diff --git a/.cirrus.yml b/.cirrus.yml index 7552d709745a..4895987da4e5 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/2021-04-19/msys2-base-x86_64-20210419.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/.github/workflows/lockdown.yml b/.github/workflows/lockdown.yml index ad8b8f7e30f9..d5e1265cffb3 100644 --- a/.github/workflows/lockdown.yml +++ b/.github/workflows/lockdown.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: dessant/repo-lockdown@v2 with: - pull-comment: | + pr-comment: | Thank you for your interest in the QEMU project. This repository is a read-only mirror of the project's repostories hosted @@ -26,5 +26,5 @@ jobs: functionality). However, we get a lot of patches, and so we have some guidelines about contributing on the project website: https://www.qemu.org/contribute/ - lock-pull: true - close-pull: true + lock-pr: true + close-pr: true diff --git a/.gitignore b/.gitignore index 9726a778b32c..61fa39967b54 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,13 @@ /GNUmakefile /build/ +/.cache/ +/.vscode/ *.pyc .sdk .stgit-* .git-submodule-status +.clang-format +.gdb_history cscope.* tags TAGS diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml new file mode 100644 index 000000000000..69b36c148a96 --- /dev/null +++ b/.gitlab-ci.d/base.yml @@ -0,0 +1,72 @@ + +# The order of rules defined here is critically important. +# They are evaluated in order and first match wins. +# +# Thus we group them into a number of stages, ordered from +# most restrictive to least restrictive +# +.base_job_template: + rules: + ############################################################# + # Stage 1: exclude scenarios where we definitely don't + # want jobs to run + ############################################################# + + # Cirrus jobs can't run unless the creds / target repo are set + - if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == null || $CIRRUS_API_TOKEN == null)' + when: never + + # Publishing jobs should only run on the default branch in upstream + - if: '$QEMU_JOB_PUBLISH == "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH' + when: never + + # Non-publishing jobs should only run on staging branches in upstream + - if: '$QEMU_JOB_PUBLISH != "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/' + when: never + + # Jobs only intended for forks should always be skipped on upstream + - if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == "qemu-project"' + when: never + + # Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set + - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: never + + # Avocado jobs don't run in forks unless $QEMU_CI_AVOCADO_TESTING is set + - if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: never + + + ############################################################# + # Stage 2: fine tune execution of jobs in specific scenarios + # where the catch all logic is inapprorpaite + ############################################################# + + # Optional jobs should not be run unless manually triggered + - if: '$QEMU_JOB_OPTIONAL' + when: manual + allow_failure: true + + # Skipped jobs should not be run unless manually triggered + - if: '$QEMU_JOB_SKIPPED' + when: manual + allow_failure: true + + # Avocado jobs can be manually start in forks if $QEMU_CI_AVOCADO_TESTING is unset + - if: '$QEMU_JOB_AVOCADO && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: manual + allow_failure: true + + + ############################################################# + # Stage 3: catch all logic applying to any job not matching + # an earlier criteria + ############################################################# + + # Forks pipeline jobs don't start automatically unless + # QEMU_CI=2 is set + - if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: manual + + # Jobs can run if any jobs they depend on were successfull + - when: on_success diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index 2c7980a4f6a2..73ecfabb8d25 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -1,4 +1,5 @@ .native_build_job_template: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest before_script: @@ -26,7 +27,8 @@ make -j"$JOBS" $MAKE_CHECK_ARGS ; fi -.native_test_job_template: +.common_test_job_template: + extends: .base_job_template stage: test image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest script: @@ -37,8 +39,18 @@ # Avoid recompiling by hiding ninja with NINJA=":" - make NINJA=":" $MAKE_CHECK_ARGS +.native_test_job_template: + extends: .common_test_job_template + artifacts: + name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + expire_in: 7 days + paths: + - build/meson-logs/testlog.txt + reports: + junit: build/meson-logs/testlog.junit.xml + .avocado_test_job_template: - extends: .native_test_job_template + extends: .common_test_job_template cache: key: "${CI_JOB_NAME}-cache" paths: @@ -67,15 +79,5 @@ after_script: - cd build - du -chs ${CI_PROJECT_DIR}/avocado-cache - rules: - # Only run these jobs if running on the mainstream namespace, - # or if the user set the QEMU_CI_AVOCADO_TESTING variable (either - # in its namespace setting or via git-push option, see documentation - # in /.gitlab-ci.yml of this repository). - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: on_success - - if: '$QEMU_CI_AVOCADO_TESTING' - when: on_success - # Otherwise, set to manual (the jobs are created but not run). - - when: manual - allow_failure: true + variables: + QEMU_JOB_AVOCADO: 1 diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 0aea7ab84c24..f09a898c3e2c 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -41,7 +41,7 @@ build-system-ubuntu: job: amd64-ubuntu2004-container variables: IMAGE: ubuntu2004 - CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system + 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 @@ -109,7 +109,8 @@ crash-test-debian: IMAGE: debian-amd64 script: - cd build - - scripts/device-crash-test -q ./qemu-system-i386 + - make check-venv + - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-i386 build-system-fedora: extends: .native_build_job_template @@ -118,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=system + --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 @@ -154,8 +155,9 @@ crash-test-fedora: IMAGE: fedora script: - cd build - - scripts/device-crash-test -q ./qemu-system-ppc - - scripts/device-crash-test -q ./qemu-system-riscv32 + - make check-venv + - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-ppc + - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-riscv32 build-system-centos: extends: .native_build_job_template @@ -165,6 +167,7 @@ build-system-centos: IMAGE: centos8 CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system --enable-modules --enable-trace-backends=dtrace --enable-docs + --enable-vfio-user-server TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu MAKE_CHECK_ARGS: check-build @@ -241,6 +244,7 @@ build-tcg-disabled: - mkdir build - cd build - ../configure --disable-tcg --audio-drv-list="" --with-coroutine=ucontext + --disable-docs --disable-sdl --disable-gtk --disable-vnc || { cat config.log meson-logs/meson-log.txt && exit 1; } - make -j"$JOBS" - make check-unit @@ -272,14 +276,10 @@ build-user-static: CONFIGURE_ARGS: --disable-tools --disable-system --static MAKE_CHECK_ARGS: check-tcg -# Because the hexagon cross-compiler takes so long to build we don't rely -# on the CI system to build it and hence this job has an optional dependency -# declared. The image is manually uploaded. build-user-hexagon: extends: .native_build_job_template needs: job: hexagon-cross-container - optional: true variables: IMAGE: debian-hexagon-cross TARGETS: hexagon-linux-user @@ -324,6 +324,7 @@ clang-user: extends: .native_build_job_template needs: job: amd64-debian-user-cross-container + timeout: 70m variables: IMAGE: debian-all-test-cross CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system @@ -335,10 +336,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 @@ -351,20 +350,18 @@ 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 - timeout: 70m + # FIXME: This job is often failing, likely due to out-of-memory problems in + # the constrained containers of the shared runners. Thus this is marked as + # skipped until the situation has been solved. + QEMU_JOB_SKIPPED: 1 + timeout: 90m artifacts: expire_in: 2 days paths: - build - rules: - # FIXME: This job is often failing, likely due to out-of-memory problems in - # the constrained containers of the shared runners. Thus this is marked as - # manual until the situation has been solved. - - when: manual - allow_failure: true check-cfi-aarch64: extends: .native_test_job_template @@ -393,20 +390,18 @@ 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 - timeout: 70m + # FIXME: This job is often failing, likely due to out-of-memory problems in + # the constrained containers of the shared runners. Thus this is marked as + # skipped until the situation has been solved. + QEMU_JOB_SKIPPED: 1 + timeout: 80m artifacts: expire_in: 2 days paths: - build - rules: - # FIXME: This job is often failing, likely due to out-of-memory problems in - # the constrained containers of the shared runners. Thus this is marked as - # manual until the situation has been solved. - - when: manual - allow_failure: true check-cfi-ppc64-s390x: extends: .native_test_job_template @@ -435,7 +430,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 +464,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 @@ -496,7 +491,17 @@ check-gprof-gcov: IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check after_script: - - ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh + - cd build + - gcovr --xml-pretty --exclude-unreachable-branches --print-summary + -o coverage.xml --root ${CI_PROJECT_DIR} . *.p + coverage: /^\s*lines:\s*\d+.\d+\%/ + artifacts: + name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA} + expire_in: 2 days + reports: + coverage_report: + coverage_format: cobertura + path: build/coverage.xml build-oss-fuzz: extends: .native_build_job_template @@ -526,8 +531,9 @@ build-tci: - TARGETS="aarch64 alpha arm hppa m68k microblaze ppc64 s390x x86_64" - mkdir build - cd build - - ../configure --enable-tcg-interpreter - --target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" || { cat config.log meson-logs/meson-log.txt && exit 1; } + - ../configure --enable-tcg-interpreter --disable-docs --disable-gtk --disable-vnc + --target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" + || { cat config.log meson-logs/meson-log.txt && exit 1; } - make -j"$JOBS" - make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test - for tg in $TARGETS ; do @@ -571,13 +577,13 @@ 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 MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow build-libvhost-user: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/fedora:latest needs: @@ -594,10 +600,13 @@ build-tools-and-docs-debian: extends: .native_build_job_template needs: job: amd64-debian-container + # when running on 'master' we use pre-existing container + optional: true variables: IMAGE: debian-amd64 - MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope + MAKE_CHECK_ARGS: check-unit ctags TAGS cscope CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools + QEMU_JOB_PUBLISH: 1 artifacts: expire_in: 2 days paths: @@ -617,6 +626,7 @@ build-tools-and-docs-debian: # that users can see the results of their commits, regardless # of what topic branch they're currently using pages: + extends: .base_job_template image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest stage: test needs: @@ -634,10 +644,5 @@ pages: artifacts: paths: - public - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: on_success - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: never - - if: '$CI_PROJECT_NAMESPACE != "qemu-project"' - when: on_success + variables: + QEMU_JOB_PUBLISH: 1 diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index b96b22e26977..785b163aa648 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -11,6 +11,7 @@ # special care, because we can't just override it at the GitLab CI job # definition level or we risk breaking it completely. .cirrus_build_job: + extends: .base_job_template stage: build image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master needs: [] @@ -40,11 +41,8 @@ <.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml - cat .gitlab-ci.d/cirrus/$NAME.yml - cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml - rules: - # Allow on 'staging' branch and 'stable-X.Y-staging' branches only - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/' - when: never - - if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN" + variables: + QEMU_JOB_CIRRUS: 1 x64-freebsd-12-build: extends: .cirrus_build_job @@ -52,7 +50,7 @@ x64-freebsd-12-build: NAME: freebsd-12 CIRRUS_VM_INSTANCE_TYPE: freebsd_instance CIRRUS_VM_IMAGE_SELECTOR: image_family - CIRRUS_VM_IMAGE_NAME: freebsd-12-3 + CIRRUS_VM_IMAGE_NAME: freebsd-12-4 CIRRUS_VM_CPUS: 8 CIRRUS_VM_RAM: 8G UPDATE_COMMAND: pkg update @@ -65,36 +63,36 @@ 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 INSTALL_COMMAND: pkg install -y TEST_TARGETS: check -x64-macos-11-base-build: +aarch64-macos-12-base-build: extends: .cirrus_build_job variables: - NAME: macos-11 - CIRRUS_VM_INSTANCE_TYPE: osx_instance + NAME: macos-12 + CIRRUS_VM_INSTANCE_TYPE: macos_instance CIRRUS_VM_IMAGE_SELECTOR: image - CIRRUS_VM_IMAGE_NAME: big-sur-base + CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-monterey-base:latest CIRRUS_VM_CPUS: 12 CIRRUS_VM_RAM: 24G UPDATE_COMMAND: brew update INSTALL_COMMAND: brew install - PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin - PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig + PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin + PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 # The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job .cirrus_kvm_job: + extends: .base_job_template stage: build image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master needs: [] timeout: 80m - allow_failure: true script: - sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g" -e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g" @@ -105,8 +103,10 @@ x64-macos-11-base-build: <.gitlab-ci.d/cirrus/kvm-build.yml >.gitlab-ci.d/cirrus/$NAME.yml - cat .gitlab-ci.d/cirrus/$NAME.yml - cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml - rules: - - when: manual + variables: + QEMU_JOB_CIRRUS: 1 + QEMU_JOB_OPTIONAL: 1 + x86-netbsd: extends: .cirrus_kvm_job diff --git a/.gitlab-ci.d/cirrus/build.yml b/.gitlab-ci.d/cirrus/build.yml index c555f5d36e64..7ef6af8d330a 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 07f313aa3abb..e3fc3235b93e 100644 --- a/.gitlab-ci.d/cirrus/freebsd-12.vars +++ b/.gitlab-ci.d/cirrus/freebsd-12.vars @@ -11,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 p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-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 sndio 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 8a648dda1ed7..9f56babd9ca7 100644 --- a/.gitlab-ci.d/cirrus/freebsd-13.vars +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -11,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 p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-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 sndio 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 deleted file mode 100644 index 08183f8793c8..000000000000 --- a/.gitlab-ci.d/cirrus/macos-11.vars +++ /dev/null @@ -1,16 +0,0 @@ -# THIS FILE WAS AUTO-GENERATED -# -# $ lcitool variables macos-11 qemu -# -# https://gitlab.com/libvirt/libvirt-ci - -CCACHE='/usr/local/bin/ccache' -CPAN_PKGS='Test::Harness' -CROSS_PKGS='' -MAKE='/usr/local/bin/gmake' -NINJA='/usr/local/bin/ninja' -PACKAGING_COMMAND='brew' -PIP3='/usr/local/bin/pip3' -PKGS='bash bc bzip2 capstone ccache cpanminus 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' -PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars new file mode 100644 index 000000000000..ef9e14b373f0 --- /dev/null +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -0,0 +1,16 @@ +# THIS FILE WAS AUTO-GENERATED +# +# $ lcitool variables macos-12 qemu +# +# https://gitlab.com/libvirt/libvirt-ci + +CCACHE='/opt/homebrew/bin/ccache' +CPAN_PKGS='' +CROSS_PKGS='' +MAKE='/opt/homebrew/bin/gmake' +NINJA='/opt/homebrew/bin/ninja' +PACKAGING_COMMAND='brew' +PIP3='/opt/homebrew/bin/pip3' +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='/opt/homebrew/bin/python3' diff --git a/.gitlab-ci.d/container-core.yml b/.gitlab-ci.d/container-core.yml index e8dd1f476a21..08f8450fa161 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 e622ac2d2131..e0d75d582462 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 @@ -27,105 +24,73 @@ arm64-debian-cross-container: armel-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-armel-cross armhf-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-armhf-cross -# We never want to build hexagon in the CI system and by default we -# always want to refer to the master registry where it lives. hexagon-cross-container: - image: docker:stable + extends: .container_job_template stage: containers - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: never - - when: always variables: NAME: debian-hexagon-cross - GIT_DEPTH: 1 - services: - - docker:dind - before_script: - - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest" - - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/qemu/$NAME:latest" - - docker info - - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" - script: - - echo "TAG:$TAG" - - echo "COMMON_TAG:$COMMON_TAG" - - docker pull $COMMON_TAG - - docker tag $COMMON_TAG $TAG - - docker push "$TAG" - after_script: - - docker logout 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 mips64el-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mips64el-cross mips-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mips-cross mipsel-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mipsel-cross powerpc-test-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian11-container'] + stage: containers variables: NAME: debian-powerpc-test-cross ppc64el-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-ppc64el-cross riscv64-debian-cross-container: extends: .container_job_template - stage: containers-layer2 + stage: containers # as we are currently based on 'sid/unstable' we may break so... allow_failure: true variables: @@ -134,7 +99,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 + stage: containers variables: NAME: debian-riscv64-test-cross @@ -146,22 +111,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/container-template.yml b/.gitlab-ci.d/container-template.yml index 1baecd946062..c434b9c8f3e3 100644 --- a/.gitlab-ci.d/container-template.yml +++ b/.gitlab-ci.d/container-template.yml @@ -1,4 +1,5 @@ .container_job_template: + extends: .base_job_template image: docker:stable stage: containers services: diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index b9b675fdcb93..96d2a3b58bea 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -7,23 +7,12 @@ 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-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-amd64 -amd64-ubuntu1804-container: - extends: .container_job_template - variables: - NAME: ubuntu1804 - amd64-ubuntu2004-container: extends: .container_job_template variables: diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 29c3c2b826c3..6d709628f127 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -1,12 +1,12 @@ .cross_system_build_job: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest timeout: 80m script: - mkdir build - cd build - - PKG_CONFIG_PATH=$PKG_CONFIG_PATH - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS + - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS --disable-user --target-list-exclude="arm-softmmu cris-softmmu i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu mips64-softmmu ppc-softmmu riscv32-softmmu sh4-softmmu @@ -24,24 +24,27 @@ # KVM), and set extra options (such disabling other accelerators) via the # $EXTRA_CONFIGURE_OPTS variable. .cross_accel_build_job: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest timeout: 30m script: - mkdir build - cd build - - PKG_CONFIG_PATH=$PKG_CONFIG_PATH - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS + - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS --disable-tools --enable-${ACCEL:-kvm} $EXTRA_CONFIGURE_OPTS - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS .cross_user_build_job: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest script: - mkdir build - cd build - - PKG_CONFIG_PATH=$PKG_CONFIG_PATH - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS - --disable-system + - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS + --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 17d6cb3e458a..8dbbb8f88198 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -62,26 +62,14 @@ cross-i386-user: cross-i386-tci: extends: .cross_accel_build_job timeout: 60m + needs: + job: i386-fedora-cross-container variables: IMAGE: fedora-i386-cross ACCEL: tcg-interpreter 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: @@ -124,6 +112,14 @@ cross-ppc64el-user: variables: IMAGE: debian-ppc64el-cross +cross-ppc64el-kvm-only: + extends: .cross_accel_build_job + needs: + job: ppc64el-debian-cross-container + variables: + IMAGE: debian-ppc64el-cross + EXTRA_CONFIGURE_OPTS: --disable-tcg --without-default-devices + # The riscv64 cross-builds currently use a 'sid' container to get # compilers and libraries. Until something more stable is found we # allow_failure so as not to block CI. diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 15aaccc481f9..97f99e29c2b7 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 49aa703f55cd..068b0c4335be 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-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml deleted file mode 100644 index 9c589bc4cf0e..000000000000 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml +++ /dev/null @@ -1,23 +0,0 @@ -# All ubuntu-20.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 18.04/20.04" - -ubuntu-20.04-aarch32-all: - needs: [] - stage: build - tags: - - ubuntu_20.04 - - aarch32 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - when: manual - allow_failure: true - - if: "$AARCH32_RUNNER_AVAILABLE" - when: manual - allow_failure: true - script: - - mkdir build - - cd build - - ../configure --cross-prefix=arm-linux-gnueabihf- - - make --output-sync -j`nproc` - - make --output-sync -j`nproc` check V=1 diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml deleted file mode 100644 index 920e388bd05e..000000000000 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml +++ /dev/null @@ -1,118 +0,0 @@ -# All ubuntu-20.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 18.04/20.04" - -ubuntu-20.04-aarch64-all-linux-static: - needs: [] - stage: build - tags: - - ubuntu_20.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 - - make --output-sync -j`nproc` - - make --output-sync -j`nproc` check V=1 - - make --output-sync -j`nproc` check-tcg V=1 - -ubuntu-20.04-aarch64-all: - needs: [] - stage: build - tags: - - ubuntu_20.04 - - aarch64 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - when: manual - allow_failure: true - - if: "$AARCH64_RUNNER_AVAILABLE" - when: manual - allow_failure: true - script: - - mkdir build - - cd build - - ../configure --disable-libssh - - make --output-sync -j`nproc` - - make --output-sync -j`nproc` check V=1 - -ubuntu-20.04-aarch64-alldbg: - needs: [] - stage: build - tags: - - ubuntu_20.04 - - aarch64 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - - if: "$AARCH64_RUNNER_AVAILABLE" - script: - - mkdir build - - cd build - - ../configure --enable-debug --disable-libssh - - make clean - - make --output-sync -j`nproc` - - make --output-sync -j`nproc` check V=1 - -ubuntu-20.04-aarch64-clang: - needs: [] - stage: build - tags: - - ubuntu_20.04 - - aarch64 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - when: manual - allow_failure: true - - if: "$AARCH64_RUNNER_AVAILABLE" - when: manual - allow_failure: true - script: - - mkdir build - - cd build - - ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers - - make --output-sync -j`nproc` - - make --output-sync -j`nproc` check V=1 - -ubuntu-20.04-aarch64-tci: - needs: [] - stage: build - tags: - - ubuntu_20.04 - - aarch64 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - when: manual - allow_failure: true - - if: "$AARCH64_RUNNER_AVAILABLE" - when: manual - allow_failure: true - script: - - mkdir build - - cd build - - ../configure --disable-libssh --enable-tcg-interpreter - - make --output-sync -j`nproc` - -ubuntu-20.04-aarch64-notcg: - needs: [] - stage: build - tags: - - ubuntu_20.04 - - aarch64 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - when: manual - allow_failure: true - - if: "$AARCH64_RUNNER_AVAILABLE" - when: manual - allow_failure: true - script: - - mkdir build - - cd build - - ../configure --disable-libssh --disable-tcg - - make --output-sync -j`nproc` - - make --output-sync -j`nproc` check V=1 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 4f292a8a5b18..fcaef9e5eff0 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml @@ -8,8 +8,6 @@ ubuntu-20.04-s390x-all-linux-static: tags: - ubuntu_20.04 - s390x - variables: - DFLTCC: 0 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - if: "$S390X_RUNNER_AVAILABLE" @@ -19,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 - - make --output-sync -j`nproc` check-tcg V=1 + - make --output-sync -j`nproc` check + || { cat meson-logs/testlog.txt; exit 1; } ; + - make --output-sync -j`nproc` check-tcg + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-all: needs: [] @@ -29,8 +30,7 @@ ubuntu-20.04-s390x-all: tags: - ubuntu_20.04 - s390x - variables: - DFLTCC: 0 + timeout: 75m rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - if: "$S390X_RUNNER_AVAILABLE" @@ -38,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 + - make --output-sync -j`nproc` check + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-alldbg: needs: [] @@ -47,8 +49,6 @@ ubuntu-20.04-s390x-alldbg: tags: - ubuntu_20.04 - s390x - variables: - DFLTCC: 0 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' when: manual @@ -60,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 + - make --output-sync -j`nproc` check + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-clang: needs: [] @@ -70,8 +72,6 @@ ubuntu-20.04-s390x-clang: tags: - ubuntu_20.04 - s390x - variables: - DFLTCC: 0 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' when: manual @@ -83,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 + - make --output-sync -j`nproc` check + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-tci: needs: [] @@ -92,8 +94,6 @@ ubuntu-20.04-s390x-tci: tags: - ubuntu_20.04 - s390x - variables: - DFLTCC: 0 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' when: manual @@ -105,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: @@ -113,8 +114,6 @@ ubuntu-20.04-s390x-notcg: tags: - ubuntu_20.04 - s390x - variables: - DFLTCC: 0 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' when: manual @@ -126,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 + - make --output-sync -j`nproc` check + || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml new file mode 100644 index 000000000000..2c386fa3e93f --- /dev/null +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml @@ -0,0 +1,25 @@ +# 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-22.04-aarch32-all: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch32 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + allow_failure: true + - if: "$AARCH32_RUNNER_AVAILABLE" + when: manual + allow_failure: true + script: + - 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 + || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml new file mode 100644 index 000000000000..abeb33eaffb4 --- /dev/null +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml @@ -0,0 +1,130 @@ +# All ubuntu-20.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-22.04-aarch64-all-linux-static: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch64 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$AARCH64_RUNNER_AVAILABLE" + script: + - mkdir build + - cd build + # 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 + || { cat meson-logs/testlog.txt; exit 1; } ; + - make --output-sync -j`nproc --ignore=40` check-tcg + || { cat meson-logs/testlog.txt; exit 1; } ; + +ubuntu-22.04-aarch64-all: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch64 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + allow_failure: true + - if: "$AARCH64_RUNNER_AVAILABLE" + when: manual + allow_failure: true + script: + - mkdir build + - cd build + - ../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 + || { cat meson-logs/testlog.txt; exit 1; } ; + +ubuntu-22.04-aarch64-alldbg: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch64 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + - if: "$AARCH64_RUNNER_AVAILABLE" + script: + - mkdir build + - cd build + - ../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 + || { cat meson-logs/testlog.txt; exit 1; } ; + +ubuntu-22.04-aarch64-clang: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch64 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + allow_failure: true + - if: "$AARCH64_RUNNER_AVAILABLE" + when: manual + allow_failure: true + script: + - 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 + || { cat meson-logs/testlog.txt; exit 1; } ; + +ubuntu-22.04-aarch64-tci: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch64 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + allow_failure: true + - if: "$AARCH64_RUNNER_AVAILABLE" + when: manual + allow_failure: true + script: + - mkdir build + - cd build + - ../configure --enable-tcg-interpreter + || { cat config.log meson-logs/meson-log.txt; exit 1; } + - make --output-sync -j`nproc --ignore=40` + +ubuntu-22.04-aarch64-notcg: + needs: [] + stage: build + tags: + - ubuntu_22.04 + - aarch64 + rules: + - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' + when: manual + allow_failure: true + - if: "$AARCH64_RUNNER_AVAILABLE" + when: manual + allow_failure: true + script: + - mkdir build + - cd build + - ../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 + || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/edk2.yml b/.gitlab-ci.d/edk2.yml index 13d0f8b019f5..314e10174521 100644 --- a/.gitlab-ci.d/edk2.yml +++ b/.gitlab-ci.d/edk2.yml @@ -1,60 +1,85 @@ # All jobs needing docker-edk2 must use the same rules it uses. .edk2_job_rules: - rules: # Only run this job when ... - - changes: - # this file is modified - - .gitlab-ci.d/edk2.yml - # or the Dockerfile is modified - - .gitlab-ci.d/edk2/Dockerfile - # or roms/edk2/ is modified (submodule updated) - - roms/edk2/* - when: on_success - - if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2' - when: on_success - - if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2' - when: on_success + rules: + # Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set + - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: never + + # In forks, if QEMU_CI=1 is set, then create manual job + # if any of the files affecting the build are touched + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project"' + changes: + - .gitlab-ci.d/edk2.yml + - .gitlab-ci.d/edk2/Dockerfile + - roms/edk2/* + when: manual + + # In forks, if QEMU_CI=1 is set, then create manual job + # if the branch/tag starts with 'edk2' + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_REF_NAME =~ /^edk2/' + when: manual + + # In forks, if QEMU_CI=1 is set, then create manual job + # if last commit msg contains 'EDK2' (case insensitive) + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_MESSAGE =~ /edk2/i' + when: manual + + # Run if any files affecting the build output are touched + - changes: + - .gitlab-ci.d/edk2.yml + - .gitlab-ci.d/edk2/Dockerfile + - roms/edk2/* + when: on_success + + # Run if the branch/tag starts with 'edk2' + - if: '$CI_COMMIT_REF_NAME =~ /^edk2/' + when: on_success + + # Run if last commit msg contains 'EDK2' (case insensitive) + - if: '$CI_COMMIT_MESSAGE =~ /edk2/i' + when: on_success docker-edk2: - extends: .edk2_job_rules - stage: containers - image: docker:19.03.1 - services: - - docker:19.03.1-dind - variables: - GIT_DEPTH: 3 - IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build - # We don't use TLS - DOCKER_HOST: tcp://docker:2375 - DOCKER_TLS_CERTDIR: "" - before_script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - script: - - docker pull $IMAGE_TAG || true - - docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - --tag $IMAGE_TAG .gitlab-ci.d/edk2 - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - - docker push $IMAGE_TAG + extends: .edk2_job_rules + stage: containers + image: docker:19.03.1 + services: + - docker:19.03.1-dind + variables: + GIT_DEPTH: 3 + IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build + # We don't use TLS + DOCKER_HOST: tcp://docker:2375 + DOCKER_TLS_CERTDIR: "" + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - docker pull $IMAGE_TAG || true + - docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + --tag $IMAGE_TAG .gitlab-ci.d/edk2 + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + - docker push $IMAGE_TAG build-edk2: - extends: .edk2_job_rules - stage: build - needs: ['docker-edk2'] - artifacts: - paths: # 'artifacts.zip' will contains the following files: - - pc-bios/edk2*bz2 - - pc-bios/edk2-licenses.txt - - edk2-stdout.log - - edk2-stderr.log - image: $CI_REGISTRY_IMAGE:edk2-cross-build - variables: - GIT_DEPTH: 3 - script: # Clone the required submodules and build EDK2 - - git submodule update --init roms/edk2 - - git -C roms/edk2 submodule update --init -- - ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 - BaseTools/Source/C/BrotliCompress/brotli - CryptoPkg/Library/OpensslLib/openssl - MdeModulePkg/Library/BrotliCustomDecompressLib/brotli - - export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1)) - - echo "=== Using ${JOBS} simultaneous jobs ===" - - make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2 + extends: .edk2_job_rules + stage: build + needs: ['docker-edk2'] + artifacts: + paths: # 'artifacts.zip' will contains the following files: + - pc-bios/edk2*bz2 + - pc-bios/edk2-licenses.txt + - edk2-stdout.log + - edk2-stderr.log + image: $CI_REGISTRY_IMAGE:edk2-cross-build + variables: + GIT_DEPTH: 3 + script: # Clone the required submodules and build EDK2 + - git submodule update --init roms/edk2 + - git -C roms/edk2 submodule update --init -- + ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 + BaseTools/Source/C/BrotliCompress/brotli + CryptoPkg/Library/OpensslLib/openssl + MdeModulePkg/Library/BrotliCustomDecompressLib/brotli + - export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1)) + - echo "=== Using ${JOBS} simultaneous jobs ===" + - make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2 diff --git a/.gitlab-ci.d/opensbi.yml b/.gitlab-ci.d/opensbi.yml index 29a22930d1d6..04ed5a3ea139 100644 --- a/.gitlab-ci.d/opensbi.yml +++ b/.gitlab-ci.d/opensbi.yml @@ -1,61 +1,85 @@ # All jobs needing docker-opensbi must use the same rules it uses. .opensbi_job_rules: - rules: # Only run this job when ... - - changes: - # this file is modified - - .gitlab-ci.d/opensbi.yml - # or the Dockerfile is modified - - .gitlab-ci.d/opensbi/Dockerfile - when: on_success - - changes: # or roms/opensbi/ is modified (submodule updated) - - roms/opensbi/* - when: on_success - - if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi' - when: on_success - - if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI' - when: on_success + rules: + # Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set + - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: never + + # In forks, if QEMU_CI=1 is set, then create manual job + # if any files affecting the build output are touched + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project"' + changes: + - .gitlab-ci.d/opensbi.yml + - .gitlab-ci.d/opensbi/Dockerfile + - roms/opensbi/* + when: manual + + # In forks, if QEMU_CI=1 is set, then create manual job + # if the branch/tag starts with 'opensbi' + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_REF_NAME =~ /^opensbi/' + when: manual + + # In forks, if QEMU_CI=1 is set, then create manual job + # if the last commit msg contains 'OpenSBI' (case insensitive) + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_MESSAGE =~ /opensbi/i' + when: manual + + # Run if any files affecting the build output are touched + - changes: + - .gitlab-ci.d/opensbi.yml + - .gitlab-ci.d/opensbi/Dockerfile + - roms/opensbi/* + when: on_success + + # Run if the branch/tag starts with 'opensbi' + - if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' + when: on_success + + # Run if the last commit msg contains 'OpenSBI' (case insensitive) + - if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' + when: on_success docker-opensbi: - extends: .opensbi_job_rules - stage: containers - image: docker:19.03.1 - services: - - docker:19.03.1-dind - variables: - GIT_DEPTH: 3 - IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build - # We don't use TLS - DOCKER_HOST: tcp://docker:2375 - DOCKER_TLS_CERTDIR: "" - before_script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - script: - - docker pull $IMAGE_TAG || true - - docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - --tag $IMAGE_TAG .gitlab-ci.d/opensbi - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - - docker push $IMAGE_TAG + extends: .opensbi_job_rules + stage: containers + image: docker:19.03.1 + services: + - docker:19.03.1-dind + variables: + GIT_DEPTH: 3 + IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build + # We don't use TLS + DOCKER_HOST: tcp://docker:2375 + DOCKER_TLS_CERTDIR: "" + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - docker pull $IMAGE_TAG || true + - docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + --tag $IMAGE_TAG .gitlab-ci.d/opensbi + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + - docker push $IMAGE_TAG build-opensbi: - extends: .opensbi_job_rules - stage: build - needs: ['docker-opensbi'] - artifacts: - paths: # 'artifacts.zip' will contains the following files: - - pc-bios/opensbi-riscv32-generic-fw_dynamic.bin - - pc-bios/opensbi-riscv64-generic-fw_dynamic.bin - - opensbi32-generic-stdout.log - - opensbi32-generic-stderr.log - - opensbi64-generic-stdout.log - - opensbi64-generic-stderr.log - image: $CI_REGISTRY_IMAGE:opensbi-cross-build - variables: - GIT_DEPTH: 3 - script: # Clone the required submodules and build OpenSBI - - git submodule update --init roms/opensbi - - export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1)) - - echo "=== Using ${JOBS} simultaneous jobs ===" - - make -j${JOBS} -C roms/opensbi clean - - make -j${JOBS} -C roms opensbi32-generic 2>&1 1>opensbi32-generic-stdout.log | tee -a opensbi32-generic-stderr.log >&2 - - make -j${JOBS} -C roms/opensbi clean - - make -j${JOBS} -C roms opensbi64-generic 2>&1 1>opensbi64-generic-stdout.log | tee -a opensbi64-generic-stderr.log >&2 + extends: .opensbi_job_rules + stage: build + needs: ['docker-opensbi'] + artifacts: + paths: # 'artifacts.zip' will contains the following files: + - pc-bios/opensbi-riscv32-generic-fw_dynamic.bin + - pc-bios/opensbi-riscv64-generic-fw_dynamic.bin + - opensbi32-generic-stdout.log + - opensbi32-generic-stderr.log + - opensbi64-generic-stdout.log + - opensbi64-generic-stderr.log + image: $CI_REGISTRY_IMAGE:opensbi-cross-build + variables: + GIT_DEPTH: 3 + script: # Clone the required submodules and build OpenSBI + - git submodule update --init roms/opensbi + - export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1)) + - echo "=== Using ${JOBS} simultaneous jobs ===" + - make -j${JOBS} -C roms/opensbi clean + - make -j${JOBS} -C roms opensbi32-generic 2>&1 1>opensbi32-generic-stdout.log | tee -a opensbi32-generic-stderr.log >&2 + - make -j${JOBS} -C roms/opensbi clean + - make -j${JOBS} -C roms opensbi64-generic 2>&1 1>opensbi64-generic-stdout.log | tee -a opensbi64-generic-stderr.log >&2 diff --git a/.gitlab-ci.d/qemu-project.yml b/.gitlab-ci.d/qemu-project.yml index 871262fe0e8a..691d9bf5dc9d 100644 --- a/.gitlab-ci.d/qemu-project.yml +++ b/.gitlab-ci.d/qemu-project.yml @@ -2,6 +2,7 @@ # https://gitlab.com/qemu-project/qemu/-/pipelines include: + - local: '/.gitlab-ci.d/base.yml' - local: '/.gitlab-ci.d/stages.yml' - local: '/.gitlab-ci.d/edk2.yml' - local: '/.gitlab-ci.d/opensbi.yml' diff --git a/.gitlab-ci.d/stages.yml b/.gitlab-ci.d/stages.yml index f50826018df9..f92f57a27dcf 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/static_checks.yml b/.gitlab-ci.d/static_checks.yml index 5e955540d321..289ad1359e3a 100644 --- a/.gitlab-ci.d/static_checks.yml +++ b/.gitlab-ci.d/static_checks.yml @@ -1,32 +1,30 @@ check-patch: + extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/centos8:latest - needs: - job: amd64-centos8-container + image: python:3.10-alpine + needs: [] script: - .gitlab-ci.d/check-patch.py variables: GIT_DEPTH: 1000 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: never - - when: on_success - allow_failure: true + QEMU_JOB_ONLY_FORKS: 1 + before_script: + - apk -U add git perl + allow_failure: true check-dco: + extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/centos8:latest - needs: - job: amd64-centos8-container + image: python:3.10-alpine + needs: [] script: .gitlab-ci.d/check-dco.py variables: GIT_DEPTH: 1000 - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: never - - when: on_success + before_script: + - apk -U add git check-python-pipenv: + extends: .base_job_template stage: test image: $CI_REGISTRY_IMAGE/qemu/python:latest script: @@ -37,6 +35,7 @@ check-python-pipenv: job: python-container check-python-tox: + extends: .base_job_template stage: test image: $CI_REGISTRY_IMAGE/qemu/python:latest script: @@ -44,8 +43,6 @@ check-python-tox: variables: GIT_DEPTH: 1 QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false + QEMU_JOB_OPTIONAL: 1 needs: job: python-container - rules: - - when: manual - allow_failure: true diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index 1df16303491e..a1d579058088 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -1,4 +1,5 @@ .shared_msys2_builder: + extends: .base_job_template tags: - shared-windows - windows @@ -9,14 +10,14 @@ - ${CI_PROJECT_DIR}/msys64/var/cache needs: [] stage: build - timeout: 70m + timeout: 80m before_script: - If ( !(Test-Path -Path msys64\var\cache ) ) { mkdir msys64\var\cache } - If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) { Invoke-WebRequest - "https://github.com/msys2/msys2-installer/releases/download/2021-07-25/msys2-base-x86_64-20210725.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 @@ -32,18 +33,23 @@ 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 mingw-w64-x86_64-gcc mingw-w64-x86_64-glib2 mingw-w64-x86_64-gnutls + mingw-w64-x86_64-gtk3 + mingw-w64-x86_64-libgcrypt + mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-libnfs mingw-w64-x86_64-libpng mingw-w64-x86_64-libssh mingw-w64-x86_64-libtasn1 mingw-w64-x86_64-libusb + mingw-w64-x86_64-lzo2 mingw-w64-x86_64-nettle mingw-w64-x86_64-ninja mingw-w64-x86_64-pixman @@ -55,18 +61,28 @@ msys2-64bit: mingw-w64-x86_64-usbredir mingw-w64-x86_64-zstd " - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - - $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment - - .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu - --enable-capstone=system --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' + - $env:MSYSTEM = 'MINGW64' # Start a 64-bit MinGW environment + - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink + - mkdir output + - cd output + # Note: do not remove "--without-default-devices"! + # commit 9f8e6cad65a6 ("gitlab-ci: Speed up the msys2-64bit job by using --without-default-devices" + # changed to compile QEMU with the --without-default-devices switch + # for the msys2 64-bit job, due to the build could not complete within + # the project timeout. + - ..\msys64\usr\bin\bash -lc '../configure --target-list=x86_64-softmmu + --without-default-devices --disable-opengl' + - ..\msys64\usr\bin\bash -lc 'make' + # qTests don't run successfully with "--without-default-devices", + # so let's exclude the qtests from CI for now. + - ..\msys64\usr\bin\bash -lc 'make check MTESTARGS=\"--no-suite qtest\" || { cat 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 @@ -76,21 +92,29 @@ msys2-32bit: mingw-w64-i686-gtk3 mingw-w64-i686-libgcrypt mingw-w64-i686-libjpeg-turbo + mingw-w64-i686-libnfs + mingw-w64-i686-libpng mingw-w64-i686-libssh mingw-w64-i686-libtasn1 mingw-w64-i686-libusb mingw-w64-i686-lzo2 + mingw-w64-i686-nettle mingw-w64-i686-ninja mingw-w64-i686-pixman mingw-w64-i686-pkgconf mingw-w64-i686-python + mingw-w64-i686-SDL2 + mingw-w64-i686-SDL2_image mingw-w64-i686-snappy - mingw-w64-i686-usbredir " + mingw-w64-i686-usbredir + mingw-w64-i686-zstd " - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - - $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment + - $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinGW environment + - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - mkdir output - cd output - - ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu - --enable-capstone=system" - - ..\msys64\usr\bin\bash -lc 'make -j2' - - ..\msys64\usr\bin\bash -lc 'make check' + - ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu + --disable-opengl' + - ..\msys64\usr\bin\bash -lc 'make' + - ..\msys64\usr\bin\bash -lc 'make check MTESTARGS=\"--no-suite qtest\" || + { cat meson-logs/testlog.txt; exit 1; }' diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md index e910f7b1c294..53a79f582846 100644 --- a/.gitlab/issue_templates/bug.md +++ b/.gitlab/issue_templates/bug.md @@ -18,11 +18,11 @@ https://www.qemu.org/contribute/security-process/ --> ## Host environment - - Operating system: (Windows 10 21H1, Fedora 34, etc.) - - OS/kernel version: (For POSIX hosts, use `uname -a`) - - Architecture: (x86, ARM, s390x, etc.) - - QEMU flavor: (qemu-system-x86_64, qemu-aarch64, qemu-img, etc.) - - QEMU version: (e.g. `qemu-system-x86_64 --version`) + - Operating system: + - OS/kernel version: + - Architecture: + - QEMU flavor: + - QEMU version: - QEMU command line: + - OS/kernel version: + - Architecture: ## Description of problem diff --git a/.gitmodules b/.gitmodules index f4b6a9b40127..24cffa87d420 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,9 +31,6 @@ [submodule "ui/keycodemapdb"] path = ui/keycodemapdb url = https://gitlab.com/qemu-project/keycodemapdb.git -[submodule "capstone"] - path = capstone - url = https://gitlab.com/qemu-project/capstone.git [submodule "roms/seabios-hppa"] path = roms/seabios-hppa url = https://gitlab.com/qemu-project/seabios-hppa.git @@ -49,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 @@ -67,3 +61,6 @@ [submodule "tests/lcitool/libvirt-ci"] path = tests/lcitool/libvirt-ci url = https://gitlab.com/libvirt/libvirt-ci.git +[submodule "subprojects/libvfio-user"] + path = subprojects/libvfio-user + url = https://gitlab.com/qemu-project/libvfio-user.git diff --git a/.mailmap b/.mailmap index 2976a675ea54..fad2aff5aa55 100644 --- a/.mailmap +++ b/.mailmap @@ -45,6 +45,7 @@ Ed Swierk Ed Swierk via Qemu-devel Ian McKellar via Qemu-devel Julia Suvorova Julia Suvorova via Qemu-devel Justin Terry (VM) Justin Terry (VM) via Qemu-devel +Stefan Weil Stefan Weil via # Next, replace old addresses by a more recent one. Aleksandar Markovic @@ -62,13 +63,17 @@ Greg Kurz Huacai Chen Huacai Chen James Hogan -Leif Lindholm +Leif Lindholm +Leif Lindholm Radoslaw Biernacki +Paul Brook Paul Burton Paul Burton Paul Burton Paul Burton -Philippe Mathieu-Daudé +Philippe Mathieu-Daudé +Philippe Mathieu-Daudé +Philippe Mathieu-Daudé Stefan Brankovic Yongbok Kim diff --git a/.travis.yml b/.travis.yml index 9afc4a54b8fd..fb3baabca9b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -218,12 +218,11 @@ jobs: - TEST_CMD="make check check-tcg V=1" - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" - UNRELIABLE=true - - DFLTCC=0 script: - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? - | if [ "$BUILD_RC" -eq 0 ] ; then - mv pc-bios/s390-ccw/*.img pc-bios/ ; + mv pc-bios/s390-ccw/*.img qemu-bundle/usr/local/share/qemu ; ${TEST_CMD} ; else $(exit $BUILD_RC); @@ -258,7 +257,7 @@ jobs: env: - CONFIG="--disable-containers --audio-drv-list=sdl --disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" - - DFLTCC=0 + - name: "[s390x] GCC (user)" arch: s390x dist: focal @@ -270,7 +269,7 @@ jobs: - ninja-build env: - CONFIG="--disable-containers --disable-system" - - DFLTCC=0 + - name: "[s390x] Clang (disable-tcg)" arch: s390x dist: focal @@ -304,4 +303,3 @@ jobs: - CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools --host-cc=clang --cxx=clang++" - UNRELIABLE=true - - DFLTCC=0 diff --git a/Kconfig.host b/Kconfig.host index 60b9c07b5eef..d763d892693c 100644 --- a/Kconfig.host +++ b/Kconfig.host @@ -22,15 +22,12 @@ config TPM config VHOST_USER bool - select VHOST config VHOST_VDPA bool - select VHOST config VHOST_KERNEL bool - select VHOST config VIRTFS bool @@ -45,3 +42,7 @@ config MULTIPROCESS_ALLOWED config FUZZ bool select SPARSE_MEM + +config VFIO_USER_SERVER_ALLOWED + bool + imply VFIO_USER_SERVER diff --git a/MAINTAINERS b/MAINTAINERS index 4ad2451e0344..6982be48c637 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23,7 +23,7 @@ Descriptions of section entries: W: Web-page with status/info Q: Patchwork web based patch tracking system site T: SCM tree type and location. Type is one of: git, hg, quilt, stgit. - S: Status, one of the following: + S: Status, one of the following (keep in sync with docs/devel/maintainers.rst): Supported: Someone is actually paid to look after this. Maintained: Someone actually looks after it. Odd Fixes: It has a maintainer but they don't have time to do @@ -78,13 +78,13 @@ M: Laurent Vivier S: Maintained L: qemu-trivial@nongnu.org K: ^Subject:.*(?i)trivial +F: docs/devel/trivial-patches.rst T: git git://git.corpit.ru/qemu.git trivial-patches T: git https://github.com/vivier/qemu.git trivial-patches Architecture support -------------------- S390 general architecture support -M: Cornelia Huck M: Thomas Huth S: Supported F: configs/devices/s390x-softmmu/default.mak @@ -106,14 +106,15 @@ F: docs/system/target-s390x.rst F: docs/system/s390x/ F: tests/migration/s390x/ K: ^Subject:.*(?i)s390x? -T: git https://gitlab.com/cohuck/qemu.git s390-next L: qemu-s390x@nongnu.org MIPS general architecture support -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Jiaxun Yang S: Odd Fixes K: ^Subject:.*(?i)mips +F: docs/system/target-mips.rst +F: configs/targets/mips* Guest CPU cores (TCG) --------------------- @@ -131,6 +132,7 @@ F: util/cacheinfo.c F: util/cacheflush.c F: scripts/decodetree.py F: docs/devel/decodetree.rst +F: docs/devel/tcg* F: include/exec/cpu*.h F: include/exec/exec-all.h F: include/exec/helper*.h @@ -165,9 +167,6 @@ F: tests/qtest/arm-cpu-features.c F: hw/arm/ F: hw/cpu/a*mpcore.c F: include/hw/cpu/a*mpcore.h -F: disas/arm.c -F: disas/arm-a64.cc -F: disas/libvixl/ F: docs/system/target-arm.rst F: docs/system/arm/cpu-features.rst @@ -200,12 +199,20 @@ Hexagon TCG CPUs M: Taylor Simpson S: Supported F: target/hexagon/ +X: target/hexagon/idef-parser/ +X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ F: tests/tcg/hexagon/ F: disas/hexagon.c F: configs/targets/hexagon-linux-user/default.mak F: docker/dockerfiles/debian-hexagon-cross.docker -F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh + +Hexagon idef-parser +M: Alessandro Di Federico +M: Anton Johansson +S: Supported +F: target/hexagon/idef-parser/ +F: target/hexagon/gen_idef_parser_funcs.py HPPA (PA-RISC) TCG CPUs M: Richard Henderson @@ -213,6 +220,13 @@ S: Maintained F: target/hppa/ F: disas/hppa.c +LoongArch TCG CPUs +M: Song Gao +M: Xiaojuan Yang +S: Maintained +F: target/loongarch/ +F: tests/tcg/loongarch64/ + M68K TCG CPUs M: Laurent Vivier S: Maintained @@ -229,21 +243,16 @@ F: tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh F: tests/tcg/nios2/Makefile.target MIPS TCG CPUs -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Aurelien Jarno R: Jiaxun Yang R: Aleksandar Rikalo S: Odd Fixes F: target/mips/ -F: disas/mips.c +F: disas/*mips.c F: docs/system/cpu-models-mips.rst.inc F: tests/tcg/mips/ -MIPS TCG CPUs (nanoMIPS ISA) -S: Orphan -F: disas/nanomips.* -F: target/mips/tcg/*nanomips* - NiosII TCG CPUs M: Chris Wulff M: Marek Vasut @@ -257,22 +266,22 @@ F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh OpenRISC TCG CPUs M: Stafford Horne S: Odd Fixes +F: docs/system/openrisc/cpu-features.rst F: target/openrisc/ F: hw/openrisc/ F: tests/tcg/openrisc/ PowerPC TCG CPUs -M: Cédric Le Goater M: Daniel Henrique Barboza +R: Cédric Le Goater R: David Gibson R: Greg Kurz L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: target/ppc/ F: hw/ppc/ppc.c F: hw/ppc/ppc_booke.c F: include/hw/ppc/ppc.h -F: disas/ppc.c RISC-V TCG CPUs M: Palmer Dabbelt @@ -301,11 +310,11 @@ F: target/rx/ S390 TCG CPUs M: Richard Henderson M: David Hildenbrand +R: Ilya Leoshkevich S: Maintained F: target/s390x/ F: target/s390x/tcg F: hw/s390x/ -F: disas/s390.c F: tests/tcg/s390x/ L: qemu-s390x@nongnu.org @@ -336,7 +345,7 @@ F: target/i386/tcg/ F: tests/tcg/i386/ F: tests/tcg/x86_64/ F: hw/i386/ -F: disas/i386.c +F: docs/system/i386/cpu.rst F: docs/system/cpu-models-x86* T: git https://gitlab.com/ehabkost/qemu.git x86-next @@ -390,11 +399,11 @@ F: target/mips/kvm* F: target/mips/sysemu/ PPC KVM CPUs -M: Cédric Le Goater M: Daniel Henrique Barboza +R: Cédric Le Goater R: David Gibson R: Greg Kurz -S: Maintained +S: Odd Fixes F: target/ppc/kvm.c S390 KVM CPUs @@ -492,7 +501,6 @@ Guest CPU Cores (HAXM) --------------------- X86 HAXM CPUs M: Wenchao Wang -M: Colin Xu L: haxm-team@intel.com W: https://github.com/intel/haxm/issues S: Maintained @@ -547,12 +555,14 @@ F: */*win32* F: include/*/*win32* X: qga/*win32* F: qemu.nsi +F: scripts/nsis.py Darwin (macOS, iOS) -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Odd Fixes F: .gitlab-ci.d/cirrus/macos-* F: */*.m +F: scripts/entitlement.sh Alpha Machines -------------- @@ -567,12 +577,14 @@ ARM Machines Allwinner-a10 M: Beniamino Galvani M: Peter Maydell +R: Strahinja Jankovic L: qemu-arm@nongnu.org S: Odd Fixes F: hw/*/allwinner* F: include/hw/*/allwinner* F: hw/arm/cubieboard.c F: docs/system/arm/cubieboard.rst +F: hw/misc/axp209.c Allwinner-h3 M: Niek Linnenbank @@ -648,7 +660,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Odd Fixes F: hw/*/exynos* -F: include/hw/arm/exynos4210.h +F: include/hw/*/exynos* Calxeda Highbank M: Rob Herring @@ -680,7 +692,7 @@ F: include/hw/rtc/goldfish_rtc.h Gumstix M: Peter Maydell -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/gumstix.c @@ -831,7 +843,7 @@ F: docs/system/arm/palm.rst Raspberry Pi M: Peter Maydell -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/raspi.c @@ -877,6 +889,7 @@ M: Peter Maydell R: Jean-Christophe Dubois L: qemu-arm@nongnu.org S: Odd Fixes +F: docs/system/arm/sabrelite.rst F: hw/arm/sabrelite.c F: hw/arm/fsl-imx6.c F: hw/misc/imx6_*.c @@ -890,7 +903,7 @@ F: include/hw/ssi/imx_spi.h SBSA-REF M: Radoslaw Biernacki M: Peter Maydell -R: Leif Lindholm +R: Leif Lindholm L: qemu-arm@nongnu.org S: Maintained F: hw/arm/sbsa-ref.c @@ -942,6 +955,7 @@ S: Maintained F: hw/arm/virt* F: include/hw/arm/virt.h F: docs/system/arm/virt.rst +F: tests/avocado/machine_aarch64_virt.py Xilinx Zynq M: Edgar E. Iglesias @@ -1024,6 +1038,12 @@ L: qemu-arm@nongnu.org S: Maintained F: hw/arm/netduinoplus2.c +Olimex STM32 H405 +M: Felipe Balbi +L: qemu-arm@nongnu.org +S: Maintained +F: hw/arm/olimex-stm32-h405.c + SmartFusion2 M: Subbaraya Sundeep M: Peter Maydell @@ -1063,6 +1083,7 @@ F: hw/net/ftgmac100.c F: include/hw/net/ftgmac100.h F: docs/system/arm/aspeed.rst F: tests/qtest/*aspeed* +F: hw/arm/fby35.c NRF51 M: Joel Stanley @@ -1092,7 +1113,7 @@ F: include/hw/misc/avr_power.h F: hw/misc/avr_power.c Arduino -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Maintained F: hw/avr/arduino.c @@ -1113,9 +1134,30 @@ S: Odd Fixes F: configs/devices/hppa-softmmu/default.mak F: hw/hppa/ F: hw/net/*i82596* +F: hw/misc/lasi.c +F: hw/pci-host/dino.c +F: include/hw/misc/lasi.h F: include/hw/net/lasi_82596.h +F: include/hw/pci-host/dino.h F: pc-bios/hppa-firmware.img +LoongArch Machines +------------------ +Virt +M: Xiaojuan Yang +M: Song Gao +S: Maintained +F: docs/system/loongarch/virt.rst +F: configs/targets/loongarch64-softmmu.mak +F: configs/devices/loongarch64-softmmu/default.mak +F: hw/loongarch/ +F: include/hw/loongarch/virt.h +F: include/hw/intc/loongarch_*.h +F: hw/intc/loongarch_*.c +F: include/hw/pci-host/ls7a.h +F: hw/rtc/ls7a_rtc.c +F: gdb-xml/loongarch*.xml + M68K Machines ------------- an5206 @@ -1186,7 +1228,7 @@ F: hw/microblaze/petalogix_ml605_mmu.c MIPS Machines ------------- Overall MIPS Machines -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Odd Fixes F: configs/devices/mips*/* F: hw/mips/ @@ -1201,7 +1243,7 @@ F: hw/display/jazz_led.c F: hw/dma/rc4030.c Malta -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Aurelien Jarno S: Odd Fixes F: hw/isa/piix4.c @@ -1220,7 +1262,7 @@ F: hw/net/mipsnet.c Fuloong 2E M: Huacai Chen -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Jiaxun Yang S: Odd Fixes F: hw/mips/fuloong2e.c @@ -1254,11 +1296,12 @@ OpenRISC Machines or1k-sim M: Jia Liu S: Maintained +F: docs/system/openrisc/or1k-sim.rst 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 @@ -1304,6 +1347,7 @@ F: hw/nvram/mac_nvram.c F: hw/input/adb* F: include/hw/misc/macio/ F: include/hw/misc/mos6522.h +F: include/hw/nvram/mac_nvram.h F: include/hw/ppc/mac_dbdma.h F: include/hw/pci-host/uninorth.h F: include/hw/input/adb* @@ -1321,6 +1365,7 @@ F: hw/intc/heathrow_pic.c F: hw/input/adb* F: include/hw/intc/heathrow_pic.h F: include/hw/input/adb* +F: include/hw/pci-host/grackle.h F: pc-bios/qemu_vga.ndrv PReP @@ -1341,12 +1386,12 @@ F: include/hw/rtc/m48t59.h F: tests/avocado/ppc_prep_40p.py sPAPR (pseries) -M: Cédric Le Goater M: Daniel Henrique Barboza +R: Cédric Le Goater R: David Gibson R: Greg Kurz L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: hw/*/spapr* F: include/hw/*/spapr* F: hw/*/xics* @@ -1363,7 +1408,7 @@ F: tests/avocado/ppc_pseries.py PowerNV (Non-Virtualized) M: Cédric Le Goater L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: docs/system/ppc/powernv.rst F: hw/ppc/pnv* F: hw/intc/pnv* @@ -1623,8 +1668,8 @@ F: hw/isa/piix3.c F: hw/isa/lpc_ich9.c F: hw/i2c/smbus_ich9.c F: hw/acpi/piix4.c -F: hw/acpi/ich9.c -F: include/hw/acpi/ich9.h +F: hw/acpi/ich9*.c +F: include/hw/acpi/ich9*.h F: include/hw/southbridge/piix.h F: hw/misc/sga.c F: hw/isa/apm.c @@ -1676,7 +1721,7 @@ F: pc-bios/bios-microvm.bin Machine core M: Eduardo Habkost M: Marcel Apfelbaum -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé R: Yanan Wang S: Supported F: cpu.c @@ -1727,8 +1772,8 @@ F: tests/qtest/intel-hda-test.c F: tests/qtest/fuzz-sb16-test.c Xilinx CAN -M: Vikram Garhwal -M: Francisco Iglesias +M: Vikram Garhwal +M: Francisco Iglesias S: Maintained F: hw/net/can/xlnx-* F: include/hw/net/xlnx-* @@ -1776,6 +1821,12 @@ F: include/hw/block/fdc.h F: tests/qtest/fdc-test.c T: git https://gitlab.com/jsnow/qemu.git ide +Hyper-V VMBus +M: Maciej S. Szmigiero +S: Odd Fixes +F: hw/hyperv/vmbus.c +F: include/hw/hyperv/vmbus*.h + OMAP M: Peter Maydell L: qemu-arm@nongnu.org @@ -1802,6 +1853,13 @@ F: qapi/pci.json F: docs/pci* F: docs/specs/*pci* +PCIE DOE +M: Huai-Cheng Kuo +M: Chris Browy +S: Supported +F: include/hw/pci/pcie_doe.h +F: hw/pci/pcie_doe.c + ACPI/SMBIOS M: Michael S. Tsirkin M: Igor Mammedov @@ -1809,7 +1867,6 @@ R: Ani Sinha S: Supported F: include/hw/acpi/* F: include/hw/firmware/smbios.h -F: hw/mem/* F: hw/acpi/* F: hw/smbios/* F: hw/i386/acpi-build.[hc] @@ -1820,6 +1877,7 @@ F: tests/qtest/acpi-utils.[hc] F: tests/data/acpi/ F: docs/specs/acpi_cpu_hotplug.rst F: docs/specs/acpi_mem_hotplug.rst +F: docs/specs/acpi_nvdimm.rst F: docs/specs/acpi_pci_hotplug.rst F: docs/specs/acpi_hw_reduced_hotplug.rst @@ -1829,6 +1887,14 @@ S: Supported F: hw/acpi/viot.c F: hw/acpi/viot.h +ACPI/AVOCADO/BIOSBITS +M: Ani Sinha +M: Michael S. Tsirkin +S: Supported +F: tests/avocado/acpi-bits/* +F: tests/avocado/acpi-bits.py +F: docs/devel/acpi-bits.rst + ACPI/HEST/GHES R: Dongjiu Geng L: qemu-arm@nongnu.org @@ -1863,7 +1929,7 @@ F: docs/virtio-net-failover.rst T: git https://github.com/jasowang/qemu.git net Parallel NOR Flash devices -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé T: git https://gitlab.com/philmd/qemu.git pflash-next S: Maintained F: hw/block/pflash_cfi*.c @@ -1885,7 +1951,7 @@ SSI M: Alistair Francis S: Maintained F: hw/ssi/* -F: hw/block/m25p80.c +F: hw/block/m25p80* F: include/hw/ssi/ssi.h X: hw/ssi/xilinx_* F: tests/qtest/m25p80-test.c @@ -1896,7 +1962,7 @@ S: Maintained F: hw/ssi/xilinx_* SD (Secure Card) -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé M: Bin Meng L: qemu-block@nongnu.org S: Odd Fixes @@ -1963,6 +2029,7 @@ F: docs/interop/vhost-user.rst F: contrib/vhost-user-*/ F: backends/vhost-user.c F: include/sysemu/vhost-user-backend.h +F: subprojects/libvhost-user/ virtio M: Michael S. Tsirkin @@ -1970,8 +2037,10 @@ S: Supported F: hw/*/virtio* F: hw/virtio/Makefile.objs F: hw/virtio/trace-events +F: qapi/virtio.json F: net/vhost-user.c F: include/hw/virtio/ +F: docs/devel/virtio* virtio-balloon M: Michael S. Tsirkin @@ -1993,6 +2062,7 @@ X: hw/9pfs/xen-9p* F: fsdev/ F: docs/tools/virtfs-proxy-helper.rst F: tests/qtest/virtio-9p-test.c +F: tests/qtest/libqos/virtio-9p* T: git https://gitlab.com/gkurz/qemu.git 9p-next T: git https://github.com/cschoenebeck/qemu.git 9p.next @@ -2000,8 +2070,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 @@ -2011,8 +2083,7 @@ M: Halil Pasic M: Eric Farman S: Supported F: hw/s390x/virtio-ccw*.[hc] -F: hw/s390x/vhost-vsock-ccw.c -F: hw/s390x/vhost-user-fs-ccw.c +F: hw/s390x/vhost-*-ccw.c T: git https://gitlab.com/cohuck/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next L: qemu-s390x@nongnu.org @@ -2063,12 +2134,20 @@ F: tests/qtest/virtio-rng-test.c vhost-user-rng M: Mathieu Poirier S: Supported -F: docs/tools/vhost-user-rng.rst +F: docs/system/devices/vhost-user-rng.rst F: hw/virtio/vhost-user-rng.c 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 @@ -2093,7 +2172,7 @@ S: Supported F: hw/nvme/* F: include/block/nvme.h F: tests/qtest/nvme-test.c -F: docs/system/nvme.rst +F: docs/system/devices/nvme.rst T: git git://git.infradead.org/qemu-nvme.git nvme-next megasas @@ -2128,15 +2207,6 @@ F: qapi/rocker.json F: tests/rocker/ F: docs/specs/rocker.txt -NVDIMM -M: Xiao Guangrong -S: Maintained -F: hw/acpi/nvdimm.c -F: hw/mem/nvdimm.c -F: include/hw/mem/nvdimm.h -F: docs/nvdimm.txt -F: docs/specs/acpi_nvdimm.rst - e1000x M: Dmitry Fleytman S: Maintained @@ -2169,6 +2239,7 @@ Generic Loader M: Alistair Francis S: Maintained F: hw/core/generic-loader.c +F: hw/core/uboot_image.h F: include/hw/core/generic-loader.h F: docs/system/generic-loader.rst @@ -2202,14 +2273,14 @@ F: tests/qtest/vmgenid-test.c F: stubs/vmgenid.c LED -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Maintained F: include/hw/misc/led.h F: hw/misc/led.c Unimplemented device M: Peter Maydell -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé R: Ani Sinha S: Maintained F: include/hw/misc/unimp.h @@ -2217,7 +2288,7 @@ F: hw/misc/unimp.c Empty slot M: Artyom Tarasenko -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé R: Ani Sinha S: Maintained F: include/hw/misc/empty_slot.h @@ -2250,11 +2321,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 @@ -2279,13 +2352,13 @@ F: qemu-edid.c PIIX4 South Bridge (i82371AB) M: Hervé Poussineau -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Maintained F: hw/isa/piix4.c F: include/hw/southbridge/piix.h Firmware configuration (fw_cfg) -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Gerd Hoffmann S: Supported F: docs/specs/fw_cfg.txt @@ -2300,7 +2373,7 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next XIVE M: Cédric Le Goater L: qemu-ppc@nongnu.org -S: Supported +S: Odd Fixes F: hw/*/*xive* F: include/hw/*/*xive* F: docs/*/*xive* @@ -2341,13 +2414,13 @@ F: hw/intc/openpic.c F: include/hw/ppc/openpic.h MIPS CPS -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Odd Fixes F: hw/misc/mips_* F: include/hw/misc/mips_* MIPS GIC -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé S: Odd Fixes F: hw/intc/mips_gic.c F: hw/timer/mips_gictimer.c @@ -2396,6 +2469,14 @@ F: hw/intc/s390_flic*.c F: include/hw/s390x/s390_flic.h L: qemu-s390x@nongnu.org +CanoKey +M: Hongren (Zenithal) Zheng +S: Maintained +R: Canokeys.org +F: hw/usb/canokey.c +F: hw/usb/canokey.h +F: docs/system/devices/canokey.rst + Subsystems ---------- Overall Audio backends @@ -2409,6 +2490,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 @@ -2420,7 +2502,7 @@ F: audio/alsaaudio.c Core Audio framework backend M: Gerd Hoffmann -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Christian Schoenebeck R: Akihiko Odaki S: Odd Fixes @@ -2453,6 +2535,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 @@ -2461,7 +2549,10 @@ S: Supported F: block* F: block/ F: hw/block/ +F: qapi/block*.json +F: qapi/transaction.json F: include/block/ +F: include/sysemu/block-*.h F: qemu-img* F: docs/tools/qemu-img.rst F: qemu-io* @@ -2507,7 +2598,7 @@ F: scsi/* Block Jobs M: John Snow -M: Vladimir Sementsov-Ogievskiy +M: Vladimir Sementsov-Ogievskiy L: qemu-block@nongnu.org S: Supported F: blockjob.c @@ -2532,21 +2623,19 @@ F: block/aio_task.c F: util/qemu-co-shared-resource.c F: include/qemu/co-shared-resource.h T: git https://gitlab.com/jsnow/qemu.git jobs -T: git https://src.openvz.org/scm/~vsementsov/qemu.git jobs +T: git https://gitlab.com/vsementsov/qemu.git block -Block QAPI, monitor, command line -M: Markus Armbruster +Compute Express Link +M: Ben Widawsky +M: Jonathan Cameron S: Supported -F: blockdev.c -F: blockdev-hmp-cmds.c -F: block/qapi.c -F: qapi/block*.json -F: qapi/transaction.json -T: git https://repo.or.cz/qemu/armbru.git block-next +F: hw/cxl/ +F: hw/mem/cxl_type3.c +F: include/hw/cxl/ Dirty Bitmaps M: Eric Blake -M: Vladimir Sementsov-Ogievskiy +M: Vladimir Sementsov-Ogievskiy R: John Snow L: qemu-block@nongnu.org S: Supported @@ -2560,6 +2649,7 @@ F: util/hbitmap.c F: tests/unit/test-hbitmap.c F: docs/interop/bitmaps.rst T: git https://repo.or.cz/qemu/ericb.git bitmaps +T: git https://gitlab.com/vsementsov/qemu.git block Character device backends M: Marc-André Lureau @@ -2630,18 +2720,20 @@ F: scripts/coccinelle/errp-guard.cocci GDB stub M: Alex Bennée -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé S: Maintained -F: gdbstub* +F: docs/system/gdb.rst +F: gdbstub/* F: include/exec/gdbstub.h F: gdb-xml/ F: tests/tcg/multiarch/gdbstub/ +F: scripts/feature_to_c.sh Memory API M: Paolo Bonzini M: Peter Xu M: David Hildenbrand -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé S: Supported F: include/exec/ioport.h F: include/exec/memop.h @@ -2657,6 +2749,19 @@ F: softmmu/physmem.c F: include/exec/memory-internal.h F: scripts/coccinelle/memory-region-housekeeping.cocci +Memory devices +M: David Hildenbrand +M: Igor Mammedov +R: Xiao Guangrong +S: Supported +F: hw/mem/memory-device.c +F: hw/mem/nvdimm.c +F: hw/mem/pc-dimm.c +F: include/hw/mem/memory-device.h +F: include/hw/mem/nvdimm.h +F: include/hw/mem/pc-dimm.h +F: docs/nvdimm.txt + SPICE M: Gerd Hoffmann S: Odd Fixes @@ -2675,10 +2780,11 @@ F: ui/ F: include/ui/ F: qapi/ui.json F: util/drm.c +F: docs/devel/ui.rst Cocoa graphics M: Peter Maydell -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Akihiko Odaki S: Odd Fixes F: ui/cocoa.m @@ -2699,6 +2805,7 @@ F: softmmu/cpu-throttle.c F: softmmu/cpu-timers.c F: softmmu/icount.c F: softmmu/runstate-action.c +F: softmmu/runstate.c F: qapi/run-state.json Read, Copy, Update (RCU) @@ -2770,16 +2877,17 @@ F: scripts/*.py F: tests/*.py Benchmark util -M: Vladimir Sementsov-Ogievskiy +M: Vladimir Sementsov-Ogievskiy S: Maintained F: scripts/simplebench/ -T: git https://src.openvz.org/scm/~vsementsov/qemu.git simplebench +T: git https://gitlab.com/vsementsov/qemu.git simplebench Transactions helper -M: Vladimir Sementsov-Ogievskiy +M: Vladimir Sementsov-Ogievskiy S: Maintained F: include/qemu/transactions.h F: util/transactions.c +T: git https://gitlab.com/vsementsov/qemu.git block QAPI M: Markus Armbruster @@ -2828,6 +2936,7 @@ T: git https://repo.or.cz/qemu/armbru.git qapi-next QEMU Guest Agent M: Michael Roth +M: Konstantin Kostiuk S: Maintained F: qga/ F: docs/interop/qemu-ga.rst @@ -2849,6 +2958,7 @@ M: Paolo Bonzini R: Daniel P. Berrange R: Eduardo Habkost S: Supported +F: docs/devel/qom.rst F: docs/qdev-device-use.txt F: hw/core/qdev* F: hw/core/bus.c @@ -2897,6 +3007,7 @@ F: softmmu/qtest.c F: accel/qtest/ F: tests/qtest/ F: docs/devel/qgraph.rst +F: docs/devel/qtest.rst X: tests/qtest/bios-tables-test* Device Fuzzing @@ -2924,7 +3035,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 @@ -2964,6 +3074,7 @@ F: include/sysemu/tpm* F: qapi/tpm.json F: backends/tpm/ F: tests/qtest/*tpm* +F: docs/specs/tpm.rst T: git https://github.com/stefanberger/qemu-tpm.git tpm-next Checkpatch @@ -3089,7 +3200,7 @@ F: include/qemu/yank.h F: qapi/yank.json COLO Framework -M: zhanghailiang +M: Hailiang Zhang S: Maintained F: migration/colo* F: include/migration/colo.h @@ -3115,7 +3226,8 @@ F: replay/* F: block/blkreplay.c F: net/filter-replay.c F: include/sysemu/replay.h -F: docs/replay.txt +F: docs/devel/replay.rst +F: docs/system/replay.rst F: stubs/replay.c F: tests/avocado/replay_kernel.py F: tests/avocado/replay_linux.py @@ -3159,14 +3271,14 @@ F: tests/qtest/max34451-test.c F: tests/qtest/isl_pmbus_vr-test.c Firmware schema specifications -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Daniel P. Berrange R: Kashyap Chamarthy S: Maintained F: docs/interop/firmware.json EDK2 Firmware -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé M: Gerd Hoffmann S: Supported F: hw/i386/*ovmf* @@ -3259,21 +3371,17 @@ M: Richard Henderson S: Maintained L: qemu-arm@nongnu.org F: tcg/aarch64/ -F: disas/arm-a64.cc -F: disas/libvixl/ ARM TCG target M: Richard Henderson S: Maintained L: qemu-arm@nongnu.org F: tcg/arm/ -F: disas/arm.c i386 TCG target M: Richard Henderson S: Maintained F: tcg/i386/ -F: disas/i386.c LoongArch64 TCG target M: WANG Xuerui @@ -3281,7 +3389,7 @@ S: Maintained F: tcg/loongarch64/ MIPS TCG target -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé R: Aurelien Jarno R: Huacai Chen R: Jiaxun Yang @@ -3293,7 +3401,6 @@ PPC TCG target M: Richard Henderson S: Odd Fixes F: tcg/ppc/ -F: disas/ppc.c RISC-V TCG target M: Palmer Dabbelt @@ -3307,12 +3414,11 @@ S390 TCG target M: Richard Henderson S: Maintained F: tcg/s390/ -F: disas/s390.c L: qemu-s390x@nongnu.org SPARC TCG target S: Odd Fixes -F: tcg/sparc/ +F: tcg/sparc64/ F: disas/sparc.c TCI TCG target @@ -3349,6 +3455,12 @@ L: qemu-block@nongnu.org S: Maintained F: block/vdi.c +blkio +M: Stefan Hajnoczi +L: qemu-block@nongnu.org +S: Maintained +F: block/blkio.c + iSCSI M: Ronnie Sahlberg M: Paolo Bonzini @@ -3360,7 +3472,7 @@ F: block/iscsi-opts.c Network Block Device (NBD) M: Eric Blake -M: Vladimir Sementsov-Ogievskiy +M: Vladimir Sementsov-Ogievskiy L: qemu-block@nongnu.org S: Maintained F: block/nbd* @@ -3370,8 +3482,9 @@ F: qemu-nbd.* F: blockdev-nbd.c F: docs/interop/nbd.txt F: docs/tools/qemu-nbd.rst +F: tests/qemu-iotests/tests/*nbd* T: git https://repo.or.cz/qemu/ericb.git nbd -T: git https://src.openvz.org/scm/~vsementsov/qemu.git nbd +T: git https://gitlab.com/vsementsov/qemu.git block NFS M: Peter Lieven @@ -3405,7 +3518,7 @@ F: block/null.c NVMe Block Driver M: Stefan Hajnoczi R: Fam Zheng -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé L: qemu-block@nongnu.org S: Supported F: block/nvme* @@ -3456,13 +3569,13 @@ F: block/dmg.c parallels M: Stefan Hajnoczi M: Denis V. Lunev -M: Vladimir Sementsov-Ogievskiy +M: Vladimir Sementsov-Ogievskiy L: qemu-block@nongnu.org S: Supported F: block/parallels.c F: block/parallels-ext.c F: docs/interop/parallels.txt -T: git https://src.openvz.org/scm/~vsementsov/qemu.git parallels +T: git https://gitlab.com/vsementsov/qemu.git block qed M: Stefan Hajnoczi @@ -3535,6 +3648,8 @@ M: Coiby Xu S: Maintained F: block/export/vhost-user-blk-server.c F: block/export/vhost-user-blk-server.h +F: block/export/virtio-blk-handler.c +F: block/export/virtio-blk-handler.h F: include/qemu/vhost-user-server.h F: tests/qtest/libqos/vhost-user-blk.c F: tests/qtest/libqos/vhost-user-blk.h @@ -3547,6 +3662,13 @@ L: qemu-block@nongnu.org S: Supported F: block/export/fuse.c +VDUSE library and block device exports +M: Xie Yongji +S: Maintained +F: subprojects/libvduse/ +F: block/export/vduse-blk.c +F: block/export/vduse-blk.h + Replication M: Wen Congyang M: Xie Changlong @@ -3597,6 +3719,11 @@ F: hw/remote/proxy-memory-listener.c F: include/hw/remote/proxy-memory-listener.h F: hw/remote/iohub.c F: include/hw/remote/iohub.h +F: subprojects/libvfio-user +F: hw/remote/vfio-user-obj.c +F: include/hw/remote/vfio-user-obj.h +F: hw/remote/iommu.c +F: include/hw/remote/iommu.h EBPF: M: Jason Wang @@ -3610,7 +3737,7 @@ Build and test automation ------------------------- Build and test automation, general continuous integration M: Alex Bennée -M: Philippe Mathieu-Daudé +M: Philippe Mathieu-Daudé M: Thomas Huth R: Wainer dos Santos Moschetta R: Beraldo Leal @@ -3624,6 +3751,7 @@ F: tests/docker/ F: tests/vm/ F: tests/lcitool/ F: scripts/archive-source.sh +F: docs/devel/testing.rst W: https://gitlab.com/qemu-project/qemu/pipelines W: https://travis-ci.org/qemu/qemu @@ -3643,15 +3771,14 @@ W: https://cirrus-ci.com/github/qemu/qemu Guest Test Compilation Support M: Alex Bennée -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé S: Maintained -F: tests/tcg/Makefile -F: tests/tcg/Makefile.include +F: tests/tcg/Makefile.target Integration Testing with the Avocado framework W: https://trello.com/b/6Qi1pxVn/avocado-qemu R: Cleber Rosa -R: Philippe Mathieu-Daudé +R: Philippe Mathieu-Daudé R: Wainer dos Santos Moschetta R: Beraldo Leal S: Odd Fixes @@ -3659,9 +3786,10 @@ F: tests/avocado/ GitLab custom runner (Works On Arm Sponsored) M: Alex Bennée -M: Philippe Mathieu-Daudé +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 ------------- @@ -3682,6 +3810,29 @@ F: docs/about/deprecated.rst Build System ------------ +Meson +M: Paolo Bonzini +R: Marc-André Lureau +R: Daniel P. Berrange +R: Thomas Huth +R: Philippe Mathieu-Daudé +S: Maintained +F: meson.build +F: meson_options.txt +F: scripts/meson-buildoptions.* +F: scripts/check_sparse.py +F: scripts/symlink-install-tree.py + +Top Level Makefile and configure +M: Paolo Bonzini +R: Alex Bennée +R: Thomas Huth +S: Maintained +F: Makefile +F: configure +F: scripts/mtest2make.py +F: tests/Makefile.include + GIT submodules M: Daniel P. Berrange S: Odd Fixes diff --git a/Makefile b/Makefile index e5fd1ebdf619..a48103cc8a1a 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 @@ -87,7 +90,7 @@ x := $(shell rm -rf meson-private meson-info meson-logs) endif # 1. ensure config-host.mak is up-to-date -config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION +config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/VERSION @echo config-host.mak is out-of-date, running configure @if test -f meson-private/coredata.dat; then \ ./config.status --skip-meson; \ @@ -143,10 +146,9 @@ MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS)))) MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq) 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 t, $(.check.build-suites), $(.check-$t.deps)) -ninja-cmd-goals += $(foreach t, $(.bench.build-suites), $(.bench-$t.deps)) +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 @@ -160,15 +162,12 @@ $(ninja-targets): run-ninja # --output-sync line. run-ninja: config-host.mak ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),) - +$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) -d keepdepfile \ - $(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat) + +$(if $(MAKE.nq),@:,$(quiet-@)$(NINJA) $(NINJAFLAGS) \ + $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat) endif endif -# Force configure to re-run if the API symbols are updated ifeq ($(CONFIG_PLUGIN),y) -config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols - .PHONY: plugins plugins: $(call quiet-command,\ @@ -190,16 +189,15 @@ include $(SRC_PATH)/tests/Makefile.include all: recurse-all -ROM_DIRS = $(addprefix pc-bios/, $(ROMS)) -ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS))) -# Only keep -O and -g cflags -.PHONY: $(ROM_DIRS_RULES) -$(ROM_DIRS_RULES): +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 $@),) .PHONY: recurse-all recurse-clean -recurse-all: $(addsuffix /all, $(ROM_DIRS)) -recurse-clean: $(addsuffix /clean, $(ROM_DIRS)) +recurse-all: $(addsuffix /all, $(ROMS)) +recurse-clean: $(addsuffix /clean, $(ROMS)) +recurse-distclean: $(addsuffix /distclean, $(ROMS)) ###################################################################### @@ -220,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 - 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.rst b/README.rst index 23795b837740..455f8e332047 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,9 @@ +============= +NXP QEMU repo +============= + +https://github.com/nxp-zephyr/qemu/wiki + =========== QEMU README =========== @@ -39,7 +45,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 +84,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/SCR-qemu.txt b/SCR-qemu.txt new file mode 100755 index 000000000000..7d6f7227efff --- /dev/null +++ b/SCR-qemu.txt @@ -0,0 +1,11 @@ +NXP Software Content Register +-------------------------------------------- +Package: qemu.git +Version: 7.2.50 +Outgoing License: GPL-2.0 +License File: LICENSE +Type of Content: source +Description and comments: NXP extension works based on qemu project. mainly add RT595 board supporting, and this is demoed on ZDS2023 conference. +Release Location: https://github.com/nxp-zephyr/qemu +Origin: qemu(https://github.com/qemu/qemu) (GPL-2.0) + NXP (GPL-2.0) diff --git a/VERSION b/VERSION index 66ce77b7ead5..d182ea165064 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0 +7.2.50 diff --git a/accel/accel-blocker.c b/accel/accel-blocker.c new file mode 100644 index 000000000000..1e7f423462df --- /dev/null +++ b/accel/accel-blocker.c @@ -0,0 +1,154 @@ +/* + * Lock to inhibit accelerator ioctls + * + * Copyright (c) 2022 Red Hat Inc. + * + * Author: Emanuele Giuseppe Esposito + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/thread.h" +#include "qemu/main-loop.h" +#include "hw/core/cpu.h" +#include "sysemu/accel-blocker.h" + +static QemuLockCnt accel_in_ioctl_lock; +static QemuEvent accel_in_ioctl_event; + +void accel_blocker_init(void) +{ + qemu_lockcnt_init(&accel_in_ioctl_lock); + qemu_event_init(&accel_in_ioctl_event, false); +} + +void accel_ioctl_begin(void) +{ + if (likely(qemu_mutex_iothread_locked())) { + return; + } + + /* block if lock is taken in kvm_ioctl_inhibit_begin() */ + qemu_lockcnt_inc(&accel_in_ioctl_lock); +} + +void accel_ioctl_end(void) +{ + if (likely(qemu_mutex_iothread_locked())) { + return; + } + + qemu_lockcnt_dec(&accel_in_ioctl_lock); + /* change event to SET. If event was BUSY, wake up all waiters */ + qemu_event_set(&accel_in_ioctl_event); +} + +void accel_cpu_ioctl_begin(CPUState *cpu) +{ + if (unlikely(qemu_mutex_iothread_locked())) { + return; + } + + /* block if lock is taken in kvm_ioctl_inhibit_begin() */ + qemu_lockcnt_inc(&cpu->in_ioctl_lock); +} + +void accel_cpu_ioctl_end(CPUState *cpu) +{ + if (unlikely(qemu_mutex_iothread_locked())) { + return; + } + + qemu_lockcnt_dec(&cpu->in_ioctl_lock); + /* change event to SET. If event was BUSY, wake up all waiters */ + qemu_event_set(&accel_in_ioctl_event); +} + +static bool accel_has_to_wait(void) +{ + CPUState *cpu; + bool needs_to_wait = false; + + CPU_FOREACH(cpu) { + if (qemu_lockcnt_count(&cpu->in_ioctl_lock)) { + /* exit the ioctl, if vcpu is running it */ + qemu_cpu_kick(cpu); + needs_to_wait = true; + } + } + + return needs_to_wait || qemu_lockcnt_count(&accel_in_ioctl_lock); +} + +void accel_ioctl_inhibit_begin(void) +{ + CPUState *cpu; + + /* + * We allow to inhibit only when holding the BQL, so we can identify + * when an inhibitor wants to issue an ioctl easily. + */ + g_assert(qemu_mutex_iothread_locked()); + + /* Block further invocations of the ioctls outside the BQL. */ + CPU_FOREACH(cpu) { + qemu_lockcnt_lock(&cpu->in_ioctl_lock); + } + qemu_lockcnt_lock(&accel_in_ioctl_lock); + + /* Keep waiting until there are running ioctls */ + while (true) { + + /* Reset event to FREE. */ + qemu_event_reset(&accel_in_ioctl_event); + + if (accel_has_to_wait()) { + /* + * If event is still FREE, and there are ioctls still in progress, + * wait. + * + * If an ioctl finishes before qemu_event_wait(), it will change + * the event state to SET. This will prevent qemu_event_wait() from + * blocking, but it's not a problem because if other ioctls are + * still running the loop will iterate once more and reset the event + * status to FREE so that it can wait properly. + * + * If an ioctls finishes while qemu_event_wait() is blocking, then + * it will be waken up, but also here the while loop makes sure + * to re-enter the wait if there are other running ioctls. + */ + qemu_event_wait(&accel_in_ioctl_event); + } else { + /* No ioctl is running */ + return; + } + } +} + +void accel_ioctl_inhibit_end(void) +{ + CPUState *cpu; + + qemu_lockcnt_unlock(&accel_in_ioctl_lock); + CPU_FOREACH(cpu) { + qemu_lockcnt_unlock(&cpu->in_ioctl_lock); + } +} + diff --git a/accel/accel-common.c b/accel/accel-common.c index 7b8ec7e0f72a..df72cc989a9b 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -49,6 +49,14 @@ AccelClass *accel_find(const char *opt_name) return ac; } +/* Return the name of the current accelerator */ +const char *current_accel_name(void) +{ + AccelClass *ac = ACCEL_GET_CLASS(current_accel()); + + return ac->name; +} + static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque) { CPUClass *cc = CPU_CLASS(klass); @@ -121,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/accel-softmmu.c b/accel/accel-softmmu.c index 67276e4f5222..f9cdafb148ac 100644 --- a/accel/accel-softmmu.c +++ b/accel/accel-softmmu.c @@ -66,6 +66,7 @@ void accel_init_ops_interfaces(AccelClass *ac) { const char *ac_name; char *ops_name; + ObjectClass *oc; AccelOpsClass *ops; ac_name = object_class_get_name(OBJECT_CLASS(ac)); @@ -73,8 +74,13 @@ void accel_init_ops_interfaces(AccelClass *ac) ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name); ops = ACCEL_OPS_CLASS(module_object_class_by_name(ops_name)); + oc = module_object_class_by_name(ops_name); + if (!oc) { + error_report("fatal: could not load module for type '%s'", ops_name); + exit(1); + } g_free(ops_name); - + ops = ACCEL_OPS_CLASS(oc); /* * all accelerators need to define ops, providing at least a mandatory * non-NULL create_vcpu_thread operation. diff --git a/accel/dummy-cpus.c b/accel/dummy-cpus.c index 10429fdfb255..d6a1b8d0a277 100644 --- a/accel/dummy-cpus.c +++ b/accel/dummy-cpus.c @@ -21,8 +21,6 @@ static void *dummy_cpu_thread_fn(void *arg) { CPUState *cpu = arg; - sigset_t waitset; - int r; rcu_register_thread(); @@ -32,8 +30,13 @@ static void *dummy_cpu_thread_fn(void *arg) cpu->can_do_io = 1; current_cpu = cpu; +#ifndef _WIN32 + sigset_t waitset; + int r; + sigemptyset(&waitset); sigaddset(&waitset, SIG_IPI); +#endif /* signal CPU creation */ cpu_thread_signal_created(cpu); @@ -41,6 +44,7 @@ static void *dummy_cpu_thread_fn(void *arg) do { qemu_mutex_unlock_iothread(); +#ifndef _WIN32 do { int sig; r = sigwait(&waitset, &sig); @@ -49,6 +53,9 @@ static void *dummy_cpu_thread_fn(void *arg) perror("sigwait"); exit(1); } +#else + qemu_sem_wait(&cpu->sem); +#endif qemu_mutex_lock_iothread(); qemu_wait_io_event(cpu); } while (!cpu->unplug); @@ -69,4 +76,7 @@ void dummy_start_vcpu_thread(CPUState *cpu) cpu->cpu_index); qemu_thread_create(cpu->thread, thread_name, dummy_cpu_thread_fn, cpu, QEMU_THREAD_JOINABLE); +#ifdef _WIN32 + qemu_sem_init(&cpu->sem, 0); +#endif } diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 54457c76c2f3..24913ca9c49f 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -120,12 +120,12 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add) { hvf_slot *mem; MemoryRegion *area = section->mr; - bool writeable = !area->readonly && !area->rom_device; + bool writable = !area->readonly && !area->rom_device; hv_memory_flags_t flags; - uint64_t page_size = qemu_real_host_page_size; + uint64_t page_size = qemu_real_host_page_size(); if (!memory_region_is_ram(area)) { - if (writeable) { + if (writable) { return; } else if (!memory_region_is_romd(area)) { /* diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c index f185b0830a75..0043f4d308ba 100644 --- a/accel/hvf/hvf-all.c +++ b/accel/hvf/hvf-all.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "sysemu/hvf.h" #include "sysemu/hvf_int.h" diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index c4244a23c651..fbf4fe34975d 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 5f1377ca048c..7e6a6076b16c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -31,6 +31,7 @@ #include "sysemu/kvm_int.h" #include "sysemu/runstate.h" #include "sysemu/cpus.h" +#include "sysemu/accel-blocker.h" #include "qemu/bswap.h" #include "exec/memory.h" #include "exec/ram_addr.h" @@ -45,8 +46,11 @@ #include "qemu/guest-random.h" #include "sysemu/hw_accel.h" #include "kvm-cpus.h" +#include "sysemu/dirtylimit.h" +#include "qemu/range.h" #include "hw/boards.h" +#include "monitor/stats.h" /* This check must be after config-host.h is included */ #ifdef CONFIG_EVENTFD @@ -59,7 +63,7 @@ #ifdef PAGE_SIZE #undef PAGE_SIZE #endif -#define PAGE_SIZE qemu_real_host_page_size +#define PAGE_SIZE qemu_real_host_page_size() #ifndef KVM_GUESTDBG_BLOCKIRQ #define KVM_GUESTDBG_BLOCKIRQ 0 @@ -75,86 +79,12 @@ do { } while (0) #endif -#define KVM_MSI_HASHTAB_SIZE 256 - struct KVMParkedVcpu { unsigned long vcpu_id; int kvm_fd; QLIST_ENTRY(KVMParkedVcpu) node; }; -enum KVMDirtyRingReaperState { - KVM_DIRTY_RING_REAPER_NONE = 0, - /* The reaper is sleeping */ - KVM_DIRTY_RING_REAPER_WAIT, - /* The reaper is reaping for dirty pages */ - KVM_DIRTY_RING_REAPER_REAPING, -}; - -/* - * KVM reaper instance, responsible for collecting the KVM dirty bits - * via the dirty ring. - */ -struct KVMDirtyRingReaper { - /* The reaper thread */ - QemuThread reaper_thr; - volatile uint64_t reaper_iteration; /* iteration number of reaper thr */ - volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */ -}; - -struct KVMState -{ - AccelState parent_obj; - - int nr_slots; - int fd; - int vmfd; - int coalesced_mmio; - int coalesced_pio; - struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; - bool coalesced_flush_in_progress; - int vcpu_events; - int robust_singlestep; - int debugregs; -#ifdef KVM_CAP_SET_GUEST_DEBUG - QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; -#endif - int max_nested_state_len; - int many_ioeventfds; - int intx_set_mask; - int kvm_shadow_mem; - bool kernel_irqchip_allowed; - bool kernel_irqchip_required; - OnOffAuto kernel_irqchip_split; - bool sync_mmu; - uint64_t manual_dirty_log_protect; - /* The man page (and posix) say ioctl numbers are signed int, but - * they're not. Linux, glibc and *BSD all treat ioctl numbers as - * unsigned, and treating them as signed here can break things */ - unsigned irq_set_ioctl; - unsigned int sigmask_len; - GHashTable *gsimap; -#ifdef KVM_CAP_IRQ_ROUTING - struct kvm_irq_routing *irq_routes; - int nr_allocated_irq_routes; - unsigned long *used_gsi_bitmap; - unsigned int gsi_count; - QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; -#endif - KVMMemoryListener memory_listener; - QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; - - /* For "info mtree -f" to tell if an MR is registered in KVM */ - int nr_as; - struct KVMAs { - KVMMemoryListener *ml; - AddressSpace *as; - } *as; - uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */ - uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */ - struct KVMDirtyRingReaper reaper; -}; - KVMState *kvm_state; bool kvm_kernel_irqchip; bool kvm_split_irqchip; @@ -173,7 +103,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; @@ -324,14 +254,14 @@ static hwaddr kvm_align_section(MemoryRegionSection *section, with sub-page size and unaligned start address. Pad the start address to next and truncate size to previous page boundary. */ aligned = ROUND_UP(section->offset_within_address_space, - qemu_real_host_page_size); + qemu_real_host_page_size()); delta = aligned - section->offset_within_address_space; *start = aligned; if (delta > size) { return 0; } - return (size - delta) & qemu_real_host_page_mask; + return (size - delta) & qemu_real_host_page_mask(); } int kvm_physical_memory_addr_from_host(KVMState *s, void *ram, @@ -476,6 +406,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) cpu->kvm_state = s; cpu->vcpu_dirty = true; cpu->dirty_pages = 0; + cpu->throttle_us_per_full = 0; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { @@ -626,7 +557,7 @@ static void kvm_log_stop(MemoryListener *listener, static void kvm_slot_sync_dirty_pages(KVMSlot *slot) { ram_addr_t start = slot->ram_start_offset; - ram_addr_t pages = slot->memory_size / qemu_real_host_page_size; + ram_addr_t pages = slot->memory_size / qemu_real_host_page_size(); cpu_physical_memory_set_dirty_lebitmap(slot->dirty_bmap, start, pages); } @@ -662,7 +593,7 @@ static void kvm_slot_init_dirty_bitmap(KVMSlot *mem) * And mem->memory_size is aligned to it (otherwise this mem can't * be registered to KVM). */ - hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size, + hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size(), /*HOST_LONG_BITS*/ 64) / 8; mem->dirty_bmap = g_malloc0(bitmap_size); mem->dirty_bmap_size = bitmap_size; @@ -707,7 +638,7 @@ static void kvm_dirty_ring_mark_page(KVMState *s, uint32_t as_id, mem = &kml->slots[slot_id]; if (!mem->memory_size || offset >= - (mem->memory_size / qemu_real_host_page_size)) { + (mem->memory_size / qemu_real_host_page_size())) { return; } @@ -716,12 +647,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); } /* @@ -756,17 +707,20 @@ static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu) } /* Must be with slots_lock held */ -static uint64_t kvm_dirty_ring_reap_locked(KVMState *s) +static uint64_t kvm_dirty_ring_reap_locked(KVMState *s, CPUState* cpu) { int ret; - CPUState *cpu; uint64_t total = 0; int64_t stamp; stamp = get_clock(); - CPU_FOREACH(cpu) { - total += kvm_dirty_ring_reap_one(s, cpu); + if (cpu) { + total = kvm_dirty_ring_reap_one(s, cpu); + } else { + CPU_FOREACH(cpu) { + total += kvm_dirty_ring_reap_one(s, cpu); + } } if (total) { @@ -787,7 +741,7 @@ static uint64_t kvm_dirty_ring_reap_locked(KVMState *s) * Currently for simplicity, we must hold BQL before calling this. We can * consider to drop the BQL if we're clear with all the race conditions. */ -static uint64_t kvm_dirty_ring_reap(KVMState *s) +static uint64_t kvm_dirty_ring_reap(KVMState *s, CPUState *cpu) { uint64_t total; @@ -807,7 +761,7 @@ static uint64_t kvm_dirty_ring_reap(KVMState *s) * reset below. */ kvm_slots_lock(); - total = kvm_dirty_ring_reap_locked(s); + total = kvm_dirty_ring_reap_locked(s, cpu); kvm_slots_unlock(); return total; @@ -854,7 +808,7 @@ static void kvm_dirty_ring_flush(void) * vcpus out in a synchronous way. */ kvm_cpu_synchronize_kick_all(); - kvm_dirty_ring_reap(kvm_state); + kvm_dirty_ring_reap(kvm_state, NULL); trace_kvm_dirty_ring_flush(1); } @@ -895,7 +849,7 @@ static void kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, /* Alignment requirement for KVM_CLEAR_DIRTY_LOG - 64 pages */ #define KVM_CLEAR_LOG_SHIFT 6 -#define KVM_CLEAR_LOG_ALIGN (qemu_real_host_page_size << KVM_CLEAR_LOG_SHIFT) +#define KVM_CLEAR_LOG_ALIGN (qemu_real_host_page_size() << KVM_CLEAR_LOG_SHIFT) #define KVM_CLEAR_LOG_MASK (-KVM_CLEAR_LOG_ALIGN) static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start, @@ -904,7 +858,7 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start, KVMState *s = kvm_state; uint64_t end, bmap_start, start_delta, bmap_npages; struct kvm_clear_dirty_log d; - unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size; + unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size(); int ret; /* @@ -1202,8 +1156,8 @@ void kvm_hwpoison_page_add(ram_addr_t ram_addr) static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size) { -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) - /* The kernel expects ioeventfd values in HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN + /* The kernel expects ioeventfd values in HOST_BIG_ENDIAN * endianness, but the memory core hands them in target endianness. * For example, PPC is always treated as big-endian even if running * on KVM and on PPC64LE. Correct here. @@ -1335,24 +1289,25 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) void kvm_set_max_memslot_size(hwaddr max_slot_size) { g_assert( - ROUND_UP(max_slot_size, qemu_real_host_page_size) == max_slot_size + ROUND_UP(max_slot_size, qemu_real_host_page_size()) == max_slot_size ); kvm_max_slot_size = max_slot_size; } +/* Called with KVMMemoryListener.slots_lock held */ static void kvm_set_phys_mem(KVMMemoryListener *kml, MemoryRegionSection *section, bool add) { KVMSlot *mem; int err; MemoryRegion *mr = section->mr; - bool writeable = !mr->readonly && !mr->rom_device; + bool writable = !mr->readonly && !mr->rom_device; hwaddr start_addr, size, slot_size, mr_offset; ram_addr_t ram_start_offset; void *ram; if (!memory_region_is_ram(mr)) { - if (writeable || !kvm_readonly_mem_allowed) { + if (writable || !kvm_readonly_mem_allowed) { return; } else if (!mr->romd_mode) { /* If the memory device is not in romd_mode, then we actually want @@ -1374,14 +1329,12 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, ram = memory_region_get_ram_ptr(mr) + mr_offset; ram_start_offset = memory_region_get_ram_addr(mr) + mr_offset; - kvm_slots_lock(); - if (!add) { do { slot_size = MIN(kvm_max_slot_size, size); mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); if (!mem) { - goto out; + return; } if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { /* @@ -1398,7 +1351,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, * Not easy. Let's cross the fingers until it's fixed. */ if (kvm_state->kvm_dirty_ring_size) { - kvm_dirty_ring_reap_locked(kvm_state); + kvm_dirty_ring_reap_locked(kvm_state, NULL); } else { kvm_slot_get_dirty_log(kvm_state, mem); } @@ -1419,7 +1372,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, start_addr += slot_size; size -= slot_size; } while (size); - goto out; + return; } /* register the new slot */ @@ -1444,9 +1397,6 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, ram += slot_size; size -= slot_size; } while (size); - -out: - kvm_slots_unlock(); } static void *kvm_dirty_ring_reaper_thread(void *data) @@ -1466,11 +1416,16 @@ static void *kvm_dirty_ring_reaper_thread(void *data) */ sleep(1); + /* keep sleeping so that dirtylimit not be interfered by reaper */ + if (dirtylimit_in_service()) { + continue; + } + trace_kvm_dirty_ring_reaper("wakeup"); r->reaper_state = KVM_DIRTY_RING_REAPER_REAPING; qemu_mutex_lock_iothread(); - kvm_dirty_ring_reap(s); + kvm_dirty_ring_reap(s, NULL); qemu_mutex_unlock_iothread(); r->reaper_iteration++; @@ -1498,18 +1453,95 @@ static void kvm_region_add(MemoryListener *listener, MemoryRegionSection *section) { KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener); + KVMMemoryUpdate *update; - memory_region_ref(section->mr); - kvm_set_phys_mem(kml, section, true); + update = g_new0(KVMMemoryUpdate, 1); + update->section = *section; + + QSIMPLEQ_INSERT_TAIL(&kml->transaction_add, update, next); } static void kvm_region_del(MemoryListener *listener, MemoryRegionSection *section) { KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener); + KVMMemoryUpdate *update; + + update = g_new0(KVMMemoryUpdate, 1); + update->section = *section; + + QSIMPLEQ_INSERT_TAIL(&kml->transaction_del, update, next); +} + +static void kvm_region_commit(MemoryListener *listener) +{ + KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, + listener); + KVMMemoryUpdate *u1, *u2; + bool need_inhibit = false; + + if (QSIMPLEQ_EMPTY(&kml->transaction_add) && + QSIMPLEQ_EMPTY(&kml->transaction_del)) { + return; + } + + /* + * We have to be careful when regions to add overlap with ranges to remove. + * We have to simulate atomic KVM memslot updates by making sure no ioctl() + * is currently active. + * + * The lists are order by addresses, so it's easy to find overlaps. + */ + u1 = QSIMPLEQ_FIRST(&kml->transaction_del); + u2 = QSIMPLEQ_FIRST(&kml->transaction_add); + while (u1 && u2) { + Range r1, r2; + + range_init_nofail(&r1, u1->section.offset_within_address_space, + int128_get64(u1->section.size)); + range_init_nofail(&r2, u2->section.offset_within_address_space, + int128_get64(u2->section.size)); + + if (range_overlaps_range(&r1, &r2)) { + need_inhibit = true; + break; + } + if (range_lob(&r1) < range_lob(&r2)) { + u1 = QSIMPLEQ_NEXT(u1, next); + } else { + u2 = QSIMPLEQ_NEXT(u2, next); + } + } + + kvm_slots_lock(); + if (need_inhibit) { + accel_ioctl_inhibit_begin(); + } + + /* Remove all memslots before adding the new ones. */ + while (!QSIMPLEQ_EMPTY(&kml->transaction_del)) { + u1 = QSIMPLEQ_FIRST(&kml->transaction_del); + QSIMPLEQ_REMOVE_HEAD(&kml->transaction_del, next); + + kvm_set_phys_mem(kml, &u1->section, false); + memory_region_unref(u1->section.mr); - kvm_set_phys_mem(kml, section, false); - memory_region_unref(section->mr); + g_free(u1); + } + while (!QSIMPLEQ_EMPTY(&kml->transaction_add)) { + u1 = QSIMPLEQ_FIRST(&kml->transaction_add); + QSIMPLEQ_REMOVE_HEAD(&kml->transaction_add, next); + + memory_region_ref(u1->section.mr); + kvm_set_phys_mem(kml, &u1->section, true); + + g_free(u1); + } + + if (need_inhibit) { + accel_ioctl_inhibit_end(); + } + kvm_slots_unlock(); } static void kvm_log_sync(MemoryListener *listener, @@ -1653,8 +1685,12 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, kml->slots[i].slot = i; } + QSIMPLEQ_INIT(&kml->transaction_add); + QSIMPLEQ_INIT(&kml->transaction_del); + kml->listener.region_add = kvm_region_add; kml->listener.region_del = kvm_region_del; + kml->listener.commit = kvm_region_commit; kml->listener.log_start = kvm_log_start; kml->listener.log_stop = kvm_log_stop; kml->listener.priority = 10; @@ -2254,7 +2290,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); @@ -2310,6 +2346,15 @@ bool kvm_dirty_ring_enabled(void) return kvm_state->kvm_dirty_ring_size ? true : false; } +static void query_stats_cb(StatsResultList **result, StatsTarget target, + strList *names, strList *targets, Error **errp); +static void query_stats_schemas_cb(StatsSchemaList **result, Error **errp); + +uint32_t kvm_dirty_ring_size(void) +{ + return kvm_state->kvm_dirty_ring_size; +} + static int kvm_init(MachineState *ms) { MachineClass *mc = MACHINE_GET_CLASS(ms); @@ -2341,9 +2386,10 @@ static int kvm_init(MachineState *ms) * even with KVM. TARGET_PAGE_SIZE is assumed to be the minimum * page size for the system though. */ - assert(TARGET_PAGE_SIZE <= qemu_real_host_page_size); + assert(TARGET_PAGE_SIZE <= qemu_real_host_page_size()); s->sigmask_len = 8; + accel_blocker_init(); #ifdef KVM_CAP_SET_GUEST_DEBUG QTAILQ_INIT(&s->kvm_sw_breakpoints); @@ -2638,6 +2684,11 @@ static int kvm_init(MachineState *ms) } } + if (kvm_check_extension(kvm_state, KVM_CAP_BINARY_STATS_FD)) { + add_stats_callbacks(STATS_PROVIDER_KVM, query_stats_cb, + query_stats_schemas_cb); + } + return 0; err: @@ -2957,8 +3008,19 @@ int kvm_cpu_exec(CPUState *cpu) */ trace_kvm_dirty_ring_full(cpu->cpu_index); qemu_mutex_lock_iothread(); - kvm_dirty_ring_reap(kvm_state); + /* + * We throttle vCPU by making it sleep once it exit from kernel + * due to dirty ring full. In the dirtylimit scenario, reaping + * all vCPUs after a single vCPU dirty ring get full result in + * the miss of sleep, so just reap the ring-fulled vCPU. + */ + if (dirtylimit_in_service()) { + kvm_dirty_ring_reap(kvm_state, cpu); + } else { + kvm_dirty_ring_reap(kvm_state, NULL); + } qemu_mutex_unlock_iothread(); + dirtylimit_vcpu_execute(cpu); ret = 0; break; case KVM_EXIT_SYSTEM_EVENT: @@ -3032,7 +3094,9 @@ int kvm_vm_ioctl(KVMState *s, int type, ...) va_end(ap); trace_kvm_vm_ioctl(type, arg); + accel_ioctl_begin(); ret = ioctl(s->vmfd, type, arg); + accel_ioctl_end(); if (ret == -1) { ret = -errno; } @@ -3050,7 +3114,9 @@ int kvm_vcpu_ioctl(CPUState *cpu, int type, ...) va_end(ap); trace_kvm_vcpu_ioctl(cpu->cpu_index, type, arg); + accel_cpu_ioctl_begin(cpu); ret = ioctl(cpu->kvm_fd, type, arg); + accel_cpu_ioctl_end(cpu); if (ret == -1) { ret = -errno; } @@ -3068,7 +3134,9 @@ int kvm_device_ioctl(int fd, int type, ...) va_end(ap); trace_kvm_device_ioctl(fd, type, arg); + accel_ioctl_begin(); ret = ioctl(fd, type, arg); + accel_ioctl_end(); if (ret == -1) { ret = -errno; } @@ -3231,8 +3299,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; @@ -3270,8 +3343,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; @@ -3335,28 +3407,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) @@ -3622,7 +3672,6 @@ static void kvm_set_dirty_ring_size(Object *obj, Visitor *v, Error **errp) { KVMState *s = KVM_STATE(obj); - Error *error = NULL; uint32_t value; if (s->fd != -1) { @@ -3630,9 +3679,7 @@ static void kvm_set_dirty_ring_size(Object *obj, Visitor *v, return; } - visit_type_uint32(v, name, &value, &error); - if (error) { - error_propagate(errp, error); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (value & (value - 1)) { @@ -3654,6 +3701,19 @@ static void kvm_accel_instance_init(Object *obj) s->kernel_irqchip_split = ON_OFF_AUTO_AUTO; /* KVM dirty ring is by default off */ s->kvm_dirty_ring_size = 0; + s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN; + s->notify_window = 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) @@ -3663,6 +3723,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, @@ -3681,6 +3742,8 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) NULL, NULL); object_class_property_set_description(oc, "dirty-ring-size", "Size of KVM dirty page ring buffer (default: 0, i.e. use bitmap)"); + + kvm_arch_accel_class_init(oc); } static const TypeInfo kvm_accel_type = { @@ -3697,3 +3760,406 @@ static void kvm_type_init(void) } type_init(kvm_type_init); + +typedef struct StatsArgs { + union StatsResultsType { + StatsResultList **stats; + StatsSchemaList **schema; + } result; + strList *names; + Error **errp; +} StatsArgs; + +static StatsList *add_kvmstat_entry(struct kvm_stats_desc *pdesc, + uint64_t *stats_data, + StatsList *stats_list, + Error **errp) +{ + + Stats *stats; + uint64List *val_list = NULL; + + /* Only add stats that we understand. */ + switch (pdesc->flags & KVM_STATS_TYPE_MASK) { + case KVM_STATS_TYPE_CUMULATIVE: + case KVM_STATS_TYPE_INSTANT: + case KVM_STATS_TYPE_PEAK: + case KVM_STATS_TYPE_LINEAR_HIST: + case KVM_STATS_TYPE_LOG_HIST: + break; + default: + return stats_list; + } + + switch (pdesc->flags & KVM_STATS_UNIT_MASK) { + case KVM_STATS_UNIT_NONE: + case KVM_STATS_UNIT_BYTES: + case KVM_STATS_UNIT_CYCLES: + case KVM_STATS_UNIT_SECONDS: + case KVM_STATS_UNIT_BOOLEAN: + break; + default: + return stats_list; + } + + switch (pdesc->flags & KVM_STATS_BASE_MASK) { + case KVM_STATS_BASE_POW10: + case KVM_STATS_BASE_POW2: + break; + default: + return stats_list; + } + + /* Alloc and populate data list */ + stats = g_new0(Stats, 1); + stats->name = g_strdup(pdesc->name); + stats->value = g_new0(StatsValue, 1);; + + if ((pdesc->flags & KVM_STATS_UNIT_MASK) == KVM_STATS_UNIT_BOOLEAN) { + stats->value->u.boolean = *stats_data; + stats->value->type = QTYPE_QBOOL; + } else if (pdesc->size == 1) { + stats->value->u.scalar = *stats_data; + stats->value->type = QTYPE_QNUM; + } else { + int i; + for (i = 0; i < pdesc->size; i++) { + QAPI_LIST_PREPEND(val_list, stats_data[i]); + } + stats->value->u.list = val_list; + stats->value->type = QTYPE_QLIST; + } + + QAPI_LIST_PREPEND(stats_list, stats); + return stats_list; +} + +static StatsSchemaValueList *add_kvmschema_entry(struct kvm_stats_desc *pdesc, + StatsSchemaValueList *list, + Error **errp) +{ + StatsSchemaValueList *schema_entry = g_new0(StatsSchemaValueList, 1); + schema_entry->value = g_new0(StatsSchemaValue, 1); + + switch (pdesc->flags & KVM_STATS_TYPE_MASK) { + case KVM_STATS_TYPE_CUMULATIVE: + schema_entry->value->type = STATS_TYPE_CUMULATIVE; + break; + case KVM_STATS_TYPE_INSTANT: + schema_entry->value->type = STATS_TYPE_INSTANT; + break; + case KVM_STATS_TYPE_PEAK: + schema_entry->value->type = STATS_TYPE_PEAK; + break; + case KVM_STATS_TYPE_LINEAR_HIST: + schema_entry->value->type = STATS_TYPE_LINEAR_HISTOGRAM; + schema_entry->value->bucket_size = pdesc->bucket_size; + schema_entry->value->has_bucket_size = true; + break; + case KVM_STATS_TYPE_LOG_HIST: + schema_entry->value->type = STATS_TYPE_LOG2_HISTOGRAM; + break; + default: + goto exit; + } + + switch (pdesc->flags & KVM_STATS_UNIT_MASK) { + case KVM_STATS_UNIT_NONE: + break; + case KVM_STATS_UNIT_BOOLEAN: + schema_entry->value->has_unit = true; + schema_entry->value->unit = STATS_UNIT_BOOLEAN; + break; + case KVM_STATS_UNIT_BYTES: + schema_entry->value->has_unit = true; + schema_entry->value->unit = STATS_UNIT_BYTES; + break; + case KVM_STATS_UNIT_CYCLES: + schema_entry->value->has_unit = true; + schema_entry->value->unit = STATS_UNIT_CYCLES; + break; + case KVM_STATS_UNIT_SECONDS: + schema_entry->value->has_unit = true; + schema_entry->value->unit = STATS_UNIT_SECONDS; + break; + default: + goto exit; + } + + schema_entry->value->exponent = pdesc->exponent; + if (pdesc->exponent) { + switch (pdesc->flags & KVM_STATS_BASE_MASK) { + case KVM_STATS_BASE_POW10: + schema_entry->value->has_base = true; + schema_entry->value->base = 10; + break; + case KVM_STATS_BASE_POW2: + schema_entry->value->has_base = true; + schema_entry->value->base = 2; + break; + default: + goto exit; + } + } + + schema_entry->value->name = g_strdup(pdesc->name); + schema_entry->next = list; + return schema_entry; +exit: + g_free(schema_entry->value); + g_free(schema_entry); + return list; +} + +/* Cached stats descriptors */ +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; + QTAILQ_ENTRY(StatsDescriptors) next; +} StatsDescriptors; + +static QTAILQ_HEAD(, StatsDescriptors) stats_descriptors = + QTAILQ_HEAD_INITIALIZER(stats_descriptors); + +/* + * Return the descriptors for 'target', that either have already been read + * or are retrieved from 'stats_fd'. + */ +static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd, + Error **errp) +{ + StatsDescriptors *descriptors; + const char *ident; + struct kvm_stats_desc *kvm_stats_desc; + struct kvm_stats_header *kvm_stats_header; + size_t size_desc; + ssize_t ret; + + ident = StatsTarget_str(target); + QTAILQ_FOREACH(descriptors, &stats_descriptors, next) { + if (g_str_equal(descriptors->ident, ident)) { + return descriptors; + } + } + + descriptors = g_new0(StatsDescriptors, 1); + + /* Read 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: " + "expected %zu actual %zu", + sizeof(*kvm_stats_header), ret); + g_free(descriptors); + return NULL; + } + size_desc = sizeof(*kvm_stats_desc) + kvm_stats_header->name_size; + + /* Read stats descriptors */ + kvm_stats_desc = g_malloc0_n(kvm_stats_header->num_desc, size_desc); + ret = pread(stats_fd, kvm_stats_desc, + size_desc * kvm_stats_header->num_desc, + kvm_stats_header->desc_offset); + + if (ret != size_desc * kvm_stats_header->num_desc) { + error_setg(errp, "KVM stats: failed to read stats descriptors: " + "expected %zu actual %zu", + size_desc * kvm_stats_header->num_desc, ret); + g_free(descriptors); + g_free(kvm_stats_desc); + return NULL; + } + descriptors->kvm_stats_desc = kvm_stats_desc; + descriptors->ident = ident; + QTAILQ_INSERT_TAIL(&stats_descriptors, descriptors, next); + return descriptors; +} + +static void query_stats(StatsResultList **result, StatsTarget target, + strList *names, int stats_fd, Error **errp) +{ + struct kvm_stats_desc *kvm_stats_desc; + struct kvm_stats_header *kvm_stats_header; + StatsDescriptors *descriptors; + g_autofree uint64_t *stats_data = NULL; + struct kvm_stats_desc *pdesc; + StatsList *stats_list = NULL; + size_t size_desc, size_data = 0; + ssize_t ret; + int i; + + descriptors = find_stats_descriptors(target, stats_fd, errp); + if (!descriptors) { + return; + } + + 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; + + /* Tally the total data size; read schema data */ + for (i = 0; i < kvm_stats_header->num_desc; ++i) { + pdesc = (void *)kvm_stats_desc + i * size_desc; + size_data += pdesc->size * sizeof(*stats_data); + } + + stats_data = g_malloc0(size_data); + ret = pread(stats_fd, stats_data, size_data, kvm_stats_header->data_offset); + + if (ret != size_data) { + error_setg(errp, "KVM stats: failed to read data: " + "expected %zu actual %zu", size_data, ret); + return; + } + + for (i = 0; i < kvm_stats_header->num_desc; ++i) { + uint64_t *stats; + pdesc = (void *)kvm_stats_desc + i * size_desc; + + /* Add entry to the list */ + stats = (void *)stats_data + pdesc->offset; + if (!apply_str_list_filter(pdesc->name, names)) { + continue; + } + stats_list = add_kvmstat_entry(pdesc, stats, stats_list, errp); + } + + if (!stats_list) { + return; + } + + switch (target) { + case STATS_TARGET_VM: + add_stats_entry(result, STATS_PROVIDER_KVM, NULL, stats_list); + break; + case STATS_TARGET_VCPU: + add_stats_entry(result, STATS_PROVIDER_KVM, + current_cpu->parent_obj.canonical_path, + stats_list); + break; + default: + g_assert_not_reached(); + } +} + +static void query_stats_schema(StatsSchemaList **result, StatsTarget target, + int stats_fd, Error **errp) +{ + struct kvm_stats_desc *kvm_stats_desc; + struct kvm_stats_header *kvm_stats_header; + StatsDescriptors *descriptors; + struct kvm_stats_desc *pdesc; + StatsSchemaValueList *stats_list = NULL; + size_t size_desc; + int i; + + descriptors = find_stats_descriptors(target, stats_fd, errp); + if (!descriptors) { + return; + } + + 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; + + /* Tally the total data size; read schema data */ + for (i = 0; i < kvm_stats_header->num_desc; ++i) { + pdesc = (void *)kvm_stats_desc + i * size_desc; + stats_list = add_kvmschema_entry(pdesc, stats_list, errp); + } + + add_stats_schema(result, STATS_PROVIDER_KVM, target, stats_list); +} + +static void query_stats_vcpu(CPUState *cpu, run_on_cpu_data data) +{ + StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr; + int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + Error *local_err = NULL; + + if (stats_fd == -1) { + error_setg_errno(&local_err, errno, "KVM stats: ioctl failed"); + error_propagate(kvm_stats_args->errp, local_err); + return; + } + query_stats(kvm_stats_args->result.stats, STATS_TARGET_VCPU, + kvm_stats_args->names, stats_fd, kvm_stats_args->errp); + close(stats_fd); +} + +static void query_stats_schema_vcpu(CPUState *cpu, run_on_cpu_data data) +{ + StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr; + int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + Error *local_err = NULL; + + if (stats_fd == -1) { + error_setg_errno(&local_err, errno, "KVM stats: ioctl failed"); + error_propagate(kvm_stats_args->errp, local_err); + return; + } + query_stats_schema(kvm_stats_args->result.schema, STATS_TARGET_VCPU, stats_fd, + kvm_stats_args->errp); + close(stats_fd); +} + +static void query_stats_cb(StatsResultList **result, StatsTarget target, + strList *names, strList *targets, Error **errp) +{ + KVMState *s = kvm_state; + CPUState *cpu; + int stats_fd; + + switch (target) { + case STATS_TARGET_VM: + { + stats_fd = kvm_vm_ioctl(s, KVM_GET_STATS_FD, NULL); + if (stats_fd == -1) { + error_setg_errno(errp, errno, "KVM stats: ioctl failed"); + return; + } + query_stats(result, target, names, stats_fd, errp); + close(stats_fd); + break; + } + case STATS_TARGET_VCPU: + { + StatsArgs stats_args; + stats_args.result.stats = result; + stats_args.names = names; + stats_args.errp = errp; + CPU_FOREACH(cpu) { + if (!apply_str_list_filter(cpu->parent_obj.canonical_path, targets)) { + continue; + } + run_on_cpu(cpu, query_stats_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + } + break; + } + default: + break; + } +} + +void query_stats_schemas_cb(StatsSchemaList **result, Error **errp) +{ + StatsArgs stats_args; + KVMState *s = kvm_state; + int stats_fd; + + stats_fd = kvm_vm_ioctl(s, KVM_GET_STATS_FD, NULL); + if (stats_fd == -1) { + error_setg_errno(errp, errno, "KVM stats: ioctl failed"); + return; + } + query_stats_schema(result, STATS_TARGET_VM, stats_fd, errp); + close(stats_fd); + + 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 bf0bd1bee4e7..fd63fe6a59d1 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/meson.build b/accel/meson.build index b9a963cf80c3..49558dd232c2 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -1,4 +1,4 @@ -specific_ss.add(files('accel-common.c')) +specific_ss.add(files('accel-common.c', 'accel-blocker.c')) softmmu_ss.add(files('accel-softmmu.c')) user_ss.add(files('accel-user.c')) @@ -11,10 +11,5 @@ if have_system subdir('stubs') endif -dummy_ss = ss.source_set() -dummy_ss.add(files( - 'dummy-cpus.c', -)) - -specific_ss.add_all(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], if_true: dummy_ss) -specific_ss.add_all(when: ['CONFIG_XEN'], if_true: dummy_ss) +# qtest +softmmu_ss.add(files('dummy-cpus.c')) diff --git a/accel/qtest/meson.build b/accel/qtest/meson.build index 4c6560029336..176d990ae15e 100644 --- a/accel/qtest/meson.build +++ b/accel/qtest/meson.build @@ -1,2 +1 @@ -qtest_module_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], - if_true: files('qtest.c')) +qtest_module_ss.add(when: ['CONFIG_SOFTMMU'], if_true: files('qtest.c')) diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 3345882d85d5..5d2dd8f351fc 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; @@ -148,3 +127,8 @@ bool kvm_dirty_ring_enabled(void) { return false; } + +uint32_t kvm_dirty_ring_size(void) +{ + return 0; +} diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index d8162673ae8d..c1b05767c06e 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -21,6 +21,17 @@ 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) +{ + g_assert_not_reached(); +} + void *probe_access(CPUArchState *env, target_ulong addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { @@ -28,12 +39,12 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, g_assert_not_reached(); } -void QEMU_NORETURN cpu_loop_exit(CPUState *cpu) +G_NORETURN void cpu_loop_exit(CPUState *cpu) { g_assert_not_reached(); } -void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc) +G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc) { g_assert_not_reached(); } diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index fc165031e868..404a530f7c2a 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -63,7 +63,7 @@ the ATOMIC_NAME macro, and redefined below. */ #if DATA_SIZE == 1 # define END -#elif defined(HOST_WORDS_BIGENDIAN) +#elif HOST_BIG_ENDIAN # define END _be #else # define END _le @@ -196,7 +196,7 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) /* Define reverse-host-endian atomic operations. Note that END is used within the ATOMIC_NAME macro. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define END _le #else # define END _be diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index be6fe45aa5a8..c7bc8c6efa14 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -71,7 +71,7 @@ void cpu_loop_exit(CPUState *cpu) void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc) { if (pc) { - cpu_restore_state(cpu, pc, true); + cpu_restore_state(cpu, pc); } cpu_loop_exit(cpu); } diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index c997c2e8e015..356fe348de1c 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/qemu-print.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" @@ -43,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" @@ -171,22 +171,96 @@ 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_addr0(tb) == 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 */ + tb_page_addr_t tb_phys_page1 = tb_page_addr1(tb); + if (tb_phys_page1 == -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_phys_page1 == 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 && @@ -197,16 +271,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", @@ -215,32 +287,30 @@ static inline void log_cpu_exec(target_ulong pc, CPUState *cpu, #if defined(DEBUG_DISAS) if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { - FILE *logfile = qemu_log_lock(); - int flags = 0; + FILE *logfile = qemu_log_trylock(); + if (logfile) { + int flags = 0; - if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) { - flags |= CPU_DUMP_FPU; - } + if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) { + flags |= CPU_DUMP_FPU; + } #if defined(TARGET_I386) - flags |= CPU_DUMP_CCOP; + flags |= CPU_DUMP_CCOP; #endif - log_cpu_state(cpu, flags); - qemu_log_unlock(logfile); + cpu_dump_state(cpu, logfile, flags); + qemu_log_unlock(logfile); + } } #endif /* DEBUG_DISAS */ } } -static bool check_for_breakpoints(CPUState *cpu, target_ulong pc, - uint32_t *cflags) +static bool check_for_breakpoints_slow(CPUState *cpu, target_ulong pc, + uint32_t *cflags) { CPUBreakpoint *bp; bool match_page = false; - if (likely(QTAILQ_EMPTY(&cpu->breakpoints))) { - return false; - } - /* * Singlestep overrides breakpoints. * This requirement is visible in the record-replay tests, where @@ -301,6 +371,13 @@ static bool check_for_breakpoints(CPUState *cpu, target_ulong pc, return false; } +static inline bool check_for_breakpoints(CPUState *cpu, target_ulong pc, + uint32_t *cflags) +{ + return unlikely(!QTAILQ_EMPTY(&cpu->breakpoints)) && + check_for_breakpoints_slow(cpu, pc, cflags); +} + /** * helper_lookup_tb_ptr: quick check for next tb * @env: current cpu state @@ -328,7 +405,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; } @@ -351,7 +430,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); @@ -375,16 +456,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)); + } } } @@ -461,13 +547,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(); @@ -486,67 +570,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) { @@ -589,11 +612,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: @@ -839,11 +859,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; @@ -935,7 +956,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(); @@ -977,6 +1000,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(); @@ -984,7 +1009,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 @@ -994,7 +1020,7 @@ int cpu_exec(CPUState *cpu) * direct jump to a TB spanning two pages because the mapping * for the second page can change. */ - if (tb->page_addr[1] != -1) { + if (tb_page_addr1(tb) != -1) { last_tb = NULL; } #endif @@ -1003,7 +1029,7 @@ int cpu_exec(CPUState *cpu) tb_add_jump(last_tb, tb_exit, tb); } - 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 */ @@ -1026,28 +1052,30 @@ void tcg_exec_realizefn(CPUState *cpu, Error **errp) cc->tcg_ops->initialize(); tcg_target_initialized = true; } - tlb_init(cpu); - qemu_plugin_vcpu_init_hook(cpu); + cpu->tb_jmp_cache = g_new0(CPUJumpCache, 1); + tlb_init(cpu); #ifndef CONFIG_USER_ONLY tcg_iommu_init_notifier_list(cpu); #endif /* !CONFIG_USER_ONLY */ + /* qemu_plugin_vcpu_init_hook delayed until cpu_index assigned. */ } /* undo the initializations in reverse order */ void tcg_exec_unrealizefn(CPUState *cpu) { + qemu_plugin_vcpu_exit_hook(cpu); #ifndef CONFIG_USER_ONLY tcg_iommu_free_notifier_list(cpu); #endif /* !CONFIG_USER_ONLY */ - qemu_plugin_vcpu_exit_hook(cpu); tlb_destroy(cpu); + g_free(cpu->tb_jmp_cache); } #ifndef CONFIG_USER_ONLY -void dump_drift_info(GString *buf) +static void dump_drift_info(GString *buf) { if (!icount_enabled()) { return; @@ -1090,7 +1118,7 @@ HumanReadableText *qmp_x_query_opcount(Error **errp) return NULL; } - dump_opcount_info(buf); + tcg_dump_op_count(buf); return human_readable_text_from_str(buf); } diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 2035b2ac0ac0..494872991751 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -33,7 +33,7 @@ #include "qemu/atomic.h" #include "qemu/atomic128.h" #include "exec/translate-all.h" -#include "trace/trace-root.h" +#include "trace.h" #include "tb-hash.h" #include "internal.h" #ifdef CONFIG_PLUGIN @@ -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) { @@ -1350,54 +1356,48 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, MemoryRegionSection *section; MemoryRegion *mr; uint64_t val; - 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); } - if (!qemu_mutex_iothread_locked()) { - qemu_mutex_lock_iothread(); - locked = true; + { + QEMU_IOTHREAD_LOCK_GUARD(); + r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs); } - r = memory_region_dispatch_read(mr, mr_offset, &val, op, iotlbentry->attrs); + if (r != MEMTX_OK) { hwaddr physaddr = mr_offset + section->offset_within_address_space - section->offset_within_region; cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type, - mmu_idx, iotlbentry->attrs, r, retaddr); - } - if (locked) { - qemu_mutex_unlock_iothread(); + mmu_idx, full->attrs, r, retaddr); } - return val; } /* - * 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) { @@ -1405,12 +1405,11 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, hwaddr mr_offset; MemoryRegionSection *section; MemoryRegion *mr; - 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,25 +1419,22 @@ 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; + { + QEMU_IOTHREAD_LOCK_GUARD(); + r = memory_region_dispatch_write(mr, mr_offset, val, op, full->attrs); } - r = memory_region_dispatch_write(mr, mr_offset, val, op, iotlbentry->attrs); + if (r != MEMTX_OK) { hwaddr physaddr = mr_offset + section->offset_within_address_space - section->offset_within_region; cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), - MMU_DATA_STORE, mmu_idx, iotlbentry->attrs, r, + MMU_DATA_STORE, mmu_idx, full->attrs, r, retaddr); } - if (locked) { - qemu_mutex_unlock_iothread(); - } } static inline target_ulong tlb_read_ofs(CPUTLBEntry *entry, size_t ofs) @@ -1480,9 +1476,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,73 +1491,15 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \ (ADDR) & TARGET_PAGE_MASK) -/* - * 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); if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { - struct page_collection *pages - = page_collection_lock(ram_addr, ram_addr + size); - tb_invalidate_phys_page_fast(pages, ram_addr, size, retaddr); - page_collection_unlock(pages); + tb_invalidate_phys_range_fast(ram_addr, size, retaddr); } /* @@ -1579,7 +1518,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 +1542,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 +1584,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 +1629,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 +1649,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 +1698,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 +1713,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); @@ -1761,7 +1745,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, MemOpIdx oi, int size, int prot, uintptr_t retaddr) { - size_t mmu_idx = get_mmuidx(oi); + uintptr_t mmu_idx = get_mmuidx(oi); MemOp mop = get_memop(oi); int a_bits = get_alignment_bits(mop); uintptr_t index; @@ -1769,6 +1753,8 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, target_ulong tlb_addr; void *hostaddr; + tcg_debug_assert(mmu_idx < NB_MMU_MODES); + /* Adjust the given return address. */ retaddr -= GETPC_ADJ; @@ -1840,7 +1826,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; @@ -1908,18 +1894,20 @@ load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi, uintptr_t retaddr, MemOp op, bool code_read, FullLoadHelper *full_load) { - uintptr_t mmu_idx = get_mmuidx(oi); - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong tlb_addr = code_read ? entry->addr_code : entry->addr_read; const size_t tlb_off = code_read ? offsetof(CPUTLBEntry, addr_code) : offsetof(CPUTLBEntry, addr_read); const MMUAccessType access_type = code_read ? MMU_INST_FETCH : MMU_DATA_LOAD; - unsigned a_bits = get_alignment_bits(get_memop(oi)); + const unsigned a_bits = get_alignment_bits(get_memop(oi)); + const size_t size = memop_size(op); + uintptr_t mmu_idx = get_mmuidx(oi); + uintptr_t index; + CPUTLBEntry *entry; + target_ulong tlb_addr; void *haddr; uint64_t res; - size_t size = memop_size(op); + + tcg_debug_assert(mmu_idx < NB_MMU_MODES); /* Handle CPU specific unaligned behaviour */ if (addr & ((1 << a_bits) - 1)) { @@ -1927,6 +1915,10 @@ load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi, mmu_idx, retaddr); } + index = tlb_index(env, mmu_idx, addr); + entry = tlb_entry(env, mmu_idx, addr); + tlb_addr = code_read ? entry->addr_code : entry->addr_read; + /* If the TLB entry is for a different page, reload and try again. */ if (!tlb_hit(tlb_addr, addr)) { if (!victim_tlb_hit(env, mmu_idx, index, tlb_off, @@ -1942,7 +1934,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. */ @@ -1950,20 +1942,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)); } @@ -2240,7 +2232,7 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val, const size_t tlb_off = offsetof(CPUTLBEntry, addr_write); uintptr_t index, index2; CPUTLBEntry *entry, *entry2; - target_ulong page2, tlb_addr, tlb_addr2; + target_ulong page1, page2, tlb_addr, tlb_addr2; MemOpIdx oi; size_t size2; int i; @@ -2248,15 +2240,17 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val, /* * Ensure the second page is in the TLB. Note that the first page * is already guaranteed to be filled, and that the second page - * cannot evict the first. + * cannot evict the first. An exception to this rule is PAGE_WRITE_INV + * handling: the first page could have evicted itself. */ + page1 = addr & TARGET_PAGE_MASK; page2 = (addr + size) & TARGET_PAGE_MASK; size2 = (addr + size) & ~TARGET_PAGE_MASK; index2 = tlb_index(env, mmu_idx, page2); entry2 = tlb_entry(env, mmu_idx, page2); tlb_addr2 = tlb_addr_write(entry2); - if (!tlb_hit_page(tlb_addr2, page2)) { + if (page1 != page2 && !tlb_hit_page(tlb_addr2, page2)) { if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) { tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE, mmu_idx, retaddr); @@ -2276,12 +2270,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); } @@ -2310,14 +2304,16 @@ static inline void QEMU_ALWAYS_INLINE store_helper(CPUArchState *env, target_ulong addr, uint64_t val, MemOpIdx oi, uintptr_t retaddr, MemOp op) { - uintptr_t mmu_idx = get_mmuidx(oi); - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong tlb_addr = tlb_addr_write(entry); const size_t tlb_off = offsetof(CPUTLBEntry, addr_write); - unsigned a_bits = get_alignment_bits(get_memop(oi)); + const unsigned a_bits = get_alignment_bits(get_memop(oi)); + const size_t size = memop_size(op); + uintptr_t mmu_idx = get_mmuidx(oi); + uintptr_t index; + CPUTLBEntry *entry; + target_ulong tlb_addr; void *haddr; - size_t size = memop_size(op); + + tcg_debug_assert(mmu_idx < NB_MMU_MODES); /* Handle CPU specific unaligned behaviour */ if (addr & ((1 << a_bits) - 1)) { @@ -2325,6 +2321,10 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, mmu_idx, retaddr); } + index = tlb_index(env, mmu_idx, addr); + entry = tlb_entry(env, mmu_idx, addr); + tlb_addr = tlb_addr_write(entry); + /* If the TLB entry is for a different page, reload and try again. */ if (!tlb_hit(tlb_addr, addr)) { if (!victim_tlb_hit(env, mmu_idx, index, tlb_off, @@ -2339,7 +2339,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. */ @@ -2347,20 +2347,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; } @@ -2372,7 +2372,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); @@ -2552,7 +2552,6 @@ void cpu_stq_le_mmu(CPUArchState *env, target_ulong addr, uint64_t val, glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) #define ATOMIC_MMU_CLEANUP -#define ATOMIC_MMU_IDX get_mmuidx(oi) #include "atomic_common.c.inc" diff --git a/accel/tcg/hmp.c b/accel/tcg/hmp.c index d2ea35265538..bb679414207c 100644 --- a/accel/tcg/hmp.c +++ b/accel/tcg/hmp.c @@ -4,7 +4,6 @@ #include "qapi/qapi-commands-machine.h" #include "exec/exec-all.h" #include "monitor/monitor.h" -#include "sysemu/tcg.h" static void hmp_tcg_register(void) { diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 881bc1ede0b1..6edff16fb027 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -11,12 +11,57 @@ #include "exec/exec-all.h" +/* + * Access to the various translations structures need to be serialised + * via locks for consistency. In user-mode emulation access to the + * memory related structures are protected with mmap_lock. + * In !user-mode we use per-page locks. + */ +#ifdef CONFIG_SOFTMMU +#define assert_memory_lock() +#else +#define assert_memory_lock() tcg_debug_assert(have_mmap_lock()) +#endif + +#if defined(CONFIG_SOFTMMU) && defined(CONFIG_DEBUG_TCG) +void assert_no_pages_locked(void); +#else +static inline void assert_no_pages_locked(void) { } +#endif + +#ifdef CONFIG_USER_ONLY +static inline void page_table_config_init(void) { } +#else +void page_table_config_init(void); +#endif + +#ifdef CONFIG_SOFTMMU +void tb_invalidate_phys_range_fast(ram_addr_t ram_addr, + unsigned size, + uintptr_t retaddr); +G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); +#endif /* CONFIG_SOFTMMU */ + TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, target_ulong cs_base, uint32_t flags, int cflags); - -void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); void page_init(void); void tb_htable_init(void); +void tb_reset_jump(TranslationBlock *tb, int n); +TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, + tb_page_addr_t phys_page2); +bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc); +void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, + uintptr_t host_pc); + +/* 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/meson.build b/accel/tcg/meson.build index 7a0a79d731d8..75e1dffb4df7 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -3,6 +3,7 @@ tcg_ss.add(files( 'tcg-all.c', 'cpu-exec-common.c', 'cpu-exec.c', + 'tb-maint.c', 'tcg-runtime-gvec.c', 'tcg-runtime.c', 'translate-all.c', diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 3d0b101e3415..c7d651484016 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -258,10 +258,13 @@ static TCGOp *rm_ops(TCGOp *op) static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op) { - *begin_op = QTAILQ_NEXT(*begin_op, link); - tcg_debug_assert(*begin_op); - op = tcg_op_insert_after(tcg_ctx, op, (*begin_op)->opc); - memcpy(op->args, (*begin_op)->args, sizeof(op->args)); + TCGOp *old_op = QTAILQ_NEXT(*begin_op, link); + unsigned nargs = old_op->nargs; + + *begin_op = old_op; + op = tcg_op_insert_after(tcg_ctx, op, old_op->opc, nargs); + memcpy(op->args, old_op->args, sizeof(op->args[0]) * nargs); + return op; } @@ -381,32 +384,23 @@ static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op) static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func, void *func, int *cb_idx) { + TCGOp *old_op; + int func_idx; + /* copy all ops until the call */ do { op = copy_op_nocheck(begin_op, op); } while (op->opc != INDEX_op_call); /* fill in the op call */ - op->param1 = (*begin_op)->param1; - op->param2 = (*begin_op)->param2; + old_op = *begin_op; + TCGOP_CALLI(op) = TCGOP_CALLI(old_op); + TCGOP_CALLO(op) = TCGOP_CALLO(old_op); tcg_debug_assert(op->life == 0); - if (*cb_idx == -1) { - int i; - /* - * Instead of working out the position of the callback in args[], just - * look for @empty_func, since it should be a unique pointer. - */ - for (i = 0; i < MAX_OPC_PARAM_ARGS; i++) { - if ((uintptr_t)(*begin_op)->args[i] == (uintptr_t)empty_func) { - *cb_idx = i; - break; - } - } - tcg_debug_assert(i < MAX_OPC_PARAM_ARGS); - } - op->args[*cb_idx] = (uintptr_t)func; - op->args[*cb_idx + 1] = (*begin_op)->args[*cb_idx + 1]; + func_idx = TCGOP_CALLO(op) + TCGOP_CALLI(op); + *cb_idx = func_idx; + op->args[func_idx] = (uintptr_t)func; return op; } @@ -424,11 +418,11 @@ static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb, op = copy_const_ptr(&begin_op, op, cb->userp); /* copy the ld_i32, but note that we only have to copy it once */ - begin_op = QTAILQ_NEXT(begin_op, link); - tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); if (*cb_idx == -1) { - op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32); - memcpy(op->args, begin_op->args, sizeof(op->args)); + op = copy_op(&begin_op, op, INDEX_op_ld_i32); + } else { + begin_op = QTAILQ_NEXT(begin_op, link); + tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); } /* call */ @@ -471,11 +465,11 @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb, op = copy_const_ptr(&begin_op, op, cb->userp); /* copy the ld_i32, but note that we only have to copy it once */ - begin_op = QTAILQ_NEXT(begin_op, link); - tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); if (*cb_idx == -1) { - op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32); - memcpy(op->args, begin_op->args, sizeof(op->args)); + op = copy_op(&begin_op, op, INDEX_op_ld_i32); + } else { + begin_op = QTAILQ_NEXT(begin_op, link); + tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); } /* extu_tl_i64 */ @@ -852,7 +846,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 +865,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 +893,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 0a273d9605a2..83dc610e4c19 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 000000000000..ff5ffc8fc206 --- /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/tb-maint.c b/accel/tcg/tb-maint.c new file mode 100644 index 000000000000..b3d6529ae297 --- /dev/null +++ b/accel/tcg/tb-maint.c @@ -0,0 +1,1228 @@ +/* + * Translation Block Maintaince + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/interval-tree.h" +#include "exec/cputlb.h" +#include "exec/log.h" +#include "exec/exec-all.h" +#include "exec/translate-all.h" +#include "sysemu/tcg.h" +#include "tcg/tcg.h" +#include "tb-hash.h" +#include "tb-context.h" +#include "internal.h" + + +/* List iterators for lists of tagged pointers in TranslationBlock. */ +#define TB_FOR_EACH_TAGGED(head, tb, n, field) \ + for (n = (head) & 1, tb = (TranslationBlock *)((head) & ~1); \ + tb; tb = (TranslationBlock *)tb->field[n], n = (uintptr_t)tb & 1, \ + tb = (TranslationBlock *)((uintptr_t)tb & ~1)) + +#define TB_FOR_EACH_JMP(head_tb, tb, n) \ + TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next) + +static bool tb_cmp(const void *ap, const void *bp) +{ + const TranslationBlock *a = ap; + const TranslationBlock *b = bp; + + 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 && + tb_page_addr0(a) == tb_page_addr0(b) && + tb_page_addr1(a) == tb_page_addr1(b)); +} + +void tb_htable_init(void) +{ + unsigned int mode = QHT_MODE_AUTO_RESIZE; + + qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode); +} + +typedef struct PageDesc PageDesc; + +#ifdef CONFIG_USER_ONLY + +/* + * In user-mode page locks aren't used; mmap_lock is enough. + */ +#define assert_page_locked(pd) tcg_debug_assert(have_mmap_lock()) + +static inline void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, + PageDesc **ret_p2, tb_page_addr_t phys2, + bool alloc) +{ + *ret_p1 = NULL; + *ret_p2 = NULL; +} + +static inline void page_unlock(PageDesc *pd) { } +static inline void page_lock_tb(const TranslationBlock *tb) { } +static inline void page_unlock_tb(const TranslationBlock *tb) { } + +/* + * For user-only, since we are protecting all of memory with a single lock, + * and because the two pages of a TranslationBlock are always contiguous, + * use a single data structure to record all TranslationBlocks. + */ +static IntervalTreeRoot tb_root; + +static void tb_remove_all(void) +{ + assert_memory_lock(); + memset(&tb_root, 0, sizeof(tb_root)); +} + +/* Call with mmap_lock held. */ +static void tb_record(TranslationBlock *tb, PageDesc *p1, PageDesc *p2) +{ + target_ulong addr; + int flags; + + assert_memory_lock(); + tb->itree.last = tb->itree.start + tb->size - 1; + + /* translator_loop() must have made all TB pages non-writable */ + addr = tb_page_addr0(tb); + flags = page_get_flags(addr); + assert(!(flags & PAGE_WRITE)); + + addr = tb_page_addr1(tb); + if (addr != -1) { + flags = page_get_flags(addr); + assert(!(flags & PAGE_WRITE)); + } + + interval_tree_insert(&tb->itree, &tb_root); +} + +/* Call with mmap_lock held. */ +static void tb_remove(TranslationBlock *tb) +{ + assert_memory_lock(); + interval_tree_remove(&tb->itree, &tb_root); +} + +/* TODO: For now, still shared with translate-all.c for system mode. */ +#define PAGE_FOR_EACH_TB(start, end, pagedesc, T, N) \ + for (T = foreach_tb_first(start, end), \ + N = foreach_tb_next(T, start, end); \ + T != NULL; \ + T = N, N = foreach_tb_next(N, start, end)) + +typedef TranslationBlock *PageForEachNext; + +static PageForEachNext foreach_tb_first(tb_page_addr_t start, + tb_page_addr_t end) +{ + IntervalTreeNode *n = interval_tree_iter_first(&tb_root, start, end - 1); + return n ? container_of(n, TranslationBlock, itree) : NULL; +} + +static PageForEachNext foreach_tb_next(PageForEachNext tb, + tb_page_addr_t start, + tb_page_addr_t end) +{ + IntervalTreeNode *n; + + if (tb) { + n = interval_tree_iter_next(&tb->itree, start, end - 1); + if (n) { + return container_of(n, TranslationBlock, itree); + } + } + return NULL; +} + +#else +/* + * In system mode we want L1_MAP to be based on ram offsets. + */ +#if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS +# define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS +#else +# define L1_MAP_ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS +#endif + +/* Size of the L2 (and L3, etc) page tables. */ +#define V_L2_BITS 10 +#define V_L2_SIZE (1 << V_L2_BITS) + +/* + * L1 Mapping properties + */ +static int v_l1_size; +static int v_l1_shift; +static int v_l2_levels; + +/* + * The bottom level has pointers to PageDesc, and is indexed by + * anything from 4 to (V_L2_BITS + 3) bits, depending on target page size. + */ +#define V_L1_MIN_BITS 4 +#define V_L1_MAX_BITS (V_L2_BITS + 3) +#define V_L1_MAX_SIZE (1 << V_L1_MAX_BITS) + +static void *l1_map[V_L1_MAX_SIZE]; + +struct PageDesc { + QemuSpin lock; + /* list of TBs intersecting this ram page */ + uintptr_t first_tb; +}; + +void page_table_config_init(void) +{ + uint32_t v_l1_bits; + + assert(TARGET_PAGE_BITS); + /* The bits remaining after N lower levels of page tables. */ + v_l1_bits = (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % V_L2_BITS; + if (v_l1_bits < V_L1_MIN_BITS) { + v_l1_bits += V_L2_BITS; + } + + v_l1_size = 1 << v_l1_bits; + v_l1_shift = L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - v_l1_bits; + v_l2_levels = v_l1_shift / V_L2_BITS - 1; + + assert(v_l1_bits <= V_L1_MAX_BITS); + assert(v_l1_shift % V_L2_BITS == 0); + assert(v_l2_levels >= 0); +} + +static PageDesc *page_find_alloc(tb_page_addr_t index, bool alloc) +{ + PageDesc *pd; + void **lp; + int i; + + /* Level 1. Always allocated. */ + lp = l1_map + ((index >> v_l1_shift) & (v_l1_size - 1)); + + /* Level 2..N-1. */ + for (i = v_l2_levels; i > 0; i--) { + void **p = qatomic_rcu_read(lp); + + if (p == NULL) { + void *existing; + + if (!alloc) { + return NULL; + } + p = g_new0(void *, V_L2_SIZE); + existing = qatomic_cmpxchg(lp, NULL, p); + if (unlikely(existing)) { + g_free(p); + p = existing; + } + } + + lp = p + ((index >> (i * V_L2_BITS)) & (V_L2_SIZE - 1)); + } + + pd = qatomic_rcu_read(lp); + if (pd == NULL) { + void *existing; + + if (!alloc) { + return NULL; + } + + pd = g_new0(PageDesc, V_L2_SIZE); + for (int i = 0; i < V_L2_SIZE; i++) { + qemu_spin_init(&pd[i].lock); + } + + existing = qatomic_cmpxchg(lp, NULL, pd); + if (unlikely(existing)) { + for (int i = 0; i < V_L2_SIZE; i++) { + qemu_spin_destroy(&pd[i].lock); + } + g_free(pd); + pd = existing; + } + } + + return pd + (index & (V_L2_SIZE - 1)); +} + +static inline PageDesc *page_find(tb_page_addr_t index) +{ + return page_find_alloc(index, false); +} + +/** + * struct page_entry - page descriptor entry + * @pd: pointer to the &struct PageDesc of the page this entry represents + * @index: page index of the page + * @locked: whether the page is locked + * + * This struct helps us keep track of the locked state of a page, without + * bloating &struct PageDesc. + * + * A page lock protects accesses to all fields of &struct PageDesc. + * + * See also: &struct page_collection. + */ +struct page_entry { + PageDesc *pd; + tb_page_addr_t index; + bool locked; +}; + +/** + * struct page_collection - tracks a set of pages (i.e. &struct page_entry's) + * @tree: Binary search tree (BST) of the pages, with key == page index + * @max: Pointer to the page in @tree with the highest page index + * + * To avoid deadlock we lock pages in ascending order of page index. + * When operating on a set of pages, we need to keep track of them so that + * we can lock them in order and also unlock them later. For this we collect + * pages (i.e. &struct page_entry's) in a binary search @tree. Given that the + * @tree implementation we use does not provide an O(1) operation to obtain the + * highest-ranked element, we use @max to keep track of the inserted page + * with the highest index. This is valuable because if a page is not in + * the tree and its index is higher than @max's, then we can lock it + * without breaking the locking order rule. + * + * Note on naming: 'struct page_set' would be shorter, but we already have a few + * page_set_*() helpers, so page_collection is used instead to avoid confusion. + * + * See also: page_collection_lock(). + */ +struct page_collection { + GTree *tree; + struct page_entry *max; +}; + +typedef int PageForEachNext; +#define PAGE_FOR_EACH_TB(start, end, pagedesc, tb, n) \ + TB_FOR_EACH_TAGGED((pagedesc)->first_tb, tb, n, page_next) + +#ifdef CONFIG_DEBUG_TCG + +static __thread GHashTable *ht_pages_locked_debug; + +static void ht_pages_locked_debug_init(void) +{ + if (ht_pages_locked_debug) { + return; + } + ht_pages_locked_debug = g_hash_table_new(NULL, NULL); +} + +static bool page_is_locked(const PageDesc *pd) +{ + PageDesc *found; + + ht_pages_locked_debug_init(); + found = g_hash_table_lookup(ht_pages_locked_debug, pd); + return !!found; +} + +static void page_lock__debug(PageDesc *pd) +{ + ht_pages_locked_debug_init(); + g_assert(!page_is_locked(pd)); + g_hash_table_insert(ht_pages_locked_debug, pd, pd); +} + +static void page_unlock__debug(const PageDesc *pd) +{ + bool removed; + + ht_pages_locked_debug_init(); + g_assert(page_is_locked(pd)); + removed = g_hash_table_remove(ht_pages_locked_debug, pd); + g_assert(removed); +} + +static void do_assert_page_locked(const PageDesc *pd, + const char *file, int line) +{ + if (unlikely(!page_is_locked(pd))) { + error_report("assert_page_lock: PageDesc %p not locked @ %s:%d", + pd, file, line); + abort(); + } +} +#define assert_page_locked(pd) do_assert_page_locked(pd, __FILE__, __LINE__) + +void assert_no_pages_locked(void) +{ + ht_pages_locked_debug_init(); + g_assert(g_hash_table_size(ht_pages_locked_debug) == 0); +} + +#else /* !CONFIG_DEBUG_TCG */ + +static inline void page_lock__debug(const PageDesc *pd) { } +static inline void page_unlock__debug(const PageDesc *pd) { } +static inline void assert_page_locked(const PageDesc *pd) { } + +#endif /* CONFIG_DEBUG_TCG */ + +static void page_lock(PageDesc *pd) +{ + page_lock__debug(pd); + qemu_spin_lock(&pd->lock); +} + +static void page_unlock(PageDesc *pd) +{ + qemu_spin_unlock(&pd->lock); + page_unlock__debug(pd); +} + +static inline struct page_entry * +page_entry_new(PageDesc *pd, tb_page_addr_t index) +{ + struct page_entry *pe = g_malloc(sizeof(*pe)); + + pe->index = index; + pe->pd = pd; + pe->locked = false; + return pe; +} + +static void page_entry_destroy(gpointer p) +{ + struct page_entry *pe = p; + + g_assert(pe->locked); + page_unlock(pe->pd); + g_free(pe); +} + +/* returns false on success */ +static bool page_entry_trylock(struct page_entry *pe) +{ + bool busy; + + busy = qemu_spin_trylock(&pe->pd->lock); + if (!busy) { + g_assert(!pe->locked); + pe->locked = true; + page_lock__debug(pe->pd); + } + return busy; +} + +static void do_page_entry_lock(struct page_entry *pe) +{ + page_lock(pe->pd); + g_assert(!pe->locked); + pe->locked = true; +} + +static gboolean page_entry_lock(gpointer key, gpointer value, gpointer data) +{ + struct page_entry *pe = value; + + do_page_entry_lock(pe); + return FALSE; +} + +static gboolean page_entry_unlock(gpointer key, gpointer value, gpointer data) +{ + struct page_entry *pe = value; + + if (pe->locked) { + pe->locked = false; + page_unlock(pe->pd); + } + return FALSE; +} + +/* + * Trylock a page, and if successful, add the page to a collection. + * Returns true ("busy") if the page could not be locked; false otherwise. + */ +static bool page_trylock_add(struct page_collection *set, tb_page_addr_t addr) +{ + tb_page_addr_t index = addr >> TARGET_PAGE_BITS; + struct page_entry *pe; + PageDesc *pd; + + pe = g_tree_lookup(set->tree, &index); + if (pe) { + return false; + } + + pd = page_find(index); + if (pd == NULL) { + return false; + } + + pe = page_entry_new(pd, index); + g_tree_insert(set->tree, &pe->index, pe); + + /* + * If this is either (1) the first insertion or (2) a page whose index + * is higher than any other so far, just lock the page and move on. + */ + if (set->max == NULL || pe->index > set->max->index) { + set->max = pe; + do_page_entry_lock(pe); + return false; + } + /* + * Try to acquire out-of-order lock; if busy, return busy so that we acquire + * locks in order. + */ + return page_entry_trylock(pe); +} + +static gint tb_page_addr_cmp(gconstpointer ap, gconstpointer bp, gpointer udata) +{ + tb_page_addr_t a = *(const tb_page_addr_t *)ap; + tb_page_addr_t b = *(const tb_page_addr_t *)bp; + + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } + return 1; +} + +/* + * Lock a range of pages ([@start,@end[) as well as the pages of all + * intersecting TBs. + * Locking order: acquire locks in ascending order of page index. + */ +static struct page_collection *page_collection_lock(tb_page_addr_t start, + tb_page_addr_t end) +{ + struct page_collection *set = g_malloc(sizeof(*set)); + tb_page_addr_t index; + PageDesc *pd; + + start >>= TARGET_PAGE_BITS; + end >>= TARGET_PAGE_BITS; + g_assert(start <= end); + + set->tree = g_tree_new_full(tb_page_addr_cmp, NULL, NULL, + page_entry_destroy); + set->max = NULL; + assert_no_pages_locked(); + + retry: + g_tree_foreach(set->tree, page_entry_lock, NULL); + + for (index = start; index <= end; index++) { + TranslationBlock *tb; + PageForEachNext n; + + pd = page_find(index); + if (pd == NULL) { + continue; + } + if (page_trylock_add(set, index << TARGET_PAGE_BITS)) { + g_tree_foreach(set->tree, page_entry_unlock, NULL); + goto retry; + } + assert_page_locked(pd); + PAGE_FOR_EACH_TB(unused, unused, pd, tb, n) { + if (page_trylock_add(set, tb_page_addr0(tb)) || + (tb_page_addr1(tb) != -1 && + page_trylock_add(set, tb_page_addr1(tb)))) { + /* drop all locks, and reacquire in order */ + g_tree_foreach(set->tree, page_entry_unlock, NULL); + goto retry; + } + } + } + return set; +} + +static void page_collection_unlock(struct page_collection *set) +{ + /* entries are unlocked and freed via page_entry_destroy */ + g_tree_destroy(set->tree); + g_free(set); +} + +/* Set to NULL all the 'first_tb' fields in all PageDescs. */ +static void tb_remove_all_1(int level, void **lp) +{ + int i; + + if (*lp == NULL) { + return; + } + if (level == 0) { + PageDesc *pd = *lp; + + for (i = 0; i < V_L2_SIZE; ++i) { + page_lock(&pd[i]); + pd[i].first_tb = (uintptr_t)NULL; + page_unlock(&pd[i]); + } + } else { + void **pp = *lp; + + for (i = 0; i < V_L2_SIZE; ++i) { + tb_remove_all_1(level - 1, pp + i); + } + } +} + +static void tb_remove_all(void) +{ + int i, l1_sz = v_l1_size; + + for (i = 0; i < l1_sz; i++) { + tb_remove_all_1(v_l2_levels, l1_map + i); + } +} + +/* + * Add the tb in the target page and protect it if necessary. + * Called with @p->lock held. + */ +static inline void tb_page_add(PageDesc *p, TranslationBlock *tb, + unsigned int n) +{ + bool page_already_protected; + + assert_page_locked(p); + + tb->page_next[n] = p->first_tb; + page_already_protected = p->first_tb != 0; + p->first_tb = (uintptr_t)tb | n; + + /* + * If some code is already present, then the pages are already + * protected. So we handle the case where only the first TB is + * allocated in a physical page. + */ + if (!page_already_protected) { + tlb_protect_code(tb->page_addr[n] & TARGET_PAGE_MASK); + } +} + +static void tb_record(TranslationBlock *tb, PageDesc *p1, PageDesc *p2) +{ + tb_page_add(p1, tb, 0); + if (unlikely(p2)) { + tb_page_add(p2, tb, 1); + } +} + +static inline void tb_page_remove(PageDesc *pd, TranslationBlock *tb) +{ + TranslationBlock *tb1; + uintptr_t *pprev; + PageForEachNext n1; + + assert_page_locked(pd); + pprev = &pd->first_tb; + PAGE_FOR_EACH_TB(unused, unused, pd, tb1, n1) { + if (tb1 == tb) { + *pprev = tb1->page_next[n1]; + return; + } + pprev = &tb1->page_next[n1]; + } + g_assert_not_reached(); +} + +static void tb_remove(TranslationBlock *tb) +{ + PageDesc *pd; + + pd = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); + tb_page_remove(pd, tb); + if (unlikely(tb->page_addr[1] != -1)) { + pd = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); + tb_page_remove(pd, tb); + } +} + +static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, + PageDesc **ret_p2, tb_page_addr_t phys2, bool alloc) +{ + PageDesc *p1, *p2; + tb_page_addr_t page1; + tb_page_addr_t page2; + + assert_memory_lock(); + g_assert(phys1 != -1); + + page1 = phys1 >> TARGET_PAGE_BITS; + page2 = phys2 >> TARGET_PAGE_BITS; + + p1 = page_find_alloc(page1, alloc); + if (ret_p1) { + *ret_p1 = p1; + } + if (likely(phys2 == -1)) { + page_lock(p1); + return; + } else if (page1 == page2) { + page_lock(p1); + if (ret_p2) { + *ret_p2 = p1; + } + return; + } + p2 = page_find_alloc(page2, alloc); + if (ret_p2) { + *ret_p2 = p2; + } + if (page1 < page2) { + page_lock(p1); + page_lock(p2); + } else { + page_lock(p2); + page_lock(p1); + } +} + +/* lock the page(s) of a TB in the correct acquisition order */ +static void page_lock_tb(const TranslationBlock *tb) +{ + page_lock_pair(NULL, tb_page_addr0(tb), NULL, tb_page_addr1(tb), false); +} + +static void page_unlock_tb(const TranslationBlock *tb) +{ + PageDesc *p1 = page_find(tb_page_addr0(tb) >> TARGET_PAGE_BITS); + + page_unlock(p1); + if (unlikely(tb_page_addr1(tb) != -1)) { + PageDesc *p2 = page_find(tb_page_addr1(tb) >> TARGET_PAGE_BITS); + + if (p2 != p1) { + page_unlock(p2); + } + } +} +#endif /* CONFIG_USER_ONLY */ + +/* flush all the translation blocks */ +static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) +{ + bool did_flush = false; + + mmap_lock(); + /* If it is already been done on request of another CPU, just retry. */ + if (tb_ctx.tb_flush_count != tb_flush_count.host_int) { + goto done; + } + did_flush = true; + + CPU_FOREACH(cpu) { + tcg_flush_jmp_cache(cpu); + } + + qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE); + tb_remove_all(); + + tcg_region_reset_all(); + /* XXX: flush processor icache at this point if cache flush is expensive */ + qatomic_mb_set(&tb_ctx.tb_flush_count, tb_ctx.tb_flush_count + 1); + +done: + mmap_unlock(); + if (did_flush) { + qemu_plugin_flush_cb(); + } +} + +void tb_flush(CPUState *cpu) +{ + if (tcg_enabled()) { + unsigned tb_flush_count = qatomic_mb_read(&tb_ctx.tb_flush_count); + + if (cpu_in_exclusive_context(cpu)) { + do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count)); + } else { + async_safe_run_on_cpu(cpu, do_tb_flush, + RUN_ON_CPU_HOST_INT(tb_flush_count)); + } + } +} + +/* remove @orig from its @n_orig-th jump list */ +static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig) +{ + uintptr_t ptr, ptr_locked; + TranslationBlock *dest; + TranslationBlock *tb; + uintptr_t *pprev; + int n; + + /* mark the LSB of jmp_dest[] so that no further jumps can be inserted */ + ptr = qatomic_or_fetch(&orig->jmp_dest[n_orig], 1); + dest = (TranslationBlock *)(ptr & ~1); + if (dest == NULL) { + return; + } + + qemu_spin_lock(&dest->jmp_lock); + /* + * While acquiring the lock, the jump might have been removed if the + * destination TB was invalidated; check again. + */ + ptr_locked = qatomic_read(&orig->jmp_dest[n_orig]); + if (ptr_locked != ptr) { + qemu_spin_unlock(&dest->jmp_lock); + /* + * The only possibility is that the jump was unlinked via + * tb_jump_unlink(dest). Seeing here another destination would be a bug, + * because we set the LSB above. + */ + g_assert(ptr_locked == 1 && dest->cflags & CF_INVALID); + return; + } + /* + * We first acquired the lock, and since the destination pointer matches, + * we know for sure that @orig is in the jmp list. + */ + pprev = &dest->jmp_list_head; + TB_FOR_EACH_JMP(dest, tb, n) { + if (tb == orig && n == n_orig) { + *pprev = tb->jmp_list_next[n]; + /* no need to set orig->jmp_dest[n]; setting the LSB was enough */ + qemu_spin_unlock(&dest->jmp_lock); + return; + } + pprev = &tb->jmp_list_next[n]; + } + g_assert_not_reached(); +} + +/* + * Reset the jump entry 'n' of a TB so that it is not chained to another TB. + */ +void tb_reset_jump(TranslationBlock *tb, int n) +{ + uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]); + tb_set_jmp_target(tb, n, addr); +} + +/* remove any jumps to the TB */ +static inline void tb_jmp_unlink(TranslationBlock *dest) +{ + TranslationBlock *tb; + int n; + + qemu_spin_lock(&dest->jmp_lock); + + TB_FOR_EACH_JMP(dest, tb, n) { + tb_reset_jump(tb, n); + qatomic_and(&tb->jmp_dest[n], (uintptr_t)NULL | 1); + /* No need to clear the list entry; setting the dest ptr is enough */ + } + dest->jmp_list_head = (uintptr_t)NULL; + + 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' + * locks held. + */ +static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) +{ + uint32_t h; + tb_page_addr_t phys_pc; + uint32_t orig_cflags = tb_cflags(tb); + + assert_memory_lock(); + + /* make sure no further incoming jumps will be chained to this TB */ + qemu_spin_lock(&tb->jmp_lock); + qatomic_set(&tb->cflags, tb->cflags | CF_INVALID); + qemu_spin_unlock(&tb->jmp_lock); + + /* remove the TB from the hash list */ + phys_pc = tb_page_addr0(tb); + 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; + } + + /* remove the TB from the page list */ + if (rm_from_page_list) { + tb_remove(tb); + } + + /* remove the TB from the hash list */ + tb_jmp_cache_inval_tb(tb); + + /* suppress this TB from the two jump lists */ + tb_remove_from_jmp_list(tb, 0); + tb_remove_from_jmp_list(tb, 1); + + /* suppress any remaining jumps to this TB */ + tb_jmp_unlink(tb); + + qatomic_set(&tb_ctx.tb_phys_invalidate_count, + tb_ctx.tb_phys_invalidate_count + 1); +} + +static void tb_phys_invalidate__locked(TranslationBlock *tb) +{ + qemu_thread_jit_write(); + do_tb_phys_invalidate(tb, true); + qemu_thread_jit_execute(); +} + +/* + * Invalidate one TB. + * Called with mmap_lock held in user-mode. + */ +void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) +{ + if (page_addr == -1 && tb_page_addr0(tb) != -1) { + page_lock_tb(tb); + do_tb_phys_invalidate(tb, true); + page_unlock_tb(tb); + } else { + do_tb_phys_invalidate(tb, false); + } +} + +/* + * Add a new TB and link it to the physical page tables. phys_page2 is + * (-1) to indicate that only one page contains the TB. + * + * Called with mmap_lock held for user-mode emulation. + * + * Returns a pointer @tb, or a pointer to an existing TB that matches @tb. + * Note that in !user-mode, another thread might have already added a TB + * for the same block of guest code that @tb corresponds to. In that case, + * the caller should discard the original @tb, and use instead the returned TB. + */ +TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, + tb_page_addr_t phys_page2) +{ + PageDesc *p; + PageDesc *p2 = NULL; + void *existing_tb = NULL; + uint32_t h; + + assert_memory_lock(); + tcg_debug_assert(!(tb->cflags & CF_INVALID)); + + /* + * Add the TB to the page list, acquiring first the pages's locks. + * We keep the locks held until after inserting the TB in the hash table, + * so that if the insertion fails we know for sure that the TBs are still + * in the page descriptors. + * 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, true); + tb_record(tb, p, p2); + + /* add in the hash table */ + 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_remove(tb); + tb = existing_tb; + } + + if (p2 && p2 != p) { + page_unlock(p2); + } + page_unlock(p); + return tb; +} + +#ifdef CONFIG_USER_ONLY +/* + * Invalidate all TBs which intersect with the target address range. + * Called with mmap_lock held for user-mode emulation. + * NOTE: this function must not be called while a TB is running. + */ +void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end) +{ + TranslationBlock *tb; + PageForEachNext n; + + assert_memory_lock(); + + PAGE_FOR_EACH_TB(start, end, unused, tb, n) { + tb_phys_invalidate__locked(tb); + } +} + +/* + * Invalidate all TBs which intersect with the target address page @addr. + * Called with mmap_lock held for user-mode emulation + * NOTE: this function must not be called while a TB is running. + */ +void tb_invalidate_phys_page(tb_page_addr_t addr) +{ + tb_page_addr_t start, end; + + start = addr & TARGET_PAGE_MASK; + end = start + TARGET_PAGE_SIZE; + tb_invalidate_phys_range(start, end); +} + +/* + * Called with mmap_lock held. If pc is not 0 then it indicates the + * host PC of the faulting store instruction that caused this invalidate. + * Returns true if the caller needs to abort execution of the current + * TB (because it was modified by this store and the guest CPU has + * precise-SMC semantics). + */ +bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc) +{ + TranslationBlock *current_tb; + bool current_tb_modified; + TranslationBlock *tb; + PageForEachNext n; + + /* + * Without precise smc semantics, or when outside of a TB, + * we can skip to invalidate. + */ +#ifndef TARGET_HAS_PRECISE_SMC + pc = 0; +#endif + if (!pc) { + tb_invalidate_phys_page(addr); + return false; + } + + assert_memory_lock(); + current_tb = tcg_tb_lookup(pc); + + addr &= TARGET_PAGE_MASK; + current_tb_modified = false; + + PAGE_FOR_EACH_TB(addr, addr + TARGET_PAGE_SIZE, unused, tb, n) { + if (current_tb == tb && + (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { + /* + * If we are modifying the current TB, we must stop its + * execution. We could be more precise by checking that + * the modification is after the current PC, but it would + * require a specialized function to partially restore + * the CPU state. + */ + current_tb_modified = true; + cpu_restore_state_from_tb(current_cpu, current_tb, pc); + } + tb_phys_invalidate__locked(tb); + } + + if (current_tb_modified) { + /* Force execution of one insn next time. */ + CPUState *cpu = current_cpu; + cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); + return true; + } + return false; +} +#else +/* + * @p must be non-NULL. + * Call with all @pages locked. + */ +static void +tb_invalidate_phys_page_range__locked(struct page_collection *pages, + PageDesc *p, tb_page_addr_t start, + tb_page_addr_t end, + uintptr_t retaddr) +{ + TranslationBlock *tb; + tb_page_addr_t tb_start, tb_end; + PageForEachNext n; +#ifdef TARGET_HAS_PRECISE_SMC + bool current_tb_modified = false; + TranslationBlock *current_tb = retaddr ? tcg_tb_lookup(retaddr) : NULL; +#endif /* TARGET_HAS_PRECISE_SMC */ + + /* + * We remove all the TBs in the range [start, end[. + * XXX: see if in some cases it could be faster to invalidate all the code + */ + PAGE_FOR_EACH_TB(start, end, 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_page_addr0(tb); + tb_end = tb_start + tb->size; + } else { + tb_start = tb_page_addr1(tb); + tb_end = tb_start + ((tb_page_addr0(tb) + tb->size) + & ~TARGET_PAGE_MASK); + } + if (!(tb_end <= start || tb_start >= end)) { +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb == tb && + (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { + /* + * If we are modifying the current TB, we must stop + * its execution. We could be more precise by checking + * that the modification is after the current PC, but it + * would require a specialized function to partially + * restore the CPU state. + */ + current_tb_modified = true; + cpu_restore_state_from_tb(current_cpu, current_tb, retaddr); + } +#endif /* TARGET_HAS_PRECISE_SMC */ + tb_phys_invalidate__locked(tb); + } + } + + /* if no code remaining, no need to continue to use slow writes */ + if (!p->first_tb) { + tlb_unprotect_code(start); + } + +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + page_collection_unlock(pages); + /* Force execution of one insn next time. */ + current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); + mmap_unlock(); + cpu_loop_exit_noexc(current_cpu); + } +#endif +} + +/* + * Invalidate all TBs which intersect with the target physical + * address page @addr. + */ +void tb_invalidate_phys_page(tb_page_addr_t addr) +{ + struct page_collection *pages; + tb_page_addr_t start, end; + PageDesc *p; + + p = page_find(addr >> TARGET_PAGE_BITS); + if (p == NULL) { + return; + } + + start = addr & TARGET_PAGE_MASK; + end = start + TARGET_PAGE_SIZE; + pages = page_collection_lock(start, end); + tb_invalidate_phys_page_range__locked(pages, p, start, end, 0); + page_collection_unlock(pages); +} + +/* + * Invalidate all TBs which intersect with the target physical address range + * [start;end[. NOTE: start and end may refer to *different* physical pages. + * 'is_cpu_write_access' should be true if called from a real cpu write + * access: the virtual CPU will exit the current TB if code is modified inside + * this TB. + */ +void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end) +{ + struct page_collection *pages; + tb_page_addr_t next; + + pages = page_collection_lock(start, end); + for (next = (start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + start < end; + start = next, next += TARGET_PAGE_SIZE) { + PageDesc *pd = page_find(start >> TARGET_PAGE_BITS); + tb_page_addr_t bound = MIN(next, end); + + if (pd == NULL) { + continue; + } + assert_page_locked(pd); + tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0); + } + page_collection_unlock(pages); +} + +/* + * Call with all @pages in the range [@start, @start + len[ locked. + */ +static void tb_invalidate_phys_page_fast__locked(struct page_collection *pages, + tb_page_addr_t start, + unsigned len, uintptr_t ra) +{ + PageDesc *p; + + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) { + return; + } + + assert_page_locked(p); + tb_invalidate_phys_page_range__locked(pages, p, start, start + len, ra); +} + +/* + * len must be <= 8 and start must be a multiple of len. + * Called via softmmu_template.h when code areas are written to with + * iothread mutex not held. + */ +void tb_invalidate_phys_range_fast(ram_addr_t ram_addr, + unsigned size, + uintptr_t retaddr) +{ + struct page_collection *pages; + + pages = page_collection_lock(ram_addr, ram_addr + size); + tb_invalidate_phys_page_fast__locked(pages, ram_addr, size, retaddr); + page_collection_unlock(pages); +} + +#endif /* CONFIG_USER_ONLY */ diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index bdaf2c943b49..84cc7421be88 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -24,8 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "sysemu/tcg.h" #include "sysemu/replay.h" #include "sysemu/cpu-timers.h" #include "qemu/main-loop.h" @@ -86,8 +84,7 @@ void icount_handle_deadline(void) * Don't interrupt cpu thread, when these events are waiting * (i.e., there is no checkpoint) */ - if (deadline == 0 - && (replay_mode != REPLAY_MODE_PLAY || replay_has_checkpoint())) { + if (deadline == 0) { icount_notify_aio_contexts(); } } @@ -111,8 +108,14 @@ void icount_prepare_for_run(CPUState *cpu) replay_mutex_lock(); - if (cpu->icount_budget == 0 && replay_has_checkpoint()) { + 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-icount.h b/accel/tcg/tcg-accel-ops-icount.h index d884aa2aaacb..1b6fd9c60751 100644 --- a/accel/tcg/tcg-accel-ops-icount.h +++ b/accel/tcg/tcg-accel-ops-icount.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_ICOUNT_H -#define TCG_CPUS_ICOUNT_H +#ifndef TCG_ACCEL_OPS_ICOUNT_H +#define TCG_ACCEL_OPS_ICOUNT_H void icount_handle_deadline(void); void icount_prepare_for_run(CPUState *cpu); @@ -16,4 +16,4 @@ void icount_process_data(CPUState *cpu); void icount_handle_interrupt(CPUState *cpu, int mask); -#endif /* TCG_CPUS_ICOUNT_H */ +#endif /* TCG_ACCEL_OPS_ICOUNT_H */ diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index ea2b741deb51..d50239e0e28f 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" #include "sysemu/cpu-timers.h" diff --git a/accel/tcg/tcg-accel-ops-mttcg.h b/accel/tcg/tcg-accel-ops-mttcg.h index 9fdc5a2ab546..8ffa7a9a9fe0 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.h +++ b/accel/tcg/tcg-accel-ops-mttcg.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_MTTCG_H -#define TCG_CPUS_MTTCG_H +#ifndef TCG_ACCEL_OPS_MTTCG_H +#define TCG_ACCEL_OPS_MTTCG_H /* kick MTTCG vCPU thread */ void mttcg_kick_vcpu_thread(CPUState *cpu); @@ -16,4 +16,4 @@ void mttcg_kick_vcpu_thread(CPUState *cpu); /* start an mttcg vCPU thread */ void mttcg_start_vcpu_thread(CPUState *cpu); -#endif /* TCG_CPUS_MTTCG_H */ +#endif /* TCG_ACCEL_OPS_MTTCG_H */ diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index b287110766ef..290833a37fb2 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" #include "sysemu/cpu-timers.h" @@ -52,7 +51,7 @@ void rr_kick_vcpu_thread(CPUState *unused) * * The kick timer is responsible for moving single threaded vCPU * emulation on to the next vCPU. If more than one vCPU is running a - * timer event with force a cpu->exit so the next vCPU can get + * timer event we force a cpu->exit so the next vCPU can get * scheduled. * * The timer is removed if all vCPUs are idle and restarted again once diff --git a/accel/tcg/tcg-accel-ops-rr.h b/accel/tcg/tcg-accel-ops-rr.h index 54f6ae6e867f..2a76a296127e 100644 --- a/accel/tcg/tcg-accel-ops-rr.h +++ b/accel/tcg/tcg-accel-ops-rr.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_RR_H -#define TCG_CPUS_RR_H +#ifndef TCG_ACCEL_OPS_RR_H +#define TCG_ACCEL_OPS_RR_H #define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10) @@ -18,4 +18,4 @@ void rr_kick_vcpu_thread(CPUState *unused); /* start the round robin vcpu thread */ void rr_start_vcpu_thread(CPUState *cpu); -#endif /* TCG_CPUS_RR_H */ +#endif /* TCG_ACCEL_OPS_RR_H */ diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index ea7dcad674cf..19cbf1db3afb 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -26,13 +26,14 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" #include "sysemu/cpu-timers.h" #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" @@ -92,23 +93,120 @@ 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()) { ops->create_vcpu_thread = mttcg_start_vcpu_thread; ops->kick_vcpu_thread = mttcg_kick_vcpu_thread; ops->handle_interrupt = tcg_handle_interrupt; - } else if (icount_enabled()) { - ops->create_vcpu_thread = rr_start_vcpu_thread; - ops->kick_vcpu_thread = rr_kick_vcpu_thread; - ops->handle_interrupt = icount_handle_interrupt; - ops->get_virtual_clock = icount_get; - ops->get_elapsed_ticks = icount_get; } else { ops->create_vcpu_thread = rr_start_vcpu_thread; ops->kick_vcpu_thread = rr_kick_vcpu_thread; - ops->handle_interrupt = tcg_handle_interrupt; + + if (icount_enabled()) { + ops->handle_interrupt = icount_handle_interrupt; + ops->get_virtual_clock = icount_get; + ops->get_elapsed_ticks = icount_get; + } else { + 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-accel-ops.h b/accel/tcg/tcg-accel-ops.h index 6a5fcef88980..f9bc6330e2d0 100644 --- a/accel/tcg/tcg-accel-ops.h +++ b/accel/tcg/tcg-accel-ops.h @@ -9,8 +9,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_H -#define TCG_CPUS_H +#ifndef TCG_ACCEL_OPS_H +#define TCG_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -19,4 +19,4 @@ int tcg_cpus_exec(CPUState *cpu); void tcg_handle_interrupt(CPUState *cpu, int mask); void tcg_cpu_init_cflags(CPUState *cpu, bool parallel); -#endif /* TCG_CPUS_H */ +#endif /* TCG_ACCEL_OPS_H */ diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index d6336a9c966d..30b503fb22fc 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -24,8 +24,8 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "sysemu/tcg.h" +#include "sysemu/replay.h" #include "sysemu/cpu-timers.h" #include "tcg/tcg.h" #include "qapi/error.h" @@ -208,12 +208,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/trace-events b/accel/tcg/trace-events index 59eab96f2647..4e9b450520b3 100644 --- a/accel/tcg/trace-events +++ b/accel/tcg/trace-events @@ -6,5 +6,9 @@ exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x" +# cputlb.c +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 + # translate-all.c translate_block(void *tb, uintptr_t pc, const void *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 5971cd53ab9f..51ac1f6c84af 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #define NO_CPU_IO_DEFS #include "trace.h" @@ -47,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" @@ -58,189 +58,18 @@ #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" -/* #define DEBUG_TB_INVALIDATE */ -/* #define DEBUG_TB_FLUSH */ -/* make various TB consistency checks */ -/* #define DEBUG_TB_CHECK */ - -#ifdef DEBUG_TB_INVALIDATE -#define DEBUG_TB_INVALIDATE_GATE 1 -#else -#define DEBUG_TB_INVALIDATE_GATE 0 -#endif - -#ifdef DEBUG_TB_FLUSH -#define DEBUG_TB_FLUSH_GATE 1 -#else -#define DEBUG_TB_FLUSH_GATE 0 -#endif - -#if !defined(CONFIG_USER_ONLY) -/* TB consistency checks only implemented for usermode emulation. */ -#undef DEBUG_TB_CHECK -#endif - -#ifdef DEBUG_TB_CHECK -#define DEBUG_TB_CHECK_GATE 1 -#else -#define DEBUG_TB_CHECK_GATE 0 -#endif - -/* Access to the various translations structures need to be serialised via locks - * for consistency. - * In user-mode emulation access to the memory related structures are protected - * with mmap_lock. - * In !user-mode we use per-page locks. - */ -#ifdef CONFIG_SOFTMMU -#define assert_memory_lock() -#else -#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 - unsigned long flags; - void *target_data; -#endif -#ifndef CONFIG_USER_ONLY - QemuSpin lock; -#endif -} PageDesc; - -/** - * struct page_entry - page descriptor entry - * @pd: pointer to the &struct PageDesc of the page this entry represents - * @index: page index of the page - * @locked: whether the page is locked - * - * This struct helps us keep track of the locked state of a page, without - * bloating &struct PageDesc. - * - * A page lock protects accesses to all fields of &struct PageDesc. - * - * See also: &struct page_collection. - */ -struct page_entry { - PageDesc *pd; - tb_page_addr_t index; - bool locked; -}; - -/** - * struct page_collection - tracks a set of pages (i.e. &struct page_entry's) - * @tree: Binary search tree (BST) of the pages, with key == page index - * @max: Pointer to the page in @tree with the highest page index - * - * To avoid deadlock we lock pages in ascending order of page index. - * When operating on a set of pages, we need to keep track of them so that - * we can lock them in order and also unlock them later. For this we collect - * pages (i.e. &struct page_entry's) in a binary search @tree. Given that the - * @tree implementation we use does not provide an O(1) operation to obtain the - * highest-ranked element, we use @max to keep track of the inserted page - * with the highest index. This is valuable because if a page is not in - * the tree and its index is higher than @max's, then we can lock it - * without breaking the locking order rule. - * - * Note on naming: 'struct page_set' would be shorter, but we already have a few - * page_set_*() helpers, so page_collection is used instead to avoid confusion. - * - * See also: page_collection_lock(). - */ -struct page_collection { - GTree *tree; - struct page_entry *max; -}; - -/* list iterators for lists of tagged pointers in TranslationBlock */ -#define TB_FOR_EACH_TAGGED(head, tb, n, field) \ - for (n = (head) & 1, tb = (TranslationBlock *)((head) & ~1); \ - tb; tb = (TranslationBlock *)tb->field[n], n = (uintptr_t)tb & 1, \ - tb = (TranslationBlock *)((uintptr_t)tb & ~1)) - -#define PAGE_FOR_EACH_TB(pagedesc, tb, n) \ - TB_FOR_EACH_TAGGED((pagedesc)->first_tb, tb, n, page_next) - -#define TB_FOR_EACH_JMP(head_tb, tb, n) \ - TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next) - -/* - * In system mode we want L1_MAP to be based on ram offsets, - * while in user mode we want it to be based on virtual addresses. - * - * TODO: For user mode, see the caveat re host vs guest virtual - * address spaces near GUEST_ADDR_MAX. - */ -#if !defined(CONFIG_USER_ONLY) -#if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS -# define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS -#else -# define L1_MAP_ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS -#endif -#else -# define L1_MAP_ADDR_SPACE_BITS MIN(HOST_LONG_BITS, TARGET_ABI_BITS) -#endif - -/* Size of the L2 (and L3, etc) page tables. */ -#define V_L2_BITS 10 -#define V_L2_SIZE (1 << V_L2_BITS) - /* Make sure all possible CPU event bits fit in tb->trace_vcpu_dstate */ QEMU_BUILD_BUG_ON(CPU_TRACE_DSTATE_MAX_EVENTS > sizeof_field(TranslationBlock, trace_vcpu_dstate) * BITS_PER_BYTE); -/* - * L1 Mapping properties - */ -static int v_l1_size; -static int v_l1_shift; -static int v_l2_levels; - -/* The bottom level has pointers to PageDesc, and is indexed by - * anything from 4 to (V_L2_BITS + 3) bits, depending on target page size. - */ -#define V_L1_MIN_BITS 4 -#define V_L1_MAX_BITS (V_L2_BITS + 3) -#define V_L1_MAX_SIZE (1 << V_L1_MAX_BITS) - -static void *l1_map[V_L1_MAX_SIZE]; - TBContext tb_ctx; -static void page_table_config_init(void) -{ - uint32_t v_l1_bits; - - assert(TARGET_PAGE_BITS); - /* The bits remaining after N lower levels of page tables. */ - v_l1_bits = (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % V_L2_BITS; - if (v_l1_bits < V_L1_MIN_BITS) { - v_l1_bits += V_L2_BITS; - } - - v_l1_size = 1 << v_l1_bits; - v_l1_shift = L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - v_l1_bits; - v_l2_levels = v_l1_shift / V_L2_BITS - 1; - - assert(v_l1_bits <= V_L1_MAX_BITS); - assert(v_l1_shift % V_L2_BITS == 0); - assert(v_l2_levels >= 0); -} - /* Encode VAL as a signed leb128 sequence at P. Return P incremented past the encoded value. */ static uint8_t *encode_sleb128(uint8_t *p, target_long val) @@ -305,7 +134,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]; } @@ -326,60 +155,77 @@ static int encode_search(TranslationBlock *tb, uint8_t *block) return p - block; } -/* The cpu state corresponding to 'searched_pc' is restored. - * When reset_icount is true, current TB will be interrupted and - * icount should be recalculated. - */ -static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, - uintptr_t searched_pc, bool reset_icount) +static int cpu_unwind_data_from_tb(TranslationBlock *tb, uintptr_t host_pc, + uint64_t *data) { - target_ulong data[TARGET_INSN_START_WORDS] = { tb->pc }; - uintptr_t host_pc = (uintptr_t)tb->tc.ptr; - CPUArchState *env = cpu->env_ptr; + uintptr_t iter_pc = (uintptr_t)tb->tc.ptr; const uint8_t *p = tb->tc.ptr + tb->tc.size; int i, j, num_insns = tb->icount; -#ifdef CONFIG_PROFILER - TCGProfile *prof = &tcg_ctx->prof; - int64_t ti = profile_getclock(); -#endif - searched_pc -= GETPC_ADJ; + host_pc -= GETPC_ADJ; - if (searched_pc < host_pc) { + if (host_pc < iter_pc) { return -1; } - /* Reconstruct the stored insn data while looking for the point at - which the end of the insn exceeds the searched_pc. */ + memset(data, 0, sizeof(uint64_t) * TARGET_INSN_START_WORDS); + 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 host_pc. + */ for (i = 0; i < num_insns; ++i) { for (j = 0; j < TARGET_INSN_START_WORDS; ++j) { data[j] += decode_sleb128(&p); } - host_pc += decode_sleb128(&p); - if (host_pc > searched_pc) { - goto found; + iter_pc += decode_sleb128(&p); + if (iter_pc > host_pc) { + return num_insns - i; } } return -1; +} - found: - if (reset_icount && (tb_cflags(tb) & CF_USE_ICOUNT)) { +/* + * The cpu state corresponding to 'host_pc' is restored in + * preparation for exiting the TB. + */ +void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, + uintptr_t host_pc) +{ + uint64_t data[TARGET_INSN_START_WORDS]; +#ifdef CONFIG_PROFILER + TCGProfile *prof = &tcg_ctx->prof; + int64_t ti = profile_getclock(); +#endif + int insns_left = cpu_unwind_data_from_tb(tb, host_pc, data); + + if (insns_left < 0) { + return; + } + + if (tb_cflags(tb) & CF_USE_ICOUNT) { assert(icount_enabled()); - /* Reset the cycle counter to the start of the block - and shift if to the number of actually executed instructions */ - cpu_neg(cpu)->icount_decr.u16.low += num_insns - i; + /* + * Reset the cycle counter to the start of the block and + * shift if to the number of actually executed instructions. + */ + cpu_neg(cpu)->icount_decr.u16.low += insns_left; } - restore_state_to_opc(env, tb, data); + + cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data); #ifdef CONFIG_PROFILER qatomic_set(&prof->restore_time, prof->restore_time + profile_getclock() - ti); qatomic_set(&prof->restore_count, prof->restore_count + 1); #endif - return 0; } -bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit) +bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc) { /* * The host_pc has to be in the rx region of the code buffer. @@ -394,988 +240,59 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit) if (in_code_gen_buffer((const void *)(host_pc - tcg_splitwx_diff))) { TranslationBlock *tb = tcg_tb_lookup(host_pc); if (tb) { - cpu_restore_state_from_tb(cpu, tb, host_pc, will_exit); + cpu_restore_state_from_tb(cpu, tb, host_pc); return true; } } return false; } -void page_init(void) -{ - page_size_init(); - page_table_config_init(); - -#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY) - { -#ifdef HAVE_KINFO_GETVMMAP - struct kinfo_vmentry *freep; - int i, cnt; - - freep = kinfo_getvmmap(getpid(), &cnt); - if (freep) { - mmap_lock(); - for (i = 0; i < cnt; i++) { - unsigned long startaddr, endaddr; - - startaddr = freep[i].kve_start; - endaddr = freep[i].kve_end; - if (h2g_valid(startaddr)) { - startaddr = h2g(startaddr) & TARGET_PAGE_MASK; - - if (h2g_valid(endaddr)) { - endaddr = h2g(endaddr); - page_set_flags(startaddr, endaddr, PAGE_RESERVED); - } else { -#if TARGET_ABI_BITS <= L1_MAP_ADDR_SPACE_BITS - endaddr = ~0ul; - page_set_flags(startaddr, endaddr, PAGE_RESERVED); -#endif - } - } - } - free(freep); - mmap_unlock(); - } -#else - FILE *f; - - last_brk = (unsigned long)sbrk(0); - - f = fopen("/compat/linux/proc/self/maps", "r"); - if (f) { - mmap_lock(); - - do { - unsigned long startaddr, endaddr; - int n; - - n = fscanf(f, "%lx-%lx %*[^\n]\n", &startaddr, &endaddr); - - if (n == 2 && h2g_valid(startaddr)) { - startaddr = h2g(startaddr) & TARGET_PAGE_MASK; - - if (h2g_valid(endaddr)) { - endaddr = h2g(endaddr); - } else { - endaddr = ~0ul; - } - page_set_flags(startaddr, endaddr, PAGE_RESERVED); - } - } while (!feof(f)); - - fclose(f); - mmap_unlock(); - } -#endif - } -#endif -} - -static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) -{ - PageDesc *pd; - void **lp; - int i; - - /* Level 1. Always allocated. */ - lp = l1_map + ((index >> v_l1_shift) & (v_l1_size - 1)); - - /* Level 2..N-1. */ - for (i = v_l2_levels; i > 0; i--) { - void **p = qatomic_rcu_read(lp); - - if (p == NULL) { - void *existing; - - if (!alloc) { - return NULL; - } - p = g_new0(void *, V_L2_SIZE); - existing = qatomic_cmpxchg(lp, NULL, p); - if (unlikely(existing)) { - g_free(p); - p = existing; - } - } - - lp = p + ((index >> (i * V_L2_BITS)) & (V_L2_SIZE - 1)); - } - - pd = qatomic_rcu_read(lp); - if (pd == NULL) { - void *existing; - - if (!alloc) { - return NULL; - } - pd = g_new0(PageDesc, V_L2_SIZE); -#ifndef CONFIG_USER_ONLY - { - int i; - - for (i = 0; i < V_L2_SIZE; i++) { - qemu_spin_init(&pd[i].lock); - } - } -#endif - existing = qatomic_cmpxchg(lp, NULL, pd); - if (unlikely(existing)) { -#ifndef CONFIG_USER_ONLY - { - int i; - - for (i = 0; i < V_L2_SIZE; i++) { - qemu_spin_destroy(&pd[i].lock); - } - } -#endif - g_free(pd); - pd = existing; - } - } - - return pd + (index & (V_L2_SIZE - 1)); -} - -static inline PageDesc *page_find(tb_page_addr_t index) -{ - return page_find_alloc(index, 0); -} - -static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, - PageDesc **ret_p2, tb_page_addr_t phys2, int alloc); - -/* In user-mode page locks aren't used; mmap_lock is enough */ -#ifdef CONFIG_USER_ONLY - -#define assert_page_locked(pd) tcg_debug_assert(have_mmap_lock()) - -static inline void page_lock(PageDesc *pd) -{ } - -static inline void page_unlock(PageDesc *pd) -{ } - -static inline void page_lock_tb(const TranslationBlock *tb) -{ } - -static inline void page_unlock_tb(const TranslationBlock *tb) -{ } - -struct page_collection * -page_collection_lock(tb_page_addr_t start, tb_page_addr_t end) -{ - return NULL; -} - -void page_collection_unlock(struct page_collection *set) -{ } -#else /* !CONFIG_USER_ONLY */ - -#ifdef CONFIG_DEBUG_TCG - -static __thread GHashTable *ht_pages_locked_debug; - -static void ht_pages_locked_debug_init(void) -{ - if (ht_pages_locked_debug) { - return; - } - ht_pages_locked_debug = g_hash_table_new(NULL, NULL); -} - -static bool page_is_locked(const PageDesc *pd) -{ - PageDesc *found; - - ht_pages_locked_debug_init(); - found = g_hash_table_lookup(ht_pages_locked_debug, pd); - return !!found; -} - -static void page_lock__debug(PageDesc *pd) -{ - ht_pages_locked_debug_init(); - g_assert(!page_is_locked(pd)); - g_hash_table_insert(ht_pages_locked_debug, pd, pd); -} - -static void page_unlock__debug(const PageDesc *pd) -{ - bool removed; - - ht_pages_locked_debug_init(); - g_assert(page_is_locked(pd)); - removed = g_hash_table_remove(ht_pages_locked_debug, pd); - g_assert(removed); -} - -static void -do_assert_page_locked(const PageDesc *pd, const char *file, int line) -{ - if (unlikely(!page_is_locked(pd))) { - error_report("assert_page_lock: PageDesc %p not locked @ %s:%d", - pd, file, line); - abort(); - } -} - -#define assert_page_locked(pd) do_assert_page_locked(pd, __FILE__, __LINE__) - -void assert_no_pages_locked(void) -{ - ht_pages_locked_debug_init(); - g_assert(g_hash_table_size(ht_pages_locked_debug) == 0); -} - -#else /* !CONFIG_DEBUG_TCG */ - -#define assert_page_locked(pd) - -static inline void page_lock__debug(const PageDesc *pd) -{ -} - -static inline void page_unlock__debug(const PageDesc *pd) -{ -} - -#endif /* CONFIG_DEBUG_TCG */ - -static inline void page_lock(PageDesc *pd) -{ - page_lock__debug(pd); - qemu_spin_lock(&pd->lock); -} - -static inline void page_unlock(PageDesc *pd) -{ - qemu_spin_unlock(&pd->lock); - page_unlock__debug(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); -} - -static inline void page_unlock_tb(const TranslationBlock *tb) -{ - PageDesc *p1 = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); - - page_unlock(p1); - if (unlikely(tb->page_addr[1] != -1)) { - PageDesc *p2 = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); - - if (p2 != p1) { - page_unlock(p2); - } - } -} - -static inline struct page_entry * -page_entry_new(PageDesc *pd, tb_page_addr_t index) -{ - struct page_entry *pe = g_malloc(sizeof(*pe)); - - pe->index = index; - pe->pd = pd; - pe->locked = false; - return pe; -} - -static void page_entry_destroy(gpointer p) -{ - struct page_entry *pe = p; - - g_assert(pe->locked); - page_unlock(pe->pd); - g_free(pe); -} - -/* returns false on success */ -static bool page_entry_trylock(struct page_entry *pe) -{ - bool busy; - - busy = qemu_spin_trylock(&pe->pd->lock); - if (!busy) { - g_assert(!pe->locked); - pe->locked = true; - page_lock__debug(pe->pd); - } - return busy; -} - -static void do_page_entry_lock(struct page_entry *pe) -{ - page_lock(pe->pd); - g_assert(!pe->locked); - pe->locked = true; -} - -static gboolean page_entry_lock(gpointer key, gpointer value, gpointer data) -{ - struct page_entry *pe = value; - - do_page_entry_lock(pe); - return FALSE; -} - -static gboolean page_entry_unlock(gpointer key, gpointer value, gpointer data) -{ - struct page_entry *pe = value; - - if (pe->locked) { - pe->locked = false; - page_unlock(pe->pd); - } - return FALSE; -} - -/* - * Trylock a page, and if successful, add the page to a collection. - * Returns true ("busy") if the page could not be locked; false otherwise. - */ -static bool page_trylock_add(struct page_collection *set, tb_page_addr_t addr) -{ - tb_page_addr_t index = addr >> TARGET_PAGE_BITS; - struct page_entry *pe; - PageDesc *pd; - - pe = g_tree_lookup(set->tree, &index); - if (pe) { - return false; - } - - pd = page_find(index); - if (pd == NULL) { - return false; - } - - pe = page_entry_new(pd, index); - g_tree_insert(set->tree, &pe->index, pe); - - /* - * If this is either (1) the first insertion or (2) a page whose index - * is higher than any other so far, just lock the page and move on. - */ - if (set->max == NULL || pe->index > set->max->index) { - set->max = pe; - do_page_entry_lock(pe); - return false; - } - /* - * Try to acquire out-of-order lock; if busy, return busy so that we acquire - * locks in order. - */ - return page_entry_trylock(pe); -} - -static gint tb_page_addr_cmp(gconstpointer ap, gconstpointer bp, gpointer udata) -{ - tb_page_addr_t a = *(const tb_page_addr_t *)ap; - tb_page_addr_t b = *(const tb_page_addr_t *)bp; - - if (a == b) { - return 0; - } else if (a < b) { - return -1; - } - return 1; -} - -/* - * Lock a range of pages ([@start,@end[) as well as the pages of all - * intersecting TBs. - * Locking order: acquire locks in ascending order of page index. - */ -struct page_collection * -page_collection_lock(tb_page_addr_t start, tb_page_addr_t end) -{ - struct page_collection *set = g_malloc(sizeof(*set)); - tb_page_addr_t index; - PageDesc *pd; - - start >>= TARGET_PAGE_BITS; - end >>= TARGET_PAGE_BITS; - g_assert(start <= end); - - set->tree = g_tree_new_full(tb_page_addr_cmp, NULL, NULL, - page_entry_destroy); - set->max = NULL; - assert_no_pages_locked(); - - retry: - g_tree_foreach(set->tree, page_entry_lock, NULL); - - for (index = start; index <= end; index++) { - TranslationBlock *tb; - int n; - - pd = page_find(index); - if (pd == NULL) { - continue; - } - if (page_trylock_add(set, index << TARGET_PAGE_BITS)) { - g_tree_foreach(set->tree, page_entry_unlock, NULL); - goto retry; - } - assert_page_locked(pd); - PAGE_FOR_EACH_TB(pd, tb, n) { - if (page_trylock_add(set, tb->page_addr[0]) || - (tb->page_addr[1] != -1 && - page_trylock_add(set, tb->page_addr[1]))) { - /* drop all locks, and reacquire in order */ - g_tree_foreach(set->tree, page_entry_unlock, NULL); - goto retry; - } - } - } - return set; -} - -void page_collection_unlock(struct page_collection *set) -{ - /* entries are unlocked and freed via page_entry_destroy */ - g_tree_destroy(set->tree); - g_free(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 *p1, *p2; - tb_page_addr_t page1; - tb_page_addr_t page2; - - assert_memory_lock(); - g_assert(phys1 != -1); - - page1 = phys1 >> TARGET_PAGE_BITS; - page2 = phys2 >> TARGET_PAGE_BITS; - - p1 = page_find_alloc(page1, alloc); - if (ret_p1) { - *ret_p1 = p1; - } - if (likely(phys2 == -1)) { - page_lock(p1); - return; - } else if (page1 == page2) { - page_lock(p1); - if (ret_p2) { - *ret_p2 = p1; - } - return; - } - p2 = page_find_alloc(page2, alloc); - if (ret_p2) { - *ret_p2 = p2; - } - if (page1 < page2) { - page_lock(p1); - page_lock(p2); - } else { - page_lock(p2); - page_lock(p1); - } -} - -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]; -} - -void tb_htable_init(void) -{ - unsigned int mode = QHT_MODE_AUTO_RESIZE; - - 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) -{ - int i; - - if (*lp == NULL) { - return; - } - if (level == 0) { - PageDesc *pd = *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 { - void **pp = *lp; - - for (i = 0; i < V_L2_SIZE; ++i) { - page_flush_tb_1(level - 1, pp + i); - } - } -} - -static void page_flush_tb(void) -{ - int i, l1_sz = v_l1_size; - - for (i = 0; i < l1_sz; i++) { - page_flush_tb_1(v_l2_levels, l1_map + i); - } -} - -static gboolean tb_host_size_iter(gpointer key, gpointer value, gpointer data) -{ - const TranslationBlock *tb = value; - size_t *size = data; - - *size += tb->tc.size; - return false; -} - -/* flush all the translation blocks */ -static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) -{ - bool did_flush = false; - - mmap_lock(); - /* If it is already been done on request of another CPU, - * just retry. - */ - if (tb_ctx.tb_flush_count != tb_flush_count.host_int) { - goto done; - } - did_flush = true; - - if (DEBUG_TB_FLUSH_GATE) { - size_t nb_tbs = tcg_nb_tbs(); - size_t host_size = 0; - - tcg_tb_foreach(tb_host_size_iter, &host_size); - printf("qemu: flush code_size=%zu nb_tbs=%zu avg_tb_size=%zu\n", - tcg_code_size(), nb_tbs, nb_tbs > 0 ? host_size / nb_tbs : 0); - } - - CPU_FOREACH(cpu) { - cpu_tb_jmp_cache_clear(cpu); - } - - qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE); - page_flush_tb(); - - tcg_region_reset_all(); - /* XXX: flush processor icache at this point if cache flush is - expensive */ - qatomic_mb_set(&tb_ctx.tb_flush_count, tb_ctx.tb_flush_count + 1); - -done: - mmap_unlock(); - if (did_flush) { - qemu_plugin_flush_cb(); - } -} - -void tb_flush(CPUState *cpu) -{ - if (tcg_enabled()) { - unsigned tb_flush_count = qatomic_mb_read(&tb_ctx.tb_flush_count); - - if (cpu_in_exclusive_context(cpu)) { - do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count)); - } else { - async_safe_run_on_cpu(cpu, do_tb_flush, - RUN_ON_CPU_HOST_INT(tb_flush_count)); - } - } -} - -/* - * Formerly ifdef DEBUG_TB_CHECK. These debug functions are user-mode-only, - * so in order to prevent bit rot we compile them unconditionally in user-mode, - * and let the optimizer get rid of them by wrapping their user-only callers - * with if (DEBUG_TB_CHECK_GATE). - */ -#ifdef CONFIG_USER_ONLY - -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)) { - printf("ERROR invalidate: address=" TARGET_FMT_lx - " PC=%08lx size=%04x\n", addr, (long)tb->pc, tb->size); - } -} - -/* verify that all the pages have correct rights for code - * - * Called with mmap_lock held. - */ -static void tb_invalidate_check(target_ulong address) -{ - address &= TARGET_PAGE_MASK; - qht_iter(&tb_ctx.htable, do_tb_invalidate_check, &address); -} - -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); - 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); - } -} - -/* verify that all the pages have correct rights for code */ -static void tb_page_check(void) -{ - qht_iter(&tb_ctx.htable, do_tb_page_check, NULL); -} - -#endif /* CONFIG_USER_ONLY */ - -/* - * user-mode: call with mmap_lock held - * !user-mode: call with @pd->lock held - */ -static inline void tb_page_remove(PageDesc *pd, TranslationBlock *tb) -{ - TranslationBlock *tb1; - uintptr_t *pprev; - unsigned int n1; - - assert_page_locked(pd); - pprev = &pd->first_tb; - PAGE_FOR_EACH_TB(pd, tb1, n1) { - if (tb1 == tb) { - *pprev = tb1->page_next[n1]; - return; - } - pprev = &tb1->page_next[n1]; - } - g_assert_not_reached(); -} - -/* remove @orig from its @n_orig-th jump list */ -static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig) -{ - uintptr_t ptr, ptr_locked; - TranslationBlock *dest; - TranslationBlock *tb; - uintptr_t *pprev; - int n; - - /* mark the LSB of jmp_dest[] so that no further jumps can be inserted */ - ptr = qatomic_or_fetch(&orig->jmp_dest[n_orig], 1); - dest = (TranslationBlock *)(ptr & ~1); - if (dest == NULL) { - return; - } - - qemu_spin_lock(&dest->jmp_lock); - /* - * While acquiring the lock, the jump might have been removed if the - * destination TB was invalidated; check again. - */ - ptr_locked = qatomic_read(&orig->jmp_dest[n_orig]); - if (ptr_locked != ptr) { - qemu_spin_unlock(&dest->jmp_lock); - /* - * The only possibility is that the jump was unlinked via - * tb_jump_unlink(dest). Seeing here another destination would be a bug, - * because we set the LSB above. - */ - g_assert(ptr_locked == 1 && dest->cflags & CF_INVALID); - return; - } - /* - * We first acquired the lock, and since the destination pointer matches, - * we know for sure that @orig is in the jmp list. - */ - pprev = &dest->jmp_list_head; - TB_FOR_EACH_JMP(dest, tb, n) { - if (tb == orig && n == n_orig) { - *pprev = tb->jmp_list_next[n]; - /* no need to set orig->jmp_dest[n]; setting the LSB was enough */ - qemu_spin_unlock(&dest->jmp_lock); - return; - } - pprev = &tb->jmp_list_next[n]; - } - g_assert_not_reached(); -} - -/* reset the jump entry 'n' of a TB so that it is not chained to - another TB */ -static inline void tb_reset_jump(TranslationBlock *tb, int n) -{ - uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]); - tb_set_jmp_target(tb, n, addr); -} - -/* remove any jumps to the TB */ -static inline void tb_jmp_unlink(TranslationBlock *dest) -{ - TranslationBlock *tb; - int n; - - qemu_spin_lock(&dest->jmp_lock); - - TB_FOR_EACH_JMP(dest, tb, n) { - tb_reset_jump(tb, n); - qatomic_and(&tb->jmp_dest[n], (uintptr_t)NULL | 1); - /* No need to clear the list entry; setting the dest ptr is enough */ - } - dest->jmp_list_head = (uintptr_t)NULL; - - qemu_spin_unlock(&dest->jmp_lock); -} - -/* - * In user-mode, call with mmap_lock held. - * In !user-mode, if @rm_from_page_list is set, call with the TB's pages' - * locks held. - */ -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; - uint32_t orig_cflags = tb_cflags(tb); - - assert_memory_lock(); - - /* make sure no further incoming jumps will be chained to this TB */ - qemu_spin_lock(&tb->jmp_lock); - qatomic_set(&tb->cflags, tb->cflags | CF_INVALID); - 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); - if (!qht_remove(&tb_ctx.htable, tb, h)) { - return; - } - - /* remove the TB from the 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); - } - } - - /* suppress this TB from the two jump lists */ - tb_remove_from_jmp_list(tb, 0); - tb_remove_from_jmp_list(tb, 1); - - /* suppress any remaining jumps to this TB */ - tb_jmp_unlink(tb); - - qatomic_set(&tb_ctx.tb_phys_invalidate_count, - tb_ctx.tb_phys_invalidate_count + 1); -} - -static void tb_phys_invalidate__locked(TranslationBlock *tb) -{ - qemu_thread_jit_write(); - do_tb_phys_invalidate(tb, true); - qemu_thread_jit_execute(); -} - -/* invalidate one TB - * - * Called with mmap_lock held in user-mode. - */ -void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) +bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data) { - if (page_addr == -1 && tb->page_addr[0] != -1) { - page_lock_tb(tb); - do_tb_phys_invalidate(tb, true); - page_unlock_tb(tb); - } else { - do_tb_phys_invalidate(tb, false); - } -} - -#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); + if (in_code_gen_buffer((const void *)(host_pc - tcg_splitwx_diff))) { + TranslationBlock *tb = tcg_tb_lookup(host_pc); + if (tb) { + return cpu_unwind_data_from_tb(tb, host_pc, data) >= 0; } - 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. - * Called with @p->lock held in !user-mode. - */ -static inline void tb_page_add(PageDesc *p, TranslationBlock *tb, - unsigned int n, tb_page_addr_t page_addr) -{ -#ifndef CONFIG_USER_ONLY - bool page_already_protected; -#endif - - assert_page_locked(p); - - tb->page_addr[n] = page_addr; - tb->page_next[n] = p->first_tb; -#ifndef CONFIG_USER_ONLY - 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 */ - assert(!(p->flags & PAGE_WRITE)); -#else - /* if some code is already present, then the pages are already - protected. So we handle the case where only the first TB is - allocated in a physical page */ - if (!page_already_protected) { - tlb_protect_code(page_addr); } -#endif + return false; +} + +void page_init(void) +{ + page_size_init(); + page_table_config_init(); } /* - * Add a new TB and link it to the physical page tables. phys_page2 is - * (-1) to indicate that only one page contains the TB. - * - * Called with mmap_lock held for user-mode emulation. - * - * Returns a pointer @tb, or a pointer to an existing TB that matches @tb. - * Note that in !user-mode, another thread might have already added a TB - * for the same block of guest code that @tb corresponds to. In that case, - * the caller should discard the original @tb, and use instead the returned TB. + * Isolate the portion of code gen which can setjmp/longjmp. + * Return the size of the generated code, or negative on error. */ -static TranslationBlock * -tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, - tb_page_addr_t phys_page2) +static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, + target_ulong pc, void *host_pc, + int *max_insns, int64_t *ti) { - PageDesc *p; - PageDesc *p2 = NULL; - void *existing_tb = NULL; - uint32_t h; - - assert_memory_lock(); - tcg_debug_assert(!(tb->cflags & CF_INVALID)); - - /* - * Add the TB to the page list, acquiring first the pages's locks. - * We keep the locks held until after inserting the TB in the hash table, - * so that if the insertion fails we know for sure that the TBs are still - * in the page descriptors. - * 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); - if (p2) { - tb_page_add(p2, tb, 1, phys_page2); - } else { - tb->page_addr[1] = -1; + int ret = sigsetjmp(tcg_ctx->jmp_trans, 0); + if (unlikely(ret != 0)) { + return ret; } - /* add in the hash table */ - h = tb_hash_func(phys_pc, tb->pc, 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; - } + tcg_func_start(tcg_ctx); - if (p2 && p2 != p) { - page_unlock(p2); - } - page_unlock(p); + tcg_ctx->cpu = env_cpu(env); + gen_intermediate_code(env_cpu(env), tb, *max_insns, pc, host_pc); + assert(tb->size != 0); + tcg_ctx->cpu = NULL; + *max_insns = tb->icount; -#ifdef CONFIG_USER_ONLY - if (DEBUG_TB_CHECK_GATE) { - tb_page_check(); - } +#ifdef CONFIG_PROFILER + qatomic_set(&tcg_ctx->prof.tb_count, tcg_ctx->prof.tb_count + 1); + qatomic_set(&tcg_ctx->prof.interm_time, + tcg_ctx->prof.interm_time + profile_getclock() - *ti); + *ti = profile_getclock(); #endif - return tb; + + return tcg_gen_code(tcg_ctx, tb, pc); } /* Called with mmap_lock held for user mode emulation. */ @@ -1385,19 +302,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 + int64_t ti; + 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 */ @@ -1423,11 +340,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_set_page_addr0(tb, phys_pc); + tb_set_page_addr1(tb, -1); tcg_ctx->tb_cflags = cflags; tb_overflow: @@ -1437,43 +358,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu, ti = profile_getclock(); #endif - gen_code_size = sigsetjmp(tcg_ctx->jmp_trans, 0); - if (unlikely(gen_code_size != 0)) { - goto error_return; - } - - tcg_func_start(tcg_ctx); - - tcg_ctx->cpu = env_cpu(env); - gen_intermediate_code(cpu, tb, max_insns); - assert(tb->size != 0); - tcg_ctx->cpu = NULL; - max_insns = tb->icount; - - trace_translate_block(tb, tb->pc, tb->tc.ptr); - - /* generate machine code */ - tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID; - tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID; - tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset; - if (TCG_TARGET_HAS_direct_jump) { - tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg; - tcg_ctx->tb_jmp_target_addr = NULL; - } else { - tcg_ctx->tb_jmp_insn_offset = NULL; - tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg; - } - -#ifdef CONFIG_PROFILER - qatomic_set(&prof->tb_count, prof->tb_count + 1); - qatomic_set(&prof->interm_time, - prof->interm_time + profile_getclock() - ti); - ti = profile_getclock(); -#endif + trace_translate_block(tb, pc, tb->tc.ptr); - gen_code_size = tcg_gen_code(tcg_ctx, tb); + gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti); if (unlikely(gen_code_size < 0)) { - error_return: switch (gen_code_size) { case -1: /* @@ -1527,70 +415,76 @@ 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)) { - FILE *logfile = qemu_log_lock(); - int code_size, data_size; - const tcg_target_ulong *rx_data_gen_ptr; - size_t chunk_start; - int insn = 0; - - if (tcg_ctx->data_gen_ptr) { - rx_data_gen_ptr = tcg_splitwx_to_rx(tcg_ctx->data_gen_ptr); - code_size = (const void *)rx_data_gen_ptr - tb->tc.ptr; - data_size = gen_code_size - code_size; - } else { - rx_data_gen_ptr = 0; - code_size = gen_code_size; - data_size = 0; - } + qemu_log_in_addr_range(pc)) { + FILE *logfile = qemu_log_trylock(); + if (logfile) { + int code_size, data_size; + const tcg_target_ulong *rx_data_gen_ptr; + size_t chunk_start; + int insn = 0; + + if (tcg_ctx->data_gen_ptr) { + rx_data_gen_ptr = tcg_splitwx_to_rx(tcg_ctx->data_gen_ptr); + code_size = (const void *)rx_data_gen_ptr - tb->tc.ptr; + data_size = gen_code_size - code_size; + } else { + rx_data_gen_ptr = 0; + code_size = gen_code_size; + data_size = 0; + } - /* Dump header and the first instruction */ - qemu_log("OUT: [size=%d]\n", gen_code_size); - qemu_log(" -- guest addr 0x" TARGET_FMT_lx " + tb prologue\n", - tcg_ctx->gen_insn_data[insn][0]); - chunk_start = tcg_ctx->gen_insn_end_off[insn]; - log_disas(tb->tc.ptr, chunk_start); + /* Dump header and the first instruction */ + fprintf(logfile, "OUT: [size=%d]\n", gen_code_size); + fprintf(logfile, + " -- guest addr 0x" TARGET_FMT_lx " + tb prologue\n", + tcg_ctx->gen_insn_data[insn][0]); + chunk_start = tcg_ctx->gen_insn_end_off[insn]; + disas(logfile, tb->tc.ptr, chunk_start); - /* - * Dump each instruction chunk, wrapping up empty chunks into - * the next instruction. The whole array is offset so the - * first entry is the beginning of the 2nd instruction. - */ - while (insn < tb->icount) { - size_t chunk_end = tcg_ctx->gen_insn_end_off[insn]; - if (chunk_end > chunk_start) { - qemu_log(" -- guest addr 0x" TARGET_FMT_lx "\n", - tcg_ctx->gen_insn_data[insn][0]); - log_disas(tb->tc.ptr + chunk_start, chunk_end - chunk_start); - chunk_start = chunk_end; + /* + * Dump each instruction chunk, wrapping up empty chunks into + * the next instruction. The whole array is offset so the + * first entry is the beginning of the 2nd instruction. + */ + while (insn < tb->icount) { + size_t chunk_end = tcg_ctx->gen_insn_end_off[insn]; + if (chunk_end > chunk_start) { + fprintf(logfile, " -- guest addr 0x" TARGET_FMT_lx "\n", + tcg_ctx->gen_insn_data[insn][0]); + disas(logfile, tb->tc.ptr + chunk_start, + chunk_end - chunk_start); + chunk_start = chunk_end; + } + insn++; } - insn++; - } - if (chunk_start < code_size) { - qemu_log(" -- tb slow paths + alignment\n"); - log_disas(tb->tc.ptr + chunk_start, code_size - chunk_start); - } + if (chunk_start < code_size) { + fprintf(logfile, " -- tb slow paths + alignment\n"); + disas(logfile, tb->tc.ptr + chunk_start, + code_size - chunk_start); + } - /* Finally dump any data we may have after the block */ - if (data_size) { - int i; - qemu_log(" data: [size=%d]\n", data_size); - for (i = 0; i < data_size / sizeof(tcg_target_ulong); i++) { - if (sizeof(tcg_target_ulong) == 8) { - qemu_log("0x%08" PRIxPTR ": .quad 0x%016" TCG_PRIlx "\n", - (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); - } else if (sizeof(tcg_target_ulong) == 4) { - qemu_log("0x%08" PRIxPTR ": .long 0x%08" TCG_PRIlx "\n", - (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); - } else { - qemu_build_not_reached(); + /* Finally dump any data we may have after the block */ + if (data_size) { + int i; + fprintf(logfile, " data: [size=%d]\n", data_size); + for (i = 0; i < data_size / sizeof(tcg_target_ulong); i++) { + if (sizeof(tcg_target_ulong) == 8) { + fprintf(logfile, + "0x%08" PRIxPTR ": .quad 0x%016" TCG_PRIlx "\n", + (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); + } else if (sizeof(tcg_target_ulong) == 4) { + fprintf(logfile, + "0x%08" PRIxPTR ": .long 0x%08" TCG_PRIlx "\n", + (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); + } else { + qemu_build_not_reached(); + } } } + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); } - qemu_log("\n"); - qemu_log_flush(); - qemu_log_unlock(logfile); } #endif @@ -1615,13 +509,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_addr0(tb) == -1) { return tb; } @@ -1632,17 +524,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_addr0(tb), tb_page_addr1(tb)); /* if the TB already exists, discard what we just translated */ if (unlikely(existing_tb != tb)) { uintptr_t orig_aligned = (uintptr_t)gen_code_buf; @@ -1655,267 +541,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, return tb; } -/* - * @p must be non-NULL. - * user-mode: call with mmap_lock held. - * !user-mode: call with all @pages locked. - */ -static void -tb_invalidate_phys_page_range__locked(struct page_collection *pages, - PageDesc *p, tb_page_addr_t start, - tb_page_addr_t end, - uintptr_t retaddr) -{ - TranslationBlock *tb; - tb_page_addr_t tb_start, tb_end; - int n; -#ifdef TARGET_HAS_PRECISE_SMC - CPUState *cpu = current_cpu; - CPUArchState *env = NULL; - bool current_tb_not_found = retaddr != 0; - bool current_tb_modified = false; - TranslationBlock *current_tb = NULL; - target_ulong current_pc = 0; - target_ulong current_cs_base = 0; - uint32_t current_flags = 0; -#endif /* TARGET_HAS_PRECISE_SMC */ - - assert_page_locked(p); - -#if defined(TARGET_HAS_PRECISE_SMC) - if (cpu != NULL) { - env = cpu->env_ptr; - } -#endif - - /* we remove all the TBs in the range [start, end[ */ - /* XXX: see if in some cases it could be faster to invalidate all - the code */ - PAGE_FOR_EACH_TB(p, tb, n) { - assert_page_locked(p); - /* 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->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); - tb_end = tb_start + tb->size; - } else { - tb_start = tb->page_addr[1]; - tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); - } - if (!(tb_end <= start || tb_start >= end)) { -#ifdef TARGET_HAS_PRECISE_SMC - if (current_tb_not_found) { - current_tb_not_found = false; - /* now we have a real cpu fault */ - current_tb = tcg_tb_lookup(retaddr); - } - if (current_tb == tb && - (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { - /* - * If we are modifying the current TB, we must stop - * its execution. We could be more precise by checking - * that the modification is after the current PC, but it - * would require a specialized function to partially - * restore the CPU state. - */ - current_tb_modified = true; - cpu_restore_state_from_tb(cpu, current_tb, retaddr, true); - cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, - ¤t_flags); - } -#endif /* TARGET_HAS_PRECISE_SMC */ - tb_phys_invalidate__locked(tb); - } - } -#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 -#ifdef TARGET_HAS_PRECISE_SMC - if (current_tb_modified) { - page_collection_unlock(pages); - /* Force execution of one insn next time. */ - cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); - mmap_unlock(); - cpu_loop_exit_noexc(cpu); - } -#endif -} - -/* - * Invalidate all TBs which intersect with the target physical address range - * [start;end[. NOTE: start and end must refer to the *same* physical page. - * 'is_cpu_write_access' should be true if called from a real cpu write - * access: the virtual CPU will exit the current TB if code is modified inside - * this TB. - * - * Called with mmap_lock held for user-mode emulation - */ -void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end) -{ - struct page_collection *pages; - PageDesc *p; - - assert_memory_lock(); - - p = page_find(start >> TARGET_PAGE_BITS); - if (p == NULL) { - return; - } - pages = page_collection_lock(start, end); - tb_invalidate_phys_page_range__locked(pages, p, start, end, 0); - page_collection_unlock(pages); -} - -/* - * Invalidate all TBs which intersect with the target physical address range - * [start;end[. NOTE: start and end may refer to *different* physical pages. - * 'is_cpu_write_access' should be true if called from a real cpu write - * access: the virtual CPU will exit the current TB if code is modified inside - * this TB. - * - * Called with mmap_lock held for user-mode emulation. - */ -#ifdef CONFIG_SOFTMMU -void tb_invalidate_phys_range(ram_addr_t start, ram_addr_t end) -#else -void tb_invalidate_phys_range(target_ulong start, target_ulong end) -#endif -{ - struct page_collection *pages; - tb_page_addr_t next; - - assert_memory_lock(); - - pages = page_collection_lock(start, end); - for (next = (start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - start < end; - start = next, next += TARGET_PAGE_SIZE) { - PageDesc *pd = page_find(start >> TARGET_PAGE_BITS); - tb_page_addr_t bound = MIN(next, end); - - if (pd == NULL) { - continue; - } - tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0); - } - page_collection_unlock(pages); -} - -#ifdef CONFIG_SOFTMMU -/* len must be <= 8 and start must be a multiple of len. - * Called via softmmu_template.h when code areas are written to with - * iothread mutex not held. - * - * Call with all @pages in the range [@start, @start + len[ locked. - */ -void tb_invalidate_phys_page_fast(struct page_collection *pages, - tb_page_addr_t start, int len, - uintptr_t retaddr) -{ - PageDesc *p; - - assert_memory_lock(); - - p = page_find(start >> TARGET_PAGE_BITS); - if (!p) { - return; - } - - 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); - } -} -#else -/* Called with mmap_lock held. If pc is not 0 then it indicates the - * host PC of the faulting store instruction that caused this invalidate. - * Returns true if the caller needs to abort execution of the current - * TB (because it was modified by this store and the guest CPU has - * precise-SMC semantics). - */ -static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc) -{ - TranslationBlock *tb; - PageDesc *p; - int n; -#ifdef TARGET_HAS_PRECISE_SMC - TranslationBlock *current_tb = NULL; - CPUState *cpu = current_cpu; - CPUArchState *env = NULL; - int current_tb_modified = 0; - target_ulong current_pc = 0; - target_ulong current_cs_base = 0; - uint32_t current_flags = 0; -#endif - - assert_memory_lock(); - - addr &= TARGET_PAGE_MASK; - p = page_find(addr >> TARGET_PAGE_BITS); - if (!p) { - return false; - } - -#ifdef TARGET_HAS_PRECISE_SMC - if (p->first_tb && pc != 0) { - current_tb = tcg_tb_lookup(pc); - } - if (cpu != NULL) { - env = cpu->env_ptr; - } -#endif - assert_page_locked(p); - PAGE_FOR_EACH_TB(p, tb, n) { -#ifdef TARGET_HAS_PRECISE_SMC - if (current_tb == tb && - (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { - /* If we are modifying the current TB, we must stop - its execution. We could be more precise by checking - that the modification is after the current PC, but it - would require a specialized function to partially - restore the CPU state */ - - current_tb_modified = 1; - cpu_restore_state_from_tb(cpu, current_tb, pc, true); - cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, - ¤t_flags); - } -#endif /* TARGET_HAS_PRECISE_SMC */ - tb_phys_invalidate(tb, addr); - } - p->first_tb = (uintptr_t)NULL; -#ifdef TARGET_HAS_PRECISE_SMC - if (current_tb_modified) { - /* Force execution of one insn next time. */ - cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); - return true; - } -#endif - - return false; -} -#endif - /* user-mode: call with mmap_lock held */ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) { @@ -1926,7 +551,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) tb = tcg_tb_lookup(retaddr); if (tb) { /* We can use retranslation to find the PC. */ - cpu_restore_state_from_tb(cpu, tb, retaddr, true); + cpu_restore_state_from_tb(cpu, tb, retaddr); tb_phys_invalidate(tb, -1); } else { /* The exception probably happened in a helper. The CPU state should @@ -1962,7 +587,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) cpu_abort(cpu, "cpu_io_recompile: could not find TB for pc=%p", (void *)retaddr); } - cpu_restore_state_from_tb(cpu, tb, retaddr, true); + cpu_restore_state_from_tb(cpu, tb, retaddr); /* * Some guests must re-execute the branch when re-executing a delay @@ -1985,9 +610,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); } @@ -2054,7 +683,7 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data) if (tb->size > tst->max_target_size) { tst->max_target_size = tb->size; } - if (tb->page_addr[1] != -1) { + if (tb_page_addr1(tb) != -1) { tst->cross_page++; } if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) { @@ -2119,11 +748,6 @@ void dump_exec_info(GString *buf) tcg_dump_info(buf); } -void dump_opcount_info(GString *buf) -{ - tcg_dump_op_count(buf); -} - #else /* CONFIG_USER_ONLY */ void cpu_interrupt(CPUState *cpu, int mask) @@ -2133,354 +757,25 @@ void cpu_interrupt(CPUState *cpu, int mask) qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); } +#endif /* CONFIG_USER_ONLY */ + /* - * Walks guest process memory "regions" one by one - * and calls callback function 'fn' for each region. + * Called by generic code at e.g. cpu reset after cpu creation, + * therefore we must be prepared to allocate the jump cache. */ -struct walk_memory_regions_data { - walk_memory_regions_fn fn; - void *priv; - target_ulong start; - int prot; -}; - -static int walk_memory_regions_end(struct walk_memory_regions_data *data, - target_ulong end, int new_prot) -{ - if (data->start != -1u) { - int rc = data->fn(data->priv, data->start, end, data->prot); - if (rc != 0) { - return rc; - } - } - - data->start = (new_prot ? end : -1u); - data->prot = new_prot; - - return 0; -} - -static int walk_memory_regions_1(struct walk_memory_regions_data *data, - target_ulong base, int level, void **lp) -{ - target_ulong pa; - int i, rc; - - if (*lp == NULL) { - return walk_memory_regions_end(data, base, 0); - } - - if (level == 0) { - PageDesc *pd = *lp; - - for (i = 0; i < V_L2_SIZE; ++i) { - int prot = pd[i].flags; - - pa = base | (i << TARGET_PAGE_BITS); - if (prot != data->prot) { - rc = walk_memory_regions_end(data, pa, prot); - if (rc != 0) { - return rc; - } - } - } - } else { - void **pp = *lp; - - for (i = 0; i < V_L2_SIZE; ++i) { - pa = base | ((target_ulong)i << - (TARGET_PAGE_BITS + V_L2_BITS * level)); - rc = walk_memory_regions_1(data, pa, level - 1, pp + i); - if (rc != 0) { - return rc; - } - } - } - - return 0; -} - -int walk_memory_regions(void *priv, walk_memory_regions_fn fn) -{ - struct walk_memory_regions_data data; - uintptr_t i, l1_sz = v_l1_size; - - data.fn = fn; - data.priv = priv; - data.start = -1u; - data.prot = 0; - - for (i = 0; i < l1_sz; i++) { - target_ulong base = i << (v_l1_shift + TARGET_PAGE_BITS); - int rc = walk_memory_regions_1(&data, base, v_l2_levels, l1_map + i); - if (rc != 0) { - return rc; - } - } - - return walk_memory_regions_end(&data, 0, 0); -} - -static int dump_region(void *priv, target_ulong start, - target_ulong end, unsigned long prot) -{ - FILE *f = (FILE *)priv; - - (void) fprintf(f, TARGET_FMT_lx"-"TARGET_FMT_lx - " "TARGET_FMT_lx" %c%c%c\n", - start, end, end - start, - ((prot & PAGE_READ) ? 'r' : '-'), - ((prot & PAGE_WRITE) ? 'w' : '-'), - ((prot & PAGE_EXEC) ? 'x' : '-')); - - return 0; -} - -/* dump memory mappings */ -void page_dump(FILE *f) -{ - const int length = sizeof(target_ulong) * 2; - (void) fprintf(f, "%-*s %-*s %-*s %s\n", - length, "start", length, "end", length, "size", "prot"); - walk_memory_regions(f, dump_region); -} - -int page_get_flags(target_ulong address) -{ - PageDesc *p; - - p = page_find(address >> TARGET_PAGE_BITS); - if (!p) { - return 0; - } - return p->flags; -} - -/* Modify the flags of a page and invalidate the code if necessary. - The flag PAGE_WRITE_ORG is positioned automatically depending - on PAGE_WRITE. The mmap_lock should already be held. */ -void page_set_flags(target_ulong start, target_ulong end, int flags) -{ - target_ulong addr, len; - bool reset_target_data; - - /* 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); - /* Only set PAGE_ANON with new mappings. */ - assert(!(flags & PAGE_ANON) || (flags & PAGE_RESET)); - assert_memory_lock(); - - start = start & TARGET_PAGE_MASK; - end = TARGET_PAGE_ALIGN(end); - - if (flags & PAGE_WRITE) { - flags |= PAGE_WRITE_ORG; - } - reset_target_data = !(flags & PAGE_VALID) || (flags & PAGE_RESET); - flags &= ~PAGE_RESET; - - 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); - - /* If the write protection bit is set, then we invalidate - the code inside. */ - if (!(p->flags & PAGE_WRITE) && - (flags & PAGE_WRITE) && - p->first_tb) { - tb_invalidate_phys_page(addr, 0); - } - if (reset_target_data) { - g_free(p->target_data); - p->target_data = NULL; - p->flags = flags; - } else { - /* Using mprotect on a page does not change MAP_ANON. */ - p->flags = (p->flags & PAGE_ANON) | flags; - } - } -} - -void *page_get_target_data(target_ulong address) -{ - PageDesc *p = page_find(address >> TARGET_PAGE_BITS); - return p ? p->target_data : NULL; -} - -void *page_alloc_target_data(target_ulong address, size_t size) -{ - PageDesc *p = page_find(address >> TARGET_PAGE_BITS); - void *ret = NULL; - - if (p->flags & PAGE_VALID) { - ret = p->target_data; - if (!ret) { - p->target_data = ret = g_malloc0(size); - } - } - return ret; -} - -int page_check_range(target_ulong start, target_ulong len, int flags) -{ - PageDesc *p; - target_ulong end; - target_ulong addr; - - /* 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. */ - if (TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS) { - assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); - } - - if (len == 0) { - return 0; - } - if (start + len - 1 < start) { - /* We've wrapped around. */ - return -1; - } - - /* must do before we loose bits in the next step */ - end = TARGET_PAGE_ALIGN(start + len); - start = start & TARGET_PAGE_MASK; - - for (addr = start, len = end - start; - len != 0; - len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { - p = page_find(addr >> TARGET_PAGE_BITS); - if (!p) { - return -1; - } - if (!(p->flags & PAGE_VALID)) { - return -1; - } - - if ((flags & PAGE_READ) && !(p->flags & PAGE_READ)) { - return -1; - } - if (flags & PAGE_WRITE) { - if (!(p->flags & PAGE_WRITE_ORG)) { - return -1; - } - /* unprotect the page if it was put read-only because it - contains translated code */ - if (!(p->flags & PAGE_WRITE)) { - if (!page_unprotect(addr, 0)) { - return -1; - } - } - } - } - return 0; -} - -void page_protect(tb_page_addr_t page_addr) +void tcg_flush_jmp_cache(CPUState *cpu) { - target_ulong addr; - PageDesc *p; - int prot; - - p = page_find(page_addr >> TARGET_PAGE_BITS); - if (p && (p->flags & PAGE_WRITE)) { - /* - * Force the host page as non writable (writes will have a page fault + - * mprotect overhead). - */ - page_addr &= qemu_host_page_mask; - prot = 0; - for (addr = page_addr; addr < page_addr + qemu_host_page_size; - addr += TARGET_PAGE_SIZE) { - - p = page_find(addr >> TARGET_PAGE_BITS); - if (!p) { - continue; - } - prot |= p->flags; - p->flags &= ~PAGE_WRITE; - } - mprotect(g2h_untagged(page_addr), qemu_host_page_size, - (prot & PAGE_BITS) & ~PAGE_WRITE); - if (DEBUG_TB_INVALIDATE_GATE) { - printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr); - } - } -} + CPUJumpCache *jc = cpu->tb_jmp_cache; -/* called from signal handler: invalidate the code and unprotect the - * page. Return 0 if the fault was not handled, 1 if it was handled, - * and 2 if it was handled but the caller must cause the TB to be - * immediately exited. (We can only return 2 if the 'pc' argument is - * non-zero.) - */ -int page_unprotect(target_ulong address, uintptr_t pc) -{ - unsigned int prot; - bool current_tb_invalidated; - PageDesc *p; - target_ulong host_start, host_end, addr; - - /* Technically this isn't safe inside a signal handler. However we - know this only ever happens in a synchronous SEGV handler, so in - practice it seems to be ok. */ - mmap_lock(); - - p = page_find(address >> TARGET_PAGE_BITS); - if (!p) { - mmap_unlock(); - return 0; + /* During early initialization, the cache may not yet be allocated. */ + if (unlikely(jc == NULL)) { + return; } - /* if the page was really writable, then we change its - protection back to writable */ - if (p->flags & PAGE_WRITE_ORG) { - current_tb_invalidated = false; - if (p->flags & PAGE_WRITE) { - /* If the page is actually marked WRITE then assume this is because - * this thread raced with another one which got here first and - * set the page to PAGE_WRITE and did the TB invalidate for us. - */ -#ifdef TARGET_HAS_PRECISE_SMC - TranslationBlock *current_tb = tcg_tb_lookup(pc); - if (current_tb) { - current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID; - } -#endif - } else { - host_start = address & qemu_host_page_mask; - host_end = host_start + qemu_host_page_size; - - prot = 0; - for (addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) { - p = page_find(addr >> TARGET_PAGE_BITS); - p->flags |= PAGE_WRITE; - prot |= p->flags; - - /* and since the content will be modified, we must invalidate - the corresponding translated code. */ - current_tb_invalidated |= tb_invalidate_phys_page(addr, pc); -#ifdef CONFIG_USER_ONLY - if (DEBUG_TB_CHECK_GATE) { - tb_invalidate_check(addr); - } -#endif - } - mprotect((void *)g2h_untagged(host_start), qemu_host_page_size, - prot & PAGE_BITS); - } - mmap_unlock(); - /* If current TB was invalidated return to main loop */ - return current_tb_invalidated ? 2 : 1; + for (int i = 0; i < TB_JMP_CACHE_SIZE; i++) { + qatomic_set(&jc->array[i].tb, NULL); } - mmap_unlock(); - return 0; } -#endif /* CONFIG_USER_ONLY */ /* 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 f06c314266b0..061519691f93 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -42,30 +42,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 */ @@ -78,7 +75,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++; @@ -139,40 +136,115 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) && qemu_log_in_addr_range(db->pc_first)) { - FILE *logfile = qemu_log_lock(); - qemu_log("----------------\n"); - ops->disas_log(db, cpu); - qemu_log("\n"); - qemu_log_unlock(logfile); + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "----------------\n"); + ops->disas_log(db, cpu, logfile); + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); + } } #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_addr0(tb) == -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_t phys_page = + get_page_addr_code_hostp(env, base, &db->host_addr[1]); + /* We cannot handle MMIO as second page. */ + assert(phys_page != -1); + tb_set_page_addr1(tb, phys_page); +#ifdef CONFIG_USER_ONLY + page_protect(end); #endif + 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); +} + +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; +} + +uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc) +{ + uint16_t ret, plug; + void *p = translator_access(env, db, pc, sizeof(ret)); + + 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; } -#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; \ +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; +} -FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD) +uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc) +{ + uint64_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 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 8edf0bbaa114..a8eb63ab96d0 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -22,6 +22,7 @@ #include "exec/exec-all.h" #include "tcg/tcg.h" #include "qemu/bitops.h" +#include "qemu/rcu.h" #include "exec/cpu_ldst.h" #include "exec/translate-all.h" #include "exec/helper-proto.h" @@ -80,10 +81,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; } @@ -101,10 +99,10 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write) * Return true if the write fault has been handled, and should be re-tried. * * Note that it is important that we don't call page_unprotect() unless - * this is really a "write to nonwriteable page" fault, because + * this is really a "write to nonwritable page" fault, because * page_unprotect() assumes that if it is called for an access to - * a page that's writeable this means we had two threads racing and - * another thread got there first and already made the page writeable; + * a page that's writable this means we had two threads racing and + * another thread got there first and already made the page writable; * so we will retry the access. If we were to call page_unprotect() * for some other kind of fault that should really be passed to the * guest, we'd end up in an infinite loop of retrying the faulting access. @@ -138,6 +136,593 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, } } +typedef struct PageFlagsNode { + struct rcu_head rcu; + IntervalTreeNode itree; + int flags; +} PageFlagsNode; + +static IntervalTreeRoot pageflags_root; + +static PageFlagsNode *pageflags_find(target_ulong start, target_long last) +{ + IntervalTreeNode *n; + + n = interval_tree_iter_first(&pageflags_root, start, last); + return n ? container_of(n, PageFlagsNode, itree) : NULL; +} + +static PageFlagsNode *pageflags_next(PageFlagsNode *p, target_ulong start, + target_long last) +{ + IntervalTreeNode *n; + + n = interval_tree_iter_next(&p->itree, start, last); + return n ? container_of(n, PageFlagsNode, itree) : NULL; +} + +int walk_memory_regions(void *priv, walk_memory_regions_fn fn) +{ + IntervalTreeNode *n; + int rc = 0; + + mmap_lock(); + for (n = interval_tree_iter_first(&pageflags_root, 0, -1); + n != NULL; + n = interval_tree_iter_next(n, 0, -1)) { + PageFlagsNode *p = container_of(n, PageFlagsNode, itree); + + rc = fn(priv, n->start, n->last + 1, p->flags); + if (rc != 0) { + break; + } + } + mmap_unlock(); + + return rc; +} + +static int dump_region(void *priv, target_ulong start, + target_ulong end, unsigned long prot) +{ + FILE *f = (FILE *)priv; + + fprintf(f, TARGET_FMT_lx"-"TARGET_FMT_lx" "TARGET_FMT_lx" %c%c%c\n", + start, end, end - start, + ((prot & PAGE_READ) ? 'r' : '-'), + ((prot & PAGE_WRITE) ? 'w' : '-'), + ((prot & PAGE_EXEC) ? 'x' : '-')); + return 0; +} + +/* dump memory mappings */ +void page_dump(FILE *f) +{ + const int length = sizeof(target_ulong) * 2; + + fprintf(f, "%-*s %-*s %-*s %s\n", + length, "start", length, "end", length, "size", "prot"); + walk_memory_regions(f, dump_region); +} + +int page_get_flags(target_ulong address) +{ + PageFlagsNode *p = pageflags_find(address, address); + + /* + * See util/interval-tree.c re lockless lookups: no false positives but + * there are false negatives. If we find nothing, retry with the mmap + * lock acquired. + */ + if (p) { + return p->flags; + } + if (have_mmap_lock()) { + return 0; + } + + mmap_lock(); + p = pageflags_find(address, address); + mmap_unlock(); + return p ? p->flags : 0; +} + +/* A subroutine of page_set_flags: insert a new node for [start,last]. */ +static void pageflags_create(target_ulong start, target_ulong last, int flags) +{ + PageFlagsNode *p = g_new(PageFlagsNode, 1); + + p->itree.start = start; + p->itree.last = last; + p->flags = flags; + interval_tree_insert(&p->itree, &pageflags_root); +} + +/* A subroutine of page_set_flags: remove everything in [start,last]. */ +static bool pageflags_unset(target_ulong start, target_ulong last) +{ + bool inval_tb = false; + + while (true) { + PageFlagsNode *p = pageflags_find(start, last); + target_ulong p_last; + + if (!p) { + break; + } + + if (p->flags & PAGE_EXEC) { + inval_tb = true; + } + + interval_tree_remove(&p->itree, &pageflags_root); + p_last = p->itree.last; + + if (p->itree.start < start) { + /* Truncate the node from the end, or split out the middle. */ + p->itree.last = start - 1; + interval_tree_insert(&p->itree, &pageflags_root); + if (last < p_last) { + pageflags_create(last + 1, p_last, p->flags); + break; + } + } else if (p_last <= last) { + /* Range completely covers node -- remove it. */ + g_free_rcu(p, rcu); + } else { + /* Truncate the node from the start. */ + p->itree.start = last + 1; + interval_tree_insert(&p->itree, &pageflags_root); + break; + } + } + + return inval_tb; +} + +/* + * A subroutine of page_set_flags: nothing overlaps [start,last], + * but check adjacent mappings and maybe merge into a single range. + */ +static void pageflags_create_merge(target_ulong start, target_ulong last, + int flags) +{ + PageFlagsNode *next = NULL, *prev = NULL; + + if (start > 0) { + prev = pageflags_find(start - 1, start - 1); + if (prev) { + if (prev->flags == flags) { + interval_tree_remove(&prev->itree, &pageflags_root); + } else { + prev = NULL; + } + } + } + if (last + 1 != 0) { + next = pageflags_find(last + 1, last + 1); + if (next) { + if (next->flags == flags) { + interval_tree_remove(&next->itree, &pageflags_root); + } else { + next = NULL; + } + } + } + + if (prev) { + if (next) { + prev->itree.last = next->itree.last; + g_free_rcu(next, rcu); + } else { + prev->itree.last = last; + } + interval_tree_insert(&prev->itree, &pageflags_root); + } else if (next) { + next->itree.start = start; + interval_tree_insert(&next->itree, &pageflags_root); + } else { + pageflags_create(start, last, flags); + } +} + +/* + * Allow the target to decide if PAGE_TARGET_[12] may be reset. + * By default, they are not kept. + */ +#ifndef PAGE_TARGET_STICKY +#define PAGE_TARGET_STICKY 0 +#endif +#define PAGE_STICKY (PAGE_ANON | PAGE_PASSTHROUGH | PAGE_TARGET_STICKY) + +/* A subroutine of page_set_flags: add flags to [start,last]. */ +static bool pageflags_set_clear(target_ulong start, target_ulong last, + int set_flags, int clear_flags) +{ + PageFlagsNode *p; + target_ulong p_start, p_last; + int p_flags, merge_flags; + bool inval_tb = false; + + restart: + p = pageflags_find(start, last); + if (!p) { + if (set_flags) { + pageflags_create_merge(start, last, set_flags); + } + goto done; + } + + p_start = p->itree.start; + p_last = p->itree.last; + p_flags = p->flags; + /* Using mprotect on a page does not change sticky bits. */ + merge_flags = (p_flags & ~clear_flags) | set_flags; + + /* + * Need to flush if an overlapping executable region + * removes exec, or adds write. + */ + if ((p_flags & PAGE_EXEC) + && (!(merge_flags & PAGE_EXEC) + || (merge_flags & ~p_flags & PAGE_WRITE))) { + inval_tb = true; + } + + /* + * If there is an exact range match, update and return without + * attempting to merge with adjacent regions. + */ + if (start == p_start && last == p_last) { + if (merge_flags) { + p->flags = merge_flags; + } else { + interval_tree_remove(&p->itree, &pageflags_root); + g_free_rcu(p, rcu); + } + goto done; + } + + /* + * If sticky bits affect the original mapping, then we must be more + * careful about the existing intervals and the separate flags. + */ + if (set_flags != merge_flags) { + if (p_start < start) { + interval_tree_remove(&p->itree, &pageflags_root); + p->itree.last = start - 1; + interval_tree_insert(&p->itree, &pageflags_root); + + if (last < p_last) { + if (merge_flags) { + pageflags_create(start, last, merge_flags); + } + pageflags_create(last + 1, p_last, p_flags); + } else { + if (merge_flags) { + pageflags_create(start, p_last, merge_flags); + } + if (p_last < last) { + start = p_last + 1; + goto restart; + } + } + } else { + if (start < p_start && set_flags) { + pageflags_create(start, p_start - 1, set_flags); + } + if (last < p_last) { + interval_tree_remove(&p->itree, &pageflags_root); + p->itree.start = last + 1; + interval_tree_insert(&p->itree, &pageflags_root); + if (merge_flags) { + pageflags_create(start, last, merge_flags); + } + } else { + if (merge_flags) { + p->flags = merge_flags; + } else { + interval_tree_remove(&p->itree, &pageflags_root); + g_free_rcu(p, rcu); + } + if (p_last < last) { + start = p_last + 1; + goto restart; + } + } + } + goto done; + } + + /* If flags are not changing for this range, incorporate it. */ + if (set_flags == p_flags) { + if (start < p_start) { + interval_tree_remove(&p->itree, &pageflags_root); + p->itree.start = start; + interval_tree_insert(&p->itree, &pageflags_root); + } + if (p_last < last) { + start = p_last + 1; + goto restart; + } + goto done; + } + + /* Maybe split out head and/or tail ranges with the original flags. */ + interval_tree_remove(&p->itree, &pageflags_root); + if (p_start < start) { + p->itree.last = start - 1; + interval_tree_insert(&p->itree, &pageflags_root); + + if (p_last < last) { + goto restart; + } + if (last < p_last) { + pageflags_create(last + 1, p_last, p_flags); + } + } else if (last < p_last) { + p->itree.start = last + 1; + interval_tree_insert(&p->itree, &pageflags_root); + } else { + g_free_rcu(p, rcu); + goto restart; + } + if (set_flags) { + pageflags_create(start, last, set_flags); + } + + done: + return inval_tb; +} + +/* + * Modify the flags of a page and invalidate the code if necessary. + * The flag PAGE_WRITE_ORG is positioned automatically depending + * on PAGE_WRITE. The mmap_lock should already be held. + */ +void page_set_flags(target_ulong start, target_ulong end, int flags) +{ + target_ulong last; + bool reset = false; + bool inval_tb = false; + + /* 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(start < end); + assert(end - 1 <= GUEST_ADDR_MAX); + /* Only set PAGE_ANON with new mappings. */ + assert(!(flags & PAGE_ANON) || (flags & PAGE_RESET)); + assert_memory_lock(); + + start = start & TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + last = end - 1; + + if (!(flags & PAGE_VALID)) { + flags = 0; + } else { + reset = flags & PAGE_RESET; + flags &= ~PAGE_RESET; + if (flags & PAGE_WRITE) { + flags |= PAGE_WRITE_ORG; + } + } + + if (!flags || reset) { + page_reset_target_data(start, end); + inval_tb |= pageflags_unset(start, last); + } + if (flags) { + inval_tb |= pageflags_set_clear(start, last, flags, + ~(reset ? 0 : PAGE_STICKY)); + } + if (inval_tb) { + tb_invalidate_phys_range(start, end); + } +} + +int page_check_range(target_ulong start, target_ulong len, int flags) +{ + target_ulong last; + int locked; /* tri-state: =0: unlocked, +1: global, -1: local */ + int ret; + + if (len == 0) { + return 0; /* trivial length */ + } + + last = start + len - 1; + if (last < start) { + return -1; /* wrap around */ + } + + locked = have_mmap_lock(); + while (true) { + PageFlagsNode *p = pageflags_find(start, last); + int missing; + + if (!p) { + if (!locked) { + /* + * Lockless lookups have false negatives. + * Retry with the lock held. + */ + mmap_lock(); + locked = -1; + p = pageflags_find(start, last); + } + if (!p) { + ret = -1; /* entire region invalid */ + break; + } + } + if (start < p->itree.start) { + ret = -1; /* initial bytes invalid */ + break; + } + + missing = flags & ~p->flags; + if (missing & PAGE_READ) { + ret = -1; /* page not readable */ + break; + } + if (missing & PAGE_WRITE) { + if (!(p->flags & PAGE_WRITE_ORG)) { + ret = -1; /* page not writable */ + break; + } + /* Asking about writable, but has been protected: undo. */ + if (!page_unprotect(start, 0)) { + ret = -1; + break; + } + /* TODO: page_unprotect should take a range, not a single page. */ + if (last - start < TARGET_PAGE_SIZE) { + ret = 0; /* ok */ + break; + } + start += TARGET_PAGE_SIZE; + continue; + } + + if (last <= p->itree.last) { + ret = 0; /* ok */ + break; + } + start = p->itree.last + 1; + } + + /* Release the lock if acquired locally. */ + if (locked < 0) { + mmap_unlock(); + } + return ret; +} + +void page_protect(tb_page_addr_t address) +{ + PageFlagsNode *p; + target_ulong start, last; + int prot; + + assert_memory_lock(); + + if (qemu_host_page_size <= TARGET_PAGE_SIZE) { + start = address & TARGET_PAGE_MASK; + last = start + TARGET_PAGE_SIZE - 1; + } else { + start = address & qemu_host_page_mask; + last = start + qemu_host_page_size - 1; + } + + p = pageflags_find(start, last); + if (!p) { + return; + } + prot = p->flags; + + if (unlikely(p->itree.last < last)) { + /* More than one protection region covers the one host page. */ + assert(TARGET_PAGE_SIZE < qemu_host_page_size); + while ((p = pageflags_next(p, start, last)) != NULL) { + prot |= p->flags; + } + } + + if (prot & PAGE_WRITE) { + pageflags_set_clear(start, last, 0, PAGE_WRITE); + mprotect(g2h_untagged(start), qemu_host_page_size, + prot & (PAGE_READ | PAGE_EXEC) ? PROT_READ : PROT_NONE); + } +} + +/* + * Called from signal handler: invalidate the code and unprotect the + * page. Return 0 if the fault was not handled, 1 if it was handled, + * and 2 if it was handled but the caller must cause the TB to be + * immediately exited. (We can only return 2 if the 'pc' argument is + * non-zero.) + */ +int page_unprotect(target_ulong address, uintptr_t pc) +{ + PageFlagsNode *p; + bool current_tb_invalidated; + + /* + * Technically this isn't safe inside a signal handler. However we + * know this only ever happens in a synchronous SEGV handler, so in + * practice it seems to be ok. + */ + mmap_lock(); + + p = pageflags_find(address, address); + + /* If this address was not really writable, nothing to do. */ + if (!p || !(p->flags & PAGE_WRITE_ORG)) { + mmap_unlock(); + return 0; + } + + current_tb_invalidated = false; + if (p->flags & PAGE_WRITE) { + /* + * If the page is actually marked WRITE then assume this is because + * this thread raced with another one which got here first and + * set the page to PAGE_WRITE and did the TB invalidate for us. + */ +#ifdef TARGET_HAS_PRECISE_SMC + TranslationBlock *current_tb = tcg_tb_lookup(pc); + if (current_tb) { + current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID; + } +#endif + } else { + target_ulong start, len, i; + int prot; + + if (qemu_host_page_size <= TARGET_PAGE_SIZE) { + start = address & TARGET_PAGE_MASK; + len = TARGET_PAGE_SIZE; + prot = p->flags | PAGE_WRITE; + pageflags_set_clear(start, start + len - 1, PAGE_WRITE, 0); + current_tb_invalidated = tb_invalidate_phys_page_unwind(start, pc); + } else { + start = address & qemu_host_page_mask; + len = qemu_host_page_size; + prot = 0; + + for (i = 0; i < len; i += TARGET_PAGE_SIZE) { + target_ulong addr = start + i; + + p = pageflags_find(addr, addr); + if (p) { + prot |= p->flags; + if (p->flags & PAGE_WRITE_ORG) { + prot |= PAGE_WRITE; + pageflags_set_clear(addr, addr + TARGET_PAGE_SIZE - 1, + PAGE_WRITE, 0); + } + } + /* + * Since the content will be modified, we must invalidate + * the corresponding translated code. + */ + current_tb_invalidated |= + tb_invalidate_phys_page_unwind(addr, pc); + } + } + if (prot & PAGE_EXEC) { + prot = (prot & ~PAGE_EXEC) | PAGE_READ; + } + mprotect((void *)g2h_untagged(start), len, prot & PAGE_BITS); + } + mmap_unlock(); + + /* If current TB was invalidated return to main loop */ + return current_tb_invalidated ? 2 : 1; +} + static int probe_access_internal(CPUArchState *env, target_ulong addr, int fault_size, MMUAccessType access_type, bool nonfault, uintptr_t ra) @@ -199,6 +784,111 @@ 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; +} + +#ifdef TARGET_PAGE_DATA_SIZE +/* + * Allocate chunks of target data together. For the only current user, + * if we allocate one hunk per page, we have overhead of 40/128 or 40%. + * Therefore, allocate memory for 64 pages at a time for overhead < 1%. + */ +#define TPD_PAGES 64 +#define TBD_MASK (TARGET_PAGE_MASK * TPD_PAGES) + +typedef struct TargetPageDataNode { + struct rcu_head rcu; + IntervalTreeNode itree; + char data[TPD_PAGES][TARGET_PAGE_DATA_SIZE] __attribute__((aligned)); +} TargetPageDataNode; + +static IntervalTreeRoot targetdata_root; + +void page_reset_target_data(target_ulong start, target_ulong end) +{ + IntervalTreeNode *n, *next; + target_ulong last; + + assert_memory_lock(); + + start = start & TARGET_PAGE_MASK; + last = TARGET_PAGE_ALIGN(end) - 1; + + for (n = interval_tree_iter_first(&targetdata_root, start, last), + next = n ? interval_tree_iter_next(n, start, last) : NULL; + n != NULL; + n = next, + next = next ? interval_tree_iter_next(n, start, last) : NULL) { + target_ulong n_start, n_last, p_ofs, p_len; + TargetPageDataNode *t = container_of(n, TargetPageDataNode, itree); + + if (n->start >= start && n->last <= last) { + interval_tree_remove(n, &targetdata_root); + g_free_rcu(t, rcu); + continue; + } + + if (n->start < start) { + n_start = start; + p_ofs = (start - n->start) >> TARGET_PAGE_BITS; + } else { + n_start = n->start; + p_ofs = 0; + } + n_last = MIN(last, n->last); + p_len = (n_last + 1 - n_start) >> TARGET_PAGE_BITS; + + memset(t->data[p_ofs], 0, p_len * TARGET_PAGE_DATA_SIZE); + } +} + +void *page_get_target_data(target_ulong address) +{ + IntervalTreeNode *n; + TargetPageDataNode *t; + target_ulong page, region; + + page = address & TARGET_PAGE_MASK; + region = address & TBD_MASK; + + n = interval_tree_iter_first(&targetdata_root, page, page); + if (!n) { + /* + * See util/interval-tree.c re lockless lookups: no false positives + * but there are false negatives. If we find nothing, retry with + * the mmap lock acquired. We also need the lock for the + * allocation + insert. + */ + mmap_lock(); + n = interval_tree_iter_first(&targetdata_root, page, page); + if (!n) { + t = g_new0(TargetPageDataNode, 1); + n = &t->itree; + n->start = region; + n->last = region | ~TBD_MASK; + interval_tree_insert(n, &targetdata_root); + } + mmap_unlock(); + } + + t = container_of(n, TargetPageDataNode, itree); + return t->data[(page - region) >> TARGET_PAGE_BITS]; +} +#else +void page_reset_target_data(target_ulong start, target_ulong end) { } +#endif /* TARGET_PAGE_DATA_SIZE */ + /* The softmmu versions of these helpers are in cputlb.c. */ /* @@ -506,7 +1196,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, #define ATOMIC_NAME(X) \ glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) #define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0) -#define ATOMIC_MMU_IDX MMU_USER_IDX #define DATA_SIZE 1 #include "atomic_template.h" diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 4a61378cd757..714bfb645392 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -449,7 +449,7 @@ static int alsa_open(bool in, struct alsa_params_req *req, snd_pcm_hw_params_t *hw_params; int err; unsigned int freq, nchannels; - const char *pcm_name = apdo->has_dev ? apdo->dev : "default"; + const char *pcm_name = apdo->dev ?: "default"; snd_pcm_uframes_t obt_buffer_size; const char *typ = in ? "ADC" : "DAC"; snd_pcm_format_t obtfmt; @@ -602,6 +602,42 @@ static int alsa_open(bool in, struct alsa_params_req *req, return -1; } +static size_t alsa_buffer_get_free(HWVoiceOut *hw) +{ + ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw; + snd_pcm_sframes_t avail; + size_t alsa_free, generic_free, generic_in_use; + + avail = snd_pcm_avail_update(alsa->handle); + if (avail < 0) { + if (avail == -EPIPE) { + if (!alsa_recover(alsa->handle)) { + avail = snd_pcm_avail_update(alsa->handle); + } + } + if (avail < 0) { + alsa_logerr(avail, + "Could not obtain number of available frames\n"); + avail = 0; + } + } + + alsa_free = avail * hw->info.bytes_per_frame; + generic_free = audio_generic_buffer_get_free(hw); + generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free; + if (generic_in_use) { + /* + * This code can only be reached in the unlikely case that + * snd_pcm_avail_update() returned a larger number of frames + * than snd_pcm_writei() could write. Make sure that all + * remaining bytes in the generic buffer can be written. + */ + alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0; + } + + return alsa_free; +} + static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len) { ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; @@ -916,7 +952,7 @@ static struct audio_pcm_ops alsa_pcm_ops = { .init_out = alsa_init_out, .fini_out = alsa_fini_out, .write = alsa_write, - .buffer_get_free = audio_generic_buffer_get_free, + .buffer_get_free = alsa_buffer_get_free, .run_buffer_out = audio_generic_run_buffer_out, .enable_out = alsa_enable_out, diff --git a/audio/audio.c b/audio/audio.c index 1c98964eb843..d849a94a8176 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -32,7 +32,8 @@ #include "qapi/qapi-visit-audio.h" #include "qemu/cutils.h" #include "qemu/module.h" -#include "qemu-common.h" +#include "qemu/help_option.h" +#include "sysemu/sysemu.h" #include "sysemu/replay.h" #include "sysemu/runstate.h" #include "ui/qemu-spice.h" @@ -72,20 +73,24 @@ void audio_driver_register(audio_driver *drv) audio_driver *audio_driver_lookup(const char *name) { struct audio_driver *d; + Error *local_err = NULL; + int rv; QLIST_FOREACH(d, &audio_drivers, next) { if (strcmp(name, d->name) == 0) { return d; } } - - audio_module_load_one(name); - QLIST_FOREACH(d, &audio_drivers, next) { - if (strcmp(name, d->name) == 0) { - return d; + rv = audio_module_load(name, &local_err); + if (rv > 0) { + QLIST_FOREACH(d, &audio_drivers, next) { + if (strcmp(name, d->name) == 0) { + return d; + } } + } else if (rv < 0) { + error_report_err(local_err); } - return NULL; } @@ -137,7 +142,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 +160,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 +547,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 +585,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 +660,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 +710,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) { @@ -985,6 +990,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on) } } +/** + * audio_frontend_frames_in() - returns the number of frames the resampling + * code generates from frames_in frames + * + * @sw: audio recording frontend + * @frames_in: number of frames + */ +static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in) +{ + return (int64_t)frames_in * sw->ratio >> 32; +} + static size_t audio_get_avail (SWVoiceIn *sw) { size_t live; @@ -997,21 +1014,28 @@ 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 ( - "%s: get_avail live %zu ret %" PRId64 "\n", + "%s: get_avail live %zu frontend frames %zu\n", SW_NAME (sw), - live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame + live, audio_frontend_frames_in(sw, live) ); - return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame; + return live; } -static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free) +/** + * audio_frontend_frames_out() - returns the number of frames needed to + * get frames_out frames after resampling + * + * @sw: audio playback frontend + * @frames_out: number of frames + */ +static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out) { - return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame; + return ((int64_t)frames_out << 32) / sw->ratio; } static size_t audio_get_free(SWVoiceOut *sw) @@ -1027,14 +1051,14 @@ 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; #ifdef DEBUG_OUT - dolog("%s: get_free live %zu dead %zu sw_bytes %zu\n", - SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead)); + dolog("%s: get_free live %zu dead %zu frontend frames %zu\n", + SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead)); #endif return dead; @@ -1120,8 +1144,12 @@ static void audio_run_out (AudioState *s) HWVoiceOut *hw = NULL; SWVoiceOut *sw; - if (!audio_get_pdo_out(s->dev)->mixing_engine) { - while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { + while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { + size_t played, live, prev_rpos; + size_t hw_free = audio_pcm_hw_get_free(hw); + int nb_live; + + if (!audio_get_pdo_out(s->dev)->mixing_engine) { /* there is exactly 1 sw for each hw with no mixeng */ sw = hw->sw_head.lh_first; @@ -1134,16 +1162,16 @@ static void audio_run_out (AudioState *s) } if (sw->active) { - sw->callback.fn(sw->callback.opaque, INT_MAX); + sw->callback.fn(sw->callback.opaque, + hw_free * sw->info.bytes_per_frame); } - } - return; - } - while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { - size_t played, live, prev_rpos; - size_t hw_free = audio_pcm_hw_get_free(hw); - int nb_live; + if (hw->pcm_ops->run_buffer_out) { + hw->pcm_ops->run_buffer_out(hw); + } + + continue; + } for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { if (sw->active) { @@ -1151,13 +1179,14 @@ static void audio_run_out (AudioState *s) size_t free; if (hw_free > sw->total_hw_samples_mixed) { - free = audio_sw_bytes_free(sw, + free = audio_frontend_frames_out(sw, MIN(sw_free, hw_free - sw->total_hw_samples_mixed)); } else { free = 0; } if (free > 0) { - sw->callback.fn(sw->callback.opaque, free); + sw->callback.fn(sw->callback.opaque, + free * sw->info.bytes_per_frame); } } } @@ -1169,7 +1198,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 +1231,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 +1251,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; @@ -1296,11 +1325,13 @@ static void audio_run_in (AudioState *s) sw->total_hw_samples_acquired -= min; if (sw->active) { + size_t sw_avail = audio_get_avail(sw); size_t avail; - avail = audio_get_avail (sw); + avail = audio_frontend_frames_in(sw, sw_avail); if (avail > 0) { - sw->callback.fn (sw->callback.opaque, avail); + sw->callback.fn(sw->callback.opaque, + avail * sw->info.bytes_per_frame); } } } @@ -1345,7 +1376,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; @@ -1500,10 +1531,6 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size) } } - if (hw->pcm_ops->run_buffer_out) { - hw->pcm_ops->run_buffer_out(hw); - } - return total; } @@ -1743,20 +1770,19 @@ 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); s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices; s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices; - if (s->nb_hw_voices_out <= 0) { + if (s->nb_hw_voices_out < 1) { dolog ("Bogus number of playback voices %d, setting to 1\n", s->nb_hw_voices_out); s->nb_hw_voices_out = 1; } - if (s->nb_hw_voices_in <= 0) { + if (s->nb_hw_voices_in < 0) { dolog ("Bogus number of capture voices %d, setting to 0\n", s->nb_hw_voices_in); s->nb_hw_voices_in = 0; @@ -1769,6 +1795,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 +1836,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; @@ -2004,15 +2035,13 @@ void audio_create_pdos(Audiodev *dev) switch (dev->driver) { #define CASE(DRIVER, driver, pdo_name) \ case AUDIODEV_DRIVER_##DRIVER: \ - if (!dev->u.driver.has_in) { \ + if (!dev->u.driver.in) { \ dev->u.driver.in = g_malloc0( \ sizeof(Audiodev##pdo_name##PerDirectionOptions)); \ - dev->u.driver.has_in = true; \ } \ - if (!dev->u.driver.has_out) { \ + if (!dev->u.driver.out) { \ dev->u.driver.out = g_malloc0( \ sizeof(Audiodev##pdo_name##PerDirectionOptions)); \ - dev->u.driver.has_out = true; \ } \ break @@ -2025,6 +2054,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,15 +2127,39 @@ 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) { - AudiodevListEntry *e; 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); + audio_define(dev); +} + +void audio_define(Audiodev *dev) +{ + AudiodevListEntry *e; + audio_validate_opts(dev, &error_fatal); e = g_new0(AudiodevListEntry, 1); @@ -2113,13 +2167,17 @@ void audio_parse_option(const char *opt) 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) @@ -2217,26 +2275,39 @@ void audio_rate_start(RateCtl *rate) rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } -size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, - size_t bytes_avail) +size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info) { int64_t now; int64_t ticks; int64_t bytes; - int64_t samples; - size_t ret; + int64_t frames; now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ticks = now - rate->start_ticks; bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); - samples = (bytes - rate->bytes_sent) / info->bytes_per_frame; - if (samples < 0 || samples > 65536) { - AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples); + frames = (bytes - rate->bytes_sent) / info->bytes_per_frame; + if (frames < 0 || frames > 65536) { + AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames); audio_rate_start(rate); - samples = 0; + frames = 0; } - ret = MIN(samples * info->bytes_per_frame, bytes_avail); - rate->bytes_sent += ret; - return ret; + return frames * info->bytes_per_frame; +} + +void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used) +{ + rate->bytes_sent += bytes_used; +} + +size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, + size_t bytes_avail) +{ + size_t bytes; + + bytes = audio_rate_peek_bytes(rate, info); + bytes = MIN(bytes, bytes_avail); + audio_rate_add_bytes(rate, bytes); + + return bytes; } diff --git a/audio/audio.h b/audio/audio.h index cbb10f4816e5..01bdc567fb17 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -32,7 +32,7 @@ typedef void (*audio_callback_fn) (void *opaque, int avail); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define AUDIO_HOST_ENDIANNESS 1 #else #define AUDIO_HOST_ENDIANNESS 0 @@ -168,8 +168,10 @@ void audio_sample_to_uint64(const void *samples, int pos, void audio_sample_from_uint64(void *samples, int pos, uint64_t left, uint64_t right); +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_int.h b/audio/audio_int.h index 2a6914d2aa65..e87ce014a04b 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -263,7 +263,9 @@ typedef struct RateCtl { } RateCtl; void audio_rate_start(RateCtl *rate); -size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, +size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info); +void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used); +size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, size_t bytes_avail); static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len) diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c index 595949f52cd4..18a89ffffb82 100644 --- a/audio/audio_legacy.c +++ b/audio/audio_legacy.c @@ -62,15 +62,12 @@ static void get_int(const char *env, uint32_t *dst, bool *has_dst) } } -static void get_str(const char *env, char **dst, bool *has_dst) +static void get_str(const char *env, char **dst) { const char *val = getenv(env); if (val) { - if (*has_dst) { - g_free(*dst); - } + g_free(*dst); *dst = g_strdup(val); - *has_dst = true; } } @@ -169,7 +166,7 @@ static void handle_alsa_per_direction( get_bool(buf, &apdo->try_poll, &apdo->has_try_poll); strcpy(buf + len, "DEV"); - get_str(buf, &apdo->dev, &apdo->has_dev); + get_str(buf, &apdo->dev); strcpy(buf + len, "SIZE_IN_USEC"); get_bool(buf, &size_in_usecs, &dummy); @@ -235,7 +232,7 @@ static void handle_oss_per_direction( const char *dev_env) { get_bool(try_poll_env, &opdo->try_poll, &opdo->has_try_poll); - get_str(dev_env, &opdo->dev, &opdo->has_dev); + get_str(dev_env, &opdo->dev); get_bytes_to_usecs("QEMU_OSS_FRAGSIZE", &opdo->buffer_length, &opdo->has_buffer_length, @@ -261,7 +258,7 @@ static void handle_oss(Audiodev *dev) static void handle_pa_per_direction( AudiodevPaPerDirectionOptions *ppdo, const char *env) { - get_str(env, &ppdo->name, &ppdo->has_name); + get_str(env, &ppdo->name); } static void handle_pa(Audiodev *dev) @@ -278,7 +275,7 @@ static void handle_pa(Audiodev *dev) &dev->u.pa.out->has_buffer_length, qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.out)); - get_str("QEMU_PA_SERVER", &dev->u.pa.server, &dev->u.pa.has_server); + get_str("QEMU_PA_SERVER", &dev->u.pa.server); } /* SDL */ @@ -299,7 +296,7 @@ static void handle_wav(Audiodev *dev) &dev->u.wav.out->has_format); get_int("QEMU_WAV_DAC_FIXED_CHANNELS", &dev->u.wav.out->channels, &dev->u.wav.out->has_channels); - get_str("QEMU_WAV_PATH", &dev->u.wav.path, &dev->u.wav.has_path); + get_str("QEMU_WAV_PATH", &dev->u.wav.path); } /* general */ diff --git a/audio/audio_template.h b/audio/audio_template.h index 7192b19e7390..720a32e57e7d 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); @@ -112,7 +110,11 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) return 0; } +#ifdef DAC samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio; +#else + samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32; +#endif sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample)); if (!sw->buf) { @@ -254,12 +256,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 +279,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 +313,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 +343,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 +441,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 +463,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 +474,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/audio_win_int.c b/audio/audio_win_int.c index 5ea8157dfcc8..316f118f5099 100644 --- a/audio/audio_win_int.c +++ b/audio/audio_win_int.c @@ -1,7 +1,6 @@ /* public domain */ #include "qemu/osdep.h" -#include "qemu-common.h" #define AUDIO_CAP "win-int" #include diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c index f178b47deec1..722df0355e1e 100644 --- a/audio/dbusaudio.c +++ b/audio/dbusaudio.c @@ -82,7 +82,7 @@ static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size) } *size = MIN(vo->buf_size - vo->buf_pos, *size); - *size = audio_rate_get_bytes(&hw->info, &vo->rate, *size); + *size = audio_rate_get_bytes(&vo->rate, &hw->info, *size); return vo->buf + vo->buf_pos; @@ -122,7 +122,7 @@ static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size) return size; } -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define AUDIO_HOST_BE TRUE #else #define AUDIO_HOST_BE FALSE @@ -343,7 +343,7 @@ dbus_read(HWVoiceIn *hw, void *buf, size_t size) trace_dbus_audio_read(size); - /* size = audio_rate_get_bytes(&hw->info, &vo->rate, size); */ + /* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */ g_hash_table_iter_init(&iter, da->in_listeners); while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) { diff --git a/audio/meson.build b/audio/meson.build index 94dab16891d5..34aed7834223 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() @@ -28,7 +29,7 @@ endforeach if dbus_display module_ss = ss.source_set() - module_ss.add(when: [gio, pixman, opengl, 'CONFIG_GIO'], if_true: files('dbusaudio.c')) + module_ss.add(when: gio, if_true: files('dbusaudio.c')) audio_modules += {'dbus': module_ss} endif diff --git a/audio/noaudio.c b/audio/noaudio.c index 84a6bfbb1c87..4fdee5adecff 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -44,7 +44,7 @@ typedef struct NoVoiceIn { static size_t no_write(HWVoiceOut *hw, void *buf, size_t len) { NoVoiceOut *no = (NoVoiceOut *) hw; - return audio_rate_get_bytes(&hw->info, &no->rate, len); + return audio_rate_get_bytes(&no->rate, &hw->info, len); } static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque) @@ -89,7 +89,7 @@ static void no_fini_in (HWVoiceIn *hw) static size_t no_read(HWVoiceIn *hw, void *buf, size_t size) { NoVoiceIn *no = (NoVoiceIn *) hw; - int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size); + int64_t bytes = audio_rate_get_bytes(&no->rate, &hw->info, size); audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame); return bytes; diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 8e075edb70d6..e8d732b612c6 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -252,7 +252,7 @@ static int oss_open(int in, struct oss_params *req, audsettings *as, audio_buf_info abinfo; int fmt, freq, nchannels; int setfragment = 1; - const char *dspname = opdo->has_dev ? opdo->dev : "/dev/dsp"; + const char *dspname = opdo->dev ?: "/dev/dsp"; const char *typ = in ? "ADC" : "DAC"; #ifdef USE_DSP_POLICY int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5; @@ -745,10 +745,8 @@ static void *oss_audio_init(Audiodev *dev) oss_init_per_direction(oopts->in); oss_init_per_direction(oopts->out); - if (access(oopts->in->has_dev ? oopts->in->dev : "/dev/dsp", - R_OK | W_OK) < 0 || - access(oopts->out->has_dev ? oopts->out->dev : "/dev/dsp", - R_OK | W_OK) < 0) { + if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0 || + access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { return NULL; } return dev; diff --git a/audio/paaudio.c b/audio/paaudio.c index e91116f2396c..529b39daacc7 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -536,9 +536,9 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, pa->stream = qpa_simple_new ( c, - ppdo->has_stream_name ? ppdo->stream_name : g->dev->id, + ppdo->stream_name ?: g->dev->id, PA_STREAM_PLAYBACK, - ppdo->has_name ? ppdo->name : NULL, + ppdo->name, &ss, &ba, /* buffering attributes */ &error @@ -585,9 +585,9 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) pa->stream = qpa_simple_new ( c, - ppdo->has_stream_name ? ppdo->stream_name : g->dev->id, + ppdo->stream_name ?: g->dev->id, PA_STREAM_RECORD, - ppdo->has_name ? ppdo->name : NULL, + ppdo->name, &ss, &ba, /* buffering attributes */ &error @@ -827,7 +827,7 @@ static void *qpa_audio_init(Audiodev *dev) assert(dev->driver == AUDIODEV_DRIVER_PA); - if (!popts->has_server) { + if (!popts->server) { char pidfile[64]; char *runtime; struct stat st; @@ -850,7 +850,7 @@ static void *qpa_audio_init(Audiodev *dev) } g = g_new0(paaudio, 1); - server = popts->has_server ? popts->server : NULL; + server = popts->server; g->dev = dev; diff --git a/audio/rate_template.h b/audio/rate_template.h index f94c940c61b1..b432719ebbaa 100644 --- a/audio/rate_template.h +++ b/audio/rate_template.h @@ -72,11 +72,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, ilast = *ibuf++; rate->ipos++; - /* if ipos overflow, there is a infinite loop */ - if (rate->ipos == 0xffffffff) { - rate->ipos = 1; - rate->opos = rate->opos & 0xffffffff; - } /* See if we finished the input buffer yet */ if (ibuf >= iend) { goto the_end; @@ -85,6 +80,12 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, icur = *ibuf; + /* wrap ipos and opos around long before they overflow */ + if (rate->ipos >= 0x10001) { + rate->ipos = 1; + rate->opos &= 0xffffffff; + } + /* interpolate */ #ifdef FLOAT_MIXENG #ifdef RECIPROCAL diff --git a/audio/sndioaudio.c b/audio/sndioaudio.c new file mode 100644 index 000000000000..632b0e3825da --- /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->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/audio/spiceaudio.c b/audio/spiceaudio.c index a8d370fe6f31..d17ef1a25efb 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -120,6 +120,13 @@ static void line_out_fini (HWVoiceOut *hw) spice_server_remove_interface (&out->sin.base); } +static size_t line_out_get_free(HWVoiceOut *hw) +{ + SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); + + return audio_rate_peek_bytes(&out->rate, &hw->info); +} + static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) { SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); @@ -133,8 +140,6 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) *size = MIN((out->fsize - out->fpos) << 2, *size); } - *size = audio_rate_get_bytes(&hw->info, &out->rate, *size); - return out->frame + out->fpos; } @@ -142,6 +147,8 @@ static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size) { SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); + audio_rate_add_bytes(&out->rate, size); + if (buf) { assert(buf == out->frame + out->fpos && out->fpos <= out->fsize); out->fpos += size >> 2; @@ -232,10 +239,13 @@ static void line_in_fini (HWVoiceIn *hw) static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len) { SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2; + uint64_t to_read = audio_rate_get_bytes(&in->rate, &hw->info, len) >> 2; size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read); - /* XXX: do we need this? */ + /* + * If the client didn't send new frames, it most likely disconnected. + * Generate silence in this case to avoid a stalled audio stream. + */ if (ready == 0) { memset(buf, 0, to_read << 2); ready = to_read; @@ -282,6 +292,7 @@ static struct audio_pcm_ops audio_callbacks = { .init_out = line_out_init, .fini_out = line_out_fini, .write = audio_generic_write, + .buffer_get_free = line_out_get_free, .get_buffer_out = line_out_get_buffer, .put_buffer_out = line_out_put_buffer, .enable_out = line_out_enable, diff --git a/audio/wavaudio.c b/audio/wavaudio.c index ac666335c783..6445a2cb90c5 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -42,7 +42,7 @@ typedef struct WAVVoiceOut { static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len) { WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len); + int64_t bytes = audio_rate_get_bytes(&wav->rate, &hw->info, len); assert(bytes % hw->info.bytes_per_frame == 0); if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) { @@ -78,7 +78,7 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as, Audiodev *dev = drv_opaque; AudiodevWavOptions *wopts = &dev->u.wav; struct audsettings wav_as = audiodev_to_audsettings(dev->u.wav.out); - const char *wav_path = wopts->has_path ? wopts->path : "qemu.wav"; + const char *wav_path = wopts->path ?: "qemu.wav"; stereo = wav_as.nchannels == 2; switch (wav_as.fmt) { diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c index 0671bf9f3e5e..cda6ca3b718a 100644 --- a/backends/cryptodev-builtin.c +++ b/backends/cryptodev-builtin.c @@ -26,6 +26,7 @@ #include "qapi/error.h" #include "standard-headers/linux/virtio_crypto.h" #include "crypto/cipher.h" +#include "crypto/akcipher.h" #include "qom/object.h" @@ -42,10 +43,11 @@ typedef struct CryptoDevBackendBuiltinSession { QCryptoCipher *cipher; uint8_t direction; /* encryption or decryption */ uint8_t type; /* cipher? hash? aead? */ + QCryptoAkCipher *akcipher; QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next; } CryptoDevBackendBuiltinSession; -/* Max number of symmetric sessions */ +/* Max number of symmetric/asymmetric sessions */ #define MAX_NUM_SESSIONS 256 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512 @@ -80,15 +82,17 @@ static void cryptodev_builtin_init( backend->conf.crypto_services = 1u << VIRTIO_CRYPTO_SERVICE_CIPHER | 1u << VIRTIO_CRYPTO_SERVICE_HASH | - 1u << VIRTIO_CRYPTO_SERVICE_MAC; + 1u << VIRTIO_CRYPTO_SERVICE_MAC | + 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER; backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC; backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1; + backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA; /* * Set the Maximum length of crypto request. * Why this value? Just avoid to overflow when * memory allocation for each crypto request. */ - backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo); + backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo); backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN; backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN; @@ -148,6 +152,55 @@ cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp) return -1; } +static int cryptodev_builtin_get_rsa_hash_algo( + int virtio_rsa_hash, Error **errp) +{ + switch (virtio_rsa_hash) { + case VIRTIO_CRYPTO_RSA_MD5: + return QCRYPTO_HASH_ALG_MD5; + + case VIRTIO_CRYPTO_RSA_SHA1: + return QCRYPTO_HASH_ALG_SHA1; + + case VIRTIO_CRYPTO_RSA_SHA256: + return QCRYPTO_HASH_ALG_SHA256; + + case VIRTIO_CRYPTO_RSA_SHA512: + return QCRYPTO_HASH_ALG_SHA512; + + default: + error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash); + return -1; + } +} + +static int cryptodev_builtin_set_rsa_options( + int virtio_padding_algo, + int virtio_hash_algo, + QCryptoAkCipherOptionsRSA *opt, + Error **errp) +{ + if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) { + int hash_alg; + + hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp); + if (hash_alg < 0) { + return -1; + } + opt->hash_alg = hash_alg; + opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1; + return 0; + } + + if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) { + opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW; + return 0; + } + + error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo); + return -1; +} + static int cryptodev_builtin_create_cipher_session( CryptoDevBackendBuiltin *builtin, CryptoDevBackendSymSessionInfo *sess_info, @@ -240,78 +293,158 @@ static int cryptodev_builtin_create_cipher_session( return index; } -static int64_t cryptodev_builtin_sym_create_session( +static int cryptodev_builtin_create_akcipher_session( + CryptoDevBackendBuiltin *builtin, + CryptoDevBackendAsymSessionInfo *sess_info, + Error **errp) +{ + CryptoDevBackendBuiltinSession *sess; + QCryptoAkCipher *akcipher; + int index; + QCryptoAkCipherKeyType type; + QCryptoAkCipherOptions opts; + + switch (sess_info->algo) { + case VIRTIO_CRYPTO_AKCIPHER_RSA: + opts.alg = QCRYPTO_AKCIPHER_ALG_RSA; + if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo, + sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) { + return -1; + } + break; + + /* TODO support DSA&ECDSA until qemu crypto framework support these */ + + default: + error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo); + return -1; + } + + switch (sess_info->keytype) { + case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC; + break; + + case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; + break; + + default: + error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype); + return -1; + } + + index = cryptodev_builtin_get_unused_session_index(builtin); + if (index < 0) { + error_setg(errp, "Total number of sessions created exceeds %u", + MAX_NUM_SESSIONS); + return -1; + } + + akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key, + sess_info->keylen, errp); + if (!akcipher) { + return -1; + } + + sess = g_new0(CryptoDevBackendBuiltinSession, 1); + sess->akcipher = akcipher; + + builtin->sessions[index] = sess; + + return index; +} + +static int cryptodev_builtin_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, - uint32_t queue_index, Error **errp) + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) { CryptoDevBackendBuiltin *builtin = CRYPTODEV_BACKEND_BUILTIN(backend); - int64_t session_id = -1; - int ret; + CryptoDevBackendSymSessionInfo *sym_sess_info; + CryptoDevBackendAsymSessionInfo *asym_sess_info; + int ret, status; + Error *local_error = NULL; switch (sess_info->op_code) { case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + sym_sess_info = &sess_info->u.sym_sess_info; ret = cryptodev_builtin_create_cipher_session( - builtin, sess_info, errp); - if (ret < 0) { - return ret; - } else { - session_id = ret; - } + builtin, sym_sess_info, &local_error); break; + + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: + asym_sess_info = &sess_info->u.asym_sess_info; + ret = cryptodev_builtin_create_akcipher_session( + builtin, asym_sess_info, &local_error); + break; + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: case VIRTIO_CRYPTO_MAC_CREATE_SESSION: default: - error_setg(errp, "Unsupported opcode :%" PRIu32 "", + error_setg(&local_error, "Unsupported opcode :%" PRIu32 "", sess_info->op_code); - return -1; + return -VIRTIO_CRYPTO_NOTSUPP; } - return session_id; + if (local_error) { + error_report_err(local_error); + } + if (ret < 0) { + status = -VIRTIO_CRYPTO_ERR; + } else { + sess_info->session_id = ret; + status = VIRTIO_CRYPTO_OK; + } + if (cb) { + cb(opaque, status); + } + return 0; } -static int cryptodev_builtin_sym_close_session( +static int cryptodev_builtin_close_session( CryptoDevBackend *backend, uint64_t session_id, - uint32_t queue_index, Error **errp) + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) { CryptoDevBackendBuiltin *builtin = CRYPTODEV_BACKEND_BUILTIN(backend); + CryptoDevBackendBuiltinSession *session; assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]); - qcrypto_cipher_free(builtin->sessions[session_id]->cipher); - g_free(builtin->sessions[session_id]); + session = builtin->sessions[session_id]; + if (session->cipher) { + qcrypto_cipher_free(session->cipher); + } else if (session->akcipher) { + qcrypto_akcipher_free(session->akcipher); + } + + g_free(session); builtin->sessions[session_id] = NULL; + if (cb) { + cb(opaque, VIRTIO_CRYPTO_OK); + } return 0; } static int cryptodev_builtin_sym_operation( - CryptoDevBackend *backend, - CryptoDevBackendSymOpInfo *op_info, - uint32_t queue_index, Error **errp) + CryptoDevBackendBuiltinSession *sess, + CryptoDevBackendSymOpInfo *op_info, Error **errp) { - CryptoDevBackendBuiltin *builtin = - CRYPTODEV_BACKEND_BUILTIN(backend); - CryptoDevBackendBuiltinSession *sess; int ret; - if (op_info->session_id >= MAX_NUM_SESSIONS || - builtin->sessions[op_info->session_id] == NULL) { - error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", - op_info->session_id); - return -VIRTIO_CRYPTO_INVSESS; - } - if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { error_setg(errp, "Algorithm chain is unsupported for cryptdoev-builtin"); return -VIRTIO_CRYPTO_NOTSUPP; } - sess = builtin->sessions[op_info->session_id]; - if (op_info->iv_len > 0) { ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, op_info->iv_len, errp); @@ -333,9 +466,109 @@ static int cryptodev_builtin_sym_operation( return -VIRTIO_CRYPTO_ERR; } } + return VIRTIO_CRYPTO_OK; } +static int cryptodev_builtin_asym_operation( + CryptoDevBackendBuiltinSession *sess, uint32_t op_code, + CryptoDevBackendAsymOpInfo *op_info, Error **errp) +{ + int ret; + + switch (op_code) { + case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: + ret = qcrypto_akcipher_encrypt(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: + ret = qcrypto_akcipher_decrypt(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + case VIRTIO_CRYPTO_AKCIPHER_SIGN: + ret = qcrypto_akcipher_sign(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + case VIRTIO_CRYPTO_AKCIPHER_VERIFY: + ret = qcrypto_akcipher_verify(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + default: + return -VIRTIO_CRYPTO_ERR; + } + + if (ret < 0) { + if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { + return -VIRTIO_CRYPTO_KEY_REJECTED; + } + return -VIRTIO_CRYPTO_ERR; + } + + /* Buffer is too short, typically the driver should handle this case */ + if (unlikely(ret > op_info->dst_len)) { + if (errp && !*errp) { + error_setg(errp, "dst buffer too short"); + } + + return -VIRTIO_CRYPTO_ERR; + } + + op_info->dst_len = ret; + + return VIRTIO_CRYPTO_OK; +} + +static int cryptodev_builtin_operation( + CryptoDevBackend *backend, + CryptoDevBackendOpInfo *op_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) +{ + CryptoDevBackendBuiltin *builtin = + CRYPTODEV_BACKEND_BUILTIN(backend); + CryptoDevBackendBuiltinSession *sess; + CryptoDevBackendSymOpInfo *sym_op_info; + CryptoDevBackendAsymOpInfo *asym_op_info; + enum CryptoDevBackendAlgType algtype = op_info->algtype; + int status = -VIRTIO_CRYPTO_ERR; + Error *local_error = NULL; + + if (op_info->session_id >= MAX_NUM_SESSIONS || + builtin->sessions[op_info->session_id] == NULL) { + error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "", + op_info->session_id); + return -VIRTIO_CRYPTO_INVSESS; + } + + sess = builtin->sessions[op_info->session_id]; + if (algtype == CRYPTODEV_BACKEND_ALG_SYM) { + sym_op_info = op_info->u.sym_op_info; + status = cryptodev_builtin_sym_operation(sess, sym_op_info, + &local_error); + } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) { + asym_op_info = op_info->u.asym_op_info; + status = cryptodev_builtin_asym_operation(sess, op_info->op_code, + asym_op_info, &local_error); + } + + if (local_error) { + error_report_err(local_error); + } + if (cb) { + cb(opaque, status); + } + return 0; +} + static void cryptodev_builtin_cleanup( CryptoDevBackend *backend, Error **errp) @@ -348,7 +581,7 @@ static void cryptodev_builtin_cleanup( for (i = 0; i < MAX_NUM_SESSIONS; i++) { if (builtin->sessions[i] != NULL) { - cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort); + cryptodev_builtin_close_session(backend, i, 0, NULL, NULL); } } @@ -370,9 +603,9 @@ cryptodev_builtin_class_init(ObjectClass *oc, void *data) bc->init = cryptodev_builtin_init; bc->cleanup = cryptodev_builtin_cleanup; - bc->create_session = cryptodev_builtin_sym_create_session; - bc->close_session = cryptodev_builtin_sym_close_session; - bc->do_sym_op = cryptodev_builtin_sym_operation; + bc->create_session = cryptodev_builtin_create_session; + bc->close_session = cryptodev_builtin_close_session; + bc->do_op = cryptodev_builtin_operation; } static const TypeInfo cryptodev_builtin_info = { diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c new file mode 100644 index 000000000000..133bd706a447 --- /dev/null +++ b/backends/cryptodev-lkcf.c @@ -0,0 +1,645 @@ +/* + * QEMU Cryptodev backend for QEMU cipher APIs + * + * Copyright (c) 2022 Bytedance.Inc + * + * Authors: + * lei he + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "crypto/cipher.h" +#include "crypto/akcipher.h" +#include "qapi/error.h" +#include "qemu/main-loop.h" +#include "qemu/thread.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "qom/object.h" +#include "sysemu/cryptodev.h" +#include "standard-headers/linux/virtio_crypto.h" + +#include +#include + +/** + * @TYPE_CRYPTODEV_BACKEND_LKCF: + * name of backend that uses linux kernel crypto framework + */ +#define TYPE_CRYPTODEV_BACKEND_LKCF "cryptodev-backend-lkcf" + +OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendLKCF, CRYPTODEV_BACKEND_LKCF) + +#define INVALID_KEY_ID -1 +#define MAX_SESSIONS 256 +#define NR_WORKER_THREAD 64 + +#define KCTL_KEY_TYPE_PKEY "asymmetric" +/** + * Here the key is uploaded to the thread-keyring of worker thread, at least + * util linux-6.0: + * 1. process keyring seems to behave unexpectedly if main-thread does not + * create the keyring before creating any other thread. + * 2. at present, the guest kernel never perform multiple operations on a + * session. + * 3. it can reduce the load of the main-loop because the key passed by the + * guest kernel has been already checked. + */ +#define KCTL_KEY_RING KEY_SPEC_THREAD_KEYRING + +typedef struct CryptoDevBackendLKCFSession { + uint8_t *key; + size_t keylen; + QCryptoAkCipherKeyType keytype; + QCryptoAkCipherOptions akcipher_opts; +} CryptoDevBackendLKCFSession; + +typedef struct CryptoDevBackendLKCF CryptoDevBackendLKCF; +typedef struct CryptoDevLKCFTask CryptoDevLKCFTask; +struct CryptoDevLKCFTask { + CryptoDevBackendLKCFSession *sess; + CryptoDevBackendOpInfo *op_info; + CryptoDevCompletionFunc cb; + void *opaque; + int status; + CryptoDevBackendLKCF *lkcf; + QSIMPLEQ_ENTRY(CryptoDevLKCFTask) queue; +}; + +typedef struct CryptoDevBackendLKCF { + CryptoDevBackend parent_obj; + CryptoDevBackendLKCFSession *sess[MAX_SESSIONS]; + QSIMPLEQ_HEAD(, CryptoDevLKCFTask) requests; + QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses; + QemuMutex mutex; + QemuCond cond; + QemuMutex rsp_mutex; + + /** + * There is no async interface for asymmetric keys like AF_ALG sockets, + * we don't seem to have better way than create a lots of thread. + */ + QemuThread worker_threads[NR_WORKER_THREAD]; + bool running; + int eventfd; +} CryptoDevBackendLKCF; + +static void *cryptodev_lkcf_worker(void *arg); +static int cryptodev_lkcf_close_session(CryptoDevBackend *backend, + uint64_t session_id, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque); + +static void cryptodev_lkcf_handle_response(void *opaque) +{ + CryptoDevBackendLKCF *lkcf = (CryptoDevBackendLKCF *)opaque; + QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses; + CryptoDevLKCFTask *task, *next; + eventfd_t nevent; + + QSIMPLEQ_INIT(&responses); + eventfd_read(lkcf->eventfd, &nevent); + + qemu_mutex_lock(&lkcf->rsp_mutex); + QSIMPLEQ_PREPEND(&responses, &lkcf->responses); + qemu_mutex_unlock(&lkcf->rsp_mutex); + + QSIMPLEQ_FOREACH_SAFE(task, &responses, queue, next) { + if (task->cb) { + task->cb(task->opaque, task->status); + } + g_free(task); + } +} + +static int cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions *opts, + char *key_desc, + size_t desc_len, + Error **errp) +{ + QCryptoAkCipherOptionsRSA *rsa_opt; + if (opts->alg != QCRYPTO_AKCIPHER_ALG_RSA) { + error_setg(errp, "Unsupported alg: %u", opts->alg); + return -1; + } + + rsa_opt = &opts->u.rsa; + if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALG_PKCS1) { + snprintf(key_desc, desc_len, "enc=%s hash=%s", + QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg), + QCryptoHashAlgorithm_str(rsa_opt->hash_alg)); + + } else { + snprintf(key_desc, desc_len, "enc=%s", + QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg)); + } + return 0; +} + +static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg, + int virtio_hash_alg, + QCryptoAkCipherOptionsRSA *opt, + Error **errp) +{ + if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) { + opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1; + + switch (virtio_hash_alg) { + case VIRTIO_CRYPTO_RSA_MD5: + opt->hash_alg = QCRYPTO_HASH_ALG_MD5; + break; + + case VIRTIO_CRYPTO_RSA_SHA1: + opt->hash_alg = QCRYPTO_HASH_ALG_SHA1; + break; + + case VIRTIO_CRYPTO_RSA_SHA256: + opt->hash_alg = QCRYPTO_HASH_ALG_SHA256; + break; + + case VIRTIO_CRYPTO_RSA_SHA512: + opt->hash_alg = QCRYPTO_HASH_ALG_SHA512; + break; + + default: + error_setg(errp, "Unsupported rsa hash algo: %d", virtio_hash_alg); + return -1; + } + return 0; + } + + if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_RAW_PADDING) { + opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW; + return 0; + } + + error_setg(errp, "Unsupported rsa padding algo: %u", virtio_padding_alg); + return -1; +} + +static int cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF *lkcf) +{ + size_t i; + + for (i = 0; i < MAX_SESSIONS; i++) { + if (lkcf->sess[i] == NULL) { + return i; + } + } + return -1; +} + +static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp) +{ + /* Only support one queue */ + int queues = backend->conf.peers.queues, i; + CryptoDevBackendClient *cc; + CryptoDevBackendLKCF *lkcf = + CRYPTODEV_BACKEND_LKCF(backend); + + if (queues != 1) { + error_setg(errp, + "Only support one queue in cryptodev-builtin backend"); + return; + } + lkcf->eventfd = eventfd(0, 0); + if (lkcf->eventfd < 0) { + error_setg(errp, "Failed to create eventfd: %d", errno); + return; + } + + cc = cryptodev_backend_new_client("cryptodev-lkcf", NULL); + cc->info_str = g_strdup_printf("cryptodev-lkcf0"); + cc->queue_index = 0; + cc->type = CRYPTODEV_BACKEND_TYPE_LKCF; + backend->conf.peers.ccs[0] = cc; + + backend->conf.crypto_services = + 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER; + backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA; + lkcf->running = true; + + QSIMPLEQ_INIT(&lkcf->requests); + QSIMPLEQ_INIT(&lkcf->responses); + qemu_mutex_init(&lkcf->mutex); + qemu_mutex_init(&lkcf->rsp_mutex); + qemu_cond_init(&lkcf->cond); + for (i = 0; i < NR_WORKER_THREAD; i++) { + qemu_thread_create(&lkcf->worker_threads[i], "lkcf-worker", + cryptodev_lkcf_worker, lkcf, 0); + } + qemu_set_fd_handler( + lkcf->eventfd, cryptodev_lkcf_handle_response, NULL, lkcf); + cryptodev_backend_set_ready(backend, true); +} + +static void cryptodev_lkcf_cleanup(CryptoDevBackend *backend, Error **errp) +{ + CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend); + size_t i; + int queues = backend->conf.peers.queues; + CryptoDevBackendClient *cc; + CryptoDevLKCFTask *task, *next; + + qemu_mutex_lock(&lkcf->mutex); + lkcf->running = false; + qemu_mutex_unlock(&lkcf->mutex); + qemu_cond_broadcast(&lkcf->cond); + + close(lkcf->eventfd); + for (i = 0; i < NR_WORKER_THREAD; i++) { + qemu_thread_join(&lkcf->worker_threads[i]); + } + + QSIMPLEQ_FOREACH_SAFE(task, &lkcf->requests, queue, next) { + if (task->cb) { + task->cb(task->opaque, task->status); + } + g_free(task); + } + + QSIMPLEQ_FOREACH_SAFE(task, &lkcf->responses, queue, next) { + if (task->cb) { + task->cb(task->opaque, task->status); + } + g_free(task); + } + + qemu_mutex_destroy(&lkcf->mutex); + qemu_cond_destroy(&lkcf->cond); + qemu_mutex_destroy(&lkcf->rsp_mutex); + + for (i = 0; i < MAX_SESSIONS; i++) { + if (lkcf->sess[i] != NULL) { + cryptodev_lkcf_close_session(backend, i, 0, NULL, NULL); + } + } + + for (i = 0; i < queues; i++) { + cc = backend->conf.peers.ccs[i]; + if (cc) { + cryptodev_backend_free_client(cc); + backend->conf.peers.ccs[i] = NULL; + } + } + + cryptodev_backend_set_ready(backend, false); +} + +static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task) +{ + CryptoDevBackendLKCFSession *session = task->sess; + CryptoDevBackendAsymOpInfo *asym_op_info; + bool kick = false; + int ret, status, op_code = task->op_info->op_code; + size_t p8info_len; + g_autofree uint8_t *p8info = NULL; + Error *local_error = NULL; + key_serial_t key_id = INVALID_KEY_ID; + char op_desc[64]; + g_autoptr(QCryptoAkCipher) akcipher = NULL; + + /** + * We only offload private key session: + * 1. currently, the Linux kernel can only accept public key wrapped + * with X.509 certificates, but unfortunately the cost of making a + * ceritificate with public key is too expensive. + * 2. generally, public key related compution is fast, just compute it with + * thread-pool. + */ + if (session->keytype == QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE) { + if (qcrypto_akcipher_export_p8info(&session->akcipher_opts, + session->key, session->keylen, + &p8info, &p8info_len, + &local_error) != 0 || + cryptodev_lkcf_set_op_desc(&session->akcipher_opts, op_desc, + sizeof(op_desc), &local_error) != 0) { + error_report_err(local_error); + } else { + key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key", + p8info, p8info_len, KCTL_KEY_RING); + } + } + + if (key_id < 0) { + if (!qcrypto_akcipher_supports(&session->akcipher_opts)) { + status = -VIRTIO_CRYPTO_NOTSUPP; + goto out; + } + akcipher = qcrypto_akcipher_new(&session->akcipher_opts, + session->keytype, + session->key, session->keylen, + &local_error); + if (!akcipher) { + status = -VIRTIO_CRYPTO_ERR; + goto out; + } + } + + asym_op_info = task->op_info->u.asym_op_info; + switch (op_code) { + case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: + if (key_id >= 0) { + ret = keyctl_pkey_encrypt(key_id, op_desc, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len); + } else { + ret = qcrypto_akcipher_encrypt(akcipher, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len, &local_error); + } + break; + + case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: + if (key_id >= 0) { + ret = keyctl_pkey_decrypt(key_id, op_desc, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len); + } else { + ret = qcrypto_akcipher_decrypt(akcipher, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len, &local_error); + } + break; + + case VIRTIO_CRYPTO_AKCIPHER_SIGN: + if (key_id >= 0) { + ret = keyctl_pkey_sign(key_id, op_desc, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len); + } else { + ret = qcrypto_akcipher_sign(akcipher, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len, &local_error); + } + break; + + case VIRTIO_CRYPTO_AKCIPHER_VERIFY: + if (key_id >= 0) { + ret = keyctl_pkey_verify(key_id, op_desc, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len); + } else { + ret = qcrypto_akcipher_verify(akcipher, + asym_op_info->src, asym_op_info->src_len, + asym_op_info->dst, asym_op_info->dst_len, &local_error); + } + break; + + default: + error_setg(&local_error, "Unknown opcode: %u", op_code); + status = -VIRTIO_CRYPTO_ERR; + goto out; + } + + if (ret < 0) { + if (!local_error) { + if (errno != EKEYREJECTED) { + error_report("Failed do operation with keyctl: %d", errno); + } + } else { + error_report_err(local_error); + } + status = op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY ? + -VIRTIO_CRYPTO_KEY_REJECTED : -VIRTIO_CRYPTO_ERR; + } else { + status = VIRTIO_CRYPTO_OK; + asym_op_info->dst_len = ret; + } + +out: + if (key_id >= 0) { + keyctl_unlink(key_id, KCTL_KEY_RING); + } + task->status = status; + + qemu_mutex_lock(&task->lkcf->rsp_mutex); + if (QSIMPLEQ_EMPTY(&task->lkcf->responses)) { + kick = true; + } + QSIMPLEQ_INSERT_TAIL(&task->lkcf->responses, task, queue); + qemu_mutex_unlock(&task->lkcf->rsp_mutex); + + if (kick) { + eventfd_write(task->lkcf->eventfd, 1); + } +} + +static void *cryptodev_lkcf_worker(void *arg) +{ + CryptoDevBackendLKCF *backend = (CryptoDevBackendLKCF *)arg; + CryptoDevLKCFTask *task; + + for (;;) { + task = NULL; + qemu_mutex_lock(&backend->mutex); + while (backend->running && QSIMPLEQ_EMPTY(&backend->requests)) { + qemu_cond_wait(&backend->cond, &backend->mutex); + } + if (backend->running) { + task = QSIMPLEQ_FIRST(&backend->requests); + QSIMPLEQ_REMOVE_HEAD(&backend->requests, queue); + } + qemu_mutex_unlock(&backend->mutex); + + /* stopped */ + if (!task) { + break; + } + cryptodev_lkcf_execute_task(task); + } + + return NULL; +} + +static int cryptodev_lkcf_operation( + CryptoDevBackend *backend, + CryptoDevBackendOpInfo *op_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) +{ + CryptoDevBackendLKCF *lkcf = + CRYPTODEV_BACKEND_LKCF(backend); + CryptoDevBackendLKCFSession *sess; + enum CryptoDevBackendAlgType algtype = op_info->algtype; + CryptoDevLKCFTask *task; + + if (op_info->session_id >= MAX_SESSIONS || + lkcf->sess[op_info->session_id] == NULL) { + error_report("Cannot find a valid session id: %" PRIu64 "", + op_info->session_id); + return -VIRTIO_CRYPTO_INVSESS; + } + + sess = lkcf->sess[op_info->session_id]; + if (algtype != CRYPTODEV_BACKEND_ALG_ASYM) { + error_report("algtype not supported: %u", algtype); + return -VIRTIO_CRYPTO_NOTSUPP; + } + + task = g_new0(CryptoDevLKCFTask, 1); + task->op_info = op_info; + task->cb = cb; + task->opaque = opaque; + task->sess = sess; + task->lkcf = lkcf; + task->status = -VIRTIO_CRYPTO_ERR; + + qemu_mutex_lock(&lkcf->mutex); + QSIMPLEQ_INSERT_TAIL(&lkcf->requests, task, queue); + qemu_mutex_unlock(&lkcf->mutex); + qemu_cond_signal(&lkcf->cond); + + return VIRTIO_CRYPTO_OK; +} + +static int cryptodev_lkcf_create_asym_session( + CryptoDevBackendLKCF *lkcf, + CryptoDevBackendAsymSessionInfo *sess_info, + uint64_t *session_id) +{ + Error *local_error = NULL; + int index; + g_autofree CryptoDevBackendLKCFSession *sess = + g_new0(CryptoDevBackendLKCFSession, 1); + + switch (sess_info->algo) { + case VIRTIO_CRYPTO_AKCIPHER_RSA: + sess->akcipher_opts.alg = QCRYPTO_AKCIPHER_ALG_RSA; + if (cryptodev_lkcf_set_rsa_opt( + sess_info->u.rsa.padding_algo, sess_info->u.rsa.hash_algo, + &sess->akcipher_opts.u.rsa, &local_error) != 0) { + error_report_err(local_error); + return -VIRTIO_CRYPTO_ERR; + } + break; + + default: + error_report("Unsupported asym alg %u", sess_info->algo); + return -VIRTIO_CRYPTO_NOTSUPP; + } + + switch (sess_info->keytype) { + case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC; + break; + + case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; + break; + + default: + error_report("Unknown akcipher keytype: %u", sess_info->keytype); + return -VIRTIO_CRYPTO_ERR; + } + + index = cryptodev_lkcf_get_unused_session_index(lkcf); + if (index < 0) { + error_report("Total number of sessions created exceeds %u", + MAX_SESSIONS); + return -VIRTIO_CRYPTO_ERR; + } + + sess->keylen = sess_info->keylen; + sess->key = g_malloc(sess_info->keylen); + memcpy(sess->key, sess_info->key, sess_info->keylen); + + lkcf->sess[index] = g_steal_pointer(&sess); + *session_id = index; + + return VIRTIO_CRYPTO_OK; +} + +static int cryptodev_lkcf_create_session( + CryptoDevBackend *backend, + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) +{ + CryptoDevBackendAsymSessionInfo *asym_sess_info; + CryptoDevBackendLKCF *lkcf = + CRYPTODEV_BACKEND_LKCF(backend); + int ret; + + switch (sess_info->op_code) { + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: + asym_sess_info = &sess_info->u.asym_sess_info; + ret = cryptodev_lkcf_create_asym_session( + lkcf, asym_sess_info, &sess_info->session_id); + break; + + default: + ret = -VIRTIO_CRYPTO_NOTSUPP; + error_report("Unsupported opcode: %" PRIu32 "", + sess_info->op_code); + break; + } + if (cb) { + cb(opaque, ret); + } + return 0; +} + +static int cryptodev_lkcf_close_session(CryptoDevBackend *backend, + uint64_t session_id, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) +{ + CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend); + CryptoDevBackendLKCFSession *session; + + assert(session_id < MAX_SESSIONS && lkcf->sess[session_id]); + session = lkcf->sess[session_id]; + lkcf->sess[session_id] = NULL; + + g_free(session->key); + g_free(session); + + if (cb) { + cb(opaque, VIRTIO_CRYPTO_OK); + } + return 0; +} + +static void cryptodev_lkcf_class_init(ObjectClass *oc, void *data) +{ + CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); + + bc->init = cryptodev_lkcf_init; + bc->cleanup = cryptodev_lkcf_cleanup; + bc->create_session = cryptodev_lkcf_create_session; + bc->close_session = cryptodev_lkcf_close_session; + bc->do_op = cryptodev_lkcf_operation; +} + +static const TypeInfo cryptodev_builtin_info = { + .name = TYPE_CRYPTODEV_BACKEND_LKCF, + .parent = TYPE_CRYPTODEV_BACKEND, + .class_init = cryptodev_lkcf_class_init, + .instance_size = sizeof(CryptoDevBackendLKCF), +}; + +static void cryptodev_lkcf_register_types(void) +{ + type_register_static(&cryptodev_builtin_info); +} + +type_init(cryptodev_lkcf_register_types); diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index bedb4524742e..ab3028e04544 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -259,15 +259,61 @@ static int64_t cryptodev_vhost_user_sym_create_session( return -1; } -static int cryptodev_vhost_user_sym_close_session( +static int cryptodev_vhost_user_create_session( + CryptoDevBackend *backend, + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) +{ + uint32_t op_code = sess_info->op_code; + CryptoDevBackendSymSessionInfo *sym_sess_info; + int64_t ret; + Error *local_error = NULL; + int status; + + switch (op_code) { + case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: + case VIRTIO_CRYPTO_MAC_CREATE_SESSION: + case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: + sym_sess_info = &sess_info->u.sym_sess_info; + ret = cryptodev_vhost_user_sym_create_session(backend, sym_sess_info, + queue_index, &local_error); + break; + + default: + error_setg(&local_error, "Unsupported opcode :%" PRIu32 "", + sess_info->op_code); + return -VIRTIO_CRYPTO_NOTSUPP; + } + + if (local_error) { + error_report_err(local_error); + } + if (ret < 0) { + status = -VIRTIO_CRYPTO_ERR; + } else { + sess_info->session_id = ret; + status = VIRTIO_CRYPTO_OK; + } + if (cb) { + cb(opaque, status); + } + return 0; +} + +static int cryptodev_vhost_user_close_session( CryptoDevBackend *backend, uint64_t session_id, - uint32_t queue_index, Error **errp) + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) { CryptoDevBackendClient *cc = backend->conf.peers.ccs[queue_index]; CryptoDevBackendVhost *vhost_crypto; - int ret; + int ret = -1, status; vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index); if (vhost_crypto) { @@ -275,12 +321,17 @@ static int cryptodev_vhost_user_sym_close_session( ret = dev->vhost_ops->vhost_crypto_close_session(dev, session_id); if (ret < 0) { - return -1; + status = -VIRTIO_CRYPTO_ERR; } else { - return 0; + status = VIRTIO_CRYPTO_OK; } + } else { + status = -VIRTIO_CRYPTO_NOTSUPP; } - return -1; + if (cb) { + cb(opaque, status); + } + return 0; } static void cryptodev_vhost_user_cleanup( @@ -313,7 +364,7 @@ static void cryptodev_vhost_user_set_chardev(Object *obj, CRYPTODEV_BACKEND_VHOST_USER(obj); if (s->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property 'chardev' can no longer be set"); } else { g_free(s->chr_name); s->chr_name = g_strdup(value); @@ -351,9 +402,9 @@ cryptodev_vhost_user_class_init(ObjectClass *oc, void *data) bc->init = cryptodev_vhost_user_init; bc->cleanup = cryptodev_vhost_user_cleanup; - bc->create_session = cryptodev_vhost_user_sym_create_session; - bc->close_session = cryptodev_vhost_user_sym_close_session; - bc->do_sym_op = NULL; + bc->create_session = cryptodev_vhost_user_create_session; + bc->close_session = cryptodev_vhost_user_close_session; + bc->do_op = NULL; object_class_property_add_str(oc, "chardev", cryptodev_vhost_user_get_chardev, diff --git a/backends/cryptodev-vhost.c b/backends/cryptodev-vhost.c index bc13e466b4f0..572f87b3bee1 100644 --- a/backends/cryptodev-vhost.c +++ b/backends/cryptodev-vhost.c @@ -94,7 +94,7 @@ cryptodev_vhost_start_one(CryptoDevBackendVhost *crypto, goto fail_notifiers; } - r = vhost_dev_start(&crypto->dev, dev); + r = vhost_dev_start(&crypto->dev, dev, false); if (r < 0) { goto fail_start; } @@ -111,7 +111,7 @@ static void cryptodev_vhost_stop_one(CryptoDevBackendVhost *crypto, VirtIODevice *dev) { - vhost_dev_stop(&crypto->dev, dev); + vhost_dev_stop(&crypto->dev, dev, false); vhost_dev_disable_notifiers(&crypto->dev, dev); } diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 2b105e433c5b..54ee8c81f50f 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -26,6 +26,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "qom/object_interfaces.h" #include "hw/virtio/virtio-crypto.h" @@ -72,71 +73,72 @@ void cryptodev_backend_cleanup( } } -int64_t cryptodev_backend_sym_create_session( +int cryptodev_backend_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, - uint32_t queue_index, Error **errp) + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(backend); if (bc->create_session) { - return bc->create_session(backend, sess_info, queue_index, errp); + return bc->create_session(backend, sess_info, queue_index, cb, opaque); } - - return -1; + return -VIRTIO_CRYPTO_NOTSUPP; } -int cryptodev_backend_sym_close_session( +int cryptodev_backend_close_session( CryptoDevBackend *backend, uint64_t session_id, - uint32_t queue_index, Error **errp) + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(backend); if (bc->close_session) { - return bc->close_session(backend, session_id, queue_index, errp); + return bc->close_session(backend, session_id, queue_index, cb, opaque); } - - return -1; + return -VIRTIO_CRYPTO_NOTSUPP; } -static int cryptodev_backend_sym_operation( +static int cryptodev_backend_operation( CryptoDevBackend *backend, - CryptoDevBackendSymOpInfo *op_info, - uint32_t queue_index, Error **errp) + CryptoDevBackendOpInfo *op_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(backend); - if (bc->do_sym_op) { - return bc->do_sym_op(backend, op_info, queue_index, errp); + if (bc->do_op) { + return bc->do_op(backend, op_info, queue_index, cb, opaque); } - - return -VIRTIO_CRYPTO_ERR; + return -VIRTIO_CRYPTO_NOTSUPP; } int cryptodev_backend_crypto_operation( CryptoDevBackend *backend, - void *opaque, - uint32_t queue_index, Error **errp) + void *opaque1, + uint32_t queue_index, + CryptoDevCompletionFunc cb, void *opaque2) { - VirtIOCryptoReq *req = opaque; - - if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { - CryptoDevBackendSymOpInfo *op_info; - op_info = req->u.sym_op_info; - - return cryptodev_backend_sym_operation(backend, - op_info, queue_index, errp); - } else { - error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "", - req->flags); - return -VIRTIO_CRYPTO_NOTSUPP; + VirtIOCryptoReq *req = opaque1; + CryptoDevBackendOpInfo *op_info = &req->op_info; + enum CryptoDevBackendAlgType algtype = req->flags; + + if ((algtype != CRYPTODEV_BACKEND_ALG_SYM) + && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) { + error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype); + return -VIRTIO_CRYPTO_NOTSUPP; } - return -VIRTIO_CRYPTO_ERR; + return cryptodev_backend_operation(backend, op_info, queue_index, + cb, opaque2); } static void diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c index 9cfd758c42f3..57369ec0f22b 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-epc.c b/backends/hostmem-epc.c index b47f98b6a3aa..037292d2672f 100644 --- a/backends/hostmem-epc.c +++ b/backends/hostmem-epc.c @@ -12,7 +12,6 @@ #include #include "qemu/osdep.h" -#include "qemu-common.h" #include "qom/object_interfaces.h" #include "qapi/error.h" #include "sysemu/hostmem.h" diff --git a/backends/hostmem.c b/backends/hostmem.c index b2a5e905e866..747e7838c031 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -23,7 +23,12 @@ #ifdef CONFIG_NUMA #include +#include QEMU_BUILD_BUG_ON(HOST_MEM_POLICY_DEFAULT != MPOL_DEFAULT); +/* + * HOST_MEM_POLICY_PREFERRED may either translate to MPOL_PREFERRED or + * MPOL_PREFERRED_MANY, see comments further below. + */ QEMU_BUILD_BUG_ON(HOST_MEM_POLICY_PREFERRED != MPOL_PREFERRED); QEMU_BUILD_BUG_ON(HOST_MEM_POLICY_BIND != MPOL_BIND); QEMU_BUILD_BUG_ON(HOST_MEM_POLICY_INTERLEAVE != MPOL_INTERLEAVE); @@ -232,7 +237,8 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value, void *ptr = memory_region_get_ram_ptr(&backend->mr); uint64_t sz = memory_region_size(&backend->mr); - os_mem_prealloc(fd, ptr, sz, backend->prealloc_threads, &local_err); + qemu_prealloc_mem(fd, ptr, sz, backend->prealloc_threads, + backend->prealloc_context, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -274,7 +280,7 @@ static void host_memory_backend_init(Object *obj) backend->merge = machine_mem_merge(machine); backend->dump = machine_dump_guest_core(machine); backend->reserve = true; - backend->prealloc_threads = 1; + backend->prealloc_threads = machine->smp.cpus; } static void host_memory_backend_post_init(Object *obj) @@ -306,22 +312,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) @@ -355,6 +351,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) * before mbind(). note: MPOL_MF_STRICT is ignored on hugepages so * this doesn't catch hugepage case. */ unsigned flags = MPOL_MF_STRICT | MPOL_MF_MOVE; + int mode = backend->policy; /* check for invalid host-nodes and policies and give more verbose * error messages than mbind(). */ @@ -378,9 +375,18 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) BITS_TO_LONGS(MAX_NODES + 1) * sizeof(unsigned long)); assert(maxnode <= MAX_NODES); +#ifdef HAVE_NUMA_HAS_PREFERRED_MANY + if (mode == MPOL_PREFERRED && numa_has_preferred_many() > 0) { + /* + * Replace with MPOL_PREFERRED_MANY otherwise the mbind() below + * silently picks the first node. + */ + mode = MPOL_PREFERRED_MANY; + } +#endif + if (maxnode && - mbind(ptr, sz, backend->policy, backend->host_nodes, maxnode + 1, - flags)) { + mbind(ptr, sz, mode, backend->host_nodes, maxnode + 1, flags)) { if (backend->policy != MPOL_DEFAULT || errno != ENOSYS) { error_setg_errno(errp, errno, "cannot bind memory to host NUMA nodes"); @@ -393,8 +399,9 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) * specified NUMA policy in place. */ if (backend->prealloc) { - os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz, - backend->prealloc_threads, &local_err); + qemu_prealloc_mem(memory_region_get_fd(&backend->mr), ptr, sz, + backend->prealloc_threads, + backend->prealloc_context, &local_err); if (local_err) { goto out; } @@ -502,6 +509,11 @@ host_memory_backend_class_init(ObjectClass *oc, void *data) NULL, NULL); object_class_property_set_description(oc, "prealloc-threads", "Number of CPU threads to use for prealloc"); + object_class_property_add_link(oc, "prealloc-context", + TYPE_THREAD_CONTEXT, offsetof(HostMemoryBackend, prealloc_context), + object_property_allow_set_link, OBJ_PROP_LINK_STRONG); + object_class_property_set_description(oc, "prealloc-context", + "Context to use for creating CPU threads for preallocation"); object_class_property_add(oc, "size", "int", host_memory_backend_get_size, host_memory_backend_set_size, diff --git a/backends/meson.build b/backends/meson.build index 6e6894552808..954e658b25a1 100644 --- a/backends/meson.build +++ b/backends/meson.build @@ -12,10 +12,17 @@ softmmu_ss.add([files( softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('rng-random.c')) softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('hostmem-file.c')) softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('hostmem-memfd.c')) -softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], if_true: files('vhost-user.c')) +if keyutils.found() + softmmu_ss.add(keyutils, files('cryptodev-lkcf.c')) +endif +if have_vhost_user + softmmu_ss.add(when: 'CONFIG_VIRTIO', if_true: files('vhost-user.c')) +endif softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c')) -softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c')) -softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio]) +if have_vhost_user_crypto + softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost-user.c')) +endif +softmmu_ss.add(when: gio, if_true: files('dbus-vmstate.c')) softmmu_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c')) subdir('tpm') diff --git a/backends/rng-egd.c b/backends/rng-egd.c index 4de142b9dc36..684c3cf3d610 100644 --- a/backends/rng-egd.c +++ b/backends/rng-egd.c @@ -116,7 +116,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp) RngEgd *s = RNG_EGD(b); if (b->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property 'chardev' can no longer be set"); } else { g_free(s->chr_name); s->chr_name = g_strdup(value); diff --git a/backends/rng-random.c b/backends/rng-random.c index 7add272edddf..80eb5be138ce 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -96,7 +96,7 @@ static void rng_random_set_filename(Object *obj, const char *filename, RngRandom *s = RNG_RANDOM(obj); if (b->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property 'filename' can no longer be set"); return; } diff --git a/backends/rng.c b/backends/rng.c index 3757b044855c..6c7bf64426af 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -48,24 +48,10 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp) static void rng_backend_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), "opened", true, errp); -} - -static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) -{ - RngBackend *s = RNG_BACKEND(obj); + RngBackend *s = RNG_BACKEND(uc); RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); Error *local_err = NULL; - if (value == s->opened) { - return; - } - - if (!value && s->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); - return; - } - if (k->opened) { k->opened(s, &local_err); if (local_err) { @@ -122,7 +108,7 @@ static void rng_backend_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "opened", rng_backend_prop_get_opened, - rng_backend_prop_set_opened); + NULL); } static const TypeInfo rng_backend_info = { diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 87d061e9bbd6..49cc3d749dc4 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 @@ static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize, 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 bd6c12cb86c1..e506ef516057 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/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c index d5558fae6cc5..179697a3a940 100644 --- a/backends/tpm/tpm_passthrough.c +++ b/backends/tpm/tpm_passthrough.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/sockets.h" @@ -260,12 +259,10 @@ tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) value = qemu_opt_get(opts, "cancel-path"); if (value) { tpm_pt->options->cancel_path = g_strdup(value); - tpm_pt->options->has_cancel_path = true; } value = qemu_opt_get(opts, "path"); if (value) { - tpm_pt->options->has_path = true; tpm_pt->options->path = g_strdup(value); } diff --git a/backends/tpm/trace-events b/backends/tpm/trace-events index 3298766dd79e..1ecef42a0746 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/backends/vhost-user.c b/backends/vhost-user.c index 10b39992d21d..7bfcaef976c4 100644 --- a/backends/vhost-user.c +++ b/backends/vhost-user.c @@ -85,7 +85,7 @@ vhost_user_backend_start(VhostUserBackend *b) } b->dev.acked_features = b->vdev->guest_features; - ret = vhost_dev_start(&b->dev, b->vdev); + ret = vhost_dev_start(&b->dev, b->vdev, true); if (ret < 0) { error_report("Error start vhost dev"); goto err_guest_notifiers; @@ -120,7 +120,7 @@ vhost_user_backend_stop(VhostUserBackend *b) return; } - vhost_dev_stop(&b->dev, b->vdev); + vhost_dev_stop(&b->dev, b->vdev, true); if (k->set_guest_notifiers) { ret = k->set_guest_notifiers(qbus->parent, @@ -141,7 +141,7 @@ static void set_chardev(Object *obj, const char *value, Error **errp) Chardev *chr; if (b->completed) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property 'chardev' can no longer be set"); return; } diff --git a/block.c b/block.c index 718e4cae8b3a..9c2ac757e495 100644 --- a/block.c +++ b/block.c @@ -90,15 +90,9 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, static bool bdrv_recurse_has_child(BlockDriverState *bs, BlockDriverState *child); -static void bdrv_child_free(BdrvChild *child); -static void bdrv_replace_child_noperm(BdrvChild **child, - BlockDriverState *new_bs, - bool free_empty_child); -static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, - BdrvChild *child, - Transaction *tran); -static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, - Transaction *tran); +static void bdrv_replace_child_noperm(BdrvChild *child, + BlockDriverState *new_bs); +static void bdrv_remove_child(BdrvChild *child, Transaction *tran); static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, @@ -108,6 +102,10 @@ static void bdrv_reopen_abort(BDRVReopenState *reopen_state); static bool bdrv_backing_overridden(BlockDriverState *bs); +static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp); + /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -135,7 +133,7 @@ size_t bdrv_opt_mem_align(BlockDriverState *bs) { if (!bs || !bs->drv) { /* page size or 4k (hdd sector size) should be on the safe side */ - return MAX(4096, qemu_real_host_page_size); + return MAX(4096, qemu_real_host_page_size()); } IO_CODE(); @@ -146,7 +144,7 @@ size_t bdrv_min_mem_align(BlockDriverState *bs) { if (!bs || !bs->drv) { /* page size or 4k (hdd sector size) should be on the safe side */ - return MAX(4096, qemu_real_host_page_size); + return MAX(4096, qemu_real_host_page_size()); } IO_CODE(); @@ -464,12 +462,18 @@ BlockDriver *bdrv_find_format(const char *format_name) /* The driver isn't registered, maybe we need to load a module */ for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) { if (!strcmp(block_driver_modules[i].format_name, format_name)) { - block_module_load_one(block_driver_modules[i].library_name); + Error *local_err = NULL; + int rv = block_module_load(block_driver_modules[i].library_name, + &local_err); + if (rv > 0) { + return bdrv_do_find_format(format_name); + } else if (rv < 0) { + error_report_err(local_err); + } break; } } - - return bdrv_do_find_format(format_name); + return NULL; } static int bdrv_format_is_whitelisted(const char *format_name, bool read_only) @@ -522,65 +526,24 @@ typedef struct CreateCo { Error *err; } CreateCo; -static void coroutine_fn bdrv_create_co_entry(void *opaque) +int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename, + QemuOpts *opts, Error **errp) { - Error *local_err = NULL; int ret; - - CreateCo *cco = opaque; - assert(cco->drv); GLOBAL_STATE_CODE(); - - ret = cco->drv->bdrv_co_create_opts(cco->drv, - cco->filename, cco->opts, &local_err); - error_propagate(&cco->err, local_err); - cco->ret = ret; -} - -int bdrv_create(BlockDriver *drv, const char* filename, - QemuOpts *opts, Error **errp) -{ - int ret; - - GLOBAL_STATE_CODE(); - - Coroutine *co; - CreateCo cco = { - .drv = drv, - .filename = g_strdup(filename), - .opts = opts, - .ret = NOT_DONE, - .err = NULL, - }; + ERRP_GUARD(); if (!drv->bdrv_co_create_opts) { - error_setg(errp, "Driver '%s' does not support image creation", drv->format_name); - ret = -ENOTSUP; - goto out; - } - - if (qemu_in_coroutine()) { - /* Fast-path if already in coroutine context */ - bdrv_create_co_entry(&cco); - } else { - co = qemu_coroutine_create(bdrv_create_co_entry, &cco); - qemu_coroutine_enter(co); - while (cco.ret == NOT_DONE) { - aio_poll(qemu_get_aio_context(), true); - } + error_setg(errp, "Driver '%s' does not support image creation", + drv->format_name); + return -ENOTSUP; } - ret = cco.ret; - if (ret < 0) { - if (cco.err) { - error_propagate(errp, cco.err); - } else { - error_setg_errno(errp, -ret, "Could not create image"); - } + ret = drv->bdrv_co_create_opts(drv, filename, opts, errp); + if (ret < 0 && !*errp) { + error_setg_errno(errp, -ret, "Could not create image"); } -out: - g_free(cco.filename); return ret; } @@ -631,9 +594,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; @@ -642,7 +606,7 @@ static int create_file_fallback_zero_first_sector(BlockBackend *blk, bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE); if (bytes_to_clear) { - ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); + ret = blk_co_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to clear the new image's first sector"); @@ -718,7 +682,8 @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, return ret; } -int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) +int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts, + Error **errp) { QemuOpts *protocol_opts; BlockDriver *drv; @@ -759,7 +724,7 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) goto out; } - ret = bdrv_create(drv, filename, protocol_opts, errp); + ret = bdrv_co_create(drv, filename, protocol_opts, errp); out: qemu_opts_del(protocol_opts); qobject_unref(qdict); @@ -860,38 +825,42 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo) /* * Create a uniquely-named empty temporary file. - * Return 0 upon success, otherwise a negative errno value. + * Return the actual file name used upon success, otherwise NULL. + * This string should be freed with g_free() when not needed any longer. + * + * Note: creating a temporary file for the caller to (re)open is + * inherently racy. Use g_file_open_tmp() instead whenever practical. */ -int get_tmp_filename(char *filename, int size) +char *create_tmp_file(Error **errp) { -#ifdef _WIN32 - char temp_dir[MAX_PATH]; - /* GetTempFileName requires that its output buffer (4th param) - have length MAX_PATH or greater. */ - assert(size >= MAX_PATH); - return (GetTempPath(MAX_PATH, temp_dir) - && GetTempFileName(temp_dir, "qem", 0, filename) - ? 0 : -GetLastError()); -#else int fd; const char *tmpdir; - tmpdir = getenv("TMPDIR"); - if (!tmpdir) { + g_autofree char *filename = NULL; + + tmpdir = g_get_tmp_dir(); +#ifndef _WIN32 + /* + * See commit 69bef79 ("block: use /var/tmp instead of /tmp for -snapshot") + * + * This function is used to create temporary disk images (like -snapshot), + * so the files can become very large. /tmp is often a tmpfs where as + * /var/tmp is usually on a disk, so more appropriate for disk images. + */ + if (!g_strcmp0(tmpdir, "/tmp")) { tmpdir = "/var/tmp"; } - if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) { - return -EOVERFLOW; - } - fd = mkstemp(filename); +#endif + + filename = g_strdup_printf("%s/vl.XXXXXX", tmpdir); + fd = g_mkstemp(filename); if (fd < 0) { - return -errno; - } - if (close(fd) != 0) { - unlink(filename); - return -errno; + error_setg_errno(errp, errno, "Could not open temporary file '%s'", + filename); + return NULL; } - return 0; -#endif + close(fd); + + return g_steal_pointer(&filename); } /* @@ -976,12 +945,16 @@ BlockDriver *bdrv_find_protocol(const char *filename, for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) { if (block_driver_modules[i].protocol_name && !strcmp(block_driver_modules[i].protocol_name, protocol)) { - block_module_load_one(block_driver_modules[i].library_name); + int rv = block_module_load(block_driver_modules[i].library_name, errp); + if (rv > 0) { + drv1 = bdrv_do_find_protocol(protocol); + } else if (rv < 0) { + return NULL; + } break; } } - drv1 = bdrv_do_find_protocol(protocol); if (!drv1) { error_setg(errp, "Unknown protocol '%s'", protocol); } @@ -1037,7 +1010,7 @@ static int find_image_format(BlockBackend *file, const char *filename, return ret; } - ret = blk_pread(file, 0, buf, sizeof(buf)); + ret = blk_pread(file, 0, sizeof(buf), buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read image for determining its " "format"); @@ -1045,14 +1018,16 @@ static int find_image_format(BlockBackend *file, const char *filename, return ret; } - drv = bdrv_probe_all(buf, ret, filename); + drv = bdrv_probe_all(buf, sizeof(buf), filename); if (!drv) { error_setg(errp, "Could not determine image format: No compatible " "driver found"); - ret = -ENOENT; + *pdrv = NULL; + return -ENOENT; } + *pdrv = drv; - return ret; + return 0; } /** @@ -1211,20 +1186,19 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c) static void bdrv_child_cb_drained_begin(BdrvChild *child) { BlockDriverState *bs = child->opaque; - bdrv_do_drained_begin_quiesce(bs, NULL, false); + bdrv_do_drained_begin_quiesce(bs, NULL); } static bool bdrv_child_cb_drained_poll(BdrvChild *child) { BlockDriverState *bs = child->opaque; - return bdrv_drain_poll(bs, false, NULL, false); + return bdrv_drain_poll(bs, NULL, false); } -static void bdrv_child_cb_drained_end(BdrvChild *child, - int *drained_end_counter) +static void bdrv_child_cb_drained_end(BdrvChild *child) { BlockDriverState *bs = child->opaque; - bdrv_drained_end_no_poll(bs, drained_end_counter); + bdrv_drained_end(bs); } static int bdrv_child_cb_inactivate(BdrvChild *child) @@ -1235,18 +1209,12 @@ static int bdrv_child_cb_inactivate(BdrvChild *child) return 0; } -static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx, - GSList **ignore, Error **errp) +static bool bdrv_child_cb_change_aio_ctx(BdrvChild *child, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp) { BlockDriverState *bs = child->opaque; - return bdrv_can_set_aio_context(bs, ctx, ignore, errp); -} - -static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx, - GSList **ignore) -{ - BlockDriverState *bs = child->opaque; - return bdrv_set_aio_context_ignore(bs, ctx, ignore); + return bdrv_change_aio_context(bs, ctx, visited, tran, errp); } /* @@ -1434,21 +1402,49 @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, *child_flags = flags; } -static void bdrv_child_cb_attach(BdrvChild *child) +static void GRAPH_WRLOCK bdrv_child_cb_attach(BdrvChild *child) { BlockDriverState *bs = child->opaque; - assert_bdrv_graph_writable(bs); + assert_bdrv_graph_writable(); QLIST_INSERT_HEAD(&bs->children, child, next); - - if (child->role & BDRV_CHILD_COW) { + if (bs->drv->is_filter || (child->role & BDRV_CHILD_FILTERED)) { + /* + * Here we handle filters and block/raw-format.c when it behave like + * filter. They generally have a single PRIMARY child, which is also the + * FILTERED child, and that they may have multiple more children, which + * are neither PRIMARY nor FILTERED. And never we have a COW child here. + * So bs->file will be the PRIMARY child, unless the PRIMARY child goes + * into bs->backing on exceptional cases; and bs->backing will be + * nothing else. + */ + assert(!(child->role & BDRV_CHILD_COW)); + if (child->role & BDRV_CHILD_PRIMARY) { + assert(child->role & BDRV_CHILD_FILTERED); + assert(!bs->backing); + assert(!bs->file); + + if (bs->drv->filtered_child_is_backing) { + bs->backing = child; + } else { + bs->file = child; + } + } else { + assert(!(child->role & BDRV_CHILD_FILTERED)); + } + } else if (child->role & BDRV_CHILD_COW) { + assert(bs->drv->supports_backing); + assert(!(child->role & BDRV_CHILD_PRIMARY)); + assert(!bs->backing); + bs->backing = child; bdrv_backing_attach(child); + } else if (child->role & BDRV_CHILD_PRIMARY) { + assert(!bs->file); + bs->file = child; } - - bdrv_apply_subtree_drain(child, bs); } -static void bdrv_child_cb_detach(BdrvChild *child) +static void GRAPH_WRLOCK bdrv_child_cb_detach(BdrvChild *child) { BlockDriverState *bs = child->opaque; @@ -1456,10 +1452,14 @@ static void bdrv_child_cb_detach(BdrvChild *child) bdrv_backing_detach(child); } - bdrv_unapply_subtree_drain(child, bs); - - assert_bdrv_graph_writable(bs); + assert_bdrv_graph_writable(); QLIST_REMOVE(child, next); + if (child == bs->backing) { + assert(child != bs->file); + bs->backing = NULL; + } else if (child == bs->file) { + bs->file = NULL; + } } static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, @@ -1489,15 +1489,14 @@ const BdrvChildClass child_of_bds = { .attach = bdrv_child_cb_attach, .detach = bdrv_child_cb_detach, .inactivate = bdrv_child_cb_inactivate, - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, + .change_aio_ctx = bdrv_child_cb_change_aio_ctx, .update_filename = bdrv_child_cb_update_filename, .get_parent_aio_context = child_of_bds_get_parent_aio_context, }; AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c) { - GLOBAL_STATE_CODE(); + IO_CODE(); return c->klass->get_parent_aio_context(c); } @@ -1638,6 +1637,20 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, goto open_failed; } + assert(!(bs->supported_read_flags & ~BDRV_REQ_MASK)); + assert(!(bs->supported_write_flags & ~BDRV_REQ_MASK)); + + /* + * Always allow the BDRV_REQ_REGISTERED_BUF optimization hint. This saves + * drivers that pass read/write requests through to a child the trouble of + * declaring support explicitly. + * + * Drivers must not propagate this flag accidentally when they initiate I/O + * to a bounce buffer. That case should be rare though. + */ + bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF; + bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF; + ret = refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); @@ -1655,8 +1668,8 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, assert(is_power_of_2(bs->bl.request_alignment)); for (i = 0; i < bs->quiesce_counter; i++) { - if (drv->bdrv_co_drain_begin) { - drv->bdrv_co_drain_begin(bs); + if (drv->bdrv_drain_begin) { + drv->bdrv_drain_begin(bs); } } @@ -1665,7 +1678,7 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, bs->drv = NULL; if (bs->file != NULL) { bdrv_unref_child(bs, bs->file); - bs->file = NULL; + assert(!bs->file); } g_free(bs->opaque); bs->opaque = NULL; @@ -2336,9 +2349,7 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, typedef struct BdrvReplaceChildState { BdrvChild *child; - BdrvChild **childp; BlockDriverState *old_bs; - bool free_empty_child; } BdrvReplaceChildState; static void bdrv_replace_child_commit(void *opaque) @@ -2346,9 +2357,6 @@ static void bdrv_replace_child_commit(void *opaque) BdrvReplaceChildState *s = opaque; GLOBAL_STATE_CODE(); - if (s->free_empty_child && !s->child->bs) { - bdrv_child_free(s->child); - } bdrv_unref(s->old_bs); } @@ -2358,34 +2366,22 @@ static void bdrv_replace_child_abort(void *opaque) BlockDriverState *new_bs = s->child->bs; GLOBAL_STATE_CODE(); - /* - * old_bs reference is transparently moved from @s to s->child. - * - * Pass &s->child here instead of s->childp, because: - * (1) s->old_bs must be non-NULL, so bdrv_replace_child_noperm() will not - * modify the BdrvChild * pointer we indirectly pass to it, i.e. it - * will not modify s->child. From that perspective, it does not matter - * whether we pass s->childp or &s->child. - * (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use - * it here. - * (3) If new_bs is NULL, *s->childp will have been NULLed by - * bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we - * must not pass a NULL *s->childp here. - * - * So whether new_bs was NULL or not, we cannot pass s->childp here; and in - * any case, there is no reason to pass it anyway. - */ - bdrv_replace_child_noperm(&s->child, s->old_bs, true); - /* - * The child was pre-existing, so s->old_bs must be non-NULL, and - * s->child thus must not have been freed - */ - assert(s->child != NULL); - if (!new_bs) { - /* As described above, *s->childp was cleared, so restore it */ - assert(s->childp != NULL); - *s->childp = s->child; + /* old_bs reference is transparently moved from @s to @s->child */ + if (!s->child->bs) { + /* + * The parents were undrained when removing old_bs from the child. New + * requests can't have been made, though, because the child was empty. + * + * TODO Make bdrv_replace_child_noperm() transactionable to avoid + * undraining the parent in the first place. Once this is done, having + * new_bs drained when calling bdrv_replace_child_tran() is not a + * requirement any more. + */ + bdrv_parent_drained_begin_single(s->child); + assert(!bdrv_parent_drained_poll_single(s->child)); } + assert(s->child->quiesced_parent); + bdrv_replace_child_noperm(s->child, s->old_bs); bdrv_unref(new_bs); } @@ -2400,47 +2396,30 @@ static TransactionActionDrv bdrv_replace_child_drv = { * * Note: real unref of old_bs is done only on commit. * - * The function doesn't update permissions, caller is responsible for this. + * Both @child->bs and @new_bs (if non-NULL) must be drained. @new_bs must be + * kept drained until the transaction is completed. * - * (*childp)->bs must not be NULL. - * - * Note that if new_bs == NULL, @childp is stored in a state object attached - * to @tran, so that the old child can be reinstated in the abort handler. - * Therefore, if @new_bs can be NULL, @childp must stay valid until the - * transaction is committed or aborted. - * - * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is - * freed (on commit). @free_empty_child should only be false if the - * caller will free the BDrvChild themselves (which may be important - * if this is in turn called in another transactional context). + * The function doesn't update permissions, caller is responsible for this. */ -static void bdrv_replace_child_tran(BdrvChild **childp, - BlockDriverState *new_bs, - Transaction *tran, - bool free_empty_child) +static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, + Transaction *tran) { BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); + + assert(child->quiesced_parent); + assert(!new_bs || new_bs->quiesce_counter); + *s = (BdrvReplaceChildState) { - .child = *childp, - .childp = new_bs == NULL ? childp : NULL, - .old_bs = (*childp)->bs, - .free_empty_child = free_empty_child, + .child = child, + .old_bs = child->bs, }; tran_add(tran, &bdrv_replace_child_drv, s); - /* The abort handler relies on this */ - assert(s->old_bs != NULL); - if (new_bs) { bdrv_ref(new_bs); } - /* - * Pass free_empty_child=false, we will free the child (if - * necessary) in bdrv_replace_child_commit() (if our - * @free_empty_child parameter was true). - */ - bdrv_replace_child_noperm(childp, new_bs, false); - /* old_bs reference is transparently moved from *childp to @s */ + bdrv_replace_child_noperm(child, new_bs); + /* old_bs reference is transparently moved from @child to @s */ } /* @@ -2518,8 +2497,12 @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, return 0; } -static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, - Transaction *tran, Error **errp) +/* + * @list is a product of bdrv_topological_dfs() (may be called several times) - + * a topologically sorted subgraph. + */ +static int bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, + Transaction *tran, Error **errp) { int ret; BlockDriverState *bs; @@ -2541,6 +2524,24 @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, return 0; } +/* + * @list is any list of nodes. List is completed by all subtrees and + * topologically sorted. It's not a problem if some node occurs in the @list + * several times. + */ +static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, + Transaction *tran, Error **errp) +{ + g_autoptr(GHashTable) found = g_hash_table_new(NULL, NULL); + g_autoptr(GSList) refresh_list = NULL; + + for ( ; list; list = list->next) { + refresh_list = bdrv_topological_dfs(refresh_list, found, list->data); + } + + return bdrv_do_refresh_perms(refresh_list, q, tran, errp); +} + void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, uint64_t *shared_perm) { @@ -2588,15 +2589,24 @@ char *bdrv_perm_names(uint64_t perm) } -static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) +/* @tran is allowed to be NULL. In this case no rollback is possible */ +static int bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran, + Error **errp) { int ret; - Transaction *tran = tran_new(); + Transaction *local_tran = NULL; g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); GLOBAL_STATE_CODE(); - ret = bdrv_list_refresh_perms(list, NULL, tran, errp); - tran_finalize(tran, ret); + if (!tran) { + tran = local_tran = tran_new(); + } + + ret = bdrv_do_refresh_perms(list, NULL, tran, errp); + + if (local_tran) { + tran_finalize(local_tran, ret); + } return ret; } @@ -2612,7 +2622,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, bdrv_child_set_perm(c, perm, shared, tran); - ret = bdrv_refresh_perms(c->bs, &local_err); + ret = bdrv_refresh_perms(c->bs, tran, &local_err); tran_finalize(tran, ret); @@ -2821,29 +2831,41 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) return permissions[qapi_perm]; } -/** - * Replace (*childp)->bs by @new_bs. - * - * If @new_bs is NULL, *childp will be set to NULL, too: BDS parents - * generally cannot handle a BdrvChild with .bs == NULL, so clearing - * BdrvChild.bs should generally immediately be followed by the - * BdrvChild pointer being cleared as well. +/* + * Replaces the node that a BdrvChild points to without updating permissions. * - * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is - * freed. @free_empty_child should only be false if the caller will - * free the BdrvChild themselves (this may be important in a - * transactional context, where it may only be freed on commit). + * If @new_bs is non-NULL, the parent of @child must already be drained through + * @child. */ -static void bdrv_replace_child_noperm(BdrvChild **childp, - BlockDriverState *new_bs, - bool free_empty_child) +static void bdrv_replace_child_noperm(BdrvChild *child, + BlockDriverState *new_bs) { - BdrvChild *child = *childp; BlockDriverState *old_bs = child->bs; int new_bs_quiesce_counter; - int drain_saldo; assert(!child->frozen); + + /* + * If we want to change the BdrvChild to point to a drained node as its new + * child->bs, we need to make sure that its new parent is drained, too. In + * other words, either child->quiesce_parent must already be true or we must + * be able to set it and keep the parent's quiesce_counter consistent with + * that, but without polling or starting new requests (this function + * guarantees that it doesn't poll, and starting new requests would be + * against the invariants of drain sections). + * + * To keep things simple, we pick the first option (child->quiesce_parent + * must already be true). We also generalise the rule a bit to make it + * easier to verify in callers and more likely to be covered in test cases: + * The parent must be quiesced through this child even if new_bs isn't + * currently drained. + * + * The only exception is for callers that always pass new_bs == NULL. In + * this case, we obviously never need to consider the case of a drained + * new_bs, so we can keep the callers simpler by allowing them not to drain + * the parent. + */ + assert(!new_bs || child->quiesced_parent); assert(old_bs != new_bs); GLOBAL_STATE_CODE(); @@ -2851,66 +2873,33 @@ static void bdrv_replace_child_noperm(BdrvChild **childp, assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); } - new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0); - drain_saldo = new_bs_quiesce_counter - child->parent_quiesce_counter; - - /* - * If the new child node is drained but the old one was not, flush - * all outstanding requests to the old child node. - */ - while (drain_saldo > 0 && child->klass->drained_begin) { - bdrv_parent_drained_begin_single(child, true); - drain_saldo--; - } - + /* TODO Pull this up into the callers to avoid polling here */ + bdrv_graph_wrlock(); if (old_bs) { - /* Detach first so that the recursive drain sections coming from @child - * are already gone and we only end the drain sections that came from - * elsewhere. */ if (child->klass->detach) { child->klass->detach(child); } - assert_bdrv_graph_writable(old_bs); QLIST_REMOVE(child, next_parent); } child->bs = new_bs; - if (!new_bs) { - *childp = NULL; - } if (new_bs) { - assert_bdrv_graph_writable(new_bs); QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); - - /* - * Detaching the old node may have led to the new node's - * quiesce_counter having been decreased. Not a problem, we - * just need to recognize this here and then invoke - * drained_end appropriately more often. - */ - assert(new_bs->quiesce_counter <= new_bs_quiesce_counter); - drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter; - - /* Attach only after starting new drained sections, so that recursive - * drain sections coming from @child don't get an extra .drained_begin - * callback. */ if (child->klass->attach) { child->klass->attach(child); } } + bdrv_graph_wrunlock(); /* - * If the old child node was drained but the new one is not, allow - * requests to come in only after the new node has been attached. + * If the parent was drained through this BdrvChild previously, but new_bs + * is not drained, allow requests to come in only after the new node has + * been attached. */ - while (drain_saldo < 0 && child->klass->drained_end) { + new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0); + if (!new_bs_quiesce_counter && child->quiesced_parent) { bdrv_parent_drained_end_single(child); - drain_saldo++; - } - - if (free_empty_child && !child->bs) { - bdrv_child_free(child); } } @@ -2931,7 +2920,7 @@ static void bdrv_child_free(BdrvChild *child) } typedef struct BdrvAttachChildCommonState { - BdrvChild **child; + BdrvChild *child; AioContext *old_parent_ctx; AioContext *old_child_ctx; } BdrvAttachChildCommonState; @@ -2939,39 +2928,35 @@ typedef struct BdrvAttachChildCommonState { static void bdrv_attach_child_common_abort(void *opaque) { BdrvAttachChildCommonState *s = opaque; - BdrvChild *child = *s->child; - BlockDriverState *bs = child->bs; + BlockDriverState *bs = s->child->bs; GLOBAL_STATE_CODE(); - /* - * Pass free_empty_child=false, because we still need the child - * for the AioContext operations on the parent below; those - * BdrvChildClass methods all work on a BdrvChild object, so we - * need to keep it as an empty shell (after this function, it will - * not be attached to any parent, and it will not have a .bs). - */ - bdrv_replace_child_noperm(s->child, NULL, false); + bdrv_replace_child_noperm(s->child, NULL); if (bdrv_get_aio_context(bs) != s->old_child_ctx) { - bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort); + bdrv_try_change_aio_context(bs, s->old_child_ctx, NULL, &error_abort); } - if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) { - GSList *ignore; + if (bdrv_child_get_parent_aio_context(s->child) != s->old_parent_ctx) { + Transaction *tran; + GHashTable *visited; + bool ret; - /* No need to ignore `child`, because it has been detached already */ - ignore = NULL; - child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore, - &error_abort); - g_slist_free(ignore); + tran = tran_new(); - ignore = NULL; - child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore); - g_slist_free(ignore); + /* No need to visit `child`, because it has been detached already */ + visited = g_hash_table_new(NULL, NULL); + ret = s->child->klass->change_aio_ctx(s->child, s->old_parent_ctx, + visited, tran, &error_abort); + g_hash_table_destroy(visited); + + /* transaction is supposed to always succeed */ + assert(ret == true); + tran_commit(tran); } bdrv_unref(bs); - bdrv_child_free(child); + bdrv_child_free(s->child); } static TransactionActionDrv bdrv_attach_child_common_drv = { @@ -2982,28 +2967,22 @@ static TransactionActionDrv bdrv_attach_child_common_drv = { /* * Common part of attaching bdrv child to bs or to blk or to job * - * Resulting new child is returned through @child. - * At start *@child must be NULL. - * @child is saved to a new entry of @tran, so that *@child could be reverted to - * NULL on abort(). So referenced variable must live at least until transaction - * end. - * * Function doesn't update permissions, caller is responsible for this. + * + * Returns new created child. */ -static int bdrv_attach_child_common(BlockDriverState *child_bs, - const char *child_name, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - uint64_t perm, uint64_t shared_perm, - void *opaque, BdrvChild **child, - Transaction *tran, Error **errp) +static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs, + const char *child_name, + const BdrvChildClass *child_class, + BdrvChildRole child_role, + uint64_t perm, uint64_t shared_perm, + void *opaque, + Transaction *tran, Error **errp) { BdrvChild *new_child; AioContext *parent_ctx; AioContext *child_ctx = bdrv_get_aio_context(child_bs); - assert(child); - assert(*child == NULL); assert(child_class->get_parent_desc); GLOBAL_STATE_CODE(); @@ -3026,63 +3005,75 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs, parent_ctx = bdrv_child_get_parent_aio_context(new_child); if (child_ctx != parent_ctx) { Error *local_err = NULL; - int ret = bdrv_try_set_aio_context(child_bs, parent_ctx, &local_err); - - if (ret < 0 && child_class->can_set_aio_ctx) { - GSList *ignore = g_slist_prepend(NULL, new_child); - if (child_class->can_set_aio_ctx(new_child, child_ctx, &ignore, - NULL)) - { + int ret = bdrv_try_change_aio_context(child_bs, parent_ctx, NULL, + &local_err); + + if (ret < 0 && child_class->change_aio_ctx) { + Transaction *tran = tran_new(); + GHashTable *visited = g_hash_table_new(NULL, NULL); + bool ret_child; + + g_hash_table_add(visited, new_child); + ret_child = child_class->change_aio_ctx(new_child, child_ctx, + visited, tran, NULL); + if (ret_child == true) { error_free(local_err); ret = 0; - g_slist_free(ignore); - ignore = g_slist_prepend(NULL, new_child); - child_class->set_aio_ctx(new_child, child_ctx, &ignore); } - g_slist_free(ignore); + tran_finalize(tran, ret_child == true ? 0 : -1); + g_hash_table_destroy(visited); } if (ret < 0) { error_propagate(errp, local_err); bdrv_child_free(new_child); - return ret; + return NULL; } } bdrv_ref(child_bs); - bdrv_replace_child_noperm(&new_child, child_bs, true); - /* child_bs was non-NULL, so new_child must not have been freed */ - assert(new_child != NULL); - - *child = new_child; + /* + * Let every new BdrvChild start with a drained parent. Inserting the child + * in the graph with bdrv_replace_child_noperm() will undrain it if + * @child_bs is not drained. + * + * The child was only just created and is not yet visible in global state + * until bdrv_replace_child_noperm() inserts it into the graph, so nobody + * could have sent requests and polling is not necessary. + * + * Note that this means that the parent isn't fully drained yet, we only + * stop new requests from coming in. This is fine, we don't care about the + * old requests here, they are not for this child. If another place enters a + * drain section for the same parent, but wants it to be fully quiesced, it + * will not run most of the the code in .drained_begin() again (which is not + * a problem, we already did this), but it will still poll until the parent + * is fully quiesced, so it will not be negatively affected either. + */ + bdrv_parent_drained_begin_single(new_child); + bdrv_replace_child_noperm(new_child, child_bs); BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1); *s = (BdrvAttachChildCommonState) { - .child = child, + .child = new_child, .old_parent_ctx = parent_ctx, .old_child_ctx = child_ctx, }; tran_add(tran, &bdrv_attach_child_common_drv, s); - return 0; + return new_child; } /* - * Variable referenced by @child must live at least until transaction end. - * (see bdrv_attach_child_common() doc for details) - * * Function doesn't update permissions, caller is responsible for this. */ -static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, - BlockDriverState *child_bs, - const char *child_name, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - BdrvChild **child, - Transaction *tran, - Error **errp) +static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs, + BlockDriverState *child_bs, + const char *child_name, + const BdrvChildClass *child_class, + BdrvChildRole child_role, + Transaction *tran, + Error **errp) { - int ret; uint64_t perm, shared_perm; assert(parent_bs->drv); @@ -3091,44 +3082,16 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, if (bdrv_recurse_has_child(child_bs, parent_bs)) { error_setg(errp, "Making '%s' a %s child of '%s' would create a cycle", child_bs->node_name, child_name, parent_bs->node_name); - return -EINVAL; + return NULL; } bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, perm, shared_perm, &perm, &shared_perm); - ret = bdrv_attach_child_common(child_bs, child_name, child_class, - child_role, perm, shared_perm, parent_bs, - child, tran, errp); - if (ret < 0) { - return ret; - } - - return 0; -} - -static void bdrv_detach_child(BdrvChild **childp) -{ - BlockDriverState *old_bs = (*childp)->bs; - - GLOBAL_STATE_CODE(); - bdrv_replace_child_noperm(childp, NULL, true); - - if (old_bs) { - /* - * Update permissions for old node. We're just taking a parent away, so - * we're loosening restrictions. Errors of permission update are not - * fatal in this case, ignore them. - */ - bdrv_refresh_perms(old_bs, NULL); - - /* - * When the parent requiring a non-default AioContext is removed, the - * node moves back to the main AioContext - */ - bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL); - } + return bdrv_attach_child_common(child_bs, child_name, child_class, + child_role, perm, shared_perm, parent_bs, + tran, errp); } /* @@ -3149,27 +3112,27 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, void *opaque, Error **errp) { int ret; - BdrvChild *child = NULL; + BdrvChild *child; Transaction *tran = tran_new(); GLOBAL_STATE_CODE(); - ret = bdrv_attach_child_common(child_bs, child_name, child_class, + child = bdrv_attach_child_common(child_bs, child_name, child_class, child_role, perm, shared_perm, opaque, - &child, tran, errp); - if (ret < 0) { + tran, errp); + if (!child) { + ret = -EINVAL; goto out; } - ret = bdrv_refresh_perms(child_bs, errp); + ret = bdrv_refresh_perms(child_bs, tran, errp); out: tran_finalize(tran, ret); - /* child is unset on failure by bdrv_attach_child_common_abort() */ - assert((ret < 0) == !child); bdrv_unref(child_bs); - return child; + + return ret < 0 ? NULL : child; } /* @@ -3191,41 +3154,56 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, Error **errp) { int ret; - BdrvChild *child = NULL; + BdrvChild *child; Transaction *tran = tran_new(); GLOBAL_STATE_CODE(); - ret = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, child_class, - child_role, &child, tran, errp); - if (ret < 0) { + child = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, + child_class, child_role, tran, errp); + if (!child) { + ret = -EINVAL; goto out; } - ret = bdrv_refresh_perms(parent_bs, errp); + ret = bdrv_refresh_perms(parent_bs, tran, errp); if (ret < 0) { goto out; } out: tran_finalize(tran, ret); - /* child is unset on failure by bdrv_attach_child_common_abort() */ - assert((ret < 0) == !child); bdrv_unref(child_bs); - return child; + return ret < 0 ? NULL : child; } /* Callers must ensure that child->frozen is false. */ void bdrv_root_unref_child(BdrvChild *child) { - BlockDriverState *child_bs; + BlockDriverState *child_bs = child->bs; GLOBAL_STATE_CODE(); + bdrv_replace_child_noperm(child, NULL); + bdrv_child_free(child); + + if (child_bs) { + /* + * Update permissions for old node. We're just taking a parent away, so + * we're loosening restrictions. Errors of permission update are not + * fatal in this case, ignore them. + */ + bdrv_refresh_perms(child_bs, NULL, NULL); + + /* + * When the parent requiring a non-default AioContext is removed, the + * node moves back to the main AioContext + */ + bdrv_try_change_aio_context(child_bs, qemu_get_aio_context(), NULL, + NULL); + } - child_bs = child->bs; - bdrv_detach_child(&child); bdrv_unref(child_bs); } @@ -3356,7 +3334,6 @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, bool is_backing, Transaction *tran, Error **errp) { - int ret = 0; bool update_inherits_from = bdrv_inherits_from_recursive(child_bs, parent_bs); BdrvChild *child = is_backing ? parent_bs->backing : parent_bs->file; @@ -3407,21 +3384,19 @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, if (child) { bdrv_unset_inherits_from(parent_bs, child, tran); - bdrv_remove_file_or_backing_child(parent_bs, child, tran); + bdrv_remove_child(child, tran); } if (!child_bs) { goto out; } - ret = bdrv_attach_child_noperm(parent_bs, child_bs, - is_backing ? "backing" : "file", - &child_of_bds, role, - is_backing ? &parent_bs->backing : - &parent_bs->file, - tran, errp); - if (ret < 0) { - return ret; + child = bdrv_attach_child_noperm(parent_bs, child_bs, + is_backing ? "backing" : "file", + &child_of_bds, role, + tran, errp); + if (!child) { + return -EINVAL; } @@ -3447,24 +3422,35 @@ static int bdrv_set_backing_noperm(BlockDriverState *bs, return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp); } -int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, - Error **errp) +int bdrv_set_backing_hd_drained(BlockDriverState *bs, + BlockDriverState *backing_hd, + Error **errp) { int ret; Transaction *tran = tran_new(); GLOBAL_STATE_CODE(); - bdrv_drained_begin(bs); + assert(bs->quiesce_counter > 0); ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp); if (ret < 0) { goto out; } - ret = bdrv_refresh_perms(bs, errp); + ret = bdrv_refresh_perms(bs, tran, errp); out: tran_finalize(tran, ret); + return ret; +} +int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, + Error **errp) +{ + int ret; + GLOBAL_STATE_CODE(); + + bdrv_drained_begin(bs); + ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp); bdrv_drained_end(bs); return ret; @@ -3666,6 +3652,29 @@ BdrvChild *bdrv_open_child(const char *filename, errp); } +/* + * Wrapper on bdrv_open_child() for most popular case: open primary child of bs. + */ +int bdrv_open_file_child(const char *filename, + QDict *options, const char *bdref_key, + BlockDriverState *parent, Error **errp) +{ + BdrvChildRole role; + + /* commit_top and mirror_top don't use this function */ + assert(!parent->drv->filtered_child_is_backing); + role = parent->drv->is_filter ? + (BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE; + + if (!bdrv_open_child(filename, options, bdref_key, parent, + &child_of_bds, role, false, errp)) + { + return -EINVAL; + } + + return 0; +} + /* * TODO Future callers may need to specify parent/child_class in order for * option inheritance to work. Existing callers use it for the root node. @@ -3715,8 +3724,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, QDict *snapshot_options, Error **errp) { - /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ - char *tmp_filename = g_malloc0(PATH_MAX + 1); + g_autofree char *tmp_filename = NULL; int64_t total_size; QemuOpts *opts = NULL; BlockDriverState *bs_snapshot = NULL; @@ -3735,9 +3743,8 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, } /* Create the temporary image */ - ret = get_tmp_filename(tmp_filename, PATH_MAX + 1); - if (ret < 0) { - error_setg_errno(errp, -ret, "Could not get temporary filename"); + tmp_filename = create_tmp_file(errp); + if (!tmp_filename) { goto out; } @@ -3771,7 +3778,6 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, out: qobject_unref(snapshot_options); - g_free(tmp_filename); return bs_snapshot; } @@ -4174,7 +4180,9 @@ static bool bdrv_recurse_has_child(BlockDriverState *bs, * returns a pointer to bs_queue, which is either the newly allocated * bs_queue, or the existing bs_queue being used. * - * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple(). + * bs is drained here and undrained by bdrv_reopen_queue_free(). + * + * To be called with bs->aio_context locked. */ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs, @@ -4194,12 +4202,10 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, int flags; QemuOpts *opts; - /* Make sure that the caller remembered to use a drained section. This is - * important to avoid graph changes between the recursive queuing here and - * bdrv_reopen_multiple(). */ - assert(bs->quiesce_counter > 0); GLOBAL_STATE_CODE(); + bdrv_drained_begin(bs); + if (bs_queue == NULL) { bs_queue = g_new0(BlockReopenQueue, 1); QTAILQ_INIT(bs_queue); @@ -4333,6 +4339,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, return bs_queue; } +/* To be called with bs->aio_context locked */ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, QDict *options, bool keep_old_opts) @@ -4349,6 +4356,12 @@ void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue) if (bs_queue) { BlockReopenQueueEntry *bs_entry, *next; QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { + AioContext *ctx = bdrv_get_aio_context(bs_entry->state.bs); + + aio_context_acquire(ctx); + bdrv_drained_end(bs_entry->state.bs); + aio_context_release(ctx); + qobject_unref(bs_entry->state.explicit_options); qobject_unref(bs_entry->state.options); g_free(bs_entry); @@ -4382,7 +4395,6 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) BlockReopenQueueEntry *bs_entry, *next; AioContext *ctx; Transaction *tran = tran_new(); - g_autoptr(GHashTable) found = NULL; g_autoptr(GSList) refresh_list = NULL; assert(qemu_get_current_aio_context() == qemu_get_aio_context()); @@ -4412,18 +4424,15 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) bs_entry->prepared = true; } - found = g_hash_table_new(NULL, NULL); QTAILQ_FOREACH(bs_entry, bs_queue, entry) { BDRVReopenState *state = &bs_entry->state; - refresh_list = bdrv_topological_dfs(refresh_list, found, state->bs); + refresh_list = g_slist_prepend(refresh_list, state->bs); if (state->old_backing_bs) { - refresh_list = bdrv_topological_dfs(refresh_list, found, - state->old_backing_bs); + refresh_list = g_slist_prepend(refresh_list, state->old_backing_bs); } if (state->old_file_bs) { - refresh_list = bdrv_topological_dfs(refresh_list, found, - state->old_file_bs); + refresh_list = g_slist_prepend(refresh_list, state->old_file_bs); } } @@ -4496,18 +4505,16 @@ int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts, GLOBAL_STATE_CODE(); - bdrv_subtree_drained_begin(bs); + queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts); + if (ctx != qemu_get_aio_context()) { aio_context_release(ctx); } - - queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts); ret = bdrv_reopen_multiple(queue, errp); if (ctx != qemu_get_aio_context()) { aio_context_acquire(ctx); } - bdrv_subtree_drained_end(bs); return ret; } @@ -4938,8 +4945,8 @@ static void bdrv_close(BlockDriverState *bs) bdrv_unref_child(bs, child); } - bs->backing = NULL; - bs->file = NULL; + assert(!bs->backing); + assert(!bs->file); g_free(bs->opaque); bs->opaque = NULL; qatomic_set(&bs->copy_on_read, 0); @@ -4978,8 +4985,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 */ @@ -5070,109 +5077,42 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) return ret; } -typedef struct BdrvRemoveFilterOrCowChild { - BdrvChild *child; - BlockDriverState *bs; - bool is_backing; -} BdrvRemoveFilterOrCowChild; - -static void bdrv_remove_filter_or_cow_child_abort(void *opaque) -{ - BdrvRemoveFilterOrCowChild *s = opaque; - BlockDriverState *parent_bs = s->child->opaque; - - if (s->is_backing) { - parent_bs->backing = s->child; - } else { - parent_bs->file = s->child; - } - - /* - * We don't have to restore child->bs here to undo bdrv_replace_child_tran() - * because that function is transactionable and it registered own completion - * entries in @tran, so .abort() for bdrv_replace_child_safe() will be - * called automatically. - */ -} - -static void bdrv_remove_filter_or_cow_child_commit(void *opaque) +static void bdrv_remove_child_commit(void *opaque) { - BdrvRemoveFilterOrCowChild *s = opaque; GLOBAL_STATE_CODE(); - bdrv_child_free(s->child); -} - -static void bdrv_remove_filter_or_cow_child_clean(void *opaque) -{ - BdrvRemoveFilterOrCowChild *s = opaque; - - /* Drop the bs reference after the transaction is done */ - bdrv_unref(s->bs); - g_free(s); + bdrv_child_free(opaque); } -static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = { - .abort = bdrv_remove_filter_or_cow_child_abort, - .commit = bdrv_remove_filter_or_cow_child_commit, - .clean = bdrv_remove_filter_or_cow_child_clean, +static TransactionActionDrv bdrv_remove_child_drv = { + .commit = bdrv_remove_child_commit, }; -/* - * A function to remove backing or file child of @bs. - * Function doesn't update permissions, caller is responsible for this. - */ -static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, - BdrvChild *child, - Transaction *tran) +/* Function doesn't update permissions, caller is responsible for this. */ +static void bdrv_remove_child(BdrvChild *child, Transaction *tran) { - BdrvChild **childp; - BdrvRemoveFilterOrCowChild *s; - if (!child) { return; } - /* - * Keep a reference to @bs so @childp will stay valid throughout the - * transaction (required by bdrv_replace_child_tran()) - */ - bdrv_ref(bs); - if (child == bs->backing) { - childp = &bs->backing; - } else if (child == bs->file) { - childp = &bs->file; - } else { - g_assert_not_reached(); - } - if (child->bs) { - /* - * Pass free_empty_child=false, we will free the child in - * bdrv_remove_filter_or_cow_child_commit() - */ - bdrv_replace_child_tran(childp, NULL, tran, false); + BlockDriverState *bs = child->bs; + bdrv_drained_begin(bs); + bdrv_replace_child_tran(child, NULL, tran); + bdrv_drained_end(bs); } - s = g_new(BdrvRemoveFilterOrCowChild, 1); - *s = (BdrvRemoveFilterOrCowChild) { - .child = child, - .bs = bs, - .is_backing = (childp == &bs->backing), - }; - tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); + tran_add(tran, &bdrv_remove_child_drv, child); } -/* - * A function to remove backing-chain child of @bs if exists: cow child for - * format nodes (always .backing) and filter child for filters (may be .file or - * .backing) - */ -static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, - Transaction *tran) +static void undrain_on_clean_cb(void *opaque) { - bdrv_remove_file_or_backing_child(bs, bdrv_filter_or_cow_child(bs), tran); + bdrv_drained_end(opaque); } +static TransactionActionDrv undrain_on_clean = { + .clean = undrain_on_clean_cb, +}; + static int bdrv_replace_node_noperm(BlockDriverState *from, BlockDriverState *to, bool auto_skip, Transaction *tran, @@ -5180,9 +5120,13 @@ static int bdrv_replace_node_noperm(BlockDriverState *from, { BdrvChild *c, *next; - assert(to != NULL); GLOBAL_STATE_CODE(); + bdrv_drained_begin(from); + bdrv_drained_begin(to); + tran_add(tran, &undrain_on_clean, from); + tran_add(tran, &undrain_on_clean, to); + QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { assert(c->bs == from); if (!should_update_child(c, to)) { @@ -5198,12 +5142,7 @@ static int bdrv_replace_node_noperm(BlockDriverState *from, c->name, from->node_name); return -EPERM; } - - /* - * Passing a pointer to the local variable @c is fine here, because - * @to is not NULL, and so &c will not be attached to the transaction. - */ - bdrv_replace_child_tran(&c, to, tran, true); + bdrv_replace_child_tran(c, to, tran); } return 0; @@ -5218,8 +5157,6 @@ static int bdrv_replace_node_noperm(BlockDriverState *from, * * With @detach_subchain=true @to must be in a backing chain of @from. In this * case backing link of the cow-parent of @to is removed. - * - * @to must not be NULL. */ static int bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to, @@ -5227,13 +5164,11 @@ static int bdrv_replace_node_common(BlockDriverState *from, Error **errp) { Transaction *tran = tran_new(); - g_autoptr(GHashTable) found = NULL; g_autoptr(GSList) refresh_list = NULL; BlockDriverState *to_cow_parent = NULL; int ret; GLOBAL_STATE_CODE(); - assert(to != NULL); if (detach_subchain) { assert(bdrv_chain_contains(from, to)); @@ -5266,13 +5201,11 @@ static int bdrv_replace_node_common(BlockDriverState *from, } if (detach_subchain) { - bdrv_remove_filter_or_cow_child(to_cow_parent, tran); + bdrv_remove_child(bdrv_filter_or_cow_child(to_cow_parent), tran); } - found = g_hash_table_new(NULL, NULL); - - refresh_list = bdrv_topological_dfs(refresh_list, found, to); - refresh_list = bdrv_topological_dfs(refresh_list, found, from); + refresh_list = g_slist_prepend(refresh_list, to); + refresh_list = g_slist_prepend(refresh_list, from); ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); if (ret < 0) { @@ -5290,9 +5223,6 @@ static int bdrv_replace_node_common(BlockDriverState *from, return ret; } -/** - * Replace node @from by @to (where neither may be NULL). - */ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp) { @@ -5325,16 +5255,18 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, Error **errp) { int ret; + BdrvChild *child; Transaction *tran = tran_new(); GLOBAL_STATE_CODE(); assert(!bs_new->backing); - ret = bdrv_attach_child_noperm(bs_new, bs_top, "backing", - &child_of_bds, bdrv_backing_role(bs_new), - &bs_new->backing, tran, errp); - if (ret < 0) { + child = bdrv_attach_child_noperm(bs_new, bs_top, "backing", + &child_of_bds, bdrv_backing_role(bs_new), + tran, errp); + if (!child) { + ret = -EINVAL; goto out; } @@ -5343,7 +5275,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, goto out; } - ret = bdrv_refresh_perms(bs_new, errp); + ret = bdrv_refresh_perms(bs_new, tran, errp); out: tran_finalize(tran, ret); @@ -5358,7 +5290,6 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, { int ret; Transaction *tran = tran_new(); - g_autoptr(GHashTable) found = NULL; g_autoptr(GSList) refresh_list = NULL; BlockDriverState *old_bs = child->bs; @@ -5368,13 +5299,10 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, bdrv_drained_begin(old_bs); bdrv_drained_begin(new_bs); - bdrv_replace_child_tran(&child, new_bs, tran, true); - /* @new_bs must have been non-NULL, so @child must not have been freed */ - assert(child != NULL); + bdrv_replace_child_tran(child, new_bs, tran); - found = g_hash_table_new(NULL, NULL); - refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs); - refresh_list = bdrv_topological_dfs(refresh_list, found, new_bs); + refresh_list = g_slist_prepend(refresh_list, old_bs); + refresh_list = g_slist_prepend(refresh_list, new_bs); ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); @@ -5474,6 +5402,7 @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix) { IO_CODE(); + assert_bdrv_graph_readable(); if (bs->drv == NULL) { return -ENOMEDIUM; } @@ -5696,7 +5625,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, GLOBAL_STATE_CODE(); bdrv_ref(top); - bdrv_subtree_drained_begin(top); + bdrv_drained_begin(base); if (!top->drv || !base->drv) { goto exit; @@ -5769,7 +5698,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, ret = 0; exit: - bdrv_subtree_drained_end(top); + bdrv_drained_end(base); bdrv_unref(top); return ret; } @@ -6165,13 +6094,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); + } } } @@ -6298,7 +6230,7 @@ const char *bdrv_get_device_or_node_name(const BlockDriverState *bs) int bdrv_get_flags(BlockDriverState *bs) { - GLOBAL_STATE_CODE(); + IO_CODE(); return bs->open_flags; } @@ -6642,7 +6574,7 @@ int bdrv_activate(BlockDriverState *bs, Error **errp) */ if (bs->open_flags & BDRV_O_INACTIVE) { bs->open_flags &= ~BDRV_O_INACTIVE; - ret = bdrv_refresh_perms(bs, errp); + ret = bdrv_refresh_perms(bs, NULL, errp); if (ret < 0) { bs->open_flags |= BDRV_O_INACTIVE; return ret; @@ -6686,6 +6618,7 @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp) IO_CODE(); assert(!(bs->open_flags & BDRV_O_INACTIVE)); + assert_bdrv_graph_readable(); if (bs->drv->bdrv_co_invalidate_cache) { bs->drv->bdrv_co_invalidate_cache(bs, &local_err); @@ -6787,7 +6720,7 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) * We only tried to loosen restrictions, so errors are not fatal, ignore * them. */ - bdrv_refresh_perms(bs, NULL); + bdrv_refresh_perms(bs, NULL, NULL); /* Recursively inactivate children */ QLIST_FOREACH(child, &bs->children, next) { @@ -6992,6 +6925,10 @@ bool bdrv_op_blocker_is_empty(BlockDriverState *bs) return true; } +/* + * Must not be called while holding the lock of an AioContext other than the + * current one. + */ void bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, char *options, uint64_t img_size, int flags, bool quiet, @@ -7310,191 +7247,221 @@ static void bdrv_attach_aio_context(BlockDriverState *bs, bs->walking_aio_notifiers = false; } -/* - * Changes the AioContext used for fd handlers, timers, and BHs by this - * BlockDriverState and all its children and parents. - * - * Must be called from the main AioContext. - * - * The caller must own the AioContext lock for the old AioContext of bs, but it - * must not own the AioContext lock for new_context (unless new_context is the - * same as the current context of bs). - * - * @ignore will accumulate all visited BdrvChild object. The caller is - * responsible for freeing the list afterwards. - */ -void bdrv_set_aio_context_ignore(BlockDriverState *bs, - AioContext *new_context, GSList **ignore) -{ - AioContext *old_context = bdrv_get_aio_context(bs); - GSList *children_to_process = NULL; - GSList *parents_to_process = NULL; - GSList *entry; - BdrvChild *child, *parent; - - g_assert(qemu_get_current_aio_context() == qemu_get_aio_context()); - GLOBAL_STATE_CODE(); - - if (old_context == new_context) { - return; - } - - bdrv_drained_begin(bs); - - QLIST_FOREACH(child, &bs->children, next) { - if (g_slist_find(*ignore, child)) { - continue; - } - *ignore = g_slist_prepend(*ignore, child); - children_to_process = g_slist_prepend(children_to_process, child); - } - - QLIST_FOREACH(parent, &bs->parents, next_parent) { - if (g_slist_find(*ignore, parent)) { - continue; - } - *ignore = g_slist_prepend(*ignore, parent); - parents_to_process = g_slist_prepend(parents_to_process, parent); - } - - for (entry = children_to_process; - entry != NULL; - entry = g_slist_next(entry)) { - child = entry->data; - bdrv_set_aio_context_ignore(child->bs, new_context, ignore); - } - g_slist_free(children_to_process); - - for (entry = parents_to_process; - entry != NULL; - entry = g_slist_next(entry)) { - parent = entry->data; - assert(parent->klass->set_aio_ctx); - parent->klass->set_aio_ctx(parent, new_context, ignore); - } - g_slist_free(parents_to_process); - - bdrv_detach_aio_context(bs); - - /* Acquire the new context, if necessary */ - if (qemu_get_aio_context() != new_context) { - aio_context_acquire(new_context); - } - - bdrv_attach_aio_context(bs, new_context); - - /* - * If this function was recursively called from - * bdrv_set_aio_context_ignore(), there may be nodes in the - * subtree that have not yet been moved to the new AioContext. - * Release the old one so bdrv_drained_end() can poll them. - */ - if (qemu_get_aio_context() != old_context) { - aio_context_release(old_context); - } - - bdrv_drained_end(bs); - - if (qemu_get_aio_context() != old_context) { - aio_context_acquire(old_context); - } - if (qemu_get_aio_context() != new_context) { - aio_context_release(new_context); - } -} +typedef struct BdrvStateSetAioContext { + AioContext *new_ctx; + BlockDriverState *bs; +} BdrvStateSetAioContext; -static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx, - GSList **ignore, Error **errp) +static bool bdrv_parent_change_aio_context(BdrvChild *c, AioContext *ctx, + GHashTable *visited, + Transaction *tran, + Error **errp) { GLOBAL_STATE_CODE(); - if (g_slist_find(*ignore, c)) { + if (g_hash_table_contains(visited, c)) { return true; } - *ignore = g_slist_prepend(*ignore, c); + g_hash_table_add(visited, c); /* * A BdrvChildClass that doesn't handle AioContext changes cannot * tolerate any AioContext changes */ - if (!c->klass->can_set_aio_ctx) { + if (!c->klass->change_aio_ctx) { char *user = bdrv_child_user_desc(c); error_setg(errp, "Changing iothreads is not supported by %s", user); g_free(user); return false; } - if (!c->klass->can_set_aio_ctx(c, ctx, ignore, errp)) { + if (!c->klass->change_aio_ctx(c, ctx, visited, tran, errp)) { assert(!errp || *errp); return false; } return true; } -bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, - GSList **ignore, Error **errp) +bool bdrv_child_change_aio_context(BdrvChild *c, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp) { GLOBAL_STATE_CODE(); - if (g_slist_find(*ignore, c)) { + if (g_hash_table_contains(visited, c)) { return true; } - *ignore = g_slist_prepend(*ignore, c); - return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp); + g_hash_table_add(visited, c); + return bdrv_change_aio_context(c->bs, ctx, visited, tran, errp); } -/* @ignore will accumulate all visited BdrvChild object. The caller is - * responsible for freeing the list afterwards. */ -bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, - GSList **ignore, Error **errp) +static void bdrv_set_aio_context_clean(void *opaque) +{ + BdrvStateSetAioContext *state = (BdrvStateSetAioContext *) opaque; + BlockDriverState *bs = (BlockDriverState *) state->bs; + + /* Paired with bdrv_drained_begin in bdrv_change_aio_context() */ + bdrv_drained_end(bs); + + g_free(state); +} + +static void bdrv_set_aio_context_commit(void *opaque) +{ + BdrvStateSetAioContext *state = (BdrvStateSetAioContext *) opaque; + BlockDriverState *bs = (BlockDriverState *) state->bs; + AioContext *new_context = state->new_ctx; + AioContext *old_context = bdrv_get_aio_context(bs); + + /* + * Take the old AioContex when detaching it from bs. + * At this point, new_context lock is already acquired, and we are now + * also taking old_context. This is safe as long as bdrv_detach_aio_context + * does not call AIO_POLL_WHILE(). + */ + if (old_context != qemu_get_aio_context()) { + aio_context_acquire(old_context); + } + bdrv_detach_aio_context(bs); + if (old_context != qemu_get_aio_context()) { + aio_context_release(old_context); + } + bdrv_attach_aio_context(bs, new_context); +} + +static TransactionActionDrv set_aio_context = { + .commit = bdrv_set_aio_context_commit, + .clean = bdrv_set_aio_context_clean, +}; + +/* + * Changes the AioContext used for fd handlers, timers, and BHs by this + * BlockDriverState and all its children and parents. + * + * Must be called from the main AioContext. + * + * The caller must own the AioContext lock for the old AioContext of bs, but it + * must not own the AioContext lock for new_context (unless new_context is the + * same as the current context of bs). + * + * @visited will accumulate all visited BdrvChild objects. The caller is + * responsible for freeing the list afterwards. + */ +static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp) { BdrvChild *c; + BdrvStateSetAioContext *state; + + GLOBAL_STATE_CODE(); if (bdrv_get_aio_context(bs) == ctx) { return true; } - GLOBAL_STATE_CODE(); - QLIST_FOREACH(c, &bs->parents, next_parent) { - if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) { + if (!bdrv_parent_change_aio_context(c, ctx, visited, tran, errp)) { return false; } } + QLIST_FOREACH(c, &bs->children, next) { - if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) { + if (!bdrv_child_change_aio_context(c, ctx, visited, tran, errp)) { return false; } } + state = g_new(BdrvStateSetAioContext, 1); + *state = (BdrvStateSetAioContext) { + .new_ctx = ctx, + .bs = bs, + }; + + /* Paired with bdrv_drained_end in bdrv_set_aio_context_clean() */ + bdrv_drained_begin(bs); + + tran_add(tran, &set_aio_context, state); + return true; } -int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, - BdrvChild *ignore_child, Error **errp) +/* + * Change bs's and recursively all of its parents' and children's AioContext + * to the given new context, returning an error if that isn't possible. + * + * If ignore_child is not NULL, that child (and its subgraph) will not + * be touched. + * + * This function still requires the caller to take the bs current + * AioContext lock, otherwise draining will fail since AIO_WAIT_WHILE + * assumes the lock is always held if bs is in another AioContext. + * For the same reason, it temporarily also holds the new AioContext, since + * bdrv_drained_end calls BDRV_POLL_WHILE that assumes the lock is taken too. + * Therefore the new AioContext lock must not be taken by the caller. + */ +int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx, + BdrvChild *ignore_child, Error **errp) { - GSList *ignore; - bool ret; - + Transaction *tran; + GHashTable *visited; + int ret; + AioContext *old_context = bdrv_get_aio_context(bs); GLOBAL_STATE_CODE(); - ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL; - ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp); - g_slist_free(ignore); + /* + * Recursion phase: go through all nodes of the graph. + * Take care of checking that all nodes support changing AioContext + * and drain them, builing a linear list of callbacks to run if everything + * is successful (the transaction itself). + */ + tran = tran_new(); + visited = g_hash_table_new(NULL, NULL); + if (ignore_child) { + g_hash_table_add(visited, ignore_child); + } + ret = bdrv_change_aio_context(bs, ctx, visited, tran, errp); + g_hash_table_destroy(visited); + + /* + * Linear phase: go through all callbacks collected in the transaction. + * Run all callbacks collected in the recursion to switch all nodes + * AioContext lock (transaction commit), or undo all changes done in the + * recursion (transaction abort). + */ if (!ret) { + /* Just run clean() callbacks. No AioContext changed. */ + tran_abort(tran); return -EPERM; } - ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL; - bdrv_set_aio_context_ignore(bs, ctx, &ignore); - g_slist_free(ignore); + /* + * Release old AioContext, it won't be needed anymore, as all + * bdrv_drained_begin() have been called already. + */ + if (qemu_get_aio_context() != old_context) { + aio_context_release(old_context); + } - return 0; -} + /* + * Acquire new AioContext since bdrv_drained_end() is going to be called + * after we switched all nodes in the new AioContext, and the function + * assumes that the lock of the bs is always taken. + */ + if (qemu_get_aio_context() != ctx) { + aio_context_acquire(ctx); + } -int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, - Error **errp) -{ - GLOBAL_STATE_CODE(); - return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp); + tran_commit(tran); + + if (qemu_get_aio_context() != ctx) { + aio_context_release(ctx); + } + + /* Re-acquire the old AioContext, since the caller takes and releases it. */ + if (qemu_get_aio_context() != old_context) { + aio_context_acquire(old_context); + } + + return 0; } void bdrv_add_aio_context_notifier(BlockDriverState *bs, diff --git a/block/accounting.c b/block/accounting.c index 2030851d79d6..2829745377a5 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/backup.c b/block/backup.c index 5cfd0b999ce3..6a9ad97a5322 100644 --- a/block/backup.c +++ b/block/backup.c @@ -228,15 +228,13 @@ static int coroutine_fn backup_loop(BackupBlockJob *job) static void backup_init_bcs_bitmap(BackupBlockJob *job) { - bool ret; uint64_t estimate; BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs); if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) { bdrv_clear_dirty_bitmap(bcs_bitmap, NULL); - ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, - NULL, true); - assert(ret); + bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, NULL, + true); } else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { /* * We can't hog the coroutine to initialize this thoroughly. @@ -311,7 +309,7 @@ static void coroutine_fn backup_pause(Job *job) } } -static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed) +static void backup_set_speed(BlockJob *job, int64_t speed) { BackupBlockJob *s = container_of(job, BackupBlockJob, common); diff --git a/block/blkdebug.c b/block/blkdebug.c index bbf294870308..ca65b043f07a 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -297,9 +297,7 @@ static int read_config(BDRVBlkdebugState *s, const char *filename, } } - qemu_config_parse_qdict(options, config_groups, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!qemu_config_parse_qdict(options, config_groups, errp)) { ret = -EINVAL; goto fail; } @@ -503,12 +501,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the image file */ - bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", - bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - ret = -EINVAL; + ret = bdrv_open_file_child(qemu_opt_get(opts, "x-image"), options, "image", + bs, errp); + if (ret < 0) { goto out; } @@ -672,7 +667,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); } -static int blkdebug_co_flush(BlockDriverState *bs) +static int coroutine_fn blkdebug_co_flush(BlockDriverState *bs) { int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH); diff --git a/block/blkio.c b/block/blkio.c new file mode 100644 index 000000000000..5eae3adfaf66 --- /dev/null +++ b/block/blkio.c @@ -0,0 +1,1046 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * libblkio BlockDriver + * + * Copyright Red Hat, Inc. + * + * Author: + * Stefan Hajnoczi + */ + +#include "qemu/osdep.h" +#include +#include "block/block_int.h" +#include "exec/memory.h" +#include "exec/cpu-common.h" /* for qemu_ram_get_fd() */ +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qapi/qmp/qdict.h" +#include "qemu/module.h" +#include "exec/memory.h" /* for ram_block_discard_disable() */ + +/* + * Keep the QEMU BlockDriver names identical to the libblkio driver names. + * Using macros instead of typing out the string literals avoids typos. + */ +#define DRIVER_IO_URING "io_uring" +#define DRIVER_NVME_IO_URING "nvme-io_uring" +#define DRIVER_VIRTIO_BLK_VFIO_PCI "virtio-blk-vfio-pci" +#define DRIVER_VIRTIO_BLK_VHOST_USER "virtio-blk-vhost-user" +#define DRIVER_VIRTIO_BLK_VHOST_VDPA "virtio-blk-vhost-vdpa" + +/* + * Allocated bounce buffers are kept in a list sorted by buffer address. + */ +typedef struct BlkioBounceBuf { + QLIST_ENTRY(BlkioBounceBuf) next; + + /* The bounce buffer */ + struct iovec buf; +} BlkioBounceBuf; + +typedef struct { + /* + * libblkio is not thread-safe so this lock protects ->blkio and + * ->blkioq. + */ + QemuMutex blkio_lock; + struct blkio *blkio; + struct blkioq *blkioq; /* make this multi-queue in the future... */ + int completion_fd; + + /* + * Polling fetches the next completion into this field. + * + * No lock is necessary since only one thread calls aio_poll() and invokes + * fd and poll handlers. + */ + struct blkio_completion poll_completion; + + /* + * Protects ->bounce_pool, ->bounce_bufs, ->bounce_available. + * + * Lock ordering: ->bounce_lock before ->blkio_lock. + */ + CoMutex bounce_lock; + + /* Bounce buffer pool */ + struct blkio_mem_region bounce_pool; + + /* Sorted list of allocated bounce buffers */ + QLIST_HEAD(, BlkioBounceBuf) bounce_bufs; + + /* Queue for coroutines waiting for bounce buffer space */ + CoQueue bounce_available; + + /* The value of the "mem-region-alignment" property */ + size_t mem_region_alignment; + + /* Can we skip adding/deleting blkio_mem_regions? */ + bool needs_mem_regions; + + /* Are file descriptors necessary for blkio_mem_regions? */ + bool needs_mem_region_fd; + + /* Are madvise(MADV_DONTNEED)-style operations unavailable? */ + bool may_pin_mem_regions; +} BDRVBlkioState; + +/* Called with s->bounce_lock held */ +static int blkio_resize_bounce_pool(BDRVBlkioState *s, int64_t bytes) +{ + /* There can be no allocated bounce buffers during resize */ + assert(QLIST_EMPTY(&s->bounce_bufs)); + + /* Pad size to reduce frequency of resize calls */ + bytes += 128 * 1024; + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + int ret; + + if (s->bounce_pool.addr) { + blkio_unmap_mem_region(s->blkio, &s->bounce_pool); + blkio_free_mem_region(s->blkio, &s->bounce_pool); + memset(&s->bounce_pool, 0, sizeof(s->bounce_pool)); + } + + /* Automatically freed when s->blkio is destroyed */ + ret = blkio_alloc_mem_region(s->blkio, &s->bounce_pool, bytes); + if (ret < 0) { + return ret; + } + + ret = blkio_map_mem_region(s->blkio, &s->bounce_pool); + if (ret < 0) { + blkio_free_mem_region(s->blkio, &s->bounce_pool); + memset(&s->bounce_pool, 0, sizeof(s->bounce_pool)); + return ret; + } + } + + return 0; +} + +/* Called with s->bounce_lock held */ +static bool +blkio_do_alloc_bounce_buffer(BDRVBlkioState *s, BlkioBounceBuf *bounce, + int64_t bytes) +{ + void *addr = s->bounce_pool.addr; + BlkioBounceBuf *cur = NULL; + BlkioBounceBuf *prev = NULL; + ptrdiff_t space; + + /* + * This is just a linear search over the holes between requests. An + * efficient allocator would be nice. + */ + QLIST_FOREACH(cur, &s->bounce_bufs, next) { + space = cur->buf.iov_base - addr; + if (bytes <= space) { + QLIST_INSERT_BEFORE(cur, bounce, next); + bounce->buf.iov_base = addr; + bounce->buf.iov_len = bytes; + return true; + } + + addr = cur->buf.iov_base + cur->buf.iov_len; + prev = cur; + } + + /* Is there space after the last request? */ + space = s->bounce_pool.addr + s->bounce_pool.len - addr; + if (bytes > space) { + return false; + } + if (prev) { + QLIST_INSERT_AFTER(prev, bounce, next); + } else { + QLIST_INSERT_HEAD(&s->bounce_bufs, bounce, next); + } + bounce->buf.iov_base = addr; + bounce->buf.iov_len = bytes; + return true; +} + +static int coroutine_fn +blkio_alloc_bounce_buffer(BDRVBlkioState *s, BlkioBounceBuf *bounce, + int64_t bytes) +{ + /* + * Ensure fairness: first time around we join the back of the queue, + * subsequently we join the front so we don't lose our place. + */ + CoQueueWaitFlags wait_flags = 0; + + QEMU_LOCK_GUARD(&s->bounce_lock); + + /* Ensure fairness: don't even try if other requests are already waiting */ + if (!qemu_co_queue_empty(&s->bounce_available)) { + qemu_co_queue_wait_flags(&s->bounce_available, &s->bounce_lock, + wait_flags); + wait_flags = CO_QUEUE_WAIT_FRONT; + } + + while (true) { + if (blkio_do_alloc_bounce_buffer(s, bounce, bytes)) { + /* Kick the next queued request since there may be space */ + qemu_co_queue_next(&s->bounce_available); + return 0; + } + + /* + * If there are no in-flight requests then the pool was simply too + * small. + */ + if (QLIST_EMPTY(&s->bounce_bufs)) { + bool ok; + int ret; + + ret = blkio_resize_bounce_pool(s, bytes); + if (ret < 0) { + /* Kick the next queued request since that may fail too */ + qemu_co_queue_next(&s->bounce_available); + return ret; + } + + ok = blkio_do_alloc_bounce_buffer(s, bounce, bytes); + assert(ok); /* must have space this time */ + return 0; + } + + qemu_co_queue_wait_flags(&s->bounce_available, &s->bounce_lock, + wait_flags); + wait_flags = CO_QUEUE_WAIT_FRONT; + } +} + +static void coroutine_fn blkio_free_bounce_buffer(BDRVBlkioState *s, + BlkioBounceBuf *bounce) +{ + QEMU_LOCK_GUARD(&s->bounce_lock); + + QLIST_REMOVE(bounce, next); + + /* Wake up waiting coroutines since space may now be available */ + qemu_co_queue_next(&s->bounce_available); +} + +/* For async to .bdrv_co_*() conversion */ +typedef struct { + Coroutine *coroutine; + int ret; +} BlkioCoData; + +static void blkio_completion_fd_read(void *opaque) +{ + BlockDriverState *bs = opaque; + BDRVBlkioState *s = bs->opaque; + uint64_t val; + int ret; + + /* Polling may have already fetched a completion */ + if (s->poll_completion.user_data != NULL) { + BlkioCoData *cod = s->poll_completion.user_data; + cod->ret = s->poll_completion.ret; + + /* Clear it in case aio_co_wake() enters a nested event loop */ + s->poll_completion.user_data = NULL; + + aio_co_wake(cod->coroutine); + } + + /* Reset completion fd status */ + ret = read(s->completion_fd, &val, sizeof(val)); + + /* Ignore errors, there's nothing we can do */ + (void)ret; + + /* + * Reading one completion at a time makes nested event loop re-entrancy + * simple. Change this loop to get multiple completions in one go if it + * becomes a performance bottleneck. + */ + while (true) { + struct blkio_completion completion; + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + ret = blkioq_do_io(s->blkioq, &completion, 0, 1, NULL); + } + if (ret != 1) { + break; + } + + BlkioCoData *cod = completion.user_data; + cod->ret = completion.ret; + aio_co_wake(cod->coroutine); + } +} + +static bool blkio_completion_fd_poll(void *opaque) +{ + BlockDriverState *bs = opaque; + BDRVBlkioState *s = bs->opaque; + int ret; + + /* Just in case we already fetched a completion */ + if (s->poll_completion.user_data != NULL) { + return true; + } + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + ret = blkioq_do_io(s->blkioq, &s->poll_completion, 0, 1, NULL); + } + return ret == 1; +} + +static void blkio_completion_fd_poll_ready(void *opaque) +{ + blkio_completion_fd_read(opaque); +} + +static void blkio_attach_aio_context(BlockDriverState *bs, + AioContext *new_context) +{ + BDRVBlkioState *s = bs->opaque; + + aio_set_fd_handler(new_context, + s->completion_fd, + false, + blkio_completion_fd_read, + NULL, + blkio_completion_fd_poll, + blkio_completion_fd_poll_ready, + bs); +} + +static void blkio_detach_aio_context(BlockDriverState *bs) +{ + BDRVBlkioState *s = bs->opaque; + + aio_set_fd_handler(bdrv_get_aio_context(bs), + s->completion_fd, + false, NULL, NULL, NULL, NULL, NULL); +} + +/* Call with s->blkio_lock held to submit I/O after enqueuing a new request */ +static void blkio_submit_io(BlockDriverState *bs) +{ + if (qatomic_read(&bs->io_plugged) == 0) { + BDRVBlkioState *s = bs->opaque; + + blkioq_do_io(s->blkioq, NULL, 0, 0, NULL); + } +} + +static int coroutine_fn +blkio_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) +{ + BDRVBlkioState *s = bs->opaque; + BlkioCoData cod = { + .coroutine = qemu_coroutine_self(), + }; + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkioq_discard(s->blkioq, offset, bytes, &cod, 0); + blkio_submit_io(bs); + } + + qemu_coroutine_yield(); + return cod.ret; +} + +static int coroutine_fn +blkio_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, + QEMUIOVector *qiov, BdrvRequestFlags flags) +{ + BlkioCoData cod = { + .coroutine = qemu_coroutine_self(), + }; + BDRVBlkioState *s = bs->opaque; + bool use_bounce_buffer = + s->needs_mem_regions && !(flags & BDRV_REQ_REGISTERED_BUF); + BlkioBounceBuf bounce; + struct iovec *iov = qiov->iov; + int iovcnt = qiov->niov; + + if (use_bounce_buffer) { + int ret = blkio_alloc_bounce_buffer(s, &bounce, bytes); + if (ret < 0) { + return ret; + } + + iov = &bounce.buf; + iovcnt = 1; + } + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkioq_readv(s->blkioq, offset, iov, iovcnt, &cod, 0); + blkio_submit_io(bs); + } + + qemu_coroutine_yield(); + + if (use_bounce_buffer) { + if (cod.ret == 0) { + qemu_iovec_from_buf(qiov, 0, + bounce.buf.iov_base, + bounce.buf.iov_len); + } + + blkio_free_bounce_buffer(s, &bounce); + } + + return cod.ret; +} + +static int coroutine_fn blkio_co_pwritev(BlockDriverState *bs, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) +{ + uint32_t blkio_flags = (flags & BDRV_REQ_FUA) ? BLKIO_REQ_FUA : 0; + BlkioCoData cod = { + .coroutine = qemu_coroutine_self(), + }; + BDRVBlkioState *s = bs->opaque; + bool use_bounce_buffer = + s->needs_mem_regions && !(flags & BDRV_REQ_REGISTERED_BUF); + BlkioBounceBuf bounce; + struct iovec *iov = qiov->iov; + int iovcnt = qiov->niov; + + if (use_bounce_buffer) { + int ret = blkio_alloc_bounce_buffer(s, &bounce, bytes); + if (ret < 0) { + return ret; + } + + qemu_iovec_to_buf(qiov, 0, bounce.buf.iov_base, bytes); + iov = &bounce.buf; + iovcnt = 1; + } + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkioq_writev(s->blkioq, offset, iov, iovcnt, &cod, blkio_flags); + blkio_submit_io(bs); + } + + qemu_coroutine_yield(); + + if (use_bounce_buffer) { + blkio_free_bounce_buffer(s, &bounce); + } + + return cod.ret; +} + +static int coroutine_fn blkio_co_flush(BlockDriverState *bs) +{ + BDRVBlkioState *s = bs->opaque; + BlkioCoData cod = { + .coroutine = qemu_coroutine_self(), + }; + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkioq_flush(s->blkioq, &cod, 0); + blkio_submit_io(bs); + } + + qemu_coroutine_yield(); + return cod.ret; +} + +static int coroutine_fn blkio_co_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int64_t bytes, BdrvRequestFlags flags) +{ + BDRVBlkioState *s = bs->opaque; + BlkioCoData cod = { + .coroutine = qemu_coroutine_self(), + }; + uint32_t blkio_flags = 0; + + if (flags & BDRV_REQ_FUA) { + blkio_flags |= BLKIO_REQ_FUA; + } + if (!(flags & BDRV_REQ_MAY_UNMAP)) { + blkio_flags |= BLKIO_REQ_NO_UNMAP; + } + if (flags & BDRV_REQ_NO_FALLBACK) { + blkio_flags |= BLKIO_REQ_NO_FALLBACK; + } + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkioq_write_zeroes(s->blkioq, offset, bytes, &cod, blkio_flags); + blkio_submit_io(bs); + } + + qemu_coroutine_yield(); + return cod.ret; +} + +static void blkio_io_unplug(BlockDriverState *bs) +{ + BDRVBlkioState *s = bs->opaque; + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkio_submit_io(bs); + } +} + +typedef enum { + BMRR_OK, + BMRR_SKIP, + BMRR_FAIL, +} BlkioMemRegionResult; + +/* + * Produce a struct blkio_mem_region for a given address and size. + * + * This function produces identical results when called multiple times with the + * same arguments. This property is necessary because blkio_unmap_mem_region() + * must receive the same struct blkio_mem_region field values that were passed + * to blkio_map_mem_region(). + */ +static BlkioMemRegionResult +blkio_mem_region_from_host(BlockDriverState *bs, + void *host, size_t size, + struct blkio_mem_region *region, + Error **errp) +{ + BDRVBlkioState *s = bs->opaque; + int fd = -1; + ram_addr_t fd_offset = 0; + + if (((uintptr_t)host | size) % s->mem_region_alignment) { + error_setg(errp, "unaligned buf %p with size %zu", host, size); + return BMRR_FAIL; + } + + /* Attempt to find the fd for the underlying memory */ + if (s->needs_mem_region_fd) { + RAMBlock *ram_block; + RAMBlock *end_block; + ram_addr_t offset; + + /* + * bdrv_register_buf() is called with the BQL held so mr lives at least + * until this function returns. + */ + ram_block = qemu_ram_block_from_host(host, false, &fd_offset); + if (ram_block) { + fd = qemu_ram_get_fd(ram_block); + } + if (fd == -1) { + /* + * Ideally every RAMBlock would have an fd. pc-bios and other + * things don't. Luckily they are usually not I/O buffers and we + * can just ignore them. + */ + return BMRR_SKIP; + } + + /* Make sure the fd covers the entire range */ + end_block = qemu_ram_block_from_host(host + size - 1, false, &offset); + if (ram_block != end_block) { + error_setg(errp, "registered buffer at %p with size %zu extends " + "beyond RAMBlock", host, size); + return BMRR_FAIL; + } + } + + *region = (struct blkio_mem_region){ + .addr = host, + .len = size, + .fd = fd, + .fd_offset = fd_offset, + }; + return BMRR_OK; +} + +static bool blkio_register_buf(BlockDriverState *bs, void *host, size_t size, + Error **errp) +{ + BDRVBlkioState *s = bs->opaque; + struct blkio_mem_region region; + BlkioMemRegionResult region_result; + int ret; + + /* + * Mapping memory regions conflicts with RAM discard (virtio-mem) when + * there is pinning, so only do it when necessary. + */ + if (!s->needs_mem_regions && s->may_pin_mem_regions) { + return true; + } + + region_result = blkio_mem_region_from_host(bs, host, size, ®ion, errp); + if (region_result == BMRR_SKIP) { + return true; + } else if (region_result != BMRR_OK) { + return false; + } + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + ret = blkio_map_mem_region(s->blkio, ®ion); + } + + if (ret < 0) { + error_setg(errp, "Failed to add blkio mem region %p with size %zu: %s", + host, size, blkio_get_error_msg()); + return false; + } + return true; +} + +static void blkio_unregister_buf(BlockDriverState *bs, void *host, size_t size) +{ + BDRVBlkioState *s = bs->opaque; + struct blkio_mem_region region; + + /* See blkio_register_buf() */ + if (!s->needs_mem_regions && s->may_pin_mem_regions) { + return; + } + + if (blkio_mem_region_from_host(bs, host, size, ®ion, NULL) != BMRR_OK) { + return; + } + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + blkio_unmap_mem_region(s->blkio, ®ion); + } +} + +static int blkio_io_uring_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) +{ + const char *filename = qdict_get_str(options, "filename"); + BDRVBlkioState *s = bs->opaque; + int ret; + + ret = blkio_set_str(s->blkio, "path", filename); + qdict_del(options, "filename"); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to set path: %s", + blkio_get_error_msg()); + return ret; + } + + if (flags & BDRV_O_NOCACHE) { + ret = blkio_set_bool(s->blkio, "direct", true); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to set direct: %s", + blkio_get_error_msg()); + return ret; + } + } + + return 0; +} + +static int blkio_nvme_io_uring(BlockDriverState *bs, QDict *options, int flags, + Error **errp) +{ + const char *path = qdict_get_try_str(options, "path"); + BDRVBlkioState *s = bs->opaque; + int ret; + + if (!path) { + error_setg(errp, "missing 'path' option"); + return -EINVAL; + } + + ret = blkio_set_str(s->blkio, "path", path); + qdict_del(options, "path"); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to set path: %s", + blkio_get_error_msg()); + return ret; + } + + if (!(flags & BDRV_O_NOCACHE)) { + error_setg(errp, "cache.direct=off is not supported"); + return -EINVAL; + } + + return 0; +} + +static int blkio_virtio_blk_common_open(BlockDriverState *bs, + QDict *options, int flags, Error **errp) +{ + const char *path = qdict_get_try_str(options, "path"); + BDRVBlkioState *s = bs->opaque; + int ret; + + if (!path) { + error_setg(errp, "missing 'path' option"); + return -EINVAL; + } + + ret = blkio_set_str(s->blkio, "path", path); + qdict_del(options, "path"); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to set path: %s", + blkio_get_error_msg()); + return ret; + } + + if (!(flags & BDRV_O_NOCACHE)) { + error_setg(errp, "cache.direct=off is not supported"); + return -EINVAL; + } + return 0; +} + +static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) +{ + const char *blkio_driver = bs->drv->protocol_name; + BDRVBlkioState *s = bs->opaque; + int ret; + + ret = blkio_create(blkio_driver, &s->blkio); + if (ret < 0) { + error_setg_errno(errp, -ret, "blkio_create failed: %s", + blkio_get_error_msg()); + return ret; + } + + if (strcmp(blkio_driver, DRIVER_IO_URING) == 0) { + ret = blkio_io_uring_open(bs, options, flags, errp); + } else if (strcmp(blkio_driver, DRIVER_NVME_IO_URING) == 0) { + ret = blkio_nvme_io_uring(bs, options, flags, errp); + } else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VFIO_PCI) == 0) { + ret = blkio_virtio_blk_common_open(bs, options, flags, errp); + } else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VHOST_USER) == 0) { + ret = blkio_virtio_blk_common_open(bs, options, flags, errp); + } else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VHOST_VDPA) == 0) { + ret = blkio_virtio_blk_common_open(bs, options, flags, errp); + } else { + g_assert_not_reached(); + } + if (ret < 0) { + blkio_destroy(&s->blkio); + return ret; + } + + if (!(flags & BDRV_O_RDWR)) { + ret = blkio_set_bool(s->blkio, "read-only", true); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to set read-only: %s", + blkio_get_error_msg()); + blkio_destroy(&s->blkio); + return ret; + } + } + + ret = blkio_connect(s->blkio); + if (ret < 0) { + error_setg_errno(errp, -ret, "blkio_connect failed: %s", + blkio_get_error_msg()); + blkio_destroy(&s->blkio); + return ret; + } + + ret = blkio_get_bool(s->blkio, + "needs-mem-regions", + &s->needs_mem_regions); + if (ret < 0) { + error_setg_errno(errp, -ret, + "failed to get needs-mem-regions: %s", + blkio_get_error_msg()); + blkio_destroy(&s->blkio); + return ret; + } + + ret = blkio_get_bool(s->blkio, + "needs-mem-region-fd", + &s->needs_mem_region_fd); + if (ret < 0) { + error_setg_errno(errp, -ret, + "failed to get needs-mem-region-fd: %s", + blkio_get_error_msg()); + blkio_destroy(&s->blkio); + return ret; + } + + ret = blkio_get_uint64(s->blkio, + "mem-region-alignment", + &s->mem_region_alignment); + if (ret < 0) { + error_setg_errno(errp, -ret, + "failed to get mem-region-alignment: %s", + blkio_get_error_msg()); + blkio_destroy(&s->blkio); + return ret; + } + + ret = blkio_get_bool(s->blkio, + "may-pin-mem-regions", + &s->may_pin_mem_regions); + if (ret < 0) { + /* Be conservative (assume pinning) if the property is not supported */ + s->may_pin_mem_regions = s->needs_mem_regions; + } + + /* + * Notify if libblkio drivers pin memory and prevent features like + * virtio-mem from working. + */ + if (s->may_pin_mem_regions) { + ret = ram_block_discard_disable(true); + if (ret < 0) { + error_setg_errno(errp, -ret, "ram_block_discard_disable() failed"); + blkio_destroy(&s->blkio); + return ret; + } + } + + ret = blkio_start(s->blkio); + if (ret < 0) { + error_setg_errno(errp, -ret, "blkio_start failed: %s", + blkio_get_error_msg()); + blkio_destroy(&s->blkio); + if (s->may_pin_mem_regions) { + ram_block_discard_disable(false); + } + return ret; + } + + bs->supported_write_flags = BDRV_REQ_FUA | BDRV_REQ_REGISTERED_BUF; + bs->supported_zero_flags = BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | + BDRV_REQ_NO_FALLBACK; + + qemu_mutex_init(&s->blkio_lock); + qemu_co_mutex_init(&s->bounce_lock); + qemu_co_queue_init(&s->bounce_available); + QLIST_INIT(&s->bounce_bufs); + s->blkioq = blkio_get_queue(s->blkio, 0); + s->completion_fd = blkioq_get_completion_fd(s->blkioq); + + blkio_attach_aio_context(bs, bdrv_get_aio_context(bs)); + return 0; +} + +static void blkio_close(BlockDriverState *bs) +{ + BDRVBlkioState *s = bs->opaque; + + /* There is no destroy() API for s->bounce_lock */ + + qemu_mutex_destroy(&s->blkio_lock); + blkio_detach_aio_context(bs); + blkio_destroy(&s->blkio); + + if (s->may_pin_mem_regions) { + ram_block_discard_disable(false); + } +} + +static int64_t blkio_getlength(BlockDriverState *bs) +{ + BDRVBlkioState *s = bs->opaque; + uint64_t capacity; + int ret; + + WITH_QEMU_LOCK_GUARD(&s->blkio_lock) { + ret = blkio_get_uint64(s->blkio, "capacity", &capacity); + } + if (ret < 0) { + return -ret; + } + + return capacity; +} + +static int coroutine_fn blkio_truncate(BlockDriverState *bs, int64_t offset, + bool exact, PreallocMode prealloc, + BdrvRequestFlags flags, Error **errp) +{ + int64_t current_length; + + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_str(prealloc)); + return -ENOTSUP; + } + + current_length = blkio_getlength(bs); + + if (offset > current_length) { + error_setg(errp, "Cannot grow device"); + return -EINVAL; + } else if (exact && offset != current_length) { + error_setg(errp, "Cannot resize device"); + return -ENOTSUP; + } + + return 0; +} + +static int blkio_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + return 0; +} + +static void blkio_refresh_limits(BlockDriverState *bs, Error **errp) +{ + BDRVBlkioState *s = bs->opaque; + QEMU_LOCK_GUARD(&s->blkio_lock); + int value; + int ret; + + ret = blkio_get_int(s->blkio, "request-alignment", &value); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to get \"request-alignment\": %s", + blkio_get_error_msg()); + return; + } + bs->bl.request_alignment = value; + if (bs->bl.request_alignment < 1 || + bs->bl.request_alignment >= INT_MAX || + !is_power_of_2(bs->bl.request_alignment)) { + error_setg(errp, "invalid \"request-alignment\" value %" PRIu32 ", " + "must be a power of 2 less than INT_MAX", + bs->bl.request_alignment); + return; + } + + ret = blkio_get_int(s->blkio, "optimal-io-size", &value); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to get \"optimal-io-size\": %s", + blkio_get_error_msg()); + return; + } + bs->bl.opt_transfer = value; + if (bs->bl.opt_transfer > INT_MAX || + (bs->bl.opt_transfer % bs->bl.request_alignment)) { + error_setg(errp, "invalid \"optimal-io-size\" value %" PRIu32 ", must " + "be a multiple of %" PRIu32, bs->bl.opt_transfer, + bs->bl.request_alignment); + return; + } + + ret = blkio_get_int(s->blkio, "max-transfer", &value); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to get \"max-transfer\": %s", + blkio_get_error_msg()); + return; + } + bs->bl.max_transfer = value; + if ((bs->bl.max_transfer % bs->bl.request_alignment) || + (bs->bl.opt_transfer && (bs->bl.max_transfer % bs->bl.opt_transfer))) { + error_setg(errp, "invalid \"max-transfer\" value %" PRIu32 ", must be " + "a multiple of %" PRIu32 " and %" PRIu32 " (if non-zero)", + bs->bl.max_transfer, bs->bl.request_alignment, + bs->bl.opt_transfer); + return; + } + + ret = blkio_get_int(s->blkio, "buf-alignment", &value); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to get \"buf-alignment\": %s", + blkio_get_error_msg()); + return; + } + if (value < 1) { + error_setg(errp, "invalid \"buf-alignment\" value %d, must be " + "positive", value); + return; + } + bs->bl.min_mem_alignment = value; + + ret = blkio_get_int(s->blkio, "optimal-buf-alignment", &value); + if (ret < 0) { + error_setg_errno(errp, -ret, + "failed to get \"optimal-buf-alignment\": %s", + blkio_get_error_msg()); + return; + } + if (value < 1) { + error_setg(errp, "invalid \"optimal-buf-alignment\" value %d, " + "must be positive", value); + return; + } + bs->bl.opt_mem_alignment = value; + + ret = blkio_get_int(s->blkio, "max-segments", &value); + if (ret < 0) { + error_setg_errno(errp, -ret, "failed to get \"max-segments\": %s", + blkio_get_error_msg()); + return; + } + if (value < 1) { + error_setg(errp, "invalid \"max-segments\" value %d, must be positive", + value); + return; + } + bs->bl.max_iov = value; +} + +/* + * TODO + * Missing libblkio APIs: + * - block_status + * - co_invalidate_cache + * + * Out of scope? + * - create + * - truncate + */ + +#define BLKIO_DRIVER(name, ...) \ + { \ + .format_name = name, \ + .protocol_name = name, \ + .instance_size = sizeof(BDRVBlkioState), \ + .bdrv_file_open = blkio_file_open, \ + .bdrv_close = blkio_close, \ + .bdrv_getlength = blkio_getlength, \ + .bdrv_co_truncate = blkio_truncate, \ + .bdrv_get_info = blkio_get_info, \ + .bdrv_attach_aio_context = blkio_attach_aio_context, \ + .bdrv_detach_aio_context = blkio_detach_aio_context, \ + .bdrv_co_pdiscard = blkio_co_pdiscard, \ + .bdrv_co_preadv = blkio_co_preadv, \ + .bdrv_co_pwritev = blkio_co_pwritev, \ + .bdrv_co_flush_to_disk = blkio_co_flush, \ + .bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \ + .bdrv_io_unplug = blkio_io_unplug, \ + .bdrv_refresh_limits = blkio_refresh_limits, \ + .bdrv_register_buf = blkio_register_buf, \ + .bdrv_unregister_buf = blkio_unregister_buf, \ + __VA_ARGS__ \ + } + +static BlockDriver bdrv_io_uring = BLKIO_DRIVER( + DRIVER_IO_URING, + .bdrv_needs_filename = true, +); + +static BlockDriver bdrv_nvme_io_uring = BLKIO_DRIVER( + DRIVER_NVME_IO_URING, +); + +static BlockDriver bdrv_virtio_blk_vfio_pci = BLKIO_DRIVER( + DRIVER_VIRTIO_BLK_VFIO_PCI +); + +static BlockDriver bdrv_virtio_blk_vhost_user = BLKIO_DRIVER( + DRIVER_VIRTIO_BLK_VHOST_USER +); + +static BlockDriver bdrv_virtio_blk_vhost_vdpa = BLKIO_DRIVER( + DRIVER_VIRTIO_BLK_VHOST_VDPA +); + +static void bdrv_blkio_init(void) +{ + bdrv_register(&bdrv_io_uring); + bdrv_register(&bdrv_nvme_io_uring); + bdrv_register(&bdrv_virtio_blk_vfio_pci); + bdrv_register(&bdrv_virtio_blk_vhost_user); + bdrv_register(&bdrv_virtio_blk_vhost_vdpa); +} + +block_init(bdrv_blkio_init); diff --git a/block/blklogwrites.c b/block/blklogwrites.c index f7a251e91f9e..cef9efe55d75 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -107,8 +107,8 @@ static uint64_t blk_log_writes_find_cur_log_sector(BdrvChild *log, struct log_write_entry cur_entry; while (cur_idx < nr_entries) { - int read_ret = bdrv_pread(log, cur_sector << sector_bits, &cur_entry, - sizeof(cur_entry)); + int read_ret = bdrv_pread(log, cur_sector << sector_bits, + sizeof(cur_entry), &cur_entry, 0); if (read_ret < 0) { error_setg_errno(errp, -read_ret, "Failed to read log entry %"PRIu64, cur_idx); @@ -155,11 +155,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the file */ - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false, - errp); - if (!bs->file) { - ret = -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { goto fail; } @@ -190,7 +187,7 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, log_sb.nr_entries = cpu_to_le64(0); log_sb.sectorsize = cpu_to_le32(BDRV_SECTOR_SIZE); } else { - ret = bdrv_pread(s->log_file, 0, &log_sb, sizeof(log_sb)); + ret = bdrv_pread(s->log_file, 0, sizeof(log_sb), &log_sb, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read log superblock"); goto fail_log; @@ -257,10 +254,6 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, s->log_file = NULL; } fail: - if (ret < 0) { - bdrv_unref_child(bs, bs->file); - bs->file = NULL; - } qemu_opts_del(opts); return ret; } diff --git a/block/blkreplay.c b/block/blkreplay.c index dcbe780ddbd3..76a0b8d12ae1 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -26,11 +26,8 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, int ret; /* Open the image file */ - bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - ret = -EINVAL; + ret = bdrv_open_file_child(NULL, options, "image", bs, errp); + if (ret < 0) { goto fail; } diff --git a/block/blkverify.c b/block/blkverify.c index e4a37af3b2ef..c60a2dc624dc 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -122,12 +122,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the raw file */ - bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", - bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - ret = -EINVAL; + ret = bdrv_open_file_child(qemu_opt_get(opts, "x-raw"), options, "raw", + bs, errp); + if (ret < 0) { goto fail; } @@ -235,8 +232,8 @@ blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, qemu_iovec_init(&raw_qiov, qiov->niov); qemu_iovec_clone(&raw_qiov, qiov, buf); - ret = blkverify_co_prwv(bs, &r, offset, bytes, qiov, &raw_qiov, flags, - false); + ret = blkverify_co_prwv(bs, &r, offset, bytes, qiov, &raw_qiov, + flags & ~BDRV_REQ_REGISTERED_BUF, false); cmp_offset = qemu_iovec_compare(qiov, &raw_qiov); if (cmp_offset != -1) { @@ -258,7 +255,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 e0e1aff4b1bd..ba7bf1d6bc1f 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -56,9 +56,6 @@ struct BlockBackend { const BlockDevOps *dev_ops; void *dev_opaque; - /* the block size for which the guest device expects atomicity */ - int guest_block_size; - /* If the BDS tree is removed, some of its options are stored here (which * can be used to restore those options in the new BDS on insert) */ BlockBackendRootState root_state; @@ -132,15 +129,14 @@ static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format, } static void blk_root_drained_begin(BdrvChild *child); static bool blk_root_drained_poll(BdrvChild *child); -static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter); +static void blk_root_drained_end(BdrvChild *child); static void blk_root_change_media(BdrvChild *child, bool load); static void blk_root_resize(BdrvChild *child); -static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx, - GSList **ignore, Error **errp); -static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx, - GSList **ignore); +static bool blk_root_change_aio_ctx(BdrvChild *child, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp); static char *blk_root_get_parent_desc(BdrvChild *child) { @@ -315,6 +311,7 @@ static void blk_root_detach(BdrvChild *child) static AioContext *blk_root_get_parent_aio_context(BdrvChild *c) { BlockBackend *blk = c->opaque; + IO_CODE(); return blk_get_aio_context(blk); } @@ -337,8 +334,7 @@ static const BdrvChildClass child_root = { .attach = blk_root_attach, .detach = blk_root_detach, - .can_set_aio_ctx = blk_root_can_set_aio_ctx, - .set_aio_ctx = blk_root_set_aio_ctx, + .change_aio_ctx = blk_root_change_aio_ctx, .get_parent_aio_context = blk_root_get_parent_aio_context, }; @@ -998,7 +994,6 @@ void blk_detach_dev(BlockBackend *blk, DeviceState *dev) blk->dev = NULL; blk->dev_ops = NULL; blk->dev_opaque = NULL; - blk->guest_block_size = 512; blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort); blk_unref(blk); } @@ -1062,7 +1057,7 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, blk->dev_opaque = opaque; /* Are we currently quiesced? Should we enforce this right now? */ - if (blk->quiesce_counter && ops->drained_begin) { + if (blk->quiesce_counter && ops && ops->drained_begin) { ops->drained_begin(opaque); } } @@ -1284,9 +1279,10 @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk) } /* To be called between exactly one pair of blk_inc/dec_in_flight() */ -int coroutine_fn -blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, - QEMUIOVector *qiov, BdrvRequestFlags flags) +static int coroutine_fn +blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes, + QEMUIOVector *qiov, size_t qiov_offset, + BdrvRequestFlags flags) { int ret; BlockDriverState *bs; @@ -1311,11 +1307,23 @@ blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, bytes, false); } - ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags); + ret = bdrv_co_preadv_part(blk->root, offset, bytes, qiov, qiov_offset, + flags); bdrv_dec_in_flight(bs); return ret; } +int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, int64_t bytes, + void *buf, BdrvRequestFlags flags) +{ + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); + IO_OR_GS_CODE(); + + assert(bytes <= SIZE_MAX); + + return blk_co_preadv(blk, offset, bytes, &qiov, flags); +} + int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) @@ -1324,14 +1332,28 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, IO_OR_GS_CODE(); blk_inc_in_flight(blk); - ret = blk_co_do_preadv(blk, offset, bytes, qiov, flags); + ret = blk_co_do_preadv_part(blk, offset, bytes, qiov, 0, flags); + blk_dec_in_flight(blk); + + return ret; +} + +int coroutine_fn blk_co_preadv_part(BlockBackend *blk, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + size_t qiov_offset, BdrvRequestFlags flags) +{ + int ret; + IO_OR_GS_CODE(); + + blk_inc_in_flight(blk); + ret = blk_co_do_preadv_part(blk, offset, bytes, qiov, qiov_offset, flags); blk_dec_in_flight(blk); return ret; } /* To be called between exactly one pair of blk_inc/dec_in_flight() */ -int coroutine_fn +static int coroutine_fn blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags) @@ -1383,6 +1405,17 @@ int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, return ret; } +int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, int64_t bytes, + const void *buf, BdrvRequestFlags flags) +{ + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); + IO_OR_GS_CODE(); + + assert(bytes <= SIZE_MAX); + + return blk_co_pwritev(blk, offset, bytes, &qiov, flags); +} + int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) @@ -1391,18 +1424,25 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags); } -static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset, - int64_t bytes, - QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags) +int coroutine_fn blk_co_block_status_above(BlockBackend *blk, + BlockDriverState *base, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, + BlockDriverState **file) { - int ret; - - blk_inc_in_flight(blk); - ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags); - blk_dec_in_flight(blk); + IO_CODE(); + return bdrv_co_block_status_above(blk_bs(blk), base, offset, bytes, pnum, + map, file); +} - return ret; +int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk, + BlockDriverState *base, + bool include_base, int64_t offset, + int64_t bytes, int64_t *pnum) +{ + IO_CODE(); + return bdrv_co_is_allocated_above(blk_bs(blk), base, include_base, offset, + bytes, pnum); } typedef struct BlkRwCo { @@ -1413,14 +1453,6 @@ typedef struct BlkRwCo { BdrvRequestFlags flags; } BlkRwCo; -int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, - int64_t bytes, BdrvRequestFlags flags) -{ - IO_OR_GS_CODE(); - return blk_pwritev_part(blk, offset, bytes, NULL, 0, - flags | BDRV_REQ_ZERO_WRITE); -} - int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) { GLOBAL_STATE_CODE(); @@ -1534,19 +1566,19 @@ 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; QEMUIOVector *qiov = rwco->iobuf; assert(qiov->size == acb->bytes); - rwco->ret = blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes, - qiov, rwco->flags); + rwco->ret = blk_co_do_preadv_part(rwco->blk, rwco->offset, acb->bytes, qiov, + 0, rwco->flags); 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; @@ -1567,31 +1599,6 @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, flags | BDRV_REQ_ZERO_WRITE, cb, opaque); } -int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes) -{ - int ret; - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); - IO_OR_GS_CODE(); - - blk_inc_in_flight(blk); - ret = blk_do_preadv(blk, offset, bytes, &qiov, 0); - blk_dec_in_flight(blk); - - return ret < 0 ? ret : bytes; -} - -int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, - BdrvRequestFlags flags) -{ - int ret; - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); - IO_OR_GS_CODE(); - - ret = blk_pwritev_part(blk, offset, bytes, &qiov, 0, flags); - - return ret < 0 ? ret : bytes; -} - int64_t blk_getlength(BlockBackend *blk) { IO_CODE(); @@ -1655,7 +1662,7 @@ void blk_aio_cancel_async(BlockAIOCB *acb) } /* To be called between exactly one pair of blk_inc/dec_in_flight() */ -int coroutine_fn +static int coroutine_fn blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) { IO_CODE(); @@ -1669,19 +1676,20 @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) return bdrv_co_ioctl(blk_bs(blk), req, buf); } -int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) +int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req, + void *buf) { int ret; IO_OR_GS_CODE(); blk_inc_in_flight(blk); - ret = blk_do_ioctl(blk, req, buf); + ret = blk_co_do_ioctl(blk, req, buf); blk_dec_in_flight(blk); 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; @@ -1699,7 +1707,7 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, } /* To be called between exactly one pair of blk_inc/dec_in_flight() */ -int coroutine_fn +static int coroutine_fn blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) { int ret; @@ -1715,7 +1723,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; @@ -1746,20 +1754,8 @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, return ret; } -int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) -{ - int ret; - IO_OR_GS_CODE(); - - blk_inc_in_flight(blk); - ret = blk_do_pdiscard(blk, offset, bytes); - blk_dec_in_flight(blk); - - return ret; -} - /* To be called between exactly one pair of blk_inc/dec_in_flight() */ -int coroutine_fn blk_co_do_flush(BlockBackend *blk) +static int coroutine_fn blk_co_do_flush(BlockBackend *blk) { blk_wait_while_drained(blk); IO_CODE(); @@ -1771,7 +1767,7 @@ 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; @@ -1799,17 +1795,6 @@ int coroutine_fn blk_co_flush(BlockBackend *blk) return ret; } -int blk_flush(BlockBackend *blk) -{ - int ret; - - blk_inc_in_flight(blk); - ret = blk_do_flush(blk); - blk_dec_in_flight(blk); - - return ret; -} - void blk_drain(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); @@ -1896,7 +1881,7 @@ static void send_qmp_error_event(BlockBackend *blk, BlockDriverState *bs = blk_bs(blk); optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE; - qapi_event_send_block_io_error(blk_name(blk), !!bs, + qapi_event_send_block_io_error(blk_name(blk), bs ? bdrv_get_node_name(bs) : NULL, optype, action, blk_iostatus_is_enabled(blk), error == ENOSPC, strerror(error)); @@ -1981,7 +1966,7 @@ bool blk_enable_write_cache(BlockBackend *blk) void blk_set_enable_write_cache(BlockBackend *blk, bool wce) { - GLOBAL_STATE_CODE(); + IO_CODE(); blk->enable_write_cache = wce; } @@ -2100,12 +2085,6 @@ int blk_get_max_iov(BlockBackend *blk) return blk->root->bs->bl.max_iov; } -void blk_set_guest_block_size(BlockBackend *blk, int align) -{ - IO_CODE(); - blk->guest_block_size = align; -} - void *blk_try_blockalign(BlockBackend *blk, size_t size) { IO_CODE(); @@ -2190,13 +2169,21 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, bdrv_ref(bs); if (update_root_node) { - ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root, - errp); + /* + * update_root_node MUST be false for blk_root_set_aio_ctx_commit(), + * as we are already in the commit function of a transaction. + */ + ret = bdrv_try_change_aio_context(bs, new_context, blk->root, errp); if (ret < 0) { bdrv_unref(bs); return ret; } } + /* + * Make blk->ctx consistent with the root node before we invoke any + * other operations like drain that might inquire blk->ctx + */ + blk->ctx = new_context; if (tgm->throttle_state) { bdrv_drained_begin(bs); throttle_group_detach_aio_context(tgm); @@ -2205,9 +2192,10 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, } bdrv_unref(bs); + } else { + blk->ctx = new_context; } - blk->ctx = new_context; return 0; } @@ -2218,33 +2206,54 @@ int blk_set_aio_context(BlockBackend *blk, AioContext *new_context, return blk_do_set_aio_context(blk, new_context, true, errp); } -static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx, - GSList **ignore, Error **errp) +typedef struct BdrvStateBlkRootContext { + AioContext *new_ctx; + BlockBackend *blk; +} BdrvStateBlkRootContext; + +static void blk_root_set_aio_ctx_commit(void *opaque) +{ + BdrvStateBlkRootContext *s = opaque; + BlockBackend *blk = s->blk; + + blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort); +} + +static TransactionActionDrv set_blk_root_context = { + .commit = blk_root_set_aio_ctx_commit, + .clean = g_free, +}; + +static bool blk_root_change_aio_ctx(BdrvChild *child, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp) { BlockBackend *blk = child->opaque; + BdrvStateBlkRootContext *s; - if (blk->allow_aio_context_change) { - return true; + if (!blk->allow_aio_context_change) { + /* + * Manually created BlockBackends (those with a name) that are not + * attached to anything can change their AioContext without updating + * their user; return an error for others. + */ + if (!blk->name || blk->dev) { + /* TODO Add BB name/QOM path */ + error_setg(errp, "Cannot change iothread of active block backend"); + return false; + } } - /* Only manually created BlockBackends that are not attached to anything - * can change their AioContext without updating their user. */ - if (!blk->name || blk->dev) { - /* TODO Add BB name/QOM path */ - error_setg(errp, "Cannot change iothread of active block backend"); - return false; - } + s = g_new(BdrvStateBlkRootContext, 1); + *s = (BdrvStateBlkRootContext) { + .new_ctx = ctx, + .blk = blk, + }; + tran_add(tran, &set_blk_root_context, s); return true; } -static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx, - GSList **ignore) -{ - BlockBackend *blk = child->opaque; - blk_do_set_aio_context(blk, ctx, false, &error_abort); -} - void blk_add_aio_context_notifier(BlockBackend *blk, void (*attached_aio_context)(AioContext *new_context, void *opaque), void (*detach_aio_context)(void *opaque), void *opaque) @@ -2347,17 +2356,18 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, flags | BDRV_REQ_ZERO_WRITE); } -int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, - int64_t bytes) +int coroutine_fn blk_co_pwrite_compressed(BlockBackend *blk, int64_t offset, + int64_t bytes, const void *buf) { QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); IO_OR_GS_CODE(); - return blk_pwritev_part(blk, offset, bytes, &qiov, 0, - BDRV_REQ_WRITE_COMPRESSED); + return blk_co_pwritev_part(blk, offset, bytes, &qiov, 0, + BDRV_REQ_WRITE_COMPRESSED); } -int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, - PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) +int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact, + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp) { IO_OR_GS_CODE(); if (!blk_is_available(blk)) { @@ -2365,7 +2375,7 @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, return -ENOMEDIUM; } - return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp); + return bdrv_co_truncate(blk->root, offset, exact, prealloc, flags, errp); } int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, @@ -2567,7 +2577,7 @@ static bool blk_root_drained_poll(BdrvChild *child) return busy || !!blk->in_flight; } -static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) +static void blk_root_drained_end(BdrvChild *child) { BlockBackend *blk = child->opaque; assert(blk->quiesce_counter); @@ -2585,16 +2595,27 @@ static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) } } -void blk_register_buf(BlockBackend *blk, void *host, size_t size) +bool blk_register_buf(BlockBackend *blk, void *host, size_t size, Error **errp) { + BlockDriverState *bs = blk_bs(blk); + GLOBAL_STATE_CODE(); - bdrv_register_buf(blk_bs(blk), host, size); + + if (bs) { + return bdrv_register_buf(bs, host, size, errp); + } + return true; } -void blk_unregister_buf(BlockBackend *blk, void *host) +void blk_unregister_buf(BlockBackend *blk, void *host, size_t size) { + BlockDriverState *bs = blk_bs(blk); + GLOBAL_STATE_CODE(); - bdrv_unregister_buf(blk_bs(blk), host); + + if (bs) { + bdrv_unregister_buf(bs, host, size); + } } int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, diff --git a/block/block-copy.c b/block/block-copy.c index ec46775ea5c0..5e59d6262fbb 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -577,8 +577,9 @@ static coroutine_fn int block_copy_task_entry(AioTask *task) return ret; } -static int block_copy_block_status(BlockCopyState *s, int64_t offset, - int64_t bytes, int64_t *pnum) +static coroutine_fn int block_copy_block_status(BlockCopyState *s, + int64_t offset, + int64_t bytes, int64_t *pnum) { int64_t num; BlockDriverState *base; @@ -590,8 +591,8 @@ static int block_copy_block_status(BlockCopyState *s, int64_t offset, base = NULL; } - ret = bdrv_block_status_above(s->source->bs, base, offset, bytes, &num, - NULL, NULL); + ret = bdrv_co_block_status_above(s->source->bs, base, offset, bytes, &num, + NULL, NULL); if (ret < 0 || num < s->cluster_size) { /* * On error or if failed to obtain large enough chunk just fallback to @@ -613,8 +614,9 @@ static int block_copy_block_status(BlockCopyState *s, int64_t offset, * Check if the cluster starting at offset is allocated or not. * return via pnum the number of contiguous clusters sharing this allocation. */ -static int block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset, - int64_t *pnum) +static int coroutine_fn block_copy_is_cluster_allocated(BlockCopyState *s, + int64_t offset, + int64_t *pnum) { BlockDriverState *bs = s->source->bs; int64_t count, total_count = 0; @@ -624,7 +626,7 @@ static int block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset, assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); while (true) { - ret = bdrv_is_allocated(bs, offset, bytes, &count); + ret = bdrv_co_is_allocated(bs, offset, bytes, &count); if (ret < 0) { return ret; } @@ -669,8 +671,9 @@ void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes) * @return 0 when the cluster at @offset was unallocated, * 1 otherwise, and -ret on error. */ -int64_t block_copy_reset_unallocated(BlockCopyState *s, - int64_t offset, int64_t *count) +int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s, + int64_t offset, + int64_t *count) { int ret; int64_t clusters, bytes; @@ -883,23 +886,42 @@ static int coroutine_fn block_copy_common(BlockCopyCallState *call_state) return ret; } +static void coroutine_fn block_copy_async_co_entry(void *opaque) +{ + block_copy_common(opaque); +} + int coroutine_fn block_copy(BlockCopyState *s, int64_t start, int64_t bytes, - bool ignore_ratelimit) + bool ignore_ratelimit, uint64_t timeout_ns, + BlockCopyAsyncCallbackFunc cb, + void *cb_opaque) { - BlockCopyCallState call_state = { + int ret; + BlockCopyCallState *call_state = g_new(BlockCopyCallState, 1); + + *call_state = (BlockCopyCallState) { .s = s, .offset = start, .bytes = bytes, .ignore_ratelimit = ignore_ratelimit, .max_workers = BLOCK_COPY_MAX_WORKERS, + .cb = cb, + .cb_opaque = cb_opaque, }; - return block_copy_common(&call_state); -} + ret = qemu_co_timeout(block_copy_async_co_entry, call_state, timeout_ns, + g_free); + if (ret < 0) { + assert(ret == -ETIMEDOUT); + block_copy_call_cancel(call_state); + /* call_state will be freed by running coroutine. */ + return ret; + } -static void coroutine_fn block_copy_async_co_entry(void *opaque) -{ - block_copy_common(opaque); + ret = call_state->ret; + g_free(call_state); + + return ret; } BlockCopyCallState *block_copy_async(BlockCopyState *s, diff --git a/block/block-gen.h b/block/block-gen.h index f80cf4897d11..89b7daaa1f39 100644 --- a/block/block-gen.h +++ b/block/block-gen.h @@ -30,20 +30,17 @@ /* Base structure for argument packing structures */ typedef struct BdrvPollCo { - BlockDriverState *bs; + AioContext *ctx; bool in_progress; - int ret; Coroutine *co; /* Keep pointer here for debugging */ } BdrvPollCo; -static inline int bdrv_poll_co(BdrvPollCo *s) +static inline void bdrv_poll_co(BdrvPollCo *s) { assert(!qemu_in_coroutine()); - bdrv_coroutine_enter(s->bs, s->co); - BDRV_POLL_WHILE(s->bs, s->in_progress); - - return s->ret; + aio_co_enter(s->ctx, s->co); + AIO_WAIT_WHILE(s->ctx, s->in_progress); } #endif /* BLOCK_BLOCK_GEN_H */ diff --git a/block/block-ram-registrar.c b/block/block-ram-registrar.c new file mode 100644 index 000000000000..25dbafa789c2 --- /dev/null +++ b/block/block-ram-registrar.c @@ -0,0 +1,58 @@ +/* + * BlockBackend RAM Registrar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "sysemu/block-backend.h" +#include "sysemu/block-ram-registrar.h" +#include "qapi/error.h" + +static void ram_block_added(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) +{ + BlockRAMRegistrar *r = container_of(n, BlockRAMRegistrar, notifier); + Error *err = NULL; + + if (!r->ok) { + return; /* don't try again if we've already failed */ + } + + if (!blk_register_buf(r->blk, host, max_size, &err)) { + error_report_err(err); + ram_block_notifier_remove(&r->notifier); + r->ok = false; + } +} + +static void ram_block_removed(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) +{ + BlockRAMRegistrar *r = container_of(n, BlockRAMRegistrar, notifier); + blk_unregister_buf(r->blk, host, max_size); +} + +void blk_ram_registrar_init(BlockRAMRegistrar *r, BlockBackend *blk) +{ + r->blk = blk; + r->notifier = (RAMBlockNotifier){ + .ram_block_added = ram_block_added, + .ram_block_removed = ram_block_removed, + + /* + * .ram_block_resized() is not necessary because we use the max_size + * value that does not change across resize. + */ + }; + r->ok = true; + + ram_block_notifier_add(&r->notifier); +} + +void blk_ram_registrar_destroy(BlockRAMRegistrar *r) +{ + if (r->ok) { + ram_block_notifier_remove(&r->notifier); + } +} diff --git a/block/bochs.c b/block/bochs.c index 4d68658087bd..e30e3908d931 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -110,13 +110,12 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } - ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)); + ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0); if (ret < 0) { return ret; } @@ -150,8 +149,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, return -ENOMEM; } - ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap, - s->catalog_size * 4); + ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_size * 4, + s->catalog_bitmap, 0); if (ret < 0) { goto fail; } @@ -224,8 +223,8 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) (s->extent_blocks + s->bitmap_blocks)); /* read in bitmap for current extent */ - ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), - &bitmap_entry, 1); + ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), 1, + &bitmap_entry, 0); if (ret < 0) { return ret; } diff --git a/block/cloop.c b/block/cloop.c index b8c6d0eccdba..3ff975a94d7b 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -71,14 +71,13 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } /* read header */ - ret = bdrv_pread(bs->file, 128, &s->block_size, 4); + ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0); if (ret < 0) { return ret; } @@ -104,7 +103,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return -EINVAL; } - ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4); + ret = bdrv_pread(bs->file, 128 + 4, 4, &s->n_blocks, 0); if (ret < 0) { return ret; } @@ -135,7 +134,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return -ENOMEM; } - ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); + ret = bdrv_pread(bs->file, 128 + 4 + 4, offsets_size, s->offsets, 0); if (ret < 0) { goto fail; } @@ -220,9 +219,9 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num) int ret; uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num]; - ret = bdrv_pread(bs->file, s->offsets[block_num], - s->compressed_block, bytes); - if (ret != bytes) { + ret = bdrv_pread(bs->file, s->offsets[block_num], bytes, + s->compressed_block, 0); + if (ret < 0) { return -1; } diff --git a/block/commit.c b/block/commit.c index 851d1c557a11..b34634176797 100644 --- a/block/commit.c +++ b/block/commit.c @@ -135,7 +135,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp) } if (base_len < len) { - ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL); + ret = blk_co_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL); if (ret) { return ret; } @@ -155,8 +155,8 @@ static int coroutine_fn commit_run(Job *job, Error **errp) break; } /* Copy if allocated above the base */ - ret = bdrv_is_allocated_above(blk_bs(s->top), s->base_overlay, true, - offset, COMMIT_BUFFER_SIZE, &n); + ret = blk_co_is_allocated_above(s->top, s->base_overlay, true, + offset, COMMIT_BUFFER_SIZE, &n); copy = (ret > 0); trace_commit_one_iteration(s, offset, n, ret); if (copy) { @@ -238,6 +238,7 @@ static BlockDriver bdrv_commit_top = { .bdrv_child_perm = bdrv_commit_top_child_perm, .is_filter = true, + .filtered_child_is_backing = true, }; void commit_start(const char *job_id, BlockDriverState *bs, @@ -527,12 +528,12 @@ int bdrv_commit(BlockDriverState *bs) goto ro_cleanup; } if (ret) { - ret = blk_pread(src, offset, buf, n); + ret = blk_pread(src, offset, n, buf, 0); if (ret < 0) { goto ro_cleanup; } - ret = blk_pwrite(backing, offset, buf, n, 0); + ret = blk_pwrite(backing, offset, n, buf, 0); if (ret < 0) { goto ro_cleanup; } diff --git a/block/copy-before-write.c b/block/copy-before-write.c index a8a06fdc09b6..70c4ba74329e 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -24,6 +24,7 @@ */ #include "qemu/osdep.h" +#include "qapi/qmp/qjson.h" #include "sysemu/block-backend.h" #include "qemu/cutils.h" @@ -40,6 +41,8 @@ typedef struct BDRVCopyBeforeWriteState { BlockCopyState *bcs; BdrvChild *target; + OnCbwError on_cbw_error; + uint32_t cbw_timeout_ns; /* * @lock: protects access to @access_bitmap, @done_bitmap and @@ -64,6 +67,14 @@ typedef struct BDRVCopyBeforeWriteState { * node. These areas must not be rewritten by guest. */ BlockReqList frozen_read_reqs; + + /* + * @snapshot_error is normally zero. But on first copy-before-write failure + * when @on_cbw_error == ON_CBW_ERROR_BREAK_SNAPSHOT, @snapshot_error takes + * value of this error (<0). After that all in-flight and further + * snapshot-API requests will fail with that error. + */ + int snapshot_error; } BDRVCopyBeforeWriteState; static coroutine_fn int cbw_co_preadv( @@ -73,6 +84,13 @@ static coroutine_fn int cbw_co_preadv( return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); } +static void block_copy_cb(void *opaque) +{ + BlockDriverState *bs = opaque; + + bdrv_dec_in_flight(bs); +} + /* * Do copy-before-write operation. * @@ -94,16 +112,36 @@ static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs, return 0; } + if (s->snapshot_error) { + return 0; + } + off = QEMU_ALIGN_DOWN(offset, cluster_size); end = QEMU_ALIGN_UP(offset + bytes, cluster_size); - ret = block_copy(s->bcs, off, end - off, true); - if (ret < 0) { + /* + * Increase in_flight, so that in case of timed-out block-copy, the + * remaining background block_copy() request (which can't be immediately + * cancelled by timeout) is presented in bs->in_flight. This way we are + * sure that on bs close() we'll previously wait for all timed-out but yet + * running block_copy calls. + */ + bdrv_inc_in_flight(bs); + ret = block_copy(s->bcs, off, end - off, true, s->cbw_timeout_ns, + block_copy_cb, bs); + if (ret < 0 && s->on_cbw_error == ON_CBW_ERROR_BREAK_GUEST_WRITE) { return ret; } WITH_QEMU_LOCK_GUARD(&s->lock) { - bdrv_set_dirty_bitmap(s->done_bitmap, off, end - off); + if (ret < 0) { + assert(s->on_cbw_error == ON_CBW_ERROR_BREAK_SNAPSHOT); + if (!s->snapshot_error) { + s->snapshot_error = ret; + } + } else { + bdrv_set_dirty_bitmap(s->done_bitmap, off, end - off); + } reqlist_wait_all(&s->frozen_read_reqs, off, end - off, &s->lock); } @@ -165,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); @@ -175,6 +213,11 @@ static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, QEMU_LOCK_GUARD(&s->lock); + if (s->snapshot_error) { + g_free(req); + return NULL; + } + if (bdrv_dirty_bitmap_next_zero(s->access_bitmap, offset, bytes) != -1) { g_free(req); return NULL; @@ -197,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; @@ -328,46 +372,36 @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, } } -static bool cbw_parse_bitmap_option(QDict *options, BdrvDirtyBitmap **bitmap, - Error **errp) +static BlockdevOptions *cbw_parse_options(QDict *options, Error **errp) { - QDict *bitmap_qdict = NULL; - BlockDirtyBitmap *bmp_param = NULL; + BlockdevOptions *opts = NULL; Visitor *v = NULL; - bool ret = false; - *bitmap = NULL; + qdict_put_str(options, "driver", "copy-before-write"); - qdict_extract_subqdict(options, &bitmap_qdict, "bitmap."); - if (!qdict_size(bitmap_qdict)) { - ret = true; - goto out; - } - - v = qobject_input_visitor_new_flat_confused(bitmap_qdict, errp); + v = qobject_input_visitor_new_flat_confused(options, errp); if (!v) { goto out; } - visit_type_BlockDirtyBitmap(v, NULL, &bmp_param, errp); - if (!bmp_param) { + visit_type_BlockdevOptions(v, NULL, &opts, errp); + if (!opts) { goto out; } - *bitmap = block_dirty_bitmap_lookup(bmp_param->node, bmp_param->name, NULL, - errp); - if (!*bitmap) { - goto out; - } - - ret = true; + /* + * Delete options which we are going to parse through BlockdevOptions + * object for original options. + */ + qdict_extract_subqdict(options, NULL, "bitmap"); + qdict_del(options, "on-cbw-error"); + qdict_del(options, "cbw-timeout"); out: - qapi_free_BlockDirtyBitmap(bmp_param); visit_free(v); - qobject_unref(bitmap_qdict); + qdict_del(options, "driver"); - return ret; + return opts; } static int cbw_open(BlockDriverState *bs, QDict *options, int flags, @@ -376,13 +410,21 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags, BDRVCopyBeforeWriteState *s = bs->opaque; BdrvDirtyBitmap *bitmap = NULL; int64_t cluster_size; + g_autoptr(BlockdevOptions) full_opts = NULL; + BlockdevOptionsCbw *opts; + int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { + full_opts = cbw_parse_options(options, errp); + if (!full_opts) { return -EINVAL; } + assert(full_opts->driver == BLOCKDEV_DRIVER_COPY_BEFORE_WRITE); + opts = &full_opts->u.copy_before_write; + + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; + } s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds, BDRV_CHILD_DATA, false, errp); @@ -390,9 +432,17 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags, return -EINVAL; } - if (!cbw_parse_bitmap_option(options, &bitmap, errp)) { - return -EINVAL; + if (opts->bitmap) { + bitmap = block_dirty_bitmap_lookup(opts->bitmap->node, + opts->bitmap->name, NULL, errp); + if (!bitmap) { + return -EINVAL; + } } + s->on_cbw_error = opts->has_on_cbw_error ? opts->on_cbw_error : + ON_CBW_ERROR_BREAK_GUEST_WRITE; + s->cbw_timeout_ns = opts->has_cbw_timeout ? + opts->cbw_timeout * NANOSECONDS_PER_SECOND : 0; bs->total_sectors = bs->file->bs->total_sectors; bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | @@ -472,7 +522,6 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source, BlockCopyState **bcs, Error **errp) { - ERRP_GUARD(); BDRVCopyBeforeWriteState *state; BlockDriverState *top; QDict *opts; diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 1fc7fb3333b1..815ac1d8356c 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -41,12 +41,11 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, BDRVStateCOR *state = bs->opaque; /* Find a bottom node name, if any */ const char *bottom_node = qdict_get_try_str(options, "bottom"); + int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } bs->supported_read_flags = BDRV_REQ_PREFETCH; diff --git a/block/copy-on-read.h b/block/copy-on-read.h index 7bf405dccd1f..1d8ad38c745f 100644 --- a/block/copy-on-read.h +++ b/block/copy-on-read.h @@ -22,11 +22,11 @@ * along with this program. If not, see . */ -#ifndef BLOCK_COPY_ON_READ -#define BLOCK_COPY_ON_READ +#ifndef BLOCK_COPY_ON_READ_H +#define BLOCK_COPY_ON_READ_H #include "block/block_int.h" void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs); -#endif /* BLOCK_COPY_ON_READ */ +#endif /* BLOCK_COPY_ON_READ_H */ diff --git a/block/coroutines.h b/block/coroutines.h index b293e943c87f..2a1e0b3c9d52 100644 --- a/block/coroutines.h +++ b/block/coroutines.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef BLOCK_COROUTINES_INT_H -#define BLOCK_COROUTINES_INT_H +#ifndef BLOCK_COROUTINES_H +#define BLOCK_COROUTINES_H #include "block/block_int.h" @@ -37,9 +37,11 @@ * the I/O API. */ -int coroutine_fn bdrv_co_check(BlockDriverState *bs, - BdrvCheckResult *res, BdrvCheckMode fix); -int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); + +int coroutine_fn GRAPH_RDLOCK +bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp); int coroutine_fn bdrv_co_common_block_status_above(BlockDriverState *bs, @@ -53,32 +55,15 @@ bdrv_co_common_block_status_above(BlockDriverState *bs, BlockDriverState **file, int *depth); -int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs, - QEMUIOVector *qiov, int64_t pos); -int coroutine_fn bdrv_co_writev_vmstate(BlockDriverState *bs, - QEMUIOVector *qiov, int64_t pos); - -int coroutine_fn -nbd_co_do_establish_connection(BlockDriverState *bs, Error **errp); - - -int coroutine_fn -blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, - QEMUIOVector *qiov, BdrvRequestFlags flags); - - -int coroutine_fn -blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, - QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); -int coroutine_fn -blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); int coroutine_fn -blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); - -int coroutine_fn blk_co_do_flush(BlockBackend *blk); +nbd_co_do_establish_connection(BlockDriverState *bs, bool blocking, + Error **errp); /* @@ -89,15 +74,7 @@ int coroutine_fn blk_co_do_flush(BlockBackend *blk); * the "I/O or GS" API. */ -int generated_co_wrapper -bdrv_preadv(BdrvChild *child, int64_t offset, unsigned int bytes, - QEMUIOVector *qiov, BdrvRequestFlags flags); - -int generated_co_wrapper -bdrv_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes, - QEMUIOVector *qiov, BdrvRequestFlags flags); - -int generated_co_wrapper +int co_wrapper_mixed_bdrv_rdlock bdrv_common_block_status_above(BlockDriverState *bs, BlockDriverState *base, bool include_base, @@ -108,24 +85,7 @@ bdrv_common_block_status_above(BlockDriverState *bs, int64_t *map, BlockDriverState **file, int *depth); -int generated_co_wrapper -nbd_do_establish_connection(BlockDriverState *bs, Error **errp); - -int generated_co_wrapper -blk_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, - QEMUIOVector *qiov, BdrvRequestFlags flags); - -int generated_co_wrapper -blk_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, - QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags); - -int generated_co_wrapper -blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf); - -int generated_co_wrapper -blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); - -int generated_co_wrapper blk_do_flush(BlockBackend *blk); +int co_wrapper_mixed +nbd_do_establish_connection(BlockDriverState *bs, bool blocking, Error **errp); -#endif /* BLOCK_COROUTINES_INT_H */ +#endif /* BLOCK_COROUTINES_H */ diff --git a/block/crypto.c b/block/crypto.c index 1ba82984efe0..bbeb9f437c14 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -55,40 +55,40 @@ static int block_crypto_probe_generic(QCryptoBlockFormat format, } -static ssize_t block_crypto_read_func(QCryptoBlock *block, - size_t offset, - uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp) +static int block_crypto_read_func(QCryptoBlock *block, + size_t offset, + uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) { BlockDriverState *bs = opaque; ssize_t ret; - ret = bdrv_pread(bs->file, offset, buf, buflen); + ret = bdrv_pread(bs->file, offset, buflen, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read encryption header"); return ret; } - return ret; + return 0; } -static ssize_t block_crypto_write_func(QCryptoBlock *block, - size_t offset, - const uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp) +static int block_crypto_write_func(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) { BlockDriverState *bs = opaque; ssize_t ret; - ret = bdrv_pwrite(bs->file, offset, buf, buflen); + ret = bdrv_pwrite(bs->file, offset, buflen, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write encryption header"); return ret; } - return ret; + return 0; } @@ -99,28 +99,28 @@ struct BlockCryptoCreateData { }; -static ssize_t block_crypto_create_write_func(QCryptoBlock *block, - size_t offset, - const uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp) +static int block_crypto_create_write_func(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) { struct BlockCryptoCreateData *data = opaque; ssize_t ret; - ret = blk_pwrite(data->blk, offset, buf, buflen, 0); + ret = blk_pwrite(data->blk, offset, buflen, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write encryption header"); return ret; } - return ret; + return 0; } -static ssize_t block_crypto_create_init_func(QCryptoBlock *block, - size_t headerlen, - void *opaque, - Error **errp) +static int block_crypto_create_init_func(QCryptoBlock *block, + size_t headerlen, + void *opaque, + Error **errp) { struct BlockCryptoCreateData *data = opaque; Error *local_error = NULL; @@ -139,7 +139,7 @@ static ssize_t block_crypto_create_init_func(QCryptoBlock *block, data->prealloc, 0, &local_error); if (ret >= 0) { - return ret; + return 0; } error: @@ -261,15 +261,14 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, { BlockCrypto *crypto = bs->opaque; QemuOpts *opts = NULL; - int ret = -EINVAL; + int ret; QCryptoBlockOpenOptions *open_opts = NULL; unsigned int cflags = 0; QDict *cryptoopts = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } bs->supported_write_flags = BDRV_REQ_FUA & @@ -277,6 +276,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort); if (!qemu_opts_absorb_qdict(opts, options, errp)) { + ret = -EINVAL; goto cleanup; } @@ -285,6 +285,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, open_opts = block_crypto_open_opts_init(cryptoopts, errp); if (!open_opts) { + ret = -EINVAL; goto cleanup; } @@ -410,7 +411,6 @@ block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); - assert(!flags); assert(payload_offset < INT64_MAX); assert(QEMU_IS_ALIGNED(offset, sector_size)); assert(QEMU_IS_ALIGNED(bytes, sector_size)); @@ -473,7 +473,8 @@ block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block); uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); - assert(!(flags & ~BDRV_REQ_FUA)); + flags &= ~BDRV_REQ_REGISTERED_BUF; + assert(payload_offset < INT64_MAX); assert(QEMU_IS_ALIGNED(offset, sector_size)); assert(QEMU_IS_ALIGNED(bytes, sector_size)); @@ -702,7 +703,7 @@ static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv, } /* Create protocol layer */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto fail; } diff --git a/block/curl.c b/block/curl.c index 1e0f60957979..cba4c4cac768 100644 --- a/block/curl.c +++ b/block/curl.c @@ -855,7 +855,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, 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/dirty-bitmap.c b/block/dirty-bitmap.c index da1b91166f48..956feeb2aeed 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -309,10 +309,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BdrvDirtyBitmap *parent, return NULL; } - if (!hbitmap_merge(parent->bitmap, successor->bitmap, parent->bitmap)) { - error_setg(errp, "Merging of parent and successor bitmap failed"); - return NULL; - } + hbitmap_merge(parent->bitmap, successor->bitmap, parent->bitmap); parent->disabled = successor->disabled; parent->busy = false; @@ -391,7 +388,7 @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) * not fail. * This function doesn't release corresponding BdrvDirtyBitmap. */ -static int coroutine_fn +int coroutine_fn bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, Error **errp) { @@ -402,45 +399,6 @@ bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, return 0; } -typedef struct BdrvRemovePersistentDirtyBitmapCo { - BlockDriverState *bs; - const char *name; - Error **errp; - int ret; -} BdrvRemovePersistentDirtyBitmapCo; - -static void coroutine_fn -bdrv_co_remove_persistent_dirty_bitmap_entry(void *opaque) -{ - BdrvRemovePersistentDirtyBitmapCo *s = opaque; - - s->ret = bdrv_co_remove_persistent_dirty_bitmap(s->bs, s->name, s->errp); - aio_wait_kick(); -} - -int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, - Error **errp) -{ - if (qemu_in_coroutine()) { - return bdrv_co_remove_persistent_dirty_bitmap(bs, name, errp); - } else { - Coroutine *co; - BdrvRemovePersistentDirtyBitmapCo s = { - .bs = bs, - .name = name, - .errp = errp, - .ret = -EINPROGRESS, - }; - - co = qemu_coroutine_create(bdrv_co_remove_persistent_dirty_bitmap_entry, - &s); - bdrv_coroutine_enter(bs, co); - BDRV_POLL_WHILE(bs, s.ret == -EINPROGRESS); - - return s.ret; - } -} - bool bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs) { @@ -450,7 +408,7 @@ bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs) return false; } -static bool coroutine_fn +bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, uint32_t granularity, Error **errp) { @@ -473,51 +431,6 @@ bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, return drv->bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp); } -typedef struct BdrvCanStoreNewDirtyBitmapCo { - BlockDriverState *bs; - const char *name; - uint32_t granularity; - Error **errp; - bool ret; - - bool in_progress; -} BdrvCanStoreNewDirtyBitmapCo; - -static void coroutine_fn bdrv_co_can_store_new_dirty_bitmap_entry(void *opaque) -{ - BdrvCanStoreNewDirtyBitmapCo *s = opaque; - - s->ret = bdrv_co_can_store_new_dirty_bitmap(s->bs, s->name, s->granularity, - s->errp); - s->in_progress = false; - aio_wait_kick(); -} - -bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, - uint32_t granularity, Error **errp) -{ - IO_CODE(); - if (qemu_in_coroutine()) { - return bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp); - } else { - Coroutine *co; - BdrvCanStoreNewDirtyBitmapCo s = { - .bs = bs, - .name = name, - .granularity = granularity, - .errp = errp, - .in_progress = true, - }; - - co = qemu_coroutine_create(bdrv_co_can_store_new_dirty_bitmap_entry, - &s); - bdrv_coroutine_enter(bs, co); - BDRV_POLL_WHILE(bs, s.in_progress); - - return s.ret; - } -} - void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) { bdrv_dirty_bitmaps_lock(bitmap->bs); @@ -544,7 +457,6 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) info->count = bdrv_get_dirty_count(bm); info->granularity = bdrv_dirty_bitmap_granularity(bm); - info->has_name = !!bm->name; info->name = g_strdup(bm->name); info->recording = bdrv_dirty_bitmap_recording(bm); info->busy = bdrv_dirty_bitmap_busy(bm); @@ -912,13 +824,15 @@ bool bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, goto out; } - if (!hbitmap_can_merge(dest->bitmap, src->bitmap)) { - error_setg(errp, "Bitmaps are incompatible and can't be merged"); + if (bdrv_dirty_bitmap_size(src) != bdrv_dirty_bitmap_size(dest)) { + error_setg(errp, "Bitmaps are of different sizes (destination size is %" + PRId64 ", source size is %" PRId64 ") and can't be merged", + bdrv_dirty_bitmap_size(dest), bdrv_dirty_bitmap_size(src)); goto out; } - ret = bdrv_dirty_bitmap_merge_internal(dest, src, backup, false); - assert(ret); + bdrv_dirty_bitmap_merge_internal(dest, src, backup, false); + ret = true; out: bdrv_dirty_bitmaps_unlock(dest->bs); @@ -932,17 +846,16 @@ bool bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, /** * bdrv_dirty_bitmap_merge_internal: merge src into dest. * Does NOT check bitmap permissions; not suitable for use as public API. + * @dest, @src and @backup (if not NULL) must have same size. * * @backup: If provided, make a copy of dest here prior to merge. * @lock: If true, lock and unlock bitmaps on the way in/out. - * returns true if the merge succeeded; false if unattempted. */ -bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, +void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, HBitmap **backup, bool lock) { - bool ret; IO_CODE(); assert(!bdrv_dirty_bitmap_readonly(dest)); @@ -959,9 +872,9 @@ bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, if (backup) { *backup = dest->bitmap; dest->bitmap = hbitmap_alloc(dest->size, hbitmap_granularity(*backup)); - ret = hbitmap_merge(*backup, src->bitmap, dest->bitmap); + hbitmap_merge(*backup, src->bitmap, dest->bitmap); } else { - ret = hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap); + hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap); } if (lock) { @@ -970,6 +883,4 @@ bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, bdrv_dirty_bitmaps_unlock(src->bs); } } - - return ret; } diff --git a/block/dmg.c b/block/dmg.c index c626587f9c50..675e840ca587 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -77,7 +77,7 @@ static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result) uint64_t buffer; int ret; - ret = bdrv_pread(bs->file, offset, &buffer, 8); + ret = bdrv_pread(bs->file, offset, 8, &buffer, 0); if (ret < 0) { return ret; } @@ -91,7 +91,7 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result) uint32_t buffer; int ret; - ret = bdrv_pread(bs->file, offset, &buffer, 4); + ret = bdrv_pread(bs->file, offset, 4, &buffer, 0); if (ret < 0) { return ret; } @@ -172,7 +172,7 @@ static int64_t dmg_find_koly_offset(BdrvChild *file, Error **errp) offset = length - 511 - 512; } length = length < 515 ? length : 515; - ret = bdrv_pread(file, offset, buffer, length); + ret = bdrv_pread(file, offset, length, buffer, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed while reading UDIF trailer"); return ret; @@ -254,6 +254,25 @@ static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds, for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) { s->types[i] = buff_read_uint32(buffer, offset); if (!dmg_is_known_block_type(s->types[i])) { + switch (s->types[i]) { + case UDBZ: + warn_report_once("dmg-bzip2 module is missing, accessing bzip2 " + "compressed blocks will result in I/O errors"); + break; + case ULFO: + warn_report_once("dmg-lzfse module is missing, accessing lzfse " + "compressed blocks will result in I/O errors"); + break; + case UDCM: + case UDLE: + /* Comments and last entry can be ignored without problems */ + break; + default: + warn_report_once("Image contains chunks of unknown type %x, " + "accessing them will result in I/O errors", + s->types[i]); + break; + } chunk_count--; i--; offset += 40; @@ -352,7 +371,7 @@ static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds, offset += 4; buffer = g_realloc(buffer, count); - ret = bdrv_pread(bs->file, offset, buffer, count); + ret = bdrv_pread(bs->file, offset, count, buffer, 0); if (ret < 0) { goto fail; } @@ -389,8 +408,8 @@ static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds, buffer = g_malloc(info_length + 1); buffer[info_length] = '\0'; - ret = bdrv_pread(bs->file, info_begin, buffer, info_length); - if (ret != info_length) { + ret = bdrv_pread(bs->file, info_begin, info_length, buffer, 0); + if (ret < 0) { ret = -EINVAL; goto fail; } @@ -440,14 +459,21 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; + } + /* + * NB: if uncompress submodules are absent, + * ie block_module_load return value == 0, the function pointers + * dmg_uncompress_bz2 and dmg_uncompress_lzfse will be NULL. + */ + if (block_module_load("dmg-bz2", errp) < 0) { + return -EINVAL; + } + if (block_module_load("dmg-lzfse", errp) < 0) { return -EINVAL; } - - block_module_load_one("dmg-bz2"); - block_module_load_one("dmg-lzfse"); s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; @@ -609,9 +635,9 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) case UDZO: { /* zlib compressed */ /* we need to buffer, because only the chunk as whole can be * inflated. */ - ret = bdrv_pread(bs->file, s->offsets[chunk], - s->compressed_chunk, s->lengths[chunk]); - if (ret != s->lengths[chunk]) { + ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk], + s->compressed_chunk, 0); + if (ret < 0) { return -1; } @@ -635,9 +661,9 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) } /* we need to buffer, because only the chunk as whole can be * inflated. */ - ret = bdrv_pread(bs->file, s->offsets[chunk], - s->compressed_chunk, s->lengths[chunk]); - if (ret != s->lengths[chunk]) { + ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk], + s->compressed_chunk, 0); + if (ret < 0) { return -1; } @@ -656,9 +682,9 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) } /* we need to buffer, because only the chunk as whole can be * inflated. */ - ret = bdrv_pread(bs->file, s->offsets[chunk], - s->compressed_chunk, s->lengths[chunk]); - if (ret != s->lengths[chunk]) { + ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk], + s->compressed_chunk, 0); + if (ret < 0) { return -1; } @@ -672,9 +698,9 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) } break; case UDRW: /* copy */ - ret = bdrv_pread(bs->file, s->offsets[chunk], - s->uncompressed_chunk, s->lengths[chunk]); - if (ret != s->lengths[chunk]) { + ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk], + s->uncompressed_chunk, 0); + if (ret < 0) { return -1; } break; diff --git a/block/export/export.c b/block/export/export.c index 7253af3bc3dc..28a91c9c4235 100644 --- a/block/export/export.c +++ b/block/export/export.c @@ -26,6 +26,9 @@ #ifdef CONFIG_VHOST_USER_BLK_SERVER #include "vhost-user-blk-server.h" #endif +#ifdef CONFIG_VDUSE_BLK_EXPORT +#include "vduse-blk.h" +#endif static const BlockExportDriver *blk_exp_drivers[] = { &blk_exp_nbd, @@ -35,6 +38,9 @@ static const BlockExportDriver *blk_exp_drivers[] = { #ifdef CONFIG_FUSE &blk_exp_fuse, #endif +#ifdef CONFIG_VDUSE_BLK_EXPORT + &blk_exp_vduse_blk, +#endif }; /* Only accessed from the main thread */ @@ -108,7 +114,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - if (export->has_iothread) { + if (export->iothread) { IOThread *iothread; AioContext *new_ctx; Error **set_context_errp; @@ -123,7 +129,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) /* Ignore errors with fixed-iothread=false */ set_context_errp = fixed_iothread ? errp : NULL; - ret = bdrv_try_set_aio_context(bs, new_ctx, set_context_errp); + ret = bdrv_try_change_aio_context(bs, new_ctx, NULL, set_context_errp); if (ret == 0) { aio_context_release(ctx); aio_context_acquire(new_ctx); diff --git a/block/export/fuse.c b/block/export/fuse.c index e80b24a86715..1b26ddfcf3c1 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -554,7 +554,7 @@ static void fuse_read(fuse_req_t req, fuse_ino_t inode, return; } - ret = blk_pread(exp->common.blk, offset, buf, size); + ret = blk_pread(exp->common.blk, offset, size, buf, 0); if (ret >= 0) { fuse_reply_buf(req, buf, size); } else { @@ -607,7 +607,7 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf, } } - ret = blk_pwrite(exp->common.blk, offset, buf, size, 0); + ret = blk_pwrite(exp->common.blk, offset, size, buf, 0); if (ret >= 0) { fuse_reply_write(req, size); } else { diff --git a/block/export/meson.build b/block/export/meson.build index 0a08e384c741..c60116f455af 100644 --- a/block/export/meson.build +++ b/block/export/meson.build @@ -1,7 +1,12 @@ blockdev_ss.add(files('export.c')) if have_vhost_user_blk_server - blockdev_ss.add(files('vhost-user-blk-server.c')) + blockdev_ss.add(files('vhost-user-blk-server.c', 'virtio-blk-handler.c')) endif blockdev_ss.add(when: fuse, if_true: files('fuse.c')) + +if have_vduse_blk_export + blockdev_ss.add(files('vduse-blk.c', 'virtio-blk-handler.c')) + blockdev_ss.add(libvduse) +endif diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c new file mode 100644 index 000000000000..350d6fdaf061 --- /dev/null +++ b/block/export/vduse-blk.c @@ -0,0 +1,373 @@ +/* + * Export QEMU block device via VDUSE + * + * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved. + * + * Author: + * Xie Yongji + * + * 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 + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "block/export.h" +#include "qemu/error-report.h" +#include "util/block-helpers.h" +#include "subprojects/libvduse/libvduse.h" +#include "virtio-blk-handler.h" + +#include "standard-headers/linux/virtio_blk.h" + +#define VDUSE_DEFAULT_NUM_QUEUE 1 +#define VDUSE_DEFAULT_QUEUE_SIZE 256 + +typedef struct VduseBlkExport { + BlockExport export; + VirtioBlkHandler handler; + VduseDev *dev; + uint16_t num_queues; + char *recon_file; + unsigned int inflight; +} VduseBlkExport; + +typedef struct VduseBlkReq { + VduseVirtqElement elem; + VduseVirtq *vq; +} VduseBlkReq; + +static void vduse_blk_inflight_inc(VduseBlkExport *vblk_exp) +{ + vblk_exp->inflight++; +} + +static void vduse_blk_inflight_dec(VduseBlkExport *vblk_exp) +{ + if (--vblk_exp->inflight == 0) { + aio_wait_kick(); + } +} + +static void vduse_blk_req_complete(VduseBlkReq *req, size_t in_len) +{ + vduse_queue_push(req->vq, &req->elem, in_len); + vduse_queue_notify(req->vq); + + free(req); +} + +static void coroutine_fn vduse_blk_virtio_process_req(void *opaque) +{ + VduseBlkReq *req = opaque; + VduseVirtq *vq = req->vq; + VduseDev *dev = vduse_queue_get_dev(vq); + VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev); + VirtioBlkHandler *handler = &vblk_exp->handler; + VduseVirtqElement *elem = &req->elem; + struct iovec *in_iov = elem->in_sg; + struct iovec *out_iov = elem->out_sg; + unsigned in_num = elem->in_num; + unsigned out_num = elem->out_num; + int in_len; + + in_len = virtio_blk_process_req(handler, in_iov, + out_iov, in_num, out_num); + if (in_len < 0) { + free(req); + return; + } + + vduse_blk_req_complete(req, in_len); + vduse_blk_inflight_dec(vblk_exp); +} + +static void vduse_blk_vq_handler(VduseDev *dev, VduseVirtq *vq) +{ + VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev); + + while (1) { + VduseBlkReq *req; + + req = vduse_queue_pop(vq, sizeof(VduseBlkReq)); + if (!req) { + break; + } + req->vq = vq; + + Coroutine *co = + qemu_coroutine_create(vduse_blk_virtio_process_req, req); + + vduse_blk_inflight_inc(vblk_exp); + qemu_coroutine_enter(co); + } +} + +static void on_vduse_vq_kick(void *opaque) +{ + VduseVirtq *vq = opaque; + VduseDev *dev = vduse_queue_get_dev(vq); + int fd = vduse_queue_get_fd(vq); + eventfd_t kick_data; + + if (eventfd_read(fd, &kick_data) == -1) { + error_report("failed to read data from eventfd"); + return; + } + + vduse_blk_vq_handler(dev, vq); +} + +static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq) +{ + VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev); + + aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq), + true, on_vduse_vq_kick, NULL, NULL, NULL, vq); + /* Make sure we don't miss any kick afer reconnecting */ + eventfd_write(vduse_queue_get_fd(vq), 1); +} + +static void vduse_blk_disable_queue(VduseDev *dev, VduseVirtq *vq) +{ + VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev); + + aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq), + true, NULL, NULL, NULL, NULL, NULL); +} + +static const VduseOps vduse_blk_ops = { + .enable_queue = vduse_blk_enable_queue, + .disable_queue = vduse_blk_disable_queue, +}; + +static void on_vduse_dev_kick(void *opaque) +{ + VduseDev *dev = opaque; + + vduse_dev_handler(dev); +} + +static void vduse_blk_attach_ctx(VduseBlkExport *vblk_exp, AioContext *ctx) +{ + int i; + + aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev), + true, on_vduse_dev_kick, NULL, NULL, NULL, + vblk_exp->dev); + + for (i = 0; i < vblk_exp->num_queues; i++) { + VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i); + int fd = vduse_queue_get_fd(vq); + + if (fd < 0) { + continue; + } + aio_set_fd_handler(vblk_exp->export.ctx, fd, true, + on_vduse_vq_kick, NULL, NULL, NULL, vq); + } +} + +static void vduse_blk_detach_ctx(VduseBlkExport *vblk_exp) +{ + int i; + + for (i = 0; i < vblk_exp->num_queues; i++) { + VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i); + int fd = vduse_queue_get_fd(vq); + + if (fd < 0) { + continue; + } + aio_set_fd_handler(vblk_exp->export.ctx, fd, + true, NULL, NULL, NULL, NULL, NULL); + } + aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev), + true, NULL, NULL, NULL, NULL, NULL); + + AIO_WAIT_WHILE(vblk_exp->export.ctx, vblk_exp->inflight > 0); +} + + +static void blk_aio_attached(AioContext *ctx, void *opaque) +{ + VduseBlkExport *vblk_exp = opaque; + + vblk_exp->export.ctx = ctx; + vduse_blk_attach_ctx(vblk_exp, ctx); +} + +static void blk_aio_detach(void *opaque) +{ + VduseBlkExport *vblk_exp = opaque; + + vduse_blk_detach_ctx(vblk_exp); + vblk_exp->export.ctx = NULL; +} + +static void vduse_blk_resize(void *opaque) +{ + BlockExport *exp = opaque; + VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export); + struct virtio_blk_config config; + + config.capacity = + cpu_to_le64(blk_getlength(exp->blk) >> VIRTIO_BLK_SECTOR_BITS); + vduse_dev_update_config(vblk_exp->dev, sizeof(config.capacity), + offsetof(struct virtio_blk_config, capacity), + (char *)&config.capacity); +} + +static const BlockDevOps vduse_block_ops = { + .resize_cb = vduse_blk_resize, +}; + +static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts, + Error **errp) +{ + VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export); + BlockExportOptionsVduseBlk *vblk_opts = &opts->u.vduse_blk; + uint64_t logical_block_size = VIRTIO_BLK_SECTOR_SIZE; + uint16_t num_queues = VDUSE_DEFAULT_NUM_QUEUE; + uint16_t queue_size = VDUSE_DEFAULT_QUEUE_SIZE; + Error *local_err = NULL; + struct virtio_blk_config config = { 0 }; + uint64_t features; + int i, ret; + + if (vblk_opts->has_num_queues) { + num_queues = vblk_opts->num_queues; + if (num_queues == 0) { + error_setg(errp, "num-queues must be greater than 0"); + return -EINVAL; + } + } + + if (vblk_opts->has_queue_size) { + queue_size = vblk_opts->queue_size; + if (queue_size <= 2 || !is_power_of_2(queue_size) || + queue_size > VIRTQUEUE_MAX_SIZE) { + error_setg(errp, "queue-size is invalid"); + return -EINVAL; + } + } + + if (vblk_opts->has_logical_block_size) { + logical_block_size = vblk_opts->logical_block_size; + check_block_size(exp->id, "logical-block-size", logical_block_size, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -EINVAL; + } + } + vblk_exp->num_queues = num_queues; + vblk_exp->handler.blk = exp->blk; + vblk_exp->handler.serial = g_strdup(vblk_opts->serial ?: ""); + vblk_exp->handler.logical_block_size = logical_block_size; + vblk_exp->handler.writable = opts->writable; + + config.capacity = + cpu_to_le64(blk_getlength(exp->blk) >> VIRTIO_BLK_SECTOR_BITS); + config.seg_max = cpu_to_le32(queue_size - 2); + config.min_io_size = cpu_to_le16(1); + config.opt_io_size = cpu_to_le32(1); + config.num_queues = cpu_to_le16(num_queues); + config.blk_size = cpu_to_le32(logical_block_size); + config.max_discard_sectors = cpu_to_le32(VIRTIO_BLK_MAX_DISCARD_SECTORS); + config.max_discard_seg = cpu_to_le32(1); + config.discard_sector_alignment = + cpu_to_le32(logical_block_size >> VIRTIO_BLK_SECTOR_BITS); + config.max_write_zeroes_sectors = + cpu_to_le32(VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS); + config.max_write_zeroes_seg = cpu_to_le32(1); + + features = vduse_get_virtio_features() | + (1ULL << VIRTIO_BLK_F_SEG_MAX) | + (1ULL << VIRTIO_BLK_F_TOPOLOGY) | + (1ULL << VIRTIO_BLK_F_BLK_SIZE) | + (1ULL << VIRTIO_BLK_F_FLUSH) | + (1ULL << VIRTIO_BLK_F_DISCARD) | + (1ULL << VIRTIO_BLK_F_WRITE_ZEROES); + + if (num_queues > 1) { + features |= 1ULL << VIRTIO_BLK_F_MQ; + } + if (!opts->writable) { + features |= 1ULL << VIRTIO_BLK_F_RO; + } + + vblk_exp->dev = vduse_dev_create(vblk_opts->name, VIRTIO_ID_BLOCK, 0, + features, num_queues, + sizeof(struct virtio_blk_config), + (char *)&config, &vduse_blk_ops, + vblk_exp); + if (!vblk_exp->dev) { + error_setg(errp, "failed to create vduse device"); + ret = -ENOMEM; + goto err_dev; + } + + vblk_exp->recon_file = g_strdup_printf("%s/vduse-blk-%s", + g_get_tmp_dir(), vblk_opts->name); + if (vduse_set_reconnect_log_file(vblk_exp->dev, vblk_exp->recon_file)) { + error_setg(errp, "failed to set reconnect log file"); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < num_queues; i++) { + vduse_dev_setup_queue(vblk_exp->dev, i, queue_size); + } + + aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev), true, + on_vduse_dev_kick, NULL, NULL, NULL, vblk_exp->dev); + + blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach, + vblk_exp); + + blk_set_dev_ops(exp->blk, &vduse_block_ops, exp); + + return 0; +err: + vduse_dev_destroy(vblk_exp->dev); + g_free(vblk_exp->recon_file); +err_dev: + g_free(vblk_exp->handler.serial); + return ret; +} + +static void vduse_blk_exp_delete(BlockExport *exp) +{ + VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export); + int ret; + + blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach, + vblk_exp); + blk_set_dev_ops(exp->blk, NULL, NULL); + ret = vduse_dev_destroy(vblk_exp->dev); + if (ret != -EBUSY) { + unlink(vblk_exp->recon_file); + } + g_free(vblk_exp->recon_file); + g_free(vblk_exp->handler.serial); +} + +static void vduse_blk_exp_request_shutdown(BlockExport *exp) +{ + VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export); + + aio_context_acquire(vblk_exp->export.ctx); + vduse_blk_detach_ctx(vblk_exp); + aio_context_acquire(vblk_exp->export.ctx); +} + +const BlockExportDriver blk_exp_vduse_blk = { + .type = BLOCK_EXPORT_TYPE_VDUSE_BLK, + .instance_size = sizeof(VduseBlkExport), + .create = vduse_blk_exp_create, + .delete = vduse_blk_exp_delete, + .request_shutdown = vduse_blk_exp_request_shutdown, +}; diff --git a/block/export/vduse-blk.h b/block/export/vduse-blk.h new file mode 100644 index 000000000000..c4eeb1b70ec9 --- /dev/null +++ b/block/export/vduse-blk.h @@ -0,0 +1,20 @@ +/* + * Export QEMU block device via VDUSE + * + * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved. + * + * Author: + * Xie Yongji + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef VDUSE_BLK_H +#define VDUSE_BLK_H + +#include "block/export.h" + +extern const BlockExportDriver blk_exp_vduse_blk; + +#endif /* VDUSE_BLK_H */ diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c index a129204c4448..3409d9e02e68 100644 --- a/block/export/vhost-user-blk-server.c +++ b/block/export/vhost-user-blk-server.c @@ -17,31 +17,15 @@ #include "vhost-user-blk-server.h" #include "qapi/error.h" #include "qom/object_interfaces.h" -#include "sysemu/block-backend.h" #include "util/block-helpers.h" - -/* - * Sector units are 512 bytes regardless of the - * virtio_blk_config->blk_size value. - */ -#define VIRTIO_BLK_SECTOR_BITS 9 -#define VIRTIO_BLK_SECTOR_SIZE (1ull << VIRTIO_BLK_SECTOR_BITS) +#include "virtio-blk-handler.h" enum { VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1, - VHOST_USER_BLK_MAX_DISCARD_SECTORS = 32768, - VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS = 32768, -}; -struct virtio_blk_inhdr { - unsigned char status; }; typedef struct VuBlkReq { VuVirtqElement elem; - int64_t sector_num; - size_t size; - struct virtio_blk_inhdr *in; - struct virtio_blk_outhdr out; VuServer *server; struct VuVirtq *vq; } VuBlkReq; @@ -50,248 +34,44 @@ typedef struct VuBlkReq { typedef struct { BlockExport export; VuServer vu_server; - uint32_t blk_size; + VirtioBlkHandler handler; QIOChannelSocket *sioc; struct virtio_blk_config blkcfg; - bool writable; } VuBlkExport; -static void vu_blk_req_complete(VuBlkReq *req) +static void vu_blk_req_complete(VuBlkReq *req, size_t in_len) { VuDev *vu_dev = &req->server->vu_dev; - /* IO size with 1 extra status byte */ - vu_queue_push(vu_dev, req->vq, &req->elem, req->size + 1); + vu_queue_push(vu_dev, req->vq, &req->elem, in_len); vu_queue_notify(vu_dev, req->vq); free(req); } -static bool vu_blk_sect_range_ok(VuBlkExport *vexp, uint64_t sector, - size_t size) -{ - uint64_t nb_sectors; - uint64_t total_sectors; - - if (size % VIRTIO_BLK_SECTOR_SIZE) { - return false; - } - - nb_sectors = size >> VIRTIO_BLK_SECTOR_BITS; - - QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != VIRTIO_BLK_SECTOR_SIZE); - if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) { - return false; - } - if ((sector << VIRTIO_BLK_SECTOR_BITS) % vexp->blk_size) { - return false; - } - blk_get_geometry(vexp->export.blk, &total_sectors); - if (sector > total_sectors || nb_sectors > total_sectors - sector) { - return false; - } - return true; -} - -static int coroutine_fn -vu_blk_discard_write_zeroes(VuBlkExport *vexp, struct iovec *iov, - uint32_t iovcnt, uint32_t type) -{ - BlockBackend *blk = vexp->export.blk; - struct virtio_blk_discard_write_zeroes desc; - ssize_t size; - uint64_t sector; - uint32_t num_sectors; - uint32_t max_sectors; - uint32_t flags; - int bytes; - - /* Only one desc is currently supported */ - if (unlikely(iov_size(iov, iovcnt) > sizeof(desc))) { - return VIRTIO_BLK_S_UNSUPP; - } - - size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc)); - if (unlikely(size != sizeof(desc))) { - error_report("Invalid size %zd, expected %zu", size, sizeof(desc)); - return VIRTIO_BLK_S_IOERR; - } - - sector = le64_to_cpu(desc.sector); - num_sectors = le32_to_cpu(desc.num_sectors); - flags = le32_to_cpu(desc.flags); - max_sectors = (type == VIRTIO_BLK_T_WRITE_ZEROES) ? - VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS : - VHOST_USER_BLK_MAX_DISCARD_SECTORS; - - /* This check ensures that 'bytes' fits in an int */ - if (unlikely(num_sectors > max_sectors)) { - return VIRTIO_BLK_S_IOERR; - } - - bytes = num_sectors << VIRTIO_BLK_SECTOR_BITS; - - if (unlikely(!vu_blk_sect_range_ok(vexp, sector, bytes))) { - return VIRTIO_BLK_S_IOERR; - } - - /* - * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard - * and write zeroes commands if any unknown flag is set. - */ - if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { - return VIRTIO_BLK_S_UNSUPP; - } - - if (type == VIRTIO_BLK_T_WRITE_ZEROES) { - int blk_flags = 0; - - if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) { - blk_flags |= BDRV_REQ_MAY_UNMAP; - } - - if (blk_co_pwrite_zeroes(blk, sector << VIRTIO_BLK_SECTOR_BITS, - bytes, blk_flags) == 0) { - return VIRTIO_BLK_S_OK; - } - } else if (type == VIRTIO_BLK_T_DISCARD) { - /* - * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for - * discard commands if the unmap flag is set. - */ - if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { - return VIRTIO_BLK_S_UNSUPP; - } - - if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS, - bytes) == 0) { - return VIRTIO_BLK_S_OK; - } - } - - return VIRTIO_BLK_S_IOERR; -} - /* Called with server refcount increased, must decrease before returning */ static void coroutine_fn vu_blk_virtio_process_req(void *opaque) { VuBlkReq *req = opaque; VuServer *server = req->server; VuVirtqElement *elem = &req->elem; - uint32_t type; - VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server); - BlockBackend *blk = vexp->export.blk; - + VirtioBlkHandler *handler = &vexp->handler; struct iovec *in_iov = elem->in_sg; struct iovec *out_iov = elem->out_sg; unsigned in_num = elem->in_num; unsigned out_num = elem->out_num; - - /* refer to hw/block/virtio_blk.c */ - if (elem->out_num < 1 || elem->in_num < 1) { - error_report("virtio-blk request missing headers"); - goto err; - } - - if (unlikely(iov_to_buf(out_iov, out_num, 0, &req->out, - sizeof(req->out)) != sizeof(req->out))) { - error_report("virtio-blk request outhdr too short"); - goto err; - } - - iov_discard_front(&out_iov, &out_num, sizeof(req->out)); - - if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) { - error_report("virtio-blk request inhdr too short"); - goto err; - } - - /* We always touch the last byte, so just see how big in_iov is. */ - req->in = (void *)in_iov[in_num - 1].iov_base - + in_iov[in_num - 1].iov_len - - sizeof(struct virtio_blk_inhdr); - iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); - - type = le32_to_cpu(req->out.type); - switch (type & ~VIRTIO_BLK_T_BARRIER) { - case VIRTIO_BLK_T_IN: - case VIRTIO_BLK_T_OUT: { - QEMUIOVector qiov; - int64_t offset; - ssize_t ret = 0; - bool is_write = type & VIRTIO_BLK_T_OUT; - req->sector_num = le64_to_cpu(req->out.sector); - - if (is_write && !vexp->writable) { - req->in->status = VIRTIO_BLK_S_IOERR; - break; - } - - if (is_write) { - qemu_iovec_init_external(&qiov, out_iov, out_num); - } else { - qemu_iovec_init_external(&qiov, in_iov, in_num); - } - - if (unlikely(!vu_blk_sect_range_ok(vexp, - req->sector_num, - qiov.size))) { - req->in->status = VIRTIO_BLK_S_IOERR; - break; - } - - offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS; - - if (is_write) { - ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0); - } else { - ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0); - } - if (ret >= 0) { - req->in->status = VIRTIO_BLK_S_OK; - } else { - req->in->status = VIRTIO_BLK_S_IOERR; - } - break; - } - case VIRTIO_BLK_T_FLUSH: - if (blk_co_flush(blk) == 0) { - req->in->status = VIRTIO_BLK_S_OK; - } else { - req->in->status = VIRTIO_BLK_S_IOERR; - } - break; - case VIRTIO_BLK_T_GET_ID: { - size_t size = MIN(iov_size(&elem->in_sg[0], in_num), - VIRTIO_BLK_ID_BYTES); - snprintf(elem->in_sg[0].iov_base, size, "%s", "vhost_user_blk"); - req->in->status = VIRTIO_BLK_S_OK; - req->size = elem->in_sg[0].iov_len; - break; + int in_len; + + in_len = virtio_blk_process_req(handler, in_iov, out_iov, + in_num, out_num); + if (in_len < 0) { + free(req); + vhost_user_server_unref(server); + return; } - case VIRTIO_BLK_T_DISCARD: - case VIRTIO_BLK_T_WRITE_ZEROES: { - if (!vexp->writable) { - req->in->status = VIRTIO_BLK_S_IOERR; - break; - } - - req->in->status = vu_blk_discard_write_zeroes(vexp, out_iov, out_num, - type); - break; - } - default: - req->in->status = VIRTIO_BLK_S_UNSUPP; - break; - } - - vu_blk_req_complete(req); - vhost_user_server_unref(server); - return; -err: - free(req); + vu_blk_req_complete(req, in_len); vhost_user_server_unref(server); } @@ -348,7 +128,7 @@ static uint64_t vu_blk_get_features(VuDev *dev) 1ull << VIRTIO_RING_F_EVENT_IDX | 1ull << VHOST_USER_F_PROTOCOL_FEATURES; - if (!vexp->writable) { + if (!vexp->handler.writable) { features |= 1ull << VIRTIO_BLK_F_RO; } @@ -455,12 +235,12 @@ vu_blk_initialize_config(BlockDriverState *bs, config->opt_io_size = cpu_to_le32(1); config->num_queues = cpu_to_le16(num_queues); config->max_discard_sectors = - cpu_to_le32(VHOST_USER_BLK_MAX_DISCARD_SECTORS); + cpu_to_le32(VIRTIO_BLK_MAX_DISCARD_SECTORS); config->max_discard_seg = cpu_to_le32(1); config->discard_sector_alignment = cpu_to_le32(blk_size >> VIRTIO_BLK_SECTOR_BITS); config->max_write_zeroes_sectors - = cpu_to_le32(VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS); + = cpu_to_le32(VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS); config->max_write_zeroes_seg = cpu_to_le32(1); } @@ -480,7 +260,6 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts, uint64_t logical_block_size; uint16_t num_queues = VHOST_USER_BLK_NUM_QUEUES_DEFAULT; - vexp->writable = opts->writable; vexp->blkcfg.wce = 0; if (vu_opts->has_logical_block_size) { @@ -494,8 +273,6 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts, error_propagate(errp, local_err); return -EINVAL; } - vexp->blk_size = logical_block_size; - blk_set_guest_block_size(exp->blk, logical_block_size); if (vu_opts->has_num_queues) { num_queues = vu_opts->num_queues; @@ -504,6 +281,10 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts, error_setg(errp, "num-queues must be greater than 0"); return -EINVAL; } + vexp->handler.blk = exp->blk; + vexp->handler.serial = g_strdup("vhost_user_blk"); + vexp->handler.logical_block_size = logical_block_size; + vexp->handler.writable = opts->writable; vu_blk_initialize_config(blk_bs(exp->blk), &vexp->blkcfg, logical_block_size, num_queues); @@ -515,6 +296,7 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts, num_queues, &vu_blk_iface, errp)) { blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach, vexp); + g_free(vexp->handler.serial); return -EADDRNOTAVAIL; } @@ -527,6 +309,7 @@ static void vu_blk_exp_delete(BlockExport *exp) blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach, vexp); + g_free(vexp->handler.serial); } const BlockExportDriver blk_exp_vhost_user_blk = { diff --git a/block/export/virtio-blk-handler.c b/block/export/virtio-blk-handler.c new file mode 100644 index 000000000000..313666e8ab9e --- /dev/null +++ b/block/export/virtio-blk-handler.c @@ -0,0 +1,240 @@ +/* + * Handler for virtio-blk I/O + * + * Copyright (c) 2020 Red Hat, Inc. + * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved. + * + * Author: + * Coiby Xu + * Xie Yongji + * + * 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 "qemu/error-report.h" +#include "virtio-blk-handler.h" + +#include "standard-headers/linux/virtio_blk.h" + +struct virtio_blk_inhdr { + unsigned char status; +}; + +static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size, + uint64_t sector, size_t size) +{ + uint64_t nb_sectors; + uint64_t total_sectors; + + if (size % VIRTIO_BLK_SECTOR_SIZE) { + return false; + } + + nb_sectors = size >> VIRTIO_BLK_SECTOR_BITS; + + QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != VIRTIO_BLK_SECTOR_SIZE); + if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) { + return false; + } + if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) { + return false; + } + blk_get_geometry(blk, &total_sectors); + if (sector > total_sectors || nb_sectors > total_sectors - sector) { + return false; + } + return true; +} + +static int coroutine_fn +virtio_blk_discard_write_zeroes(VirtioBlkHandler *handler, struct iovec *iov, + uint32_t iovcnt, uint32_t type) +{ + BlockBackend *blk = handler->blk; + struct virtio_blk_discard_write_zeroes desc; + ssize_t size; + uint64_t sector; + uint32_t num_sectors; + uint32_t max_sectors; + uint32_t flags; + int bytes; + + /* Only one desc is currently supported */ + if (unlikely(iov_size(iov, iovcnt) > sizeof(desc))) { + return VIRTIO_BLK_S_UNSUPP; + } + + size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc)); + if (unlikely(size != sizeof(desc))) { + error_report("Invalid size %zd, expected %zu", size, sizeof(desc)); + return VIRTIO_BLK_S_IOERR; + } + + sector = le64_to_cpu(desc.sector); + num_sectors = le32_to_cpu(desc.num_sectors); + flags = le32_to_cpu(desc.flags); + max_sectors = (type == VIRTIO_BLK_T_WRITE_ZEROES) ? + VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS : + VIRTIO_BLK_MAX_DISCARD_SECTORS; + + /* This check ensures that 'bytes' fits in an int */ + if (unlikely(num_sectors > max_sectors)) { + return VIRTIO_BLK_S_IOERR; + } + + bytes = num_sectors << VIRTIO_BLK_SECTOR_BITS; + + if (unlikely(!virtio_blk_sect_range_ok(blk, handler->logical_block_size, + sector, bytes))) { + return VIRTIO_BLK_S_IOERR; + } + + /* + * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard + * and write zeroes commands if any unknown flag is set. + */ + if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { + return VIRTIO_BLK_S_UNSUPP; + } + + if (type == VIRTIO_BLK_T_WRITE_ZEROES) { + int blk_flags = 0; + + if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) { + blk_flags |= BDRV_REQ_MAY_UNMAP; + } + + if (blk_co_pwrite_zeroes(blk, sector << VIRTIO_BLK_SECTOR_BITS, + bytes, blk_flags) == 0) { + return VIRTIO_BLK_S_OK; + } + } else if (type == VIRTIO_BLK_T_DISCARD) { + /* + * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for + * discard commands if the unmap flag is set. + */ + if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { + return VIRTIO_BLK_S_UNSUPP; + } + + if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS, + bytes) == 0) { + return VIRTIO_BLK_S_OK; + } + } + + return VIRTIO_BLK_S_IOERR; +} + +int coroutine_fn virtio_blk_process_req(VirtioBlkHandler *handler, + struct iovec *in_iov, + struct iovec *out_iov, + unsigned int in_num, + unsigned int out_num) +{ + BlockBackend *blk = handler->blk; + struct virtio_blk_inhdr *in; + struct virtio_blk_outhdr out; + uint32_t type; + int in_len; + + if (out_num < 1 || in_num < 1) { + error_report("virtio-blk request missing headers"); + return -EINVAL; + } + + if (unlikely(iov_to_buf(out_iov, out_num, 0, &out, + sizeof(out)) != sizeof(out))) { + error_report("virtio-blk request outhdr too short"); + return -EINVAL; + } + + iov_discard_front(&out_iov, &out_num, sizeof(out)); + + if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) { + error_report("virtio-blk request inhdr too short"); + return -EINVAL; + } + + /* We always touch the last byte, so just see how big in_iov is. */ + in_len = iov_size(in_iov, in_num); + in = (void *)in_iov[in_num - 1].iov_base + + in_iov[in_num - 1].iov_len + - sizeof(struct virtio_blk_inhdr); + iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); + + type = le32_to_cpu(out.type); + switch (type & ~VIRTIO_BLK_T_BARRIER) { + case VIRTIO_BLK_T_IN: + case VIRTIO_BLK_T_OUT: { + QEMUIOVector qiov; + int64_t offset; + ssize_t ret = 0; + bool is_write = type & VIRTIO_BLK_T_OUT; + int64_t sector_num = le64_to_cpu(out.sector); + + if (is_write && !handler->writable) { + in->status = VIRTIO_BLK_S_IOERR; + break; + } + + if (is_write) { + qemu_iovec_init_external(&qiov, out_iov, out_num); + } else { + qemu_iovec_init_external(&qiov, in_iov, in_num); + } + + if (unlikely(!virtio_blk_sect_range_ok(blk, + handler->logical_block_size, + sector_num, qiov.size))) { + in->status = VIRTIO_BLK_S_IOERR; + break; + } + + offset = sector_num << VIRTIO_BLK_SECTOR_BITS; + + if (is_write) { + ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0); + } else { + ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0); + } + if (ret >= 0) { + in->status = VIRTIO_BLK_S_OK; + } else { + in->status = VIRTIO_BLK_S_IOERR; + } + break; + } + case VIRTIO_BLK_T_FLUSH: + if (blk_co_flush(blk) == 0) { + in->status = VIRTIO_BLK_S_OK; + } else { + in->status = VIRTIO_BLK_S_IOERR; + } + break; + case VIRTIO_BLK_T_GET_ID: { + size_t size = MIN(strlen(handler->serial) + 1, + MIN(iov_size(in_iov, in_num), + VIRTIO_BLK_ID_BYTES)); + iov_from_buf(in_iov, in_num, 0, handler->serial, size); + in->status = VIRTIO_BLK_S_OK; + break; + } + case VIRTIO_BLK_T_DISCARD: + case VIRTIO_BLK_T_WRITE_ZEROES: + if (!handler->writable) { + in->status = VIRTIO_BLK_S_IOERR; + break; + } + in->status = virtio_blk_discard_write_zeroes(handler, out_iov, + out_num, type); + break; + default: + in->status = VIRTIO_BLK_S_UNSUPP; + break; + } + + return in_len; +} diff --git a/block/export/virtio-blk-handler.h b/block/export/virtio-blk-handler.h new file mode 100644 index 000000000000..150d44cff249 --- /dev/null +++ b/block/export/virtio-blk-handler.h @@ -0,0 +1,37 @@ +/* + * Handler for virtio-blk I/O + * + * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved. + * + * Author: + * Xie Yongji + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef VIRTIO_BLK_HANDLER_H +#define VIRTIO_BLK_HANDLER_H + +#include "sysemu/block-backend.h" + +#define VIRTIO_BLK_SECTOR_BITS 9 +#define VIRTIO_BLK_SECTOR_SIZE (1ULL << VIRTIO_BLK_SECTOR_BITS) + +#define VIRTIO_BLK_MAX_DISCARD_SECTORS 32768 +#define VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS 32768 + +typedef struct { + BlockBackend *blk; + char *serial; + uint32_t logical_block_size; + bool writable; +} VirtioBlkHandler; + +int coroutine_fn virtio_blk_process_req(VirtioBlkHandler *handler, + struct iovec *in_iov, + struct iovec *out_iov, + unsigned int in_num, + unsigned int out_num); + +#endif /* VIRTIO_BLK_HANDLER_H */ diff --git a/block/file-posix.c b/block/file-posix.c index 39a3d6dbe6e2..b9955db2053a 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -155,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 */ @@ -386,7 +384,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) { BDRVRawState *s = bs->opaque; char *buf; - size_t max_align = MAX(MAX_BLOCKSIZE, qemu_real_host_page_size); + size_t max_align = MAX(MAX_BLOCKSIZE, qemu_real_host_page_size()); size_t alignments[] = {1, 512, 1024, 2048, 4096}; /* For SCSI generic devices the alignment is not really used. @@ -756,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 { @@ -770,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 @@ -1023,6 +1013,21 @@ static int raw_handle_perm_lock(BlockDriverState *bs, return ret; } +/* Sets a specific flag */ +static int fcntl_setfl(int fd, int flag) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) { + return -errno; + } + if (fcntl(fd, F_SETFL, flags | flag) == -1) { + return -errno; + } + return 0; +} + static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, int *open_flags, uint64_t perm, bool force_dup, Error **errp) @@ -1224,9 +1229,7 @@ static int hdev_get_max_segments(int fd, struct stat *st) ret = -errno; goto out; } - do { - ret = read(sysfd, buf, sizeof(buf) - 1); - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR(read(sysfd, buf, sizeof(buf) - 1)); if (ret < 0) { ret = -errno; goto out; @@ -1261,7 +1264,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) raw_probe_alignment(bs, s->fd, errp); bs->bl.min_mem_alignment = s->buf_align; - bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size); + bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size()); /* * Maximum transfers are best effort, so it is okay to ignore any @@ -1281,7 +1284,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) { @@ -1374,9 +1377,9 @@ static int handle_aiocb_ioctl(void *opaque) RawPosixAIOData *aiocb = opaque; int ret; - do { - ret = ioctl(aiocb->aio_fildes, aiocb->ioctl.cmd, aiocb->ioctl.buf); - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR( + ioctl(aiocb->aio_fildes, aiocb->ioctl.cmd, aiocb->ioctl.buf) + ); if (ret == -1) { return -errno; } @@ -1458,18 +1461,17 @@ static ssize_t handle_aiocb_rw_vector(RawPosixAIOData *aiocb) { ssize_t len; - do { - if (aiocb->aio_type & QEMU_AIO_WRITE) - len = qemu_pwritev(aiocb->aio_fildes, - aiocb->io.iov, - aiocb->io.niov, - aiocb->aio_offset); - else - len = qemu_preadv(aiocb->aio_fildes, - aiocb->io.iov, - aiocb->io.niov, - aiocb->aio_offset); - } while (len == -1 && errno == EINTR); + len = RETRY_ON_EINTR( + (aiocb->aio_type & QEMU_AIO_WRITE) ? + qemu_pwritev(aiocb->aio_fildes, + aiocb->io.iov, + aiocb->io.niov, + aiocb->aio_offset) : + qemu_preadv(aiocb->aio_fildes, + aiocb->io.iov, + aiocb->io.niov, + aiocb->aio_offset) + ); if (len == -1) { return -errno; @@ -1886,7 +1888,7 @@ static int allocate_first_block(int fd, size_t max_size) size_t write_size = (max_size < MAX_BLOCKSIZE) ? BDRV_SECTOR_SIZE : MAX_BLOCKSIZE; - size_t max_align = MAX(MAX_BLOCKSIZE, qemu_real_host_page_size); + size_t max_align = MAX(MAX_BLOCKSIZE, qemu_real_host_page_size()); void *buf; ssize_t n; int ret; @@ -1894,9 +1896,7 @@ static int allocate_first_block(int fd, size_t max_size) buf = qemu_memalign(max_align, write_size); memset(buf, 0, write_size); - do { - n = pwrite(fd, buf, write_size, 0); - } while (n == -1 && errno == EINTR); + n = RETRY_ON_EINTR(pwrite(fd, buf, write_size, 0)); ret = (n == -1) ? -errno : 0; @@ -2047,6 +2047,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) { @@ -2106,7 +2128,6 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) { - assert(flags == 0); return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE); } @@ -2144,7 +2165,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/filter-compress.c b/block/filter-compress.c index d5be538619ae..305716c86cb3 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -30,11 +30,9 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - return -EINVAL; + int ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) { diff --git a/block/gluster.c b/block/gluster.c index 398976bc66d2..7efc2963996e 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -830,7 +830,6 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT); gconf->logfile = g_strdup(s->logfile); - gconf->has_logfile = true; s->glfs = qemu_gluster_init(gconf, filename, options, errp); if (!s->glfs) { @@ -891,7 +890,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp) { bs->bl.max_transfer = GLUSTER_MAX_TRANSFER; - bs->bl.max_pdiscard = SIZE_MAX; + bs->bl.max_pdiscard = MIN(SIZE_MAX, INT64_MAX); } static int qemu_gluster_reopen_prepare(BDRVReopenState *state, @@ -917,7 +916,6 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state, gconf->debug = s->debug; gconf->has_debug = true; gconf->logfile = g_strdup(s->logfile); - gconf->has_logfile = true; /* * If 'state->bs->exact_filename' is empty, 'state->options' should contain @@ -1162,7 +1160,6 @@ static int coroutine_fn qemu_gluster_co_create_opts(BlockDriver *drv, if (!gconf->logfile) { gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT); } - gconf->has_logfile = true; ret = qemu_gluster_parse(gconf, filename, NULL, errp); if (ret < 0) { @@ -1236,7 +1233,6 @@ static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs, QEMUIOVector *qiov, int flags) { - assert(!flags); return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1); } @@ -1555,7 +1551,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 +1580,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 +1609,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 +1644,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/graph-lock.c b/block/graph-lock.c new file mode 100644 index 000000000000..454c31e691cf --- /dev/null +++ b/block/graph-lock.c @@ -0,0 +1,275 @@ +/* + * Graph lock: rwlock to protect block layer graph manipulations (add/remove + * edges and nodes) + * + * Copyright (c) 2022 Red Hat + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "block/graph-lock.h" +#include "block/block.h" +#include "block/block_int.h" + +/* Dummy lock object to use for Thread Safety Analysis (TSA) */ +BdrvGraphLock graph_lock; + +/* Protects the list of aiocontext and orphaned_reader_count */ +static QemuMutex aio_context_list_lock; + +/* Written and read with atomic operations. */ +static int has_writer; + +/* + * A reader coroutine could move from an AioContext to another. + * If this happens, there is no problem from the point of view of + * counters. The problem is that the total count becomes + * unbalanced if one of the two AioContexts gets deleted. + * The count of readers must remain correct, so the AioContext's + * balance is transferred to this glboal variable. + * Protected by aio_context_list_lock. + */ +static uint32_t orphaned_reader_count; + +/* Queue of readers waiting for the writer to finish */ +static CoQueue reader_queue; + +struct BdrvGraphRWlock { + /* How many readers are currently reading the graph. */ + uint32_t reader_count; + + /* + * List of BdrvGraphRWlock kept in graph-lock.c + * Protected by aio_context_list_lock + */ + QTAILQ_ENTRY(BdrvGraphRWlock) next_aio; +}; + +/* + * List of BdrvGraphRWlock. This list ensures that each BdrvGraphRWlock + * can safely modify only its own counter, avoid reading/writing + * others and thus improving performances by avoiding cacheline bounces. + */ +static QTAILQ_HEAD(, BdrvGraphRWlock) aio_context_list = + QTAILQ_HEAD_INITIALIZER(aio_context_list); + +static void __attribute__((__constructor__)) bdrv_init_graph_lock(void) +{ + qemu_mutex_init(&aio_context_list_lock); + qemu_co_queue_init(&reader_queue); +} + +void register_aiocontext(AioContext *ctx) +{ + ctx->bdrv_graph = g_new0(BdrvGraphRWlock, 1); + QEMU_LOCK_GUARD(&aio_context_list_lock); + assert(ctx->bdrv_graph->reader_count == 0); + QTAILQ_INSERT_TAIL(&aio_context_list, ctx->bdrv_graph, next_aio); +} + +void unregister_aiocontext(AioContext *ctx) +{ + QEMU_LOCK_GUARD(&aio_context_list_lock); + orphaned_reader_count += ctx->bdrv_graph->reader_count; + QTAILQ_REMOVE(&aio_context_list, ctx->bdrv_graph, next_aio); + g_free(ctx->bdrv_graph); +} + +static uint32_t reader_count(void) +{ + BdrvGraphRWlock *brdv_graph; + uint32_t rd; + + QEMU_LOCK_GUARD(&aio_context_list_lock); + + /* rd can temporarly be negative, but the total will *always* be >= 0 */ + rd = orphaned_reader_count; + QTAILQ_FOREACH(brdv_graph, &aio_context_list, next_aio) { + rd += qatomic_read(&brdv_graph->reader_count); + } + + /* shouldn't overflow unless there are 2^31 readers */ + assert((int32_t)rd >= 0); + return rd; +} + +void bdrv_graph_wrlock(void) +{ + GLOBAL_STATE_CODE(); + assert(!qatomic_read(&has_writer)); + + /* Make sure that constantly arriving new I/O doesn't cause starvation */ + bdrv_drain_all_begin_nopoll(); + + /* + * reader_count == 0: this means writer will read has_reader as 1 + * reader_count >= 1: we don't know if writer read has_writer == 0 or 1, + * but we need to wait. + * Wait by allowing other coroutine (and possible readers) to continue. + */ + do { + /* + * has_writer must be 0 while polling, otherwise we get a deadlock if + * any callback involved during AIO_WAIT_WHILE() tries to acquire the + * reader lock. + */ + qatomic_set(&has_writer, 0); + AIO_WAIT_WHILE(qemu_get_aio_context(), reader_count() >= 1); + qatomic_set(&has_writer, 1); + + /* + * We want to only check reader_count() after has_writer = 1 is visible + * to other threads. That way no more readers can sneak in after we've + * determined reader_count() == 0. + */ + smp_mb(); + } while (reader_count() >= 1); + + bdrv_drain_all_end(); +} + +void bdrv_graph_wrunlock(void) +{ + GLOBAL_STATE_CODE(); + QEMU_LOCK_GUARD(&aio_context_list_lock); + assert(qatomic_read(&has_writer)); + + /* + * No need for memory barriers, this works in pair with + * the slow path of rdlock() and both take the lock. + */ + qatomic_store_release(&has_writer, 0); + + /* Wake up all coroutine that are waiting to read the graph */ + qemu_co_enter_all(&reader_queue, &aio_context_list_lock); +} + +void coroutine_fn bdrv_graph_co_rdlock(void) +{ + BdrvGraphRWlock *bdrv_graph; + bdrv_graph = qemu_get_current_aio_context()->bdrv_graph; + + /* Do not lock if in main thread */ + if (qemu_in_main_thread()) { + return; + } + + for (;;) { + qatomic_set(&bdrv_graph->reader_count, + bdrv_graph->reader_count + 1); + /* make sure writer sees reader_count before we check has_writer */ + smp_mb(); + + /* + * has_writer == 0: this means writer will read reader_count as >= 1 + * has_writer == 1: we don't know if writer read reader_count == 0 + * or > 0, but we need to wait anyways because + * it will write. + */ + if (!qatomic_read(&has_writer)) { + break; + } + + /* + * Synchronize access with reader_count() in bdrv_graph_wrlock(). + * Case 1: + * If this critical section gets executed first, reader_count will + * decrease and the reader will go to sleep. + * Then the writer will read reader_count that does not take into + * account this reader, and if there's no other reader it will + * enter the write section. + * Case 2: + * If reader_count() critical section gets executed first, + * then writer will read reader_count >= 1. + * It will wait in AIO_WAIT_WHILE(), but once it releases the lock + * we will enter this critical section and call aio_wait_kick(). + */ + WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) { + /* + * Additional check when we use the above lock to synchronize + * with bdrv_graph_wrunlock(). + * Case 1: + * If this gets executed first, has_writer is still 1, so we reduce + * reader_count and go to sleep. + * Then the writer will set has_writer to 0 and wake up all readers, + * us included. + * Case 2: + * If bdrv_graph_wrunlock() critical section gets executed first, + * then it will set has_writer to 0 and wake up all other readers. + * Then we execute this critical section, and therefore must check + * again for has_writer, otherwise we sleep without any writer + * actually running. + */ + if (!qatomic_read(&has_writer)) { + return; + } + + /* slow path where reader sleeps */ + bdrv_graph->reader_count--; + aio_wait_kick(); + qemu_co_queue_wait(&reader_queue, &aio_context_list_lock); + } + } +} + +void coroutine_fn bdrv_graph_co_rdunlock(void) +{ + BdrvGraphRWlock *bdrv_graph; + bdrv_graph = qemu_get_current_aio_context()->bdrv_graph; + + /* Do not lock if in main thread */ + if (qemu_in_main_thread()) { + return; + } + + qatomic_store_release(&bdrv_graph->reader_count, + bdrv_graph->reader_count - 1); + /* make sure writer sees reader_count before we check has_writer */ + smp_mb(); + + /* + * has_writer == 0: this means reader will read reader_count decreased + * has_writer == 1: we don't know if writer read reader_count old or + * new. Therefore, kick again so on next iteration + * writer will for sure read the updated value. + */ + if (qatomic_read(&has_writer)) { + aio_wait_kick(); + } +} + +void bdrv_graph_rdlock_main_loop(void) +{ + GLOBAL_STATE_CODE(); + assert(!qemu_in_coroutine()); +} + +void bdrv_graph_rdunlock_main_loop(void) +{ + GLOBAL_STATE_CODE(); + assert(!qemu_in_coroutine()); +} + +void assert_bdrv_graph_readable(void) +{ + assert(qemu_in_main_thread() || reader_count()); +} + +void assert_bdrv_graph_writable(void) +{ + assert(qemu_in_main_thread()); + assert(qatomic_read(&has_writer)); +} diff --git a/block/io.c b/block/io.c index 3280144a17d4..a09b1b34abf0 100644 --- a/block/io.c +++ b/block/io.c @@ -45,52 +45,43 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs); static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, BdrvRequestFlags flags); -static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, - bool ignore_bds_parents) +static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c, *next; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { - if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { + if (c == ignore) { continue; } - bdrv_parent_drained_begin_single(c, false); - } -} - -static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c, - int *drained_end_counter) -{ - assert(c->parent_quiesce_counter > 0); - c->parent_quiesce_counter--; - if (c->klass->drained_end) { - c->klass->drained_end(c, drained_end_counter); + bdrv_parent_drained_begin_single(c); } } void bdrv_parent_drained_end_single(BdrvChild *c) { - int drained_end_counter = 0; IO_OR_GS_CODE(); - bdrv_parent_drained_end_single_no_poll(c, &drained_end_counter); - BDRV_POLL_WHILE(c->bs, qatomic_read(&drained_end_counter) > 0); + + assert(c->quiesced_parent); + c->quiesced_parent = false; + + if (c->klass->drained_end) { + c->klass->drained_end(c); + } } -static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, - bool ignore_bds_parents, - int *drained_end_counter) +static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c; QLIST_FOREACH(c, &bs->parents, next_parent) { - if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { + if (c == ignore) { continue; } - bdrv_parent_drained_end_single_no_poll(c, drained_end_counter); + bdrv_parent_drained_end_single(c); } } -static bool bdrv_parent_drained_poll_single(BdrvChild *c) +bool bdrv_parent_drained_poll_single(BdrvChild *c) { if (c->klass->drained_poll) { return c->klass->drained_poll(c); @@ -114,16 +105,16 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, return busy; } -void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll) +void bdrv_parent_drained_begin_single(BdrvChild *c) { IO_OR_GS_CODE(); - c->parent_quiesce_counter++; + + assert(!c->quiesced_parent); + c->quiesced_parent = true; + if (c->klass->drained_begin) { c->klass->drained_begin(c); } - if (poll) { - BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c)); - } } static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) @@ -201,7 +192,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) if (!have_limits) { bs->bl.min_mem_alignment = 512; - bs->bl.opt_mem_alignment = qemu_real_host_page_size; + bs->bl.opt_mem_alignment = qemu_real_host_page_size(); /* Safe default since most protocols use readv()/writev()/etc */ bs->bl.max_iov = IOV_MAX; @@ -243,69 +234,14 @@ typedef struct { BlockDriverState *bs; bool done; bool begin; - bool recursive; bool poll; BdrvChild *parent; - bool ignore_bds_parents; - int *drained_end_counter; } BdrvCoDrainData; -static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) -{ - BdrvCoDrainData *data = opaque; - BlockDriverState *bs = data->bs; - - if (data->begin) { - bs->drv->bdrv_co_drain_begin(bs); - } else { - bs->drv->bdrv_co_drain_end(bs); - } - - /* Set data->done and decrement drained_end_counter before bdrv_wakeup() */ - qatomic_mb_set(&data->done, true); - if (!data->begin) { - qatomic_dec(data->drained_end_counter); - } - bdrv_dec_in_flight(bs); - - g_free(data); -} - -/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ -static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, - int *drained_end_counter) -{ - BdrvCoDrainData *data; - - if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || - (!begin && !bs->drv->bdrv_co_drain_end)) { - return; - } - - data = g_new(BdrvCoDrainData, 1); - *data = (BdrvCoDrainData) { - .bs = bs, - .done = false, - .begin = begin, - .drained_end_counter = drained_end_counter, - }; - - if (!begin) { - qatomic_inc(drained_end_counter); - } - - /* Make sure the driver callback completes during the polling phase for - * drain_begin. */ - bdrv_inc_in_flight(bs); - data->co = qemu_coroutine_create(bdrv_drain_invoke_entry, data); - aio_co_schedule(bdrv_get_aio_context(bs), data->co); -} - /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ -bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, - BdrvChild *ignore_parent, bool ignore_bds_parents) +bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent, + bool ignore_bds_parents) { - BdrvChild *child, *next; IO_OR_GS_CODE(); if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) { @@ -316,30 +252,18 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, return true; } - if (recursive) { - assert(!ignore_bds_parents); - QLIST_FOREACH_SAFE(child, &bs->children, next, next) { - if (bdrv_drain_poll(child->bs, recursive, child, false)) { - return true; - } - } - } - return false; } -static bool bdrv_drain_poll_top_level(BlockDriverState *bs, bool recursive, +static bool bdrv_drain_poll_top_level(BlockDriverState *bs, BdrvChild *ignore_parent) { - return bdrv_drain_poll(bs, recursive, ignore_parent, false); + return bdrv_drain_poll(bs, ignore_parent, false); } -static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, - BdrvChild *parent, bool ignore_bds_parents, +static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent, bool poll); -static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, - BdrvChild *parent, bool ignore_bds_parents, - int *drained_end_counter); +static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent); static void bdrv_co_drain_bh_cb(void *opaque) { @@ -352,14 +276,10 @@ static void bdrv_co_drain_bh_cb(void *opaque) aio_context_acquire(ctx); bdrv_dec_in_flight(bs); if (data->begin) { - assert(!data->drained_end_counter); - bdrv_do_drained_begin(bs, data->recursive, data->parent, - data->ignore_bds_parents, data->poll); + bdrv_do_drained_begin(bs, data->parent, data->poll); } else { assert(!data->poll); - bdrv_do_drained_end(bs, data->recursive, data->parent, - data->ignore_bds_parents, - data->drained_end_counter); + bdrv_do_drained_end(bs, data->parent); } aio_context_release(ctx); } else { @@ -372,11 +292,9 @@ static void bdrv_co_drain_bh_cb(void *opaque) } static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, - bool begin, bool recursive, + bool begin, BdrvChild *parent, - bool ignore_bds_parents, - bool poll, - int *drained_end_counter) + bool poll) { BdrvCoDrainData data; Coroutine *self = qemu_coroutine_self(); @@ -392,11 +310,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, .bs = bs, .done = false, .begin = begin, - .recursive = recursive, .parent = parent, - .ignore_bds_parents = ignore_bds_parents, .poll = poll, - .drained_end_counter = drained_end_counter, }; if (bs) { @@ -427,41 +342,22 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, } } -void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, - BdrvChild *parent, bool ignore_bds_parents) -{ - IO_OR_GS_CODE(); - assert(!qemu_in_coroutine()); - - /* Stop things in parent-to-child order */ - if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) { - aio_disable_external(bdrv_get_aio_context(bs)); - } - - bdrv_parent_drained_begin(bs, parent, ignore_bds_parents); - bdrv_drain_invoke(bs, true, NULL); -} - -static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, - BdrvChild *parent, bool ignore_bds_parents, +static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent, bool poll) { - BdrvChild *child, *next; + IO_OR_GS_CODE(); if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents, - poll, NULL); + bdrv_co_yield_to_drain(bs, true, parent, poll); return; } - bdrv_do_drained_begin_quiesce(bs, parent, ignore_bds_parents); - - if (recursive) { - assert(!ignore_bds_parents); - bs->recursive_quiesce_counter++; - QLIST_FOREACH_SAFE(child, &bs->children, next, next) { - bdrv_do_drained_begin(child->bs, true, child, ignore_bds_parents, - false); + /* Stop things in parent-to-child order */ + if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) { + aio_disable_external(bdrv_get_aio_context(bs)); + bdrv_parent_drained_begin(bs, parent); + if (bs->drv && bs->drv->bdrv_drain_begin) { + bs->drv->bdrv_drain_begin(bs); } } @@ -475,132 +371,50 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, * nodes. */ if (poll) { - assert(!ignore_bds_parents); - BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, recursive, parent)); + BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent)); } } -void bdrv_drained_begin(BlockDriverState *bs) +void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent) { - IO_OR_GS_CODE(); - bdrv_do_drained_begin(bs, false, NULL, false, true); + bdrv_do_drained_begin(bs, parent, false); } -void bdrv_subtree_drained_begin(BlockDriverState *bs) +void bdrv_drained_begin(BlockDriverState *bs) { IO_OR_GS_CODE(); - bdrv_do_drained_begin(bs, true, NULL, false, true); + bdrv_do_drained_begin(bs, NULL, true); } /** * This function does not poll, nor must any of its recursively called - * functions. The *drained_end_counter pointee will be incremented - * once for every background operation scheduled, and decremented once - * the operation settles. Therefore, the pointer must remain valid - * until the pointee reaches 0. That implies that whoever sets up the - * pointee has to poll until it is 0. - * - * We use atomic operations to access *drained_end_counter, because - * (1) when called from bdrv_set_aio_context_ignore(), the subgraph of - * @bs may contain nodes in different AioContexts, - * (2) bdrv_drain_all_end() uses the same counter for all nodes, - * regardless of which AioContext they are in. + * functions. */ -static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, - BdrvChild *parent, bool ignore_bds_parents, - int *drained_end_counter) +static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) { - BdrvChild *child; int old_quiesce_counter; - assert(drained_end_counter != NULL); - if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents, - false, drained_end_counter); + bdrv_co_yield_to_drain(bs, false, parent, false); return; } assert(bs->quiesce_counter > 0); /* Re-enable things in child-to-parent order */ - bdrv_drain_invoke(bs, false, drained_end_counter); - bdrv_parent_drained_end(bs, parent, ignore_bds_parents, - drained_end_counter); - old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter); if (old_quiesce_counter == 1) { - aio_enable_external(bdrv_get_aio_context(bs)); - } - - if (recursive) { - assert(!ignore_bds_parents); - bs->recursive_quiesce_counter--; - QLIST_FOREACH(child, &bs->children, next) { - bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents, - drained_end_counter); + if (bs->drv && bs->drv->bdrv_drain_end) { + bs->drv->bdrv_drain_end(bs); } + bdrv_parent_drained_end(bs, parent); + aio_enable_external(bdrv_get_aio_context(bs)); } } void bdrv_drained_end(BlockDriverState *bs) { - int drained_end_counter = 0; IO_OR_GS_CODE(); - bdrv_do_drained_end(bs, false, NULL, false, &drained_end_counter); - BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); -} - -void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter) -{ - IO_CODE(); - bdrv_do_drained_end(bs, false, NULL, false, drained_end_counter); -} - -void bdrv_subtree_drained_end(BlockDriverState *bs) -{ - int drained_end_counter = 0; - IO_OR_GS_CODE(); - bdrv_do_drained_end(bs, true, NULL, false, &drained_end_counter); - BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); -} - -void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) -{ - int i; - IO_OR_GS_CODE(); - - for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { - bdrv_do_drained_begin(child->bs, true, child, false, true); - } -} - -void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) -{ - int drained_end_counter = 0; - int i; - IO_OR_GS_CODE(); - - for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { - bdrv_do_drained_end(child->bs, true, child, false, - &drained_end_counter); - } - - BDRV_POLL_WHILE(child->bs, qatomic_read(&drained_end_counter) > 0); -} - -/* - * Wait for pending requests to complete on a single BlockDriverState subtree, - * and suspend block driver's internal I/O until next request arrives. - * - * Note that unlike bdrv_drain_all(), the caller must hold the BlockDriverState - * AioContext. - */ -void coroutine_fn bdrv_co_drain(BlockDriverState *bs) -{ - IO_OR_GS_CODE(); - assert(qemu_in_coroutine()); - bdrv_drained_begin(bs); - bdrv_drained_end(bs); + bdrv_do_drained_end(bs, NULL); } void bdrv_drain(BlockDriverState *bs) @@ -633,7 +447,7 @@ static bool bdrv_drain_all_poll(void) while ((bs = bdrv_next_all_states(bs))) { AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - result |= bdrv_drain_poll(bs, false, NULL, true); + result |= bdrv_drain_poll(bs, NULL, true); aio_context_release(aio_context); } @@ -652,16 +466,11 @@ static bool bdrv_drain_all_poll(void) * NOTE: no new block jobs or BlockDriverStates can be created between * the bdrv_drain_all_begin() and bdrv_drain_all_end() calls. */ -void bdrv_drain_all_begin(void) +void bdrv_drain_all_begin_nopoll(void) { BlockDriverState *bs = NULL; GLOBAL_STATE_CODE(); - if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true, NULL); - return; - } - /* * bdrv queue is managed by record/replay, * waiting for finishing the I/O requests may @@ -683,9 +492,30 @@ void bdrv_drain_all_begin(void) AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - bdrv_do_drained_begin(bs, false, NULL, true, false); + bdrv_do_drained_begin(bs, NULL, false); aio_context_release(aio_context); } +} + +void bdrv_drain_all_begin(void) +{ + BlockDriverState *bs = NULL; + + if (qemu_in_coroutine()) { + bdrv_co_yield_to_drain(NULL, true, NULL, true); + return; + } + + /* + * bdrv queue is managed by record/replay, + * waiting for finishing the I/O requests may + * be infinite + */ + if (replay_events_enabled()) { + return; + } + + bdrv_drain_all_begin_nopoll(); /* Now poll the in-flight requests */ AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll()); @@ -697,22 +527,19 @@ void bdrv_drain_all_begin(void) void bdrv_drain_all_end_quiesce(BlockDriverState *bs) { - int drained_end_counter = 0; GLOBAL_STATE_CODE(); g_assert(bs->quiesce_counter > 0); g_assert(!bs->refcnt); while (bs->quiesce_counter) { - bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter); + bdrv_do_drained_end(bs, NULL); } - BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); } void bdrv_drain_all_end(void) { BlockDriverState *bs = NULL; - int drained_end_counter = 0; GLOBAL_STATE_CODE(); /* @@ -728,13 +555,11 @@ void bdrv_drain_all_end(void) AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter); + bdrv_do_drained_end(bs, NULL); aio_context_release(aio_context); } assert(qemu_get_current_aio_context() == qemu_get_aio_context()); - AIO_WAIT_WHILE(NULL, qatomic_read(&drained_end_counter) > 0); - assert(bdrv_drain_all_count > 0); bdrv_drain_all_count--; } @@ -751,7 +576,7 @@ void bdrv_drain_all(void) * * This function should be called when a tracked request is completing. */ -static void tracked_request_end(BdrvTrackedRequest *req) +static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req) { if (req->serialising) { qatomic_dec(&req->bs->serialising_in_flight); @@ -766,11 +591,11 @@ static void 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); @@ -809,7 +634,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; @@ -843,20 +668,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 */ @@ -949,36 +770,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, @@ -1061,14 +877,6 @@ static int bdrv_check_request32(int64_t offset, int64_t bytes, return 0; } -int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, - int64_t bytes, BdrvRequestFlags flags) -{ - IO_CODE(); - return bdrv_pwritev(child, offset, bytes, NULL, - BDRV_REQ_ZERO_WRITE | flags); -} - /* * Completely zero out a block device with the help of bdrv_pwrite_zeroes. * The operation is sped up by checking the block status and only writing @@ -1111,62 +919,25 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) } } -/* See bdrv_pwrite() for the return codes */ -int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes) -{ - int ret; - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); - IO_CODE(); - - if (bytes < 0) { - return -EINVAL; - } - - ret = bdrv_preadv(child, offset, bytes, &qiov, 0); - - return ret < 0 ? ret : bytes; -} - -/* Return no. of bytes on success or < 0 on error. Important errors are: - -EIO generic I/O error (may happen for all errors) - -ENOMEDIUM No media inserted. - -EINVAL Invalid offset or number of bytes - -EACCES Trying to write a read-only device -*/ -int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, - int64_t bytes) -{ - int ret; - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); - IO_CODE(); - - if (bytes < 0) { - return -EINVAL; - } - - ret = bdrv_pwritev(child, offset, bytes, &qiov, 0); - - return ret < 0 ? ret : bytes; -} - /* * Writes to the file and ensures that no writes are reordered across this * request (acts as a barrier) * * Returns 0 on success, -errno in error cases. */ -int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, - const void *buf, int64_t count) +int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, + int64_t bytes, const void *buf, + BdrvRequestFlags flags) { int ret; IO_CODE(); - ret = bdrv_pwrite(child, offset, buf, count); + ret = bdrv_co_pwrite(child, offset, bytes, buf, flags); if (ret < 0) { return ret; } - ret = bdrv_flush(child->bs); + ret = bdrv_co_flush(child->bs); if (ret < 0) { return ret; } @@ -1199,8 +970,7 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs, int ret; bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); - assert(!(flags & ~BDRV_REQ_MASK)); - assert(!(flags & BDRV_REQ_NO_FALLBACK)); + assert(!(flags & ~bs->supported_read_flags)); if (!drv) { return -ENOMEDIUM; @@ -1264,23 +1034,29 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, BdrvRequestFlags flags) { BlockDriver *drv = bs->drv; + bool emulate_fua = false; int64_t sector_num; unsigned int nb_sectors; QEMUIOVector local_qiov; int ret; bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); - assert(!(flags & ~BDRV_REQ_MASK)); - assert(!(flags & BDRV_REQ_NO_FALLBACK)); if (!drv) { return -ENOMEDIUM; } + if ((flags & BDRV_REQ_FUA) && + (~bs->supported_write_flags & BDRV_REQ_FUA)) { + flags &= ~BDRV_REQ_FUA; + emulate_fua = true; + } + + flags &= bs->supported_write_flags; + if (drv->bdrv_co_pwritev_part) { ret = drv->bdrv_co_pwritev_part(bs, offset, bytes, qiov, qiov_offset, - flags & bs->supported_write_flags); - flags &= ~bs->supported_write_flags; + flags); goto emulate_flags; } @@ -1290,9 +1066,7 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, } if (drv->bdrv_co_pwritev) { - ret = drv->bdrv_co_pwritev(bs, offset, bytes, qiov, - flags & bs->supported_write_flags); - flags &= ~bs->supported_write_flags; + ret = drv->bdrv_co_pwritev(bs, offset, bytes, qiov, flags); goto emulate_flags; } @@ -1302,10 +1076,8 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, .coroutine = qemu_coroutine_self(), }; - acb = drv->bdrv_aio_pwritev(bs, offset, bytes, qiov, - flags & bs->supported_write_flags, + acb = drv->bdrv_aio_pwritev(bs, offset, bytes, qiov, flags, bdrv_co_io_em_complete, &co); - flags &= ~bs->supported_write_flags; if (acb == NULL) { ret = -EIO; } else { @@ -1323,12 +1095,10 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, assert(bytes <= BDRV_REQUEST_MAX_BYTES); assert(drv->bdrv_co_writev); - ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov, - flags & bs->supported_write_flags); - flags &= ~bs->supported_write_flags; + ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov, flags); emulate_flags: - if (ret == 0 && (flags & BDRV_REQ_FUA)) { + if (ret == 0 && emulate_fua) { ret = bdrv_co_flush(bs); } @@ -1556,11 +1326,14 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, max_transfer = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_transfer, INT_MAX), align); - /* TODO: We would need a per-BDS .supported_read_flags and + /* + * TODO: We would need a per-BDS .supported_read_flags and * potential fallback support, if we ever implement any read flags * to pass through to drivers. For now, there aren't any - * passthrough flags. */ - assert(!(flags & ~(BDRV_REQ_COPY_ON_READ | BDRV_REQ_PREFETCH))); + * passthrough flags except the BDRV_REQ_REGISTERED_BUF optimization hint. + */ + assert(!(flags & ~(BDRV_REQ_COPY_ON_READ | BDRV_REQ_PREFETCH | + BDRV_REQ_REGISTERED_BUF))); /* Handle Copy on Read and associated serialisation */ if (flags & BDRV_REQ_COPY_ON_READ) { @@ -1601,7 +1374,7 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, goto out; } - assert(!(flags & ~bs->supported_read_flags)); + assert(!(flags & ~(bs->supported_read_flags | BDRV_REQ_REGISTERED_BUF))); max_bytes = ROUND_UP(MAX(0, total_bytes - offset), align); if (bytes <= max_bytes && bytes <= max_transfer) { @@ -1704,10 +1477,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; @@ -1790,7 +1563,8 @@ static void bdrv_padding_destroy(BdrvRequestPadding *pad) static int bdrv_pad_request(BlockDriverState *bs, QEMUIOVector **qiov, size_t *qiov_offset, int64_t *offset, int64_t *bytes, - BdrvRequestPadding *pad, bool *padded) + BdrvRequestPadding *pad, bool *padded, + BdrvRequestFlags *flags) { int ret; @@ -1818,6 +1592,10 @@ static int bdrv_pad_request(BlockDriverState *bs, if (padded) { *padded = true; } + if (flags) { + /* Can't use optimization hint with bounce buffer */ + *flags &= ~BDRV_REQ_REGISTERED_BUF; + } return 0; } @@ -1872,7 +1650,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, } ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad, - NULL); + NULL, &flags); if (ret < 0) { goto fail; } @@ -1917,6 +1695,11 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, return -ENOTSUP; } + /* By definition there is no user buffer so this flag doesn't make sense */ + if (flags & BDRV_REQ_REGISTERED_BUF) { + return -EINVAL; + } + /* Invalidate the cached block-status data range if this write overlaps */ bdrv_bsc_invalidate_range(bs, offset, bytes); @@ -2202,6 +1985,9 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, bool padding; BdrvRequestPadding pad; + /* This flag doesn't make sense for padding or zero writes */ + flags &= ~BDRV_REQ_REGISTERED_BUF; + padding = bdrv_init_padding(bs, offset, bytes, &pad); if (padding) { assert(!(flags & BDRV_REQ_NO_WAIT)); @@ -2319,7 +2105,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, * alignment only if there is no ZERO flag. */ ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad, - &padded); + &padded, &flags); if (ret < 0) { return ret; } @@ -2763,6 +2549,17 @@ bdrv_co_common_block_status_above(BlockDriverState *bs, return ret; } +int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs, + BlockDriverState *base, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, + BlockDriverState **file) +{ + IO_CODE(); + return bdrv_co_common_block_status_above(bs, base, false, true, offset, + bytes, pnum, map, file, NULL); +} + int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) @@ -2798,8 +2595,8 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, return 1; } - ret = bdrv_common_block_status_above(bs, NULL, false, false, offset, - bytes, &pnum, NULL, NULL, NULL); + ret = bdrv_co_common_block_status_above(bs, NULL, false, false, offset, + bytes, &pnum, NULL, NULL, NULL); if (ret < 0) { return ret; @@ -2808,8 +2605,24 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, return (pnum == bytes) && (ret & BDRV_BLOCK_ZERO); } -int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, - int64_t bytes, int64_t *pnum) +int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, + int64_t bytes, int64_t *pnum) +{ + int ret; + int64_t dummy; + IO_CODE(); + + ret = bdrv_co_common_block_status_above(bs, bs, true, false, offset, + bytes, pnum ? pnum : &dummy, NULL, + NULL, NULL); + if (ret < 0) { + return ret; + } + return !!(ret & BDRV_BLOCK_ALLOCATED); +} + +int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, + int64_t *pnum) { int ret; int64_t dummy; @@ -2824,6 +2637,29 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, return !!(ret & BDRV_BLOCK_ALLOCATED); } +/* See bdrv_is_allocated_above for documentation */ +int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, + BlockDriverState *base, + bool include_base, int64_t offset, + int64_t bytes, int64_t *pnum) +{ + int depth; + int ret; + IO_CODE(); + + ret = bdrv_co_common_block_status_above(top, base, include_base, false, + offset, bytes, pnum, NULL, NULL, + &depth); + if (ret < 0) { + return ret; + } + + if (ret & BDRV_BLOCK_ALLOCATED) { + return depth; + } + return 0; +} + /* * Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP] * @@ -2847,10 +2683,12 @@ int bdrv_is_allocated_above(BlockDriverState *top, int64_t bytes, int64_t *pnum) { int depth; - int ret = bdrv_common_block_status_above(top, base, include_base, false, - offset, bytes, pnum, NULL, NULL, - &depth); + int ret; IO_CODE(); + + ret = bdrv_common_block_status_above(top, base, include_base, false, + offset, bytes, pnum, NULL, NULL, + &depth); if (ret < 0) { return ret; } @@ -2868,6 +2706,7 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) BlockDriverState *child_bs = bdrv_primary_bs(bs); int ret; IO_CODE(); + assert_bdrv_graph_readable(); ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL); if (ret < 0) { @@ -2900,6 +2739,7 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) BlockDriverState *child_bs = bdrv_primary_bs(bs); int ret; IO_CODE(); + assert_bdrv_graph_readable(); ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL); if (ret < 0) { @@ -3228,7 +3068,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, 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 = { @@ -3296,27 +3136,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; @@ -3352,29 +3171,57 @@ void bdrv_io_unplug(BlockDriverState *bs) } } -void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size) +/* Helper that undoes bdrv_register_buf() when it fails partway through */ +static void bdrv_register_buf_rollback(BlockDriverState *bs, + void *host, + size_t size, + BdrvChild *final_child) +{ + BdrvChild *child; + + QLIST_FOREACH(child, &bs->children, next) { + if (child == final_child) { + break; + } + + bdrv_unregister_buf(child->bs, host, size); + } + + if (bs->drv && bs->drv->bdrv_unregister_buf) { + bs->drv->bdrv_unregister_buf(bs, host, size); + } +} + +bool bdrv_register_buf(BlockDriverState *bs, void *host, size_t size, + Error **errp) { BdrvChild *child; GLOBAL_STATE_CODE(); if (bs->drv && bs->drv->bdrv_register_buf) { - bs->drv->bdrv_register_buf(bs, host, size); + if (!bs->drv->bdrv_register_buf(bs, host, size, errp)) { + return false; + } } QLIST_FOREACH(child, &bs->children, next) { - bdrv_register_buf(child->bs, host, size); + if (!bdrv_register_buf(child->bs, host, size, errp)) { + bdrv_register_buf_rollback(bs, host, size, child); + return false; + } } + return true; } -void bdrv_unregister_buf(BlockDriverState *bs, void *host) +void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size) { BdrvChild *child; GLOBAL_STATE_CODE(); if (bs->drv && bs->drv->bdrv_unregister_buf) { - bs->drv->bdrv_unregister_buf(bs, host); + bs->drv->bdrv_unregister_buf(bs, host, size); } QLIST_FOREACH(child, &bs->children, next) { - bdrv_unregister_buf(child->bs, host); + bdrv_unregister_buf(child->bs, host, size); } } diff --git a/block/io_uring.c b/block/io_uring.c index 782afdb433e1..973e15d87693 100644 --- a/block/io_uring.c +++ b/block/io_uring.c @@ -10,7 +10,6 @@ */ #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "block/aio.h" #include "qemu/queue.h" #include "block/block.h" @@ -73,12 +72,8 @@ static void luring_resubmit(LuringState *s, LuringAIOCB *luringcb) /** * luring_resubmit_short_read: * - * Before Linux commit 9d93a3f5a0c ("io_uring: punt short reads to async - * context") a buffered I/O request with the start of the file range in the - * page cache could result in a short read. Applications need to resubmit the - * remaining read request. - * - * This is a slow path but recent kernels never take it. + * Short reads are rare but may occur. The remaining read request needs to be + * resubmitted. */ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, int nread) @@ -89,7 +84,7 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, trace_luring_resubmit_short_read(s, luringcb, nread); /* Update read position */ - luringcb->total_read = nread; + luringcb->total_read += nread; remaining = luringcb->qiov->size - luringcb->total_read; /* Shorten qiov */ @@ -103,7 +98,7 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, remaining); /* Update sqe */ - luringcb->sqeq.off = nread; + luringcb->sqeq.off += nread; luringcb->sqeq.addr = (__u64)(uintptr_t)luringcb->resubmit_qiov.iov; luringcb->sqeq.len = luringcb->resubmit_qiov.niov; diff --git a/block/iscsi.c b/block/iscsi.c index 51f2a5eeaa80..a316d46d9625 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -28,7 +28,7 @@ #include #include #include -#include "qemu-common.h" +#include "sysemu/sysemu.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/bitops.h" @@ -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 4c423fcccf94..d2cfb7f52330 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -363,8 +363,16 @@ void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, uint64_t dev_max_batch) { assert(s->io_q.plugged); + s->io_q.plugged--; + + /* + * Why max batch checking is performed here: + * Another BDS may have queued requests with a higher dev_max_batch and + * therefore in_queue could now exceed our dev_max_batch. Re-check the max + * batch so we can honor our device's dev_max_batch. + */ if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) || - (--s->io_q.plugged == 0 && + (!s->io_q.plugged && !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) { ioq_submit(s); } @@ -453,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/meson.build b/block/meson.build index 0b2a60c99b71..90011a2805de 100644 --- a/block/meson.build +++ b/block/meson.build @@ -10,6 +10,7 @@ block_ss.add(files( 'blkverify.c', 'block-backend.c', 'block-copy.c', + 'graph-lock.c', 'commit.c', 'copy-on-read.c', 'preallocate.c', @@ -46,6 +47,7 @@ block_ss.add(files( ), zstd, zlib, gnutls) softmmu_ss.add(when: 'CONFIG_TCG', if_true: files('blkreplay.c')) +softmmu_ss.add(files('block-ram-registrar.c')) if get_option('qcow1').allowed() block_ss.add(files('qcow.c')) @@ -92,6 +94,7 @@ block_modules = {} modsrc = [] foreach m : [ + [blkio, 'blkio', files('blkio.c')], [curl, 'curl', files('curl.c')], [glusterfs, 'gluster', files('gluster.c')], [libiscsi, 'iscsi', [files('iscsi.c'), libm]], @@ -135,7 +138,9 @@ block_gen_c = custom_target('block-gen.c', output: 'block-gen.c', input: files( '../include/block/block-io.h', + '../include/block/dirty-bitmap.h', '../include/block/block-global-state.h', + '../include/sysemu/block-backend-io.h', 'coroutines.h' ), command: [wrapper_py, '@OUTPUT@', '@INPUT@']) diff --git a/block/mirror.c b/block/mirror.c index d8ecb9efa29a..251adc5ae02a 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -73,7 +73,7 @@ typedef struct MirrorBlockJob { uint64_t last_pause_ns; unsigned long *in_flight_bitmap; - int in_flight; + unsigned in_flight; int64_t bytes_in_flight; QTAILQ_HEAD(, MirrorOp) ops_in_flight; int ret; @@ -82,6 +82,7 @@ typedef struct MirrorBlockJob { int max_iov; bool initial_zeroing_ongoing; int in_active_write_counter; + int64_t active_write_bytes_in_flight; bool prepared; bool in_drain; } MirrorBlockJob; @@ -304,19 +305,21 @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset, } static inline void coroutine_fn -mirror_wait_for_any_operation(MirrorBlockJob *s, bool active) +mirror_wait_for_free_in_flight_slot(MirrorBlockJob *s) { MirrorOp *op; QTAILQ_FOREACH(op, &s->ops_in_flight, next) { - /* Do not wait on pseudo ops, because it may in turn wait on + /* + * Do not wait on pseudo ops, because it may in turn wait on * some other operation to start, which may in fact be the * caller of this function. Since there is only one pseudo op * at any given time, we will always find some real operation - * to wait on. */ - if (!op->is_pseudo_op && op->is_in_flight && - op->is_active_write == active) - { + * to wait on. + * Also, do not wait on active operations, because they do not + * use up in-flight slots. + */ + if (!op->is_pseudo_op && op->is_in_flight && !op->is_active_write) { qemu_co_queue_wait(&op->waiting_requests, NULL); return; } @@ -324,13 +327,6 @@ mirror_wait_for_any_operation(MirrorBlockJob *s, bool active) abort(); } -static inline void coroutine_fn -mirror_wait_for_free_in_flight_slot(MirrorBlockJob *s) -{ - /* Only non-active operations use up in-flight slots */ - mirror_wait_for_any_operation(s, false); -} - /* Perform a mirror copy operation. * * *op->bytes_handled is set to the number of bytes copied after and @@ -494,6 +490,13 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) } bdrv_dirty_bitmap_unlock(s->dirty_bitmap); + /* + * Wait for concurrent requests to @offset. The next loop will limit the + * copied area based on in_flight_bitmap so we only copy an area that does + * not overlap with concurrent in-flight requests. Still, we would like to + * copy something, so wait until there are at least no more requests to the + * very beginning of the area. + */ mirror_wait_on_conflicts(NULL, s, offset, 1); job_pause_point(&s->common.job); @@ -894,6 +897,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; @@ -921,8 +925,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) * active layer. */ if (s->base == blk_bs(s->target)) { if (s->bdev_length > target_length) { - ret = blk_truncate(s->target, s->bdev_length, false, - PREALLOC_MODE_OFF, 0, NULL); + ret = blk_co_truncate(s->target, s->bdev_length, false, + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { goto immediate_exit; } @@ -987,12 +991,6 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) int64_t cnt, delta; bool should_complete; - /* Do not start passive operations while there are active - * writes in progress */ - while (s->in_active_write_counter) { - mirror_wait_for_any_operation(s, true); - } - if (s->ret < 0) { ret = s->ret; goto immediate_exit; @@ -1009,15 +1007,20 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is * the number of bytes currently being processed; together those are * the current remaining operation length */ - job_progress_set_remaining(&s->common.job, s->bytes_in_flight + cnt); + job_progress_set_remaining(&s->common.job, + s->bytes_in_flight + cnt + + s->active_write_bytes_in_flight); /* Note that even when no rate limit is applied we need to yield * periodically with no pending I/O so that bdrv_drain_all() returns. * 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); @@ -1067,6 +1070,10 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) s->in_drain = true; bdrv_drained_begin(bs); + + /* Must be zero because we are drained */ + assert(s->in_active_write_counter == 0); + cnt = bdrv_get_dirty_count(s->dirty_bitmap); if (cnt > 0 || mirror_flush(s) < 0) { bdrv_drained_end(bs); @@ -1152,8 +1159,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 +1182,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; @@ -1297,6 +1309,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, } job_progress_increase_remaining(&job->common.job, bytes); + job->active_write_bytes_in_flight += bytes; switch (method) { case MIRROR_METHOD_COPY: @@ -1318,6 +1331,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, abort(); } + job->active_write_bytes_in_flight -= bytes; if (ret >= 0) { job_progress_update(&job->common.job, bytes); } else { @@ -1366,6 +1380,19 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s, s->in_active_write_counter++; + /* + * Wait for concurrent requests affecting the area. If there are already + * running requests that are copying off now-to-be stale data in the area, + * we must wait for them to finish before we begin writing fresh data to the + * target so that the write operations appear in the correct order. + * Note that background requests (see mirror_iteration()) in contrast only + * wait for conflicting requests at the start of the dirty area, and then + * (based on the in_flight_bitmap) truncate the area to copy so it will not + * conflict with any requests beyond that. For active writes, however, we + * cannot truncate that area. The request from our parent must be blocked + * until the area is copied in full. Therefore, we must wait for the whole + * area to become free of concurrent requests. + */ mirror_wait_on_conflicts(op, s, offset, bytes); bitmap_set(s->in_flight_bitmap, start_chunk, end_chunk - start_chunk); @@ -1411,11 +1438,13 @@ static int coroutine_fn bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorOp *op = NULL; MirrorBDSOpaque *s = bs->opaque; int ret = 0; - bool copy_to_target; + bool copy_to_target = false; - copy_to_target = s->job->ret >= 0 && - !job_is_cancelled(&s->job->common.job) && - s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING; + if (s->job) { + copy_to_target = s->job->ret >= 0 && + !job_is_cancelled(&s->job->common.job) && + s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING; + } if (copy_to_target) { op = active_write_prepare(s->job, offset, bytes); @@ -1460,11 +1489,13 @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, QEMUIOVector bounce_qiov; void *bounce_buf; int ret = 0; - bool copy_to_target; + bool copy_to_target = false; - copy_to_target = s->job->ret >= 0 && - !job_is_cancelled(&s->job->common.job) && - s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING; + if (s->job) { + copy_to_target = s->job->ret >= 0 && + !job_is_cancelled(&s->job->common.job) && + s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING; + } if (copy_to_target) { /* The guest might concurrently modify the data to write; but @@ -1477,6 +1508,8 @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, qemu_iovec_init(&bounce_qiov, 1); qemu_iovec_add(&bounce_qiov, bounce_buf, bytes); qiov = &bounce_qiov; + + flags &= ~BDRV_REQ_REGISTERED_BUF; } ret = bdrv_mirror_top_do_write(bs, MIRROR_METHOD_COPY, offset, bytes, qiov, @@ -1578,6 +1611,7 @@ static BlockDriver bdrv_mirror_top = { .bdrv_child_perm = bdrv_mirror_top_child_perm, .is_filter = true, + .filtered_child_is_backing = true, }; static BlockJob *mirror_start_job( diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c index 8e35616c2e0d..282363606f94 100644 --- a/block/monitor/bitmap-qmp-cmds.c +++ b/block/monitor/bitmap-qmp-cmds.c @@ -257,12 +257,13 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name, } BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bms, + BlockDirtyBitmapOrStrList *bms, HBitmap **backup, Error **errp) { BlockDriverState *bs; - BdrvDirtyBitmap *dst, *src, *anon; - BlockDirtyBitmapMergeSourceList *lst; + BdrvDirtyBitmap *dst, *src; + BlockDirtyBitmapOrStrList *lst; + HBitmap *local_backup = NULL; GLOBAL_STATE_CODE(); @@ -271,12 +272,6 @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, return NULL; } - anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst), - NULL, errp); - if (!anon) { - return NULL; - } - for (lst = bms; lst; lst = lst->next) { switch (lst->value->type) { const char *name, *node; @@ -285,8 +280,7 @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, src = bdrv_find_dirty_bitmap(bs, name); if (!src) { error_setg(errp, "Dirty bitmap '%s' not found", name); - dst = NULL; - goto out; + goto fail; } break; case QTYPE_QDICT: @@ -294,30 +288,40 @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, name = lst->value->u.external.name; src = block_dirty_bitmap_lookup(node, name, NULL, errp); if (!src) { - dst = NULL; - goto out; + goto fail; } break; default: abort(); } - if (!bdrv_merge_dirty_bitmap(anon, src, NULL, errp)) { - dst = NULL; - goto out; + /* We do backup only for first merge operation */ + if (!bdrv_merge_dirty_bitmap(dst, src, + local_backup ? NULL : &local_backup, + errp)) + { + goto fail; } } - /* Merge into dst; dst is unchanged on failure. */ - bdrv_merge_dirty_bitmap(dst, anon, backup, errp); + if (backup) { + *backup = local_backup; + } else { + hbitmap_free(local_backup); + } - out: - bdrv_release_dirty_bitmap(anon); return dst; + +fail: + if (local_backup) { + bdrv_restore_dirty_bitmap(dst, local_backup); + } + + return NULL; } void qmp_block_dirty_bitmap_merge(const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bitmaps, + BlockDirtyBitmapOrStrList *bitmaps, Error **errp) { block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index bfb3c043a052..0ff7c84039c5 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -241,7 +241,6 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) DriveMirror mirror = { .device = (char *)qdict_get_str(qdict, "device"), .target = (char *)filename, - .has_format = !!format, .format = (char *)format, .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, .has_mode = true, @@ -270,7 +269,6 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict) DriveBackup backup = { .device = (char *)device, .target = (char *)filename, - .has_format = !!format, .format = (char *)format, .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, .has_mode = true, @@ -360,9 +358,7 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) } mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS; - qmp_blockdev_snapshot_sync(true, device, false, NULL, - filename, false, NULL, - !!format, format, + qmp_blockdev_snapshot_sync(device, NULL, filename, NULL, format, true, mode, &err); end: hmp_handle_error(mon, err); @@ -385,8 +381,7 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict) const char *id = qdict_get_try_str(qdict, "id"); Error *err = NULL; - qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id, - true, name, &err); + qmp_blockdev_snapshot_delete_internal_sync(device, id, name, &err); hmp_handle_error(mon, err); } @@ -427,7 +422,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) block_list = qmp_query_block(NULL); for (info = block_list; info; info = info->next) { - if (!info->value->has_inserted) { + if (!info->value->inserted) { continue; } @@ -460,7 +455,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict) NbdServerAddOptions export = { .device = (char *) device, - .has_name = !!name, .name = (char *) name, .has_writable = true, .writable = writable, @@ -489,13 +483,13 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_block_resize(Monitor *mon, const QDict *qdict) +void coroutine_fn hmp_block_resize(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); int64_t size = qdict_get_int(qdict, "size"); Error *err = NULL; - qmp_block_resize(true, device, false, NULL, size, &err); + qmp_block_resize(device, NULL, size, &err); hmp_handle_error(mon, err); } @@ -506,11 +500,10 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) const char *base = qdict_get_try_str(qdict, "base"); int64_t speed = qdict_get_try_int(qdict, "speed", 0); - qmp_block_stream(true, device, device, base != NULL, base, false, NULL, - false, NULL, false, NULL, - qdict_haskey(qdict, "speed"), speed, true, - BLOCKDEV_ON_ERROR_REPORT, false, NULL, false, false, false, - false, &error); + qmp_block_stream(device, device, base, NULL, NULL, NULL, + qdict_haskey(qdict, "speed"), speed, + true, BLOCKDEV_ON_ERROR_REPORT, NULL, + false, false, false, false, &error); hmp_handle_error(mon, error); } @@ -534,10 +527,8 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict) * version has only one, so we must decide which one to pass. */ if (blk_by_name(device)) { - throttle.has_device = true; throttle.device = device; } else { - throttle.has_id = true; throttle.id = device; } @@ -551,7 +542,7 @@ void hmp_eject(Monitor *mon, const QDict *qdict) const char *device = qdict_get_str(qdict, "device"); Error *err = NULL; - qmp_eject(true, device, false, NULL, true, force, &err); + qmp_eject(device, NULL, true, force, &err); hmp_handle_error(mon, err); } @@ -635,19 +626,19 @@ static void print_block_info(Monitor *mon, BlockInfo *info, { ImageInfo *image_info; - assert(!info || !info->has_inserted || info->inserted == inserted); + assert(!info || !info->inserted || info->inserted == inserted); if (info && *info->device) { - monitor_printf(mon, "%s", info->device); - if (inserted && inserted->has_node_name) { + monitor_puts(mon, info->device); + if (inserted && inserted->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->node_name ? inserted->node_name + : info && info->qdev ? info->qdev + : ""); } if (inserted) { @@ -661,7 +652,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, } if (info) { - if (info->has_qdev) { + if (info->qdev) { monitor_printf(mon, " Attached to: %s\n", info->qdev); } if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) { @@ -686,7 +677,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, inserted->cache->direct ? ", direct" : "", inserted->cache->no_flush ? ", ignore flushes" : ""); - if (inserted->has_backing_file) { + if (inserted->backing_file) { monitor_printf(mon, " Backing file: %s " "(chain depth: %" PRId64 ")\n", @@ -735,7 +726,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, image_info = inserted->image; while (1) { bdrv_image_info_dump(image_info); - if (image_info->has_backing_image) { + if (image_info->backing_image) { image_info = image_info->backing_image; } else { break; @@ -769,8 +760,7 @@ void hmp_info_block(Monitor *mon, const QDict *qdict) monitor_printf(mon, "\n"); } - print_block_info(mon, info->value, info->value->has_inserted - ? info->value->inserted : NULL, + print_block_info(mon, info->value, info->value->inserted, verbose); printed = true; } @@ -784,7 +774,7 @@ void hmp_info_block(Monitor *mon, const QDict *qdict) /* Print node information */ blockdev_list = qmp_query_named_block_nodes(false, false, NULL); for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) { - assert(blockdev->value->has_node_name); + assert(blockdev->value->node_name); if (device && strcmp(device, blockdev->value->node_name)) { continue; } @@ -805,7 +795,7 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict) stats_list = qmp_query_blockstats(false, false, NULL); for (stats = stats_list; stats; stats = stats->next) { - if (!stats->value->has_device) { + if (!stats->value->device) { continue; } diff --git a/block/nbd.c b/block/nbd.c index 567872ac5338..7d485c86d285 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -35,7 +35,6 @@ #include "qemu/option.h" #include "qemu/cutils.h" #include "qemu/main-loop.h" -#include "qemu/atomic.h" #include "qapi/qapi-visit-sockets.h" #include "qapi/qmp/qstring.h" @@ -58,7 +57,6 @@ typedef struct { Coroutine *coroutine; uint64_t offset; /* original offset of the request */ bool receiving; /* sleeping in the yield in nbd_receive_replies */ - bool reply_possible; /* reply header not yet received */ } NBDClientRequest; typedef enum NBDClientState { @@ -72,18 +70,29 @@ typedef struct BDRVNBDState { QIOChannel *ioc; /* The current I/O channel */ NBDExportInfo info; - CoMutex send_mutex; + /* + * Protects state, free_sema, in_flight, requests[].coroutine, + * reconnect_delay_timer. + */ + QemuMutex requests_lock; + NBDClientState state; CoQueue free_sema; + unsigned in_flight; + NBDClientRequest requests[MAX_NBD_REQUESTS]; + QEMUTimer *reconnect_delay_timer; + /* Protects sending data on the socket. */ + CoMutex send_mutex; + + /* + * Protects receiving reply headers from the socket, as well as the + * fields reply and requests[].receiving + */ CoMutex receive_mutex; - int in_flight; - NBDClientState state; + NBDReply reply; - QEMUTimer *reconnect_delay_timer; QEMUTimer *open_timer; - NBDClientRequest requests[MAX_NBD_REQUESTS]; - NBDReply reply; BlockDriverState *bs; /* Connection parameters */ @@ -128,12 +137,8 @@ static void nbd_clear_bdrvstate(BlockDriverState *bs) s->x_dirty_bitmap = NULL; } -static bool nbd_client_connected(BDRVNBDState *s) -{ - return qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTED; -} - -static bool nbd_recv_coroutine_wake_one(NBDClientRequest *req) +/* Called with s->receive_mutex taken. */ +static bool coroutine_fn nbd_recv_coroutine_wake_one(NBDClientRequest *req) { if (req->receiving) { req->receiving = false; @@ -144,33 +149,39 @@ static bool nbd_recv_coroutine_wake_one(NBDClientRequest *req) return false; } -static void nbd_recv_coroutines_wake(BDRVNBDState *s, bool all) +static void coroutine_fn nbd_recv_coroutines_wake(BDRVNBDState *s) { int i; + QEMU_LOCK_GUARD(&s->receive_mutex); for (i = 0; i < MAX_NBD_REQUESTS; i++) { - if (nbd_recv_coroutine_wake_one(&s->requests[i]) && !all) { + if (nbd_recv_coroutine_wake_one(&s->requests[i])) { return; } } } -static void nbd_channel_error(BDRVNBDState *s, int ret) +/* Called with s->requests_lock held. */ +static void coroutine_fn nbd_channel_error_locked(BDRVNBDState *s, int ret) { - if (nbd_client_connected(s)) { + if (s->state == NBD_CLIENT_CONNECTED) { qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); } if (ret == -EIO) { - if (nbd_client_connected(s)) { + if (s->state == NBD_CLIENT_CONNECTED) { s->state = s->reconnect_delay ? NBD_CLIENT_CONNECTING_WAIT : NBD_CLIENT_CONNECTING_NOWAIT; } } else { s->state = NBD_CLIENT_QUIT; } +} - nbd_recv_coroutines_wake(s, true); +static void coroutine_fn nbd_channel_error(BDRVNBDState *s, int ret) +{ + QEMU_LOCK_GUARD(&s->requests_lock); + nbd_channel_error_locked(s, ret); } static void reconnect_delay_timer_del(BDRVNBDState *s) @@ -185,23 +196,18 @@ static void reconnect_delay_timer_cb(void *opaque) { BDRVNBDState *s = opaque; - if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) { - s->state = NBD_CLIENT_CONNECTING_NOWAIT; - nbd_co_establish_connection_cancel(s->conn); - while (qemu_co_enter_next(&s->free_sema, NULL)) { - /* Resume all queued requests */ + reconnect_delay_timer_del(s); + WITH_QEMU_LOCK_GUARD(&s->requests_lock) { + if (s->state != NBD_CLIENT_CONNECTING_WAIT) { + return; } + s->state = NBD_CLIENT_CONNECTING_NOWAIT; } - - reconnect_delay_timer_del(s); + nbd_co_establish_connection_cancel(s->conn); } static void reconnect_delay_timer_init(BDRVNBDState *s, uint64_t expire_time_ns) { - if (qatomic_load_acquire(&s->state) != NBD_CLIENT_CONNECTING_WAIT) { - return; - } - assert(!s->reconnect_delay_timer); s->reconnect_delay_timer = aio_timer_new(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME, @@ -224,7 +230,9 @@ static void nbd_teardown_connection(BlockDriverState *bs) s->ioc = NULL; } - s->state = NBD_CLIENT_QUIT; + WITH_QEMU_LOCK_GUARD(&s->requests_lock) { + s->state = NBD_CLIENT_QUIT; + } } static void open_timer_del(BDRVNBDState *s) @@ -253,16 +261,13 @@ static void open_timer_init(BDRVNBDState *s, uint64_t expire_time_ns) timer_mod(s->open_timer, expire_time_ns); } -static bool nbd_client_connecting(BDRVNBDState *s) -{ - NBDClientState state = qatomic_load_acquire(&s->state); - return state == NBD_CLIENT_CONNECTING_WAIT || - state == NBD_CLIENT_CONNECTING_NOWAIT; -} - -static bool nbd_client_connecting_wait(BDRVNBDState *s) +static bool nbd_client_will_reconnect(BDRVNBDState *s) { - return qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT; + /* + * Called only after a socket error, so this is not performance sensitive. + */ + QEMU_LOCK_GUARD(&s->requests_lock); + return s->state == NBD_CLIENT_CONNECTING_WAIT; } /* @@ -311,11 +316,10 @@ static int nbd_handle_updated_info(BlockDriverState *bs, Error **errp) } int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs, - Error **errp) + bool blocking, Error **errp) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; int ret; - bool blocking = nbd_client_connecting_wait(s); IO_CODE(); assert(!s->ioc); @@ -350,35 +354,46 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs, qio_channel_attach_aio_context(s->ioc, bdrv_get_aio_context(bs)); /* successfully connected */ - s->state = NBD_CLIENT_CONNECTED; - qemu_co_queue_restart_all(&s->free_sema); + WITH_QEMU_LOCK_GUARD(&s->requests_lock) { + s->state = NBD_CLIENT_CONNECTED; + } return 0; } -/* called under s->send_mutex */ +/* Called with s->requests_lock held. */ +static bool nbd_client_connecting(BDRVNBDState *s) +{ + return s->state == NBD_CLIENT_CONNECTING_WAIT || + s->state == NBD_CLIENT_CONNECTING_NOWAIT; +} + +/* Called with s->requests_lock taken. */ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) { + int ret; + bool blocking = s->state == NBD_CLIENT_CONNECTING_WAIT; + + /* + * Now we are sure that nobody is accessing the channel, and no one will + * try until we set the state to CONNECTED. + */ assert(nbd_client_connecting(s)); - assert(s->in_flight == 0); + assert(s->in_flight == 1); - if (nbd_client_connecting_wait(s) && s->reconnect_delay && - !s->reconnect_delay_timer) - { + trace_nbd_reconnect_attempt(s->bs->in_flight); + + if (blocking && !s->reconnect_delay_timer) { /* - * It's first reconnect attempt after switching to + * It's the first reconnect attempt after switching to * NBD_CLIENT_CONNECTING_WAIT */ + g_assert(s->reconnect_delay); reconnect_delay_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->reconnect_delay * NANOSECONDS_PER_SECOND); } - /* - * Now we are sure that nobody is accessing the channel, and no one will - * try until we set the state to CONNECTED. - */ - /* Finalize previous connection if any */ if (s->ioc) { qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc)); @@ -388,7 +403,10 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) s->ioc = NULL; } - nbd_co_do_establish_connection(s->bs, NULL); + qemu_mutex_unlock(&s->requests_lock); + ret = nbd_co_do_establish_connection(s->bs, blocking, NULL); + trace_nbd_reconnect_attempt_result(ret, s->bs->in_flight); + qemu_mutex_lock(&s->requests_lock); /* * The reconnect attempt is done (maybe successfully, maybe not), so @@ -410,10 +428,6 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle) return 0; } - if (!nbd_client_connected(s)) { - return -EIO; - } - if (s->reply.handle != 0) { /* * Some other request is being handled now. It should already be @@ -428,11 +442,10 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle) qemu_coroutine_yield(); /* - * We may be woken for 3 reasons: + * We may be woken for 2 reasons: * 1. From this function, executing in parallel coroutine, when our * handle is received. - * 2. From nbd_channel_error(), when connection is lost. - * 3. From nbd_co_receive_one_chunk(), when previous request is + * 2. From nbd_co_receive_one_chunk(), when previous request is * finished and s->reply.handle set to 0. * Anyway, it's OK to lock the mutex and go to the next iteration. */ @@ -454,44 +467,43 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle) nbd_channel_error(s, -EINVAL); return -EINVAL; } - if (s->reply.handle == handle) { - /* We are done */ - return 0; - } ind2 = HANDLE_TO_INDEX(s, s->reply.handle); - if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].reply_possible) { + if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) { nbd_channel_error(s, -EINVAL); return -EINVAL; } + if (s->reply.handle == handle) { + /* We are done */ + return 0; + } nbd_recv_coroutine_wake_one(&s->requests[ind2]); } } -static int nbd_co_send_request(BlockDriverState *bs, - NBDRequest *request, - QEMUIOVector *qiov) +static int coroutine_fn nbd_co_send_request(BlockDriverState *bs, + NBDRequest *request, + QEMUIOVector *qiov) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; int rc, i = -1; - qemu_co_mutex_lock(&s->send_mutex); - + qemu_mutex_lock(&s->requests_lock); while (s->in_flight == MAX_NBD_REQUESTS || - (!nbd_client_connected(s) && s->in_flight > 0)) - { - qemu_co_queue_wait(&s->free_sema, &s->send_mutex); - } - - if (nbd_client_connecting(s)) { - nbd_reconnect_attempt(s); - } - - if (!nbd_client_connected(s)) { - rc = -EIO; - goto err; + (s->state != NBD_CLIENT_CONNECTED && s->in_flight > 0)) { + qemu_co_queue_wait(&s->free_sema, &s->requests_lock); } s->in_flight++; + if (s->state != NBD_CLIENT_CONNECTED) { + if (nbd_client_connecting(s)) { + nbd_reconnect_attempt(s); + qemu_co_queue_restart_all(&s->free_sema); + } + if (s->state != NBD_CLIENT_CONNECTED) { + rc = -EIO; + goto err; + } + } for (i = 0; i < MAX_NBD_REQUESTS; i++) { if (s->requests[i].coroutine == NULL) { @@ -499,14 +511,13 @@ static int nbd_co_send_request(BlockDriverState *bs, } } - g_assert(qemu_in_coroutine()); assert(i < MAX_NBD_REQUESTS); - s->requests[i].coroutine = qemu_coroutine_self(); s->requests[i].offset = request->from; s->requests[i].receiving = false; - s->requests[i].reply_possible = true; + qemu_mutex_unlock(&s->requests_lock); + qemu_co_mutex_lock(&s->send_mutex); request->handle = INDEX_TO_HANDLE(s, i); assert(s->ioc); @@ -514,29 +525,27 @@ static int nbd_co_send_request(BlockDriverState *bs, if (qiov) { qio_channel_set_cork(s->ioc, true); rc = nbd_send_request(s->ioc, request); - if (nbd_client_connected(s) && rc >= 0) { - if (qio_channel_writev_all(s->ioc, qiov->iov, qiov->niov, - NULL) < 0) { - rc = -EIO; - } - } else if (rc >= 0) { + if (rc >= 0 && qio_channel_writev_all(s->ioc, qiov->iov, qiov->niov, + NULL) < 0) { rc = -EIO; } qio_channel_set_cork(s->ioc, false); } else { rc = nbd_send_request(s->ioc, request); } + qemu_co_mutex_unlock(&s->send_mutex); -err: if (rc < 0) { - nbd_channel_error(s, rc); + qemu_mutex_lock(&s->requests_lock); +err: + nbd_channel_error_locked(s, rc); if (i != -1) { s->requests[i].coroutine = NULL; - s->in_flight--; } + s->in_flight--; qemu_co_queue_next(&s->free_sema); + qemu_mutex_unlock(&s->requests_lock); } - qemu_co_mutex_unlock(&s->send_mutex); return rc; } @@ -723,9 +732,9 @@ static int nbd_parse_error_payload(NBDStructuredReplyChunk *chunk, return 0; } -static int nbd_co_receive_offset_data_payload(BDRVNBDState *s, - uint64_t orig_offset, - QEMUIOVector *qiov, Error **errp) +static int coroutine_fn +nbd_co_receive_offset_data_payload(BDRVNBDState *s, uint64_t orig_offset, + QEMUIOVector *qiov, Error **errp) { QEMUIOVector sub_qiov; uint64_t offset; @@ -831,8 +840,8 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( } *request_ret = 0; - nbd_receive_replies(s, handle); - if (!nbd_client_connected(s)) { + ret = nbd_receive_replies(s, handle); + if (ret < 0) { error_setg(errp, "Connection closed"); return -EIO; } @@ -924,7 +933,7 @@ static coroutine_fn int nbd_co_receive_one_chunk( } s->reply.handle = 0; - nbd_recv_coroutines_wake(s, false); + nbd_recv_coroutines_wake(s); return ret; } @@ -974,21 +983,17 @@ 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; NBDStructuredReplyChunk *chunk; Error *local_err = NULL; - if (!nbd_client_connected(s)) { - error_setg(&local_err, "Connection closed"); - nbd_iter_channel_error(iter, -EIO, &local_err); - goto break_loop; - } if (iter->done) { /* Previous iteration was last. */ @@ -1009,7 +1014,7 @@ static bool nbd_reply_chunk_iter_receive(BDRVNBDState *s, } /* Do not execute the body of NBD_FOREACH_REPLY_CHUNK for simple reply. */ - if (nbd_reply_is_simple(reply) || !nbd_client_connected(s)) { + if (nbd_reply_is_simple(reply) || iter->ret < 0) { goto break_loop; } @@ -1031,18 +1036,17 @@ static bool nbd_reply_chunk_iter_receive(BDRVNBDState *s, return true; break_loop: + qemu_mutex_lock(&s->requests_lock); s->requests[HANDLE_TO_INDEX(s, handle)].coroutine = NULL; - - qemu_co_mutex_lock(&s->send_mutex); s->in_flight--; qemu_co_queue_next(&s->free_sema); - qemu_co_mutex_unlock(&s->send_mutex); + qemu_mutex_unlock(&s->requests_lock); return false; } -static int nbd_co_receive_return_code(BDRVNBDState *s, uint64_t handle, - int *request_ret, Error **errp) +static int coroutine_fn nbd_co_receive_return_code(BDRVNBDState *s, uint64_t handle, + int *request_ret, Error **errp) { NBDReplyChunkIter iter; @@ -1055,9 +1059,9 @@ static int nbd_co_receive_return_code(BDRVNBDState *s, uint64_t handle, return iter.ret; } -static int nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t handle, - uint64_t offset, QEMUIOVector *qiov, - int *request_ret, Error **errp) +static int coroutine_fn nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t handle, + uint64_t offset, QEMUIOVector *qiov, + int *request_ret, Error **errp) { NBDReplyChunkIter iter; NBDReply reply; @@ -1107,10 +1111,10 @@ static int nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t handle, return iter.ret; } -static int nbd_co_receive_blockstatus_reply(BDRVNBDState *s, - uint64_t handle, uint64_t length, - NBDExtent *extent, - int *request_ret, Error **errp) +static int coroutine_fn nbd_co_receive_blockstatus_reply(BDRVNBDState *s, + uint64_t handle, uint64_t length, + NBDExtent *extent, + int *request_ret, Error **errp) { NBDReplyChunkIter iter; NBDReply reply; @@ -1167,8 +1171,8 @@ static int nbd_co_receive_blockstatus_reply(BDRVNBDState *s, return iter.ret; } -static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, - QEMUIOVector *write_qiov) +static int coroutine_fn nbd_co_request(BlockDriverState *bs, NBDRequest *request, + QEMUIOVector *write_qiov) { int ret, request_ret; Error *local_err = NULL; @@ -1199,14 +1203,14 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, error_free(local_err); local_err = NULL; } - } while (ret < 0 && nbd_client_connecting_wait(s)); + } while (ret < 0 && nbd_client_will_reconnect(s)); return ret ? ret : request_ret; } -static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset, - int64_t bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +static int coroutine_fn nbd_client_co_preadv(BlockDriverState *bs, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) { int ret, request_ret; Error *local_err = NULL; @@ -1218,7 +1222,6 @@ static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset, }; assert(bytes <= NBD_MAX_BUFFER_SIZE); - assert(!flags); if (!bytes) { return 0; @@ -1258,14 +1261,14 @@ static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset, error_free(local_err); local_err = NULL; } - } while (ret < 0 && nbd_client_connecting_wait(s)); + } while (ret < 0 && nbd_client_will_reconnect(s)); return ret ? ret : request_ret; } -static int nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset, - int64_t bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +static int coroutine_fn nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; NBDRequest request = { @@ -1288,8 +1291,8 @@ static int nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset, return nbd_co_request(bs, &request, qiov); } -static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, - int64_t bytes, BdrvRequestFlags flags) +static int coroutine_fn nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, + int64_t bytes, BdrvRequestFlags flags) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; NBDRequest request = { @@ -1323,7 +1326,7 @@ static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, return nbd_co_request(bs, &request, NULL); } -static int nbd_client_co_flush(BlockDriverState *bs) +static int coroutine_fn nbd_client_co_flush(BlockDriverState *bs) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; NBDRequest request = { .type = NBD_CMD_FLUSH }; @@ -1338,8 +1341,8 @@ static int nbd_client_co_flush(BlockDriverState *bs) return nbd_co_request(bs, &request, NULL); } -static int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, - int64_t bytes) +static int coroutine_fn nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, + int64_t bytes) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; NBDRequest request = { @@ -1416,7 +1419,7 @@ static int coroutine_fn nbd_client_co_block_status( error_free(local_err); local_err = NULL; } - } while (ret < 0 && nbd_client_connecting_wait(s)); + } while (ret < 0 && nbd_client_will_reconnect(s)); if (ret < 0 || request_ret < 0) { return ret ? ret : request_ret; @@ -1448,8 +1451,9 @@ static void nbd_yank(void *opaque) BlockDriverState *bs = opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque; - qatomic_store_release(&s->state, NBD_CLIENT_QUIT); + QEMU_LOCK_GUARD(&s->requests_lock); qio_channel_shutdown(QIO_CHANNEL(s->ioc), QIO_CHANNEL_SHUTDOWN_BOTH, NULL); + s->state = NBD_CLIENT_QUIT; } static void nbd_client_close(BlockDriverState *bs) @@ -1869,8 +1873,9 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, BDRVNBDState *s = (BDRVNBDState *)bs->opaque; s->bs = bs; - qemu_co_mutex_init(&s->send_mutex); + qemu_mutex_init(&s->requests_lock); qemu_co_queue_init(&s->free_sema); + qemu_co_mutex_init(&s->send_mutex); qemu_co_mutex_init(&s->receive_mutex); if (!yank_register_instance(BLOCKDEV_YANK_INSTANCE(bs->node_name), errp)) { @@ -1893,7 +1898,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, } s->state = NBD_CLIENT_CONNECTING_WAIT; - ret = nbd_do_establish_connection(bs, errp); + ret = nbd_do_establish_connection(bs, true, errp); if (ret < 0) { goto fail; } @@ -1915,7 +1920,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, return ret; } -static int nbd_co_flush(BlockDriverState *bs) +static int coroutine_fn nbd_co_flush(BlockDriverState *bs) { return nbd_client_co_flush(bs); } @@ -2057,10 +2062,11 @@ static void nbd_cancel_in_flight(BlockDriverState *bs) reconnect_delay_timer_del(s); + qemu_mutex_lock(&s->requests_lock); if (s->state == NBD_CLIENT_CONNECTING_WAIT) { s->state = NBD_CLIENT_CONNECTING_NOWAIT; - qemu_co_queue_restart_all(&s->free_sema); } + qemu_mutex_unlock(&s->requests_lock); nbd_co_establish_connection_cancel(s->conn); } diff --git a/block/nfs.c b/block/nfs.c index 444c40b458d9..ece22353ac53 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(), @@ -418,7 +418,11 @@ static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts, int flags, int open_flags, Error **errp) { int64_t ret = -EINVAL; +#ifdef _WIN32 + struct __stat64 st; +#else struct stat st; +#endif char *file = NULL, *strp = NULL; qemu_mutex_init(&client->mutex); @@ -781,7 +785,11 @@ static int nfs_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, Error **errp) { NFSClient *client = state->bs->opaque; +#ifdef _WIN32 + struct __stat64 st; +#else struct stat st; +#endif int ret = 0; if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) { diff --git a/block/nvme.c b/block/nvme.c index 552029931d59..656624c585a2 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -169,9 +169,9 @@ static bool nvme_init_queue(BDRVNVMeState *s, NVMeQueue *q, size_t bytes; int r; - bytes = ROUND_UP(nentries * entry_bytes, qemu_real_host_page_size); + bytes = ROUND_UP(nentries * entry_bytes, qemu_real_host_page_size()); q->head = q->tail = 0; - q->queue = qemu_try_memalign(qemu_real_host_page_size, bytes); + q->queue = qemu_try_memalign(qemu_real_host_page_size(), bytes); if (!q->queue) { error_setg(errp, "Cannot allocate queue"); return false; @@ -232,8 +232,8 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s, trace_nvme_create_queue_pair(idx, q, size, aio_context, event_notifier_get_fd(s->irq_notifier)); bytes = QEMU_ALIGN_UP(s->page_size * NVME_NUM_REQS, - qemu_real_host_page_size); - q->prp_list_pages = qemu_try_memalign(qemu_real_host_page_size, bytes); + qemu_real_host_page_size()); + q->prp_list_pages = qemu_try_memalign(qemu_real_host_page_size(), bytes); if (!q->prp_list_pages) { error_setg(errp, "Cannot allocate PRP page list"); goto fail; @@ -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; } @@ -533,9 +541,9 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp) .opcode = NVME_ADM_CMD_IDENTIFY, .cdw10 = cpu_to_le32(0x1), }; - size_t id_size = QEMU_ALIGN_UP(sizeof(*id), qemu_real_host_page_size); + size_t id_size = QEMU_ALIGN_UP(sizeof(*id), qemu_real_host_page_size()); - id = qemu_try_memalign(qemu_real_host_page_size, id_size); + id = qemu_try_memalign(qemu_real_host_page_size(), id_size); if (!id) { error_setg(errp, "Cannot allocate buffer for identify response"); goto out; @@ -1048,7 +1056,7 @@ static coroutine_fn int nvme_cmd_map_qiov(BlockDriverState *bs, NvmeCmd *cmd, bool retry = true; uint64_t iova; size_t len = QEMU_ALIGN_UP(qiov->iov[i].iov_len, - qemu_real_host_page_size); + qemu_real_host_page_size()); try_map: r = qemu_vfio_dma_map(s->vfio, qiov->iov[i].iov_base, @@ -1224,8 +1232,8 @@ static inline bool nvme_qiov_aligned(BlockDriverState *bs, for (i = 0; i < qiov->niov; ++i) { if (!QEMU_PTR_IS_ALIGNED(qiov->iov[i].iov_base, - qemu_real_host_page_size) || - !QEMU_IS_ALIGNED(qiov->iov[i].iov_len, qemu_real_host_page_size)) { + qemu_real_host_page_size()) || + !QEMU_IS_ALIGNED(qiov->iov[i].iov_len, qemu_real_host_page_size())) { trace_nvme_qiov_unaligned(qiov, i, qiov->iov[i].iov_base, qiov->iov[i].iov_len, s->page_size); return false; @@ -1234,14 +1242,16 @@ 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; QEMU_AUTO_VFREE uint8_t *buf = NULL; QEMUIOVector local_qiov; - size_t len = QEMU_ALIGN_UP(bytes, qemu_real_host_page_size); + size_t len = QEMU_ALIGN_UP(bytes, qemu_real_host_page_size()); assert(QEMU_IS_ALIGNED(offset, s->page_size)); assert(QEMU_IS_ALIGNED(bytes, s->page_size)); assert(bytes <= s->max_transfer); @@ -1251,7 +1261,7 @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, } s->stats.unaligned_accesses++; trace_nvme_prw_buffered(s, offset, bytes, qiov->niov, is_write); - buf = qemu_try_memalign(qemu_real_host_page_size, len); + buf = qemu_try_memalign(qemu_real_host_page_size(), len); if (!buf) { return -ENOMEM; @@ -1577,22 +1587,22 @@ static void nvme_aio_unplug(BlockDriverState *bs) } } -static void nvme_register_buf(BlockDriverState *bs, void *host, size_t size) +static bool nvme_register_buf(BlockDriverState *bs, void *host, size_t size, + Error **errp) { int ret; - Error *local_err = NULL; BDRVNVMeState *s = bs->opaque; - ret = qemu_vfio_dma_map(s->vfio, host, size, false, NULL, &local_err); - if (ret) { - /* FIXME: we may run out of IOVA addresses after repeated - * bdrv_register_buf/bdrv_unregister_buf, because nvme_vfio_dma_unmap - * doesn't reclaim addresses for fixed mappings. */ - error_reportf_err(local_err, "nvme_register_buf failed: "); - } + /* + * FIXME: we may run out of IOVA addresses after repeated + * bdrv_register_buf/bdrv_unregister_buf, because nvme_vfio_dma_unmap + * doesn't reclaim addresses for fixed mappings. + */ + ret = qemu_vfio_dma_map(s->vfio, host, size, false, NULL, errp); + return ret == 0; } -static void nvme_unregister_buf(BlockDriverState *bs, void *host) +static void nvme_unregister_buf(BlockDriverState *bs, void *host, size_t size) { BDRVNVMeState *s = bs->opaque; diff --git a/block/parallels-ext.c b/block/parallels-ext.c index 5122f67ac28f..c9dbbf5089e5 100644 --- a/block/parallels-ext.c +++ b/block/parallels-ext.c @@ -93,8 +93,8 @@ static int parallels_load_bitmap_data(BlockDriverState *bs, if (entry == 1) { bdrv_dirty_bitmap_deserialize_ones(bitmap, offset, count, false); } else { - ret = bdrv_pread(bs->file, entry << BDRV_SECTOR_BITS, buf, - s->cluster_size); + ret = bdrv_pread(bs->file, entry << BDRV_SECTOR_BITS, + s->cluster_size, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read bitmap data cluster"); @@ -286,7 +286,7 @@ int parallels_read_format_extension(BlockDriverState *bs, assert(ext_off > 0); - ret = bdrv_pread(bs->file, ext_off, ext_cluster, s->cluster_size); + ret = bdrv_pread(bs->file, ext_off, s->cluster_size, ext_cluster, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read Format Extension cluster"); goto out; diff --git a/block/parallels.c b/block/parallels.c index cd23e02d06c1..bbea2f2221ff 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; @@ -204,18 +205,18 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, * force the safer-but-slower fallocate. */ if (s->prealloc_mode == PRL_PREALLOC_MODE_TRUNCATE) { - ret = bdrv_truncate(bs->file, - (s->data_end + space) << BDRV_SECTOR_BITS, - false, PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, - NULL); + ret = bdrv_co_truncate(bs->file, + (s->data_end + space) << BDRV_SECTOR_BITS, + false, PREALLOC_MODE_OFF, + BDRV_REQ_ZERO_WRITE, NULL); if (ret == -ENOTSUP) { s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; } } if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) { - ret = bdrv_pwrite_zeroes(bs->file, - s->data_end << BDRV_SECTOR_BITS, - space << BDRV_SECTOR_BITS, 0); + ret = bdrv_co_pwrite_zeroes(bs->file, + s->data_end << BDRV_SECTOR_BITS, + space << BDRV_SECTOR_BITS, 0); } if (ret < 0) { return ret; @@ -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; @@ -277,8 +278,8 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs) if (off + to_write > s->header_size) { to_write = s->header_size - off; } - ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off, - to_write); + ret = bdrv_co_pwrite(bs->file, off, to_write, + (uint8_t *)s->header + off, 0); if (ret < 0) { qemu_co_mutex_unlock(&s->lock); return ret; @@ -328,7 +329,6 @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs, QEMUIOVector hd_qiov; int ret = 0; - assert(!flags); qemu_iovec_init(&hd_qiov, qiov->niov); while (nb_sectors > 0) { @@ -481,7 +481,7 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs, ret = 0; if (flush_bat) { - ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size); + ret = bdrv_co_pwrite_sync(bs->file, 0, s->header_size, s->header, 0); if (ret < 0) { res->check_errors++; goto out; @@ -503,8 +503,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs, * In order to really repair the image, we must shrink it. * That means we have to pass exact=true. */ - ret = bdrv_truncate(bs->file, res->image_end_offset, true, - PREALLOC_MODE_OFF, 0, &local_err); + ret = bdrv_co_truncate(bs->file, res->image_end_offset, true, + PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); res->check_errors++; @@ -599,12 +599,12 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts, memset(tmp, 0, sizeof(tmp)); memcpy(tmp, &header, sizeof(header)); - ret = blk_pwrite(blk, 0, tmp, BDRV_SECTOR_SIZE, 0); + ret = blk_co_pwrite(blk, 0, BDRV_SECTOR_SIZE, tmp, 0); if (ret < 0) { goto exit; } - ret = blk_pwrite_zeroes(blk, BDRV_SECTOR_SIZE, - (bat_sectors - 1) << BDRV_SECTOR_BITS, 0); + ret = blk_co_pwrite_zeroes(blk, BDRV_SECTOR_SIZE, + (bat_sectors - 1) << BDRV_SECTOR_BITS, 0); if (ret < 0) { goto exit; } @@ -646,7 +646,7 @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto done; } @@ -723,7 +723,7 @@ static int parallels_update_header(BlockDriverState *bs) if (size > s->header_size) { size = s->header_size; } - return bdrv_pwrite_sync(bs->file, 0, s->header, size); + return bdrv_pwrite_sync(bs->file, 0, size, s->header, 0); } static int parallels_open(BlockDriverState *bs, QDict *options, int flags, @@ -736,13 +736,12 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; char *buf; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } - ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph)); + ret = bdrv_pread(bs->file, 0, sizeof(ph), &ph, 0); if (ret < 0) { goto fail; } @@ -798,7 +797,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, s->header_size = size; } - ret = bdrv_pread(bs->file, 0, s->header, s->header_size); + ret = bdrv_pread(bs->file, 0, s->header_size, s->header, 0); if (ret < 0) { goto fail; } @@ -870,7 +869,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, } } - s->bat_dirty_block = 4 * qemu_real_host_page_size; + s->bat_dirty_block = 4 * qemu_real_host_page_size(); s->bat_dirty_bmap = bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); diff --git a/block/preallocate.c b/block/preallocate.c index e15cb8c74aae..d50ee7f49b57 100644 --- a/block/preallocate.c +++ b/block/preallocate.c @@ -134,6 +134,7 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVPreallocateState *s = bs->opaque; + int ret; /* * s->data_end and friends should be initialized on permission update. @@ -141,11 +142,9 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, */ s->file_end = s->zero_start = s->data_end = -EINVAL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) { diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c index 8498402ad43d..0c7a1423debd 100644 --- a/block/qapi-sysemu.c +++ b/block/qapi-sysemu.c @@ -116,8 +116,8 @@ static int do_open_tray(const char *blk_name, const char *qdev_id, return 0; } -void qmp_blockdev_open_tray(bool has_device, const char *device, - bool has_id, const char *id, +void qmp_blockdev_open_tray(const char *device, + const char *id, bool has_force, bool force, Error **errp) { @@ -127,9 +127,7 @@ void qmp_blockdev_open_tray(bool has_device, const char *device, if (!has_force) { force = false; } - rc = do_open_tray(has_device ? device : NULL, - has_id ? id : NULL, - force, &local_err); + rc = do_open_tray(device, id, force, &local_err); if (rc && rc != -ENOSYS && rc != -EINPROGRESS) { error_propagate(errp, local_err); return; @@ -137,16 +135,13 @@ void qmp_blockdev_open_tray(bool has_device, const char *device, error_free(local_err); } -void qmp_blockdev_close_tray(bool has_device, const char *device, - bool has_id, const char *id, +void qmp_blockdev_close_tray(const char *device, + const char *id, Error **errp) { BlockBackend *blk; Error *local_err = NULL; - device = has_device ? device : NULL; - id = has_id ? id : NULL; - blk = qmp_get_blk(device, id, errp); if (!blk) { return; @@ -173,17 +168,14 @@ void qmp_blockdev_close_tray(bool has_device, const char *device, } } -static void blockdev_remove_medium(bool has_device, const char *device, - bool has_id, const char *id, Error **errp) +static void blockdev_remove_medium(const char *device, const char *id, + Error **errp) { BlockBackend *blk; BlockDriverState *bs; AioContext *aio_context; bool has_attached_device; - device = has_device ? device : NULL; - id = has_id ? id : NULL; - blk = qmp_get_blk(device, id, errp); if (!blk) { return; @@ -232,7 +224,7 @@ static void blockdev_remove_medium(bool has_device, const char *device, void qmp_blockdev_remove_medium(const char *id, Error **errp) { - blockdev_remove_medium(false, NULL, true, id, errp); + blockdev_remove_medium(NULL, id, errp); } static void qmp_blockdev_insert_anon_medium(BlockBackend *blk, @@ -280,16 +272,13 @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk, } } -static void blockdev_insert_medium(bool has_device, const char *device, - bool has_id, const char *id, +static void blockdev_insert_medium(const char *device, const char *id, const char *node_name, Error **errp) { BlockBackend *blk; BlockDriverState *bs; - blk = qmp_get_blk(has_device ? device : NULL, - has_id ? id : NULL, - errp); + blk = qmp_get_blk(device, id, errp); if (!blk) { return; } @@ -311,13 +300,14 @@ static void blockdev_insert_medium(bool has_device, const char *device, void qmp_blockdev_insert_medium(const char *id, const char *node_name, Error **errp) { - blockdev_insert_medium(false, NULL, true, id, node_name, errp); + blockdev_insert_medium(NULL, id, node_name, errp); } -void qmp_blockdev_change_medium(bool has_device, const char *device, - bool has_id, const char *id, +void qmp_blockdev_change_medium(const char *device, + const char *id, const char *filename, - bool has_format, const char *format, + const char *format, + bool has_force, bool force, bool has_read_only, BlockdevChangeReadOnlyMode read_only, Error **errp) @@ -330,9 +320,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, QDict *options = NULL; Error *err = NULL; - blk = qmp_get_blk(has_device ? device : NULL, - has_id ? id : NULL, - errp); + blk = qmp_get_blk(device, id, errp); if (!blk) { goto fail; } @@ -369,7 +357,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, detect_zeroes = blk_get_detect_zeroes_from_root_state(blk); qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off"); - if (has_format) { + if (format) { qdict_put_str(options, "driver", format); } @@ -378,9 +366,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, goto fail; } - rc = do_open_tray(has_device ? device : NULL, - has_id ? id : NULL, - false, &err); + rc = do_open_tray(device, id, force, &err); if (rc && rc != -ENOSYS) { error_propagate(errp, err); goto fail; @@ -388,7 +374,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, error_free(err); err = NULL; - blockdev_remove_medium(has_device, device, has_id, id, &err); + blockdev_remove_medium(device, id, &err); if (err) { error_propagate(errp, err); goto fail; @@ -400,7 +386,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, goto fail; } - qmp_blockdev_close_tray(has_device, device, has_id, id, errp); + qmp_blockdev_close_tray(device, id, errp); fail: /* If the medium has been inserted, the device has its own reference, so @@ -409,8 +395,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, bdrv_unref(medium_bs); } -void qmp_eject(bool has_device, const char *device, - bool has_id, const char *id, +void qmp_eject(const char *device, const char *id, bool has_force, bool force, Error **errp) { Error *local_err = NULL; @@ -420,16 +405,14 @@ void qmp_eject(bool has_device, const char *device, force = false; } - rc = do_open_tray(has_device ? device : NULL, - has_id ? id : NULL, - force, &local_err); + rc = do_open_tray(device, id, force, &local_err); if (rc && rc != -ENOSYS) { error_propagate(errp, local_err); return; } error_free(local_err); - blockdev_remove_medium(has_device, device, has_id, id, errp); + blockdev_remove_medium(device, id, errp); } /* throttling disk I/O limits */ @@ -440,9 +423,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) BlockBackend *blk; AioContext *aio_context; - blk = qmp_get_blk(arg->has_device ? arg->device : NULL, - arg->has_id ? arg->id : NULL, - errp); + blk = qmp_get_blk(arg->device, arg->id, errp); if (!blk) { return; } @@ -515,11 +496,8 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) /* Enable I/O limits if they're not enabled yet, otherwise * just update the throttling group. */ if (!blk_get_public(blk)->throttle_group_member.throttle_state) { - blk_io_limits_enable(blk, - arg->has_group ? arg->group : - arg->has_device ? arg->device : - arg->id); - } else if (arg->has_group) { + blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id); + } else if (arg->group) { blk_io_limits_update_group(blk, arg->group); } /* Set the new throttling configuration */ diff --git a/block/qapi.c b/block/qapi.c index cf557e3aea7c..fea808425b4e 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -71,13 +71,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, }; if (bs->node_name[0]) { - info->has_node_name = true; info->node_name = g_strdup(bs->node_name); } backing = bdrv_cow_bs(bs); if (backing) { - info->has_backing_file = true; info->backing_file = g_strdup(backing->filename); } @@ -139,7 +137,6 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, info->has_iops_size = cfg.op_size; info->iops_size = cfg.op_size; - info->has_group = true; info->group = g_strdup(throttle_group_get_name(&blkp->throttle_group_member)); } @@ -170,7 +167,6 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, */ info->backing_file_depth++; bs0 = bdrv_filter_or_cow_bs(bs0); - (*p_image_info)->has_backing_image = true; p_image_info = &((*p_image_info)->backing_image); } else { break; @@ -301,26 +297,21 @@ void bdrv_query_image_info(BlockDriverState *bs, qapi_free_ImageInfo(info); goto out; } - info->has_format_specific = info->format_specific != NULL; - backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { char *backing_filename2; info->backing_filename = g_strdup(backing_filename); - info->has_backing_filename = true; backing_filename2 = bdrv_get_full_backing_filename(bs, NULL); /* Always report the full_backing_filename if present, even if it's the * same as backing_filename. That they are same is useful info. */ if (backing_filename2) { info->full_backing_filename = g_strdup(backing_filename2); - info->has_full_backing_filename = true; } if (bs->backing_format[0]) { info->backing_filename_format = g_strdup(bs->backing_format); - info->has_backing_filename_format = true; } g_free(backing_filename2); } @@ -367,7 +358,6 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, qdev = blk_get_attached_dev_id(blk); if (qdev && *qdev) { - info->has_qdev = true; info->qdev = qdev; } else { g_free(qdev); @@ -384,7 +374,6 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, } if (bs && bs->drv) { - info->has_inserted = true; info->inserted = bdrv_block_device_info(blk, bs, false, errp); if (info->inserted == NULL) { goto err; @@ -411,23 +400,26 @@ static uint64List *uint64_list(uint64_t *list, int size) return out_list; } -static void bdrv_latency_histogram_stats(BlockLatencyHistogram *hist, - bool *not_null, - BlockLatencyHistogramInfo **info) +static BlockLatencyHistogramInfo * +bdrv_latency_histogram_stats(BlockLatencyHistogram *hist) { - *not_null = hist->bins != NULL; - if (*not_null) { - *info = g_new0(BlockLatencyHistogramInfo, 1); + BlockLatencyHistogramInfo *info; - (*info)->boundaries = uint64_list(hist->boundaries, hist->nbins - 1); - (*info)->bins = uint64_list(hist->bins, hist->nbins); + if (!hist->bins) { + return NULL; } + + info = g_new0(BlockLatencyHistogramInfo, 1); + info->boundaries = uint64_list(hist->boundaries, hist->nbins - 1); + info->bins = uint64_list(hist->bins, hist->nbins); + return info; } static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) { BlockAcctStats *stats = blk_get_stats(blk); BlockAcctTimedStats *ts = NULL; + BlockLatencyHistogram *hgram; ds->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ]; ds->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE]; @@ -493,15 +485,13 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) QAPI_LIST_PREPEND(ds->timed_stats, dev_stats); } - bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_READ], - &ds->has_rd_latency_histogram, - &ds->rd_latency_histogram); - bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_WRITE], - &ds->has_wr_latency_histogram, - &ds->wr_latency_histogram); - bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_FLUSH], - &ds->has_flush_latency_histogram, - &ds->flush_latency_histogram); + hgram = stats->latency_histogram; + ds->rd_latency_histogram + = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_READ]); + ds->wr_latency_histogram + = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_WRITE]); + ds->flush_latency_histogram + = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_FLUSH]); } static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs, @@ -526,16 +516,12 @@ static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs, } if (bdrv_get_node_name(bs)[0]) { - s->has_node_name = true; s->node_name = g_strdup(bdrv_get_node_name(bs)); } s->stats->wr_highest_offset = stat64_get(&bs->wr_highest_offset); s->driver_specific = bdrv_get_specific_stats(bs); - if (s->driver_specific) { - s->has_driver_specific = true; - } parent_child = bdrv_primary_child(bs); if (!parent_child || @@ -564,7 +550,6 @@ static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs, } } if (parent_child) { - s->has_parent = true; s->parent = bdrv_query_bds_stats(parent_child->bs, blk_level); } @@ -575,7 +560,6 @@ static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs, * compatibility to when we put bs0->backing here, which might * be either) */ - s->has_backing = true; s->backing = bdrv_query_bds_stats(filter_or_cow_bs, blk_level); } @@ -640,12 +624,10 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes, aio_context_acquire(ctx); s = bdrv_query_bds_stats(blk_bs(blk), true); - s->has_device = true; s->device = g_strdup(blk_name(blk)); qdev = blk_get_attached_dev_id(blk); if (qdev && *qdev) { - s->has_qdev = true; s->qdev = qdev; } else { g_free(qdev); @@ -822,16 +804,16 @@ void bdrv_image_info_dump(ImageInfo *info) qemu_printf("cleanly shut down: no\n"); } - if (info->has_backing_filename) { + if (info->backing_filename) { qemu_printf("backing file: %s", info->backing_filename); - if (!info->has_full_backing_filename) { + if (!info->full_backing_filename) { qemu_printf(" (cannot determine actual path)"); } else if (strcmp(info->backing_filename, info->full_backing_filename) != 0) { qemu_printf(" (actual path: %s)", info->full_backing_filename); } qemu_printf("\n"); - if (info->has_backing_filename_format) { + if (info->backing_filename_format) { qemu_printf("backing file format: %s\n", info->backing_filename_format); } @@ -865,7 +847,7 @@ void bdrv_image_info_dump(ImageInfo *info) } } - if (info->has_format_specific) { + if (info->format_specific) { qemu_printf("Format specific information:\n"); bdrv_image_info_specific_dump(info->format_specific); } diff --git a/block/qcow.c b/block/qcow.c index 4fba1b9e3647..5d99f00411f7 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -92,7 +92,8 @@ typedef struct BDRVQcowState { static QemuOptsList qcow_create_opts; -static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); +static int coroutine_fn decompress_cluster(BlockDriverState *bs, + uint64_t cluster_offset); static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -121,14 +122,12 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, qdict_extract_subqdict(options, &encryptopts, "encrypt."); encryptfmt = qdict_get_try_str(encryptopts, "format"); - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - ret = -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { goto fail; } - ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); + ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); if (ret < 0) { goto fail; } @@ -260,8 +259,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, - s->l1_size * sizeof(uint64_t)); + ret = bdrv_pread(bs->file, s->l1_table_offset, + s->l1_size * sizeof(uint64_t), s->l1_table, 0); if (ret < 0) { goto fail; } @@ -291,8 +290,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, ret = -EINVAL; goto fail; } - ret = bdrv_pread(bs->file, header.backing_file_offset, - bs->auto_backing_file, len); + ret = bdrv_pread(bs->file, header.backing_file_offset, len, + bs->auto_backing_file, 0); if (ret < 0) { goto fail; } @@ -351,10 +350,11 @@ static int qcow_reopen_prepare(BDRVReopenState *state, * return 0 if not allocated, 1 if *result is assigned, and negative * errno on failure. */ -static int get_cluster_offset(BlockDriverState *bs, - uint64_t offset, int allocate, - int compressed_size, - int n_start, int n_end, uint64_t *result) +static int coroutine_fn get_cluster_offset(BlockDriverState *bs, + uint64_t offset, int allocate, + int compressed_size, + int n_start, int n_end, + uint64_t *result) { BDRVQcowState *s = bs->opaque; int min_index, i, j, l1_index, l2_index, ret; @@ -381,9 +381,9 @@ static int get_cluster_offset(BlockDriverState *bs, s->l1_table[l1_index] = l2_offset; tmp = cpu_to_be64(l2_offset); BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE); - ret = bdrv_pwrite_sync(bs->file, - s->l1_table_offset + l1_index * sizeof(tmp), - &tmp, sizeof(tmp)); + ret = bdrv_co_pwrite_sync(bs->file, + s->l1_table_offset + l1_index * sizeof(tmp), + sizeof(tmp), &tmp, 0); if (ret < 0) { return ret; } @@ -414,14 +414,14 @@ static int get_cluster_offset(BlockDriverState *bs, BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD); if (new_l2_table) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table, - s->l2_size * sizeof(uint64_t)); + ret = bdrv_co_pwrite_sync(bs->file, l2_offset, + s->l2_size * sizeof(uint64_t), l2_table, 0); if (ret < 0) { return ret; } } else { - ret = bdrv_pread(bs->file, l2_offset, l2_table, - s->l2_size * sizeof(uint64_t)); + ret = bdrv_co_pread(bs->file, l2_offset, + s->l2_size * sizeof(uint64_t), l2_table, 0); if (ret < 0) { return ret; } @@ -453,8 +453,8 @@ static int get_cluster_offset(BlockDriverState *bs, cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size); /* write the cluster content */ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); - ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, - s->cluster_size); + ret = bdrv_co_pwrite(bs->file, cluster_offset, s->cluster_size, + s->cluster_cache, 0); if (ret < 0) { return ret; } @@ -469,8 +469,9 @@ static int get_cluster_offset(BlockDriverState *bs, if (cluster_offset + s->cluster_size > INT64_MAX) { return -E2BIG; } - ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size, - false, PREALLOC_MODE_OFF, 0, NULL); + ret = bdrv_co_truncate(bs->file, + cluster_offset + s->cluster_size, + false, PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; } @@ -492,10 +493,9 @@ static int get_cluster_offset(BlockDriverState *bs, return -EIO; } BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); - ret = bdrv_pwrite(bs->file, - cluster_offset + i, - s->cluster_data, - BDRV_SECTOR_SIZE); + ret = bdrv_co_pwrite(bs->file, cluster_offset + i, + BDRV_SECTOR_SIZE, + s->cluster_data, 0); if (ret < 0) { return ret; } @@ -515,8 +515,8 @@ static int get_cluster_offset(BlockDriverState *bs, } else { BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); } - ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp), - &tmp, sizeof(tmp)); + ret = bdrv_co_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp), + sizeof(tmp), &tmp, 0); if (ret < 0) { return ret; } @@ -586,7 +586,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, return 0; } -static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) +static int coroutine_fn decompress_cluster(BlockDriverState *bs, + uint64_t cluster_offset) { BDRVQcowState *s = bs->opaque; int ret, csize; @@ -597,8 +598,8 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) csize = cluster_offset >> (63 - s->cluster_bits); csize &= (s->cluster_size - 1); BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED); - ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize); - if (ret != csize) + ret = bdrv_co_pread(bs->file, coffset, csize, s->cluster_data, 0); + if (ret < 0) return -1; if (decompress_buffer(s->cluster_cache, s->cluster_size, s->cluster_data, csize) < 0) { @@ -629,7 +630,6 @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, uint8_t *buf; void *orig_buf; - assert(!flags); if (qiov->niov > 1) { buf = orig_buf = qemu_try_blockalign(bs, qiov->size); if (buf == NULL) { @@ -726,7 +726,6 @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset, uint8_t *buf; void *orig_buf; - assert(!flags); s->cluster_cache_offset = -1; /* disable compressed cache */ /* We must always copy the iov when encrypting, so we @@ -826,7 +825,7 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, return -EINVAL; } - if (qcow_opts->has_encrypt && + if (qcow_opts->encrypt && qcow_opts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_QCOW) { error_setg(errp, "Unsupported encryption format"); @@ -854,7 +853,7 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, header.size = cpu_to_be64(total_size); header_size = sizeof(header); backing_filename_len = 0; - if (qcow_opts->has_backing_file) { + if (qcow_opts->backing_file) { if (strcmp(qcow_opts->backing_file, "fat:")) { header.backing_file_offset = cpu_to_be64(header_size); backing_filename_len = strlen(qcow_opts->backing_file); @@ -862,7 +861,7 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, header_size += backing_filename_len; } else { /* special backing file for vvfat */ - qcow_opts->has_backing_file = false; + qcow_opts->backing_file = NULL; } header.cluster_bits = 9; /* 512 byte cluster to avoid copying unmodified sectors */ @@ -877,7 +876,7 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, header.l1_table_offset = cpu_to_be64(header_size); - if (qcow_opts->has_encrypt) { + if (qcow_opts->encrypt) { header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); crypto = qcrypto_block_create(qcow_opts->encrypt, "encrypt.", @@ -891,15 +890,15 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, } /* write all the data */ - ret = blk_pwrite(qcow_blk, 0, &header, sizeof(header), 0); - if (ret != sizeof(header)) { + ret = blk_co_pwrite(qcow_blk, 0, sizeof(header), &header, 0); + if (ret < 0) { goto exit; } - if (qcow_opts->has_backing_file) { - ret = blk_pwrite(qcow_blk, sizeof(header), - qcow_opts->backing_file, backing_filename_len, 0); - if (ret != backing_filename_len) { + if (qcow_opts->backing_file) { + ret = blk_co_pwrite(qcow_blk, sizeof(header), backing_filename_len, + qcow_opts->backing_file, 0); + if (ret < 0) { goto exit; } } @@ -907,9 +906,9 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, tmp = g_malloc0(BDRV_SECTOR_SIZE); for (i = 0; i < DIV_ROUND_UP(sizeof(uint64_t) * l1_size, BDRV_SECTOR_SIZE); i++) { - ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i, - tmp, BDRV_SECTOR_SIZE, 0); - if (ret != BDRV_SECTOR_SIZE) { + ret = blk_co_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i, + BDRV_SECTOR_SIZE, tmp, 0); + if (ret < 0) { g_free(tmp); goto exit; } @@ -974,7 +973,7 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto fail; } @@ -1030,8 +1029,8 @@ static int qcow_make_empty(BlockDriverState *bs) int ret; memset(s->l1_table, 0, l1_length); - if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table, - l1_length) < 0) + if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, l1_length, s->l1_table, + 0) < 0) return -1; ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false, PREALLOC_MODE_OFF, 0, NULL); diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 8fb473155154..bcad567c0c33 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -234,8 +234,8 @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb, } assert(tb->size <= BME_MAX_TABLE_SIZE); - ret = bdrv_pread(bs->file, tb->offset, - table, tb->size * BME_TABLE_ENTRY_SIZE); + ret = bdrv_pread(bs->file, tb->offset, tb->size * BME_TABLE_ENTRY_SIZE, + table, 0); if (ret < 0) { goto fail; } @@ -317,7 +317,7 @@ static int load_bitmap_data(BlockDriverState *bs, * already cleared */ } } else { - ret = bdrv_pread(bs->file, data_offset, buf, s->cluster_size); + ret = bdrv_pread(bs->file, data_offset, s->cluster_size, buf, 0); if (ret < 0) { goto finish; } @@ -575,7 +575,7 @@ static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset, } dir_end = dir + size; - ret = bdrv_pread(bs->file, offset, dir, size); + ret = bdrv_pread(bs->file, offset, size, dir, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read bitmap directory"); goto fail; @@ -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); @@ -798,7 +798,7 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, goto fail; } - ret = bdrv_pwrite(bs->file, dir_offset, dir, dir_size); + ret = bdrv_pwrite(bs->file, dir_offset, dir_size, dir, 0); if (ret < 0) { goto fail; } @@ -955,8 +955,8 @@ static void set_readonly_helper(gpointer bitmap, gpointer value) * If header_updated is not NULL then it is set appropriately regardless of * the return value. */ -bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, - Error **errp) +bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs, + bool *header_updated, Error **errp) { BDRVQcow2State *s = bs->opaque; Qcow2BitmapList *bm_list; @@ -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: @@ -1339,7 +1339,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs, goto fail; } - ret = bdrv_pwrite(bs->file, off, buf, s->cluster_size); + ret = bdrv_pwrite(bs->file, off, s->cluster_size, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", bm_name); @@ -1402,7 +1402,7 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) } bitmap_table_to_be(tb, tb_size); - ret = bdrv_pwrite(bs->file, tb_offset, tb, tb_size * sizeof(tb[0])); + ret = bdrv_pwrite(bs->file, tb_offset, tb_size * sizeof(tb[0]), tb, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", bm_name); diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 8a0105911f7e..54b2d5f4de19 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -75,7 +75,7 @@ static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables) /* Using MADV_DONTNEED to discard memory is a Linux-specific feature */ #ifdef CONFIG_LINUX void *t = qcow2_cache_get_table_addr(c, i); - int align = qemu_real_host_page_size; + int align = qemu_real_host_page_size(); size_t mem_size = (size_t) c->table_size * num_tables; size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t; size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align); @@ -223,8 +223,8 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); } - ret = bdrv_pwrite(bs->file, c->entries[i].offset, - qcow2_cache_get_table_addr(c, i), c->table_size); + ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->table_size, + qcow2_cache_get_table_addr(c, i), 0); if (ret < 0) { return ret; } @@ -379,9 +379,8 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD); } - ret = bdrv_pread(bs->file, offset, - qcow2_cache_get_table_addr(c, i), - c->table_size); + ret = bdrv_pread(bs->file, offset, c->table_size, + qcow2_cache_get_table_addr(c, i), 0); if (ret < 0) { return ret; } diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 20a16ba6ee06..40ed847f97cd 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -31,7 +31,8 @@ #include "qemu/memalign.h" #include "trace.h" -int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size) +int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs, + uint64_t exact_size) { BDRVQcow2State *s = bs->opaque; int new_l1_size, i, ret; @@ -47,14 +48,14 @@ int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size) #endif BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE); - ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset + - new_l1_size * L1E_SIZE, - (s->l1_size - new_l1_size) * L1E_SIZE, 0); + ret = bdrv_co_pwrite_zeroes(bs->file, + s->l1_table_offset + new_l1_size * L1E_SIZE, + (s->l1_size - new_l1_size) * L1E_SIZE, 0); if (ret < 0) { goto fail; } - ret = bdrv_flush(bs->file->bs); + ret = bdrv_co_flush(bs->file->bs); if (ret < 0) { goto fail; } @@ -159,8 +160,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE); for(i = 0; i < s->l1_size; i++) new_l1_table[i] = cpu_to_be64(new_l1_table[i]); - ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, - new_l1_table, new_l1_size2); + ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_size2, + new_l1_table, 0); if (ret < 0) goto fail; for(i = 0; i < s->l1_size; i++) @@ -171,7 +172,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, stl_be_p(data, new_l1_size); stq_be_p(data + 4, new_l1_table_offset); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), - data, sizeof(data)); + sizeof(data), data, 0); if (ret < 0) { goto fail; } @@ -249,7 +250,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE); ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + L1E_SIZE * l1_start_index, - buf, bufsize); + bufsize, buf, 0); if (ret < 0) { return ret; } @@ -823,10 +824,10 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, * * Return 0 on success and -errno in error cases */ -int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size, - uint64_t *host_offset) +int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size, + uint64_t *host_offset) { BDRVQcow2State *s = bs->opaque; int l2_index, ret; @@ -884,7 +885,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 +1025,8 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) 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 +1399,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; @@ -1486,8 +1489,9 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, * * -errno: in error cases */ -static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, - uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) +static int coroutine_fn handle_copied(BlockDriverState *bs, + uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes, + QCowL2Meta **m) { BDRVQcow2State *s = bs->opaque; int l2_index; @@ -1651,8 +1655,9 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, * * -errno: in error cases */ -static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, - uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) +static int coroutine_fn handle_alloc(BlockDriverState *bs, + uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes, + QCowL2Meta **m) { BDRVQcow2State *s = bs->opaque; int l2_index; @@ -1772,9 +1777,10 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, * * 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 +2111,8 @@ static int zero_l2_subclusters(BlockDriverState *bs, uint64_t offset, 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; @@ -2260,7 +2266,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, (void **)&l2_slice); } else { /* load inactive L2 tables from disk */ - ret = bdrv_pread(bs->file, slice_offset, l2_slice, slice_size2); + ret = bdrv_pread(bs->file, slice_offset, slice_size2, + l2_slice, 0); } if (ret < 0) { goto fail; @@ -2376,8 +2383,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, goto fail; } - ret = bdrv_pwrite(bs->file, slice_offset, - l2_slice, slice_size2); + ret = bdrv_pwrite(bs->file, slice_offset, slice_size2, + l2_slice, 0); if (ret < 0) { goto fail; } @@ -2470,8 +2477,8 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs, l1_table = new_l1_table; - ret = bdrv_pread(bs->file, s->snapshots[i].l1_table_offset, - l1_table, l1_size2); + ret = bdrv_pread(bs->file, s->snapshots[i].l1_table_offset, l1_size2, + l1_table, 0); if (ret < 0) { goto fail; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index b91499410c0c..81264740f047 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -97,7 +97,7 @@ static void update_max_refcount_table_index(BDRVQcow2State *s) s->max_refcount_table_index = i; } -int qcow2_refcount_init(BlockDriverState *bs) +int coroutine_fn qcow2_refcount_init(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; unsigned int refcount_table_size2, i; @@ -118,8 +118,8 @@ int qcow2_refcount_init(BlockDriverState *bs) goto fail; } BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD); - ret = bdrv_pread(bs->file, s->refcount_table_offset, - s->refcount_table, refcount_table_size2); + ret = bdrv_co_pread(bs->file, s->refcount_table_offset, + refcount_table_size2, s->refcount_table, 0); if (ret < 0) { goto fail; } @@ -439,7 +439,7 @@ static int alloc_refcount_block(BlockDriverState *bs, BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP); ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset + refcount_table_index * REFTABLE_ENTRY_SIZE, - &data64, sizeof(data64)); + sizeof(data64), &data64, 0); if (ret < 0) { goto fail; } @@ -684,8 +684,8 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset, } BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE); - ret = bdrv_pwrite_sync(bs->file, table_offset, new_table, - table_size * REFTABLE_ENTRY_SIZE); + ret = bdrv_pwrite_sync(bs->file, table_offset, + table_size * REFTABLE_ENTRY_SIZE, new_table, 0); if (ret < 0) { goto fail; } @@ -704,7 +704,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset, BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset), - &data, sizeof(data)); + sizeof(data), &data, 0); if (ret < 0) { goto fail; } @@ -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) { @@ -1274,7 +1274,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } l1_allocated = true; - ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2); + ret = bdrv_pread(bs->file, l1_table_offset, l1_size2, l1_table, 0); if (ret < 0) { goto fail; } @@ -1435,8 +1435,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, cpu_to_be64s(&l1_table[i]); } - ret = bdrv_pwrite_sync(bs->file, l1_table_offset, - l1_table, l1_size2); + ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_size2, l1_table, + 0); for (i = 0; i < l1_size; i++) { be64_to_cpus(&l1_table[i]); @@ -1633,8 +1633,8 @@ static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res, goto fail; } - ret = bdrv_pwrite_sync(bs->file, l2e_offset, &l2_table[idx], - l2_entry_size(s)); + ret = bdrv_pwrite_sync(bs->file, l2e_offset, l2_entry_size(s), + &l2_table[idx], 0); if (ret < 0) { fprintf(stderr, "ERROR: Failed to overwrite L2 " "table entry: %s\n", strerror(-ret)); @@ -1672,7 +1672,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, bool metadata_overlap; /* Read L2 table from disk */ - ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size_bytes); + ret = bdrv_pread(bs->file, l2_offset, l2_size_bytes, l2_table, 0); if (ret < 0) { fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n"); res->check_errors++; @@ -1888,7 +1888,7 @@ static int check_refcounts_l1(BlockDriverState *bs, } /* Read L1 table entries from disk */ - ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size_bytes); + ret = bdrv_pread(bs->file, l1_table_offset, l1_size_bytes, l1_table, 0); if (ret < 0) { fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); res->check_errors++; @@ -2004,8 +2004,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, } } - ret = bdrv_pread(bs->file, l2_offset, l2_table, - s->l2_size * l2_entry_size(s)); + ret = bdrv_pread(bs->file, l2_offset, s->l2_size * l2_entry_size(s), + l2_table, 0); if (ret < 0) { fprintf(stderr, "ERROR: Could not read L2 table: %s\n", strerror(-ret)); @@ -2058,8 +2058,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, goto fail; } - ret = bdrv_pwrite(bs->file, l2_offset, l2_table, - s->cluster_size); + ret = bdrv_pwrite(bs->file, l2_offset, s->cluster_size, l2_table, + 0); if (ret < 0) { fprintf(stderr, "ERROR: Could not write L2 table: %s\n", strerror(-ret)); @@ -2438,188 +2438,329 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs, } /* - * Creates a new refcount structure based solely on the in-memory information - * given through *refcount_table. All necessary allocations will be reflected - * in that array. + * Helper function for rebuild_refcount_structure(). * - * On success, the old refcount structure is leaked (it will be covered by the - * new refcount structure). + * Scan the range of clusters [first_cluster, end_cluster) for allocated + * clusters and write all corresponding refblocks to disk. The refblock + * and allocation data is taken from the in-memory refcount table + * *refcount_table[] (of size *nb_clusters), which is basically one big + * (unlimited size) refblock for the whole image. + * + * For these refblocks, clusters are allocated using said in-memory + * refcount table. Care is taken that these allocations are reflected + * in the refblocks written to disk. + * + * The refblocks' offsets are written into a reftable, which is + * *on_disk_reftable_ptr[] (of size *on_disk_reftable_entries_ptr). If + * that reftable is of insufficient size, it will be resized to fit. + * This reftable is not written to disk. + * + * (If *on_disk_reftable_ptr is not NULL, the entries within are assumed + * to point to existing valid refblocks that do not need to be allocated + * again.) + * + * Return whether the on-disk reftable array was resized (true/false), + * or -errno on error. */ -static int rebuild_refcount_structure(BlockDriverState *bs, - BdrvCheckResult *res, - void **refcount_table, - int64_t *nb_clusters) +static int rebuild_refcounts_write_refblocks( + BlockDriverState *bs, void **refcount_table, int64_t *nb_clusters, + int64_t first_cluster, int64_t end_cluster, + uint64_t **on_disk_reftable_ptr, uint32_t *on_disk_reftable_entries_ptr, + Error **errp + ) { BDRVQcow2State *s = bs->opaque; - int64_t first_free_cluster = 0, reftable_offset = -1, cluster = 0; + int64_t cluster; int64_t refblock_offset, refblock_start, refblock_index; - uint32_t reftable_size = 0; - uint64_t *on_disk_reftable = NULL; + int64_t first_free_cluster = 0; + uint64_t *on_disk_reftable = *on_disk_reftable_ptr; + uint32_t on_disk_reftable_entries = *on_disk_reftable_entries_ptr; void *on_disk_refblock; - int ret = 0; - struct { - uint64_t reftable_offset; - uint32_t reftable_clusters; - } QEMU_PACKED reftable_offset_and_clusters; - - qcow2_cache_empty(bs, s->refcount_block_cache); + bool reftable_grown = false; + int ret; -write_refblocks: - for (; cluster < *nb_clusters; cluster++) { + for (cluster = first_cluster; cluster < end_cluster; cluster++) { + /* Check all clusters to find refblocks that contain non-zero entries */ if (!s->get_refcount(*refcount_table, cluster)) { continue; } + /* + * This cluster is allocated, so we need to create a refblock + * for it. The data we will write to disk is just the + * respective slice from *refcount_table, so it will contain + * accurate refcounts for all clusters belonging to this + * refblock. After we have written it, we will therefore skip + * all remaining clusters in this refblock. + */ + refblock_index = cluster >> s->refcount_block_bits; refblock_start = refblock_index << s->refcount_block_bits; - /* Don't allocate a cluster in a refblock already written to disk */ - if (first_free_cluster < refblock_start) { - first_free_cluster = refblock_start; - } - refblock_offset = alloc_clusters_imrt(bs, 1, refcount_table, - nb_clusters, &first_free_cluster); - if (refblock_offset < 0) { - fprintf(stderr, "ERROR allocating refblock: %s\n", - strerror(-refblock_offset)); - res->check_errors++; - ret = refblock_offset; - goto fail; - } + if (on_disk_reftable_entries > refblock_index && + on_disk_reftable[refblock_index]) + { + /* + * We can get here after a `goto write_refblocks`: We have a + * reftable from a previous run, and the refblock is already + * allocated. No need to allocate it again. + */ + refblock_offset = on_disk_reftable[refblock_index]; + } else { + int64_t refblock_cluster_index; - if (reftable_size <= refblock_index) { - uint32_t old_reftable_size = reftable_size; - uint64_t *new_on_disk_reftable; + /* Don't allocate a cluster in a refblock already written to disk */ + if (first_free_cluster < refblock_start) { + first_free_cluster = refblock_start; + } + refblock_offset = alloc_clusters_imrt(bs, 1, refcount_table, + nb_clusters, + &first_free_cluster); + if (refblock_offset < 0) { + error_setg_errno(errp, -refblock_offset, + "ERROR allocating refblock"); + return refblock_offset; + } - reftable_size = ROUND_UP((refblock_index + 1) * REFTABLE_ENTRY_SIZE, - s->cluster_size) / REFTABLE_ENTRY_SIZE; - new_on_disk_reftable = g_try_realloc(on_disk_reftable, - reftable_size * - REFTABLE_ENTRY_SIZE); - if (!new_on_disk_reftable) { - res->check_errors++; - ret = -ENOMEM; - goto fail; + refblock_cluster_index = refblock_offset / s->cluster_size; + if (refblock_cluster_index >= end_cluster) { + /* + * We must write the refblock that holds this refblock's + * refcount + */ + end_cluster = refblock_cluster_index + 1; } - on_disk_reftable = new_on_disk_reftable; - memset(on_disk_reftable + old_reftable_size, 0, - (reftable_size - old_reftable_size) * REFTABLE_ENTRY_SIZE); + if (on_disk_reftable_entries <= refblock_index) { + on_disk_reftable_entries = + ROUND_UP((refblock_index + 1) * REFTABLE_ENTRY_SIZE, + s->cluster_size) / REFTABLE_ENTRY_SIZE; + on_disk_reftable = + g_try_realloc(on_disk_reftable, + on_disk_reftable_entries * + REFTABLE_ENTRY_SIZE); + if (!on_disk_reftable) { + error_setg(errp, "ERROR allocating reftable memory"); + return -ENOMEM; + } - /* The offset we have for the reftable is now no longer valid; - * this will leak that range, but we can easily fix that by running - * a leak-fixing check after this rebuild operation */ - reftable_offset = -1; - } else { - assert(on_disk_reftable); - } - on_disk_reftable[refblock_index] = refblock_offset; + memset(on_disk_reftable + *on_disk_reftable_entries_ptr, 0, + (on_disk_reftable_entries - + *on_disk_reftable_entries_ptr) * + REFTABLE_ENTRY_SIZE); - /* If this is apparently the last refblock (for now), try to squeeze the - * reftable in */ - if (refblock_index == (*nb_clusters - 1) >> s->refcount_block_bits && - reftable_offset < 0) - { - uint64_t reftable_clusters = size_to_clusters(s, reftable_size * - REFTABLE_ENTRY_SIZE); - reftable_offset = alloc_clusters_imrt(bs, reftable_clusters, - refcount_table, nb_clusters, - &first_free_cluster); - if (reftable_offset < 0) { - fprintf(stderr, "ERROR allocating reftable: %s\n", - strerror(-reftable_offset)); - res->check_errors++; - ret = reftable_offset; - goto fail; + *on_disk_reftable_ptr = on_disk_reftable; + *on_disk_reftable_entries_ptr = on_disk_reftable_entries; + + reftable_grown = true; + } else { + assert(on_disk_reftable); } + on_disk_reftable[refblock_index] = refblock_offset; } + /* Refblock is allocated, write it to disk */ + ret = qcow2_pre_write_overlap_check(bs, 0, refblock_offset, s->cluster_size, false); if (ret < 0) { - fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret)); - goto fail; + error_setg_errno(errp, -ret, "ERROR writing refblock"); + return ret; } - /* The size of *refcount_table is always cluster-aligned, therefore the - * write operation will not overflow */ + /* + * The refblock is simply a slice of *refcount_table. + * Note that the size of *refcount_table is always aligned to + * whole clusters, so the write operation will not result in + * out-of-bounds accesses. + */ on_disk_refblock = (void *)((char *) *refcount_table + refblock_index * s->cluster_size); - ret = bdrv_pwrite(bs->file, refblock_offset, on_disk_refblock, - s->cluster_size); + ret = bdrv_pwrite(bs->file, refblock_offset, s->cluster_size, + on_disk_refblock, 0); if (ret < 0) { - fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret)); - goto fail; + error_setg_errno(errp, -ret, "ERROR writing refblock"); + return ret; } - /* Go to the end of this refblock */ + /* This refblock is done, skip to its end */ cluster = refblock_start + s->refcount_block_size - 1; } - if (reftable_offset < 0) { - uint64_t post_refblock_start, reftable_clusters; + return reftable_grown; +} + +/* + * Creates a new refcount structure based solely on the in-memory information + * given through *refcount_table (this in-memory information is basically just + * the concatenation of all refblocks). All necessary allocations will be + * reflected in that array. + * + * On success, the old refcount structure is leaked (it will be covered by the + * new refcount structure). + */ +static int rebuild_refcount_structure(BlockDriverState *bs, + BdrvCheckResult *res, + void **refcount_table, + int64_t *nb_clusters, + Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + int64_t reftable_offset = -1; + int64_t reftable_length = 0; + int64_t reftable_clusters; + int64_t refblock_index; + uint32_t on_disk_reftable_entries = 0; + uint64_t *on_disk_reftable = NULL; + int ret = 0; + int reftable_size_changed = 0; + struct { + uint64_t reftable_offset; + uint32_t reftable_clusters; + } QEMU_PACKED reftable_offset_and_clusters; + + qcow2_cache_empty(bs, s->refcount_block_cache); + + /* + * For each refblock containing entries, we try to allocate a + * cluster (in the in-memory refcount table) and write its offset + * into on_disk_reftable[]. We then write the whole refblock to + * disk (as a slice of the in-memory refcount table). + * This is done by rebuild_refcounts_write_refblocks(). + * + * Once we have scanned all clusters, we try to find space for the + * reftable. This will dirty the in-memory refcount table (i.e. + * make it differ from the refblocks we have already written), so we + * need to run rebuild_refcounts_write_refblocks() again for the + * range of clusters where the reftable has been allocated. + * + * This second run might make the reftable grow again, in which case + * we will need to allocate another space for it, which is why we + * repeat all this until the reftable stops growing. + * + * (This loop will terminate, because with every cluster the + * reftable grows, it can accomodate a multitude of more refcounts, + * so that at some point this must be able to cover the reftable + * and all refblocks describing it.) + * + * We then convert the reftable to big-endian and write it to disk. + * + * Note that we never free any reftable allocations. Doing so would + * needlessly complicate the algorithm: The eventual second check + * run we do will clean up all leaks we have caused. + */ + + reftable_size_changed = + rebuild_refcounts_write_refblocks(bs, refcount_table, nb_clusters, + 0, *nb_clusters, + &on_disk_reftable, + &on_disk_reftable_entries, errp); + if (reftable_size_changed < 0) { + res->check_errors++; + ret = reftable_size_changed; + goto fail; + } + + /* + * There was no reftable before, so rebuild_refcounts_write_refblocks() + * must have increased its size (from 0 to something). + */ + assert(reftable_size_changed); + + do { + int64_t reftable_start_cluster, reftable_end_cluster; + int64_t first_free_cluster = 0; + + reftable_length = on_disk_reftable_entries * REFTABLE_ENTRY_SIZE; + reftable_clusters = size_to_clusters(s, reftable_length); - post_refblock_start = ROUND_UP(*nb_clusters, s->refcount_block_size); - reftable_clusters = - size_to_clusters(s, reftable_size * REFTABLE_ENTRY_SIZE); - /* Not pretty but simple */ - if (first_free_cluster < post_refblock_start) { - first_free_cluster = post_refblock_start; - } reftable_offset = alloc_clusters_imrt(bs, reftable_clusters, refcount_table, nb_clusters, &first_free_cluster); if (reftable_offset < 0) { - fprintf(stderr, "ERROR allocating reftable: %s\n", - strerror(-reftable_offset)); + error_setg_errno(errp, -reftable_offset, + "ERROR allocating reftable"); res->check_errors++; ret = reftable_offset; goto fail; } - goto write_refblocks; - } + /* + * We need to update the affected refblocks, so re-run the + * write_refblocks loop for the reftable's range of clusters. + */ + assert(offset_into_cluster(s, reftable_offset) == 0); + reftable_start_cluster = reftable_offset / s->cluster_size; + reftable_end_cluster = reftable_start_cluster + reftable_clusters; + reftable_size_changed = + rebuild_refcounts_write_refblocks(bs, refcount_table, nb_clusters, + reftable_start_cluster, + reftable_end_cluster, + &on_disk_reftable, + &on_disk_reftable_entries, errp); + if (reftable_size_changed < 0) { + res->check_errors++; + ret = reftable_size_changed; + goto fail; + } + + /* + * If the reftable size has changed, we will need to find a new + * allocation, repeating the loop. + */ + } while (reftable_size_changed); - for (refblock_index = 0; refblock_index < reftable_size; refblock_index++) { + /* The above loop must have run at least once */ + assert(reftable_offset >= 0); + + /* + * All allocations are done, all refblocks are written, convert the + * reftable to big-endian and write it to disk. + */ + + for (refblock_index = 0; refblock_index < on_disk_reftable_entries; + refblock_index++) + { cpu_to_be64s(&on_disk_reftable[refblock_index]); } - ret = qcow2_pre_write_overlap_check(bs, 0, reftable_offset, - reftable_size * REFTABLE_ENTRY_SIZE, + ret = qcow2_pre_write_overlap_check(bs, 0, reftable_offset, reftable_length, false); if (ret < 0) { - fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret)); + error_setg_errno(errp, -ret, "ERROR writing reftable"); goto fail; } - assert(reftable_size < INT_MAX / REFTABLE_ENTRY_SIZE); - ret = bdrv_pwrite(bs->file, reftable_offset, on_disk_reftable, - reftable_size * REFTABLE_ENTRY_SIZE); + assert(reftable_length < INT_MAX); + ret = bdrv_pwrite(bs->file, reftable_offset, reftable_length, + on_disk_reftable, 0); if (ret < 0) { - fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret)); + error_setg_errno(errp, -ret, "ERROR writing reftable"); goto fail; } /* Enter new reftable into the image header */ reftable_offset_and_clusters.reftable_offset = cpu_to_be64(reftable_offset); reftable_offset_and_clusters.reftable_clusters = - cpu_to_be32(size_to_clusters(s, reftable_size * REFTABLE_ENTRY_SIZE)); + cpu_to_be32(reftable_clusters); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset), - &reftable_offset_and_clusters, - sizeof(reftable_offset_and_clusters)); + sizeof(reftable_offset_and_clusters), + &reftable_offset_and_clusters, 0); if (ret < 0) { - fprintf(stderr, "ERROR setting reftable: %s\n", strerror(-ret)); + error_setg_errno(errp, -ret, "ERROR setting reftable"); goto fail; } - for (refblock_index = 0; refblock_index < reftable_size; refblock_index++) { + for (refblock_index = 0; refblock_index < on_disk_reftable_entries; + refblock_index++) + { be64_to_cpus(&on_disk_reftable[refblock_index]); } s->refcount_table = on_disk_reftable; s->refcount_table_offset = reftable_offset; - s->refcount_table_size = reftable_size; + s->refcount_table_size = on_disk_reftable_entries; update_max_refcount_table_index(s); return 0; @@ -2676,11 +2817,13 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, if (rebuild && (fix & BDRV_FIX_ERRORS)) { BdrvCheckResult old_res = *res; int fresh_leaks = 0; + Error *local_err = NULL; fprintf(stderr, "Rebuilding refcount structure\n"); ret = rebuild_refcount_structure(bs, res, &refcount_table, - &nb_clusters); + &nb_clusters, &local_err); if (ret < 0) { + error_report_err(local_err); goto fail; } @@ -2866,7 +3009,7 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, return -ENOMEM; } - ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2); + ret = bdrv_pread(bs->file, l1_ofs, l1_sz2, l1, 0); if (ret < 0) { g_free(l1); return ret; @@ -3037,7 +3180,7 @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, return ret; } - ret = bdrv_pwrite(bs->file, offset, refblock, s->cluster_size); + ret = bdrv_pwrite(bs->file, offset, s->cluster_size, refblock, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write refblock"); return ret; @@ -3309,8 +3452,9 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, cpu_to_be64s(&new_reftable[i]); } - ret = bdrv_pwrite(bs->file, new_reftable_offset, new_reftable, - new_reftable_size * REFTABLE_ENTRY_SIZE); + ret = bdrv_pwrite(bs->file, new_reftable_offset, + new_reftable_size * REFTABLE_ENTRY_SIZE, new_reftable, + 0); for (i = 0; i < new_reftable_size; i++) { be64_to_cpus(&new_reftable[i]); @@ -3415,8 +3559,8 @@ static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset) return covering_refblock_offset; } -static int qcow2_discard_refcount_block(BlockDriverState *bs, - uint64_t discard_block_offs) +static int coroutine_fn +qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs) { BDRVQcow2State *s = bs->opaque; int64_t refblock_offs; @@ -3472,7 +3616,7 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs, return 0; } -int qcow2_shrink_reftable(BlockDriverState *bs) +int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; uint64_t *reftable_tmp = @@ -3513,8 +3657,9 @@ int qcow2_shrink_reftable(BlockDriverState *bs) reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]); } - ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset, reftable_tmp, - s->refcount_table_size * REFTABLE_ENTRY_SIZE); + ret = bdrv_co_pwrite_sync(bs->file, s->refcount_table_offset, + s->refcount_table_size * REFTABLE_ENTRY_SIZE, + reftable_tmp, 0); /* * If the write in the reftable failed the image may contain a partially * overwritten reftable. In this case it would be better to clear the @@ -3561,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-snapshot.c b/block/qcow2-snapshot.c index 075269a02374..62e8a0335d44 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -108,7 +108,7 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, /* Read statically sized part of the snapshot header */ offset = ROUND_UP(offset, 8); - ret = bdrv_pread(bs->file, offset, &h, sizeof(h)); + ret = bdrv_pread(bs->file, offset, sizeof(h), &h, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read snapshot table"); goto fail; @@ -146,8 +146,8 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, } /* Read known extra data */ - ret = bdrv_pread(bs->file, offset, &extra, - MIN(sizeof(extra), sn->extra_data_size)); + ret = bdrv_pread(bs->file, offset, + MIN(sizeof(extra), sn->extra_data_size), &extra, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read snapshot table"); goto fail; @@ -184,8 +184,8 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, /* Store unknown extra data */ unknown_extra_data_size = sn->extra_data_size - sizeof(extra); sn->unknown_extra_data = g_malloc(unknown_extra_data_size); - ret = bdrv_pread(bs->file, offset, sn->unknown_extra_data, - unknown_extra_data_size); + ret = bdrv_pread(bs->file, offset, unknown_extra_data_size, + sn->unknown_extra_data, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read snapshot table"); @@ -196,7 +196,7 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, /* Read snapshot ID */ sn->id_str = g_malloc(id_str_size + 1); - ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size); + ret = bdrv_pread(bs->file, offset, id_str_size, sn->id_str, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read snapshot table"); goto fail; @@ -206,7 +206,7 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, /* Read snapshot name */ sn->name = g_malloc(name_size + 1); - ret = bdrv_pread(bs->file, offset, sn->name, name_size); + ret = bdrv_pread(bs->file, offset, name_size, sn->name, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read snapshot table"); goto fail; @@ -349,13 +349,13 @@ int qcow2_write_snapshots(BlockDriverState *bs) h.name_size = cpu_to_be16(name_size); offset = ROUND_UP(offset, 8); - ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h)); + ret = bdrv_pwrite(bs->file, offset, sizeof(h), &h, 0); if (ret < 0) { goto fail; } offset += sizeof(h); - ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra)); + ret = bdrv_pwrite(bs->file, offset, sizeof(extra), &extra, 0); if (ret < 0) { goto fail; } @@ -369,21 +369,21 @@ int qcow2_write_snapshots(BlockDriverState *bs) assert(unknown_extra_data_size <= BDRV_REQUEST_MAX_BYTES); assert(sn->unknown_extra_data); - ret = bdrv_pwrite(bs->file, offset, sn->unknown_extra_data, - unknown_extra_data_size); + ret = bdrv_pwrite(bs->file, offset, unknown_extra_data_size, + sn->unknown_extra_data, 0); if (ret < 0) { goto fail; } offset += unknown_extra_data_size; } - ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size); + ret = bdrv_pwrite(bs->file, offset, id_str_size, sn->id_str, 0); if (ret < 0) { goto fail; } offset += id_str_size; - ret = bdrv_pwrite(bs->file, offset, sn->name, name_size); + ret = bdrv_pwrite(bs->file, offset, name_size, sn->name, 0); if (ret < 0) { goto fail; } @@ -406,7 +406,7 @@ int qcow2_write_snapshots(BlockDriverState *bs) header_data.snapshots_offset = cpu_to_be64(snapshots_offset); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots), - &header_data, sizeof(header_data)); + sizeof(header_data), &header_data, 0); if (ret < 0) { goto fail; } @@ -441,8 +441,9 @@ int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs, } QEMU_PACKED snapshot_table_pointer; /* qcow2_do_open() discards this information in check mode */ - ret = bdrv_pread(bs->file, offsetof(QCowHeader, nb_snapshots), - &snapshot_table_pointer, sizeof(snapshot_table_pointer)); + ret = bdrv_co_pread(bs->file, offsetof(QCowHeader, nb_snapshots), + sizeof(snapshot_table_pointer), &snapshot_table_pointer, + 0); if (ret < 0) { result->check_errors++; fprintf(stderr, "ERROR failed to read the snapshot table pointer from " @@ -511,9 +512,9 @@ int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs, assert(fix & BDRV_FIX_ERRORS); snapshot_table_pointer.nb_snapshots = cpu_to_be32(s->nb_snapshots); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots), - &snapshot_table_pointer.nb_snapshots, - sizeof(snapshot_table_pointer.nb_snapshots)); + ret = bdrv_co_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots), + sizeof(snapshot_table_pointer.nb_snapshots), + &snapshot_table_pointer.nb_snapshots, 0); if (ret < 0) { result->check_errors++; fprintf(stderr, "ERROR failed to update the snapshot count in the " @@ -693,8 +694,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) goto fail; } - ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table, - s->l1_size * L1E_SIZE); + ret = bdrv_pwrite(bs->file, sn->l1_table_offset, s->l1_size * L1E_SIZE, + l1_table, 0); if (ret < 0) { goto fail; } @@ -829,8 +830,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto fail; } - ret = bdrv_pread(bs->file, sn->l1_table_offset, - sn_l1_table, sn_l1_bytes); + ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_bytes, sn_l1_table, + 0); if (ret < 0) { goto fail; } @@ -848,8 +849,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto fail; } - ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table, - cur_l1_bytes); + ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, cur_l1_bytes, + sn_l1_table, 0); if (ret < 0) { goto fail; } @@ -1051,8 +1052,8 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, return -ENOMEM; } - ret = bdrv_pread(bs->file, sn->l1_table_offset, - new_l1_table, new_l1_bytes); + ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_bytes, + new_l1_table, 0); if (ret < 0) { error_setg(errp, "Failed to read l1 table for snapshot"); qemu_vfree(new_l1_table); diff --git a/block/qcow2.c b/block/qcow2.c index b5c47931ef4a..bafbd077b9f1 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -94,9 +94,9 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) } -static ssize_t qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset, - uint8_t *buf, size_t buflen, - void *opaque, Error **errp) +static int qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset, + uint8_t *buf, size_t buflen, + void *opaque, Error **errp) { BlockDriverState *bs = opaque; BDRVQcow2State *s = bs->opaque; @@ -107,18 +107,18 @@ static ssize_t qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset, return -1; } - ret = bdrv_pread(bs->file, - s->crypto_header.offset + offset, buf, buflen); + ret = bdrv_pread(bs->file, s->crypto_header.offset + offset, buflen, buf, + 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read encryption header"); return -1; } - return ret; + return 0; } -static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, - void *opaque, Error **errp) +static int qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, + void *opaque, Error **errp) { BlockDriverState *bs = opaque; BDRVQcow2State *s = bs->opaque; @@ -151,13 +151,13 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, return -1; } - return ret; + return 0; } -static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, - const uint8_t *buf, size_t buflen, - void *opaque, Error **errp) +static int qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, + const uint8_t *buf, size_t buflen, + void *opaque, Error **errp) { BlockDriverState *bs = opaque; BDRVQcow2State *s = bs->opaque; @@ -168,13 +168,13 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, return -1; } - ret = bdrv_pwrite(bs->file, - s->crypto_header.offset + offset, buf, buflen); + ret = bdrv_pwrite(bs->file, s->crypto_header.offset + offset, buflen, buf, + 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read encryption header"); return -1; } - return ret; + return 0; } static QDict* @@ -227,7 +227,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, printf("attempting to read extended header in offset %lu\n", offset); #endif - ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext)); + ret = bdrv_pread(bs->file, offset, sizeof(ext), &ext, 0); if (ret < 0) { error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: " "pread fail from offset %" PRIu64, offset); @@ -255,7 +255,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, sizeof(bs->backing_format)); return 2; } - ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len); + ret = bdrv_pread(bs->file, offset, ext.len, bs->backing_format, 0); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_backing_format: " "Could not read format name"); @@ -271,10 +271,11 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, case QCOW2_EXT_MAGIC_FEATURE_TABLE: if (p_feature_table != NULL) { void *feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); - ret = bdrv_pread(bs->file, offset , feature_table, ext.len); + ret = bdrv_pread(bs->file, offset, ext.len, feature_table, 0); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_feature_table: " "Could not read table"); + g_free(feature_table); return ret; } @@ -296,7 +297,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, return -EINVAL; } - ret = bdrv_pread(bs->file, offset, &s->crypto_header, ext.len); + ret = bdrv_pread(bs->file, offset, ext.len, &s->crypto_header, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Unable to read CRYPTO header extension"); @@ -352,7 +353,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, break; } - ret = bdrv_pread(bs->file, offset, &bitmaps_ext, ext.len); + ret = bdrv_pread(bs->file, offset, ext.len, &bitmaps_ext, 0); if (ret < 0) { error_setg_errno(errp, -ret, "bitmaps_ext: " "Could not read ext header"); @@ -416,7 +417,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, case QCOW2_EXT_MAGIC_DATA_FILE: { s->image_data_file = g_malloc0(ext.len + 1); - ret = bdrv_pread(bs->file, offset, s->image_data_file, ext.len); + ret = bdrv_pread(bs->file, offset, ext.len, s->image_data_file, 0); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: Could not read data file name"); @@ -440,7 +441,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, uext->len = ext.len; QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next); - ret = bdrv_pread(bs->file, offset , uext->data, uext->len); + ret = bdrv_pread(bs->file, offset, uext->len, uext->data, 0); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: unknown extension: " "Could not read data"); @@ -516,12 +517,9 @@ int qcow2_mark_dirty(BlockDriverState *bs) } val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY); - ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, incompatible_features), - &val, sizeof(val)); - if (ret < 0) { - return ret; - } - ret = bdrv_flush(bs->file->bs); + ret = bdrv_pwrite_sync(bs->file, + offsetof(QCowHeader, incompatible_features), + sizeof(val), &val, 0); if (ret < 0) { return ret; } @@ -1296,7 +1294,8 @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp) /* Called with s->lock held. */ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, - int flags, Error **errp) + int flags, bool open_data_file, + Error **errp) { ERRP_GUARD(); BDRVQcow2State *s = bs->opaque; @@ -1307,7 +1306,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, uint64_t l1_vm_state_index; bool update_header = false; - ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); + ret = bdrv_co_pread(bs->file, 0, sizeof(header), &header, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read qcow2 header"); goto fail; @@ -1383,8 +1382,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (header.header_length > sizeof(header)) { s->unknown_header_fields_size = header.header_length - sizeof(header); s->unknown_header_fields = g_malloc(s->unknown_header_fields_size); - ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields, - s->unknown_header_fields_size); + ret = bdrv_co_pread(bs->file, sizeof(header), + s->unknown_header_fields_size, + s->unknown_header_fields, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read unknown qcow2 header " "fields"); @@ -1579,8 +1579,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, ret = -ENOMEM; goto fail; } - ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, - s->l1_size * L1E_SIZE); + ret = bdrv_co_pread(bs->file, s->l1_table_offset, s->l1_size * L1E_SIZE, + s->l1_table, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read L1 table"); goto fail; @@ -1614,50 +1614,52 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } - /* Open external data file */ - s->data_file = bdrv_open_child(NULL, options, "data-file", bs, - &child_of_bds, BDRV_CHILD_DATA, - true, errp); - if (*errp) { - ret = -EINVAL; - goto fail; - } + if (open_data_file) { + /* Open external data file */ + s->data_file = bdrv_open_child(NULL, options, "data-file", bs, + &child_of_bds, BDRV_CHILD_DATA, + true, errp); + if (*errp) { + ret = -EINVAL; + goto fail; + } - if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { - if (!s->data_file && s->image_data_file) { - s->data_file = bdrv_open_child(s->image_data_file, options, - "data-file", bs, &child_of_bds, - BDRV_CHILD_DATA, false, errp); + if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { + if (!s->data_file && s->image_data_file) { + s->data_file = bdrv_open_child(s->image_data_file, options, + "data-file", bs, &child_of_bds, + BDRV_CHILD_DATA, false, errp); + if (!s->data_file) { + ret = -EINVAL; + goto fail; + } + } if (!s->data_file) { + error_setg(errp, "'data-file' is required for this image"); ret = -EINVAL; goto fail; } - } - if (!s->data_file) { - error_setg(errp, "'data-file' is required for this image"); - ret = -EINVAL; - goto fail; - } - /* No data here */ - bs->file->role &= ~BDRV_CHILD_DATA; + /* No data here */ + bs->file->role &= ~BDRV_CHILD_DATA; - /* Must succeed because we have given up permissions if anything */ - bdrv_child_refresh_perms(bs, bs->file, &error_abort); - } else { - if (s->data_file) { - error_setg(errp, "'data-file' can only be set for images with an " - "external data file"); - ret = -EINVAL; - goto fail; - } + /* Must succeed because we have given up permissions if anything */ + bdrv_child_refresh_perms(bs, bs->file, &error_abort); + } else { + if (s->data_file) { + error_setg(errp, "'data-file' can only be set for images with " + "an external data file"); + ret = -EINVAL; + goto fail; + } - s->data_file = bs->file; + s->data_file = bs->file; - if (data_file_is_raw(bs)) { - error_setg(errp, "data-file-raw requires a data file"); - ret = -EINVAL; - goto fail; + if (data_file_is_raw(bs)) { + error_setg(errp, "data-file-raw requires a data file"); + ret = -EINVAL; + goto fail; + } } } @@ -1695,16 +1697,27 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, ret = -EINVAL; goto fail; } - ret = bdrv_pread(bs->file, header.backing_file_offset, - bs->auto_backing_file, len); + + s->image_backing_file = g_malloc(len + 1); + ret = bdrv_co_pread(bs->file, header.backing_file_offset, len, + 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); + } } /* @@ -1839,7 +1852,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, fail: g_free(s->image_data_file); - if (has_data_file(bs)) { + if (open_data_file && has_data_file(bs)) { bdrv_unref_child(bs, s->data_file); s->data_file = NULL; } @@ -1876,7 +1889,8 @@ static void coroutine_fn qcow2_open_entry(void *opaque) BDRVQcow2State *s = qoc->bs->opaque; qemu_co_mutex_lock(&s->lock); - qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp); + qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true, + qoc->errp); qemu_co_mutex_unlock(&s->lock); } @@ -1891,11 +1905,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, .errp = errp, .ret = -EINPROGRESS }; + int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } /* Initialise locks */ @@ -2434,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 @@ -2452,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; @@ -2714,7 +2729,7 @@ static int qcow2_inactivate(BlockDriverState *bs) return result; } -static void qcow2_close(BlockDriverState *bs) +static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) { BDRVQcow2State *s = bs->opaque; qemu_vfree(s->l1_table); @@ -2740,7 +2755,7 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->image_backing_file); g_free(s->image_backing_format); - if (has_data_file(bs)) { + if (close_data_file && has_data_file(bs)) { bdrv_unref_child(bs, s->data_file); s->data_file = NULL; } @@ -2749,11 +2764,17 @@ static void qcow2_close(BlockDriverState *bs) qcow2_free_snapshots(bs); } +static void qcow2_close(BlockDriverState *bs) +{ + qcow2_do_close(bs, true); +} + static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs, Error **errp) { ERRP_GUARD(); BDRVQcow2State *s = bs->opaque; + BdrvChild *data_file; int flags = s->flags; QCryptoBlock *crypto = NULL; QDict *options; @@ -2767,14 +2788,24 @@ static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs, crypto = s->crypto; s->crypto = NULL; - qcow2_close(bs); + /* + * Do not reopen s->data_file (i.e., have qcow2_do_close() not close it, + * and then prevent qcow2_do_open() from opening it), because this function + * runs in the I/O path and as such we must not invoke global-state + * functions like bdrv_unref_child() and bdrv_open_child(). + */ + + qcow2_do_close(bs, false); + data_file = s->data_file; memset(s, 0, sizeof(BDRVQcow2State)); + s->data_file = data_file; + options = qdict_clone_shallow(bs->options); flags &= ~BDRV_O_INACTIVE; qemu_co_mutex_lock(&s->lock); - ret = qcow2_do_open(bs, options, flags, errp); + ret = qcow2_do_open(bs, options, flags, false, errp); qemu_co_mutex_unlock(&s->lock); qobject_unref(options); if (ret < 0) { @@ -3061,7 +3092,7 @@ int qcow2_update_header(BlockDriverState *bs) } /* Write the new header */ - ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size); + ret = bdrv_pwrite(bs->file, 0, s->cluster_size, header, 0); if (ret < 0) { goto fail; } @@ -3477,7 +3508,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) if (!qcow2_opts->has_preallocation) { qcow2_opts->preallocation = PREALLOC_MODE_OFF; } - if (qcow2_opts->has_backing_file && + if (qcow2_opts->backing_file && qcow2_opts->preallocation != PREALLOC_MODE_OFF && !qcow2_opts->extended_l2) { @@ -3486,7 +3517,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) ret = -EINVAL; goto out; } - if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) { + if (qcow2_opts->has_backing_fmt && !qcow2_opts->backing_file) { error_setg(errp, "Backing format cannot be used without backing file"); ret = -EINVAL; goto out; @@ -3527,7 +3558,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) ret = -EINVAL; goto out; } - if (qcow2_opts->data_file_raw && qcow2_opts->has_backing_file) { + if (qcow2_opts->data_file_raw && qcow2_opts->backing_file) { error_setg(errp, "Backing file and data-file-raw cannot be used at " "the same time"); ret = -EINVAL; @@ -3553,7 +3584,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) * backing file when specifying data_file_raw is an error * anyway. */ - assert(!qcow2_opts->has_backing_file); + assert(!qcow2_opts->backing_file); } if (qcow2_opts->data_file) { @@ -3648,7 +3679,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) cpu_to_be64(QCOW2_INCOMPAT_EXTL2); } - ret = blk_pwrite(blk, 0, header, cluster_size, 0); + ret = blk_co_pwrite(blk, 0, cluster_size, header, 0); g_free(header); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write qcow2 header"); @@ -3658,7 +3689,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) /* Write a refcount table with one refcount block */ refcount_table = g_malloc0(2 * cluster_size); refcount_table[0] = cpu_to_be64(2 * cluster_size); - ret = blk_pwrite(blk, cluster_size, refcount_table, 2 * cluster_size, 0); + ret = blk_co_pwrite(blk, cluster_size, 2 * cluster_size, refcount_table, 0); g_free(refcount_table); if (ret < 0) { @@ -3713,15 +3744,15 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Okay, now that we have a valid image, let's give it the right size */ - ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation, - 0, errp); + ret = blk_co_truncate(blk, qcow2_opts->size, false, + qcow2_opts->preallocation, 0, errp); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; } /* Want a backing file? There you go. */ - if (qcow2_opts->has_backing_file) { + if (qcow2_opts->backing_file) { const char *backing_format = NULL; if (qcow2_opts->has_backing_fmt) { @@ -3739,7 +3770,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Want encryption? There you go. */ - if (qcow2_opts->has_encrypt) { + if (qcow2_opts->encrypt) { ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp); if (ret < 0) { goto out; @@ -3840,7 +3871,7 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto finish; } @@ -3855,7 +3886,7 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, /* Create and open an external data file (protocol layer) */ val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE); if (val) { - ret = bdrv_create_file(val, opts, errp); + ret = bdrv_co_create_file(val, opts, errp); if (ret < 0) { goto finish; } @@ -4530,8 +4561,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, /* write updated header.size */ offset = cpu_to_be64(offset); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), - &offset, sizeof(offset)); + ret = bdrv_co_pwrite_sync(bs->file, offsetof(QCowHeader, size), + sizeof(offset), &offset, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to update the image size"); goto fail; @@ -4808,7 +4839,7 @@ static int make_completely_empty(BlockDriverState *bs) l1_ofs_rt_ofs_cls.reftable_offset = cpu_to_be64(s->cluster_size); l1_ofs_rt_ofs_cls.reftable_clusters = cpu_to_be32(1); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_table_offset), - &l1_ofs_rt_ofs_cls, sizeof(l1_ofs_rt_ofs_cls)); + sizeof(l1_ofs_rt_ofs_cls), &l1_ofs_rt_ofs_cls, 0); if (ret < 0) { goto fail_broken_refcounts; } @@ -4839,8 +4870,8 @@ static int make_completely_empty(BlockDriverState *bs) /* Enter the first refblock into the reftable */ rt_entry = cpu_to_be64(2 * s->cluster_size); - ret = bdrv_pwrite_sync(bs->file, s->cluster_size, - &rt_entry, sizeof(rt_entry)); + ret = bdrv_pwrite_sync(bs->file, s->cluster_size, sizeof(rt_entry), + &rt_entry, 0); if (ret < 0) { goto fail_broken_refcounts; } @@ -5164,7 +5195,6 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, .refcount_bits = s->refcount_bits, .has_bitmaps = !!bitmaps, .bitmaps = bitmaps, - .has_data_file = !!s->image_data_file, .data_file = g_strdup(s->image_data_file), .has_data_file_raw = has_data_file(bs), .data_file_raw = data_file_is_raw(bs), @@ -5195,7 +5225,6 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, memset(&encrypt_info->u, 0, sizeof(encrypt_info->u)); qapi_free_QCryptoBlockInfo(encrypt_info); - spec_info->u.qcow2.data->has_encrypt = true; spec_info->u.qcow2.data->encrypt = qencrypt; } @@ -5256,8 +5285,8 @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs, return pos; } -static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t pos) +static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs, + QEMUIOVector *qiov, int64_t pos) { int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); if (offset < 0) { @@ -5268,8 +5297,8 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0); } -static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t pos) +static coroutine_fn int qcow2_load_vmstate(BlockDriverState *bs, + QEMUIOVector *qiov, int64_t pos) { int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); if (offset < 0) { @@ -5815,7 +5844,7 @@ static int coroutine_fn qcow2_co_amend(BlockDriverState *bs, BDRVQcow2State *s = bs->opaque; int ret = 0; - if (qopts->has_encrypt) { + if (qopts->encrypt) { if (!s->crypto) { error_setg(errp, "image is not encrypted, can't amend"); return -EOPNOTSUPP; @@ -5880,7 +5909,7 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, node_name = bdrv_get_node_name(bs); qapi_event_send_block_image_corrupted(bdrv_get_device_name(bs), - *node_name != '\0', node_name, + *node_name ? node_name : NULL, message, offset >= 0, offset, size >= 0, size, fatal); diff --git a/block/qcow2.h b/block/qcow2.h index ba436a8d0d68..2285f18a734b 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -846,7 +846,7 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset, Error **errp); /* qcow2-refcount.c functions */ -int qcow2_refcount_init(BlockDriverState *bs); +int coroutine_fn qcow2_refcount_init(BlockDriverState *bs); void qcow2_refcount_close(BlockDriverState *bs); int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, @@ -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); @@ -893,14 +893,14 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, Error **errp); -int qcow2_shrink_reftable(BlockDriverState *bs); +int coroutine_fn 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, bool exact_size); -int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); +int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, uint8_t *buf, int nb_sectors, bool enc, Error **errp); @@ -908,23 +908,24 @@ 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 qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size, - uint64_t *host_offset); +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, + unsigned int *bytes, + uint64_t *host_offset, QCowL2Meta **m); +int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size, + uint64_t *host_offset); 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, @@ -981,8 +982,8 @@ void qcow2_cache_discard(Qcow2Cache *c, void *table); int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size); -bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, - Error **errp); +bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs, + bool *header_updated, Error **errp); bool qcow2_get_bitmap_info_list(BlockDriverState *bs, Qcow2BitmapInfoList **info_list, Error **errp); int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); @@ -990,13 +991,13 @@ int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored, Error **errp); int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); -bool qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, - const char *name, - uint32_t granularity, - Error **errp); -int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, - const char *name, - Error **errp); +bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, + const char *name, + uint32_t granularity, + Error **errp); +int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, + const char *name, + Error **errp); bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, uint32_t cluster_size); diff --git a/block/qed-table.c b/block/qed-table.c index 1cc844b1a5f8..aa203f262797 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -100,7 +100,7 @@ static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset, } if (flush) { - ret = bdrv_flush(s->bs); + ret = bdrv_co_flush(s->bs); if (ret < 0) { goto out; } diff --git a/block/qed.c b/block/qed.c index f34d9a3ac1a0..faa606618e1a 100644 --- a/block/qed.c +++ b/block/qed.c @@ -87,14 +87,9 @@ static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le) int qed_write_header_sync(BDRVQEDState *s) { QEDHeader le; - int ret; qed_header_cpu_to_le(&s->header, &le); - ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le)); - if (ret != sizeof(le)) { - return ret; - } - return 0; + return bdrv_pwrite(s->bs->file, 0, sizeof(le), &le, 0); } /** @@ -207,7 +202,7 @@ static int qed_read_string(BdrvChild *file, uint64_t offset, size_t n, if (n >= buflen) { return -EINVAL; } - ret = bdrv_pread(file, offset, buf, n); + ret = bdrv_pread(file, offset, n, buf, 0); if (ret < 0) { return ret; } @@ -259,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); @@ -267,7 +262,7 @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) assert(!s->allocating_write_reqs_plugged); if (s->allocating_acb != NULL) { /* Another allocating write came concurrently. This cannot happen - * from bdrv_qed_co_drain_begin, but it can happen when the timer runs. + * from bdrv_qed_drain_begin, but it can happen when the timer runs. */ qemu_co_mutex_unlock(&s->table_lock); return false; @@ -278,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); @@ -287,9 +282,8 @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s) qemu_co_mutex_unlock(&s->table_lock); } -static void coroutine_fn qed_need_check_timer_entry(void *opaque) +static void coroutine_fn qed_need_check_timer(BDRVQEDState *s) { - BDRVQEDState *s = opaque; int ret; trace_qed_need_check_timer_cb(s); @@ -315,9 +309,20 @@ static void coroutine_fn qed_need_check_timer_entry(void *opaque) (void) ret; } +static void coroutine_fn qed_need_check_timer_entry(void *opaque) +{ + BDRVQEDState *s = opaque; + + qed_need_check_timer(opaque); + bdrv_dec_in_flight(s->bs); +} + static void qed_need_check_timer_cb(void *opaque) { + BDRVQEDState *s = opaque; Coroutine *co = qemu_coroutine_create(qed_need_check_timer_entry, opaque); + + bdrv_inc_in_flight(s->bs); qemu_coroutine_enter(co); } @@ -360,7 +365,7 @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs, } } -static void coroutine_fn bdrv_qed_co_drain_begin(BlockDriverState *bs) +static void bdrv_qed_drain_begin(BlockDriverState *bs) { BDRVQEDState *s = bs->opaque; @@ -368,8 +373,12 @@ static void coroutine_fn bdrv_qed_co_drain_begin(BlockDriverState *bs) * header is flushed. */ if (s->need_check_timer && timer_pending(s->need_check_timer)) { + Coroutine *co; + qed_cancel_need_check_timer(s); - qed_need_check_timer_entry(s); + co = qemu_coroutine_create(qed_need_check_timer_entry, s); + bdrv_inc_in_flight(bs); + aio_co_enter(bdrv_get_aio_context(bs), co); } } @@ -392,7 +401,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int64_t file_size; int ret; - ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header)); + ret = bdrv_co_pread(bs->file, 0, sizeof(le_header), &le_header, 0); if (ret < 0) { error_setg(errp, "Failed to read QED header"); return ret; @@ -450,6 +459,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) { @@ -457,16 +468,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"); @@ -490,7 +506,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } /* From here on only known autoclear feature bits are valid */ - bdrv_flush(bs->file->bs); + bdrv_co_flush(bs->file->bs); } s->l1_table = qed_alloc_table(s); @@ -559,11 +575,11 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, .errp = errp, .ret = -EINPROGRESS }; + int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } bdrv_qed_init_state(bs); @@ -691,12 +707,12 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, * The QED format associates file length with allocation status, * so a new file (which is empty) must have a length of 0. */ - ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp); + ret = blk_co_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto out; } - if (qed_opts->has_backing_file) { + if (qed_opts->backing_file) { header.features |= QED_F_BACKING_FILE; header.backing_filename_offset = sizeof(le_header); header.backing_filename_size = strlen(qed_opts->backing_file); @@ -710,18 +726,18 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, } qed_header_cpu_to_le(&header, &le_header); - ret = blk_pwrite(blk, 0, &le_header, sizeof(le_header), 0); + ret = blk_co_pwrite(blk, 0, sizeof(le_header), &le_header, 0); if (ret < 0) { goto out; } - ret = blk_pwrite(blk, sizeof(le_header), qed_opts->backing_file, - header.backing_filename_size, 0); + ret = blk_co_pwrite(blk, sizeof(le_header), header.backing_filename_size, + qed_opts->backing_file, 0); if (ret < 0) { goto out; } l1_table = g_malloc0(l1_size); - ret = blk_pwrite(blk, header.l1_table_offset, l1_table, l1_size, 0); + ret = blk_co_pwrite(blk, header.l1_table_offset, l1_size, l1_table, 0); if (ret < 0) { goto out; } @@ -762,7 +778,7 @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto fail; } @@ -1393,7 +1409,6 @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags) { - assert(!flags); return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE); } @@ -1545,7 +1560,7 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs, } /* Write new header */ - ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len); + ret = bdrv_pwrite_sync(bs->file, 0, buffer_len, buffer, 0); g_free(buffer); if (ret == 0) { memcpy(&s->header, &new_header, sizeof(new_header)); @@ -1646,7 +1661,7 @@ static BlockDriver bdrv_qed = { .bdrv_co_check = bdrv_qed_co_check, .bdrv_detach_aio_context = bdrv_qed_detach_aio_context, .bdrv_attach_aio_context = bdrv_qed_attach_aio_context, - .bdrv_co_drain_begin = bdrv_qed_co_drain_begin, + .bdrv_drain_begin = bdrv_qed_drain_begin, }; static void bdrv_qed_init(void) diff --git a/block/quorum.c b/block/quorum.c index f33f30d36b84..7f21c03f1fdb 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); @@ -203,7 +202,7 @@ static void quorum_report_bad(QuorumOpType type, uint64_t offset, msg = strerror(-ret); } - qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name, start_sector, + qapi_event_send_quorum_report_bad(type, msg, node_name, start_sector, end_sector - start_sector); } @@ -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 @@ static void quorum_vote(QuorumAIOCB *acb) 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 69fd650eaf77..28905b09ee8a 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -258,6 +258,8 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, qemu_iovec_add(&local_qiov, buf, 512); qemu_iovec_concat(&local_qiov, qiov, 512, qiov->size - 512); qiov = &local_qiov; + + flags &= ~BDRV_REQ_REGISTERED_BUF; } ret = raw_adjust_offset(bs, &offset, bytes, true); @@ -411,7 +413,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) { @@ -430,7 +433,7 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, QemuOpts *opts, Error **errp) { - return bdrv_create_file(filename, opts, errp); + return bdrv_co_create_file(filename, opts, errp); } static int raw_open(BlockDriverState *bs, QDict *options, int flags, @@ -457,13 +460,13 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - file_role, false, errp); + bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + file_role, false, errp); if (!bs->file) { 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 +492,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/rbd.c b/block/rbd.c index 6caf35cbbade..3aa6aae0e0af 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -536,13 +536,13 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options, int ret; assert(options->driver == BLOCKDEV_DRIVER_RBD); - if (opts->location->has_snapshot) { + if (opts->location->snapshot) { error_setg(errp, "Can't use snapshot name for image creation"); return -EINVAL; } #ifndef LIBRBD_SUPPORTS_ENCRYPTION - if (opts->has_encrypt) { + if (opts->encrypt) { error_setg(errp, "RBD library does not support image encryption"); return -ENOTSUP; } @@ -574,7 +574,7 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options, } #ifdef LIBRBD_SUPPORTS_ENCRYPTION - if (opts->has_encrypt) { + if (opts->encrypt) { rbd_image_t image; ret = rbd_open(io_ctx, opts->location->image, &image, NULL); @@ -686,7 +686,6 @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv, goto exit; } rbd_opts->encrypt = encrypt; - rbd_opts->has_encrypt = !!encrypt; /* * Caution: while qdict_get_try_str() is fine, getting non-string @@ -697,11 +696,8 @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv, loc = rbd_opts->location; loc->pool = g_strdup(qdict_get_try_str(options, "pool")); loc->conf = g_strdup(qdict_get_try_str(options, "conf")); - loc->has_conf = !!loc->conf; loc->user = g_strdup(qdict_get_try_str(options, "user")); - loc->has_user = !!loc->user; loc->q_namespace = g_strdup(qdict_get_try_str(options, "namespace")); - loc->has_q_namespace = !!loc->q_namespace; loc->image = g_strdup(qdict_get_try_str(options, "image")); keypairs = qdict_get_try_str(options, "=keyvalue-pairs"); @@ -767,7 +763,6 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, return -EINVAL; } opts->key_secret = g_strdup(secretid); - opts->has_key_secret = true; } mon_host = qemu_rbd_mon_host(opts, &local_err); @@ -785,7 +780,7 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, /* try default location when conf=NULL, but ignore failure */ r = rados_conf_read_file(*cluster, opts->conf); - if (opts->has_conf && r < 0) { + if (opts->conf && r < 0) { error_setg_errno(errp, -r, "error reading conf file %s", opts->conf); goto failed_shutdown; } @@ -831,6 +826,26 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, error_setg_errno(errp, -r, "error opening pool %s", opts->pool); goto failed_shutdown; } + +#ifdef HAVE_RBD_NAMESPACE_EXISTS + if (opts->q_namespace && strlen(opts->q_namespace) > 0) { + bool exists; + + r = rbd_namespace_exists(*io_ctx, opts->q_namespace, &exists); + if (r < 0) { + error_setg_errno(errp, -r, "error checking namespace"); + goto failed_ioctx_destroy; + } + + if (!exists) { + error_setg(errp, "namespace '%s' does not exist", + opts->q_namespace); + r = -ENOENT; + goto failed_ioctx_destroy; + } + } +#endif + /* * Set the namespace after opening the io context on the pool, * if nspace == NULL or if nspace == "", it is just as we did nothing @@ -840,6 +855,10 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, r = 0; goto out; +#ifdef HAVE_RBD_NAMESPACE_EXISTS +failed_ioctx_destroy: + rados_ioctx_destroy(*io_ctx); +#endif failed_shutdown: rados_shutdown(*cluster); out: @@ -967,7 +986,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, goto failed_open; } - if (opts->has_encrypt) { + if (opts->encrypt) { #ifdef LIBRBD_SUPPORTS_ENCRYPTION r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp); if (r < 0) { diff --git a/block/replication.c b/block/replication.c index 55c8f894aa31..c62f48a87465 100644 --- a/block/replication.c +++ b/block/replication.c @@ -88,11 +88,9 @@ static int replication_open(BlockDriverState *bs, QDict *options, const char *mode; const char *top_id; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } ret = -EINVAL; @@ -142,6 +140,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); @@ -260,7 +259,6 @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs, int ret; int64_t n; - assert(!flags); ret = replication_get_io_status(s); if (ret < 0) { goto out; @@ -376,9 +374,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, s->orig_secondary_read_only = bdrv_is_read_only(secondary_disk->bs); } - bdrv_subtree_drained_begin(hidden_disk->bs); - bdrv_subtree_drained_begin(secondary_disk->bs); - if (s->orig_hidden_read_only) { QDict *opts = qdict_new(); qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); @@ -403,9 +398,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, aio_context_acquire(ctx); } } - - bdrv_subtree_drained_end(hidden_disk->bs); - bdrv_subtree_drained_end(secondary_disk->bs); } static void backup_job_cleanup(BlockDriverState *bs) @@ -726,7 +718,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/snapshot-access.c b/block/snapshot-access.c index 77b87c194619..0a30ec6cd9aa 100644 --- a/block/snapshot-access.c +++ b/block/snapshot-access.c @@ -82,9 +82,9 @@ static void snapshot_access_refresh_filename(BlockDriverState *bs) static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, - false, errp); + bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, + false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/snapshot.c b/block/snapshot.c index d6f53c30657d..e22ac3eac638 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -151,41 +151,29 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs, } /** - * Return a pointer to the child BDS pointer to which we can fall + * Return a pointer to child of given BDS to which we can fall * back if the given BDS does not support snapshots. * Return NULL if there is no BDS to (safely) fall back to. - * - * We need to return an indirect pointer because bdrv_snapshot_goto() - * has to modify the BdrvChild pointer. */ -static BdrvChild **bdrv_snapshot_fallback_ptr(BlockDriverState *bs) +static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs) { - BdrvChild **fallback; + BdrvChild *fallback = bdrv_primary_child(bs); BdrvChild *child; - /* - * The only BdrvChild pointers that are safe to modify (and which - * we can thus return a reference to) are bs->file and - * bs->backing. - */ - fallback = &bs->file; - if (!*fallback && bs->drv && bs->drv->is_filter) { - fallback = &bs->backing; - } - - if (!*fallback) { + /* We allow fallback only to primary child */ + if (!fallback) { return NULL; } /* * Check that there are no other children that would need to be * snapshotted. If there are, it is not safe to fall back to - * *fallback. + * fallback. */ QLIST_FOREACH(child, &bs->children, next) { if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | BDRV_CHILD_FILTERED) && - child != *fallback) + child != fallback) { return NULL; } @@ -196,8 +184,7 @@ static BdrvChild **bdrv_snapshot_fallback_ptr(BlockDriverState *bs) static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) { - BdrvChild **child_ptr = bdrv_snapshot_fallback_ptr(bs); - return child_ptr ? (*child_ptr)->bs : NULL; + return child_bs(bdrv_snapshot_fallback_child(bs)); } int bdrv_can_snapshot(BlockDriverState *bs) @@ -244,7 +231,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, Error **errp) { BlockDriver *drv = bs->drv; - BdrvChild **fallback_ptr; + BdrvChild *fallback; int ret, open_ret; GLOBAL_STATE_CODE(); @@ -267,13 +254,13 @@ int bdrv_snapshot_goto(BlockDriverState *bs, return ret; } - fallback_ptr = bdrv_snapshot_fallback_ptr(bs); - if (fallback_ptr) { + fallback = bdrv_snapshot_fallback_child(bs); + if (fallback) { QDict *options; QDict *file_options; Error *local_err = NULL; - BlockDriverState *fallback_bs = (*fallback_ptr)->bs; - char *subqdict_prefix = g_strdup_printf("%s.", (*fallback_ptr)->name); + BlockDriverState *fallback_bs = fallback->bs; + char *subqdict_prefix = g_strdup_printf("%s.", fallback->name); options = qdict_clone_shallow(bs->options); @@ -284,8 +271,8 @@ int bdrv_snapshot_goto(BlockDriverState *bs, qobject_unref(file_options); g_free(subqdict_prefix); - /* Force .bdrv_open() below to re-attach fallback_bs on *fallback_ptr */ - qdict_put_str(options, (*fallback_ptr)->name, + /* Force .bdrv_open() below to re-attach fallback_bs on fallback */ + qdict_put_str(options, fallback->name, bdrv_get_node_name(fallback_bs)); /* Now close bs, apply the snapshot on fallback_bs, and re-open bs */ @@ -294,8 +281,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, } /* .bdrv_open() will re-attach it */ - bdrv_unref_child(bs, *fallback_ptr); - *fallback_ptr = NULL; + bdrv_unref_child(bs, fallback); ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp); open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err); @@ -309,15 +295,12 @@ int bdrv_snapshot_goto(BlockDriverState *bs, } /* - * fallback_ptr is &bs->file or &bs->backing. *fallback_ptr - * was closed above and set to NULL, but the .bdrv_open() call - * has opened it again, because we set the respective option - * (with the qdict_put_str() call above). - * Assert that .bdrv_open() has attached some child on - * *fallback_ptr, and that it has attached the one we wanted - * it to (i.e., fallback_bs). + * fallback was a primary child. It was closed above and set to NULL, + * but the .bdrv_open() call has opened it again, because we set the + * respective option (with the qdict_put_str() call above). + * Assert that .bdrv_open() has attached the right BDS as primary child. */ - assert(*fallback_ptr && fallback_bs == (*fallback_ptr)->bs); + assert(bdrv_primary_bs(bs) == fallback_bs); bdrv_unref(fallback_bs); return ret; } diff --git a/block/ssh.c b/block/ssh.c index a2dc64653699..8508710f2f54 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -643,7 +643,7 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts, unsigned int port = 0; int new_sock = -1; - if (opts->has_user) { + if (opts->user) { s->user = g_strdup(opts->user); } else { s->user = g_strdup(g_get_user_name()); @@ -1129,9 +1129,9 @@ static coroutine_fn int ssh_co_readv(BlockDriverState *bs, return ret; } -static int ssh_write(BDRVSSHState *s, BlockDriverState *bs, - int64_t offset, size_t size, - QEMUIOVector *qiov) +static coroutine_fn int ssh_write(BDRVSSHState *s, BlockDriverState *bs, + int64_t offset, size_t size, + QEMUIOVector *qiov) { ssize_t r; size_t written; @@ -1196,7 +1196,6 @@ static coroutine_fn int ssh_co_writev(BlockDriverState *bs, BDRVSSHState *s = bs->opaque; int ret; - assert(!flags); qemu_co_mutex_lock(&s->lock); ret = ssh_write(s, bs, sector_num * BDRV_SECTOR_SIZE, nb_sectors * BDRV_SECTOR_SIZE, qiov); diff --git a/block/stream.c b/block/stream.c index 694709bd2591..8744ad103f71 100644 --- a/block/stream.c +++ b/block/stream.c @@ -64,13 +64,16 @@ static int stream_prepare(Job *job) bdrv_cor_filter_drop(s->cor_filter_bs); s->cor_filter_bs = NULL; - bdrv_subtree_drained_begin(s->above_base); + /* + * bdrv_set_backing_hd() requires that unfiltered_bs is drained. Drain + * already here and use bdrv_set_backing_hd_drained() instead because + * the polling during drained_begin() might change the graph, and if we do + * this only later, we may end up working with the wrong base node (or it + * might even have gone away by the time we want to use it). + */ + bdrv_drained_begin(unfiltered_bs); base = bdrv_filter_or_cow_bs(s->above_base); - if (base) { - bdrv_ref(base); - } - unfiltered_base = bdrv_skip_filters(base); if (bdrv_cow_child(unfiltered_bs)) { @@ -82,7 +85,13 @@ static int stream_prepare(Job *job) } } - bdrv_set_backing_hd(unfiltered_bs, base, &local_err); + bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err); + + /* + * This call will do I/O, so the graph can change again from here on. + * We have already completed the graph change, so we are not in danger + * of operating on the wrong node any more if this happens. + */ ret = bdrv_change_backing_file(unfiltered_bs, base_id, base_fmt, false); if (local_err) { error_report_err(local_err); @@ -92,10 +101,7 @@ static int stream_prepare(Job *job) } out: - if (base) { - bdrv_unref(base); - } - bdrv_subtree_drained_end(s->above_base); + bdrv_drained_end(unfiltered_bs); return ret; } diff --git a/block/throttle.c b/block/throttle.c index 6e8d52fa2451..88851c84f4d3 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -78,11 +78,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options, char *group; int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } bs->supported_write_flags = bs->file->bs->supported_write_flags | BDRV_REQ_WRITE_UNCHANGED; @@ -162,7 +160,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); } @@ -216,7 +214,7 @@ static void throttle_reopen_abort(BDRVReopenState *reopen_state) reopen_state->opaque = NULL; } -static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs) +static void throttle_drain_begin(BlockDriverState *bs) { ThrottleGroupMember *tgm = bs->opaque; if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) { @@ -224,7 +222,7 @@ static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs) } } -static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs) +static void throttle_drain_end(BlockDriverState *bs) { ThrottleGroupMember *tgm = bs->opaque; assert(tgm->io_limits_disabled); @@ -263,8 +261,8 @@ static BlockDriver bdrv_throttle = { .bdrv_reopen_commit = throttle_reopen_commit, .bdrv_reopen_abort = throttle_reopen_abort, - .bdrv_co_drain_begin = throttle_co_drain_begin, - .bdrv_co_drain_end = throttle_co_drain_end, + .bdrv_drain_begin = throttle_drain_begin, + .bdrv_drain_end = throttle_drain_end, .is_filter = true, .strong_runtime_opts = throttle_strong_runtime_opts, diff --git a/block/trace-events b/block/trace-events index 549090d453e7..48dbf10c66fe 100644 --- a/block/trace-events +++ b/block/trace-events @@ -172,6 +172,8 @@ nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" nbd_client_handshake(const char *export_name) "export '%s'" nbd_client_handshake_success(const char *export_name) "export '%s'" +nbd_reconnect_attempt(unsigned in_flight) "in_flight %u" +nbd_reconnect_attempt_result(int ret, unsigned in_flight) "ret %d in_flight %u" # ssh.c ssh_restart_coroutine(void *co) "co=%p" diff --git a/block/vdi.c b/block/vdi.c index cca3a3a3567f..479bcfe820ed 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -377,15 +377,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, int ret; QemuUUID uuid_link, uuid_parent; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } logout("\n"); - ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); + ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); if (ret < 0) { goto fail; } @@ -485,8 +484,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - ret = bdrv_pread(bs->file, header.offset_bmap, s->bmap, - bmap_size * SECTOR_SIZE); + ret = bdrv_pread(bs->file, header.offset_bmap, bmap_size * SECTOR_SIZE, + s->bmap, 0); if (ret < 0) { goto fail_free_bmap; } @@ -664,7 +663,8 @@ vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, * so this full-cluster write does not overlap a partial write * of the same cluster, issued from the "else" branch. */ - ret = bdrv_pwrite(bs->file, data_offset, block, s->block_size); + ret = bdrv_co_pwrite(bs->file, data_offset, s->block_size, block, + 0); qemu_co_rwlock_unlock(&s->bmap_lock); } else { nonallocating_write: @@ -709,7 +709,7 @@ vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, assert(VDI_IS_ALLOCATED(bmap_first)); *header = s->header; vdi_header_to_le(header); - ret = bdrv_pwrite(bs->file, 0, header, sizeof(*header)); + ret = bdrv_co_pwrite(bs->file, 0, sizeof(*header), header, 0); g_free(header); if (ret < 0) { @@ -726,11 +726,11 @@ vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; logout("will write %u block map sectors starting from entry %u\n", n_sectors, bmap_first); - ret = bdrv_pwrite(bs->file, offset * SECTOR_SIZE, base, - n_sectors * SECTOR_SIZE); + ret = bdrv_co_pwrite(bs->file, offset * SECTOR_SIZE, + n_sectors * SECTOR_SIZE, base, 0); } - return ret < 0 ? ret : 0; + return ret; } static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, @@ -845,7 +845,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, vdi_header_print(&header); } vdi_header_to_le(&header); - ret = blk_pwrite(blk, offset, &header, sizeof(header), 0); + ret = blk_co_pwrite(blk, offset, sizeof(header), &header, 0); if (ret < 0) { error_setg(errp, "Error writing header"); goto exit; @@ -866,7 +866,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, bmap[i] = VDI_UNALLOCATED; } } - ret = blk_pwrite(blk, offset, bmap, bmap_size, 0); + ret = blk_co_pwrite(blk, offset, bmap_size, bmap, 0); if (ret < 0) { error_setg(errp, "Error writing bmap"); goto exit; @@ -875,8 +875,8 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, } if (image_type == VDI_TYPE_STATIC) { - ret = blk_truncate(blk, offset + blocks * block_size, false, - PREALLOC_MODE_OFF, 0, errp); + ret = blk_co_truncate(blk, offset + blocks * block_size, false, + PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { error_prepend(errp, "Failed to statically allocate file"); goto exit; @@ -934,7 +934,7 @@ static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true); /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto done; } diff --git a/block/vhdx-log.c b/block/vhdx-log.c index ff0d4e0da057..572582b87bfb 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -84,7 +84,7 @@ static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log, offset = log->offset + read; - ret = bdrv_pread(bs->file, offset, hdr, sizeof(VHDXLogEntryHeader)); + ret = bdrv_pread(bs->file, offset, sizeof(VHDXLogEntryHeader), hdr, 0); if (ret < 0) { goto exit; } @@ -144,7 +144,7 @@ static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log, } offset = log->offset + read; - ret = bdrv_pread(bs->file, offset, buffer, VHDX_LOG_SECTOR_SIZE); + ret = bdrv_pread(bs->file, offset, VHDX_LOG_SECTOR_SIZE, buffer, 0); if (ret < 0) { goto exit; } @@ -194,8 +194,8 @@ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log, /* full */ break; } - ret = bdrv_pwrite(bs->file, offset, buffer_tmp, - VHDX_LOG_SECTOR_SIZE); + ret = bdrv_pwrite(bs->file, offset, VHDX_LOG_SECTOR_SIZE, buffer_tmp, + 0); if (ret < 0) { goto exit; } @@ -466,8 +466,8 @@ static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc, /* count is only > 1 if we are writing zeroes */ for (i = 0; i < count; i++) { - ret = bdrv_pwrite_sync(bs->file, file_offset, buffer, - VHDX_LOG_SECTOR_SIZE); + ret = bdrv_pwrite_sync(bs->file, file_offset, VHDX_LOG_SECTOR_SIZE, + buffer, 0); if (ret < 0) { goto exit; } @@ -970,8 +970,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s, if (i == 0 && leading_length) { /* partial sector at the front of the buffer */ - ret = bdrv_pread(bs->file, file_offset, merged_sector, - VHDX_LOG_SECTOR_SIZE); + ret = bdrv_pread(bs->file, file_offset, VHDX_LOG_SECTOR_SIZE, + merged_sector, 0); if (ret < 0) { goto exit; } @@ -980,10 +980,9 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s, sector_write = merged_sector; } else if (i == sectors - 1 && trailing_length) { /* partial sector at the end of the buffer */ - ret = bdrv_pread(bs->file, - file_offset, - merged_sector + trailing_length, - VHDX_LOG_SECTOR_SIZE - trailing_length); + ret = bdrv_pread(bs->file, file_offset, + VHDX_LOG_SECTOR_SIZE - trailing_length, + merged_sector + trailing_length, 0); if (ret < 0) { goto exit; } diff --git a/block/vhdx.c b/block/vhdx.c index 410c6f961017..4c929800feeb 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -326,7 +326,7 @@ static int vhdx_write_header(BdrvChild *file, VHDXHeader *hdr, buffer = qemu_blockalign(bs_file, VHDX_HEADER_SIZE); if (read) { /* if true, we can't assume the extra reserved bytes are 0 */ - ret = bdrv_pread(file, offset, buffer, VHDX_HEADER_SIZE); + ret = bdrv_pread(file, offset, VHDX_HEADER_SIZE, buffer, 0); if (ret < 0) { goto exit; } @@ -340,7 +340,7 @@ static int vhdx_write_header(BdrvChild *file, VHDXHeader *hdr, vhdx_header_le_export(hdr, header_le); vhdx_update_checksum(buffer, VHDX_HEADER_SIZE, offsetof(VHDXHeader, checksum)); - ret = bdrv_pwrite_sync(file, offset, header_le, sizeof(VHDXHeader)); + ret = bdrv_pwrite_sync(file, offset, sizeof(VHDXHeader), header_le, 0); exit: qemu_vfree(buffer); @@ -440,8 +440,8 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s, /* We have to read the whole VHDX_HEADER_SIZE instead of * sizeof(VHDXHeader), because the checksum is over the whole * region */ - ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer, - VHDX_HEADER_SIZE); + ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, VHDX_HEADER_SIZE, buffer, + 0); if (ret < 0) { goto fail; } @@ -457,8 +457,8 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s, } } - ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, - VHDX_HEADER_SIZE); + ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, VHDX_HEADER_SIZE, buffer, + 0); if (ret < 0) { goto fail; } @@ -531,8 +531,8 @@ static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s) * whole block */ buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE); - ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, buffer, - VHDX_HEADER_BLOCK_SIZE); + ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, + VHDX_HEADER_BLOCK_SIZE, buffer, 0); if (ret < 0) { goto fail; } @@ -644,8 +644,8 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE); - ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, buffer, - VHDX_METADATA_TABLE_MAX_SIZE); + ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, + VHDX_METADATA_TABLE_MAX_SIZE, buffer, 0); if (ret < 0) { goto exit; } @@ -750,8 +750,9 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) ret = bdrv_pread(bs->file, s->metadata_entries.file_parameters_entry.offset + s->metadata_rt.file_offset, + sizeof(s->params), &s->params, - sizeof(s->params)); + 0); if (ret < 0) { goto exit; @@ -785,24 +786,27 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) ret = bdrv_pread(bs->file, s->metadata_entries.virtual_disk_size_entry.offset + s->metadata_rt.file_offset, + sizeof(uint64_t), &s->virtual_disk_size, - sizeof(uint64_t)); + 0); if (ret < 0) { goto exit; } ret = bdrv_pread(bs->file, s->metadata_entries.logical_sector_size_entry.offset + s->metadata_rt.file_offset, + sizeof(uint32_t), &s->logical_sector_size, - sizeof(uint32_t)); + 0); if (ret < 0) { goto exit; } ret = bdrv_pread(bs->file, s->metadata_entries.phys_sector_size_entry.offset + s->metadata_rt.file_offset, + sizeof(uint32_t), &s->physical_sector_size, - sizeof(uint32_t)); + 0); if (ret < 0) { goto exit; } @@ -997,10 +1001,9 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, uint64_t signature; Error *local_err = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } s->bat = NULL; @@ -1010,7 +1013,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, QLIST_INIT(&s->regions); /* validate the file signature */ - ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t)); + ret = bdrv_pread(bs->file, 0, sizeof(uint64_t), &signature, 0); if (ret < 0) { goto fail; } @@ -1069,7 +1072,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length); + ret = bdrv_pread(bs->file, s->bat_offset, s->bat_rt.length, s->bat, 0); if (ret < 0) { goto fail; } @@ -1338,7 +1341,6 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, uint64_t bat_prior_offset = 0; bool bat_update = false; - assert(!flags); qemu_iovec_init(&hd_qiov, qiov->niov); qemu_co_mutex_lock(&s->lock); @@ -1661,13 +1663,13 @@ static int vhdx_create_new_metadata(BlockBackend *blk, VHDX_META_FLAGS_IS_VIRTUAL_DISK; vhdx_metadata_entry_le_export(&md_table_entry[4]); - ret = blk_pwrite(blk, metadata_offset, buffer, VHDX_HEADER_BLOCK_SIZE, 0); + ret = blk_pwrite(blk, metadata_offset, VHDX_HEADER_BLOCK_SIZE, buffer, 0); if (ret < 0) { goto exit; } - ret = blk_pwrite(blk, metadata_offset + (64 * KiB), entry_buffer, - VHDX_METADATA_ENTRY_BUFFER_SIZE, 0); + ret = blk_pwrite(blk, metadata_offset + (64 * KiB), + VHDX_METADATA_ENTRY_BUFFER_SIZE, entry_buffer, 0); if (ret < 0) { goto exit; } @@ -1752,7 +1754,7 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]); sector_num += s->sectors_per_block; } - ret = blk_pwrite(blk, file_offset, s->bat, length, 0); + ret = blk_pwrite(blk, file_offset, length, s->bat, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write the BAT"); goto exit; @@ -1856,15 +1858,15 @@ static int vhdx_create_new_region_table(BlockBackend *blk, } /* Now write out the region headers to disk */ - ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, buffer, - VHDX_HEADER_BLOCK_SIZE, 0); + ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, VHDX_HEADER_BLOCK_SIZE, + buffer, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write first region table"); goto exit; } - ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, buffer, - VHDX_HEADER_BLOCK_SIZE, 0); + ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, VHDX_HEADER_BLOCK_SIZE, + buffer, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write second region table"); goto exit; @@ -2008,15 +2010,15 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL, &creator_items, NULL); signature = cpu_to_le64(VHDX_FILE_SIGNATURE); - ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature), - 0); + ret = blk_co_pwrite(blk, VHDX_FILE_ID_OFFSET, sizeof(signature), &signature, + 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write file signature"); goto delete_and_exit; } if (creator) { - ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature), - creator, creator_items * sizeof(gunichar2), 0); + ret = blk_co_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature), + creator_items * sizeof(gunichar2), creator, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to write creator field"); goto delete_and_exit; @@ -2082,7 +2084,7 @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto fail; } diff --git a/block/vmdk.c b/block/vmdk.c index 37c0946066ee..8894dac2d4ff 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -178,6 +178,10 @@ typedef struct BDRVVmdkState { char *create_type; } BDRVVmdkState; +typedef struct BDRVVmdkReopenState { + bool *extents_using_bs_file; +} BDRVVmdkReopenState; + typedef struct VmdkMetaData { unsigned int l1_index; unsigned int l2_index; @@ -303,7 +307,7 @@ static int vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid) int ret; desc = g_malloc0(DESC_SIZE); - ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0); if (ret < 0) { goto out; } @@ -344,7 +348,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) desc = g_malloc0(DESC_SIZE); tmp_desc = g_malloc0(DESC_SIZE); - ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0); if (ret < 0) { goto out; } @@ -364,7 +368,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) pstrcat(desc, DESC_SIZE, tmp_desc); } - ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0); out: g_free(desc); @@ -400,15 +404,63 @@ static int vmdk_is_cid_valid(BlockDriverState *bs) return 1; } -/* We have nothing to do for VMDK reopen, stubs just return success */ static int vmdk_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, Error **errp) { + BDRVVmdkState *s; + BDRVVmdkReopenState *rs; + int i; + assert(state != NULL); assert(state->bs != NULL); + assert(state->opaque == NULL); + + s = state->bs->opaque; + + rs = g_new0(BDRVVmdkReopenState, 1); + state->opaque = rs; + + /* + * Check whether there are any extents stored in bs->file; if bs->file + * changes, we will need to update their .file pointers to follow suit + */ + rs->extents_using_bs_file = g_new(bool, s->num_extents); + for (i = 0; i < s->num_extents; i++) { + rs->extents_using_bs_file[i] = s->extents[i].file == state->bs->file; + } + return 0; } +static void vmdk_reopen_clean(BDRVReopenState *state) +{ + BDRVVmdkReopenState *rs = state->opaque; + + g_free(rs->extents_using_bs_file); + g_free(rs); + state->opaque = NULL; +} + +static void vmdk_reopen_commit(BDRVReopenState *state) +{ + BDRVVmdkState *s = state->bs->opaque; + BDRVVmdkReopenState *rs = state->opaque; + int i; + + for (i = 0; i < s->num_extents; i++) { + if (rs->extents_using_bs_file[i]) { + s->extents[i].file = state->bs->file; + } + } + + vmdk_reopen_clean(state); +} + +static void vmdk_reopen_abort(BDRVReopenState *state) +{ + vmdk_reopen_clean(state); +} + static int vmdk_parent_open(BlockDriverState *bs) { char *p_name; @@ -417,11 +469,10 @@ static int vmdk_parent_open(BlockDriverState *bs) int ret; desc = g_malloc0(DESC_SIZE + 1); - ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0); if (ret < 0) { goto out; } - ret = 0; p_name = strstr(desc, "parentFileNameHint"); if (p_name != NULL) { @@ -537,10 +588,8 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, return -ENOMEM; } - ret = bdrv_pread(extent->file, - extent->l1_table_offset, - extent->l1_table, - l1_size); + ret = bdrv_pread(extent->file, extent->l1_table_offset, l1_size, + extent->l1_table, 0); if (ret < 0) { bdrv_refresh_filename(extent->file->bs); error_setg_errno(errp, -ret, @@ -564,10 +613,8 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, ret = -ENOMEM; goto fail_l1; } - ret = bdrv_pread(extent->file, - extent->l1_backup_table_offset, - extent->l1_backup_table, - l1_size); + ret = bdrv_pread(extent->file, extent->l1_backup_table_offset, + l1_size, extent->l1_backup_table, 0); if (ret < 0) { bdrv_refresh_filename(extent->file->bs); error_setg_errno(errp, -ret, @@ -599,7 +646,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, VMDK3Header header; VmdkExtent *extent = NULL; - ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); + ret = bdrv_pread(file, sizeof(magic), sizeof(header), &header, 0); if (ret < 0) { bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, @@ -763,7 +810,7 @@ static int vmdk_open_se_sparse(BlockDriverState *bs, assert(sizeof(const_header) == SECTOR_SIZE); - ret = bdrv_pread(file, 0, &const_header, sizeof(const_header)); + ret = bdrv_pread(file, 0, sizeof(const_header), &const_header, 0); if (ret < 0) { bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, @@ -780,9 +827,8 @@ static int vmdk_open_se_sparse(BlockDriverState *bs, assert(sizeof(volatile_header) == SECTOR_SIZE); - ret = bdrv_pread(file, - const_header.volatile_header_offset * SECTOR_SIZE, - &volatile_header, sizeof(volatile_header)); + ret = bdrv_pread(file, const_header.volatile_header_offset * SECTOR_SIZE, + sizeof(volatile_header), &volatile_header, 0); if (ret < 0) { bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, @@ -852,13 +898,13 @@ static char *vmdk_read_desc(BdrvChild *file, uint64_t desc_offset, Error **errp) size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ buf = g_malloc(size + 1); - ret = bdrv_pread(file, desc_offset, buf, size); + ret = bdrv_pread(file, desc_offset, size, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read from file"); g_free(buf); return NULL; } - buf[ret] = 0; + buf[size] = 0; return buf; } @@ -876,7 +922,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, int64_t l1_backup_offset = 0; bool compressed; - ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); + ret = bdrv_pread(file, sizeof(magic), sizeof(header), &header, 0); if (ret < 0) { bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, @@ -927,9 +973,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, } QEMU_PACKED eos_marker; } QEMU_PACKED footer; - ret = bdrv_pread(file, - bs->file->bs->total_sectors * 512 - 1536, - &footer, sizeof(footer)); + ret = bdrv_pread(file, bs->file->bs->total_sectors * 512 - 1536, + sizeof(footer), &footer, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read footer"); return ret; @@ -1263,10 +1308,9 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, BDRVVmdkState *s = bs->opaque; uint32_t magic; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } buf = vmdk_read_desc(bs->file, 0, errp); @@ -1359,13 +1403,13 @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp) * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave * it for call to write user data in the request. */ -static int get_whole_cluster(BlockDriverState *bs, - VmdkExtent *extent, - uint64_t cluster_offset, - uint64_t offset, - uint64_t skip_start_bytes, - uint64_t skip_end_bytes, - bool zeroed) +static int coroutine_fn get_whole_cluster(BlockDriverState *bs, + VmdkExtent *extent, + uint64_t cluster_offset, + uint64_t offset, + uint64_t skip_start_bytes, + uint64_t skip_end_bytes, + bool zeroed) { int ret = VMDK_OK; int64_t cluster_bytes; @@ -1396,16 +1440,16 @@ static int get_whole_cluster(BlockDriverState *bs, if (copy_from_backing) { /* qcow2 emits this on bs->file instead of bs->backing */ BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); - ret = bdrv_pread(bs->backing, offset, whole_grain, - skip_start_bytes); + ret = bdrv_co_pread(bs->backing, offset, skip_start_bytes, + whole_grain, 0); if (ret < 0) { ret = VMDK_ERROR; goto exit; } } BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE); - ret = bdrv_pwrite(extent->file, cluster_offset, whole_grain, - skip_start_bytes); + ret = bdrv_co_pwrite(extent->file, cluster_offset, skip_start_bytes, + whole_grain, 0); if (ret < 0) { ret = VMDK_ERROR; goto exit; @@ -1416,18 +1460,18 @@ static int get_whole_cluster(BlockDriverState *bs, if (copy_from_backing) { /* qcow2 emits this on bs->file instead of bs->backing */ BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); - ret = bdrv_pread(bs->backing, offset + skip_end_bytes, - whole_grain + skip_end_bytes, - cluster_bytes - skip_end_bytes); + ret = bdrv_co_pread(bs->backing, offset + skip_end_bytes, + cluster_bytes - skip_end_bytes, + whole_grain + skip_end_bytes, 0); if (ret < 0) { ret = VMDK_ERROR; goto exit; } } BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE); - ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes, - whole_grain + skip_end_bytes, - cluster_bytes - skip_end_bytes); + ret = bdrv_co_pwrite(extent->file, cluster_offset + skip_end_bytes, + cluster_bytes - skip_end_bytes, + whole_grain + skip_end_bytes, 0); if (ret < 0) { ret = VMDK_ERROR; goto exit; @@ -1440,29 +1484,29 @@ static int get_whole_cluster(BlockDriverState *bs, return ret; } -static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, - uint32_t offset) +static int coroutine_fn vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, + uint32_t offset) { offset = cpu_to_le32(offset); /* update L2 table */ BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE); - if (bdrv_pwrite(extent->file, - ((int64_t)m_data->l2_offset * 512) - + (m_data->l2_index * sizeof(offset)), - &offset, sizeof(offset)) < 0) { + if (bdrv_co_pwrite(extent->file, + ((int64_t)m_data->l2_offset * 512) + + (m_data->l2_index * sizeof(offset)), + sizeof(offset), &offset, 0) < 0) { return VMDK_ERROR; } /* update backup L2 table */ if (extent->l1_backup_table_offset != 0) { m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; - if (bdrv_pwrite(extent->file, - ((int64_t)m_data->l2_offset * 512) - + (m_data->l2_index * sizeof(offset)), - &offset, sizeof(offset)) < 0) { + if (bdrv_co_pwrite(extent->file, + ((int64_t)m_data->l2_offset * 512) + + (m_data->l2_index * sizeof(offset)), + sizeof(offset), &offset, 0) < 0) { return VMDK_ERROR; } } - if (bdrv_flush(extent->file->bs) < 0) { + if (bdrv_co_flush(extent->file->bs) < 0) { return VMDK_ERROR; } if (m_data->l2_cache_entry) { @@ -1492,14 +1536,14 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, * VMDK_UNALLOC if cluster is not mapped and @allocate is false. * VMDK_ERROR if failed. */ -static int get_cluster_offset(BlockDriverState *bs, - VmdkExtent *extent, - VmdkMetaData *m_data, - uint64_t offset, - bool allocate, - uint64_t *cluster_offset, - uint64_t skip_start_bytes, - uint64_t skip_end_bytes) +static int coroutine_fn get_cluster_offset(BlockDriverState *bs, + VmdkExtent *extent, + VmdkMetaData *m_data, + uint64_t offset, + bool allocate, + uint64_t *cluster_offset, + uint64_t skip_start_bytes, + uint64_t skip_end_bytes) { unsigned int l1_index, l2_offset, l2_index; int min_index, i, j; @@ -1579,11 +1623,11 @@ static int get_cluster_offset(BlockDriverState *bs, } l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes); BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD); - if (bdrv_pread(extent->file, + if (bdrv_co_pread(extent->file, (int64_t)l2_offset * 512, - l2_table, - l2_size_bytes - ) != l2_size_bytes) { + l2_size_bytes, + l2_table, 0 + ) < 0) { return VMDK_ERROR; } @@ -1741,10 +1785,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; @@ -1822,9 +1867,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; @@ -1851,9 +1897,8 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, cluster_buf = g_malloc(buf_bytes); uncomp_buf = g_malloc(cluster_bytes); BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED); - ret = bdrv_pread(extent->file, - cluster_offset, - cluster_buf, buf_bytes); + ret = bdrv_co_pread(extent->file, cluster_offset, buf_bytes, cluster_buf, + 0); if (ret < 0) { goto out; } @@ -1971,9 +2016,9 @@ vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, * * 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; @@ -2098,8 +2143,8 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, return length; } length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); - ret = bdrv_truncate(s->extents[i].file, length, false, - PREALLOC_MODE_OFF, 0, NULL); + ret = bdrv_co_truncate(s->extents[i].file, length, false, + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; } @@ -2192,12 +2237,12 @@ static int vmdk_init_extent(BlockBackend *blk, header.check_bytes[3] = 0xa; /* write all the data */ - ret = blk_pwrite(blk, 0, &magic, sizeof(magic), 0); + ret = blk_pwrite(blk, 0, sizeof(magic), &magic, 0); if (ret < 0) { error_setg(errp, QERR_IO_ERROR); goto exit; } - ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header), 0); + ret = blk_pwrite(blk, sizeof(magic), sizeof(header), &header, 0); if (ret < 0) { error_setg(errp, QERR_IO_ERROR); goto exit; @@ -2217,7 +2262,7 @@ static int vmdk_init_extent(BlockBackend *blk, gd_buf[i] = cpu_to_le32(tmp); } ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, - gd_buf, gd_buf_size, 0); + gd_buf_size, gd_buf, 0); if (ret < 0) { error_setg(errp, QERR_IO_ERROR); goto exit; @@ -2229,7 +2274,7 @@ static int vmdk_init_extent(BlockBackend *blk, gd_buf[i] = cpu_to_le32(tmp); } ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, - gd_buf, gd_buf_size, 0); + gd_buf_size, gd_buf, 0); if (ret < 0) { error_setg(errp, QERR_IO_ERROR); } @@ -2240,15 +2285,16 @@ static int vmdk_init_extent(BlockBackend *blk, return ret; } -static int vmdk_create_extent(const char *filename, int64_t filesize, - bool flat, bool compress, bool zeroed_grain, - BlockBackend **pbb, - QemuOpts *opts, Error **errp) +static int coroutine_fn vmdk_create_extent(const char *filename, + int64_t filesize, bool flat, + bool compress, bool zeroed_grain, + BlockBackend **pbb, + QemuOpts *opts, Error **errp) { int ret; BlockBackend *blk = NULL; - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto exit; } @@ -2321,14 +2367,14 @@ static int filename_decompose(const char *filename, char *path, char *prefix, * non-split format. * idx >= 1: get the n-th extent if in a split subformat */ -typedef BlockBackend *(*vmdk_create_extent_fn)(int64_t size, - int idx, - bool flat, - bool split, - bool compress, - bool zeroed_grain, - void *opaque, - Error **errp); +typedef BlockBackend * coroutine_fn (*vmdk_create_extent_fn)(int64_t size, + int idx, + bool flat, + bool split, + bool compress, + bool zeroed_grain, + void *opaque, + Error **errp); static void vmdk_desc_add_extent(GString *desc, const char *extent_line_fmt, @@ -2540,7 +2586,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, desc_offset = 0x200; } - ret = blk_pwrite(blk, desc_offset, desc, desc_len, 0); + ret = blk_co_pwrite(blk, desc_offset, desc_len, desc, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write description"); goto exit; @@ -2548,7 +2594,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, /* bdrv_pwrite write padding zeros to align to sector, we don't need that * for description file */ if (desc_offset == 0) { - ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp); + ret = blk_co_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto exit; } @@ -2571,7 +2617,7 @@ typedef struct { QemuOpts *opts; } VMDKCreateOptsData; -static BlockBackend *vmdk_co_create_opts_cb(int64_t size, int idx, +static BlockBackend * coroutine_fn vmdk_co_create_opts_cb(int64_t size, int idx, bool flat, bool split, bool compress, bool zeroed_grain, void *opaque, Error **errp) @@ -2723,10 +2769,11 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv, return ret; } -static BlockBackend *vmdk_co_create_cb(int64_t size, int idx, - bool flat, bool split, bool compress, - bool zeroed_grain, void *opaque, - Error **errp) +static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx, + bool flat, bool split, + bool compress, + bool zeroed_grain, + void *opaque, Error **errp) { int ret; BlockDriverState *bs; @@ -2776,7 +2823,6 @@ static BlockBackend *vmdk_co_create_cb(int64_t size, int idx, static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options, Error **errp) { - int ret; BlockdevCreateOptionsVmdk *opts; opts = &create_options->u.vmdk; @@ -2784,24 +2830,19 @@ static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options, /* Validate options */ if (!QEMU_IS_ALIGNED(opts->size, BDRV_SECTOR_SIZE)) { error_setg(errp, "Image size must be a multiple of 512 bytes"); - ret = -EINVAL; - goto out; + return -EINVAL; } - ret = vmdk_co_do_create(opts->size, - opts->subformat, - opts->adapter_type, - opts->backing_file, - opts->hwversion, - opts->toolsversion, - false, - opts->zeroed_grain, - vmdk_co_create_cb, - opts, errp); - return ret; - -out: - return ret; + return vmdk_co_do_create(opts->size, + opts->subformat, + opts->adapter_type, + opts->backing_file, + opts->hwversion, + opts->toolsversion, + false, + opts->zeroed_grain, + vmdk_co_create_cb, + opts, errp); } static void vmdk_close(BlockDriverState *bs) @@ -3072,6 +3113,8 @@ static BlockDriver bdrv_vmdk = { .bdrv_open = vmdk_open, .bdrv_co_check = vmdk_co_check, .bdrv_reopen_prepare = vmdk_reopen_prepare, + .bdrv_reopen_commit = vmdk_reopen_commit, + .bdrv_reopen_abort = vmdk_reopen_abort, .bdrv_child_perm = bdrv_default_perms, .bdrv_co_preadv = vmdk_co_preadv, .bdrv_co_pwritev = vmdk_co_pwritev, diff --git a/block/vpc.c b/block/vpc.c index 4d8f16e1990c..6ee95dcb9600 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -233,10 +233,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, int ret; int64_t bs_size; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, - BDRV_CHILD_IMAGE, false, errp); - if (!bs->file) { - return -EINVAL; + ret = bdrv_open_file_child(NULL, options, "file", bs, errp); + if (ret < 0) { + return ret; } opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort); @@ -252,7 +251,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - ret = bdrv_pread(bs->file, 0, &s->footer, sizeof(s->footer)); + ret = bdrv_pread(bs->file, 0, sizeof(s->footer), &s->footer, 0); if (ret < 0) { error_setg(errp, "Unable to read VHD header"); goto fail; @@ -272,8 +271,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } /* If a fixed disk, the footer is found only at the end of the file */ - ret = bdrv_pread(bs->file, offset - sizeof(*footer), - footer, sizeof(*footer)); + ret = bdrv_pread(bs->file, offset - sizeof(*footer), sizeof(*footer), + footer, 0); if (ret < 0) { goto fail; } @@ -347,7 +346,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, if (disk_type == VHD_DYNAMIC) { ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), - &dyndisk_header, sizeof(dyndisk_header)); + sizeof(dyndisk_header), &dyndisk_header, 0); if (ret < 0) { error_setg(errp, "Error reading dynamic VHD header"); goto fail; @@ -401,8 +400,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, s->bat_offset = be64_to_cpu(dyndisk_header.table_offset); - ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, - pagetable_size); + ret = bdrv_pread(bs->file, s->bat_offset, pagetable_size, + s->pagetable, 0); if (ret < 0) { error_setg(errp, "Error reading pagetable"); goto fail; @@ -516,7 +515,8 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset, s->last_bitmap_offset = bitmap_offset; memset(bitmap, 0xff, s->bitmap_size); - r = bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size); + r = bdrv_pwrite_sync(bs->file, bitmap_offset, s->bitmap_size, bitmap, + 0); if (r < 0) { *err = r; return -2; @@ -538,7 +538,7 @@ static int rewrite_footer(BlockDriverState *bs) BDRVVPCState *s = bs->opaque; int64_t offset = s->free_data_block_offset; - ret = bdrv_pwrite_sync(bs->file, offset, &s->footer, sizeof(s->footer)); + ret = bdrv_pwrite_sync(bs->file, offset, sizeof(s->footer), &s->footer, 0); if (ret < 0) return ret; @@ -572,8 +572,8 @@ static int64_t alloc_block(BlockDriverState *bs, int64_t offset) /* Initialize the block's bitmap */ memset(bitmap, 0xff, s->bitmap_size); - ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap, - s->bitmap_size); + ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, + s->bitmap_size, bitmap, 0); if (ret < 0) { return ret; } @@ -587,7 +587,7 @@ static int64_t alloc_block(BlockDriverState *bs, int64_t offset) /* Write BAT entry to disk */ bat_offset = s->bat_offset + (4 * index); bat_value = cpu_to_be32(s->pagetable[index]); - ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4); + ret = bdrv_pwrite_sync(bs->file, bat_offset, 4, &bat_value, 0); if (ret < 0) goto fail; @@ -833,13 +833,13 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer, block_size = 0x200000; num_bat_entries = DIV_ROUND_UP(total_sectors, block_size / 512); - ret = blk_pwrite(blk, offset, footer, sizeof(*footer), 0); + ret = blk_pwrite(blk, offset, sizeof(*footer), footer, 0); if (ret < 0) { goto fail; } offset = 1536 + ((num_bat_entries * 4 + 511) & ~511); - ret = blk_pwrite(blk, offset, footer, sizeof(*footer), 0); + ret = blk_pwrite(blk, offset, sizeof(*footer), footer, 0); if (ret < 0) { goto fail; } @@ -849,7 +849,7 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer, memset(bat_sector, 0xFF, 512); for (i = 0; i < DIV_ROUND_UP(num_bat_entries * 4, 512); i++) { - ret = blk_pwrite(blk, offset, bat_sector, 512, 0); + ret = blk_pwrite(blk, offset, 512, bat_sector, 0); if (ret < 0) { goto fail; } @@ -877,7 +877,7 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer, /* Write the header */ offset = 512; - ret = blk_pwrite(blk, offset, &dyndisk_header, sizeof(dyndisk_header), 0); + ret = blk_pwrite(blk, offset, sizeof(dyndisk_header), &dyndisk_header, 0); if (ret < 0) { goto fail; } @@ -900,8 +900,8 @@ static int create_fixed_disk(BlockBackend *blk, VHDFooter *footer, return ret; } - ret = blk_pwrite(blk, total_size - sizeof(*footer), - footer, sizeof(*footer), 0); + ret = blk_pwrite(blk, total_size - sizeof(*footer), sizeof(*footer), + footer, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Unable to write VHD header"); return ret; @@ -1111,7 +1111,7 @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, errp); + ret = bdrv_co_create_file(filename, opts, errp); if (ret < 0) { goto fail; } diff --git a/block/vvfat.c b/block/vvfat.c index b2b58d93b8b6..723c91216e0c 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include +#include #include "qapi/error.h" #include "block/block_int.h" #include "block/qdict.h" @@ -499,7 +500,7 @@ static bool valid_filename(const unsigned char *name) (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c > 127 || - strchr("$%'-_@~`!(){}^#&.+,;=[]", c) != NULL)) + strchr(" $%'-_@~`!(){}^#&.+,;=[]", c) != NULL)) { return false; } @@ -1488,8 +1489,8 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64 " allocated\n", sector_num, n >> BDRV_SECTOR_BITS)); - if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, - buf + i * 0x200, n) < 0) { + if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n, + buf + i * 0x200, 0) < 0) { return -1; } i += (n >> BDRV_SECTOR_BITS) - 1; @@ -1978,7 +1979,8 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, return -1; } res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE, - s->cluster_buffer, BDRV_SECTOR_SIZE); + BDRV_SECTOR_SIZE, s->cluster_buffer, + 0); if (res < 0) { return -2; } @@ -2725,13 +2727,9 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) mapping_t* mapping; int j, parent_path_len; -#ifdef __MINGW32__ - if (mkdir(commit->path)) + if (g_mkdir(commit->path, 0755)) { return -5; -#else - if (mkdir(commit->path, 0755)) - return -5; -#endif + } mapping = insert_mapping(s, commit->param.mkdir.cluster, commit->param.mkdir.cluster + 1); @@ -2992,11 +2990,35 @@ DLOG(checkpoint()); vvfat_close_current_file(s); + if (sector_num == s->offset_to_bootsector && nb_sectors == 1) { + /* + * Write on bootsector. Allow only changing the reserved1 field, + * used to mark volume dirtiness + */ + unsigned char *bootsector = s->first_sectors + + s->offset_to_bootsector * 0x200; + /* + * LATER TODO: if FAT32, this is wrong (see init_directories(), + * which always creates a FAT16 bootsector) + */ + const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1); + + for (i = 0; i < 0x200; i++) { + if (i != reserved1_offset && bootsector[i] != buf[i]) { + fprintf(stderr, "Tried to write to protected bootsector\n"); + return -1; + } + } + + /* Update bootsector with the only updatable byte, and return success */ + bootsector[reserved1_offset] = buf[reserved1_offset]; + return 0; + } + /* * Some sanity checks: * - do not allow writing to the boot sector */ - if (sector_num < s->offset_to_fat) return -1; @@ -3062,8 +3084,8 @@ DLOG(checkpoint()); * Use qcow backend. Commit later. */ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); - ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, buf, - nb_sectors * BDRV_SECTOR_SIZE); + ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE, buf, 0); if (ret < 0) { fprintf(stderr, "Error writing to qcow backend\n"); return ret; @@ -3145,10 +3167,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) array_init(&(s->commits), sizeof(commit_t)); - s->qcow_filename = g_malloc(PATH_MAX); - ret = get_tmp_filename(s->qcow_filename, PATH_MAX); - if (ret < 0) { - error_setg_errno(errp, -ret, "can't create temporary file"); + s->qcow_filename = create_tmp_file(errp); + if (!s->qcow_filename) { + ret = -ENOENT; goto err; } diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 9840d25a8298..213012435f46 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -30,18 +30,23 @@ typedef struct NBDServerData { } NBDServerData; static NBDServerData *nbd_server; -static bool is_qemu_nbd; +static int qemu_nbd_connections = -1; /* Non-negative if this is qemu-nbd */ static void nbd_update_server_watch(NBDServerData *s); -void nbd_server_is_qemu_nbd(bool value) +void nbd_server_is_qemu_nbd(int max_connections) { - is_qemu_nbd = value; + qemu_nbd_connections = max_connections; } bool nbd_server_is_running(void) { - return nbd_server || is_qemu_nbd; + return nbd_server || qemu_nbd_connections >= 0; +} + +int nbd_server_max_connections(void) +{ + return nbd_server ? nbd_server->max_connections : qemu_nbd_connections; } static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) @@ -168,8 +173,8 @@ void nbd_server_start_options(NbdServerOptions *arg, Error **errp) } void qmp_nbd_server_start(SocketAddressLegacy *addr, - bool has_tls_creds, const char *tls_creds, - bool has_tls_authz, const char *tls_authz, + const char *tls_creds, + const char *tls_authz, bool has_max_connections, uint32_t max_connections, Error **errp) { @@ -195,8 +200,7 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp) * block-export-add would default to the node-name, but we may have to use * the device name as a default here for compatibility. */ - if (!arg->has_name) { - arg->has_name = true; + if (!arg->name) { arg->name = g_strdup(arg->device); } @@ -210,9 +214,15 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp) }; QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd, qapi_NbdServerAddOptions_base(arg)); - if (arg->has_bitmap) { + if (arg->bitmap) { + BlockDirtyBitmapOrStr *el = g_new(BlockDirtyBitmapOrStr, 1); + + *el = (BlockDirtyBitmapOrStr) { + .type = QTYPE_QSTRING, + .u.local = g_strdup(arg->bitmap), + }; export_opts->u.nbd.has_bitmaps = true; - QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, g_strdup(arg->bitmap)); + QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, el); } /* diff --git a/blockdev.c b/blockdev.c index e46e8312121e..ebf952cd218e 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)) { - 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); + JOB_LOCK_GUARD(); - aio_context_release(aio_context); + for (job = block_job_next_locked(NULL); job; + job = block_job_next_locked(job)) { + if (block_job_has_bdrv(job, blk_bs(blk))) { + 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); @@ -1039,26 +1048,20 @@ static void blockdev_do_action(TransactionAction *action, Error **errp) list.value = action; list.next = NULL; - qmp_transaction(&list, false, NULL, errp); + qmp_transaction(&list, NULL, errp); } -void qmp_blockdev_snapshot_sync(bool has_device, const char *device, - bool has_node_name, const char *node_name, +void qmp_blockdev_snapshot_sync(const char *device, const char *node_name, const char *snapshot_file, - bool has_snapshot_node_name, const char *snapshot_node_name, - bool has_format, const char *format, + const char *format, bool has_mode, NewImageMode mode, Error **errp) { BlockdevSnapshotSync snapshot = { - .has_device = has_device, .device = (char *) device, - .has_node_name = has_node_name, .node_name = (char *) node_name, .snapshot_file = (char *) snapshot_file, - .has_snapshot_node_name = has_snapshot_node_name, .snapshot_node_name = (char *) snapshot_node_name, - .has_format = has_format, .format = (char *) format, .has_mode = has_mode, .mode = mode, @@ -1100,9 +1103,7 @@ void qmp_blockdev_snapshot_internal_sync(const char *device, } SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, - bool has_id, const char *id, - bool has_name, const char *name, Error **errp) { @@ -1120,14 +1121,6 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - if (!has_id) { - id = NULL; - } - - if (!has_name) { - name = NULL; - } - if (!id && !name) { error_setg(errp, "Name or id must be provided"); goto out_aio_context; @@ -1258,7 +1251,7 @@ static void internal_snapshot_prepare(BlkActionState *common, BlockDriverState *bs; QEMUSnapshotInfo old_sn, *sn; bool ret; - qemu_timeval tv; + int64_t rt; BlockdevSnapshotInternal *internal; InternalSnapshotState *state; AioContext *aio_context; @@ -1328,9 +1321,9 @@ static void internal_snapshot_prepare(BlkActionState *common, /* 3. take the snapshot */ sn = &state->sn; pstrcpy(sn->name, sizeof(sn->name), name); - qemu_gettimeofday(&tv); - sn->date_sec = tv.tv_sec; - sn->date_nsec = tv.tv_usec * 1000; + rt = g_get_real_time(); + sn->date_sec = rt / G_USEC_PER_SEC; + sn->date_nsec = (rt % G_USEC_PER_SEC) * 1000; sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (replay_mode != REPLAY_MODE_NONE) { sn->icount = replay_get_current_icount(); @@ -1441,8 +1434,8 @@ static void external_snapshot_prepare(BlkActionState *common, case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC: { BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data; - device = s->has_device ? s->device : NULL; - node_name = s->has_node_name ? s->node_name : NULL; + device = s->device; + node_name = s->node_name; new_image_file = s->snapshot_file; snapshot_ref = NULL; } @@ -1486,10 +1479,9 @@ static void external_snapshot_prepare(BlkActionState *common, if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) { BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data; - const char *format = s->has_format ? s->format : "qcow2"; + const char *format = s->format ?: "qcow2"; enum NewImageMode mode; - const char *snapshot_node_name = - s->has_snapshot_node_name ? s->snapshot_node_name : NULL; + const char *snapshot_node_name = s->snapshot_node_name; if (node_name && !snapshot_node_name) { error_setg(errp, "New overlay node-name missing"); @@ -1515,10 +1507,14 @@ static void external_snapshot_prepare(BlkActionState *common, goto out; } bdrv_refresh_filename(state->old_bs); + + aio_context_release(aio_context); bdrv_img_create(new_image_file, format, state->old_bs->filename, state->old_bs->drv->format_name, NULL, size, flags, false, &local_err); + aio_context_acquire(aio_context); + if (local_err) { error_propagate(errp, local_err); goto out; @@ -1621,8 +1617,8 @@ static void external_snapshot_abort(BlkActionState *common) aio_context_release(aio_context); aio_context_acquire(tmp_context); - ret = bdrv_try_set_aio_context(state->old_bs, - aio_context, NULL); + ret = bdrv_try_change_aio_context(state->old_bs, + aio_context, NULL, NULL); assert(ret == 0); aio_context_release(tmp_context); @@ -1677,6 +1673,7 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) BlockDriverState *source = NULL; AioContext *aio_context; AioContext *old_context; + const char *format; QDict *options; Error *local_err = NULL; int flags; @@ -1708,9 +1705,9 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) /* Paired with .clean() */ bdrv_drained_begin(bs); - if (!backup->has_format) { - backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ? - NULL : (char *) bs->drv->format_name; + format = backup->format; + if (!format && backup->mode != NEW_IMAGE_MODE_EXISTING) { + format = bs->drv->format_name; } /* Early check to avoid creating target */ @@ -1749,19 +1746,19 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) } if (backup->mode != NEW_IMAGE_MODE_EXISTING) { - assert(backup->format); + assert(format); if (source) { /* Implicit filters should not appear in the filename */ BlockDriverState *explicit_backing = bdrv_skip_implicit_filters(source); bdrv_refresh_filename(explicit_backing); - bdrv_img_create(backup->target, backup->format, + bdrv_img_create(backup->target, format, explicit_backing->filename, explicit_backing->drv->format_name, NULL, size, flags, false, &local_err); } else { - bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL, + bdrv_img_create(backup->target, format, NULL, NULL, NULL, size, flags, false, &local_err); } } @@ -1774,8 +1771,8 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) options = qdict_new(); qdict_put_str(options, "discard", "unmap"); qdict_put_str(options, "detect-zeroes", "unmap"); - if (backup->format) { - qdict_put_str(options, "driver", backup->format); + if (format) { + qdict_put_str(options, "driver", format); } target_bs = bdrv_open(backup->target, NULL, options, flags, errp); @@ -1783,12 +1780,12 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) goto out; } - /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ + /* Honor bdrv_try_change_aio_context() context acquisition requirements. */ old_context = bdrv_get_aio_context(target_bs); aio_context_release(aio_context); aio_context_acquire(old_context); - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp); if (ret < 0) { bdrv_unref(target_bs); aio_context_release(old_context); @@ -1833,14 +1830,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); } } @@ -1890,12 +1880,12 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) return; } - /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ + /* Honor bdrv_try_change_aio_context() context acquisition requirements. */ aio_context = bdrv_get_aio_context(bs); old_context = bdrv_get_aio_context(target_bs); aio_context_acquire(old_context); - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp); if (ret < 0) { aio_context_release(old_context); return; @@ -1934,14 +1924,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); } } @@ -2310,11 +2293,11 @@ static TransactionProperties *get_transaction_properties( * Always run under BQL. */ void qmp_transaction(TransactionActionList *dev_list, - bool has_props, struct TransactionProperties *props, Error **errp) { TransactionActionList *dev_entry = dev_list; + bool has_props = !!props; JobTxn *block_job_txn = NULL; BlkActionState *state, *next; Error *local_err = NULL; @@ -2416,8 +2399,7 @@ BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, return ret; } -void coroutine_fn qmp_block_resize(bool has_device, const char *device, - bool has_node_name, const char *node_name, +void coroutine_fn qmp_block_resize(const char *device, const char *node_name, int64_t size, Error **errp) { Error *local_err = NULL; @@ -2425,9 +2407,7 @@ void coroutine_fn qmp_block_resize(bool has_device, const char *device, BlockDriverState *bs; AioContext *old_ctx; - bs = bdrv_lookup_bs(has_device ? device : NULL, - has_node_name ? node_name : NULL, - &local_err); + bs = bdrv_lookup_bs(device, node_name, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -2453,7 +2433,7 @@ void coroutine_fn qmp_block_resize(bool has_device, const char *device, bdrv_co_unlock(bs); old_ctx = bdrv_co_enter(bs); - blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); + blk_co_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); bdrv_co_leave(bs, old_ctx); bdrv_co_lock(bs); @@ -2462,14 +2442,14 @@ void coroutine_fn qmp_block_resize(bool has_device, const char *device, bdrv_co_unlock(bs); } -void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, - bool has_base, const char *base, - bool has_base_node, const char *base_node, - bool has_backing_file, const char *backing_file, - bool has_bottom, const char *bottom, +void qmp_block_stream(const char *job_id, const char *device, + const char *base, + const char *base_node, + const char *backing_file, + const char *bottom, bool has_speed, int64_t speed, bool has_on_error, BlockdevOnError on_error, - bool has_filter_node_name, const char *filter_node_name, + const char *filter_node_name, bool has_auto_finalize, bool auto_finalize, bool has_auto_dismiss, bool auto_dismiss, Error **errp) @@ -2481,19 +2461,19 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, Error *local_err = NULL; int job_flags = JOB_DEFAULT; - if (has_base && has_base_node) { + if (base && base_node) { error_setg(errp, "'base' and 'base-node' cannot be specified " "at the same time"); return; } - if (has_base && has_bottom) { + if (base && bottom) { error_setg(errp, "'base' and 'bottom' cannot be specified " "at the same time"); return; } - if (has_bottom && has_base_node) { + if (bottom && base_node) { error_setg(errp, "'bottom' and 'base-node' cannot be specified " "at the same time"); return; @@ -2511,7 +2491,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - if (has_base) { + if (base) { base_bs = bdrv_find_backing_image(bs, base); if (base_bs == NULL) { error_setg(errp, "Can't find '%s' in the backing chain", base); @@ -2520,7 +2500,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, assert(bdrv_get_aio_context(base_bs) == aio_context); } - if (has_base_node) { + if (base_node) { base_bs = bdrv_lookup_bs(NULL, base_node, errp); if (!base_bs) { goto out; @@ -2534,7 +2514,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, bdrv_refresh_filename(base_bs); } - if (has_bottom) { + if (bottom) { bottom_bs = bdrv_lookup_bs(NULL, bottom, errp); if (!bottom_bs) { goto out; @@ -2559,7 +2539,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, /* * Check for op blockers in the whole chain between bs and base (or bottom) */ - iter_end = has_bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs; + iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs; for (iter = bs; iter && iter != iter_end; iter = bdrv_filter_or_cow_bs(iter)) { @@ -2570,7 +2550,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, /* if we are streaming the entire chain, the result will have no backing * file, and specifying one is therefore an error */ - if (base_bs == NULL && has_backing_file) { + if (!base_bs && backing_file) { error_setg(errp, "backing file specified, but streaming the " "entire chain"); goto out; @@ -2583,7 +2563,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, job_flags |= JOB_MANUAL_DISMISS; } - stream_start(has_job_id ? job_id : NULL, bs, base_bs, backing_file, + stream_start(job_id, bs, base_bs, backing_file, bottom_bs, job_flags, has_speed ? speed : 0, on_error, filter_node_name, &local_err); if (local_err) { @@ -2597,15 +2577,15 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, aio_context_release(aio_context); } -void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, - bool has_base_node, const char *base_node, - bool has_base, const char *base, - bool has_top_node, const char *top_node, - bool has_top, const char *top, - bool has_backing_file, const char *backing_file, +void qmp_block_commit(const char *job_id, const char *device, + const char *base_node, + const char *base, + const char *top_node, + const char *top, + const char *backing_file, bool has_speed, int64_t speed, bool has_on_error, BlockdevOnError on_error, - bool has_filter_node_name, const char *filter_node_name, + const char *filter_node_name, bool has_auto_finalize, bool auto_finalize, bool has_auto_dismiss, bool auto_dismiss, Error **errp) @@ -2624,9 +2604,6 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, if (!has_on_error) { on_error = BLOCKDEV_ON_ERROR_REPORT; } - if (!has_filter_node_name) { - filter_node_name = NULL; - } if (has_auto_finalize && !auto_finalize) { job_flags |= JOB_MANUAL_FINALIZE; } @@ -2662,10 +2639,10 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, /* default top_bs is the active layer */ top_bs = bs; - if (has_top_node && has_top) { + if (top_node && top) { error_setg(errp, "'top-node' and 'top' are mutually exclusive"); goto out; - } else if (has_top_node) { + } else if (top_node) { top_bs = bdrv_lookup_bs(NULL, top_node, errp); if (top_bs == NULL) { goto out; @@ -2675,7 +2652,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, top_node); goto out; } - } else if (has_top && top) { + } else if (top) { /* This strcmp() is just a shortcut, there is no need to * refresh @bs's filename. If it mismatches, * bdrv_find_backing_image() will do the refresh and may still @@ -2692,10 +2669,10 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, assert(bdrv_get_aio_context(top_bs) == aio_context); - if (has_base_node && has_base) { + if (base_node && base) { error_setg(errp, "'base-node' and 'base' are mutually exclusive"); goto out; - } else if (has_base_node) { + } else if (base_node) { base_bs = bdrv_lookup_bs(NULL, base_node, errp); if (base_bs == NULL) { goto out; @@ -2705,7 +2682,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, base_node); goto out; } - } else if (has_base && base) { + } else if (base) { base_bs = bdrv_find_backing_image(top_bs, base); if (base_bs == NULL) { error_setg(errp, "Can't find '%s' in the backing chain", base); @@ -2747,7 +2724,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, if (top_perm & BLK_PERM_WRITE || bdrv_skip_filters(top_bs) == bdrv_skip_filters(bs)) { - if (has_backing_file) { + if (backing_file) { if (bdrv_skip_filters(top_bs) == bdrv_skip_filters(bs)) { error_setg(errp, "'backing-file' specified," " but 'top' is the active layer"); @@ -2757,7 +2734,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, } goto out; } - if (!has_job_id) { + if (!job_id) { /* * Emulate here what block_job_create() does, because it * is possible that @bs != @top_bs (the block job should @@ -2773,8 +2750,8 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) { goto out; } - commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, job_flags, - speed, on_error, has_backing_file ? backing_file : NULL, + commit_start(job_id, bs, base_bs, top_bs, job_flags, + speed, on_error, backing_file, filter_node_name, &local_err); } if (local_err != NULL) { @@ -2807,9 +2784,6 @@ static BlockJob *do_backup_common(BackupCommon *backup, if (!backup->has_on_target_error) { backup->on_target_error = BLOCKDEV_ON_ERROR_REPORT; } - if (!backup->has_job_id) { - backup->job_id = NULL; - } if (!backup->has_auto_finalize) { backup->auto_finalize = true; } @@ -2835,7 +2809,7 @@ static BlockJob *do_backup_common(BackupCommon *backup, if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) || (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) { /* done before desugaring 'incremental' to print the right message */ - if (!backup->has_bitmap) { + if (!backup->bitmap) { error_setg(errp, "must provide a valid bitmap name for " "'%s' sync mode", MirrorSyncMode_str(backup->sync)); return NULL; @@ -2856,7 +2830,7 @@ static BlockJob *do_backup_common(BackupCommon *backup, backup->bitmap_mode = BITMAP_SYNC_MODE_ON_SUCCESS; } - if (backup->has_bitmap) { + if (backup->bitmap) { bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); if (!bmap) { error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); @@ -2889,7 +2863,7 @@ static BlockJob *do_backup_common(BackupCommon *backup, } } - if (!backup->has_bitmap && backup->has_bitmap_mode) { + if (!backup->bitmap && backup->has_bitmap_mode) { error_setg(errp, "Cannot specify bitmap sync mode without a bitmap"); return NULL; } @@ -2949,7 +2923,7 @@ void qmp_blockdev_backup(BlockdevBackup *backup, Error **errp) **/ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, BlockDriverState *target, - bool has_replaces, const char *replaces, + const char *replaces, enum MirrorSyncMode sync, BlockMirrorBackingMode backing_mode, bool zero_target, @@ -2961,7 +2935,6 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, bool has_on_target_error, BlockdevOnError on_target_error, bool has_unmap, bool unmap, - bool has_filter_node_name, const char *filter_node_name, bool has_copy_mode, MirrorCopyMode copy_mode, bool has_auto_finalize, bool auto_finalize, @@ -2989,9 +2962,6 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, if (!has_unmap) { unmap = true; } - if (!has_filter_node_name) { - filter_node_name = NULL; - } if (!has_copy_mode) { copy_mode = MIRROR_COPY_MODE_BACKGROUND; } @@ -3024,16 +2994,15 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, sync = MIRROR_SYNC_MODE_FULL; } - if (!has_replaces) { + if (!replaces) { /* We want to mirror from @bs, but keep implicit filters on top */ unfiltered_bs = bdrv_skip_implicit_filters(bs); if (unfiltered_bs != bs) { replaces = unfiltered_bs->node_name; - has_replaces = true; } } - if (has_replaces) { + if (replaces) { BlockDriverState *to_replace_bs; AioContext *replace_aio_context; int64_t bs_size, replace_size; @@ -3070,7 +3039,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, * and will allow to check whether the node still exist at mirror completion */ mirror_start(job_id, bs, target, - has_replaces ? replaces : NULL, job_flags, + replaces, job_flags, speed, granularity, buf_size, sync, backing_mode, zero_target, on_source_error, on_target_error, unmap, filter_node_name, copy_mode, errp); @@ -3108,7 +3077,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) arg->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; } - if (!arg->has_format) { + if (!arg->format) { format = (arg->mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name); } @@ -3128,8 +3097,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) goto out; } - if (arg->has_replaces) { - if (!arg->has_node_name) { + if (arg->replaces) { + if (!arg->node_name) { error_setg(errp, "a node-name must be provided when replacing a" " named node of the graph"); goto out; @@ -3179,7 +3148,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) } options = qdict_new(); - if (arg->has_node_name) { + if (arg->node_name) { qdict_put_str(options, "node-name", arg->node_name); } if (format) { @@ -3199,12 +3168,12 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) !bdrv_has_zero_init(target_bs))); - /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ + /* Honor bdrv_try_change_aio_context() context acquisition requirements. */ old_context = bdrv_get_aio_context(target_bs); aio_context_release(aio_context); aio_context_acquire(old_context); - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp); if (ret < 0) { bdrv_unref(target_bs); aio_context_release(old_context); @@ -3214,8 +3183,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) aio_context_release(old_context); aio_context_acquire(aio_context); - blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, - arg->has_replaces, arg->replaces, arg->sync, + blockdev_mirror_common(arg->job_id, bs, target_bs, + arg->replaces, arg->sync, backing_mode, zero_target, arg->has_speed, arg->speed, arg->has_granularity, arg->granularity, @@ -3223,7 +3192,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) arg->has_on_source_error, arg->on_source_error, arg->has_on_target_error, arg->on_target_error, arg->has_unmap, arg->unmap, - false, NULL, + NULL, arg->has_copy_mode, arg->copy_mode, arg->has_auto_finalize, arg->auto_finalize, arg->has_auto_dismiss, arg->auto_dismiss, @@ -3233,9 +3202,9 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) aio_context_release(aio_context); } -void qmp_blockdev_mirror(bool has_job_id, const char *job_id, +void qmp_blockdev_mirror(const char *job_id, const char *device, const char *target, - bool has_replaces, const char *replaces, + const char *replaces, MirrorSyncMode sync, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, @@ -3244,7 +3213,6 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, BlockdevOnError on_source_error, bool has_on_target_error, BlockdevOnError on_target_error, - bool has_filter_node_name, const char *filter_node_name, bool has_copy_mode, MirrorCopyMode copy_mode, bool has_auto_finalize, bool auto_finalize, @@ -3271,12 +3239,12 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, zero_target = (sync == MIRROR_SYNC_MODE_FULL); - /* Honor bdrv_try_set_aio_context() context acquisition requirements. */ + /* Honor bdrv_try_change_aio_context() context acquisition requirements. */ old_context = bdrv_get_aio_context(target_bs); aio_context = bdrv_get_aio_context(bs); aio_context_acquire(old_context); - ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp); aio_context_release(old_context); aio_context_acquire(aio_context); @@ -3285,15 +3253,14 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, goto out; } - blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs, - has_replaces, replaces, sync, backing_mode, + blockdev_mirror_common(job_id, bs, target_bs, + replaces, sync, backing_mode, zero_target, has_speed, speed, has_granularity, granularity, has_buf_size, buf_size, has_on_source_error, on_source_error, has_on_target_error, on_target_error, - true, true, - has_filter_node_name, filter_node_name, + true, true, filter_node_name, has_copy_mode, copy_mode, has_auto_finalize, auto_finalize, has_auto_dismiss, auto_dismiss, @@ -3302,17 +3269,16 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, 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 +3286,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 +3319,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, @@ -3556,8 +3519,6 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp) { BlockReopenQueue *queue = NULL; - GSList *drained = NULL; - GSList *p; /* Add each one of the BDS that we want to reopen to the queue */ for (; reopen_list != NULL; reopen_list = reopen_list->next) { @@ -3569,7 +3530,7 @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp) QDict *qdict; /* Check for the selected node name */ - if (!options->has_node_name) { + if (!options->node_name) { error_setg(errp, "node-name not specified"); goto fail; } @@ -3594,9 +3555,7 @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp) ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - bdrv_subtree_drained_begin(bs); queue = bdrv_reopen_queue(queue, bs, qdict, false); - drained = g_slist_prepend(drained, bs); aio_context_release(ctx); } @@ -3607,15 +3566,6 @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp) fail: bdrv_reopen_queue_free(queue); - for (p = drained; p; p = p->next) { - BlockDriverState *bs = p->data; - AioContext *ctx = bdrv_get_aio_context(bs); - - aio_context_acquire(ctx); - bdrv_subtree_drained_end(bs); - aio_context_release(ctx); - } - g_slist_free(drained); } void qmp_blockdev_del(const char *node_name, Error **errp) @@ -3674,8 +3624,7 @@ static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs, return NULL; } -void qmp_x_blockdev_change(const char *parent, bool has_child, - const char *child, bool has_node, +void qmp_x_blockdev_change(const char *parent, const char *child, const char *node, Error **errp) { BlockDriverState *parent_bs, *new_bs = NULL; @@ -3686,8 +3635,8 @@ void qmp_x_blockdev_change(const char *parent, bool has_child, return; } - if (has_child == has_node) { - if (has_child) { + if (!child == !node) { + if (child) { error_setg(errp, "The parameters child and node are in conflict"); } else { error_setg(errp, "Either child or node must be specified"); @@ -3695,7 +3644,7 @@ void qmp_x_blockdev_change(const char *parent, bool has_child, return; } - if (has_child) { + if (child) { p_child = bdrv_find_child(parent_bs, child); if (!p_child) { error_setg(errp, "Node '%s' does not have child '%s'", @@ -3705,7 +3654,7 @@ void qmp_x_blockdev_change(const char *parent, bool has_child, bdrv_del_child(parent_bs, p_child, errp); } - if (has_node) { + if (node) { new_bs = bdrv_find_node(node); if (!new_bs) { error_setg(errp, "Node '%s' not found", node); @@ -3720,17 +3669,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; @@ -3777,7 +3725,7 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, old_context = bdrv_get_aio_context(bs); aio_context_acquire(old_context); - bdrv_try_set_aio_context(bs, new_context, errp); + bdrv_try_change_aio_context(bs, new_context, NULL, errp); aio_context_release(old_context); } diff --git a/blockjob.c b/blockjob.c index 4868453d7498..b7daf2a9f628 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 @@ -127,48 +120,61 @@ static bool child_job_drained_poll(BdrvChild *c) } } -static void child_job_drained_end(BdrvChild *c, int *drained_end_counter) +static void child_job_drained_end(BdrvChild *c) { BlockJob *job = c->opaque; job_resume(&job->job); } -static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx, - GSList **ignore, Error **errp) +typedef struct BdrvStateChildJobContext { + AioContext *new_ctx; + BlockJob *job; +} BdrvStateChildJobContext; + +static void child_job_set_aio_ctx_commit(void *opaque) { - BlockJob *job = c->opaque; - GSList *l; + BdrvStateChildJobContext *s = opaque; + BlockJob *job = s->job; - for (l = job->nodes; l; l = l->next) { - BdrvChild *sibling = l->data; - if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) { - return false; - } - } - return true; + job_set_aio_context(&job->job, s->new_ctx); } -static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, - GSList **ignore) +static TransactionActionDrv change_child_job_context = { + .commit = child_job_set_aio_ctx_commit, + .clean = g_free, +}; + +static bool child_job_change_aio_ctx(BdrvChild *c, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp) { BlockJob *job = c->opaque; + BdrvStateChildJobContext *s; GSList *l; for (l = job->nodes; l; l = l->next) { BdrvChild *sibling = l->data; - if (g_slist_find(*ignore, sibling)) { - continue; + if (!bdrv_child_change_aio_context(sibling, ctx, visited, + tran, errp)) { + return false; } - *ignore = g_slist_prepend(*ignore, sibling); - bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore); } - job->job.aio_context = ctx; + s = g_new(BdrvStateChildJobContext, 1); + *s = (BdrvStateChildJobContext) { + .new_ctx = ctx, + .job = job, + }; + + tran_add(tran, &change_child_job_context, s); + return true; } static AioContext *child_job_get_parent_aio_context(BdrvChild *c) { BlockJob *job = c->opaque; + IO_CODE(); + JOB_LOCK_GUARD(); return job->job.aio_context; } @@ -178,8 +184,7 @@ static const BdrvChildClass child_job = { .drained_begin = child_job_drained_begin, .drained_poll = child_job_drained_poll, .drained_end = child_job_drained_end, - .can_set_aio_ctx = child_job_can_set_aio_ctx, - .set_aio_ctx = child_job_set_aio_ctx, + .change_aio_ctx = child_job_change_aio_ctx, .stay_at_node = true, .get_parent_aio_context = child_job_get_parent_aio_context, }; @@ -250,7 +255,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 +277,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 +298,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 +308,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,18 +343,17 @@ 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; if (job->job.ret) { - info->has_error = true; info->error = job->job.err ? g_strdup(error_get_pretty(job->job.err)) : g_strdup(strerror(-job->job.ret)); @@ -348,7 +361,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 +370,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 +390,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; @@ -397,11 +413,11 @@ static void block_job_event_completed(Notifier *n, void *opaque) progress_total, progress_current, job->speed, - !!msg, 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 +429,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 +450,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 +475,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; - - 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); + 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; + + 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 +512,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, 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 +522,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 +566,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/bsd-user/arm/target.h b/bsd-user/arm/target.h index 419c039b68e1..7c423ec5752d 100644 --- a/bsd-user/arm/target.h +++ b/bsd-user/arm/target.h @@ -17,5 +17,5 @@ static inline bool regpairs_aligned(void *cpu_env) return true; } -#endif /* ! TARGET_H */ +#endif /* TARGET_H */ diff --git a/bsd-user/arm/target_arch.h b/bsd-user/arm/target_arch.h index 93cfaea0986e..561934bbd259 100644 --- a/bsd-user/arm/target_arch.h +++ b/bsd-user/arm/target_arch.h @@ -17,12 +17,12 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_H_ -#define _TARGET_ARCH_H_ +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H #include "qemu.h" void target_cpu_set_tls(CPUARMState *env, target_ulong newtls); target_ulong target_cpu_get_tls(CPUARMState *env); -#endif /* !_TARGET_ARCH_H_ */ +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h index afb7814a8d10..517d0087644e 100644 --- a/bsd-user/arm/target_arch_cpu.h +++ b/bsd-user/arm/target_arch_cpu.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_CPU_H_ -#define _TARGET_ARCH_CPU_H_ +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" @@ -210,4 +210,4 @@ static inline void target_cpu_reset(CPUArchState *env) { } -#endif /* !_TARGET_ARCH_CPU_H */ +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/arm/target_arch_elf.h b/bsd-user/arm/target_arch_elf.h index 4a0215d02ed9..935bce347fc2 100644 --- a/bsd-user/arm/target_arch_elf.h +++ b/bsd-user/arm/target_arch_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_ELF_H_ -#define _TARGET_ARCH_ELF_H_ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H #define ELF_START_MMAP 0x80000000 #define ELF_ET_DYN_LOAD_ADDR 0x500000 @@ -125,4 +126,4 @@ static uint32_t get_elf_hwcap2(void) #undef GET_FEATURE #undef GET_FEATURE_ID -#endif /* _TARGET_ARCH_ELF_H_ */ +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/arm/target_arch_reg.h b/bsd-user/arm/target_arch_reg.h index ef5ed5154f1c..070fa24da123 100644 --- a/bsd-user/arm/target_arch_reg.h +++ b/bsd-user/arm/target_arch_reg.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_REG_H_ -#define _TARGET_ARCH_REG_H_ +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H /* See sys/arm/include/reg.h */ typedef struct target_reg { @@ -57,4 +57,4 @@ static inline void target_copy_regs(target_reg_t *regs, const CPUARMState *env) #undef tswapreg -#endif /* !_TARGET_ARCH_REG_H_ */ +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h index f1844dbf2251..02b2b33e07ab 100644 --- a/bsd-user/arm/target_arch_signal.h +++ b/bsd-user/arm/target_arch_signal.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGNAL_H_ -#define _TARGET_ARCH_SIGNAL_H_ + +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H #include "cpu.h" @@ -85,4 +86,4 @@ struct target_sigframe { target_mcontext_vfp_t sf_vfp; /* actual saved VFP context */ }; -#endif /* !_TARGET_ARCH_SIGNAL_H_ */ +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/arm/target_arch_sigtramp.h b/bsd-user/arm/target_arch_sigtramp.h index 5d434a9e7e80..06198045edf5 100644 --- a/bsd-user/arm/target_arch_sigtramp.h +++ b/bsd-user/arm/target_arch_sigtramp.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGTRAMP_H_ -#define _TARGET_ARCH_SIGTRAMP_H_ +#ifndef TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H /* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, @@ -46,4 +46,4 @@ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE); } -#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/arm/target_arch_sysarch.h b/bsd-user/arm/target_arch_sysarch.h index 8cc6bff2077e..5cb7864197d3 100644 --- a/bsd-user/arm/target_arch_sysarch.h +++ b/bsd-user/arm/target_arch_sysarch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SYSARCH_H_ -#define _TARGET_ARCH_SYSARCH_H_ +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H #include "target_syscall.h" #include "target_arch.h" @@ -75,4 +75,4 @@ static inline void do_freebsd_arch_print_sysarch( } } -#endif /*!_TARGET_ARCH_SYSARCH_H_ */ +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h index fcafca2408cf..fd257f313d86 100644 --- a/bsd-user/arm/target_arch_thread.h +++ b/bsd-user/arm/target_arch_thread.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_THREAD_H_ -#define _TARGET_ARCH_THREAD_H_ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H /* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */ static inline void target_thread_set_upcall(CPUARMState *env, abi_ulong entry, @@ -77,4 +78,4 @@ static inline void target_thread_init(struct target_pt_regs *regs, */ } -#endif /* !_TARGET_ARCH_THREAD_H_ */ +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/arm/target_arch_vmparam.h b/bsd-user/arm/target_arch_vmparam.h index 4bbc04ddf5b8..3fb69aff51a8 100644 --- a/bsd-user/arm/target_arch_vmparam.h +++ b/bsd-user/arm/target_arch_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_VMPARAM_H_ -#define _TARGET_ARCH_VMPARAM_H_ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H #include "cpu.h" @@ -45,4 +46,4 @@ static inline void set_second_rval(CPUARMState *state, abi_ulong retval2) state->regs[1] = retval2; } -#endif /* ! _TARGET_ARCH_VMPARAM_H_ */ +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/bsd-user/arm/target_syscall.h b/bsd-user/arm/target_syscall.h index a5f2bb4e0111..5804a535412c 100644 --- a/bsd-user/arm/target_syscall.h +++ b/bsd-user/arm/target_syscall.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SYSCALL_H_ -#define _TARGET_ARCH_SYSCALL_H_ +#ifndef ARM_TARGET_SYSCALL_H +#define ARM_TARGET_SYSCALL_H struct target_pt_regs { abi_long uregs[17]; @@ -52,4 +52,4 @@ struct target_pt_regs { #define TARGET_HW_MACHINE "arm" #define TARGET_HW_MACHINE_ARCH "armv7" -#endif /* !_TARGET_ARCH_SYSCALL_H_ */ +#endif /* ARM_TARGET_SYSCALL_H */ diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h index f0c3f347ec05..588e0c50d455 100644 --- a/bsd-user/bsd-file.h +++ b/bsd-user/bsd-file.h @@ -17,14 +17,926 @@ * along with this program; if not, see . */ -#ifndef BSD_FILE_H_ -#define BSD_FILE_H_ +#ifndef BSD_FILE_H +#define BSD_FILE_H #include "qemu/path.h" +#define LOCK_PATH(p, arg) \ +do { \ + (p) = lock_user_string(arg); \ + if ((p) == NULL) { \ + return -TARGET_EFAULT; \ + } \ +} while (0) + +#define UNLOCK_PATH(p, arg) unlock_user(p, arg, 0) + +#define LOCK_PATH2(p1, arg1, p2, arg2) \ +do { \ + (p1) = lock_user_string(arg1); \ + if ((p1) == NULL) { \ + return -TARGET_EFAULT; \ + } \ + (p2) = lock_user_string(arg2); \ + if ((p2) == NULL) { \ + unlock_user(p1, arg1, 0); \ + return -TARGET_EFAULT; \ + } \ +} while (0) + +#define UNLOCK_PATH2(p1, arg1, p2, arg2) \ +do { \ + unlock_user(p2, arg2, 0); \ + unlock_user(p1, arg1, 0); \ +} while (0) + extern struct iovec *lock_iovec(int type, abi_ulong target_addr, int count, int copy); extern void unlock_iovec(struct iovec *vec, abi_ulong target_addr, int count, int copy); -#endif /* !BSD_FILE_H_ */ +int safe_open(const char *path, int flags, mode_t mode); +int safe_openat(int fd, const char *path, int flags, mode_t mode); + +ssize_t safe_read(int fd, void *buf, size_t nbytes); +ssize_t safe_pread(int fd, void *buf, size_t nbytes, off_t offset); +ssize_t safe_readv(int fd, const struct iovec *iov, int iovcnt); +ssize_t safe_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); + +ssize_t safe_write(int fd, void *buf, size_t nbytes); +ssize_t safe_pwrite(int fd, void *buf, size_t nbytes, off_t offset); +ssize_t safe_writev(int fd, const struct iovec *iov, int iovcnt); +ssize_t safe_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); + +/* read(2) */ +static abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long ret; + void *p; + + p = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(safe_read(arg1, p, arg3)); + unlock_user(p, arg2, ret); + + return ret; +} + +/* pread(2) */ +static abi_long do_bsd_pread(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) +{ + abi_long ret; + void *p; + + p = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + if (regpairs_aligned(cpu_env) != 0) { + arg4 = arg5; + arg5 = arg6; + } + ret = get_errno(safe_pread(arg1, p, arg3, target_arg64(arg4, arg5))); + unlock_user(p, arg2, ret); + + return ret; +} + +/* readv(2) */ +static abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long ret; + struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0); + + if (vec != NULL) { + ret = get_errno(safe_readv(arg1, vec, arg3)); + unlock_iovec(vec, arg2, arg3, 1); + } else { + ret = -host_to_target_errno(errno); + } + + return ret; +} + +/* preadv(2) */ +static abi_long do_bsd_preadv(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) +{ + abi_long ret; + struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 1); + + if (vec != NULL) { + if (regpairs_aligned(cpu_env) != 0) { + arg4 = arg5; + arg5 = arg6; + } + ret = get_errno(safe_preadv(arg1, vec, arg3, target_arg64(arg4, arg5))); + unlock_iovec(vec, arg2, arg3, 0); + } else { + ret = -host_to_target_errno(errno); + } + + return ret; +} + +/* write(2) */ +static abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long nbytes, ret; + void *p; + + /* nbytes < 0 implies that it was larger than SIZE_MAX. */ + nbytes = arg3; + if (nbytes < 0) { + return -TARGET_EINVAL; + } + p = lock_user(VERIFY_READ, arg2, nbytes, 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(safe_write(arg1, p, arg3)); + unlock_user(p, arg2, 0); + + return ret; +} + +/* pwrite(2) */ +static abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) +{ + abi_long ret; + void *p; + + p = lock_user(VERIFY_READ, arg2, arg3, 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + if (regpairs_aligned(cpu_env) != 0) { + arg4 = arg5; + arg5 = arg6; + } + ret = get_errno(safe_pwrite(arg1, p, arg3, target_arg64(arg4, arg5))); + unlock_user(p, arg2, 0); + + return ret; +} + +/* writev(2) */ +static abi_long do_bsd_writev(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long ret; + struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1); + + if (vec != NULL) { + ret = get_errno(safe_writev(arg1, vec, arg3)); + unlock_iovec(vec, arg2, arg3, 0); + } else { + ret = -host_to_target_errno(errno); + } + + return ret; +} + +/* pwritev(2) */ +static abi_long do_bsd_pwritev(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) +{ + abi_long ret; + struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1); + + if (vec != NULL) { + if (regpairs_aligned(cpu_env) != 0) { + arg4 = arg5; + arg5 = arg6; + } + ret = get_errno(safe_pwritev(arg1, vec, arg3, target_arg64(arg4, arg5))); + unlock_iovec(vec, arg2, arg3, 0); + } else { + ret = -host_to_target_errno(errno); + } + + return ret; +} + +/* open(2) */ +static abi_long do_bsd_open(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(safe_open(path(p), target_to_host_bitmask(arg2, + fcntl_flags_tbl), arg3)); + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* openat(2) */ +static abi_long do_bsd_openat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(safe_openat(arg1, path(p), + target_to_host_bitmask(arg3, fcntl_flags_tbl), arg4)); + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* close(2) */ +static abi_long do_bsd_close(abi_long arg1) +{ + return get_errno(close(arg1)); +} + +/* fdatasync(2) */ +static abi_long do_bsd_fdatasync(abi_long arg1) +{ + return get_errno(fdatasync(arg1)); +} + +/* fsync(2) */ +static abi_long do_bsd_fsync(abi_long arg1) +{ + return get_errno(fsync(arg1)); +} + +/* closefrom(2) */ +static abi_long do_bsd_closefrom(abi_long arg1) +{ + closefrom(arg1); /* returns void */ + return get_errno(0); +} + +/* revoke(2) */ +static abi_long do_bsd_revoke(abi_long arg1) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(revoke(p)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* access(2) */ +static abi_long do_bsd_access(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(access(path(p), arg2)); + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* eaccess(2) */ +static abi_long do_bsd_eaccess(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(eaccess(path(p), arg2)); + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* faccessat(2) */ +static abi_long do_bsd_faccessat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(faccessat(arg1, p, arg3, arg4)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* chdir(2) */ +static abi_long do_bsd_chdir(abi_long arg1) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(chdir(p)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fchdir(2) */ +static abi_long do_bsd_fchdir(abi_long arg1) +{ + return get_errno(fchdir(arg1)); +} + +/* rename(2) */ +static abi_long do_bsd_rename(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg1, p2, arg2); + ret = get_errno(rename(p1, p2)); /* XXX path(p1), path(p2) */ + UNLOCK_PATH2(p1, arg1, p2, arg2); + + return ret; +} + +/* renameat(2) */ +static abi_long do_bsd_renameat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg2, p2, arg4); + ret = get_errno(renameat(arg1, p1, arg3, p2)); + UNLOCK_PATH2(p1, arg2, p2, arg4); + + return ret; +} + +/* link(2) */ +static abi_long do_bsd_link(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg1, p2, arg2); + ret = get_errno(link(p1, p2)); /* XXX path(p1), path(p2) */ + UNLOCK_PATH2(p1, arg1, p2, arg2); + + return ret; +} + +/* linkat(2) */ +static abi_long do_bsd_linkat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg2, p2, arg4); + ret = get_errno(linkat(arg1, p1, arg3, p2, arg5)); + UNLOCK_PATH2(p1, arg2, p2, arg4); + + return ret; +} + +/* unlink(2) */ +static abi_long do_bsd_unlink(abi_long arg1) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(unlink(p)); /* XXX path(p) */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* unlinkat(2) */ +static abi_long do_bsd_unlinkat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(unlinkat(arg1, p, arg3)); /* XXX path(p) */ + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* mkdir(2) */ +static abi_long do_bsd_mkdir(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(mkdir(p, arg2)); /* XXX path(p) */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* mkdirat(2) */ +static abi_long do_bsd_mkdirat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(mkdirat(arg1, p, arg3)); + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* rmdir(2) */ +static abi_long do_bsd_rmdir(abi_long arg1) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(rmdir(p)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* undocumented __getcwd(char *buf, size_t len) system call */ +static abi_long do_bsd___getcwd(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + p = lock_user(VERIFY_WRITE, arg1, arg2, 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = safe_syscall(SYS___getcwd, p, arg2); + unlock_user(p, arg1, ret == 0 ? strlen(p) + 1 : 0); + + return get_errno(ret); +} + +/* dup(2) */ +static abi_long do_bsd_dup(abi_long arg1) +{ + return get_errno(dup(arg1)); +} + +/* dup2(2) */ +static abi_long do_bsd_dup2(abi_long arg1, abi_long arg2) +{ + return get_errno(dup2(arg1, arg2)); +} + +/* truncate(2) */ +static abi_long do_bsd_truncate(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + if (regpairs_aligned(cpu_env) != 0) { + arg2 = arg3; + arg3 = arg4; + } + ret = get_errno(truncate(p, target_arg64(arg2, arg3))); + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* ftruncate(2) */ +static abi_long do_bsd_ftruncate(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4) +{ + if (regpairs_aligned(cpu_env) != 0) { + arg2 = arg3; + arg3 = arg4; + } + return get_errno(ftruncate(arg1, target_arg64(arg2, arg3))); +} + +/* acct(2) */ +static abi_long do_bsd_acct(abi_long arg1) +{ + abi_long ret; + void *p; + + if (arg1 == 0) { + ret = get_errno(acct(NULL)); + } else { + LOCK_PATH(p, arg1); + ret = get_errno(acct(path(p))); + UNLOCK_PATH(p, arg1); + } + return ret; +} + +/* sync(2) */ +static abi_long do_bsd_sync(void) +{ + sync(); + return 0; +} + +/* mount(2) */ +static abi_long do_bsd_mount(abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg1, p2, arg2); + /* + * XXX arg4 should be locked, but it isn't clear how to do that since it may + * be not be a NULL-terminated string. + */ + if (arg4 == 0) { + ret = get_errno(mount(p1, p2, arg3, NULL)); /* XXX path(p2)? */ + } else { + ret = get_errno(mount(p1, p2, arg3, g2h_untagged(arg4))); /* XXX path(p2)? */ + } + UNLOCK_PATH2(p1, arg1, p2, arg2); + + return ret; +} + +/* unmount(2) */ +static abi_long do_bsd_unmount(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(unmount(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* nmount(2) */ +static abi_long do_bsd_nmount(abi_long arg1, abi_long count, + abi_long flags) +{ + abi_long ret; + struct iovec *vec = lock_iovec(VERIFY_READ, arg1, count, 1); + + if (vec != NULL) { + ret = get_errno(nmount(vec, count, flags)); + unlock_iovec(vec, arg1, count, 0); + } else { + return -TARGET_EFAULT; + } + + return ret; +} + +/* symlink(2) */ +static abi_long do_bsd_symlink(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg1, p2, arg2); + ret = get_errno(symlink(p1, p2)); /* XXX path(p1), path(p2) */ + UNLOCK_PATH2(p1, arg1, p2, arg2); + + return ret; +} + +/* symlinkat(2) */ +static abi_long do_bsd_symlinkat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH2(p1, arg1, p2, arg3); + ret = get_errno(symlinkat(p1, arg2, p2)); /* XXX path(p1), path(p2) */ + UNLOCK_PATH2(p1, arg1, p2, arg3); + + return ret; +} + +/* readlink(2) */ +static abi_long do_bsd_readlink(CPUArchState *env, abi_long arg1, + abi_long arg2, abi_long arg3) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH(p1, arg1); + p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (p2 == NULL) { + UNLOCK_PATH(p1, arg1); + return -TARGET_EFAULT; + } + if (strcmp(p1, "/proc/curproc/file") == 0) { + CPUState *cpu = env_cpu(env); + TaskState *ts = (TaskState *)cpu->opaque; + strncpy(p2, ts->bprm->fullpath, arg3); + ret = MIN((abi_long)strlen(ts->bprm->fullpath), arg3); + } else { + ret = get_errno(readlink(path(p1), p2, arg3)); + } + unlock_user(p2, arg2, ret); + UNLOCK_PATH(p1, arg1); + + return ret; +} + +/* readlinkat(2) */ +static abi_long do_bsd_readlinkat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p1, *p2; + + LOCK_PATH(p1, arg2); + p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (p2 == NULL) { + UNLOCK_PATH(p1, arg2); + return -TARGET_EFAULT; + } + ret = get_errno(readlinkat(arg1, p1, p2, arg4)); + unlock_user(p2, arg3, ret); + UNLOCK_PATH(p1, arg2); + + return ret; +} + +/* chmod(2) */ +static abi_long do_bsd_chmod(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(chmod(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fchmod(2) */ +static abi_long do_bsd_fchmod(abi_long arg1, abi_long arg2) +{ + return get_errno(fchmod(arg1, arg2)); +} + +/* lchmod(2) */ +static abi_long do_bsd_lchmod(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(lchmod(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fchmodat(2) */ +static abi_long do_bsd_fchmodat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(fchmodat(arg1, p, arg3, arg4)); + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* pre-ino64 mknod(2) */ +static abi_long do_bsd_freebsd11_mknod(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(syscall(SYS_freebsd11_mknod, p, arg2, arg3)); + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* pre-ino64 mknodat(2) */ +static abi_long do_bsd_freebsd11_mknodat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(syscall(SYS_freebsd11_mknodat, arg1, p, arg3, arg4)); + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* post-ino64 mknodat(2) */ +static abi_long do_bsd_mknodat(void *cpu_env, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, + abi_long arg6) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + /* 32-bit arch's use two 32 registers for 64 bit return value */ + if (regpairs_aligned(cpu_env) != 0) { + ret = get_errno(mknodat(arg1, p, arg3, target_arg64(arg5, arg6))); + } else { + ret = get_errno(mknodat(arg1, p, arg3, target_arg64(arg4, arg5))); + } + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* chown(2) */ +static abi_long do_bsd_chown(abi_long arg1, abi_long arg2, abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(chown(p, arg2, arg3)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fchown(2) */ +static abi_long do_bsd_fchown(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + return get_errno(fchown(arg1, arg2, arg3)); +} + +/* lchown(2) */ +static abi_long do_bsd_lchown(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(lchown(p, arg2, arg3)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fchownat(2) */ +static abi_long do_bsd_fchownat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(fchownat(arg1, p, arg3, arg4, arg5)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* chflags(2) */ +static abi_long do_bsd_chflags(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(chflags(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* lchflags(2) */ +static abi_long do_bsd_lchflags(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(lchflags(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fchflags(2) */ +static abi_long do_bsd_fchflags(abi_long arg1, abi_long arg2) +{ + return get_errno(fchflags(arg1, arg2)); +} + +/* chroot(2) */ +static abi_long do_bsd_chroot(abi_long arg1) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(chroot(p)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* flock(2) */ +static abi_long do_bsd_flock(abi_long arg1, abi_long arg2) +{ + return get_errno(flock(arg1, arg2)); +} + +/* mkfifo(2) */ +static abi_long do_bsd_mkfifo(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(mkfifo(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* mkfifoat(2) */ +static abi_long do_bsd_mkfifoat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg2); + ret = get_errno(mkfifoat(arg1, p, arg3)); + UNLOCK_PATH(p, arg2); + + return ret; +} + +/* pathconf(2) */ +static abi_long do_bsd_pathconf(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(pathconf(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* lpathconf(2) */ +static abi_long do_bsd_lpathconf(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(lpathconf(p, arg2)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +/* fpathconf(2) */ +static abi_long do_bsd_fpathconf(abi_long arg1, abi_long arg2) +{ + return get_errno(fpathconf(arg1, arg2)); +} + +/* undelete(2) */ +static abi_long do_bsd_undelete(abi_long arg1) +{ + abi_long ret; + void *p; + + LOCK_PATH(p, arg1); + ret = get_errno(undelete(p)); /* XXX path(p)? */ + UNLOCK_PATH(p, arg1); + + return ret; +} + +#endif /* BSD_FILE_H */ diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h new file mode 100644 index 000000000000..68b66e571d32 --- /dev/null +++ b/bsd-user/bsd-proc.h @@ -0,0 +1,42 @@ +/* + * process related system call shims and definitions + * + * Copyright (c) 2013-2014 Stacey D. Son + * + * 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 . + */ + +#ifndef BSD_PROC_H_ +#define BSD_PROC_H_ + +#include +#include +#include +#include +#include + +/* exit(2) */ +static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1) +{ +#ifdef TARGET_GPROF + _mcleanup(); +#endif + gdb_exit(arg1); + qemu_plugin_user_exit(); + _exit(arg1); + + return 0; +} + +#endif /* !BSD_PROC_H_ */ diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 142a5bfac260..fbcdc94b960d 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -156,7 +156,7 @@ static abi_ulong copy_elf_strings(int argc, char **argv, void **page, --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; - pag = (char *)page[p / TARGET_PAGE_SIZE]; + pag = page[p / TARGET_PAGE_SIZE]; if (!pag) { pag = g_try_malloc0(TARGET_PAGE_SIZE); page[p / TARGET_PAGE_SIZE] = pag; @@ -246,7 +246,7 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss) * patch target_mmap(), but it is more complicated as the file * size must be known. */ - if (qemu_real_host_page_size < qemu_host_page_size) { + if (qemu_real_host_page_size() < qemu_host_page_size) { abi_ulong end_addr, end_addr1; end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss); end_addr = HOST_PAGE_ALIGN(elf_bss); diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h index 73cfa24b7f59..f3e8ac34883f 100644 --- a/bsd-user/errno_defs.h +++ b/bsd-user/errno_defs.h @@ -34,8 +34,8 @@ * @(#)errno.h 8.5 (Berkeley) 1/21/94 */ -#ifndef _ERRNO_DEFS_H_ -#define _ERRNO_DEFS_H_ +#ifndef ERRNO_DEFS_H +#define ERRNO_DEFS_H #define TARGET_EPERM 1 /* Operation not permitted */ #define TARGET_ENOENT 2 /* No such file or directory */ @@ -157,4 +157,4 @@ _Static_assert(TARGET_ERESTART == QEMU_ERESTARTSYS, "TARGET_ERESTART and QEMU_ERESTARTSYS expected to match"); -#endif /* ! _ERRNO_DEFS_H_ */ +#endif /* ERRNO_DEFS_H */ diff --git a/bsd-user/freebsd/host-os.h b/bsd-user/freebsd/host-os.h index dfb8344b7b6f..40cae72ec9a6 100644 --- a/bsd-user/freebsd/host-os.h +++ b/bsd-user/freebsd/host-os.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _HOST_OS_H_ -#define _HOST_OS_H_ +#ifndef HOST_OS_H +#define HOST_OS_H #define HOST_DEFAULT_BSD_TYPE target_freebsd -#endif /*!_HOST_OS_H_ */ +#endif /* HOST_OS_H */ diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index a17ff9f6ecce..57996cad8aee 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -32,16 +32,37 @@ #include "qemu/cutils.h" #include "qemu/path.h" #include +#include #include +#include #include #include #include "qemu.h" -#include "qemu-common.h" #include "signal-common.h" #include "user/syscall-trace.h" #include "bsd-file.h" +#include "bsd-proc.h" + +/* I/O */ +safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode); +safe_syscall4(int, openat, int, fd, const char *, path, int, flags, mode_t, + mode); + +safe_syscall3(ssize_t, read, int, fd, void *, buf, size_t, nbytes); +safe_syscall4(ssize_t, pread, int, fd, void *, buf, size_t, nbytes, off_t, + offset); +safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt); +safe_syscall4(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt, + off_t, offset); + +safe_syscall3(ssize_t, write, int, fd, void *, buf, size_t, nbytes); +safe_syscall4(ssize_t, pwrite, int, fd, void *, buf, size_t, nbytes, off_t, + offset); +safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt); +safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt, + off_t, offset); void target_set_brk(abi_ulong new_brk) { @@ -75,16 +96,437 @@ bool is_error(abi_long ret) } /* - * do_syscall() should always have a single exit point at the end so that - * actions, such as logging of syscall results, can be performed. All errnos - * that do_syscall() returns must be -TARGET_. + * Unlocks a iovec. Unlike unlock_iovec, it assumes the tvec array itself is + * already locked from target_addr. It will be unlocked as well as all the iovec + * elements. + */ +static void helper_unlock_iovec(struct target_iovec *target_vec, + abi_ulong target_addr, struct iovec *vec, + int count, int copy) +{ + for (int i = 0; i < count; i++) { + abi_ulong base = tswapal(target_vec[i].iov_base); + + if (vec[i].iov_base) { + unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); + } + } + unlock_user(target_vec, target_addr, 0); +} + +struct iovec *lock_iovec(int type, abi_ulong target_addr, + int count, int copy) +{ + struct target_iovec *target_vec; + struct iovec *vec; + abi_ulong total_len, max_len; + int i; + int err = 0; + + if (count == 0) { + errno = 0; + return NULL; + } + if (count < 0 || count > IOV_MAX) { + errno = EINVAL; + return NULL; + } + + vec = g_try_new0(struct iovec, count); + if (vec == NULL) { + errno = ENOMEM; + return NULL; + } + + target_vec = lock_user(VERIFY_READ, target_addr, + count * sizeof(struct target_iovec), 1); + if (target_vec == NULL) { + err = EFAULT; + goto fail2; + } + + max_len = 0x7fffffff & MIN(TARGET_PAGE_MASK, PAGE_MASK); + total_len = 0; + + for (i = 0; i < count; i++) { + abi_ulong base = tswapal(target_vec[i].iov_base); + abi_long len = tswapal(target_vec[i].iov_len); + + if (len < 0) { + err = EINVAL; + goto fail; + } else if (len == 0) { + /* Zero length pointer is ignored. */ + vec[i].iov_base = 0; + } else { + vec[i].iov_base = lock_user(type, base, len, copy); + /* + * If the first buffer pointer is bad, this is a fault. But + * subsequent bad buffers will result in a partial write; this is + * realized by filling the vector with null pointers and zero + * lengths. + */ + if (!vec[i].iov_base) { + if (i == 0) { + err = EFAULT; + goto fail; + } else { + /* + * Fail all the subsequent addresses, they are already + * zero'd. + */ + goto out; + } + } + if (len > max_len - total_len) { + len = max_len - total_len; + } + } + vec[i].iov_len = len; + total_len += len; + } +out: + unlock_user(target_vec, target_addr, 0); + return vec; + +fail: + helper_unlock_iovec(target_vec, target_addr, vec, i, copy); +fail2: + g_free(vec); + errno = err; + return NULL; +} + +void unlock_iovec(struct iovec *vec, abi_ulong target_addr, + int count, int copy) +{ + struct target_iovec *target_vec; + + target_vec = lock_user(VERIFY_READ, target_addr, + count * sizeof(struct target_iovec), 1); + if (target_vec) { + helper_unlock_iovec(target_vec, target_addr, vec, count, copy); + } + + g_free(vec); +} + +/* + * All errnos that freebsd_syscall() returns must be -TARGET_. + */ +static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8) +{ + abi_long ret; + + switch (num) { + /* + * process system calls + */ + case TARGET_FREEBSD_NR_exit: /* exit(2) */ + ret = do_bsd_exit(cpu_env, arg1); + break; + + /* + * File system calls. + */ + case TARGET_FREEBSD_NR_read: /* read(2) */ + ret = do_bsd_read(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_pread: /* pread(2) */ + ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_readv: /* readv(2) */ + ret = do_bsd_readv(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_preadv: /* preadv(2) */ + ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + + case TARGET_FREEBSD_NR_write: /* write(2) */ + ret = do_bsd_write(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */ + ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_writev: /* writev(2) */ + ret = do_bsd_writev(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */ + ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_open: /* open(2) */ + ret = do_bsd_open(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_openat: /* openat(2) */ + ret = do_bsd_openat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_close: /* close(2) */ + ret = do_bsd_close(arg1); + break; + + case TARGET_FREEBSD_NR_fdatasync: /* fdatasync(2) */ + ret = do_bsd_fdatasync(arg1); + break; + + case TARGET_FREEBSD_NR_fsync: /* fsync(2) */ + ret = do_bsd_fsync(arg1); + break; + + case TARGET_FREEBSD_NR_freebsd12_closefrom: /* closefrom(2) */ + ret = do_bsd_closefrom(arg1); + break; + + case TARGET_FREEBSD_NR_revoke: /* revoke(2) */ + ret = do_bsd_revoke(arg1); + break; + + case TARGET_FREEBSD_NR_access: /* access(2) */ + ret = do_bsd_access(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */ + ret = do_bsd_eaccess(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */ + ret = do_bsd_faccessat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_chdir: /* chdir(2) */ + ret = do_bsd_chdir(arg1); + break; + + case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */ + ret = do_bsd_fchdir(arg1); + break; + + case TARGET_FREEBSD_NR_rename: /* rename(2) */ + ret = do_bsd_rename(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_renameat: /* renameat(2) */ + ret = do_bsd_renameat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_link: /* link(2) */ + ret = do_bsd_link(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_linkat: /* linkat(2) */ + ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5); + break; + + case TARGET_FREEBSD_NR_unlink: /* unlink(2) */ + ret = do_bsd_unlink(arg1); + break; + + case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */ + ret = do_bsd_unlinkat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */ + ret = do_bsd_mkdir(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */ + ret = do_bsd_mkdirat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */ + ret = do_bsd_rmdir(arg1); + break; + + case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */ + ret = do_bsd___getcwd(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_dup: /* dup(2) */ + ret = do_bsd_dup(arg1); + break; + + case TARGET_FREEBSD_NR_dup2: /* dup2(2) */ + ret = do_bsd_dup2(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_truncate: /* truncate(2) */ + ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */ + ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_acct: /* acct(2) */ + ret = do_bsd_acct(arg1); + break; + + case TARGET_FREEBSD_NR_sync: /* sync(2) */ + ret = do_bsd_sync(); + break; + + case TARGET_FREEBSD_NR_mount: /* mount(2) */ + ret = do_bsd_mount(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_unmount: /* unmount(2) */ + ret = do_bsd_unmount(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_nmount: /* nmount(2) */ + ret = do_bsd_nmount(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_symlink: /* symlink(2) */ + ret = do_bsd_symlink(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */ + ret = do_bsd_symlinkat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_readlink: /* readlink(2) */ + ret = do_bsd_readlink(cpu_env, arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */ + ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_chmod: /* chmod(2) */ + ret = do_bsd_chmod(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */ + ret = do_bsd_fchmod(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */ + ret = do_bsd_lchmod(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */ + ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_freebsd11_mknod: /* mknod(2) */ + ret = do_bsd_freebsd11_mknod(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_freebsd11_mknodat: /* mknodat(2) */ + ret = do_bsd_freebsd11_mknodat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */ + ret = do_bsd_mknodat(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_chown: /* chown(2) */ + ret = do_bsd_chown(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_fchown: /* fchown(2) */ + ret = do_bsd_fchown(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_lchown: /* lchown(2) */ + ret = do_bsd_lchown(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */ + ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5); + break; + + case TARGET_FREEBSD_NR_chflags: /* chflags(2) */ + ret = do_bsd_chflags(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */ + ret = do_bsd_lchflags(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */ + ret = do_bsd_fchflags(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_chroot: /* chroot(2) */ + ret = do_bsd_chroot(arg1); + break; + + case TARGET_FREEBSD_NR_flock: /* flock(2) */ + ret = do_bsd_flock(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */ + ret = do_bsd_mkfifo(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */ + ret = do_bsd_mkfifoat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */ + ret = do_bsd_pathconf(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */ + ret = do_bsd_lpathconf(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */ + ret = do_bsd_fpathconf(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_undelete: /* undelete(2) */ + ret = do_bsd_undelete(arg1); + break; + + default: + qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); + ret = -TARGET_ENOSYS; + break; + } + + return ret; +} + +/* + * do_freebsd_syscall() should always have a single exit point at the end so + * that actions, such as logging of syscall results, can be performed. This + * as a wrapper around freebsd_syscall() so that actually happens. Since + * that is a singleton, modern compilers will inline it anyway... */ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) { - return 0; + CPUState *cpu = env_cpu(cpu_env); + int ret; + + trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + if (do_strace) { + print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + } + + ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, + arg7, arg8); + if (do_strace) { + print_freebsd_syscall_ret(num, ret); + } + trace_guest_user_syscall_ret(cpu, num, ret); + + return ret; } void syscall_init(void) diff --git a/bsd-user/freebsd/target_os_elf.h b/bsd-user/freebsd/target_os_elf.h index e5ac8e8e5011..9df17d56d8a9 100644 --- a/bsd-user/freebsd/target_os_elf.h +++ b/bsd-user/freebsd/target_os_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_ELF_H_ -#define _TARGET_OS_ELF_H_ + +#ifndef TARGET_OS_ELF_H +#define TARGET_OS_ELF_H #include "target_arch_elf.h" #include "elf.h" @@ -134,4 +135,4 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#endif /* _TARGET_OS_ELF_H_ */ +#endif /* TARGET_OS_ELF_H */ diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h index d50a3034a887..4573738752d9 100644 --- a/bsd-user/freebsd/target_os_siginfo.h +++ b/bsd-user/freebsd/target_os_siginfo.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_SIGINFO_H_ -#define _TARGET_OS_SIGINFO_H_ + +#ifndef TARGET_OS_SIGINFO_H +#define TARGET_OS_SIGINFO_H #define TARGET_NSIG 128 #define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) @@ -155,4 +156,4 @@ struct target_sigevent { #define TARGET_FPE_FLTINV (7) /* Invalid floating point operation. */ #define TARGET_FPE_FLTSUB (8) /* Subscript out of range. */ -#endif /* !_TARGET_OS_SIGINFO_H_ */ +#endif /* TARGET_OS_SIGINFO_H */ diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h index 43700d08f71a..5030abb52b75 100644 --- a/bsd-user/freebsd/target_os_signal.h +++ b/bsd-user/freebsd/target_os_signal.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGNAL_H_ -#define _TARGET_OS_SIGNAL_H_ +#ifndef TARGET_OS_SIGNAL_H +#define TARGET_OS_SIGNAL_H #include "target_os_siginfo.h" #include "target_arch_signal.h" @@ -78,4 +78,4 @@ abi_long setup_sigframe_arch(CPUArchState *env, abi_ulong frame_addr, #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ #define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack*/ -#endif /* !_TARGET_OS_SIGNAL_H_ */ +#endif /* TARGET_OS_SIGNAL_H */ diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h index 1bb1a2bf569d..059013329153 100644 --- a/bsd-user/freebsd/target_os_stack.h +++ b/bsd-user/freebsd/target_os_stack.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_STACK_H_ -#define _TARGET_OS_STACK_H_ +#ifndef TARGET_OS_STACK_H +#define TARGET_OS_STACK_H #include #include "target_arch_sigtramp.h" @@ -178,4 +178,4 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm, return 0; } -#endif /* !_TARGET_OS_STACK_H_ */ +#endif /* TARGET_OS_STACK_H */ diff --git a/bsd-user/freebsd/target_os_thread.h b/bsd-user/freebsd/target_os_thread.h index 77433acdff8d..1b32cebd26ee 100644 --- a/bsd-user/freebsd/target_os_thread.h +++ b/bsd-user/freebsd/target_os_thread.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_THREAD_H_ -#define _TARGET_OS_THREAD_H_ +#ifndef TARGET_OS_THREAD_H +#define TARGET_OS_THREAD_H #include "target_arch_thread.h" -#endif /* !_TARGET_OS_THREAD_H_ */ +#endif /* TARGET_OS_THREAD_H */ diff --git a/bsd-user/freebsd/target_os_user.h b/bsd-user/freebsd/target_os_user.h index 19892c5071bb..f036a323435b 100644 --- a/bsd-user/freebsd/target_os_user.h +++ b/bsd-user/freebsd/target_os_user.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_USER_H_ -#define _TARGET_OS_USER_H_ +#ifndef TARGET_OS_USER_H +#define TARGET_OS_USER_H /* * from sys/priority.h @@ -326,4 +326,4 @@ struct target_kinfo_vmentry { char kve_path[PATH_MAX]; /* Path to VM obj, if any. */ }; -#endif /* ! _TARGET_OS_USER_H_ */ +#endif /* TARGET_OS_USER_H */ diff --git a/bsd-user/freebsd/target_os_vmparam.h b/bsd-user/freebsd/target_os_vmparam.h index 990300c619f9..8457dd391396 100644 --- a/bsd-user/freebsd/target_os_vmparam.h +++ b/bsd-user/freebsd/target_os_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_VMPARAM_H_ -#define _TARGET_OS_VMPARAM_H_ + +#ifndef TARGET_OS_VMPARAM_H +#define TARGET_OS_VMPARAM_H #include "target_arch_vmparam.h" @@ -35,4 +36,4 @@ extern abi_ulong target_stksiz; #define TARGET_PS_STRINGS ((target_stkbas + target_stksiz) - \ sizeof(struct target_ps_strings)) -#endif /* !TARGET_OS_VMPARAM_H_ */ +#endif /* TARGET_OS_VMPARAM_H */ diff --git a/bsd-user/host/i386/host-signal.h b/bsd-user/host/i386/host-signal.h index 169e61b154c9..ffdfaba534ac 100644 --- a/bsd-user/host/i386/host-signal.h +++ b/bsd-user/host/i386/host-signal.h @@ -9,6 +9,7 @@ #ifndef I386_HOST_SIGNAL_H #define I386_HOST_SIGNAL_H +#include #include #include #include diff --git a/bsd-user/host/x86_64/host-signal.h b/bsd-user/host/x86_64/host-signal.h index 47ca19f8814b..32ac4e418034 100644 --- a/bsd-user/host/x86_64/host-signal.h +++ b/bsd-user/host/x86_64/host-signal.h @@ -9,6 +9,7 @@ #ifndef X86_64_HOST_SIGNAL_H #define X86_64_HOST_SIGNAL_H +#include #include #include #include diff --git a/bsd-user/i386/target.h b/bsd-user/i386/target.h index 9b9df047a3b7..ddd3b8ec0830 100644 --- a/bsd-user/i386/target.h +++ b/bsd-user/i386/target.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET_ARCH_H -#define TARGET_ARCH_H +#ifndef TARGET_H +#define TARGET_H /* * i386 doesn't 'lump' the registers for 64-bit args. @@ -17,5 +17,4 @@ static inline bool regpairs_aligned(void *cpu_env) return false; } -#endif /* ! TARGET_ARCH_H */ - +#endif /* TARGET_H */ diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h index 73e9a028feb9..9595e60f09f1 100644 --- a/bsd-user/i386/target_arch.h +++ b/bsd-user/i386/target_arch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_H_ -#define _TARGET_ARCH_H_ +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H /* target_arch_cpu.c */ void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit, @@ -28,4 +28,4 @@ void bsd_i386_set_idt_base(uint64_t base); #define target_cpu_set_tls(env, newtls) -#endif /* ! _TARGET_ARCH_H_ */ +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h index 9da22202d484..d792dc720f9e 100644 --- a/bsd-user/i386/target_arch_cpu.h +++ b/bsd-user/i386/target_arch_cpu.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_CPU_H_ -#define _TARGET_ARCH_CPU_H_ +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" @@ -195,4 +195,4 @@ static inline void target_cpu_reset(CPUArchState *env) cpu_reset(env_cpu(env)); } -#endif /* ! _TARGET_ARCH_CPU_H_ */ +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/i386/target_arch_elf.h b/bsd-user/i386/target_arch_elf.h index eb760e07faa0..cbcd1f08e2fe 100644 --- a/bsd-user/i386/target_arch_elf.h +++ b/bsd-user/i386/target_arch_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_ELF_H_ -#define _TARGET_ARCH_ELF_H_ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H #define ELF_START_MMAP 0x80000000 #define ELF_ET_DYN_LOAD_ADDR 0x01001000 @@ -32,4 +33,4 @@ #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 -#endif /* _TARGET_ARCH_ELF_H_ */ +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/i386/target_arch_reg.h b/bsd-user/i386/target_arch_reg.h index 1fce1daf0159..81231096972d 100644 --- a/bsd-user/i386/target_arch_reg.h +++ b/bsd-user/i386/target_arch_reg.h @@ -18,8 +18,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_REG_H_ -#define _TARGET_ARCH_REG_H_ +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H /* See sys/i386/include/reg.h */ typedef struct target_reg { @@ -79,4 +79,4 @@ static inline void target_copy_regs(target_reg_t *regs, const CPUX86State *env) regs->r_gs = env->segs[R_GS].selector & 0xffff; } -#endif /* !_TARGET_ARCH_REG_H_ */ +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h index cb4e89b0b0de..ef94cc864f2f 100644 --- a/bsd-user/i386/target_arch_sigtramp.h +++ b/bsd-user/i386/target_arch_sigtramp.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGTRAMP_H_ -#define _TARGET_ARCH_SIGTRAMP_H_ +#ifndef TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned sys_sigreturn) @@ -26,4 +26,4 @@ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, return 0; } -#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/i386/target_arch_sysarch.h b/bsd-user/i386/target_arch_sysarch.h index e9ab98ec3208..db8fee6380a4 100644 --- a/bsd-user/i386/target_arch_sysarch.h +++ b/bsd-user/i386/target_arch_sysarch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef BSD_USER_ARCH_SYSARCH_H_ -#define BSD_USER_ARCH_SYSARCH_H_ +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H #include "target_syscall.h" @@ -74,4 +74,4 @@ static inline void do_freebsd_arch_print_sysarch( TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4); } -#endif /* !BSD_USER_ARCH_SYSARCH_H_ */ +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/i386/target_arch_thread.h b/bsd-user/i386/target_arch_thread.h index e65e476f7577..cee2148d946d 100644 --- a/bsd-user/i386/target_arch_thread.h +++ b/bsd-user/i386/target_arch_thread.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_THREAD_H_ -#define _TARGET_ARCH_THREAD_H_ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H /* Compare to vm_machdep.c cpu_set_upcall_kse() */ static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry, @@ -44,4 +45,4 @@ static inline void target_thread_init(struct target_pt_regs *regs, regs->edx = 0; } -#endif /* !_TARGET_ARCH_THREAD_H_ */ +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/i386/target_arch_vmparam.h b/bsd-user/i386/target_arch_vmparam.h index bb7718265b2a..79db420e5929 100644 --- a/bsd-user/i386/target_arch_vmparam.h +++ b/bsd-user/i386/target_arch_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_VMPARAM_H_ -#define _TARGET_ARCH_VMPARAM_H_ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H #include "cpu.h" @@ -43,4 +44,4 @@ static inline void set_second_rval(CPUX86State *state, abi_ulong retval2) state->regs[R_EDX] = retval2; } -#endif /* !_TARGET_ARCH_VMPARAM_H_ */ +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/bsd-user/main.c b/bsd-user/main.c index 88d347d05ebf..6f09180d6541 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -24,10 +24,9 @@ #include #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qemu/units.h" #include "qemu/accel.h" -#include "sysemu/tcg.h" #include "qemu-version.h" #include @@ -405,17 +404,16 @@ int main(int argc, char **argv) } /* init debug */ - qemu_log_needs_buffers(); - qemu_set_log_filename(log_file, &error_fatal); - if (log_mask) { - int mask; - - mask = qemu_str_to_log_mask(log_mask); - if (!mask) { - qemu_print_log_usage(stdout); - exit(1); + { + int mask = 0; + if (log_mask) { + mask = qemu_str_to_log_mask(log_mask); + if (!mask) { + qemu_print_log_usage(stdout); + exit(1); + } } - qemu_set_log(mask); + qemu_set_log_filename_flags(log_file, mask, &error_fatal); } if (optind >= argc) { @@ -504,20 +502,29 @@ int main(int argc, char **argv) g_free(target_environ); if (qemu_loglevel_mask(CPU_LOG_PAGE)) { - qemu_log("guest_base %p\n", (void *)guest_base); - log_page_dump("binary load"); - - qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); - qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); - qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n", - info->start_code); - qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n", - info->start_data); - qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data); - qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", - info->start_stack); - qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); - qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); + FILE *f = qemu_log_trylock(); + if (f) { + fprintf(f, "guest_base %p\n", (void *)guest_base); + fprintf(f, "page layout changed following binary load\n"); + page_dump(f); + + fprintf(f, "start_brk 0x" TARGET_ABI_FMT_lx "\n", + info->start_brk); + fprintf(f, "end_code 0x" TARGET_ABI_FMT_lx "\n", + info->end_code); + fprintf(f, "start_code 0x" TARGET_ABI_FMT_lx "\n", + info->start_code); + fprintf(f, "start_data 0x" TARGET_ABI_FMT_lx "\n", + info->start_data); + fprintf(f, "end_data 0x" TARGET_ABI_FMT_lx "\n", + info->end_data); + fprintf(f, "start_stack 0x" TARGET_ABI_FMT_lx "\n", + info->start_stack); + fprintf(f, "brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); + fprintf(f, "entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); + + qemu_log_unlock(f); + } } /* build Task State */ diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 13cb32dba13e..d6c5a344c9b5 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "qemu-common.h" static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static __thread int mmap_lock_count; @@ -515,7 +514,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, * up to the targets page boundary. */ - if ((qemu_real_host_page_size < qemu_host_page_size) && fd != -1) { + if ((qemu_real_host_page_size() < qemu_host_page_size) && fd != -1) { struct stat sb; if (fstat(fd, &sb) == -1) { @@ -664,7 +663,6 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, page_dump(stdout); printf("\n"); #endif - tb_invalidate_phys_range(start, start + len); mmap_unlock(); return start; fail: @@ -770,7 +768,6 @@ int target_munmap(abi_ulong start, abi_ulong len) if (ret == 0) { page_set_flags(start, start + len, 0); - tb_invalidate_phys_range(start, start + len); } mmap_unlock(); return ret; diff --git a/bsd-user/netbsd/host-os.h b/bsd-user/netbsd/host-os.h index c0be51a7ef49..7c14b1ea7801 100644 --- a/bsd-user/netbsd/host-os.h +++ b/bsd-user/netbsd/host-os.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _HOST_OS_H_ -#define _HOST_OS_H_ +#ifndef HOST_OS_H +#define HOST_OS_H #define HOST_DEFAULT_BSD_TYPE target_netbsd -#endif /*!_HOST_OS_H_ */ +#endif /* HOST_OS_H */ diff --git a/bsd-user/netbsd/target_os_elf.h b/bsd-user/netbsd/target_os_elf.h index 21b475f458c2..2f3cb2087182 100644 --- a/bsd-user/netbsd/target_os_elf.h +++ b/bsd-user/netbsd/target_os_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_ELF_H_ -#define _TARGET_OS_ELF_H_ + +#ifndef TARGET_OS_ELF_H +#define TARGET_OS_ELF_H #include "target_arch_elf.h" #include "elf.h" @@ -143,4 +144,4 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#endif /* _TARGET_OS_ELF_H_ */ +#endif /* TARGET_OS_ELF_H */ diff --git a/bsd-user/netbsd/target_os_siginfo.h b/bsd-user/netbsd/target_os_siginfo.h index 667c19cc7cee..eb57e0a3098f 100644 --- a/bsd-user/netbsd/target_os_siginfo.h +++ b/bsd-user/netbsd/target_os_siginfo.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGINFO_H_ -#define _TARGET_OS_SIGINFO_H_ +#ifndef TARGET_OS_SIGINFO_H +#define TARGET_OS_SIGINFO_H #define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ #define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) @@ -79,4 +79,4 @@ typedef union target_siginfo { #define TARGET_TRAP_TRACE 2 -#endif /* ! _TARGET_OS_SIGINFO_H_ */ +#endif /* TARGET_OS_SIGINFO_H */ diff --git a/bsd-user/netbsd/target_os_signal.h b/bsd-user/netbsd/target_os_signal.h index a373922f7e8f..4ee4f768e0e1 100644 --- a/bsd-user/netbsd/target_os_signal.h +++ b/bsd-user/netbsd/target_os_signal.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGNAL_H_ -#define _TARGET_OS_SIGNAL_H_ +#ifndef TARGET_OS_SIGNAL_H +#define TARGET_OS_SIGNAL_H #include "target_os_siginfo.h" #include "target_arch_signal.h" @@ -66,4 +66,4 @@ #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ #define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ -#endif /* !_TARGET_OS_SIGNAL_H_ */ +#endif /* TARGET_OS_SIGNAL_H */ diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h index 503279c1a904..8349e9149b89 100644 --- a/bsd-user/netbsd/target_os_stack.h +++ b/bsd-user/netbsd/target_os_stack.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_STACK_H_ -#define _TARGET_OS_STACK_H_ +#ifndef TARGET_OS_STACK_H +#define TARGET_OS_STACK_H #include "target_arch_sigtramp.h" @@ -53,4 +53,4 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p, return 0; } -#endif /* !_TARGET_OS_STACK_H_ */ +#endif /* TARGET_OS_STACK_H */ diff --git a/bsd-user/netbsd/target_os_thread.h b/bsd-user/netbsd/target_os_thread.h index 904dd1bf782b..8ccfa16e4bed 100644 --- a/bsd-user/netbsd/target_os_thread.h +++ b/bsd-user/netbsd/target_os_thread.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_THREAD_H_ -#define _TARGET_OS_THREAD_H_ +#ifndef TARGET_OS_THREAD_H +#define TARGET_OS_THREAD_H #include "target_arch_thread.h" -#endif /* !_TARGET_OS_THREAD_H_ */ +#endif /* TARGET_OS_THREAD_H */ diff --git a/bsd-user/openbsd/host-os.h b/bsd-user/openbsd/host-os.h index eb8fdf156792..b9222335d46e 100644 --- a/bsd-user/openbsd/host-os.h +++ b/bsd-user/openbsd/host-os.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _HOST_OS_H_ -#define _HOST_OS_H_ +#ifndef HOST_OS_H +#define HOST_OS_H #define HOST_DEFAULT_BSD_TYPE target_openbsd -#endif /*!_HOST_OS_H_ */ +#endif /* HOST_OS_H */ diff --git a/bsd-user/openbsd/target_os_elf.h b/bsd-user/openbsd/target_os_elf.h index a5cfcd3aff8d..6dca9c5a8537 100644 --- a/bsd-user/openbsd/target_os_elf.h +++ b/bsd-user/openbsd/target_os_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_ELF_H_ -#define _TARGET_OS_ELF_H_ + +#ifndef TARGET_OS_ELF_H +#define TARGET_OS_ELF_H #include "target_arch_elf.h" #include "elf.h" @@ -143,4 +144,4 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#endif /* _TARGET_OS_ELF_H_ */ +#endif /* TARGET_OS_ELF_H */ diff --git a/bsd-user/openbsd/target_os_siginfo.h b/bsd-user/openbsd/target_os_siginfo.h index baf646a5ab33..732009a8201a 100644 --- a/bsd-user/openbsd/target_os_siginfo.h +++ b/bsd-user/openbsd/target_os_siginfo.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGINFO_H_ -#define _TARGET_OS_SIGINFO_H_ +#ifndef TARGET_OS_SIGINFO_H +#define TARGET_OS_SIGINFO_H #define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ #define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) @@ -79,4 +79,4 @@ typedef union target_siginfo { #define TARGET_TRAP_TRACE 2 -#endif /* ! _TARGET_OS_SIGINFO_H_ */ +#endif /* TARGET_OS_SIGINFO_H */ diff --git a/bsd-user/openbsd/target_os_signal.h b/bsd-user/openbsd/target_os_signal.h index a373922f7e8f..4ee4f768e0e1 100644 --- a/bsd-user/openbsd/target_os_signal.h +++ b/bsd-user/openbsd/target_os_signal.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGNAL_H_ -#define _TARGET_OS_SIGNAL_H_ +#ifndef TARGET_OS_SIGNAL_H +#define TARGET_OS_SIGNAL_H #include "target_os_siginfo.h" #include "target_arch_signal.h" @@ -66,4 +66,4 @@ #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ #define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ -#endif /* !_TARGET_OS_SIGNAL_H_ */ +#endif /* TARGET_OS_SIGNAL_H */ diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h index 4b37955d3b1e..264a6586089b 100644 --- a/bsd-user/openbsd/target_os_stack.h +++ b/bsd-user/openbsd/target_os_stack.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_STACK_H_ -#define _TARGET_OS_STACK_H_ +#ifndef TARGET_OS_STACK_H +#define TARGET_OS_STACK_H #include "target_arch_sigtramp.h" @@ -53,4 +53,4 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p, return 0; } -#endif /* !_TARGET_OS_STACK_H_ */ +#endif /* TARGET_OS_STACK_H */ diff --git a/bsd-user/openbsd/target_os_thread.h b/bsd-user/openbsd/target_os_thread.h index 01ed0d9fc86c..c3adc6712fe5 100644 --- a/bsd-user/openbsd/target_os_thread.h +++ b/bsd-user/openbsd/target_os_thread.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_THREAD_H_ -#define _TARGET_OS_THREAD_H_ +#ifndef TARGET_OS_THREAD_H +#define TARGET_OS_THREAD_H #include "target_arch_thread.h" -#endif /* !_TARGET_OS_THREAD_H_ */ +#endif /* TARGET_OS_THREAD_H */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 21c06f2e7003..be6105385e8c 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -465,7 +465,7 @@ static inline void *lock_user_string(abi_ulong guest_addr) static inline uint64_t target_arg64(uint32_t word0, uint32_t word1) { #if TARGET_ABI_BITS == 32 -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN return ((uint64_t)word0 << 32) | word1; #else return ((uint64_t)word1 << 32) | word0; diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 8a36b696d82b..58a53863957a 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -347,7 +347,8 @@ static int core_dump_signal(int sig) } /* Abort execution with signal. */ -static void QEMU_NORETURN dump_core_and_abort(int target_sig) +static G_NORETURN +void dump_core_and_abort(int target_sig) { CPUArchState *env = thread_cpu->env_ptr; CPUState *cpu = env_cpu(env); diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index c3bf14f38f45..b6d113d24a73 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _SYSCALL_DEFS_H_ -#define _SYSCALL_DEFS_H_ +#ifndef SYSCALL_DEFS_H +#define SYSCALL_DEFS_H #include #include @@ -226,4 +226,8 @@ type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ } -#endif /* ! _SYSCALL_DEFS_H_ */ +/* So far all target and host bitmasks are the same */ +#define target_to_host_bitmask(x, tbl) (x) +#define host_to_target_bitmask(x, tbl) (x) + +#endif /* SYSCALL_DEFS_H */ diff --git a/bsd-user/x86_64/target.h b/bsd-user/x86_64/target.h index 8956631db1d5..0cf0e2a14aba 100644 --- a/bsd-user/x86_64/target.h +++ b/bsd-user/x86_64/target.h @@ -17,5 +17,5 @@ static inline bool regpairs_aligned(void *cpu_env) return false; } -#endif /* ! TARGET_H */ +#endif /* TARGET_H */ diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h index e558e1b956e2..09bd97488985 100644 --- a/bsd-user/x86_64/target_arch.h +++ b/bsd-user/x86_64/target_arch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_H_ -#define _TARGET_ARCH_H_ +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H /* target_arch_cpu.c */ void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit, @@ -28,4 +28,4 @@ void bsd_x86_64_set_idt_base(uint64_t base); #define target_cpu_set_tls(env, newtls) -#endif /* !_TARGET_ARCH_H_ */ +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h index 5be2f02416ec..4094d61da1af 100644 --- a/bsd-user/x86_64/target_arch_cpu.h +++ b/bsd-user/x86_64/target_arch_cpu.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_CPU_H_ -#define _TARGET_ARCH_CPU_H_ +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" @@ -174,4 +174,4 @@ static inline void target_cpu_reset(CPUArchState *env) cpu_reset(env_cpu(env)); } -#endif /* ! _TARGET_ARCH_CPU_H_ */ +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/x86_64/target_arch_elf.h b/bsd-user/x86_64/target_arch_elf.h index c2f85539626e..b24471188834 100644 --- a/bsd-user/x86_64/target_arch_elf.h +++ b/bsd-user/x86_64/target_arch_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_ELF_H_ -#define _TARGET_ARCH_ELF_H_ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H #define ELF_START_MMAP 0x2aaaaab000ULL #define ELF_ET_DYN_LOAD_ADDR 0x01021000 @@ -32,4 +33,4 @@ #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 -#endif /* _TARGET_ARCH_ELF_H_ */ +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/x86_64/target_arch_reg.h b/bsd-user/x86_64/target_arch_reg.h index 00e96245178f..7a766de91850 100644 --- a/bsd-user/x86_64/target_arch_reg.h +++ b/bsd-user/x86_64/target_arch_reg.h @@ -18,8 +18,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_REG_H_ -#define _TARGET_ARCH_REG_H_ +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H /* See sys/amd64/include/reg.h */ typedef struct target_reg { @@ -89,4 +89,4 @@ static inline void target_copy_regs(target_reg_t *regs, const CPUX86State *env) regs->r_ss = env->segs[R_SS].selector & 0xffff; } -#endif /* !_TARGET_ARCH_REG_H_ */ +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h index b4a0ebf2bd5f..ca24bf1e7f70 100644 --- a/bsd-user/x86_64/target_arch_signal.h +++ b/bsd-user/x86_64/target_arch_signal.h @@ -15,8 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGNAL_H_ -#define _TARGET_ARCH_SIGNAL_H_ + +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H #include "cpu.h" @@ -96,4 +97,4 @@ struct target_sigframe { uint32_t __spare__[2]; }; -#endif /* !TARGET_ARCH_SIGNAL_H_ */ +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h index 29d4a8b55f3f..01da614098a8 100644 --- a/bsd-user/x86_64/target_arch_sigtramp.h +++ b/bsd-user/x86_64/target_arch_sigtramp.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGTRAMP_H_ -#define _TARGET_ARCH_SIGTRAMP_H_ +#ifndef TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned sys_sigreturn) @@ -26,4 +26,4 @@ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, return 0; } -#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/x86_64/target_arch_sysarch.h b/bsd-user/x86_64/target_arch_sysarch.h index 5c36fc075206..152cb8bcb86f 100644 --- a/bsd-user/x86_64/target_arch_sysarch.h +++ b/bsd-user/x86_64/target_arch_sysarch.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef BSD_USER_ARCH_SYSARCH_H_ -#define BSD_USER_ARCH_SYSARCH_H_ +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H #include "target_syscall.h" @@ -73,4 +73,4 @@ static inline void do_freebsd_arch_print_sysarch( TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4); } -#endif /*! BSD_USER_ARCH_SYSARCH_H_ */ +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h index b745d7ffeb7d..52c28906d6dd 100644 --- a/bsd-user/x86_64/target_arch_thread.h +++ b/bsd-user/x86_64/target_arch_thread.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_THREAD_H_ -#define _TARGET_ARCH_THREAD_H_ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H /* Compare to vm_machdep.c cpu_set_upcall_kse() */ static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry, @@ -35,4 +36,4 @@ static inline void target_thread_init(struct target_pt_regs *regs, regs->rdi = infop->start_stack; } -#endif /* !_TARGET_ARCH_THREAD_H_ */ +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/x86_64/target_arch_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h index 81a915f2e556..6797623a6ba2 100644 --- a/bsd-user/x86_64/target_arch_vmparam.h +++ b/bsd-user/x86_64/target_arch_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_VMPARAM_H_ -#define _TARGET_ARCH_VMPARAM_H_ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H #include "cpu.h" @@ -43,4 +44,4 @@ static inline void set_second_rval(CPUX86State *state, abi_ulong retval2) state->regs[R_EDX] = retval2; } -#endif /* !_TARGET_ARCH_VMPARAM_H_ */ +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/capstone b/capstone deleted file mode 160000 index f8b1b833015a..000000000000 --- a/capstone +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f8b1b833015a4ae47110ed068e0deb7106ced66d diff --git a/chardev/baum.c b/chardev/baum.c index 79d618e35045..0a0d12661a43 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-fd.c b/chardev/char-fd.c index 93c56913b49a..d2c492335989 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/module.h" #include "qemu/sockets.h" #include "qapi/error.h" @@ -199,7 +198,7 @@ int qmp_chardev_open_file_source(char *src, int flags, Error **errp) { int fd = -1; - TFR(fd = qemu_open_old(src, flags, 0666)); + fd = RETRY_ON_EINTR(qemu_open_old(src, flags, 0666)); if (fd == -1) { error_setg_file_open(errp, errno, src); } @@ -213,8 +212,8 @@ void qemu_chr_open_fd(Chardev *chr, FDChardev *s = FD_CHARDEV(chr); g_autofree char *name = NULL; - if (fd_out >= 0) { - qemu_set_nonblock(fd_out); + if (fd_out >= 0 && !g_unix_set_fd_nonblocking(fd_out, true, NULL)) { + assert(!"Failed to set FD nonblocking"); } if (fd_out == fd_in && fd_in >= 0) { diff --git a/chardev/char-file.c b/chardev/char-file.c index 2fd80707e5f4..3a7b9caf6f0a 100644 --- a/chardev/char-file.c +++ b/chardev/char-file.c @@ -45,7 +45,7 @@ static void qmp_chardev_open_file(Chardev *chr, DWORD accessmode; DWORD flags; - if (file->has_in) { + if (file->in) { error_setg(errp, "input file not supported"); return; } @@ -83,7 +83,7 @@ static void qmp_chardev_open_file(Chardev *chr, return; } - if (file->has_in) { + if (file->in) { flags = O_RDONLY; in = qmp_chardev_open_file_source(file->in, flags, errp); if (in < 0) { diff --git a/chardev/char-io.c b/chardev/char-io.c index 8ced18416093..4451128cba5d 100644 --- a/chardev/char-io.c +++ b/chardev/char-io.c @@ -122,7 +122,7 @@ int io_channel_send_full(QIOChannel *ioc, ret = qio_channel_writev_full( ioc, &iov, 1, - fds, nfds, NULL); + fds, nfds, 0, NULL); if (ret == QIO_CHANNEL_ERR_BLOCK) { if (offset) { return offset; diff --git a/chardev/char-parallel.c b/chardev/char-parallel.c index 05e7efbd6ca9..a5164f975af3 100644 --- a/chardev/char-parallel.c +++ b/chardev/char-parallel.c @@ -238,7 +238,6 @@ static void qemu_chr_open_pp_fd(Chardev *chr, } #endif -#ifdef HAVE_CHARDEV_PARPORT static void qmp_chardev_open_parallel(Chardev *chr, ChardevBackend *backend, bool *be_opened, @@ -276,29 +275,21 @@ static void char_parallel_class_init(ObjectClass *oc, void *data) cc->parse = qemu_chr_parse_parallel; cc->open = qmp_chardev_open_parallel; -#if defined(__linux__) - cc->chr_ioctl = pp_ioctl; -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ - defined(__DragonFly__) cc->chr_ioctl = pp_ioctl; -#endif } static void char_parallel_finalize(Object *obj) { -#if defined(__linux__) Chardev *chr = CHARDEV(obj); ParallelChardev *drv = PARALLEL_CHARDEV(chr); int fd = drv->fd; +#if defined(__linux__) pp_hw_mode(drv, IEEE1284_MODE_COMPAT); ioctl(fd, PPRELEASE); +#endif close(fd); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ - defined(__DragonFly__) - /* FIXME: close fd? */ -#endif } static const TypeInfo char_parallel_type_info = { @@ -315,5 +306,3 @@ static void register_types(void) } type_init(register_types); - -#endif diff --git a/chardev/char-pipe.c b/chardev/char-pipe.c index 7eca5d9a56ae..5ad30bcc599f 100644 --- a/chardev/char-pipe.c +++ b/chardev/char-pipe.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/main-loop.h" #include "qemu/module.h" @@ -132,8 +131,8 @@ static void qemu_chr_open_pipe(Chardev *chr, filename_in = g_strdup_printf("%s.in", filename); filename_out = g_strdup_printf("%s.out", filename); - TFR(fd_in = qemu_open_old(filename_in, O_RDWR | O_BINARY)); - TFR(fd_out = qemu_open_old(filename_out, O_RDWR | O_BINARY)); + fd_in = RETRY_ON_EINTR(qemu_open_old(filename_in, O_RDWR | O_BINARY)); + fd_out = RETRY_ON_EINTR(qemu_open_old(filename_out, O_RDWR | O_BINARY)); g_free(filename_in); g_free(filename_out); if (fd_in < 0 || fd_out < 0) { @@ -143,7 +142,9 @@ static void qemu_chr_open_pipe(Chardev *chr, if (fd_out >= 0) { close(fd_out); } - TFR(fd_in = fd_out = qemu_open_old(filename, O_RDWR | O_BINARY)); + fd_in = fd_out = RETRY_ON_EINTR( + qemu_open_old(filename, O_RDWR | O_BINARY) + ); if (fd_in < 0) { error_setg_file_open(errp, errno, filename); return; diff --git a/chardev/char-pty.c b/chardev/char-pty.c index a2d1e7c985bc..92fd33c854cb 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "chardev/char.h" #include "io/channel-file.h" @@ -94,9 +93,7 @@ static void pty_chr_update_read_handler(Chardev *chr) pfd.fd = fioc->fd; pfd.events = G_IO_OUT; pfd.revents = 0; - do { - rc = g_poll(&pfd, 1, 0); - } while (rc == -1 && errno == EINTR); + rc = RETRY_ON_EINTR(g_poll(&pfd, 1, 0)); assert(rc >= 0); if (pfd.revents & G_IO_HUP) { @@ -197,6 +194,117 @@ static void char_pty_finalize(Object *obj) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } +#if defined HAVE_PTY_H +# include +#elif defined CONFIG_BSD +# include +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +# include +# else +# include +# endif +#elif defined CONFIG_SOLARIS +# include +# include +#else +# include +#endif + +#ifdef __sun__ + +#if !defined(HAVE_OPENPTY) +/* Once illumos has openpty(), this is going to be removed. */ +static int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + const char *slave; + int mfd = -1, sfd = -1; + + *amaster = *aslave = -1; + + mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); + if (mfd < 0) { + goto err; + } + + if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) { + goto err; + } + + if ((slave = ptsname(mfd)) == NULL) { + goto err; + } + + if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) { + goto err; + } + + if (ioctl(sfd, I_PUSH, "ptem") == -1 || + (termp != NULL && tcgetattr(sfd, termp) < 0)) { + goto err; + } + + *amaster = mfd; + *aslave = sfd; + + if (winp) { + ioctl(sfd, TIOCSWINSZ, winp); + } + + return 0; + +err: + if (sfd != -1) { + close(sfd); + } + close(mfd); + return -1; +} +#endif + +static void cfmakeraw (struct termios *termios_p) +{ + termios_p->c_iflag &= + ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + termios_p->c_oflag &= ~OPOST; + termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + termios_p->c_cflag &= ~(CSIZE | PARENB); + termios_p->c_cflag |= CS8; + + termios_p->c_cc[VMIN] = 0; + termios_p->c_cc[VTIME] = 0; +} +#endif + +/* like openpty() but also makes it raw; return master fd */ +static int qemu_openpty_raw(int *aslave, char *pty_name) +{ + int amaster; + struct termios tty; +#if defined(__OpenBSD__) || defined(__DragonFly__) + char pty_buf[PATH_MAX]; +#define q_ptsname(x) pty_buf +#else + char *pty_buf = NULL; +#define q_ptsname(x) ptsname(x) +#endif + + if (openpty(&amaster, aslave, pty_buf, NULL, NULL) < 0) { + return -1; + } + + /* Set raw attributes on the pty. */ + tcgetattr(*aslave, &tty); + cfmakeraw(&tty); + tcsetattr(*aslave, TCSAFLUSH, &tty); + + if (pty_name) { + strcpy(pty_name, q_ptsname(amaster)); + } + + return amaster; +} + static void char_pty_open(Chardev *chr, ChardevBackend *backend, bool *be_opened, @@ -214,7 +322,10 @@ static void char_pty_open(Chardev *chr, } close(slave_fd); - qemu_set_nonblock(master_fd); + if (!g_unix_set_fd_nonblocking(master_fd, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return; + } chr->filename = g_strdup_printf("pty:%s", pty_name); qemu_printf("char device redirected to %s (label %s)\n", diff --git a/chardev/char-serial.c b/chardev/char-serial.c index 7c3d84ae243e..4b0b83d5b45e 100644 --- a/chardev/char-serial.c +++ b/chardev/char-serial.c @@ -271,7 +271,10 @@ static void qmp_chardev_open_serial(Chardev *chr, if (fd < 0) { return; } - qemu_set_nonblock(fd); + if (!g_unix_set_fd_nonblocking(fd, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return; + } tty_serial_init(fd, 115200, 'N', 8, 1); qemu_chr_open_fd(chr, fd, fd); diff --git a/chardev/char-socket.c b/chardev/char-socket.c index fab2d791d43d..29ffe5075e27 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -311,7 +311,7 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len) } /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */ - qemu_set_block(fd); + qemu_socket_set_block(fd); #ifndef MSG_CMSG_CLOEXEC qemu_set_cloexec(fd); @@ -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 = "]"; @@ -1253,7 +1251,7 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock, "'fd' address type"); return false; } - if (sock->has_tls_creds && + if (sock->tls_creds && !(sock->has_server && sock->server)) { error_setg(errp, "'tls_creds' option is incompatible with " @@ -1263,7 +1261,7 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock, break; case SOCKET_ADDRESS_TYPE_UNIX: - if (sock->has_tls_creds) { + if (sock->tls_creds) { error_setg(errp, "'tls_creds' option is incompatible with " "'unix' address type"); @@ -1275,7 +1273,7 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock, break; case SOCKET_ADDRESS_TYPE_VSOCK: - if (sock->has_tls_creds) { + if (sock->tls_creds) { error_setg(errp, "'tls_creds' option is incompatible with " "'vsock' address type"); @@ -1286,7 +1284,7 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock, break; } - if (sock->has_tls_authz && !sock->has_tls_creds) { + if (sock->tls_authz && !sock->tls_creds) { error_setg(errp, "'tls_authz' option requires 'tls_creds' option"); return false; } @@ -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 @@ -1465,9 +1465,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, sock->wait = qemu_opt_get_bool(opts, "wait", true); sock->has_reconnect = qemu_opt_find(opts, "reconnect"); sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0); - sock->has_tls_creds = qemu_opt_get(opts, "tls-creds"); sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds")); - sock->has_tls_authz = qemu_opt_get(opts, "tls-authz"); sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz")); addr = g_new0(SocketAddressLegacy, 1); diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c index 403da308c980..3c648678ab14 100644 --- a/chardev/char-stdio.c +++ b/chardev/char-stdio.c @@ -103,7 +103,10 @@ static void qemu_chr_open_stdio(Chardev *chr, stdio_in_use = true; old_fd0_flags = fcntl(0, F_GETFL); tcgetattr(0, &oldtty); - qemu_set_nonblock(0); + if (!g_unix_set_fd_nonblocking(0, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return; + } atexit(term_exit); memset(&act, 0, sizeof(act)); diff --git a/chardev/char-udp.c b/chardev/char-udp.c index 6756e69924cb..3d9a2d5e7724 100644 --- a/chardev/char-udp.c +++ b/chardev/char-udp.c @@ -178,7 +178,6 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, udp->remote = addr; if (has_local) { - udp->has_local = true; addr = g_new0(SocketAddressLegacy, 1); addr->type = SOCKET_ADDRESS_TYPE_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c index a4771ab82e64..eb830eabd957 100644 --- a/chardev/char-win-stdio.c +++ b/chardev/char-win-stdio.c @@ -146,6 +146,8 @@ static void qemu_chr_open_stdio(Chardev *chr, bool *be_opened, Error **errp) { + ChardevStdio *opts = backend->u.stdio.data; + bool stdio_allow_signal = !opts->has_signal || opts->signal; WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr); DWORD dwMode; int is_console = 0; @@ -193,7 +195,11 @@ static void qemu_chr_open_stdio(Chardev *chr, if (is_console) { /* set the terminal in raw mode */ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ - dwMode |= ENABLE_PROCESSED_INPUT; + if (stdio_allow_signal) { + dwMode |= ENABLE_PROCESSED_INPUT; + } else { + dwMode &= ~ENABLE_PROCESSED_INPUT; + } } SetConsoleMode(stdio->hStdIn, dwMode); diff --git a/chardev/char.c b/chardev/char.c index 0169d8dde4b5..87ab6efbcca0 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) { @@ -240,7 +240,7 @@ static void qemu_char_open(Chardev *chr, ChardevBackend *backend, /* Any ChardevCommon member would work */ ChardevCommon *common = backend ? backend->u.null.data : NULL; - if (common && common->has_logfile) { + if (common && common->logfile) { int flags = O_WRONLY; if (common->has_logappend && common->logappend) { @@ -496,9 +496,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend) { const char *logfile = qemu_opt_get(opts, "logfile"); - backend->has_logfile = logfile != NULL; backend->logfile = g_strdup(logfile); - backend->has_logappend = true; backend->logappend = qemu_opt_get_bool(opts, "logappend", false); } @@ -532,19 +530,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp) return cc; } -static struct ChardevAlias { - const char *typename; - const char *alias; - bool deprecation_warning_printed; -} chardev_alias_table[] = { -#ifdef HAVE_CHARDEV_PARPORT - { "parallel", "parport" }, -#endif -#ifdef HAVE_CHARDEV_SERIAL - { "serial", "tty" }, -#endif -}; - typedef struct ChadevClassFE { void (*fn)(const char *name, void *opaque); void *opaque; @@ -580,28 +565,12 @@ help_string_append(const char *name, void *opaque) g_string_append_printf(str, "\n %s", name); } -static const char *chardev_alias_translate(const char *name) -{ - int i; - for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) { - if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) { - if (!chardev_alias_table[i].deprecation_warning_printed) { - warn_report("The alias '%s' is deprecated, use '%s' instead", - name, chardev_alias_table[i].typename); - chardev_alias_table[i].deprecation_warning_printed = true; - } - return chardev_alias_table[i].typename; - } - } - return name; -} - ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp) { Error *local_err = NULL; const ChardevClass *cc; ChardevBackend *backend = NULL; - const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend")); + const char *name = qemu_opt_get(opts, "backend"); if (name == NULL) { error_setg(errp, "chardev: \"%s\" missing backend", @@ -639,7 +608,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context, const ChardevClass *cc; Chardev *chr = NULL; ChardevBackend *backend = NULL; - const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend")); + const char *name = qemu_opt_get(opts, "backend"); const char *id = qemu_opts_id(opts); char *bid = NULL; @@ -1057,7 +1026,6 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, ret = g_new0(ChardevReturn, 1); if (CHARDEV_IS_PTY(chr)) { ret->pty = g_strdup(chr->filename + 4); - ret->has_pty = true; } return ret; @@ -1160,7 +1128,6 @@ ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, ret = g_new0(ChardevReturn, 1); if (CHARDEV_IS_PTY(chr_new)) { ret->pty = g_strdup(chr_new->filename + 4); - ret->has_pty = true; } return ret; diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h index aba0240759eb..4e03af31476c 100644 --- a/chardev/chardev-internal.h +++ b/chardev/chardev-internal.h @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #ifndef CHARDEV_INTERNAL_H #define CHARDEV_INTERNAL_H @@ -64,4 +65,4 @@ void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event); Object *get_chardevs_root(void); -#endif /* CHAR_MUX_H */ +#endif /* CHARDEV_INTERNAL_H */ diff --git a/chardev/meson.build b/chardev/meson.build index 325ba2bdb97d..789b50056ae4 100644 --- a/chardev/meson.build +++ b/chardev/meson.build @@ -12,11 +12,14 @@ chardev_ss.add(files( 'char-udp.c', 'char.c', )) -chardev_ss.add(when: 'CONFIG_POSIX', if_true: files( +chardev_ss.add(when: 'CONFIG_POSIX', if_true: [files( 'char-fd.c', - 'char-parallel.c', 'char-pty.c', -)) +), util]) +if targetos in ['linux', 'gnu/kfreebsd', 'freebsd', 'dragonfly'] + chardev_ss.add(files('char-parallel.c')) +endif + chardev_ss.add(when: 'CONFIG_WIN32', if_true: files( 'char-console.c', 'char-win-stdio.c', diff --git a/chardev/msmouse.c b/chardev/msmouse.c index eb9231dcdb98..ab8fe981d63f 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 e8b292c43ca7..43bdf6b60835 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/common-user/meson.build b/common-user/meson.build index 26212dda5c7a..ac9de5b9e3f5 100644 --- a/common-user/meson.build +++ b/common-user/meson.build @@ -1,3 +1,7 @@ +if not have_user + subdir_done() +endif + common_user_inc += include_directories('host/' / host_arch) user_ss.add(files( diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak index 6985a25377a0..d741ca86ec54 100644 --- a/configs/devices/arm-softmmu/default.mak +++ b/configs/devices/arm-softmmu/default.mak @@ -30,6 +30,7 @@ CONFIG_COLLIE=y CONFIG_ASPEED_SOC=y CONFIG_NETDUINO2=y CONFIG_NETDUINOPLUS2=y +CONFIG_OLIMEX_STM32_H405=y CONFIG_MPS2=y CONFIG_RASPI=y CONFIG_DIGIC=y @@ -42,3 +43,4 @@ CONFIG_FSL_IMX6UL=y CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y CONFIG_ALLWINNER_H3=y +CONFIG_NXP_RT595=y diff --git a/configs/devices/hppa-softmmu/default.mak b/configs/devices/hppa-softmmu/default.mak index b64c5eb3ff64..b0364bb88f27 100644 --- a/configs/devices/hppa-softmmu/default.mak +++ b/configs/devices/hppa-softmmu/default.mak @@ -6,4 +6,4 @@ # Boards: # -CONFIG_DINO=y +CONFIG_HPPA_B160L=y diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak new file mode 100644 index 000000000000..928bc117ef78 --- /dev/null +++ b/configs/devices/loongarch64-softmmu/default.mak @@ -0,0 +1,3 @@ +# Default configuration for loongarch64-softmmu + +CONFIG_LOONGARCH_VIRT=y diff --git a/configs/devices/mips-softmmu/common.mak b/configs/devices/mips-softmmu/common.mak index d2202c839e03..88aff9462564 100644 --- a/configs/devices/mips-softmmu/common.mak +++ b/configs/devices/mips-softmmu/common.mak @@ -17,13 +17,10 @@ CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y CONFIG_FDC=y -CONFIG_ACPI=y CONFIG_ACPI_PIIX4=y -CONFIG_APM=y CONFIG_I8257=y CONFIG_PIIX4=y CONFIG_IDE_ISA=y -CONFIG_IDE_PIIX=y CONFIG_PFLASH_CFI01=y CONFIG_I8259=y CONFIG_MC146818RTC=y @@ -33,6 +30,5 @@ CONFIG_MIPS_ITU=y CONFIG_MALTA=y CONFIG_PCNET_PCI=y CONFIG_MIPSSIM=y -CONFIG_ACPI_SMBUS=y CONFIG_SMBUS_EEPROM=y CONFIG_TEST_DEVICES=y diff --git a/configs/devices/mips64el-softmmu/default.mak b/configs/devices/mips64el-softmmu/default.mak index c610749ac13e..d5188f7ea58d 100644 --- a/configs/devices/mips64el-softmmu/default.mak +++ b/configs/devices/mips64el-softmmu/default.mak @@ -1,7 +1,6 @@ # Default configuration for mips64el-softmmu include ../mips-softmmu/common.mak -CONFIG_IDE_VIA=y CONFIG_FULOONG=y CONFIG_LOONGSON3V=y CONFIG_ATI_VGA=y diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a54..89c39e31237d 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/devices/ppc-softmmu/default.mak b/configs/devices/ppc-softmmu/default.mak index 658a454426ed..a887f5438b86 100644 --- a/configs/devices/ppc-softmmu/default.mak +++ b/configs/devices/ppc-softmmu/default.mak @@ -1,7 +1,8 @@ # Default configuration for ppc-softmmu # For embedded PPCs: -CONFIG_E500=y +CONFIG_E500PLAT=y +CONFIG_MPC8544DS=y CONFIG_PPC405=y CONFIG_PPC440=y CONFIG_VIRTEX=y diff --git a/configs/devices/xtensa-softmmu/default.mak b/configs/devices/xtensa-softmmu/default.mak index 4fe1bf00c94b..ff274bb41d05 100644 --- a/configs/devices/xtensa-softmmu/default.mak +++ b/configs/devices/xtensa-softmmu/default.mak @@ -7,3 +7,4 @@ CONFIG_SEMIHOSTING=y CONFIG_XTENSA_SIM=y CONFIG_XTENSA_VIRT=y CONFIG_XTENSA_XTFPGA=y +CONFIG_XTENSA_RT595=y diff --git a/configs/targets/aarch64-linux-user.mak b/configs/targets/aarch64-linux-user.mak index d0c603c54ec2..db552f183903 100644 --- a/configs/targets/aarch64-linux-user.mak +++ b/configs/targets/aarch64-linux-user.mak @@ -2,4 +2,5 @@ TARGET_ARCH=aarch64 TARGET_BASE_ARCH=arm TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/aarch64_be-linux-user.mak b/configs/targets/aarch64_be-linux-user.mak index d3ee10c00f31..dc78044fb155 100644 --- a/configs/targets/aarch64_be-linux-user.mak +++ b/configs/targets/aarch64_be-linux-user.mak @@ -1,6 +1,7 @@ TARGET_ARCH=aarch64 TARGET_BASE_ARCH=arm -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/arm-linux-user.mak b/configs/targets/arm-linux-user.mak index 3e10d6b15d5d..7f5d65794c1a 100644 --- a/configs/targets/arm-linux-user.mak +++ b/configs/targets/arm-linux-user.mak @@ -3,4 +3,5 @@ TARGET_SYSTBL_ABI=common,oabi TARGET_SYSTBL=syscall.tbl TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/armeb-linux-user.mak b/configs/targets/armeb-linux-user.mak index f81e5bf1fe4b..943d0d87bfdb 100644 --- a/configs/targets/armeb-linux-user.mak +++ b/configs/targets/armeb-linux-user.mak @@ -1,7 +1,8 @@ TARGET_ARCH=arm TARGET_SYSTBL_ABI=common,oabi TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/hppa-linux-user.mak b/configs/targets/hppa-linux-user.mak index f01e0a7b9ed8..db873a879688 100644 --- a/configs/targets/hppa-linux-user.mak +++ b/configs/targets/hppa-linux-user.mak @@ -2,4 +2,4 @@ TARGET_ARCH=hppa TARGET_SYSTBL_ABI=common,32 TARGET_SYSTBL=syscall.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/hppa-softmmu.mak b/configs/targets/hppa-softmmu.mak index e3e71eb21b9a..44f07b033238 100644 --- a/configs/targets/hppa-softmmu.mak +++ b/configs/targets/hppa-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=hppa TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak new file mode 100644 index 000000000000..7d1b96402098 --- /dev/null +++ b/configs/targets/loongarch64-linux-user.mak @@ -0,0 +1,3 @@ +# Default configuration for loongarch64-linux-user +TARGET_ARCH=loongarch64 +TARGET_BASE_ARCH=loongarch diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak new file mode 100644 index 000000000000..9abc99056fb7 --- /dev/null +++ b/configs/targets/loongarch64-softmmu.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=loongarch64 +TARGET_BASE_ARCH=loongarch +TARGET_SUPPORTS_MTTCG=y +TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml +TARGET_NEED_FDT=y diff --git a/configs/targets/m68k-linux-user.mak b/configs/targets/m68k-linux-user.mak index 805d16c6ab2d..579b5d299ccf 100644 --- a/configs/targets/m68k-linux-user.mak +++ b/configs/targets/m68k-linux-user.mak @@ -1,6 +1,6 @@ TARGET_ARCH=m68k TARGET_SYSTBL_ABI=common TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/cf-core.xml gdb-xml/cf-fp.xml gdb-xml/m68k-core.xml gdb-xml/m68k-fp.xml TARGET_HAS_BFLT=y diff --git a/configs/targets/m68k-softmmu.mak b/configs/targets/m68k-softmmu.mak index 5df1a2b7d76c..bbcd0bada698 100644 --- a/configs/targets/m68k-softmmu.mak +++ b/configs/targets/m68k-softmmu.mak @@ -1,3 +1,3 @@ TARGET_ARCH=m68k -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/cf-core.xml gdb-xml/cf-fp.xml gdb-xml/m68k-core.xml gdb-xml/m68k-fp.xml diff --git a/configs/targets/microblaze-linux-user.mak b/configs/targets/microblaze-linux-user.mak index 2a25bf2fa39a..4249a37f6528 100644 --- a/configs/targets/microblaze-linux-user.mak +++ b/configs/targets/microblaze-linux-user.mak @@ -1,5 +1,5 @@ TARGET_ARCH=microblaze TARGET_SYSTBL_ABI=common TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_HAS_BFLT=y diff --git a/configs/targets/microblaze-softmmu.mak b/configs/targets/microblaze-softmmu.mak index 33f2a004029f..8385e2d33363 100644 --- a/configs/targets/microblaze-softmmu.mak +++ b/configs/targets/microblaze-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=microblaze -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y TARGET_NEED_FDT=y diff --git a/configs/targets/mips-linux-user.mak b/configs/targets/mips-linux-user.mak index 19f5779831ae..71fa77d464dd 100644 --- a/configs/targets/mips-linux-user.mak +++ b/configs/targets/mips-linux-user.mak @@ -3,4 +3,4 @@ TARGET_ABI_MIPSO32=y TARGET_SYSTBL_ABI=o32 TARGET_SYSTBL=syscall_o32.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/mips-softmmu.mak b/configs/targets/mips-softmmu.mak index 8a49999a47dd..7787a4d94cf6 100644 --- a/configs/targets/mips-softmmu.mak +++ b/configs/targets/mips-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=mips TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y diff --git a/configs/targets/mips64-linux-user.mak b/configs/targets/mips64-linux-user.mak index 32fd1acdf254..5a4771f22dba 100644 --- a/configs/targets/mips64-linux-user.mak +++ b/configs/targets/mips64-linux-user.mak @@ -4,4 +4,4 @@ TARGET_BASE_ARCH=mips TARGET_SYSTBL_ABI=n64 TARGET_SYSTBL=syscall_n64.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/mips64-softmmu.mak b/configs/targets/mips64-softmmu.mak index ece25b96242e..568d66650c88 100644 --- a/configs/targets/mips64-softmmu.mak +++ b/configs/targets/mips64-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=mips64 TARGET_BASE_ARCH=mips TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/mipsn32-linux-user.mak b/configs/targets/mipsn32-linux-user.mak index b8c2441ad076..1e80b302fcb5 100644 --- a/configs/targets/mipsn32-linux-user.mak +++ b/configs/targets/mipsn32-linux-user.mak @@ -5,4 +5,4 @@ TARGET_BASE_ARCH=mips TARGET_SYSTBL_ABI=n32 TARGET_SYSTBL=syscall_n32.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/nios2-softmmu.mak b/configs/targets/nios2-softmmu.mak index 9a372f071772..1e93b54cd13a 100644 --- a/configs/targets/nios2-softmmu.mak +++ b/configs/targets/nios2-softmmu.mak @@ -1 +1,2 @@ TARGET_ARCH=nios2 +TARGET_ALIGNED_ONLY=y diff --git a/configs/targets/or1k-linux-user.mak b/configs/targets/or1k-linux-user.mak index 1dfb93e46dc8..39558f77ecfe 100644 --- a/configs/targets/or1k-linux-user.mak +++ b/configs/targets/or1k-linux-user.mak @@ -1,2 +1,2 @@ TARGET_ARCH=openrisc -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 9e1d4a1fb1e5..432f855a30a0 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc -TARGET_WORDS_BIGENDIAN=y +TARGET_SUPPORTS_MTTCG=y +TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/configs/targets/ppc-linux-user.mak b/configs/targets/ppc-linux-user.mak index ca4187e4aaca..cc0439a52857 100644 --- a/configs/targets/ppc-linux-user.mak +++ b/configs/targets/ppc-linux-user.mak @@ -1,5 +1,5 @@ TARGET_ARCH=ppc TARGET_SYSTBL_ABI=common,nospu,32 TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/power-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml diff --git a/configs/targets/ppc-softmmu.mak b/configs/targets/ppc-softmmu.mak index f4eef1819a66..774440108f7f 100644 --- a/configs/targets/ppc-softmmu.mak +++ b/configs/targets/ppc-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=ppc -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/power-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml TARGET_NEED_FDT=y diff --git a/configs/targets/ppc64-linux-user.mak b/configs/targets/ppc64-linux-user.mak index 3133346676cf..4d81969f4a2d 100644 --- a/configs/targets/ppc64-linux-user.mak +++ b/configs/targets/ppc64-linux-user.mak @@ -3,5 +3,5 @@ TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc TARGET_SYSTBL_ABI=common,nospu,64 TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml diff --git a/configs/targets/ppc64-softmmu.mak b/configs/targets/ppc64-softmmu.mak index 84fbf46be9e0..ddf0c39617f4 100644 --- a/configs/targets/ppc64-softmmu.mak +++ b/configs/targets/ppc64-softmmu.mak @@ -1,6 +1,6 @@ TARGET_ARCH=ppc64 TARGET_BASE_ARCH=ppc -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml TARGET_NEED_FDT=y diff --git a/configs/targets/riscv32-linux-user.mak b/configs/targets/riscv32-linux-user.mak index bd2f1fd4973f..9761618e67f4 100644 --- a/configs/targets/riscv32-linux-user.mak +++ b/configs/targets/riscv32-linux-user.mak @@ -2,4 +2,5 @@ TARGET_ARCH=riscv32 TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml +CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/riscv64-linux-user.mak b/configs/targets/riscv64-linux-user.mak index 4aca7662cea6..cfd1fd382f92 100644 --- a/configs/targets/riscv64-linux-user.mak +++ b/configs/targets/riscv64-linux-user.mak @@ -2,4 +2,5 @@ TARGET_ARCH=riscv64 TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml +CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/s390x-linux-user.mak b/configs/targets/s390x-linux-user.mak index 9e31ce6457e9..e2978248eded 100644 --- a/configs/targets/s390x-linux-user.mak +++ b/configs/targets/s390x-linux-user.mak @@ -1,5 +1,5 @@ TARGET_ARCH=s390x TARGET_SYSTBL_ABI=common,64 TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_XML_FILES= gdb-xml/s390x-core64.xml gdb-xml/s390-acr.xml gdb-xml/s390-fpr.xml gdb-xml/s390-vx.xml gdb-xml/s390-cr.xml gdb-xml/s390-virt.xml gdb-xml/s390-gs.xml diff --git a/configs/targets/s390x-softmmu.mak b/configs/targets/s390x-softmmu.mak index fd9fbd870d32..258b4cf35824 100644 --- a/configs/targets/s390x-softmmu.mak +++ b/configs/targets/s390x-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=s390x -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/s390x-core64.xml gdb-xml/s390-acr.xml gdb-xml/s390-fpr.xml gdb-xml/s390-vx.xml gdb-xml/s390-cr.xml gdb-xml/s390-virt.xml gdb-xml/s390-gs.xml diff --git a/configs/targets/sh4eb-linux-user.mak b/configs/targets/sh4eb-linux-user.mak index 9b6fb4c1bbed..6724165efee2 100644 --- a/configs/targets/sh4eb-linux-user.mak +++ b/configs/targets/sh4eb-linux-user.mak @@ -2,5 +2,5 @@ TARGET_ARCH=sh4 TARGET_SYSTBL_ABI=common TARGET_SYSTBL=syscall.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_HAS_BFLT=y diff --git a/configs/targets/sh4eb-softmmu.mak b/configs/targets/sh4eb-softmmu.mak index 382e9a80f8d2..dc8b30bf7a22 100644 --- a/configs/targets/sh4eb-softmmu.mak +++ b/configs/targets/sh4eb-softmmu.mak @@ -1,3 +1,3 @@ TARGET_ARCH=sh4 TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc-linux-user.mak b/configs/targets/sparc-linux-user.mak index 53dc7aaed5a6..00e7bc1f076a 100644 --- a/configs/targets/sparc-linux-user.mak +++ b/configs/targets/sparc-linux-user.mak @@ -2,4 +2,4 @@ TARGET_ARCH=sparc TARGET_SYSTBL_ABI=common,32 TARGET_SYSTBL=syscall.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc-softmmu.mak b/configs/targets/sparc-softmmu.mak index 9ba3d7b07f19..a849190f0108 100644 --- a/configs/targets/sparc-softmmu.mak +++ b/configs/targets/sparc-softmmu.mak @@ -1,3 +1,3 @@ TARGET_ARCH=sparc TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc32plus-linux-user.mak b/configs/targets/sparc32plus-linux-user.mak index e4c51df3dcad..a65c0951a18b 100644 --- a/configs/targets/sparc32plus-linux-user.mak +++ b/configs/targets/sparc32plus-linux-user.mak @@ -5,4 +5,4 @@ TARGET_ABI_DIR=sparc TARGET_SYSTBL_ABI=common,32 TARGET_SYSTBL=syscall.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc64-linux-user.mak b/configs/targets/sparc64-linux-user.mak index 9d23ab4a266e..20fcb93fa4b1 100644 --- a/configs/targets/sparc64-linux-user.mak +++ b/configs/targets/sparc64-linux-user.mak @@ -4,4 +4,4 @@ TARGET_ABI_DIR=sparc TARGET_SYSTBL_ABI=common,64 TARGET_SYSTBL=syscall.tbl TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc64-softmmu.mak b/configs/targets/sparc64-softmmu.mak index 8dd321780042..c626ac3eae67 100644 --- a/configs/targets/sparc64-softmmu.mak +++ b/configs/targets/sparc64-softmmu.mak @@ -1,4 +1,4 @@ TARGET_ARCH=sparc64 TARGET_BASE_ARCH=sparc TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/xtensaeb-linux-user.mak b/configs/targets/xtensaeb-linux-user.mak index 1ea0f1ba9156..bce2d1d65d23 100644 --- a/configs/targets/xtensaeb-linux-user.mak +++ b/configs/targets/xtensaeb-linux-user.mak @@ -1,5 +1,5 @@ TARGET_ARCH=xtensa TARGET_SYSTBL_ABI=common TARGET_SYSTBL=syscall.tbl -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_HAS_BFLT=y diff --git a/configs/targets/xtensaeb-softmmu.mak b/configs/targets/xtensaeb-softmmu.mak index 405cf5acbb4a..b02e11b82008 100644 --- a/configs/targets/xtensaeb-softmmu.mak +++ b/configs/targets/xtensaeb-softmmu.mak @@ -1,3 +1,3 @@ TARGET_ARCH=xtensa -TARGET_WORDS_BIGENDIAN=y +TARGET_BIG_ENDIAN=y TARGET_SUPPORTS_MTTCG=y diff --git a/configure b/configure index 7c08c18358be..9e407ce2e3a9 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" @@ -85,9 +83,10 @@ rm -f config.log # Print a helpful header at the top of config.log echo "# QEMU configure log $(date)" >> config.log printf "# Configured with:" >> config.log -printf " '%s'" "$0" "$@" >> config.log -echo >> config.log -echo "#" >> config.log +# repeat the invocation to log and stdout for CI +invoke=$(printf " '%s'" "$0" "$@") +test -n "$GITLAB_CI" && echo "configuring with: $invoke" +{ echo "$invoke"; echo; echo "#"; } >> config.log quote_sh() { printf "%s" "$1" | sed "s,','\\\\'',g; s,.*,'&'," @@ -109,6 +108,20 @@ error_exit() { } do_compiler() { + # Run the compiler, capturing its output to the log. First argument + # is compiler binary to execute. + compiler="$1" + shift + if test -n "$BASH_VERSION"; then eval ' + echo >>config.log " +funcs: ${FUNCNAME[*]} +lines: ${BASH_LINENO[*]}" + '; fi + echo $compiler "$@" >> config.log + $compiler "$@" >> config.log 2>&1 || return $? +} + +do_compiler_werror() { # Run the compiler, capturing its output to the log. First argument # is compiler binary to execute. compiler="$1" @@ -142,15 +155,11 @@ lines: ${BASH_LINENO[*]}" } do_cc() { - do_compiler "$cc" $CPU_CFLAGS "$@" -} - -do_cxx() { - do_compiler "$cxx" $CPU_CFLAGS "$@" + do_compiler_werror "$cc" $CPU_CFLAGS "$@" } do_objc() { - do_compiler "$objcc" $CPU_CFLAGS "$@" + do_compiler_werror "$objcc" $CPU_CFLAGS "$@" } # Append $2 to the variable named $1, with space separation @@ -158,24 +167,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 @@ -220,14 +211,6 @@ version_ge () { done } -glob() { - eval test -z '"${1#'"$2"'}"' -} - -ld_has() { - $ld --help 2>/dev/null | grep ".$1" >/dev/null 2>&1 -} - if printf %s\\n "$source_path" "$PWD" | grep -q "[[:space:]:]"; then error_exit "main directory cannot contain spaces nor colons" @@ -235,17 +218,10 @@ fi # default parameters cpu="" -iasl="iasl" -interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_compile="no" cross_prefix="" -audio_drv_list="default" -block_drv_rw_whitelist="" -block_drv_ro_whitelist="" host_cc="cc" -debug_info="yes" -lto="false" stack_protector="" safe_stack="" use_containers="yes" @@ -293,69 +269,36 @@ EXTRA_CXXFLAGS="" EXTRA_OBJCFLAGS="" EXTRA_LDFLAGS="" -xen_ctrl_version="$default_feature" -vhost_kernel="$default_feature" -vhost_net="$default_feature" -vhost_crypto="$default_feature" -vhost_scsi="$default_feature" -vhost_vsock="$default_feature" -vhost_user="no" -vhost_user_fs="$default_feature" -vhost_vdpa="$default_feature" -rdma="$default_feature" -pvrdma="$default_feature" debug_tcg="no" -debug="no" sanitizers="no" tsan="no" -fortify_source="$default_feature" -gcov="no" +fortify_source="yes" EXESUF="" modules="no" -module_upgrades="no" prefix="/usr/local" qemu_suffix="qemu" softmmu="yes" linux_user="" bsd_user="" -pkgversion="" pie="" -trace_backends="log" -trace_file="trace" -opengl="$default_feature" coroutine="" -tls_priority="NORMAL" plugins="$default_feature" -secret_keyring="$default_feature" meson="" -meson_args="" ninja="" -gio="$default_feature" +bindir="bin" skip_meson=no +vfio_user_server="disabled" # The following Meson options are handled manually (still they # are included in the automatically generated help message) # 1. Track which submodules are needed -if test "$default_feature" = no ; then - capstone="disabled" - slirp="disabled" -else - capstone="auto" - slirp="auto" -fi fdt="auto" -# 2. Support --with/--without option -default_devices="true" - -# 3. Automatically enable/disable other options -tcg="enabled" +# 2. Automatically enable/disable other options +tcg="auto" cfi="false" -# 4. Detection partly done in configure -xen=${default_feature:+disabled} - # parse CC options second for opt do optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') @@ -380,26 +323,21 @@ for opt do ;; --extra-ldflags=*) EXTRA_LDFLAGS="$EXTRA_LDFLAGS $optarg" ;; - --enable-debug-info) debug_info="yes" - ;; - --disable-debug-info) debug_info="no" - ;; --cross-cc-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --cross-cc-FOO option" ;; --cross-cc-cflags-*) cc_arch=${opt#--cross-cc-cflags-}; cc_arch=${cc_arch%%=*} eval "cross_cc_cflags_${cc_arch}=\$optarg" - cross_cc_vars="$cross_cc_vars cross_cc_cflags_${cc_arch}" ;; --cross-cc-*) cc_arch=${opt#--cross-cc-}; cc_arch=${cc_arch%%=*} - cc_archs="$cc_archs $cc_arch" eval "cross_cc_${cc_arch}=\$optarg" - cross_cc_vars="$cross_cc_vars cross_cc_${cc_arch}" + ;; + --cross-prefix-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --cross-prefix-FOO option" + ;; + --cross-prefix-*) cc_arch=${opt#--cross-prefix-}; cc_arch=${cc_arch%%=*} + eval "cross_prefix_${cc_arch}=\$optarg" ;; esac done -# OS specific -# Using uname is really, really broken. Once we have the right set of checks -# we can eliminate its usage altogether. # Preferred compiler: # ${CC} (if set) @@ -420,14 +358,15 @@ fi ar="${AR-${cross_prefix}ar}" as="${AS-${cross_prefix}as}" ccas="${CCAS-$cc}" -cpp="${CPP-$cc -E}" objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" ranlib="${RANLIB-${cross_prefix}ranlib}" nm="${NM-${cross_prefix}nm}" smbd="$SMBD" strip="${STRIP-${cross_prefix}strip}" +widl="${WIDL-${cross_prefix}widl}" windres="${WINDRES-${cross_prefix}windres}" +windmc="${WINDMC-${cross_prefix}windmc}" pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}" query_pkg_config() { "${pkg_config_exe}" ${QEMU_PKG_CONFIG_FLAGS} "$@" @@ -441,8 +380,6 @@ sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}" # 2s-complement style results. (Both clang and gcc agree that it # provides these semantics.) QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv" -QEMU_CFLAGS="-Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" QEMU_LDFLAGS= @@ -549,13 +486,6 @@ sunos) QEMU_CFLAGS="-D_XOPEN_SOURCE=600 $QEMU_CFLAGS" # needed for TIOCWIN* defines in termios.h QEMU_CFLAGS="-D__EXTENSIONS__ $QEMU_CFLAGS" - # $(uname -m) returns i86pc even on an x86_64 box, so default based on isainfo - # Note that this check is broken for cross-compilation: if you're - # cross-compiling to one of these OSes then you'll need to specify - # the correct CPU with the --cpu option. - if test -z "$cpu" && test "$(isainfo -k)" = "amd64"; then - cpu="x86_64" - fi ;; haiku) pie="no" @@ -563,7 +493,6 @@ haiku) ;; linux) linux="yes" - vhost_user=${default_feature:-yes} ;; esac @@ -611,16 +540,21 @@ elif check_define __aarch64__ ; then elif check_define __loongarch64 ; then cpu="loongarch64" else + # Using uname is really broken, but it is just a fallback for architectures + # that are going to use TCI anyway cpu=$(uname -m) + echo "WARNING: unrecognized host CPU, proceeding with 'uname -m' output '$cpu'" fi -# Normalise host CPU name, set multilib cflags +# Normalise host CPU name and set multilib cflags. The canonicalization +# isn't really necessary, because the architectures that we check for +# should not hit the 'uname -m' case, but better safe than sorry. # Note that this case should only have supported host CPUs, not guests. case "$cpu" in armv*b|armv*l|arm) cpu="arm" ;; - i386|i486|i586|i686|i86pc|BePC) + i386|i486|i586|i686) cpu="i386" CPU_CFLAGS="-m32" ;; x32) @@ -695,16 +629,35 @@ if test "$mingw32" = "yes" ; then EXESUF=".exe" # MinGW needs -mthreads for TLS and macro _MT. CONFIGURE_CFLAGS="-mthreads $CONFIGURE_CFLAGS" - write_c_skeleton; prefix="/qemu" + bindir="" qemu_suffix="" fi werror="" -. $source_path/scripts/meson-buildoptions.sh +meson_option_build_array() { + printf '[' + (if test "$targetos" = windows; then + IFS=\; + else + IFS=: + fi + for e in $1; do + printf '"""' + # backslash escape any '\' and '"' characters + printf "%s" "$e" | sed -e 's/\([\"]\)/\\\1/g' + printf '""",' + done) + printf ']\n' +} + +. "$source_path/scripts/meson-buildoptions.sh" meson_options= +meson_option_add() { + meson_options="$meson_options $(quote_sh "$1")" +} meson_option_parse() { meson_options="$meson_options $(_meson_option_parse "$@")" if test $? -eq 1; then @@ -719,12 +672,10 @@ 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" ;; - --interp-prefix=*) interp_prefix="$optarg" - ;; --cross-prefix=*) ;; --cc=*) @@ -733,8 +684,6 @@ for opt do ;; --cxx=*) ;; - --iasl=*) iasl="$optarg" - ;; --objcc=*) objcc="$optarg" ;; --make=*) make="$optarg" @@ -743,8 +692,6 @@ for opt do ;; --python=*) python="$optarg" ; explicit_python=yes ;; - --sphinx-build=*) sphinx_build="$optarg" - ;; --skip-meson) skip_meson=yes ;; --meson=*) meson="$optarg" @@ -761,11 +708,13 @@ for opt do ;; --extra-ldflags=*) ;; - --enable-debug-info) + --cross-cc-*) ;; - --disable-debug-info) + --cross-prefix-*) ;; - --cross-cc-*) + --enable-debug-info) meson_option_add -Ddebug=true + ;; + --disable-debug-info) meson_option_add -Ddebug=false ;; --enable-modules) modules="yes" @@ -773,10 +722,6 @@ for opt do --disable-modules) modules="no" ;; - --disable-module-upgrades) module_upgrades="no" - ;; - --enable-module-upgrades) module_upgrades="yes" - ;; --cpu=*) ;; --target-list=*) target_list="$optarg" @@ -789,11 +734,9 @@ for opt do error_exit "Can't mix --target-list-exclude with --target-list" fi ;; - --with-trace-file=*) trace_file="$optarg" - ;; - --with-default-devices) default_devices="true" + --with-default-devices) meson_option_add -Ddefault_devices=true ;; - --without-default-devices) default_devices="false" + --without-default-devices) meson_option_add -Ddefault_devices=false ;; --with-devices-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --with-devices-FOO option" ;; @@ -809,36 +752,14 @@ for opt do ;; --without-default-features) # processed above ;; - --enable-gcov) gcov="yes" - ;; --static) static="yes" QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS" ;; - --mandir=*) mandir="$optarg" - ;; --bindir=*) bindir="$optarg" ;; - --libdir=*) libdir="$optarg" - ;; - --libexecdir=*) libexecdir="$optarg" - ;; - --includedir=*) includedir="$optarg" - ;; - --datadir=*) datadir="$optarg" - ;; --with-suffix=*) qemu_suffix="$optarg" ;; - --docdir=*) docdir="$optarg" - ;; - --localedir=*) localedir="$optarg" - ;; - --sysconfdir=*) sysconfdir="$optarg" - ;; - --localstatedir=*) local_statedir="$optarg" - ;; - --firmwarepath=*) firmwarepath="$optarg" - ;; --host=*|--build=*|\ --disable-dependency-tracking|\ --sbindir=*|--sharedstatedir=*|\ @@ -849,12 +770,6 @@ for opt do # configure to be used by RPM and similar macros that set # lots of directory switches by default. ;; - --audio-drv-list=*) audio_drv_list="$optarg" - ;; - --block-drv-rw-whitelist=*|--block-drv-whitelist=*) block_drv_rw_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') - ;; - --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') - ;; --enable-debug-tcg) debug_tcg="yes" ;; --disable-debug-tcg) debug_tcg="no" @@ -863,7 +778,7 @@ for opt do # Enable debugging options that aren't excessively noisy debug_tcg="yes" meson_option_parse --enable-debug-mutex "" - debug="yes" + meson_option_add -Doptimization=0 fortify_source="no" ;; --enable-sanitizers) sanitizers="yes" @@ -874,18 +789,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-xen) xen="disabled" - ;; - --enable-xen) xen="enabled" - ;; --disable-tcg) tcg="disabled" plugins="no" ;; @@ -916,10 +819,6 @@ for opt do ;; --disable-werror) werror="no" ;; - --enable-lto) lto="true" - ;; - --disable-lto) lto="false" - ;; --enable-stack-protector) stack_protector="yes" ;; --disable-stack-protector) stack_protector="no" @@ -930,7 +829,7 @@ for opt do ;; --enable-cfi) cfi="true"; - lto="true"; + meson_option_add -Db_lto=true ;; --disable-cfi) cfi="false" ;; @@ -942,75 +841,8 @@ for opt do ;; --enable-fdt=*) fdt="$optarg" ;; - --with-pkgversion=*) pkgversion="$optarg" - ;; --with-coroutine=*) coroutine="$optarg" ;; - --disable-vhost-net) vhost_net="no" - ;; - --enable-vhost-net) vhost_net="yes" - ;; - --disable-vhost-crypto) vhost_crypto="no" - ;; - --enable-vhost-crypto) vhost_crypto="yes" - ;; - --disable-vhost-scsi) vhost_scsi="no" - ;; - --enable-vhost-scsi) vhost_scsi="yes" - ;; - --disable-vhost-vsock) vhost_vsock="no" - ;; - --enable-vhost-vsock) vhost_vsock="yes" - ;; - --disable-vhost-user-fs) vhost_user_fs="no" - ;; - --enable-vhost-user-fs) vhost_user_fs="yes" - ;; - --disable-opengl) opengl="no" - ;; - --enable-opengl) opengl="yes" - ;; - --disable-zlib-test) - ;; - --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) - echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2 - ;; - --enable-vhdx|--disable-vhdx) - echo "$0: $opt is obsolete, VHDX driver is always built" >&2 - ;; - --enable-uuid|--disable-uuid) - echo "$0: $opt is obsolete, UUID support is always built" >&2 - ;; - --tls-priority=*) tls_priority="$optarg" - ;; - --enable-rdma) rdma="yes" - ;; - --disable-rdma) rdma="no" - ;; - --enable-pvrdma) pvrdma="yes" - ;; - --disable-pvrdma) pvrdma="no" - ;; - --disable-vhost-user) vhost_user="no" - ;; - --enable-vhost-user) vhost_user="yes" - ;; - --disable-vhost-vdpa) vhost_vdpa="no" - ;; - --enable-vhost-vdpa) vhost_vdpa="yes" - ;; - --disable-vhost-kernel) vhost_kernel="no" - ;; - --enable-vhost-kernel) vhost_kernel="yes" - ;; - --disable-capstone) capstone="disabled" - ;; - --enable-capstone) capstone="enabled" - ;; - --enable-capstone=git) capstone="internal" - ;; - --enable-capstone=*) capstone="$optarg" - ;; --with-git=*) git="$optarg" ;; --with-git-submodules=*) @@ -1030,30 +862,12 @@ for opt do ;; --gdb=*) gdb_bin="$optarg" ;; - --enable-keyring) secret_keyring="yes" + --enable-vfio-user-server) vfio_user_server="enabled" ;; - --disable-keyring) secret_keyring="no" - ;; - --enable-gio) gio=yes - ;; - --disable-gio) gio=no - ;; - # backwards compatibility options - --enable-trace-backend=*) meson_option_parse "--enable-trace-backends=$optarg" "$optarg" - ;; - --disable-blobs) meson_option_parse --disable-install-blobs "" - ;; - --enable-tcmalloc) meson_option_parse --enable-malloc=tcmalloc tcmalloc - ;; - --enable-jemalloc) meson_option_parse --enable-malloc=jemalloc jemalloc + --disable-vfio-user-server) vfio_user_server="disabled" ;; # everything else has the same name in configure and meson - --enable-* | --disable-*) meson_option_parse "$opt" "$optarg" - ;; - *) - echo "ERROR: unknown option $opt" - echo "Try '$0 --help' for more information" - exit 1 + --*) meson_option_parse "$opt" "$optarg" ;; esac done @@ -1100,33 +914,11 @@ case $git_submodules_action in ;; esac -libdir="${libdir:-$prefix/lib}" -libexecdir="${libexecdir:-$prefix/libexec}" -includedir="${includedir:-$prefix/include}" - -if test "$mingw32" = "yes" ; then - bindir="${bindir:-$prefix}" -else - bindir="${bindir:-$prefix/bin}" -fi -mandir="${mandir:-$prefix/share/man}" -datadir="${datadir:-$prefix/share}" -docdir="${docdir:-$prefix/share/doc}" -sysconfdir="${sysconfdir:-$prefix/etc}" -local_statedir="${local_statedir:-$prefix/var}" -firmwarepath="${firmwarepath:-$datadir/qemu-firmware}" -localedir="${localedir:-$datadir/locale}" - -if eval test -z "\${cross_cc_$cpu}"; then - eval "cross_cc_${cpu}=\$cc" - cross_cc_vars="$cross_cc_vars cross_cc_${cpu}" -fi - 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" @@ -1136,7 +928,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 @@ -1166,8 +958,6 @@ Options: [defaults in brackets after descriptions] Standard options: --help print this message --prefix=PREFIX install in PREFIX [$prefix] - --interp-prefix=PREFIX where to find shared libraries, etc. - use %M for cpu name [$interp_prefix] --target-list=LIST set target list (default: build all) $(echo Available targets: $default_target_list | \ fold -s -w 53 | sed -e 's/^/ /') @@ -1176,7 +966,6 @@ $(echo Available targets: $default_target_list | \ Advanced options (experts only): --cross-prefix=PREFIX use PREFIX for compile tools, PREFIX can be blank [$cross_prefix] --cc=CC use C compiler CC [$cc] - --iasl=IASL use ACPI compiler IASL [$iasl] --host-cc=CC use C compiler CC [$host_cc] for code run at build time --cxx=CXX use C++ compiler CXX [$cxx] @@ -1187,9 +976,9 @@ Advanced options (experts only): --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS --cross-cc-ARCH=CC use compiler when building ARCH guest test cases --cross-cc-cflags-ARCH= use compiler flags when building ARCH guest tests + --cross-prefix-ARCH=PREFIX cross compiler prefix when building ARCH guest test cases --make=MAKE use specified make [$make] --python=PYTHON use specified python [$python] - --sphinx-build=SPHINX use specified sphinx-build [$sphinx_build] --meson=MESON use specified meson [$meson] --ninja=NINJA use specified ninja [$ninja] --smbd=SMBD use specified smbd [$smbd] @@ -1198,19 +987,8 @@ Advanced options (experts only): --with-git-submodules=validate fail if git submodules are not up to date --with-git-submodules=ignore do not update or check git submodules (default if no .git dir) --static enable static build [$static] - --mandir=PATH install man pages in PATH - --datadir=PATH install firmware in PATH/$qemu_suffix - --localedir=PATH install translation in PATH/$qemu_suffix - --docdir=PATH install documentation in PATH/$qemu_suffix --bindir=PATH install binaries in PATH - --libdir=PATH install libraries in PATH - --libexecdir=PATH install helper binaries in PATH - --sysconfdir=PATH install config in PATH/$qemu_suffix - --localstatedir=PATH install local state in PATH (set at runtime on win32) - --firmwarepath=PATH search PATH for firmware files - --efi-aarch64=PATH PATH of efi file to use for aarch64 VMs. --with-suffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir/docdir [$qemu_suffix] - --with-pkgversion=VERS use specified string as sub-version of the package --without-default-features default all --enable-* options to "disabled" --without-default-devices do not include any device that is not needed to start the emulator (only use if you are including @@ -1221,21 +999,9 @@ Advanced options (experts only): --enable-tsan enable thread sanitizer --disable-werror disable compilation abort on warning --disable-stack-protector disable compiler-provided stack protection - --audio-drv-list=LIST set audio drivers to try if -audiodev is not used - --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L - --block-drv-rw-whitelist=L - set block driver read-write whitelist - (by default affects only QEMU, not tools like qemu-img) - --block-drv-ro-whitelist=L - set block driver read-only whitelist - (by default affects only QEMU, not tools like qemu-img) - --with-trace-file=NAME Full PATH,NAME of file to store traces - Default:trace- --cpu=CPU Build for host CPU [$cpu] --with-coroutine=BACKEND coroutine backend. Supported options: ucontext, sigaltstack, windows - --enable-gcov enable test coverage analysis with gcov - --tls-priority default TLS protocol/cipher priority string --enable-plugins enable plugins via shared library loading --disable-containers don't use containers for cross-building @@ -1249,23 +1015,10 @@ cat << EOF bsd-user all BSD usermode emulation targets pie Position Independent Executables modules modules support (non-Windows) - module-upgrades try to load modules from alternate paths for upgrades debug-tcg TCG debugging (default is disabled) debug-info debugging information - lto Enable Link-Time Optimization. safe-stack SafeStack Stack Smash Protection. Depends on clang/llvm >= 3.7 and requires coroutine backend ucontext. - rdma Enable RDMA-based migration - pvrdma Enable PVRDMA support - vhost-net vhost-net kernel acceleration support - vhost-vsock virtio sockets device support - vhost-scsi vhost-scsi kernel target support - vhost-crypto vhost-user-crypto backend support - vhost-kernel vhost kernel backend support - vhost-user vhost-user backend support - vhost-vdpa vhost-vdpa kernel backend support - opengl opengl support - gio libgio support NOTE: The object files are built at the place where configure is launched EOF @@ -1273,7 +1026,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 @@ -1291,16 +1044,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 @@ -1416,6 +1166,11 @@ fi # just silently disable some features, so it's too error prone. warn_flags= +add_to warn_flags -Wundef +add_to warn_flags -Wwrite-strings +add_to warn_flags -Wmissing-prototypes +add_to warn_flags -Wstrict-prototypes +add_to warn_flags -Wredundant-decls add_to warn_flags -Wold-style-declaration add_to warn_flags -Wold-style-definition add_to warn_flags -Wtype-limits @@ -1428,6 +1183,7 @@ add_to warn_flags -Wnested-externs add_to warn_flags -Wendif-labels add_to warn_flags -Wexpansion-to-defined add_to warn_flags -Wimplicit-fallthrough=2 +add_to warn_flags -Wmissing-format-attribute nowarn_flags= add_to nowarn_flags -Wno-initializer-overrides @@ -1437,6 +1193,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" @@ -1477,7 +1234,7 @@ if test "$stack_protector" != "no"; then cat > $TMPC << EOF int main(int argc, char *argv[]) { - char arr[64], *p = arr, *c = argv[0]; + char arr[64], *p = arr, *c = argv[argc - 1]; while (*c) { *p++ = *c++; } @@ -1522,11 +1279,6 @@ if test "$modules" = "yes" && test "$mingw32" = "yes" ; then error_exit "Modules are not available for Windows" fi -# module_upgrades is only reasonable if modules are enabled -if test "$modules" = "no" && test "$module_upgrades" = "yes" ; then - error_exit "Can't enable module-upgrades as Modules are not enabled" -fi - # Static linking is not possible with plugins, modules or PIE if test "$static" = "yes" ; then if test "$modules" = "yes" ; then @@ -1551,27 +1303,24 @@ static THREAD int tls_var; int main(void) { return tls_var; } EOF -# Check we support -fno-pie and -no-pie first; we will need the former for -# building ROMs, and both for everything if --disable-pie is passed. -if compile_prog "-Werror -fno-pie" "-no-pie"; then - CFLAGS_NOPIE="-fno-pie" - LDFLAGS_NOPIE="-no-pie" -fi - +# 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. 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" + QEMU_CFLAGS="-fno-pie -no-pie $QEMU_CFLAGS" fi elif test "$pie" = "no"; then - CONFIGURE_CFLAGS="$CFLAGS_NOPIE $CONFIGURE_CFLAGS" - CONFIGURE_LDFLAGS="$LDFLAGS_NOPIE $CONFIGURE_LDFLAGS" + if compile_prog "-Werror -fno-pie" "-no-pie"; then + CONFIGURE_CFLAGS="-fno-pie $CONFIGURE_CFLAGS" + CONFIGURE_LDFLAGS="-no-pie $CONFIGURE_LDFLAGS" + QEMU_CFLAGS="-fno-pie -no-pie $QEMU_CFLAGS" + fi elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS" CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS" @@ -1583,12 +1332,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 @@ -1614,11 +1357,6 @@ EOF fi fi -if test "$tcg" = "enabled"; then - git_submodules="$git_submodules tests/fp/berkeley-testfloat-3" - git_submodules="$git_submodules tests/fp/berkeley-softfloat-3" -fi - if test -z "${target_list+xxx}" ; then default_targets=yes for target in $default_target_list; do @@ -1649,91 +1387,44 @@ case " $target_list " in ;; esac -feature_not_found() { - feature=$1 - remedy=$2 +if test "$tcg" = "auto"; then + if test -z "$target_list"; then + tcg="disabled" + else + tcg="enabled" + fi +fi - error_exit "User requested feature $feature" \ - "configure was not able to find it." \ - "$remedy" -} +if test "$tcg" = "enabled"; then + git_submodules="$git_submodules tests/fp/berkeley-testfloat-3" + git_submodules="$git_submodules tests/fp/berkeley-softfloat-3" +fi -# --- +########################################## # big/little endian test cat > $TMPC << EOF -#include -short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, }; -short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, }; -int main(int argc, char *argv[]) -{ - return printf("%s %s\n", (char *)big_endian, (char *)little_endian); -} +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# error LITTLE +#endif +int main(void) { return 0; } EOF -if compile_prog ; then - if strings -a $TMPE | grep -q BiGeNdIaN ; then - bigendian="yes" - elif strings -a $TMPE | grep -q LiTtLeEnDiAn ; then - bigendian="no" - else - echo big/little test failed - exit 1 - fi +if ! compile_prog ; then + bigendian="no" else + cat > $TMPC << EOF +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# error BIG +#endif +int main(void) { return 0; } +EOF + + if ! compile_prog ; then + bigendian="yes" + else echo big/little test failed exit 1 -fi - -######################################### -# vhost interdependencies and host support - -# vhost backends -if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then - error_exit "vhost-user is not available on Windows" -fi -test "$vhost_vdpa" = "" && vhost_vdpa=$linux -if test "$vhost_vdpa" = "yes" && test "$linux" != "yes"; then - error_exit "vhost-vdpa is only available on Linux" -fi -test "$vhost_kernel" = "" && vhost_kernel=$linux -if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then - error_exit "vhost-kernel is only available on Linux" -fi - -# vhost-kernel devices -test "$vhost_scsi" = "" && vhost_scsi=$vhost_kernel -if test "$vhost_scsi" = "yes" && test "$vhost_kernel" != "yes"; then - error_exit "--enable-vhost-scsi requires --enable-vhost-kernel" -fi -test "$vhost_vsock" = "" && vhost_vsock=$vhost_kernel -if test "$vhost_vsock" = "yes" && test "$vhost_kernel" != "yes"; then - error_exit "--enable-vhost-vsock requires --enable-vhost-kernel" -fi - -# vhost-user backends -test "$vhost_net_user" = "" && vhost_net_user=$vhost_user -if test "$vhost_net_user" = "yes" && test "$vhost_user" = "no"; then - error_exit "--enable-vhost-net-user requires --enable-vhost-user" -fi -test "$vhost_crypto" = "" && vhost_crypto=$vhost_user -if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then - error_exit "--enable-vhost-crypto requires --enable-vhost-user" -fi -test "$vhost_user_fs" = "" && vhost_user_fs=$vhost_user -if test "$vhost_user_fs" = "yes" && test "$vhost_user" = "no"; then - error_exit "--enable-vhost-user-fs requires --enable-vhost-user" -fi -#vhost-vdpa backends -test "$vhost_net_vdpa" = "" && vhost_net_vdpa=$vhost_vdpa -if test "$vhost_net_vdpa" = "yes" && test "$vhost_vdpa" = "no"; then - error_exit "--enable-vhost-net-vdpa requires --enable-vhost-vdpa" -fi - -# OR the vhost-kernel, vhost-vdpa and vhost-user values for simplicity -if test "$vhost_net" = ""; then - test "$vhost_net_user" = "yes" && vhost_net=yes - test "$vhost_net_vdpa" = "yes" && vhost_net=yes - test "$vhost_kernel" = "yes" && vhost_net=yes + fi fi ########################################## @@ -1744,614 +1435,99 @@ if ! has "$pkg_config_exe"; then fi ########################################## -# xen probe - -if test "$xen" != "disabled" ; then - # Check whether Xen library path is specified via --extra-ldflags to avoid - # overriding this setting with pkg-config output. If not, try pkg-config - # to obtain all needed flags. - - if ! echo $EXTRA_LDFLAGS | grep tools/libxc > /dev/null && \ - $pkg_config --exists xencontrol ; then - xen_ctrl_version="$(printf '%d%02d%02d' \ - $($pkg_config --modversion xencontrol | sed 's/\./ /g') )" - xen=enabled - xen_pc="xencontrol xenstore xenforeignmemory xengnttab" - xen_pc="$xen_pc xenevtchn xendevicemodel" - if $pkg_config --exists xentoolcore; then - xen_pc="$xen_pc xentoolcore" - fi - xen_cflags="$($pkg_config --cflags $xen_pc)" - xen_libs="$($pkg_config --libs $xen_pc)" - else +# glib support probe - xen_libs="-lxenstore -lxenctrl" - xen_stable_libs="-lxenforeignmemory -lxengnttab -lxenevtchn" +# When bumping glib_req_ver, please check also whether we should increase +# the _WIN32_WINNT setting in osdep.h according to the value from glib +glib_req_ver=2.56 +glib_modules=gthread-2.0 +if test "$modules" = yes; then + glib_modules="$glib_modules gmodule-export-2.0" +elif test "$plugins" = "yes"; then + glib_modules="$glib_modules gmodule-no-export-2.0" +fi - # First we test whether Xen headers and libraries are available. - # If no, we are done and there is no Xen support. - # If yes, more tests are run to detect the Xen version. +for i in $glib_modules; do + if $pkg_config --atleast-version=$glib_req_ver $i; then + glib_cflags=$($pkg_config --cflags $i) + glib_libs=$($pkg_config --libs $i) + else + error_exit "glib-$glib_req_ver $i is required to compile QEMU" + fi +done - # Xen (any) - cat > $TMPC < -int main(void) { - return 0; -} -EOF - if ! compile_prog "" "$xen_libs" ; then - # Xen not found - if test "$xen" = "enabled" ; then - feature_not_found "xen" "Install xen devel" - fi - xen=disabled - - # Xen unstable - elif - cat > $TMPC < -#include -int main(void) { - xendevicemodel_handle *xd; - xenforeignmemory_handle *xfmem; +glib_bindir="$($pkg_config --variable=bindir glib-2.0)" +if test -z "$glib_bindir" ; then + glib_bindir="$($pkg_config --variable=prefix glib-2.0)"/bin +fi - xd = xendevicemodel_open(0, 0); - xendevicemodel_pin_memory_cacheattr(xd, 0, 0, 0, 0); +# This workaround is required due to a bug in pkg-config file for glib as it +# doesn't define GLIB_STATIC_COMPILATION for pkg-config --static - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map_resource(xfmem, 0, 0, 0, 0, 0, NULL, 0, 0); +if test "$static" = yes && test "$mingw32" = yes; then + glib_cflags="-DGLIB_STATIC_COMPILATION $glib_cflags" +fi - return 0; -} -EOF - compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs -lxentoolcore" - then - xen_stable_libs="-lxendevicemodel $xen_stable_libs -lxentoolcore" - xen_ctrl_version=41100 - xen=enabled - elif - cat > $TMPC < -#include -int main(void) { - xenforeignmemory_handle *xfmem; +# Sanity check that the current size_t matches the +# size that glib thinks it should be. This catches +# problems on multi-arch where people try to build +# 32-bit QEMU while pointing at 64-bit glib headers +cat > $TMPC < +#include - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map2(xfmem, 0, 0, 0, 0, 0, 0, 0); - xentoolcore_restrict_all(0); +#define QEMU_BUILD_BUG_ON(x) \ + typedef char qemu_build_bug_on[(x)?-1:1] __attribute__((unused)); - return 0; +int main(void) { + QEMU_BUILD_BUG_ON(sizeof(size_t) != GLIB_SIZEOF_SIZE_T); + return 0; } EOF - compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs -lxentoolcore" - then - xen_stable_libs="-lxendevicemodel $xen_stable_libs -lxentoolcore" - xen_ctrl_version=41000 - xen=enabled - elif - cat > $TMPC < -int main(void) { - xendevicemodel_handle *xd; - xd = xendevicemodel_open(0, 0); - xendevicemodel_close(xd); +if ! compile_prog "$glib_cflags" "$glib_libs" ; then + error_exit "sizeof(size_t) doesn't match GLIB_SIZEOF_SIZE_T."\ + "You probably need to set PKG_CONFIG_LIBDIR"\ + "to point to the right pkg-config files for your"\ + "build target" +fi - return 0; +# Silence clang warnings triggered by glib < 2.57.2 +cat > $TMPC << EOF +#include +typedef struct Foo { + int i; +} Foo; +static void foo_free(Foo *f) +{ + g_free(f); } +G_DEFINE_AUTOPTR_CLEANUP_FUNC(Foo, foo_free) +int main(void) { return 0; } EOF - compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs" - then - xen_stable_libs="-lxendevicemodel $xen_stable_libs" - xen_ctrl_version=40900 - xen=enabled - elif - cat > $TMPC < -#include -#include -#include -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc = NULL; - xenforeignmemory_handle *xfmem; - xenevtchn_handle *xe; - xengnttab_handle *xg; - xengnttab_grant_copy_segment_t* seg = NULL; - - xs_daemon_open(); +if ! compile_prog "$glib_cflags -Werror" "$glib_libs" ; then + if cc_has_warning_flag "-Wno-unused-function"; then + glib_cflags="$glib_cflags -Wno-unused-function" + CONFIGURE_CFLAGS="$CONFIGURE_CFLAGS -Wno-unused-function" + fi +fi - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); +########################################## +# fdt probe - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); +case "$fdt" in + auto | enabled | internal) + # Simpler to always update submodule, even if not needed. + git_submodules="${git_submodules} dtc" + ;; +esac - xe = xenevtchn_open(0, 0); - xenevtchn_fd(xe); +########################################## +# check and set a backend for coroutine - xg = xengnttab_open(0, 0); - xengnttab_grant_copy(xg, 0, seg); - - return 0; -} -EOF - compile_prog "" "$xen_libs $xen_stable_libs" - then - xen_ctrl_version=40800 - xen=enabled - elif - cat > $TMPC < -#include -#include -#include -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc = NULL; - xenforeignmemory_handle *xfmem; - xenevtchn_handle *xe; - xengnttab_handle *xg; - - xs_daemon_open(); - - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); - - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); - - xe = xenevtchn_open(0, 0); - xenevtchn_fd(xe); - - xg = xengnttab_open(0, 0); - xengnttab_map_grant_ref(xg, 0, 0, 0); - - return 0; -} -EOF - compile_prog "" "$xen_libs $xen_stable_libs" - then - xen_ctrl_version=40701 - xen=enabled - - # Xen 4.6 - elif - cat > $TMPC < -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc; - xs_daemon_open(); - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_gnttab_open(NULL, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); - xc_reserved_device_memory_map(xc, 0, 0, 0, 0, NULL, 0); - return 0; -} -EOF - compile_prog "" "$xen_libs" - then - xen_ctrl_version=40600 - xen=enabled - - # Xen 4.5 - elif - cat > $TMPC < -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc; - xs_daemon_open(); - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_gnttab_open(NULL, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, 0, NULL); - return 0; -} -EOF - compile_prog "" "$xen_libs" - then - xen_ctrl_version=40500 - xen=enabled - - elif - cat > $TMPC < -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc; - xs_daemon_open(); - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_gnttab_open(NULL, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - return 0; -} -EOF - compile_prog "" "$xen_libs" - then - xen_ctrl_version=40200 - xen=enabled - - else - if test "$xen" = "enabled" ; then - feature_not_found "xen (unsupported version)" \ - "Install a supported xen (xen 4.2 or newer)" - fi - xen=disabled - fi - - if test "$xen" = enabled; then - if test $xen_ctrl_version -ge 40701 ; then - xen_libs="$xen_libs $xen_stable_libs " - fi - fi - fi -fi - -########################################## -# RDMA needs OpenFabrics libraries -if test "$rdma" != "no" ; then - cat > $TMPC < -int main(void) { return 0; } -EOF - rdma_libs="-lrdmacm -libverbs -libumad" - if compile_prog "" "$rdma_libs" ; then - rdma="yes" - else - if test "$rdma" = "yes" ; then - error_exit \ - " OpenFabrics librdmacm/libibverbs/libibumad not present." \ - " Your options:" \ - " (1) Fast: Install infiniband packages (devel) from your distro." \ - " (2) Cleanest: Install libraries from www.openfabrics.org" \ - " (3) Also: Install softiwarp if you don't have RDMA hardware" - fi - rdma="no" - fi -fi - -########################################## -# PVRDMA detection - -cat > $TMPC < - -int -main(void) -{ - char buf = 0; - void *addr = &buf; - addr = mremap(addr, 0, 1, MREMAP_MAYMOVE | MREMAP_FIXED); - - return 0; -} -EOF - -if test "$rdma" = "yes" ; then - case "$pvrdma" in - "") - if compile_prog "" ""; then - pvrdma="yes" - else - pvrdma="no" - fi - ;; - "yes") - if ! compile_prog "" ""; then - error_exit "PVRDMA is not supported since mremap is not implemented" - fi - pvrdma="yes" - ;; - "no") - pvrdma="no" - ;; - esac -else - if test "$pvrdma" = "yes" ; then - error_exit "PVRDMA requires rdma suppport" - fi - pvrdma="no" -fi - -# Let's see if enhanced reg_mr is supported -if test "$pvrdma" = "yes" ; then - -cat > $TMPC < - -int -main(void) -{ - struct ibv_mr *mr; - struct ibv_pd *pd = NULL; - size_t length = 10; - uint64_t iova = 0; - int access = 0; - void *addr = NULL; - - mr = ibv_reg_mr_iova(pd, addr, length, iova, access); - - ibv_dereg_mr(mr); - - return 0; -} -EOF - if ! compile_prog "" "-libverbs"; then - QEMU_CFLAGS="$QEMU_CFLAGS -DLEGACY_RDMA_REG_MR" - fi -fi - -########################################## -# glib support probe - -glib_req_ver=2.56 -glib_modules=gthread-2.0 -if test "$modules" = yes; then - glib_modules="$glib_modules gmodule-export-2.0" -elif test "$plugins" = "yes"; then - glib_modules="$glib_modules gmodule-no-export-2.0" -fi - -for i in $glib_modules; do - if $pkg_config --atleast-version=$glib_req_ver $i; then - glib_cflags=$($pkg_config --cflags $i) - glib_libs=$($pkg_config --libs $i) - else - error_exit "glib-$glib_req_ver $i is required to compile QEMU" - fi -done - -# This workaround is required due to a bug in pkg-config file for glib as it -# doesn't define GLIB_STATIC_COMPILATION for pkg-config --static - -if test "$static" = yes && test "$mingw32" = yes; then - glib_cflags="-DGLIB_STATIC_COMPILATION $glib_cflags" -fi - -if ! test "$gio" = "no"; then - pass=no - if $pkg_config --atleast-version=$glib_req_ver gio-2.0; then - gio_cflags=$($pkg_config --cflags gio-2.0) - gio_libs=$($pkg_config --libs gio-2.0) - gdbus_codegen=$($pkg_config --variable=gdbus_codegen gio-2.0) - if ! has "$gdbus_codegen"; then - gdbus_codegen= - fi - # Check that the libraries actually work -- Ubuntu 18.04 ships - # with pkg-config --static --libs data for gio-2.0 that is missing - # -lblkid and will give a link error. - cat > $TMPC < -int main(void) -{ - g_dbus_proxy_new_sync(0, 0, 0, 0, 0, 0, 0, 0); - return 0; -} -EOF - if compile_prog "$gio_cflags" "$gio_libs" ; then - pass=yes - else - pass=no - fi - - if test "$pass" = "yes" && - $pkg_config --atleast-version=$glib_req_ver gio-unix-2.0; then - gio_cflags="$gio_cflags $($pkg_config --cflags gio-unix-2.0)" - gio_libs="$gio_libs $($pkg_config --libs gio-unix-2.0)" - fi - fi - - if test "$pass" = "no"; then - if test "$gio" = "yes"; then - feature_not_found "gio" "Install libgio >= 2.0" - else - gio=no - fi - else - gio=yes - fi -fi - -# Sanity check that the current size_t matches the -# size that glib thinks it should be. This catches -# problems on multi-arch where people try to build -# 32-bit QEMU while pointing at 64-bit glib headers -cat > $TMPC < -#include - -#define QEMU_BUILD_BUG_ON(x) \ - typedef char qemu_build_bug_on[(x)?-1:1] __attribute__((unused)); - -int main(void) { - QEMU_BUILD_BUG_ON(sizeof(size_t) != GLIB_SIZEOF_SIZE_T); - return 0; -} -EOF - -if ! compile_prog "$glib_cflags" "$glib_libs" ; then - error_exit "sizeof(size_t) doesn't match GLIB_SIZEOF_SIZE_T."\ - "You probably need to set PKG_CONFIG_LIBDIR"\ - "to point to the right pkg-config files for your"\ - "build target" -fi - -# Silence clang warnings triggered by glib < 2.57.2 -cat > $TMPC << EOF -#include -typedef struct Foo { - int i; -} Foo; -static void foo_free(Foo *f) -{ - g_free(f); -} -G_DEFINE_AUTOPTR_CLEANUP_FUNC(Foo, foo_free) -int main(void) { return 0; } -EOF -if ! compile_prog "$glib_cflags -Werror" "$glib_libs" ; then - if cc_has_warning_flag "-Wno-unused-function"; then - glib_cflags="$glib_cflags -Wno-unused-function" - CONFIGURE_CFLAGS="$CONFIGURE_CFLAGS -Wno-unused-function" - fi -fi - -########################################## -# SHA command probe for modules -if test "$modules" = yes; then - shacmd_probe="sha1sum sha1 shasum" - for c in $shacmd_probe; do - if has $c; then - shacmd="$c" - break - fi - done - if test "$shacmd" = ""; then - error_exit "one of the checksum commands is required to enable modules: $shacmd_probe" - fi -fi - -########################################## -# fdt probe - -case "$fdt" in - auto | enabled | internal) - # Simpler to always update submodule, even if not needed. - git_submodules="${git_submodules} dtc" - ;; -esac - -########################################## -# opengl probe (for sdl2, gtk) - -if test "$opengl" != "no" ; then - epoxy=no - if $pkg_config epoxy; then - cat > $TMPC << EOF -#include -int main(void) { return 0; } -EOF - if compile_prog "" "" ; then - epoxy=yes - fi - fi - - if test "$epoxy" = "yes" ; then - opengl_cflags="$($pkg_config --cflags epoxy)" - opengl_libs="$($pkg_config --libs epoxy)" - opengl=yes - else - if test "$opengl" = "yes" ; then - feature_not_found "opengl" "Please install epoxy with EGL" - fi - opengl_cflags="" - opengl_libs="" - opengl=no - fi -fi - -# check for usbfs -have_usbfs=no -if test "$linux_user" = "yes"; then - cat > $TMPC << EOF -#include - -#ifndef USBDEVFS_GET_CAPABILITIES -#error "USBDEVFS_GET_CAPABILITIES undefined" -#endif - -#ifndef USBDEVFS_DISCONNECT_CLAIM -#error "USBDEVFS_DISCONNECT_CLAIM undefined" -#endif - -int main(void) -{ - return 0; -} -EOF - if compile_prog "" ""; then - have_usbfs=yes - fi -fi - -########################################## -# capstone - -case "$capstone" in - auto | enabled | internal) - # Simpler to always update submodule, even if not needed. - git_submodules="${git_submodules} capstone" - ;; -esac - -########################################## -# check and set a backend for coroutine - -# We prefer ucontext, but it's not always possible. The fallback -# is sigcontext. On Windows the only valid backend is the Windows -# specific one. +# We prefer ucontext, but it's not always possible. The fallback +# is sigcontext. On Windows the only valid backend is the Windows +# specific one. ucontext_works=no if test "$darwin" != "yes"; then @@ -2387,7 +1563,7 @@ else ;; ucontext) if test "$ucontext_works" != "yes"; then - feature_not_found "ucontext" + error_exit "'ucontext' backend requested but makecontext not available" fi ;; sigaltstack) @@ -2407,7 +1583,7 @@ fi if test "$safe_stack" = "yes"; then cat > $TMPC << EOF -int main(int argc, char *argv[]) +int main(void) { #if ! __has_feature(safe_stack) #error SafeStack Disabled @@ -2429,7 +1605,7 @@ EOF fi else cat > $TMPC << EOF -int main(int argc, char *argv[]) +int main(void) { #if defined(__has_feature) #if __has_feature(safe_stack) @@ -2475,7 +1651,7 @@ static const int Z = 1; #define TAUT(X) ((X) == Z) #define PAREN(X, Y) (X == Y) #define ID(X) (X) -int main(int argc, char *argv[]) +int main(void) { int x = 0, y = 0; x = ID(x); @@ -2577,49 +1753,427 @@ EOF fi ########################################## -# check for slirp +# functions to probe cross compilers + +container="no" +if test $use_containers = "yes" && (has "docker" || has "podman"); then + 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 -case "$slirp" in - auto | enabled | internal) - # Simpler to always update submodule, even if not needed. - git_submodules="${git_submodules} slirp" - ;; -esac +# cross compilers defaults, can be overridden with --cross-cc-ARCH +: ${cross_prefix_aarch64="aarch64-linux-gnu-"} +: ${cross_prefix_aarch64_be="$cross_prefix_aarch64"} +: ${cross_prefix_alpha="alpha-linux-gnu-"} +: ${cross_prefix_arm="arm-linux-gnueabihf-"} +: ${cross_prefix_armeb="$cross_prefix_arm"} +: ${cross_prefix_hexagon="hexagon-unknown-linux-musl-"} +: ${cross_prefix_loongarch64="loongarch64-unknown-linux-gnu-"} +: ${cross_prefix_hppa="hppa-linux-gnu-"} +: ${cross_prefix_i386="i686-linux-gnu-"} +: ${cross_prefix_m68k="m68k-linux-gnu-"} +: ${cross_prefix_microblaze="microblaze-linux-musl-"} +: ${cross_prefix_mips64el="mips64el-linux-gnuabi64-"} +: ${cross_prefix_mips64="mips64-linux-gnuabi64-"} +: ${cross_prefix_mipsel="mipsel-linux-gnu-"} +: ${cross_prefix_mips="mips-linux-gnu-"} +: ${cross_prefix_nios2="nios2-linux-gnu-"} +: ${cross_prefix_ppc="powerpc-linux-gnu-"} +: ${cross_prefix_ppc64="powerpc64-linux-gnu-"} +: ${cross_prefix_ppc64le="$cross_prefix_ppc64"} +: ${cross_prefix_riscv64="riscv64-linux-gnu-"} +: ${cross_prefix_s390x="s390x-linux-gnu-"} +: ${cross_prefix_sh4="sh4-linux-gnu-"} +: ${cross_prefix_sparc64="sparc64-linux-gnu-"} +: ${cross_prefix_sparc="$cross_prefix_sparc64"} +: ${cross_prefix_x86_64="x86_64-linux-gnu-"} + +: ${cross_cc_aarch64_be="$cross_cc_aarch64"} +: ${cross_cc_cflags_aarch64_be="-mbig-endian"} +: ${cross_cc_armeb="$cross_cc_arm"} +: ${cross_cc_cflags_armeb="-mbig-endian"} +: ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"} +: ${cross_cc_cflags_hexagon="-mv67 -O2 -static"} +: ${cross_cc_cflags_i386="-m32"} +: ${cross_cc_cflags_ppc="-m32 -mbig-endian"} +: ${cross_cc_cflags_ppc64="-m64 -mbig-endian"} +: ${cross_cc_ppc64le="$cross_cc_ppc64"} +: ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"} +: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} +: ${cross_cc_sparc="$cross_cc_sparc64"} +: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} +: ${cross_cc_cflags_x86_64="-m64"} + +compute_target_variable() { + eval "$2=" + if eval test -n "\"\${cross_prefix_$1}\""; then + if eval has "\"\${cross_prefix_$1}\$3\""; then + eval "$2=\"\${cross_prefix_$1}\$3\"" + fi + fi +} -########################################## -# check for usable __NR_keyctl syscall +have_target() { + for i; do + case " $target_list " in + *" $i "*) return 0;; + *) ;; + esac + done + return 1 +} -if test "$linux" = "yes" ; then +# probe_target_compiler TARGET +# +# Look for a compiler for the given target, either native or cross. +# Set variables target_* if a compiler is found, and container_cross_* +# if a Docker-based cross-compiler image is known for the target. +# Set got_cross_cc to yes/no depending on whether a non-container-based +# compiler was found. +# +# If TARGET is a user-mode emulation target, also set build_static to +# "y" if static linking is possible. +# +probe_target_compiler() { + # reset all output variables + got_cross_cc=no + container_image= + container_hosts= + container_cross_cc= + container_cross_ar= + container_cross_as= + container_cross_ld= + container_cross_nm= + container_cross_objcopy= + container_cross_ranlib= + container_cross_strip= + + # We shall skip configuring the target compiler if the user didn't + # bother enabling an appropriate guest. This avoids building + # extraneous firmware images and tests. + if test "${target_list#*$1}" = "$1"; then + return 1 + fi - have_keyring=no - cat > $TMPC << EOF -#include -#include -#include -#include -int main(void) { - return syscall(__NR_keyctl, KEYCTL_READ, 0, NULL, NULL, 0); + target_arch=${1%%-*} + case $target_arch in + aarch64) container_hosts="x86_64 aarch64" ;; + alpha) container_hosts=x86_64 ;; + arm) container_hosts="x86_64 aarch64" ;; + cris) container_hosts=x86_64 ;; + hexagon) container_hosts=x86_64 ;; + hppa) container_hosts=x86_64 ;; + i386) container_hosts=x86_64 ;; + loongarch64) container_hosts=x86_64 ;; + m68k) container_hosts=x86_64 ;; + microblaze) container_hosts=x86_64 ;; + mips64el) container_hosts=x86_64 ;; + mips64) container_hosts=x86_64 ;; + mipsel) container_hosts=x86_64 ;; + mips) container_hosts=x86_64 ;; + nios2) container_hosts=x86_64 ;; + ppc) container_hosts=x86_64 ;; + ppc64|ppc64le) container_hosts=x86_64 ;; + riscv64) container_hosts=x86_64 ;; + s390x) container_hosts=x86_64 ;; + sh4) container_hosts=x86_64 ;; + sparc64) container_hosts=x86_64 ;; + tricore) container_hosts=x86_64 ;; + x86_64) container_hosts="aarch64 ppc64el x86_64" ;; + xtensa*) container_hosts=x86_64 ;; + esac + + for host in $container_hosts; do + test "$container" != no || continue + test "$host" = "$cpu" || continue + case $target_arch in + aarch64) + # We don't have any bigendian build tools so we only use this for AArch64 + container_image=debian-arm64-cross + container_cross_prefix=aarch64-linux-gnu- + container_cross_cc=${container_cross_prefix}gcc-10 + ;; + alpha) + container_image=debian-alpha-cross + container_cross_prefix=alpha-linux-gnu- + ;; + arm) + # We don't have any bigendian build tools so we only use this for ARM + container_image=debian-armhf-cross + container_cross_prefix=arm-linux-gnueabihf- + ;; + cris) + container_image=fedora-cris-cross + container_cross_prefix=cris-linux-gnu- + ;; + hexagon) + container_image=debian-hexagon-cross + container_cross_prefix=hexagon-unknown-linux-musl- + container_cross_cc=${container_cross_prefix}clang + ;; + hppa) + container_image=debian-hppa-cross + container_cross_prefix=hppa-linux-gnu- + ;; + i386) + container_image=fedora-i386-cross + container_cross_prefix= + ;; + loongarch64) + container_image=debian-loongarch-cross + container_cross_prefix=loongarch64-unknown-linux-gnu- + ;; + m68k) + container_image=debian-m68k-cross + container_cross_prefix=m68k-linux-gnu- + ;; + microblaze) + container_image=debian-microblaze-cross + container_cross_prefix=microblaze-linux-musl- + ;; + mips64el) + container_image=debian-mips64el-cross + container_cross_prefix=mips64el-linux-gnuabi64- + ;; + mips64) + container_image=debian-mips64-cross + container_cross_prefix=mips64-linux-gnuabi64- + ;; + mipsel) + container_image=debian-mipsel-cross + container_cross_prefix=mipsel-linux-gnu- + ;; + mips) + container_image=debian-mips-cross + container_cross_prefix=mips-linux-gnu- + ;; + nios2) + container_image=debian-nios2-cross + container_cross_prefix=nios2-linux-gnu- + ;; + ppc) + container_image=debian-powerpc-test-cross + container_cross_prefix=powerpc-linux-gnu- + container_cross_cc=${container_cross_prefix}gcc-10 + ;; + ppc64|ppc64le) + container_image=debian-powerpc-test-cross + container_cross_prefix=powerpc${target_arch#ppc}-linux-gnu- + container_cross_cc=${container_cross_prefix}gcc-10 + ;; + riscv64) + container_image=debian-riscv64-test-cross + container_cross_prefix=riscv64-linux-gnu- + ;; + s390x) + container_image=debian-s390x-cross + container_cross_prefix=s390x-linux-gnu- + ;; + sh4) + container_image=debian-sh4-cross + container_cross_prefix=sh4-linux-gnu- + ;; + sparc64) + container_image=debian-sparc64-cross + container_cross_prefix=sparc64-linux-gnu- + ;; + tricore) + container_image=debian-tricore-cross + container_cross_prefix=tricore- + container_cross_as=tricore-as + container_cross_ld=tricore-ld + break + ;; + x86_64) + container_image=debian-amd64-cross + container_cross_prefix=x86_64-linux-gnu- + ;; + xtensa*) + container_hosts=x86_64 + container_image=debian-xtensa-cross + + # default to the dc232b cpu + container_cross_prefix=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf- + ;; + esac + : ${container_cross_cc:=${container_cross_prefix}gcc} + : ${container_cross_ar:=${container_cross_prefix}ar} + : ${container_cross_as:=${container_cross_prefix}as} + : ${container_cross_ld:=${container_cross_prefix}ld} + : ${container_cross_nm:=${container_cross_prefix}nm} + : ${container_cross_objcopy:=${container_cross_prefix}objcopy} + : ${container_cross_ranlib:=${container_cross_prefix}ranlib} + : ${container_cross_strip:=${container_cross_prefix}strip} + done + + try=cross + case "$target_arch:$cpu" in + aarch64_be:aarch64 | \ + armeb:arm | \ + i386:x86_64 | \ + mips*:mips64 | \ + ppc*:ppc64 | \ + sparc:sparc64 | \ + "$cpu:$cpu") + try='native cross' ;; + esac + eval "target_cflags=\${cross_cc_cflags_$target_arch}" + for thistry in $try; do + case $thistry in + native) + target_cc=$cc + target_ccas=$ccas + target_ar=$ar + target_as=$as + target_ld=$ld + target_nm=$nm + target_objcopy=$objcopy + target_ranlib=$ranlib + target_strip=$strip + ;; + cross) + target_cc= + if eval test -n "\"\${cross_cc_$target_arch}\""; then + if eval has "\"\${cross_cc_$target_arch}\""; then + eval "target_cc=\"\${cross_cc_$target_arch}\"" + fi + else + compute_target_variable $target_arch target_cc gcc + fi + target_ccas=$target_cc + compute_target_variable $target_arch target_ar ar + compute_target_variable $target_arch target_as as + compute_target_variable $target_arch target_ld ld + compute_target_variable $target_arch target_nm nm + compute_target_variable $target_arch target_objcopy objcopy + compute_target_variable $target_arch target_ranlib ranlib + compute_target_variable $target_arch target_strip strip + ;; + esac + + if test -n "$target_cc"; then + case $target_arch in + i386|x86_64) + if $target_cc --version | grep -qi "clang"; then + continue + fi + ;; + esac + elif test -n "$target_as" && test -n "$target_ld"; then + # Special handling for assembler only targets + case $target in + tricore-softmmu) + build_static= + got_cross_cc=yes + break + ;; + *) + continue + ;; + esac + else + continue + fi + + write_c_skeleton + case $1 in + *-softmmu) + if do_compiler "$target_cc" $target_cflags -o $TMPO -c $TMPC && + do_compiler "$target_cc" $target_cflags -r -nostdlib -o "${TMPDIR1}/${TMPB}2.o" "$TMPO" -lgcc; then + got_cross_cc=yes + break + fi + ;; + *) + if do_compiler "$target_cc" $target_cflags -o $TMPE $TMPC -static ; then + build_static=y + got_cross_cc=yes + break + fi + if do_compiler "$target_cc" $target_cflags -o $TMPE $TMPC ; then + build_static= + got_cross_cc=yes + break + fi + ;; + esac + done + if test $got_cross_cc != yes; then + build_static= + target_cc= + target_ccas= + target_ar= + target_as= + target_ld= + target_nm= + target_objcopy= + target_ranlib= + target_strip= + fi + test -n "$target_cc" } -EOF - if compile_prog "" "" ; then - have_keyring=yes + +write_target_makefile() { + echo "EXTRA_CFLAGS=$target_cflags" + 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 -fi -if test "$secret_keyring" != "no" -then - if test "$have_keyring" = "yes" - then - secret_keyring=yes - else - if test "$secret_keyring" = "yes" - then - error_exit "syscall __NR_keyctl requested, \ -but not implemented on your system" - else - secret_keyring=no - 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 -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 +} + +########################################## +# check for vfio_user_server + +case "$vfio_user_server" in + enabled ) + if test "$git_submodules_action" != "ignore"; then + git_submodules="${git_submodules} subprojects/libvfio-user" + fi + ;; +esac ########################################## # End of CC checks @@ -2627,20 +2181,10 @@ fi write_c_skeleton -if test "$gcov" = "yes" ; then - : -elif test "$fortify_source" = "yes" ; then +if test "$fortify_source" = "yes" ; then QEMU_CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $QEMU_CFLAGS" - debug=no 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" @@ -2667,113 +2211,83 @@ if test "$have_ubsan" = "yes"; then QEMU_LDFLAGS="-fsanitize=undefined $QEMU_LDFLAGS" 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 - -# Use ASLR, no-SEH and DEP if available -if test "$mingw32" = "yes" ; then - flags="--no-seh --nxcompat" +####################################### +# cross-compiled firmware targets - # Disable ASLR for debug builds to allow debugging with gdb - if test "$debug" = "no" ; then - flags="--dynamicbase $flags" +# Set up build tree symlinks that point back into the source tree +# (these can be both files and directories). +# Caution: avoid adding files or directories here using wildcards. This +# will result in problems later if a new file matching the wildcard is +# added to the source tree -- nothing will cause configure to be rerun +# so the build tree will be missing the link back to the new file, and +# tests might fail. Prefer to keep the relevant files in their own +# directory and symlink the directory instead. +LINKS="Makefile" +LINKS="$LINKS pc-bios/optionrom/Makefile" +LINKS="$LINKS pc-bios/s390-ccw/Makefile" +LINKS="$LINKS pc-bios/vof/Makefile" +LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit +LINKS="$LINKS tests/avocado tests/data" +LINKS="$LINKS tests/qemu-iotests/check" +LINKS="$LINKS python" +LINKS="$LINKS contrib/plugins/Makefile " +for f in $LINKS ; do + if [ -e "$source_path/$f" ]; then + mkdir -p "$(dirname ./"$f")" + symlink "$source_path/$f" "$f" fi +done - for flag in $flags; do - if ld_has $flag ; then - QEMU_LDFLAGS="-Wl,$flag $QEMU_LDFLAGS" - fi - done -fi - -# Guest agent Windows MSI package - -if test "$QEMU_GA_MANUFACTURER" = ""; then - QEMU_GA_MANUFACTURER=QEMU -fi -if test "$QEMU_GA_DISTRO" = ""; then - QEMU_GA_DISTRO=Linux -fi -if test "$QEMU_GA_VERSION" = ""; then - QEMU_GA_VERSION=$(cat $source_path/VERSION) -fi - -QEMU_GA_MSI_MINGW_DLL_PATH="$($pkg_config --variable=prefix glib-2.0)/bin" +echo "# Automatically generated by configure - do not modify" > Makefile.prereqs # Mac OS X ships with a broken assembler roms= -if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ +if have_target i386-softmmu x86_64-softmmu && \ 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 "$ld" -verbose 2>&1 | grep -q "^[[:space:]]*$emu[[:space:]]*$"; then - ld_i386_emulation="$emu" - roms="optionrom" - break - fi - done + test "$targetos" != "haiku" && \ + 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 -# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900 -# or -march=z10 (which is the lowest architecture level that Clang supports) -if test "$cpu" = "s390x" ; then +if have_target ppc-softmmu ppc64-softmmu && \ + 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 + echo "SRC_DIR=$source_path/pc-bios/vof" >> $config_mak + write_target_makefile >> $config_mak +fi + +# Only build s390-ccw bios if the compiler has -march=z900 or -march=z10 +# (which is the lowest architecture level that Clang supports) +if have_target s390x-softmmu && probe_target_compiler s390x-softmmu; then write_c_skeleton - compile_prog "-march=z900" "" + do_compiler "$target_cc" $target_cc_cflags -march=z900 -o $TMPO -c $TMPC has_z900=$? - if [ $has_z900 = 0 ] || compile_object "-march=z10 -msoft-float -Werror"; then + if [ $has_z900 = 0 ] || do_compiler "$target_cc" $target_cc_cflags -march=z10 -msoft-float -Werror -o $TMPO -c $TMPC; then if [ $has_z900 != 0 ]; then echo "WARNING: Your compiler does not support the z900!" echo " The s390-ccw bios will only work with guest CPUs >= z10." fi - roms="$roms s390-ccw" + roms="$roms pc-bios/s390-ccw" + config_mak=pc-bios/s390-ccw/config-host.mak + echo "# Automatically generated by configure - do not modify" > $config_mak + echo "SRC_PATH=$source_path/pc-bios/s390-ccw" >> $config_mak + write_target_makefile >> $config_mak # SLOF is required for building the s390-ccw firmware on s390x, # since it is using the libnet code from SLOF for network booting. git_submodules="${git_submodules} roms/SLOF" fi fi -# 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 - echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak - echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER}" >> $config_host_mak - echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO}" >> $config_host_mak - echo "QEMU_GA_VERSION=${QEMU_GA_VERSION}" >> $config_host_mak + echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER-QEMU}" >> $config_host_mak + echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO-Linux}" >> $config_host_mak + echo "QEMU_GA_VERSION=${QEMU_GA_VERSION-$(cat "$source_path"/VERSION)}" >> $config_host_mak else echo "CONFIG_POSIX=y" >> $config_host_mak fi @@ -2814,82 +2327,11 @@ fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi -echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak -echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak -qemu_version=$(head $source_path/VERSION) -echo "PKGVERSION=$pkgversion" >>$config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak echo "TARGET_DIRS=$target_list" >> $config_host_mak if test "$modules" = "yes"; then - # $shacmd can generate a hash started with digit, which the compiler doesn't - # like as an symbol. So prefix it with an underscore - echo "CONFIG_STAMP=_$( (echo $qemu_version; echo $pkgversion; cat $0) | $shacmd - | cut -f1 -d\ )" >> $config_host_mak echo "CONFIG_MODULES=y" >> $config_host_mak fi -if test "$module_upgrades" = "yes"; then - echo "CONFIG_MODULE_UPGRADES=y" >> $config_host_mak -fi -if test "$have_usbfs" = "yes" ; then - echo "CONFIG_USBFS=y" >> $config_host_mak -fi -if test "$gio" = "yes" ; then - echo "CONFIG_GIO=y" >> $config_host_mak - echo "GIO_CFLAGS=$gio_cflags" >> $config_host_mak - echo "GIO_LIBS=$gio_libs" >> $config_host_mak -fi -if test "$gdbus_codegen" != "" ; then - echo "GDBUS_CODEGEN=$gdbus_codegen" >> $config_host_mak -fi -echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak - -if test "$xen" = "enabled" ; then - echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak - echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak - echo "XEN_CFLAGS=$xen_cflags" >> $config_host_mak - echo "XEN_LIBS=$xen_libs" >> $config_host_mak -fi -if test "$vhost_scsi" = "yes" ; then - echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak -fi -if test "$vhost_net" = "yes" ; then - echo "CONFIG_VHOST_NET=y" >> $config_host_mak -fi -if test "$vhost_net_user" = "yes" ; then - echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak -fi -if test "$vhost_net_vdpa" = "yes" ; then - echo "CONFIG_VHOST_NET_VDPA=y" >> $config_host_mak -fi -if test "$vhost_crypto" = "yes" ; then - echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak -fi -if test "$vhost_vsock" = "yes" ; then - echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak - if test "$vhost_user" = "yes" ; then - echo "CONFIG_VHOST_USER_VSOCK=y" >> $config_host_mak - fi -fi -if test "$vhost_kernel" = "yes" ; then - echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak -fi -if test "$vhost_user" = "yes" ; then - echo "CONFIG_VHOST_USER=y" >> $config_host_mak -fi -if test "$vhost_vdpa" = "yes" ; then - echo "CONFIG_VHOST_VDPA=y" >> $config_host_mak -fi -if test "$vhost_user_fs" = "yes" ; then - echo "CONFIG_VHOST_USER_FS=y" >> $config_host_mak -fi -if test "$tcg" = "enabled" -a "$tcg_interpreter" = "true" ; then - echo "CONFIG_TCG_INTERPRETER=y" >> $config_host_mak -fi - -if test "$opengl" = "yes" ; then - echo "CONFIG_OPENGL=y" >> $config_host_mak - echo "OPENGL_CFLAGS=$opengl_cflags" >> $config_host_mak - echo "OPENGL_LIBS=$opengl_libs" >> $config_host_mak -fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then @@ -2906,15 +2348,6 @@ if test "$have_tsan" = "yes" && test "$have_tsan_iface_fiber" = "yes" ; then echo "CONFIG_TSAN=y" >> $config_host_mak fi -if test "$rdma" = "yes" ; then - echo "CONFIG_RDMA=y" >> $config_host_mak - echo "RDMA_LIBS=$rdma_libs" >> $config_host_mak -fi - -if test "$pvrdma" = "yes" ; then - echo "CONFIG_PVRDMA=y" >> $config_host_mak -fi - if test "$plugins" = "yes" ; then echo "CONFIG_PLUGIN=y" >> $config_host_mak fi @@ -2923,13 +2356,14 @@ if test -n "$gdb_bin"; then gdb_version=$($gdb_bin --version | head -n 1) if version_ge ${gdb_version##* } 9.1; then echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak + else + gdb_bin="" fi fi -if test "$secret_keyring" = "yes" ; then - echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak +if test "$container" != no; then + echo "ENGINE=$container" >> $config_host_mak fi - echo "ROMS=$roms" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak echo "PYTHON=$python" >> $config_host_mak @@ -2937,23 +2371,13 @@ echo "GENISOIMAGE=$genisoimage" >> $config_host_mak echo "MESON=$meson" >> $config_host_mak echo "NINJA=$ninja" >> $config_host_mak echo "CC=$cc" >> $config_host_mak -echo "HOST_CC=$host_cc" >> $config_host_mak -echo "AR=$ar" >> $config_host_mak -echo "AS=$as" >> $config_host_mak -echo "CCAS=$ccas" >> $config_host_mak -echo "CPP=$cpp" >> $config_host_mak -echo "OBJCOPY=$objcopy" >> $config_host_mak -echo "LD=$ld" >> $config_host_mak -echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $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 -echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak +echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak +echo "GLIB_VERSION=$($pkg_config --modversion glib-2.0)" >> $config_host_mak echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak -echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak -echo "STRIP=$strip" >> $config_host_mak echo "EXESUF=$EXESUF" >> $config_host_mak # use included Linux headers @@ -2992,14 +2416,13 @@ 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" ;; esac done -echo "CONFIG_QEMU_INTERP_PREFIX=$interp_prefix" | sed 's/%M/@0@/' >> $config_host_mak if test "$default_targets" = "yes"; then echo "CONFIG_DEFAULT_TARGETS=y" >> $config_host_mak fi @@ -3012,75 +2435,55 @@ if test "$safe_stack" = "yes"; then echo "CONFIG_SAFESTACK=y" >> $config_host_mak fi -# If we're using a separate build tree, set it up now. -# LINKS are things to symlink back into the source tree -# (these can be both files and directories). -# Caution: do not add files or directories here using wildcards. This -# will result in problems later if a new file matching the wildcard is -# added to the source tree -- nothing will cause configure to be rerun -# so the build tree will be missing the link back to the new file, and -# tests might fail. Prefer to keep the relevant files in their own -# directory and symlink the directory instead. -LINKS="Makefile" -LINKS="$LINKS tests/tcg/Makefile.target" -LINKS="$LINKS pc-bios/optionrom/Makefile" -LINKS="$LINKS pc-bios/s390-ccw/Makefile" -LINKS="$LINKS roms/seabios/Makefile" -LINKS="$LINKS pc-bios/qemu-icon.bmp" -LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit -LINKS="$LINKS tests/avocado tests/data" -LINKS="$LINKS tests/qemu-iotests/check" -LINKS="$LINKS python" -LINKS="$LINKS contrib/plugins/Makefile " -for bios_file in \ - $source_path/pc-bios/*.bin \ - $source_path/pc-bios/*.elf \ - $source_path/pc-bios/*.lid \ - $source_path/pc-bios/*.rom \ - $source_path/pc-bios/*.dtb \ - $source_path/pc-bios/*.img \ - $source_path/pc-bios/openbios-* \ - $source_path/pc-bios/u-boot.* \ - $source_path/pc-bios/palcode-* \ - $source_path/pc-bios/qemu_vga.ndrv - -do - LINKS="$LINKS pc-bios/$(basename $bios_file)" -done -for f in $LINKS ; do - if [ -e "$source_path/$f" ]; then - mkdir -p `dirname ./$f` - symlink "$source_path/$f" "$f" - fi -done - -(for i in $cross_cc_vars; do - export $i -done -export target_list source_path use_containers cpu -$source_path/tests/tcg/configure.sh) +# tests/tcg configuration +(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 -# temporary config to build submodules -if test -f $source_path/roms/seabios/Makefile; then - for rom in seabios; do - config_mak=roms/$rom/config.mak - echo "# Automatically generated by configure - do not modify" > $config_mak - echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak - echo "AS=$as" >> $config_mak - echo "CCAS=$ccas" >> $config_mak - echo "CC=$cc" >> $config_mak - echo "BCC=bcc" >> $config_mak - echo "CPP=$cpp" >> $config_mak - echo "OBJCOPY=objcopy" >> $config_mak - echo "IASL=$iasl" >> $config_mak - echo "LD=$ld" >> $config_mak - echo "RANLIB=$ranlib" >> $config_mak - done +# 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 +if test "$plugins" = "yes" ; then + echo "CONFIG_PLUGIN=y" >> $config_host_mak +fi + +tcg_tests_targets= +for target in $target_list; do + arch=${target%%-*} + + 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 + qemu="qemu-system-$arch" + ;; + *-linux-user|*-bsd-user) + qemu="qemu-$arch" + ;; + esac -config_mak=pc-bios/optionrom/config.mak -echo "# Automatically generated by configure - do not modify" > $config_mak -echo "TOPSRC_DIR=$source_path" >> $config_mak + 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" >> config-host.mak) if test "$skip_meson" = no; then cross="config-meson.cross.new" @@ -3098,7 +2501,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 @@ -3117,7 +2519,9 @@ if test "$skip_meson" = no; then echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross fi echo "strip = [$(meson_quote $strip)]" >> $cross + echo "widl = [$(meson_quote $widl)]" >> $cross echo "windres = [$(meson_quote $windres)]" >> $cross + echo "windmc = [$(meson_quote $windmc)]" >> $cross if test "$cross_compile" = "yes"; then cross_arg="--cross-file config-meson.cross" echo "[host_machine]" >> $cross @@ -3142,52 +2546,28 @@ if test "$skip_meson" = no; then mv $cross config-meson.cross rm -rf meson-private meson-info meson-logs + + # Built-in options + test "$bindir" != "bin" && meson_option_add "-Dbindir=$bindir" + test "$default_feature" = no && meson_option_add -Dauto_features=disabled + test "$pie" = no && meson_option_add -Db_pie=false + test "$werror" = yes && meson_option_add -Dwerror=true + + # QEMU options + test "$cfi" != false && meson_option_add "-Dcfi=$cfi" + 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 "$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" run_meson() { - NINJA=$ninja $meson setup \ - --prefix "$prefix" \ - --libdir "$libdir" \ - --libexecdir "$libexecdir" \ - --bindir "$bindir" \ - --includedir "$includedir" \ - --datadir "$datadir" \ - --mandir "$mandir" \ - --sysconfdir "$sysconfdir" \ - --localedir "$localedir" \ - --localstatedir "$local_statedir" \ - -Daudio_drv_list=$audio_drv_list \ - -Ddefault_devices=$default_devices \ - -Ddocdir="$docdir" \ - -Diasl="$($iasl -h >/dev/null 2>&1 && printf %s "$iasl")" \ - -Dqemu_firmwarepath="$firmwarepath" \ - -Dqemu_suffix="$qemu_suffix" \ - -Dsmbd="$smbd" \ - -Dsphinx_build="$sphinx_build" \ - -Dtrace_file="$trace_file" \ - -Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \ - -Ddebug=$(if test "$debug_info" = yes; then echo true; else echo false; fi) \ - -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ - -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ - -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ - -Db_lto=$lto -Dcfi=$cfi -Dtcg=$tcg -Dxen=$xen \ - -Dcapstone=$capstone -Dfdt=$fdt -Dslirp=$slirp \ - $(test -n "${LIB_FUZZING_ENGINE+xxx}" && echo "-Dfuzzing_engine=$LIB_FUZZING_ENGINE") \ - $(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi) \ - "$@" $cross_arg "$PWD" "$source_path" + NINJA=$ninja $meson setup --prefix "$prefix" "$@" $cross_arg "$PWD" "$source_path" } eval run_meson $meson_options if test "$?" -ne 0 ; then error_exit "meson setup failed" fi -else - if test -f meson-private/cmd_line.txt; then - # Adjust old command line options whose type was changed - # Avoids having to use "setup --wipe" when Meson is upgraded - perl -i -ne ' - s/^gettext = true$/gettext = auto/; - s/^gettext = false$/gettext = disabled/; - /^b_staticpic/ && next; - print;' meson-private/cmd_line.txt - fi fi # Save the configure command line for later reuse. @@ -3218,27 +2598,30 @@ preserve_env() { preserve_env AR preserve_env AS preserve_env CC -preserve_env CPP preserve_env CFLAGS preserve_env CXX preserve_env CXXFLAGS -preserve_env INSTALL preserve_env LD preserve_env LDFLAGS preserve_env LD_LIBRARY_PATH -preserve_env LIBTOOL preserve_env MAKE preserve_env NM +preserve_env OBJCFLAGS preserve_env OBJCOPY preserve_env PATH preserve_env PKG_CONFIG preserve_env PKG_CONFIG_LIBDIR preserve_env PKG_CONFIG_PATH preserve_env PYTHON +preserve_env QEMU_GA_MANUFACTURER +preserve_env QEMU_GA_DISTRO +preserve_env QEMU_GA_VERSION preserve_env SDL2_CONFIG preserve_env SMBD preserve_env STRIP +preserve_env WIDL preserve_env WINDRES +preserve_env WINDMC printf "exec" >>config.status for i in "$0" "$@"; do diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c index 20b477d582a4..d77b8f98f78d 100644 --- a/contrib/elf2dmp/main.c +++ b/contrib/elf2dmp/main.c @@ -125,6 +125,7 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb, if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) { eprintf("Failed to extract entire KDBG\n"); + free(kdbg); return NULL; } @@ -141,10 +142,10 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb, return kdbg; } -static void win_context_init_from_qemu_cpu_state(WinContext *ctx, +static void win_context_init_from_qemu_cpu_state(WinContext64 *ctx, QEMUCPUState *s) { - WinContext win_ctx = (WinContext){ + WinContext64 win_ctx = (WinContext64){ .ContextFlags = WIN_CTX_X64 | WIN_CTX_INT | WIN_CTX_SEG | WIN_CTX_CTL, .MxCsr = INITIAL_MXCSR, @@ -302,7 +303,7 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg, for (i = 0; i < qe->state_nr; i++) { uint64_t Prcb; uint64_t Context; - WinContext ctx; + WinContext64 ctx; QEMUCPUState *s = qe->state[i]; if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i, diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c index b601b6d7ba44..ebda60dcb8a2 100644 --- a/contrib/elf2dmp/qemu_elf.c +++ b/contrib/elf2dmp/qemu_elf.c @@ -118,6 +118,53 @@ static void exit_states(QEMU_Elf *qe) free(qe->state); } +static bool check_ehdr(QEMU_Elf *qe) +{ + Elf64_Ehdr *ehdr = qe->map; + + if (sizeof(Elf64_Ehdr) > qe->size) { + eprintf("Invalid input dump file size\n"); + return false; + } + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + eprintf("Invalid ELF signature, input file is not ELF\n"); + return false; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 || + ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { + eprintf("Invalid ELF class or byte order, must be 64-bit LE\n"); + return false; + } + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + eprintf("Invalid ELF version\n"); + return false; + } + + if (ehdr->e_machine != EM_X86_64) { + eprintf("Invalid input dump architecture, only x86_64 is supported\n"); + return false; + } + + if (ehdr->e_type != ET_CORE) { + eprintf("Invalid ELF type, must be core file\n"); + return false; + } + + /* + * ELF dump file must contain one PT_NOTE and at least one PT_LOAD to + * restore physical address space. + */ + if (ehdr->e_phnum < 2) { + eprintf("Invalid number of ELF program headers\n"); + return false; + } + + return true; +} + int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) { GError *gerr = NULL; @@ -133,6 +180,12 @@ int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) qe->map = g_mapped_file_get_contents(qe->gmf); qe->size = g_mapped_file_get_length(qe->gmf); + if (!check_ehdr(qe)) { + eprintf("Input file has the wrong format\n"); + err = 1; + goto out_unmap; + } + if (init_states(qe)) { eprintf("Failed to extract QEMU CPU states\n"); err = 1; diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index 2800d9f986ae..37279186412f 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 44745ca85b66..082458e1bde6 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 f816aa877026..53883cc526f3 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/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c index 39a6ffdb5df9..2f3c7320a678 100644 --- a/contrib/ivshmem-server/ivshmem-server.c +++ b/contrib/ivshmem-server/ivshmem-server.c @@ -146,7 +146,7 @@ ivshmem_server_handle_new_conn(IvshmemServer *server) return -1; } - qemu_set_nonblock(newfd); + qemu_socket_set_nonblock(newfd); IVSHMEM_SERVER_DEBUG(server, "accept()=%d\n", newfd); /* allocate new structure for this peer */ diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index df3499f4f208..23e0396687e8 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -29,6 +29,7 @@ SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) CFLAGS = $(GLIB_CFLAGS) CFLAGS += -fPIC -Wall $(filter -W%, $(QEMU_CFLAGS)) CFLAGS += $(if $(findstring no-psabi,$(QEMU_CFLAGS)),-Wpsabi) +CFLAGS += $(if $(CONFIG_DEBUG_TCG), -ggdb -O0) CFLAGS += -I$(SRC_PATH)/include/qemu all: $(SONAMES) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index b9226e7c40b6..2e25184a7f15 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. * @@ -405,7 +405,7 @@ static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, g_mutex_lock(&l1_dcache_locks[cache_idx]); hit_in_l1 = access_cache(l1_dcaches[cache_idx], effective_addr); if (!hit_in_l1) { - insn = (InsnData *) userdata; + insn = userdata; __atomic_fetch_add(&insn->l1_dmisses, 1, __ATOMIC_SEQ_CST); l1_dcaches[cache_idx]->misses++; } @@ -419,7 +419,7 @@ static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, g_mutex_lock(&l2_ucache_locks[cache_idx]); if (!access_cache(l2_ucaches[cache_idx], effective_addr)) { - insn = (InsnData *) userdata; + insn = userdata; __atomic_fetch_add(&insn->l2_misses, 1, __ATOMIC_SEQ_CST); l2_ucaches[cache_idx]->misses++; } @@ -440,7 +440,7 @@ static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) g_mutex_lock(&l1_icache_locks[cache_idx]); hit_in_l1 = access_cache(l1_icaches[cache_idx], insn_addr); if (!hit_in_l1) { - insn = (InsnData *) userdata; + insn = userdata; __atomic_fetch_add(&insn->l1_imisses, 1, __ATOMIC_SEQ_CST); l1_icaches[cache_idx]->misses++; } @@ -454,7 +454,7 @@ static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) g_mutex_lock(&l2_ucache_locks[cache_idx]); if (!access_cache(l2_ucaches[cache_idx], insn_addr)) { - insn = (InsnData *) userdata; + insn = userdata; __atomic_fetch_add(&insn->l2_misses, 1, __ATOMIC_SEQ_CST); l2_ucaches[cache_idx]->misses++; } diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c index a5275dcc15c2..e255bd21fd65 100644 --- a/contrib/plugins/execlog.c +++ b/contrib/plugins/execlog.c @@ -18,7 +18,29 @@ 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 *last_exec; +static GMutex expand_array_lock; + +static GPtrArray *imatches; +static GArray *amatches; + +/* + * Expand last_exec array. + * + * As we could have multiple threads trying to do this we need to + * serialise the expansion under a lock. Threads accessing already + * created entries can continue without issue even if the ptr array + * gets reallocated during resize. + */ +static void expand_last_exec(int cpu_index) +{ + g_mutex_lock(&expand_array_lock); + while (cpu_index >= last_exec->len) { + GString *s = g_string_new(NULL); + g_ptr_array_add(last_exec, s); + } + g_mutex_unlock(&expand_array_lock); +} /** * Add memory read or write information to current instruction log @@ -30,7 +52,7 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info, /* Find vCPU in array */ g_assert(cpu_index < last_exec->len); - s = g_array_index(last_exec, GString *, cpu_index); + s = g_ptr_array_index(last_exec, cpu_index); /* Indicate type of memory access */ if (qemu_plugin_mem_is_store(info)) { @@ -58,11 +80,10 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata) GString *s; /* Find or create vCPU in array */ - while (cpu_index >= last_exec->len) { - s = g_string_new(NULL); - g_array_append_val(last_exec, s); + if (cpu_index >= last_exec->len) { + expand_last_exec(cpu_index); } - s = g_array_index(last_exec, GString *, cpu_index); + s = g_ptr_array_index(last_exec, cpu_index); /* Print previous instruction in cache */ if (s->len) { @@ -85,12 +106,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 +121,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); + + /* + * 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; + } + } + } - /* 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 (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); } } @@ -124,7 +181,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) guint i; GString *s; for (i = 0; i < last_exec->len; i++) { - s = g_array_index(last_exec, GString *, i); + s = g_ptr_array_index(last_exec, i); if (s->str) { qemu_plugin_outs(s->str); qemu_plugin_outs("\n"); @@ -132,6 +189,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 */ @@ -143,7 +219,24 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, * Initialize dynamic array to cache vCPU instruction. In user mode * we don't know the size before emulation. */ - last_exec = g_array_new(FALSE, FALSE, sizeof(GString *)); + if (info->system_emulation) { + last_exec = g_ptr_array_sized_new(info->system.max_vcpus); + } else { + last_exec = g_ptr_array_new(); + } + + 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); diff --git a/contrib/rdmacm-mux/meson.build b/contrib/rdmacm-mux/meson.build index 7674f54cc5b5..36c9c8963047 100644 --- a/contrib/rdmacm-mux/meson.build +++ b/contrib/rdmacm-mux/meson.build @@ -1,7 +1,5 @@ -if 'CONFIG_PVRDMA' in config_host - # if not found, CONFIG_PVRDMA should not be set +if have_pvrdma # FIXME: broken on big endian architectures - libumad = cc.find_library('ibumad', required: true) executable('rdmacm-mux', files('main.c'), genh, dependencies: [glib, libumad], build_by_default: false, diff --git a/contrib/vhost-user-blk/meson.build b/contrib/vhost-user-blk/meson.build index 601ea15ef54a..dcb9e2ffcd08 100644 --- a/contrib/vhost-user-blk/meson.build +++ b/contrib/vhost-user-blk/meson.build @@ -1,5 +1,4 @@ -# FIXME: broken on 32-bit architectures executable('vhost-user-blk', files('vhost-user-blk.c'), dependencies: [qemuutil, vhost_user], - build_by_default: false, + build_by_default: targetos == 'linux', install: false) diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c index d14b2896bf00..7941694e5353 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); } @@ -146,7 +143,7 @@ vub_readv(VubReq *req, struct iovec *iov, uint32_t iovcnt) req->size = vub_iov_size(iov, iovcnt); rc = preadv(vdev_blk->blk_fd, iov, iovcnt, req->sector_num * 512); if (rc < 0) { - fprintf(stderr, "%s, Sector %"PRIu64", Size %lu failed with %s\n", + fprintf(stderr, "%s, Sector %"PRIu64", Size %zu failed with %s\n", vdev_blk->blk_name, req->sector_num, req->size, strerror(errno)); return -1; @@ -169,7 +166,7 @@ vub_writev(VubReq *req, struct iovec *iov, uint32_t iovcnt) req->size = vub_iov_size(iov, iovcnt); rc = pwritev(vdev_blk->blk_fd, iov, iovcnt, req->sector_num * 512); if (rc < 0) { - fprintf(stderr, "%s, Sector %"PRIu64", Size %lu failed with %s\n", + fprintf(stderr, "%s, Sector %"PRIu64", Size %zu failed with %s\n", vdev_blk->blk_name, req->sector_num, req->size, strerror(errno)); return -1; @@ -188,7 +185,7 @@ vub_discard_write_zeroes(VubReq *req, struct iovec *iov, uint32_t iovcnt, size = vub_iov_size(iov, iovcnt); if (size != sizeof(*desc)) { - fprintf(stderr, "Invalid size %ld, expect %ld\n", size, sizeof(*desc)); + fprintf(stderr, "Invalid size %zd, expect %zd\n", size, sizeof(*desc)); return -1; } buf = g_new0(char, size); @@ -196,7 +193,7 @@ vub_discard_write_zeroes(VubReq *req, struct iovec *iov, uint32_t iovcnt, #if defined(__linux__) && defined(BLKDISCARD) && defined(BLKZEROOUT) VubDev *vdev_blk = req->vdev_blk; - desc = (struct virtio_blk_discard_write_zeroes *)buf; + desc = buf; uint64_t range[2] = { le64toh(desc->sector) << 9, le32toh(desc->num_sectors) << 9 }; if (type == VIRTIO_BLK_T_DISCARD) { @@ -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; } @@ -535,9 +532,9 @@ vub_get_blocksize(int fd) static void vub_initialize_config(int fd, struct virtio_blk_config *config) { - off64_t capacity; + off_t capacity; - capacity = lseek64(fd, 0, SEEK_END); + capacity = lseek(fd, 0, SEEK_END); config->capacity = capacity >> 9; config->blk_size = vub_get_blocksize(fd); config->size_max = 65536; @@ -593,7 +590,8 @@ static GOptionEntry entries[] = { {"blk-file", 'b', 0, G_OPTION_ARG_FILENAME, &opt_blk_file, "block device or file path", "PATH"}, { "read-only", 'r', 0, G_OPTION_ARG_NONE, &opt_read_only, - "Enable read-only", NULL } + "Enable read-only", NULL }, + { NULL, }, }; int main(int argc, char **argv) diff --git a/contrib/vhost-user-gpu/vugbm.c b/contrib/vhost-user-gpu/vugbm.c index fb15d0372c25..503d0a4566f8 100644 --- a/contrib/vhost-user-gpu/vugbm.c +++ b/contrib/vhost-user-gpu/vugbm.c @@ -53,7 +53,7 @@ struct udmabuf_create { static size_t udmabuf_get_size(struct vugbm_buffer *buf) { - return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size); + return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size()); } static bool diff --git a/contrib/vhost-user-scsi/vhost-user-scsi.c b/contrib/vhost-user-scsi/vhost-user-scsi.c index 4f6e3e2a24bc..9ef61cf5a797 100644 --- a/contrib/vhost-user-scsi/vhost-user-scsi.c +++ b/contrib/vhost-user-scsi/vhost-user-scsi.c @@ -351,34 +351,59 @@ static int unix_sock_new(char *unix_fn) /** vhost-user-scsi **/ +static int opt_fdnum = -1; +static char *opt_socket_path; +static gboolean opt_print_caps; +static char *iscsi_uri; + +static GOptionEntry entries[] = { + { "print-capabilities", 'c', 0, G_OPTION_ARG_NONE, &opt_print_caps, + "Print capabilities", NULL }, + { "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum, + "Use inherited fd socket", "FDNUM" }, + { "iscsi-uri", 'i', 0, G_OPTION_ARG_FILENAME, &iscsi_uri, + "iSCSI URI to connect to", "FDNUM" }, + { "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path, + "Use UNIX socket path", "PATH" }, + { NULL, } +}; + int main(int argc, char **argv) { VusDev *vdev_scsi = NULL; - char *unix_fn = NULL; - char *iscsi_uri = NULL; - int lsock = -1, csock = -1, opt, err = EXIT_SUCCESS; - - while ((opt = getopt(argc, argv, "u:i:")) != -1) { - switch (opt) { - case 'h': - goto help; - case 'u': - unix_fn = g_strdup(optarg); - break; - case 'i': - iscsi_uri = g_strdup(optarg); - break; - default: - goto help; - } + int lsock = -1, csock = -1, err = EXIT_SUCCESS; + + GError *error = NULL; + GOptionContext *context; + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_printerr("Option parsing failed: %s\n", error->message); + exit(EXIT_FAILURE); } - if (!unix_fn || !iscsi_uri) { + + if (opt_print_caps) { + g_print("{\n"); + g_print(" \"type\": \"scsi\"\n"); + g_print("}\n"); + goto out; + } + + if (!iscsi_uri) { goto help; } - lsock = unix_sock_new(unix_fn); - if (lsock < 0) { - goto err; + if (opt_socket_path) { + lsock = unix_sock_new(opt_socket_path); + if (lsock < 0) { + exit(EXIT_FAILURE); + } + } else if (opt_fdnum < 0) { + g_print("%s\n", g_option_context_get_help(context, true, NULL)); + exit(EXIT_FAILURE); + } else { + lsock = opt_fdnum; } csock = accept(lsock, NULL, NULL); @@ -408,15 +433,18 @@ int main(int argc, char **argv) if (vdev_scsi) { g_main_loop_unref(vdev_scsi->loop); g_free(vdev_scsi); - unlink(unix_fn); } if (csock >= 0) { close(csock); } if (lsock >= 0) { close(lsock); + + if (opt_socket_path) { + unlink(opt_socket_path); + } } - g_free(unix_fn); + g_free(opt_socket_path); g_free(iscsi_uri); return err; @@ -426,10 +454,12 @@ int main(int argc, char **argv) goto out; help: - fprintf(stderr, "Usage: %s [ -u unix_sock_path -i iscsi_uri ] | [ -h ]\n", + fprintf(stderr, "Usage: %s [ -s socket-path -i iscsi-uri -f fd -p print-capabilities ] | [ -h ]\n", argv[0]); - fprintf(stderr, " -u path to unix socket\n"); - fprintf(stderr, " -i iscsi uri for lun 0\n"); + fprintf(stderr, " -s, --socket-path=SOCKET_PATH path to unix socket\n"); + fprintf(stderr, " -i, --iscsi-uri=ISCSI_URI iscsi uri for lun 0\n"); + fprintf(stderr, " -f, --fd=FILE_DESCRIPTOR file-descriptor\n"); + fprintf(stderr, " -p, --print-capabilities=PRINT_CAPABILITIES denotes print-capabilities\n"); fprintf(stderr, " -h print help and quit\n"); goto err; diff --git a/cpu.c b/cpu.c index be1f8b074ce4..4a7d86542780 100644 --- a/cpu.c +++ b/cpu.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "exec/target_page.h" @@ -132,19 +131,26 @@ 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)) { return; } + /* NB: errp parameter is unused currently */ if (tcg_enabled()) { tcg_exec_realizefn(cpu, errp); } + /* Wait until cpu initialization complete before exposing cpu. */ + cpu_list_add(cpu); + + /* Plugin initialization must wait until cpu_index assigned. */ + if (tcg_enabled()) { + qemu_plugin_vcpu_init_hook(cpu); + } + #ifdef CONFIG_USER_ONLY assert(qdev_get_vmsd(DEVICE(cpu)) == NULL || qdev_get_vmsd(DEVICE(cpu))->unmigratable); @@ -152,8 +158,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 */ } @@ -279,7 +285,7 @@ void list_cpus(const char *optarg) void tb_invalidate_phys_addr(target_ulong addr) { mmap_lock(); - tb_invalidate_phys_page_range(addr, addr + 1); + tb_invalidate_phys_page(addr); mmap_unlock(); } #else @@ -300,7 +306,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) return; } ram_addr = memory_region_get_ram_addr(mr) + addr; - tb_invalidate_phys_page_range(ram_addr, ram_addr + 1); + tb_invalidate_phys_page(ram_addr); } #endif @@ -400,14 +406,14 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...) fprintf(stderr, "\n"); cpu_dump_state(cpu, stderr, CPU_DUMP_FPU | CPU_DUMP_CCOP); if (qemu_log_separate()) { - FILE *logfile = qemu_log_lock(); - qemu_log("qemu: fatal: "); - qemu_log_vprintf(fmt, ap2); - qemu_log("\n"); - log_cpu_state(cpu, CPU_DUMP_FPU | CPU_DUMP_CCOP); - qemu_log_flush(); - qemu_log_unlock(logfile); - qemu_log_close(); + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "qemu: fatal: "); + vfprintf(logfile, fmt, ap2); + fprintf(logfile, "\n"); + cpu_dump_state(cpu, logfile, CPU_DUMP_FPU | CPU_DUMP_CCOP); + qemu_log_unlock(logfile); + } } va_end(ap2); va_end(ap); @@ -469,7 +475,7 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, bool target_words_bigendian(void) { -#if defined(TARGET_WORDS_BIGENDIAN) +#if TARGET_BIG_ENDIAN return true; #else return false; @@ -481,7 +487,7 @@ void page_size_init(void) /* NOTE: we can always suppose that qemu_host_page_size >= TARGET_PAGE_SIZE */ if (qemu_host_page_size == 0) { - qemu_host_page_size = qemu_real_host_page_size; + qemu_host_page_size = qemu_real_host_page_size(); } if (qemu_host_page_size < TARGET_PAGE_SIZE) { qemu_host_page_size = TARGET_PAGE_SIZE; diff --git a/cpus-common.c b/cpus-common.c index db459b41ce20..793364dc0ed5 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -73,6 +73,12 @@ static int cpu_get_free_index(void) } CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); +static unsigned int cpu_list_generation_id; + +unsigned int cpu_list_generation_id_get(void) +{ + return cpu_list_generation_id; +} void cpu_list_add(CPUState *cpu) { @@ -84,6 +90,7 @@ void cpu_list_add(CPUState *cpu) assert(!cpu_index_auto_assigned); } QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node); + cpu_list_generation_id++; } void cpu_list_remove(CPUState *cpu) @@ -96,6 +103,7 @@ void cpu_list_remove(CPUState *cpu) QTAILQ_REMOVE_RCU(&cpus, cpu, node); cpu->cpu_index = UNASSIGNED_CPU_INDEX; + cpu_list_generation_id++; } CPUState *qemu_get_cpu(int index) diff --git a/crypto/akcipher-gcrypt.c.inc b/crypto/akcipher-gcrypt.c.inc new file mode 100644 index 000000000000..abb1fb272e45 --- /dev/null +++ b/crypto/akcipher-gcrypt.c.inc @@ -0,0 +1,595 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "crypto/akcipher.h" +#include "crypto/random.h" +#include "qapi/error.h" +#include "sysemu/cryptodev.h" +#include "rsakey.h" + +typedef struct QCryptoGcryptRSA { + QCryptoAkCipher akcipher; + gcry_sexp_t key; + QCryptoRSAPaddingAlgorithm padding_alg; + QCryptoHashAlgorithm hash_alg; +} QCryptoGcryptRSA; + +static void qcrypto_gcrypt_rsa_free(QCryptoAkCipher *akcipher) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + if (!rsa) { + return; + } + + gcry_sexp_release(rsa->key); + g_free(rsa); +} + +static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp); + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + return (QCryptoAkCipher *)qcrypto_gcrypt_rsa_new( + &opts->u.rsa, type, key, keylen, errp); + + default: + error_setg(errp, "Unsupported algorithm: %u", opts->alg); + return NULL; + } + + return NULL; +} + +static void qcrypto_gcrypt_set_rsa_size(QCryptoAkCipher *akcipher, gcry_mpi_t n) +{ + size_t key_size = (gcry_mpi_get_nbits(n) + 7) / 8; + akcipher->max_plaintext_len = key_size; + akcipher->max_ciphertext_len = key_size; + akcipher->max_dgst_len = key_size; + akcipher->max_signature_len = key_size; +} + +static int qcrypto_gcrypt_parse_rsa_private_key( + QCryptoGcryptRSA *rsa, + const uint8_t *key, size_t keylen, Error **errp) +{ + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp); + gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL, u = NULL; + bool compute_mul_inv = false; + int ret = -1; + gcry_error_t err; + + if (!rsa_key) { + return ret; + } + + err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD, + rsa_key->n.data, rsa_key->n.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter n: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD, + rsa_key->e.data, rsa_key->e.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter e: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&d, GCRYMPI_FMT_STD, + rsa_key->d.data, rsa_key->d.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter d: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&p, GCRYMPI_FMT_STD, + rsa_key->p.data, rsa_key->p.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter p: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&q, GCRYMPI_FMT_STD, + rsa_key->q.data, rsa_key->q.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter q: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + if (gcry_mpi_cmp_ui(p, 0) > 0 && gcry_mpi_cmp_ui(q, 0) > 0) { + compute_mul_inv = true; + + u = gcry_mpi_new(0); + if (gcry_mpi_cmp(p, q) > 0) { + gcry_mpi_swap(p, q); + } + gcry_mpi_invm(u, p, q); + } + + if (compute_mul_inv) { + err = gcry_sexp_build(&rsa->key, NULL, + "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))", + n, e, d, p, q, u); + } else { + err = gcry_sexp_build(&rsa->key, NULL, + "(private-key (rsa (n %m) (e %m) (d %m)))", n, e, d); + } + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build RSA private key: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n); + ret = 0; + +cleanup: + gcry_mpi_release(n); + gcry_mpi_release(e); + gcry_mpi_release(d); + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(u); + return ret; +} + +static int qcrypto_gcrypt_parse_rsa_public_key(QCryptoGcryptRSA *rsa, + const uint8_t *key, + size_t keylen, + Error **errp) +{ + + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp); + gcry_mpi_t n = NULL, e = NULL; + int ret = -1; + gcry_error_t err; + + if (!rsa_key) { + return ret; + } + + err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD, + rsa_key->n.data, rsa_key->n.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter n: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD, + rsa_key->e.data, rsa_key->e.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter e: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_sexp_build(&rsa->key, NULL, + "(public-key (rsa (n %m) (e %m)))", n, e); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build RSA public key: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n); + ret = 0; + +cleanup: + gcry_mpi_release(n); + gcry_mpi_release(e); + return ret; +} + +static int qcrypto_gcrypt_rsa_encrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, + Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL; + gcry_sexp_t cipher_sexp_item = NULL; + gcry_mpi_t cipher_mpi = NULL; + const char *result; + gcry_error_t err; + size_t actual_len; + + if (in_len > akcipher->max_plaintext_len) { + error_setg(errp, "Plaintext length is greater than key size: %d", + akcipher->max_plaintext_len); + return ret; + } + + err = gcry_sexp_build(&data_sexp, NULL, + "(data (flags %s) (value %b))", + QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg), + in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build plaintext: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_encrypt(&cipher_sexp, data_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to encrypt: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + /* S-expression of cipher: (enc-val (rsa (a a-mpi))) */ + cipher_sexp_item = gcry_sexp_find_token(cipher_sexp, "a", 0); + if (!cipher_sexp_item || gcry_sexp_length(cipher_sexp_item) != 2) { + error_setg(errp, "Invalid ciphertext result"); + goto cleanup; + } + + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + cipher_mpi = gcry_sexp_nth_mpi(cipher_sexp_item, 1, GCRYMPI_FMT_USG); + if (!cipher_mpi) { + error_setg(errp, "Invalid ciphertext result"); + goto cleanup; + } + err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len, + &actual_len, cipher_mpi); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to print MPI: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + if (actual_len > out_len) { + error_setg(errp, "Ciphertext buffer length is too small"); + goto cleanup; + } + + /* We always padding leading-zeros for RSA-RAW */ + if (actual_len < out_len) { + memmove((uint8_t *)out + (out_len - actual_len), out, actual_len); + memset(out, 0, out_len - actual_len); + } + ret = out_len; + + } else { + result = gcry_sexp_nth_data(cipher_sexp_item, 1, &actual_len); + if (!result) { + error_setg(errp, "Invalid ciphertext result"); + goto cleanup; + } + if (actual_len > out_len) { + error_setg(errp, "Ciphertext buffer length is too small"); + goto cleanup; + } + memcpy(out, result, actual_len); + ret = actual_len; + } + +cleanup: + gcry_sexp_release(data_sexp); + gcry_sexp_release(cipher_sexp); + gcry_sexp_release(cipher_sexp_item); + gcry_mpi_release(cipher_mpi); + return ret; +} + +static int qcrypto_gcrypt_rsa_decrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, + Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL; + gcry_mpi_t data_mpi = NULL; + gcry_error_t err; + size_t actual_len; + const char *result; + + if (in_len > akcipher->max_ciphertext_len) { + error_setg(errp, "Ciphertext length is greater than key size: %d", + akcipher->max_ciphertext_len); + return ret; + } + + err = gcry_sexp_build(&cipher_sexp, NULL, + "(enc-val (flags %s) (rsa (a %b) ))", + QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg), + in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build ciphertext: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_decrypt(&data_sexp, cipher_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to decrypt: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + /* S-expression of plaintext: (value plaintext) */ + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + data_mpi = gcry_sexp_nth_mpi(data_sexp, 1, GCRYMPI_FMT_USG); + if (!data_mpi) { + error_setg(errp, "Invalid plaintext result"); + goto cleanup; + } + err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len, + &actual_len, data_mpi); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to print MPI: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + if (actual_len > out_len) { + error_setg(errp, "Plaintext buffer length is too small"); + goto cleanup; + } + /* We always padding leading-zeros for RSA-RAW */ + if (actual_len < out_len) { + memmove((uint8_t *)out + (out_len - actual_len), out, actual_len); + memset(out, 0, out_len - actual_len); + } + ret = out_len; + } else { + result = gcry_sexp_nth_data(data_sexp, 1, &actual_len); + if (!result) { + error_setg(errp, "Invalid plaintext result"); + goto cleanup; + } + if (actual_len > out_len) { + error_setg(errp, "Plaintext buffer length is too small"); + goto cleanup; + } + memcpy(out, result, actual_len); + ret = actual_len; + } + +cleanup: + gcry_sexp_release(cipher_sexp); + gcry_sexp_release(data_sexp); + gcry_mpi_release(data_mpi); + return ret; +} + +static int qcrypto_gcrypt_rsa_sign(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t dgst_sexp = NULL, sig_sexp = NULL; + gcry_sexp_t sig_sexp_item = NULL; + const char *result; + gcry_error_t err; + size_t actual_len; + + if (in_len > akcipher->max_dgst_len) { + error_setg(errp, "Data length is greater than key size: %d", + akcipher->max_dgst_len); + return ret; + } + + if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) { + error_setg(errp, "Invalid padding %u", rsa->padding_alg); + return ret; + } + + err = gcry_sexp_build(&dgst_sexp, NULL, + "(data (flags pkcs1) (hash %s %b))", + QCryptoHashAlgorithm_str(rsa->hash_alg), + in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build dgst: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_sign(&sig_sexp, dgst_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to make signature: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + /* S-expression of signature: (sig-val (rsa (s s-mpi))) */ + sig_sexp_item = gcry_sexp_find_token(sig_sexp, "s", 0); + if (!sig_sexp_item || gcry_sexp_length(sig_sexp_item) != 2) { + error_setg(errp, "Invalid signature result"); + goto cleanup; + } + + result = gcry_sexp_nth_data(sig_sexp_item, 1, &actual_len); + if (!result) { + error_setg(errp, "Invalid signature result"); + goto cleanup; + } + + if (actual_len > out_len) { + error_setg(errp, "Signature buffer length is too small"); + goto cleanup; + } + memcpy(out, result, actual_len); + ret = actual_len; + +cleanup: + gcry_sexp_release(dgst_sexp); + gcry_sexp_release(sig_sexp); + gcry_sexp_release(sig_sexp_item); + + return ret; +} + +static int qcrypto_gcrypt_rsa_verify(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, + Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t sig_sexp = NULL, dgst_sexp = NULL; + gcry_error_t err; + + if (in_len > akcipher->max_signature_len) { + error_setg(errp, "Signature length is greater than key size: %d", + akcipher->max_signature_len); + return ret; + } + + if (in2_len > akcipher->max_dgst_len) { + error_setg(errp, "Data length is greater than key size: %d", + akcipher->max_dgst_len); + return ret; + } + + if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) { + error_setg(errp, "Invalid padding %u", rsa->padding_alg); + return ret; + } + + err = gcry_sexp_build(&sig_sexp, NULL, + "(sig-val (rsa (s %b)))", in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build signature: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_sexp_build(&dgst_sexp, NULL, + "(data (flags pkcs1) (hash %s %b))", + QCryptoHashAlgorithm_str(rsa->hash_alg), + in2_len, in2); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build dgst: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_verify(sig_sexp, dgst_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to verify signature: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + ret = 0; + +cleanup: + gcry_sexp_release(dgst_sexp); + gcry_sexp_release(sig_sexp); + + return ret; +} + +QCryptoAkCipherDriver gcrypt_rsa = { + .encrypt = qcrypto_gcrypt_rsa_encrypt, + .decrypt = qcrypto_gcrypt_rsa_decrypt, + .sign = qcrypto_gcrypt_rsa_sign, + .verify = qcrypto_gcrypt_rsa_verify, + .free = qcrypto_gcrypt_rsa_free, +}; + +static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + QCryptoGcryptRSA *rsa = g_new0(QCryptoGcryptRSA, 1); + rsa->padding_alg = opt->padding_alg; + rsa->hash_alg = opt->hash_alg; + rsa->akcipher.driver = &gcrypt_rsa; + + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + if (qcrypto_gcrypt_parse_rsa_private_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + if (qcrypto_gcrypt_parse_rsa_public_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + default: + error_setg(errp, "Unknown akcipher key type %d", type); + goto error; + } + + return rsa; + +error: + qcrypto_gcrypt_rsa_free((QCryptoAkCipher *)rsa); + return NULL; +} + + +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + switch (opts->u.rsa.padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + return true; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + switch (opts->u.rsa.hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA512: + return true; + + default: + return false; + } + + default: + return false; + } + + default: + return true; + } +} diff --git a/crypto/akcipher-nettle.c.inc b/crypto/akcipher-nettle.c.inc new file mode 100644 index 000000000000..02699e6e6d13 --- /dev/null +++ b/crypto/akcipher-nettle.c.inc @@ -0,0 +1,451 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "crypto/akcipher.h" +#include "crypto/random.h" +#include "qapi/error.h" +#include "sysemu/cryptodev.h" +#include "rsakey.h" + +typedef struct QCryptoNettleRSA { + QCryptoAkCipher akcipher; + struct rsa_public_key pub; + struct rsa_private_key priv; + QCryptoRSAPaddingAlgorithm padding_alg; + QCryptoHashAlgorithm hash_alg; +} QCryptoNettleRSA; + +static void qcrypto_nettle_rsa_free(QCryptoAkCipher *akcipher) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + if (!rsa) { + return; + } + + rsa_public_key_clear(&rsa->pub); + rsa_private_key_clear(&rsa->priv); + g_free(rsa); +} + +static QCryptoAkCipher *qcrypto_nettle_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp); + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + return qcrypto_nettle_rsa_new(&opts->u.rsa, type, key, keylen, errp); + + default: + error_setg(errp, "Unsupported algorithm: %u", opts->alg); + return NULL; + } + + return NULL; +} + +static void qcrypto_nettle_rsa_set_akcipher_size(QCryptoAkCipher *akcipher, + int key_size) +{ + akcipher->max_plaintext_len = key_size; + akcipher->max_ciphertext_len = key_size; + akcipher->max_signature_len = key_size; + akcipher->max_dgst_len = key_size; +} + +static int qcrypt_nettle_parse_rsa_private_key(QCryptoNettleRSA *rsa, + const uint8_t *key, + size_t keylen, + Error **errp) +{ + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp); + + if (!rsa_key) { + return -1; + } + + nettle_mpz_init_set_str_256_u(rsa->pub.n, rsa_key->n.len, rsa_key->n.data); + nettle_mpz_init_set_str_256_u(rsa->pub.e, rsa_key->e.len, rsa_key->e.data); + nettle_mpz_init_set_str_256_u(rsa->priv.d, rsa_key->d.len, rsa_key->d.data); + nettle_mpz_init_set_str_256_u(rsa->priv.p, rsa_key->p.len, rsa_key->p.data); + nettle_mpz_init_set_str_256_u(rsa->priv.q, rsa_key->q.len, rsa_key->q.data); + nettle_mpz_init_set_str_256_u(rsa->priv.a, rsa_key->dp.len, + rsa_key->dp.data); + nettle_mpz_init_set_str_256_u(rsa->priv.b, rsa_key->dq.len, + rsa_key->dq.data); + nettle_mpz_init_set_str_256_u(rsa->priv.c, rsa_key->u.len, rsa_key->u.data); + + if (!rsa_public_key_prepare(&rsa->pub)) { + error_setg(errp, "Failed to check RSA key"); + return -1; + } + + /** + * Since in the kernel's unit test, the p, q, a, b, c of some + * private keys is 0, only the simplest length check is done here + */ + if (rsa_key->p.len > 1 && + rsa_key->q.len > 1 && + rsa_key->dp.len > 1 && + rsa_key->dq.len > 1 && + rsa_key->u.len > 1) { + if (!rsa_private_key_prepare(&rsa->priv)) { + error_setg(errp, "Failed to check RSA key"); + return -1; + } + } else { + rsa->priv.size = rsa->pub.size; + } + qcrypto_nettle_rsa_set_akcipher_size( + (QCryptoAkCipher *)rsa, rsa->priv.size); + + return 0; +} + +static int qcrypt_nettle_parse_rsa_public_key(QCryptoNettleRSA *rsa, + const uint8_t *key, + size_t keylen, + Error **errp) +{ + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp); + + if (!rsa_key) { + return -1; + } + nettle_mpz_init_set_str_256_u(rsa->pub.n, rsa_key->n.len, rsa_key->n.data); + nettle_mpz_init_set_str_256_u(rsa->pub.e, rsa_key->e.len, rsa_key->e.data); + + if (!rsa_public_key_prepare(&rsa->pub)) { + error_setg(errp, "Failed to check RSA key"); + return -1; + } + qcrypto_nettle_rsa_set_akcipher_size( + (QCryptoAkCipher *)rsa, rsa->pub.size); + + return 0; +} + +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out) +{ + qcrypto_random_bytes(out, len, &error_abort); +} + +static int qcrypto_nettle_rsa_encrypt(QCryptoAkCipher *akcipher, + const void *data, size_t data_len, + void *enc, size_t enc_len, + Error **errp) +{ + + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + mpz_t c; + int ret = -1; + + if (data_len > rsa->pub.size) { + error_setg(errp, "Plaintext length %zu is greater than key size: %zu", + data_len, rsa->pub.size); + return ret; + } + + if (enc_len < rsa->pub.size) { + error_setg(errp, "Ciphertext buffer length %zu is less than " + "key size: %zu", enc_len, rsa->pub.size); + return ret; + } + + /* Nettle do not support RSA encryption without any padding */ + switch (rsa->padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + error_setg(errp, "RSA with raw padding is not supported"); + break; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + mpz_init(c); + if (rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func, + data_len, (uint8_t *)data, c) != 1) { + error_setg(errp, "Failed to encrypt"); + } else { + nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c); + ret = nettle_mpz_sizeinbase_256_u(c); + } + mpz_clear(c); + break; + + default: + error_setg(errp, "Unknown padding"); + } + + return ret; +} + +static int qcrypto_nettle_rsa_decrypt(QCryptoAkCipher *akcipher, + const void *enc, size_t enc_len, + void *data, size_t data_len, + Error **errp) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + mpz_t c; + int ret = -1; + + if (enc_len > rsa->priv.size) { + error_setg(errp, "Ciphertext length %zu is greater than key size: %zu", + enc_len, rsa->priv.size); + return ret; + } + + switch (rsa->padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + error_setg(errp, "RSA with raw padding is not supported"); + break; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + nettle_mpz_init_set_str_256_u(c, enc_len, enc); + if (!rsa_decrypt(&rsa->priv, &data_len, (uint8_t *)data, c)) { + error_setg(errp, "Failed to decrypt"); + } else { + ret = data_len; + } + + mpz_clear(c); + break; + + default: + error_setg(errp, "Unknown padding algorithm: %d", rsa->padding_alg); + } + + return ret; +} + +static int qcrypto_nettle_rsa_sign(QCryptoAkCipher *akcipher, + const void *data, size_t data_len, + void *sig, size_t sig_len, Error **errp) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + int ret = -1, rv; + mpz_t s; + + /** + * The RSA algorithm cannot be used for signature/verification + * without padding. + */ + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + error_setg(errp, "Try to make signature without padding"); + return ret; + } + + if (data_len > rsa->priv.size) { + error_setg(errp, "Data length %zu is greater than key size: %zu", + data_len, rsa->priv.size); + return ret; + } + + if (sig_len < rsa->priv.size) { + error_setg(errp, "Signature buffer length %zu is less than " + "key size: %zu", sig_len, rsa->priv.size); + return ret; + } + + mpz_init(s); + switch (rsa->hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + rv = rsa_md5_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA1: + rv = rsa_sha1_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA256: + rv = rsa_sha256_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA512: + rv = rsa_sha512_sign_digest(&rsa->priv, data, s); + break; + + default: + error_setg(errp, "Unknown hash algorithm: %d", rsa->hash_alg); + goto cleanup; + } + + if (rv != 1) { + error_setg(errp, "Failed to make signature"); + goto cleanup; + } + nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s); + ret = nettle_mpz_sizeinbase_256_u(s); + +cleanup: + mpz_clear(s); + + return ret; +} + +static int qcrypto_nettle_rsa_verify(QCryptoAkCipher *akcipher, + const void *sig, size_t sig_len, + const void *data, size_t data_len, + Error **errp) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + + int ret = -1, rv; + mpz_t s; + + /** + * The RSA algorithm cannot be used for signature/verification + * without padding. + */ + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + error_setg(errp, "Try to verify signature without padding"); + return ret; + } + if (data_len > rsa->pub.size) { + error_setg(errp, "Data length %zu is greater than key size: %zu", + data_len, rsa->pub.size); + return ret; + } + if (sig_len < rsa->pub.size) { + error_setg(errp, "Signature length %zu is greater than key size: %zu", + sig_len, rsa->pub.size); + return ret; + } + + nettle_mpz_init_set_str_256_u(s, sig_len, sig); + switch (rsa->hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + rv = rsa_md5_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA1: + rv = rsa_sha1_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA256: + rv = rsa_sha256_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA512: + rv = rsa_sha512_verify_digest(&rsa->pub, data, s); + break; + + default: + error_setg(errp, "Unsupported hash algorithm: %d", rsa->hash_alg); + goto cleanup; + } + + if (rv != 1) { + error_setg(errp, "Failed to verify signature"); + goto cleanup; + } + ret = 0; + +cleanup: + mpz_clear(s); + + return ret; +} + +QCryptoAkCipherDriver nettle_rsa = { + .encrypt = qcrypto_nettle_rsa_encrypt, + .decrypt = qcrypto_nettle_rsa_decrypt, + .sign = qcrypto_nettle_rsa_sign, + .verify = qcrypto_nettle_rsa_verify, + .free = qcrypto_nettle_rsa_free, +}; + +static QCryptoAkCipher *qcrypto_nettle_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + QCryptoNettleRSA *rsa = g_new0(QCryptoNettleRSA, 1); + + rsa->padding_alg = opt->padding_alg; + rsa->hash_alg = opt->hash_alg; + rsa->akcipher.driver = &nettle_rsa; + rsa_public_key_init(&rsa->pub); + rsa_private_key_init(&rsa->priv); + + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + if (qcrypt_nettle_parse_rsa_private_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + if (qcrypt_nettle_parse_rsa_public_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + default: + error_setg(errp, "Unknown akcipher key type %d", type); + goto error; + } + + return (QCryptoAkCipher *)rsa; + +error: + qcrypto_nettle_rsa_free((QCryptoAkCipher *)rsa); + return NULL; +} + + +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + switch (opts->u.rsa.padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + switch (opts->u.rsa.hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA512: + return true; + + default: + return false; + } + + case QCRYPTO_RSA_PADDING_ALG_RAW: + default: + return false; + } + break; + + default: + return false; + } +} diff --git a/crypto/akcipher.c b/crypto/akcipher.c new file mode 100644 index 000000000000..e4bbc6e5f1a6 --- /dev/null +++ b/crypto/akcipher.c @@ -0,0 +1,126 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: zhenwei pi + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "crypto/akcipher.h" +#include "akcipherpriv.h" +#include "der.h" +#include "rsakey.h" + +#if defined(CONFIG_GCRYPT) +#include "akcipher-gcrypt.c.inc" +#elif defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) +#include "akcipher-nettle.c.inc" +#else +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + QCryptoAkCipher *akcipher = NULL; + + return akcipher; +} + +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) +{ + return false; +} +#endif + +int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->encrypt(akcipher, in, in_len, out, out_len, errp); +} + +int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->decrypt(akcipher, in, in_len, out, out_len, errp); +} + +int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->sign(akcipher, in, in_len, out, out_len, errp); +} + +int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->verify(akcipher, in, in_len, in2, in2_len, errp); +} + +int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_plaintext_len; +} + +int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_ciphertext_len; +} + +int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_signature_len; +} + +int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_dgst_len; +} + +void qcrypto_akcipher_free(QCryptoAkCipher *akcipher) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + drv->free(akcipher); +} + +int qcrypto_akcipher_export_p8info(const QCryptoAkCipherOptions *opts, + uint8_t *key, size_t keylen, + uint8_t **dst, size_t *dst_len, + Error **errp) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + qcrypto_akcipher_rsakey_export_p8info(key, keylen, dst, dst_len); + return 0; + + default: + error_setg(errp, "Unsupported algorithm: %u", opts->alg); + return -1; + } +} diff --git a/crypto/akcipherpriv.h b/crypto/akcipherpriv.h new file mode 100644 index 000000000000..739f639bcf26 --- /dev/null +++ b/crypto/akcipherpriv.h @@ -0,0 +1,55 @@ +/* + * QEMU Crypto asymmetric algorithms + * + * Copyright (c) 2022 Bytedance + * Author: zhenwei pi + * + * 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 QCRYPTO_AKCIPHERPRIV_H +#define QCRYPTO_AKCIPHERPRIV_H + +#include "qapi/qapi-types-crypto.h" + +typedef struct QCryptoAkCipherDriver QCryptoAkCipherDriver; + +struct QCryptoAkCipher { + QCryptoAkCipherAlgorithm alg; + QCryptoAkCipherKeyType type; + int max_plaintext_len; + int max_ciphertext_len; + int max_signature_len; + int max_dgst_len; + QCryptoAkCipherDriver *driver; +}; + +struct QCryptoAkCipherDriver { + int (*encrypt)(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + int (*decrypt)(QCryptoAkCipher *akcipher, + const void *out, size_t out_len, + void *in, size_t in_len, Error **errp); + int (*sign)(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + int (*verify)(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, Error **errp); + void (*free)(QCryptoAkCipher *akcipher); +}; + +#endif /* QCRYPTO_AKCIPHER_H */ diff --git a/crypto/block-luks-priv.h b/crypto/block-luks-priv.h new file mode 100644 index 000000000000..90a20d432bc1 --- /dev/null +++ b/crypto/block-luks-priv.h @@ -0,0 +1,143 @@ +/* + * QEMU Crypto block device encryption LUKS format + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/bswap.h" + +#include "block-luks.h" + +#include "crypto/hash.h" +#include "crypto/afsplit.h" +#include "crypto/pbkdf.h" +#include "crypto/secret.h" +#include "crypto/random.h" +#include "qemu/uuid.h" + +#include "qemu/coroutine.h" +#include "qemu/bitmap.h" + +/* + * Reference for the LUKS format implemented here is + * + * docs/on-disk-format.pdf + * + * in 'cryptsetup' package source code + * + * This file implements the 1.2.1 specification, dated + * Oct 16, 2011. + */ + +typedef struct QCryptoBlockLUKSHeader QCryptoBlockLUKSHeader; +typedef struct QCryptoBlockLUKSKeySlot QCryptoBlockLUKSKeySlot; + + +/* The following constants are all defined by the LUKS spec */ +#define QCRYPTO_BLOCK_LUKS_VERSION 1 + +#define QCRYPTO_BLOCK_LUKS_MAGIC_LEN 6 +#define QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN 32 +#define QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN 32 +#define QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN 32 +#define QCRYPTO_BLOCK_LUKS_DIGEST_LEN 20 +#define QCRYPTO_BLOCK_LUKS_SALT_LEN 32 +#define QCRYPTO_BLOCK_LUKS_UUID_LEN 40 +#define QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS 8 +#define QCRYPTO_BLOCK_LUKS_STRIPES 4000 +#define QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS 1000 +#define QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS 1000 +#define QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET 4096 + +#define QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED 0x0000DEAD +#define QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED 0x00AC71F3 + +#define QCRYPTO_BLOCK_LUKS_SECTOR_SIZE 512LL + +#define QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS 2000 +#define QCRYPTO_BLOCK_LUKS_ERASE_ITERATIONS 40 + +static const char qcrypto_block_luks_magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN] = { + 'L', 'U', 'K', 'S', 0xBA, 0xBE +}; + +/* + * This struct is written to disk in big-endian format, + * but operated upon in native-endian format. + */ +struct QCryptoBlockLUKSKeySlot { + /* state of keyslot, enabled/disable */ + uint32_t active; + /* iterations for PBKDF2 */ + uint32_t iterations; + /* salt for PBKDF2 */ + uint8_t salt[QCRYPTO_BLOCK_LUKS_SALT_LEN]; + /* start sector of key material */ + uint32_t key_offset_sector; + /* number of anti-forensic stripes */ + uint32_t stripes; +}; + +/* + * This struct is written to disk in big-endian format, + * but operated upon in native-endian format. + */ +struct QCryptoBlockLUKSHeader { + /* 'L', 'U', 'K', 'S', '0xBA', '0xBE' */ + char magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN]; + + /* LUKS version, currently 1 */ + uint16_t version; + + /* cipher name specification (aes, etc) */ + char cipher_name[QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN]; + + /* cipher mode specification (cbc-plain, xts-essiv:sha256, etc) */ + char cipher_mode[QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN]; + + /* hash specification (sha256, etc) */ + char hash_spec[QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN]; + + /* start offset of the volume data (in 512 byte sectors) */ + uint32_t payload_offset_sector; + + /* Number of key bytes */ + uint32_t master_key_len; + + /* master key checksum after PBKDF2 */ + uint8_t master_key_digest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN]; + + /* salt for master key PBKDF2 */ + uint8_t master_key_salt[QCRYPTO_BLOCK_LUKS_SALT_LEN]; + + /* iterations for master key PBKDF2 */ + uint32_t master_key_iterations; + + /* UUID of the partition in standard ASCII representation */ + uint8_t uuid[QCRYPTO_BLOCK_LUKS_UUID_LEN]; + + /* key slots */ + QCryptoBlockLUKSKeySlot key_slots[QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS]; +}; + + +void +qcrypto_block_luks_to_disk_endian(QCryptoBlockLUKSHeader *hdr); +void +qcrypto_block_luks_from_disk_endian(QCryptoBlockLUKSHeader *hdr); diff --git a/crypto/block-luks.c b/crypto/block-luks.c index fe8f04ffb294..ff9e3945d1b9 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -23,6 +23,7 @@ #include "qemu/bswap.h" #include "block-luks.h" +#include "block-luks-priv.h" #include "crypto/hash.h" #include "crypto/afsplit.h" @@ -46,37 +47,6 @@ */ typedef struct QCryptoBlockLUKS QCryptoBlockLUKS; -typedef struct QCryptoBlockLUKSHeader QCryptoBlockLUKSHeader; -typedef struct QCryptoBlockLUKSKeySlot QCryptoBlockLUKSKeySlot; - - -/* The following constants are all defined by the LUKS spec */ -#define QCRYPTO_BLOCK_LUKS_VERSION 1 - -#define QCRYPTO_BLOCK_LUKS_MAGIC_LEN 6 -#define QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN 32 -#define QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN 32 -#define QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN 32 -#define QCRYPTO_BLOCK_LUKS_DIGEST_LEN 20 -#define QCRYPTO_BLOCK_LUKS_SALT_LEN 32 -#define QCRYPTO_BLOCK_LUKS_UUID_LEN 40 -#define QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS 8 -#define QCRYPTO_BLOCK_LUKS_STRIPES 4000 -#define QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS 1000 -#define QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS 1000 -#define QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET 4096 - -#define QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED 0x0000DEAD -#define QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED 0x00AC71F3 - -#define QCRYPTO_BLOCK_LUKS_SECTOR_SIZE 512LL - -#define QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS 2000 -#define QCRYPTO_BLOCK_LUKS_ERASE_ITERATIONS 40 - -static const char qcrypto_block_luks_magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN] = { - 'L', 'U', 'K', 'S', 0xBA, 0xBE -}; typedef struct QCryptoBlockLUKSNameMap QCryptoBlockLUKSNameMap; struct QCryptoBlockLUKSNameMap { @@ -134,69 +104,7 @@ qcrypto_block_luks_cipher_name_map[] = { { "twofish", qcrypto_block_luks_cipher_size_map_twofish }, }; - -/* - * This struct is written to disk in big-endian format, - * but operated upon in native-endian format. - */ -struct QCryptoBlockLUKSKeySlot { - /* state of keyslot, enabled/disable */ - uint32_t active; - /* iterations for PBKDF2 */ - uint32_t iterations; - /* salt for PBKDF2 */ - uint8_t salt[QCRYPTO_BLOCK_LUKS_SALT_LEN]; - /* start sector of key material */ - uint32_t key_offset_sector; - /* number of anti-forensic stripes */ - uint32_t stripes; -}; - QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSKeySlot) != 48); - - -/* - * This struct is written to disk in big-endian format, - * but operated upon in native-endian format. - */ -struct QCryptoBlockLUKSHeader { - /* 'L', 'U', 'K', 'S', '0xBA', '0xBE' */ - char magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN]; - - /* LUKS version, currently 1 */ - uint16_t version; - - /* cipher name specification (aes, etc) */ - char cipher_name[QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN]; - - /* cipher mode specification (cbc-plain, xts-essiv:sha256, etc) */ - char cipher_mode[QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN]; - - /* hash specification (sha256, etc) */ - char hash_spec[QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN]; - - /* start offset of the volume data (in 512 byte sectors) */ - uint32_t payload_offset_sector; - - /* Number of key bytes */ - uint32_t master_key_len; - - /* master key checksum after PBKDF2 */ - uint8_t master_key_digest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN]; - - /* salt for master key PBKDF2 */ - uint8_t master_key_salt[QCRYPTO_BLOCK_LUKS_SALT_LEN]; - - /* iterations for master key PBKDF2 */ - uint32_t master_key_iterations; - - /* UUID of the partition in standard ASCII representation */ - uint8_t uuid[QCRYPTO_BLOCK_LUKS_UUID_LEN]; - - /* key slots */ - QCryptoBlockLUKSKeySlot key_slots[QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS]; -}; - QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSHeader) != 592); @@ -254,7 +162,7 @@ static int qcrypto_block_luks_cipher_name_lookup(const char *name, } } - error_setg(errp, "Algorithm %s with key size %d bytes not supported", + error_setg(errp, "Algorithm '%s' with key size %d bytes not supported", name, key_bytes); return 0; } @@ -290,7 +198,7 @@ static int qcrypto_block_luks_name_lookup(const char *name, int ret = qapi_enum_parse(map, name, -1, NULL); if (ret < 0) { - error_setg(errp, "%s %s not supported", type, name); + error_setg(errp, "%s '%s' not supported", type, name); return 0; } return ret; @@ -440,6 +348,51 @@ qcrypto_block_luks_splitkeylen_sectors(const QCryptoBlockLUKS *luks, return ROUND_UP(splitkeylen_sectors, header_sectors); } + +void +qcrypto_block_luks_to_disk_endian(QCryptoBlockLUKSHeader *hdr) +{ + size_t i; + + /* + * Everything on disk uses Big Endian (tm), so flip header fields + * before writing them + */ + cpu_to_be16s(&hdr->version); + cpu_to_be32s(&hdr->payload_offset_sector); + cpu_to_be32s(&hdr->master_key_len); + cpu_to_be32s(&hdr->master_key_iterations); + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + cpu_to_be32s(&hdr->key_slots[i].active); + cpu_to_be32s(&hdr->key_slots[i].iterations); + cpu_to_be32s(&hdr->key_slots[i].key_offset_sector); + cpu_to_be32s(&hdr->key_slots[i].stripes); + } +} + +void +qcrypto_block_luks_from_disk_endian(QCryptoBlockLUKSHeader *hdr) +{ + size_t i; + + /* + * The header is always stored in big-endian format, so + * convert everything to native + */ + be16_to_cpus(&hdr->version); + be32_to_cpus(&hdr->payload_offset_sector); + be32_to_cpus(&hdr->master_key_len); + be32_to_cpus(&hdr->master_key_iterations); + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + be32_to_cpus(&hdr->key_slots[i].active); + be32_to_cpus(&hdr->key_slots[i].iterations); + be32_to_cpus(&hdr->key_slots[i].key_offset_sector); + be32_to_cpus(&hdr->key_slots[i].stripes); + } +} + /* * Stores the main LUKS header, taking care of endianess */ @@ -451,28 +404,13 @@ qcrypto_block_luks_store_header(QCryptoBlock *block, { const QCryptoBlockLUKS *luks = block->opaque; Error *local_err = NULL; - size_t i; g_autofree QCryptoBlockLUKSHeader *hdr_copy = NULL; /* Create a copy of the header */ hdr_copy = g_new0(QCryptoBlockLUKSHeader, 1); memcpy(hdr_copy, &luks->header, sizeof(QCryptoBlockLUKSHeader)); - /* - * Everything on disk uses Big Endian (tm), so flip header fields - * before writing them - */ - cpu_to_be16s(&hdr_copy->version); - cpu_to_be32s(&hdr_copy->payload_offset_sector); - cpu_to_be32s(&hdr_copy->master_key_len); - cpu_to_be32s(&hdr_copy->master_key_iterations); - - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { - cpu_to_be32s(&hdr_copy->key_slots[i].active); - cpu_to_be32s(&hdr_copy->key_slots[i].iterations); - cpu_to_be32s(&hdr_copy->key_slots[i].key_offset_sector); - cpu_to_be32s(&hdr_copy->key_slots[i].stripes); - } + qcrypto_block_luks_to_disk_endian(hdr_copy); /* Write out the partition header and key slot headers */ writefunc(block, 0, (const uint8_t *)hdr_copy, sizeof(*hdr_copy), @@ -495,8 +433,7 @@ qcrypto_block_luks_load_header(QCryptoBlock *block, void *opaque, Error **errp) { - ssize_t rv; - size_t i; + int rv; QCryptoBlockLUKS *luks = block->opaque; /* @@ -512,21 +449,7 @@ qcrypto_block_luks_load_header(QCryptoBlock *block, return rv; } - /* - * The header is always stored in big-endian format, so - * convert everything to native - */ - be16_to_cpus(&luks->header.version); - be32_to_cpus(&luks->header.payload_offset_sector); - be32_to_cpus(&luks->header.master_key_len); - be32_to_cpus(&luks->header.master_key_iterations); - - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { - be32_to_cpus(&luks->header.key_slots[i].active); - be32_to_cpus(&luks->header.key_slots[i].iterations); - be32_to_cpus(&luks->header.key_slots[i].key_offset_sector); - be32_to_cpus(&luks->header.key_slots[i].stripes); - } + qcrypto_block_luks_from_disk_endian(&luks->header); return 0; } @@ -554,6 +477,36 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) return -1; } + if (!memchr(luks->header.cipher_name, '\0', + sizeof(luks->header.cipher_name))) { + error_setg(errp, "LUKS header cipher name is not NUL terminated"); + return -1; + } + + if (!memchr(luks->header.cipher_mode, '\0', + sizeof(luks->header.cipher_mode))) { + error_setg(errp, "LUKS header cipher mode is not NUL terminated"); + return -1; + } + + if (!memchr(luks->header.hash_spec, '\0', + sizeof(luks->header.hash_spec))) { + error_setg(errp, "LUKS header hash spec is not NUL terminated"); + return -1; + } + + if (luks->header.payload_offset_sector < + DIV_ROUND_UP(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET, + QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) { + error_setg(errp, "LUKS payload is overlapping with the header"); + return -1; + } + + if (luks->header.master_key_iterations == 0) { + error_setg(errp, "LUKS key iteration count is zero"); + return -1; + } + /* Check all keyslots for corruption */ for (i = 0 ; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS ; i++) { @@ -564,8 +517,9 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) header_sectors, slot1->stripes); - if (slot1->stripes == 0) { - error_setg(errp, "Keyslot %zu is corrupted (stripes == 0)", i); + if (slot1->stripes != QCRYPTO_BLOCK_LUKS_STRIPES) { + error_setg(errp, "Keyslot %zu is corrupted (stripes %d != %d)", + i, slot1->stripes, QCRYPTO_BLOCK_LUKS_STRIPES); return -1; } @@ -576,6 +530,20 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) return -1; } + if (slot1->active == QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED && + slot1->iterations == 0) { + error_setg(errp, "Keyslot %zu iteration count is zero", i); + return -1; + } + + if (start1 < DIV_ROUND_UP(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET, + QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) { + error_setg(errp, + "Keyslot %zu is overlapping with the LUKS header", + i); + return -1; + } + if (start1 + len1 > luks->header.payload_offset_sector) { error_setg(errp, "Keyslot %zu is overlapping with the encrypted payload", @@ -624,7 +592,7 @@ qcrypto_block_luks_parse_header(QCryptoBlockLUKS *luks, Error **errp) */ ivgen_name = strchr(cipher_mode, '-'); if (!ivgen_name) { - error_setg(errp, "Unexpected cipher mode string format %s", + error_setg(errp, "Unexpected cipher mode string format '%s'", luks->header.cipher_mode); return -1; } @@ -856,7 +824,7 @@ qcrypto_block_luks_store_key(QCryptoBlock *block, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, splitkey, splitkeylen, opaque, - errp) != splitkeylen) { + errp) < 0) { goto cleanup; } @@ -903,7 +871,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, g_autofree uint8_t *splitkey = NULL; size_t splitkeylen; g_autofree uint8_t *possiblekey = NULL; - ssize_t rv; + int rv; g_autoptr(QCryptoCipher) cipher = NULL; uint8_t keydigest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN]; g_autoptr(QCryptoIVGen) ivgen = NULL; @@ -1193,7 +1161,7 @@ qcrypto_block_luks_erase_key(QCryptoBlock *block, garbagesplitkey, splitkeylen, opaque, - &local_err) != splitkeylen) { + &local_err) < 0) { error_propagate(errp, local_err); return -1; } @@ -1629,13 +1597,13 @@ qcrypto_block_luks_amend_add_keyslot(QCryptoBlock *block, g_autofree char *new_password = NULL; g_autofree uint8_t *master_key = NULL; - char *secret = opts_luks->has_secret ? opts_luks->secret : luks->secret; + char *secret = opts_luks->secret ?: luks->secret; - if (!opts_luks->has_new_secret) { + if (!opts_luks->new_secret) { error_setg(errp, "'new-secret' is required to activate a keyslot"); return -1; } - if (opts_luks->has_old_secret) { + if (opts_luks->old_secret) { error_setg(errp, "'old-secret' must not be given when activating keyslots"); return -1; @@ -1709,7 +1677,7 @@ qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block, g_autofree uint8_t *tmpkey = NULL; g_autofree char *old_password = NULL; - if (opts_luks->has_new_secret) { + if (opts_luks->new_secret) { error_setg(errp, "'new-secret' must not be given when erasing keyslots"); return -1; @@ -1719,14 +1687,14 @@ qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block, "'iter-time' must not be given when erasing keyslots"); return -1; } - if (opts_luks->has_secret) { + if (opts_luks->secret) { error_setg(errp, "'secret' must not be given when erasing keyslots"); return -1; } /* Load the old password if given */ - if (opts_luks->has_old_secret) { + if (opts_luks->old_secret) { old_password = qcrypto_secret_lookup_as_utf8(opts_luks->old_secret, errp); if (!old_password) { @@ -1751,7 +1719,7 @@ qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block, return -1; } - if (opts_luks->has_old_secret) { + if (opts_luks->old_secret) { int rv = qcrypto_block_luks_load_key(block, keyslot, old_password, @@ -1793,7 +1761,7 @@ qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block, } /* Erase all keyslots that match the given old password */ - } else if (opts_luks->has_old_secret) { + } else if (opts_luks->old_secret) { unsigned long slots_to_erase_bitmap = 0; size_t i; diff --git a/crypto/block.c b/crypto/block.c index eb057948b591..7bb4b74a37cd 100644 --- a/crypto/block.c +++ b/crypto/block.c @@ -115,7 +115,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, } -static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block, +static int qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block, size_t headerlen, void *opaque, Error **errp) { size_t *headerlenp = opaque; @@ -126,12 +126,12 @@ static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block, } -static ssize_t qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block, +static int qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block, size_t offset, const uint8_t *buf, size_t buflen, void *opaque, Error **errp) { /* Discard the bytes, we're not actually writing to an image */ - return buflen; + return 0; } diff --git a/crypto/cipher-afalg.c b/crypto/cipher-afalg.c index c55cd28bf01c..3df8fc54c051 100644 --- a/crypto/cipher-afalg.c +++ b/crypto/cipher-afalg.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" #include "qemu/sockets.h" -#include "qemu-common.h" #include "qapi/error.h" #include "crypto/cipher.h" #include "cipherpriv.h" diff --git a/crypto/der.c b/crypto/der.c new file mode 100644 index 000000000000..dab3fe4f2432 --- /dev/null +++ b/crypto/der.c @@ -0,0 +1,452 @@ +/* + * QEMU Crypto ASN.1 DER decoder + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "crypto/der.h" + +typedef struct QCryptoDerEncodeNode { + uint8_t tag; + struct QCryptoDerEncodeNode *parent; + struct QCryptoDerEncodeNode *next; + /* for constructed type, data is null */ + const uint8_t *data; + size_t dlen; +} QCryptoDerEncodeNode; + +typedef struct QCryptoEncodeContext { + QCryptoDerEncodeNode root; + QCryptoDerEncodeNode *current_parent; + QCryptoDerEncodeNode *tail; +} QCryptoEncodeContext; + +enum QCryptoDERTypeTag { + QCRYPTO_DER_TYPE_TAG_BOOL = 0x1, + QCRYPTO_DER_TYPE_TAG_INT = 0x2, + QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3, + QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4, + QCRYPTO_DER_TYPE_TAG_NULL = 0x5, + QCRYPTO_DER_TYPE_TAG_OID = 0x6, + QCRYPTO_DER_TYPE_TAG_SEQ = 0x10, + QCRYPTO_DER_TYPE_TAG_SET = 0x11, +}; + +enum QCryptoDERTagClass { + QCRYPTO_DER_TAG_CLASS_UNIV = 0x0, + QCRYPTO_DER_TAG_CLASS_APPL = 0x1, + QCRYPTO_DER_TAG_CLASS_CONT = 0x2, + QCRYPTO_DER_TAG_CLASS_PRIV = 0x3, +}; + +enum QCryptoDERTagEnc { + QCRYPTO_DER_TAG_ENC_PRIM = 0x0, + QCRYPTO_DER_TAG_ENC_CONS = 0x1, +}; + +#define QCRYPTO_DER_TAG_ENC_MASK 0x20 +#define QCRYPTO_DER_TAG_ENC_SHIFT 5 + +#define QCRYPTO_DER_TAG_CLASS_MASK 0xc0 +#define QCRYPTO_DER_TAG_CLASS_SHIFT 6 + +#define QCRYPTO_DER_TAG_VAL_MASK 0x1f +#define QCRYPTO_DER_SHORT_LEN_MASK 0x80 + +#define QCRYPTO_DER_TAG(class, enc, val) \ + (((class) << QCRYPTO_DER_TAG_CLASS_SHIFT) | \ + ((enc) << QCRYPTO_DER_TAG_ENC_SHIFT) | (val)) + +/** + * qcrypto_der_encode_length: + * @src_len: the length of source data + * @dst: distination to save the encoded 'length', if dst is NULL, only compute + * the expected buffer size in bytes. + * @dst_len: output parameter, indicates how many bytes wrote. + * + * Encode the 'length' part of TLV tuple. + */ +static void qcrypto_der_encode_length(size_t src_len, + uint8_t *dst, size_t *dst_len) +{ + size_t max_length = 0xFF; + uint8_t length_bytes = 0, header_byte; + + if (src_len < QCRYPTO_DER_SHORT_LEN_MASK) { + header_byte = src_len; + *dst_len = 1; + } else { + for (length_bytes = 1; max_length < src_len; length_bytes++) { + max_length = (max_length << 8) + max_length; + } + header_byte = length_bytes; + header_byte |= QCRYPTO_DER_SHORT_LEN_MASK; + *dst_len = length_bytes + 1; + } + if (!dst) { + return; + } + *dst++ = header_byte; + /* Bigendian length bytes */ + for (; length_bytes > 0; length_bytes--) { + *dst++ = ((src_len >> (length_bytes - 1) * 8) & 0xFF); + } +} + +static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen) +{ + return **data; +} + +static void qcrypto_der_cut_nbytes(const uint8_t **data, + size_t *dlen, + size_t nbytes) +{ + *data += nbytes; + *dlen -= nbytes; +} + +static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen) +{ + uint8_t val = qcrypto_der_peek_byte(data, dlen); + + qcrypto_der_cut_nbytes(data, dlen, 1); + + return val; +} + +static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx, + const uint8_t *value, size_t vlen, + Error **errp) +{ + if (!cb) { + return 0; + } + + return cb(ctx, value, vlen, errp); +} + +static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, + Error **errp) +{ + const uint8_t *value; + size_t vlen = 0; + uint8_t byte_count = qcrypto_der_cut_byte(data, dlen); + + /* short format of definite-length */ + if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) { + if (byte_count > *dlen) { + error_setg(errp, "Invalid content length: %u", byte_count); + return -1; + } + + value = *data; + vlen = byte_count; + qcrypto_der_cut_nbytes(data, dlen, vlen); + + if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) { + return -1; + } + return vlen; + } + + /* Ignore highest bit */ + byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK; + + /* + * size_t is enough to store the value of length, although the DER + * encoding standard supports larger length. + */ + if (byte_count > sizeof(size_t)) { + error_setg(errp, "Invalid byte count of content length: %u", + byte_count); + return -1; + } + + if (byte_count > *dlen) { + error_setg(errp, "Invalid content length: %u", byte_count); + return -1; + } + while (byte_count--) { + vlen <<= 8; + vlen += qcrypto_der_cut_byte(data, dlen); + } + + if (vlen > *dlen) { + error_setg(errp, "Invalid content length: %zu", vlen); + return -1; + } + + value = *data; + qcrypto_der_cut_nbytes(data, dlen, vlen); + + if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) { + return -1; + } + return vlen; +} + +static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, + Error **errp) +{ + uint8_t val; + if (*dlen < 1) { + error_setg(errp, "Need more data"); + return -1; + } + val = qcrypto_der_peek_byte(data, dlen); + + /* must use definite length format */ + if (val == QCRYPTO_DER_SHORT_LEN_MASK) { + error_setg(errp, "Only definite length format is allowed"); + return -1; + } + + return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp); +} + +static int qcrypto_der_decode_tlv(const uint8_t expected_tag, + const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, + void *ctx, Error **errp) +{ + const uint8_t *saved_data = *data; + size_t saved_dlen = *dlen; + uint8_t tag; + int data_length; + + if (*dlen < 1) { + error_setg(errp, "Need more data"); + return -1; + } + tag = qcrypto_der_cut_byte(data, dlen); + if (tag != expected_tag) { + error_setg(errp, "Unexpected tag: expected: %u, actual: %u", + expected_tag, tag); + goto error; + } + + data_length = qcrypto_der_extract_data(data, dlen, cb, ctx, errp); + if (data_length < 0) { + goto error; + } + return data_length; + +error: + *data = saved_data; + *dlen = saved_dlen; + return -1; +} + +int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + const uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_INT); + return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_CONS, + QCRYPTO_DER_TYPE_TAG_SEQ); + return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_octet_str(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_OCT_STR); + return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_bit_str(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_BIT_STR); + return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_oid(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_OID); + return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_ctx_tag(const uint8_t **data, size_t *dlen, int tag_id, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_CONT, + QCRYPTO_DER_TAG_ENC_CONS, + tag_id); + return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp); +} + +static void qcrypto_der_encode_prim(QCryptoEncodeContext *ctx, uint8_t tag, + const uint8_t *data, size_t dlen) +{ + QCryptoDerEncodeNode *node = g_new0(QCryptoDerEncodeNode, 1); + size_t nbytes_len; + + node->tag = tag; + node->data = data; + node->dlen = dlen; + node->parent = ctx->current_parent; + + qcrypto_der_encode_length(dlen, NULL, &nbytes_len); + /* 1 byte for Tag, nbyte_len for Length, and dlen for Value */ + node->parent->dlen += 1 + nbytes_len + dlen; + + ctx->tail->next = node; + ctx->tail = node; +} + +QCryptoEncodeContext *qcrypto_der_encode_ctx_new(void) +{ + QCryptoEncodeContext *ctx = g_new0(QCryptoEncodeContext, 1); + ctx->current_parent = &ctx->root; + ctx->tail = &ctx->root; + return ctx; +} + +static void qcrypto_der_encode_cons_begin(QCryptoEncodeContext *ctx, + uint8_t tag) +{ + QCryptoDerEncodeNode *node = g_new0(QCryptoDerEncodeNode, 1); + + node->tag = tag; + node->parent = ctx->current_parent; + ctx->current_parent = node; + ctx->tail->next = node; + ctx->tail = node; +} + +static void qcrypto_der_encode_cons_end(QCryptoEncodeContext *ctx) +{ + QCryptoDerEncodeNode *cons_node = ctx->current_parent; + size_t nbytes_len; + + qcrypto_der_encode_length(cons_node->dlen, NULL, &nbytes_len); + /* 1 byte for Tag, nbyte_len for Length, and dlen for Value */ + cons_node->parent->dlen += 1 + nbytes_len + cons_node->dlen; + ctx->current_parent = cons_node->parent; +} + +void qcrypto_der_encode_seq_begin(QCryptoEncodeContext *ctx) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_CONS, + QCRYPTO_DER_TYPE_TAG_SEQ); + qcrypto_der_encode_cons_begin(ctx, tag); +} + +void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx) +{ + qcrypto_der_encode_cons_end(ctx); +} + +void qcrypto_der_encode_oid(QCryptoEncodeContext *ctx, + const uint8_t *src, size_t src_len) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_OID); + qcrypto_der_encode_prim(ctx, tag, src, src_len); +} + +void qcrypto_der_encode_int(QCryptoEncodeContext *ctx, + const uint8_t *src, size_t src_len) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_INT); + qcrypto_der_encode_prim(ctx, tag, src, src_len); +} + +void qcrypto_der_encode_null(QCryptoEncodeContext *ctx) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_NULL); + qcrypto_der_encode_prim(ctx, tag, NULL, 0); +} + +void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx, + const uint8_t *src, size_t src_len) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_OCT_STR); + qcrypto_der_encode_prim(ctx, tag, src, src_len); +} + +void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx) +{ + uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV, + QCRYPTO_DER_TAG_ENC_PRIM, + QCRYPTO_DER_TYPE_TAG_OCT_STR); + qcrypto_der_encode_cons_begin(ctx, tag); +} + +void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx) +{ + qcrypto_der_encode_cons_end(ctx); +} + +size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx) +{ + return ctx->root.dlen; +} + +void qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext *ctx, + uint8_t *dst) +{ + QCryptoDerEncodeNode *node, *prev; + size_t len; + + for (prev = &ctx->root; + (node = prev->next) && (prev->next = node->next, 1);) { + /* Tag */ + *dst++ = node->tag; + + /* Length */ + qcrypto_der_encode_length(node->dlen, dst, &len); + dst += len; + + /* Value */ + if (node->data) { + memcpy(dst, node->data, node->dlen); + dst += node->dlen; + } + g_free(node); + } + g_free(ctx); +} diff --git a/crypto/der.h b/crypto/der.h new file mode 100644 index 000000000000..0e895bbeec2f --- /dev/null +++ b/crypto/der.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 QCRYPTO_ASN1_DECODER_H +#define QCRYPTO_ASN1_DECODER_H + +#include "qapi/error.h" + +typedef struct QCryptoEncodeContext QCryptoEncodeContext; + +/* rsaEncryption: 1.2.840.113549.1.1.1 */ +#define QCRYPTO_OID_rsaEncryption "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01" + +/* Simple decoder used to parse DER encoded rsa keys. */ + +/** + * @opaque: user context. + * @value: the starting address of |value| part of 'Tag-Length-Value' pattern. + * @vlen: length of the |value|. + * Returns: 0 for success, any other value is considered an error. + */ +typedef int (*QCryptoDERDecodeCb) (void *opaque, const uint8_t *value, + size_t vlen, Error **errp); + +/** + * qcrypto_der_decode_int: + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Decode integer from DER-encoded data. + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded INTEGER will be returned. Otherwise, -1 is + * returned and the valued of *data and *dlen keep unchanged. + */ +int qcrypto_der_decode_int(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); +/** + * qcrypto_der_decode_seq: + * + * Decode sequence from DER-encoded data, similar with der_decode_int. + * + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded SEQUENCE will be returned. Otherwise, -1 is + * returned and the valued of *data and *dlen keep unchanged. + */ +int qcrypto_der_decode_seq(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + +/** + * qcrypto_der_decode_oid: + * + * Decode OID from DER-encoded data, similar with der_decode_int. + * + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded OID will be returned. Otherwise, -1 is + * returned and the valued of *data and *dlen keep unchanged. + */ +int qcrypto_der_decode_oid(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + +/** + * qcrypto_der_decode_octet_str: + * + * Decode OCTET STRING from DER-encoded data, similar with der_decode_int. + * + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded OCTET STRING will be returned. Otherwise, -1 is + * returned and the valued of *data and *dlen keep unchanged. + */ +int qcrypto_der_decode_octet_str(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + +/** + * qcrypto_der_decode_bit_str: + * + * Decode BIT STRING from DER-encoded data, similar with der_decode_int. + * + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded BIT STRING will be returned. Otherwise, -1 is + * returned and the valued of *data and *dlen keep unchanged. + */ +int qcrypto_der_decode_bit_str(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + + +/** + * qcrypto_der_decode_ctx_tag: + * + * Decode context specific tag + * + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @tag: expected value of context specific tag + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded BIT STRING will be returned. Otherwise, -1 is + * returned and the valued of *data and *dlen keep unchanged. + */ +int qcrypto_der_decode_ctx_tag(const uint8_t **data, + size_t *dlen, int tag_id, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + +/** + * qcrypto_der_encode_ctx_new: + * + * Allocate a context used for der encoding. + */ +QCryptoEncodeContext *qcrypto_der_encode_ctx_new(void); + +/** + * qcrypto_der_encode_seq_begin: + * @ctx: the encode context. + * + * Start encoding a SEQUENCE for ctx. + * + */ +void qcrypto_der_encode_seq_begin(QCryptoEncodeContext *ctx); + +/** + * qcrypto_der_encode_seq_begin: + * @ctx: the encode context. + * + * Finish uencoding a SEQUENCE for ctx. + * + */ +void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx); + + +/** + * qcrypto_der_encode_oid: + * @ctx: the encode context. + * @src: the source data of oid, note it should be already encoded, this + * function only add tag and length part for it. + * + * Encode an oid into ctx. + */ +void qcrypto_der_encode_oid(QCryptoEncodeContext *ctx, + const uint8_t *src, size_t src_len); + +/** + * qcrypto_der_encode_int: + * @ctx: the encode context. + * @src: the source data of integer, note it should be already encoded, this + * function only add tag and length part for it. + * + * Encode an integer into ctx. + */ +void qcrypto_der_encode_int(QCryptoEncodeContext *ctx, + const uint8_t *src, size_t src_len); + +/** + * qcrypto_der_encode_null: + * @ctx: the encode context. + * + * Encode a null into ctx. + */ +void qcrypto_der_encode_null(QCryptoEncodeContext *ctx); + +/** + * qcrypto_der_encode_octet_str: + * @ctx: the encode context. + * @src: the source data of the octet string. + * + * Encode a octet string into ctx. + */ +void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx, + const uint8_t *src, size_t src_len); + +/** + * qcrypto_der_encode_octet_str_begin: + * @ctx: the encode context. + * + * Start encoding a octet string, All fields between + * qcrypto_der_encode_octet_str_begin and qcrypto_der_encode_octet_str_end + * are encoded as an octet string. This is useful when we need to encode a + * encoded SEQUNCE as OCTET STRING. + */ +void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx); + +/** + * qcrypto_der_encode_octet_str_end: + * @ctx: the encode context. + * + * Finish encoding a octet string, All fields between + * qcrypto_der_encode_octet_str_begin and qcrypto_der_encode_octet_str_end + * are encoded as an octet string. This is useful when we need to encode a + * encoded SEQUNCE as OCTET STRING. + */ +void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx); + +/** + * qcrypto_der_encode_ctx_buffer_len: + * @ctx: the encode context. + * + * Compute the expected buffer size to save all encoded things. + */ +size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx); + +/** + * qcrypto_der_encode_ctx_flush_and_free: + * @ctx: the encode context. + * @dst: the distination to save the encoded data, the length of dst should + * not less than qcrypto_der_encode_cxt_buffer_len + * + * Flush all encoded data into dst, then free ctx. + */ +void qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext *ctx, + uint8_t *dst); + +#endif /* QCRYPTO_ASN1_DECODER_H */ diff --git a/crypto/hash-afalg.c b/crypto/hash-afalg.c index 4ac18c7c1db7..3ebea392920d 100644 --- a/crypto/hash-afalg.c +++ b/crypto/hash-afalg.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "qemu-common.h" #include "qapi/error.h" #include "crypto/hash.h" #include "crypto/hmac.h" diff --git a/crypto/ivgen-plain.h b/crypto/ivgen-plain.h index 43db898809a0..ebae6acd0405 100644 --- a/crypto/ivgen-plain.h +++ b/crypto/ivgen-plain.h @@ -17,11 +17,11 @@ * License along with this library; if not, see . */ -#ifndef QCRYPTO_IVGEN_PLAIN_H__ -#define QCRYPTO_IVGEN_PLAIN_H__ +#ifndef QCRYPTO_IVGEN_PLAIN_H +#define QCRYPTO_IVGEN_PLAIN_H #include "ivgenpriv.h" extern struct QCryptoIVGenDriver qcrypto_ivgen_plain; -#endif /* QCRYPTO_IVGEN_PLAIN_H__ */ +#endif /* QCRYPTO_IVGEN_PLAIN_H */ diff --git a/crypto/meson.build b/crypto/meson.build index 19c44bea8980..5f03a30d342d 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -1,10 +1,12 @@ crypto_ss.add(genh) crypto_ss.add(files( 'afsplit.c', + 'akcipher.c', 'block-luks.c', 'block-qcow.c', 'block.c', 'cipher.c', + 'der.c', 'hash.c', 'hmac.c', 'ivgen-essiv.c', @@ -19,10 +21,14 @@ crypto_ss.add(files( 'tlscredspsk.c', 'tlscredsx509.c', 'tlssession.c', + 'rsakey.c', )) if nettle.found() crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c')) + if hogweed.found() + crypto_ss.add(gmp, hogweed) + endif if xts == 'private' crypto_ss.add(files('xts.c')) endif @@ -34,12 +40,15 @@ else crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c')) endif -crypto_ss.add(when: 'CONFIG_SECRET_KEYRING', if_true: files('secret_keyring.c')) +if have_keyring + crypto_ss.add(files('secret_keyring.c')) +endif if have_afalg crypto_ss.add(if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c')) endif crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) +util_ss.add(files('sm4.c')) util_ss.add(files('aes.c')) util_ss.add(files('init.c')) if gnutls.found() diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c index 3775ddc6c5a2..8d198c152cf2 100644 --- a/crypto/pbkdf.c +++ b/crypto/pbkdf.c @@ -24,6 +24,11 @@ #ifndef _WIN32 #include #endif +#ifdef CONFIG_DARWIN +#include +#include +#include +#endif static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms, @@ -45,6 +50,24 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms, /* QuadPart is units of 100ns and we want ms as unit */ *val_ms = thread_time.QuadPart / 10000ll; return 0; +#elif defined(CONFIG_DARWIN) + mach_port_t thread; + kern_return_t kr; + mach_msg_type_number_t count; + thread_basic_info_data_t info; + + thread = mach_thread_self(); + count = THREAD_BASIC_INFO_COUNT; + kr = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count); + mach_port_deallocate(mach_task_self(), thread); + if (kr != KERN_SUCCESS || (info.flags & TH_FLAGS_IDLE) != 0) { + error_setg_errno(errp, errno, "Unable to get thread CPU usage"); + return -1; + } + + *val_ms = ((info.user_time.seconds * 1000ll) + + (info.user_time.microseconds / 1000)); + return 0; #elif defined(RUSAGE_THREAD) struct rusage ru; if (getrusage(RUSAGE_THREAD, &ru) < 0) { diff --git a/crypto/rsakey-builtin.c.inc b/crypto/rsakey-builtin.c.inc new file mode 100644 index 000000000000..aeeacc8f9bfa --- /dev/null +++ b/crypto/rsakey-builtin.c.inc @@ -0,0 +1,200 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include "der.h" +#include "rsakey.h" + +static int extract_mpi(void *ctx, const uint8_t *value, + size_t vlen, Error **errp) +{ + QCryptoAkCipherMPI *mpi = (QCryptoAkCipherMPI *)ctx; + if (vlen == 0) { + error_setg(errp, "Empty mpi field"); + return -1; + } + mpi->data = g_memdup2(value, vlen); + mpi->len = vlen; + return 0; +} + +static int extract_version(void *ctx, const uint8_t *value, + size_t vlen, Error **errp) +{ + uint8_t *version = (uint8_t *)ctx; + if (vlen != 1 || *value > 1) { + error_setg(errp, "Invalid rsakey version"); + return -1; + } + *version = *value; + return 0; +} + +static int extract_seq_content(void *ctx, const uint8_t *value, + size_t vlen, Error **errp) +{ + const uint8_t **content = (const uint8_t **)ctx; + if (vlen == 0) { + error_setg(errp, "Empty sequence"); + return -1; + } + *content = value; + return 0; +} + +/** + * + * RsaPubKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_public_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + const uint8_t *seq; + size_t seq_length; + int decode_ret; + + decode_ret = qcrypto_der_decode_seq(&key, &keylen, + extract_seq_content, &seq, errp); + if (decode_ret < 0 || keylen != 0) { + goto error; + } + seq_length = decode_ret; + + if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->n, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->e, errp) < 0) { + goto error; + } + if (seq_length != 0) { + goto error; + } + + return rsa; + +error: + if (errp && !*errp) { + error_setg(errp, "Invalid RSA public key"); + } + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +/** + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * dp INTEGER + * dq INTEGER + * u INTEGER + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_private_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + uint8_t version; + const uint8_t *seq; + int decode_ret; + size_t seq_length; + + decode_ret = qcrypto_der_decode_seq(&key, &keylen, extract_seq_content, + &seq, errp); + if (decode_ret < 0 || keylen != 0) { + goto error; + } + seq_length = decode_ret; + + decode_ret = qcrypto_der_decode_int(&seq, &seq_length, extract_version, + &version, errp); + + if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->n, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->e, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->d, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->p, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->q, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dp, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dq, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->u, + errp) < 0) { + goto error; + } + + /** + * According to the standard, otherPrimeInfos must be present for version 1. + * There is no strict verification here, this is to be compatible with + * the unit test of the kernel. TODO: remove this until linux kernel's + * unit-test is fixed. + */ + if (version == 1 && seq_length != 0) { + if (qcrypto_der_decode_seq(&seq, &seq_length, NULL, NULL, errp) < 0) { + goto error; + } + if (seq_length != 0) { + goto error; + } + return rsa; + } + if (seq_length != 0) { + goto error; + } + + return rsa; + +error: + if (errp && !*errp) { + error_setg(errp, "Invalid RSA private key"); + } + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( + QCryptoAkCipherKeyType type, const uint8_t *key, + size_t keylen, Error **errp) +{ + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + return qcrypto_builtin_rsa_private_key_parse(key, keylen, errp); + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + return qcrypto_builtin_rsa_public_key_parse(key, keylen, errp); + + default: + error_setg(errp, "Unknown key type: %d", type); + return NULL; + } +} diff --git a/crypto/rsakey-nettle.c.inc b/crypto/rsakey-nettle.c.inc new file mode 100644 index 000000000000..cc49872e78d4 --- /dev/null +++ b/crypto/rsakey-nettle.c.inc @@ -0,0 +1,158 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "rsakey.h" + +static bool DumpMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi) +{ + mpi->data = g_memdup2(i->data, i->length); + mpi->len = i->length; + return true; +} + +static bool GetMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi) +{ + if (asn1_der_iterator_next(i) != ASN1_ITERATOR_PRIMITIVE || + i->type != ASN1_INTEGER) { + return false; + } + return DumpMPI(i, mpi); +} + +/** + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * dp INTEGER + * dq INTEGER + * u INTEGER + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_private_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + struct asn1_der_iterator i; + uint32_t version; + int tag; + + /* Parse entire struct */ + if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED || + i.type != ASN1_SEQUENCE || + asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE || + i.type != ASN1_INTEGER || + !asn1_der_get_uint32(&i, &version) || + version > 1 || + !GetMPI(&i, &rsa->n) || + !GetMPI(&i, &rsa->e) || + !GetMPI(&i, &rsa->d) || + !GetMPI(&i, &rsa->p) || + !GetMPI(&i, &rsa->q) || + !GetMPI(&i, &rsa->dp) || + !GetMPI(&i, &rsa->dq) || + !GetMPI(&i, &rsa->u)) { + goto error; + } + + if (version == 1) { + tag = asn1_der_iterator_next(&i); + /** + * According to the standard otherPrimeInfos must be present for + * version 1. There is no strict verification here, this is to be + * compatible with the unit test of the kernel. TODO: remove this + * until linux-kernel's unit-test is fixed; + */ + if (tag == ASN1_ITERATOR_END) { + return rsa; + } + if (tag != ASN1_ITERATOR_CONSTRUCTED || + i.type != ASN1_SEQUENCE) { + goto error; + } + } + + if (asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) { + goto error; + } + + return rsa; + +error: + error_setg(errp, "Failed to parse RSA private key"); + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +/** + * RsaPubKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_public_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + struct asn1_der_iterator i; + + if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED || + i.type != ASN1_SEQUENCE || + asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE || + !DumpMPI(&i, &rsa->n) || + !GetMPI(&i, &rsa->e) || + asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) { + goto error; + } + + return rsa; + +error: + error_setg(errp, "Failed to parse RSA public key"); + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( + QCryptoAkCipherKeyType type, const uint8_t *key, + size_t keylen, Error **errp) +{ + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + return qcrypto_nettle_rsa_private_key_parse(key, keylen, errp); + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + return qcrypto_nettle_rsa_public_key_parse(key, keylen, errp); + + default: + error_setg(errp, "Unknown key type: %d", type); + return NULL; + } +} diff --git a/crypto/rsakey.c b/crypto/rsakey.c new file mode 100644 index 000000000000..7d6f273aef6b --- /dev/null +++ b/crypto/rsakey.c @@ -0,0 +1,86 @@ +/* + * QEMU Crypto RSA key parser + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "der.h" +#include "rsakey.h" + +void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *rsa_key) +{ + if (!rsa_key) { + return; + } + g_free(rsa_key->n.data); + g_free(rsa_key->e.data); + g_free(rsa_key->d.data); + g_free(rsa_key->p.data); + g_free(rsa_key->q.data); + g_free(rsa_key->dp.data); + g_free(rsa_key->dq.data); + g_free(rsa_key->u.data); + g_free(rsa_key); +} + +/** + * PKCS#8 private key info for RSA + * + * PrivateKeyInfo ::= SEQUENCE { + * version INTEGER, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey OCTET STRING, + * attributes [0] IMPLICIT Attributes OPTIONAL + * } + */ +void qcrypto_akcipher_rsakey_export_p8info(const uint8_t *key, + size_t keylen, + uint8_t **dst, + size_t *dlen) +{ + QCryptoEncodeContext *ctx = qcrypto_der_encode_ctx_new(); + uint8_t version = 0; + + qcrypto_der_encode_seq_begin(ctx); + + /* version */ + qcrypto_der_encode_int(ctx, &version, sizeof(version)); + + /* algorithm identifier */ + qcrypto_der_encode_seq_begin(ctx); + qcrypto_der_encode_oid(ctx, (uint8_t *)QCRYPTO_OID_rsaEncryption, + sizeof(QCRYPTO_OID_rsaEncryption) - 1); + qcrypto_der_encode_null(ctx); + qcrypto_der_encode_seq_end(ctx); + + /* RSA private key */ + qcrypto_der_encode_octet_str(ctx, key, keylen); + + qcrypto_der_encode_seq_end(ctx); + + *dlen = qcrypto_der_encode_ctx_buffer_len(ctx); + *dst = g_malloc(*dlen); + qcrypto_der_encode_ctx_flush_and_free(ctx, *dst); +} + +#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) +#include "rsakey-nettle.c.inc" +#else +#include "rsakey-builtin.c.inc" +#endif diff --git a/crypto/rsakey.h b/crypto/rsakey.h new file mode 100644 index 000000000000..00b3eccec78e --- /dev/null +++ b/crypto/rsakey.h @@ -0,0 +1,101 @@ +/* + * QEMU Crypto RSA key parser + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 QCRYPTO_RSAKEY_H +#define QCRYPTO_RSAKEY_H + +#include "qemu/host-utils.h" +#include "crypto/akcipher.h" + +typedef struct QCryptoAkCipherRSAKey QCryptoAkCipherRSAKey; +typedef struct QCryptoAkCipherMPI QCryptoAkCipherMPI; + +/** + * Multiple precious integer, encoded as two' complement, + * copied directly from DER encoded ASN.1 structures. + */ +struct QCryptoAkCipherMPI { + uint8_t *data; + size_t len; +}; + +/* See rfc2437: https://datatracker.ietf.org/doc/html/rfc2437 */ +struct QCryptoAkCipherRSAKey { + /* The modulus */ + QCryptoAkCipherMPI n; + /* The public exponent */ + QCryptoAkCipherMPI e; + /* The private exponent */ + QCryptoAkCipherMPI d; + /* The first factor */ + QCryptoAkCipherMPI p; + /* The second factor */ + QCryptoAkCipherMPI q; + /* The first factor's exponent */ + QCryptoAkCipherMPI dp; + /* The second factor's exponent */ + QCryptoAkCipherMPI dq; + /* The CRT coefficient */ + QCryptoAkCipherMPI u; +}; + +/** + * Parse DER encoded ASN.1 RSA keys, expected ASN.1 schemas: + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * dp INTEGER + * dq INTEGER + * u INTEGER + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * RsaPubKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + * + * Returns: On success QCryptoAkCipherRSAKey is returned, otherwise returns NULL + */ +QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, Error **errp); + +/** + * qcrypto_akcipher_rsakey_export_as_p8info: + * + * Export RSA private key to PKCS#8 private key info. + */ +void qcrypto_akcipher_rsakey_export_p8info(const uint8_t *key, + size_t keylen, + uint8_t **dst, + size_t *dlen); + +void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *key); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipherRSAKey, + qcrypto_akcipher_rsakey_free); + +#endif diff --git a/crypto/secret_common.c b/crypto/secret_common.c index 714a15d5e52d..3441c44ca89e 100644 --- a/crypto/secret_common.c +++ b/crypto/secret_common.c @@ -138,36 +138,44 @@ static void qcrypto_secret_decode(const uint8_t *input, static void -qcrypto_secret_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_secret_complete(UserCreatable *uc, Error **errp) { - QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(uc); QCryptoSecretCommonClass *sec_class - = QCRYPTO_SECRET_COMMON_GET_CLASS(obj); - - if (value) { - Error *local_err = NULL; - uint8_t *input = NULL; - size_t inputlen = 0; - uint8_t *output = NULL; - size_t outputlen = 0; - - if (sec_class->load_data) { - sec_class->load_data(secret, &input, &inputlen, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } else { - error_setg(errp, "%s provides no 'load_data' method'", - object_get_typename(obj)); + = QCRYPTO_SECRET_COMMON_GET_CLASS(uc); + + Error *local_err = NULL; + uint8_t *input = NULL; + size_t inputlen = 0; + uint8_t *output = NULL; + size_t outputlen = 0; + + if (sec_class->load_data) { + sec_class->load_data(secret, &input, &inputlen, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } + } else { + error_setg(errp, "%s provides no 'load_data' method'", + object_get_typename(OBJECT(uc))); + return; + } - if (secret->keyid) { - qcrypto_secret_decrypt(secret, input, inputlen, - &output, &outputlen, &local_err); + if (secret->keyid) { + qcrypto_secret_decrypt(secret, input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } else { + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + qcrypto_secret_decode(input, inputlen, + &output, &outputlen, &local_err); g_free(input); if (local_err) { error_propagate(errp, local_err); @@ -175,26 +183,11 @@ qcrypto_secret_prop_set_loaded(Object *obj, } input = output; inputlen = outputlen; - } else { - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - qcrypto_secret_decode(input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } } - - secret->rawdata = input; - secret->rawlen = inputlen; - } else if (secret->rawdata) { - error_setg(errp, "Cannot unload secret"); - return; } + + secret->rawdata = input; + secret->rawlen = inputlen; } @@ -268,13 +261,6 @@ qcrypto_secret_prop_get_keyid(Object *obj, } -static void -qcrypto_secret_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_secret_finalize(Object *obj) { @@ -294,7 +280,7 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_secret_prop_get_loaded, - qcrypto_secret_prop_set_loaded); + NULL); object_class_property_add_enum(oc, "format", "QCryptoSecretFormat", &QCryptoSecretFormat_lookup, diff --git a/crypto/sm4.c b/crypto/sm4.c new file mode 100644 index 000000000000..9f0cd452c782 --- /dev/null +++ b/crypto/sm4.c @@ -0,0 +1,49 @@ +/* + * QEMU crypto sm4 support + * + * Copyright (C) 2013 - 2018 Linaro Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "crypto/sm4.h" + +uint8_t const sm4_sbox[] = { + 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, + 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, + 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, + 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, + 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, + 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, + 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, + 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, + 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, + 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, + 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, + 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, + 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, + 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, + 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, + 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, + 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, + 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, + 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, + 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, + 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, + 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, + 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, + 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, + 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, + 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, + 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, + 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, + 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, + 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, + 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, + 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, +}; + diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index 6fb83639ecd2..c0d23a0ef3c0 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -119,16 +119,11 @@ qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_anon_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj); + QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(uc); - qcrypto_tls_creds_anon_unload(creds); - if (value) { - qcrypto_tls_creds_anon_load(creds, errp); - } + qcrypto_tls_creds_anon_load(creds, errp); } @@ -163,13 +158,6 @@ qcrypto_tls_creds_anon_prop_get_loaded(Object *obj G_GNUC_UNUSED, #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_anon_finalize(Object *obj) { @@ -188,7 +176,7 @@ qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_anon_prop_get_loaded, - qcrypto_tls_creds_anon_prop_set_loaded); + NULL); } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 752f2d92bee7..546cad1c5a49 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -109,7 +109,12 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds, goto cleanup; } - gnutls_psk_set_server_credentials_file(creds->data.server, pskfile); + ret = gnutls_psk_set_server_credentials_file(creds->data.server, pskfile); + if (ret < 0) { + error_setg(errp, "Cannot set PSK server credentials: %s", + gnutls_strerror(ret)); + goto cleanup; + } gnutls_psk_set_server_dh_params(creds->data.server, creds->parent_obj.dh_params); } else { @@ -135,8 +140,13 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds, goto cleanup; } - gnutls_psk_set_client_credentials(creds->data.client, - username, &key, GNUTLS_PSK_KEY_HEX); + ret = gnutls_psk_set_client_credentials(creds->data.client, + username, &key, GNUTLS_PSK_KEY_HEX); + if (ret < 0) { + error_setg(errp, "Cannot set PSK client credentials: %s", + gnutls_strerror(ret)); + goto cleanup; + } } rv = 0; @@ -188,16 +198,11 @@ qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_psk_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj); + QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(uc); - qcrypto_tls_creds_psk_unload(creds); - if (value) { - qcrypto_tls_creds_psk_load(creds, errp); - } + qcrypto_tls_creds_psk_load(creds, errp); } @@ -232,13 +237,6 @@ qcrypto_tls_creds_psk_prop_get_loaded(Object *obj G_GNUC_UNUSED, #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_psk_finalize(Object *obj) { @@ -276,7 +274,7 @@ qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_psk_prop_get_loaded, - qcrypto_tls_creds_psk_prop_set_loaded); + NULL); object_class_property_add_str(oc, "username", qcrypto_tls_creds_psk_prop_get_username, qcrypto_tls_creds_psk_prop_set_username); diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index 32948a6bdc41..d14313925dd8 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -687,16 +687,11 @@ qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_x509_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); + QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc); - qcrypto_tls_creds_x509_unload(creds); - if (value) { - qcrypto_tls_creds_x509_load(creds, errp); - } + qcrypto_tls_creds_x509_load(creds, errp); } @@ -814,13 +809,6 @@ qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp) #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_x509_init(Object *obj) { @@ -852,7 +840,7 @@ qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_x509_prop_get_loaded, - qcrypto_tls_creds_x509_prop_set_loaded); + NULL); object_class_property_add_bool(oc, "sanity-check", qcrypto_tls_creds_x509_prop_get_sanity, qcrypto_tls_creds_x509_prop_set_sanity); diff --git a/disas.c b/disas.c index 3dab4482d1a1..3b31315f4038 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); - - 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); + g_autofree uint8_t *buf = g_malloc(n); + + 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; } @@ -126,7 +126,7 @@ static void initialize_debug_target(CPUDebug *s, CPUState *cpu) s->cpu = cpu; s->info.read_memory_func = target_read_memory; s->info.print_address_func = print_address; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN s->info.endian = BFD_ENDIAN_BIG; #else s->info.endian = BFD_ENDIAN_LITTLE; @@ -144,7 +144,7 @@ static void initialize_debug_host(CPUDebug *s) s->info.read_memory_func = host_read_memory; s->info.print_address_func = host_print_address; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN s->info.endian = BFD_ENDIAN_BIG; #else s->info.endian = BFD_ENDIAN_LITTLE; @@ -153,21 +153,17 @@ static void initialize_debug_host(CPUDebug *s) s->info.print_insn = print_insn_tci; #elif defined(__i386__) s->info.mach = bfd_mach_i386_i386; - s->info.print_insn = print_insn_i386; s->info.cap_arch = CS_ARCH_X86; s->info.cap_mode = CS_MODE_32; s->info.cap_insn_unit = 1; s->info.cap_insn_split = 8; #elif defined(__x86_64__) s->info.mach = bfd_mach_x86_64; - s->info.print_insn = print_insn_i386; s->info.cap_arch = CS_ARCH_X86; s->info.cap_mode = CS_MODE_64; s->info.cap_insn_unit = 1; s->info.cap_insn_split = 8; #elif defined(_ARCH_PPC) - s->info.disassembler_options = (char *)"any"; - s->info.print_insn = print_insn_ppc; s->info.cap_arch = CS_ARCH_PPC; # ifdef _ARCH_PPC64 s->info.cap_mode = CS_MODE_64; @@ -182,9 +178,6 @@ static void initialize_debug_host(CPUDebug *s) #endif #elif defined(__aarch64__) s->info.cap_arch = CS_ARCH_ARM64; -# ifdef CONFIG_ARM_A64_DIS - s->info.print_insn = print_insn_arm_a64; -# endif #elif defined(__alpha__) s->info.print_insn = print_insn_alpha; #elif defined(__sparc__) @@ -192,7 +185,6 @@ static void initialize_debug_host(CPUDebug *s) s->info.mach = bfd_mach_sparc_v9b; #elif defined(__arm__) /* TCG only generates code for arm mode. */ - s->info.print_insn = print_insn_arm; s->info.cap_arch = CS_ARCH_ARM; #elif defined(__MIPSEB__) s->info.print_insn = print_insn_big_mips; @@ -201,7 +193,6 @@ static void initialize_debug_host(CPUDebug *s) #elif defined(__m68k__) s->info.print_insn = print_insn_m68k; #elif defined(__s390__) - s->info.print_insn = print_insn_s390; s->info.cap_arch = CS_ARCH_SYSZ; s->info.cap_insn_unit = 2; s->info.cap_insn_split = 6; @@ -248,7 +239,8 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code, } } -static int plugin_printf(FILE *stream, const char *fmt, ...) +static int G_GNUC_PRINTF(2, 3) +gstring_printf(FILE *stream, const char *fmt, ...) { /* We abuse the FILE parameter to pass a GString. */ GString *s = (GString *)stream; @@ -279,7 +271,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; @@ -367,15 +359,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; } @@ -385,13 +381,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/arm-a64.cc b/disas/arm-a64.cc deleted file mode 100644 index a1402a2e0715..000000000000 --- a/disas/arm-a64.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * ARM A64 disassembly output wrapper to libvixl - * Copyright (c) 2013 Linaro Limited - * Written by Claudio Fontana - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" - -#include "vixl/a64/disasm-a64.h" - -using namespace vixl; - -static Decoder *vixl_decoder = NULL; -static Disassembler *vixl_disasm = NULL; - -/* We don't use libvixl's PrintDisassembler because its output - * is a little unhelpful (trailing newlines, for example). - * Instead we use our own very similar variant so we have - * control over the format. - */ -class QEMUDisassembler : public Disassembler { -public: - QEMUDisassembler() : printf_(NULL), stream_(NULL) { } - ~QEMUDisassembler() { } - - void SetStream(FILE *stream) { - stream_ = stream; - } - - void SetPrintf(fprintf_function printf_fn) { - printf_ = printf_fn; - } - -protected: - virtual void ProcessOutput(const Instruction *instr) { - printf_(stream_, "%08" PRIx32 " %s", - instr->InstructionBits(), GetOutput()); - } - -private: - fprintf_function printf_; - FILE *stream_; -}; - -static int vixl_is_initialized(void) -{ - return vixl_decoder != NULL; -} - -static void vixl_init() { - vixl_decoder = new Decoder(); - vixl_disasm = new QEMUDisassembler(); - vixl_decoder->AppendVisitor(vixl_disasm); -} - -#define INSN_SIZE 4 - -/* Disassemble ARM A64 instruction. This is our only entry - * point from QEMU's C code. - */ -int print_insn_arm_a64(uint64_t addr, disassemble_info *info) -{ - uint8_t bytes[INSN_SIZE]; - uint32_t instrval; - const Instruction *instr; - int status; - - status = info->read_memory_func(addr, bytes, INSN_SIZE, info); - if (status != 0) { - info->memory_error_func(status, addr, info); - return -1; - } - - if (!vixl_is_initialized()) { - vixl_init(); - } - - ((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func); - ((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream); - - instrval = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; - instr = reinterpret_cast(&instrval); - vixl_disasm->MapCodeAddress(addr, instr); - vixl_decoder->Decode(instr); - - return INSN_SIZE; -} diff --git a/disas/arm.c b/disas/arm.c deleted file mode 100644 index 7d940f23967c..000000000000 --- a/disas/arm.c +++ /dev/null @@ -1,4012 +0,0 @@ -/* Instruction printing code for the ARM - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 - 2007, Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) - Modification by James G. Smith (jsmith@cygnus.co.uk) - - This file is part of libopcodes. - - 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 . */ - -/* Start of qemu specific additions. Mostly this is stub definitions - for things we don't care about. */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" - -#define ARM_EXT_V1 0 -#define ARM_EXT_V2 0 -#define ARM_EXT_V2S 0 -#define ARM_EXT_V3 0 -#define ARM_EXT_V3M 0 -#define ARM_EXT_V4 0 -#define ARM_EXT_V4T 0 -#define ARM_EXT_V5 0 -#define ARM_EXT_V5T 0 -#define ARM_EXT_V5ExP 0 -#define ARM_EXT_V5E 0 -#define ARM_EXT_V5J 0 -#define ARM_EXT_V6 0 -#define ARM_EXT_V6K 0 -#define ARM_EXT_V6Z 0 -#define ARM_EXT_V6T2 0 -#define ARM_EXT_V7 0 -#define ARM_EXT_DIV 0 - -/* Co-processor space extensions. */ -#define ARM_CEXT_XSCALE 0 -#define ARM_CEXT_MAVERICK 0 -#define ARM_CEXT_IWMMXT 0 - -#define FPU_FPA_EXT_V1 0 -#define FPU_FPA_EXT_V2 0 -#define FPU_VFP_EXT_NONE 0 -#define FPU_VFP_EXT_V1xD 0 -#define FPU_VFP_EXT_V1 0 -#define FPU_VFP_EXT_V2 0 -#define FPU_MAVERICK 0 -#define FPU_VFP_EXT_V3 0 -#define FPU_NEON_EXT_V1 0 - -/* Assume host uses ieee float. */ -static void floatformat_to_double (unsigned char *data, double *dest) -{ - union { - uint32_t i; - float f; - } u; - u.i = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - *dest = u.f; -} - -static int arm_read_memory(bfd_vma memaddr, bfd_byte *b, int length, - struct disassemble_info *info) -{ - assert((info->flags & INSN_ARM_BE32) == 0 || length == 2 || length == 4); - - if ((info->flags & INSN_ARM_BE32) != 0 && length == 2) { - memaddr ^= 2; - } - return info->read_memory_func(memaddr, b, length, info); -} - -/* End of qemu specific additions. */ - -struct opcode32 -{ - unsigned long arch; /* Architecture defining this insn. */ - unsigned long value, mask; /* Recognise insn if (op&mask)==value. */ - const char *assembler; /* How to disassemble this insn. */ -}; - -struct opcode16 -{ - unsigned long arch; /* Architecture defining this insn. */ - unsigned short value, mask; /* Recognise insn if (op&mask)==value. */ - const char *assembler; /* How to disassemble this insn. */ -}; - -/* print_insn_coprocessor recognizes the following format control codes: - - %% % - - %c print condition code (always bits 28-31 in ARM mode) - %q print shifter argument - %u print condition code (unconditional in ARM mode) - %A print address for ldc/stc/ldf/stf instruction - %B print vstm/vldm register list - %C print vstr/vldr address operand - %I print cirrus signed shift immediate: bits 0..3|4..6 - %F print the COUNT field of a LFM/SFM instruction. - %P print floating point precision in arithmetic insn - %Q print floating point precision in ldf/stf insn - %R print floating point rounding mode - - %r print as an ARM register - %d print the bitfield in decimal - %k print immediate for VFPv3 conversion instruction - %x print the bitfield in hex - %X print the bitfield as 1 hex digit without leading "0x" - %f print a floating point constant if >7 else a - floating point register - %w print as an iWMMXt width field - [bhwd]ss/us - %g print as an iWMMXt 64-bit register - %G print as an iWMMXt general purpose or control register - %D print as a NEON D register - %Q print as a NEON Q register - - %y print a single precision VFP reg. - Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair - %z print a double precision VFP reg - Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order - - %L print as an iWMMXt N/M width field. - %Z print the Immediate of a WSHUFH instruction. - %l like 'A' except use byte offsets for 'B' & 'H' - versions. - %i print 5-bit immediate in bits 8,3..0 - (print "32" when 0) - %r print register offset address for wldt/wstr instruction -*/ - -/* Common coprocessor opcodes shared between Arm and Thumb-2. */ - -static const struct opcode32 coprocessor_opcodes[] = -{ - /* XScale instructions. */ - {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"}, - {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"}, - - /* Intel Wireless MMX technology instructions. */ -#define FIRST_IWMMXT_INSN 0x0e130130 -#define IWMMXT_INSN_COUNT 73 - {ARM_CEXT_IWMMXT, 0x0e130130, 0x0f3f0fff, "tandc%22-23w%c\t%12-15r"}, - {ARM_CEXT_XSCALE, 0x0e400010, 0x0ff00f3f, "tbcst%6-7w%c\t%16-19g, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e130170, 0x0f3f0ff8, "textrc%22-23w%c\t%12-15r, #%0-2d"}, - {ARM_CEXT_XSCALE, 0x0e100070, 0x0f300ff0, "textrm%3?su%22-23w%c\t%12-15r, %16-19g, #%0-2d"}, - {ARM_CEXT_XSCALE, 0x0e600010, 0x0ff00f38, "tinsr%6-7w%c\t%16-19g, %12-15r, #%0-2d"}, - {ARM_CEXT_XSCALE, 0x0e000110, 0x0ff00fff, "tmcr%c\t%16-19G, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00ff0, "tmcrr%c\t%0-3g, %12-15r, %16-19r"}, - {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0e10, "tmia%17?tb%16?tb%c\t%5-8g, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0e10, "tmia%c\t%5-8g, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0e10, "tmiaph%c\t%5-8g, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e100030, 0x0f300fff, "tmovmsk%22-23w%c\t%12-15r, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e100110, 0x0ff00ff0, "tmrc%c\t%12-15r, %16-19G"}, - {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00ff0, "tmrrc%c\t%12-15r, %16-19r, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e130150, 0x0f3f0fff, "torc%22-23w%c\t%12-15r"}, - {ARM_CEXT_XSCALE, 0x0e130190, 0x0f3f0fff, "torvsc%22-23w%c\t%12-15r"}, - {ARM_CEXT_XSCALE, 0x0e2001c0, 0x0f300fff, "wabs%22-23w%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e0001c0, 0x0f300fff, "wacc%22-23w%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e000180, 0x0f000ff0, "wadd%20-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e2001a0, 0x0f300ff0, "waddbhus%22?ml%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ea001a0, 0x0ff00ff0, "waddsubhx%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000020, 0x0f800ff0, "waligni%c\t%12-15g, %16-19g, %0-3g, #%20-22d"}, - {ARM_CEXT_XSCALE, 0x0e800020, 0x0fc00ff0, "walignr%20-21d%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e200000, 0x0fe00ff0, "wand%20'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e800000, 0x0fa00ff0, "wavg2%22?hb%20'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e400000, 0x0fe00ff0, "wavg4%20'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000060, 0x0f300ff0, "wcmpeq%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100060, 0x0f100ff0, "wcmpgt%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0xfc500100, 0xfe500f00, "wldrd\t%12-15g, %r"}, - {ARM_CEXT_XSCALE, 0xfc100100, 0xfe500f00, "wldrw\t%12-15G, %A"}, - {ARM_CEXT_XSCALE, 0x0c100000, 0x0e100e00, "wldr%L%c\t%12-15g, %l"}, - {ARM_CEXT_XSCALE, 0x0e400100, 0x0fc00ff0, "wmac%21?su%20'z%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e800100, 0x0fc00ff0, "wmadd%21?su%20'x%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ec00100, 0x0fd00ff0, "wmadd%21?sun%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000160, 0x0f100ff0, "wmax%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000080, 0x0f100fe0, "wmerge%c\t%12-15g, %16-19g, %0-3g, #%21-23d"}, - {ARM_CEXT_XSCALE, 0x0e0000a0, 0x0f800ff0, "wmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e800120, 0x0f800ff0, "wmiaw%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100160, 0x0f100ff0, "wmin%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000100, 0x0fc00ff0, "wmul%21?su%20?ml%23'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ed00100, 0x0fd00ff0, "wmul%21?sumr%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ee000c0, 0x0fe00ff0, "wmulwsm%20`r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ec000c0, 0x0fe00ff0, "wmulwum%20`r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0eb000c0, 0x0ff00ff0, "wmulwl%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e8000a0, 0x0f800ff0, "wqmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100080, 0x0fd00ff0, "wqmulm%21'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ec000e0, 0x0fd00ff0, "wqmulwm%21'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000000, 0x0ff00ff0, "wor%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000080, 0x0f000ff0, "wpack%20-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0xfe300040, 0xff300ef0, "wror%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e300040, 0x0f300ff0, "wror%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e300140, 0x0f300ff0, "wror%22-23wg%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0x0e000120, 0x0fa00ff0, "wsad%22?hb%20'z%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e0001e0, 0x0f000ff0, "wshufh%c\t%12-15g, %16-19g, #%Z"}, - {ARM_CEXT_XSCALE, 0xfe100040, 0xff300ef0, "wsll%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e100040, 0x0f300ff0, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100148, 0x0f300ffc, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0xfe000040, 0xff300ef0, "wsra%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e000040, 0x0f300ff0, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000148, 0x0f300ffc, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0xfe200040, 0xff300ef0, "wsrl%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e200040, 0x0f300ff0, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e200148, 0x0f300ffc, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0xfc400100, 0xfe500f00, "wstrd\t%12-15g, %r"}, - {ARM_CEXT_XSCALE, 0xfc000100, 0xfe500f00, "wstrw\t%12-15G, %A"}, - {ARM_CEXT_XSCALE, 0x0c000000, 0x0e100e00, "wstr%L%c\t%12-15g, %l"}, - {ARM_CEXT_XSCALE, 0x0e0001a0, 0x0f000ff0, "wsub%20-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ed001c0, 0x0ff00ff0, "wsubaddhx%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e1001c0, 0x0f300ff0, "wabsdiff%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e0000c0, 0x0fd00fff, "wunpckeh%21?sub%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e4000c0, 0x0fd00fff, "wunpckeh%21?suh%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e8000c0, 0x0fd00fff, "wunpckeh%21?suw%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e0000e0, 0x0f100fff, "wunpckel%21?su%22-23w%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e1000c0, 0x0f300ff0, "wunpckih%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e1000e0, 0x0f300ff0, "wunpckil%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100000, 0x0ff00ff0, "wxor%c\t%12-15g, %16-19g, %0-3g"}, - - /* Floating point coprocessor (FPA) instructions */ - {FPU_FPA_EXT_V1, 0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"}, - {FPU_FPA_EXT_V1, 0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"}, - {FPU_FPA_EXT_V1, 0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"}, - {FPU_FPA_EXT_V1, 0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"}, - {FPU_FPA_EXT_V2, 0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"}, - {FPU_FPA_EXT_V2, 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, - - /* Register load/store */ - {FPU_NEON_EXT_V1, 0x0d200b00, 0x0fb00f01, "vstmdb%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0d300b00, 0x0fb00f01, "vldmdb%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0c800b00, 0x0f900f01, "vstmia%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0c900b00, 0x0f900f01, "vldmia%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0d000b00, 0x0f300f00, "vstr%c\t%12-15,22D, %C"}, - {FPU_NEON_EXT_V1, 0x0d100b00, 0x0f300f00, "vldr%c\t%12-15,22D, %C"}, - - /* Data transfer between ARM and NEON registers */ - {FPU_NEON_EXT_V1, 0x0e800b10, 0x0ff00f70, "vdup%c.32\t%16-19,7D, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e800b30, 0x0ff00f70, "vdup%c.16\t%16-19,7D, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ea00b10, 0x0ff00f70, "vdup%c.32\t%16-19,7Q, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ea00b30, 0x0ff00f70, "vdup%c.16\t%16-19,7Q, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ec00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7D, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ee00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7Q, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0c400b10, 0x0ff00fd0, "vmov%c\t%0-3,5D, %12-15r, %16-19r"}, - {FPU_NEON_EXT_V1, 0x0c500b10, 0x0ff00fd0, "vmov%c\t%12-15r, %16-19r, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0x0e000b10, 0x0fd00f70, "vmov%c.32\t%16-19,7D[%21d], %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e100b10, 0x0f500f70, "vmov%c.32\t%12-15r, %16-19,7D[%21d]"}, - {FPU_NEON_EXT_V1, 0x0e000b30, 0x0fd00f30, "vmov%c.16\t%16-19,7D[%6,21d], %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e100b30, 0x0f500f30, "vmov%c.%23?us16\t%12-15r, %16-19,7D[%6,21d]"}, - {FPU_NEON_EXT_V1, 0x0e400b10, 0x0fd00f10, "vmov%c.8\t%16-19,7D[%5,6,21d], %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e500b10, 0x0f500f10, "vmov%c.%23?us8\t%12-15r, %16-19,7D[%5,6,21d]"}, - - /* Floating point coprocessor (VFP) instructions */ - {FPU_VFP_EXT_V1xD, 0x0ef1fa10, 0x0fffffff, "fmstat%c"}, - {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee60a10, 0x0fff0fff, "fmxr%c\tmvfr1, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee70a10, 0x0fff0fff, "fmxr%c\tmvfr0, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"}, - {FPU_VFP_EXT_V1xD, 0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"}, - {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"}, - {FPU_VFP_EXT_V1xD, 0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"}, - {FPU_VFP_EXT_V1xD, 0x0ef60a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr1"}, - {FPU_VFP_EXT_V1xD, 0x0ef70a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr0"}, - {FPU_VFP_EXT_V1xD, 0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"}, - {FPU_VFP_EXT_V1xD, 0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"}, - {FPU_VFP_EXT_V1xD, 0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"}, - {FPU_VFP_EXT_V1, 0x0e000b10, 0x0ff00fff, "fmdlr%c\t%z2, %12-15r"}, - {FPU_VFP_EXT_V1, 0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %z2"}, - {FPU_VFP_EXT_V1, 0x0e200b10, 0x0ff00fff, "fmdhr%c\t%z2, %12-15r"}, - {FPU_VFP_EXT_V1, 0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %z2"}, - {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0ff00fff, "fmxr%c\t, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, "}, - {FPU_VFP_EXT_V1xD, 0x0e000a10, 0x0ff00f7f, "fmsr%c\t%y2, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %y2"}, - {FPU_VFP_EXT_V1xD, 0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%y1"}, - {FPU_VFP_EXT_V1, 0x0eb50b40, 0x0fbf0f70, "fcmp%7'ezd%c\t%z1"}, - {FPU_VFP_EXT_V1xD, 0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb00b40, 0x0fbf0fd0, "fcpyd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1, 0x0eb00bc0, 0x0fbf0fd0, "fabsd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb10b40, 0x0fbf0fd0, "fnegd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1, 0x0eb10bc0, 0x0fbf0fd0, "fsqrtd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1, 0x0eb70ac0, 0x0fbf0fd0, "fcvtds%c\t%z1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb70bc0, 0x0fbf0fd0, "fcvtsd%c\t%y1, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb80b40, 0x0fbf0fd0, "fuitod%c\t%z1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb80bc0, 0x0fbf0fd0, "fsitod%c\t%z1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb40b40, 0x0fbf0f50, "fcmp%7'ed%c\t%z1, %z0"}, - {FPU_VFP_EXT_V3, 0x0eba0a40, 0x0fbe0f50, "f%16?us%7?lhtos%c\t%y1, #%5,0-3k"}, - {FPU_VFP_EXT_V3, 0x0eba0b40, 0x0fbe0f50, "f%16?us%7?lhtod%c\t%z1, #%5,0-3k"}, - {FPU_VFP_EXT_V1xD, 0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0ebc0b40, 0x0fbe0f50, "fto%16?sui%7'zd%c\t%y1, %z0"}, - {FPU_VFP_EXT_V3, 0x0ebe0a40, 0x0fbe0f50, "fto%16?us%7?lhs%c\t%y1, #%5,0-3k"}, - {FPU_VFP_EXT_V3, 0x0ebe0b40, 0x0fbe0f50, "fto%16?us%7?lhd%c\t%z1, #%5,0-3k"}, - {FPU_VFP_EXT_V1, 0x0c500b10, 0x0fb00ff0, "fmrrd%c\t%12-15r, %16-19r, %z0"}, - {FPU_VFP_EXT_V3, 0x0eb00a00, 0x0fb00ff0, "fconsts%c\t%y1, #%0-3,16-19d"}, - {FPU_VFP_EXT_V3, 0x0eb00b00, 0x0fb00ff0, "fconstd%c\t%z1, #%0-3,16-19d"}, - {FPU_VFP_EXT_V2, 0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%y4, %12-15r, %16-19r"}, - {FPU_VFP_EXT_V2, 0x0c400b10, 0x0ff00fd0, "fmdrr%c\t%z0, %12-15r, %16-19r"}, - {FPU_VFP_EXT_V2, 0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %y4"}, - {FPU_VFP_EXT_V1xD, 0x0e000a00, 0x0fb00f50, "fmacs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e000a40, 0x0fb00f50, "fnmacs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e000b00, 0x0fb00f50, "fmacd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e000b40, 0x0fb00f50, "fnmacd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e100a00, 0x0fb00f50, "fmscs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e100a40, 0x0fb00f50, "fnmscs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e100b00, 0x0fb00f50, "fmscd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e100b40, 0x0fb00f50, "fnmscd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e200a00, 0x0fb00f50, "fmuls%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e200a40, 0x0fb00f50, "fnmuls%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e200b00, 0x0fb00f50, "fmuld%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e200b40, 0x0fb00f50, "fnmuld%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e300a00, 0x0fb00f50, "fadds%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e300a40, 0x0fb00f50, "fsubs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e300b00, 0x0fb00f50, "faddd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e300b40, 0x0fb00f50, "fsubd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e800a00, 0x0fb00f50, "fdivs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e800b00, 0x0fb00f50, "fdivd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0d200b00, 0x0fb00f00, "fstmdb%0?xd%c\t%16-19r!, %z3"}, - {FPU_VFP_EXT_V1xD, 0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0d300b00, 0x0fb00f00, "fldmdb%0?xd%c\t%16-19r!, %z3"}, - {FPU_VFP_EXT_V1xD, 0x0d000a00, 0x0f300f00, "fsts%c\t%y1, %A"}, - {FPU_VFP_EXT_V1, 0x0d000b00, 0x0f300f00, "fstd%c\t%z1, %A"}, - {FPU_VFP_EXT_V1xD, 0x0d100a00, 0x0f300f00, "flds%c\t%y1, %A"}, - {FPU_VFP_EXT_V1, 0x0d100b00, 0x0f300f00, "fldd%c\t%z1, %A"}, - {FPU_VFP_EXT_V1xD, 0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0c800b00, 0x0f900f00, "fstmia%0?xd%c\t%16-19r%21'!, %z3"}, - {FPU_VFP_EXT_V1xD, 0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0c900b00, 0x0f900f00, "fldmia%0?xd%c\t%16-19r%21'!, %z3"}, - - /* Cirrus coprocessor instructions. */ - {ARM_CEXT_MAVERICK, 0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e200440, 0x0ff00fff, "cfmval32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100440, 0x0ff00fff, "cfmv32al%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e200460, 0x0ff00fff, "cfmvam32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100460, 0x0ff00fff, "cfmv32am%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e200480, 0x0ff00fff, "cfmvah32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100480, 0x0ff00fff, "cfmv32ah%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e2004a0, 0x0ff00fff, "cfmva32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1004a0, 0x0ff00fff, "cfmv32a%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e2004c0, 0x0ff00fff, "cfmva64%c\tmvax%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1004c0, 0x0ff00fff, "cfmv64a%c\tmvdx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e2004e0, 0x0fff0fff, "cfmvsc32%c\tdspsc, mvdx%12-15d"}, - {ARM_CEXT_MAVERICK, 0x0e1004e0, 0x0fff0fff, "cfmv32sc%c\tmvdx%12-15d, dspsc"}, - {ARM_CEXT_MAVERICK, 0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e000500, 0x0ff00f10, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"}, - {ARM_CEXT_MAVERICK, 0x0e200500, 0x0ff00f10, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"}, - {ARM_CEXT_MAVERICK, 0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e000600, 0x0ff00f10, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100600, 0x0ff00f10, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e200600, 0x0ff00f10, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e300600, 0x0ff00f10, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, - - /* Generic coprocessor instructions */ - {ARM_EXT_V2, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - {ARM_EXT_V2, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - {ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"}, - {ARM_EXT_V2, 0x0c100000, 0x0e100000, "ldc%22'l%c\t%8-11d, cr%12-15d, %A"}, - - /* V6 coprocessor instructions */ - {ARM_EXT_V6, 0xfc500000, 0xfff00000, "mrrc2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - {ARM_EXT_V6, 0xfc400000, 0xfff00000, "mcrr2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - - /* V5 coprocessor instructions */ - {ARM_EXT_V5, 0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"}, - {ARM_EXT_V5, 0xfc000000, 0xfe100000, "stc2%22'l%c\t%8-11d, cr%12-15d, %A"}, - {ARM_EXT_V5, 0xfe000000, 0xff000010, "cdp2%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V5, 0xfe000010, 0xff100010, "mcr2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V5, 0xfe100010, 0xff100010, "mrc2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - - {0, 0, 0, 0} -}; - -/* Neon opcode table: This does not encode the top byte -- that is - checked by the print_insn_neon routine, as it depends on whether we are - doing thumb32 or arm32 disassembly. */ - -/* print_insn_neon recognizes the following format control codes: - - %% % - - %c print condition code - %A print v{st,ld}[1234] operands - %B print v{st,ld}[1234] any one operands - %C print v{st,ld}[1234] single->all operands - %D print scalar - %E print vmov, vmvn, vorr, vbic encoded constant - %F print vtbl,vtbx register list - - %r print as an ARM register - %d print the bitfield in decimal - %e print the 2^N - bitfield in decimal - %D print as a NEON D register - %Q print as a NEON Q register - %R print as a NEON D or Q register - %Sn print byte scaled width limited by n - %Tn print short scaled width limited by n - %Un print long scaled width limited by n - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order */ - -static const struct opcode32 neon_opcodes[] = -{ - /* Extract */ - {FPU_NEON_EXT_V1, 0xf2b00840, 0xffb00850, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, - {FPU_NEON_EXT_V1, 0xf2b00000, 0xffb00810, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, - - /* Move data element to all lanes */ - {FPU_NEON_EXT_V1, 0xf3b40c00, 0xffb70f90, "vdup%c.32\t%12-15,22R, %0-3,5D[%19d]"}, - {FPU_NEON_EXT_V1, 0xf3b20c00, 0xffb30f90, "vdup%c.16\t%12-15,22R, %0-3,5D[%18-19d]"}, - {FPU_NEON_EXT_V1, 0xf3b10c00, 0xffb10f90, "vdup%c.8\t%12-15,22R, %0-3,5D[%17-19d]"}, - - /* Table lookup */ - {FPU_NEON_EXT_V1, 0xf3b00800, 0xffb00c50, "vtbl%c.8\t%12-15,22D, %F, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf3b00840, 0xffb00c50, "vtbx%c.8\t%12-15,22D, %F, %0-3,5D"}, - - /* Two registers, miscellaneous */ - {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf3b00500, 0xffbf0f90, "vcnt%c.8\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00580, 0xffbf0f90, "vmvn%c\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20000, 0xffbf0f90, "vswp%c\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20200, 0xffb30fd0, "vmovn%c.i%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b20240, 0xffb30fd0, "vqmovun%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b20280, 0xffb30fd0, "vqmovn%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b202c0, 0xffb30fd0, "vqmovn%c.u%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b20300, 0xffb30fd0, "vshll%c.i%18-19S2\t%12-15,22Q, %0-3,5D, #%18-19S2"}, - {FPU_NEON_EXT_V1, 0xf3bb0400, 0xffbf0e90, "vrecpe%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3bb0480, 0xffbf0e90, "vrsqrte%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00000, 0xffb30f90, "vrev64%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00080, 0xffb30f90, "vrev32%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00100, 0xffb30f90, "vrev16%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00400, 0xffb30f90, "vcls%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00480, 0xffb30f90, "vclz%c.i%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00700, 0xffb30f90, "vqabs%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00780, 0xffb30f90, "vqneg%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20080, 0xffb30f90, "vtrn%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20100, 0xffb30f90, "vuzp%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20180, 0xffb30f90, "vzip%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b10000, 0xffb30b90, "vcgt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10080, 0xffb30b90, "vcge%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10100, 0xffb30b90, "vceq%c.%10?fi%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10180, 0xffb30b90, "vcle%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10200, 0xffb30b90, "vclt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10300, 0xffb30b90, "vabs%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b10380, 0xffb30b90, "vneg%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00200, 0xffb30f10, "vpaddl%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00600, 0xffb30f10, "vpadal%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"}, - - /* Three registers of the same length */ - {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2300110, 0xffb00f10, "vorn%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000110, 0xffb00f10, "veor%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3100110, 0xffb00f10, "vbsl%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200110, 0xffb00f10, "vbit%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3300110, 0xffb00f10, "vbif%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000d00, 0xffa00f10, "vadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000d10, 0xffa00f10, "vmla%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000e00, 0xffa00f10, "vceq%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000f00, 0xffa00f10, "vmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000f10, 0xffa00f10, "vrecps%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200d00, 0xffa00f10, "vsub%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200d10, 0xffa00f10, "vmls%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200f00, 0xffa00f10, "vmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200f10, 0xffa00f10, "vrsqrts%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000d00, 0xffa00f10, "vpadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000d10, 0xffa00f10, "vmul%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000e00, 0xffa00f10, "vcge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000e10, 0xffa00f10, "vacge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000f00, 0xffa00f10, "vpmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200d00, 0xffa00f10, "vabd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200e00, 0xffa00f10, "vcgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200e10, 0xffa00f10, "vacgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200f00, 0xffa00f10, "vpmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000800, 0xff800f10, "vadd%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000810, 0xff800f10, "vtst%c.%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000900, 0xff800f10, "vmla%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000b00, 0xff800f10, "vqdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000b10, 0xff800f10, "vpadd%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000800, 0xff800f10, "vsub%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000810, 0xff800f10, "vceq%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000900, 0xff800f10, "vmls%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000b00, 0xff800f10, "vqrdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000000, 0xfe800f10, "vhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000010, 0xfe800f10, "vqadd%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000100, 0xfe800f10, "vrhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000200, 0xfe800f10, "vhsub%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000210, 0xfe800f10, "vqsub%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000300, 0xfe800f10, "vcgt%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000310, 0xfe800f10, "vcge%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000400, 0xfe800f10, "vshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000410, 0xfe800f10, "vqshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000500, 0xfe800f10, "vrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000510, 0xfe800f10, "vqrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000600, 0xfe800f10, "vmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000610, 0xfe800f10, "vmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000700, 0xfe800f10, "vabd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000710, 0xfe800f10, "vaba%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000910, 0xfe800f10, "vmul%c.%24?pi%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000a00, 0xfe800f10, "vpmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000a10, 0xfe800f10, "vpmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - - /* One register and an immediate value */ - {FPU_NEON_EXT_V1, 0xf2800e10, 0xfeb80fb0, "vmov%c.i8\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800e30, 0xfeb80fb0, "vmov%c.i64\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800f10, 0xfeb80fb0, "vmov%c.f32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800810, 0xfeb80db0, "vmov%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800830, 0xfeb80db0, "vmvn%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800910, 0xfeb80db0, "vorr%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800930, 0xfeb80db0, "vbic%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800c10, 0xfeb80eb0, "vmov%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800c30, 0xfeb80eb0, "vmvn%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800110, 0xfeb809b0, "vorr%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800130, 0xfeb809b0, "vbic%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800010, 0xfeb808b0, "vmov%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800030, 0xfeb808b0, "vmvn%c.i32\t%12-15,22R, %E"}, - - /* Two registers and a shift amount */ - {FPU_NEON_EXT_V1, 0xf2880810, 0xffb80fd0, "vshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880850, 0xffb80fd0, "vrshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880810, 0xfeb80fd0, "vqshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880850, 0xfeb80fd0, "vqrshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880910, 0xfeb80fd0, "vqshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880950, 0xfeb80fd0, "vqrshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880a10, 0xfeb80fd0, "vshll%c.%24?us8\t%12-15,22D, %0-3,5Q, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf2900810, 0xffb00fd0, "vshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900850, 0xffb00fd0, "vrshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2880510, 0xffb80f90, "vshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf3880410, 0xffb80f90, "vsri%c.8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf3880510, 0xffb80f90, "vsli%c.8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf3880610, 0xffb80f90, "vqshlu%c.s8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf2900810, 0xfeb00fd0, "vqshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900850, 0xfeb00fd0, "vqrshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900910, 0xfeb00fd0, "vqshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900950, 0xfeb00fd0, "vqrshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900a10, 0xfeb00fd0, "vshll%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf2880010, 0xfeb80f90, "vshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880110, 0xfeb80f90, "vsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880210, 0xfeb80f90, "vrshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880310, 0xfeb80f90, "vrsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880710, 0xfeb80f90, "vqshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf2a00810, 0xffa00fd0, "vshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00850, 0xffa00fd0, "vrshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2900510, 0xffb00f90, "vshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf3900410, 0xffb00f90, "vsri%c.16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf3900510, 0xffb00f90, "vsli%c.16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf3900610, 0xffb00f90, "vqshlu%c.s16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfea00fd0, "vshll%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf2900010, 0xfeb00f90, "vshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900110, 0xfeb00f90, "vsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900210, 0xfeb00f90, "vrshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900310, 0xfeb00f90, "vrsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900710, 0xfeb00f90, "vqshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf2800810, 0xfec00fd0, "vqshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2800850, 0xfec00fd0, "vqrshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2800910, 0xfec00fd0, "vqshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2800950, 0xfec00fd0, "vqrshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00510, 0xffa00f90, "vshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf3a00410, 0xffa00f90, "vsri%c.32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf3a00510, 0xffa00f90, "vsli%c.32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf3a00610, 0xffa00f90, "vqshlu%c.s32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf2a00010, 0xfea00f90, "vshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00110, 0xfea00f90, "vsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00210, 0xfea00f90, "vrshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00310, 0xfea00f90, "vrsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00710, 0xfea00f90, "vqshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf2800590, 0xff800f90, "vshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf3800490, 0xff800f90, "vsri%c.64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf3800590, 0xff800f90, "vsli%c.64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf3800690, 0xff800f90, "vqshlu%c.s64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf2800090, 0xfe800f90, "vshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800190, 0xfe800f90, "vsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800290, 0xfe800f90, "vrshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800390, 0xfe800f90, "vrsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800790, 0xfe800f90, "vqshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf2a00e10, 0xfea00e90, "vcvt%c.%24,8?usff32.%24,8?ffus32\t%12-15,22R, %0-3,5R, #%16-20e"}, - - /* Three registers of different lengths */ - {FPU_NEON_EXT_V1, 0xf2800e00, 0xfea00f50, "vmull%c.p%20S0\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800400, 0xff800f50, "vaddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf2800600, 0xff800f50, "vsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf2800900, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800b00, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800d00, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf3800400, 0xff800f50, "vraddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3800600, 0xff800f50, "vrsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf2800000, 0xfe800f50, "vaddl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800100, 0xfe800f50, "vaddw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800200, 0xfe800f50, "vsubl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800300, 0xfe800f50, "vsubw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800500, 0xfe800f50, "vabal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800700, 0xfe800f50, "vabdl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800800, 0xfe800f50, "vmlal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800a00, 0xfe800f50, "vmlsl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800c00, 0xfe800f50, "vmull%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - - /* Two registers and a scalar */ - {FPU_NEON_EXT_V1, 0xf2800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800340, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800540, 0xff800f50, "vmls%c.f%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800740, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800b40, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf3800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800540, 0xff800f50, "vmls%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf2800240, 0xfe800f50, "vmlal%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800640, 0xfe800f50, "vmlsl%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800a40, 0xfe800f50, "vmull%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - - /* Element and structure load/store */ - {FPU_NEON_EXT_V1, 0xf4a00fc0, 0xffb00fc0, "vld4%c.32\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00c00, 0xffb00f00, "vld1%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00d00, 0xffb00f00, "vld2%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00e00, 0xffb00f00, "vld3%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00f00, 0xffb00f00, "vld4%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4000200, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000300, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000400, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000500, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000600, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000700, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000800, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000900, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000a00, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000000, 0xff900e00, "v%21?ls%21?dt4%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4800000, 0xff900300, "v%21?ls%21?dt1%c.%10-11S2\t%B"}, - {FPU_NEON_EXT_V1, 0xf4800100, 0xff900300, "v%21?ls%21?dt2%c.%10-11S2\t%B"}, - {FPU_NEON_EXT_V1, 0xf4800200, 0xff900300, "v%21?ls%21?dt3%c.%10-11S2\t%B"}, - {FPU_NEON_EXT_V1, 0xf4800300, 0xff900300, "v%21?ls%21?dt4%c.%10-11S2\t%B"}, - - {0,0 ,0, 0} -}; - -/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially - ordered: they must be searched linearly from the top to obtain a correct - match. */ - -/* print_insn_arm recognizes the following format control codes: - - %% % - - %a print address for ldr/str instruction - %s print address for ldr/str halfword/signextend instruction - %b print branch destination - %c print condition code (always bits 28-31) - %m print register mask for ldm/stm instruction - %o print operand2 (immediate or register + shift) - %p print 'p' iff bits 12-15 are 15 - %t print 't' iff bit 21 set and bit 24 clear - %B print arm BLX(1) destination - %C print the PSR sub type. - %U print barrier type. - %P print address for pli instruction. - - %r print as an ARM register - %d print the bitfield in decimal - %W print the bitfield plus one in decimal - %x print the bitfield in hex - %X print the bitfield as 1 hex digit without leading "0x" - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order - - %e print arm SMI operand (bits 0..7,8..19). - %E print the LSB and WIDTH fields of a BFI or BFC instruction. - %V print the 16-bit immediate field of a MOVT or MOVW instruction. */ - -static const struct opcode32 arm_opcodes[] = -{ - /* ARM instructions. */ - {ARM_EXT_V1, 0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"}, - {ARM_EXT_V4T | ARM_EXT_V5, 0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"}, - {ARM_EXT_V2, 0x00000090, 0x0fe000f0, "mul%20's%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V2, 0x00200090, 0x0fe000f0, "mla%20's%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V2S, 0x01000090, 0x0fb00ff0, "swp%22'b%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - - /* IDIV instructions. */ - {ARM_EXT_DIV, 0x0710f010, 0x0ff0f0f0, "sdiv%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_DIV, 0x0730f010, 0x0ff0f0f0, "udiv%c\t%16-19r, %0-3r, %8-11r"}, - - /* V7 instructions. */ - {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"}, - {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"}, - {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"}, - {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"}, - {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"}, - - /* ARM V6T2 instructions. */ - {ARM_EXT_V6T2, 0x07c0001f, 0x0fe0007f, "bfc%c\t%12-15r, %E"}, - {ARM_EXT_V6T2, 0x07c00010, 0x0fe00070, "bfi%c\t%12-15r, %0-3r, %E"}, - {ARM_EXT_V6T2, 0x00600090, 0x0ff000f0, "mls%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6T2, 0x006000b0, 0x0f7000f0, "strht%c\t%12-15r, %s"}, - {ARM_EXT_V6T2, 0x00300090, 0x0f300090, "ldr%6's%5?hbt%c\t%12-15r, %s"}, - {ARM_EXT_V6T2, 0x03000000, 0x0ff00000, "movw%c\t%12-15r, %V"}, - {ARM_EXT_V6T2, 0x03400000, 0x0ff00000, "movt%c\t%12-15r, %V"}, - {ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"}, - - /* ARM V6Z instructions. */ - {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"}, - - /* ARM V6K instructions. */ - {ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"}, - {ARM_EXT_V6K, 0x01d00f9f, 0x0ff00fff, "ldrexb%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01b00f9f, 0x0ff00fff, "ldrexd%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01f00f9f, 0x0ff00fff, "ldrexh%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01c00f90, 0x0ff00ff0, "strexb%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01a00f90, 0x0ff00ff0, "strexd%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01e00f90, 0x0ff00ff0, "strexh%c\t%12-15r, %0-3r, [%16-19r]"}, - - /* ARM V6K NOP hints. */ - {ARM_EXT_V6K, 0x0320f001, 0x0fffffff, "yield%c"}, - {ARM_EXT_V6K, 0x0320f002, 0x0fffffff, "wfe%c"}, - {ARM_EXT_V6K, 0x0320f003, 0x0fffffff, "wfi%c"}, - {ARM_EXT_V6K, 0x0320f004, 0x0fffffff, "sev%c"}, - {ARM_EXT_V6K, 0x0320f000, 0x0fffff00, "nop%c\t{%0-7d}"}, - - /* ARM V6 instructions. */ - {ARM_EXT_V6, 0xf1080000, 0xfffffe3f, "cpsie\t%8'a%7'i%6'f"}, - {ARM_EXT_V6, 0xf10a0000, 0xfffffe20, "cpsie\t%8'a%7'i%6'f,#%0-4d"}, - {ARM_EXT_V6, 0xf10C0000, 0xfffffe3f, "cpsid\t%8'a%7'i%6'f"}, - {ARM_EXT_V6, 0xf10e0000, 0xfffffe20, "cpsid\t%8'a%7'i%6'f,#%0-4d"}, - {ARM_EXT_V6, 0xf1000000, 0xfff1fe20, "cps\t#%0-4d"}, - {ARM_EXT_V6, 0x06800010, 0x0ff00ff0, "pkhbt%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06800010, 0x0ff00070, "pkhbt%c\t%12-15r, %16-19r, %0-3r, lsl #%7-11d"}, - {ARM_EXT_V6, 0x06800050, 0x0ff00ff0, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #32"}, - {ARM_EXT_V6, 0x06800050, 0x0ff00070, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #%7-11d"}, - {ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19r]"}, - {ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t\%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t\%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t\%12-15r, %0-3r"}, - {ARM_EXT_V6, 0xf8100a00, 0xfe50ffff, "rfe%23?id%24?ba\t\%16-19r%21'!"}, - {ARM_EXT_V6, 0x06bf0070, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06bf0470, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06bf0870, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06bf0c70, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x068f0070, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x068f0470, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x068f0870, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x068f0c70, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06af0070, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06af0470, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06af0870, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06af0c70, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06ff0070, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06ff0470, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06ff0870, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06ff0c70, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06cf0070, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06cf0470, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06cf0870, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06cf0c70, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06ef0070, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06ef0470, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06ef0870, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06ef0c70, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06b00070, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06b00470, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06b00870, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06b00c70, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06800070, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06800470, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06800870, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06800c70, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06a00070, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06a00470, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06a00870, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06a00c70, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06f00070, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06f00470, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06f00870, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06f00c70, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06c00070, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06c00470, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06c00870, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06c00c70, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ROR #24"}, - {ARM_EXT_V6, 0x06e00070, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06e00470, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06e00870, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06e00c70, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06800fb0, 0x0ff00ff0, "sel%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0xf1010000, 0xfffffc00, "setend\t%9?ble"}, - {ARM_EXT_V6, 0x0700f010, 0x0ff0f0d0, "smuad%5'x%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x0700f050, 0x0ff0f0d0, "smusd%5'x%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07000010, 0x0ff000d0, "smlad%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x07400010, 0x0ff000d0, "smlald%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07000050, 0x0ff000d0, "smlsd%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x07400050, 0x0ff000d0, "smlsld%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x0750f010, 0x0ff0f0d0, "smmul%5'r%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07500010, 0x0ff000d0, "smmla%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x075000d0, 0x0ff000d0, "smmls%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0xf84d0500, 0xfe5fffe0, "srs%23?id%24?ba\t%16-19r%21'!, #%0-4d"}, - {ARM_EXT_V6, 0x06a00010, 0x0fe00ff0, "ssat%c\t%12-15r, #%16-20W, %0-3r"}, - {ARM_EXT_V6, 0x06a00010, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, lsl #%7-11d"}, - {ARM_EXT_V6, 0x06a00050, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, asr #%7-11d"}, - {ARM_EXT_V6, 0x06a00f30, 0x0ff00ff0, "ssat16%c\t%12-15r, #%16-19W, %0-3r"}, - {ARM_EXT_V6, 0x01800f90, 0x0ff00ff0, "strex%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V6, 0x00400090, 0x0ff000f0, "umaal%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x0780f010, 0x0ff0f0f0, "usad8%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07800010, 0x0ff000f0, "usada8%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x06e00010, 0x0fe00ff0, "usat%c\t%12-15r, #%16-20d, %0-3r"}, - {ARM_EXT_V6, 0x06e00010, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, lsl #%7-11d"}, - {ARM_EXT_V6, 0x06e00050, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, asr #%7-11d"}, - {ARM_EXT_V6, 0x06e00f30, 0x0ff00ff0, "usat16%c\t%12-15r, #%16-19d, %0-3r"}, - - /* V5J instruction. */ - {ARM_EXT_V5J, 0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"}, - - /* V5 Instructions. */ - {ARM_EXT_V5, 0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"}, - {ARM_EXT_V5, 0xfa000000, 0xfe000000, "blx\t%B"}, - {ARM_EXT_V5, 0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"}, - {ARM_EXT_V5, 0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"}, - - /* V5E "El Segundo" Instructions. */ - {ARM_EXT_V5E, 0x000000d0, 0x0e1000f0, "ldrd%c\t%12-15r, %s"}, - {ARM_EXT_V5E, 0x000000f0, 0x0e1000f0, "strd%c\t%12-15r, %s"}, - {ARM_EXT_V5E, 0xf450f000, 0xfc70f000, "pld\t%a"}, - {ARM_EXT_V5ExP, 0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - - {ARM_EXT_V5ExP, 0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - - {ARM_EXT_V5ExP, 0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - - {ARM_EXT_V5ExP, 0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"}, - - {ARM_EXT_V5ExP, 0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"}, - - {ARM_EXT_V5ExP, 0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"}, - {ARM_EXT_V5ExP, 0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"}, - {ARM_EXT_V5ExP, 0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"}, - {ARM_EXT_V5ExP, 0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"}, - - /* ARM Instructions. */ - {ARM_EXT_V1, 0x00000090, 0x0e100090, "str%6's%5?hb%c\t%12-15r, %s"}, - {ARM_EXT_V1, 0x00100090, 0x0e100090, "ldr%6's%5?hb%c\t%12-15r, %s"}, - {ARM_EXT_V1, 0x00000000, 0x0de00000, "and%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00200000, 0x0de00000, "eor%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00400000, 0x0de00000, "sub%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00600000, 0x0de00000, "rsb%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00800000, 0x0de00000, "add%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00a00000, 0x0de00000, "adc%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00c00000, 0x0de00000, "sbc%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00e00000, 0x0de00000, "rsc%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"}, - {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"}, - {ARM_EXT_V1, 0x01000000, 0x0de00000, "tst%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01200000, 0x0de00000, "teq%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01400000, 0x0de00000, "cmp%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01600000, 0x0de00000, "cmn%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01800000, 0x0de00000, "orr%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x03a00000, 0x0fef0000, "mov%20's%c\t%12-15r, %o"}, - {ARM_EXT_V1, 0x01a00000, 0x0def0ff0, "mov%20's%c\t%12-15r, %0-3r"}, - {ARM_EXT_V1, 0x01a00000, 0x0def0060, "lsl%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01a00020, 0x0def0060, "lsr%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01a00040, 0x0def0060, "asr%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01a00060, 0x0def0ff0, "rrx%20's%c\t%12-15r, %0-3r"}, - {ARM_EXT_V1, 0x01a00060, 0x0def0060, "ror%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01c00000, 0x0de00000, "bic%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x01e00000, 0x0de00000, "mvn%20's%c\t%12-15r, %o"}, - {ARM_EXT_V1, 0x052d0004, 0x0fff0fff, "push%c\t{%12-15r}\t\t; (str%c %12-15r, %a)"}, - {ARM_EXT_V1, 0x04000000, 0x0e100000, "str%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x06000000, 0x0e100ff0, "str%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x04000000, 0x0c100010, "str%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x06000010, 0x0e000010, "undefined"}, - {ARM_EXT_V1, 0x049d0004, 0x0fff0fff, "pop%c\t{%12-15r}\t\t; (ldr%c %12-15r, %a)"}, - {ARM_EXT_V1, 0x04100000, 0x0c100000, "ldr%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x092d0000, 0x0fff0000, "push%c\t%m"}, - {ARM_EXT_V1, 0x08800000, 0x0ff00000, "stm%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x08000000, 0x0e100000, "stm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x08bd0000, 0x0fff0000, "pop%c\t%m"}, - {ARM_EXT_V1, 0x08900000, 0x0f900000, "ldm%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x08100000, 0x0e100000, "ldm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x0a000000, 0x0e000000, "b%24'l%c\t%b"}, - {ARM_EXT_V1, 0x0f000000, 0x0f000000, "svc%c\t%0-23x"}, - - /* The rest. */ - {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined instruction %0-31x"}, - {0, 0x00000000, 0x00000000, 0} -}; - -/* print_insn_thumb16 recognizes the following format control codes: - - %S print Thumb register (bits 3..5 as high number if bit 6 set) - %D print Thumb register (bits 0..2 as high number if bit 7 set) - %I print bitfield as a signed decimal - (top bit of range being the sign bit) - %N print Thumb register mask (with LR) - %O print Thumb register mask (with PC) - %M print Thumb register mask - %b print CZB's 6-bit unsigned branch destination - %s print Thumb right-shift immediate (6..10; 0 == 32). - %c print the condition code - %C print the condition code, or "s" if not conditional - %x print warning if conditional an not at end of IT block" - %X print "\t; unpredictable " if conditional - %I print IT instruction suffix and operands - %r print bitfield as an ARM register - %d print bitfield as a decimal - %H print (bitfield * 2) as a decimal - %W print (bitfield * 4) as a decimal - %a print (bitfield * 4) as a pc-rel offset + decoded symbol - %B print Thumb branch destination (signed displacement) - %c print bitfield as a condition code - %'c print specified char iff bit is one - %?ab print a if bit is one else print b. */ - -static const struct opcode16 thumb_opcodes[] = -{ - /* Thumb instructions. */ - - /* ARM V6K no-argument instructions. */ - {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"}, - {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"}, - {ARM_EXT_V6K, 0xbf20, 0xffff, "wfe%c"}, - {ARM_EXT_V6K, 0xbf30, 0xffff, "wfi%c"}, - {ARM_EXT_V6K, 0xbf40, 0xffff, "sev%c"}, - {ARM_EXT_V6K, 0xbf00, 0xff0f, "nop%c\t{%4-7d}"}, - - /* ARM V6T2 instructions. */ - {ARM_EXT_V6T2, 0xb900, 0xfd00, "cbnz\t%0-2r, %b%X"}, - {ARM_EXT_V6T2, 0xb100, 0xfd00, "cbz\t%0-2r, %b%X"}, - {ARM_EXT_V6T2, 0xbf00, 0xff00, "it%I%X"}, - - /* ARM V6. */ - {ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f%X"}, - {ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f%X"}, - {ARM_EXT_V6, 0x4600, 0xffc0, "mov%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xba00, 0xffc0, "rev%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xba40, 0xffc0, "rev16%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xbac0, 0xffc0, "revsh%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb650, 0xfff7, "setend\t%3?ble%X"}, - {ARM_EXT_V6, 0xb200, 0xffc0, "sxth%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb240, 0xffc0, "sxtb%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb280, 0xffc0, "uxth%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb2c0, 0xffc0, "uxtb%c\t%0-2r, %3-5r"}, - - /* ARM V5 ISA extends Thumb. */ - {ARM_EXT_V5T, 0xbe00, 0xff00, "bkpt\t%0-7x"}, /* Is always unconditional. */ - /* This is BLX(2). BLX(1) is a 32-bit instruction. */ - {ARM_EXT_V5T, 0x4780, 0xff87, "blx%c\t%3-6r%x"}, /* note: 4 bit register number. */ - /* ARM V4T ISA (Thumb v1). */ - {ARM_EXT_V4T, 0x46C0, 0xFFFF, "nop%c\t\t\t(mov r8, r8)"}, - /* Format 4. */ - {ARM_EXT_V4T, 0x4000, 0xFFC0, "and%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4040, 0xFFC0, "eor%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4080, 0xFFC0, "lsl%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x40C0, 0xFFC0, "lsr%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4100, 0xFFC0, "asr%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4140, 0xFFC0, "adc%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4180, 0xFFC0, "sbc%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x41C0, 0xFFC0, "ror%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4200, 0xFFC0, "tst%c\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4240, 0xFFC0, "neg%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4280, 0xFFC0, "cmp%c\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x42C0, 0xFFC0, "cmn%c\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4300, 0xFFC0, "orr%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4340, 0xFFC0, "mul%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4380, 0xFFC0, "bic%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x43C0, 0xFFC0, "mvn%C\t%0-2r, %3-5r"}, - /* format 13 */ - {ARM_EXT_V4T, 0xB000, 0xFF80, "add%c\tsp, #%0-6W"}, - {ARM_EXT_V4T, 0xB080, 0xFF80, "sub%c\tsp, #%0-6W"}, - /* format 5 */ - {ARM_EXT_V4T, 0x4700, 0xFF80, "bx%c\t%S%x"}, - {ARM_EXT_V4T, 0x4400, 0xFF00, "add%c\t%D, %S"}, - {ARM_EXT_V4T, 0x4500, 0xFF00, "cmp%c\t%D, %S"}, - {ARM_EXT_V4T, 0x4600, 0xFF00, "mov%c\t%D, %S"}, - /* format 14 */ - {ARM_EXT_V4T, 0xB400, 0xFE00, "push%c\t%N"}, - {ARM_EXT_V4T, 0xBC00, 0xFE00, "pop%c\t%O"}, - /* format 2 */ - {ARM_EXT_V4T, 0x1800, 0xFE00, "add%C\t%0-2r, %3-5r, %6-8r"}, - {ARM_EXT_V4T, 0x1A00, 0xFE00, "sub%C\t%0-2r, %3-5r, %6-8r"}, - {ARM_EXT_V4T, 0x1C00, 0xFE00, "add%C\t%0-2r, %3-5r, #%6-8d"}, - {ARM_EXT_V4T, 0x1E00, 0xFE00, "sub%C\t%0-2r, %3-5r, #%6-8d"}, - /* format 8 */ - {ARM_EXT_V4T, 0x5200, 0xFE00, "strh%c\t%0-2r, [%3-5r, %6-8r]"}, - {ARM_EXT_V4T, 0x5A00, 0xFE00, "ldrh%c\t%0-2r, [%3-5r, %6-8r]"}, - {ARM_EXT_V4T, 0x5600, 0xF600, "ldrs%11?hb%c\t%0-2r, [%3-5r, %6-8r]"}, - /* format 7 */ - {ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, - {ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, - /* format 1 */ - {ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"}, - {ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"}, - {ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"}, - /* format 3 */ - {ARM_EXT_V4T, 0x2000, 0xF800, "mov%C\t%8-10r, #%0-7d"}, - {ARM_EXT_V4T, 0x2800, 0xF800, "cmp%c\t%8-10r, #%0-7d"}, - {ARM_EXT_V4T, 0x3000, 0xF800, "add%C\t%8-10r, #%0-7d"}, - {ARM_EXT_V4T, 0x3800, 0xF800, "sub%C\t%8-10r, #%0-7d"}, - /* format 6 */ - {ARM_EXT_V4T, 0x4800, 0xF800, "ldr%c\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=" */ - /* format 9 */ - {ARM_EXT_V4T, 0x6000, 0xF800, "str%c\t%0-2r, [%3-5r, #%6-10W]"}, - {ARM_EXT_V4T, 0x6800, 0xF800, "ldr%c\t%0-2r, [%3-5r, #%6-10W]"}, - {ARM_EXT_V4T, 0x7000, 0xF800, "strb%c\t%0-2r, [%3-5r, #%6-10d]"}, - {ARM_EXT_V4T, 0x7800, 0xF800, "ldrb%c\t%0-2r, [%3-5r, #%6-10d]"}, - /* format 10 */ - {ARM_EXT_V4T, 0x8000, 0xF800, "strh%c\t%0-2r, [%3-5r, #%6-10H]"}, - {ARM_EXT_V4T, 0x8800, 0xF800, "ldrh%c\t%0-2r, [%3-5r, #%6-10H]"}, - /* format 11 */ - {ARM_EXT_V4T, 0x9000, 0xF800, "str%c\t%8-10r, [sp, #%0-7W]"}, - {ARM_EXT_V4T, 0x9800, 0xF800, "ldr%c\t%8-10r, [sp, #%0-7W]"}, - /* format 12 */ - {ARM_EXT_V4T, 0xA000, 0xF800, "add%c\t%8-10r, pc, #%0-7W\t(adr %8-10r, %0-7a)"}, - {ARM_EXT_V4T, 0xA800, 0xF800, "add%c\t%8-10r, sp, #%0-7W"}, - /* format 15 */ - {ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"}, - {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"}, - /* format 17 */ - {ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"}, - /* format 16 */ - {ARM_EXT_V4T, 0xDE00, 0xFE00, "undefined"}, - {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B%X"}, - /* format 18 */ - {ARM_EXT_V4T, 0xE000, 0xF800, "b%c.n\t%0-10B%x"}, - - /* The E800 .. FFFF range is unconditionally redirected to the - 32-bit table, because even in pre-V6T2 ISAs, BL and BLX(1) pairs - are processed via that table. Thus, we can never encounter a - bare "second half of BL/BLX(1)" instruction here. */ - {ARM_EXT_V1, 0x0000, 0x0000, "undefined"}, - {0, 0, 0, 0} -}; - -/* Thumb32 opcodes use the same table structure as the ARM opcodes. - We adopt the convention that hw1 is the high 16 bits of .value and - .mask, hw2 the low 16 bits. - - print_insn_thumb32 recognizes the following format control codes: - - %% % - - %I print a 12-bit immediate from hw1[10],hw2[14:12,7:0] - %M print a modified 12-bit immediate (same location) - %J print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0] - %K print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4] - %S print a possibly-shifted Rm - - %a print the address of a plain load/store - %w print the width and signedness of a core load/store - %m print register mask for ldm/stm - - %E print the lsb and width fields of a bfc/bfi instruction - %F print the lsb and width fields of a sbfx/ubfx instruction - %b print a conditional branch offset - %B print an unconditional branch offset - %s print the shift field of an SSAT instruction - %R print the rotation field of an SXT instruction - %U print barrier type. - %P print address for pli instruction. - %c print the condition code - %x print warning if conditional an not at end of IT block" - %X print "\t; unpredictable " if conditional - - %d print bitfield in decimal - %W print bitfield*4 in decimal - %r print bitfield as an ARM register - %c print bitfield as a condition code - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order - - With one exception at the bottom (done because BL and BLX(1) need - to come dead last), this table was machine-sorted first in - decreasing order of number of bits set in the mask, then in - increasing numeric order of mask, then in increasing numeric order - of opcode. This order is not the clearest for a human reader, but - is guaranteed never to catch a special-case bit pattern with a more - general mask, which is important, because this instruction encoding - makes heavy use of special-case bit patterns. */ -static const struct opcode32 thumb32_opcodes[] = -{ - /* V7 instructions. */ - {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"}, - {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"}, - {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"}, - {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"}, - {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"}, - {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"}, - - /* Instructions defined in the basic V6T2 set. */ - {ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"}, - {ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"}, - {ARM_EXT_V6T2, 0xf3af8002, 0xffffffff, "wfe%c.w"}, - {ARM_EXT_V6T2, 0xf3af8003, 0xffffffff, "wfi%c.w"}, - {ARM_EXT_V6T2, 0xf3af9004, 0xffffffff, "sev%c.w"}, - {ARM_EXT_V6T2, 0xf3af8000, 0xffffff00, "nop%c.w\t{%0-7d}"}, - - {ARM_EXT_V6T2, 0xf3bf8f2f, 0xffffffff, "clrex%c"}, - {ARM_EXT_V6T2, 0xf3af8400, 0xffffff1f, "cpsie.w\t%7'a%6'i%5'f%X"}, - {ARM_EXT_V6T2, 0xf3af8600, 0xffffff1f, "cpsid.w\t%7'a%6'i%5'f%X"}, - {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"}, - {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"}, - {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"}, - {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"}, - {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"}, - {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"}, - {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"}, - {ARM_EXT_V6T2, 0xf3af8500, 0xffffff00, "cpsie\t%7'a%6'i%5'f, #%0-4d%X"}, - {ARM_EXT_V6T2, 0xf3af8700, 0xffffff00, "cpsid\t%7'a%6'i%5'f, #%0-4d%X"}, - {ARM_EXT_V6T2, 0xf3de8f00, 0xffffff00, "subs%c\tpc, lr, #%0-7d"}, - {ARM_EXT_V6T2, 0xf3808000, 0xffe0f000, "msr%c\t%C, %16-19r"}, - {ARM_EXT_V6T2, 0xe8500f00, 0xfff00fff, "ldrex%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe8d00f4f, 0xfff00fef, "ldrex%4?hb%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe800c000, 0xffd0ffe0, "srsdb%c\t%16-19r%21'!, #%0-4d"}, - {ARM_EXT_V6T2, 0xe980c000, 0xffd0ffe0, "srsia%c\t%16-19r%21'!, #%0-4d"}, - {ARM_EXT_V6T2, 0xfa0ff080, 0xfffff0c0, "sxth%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa1ff080, 0xfffff0c0, "uxth%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa2ff080, 0xfffff0c0, "sxtb16%c\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa3ff080, 0xfffff0c0, "uxtb16%c\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa4ff080, 0xfffff0c0, "sxtb%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa5ff080, 0xfffff0c0, "uxtb%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xe8400000, 0xfff000ff, "strex%c\t%8-11r, %12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe8d0007f, 0xfff000ff, "ldrexd%c\t%12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xfa80f000, 0xfff0f0f0, "sadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f010, 0xfff0f0f0, "qadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f020, 0xfff0f0f0, "shadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f040, 0xfff0f0f0, "uadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f050, 0xfff0f0f0, "uqadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f060, 0xfff0f0f0, "uhadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f080, 0xfff0f0f0, "qadd%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa80f090, 0xfff0f0f0, "qdadd%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa80f0a0, 0xfff0f0f0, "qsub%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa80f0b0, 0xfff0f0f0, "qdsub%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f000, 0xfff0f0f0, "sadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f010, 0xfff0f0f0, "qadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f020, 0xfff0f0f0, "shadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f040, 0xfff0f0f0, "uadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f050, 0xfff0f0f0, "uqadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f060, 0xfff0f0f0, "uhadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f080, 0xfff0f0f0, "rev%c.w\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f010, 0xfff0f0f0, "qsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f020, 0xfff0f0f0, "shsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f040, 0xfff0f0f0, "usub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f050, 0xfff0f0f0, "uqsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f060, 0xfff0f0f0, "uhsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f000, 0xfff0f0f0, "ssub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f010, 0xfff0f0f0, "qsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f020, 0xfff0f0f0, "shsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa20f000, 0xffe0f0f0, "lsr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa40f000, 0xffe0f0f0, "asr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa60f000, 0xffe0f0f0, "ror%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xe8c00f40, 0xfff00fe0, "strex%4?hb%c\t%0-3r, %12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xf3200000, 0xfff0f0e0, "ssat16%c\t%8-11r, #%0-4d, %16-19r"}, - {ARM_EXT_V6T2, 0xf3a00000, 0xfff0f0e0, "usat16%c\t%8-11r, #%0-4d, %16-19r"}, - {ARM_EXT_V6T2, 0xfb20f000, 0xfff0f0e0, "smuad%4'x%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb30f000, 0xfff0f0e0, "smulw%4?tb%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb40f000, 0xfff0f0e0, "smusd%4'x%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb50f000, 0xfff0f0e0, "smmul%4'r%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa00f080, 0xfff0f0c0, "sxtah%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa10f080, 0xfff0f0c0, "uxtah%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa20f080, 0xfff0f0c0, "sxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa30f080, 0xfff0f0c0, "uxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa40f080, 0xfff0f0c0, "sxtab%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa50f080, 0xfff0f0c0, "uxtab%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfb10f000, 0xfff0f0c0, "smul%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xf36f0000, 0xffff8020, "bfc%c\t%8-11r, %E"}, - {ARM_EXT_V6T2, 0xea100f00, 0xfff08f00, "tst%c.w\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xea900f00, 0xfff08f00, "teq%c\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb100f00, 0xfff08f00, "cmn%c.w\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xebb00f00, 0xfff08f00, "cmp%c.w\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xf0100f00, 0xfbf08f00, "tst%c.w\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0900f00, 0xfbf08f00, "teq%c\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1100f00, 0xfbf08f00, "cmn%c.w\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1b00f00, 0xfbf08f00, "cmp%c.w\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xea4f0000, 0xffef8000, "mov%20's%c.w\t%8-11r, %S"}, - {ARM_EXT_V6T2, 0xea6f0000, 0xffef8000, "mvn%20's%c.w\t%8-11r, %S"}, - {ARM_EXT_V6T2, 0xe8c00070, 0xfff000f0, "strexd%c\t%0-3r, %12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xfb000000, 0xfff000f0, "mla%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb000010, 0xfff000f0, "mls%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb700000, 0xfff000f0, "usada8%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb800000, 0xfff000f0, "smull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfba00000, 0xfff000f0, "umull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbc00000, 0xfff000f0, "smlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"}, - {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"}, - {ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"}, - {ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"}, - {ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"}, - {ARM_EXT_V6T2, 0xfb200000, 0xfff000e0, "smlad%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb300000, 0xfff000e0, "smlaw%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb400000, 0xfff000e0, "smlsd%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb500000, 0xfff000e0, "smmla%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb600000, 0xfff000e0, "smmls%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfbc000c0, 0xfff000e0, "smlald%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbd000c0, 0xfff000e0, "smlsld%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xeac00000, 0xfff08030, "pkhbt%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeac00020, 0xfff08030, "pkhtb%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xf3400000, 0xfff08020, "sbfx%c\t%8-11r, %16-19r, %F"}, - {ARM_EXT_V6T2, 0xf3c00000, 0xfff08020, "ubfx%c\t%8-11r, %16-19r, %F"}, - {ARM_EXT_V6T2, 0xf8000e00, 0xff900f00, "str%wt%c\t%12-15r, %a"}, - {ARM_EXT_V6T2, 0xfb100000, 0xfff000c0, "smla%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfbc00080, 0xfff000c0, "smlal%5?tb%4?tb%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xf3600000, 0xfff08020, "bfi%c\t%8-11r, %16-19r, %E"}, - {ARM_EXT_V6T2, 0xf8100e00, 0xfe900f00, "ldr%wt%c\t%12-15r, %a"}, - {ARM_EXT_V6T2, 0xf3000000, 0xffd08020, "ssat%c\t%8-11r, #%0-4d, %16-19r%s"}, - {ARM_EXT_V6T2, 0xf3800000, 0xffd08020, "usat%c\t%8-11r, #%0-4d, %16-19r%s"}, - {ARM_EXT_V6T2, 0xf2000000, 0xfbf08000, "addw%c\t%8-11r, %16-19r, %I"}, - {ARM_EXT_V6T2, 0xf2400000, 0xfbf08000, "movw%c\t%8-11r, %J"}, - {ARM_EXT_V6T2, 0xf2a00000, 0xfbf08000, "subw%c\t%8-11r, %16-19r, %I"}, - {ARM_EXT_V6T2, 0xf2c00000, 0xfbf08000, "movt%c\t%8-11r, %J"}, - {ARM_EXT_V6T2, 0xea000000, 0xffe08000, "and%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea200000, 0xffe08000, "bic%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea400000, 0xffe08000, "orr%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea600000, 0xffe08000, "orn%20's%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea800000, 0xffe08000, "eor%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb000000, 0xffe08000, "add%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb400000, 0xffe08000, "adc%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb600000, 0xffe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeba00000, 0xffe08000, "sub%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xebc00000, 0xffe08000, "rsb%20's%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xe8400000, 0xfff00000, "strex%c\t%8-11r, %12-15r, [%16-19r, #%0-7W]"}, - {ARM_EXT_V6T2, 0xf0000000, 0xfbe08000, "and%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0200000, 0xfbe08000, "bic%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0400000, 0xfbe08000, "orr%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0600000, 0xfbe08000, "orn%20's%c\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0800000, 0xfbe08000, "eor%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1000000, 0xfbe08000, "add%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1400000, 0xfbe08000, "adc%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1600000, 0xfbe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1a00000, 0xfbe08000, "sub%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1c00000, 0xfbe08000, "rsb%20's%c\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xe8800000, 0xffd00000, "stmia%c.w\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe8900000, 0xffd00000, "ldmia%c.w\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe9000000, 0xffd00000, "stmdb%c\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe9100000, 0xffd00000, "ldmdb%c\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe9c00000, 0xffd000ff, "strd%c\t%12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe9d00000, 0xffd000ff, "ldrd%c\t%12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe9400000, 0xff500000, "strd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, - {ARM_EXT_V6T2, 0xe9500000, 0xff500000, "ldrd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, - {ARM_EXT_V6T2, 0xe8600000, 0xff700000, "strd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, - {ARM_EXT_V6T2, 0xe8700000, 0xff700000, "ldrd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, - {ARM_EXT_V6T2, 0xf8000000, 0xff100000, "str%w%c.w\t%12-15r, %a"}, - {ARM_EXT_V6T2, 0xf8100000, 0xfe100000, "ldr%w%c.w\t%12-15r, %a"}, - - /* Filter out Bcc with cond=E or F, which are used for other instructions. */ - {ARM_EXT_V6T2, 0xf3c08000, 0xfbc0d000, "undefined (bcc, cond=0xF)"}, - {ARM_EXT_V6T2, 0xf3808000, 0xfbc0d000, "undefined (bcc, cond=0xE)"}, - {ARM_EXT_V6T2, 0xf0008000, 0xf800d000, "b%22-25c.w\t%b%X"}, - {ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"}, - - /* These have been 32-bit since the invention of Thumb. */ - {ARM_EXT_V4T, 0xf000c000, 0xf800d000, "blx%c\t%B%x"}, - {ARM_EXT_V4T, 0xf000d000, 0xf800d000, "bl%c\t%B%x"}, - - /* Fallback. */ - {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined"}, - {0, 0, 0, 0} -}; - -static const char *const arm_conditional[] = -{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "al", "", ""}; - -static const char *const arm_fp_const[] = -{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; - -static const char *const arm_shift[] = -{"lsl", "lsr", "asr", "ror"}; - -typedef struct -{ - const char *name; - const char *description; - const char *reg_names[16]; -} -arm_regname; - -static const arm_regname regnames[] = -{ - { "raw" , "Select raw register names", - { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, - { "gcc", "Select register names used by GCC", - { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, - { "std", "Select register names used in ARM's ISA documentation", - { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, - { "apcs", "Select register names used in the APCS", - { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, - { "atpcs", "Select register names used in the ATPCS", - { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, - { "special-atpcs", "Select special register names used in the ATPCS", - { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}, -}; - -static const char *const iwmmxt_wwnames[] = -{"b", "h", "w", "d"}; - -static const char *const iwmmxt_wwssnames[] = -{"b", "bus", "bc", "bss", - "h", "hus", "hc", "hss", - "w", "wus", "wc", "wss", - "d", "dus", "dc", "dss" -}; - -static const char *const iwmmxt_regnames[] = -{ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", - "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15" -}; - -static const char *const iwmmxt_cregnames[] = -{ "wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", - "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved" -}; - -/* Default to GCC register name set. */ -static unsigned int regname_selected = 1; - -#define arm_regnames regnames[regname_selected].reg_names - -static bfd_boolean force_thumb = false; - -/* Current IT instruction state. This contains the same state as the IT - bits in the CPSR. */ -static unsigned int ifthen_state; -/* IT state for the next instruction. */ -static unsigned int ifthen_next_state; -/* The address of the insn for which the IT state is valid. */ -static bfd_vma ifthen_address; -#define IFTHEN_COND ((ifthen_state >> 4) & 0xf) - -/* Cached mapping symbol state. */ -enum map_type { - MAP_ARM, - MAP_THUMB, - MAP_DATA -}; - -/* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?. - Returns pointer to following character of the format string and - fills in *VALUEP and *WIDTHP with the extracted value and number of - bits extracted. WIDTHP can be NULL. */ - -static const char * -arm_decode_bitfield (const char *ptr, unsigned long insn, - unsigned long *valuep, int *widthp) -{ - unsigned long value = 0; - int width = 0; - - do - { - int start, end; - int bits; - - for (start = 0; *ptr >= '0' && *ptr <= '9'; ptr++) - start = start * 10 + *ptr - '0'; - if (*ptr == '-') - for (end = 0, ptr++; *ptr >= '0' && *ptr <= '9'; ptr++) - end = end * 10 + *ptr - '0'; - else - end = start; - bits = end - start; - if (bits < 0) - abort (); - value |= ((insn >> start) & ((2ul << bits) - 1)) << width; - width += bits + 1; - } - while (*ptr++ == ','); - *valuep = value; - if (widthp) - *widthp = width; - return ptr - 1; -} - -static void -arm_decode_shift (long given, fprintf_function func, void *stream, - int print_shift) -{ - func (stream, "%s", arm_regnames[given & 0xf]); - - if ((given & 0xff0) != 0) - { - if ((given & 0x10) == 0) - { - int amount = (given & 0xf80) >> 7; - int shift = (given & 0x60) >> 5; - - if (amount == 0) - { - if (shift == 3) - { - func (stream, ", rrx"); - return; - } - - amount = 32; - } - - if (print_shift) - func (stream, ", %s #%d", arm_shift[shift], amount); - else - func (stream, ", #%d", amount); - } - else if (print_shift) - func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], - arm_regnames[(given & 0xf00) >> 8]); - else - func (stream, ", %s", arm_regnames[(given & 0xf00) >> 8]); - } -} - -/* Print one coprocessor instruction on INFO->STREAM. - Return true if the instruction matched, false if this is not a - recognised coprocessor instruction. */ - -static bfd_boolean -print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, - bfd_boolean thumb) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - unsigned long mask; - unsigned long value; - int cond; - - for (insn = coprocessor_opcodes; insn->assembler; insn++) - { - if (insn->value == FIRST_IWMMXT_INSN - && info->mach != bfd_mach_arm_XScale - && info->mach != bfd_mach_arm_iWMMXt - && info->mach != bfd_mach_arm_iWMMXt2) - insn = insn + IWMMXT_INSN_COUNT; - - mask = insn->mask; - value = insn->value; - if (thumb) - { - /* The high 4 bits are 0xe for Arm conditional instructions, and - 0xe for arm unconditional instructions. The rest of the - encoding is the same. */ - mask |= 0xf0000000; - value |= 0xe0000000; - if (ifthen_state) - cond = IFTHEN_COND; - else - cond = 16; - } - else - { - /* Only match unconditional instructions against unconditional - patterns. */ - if ((given & 0xf0000000) == 0xf0000000) - { - mask |= 0xf0000000; - cond = 16; - } - else - { - cond = (given >> 28) & 0xf; - if (cond == 0xe) - cond = 16; - } - } - if ((given & mask) == value) - { - const char *c; - - for (c = insn->assembler; *c; c++) - { - if (*c == '%') - { - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'A': - func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - - if ((given & (1 << 24)) != 0) - { - int offset = given & 0xff; - - if (offset) - func (stream, ", #%s%d]%s", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4, - ((given & 0x00200000) != 0 ? "!" : "")); - else - func (stream, "]"); - } - else - { - int offset = given & 0xff; - - func (stream, "]"); - - if (given & (1 << 21)) - { - if (offset) - func (stream, ", #%s%d", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4); - } - else - func (stream, ", {%d}", offset); - } - break; - - case 'B': - { - int regno = ((given >> 12) & 0xf) | ((given >> (22 - 4)) & 0x10); - int offset = (given >> 1) & 0x3f; - - if (offset == 1) - func (stream, "{d%d}", regno); - else if (regno + offset > 32) - func (stream, "{d%d-}", regno, regno + offset - 1); - else - func (stream, "{d%d-d%d}", regno, regno + offset - 1); - } - break; - - case 'C': - { - int rn = (given >> 16) & 0xf; - int offset = (given & 0xff) * 4; - int add = (given >> 23) & 1; - - func (stream, "[%s", arm_regnames[rn]); - - if (offset) - { - if (!add) - offset = -offset; - func (stream, ", #%d", offset); - } - func (stream, "]"); - if (rn == 15) - { - func (stream, "\t; "); - /* FIXME: Unsure if info->bytes_per_chunk is the - right thing to use here. */ - info->print_address_func (offset + pc - + info->bytes_per_chunk * 2, info); - } - } - break; - - case 'c': - func (stream, "%s", arm_conditional[cond]); - break; - - case 'I': - /* Print a Cirrus/DSP shift immediate. */ - /* Immediates are 7bit signed ints with bits 0..3 in - bits 0..3 of opcode and bits 4..6 in bits 5..7 - of opcode. */ - { - int imm; - - imm = (given & 0xf) | ((given & 0xe0) >> 1); - - /* Is ``imm'' a negative number? */ - if (imm & 0x40) - imm |= (~0u << 7); - - func (stream, "%d", imm); - } - - break; - - case 'F': - switch (given & 0x00408000) - { - case 0: - func (stream, "4"); - break; - case 0x8000: - func (stream, "1"); - break; - case 0x00400000: - func (stream, "2"); - break; - default: - func (stream, "3"); - } - break; - - case 'P': - switch (given & 0x00080080) - { - case 0: - func (stream, "s"); - break; - case 0x80: - func (stream, "d"); - break; - case 0x00080000: - func (stream, "e"); - break; - default: - func (stream, ""); - break; - } - break; - case 'Q': - switch (given & 0x00408000) - { - case 0: - func (stream, "s"); - break; - case 0x8000: - func (stream, "d"); - break; - case 0x00400000: - func (stream, "e"); - break; - default: - func (stream, "p"); - break; - } - break; - case 'R': - switch (given & 0x60) - { - case 0: - break; - case 0x20: - func (stream, "p"); - break; - case 0x40: - func (stream, "m"); - break; - default: - func (stream, "z"); - break; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int width; - unsigned long value; - - c = arm_decode_bitfield (c, given, &value, &width); - - switch (*c) - { - case 'r': - func (stream, "%s", arm_regnames[value]); - break; - case 'D': - func (stream, "d%ld", value); - break; - case 'Q': - if (value & 1) - func (stream, "", value >> 1); - else - func (stream, "q%ld", value >> 1); - break; - case 'd': - func (stream, "%ld", value); - break; - case 'k': - { - int from = (given & (1 << 7)) ? 32 : 16; - func (stream, "%ld", from - value); - } - break; - - case 'f': - if (value > 7) - func (stream, "#%s", arm_fp_const[value & 7]); - else - func (stream, "f%ld", value); - break; - - case 'w': - if (width == 2) - func (stream, "%s", iwmmxt_wwnames[value]); - else - func (stream, "%s", iwmmxt_wwssnames[value]); - break; - - case 'g': - func (stream, "%s", iwmmxt_regnames[value]); - break; - case 'G': - func (stream, "%s", iwmmxt_cregnames[value]); - break; - - case 'x': - func (stream, "0x%lx", value); - break; - - case '`': - c++; - if (value == 0) - func (stream, "%c", *c); - break; - case '\'': - c++; - if (value == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - case '?': - func (stream, "%c", c[(1 << width) - (int)value]); - c += 1 << width; - break; - default: - abort (); - } - break; - - case 'y': - case 'z': - { - int single = *c++ == 'y'; - int regno; - - switch (*c) - { - case '4': /* Sm pair */ - func (stream, "{"); - /* Fall through. */ - case '0': /* Sm, Dm */ - regno = given & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 5) & 1; - } - else - regno += ((given >> 5) & 1) << 4; - break; - - case '1': /* Sd, Dd */ - regno = (given >> 12) & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 22) & 1; - } - else - regno += ((given >> 22) & 1) << 4; - break; - - case '2': /* Sn, Dn */ - regno = (given >> 16) & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 7) & 1; - } - else - regno += ((given >> 7) & 1) << 4; - break; - - case '3': /* List */ - func (stream, "{"); - regno = (given >> 12) & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 22) & 1; - } - else - regno += ((given >> 22) & 1) << 4; - break; - - default: - abort (); - } - - func (stream, "%c%d", single ? 's' : 'd', regno); - - if (*c == '3') - { - int count = given & 0xff; - - if (single == 0) - count >>= 1; - - if (--count) - { - func (stream, "-%c%d", - single ? 's' : 'd', - regno + count); - } - - func (stream, "}"); - } - else if (*c == '4') - func (stream, ", %c%d}", single ? 's' : 'd', - regno + 1); - } - break; - - case 'L': - switch (given & 0x00400100) - { - case 0x00000000: func (stream, "b"); break; - case 0x00400000: func (stream, "h"); break; - case 0x00000100: func (stream, "w"); break; - case 0x00400100: func (stream, "d"); break; - default: - break; - } - break; - - case 'Z': - { - int value; - /* given (20, 23) | given (0, 3) */ - value = ((given >> 16) & 0xf0) | (given & 0xf); - func (stream, "%d", value); - } - break; - - case 'l': - /* This is like the 'A' operator, except that if - the width field "M" is zero, then the offset is - *not* multiplied by four. */ - { - int offset = given & 0xff; - int multiplier = (given & 0x00000100) ? 4 : 1; - - func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - - if (offset) - { - if ((given & 0x01000000) != 0) - func (stream, ", #%s%d]%s", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * multiplier, - ((given & 0x00200000) != 0 ? "!" : "")); - else - func (stream, "], #%s%d", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * multiplier); - } - else - func (stream, "]"); - } - break; - - case 'r': - { - int imm4 = (given >> 4) & 0xf; - int puw_bits = ((given >> 22) & 6) | ((given >> 21) & 1); - int ubit = (given >> 23) & 1; - const char *rm = arm_regnames [given & 0xf]; - const char *rn = arm_regnames [(given >> 16) & 0xf]; - - switch (puw_bits) - { - case 1: - /* fall through */ - case 3: - func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm); - if (imm4) - func (stream, ", lsl #%d", imm4); - break; - - case 4: - /* fall through */ - case 5: - /* fall through */ - case 6: - /* fall through */ - case 7: - func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm); - if (imm4 > 0) - func (stream, ", lsl #%d", imm4); - func (stream, "]"); - if (puw_bits == 5 || puw_bits == 7) - func (stream, "!"); - break; - - default: - func (stream, "INVALID"); - } - } - break; - - case 'i': - { - long imm5; - imm5 = ((given & 0x100) >> 4) | (given & 0xf); - func (stream, "%ld", (imm5 == 0) ? 32 : imm5); - } - break; - - default: - abort (); - } - } - } - else - func (stream, "%c", *c); - } - return true; - } - } - return false; -} - -static void -print_arm_address (bfd_vma pc, struct disassemble_info *info, long given) -{ - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (((given & 0x000f0000) == 0x000f0000) - && ((given & 0x02000000) == 0)) - { - int offset = given & 0xfff; - - func (stream, "[pc"); - - if (given & 0x01000000) - { - if ((given & 0x00800000) == 0) - offset = - offset; - - /* Pre-indexed. */ - func (stream, ", #%d]", offset); - - offset += pc + 8; - - /* Cope with the possibility of write-back - being used. Probably a very dangerous thing - for the programmer to do, but who are we to - argue ? */ - if (given & 0x00200000) - func (stream, "!"); - } - else - { - /* Post indexed. */ - func (stream, "], #%d", offset); - - /* ie ignore the offset. */ - offset = pc + 8; - } - - func (stream, "\t; "); - info->print_address_func (offset, info); - } - else - { - func (stream, "[%s", - arm_regnames[(given >> 16) & 0xf]); - if ((given & 0x01000000) != 0) - { - if ((given & 0x02000000) == 0) - { - int offset = given & 0xfff; - if (offset) - func (stream, ", #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - } - else - { - func (stream, ", %s", - (((given & 0x00800000) == 0) - ? "-" : "")); - arm_decode_shift (given, func, stream, 1); - } - - func (stream, "]%s", - ((given & 0x00200000) != 0) ? "!" : ""); - } - else - { - if ((given & 0x02000000) == 0) - { - int offset = given & 0xfff; - if (offset) - func (stream, "], #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - else - func (stream, "]"); - } - else - { - func (stream, "], %s", - (((given & 0x00800000) == 0) - ? "-" : "")); - arm_decode_shift (given, func, stream, 1); - } - } - } -} - -/* Print one neon instruction on INFO->STREAM. - Return true if the instruction matched, false if this is not a - recognised neon instruction. */ - -static bfd_boolean -print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (thumb) - { - if ((given & 0xef000000) == 0xef000000) - { - /* move bit 28 to bit 24 to translate Thumb2 to ARM encoding. */ - unsigned long bit28 = given & (1 << 28); - - given &= 0x00ffffff; - if (bit28) - given |= 0xf3000000; - else - given |= 0xf2000000; - } - else if ((given & 0xff000000) == 0xf9000000) - given ^= 0xf9000000 ^ 0xf4000000; - else - return false; - } - - for (insn = neon_opcodes; insn->assembler; insn++) - { - if ((given & insn->mask) == insn->value) - { - const char *c; - - for (c = insn->assembler; *c; c++) - { - if (*c == '%') - { - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'c': - if (thumb && ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - break; - - case 'A': - { - static const unsigned char enc[16] = - { - 0x4, 0x14, /* st4 0,1 */ - 0x4, /* st1 2 */ - 0x4, /* st2 3 */ - 0x3, /* st3 4 */ - 0x13, /* st3 5 */ - 0x3, /* st1 6 */ - 0x1, /* st1 7 */ - 0x2, /* st2 8 */ - 0x12, /* st2 9 */ - 0x2, /* st1 10 */ - 0, 0, 0, 0, 0 - }; - int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); - int rn = ((given >> 16) & 0xf); - int rm = ((given >> 0) & 0xf); - int align = ((given >> 4) & 0x3); - int type = ((given >> 8) & 0xf); - int n = enc[type] & 0xf; - int stride = (enc[type] >> 4) + 1; - int ix; - - func (stream, "{"); - if (stride > 1) - for (ix = 0; ix != n; ix++) - func (stream, "%sd%d", ix ? "," : "", rd + ix * stride); - else if (n == 1) - func (stream, "d%d", rd); - else - func (stream, "d%d-d%d", rd, rd + n - 1); - func (stream, "}, [%s", arm_regnames[rn]); - if (align) - func (stream, ", :%d", 32 << align); - func (stream, "]"); - if (rm == 0xd) - func (stream, "!"); - else if (rm != 0xf) - func (stream, ", %s", arm_regnames[rm]); - } - break; - - case 'B': - { - int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); - int rn = ((given >> 16) & 0xf); - int rm = ((given >> 0) & 0xf); - int idx_align = ((given >> 4) & 0xf); - int align = 0; - int size = ((given >> 10) & 0x3); - int idx = idx_align >> (size + 1); - int length = ((given >> 8) & 3) + 1; - int stride = 1; - int i; - - if (length > 1 && size > 0) - stride = (idx_align & (1 << size)) ? 2 : 1; - - switch (length) - { - case 1: - { - int amask = (1 << size) - 1; - if ((idx_align & (1 << size)) != 0) - return false; - if (size > 0) - { - if ((idx_align & amask) == amask) - align = 8 << size; - else if ((idx_align & amask) != 0) - return false; - } - } - break; - - case 2: - if (size == 2 && (idx_align & 2) != 0) - return false; - align = (idx_align & 1) ? 16 << size : 0; - break; - - case 3: - if ((size == 2 && (idx_align & 3) != 0) - || (idx_align & 1) != 0) - return false; - break; - - case 4: - if (size == 2) - { - if ((idx_align & 3) == 3) - return false; - align = (idx_align & 3) * 64; - } - else - align = (idx_align & 1) ? 32 << size : 0; - break; - - default: - abort (); - } - - func (stream, "{"); - for (i = 0; i < length; i++) - func (stream, "%sd%d[%d]", (i == 0) ? "" : ",", - rd + i * stride, idx); - func (stream, "}, [%s", arm_regnames[rn]); - if (align) - func (stream, ", :%d", align); - func (stream, "]"); - if (rm == 0xd) - func (stream, "!"); - else if (rm != 0xf) - func (stream, ", %s", arm_regnames[rm]); - } - break; - - case 'C': - { - int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); - int rn = ((given >> 16) & 0xf); - int rm = ((given >> 0) & 0xf); - int align = ((given >> 4) & 0x1); - int size = ((given >> 6) & 0x3); - int type = ((given >> 8) & 0x3); - int n = type + 1; - int stride = ((given >> 5) & 0x1); - int ix; - - if (stride && (n == 1)) - n++; - else - stride++; - - func (stream, "{"); - if (stride > 1) - for (ix = 0; ix != n; ix++) - func (stream, "%sd%d[]", ix ? "," : "", rd + ix * stride); - else if (n == 1) - func (stream, "d%d[]", rd); - else - func (stream, "d%d[]-d%d[]", rd, rd + n - 1); - func (stream, "}, [%s", arm_regnames[rn]); - if (align) - { - int align = (8 * (type + 1)) << size; - if (type == 3) - align = (size > 1) ? align >> 1 : align; - if (type == 2 || (type == 0 && !size)) - func (stream, ", :", align); - else - func (stream, ", :%d", align); - } - func (stream, "]"); - if (rm == 0xd) - func (stream, "!"); - else if (rm != 0xf) - func (stream, ", %s", arm_regnames[rm]); - } - break; - - case 'D': - { - int raw_reg = (given & 0xf) | ((given >> 1) & 0x10); - int size = (given >> 20) & 3; - int reg = raw_reg & ((4 << size) - 1); - int ix = raw_reg >> size >> 2; - - func (stream, "d%d[%d]", reg, ix); - } - break; - - case 'E': - /* Neon encoded constant for mov, mvn, vorr, vbic */ - { - int bits = 0; - int cmode = (given >> 8) & 0xf; - int op = (given >> 5) & 0x1; - unsigned long value = 0, hival = 0; - unsigned shift; - int size = 0; - int isfloat = 0; - - bits |= ((given >> 24) & 1) << 7; - bits |= ((given >> 16) & 7) << 4; - bits |= ((given >> 0) & 15) << 0; - - if (cmode < 8) - { - shift = (cmode >> 1) & 3; - value = (unsigned long)bits << (8 * shift); - size = 32; - } - else if (cmode < 12) - { - shift = (cmode >> 1) & 1; - value = (unsigned long)bits << (8 * shift); - size = 16; - } - else if (cmode < 14) - { - shift = (cmode & 1) + 1; - value = (unsigned long)bits << (8 * shift); - value |= (1ul << (8 * shift)) - 1; - size = 32; - } - else if (cmode == 14) - { - if (op) - { - /* bit replication into bytes */ - int ix; - unsigned long mask; - - value = 0; - hival = 0; - for (ix = 7; ix >= 0; ix--) - { - mask = ((bits >> ix) & 1) ? 0xff : 0; - if (ix <= 3) - value = (value << 8) | mask; - else - hival = (hival << 8) | mask; - } - size = 64; - } - else - { - /* byte replication */ - value = (unsigned long)bits; - size = 8; - } - } - else if (!op) - { - /* floating point encoding */ - int tmp; - - value = (unsigned long)(bits & 0x7f) << 19; - value |= (unsigned long)(bits & 0x80) << 24; - tmp = bits & 0x40 ? 0x3c : 0x40; - value |= (unsigned long)tmp << 24; - size = 32; - isfloat = 1; - } - else - { - func (stream, "", - bits, cmode, op); - break; - } - switch (size) - { - case 8: - func (stream, "#%ld\t; 0x%.2lx", value, value); - break; - - case 16: - func (stream, "#%ld\t; 0x%.4lx", value, value); - break; - - case 32: - if (isfloat) - { - unsigned char valbytes[4]; - double fvalue; - - /* Do this a byte at a time so we don't have to - worry about the host's endianness. */ - valbytes[0] = value & 0xff; - valbytes[1] = (value >> 8) & 0xff; - valbytes[2] = (value >> 16) & 0xff; - valbytes[3] = (value >> 24) & 0xff; - - floatformat_to_double (valbytes, &fvalue); - - func (stream, "#%.7g\t; 0x%.8lx", fvalue, - value); - } - else - func (stream, "#%ld\t; 0x%.8lx", - (long) ((value & 0x80000000) - ? value | ~0xffffffffl : value), value); - break; - - case 64: - func (stream, "#0x%.8lx%.8lx", hival, value); - break; - - default: - abort (); - } - } - break; - - case 'F': - { - int regno = ((given >> 16) & 0xf) | ((given >> (7 - 4)) & 0x10); - int num = (given >> 8) & 0x3; - - if (!num) - func (stream, "{d%d}", regno); - else if (num + regno >= 32) - func (stream, "{d%d-= '0' && *c <= '9') - limit = *c - '0'; - else if (*c >= 'a' && *c <= 'f') - limit = *c - 'a' + 10; - else - abort (); - low = limit >> 2; - high = limit & 3; - - if (value < low || value > high) - func (stream, "", base << value); - else - func (stream, "%d", base << value); - } - break; - case 'R': - if (given & (1 << 6)) - goto Q; - /* FALLTHROUGH */ - case 'D': - func (stream, "d%ld", value); - break; - case 'Q': - Q: - if (value & 1) - func (stream, "", value >> 1); - else - func (stream, "q%ld", value >> 1); - break; - - case '`': - c++; - if (value == 0) - func (stream, "%c", *c); - break; - case '\'': - c++; - if (value == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - case '?': - func (stream, "%c", c[(1 << width) - (int)value]); - c += 1 << width; - break; - default: - abort (); - } - break; - - default: - abort (); - } - } - } - else - func (stream, "%c", *c); - } - return true; - } - } - return false; -} - -/* Print one ARM instruction from PC on INFO->STREAM. */ - -static void -print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (print_insn_coprocessor (pc, info, given, false)) - return; - - if (print_insn_neon (info, given, false)) - return; - - for (insn = arm_opcodes; insn->assembler; insn++) - { - if (insn->value == FIRST_IWMMXT_INSN - && info->mach != bfd_mach_arm_XScale - && info->mach != bfd_mach_arm_iWMMXt) - insn = insn + IWMMXT_INSN_COUNT; - - if ((given & insn->mask) == insn->value - /* Special case: an instruction with all bits set in the condition field - (0xFnnn_nnnn) is only matched if all those bits are set in insn->mask, - or by the catchall at the end of the table. */ - && ((given & 0xF0000000) != 0xF0000000 - || (insn->mask & 0xF0000000) == 0xF0000000 - || (insn->mask == 0 && insn->value == 0))) - { - const char *c; - - for (c = insn->assembler; *c; c++) - { - if (*c == '%') - { - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'a': - print_arm_address (pc, info, given); - break; - - case 'P': - /* Set P address bit and use normal address - printing routine. */ - print_arm_address (pc, info, given | (1 << 24)); - break; - - case 's': - if ((given & 0x004f0000) == 0x004f0000) - { - /* PC relative with immediate offset. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); - - if ((given & 0x00800000) == 0) - offset = -offset; - - func (stream, "[pc, #%d]\t; ", offset); - info->print_address_func (offset + pc + 8, info); - } - else - { - func (stream, "[%s", - arm_regnames[(given >> 16) & 0xf]); - if ((given & 0x01000000) != 0) - { - /* Pre-indexed. */ - if ((given & 0x00400000) == 0x00400000) - { - /* Immediate. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); - if (offset) - func (stream, ", #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - } - else - { - /* Register. */ - func (stream, ", %s%s", - (((given & 0x00800000) == 0) - ? "-" : ""), - arm_regnames[given & 0xf]); - } - - func (stream, "]%s", - ((given & 0x00200000) != 0) ? "!" : ""); - } - else - { - /* Post-indexed. */ - if ((given & 0x00400000) == 0x00400000) - { - /* Immediate. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); - if (offset) - func (stream, "], #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - else - func (stream, "]"); - } - else - { - /* Register. */ - func (stream, "], %s%s", - (((given & 0x00800000) == 0) - ? "-" : ""), - arm_regnames[given & 0xf]); - } - } - } - break; - - case 'b': - { - int disp = (((given & 0xffffff) ^ 0x800000) - 0x800000); - info->print_address_func (disp*4 + pc + 8, info); - } - break; - - case 'c': - if (((given >> 28) & 0xf) != 0xe) - func (stream, "%s", - arm_conditional [(given >> 28) & 0xf]); - break; - - case 'm': - { - int started = 0; - int reg; - - func (stream, "{"); - for (reg = 0; reg < 16; reg++) - if ((given & (1 << reg)) != 0) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[reg]); - } - func (stream, "}"); - } - break; - - case 'q': - arm_decode_shift (given, func, stream, 0); - break; - - case 'o': - if ((given & 0x02000000) != 0) - { - int rotate = (given & 0xf00) >> 7; - int immed = (given & 0xff); - immed = (((immed << (32 - rotate)) - | (immed >> rotate)) & 0xffffffff); - func (stream, "#%d\t; 0x%x", immed, immed); - } - else - arm_decode_shift (given, func, stream, 1); - break; - - case 'p': - if ((given & 0x0000f000) == 0x0000f000) - func (stream, "p"); - break; - - case 't': - if ((given & 0x01200000) == 0x00200000) - func (stream, "t"); - break; - - case 'A': - func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - - if ((given & (1 << 24)) != 0) - { - int offset = given & 0xff; - - if (offset) - func (stream, ", #%s%d]%s", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4, - ((given & 0x00200000) != 0 ? "!" : "")); - else - func (stream, "]"); - } - else - { - int offset = given & 0xff; - - func (stream, "]"); - - if (given & (1 << 21)) - { - if (offset) - func (stream, ", #%s%d", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4); - } - else - func (stream, ", {%d}", offset); - } - break; - - case 'B': - /* Print ARM V5 BLX(1) address: pc+25 bits. */ - { - bfd_vma address; - bfd_vma offset = 0; - - if (given & 0x00800000) - /* Is signed, hi bits should be ones. */ - offset = (-1) ^ 0x00ffffff; - - /* Offset is (SignExtend(offset field)<<2). */ - offset += given & 0x00ffffff; - offset <<= 2; - address = offset + pc + 8; - - if (given & 0x01000000) - /* H bit allows addressing to 2-byte boundaries. */ - address += 2; - - info->print_address_func (address, info); - } - break; - - case 'C': - func (stream, "_"); - if (given & 0x80000) - func (stream, "f"); - if (given & 0x40000) - func (stream, "s"); - if (given & 0x20000) - func (stream, "x"); - if (given & 0x10000) - func (stream, "c"); - break; - - case 'U': - switch (given & 0xf) - { - case 0xf: func(stream, "sy"); break; - case 0x7: func(stream, "un"); break; - case 0xe: func(stream, "st"); break; - case 0x6: func(stream, "unst"); break; - default: - func(stream, "#%d", (int)given & 0xf); - break; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int width; - unsigned long value; - - c = arm_decode_bitfield (c, given, &value, &width); - - switch (*c) - { - case 'r': - func (stream, "%s", arm_regnames[value]); - break; - case 'd': - func (stream, "%ld", value); - break; - case 'b': - func (stream, "%ld", value * 8); - break; - case 'W': - func (stream, "%ld", value + 1); - break; - case 'x': - func (stream, "0x%08lx", value); - - /* Some SWI instructions have special - meanings. */ - if ((given & 0x0fffffff) == 0x0FF00000) - func (stream, "\t; IMB"); - else if ((given & 0x0fffffff) == 0x0FF00001) - func (stream, "\t; IMBRange"); - break; - case 'X': - func (stream, "%01lx", value & 0xf); - break; - case '`': - c++; - if (value == 0) - func (stream, "%c", *c); - break; - case '\'': - c++; - if (value == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - case '?': - func (stream, "%c", c[(1 << width) - (int)value]); - c += 1 << width; - break; - default: - abort (); - } - break; - - case 'e': - { - int imm; - - imm = (given & 0xf) | ((given & 0xfff00) >> 4); - func (stream, "%d", imm); - } - break; - - case 'E': - /* LSB and WIDTH fields of BFI or BFC. The machine- - language instruction encodes LSB and MSB. */ - { - long msb = (given & 0x001f0000) >> 16; - long lsb = (given & 0x00000f80) >> 7; - - long width = msb - lsb + 1; - if (width > 0) - func (stream, "#%lu, #%lu", lsb, width); - else - func (stream, "(invalid: %lu:%lu)", lsb, msb); - } - break; - - case 'V': - /* 16-bit unsigned immediate from a MOVT or MOVW - instruction, encoded in bits 0:11 and 15:19. */ - { - long hi = (given & 0x000f0000) >> 4; - long lo = (given & 0x00000fff); - long imm16 = hi | lo; - func (stream, "#%lu\t; 0x%lx", imm16, imm16); - } - break; - - default: - abort (); - } - } - } - else - func (stream, "%c", *c); - } - return; - } - } - abort (); -} - -/* Print one 16-bit Thumb instruction from PC on INFO->STREAM. */ - -static void -print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given) -{ - const struct opcode16 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - for (insn = thumb_opcodes; insn->assembler; insn++) - if ((given & insn->mask) == insn->value) - { - const char *c = insn->assembler; - for (; *c; c++) - { - int domaskpc = 0; - int domasklr = 0; - - if (*c != '%') - { - func (stream, "%c", *c); - continue; - } - - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'c': - if (ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - break; - - case 'C': - if (ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - else - func (stream, "s"); - break; - - case 'I': - { - unsigned int tmp; - - ifthen_next_state = given & 0xff; - for (tmp = given << 1; tmp & 0xf; tmp <<= 1) - func (stream, ((given ^ tmp) & 0x10) ? "e" : "t"); - func (stream, "\t%s", arm_conditional[(given >> 4) & 0xf]); - } - break; - - case 'x': - if (ifthen_next_state) - func (stream, "\t; unpredictable branch in IT block\n"); - break; - - case 'X': - if (ifthen_state) - func (stream, "\t; unpredictable ", - arm_conditional[IFTHEN_COND]); - break; - - case 'S': - { - long reg; - - reg = (given >> 3) & 0x7; - if (given & (1 << 6)) - reg += 8; - - func (stream, "%s", arm_regnames[reg]); - } - break; - - case 'D': - { - long reg; - - reg = given & 0x7; - if (given & (1 << 7)) - reg += 8; - - func (stream, "%s", arm_regnames[reg]); - } - break; - - case 'N': - if (given & (1 << 8)) - domasklr = 1; - /* Fall through. */ - case 'O': - if (*c == 'O' && (given & (1 << 8))) - domaskpc = 1; - /* Fall through. */ - case 'M': - { - int started = 0; - int reg; - - func (stream, "{"); - - /* It would be nice if we could spot - ranges, and generate the rS-rE format: */ - for (reg = 0; (reg < 8); reg++) - if ((given & (1 << reg)) != 0) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[reg]); - } - - if (domasklr) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[14] /* "lr" */); - } - - if (domaskpc) - { - if (started) - func (stream, ", "); - func (stream, "%s", arm_regnames[15] /* "pc" */); - } - - func (stream, "}"); - } - break; - - case 'b': - /* Print ARM V6T2 CZB address: pc+4+6 bits. */ - { - bfd_vma address = (pc + 4 - + ((given & 0x00f8) >> 2) - + ((given & 0x0200) >> 3)); - info->print_address_func (address, info); - } - break; - - case 's': - /* Right shift immediate -- bits 6..10; 1-31 print - as themselves, 0 prints as 32. */ - { - long imm = (given & 0x07c0) >> 6; - if (imm == 0) - imm = 32; - func (stream, "#%ld", imm); - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int bitstart = *c++ - '0'; - int bitend = 0; - - while (*c >= '0' && *c <= '9') - bitstart = (bitstart * 10) + *c++ - '0'; - - switch (*c) - { - case '-': - { - long reg; - - c++; - while (*c >= '0' && *c <= '9') - bitend = (bitend * 10) + *c++ - '0'; - if (!bitend) - abort (); - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; - switch (*c) - { - case 'r': - func (stream, "%s", arm_regnames[reg]); - break; - - case 'd': - func (stream, "%ld", reg); - break; - - case 'H': - func (stream, "%ld", reg << 1); - break; - - case 'W': - func (stream, "%ld", reg << 2); - break; - - case 'a': - /* PC-relative address -- the bottom two - bits of the address are dropped - before the calculation. */ - info->print_address_func - (((pc + 4) & ~3) + (reg << 2), info); - break; - - case 'x': - func (stream, "0x%04lx", reg); - break; - - case 'B': - reg = ((reg ^ (1 << bitend)) - (1 << bitend)); - info->print_address_func (reg * 2 + pc + 4, info); - break; - - case 'c': - func (stream, "%s", arm_conditional [reg]); - break; - - default: - abort (); - } - } - break; - - case '\'': - c++; - if ((given & (1 << bitstart)) != 0) - func (stream, "%c", *c); - break; - - case '?': - ++c; - if ((given & (1 << bitstart)) != 0) - func (stream, "%c", *c++); - else - func (stream, "%c", *++c); - break; - - default: - abort (); - } - } - break; - - default: - abort (); - } - } - return; - } - - /* No match. */ - abort (); -} - -/* Return the name of an V7M special register. */ -static const char * -psr_name (int regno) -{ - switch (regno) - { - case 0: return "APSR"; - case 1: return "IAPSR"; - case 2: return "EAPSR"; - case 3: return "PSR"; - case 5: return "IPSR"; - case 6: return "EPSR"; - case 7: return "IEPSR"; - case 8: return "MSP"; - case 9: return "PSP"; - case 16: return "PRIMASK"; - case 17: return "BASEPRI"; - case 18: return "BASEPRI_MASK"; - case 19: return "FAULTMASK"; - case 20: return "CONTROL"; - default: return ""; - } -} - -/* Print one 32-bit Thumb instruction from PC on INFO->STREAM. */ - -static void -print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (print_insn_coprocessor (pc, info, given, true)) - return; - - if (print_insn_neon (info, given, true)) - return; - - for (insn = thumb32_opcodes; insn->assembler; insn++) - if ((given & insn->mask) == insn->value) - { - const char *c = insn->assembler; - for (; *c; c++) - { - if (*c != '%') - { - func (stream, "%c", *c); - continue; - } - - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'c': - if (ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - break; - - case 'x': - if (ifthen_next_state) - func (stream, "\t; unpredictable branch in IT block\n"); - break; - - case 'X': - if (ifthen_state) - func (stream, "\t; unpredictable ", - arm_conditional[IFTHEN_COND]); - break; - - case 'I': - { - unsigned int imm12 = 0; - imm12 |= (given & 0x000000ffu); - imm12 |= (given & 0x00007000u) >> 4; - imm12 |= (given & 0x04000000u) >> 15; - func (stream, "#%u\t; 0x%x", imm12, imm12); - } - break; - - case 'M': - { - unsigned int bits = 0, imm, imm8, mod; - bits |= (given & 0x000000ffu); - bits |= (given & 0x00007000u) >> 4; - bits |= (given & 0x04000000u) >> 15; - imm8 = (bits & 0x0ff); - mod = (bits & 0xf00) >> 8; - switch (mod) - { - case 0: imm = imm8; break; - case 1: imm = ((imm8<<16) | imm8); break; - case 2: imm = ((imm8<<24) | (imm8 << 8)); break; - case 3: imm = ((imm8<<24) | (imm8 << 16) | (imm8 << 8) | imm8); break; - default: - mod = (bits & 0xf80) >> 7; - imm8 = (bits & 0x07f) | 0x80; - imm = (((imm8 << (32 - mod)) | (imm8 >> mod)) & 0xffffffff); - } - func (stream, "#%u\t; 0x%x", imm, imm); - } - break; - - case 'J': - { - unsigned int imm = 0; - imm |= (given & 0x000000ffu); - imm |= (given & 0x00007000u) >> 4; - imm |= (given & 0x04000000u) >> 15; - imm |= (given & 0x000f0000u) >> 4; - func (stream, "#%u\t; 0x%x", imm, imm); - } - break; - - case 'K': - { - unsigned int imm = 0; - imm |= (given & 0x000f0000u) >> 16; - imm |= (given & 0x00000ff0u) >> 0; - imm |= (given & 0x0000000fu) << 12; - func (stream, "#%u\t; 0x%x", imm, imm); - } - break; - - case 'S': - { - unsigned int reg = (given & 0x0000000fu); - unsigned int stp = (given & 0x00000030u) >> 4; - unsigned int imm = 0; - imm |= (given & 0x000000c0u) >> 6; - imm |= (given & 0x00007000u) >> 10; - - func (stream, "%s", arm_regnames[reg]); - switch (stp) - { - case 0: - if (imm > 0) - func (stream, ", lsl #%u", imm); - break; - - case 1: - if (imm == 0) - imm = 32; - func (stream, ", lsr #%u", imm); - break; - - case 2: - if (imm == 0) - imm = 32; - func (stream, ", asr #%u", imm); - break; - - case 3: - if (imm == 0) - func (stream, ", rrx"); - else - func (stream, ", ror #%u", imm); - } - } - break; - - case 'a': - { - unsigned int Rn = (given & 0x000f0000) >> 16; - unsigned int U = (given & 0x00800000) >> 23; - unsigned int op = (given & 0x00000f00) >> 8; - unsigned int i12 = (given & 0x00000fff); - unsigned int i8 = (given & 0x000000ff); - bfd_boolean writeback = false, postind = false; - int offset = 0; - - func (stream, "[%s", arm_regnames[Rn]); - if (U) /* 12-bit positive immediate offset */ - offset = i12; - else if (Rn == 15) /* 12-bit negative immediate offset */ - offset = -(int)i12; - else if (op == 0x0) /* shifted register offset */ - { - unsigned int Rm = (i8 & 0x0f); - unsigned int sh = (i8 & 0x30) >> 4; - func (stream, ", %s", arm_regnames[Rm]); - if (sh) - func (stream, ", lsl #%u", sh); - func (stream, "]"); - break; - } - else switch (op) - { - case 0xE: /* 8-bit positive immediate offset */ - offset = i8; - break; - - case 0xC: /* 8-bit negative immediate offset */ - offset = -i8; - break; - - case 0xF: /* 8-bit + preindex with wb */ - offset = i8; - writeback = true; - break; - - case 0xD: /* 8-bit - preindex with wb */ - offset = -i8; - writeback = true; - break; - - case 0xB: /* 8-bit + postindex */ - offset = i8; - postind = true; - break; - - case 0x9: /* 8-bit - postindex */ - offset = -i8; - postind = true; - break; - - default: - func (stream, ", ]"); - goto skip; - } - - if (postind) - func (stream, "], #%d", offset); - else - { - if (offset) - func (stream, ", #%d", offset); - func (stream, writeback ? "]!" : "]"); - } - - if (Rn == 15) - { - func (stream, "\t; "); - info->print_address_func (((pc + 4) & ~3) + offset, info); - } - } - skip: - break; - - case 'A': - { - unsigned int P = (given & 0x01000000) >> 24; - unsigned int U = (given & 0x00800000) >> 23; - unsigned int W = (given & 0x00400000) >> 21; - unsigned int Rn = (given & 0x000f0000) >> 16; - unsigned int off = (given & 0x000000ff); - - func (stream, "[%s", arm_regnames[Rn]); - if (P) - { - if (off || !U) - func (stream, ", #%c%u", U ? '+' : '-', off * 4); - func (stream, "]"); - if (W) - func (stream, "!"); - } - else - { - func (stream, "], "); - if (W) - func (stream, "#%c%u", U ? '+' : '-', off * 4); - else - func (stream, "{%u}", off); - } - } - break; - - case 'w': - { - unsigned int Sbit = (given & 0x01000000) >> 24; - unsigned int type = (given & 0x00600000) >> 21; - switch (type) - { - case 0: func (stream, Sbit ? "sb" : "b"); break; - case 1: func (stream, Sbit ? "sh" : "h"); break; - case 2: - if (Sbit) - func (stream, "??"); - break; - case 3: - func (stream, "??"); - break; - } - } - break; - - case 'm': - { - int started = 0; - int reg; - - func (stream, "{"); - for (reg = 0; reg < 16; reg++) - if ((given & (1 << reg)) != 0) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[reg]); - } - func (stream, "}"); - } - break; - - case 'E': - { - unsigned int msb = (given & 0x0000001f); - unsigned int lsb = 0; - lsb |= (given & 0x000000c0u) >> 6; - lsb |= (given & 0x00007000u) >> 10; - func (stream, "#%u, #%u", lsb, msb - lsb + 1); - } - break; - - case 'F': - { - unsigned int width = (given & 0x0000001f) + 1; - unsigned int lsb = 0; - lsb |= (given & 0x000000c0u) >> 6; - lsb |= (given & 0x00007000u) >> 10; - func (stream, "#%u, #%u", lsb, width); - } - break; - - case 'b': - { - unsigned int S = (given & 0x04000000u) >> 26; - unsigned int J1 = (given & 0x00002000u) >> 13; - unsigned int J2 = (given & 0x00000800u) >> 11; - int offset = 0; - - offset |= !S << 20; - offset |= J2 << 19; - offset |= J1 << 18; - offset |= (given & 0x003f0000) >> 4; - offset |= (given & 0x000007ff) << 1; - offset -= (1 << 20); - - info->print_address_func (pc + 4 + offset, info); - } - break; - - case 'B': - { - unsigned int S = (given & 0x04000000u) >> 26; - unsigned int I1 = (given & 0x00002000u) >> 13; - unsigned int I2 = (given & 0x00000800u) >> 11; - int offset = 0; - - offset |= !S << 24; - offset |= !(I1 ^ S) << 23; - offset |= !(I2 ^ S) << 22; - offset |= (given & 0x03ff0000u) >> 4; - offset |= (given & 0x000007ffu) << 1; - offset -= (1 << 24); - offset += pc + 4; - - /* BLX target addresses are always word aligned. */ - if ((given & 0x00001000u) == 0) - offset &= ~2u; - - info->print_address_func (offset, info); - } - break; - - case 's': - { - unsigned int shift = 0; - shift |= (given & 0x000000c0u) >> 6; - shift |= (given & 0x00007000u) >> 10; - if (given & 0x00200000u) - func (stream, ", asr #%u", shift); - else if (shift) - func (stream, ", lsl #%u", shift); - /* else print nothing - lsl #0 */ - } - break; - - case 'R': - { - unsigned int rot = (given & 0x00000030) >> 4; - if (rot) - func (stream, ", ror #%u", rot * 8); - } - break; - - case 'U': - switch (given & 0xf) - { - case 0xf: func(stream, "sy"); break; - case 0x7: func(stream, "un"); break; - case 0xe: func(stream, "st"); break; - case 0x6: func(stream, "unst"); break; - default: - func(stream, "#%d", (int)given & 0xf); - break; - } - break; - - case 'C': - if ((given & 0xff) == 0) - { - func (stream, "%cPSR_", (given & 0x100000) ? 'S' : 'C'); - if (given & 0x800) - func (stream, "f"); - if (given & 0x400) - func (stream, "s"); - if (given & 0x200) - func (stream, "x"); - if (given & 0x100) - func (stream, "c"); - } - else - { - func (stream, "%s", psr_name (given & 0xff)); - } - break; - - case 'D': - if ((given & 0xff) == 0) - func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C'); - else - func (stream, "%s", psr_name (given & 0xff)); - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int width; - unsigned long val; - - c = arm_decode_bitfield (c, given, &val, &width); - - switch (*c) - { - case 'd': func (stream, "%lu", val); break; - case 'W': func (stream, "%lu", val * 4); break; - case 'r': func (stream, "%s", arm_regnames[val]); break; - - case 'c': - func (stream, "%s", arm_conditional[val]); - break; - - case '\'': - c++; - if (val == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - - case '`': - c++; - if (val == 0) - func (stream, "%c", *c); - break; - - case '?': - func (stream, "%c", c[(1 << width) - (int)val]); - c += 1 << width; - break; - - default: - abort (); - } - } - break; - - default: - abort (); - } - } - return; - } - - /* No match. */ - abort (); -} - -/* Print data bytes on INFO->STREAM. */ - -static void -print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, struct disassemble_info *info, - long given) -{ - switch (info->bytes_per_chunk) - { - case 1: - info->fprintf_func (info->stream, ".byte\t0x%02lx", given); - break; - case 2: - info->fprintf_func (info->stream, ".short\t0x%04lx", given); - break; - case 4: - info->fprintf_func (info->stream, ".word\t0x%08lx", given); - break; - default: - abort (); - } -} - -/* Search back through the insn stream to determine if this instruction is - conditionally executed. */ -static void -find_ifthen_state (bfd_vma pc, struct disassemble_info *info, - bfd_boolean little) -{ - unsigned char b[2]; - unsigned int insn; - int status; - /* COUNT is twice the number of instructions seen. It will be odd if we - just crossed an instruction boundary. */ - int count; - int it_count; - unsigned int seen_it; - bfd_vma addr; - - ifthen_address = pc; - ifthen_state = 0; - - addr = pc; - count = 1; - it_count = 0; - seen_it = 0; - /* Scan backwards looking for IT instructions, keeping track of where - instruction boundaries are. We don't know if something is actually an - IT instruction until we find a definite instruction boundary. */ - for (;;) - { - if (addr == 0 || info->symbol_at_address_func(addr, info)) - { - /* A symbol must be on an instruction boundary, and will not - be within an IT block. */ - if (seen_it && (count & 1)) - break; - - return; - } - addr -= 2; - status = arm_read_memory (addr, (bfd_byte *)b, 2, info); - if (status) - return; - - if (little) - insn = (b[0]) | (b[1] << 8); - else - insn = (b[1]) | (b[0] << 8); - if (seen_it) - { - if ((insn & 0xf800) < 0xe800) - { - /* Addr + 2 is an instruction boundary. See if this matches - the expected boundary based on the position of the last - IT candidate. */ - if (count & 1) - break; - seen_it = 0; - } - } - if ((insn & 0xff00) == 0xbf00 && (insn & 0xf) != 0) - { - /* This could be an IT instruction. */ - seen_it = insn; - it_count = count >> 1; - } - if ((insn & 0xf800) >= 0xe800) - count++; - else - count = (count + 2) | 1; - /* IT blocks contain at most 4 instructions. */ - if (count >= 8 && !seen_it) - return; - } - /* We found an IT instruction. */ - ifthen_state = (seen_it & 0xe0) | ((seen_it << it_count) & 0x1f); - if ((ifthen_state & 0xf) == 0) - ifthen_state = 0; -} - -/* NOTE: There are no checks in these routines that - the relevant number of data bytes exist. */ - -int -print_insn_arm (bfd_vma pc, struct disassemble_info *info) -{ - unsigned char b[4]; - long given; - int status; - int is_thumb = false; - int is_data = false; - unsigned int size = 4; - void (*printer) (bfd_vma, struct disassemble_info *, long); - int little; - - little = (info->endian == BFD_ENDIAN_LITTLE); - is_thumb |= (pc & 1); - pc &= ~(bfd_vma)1; - - if (force_thumb) - is_thumb = true; - - info->bytes_per_line = 4; - - if (is_data) - { - int i; - - /* size was already set above. */ - info->bytes_per_chunk = size; - printer = print_insn_data; - - status = arm_read_memory (pc, (bfd_byte *)b, size, info); - given = 0; - if (little) - for (i = size - 1; i >= 0; i--) - given = b[i] | (given << 8); - else - for (i = 0; i < (int) size; i++) - given = b[i] | (given << 8); - } - else if (!is_thumb) - { - /* In ARM mode endianness is a straightforward issue: the instruction - is four bytes long and is either ordered 0123 or 3210. */ - printer = print_insn_arm_internal; - info->bytes_per_chunk = 4; - size = 4; - - status = arm_read_memory (pc, (bfd_byte *)b, 4, info); - if (little) - given = (b[0]) | (b[1] << 8) | (b[2] << 16) | ((unsigned)b[3] << 24); - else - given = (b[3]) | (b[2] << 8) | (b[1] << 16) | ((unsigned)b[0] << 24); - } - else - { - /* In Thumb mode we have the additional wrinkle of two - instruction lengths. Fortunately, the bits that determine - the length of the current instruction are always to be found - in the first two bytes. */ - printer = print_insn_thumb16; - info->bytes_per_chunk = 2; - size = 2; - - status = arm_read_memory (pc, (bfd_byte *)b, 2, info); - if (little) - given = (b[0]) | (b[1] << 8); - else - given = (b[1]) | (b[0] << 8); - - if (!status) - { - /* These bit patterns signal a four-byte Thumb - instruction. */ - if ((given & 0xF800) == 0xF800 - || (given & 0xF800) == 0xF000 - || (given & 0xF800) == 0xE800) - { - status = arm_read_memory (pc + 2, (bfd_byte *)b, 2, info); - if (little) - given = (b[0]) | (b[1] << 8) | (given << 16); - else - given = (b[1]) | (b[0] << 8) | (given << 16); - - printer = print_insn_thumb32; - size = 4; - } - } - - if (ifthen_address != pc) - find_ifthen_state(pc, info, little); - - if (ifthen_state) - { - if ((ifthen_state & 0xf) == 0x8) - ifthen_next_state = 0; - else - ifthen_next_state = (ifthen_state & 0xe0) - | ((ifthen_state & 0xf) << 1); - } - } - - if (status) - { - info->memory_error_func (status, pc, info); - return -1; - } - if (info->flags & INSN_HAS_RELOC) - /* If the instruction has a reloc associated with it, then - the offset field in the instruction will actually be the - addend for the reloc. (We are using REL type relocs). - In such cases, we can ignore the pc when computing - addresses, since the addend is not currently pc-relative. */ - pc = 0; - - /* We include the hexdump of the instruction. The format here - matches that used by objdump and the ARM ARM (in particular, - 32 bit Thumb instructions are displayed as pairs of halfwords, - not as a single word.) */ - if (is_thumb) - { - if (size == 2) - { - info->fprintf_func(info->stream, "%04lx ", - ((unsigned long)given) & 0xffff); - } - else - { - info->fprintf_func(info->stream, "%04lx %04lx ", - (((unsigned long)given) >> 16) & 0xffff, - ((unsigned long)given) & 0xffff); - } - } - else - { - info->fprintf_func(info->stream, "%08lx ", - ((unsigned long)given) & 0xffffffff); - } - - printer (pc, info, given); - - if (is_thumb) - { - ifthen_state = ifthen_next_state; - ifthen_address += size; - } - return size; -} diff --git a/disas/capstone.c b/disas/capstone.c index 20bc8f966955..fe3efb0d3c1e 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 (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - cap_dump_insn(info, insn); - if (--count <= 0) { - break; + 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; + } } + 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/i386.c b/disas/i386.c deleted file mode 100644 index 06c835236e6e..000000000000 --- a/disas/i386.c +++ /dev/null @@ -1,6771 +0,0 @@ -/* opcodes/i386-dis.c r1.126 */ -/* Print i386 instructions for GDB, the GNU debugger. - Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This file is part of GDB. - - 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 . */ - -/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) - July 1988 - modified by John Hassey (hassey@dg-rtp.dg.com) - x86-64 support added by Jan Hubicka (jh@suse.cz) - VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ - -/* The main tables describing the instructions is essentially a copy - of the "Opcode Map" chapter (Appendix A) of the Intel 80386 - Programmers Manual. Usually, there is a capital letter, followed - by a small letter. The capital letter tell the addressing mode, - and the small letter tells about the operand size. Refer to - the Intel manual for details. */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" -#include "qemu/cutils.h" - -/* include/opcode/i386.h r1.78 */ - -/* opcode/i386.h -- Intel 80386 opcode macros - Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. - - This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. - - 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 . */ - -/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived - ix86 Unix assemblers, generate floating point instructions with - reversed source and destination registers in certain cases. - Unfortunately, gcc and possibly many other programs use this - reversed syntax, so we're stuck with it. - - eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but - `fsub %st,%st(3)' results in st(3) = st - st(3), rather than - the expected st(3) = st(3) - st - - This happens with all the non-commutative arithmetic floating point - operations with two register operands, where the source register is - %st, and destination register is %st(i). - - The affected opcode map is dceX, dcfX, deeX, defX. */ - -#ifndef SYSV386_COMPAT -/* Set non-zero for broken, compatible instructions. Set to zero for - non-broken opcodes at your peril. gcc generates SystemV/386 - compatible instructions. */ -#define SYSV386_COMPAT 1 -#endif -#ifndef OLDGCC_COMPAT -/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could - generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands - reversed. */ -#define OLDGCC_COMPAT SYSV386_COMPAT -#endif - -#define MOV_AX_DISP32 0xa0 -#define POP_SEG_SHORT 0x07 -#define JUMP_PC_RELATIVE 0xeb -#define INT_OPCODE 0xcd -#define INT3_OPCODE 0xcc -/* The opcode for the fwait instruction, which disassembler treats as a - prefix when it can. */ -#define FWAIT_OPCODE 0x9b -#define ADDR_PREFIX_OPCODE 0x67 -#define DATA_PREFIX_OPCODE 0x66 -#define LOCK_PREFIX_OPCODE 0xf0 -#define CS_PREFIX_OPCODE 0x2e -#define DS_PREFIX_OPCODE 0x3e -#define ES_PREFIX_OPCODE 0x26 -#define FS_PREFIX_OPCODE 0x64 -#define GS_PREFIX_OPCODE 0x65 -#define SS_PREFIX_OPCODE 0x36 -#define REPNE_PREFIX_OPCODE 0xf2 -#define REPE_PREFIX_OPCODE 0xf3 - -#define TWO_BYTE_OPCODE_ESCAPE 0x0f -#define NOP_OPCODE (char) 0x90 - -/* register numbers */ -#define EBP_REG_NUM 5 -#define ESP_REG_NUM 4 - -/* modrm_byte.regmem for twobyte escape */ -#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM -/* index_base_byte.index for no index register addressing */ -#define NO_INDEX_REGISTER ESP_REG_NUM -/* index_base_byte.base for no base register addressing */ -#define NO_BASE_REGISTER EBP_REG_NUM -#define NO_BASE_REGISTER_16 6 - -/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ -#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ -#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) - -/* x86-64 extension prefix. */ -#define REX_OPCODE 0x40 - -/* Indicates 64 bit operand size. */ -#define REX_W 8 -/* High extension to reg field of modrm byte. */ -#define REX_R 4 -/* High extension to SIB index field. */ -#define REX_X 2 -/* High extension to base field of modrm or SIB, or reg field of opcode. */ -#define REX_B 1 - -/* max operands per insn */ -#define MAX_OPERANDS 4 - -/* max immediates per insn (lcall, ljmp, insertq, extrq) */ -#define MAX_IMMEDIATE_OPERANDS 2 - -/* max memory refs per insn (string ops) */ -#define MAX_MEMORY_OPERANDS 2 - -/* max size of insn mnemonics. */ -#define MAX_MNEM_SIZE 16 - -/* max size of register name in insn mnemonics. */ -#define MAX_REG_NAME_SIZE 8 - -/* opcodes/i386-dis.c r1.126 */ - -static int fetch_data2(struct disassemble_info *, bfd_byte *); -static int fetch_data(struct disassemble_info *, bfd_byte *); -static void ckprefix (void); -static const char *prefix_name (int, int); -static int print_insn (bfd_vma, disassemble_info *); -static void dofloat (int); -static void OP_ST (int, int); -static void OP_STi (int, int); -static int putop (const char *, int); -static void oappend (const char *); -static void append_seg (void); -static void OP_indirE (int, int); -static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp); -static void print_displacement (char *, bfd_vma); -static void OP_E (int, int); -static void OP_G (int, int); -static void OP_vvvv (int, int); -static bfd_vma get64 (void); -static bfd_signed_vma get32 (void); -static bfd_signed_vma get32s (void); -static int get16 (void); -static void set_op (bfd_vma, int); -static void OP_REG (int, int); -static void OP_IMREG (int, int); -static void OP_I (int, int); -static void OP_I64 (int, int); -static void OP_sI (int, int); -static void OP_J (int, int); -static void OP_SEG (int, int); -static void OP_DIR (int, int); -static void OP_OFF (int, int); -static void OP_OFF64 (int, int); -static void ptr_reg (int, int); -static void OP_ESreg (int, int); -static void OP_DSreg (int, int); -static void OP_C (int, int); -static void OP_D (int, int); -static void OP_T (int, int); -static void OP_R (int, int); -static void OP_MMX (int, int); -static void OP_XMM (int, int); -static void OP_EM (int, int); -static void OP_EX (int, int); -static void OP_EMC (int,int); -static void OP_MXC (int,int); -static void OP_MS (int, int); -static void OP_XS (int, int); -static void OP_M (int, int); -static void OP_VMX (int, int); -static void OP_0fae (int, int); -static void OP_0f07 (int, int); -static void NOP_Fixup1 (int, int); -static void NOP_Fixup2 (int, int); -static void OP_3DNowSuffix (int, int); -static void OP_SIMD_Suffix (int, int); -static void SIMD_Fixup (int, int); -static void PNI_Fixup (int, int); -static void SVME_Fixup (int, int); -static void INVLPG_Fixup (int, int); -static void BadOp (void); -static void VMX_Fixup (int, int); -static void REP_Fixup (int, int); -static void CMPXCHG8B_Fixup (int, int); -static void XMM_Fixup (int, int); -static void CRC32_Fixup (int, int); - -struct dis_private { - /* Points to first byte not fetched. */ - bfd_byte *max_fetched; - bfd_byte the_buffer[MAX_MNEM_SIZE]; - bfd_vma insn_start; - int orig_sizeflag; - sigjmp_buf bailout; -}; - -enum address_mode -{ - mode_16bit, - mode_32bit, - mode_64bit -}; - -static enum address_mode address_mode; - -/* Flags for the prefixes for the current instruction. See below. */ -static int prefixes; - -/* REX prefix the current instruction. See below. */ -static int rex; -/* Bits of REX we've already used. */ -static int rex_used; -/* Mark parts used in the REX prefix. When we are testing for - empty prefix (for 8bit register REX extension), just mask it - out. Otherwise test for REX bit is excuse for existence of REX - only in case value is nonzero. */ -#define USED_REX(value) \ - { \ - if (value) \ - { \ - if ((rex & value)) \ - rex_used |= (value) | REX_OPCODE; \ - } \ - else \ - rex_used |= REX_OPCODE; \ - } - -/* Flags for prefixes which we somehow handled when printing the - current instruction. */ -static int used_prefixes; - -/* The VEX.vvvv register, unencoded. */ -static int vex_reg; - -/* Flags stored in PREFIXES. */ -#define PREFIX_REPZ 1 -#define PREFIX_REPNZ 2 -#define PREFIX_LOCK 4 -#define PREFIX_CS 8 -#define PREFIX_SS 0x10 -#define PREFIX_DS 0x20 -#define PREFIX_ES 0x40 -#define PREFIX_FS 0x80 -#define PREFIX_GS 0x100 -#define PREFIX_DATA 0x200 -#define PREFIX_ADDR 0x400 -#define PREFIX_FWAIT 0x800 - -#define PREFIX_VEX_0F 0x1000 -#define PREFIX_VEX_0F38 0x2000 -#define PREFIX_VEX_0F3A 0x4000 - -/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) - to ADDR (exclusive) are valid. Returns 1 for success, longjmps - on error. */ -static int -fetch_data2(struct disassemble_info *info, bfd_byte *addr) -{ - int status; - struct dis_private *priv = (struct dis_private *) info->private_data; - bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); - - if (addr <= priv->the_buffer + MAX_MNEM_SIZE) - status = (*info->read_memory_func) (start, - priv->max_fetched, - addr - priv->max_fetched, - info); - else - status = -1; - if (status != 0) - { - /* If we did manage to read at least one byte, then - print_insn_i386 will do something sensible. Otherwise, print - an error. We do that here because this is where we know - STATUS. */ - if (priv->max_fetched == priv->the_buffer) - (*info->memory_error_func) (status, start, info); - siglongjmp(priv->bailout, 1); - } - else - priv->max_fetched = addr; - return 1; -} - -static int -fetch_data(struct disassemble_info *info, bfd_byte *addr) -{ - if (addr <= ((struct dis_private *) (info->private_data))->max_fetched) { - return 1; - } else { - return fetch_data2(info, addr); - } -} - - -#define XX { NULL, 0 } - -#define Bv { OP_vvvv, v_mode } -#define Eb { OP_E, b_mode } -#define Ev { OP_E, v_mode } -#define Ed { OP_E, d_mode } -#define Edq { OP_E, dq_mode } -#define Edqw { OP_E, dqw_mode } -#define Edqb { OP_E, dqb_mode } -#define Edqd { OP_E, dqd_mode } -#define indirEv { OP_indirE, stack_v_mode } -#define indirEp { OP_indirE, f_mode } -#define stackEv { OP_E, stack_v_mode } -#define Em { OP_E, m_mode } -#define Ew { OP_E, w_mode } -#define M { OP_M, 0 } /* lea, lgdt, etc. */ -#define Ma { OP_M, v_mode } -#define Mp { OP_M, f_mode } /* 32 or 48 bit memory operand for LDS, LES etc */ -#define Mq { OP_M, q_mode } -#define Gb { OP_G, b_mode } -#define Gv { OP_G, v_mode } -#define Gd { OP_G, d_mode } -#define Gdq { OP_G, dq_mode } -#define Gm { OP_G, m_mode } -#define Gw { OP_G, w_mode } -#define Rd { OP_R, d_mode } -#define Rm { OP_R, m_mode } -#define Ib { OP_I, b_mode } -#define sIb { OP_sI, b_mode } /* sign extended byte */ -#define Iv { OP_I, v_mode } -#define Iq { OP_I, q_mode } -#define Iv64 { OP_I64, v_mode } -#define Iw { OP_I, w_mode } -#define I1 { OP_I, const_1_mode } -#define Jb { OP_J, b_mode } -#define Jv { OP_J, v_mode } -#define Cm { OP_C, m_mode } -#define Dm { OP_D, m_mode } -#define Td { OP_T, d_mode } - -#define RMeAX { OP_REG, eAX_reg } -#define RMeBX { OP_REG, eBX_reg } -#define RMeCX { OP_REG, eCX_reg } -#define RMeDX { OP_REG, eDX_reg } -#define RMeSP { OP_REG, eSP_reg } -#define RMeBP { OP_REG, eBP_reg } -#define RMeSI { OP_REG, eSI_reg } -#define RMeDI { OP_REG, eDI_reg } -#define RMrAX { OP_REG, rAX_reg } -#define RMrBX { OP_REG, rBX_reg } -#define RMrCX { OP_REG, rCX_reg } -#define RMrDX { OP_REG, rDX_reg } -#define RMrSP { OP_REG, rSP_reg } -#define RMrBP { OP_REG, rBP_reg } -#define RMrSI { OP_REG, rSI_reg } -#define RMrDI { OP_REG, rDI_reg } -#define RMAL { OP_REG, al_reg } -#define RMAL { OP_REG, al_reg } -#define RMCL { OP_REG, cl_reg } -#define RMDL { OP_REG, dl_reg } -#define RMBL { OP_REG, bl_reg } -#define RMAH { OP_REG, ah_reg } -#define RMCH { OP_REG, ch_reg } -#define RMDH { OP_REG, dh_reg } -#define RMBH { OP_REG, bh_reg } -#define RMAX { OP_REG, ax_reg } -#define RMDX { OP_REG, dx_reg } - -#define eAX { OP_IMREG, eAX_reg } -#define eBX { OP_IMREG, eBX_reg } -#define eCX { OP_IMREG, eCX_reg } -#define eDX { OP_IMREG, eDX_reg } -#define eSP { OP_IMREG, eSP_reg } -#define eBP { OP_IMREG, eBP_reg } -#define eSI { OP_IMREG, eSI_reg } -#define eDI { OP_IMREG, eDI_reg } -#define AL { OP_IMREG, al_reg } -#define CL { OP_IMREG, cl_reg } -#define DL { OP_IMREG, dl_reg } -#define BL { OP_IMREG, bl_reg } -#define AH { OP_IMREG, ah_reg } -#define CH { OP_IMREG, ch_reg } -#define DH { OP_IMREG, dh_reg } -#define BH { OP_IMREG, bh_reg } -#define AX { OP_IMREG, ax_reg } -#define DX { OP_IMREG, dx_reg } -#define zAX { OP_IMREG, z_mode_ax_reg } -#define indirDX { OP_IMREG, indir_dx_reg } - -#define Sw { OP_SEG, w_mode } -#define Sv { OP_SEG, v_mode } -#define Ap { OP_DIR, 0 } -#define Ob { OP_OFF64, b_mode } -#define Ov { OP_OFF64, v_mode } -#define Xb { OP_DSreg, eSI_reg } -#define Xv { OP_DSreg, eSI_reg } -#define Xz { OP_DSreg, eSI_reg } -#define Yb { OP_ESreg, eDI_reg } -#define Yv { OP_ESreg, eDI_reg } -#define DSBX { OP_DSreg, eBX_reg } - -#define es { OP_REG, es_reg } -#define ss { OP_REG, ss_reg } -#define cs { OP_REG, cs_reg } -#define ds { OP_REG, ds_reg } -#define fs { OP_REG, fs_reg } -#define gs { OP_REG, gs_reg } - -#define MX { OP_MMX, 0 } -#define XM { OP_XMM, 0 } -#define EM { OP_EM, v_mode } -#define EMd { OP_EM, d_mode } -#define EMq { OP_EM, q_mode } -#define EXd { OP_EX, d_mode } -#define EXq { OP_EX, q_mode } -#define EXx { OP_EX, x_mode } -#define MS { OP_MS, v_mode } -#define XS { OP_XS, v_mode } -#define EMC { OP_EMC, v_mode } -#define MXC { OP_MXC, 0 } -#define VM { OP_VMX, q_mode } -#define OPSUF { OP_3DNowSuffix, 0 } -#define OPSIMD { OP_SIMD_Suffix, 0 } -#define XMM0 { XMM_Fixup, 0 } - -/* Used handle "rep" prefix for string instructions. */ -#define Xbr { REP_Fixup, eSI_reg } -#define Xvr { REP_Fixup, eSI_reg } -#define Ybr { REP_Fixup, eDI_reg } -#define Yvr { REP_Fixup, eDI_reg } -#define Yzr { REP_Fixup, eDI_reg } -#define indirDXr { REP_Fixup, indir_dx_reg } -#define ALr { REP_Fixup, al_reg } -#define eAXr { REP_Fixup, eAX_reg } - -#define cond_jump_flag { NULL, cond_jump_mode } -#define loop_jcxz_flag { NULL, loop_jcxz_mode } - -/* bits in sizeflag */ -#define SUFFIX_ALWAYS 4 -#define AFLAG 2 -#define DFLAG 1 - -#define b_mode 1 /* byte operand */ -#define v_mode 2 /* operand size depends on prefixes */ -#define w_mode 3 /* word operand */ -#define d_mode 4 /* double word operand */ -#define q_mode 5 /* quad word operand */ -#define t_mode 6 /* ten-byte operand */ -#define x_mode 7 /* 16-byte XMM operand */ -#define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ -#define cond_jump_mode 9 -#define loop_jcxz_mode 10 -#define dq_mode 11 /* operand size depends on REX prefixes. */ -#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ -#define f_mode 13 /* 4- or 6-byte pointer operand */ -#define const_1_mode 14 -#define stack_v_mode 15 /* v_mode for stack-related opcodes. */ -#define z_mode 16 /* non-quad operand size depends on prefixes */ -#define o_mode 17 /* 16-byte operand */ -#define dqb_mode 18 /* registers like dq_mode, memory like b_mode. */ -#define dqd_mode 19 /* registers like dq_mode, memory like d_mode. */ - -#define es_reg 100 -#define cs_reg 101 -#define ss_reg 102 -#define ds_reg 103 -#define fs_reg 104 -#define gs_reg 105 - -#define eAX_reg 108 -#define eCX_reg 109 -#define eDX_reg 110 -#define eBX_reg 111 -#define eSP_reg 112 -#define eBP_reg 113 -#define eSI_reg 114 -#define eDI_reg 115 - -#define al_reg 116 -#define cl_reg 117 -#define dl_reg 118 -#define bl_reg 119 -#define ah_reg 120 -#define ch_reg 121 -#define dh_reg 122 -#define bh_reg 123 - -#define ax_reg 124 -#define cx_reg 125 -#define dx_reg 126 -#define bx_reg 127 -#define sp_reg 128 -#define bp_reg 129 -#define si_reg 130 -#define di_reg 131 - -#define rAX_reg 132 -#define rCX_reg 133 -#define rDX_reg 134 -#define rBX_reg 135 -#define rSP_reg 136 -#define rBP_reg 137 -#define rSI_reg 138 -#define rDI_reg 139 - -#define z_mode_ax_reg 149 -#define indir_dx_reg 150 - -#define FLOATCODE 1 -#define USE_GROUPS 2 -#define USE_PREFIX_USER_TABLE 3 -#define X86_64_SPECIAL 4 -#define IS_3BYTE_OPCODE 5 - -#define FLOAT NULL, { { NULL, FLOATCODE } } - -#define GRP1a NULL, { { NULL, USE_GROUPS }, { NULL, 0 } } -#define GRP1b NULL, { { NULL, USE_GROUPS }, { NULL, 1 } } -#define GRP1S NULL, { { NULL, USE_GROUPS }, { NULL, 2 } } -#define GRP1Ss NULL, { { NULL, USE_GROUPS }, { NULL, 3 } } -#define GRP2b NULL, { { NULL, USE_GROUPS }, { NULL, 4 } } -#define GRP2S NULL, { { NULL, USE_GROUPS }, { NULL, 5 } } -#define GRP2b_one NULL, { { NULL, USE_GROUPS }, { NULL, 6 } } -#define GRP2S_one NULL, { { NULL, USE_GROUPS }, { NULL, 7 } } -#define GRP2b_cl NULL, { { NULL, USE_GROUPS }, { NULL, 8 } } -#define GRP2S_cl NULL, { { NULL, USE_GROUPS }, { NULL, 9 } } -#define GRP3b NULL, { { NULL, USE_GROUPS }, { NULL, 10 } } -#define GRP3S NULL, { { NULL, USE_GROUPS }, { NULL, 11 } } -#define GRP4 NULL, { { NULL, USE_GROUPS }, { NULL, 12 } } -#define GRP5 NULL, { { NULL, USE_GROUPS }, { NULL, 13 } } -#define GRP6 NULL, { { NULL, USE_GROUPS }, { NULL, 14 } } -#define GRP7 NULL, { { NULL, USE_GROUPS }, { NULL, 15 } } -#define GRP8 NULL, { { NULL, USE_GROUPS }, { NULL, 16 } } -#define GRP9 NULL, { { NULL, USE_GROUPS }, { NULL, 17 } } -#define GRP11_C6 NULL, { { NULL, USE_GROUPS }, { NULL, 18 } } -#define GRP11_C7 NULL, { { NULL, USE_GROUPS }, { NULL, 19 } } -#define GRP12 NULL, { { NULL, USE_GROUPS }, { NULL, 20 } } -#define GRP13 NULL, { { NULL, USE_GROUPS }, { NULL, 21 } } -#define GRP14 NULL, { { NULL, USE_GROUPS }, { NULL, 22 } } -#define GRP15 NULL, { { NULL, USE_GROUPS }, { NULL, 23 } } -#define GRP16 NULL, { { NULL, USE_GROUPS }, { NULL, 24 } } -#define GRPAMD NULL, { { NULL, USE_GROUPS }, { NULL, 25 } } -#define GRPPADLCK1 NULL, { { NULL, USE_GROUPS }, { NULL, 26 } } -#define GRPPADLCK2 NULL, { { NULL, USE_GROUPS }, { NULL, 27 } } - -#define PREGRP0 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 0 } } -#define PREGRP1 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 1 } } -#define PREGRP2 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 2 } } -#define PREGRP3 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 3 } } -#define PREGRP4 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 4 } } -#define PREGRP5 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 5 } } -#define PREGRP6 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 6 } } -#define PREGRP7 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 7 } } -#define PREGRP8 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 8 } } -#define PREGRP9 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 9 } } -#define PREGRP10 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 10 } } -#define PREGRP11 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 11 } } -#define PREGRP12 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 12 } } -#define PREGRP13 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 13 } } -#define PREGRP14 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 14 } } -#define PREGRP15 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 15 } } -#define PREGRP16 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 16 } } -#define PREGRP17 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 17 } } -#define PREGRP18 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 18 } } -#define PREGRP19 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 19 } } -#define PREGRP20 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 20 } } -#define PREGRP21 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 21 } } -#define PREGRP22 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 22 } } -#define PREGRP23 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 23 } } -#define PREGRP24 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 24 } } -#define PREGRP25 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 25 } } -#define PREGRP26 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 26 } } -#define PREGRP27 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 27 } } -#define PREGRP28 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 28 } } -#define PREGRP29 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 29 } } -#define PREGRP30 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 30 } } -#define PREGRP31 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 31 } } -#define PREGRP32 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 32 } } -#define PREGRP33 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 33 } } -#define PREGRP34 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 34 } } -#define PREGRP35 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } } -#define PREGRP36 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } } -#define PREGRP37 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } } -#define PREGRP38 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } } -#define PREGRP39 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 39 } } -#define PREGRP40 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 40 } } -#define PREGRP41 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 41 } } -#define PREGRP42 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 42 } } -#define PREGRP43 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 43 } } -#define PREGRP44 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 44 } } -#define PREGRP45 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 45 } } -#define PREGRP46 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 46 } } -#define PREGRP47 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 47 } } -#define PREGRP48 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 48 } } -#define PREGRP49 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 49 } } -#define PREGRP50 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 50 } } -#define PREGRP51 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 51 } } -#define PREGRP52 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 52 } } -#define PREGRP53 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 53 } } -#define PREGRP54 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 54 } } -#define PREGRP55 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 55 } } -#define PREGRP56 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 56 } } -#define PREGRP57 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 57 } } -#define PREGRP58 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 58 } } -#define PREGRP59 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 59 } } -#define PREGRP60 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 60 } } -#define PREGRP61 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 61 } } -#define PREGRP62 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 62 } } -#define PREGRP63 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 63 } } -#define PREGRP64 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 64 } } -#define PREGRP65 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 65 } } -#define PREGRP66 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 66 } } -#define PREGRP67 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 67 } } -#define PREGRP68 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 68 } } -#define PREGRP69 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 69 } } -#define PREGRP70 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 70 } } -#define PREGRP71 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 71 } } -#define PREGRP72 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 72 } } -#define PREGRP73 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 73 } } -#define PREGRP74 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 74 } } -#define PREGRP75 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 75 } } -#define PREGRP76 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 76 } } -#define PREGRP77 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 77 } } -#define PREGRP78 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 78 } } -#define PREGRP79 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 79 } } -#define PREGRP80 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 80 } } -#define PREGRP81 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 81 } } -#define PREGRP82 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 82 } } -#define PREGRP83 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 83 } } -#define PREGRP84 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 84 } } -#define PREGRP85 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 85 } } -#define PREGRP86 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 86 } } -#define PREGRP87 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 87 } } -#define PREGRP88 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 88 } } -#define PREGRP89 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 89 } } -#define PREGRP90 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 90 } } -#define PREGRP91 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 91 } } -#define PREGRP92 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 92 } } -#define PREGRP93 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 93 } } -#define PREGRP94 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 94 } } -#define PREGRP95 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } } -#define PREGRP96 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } } -#define PREGRP97 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } } -#define PREGRP98 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 98 } } -#define PREGRP99 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 99 } } -#define PREGRP100 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 100 } } -#define PREGRP101 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 101 } } -#define PREGRP102 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 102 } } -#define PREGRP103 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 103 } } -#define PREGRP104 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 104 } } -#define PREGRP105 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 105 } } -#define PREGRP106 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 106 } } -#define PREGRP107 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 107 } } -#define PREGRP108 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 108 } } -#define PREGRP109 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 109 } } - -#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } } -#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } } -#define X86_64_2 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 2 } } -#define X86_64_3 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 3 } } - -#define THREE_BYTE_0 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 0 } } -#define THREE_BYTE_1 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 1 } } - -typedef void (*op_rtn) (int bytemode, int sizeflag); - -struct dis386 { - const char *name; - struct - { - op_rtn rtn; - int bytemode; - } op[MAX_OPERANDS]; -}; - -/* Upper case letters in the instruction names here are macros. - 'A' => print 'b' if no register operands or suffix_always is true - 'B' => print 'b' if suffix_always is true - 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand - . size prefix - 'D' => print 'w' if no register operands or 'w', 'l' or 'q', if - . suffix_always is true - 'E' => print 'e' if 32-bit form of jcxz - 'F' => print 'w' or 'l' depending on address size prefix (loop insns) - 'G' => print 'w' or 'l' depending on operand size prefix (i/o insns) - 'H' => print ",pt" or ",pn" branch hint - 'I' => honor following macro letter even in Intel mode (implemented only - . for some of the macro letters) - 'J' => print 'l' - 'K' => print 'd' or 'q' if rex prefix is present. - 'L' => print 'l' if suffix_always is true - 'N' => print 'n' if instruction has no wait "prefix" - 'O' => print 'd' or 'o' (or 'q' in Intel mode) - 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, - . or suffix_always is true. print 'q' if rex prefix is present. - 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always - . is true - 'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode) - 'S' => print 'w', 'l' or 'q' if suffix_always is true - 'T' => print 'q' in 64bit mode and behave as 'P' otherwise - 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise - 'V' => print 'q' in 64bit mode and behave as 'S' otherwise - 'W' => print 'b', 'w' or 'l' ('d' in Intel mode) - 'X' => print 's', 'd' depending on data16 prefix (for XMM) - 'Y' => 'q' if instruction has an REX 64bit overwrite prefix - 'Z' => print 'q' in 64bit mode and behave as 'L' otherwise - - Many of the above letters print nothing in Intel mode. See "putop" - for the details. - - Braces '{' and '}', and vertical bars '|', indicate alternative - mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel - modes. In cases where there are only two alternatives, the X86_64 - instruction is reserved, and "(bad)" is printed. -*/ - -static const struct dis386 dis386[] = { - /* 00 */ - { "addB", { Eb, Gb } }, - { "addS", { Ev, Gv } }, - { "addB", { Gb, Eb } }, - { "addS", { Gv, Ev } }, - { "addB", { AL, Ib } }, - { "addS", { eAX, Iv } }, - { "push{T|}", { es } }, - { "pop{T|}", { es } }, - /* 08 */ - { "orB", { Eb, Gb } }, - { "orS", { Ev, Gv } }, - { "orB", { Gb, Eb } }, - { "orS", { Gv, Ev } }, - { "orB", { AL, Ib } }, - { "orS", { eAX, Iv } }, - { "push{T|}", { cs } }, - { "(bad)", { XX } }, /* 0x0f extended opcode escape */ - /* 10 */ - { "adcB", { Eb, Gb } }, - { "adcS", { Ev, Gv } }, - { "adcB", { Gb, Eb } }, - { "adcS", { Gv, Ev } }, - { "adcB", { AL, Ib } }, - { "adcS", { eAX, Iv } }, - { "push{T|}", { ss } }, - { "pop{T|}", { ss } }, - /* 18 */ - { "sbbB", { Eb, Gb } }, - { "sbbS", { Ev, Gv } }, - { "sbbB", { Gb, Eb } }, - { "sbbS", { Gv, Ev } }, - { "sbbB", { AL, Ib } }, - { "sbbS", { eAX, Iv } }, - { "push{T|}", { ds } }, - { "pop{T|}", { ds } }, - /* 20 */ - { "andB", { Eb, Gb } }, - { "andS", { Ev, Gv } }, - { "andB", { Gb, Eb } }, - { "andS", { Gv, Ev } }, - { "andB", { AL, Ib } }, - { "andS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG ES prefix */ - { "daa{|}", { XX } }, - /* 28 */ - { "subB", { Eb, Gb } }, - { "subS", { Ev, Gv } }, - { "subB", { Gb, Eb } }, - { "subS", { Gv, Ev } }, - { "subB", { AL, Ib } }, - { "subS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG CS prefix */ - { "das{|}", { XX } }, - /* 30 */ - { "xorB", { Eb, Gb } }, - { "xorS", { Ev, Gv } }, - { "xorB", { Gb, Eb } }, - { "xorS", { Gv, Ev } }, - { "xorB", { AL, Ib } }, - { "xorS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG SS prefix */ - { "aaa{|}", { XX } }, - /* 38 */ - { "cmpB", { Eb, Gb } }, - { "cmpS", { Ev, Gv } }, - { "cmpB", { Gb, Eb } }, - { "cmpS", { Gv, Ev } }, - { "cmpB", { AL, Ib } }, - { "cmpS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG DS prefix */ - { "aas{|}", { XX } }, - /* 40 */ - { "inc{S|}", { RMeAX } }, - { "inc{S|}", { RMeCX } }, - { "inc{S|}", { RMeDX } }, - { "inc{S|}", { RMeBX } }, - { "inc{S|}", { RMeSP } }, - { "inc{S|}", { RMeBP } }, - { "inc{S|}", { RMeSI } }, - { "inc{S|}", { RMeDI } }, - /* 48 */ - { "dec{S|}", { RMeAX } }, - { "dec{S|}", { RMeCX } }, - { "dec{S|}", { RMeDX } }, - { "dec{S|}", { RMeBX } }, - { "dec{S|}", { RMeSP } }, - { "dec{S|}", { RMeBP } }, - { "dec{S|}", { RMeSI } }, - { "dec{S|}", { RMeDI } }, - /* 50 */ - { "pushV", { RMrAX } }, - { "pushV", { RMrCX } }, - { "pushV", { RMrDX } }, - { "pushV", { RMrBX } }, - { "pushV", { RMrSP } }, - { "pushV", { RMrBP } }, - { "pushV", { RMrSI } }, - { "pushV", { RMrDI } }, - /* 58 */ - { "popV", { RMrAX } }, - { "popV", { RMrCX } }, - { "popV", { RMrDX } }, - { "popV", { RMrBX } }, - { "popV", { RMrSP } }, - { "popV", { RMrBP } }, - { "popV", { RMrSI } }, - { "popV", { RMrDI } }, - /* 60 */ - { X86_64_0 }, - { X86_64_1 }, - { X86_64_2 }, - { X86_64_3 }, - { "(bad)", { XX } }, /* seg fs */ - { "(bad)", { XX } }, /* seg gs */ - { "(bad)", { XX } }, /* op size prefix */ - { "(bad)", { XX } }, /* adr size prefix */ - /* 68 */ - { "pushT", { Iq } }, - { "imulS", { Gv, Ev, Iv } }, - { "pushT", { sIb } }, - { "imulS", { Gv, Ev, sIb } }, - { "ins{b||b|}", { Ybr, indirDX } }, - { "ins{R||G|}", { Yzr, indirDX } }, - { "outs{b||b|}", { indirDXr, Xb } }, - { "outs{R||G|}", { indirDXr, Xz } }, - /* 70 */ - { "joH", { Jb, XX, cond_jump_flag } }, - { "jnoH", { Jb, XX, cond_jump_flag } }, - { "jbH", { Jb, XX, cond_jump_flag } }, - { "jaeH", { Jb, XX, cond_jump_flag } }, - { "jeH", { Jb, XX, cond_jump_flag } }, - { "jneH", { Jb, XX, cond_jump_flag } }, - { "jbeH", { Jb, XX, cond_jump_flag } }, - { "jaH", { Jb, XX, cond_jump_flag } }, - /* 78 */ - { "jsH", { Jb, XX, cond_jump_flag } }, - { "jnsH", { Jb, XX, cond_jump_flag } }, - { "jpH", { Jb, XX, cond_jump_flag } }, - { "jnpH", { Jb, XX, cond_jump_flag } }, - { "jlH", { Jb, XX, cond_jump_flag } }, - { "jgeH", { Jb, XX, cond_jump_flag } }, - { "jleH", { Jb, XX, cond_jump_flag } }, - { "jgH", { Jb, XX, cond_jump_flag } }, - /* 80 */ - { GRP1b }, - { GRP1S }, - { "(bad)", { XX } }, - { GRP1Ss }, - { "testB", { Eb, Gb } }, - { "testS", { Ev, Gv } }, - { "xchgB", { Eb, Gb } }, - { "xchgS", { Ev, Gv } }, - /* 88 */ - { "movB", { Eb, Gb } }, - { "movS", { Ev, Gv } }, - { "movB", { Gb, Eb } }, - { "movS", { Gv, Ev } }, - { "movD", { Sv, Sw } }, - { "leaS", { Gv, M } }, - { "movD", { Sw, Sv } }, - { GRP1a }, - /* 90 */ - { PREGRP38 }, - { "xchgS", { RMeCX, eAX } }, - { "xchgS", { RMeDX, eAX } }, - { "xchgS", { RMeBX, eAX } }, - { "xchgS", { RMeSP, eAX } }, - { "xchgS", { RMeBP, eAX } }, - { "xchgS", { RMeSI, eAX } }, - { "xchgS", { RMeDI, eAX } }, - /* 98 */ - { "cW{t||t|}R", { XX } }, - { "cR{t||t|}O", { XX } }, - { "Jcall{T|}", { Ap } }, - { "(bad)", { XX } }, /* fwait */ - { "pushfT", { XX } }, - { "popfT", { XX } }, - { "sahf{|}", { XX } }, - { "lahf{|}", { XX } }, - /* a0 */ - { "movB", { AL, Ob } }, - { "movS", { eAX, Ov } }, - { "movB", { Ob, AL } }, - { "movS", { Ov, eAX } }, - { "movs{b||b|}", { Ybr, Xb } }, - { "movs{R||R|}", { Yvr, Xv } }, - { "cmps{b||b|}", { Xb, Yb } }, - { "cmps{R||R|}", { Xv, Yv } }, - /* a8 */ - { "testB", { AL, Ib } }, - { "testS", { eAX, Iv } }, - { "stosB", { Ybr, AL } }, - { "stosS", { Yvr, eAX } }, - { "lodsB", { ALr, Xb } }, - { "lodsS", { eAXr, Xv } }, - { "scasB", { AL, Yb } }, - { "scasS", { eAX, Yv } }, - /* b0 */ - { "movB", { RMAL, Ib } }, - { "movB", { RMCL, Ib } }, - { "movB", { RMDL, Ib } }, - { "movB", { RMBL, Ib } }, - { "movB", { RMAH, Ib } }, - { "movB", { RMCH, Ib } }, - { "movB", { RMDH, Ib } }, - { "movB", { RMBH, Ib } }, - /* b8 */ - { "movS", { RMeAX, Iv64 } }, - { "movS", { RMeCX, Iv64 } }, - { "movS", { RMeDX, Iv64 } }, - { "movS", { RMeBX, Iv64 } }, - { "movS", { RMeSP, Iv64 } }, - { "movS", { RMeBP, Iv64 } }, - { "movS", { RMeSI, Iv64 } }, - { "movS", { RMeDI, Iv64 } }, - /* c0 */ - { GRP2b }, - { GRP2S }, - { "retT", { Iw } }, - { "retT", { XX } }, - { "les{S|}", { Gv, Mp } }, - { "ldsS", { Gv, Mp } }, - { GRP11_C6 }, - { GRP11_C7 }, - /* c8 */ - { "enterT", { Iw, Ib } }, - { "leaveT", { XX } }, - { "lretP", { Iw } }, - { "lretP", { XX } }, - { "int3", { XX } }, - { "int", { Ib } }, - { "into{|}", { XX } }, - { "iretP", { XX } }, - /* d0 */ - { GRP2b_one }, - { GRP2S_one }, - { GRP2b_cl }, - { GRP2S_cl }, - { "aam{|}", { sIb } }, - { "aad{|}", { sIb } }, - { "(bad)", { XX } }, - { "xlat", { DSBX } }, - /* d8 */ - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - /* e0 */ - { "loopneFH", { Jb, XX, loop_jcxz_flag } }, - { "loopeFH", { Jb, XX, loop_jcxz_flag } }, - { "loopFH", { Jb, XX, loop_jcxz_flag } }, - { "jEcxzH", { Jb, XX, loop_jcxz_flag } }, - { "inB", { AL, Ib } }, - { "inG", { zAX, Ib } }, - { "outB", { Ib, AL } }, - { "outG", { Ib, zAX } }, - /* e8 */ - { "callT", { Jv } }, - { "jmpT", { Jv } }, - { "Jjmp{T|}", { Ap } }, - { "jmp", { Jb } }, - { "inB", { AL, indirDX } }, - { "inG", { zAX, indirDX } }, - { "outB", { indirDX, AL } }, - { "outG", { indirDX, zAX } }, - /* f0 */ - { "(bad)", { XX } }, /* lock prefix */ - { "icebp", { XX } }, - { "(bad)", { XX } }, /* repne */ - { "(bad)", { XX } }, /* repz */ - { "hlt", { XX } }, - { "cmc", { XX } }, - { GRP3b }, - { GRP3S }, - /* f8 */ - { "clc", { XX } }, - { "stc", { XX } }, - { "cli", { XX } }, - { "sti", { XX } }, - { "cld", { XX } }, - { "std", { XX } }, - { GRP4 }, - { GRP5 }, -}; - -static const struct dis386 dis386_twobyte[] = { - /* 00 */ - { GRP6 }, - { GRP7 }, - { "larS", { Gv, Ew } }, - { "lslS", { Gv, Ew } }, - { "(bad)", { XX } }, - { "syscall", { XX } }, - { "clts", { XX } }, - { "sysretP", { XX } }, - /* 08 */ - { "invd", { XX } }, - { "wbinvd", { XX } }, - { "(bad)", { XX } }, - { "ud2a", { XX } }, - { "(bad)", { XX } }, - { GRPAMD }, - { "femms", { XX } }, - { "", { MX, EM, OPSUF } }, /* See OP_3DNowSuffix. */ - /* 10 */ - { PREGRP8 }, - { PREGRP9 }, - { PREGRP30 }, - { "movlpX", { EXq, XM, { SIMD_Fixup, 'h' } } }, - { "unpcklpX", { XM, EXq } }, - { "unpckhpX", { XM, EXq } }, - { PREGRP31 }, - { "movhpX", { EXq, XM, { SIMD_Fixup, 'l' } } }, - /* 18 */ - { GRP16 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "nopQ", { Ev } }, - /* 20 */ - { "movZ", { Rm, Cm } }, - { "movZ", { Rm, Dm } }, - { "movZ", { Cm, Rm } }, - { "movZ", { Dm, Rm } }, - { "movL", { Rd, Td } }, - { "(bad)", { XX } }, - { "movL", { Td, Rd } }, - { "(bad)", { XX } }, - /* 28 */ - { "movapX", { XM, EXx } }, - { "movapX", { EXx, XM } }, - { PREGRP2 }, - { PREGRP33 }, - { PREGRP4 }, - { PREGRP3 }, - { PREGRP93 }, - { PREGRP94 }, - /* 30 */ - { "wrmsr", { XX } }, - { "rdtsc", { XX } }, - { "rdmsr", { XX } }, - { "rdpmc", { XX } }, - { "sysenter", { XX } }, - { "sysexit", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 38 */ - { THREE_BYTE_0 }, - { "(bad)", { XX } }, - { THREE_BYTE_1 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 40 */ - { "cmovo", { Gv, Ev } }, - { "cmovno", { Gv, Ev } }, - { "cmovb", { Gv, Ev } }, - { "cmovae", { Gv, Ev } }, - { "cmove", { Gv, Ev } }, - { "cmovne", { Gv, Ev } }, - { "cmovbe", { Gv, Ev } }, - { "cmova", { Gv, Ev } }, - /* 48 */ - { "cmovs", { Gv, Ev } }, - { "cmovns", { Gv, Ev } }, - { "cmovp", { Gv, Ev } }, - { "cmovnp", { Gv, Ev } }, - { "cmovl", { Gv, Ev } }, - { "cmovge", { Gv, Ev } }, - { "cmovle", { Gv, Ev } }, - { "cmovg", { Gv, Ev } }, - /* 50 */ - { "movmskpX", { Gdq, XS } }, - { PREGRP13 }, - { PREGRP12 }, - { PREGRP11 }, - { "andpX", { XM, EXx } }, - { "andnpX", { XM, EXx } }, - { "orpX", { XM, EXx } }, - { "xorpX", { XM, EXx } }, - /* 58 */ - { PREGRP0 }, - { PREGRP10 }, - { PREGRP17 }, - { PREGRP16 }, - { PREGRP14 }, - { PREGRP7 }, - { PREGRP5 }, - { PREGRP6 }, - /* 60 */ - { PREGRP95 }, - { PREGRP96 }, - { PREGRP97 }, - { "packsswb", { MX, EM } }, - { "pcmpgtb", { MX, EM } }, - { "pcmpgtw", { MX, EM } }, - { "pcmpgtd", { MX, EM } }, - { "packuswb", { MX, EM } }, - /* 68 */ - { "punpckhbw", { MX, EM } }, - { "punpckhwd", { MX, EM } }, - { "punpckhdq", { MX, EM } }, - { "packssdw", { MX, EM } }, - { PREGRP26 }, - { PREGRP24 }, - { "movd", { MX, Edq } }, - { PREGRP19 }, - /* 70 */ - { PREGRP22 }, - { GRP12 }, - { GRP13 }, - { GRP14 }, - { "pcmpeqb", { MX, EM } }, - { "pcmpeqw", { MX, EM } }, - { "pcmpeqd", { MX, EM } }, - { "emms", { XX } }, - /* 78 */ - { PREGRP34 }, - { PREGRP35 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP28 }, - { PREGRP29 }, - { PREGRP23 }, - { PREGRP20 }, - /* 80 */ - { "joH", { Jv, XX, cond_jump_flag } }, - { "jnoH", { Jv, XX, cond_jump_flag } }, - { "jbH", { Jv, XX, cond_jump_flag } }, - { "jaeH", { Jv, XX, cond_jump_flag } }, - { "jeH", { Jv, XX, cond_jump_flag } }, - { "jneH", { Jv, XX, cond_jump_flag } }, - { "jbeH", { Jv, XX, cond_jump_flag } }, - { "jaH", { Jv, XX, cond_jump_flag } }, - /* 88 */ - { "jsH", { Jv, XX, cond_jump_flag } }, - { "jnsH", { Jv, XX, cond_jump_flag } }, - { "jpH", { Jv, XX, cond_jump_flag } }, - { "jnpH", { Jv, XX, cond_jump_flag } }, - { "jlH", { Jv, XX, cond_jump_flag } }, - { "jgeH", { Jv, XX, cond_jump_flag } }, - { "jleH", { Jv, XX, cond_jump_flag } }, - { "jgH", { Jv, XX, cond_jump_flag } }, - /* 90 */ - { "seto", { Eb } }, - { "setno", { Eb } }, - { "setb", { Eb } }, - { "setae", { Eb } }, - { "sete", { Eb } }, - { "setne", { Eb } }, - { "setbe", { Eb } }, - { "seta", { Eb } }, - /* 98 */ - { "sets", { Eb } }, - { "setns", { Eb } }, - { "setp", { Eb } }, - { "setnp", { Eb } }, - { "setl", { Eb } }, - { "setge", { Eb } }, - { "setle", { Eb } }, - { "setg", { Eb } }, - /* a0 */ - { "pushT", { fs } }, - { "popT", { fs } }, - { "cpuid", { XX } }, - { "btS", { Ev, Gv } }, - { "shldS", { Ev, Gv, Ib } }, - { "shldS", { Ev, Gv, CL } }, - { GRPPADLCK2 }, - { GRPPADLCK1 }, - /* a8 */ - { "pushT", { gs } }, - { "popT", { gs } }, - { "rsm", { XX } }, - { "btsS", { Ev, Gv } }, - { "shrdS", { Ev, Gv, Ib } }, - { "shrdS", { Ev, Gv, CL } }, - { GRP15 }, - { "imulS", { Gv, Ev } }, - /* b0 */ - { "cmpxchgB", { Eb, Gb } }, - { "cmpxchgS", { Ev, Gv } }, - { "lssS", { Gv, Mp } }, - { "btrS", { Ev, Gv } }, - { "lfsS", { Gv, Mp } }, - { "lgsS", { Gv, Mp } }, - { "movz{bR|x|bR|x}", { Gv, Eb } }, - { "movz{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movzww ! */ - /* b8 */ - { PREGRP37 }, - { "ud2b", { XX } }, - { GRP8 }, - { "btcS", { Ev, Gv } }, - { PREGRP107 }, - { PREGRP36 }, - { "movs{bR|x|bR|x}", { Gv, Eb } }, - { "movs{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movsww ! */ - /* c0 */ - { "xaddB", { Eb, Gb } }, - { "xaddS", { Ev, Gv } }, - { PREGRP1 }, - { "movntiS", { Ev, Gv } }, - { "pinsrw", { MX, Edqw, Ib } }, - { "pextrw", { Gdq, MS, Ib } }, - { "shufpX", { XM, EXx, Ib } }, - { GRP9 }, - /* c8 */ - { "bswap", { RMeAX } }, - { "bswap", { RMeCX } }, - { "bswap", { RMeDX } }, - { "bswap", { RMeBX } }, - { "bswap", { RMeSP } }, - { "bswap", { RMeBP } }, - { "bswap", { RMeSI } }, - { "bswap", { RMeDI } }, - /* d0 */ - { PREGRP27 }, - { "psrlw", { MX, EM } }, - { "psrld", { MX, EM } }, - { "psrlq", { MX, EM } }, - { "paddq", { MX, EM } }, - { "pmullw", { MX, EM } }, - { PREGRP21 }, - { "pmovmskb", { Gdq, MS } }, - /* d8 */ - { "psubusb", { MX, EM } }, - { "psubusw", { MX, EM } }, - { "pminub", { MX, EM } }, - { "pand", { MX, EM } }, - { "paddusb", { MX, EM } }, - { "paddusw", { MX, EM } }, - { "pmaxub", { MX, EM } }, - { "pandn", { MX, EM } }, - /* e0 */ - { "pavgb", { MX, EM } }, - { "psraw", { MX, EM } }, - { "psrad", { MX, EM } }, - { "pavgw", { MX, EM } }, - { "pmulhuw", { MX, EM } }, - { "pmulhw", { MX, EM } }, - { PREGRP15 }, - { PREGRP25 }, - /* e8 */ - { "psubsb", { MX, EM } }, - { "psubsw", { MX, EM } }, - { "pminsw", { MX, EM } }, - { "por", { MX, EM } }, - { "paddsb", { MX, EM } }, - { "paddsw", { MX, EM } }, - { "pmaxsw", { MX, EM } }, - { "pxor", { MX, EM } }, - /* f0 */ - { PREGRP32 }, - { "psllw", { MX, EM } }, - { "pslld", { MX, EM } }, - { "psllq", { MX, EM } }, - { "pmuludq", { MX, EM } }, - { "pmaddwd", { MX, EM } }, - { "psadbw", { MX, EM } }, - { PREGRP18 }, - /* f8 */ - { "psubb", { MX, EM } }, - { "psubw", { MX, EM } }, - { "psubd", { MX, EM } }, - { "psubq", { MX, EM } }, - { "paddb", { MX, EM } }, - { "paddw", { MX, EM } }, - { "paddd", { MX, EM } }, - { "(bad)", { XX } }, -}; - -static const unsigned char onebyte_has_modrm[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ - /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ - /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ - /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ - /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ - /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ - /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ - /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ - /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_has_modrm[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ - /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */ - /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ - /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ - /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ - /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ - /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ - /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ - /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */ - /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ - /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ - /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_uses_DATA_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ - /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_uses_REPNZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_uses_REPZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6f */ - /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, /* bf */ - /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 38 XX uses DATA prefix. */ -static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 0f */ - /* 10 */ 1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0, /* 1f */ - /* 20 */ 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0, /* 2f */ - /* 30 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 3f */ - /* 40 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 38 XX uses REPNZ prefix. */ -static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 38 XX uses REPZ prefix. */ -static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 3a XX uses DATA prefix. */ -static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, /* 0f */ - /* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 3a XX uses REPNZ prefix. */ -static const unsigned char threebyte_0x3a_uses_REPNZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 3a XX uses REPZ prefix. */ -static const unsigned char threebyte_0x3a_uses_REPZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static char obuf[100]; -static char *obufp; -static char scratchbuf[100]; -static unsigned char *start_codep; -static unsigned char *insn_codep; -static unsigned char *codep; -static disassemble_info *the_info; -static struct - { - int mod; - int reg; - int rm; - } -modrm; -static unsigned char need_modrm; - -/* If we are accessing mod/rm/reg without need_modrm set, then the - values are stale. Hitting this abort likely indicates that you - need to update onebyte_has_modrm or twobyte_has_modrm. */ -#define MODRM_CHECK if (!need_modrm) abort () - -static const char * const *names64; -static const char * const *names32; -static const char * const *names16; -static const char * const *names8; -static const char * const *names8rex; -static const char * const *names_seg; -static const char * const *index16; - -static const char * const intel_names64[] = { - "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" -}; -static const char * const intel_names32[] = { - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", - "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" -}; -static const char * const intel_names16[] = { - "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", - "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" -}; -static const char * const intel_names8[] = { - "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", -}; -static const char * const intel_names8rex[] = { - "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", - "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" -}; -static const char * const intel_names_seg[] = { - "es", "cs", "ss", "ds", "fs", "gs", "?", "?", -}; -static const char * const intel_index16[] = { - "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" -}; - -static const char * const att_names64[] = { - "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", - "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" -}; -static const char * const att_names32[] = { - "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", - "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" -}; -static const char * const att_names16[] = { - "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", - "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" -}; -static const char * const att_names8[] = { - "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", -}; -static const char * const att_names8rex[] = { - "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", - "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" -}; -static const char * const att_names_seg[] = { - "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", -}; -static const char * const att_index16[] = { - "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" -}; - -static const struct dis386 grps[][8] = { - /* GRP1a */ - { - { "popU", { stackEv } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP1b */ - { - { "addA", { Eb, Ib } }, - { "orA", { Eb, Ib } }, - { "adcA", { Eb, Ib } }, - { "sbbA", { Eb, Ib } }, - { "andA", { Eb, Ib } }, - { "subA", { Eb, Ib } }, - { "xorA", { Eb, Ib } }, - { "cmpA", { Eb, Ib } }, - }, - /* GRP1S */ - { - { "addQ", { Ev, Iv } }, - { "orQ", { Ev, Iv } }, - { "adcQ", { Ev, Iv } }, - { "sbbQ", { Ev, Iv } }, - { "andQ", { Ev, Iv } }, - { "subQ", { Ev, Iv } }, - { "xorQ", { Ev, Iv } }, - { "cmpQ", { Ev, Iv } }, - }, - /* GRP1Ss */ - { - { "addQ", { Ev, sIb } }, - { "orQ", { Ev, sIb } }, - { "adcQ", { Ev, sIb } }, - { "sbbQ", { Ev, sIb } }, - { "andQ", { Ev, sIb } }, - { "subQ", { Ev, sIb } }, - { "xorQ", { Ev, sIb } }, - { "cmpQ", { Ev, sIb } }, - }, - /* GRP2b */ - { - { "rolA", { Eb, Ib } }, - { "rorA", { Eb, Ib } }, - { "rclA", { Eb, Ib } }, - { "rcrA", { Eb, Ib } }, - { "shlA", { Eb, Ib } }, - { "shrA", { Eb, Ib } }, - { "(bad)", { XX } }, - { "sarA", { Eb, Ib } }, - }, - /* GRP2S */ - { - { "rolQ", { Ev, Ib } }, - { "rorQ", { Ev, Ib } }, - { "rclQ", { Ev, Ib } }, - { "rcrQ", { Ev, Ib } }, - { "shlQ", { Ev, Ib } }, - { "shrQ", { Ev, Ib } }, - { "(bad)", { XX } }, - { "sarQ", { Ev, Ib } }, - }, - /* GRP2b_one */ - { - { "rolA", { Eb, I1 } }, - { "rorA", { Eb, I1 } }, - { "rclA", { Eb, I1 } }, - { "rcrA", { Eb, I1 } }, - { "shlA", { Eb, I1 } }, - { "shrA", { Eb, I1 } }, - { "(bad)", { XX } }, - { "sarA", { Eb, I1 } }, - }, - /* GRP2S_one */ - { - { "rolQ", { Ev, I1 } }, - { "rorQ", { Ev, I1 } }, - { "rclQ", { Ev, I1 } }, - { "rcrQ", { Ev, I1 } }, - { "shlQ", { Ev, I1 } }, - { "shrQ", { Ev, I1 } }, - { "(bad)", { XX } }, - { "sarQ", { Ev, I1 } }, - }, - /* GRP2b_cl */ - { - { "rolA", { Eb, CL } }, - { "rorA", { Eb, CL } }, - { "rclA", { Eb, CL } }, - { "rcrA", { Eb, CL } }, - { "shlA", { Eb, CL } }, - { "shrA", { Eb, CL } }, - { "(bad)", { XX } }, - { "sarA", { Eb, CL } }, - }, - /* GRP2S_cl */ - { - { "rolQ", { Ev, CL } }, - { "rorQ", { Ev, CL } }, - { "rclQ", { Ev, CL } }, - { "rcrQ", { Ev, CL } }, - { "shlQ", { Ev, CL } }, - { "shrQ", { Ev, CL } }, - { "(bad)", { XX } }, - { "sarQ", { Ev, CL } }, - }, - /* GRP3b */ - { - { "testA", { Eb, Ib } }, - { "(bad)", { Eb } }, - { "notA", { Eb } }, - { "negA", { Eb } }, - { "mulA", { Eb } }, /* Don't print the implicit %al register, */ - { "imulA", { Eb } }, /* to distinguish these opcodes from other */ - { "divA", { Eb } }, /* mul/imul opcodes. Do the same for div */ - { "idivA", { Eb } }, /* and idiv for consistency. */ - }, - /* GRP3S */ - { - { "testQ", { Ev, Iv } }, - { "(bad)", { XX } }, - { "notQ", { Ev } }, - { "negQ", { Ev } }, - { "mulQ", { Ev } }, /* Don't print the implicit register. */ - { "imulQ", { Ev } }, - { "divQ", { Ev } }, - { "idivQ", { Ev } }, - }, - /* GRP4 */ - { - { "incA", { Eb } }, - { "decA", { Eb } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP5 */ - { - { "incQ", { Ev } }, - { "decQ", { Ev } }, - { "callT", { indirEv } }, - { "JcallT", { indirEp } }, - { "jmpT", { indirEv } }, - { "JjmpT", { indirEp } }, - { "pushU", { stackEv } }, - { "(bad)", { XX } }, - }, - /* GRP6 */ - { - { "sldtD", { Sv } }, - { "strD", { Sv } }, - { "lldt", { Ew } }, - { "ltr", { Ew } }, - { "verr", { Ew } }, - { "verw", { Ew } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP7 */ - { - { "sgdt{Q|IQ||}", { { VMX_Fixup, 0 } } }, - { "sidt{Q|IQ||}", { { PNI_Fixup, 0 } } }, - { "lgdt{Q|Q||}", { M } }, - { "lidt{Q|Q||}", { { SVME_Fixup, 0 } } }, - { "smswD", { Sv } }, - { "(bad)", { XX } }, - { "lmsw", { Ew } }, - { "invlpg", { { INVLPG_Fixup, w_mode } } }, - }, - /* GRP8 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "btQ", { Ev, Ib } }, - { "btsQ", { Ev, Ib } }, - { "btrQ", { Ev, Ib } }, - { "btcQ", { Ev, Ib } }, - }, - /* GRP9 */ - { - { "(bad)", { XX } }, - { "cmpxchg8b", { { CMPXCHG8B_Fixup, q_mode } } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "", { VM } }, /* See OP_VMX. */ - { "vmptrst", { Mq } }, - }, - /* GRP11_C6 */ - { - { "movA", { Eb, Ib } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP11_C7 */ - { - { "movQ", { Ev, Iv } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP12 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psrlw", { MS, Ib } }, - { "(bad)", { XX } }, - { "psraw", { MS, Ib } }, - { "(bad)", { XX } }, - { "psllw", { MS, Ib } }, - { "(bad)", { XX } }, - }, - /* GRP13 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psrld", { MS, Ib } }, - { "(bad)", { XX } }, - { "psrad", { MS, Ib } }, - { "(bad)", { XX } }, - { "pslld", { MS, Ib } }, - { "(bad)", { XX } }, - }, - /* GRP14 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psrlq", { MS, Ib } }, - { "psrldq", { MS, Ib } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psllq", { MS, Ib } }, - { "pslldq", { MS, Ib } }, - }, - /* GRP15 */ - { - { "fxsave", { Ev } }, - { "fxrstor", { Ev } }, - { "ldmxcsr", { Ev } }, - { "stmxcsr", { Ev } }, - { "(bad)", { XX } }, - { "lfence", { { OP_0fae, 0 } } }, - { "mfence", { { OP_0fae, 0 } } }, - { "clflush", { { OP_0fae, 0 } } }, - }, - /* GRP16 */ - { - { "prefetchnta", { Ev } }, - { "prefetcht0", { Ev } }, - { "prefetcht1", { Ev } }, - { "prefetcht2", { Ev } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRPAMD */ - { - { "prefetch", { Eb } }, - { "prefetchw", { Eb } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRPPADLCK1 */ - { - { "xstore-rng", { { OP_0f07, 0 } } }, - { "xcrypt-ecb", { { OP_0f07, 0 } } }, - { "xcrypt-cbc", { { OP_0f07, 0 } } }, - { "xcrypt-ctr", { { OP_0f07, 0 } } }, - { "xcrypt-cfb", { { OP_0f07, 0 } } }, - { "xcrypt-ofb", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - }, - /* GRPPADLCK2 */ - { - { "montmul", { { OP_0f07, 0 } } }, - { "xsha1", { { OP_0f07, 0 } } }, - { "xsha256", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - } -}; - -static const struct dis386 prefix_user_table[][4] = { - /* PREGRP0 */ - { - { "addps", { XM, EXx } }, - { "addss", { XM, EXd } }, - { "addpd", { XM, EXx } }, - { "addsd", { XM, EXq } }, - }, - /* PREGRP1 */ - { - { "", { XM, EXx, OPSIMD } }, /* See OP_SIMD_SUFFIX. */ - { "", { XM, EXx, OPSIMD } }, - { "", { XM, EXx, OPSIMD } }, - { "", { XM, EXx, OPSIMD } }, - }, - /* PREGRP2 */ - { - { "cvtpi2ps", { XM, EMC } }, - { "cvtsi2ssY", { XM, Ev } }, - { "cvtpi2pd", { XM, EMC } }, - { "cvtsi2sdY", { XM, Ev } }, - }, - /* PREGRP3 */ - { - { "cvtps2pi", { MXC, EXx } }, - { "cvtss2siY", { Gv, EXx } }, - { "cvtpd2pi", { MXC, EXx } }, - { "cvtsd2siY", { Gv, EXx } }, - }, - /* PREGRP4 */ - { - { "cvttps2pi", { MXC, EXx } }, - { "cvttss2siY", { Gv, EXx } }, - { "cvttpd2pi", { MXC, EXx } }, - { "cvttsd2siY", { Gv, EXx } }, - }, - /* PREGRP5 */ - { - { "divps", { XM, EXx } }, - { "divss", { XM, EXx } }, - { "divpd", { XM, EXx } }, - { "divsd", { XM, EXx } }, - }, - /* PREGRP6 */ - { - { "maxps", { XM, EXx } }, - { "maxss", { XM, EXx } }, - { "maxpd", { XM, EXx } }, - { "maxsd", { XM, EXx } }, - }, - /* PREGRP7 */ - { - { "minps", { XM, EXx } }, - { "minss", { XM, EXx } }, - { "minpd", { XM, EXx } }, - { "minsd", { XM, EXx } }, - }, - /* PREGRP8 */ - { - { "movups", { XM, EXx } }, - { "movss", { XM, EXx } }, - { "movupd", { XM, EXx } }, - { "movsd", { XM, EXx } }, - }, - /* PREGRP9 */ - { - { "movups", { EXx, XM } }, - { "movss", { EXx, XM } }, - { "movupd", { EXx, XM } }, - { "movsd", { EXx, XM } }, - }, - /* PREGRP10 */ - { - { "mulps", { XM, EXx } }, - { "mulss", { XM, EXx } }, - { "mulpd", { XM, EXx } }, - { "mulsd", { XM, EXx } }, - }, - /* PREGRP11 */ - { - { "rcpps", { XM, EXx } }, - { "rcpss", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP12 */ - { - { "rsqrtps",{ XM, EXx } }, - { "rsqrtss",{ XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP13 */ - { - { "sqrtps", { XM, EXx } }, - { "sqrtss", { XM, EXx } }, - { "sqrtpd", { XM, EXx } }, - { "sqrtsd", { XM, EXx } }, - }, - /* PREGRP14 */ - { - { "subps", { XM, EXx } }, - { "subss", { XM, EXx } }, - { "subpd", { XM, EXx } }, - { "subsd", { XM, EXx } }, - }, - /* PREGRP15 */ - { - { "(bad)", { XM, EXx } }, - { "cvtdq2pd", { XM, EXq } }, - { "cvttpd2dq", { XM, EXx } }, - { "cvtpd2dq", { XM, EXx } }, - }, - /* PREGRP16 */ - { - { "cvtdq2ps", { XM, EXx } }, - { "cvttps2dq", { XM, EXx } }, - { "cvtps2dq", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP17 */ - { - { "cvtps2pd", { XM, EXq } }, - { "cvtss2sd", { XM, EXx } }, - { "cvtpd2ps", { XM, EXx } }, - { "cvtsd2ss", { XM, EXx } }, - }, - /* PREGRP18 */ - { - { "maskmovq", { MX, MS } }, - { "(bad)", { XM, EXx } }, - { "maskmovdqu", { XM, XS } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP19 */ - { - { "movq", { MX, EM } }, - { "movdqu", { XM, EXx } }, - { "movdqa", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP20 */ - { - { "movq", { EM, MX } }, - { "movdqu", { EXx, XM } }, - { "movdqa", { EXx, XM } }, - { "(bad)", { EXx, XM } }, - }, - /* PREGRP21 */ - { - { "(bad)", { EXx, XM } }, - { "movq2dq",{ XM, MS } }, - { "movq", { EXx, XM } }, - { "movdq2q",{ MX, XS } }, - }, - /* PREGRP22 */ - { - { "pshufw", { MX, EM, Ib } }, - { "pshufhw",{ XM, EXx, Ib } }, - { "pshufd", { XM, EXx, Ib } }, - { "pshuflw",{ XM, EXx, Ib } }, - }, - /* PREGRP23 */ - { - { "movd", { Edq, MX } }, - { "movq", { XM, EXx } }, - { "movd", { Edq, XM } }, - { "(bad)", { Ed, XM } }, - }, - /* PREGRP24 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "punpckhqdq", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP25 */ - { - { "movntq", { EM, MX } }, - { "(bad)", { EM, XM } }, - { "movntdq",{ EM, XM } }, - { "(bad)", { EM, XM } }, - }, - /* PREGRP26 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "punpcklqdq", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP27 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "addsubpd", { XM, EXx } }, - { "addsubps", { XM, EXx } }, - }, - /* PREGRP28 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "haddpd", { XM, EXx } }, - { "haddps", { XM, EXx } }, - }, - /* PREGRP29 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "hsubpd", { XM, EXx } }, - { "hsubps", { XM, EXx } }, - }, - /* PREGRP30 */ - { - { "movlpX", { XM, EXq, { SIMD_Fixup, 'h' } } }, /* really only 2 operands */ - { "movsldup", { XM, EXx } }, - { "movlpd", { XM, EXq } }, - { "movddup", { XM, EXq } }, - }, - /* PREGRP31 */ - { - { "movhpX", { XM, EXq, { SIMD_Fixup, 'l' } } }, - { "movshdup", { XM, EXx } }, - { "movhpd", { XM, EXq } }, - { "(bad)", { XM, EXq } }, - }, - /* PREGRP32 */ - { - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "lddqu", { XM, M } }, - }, - /* PREGRP33 */ - { - {"movntps", { Ev, XM } }, - {"movntss", { Ev, XM } }, - {"movntpd", { Ev, XM } }, - {"movntsd", { Ev, XM } }, - }, - - /* PREGRP34 */ - { - {"vmread", { Em, Gm } }, - {"(bad)", { XX } }, - {"extrq", { XS, Ib, Ib } }, - {"insertq", { XM, XS, Ib, Ib } }, - }, - - /* PREGRP35 */ - { - {"vmwrite", { Gm, Em } }, - {"(bad)", { XX } }, - {"extrq", { XM, XS } }, - {"insertq", { XM, XS } }, - }, - - /* PREGRP36 */ - { - { "bsrS", { Gv, Ev } }, - { "lzcntS", { Gv, Ev } }, - { "bsrS", { Gv, Ev } }, - { "(bad)", { XX } }, - }, - - /* PREGRP37 */ - { - { "(bad)", { XX } }, - { "popcntS", { Gv, Ev } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - - /* PREGRP38 */ - { - { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, - { "pause", { XX } }, - { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, - { "(bad)", { XX } }, - }, - - /* PREGRP39 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pblendvb", {XM, EXx, XMM0 } }, - { "(bad)", { XX } }, - }, - - /* PREGRP40 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendvps", {XM, EXx, XMM0 } }, - { "(bad)", { XX } }, - }, - - /* PREGRP41 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendvpd", { XM, EXx, XMM0 } }, - { "(bad)", { XX } }, - }, - - /* PREGRP42 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "ptest", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP43 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxbw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP44 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxbd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP45 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxbq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP46 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxwd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP47 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxwq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP48 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxdq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP49 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmuldq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP50 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpeqq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP51 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "movntdqa", { XM, EM } }, - { "(bad)", { XX } }, - }, - - /* PREGRP52 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "packusdw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP53 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxbw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP54 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxbd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP55 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxbq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP56 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxwd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP57 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxwq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP58 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxdq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP59 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminsb", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP60 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminsd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP61 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminuw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP62 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminud", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP63 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxsb", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP64 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxsd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP65 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxuw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP66 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxud", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP67 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmulld", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP68 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "phminposuw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP69 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP70 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundpd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP71 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundss", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP72 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundsd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP73 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP74 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendpd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP75 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pblendw", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP76 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pextrb", { Edqb, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP77 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pextrw", { Edqw, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP78 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pextrK", { Edq, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP79 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "extractps", { Edqd, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP80 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pinsrb", { XM, Edqb, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP81 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "insertps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP82 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pinsrK", { XM, Edq, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP83 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "dpps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP84 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "dppd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP85 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "mpsadbw", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP86 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpgtq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP87 */ - { - { "movbe", { Gv, Ev } }, - { "(bad)", { XX } }, - { "movbe", { Gv, Ev } }, - { "crc32", { Gdq, { CRC32_Fixup, b_mode } } }, - }, - - /* PREGRP88 */ - { - { "movbe", { Ev, Gv } }, - { "(bad)", { XX } }, - { "movbe", { Ev, Gv } }, - { "crc32", { Gdq, { CRC32_Fixup, v_mode } } }, - }, - - /* PREGRP89 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpestrm", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP90 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpestri", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP91 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpistrm", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP92 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpistri", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP93 */ - { - { "ucomiss",{ XM, EXd } }, - { "(bad)", { XX } }, - { "ucomisd",{ XM, EXq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP94 */ - { - { "comiss", { XM, EXd } }, - { "(bad)", { XX } }, - { "comisd", { XM, EXq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP95 */ - { - { "punpcklbw",{ MX, EMd } }, - { "(bad)", { XX } }, - { "punpcklbw",{ MX, EMq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP96 */ - { - { "punpcklwd",{ MX, EMd } }, - { "(bad)", { XX } }, - { "punpcklwd",{ MX, EMq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP97 */ - { - { "punpckldq",{ MX, EMd } }, - { "(bad)", { XX } }, - { "punpckldq",{ MX, EMq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP98 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pclmulqdq", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP99 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesimc", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP100 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesenc", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP101 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesenclast", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP102 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesdec", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP103 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesdeclast", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP104 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aeskeygenassist", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP105 */ - { - { "andnS", { Gv, Bv, Ev } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - - /* PREGRP106 */ - { - { "bextrS", { Gv, Ev, Bv } }, - { "sarxS", { Gv, Ev, Bv } }, - { "shlxS", { Gv, Ev, Bv } }, - { "shrxS", { Gv, Ev, Bv } }, - }, - - /* PREGRP107 */ - { - { "bsfS", { Gv, Ev } }, - { "tzcntS", { Gv, Ev } }, - { "bsfS", { Gv, Ev } }, - { "(bad)", { XX } }, - }, - - /* PREGRP108 */ - { - { "bzhi", { Gv, Ev, Bv } }, - { "pext", { Gv, Bv, Ev } }, - { "(bad)", { XX } }, - { "pdep", { Gv, Bv, Ev } }, - }, - - /* PREGRP109 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "rorx", { Gv, Ev, Ib } }, - }, -}; - -static const struct dis386 x86_64_table[][2] = { - { - { "pusha{P|}", { XX } }, - { "(bad)", { XX } }, - }, - { - { "popa{P|}", { XX } }, - { "(bad)", { XX } }, - }, - { - { "bound{S|}", { Gv, Ma } }, - { "(bad)", { XX } }, - }, - { - { "arpl", { Ew, Gw } }, - { "movs{||lq|xd}", { Gv, Ed } }, - }, -}; - -static const struct dis386 three_byte_table[][256] = { - /* THREE_BYTE_0 */ - { - /* 00 */ - { "pshufb", { MX, EM } }, - { "phaddw", { MX, EM } }, - { "phaddd", { MX, EM } }, - { "phaddsw", { MX, EM } }, - { "pmaddubsw", { MX, EM } }, - { "phsubw", { MX, EM } }, - { "phsubd", { MX, EM } }, - { "phsubsw", { MX, EM } }, - /* 08 */ - { "psignb", { MX, EM } }, - { "psignw", { MX, EM } }, - { "psignd", { MX, EM } }, - { "pmulhrsw", { MX, EM } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 10 */ - { PREGRP39 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP40 }, - { PREGRP41 }, - { "(bad)", { XX } }, - { PREGRP42 }, - /* 18 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pabsb", { MX, EM } }, - { "pabsw", { MX, EM } }, - { "pabsd", { MX, EM } }, - { "(bad)", { XX } }, - /* 20 */ - { PREGRP43 }, - { PREGRP44 }, - { PREGRP45 }, - { PREGRP46 }, - { PREGRP47 }, - { PREGRP48 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 28 */ - { PREGRP49 }, - { PREGRP50 }, - { PREGRP51 }, - { PREGRP52 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 30 */ - { PREGRP53 }, - { PREGRP54 }, - { PREGRP55 }, - { PREGRP56 }, - { PREGRP57 }, - { PREGRP58 }, - { "(bad)", { XX } }, - { PREGRP86 }, - /* 38 */ - { PREGRP59 }, - { PREGRP60 }, - { PREGRP61 }, - { PREGRP62 }, - { PREGRP63 }, - { PREGRP64 }, - { PREGRP65 }, - { PREGRP66 }, - /* 40 */ - { PREGRP67 }, - { PREGRP68 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 48 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 50 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 58 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 60 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 68 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 70 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 78 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 80 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 88 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 90 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 98 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP99 }, - { PREGRP100 }, - { PREGRP101 }, - { PREGRP102 }, - { PREGRP103 }, - /* e0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* e8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* f0 */ - { PREGRP87 }, - { PREGRP88 }, - { PREGRP105 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP108 }, - { "(bad)", { XX } }, - { PREGRP106 }, - /* f8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* THREE_BYTE_1 */ - { - /* 00 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 08 */ - { PREGRP69 }, - { PREGRP70 }, - { PREGRP71 }, - { PREGRP72 }, - { PREGRP73 }, - { PREGRP74 }, - { PREGRP75 }, - { "palignr", { MX, EM, Ib } }, - /* 10 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP76 }, - { PREGRP77 }, - { PREGRP78 }, - { PREGRP79 }, - /* 18 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 20 */ - { PREGRP80 }, - { PREGRP81 }, - { PREGRP82 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 28 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 30 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 38 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 40 */ - { PREGRP83 }, - { PREGRP84 }, - { PREGRP85 }, - { "(bad)", { XX } }, - { PREGRP98 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 48 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 50 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 58 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 60 */ - { PREGRP89 }, - { PREGRP90 }, - { PREGRP91 }, - { PREGRP92 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 68 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 70 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 78 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 80 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 88 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 90 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 98 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP104 }, - /* e0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* e8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* f0 */ - { PREGRP109 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* f8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - } -}; - -#define INTERNAL_DISASSEMBLER_ERROR "" - -static void -ckprefix (void) -{ - int newrex; - rex = 0; - prefixes = 0; - used_prefixes = 0; - rex_used = 0; - while (1) - { - fetch_data(the_info, codep + 1); - newrex = 0; - switch (*codep) - { - /* REX prefixes family. */ - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - if (address_mode == mode_64bit) - newrex = *codep; - else - return; - break; - case 0xf3: - prefixes |= PREFIX_REPZ; - break; - case 0xf2: - prefixes |= PREFIX_REPNZ; - break; - case 0xf0: - prefixes |= PREFIX_LOCK; - break; - case 0x2e: - prefixes |= PREFIX_CS; - break; - case 0x36: - prefixes |= PREFIX_SS; - break; - case 0x3e: - prefixes |= PREFIX_DS; - break; - case 0x26: - prefixes |= PREFIX_ES; - break; - case 0x64: - prefixes |= PREFIX_FS; - break; - case 0x65: - prefixes |= PREFIX_GS; - break; - case 0x66: - prefixes |= PREFIX_DATA; - break; - case 0x67: - prefixes |= PREFIX_ADDR; - break; - case FWAIT_OPCODE: - /* fwait is really an instruction. If there are prefixes - before the fwait, they belong to the fwait, *not* to the - following instruction. */ - if (prefixes || rex) - { - prefixes |= PREFIX_FWAIT; - codep++; - return; - } - prefixes = PREFIX_FWAIT; - break; - default: - return; - } - /* Rex is ignored when followed by another prefix. */ - if (rex) - { - rex_used = rex; - return; - } - rex = newrex; - codep++; - } -} - -static void -ckvexprefix (void) -{ - int op, vex2, vex3, newrex = 0, newpfx = prefixes; - - if (address_mode == mode_16bit) { - return; - } - - fetch_data(the_info, codep + 1); - op = *codep; - - if (op != 0xc4 && op != 0xc5) { - return; - } - - fetch_data(the_info, codep + 2); - vex2 = codep[1]; - - if (address_mode == mode_32bit && (vex2 & 0xc0) != 0xc0) { - return; - } - - if (op == 0xc4) { - /* Three byte VEX prefix. */ - fetch_data(the_info, codep + 3); - vex3 = codep[2]; - - newrex |= (vex2 & 0x80 ? 0 : REX_R); - newrex |= (vex2 & 0x40 ? 0 : REX_X); - newrex |= (vex2 & 0x20 ? 0 : REX_B); - newrex |= (vex3 & 0x80 ? REX_W : 0); - switch (vex2 & 0x1f) { /* VEX.m-mmmm */ - case 1: - newpfx |= PREFIX_VEX_0F; - break; - case 2: - newpfx |= PREFIX_VEX_0F | PREFIX_VEX_0F38; - break; - case 3: - newpfx |= PREFIX_VEX_0F | PREFIX_VEX_0F3A; - break; - } - vex2 = vex3; - codep += 3; - } else { - /* Two byte VEX prefix. */ - newrex |= (vex2 & 0x80 ? 0 : REX_R); - newpfx |= PREFIX_VEX_0F; - codep += 2; - } - - vex_reg = (~vex2 >> 3) & 15; /* VEX.vvvv */ - switch (vex2 & 3) { /* VEX.pp */ - case 1: - newpfx |= PREFIX_DATA; /* 0x66 */ - break; - case 2: - newpfx |= PREFIX_REPZ; /* 0xf3 */ - break; - case 3: - newpfx |= PREFIX_REPNZ; /* 0xf2 */ - break; - } - - rex = newrex; - prefixes = newpfx; -} - -/* Return the name of the prefix byte PREF, or NULL if PREF is not a - prefix byte. */ - -static const char * -prefix_name (int pref, int sizeflag) -{ - static const char * const rexes [16] = - { - "rex", /* 0x40 */ - "rex.B", /* 0x41 */ - "rex.X", /* 0x42 */ - "rex.XB", /* 0x43 */ - "rex.R", /* 0x44 */ - "rex.RB", /* 0x45 */ - "rex.RX", /* 0x46 */ - "rex.RXB", /* 0x47 */ - "rex.W", /* 0x48 */ - "rex.WB", /* 0x49 */ - "rex.WX", /* 0x4a */ - "rex.WXB", /* 0x4b */ - "rex.WR", /* 0x4c */ - "rex.WRB", /* 0x4d */ - "rex.WRX", /* 0x4e */ - "rex.WRXB", /* 0x4f */ - }; - - switch (pref) - { - /* REX prefixes family. */ - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - return rexes [pref - 0x40]; - case 0xf3: - return "repz"; - case 0xf2: - return "repnz"; - case 0xf0: - return "lock"; - case 0x2e: - return "cs"; - case 0x36: - return "ss"; - case 0x3e: - return "ds"; - case 0x26: - return "es"; - case 0x64: - return "fs"; - case 0x65: - return "gs"; - case 0x66: - return (sizeflag & DFLAG) ? "data16" : "data32"; - case 0x67: - if (address_mode == mode_64bit) - return (sizeflag & AFLAG) ? "addr32" : "addr64"; - else - return (sizeflag & AFLAG) ? "addr16" : "addr32"; - case FWAIT_OPCODE: - return "fwait"; - default: - return NULL; - } -} - -static char op_out[MAX_OPERANDS][100]; -static int op_ad, op_index[MAX_OPERANDS]; -static int two_source_ops; -static bfd_vma op_address[MAX_OPERANDS]; -static bfd_vma op_riprel[MAX_OPERANDS]; -static bfd_vma start_pc; - -/* - * On the 386's of 1988, the maximum length of an instruction is 15 bytes. - * (see topic "Redundant prefixes" in the "Differences from 8086" - * section of the "Virtual 8086 Mode" chapter.) - * 'pc' should be the address of this instruction, it will - * be used to print the target address if this is a relative jump or call - * The function returns the length of this instruction in bytes. - */ - -static char intel_syntax; -static char open_char; -static char close_char; -static char separator_char; -static char scale_char; - -int -print_insn_i386 (bfd_vma pc, disassemble_info *info) -{ - intel_syntax = -1; - - return print_insn (pc, info); -} - -static int -print_insn (bfd_vma pc, disassemble_info *info) -{ - const struct dis386 *dp; - int i; - char *op_txt[MAX_OPERANDS]; - int needcomma; - unsigned char uses_DATA_prefix, uses_LOCK_prefix; - unsigned char uses_REPNZ_prefix, uses_REPZ_prefix; - int sizeflag; - const char *p; - struct dis_private priv; - unsigned char op; - unsigned char threebyte; - - if (info->mach == bfd_mach_x86_64_intel_syntax - || info->mach == bfd_mach_x86_64) - address_mode = mode_64bit; - else - address_mode = mode_32bit; - - if (intel_syntax == (char) -1) - intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax - || info->mach == bfd_mach_x86_64_intel_syntax); - - if (info->mach == bfd_mach_i386_i386 - || info->mach == bfd_mach_x86_64 - || info->mach == bfd_mach_i386_i386_intel_syntax - || info->mach == bfd_mach_x86_64_intel_syntax) - priv.orig_sizeflag = AFLAG | DFLAG; - else if (info->mach == bfd_mach_i386_i8086) - priv.orig_sizeflag = 0; - else - abort (); - - for (p = info->disassembler_options; p != NULL; ) - { - if (strncmp (p, "x86-64", 6) == 0) - { - address_mode = mode_64bit; - priv.orig_sizeflag = AFLAG | DFLAG; - } - else if (strncmp (p, "i386", 4) == 0) - { - address_mode = mode_32bit; - priv.orig_sizeflag = AFLAG | DFLAG; - } - else if (strncmp (p, "i8086", 5) == 0) - { - address_mode = mode_16bit; - priv.orig_sizeflag = 0; - } - else if (strncmp (p, "intel", 5) == 0) - { - intel_syntax = 1; - } - else if (strncmp (p, "att", 3) == 0) - { - intel_syntax = 0; - } - else if (strncmp (p, "addr", 4) == 0) - { - if (address_mode == mode_64bit) - { - if (p[4] == '3' && p[5] == '2') - priv.orig_sizeflag &= ~AFLAG; - else if (p[4] == '6' && p[5] == '4') - priv.orig_sizeflag |= AFLAG; - } - else - { - if (p[4] == '1' && p[5] == '6') - priv.orig_sizeflag &= ~AFLAG; - else if (p[4] == '3' && p[5] == '2') - priv.orig_sizeflag |= AFLAG; - } - } - else if (strncmp (p, "data", 4) == 0) - { - if (p[4] == '1' && p[5] == '6') - priv.orig_sizeflag &= ~DFLAG; - else if (p[4] == '3' && p[5] == '2') - priv.orig_sizeflag |= DFLAG; - } - else if (strncmp (p, "suffix", 6) == 0) - priv.orig_sizeflag |= SUFFIX_ALWAYS; - - p = strchr (p, ','); - if (p != NULL) - p++; - } - - if (intel_syntax) - { - names64 = intel_names64; - names32 = intel_names32; - names16 = intel_names16; - names8 = intel_names8; - names8rex = intel_names8rex; - names_seg = intel_names_seg; - index16 = intel_index16; - open_char = '['; - close_char = ']'; - separator_char = '+'; - scale_char = '*'; - } - else - { - names64 = att_names64; - names32 = att_names32; - names16 = att_names16; - names8 = att_names8; - names8rex = att_names8rex; - names_seg = att_names_seg; - index16 = att_index16; - open_char = '('; - close_char = ')'; - separator_char = ','; - scale_char = ','; - } - - /* The output looks better if we put 7 bytes on a line, since that - puts most long word instructions on a single line. */ - info->bytes_per_line = 7; - - info->private_data = &priv; - priv.max_fetched = priv.the_buffer; - priv.insn_start = pc; - - obuf[0] = 0; - for (i = 0; i < MAX_OPERANDS; ++i) - { - op_out[i][0] = 0; - op_index[i] = -1; - } - - the_info = info; - start_pc = pc; - start_codep = priv.the_buffer; - codep = priv.the_buffer; - - if (sigsetjmp(priv.bailout, 0) != 0) - { - const char *name; - - /* Getting here means we tried for data but didn't get it. That - means we have an incomplete instruction of some sort. Just - print the first byte as a prefix or a .byte pseudo-op. */ - if (codep > priv.the_buffer) - { - name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); - if (name != NULL) - (*info->fprintf_func) (info->stream, "%s", name); - else - { - /* Just print the first byte as a .byte instruction. */ - (*info->fprintf_func) (info->stream, ".byte 0x%x", - (unsigned int) priv.the_buffer[0]); - } - - return 1; - } - - return -1; - } - - obufp = obuf; - ckprefix (); - ckvexprefix (); - - insn_codep = codep; - sizeflag = priv.orig_sizeflag; - - fetch_data(info, codep + 1); - two_source_ops = (*codep == 0x62) || (*codep == 0xc8); - - if (((prefixes & PREFIX_FWAIT) - && ((*codep < 0xd8) || (*codep > 0xdf))) - || (rex && rex_used)) - { - const char *name; - - /* fwait not followed by floating point instruction, or rex followed - by other prefixes. Print the first prefix. */ - name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s", name); - return 1; - } - - op = 0; - if (prefixes & PREFIX_VEX_0F) - { - used_prefixes |= PREFIX_VEX_0F | PREFIX_VEX_0F38 | PREFIX_VEX_0F3A; - if (prefixes & PREFIX_VEX_0F38) - threebyte = 0x38; - else if (prefixes & PREFIX_VEX_0F3A) - threebyte = 0x3a; - else - threebyte = *codep++; - goto vex_opcode; - } - if (*codep == 0x0f) - { - fetch_data(info, codep + 2); - threebyte = codep[1]; - codep += 2; - vex_opcode: - dp = &dis386_twobyte[threebyte]; - need_modrm = twobyte_has_modrm[threebyte]; - uses_DATA_prefix = twobyte_uses_DATA_prefix[threebyte]; - uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[threebyte]; - uses_REPZ_prefix = twobyte_uses_REPZ_prefix[threebyte]; - uses_LOCK_prefix = (threebyte & ~0x02) == 0x20; - if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) - { - fetch_data(info, codep + 2); - op = *codep++; - switch (threebyte) - { - case 0x38: - uses_DATA_prefix = threebyte_0x38_uses_DATA_prefix[op]; - uses_REPNZ_prefix = threebyte_0x38_uses_REPNZ_prefix[op]; - uses_REPZ_prefix = threebyte_0x38_uses_REPZ_prefix[op]; - break; - case 0x3a: - uses_DATA_prefix = threebyte_0x3a_uses_DATA_prefix[op]; - uses_REPNZ_prefix = threebyte_0x3a_uses_REPNZ_prefix[op]; - uses_REPZ_prefix = threebyte_0x3a_uses_REPZ_prefix[op]; - break; - default: - break; - } - } - } - else - { - dp = &dis386[*codep]; - need_modrm = onebyte_has_modrm[*codep]; - uses_DATA_prefix = 0; - uses_REPNZ_prefix = 0; - /* pause is 0xf3 0x90. */ - uses_REPZ_prefix = *codep == 0x90; - uses_LOCK_prefix = 0; - codep++; - } - - if (!uses_REPZ_prefix && (prefixes & PREFIX_REPZ)) - { - oappend ("repz "); - used_prefixes |= PREFIX_REPZ; - } - if (!uses_REPNZ_prefix && (prefixes & PREFIX_REPNZ)) - { - oappend ("repnz "); - used_prefixes |= PREFIX_REPNZ; - } - - if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) - { - oappend ("lock "); - used_prefixes |= PREFIX_LOCK; - } - - if (prefixes & PREFIX_ADDR) - { - sizeflag ^= AFLAG; - if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax) - { - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - oappend ("addr32 "); - else - oappend ("addr16 "); - used_prefixes |= PREFIX_ADDR; - } - } - - if (!uses_DATA_prefix && (prefixes & PREFIX_DATA)) - { - sizeflag ^= DFLAG; - if (dp->op[2].bytemode == cond_jump_mode - && dp->op[0].bytemode == v_mode - && !intel_syntax) - { - if (sizeflag & DFLAG) - oappend ("data32 "); - else - oappend ("data16 "); - used_prefixes |= PREFIX_DATA; - } - } - - if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) - { - dp = &three_byte_table[dp->op[1].bytemode][op]; - modrm.mod = (*codep >> 6) & 3; - modrm.reg = (*codep >> 3) & 7; - modrm.rm = *codep & 7; - } - else if (need_modrm) - { - fetch_data(info, codep + 1); - modrm.mod = (*codep >> 6) & 3; - modrm.reg = (*codep >> 3) & 7; - modrm.rm = *codep & 7; - } - - if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) - { - dofloat (sizeflag); - } - else - { - int index; - if (dp->name == NULL) - { - switch (dp->op[0].bytemode) - { - case USE_GROUPS: - dp = &grps[dp->op[1].bytemode][modrm.reg]; - break; - - case USE_PREFIX_USER_TABLE: - index = 0; - used_prefixes |= (prefixes & PREFIX_REPZ); - if (prefixes & PREFIX_REPZ) - index = 1; - else - { - /* We should check PREFIX_REPNZ and PREFIX_REPZ - before PREFIX_DATA. */ - used_prefixes |= (prefixes & PREFIX_REPNZ); - if (prefixes & PREFIX_REPNZ) - index = 3; - else - { - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - index = 2; - } - } - dp = &prefix_user_table[dp->op[1].bytemode][index]; - break; - - case X86_64_SPECIAL: - index = address_mode == mode_64bit ? 1 : 0; - dp = &x86_64_table[dp->op[1].bytemode][index]; - break; - - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } - } - - if (dp->name != NULL && putop (dp->name, sizeflag) == 0) - { - for (i = 0; i < MAX_OPERANDS; ++i) - { - obufp = op_out[i]; - op_ad = MAX_OPERANDS - 1 - i; - if (dp->op[i].rtn) - (*dp->op[i].rtn) (dp->op[i].bytemode, sizeflag); - } - } - } - - /* See if any prefixes were not used. If so, print the first one - separately. If we don't do this, we'll wind up printing an - instruction stream which does not precisely correspond to the - bytes we are disassembling. */ - if ((prefixes & ~used_prefixes) != 0) - { - const char *name; - - name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s", name); - return 1; - } - if (rex & ~rex_used) - { - const char *name; - name = prefix_name (rex | 0x40, priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s ", name); - } - - obufp = obuf + strlen (obuf); - for (i = strlen (obuf); i < 6; i++) - oappend (" "); - oappend (" "); - (*info->fprintf_func) (info->stream, "%s", obuf); - - /* The enter and bound instructions are printed with operands in the same - order as the intel book; everything else is printed in reverse order. */ - if (intel_syntax || two_source_ops) - { - bfd_vma riprel; - - for (i = 0; i < MAX_OPERANDS; ++i) - op_txt[i] = op_out[i]; - - for (i = 0; i < (MAX_OPERANDS >> 1); ++i) - { - op_ad = op_index[i]; - op_index[i] = op_index[MAX_OPERANDS - 1 - i]; - op_index[MAX_OPERANDS - 1 - i] = op_ad; - riprel = op_riprel[i]; - op_riprel[i] = op_riprel [MAX_OPERANDS - 1 - i]; - op_riprel[MAX_OPERANDS - 1 - i] = riprel; - } - } - else - { - for (i = 0; i < MAX_OPERANDS; ++i) - op_txt[MAX_OPERANDS - 1 - i] = op_out[i]; - } - - needcomma = 0; - for (i = 0; i < MAX_OPERANDS; ++i) - if (*op_txt[i]) - { - if (needcomma) - (*info->fprintf_func) (info->stream, ","); - if (op_index[i] != -1 && !op_riprel[i]) - (*info->print_address_func) ((bfd_vma) op_address[op_index[i]], info); - else - (*info->fprintf_func) (info->stream, "%s", op_txt[i]); - needcomma = 1; - } - - for (i = 0; i < MAX_OPERANDS; i++) - if (op_index[i] != -1 && op_riprel[i]) - { - (*info->fprintf_func) (info->stream, " # "); - (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep - + op_address[op_index[i]]), info); - break; - } - return codep - priv.the_buffer; -} - -static const char *float_mem[] = { - /* d8 */ - "fadd{s||s|}", - "fmul{s||s|}", - "fcom{s||s|}", - "fcomp{s||s|}", - "fsub{s||s|}", - "fsubr{s||s|}", - "fdiv{s||s|}", - "fdivr{s||s|}", - /* d9 */ - "fld{s||s|}", - "(bad)", - "fst{s||s|}", - "fstp{s||s|}", - "fldenvIC", - "fldcw", - "fNstenvIC", - "fNstcw", - /* da */ - "fiadd{l||l|}", - "fimul{l||l|}", - "ficom{l||l|}", - "ficomp{l||l|}", - "fisub{l||l|}", - "fisubr{l||l|}", - "fidiv{l||l|}", - "fidivr{l||l|}", - /* db */ - "fild{l||l|}", - "fisttp{l||l|}", - "fist{l||l|}", - "fistp{l||l|}", - "(bad)", - "fld{t||t|}", - "(bad)", - "fstp{t||t|}", - /* dc */ - "fadd{l||l|}", - "fmul{l||l|}", - "fcom{l||l|}", - "fcomp{l||l|}", - "fsub{l||l|}", - "fsubr{l||l|}", - "fdiv{l||l|}", - "fdivr{l||l|}", - /* dd */ - "fld{l||l|}", - "fisttp{ll||ll|}", - "fst{l||l|}", - "fstp{l||l|}", - "frstorIC", - "(bad)", - "fNsaveIC", - "fNstsw", - /* de */ - "fiadd", - "fimul", - "ficom", - "ficomp", - "fisub", - "fisubr", - "fidiv", - "fidivr", - /* df */ - "fild", - "fisttp", - "fist", - "fistp", - "fbld", - "fild{ll||ll|}", - "fbstp", - "fistp{ll||ll|}", -}; - -static const unsigned char float_mem_mode[] = { - /* d8 */ - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - /* d9 */ - d_mode, - 0, - d_mode, - d_mode, - 0, - w_mode, - 0, - w_mode, - /* da */ - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - /* db */ - d_mode, - d_mode, - d_mode, - d_mode, - 0, - t_mode, - 0, - t_mode, - /* dc */ - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - /* dd */ - q_mode, - q_mode, - q_mode, - q_mode, - 0, - 0, - 0, - w_mode, - /* de */ - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - /* df */ - w_mode, - w_mode, - w_mode, - w_mode, - t_mode, - q_mode, - t_mode, - q_mode -}; - -#define ST { OP_ST, 0 } -#define STi { OP_STi, 0 } - -#define FGRPd9_2 NULL, { { NULL, 0 } } -#define FGRPd9_4 NULL, { { NULL, 1 } } -#define FGRPd9_5 NULL, { { NULL, 2 } } -#define FGRPd9_6 NULL, { { NULL, 3 } } -#define FGRPd9_7 NULL, { { NULL, 4 } } -#define FGRPda_5 NULL, { { NULL, 5 } } -#define FGRPdb_4 NULL, { { NULL, 6 } } -#define FGRPde_3 NULL, { { NULL, 7 } } -#define FGRPdf_4 NULL, { { NULL, 8 } } - -static const struct dis386 float_reg[][8] = { - /* d8 */ - { - { "fadd", { ST, STi } }, - { "fmul", { ST, STi } }, - { "fcom", { STi } }, - { "fcomp", { STi } }, - { "fsub", { ST, STi } }, - { "fsubr", { ST, STi } }, - { "fdiv", { ST, STi } }, - { "fdivr", { ST, STi } }, - }, - /* d9 */ - { - { "fld", { STi } }, - { "fxch", { STi } }, - { FGRPd9_2 }, - { "(bad)", { XX } }, - { FGRPd9_4 }, - { FGRPd9_5 }, - { FGRPd9_6 }, - { FGRPd9_7 }, - }, - /* da */ - { - { "fcmovb", { ST, STi } }, - { "fcmove", { ST, STi } }, - { "fcmovbe",{ ST, STi } }, - { "fcmovu", { ST, STi } }, - { "(bad)", { XX } }, - { FGRPda_5 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* db */ - { - { "fcmovnb",{ ST, STi } }, - { "fcmovne",{ ST, STi } }, - { "fcmovnbe",{ ST, STi } }, - { "fcmovnu",{ ST, STi } }, - { FGRPdb_4 }, - { "fucomi", { ST, STi } }, - { "fcomi", { ST, STi } }, - { "(bad)", { XX } }, - }, - /* dc */ - { - { "fadd", { STi, ST } }, - { "fmul", { STi, ST } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, -#if SYSV386_COMPAT - { "fsub", { STi, ST } }, - { "fsubr", { STi, ST } }, - { "fdiv", { STi, ST } }, - { "fdivr", { STi, ST } }, -#else - { "fsubr", { STi, ST } }, - { "fsub", { STi, ST } }, - { "fdivr", { STi, ST } }, - { "fdiv", { STi, ST } }, -#endif - }, - /* dd */ - { - { "ffree", { STi } }, - { "(bad)", { XX } }, - { "fst", { STi } }, - { "fstp", { STi } }, - { "fucom", { STi } }, - { "fucomp", { STi } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* de */ - { - { "faddp", { STi, ST } }, - { "fmulp", { STi, ST } }, - { "(bad)", { XX } }, - { FGRPde_3 }, -#if SYSV386_COMPAT - { "fsubp", { STi, ST } }, - { "fsubrp", { STi, ST } }, - { "fdivp", { STi, ST } }, - { "fdivrp", { STi, ST } }, -#else - { "fsubrp", { STi, ST } }, - { "fsubp", { STi, ST } }, - { "fdivrp", { STi, ST } }, - { "fdivp", { STi, ST } }, -#endif - }, - /* df */ - { - { "ffreep", { STi } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { FGRPdf_4 }, - { "fucomip", { ST, STi } }, - { "fcomip", { ST, STi } }, - { "(bad)", { XX } }, - }, -}; - -static const char *fgrps[][8] = { - /* d9_2 0 */ - { - "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, - - /* d9_4 1 */ - { - "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", - }, - - /* d9_5 2 */ - { - "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", - }, - - /* d9_6 3 */ - { - "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", - }, - - /* d9_7 4 */ - { - "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", - }, - - /* da_5 5 */ - { - "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, - - /* db_4 6 */ - { - "feni(287 only)","fdisi(287 only)","fNclex","fNinit", - "fNsetpm(287 only)","(bad)","(bad)","(bad)", - }, - - /* de_3 7 */ - { - "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, - - /* df_4 8 */ - { - "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, -}; - -static void -dofloat (int sizeflag) -{ - const struct dis386 *dp; - unsigned char floatop; - - floatop = codep[-1]; - - if (modrm.mod != 3) - { - int fp_indx = (floatop - 0xd8) * 8 + modrm.reg; - - putop (float_mem[fp_indx], sizeflag); - obufp = op_out[0]; - op_ad = 2; - OP_E (float_mem_mode[fp_indx], sizeflag); - return; - } - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - - dp = &float_reg[floatop - 0xd8][modrm.reg]; - if (dp->name == NULL) - { - putop (fgrps[dp->op[0].bytemode][modrm.rm], sizeflag); - - /* Instruction fnstsw is only one with strange arg. */ - if (floatop == 0xdf && codep[-1] == 0xe0) - pstrcpy (op_out[0], sizeof(op_out[0]), names16[0]); - } - else - { - putop (dp->name, sizeflag); - - obufp = op_out[0]; - op_ad = 2; - if (dp->op[0].rtn) - (*dp->op[0].rtn) (dp->op[0].bytemode, sizeflag); - - obufp = op_out[1]; - op_ad = 1; - if (dp->op[1].rtn) - (*dp->op[1].rtn) (dp->op[1].bytemode, sizeflag); - } -} - -static void -OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - oappend ("%st" + intel_syntax); -} - -static void -OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", modrm.rm); - oappend (scratchbuf + intel_syntax); -} - -/* Capital letters in template are macros. */ -static int -putop (const char *template, int sizeflag) -{ - const char *p; - int alt = 0; - - for (p = template; *p; p++) - { - switch (*p) - { - default: - *obufp++ = *p; - break; - case '{': - alt = 0; - if (intel_syntax) - alt += 1; - if (address_mode == mode_64bit) - alt += 2; - while (alt != 0) - { - while (*++p != '|') - { - if (*p == '}') - { - /* Alternative not valid. */ - pstrcpy (obuf, sizeof(obuf), "(bad)"); - obufp = obuf + 5; - return 1; - } - else if (*p == '\0') - abort (); - } - alt--; - } - /* Fall through. */ - case 'I': - alt = 1; - continue; - case '|': - while (*++p != '}') - { - if (*p == '\0') - abort (); - } - break; - case '}': - break; - case 'A': - if (intel_syntax) - break; - if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) - *obufp++ = 'b'; - break; - case 'B': - if (intel_syntax) - break; - if (sizeflag & SUFFIX_ALWAYS) - *obufp++ = 'b'; - break; - case 'C': - if (intel_syntax && !alt) - break; - if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) - { - if (sizeflag & DFLAG) - *obufp++ = intel_syntax ? 'd' : 'l'; - else - *obufp++ = intel_syntax ? 'w' : 's'; - used_prefixes |= (prefixes & PREFIX_DATA); - } - break; - case 'D': - if (intel_syntax || !(sizeflag & SUFFIX_ALWAYS)) - break; - USED_REX (REX_W); - if (modrm.mod == 3) - { - if (rex & REX_W) - *obufp++ = 'q'; - else if (sizeflag & DFLAG) - *obufp++ = intel_syntax ? 'd' : 'l'; - else - *obufp++ = 'w'; - used_prefixes |= (prefixes & PREFIX_DATA); - } - else - *obufp++ = 'w'; - break; - case 'E': /* For jcxz/jecxz */ - if (address_mode == mode_64bit) - { - if (sizeflag & AFLAG) - *obufp++ = 'r'; - else - *obufp++ = 'e'; - } - else - if (sizeflag & AFLAG) - *obufp++ = 'e'; - used_prefixes |= (prefixes & PREFIX_ADDR); - break; - case 'F': - if (intel_syntax) - break; - if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) - { - if (sizeflag & AFLAG) - *obufp++ = address_mode == mode_64bit ? 'q' : 'l'; - else - *obufp++ = address_mode == mode_64bit ? 'l' : 'w'; - used_prefixes |= (prefixes & PREFIX_ADDR); - } - break; - case 'G': - if (intel_syntax || (obufp[-1] != 's' && !(sizeflag & SUFFIX_ALWAYS))) - break; - if ((rex & REX_W) || (sizeflag & DFLAG)) - *obufp++ = 'l'; - else - *obufp++ = 'w'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'H': - if (intel_syntax) - break; - if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS - || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) - { - used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); - *obufp++ = ','; - *obufp++ = 'p'; - if (prefixes & PREFIX_DS) - *obufp++ = 't'; - else - *obufp++ = 'n'; - } - break; - case 'J': - if (intel_syntax) - break; - *obufp++ = 'l'; - break; - case 'K': - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'q'; - else - *obufp++ = 'd'; - break; - case 'Z': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & SUFFIX_ALWAYS)) - { - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'L': - if (intel_syntax) - break; - if (sizeflag & SUFFIX_ALWAYS) - *obufp++ = 'l'; - break; - case 'N': - if ((prefixes & PREFIX_FWAIT) == 0) - *obufp++ = 'n'; - else - used_prefixes |= PREFIX_FWAIT; - break; - case 'O': - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'o'; - else if (intel_syntax && (sizeflag & DFLAG)) - *obufp++ = 'q'; - else - *obufp++ = 'd'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'T': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'P': - if (intel_syntax) - break; - if ((prefixes & PREFIX_DATA) - || (rex & REX_W) - || (sizeflag & SUFFIX_ALWAYS)) - { - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'q'; - else - { - if (sizeflag & DFLAG) - *obufp++ = 'l'; - else - *obufp++ = 'w'; - } - used_prefixes |= (prefixes & PREFIX_DATA); - } - break; - case 'U': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'Q': - if (intel_syntax && !alt) - break; - USED_REX (REX_W); - if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) - { - if (rex & REX_W) - *obufp++ = 'q'; - else - { - if (sizeflag & DFLAG) - *obufp++ = intel_syntax ? 'd' : 'l'; - else - *obufp++ = 'w'; - } - used_prefixes |= (prefixes & PREFIX_DATA); - } - break; - case 'R': - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'q'; - else if (sizeflag & DFLAG) - { - if (intel_syntax) - *obufp++ = 'd'; - else - *obufp++ = 'l'; - } - else - *obufp++ = 'w'; - if (intel_syntax && !p[1] - && ((rex & REX_W) || (sizeflag & DFLAG))) - *obufp++ = 'e'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'V': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - if (sizeflag & SUFFIX_ALWAYS) - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'S': - if (intel_syntax) - break; - if (sizeflag & SUFFIX_ALWAYS) - { - if (rex & REX_W) - *obufp++ = 'q'; - else - { - if (sizeflag & DFLAG) - *obufp++ = 'l'; - else - *obufp++ = 'w'; - used_prefixes |= (prefixes & PREFIX_DATA); - } - } - break; - case 'X': - if (prefixes & PREFIX_DATA) - *obufp++ = 'd'; - else - *obufp++ = 's'; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'Y': - if (intel_syntax) - break; - if (rex & REX_W) - { - USED_REX (REX_W); - *obufp++ = 'q'; - } - break; - /* implicit operand size 'l' for i386 or 'q' for x86-64 */ - case 'W': - /* operand size flag for cwtl, cbtw */ - USED_REX (REX_W); - if (rex & REX_W) - { - if (intel_syntax) - *obufp++ = 'd'; - else - *obufp++ = 'l'; - } - else if (sizeflag & DFLAG) - *obufp++ = 'w'; - else - *obufp++ = 'b'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - } - alt = 0; - } - *obufp = 0; - return 0; -} - -static void -oappend (const char *s) -{ - strcpy (obufp, s); - obufp += strlen (s); -} - -static void -append_seg (void) -{ - if (prefixes & PREFIX_CS) - { - used_prefixes |= PREFIX_CS; - oappend ("%cs:" + intel_syntax); - } - if (prefixes & PREFIX_DS) - { - used_prefixes |= PREFIX_DS; - oappend ("%ds:" + intel_syntax); - } - if (prefixes & PREFIX_SS) - { - used_prefixes |= PREFIX_SS; - oappend ("%ss:" + intel_syntax); - } - if (prefixes & PREFIX_ES) - { - used_prefixes |= PREFIX_ES; - oappend ("%es:" + intel_syntax); - } - if (prefixes & PREFIX_FS) - { - used_prefixes |= PREFIX_FS; - oappend ("%fs:" + intel_syntax); - } - if (prefixes & PREFIX_GS) - { - used_prefixes |= PREFIX_GS; - oappend ("%gs:" + intel_syntax); - } -} - -static void -OP_indirE (int bytemode, int sizeflag) -{ - if (!intel_syntax) - oappend ("*"); - OP_E (bytemode, sizeflag); -} - -static void -print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp) -{ - if (address_mode == mode_64bit) - { - if (hex) - { - char tmp[30]; - int i; - buf[0] = '0'; - buf[1] = 'x'; - snprintf_vma (tmp, sizeof(tmp), disp); - for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) { - } - pstrcpy (buf + 2, bufsize - 2, tmp + i); - } - else - { - bfd_signed_vma v = disp; - char tmp[30]; - int i; - if (v < 0) - { - *(buf++) = '-'; - v = -disp; - /* Check for possible overflow on 0x8000000000000000. */ - if (v < 0) - { - pstrcpy (buf, bufsize, "9223372036854775808"); - return; - } - } - if (!v) - { - pstrcpy (buf, bufsize, "0"); - return; - } - - i = 0; - tmp[29] = 0; - while (v) - { - tmp[28 - i] = (v % 10) + '0'; - v /= 10; - i++; - } - pstrcpy (buf, bufsize, tmp + 29 - i); - } - } - else - { - if (hex) - snprintf (buf, bufsize, "0x%x", (unsigned int) disp); - else - snprintf (buf, bufsize, "%d", (int) disp); - } -} - -/* Put DISP in BUF as signed hex number. */ - -static void -print_displacement (char *buf, bfd_vma disp) -{ - bfd_signed_vma val = disp; - char tmp[30]; - int i, j = 0; - - if (val < 0) - { - buf[j++] = '-'; - val = -disp; - - /* Check for possible overflow. */ - if (val < 0) - { - switch (address_mode) - { - case mode_64bit: - strcpy (buf + j, "0x8000000000000000"); - break; - case mode_32bit: - strcpy (buf + j, "0x80000000"); - break; - case mode_16bit: - strcpy (buf + j, "0x8000"); - break; - } - return; - } - } - - buf[j++] = '0'; - buf[j++] = 'x'; - - snprintf_vma (tmp, sizeof(tmp), val); - for (i = 0; tmp[i] == '0'; i++) - continue; - if (tmp[i] == '\0') - i--; - strcpy (buf + j, tmp + i); -} - -static void -intel_operand_size (int bytemode, int sizeflag) -{ - switch (bytemode) - { - case b_mode: - case dqb_mode: - oappend ("BYTE PTR "); - break; - case w_mode: - case dqw_mode: - oappend ("WORD PTR "); - break; - case stack_v_mode: - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - oappend ("QWORD PTR "); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - } - /* FALLTHRU */ - case v_mode: - case dq_mode: - USED_REX (REX_W); - if (rex & REX_W) - oappend ("QWORD PTR "); - else if ((sizeflag & DFLAG) || bytemode == dq_mode) - oappend ("DWORD PTR "); - else - oappend ("WORD PTR "); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case z_mode: - if ((rex & REX_W) || (sizeflag & DFLAG)) - *obufp++ = 'D'; - oappend ("WORD PTR "); - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case d_mode: - case dqd_mode: - oappend ("DWORD PTR "); - break; - case q_mode: - oappend ("QWORD PTR "); - break; - case m_mode: - if (address_mode == mode_64bit) - oappend ("QWORD PTR "); - else - oappend ("DWORD PTR "); - break; - case f_mode: - if (sizeflag & DFLAG) - oappend ("FWORD PTR "); - else - oappend ("DWORD PTR "); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case t_mode: - oappend ("TBYTE PTR "); - break; - case x_mode: - oappend ("XMMWORD PTR "); - break; - case o_mode: - oappend ("OWORD PTR "); - break; - default: - break; - } -} - -static void -OP_E (int bytemode, int sizeflag) -{ - bfd_vma disp; - int add = 0; - int riprel = 0; - USED_REX (REX_B); - if (rex & REX_B) - add += 8; - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - - if (modrm.mod == 3) - { - switch (bytemode) - { - case b_mode: - USED_REX (0); - if (rex) - oappend (names8rex[modrm.rm + add]); - else - oappend (names8[modrm.rm + add]); - break; - case w_mode: - oappend (names16[modrm.rm + add]); - break; - case d_mode: - oappend (names32[modrm.rm + add]); - break; - case q_mode: - oappend (names64[modrm.rm + add]); - break; - case m_mode: - if (address_mode == mode_64bit) - oappend (names64[modrm.rm + add]); - else - oappend (names32[modrm.rm + add]); - break; - case stack_v_mode: - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - oappend (names64[modrm.rm + add]); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - } - bytemode = v_mode; - /* FALLTHRU */ - case v_mode: - case dq_mode: - case dqb_mode: - case dqd_mode: - case dqw_mode: - USED_REX (REX_W); - if (rex & REX_W) - oappend (names64[modrm.rm + add]); - else if ((sizeflag & DFLAG) || bytemode != v_mode) - oappend (names32[modrm.rm + add]); - else - oappend (names16[modrm.rm + add]); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 0: - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } - return; - } - - disp = 0; - if (intel_syntax) - intel_operand_size (bytemode, sizeflag); - append_seg (); - - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - { - /* 32/64 bit address mode */ - int havedisp; - int havesib; - int havebase; - int base; - int index = 0; - int scale = 0; - - havesib = 0; - havebase = 1; - base = modrm.rm; - - if (base == 4) - { - havesib = 1; - fetch_data(the_info, codep + 1); - index = (*codep >> 3) & 7; - if (address_mode == mode_64bit || index != 0x4) - /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ - scale = (*codep >> 6) & 3; - base = *codep & 7; - USED_REX (REX_X); - if (rex & REX_X) - index += 8; - codep++; - } - base += add; - - switch (modrm.mod) - { - case 0: - if ((base & 7) == 5) - { - havebase = 0; - if (address_mode == mode_64bit && !havesib) - riprel = 1; - disp = get32s (); - } - break; - case 1: - fetch_data (the_info, codep + 1); - disp = *codep++; - if ((disp & 0x80) != 0) - disp -= 0x100; - break; - case 2: - disp = get32s (); - break; - } - - havedisp = havebase || (havesib && (index != 4 || scale != 0)); - - if (!intel_syntax) - if (modrm.mod != 0 || (base & 7) == 5) - { - if (havedisp || riprel) - print_displacement (scratchbuf, disp); - else - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); - oappend (scratchbuf); - if (riprel) - { - set_op (disp, 1); - oappend ("(%rip)"); - } - } - - if (havedisp || (intel_syntax && riprel)) - { - *obufp++ = open_char; - if (intel_syntax && riprel) - { - set_op (disp, 1); - oappend ("rip"); - } - *obufp = '\0'; - if (havebase) - oappend (address_mode == mode_64bit && (sizeflag & AFLAG) - ? names64[base] : names32[base]); - if (havesib) - { - if (index != 4) - { - if (!intel_syntax || havebase) - { - *obufp++ = separator_char; - *obufp = '\0'; - } - oappend (address_mode == mode_64bit && (sizeflag & AFLAG) - ? names64[index] : names32[index]); - } - if (scale != 0 || (!intel_syntax && index != 4)) - { - *obufp++ = scale_char; - *obufp = '\0'; - snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale); - oappend (scratchbuf); - } - } - if (intel_syntax - && (disp || modrm.mod != 0 || (base & 7) == 5)) - { - if ((bfd_signed_vma) disp >= 0) - { - *obufp++ = '+'; - *obufp = '\0'; - } - else if (modrm.mod != 1) - { - *obufp++ = '-'; - *obufp = '\0'; - disp = - (bfd_signed_vma) disp; - } - - print_displacement (scratchbuf, disp); - oappend (scratchbuf); - } - - *obufp++ = close_char; - *obufp = '\0'; - } - else if (intel_syntax) - { - if (modrm.mod != 0 || (base & 7) == 5) - { - if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS)) - ; - else - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); - oappend (scratchbuf); - } - } - } - else - { /* 16 bit address mode */ - switch (modrm.mod) - { - case 0: - if (modrm.rm == 6) - { - disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - } - break; - case 1: - fetch_data(the_info, codep + 1); - disp = *codep++; - if ((disp & 0x80) != 0) - disp -= 0x100; - break; - case 2: - disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - break; - } - - if (!intel_syntax) - if (modrm.mod != 0 || modrm.rm == 6) - { - print_displacement (scratchbuf, disp); - oappend (scratchbuf); - } - - if (modrm.mod != 0 || modrm.rm != 6) - { - *obufp++ = open_char; - *obufp = '\0'; - oappend (index16[modrm.rm]); - if (intel_syntax - && (disp || modrm.mod != 0 || modrm.rm == 6)) - { - if ((bfd_signed_vma) disp >= 0) - { - *obufp++ = '+'; - *obufp = '\0'; - } - else if (modrm.mod != 1) - { - *obufp++ = '-'; - *obufp = '\0'; - disp = - (bfd_signed_vma) disp; - } - - print_displacement (scratchbuf, disp); - oappend (scratchbuf); - } - - *obufp++ = close_char; - *obufp = '\0'; - } - else if (intel_syntax) - { - if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS)) - ; - else - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, - disp & 0xffff); - oappend (scratchbuf); - } - } -} - -static void -OP_G (int bytemode, int sizeflag) -{ - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add += 8; - switch (bytemode) - { - case b_mode: - USED_REX (0); - if (rex) - oappend (names8rex[modrm.reg + add]); - else - oappend (names8[modrm.reg + add]); - break; - case w_mode: - oappend (names16[modrm.reg + add]); - break; - case d_mode: - oappend (names32[modrm.reg + add]); - break; - case q_mode: - oappend (names64[modrm.reg + add]); - break; - case v_mode: - case dq_mode: - case dqb_mode: - case dqd_mode: - case dqw_mode: - USED_REX (REX_W); - if (rex & REX_W) - oappend (names64[modrm.reg + add]); - else if ((sizeflag & DFLAG) || bytemode != v_mode) - oappend (names32[modrm.reg + add]); - else - oappend (names16[modrm.reg + add]); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case m_mode: - if (address_mode == mode_64bit) - oappend (names64[modrm.reg + add]); - else - oappend (names32[modrm.reg + add]); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } -} - -static void -OP_vvvv (int bytemode, int sizeflags) -{ - USED_REX (REX_W); - if (rex & REX_W) { - oappend(names64[vex_reg]); - } else { - oappend(names32[vex_reg]); - } -} - -static bfd_vma -get64 (void) -{ - bfd_vma x; -#ifdef BFD64 - unsigned int a; - unsigned int b; - - fetch_data(the_info, codep + 8); - a = *codep++ & 0xff; - a |= (*codep++ & 0xff) << 8; - a |= (*codep++ & 0xff) << 16; - a |= (*codep++ & 0xff) << 24; - b = *codep++ & 0xff; - b |= (*codep++ & 0xff) << 8; - b |= (*codep++ & 0xff) << 16; - b |= (*codep++ & 0xff) << 24; - x = a + ((bfd_vma) b << 32); -#else - abort (); - x = 0; -#endif - return x; -} - -static bfd_signed_vma -get32 (void) -{ - bfd_signed_vma x = 0; - - fetch_data(the_info, codep + 4); - x = *codep++ & (bfd_signed_vma) 0xff; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; - return x; -} - -static bfd_signed_vma -get32s (void) -{ - bfd_signed_vma x = 0; - - fetch_data(the_info, codep + 4); - x = *codep++ & (bfd_signed_vma) 0xff; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; - - x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); - - return x; -} - -static int -get16 (void) -{ - int x = 0; - - fetch_data(the_info, codep + 2); - x = *codep++ & 0xff; - x |= (*codep++ & 0xff) << 8; - return x; -} - -static void -set_op (bfd_vma op, int riprel) -{ - op_index[op_ad] = op_ad; - if (address_mode == mode_64bit) - { - op_address[op_ad] = op; - op_riprel[op_ad] = riprel; - } - else - { - /* Mask to get a 32-bit address. */ - op_address[op_ad] = op & 0xffffffff; - op_riprel[op_ad] = riprel & 0xffffffff; - } -} - -static void -OP_REG (int code, int sizeflag) -{ - const char *s; - int add = 0; - USED_REX (REX_B); - if (rex & REX_B) - add = 8; - - switch (code) - { - case ax_reg: case cx_reg: case dx_reg: case bx_reg: - case sp_reg: case bp_reg: case si_reg: case di_reg: - s = names16[code - ax_reg + add]; - break; - case es_reg: case ss_reg: case cs_reg: - case ds_reg: case fs_reg: case gs_reg: - s = names_seg[code - es_reg + add]; - break; - case al_reg: case ah_reg: case cl_reg: case ch_reg: - case dl_reg: case dh_reg: case bl_reg: case bh_reg: - USED_REX (0); - if (rex) - s = names8rex[code - al_reg + add]; - else - s = names8[code - al_reg]; - break; - case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: - case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - s = names64[code - rAX_reg + add]; - break; - } - code += eAX_reg - rAX_reg; - /* Fall through. */ - case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: - case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: - USED_REX (REX_W); - if (rex & REX_W) - s = names64[code - eAX_reg + add]; - else if (sizeflag & DFLAG) - s = names32[code - eAX_reg + add]; - else - s = names16[code - eAX_reg + add]; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - s = INTERNAL_DISASSEMBLER_ERROR; - break; - } - oappend (s); -} - -static void -OP_IMREG (int code, int sizeflag) -{ - const char *s; - - switch (code) - { - case indir_dx_reg: - if (intel_syntax) - s = "dx"; - else - s = "(%dx)"; - break; - case ax_reg: case cx_reg: case dx_reg: case bx_reg: - case sp_reg: case bp_reg: case si_reg: case di_reg: - s = names16[code - ax_reg]; - break; - case es_reg: case ss_reg: case cs_reg: - case ds_reg: case fs_reg: case gs_reg: - s = names_seg[code - es_reg]; - break; - case al_reg: case ah_reg: case cl_reg: case ch_reg: - case dl_reg: case dh_reg: case bl_reg: case bh_reg: - USED_REX (0); - if (rex) - s = names8rex[code - al_reg]; - else - s = names8[code - al_reg]; - break; - case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: - case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: - USED_REX (REX_W); - if (rex & REX_W) - s = names64[code - eAX_reg]; - else if (sizeflag & DFLAG) - s = names32[code - eAX_reg]; - else - s = names16[code - eAX_reg]; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case z_mode_ax_reg: - if ((rex & REX_W) || (sizeflag & DFLAG)) - s = *names32; - else - s = *names16; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - s = INTERNAL_DISASSEMBLER_ERROR; - break; - } - oappend (s); -} - -static void -OP_I (int bytemode, int sizeflag) -{ - bfd_signed_vma op; - bfd_signed_vma mask = -1; - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - op = *codep++; - mask = 0xff; - break; - case q_mode: - if (address_mode == mode_64bit) - { - op = get32s (); - break; - } - /* Fall through. */ - case v_mode: - USED_REX (REX_W); - if (rex & REX_W) - op = get32s (); - else if (sizeflag & DFLAG) - { - op = get32 (); - mask = 0xffffffff; - } - else - { - op = get16 (); - mask = 0xfffff; - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case w_mode: - mask = 0xfffff; - op = get16 (); - break; - case const_1_mode: - if (intel_syntax) - oappend ("1"); - return; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - - op &= mask; - scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); - oappend (scratchbuf + intel_syntax); - scratchbuf[0] = '\0'; -} - -static void -OP_I64 (int bytemode, int sizeflag) -{ - bfd_signed_vma op; - bfd_signed_vma mask = -1; - - if (address_mode != mode_64bit) - { - OP_I (bytemode, sizeflag); - return; - } - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - op = *codep++; - mask = 0xff; - break; - case v_mode: - USED_REX (REX_W); - if (rex & REX_W) - op = get64 (); - else if (sizeflag & DFLAG) - { - op = get32 (); - mask = 0xffffffff; - } - else - { - op = get16 (); - mask = 0xfffff; - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case w_mode: - mask = 0xfffff; - op = get16 (); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - - op &= mask; - scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); - oappend (scratchbuf + intel_syntax); - scratchbuf[0] = '\0'; -} - -static void -OP_sI (int bytemode, int sizeflag) -{ - bfd_signed_vma op; - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - op = *codep++; - if ((op & 0x80) != 0) - op -= 0x100; - break; - case v_mode: - USED_REX (REX_W); - if (rex & REX_W) - op = get32s (); - else if (sizeflag & DFLAG) - { - op = get32s (); - } - else - { - op = get16 (); - if ((op & 0x8000) != 0) - op -= 0x10000; - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case w_mode: - op = get16 (); - if ((op & 0x8000) != 0) - op -= 0x10000; - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - - scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_J (int bytemode, int sizeflag) -{ - bfd_vma disp; - bfd_vma mask = -1; - bfd_vma segment = 0; - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - disp = *codep++; - if ((disp & 0x80) != 0) - disp -= 0x100; - break; - case v_mode: - if ((sizeflag & DFLAG) || (rex & REX_W)) - disp = get32s (); - else - { - disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - /* In 16bit mode, address is wrapped around at 64k within - the same segment. Otherwise, a data16 prefix on a jump - instruction means that the pc is masked to 16 bits after - the displacement is added! */ - mask = 0xffff; - if ((prefixes & PREFIX_DATA) == 0) - segment = ((start_pc + codep - start_codep) - & ~((bfd_vma) 0xffff)); - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - disp = ((start_pc + codep - start_codep + disp) & mask) | segment; - set_op (disp, 0); - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); - oappend (scratchbuf); -} - -static void -OP_SEG (int bytemode, int sizeflag) -{ - if (bytemode == w_mode) - oappend (names_seg[modrm.reg]); - else - OP_E (modrm.mod == 3 ? bytemode : w_mode, sizeflag); -} - -static void -OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) -{ - int seg, offset; - - if (sizeflag & DFLAG) - { - offset = get32 (); - seg = get16 (); - } - else - { - offset = get16 (); - seg = get16 (); - } - used_prefixes |= (prefixes & PREFIX_DATA); - if (intel_syntax) - snprintf (scratchbuf, sizeof(scratchbuf), "0x%x:0x%x", seg, offset); - else - snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset); - oappend (scratchbuf); -} - -static void -OP_OFF (int bytemode, int sizeflag) -{ - bfd_vma off; - - if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) - intel_operand_size (bytemode, sizeflag); - append_seg (); - - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - off = get32 (); - else - off = get16 (); - - if (intel_syntax) - { - if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS))) - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); - oappend (scratchbuf); -} - -static void -OP_OFF64 (int bytemode, int sizeflag) -{ - bfd_vma off; - - if (address_mode != mode_64bit - || (prefixes & PREFIX_ADDR)) - { - OP_OFF (bytemode, sizeflag); - return; - } - - if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) - intel_operand_size (bytemode, sizeflag); - append_seg (); - - off = get64 (); - - if (intel_syntax) - { - if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS))) - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); - oappend (scratchbuf); -} - -static void -ptr_reg (int code, int sizeflag) -{ - const char *s; - - *obufp++ = open_char; - used_prefixes |= (prefixes & PREFIX_ADDR); - if (address_mode == mode_64bit) - { - if (!(sizeflag & AFLAG)) - s = names32[code - eAX_reg]; - else - s = names64[code - eAX_reg]; - } - else if (sizeflag & AFLAG) - s = names32[code - eAX_reg]; - else - s = names16[code - eAX_reg]; - oappend (s); - *obufp++ = close_char; - *obufp = 0; -} - -static void -OP_ESreg (int code, int sizeflag) -{ - if (intel_syntax) - { - switch (codep[-1]) - { - case 0x6d: /* insw/insl */ - intel_operand_size (z_mode, sizeflag); - break; - case 0xa5: /* movsw/movsl/movsq */ - case 0xa7: /* cmpsw/cmpsl/cmpsq */ - case 0xab: /* stosw/stosl */ - case 0xaf: /* scasw/scasl */ - intel_operand_size (v_mode, sizeflag); - break; - default: - intel_operand_size (b_mode, sizeflag); - } - } - oappend ("%es:" + intel_syntax); - ptr_reg (code, sizeflag); -} - -static void -OP_DSreg (int code, int sizeflag) -{ - if (intel_syntax) - { - switch (codep[-1]) - { - case 0x6f: /* outsw/outsl */ - intel_operand_size (z_mode, sizeflag); - break; - case 0xa5: /* movsw/movsl/movsq */ - case 0xa7: /* cmpsw/cmpsl/cmpsq */ - case 0xad: /* lodsw/lodsl/lodsq */ - intel_operand_size (v_mode, sizeflag); - break; - default: - intel_operand_size (b_mode, sizeflag); - } - } - if ((prefixes - & (PREFIX_CS - | PREFIX_DS - | PREFIX_SS - | PREFIX_ES - | PREFIX_FS - | PREFIX_GS)) == 0) - prefixes |= PREFIX_DS; - append_seg (); - ptr_reg (code, sizeflag); -} - -static void -OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - int add = 0; - if (rex & REX_R) - { - USED_REX (REX_R); - add = 8; - } - else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK)) - { - used_prefixes |= PREFIX_LOCK; - add = 8; - } - snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", modrm.reg + add); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add = 8; - if (intel_syntax) - snprintf (scratchbuf, sizeof(scratchbuf), "db%d", modrm.reg + add); - else - snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", modrm.reg + add); - oappend (scratchbuf); -} - -static void -OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", modrm.reg); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_R (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - OP_E (bytemode, sizeflag); - else - BadOp (); -} - -static void -OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - { - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add = 8; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); - } - else - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add = 8; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_EM (int bytemode, int sizeflag) -{ - if (modrm.mod != 3) - { - if (intel_syntax && bytemode == v_mode) - { - bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; - used_prefixes |= (prefixes & PREFIX_DATA); - } - OP_E (bytemode, sizeflag); - return; - } - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - { - int add = 0; - - USED_REX (REX_B); - if (rex & REX_B) - add = 8; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); - } - else - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); - oappend (scratchbuf + intel_syntax); -} - -/* cvt* are the only instructions in sse2 which have - both SSE and MMX operands and also have 0x66 prefix - in their opcode. 0x66 was originally used to differentiate - between SSE and MMX instruction(operands). So we have to handle the - cvt* separately using OP_EMC and OP_MXC */ -static void -OP_EMC (int bytemode, int sizeflag) -{ - if (modrm.mod != 3) - { - if (intel_syntax && bytemode == v_mode) - { - bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; - used_prefixes |= (prefixes & PREFIX_DATA); - } - OP_E (bytemode, sizeflag); - return; - } - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - used_prefixes |= (prefixes & PREFIX_DATA); - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_MXC (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - used_prefixes |= (prefixes & PREFIX_DATA); - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_EX (int bytemode, int sizeflag) -{ - int add = 0; - if (modrm.mod != 3) - { - OP_E (bytemode, sizeflag); - return; - } - USED_REX (REX_B); - if (rex & REX_B) - add = 8; - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_MS (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - OP_EM (bytemode, sizeflag); - else - BadOp (); -} - -static void -OP_XS (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - OP_EX (bytemode, sizeflag); - else - BadOp (); -} - -static void -OP_M (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - /* bad bound,lea,lds,les,lfs,lgs,lss,cmpxchg8b,vmptrst modrm */ - BadOp (); - else - OP_E (bytemode, sizeflag); -} - -static void -OP_0f07 (int bytemode, int sizeflag) -{ - if (modrm.mod != 3 || modrm.rm != 0) - BadOp (); - else - OP_E (bytemode, sizeflag); -} - -static void -OP_0fae (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - { - if (modrm.reg == 7) - strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); - - if (modrm.reg < 5 || modrm.rm != 0) - { - BadOp (); /* bad sfence, mfence, or lfence */ - return; - } - } - else if (modrm.reg != 7) - { - BadOp (); /* bad clflush */ - return; - } - - OP_E (bytemode, sizeflag); -} - -/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in - 32bit mode and "xchg %rax,%rax" in 64bit mode. */ - -static void -NOP_Fixup1 (int bytemode, int sizeflag) -{ - if ((prefixes & PREFIX_DATA) != 0 - || (rex != 0 - && rex != 0x48 - && address_mode == mode_64bit)) - OP_REG (bytemode, sizeflag); - else - strcpy (obuf, "nop"); -} - -static void -NOP_Fixup2 (int bytemode, int sizeflag) -{ - if ((prefixes & PREFIX_DATA) != 0 - || (rex != 0 - && rex != 0x48 - && address_mode == mode_64bit)) - OP_IMREG (bytemode, sizeflag); -} - -static const char *Suffix3DNow[] = { -/* 00 */ NULL, NULL, NULL, NULL, -/* 04 */ NULL, NULL, NULL, NULL, -/* 08 */ NULL, NULL, NULL, NULL, -/* 0C */ "pi2fw", "pi2fd", NULL, NULL, -/* 10 */ NULL, NULL, NULL, NULL, -/* 14 */ NULL, NULL, NULL, NULL, -/* 18 */ NULL, NULL, NULL, NULL, -/* 1C */ "pf2iw", "pf2id", NULL, NULL, -/* 20 */ NULL, NULL, NULL, NULL, -/* 24 */ NULL, NULL, NULL, NULL, -/* 28 */ NULL, NULL, NULL, NULL, -/* 2C */ NULL, NULL, NULL, NULL, -/* 30 */ NULL, NULL, NULL, NULL, -/* 34 */ NULL, NULL, NULL, NULL, -/* 38 */ NULL, NULL, NULL, NULL, -/* 3C */ NULL, NULL, NULL, NULL, -/* 40 */ NULL, NULL, NULL, NULL, -/* 44 */ NULL, NULL, NULL, NULL, -/* 48 */ NULL, NULL, NULL, NULL, -/* 4C */ NULL, NULL, NULL, NULL, -/* 50 */ NULL, NULL, NULL, NULL, -/* 54 */ NULL, NULL, NULL, NULL, -/* 58 */ NULL, NULL, NULL, NULL, -/* 5C */ NULL, NULL, NULL, NULL, -/* 60 */ NULL, NULL, NULL, NULL, -/* 64 */ NULL, NULL, NULL, NULL, -/* 68 */ NULL, NULL, NULL, NULL, -/* 6C */ NULL, NULL, NULL, NULL, -/* 70 */ NULL, NULL, NULL, NULL, -/* 74 */ NULL, NULL, NULL, NULL, -/* 78 */ NULL, NULL, NULL, NULL, -/* 7C */ NULL, NULL, NULL, NULL, -/* 80 */ NULL, NULL, NULL, NULL, -/* 84 */ NULL, NULL, NULL, NULL, -/* 88 */ NULL, NULL, "pfnacc", NULL, -/* 8C */ NULL, NULL, "pfpnacc", NULL, -/* 90 */ "pfcmpge", NULL, NULL, NULL, -/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", -/* 98 */ NULL, NULL, "pfsub", NULL, -/* 9C */ NULL, NULL, "pfadd", NULL, -/* A0 */ "pfcmpgt", NULL, NULL, NULL, -/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", -/* A8 */ NULL, NULL, "pfsubr", NULL, -/* AC */ NULL, NULL, "pfacc", NULL, -/* B0 */ "pfcmpeq", NULL, NULL, NULL, -/* B4 */ "pfmul", NULL, "pfrcpit2", "pmulhrw", -/* B8 */ NULL, NULL, NULL, "pswapd", -/* BC */ NULL, NULL, NULL, "pavgusb", -/* C0 */ NULL, NULL, NULL, NULL, -/* C4 */ NULL, NULL, NULL, NULL, -/* C8 */ NULL, NULL, NULL, NULL, -/* CC */ NULL, NULL, NULL, NULL, -/* D0 */ NULL, NULL, NULL, NULL, -/* D4 */ NULL, NULL, NULL, NULL, -/* D8 */ NULL, NULL, NULL, NULL, -/* DC */ NULL, NULL, NULL, NULL, -/* E0 */ NULL, NULL, NULL, NULL, -/* E4 */ NULL, NULL, NULL, NULL, -/* E8 */ NULL, NULL, NULL, NULL, -/* EC */ NULL, NULL, NULL, NULL, -/* F0 */ NULL, NULL, NULL, NULL, -/* F4 */ NULL, NULL, NULL, NULL, -/* F8 */ NULL, NULL, NULL, NULL, -/* FC */ NULL, NULL, NULL, NULL, -}; - -static void -OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - const char *mnemonic; - - fetch_data(the_info, codep + 1); - /* AMD 3DNow! instructions are specified by an opcode suffix in the - place where an 8-bit immediate would normally go. ie. the last - byte of the instruction. */ - obufp = obuf + strlen (obuf); - mnemonic = Suffix3DNow[*codep++ & 0xff]; - if (mnemonic) - oappend (mnemonic); - else - { - /* Since a variable sized modrm/sib chunk is between the start - of the opcode (0x0f0f) and the opcode suffix, we need to do - all the modrm processing first, and don't know until now that - we have a bad opcode. This necessitates some cleaning up. */ - op_out[0][0] = '\0'; - op_out[1][0] = '\0'; - BadOp (); - } -} - -static const char *simd_cmp_op[] = { - "eq", - "lt", - "le", - "unord", - "neq", - "nlt", - "nle", - "ord" -}; - -static void -OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - unsigned int cmp_type; - - fetch_data(the_info, codep + 1); - obufp = obuf + strlen (obuf); - cmp_type = *codep++ & 0xff; - if (cmp_type < 8) - { - char suffix1 = 'p', suffix2 = 's'; - used_prefixes |= (prefixes & PREFIX_REPZ); - if (prefixes & PREFIX_REPZ) - suffix1 = 's'; - else - { - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - suffix2 = 'd'; - else - { - used_prefixes |= (prefixes & PREFIX_REPNZ); - if (prefixes & PREFIX_REPNZ) - suffix1 = 's', suffix2 = 'd'; - } - } - snprintf (scratchbuf, sizeof(scratchbuf), "cmp%s%c%c", - simd_cmp_op[cmp_type], suffix1, suffix2); - used_prefixes |= (prefixes & PREFIX_REPZ); - oappend (scratchbuf); - } - else - { - /* We have a bad extension byte. Clean up. */ - op_out[0][0] = '\0'; - op_out[1][0] = '\0'; - BadOp (); - } -} - -static void -SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) -{ - /* Change movlps/movhps to movhlps/movlhps for 2 register operand - forms of these instructions. */ - if (modrm.mod == 3) - { - char *p = obuf + strlen (obuf); - *(p + 1) = '\0'; - *p = *(p - 1); - *(p - 1) = *(p - 2); - *(p - 2) = *(p - 3); - *(p - 3) = extrachar; - } -} - -static void -PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) -{ - if (modrm.mod == 3 && modrm.reg == 1 && modrm.rm <= 1) - { - /* Override "sidt". */ - size_t olen = strlen (obuf); - char *p = obuf + olen - 4; - const char * const *names = (address_mode == mode_64bit - ? names64 : names32); - - /* We might have a suffix when disassembling with -Msuffix. */ - if (*p == 'i') - --p; - - /* Remove "addr16/addr32" if we aren't in Intel mode. */ - if (!intel_syntax - && (prefixes & PREFIX_ADDR) - && olen >= (4 + 7) - && *(p - 1) == ' ' - && strncmp (p - 7, "addr", 4) == 0 - && (strncmp (p - 3, "16", 2) == 0 - || strncmp (p - 3, "32", 2) == 0)) - p -= 7; - - if (modrm.rm) - { - /* mwait %eax,%ecx */ - strcpy (p, "mwait"); - if (!intel_syntax) - strcpy (op_out[0], names[0]); - } - else - { - /* monitor %eax,%ecx,%edx" */ - strcpy (p, "monitor"); - if (!intel_syntax) - { - const char * const *op1_names; - if (!(prefixes & PREFIX_ADDR)) - op1_names = (address_mode == mode_16bit - ? names16 : names); - else - { - op1_names = (address_mode != mode_32bit - ? names32 : names16); - used_prefixes |= PREFIX_ADDR; - } - strcpy (op_out[0], op1_names[0]); - strcpy (op_out[2], names[2]); - } - } - if (!intel_syntax) - { - strcpy (op_out[1], names[1]); - two_source_ops = 1; - } - - codep++; - } - else - OP_M (0, sizeflag); -} - -static void -SVME_Fixup (int bytemode, int sizeflag) -{ - const char *alt; - char *p; - - switch (*codep) - { - case 0xd8: - alt = "vmrun"; - break; - case 0xd9: - alt = "vmmcall"; - break; - case 0xda: - alt = "vmload"; - break; - case 0xdb: - alt = "vmsave"; - break; - case 0xdc: - alt = "stgi"; - break; - case 0xdd: - alt = "clgi"; - break; - case 0xde: - alt = "skinit"; - break; - case 0xdf: - alt = "invlpga"; - break; - default: - OP_M (bytemode, sizeflag); - return; - } - /* Override "lidt". */ - p = obuf + strlen (obuf) - 4; - /* We might have a suffix. */ - if (*p == 'i') - --p; - strcpy (p, alt); - if (!(prefixes & PREFIX_ADDR)) - { - ++codep; - return; - } - used_prefixes |= PREFIX_ADDR; - switch (*codep++) - { - case 0xdf: - strcpy (op_out[1], names32[1]); - two_source_ops = 1; - /* Fall through. */ - case 0xd8: - case 0xda: - case 0xdb: - *obufp++ = open_char; - if (address_mode == mode_64bit || (sizeflag & AFLAG)) - alt = names32[0]; - else - alt = names16[0]; - strcpy (obufp, alt); - obufp += strlen (alt); - *obufp++ = close_char; - *obufp = '\0'; - break; - } -} - -static void -INVLPG_Fixup (int bytemode, int sizeflag) -{ - const char *alt; - - switch (*codep) - { - case 0xf8: - alt = "swapgs"; - break; - case 0xf9: - alt = "rdtscp"; - break; - default: - OP_M (bytemode, sizeflag); - return; - } - /* Override "invlpg". */ - strcpy (obuf + strlen (obuf) - 6, alt); - codep++; -} - -static void -BadOp (void) -{ - /* Throw away prefixes and 1st. opcode byte. */ - codep = insn_codep + 1; - oappend ("(bad)"); -} - -static void -VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) -{ - if (modrm.mod == 3 - && modrm.reg == 0 - && modrm.rm >=1 - && modrm.rm <= 4) - { - /* Override "sgdt". */ - char *p = obuf + strlen (obuf) - 4; - - /* We might have a suffix when disassembling with -Msuffix. */ - if (*p == 'g') - --p; - - switch (modrm.rm) - { - case 1: - strcpy (p, "vmcall"); - break; - case 2: - strcpy (p, "vmlaunch"); - break; - case 3: - strcpy (p, "vmresume"); - break; - case 4: - strcpy (p, "vmxoff"); - break; - } - - codep++; - } - else - OP_E (0, sizeflag); -} - -static void -OP_VMX (int bytemode, int sizeflag) -{ - used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ)); - if (prefixes & PREFIX_DATA) - strcpy (obuf, "vmclear"); - else if (prefixes & PREFIX_REPZ) - strcpy (obuf, "vmxon"); - else - strcpy (obuf, "vmptrld"); - OP_E (bytemode, sizeflag); -} - -static void -REP_Fixup (int bytemode, int sizeflag) -{ - /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs, - lods and stos. */ - size_t ilen = 0; - - if (prefixes & PREFIX_REPZ) - switch (*insn_codep) - { - case 0x6e: /* outsb */ - case 0x6f: /* outsw/outsl */ - case 0xa4: /* movsb */ - case 0xa5: /* movsw/movsl/movsq */ - if (!intel_syntax) - ilen = 5; - else - ilen = 4; - break; - case 0xaa: /* stosb */ - case 0xab: /* stosw/stosl/stosq */ - case 0xac: /* lodsb */ - case 0xad: /* lodsw/lodsl/lodsq */ - if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS)) - ilen = 5; - else - ilen = 4; - break; - case 0x6c: /* insb */ - case 0x6d: /* insl/insw */ - if (!intel_syntax) - ilen = 4; - else - ilen = 3; - break; - default: - abort (); - break; - } - - if (ilen != 0) - { - size_t olen; - char *p; - - olen = strlen (obuf); - p = obuf + olen - ilen - 1 - 4; - /* Handle "repz [addr16|addr32]". */ - if ((prefixes & PREFIX_ADDR)) - p -= 1 + 6; - - memmove (p + 3, p + 4, olen - (p + 3 - obuf)); - } - - switch (bytemode) - { - case al_reg: - case eAX_reg: - case indir_dx_reg: - OP_IMREG (bytemode, sizeflag); - break; - case eDI_reg: - OP_ESreg (bytemode, sizeflag); - break; - case eSI_reg: - OP_DSreg (bytemode, sizeflag); - break; - default: - abort (); - break; - } -} - -static void -CMPXCHG8B_Fixup (int bytemode, int sizeflag) -{ - USED_REX (REX_W); - if (rex & REX_W) - { - /* Change cmpxchg8b to cmpxchg16b. */ - char *p = obuf + strlen (obuf) - 2; - strcpy (p, "16b"); - bytemode = o_mode; - } - OP_M (bytemode, sizeflag); -} - -static void -XMM_Fixup (int reg, int sizeflag ATTRIBUTE_UNUSED) -{ - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg); - oappend (scratchbuf + intel_syntax); -} - -static void -CRC32_Fixup (int bytemode, int sizeflag) -{ - /* Add proper suffix to "crc32". */ - char *p = obuf + strlen (obuf); - - switch (bytemode) - { - case b_mode: - if (intel_syntax) - break; - - *p++ = 'b'; - break; - case v_mode: - if (intel_syntax) - break; - - USED_REX (REX_W); - if (rex & REX_W) - *p++ = 'q'; - else if (sizeflag & DFLAG) - *p++ = 'l'; - else - *p++ = 'w'; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } - *p = '\0'; - - if (modrm.mod == 3) - { - int add; - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - - USED_REX (REX_B); - add = (rex & REX_B) ? 8 : 0; - if (bytemode == b_mode) - { - USED_REX (0); - if (rex) - oappend (names8rex[modrm.rm + add]); - else - oappend (names8[modrm.rm + add]); - } - else - { - USED_REX (REX_W); - if (rex & REX_W) - oappend (names64[modrm.rm + add]); - else if ((prefixes & PREFIX_DATA)) - oappend (names16[modrm.rm + add]); - else - oappend (names32[modrm.rm + add]); - } - } - else - OP_E (bytemode, sizeflag); -} diff --git a/disas/libvixl/LICENCE b/disas/libvixl/LICENCE deleted file mode 100644 index b7e160a3f580..000000000000 --- a/disas/libvixl/LICENCE +++ /dev/null @@ -1,30 +0,0 @@ -LICENCE -======= - -The software in this repository is covered by the following licence. - -// Copyright 2013, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/disas/libvixl/README b/disas/libvixl/README deleted file mode 100644 index 932a41adf7ff..000000000000 --- a/disas/libvixl/README +++ /dev/null @@ -1,11 +0,0 @@ - -The code in this directory is a subset of libvixl: - https://github.com/armvixl/vixl -(specifically, it is the set of files needed for disassembly only, -taken from libvixl 1.12). -Bugfixes should preferably be sent upstream initially. - -The disassembler does not currently support the entire A64 instruction -set. Notably: - * Limited support for system instructions. - * A few miscellaneous integer and floating point instructions are missing. diff --git a/disas/libvixl/meson.build b/disas/libvixl/meson.build deleted file mode 100644 index 5e2eb33e8ef5..000000000000 --- a/disas/libvixl/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -libvixl_ss.add(files( - 'vixl/a64/decoder-a64.cc', - 'vixl/a64/disasm-a64.cc', - 'vixl/a64/instructions-a64.cc', - 'vixl/compiler-intrinsics.cc', - 'vixl/utils.cc', -)) diff --git a/disas/libvixl/vixl/a64/assembler-a64.h b/disas/libvixl/vixl/a64/assembler-a64.h deleted file mode 100644 index fda5ccc6c75a..000000000000 --- a/disas/libvixl/vixl/a64/assembler-a64.h +++ /dev/null @@ -1,4624 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_A64_ASSEMBLER_A64_H_ -#define VIXL_A64_ASSEMBLER_A64_H_ - - -#include "vixl/globals.h" -#include "vixl/invalset.h" -#include "vixl/utils.h" -#include "vixl/code-buffer.h" -#include "vixl/a64/instructions-a64.h" - -namespace vixl { - -typedef uint64_t RegList; -static const int kRegListSizeInBits = sizeof(RegList) * 8; - - -// Registers. - -// Some CPURegister methods can return Register or VRegister types, so we need -// to declare them in advance. -class Register; -class VRegister; - -class CPURegister { - public: - enum RegisterType { - // The kInvalid value is used to detect uninitialized static instances, - // which are always zero-initialized before any constructors are called. - kInvalid = 0, - kRegister, - kVRegister, - kFPRegister = kVRegister, - kNoRegister - }; - - CPURegister() : code_(0), size_(0), type_(kNoRegister) { - VIXL_ASSERT(!IsValid()); - VIXL_ASSERT(IsNone()); - } - - CPURegister(unsigned code, unsigned size, RegisterType type) - : code_(code), size_(size), type_(type) { - VIXL_ASSERT(IsValidOrNone()); - } - - unsigned code() const { - VIXL_ASSERT(IsValid()); - return code_; - } - - RegisterType type() const { - VIXL_ASSERT(IsValidOrNone()); - return type_; - } - - RegList Bit() const { - VIXL_ASSERT(code_ < (sizeof(RegList) * 8)); - return IsValid() ? (static_cast(1) << code_) : 0; - } - - unsigned size() const { - VIXL_ASSERT(IsValid()); - return size_; - } - - int SizeInBytes() const { - VIXL_ASSERT(IsValid()); - VIXL_ASSERT(size() % 8 == 0); - return size_ / 8; - } - - int SizeInBits() const { - VIXL_ASSERT(IsValid()); - return size_; - } - - bool Is8Bits() const { - VIXL_ASSERT(IsValid()); - return size_ == 8; - } - - bool Is16Bits() const { - VIXL_ASSERT(IsValid()); - return size_ == 16; - } - - bool Is32Bits() const { - VIXL_ASSERT(IsValid()); - return size_ == 32; - } - - bool Is64Bits() const { - VIXL_ASSERT(IsValid()); - return size_ == 64; - } - - bool Is128Bits() const { - VIXL_ASSERT(IsValid()); - return size_ == 128; - } - - bool IsValid() const { - if (IsValidRegister() || IsValidVRegister()) { - VIXL_ASSERT(!IsNone()); - return true; - } else { - // This assert is hit when the register has not been properly initialized. - // One cause for this can be an initialisation order fiasco. See - // https://isocpp.org/wiki/faq/ctors#static-init-order for some details. - VIXL_ASSERT(IsNone()); - return false; - } - } - - bool IsValidRegister() const { - return IsRegister() && - ((size_ == kWRegSize) || (size_ == kXRegSize)) && - ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)); - } - - bool IsValidVRegister() const { - return IsVRegister() && - ((size_ == kBRegSize) || (size_ == kHRegSize) || - (size_ == kSRegSize) || (size_ == kDRegSize) || - (size_ == kQRegSize)) && - (code_ < kNumberOfVRegisters); - } - - bool IsValidFPRegister() const { - return IsFPRegister() && (code_ < kNumberOfVRegisters); - } - - bool IsNone() const { - // kNoRegister types should always have size 0 and code 0. - VIXL_ASSERT((type_ != kNoRegister) || (code_ == 0)); - VIXL_ASSERT((type_ != kNoRegister) || (size_ == 0)); - - return type_ == kNoRegister; - } - - bool Aliases(const CPURegister& other) const { - VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); - return (code_ == other.code_) && (type_ == other.type_); - } - - bool Is(const CPURegister& other) const { - VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); - return Aliases(other) && (size_ == other.size_); - } - - bool IsZero() const { - VIXL_ASSERT(IsValid()); - return IsRegister() && (code_ == kZeroRegCode); - } - - bool IsSP() const { - VIXL_ASSERT(IsValid()); - return IsRegister() && (code_ == kSPRegInternalCode); - } - - bool IsRegister() const { - return type_ == kRegister; - } - - bool IsVRegister() const { - return type_ == kVRegister; - } - - bool IsFPRegister() const { - return IsS() || IsD(); - } - - bool IsW() const { return IsValidRegister() && Is32Bits(); } - bool IsX() const { return IsValidRegister() && Is64Bits(); } - - // These assertions ensure that the size and type of the register are as - // described. They do not consider the number of lanes that make up a vector. - // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() - // does not imply Is1D() or Is8B(). - // Check the number of lanes, ie. the format of the vector, using methods such - // as Is8B(), Is1D(), etc. in the VRegister class. - bool IsV() const { return IsVRegister(); } - bool IsB() const { return IsV() && Is8Bits(); } - bool IsH() const { return IsV() && Is16Bits(); } - bool IsS() const { return IsV() && Is32Bits(); } - bool IsD() const { return IsV() && Is64Bits(); } - bool IsQ() const { return IsV() && Is128Bits(); } - - const Register& W() const; - const Register& X() const; - const VRegister& V() const; - const VRegister& B() const; - const VRegister& H() const; - const VRegister& S() const; - const VRegister& D() const; - const VRegister& Q() const; - - bool IsSameSizeAndType(const CPURegister& other) const { - return (size_ == other.size_) && (type_ == other.type_); - } - - protected: - unsigned code_; - unsigned size_; - RegisterType type_; - - private: - bool IsValidOrNone() const { - return IsValid() || IsNone(); - } -}; - - -class Register : public CPURegister { - public: - Register() : CPURegister() {} - explicit Register(const CPURegister& other) - : CPURegister(other.code(), other.size(), other.type()) { - VIXL_ASSERT(IsValidRegister()); - } - Register(unsigned code, unsigned size) - : CPURegister(code, size, kRegister) {} - - bool IsValid() const { - VIXL_ASSERT(IsRegister() || IsNone()); - return IsValidRegister(); - } - - static const Register& WRegFromCode(unsigned code); - static const Register& XRegFromCode(unsigned code); - - private: - static const Register wregisters[]; - static const Register xregisters[]; -}; - - -class VRegister : public CPURegister { - public: - VRegister() : CPURegister(), lanes_(1) {} - explicit VRegister(const CPURegister& other) - : CPURegister(other.code(), other.size(), other.type()), lanes_(1) { - VIXL_ASSERT(IsValidVRegister()); - VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); - } - VRegister(unsigned code, unsigned size, unsigned lanes = 1) - : CPURegister(code, size, kVRegister), lanes_(lanes) { - VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); - } - VRegister(unsigned code, VectorFormat format) - : CPURegister(code, RegisterSizeInBitsFromFormat(format), kVRegister), - lanes_(IsVectorFormat(format) ? LaneCountFromFormat(format) : 1) { - VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); - } - - bool IsValid() const { - VIXL_ASSERT(IsVRegister() || IsNone()); - return IsValidVRegister(); - } - - static const VRegister& BRegFromCode(unsigned code); - static const VRegister& HRegFromCode(unsigned code); - static const VRegister& SRegFromCode(unsigned code); - static const VRegister& DRegFromCode(unsigned code); - static const VRegister& QRegFromCode(unsigned code); - static const VRegister& VRegFromCode(unsigned code); - - VRegister V8B() const { return VRegister(code_, kDRegSize, 8); } - VRegister V16B() const { return VRegister(code_, kQRegSize, 16); } - VRegister V4H() const { return VRegister(code_, kDRegSize, 4); } - VRegister V8H() const { return VRegister(code_, kQRegSize, 8); } - VRegister V2S() const { return VRegister(code_, kDRegSize, 2); } - VRegister V4S() const { return VRegister(code_, kQRegSize, 4); } - VRegister V2D() const { return VRegister(code_, kQRegSize, 2); } - VRegister V1D() const { return VRegister(code_, kDRegSize, 1); } - - bool Is8B() const { return (Is64Bits() && (lanes_ == 8)); } - bool Is16B() const { return (Is128Bits() && (lanes_ == 16)); } - bool Is4H() const { return (Is64Bits() && (lanes_ == 4)); } - bool Is8H() const { return (Is128Bits() && (lanes_ == 8)); } - bool Is2S() const { return (Is64Bits() && (lanes_ == 2)); } - bool Is4S() const { return (Is128Bits() && (lanes_ == 4)); } - bool Is1D() const { return (Is64Bits() && (lanes_ == 1)); } - bool Is2D() const { return (Is128Bits() && (lanes_ == 2)); } - - // For consistency, we assert the number of lanes of these scalar registers, - // even though there are no vectors of equivalent total size with which they - // could alias. - bool Is1B() const { - VIXL_ASSERT(!(Is8Bits() && IsVector())); - return Is8Bits(); - } - bool Is1H() const { - VIXL_ASSERT(!(Is16Bits() && IsVector())); - return Is16Bits(); - } - bool Is1S() const { - VIXL_ASSERT(!(Is32Bits() && IsVector())); - return Is32Bits(); - } - - bool IsLaneSizeB() const { return LaneSizeInBits() == kBRegSize; } - bool IsLaneSizeH() const { return LaneSizeInBits() == kHRegSize; } - bool IsLaneSizeS() const { return LaneSizeInBits() == kSRegSize; } - bool IsLaneSizeD() const { return LaneSizeInBits() == kDRegSize; } - - int lanes() const { - return lanes_; - } - - bool IsScalar() const { - return lanes_ == 1; - } - - bool IsVector() const { - return lanes_ > 1; - } - - bool IsSameFormat(const VRegister& other) const { - return (size_ == other.size_) && (lanes_ == other.lanes_); - } - - unsigned LaneSizeInBytes() const { - return SizeInBytes() / lanes_; - } - - unsigned LaneSizeInBits() const { - return LaneSizeInBytes() * 8; - } - - private: - static const VRegister bregisters[]; - static const VRegister hregisters[]; - static const VRegister sregisters[]; - static const VRegister dregisters[]; - static const VRegister qregisters[]; - static const VRegister vregisters[]; - int lanes_; -}; - - -// Backward compatibility for FPRegisters. -typedef VRegister FPRegister; - -// No*Reg is used to indicate an unused argument, or an error case. Note that -// these all compare equal (using the Is() method). The Register and VRegister -// variants are provided for convenience. -const Register NoReg; -const VRegister NoVReg; -const FPRegister NoFPReg; // For backward compatibility. -const CPURegister NoCPUReg; - - -#define DEFINE_REGISTERS(N) \ -const Register w##N(N, kWRegSize); \ -const Register x##N(N, kXRegSize); -REGISTER_CODE_LIST(DEFINE_REGISTERS) -#undef DEFINE_REGISTERS -const Register wsp(kSPRegInternalCode, kWRegSize); -const Register sp(kSPRegInternalCode, kXRegSize); - - -#define DEFINE_VREGISTERS(N) \ -const VRegister b##N(N, kBRegSize); \ -const VRegister h##N(N, kHRegSize); \ -const VRegister s##N(N, kSRegSize); \ -const VRegister d##N(N, kDRegSize); \ -const VRegister q##N(N, kQRegSize); \ -const VRegister v##N(N, kQRegSize); -REGISTER_CODE_LIST(DEFINE_VREGISTERS) -#undef DEFINE_VREGISTERS - - -// Registers aliases. -const Register ip0 = x16; -const Register ip1 = x17; -const Register lr = x30; -const Register xzr = x31; -const Register wzr = w31; - - -// AreAliased returns true if any of the named registers overlap. Arguments -// set to NoReg are ignored. The system stack pointer may be specified. -bool AreAliased(const CPURegister& reg1, - const CPURegister& reg2, - const CPURegister& reg3 = NoReg, - const CPURegister& reg4 = NoReg, - const CPURegister& reg5 = NoReg, - const CPURegister& reg6 = NoReg, - const CPURegister& reg7 = NoReg, - const CPURegister& reg8 = NoReg); - - -// AreSameSizeAndType returns true if all of the specified registers have the -// same size, and are of the same type. The system stack pointer may be -// specified. Arguments set to NoReg are ignored, as are any subsequent -// arguments. At least one argument (reg1) must be valid (not NoCPUReg). -bool AreSameSizeAndType(const CPURegister& reg1, - const CPURegister& reg2, - const CPURegister& reg3 = NoCPUReg, - const CPURegister& reg4 = NoCPUReg, - const CPURegister& reg5 = NoCPUReg, - const CPURegister& reg6 = NoCPUReg, - const CPURegister& reg7 = NoCPUReg, - const CPURegister& reg8 = NoCPUReg); - - -// AreSameFormat returns true if all of the specified VRegisters have the same -// vector format. Arguments set to NoReg are ignored, as are any subsequent -// arguments. At least one argument (reg1) must be valid (not NoVReg). -bool AreSameFormat(const VRegister& reg1, - const VRegister& reg2, - const VRegister& reg3 = NoVReg, - const VRegister& reg4 = NoVReg); - - -// AreConsecutive returns true if all of the specified VRegisters are -// consecutive in the register file. Arguments set to NoReg are ignored, as are -// any subsequent arguments. At least one argument (reg1) must be valid -// (not NoVReg). -bool AreConsecutive(const VRegister& reg1, - const VRegister& reg2, - const VRegister& reg3 = NoVReg, - const VRegister& reg4 = NoVReg); - - -// Lists of registers. -class CPURegList { - public: - explicit CPURegList(CPURegister reg1, - CPURegister reg2 = NoCPUReg, - CPURegister reg3 = NoCPUReg, - CPURegister reg4 = NoCPUReg) - : list_(reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit()), - size_(reg1.size()), type_(reg1.type()) { - VIXL_ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4)); - VIXL_ASSERT(IsValid()); - } - - CPURegList(CPURegister::RegisterType type, unsigned size, RegList list) - : list_(list), size_(size), type_(type) { - VIXL_ASSERT(IsValid()); - } - - CPURegList(CPURegister::RegisterType type, unsigned size, - unsigned first_reg, unsigned last_reg) - : size_(size), type_(type) { - VIXL_ASSERT(((type == CPURegister::kRegister) && - (last_reg < kNumberOfRegisters)) || - ((type == CPURegister::kVRegister) && - (last_reg < kNumberOfVRegisters))); - VIXL_ASSERT(last_reg >= first_reg); - list_ = (UINT64_C(1) << (last_reg + 1)) - 1; - list_ &= ~((UINT64_C(1) << first_reg) - 1); - VIXL_ASSERT(IsValid()); - } - - CPURegister::RegisterType type() const { - VIXL_ASSERT(IsValid()); - return type_; - } - - // Combine another CPURegList into this one. Registers that already exist in - // this list are left unchanged. The type and size of the registers in the - // 'other' list must match those in this list. - void Combine(const CPURegList& other) { - VIXL_ASSERT(IsValid()); - VIXL_ASSERT(other.type() == type_); - VIXL_ASSERT(other.RegisterSizeInBits() == size_); - list_ |= other.list(); - } - - // Remove every register in the other CPURegList from this one. Registers that - // do not exist in this list are ignored. The type and size of the registers - // in the 'other' list must match those in this list. - void Remove(const CPURegList& other) { - VIXL_ASSERT(IsValid()); - VIXL_ASSERT(other.type() == type_); - VIXL_ASSERT(other.RegisterSizeInBits() == size_); - list_ &= ~other.list(); - } - - // Variants of Combine and Remove which take a single register. - void Combine(const CPURegister& other) { - VIXL_ASSERT(other.type() == type_); - VIXL_ASSERT(other.size() == size_); - Combine(other.code()); - } - - void Remove(const CPURegister& other) { - VIXL_ASSERT(other.type() == type_); - VIXL_ASSERT(other.size() == size_); - Remove(other.code()); - } - - // Variants of Combine and Remove which take a single register by its code; - // the type and size of the register is inferred from this list. - void Combine(int code) { - VIXL_ASSERT(IsValid()); - VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); - list_ |= (UINT64_C(1) << code); - } - - void Remove(int code) { - VIXL_ASSERT(IsValid()); - VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); - list_ &= ~(UINT64_C(1) << code); - } - - static CPURegList Union(const CPURegList& list_1, const CPURegList& list_2) { - VIXL_ASSERT(list_1.type_ == list_2.type_); - VIXL_ASSERT(list_1.size_ == list_2.size_); - return CPURegList(list_1.type_, list_1.size_, list_1.list_ | list_2.list_); - } - static CPURegList Union(const CPURegList& list_1, - const CPURegList& list_2, - const CPURegList& list_3); - static CPURegList Union(const CPURegList& list_1, - const CPURegList& list_2, - const CPURegList& list_3, - const CPURegList& list_4); - - static CPURegList Intersection(const CPURegList& list_1, - const CPURegList& list_2) { - VIXL_ASSERT(list_1.type_ == list_2.type_); - VIXL_ASSERT(list_1.size_ == list_2.size_); - return CPURegList(list_1.type_, list_1.size_, list_1.list_ & list_2.list_); - } - static CPURegList Intersection(const CPURegList& list_1, - const CPURegList& list_2, - const CPURegList& list_3); - static CPURegList Intersection(const CPURegList& list_1, - const CPURegList& list_2, - const CPURegList& list_3, - const CPURegList& list_4); - - bool Overlaps(const CPURegList& other) const { - return (type_ == other.type_) && ((list_ & other.list_) != 0); - } - - RegList list() const { - VIXL_ASSERT(IsValid()); - return list_; - } - - void set_list(RegList new_list) { - VIXL_ASSERT(IsValid()); - list_ = new_list; - } - - // Remove all callee-saved registers from the list. This can be useful when - // preparing registers for an AAPCS64 function call, for example. - void RemoveCalleeSaved(); - - CPURegister PopLowestIndex(); - CPURegister PopHighestIndex(); - - // AAPCS64 callee-saved registers. - static CPURegList GetCalleeSaved(unsigned size = kXRegSize); - static CPURegList GetCalleeSavedV(unsigned size = kDRegSize); - - // AAPCS64 caller-saved registers. Note that this includes lr. - // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top - // 64-bits being caller-saved. - static CPURegList GetCallerSaved(unsigned size = kXRegSize); - static CPURegList GetCallerSavedV(unsigned size = kDRegSize); - - bool IsEmpty() const { - VIXL_ASSERT(IsValid()); - return list_ == 0; - } - - bool IncludesAliasOf(const CPURegister& other) const { - VIXL_ASSERT(IsValid()); - return (type_ == other.type()) && ((other.Bit() & list_) != 0); - } - - bool IncludesAliasOf(int code) const { - VIXL_ASSERT(IsValid()); - return ((code & list_) != 0); - } - - int Count() const { - VIXL_ASSERT(IsValid()); - return CountSetBits(list_); - } - - unsigned RegisterSizeInBits() const { - VIXL_ASSERT(IsValid()); - return size_; - } - - unsigned RegisterSizeInBytes() const { - int size_in_bits = RegisterSizeInBits(); - VIXL_ASSERT((size_in_bits % 8) == 0); - return size_in_bits / 8; - } - - unsigned TotalSizeInBytes() const { - VIXL_ASSERT(IsValid()); - return RegisterSizeInBytes() * Count(); - } - - private: - RegList list_; - unsigned size_; - CPURegister::RegisterType type_; - - bool IsValid() const; -}; - - -// AAPCS64 callee-saved registers. -extern const CPURegList kCalleeSaved; -extern const CPURegList kCalleeSavedV; - - -// AAPCS64 caller-saved registers. Note that this includes lr. -extern const CPURegList kCallerSaved; -extern const CPURegList kCallerSavedV; - - -// Operand. -class Operand { - public: - // # - // where is int64_t. - // This is allowed to be an implicit constructor because Operand is - // a wrapper class that doesn't normally perform any type conversion. - Operand(int64_t immediate = 0); // NOLINT(runtime/explicit) - - // rm, { #} - // where is one of {LSL, LSR, ASR, ROR}. - // is uint6_t. - // This is allowed to be an implicit constructor because Operand is - // a wrapper class that doesn't normally perform any type conversion. - Operand(Register reg, - Shift shift = LSL, - unsigned shift_amount = 0); // NOLINT(runtime/explicit) - - // rm, { {#}} - // where is one of {UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX}. - // is uint2_t. - explicit Operand(Register reg, Extend extend, unsigned shift_amount = 0); - - bool IsImmediate() const; - bool IsShiftedRegister() const; - bool IsExtendedRegister() const; - bool IsZero() const; - - // This returns an LSL shift (<= 4) operand as an equivalent extend operand, - // which helps in the encoding of instructions that use the stack pointer. - Operand ToExtendedRegister() const; - - int64_t immediate() const { - VIXL_ASSERT(IsImmediate()); - return immediate_; - } - - Register reg() const { - VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister()); - return reg_; - } - - Shift shift() const { - VIXL_ASSERT(IsShiftedRegister()); - return shift_; - } - - Extend extend() const { - VIXL_ASSERT(IsExtendedRegister()); - return extend_; - } - - unsigned shift_amount() const { - VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister()); - return shift_amount_; - } - - private: - int64_t immediate_; - Register reg_; - Shift shift_; - Extend extend_; - unsigned shift_amount_; -}; - - -// MemOperand represents the addressing mode of a load or store instruction. -class MemOperand { - public: - explicit MemOperand(Register base, - int64_t offset = 0, - AddrMode addrmode = Offset); - MemOperand(Register base, - Register regoffset, - Shift shift = LSL, - unsigned shift_amount = 0); - MemOperand(Register base, - Register regoffset, - Extend extend, - unsigned shift_amount = 0); - MemOperand(Register base, - const Operand& offset, - AddrMode addrmode = Offset); - - const Register& base() const { return base_; } - const Register& regoffset() const { return regoffset_; } - int64_t offset() const { return offset_; } - AddrMode addrmode() const { return addrmode_; } - Shift shift() const { return shift_; } - Extend extend() const { return extend_; } - unsigned shift_amount() const { return shift_amount_; } - bool IsImmediateOffset() const; - bool IsRegisterOffset() const; - bool IsPreIndex() const; - bool IsPostIndex() const; - - void AddOffset(int64_t offset); - - private: - Register base_; - Register regoffset_; - int64_t offset_; - AddrMode addrmode_; - Shift shift_; - Extend extend_; - unsigned shift_amount_; -}; - - -class LabelTestHelper; // Forward declaration. - - -class Label { - public: - Label() : location_(kLocationUnbound) {} - ~Label() { - // If the label has been linked to, it needs to be bound to a target. - VIXL_ASSERT(!IsLinked() || IsBound()); - } - - bool IsBound() const { return location_ >= 0; } - bool IsLinked() const { return !links_.empty(); } - - ptrdiff_t location() const { return location_; } - - static const int kNPreallocatedLinks = 4; - static const ptrdiff_t kInvalidLinkKey = PTRDIFF_MAX; - static const size_t kReclaimFrom = 512; - static const size_t kReclaimFactor = 2; - - typedef InvalSet LinksSetBase; - typedef InvalSetIterator LabelLinksIteratorBase; - - private: - class LinksSet : public LinksSetBase { - public: - LinksSet() : LinksSetBase() {} - }; - - // Allows iterating over the links of a label. The behaviour is undefined if - // the list of links is modified in any way while iterating. - class LabelLinksIterator : public LabelLinksIteratorBase { - public: - explicit LabelLinksIterator(Label* label) - : LabelLinksIteratorBase(&label->links_) {} - }; - - void Bind(ptrdiff_t location) { - // Labels can only be bound once. - VIXL_ASSERT(!IsBound()); - location_ = location; - } - - void AddLink(ptrdiff_t instruction) { - // If a label is bound, the assembler already has the information it needs - // to write the instruction, so there is no need to add it to links_. - VIXL_ASSERT(!IsBound()); - links_.insert(instruction); - } - - void DeleteLink(ptrdiff_t instruction) { - links_.erase(instruction); - } - - void ClearAllLinks() { - links_.clear(); - } - - // TODO: The comment below considers average case complexity for our - // usual use-cases. The elements of interest are: - // - Branches to a label are emitted in order: branch instructions to a label - // are generated at an offset in the code generation buffer greater than any - // other branch to that same label already generated. As an example, this can - // be broken when an instruction is patched to become a branch. Note that the - // code will still work, but the complexity considerations below may locally - // not apply any more. - // - Veneers are generated in order: for multiple branches of the same type - // branching to the same unbound label going out of range, veneers are - // generated in growing order of the branch instruction offset from the start - // of the buffer. - // - // When creating a veneer for a branch going out of range, the link for this - // branch needs to be removed from this `links_`. Since all branches are - // tracked in one underlying InvalSet, the complexity for this deletion is the - // same as for finding the element, ie. O(n), where n is the number of links - // in the set. - // This could be reduced to O(1) by using the same trick as used when tracking - // branch information for veneers: split the container to use one set per type - // of branch. With that setup, when a veneer is created and the link needs to - // be deleted, if the two points above hold, it must be the minimum element of - // the set for its type of branch, and that minimum element will be accessible - // in O(1). - - // The offsets of the instructions that have linked to this label. - LinksSet links_; - // The label location. - ptrdiff_t location_; - - static const ptrdiff_t kLocationUnbound = -1; - - // It is not safe to copy labels, so disable the copy constructor and operator - // by declaring them private (without an implementation). - Label(const Label&); - void operator=(const Label&); - - // The Assembler class is responsible for binding and linking labels, since - // the stored offsets need to be consistent with the Assembler's buffer. - friend class Assembler; - // The MacroAssembler and VeneerPool handle resolution of branches to distant - // targets. - friend class MacroAssembler; - friend class VeneerPool; -}; - - -// Required InvalSet template specialisations. -#define INVAL_SET_TEMPLATE_PARAMETERS \ - ptrdiff_t, \ - Label::kNPreallocatedLinks, \ - ptrdiff_t, \ - Label::kInvalidLinkKey, \ - Label::kReclaimFrom, \ - Label::kReclaimFactor -template<> -inline ptrdiff_t InvalSet::Key( - const ptrdiff_t& element) { - return element; -} -template<> -inline void InvalSet::SetKey( - ptrdiff_t* element, ptrdiff_t key) { - *element = key; -} -#undef INVAL_SET_TEMPLATE_PARAMETERS - - -class Assembler; -class LiteralPool; - -// A literal is a 32-bit or 64-bit piece of data stored in the instruction -// stream and loaded through a pc relative load. The same literal can be -// referred to by multiple instructions but a literal can only reside at one -// place in memory. A literal can be used by a load before or after being -// placed in memory. -// -// Internally an offset of 0 is associated with a literal which has been -// neither used nor placed. Then two possibilities arise: -// 1) the label is placed, the offset (stored as offset + 1) is used to -// resolve any subsequent load using the label. -// 2) the label is not placed and offset is the offset of the last load using -// the literal (stored as -offset -1). If multiple loads refer to this -// literal then the last load holds the offset of the preceding load and -// all loads form a chain. Once the offset is placed all the loads in the -// chain are resolved and future loads fall back to possibility 1. -class RawLiteral { - public: - enum DeletionPolicy { - kDeletedOnPlacementByPool, - kDeletedOnPoolDestruction, - kManuallyDeleted - }; - - RawLiteral(size_t size, - LiteralPool* literal_pool, - DeletionPolicy deletion_policy = kManuallyDeleted); - - // The literal pool only sees and deletes `RawLiteral*` pointers, but they are - // actually pointing to `Literal` objects. - virtual ~RawLiteral() {} - - size_t size() { - VIXL_STATIC_ASSERT(kDRegSizeInBytes == kXRegSizeInBytes); - VIXL_STATIC_ASSERT(kSRegSizeInBytes == kWRegSizeInBytes); - VIXL_ASSERT((size_ == kXRegSizeInBytes) || - (size_ == kWRegSizeInBytes) || - (size_ == kQRegSizeInBytes)); - return size_; - } - uint64_t raw_value128_low64() { - VIXL_ASSERT(size_ == kQRegSizeInBytes); - return low64_; - } - uint64_t raw_value128_high64() { - VIXL_ASSERT(size_ == kQRegSizeInBytes); - return high64_; - } - uint64_t raw_value64() { - VIXL_ASSERT(size_ == kXRegSizeInBytes); - VIXL_ASSERT(high64_ == 0); - return low64_; - } - uint32_t raw_value32() { - VIXL_ASSERT(size_ == kWRegSizeInBytes); - VIXL_ASSERT(high64_ == 0); - VIXL_ASSERT(is_uint32(low64_) || is_int32(low64_)); - return static_cast(low64_); - } - bool IsUsed() { return offset_ < 0; } - bool IsPlaced() { return offset_ > 0; } - - LiteralPool* GetLiteralPool() const { - return literal_pool_; - } - - ptrdiff_t offset() { - VIXL_ASSERT(IsPlaced()); - return offset_ - 1; - } - - protected: - void set_offset(ptrdiff_t offset) { - VIXL_ASSERT(offset >= 0); - VIXL_ASSERT(IsWordAligned(offset)); - VIXL_ASSERT(!IsPlaced()); - offset_ = offset + 1; - } - ptrdiff_t last_use() { - VIXL_ASSERT(IsUsed()); - return -offset_ - 1; - } - void set_last_use(ptrdiff_t offset) { - VIXL_ASSERT(offset >= 0); - VIXL_ASSERT(IsWordAligned(offset)); - VIXL_ASSERT(!IsPlaced()); - offset_ = -offset - 1; - } - - size_t size_; - ptrdiff_t offset_; - uint64_t low64_; - uint64_t high64_; - - private: - LiteralPool* literal_pool_; - DeletionPolicy deletion_policy_; - - friend class Assembler; - friend class LiteralPool; -}; - - -template -class Literal : public RawLiteral { - public: - explicit Literal(T value, - LiteralPool* literal_pool = NULL, - RawLiteral::DeletionPolicy ownership = kManuallyDeleted) - : RawLiteral(sizeof(value), literal_pool, ownership) { - VIXL_STATIC_ASSERT(sizeof(value) <= kXRegSizeInBytes); - UpdateValue(value); - } - - Literal(T high64, T low64, - LiteralPool* literal_pool = NULL, - RawLiteral::DeletionPolicy ownership = kManuallyDeleted) - : RawLiteral(kQRegSizeInBytes, literal_pool, ownership) { - VIXL_STATIC_ASSERT(sizeof(low64) == (kQRegSizeInBytes / 2)); - UpdateValue(high64, low64); - } - - virtual ~Literal() {} - - // Update the value of this literal, if necessary by rewriting the value in - // the pool. - // If the literal has already been placed in a literal pool, the address of - // the start of the code buffer must be provided, as the literal only knows it - // offset from there. This also allows patching the value after the code has - // been moved in memory. - void UpdateValue(T new_value, uint8_t* code_buffer = NULL) { - VIXL_ASSERT(sizeof(new_value) == size_); - memcpy(&low64_, &new_value, sizeof(new_value)); - if (IsPlaced()) { - VIXL_ASSERT(code_buffer != NULL); - RewriteValueInCode(code_buffer); - } - } - - void UpdateValue(T high64, T low64, uint8_t* code_buffer = NULL) { - VIXL_ASSERT(sizeof(low64) == size_ / 2); - memcpy(&low64_, &low64, sizeof(low64)); - memcpy(&high64_, &high64, sizeof(high64)); - if (IsPlaced()) { - VIXL_ASSERT(code_buffer != NULL); - RewriteValueInCode(code_buffer); - } - } - - void UpdateValue(T new_value, const Assembler* assembler); - void UpdateValue(T high64, T low64, const Assembler* assembler); - - private: - void RewriteValueInCode(uint8_t* code_buffer) { - VIXL_ASSERT(IsPlaced()); - VIXL_STATIC_ASSERT(sizeof(T) <= kXRegSizeInBytes); - switch (size()) { - case kSRegSizeInBytes: - *reinterpret_cast(code_buffer + offset()) = raw_value32(); - break; - case kDRegSizeInBytes: - *reinterpret_cast(code_buffer + offset()) = raw_value64(); - break; - default: - VIXL_ASSERT(size() == kQRegSizeInBytes); - uint64_t* base_address = - reinterpret_cast(code_buffer + offset()); - *base_address = raw_value128_low64(); - *(base_address + 1) = raw_value128_high64(); - } - } -}; - - -// Control whether or not position-independent code should be emitted. -enum PositionIndependentCodeOption { - // All code generated will be position-independent; all branches and - // references to labels generated with the Label class will use PC-relative - // addressing. - PositionIndependentCode, - - // Allow VIXL to generate code that refers to absolute addresses. With this - // option, it will not be possible to copy the code buffer and run it from a - // different address; code must be generated in its final location. - PositionDependentCode, - - // Allow VIXL to assume that the bottom 12 bits of the address will be - // constant, but that the top 48 bits may change. This allows `adrp` to - // function in systems which copy code between pages, but otherwise maintain - // 4KB page alignment. - PageOffsetDependentCode -}; - - -// Control how scaled- and unscaled-offset loads and stores are generated. -enum LoadStoreScalingOption { - // Prefer scaled-immediate-offset instructions, but emit unscaled-offset, - // register-offset, pre-index or post-index instructions if necessary. - PreferScaledOffset, - - // Prefer unscaled-immediate-offset instructions, but emit scaled-offset, - // register-offset, pre-index or post-index instructions if necessary. - PreferUnscaledOffset, - - // Require scaled-immediate-offset instructions. - RequireScaledOffset, - - // Require unscaled-immediate-offset instructions. - RequireUnscaledOffset -}; - - -// Assembler. -class Assembler { - public: - Assembler(size_t capacity, - PositionIndependentCodeOption pic = PositionIndependentCode); - Assembler(byte* buffer, size_t capacity, - PositionIndependentCodeOption pic = PositionIndependentCode); - - // The destructor asserts that one of the following is true: - // * The Assembler object has not been used. - // * Nothing has been emitted since the last Reset() call. - // * Nothing has been emitted since the last FinalizeCode() call. - ~Assembler(); - - // System functions. - - // Start generating code from the beginning of the buffer, discarding any code - // and data that has already been emitted into the buffer. - void Reset(); - - // Finalize a code buffer of generated instructions. This function must be - // called before executing or copying code from the buffer. - void FinalizeCode(); - - // Label. - // Bind a label to the current PC. - void bind(Label* label); - - // Bind a label to a specified offset from the start of the buffer. - void BindToOffset(Label* label, ptrdiff_t offset); - - // Place a literal at the current PC. - void place(RawLiteral* literal); - - ptrdiff_t CursorOffset() const { - return buffer_->CursorOffset(); - } - - ptrdiff_t BufferEndOffset() const { - return static_cast(buffer_->capacity()); - } - - // Return the address of an offset in the buffer. - template - T GetOffsetAddress(ptrdiff_t offset) const { - VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); - return buffer_->GetOffsetAddress(offset); - } - - // Return the address of a bound label. - template - T GetLabelAddress(const Label * label) const { - VIXL_ASSERT(label->IsBound()); - VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); - return GetOffsetAddress(label->location()); - } - - // Return the address of the cursor. - template - T GetCursorAddress() const { - VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); - return GetOffsetAddress(CursorOffset()); - } - - // Return the address of the start of the buffer. - template - T GetStartAddress() const { - VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); - return GetOffsetAddress(0); - } - - Instruction* InstructionAt(ptrdiff_t instruction_offset) { - return GetOffsetAddress(instruction_offset); - } - - ptrdiff_t InstructionOffset(Instruction* instruction) { - VIXL_STATIC_ASSERT(sizeof(*instruction) == 1); - ptrdiff_t offset = instruction - GetStartAddress(); - VIXL_ASSERT((0 <= offset) && - (offset < static_cast(BufferCapacity()))); - return offset; - } - - // Instruction set functions. - - // Branch / Jump instructions. - // Branch to register. - void br(const Register& xn); - - // Branch with link to register. - void blr(const Register& xn); - - // Branch to register with return hint. - void ret(const Register& xn = lr); - - // Unconditional branch to label. - void b(Label* label); - - // Conditional branch to label. - void b(Label* label, Condition cond); - - // Unconditional branch to PC offset. - void b(int imm26); - - // Conditional branch to PC offset. - void b(int imm19, Condition cond); - - // Branch with link to label. - void bl(Label* label); - - // Branch with link to PC offset. - void bl(int imm26); - - // Compare and branch to label if zero. - void cbz(const Register& rt, Label* label); - - // Compare and branch to PC offset if zero. - void cbz(const Register& rt, int imm19); - - // Compare and branch to label if not zero. - void cbnz(const Register& rt, Label* label); - - // Compare and branch to PC offset if not zero. - void cbnz(const Register& rt, int imm19); - - // Table lookup from one register. - void tbl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Table lookup from two registers. - void tbl(const VRegister& vd, - const VRegister& vn, - const VRegister& vn2, - const VRegister& vm); - - // Table lookup from three registers. - void tbl(const VRegister& vd, - const VRegister& vn, - const VRegister& vn2, - const VRegister& vn3, - const VRegister& vm); - - // Table lookup from four registers. - void tbl(const VRegister& vd, - const VRegister& vn, - const VRegister& vn2, - const VRegister& vn3, - const VRegister& vn4, - const VRegister& vm); - - // Table lookup extension from one register. - void tbx(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Table lookup extension from two registers. - void tbx(const VRegister& vd, - const VRegister& vn, - const VRegister& vn2, - const VRegister& vm); - - // Table lookup extension from three registers. - void tbx(const VRegister& vd, - const VRegister& vn, - const VRegister& vn2, - const VRegister& vn3, - const VRegister& vm); - - // Table lookup extension from four registers. - void tbx(const VRegister& vd, - const VRegister& vn, - const VRegister& vn2, - const VRegister& vn3, - const VRegister& vn4, - const VRegister& vm); - - // Test bit and branch to label if zero. - void tbz(const Register& rt, unsigned bit_pos, Label* label); - - // Test bit and branch to PC offset if zero. - void tbz(const Register& rt, unsigned bit_pos, int imm14); - - // Test bit and branch to label if not zero. - void tbnz(const Register& rt, unsigned bit_pos, Label* label); - - // Test bit and branch to PC offset if not zero. - void tbnz(const Register& rt, unsigned bit_pos, int imm14); - - // Address calculation instructions. - // Calculate a PC-relative address. Unlike for branches the offset in adr is - // unscaled (i.e. the result can be unaligned). - - // Calculate the address of a label. - void adr(const Register& rd, Label* label); - - // Calculate the address of a PC offset. - void adr(const Register& rd, int imm21); - - // Calculate the page address of a label. - void adrp(const Register& rd, Label* label); - - // Calculate the page address of a PC offset. - void adrp(const Register& rd, int imm21); - - // Data Processing instructions. - // Add. - void add(const Register& rd, - const Register& rn, - const Operand& operand); - - // Add and update status flags. - void adds(const Register& rd, - const Register& rn, - const Operand& operand); - - // Compare negative. - void cmn(const Register& rn, const Operand& operand); - - // Subtract. - void sub(const Register& rd, - const Register& rn, - const Operand& operand); - - // Subtract and update status flags. - void subs(const Register& rd, - const Register& rn, - const Operand& operand); - - // Compare. - void cmp(const Register& rn, const Operand& operand); - - // Negate. - void neg(const Register& rd, - const Operand& operand); - - // Negate and update status flags. - void negs(const Register& rd, - const Operand& operand); - - // Add with carry bit. - void adc(const Register& rd, - const Register& rn, - const Operand& operand); - - // Add with carry bit and update status flags. - void adcs(const Register& rd, - const Register& rn, - const Operand& operand); - - // Subtract with carry bit. - void sbc(const Register& rd, - const Register& rn, - const Operand& operand); - - // Subtract with carry bit and update status flags. - void sbcs(const Register& rd, - const Register& rn, - const Operand& operand); - - // Negate with carry bit. - void ngc(const Register& rd, - const Operand& operand); - - // Negate with carry bit and update status flags. - void ngcs(const Register& rd, - const Operand& operand); - - // Logical instructions. - // Bitwise and (A & B). - void and_(const Register& rd, - const Register& rn, - const Operand& operand); - - // Bitwise and (A & B) and update status flags. - void ands(const Register& rd, - const Register& rn, - const Operand& operand); - - // Bit test and set flags. - void tst(const Register& rn, const Operand& operand); - - // Bit clear (A & ~B). - void bic(const Register& rd, - const Register& rn, - const Operand& operand); - - // Bit clear (A & ~B) and update status flags. - void bics(const Register& rd, - const Register& rn, - const Operand& operand); - - // Bitwise or (A | B). - void orr(const Register& rd, const Register& rn, const Operand& operand); - - // Bitwise nor (A | ~B). - void orn(const Register& rd, const Register& rn, const Operand& operand); - - // Bitwise eor/xor (A ^ B). - void eor(const Register& rd, const Register& rn, const Operand& operand); - - // Bitwise enor/xnor (A ^ ~B). - void eon(const Register& rd, const Register& rn, const Operand& operand); - - // Logical shift left by variable. - void lslv(const Register& rd, const Register& rn, const Register& rm); - - // Logical shift right by variable. - void lsrv(const Register& rd, const Register& rn, const Register& rm); - - // Arithmetic shift right by variable. - void asrv(const Register& rd, const Register& rn, const Register& rm); - - // Rotate right by variable. - void rorv(const Register& rd, const Register& rn, const Register& rm); - - // Bitfield instructions. - // Bitfield move. - void bfm(const Register& rd, - const Register& rn, - unsigned immr, - unsigned imms); - - // Signed bitfield move. - void sbfm(const Register& rd, - const Register& rn, - unsigned immr, - unsigned imms); - - // Unsigned bitfield move. - void ubfm(const Register& rd, - const Register& rn, - unsigned immr, - unsigned imms); - - // Bfm aliases. - // Bitfield insert. - void bfi(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { - VIXL_ASSERT(width >= 1); - VIXL_ASSERT(lsb + width <= rn.size()); - bfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); - } - - // Bitfield extract and insert low. - void bfxil(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { - VIXL_ASSERT(width >= 1); - VIXL_ASSERT(lsb + width <= rn.size()); - bfm(rd, rn, lsb, lsb + width - 1); - } - - // Sbfm aliases. - // Arithmetic shift right. - void asr(const Register& rd, const Register& rn, unsigned shift) { - VIXL_ASSERT(shift < rd.size()); - sbfm(rd, rn, shift, rd.size() - 1); - } - - // Signed bitfield insert with zero at right. - void sbfiz(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { - VIXL_ASSERT(width >= 1); - VIXL_ASSERT(lsb + width <= rn.size()); - sbfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); - } - - // Signed bitfield extract. - void sbfx(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { - VIXL_ASSERT(width >= 1); - VIXL_ASSERT(lsb + width <= rn.size()); - sbfm(rd, rn, lsb, lsb + width - 1); - } - - // Signed extend byte. - void sxtb(const Register& rd, const Register& rn) { - sbfm(rd, rn, 0, 7); - } - - // Signed extend halfword. - void sxth(const Register& rd, const Register& rn) { - sbfm(rd, rn, 0, 15); - } - - // Signed extend word. - void sxtw(const Register& rd, const Register& rn) { - sbfm(rd, rn, 0, 31); - } - - // Ubfm aliases. - // Logical shift left. - void lsl(const Register& rd, const Register& rn, unsigned shift) { - unsigned reg_size = rd.size(); - VIXL_ASSERT(shift < reg_size); - ubfm(rd, rn, (reg_size - shift) % reg_size, reg_size - shift - 1); - } - - // Logical shift right. - void lsr(const Register& rd, const Register& rn, unsigned shift) { - VIXL_ASSERT(shift < rd.size()); - ubfm(rd, rn, shift, rd.size() - 1); - } - - // Unsigned bitfield insert with zero at right. - void ubfiz(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { - VIXL_ASSERT(width >= 1); - VIXL_ASSERT(lsb + width <= rn.size()); - ubfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); - } - - // Unsigned bitfield extract. - void ubfx(const Register& rd, - const Register& rn, - unsigned lsb, - unsigned width) { - VIXL_ASSERT(width >= 1); - VIXL_ASSERT(lsb + width <= rn.size()); - ubfm(rd, rn, lsb, lsb + width - 1); - } - - // Unsigned extend byte. - void uxtb(const Register& rd, const Register& rn) { - ubfm(rd, rn, 0, 7); - } - - // Unsigned extend halfword. - void uxth(const Register& rd, const Register& rn) { - ubfm(rd, rn, 0, 15); - } - - // Unsigned extend word. - void uxtw(const Register& rd, const Register& rn) { - ubfm(rd, rn, 0, 31); - } - - // Extract. - void extr(const Register& rd, - const Register& rn, - const Register& rm, - unsigned lsb); - - // Conditional select: rd = cond ? rn : rm. - void csel(const Register& rd, - const Register& rn, - const Register& rm, - Condition cond); - - // Conditional select increment: rd = cond ? rn : rm + 1. - void csinc(const Register& rd, - const Register& rn, - const Register& rm, - Condition cond); - - // Conditional select inversion: rd = cond ? rn : ~rm. - void csinv(const Register& rd, - const Register& rn, - const Register& rm, - Condition cond); - - // Conditional select negation: rd = cond ? rn : -rm. - void csneg(const Register& rd, - const Register& rn, - const Register& rm, - Condition cond); - - // Conditional set: rd = cond ? 1 : 0. - void cset(const Register& rd, Condition cond); - - // Conditional set mask: rd = cond ? -1 : 0. - void csetm(const Register& rd, Condition cond); - - // Conditional increment: rd = cond ? rn + 1 : rn. - void cinc(const Register& rd, const Register& rn, Condition cond); - - // Conditional invert: rd = cond ? ~rn : rn. - void cinv(const Register& rd, const Register& rn, Condition cond); - - // Conditional negate: rd = cond ? -rn : rn. - void cneg(const Register& rd, const Register& rn, Condition cond); - - // Rotate right. - void ror(const Register& rd, const Register& rs, unsigned shift) { - extr(rd, rs, rs, shift); - } - - // Conditional comparison. - // Conditional compare negative. - void ccmn(const Register& rn, - const Operand& operand, - StatusFlags nzcv, - Condition cond); - - // Conditional compare. - void ccmp(const Register& rn, - const Operand& operand, - StatusFlags nzcv, - Condition cond); - - // CRC-32 checksum from byte. - void crc32b(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32 checksum from half-word. - void crc32h(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32 checksum from word. - void crc32w(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32 checksum from double word. - void crc32x(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32 C checksum from byte. - void crc32cb(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32 C checksum from half-word. - void crc32ch(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32 C checksum from word. - void crc32cw(const Register& rd, - const Register& rn, - const Register& rm); - - // CRC-32C checksum from double word. - void crc32cx(const Register& rd, - const Register& rn, - const Register& rm); - - // Multiply. - void mul(const Register& rd, const Register& rn, const Register& rm); - - // Negated multiply. - void mneg(const Register& rd, const Register& rn, const Register& rm); - - // Signed long multiply: 32 x 32 -> 64-bit. - void smull(const Register& rd, const Register& rn, const Register& rm); - - // Signed multiply high: 64 x 64 -> 64-bit <127:64>. - void smulh(const Register& xd, const Register& xn, const Register& xm); - - // Multiply and accumulate. - void madd(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra); - - // Multiply and subtract. - void msub(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra); - - // Signed long multiply and accumulate: 32 x 32 + 64 -> 64-bit. - void smaddl(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra); - - // Unsigned long multiply and accumulate: 32 x 32 + 64 -> 64-bit. - void umaddl(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra); - - // Unsigned long multiply: 32 x 32 -> 64-bit. - void umull(const Register& rd, - const Register& rn, - const Register& rm) { - umaddl(rd, rn, rm, xzr); - } - - // Unsigned multiply high: 64 x 64 -> 64-bit <127:64>. - void umulh(const Register& xd, - const Register& xn, - const Register& xm); - - // Signed long multiply and subtract: 64 - (32 x 32) -> 64-bit. - void smsubl(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra); - - // Unsigned long multiply and subtract: 64 - (32 x 32) -> 64-bit. - void umsubl(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra); - - // Signed integer divide. - void sdiv(const Register& rd, const Register& rn, const Register& rm); - - // Unsigned integer divide. - void udiv(const Register& rd, const Register& rn, const Register& rm); - - // Bit reverse. - void rbit(const Register& rd, const Register& rn); - - // Reverse bytes in 16-bit half words. - void rev16(const Register& rd, const Register& rn); - - // Reverse bytes in 32-bit words. - void rev32(const Register& rd, const Register& rn); - - // Reverse bytes. - void rev(const Register& rd, const Register& rn); - - // Count leading zeroes. - void clz(const Register& rd, const Register& rn); - - // Count leading sign bits. - void cls(const Register& rd, const Register& rn); - - // Memory instructions. - // Load integer or FP register. - void ldr(const CPURegister& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferScaledOffset); - - // Store integer or FP register. - void str(const CPURegister& rt, const MemOperand& dst, - LoadStoreScalingOption option = PreferScaledOffset); - - // Load word with sign extension. - void ldrsw(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferScaledOffset); - - // Load byte. - void ldrb(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferScaledOffset); - - // Store byte. - void strb(const Register& rt, const MemOperand& dst, - LoadStoreScalingOption option = PreferScaledOffset); - - // Load byte with sign extension. - void ldrsb(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferScaledOffset); - - // Load half-word. - void ldrh(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferScaledOffset); - - // Store half-word. - void strh(const Register& rt, const MemOperand& dst, - LoadStoreScalingOption option = PreferScaledOffset); - - // Load half-word with sign extension. - void ldrsh(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferScaledOffset); - - // Load integer or FP register (with unscaled offset). - void ldur(const CPURegister& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Store integer or FP register (with unscaled offset). - void stur(const CPURegister& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Load word with sign extension. - void ldursw(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Load byte (with unscaled offset). - void ldurb(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Store byte (with unscaled offset). - void sturb(const Register& rt, const MemOperand& dst, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Load byte with sign extension (and unscaled offset). - void ldursb(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Load half-word (with unscaled offset). - void ldurh(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Store half-word (with unscaled offset). - void sturh(const Register& rt, const MemOperand& dst, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Load half-word with sign extension (and unscaled offset). - void ldursh(const Register& rt, const MemOperand& src, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Load integer or FP register pair. - void ldp(const CPURegister& rt, const CPURegister& rt2, - const MemOperand& src); - - // Store integer or FP register pair. - void stp(const CPURegister& rt, const CPURegister& rt2, - const MemOperand& dst); - - // Load word pair with sign extension. - void ldpsw(const Register& rt, const Register& rt2, const MemOperand& src); - - // Load integer or FP register pair, non-temporal. - void ldnp(const CPURegister& rt, const CPURegister& rt2, - const MemOperand& src); - - // Store integer or FP register pair, non-temporal. - void stnp(const CPURegister& rt, const CPURegister& rt2, - const MemOperand& dst); - - // Load integer or FP register from literal pool. - void ldr(const CPURegister& rt, RawLiteral* literal); - - // Load word with sign extension from literal pool. - void ldrsw(const Register& rt, RawLiteral* literal); - - // Load integer or FP register from pc + imm19 << 2. - void ldr(const CPURegister& rt, int imm19); - - // Load word with sign extension from pc + imm19 << 2. - void ldrsw(const Register& rt, int imm19); - - // Store exclusive byte. - void stxrb(const Register& rs, const Register& rt, const MemOperand& dst); - - // Store exclusive half-word. - void stxrh(const Register& rs, const Register& rt, const MemOperand& dst); - - // Store exclusive register. - void stxr(const Register& rs, const Register& rt, const MemOperand& dst); - - // Load exclusive byte. - void ldxrb(const Register& rt, const MemOperand& src); - - // Load exclusive half-word. - void ldxrh(const Register& rt, const MemOperand& src); - - // Load exclusive register. - void ldxr(const Register& rt, const MemOperand& src); - - // Store exclusive register pair. - void stxp(const Register& rs, - const Register& rt, - const Register& rt2, - const MemOperand& dst); - - // Load exclusive register pair. - void ldxp(const Register& rt, const Register& rt2, const MemOperand& src); - - // Store-release exclusive byte. - void stlxrb(const Register& rs, const Register& rt, const MemOperand& dst); - - // Store-release exclusive half-word. - void stlxrh(const Register& rs, const Register& rt, const MemOperand& dst); - - // Store-release exclusive register. - void stlxr(const Register& rs, const Register& rt, const MemOperand& dst); - - // Load-acquire exclusive byte. - void ldaxrb(const Register& rt, const MemOperand& src); - - // Load-acquire exclusive half-word. - void ldaxrh(const Register& rt, const MemOperand& src); - - // Load-acquire exclusive register. - void ldaxr(const Register& rt, const MemOperand& src); - - // Store-release exclusive register pair. - void stlxp(const Register& rs, - const Register& rt, - const Register& rt2, - const MemOperand& dst); - - // Load-acquire exclusive register pair. - void ldaxp(const Register& rt, const Register& rt2, const MemOperand& src); - - // Store-release byte. - void stlrb(const Register& rt, const MemOperand& dst); - - // Store-release half-word. - void stlrh(const Register& rt, const MemOperand& dst); - - // Store-release register. - void stlr(const Register& rt, const MemOperand& dst); - - // Load-acquire byte. - void ldarb(const Register& rt, const MemOperand& src); - - // Load-acquire half-word. - void ldarh(const Register& rt, const MemOperand& src); - - // Load-acquire register. - void ldar(const Register& rt, const MemOperand& src); - - // Prefetch memory. - void prfm(PrefetchOperation op, const MemOperand& addr, - LoadStoreScalingOption option = PreferScaledOffset); - - // Prefetch memory (with unscaled offset). - void prfum(PrefetchOperation op, const MemOperand& addr, - LoadStoreScalingOption option = PreferUnscaledOffset); - - // Prefetch memory in the literal pool. - void prfm(PrefetchOperation op, RawLiteral* literal); - - // Prefetch from pc + imm19 << 2. - void prfm(PrefetchOperation op, int imm19); - - // Move instructions. The default shift of -1 indicates that the move - // instruction will calculate an appropriate 16-bit immediate and left shift - // that is equal to the 64-bit immediate argument. If an explicit left shift - // is specified (0, 16, 32 or 48), the immediate must be a 16-bit value. - // - // For movk, an explicit shift can be used to indicate which half word should - // be overwritten, eg. movk(x0, 0, 0) will overwrite the least-significant - // half word with zero, whereas movk(x0, 0, 48) will overwrite the - // most-significant. - - // Move immediate and keep. - void movk(const Register& rd, uint64_t imm, int shift = -1) { - MoveWide(rd, imm, shift, MOVK); - } - - // Move inverted immediate. - void movn(const Register& rd, uint64_t imm, int shift = -1) { - MoveWide(rd, imm, shift, MOVN); - } - - // Move immediate. - void movz(const Register& rd, uint64_t imm, int shift = -1) { - MoveWide(rd, imm, shift, MOVZ); - } - - // Misc instructions. - // Monitor debug-mode breakpoint. - void brk(int code); - - // Halting debug-mode breakpoint. - void hlt(int code); - - // Generate exception targeting EL1. - void svc(int code); - - // Move register to register. - void mov(const Register& rd, const Register& rn); - - // Move inverted operand to register. - void mvn(const Register& rd, const Operand& operand); - - // System instructions. - // Move to register from system register. - void mrs(const Register& rt, SystemRegister sysreg); - - // Move from register to system register. - void msr(SystemRegister sysreg, const Register& rt); - - // System instruction. - void sys(int op1, int crn, int crm, int op2, const Register& rt = xzr); - - // System instruction with pre-encoded op (op1:crn:crm:op2). - void sys(int op, const Register& rt = xzr); - - // System data cache operation. - void dc(DataCacheOp op, const Register& rt); - - // System instruction cache operation. - void ic(InstructionCacheOp op, const Register& rt); - - // System hint. - void hint(SystemHint code); - - // Clear exclusive monitor. - void clrex(int imm4 = 0xf); - - // Data memory barrier. - void dmb(BarrierDomain domain, BarrierType type); - - // Data synchronization barrier. - void dsb(BarrierDomain domain, BarrierType type); - - // Instruction synchronization barrier. - void isb(); - - // Alias for system instructions. - // No-op. - void nop() { - hint(NOP); - } - - // FP and NEON instructions. - // Move double precision immediate to FP register. - void fmov(const VRegister& vd, double imm); - - // Move single precision immediate to FP register. - void fmov(const VRegister& vd, float imm); - - // Move FP register to register. - void fmov(const Register& rd, const VRegister& fn); - - // Move register to FP register. - void fmov(const VRegister& vd, const Register& rn); - - // Move FP register to FP register. - void fmov(const VRegister& vd, const VRegister& fn); - - // Move 64-bit register to top half of 128-bit FP register. - void fmov(const VRegister& vd, int index, const Register& rn); - - // Move top half of 128-bit FP register to 64-bit register. - void fmov(const Register& rd, const VRegister& vn, int index); - - // FP add. - void fadd(const VRegister& vd, const VRegister& vn, const VRegister& vm); - - // FP subtract. - void fsub(const VRegister& vd, const VRegister& vn, const VRegister& vm); - - // FP multiply. - void fmul(const VRegister& vd, const VRegister& vn, const VRegister& vm); - - // FP fused multiply-add. - void fmadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - const VRegister& va); - - // FP fused multiply-subtract. - void fmsub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - const VRegister& va); - - // FP fused multiply-add and negate. - void fnmadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - const VRegister& va); - - // FP fused multiply-subtract and negate. - void fnmsub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - const VRegister& va); - - // FP multiply-negate scalar. - void fnmul(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP reciprocal exponent scalar. - void frecpx(const VRegister& vd, - const VRegister& vn); - - // FP divide. - void fdiv(const VRegister& vd, const VRegister& fn, const VRegister& vm); - - // FP maximum. - void fmax(const VRegister& vd, const VRegister& fn, const VRegister& vm); - - // FP minimum. - void fmin(const VRegister& vd, const VRegister& fn, const VRegister& vm); - - // FP maximum number. - void fmaxnm(const VRegister& vd, const VRegister& fn, const VRegister& vm); - - // FP minimum number. - void fminnm(const VRegister& vd, const VRegister& fn, const VRegister& vm); - - // FP absolute. - void fabs(const VRegister& vd, const VRegister& vn); - - // FP negate. - void fneg(const VRegister& vd, const VRegister& vn); - - // FP square root. - void fsqrt(const VRegister& vd, const VRegister& vn); - - // FP round to integer, nearest with ties to away. - void frinta(const VRegister& vd, const VRegister& vn); - - // FP round to integer, implicit rounding. - void frinti(const VRegister& vd, const VRegister& vn); - - // FP round to integer, toward minus infinity. - void frintm(const VRegister& vd, const VRegister& vn); - - // FP round to integer, nearest with ties to even. - void frintn(const VRegister& vd, const VRegister& vn); - - // FP round to integer, toward plus infinity. - void frintp(const VRegister& vd, const VRegister& vn); - - // FP round to integer, exact, implicit rounding. - void frintx(const VRegister& vd, const VRegister& vn); - - // FP round to integer, towards zero. - void frintz(const VRegister& vd, const VRegister& vn); - - void FPCompareMacro(const VRegister& vn, - double value, - FPTrapFlags trap); - - void FPCompareMacro(const VRegister& vn, - const VRegister& vm, - FPTrapFlags trap); - - // FP compare registers. - void fcmp(const VRegister& vn, const VRegister& vm); - - // FP compare immediate. - void fcmp(const VRegister& vn, double value); - - void FPCCompareMacro(const VRegister& vn, - const VRegister& vm, - StatusFlags nzcv, - Condition cond, - FPTrapFlags trap); - - // FP conditional compare. - void fccmp(const VRegister& vn, - const VRegister& vm, - StatusFlags nzcv, - Condition cond); - - // FP signaling compare registers. - void fcmpe(const VRegister& vn, const VRegister& vm); - - // FP signaling compare immediate. - void fcmpe(const VRegister& vn, double value); - - // FP conditional signaling compare. - void fccmpe(const VRegister& vn, - const VRegister& vm, - StatusFlags nzcv, - Condition cond); - - // FP conditional select. - void fcsel(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - Condition cond); - - // Common FP Convert functions. - void NEONFPConvertToInt(const Register& rd, - const VRegister& vn, - Instr op); - void NEONFPConvertToInt(const VRegister& vd, - const VRegister& vn, - Instr op); - - // FP convert between precisions. - void fcvt(const VRegister& vd, const VRegister& vn); - - // FP convert to higher precision. - void fcvtl(const VRegister& vd, const VRegister& vn); - - // FP convert to higher precision (second part). - void fcvtl2(const VRegister& vd, const VRegister& vn); - - // FP convert to lower precision. - void fcvtn(const VRegister& vd, const VRegister& vn); - - // FP convert to lower prevision (second part). - void fcvtn2(const VRegister& vd, const VRegister& vn); - - // FP convert to lower precision, rounding to odd. - void fcvtxn(const VRegister& vd, const VRegister& vn); - - // FP convert to lower precision, rounding to odd (second part). - void fcvtxn2(const VRegister& vd, const VRegister& vn); - - // FP convert to signed integer, nearest with ties to away. - void fcvtas(const Register& rd, const VRegister& vn); - - // FP convert to unsigned integer, nearest with ties to away. - void fcvtau(const Register& rd, const VRegister& vn); - - // FP convert to signed integer, nearest with ties to away. - void fcvtas(const VRegister& vd, const VRegister& vn); - - // FP convert to unsigned integer, nearest with ties to away. - void fcvtau(const VRegister& vd, const VRegister& vn); - - // FP convert to signed integer, round towards -infinity. - void fcvtms(const Register& rd, const VRegister& vn); - - // FP convert to unsigned integer, round towards -infinity. - void fcvtmu(const Register& rd, const VRegister& vn); - - // FP convert to signed integer, round towards -infinity. - void fcvtms(const VRegister& vd, const VRegister& vn); - - // FP convert to unsigned integer, round towards -infinity. - void fcvtmu(const VRegister& vd, const VRegister& vn); - - // FP convert to signed integer, nearest with ties to even. - void fcvtns(const Register& rd, const VRegister& vn); - - // FP convert to unsigned integer, nearest with ties to even. - void fcvtnu(const Register& rd, const VRegister& vn); - - // FP convert to signed integer, nearest with ties to even. - void fcvtns(const VRegister& rd, const VRegister& vn); - - // FP convert to unsigned integer, nearest with ties to even. - void fcvtnu(const VRegister& rd, const VRegister& vn); - - // FP convert to signed integer or fixed-point, round towards zero. - void fcvtzs(const Register& rd, const VRegister& vn, int fbits = 0); - - // FP convert to unsigned integer or fixed-point, round towards zero. - void fcvtzu(const Register& rd, const VRegister& vn, int fbits = 0); - - // FP convert to signed integer or fixed-point, round towards zero. - void fcvtzs(const VRegister& vd, const VRegister& vn, int fbits = 0); - - // FP convert to unsigned integer or fixed-point, round towards zero. - void fcvtzu(const VRegister& vd, const VRegister& vn, int fbits = 0); - - // FP convert to signed integer, round towards +infinity. - void fcvtps(const Register& rd, const VRegister& vn); - - // FP convert to unsigned integer, round towards +infinity. - void fcvtpu(const Register& rd, const VRegister& vn); - - // FP convert to signed integer, round towards +infinity. - void fcvtps(const VRegister& vd, const VRegister& vn); - - // FP convert to unsigned integer, round towards +infinity. - void fcvtpu(const VRegister& vd, const VRegister& vn); - - // Convert signed integer or fixed point to FP. - void scvtf(const VRegister& fd, const Register& rn, int fbits = 0); - - // Convert unsigned integer or fixed point to FP. - void ucvtf(const VRegister& fd, const Register& rn, int fbits = 0); - - // Convert signed integer or fixed-point to FP. - void scvtf(const VRegister& fd, const VRegister& vn, int fbits = 0); - - // Convert unsigned integer or fixed-point to FP. - void ucvtf(const VRegister& fd, const VRegister& vn, int fbits = 0); - - // Unsigned absolute difference. - void uabd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed absolute difference. - void sabd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned absolute difference and accumulate. - void uaba(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed absolute difference and accumulate. - void saba(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Add. - void add(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Subtract. - void sub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned halving add. - void uhadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed halving add. - void shadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned rounding halving add. - void urhadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed rounding halving add. - void srhadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned halving sub. - void uhsub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed halving sub. - void shsub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned saturating add. - void uqadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating add. - void sqadd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned saturating subtract. - void uqsub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating subtract. - void sqsub(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Add pairwise. - void addp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Add pair of elements scalar. - void addp(const VRegister& vd, - const VRegister& vn); - - // Multiply-add to accumulator. - void mla(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Multiply-subtract to accumulator. - void mls(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Multiply. - void mul(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Multiply by scalar element. - void mul(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Multiply-add by scalar element. - void mla(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Multiply-subtract by scalar element. - void mls(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed long multiply-add by scalar element. - void smlal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed long multiply-add by scalar element (second part). - void smlal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply-add by scalar element. - void umlal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply-add by scalar element (second part). - void umlal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed long multiply-sub by scalar element. - void smlsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed long multiply-sub by scalar element (second part). - void smlsl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply-sub by scalar element. - void umlsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply-sub by scalar element (second part). - void umlsl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed long multiply by scalar element. - void smull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed long multiply by scalar element (second part). - void smull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply by scalar element. - void umull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply by scalar element (second part). - void umull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating double long multiply by element. - void sqdmull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating double long multiply by element (second part). - void sqdmull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating doubling long multiply-add by element. - void sqdmlal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating doubling long multiply-add by element (second part). - void sqdmlal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating doubling long multiply-sub by element. - void sqdmlsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating doubling long multiply-sub by element (second part). - void sqdmlsl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Compare equal. - void cmeq(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Compare signed greater than or equal. - void cmge(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Compare signed greater than. - void cmgt(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Compare unsigned higher. - void cmhi(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Compare unsigned higher or same. - void cmhs(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Compare bitwise test bits nonzero. - void cmtst(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Compare bitwise to zero. - void cmeq(const VRegister& vd, - const VRegister& vn, - int value); - - // Compare signed greater than or equal to zero. - void cmge(const VRegister& vd, - const VRegister& vn, - int value); - - // Compare signed greater than zero. - void cmgt(const VRegister& vd, - const VRegister& vn, - int value); - - // Compare signed less than or equal to zero. - void cmle(const VRegister& vd, - const VRegister& vn, - int value); - - // Compare signed less than zero. - void cmlt(const VRegister& vd, - const VRegister& vn, - int value); - - // Signed shift left by register. - void sshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned shift left by register. - void ushl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating shift left by register. - void sqshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned saturating shift left by register. - void uqshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed rounding shift left by register. - void srshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned rounding shift left by register. - void urshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating rounding shift left by register. - void sqrshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned saturating rounding shift left by register. - void uqrshl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise and. - void and_(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise or. - void orr(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise or immediate. - void orr(const VRegister& vd, - const int imm8, - const int left_shift = 0); - - // Move register to register. - void mov(const VRegister& vd, - const VRegister& vn); - - // Bitwise orn. - void orn(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise eor. - void eor(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bit clear immediate. - void bic(const VRegister& vd, - const int imm8, - const int left_shift = 0); - - // Bit clear. - void bic(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise insert if false. - void bif(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise insert if true. - void bit(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Bitwise select. - void bsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Polynomial multiply. - void pmul(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Vector move immediate. - void movi(const VRegister& vd, - const uint64_t imm, - Shift shift = LSL, - const int shift_amount = 0); - - // Bitwise not. - void mvn(const VRegister& vd, - const VRegister& vn); - - // Vector move inverted immediate. - void mvni(const VRegister& vd, - const int imm8, - Shift shift = LSL, - const int shift_amount = 0); - - // Signed saturating accumulate of unsigned value. - void suqadd(const VRegister& vd, - const VRegister& vn); - - // Unsigned saturating accumulate of signed value. - void usqadd(const VRegister& vd, - const VRegister& vn); - - // Absolute value. - void abs(const VRegister& vd, - const VRegister& vn); - - // Signed saturating absolute value. - void sqabs(const VRegister& vd, - const VRegister& vn); - - // Negate. - void neg(const VRegister& vd, - const VRegister& vn); - - // Signed saturating negate. - void sqneg(const VRegister& vd, - const VRegister& vn); - - // Bitwise not. - void not_(const VRegister& vd, - const VRegister& vn); - - // Extract narrow. - void xtn(const VRegister& vd, - const VRegister& vn); - - // Extract narrow (second part). - void xtn2(const VRegister& vd, - const VRegister& vn); - - // Signed saturating extract narrow. - void sqxtn(const VRegister& vd, - const VRegister& vn); - - // Signed saturating extract narrow (second part). - void sqxtn2(const VRegister& vd, - const VRegister& vn); - - // Unsigned saturating extract narrow. - void uqxtn(const VRegister& vd, - const VRegister& vn); - - // Unsigned saturating extract narrow (second part). - void uqxtn2(const VRegister& vd, - const VRegister& vn); - - // Signed saturating extract unsigned narrow. - void sqxtun(const VRegister& vd, - const VRegister& vn); - - // Signed saturating extract unsigned narrow (second part). - void sqxtun2(const VRegister& vd, - const VRegister& vn); - - // Extract vector from pair of vectors. - void ext(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int index); - - // Duplicate vector element to vector or scalar. - void dup(const VRegister& vd, - const VRegister& vn, - int vn_index); - - // Move vector element to scalar. - void mov(const VRegister& vd, - const VRegister& vn, - int vn_index); - - // Duplicate general-purpose register to vector. - void dup(const VRegister& vd, - const Register& rn); - - // Insert vector element from another vector element. - void ins(const VRegister& vd, - int vd_index, - const VRegister& vn, - int vn_index); - - // Move vector element to another vector element. - void mov(const VRegister& vd, - int vd_index, - const VRegister& vn, - int vn_index); - - // Insert vector element from general-purpose register. - void ins(const VRegister& vd, - int vd_index, - const Register& rn); - - // Move general-purpose register to a vector element. - void mov(const VRegister& vd, - int vd_index, - const Register& rn); - - // Unsigned move vector element to general-purpose register. - void umov(const Register& rd, - const VRegister& vn, - int vn_index); - - // Move vector element to general-purpose register. - void mov(const Register& rd, - const VRegister& vn, - int vn_index); - - // Signed move vector element to general-purpose register. - void smov(const Register& rd, - const VRegister& vn, - int vn_index); - - // One-element structure load to one register. - void ld1(const VRegister& vt, - const MemOperand& src); - - // One-element structure load to two registers. - void ld1(const VRegister& vt, - const VRegister& vt2, - const MemOperand& src); - - // One-element structure load to three registers. - void ld1(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const MemOperand& src); - - // One-element structure load to four registers. - void ld1(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - const MemOperand& src); - - // One-element single structure load to one lane. - void ld1(const VRegister& vt, - int lane, - const MemOperand& src); - - // One-element single structure load to all lanes. - void ld1r(const VRegister& vt, - const MemOperand& src); - - // Two-element structure load. - void ld2(const VRegister& vt, - const VRegister& vt2, - const MemOperand& src); - - // Two-element single structure load to one lane. - void ld2(const VRegister& vt, - const VRegister& vt2, - int lane, - const MemOperand& src); - - // Two-element single structure load to all lanes. - void ld2r(const VRegister& vt, - const VRegister& vt2, - const MemOperand& src); - - // Three-element structure load. - void ld3(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const MemOperand& src); - - // Three-element single structure load to one lane. - void ld3(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - int lane, - const MemOperand& src); - - // Three-element single structure load to all lanes. - void ld3r(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const MemOperand& src); - - // Four-element structure load. - void ld4(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - const MemOperand& src); - - // Four-element single structure load to one lane. - void ld4(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - int lane, - const MemOperand& src); - - // Four-element single structure load to all lanes. - void ld4r(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - const MemOperand& src); - - // Count leading sign bits. - void cls(const VRegister& vd, - const VRegister& vn); - - // Count leading zero bits (vector). - void clz(const VRegister& vd, - const VRegister& vn); - - // Population count per byte. - void cnt(const VRegister& vd, - const VRegister& vn); - - // Reverse bit order. - void rbit(const VRegister& vd, - const VRegister& vn); - - // Reverse elements in 16-bit halfwords. - void rev16(const VRegister& vd, - const VRegister& vn); - - // Reverse elements in 32-bit words. - void rev32(const VRegister& vd, - const VRegister& vn); - - // Reverse elements in 64-bit doublewords. - void rev64(const VRegister& vd, - const VRegister& vn); - - // Unsigned reciprocal square root estimate. - void ursqrte(const VRegister& vd, - const VRegister& vn); - - // Unsigned reciprocal estimate. - void urecpe(const VRegister& vd, - const VRegister& vn); - - // Signed pairwise long add. - void saddlp(const VRegister& vd, - const VRegister& vn); - - // Unsigned pairwise long add. - void uaddlp(const VRegister& vd, - const VRegister& vn); - - // Signed pairwise long add and accumulate. - void sadalp(const VRegister& vd, - const VRegister& vn); - - // Unsigned pairwise long add and accumulate. - void uadalp(const VRegister& vd, - const VRegister& vn); - - // Shift left by immediate. - void shl(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating shift left by immediate. - void sqshl(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating shift left unsigned by immediate. - void sqshlu(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned saturating shift left by immediate. - void uqshl(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed shift left long by immediate. - void sshll(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed shift left long by immediate (second part). - void sshll2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed extend long. - void sxtl(const VRegister& vd, - const VRegister& vn); - - // Signed extend long (second part). - void sxtl2(const VRegister& vd, - const VRegister& vn); - - // Unsigned shift left long by immediate. - void ushll(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned shift left long by immediate (second part). - void ushll2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Shift left long by element size. - void shll(const VRegister& vd, - const VRegister& vn, - int shift); - - // Shift left long by element size (second part). - void shll2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned extend long. - void uxtl(const VRegister& vd, - const VRegister& vn); - - // Unsigned extend long (second part). - void uxtl2(const VRegister& vd, - const VRegister& vn); - - // Shift left by immediate and insert. - void sli(const VRegister& vd, - const VRegister& vn, - int shift); - - // Shift right by immediate and insert. - void sri(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed maximum. - void smax(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed pairwise maximum. - void smaxp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Add across vector. - void addv(const VRegister& vd, - const VRegister& vn); - - // Signed add long across vector. - void saddlv(const VRegister& vd, - const VRegister& vn); - - // Unsigned add long across vector. - void uaddlv(const VRegister& vd, - const VRegister& vn); - - // FP maximum number across vector. - void fmaxnmv(const VRegister& vd, - const VRegister& vn); - - // FP maximum across vector. - void fmaxv(const VRegister& vd, - const VRegister& vn); - - // FP minimum number across vector. - void fminnmv(const VRegister& vd, - const VRegister& vn); - - // FP minimum across vector. - void fminv(const VRegister& vd, - const VRegister& vn); - - // Signed maximum across vector. - void smaxv(const VRegister& vd, - const VRegister& vn); - - // Signed minimum. - void smin(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed minimum pairwise. - void sminp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed minimum across vector. - void sminv(const VRegister& vd, - const VRegister& vn); - - // One-element structure store from one register. - void st1(const VRegister& vt, - const MemOperand& src); - - // One-element structure store from two registers. - void st1(const VRegister& vt, - const VRegister& vt2, - const MemOperand& src); - - // One-element structure store from three registers. - void st1(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const MemOperand& src); - - // One-element structure store from four registers. - void st1(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - const MemOperand& src); - - // One-element single structure store from one lane. - void st1(const VRegister& vt, - int lane, - const MemOperand& src); - - // Two-element structure store from two registers. - void st2(const VRegister& vt, - const VRegister& vt2, - const MemOperand& src); - - // Two-element single structure store from two lanes. - void st2(const VRegister& vt, - const VRegister& vt2, - int lane, - const MemOperand& src); - - // Three-element structure store from three registers. - void st3(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const MemOperand& src); - - // Three-element single structure store from three lanes. - void st3(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - int lane, - const MemOperand& src); - - // Four-element structure store from four registers. - void st4(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - const MemOperand& src); - - // Four-element single structure store from four lanes. - void st4(const VRegister& vt, - const VRegister& vt2, - const VRegister& vt3, - const VRegister& vt4, - int lane, - const MemOperand& src); - - // Unsigned add long. - void uaddl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned add long (second part). - void uaddl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned add wide. - void uaddw(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned add wide (second part). - void uaddw2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed add long. - void saddl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed add long (second part). - void saddl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed add wide. - void saddw(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed add wide (second part). - void saddw2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned subtract long. - void usubl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned subtract long (second part). - void usubl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned subtract wide. - void usubw(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned subtract wide (second part). - void usubw2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed subtract long. - void ssubl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed subtract long (second part). - void ssubl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed integer subtract wide. - void ssubw(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed integer subtract wide (second part). - void ssubw2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned maximum. - void umax(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned pairwise maximum. - void umaxp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned maximum across vector. - void umaxv(const VRegister& vd, - const VRegister& vn); - - // Unsigned minimum. - void umin(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned pairwise minimum. - void uminp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned minimum across vector. - void uminv(const VRegister& vd, - const VRegister& vn); - - // Transpose vectors (primary). - void trn1(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Transpose vectors (secondary). - void trn2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unzip vectors (primary). - void uzp1(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unzip vectors (secondary). - void uzp2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Zip vectors (primary). - void zip1(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Zip vectors (secondary). - void zip2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed shift right by immediate. - void sshr(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned shift right by immediate. - void ushr(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed rounding shift right by immediate. - void srshr(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned rounding shift right by immediate. - void urshr(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed shift right by immediate and accumulate. - void ssra(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned shift right by immediate and accumulate. - void usra(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed rounding shift right by immediate and accumulate. - void srsra(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned rounding shift right by immediate and accumulate. - void ursra(const VRegister& vd, - const VRegister& vn, - int shift); - - // Shift right narrow by immediate. - void shrn(const VRegister& vd, - const VRegister& vn, - int shift); - - // Shift right narrow by immediate (second part). - void shrn2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Rounding shift right narrow by immediate. - void rshrn(const VRegister& vd, - const VRegister& vn, - int shift); - - // Rounding shift right narrow by immediate (second part). - void rshrn2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned saturating shift right narrow by immediate. - void uqshrn(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned saturating shift right narrow by immediate (second part). - void uqshrn2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned saturating rounding shift right narrow by immediate. - void uqrshrn(const VRegister& vd, - const VRegister& vn, - int shift); - - // Unsigned saturating rounding shift right narrow by immediate (second part). - void uqrshrn2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating shift right narrow by immediate. - void sqshrn(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating shift right narrow by immediate (second part). - void sqshrn2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating rounded shift right narrow by immediate. - void sqrshrn(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating rounded shift right narrow by immediate (second part). - void sqrshrn2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating shift right unsigned narrow by immediate. - void sqshrun(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed saturating shift right unsigned narrow by immediate (second part). - void sqshrun2(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed sat rounded shift right unsigned narrow by immediate. - void sqrshrun(const VRegister& vd, - const VRegister& vn, - int shift); - - // Signed sat rounded shift right unsigned narrow by immediate (second part). - void sqrshrun2(const VRegister& vd, - const VRegister& vn, - int shift); - - // FP reciprocal step. - void frecps(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP reciprocal estimate. - void frecpe(const VRegister& vd, - const VRegister& vn); - - // FP reciprocal square root estimate. - void frsqrte(const VRegister& vd, - const VRegister& vn); - - // FP reciprocal square root step. - void frsqrts(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed absolute difference and accumulate long. - void sabal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed absolute difference and accumulate long (second part). - void sabal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned absolute difference and accumulate long. - void uabal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned absolute difference and accumulate long (second part). - void uabal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed absolute difference long. - void sabdl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed absolute difference long (second part). - void sabdl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned absolute difference long. - void uabdl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned absolute difference long (second part). - void uabdl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Polynomial multiply long. - void pmull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Polynomial multiply long (second part). - void pmull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed long multiply-add. - void smlal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed long multiply-add (second part). - void smlal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned long multiply-add. - void umlal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned long multiply-add (second part). - void umlal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed long multiply-sub. - void smlsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed long multiply-sub (second part). - void smlsl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned long multiply-sub. - void umlsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned long multiply-sub (second part). - void umlsl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed long multiply. - void smull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed long multiply (second part). - void smull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling long multiply-add. - void sqdmlal(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling long multiply-add (second part). - void sqdmlal2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling long multiply-subtract. - void sqdmlsl(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling long multiply-subtract (second part). - void sqdmlsl2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling long multiply. - void sqdmull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling long multiply (second part). - void sqdmull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling multiply returning high half. - void sqdmulh(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating rounding doubling multiply returning high half. - void sqrdmulh(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Signed saturating doubling multiply element returning high half. - void sqdmulh(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Signed saturating rounding doubling multiply element returning high half. - void sqrdmulh(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // Unsigned long multiply long. - void umull(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Unsigned long multiply (second part). - void umull2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Add narrow returning high half. - void addhn(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Add narrow returning high half (second part). - void addhn2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Rounding add narrow returning high half. - void raddhn(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Rounding add narrow returning high half (second part). - void raddhn2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Subtract narrow returning high half. - void subhn(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Subtract narrow returning high half (second part). - void subhn2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Rounding subtract narrow returning high half. - void rsubhn(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // Rounding subtract narrow returning high half (second part). - void rsubhn2(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP vector multiply accumulate. - void fmla(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP vector multiply subtract. - void fmls(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP vector multiply extended. - void fmulx(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP absolute greater than or equal. - void facge(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP absolute greater than. - void facgt(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP multiply by element. - void fmul(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // FP fused multiply-add to accumulator by element. - void fmla(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // FP fused multiply-sub from accumulator by element. - void fmls(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // FP multiply extended by element. - void fmulx(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index); - - // FP compare equal. - void fcmeq(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP greater than. - void fcmgt(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP greater than or equal. - void fcmge(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP compare equal to zero. - void fcmeq(const VRegister& vd, - const VRegister& vn, - double imm); - - // FP greater than zero. - void fcmgt(const VRegister& vd, - const VRegister& vn, - double imm); - - // FP greater than or equal to zero. - void fcmge(const VRegister& vd, - const VRegister& vn, - double imm); - - // FP less than or equal to zero. - void fcmle(const VRegister& vd, - const VRegister& vn, - double imm); - - // FP less than to zero. - void fcmlt(const VRegister& vd, - const VRegister& vn, - double imm); - - // FP absolute difference. - void fabd(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP pairwise add vector. - void faddp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP pairwise add scalar. - void faddp(const VRegister& vd, - const VRegister& vn); - - // FP pairwise maximum vector. - void fmaxp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP pairwise maximum scalar. - void fmaxp(const VRegister& vd, - const VRegister& vn); - - // FP pairwise minimum vector. - void fminp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP pairwise minimum scalar. - void fminp(const VRegister& vd, - const VRegister& vn); - - // FP pairwise maximum number vector. - void fmaxnmp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP pairwise maximum number scalar. - void fmaxnmp(const VRegister& vd, - const VRegister& vn); - - // FP pairwise minimum number vector. - void fminnmp(const VRegister& vd, - const VRegister& vn, - const VRegister& vm); - - // FP pairwise minimum number scalar. - void fminnmp(const VRegister& vd, - const VRegister& vn); - - // Emit generic instructions. - // Emit raw instructions into the instruction stream. - void dci(Instr raw_inst) { Emit(raw_inst); } - - // Emit 32 bits of data into the instruction stream. - void dc32(uint32_t data) { - VIXL_ASSERT(buffer_monitor_ > 0); - buffer_->Emit32(data); - } - - // Emit 64 bits of data into the instruction stream. - void dc64(uint64_t data) { - VIXL_ASSERT(buffer_monitor_ > 0); - buffer_->Emit64(data); - } - - // Copy a string into the instruction stream, including the terminating NULL - // character. The instruction pointer is then aligned correctly for - // subsequent instructions. - void EmitString(const char * string) { - VIXL_ASSERT(string != NULL); - VIXL_ASSERT(buffer_monitor_ > 0); - - buffer_->EmitString(string); - buffer_->Align(); - } - - // Code generation helpers. - - // Register encoding. - static Instr Rd(CPURegister rd) { - VIXL_ASSERT(rd.code() != kSPRegInternalCode); - return rd.code() << Rd_offset; - } - - static Instr Rn(CPURegister rn) { - VIXL_ASSERT(rn.code() != kSPRegInternalCode); - return rn.code() << Rn_offset; - } - - static Instr Rm(CPURegister rm) { - VIXL_ASSERT(rm.code() != kSPRegInternalCode); - return rm.code() << Rm_offset; - } - - static Instr RmNot31(CPURegister rm) { - VIXL_ASSERT(rm.code() != kSPRegInternalCode); - VIXL_ASSERT(!rm.IsZero()); - return Rm(rm); - } - - static Instr Ra(CPURegister ra) { - VIXL_ASSERT(ra.code() != kSPRegInternalCode); - return ra.code() << Ra_offset; - } - - static Instr Rt(CPURegister rt) { - VIXL_ASSERT(rt.code() != kSPRegInternalCode); - return rt.code() << Rt_offset; - } - - static Instr Rt2(CPURegister rt2) { - VIXL_ASSERT(rt2.code() != kSPRegInternalCode); - return rt2.code() << Rt2_offset; - } - - static Instr Rs(CPURegister rs) { - VIXL_ASSERT(rs.code() != kSPRegInternalCode); - return rs.code() << Rs_offset; - } - - // These encoding functions allow the stack pointer to be encoded, and - // disallow the zero register. - static Instr RdSP(Register rd) { - VIXL_ASSERT(!rd.IsZero()); - return (rd.code() & kRegCodeMask) << Rd_offset; - } - - static Instr RnSP(Register rn) { - VIXL_ASSERT(!rn.IsZero()); - return (rn.code() & kRegCodeMask) << Rn_offset; - } - - // Flags encoding. - static Instr Flags(FlagsUpdate S) { - if (S == SetFlags) { - return 1 << FlagsUpdate_offset; - } else if (S == LeaveFlags) { - return 0 << FlagsUpdate_offset; - } - VIXL_UNREACHABLE(); - return 0; - } - - static Instr Cond(Condition cond) { - return cond << Condition_offset; - } - - // PC-relative address encoding. - static Instr ImmPCRelAddress(int imm21) { - VIXL_ASSERT(is_int21(imm21)); - Instr imm = static_cast(truncate_to_int21(imm21)); - Instr immhi = (imm >> ImmPCRelLo_width) << ImmPCRelHi_offset; - Instr immlo = imm << ImmPCRelLo_offset; - return (immhi & ImmPCRelHi_mask) | (immlo & ImmPCRelLo_mask); - } - - // Branch encoding. - static Instr ImmUncondBranch(int imm26) { - VIXL_ASSERT(is_int26(imm26)); - return truncate_to_int26(imm26) << ImmUncondBranch_offset; - } - - static Instr ImmCondBranch(int imm19) { - VIXL_ASSERT(is_int19(imm19)); - return truncate_to_int19(imm19) << ImmCondBranch_offset; - } - - static Instr ImmCmpBranch(int imm19) { - VIXL_ASSERT(is_int19(imm19)); - return truncate_to_int19(imm19) << ImmCmpBranch_offset; - } - - static Instr ImmTestBranch(int imm14) { - VIXL_ASSERT(is_int14(imm14)); - return truncate_to_int14(imm14) << ImmTestBranch_offset; - } - - static Instr ImmTestBranchBit(unsigned bit_pos) { - VIXL_ASSERT(is_uint6(bit_pos)); - // Subtract five from the shift offset, as we need bit 5 from bit_pos. - unsigned b5 = bit_pos << (ImmTestBranchBit5_offset - 5); - unsigned b40 = bit_pos << ImmTestBranchBit40_offset; - b5 &= ImmTestBranchBit5_mask; - b40 &= ImmTestBranchBit40_mask; - return b5 | b40; - } - - // Data Processing encoding. - static Instr SF(Register rd) { - return rd.Is64Bits() ? SixtyFourBits : ThirtyTwoBits; - } - - static Instr ImmAddSub(int imm) { - VIXL_ASSERT(IsImmAddSub(imm)); - if (is_uint12(imm)) { // No shift required. - imm <<= ImmAddSub_offset; - } else { - imm = ((imm >> 12) << ImmAddSub_offset) | (1 << ShiftAddSub_offset); - } - return imm; - } - - static Instr ImmS(unsigned imms, unsigned reg_size) { - VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(imms)) || - ((reg_size == kWRegSize) && is_uint5(imms))); - USE(reg_size); - return imms << ImmS_offset; - } - - static Instr ImmR(unsigned immr, unsigned reg_size) { - VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || - ((reg_size == kWRegSize) && is_uint5(immr))); - USE(reg_size); - VIXL_ASSERT(is_uint6(immr)); - return immr << ImmR_offset; - } - - static Instr ImmSetBits(unsigned imms, unsigned reg_size) { - VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - VIXL_ASSERT(is_uint6(imms)); - VIXL_ASSERT((reg_size == kXRegSize) || is_uint6(imms + 3)); - USE(reg_size); - return imms << ImmSetBits_offset; - } - - static Instr ImmRotate(unsigned immr, unsigned reg_size) { - VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || - ((reg_size == kWRegSize) && is_uint5(immr))); - USE(reg_size); - return immr << ImmRotate_offset; - } - - static Instr ImmLLiteral(int imm19) { - VIXL_ASSERT(is_int19(imm19)); - return truncate_to_int19(imm19) << ImmLLiteral_offset; - } - - static Instr BitN(unsigned bitn, unsigned reg_size) { - VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - VIXL_ASSERT((reg_size == kXRegSize) || (bitn == 0)); - USE(reg_size); - return bitn << BitN_offset; - } - - static Instr ShiftDP(Shift shift) { - VIXL_ASSERT(shift == LSL || shift == LSR || shift == ASR || shift == ROR); - return shift << ShiftDP_offset; - } - - static Instr ImmDPShift(unsigned amount) { - VIXL_ASSERT(is_uint6(amount)); - return amount << ImmDPShift_offset; - } - - static Instr ExtendMode(Extend extend) { - return extend << ExtendMode_offset; - } - - static Instr ImmExtendShift(unsigned left_shift) { - VIXL_ASSERT(left_shift <= 4); - return left_shift << ImmExtendShift_offset; - } - - static Instr ImmCondCmp(unsigned imm) { - VIXL_ASSERT(is_uint5(imm)); - return imm << ImmCondCmp_offset; - } - - static Instr Nzcv(StatusFlags nzcv) { - return ((nzcv >> Flags_offset) & 0xf) << Nzcv_offset; - } - - // MemOperand offset encoding. - static Instr ImmLSUnsigned(int imm12) { - VIXL_ASSERT(is_uint12(imm12)); - return imm12 << ImmLSUnsigned_offset; - } - - static Instr ImmLS(int imm9) { - VIXL_ASSERT(is_int9(imm9)); - return truncate_to_int9(imm9) << ImmLS_offset; - } - - static Instr ImmLSPair(int imm7, unsigned access_size) { - VIXL_ASSERT(((imm7 >> access_size) << access_size) == imm7); - int scaled_imm7 = imm7 >> access_size; - VIXL_ASSERT(is_int7(scaled_imm7)); - return truncate_to_int7(scaled_imm7) << ImmLSPair_offset; - } - - static Instr ImmShiftLS(unsigned shift_amount) { - VIXL_ASSERT(is_uint1(shift_amount)); - return shift_amount << ImmShiftLS_offset; - } - - static Instr ImmPrefetchOperation(int imm5) { - VIXL_ASSERT(is_uint5(imm5)); - return imm5 << ImmPrefetchOperation_offset; - } - - static Instr ImmException(int imm16) { - VIXL_ASSERT(is_uint16(imm16)); - return imm16 << ImmException_offset; - } - - static Instr ImmSystemRegister(int imm15) { - VIXL_ASSERT(is_uint15(imm15)); - return imm15 << ImmSystemRegister_offset; - } - - static Instr ImmHint(int imm7) { - VIXL_ASSERT(is_uint7(imm7)); - return imm7 << ImmHint_offset; - } - - static Instr CRm(int imm4) { - VIXL_ASSERT(is_uint4(imm4)); - return imm4 << CRm_offset; - } - - static Instr CRn(int imm4) { - VIXL_ASSERT(is_uint4(imm4)); - return imm4 << CRn_offset; - } - - static Instr SysOp(int imm14) { - VIXL_ASSERT(is_uint14(imm14)); - return imm14 << SysOp_offset; - } - - static Instr ImmSysOp1(int imm3) { - VIXL_ASSERT(is_uint3(imm3)); - return imm3 << SysOp1_offset; - } - - static Instr ImmSysOp2(int imm3) { - VIXL_ASSERT(is_uint3(imm3)); - return imm3 << SysOp2_offset; - } - - static Instr ImmBarrierDomain(int imm2) { - VIXL_ASSERT(is_uint2(imm2)); - return imm2 << ImmBarrierDomain_offset; - } - - static Instr ImmBarrierType(int imm2) { - VIXL_ASSERT(is_uint2(imm2)); - return imm2 << ImmBarrierType_offset; - } - - // Move immediates encoding. - static Instr ImmMoveWide(uint64_t imm) { - VIXL_ASSERT(is_uint16(imm)); - return static_cast(imm << ImmMoveWide_offset); - } - - static Instr ShiftMoveWide(int64_t shift) { - VIXL_ASSERT(is_uint2(shift)); - return static_cast(shift << ShiftMoveWide_offset); - } - - // FP Immediates. - static Instr ImmFP32(float imm); - static Instr ImmFP64(double imm); - - // FP register type. - static Instr FPType(FPRegister fd) { - return fd.Is64Bits() ? FP64 : FP32; - } - - static Instr FPScale(unsigned scale) { - VIXL_ASSERT(is_uint6(scale)); - return scale << FPScale_offset; - } - - // Immediate field checking helpers. - static bool IsImmAddSub(int64_t immediate); - static bool IsImmConditionalCompare(int64_t immediate); - static bool IsImmFP32(float imm); - static bool IsImmFP64(double imm); - static bool IsImmLogical(uint64_t value, - unsigned width, - unsigned* n = NULL, - unsigned* imm_s = NULL, - unsigned* imm_r = NULL); - static bool IsImmLSPair(int64_t offset, unsigned access_size); - static bool IsImmLSScaled(int64_t offset, unsigned access_size); - static bool IsImmLSUnscaled(int64_t offset); - static bool IsImmMovn(uint64_t imm, unsigned reg_size); - static bool IsImmMovz(uint64_t imm, unsigned reg_size); - - // Instruction bits for vector format in data processing operations. - static Instr VFormat(VRegister vd) { - if (vd.Is64Bits()) { - switch (vd.lanes()) { - case 2: return NEON_2S; - case 4: return NEON_4H; - case 8: return NEON_8B; - default: return 0xffffffff; - } - } else { - VIXL_ASSERT(vd.Is128Bits()); - switch (vd.lanes()) { - case 2: return NEON_2D; - case 4: return NEON_4S; - case 8: return NEON_8H; - case 16: return NEON_16B; - default: return 0xffffffff; - } - } - } - - // Instruction bits for vector format in floating point data processing - // operations. - static Instr FPFormat(VRegister vd) { - if (vd.lanes() == 1) { - // Floating point scalar formats. - VIXL_ASSERT(vd.Is32Bits() || vd.Is64Bits()); - return vd.Is64Bits() ? FP64 : FP32; - } - - // Two lane floating point vector formats. - if (vd.lanes() == 2) { - VIXL_ASSERT(vd.Is64Bits() || vd.Is128Bits()); - return vd.Is128Bits() ? NEON_FP_2D : NEON_FP_2S; - } - - // Four lane floating point vector format. - VIXL_ASSERT((vd.lanes() == 4) && vd.Is128Bits()); - return NEON_FP_4S; - } - - // Instruction bits for vector format in load and store operations. - static Instr LSVFormat(VRegister vd) { - if (vd.Is64Bits()) { - switch (vd.lanes()) { - case 1: return LS_NEON_1D; - case 2: return LS_NEON_2S; - case 4: return LS_NEON_4H; - case 8: return LS_NEON_8B; - default: return 0xffffffff; - } - } else { - VIXL_ASSERT(vd.Is128Bits()); - switch (vd.lanes()) { - case 2: return LS_NEON_2D; - case 4: return LS_NEON_4S; - case 8: return LS_NEON_8H; - case 16: return LS_NEON_16B; - default: return 0xffffffff; - } - } - } - - // Instruction bits for scalar format in data processing operations. - static Instr SFormat(VRegister vd) { - VIXL_ASSERT(vd.lanes() == 1); - switch (vd.SizeInBytes()) { - case 1: return NEON_B; - case 2: return NEON_H; - case 4: return NEON_S; - case 8: return NEON_D; - default: return 0xffffffff; - } - } - - static Instr ImmNEONHLM(int index, int num_bits) { - int h, l, m; - if (num_bits == 3) { - VIXL_ASSERT(is_uint3(index)); - h = (index >> 2) & 1; - l = (index >> 1) & 1; - m = (index >> 0) & 1; - } else if (num_bits == 2) { - VIXL_ASSERT(is_uint2(index)); - h = (index >> 1) & 1; - l = (index >> 0) & 1; - m = 0; - } else { - VIXL_ASSERT(is_uint1(index) && (num_bits == 1)); - h = (index >> 0) & 1; - l = 0; - m = 0; - } - return (h << NEONH_offset) | (l << NEONL_offset) | (m << NEONM_offset); - } - - static Instr ImmNEONExt(int imm4) { - VIXL_ASSERT(is_uint4(imm4)); - return imm4 << ImmNEONExt_offset; - } - - static Instr ImmNEON5(Instr format, int index) { - VIXL_ASSERT(is_uint4(index)); - int s = LaneSizeInBytesLog2FromFormat(static_cast(format)); - int imm5 = (index << (s + 1)) | (1 << s); - return imm5 << ImmNEON5_offset; - } - - static Instr ImmNEON4(Instr format, int index) { - VIXL_ASSERT(is_uint4(index)); - int s = LaneSizeInBytesLog2FromFormat(static_cast(format)); - int imm4 = index << s; - return imm4 << ImmNEON4_offset; - } - - static Instr ImmNEONabcdefgh(int imm8) { - VIXL_ASSERT(is_uint8(imm8)); - Instr instr; - instr = ((imm8 >> 5) & 7) << ImmNEONabc_offset; - instr |= (imm8 & 0x1f) << ImmNEONdefgh_offset; - return instr; - } - - static Instr NEONCmode(int cmode) { - VIXL_ASSERT(is_uint4(cmode)); - return cmode << NEONCmode_offset; - } - - static Instr NEONModImmOp(int op) { - VIXL_ASSERT(is_uint1(op)); - return op << NEONModImmOp_offset; - } - - // Size of the code generated since label to the current position. - size_t SizeOfCodeGeneratedSince(Label* label) const { - VIXL_ASSERT(label->IsBound()); - return buffer_->OffsetFrom(label->location()); - } - - size_t SizeOfCodeGenerated() const { - return buffer_->CursorOffset(); - } - - size_t BufferCapacity() const { return buffer_->capacity(); } - - size_t RemainingBufferSpace() const { return buffer_->RemainingBytes(); } - - void EnsureSpaceFor(size_t amount) { - if (buffer_->RemainingBytes() < amount) { - size_t capacity = buffer_->capacity(); - size_t size = buffer_->CursorOffset(); - do { - // TODO(all): refine. - capacity *= 2; - } while ((capacity - size) < amount); - buffer_->Grow(capacity); - } - } - -#ifdef VIXL_DEBUG - void AcquireBuffer() { - VIXL_ASSERT(buffer_monitor_ >= 0); - buffer_monitor_++; - } - - void ReleaseBuffer() { - buffer_monitor_--; - VIXL_ASSERT(buffer_monitor_ >= 0); - } -#endif - - PositionIndependentCodeOption pic() const { - return pic_; - } - - bool AllowPageOffsetDependentCode() const { - return (pic() == PageOffsetDependentCode) || - (pic() == PositionDependentCode); - } - - static const Register& AppropriateZeroRegFor(const CPURegister& reg) { - return reg.Is64Bits() ? xzr : wzr; - } - - - protected: - void LoadStore(const CPURegister& rt, - const MemOperand& addr, - LoadStoreOp op, - LoadStoreScalingOption option = PreferScaledOffset); - - void LoadStorePair(const CPURegister& rt, - const CPURegister& rt2, - const MemOperand& addr, - LoadStorePairOp op); - void LoadStoreStruct(const VRegister& vt, - const MemOperand& addr, - NEONLoadStoreMultiStructOp op); - void LoadStoreStruct1(const VRegister& vt, - int reg_count, - const MemOperand& addr); - void LoadStoreStructSingle(const VRegister& vt, - uint32_t lane, - const MemOperand& addr, - NEONLoadStoreSingleStructOp op); - void LoadStoreStructSingleAllLanes(const VRegister& vt, - const MemOperand& addr, - NEONLoadStoreSingleStructOp op); - void LoadStoreStructVerify(const VRegister& vt, - const MemOperand& addr, - Instr op); - - void Prefetch(PrefetchOperation op, - const MemOperand& addr, - LoadStoreScalingOption option = PreferScaledOffset); - - // TODO(all): The third parameter should be passed by reference but gcc 4.8.2 - // reports a bogus uninitialised warning then. - void Logical(const Register& rd, - const Register& rn, - const Operand operand, - LogicalOp op); - void LogicalImmediate(const Register& rd, - const Register& rn, - unsigned n, - unsigned imm_s, - unsigned imm_r, - LogicalOp op); - - void ConditionalCompare(const Register& rn, - const Operand& operand, - StatusFlags nzcv, - Condition cond, - ConditionalCompareOp op); - - void AddSubWithCarry(const Register& rd, - const Register& rn, - const Operand& operand, - FlagsUpdate S, - AddSubWithCarryOp op); - - - // Functions for emulating operands not directly supported by the instruction - // set. - void EmitShift(const Register& rd, - const Register& rn, - Shift shift, - unsigned amount); - void EmitExtendShift(const Register& rd, - const Register& rn, - Extend extend, - unsigned left_shift); - - void AddSub(const Register& rd, - const Register& rn, - const Operand& operand, - FlagsUpdate S, - AddSubOp op); - - void NEONTable(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - NEONTableOp op); - - // Find an appropriate LoadStoreOp or LoadStorePairOp for the specified - // registers. Only simple loads are supported; sign- and zero-extension (such - // as in LDPSW_x or LDRB_w) are not supported. - static LoadStoreOp LoadOpFor(const CPURegister& rt); - static LoadStorePairOp LoadPairOpFor(const CPURegister& rt, - const CPURegister& rt2); - static LoadStoreOp StoreOpFor(const CPURegister& rt); - static LoadStorePairOp StorePairOpFor(const CPURegister& rt, - const CPURegister& rt2); - static LoadStorePairNonTemporalOp LoadPairNonTemporalOpFor( - const CPURegister& rt, const CPURegister& rt2); - static LoadStorePairNonTemporalOp StorePairNonTemporalOpFor( - const CPURegister& rt, const CPURegister& rt2); - static LoadLiteralOp LoadLiteralOpFor(const CPURegister& rt); - - - private: - static uint32_t FP32ToImm8(float imm); - static uint32_t FP64ToImm8(double imm); - - // Instruction helpers. - void MoveWide(const Register& rd, - uint64_t imm, - int shift, - MoveWideImmediateOp mov_op); - void DataProcShiftedRegister(const Register& rd, - const Register& rn, - const Operand& operand, - FlagsUpdate S, - Instr op); - void DataProcExtendedRegister(const Register& rd, - const Register& rn, - const Operand& operand, - FlagsUpdate S, - Instr op); - void LoadStorePairNonTemporal(const CPURegister& rt, - const CPURegister& rt2, - const MemOperand& addr, - LoadStorePairNonTemporalOp op); - void LoadLiteral(const CPURegister& rt, uint64_t imm, LoadLiteralOp op); - void ConditionalSelect(const Register& rd, - const Register& rn, - const Register& rm, - Condition cond, - ConditionalSelectOp op); - void DataProcessing1Source(const Register& rd, - const Register& rn, - DataProcessing1SourceOp op); - void DataProcessing3Source(const Register& rd, - const Register& rn, - const Register& rm, - const Register& ra, - DataProcessing3SourceOp op); - void FPDataProcessing1Source(const VRegister& fd, - const VRegister& fn, - FPDataProcessing1SourceOp op); - void FPDataProcessing3Source(const VRegister& fd, - const VRegister& fn, - const VRegister& fm, - const VRegister& fa, - FPDataProcessing3SourceOp op); - void NEONAcrossLanesL(const VRegister& vd, - const VRegister& vn, - NEONAcrossLanesOp op); - void NEONAcrossLanes(const VRegister& vd, - const VRegister& vn, - NEONAcrossLanesOp op); - void NEONModifiedImmShiftLsl(const VRegister& vd, - const int imm8, - const int left_shift, - NEONModifiedImmediateOp op); - void NEONModifiedImmShiftMsl(const VRegister& vd, - const int imm8, - const int shift_amount, - NEONModifiedImmediateOp op); - void NEONFP2Same(const VRegister& vd, - const VRegister& vn, - Instr vop); - void NEON3Same(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - NEON3SameOp vop); - void NEONFP3Same(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - Instr op); - void NEON3DifferentL(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - NEON3DifferentOp vop); - void NEON3DifferentW(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - NEON3DifferentOp vop); - void NEON3DifferentHN(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - NEON3DifferentOp vop); - void NEONFP2RegMisc(const VRegister& vd, - const VRegister& vn, - NEON2RegMiscOp vop, - double value = 0.0); - void NEON2RegMisc(const VRegister& vd, - const VRegister& vn, - NEON2RegMiscOp vop, - int value = 0); - void NEONFP2RegMisc(const VRegister& vd, - const VRegister& vn, - Instr op); - void NEONAddlp(const VRegister& vd, - const VRegister& vn, - NEON2RegMiscOp op); - void NEONPerm(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - NEONPermOp op); - void NEONFPByElement(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index, - NEONByIndexedElementOp op); - void NEONByElement(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index, - NEONByIndexedElementOp op); - void NEONByElementL(const VRegister& vd, - const VRegister& vn, - const VRegister& vm, - int vm_index, - NEONByIndexedElementOp op); - void NEONShiftImmediate(const VRegister& vd, - const VRegister& vn, - NEONShiftImmediateOp op, - int immh_immb); - void NEONShiftLeftImmediate(const VRegister& vd, - const VRegister& vn, - int shift, - NEONShiftImmediateOp op); - void NEONShiftRightImmediate(const VRegister& vd, - const VRegister& vn, - int shift, - NEONShiftImmediateOp op); - void NEONShiftImmediateL(const VRegister& vd, - const VRegister& vn, - int shift, - NEONShiftImmediateOp op); - void NEONShiftImmediateN(const VRegister& vd, - const VRegister& vn, - int shift, - NEONShiftImmediateOp op); - void NEONXtn(const VRegister& vd, - const VRegister& vn, - NEON2RegMiscOp vop); - - Instr LoadStoreStructAddrModeField(const MemOperand& addr); - - // Encode the specified MemOperand for the specified access size and scaling - // preference. - Instr LoadStoreMemOperand(const MemOperand& addr, - unsigned access_size, - LoadStoreScalingOption option); - - // Link the current (not-yet-emitted) instruction to the specified label, then - // return an offset to be encoded in the instruction. If the label is not yet - // bound, an offset of 0 is returned. - ptrdiff_t LinkAndGetByteOffsetTo(Label * label); - ptrdiff_t LinkAndGetInstructionOffsetTo(Label * label); - ptrdiff_t LinkAndGetPageOffsetTo(Label * label); - - // A common implementation for the LinkAndGetOffsetTo helpers. - template - ptrdiff_t LinkAndGetOffsetTo(Label* label); - - // Literal load offset are in words (32-bit). - ptrdiff_t LinkAndGetWordOffsetTo(RawLiteral* literal); - - // Emit the instruction in buffer_. - void Emit(Instr instruction) { - VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize); - VIXL_ASSERT(buffer_monitor_ > 0); - buffer_->Emit32(instruction); - } - - // Buffer where the code is emitted. - CodeBuffer* buffer_; - PositionIndependentCodeOption pic_; - -#ifdef VIXL_DEBUG - int64_t buffer_monitor_; -#endif -}; - - -// All Assembler emits MUST acquire/release the underlying code buffer. The -// helper scope below will do so and optionally ensure the buffer is big enough -// to receive the emit. It is possible to request the scope not to perform any -// checks (kNoCheck) if for example it is known in advance the buffer size is -// adequate or there is some other size checking mechanism in place. -class CodeBufferCheckScope { - public: - // Tell whether or not the scope needs to ensure the associated CodeBuffer - // has enough space for the requested size. - enum CheckPolicy { - kNoCheck, - kCheck - }; - - // Tell whether or not the scope should assert the amount of code emitted - // within the scope is consistent with the requested amount. - enum AssertPolicy { - kNoAssert, // No assert required. - kExactSize, // The code emitted must be exactly size bytes. - kMaximumSize // The code emitted must be at most size bytes. - }; - - CodeBufferCheckScope(Assembler* assm, - size_t size, - CheckPolicy check_policy = kCheck, - AssertPolicy assert_policy = kMaximumSize) - : assm_(assm) { - if (check_policy == kCheck) assm->EnsureSpaceFor(size); -#ifdef VIXL_DEBUG - assm->bind(&start_); - size_ = size; - assert_policy_ = assert_policy; - assm->AcquireBuffer(); -#else - USE(assert_policy); -#endif - } - - // This is a shortcut for CodeBufferCheckScope(assm, 0, kNoCheck, kNoAssert). - explicit CodeBufferCheckScope(Assembler* assm) : assm_(assm) { -#ifdef VIXL_DEBUG - size_ = 0; - assert_policy_ = kNoAssert; - assm->AcquireBuffer(); -#endif - } - - ~CodeBufferCheckScope() { -#ifdef VIXL_DEBUG - assm_->ReleaseBuffer(); - switch (assert_policy_) { - case kNoAssert: break; - case kExactSize: - VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) == size_); - break; - case kMaximumSize: - VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) <= size_); - break; - default: - VIXL_UNREACHABLE(); - } -#endif - } - - protected: - Assembler* assm_; -#ifdef VIXL_DEBUG - Label start_; - size_t size_; - AssertPolicy assert_policy_; -#endif -}; - - -template -void Literal::UpdateValue(T new_value, const Assembler* assembler) { - return UpdateValue(new_value, assembler->GetStartAddress()); -} - - -template -void Literal::UpdateValue(T high64, T low64, const Assembler* assembler) { - return UpdateValue(high64, low64, assembler->GetStartAddress()); -} - - -} // namespace vixl - -#endif // VIXL_A64_ASSEMBLER_A64_H_ diff --git a/disas/libvixl/vixl/a64/constants-a64.h b/disas/libvixl/vixl/a64/constants-a64.h deleted file mode 100644 index 2caa73af87f2..000000000000 --- a/disas/libvixl/vixl/a64/constants-a64.h +++ /dev/null @@ -1,2116 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_A64_CONSTANTS_A64_H_ -#define VIXL_A64_CONSTANTS_A64_H_ - -namespace vixl { - -const unsigned kNumberOfRegisters = 32; -const unsigned kNumberOfVRegisters = 32; -const unsigned kNumberOfFPRegisters = kNumberOfVRegisters; -// Callee saved registers are x21-x30(lr). -const int kNumberOfCalleeSavedRegisters = 10; -const int kFirstCalleeSavedRegisterIndex = 21; -// Callee saved FP registers are d8-d15. -const int kNumberOfCalleeSavedFPRegisters = 8; -const int kFirstCalleeSavedFPRegisterIndex = 8; - -#define REGISTER_CODE_LIST(R) \ -R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ -R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ -R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ -R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) - -#define INSTRUCTION_FIELDS_LIST(V_) \ -/* Register fields */ \ -V_(Rd, 4, 0, Bits) /* Destination register. */ \ -V_(Rn, 9, 5, Bits) /* First source register. */ \ -V_(Rm, 20, 16, Bits) /* Second source register. */ \ -V_(Ra, 14, 10, Bits) /* Third source register. */ \ -V_(Rt, 4, 0, Bits) /* Load/store register. */ \ -V_(Rt2, 14, 10, Bits) /* Load/store second register. */ \ -V_(Rs, 20, 16, Bits) /* Exclusive access status. */ \ - \ -/* Common bits */ \ -V_(SixtyFourBits, 31, 31, Bits) \ -V_(FlagsUpdate, 29, 29, Bits) \ - \ -/* PC relative addressing */ \ -V_(ImmPCRelHi, 23, 5, SignedBits) \ -V_(ImmPCRelLo, 30, 29, Bits) \ - \ -/* Add/subtract/logical shift register */ \ -V_(ShiftDP, 23, 22, Bits) \ -V_(ImmDPShift, 15, 10, Bits) \ - \ -/* Add/subtract immediate */ \ -V_(ImmAddSub, 21, 10, Bits) \ -V_(ShiftAddSub, 23, 22, Bits) \ - \ -/* Add/substract extend */ \ -V_(ImmExtendShift, 12, 10, Bits) \ -V_(ExtendMode, 15, 13, Bits) \ - \ -/* Move wide */ \ -V_(ImmMoveWide, 20, 5, Bits) \ -V_(ShiftMoveWide, 22, 21, Bits) \ - \ -/* Logical immediate, bitfield and extract */ \ -V_(BitN, 22, 22, Bits) \ -V_(ImmRotate, 21, 16, Bits) \ -V_(ImmSetBits, 15, 10, Bits) \ -V_(ImmR, 21, 16, Bits) \ -V_(ImmS, 15, 10, Bits) \ - \ -/* Test and branch immediate */ \ -V_(ImmTestBranch, 18, 5, SignedBits) \ -V_(ImmTestBranchBit40, 23, 19, Bits) \ -V_(ImmTestBranchBit5, 31, 31, Bits) \ - \ -/* Conditionals */ \ -V_(Condition, 15, 12, Bits) \ -V_(ConditionBranch, 3, 0, Bits) \ -V_(Nzcv, 3, 0, Bits) \ -V_(ImmCondCmp, 20, 16, Bits) \ -V_(ImmCondBranch, 23, 5, SignedBits) \ - \ -/* Floating point */ \ -V_(FPType, 23, 22, Bits) \ -V_(ImmFP, 20, 13, Bits) \ -V_(FPScale, 15, 10, Bits) \ - \ -/* Load Store */ \ -V_(ImmLS, 20, 12, SignedBits) \ -V_(ImmLSUnsigned, 21, 10, Bits) \ -V_(ImmLSPair, 21, 15, SignedBits) \ -V_(ImmShiftLS, 12, 12, Bits) \ -V_(LSOpc, 23, 22, Bits) \ -V_(LSVector, 26, 26, Bits) \ -V_(LSSize, 31, 30, Bits) \ -V_(ImmPrefetchOperation, 4, 0, Bits) \ -V_(PrefetchHint, 4, 3, Bits) \ -V_(PrefetchTarget, 2, 1, Bits) \ -V_(PrefetchStream, 0, 0, Bits) \ - \ -/* Other immediates */ \ -V_(ImmUncondBranch, 25, 0, SignedBits) \ -V_(ImmCmpBranch, 23, 5, SignedBits) \ -V_(ImmLLiteral, 23, 5, SignedBits) \ -V_(ImmException, 20, 5, Bits) \ -V_(ImmHint, 11, 5, Bits) \ -V_(ImmBarrierDomain, 11, 10, Bits) \ -V_(ImmBarrierType, 9, 8, Bits) \ - \ -/* System (MRS, MSR, SYS) */ \ -V_(ImmSystemRegister, 19, 5, Bits) \ -V_(SysO0, 19, 19, Bits) \ -V_(SysOp, 18, 5, Bits) \ -V_(SysOp1, 18, 16, Bits) \ -V_(SysOp2, 7, 5, Bits) \ -V_(CRn, 15, 12, Bits) \ -V_(CRm, 11, 8, Bits) \ - \ -/* Load-/store-exclusive */ \ -V_(LdStXLoad, 22, 22, Bits) \ -V_(LdStXNotExclusive, 23, 23, Bits) \ -V_(LdStXAcquireRelease, 15, 15, Bits) \ -V_(LdStXSizeLog2, 31, 30, Bits) \ -V_(LdStXPair, 21, 21, Bits) \ - \ -/* NEON generic fields */ \ -V_(NEONQ, 30, 30, Bits) \ -V_(NEONSize, 23, 22, Bits) \ -V_(NEONLSSize, 11, 10, Bits) \ -V_(NEONS, 12, 12, Bits) \ -V_(NEONL, 21, 21, Bits) \ -V_(NEONM, 20, 20, Bits) \ -V_(NEONH, 11, 11, Bits) \ -V_(ImmNEONExt, 14, 11, Bits) \ -V_(ImmNEON5, 20, 16, Bits) \ -V_(ImmNEON4, 14, 11, Bits) \ - \ -/* NEON Modified Immediate fields */ \ -V_(ImmNEONabc, 18, 16, Bits) \ -V_(ImmNEONdefgh, 9, 5, Bits) \ -V_(NEONModImmOp, 29, 29, Bits) \ -V_(NEONCmode, 15, 12, Bits) \ - \ -/* NEON Shift Immediate fields */ \ -V_(ImmNEONImmhImmb, 22, 16, Bits) \ -V_(ImmNEONImmh, 22, 19, Bits) \ -V_(ImmNEONImmb, 18, 16, Bits) - -#define SYSTEM_REGISTER_FIELDS_LIST(V_, M_) \ -/* NZCV */ \ -V_(Flags, 31, 28, Bits) \ -V_(N, 31, 31, Bits) \ -V_(Z, 30, 30, Bits) \ -V_(C, 29, 29, Bits) \ -V_(V, 28, 28, Bits) \ -M_(NZCV, Flags_mask) \ -/* FPCR */ \ -V_(AHP, 26, 26, Bits) \ -V_(DN, 25, 25, Bits) \ -V_(FZ, 24, 24, Bits) \ -V_(RMode, 23, 22, Bits) \ -M_(FPCR, AHP_mask | DN_mask | FZ_mask | RMode_mask) - -// Fields offsets. -#define DECLARE_FIELDS_OFFSETS(Name, HighBit, LowBit, X) \ -const int Name##_offset = LowBit; \ -const int Name##_width = HighBit - LowBit + 1; \ -const uint32_t Name##_mask = ((1 << Name##_width) - 1) << LowBit; -#define NOTHING(A, B) -INSTRUCTION_FIELDS_LIST(DECLARE_FIELDS_OFFSETS) -SYSTEM_REGISTER_FIELDS_LIST(DECLARE_FIELDS_OFFSETS, NOTHING) -#undef NOTHING -#undef DECLARE_FIELDS_BITS - -// ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), formed -// from ImmPCRelLo and ImmPCRelHi. -const int ImmPCRel_mask = ImmPCRelLo_mask | ImmPCRelHi_mask; - -// Condition codes. -enum Condition { - eq = 0, // Z set Equal. - ne = 1, // Z clear Not equal. - cs = 2, // C set Carry set. - cc = 3, // C clear Carry clear. - mi = 4, // N set Negative. - pl = 5, // N clear Positive or zero. - vs = 6, // V set Overflow. - vc = 7, // V clear No overflow. - hi = 8, // C set, Z clear Unsigned higher. - ls = 9, // C clear or Z set Unsigned lower or same. - ge = 10, // N == V Greater or equal. - lt = 11, // N != V Less than. - gt = 12, // Z clear, N == V Greater than. - le = 13, // Z set or N != V Less then or equal - al = 14, // Always. - nv = 15, // Behaves as always/al. - - // Aliases. - hs = cs, // C set Unsigned higher or same. - lo = cc // C clear Unsigned lower. -}; - -inline Condition InvertCondition(Condition cond) { - // Conditions al and nv behave identically, as "always true". They can't be - // inverted, because there is no "always false" condition. - VIXL_ASSERT((cond != al) && (cond != nv)); - return static_cast(cond ^ 1); -} - -enum FPTrapFlags { - EnableTrap = 1, - DisableTrap = 0 -}; - -enum FlagsUpdate { - SetFlags = 1, - LeaveFlags = 0 -}; - -enum StatusFlags { - NoFlag = 0, - - // Derive the flag combinations from the system register bit descriptions. - NFlag = N_mask, - ZFlag = Z_mask, - CFlag = C_mask, - VFlag = V_mask, - NZFlag = NFlag | ZFlag, - NCFlag = NFlag | CFlag, - NVFlag = NFlag | VFlag, - ZCFlag = ZFlag | CFlag, - ZVFlag = ZFlag | VFlag, - CVFlag = CFlag | VFlag, - NZCFlag = NFlag | ZFlag | CFlag, - NZVFlag = NFlag | ZFlag | VFlag, - NCVFlag = NFlag | CFlag | VFlag, - ZCVFlag = ZFlag | CFlag | VFlag, - NZCVFlag = NFlag | ZFlag | CFlag | VFlag, - - // Floating-point comparison results. - FPEqualFlag = ZCFlag, - FPLessThanFlag = NFlag, - FPGreaterThanFlag = CFlag, - FPUnorderedFlag = CVFlag -}; - -enum Shift { - NO_SHIFT = -1, - LSL = 0x0, - LSR = 0x1, - ASR = 0x2, - ROR = 0x3, - MSL = 0x4 -}; - -enum Extend { - NO_EXTEND = -1, - UXTB = 0, - UXTH = 1, - UXTW = 2, - UXTX = 3, - SXTB = 4, - SXTH = 5, - SXTW = 6, - SXTX = 7 -}; - -enum SystemHint { - NOP = 0, - YIELD = 1, - WFE = 2, - WFI = 3, - SEV = 4, - SEVL = 5 -}; - -enum BarrierDomain { - OuterShareable = 0, - NonShareable = 1, - InnerShareable = 2, - FullSystem = 3 -}; - -enum BarrierType { - BarrierOther = 0, - BarrierReads = 1, - BarrierWrites = 2, - BarrierAll = 3 -}; - -enum PrefetchOperation { - PLDL1KEEP = 0x00, - PLDL1STRM = 0x01, - PLDL2KEEP = 0x02, - PLDL2STRM = 0x03, - PLDL3KEEP = 0x04, - PLDL3STRM = 0x05, - - PLIL1KEEP = 0x08, - PLIL1STRM = 0x09, - PLIL2KEEP = 0x0a, - PLIL2STRM = 0x0b, - PLIL3KEEP = 0x0c, - PLIL3STRM = 0x0d, - - PSTL1KEEP = 0x10, - PSTL1STRM = 0x11, - PSTL2KEEP = 0x12, - PSTL2STRM = 0x13, - PSTL3KEEP = 0x14, - PSTL3STRM = 0x15 -}; - -// System/special register names. -// This information is not encoded as one field but as the concatenation of -// multiple fields (Op0<0>, Op1, Crn, Crm, Op2). -enum SystemRegister { - NZCV = ((0x1 << SysO0_offset) | - (0x3 << SysOp1_offset) | - (0x4 << CRn_offset) | - (0x2 << CRm_offset) | - (0x0 << SysOp2_offset)) >> ImmSystemRegister_offset, - FPCR = ((0x1 << SysO0_offset) | - (0x3 << SysOp1_offset) | - (0x4 << CRn_offset) | - (0x4 << CRm_offset) | - (0x0 << SysOp2_offset)) >> ImmSystemRegister_offset -}; - -enum InstructionCacheOp { - IVAU = ((0x3 << SysOp1_offset) | - (0x7 << CRn_offset) | - (0x5 << CRm_offset) | - (0x1 << SysOp2_offset)) >> SysOp_offset -}; - -enum DataCacheOp { - CVAC = ((0x3 << SysOp1_offset) | - (0x7 << CRn_offset) | - (0xa << CRm_offset) | - (0x1 << SysOp2_offset)) >> SysOp_offset, - CVAU = ((0x3 << SysOp1_offset) | - (0x7 << CRn_offset) | - (0xb << CRm_offset) | - (0x1 << SysOp2_offset)) >> SysOp_offset, - CIVAC = ((0x3 << SysOp1_offset) | - (0x7 << CRn_offset) | - (0xe << CRm_offset) | - (0x1 << SysOp2_offset)) >> SysOp_offset, - ZVA = ((0x3 << SysOp1_offset) | - (0x7 << CRn_offset) | - (0x4 << CRm_offset) | - (0x1 << SysOp2_offset)) >> SysOp_offset -}; - -// Instruction enumerations. -// -// These are the masks that define a class of instructions, and the list of -// instructions within each class. Each enumeration has a Fixed, FMask and -// Mask value. -// -// Fixed: The fixed bits in this instruction class. -// FMask: The mask used to extract the fixed bits in the class. -// Mask: The mask used to identify the instructions within a class. -// -// The enumerations can be used like this: -// -// VIXL_ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed); -// switch(instr->Mask(PCRelAddressingMask)) { -// case ADR: Format("adr 'Xd, 'AddrPCRelByte"); break; -// case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break; -// default: printf("Unknown instruction\n"); -// } - - -// Generic fields. -enum GenericInstrField { - SixtyFourBits = 0x80000000, - ThirtyTwoBits = 0x00000000, - FP32 = 0x00000000, - FP64 = 0x00400000 -}; - -enum NEONFormatField { - NEONFormatFieldMask = 0x40C00000, - NEON_Q = 0x40000000, - NEON_8B = 0x00000000, - NEON_16B = NEON_8B | NEON_Q, - NEON_4H = 0x00400000, - NEON_8H = NEON_4H | NEON_Q, - NEON_2S = 0x00800000, - NEON_4S = NEON_2S | NEON_Q, - NEON_1D = 0x00C00000, - NEON_2D = 0x00C00000 | NEON_Q -}; - -enum NEONFPFormatField { - NEONFPFormatFieldMask = 0x40400000, - NEON_FP_2S = FP32, - NEON_FP_4S = FP32 | NEON_Q, - NEON_FP_2D = FP64 | NEON_Q -}; - -enum NEONLSFormatField { - NEONLSFormatFieldMask = 0x40000C00, - LS_NEON_8B = 0x00000000, - LS_NEON_16B = LS_NEON_8B | NEON_Q, - LS_NEON_4H = 0x00000400, - LS_NEON_8H = LS_NEON_4H | NEON_Q, - LS_NEON_2S = 0x00000800, - LS_NEON_4S = LS_NEON_2S | NEON_Q, - LS_NEON_1D = 0x00000C00, - LS_NEON_2D = LS_NEON_1D | NEON_Q -}; - -enum NEONScalarFormatField { - NEONScalarFormatFieldMask = 0x00C00000, - NEONScalar = 0x10000000, - NEON_B = 0x00000000, - NEON_H = 0x00400000, - NEON_S = 0x00800000, - NEON_D = 0x00C00000 -}; - -// PC relative addressing. -enum PCRelAddressingOp { - PCRelAddressingFixed = 0x10000000, - PCRelAddressingFMask = 0x1F000000, - PCRelAddressingMask = 0x9F000000, - ADR = PCRelAddressingFixed | 0x00000000, - ADRP = PCRelAddressingFixed | 0x80000000 -}; - -// Add/sub (immediate, shifted and extended.) -const int kSFOffset = 31; -enum AddSubOp { - AddSubOpMask = 0x60000000, - AddSubSetFlagsBit = 0x20000000, - ADD = 0x00000000, - ADDS = ADD | AddSubSetFlagsBit, - SUB = 0x40000000, - SUBS = SUB | AddSubSetFlagsBit -}; - -#define ADD_SUB_OP_LIST(V) \ - V(ADD), \ - V(ADDS), \ - V(SUB), \ - V(SUBS) - -enum AddSubImmediateOp { - AddSubImmediateFixed = 0x11000000, - AddSubImmediateFMask = 0x1F000000, - AddSubImmediateMask = 0xFF000000, - #define ADD_SUB_IMMEDIATE(A) \ - A##_w_imm = AddSubImmediateFixed | A, \ - A##_x_imm = AddSubImmediateFixed | A | SixtyFourBits - ADD_SUB_OP_LIST(ADD_SUB_IMMEDIATE) - #undef ADD_SUB_IMMEDIATE -}; - -enum AddSubShiftedOp { - AddSubShiftedFixed = 0x0B000000, - AddSubShiftedFMask = 0x1F200000, - AddSubShiftedMask = 0xFF200000, - #define ADD_SUB_SHIFTED(A) \ - A##_w_shift = AddSubShiftedFixed | A, \ - A##_x_shift = AddSubShiftedFixed | A | SixtyFourBits - ADD_SUB_OP_LIST(ADD_SUB_SHIFTED) - #undef ADD_SUB_SHIFTED -}; - -enum AddSubExtendedOp { - AddSubExtendedFixed = 0x0B200000, - AddSubExtendedFMask = 0x1F200000, - AddSubExtendedMask = 0xFFE00000, - #define ADD_SUB_EXTENDED(A) \ - A##_w_ext = AddSubExtendedFixed | A, \ - A##_x_ext = AddSubExtendedFixed | A | SixtyFourBits - ADD_SUB_OP_LIST(ADD_SUB_EXTENDED) - #undef ADD_SUB_EXTENDED -}; - -// Add/sub with carry. -enum AddSubWithCarryOp { - AddSubWithCarryFixed = 0x1A000000, - AddSubWithCarryFMask = 0x1FE00000, - AddSubWithCarryMask = 0xFFE0FC00, - ADC_w = AddSubWithCarryFixed | ADD, - ADC_x = AddSubWithCarryFixed | ADD | SixtyFourBits, - ADC = ADC_w, - ADCS_w = AddSubWithCarryFixed | ADDS, - ADCS_x = AddSubWithCarryFixed | ADDS | SixtyFourBits, - SBC_w = AddSubWithCarryFixed | SUB, - SBC_x = AddSubWithCarryFixed | SUB | SixtyFourBits, - SBC = SBC_w, - SBCS_w = AddSubWithCarryFixed | SUBS, - SBCS_x = AddSubWithCarryFixed | SUBS | SixtyFourBits -}; - - -// Logical (immediate and shifted register). -enum LogicalOp { - LogicalOpMask = 0x60200000, - NOT = 0x00200000, - AND = 0x00000000, - BIC = AND | NOT, - ORR = 0x20000000, - ORN = ORR | NOT, - EOR = 0x40000000, - EON = EOR | NOT, - ANDS = 0x60000000, - BICS = ANDS | NOT -}; - -// Logical immediate. -enum LogicalImmediateOp { - LogicalImmediateFixed = 0x12000000, - LogicalImmediateFMask = 0x1F800000, - LogicalImmediateMask = 0xFF800000, - AND_w_imm = LogicalImmediateFixed | AND, - AND_x_imm = LogicalImmediateFixed | AND | SixtyFourBits, - ORR_w_imm = LogicalImmediateFixed | ORR, - ORR_x_imm = LogicalImmediateFixed | ORR | SixtyFourBits, - EOR_w_imm = LogicalImmediateFixed | EOR, - EOR_x_imm = LogicalImmediateFixed | EOR | SixtyFourBits, - ANDS_w_imm = LogicalImmediateFixed | ANDS, - ANDS_x_imm = LogicalImmediateFixed | ANDS | SixtyFourBits -}; - -// Logical shifted register. -enum LogicalShiftedOp { - LogicalShiftedFixed = 0x0A000000, - LogicalShiftedFMask = 0x1F000000, - LogicalShiftedMask = 0xFF200000, - AND_w = LogicalShiftedFixed | AND, - AND_x = LogicalShiftedFixed | AND | SixtyFourBits, - AND_shift = AND_w, - BIC_w = LogicalShiftedFixed | BIC, - BIC_x = LogicalShiftedFixed | BIC | SixtyFourBits, - BIC_shift = BIC_w, - ORR_w = LogicalShiftedFixed | ORR, - ORR_x = LogicalShiftedFixed | ORR | SixtyFourBits, - ORR_shift = ORR_w, - ORN_w = LogicalShiftedFixed | ORN, - ORN_x = LogicalShiftedFixed | ORN | SixtyFourBits, - ORN_shift = ORN_w, - EOR_w = LogicalShiftedFixed | EOR, - EOR_x = LogicalShiftedFixed | EOR | SixtyFourBits, - EOR_shift = EOR_w, - EON_w = LogicalShiftedFixed | EON, - EON_x = LogicalShiftedFixed | EON | SixtyFourBits, - EON_shift = EON_w, - ANDS_w = LogicalShiftedFixed | ANDS, - ANDS_x = LogicalShiftedFixed | ANDS | SixtyFourBits, - ANDS_shift = ANDS_w, - BICS_w = LogicalShiftedFixed | BICS, - BICS_x = LogicalShiftedFixed | BICS | SixtyFourBits, - BICS_shift = BICS_w -}; - -// Move wide immediate. -enum MoveWideImmediateOp { - MoveWideImmediateFixed = 0x12800000, - MoveWideImmediateFMask = 0x1F800000, - MoveWideImmediateMask = 0xFF800000, - MOVN = 0x00000000, - MOVZ = 0x40000000, - MOVK = 0x60000000, - MOVN_w = MoveWideImmediateFixed | MOVN, - MOVN_x = MoveWideImmediateFixed | MOVN | SixtyFourBits, - MOVZ_w = MoveWideImmediateFixed | MOVZ, - MOVZ_x = MoveWideImmediateFixed | MOVZ | SixtyFourBits, - MOVK_w = MoveWideImmediateFixed | MOVK, - MOVK_x = MoveWideImmediateFixed | MOVK | SixtyFourBits -}; - -// Bitfield. -const int kBitfieldNOffset = 22; -enum BitfieldOp { - BitfieldFixed = 0x13000000, - BitfieldFMask = 0x1F800000, - BitfieldMask = 0xFF800000, - SBFM_w = BitfieldFixed | 0x00000000, - SBFM_x = BitfieldFixed | 0x80000000, - SBFM = SBFM_w, - BFM_w = BitfieldFixed | 0x20000000, - BFM_x = BitfieldFixed | 0xA0000000, - BFM = BFM_w, - UBFM_w = BitfieldFixed | 0x40000000, - UBFM_x = BitfieldFixed | 0xC0000000, - UBFM = UBFM_w - // Bitfield N field. -}; - -// Extract. -enum ExtractOp { - ExtractFixed = 0x13800000, - ExtractFMask = 0x1F800000, - ExtractMask = 0xFFA00000, - EXTR_w = ExtractFixed | 0x00000000, - EXTR_x = ExtractFixed | 0x80000000, - EXTR = EXTR_w -}; - -// Unconditional branch. -enum UnconditionalBranchOp { - UnconditionalBranchFixed = 0x14000000, - UnconditionalBranchFMask = 0x7C000000, - UnconditionalBranchMask = 0xFC000000, - B = UnconditionalBranchFixed | 0x00000000, - BL = UnconditionalBranchFixed | 0x80000000 -}; - -// Unconditional branch to register. -enum UnconditionalBranchToRegisterOp { - UnconditionalBranchToRegisterFixed = 0xD6000000, - UnconditionalBranchToRegisterFMask = 0xFE000000, - UnconditionalBranchToRegisterMask = 0xFFFFFC1F, - BR = UnconditionalBranchToRegisterFixed | 0x001F0000, - BLR = UnconditionalBranchToRegisterFixed | 0x003F0000, - RET = UnconditionalBranchToRegisterFixed | 0x005F0000 -}; - -// Compare and branch. -enum CompareBranchOp { - CompareBranchFixed = 0x34000000, - CompareBranchFMask = 0x7E000000, - CompareBranchMask = 0xFF000000, - CBZ_w = CompareBranchFixed | 0x00000000, - CBZ_x = CompareBranchFixed | 0x80000000, - CBZ = CBZ_w, - CBNZ_w = CompareBranchFixed | 0x01000000, - CBNZ_x = CompareBranchFixed | 0x81000000, - CBNZ = CBNZ_w -}; - -// Test and branch. -enum TestBranchOp { - TestBranchFixed = 0x36000000, - TestBranchFMask = 0x7E000000, - TestBranchMask = 0x7F000000, - TBZ = TestBranchFixed | 0x00000000, - TBNZ = TestBranchFixed | 0x01000000 -}; - -// Conditional branch. -enum ConditionalBranchOp { - ConditionalBranchFixed = 0x54000000, - ConditionalBranchFMask = 0xFE000000, - ConditionalBranchMask = 0xFF000010, - B_cond = ConditionalBranchFixed | 0x00000000 -}; - -// System. -// System instruction encoding is complicated because some instructions use op -// and CR fields to encode parameters. To handle this cleanly, the system -// instructions are split into more than one enum. - -enum SystemOp { - SystemFixed = 0xD5000000, - SystemFMask = 0xFFC00000 -}; - -enum SystemSysRegOp { - SystemSysRegFixed = 0xD5100000, - SystemSysRegFMask = 0xFFD00000, - SystemSysRegMask = 0xFFF00000, - MRS = SystemSysRegFixed | 0x00200000, - MSR = SystemSysRegFixed | 0x00000000 -}; - -enum SystemHintOp { - SystemHintFixed = 0xD503201F, - SystemHintFMask = 0xFFFFF01F, - SystemHintMask = 0xFFFFF01F, - HINT = SystemHintFixed | 0x00000000 -}; - -enum SystemSysOp { - SystemSysFixed = 0xD5080000, - SystemSysFMask = 0xFFF80000, - SystemSysMask = 0xFFF80000, - SYS = SystemSysFixed | 0x00000000 -}; - -// Exception. -enum ExceptionOp { - ExceptionFixed = 0xD4000000, - ExceptionFMask = 0xFF000000, - ExceptionMask = 0xFFE0001F, - HLT = ExceptionFixed | 0x00400000, - BRK = ExceptionFixed | 0x00200000, - SVC = ExceptionFixed | 0x00000001, - HVC = ExceptionFixed | 0x00000002, - SMC = ExceptionFixed | 0x00000003, - DCPS1 = ExceptionFixed | 0x00A00001, - DCPS2 = ExceptionFixed | 0x00A00002, - DCPS3 = ExceptionFixed | 0x00A00003 -}; - -enum MemBarrierOp { - MemBarrierFixed = 0xD503309F, - MemBarrierFMask = 0xFFFFF09F, - MemBarrierMask = 0xFFFFF0FF, - DSB = MemBarrierFixed | 0x00000000, - DMB = MemBarrierFixed | 0x00000020, - ISB = MemBarrierFixed | 0x00000040 -}; - -enum SystemExclusiveMonitorOp { - SystemExclusiveMonitorFixed = 0xD503305F, - SystemExclusiveMonitorFMask = 0xFFFFF0FF, - SystemExclusiveMonitorMask = 0xFFFFF0FF, - CLREX = SystemExclusiveMonitorFixed -}; - -// Any load or store. -enum LoadStoreAnyOp { - LoadStoreAnyFMask = 0x0a000000, - LoadStoreAnyFixed = 0x08000000 -}; - -// Any load pair or store pair. -enum LoadStorePairAnyOp { - LoadStorePairAnyFMask = 0x3a000000, - LoadStorePairAnyFixed = 0x28000000 -}; - -#define LOAD_STORE_PAIR_OP_LIST(V) \ - V(STP, w, 0x00000000), \ - V(LDP, w, 0x00400000), \ - V(LDPSW, x, 0x40400000), \ - V(STP, x, 0x80000000), \ - V(LDP, x, 0x80400000), \ - V(STP, s, 0x04000000), \ - V(LDP, s, 0x04400000), \ - V(STP, d, 0x44000000), \ - V(LDP, d, 0x44400000), \ - V(STP, q, 0x84000000), \ - V(LDP, q, 0x84400000) - -// Load/store pair (post, pre and offset.) -enum LoadStorePairOp { - LoadStorePairMask = 0xC4400000, - LoadStorePairLBit = 1 << 22, - #define LOAD_STORE_PAIR(A, B, C) \ - A##_##B = C - LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR) - #undef LOAD_STORE_PAIR -}; - -enum LoadStorePairPostIndexOp { - LoadStorePairPostIndexFixed = 0x28800000, - LoadStorePairPostIndexFMask = 0x3B800000, - LoadStorePairPostIndexMask = 0xFFC00000, - #define LOAD_STORE_PAIR_POST_INDEX(A, B, C) \ - A##_##B##_post = LoadStorePairPostIndexFixed | A##_##B - LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_POST_INDEX) - #undef LOAD_STORE_PAIR_POST_INDEX -}; - -enum LoadStorePairPreIndexOp { - LoadStorePairPreIndexFixed = 0x29800000, - LoadStorePairPreIndexFMask = 0x3B800000, - LoadStorePairPreIndexMask = 0xFFC00000, - #define LOAD_STORE_PAIR_PRE_INDEX(A, B, C) \ - A##_##B##_pre = LoadStorePairPreIndexFixed | A##_##B - LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_PRE_INDEX) - #undef LOAD_STORE_PAIR_PRE_INDEX -}; - -enum LoadStorePairOffsetOp { - LoadStorePairOffsetFixed = 0x29000000, - LoadStorePairOffsetFMask = 0x3B800000, - LoadStorePairOffsetMask = 0xFFC00000, - #define LOAD_STORE_PAIR_OFFSET(A, B, C) \ - A##_##B##_off = LoadStorePairOffsetFixed | A##_##B - LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_OFFSET) - #undef LOAD_STORE_PAIR_OFFSET -}; - -enum LoadStorePairNonTemporalOp { - LoadStorePairNonTemporalFixed = 0x28000000, - LoadStorePairNonTemporalFMask = 0x3B800000, - LoadStorePairNonTemporalMask = 0xFFC00000, - LoadStorePairNonTemporalLBit = 1 << 22, - STNP_w = LoadStorePairNonTemporalFixed | STP_w, - LDNP_w = LoadStorePairNonTemporalFixed | LDP_w, - STNP_x = LoadStorePairNonTemporalFixed | STP_x, - LDNP_x = LoadStorePairNonTemporalFixed | LDP_x, - STNP_s = LoadStorePairNonTemporalFixed | STP_s, - LDNP_s = LoadStorePairNonTemporalFixed | LDP_s, - STNP_d = LoadStorePairNonTemporalFixed | STP_d, - LDNP_d = LoadStorePairNonTemporalFixed | LDP_d, - STNP_q = LoadStorePairNonTemporalFixed | STP_q, - LDNP_q = LoadStorePairNonTemporalFixed | LDP_q -}; - -// Load literal. -enum LoadLiteralOp { - LoadLiteralFixed = 0x18000000, - LoadLiteralFMask = 0x3B000000, - LoadLiteralMask = 0xFF000000, - LDR_w_lit = LoadLiteralFixed | 0x00000000, - LDR_x_lit = LoadLiteralFixed | 0x40000000, - LDRSW_x_lit = LoadLiteralFixed | 0x80000000, - PRFM_lit = LoadLiteralFixed | 0xC0000000, - LDR_s_lit = LoadLiteralFixed | 0x04000000, - LDR_d_lit = LoadLiteralFixed | 0x44000000, - LDR_q_lit = LoadLiteralFixed | 0x84000000 -}; - -#define LOAD_STORE_OP_LIST(V) \ - V(ST, RB, w, 0x00000000), \ - V(ST, RH, w, 0x40000000), \ - V(ST, R, w, 0x80000000), \ - V(ST, R, x, 0xC0000000), \ - V(LD, RB, w, 0x00400000), \ - V(LD, RH, w, 0x40400000), \ - V(LD, R, w, 0x80400000), \ - V(LD, R, x, 0xC0400000), \ - V(LD, RSB, x, 0x00800000), \ - V(LD, RSH, x, 0x40800000), \ - V(LD, RSW, x, 0x80800000), \ - V(LD, RSB, w, 0x00C00000), \ - V(LD, RSH, w, 0x40C00000), \ - V(ST, R, b, 0x04000000), \ - V(ST, R, h, 0x44000000), \ - V(ST, R, s, 0x84000000), \ - V(ST, R, d, 0xC4000000), \ - V(ST, R, q, 0x04800000), \ - V(LD, R, b, 0x04400000), \ - V(LD, R, h, 0x44400000), \ - V(LD, R, s, 0x84400000), \ - V(LD, R, d, 0xC4400000), \ - V(LD, R, q, 0x04C00000) - -// Load/store (post, pre, offset and unsigned.) -enum LoadStoreOp { - LoadStoreMask = 0xC4C00000, - LoadStoreVMask = 0x04000000, - #define LOAD_STORE(A, B, C, D) \ - A##B##_##C = D - LOAD_STORE_OP_LIST(LOAD_STORE), - #undef LOAD_STORE - PRFM = 0xC0800000 -}; - -// Load/store unscaled offset. -enum LoadStoreUnscaledOffsetOp { - LoadStoreUnscaledOffsetFixed = 0x38000000, - LoadStoreUnscaledOffsetFMask = 0x3B200C00, - LoadStoreUnscaledOffsetMask = 0xFFE00C00, - PRFUM = LoadStoreUnscaledOffsetFixed | PRFM, - #define LOAD_STORE_UNSCALED(A, B, C, D) \ - A##U##B##_##C = LoadStoreUnscaledOffsetFixed | D - LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED) - #undef LOAD_STORE_UNSCALED -}; - -// Load/store post index. -enum LoadStorePostIndex { - LoadStorePostIndexFixed = 0x38000400, - LoadStorePostIndexFMask = 0x3B200C00, - LoadStorePostIndexMask = 0xFFE00C00, - #define LOAD_STORE_POST_INDEX(A, B, C, D) \ - A##B##_##C##_post = LoadStorePostIndexFixed | D - LOAD_STORE_OP_LIST(LOAD_STORE_POST_INDEX) - #undef LOAD_STORE_POST_INDEX -}; - -// Load/store pre index. -enum LoadStorePreIndex { - LoadStorePreIndexFixed = 0x38000C00, - LoadStorePreIndexFMask = 0x3B200C00, - LoadStorePreIndexMask = 0xFFE00C00, - #define LOAD_STORE_PRE_INDEX(A, B, C, D) \ - A##B##_##C##_pre = LoadStorePreIndexFixed | D - LOAD_STORE_OP_LIST(LOAD_STORE_PRE_INDEX) - #undef LOAD_STORE_PRE_INDEX -}; - -// Load/store unsigned offset. -enum LoadStoreUnsignedOffset { - LoadStoreUnsignedOffsetFixed = 0x39000000, - LoadStoreUnsignedOffsetFMask = 0x3B000000, - LoadStoreUnsignedOffsetMask = 0xFFC00000, - PRFM_unsigned = LoadStoreUnsignedOffsetFixed | PRFM, - #define LOAD_STORE_UNSIGNED_OFFSET(A, B, C, D) \ - A##B##_##C##_unsigned = LoadStoreUnsignedOffsetFixed | D - LOAD_STORE_OP_LIST(LOAD_STORE_UNSIGNED_OFFSET) - #undef LOAD_STORE_UNSIGNED_OFFSET -}; - -// Load/store register offset. -enum LoadStoreRegisterOffset { - LoadStoreRegisterOffsetFixed = 0x38200800, - LoadStoreRegisterOffsetFMask = 0x3B200C00, - LoadStoreRegisterOffsetMask = 0xFFE00C00, - PRFM_reg = LoadStoreRegisterOffsetFixed | PRFM, - #define LOAD_STORE_REGISTER_OFFSET(A, B, C, D) \ - A##B##_##C##_reg = LoadStoreRegisterOffsetFixed | D - LOAD_STORE_OP_LIST(LOAD_STORE_REGISTER_OFFSET) - #undef LOAD_STORE_REGISTER_OFFSET -}; - -enum LoadStoreExclusive { - LoadStoreExclusiveFixed = 0x08000000, - LoadStoreExclusiveFMask = 0x3F000000, - LoadStoreExclusiveMask = 0xFFE08000, - STXRB_w = LoadStoreExclusiveFixed | 0x00000000, - STXRH_w = LoadStoreExclusiveFixed | 0x40000000, - STXR_w = LoadStoreExclusiveFixed | 0x80000000, - STXR_x = LoadStoreExclusiveFixed | 0xC0000000, - LDXRB_w = LoadStoreExclusiveFixed | 0x00400000, - LDXRH_w = LoadStoreExclusiveFixed | 0x40400000, - LDXR_w = LoadStoreExclusiveFixed | 0x80400000, - LDXR_x = LoadStoreExclusiveFixed | 0xC0400000, - STXP_w = LoadStoreExclusiveFixed | 0x80200000, - STXP_x = LoadStoreExclusiveFixed | 0xC0200000, - LDXP_w = LoadStoreExclusiveFixed | 0x80600000, - LDXP_x = LoadStoreExclusiveFixed | 0xC0600000, - STLXRB_w = LoadStoreExclusiveFixed | 0x00008000, - STLXRH_w = LoadStoreExclusiveFixed | 0x40008000, - STLXR_w = LoadStoreExclusiveFixed | 0x80008000, - STLXR_x = LoadStoreExclusiveFixed | 0xC0008000, - LDAXRB_w = LoadStoreExclusiveFixed | 0x00408000, - LDAXRH_w = LoadStoreExclusiveFixed | 0x40408000, - LDAXR_w = LoadStoreExclusiveFixed | 0x80408000, - LDAXR_x = LoadStoreExclusiveFixed | 0xC0408000, - STLXP_w = LoadStoreExclusiveFixed | 0x80208000, - STLXP_x = LoadStoreExclusiveFixed | 0xC0208000, - LDAXP_w = LoadStoreExclusiveFixed | 0x80608000, - LDAXP_x = LoadStoreExclusiveFixed | 0xC0608000, - STLRB_w = LoadStoreExclusiveFixed | 0x00808000, - STLRH_w = LoadStoreExclusiveFixed | 0x40808000, - STLR_w = LoadStoreExclusiveFixed | 0x80808000, - STLR_x = LoadStoreExclusiveFixed | 0xC0808000, - LDARB_w = LoadStoreExclusiveFixed | 0x00C08000, - LDARH_w = LoadStoreExclusiveFixed | 0x40C08000, - LDAR_w = LoadStoreExclusiveFixed | 0x80C08000, - LDAR_x = LoadStoreExclusiveFixed | 0xC0C08000 -}; - -// Conditional compare. -enum ConditionalCompareOp { - ConditionalCompareMask = 0x60000000, - CCMN = 0x20000000, - CCMP = 0x60000000 -}; - -// Conditional compare register. -enum ConditionalCompareRegisterOp { - ConditionalCompareRegisterFixed = 0x1A400000, - ConditionalCompareRegisterFMask = 0x1FE00800, - ConditionalCompareRegisterMask = 0xFFE00C10, - CCMN_w = ConditionalCompareRegisterFixed | CCMN, - CCMN_x = ConditionalCompareRegisterFixed | SixtyFourBits | CCMN, - CCMP_w = ConditionalCompareRegisterFixed | CCMP, - CCMP_x = ConditionalCompareRegisterFixed | SixtyFourBits | CCMP -}; - -// Conditional compare immediate. -enum ConditionalCompareImmediateOp { - ConditionalCompareImmediateFixed = 0x1A400800, - ConditionalCompareImmediateFMask = 0x1FE00800, - ConditionalCompareImmediateMask = 0xFFE00C10, - CCMN_w_imm = ConditionalCompareImmediateFixed | CCMN, - CCMN_x_imm = ConditionalCompareImmediateFixed | SixtyFourBits | CCMN, - CCMP_w_imm = ConditionalCompareImmediateFixed | CCMP, - CCMP_x_imm = ConditionalCompareImmediateFixed | SixtyFourBits | CCMP -}; - -// Conditional select. -enum ConditionalSelectOp { - ConditionalSelectFixed = 0x1A800000, - ConditionalSelectFMask = 0x1FE00000, - ConditionalSelectMask = 0xFFE00C00, - CSEL_w = ConditionalSelectFixed | 0x00000000, - CSEL_x = ConditionalSelectFixed | 0x80000000, - CSEL = CSEL_w, - CSINC_w = ConditionalSelectFixed | 0x00000400, - CSINC_x = ConditionalSelectFixed | 0x80000400, - CSINC = CSINC_w, - CSINV_w = ConditionalSelectFixed | 0x40000000, - CSINV_x = ConditionalSelectFixed | 0xC0000000, - CSINV = CSINV_w, - CSNEG_w = ConditionalSelectFixed | 0x40000400, - CSNEG_x = ConditionalSelectFixed | 0xC0000400, - CSNEG = CSNEG_w -}; - -// Data processing 1 source. -enum DataProcessing1SourceOp { - DataProcessing1SourceFixed = 0x5AC00000, - DataProcessing1SourceFMask = 0x5FE00000, - DataProcessing1SourceMask = 0xFFFFFC00, - RBIT = DataProcessing1SourceFixed | 0x00000000, - RBIT_w = RBIT, - RBIT_x = RBIT | SixtyFourBits, - REV16 = DataProcessing1SourceFixed | 0x00000400, - REV16_w = REV16, - REV16_x = REV16 | SixtyFourBits, - REV = DataProcessing1SourceFixed | 0x00000800, - REV_w = REV, - REV32_x = REV | SixtyFourBits, - REV_x = DataProcessing1SourceFixed | SixtyFourBits | 0x00000C00, - CLZ = DataProcessing1SourceFixed | 0x00001000, - CLZ_w = CLZ, - CLZ_x = CLZ | SixtyFourBits, - CLS = DataProcessing1SourceFixed | 0x00001400, - CLS_w = CLS, - CLS_x = CLS | SixtyFourBits -}; - -// Data processing 2 source. -enum DataProcessing2SourceOp { - DataProcessing2SourceFixed = 0x1AC00000, - DataProcessing2SourceFMask = 0x5FE00000, - DataProcessing2SourceMask = 0xFFE0FC00, - UDIV_w = DataProcessing2SourceFixed | 0x00000800, - UDIV_x = DataProcessing2SourceFixed | 0x80000800, - UDIV = UDIV_w, - SDIV_w = DataProcessing2SourceFixed | 0x00000C00, - SDIV_x = DataProcessing2SourceFixed | 0x80000C00, - SDIV = SDIV_w, - LSLV_w = DataProcessing2SourceFixed | 0x00002000, - LSLV_x = DataProcessing2SourceFixed | 0x80002000, - LSLV = LSLV_w, - LSRV_w = DataProcessing2SourceFixed | 0x00002400, - LSRV_x = DataProcessing2SourceFixed | 0x80002400, - LSRV = LSRV_w, - ASRV_w = DataProcessing2SourceFixed | 0x00002800, - ASRV_x = DataProcessing2SourceFixed | 0x80002800, - ASRV = ASRV_w, - RORV_w = DataProcessing2SourceFixed | 0x00002C00, - RORV_x = DataProcessing2SourceFixed | 0x80002C00, - RORV = RORV_w, - CRC32B = DataProcessing2SourceFixed | 0x00004000, - CRC32H = DataProcessing2SourceFixed | 0x00004400, - CRC32W = DataProcessing2SourceFixed | 0x00004800, - CRC32X = DataProcessing2SourceFixed | SixtyFourBits | 0x00004C00, - CRC32CB = DataProcessing2SourceFixed | 0x00005000, - CRC32CH = DataProcessing2SourceFixed | 0x00005400, - CRC32CW = DataProcessing2SourceFixed | 0x00005800, - CRC32CX = DataProcessing2SourceFixed | SixtyFourBits | 0x00005C00 -}; - -// Data processing 3 source. -enum DataProcessing3SourceOp { - DataProcessing3SourceFixed = 0x1B000000, - DataProcessing3SourceFMask = 0x1F000000, - DataProcessing3SourceMask = 0xFFE08000, - MADD_w = DataProcessing3SourceFixed | 0x00000000, - MADD_x = DataProcessing3SourceFixed | 0x80000000, - MADD = MADD_w, - MSUB_w = DataProcessing3SourceFixed | 0x00008000, - MSUB_x = DataProcessing3SourceFixed | 0x80008000, - MSUB = MSUB_w, - SMADDL_x = DataProcessing3SourceFixed | 0x80200000, - SMSUBL_x = DataProcessing3SourceFixed | 0x80208000, - SMULH_x = DataProcessing3SourceFixed | 0x80400000, - UMADDL_x = DataProcessing3SourceFixed | 0x80A00000, - UMSUBL_x = DataProcessing3SourceFixed | 0x80A08000, - UMULH_x = DataProcessing3SourceFixed | 0x80C00000 -}; - -// Floating point compare. -enum FPCompareOp { - FPCompareFixed = 0x1E202000, - FPCompareFMask = 0x5F203C00, - FPCompareMask = 0xFFE0FC1F, - FCMP_s = FPCompareFixed | 0x00000000, - FCMP_d = FPCompareFixed | FP64 | 0x00000000, - FCMP = FCMP_s, - FCMP_s_zero = FPCompareFixed | 0x00000008, - FCMP_d_zero = FPCompareFixed | FP64 | 0x00000008, - FCMP_zero = FCMP_s_zero, - FCMPE_s = FPCompareFixed | 0x00000010, - FCMPE_d = FPCompareFixed | FP64 | 0x00000010, - FCMPE = FCMPE_s, - FCMPE_s_zero = FPCompareFixed | 0x00000018, - FCMPE_d_zero = FPCompareFixed | FP64 | 0x00000018, - FCMPE_zero = FCMPE_s_zero -}; - -// Floating point conditional compare. -enum FPConditionalCompareOp { - FPConditionalCompareFixed = 0x1E200400, - FPConditionalCompareFMask = 0x5F200C00, - FPConditionalCompareMask = 0xFFE00C10, - FCCMP_s = FPConditionalCompareFixed | 0x00000000, - FCCMP_d = FPConditionalCompareFixed | FP64 | 0x00000000, - FCCMP = FCCMP_s, - FCCMPE_s = FPConditionalCompareFixed | 0x00000010, - FCCMPE_d = FPConditionalCompareFixed | FP64 | 0x00000010, - FCCMPE = FCCMPE_s -}; - -// Floating point conditional select. -enum FPConditionalSelectOp { - FPConditionalSelectFixed = 0x1E200C00, - FPConditionalSelectFMask = 0x5F200C00, - FPConditionalSelectMask = 0xFFE00C00, - FCSEL_s = FPConditionalSelectFixed | 0x00000000, - FCSEL_d = FPConditionalSelectFixed | FP64 | 0x00000000, - FCSEL = FCSEL_s -}; - -// Floating point immediate. -enum FPImmediateOp { - FPImmediateFixed = 0x1E201000, - FPImmediateFMask = 0x5F201C00, - FPImmediateMask = 0xFFE01C00, - FMOV_s_imm = FPImmediateFixed | 0x00000000, - FMOV_d_imm = FPImmediateFixed | FP64 | 0x00000000 -}; - -// Floating point data processing 1 source. -enum FPDataProcessing1SourceOp { - FPDataProcessing1SourceFixed = 0x1E204000, - FPDataProcessing1SourceFMask = 0x5F207C00, - FPDataProcessing1SourceMask = 0xFFFFFC00, - FMOV_s = FPDataProcessing1SourceFixed | 0x00000000, - FMOV_d = FPDataProcessing1SourceFixed | FP64 | 0x00000000, - FMOV = FMOV_s, - FABS_s = FPDataProcessing1SourceFixed | 0x00008000, - FABS_d = FPDataProcessing1SourceFixed | FP64 | 0x00008000, - FABS = FABS_s, - FNEG_s = FPDataProcessing1SourceFixed | 0x00010000, - FNEG_d = FPDataProcessing1SourceFixed | FP64 | 0x00010000, - FNEG = FNEG_s, - FSQRT_s = FPDataProcessing1SourceFixed | 0x00018000, - FSQRT_d = FPDataProcessing1SourceFixed | FP64 | 0x00018000, - FSQRT = FSQRT_s, - FCVT_ds = FPDataProcessing1SourceFixed | 0x00028000, - FCVT_sd = FPDataProcessing1SourceFixed | FP64 | 0x00020000, - FCVT_hs = FPDataProcessing1SourceFixed | 0x00038000, - FCVT_hd = FPDataProcessing1SourceFixed | FP64 | 0x00038000, - FCVT_sh = FPDataProcessing1SourceFixed | 0x00C20000, - FCVT_dh = FPDataProcessing1SourceFixed | 0x00C28000, - FRINTN_s = FPDataProcessing1SourceFixed | 0x00040000, - FRINTN_d = FPDataProcessing1SourceFixed | FP64 | 0x00040000, - FRINTN = FRINTN_s, - FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000, - FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000, - FRINTP = FRINTP_s, - FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000, - FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000, - FRINTM = FRINTM_s, - FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000, - FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000, - FRINTZ = FRINTZ_s, - FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000, - FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000, - FRINTA = FRINTA_s, - FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000, - FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000, - FRINTX = FRINTX_s, - FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000, - FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000, - FRINTI = FRINTI_s -}; - -// Floating point data processing 2 source. -enum FPDataProcessing2SourceOp { - FPDataProcessing2SourceFixed = 0x1E200800, - FPDataProcessing2SourceFMask = 0x5F200C00, - FPDataProcessing2SourceMask = 0xFFE0FC00, - FMUL = FPDataProcessing2SourceFixed | 0x00000000, - FMUL_s = FMUL, - FMUL_d = FMUL | FP64, - FDIV = FPDataProcessing2SourceFixed | 0x00001000, - FDIV_s = FDIV, - FDIV_d = FDIV | FP64, - FADD = FPDataProcessing2SourceFixed | 0x00002000, - FADD_s = FADD, - FADD_d = FADD | FP64, - FSUB = FPDataProcessing2SourceFixed | 0x00003000, - FSUB_s = FSUB, - FSUB_d = FSUB | FP64, - FMAX = FPDataProcessing2SourceFixed | 0x00004000, - FMAX_s = FMAX, - FMAX_d = FMAX | FP64, - FMIN = FPDataProcessing2SourceFixed | 0x00005000, - FMIN_s = FMIN, - FMIN_d = FMIN | FP64, - FMAXNM = FPDataProcessing2SourceFixed | 0x00006000, - FMAXNM_s = FMAXNM, - FMAXNM_d = FMAXNM | FP64, - FMINNM = FPDataProcessing2SourceFixed | 0x00007000, - FMINNM_s = FMINNM, - FMINNM_d = FMINNM | FP64, - FNMUL = FPDataProcessing2SourceFixed | 0x00008000, - FNMUL_s = FNMUL, - FNMUL_d = FNMUL | FP64 -}; - -// Floating point data processing 3 source. -enum FPDataProcessing3SourceOp { - FPDataProcessing3SourceFixed = 0x1F000000, - FPDataProcessing3SourceFMask = 0x5F000000, - FPDataProcessing3SourceMask = 0xFFE08000, - FMADD_s = FPDataProcessing3SourceFixed | 0x00000000, - FMSUB_s = FPDataProcessing3SourceFixed | 0x00008000, - FNMADD_s = FPDataProcessing3SourceFixed | 0x00200000, - FNMSUB_s = FPDataProcessing3SourceFixed | 0x00208000, - FMADD_d = FPDataProcessing3SourceFixed | 0x00400000, - FMSUB_d = FPDataProcessing3SourceFixed | 0x00408000, - FNMADD_d = FPDataProcessing3SourceFixed | 0x00600000, - FNMSUB_d = FPDataProcessing3SourceFixed | 0x00608000 -}; - -// Conversion between floating point and integer. -enum FPIntegerConvertOp { - FPIntegerConvertFixed = 0x1E200000, - FPIntegerConvertFMask = 0x5F20FC00, - FPIntegerConvertMask = 0xFFFFFC00, - FCVTNS = FPIntegerConvertFixed | 0x00000000, - FCVTNS_ws = FCVTNS, - FCVTNS_xs = FCVTNS | SixtyFourBits, - FCVTNS_wd = FCVTNS | FP64, - FCVTNS_xd = FCVTNS | SixtyFourBits | FP64, - FCVTNU = FPIntegerConvertFixed | 0x00010000, - FCVTNU_ws = FCVTNU, - FCVTNU_xs = FCVTNU | SixtyFourBits, - FCVTNU_wd = FCVTNU | FP64, - FCVTNU_xd = FCVTNU | SixtyFourBits | FP64, - FCVTPS = FPIntegerConvertFixed | 0x00080000, - FCVTPS_ws = FCVTPS, - FCVTPS_xs = FCVTPS | SixtyFourBits, - FCVTPS_wd = FCVTPS | FP64, - FCVTPS_xd = FCVTPS | SixtyFourBits | FP64, - FCVTPU = FPIntegerConvertFixed | 0x00090000, - FCVTPU_ws = FCVTPU, - FCVTPU_xs = FCVTPU | SixtyFourBits, - FCVTPU_wd = FCVTPU | FP64, - FCVTPU_xd = FCVTPU | SixtyFourBits | FP64, - FCVTMS = FPIntegerConvertFixed | 0x00100000, - FCVTMS_ws = FCVTMS, - FCVTMS_xs = FCVTMS | SixtyFourBits, - FCVTMS_wd = FCVTMS | FP64, - FCVTMS_xd = FCVTMS | SixtyFourBits | FP64, - FCVTMU = FPIntegerConvertFixed | 0x00110000, - FCVTMU_ws = FCVTMU, - FCVTMU_xs = FCVTMU | SixtyFourBits, - FCVTMU_wd = FCVTMU | FP64, - FCVTMU_xd = FCVTMU | SixtyFourBits | FP64, - FCVTZS = FPIntegerConvertFixed | 0x00180000, - FCVTZS_ws = FCVTZS, - FCVTZS_xs = FCVTZS | SixtyFourBits, - FCVTZS_wd = FCVTZS | FP64, - FCVTZS_xd = FCVTZS | SixtyFourBits | FP64, - FCVTZU = FPIntegerConvertFixed | 0x00190000, - FCVTZU_ws = FCVTZU, - FCVTZU_xs = FCVTZU | SixtyFourBits, - FCVTZU_wd = FCVTZU | FP64, - FCVTZU_xd = FCVTZU | SixtyFourBits | FP64, - SCVTF = FPIntegerConvertFixed | 0x00020000, - SCVTF_sw = SCVTF, - SCVTF_sx = SCVTF | SixtyFourBits, - SCVTF_dw = SCVTF | FP64, - SCVTF_dx = SCVTF | SixtyFourBits | FP64, - UCVTF = FPIntegerConvertFixed | 0x00030000, - UCVTF_sw = UCVTF, - UCVTF_sx = UCVTF | SixtyFourBits, - UCVTF_dw = UCVTF | FP64, - UCVTF_dx = UCVTF | SixtyFourBits | FP64, - FCVTAS = FPIntegerConvertFixed | 0x00040000, - FCVTAS_ws = FCVTAS, - FCVTAS_xs = FCVTAS | SixtyFourBits, - FCVTAS_wd = FCVTAS | FP64, - FCVTAS_xd = FCVTAS | SixtyFourBits | FP64, - FCVTAU = FPIntegerConvertFixed | 0x00050000, - FCVTAU_ws = FCVTAU, - FCVTAU_xs = FCVTAU | SixtyFourBits, - FCVTAU_wd = FCVTAU | FP64, - FCVTAU_xd = FCVTAU | SixtyFourBits | FP64, - FMOV_ws = FPIntegerConvertFixed | 0x00060000, - FMOV_sw = FPIntegerConvertFixed | 0x00070000, - FMOV_xd = FMOV_ws | SixtyFourBits | FP64, - FMOV_dx = FMOV_sw | SixtyFourBits | FP64, - FMOV_d1_x = FPIntegerConvertFixed | SixtyFourBits | 0x008F0000, - FMOV_x_d1 = FPIntegerConvertFixed | SixtyFourBits | 0x008E0000 -}; - -// Conversion between fixed point and floating point. -enum FPFixedPointConvertOp { - FPFixedPointConvertFixed = 0x1E000000, - FPFixedPointConvertFMask = 0x5F200000, - FPFixedPointConvertMask = 0xFFFF0000, - FCVTZS_fixed = FPFixedPointConvertFixed | 0x00180000, - FCVTZS_ws_fixed = FCVTZS_fixed, - FCVTZS_xs_fixed = FCVTZS_fixed | SixtyFourBits, - FCVTZS_wd_fixed = FCVTZS_fixed | FP64, - FCVTZS_xd_fixed = FCVTZS_fixed | SixtyFourBits | FP64, - FCVTZU_fixed = FPFixedPointConvertFixed | 0x00190000, - FCVTZU_ws_fixed = FCVTZU_fixed, - FCVTZU_xs_fixed = FCVTZU_fixed | SixtyFourBits, - FCVTZU_wd_fixed = FCVTZU_fixed | FP64, - FCVTZU_xd_fixed = FCVTZU_fixed | SixtyFourBits | FP64, - SCVTF_fixed = FPFixedPointConvertFixed | 0x00020000, - SCVTF_sw_fixed = SCVTF_fixed, - SCVTF_sx_fixed = SCVTF_fixed | SixtyFourBits, - SCVTF_dw_fixed = SCVTF_fixed | FP64, - SCVTF_dx_fixed = SCVTF_fixed | SixtyFourBits | FP64, - UCVTF_fixed = FPFixedPointConvertFixed | 0x00030000, - UCVTF_sw_fixed = UCVTF_fixed, - UCVTF_sx_fixed = UCVTF_fixed | SixtyFourBits, - UCVTF_dw_fixed = UCVTF_fixed | FP64, - UCVTF_dx_fixed = UCVTF_fixed | SixtyFourBits | FP64 -}; - -// Crypto - two register SHA. -enum Crypto2RegSHAOp { - Crypto2RegSHAFixed = 0x5E280800, - Crypto2RegSHAFMask = 0xFF3E0C00 -}; - -// Crypto - three register SHA. -enum Crypto3RegSHAOp { - Crypto3RegSHAFixed = 0x5E000000, - Crypto3RegSHAFMask = 0xFF208C00 -}; - -// Crypto - AES. -enum CryptoAESOp { - CryptoAESFixed = 0x4E280800, - CryptoAESFMask = 0xFF3E0C00 -}; - -// NEON instructions with two register operands. -enum NEON2RegMiscOp { - NEON2RegMiscFixed = 0x0E200800, - NEON2RegMiscFMask = 0x9F3E0C00, - NEON2RegMiscMask = 0xBF3FFC00, - NEON2RegMiscUBit = 0x20000000, - NEON_REV64 = NEON2RegMiscFixed | 0x00000000, - NEON_REV32 = NEON2RegMiscFixed | 0x20000000, - NEON_REV16 = NEON2RegMiscFixed | 0x00001000, - NEON_SADDLP = NEON2RegMiscFixed | 0x00002000, - NEON_UADDLP = NEON_SADDLP | NEON2RegMiscUBit, - NEON_SUQADD = NEON2RegMiscFixed | 0x00003000, - NEON_USQADD = NEON_SUQADD | NEON2RegMiscUBit, - NEON_CLS = NEON2RegMiscFixed | 0x00004000, - NEON_CLZ = NEON2RegMiscFixed | 0x20004000, - NEON_CNT = NEON2RegMiscFixed | 0x00005000, - NEON_RBIT_NOT = NEON2RegMiscFixed | 0x20005000, - NEON_SADALP = NEON2RegMiscFixed | 0x00006000, - NEON_UADALP = NEON_SADALP | NEON2RegMiscUBit, - NEON_SQABS = NEON2RegMiscFixed | 0x00007000, - NEON_SQNEG = NEON2RegMiscFixed | 0x20007000, - NEON_CMGT_zero = NEON2RegMiscFixed | 0x00008000, - NEON_CMGE_zero = NEON2RegMiscFixed | 0x20008000, - NEON_CMEQ_zero = NEON2RegMiscFixed | 0x00009000, - NEON_CMLE_zero = NEON2RegMiscFixed | 0x20009000, - NEON_CMLT_zero = NEON2RegMiscFixed | 0x0000A000, - NEON_ABS = NEON2RegMiscFixed | 0x0000B000, - NEON_NEG = NEON2RegMiscFixed | 0x2000B000, - NEON_XTN = NEON2RegMiscFixed | 0x00012000, - NEON_SQXTUN = NEON2RegMiscFixed | 0x20012000, - NEON_SHLL = NEON2RegMiscFixed | 0x20013000, - NEON_SQXTN = NEON2RegMiscFixed | 0x00014000, - NEON_UQXTN = NEON_SQXTN | NEON2RegMiscUBit, - - NEON2RegMiscOpcode = 0x0001F000, - NEON_RBIT_NOT_opcode = NEON_RBIT_NOT & NEON2RegMiscOpcode, - NEON_NEG_opcode = NEON_NEG & NEON2RegMiscOpcode, - NEON_XTN_opcode = NEON_XTN & NEON2RegMiscOpcode, - NEON_UQXTN_opcode = NEON_UQXTN & NEON2RegMiscOpcode, - - // These instructions use only one bit of the size field. The other bit is - // used to distinguish between instructions. - NEON2RegMiscFPMask = NEON2RegMiscMask | 0x00800000, - NEON_FABS = NEON2RegMiscFixed | 0x0080F000, - NEON_FNEG = NEON2RegMiscFixed | 0x2080F000, - NEON_FCVTN = NEON2RegMiscFixed | 0x00016000, - NEON_FCVTXN = NEON2RegMiscFixed | 0x20016000, - NEON_FCVTL = NEON2RegMiscFixed | 0x00017000, - NEON_FRINTN = NEON2RegMiscFixed | 0x00018000, - NEON_FRINTA = NEON2RegMiscFixed | 0x20018000, - NEON_FRINTP = NEON2RegMiscFixed | 0x00818000, - NEON_FRINTM = NEON2RegMiscFixed | 0x00019000, - NEON_FRINTX = NEON2RegMiscFixed | 0x20019000, - NEON_FRINTZ = NEON2RegMiscFixed | 0x00819000, - NEON_FRINTI = NEON2RegMiscFixed | 0x20819000, - NEON_FCVTNS = NEON2RegMiscFixed | 0x0001A000, - NEON_FCVTNU = NEON_FCVTNS | NEON2RegMiscUBit, - NEON_FCVTPS = NEON2RegMiscFixed | 0x0081A000, - NEON_FCVTPU = NEON_FCVTPS | NEON2RegMiscUBit, - NEON_FCVTMS = NEON2RegMiscFixed | 0x0001B000, - NEON_FCVTMU = NEON_FCVTMS | NEON2RegMiscUBit, - NEON_FCVTZS = NEON2RegMiscFixed | 0x0081B000, - NEON_FCVTZU = NEON_FCVTZS | NEON2RegMiscUBit, - NEON_FCVTAS = NEON2RegMiscFixed | 0x0001C000, - NEON_FCVTAU = NEON_FCVTAS | NEON2RegMiscUBit, - NEON_FSQRT = NEON2RegMiscFixed | 0x2081F000, - NEON_SCVTF = NEON2RegMiscFixed | 0x0001D000, - NEON_UCVTF = NEON_SCVTF | NEON2RegMiscUBit, - NEON_URSQRTE = NEON2RegMiscFixed | 0x2081C000, - NEON_URECPE = NEON2RegMiscFixed | 0x0081C000, - NEON_FRSQRTE = NEON2RegMiscFixed | 0x2081D000, - NEON_FRECPE = NEON2RegMiscFixed | 0x0081D000, - NEON_FCMGT_zero = NEON2RegMiscFixed | 0x0080C000, - NEON_FCMGE_zero = NEON2RegMiscFixed | 0x2080C000, - NEON_FCMEQ_zero = NEON2RegMiscFixed | 0x0080D000, - NEON_FCMLE_zero = NEON2RegMiscFixed | 0x2080D000, - NEON_FCMLT_zero = NEON2RegMiscFixed | 0x0080E000, - - NEON_FCVTL_opcode = NEON_FCVTL & NEON2RegMiscOpcode, - NEON_FCVTN_opcode = NEON_FCVTN & NEON2RegMiscOpcode -}; - -// NEON instructions with three same-type operands. -enum NEON3SameOp { - NEON3SameFixed = 0x0E200400, - NEON3SameFMask = 0x9F200400, - NEON3SameMask = 0xBF20FC00, - NEON3SameUBit = 0x20000000, - NEON_ADD = NEON3SameFixed | 0x00008000, - NEON_ADDP = NEON3SameFixed | 0x0000B800, - NEON_SHADD = NEON3SameFixed | 0x00000000, - NEON_SHSUB = NEON3SameFixed | 0x00002000, - NEON_SRHADD = NEON3SameFixed | 0x00001000, - NEON_CMEQ = NEON3SameFixed | NEON3SameUBit | 0x00008800, - NEON_CMGE = NEON3SameFixed | 0x00003800, - NEON_CMGT = NEON3SameFixed | 0x00003000, - NEON_CMHI = NEON3SameFixed | NEON3SameUBit | NEON_CMGT, - NEON_CMHS = NEON3SameFixed | NEON3SameUBit | NEON_CMGE, - NEON_CMTST = NEON3SameFixed | 0x00008800, - NEON_MLA = NEON3SameFixed | 0x00009000, - NEON_MLS = NEON3SameFixed | 0x20009000, - NEON_MUL = NEON3SameFixed | 0x00009800, - NEON_PMUL = NEON3SameFixed | 0x20009800, - NEON_SRSHL = NEON3SameFixed | 0x00005000, - NEON_SQSHL = NEON3SameFixed | 0x00004800, - NEON_SQRSHL = NEON3SameFixed | 0x00005800, - NEON_SSHL = NEON3SameFixed | 0x00004000, - NEON_SMAX = NEON3SameFixed | 0x00006000, - NEON_SMAXP = NEON3SameFixed | 0x0000A000, - NEON_SMIN = NEON3SameFixed | 0x00006800, - NEON_SMINP = NEON3SameFixed | 0x0000A800, - NEON_SABD = NEON3SameFixed | 0x00007000, - NEON_SABA = NEON3SameFixed | 0x00007800, - NEON_UABD = NEON3SameFixed | NEON3SameUBit | NEON_SABD, - NEON_UABA = NEON3SameFixed | NEON3SameUBit | NEON_SABA, - NEON_SQADD = NEON3SameFixed | 0x00000800, - NEON_SQSUB = NEON3SameFixed | 0x00002800, - NEON_SUB = NEON3SameFixed | NEON3SameUBit | 0x00008000, - NEON_UHADD = NEON3SameFixed | NEON3SameUBit | NEON_SHADD, - NEON_UHSUB = NEON3SameFixed | NEON3SameUBit | NEON_SHSUB, - NEON_URHADD = NEON3SameFixed | NEON3SameUBit | NEON_SRHADD, - NEON_UMAX = NEON3SameFixed | NEON3SameUBit | NEON_SMAX, - NEON_UMAXP = NEON3SameFixed | NEON3SameUBit | NEON_SMAXP, - NEON_UMIN = NEON3SameFixed | NEON3SameUBit | NEON_SMIN, - NEON_UMINP = NEON3SameFixed | NEON3SameUBit | NEON_SMINP, - NEON_URSHL = NEON3SameFixed | NEON3SameUBit | NEON_SRSHL, - NEON_UQADD = NEON3SameFixed | NEON3SameUBit | NEON_SQADD, - NEON_UQRSHL = NEON3SameFixed | NEON3SameUBit | NEON_SQRSHL, - NEON_UQSHL = NEON3SameFixed | NEON3SameUBit | NEON_SQSHL, - NEON_UQSUB = NEON3SameFixed | NEON3SameUBit | NEON_SQSUB, - NEON_USHL = NEON3SameFixed | NEON3SameUBit | NEON_SSHL, - NEON_SQDMULH = NEON3SameFixed | 0x0000B000, - NEON_SQRDMULH = NEON3SameFixed | 0x2000B000, - - // NEON floating point instructions with three same-type operands. - NEON3SameFPFixed = NEON3SameFixed | 0x0000C000, - NEON3SameFPFMask = NEON3SameFMask | 0x0000C000, - NEON3SameFPMask = NEON3SameMask | 0x00800000, - NEON_FADD = NEON3SameFixed | 0x0000D000, - NEON_FSUB = NEON3SameFixed | 0x0080D000, - NEON_FMUL = NEON3SameFixed | 0x2000D800, - NEON_FDIV = NEON3SameFixed | 0x2000F800, - NEON_FMAX = NEON3SameFixed | 0x0000F000, - NEON_FMAXNM = NEON3SameFixed | 0x0000C000, - NEON_FMAXP = NEON3SameFixed | 0x2000F000, - NEON_FMAXNMP = NEON3SameFixed | 0x2000C000, - NEON_FMIN = NEON3SameFixed | 0x0080F000, - NEON_FMINNM = NEON3SameFixed | 0x0080C000, - NEON_FMINP = NEON3SameFixed | 0x2080F000, - NEON_FMINNMP = NEON3SameFixed | 0x2080C000, - NEON_FMLA = NEON3SameFixed | 0x0000C800, - NEON_FMLS = NEON3SameFixed | 0x0080C800, - NEON_FMULX = NEON3SameFixed | 0x0000D800, - NEON_FRECPS = NEON3SameFixed | 0x0000F800, - NEON_FRSQRTS = NEON3SameFixed | 0x0080F800, - NEON_FABD = NEON3SameFixed | 0x2080D000, - NEON_FADDP = NEON3SameFixed | 0x2000D000, - NEON_FCMEQ = NEON3SameFixed | 0x0000E000, - NEON_FCMGE = NEON3SameFixed | 0x2000E000, - NEON_FCMGT = NEON3SameFixed | 0x2080E000, - NEON_FACGE = NEON3SameFixed | 0x2000E800, - NEON_FACGT = NEON3SameFixed | 0x2080E800, - - // NEON logical instructions with three same-type operands. - NEON3SameLogicalFixed = NEON3SameFixed | 0x00001800, - NEON3SameLogicalFMask = NEON3SameFMask | 0x0000F800, - NEON3SameLogicalMask = 0xBFE0FC00, - NEON3SameLogicalFormatMask = NEON_Q, - NEON_AND = NEON3SameLogicalFixed | 0x00000000, - NEON_ORR = NEON3SameLogicalFixed | 0x00A00000, - NEON_ORN = NEON3SameLogicalFixed | 0x00C00000, - NEON_EOR = NEON3SameLogicalFixed | 0x20000000, - NEON_BIC = NEON3SameLogicalFixed | 0x00400000, - NEON_BIF = NEON3SameLogicalFixed | 0x20C00000, - NEON_BIT = NEON3SameLogicalFixed | 0x20800000, - NEON_BSL = NEON3SameLogicalFixed | 0x20400000 -}; - -// NEON instructions with three different-type operands. -enum NEON3DifferentOp { - NEON3DifferentFixed = 0x0E200000, - NEON3DifferentFMask = 0x9F200C00, - NEON3DifferentMask = 0xFF20FC00, - NEON_ADDHN = NEON3DifferentFixed | 0x00004000, - NEON_ADDHN2 = NEON_ADDHN | NEON_Q, - NEON_PMULL = NEON3DifferentFixed | 0x0000E000, - NEON_PMULL2 = NEON_PMULL | NEON_Q, - NEON_RADDHN = NEON3DifferentFixed | 0x20004000, - NEON_RADDHN2 = NEON_RADDHN | NEON_Q, - NEON_RSUBHN = NEON3DifferentFixed | 0x20006000, - NEON_RSUBHN2 = NEON_RSUBHN | NEON_Q, - NEON_SABAL = NEON3DifferentFixed | 0x00005000, - NEON_SABAL2 = NEON_SABAL | NEON_Q, - NEON_SABDL = NEON3DifferentFixed | 0x00007000, - NEON_SABDL2 = NEON_SABDL | NEON_Q, - NEON_SADDL = NEON3DifferentFixed | 0x00000000, - NEON_SADDL2 = NEON_SADDL | NEON_Q, - NEON_SADDW = NEON3DifferentFixed | 0x00001000, - NEON_SADDW2 = NEON_SADDW | NEON_Q, - NEON_SMLAL = NEON3DifferentFixed | 0x00008000, - NEON_SMLAL2 = NEON_SMLAL | NEON_Q, - NEON_SMLSL = NEON3DifferentFixed | 0x0000A000, - NEON_SMLSL2 = NEON_SMLSL | NEON_Q, - NEON_SMULL = NEON3DifferentFixed | 0x0000C000, - NEON_SMULL2 = NEON_SMULL | NEON_Q, - NEON_SSUBL = NEON3DifferentFixed | 0x00002000, - NEON_SSUBL2 = NEON_SSUBL | NEON_Q, - NEON_SSUBW = NEON3DifferentFixed | 0x00003000, - NEON_SSUBW2 = NEON_SSUBW | NEON_Q, - NEON_SQDMLAL = NEON3DifferentFixed | 0x00009000, - NEON_SQDMLAL2 = NEON_SQDMLAL | NEON_Q, - NEON_SQDMLSL = NEON3DifferentFixed | 0x0000B000, - NEON_SQDMLSL2 = NEON_SQDMLSL | NEON_Q, - NEON_SQDMULL = NEON3DifferentFixed | 0x0000D000, - NEON_SQDMULL2 = NEON_SQDMULL | NEON_Q, - NEON_SUBHN = NEON3DifferentFixed | 0x00006000, - NEON_SUBHN2 = NEON_SUBHN | NEON_Q, - NEON_UABAL = NEON_SABAL | NEON3SameUBit, - NEON_UABAL2 = NEON_UABAL | NEON_Q, - NEON_UABDL = NEON_SABDL | NEON3SameUBit, - NEON_UABDL2 = NEON_UABDL | NEON_Q, - NEON_UADDL = NEON_SADDL | NEON3SameUBit, - NEON_UADDL2 = NEON_UADDL | NEON_Q, - NEON_UADDW = NEON_SADDW | NEON3SameUBit, - NEON_UADDW2 = NEON_UADDW | NEON_Q, - NEON_UMLAL = NEON_SMLAL | NEON3SameUBit, - NEON_UMLAL2 = NEON_UMLAL | NEON_Q, - NEON_UMLSL = NEON_SMLSL | NEON3SameUBit, - NEON_UMLSL2 = NEON_UMLSL | NEON_Q, - NEON_UMULL = NEON_SMULL | NEON3SameUBit, - NEON_UMULL2 = NEON_UMULL | NEON_Q, - NEON_USUBL = NEON_SSUBL | NEON3SameUBit, - NEON_USUBL2 = NEON_USUBL | NEON_Q, - NEON_USUBW = NEON_SSUBW | NEON3SameUBit, - NEON_USUBW2 = NEON_USUBW | NEON_Q -}; - -// NEON instructions operating across vectors. -enum NEONAcrossLanesOp { - NEONAcrossLanesFixed = 0x0E300800, - NEONAcrossLanesFMask = 0x9F3E0C00, - NEONAcrossLanesMask = 0xBF3FFC00, - NEON_ADDV = NEONAcrossLanesFixed | 0x0001B000, - NEON_SADDLV = NEONAcrossLanesFixed | 0x00003000, - NEON_UADDLV = NEONAcrossLanesFixed | 0x20003000, - NEON_SMAXV = NEONAcrossLanesFixed | 0x0000A000, - NEON_SMINV = NEONAcrossLanesFixed | 0x0001A000, - NEON_UMAXV = NEONAcrossLanesFixed | 0x2000A000, - NEON_UMINV = NEONAcrossLanesFixed | 0x2001A000, - - // NEON floating point across instructions. - NEONAcrossLanesFPFixed = NEONAcrossLanesFixed | 0x0000C000, - NEONAcrossLanesFPFMask = NEONAcrossLanesFMask | 0x0000C000, - NEONAcrossLanesFPMask = NEONAcrossLanesMask | 0x00800000, - - NEON_FMAXV = NEONAcrossLanesFPFixed | 0x2000F000, - NEON_FMINV = NEONAcrossLanesFPFixed | 0x2080F000, - NEON_FMAXNMV = NEONAcrossLanesFPFixed | 0x2000C000, - NEON_FMINNMV = NEONAcrossLanesFPFixed | 0x2080C000 -}; - -// NEON instructions with indexed element operand. -enum NEONByIndexedElementOp { - NEONByIndexedElementFixed = 0x0F000000, - NEONByIndexedElementFMask = 0x9F000400, - NEONByIndexedElementMask = 0xBF00F400, - NEON_MUL_byelement = NEONByIndexedElementFixed | 0x00008000, - NEON_MLA_byelement = NEONByIndexedElementFixed | 0x20000000, - NEON_MLS_byelement = NEONByIndexedElementFixed | 0x20004000, - NEON_SMULL_byelement = NEONByIndexedElementFixed | 0x0000A000, - NEON_SMLAL_byelement = NEONByIndexedElementFixed | 0x00002000, - NEON_SMLSL_byelement = NEONByIndexedElementFixed | 0x00006000, - NEON_UMULL_byelement = NEONByIndexedElementFixed | 0x2000A000, - NEON_UMLAL_byelement = NEONByIndexedElementFixed | 0x20002000, - NEON_UMLSL_byelement = NEONByIndexedElementFixed | 0x20006000, - NEON_SQDMULL_byelement = NEONByIndexedElementFixed | 0x0000B000, - NEON_SQDMLAL_byelement = NEONByIndexedElementFixed | 0x00003000, - NEON_SQDMLSL_byelement = NEONByIndexedElementFixed | 0x00007000, - NEON_SQDMULH_byelement = NEONByIndexedElementFixed | 0x0000C000, - NEON_SQRDMULH_byelement = NEONByIndexedElementFixed | 0x0000D000, - - // Floating point instructions. - NEONByIndexedElementFPFixed = NEONByIndexedElementFixed | 0x00800000, - NEONByIndexedElementFPMask = NEONByIndexedElementMask | 0x00800000, - NEON_FMLA_byelement = NEONByIndexedElementFPFixed | 0x00001000, - NEON_FMLS_byelement = NEONByIndexedElementFPFixed | 0x00005000, - NEON_FMUL_byelement = NEONByIndexedElementFPFixed | 0x00009000, - NEON_FMULX_byelement = NEONByIndexedElementFPFixed | 0x20009000 -}; - -// NEON register copy. -enum NEONCopyOp { - NEONCopyFixed = 0x0E000400, - NEONCopyFMask = 0x9FE08400, - NEONCopyMask = 0x3FE08400, - NEONCopyInsElementMask = NEONCopyMask | 0x40000000, - NEONCopyInsGeneralMask = NEONCopyMask | 0x40007800, - NEONCopyDupElementMask = NEONCopyMask | 0x20007800, - NEONCopyDupGeneralMask = NEONCopyDupElementMask, - NEONCopyUmovMask = NEONCopyMask | 0x20007800, - NEONCopySmovMask = NEONCopyMask | 0x20007800, - NEON_INS_ELEMENT = NEONCopyFixed | 0x60000000, - NEON_INS_GENERAL = NEONCopyFixed | 0x40001800, - NEON_DUP_ELEMENT = NEONCopyFixed | 0x00000000, - NEON_DUP_GENERAL = NEONCopyFixed | 0x00000800, - NEON_SMOV = NEONCopyFixed | 0x00002800, - NEON_UMOV = NEONCopyFixed | 0x00003800 -}; - -// NEON extract. -enum NEONExtractOp { - NEONExtractFixed = 0x2E000000, - NEONExtractFMask = 0xBF208400, - NEONExtractMask = 0xBFE08400, - NEON_EXT = NEONExtractFixed | 0x00000000 -}; - -enum NEONLoadStoreMultiOp { - NEONLoadStoreMultiL = 0x00400000, - NEONLoadStoreMulti1_1v = 0x00007000, - NEONLoadStoreMulti1_2v = 0x0000A000, - NEONLoadStoreMulti1_3v = 0x00006000, - NEONLoadStoreMulti1_4v = 0x00002000, - NEONLoadStoreMulti2 = 0x00008000, - NEONLoadStoreMulti3 = 0x00004000, - NEONLoadStoreMulti4 = 0x00000000 -}; - -// NEON load/store multiple structures. -enum NEONLoadStoreMultiStructOp { - NEONLoadStoreMultiStructFixed = 0x0C000000, - NEONLoadStoreMultiStructFMask = 0xBFBF0000, - NEONLoadStoreMultiStructMask = 0xBFFFF000, - NEONLoadStoreMultiStructStore = NEONLoadStoreMultiStructFixed, - NEONLoadStoreMultiStructLoad = NEONLoadStoreMultiStructFixed | - NEONLoadStoreMultiL, - NEON_LD1_1v = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti1_1v, - NEON_LD1_2v = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti1_2v, - NEON_LD1_3v = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti1_3v, - NEON_LD1_4v = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti1_4v, - NEON_LD2 = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti2, - NEON_LD3 = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti3, - NEON_LD4 = NEONLoadStoreMultiStructLoad | NEONLoadStoreMulti4, - NEON_ST1_1v = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti1_1v, - NEON_ST1_2v = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti1_2v, - NEON_ST1_3v = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti1_3v, - NEON_ST1_4v = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti1_4v, - NEON_ST2 = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti2, - NEON_ST3 = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti3, - NEON_ST4 = NEONLoadStoreMultiStructStore | NEONLoadStoreMulti4 -}; - -// NEON load/store multiple structures with post-index addressing. -enum NEONLoadStoreMultiStructPostIndexOp { - NEONLoadStoreMultiStructPostIndexFixed = 0x0C800000, - NEONLoadStoreMultiStructPostIndexFMask = 0xBFA00000, - NEONLoadStoreMultiStructPostIndexMask = 0xBFE0F000, - NEONLoadStoreMultiStructPostIndex = 0x00800000, - NEON_LD1_1v_post = NEON_LD1_1v | NEONLoadStoreMultiStructPostIndex, - NEON_LD1_2v_post = NEON_LD1_2v | NEONLoadStoreMultiStructPostIndex, - NEON_LD1_3v_post = NEON_LD1_3v | NEONLoadStoreMultiStructPostIndex, - NEON_LD1_4v_post = NEON_LD1_4v | NEONLoadStoreMultiStructPostIndex, - NEON_LD2_post = NEON_LD2 | NEONLoadStoreMultiStructPostIndex, - NEON_LD3_post = NEON_LD3 | NEONLoadStoreMultiStructPostIndex, - NEON_LD4_post = NEON_LD4 | NEONLoadStoreMultiStructPostIndex, - NEON_ST1_1v_post = NEON_ST1_1v | NEONLoadStoreMultiStructPostIndex, - NEON_ST1_2v_post = NEON_ST1_2v | NEONLoadStoreMultiStructPostIndex, - NEON_ST1_3v_post = NEON_ST1_3v | NEONLoadStoreMultiStructPostIndex, - NEON_ST1_4v_post = NEON_ST1_4v | NEONLoadStoreMultiStructPostIndex, - NEON_ST2_post = NEON_ST2 | NEONLoadStoreMultiStructPostIndex, - NEON_ST3_post = NEON_ST3 | NEONLoadStoreMultiStructPostIndex, - NEON_ST4_post = NEON_ST4 | NEONLoadStoreMultiStructPostIndex -}; - -enum NEONLoadStoreSingleOp { - NEONLoadStoreSingle1 = 0x00000000, - NEONLoadStoreSingle2 = 0x00200000, - NEONLoadStoreSingle3 = 0x00002000, - NEONLoadStoreSingle4 = 0x00202000, - NEONLoadStoreSingleL = 0x00400000, - NEONLoadStoreSingle_b = 0x00000000, - NEONLoadStoreSingle_h = 0x00004000, - NEONLoadStoreSingle_s = 0x00008000, - NEONLoadStoreSingle_d = 0x00008400, - NEONLoadStoreSingleAllLanes = 0x0000C000, - NEONLoadStoreSingleLenMask = 0x00202000 -}; - -// NEON load/store single structure. -enum NEONLoadStoreSingleStructOp { - NEONLoadStoreSingleStructFixed = 0x0D000000, - NEONLoadStoreSingleStructFMask = 0xBF9F0000, - NEONLoadStoreSingleStructMask = 0xBFFFE000, - NEONLoadStoreSingleStructStore = NEONLoadStoreSingleStructFixed, - NEONLoadStoreSingleStructLoad = NEONLoadStoreSingleStructFixed | - NEONLoadStoreSingleL, - NEONLoadStoreSingleStructLoad1 = NEONLoadStoreSingle1 | - NEONLoadStoreSingleStructLoad, - NEONLoadStoreSingleStructLoad2 = NEONLoadStoreSingle2 | - NEONLoadStoreSingleStructLoad, - NEONLoadStoreSingleStructLoad3 = NEONLoadStoreSingle3 | - NEONLoadStoreSingleStructLoad, - NEONLoadStoreSingleStructLoad4 = NEONLoadStoreSingle4 | - NEONLoadStoreSingleStructLoad, - NEONLoadStoreSingleStructStore1 = NEONLoadStoreSingle1 | - NEONLoadStoreSingleStructFixed, - NEONLoadStoreSingleStructStore2 = NEONLoadStoreSingle2 | - NEONLoadStoreSingleStructFixed, - NEONLoadStoreSingleStructStore3 = NEONLoadStoreSingle3 | - NEONLoadStoreSingleStructFixed, - NEONLoadStoreSingleStructStore4 = NEONLoadStoreSingle4 | - NEONLoadStoreSingleStructFixed, - NEON_LD1_b = NEONLoadStoreSingleStructLoad1 | NEONLoadStoreSingle_b, - NEON_LD1_h = NEONLoadStoreSingleStructLoad1 | NEONLoadStoreSingle_h, - NEON_LD1_s = NEONLoadStoreSingleStructLoad1 | NEONLoadStoreSingle_s, - NEON_LD1_d = NEONLoadStoreSingleStructLoad1 | NEONLoadStoreSingle_d, - NEON_LD1R = NEONLoadStoreSingleStructLoad1 | NEONLoadStoreSingleAllLanes, - NEON_ST1_b = NEONLoadStoreSingleStructStore1 | NEONLoadStoreSingle_b, - NEON_ST1_h = NEONLoadStoreSingleStructStore1 | NEONLoadStoreSingle_h, - NEON_ST1_s = NEONLoadStoreSingleStructStore1 | NEONLoadStoreSingle_s, - NEON_ST1_d = NEONLoadStoreSingleStructStore1 | NEONLoadStoreSingle_d, - - NEON_LD2_b = NEONLoadStoreSingleStructLoad2 | NEONLoadStoreSingle_b, - NEON_LD2_h = NEONLoadStoreSingleStructLoad2 | NEONLoadStoreSingle_h, - NEON_LD2_s = NEONLoadStoreSingleStructLoad2 | NEONLoadStoreSingle_s, - NEON_LD2_d = NEONLoadStoreSingleStructLoad2 | NEONLoadStoreSingle_d, - NEON_LD2R = NEONLoadStoreSingleStructLoad2 | NEONLoadStoreSingleAllLanes, - NEON_ST2_b = NEONLoadStoreSingleStructStore2 | NEONLoadStoreSingle_b, - NEON_ST2_h = NEONLoadStoreSingleStructStore2 | NEONLoadStoreSingle_h, - NEON_ST2_s = NEONLoadStoreSingleStructStore2 | NEONLoadStoreSingle_s, - NEON_ST2_d = NEONLoadStoreSingleStructStore2 | NEONLoadStoreSingle_d, - - NEON_LD3_b = NEONLoadStoreSingleStructLoad3 | NEONLoadStoreSingle_b, - NEON_LD3_h = NEONLoadStoreSingleStructLoad3 | NEONLoadStoreSingle_h, - NEON_LD3_s = NEONLoadStoreSingleStructLoad3 | NEONLoadStoreSingle_s, - NEON_LD3_d = NEONLoadStoreSingleStructLoad3 | NEONLoadStoreSingle_d, - NEON_LD3R = NEONLoadStoreSingleStructLoad3 | NEONLoadStoreSingleAllLanes, - NEON_ST3_b = NEONLoadStoreSingleStructStore3 | NEONLoadStoreSingle_b, - NEON_ST3_h = NEONLoadStoreSingleStructStore3 | NEONLoadStoreSingle_h, - NEON_ST3_s = NEONLoadStoreSingleStructStore3 | NEONLoadStoreSingle_s, - NEON_ST3_d = NEONLoadStoreSingleStructStore3 | NEONLoadStoreSingle_d, - - NEON_LD4_b = NEONLoadStoreSingleStructLoad4 | NEONLoadStoreSingle_b, - NEON_LD4_h = NEONLoadStoreSingleStructLoad4 | NEONLoadStoreSingle_h, - NEON_LD4_s = NEONLoadStoreSingleStructLoad4 | NEONLoadStoreSingle_s, - NEON_LD4_d = NEONLoadStoreSingleStructLoad4 | NEONLoadStoreSingle_d, - NEON_LD4R = NEONLoadStoreSingleStructLoad4 | NEONLoadStoreSingleAllLanes, - NEON_ST4_b = NEONLoadStoreSingleStructStore4 | NEONLoadStoreSingle_b, - NEON_ST4_h = NEONLoadStoreSingleStructStore4 | NEONLoadStoreSingle_h, - NEON_ST4_s = NEONLoadStoreSingleStructStore4 | NEONLoadStoreSingle_s, - NEON_ST4_d = NEONLoadStoreSingleStructStore4 | NEONLoadStoreSingle_d -}; - -// NEON load/store single structure with post-index addressing. -enum NEONLoadStoreSingleStructPostIndexOp { - NEONLoadStoreSingleStructPostIndexFixed = 0x0D800000, - NEONLoadStoreSingleStructPostIndexFMask = 0xBF800000, - NEONLoadStoreSingleStructPostIndexMask = 0xBFE0E000, - NEONLoadStoreSingleStructPostIndex = 0x00800000, - NEON_LD1_b_post = NEON_LD1_b | NEONLoadStoreSingleStructPostIndex, - NEON_LD1_h_post = NEON_LD1_h | NEONLoadStoreSingleStructPostIndex, - NEON_LD1_s_post = NEON_LD1_s | NEONLoadStoreSingleStructPostIndex, - NEON_LD1_d_post = NEON_LD1_d | NEONLoadStoreSingleStructPostIndex, - NEON_LD1R_post = NEON_LD1R | NEONLoadStoreSingleStructPostIndex, - NEON_ST1_b_post = NEON_ST1_b | NEONLoadStoreSingleStructPostIndex, - NEON_ST1_h_post = NEON_ST1_h | NEONLoadStoreSingleStructPostIndex, - NEON_ST1_s_post = NEON_ST1_s | NEONLoadStoreSingleStructPostIndex, - NEON_ST1_d_post = NEON_ST1_d | NEONLoadStoreSingleStructPostIndex, - - NEON_LD2_b_post = NEON_LD2_b | NEONLoadStoreSingleStructPostIndex, - NEON_LD2_h_post = NEON_LD2_h | NEONLoadStoreSingleStructPostIndex, - NEON_LD2_s_post = NEON_LD2_s | NEONLoadStoreSingleStructPostIndex, - NEON_LD2_d_post = NEON_LD2_d | NEONLoadStoreSingleStructPostIndex, - NEON_LD2R_post = NEON_LD2R | NEONLoadStoreSingleStructPostIndex, - NEON_ST2_b_post = NEON_ST2_b | NEONLoadStoreSingleStructPostIndex, - NEON_ST2_h_post = NEON_ST2_h | NEONLoadStoreSingleStructPostIndex, - NEON_ST2_s_post = NEON_ST2_s | NEONLoadStoreSingleStructPostIndex, - NEON_ST2_d_post = NEON_ST2_d | NEONLoadStoreSingleStructPostIndex, - - NEON_LD3_b_post = NEON_LD3_b | NEONLoadStoreSingleStructPostIndex, - NEON_LD3_h_post = NEON_LD3_h | NEONLoadStoreSingleStructPostIndex, - NEON_LD3_s_post = NEON_LD3_s | NEONLoadStoreSingleStructPostIndex, - NEON_LD3_d_post = NEON_LD3_d | NEONLoadStoreSingleStructPostIndex, - NEON_LD3R_post = NEON_LD3R | NEONLoadStoreSingleStructPostIndex, - NEON_ST3_b_post = NEON_ST3_b | NEONLoadStoreSingleStructPostIndex, - NEON_ST3_h_post = NEON_ST3_h | NEONLoadStoreSingleStructPostIndex, - NEON_ST3_s_post = NEON_ST3_s | NEONLoadStoreSingleStructPostIndex, - NEON_ST3_d_post = NEON_ST3_d | NEONLoadStoreSingleStructPostIndex, - - NEON_LD4_b_post = NEON_LD4_b | NEONLoadStoreSingleStructPostIndex, - NEON_LD4_h_post = NEON_LD4_h | NEONLoadStoreSingleStructPostIndex, - NEON_LD4_s_post = NEON_LD4_s | NEONLoadStoreSingleStructPostIndex, - NEON_LD4_d_post = NEON_LD4_d | NEONLoadStoreSingleStructPostIndex, - NEON_LD4R_post = NEON_LD4R | NEONLoadStoreSingleStructPostIndex, - NEON_ST4_b_post = NEON_ST4_b | NEONLoadStoreSingleStructPostIndex, - NEON_ST4_h_post = NEON_ST4_h | NEONLoadStoreSingleStructPostIndex, - NEON_ST4_s_post = NEON_ST4_s | NEONLoadStoreSingleStructPostIndex, - NEON_ST4_d_post = NEON_ST4_d | NEONLoadStoreSingleStructPostIndex -}; - -// NEON modified immediate. -enum NEONModifiedImmediateOp { - NEONModifiedImmediateFixed = 0x0F000400, - NEONModifiedImmediateFMask = 0x9FF80400, - NEONModifiedImmediateOpBit = 0x20000000, - NEONModifiedImmediate_MOVI = NEONModifiedImmediateFixed | 0x00000000, - NEONModifiedImmediate_MVNI = NEONModifiedImmediateFixed | 0x20000000, - NEONModifiedImmediate_ORR = NEONModifiedImmediateFixed | 0x00001000, - NEONModifiedImmediate_BIC = NEONModifiedImmediateFixed | 0x20001000 -}; - -// NEON shift immediate. -enum NEONShiftImmediateOp { - NEONShiftImmediateFixed = 0x0F000400, - NEONShiftImmediateFMask = 0x9F800400, - NEONShiftImmediateMask = 0xBF80FC00, - NEONShiftImmediateUBit = 0x20000000, - NEON_SHL = NEONShiftImmediateFixed | 0x00005000, - NEON_SSHLL = NEONShiftImmediateFixed | 0x0000A000, - NEON_USHLL = NEONShiftImmediateFixed | 0x2000A000, - NEON_SLI = NEONShiftImmediateFixed | 0x20005000, - NEON_SRI = NEONShiftImmediateFixed | 0x20004000, - NEON_SHRN = NEONShiftImmediateFixed | 0x00008000, - NEON_RSHRN = NEONShiftImmediateFixed | 0x00008800, - NEON_UQSHRN = NEONShiftImmediateFixed | 0x20009000, - NEON_UQRSHRN = NEONShiftImmediateFixed | 0x20009800, - NEON_SQSHRN = NEONShiftImmediateFixed | 0x00009000, - NEON_SQRSHRN = NEONShiftImmediateFixed | 0x00009800, - NEON_SQSHRUN = NEONShiftImmediateFixed | 0x20008000, - NEON_SQRSHRUN = NEONShiftImmediateFixed | 0x20008800, - NEON_SSHR = NEONShiftImmediateFixed | 0x00000000, - NEON_SRSHR = NEONShiftImmediateFixed | 0x00002000, - NEON_USHR = NEONShiftImmediateFixed | 0x20000000, - NEON_URSHR = NEONShiftImmediateFixed | 0x20002000, - NEON_SSRA = NEONShiftImmediateFixed | 0x00001000, - NEON_SRSRA = NEONShiftImmediateFixed | 0x00003000, - NEON_USRA = NEONShiftImmediateFixed | 0x20001000, - NEON_URSRA = NEONShiftImmediateFixed | 0x20003000, - NEON_SQSHLU = NEONShiftImmediateFixed | 0x20006000, - NEON_SCVTF_imm = NEONShiftImmediateFixed | 0x0000E000, - NEON_UCVTF_imm = NEONShiftImmediateFixed | 0x2000E000, - NEON_FCVTZS_imm = NEONShiftImmediateFixed | 0x0000F800, - NEON_FCVTZU_imm = NEONShiftImmediateFixed | 0x2000F800, - NEON_SQSHL_imm = NEONShiftImmediateFixed | 0x00007000, - NEON_UQSHL_imm = NEONShiftImmediateFixed | 0x20007000 -}; - -// NEON table. -enum NEONTableOp { - NEONTableFixed = 0x0E000000, - NEONTableFMask = 0xBF208C00, - NEONTableExt = 0x00001000, - NEONTableMask = 0xBF20FC00, - NEON_TBL_1v = NEONTableFixed | 0x00000000, - NEON_TBL_2v = NEONTableFixed | 0x00002000, - NEON_TBL_3v = NEONTableFixed | 0x00004000, - NEON_TBL_4v = NEONTableFixed | 0x00006000, - NEON_TBX_1v = NEON_TBL_1v | NEONTableExt, - NEON_TBX_2v = NEON_TBL_2v | NEONTableExt, - NEON_TBX_3v = NEON_TBL_3v | NEONTableExt, - NEON_TBX_4v = NEON_TBL_4v | NEONTableExt -}; - -// NEON perm. -enum NEONPermOp { - NEONPermFixed = 0x0E000800, - NEONPermFMask = 0xBF208C00, - NEONPermMask = 0x3F20FC00, - NEON_UZP1 = NEONPermFixed | 0x00001000, - NEON_TRN1 = NEONPermFixed | 0x00002000, - NEON_ZIP1 = NEONPermFixed | 0x00003000, - NEON_UZP2 = NEONPermFixed | 0x00005000, - NEON_TRN2 = NEONPermFixed | 0x00006000, - NEON_ZIP2 = NEONPermFixed | 0x00007000 -}; - -// NEON scalar instructions with two register operands. -enum NEONScalar2RegMiscOp { - NEONScalar2RegMiscFixed = 0x5E200800, - NEONScalar2RegMiscFMask = 0xDF3E0C00, - NEONScalar2RegMiscMask = NEON_Q | NEONScalar | NEON2RegMiscMask, - NEON_CMGT_zero_scalar = NEON_Q | NEONScalar | NEON_CMGT_zero, - NEON_CMEQ_zero_scalar = NEON_Q | NEONScalar | NEON_CMEQ_zero, - NEON_CMLT_zero_scalar = NEON_Q | NEONScalar | NEON_CMLT_zero, - NEON_CMGE_zero_scalar = NEON_Q | NEONScalar | NEON_CMGE_zero, - NEON_CMLE_zero_scalar = NEON_Q | NEONScalar | NEON_CMLE_zero, - NEON_ABS_scalar = NEON_Q | NEONScalar | NEON_ABS, - NEON_SQABS_scalar = NEON_Q | NEONScalar | NEON_SQABS, - NEON_NEG_scalar = NEON_Q | NEONScalar | NEON_NEG, - NEON_SQNEG_scalar = NEON_Q | NEONScalar | NEON_SQNEG, - NEON_SQXTN_scalar = NEON_Q | NEONScalar | NEON_SQXTN, - NEON_UQXTN_scalar = NEON_Q | NEONScalar | NEON_UQXTN, - NEON_SQXTUN_scalar = NEON_Q | NEONScalar | NEON_SQXTUN, - NEON_SUQADD_scalar = NEON_Q | NEONScalar | NEON_SUQADD, - NEON_USQADD_scalar = NEON_Q | NEONScalar | NEON_USQADD, - - NEONScalar2RegMiscOpcode = NEON2RegMiscOpcode, - NEON_NEG_scalar_opcode = NEON_NEG_scalar & NEONScalar2RegMiscOpcode, - - NEONScalar2RegMiscFPMask = NEONScalar2RegMiscMask | 0x00800000, - NEON_FRSQRTE_scalar = NEON_Q | NEONScalar | NEON_FRSQRTE, - NEON_FRECPE_scalar = NEON_Q | NEONScalar | NEON_FRECPE, - NEON_SCVTF_scalar = NEON_Q | NEONScalar | NEON_SCVTF, - NEON_UCVTF_scalar = NEON_Q | NEONScalar | NEON_UCVTF, - NEON_FCMGT_zero_scalar = NEON_Q | NEONScalar | NEON_FCMGT_zero, - NEON_FCMEQ_zero_scalar = NEON_Q | NEONScalar | NEON_FCMEQ_zero, - NEON_FCMLT_zero_scalar = NEON_Q | NEONScalar | NEON_FCMLT_zero, - NEON_FCMGE_zero_scalar = NEON_Q | NEONScalar | NEON_FCMGE_zero, - NEON_FCMLE_zero_scalar = NEON_Q | NEONScalar | NEON_FCMLE_zero, - NEON_FRECPX_scalar = NEONScalar2RegMiscFixed | 0x0081F000, - NEON_FCVTNS_scalar = NEON_Q | NEONScalar | NEON_FCVTNS, - NEON_FCVTNU_scalar = NEON_Q | NEONScalar | NEON_FCVTNU, - NEON_FCVTPS_scalar = NEON_Q | NEONScalar | NEON_FCVTPS, - NEON_FCVTPU_scalar = NEON_Q | NEONScalar | NEON_FCVTPU, - NEON_FCVTMS_scalar = NEON_Q | NEONScalar | NEON_FCVTMS, - NEON_FCVTMU_scalar = NEON_Q | NEONScalar | NEON_FCVTMU, - NEON_FCVTZS_scalar = NEON_Q | NEONScalar | NEON_FCVTZS, - NEON_FCVTZU_scalar = NEON_Q | NEONScalar | NEON_FCVTZU, - NEON_FCVTAS_scalar = NEON_Q | NEONScalar | NEON_FCVTAS, - NEON_FCVTAU_scalar = NEON_Q | NEONScalar | NEON_FCVTAU, - NEON_FCVTXN_scalar = NEON_Q | NEONScalar | NEON_FCVTXN -}; - -// NEON scalar instructions with three same-type operands. -enum NEONScalar3SameOp { - NEONScalar3SameFixed = 0x5E200400, - NEONScalar3SameFMask = 0xDF200400, - NEONScalar3SameMask = 0xFF20FC00, - NEON_ADD_scalar = NEON_Q | NEONScalar | NEON_ADD, - NEON_CMEQ_scalar = NEON_Q | NEONScalar | NEON_CMEQ, - NEON_CMGE_scalar = NEON_Q | NEONScalar | NEON_CMGE, - NEON_CMGT_scalar = NEON_Q | NEONScalar | NEON_CMGT, - NEON_CMHI_scalar = NEON_Q | NEONScalar | NEON_CMHI, - NEON_CMHS_scalar = NEON_Q | NEONScalar | NEON_CMHS, - NEON_CMTST_scalar = NEON_Q | NEONScalar | NEON_CMTST, - NEON_SUB_scalar = NEON_Q | NEONScalar | NEON_SUB, - NEON_UQADD_scalar = NEON_Q | NEONScalar | NEON_UQADD, - NEON_SQADD_scalar = NEON_Q | NEONScalar | NEON_SQADD, - NEON_UQSUB_scalar = NEON_Q | NEONScalar | NEON_UQSUB, - NEON_SQSUB_scalar = NEON_Q | NEONScalar | NEON_SQSUB, - NEON_USHL_scalar = NEON_Q | NEONScalar | NEON_USHL, - NEON_SSHL_scalar = NEON_Q | NEONScalar | NEON_SSHL, - NEON_UQSHL_scalar = NEON_Q | NEONScalar | NEON_UQSHL, - NEON_SQSHL_scalar = NEON_Q | NEONScalar | NEON_SQSHL, - NEON_URSHL_scalar = NEON_Q | NEONScalar | NEON_URSHL, - NEON_SRSHL_scalar = NEON_Q | NEONScalar | NEON_SRSHL, - NEON_UQRSHL_scalar = NEON_Q | NEONScalar | NEON_UQRSHL, - NEON_SQRSHL_scalar = NEON_Q | NEONScalar | NEON_SQRSHL, - NEON_SQDMULH_scalar = NEON_Q | NEONScalar | NEON_SQDMULH, - NEON_SQRDMULH_scalar = NEON_Q | NEONScalar | NEON_SQRDMULH, - - // NEON floating point scalar instructions with three same-type operands. - NEONScalar3SameFPFixed = NEONScalar3SameFixed | 0x0000C000, - NEONScalar3SameFPFMask = NEONScalar3SameFMask | 0x0000C000, - NEONScalar3SameFPMask = NEONScalar3SameMask | 0x00800000, - NEON_FACGE_scalar = NEON_Q | NEONScalar | NEON_FACGE, - NEON_FACGT_scalar = NEON_Q | NEONScalar | NEON_FACGT, - NEON_FCMEQ_scalar = NEON_Q | NEONScalar | NEON_FCMEQ, - NEON_FCMGE_scalar = NEON_Q | NEONScalar | NEON_FCMGE, - NEON_FCMGT_scalar = NEON_Q | NEONScalar | NEON_FCMGT, - NEON_FMULX_scalar = NEON_Q | NEONScalar | NEON_FMULX, - NEON_FRECPS_scalar = NEON_Q | NEONScalar | NEON_FRECPS, - NEON_FRSQRTS_scalar = NEON_Q | NEONScalar | NEON_FRSQRTS, - NEON_FABD_scalar = NEON_Q | NEONScalar | NEON_FABD -}; - -// NEON scalar instructions with three different-type operands. -enum NEONScalar3DiffOp { - NEONScalar3DiffFixed = 0x5E200000, - NEONScalar3DiffFMask = 0xDF200C00, - NEONScalar3DiffMask = NEON_Q | NEONScalar | NEON3DifferentMask, - NEON_SQDMLAL_scalar = NEON_Q | NEONScalar | NEON_SQDMLAL, - NEON_SQDMLSL_scalar = NEON_Q | NEONScalar | NEON_SQDMLSL, - NEON_SQDMULL_scalar = NEON_Q | NEONScalar | NEON_SQDMULL -}; - -// NEON scalar instructions with indexed element operand. -enum NEONScalarByIndexedElementOp { - NEONScalarByIndexedElementFixed = 0x5F000000, - NEONScalarByIndexedElementFMask = 0xDF000400, - NEONScalarByIndexedElementMask = 0xFF00F400, - NEON_SQDMLAL_byelement_scalar = NEON_Q | NEONScalar | NEON_SQDMLAL_byelement, - NEON_SQDMLSL_byelement_scalar = NEON_Q | NEONScalar | NEON_SQDMLSL_byelement, - NEON_SQDMULL_byelement_scalar = NEON_Q | NEONScalar | NEON_SQDMULL_byelement, - NEON_SQDMULH_byelement_scalar = NEON_Q | NEONScalar | NEON_SQDMULH_byelement, - NEON_SQRDMULH_byelement_scalar - = NEON_Q | NEONScalar | NEON_SQRDMULH_byelement, - - // Floating point instructions. - NEONScalarByIndexedElementFPFixed - = NEONScalarByIndexedElementFixed | 0x00800000, - NEONScalarByIndexedElementFPMask - = NEONScalarByIndexedElementMask | 0x00800000, - NEON_FMLA_byelement_scalar = NEON_Q | NEONScalar | NEON_FMLA_byelement, - NEON_FMLS_byelement_scalar = NEON_Q | NEONScalar | NEON_FMLS_byelement, - NEON_FMUL_byelement_scalar = NEON_Q | NEONScalar | NEON_FMUL_byelement, - NEON_FMULX_byelement_scalar = NEON_Q | NEONScalar | NEON_FMULX_byelement -}; - -// NEON scalar register copy. -enum NEONScalarCopyOp { - NEONScalarCopyFixed = 0x5E000400, - NEONScalarCopyFMask = 0xDFE08400, - NEONScalarCopyMask = 0xFFE0FC00, - NEON_DUP_ELEMENT_scalar = NEON_Q | NEONScalar | NEON_DUP_ELEMENT -}; - -// NEON scalar pairwise instructions. -enum NEONScalarPairwiseOp { - NEONScalarPairwiseFixed = 0x5E300800, - NEONScalarPairwiseFMask = 0xDF3E0C00, - NEONScalarPairwiseMask = 0xFFB1F800, - NEON_ADDP_scalar = NEONScalarPairwiseFixed | 0x0081B000, - NEON_FMAXNMP_scalar = NEONScalarPairwiseFixed | 0x2000C000, - NEON_FMINNMP_scalar = NEONScalarPairwiseFixed | 0x2080C000, - NEON_FADDP_scalar = NEONScalarPairwiseFixed | 0x2000D000, - NEON_FMAXP_scalar = NEONScalarPairwiseFixed | 0x2000F000, - NEON_FMINP_scalar = NEONScalarPairwiseFixed | 0x2080F000 -}; - -// NEON scalar shift immediate. -enum NEONScalarShiftImmediateOp { - NEONScalarShiftImmediateFixed = 0x5F000400, - NEONScalarShiftImmediateFMask = 0xDF800400, - NEONScalarShiftImmediateMask = 0xFF80FC00, - NEON_SHL_scalar = NEON_Q | NEONScalar | NEON_SHL, - NEON_SLI_scalar = NEON_Q | NEONScalar | NEON_SLI, - NEON_SRI_scalar = NEON_Q | NEONScalar | NEON_SRI, - NEON_SSHR_scalar = NEON_Q | NEONScalar | NEON_SSHR, - NEON_USHR_scalar = NEON_Q | NEONScalar | NEON_USHR, - NEON_SRSHR_scalar = NEON_Q | NEONScalar | NEON_SRSHR, - NEON_URSHR_scalar = NEON_Q | NEONScalar | NEON_URSHR, - NEON_SSRA_scalar = NEON_Q | NEONScalar | NEON_SSRA, - NEON_USRA_scalar = NEON_Q | NEONScalar | NEON_USRA, - NEON_SRSRA_scalar = NEON_Q | NEONScalar | NEON_SRSRA, - NEON_URSRA_scalar = NEON_Q | NEONScalar | NEON_URSRA, - NEON_UQSHRN_scalar = NEON_Q | NEONScalar | NEON_UQSHRN, - NEON_UQRSHRN_scalar = NEON_Q | NEONScalar | NEON_UQRSHRN, - NEON_SQSHRN_scalar = NEON_Q | NEONScalar | NEON_SQSHRN, - NEON_SQRSHRN_scalar = NEON_Q | NEONScalar | NEON_SQRSHRN, - NEON_SQSHRUN_scalar = NEON_Q | NEONScalar | NEON_SQSHRUN, - NEON_SQRSHRUN_scalar = NEON_Q | NEONScalar | NEON_SQRSHRUN, - NEON_SQSHLU_scalar = NEON_Q | NEONScalar | NEON_SQSHLU, - NEON_SQSHL_imm_scalar = NEON_Q | NEONScalar | NEON_SQSHL_imm, - NEON_UQSHL_imm_scalar = NEON_Q | NEONScalar | NEON_UQSHL_imm, - NEON_SCVTF_imm_scalar = NEON_Q | NEONScalar | NEON_SCVTF_imm, - NEON_UCVTF_imm_scalar = NEON_Q | NEONScalar | NEON_UCVTF_imm, - NEON_FCVTZS_imm_scalar = NEON_Q | NEONScalar | NEON_FCVTZS_imm, - NEON_FCVTZU_imm_scalar = NEON_Q | NEONScalar | NEON_FCVTZU_imm -}; - -// Unimplemented and unallocated instructions. These are defined to make fixed -// bit assertion easier. -enum UnimplementedOp { - UnimplementedFixed = 0x00000000, - UnimplementedFMask = 0x00000000 -}; - -enum UnallocatedOp { - UnallocatedFixed = 0x00000000, - UnallocatedFMask = 0x00000000 -}; - -} // namespace vixl - -#endif // VIXL_A64_CONSTANTS_A64_H_ diff --git a/disas/libvixl/vixl/a64/cpu-a64.h b/disas/libvixl/vixl/a64/cpu-a64.h deleted file mode 100644 index cdf09a6af174..000000000000 --- a/disas/libvixl/vixl/a64/cpu-a64.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2014, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_CPU_A64_H -#define VIXL_CPU_A64_H - -#include "vixl/globals.h" -#include "vixl/a64/instructions-a64.h" - -namespace vixl { - -class CPU { - public: - // Initialise CPU support. - static void SetUp(); - - // Ensures the data at a given address and with a given size is the same for - // the I and D caches. I and D caches are not automatically coherent on ARM - // so this operation is required before any dynamically generated code can - // safely run. - static void EnsureIAndDCacheCoherency(void *address, size_t length); - - // Handle tagged pointers. - template - static T SetPointerTag(T pointer, uint64_t tag) { - VIXL_ASSERT(is_uintn(kAddressTagWidth, tag)); - - // Use C-style casts to get static_cast behaviour for integral types (T), - // and reinterpret_cast behaviour for other types. - - uint64_t raw = (uint64_t)pointer; - VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(raw)); - - raw = (raw & ~kAddressTagMask) | (tag << kAddressTagOffset); - return (T)raw; - } - - template - static uint64_t GetPointerTag(T pointer) { - // Use C-style casts to get static_cast behaviour for integral types (T), - // and reinterpret_cast behaviour for other types. - - uint64_t raw = (uint64_t)pointer; - VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(raw)); - - return (raw & kAddressTagMask) >> kAddressTagOffset; - } - - private: - // Return the content of the cache type register. - static uint32_t GetCacheType(); - - // I and D cache line size in bytes. - static unsigned icache_line_size_; - static unsigned dcache_line_size_; -}; - -} // namespace vixl - -#endif // VIXL_CPU_A64_H diff --git a/disas/libvixl/vixl/a64/decoder-a64.cc b/disas/libvixl/vixl/a64/decoder-a64.cc deleted file mode 100644 index 5ba2d3ce045d..000000000000 --- a/disas/libvixl/vixl/a64/decoder-a64.cc +++ /dev/null @@ -1,877 +0,0 @@ -// Copyright 2014, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "vixl/globals.h" -#include "vixl/utils.h" -#include "vixl/a64/decoder-a64.h" - -namespace vixl { - -void Decoder::DecodeInstruction(const Instruction *instr) { - if (instr->Bits(28, 27) == 0) { - VisitUnallocated(instr); - } else { - switch (instr->Bits(27, 24)) { - // 0: PC relative addressing. - case 0x0: DecodePCRelAddressing(instr); break; - - // 1: Add/sub immediate. - case 0x1: DecodeAddSubImmediate(instr); break; - - // A: Logical shifted register. - // Add/sub with carry. - // Conditional compare register. - // Conditional compare immediate. - // Conditional select. - // Data processing 1 source. - // Data processing 2 source. - // B: Add/sub shifted register. - // Add/sub extended register. - // Data processing 3 source. - case 0xA: - case 0xB: DecodeDataProcessing(instr); break; - - // 2: Logical immediate. - // Move wide immediate. - case 0x2: DecodeLogical(instr); break; - - // 3: Bitfield. - // Extract. - case 0x3: DecodeBitfieldExtract(instr); break; - - // 4: Unconditional branch immediate. - // Exception generation. - // Compare and branch immediate. - // 5: Compare and branch immediate. - // Conditional branch. - // System. - // 6,7: Unconditional branch. - // Test and branch immediate. - case 0x4: - case 0x5: - case 0x6: - case 0x7: DecodeBranchSystemException(instr); break; - - // 8,9: Load/store register pair post-index. - // Load register literal. - // Load/store register unscaled immediate. - // Load/store register immediate post-index. - // Load/store register immediate pre-index. - // Load/store register offset. - // Load/store exclusive. - // C,D: Load/store register pair offset. - // Load/store register pair pre-index. - // Load/store register unsigned immediate. - // Advanced SIMD. - case 0x8: - case 0x9: - case 0xC: - case 0xD: DecodeLoadStore(instr); break; - - // E: FP fixed point conversion. - // FP integer conversion. - // FP data processing 1 source. - // FP compare. - // FP immediate. - // FP data processing 2 source. - // FP conditional compare. - // FP conditional select. - // Advanced SIMD. - // F: FP data processing 3 source. - // Advanced SIMD. - case 0xE: - case 0xF: DecodeFP(instr); break; - } - } -} - -void Decoder::AppendVisitor(DecoderVisitor* new_visitor) { - visitors_.push_back(new_visitor); -} - - -void Decoder::PrependVisitor(DecoderVisitor* new_visitor) { - visitors_.push_front(new_visitor); -} - - -void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor, - DecoderVisitor* registered_visitor) { - std::list::iterator it; - for (it = visitors_.begin(); it != visitors_.end(); it++) { - if (*it == registered_visitor) { - visitors_.insert(it, new_visitor); - return; - } - } - // We reached the end of the list. The last element must be - // registered_visitor. - VIXL_ASSERT(*it == registered_visitor); - visitors_.insert(it, new_visitor); -} - - -void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor, - DecoderVisitor* registered_visitor) { - std::list::iterator it; - for (it = visitors_.begin(); it != visitors_.end(); it++) { - if (*it == registered_visitor) { - it++; - visitors_.insert(it, new_visitor); - return; - } - } - // We reached the end of the list. The last element must be - // registered_visitor. - VIXL_ASSERT(*it == registered_visitor); - visitors_.push_back(new_visitor); -} - - -void Decoder::RemoveVisitor(DecoderVisitor* visitor) { - visitors_.remove(visitor); -} - - -void Decoder::DecodePCRelAddressing(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(27, 24) == 0x0); - // We know bit 28 is set, as = 0 is filtered out at the top level - // decode. - VIXL_ASSERT(instr->Bit(28) == 0x1); - VisitPCRelAddressing(instr); -} - - -void Decoder::DecodeBranchSystemException(const Instruction* instr) { - VIXL_ASSERT((instr->Bits(27, 24) == 0x4) || - (instr->Bits(27, 24) == 0x5) || - (instr->Bits(27, 24) == 0x6) || - (instr->Bits(27, 24) == 0x7) ); - - switch (instr->Bits(31, 29)) { - case 0: - case 4: { - VisitUnconditionalBranch(instr); - break; - } - case 1: - case 5: { - if (instr->Bit(25) == 0) { - VisitCompareBranch(instr); - } else { - VisitTestBranch(instr); - } - break; - } - case 2: { - if (instr->Bit(25) == 0) { - if ((instr->Bit(24) == 0x1) || - (instr->Mask(0x01000010) == 0x00000010)) { - VisitUnallocated(instr); - } else { - VisitConditionalBranch(instr); - } - } else { - VisitUnallocated(instr); - } - break; - } - case 6: { - if (instr->Bit(25) == 0) { - if (instr->Bit(24) == 0) { - if ((instr->Bits(4, 2) != 0) || - (instr->Mask(0x00E0001D) == 0x00200001) || - (instr->Mask(0x00E0001D) == 0x00400001) || - (instr->Mask(0x00E0001E) == 0x00200002) || - (instr->Mask(0x00E0001E) == 0x00400002) || - (instr->Mask(0x00E0001C) == 0x00600000) || - (instr->Mask(0x00E0001C) == 0x00800000) || - (instr->Mask(0x00E0001F) == 0x00A00000) || - (instr->Mask(0x00C0001C) == 0x00C00000)) { - VisitUnallocated(instr); - } else { - VisitException(instr); - } - } else { - if (instr->Bits(23, 22) == 0) { - const Instr masked_003FF0E0 = instr->Mask(0x003FF0E0); - if ((instr->Bits(21, 19) == 0x4) || - (masked_003FF0E0 == 0x00033000) || - (masked_003FF0E0 == 0x003FF020) || - (masked_003FF0E0 == 0x003FF060) || - (masked_003FF0E0 == 0x003FF0E0) || - (instr->Mask(0x00388000) == 0x00008000) || - (instr->Mask(0x0038E000) == 0x00000000) || - (instr->Mask(0x0039E000) == 0x00002000) || - (instr->Mask(0x003AE000) == 0x00002000) || - (instr->Mask(0x003CE000) == 0x00042000) || - (instr->Mask(0x003FFFC0) == 0x000320C0) || - (instr->Mask(0x003FF100) == 0x00032100) || - (instr->Mask(0x003FF200) == 0x00032200) || - (instr->Mask(0x003FF400) == 0x00032400) || - (instr->Mask(0x003FF800) == 0x00032800) || - (instr->Mask(0x0038F000) == 0x00005000) || - (instr->Mask(0x0038E000) == 0x00006000)) { - VisitUnallocated(instr); - } else { - VisitSystem(instr); - } - } else { - VisitUnallocated(instr); - } - } - } else { - if ((instr->Bit(24) == 0x1) || - (instr->Bits(20, 16) != 0x1F) || - (instr->Bits(15, 10) != 0) || - (instr->Bits(4, 0) != 0) || - (instr->Bits(24, 21) == 0x3) || - (instr->Bits(24, 22) == 0x3)) { - VisitUnallocated(instr); - } else { - VisitUnconditionalBranchToRegister(instr); - } - } - break; - } - case 3: - case 7: { - VisitUnallocated(instr); - break; - } - } -} - - -void Decoder::DecodeLoadStore(const Instruction* instr) { - VIXL_ASSERT((instr->Bits(27, 24) == 0x8) || - (instr->Bits(27, 24) == 0x9) || - (instr->Bits(27, 24) == 0xC) || - (instr->Bits(27, 24) == 0xD) ); - // TODO(all): rearrange the tree to integrate this branch. - if ((instr->Bit(28) == 0) && (instr->Bit(29) == 0) && (instr->Bit(26) == 1)) { - DecodeNEONLoadStore(instr); - return; - } - - if (instr->Bit(24) == 0) { - if (instr->Bit(28) == 0) { - if (instr->Bit(29) == 0) { - if (instr->Bit(26) == 0) { - VisitLoadStoreExclusive(instr); - } else { - VIXL_UNREACHABLE(); - } - } else { - if ((instr->Bits(31, 30) == 0x3) || - (instr->Mask(0xC4400000) == 0x40000000)) { - VisitUnallocated(instr); - } else { - if (instr->Bit(23) == 0) { - if (instr->Mask(0xC4400000) == 0xC0400000) { - VisitUnallocated(instr); - } else { - VisitLoadStorePairNonTemporal(instr); - } - } else { - VisitLoadStorePairPostIndex(instr); - } - } - } - } else { - if (instr->Bit(29) == 0) { - if (instr->Mask(0xC4000000) == 0xC4000000) { - VisitUnallocated(instr); - } else { - VisitLoadLiteral(instr); - } - } else { - if ((instr->Mask(0x84C00000) == 0x80C00000) || - (instr->Mask(0x44800000) == 0x44800000) || - (instr->Mask(0x84800000) == 0x84800000)) { - VisitUnallocated(instr); - } else { - if (instr->Bit(21) == 0) { - switch (instr->Bits(11, 10)) { - case 0: { - VisitLoadStoreUnscaledOffset(instr); - break; - } - case 1: { - if (instr->Mask(0xC4C00000) == 0xC0800000) { - VisitUnallocated(instr); - } else { - VisitLoadStorePostIndex(instr); - } - break; - } - case 2: { - // TODO: VisitLoadStoreRegisterOffsetUnpriv. - VisitUnimplemented(instr); - break; - } - case 3: { - if (instr->Mask(0xC4C00000) == 0xC0800000) { - VisitUnallocated(instr); - } else { - VisitLoadStorePreIndex(instr); - } - break; - } - } - } else { - if (instr->Bits(11, 10) == 0x2) { - if (instr->Bit(14) == 0) { - VisitUnallocated(instr); - } else { - VisitLoadStoreRegisterOffset(instr); - } - } else { - VisitUnallocated(instr); - } - } - } - } - } - } else { - if (instr->Bit(28) == 0) { - if (instr->Bit(29) == 0) { - VisitUnallocated(instr); - } else { - if ((instr->Bits(31, 30) == 0x3) || - (instr->Mask(0xC4400000) == 0x40000000)) { - VisitUnallocated(instr); - } else { - if (instr->Bit(23) == 0) { - VisitLoadStorePairOffset(instr); - } else { - VisitLoadStorePairPreIndex(instr); - } - } - } - } else { - if (instr->Bit(29) == 0) { - VisitUnallocated(instr); - } else { - if ((instr->Mask(0x84C00000) == 0x80C00000) || - (instr->Mask(0x44800000) == 0x44800000) || - (instr->Mask(0x84800000) == 0x84800000)) { - VisitUnallocated(instr); - } else { - VisitLoadStoreUnsignedOffset(instr); - } - } - } - } -} - - -void Decoder::DecodeLogical(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(27, 24) == 0x2); - - if (instr->Mask(0x80400000) == 0x00400000) { - VisitUnallocated(instr); - } else { - if (instr->Bit(23) == 0) { - VisitLogicalImmediate(instr); - } else { - if (instr->Bits(30, 29) == 0x1) { - VisitUnallocated(instr); - } else { - VisitMoveWideImmediate(instr); - } - } - } -} - - -void Decoder::DecodeBitfieldExtract(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(27, 24) == 0x3); - - if ((instr->Mask(0x80400000) == 0x80000000) || - (instr->Mask(0x80400000) == 0x00400000) || - (instr->Mask(0x80008000) == 0x00008000)) { - VisitUnallocated(instr); - } else if (instr->Bit(23) == 0) { - if ((instr->Mask(0x80200000) == 0x00200000) || - (instr->Mask(0x60000000) == 0x60000000)) { - VisitUnallocated(instr); - } else { - VisitBitfield(instr); - } - } else { - if ((instr->Mask(0x60200000) == 0x00200000) || - (instr->Mask(0x60000000) != 0x00000000)) { - VisitUnallocated(instr); - } else { - VisitExtract(instr); - } - } -} - - -void Decoder::DecodeAddSubImmediate(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(27, 24) == 0x1); - if (instr->Bit(23) == 1) { - VisitUnallocated(instr); - } else { - VisitAddSubImmediate(instr); - } -} - - -void Decoder::DecodeDataProcessing(const Instruction* instr) { - VIXL_ASSERT((instr->Bits(27, 24) == 0xA) || - (instr->Bits(27, 24) == 0xB)); - - if (instr->Bit(24) == 0) { - if (instr->Bit(28) == 0) { - if (instr->Mask(0x80008000) == 0x00008000) { - VisitUnallocated(instr); - } else { - VisitLogicalShifted(instr); - } - } else { - switch (instr->Bits(23, 21)) { - case 0: { - if (instr->Mask(0x0000FC00) != 0) { - VisitUnallocated(instr); - } else { - VisitAddSubWithCarry(instr); - } - break; - } - case 2: { - if ((instr->Bit(29) == 0) || - (instr->Mask(0x00000410) != 0)) { - VisitUnallocated(instr); - } else { - if (instr->Bit(11) == 0) { - VisitConditionalCompareRegister(instr); - } else { - VisitConditionalCompareImmediate(instr); - } - } - break; - } - case 4: { - if (instr->Mask(0x20000800) != 0x00000000) { - VisitUnallocated(instr); - } else { - VisitConditionalSelect(instr); - } - break; - } - case 6: { - if (instr->Bit(29) == 0x1) { - VisitUnallocated(instr); - VIXL_FALLTHROUGH(); - } else { - if (instr->Bit(30) == 0) { - if ((instr->Bit(15) == 0x1) || - (instr->Bits(15, 11) == 0) || - (instr->Bits(15, 12) == 0x1) || - (instr->Bits(15, 12) == 0x3) || - (instr->Bits(15, 13) == 0x3) || - (instr->Mask(0x8000EC00) == 0x00004C00) || - (instr->Mask(0x8000E800) == 0x80004000) || - (instr->Mask(0x8000E400) == 0x80004000)) { - VisitUnallocated(instr); - } else { - VisitDataProcessing2Source(instr); - } - } else { - if ((instr->Bit(13) == 1) || - (instr->Bits(20, 16) != 0) || - (instr->Bits(15, 14) != 0) || - (instr->Mask(0xA01FFC00) == 0x00000C00) || - (instr->Mask(0x201FF800) == 0x00001800)) { - VisitUnallocated(instr); - } else { - VisitDataProcessing1Source(instr); - } - } - break; - } - } - case 1: - case 3: - case 5: - case 7: VisitUnallocated(instr); break; - } - } - } else { - if (instr->Bit(28) == 0) { - if (instr->Bit(21) == 0) { - if ((instr->Bits(23, 22) == 0x3) || - (instr->Mask(0x80008000) == 0x00008000)) { - VisitUnallocated(instr); - } else { - VisitAddSubShifted(instr); - } - } else { - if ((instr->Mask(0x00C00000) != 0x00000000) || - (instr->Mask(0x00001400) == 0x00001400) || - (instr->Mask(0x00001800) == 0x00001800)) { - VisitUnallocated(instr); - } else { - VisitAddSubExtended(instr); - } - } - } else { - if ((instr->Bit(30) == 0x1) || - (instr->Bits(30, 29) == 0x1) || - (instr->Mask(0xE0600000) == 0x00200000) || - (instr->Mask(0xE0608000) == 0x00400000) || - (instr->Mask(0x60608000) == 0x00408000) || - (instr->Mask(0x60E00000) == 0x00E00000) || - (instr->Mask(0x60E00000) == 0x00800000) || - (instr->Mask(0x60E00000) == 0x00600000)) { - VisitUnallocated(instr); - } else { - VisitDataProcessing3Source(instr); - } - } - } -} - - -void Decoder::DecodeFP(const Instruction* instr) { - VIXL_ASSERT((instr->Bits(27, 24) == 0xE) || - (instr->Bits(27, 24) == 0xF)); - if (instr->Bit(28) == 0) { - DecodeNEONVectorDataProcessing(instr); - } else { - if (instr->Bits(31, 30) == 0x3) { - VisitUnallocated(instr); - } else if (instr->Bits(31, 30) == 0x1) { - DecodeNEONScalarDataProcessing(instr); - } else { - if (instr->Bit(29) == 0) { - if (instr->Bit(24) == 0) { - if (instr->Bit(21) == 0) { - if ((instr->Bit(23) == 1) || - (instr->Bit(18) == 1) || - (instr->Mask(0x80008000) == 0x00000000) || - (instr->Mask(0x000E0000) == 0x00000000) || - (instr->Mask(0x000E0000) == 0x000A0000) || - (instr->Mask(0x00160000) == 0x00000000) || - (instr->Mask(0x00160000) == 0x00120000)) { - VisitUnallocated(instr); - } else { - VisitFPFixedPointConvert(instr); - } - } else { - if (instr->Bits(15, 10) == 32) { - VisitUnallocated(instr); - } else if (instr->Bits(15, 10) == 0) { - if ((instr->Bits(23, 22) == 0x3) || - (instr->Mask(0x000E0000) == 0x000A0000) || - (instr->Mask(0x000E0000) == 0x000C0000) || - (instr->Mask(0x00160000) == 0x00120000) || - (instr->Mask(0x00160000) == 0x00140000) || - (instr->Mask(0x20C40000) == 0x00800000) || - (instr->Mask(0x20C60000) == 0x00840000) || - (instr->Mask(0xA0C60000) == 0x80060000) || - (instr->Mask(0xA0C60000) == 0x00860000) || - (instr->Mask(0xA0C60000) == 0x00460000) || - (instr->Mask(0xA0CE0000) == 0x80860000) || - (instr->Mask(0xA0CE0000) == 0x804E0000) || - (instr->Mask(0xA0CE0000) == 0x000E0000) || - (instr->Mask(0xA0D60000) == 0x00160000) || - (instr->Mask(0xA0D60000) == 0x80560000) || - (instr->Mask(0xA0D60000) == 0x80960000)) { - VisitUnallocated(instr); - } else { - VisitFPIntegerConvert(instr); - } - } else if (instr->Bits(14, 10) == 16) { - const Instr masked_A0DF8000 = instr->Mask(0xA0DF8000); - if ((instr->Mask(0x80180000) != 0) || - (masked_A0DF8000 == 0x00020000) || - (masked_A0DF8000 == 0x00030000) || - (masked_A0DF8000 == 0x00068000) || - (masked_A0DF8000 == 0x00428000) || - (masked_A0DF8000 == 0x00430000) || - (masked_A0DF8000 == 0x00468000) || - (instr->Mask(0xA0D80000) == 0x00800000) || - (instr->Mask(0xA0DE0000) == 0x00C00000) || - (instr->Mask(0xA0DF0000) == 0x00C30000) || - (instr->Mask(0xA0DC0000) == 0x00C40000)) { - VisitUnallocated(instr); - } else { - VisitFPDataProcessing1Source(instr); - } - } else if (instr->Bits(13, 10) == 8) { - if ((instr->Bits(15, 14) != 0) || - (instr->Bits(2, 0) != 0) || - (instr->Mask(0x80800000) != 0x00000000)) { - VisitUnallocated(instr); - } else { - VisitFPCompare(instr); - } - } else if (instr->Bits(12, 10) == 4) { - if ((instr->Bits(9, 5) != 0) || - (instr->Mask(0x80800000) != 0x00000000)) { - VisitUnallocated(instr); - } else { - VisitFPImmediate(instr); - } - } else { - if (instr->Mask(0x80800000) != 0x00000000) { - VisitUnallocated(instr); - } else { - switch (instr->Bits(11, 10)) { - case 1: { - VisitFPConditionalCompare(instr); - break; - } - case 2: { - if ((instr->Bits(15, 14) == 0x3) || - (instr->Mask(0x00009000) == 0x00009000) || - (instr->Mask(0x0000A000) == 0x0000A000)) { - VisitUnallocated(instr); - } else { - VisitFPDataProcessing2Source(instr); - } - break; - } - case 3: { - VisitFPConditionalSelect(instr); - break; - } - default: VIXL_UNREACHABLE(); - } - } - } - } - } else { - // Bit 30 == 1 has been handled earlier. - VIXL_ASSERT(instr->Bit(30) == 0); - if (instr->Mask(0xA0800000) != 0) { - VisitUnallocated(instr); - } else { - VisitFPDataProcessing3Source(instr); - } - } - } else { - VisitUnallocated(instr); - } - } - } -} - - -void Decoder::DecodeNEONLoadStore(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(29, 25) == 0x6); - if (instr->Bit(31) == 0) { - if ((instr->Bit(24) == 0) && (instr->Bit(21) == 1)) { - VisitUnallocated(instr); - return; - } - - if (instr->Bit(23) == 0) { - if (instr->Bits(20, 16) == 0) { - if (instr->Bit(24) == 0) { - VisitNEONLoadStoreMultiStruct(instr); - } else { - VisitNEONLoadStoreSingleStruct(instr); - } - } else { - VisitUnallocated(instr); - } - } else { - if (instr->Bit(24) == 0) { - VisitNEONLoadStoreMultiStructPostIndex(instr); - } else { - VisitNEONLoadStoreSingleStructPostIndex(instr); - } - } - } else { - VisitUnallocated(instr); - } -} - - -void Decoder::DecodeNEONVectorDataProcessing(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(28, 25) == 0x7); - if (instr->Bit(31) == 0) { - if (instr->Bit(24) == 0) { - if (instr->Bit(21) == 0) { - if (instr->Bit(15) == 0) { - if (instr->Bit(10) == 0) { - if (instr->Bit(29) == 0) { - if (instr->Bit(11) == 0) { - VisitNEONTable(instr); - } else { - VisitNEONPerm(instr); - } - } else { - VisitNEONExtract(instr); - } - } else { - if (instr->Bits(23, 22) == 0) { - VisitNEONCopy(instr); - } else { - VisitUnallocated(instr); - } - } - } else { - VisitUnallocated(instr); - } - } else { - if (instr->Bit(10) == 0) { - if (instr->Bit(11) == 0) { - VisitNEON3Different(instr); - } else { - if (instr->Bits(18, 17) == 0) { - if (instr->Bit(20) == 0) { - if (instr->Bit(19) == 0) { - VisitNEON2RegMisc(instr); - } else { - if (instr->Bits(30, 29) == 0x2) { - VisitCryptoAES(instr); - } else { - VisitUnallocated(instr); - } - } - } else { - if (instr->Bit(19) == 0) { - VisitNEONAcrossLanes(instr); - } else { - VisitUnallocated(instr); - } - } - } else { - VisitUnallocated(instr); - } - } - } else { - VisitNEON3Same(instr); - } - } - } else { - if (instr->Bit(10) == 0) { - VisitNEONByIndexedElement(instr); - } else { - if (instr->Bit(23) == 0) { - if (instr->Bits(22, 19) == 0) { - VisitNEONModifiedImmediate(instr); - } else { - VisitNEONShiftImmediate(instr); - } - } else { - VisitUnallocated(instr); - } - } - } - } else { - VisitUnallocated(instr); - } -} - - -void Decoder::DecodeNEONScalarDataProcessing(const Instruction* instr) { - VIXL_ASSERT(instr->Bits(28, 25) == 0xF); - if (instr->Bit(24) == 0) { - if (instr->Bit(21) == 0) { - if (instr->Bit(15) == 0) { - if (instr->Bit(10) == 0) { - if (instr->Bit(29) == 0) { - if (instr->Bit(11) == 0) { - VisitCrypto3RegSHA(instr); - } else { - VisitUnallocated(instr); - } - } else { - VisitUnallocated(instr); - } - } else { - if (instr->Bits(23, 22) == 0) { - VisitNEONScalarCopy(instr); - } else { - VisitUnallocated(instr); - } - } - } else { - VisitUnallocated(instr); - } - } else { - if (instr->Bit(10) == 0) { - if (instr->Bit(11) == 0) { - VisitNEONScalar3Diff(instr); - } else { - if (instr->Bits(18, 17) == 0) { - if (instr->Bit(20) == 0) { - if (instr->Bit(19) == 0) { - VisitNEONScalar2RegMisc(instr); - } else { - if (instr->Bit(29) == 0) { - VisitCrypto2RegSHA(instr); - } else { - VisitUnallocated(instr); - } - } - } else { - if (instr->Bit(19) == 0) { - VisitNEONScalarPairwise(instr); - } else { - VisitUnallocated(instr); - } - } - } else { - VisitUnallocated(instr); - } - } - } else { - VisitNEONScalar3Same(instr); - } - } - } else { - if (instr->Bit(10) == 0) { - VisitNEONScalarByIndexedElement(instr); - } else { - if (instr->Bit(23) == 0) { - VisitNEONScalarShiftImmediate(instr); - } else { - VisitUnallocated(instr); - } - } - } -} - - -#define DEFINE_VISITOR_CALLERS(A) \ - void Decoder::Visit##A(const Instruction *instr) { \ - VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \ - std::list::iterator it; \ - for (it = visitors_.begin(); it != visitors_.end(); it++) { \ - (*it)->Visit##A(instr); \ - } \ - } -VISITOR_LIST(DEFINE_VISITOR_CALLERS) -#undef DEFINE_VISITOR_CALLERS -} // namespace vixl diff --git a/disas/libvixl/vixl/a64/decoder-a64.h b/disas/libvixl/vixl/a64/decoder-a64.h deleted file mode 100644 index b3f04f68fc55..000000000000 --- a/disas/libvixl/vixl/a64/decoder-a64.h +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2014, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_A64_DECODER_A64_H_ -#define VIXL_A64_DECODER_A64_H_ - -#include - -#include "vixl/globals.h" -#include "vixl/a64/instructions-a64.h" - - -// List macro containing all visitors needed by the decoder class. - -#define VISITOR_LIST_THAT_RETURN(V) \ - V(PCRelAddressing) \ - V(AddSubImmediate) \ - V(LogicalImmediate) \ - V(MoveWideImmediate) \ - V(Bitfield) \ - V(Extract) \ - V(UnconditionalBranch) \ - V(UnconditionalBranchToRegister) \ - V(CompareBranch) \ - V(TestBranch) \ - V(ConditionalBranch) \ - V(System) \ - V(Exception) \ - V(LoadStorePairPostIndex) \ - V(LoadStorePairOffset) \ - V(LoadStorePairPreIndex) \ - V(LoadStorePairNonTemporal) \ - V(LoadLiteral) \ - V(LoadStoreUnscaledOffset) \ - V(LoadStorePostIndex) \ - V(LoadStorePreIndex) \ - V(LoadStoreRegisterOffset) \ - V(LoadStoreUnsignedOffset) \ - V(LoadStoreExclusive) \ - V(LogicalShifted) \ - V(AddSubShifted) \ - V(AddSubExtended) \ - V(AddSubWithCarry) \ - V(ConditionalCompareRegister) \ - V(ConditionalCompareImmediate) \ - V(ConditionalSelect) \ - V(DataProcessing1Source) \ - V(DataProcessing2Source) \ - V(DataProcessing3Source) \ - V(FPCompare) \ - V(FPConditionalCompare) \ - V(FPConditionalSelect) \ - V(FPImmediate) \ - V(FPDataProcessing1Source) \ - V(FPDataProcessing2Source) \ - V(FPDataProcessing3Source) \ - V(FPIntegerConvert) \ - V(FPFixedPointConvert) \ - V(Crypto2RegSHA) \ - V(Crypto3RegSHA) \ - V(CryptoAES) \ - V(NEON2RegMisc) \ - V(NEON3Different) \ - V(NEON3Same) \ - V(NEONAcrossLanes) \ - V(NEONByIndexedElement) \ - V(NEONCopy) \ - V(NEONExtract) \ - V(NEONLoadStoreMultiStruct) \ - V(NEONLoadStoreMultiStructPostIndex) \ - V(NEONLoadStoreSingleStruct) \ - V(NEONLoadStoreSingleStructPostIndex) \ - V(NEONModifiedImmediate) \ - V(NEONScalar2RegMisc) \ - V(NEONScalar3Diff) \ - V(NEONScalar3Same) \ - V(NEONScalarByIndexedElement) \ - V(NEONScalarCopy) \ - V(NEONScalarPairwise) \ - V(NEONScalarShiftImmediate) \ - V(NEONShiftImmediate) \ - V(NEONTable) \ - V(NEONPerm) \ - -#define VISITOR_LIST_THAT_DONT_RETURN(V) \ - V(Unallocated) \ - V(Unimplemented) \ - -#define VISITOR_LIST(V) \ - VISITOR_LIST_THAT_RETURN(V) \ - VISITOR_LIST_THAT_DONT_RETURN(V) \ - -namespace vixl { - -// The Visitor interface. Disassembler and simulator (and other tools) -// must provide implementations for all of these functions. -class DecoderVisitor { - public: - enum VisitorConstness { - kConstVisitor, - kNonConstVisitor - }; - explicit DecoderVisitor(VisitorConstness constness = kConstVisitor) - : constness_(constness) {} - - virtual ~DecoderVisitor() {} - - #define DECLARE(A) virtual void Visit##A(const Instruction* instr) = 0; - VISITOR_LIST(DECLARE) - #undef DECLARE - - bool IsConstVisitor() const { return constness_ == kConstVisitor; } - Instruction* MutableInstruction(const Instruction* instr) { - VIXL_ASSERT(!IsConstVisitor()); - return const_cast(instr); - } - - private: - const VisitorConstness constness_; -}; - - -class Decoder { - public: - Decoder() {} - - // Top-level wrappers around the actual decoding function. - void Decode(const Instruction* instr) { - std::list::iterator it; - for (it = visitors_.begin(); it != visitors_.end(); it++) { - VIXL_ASSERT((*it)->IsConstVisitor()); - } - DecodeInstruction(instr); - } - void Decode(Instruction* instr) { - DecodeInstruction(const_cast(instr)); - } - - // Register a new visitor class with the decoder. - // Decode() will call the corresponding visitor method from all registered - // visitor classes when decoding reaches the leaf node of the instruction - // decode tree. - // Visitors are called in order. - // A visitor can be registered multiple times. - // - // d.AppendVisitor(V1); - // d.AppendVisitor(V2); - // d.PrependVisitor(V2); - // d.AppendVisitor(V3); - // - // d.Decode(i); - // - // will call in order visitor methods in V2, V1, V2, V3. - void AppendVisitor(DecoderVisitor* visitor); - void PrependVisitor(DecoderVisitor* visitor); - // These helpers register `new_visitor` before or after the first instance of - // `registered_visiter` in the list. - // So if - // V1, V2, V1, V2 - // are registered in this order in the decoder, calls to - // d.InsertVisitorAfter(V3, V1); - // d.InsertVisitorBefore(V4, V2); - // will yield the order - // V1, V3, V4, V2, V1, V2 - // - // For more complex modifications of the order of registered visitors, one can - // directly access and modify the list of visitors via the `visitors()' - // accessor. - void InsertVisitorBefore(DecoderVisitor* new_visitor, - DecoderVisitor* registered_visitor); - void InsertVisitorAfter(DecoderVisitor* new_visitor, - DecoderVisitor* registered_visitor); - - // Remove all instances of a previously registered visitor class from the list - // of visitors stored by the decoder. - void RemoveVisitor(DecoderVisitor* visitor); - - #define DECLARE(A) void Visit##A(const Instruction* instr); - VISITOR_LIST(DECLARE) - #undef DECLARE - - - std::list* visitors() { return &visitors_; } - - private: - // Decodes an instruction and calls the visitor functions registered with the - // Decoder class. - void DecodeInstruction(const Instruction* instr); - - // Decode the PC relative addressing instruction, and call the corresponding - // visitors. - // On entry, instruction bits 27:24 = 0x0. - void DecodePCRelAddressing(const Instruction* instr); - - // Decode the add/subtract immediate instruction, and call the correspoding - // visitors. - // On entry, instruction bits 27:24 = 0x1. - void DecodeAddSubImmediate(const Instruction* instr); - - // Decode the branch, system command, and exception generation parts of - // the instruction tree, and call the corresponding visitors. - // On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}. - void DecodeBranchSystemException(const Instruction* instr); - - // Decode the load and store parts of the instruction tree, and call - // the corresponding visitors. - // On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}. - void DecodeLoadStore(const Instruction* instr); - - // Decode the logical immediate and move wide immediate parts of the - // instruction tree, and call the corresponding visitors. - // On entry, instruction bits 27:24 = 0x2. - void DecodeLogical(const Instruction* instr); - - // Decode the bitfield and extraction parts of the instruction tree, - // and call the corresponding visitors. - // On entry, instruction bits 27:24 = 0x3. - void DecodeBitfieldExtract(const Instruction* instr); - - // Decode the data processing parts of the instruction tree, and call the - // corresponding visitors. - // On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}. - void DecodeDataProcessing(const Instruction* instr); - - // Decode the floating point parts of the instruction tree, and call the - // corresponding visitors. - // On entry, instruction bits 27:24 = {0xE, 0xF}. - void DecodeFP(const Instruction* instr); - - // Decode the Advanced SIMD (NEON) load/store part of the instruction tree, - // and call the corresponding visitors. - // On entry, instruction bits 29:25 = 0x6. - void DecodeNEONLoadStore(const Instruction* instr); - - // Decode the Advanced SIMD (NEON) vector data processing part of the - // instruction tree, and call the corresponding visitors. - // On entry, instruction bits 28:25 = 0x7. - void DecodeNEONVectorDataProcessing(const Instruction* instr); - - // Decode the Advanced SIMD (NEON) scalar data processing part of the - // instruction tree, and call the corresponding visitors. - // On entry, instruction bits 28:25 = 0xF. - void DecodeNEONScalarDataProcessing(const Instruction* instr); - - private: - // Visitors are registered in a list. - std::list visitors_; -}; - -} // namespace vixl - -#endif // VIXL_A64_DECODER_A64_H_ diff --git a/disas/libvixl/vixl/a64/disasm-a64.cc b/disas/libvixl/vixl/a64/disasm-a64.cc deleted file mode 100644 index f34d1d68daba..000000000000 --- a/disas/libvixl/vixl/a64/disasm-a64.cc +++ /dev/null @@ -1,3495 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include "vixl/a64/disasm-a64.h" - -namespace vixl { - -Disassembler::Disassembler() { - buffer_size_ = 256; - buffer_ = reinterpret_cast(malloc(buffer_size_)); - buffer_pos_ = 0; - own_buffer_ = true; - code_address_offset_ = 0; -} - - -Disassembler::Disassembler(char* text_buffer, int buffer_size) { - buffer_size_ = buffer_size; - buffer_ = text_buffer; - buffer_pos_ = 0; - own_buffer_ = false; - code_address_offset_ = 0; -} - - -Disassembler::~Disassembler() { - if (own_buffer_) { - free(buffer_); - } -} - - -char* Disassembler::GetOutput() { - return buffer_; -} - - -void Disassembler::VisitAddSubImmediate(const Instruction* instr) { - bool rd_is_zr = RdIsZROrSP(instr); - bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) && - (instr->ImmAddSub() == 0) ? true : false; - const char *mnemonic = ""; - const char *form = "'Rds, 'Rns, 'IAddSub"; - const char *form_cmp = "'Rns, 'IAddSub"; - const char *form_mov = "'Rds, 'Rns"; - - switch (instr->Mask(AddSubImmediateMask)) { - case ADD_w_imm: - case ADD_x_imm: { - mnemonic = "add"; - if (stack_op) { - mnemonic = "mov"; - form = form_mov; - } - break; - } - case ADDS_w_imm: - case ADDS_x_imm: { - mnemonic = "adds"; - if (rd_is_zr) { - mnemonic = "cmn"; - form = form_cmp; - } - break; - } - case SUB_w_imm: - case SUB_x_imm: mnemonic = "sub"; break; - case SUBS_w_imm: - case SUBS_x_imm: { - mnemonic = "subs"; - if (rd_is_zr) { - mnemonic = "cmp"; - form = form_cmp; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitAddSubShifted(const Instruction* instr) { - bool rd_is_zr = RdIsZROrSP(instr); - bool rn_is_zr = RnIsZROrSP(instr); - const char *mnemonic = ""; - const char *form = "'Rd, 'Rn, 'Rm'NDP"; - const char *form_cmp = "'Rn, 'Rm'NDP"; - const char *form_neg = "'Rd, 'Rm'NDP"; - - switch (instr->Mask(AddSubShiftedMask)) { - case ADD_w_shift: - case ADD_x_shift: mnemonic = "add"; break; - case ADDS_w_shift: - case ADDS_x_shift: { - mnemonic = "adds"; - if (rd_is_zr) { - mnemonic = "cmn"; - form = form_cmp; - } - break; - } - case SUB_w_shift: - case SUB_x_shift: { - mnemonic = "sub"; - if (rn_is_zr) { - mnemonic = "neg"; - form = form_neg; - } - break; - } - case SUBS_w_shift: - case SUBS_x_shift: { - mnemonic = "subs"; - if (rd_is_zr) { - mnemonic = "cmp"; - form = form_cmp; - } else if (rn_is_zr) { - mnemonic = "negs"; - form = form_neg; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitAddSubExtended(const Instruction* instr) { - bool rd_is_zr = RdIsZROrSP(instr); - const char *mnemonic = ""; - Extend mode = static_cast(instr->ExtendMode()); - const char *form = ((mode == UXTX) || (mode == SXTX)) ? - "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext"; - const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ? - "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext"; - - switch (instr->Mask(AddSubExtendedMask)) { - case ADD_w_ext: - case ADD_x_ext: mnemonic = "add"; break; - case ADDS_w_ext: - case ADDS_x_ext: { - mnemonic = "adds"; - if (rd_is_zr) { - mnemonic = "cmn"; - form = form_cmp; - } - break; - } - case SUB_w_ext: - case SUB_x_ext: mnemonic = "sub"; break; - case SUBS_w_ext: - case SUBS_x_ext: { - mnemonic = "subs"; - if (rd_is_zr) { - mnemonic = "cmp"; - form = form_cmp; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitAddSubWithCarry(const Instruction* instr) { - bool rn_is_zr = RnIsZROrSP(instr); - const char *mnemonic = ""; - const char *form = "'Rd, 'Rn, 'Rm"; - const char *form_neg = "'Rd, 'Rm"; - - switch (instr->Mask(AddSubWithCarryMask)) { - case ADC_w: - case ADC_x: mnemonic = "adc"; break; - case ADCS_w: - case ADCS_x: mnemonic = "adcs"; break; - case SBC_w: - case SBC_x: { - mnemonic = "sbc"; - if (rn_is_zr) { - mnemonic = "ngc"; - form = form_neg; - } - break; - } - case SBCS_w: - case SBCS_x: { - mnemonic = "sbcs"; - if (rn_is_zr) { - mnemonic = "ngcs"; - form = form_neg; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLogicalImmediate(const Instruction* instr) { - bool rd_is_zr = RdIsZROrSP(instr); - bool rn_is_zr = RnIsZROrSP(instr); - const char *mnemonic = ""; - const char *form = "'Rds, 'Rn, 'ITri"; - - if (instr->ImmLogical() == 0) { - // The immediate encoded in the instruction is not in the expected format. - Format(instr, "unallocated", "(LogicalImmediate)"); - return; - } - - switch (instr->Mask(LogicalImmediateMask)) { - case AND_w_imm: - case AND_x_imm: mnemonic = "and"; break; - case ORR_w_imm: - case ORR_x_imm: { - mnemonic = "orr"; - unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize - : kWRegSize; - if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) { - mnemonic = "mov"; - form = "'Rds, 'ITri"; - } - break; - } - case EOR_w_imm: - case EOR_x_imm: mnemonic = "eor"; break; - case ANDS_w_imm: - case ANDS_x_imm: { - mnemonic = "ands"; - if (rd_is_zr) { - mnemonic = "tst"; - form = "'Rn, 'ITri"; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) { - VIXL_ASSERT((reg_size == kXRegSize) || - ((reg_size == kWRegSize) && (value <= 0xffffffff))); - - // Test for movz: 16 bits set at positions 0, 16, 32 or 48. - if (((value & UINT64_C(0xffffffffffff0000)) == 0) || - ((value & UINT64_C(0xffffffff0000ffff)) == 0) || - ((value & UINT64_C(0xffff0000ffffffff)) == 0) || - ((value & UINT64_C(0x0000ffffffffffff)) == 0)) { - return true; - } - - // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48). - if ((reg_size == kXRegSize) && - (((~value & UINT64_C(0xffffffffffff0000)) == 0) || - ((~value & UINT64_C(0xffffffff0000ffff)) == 0) || - ((~value & UINT64_C(0xffff0000ffffffff)) == 0) || - ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) { - return true; - } - if ((reg_size == kWRegSize) && - (((value & 0xffff0000) == 0xffff0000) || - ((value & 0x0000ffff) == 0x0000ffff))) { - return true; - } - return false; -} - - -void Disassembler::VisitLogicalShifted(const Instruction* instr) { - bool rd_is_zr = RdIsZROrSP(instr); - bool rn_is_zr = RnIsZROrSP(instr); - const char *mnemonic = ""; - const char *form = "'Rd, 'Rn, 'Rm'NLo"; - - switch (instr->Mask(LogicalShiftedMask)) { - case AND_w: - case AND_x: mnemonic = "and"; break; - case BIC_w: - case BIC_x: mnemonic = "bic"; break; - case EOR_w: - case EOR_x: mnemonic = "eor"; break; - case EON_w: - case EON_x: mnemonic = "eon"; break; - case BICS_w: - case BICS_x: mnemonic = "bics"; break; - case ANDS_w: - case ANDS_x: { - mnemonic = "ands"; - if (rd_is_zr) { - mnemonic = "tst"; - form = "'Rn, 'Rm'NLo"; - } - break; - } - case ORR_w: - case ORR_x: { - mnemonic = "orr"; - if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { - mnemonic = "mov"; - form = "'Rd, 'Rm"; - } - break; - } - case ORN_w: - case ORN_x: { - mnemonic = "orn"; - if (rn_is_zr) { - mnemonic = "mvn"; - form = "'Rd, 'Rm'NLo"; - } - break; - } - default: VIXL_UNREACHABLE(); - } - - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rn, 'Rm, 'INzcv, 'Cond"; - - switch (instr->Mask(ConditionalCompareRegisterMask)) { - case CCMN_w: - case CCMN_x: mnemonic = "ccmn"; break; - case CCMP_w: - case CCMP_x: mnemonic = "ccmp"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rn, 'IP, 'INzcv, 'Cond"; - - switch (instr->Mask(ConditionalCompareImmediateMask)) { - case CCMN_w_imm: - case CCMN_x_imm: mnemonic = "ccmn"; break; - case CCMP_w_imm: - case CCMP_x_imm: mnemonic = "ccmp"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitConditionalSelect(const Instruction* instr) { - bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr)); - bool rn_is_rm = (instr->Rn() == instr->Rm()); - const char *mnemonic = ""; - const char *form = "'Rd, 'Rn, 'Rm, 'Cond"; - const char *form_test = "'Rd, 'CInv"; - const char *form_update = "'Rd, 'Rn, 'CInv"; - - Condition cond = static_cast(instr->Condition()); - bool invertible_cond = (cond != al) && (cond != nv); - - switch (instr->Mask(ConditionalSelectMask)) { - case CSEL_w: - case CSEL_x: mnemonic = "csel"; break; - case CSINC_w: - case CSINC_x: { - mnemonic = "csinc"; - if (rnm_is_zr && invertible_cond) { - mnemonic = "cset"; - form = form_test; - } else if (rn_is_rm && invertible_cond) { - mnemonic = "cinc"; - form = form_update; - } - break; - } - case CSINV_w: - case CSINV_x: { - mnemonic = "csinv"; - if (rnm_is_zr && invertible_cond) { - mnemonic = "csetm"; - form = form_test; - } else if (rn_is_rm && invertible_cond) { - mnemonic = "cinv"; - form = form_update; - } - break; - } - case CSNEG_w: - case CSNEG_x: { - mnemonic = "csneg"; - if (rn_is_rm && invertible_cond) { - mnemonic = "cneg"; - form = form_update; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitBitfield(const Instruction* instr) { - unsigned s = instr->ImmS(); - unsigned r = instr->ImmR(); - unsigned rd_size_minus_1 = - ((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1; - const char *mnemonic = ""; - const char *form = ""; - const char *form_shift_right = "'Rd, 'Rn, 'IBr"; - const char *form_extend = "'Rd, 'Wn"; - const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1"; - const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1"; - const char *form_lsl = "'Rd, 'Rn, 'IBZ-r"; - - switch (instr->Mask(BitfieldMask)) { - case SBFM_w: - case SBFM_x: { - mnemonic = "sbfx"; - form = form_bfx; - if (r == 0) { - form = form_extend; - if (s == 7) { - mnemonic = "sxtb"; - } else if (s == 15) { - mnemonic = "sxth"; - } else if ((s == 31) && (instr->SixtyFourBits() == 1)) { - mnemonic = "sxtw"; - } else { - form = form_bfx; - } - } else if (s == rd_size_minus_1) { - mnemonic = "asr"; - form = form_shift_right; - } else if (s < r) { - mnemonic = "sbfiz"; - form = form_bfiz; - } - break; - } - case UBFM_w: - case UBFM_x: { - mnemonic = "ubfx"; - form = form_bfx; - if (r == 0) { - form = form_extend; - if (s == 7) { - mnemonic = "uxtb"; - } else if (s == 15) { - mnemonic = "uxth"; - } else { - form = form_bfx; - } - } - if (s == rd_size_minus_1) { - mnemonic = "lsr"; - form = form_shift_right; - } else if (r == s + 1) { - mnemonic = "lsl"; - form = form_lsl; - } else if (s < r) { - mnemonic = "ubfiz"; - form = form_bfiz; - } - break; - } - case BFM_w: - case BFM_x: { - mnemonic = "bfxil"; - form = form_bfx; - if (s < r) { - mnemonic = "bfi"; - form = form_bfiz; - } - } - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitExtract(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rd, 'Rn, 'Rm, 'IExtract"; - - switch (instr->Mask(ExtractMask)) { - case EXTR_w: - case EXTR_x: { - if (instr->Rn() == instr->Rm()) { - mnemonic = "ror"; - form = "'Rd, 'Rn, 'IExtract"; - } else { - mnemonic = "extr"; - } - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitPCRelAddressing(const Instruction* instr) { - switch (instr->Mask(PCRelAddressingMask)) { - case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; - case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break; - default: Format(instr, "unimplemented", "(PCRelAddressing)"); - } -} - - -void Disassembler::VisitConditionalBranch(const Instruction* instr) { - switch (instr->Mask(ConditionalBranchMask)) { - case B_cond: Format(instr, "b.'CBrn", "'TImmCond"); break; - default: VIXL_UNREACHABLE(); - } -} - - -void Disassembler::VisitUnconditionalBranchToRegister( - const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Xn"; - - switch (instr->Mask(UnconditionalBranchToRegisterMask)) { - case BR: mnemonic = "br"; break; - case BLR: mnemonic = "blr"; break; - case RET: { - mnemonic = "ret"; - if (instr->Rn() == kLinkRegCode) { - form = NULL; - } - break; - } - default: form = "(UnconditionalBranchToRegister)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitUnconditionalBranch(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'TImmUncn"; - - switch (instr->Mask(UnconditionalBranchMask)) { - case B: mnemonic = "b"; break; - case BL: mnemonic = "bl"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitDataProcessing1Source(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rd, 'Rn"; - - switch (instr->Mask(DataProcessing1SourceMask)) { - #define FORMAT(A, B) \ - case A##_w: \ - case A##_x: mnemonic = B; break; - FORMAT(RBIT, "rbit"); - FORMAT(REV16, "rev16"); - FORMAT(REV, "rev"); - FORMAT(CLZ, "clz"); - FORMAT(CLS, "cls"); - #undef FORMAT - case REV32_x: mnemonic = "rev32"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitDataProcessing2Source(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Rd, 'Rn, 'Rm"; - const char *form_wwx = "'Wd, 'Wn, 'Xm"; - - switch (instr->Mask(DataProcessing2SourceMask)) { - #define FORMAT(A, B) \ - case A##_w: \ - case A##_x: mnemonic = B; break; - FORMAT(UDIV, "udiv"); - FORMAT(SDIV, "sdiv"); - FORMAT(LSLV, "lsl"); - FORMAT(LSRV, "lsr"); - FORMAT(ASRV, "asr"); - FORMAT(RORV, "ror"); - #undef FORMAT - case CRC32B: mnemonic = "crc32b"; break; - case CRC32H: mnemonic = "crc32h"; break; - case CRC32W: mnemonic = "crc32w"; break; - case CRC32X: mnemonic = "crc32x"; form = form_wwx; break; - case CRC32CB: mnemonic = "crc32cb"; break; - case CRC32CH: mnemonic = "crc32ch"; break; - case CRC32CW: mnemonic = "crc32cw"; break; - case CRC32CX: mnemonic = "crc32cx"; form = form_wwx; break; - default: form = "(DataProcessing2Source)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitDataProcessing3Source(const Instruction* instr) { - bool ra_is_zr = RaIsZROrSP(instr); - const char *mnemonic = ""; - const char *form = "'Xd, 'Wn, 'Wm, 'Xa"; - const char *form_rrr = "'Rd, 'Rn, 'Rm"; - const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra"; - const char *form_xww = "'Xd, 'Wn, 'Wm"; - const char *form_xxx = "'Xd, 'Xn, 'Xm"; - - switch (instr->Mask(DataProcessing3SourceMask)) { - case MADD_w: - case MADD_x: { - mnemonic = "madd"; - form = form_rrrr; - if (ra_is_zr) { - mnemonic = "mul"; - form = form_rrr; - } - break; - } - case MSUB_w: - case MSUB_x: { - mnemonic = "msub"; - form = form_rrrr; - if (ra_is_zr) { - mnemonic = "mneg"; - form = form_rrr; - } - break; - } - case SMADDL_x: { - mnemonic = "smaddl"; - if (ra_is_zr) { - mnemonic = "smull"; - form = form_xww; - } - break; - } - case SMSUBL_x: { - mnemonic = "smsubl"; - if (ra_is_zr) { - mnemonic = "smnegl"; - form = form_xww; - } - break; - } - case UMADDL_x: { - mnemonic = "umaddl"; - if (ra_is_zr) { - mnemonic = "umull"; - form = form_xww; - } - break; - } - case UMSUBL_x: { - mnemonic = "umsubl"; - if (ra_is_zr) { - mnemonic = "umnegl"; - form = form_xww; - } - break; - } - case SMULH_x: { - mnemonic = "smulh"; - form = form_xxx; - break; - } - case UMULH_x: { - mnemonic = "umulh"; - form = form_xxx; - break; - } - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitCompareBranch(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rt, 'TImmCmpa"; - - switch (instr->Mask(CompareBranchMask)) { - case CBZ_w: - case CBZ_x: mnemonic = "cbz"; break; - case CBNZ_w: - case CBNZ_x: mnemonic = "cbnz"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitTestBranch(const Instruction* instr) { - const char *mnemonic = ""; - // If the top bit of the immediate is clear, the tested register is - // disassembled as Wt, otherwise Xt. As the top bit of the immediate is - // encoded in bit 31 of the instruction, we can reuse the Rt form, which - // uses bit 31 (normally "sf") to choose the register size. - const char *form = "'Rt, 'IS, 'TImmTest"; - - switch (instr->Mask(TestBranchMask)) { - case TBZ: mnemonic = "tbz"; break; - case TBNZ: mnemonic = "tbnz"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitMoveWideImmediate(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rd, 'IMoveImm"; - - // Print the shift separately for movk, to make it clear which half word will - // be overwritten. Movn and movz print the computed immediate, which includes - // shift calculation. - switch (instr->Mask(MoveWideImmediateMask)) { - case MOVN_w: - case MOVN_x: - if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) { - if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) { - mnemonic = "movn"; - } else { - mnemonic = "mov"; - form = "'Rd, 'IMoveNeg"; - } - } else { - mnemonic = "movn"; - } - break; - case MOVZ_w: - case MOVZ_x: - if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) - mnemonic = "mov"; - else - mnemonic = "movz"; - break; - case MOVK_w: - case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -#define LOAD_STORE_LIST(V) \ - V(STRB_w, "strb", "'Wt") \ - V(STRH_w, "strh", "'Wt") \ - V(STR_w, "str", "'Wt") \ - V(STR_x, "str", "'Xt") \ - V(LDRB_w, "ldrb", "'Wt") \ - V(LDRH_w, "ldrh", "'Wt") \ - V(LDR_w, "ldr", "'Wt") \ - V(LDR_x, "ldr", "'Xt") \ - V(LDRSB_x, "ldrsb", "'Xt") \ - V(LDRSH_x, "ldrsh", "'Xt") \ - V(LDRSW_x, "ldrsw", "'Xt") \ - V(LDRSB_w, "ldrsb", "'Wt") \ - V(LDRSH_w, "ldrsh", "'Wt") \ - V(STR_b, "str", "'Bt") \ - V(STR_h, "str", "'Ht") \ - V(STR_s, "str", "'St") \ - V(STR_d, "str", "'Dt") \ - V(LDR_b, "ldr", "'Bt") \ - V(LDR_h, "ldr", "'Ht") \ - V(LDR_s, "ldr", "'St") \ - V(LDR_d, "ldr", "'Dt") \ - V(STR_q, "str", "'Qt") \ - V(LDR_q, "ldr", "'Qt") - -void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStorePreIndex)"; - - switch (instr->Mask(LoadStorePreIndexMask)) { - #define LS_PREINDEX(A, B, C) \ - case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; - LOAD_STORE_LIST(LS_PREINDEX) - #undef LS_PREINDEX - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStorePostIndex)"; - - switch (instr->Mask(LoadStorePostIndexMask)) { - #define LS_POSTINDEX(A, B, C) \ - case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break; - LOAD_STORE_LIST(LS_POSTINDEX) - #undef LS_POSTINDEX - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStoreUnsignedOffset)"; - - switch (instr->Mask(LoadStoreUnsignedOffsetMask)) { - #define LS_UNSIGNEDOFFSET(A, B, C) \ - case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break; - LOAD_STORE_LIST(LS_UNSIGNEDOFFSET) - #undef LS_UNSIGNEDOFFSET - case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStoreRegisterOffset)"; - - switch (instr->Mask(LoadStoreRegisterOffsetMask)) { - #define LS_REGISTEROFFSET(A, B, C) \ - case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break; - LOAD_STORE_LIST(LS_REGISTEROFFSET) - #undef LS_REGISTEROFFSET - case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Wt, ['Xns'ILS]"; - const char *form_x = "'Xt, ['Xns'ILS]"; - const char *form_b = "'Bt, ['Xns'ILS]"; - const char *form_h = "'Ht, ['Xns'ILS]"; - const char *form_s = "'St, ['Xns'ILS]"; - const char *form_d = "'Dt, ['Xns'ILS]"; - const char *form_q = "'Qt, ['Xns'ILS]"; - const char *form_prefetch = "'PrefOp, ['Xns'ILS]"; - - switch (instr->Mask(LoadStoreUnscaledOffsetMask)) { - case STURB_w: mnemonic = "sturb"; break; - case STURH_w: mnemonic = "sturh"; break; - case STUR_w: mnemonic = "stur"; break; - case STUR_x: mnemonic = "stur"; form = form_x; break; - case STUR_b: mnemonic = "stur"; form = form_b; break; - case STUR_h: mnemonic = "stur"; form = form_h; break; - case STUR_s: mnemonic = "stur"; form = form_s; break; - case STUR_d: mnemonic = "stur"; form = form_d; break; - case STUR_q: mnemonic = "stur"; form = form_q; break; - case LDURB_w: mnemonic = "ldurb"; break; - case LDURH_w: mnemonic = "ldurh"; break; - case LDUR_w: mnemonic = "ldur"; break; - case LDUR_x: mnemonic = "ldur"; form = form_x; break; - case LDUR_b: mnemonic = "ldur"; form = form_b; break; - case LDUR_h: mnemonic = "ldur"; form = form_h; break; - case LDUR_s: mnemonic = "ldur"; form = form_s; break; - case LDUR_d: mnemonic = "ldur"; form = form_d; break; - case LDUR_q: mnemonic = "ldur"; form = form_q; break; - case LDURSB_x: form = form_x; VIXL_FALLTHROUGH(); - case LDURSB_w: mnemonic = "ldursb"; break; - case LDURSH_x: form = form_x; VIXL_FALLTHROUGH(); - case LDURSH_w: mnemonic = "ldursh"; break; - case LDURSW_x: mnemonic = "ldursw"; form = form_x; break; - case PRFUM: mnemonic = "prfum"; form = form_prefetch; break; - default: form = "(LoadStoreUnscaledOffset)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadLiteral(const Instruction* instr) { - const char *mnemonic = "ldr"; - const char *form = "(LoadLiteral)"; - - switch (instr->Mask(LoadLiteralMask)) { - case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; - case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; - case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; - case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; - case LDR_q_lit: form = "'Qt, 'ILLiteral 'LValue"; break; - case LDRSW_x_lit: { - mnemonic = "ldrsw"; - form = "'Xt, 'ILLiteral 'LValue"; - break; - } - case PRFM_lit: { - mnemonic = "prfm"; - form = "'PrefOp, 'ILLiteral 'LValue"; - break; - } - default: mnemonic = "unimplemented"; - } - Format(instr, mnemonic, form); -} - - -#define LOAD_STORE_PAIR_LIST(V) \ - V(STP_w, "stp", "'Wt, 'Wt2", "2") \ - V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \ - V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \ - V(STP_x, "stp", "'Xt, 'Xt2", "3") \ - V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \ - V(STP_s, "stp", "'St, 'St2", "2") \ - V(LDP_s, "ldp", "'St, 'St2", "2") \ - V(STP_d, "stp", "'Dt, 'Dt2", "3") \ - V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \ - V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \ - V(STP_q, "stp", "'Qt, 'Qt2", "4") - -void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStorePairPostIndex)"; - - switch (instr->Mask(LoadStorePairPostIndexMask)) { - #define LSP_POSTINDEX(A, B, C, D) \ - case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; - LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) - #undef LSP_POSTINDEX - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStorePairPreIndex)"; - - switch (instr->Mask(LoadStorePairPreIndexMask)) { - #define LSP_PREINDEX(A, B, C, D) \ - case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break; - LOAD_STORE_PAIR_LIST(LSP_PREINDEX) - #undef LSP_PREINDEX - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(LoadStorePairOffset)"; - - switch (instr->Mask(LoadStorePairOffsetMask)) { - #define LSP_OFFSET(A, B, C, D) \ - case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break; - LOAD_STORE_PAIR_LIST(LSP_OFFSET) - #undef LSP_OFFSET - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form; - - switch (instr->Mask(LoadStorePairNonTemporalMask)) { - case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP2]"; break; - case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP2]"; break; - case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP3]"; break; - case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP3]"; break; - case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP2]"; break; - case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP2]"; break; - case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP3]"; break; - case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP3]"; break; - case STNP_q: mnemonic = "stnp"; form = "'Qt, 'Qt2, ['Xns'ILP4]"; break; - case LDNP_q: mnemonic = "ldnp"; form = "'Qt, 'Qt2, ['Xns'ILP4]"; break; - default: form = "(LoadStorePairNonTemporal)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form; - - switch (instr->Mask(LoadStoreExclusiveMask)) { - case STXRB_w: mnemonic = "stxrb"; form = "'Ws, 'Wt, ['Xns]"; break; - case STXRH_w: mnemonic = "stxrh"; form = "'Ws, 'Wt, ['Xns]"; break; - case STXR_w: mnemonic = "stxr"; form = "'Ws, 'Wt, ['Xns]"; break; - case STXR_x: mnemonic = "stxr"; form = "'Ws, 'Xt, ['Xns]"; break; - case LDXRB_w: mnemonic = "ldxrb"; form = "'Wt, ['Xns]"; break; - case LDXRH_w: mnemonic = "ldxrh"; form = "'Wt, ['Xns]"; break; - case LDXR_w: mnemonic = "ldxr"; form = "'Wt, ['Xns]"; break; - case LDXR_x: mnemonic = "ldxr"; form = "'Xt, ['Xns]"; break; - case STXP_w: mnemonic = "stxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break; - case STXP_x: mnemonic = "stxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break; - case LDXP_w: mnemonic = "ldxp"; form = "'Wt, 'Wt2, ['Xns]"; break; - case LDXP_x: mnemonic = "ldxp"; form = "'Xt, 'Xt2, ['Xns]"; break; - case STLXRB_w: mnemonic = "stlxrb"; form = "'Ws, 'Wt, ['Xns]"; break; - case STLXRH_w: mnemonic = "stlxrh"; form = "'Ws, 'Wt, ['Xns]"; break; - case STLXR_w: mnemonic = "stlxr"; form = "'Ws, 'Wt, ['Xns]"; break; - case STLXR_x: mnemonic = "stlxr"; form = "'Ws, 'Xt, ['Xns]"; break; - case LDAXRB_w: mnemonic = "ldaxrb"; form = "'Wt, ['Xns]"; break; - case LDAXRH_w: mnemonic = "ldaxrh"; form = "'Wt, ['Xns]"; break; - case LDAXR_w: mnemonic = "ldaxr"; form = "'Wt, ['Xns]"; break; - case LDAXR_x: mnemonic = "ldaxr"; form = "'Xt, ['Xns]"; break; - case STLXP_w: mnemonic = "stlxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break; - case STLXP_x: mnemonic = "stlxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break; - case LDAXP_w: mnemonic = "ldaxp"; form = "'Wt, 'Wt2, ['Xns]"; break; - case LDAXP_x: mnemonic = "ldaxp"; form = "'Xt, 'Xt2, ['Xns]"; break; - case STLRB_w: mnemonic = "stlrb"; form = "'Wt, ['Xns]"; break; - case STLRH_w: mnemonic = "stlrh"; form = "'Wt, ['Xns]"; break; - case STLR_w: mnemonic = "stlr"; form = "'Wt, ['Xns]"; break; - case STLR_x: mnemonic = "stlr"; form = "'Xt, ['Xns]"; break; - case LDARB_w: mnemonic = "ldarb"; form = "'Wt, ['Xns]"; break; - case LDARH_w: mnemonic = "ldarh"; form = "'Wt, ['Xns]"; break; - case LDAR_w: mnemonic = "ldar"; form = "'Wt, ['Xns]"; break; - case LDAR_x: mnemonic = "ldar"; form = "'Xt, ['Xns]"; break; - default: form = "(LoadStoreExclusive)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPCompare(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Fn, 'Fm"; - const char *form_zero = "'Fn, #0.0"; - - switch (instr->Mask(FPCompareMask)) { - case FCMP_s_zero: - case FCMP_d_zero: form = form_zero; VIXL_FALLTHROUGH(); - case FCMP_s: - case FCMP_d: mnemonic = "fcmp"; break; - case FCMPE_s_zero: - case FCMPE_d_zero: form = form_zero; VIXL_FALLTHROUGH(); - case FCMPE_s: - case FCMPE_d: mnemonic = "fcmpe"; break; - default: form = "(FPCompare)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPConditionalCompare(const Instruction* instr) { - const char *mnemonic = "unmplemented"; - const char *form = "'Fn, 'Fm, 'INzcv, 'Cond"; - - switch (instr->Mask(FPConditionalCompareMask)) { - case FCCMP_s: - case FCCMP_d: mnemonic = "fccmp"; break; - case FCCMPE_s: - case FCCMPE_d: mnemonic = "fccmpe"; break; - default: form = "(FPConditionalCompare)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPConditionalSelect(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Fd, 'Fn, 'Fm, 'Cond"; - - switch (instr->Mask(FPConditionalSelectMask)) { - case FCSEL_s: - case FCSEL_d: mnemonic = "fcsel"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Fd, 'Fn"; - - switch (instr->Mask(FPDataProcessing1SourceMask)) { - #define FORMAT(A, B) \ - case A##_s: \ - case A##_d: mnemonic = B; break; - FORMAT(FMOV, "fmov"); - FORMAT(FABS, "fabs"); - FORMAT(FNEG, "fneg"); - FORMAT(FSQRT, "fsqrt"); - FORMAT(FRINTN, "frintn"); - FORMAT(FRINTP, "frintp"); - FORMAT(FRINTM, "frintm"); - FORMAT(FRINTZ, "frintz"); - FORMAT(FRINTA, "frinta"); - FORMAT(FRINTX, "frintx"); - FORMAT(FRINTI, "frinti"); - #undef FORMAT - case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; - case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break; - case FCVT_hs: mnemonic = "fcvt"; form = "'Hd, 'Sn"; break; - case FCVT_sh: mnemonic = "fcvt"; form = "'Sd, 'Hn"; break; - case FCVT_dh: mnemonic = "fcvt"; form = "'Dd, 'Hn"; break; - case FCVT_hd: mnemonic = "fcvt"; form = "'Hd, 'Dn"; break; - default: form = "(FPDataProcessing1Source)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Fd, 'Fn, 'Fm"; - - switch (instr->Mask(FPDataProcessing2SourceMask)) { - #define FORMAT(A, B) \ - case A##_s: \ - case A##_d: mnemonic = B; break; - FORMAT(FMUL, "fmul"); - FORMAT(FDIV, "fdiv"); - FORMAT(FADD, "fadd"); - FORMAT(FSUB, "fsub"); - FORMAT(FMAX, "fmax"); - FORMAT(FMIN, "fmin"); - FORMAT(FMAXNM, "fmaxnm"); - FORMAT(FMINNM, "fminnm"); - FORMAT(FNMUL, "fnmul"); - #undef FORMAT - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Fd, 'Fn, 'Fm, 'Fa"; - - switch (instr->Mask(FPDataProcessing3SourceMask)) { - #define FORMAT(A, B) \ - case A##_s: \ - case A##_d: mnemonic = B; break; - FORMAT(FMADD, "fmadd"); - FORMAT(FMSUB, "fmsub"); - FORMAT(FNMADD, "fnmadd"); - FORMAT(FNMSUB, "fnmsub"); - #undef FORMAT - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPImmediate(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "(FPImmediate)"; - - switch (instr->Mask(FPImmediateMask)) { - case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break; - case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPIntegerConvert(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(FPIntegerConvert)"; - const char *form_rf = "'Rd, 'Fn"; - const char *form_fr = "'Fd, 'Rn"; - - switch (instr->Mask(FPIntegerConvertMask)) { - case FMOV_ws: - case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; - case FMOV_sw: - case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; - case FMOV_d1_x: mnemonic = "fmov"; form = "'Vd.D[1], 'Rn"; break; - case FMOV_x_d1: mnemonic = "fmov"; form = "'Rd, 'Vn.D[1]"; break; - case FCVTAS_ws: - case FCVTAS_xs: - case FCVTAS_wd: - case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; - case FCVTAU_ws: - case FCVTAU_xs: - case FCVTAU_wd: - case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; - case FCVTMS_ws: - case FCVTMS_xs: - case FCVTMS_wd: - case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break; - case FCVTMU_ws: - case FCVTMU_xs: - case FCVTMU_wd: - case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break; - case FCVTNS_ws: - case FCVTNS_xs: - case FCVTNS_wd: - case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break; - case FCVTNU_ws: - case FCVTNU_xs: - case FCVTNU_wd: - case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; - case FCVTZU_xd: - case FCVTZU_ws: - case FCVTZU_wd: - case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; - case FCVTZS_xd: - case FCVTZS_wd: - case FCVTZS_xs: - case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break; - case FCVTPU_xd: - case FCVTPU_ws: - case FCVTPU_wd: - case FCVTPU_xs: mnemonic = "fcvtpu"; form = form_rf; break; - case FCVTPS_xd: - case FCVTPS_wd: - case FCVTPS_xs: - case FCVTPS_ws: mnemonic = "fcvtps"; form = form_rf; break; - case SCVTF_sw: - case SCVTF_sx: - case SCVTF_dw: - case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; - case UCVTF_sw: - case UCVTF_sx: - case UCVTF_dw: - case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) { - const char *mnemonic = ""; - const char *form = "'Rd, 'Fn, 'IFPFBits"; - const char *form_fr = "'Fd, 'Rn, 'IFPFBits"; - - switch (instr->Mask(FPFixedPointConvertMask)) { - case FCVTZS_ws_fixed: - case FCVTZS_xs_fixed: - case FCVTZS_wd_fixed: - case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break; - case FCVTZU_ws_fixed: - case FCVTZU_xs_fixed: - case FCVTZU_wd_fixed: - case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break; - case SCVTF_sw_fixed: - case SCVTF_sx_fixed: - case SCVTF_dw_fixed: - case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break; - case UCVTF_sw_fixed: - case UCVTF_sx_fixed: - case UCVTF_dw_fixed: - case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break; - default: VIXL_UNREACHABLE(); - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitSystem(const Instruction* instr) { - // Some system instructions hijack their Op and Cp fields to represent a - // range of immediates instead of indicating a different instruction. This - // makes the decoding tricky. - const char *mnemonic = "unimplemented"; - const char *form = "(System)"; - - if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) { - switch (instr->Mask(SystemExclusiveMonitorMask)) { - case CLREX: { - mnemonic = "clrex"; - form = (instr->CRm() == 0xf) ? NULL : "'IX"; - break; - } - } - } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) { - switch (instr->Mask(SystemSysRegMask)) { - case MRS: { - mnemonic = "mrs"; - switch (instr->ImmSystemRegister()) { - case NZCV: form = "'Xt, nzcv"; break; - case FPCR: form = "'Xt, fpcr"; break; - default: form = "'Xt, (unknown)"; break; - } - break; - } - case MSR: { - mnemonic = "msr"; - switch (instr->ImmSystemRegister()) { - case NZCV: form = "nzcv, 'Xt"; break; - case FPCR: form = "fpcr, 'Xt"; break; - default: form = "(unknown), 'Xt"; break; - } - break; - } - } - } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) { - switch (instr->ImmHint()) { - case NOP: { - mnemonic = "nop"; - form = NULL; - break; - } - } - } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) { - switch (instr->Mask(MemBarrierMask)) { - case DMB: { - mnemonic = "dmb"; - form = "'M"; - break; - } - case DSB: { - mnemonic = "dsb"; - form = "'M"; - break; - } - case ISB: { - mnemonic = "isb"; - form = NULL; - break; - } - } - } else if (instr->Mask(SystemSysFMask) == SystemSysFixed) { - switch (instr->SysOp()) { - case IVAU: - mnemonic = "ic"; - form = "ivau, 'Xt"; - break; - case CVAC: - mnemonic = "dc"; - form = "cvac, 'Xt"; - break; - case CVAU: - mnemonic = "dc"; - form = "cvau, 'Xt"; - break; - case CIVAC: - mnemonic = "dc"; - form = "civac, 'Xt"; - break; - case ZVA: - mnemonic = "dc"; - form = "zva, 'Xt"; - break; - default: - mnemonic = "sys"; - if (instr->Rt() == 31) { - form = "'G1, 'Kn, 'Km, 'G2"; - } else { - form = "'G1, 'Kn, 'Km, 'G2, 'Xt"; - } - break; - } - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitException(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'IDebug"; - - switch (instr->Mask(ExceptionMask)) { - case HLT: mnemonic = "hlt"; break; - case BRK: mnemonic = "brk"; break; - case SVC: mnemonic = "svc"; break; - case HVC: mnemonic = "hvc"; break; - case SMC: mnemonic = "smc"; break; - case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; - case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; - case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; - default: form = "(Exception)"; - } - Format(instr, mnemonic, form); -} - - -void Disassembler::VisitCrypto2RegSHA(const Instruction* instr) { - VisitUnimplemented(instr); -} - - -void Disassembler::VisitCrypto3RegSHA(const Instruction* instr) { - VisitUnimplemented(instr); -} - - -void Disassembler::VisitCryptoAES(const Instruction* instr) { - VisitUnimplemented(instr); -} - - -void Disassembler::VisitNEON2RegMisc(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Vd.%s, 'Vn.%s"; - const char *form_cmp_zero = "'Vd.%s, 'Vn.%s, #0"; - const char *form_fcmp_zero = "'Vd.%s, 'Vn.%s, #0.0"; - NEONFormatDecoder nfd(instr); - - static const NEONFormatMap map_lp_ta = { - {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D} - }; - - static const NEONFormatMap map_cvt_ta = { - {22}, {NF_4S, NF_2D} - }; - - static const NEONFormatMap map_cvt_tb = { - {22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S} - }; - - if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) { - // These instructions all use a two bit size field, except NOT and RBIT, - // which use the field to encode the operation. - switch (instr->Mask(NEON2RegMiscMask)) { - case NEON_REV64: mnemonic = "rev64"; break; - case NEON_REV32: mnemonic = "rev32"; break; - case NEON_REV16: mnemonic = "rev16"; break; - case NEON_SADDLP: - mnemonic = "saddlp"; - nfd.SetFormatMap(0, &map_lp_ta); - break; - case NEON_UADDLP: - mnemonic = "uaddlp"; - nfd.SetFormatMap(0, &map_lp_ta); - break; - case NEON_SUQADD: mnemonic = "suqadd"; break; - case NEON_USQADD: mnemonic = "usqadd"; break; - case NEON_CLS: mnemonic = "cls"; break; - case NEON_CLZ: mnemonic = "clz"; break; - case NEON_CNT: mnemonic = "cnt"; break; - case NEON_SADALP: - mnemonic = "sadalp"; - nfd.SetFormatMap(0, &map_lp_ta); - break; - case NEON_UADALP: - mnemonic = "uadalp"; - nfd.SetFormatMap(0, &map_lp_ta); - break; - case NEON_SQABS: mnemonic = "sqabs"; break; - case NEON_SQNEG: mnemonic = "sqneg"; break; - case NEON_CMGT_zero: mnemonic = "cmgt"; form = form_cmp_zero; break; - case NEON_CMGE_zero: mnemonic = "cmge"; form = form_cmp_zero; break; - case NEON_CMEQ_zero: mnemonic = "cmeq"; form = form_cmp_zero; break; - case NEON_CMLE_zero: mnemonic = "cmle"; form = form_cmp_zero; break; - case NEON_CMLT_zero: mnemonic = "cmlt"; form = form_cmp_zero; break; - case NEON_ABS: mnemonic = "abs"; break; - case NEON_NEG: mnemonic = "neg"; break; - case NEON_RBIT_NOT: - switch (instr->FPType()) { - case 0: mnemonic = "mvn"; break; - case 1: mnemonic = "rbit"; break; - default: form = "(NEON2RegMisc)"; - } - nfd.SetFormatMaps(nfd.LogicalFormatMap()); - break; - } - } else { - // These instructions all use a one bit size field, except XTN, SQXTUN, - // SHLL, SQXTN and UQXTN, which use a two bit size field. - nfd.SetFormatMaps(nfd.FPFormatMap()); - switch (instr->Mask(NEON2RegMiscFPMask)) { - case NEON_FABS: mnemonic = "fabs"; break; - case NEON_FNEG: mnemonic = "fneg"; break; - case NEON_FCVTN: - mnemonic = instr->Mask(NEON_Q) ? "fcvtn2" : "fcvtn"; - nfd.SetFormatMap(0, &map_cvt_tb); - nfd.SetFormatMap(1, &map_cvt_ta); - break; - case NEON_FCVTXN: - mnemonic = instr->Mask(NEON_Q) ? "fcvtxn2" : "fcvtxn"; - nfd.SetFormatMap(0, &map_cvt_tb); - nfd.SetFormatMap(1, &map_cvt_ta); - break; - case NEON_FCVTL: - mnemonic = instr->Mask(NEON_Q) ? "fcvtl2" : "fcvtl"; - nfd.SetFormatMap(0, &map_cvt_ta); - nfd.SetFormatMap(1, &map_cvt_tb); - break; - case NEON_FRINTN: mnemonic = "frintn"; break; - case NEON_FRINTA: mnemonic = "frinta"; break; - case NEON_FRINTP: mnemonic = "frintp"; break; - case NEON_FRINTM: mnemonic = "frintm"; break; - case NEON_FRINTX: mnemonic = "frintx"; break; - case NEON_FRINTZ: mnemonic = "frintz"; break; - case NEON_FRINTI: mnemonic = "frinti"; break; - case NEON_FCVTNS: mnemonic = "fcvtns"; break; - case NEON_FCVTNU: mnemonic = "fcvtnu"; break; - case NEON_FCVTPS: mnemonic = "fcvtps"; break; - case NEON_FCVTPU: mnemonic = "fcvtpu"; break; - case NEON_FCVTMS: mnemonic = "fcvtms"; break; - case NEON_FCVTMU: mnemonic = "fcvtmu"; break; - case NEON_FCVTZS: mnemonic = "fcvtzs"; break; - case NEON_FCVTZU: mnemonic = "fcvtzu"; break; - case NEON_FCVTAS: mnemonic = "fcvtas"; break; - case NEON_FCVTAU: mnemonic = "fcvtau"; break; - case NEON_FSQRT: mnemonic = "fsqrt"; break; - case NEON_SCVTF: mnemonic = "scvtf"; break; - case NEON_UCVTF: mnemonic = "ucvtf"; break; - case NEON_URSQRTE: mnemonic = "ursqrte"; break; - case NEON_URECPE: mnemonic = "urecpe"; break; - case NEON_FRSQRTE: mnemonic = "frsqrte"; break; - case NEON_FRECPE: mnemonic = "frecpe"; break; - case NEON_FCMGT_zero: mnemonic = "fcmgt"; form = form_fcmp_zero; break; - case NEON_FCMGE_zero: mnemonic = "fcmge"; form = form_fcmp_zero; break; - case NEON_FCMEQ_zero: mnemonic = "fcmeq"; form = form_fcmp_zero; break; - case NEON_FCMLE_zero: mnemonic = "fcmle"; form = form_fcmp_zero; break; - case NEON_FCMLT_zero: mnemonic = "fcmlt"; form = form_fcmp_zero; break; - default: - if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) && - (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) { - nfd.SetFormatMap(0, nfd.IntegerFormatMap()); - nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); - - switch (instr->Mask(NEON2RegMiscMask)) { - case NEON_XTN: mnemonic = "xtn"; break; - case NEON_SQXTN: mnemonic = "sqxtn"; break; - case NEON_UQXTN: mnemonic = "uqxtn"; break; - case NEON_SQXTUN: mnemonic = "sqxtun"; break; - case NEON_SHLL: - mnemonic = "shll"; - nfd.SetFormatMap(0, nfd.LongIntegerFormatMap()); - nfd.SetFormatMap(1, nfd.IntegerFormatMap()); - switch (instr->NEONSize()) { - case 0: form = "'Vd.%s, 'Vn.%s, #8"; break; - case 1: form = "'Vd.%s, 'Vn.%s, #16"; break; - case 2: form = "'Vd.%s, 'Vn.%s, #32"; break; - default: form = "(NEON2RegMisc)"; - } - } - Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); - return; - } else { - form = "(NEON2RegMisc)"; - } - } - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEON3Same(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; - NEONFormatDecoder nfd(instr); - - if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) { - switch (instr->Mask(NEON3SameLogicalMask)) { - case NEON_AND: mnemonic = "and"; break; - case NEON_ORR: - mnemonic = "orr"; - if (instr->Rm() == instr->Rn()) { - mnemonic = "mov"; - form = "'Vd.%s, 'Vn.%s"; - } - break; - case NEON_ORN: mnemonic = "orn"; break; - case NEON_EOR: mnemonic = "eor"; break; - case NEON_BIC: mnemonic = "bic"; break; - case NEON_BIF: mnemonic = "bif"; break; - case NEON_BIT: mnemonic = "bit"; break; - case NEON_BSL: mnemonic = "bsl"; break; - default: form = "(NEON3Same)"; - } - nfd.SetFormatMaps(nfd.LogicalFormatMap()); - } else { - static const char *mnemonics[] = { - "shadd", "uhadd", "shadd", "uhadd", - "sqadd", "uqadd", "sqadd", "uqadd", - "srhadd", "urhadd", "srhadd", "urhadd", - NULL, NULL, NULL, NULL, // Handled by logical cases above. - "shsub", "uhsub", "shsub", "uhsub", - "sqsub", "uqsub", "sqsub", "uqsub", - "cmgt", "cmhi", "cmgt", "cmhi", - "cmge", "cmhs", "cmge", "cmhs", - "sshl", "ushl", "sshl", "ushl", - "sqshl", "uqshl", "sqshl", "uqshl", - "srshl", "urshl", "srshl", "urshl", - "sqrshl", "uqrshl", "sqrshl", "uqrshl", - "smax", "umax", "smax", "umax", - "smin", "umin", "smin", "umin", - "sabd", "uabd", "sabd", "uabd", - "saba", "uaba", "saba", "uaba", - "add", "sub", "add", "sub", - "cmtst", "cmeq", "cmtst", "cmeq", - "mla", "mls", "mla", "mls", - "mul", "pmul", "mul", "pmul", - "smaxp", "umaxp", "smaxp", "umaxp", - "sminp", "uminp", "sminp", "uminp", - "sqdmulh", "sqrdmulh", "sqdmulh", "sqrdmulh", - "addp", "unallocated", "addp", "unallocated", - "fmaxnm", "fmaxnmp", "fminnm", "fminnmp", - "fmla", "unallocated", "fmls", "unallocated", - "fadd", "faddp", "fsub", "fabd", - "fmulx", "fmul", "unallocated", "unallocated", - "fcmeq", "fcmge", "unallocated", "fcmgt", - "unallocated", "facge", "unallocated", "facgt", - "fmax", "fmaxp", "fmin", "fminp", - "frecps", "fdiv", "frsqrts", "unallocated"}; - - // Operation is determined by the opcode bits (15-11), the top bit of - // size (23) and the U bit (29). - unsigned index = (instr->Bits(15, 11) << 2) | (instr->Bit(23) << 1) | - instr->Bit(29); - VIXL_ASSERT(index < (sizeof(mnemonics) / sizeof(mnemonics[0]))); - mnemonic = mnemonics[index]; - // Assert that index is not one of the previously handled logical - // instructions. - VIXL_ASSERT(mnemonic != NULL); - - if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) { - nfd.SetFormatMaps(nfd.FPFormatMap()); - } - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEON3Different(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; - - NEONFormatDecoder nfd(instr); - nfd.SetFormatMap(0, nfd.LongIntegerFormatMap()); - - // Ignore the Q bit. Appending a "2" suffix is handled later. - switch (instr->Mask(NEON3DifferentMask) & ~NEON_Q) { - case NEON_PMULL: mnemonic = "pmull"; break; - case NEON_SABAL: mnemonic = "sabal"; break; - case NEON_SABDL: mnemonic = "sabdl"; break; - case NEON_SADDL: mnemonic = "saddl"; break; - case NEON_SMLAL: mnemonic = "smlal"; break; - case NEON_SMLSL: mnemonic = "smlsl"; break; - case NEON_SMULL: mnemonic = "smull"; break; - case NEON_SSUBL: mnemonic = "ssubl"; break; - case NEON_SQDMLAL: mnemonic = "sqdmlal"; break; - case NEON_SQDMLSL: mnemonic = "sqdmlsl"; break; - case NEON_SQDMULL: mnemonic = "sqdmull"; break; - case NEON_UABAL: mnemonic = "uabal"; break; - case NEON_UABDL: mnemonic = "uabdl"; break; - case NEON_UADDL: mnemonic = "uaddl"; break; - case NEON_UMLAL: mnemonic = "umlal"; break; - case NEON_UMLSL: mnemonic = "umlsl"; break; - case NEON_UMULL: mnemonic = "umull"; break; - case NEON_USUBL: mnemonic = "usubl"; break; - case NEON_SADDW: - mnemonic = "saddw"; - nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); - break; - case NEON_SSUBW: - mnemonic = "ssubw"; - nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); - break; - case NEON_UADDW: - mnemonic = "uaddw"; - nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); - break; - case NEON_USUBW: - mnemonic = "usubw"; - nfd.SetFormatMap(1, nfd.LongIntegerFormatMap()); - break; - case NEON_ADDHN: - mnemonic = "addhn"; - nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); - nfd.SetFormatMap(0, nfd.IntegerFormatMap()); - break; - case NEON_RADDHN: - mnemonic = "raddhn"; - nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); - nfd.SetFormatMap(0, nfd.IntegerFormatMap()); - break; - case NEON_RSUBHN: - mnemonic = "rsubhn"; - nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); - nfd.SetFormatMap(0, nfd.IntegerFormatMap()); - break; - case NEON_SUBHN: - mnemonic = "subhn"; - nfd.SetFormatMaps(nfd.LongIntegerFormatMap()); - nfd.SetFormatMap(0, nfd.IntegerFormatMap()); - break; - default: form = "(NEON3Different)"; - } - Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONAcrossLanes(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, 'Vn.%s"; - - NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap(), - NEONFormatDecoder::IntegerFormatMap()); - - if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) { - nfd.SetFormatMap(0, nfd.FPScalarFormatMap()); - nfd.SetFormatMap(1, nfd.FPFormatMap()); - switch (instr->Mask(NEONAcrossLanesFPMask)) { - case NEON_FMAXV: mnemonic = "fmaxv"; break; - case NEON_FMINV: mnemonic = "fminv"; break; - case NEON_FMAXNMV: mnemonic = "fmaxnmv"; break; - case NEON_FMINNMV: mnemonic = "fminnmv"; break; - default: form = "(NEONAcrossLanes)"; break; - } - } else if (instr->Mask(NEONAcrossLanesFMask) == NEONAcrossLanesFixed) { - switch (instr->Mask(NEONAcrossLanesMask)) { - case NEON_ADDV: mnemonic = "addv"; break; - case NEON_SMAXV: mnemonic = "smaxv"; break; - case NEON_SMINV: mnemonic = "sminv"; break; - case NEON_UMAXV: mnemonic = "umaxv"; break; - case NEON_UMINV: mnemonic = "uminv"; break; - case NEON_SADDLV: - mnemonic = "saddlv"; - nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); - break; - case NEON_UADDLV: - mnemonic = "uaddlv"; - nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); - break; - default: form = "(NEONAcrossLanes)"; break; - } - } - Format(instr, mnemonic, nfd.Substitute(form, - NEONFormatDecoder::kPlaceholder, NEONFormatDecoder::kFormat)); -} - - -void Disassembler::VisitNEONByIndexedElement(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - bool l_instr = false; - bool fp_instr = false; - - const char *form = "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]"; - - static const NEONFormatMap map_ta = { - {23, 22}, {NF_UNDEF, NF_4S, NF_2D} - }; - NEONFormatDecoder nfd(instr, &map_ta, - NEONFormatDecoder::IntegerFormatMap(), - NEONFormatDecoder::ScalarFormatMap()); - - switch (instr->Mask(NEONByIndexedElementMask)) { - case NEON_SMULL_byelement: mnemonic = "smull"; l_instr = true; break; - case NEON_UMULL_byelement: mnemonic = "umull"; l_instr = true; break; - case NEON_SMLAL_byelement: mnemonic = "smlal"; l_instr = true; break; - case NEON_UMLAL_byelement: mnemonic = "umlal"; l_instr = true; break; - case NEON_SMLSL_byelement: mnemonic = "smlsl"; l_instr = true; break; - case NEON_UMLSL_byelement: mnemonic = "umlsl"; l_instr = true; break; - case NEON_SQDMULL_byelement: mnemonic = "sqdmull"; l_instr = true; break; - case NEON_SQDMLAL_byelement: mnemonic = "sqdmlal"; l_instr = true; break; - case NEON_SQDMLSL_byelement: mnemonic = "sqdmlsl"; l_instr = true; break; - case NEON_MUL_byelement: mnemonic = "mul"; break; - case NEON_MLA_byelement: mnemonic = "mla"; break; - case NEON_MLS_byelement: mnemonic = "mls"; break; - case NEON_SQDMULH_byelement: mnemonic = "sqdmulh"; break; - case NEON_SQRDMULH_byelement: mnemonic = "sqrdmulh"; break; - default: - switch (instr->Mask(NEONByIndexedElementFPMask)) { - case NEON_FMUL_byelement: mnemonic = "fmul"; fp_instr = true; break; - case NEON_FMLA_byelement: mnemonic = "fmla"; fp_instr = true; break; - case NEON_FMLS_byelement: mnemonic = "fmls"; fp_instr = true; break; - case NEON_FMULX_byelement: mnemonic = "fmulx"; fp_instr = true; break; - } - } - - if (l_instr) { - Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form)); - } else if (fp_instr) { - nfd.SetFormatMap(0, nfd.FPFormatMap()); - Format(instr, mnemonic, nfd.Substitute(form)); - } else { - nfd.SetFormatMap(0, nfd.IntegerFormatMap()); - Format(instr, mnemonic, nfd.Substitute(form)); - } -} - - -void Disassembler::VisitNEONCopy(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONCopy)"; - - NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap(), - NEONFormatDecoder::TriangularScalarFormatMap()); - - if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) { - mnemonic = "mov"; - nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); - form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]"; - } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) { - mnemonic = "mov"; - nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); - if (nfd.GetVectorFormat() == kFormatD) { - form = "'Vd.%s['IVInsIndex1], 'Xn"; - } else { - form = "'Vd.%s['IVInsIndex1], 'Wn"; - } - } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) { - if (instr->Mask(NEON_Q) || ((instr->ImmNEON5() & 7) == 4)) { - mnemonic = "mov"; - } else { - mnemonic = "umov"; - } - nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); - if (nfd.GetVectorFormat() == kFormatD) { - form = "'Xd, 'Vn.%s['IVInsIndex1]"; - } else { - form = "'Wd, 'Vn.%s['IVInsIndex1]"; - } - } else if (instr->Mask(NEONCopySmovMask) == NEON_SMOV) { - mnemonic = "smov"; - nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap()); - form = "'Rdq, 'Vn.%s['IVInsIndex1]"; - } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) { - mnemonic = "dup"; - form = "'Vd.%s, 'Vn.%s['IVInsIndex1]"; - } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) { - mnemonic = "dup"; - if (nfd.GetVectorFormat() == kFormat2D) { - form = "'Vd.%s, 'Xn"; - } else { - form = "'Vd.%s, 'Wn"; - } - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONExtract(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONExtract)"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap()); - if (instr->Mask(NEONExtractMask) == NEON_EXT) { - mnemonic = "ext"; - form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract"; - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONLoadStoreMultiStruct(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONLoadStoreMultiStruct)"; - const char *form_1v = "{'Vt.%1$s}, ['Xns]"; - const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]"; - const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]"; - const char *form_4v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); - - switch (instr->Mask(NEONLoadStoreMultiStructMask)) { - case NEON_LD1_1v: mnemonic = "ld1"; form = form_1v; break; - case NEON_LD1_2v: mnemonic = "ld1"; form = form_2v; break; - case NEON_LD1_3v: mnemonic = "ld1"; form = form_3v; break; - case NEON_LD1_4v: mnemonic = "ld1"; form = form_4v; break; - case NEON_LD2: mnemonic = "ld2"; form = form_2v; break; - case NEON_LD3: mnemonic = "ld3"; form = form_3v; break; - case NEON_LD4: mnemonic = "ld4"; form = form_4v; break; - case NEON_ST1_1v: mnemonic = "st1"; form = form_1v; break; - case NEON_ST1_2v: mnemonic = "st1"; form = form_2v; break; - case NEON_ST1_3v: mnemonic = "st1"; form = form_3v; break; - case NEON_ST1_4v: mnemonic = "st1"; form = form_4v; break; - case NEON_ST2: mnemonic = "st2"; form = form_2v; break; - case NEON_ST3: mnemonic = "st3"; form = form_3v; break; - case NEON_ST4: mnemonic = "st4"; form = form_4v; break; - default: break; - } - - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONLoadStoreMultiStructPostIndex( - const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONLoadStoreMultiStructPostIndex)"; - const char *form_1v = "{'Vt.%1$s}, ['Xns], 'Xmr1"; - const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2"; - const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3"; - const char *form_4v = - "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); - - switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) { - case NEON_LD1_1v_post: mnemonic = "ld1"; form = form_1v; break; - case NEON_LD1_2v_post: mnemonic = "ld1"; form = form_2v; break; - case NEON_LD1_3v_post: mnemonic = "ld1"; form = form_3v; break; - case NEON_LD1_4v_post: mnemonic = "ld1"; form = form_4v; break; - case NEON_LD2_post: mnemonic = "ld2"; form = form_2v; break; - case NEON_LD3_post: mnemonic = "ld3"; form = form_3v; break; - case NEON_LD4_post: mnemonic = "ld4"; form = form_4v; break; - case NEON_ST1_1v_post: mnemonic = "st1"; form = form_1v; break; - case NEON_ST1_2v_post: mnemonic = "st1"; form = form_2v; break; - case NEON_ST1_3v_post: mnemonic = "st1"; form = form_3v; break; - case NEON_ST1_4v_post: mnemonic = "st1"; form = form_4v; break; - case NEON_ST2_post: mnemonic = "st2"; form = form_2v; break; - case NEON_ST3_post: mnemonic = "st3"; form = form_3v; break; - case NEON_ST4_post: mnemonic = "st4"; form = form_4v; break; - default: break; - } - - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONLoadStoreSingleStruct(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONLoadStoreSingleStruct)"; - - const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns]"; - const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns]"; - const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns]"; - const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns]"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); - - switch (instr->Mask(NEONLoadStoreSingleStructMask)) { - case NEON_LD1_b: mnemonic = "ld1"; form = form_1b; break; - case NEON_LD1_h: mnemonic = "ld1"; form = form_1h; break; - case NEON_LD1_s: - mnemonic = "ld1"; - VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d); - form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; - break; - case NEON_ST1_b: mnemonic = "st1"; form = form_1b; break; - case NEON_ST1_h: mnemonic = "st1"; form = form_1h; break; - case NEON_ST1_s: - mnemonic = "st1"; - VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d); - form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; - break; - case NEON_LD1R: - mnemonic = "ld1r"; - form = "{'Vt.%s}, ['Xns]"; - break; - case NEON_LD2_b: - case NEON_ST2_b: - mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; - form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]"; - break; - case NEON_LD2_h: - case NEON_ST2_h: - mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; - form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]"; - break; - case NEON_LD2_s: - case NEON_ST2_s: - VIXL_STATIC_ASSERT((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d); - VIXL_STATIC_ASSERT((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d); - mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; - if ((instr->NEONLSSize() & 1) == 0) - form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]"; - else - form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]"; - break; - case NEON_LD2R: - mnemonic = "ld2r"; - form = "{'Vt.%s, 'Vt2.%s}, ['Xns]"; - break; - case NEON_LD3_b: - case NEON_ST3_b: - mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; - form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]"; - break; - case NEON_LD3_h: - case NEON_ST3_h: - mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; - form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]"; - break; - case NEON_LD3_s: - case NEON_ST3_s: - mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; - if ((instr->NEONLSSize() & 1) == 0) - form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]"; - else - form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]"; - break; - case NEON_LD3R: - mnemonic = "ld3r"; - form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]"; - break; - case NEON_LD4_b: - case NEON_ST4_b: - mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; - form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]"; - break; - case NEON_LD4_h: - case NEON_ST4_h: - mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; - form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]"; - break; - case NEON_LD4_s: - case NEON_ST4_s: - VIXL_STATIC_ASSERT((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d); - VIXL_STATIC_ASSERT((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d); - mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; - if ((instr->NEONLSSize() & 1) == 0) - form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]"; - else - form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]"; - break; - case NEON_LD4R: - mnemonic = "ld4r"; - form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]"; - break; - default: break; - } - - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONLoadStoreSingleStructPostIndex( - const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONLoadStoreSingleStructPostIndex)"; - - const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1"; - const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2"; - const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4"; - const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap()); - - switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) { - case NEON_LD1_b_post: mnemonic = "ld1"; form = form_1b; break; - case NEON_LD1_h_post: mnemonic = "ld1"; form = form_1h; break; - case NEON_LD1_s_post: - mnemonic = "ld1"; - VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d); - form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; - break; - case NEON_ST1_b_post: mnemonic = "st1"; form = form_1b; break; - case NEON_ST1_h_post: mnemonic = "st1"; form = form_1h; break; - case NEON_ST1_s_post: - mnemonic = "st1"; - VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d); - form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d; - break; - case NEON_LD1R_post: - mnemonic = "ld1r"; - form = "{'Vt.%s}, ['Xns], 'Xmz1"; - break; - case NEON_LD2_b_post: - case NEON_ST2_b_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; - form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2"; - break; - case NEON_ST2_h_post: - case NEON_LD2_h_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; - form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4"; - break; - case NEON_LD2_s_post: - case NEON_ST2_s_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2"; - if ((instr->NEONLSSize() & 1) == 0) - form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8"; - else - form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16"; - break; - case NEON_LD2R_post: - mnemonic = "ld2r"; - form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2"; - break; - case NEON_LD3_b_post: - case NEON_ST3_b_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; - form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3"; - break; - case NEON_LD3_h_post: - case NEON_ST3_h_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; - form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6"; - break; - case NEON_LD3_s_post: - case NEON_ST3_s_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3"; - if ((instr->NEONLSSize() & 1) == 0) - form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12"; - else - form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmr3"; - break; - case NEON_LD3R_post: - mnemonic = "ld3r"; - form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3"; - break; - case NEON_LD4_b_post: - case NEON_ST4_b_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; - form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4"; - break; - case NEON_LD4_h_post: - case NEON_ST4_h_post: - mnemonic = (instr->LdStXLoad()) == 1 ? "ld4" : "st4"; - form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8"; - break; - case NEON_LD4_s_post: - case NEON_ST4_s_post: - mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4"; - if ((instr->NEONLSSize() & 1) == 0) - form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16"; - else - form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32"; - break; - case NEON_LD4R_post: - mnemonic = "ld4r"; - form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4"; - break; - default: break; - } - - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONModifiedImmediate(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1"; - - int cmode = instr->NEONCmode(); - int cmode_3 = (cmode >> 3) & 1; - int cmode_2 = (cmode >> 2) & 1; - int cmode_1 = (cmode >> 1) & 1; - int cmode_0 = cmode & 1; - int q = instr->NEONQ(); - int op = instr->NEONModImmOp(); - - static const NEONFormatMap map_b = { {30}, {NF_8B, NF_16B} }; - static const NEONFormatMap map_h = { {30}, {NF_4H, NF_8H} }; - static const NEONFormatMap map_s = { {30}, {NF_2S, NF_4S} }; - NEONFormatDecoder nfd(instr, &map_b); - - if (cmode_3 == 0) { - if (cmode_0 == 0) { - mnemonic = (op == 1) ? "mvni" : "movi"; - } else { // cmode<0> == '1'. - mnemonic = (op == 1) ? "bic" : "orr"; - } - nfd.SetFormatMap(0, &map_s); - } else { // cmode<3> == '1'. - if (cmode_2 == 0) { - if (cmode_0 == 0) { - mnemonic = (op == 1) ? "mvni" : "movi"; - } else { // cmode<0> == '1'. - mnemonic = (op == 1) ? "bic" : "orr"; - } - nfd.SetFormatMap(0, &map_h); - } else { // cmode<2> == '1'. - if (cmode_1 == 0) { - mnemonic = (op == 1) ? "mvni" : "movi"; - form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2"; - nfd.SetFormatMap(0, &map_s); - } else { // cmode<1> == '1'. - if (cmode_0 == 0) { - mnemonic = "movi"; - if (op == 0) { - form = "'Vt.%s, 'IVMIImm8"; - } else { - form = (q == 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm"; - } - } else { // cmode<0> == '1' - mnemonic = "fmov"; - if (op == 0) { - form = "'Vt.%s, 'IVMIImmFPSingle"; - nfd.SetFormatMap(0, &map_s); - } else { - if (q == 1) { - form = "'Vt.2d, 'IVMIImmFPDouble"; - } - } - } - } - } - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONScalar2RegMisc(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, %sn"; - const char *form_0 = "%sd, %sn, #0"; - const char *form_fp0 = "%sd, %sn, #0.0"; - - NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); - - if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) { - // These instructions all use a two bit size field, except NOT and RBIT, - // which use the field to encode the operation. - switch (instr->Mask(NEONScalar2RegMiscMask)) { - case NEON_CMGT_zero_scalar: mnemonic = "cmgt"; form = form_0; break; - case NEON_CMGE_zero_scalar: mnemonic = "cmge"; form = form_0; break; - case NEON_CMLE_zero_scalar: mnemonic = "cmle"; form = form_0; break; - case NEON_CMLT_zero_scalar: mnemonic = "cmlt"; form = form_0; break; - case NEON_CMEQ_zero_scalar: mnemonic = "cmeq"; form = form_0; break; - case NEON_NEG_scalar: mnemonic = "neg"; break; - case NEON_SQNEG_scalar: mnemonic = "sqneg"; break; - case NEON_ABS_scalar: mnemonic = "abs"; break; - case NEON_SQABS_scalar: mnemonic = "sqabs"; break; - case NEON_SUQADD_scalar: mnemonic = "suqadd"; break; - case NEON_USQADD_scalar: mnemonic = "usqadd"; break; - default: form = "(NEONScalar2RegMisc)"; - } - } else { - // These instructions all use a one bit size field, except SQXTUN, SQXTN - // and UQXTN, which use a two bit size field. - nfd.SetFormatMaps(nfd.FPScalarFormatMap()); - switch (instr->Mask(NEONScalar2RegMiscFPMask)) { - case NEON_FRSQRTE_scalar: mnemonic = "frsqrte"; break; - case NEON_FRECPE_scalar: mnemonic = "frecpe"; break; - case NEON_SCVTF_scalar: mnemonic = "scvtf"; break; - case NEON_UCVTF_scalar: mnemonic = "ucvtf"; break; - case NEON_FCMGT_zero_scalar: mnemonic = "fcmgt"; form = form_fp0; break; - case NEON_FCMGE_zero_scalar: mnemonic = "fcmge"; form = form_fp0; break; - case NEON_FCMLE_zero_scalar: mnemonic = "fcmle"; form = form_fp0; break; - case NEON_FCMLT_zero_scalar: mnemonic = "fcmlt"; form = form_fp0; break; - case NEON_FCMEQ_zero_scalar: mnemonic = "fcmeq"; form = form_fp0; break; - case NEON_FRECPX_scalar: mnemonic = "frecpx"; break; - case NEON_FCVTNS_scalar: mnemonic = "fcvtns"; break; - case NEON_FCVTNU_scalar: mnemonic = "fcvtnu"; break; - case NEON_FCVTPS_scalar: mnemonic = "fcvtps"; break; - case NEON_FCVTPU_scalar: mnemonic = "fcvtpu"; break; - case NEON_FCVTMS_scalar: mnemonic = "fcvtms"; break; - case NEON_FCVTMU_scalar: mnemonic = "fcvtmu"; break; - case NEON_FCVTZS_scalar: mnemonic = "fcvtzs"; break; - case NEON_FCVTZU_scalar: mnemonic = "fcvtzu"; break; - case NEON_FCVTAS_scalar: mnemonic = "fcvtas"; break; - case NEON_FCVTAU_scalar: mnemonic = "fcvtau"; break; - case NEON_FCVTXN_scalar: - nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); - mnemonic = "fcvtxn"; - break; - default: - nfd.SetFormatMap(0, nfd.ScalarFormatMap()); - nfd.SetFormatMap(1, nfd.LongScalarFormatMap()); - switch (instr->Mask(NEONScalar2RegMiscMask)) { - case NEON_SQXTN_scalar: mnemonic = "sqxtn"; break; - case NEON_UQXTN_scalar: mnemonic = "uqxtn"; break; - case NEON_SQXTUN_scalar: mnemonic = "sqxtun"; break; - default: form = "(NEONScalar2RegMisc)"; - } - } - } - Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); -} - - -void Disassembler::VisitNEONScalar3Diff(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, %sn, %sm"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap(), - NEONFormatDecoder::ScalarFormatMap()); - - switch (instr->Mask(NEONScalar3DiffMask)) { - case NEON_SQDMLAL_scalar : mnemonic = "sqdmlal"; break; - case NEON_SQDMLSL_scalar : mnemonic = "sqdmlsl"; break; - case NEON_SQDMULL_scalar : mnemonic = "sqdmull"; break; - default: form = "(NEONScalar3Diff)"; - } - Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); -} - - -void Disassembler::VisitNEONScalar3Same(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, %sn, %sm"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); - - if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) { - nfd.SetFormatMaps(nfd.FPScalarFormatMap()); - switch (instr->Mask(NEONScalar3SameFPMask)) { - case NEON_FACGE_scalar: mnemonic = "facge"; break; - case NEON_FACGT_scalar: mnemonic = "facgt"; break; - case NEON_FCMEQ_scalar: mnemonic = "fcmeq"; break; - case NEON_FCMGE_scalar: mnemonic = "fcmge"; break; - case NEON_FCMGT_scalar: mnemonic = "fcmgt"; break; - case NEON_FMULX_scalar: mnemonic = "fmulx"; break; - case NEON_FRECPS_scalar: mnemonic = "frecps"; break; - case NEON_FRSQRTS_scalar: mnemonic = "frsqrts"; break; - case NEON_FABD_scalar: mnemonic = "fabd"; break; - default: form = "(NEONScalar3Same)"; - } - } else { - switch (instr->Mask(NEONScalar3SameMask)) { - case NEON_ADD_scalar: mnemonic = "add"; break; - case NEON_SUB_scalar: mnemonic = "sub"; break; - case NEON_CMEQ_scalar: mnemonic = "cmeq"; break; - case NEON_CMGE_scalar: mnemonic = "cmge"; break; - case NEON_CMGT_scalar: mnemonic = "cmgt"; break; - case NEON_CMHI_scalar: mnemonic = "cmhi"; break; - case NEON_CMHS_scalar: mnemonic = "cmhs"; break; - case NEON_CMTST_scalar: mnemonic = "cmtst"; break; - case NEON_UQADD_scalar: mnemonic = "uqadd"; break; - case NEON_SQADD_scalar: mnemonic = "sqadd"; break; - case NEON_UQSUB_scalar: mnemonic = "uqsub"; break; - case NEON_SQSUB_scalar: mnemonic = "sqsub"; break; - case NEON_USHL_scalar: mnemonic = "ushl"; break; - case NEON_SSHL_scalar: mnemonic = "sshl"; break; - case NEON_UQSHL_scalar: mnemonic = "uqshl"; break; - case NEON_SQSHL_scalar: mnemonic = "sqshl"; break; - case NEON_URSHL_scalar: mnemonic = "urshl"; break; - case NEON_SRSHL_scalar: mnemonic = "srshl"; break; - case NEON_UQRSHL_scalar: mnemonic = "uqrshl"; break; - case NEON_SQRSHL_scalar: mnemonic = "sqrshl"; break; - case NEON_SQDMULH_scalar: mnemonic = "sqdmulh"; break; - case NEON_SQRDMULH_scalar: mnemonic = "sqrdmulh"; break; - default: form = "(NEONScalar3Same)"; - } - } - Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); -} - - -void Disassembler::VisitNEONScalarByIndexedElement(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, %sn, 'Ve.%s['IVByElemIndex]"; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap()); - bool long_instr = false; - - switch (instr->Mask(NEONScalarByIndexedElementMask)) { - case NEON_SQDMULL_byelement_scalar: - mnemonic = "sqdmull"; - long_instr = true; - break; - case NEON_SQDMLAL_byelement_scalar: - mnemonic = "sqdmlal"; - long_instr = true; - break; - case NEON_SQDMLSL_byelement_scalar: - mnemonic = "sqdmlsl"; - long_instr = true; - break; - case NEON_SQDMULH_byelement_scalar: - mnemonic = "sqdmulh"; - break; - case NEON_SQRDMULH_byelement_scalar: - mnemonic = "sqrdmulh"; - break; - default: - nfd.SetFormatMap(0, nfd.FPScalarFormatMap()); - switch (instr->Mask(NEONScalarByIndexedElementFPMask)) { - case NEON_FMUL_byelement_scalar: mnemonic = "fmul"; break; - case NEON_FMLA_byelement_scalar: mnemonic = "fmla"; break; - case NEON_FMLS_byelement_scalar: mnemonic = "fmls"; break; - case NEON_FMULX_byelement_scalar: mnemonic = "fmulx"; break; - default: form = "(NEONScalarByIndexedElement)"; - } - } - - if (long_instr) { - nfd.SetFormatMap(0, nfd.LongScalarFormatMap()); - } - - Format(instr, mnemonic, nfd.Substitute( - form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat)); -} - - -void Disassembler::VisitNEONScalarCopy(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONScalarCopy)"; - - NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap()); - - if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) { - mnemonic = "mov"; - form = "%sd, 'Vn.%s['IVInsIndex1]"; - } - - Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat)); -} - - -void Disassembler::VisitNEONScalarPairwise(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, 'Vn.%s"; - NEONFormatMap map = { {22}, {NF_2S, NF_2D} }; - NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap(), &map); - - switch (instr->Mask(NEONScalarPairwiseMask)) { - case NEON_ADDP_scalar: mnemonic = "addp"; break; - case NEON_FADDP_scalar: mnemonic = "faddp"; break; - case NEON_FMAXP_scalar: mnemonic = "fmaxp"; break; - case NEON_FMAXNMP_scalar: mnemonic = "fmaxnmp"; break; - case NEON_FMINP_scalar: mnemonic = "fminp"; break; - case NEON_FMINNMP_scalar: mnemonic = "fminnmp"; break; - default: form = "(NEONScalarPairwise)"; - } - Format(instr, mnemonic, nfd.Substitute(form, - NEONFormatDecoder::kPlaceholder, NEONFormatDecoder::kFormat)); -} - - -void Disassembler::VisitNEONScalarShiftImmediate(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "%sd, %sn, 'Is1"; - const char *form_2 = "%sd, %sn, 'Is2"; - - static const NEONFormatMap map_shift = { - {22, 21, 20, 19}, - {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S, - NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D} - }; - static const NEONFormatMap map_shift_narrow = { - {21, 20, 19}, - {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D} - }; - NEONFormatDecoder nfd(instr, &map_shift); - - if (instr->ImmNEONImmh()) { // immh has to be non-zero. - switch (instr->Mask(NEONScalarShiftImmediateMask)) { - case NEON_FCVTZU_imm_scalar: mnemonic = "fcvtzu"; break; - case NEON_FCVTZS_imm_scalar: mnemonic = "fcvtzs"; break; - case NEON_SCVTF_imm_scalar: mnemonic = "scvtf"; break; - case NEON_UCVTF_imm_scalar: mnemonic = "ucvtf"; break; - case NEON_SRI_scalar: mnemonic = "sri"; break; - case NEON_SSHR_scalar: mnemonic = "sshr"; break; - case NEON_USHR_scalar: mnemonic = "ushr"; break; - case NEON_SRSHR_scalar: mnemonic = "srshr"; break; - case NEON_URSHR_scalar: mnemonic = "urshr"; break; - case NEON_SSRA_scalar: mnemonic = "ssra"; break; - case NEON_USRA_scalar: mnemonic = "usra"; break; - case NEON_SRSRA_scalar: mnemonic = "srsra"; break; - case NEON_URSRA_scalar: mnemonic = "ursra"; break; - case NEON_SHL_scalar: mnemonic = "shl"; form = form_2; break; - case NEON_SLI_scalar: mnemonic = "sli"; form = form_2; break; - case NEON_SQSHLU_scalar: mnemonic = "sqshlu"; form = form_2; break; - case NEON_SQSHL_imm_scalar: mnemonic = "sqshl"; form = form_2; break; - case NEON_UQSHL_imm_scalar: mnemonic = "uqshl"; form = form_2; break; - case NEON_UQSHRN_scalar: - mnemonic = "uqshrn"; - nfd.SetFormatMap(1, &map_shift_narrow); - break; - case NEON_UQRSHRN_scalar: - mnemonic = "uqrshrn"; - nfd.SetFormatMap(1, &map_shift_narrow); - break; - case NEON_SQSHRN_scalar: - mnemonic = "sqshrn"; - nfd.SetFormatMap(1, &map_shift_narrow); - break; - case NEON_SQRSHRN_scalar: - mnemonic = "sqrshrn"; - nfd.SetFormatMap(1, &map_shift_narrow); - break; - case NEON_SQSHRUN_scalar: - mnemonic = "sqshrun"; - nfd.SetFormatMap(1, &map_shift_narrow); - break; - case NEON_SQRSHRUN_scalar: - mnemonic = "sqrshrun"; - nfd.SetFormatMap(1, &map_shift_narrow); - break; - default: - form = "(NEONScalarShiftImmediate)"; - } - } else { - form = "(NEONScalarShiftImmediate)"; - } - Format(instr, mnemonic, nfd.SubstitutePlaceholders(form)); -} - - -void Disassembler::VisitNEONShiftImmediate(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Vd.%s, 'Vn.%s, 'Is1"; - const char *form_shift_2 = "'Vd.%s, 'Vn.%s, 'Is2"; - const char *form_xtl = "'Vd.%s, 'Vn.%s"; - - // 0001->8H, 001x->4S, 01xx->2D, all others undefined. - static const NEONFormatMap map_shift_ta = { - {22, 21, 20, 19}, - {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D} - }; - - // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H, - // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined. - static const NEONFormatMap map_shift_tb = { - {22, 21, 20, 19, 30}, - {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H, - NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, - NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, - NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D} - }; - - NEONFormatDecoder nfd(instr, &map_shift_tb); - - if (instr->ImmNEONImmh()) { // immh has to be non-zero. - switch (instr->Mask(NEONShiftImmediateMask)) { - case NEON_SQSHLU: mnemonic = "sqshlu"; form = form_shift_2; break; - case NEON_SQSHL_imm: mnemonic = "sqshl"; form = form_shift_2; break; - case NEON_UQSHL_imm: mnemonic = "uqshl"; form = form_shift_2; break; - case NEON_SHL: mnemonic = "shl"; form = form_shift_2; break; - case NEON_SLI: mnemonic = "sli"; form = form_shift_2; break; - case NEON_SCVTF_imm: mnemonic = "scvtf"; break; - case NEON_UCVTF_imm: mnemonic = "ucvtf"; break; - case NEON_FCVTZU_imm: mnemonic = "fcvtzu"; break; - case NEON_FCVTZS_imm: mnemonic = "fcvtzs"; break; - case NEON_SRI: mnemonic = "sri"; break; - case NEON_SSHR: mnemonic = "sshr"; break; - case NEON_USHR: mnemonic = "ushr"; break; - case NEON_SRSHR: mnemonic = "srshr"; break; - case NEON_URSHR: mnemonic = "urshr"; break; - case NEON_SSRA: mnemonic = "ssra"; break; - case NEON_USRA: mnemonic = "usra"; break; - case NEON_SRSRA: mnemonic = "srsra"; break; - case NEON_URSRA: mnemonic = "ursra"; break; - case NEON_SHRN: - mnemonic = instr->Mask(NEON_Q) ? "shrn2" : "shrn"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_RSHRN: - mnemonic = instr->Mask(NEON_Q) ? "rshrn2" : "rshrn"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_UQSHRN: - mnemonic = instr->Mask(NEON_Q) ? "uqshrn2" : "uqshrn"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_UQRSHRN: - mnemonic = instr->Mask(NEON_Q) ? "uqrshrn2" : "uqrshrn"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_SQSHRN: - mnemonic = instr->Mask(NEON_Q) ? "sqshrn2" : "sqshrn"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_SQRSHRN: - mnemonic = instr->Mask(NEON_Q) ? "sqrshrn2" : "sqrshrn"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_SQSHRUN: - mnemonic = instr->Mask(NEON_Q) ? "sqshrun2" : "sqshrun"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_SQRSHRUN: - mnemonic = instr->Mask(NEON_Q) ? "sqrshrun2" : "sqrshrun"; - nfd.SetFormatMap(1, &map_shift_ta); - break; - case NEON_SSHLL: - nfd.SetFormatMap(0, &map_shift_ta); - if (instr->ImmNEONImmb() == 0 && - CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // sxtl variant. - form = form_xtl; - mnemonic = instr->Mask(NEON_Q) ? "sxtl2" : "sxtl"; - } else { // sshll variant. - form = form_shift_2; - mnemonic = instr->Mask(NEON_Q) ? "sshll2" : "sshll"; - } - break; - case NEON_USHLL: - nfd.SetFormatMap(0, &map_shift_ta); - if (instr->ImmNEONImmb() == 0 && - CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // uxtl variant. - form = form_xtl; - mnemonic = instr->Mask(NEON_Q) ? "uxtl2" : "uxtl"; - } else { // ushll variant. - form = form_shift_2; - mnemonic = instr->Mask(NEON_Q) ? "ushll2" : "ushll"; - } - break; - default: form = "(NEONShiftImmediate)"; - } - } else { - form = "(NEONShiftImmediate)"; - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitNEONTable(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "(NEONTable)"; - const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s"; - const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s"; - const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s"; - const char form_4v[] = - "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s"; - static const NEONFormatMap map_b = { {30}, {NF_8B, NF_16B} }; - NEONFormatDecoder nfd(instr, &map_b); - - switch (instr->Mask(NEONTableMask)) { - case NEON_TBL_1v: mnemonic = "tbl"; form = form_1v; break; - case NEON_TBL_2v: mnemonic = "tbl"; form = form_2v; break; - case NEON_TBL_3v: mnemonic = "tbl"; form = form_3v; break; - case NEON_TBL_4v: mnemonic = "tbl"; form = form_4v; break; - case NEON_TBX_1v: mnemonic = "tbx"; form = form_1v; break; - case NEON_TBX_2v: mnemonic = "tbx"; form = form_2v; break; - case NEON_TBX_3v: mnemonic = "tbx"; form = form_3v; break; - case NEON_TBX_4v: mnemonic = "tbx"; form = form_4v; break; - default: break; - } - - char re_form[sizeof(form_4v) + 6]; - int reg_num = instr->Rn(); - snprintf(re_form, sizeof(re_form), form, - (reg_num + 1) % kNumberOfVRegisters, - (reg_num + 2) % kNumberOfVRegisters, - (reg_num + 3) % kNumberOfVRegisters); - - Format(instr, mnemonic, nfd.Substitute(re_form)); -} - - -void Disassembler::VisitNEONPerm(const Instruction* instr) { - const char *mnemonic = "unimplemented"; - const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s"; - NEONFormatDecoder nfd(instr); - - switch (instr->Mask(NEONPermMask)) { - case NEON_TRN1: mnemonic = "trn1"; break; - case NEON_TRN2: mnemonic = "trn2"; break; - case NEON_UZP1: mnemonic = "uzp1"; break; - case NEON_UZP2: mnemonic = "uzp2"; break; - case NEON_ZIP1: mnemonic = "zip1"; break; - case NEON_ZIP2: mnemonic = "zip2"; break; - default: form = "(NEONPerm)"; - } - Format(instr, mnemonic, nfd.Substitute(form)); -} - - -void Disassembler::VisitUnimplemented(const Instruction* instr) { - Format(instr, "unimplemented", "(Unimplemented)"); -} - - -void Disassembler::VisitUnallocated(const Instruction* instr) { - Format(instr, "unallocated", "(Unallocated)"); -} - - -void Disassembler::ProcessOutput(const Instruction* /*instr*/) { - // The base disasm does nothing more than disassembling into a buffer. -} - - -void Disassembler::AppendRegisterNameToOutput(const Instruction* instr, - const CPURegister& reg) { - USE(instr); - VIXL_ASSERT(reg.IsValid()); - char reg_char; - - if (reg.IsRegister()) { - reg_char = reg.Is64Bits() ? 'x' : 'w'; - } else { - VIXL_ASSERT(reg.IsVRegister()); - switch (reg.SizeInBits()) { - case kBRegSize: reg_char = 'b'; break; - case kHRegSize: reg_char = 'h'; break; - case kSRegSize: reg_char = 's'; break; - case kDRegSize: reg_char = 'd'; break; - default: - VIXL_ASSERT(reg.Is128Bits()); - reg_char = 'q'; - } - } - - if (reg.IsVRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) { - // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31. - AppendToOutput("%c%d", reg_char, reg.code()); - } else if (reg.Aliases(sp)) { - // Disassemble w31/x31 as stack pointer wsp/sp. - AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp"); - } else { - // Disassemble w31/x31 as zero register wzr/xzr. - AppendToOutput("%czr", reg_char); - } -} - - -void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr, - int64_t offset) { - USE(instr); - uint64_t abs_offset = offset; - char sign = (offset < 0) ? '-' : '+'; - if (offset < 0) { - abs_offset = -abs_offset; - } - AppendToOutput("#%c0x%" PRIx64, sign, abs_offset); -} - - -void Disassembler::AppendAddressToOutput(const Instruction* instr, - const void* addr) { - USE(instr); - AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast(addr)); -} - - -void Disassembler::AppendCodeAddressToOutput(const Instruction* instr, - const void* addr) { - AppendAddressToOutput(instr, addr); -} - - -void Disassembler::AppendDataAddressToOutput(const Instruction* instr, - const void* addr) { - AppendAddressToOutput(instr, addr); -} - - -void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr, - const void* addr) { - USE(instr); - int64_t rel_addr = CodeRelativeAddress(addr); - if (rel_addr >= 0) { - AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr); - } else { - AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr); - } -} - - -void Disassembler::AppendCodeRelativeCodeAddressToOutput( - const Instruction* instr, const void* addr) { - AppendCodeRelativeAddressToOutput(instr, addr); -} - - -void Disassembler::AppendCodeRelativeDataAddressToOutput( - const Instruction* instr, const void* addr) { - AppendCodeRelativeAddressToOutput(instr, addr); -} - - -void Disassembler::MapCodeAddress(int64_t base_address, - const Instruction* instr_address) { - set_code_address_offset( - base_address - reinterpret_cast(instr_address)); -} -int64_t Disassembler::CodeRelativeAddress(const void* addr) { - return reinterpret_cast(addr) + code_address_offset(); -} - - -void Disassembler::Format(const Instruction* instr, const char* mnemonic, - const char* format) { - VIXL_ASSERT(mnemonic != NULL); - ResetOutput(); - Substitute(instr, mnemonic); - if (format != NULL) { - VIXL_ASSERT(buffer_pos_ < buffer_size_); - buffer_[buffer_pos_++] = ' '; - Substitute(instr, format); - } - VIXL_ASSERT(buffer_pos_ < buffer_size_); - buffer_[buffer_pos_] = 0; - ProcessOutput(instr); -} - - -void Disassembler::Substitute(const Instruction* instr, const char* string) { - char chr = *string++; - while (chr != '\0') { - if (chr == '\'') { - string += SubstituteField(instr, string); - } else { - VIXL_ASSERT(buffer_pos_ < buffer_size_); - buffer_[buffer_pos_++] = chr; - } - chr = *string++; - } -} - - -int Disassembler::SubstituteField(const Instruction* instr, - const char* format) { - switch (format[0]) { - // NB. The remaining substitution prefix characters are: GJKUZ. - case 'R': // Register. X or W, selected by sf bit. - case 'F': // FP register. S or D, selected by type field. - case 'V': // Vector register, V, vector format. - case 'W': - case 'X': - case 'B': - case 'H': - case 'S': - case 'D': - case 'Q': return SubstituteRegisterField(instr, format); - case 'I': return SubstituteImmediateField(instr, format); - case 'L': return SubstituteLiteralField(instr, format); - case 'N': return SubstituteShiftField(instr, format); - case 'P': return SubstitutePrefetchField(instr, format); - case 'C': return SubstituteConditionField(instr, format); - case 'E': return SubstituteExtendField(instr, format); - case 'A': return SubstitutePCRelAddressField(instr, format); - case 'T': return SubstituteBranchTargetField(instr, format); - case 'O': return SubstituteLSRegOffsetField(instr, format); - case 'M': return SubstituteBarrierField(instr, format); - case 'K': return SubstituteCrField(instr, format); - case 'G': return SubstituteSysOpField(instr, format); - default: { - VIXL_UNREACHABLE(); - return 1; - } - } -} - - -int Disassembler::SubstituteRegisterField(const Instruction* instr, - const char* format) { - char reg_prefix = format[0]; - unsigned reg_num = 0; - unsigned field_len = 2; - - switch (format[1]) { - case 'd': - reg_num = instr->Rd(); - if (format[2] == 'q') { - reg_prefix = instr->NEONQ() ? 'X' : 'W'; - field_len = 3; - } - break; - case 'n': reg_num = instr->Rn(); break; - case 'm': - reg_num = instr->Rm(); - switch (format[2]) { - // Handle registers tagged with b (bytes), z (instruction), or - // r (registers), used for address updates in - // NEON load/store instructions. - case 'r': - case 'b': - case 'z': { - field_len = 3; - char* eimm; - int imm = static_cast(strtol(&format[3], &eimm, 10)); - field_len += eimm - &format[3]; - if (reg_num == 31) { - switch (format[2]) { - case 'z': - imm *= (1 << instr->NEONLSSize()); - break; - case 'r': - imm *= (instr->NEONQ() == 0) ? kDRegSizeInBytes - : kQRegSizeInBytes; - break; - case 'b': - break; - } - AppendToOutput("#%d", imm); - return field_len; - } - break; - } - } - break; - case 'e': - // This is register Rm, but using a 4-bit specifier. Used in NEON - // by-element instructions. - reg_num = (instr->Rm() & 0xf); - break; - case 'a': reg_num = instr->Ra(); break; - case 's': reg_num = instr->Rs(); break; - case 't': - reg_num = instr->Rt(); - if (format[0] == 'V') { - if ((format[2] >= '2') && (format[2] <= '4')) { - // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4. - reg_num = (reg_num + format[2] - '1') % 32; - field_len = 3; - } - } else { - if (format[2] == '2') { - // Handle register specifier Rt2. - reg_num = instr->Rt2(); - field_len = 3; - } - } - break; - default: VIXL_UNREACHABLE(); - } - - // Increase field length for registers tagged as stack. - if (format[2] == 's') { - field_len = 3; - } - - CPURegister::RegisterType reg_type = CPURegister::kRegister; - unsigned reg_size = kXRegSize; - - if (reg_prefix == 'R') { - reg_prefix = instr->SixtyFourBits() ? 'X' : 'W'; - } else if (reg_prefix == 'F') { - reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D'; - } - - switch (reg_prefix) { - case 'W': - reg_type = CPURegister::kRegister; reg_size = kWRegSize; break; - case 'X': - reg_type = CPURegister::kRegister; reg_size = kXRegSize; break; - case 'B': - reg_type = CPURegister::kVRegister; reg_size = kBRegSize; break; - case 'H': - reg_type = CPURegister::kVRegister; reg_size = kHRegSize; break; - case 'S': - reg_type = CPURegister::kVRegister; reg_size = kSRegSize; break; - case 'D': - reg_type = CPURegister::kVRegister; reg_size = kDRegSize; break; - case 'Q': - reg_type = CPURegister::kVRegister; reg_size = kQRegSize; break; - case 'V': - AppendToOutput("v%d", reg_num); - return field_len; - default: - VIXL_UNREACHABLE(); - } - - if ((reg_type == CPURegister::kRegister) && - (reg_num == kZeroRegCode) && (format[2] == 's')) { - reg_num = kSPRegInternalCode; - } - - AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type)); - - return field_len; -} - - -int Disassembler::SubstituteImmediateField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'I'); - - switch (format[1]) { - case 'M': { // IMoveImm, IMoveNeg or IMoveLSL. - if (format[5] == 'L') { - AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide()); - if (instr->ShiftMoveWide() > 0) { - AppendToOutput(", lsl #%" PRId32, 16 * instr->ShiftMoveWide()); - } - } else { - VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N')); - uint64_t imm = static_cast(instr->ImmMoveWide()) << - (16 * instr->ShiftMoveWide()); - if (format[5] == 'N') - imm = ~imm; - if (!instr->SixtyFourBits()) - imm &= UINT64_C(0xffffffff); - AppendToOutput("#0x%" PRIx64, imm); - } - return 8; - } - case 'L': { - switch (format[2]) { - case 'L': { // ILLiteral - Immediate Load Literal. - AppendToOutput("pc%+" PRId32, - instr->ImmLLiteral() << kLiteralEntrySizeLog2); - return 9; - } - case 'S': { // ILS - Immediate Load/Store. - if (instr->ImmLS() != 0) { - AppendToOutput(", #%" PRId32, instr->ImmLS()); - } - return 3; - } - case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. - if (instr->ImmLSPair() != 0) { - // format[3] is the scale value. Convert to a number. - int scale = 1 << (format[3] - '0'); - AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale); - } - return 4; - } - case 'U': { // ILU - Immediate Load/Store Unsigned. - if (instr->ImmLSUnsigned() != 0) { - int shift = instr->SizeLS(); - AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift); - } - return 3; - } - default: { - VIXL_UNIMPLEMENTED(); - return 0; - } - } - } - case 'C': { // ICondB - Immediate Conditional Branch. - int64_t offset = instr->ImmCondBranch() << 2; - AppendPCRelativeOffsetToOutput(instr, offset); - return 6; - } - case 'A': { // IAddSub. - VIXL_ASSERT(instr->ShiftAddSub() <= 1); - int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub()); - AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm); - return 7; - } - case 'F': { // IFPSingle, IFPDouble or IFPFBits. - if (format[3] == 'F') { // IFPFbits. - AppendToOutput("#%" PRId32, 64 - instr->FPScale()); - return 8; - } else { - AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(), - format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64()); - return 9; - } - } - case 'T': { // ITri - Immediate Triangular Encoded. - AppendToOutput("#0x%" PRIx64, instr->ImmLogical()); - return 4; - } - case 'N': { // INzcv. - int nzcv = (instr->Nzcv() << Flags_offset); - AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N', - ((nzcv & ZFlag) == 0) ? 'z' : 'Z', - ((nzcv & CFlag) == 0) ? 'c' : 'C', - ((nzcv & VFlag) == 0) ? 'v' : 'V'); - return 5; - } - case 'P': { // IP - Conditional compare. - AppendToOutput("#%" PRId32, instr->ImmCondCmp()); - return 2; - } - case 'B': { // Bitfields. - return SubstituteBitfieldImmediateField(instr, format); - } - case 'E': { // IExtract. - AppendToOutput("#%" PRId32, instr->ImmS()); - return 8; - } - case 'S': { // IS - Test and branch bit. - AppendToOutput("#%" PRId32, (instr->ImmTestBranchBit5() << 5) | - instr->ImmTestBranchBit40()); - return 2; - } - case 's': { // Is - Shift (immediate). - switch (format[2]) { - case '1': { // Is1 - SSHR. - int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh()); - shift -= instr->ImmNEONImmhImmb(); - AppendToOutput("#%d", shift); - return 3; - } - case '2': { // Is2 - SLI. - int shift = instr->ImmNEONImmhImmb(); - shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh()); - AppendToOutput("#%d", shift); - return 3; - } - default: { - VIXL_UNIMPLEMENTED(); - return 0; - } - } - } - case 'D': { // IDebug - HLT and BRK instructions. - AppendToOutput("#0x%" PRIx32, instr->ImmException()); - return 6; - } - case 'V': { // Immediate Vector. - switch (format[2]) { - case 'E': { // IVExtract. - AppendToOutput("#%" PRId32, instr->ImmNEONExt()); - return 9; - } - case 'B': { // IVByElemIndex. - int vm_index = (instr->NEONH() << 1) | instr->NEONL(); - if (instr->NEONSize() == 1) { - vm_index = (vm_index << 1) | instr->NEONM(); - } - AppendToOutput("%d", vm_index); - return strlen("IVByElemIndex"); - } - case 'I': { // INS element. - if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) { - int rd_index, rn_index; - int imm5 = instr->ImmNEON5(); - int imm4 = instr->ImmNEON4(); - int tz = CountTrailingZeros(imm5, 32); - rd_index = imm5 >> (tz + 1); - rn_index = imm4 >> tz; - if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) { - AppendToOutput("%d", rd_index); - return strlen("IVInsIndex1"); - } else if (strncmp(format, "IVInsIndex2", - strlen("IVInsIndex2")) == 0) { - AppendToOutput("%d", rn_index); - return strlen("IVInsIndex2"); - } else { - VIXL_UNIMPLEMENTED(); - return 0; - } - } - VIXL_FALLTHROUGH(); - } - case 'L': { // IVLSLane[0123] - suffix indicates access size shift. - AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0')); - return 9; - } - case 'M': { // Modified Immediate cases. - if (strncmp(format, - "IVMIImmFPSingle", - strlen("IVMIImmFPSingle")) == 0) { - AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), - instr->ImmNEONFP32()); - return strlen("IVMIImmFPSingle"); - } else if (strncmp(format, - "IVMIImmFPDouble", - strlen("IVMIImmFPDouble")) == 0) { - AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(), - instr->ImmNEONFP64()); - return strlen("IVMIImmFPDouble"); - } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) { - uint64_t imm8 = instr->ImmNEONabcdefgh(); - AppendToOutput("#0x%" PRIx64, imm8); - return strlen("IVMIImm8"); - } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) { - uint64_t imm8 = instr->ImmNEONabcdefgh(); - uint64_t imm = 0; - for (int i = 0; i < 8; ++i) { - if (imm8 & (1 << i)) { - imm |= (UINT64_C(0xff) << (8 * i)); - } - } - AppendToOutput("#0x%" PRIx64, imm); - return strlen("IVMIImm"); - } else if (strncmp(format, "IVMIShiftAmt1", - strlen("IVMIShiftAmt1")) == 0) { - int cmode = instr->NEONCmode(); - int shift_amount = 8 * ((cmode >> 1) & 3); - AppendToOutput("#%d", shift_amount); - return strlen("IVMIShiftAmt1"); - } else if (strncmp(format, "IVMIShiftAmt2", - strlen("IVMIShiftAmt2")) == 0) { - int cmode = instr->NEONCmode(); - int shift_amount = 8 << (cmode & 1); - AppendToOutput("#%d", shift_amount); - return strlen("IVMIShiftAmt2"); - } else { - VIXL_UNIMPLEMENTED(); - return 0; - } - } - default: { - VIXL_UNIMPLEMENTED(); - return 0; - } - } - } - case 'X': { // IX - CLREX instruction. - AppendToOutput("#0x%" PRIx32, instr->CRm()); - return 2; - } - default: { - VIXL_UNIMPLEMENTED(); - return 0; - } - } -} - - -int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr, - const char* format) { - VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B')); - unsigned r = instr->ImmR(); - unsigned s = instr->ImmS(); - - switch (format[2]) { - case 'r': { // IBr. - AppendToOutput("#%d", r); - return 3; - } - case 's': { // IBs+1 or IBs-r+1. - if (format[3] == '+') { - AppendToOutput("#%d", s + 1); - return 5; - } else { - VIXL_ASSERT(format[3] == '-'); - AppendToOutput("#%d", s - r + 1); - return 7; - } - } - case 'Z': { // IBZ-r. - VIXL_ASSERT((format[3] == '-') && (format[4] == 'r')); - unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize; - AppendToOutput("#%d", reg_size - r); - return 5; - } - default: { - VIXL_UNREACHABLE(); - return 0; - } - } -} - - -int Disassembler::SubstituteLiteralField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(strncmp(format, "LValue", 6) == 0); - USE(format); - - const void * address = instr->LiteralAddress(); - switch (instr->Mask(LoadLiteralMask)) { - case LDR_w_lit: - case LDR_x_lit: - case LDRSW_x_lit: - case LDR_s_lit: - case LDR_d_lit: - case LDR_q_lit: - AppendCodeRelativeDataAddressToOutput(instr, address); - break; - case PRFM_lit: { - // Use the prefetch hint to decide how to print the address. - switch (instr->PrefetchHint()) { - case 0x0: // PLD: prefetch for load. - case 0x2: // PST: prepare for store. - AppendCodeRelativeDataAddressToOutput(instr, address); - break; - case 0x1: // PLI: preload instructions. - AppendCodeRelativeCodeAddressToOutput(instr, address); - break; - case 0x3: // Unallocated hint. - AppendCodeRelativeAddressToOutput(instr, address); - break; - } - break; - } - default: - VIXL_UNREACHABLE(); - } - - return 6; -} - - -int Disassembler::SubstituteShiftField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'N'); - VIXL_ASSERT(instr->ShiftDP() <= 0x3); - - switch (format[1]) { - case 'D': { // HDP. - VIXL_ASSERT(instr->ShiftDP() != ROR); - VIXL_FALLTHROUGH(); - } - case 'L': { // HLo. - if (instr->ImmDPShift() != 0) { - const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; - AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()], - instr->ImmDPShift()); - } - return 3; - } - default: - VIXL_UNIMPLEMENTED(); - return 0; - } -} - - -int Disassembler::SubstituteConditionField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'C'); - const char* condition_code[] = { "eq", "ne", "hs", "lo", - "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", - "gt", "le", "al", "nv" }; - int cond; - switch (format[1]) { - case 'B': cond = instr->ConditionBranch(); break; - case 'I': { - cond = InvertCondition(static_cast(instr->Condition())); - break; - } - default: cond = instr->Condition(); - } - AppendToOutput("%s", condition_code[cond]); - return 4; -} - - -int Disassembler::SubstitutePCRelAddressField(const Instruction* instr, - const char* format) { - VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`. - (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`. - - int64_t offset = instr->ImmPCRel(); - - // Compute the target address based on the effective address (after applying - // code_address_offset). This is required for correct behaviour of adrp. - const Instruction* base = instr + code_address_offset(); - if (format[9] == 'P') { - offset *= kPageSize; - base = AlignDown(base, kPageSize); - } - // Strip code_address_offset before printing, so we can use the - // semantically-correct AppendCodeRelativeAddressToOutput. - const void* target = - reinterpret_cast(base + offset - code_address_offset()); - - AppendPCRelativeOffsetToOutput(instr, offset); - AppendToOutput(" "); - AppendCodeRelativeAddressToOutput(instr, target); - return 13; -} - - -int Disassembler::SubstituteBranchTargetField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(strncmp(format, "TImm", 4) == 0); - - int64_t offset = 0; - switch (format[5]) { - // BImmUncn - unconditional branch immediate. - case 'n': offset = instr->ImmUncondBranch(); break; - // BImmCond - conditional branch immediate. - case 'o': offset = instr->ImmCondBranch(); break; - // BImmCmpa - compare and branch immediate. - case 'm': offset = instr->ImmCmpBranch(); break; - // BImmTest - test and branch immediate. - case 'e': offset = instr->ImmTestBranch(); break; - default: VIXL_UNIMPLEMENTED(); - } - offset <<= kInstructionSizeLog2; - const void* target_address = reinterpret_cast(instr + offset); - VIXL_STATIC_ASSERT(sizeof(*instr) == 1); - - AppendPCRelativeOffsetToOutput(instr, offset); - AppendToOutput(" "); - AppendCodeRelativeCodeAddressToOutput(instr, target_address); - - return 8; -} - - -int Disassembler::SubstituteExtendField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(strncmp(format, "Ext", 3) == 0); - VIXL_ASSERT(instr->ExtendMode() <= 7); - USE(format); - - const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx", - "sxtb", "sxth", "sxtw", "sxtx" }; - - // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit - // registers becomes lsl. - if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) && - (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) || - (instr->ExtendMode() == UXTX))) { - if (instr->ImmExtendShift() > 0) { - AppendToOutput(", lsl #%" PRId32, instr->ImmExtendShift()); - } - } else { - AppendToOutput(", %s", extend_mode[instr->ExtendMode()]); - if (instr->ImmExtendShift() > 0) { - AppendToOutput(" #%" PRId32, instr->ImmExtendShift()); - } - } - return 3; -} - - -int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0); - const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl", - "undefined", "undefined", "sxtw", "sxtx" }; - USE(format); - - unsigned shift = instr->ImmShiftLS(); - Extend ext = static_cast(instr->ExtendMode()); - char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x'; - - unsigned rm = instr->Rm(); - if (rm == kZeroRegCode) { - AppendToOutput("%czr", reg_type); - } else { - AppendToOutput("%c%d", reg_type, rm); - } - - // Extend mode UXTX is an alias for shift mode LSL here. - if (!((ext == UXTX) && (shift == 0))) { - AppendToOutput(", %s", extend_mode[ext]); - if (shift != 0) { - AppendToOutput(" #%d", instr->SizeLS()); - } - } - return 9; -} - - -int Disassembler::SubstitutePrefetchField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'P'); - USE(format); - - static const char* hints[] = {"ld", "li", "st"}; - static const char* stream_options[] = {"keep", "strm"}; - - unsigned hint = instr->PrefetchHint(); - unsigned target = instr->PrefetchTarget() + 1; - unsigned stream = instr->PrefetchStream(); - - if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) { - // Unallocated prefetch operations. - int prefetch_mode = instr->ImmPrefetchOperation(); - AppendToOutput("#0b%c%c%c%c%c", - (prefetch_mode & (1 << 4)) ? '1' : '0', - (prefetch_mode & (1 << 3)) ? '1' : '0', - (prefetch_mode & (1 << 2)) ? '1' : '0', - (prefetch_mode & (1 << 1)) ? '1' : '0', - (prefetch_mode & (1 << 0)) ? '1' : '0'); - } else { - VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0]))); - AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]); - } - return 6; -} - -int Disassembler::SubstituteBarrierField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'M'); - USE(format); - - static const char* options[4][4] = { - { "sy (0b0000)", "oshld", "oshst", "osh" }, - { "sy (0b0100)", "nshld", "nshst", "nsh" }, - { "sy (0b1000)", "ishld", "ishst", "ish" }, - { "sy (0b1100)", "ld", "st", "sy" } - }; - int domain = instr->ImmBarrierDomain(); - int type = instr->ImmBarrierType(); - - AppendToOutput("%s", options[domain][type]); - return 1; -} - -int Disassembler::SubstituteSysOpField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'G'); - int op = -1; - switch (format[1]) { - case '1': op = instr->SysOp1(); break; - case '2': op = instr->SysOp2(); break; - default: - VIXL_UNREACHABLE(); - } - AppendToOutput("#%d", op); - return 2; -} - -int Disassembler::SubstituteCrField(const Instruction* instr, - const char* format) { - VIXL_ASSERT(format[0] == 'K'); - int cr = -1; - switch (format[1]) { - case 'n': cr = instr->CRn(); break; - case 'm': cr = instr->CRm(); break; - default: - VIXL_UNREACHABLE(); - } - AppendToOutput("C%d", cr); - return 2; -} - -void Disassembler::ResetOutput() { - buffer_pos_ = 0; - buffer_[buffer_pos_] = 0; -} - - -void Disassembler::AppendToOutput(const char* format, ...) { - va_list args; - va_start(args, format); - buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_ - buffer_pos_, - format, args); - va_end(args); -} - - -void PrintDisassembler::ProcessOutput(const Instruction* instr) { - fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n", - reinterpret_cast(instr), - instr->InstructionBits(), - GetOutput()); -} - -} // namespace vixl diff --git a/disas/libvixl/vixl/a64/disasm-a64.h b/disas/libvixl/vixl/a64/disasm-a64.h deleted file mode 100644 index 930df6ea6a58..000000000000 --- a/disas/libvixl/vixl/a64/disasm-a64.h +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_A64_DISASM_A64_H -#define VIXL_A64_DISASM_A64_H - -#include "vixl/globals.h" -#include "vixl/utils.h" -#include "vixl/a64/instructions-a64.h" -#include "vixl/a64/decoder-a64.h" -#include "vixl/a64/assembler-a64.h" - -namespace vixl { - -class Disassembler: public DecoderVisitor { - public: - Disassembler(); - Disassembler(char* text_buffer, int buffer_size); - virtual ~Disassembler(); - char* GetOutput(); - - // Declare all Visitor functions. - #define DECLARE(A) virtual void Visit##A(const Instruction* instr); - VISITOR_LIST(DECLARE) - #undef DECLARE - - protected: - virtual void ProcessOutput(const Instruction* instr); - - // Default output functions. The functions below implement a default way of - // printing elements in the disassembly. A sub-class can override these to - // customize the disassembly output. - - // Prints the name of a register. - // TODO: This currently doesn't allow renaming of V registers. - virtual void AppendRegisterNameToOutput(const Instruction* instr, - const CPURegister& reg); - - // Prints a PC-relative offset. This is used for example when disassembling - // branches to immediate offsets. - virtual void AppendPCRelativeOffsetToOutput(const Instruction* instr, - int64_t offset); - - // Prints an address, in the general case. It can be code or data. This is - // used for example to print the target address of an ADR instruction. - virtual void AppendCodeRelativeAddressToOutput(const Instruction* instr, - const void* addr); - - // Prints the address of some code. - // This is used for example to print the target address of a branch to an - // immediate offset. - // A sub-class can for example override this method to lookup the address and - // print an appropriate name. - virtual void AppendCodeRelativeCodeAddressToOutput(const Instruction* instr, - const void* addr); - - // Prints the address of some data. - // This is used for example to print the source address of a load literal - // instruction. - virtual void AppendCodeRelativeDataAddressToOutput(const Instruction* instr, - const void* addr); - - // Same as the above, but for addresses that are not relative to the code - // buffer. They are currently not used by VIXL. - virtual void AppendAddressToOutput(const Instruction* instr, - const void* addr); - virtual void AppendCodeAddressToOutput(const Instruction* instr, - const void* addr); - virtual void AppendDataAddressToOutput(const Instruction* instr, - const void* addr); - - public: - // Get/Set the offset that should be added to code addresses when printing - // code-relative addresses in the AppendCodeRelativeAddressToOutput() - // helpers. - // Below is an example of how a branch immediate instruction in memory at - // address 0xb010200 would disassemble with different offsets. - // Base address | Disassembly - // 0x0 | 0xb010200: b #+0xcc (addr 0xb0102cc) - // 0x10000 | 0xb000200: b #+0xcc (addr 0xb0002cc) - // 0xb010200 | 0x0: b #+0xcc (addr 0xcc) - void MapCodeAddress(int64_t base_address, const Instruction* instr_address); - int64_t CodeRelativeAddress(const void* instr); - - private: - void Format( - const Instruction* instr, const char* mnemonic, const char* format); - void Substitute(const Instruction* instr, const char* string); - int SubstituteField(const Instruction* instr, const char* format); - int SubstituteRegisterField(const Instruction* instr, const char* format); - int SubstituteImmediateField(const Instruction* instr, const char* format); - int SubstituteLiteralField(const Instruction* instr, const char* format); - int SubstituteBitfieldImmediateField( - const Instruction* instr, const char* format); - int SubstituteShiftField(const Instruction* instr, const char* format); - int SubstituteExtendField(const Instruction* instr, const char* format); - int SubstituteConditionField(const Instruction* instr, const char* format); - int SubstitutePCRelAddressField(const Instruction* instr, const char* format); - int SubstituteBranchTargetField(const Instruction* instr, const char* format); - int SubstituteLSRegOffsetField(const Instruction* instr, const char* format); - int SubstitutePrefetchField(const Instruction* instr, const char* format); - int SubstituteBarrierField(const Instruction* instr, const char* format); - int SubstituteSysOpField(const Instruction* instr, const char* format); - int SubstituteCrField(const Instruction* instr, const char* format); - bool RdIsZROrSP(const Instruction* instr) const { - return (instr->Rd() == kZeroRegCode); - } - - bool RnIsZROrSP(const Instruction* instr) const { - return (instr->Rn() == kZeroRegCode); - } - - bool RmIsZROrSP(const Instruction* instr) const { - return (instr->Rm() == kZeroRegCode); - } - - bool RaIsZROrSP(const Instruction* instr) const { - return (instr->Ra() == kZeroRegCode); - } - - bool IsMovzMovnImm(unsigned reg_size, uint64_t value); - - int64_t code_address_offset() const { return code_address_offset_; } - - protected: - void ResetOutput(); - void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3); - - void set_code_address_offset(int64_t code_address_offset) { - code_address_offset_ = code_address_offset; - } - - char* buffer_; - uint32_t buffer_pos_; - uint32_t buffer_size_; - bool own_buffer_; - - int64_t code_address_offset_; -}; - - -class PrintDisassembler: public Disassembler { - public: - explicit PrintDisassembler(FILE* stream) : stream_(stream) { } - - protected: - virtual void ProcessOutput(const Instruction* instr); - - private: - FILE *stream_; -}; -} // namespace vixl - -#endif // VIXL_A64_DISASM_A64_H diff --git a/disas/libvixl/vixl/a64/instructions-a64.cc b/disas/libvixl/vixl/a64/instructions-a64.cc deleted file mode 100644 index 33992f88a411..000000000000 --- a/disas/libvixl/vixl/a64/instructions-a64.cc +++ /dev/null @@ -1,622 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "vixl/a64/instructions-a64.h" -#include "vixl/a64/assembler-a64.h" - -namespace vixl { - - -// Floating-point infinity values. -const float16 kFP16PositiveInfinity = 0x7c00; -const float16 kFP16NegativeInfinity = 0xfc00; -const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000); -const float kFP32NegativeInfinity = rawbits_to_float(0xff800000); -const double kFP64PositiveInfinity = - rawbits_to_double(UINT64_C(0x7ff0000000000000)); -const double kFP64NegativeInfinity = - rawbits_to_double(UINT64_C(0xfff0000000000000)); - - -// The default NaN values (for FPCR.DN=1). -const double kFP64DefaultNaN = rawbits_to_double(UINT64_C(0x7ff8000000000000)); -const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000); -const float16 kFP16DefaultNaN = 0x7e00; - - -static uint64_t RotateRight(uint64_t value, - unsigned int rotate, - unsigned int width) { - VIXL_ASSERT(width <= 64); - rotate &= 63; - return ((value & ((UINT64_C(1) << rotate) - 1)) << - (width - rotate)) | (value >> rotate); -} - - -static uint64_t RepeatBitsAcrossReg(unsigned reg_size, - uint64_t value, - unsigned width) { - VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) || - (width == 32)); - VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - uint64_t result = value & ((UINT64_C(1) << width) - 1); - for (unsigned i = width; i < reg_size; i *= 2) { - result |= (result << i); - } - return result; -} - - -bool Instruction::IsLoad() const { - if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { - return false; - } - - if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { - return Mask(LoadStorePairLBit) != 0; - } else { - LoadStoreOp op = static_cast(Mask(LoadStoreMask)); - switch (op) { - case LDRB_w: - case LDRH_w: - case LDR_w: - case LDR_x: - case LDRSB_w: - case LDRSB_x: - case LDRSH_w: - case LDRSH_x: - case LDRSW_x: - case LDR_b: - case LDR_h: - case LDR_s: - case LDR_d: - case LDR_q: return true; - default: return false; - } - } -} - - -bool Instruction::IsStore() const { - if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { - return false; - } - - if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { - return Mask(LoadStorePairLBit) == 0; - } else { - LoadStoreOp op = static_cast(Mask(LoadStoreMask)); - switch (op) { - case STRB_w: - case STRH_w: - case STR_w: - case STR_x: - case STR_b: - case STR_h: - case STR_s: - case STR_d: - case STR_q: return true; - default: return false; - } - } -} - - -// Logical immediates can't encode zero, so a return value of zero is used to -// indicate a failure case. Specifically, where the constraints on imm_s are -// not met. -uint64_t Instruction::ImmLogical() const { - unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize; - int32_t n = BitN(); - int32_t imm_s = ImmSetBits(); - int32_t imm_r = ImmRotate(); - - // An integer is constructed from the n, imm_s and imm_r bits according to - // the following table: - // - // N imms immr size S R - // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr) - // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr) - // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr) - // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr) - // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr) - // 0 11110s xxxxxr 2 UInt(s) UInt(r) - // (s bits must not be all set) - // - // A pattern is constructed of size bits, where the least significant S+1 - // bits are set. The pattern is rotated right by R, and repeated across a - // 32 or 64-bit value, depending on destination register width. - // - - if (n == 1) { - if (imm_s == 0x3f) { - return 0; - } - uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1; - return RotateRight(bits, imm_r, 64); - } else { - if ((imm_s >> 1) == 0x1f) { - return 0; - } - for (int width = 0x20; width >= 0x2; width >>= 1) { - if ((imm_s & width) == 0) { - int mask = width - 1; - if ((imm_s & mask) == mask) { - return 0; - } - uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1; - return RepeatBitsAcrossReg(reg_size, - RotateRight(bits, imm_r & mask, width), - width); - } - } - } - VIXL_UNREACHABLE(); - return 0; -} - - -uint32_t Instruction::ImmNEONabcdefgh() const { - return ImmNEONabc() << 5 | ImmNEONdefgh(); -} - - -float Instruction::Imm8ToFP32(uint32_t imm8) { - // Imm8: abcdefgh (8 bits) - // Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits) - // where B is b ^ 1 - uint32_t bits = imm8; - uint32_t bit7 = (bits >> 7) & 0x1; - uint32_t bit6 = (bits >> 6) & 0x1; - uint32_t bit5_to_0 = bits & 0x3f; - uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19); - - return rawbits_to_float(result); -} - - -float Instruction::ImmFP32() const { - return Imm8ToFP32(ImmFP()); -} - - -double Instruction::Imm8ToFP64(uint32_t imm8) { - // Imm8: abcdefgh (8 bits) - // Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 - // 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits) - // where B is b ^ 1 - uint32_t bits = imm8; - uint64_t bit7 = (bits >> 7) & 0x1; - uint64_t bit6 = (bits >> 6) & 0x1; - uint64_t bit5_to_0 = bits & 0x3f; - uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48); - - return rawbits_to_double(result); -} - - -double Instruction::ImmFP64() const { - return Imm8ToFP64(ImmFP()); -} - - -float Instruction::ImmNEONFP32() const { - return Imm8ToFP32(ImmNEONabcdefgh()); -} - - -double Instruction::ImmNEONFP64() const { - return Imm8ToFP64(ImmNEONabcdefgh()); -} - - -unsigned CalcLSDataSize(LoadStoreOp op) { - VIXL_ASSERT((LSSize_offset + LSSize_width) == (kInstructionSize * 8)); - unsigned size = static_cast(op) >> LSSize_offset; - if ((op & LSVector_mask) != 0) { - // Vector register memory operations encode the access size in the "size" - // and "opc" fields. - if ((size == 0) && ((op & LSOpc_mask) >> LSOpc_offset) >= 2) { - size = kQRegSizeInBytesLog2; - } - } - return size; -} - - -unsigned CalcLSPairDataSize(LoadStorePairOp op) { - VIXL_STATIC_ASSERT(kXRegSizeInBytes == kDRegSizeInBytes); - VIXL_STATIC_ASSERT(kWRegSizeInBytes == kSRegSizeInBytes); - switch (op) { - case STP_q: - case LDP_q: return kQRegSizeInBytesLog2; - case STP_x: - case LDP_x: - case STP_d: - case LDP_d: return kXRegSizeInBytesLog2; - default: return kWRegSizeInBytesLog2; - } -} - - -int Instruction::ImmBranchRangeBitwidth(ImmBranchType branch_type) { - switch (branch_type) { - case UncondBranchType: - return ImmUncondBranch_width; - case CondBranchType: - return ImmCondBranch_width; - case CompareBranchType: - return ImmCmpBranch_width; - case TestBranchType: - return ImmTestBranch_width; - default: - VIXL_UNREACHABLE(); - return 0; - } -} - - -int32_t Instruction::ImmBranchForwardRange(ImmBranchType branch_type) { - int32_t encoded_max = 1 << (ImmBranchRangeBitwidth(branch_type) - 1); - return encoded_max * kInstructionSize; -} - - -bool Instruction::IsValidImmPCOffset(ImmBranchType branch_type, - int64_t offset) { - return is_intn(ImmBranchRangeBitwidth(branch_type), offset); -} - - -const Instruction* Instruction::ImmPCOffsetTarget() const { - const Instruction * base = this; - ptrdiff_t offset; - if (IsPCRelAddressing()) { - // ADR and ADRP. - offset = ImmPCRel(); - if (Mask(PCRelAddressingMask) == ADRP) { - base = AlignDown(base, kPageSize); - offset *= kPageSize; - } else { - VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR); - } - } else { - // All PC-relative branches. - VIXL_ASSERT(BranchType() != UnknownBranchType); - // Relative branch offsets are instruction-size-aligned. - offset = ImmBranch() << kInstructionSizeLog2; - } - return base + offset; -} - - -int Instruction::ImmBranch() const { - switch (BranchType()) { - case CondBranchType: return ImmCondBranch(); - case UncondBranchType: return ImmUncondBranch(); - case CompareBranchType: return ImmCmpBranch(); - case TestBranchType: return ImmTestBranch(); - default: VIXL_UNREACHABLE(); - } - return 0; -} - - -void Instruction::SetImmPCOffsetTarget(const Instruction* target) { - if (IsPCRelAddressing()) { - SetPCRelImmTarget(target); - } else { - SetBranchImmTarget(target); - } -} - - -void Instruction::SetPCRelImmTarget(const Instruction* target) { - ptrdiff_t imm21; - if ((Mask(PCRelAddressingMask) == ADR)) { - imm21 = target - this; - } else { - VIXL_ASSERT(Mask(PCRelAddressingMask) == ADRP); - uintptr_t this_page = reinterpret_cast(this) / kPageSize; - uintptr_t target_page = reinterpret_cast(target) / kPageSize; - imm21 = target_page - this_page; - } - Instr imm = Assembler::ImmPCRelAddress(static_cast(imm21)); - - SetInstructionBits(Mask(~ImmPCRel_mask) | imm); -} - - -void Instruction::SetBranchImmTarget(const Instruction* target) { - VIXL_ASSERT(((target - this) & 3) == 0); - Instr branch_imm = 0; - uint32_t imm_mask = 0; - int offset = static_cast((target - this) >> kInstructionSizeLog2); - switch (BranchType()) { - case CondBranchType: { - branch_imm = Assembler::ImmCondBranch(offset); - imm_mask = ImmCondBranch_mask; - break; - } - case UncondBranchType: { - branch_imm = Assembler::ImmUncondBranch(offset); - imm_mask = ImmUncondBranch_mask; - break; - } - case CompareBranchType: { - branch_imm = Assembler::ImmCmpBranch(offset); - imm_mask = ImmCmpBranch_mask; - break; - } - case TestBranchType: { - branch_imm = Assembler::ImmTestBranch(offset); - imm_mask = ImmTestBranch_mask; - break; - } - default: VIXL_UNREACHABLE(); - } - SetInstructionBits(Mask(~imm_mask) | branch_imm); -} - - -void Instruction::SetImmLLiteral(const Instruction* source) { - VIXL_ASSERT(IsWordAligned(source)); - ptrdiff_t offset = (source - this) >> kLiteralEntrySizeLog2; - Instr imm = Assembler::ImmLLiteral(static_cast(offset)); - Instr mask = ImmLLiteral_mask; - - SetInstructionBits(Mask(~mask) | imm); -} - - -VectorFormat VectorFormatHalfWidth(const VectorFormat vform) { - VIXL_ASSERT(vform == kFormat8H || vform == kFormat4S || vform == kFormat2D || - vform == kFormatH || vform == kFormatS || vform == kFormatD); - switch (vform) { - case kFormat8H: return kFormat8B; - case kFormat4S: return kFormat4H; - case kFormat2D: return kFormat2S; - case kFormatH: return kFormatB; - case kFormatS: return kFormatH; - case kFormatD: return kFormatS; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - - -VectorFormat VectorFormatDoubleWidth(const VectorFormat vform) { - VIXL_ASSERT(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S || - vform == kFormatB || vform == kFormatH || vform == kFormatS); - switch (vform) { - case kFormat8B: return kFormat8H; - case kFormat4H: return kFormat4S; - case kFormat2S: return kFormat2D; - case kFormatB: return kFormatH; - case kFormatH: return kFormatS; - case kFormatS: return kFormatD; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - - -VectorFormat VectorFormatFillQ(const VectorFormat vform) { - switch (vform) { - case kFormatB: - case kFormat8B: - case kFormat16B: return kFormat16B; - case kFormatH: - case kFormat4H: - case kFormat8H: return kFormat8H; - case kFormatS: - case kFormat2S: - case kFormat4S: return kFormat4S; - case kFormatD: - case kFormat1D: - case kFormat2D: return kFormat2D; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - -VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform) { - switch (vform) { - case kFormat4H: return kFormat8B; - case kFormat8H: return kFormat16B; - case kFormat2S: return kFormat4H; - case kFormat4S: return kFormat8H; - case kFormat1D: return kFormat2S; - case kFormat2D: return kFormat4S; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - -VectorFormat VectorFormatDoubleLanes(const VectorFormat vform) { - VIXL_ASSERT(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S); - switch (vform) { - case kFormat8B: return kFormat16B; - case kFormat4H: return kFormat8H; - case kFormat2S: return kFormat4S; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - - -VectorFormat VectorFormatHalfLanes(const VectorFormat vform) { - VIXL_ASSERT(vform == kFormat16B || vform == kFormat8H || vform == kFormat4S); - switch (vform) { - case kFormat16B: return kFormat8B; - case kFormat8H: return kFormat4H; - case kFormat4S: return kFormat2S; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - - -VectorFormat ScalarFormatFromLaneSize(int laneSize) { - switch (laneSize) { - case 8: return kFormatB; - case 16: return kFormatH; - case 32: return kFormatS; - case 64: return kFormatD; - default: VIXL_UNREACHABLE(); return kFormatUndefined; - } -} - - -unsigned RegisterSizeInBitsFromFormat(VectorFormat vform) { - VIXL_ASSERT(vform != kFormatUndefined); - switch (vform) { - case kFormatB: return kBRegSize; - case kFormatH: return kHRegSize; - case kFormatS: return kSRegSize; - case kFormatD: return kDRegSize; - case kFormat8B: - case kFormat4H: - case kFormat2S: - case kFormat1D: return kDRegSize; - default: return kQRegSize; - } -} - - -unsigned RegisterSizeInBytesFromFormat(VectorFormat vform) { - return RegisterSizeInBitsFromFormat(vform) / 8; -} - - -unsigned LaneSizeInBitsFromFormat(VectorFormat vform) { - VIXL_ASSERT(vform != kFormatUndefined); - switch (vform) { - case kFormatB: - case kFormat8B: - case kFormat16B: return 8; - case kFormatH: - case kFormat4H: - case kFormat8H: return 16; - case kFormatS: - case kFormat2S: - case kFormat4S: return 32; - case kFormatD: - case kFormat1D: - case kFormat2D: return 64; - default: VIXL_UNREACHABLE(); return 0; - } -} - - -int LaneSizeInBytesFromFormat(VectorFormat vform) { - return LaneSizeInBitsFromFormat(vform) / 8; -} - - -int LaneSizeInBytesLog2FromFormat(VectorFormat vform) { - VIXL_ASSERT(vform != kFormatUndefined); - switch (vform) { - case kFormatB: - case kFormat8B: - case kFormat16B: return 0; - case kFormatH: - case kFormat4H: - case kFormat8H: return 1; - case kFormatS: - case kFormat2S: - case kFormat4S: return 2; - case kFormatD: - case kFormat1D: - case kFormat2D: return 3; - default: VIXL_UNREACHABLE(); return 0; - } -} - - -int LaneCountFromFormat(VectorFormat vform) { - VIXL_ASSERT(vform != kFormatUndefined); - switch (vform) { - case kFormat16B: return 16; - case kFormat8B: - case kFormat8H: return 8; - case kFormat4H: - case kFormat4S: return 4; - case kFormat2S: - case kFormat2D: return 2; - case kFormat1D: - case kFormatB: - case kFormatH: - case kFormatS: - case kFormatD: return 1; - default: VIXL_UNREACHABLE(); return 0; - } -} - - -int MaxLaneCountFromFormat(VectorFormat vform) { - VIXL_ASSERT(vform != kFormatUndefined); - switch (vform) { - case kFormatB: - case kFormat8B: - case kFormat16B: return 16; - case kFormatH: - case kFormat4H: - case kFormat8H: return 8; - case kFormatS: - case kFormat2S: - case kFormat4S: return 4; - case kFormatD: - case kFormat1D: - case kFormat2D: return 2; - default: VIXL_UNREACHABLE(); return 0; - } -} - - -// Does 'vform' indicate a vector format or a scalar format? -bool IsVectorFormat(VectorFormat vform) { - VIXL_ASSERT(vform != kFormatUndefined); - switch (vform) { - case kFormatB: - case kFormatH: - case kFormatS: - case kFormatD: return false; - default: return true; - } -} - - -int64_t MaxIntFromFormat(VectorFormat vform) { - return INT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform)); -} - - -int64_t MinIntFromFormat(VectorFormat vform) { - return INT64_MIN >> (64 - LaneSizeInBitsFromFormat(vform)); -} - - -uint64_t MaxUintFromFormat(VectorFormat vform) { - return UINT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform)); -} -} // namespace vixl - diff --git a/disas/libvixl/vixl/a64/instructions-a64.h b/disas/libvixl/vixl/a64/instructions-a64.h deleted file mode 100644 index 7e0dbae36af0..000000000000 --- a/disas/libvixl/vixl/a64/instructions-a64.h +++ /dev/null @@ -1,757 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_A64_INSTRUCTIONS_A64_H_ -#define VIXL_A64_INSTRUCTIONS_A64_H_ - -#include "vixl/globals.h" -#include "vixl/utils.h" -#include "vixl/a64/constants-a64.h" - -namespace vixl { -// ISA constants. -------------------------------------------------------------- - -typedef uint32_t Instr; -const unsigned kInstructionSize = 4; -const unsigned kInstructionSizeLog2 = 2; -const unsigned kLiteralEntrySize = 4; -const unsigned kLiteralEntrySizeLog2 = 2; -const unsigned kMaxLoadLiteralRange = 1 * MBytes; - -// This is the nominal page size (as used by the adrp instruction); the actual -// size of the memory pages allocated by the kernel is likely to differ. -const unsigned kPageSize = 4 * KBytes; -const unsigned kPageSizeLog2 = 12; - -const unsigned kBRegSize = 8; -const unsigned kBRegSizeLog2 = 3; -const unsigned kBRegSizeInBytes = kBRegSize / 8; -const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3; -const unsigned kHRegSize = 16; -const unsigned kHRegSizeLog2 = 4; -const unsigned kHRegSizeInBytes = kHRegSize / 8; -const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3; -const unsigned kWRegSize = 32; -const unsigned kWRegSizeLog2 = 5; -const unsigned kWRegSizeInBytes = kWRegSize / 8; -const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; -const unsigned kXRegSize = 64; -const unsigned kXRegSizeLog2 = 6; -const unsigned kXRegSizeInBytes = kXRegSize / 8; -const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; -const unsigned kSRegSize = 32; -const unsigned kSRegSizeLog2 = 5; -const unsigned kSRegSizeInBytes = kSRegSize / 8; -const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; -const unsigned kDRegSize = 64; -const unsigned kDRegSizeLog2 = 6; -const unsigned kDRegSizeInBytes = kDRegSize / 8; -const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; -const unsigned kQRegSize = 128; -const unsigned kQRegSizeLog2 = 7; -const unsigned kQRegSizeInBytes = kQRegSize / 8; -const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3; -const uint64_t kWRegMask = UINT64_C(0xffffffff); -const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); -const uint64_t kSRegMask = UINT64_C(0xffffffff); -const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); -const uint64_t kSSignMask = UINT64_C(0x80000000); -const uint64_t kDSignMask = UINT64_C(0x8000000000000000); -const uint64_t kWSignMask = UINT64_C(0x80000000); -const uint64_t kXSignMask = UINT64_C(0x8000000000000000); -const uint64_t kByteMask = UINT64_C(0xff); -const uint64_t kHalfWordMask = UINT64_C(0xffff); -const uint64_t kWordMask = UINT64_C(0xffffffff); -const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff); -const uint64_t kWMaxUInt = UINT64_C(0xffffffff); -const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); -const int64_t kXMinInt = INT64_C(0x8000000000000000); -const int32_t kWMaxInt = INT32_C(0x7fffffff); -const int32_t kWMinInt = INT32_C(0x80000000); -const unsigned kLinkRegCode = 30; -const unsigned kZeroRegCode = 31; -const unsigned kSPRegInternalCode = 63; -const unsigned kRegCodeMask = 0x1f; - -const unsigned kAddressTagOffset = 56; -const unsigned kAddressTagWidth = 8; -const uint64_t kAddressTagMask = - ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset; -VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000)); - -// AArch64 floating-point specifics. These match IEEE-754. -const unsigned kDoubleMantissaBits = 52; -const unsigned kDoubleExponentBits = 11; -const unsigned kFloatMantissaBits = 23; -const unsigned kFloatExponentBits = 8; -const unsigned kFloat16MantissaBits = 10; -const unsigned kFloat16ExponentBits = 5; - -// Floating-point infinity values. -extern const float16 kFP16PositiveInfinity; -extern const float16 kFP16NegativeInfinity; -extern const float kFP32PositiveInfinity; -extern const float kFP32NegativeInfinity; -extern const double kFP64PositiveInfinity; -extern const double kFP64NegativeInfinity; - -// The default NaN values (for FPCR.DN=1). -extern const float16 kFP16DefaultNaN; -extern const float kFP32DefaultNaN; -extern const double kFP64DefaultNaN; - -unsigned CalcLSDataSize(LoadStoreOp op); -unsigned CalcLSPairDataSize(LoadStorePairOp op); - -enum ImmBranchType { - UnknownBranchType = 0, - CondBranchType = 1, - UncondBranchType = 2, - CompareBranchType = 3, - TestBranchType = 4 -}; - -enum AddrMode { - Offset, - PreIndex, - PostIndex -}; - -enum FPRounding { - // The first four values are encodable directly by FPCR. - FPTieEven = 0x0, - FPPositiveInfinity = 0x1, - FPNegativeInfinity = 0x2, - FPZero = 0x3, - - // The final rounding modes are only available when explicitly specified by - // the instruction (such as with fcvta). It cannot be set in FPCR. - FPTieAway, - FPRoundOdd -}; - -enum Reg31Mode { - Reg31IsStackPointer, - Reg31IsZeroRegister -}; - -// Instructions. --------------------------------------------------------------- - -class Instruction { - public: - Instr InstructionBits() const { - return *(reinterpret_cast(this)); - } - - void SetInstructionBits(Instr new_instr) { - *(reinterpret_cast(this)) = new_instr; - } - - int Bit(int pos) const { - return (InstructionBits() >> pos) & 1; - } - - uint32_t Bits(int msb, int lsb) const { - return unsigned_bitextract_32(msb, lsb, InstructionBits()); - } - - int32_t SignedBits(int msb, int lsb) const { - int32_t bits = *(reinterpret_cast(this)); - return signed_bitextract_32(msb, lsb, bits); - } - - Instr Mask(uint32_t mask) const { - return InstructionBits() & mask; - } - - #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ - int32_t Name() const { return Func(HighBit, LowBit); } - INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) - #undef DEFINE_GETTER - - // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), - // formed from ImmPCRelLo and ImmPCRelHi. - int ImmPCRel() const { - int offset = - static_cast((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); - int width = ImmPCRelLo_width + ImmPCRelHi_width; - return signed_bitextract_32(width - 1, 0, offset); - } - - uint64_t ImmLogical() const; - unsigned ImmNEONabcdefgh() const; - float ImmFP32() const; - double ImmFP64() const; - float ImmNEONFP32() const; - double ImmNEONFP64() const; - - unsigned SizeLS() const { - return CalcLSDataSize(static_cast(Mask(LoadStoreMask))); - } - - unsigned SizeLSPair() const { - return CalcLSPairDataSize( - static_cast(Mask(LoadStorePairMask))); - } - - int NEONLSIndex(int access_size_shift) const { - int64_t q = NEONQ(); - int64_t s = NEONS(); - int64_t size = NEONLSSize(); - int64_t index = (q << 3) | (s << 2) | size; - return static_cast(index >> access_size_shift); - } - - // Helpers. - bool IsCondBranchImm() const { - return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; - } - - bool IsUncondBranchImm() const { - return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; - } - - bool IsCompareBranch() const { - return Mask(CompareBranchFMask) == CompareBranchFixed; - } - - bool IsTestBranch() const { - return Mask(TestBranchFMask) == TestBranchFixed; - } - - bool IsImmBranch() const { - return BranchType() != UnknownBranchType; - } - - bool IsPCRelAddressing() const { - return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; - } - - bool IsLogicalImmediate() const { - return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; - } - - bool IsAddSubImmediate() const { - return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; - } - - bool IsAddSubExtended() const { - return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; - } - - bool IsLoadOrStore() const { - return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; - } - - bool IsLoad() const; - bool IsStore() const; - - bool IsLoadLiteral() const { - // This includes PRFM_lit. - return Mask(LoadLiteralFMask) == LoadLiteralFixed; - } - - bool IsMovn() const { - return (Mask(MoveWideImmediateMask) == MOVN_x) || - (Mask(MoveWideImmediateMask) == MOVN_w); - } - - static int ImmBranchRangeBitwidth(ImmBranchType branch_type); - static int32_t ImmBranchForwardRange(ImmBranchType branch_type); - static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset); - - // Indicate whether Rd can be the stack pointer or the zero register. This - // does not check that the instruction actually has an Rd field. - Reg31Mode RdMode() const { - // The following instructions use sp or wsp as Rd: - // Add/sub (immediate) when not setting the flags. - // Add/sub (extended) when not setting the flags. - // Logical (immediate) when not setting the flags. - // Otherwise, r31 is the zero register. - if (IsAddSubImmediate() || IsAddSubExtended()) { - if (Mask(AddSubSetFlagsBit)) { - return Reg31IsZeroRegister; - } else { - return Reg31IsStackPointer; - } - } - if (IsLogicalImmediate()) { - // Of the logical (immediate) instructions, only ANDS (and its aliases) - // can set the flags. The others can all write into sp. - // Note that some logical operations are not available to - // immediate-operand instructions, so we have to combine two masks here. - if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) { - return Reg31IsZeroRegister; - } else { - return Reg31IsStackPointer; - } - } - return Reg31IsZeroRegister; - } - - // Indicate whether Rn can be the stack pointer or the zero register. This - // does not check that the instruction actually has an Rn field. - Reg31Mode RnMode() const { - // The following instructions use sp or wsp as Rn: - // All loads and stores. - // Add/sub (immediate). - // Add/sub (extended). - // Otherwise, r31 is the zero register. - if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { - return Reg31IsStackPointer; - } - return Reg31IsZeroRegister; - } - - ImmBranchType BranchType() const { - if (IsCondBranchImm()) { - return CondBranchType; - } else if (IsUncondBranchImm()) { - return UncondBranchType; - } else if (IsCompareBranch()) { - return CompareBranchType; - } else if (IsTestBranch()) { - return TestBranchType; - } else { - return UnknownBranchType; - } - } - - // Find the target of this instruction. 'this' may be a branch or a - // PC-relative addressing instruction. - const Instruction* ImmPCOffsetTarget() const; - - // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or - // a PC-relative addressing instruction. - void SetImmPCOffsetTarget(const Instruction* target); - // Patch a literal load instruction to load from 'source'. - void SetImmLLiteral(const Instruction* source); - - // The range of a load literal instruction, expressed as 'instr +- range'. - // The range is actually the 'positive' range; the branch instruction can - // target [instr - range - kInstructionSize, instr + range]. - static const int kLoadLiteralImmBitwidth = 19; - static const int kLoadLiteralRange = - (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize; - - // Calculate the address of a literal referred to by a load-literal - // instruction, and return it as the specified type. - // - // The literal itself is safely mutable only if the backing buffer is safely - // mutable. - template - T LiteralAddress() const { - uint64_t base_raw = reinterpret_cast(this); - int64_t offset = ImmLLiteral() << kLiteralEntrySizeLog2; - uint64_t address_raw = base_raw + offset; - - // Cast the address using a C-style cast. A reinterpret_cast would be - // appropriate, but it can't cast one integral type to another. - T address = (T)(address_raw); - - // Assert that the address can be represented by the specified type. - VIXL_ASSERT((uint64_t)(address) == address_raw); - - return address; - } - - uint32_t Literal32() const { - uint32_t literal; - memcpy(&literal, LiteralAddress(), sizeof(literal)); - return literal; - } - - uint64_t Literal64() const { - uint64_t literal; - memcpy(&literal, LiteralAddress(), sizeof(literal)); - return literal; - } - - float LiteralFP32() const { - return rawbits_to_float(Literal32()); - } - - double LiteralFP64() const { - return rawbits_to_double(Literal64()); - } - - const Instruction* NextInstruction() const { - return this + kInstructionSize; - } - - const Instruction* InstructionAtOffset(int64_t offset) const { - VIXL_ASSERT(IsWordAligned(this + offset)); - return this + offset; - } - - template static Instruction* Cast(T src) { - return reinterpret_cast(src); - } - - template static const Instruction* CastConst(T src) { - return reinterpret_cast(src); - } - - private: - int ImmBranch() const; - - static float Imm8ToFP32(uint32_t imm8); - static double Imm8ToFP64(uint32_t imm8); - - void SetPCRelImmTarget(const Instruction* target); - void SetBranchImmTarget(const Instruction* target); -}; - - -// Functions for handling NEON vector format information. -enum VectorFormat { - kFormatUndefined = 0xffffffff, - kFormat8B = NEON_8B, - kFormat16B = NEON_16B, - kFormat4H = NEON_4H, - kFormat8H = NEON_8H, - kFormat2S = NEON_2S, - kFormat4S = NEON_4S, - kFormat1D = NEON_1D, - kFormat2D = NEON_2D, - - // Scalar formats. We add the scalar bit to distinguish between scalar and - // vector enumerations; the bit is always set in the encoding of scalar ops - // and always clear for vector ops. Although kFormatD and kFormat1D appear - // to be the same, their meaning is subtly different. The first is a scalar - // operation, the second a vector operation that only affects one lane. - kFormatB = NEON_B | NEONScalar, - kFormatH = NEON_H | NEONScalar, - kFormatS = NEON_S | NEONScalar, - kFormatD = NEON_D | NEONScalar -}; - -VectorFormat VectorFormatHalfWidth(const VectorFormat vform); -VectorFormat VectorFormatDoubleWidth(const VectorFormat vform); -VectorFormat VectorFormatDoubleLanes(const VectorFormat vform); -VectorFormat VectorFormatHalfLanes(const VectorFormat vform); -VectorFormat ScalarFormatFromLaneSize(int lanesize); -VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform); -VectorFormat VectorFormatFillQ(const VectorFormat vform); -unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); -unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); -// TODO: Make the return types of these functions consistent. -unsigned LaneSizeInBitsFromFormat(VectorFormat vform); -int LaneSizeInBytesFromFormat(VectorFormat vform); -int LaneSizeInBytesLog2FromFormat(VectorFormat vform); -int LaneCountFromFormat(VectorFormat vform); -int MaxLaneCountFromFormat(VectorFormat vform); -bool IsVectorFormat(VectorFormat vform); -int64_t MaxIntFromFormat(VectorFormat vform); -int64_t MinIntFromFormat(VectorFormat vform); -uint64_t MaxUintFromFormat(VectorFormat vform); - - -enum NEONFormat { - NF_UNDEF = 0, - NF_8B = 1, - NF_16B = 2, - NF_4H = 3, - NF_8H = 4, - NF_2S = 5, - NF_4S = 6, - NF_1D = 7, - NF_2D = 8, - NF_B = 9, - NF_H = 10, - NF_S = 11, - NF_D = 12 -}; - -static const unsigned kNEONFormatMaxBits = 6; - -struct NEONFormatMap { - // The bit positions in the instruction to consider. - uint8_t bits[kNEONFormatMaxBits]; - - // Mapping from concatenated bits to format. - NEONFormat map[1 << kNEONFormatMaxBits]; -}; - -class NEONFormatDecoder { - public: - enum SubstitutionMode { - kPlaceholder, - kFormat - }; - - // Construct a format decoder with increasingly specific format maps for each - // subsitution. If no format map is specified, the default is the integer - // format map. - explicit NEONFormatDecoder(const Instruction* instr) { - instrbits_ = instr->InstructionBits(); - SetFormatMaps(IntegerFormatMap()); - } - NEONFormatDecoder(const Instruction* instr, - const NEONFormatMap* format) { - instrbits_ = instr->InstructionBits(); - SetFormatMaps(format); - } - NEONFormatDecoder(const Instruction* instr, - const NEONFormatMap* format0, - const NEONFormatMap* format1) { - instrbits_ = instr->InstructionBits(); - SetFormatMaps(format0, format1); - } - NEONFormatDecoder(const Instruction* instr, - const NEONFormatMap* format0, - const NEONFormatMap* format1, - const NEONFormatMap* format2) { - instrbits_ = instr->InstructionBits(); - SetFormatMaps(format0, format1, format2); - } - - // Set the format mapping for all or individual substitutions. - void SetFormatMaps(const NEONFormatMap* format0, - const NEONFormatMap* format1 = NULL, - const NEONFormatMap* format2 = NULL) { - VIXL_ASSERT(format0 != NULL); - formats_[0] = format0; - formats_[1] = (format1 == NULL) ? formats_[0] : format1; - formats_[2] = (format2 == NULL) ? formats_[1] : format2; - } - void SetFormatMap(unsigned index, const NEONFormatMap* format) { - VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0]))); - VIXL_ASSERT(format != NULL); - formats_[index] = format; - } - - // Substitute %s in the input string with the placeholder string for each - // register, ie. "'B", "'H", etc. - const char* SubstitutePlaceholders(const char* string) { - return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); - } - - // Substitute %s in the input string with a new string based on the - // substitution mode. - const char* Substitute(const char* string, - SubstitutionMode mode0 = kFormat, - SubstitutionMode mode1 = kFormat, - SubstitutionMode mode2 = kFormat) { - snprintf(form_buffer_, sizeof(form_buffer_), string, - GetSubstitute(0, mode0), - GetSubstitute(1, mode1), - GetSubstitute(2, mode2)); - return form_buffer_; - } - - // Append a "2" to a mnemonic string based of the state of the Q bit. - const char* Mnemonic(const char* mnemonic) { - if ((instrbits_ & NEON_Q) != 0) { - snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic); - return mne_buffer_; - } - return mnemonic; - } - - VectorFormat GetVectorFormat(int format_index = 0) { - return GetVectorFormat(formats_[format_index]); - } - - VectorFormat GetVectorFormat(const NEONFormatMap* format_map) { - static const VectorFormat vform[] = { - kFormatUndefined, - kFormat8B, kFormat16B, kFormat4H, kFormat8H, - kFormat2S, kFormat4S, kFormat1D, kFormat2D, - kFormatB, kFormatH, kFormatS, kFormatD - }; - VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0]))); - return vform[GetNEONFormat(format_map)]; - } - - // Built in mappings for common cases. - - // The integer format map uses three bits (Q, size<1:0>) to encode the - // "standard" set of NEON integer vector formats. - static const NEONFormatMap* IntegerFormatMap() { - static const NEONFormatMap map = { - {23, 22, 30}, - {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D} - }; - return ↦ - } - - // The long integer format map uses two bits (size<1:0>) to encode the - // long set of NEON integer vector formats. These are used in narrow, wide - // and long operations. - static const NEONFormatMap* LongIntegerFormatMap() { - static const NEONFormatMap map = { - {23, 22}, {NF_8H, NF_4S, NF_2D} - }; - return ↦ - } - - // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector - // formats: NF_2S, NF_4S, NF_2D. - static const NEONFormatMap* FPFormatMap() { - // The FP format map assumes two bits (Q, size<0>) are used to encode the - // NEON FP vector formats: NF_2S, NF_4S, NF_2D. - static const NEONFormatMap map = { - {22, 30}, {NF_2S, NF_4S, NF_UNDEF, NF_2D} - }; - return ↦ - } - - // The load/store format map uses three bits (Q, 11, 10) to encode the - // set of NEON vector formats. - static const NEONFormatMap* LoadStoreFormatMap() { - static const NEONFormatMap map = { - {11, 10, 30}, - {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D} - }; - return ↦ - } - - // The logical format map uses one bit (Q) to encode the NEON vector format: - // NF_8B, NF_16B. - static const NEONFormatMap* LogicalFormatMap() { - static const NEONFormatMap map = { - {30}, {NF_8B, NF_16B} - }; - return ↦ - } - - // The triangular format map uses between two and five bits to encode the NEON - // vector format: - // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H - // x1000->2S, x1001->4S, 10001->2D, all others undefined. - static const NEONFormatMap* TriangularFormatMap() { - static const NEONFormatMap map = { - {19, 18, 17, 16, 30}, - {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, - NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_UNDEF, NF_2D, - NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, NF_4S, NF_8B, NF_16B, - NF_4H, NF_8H, NF_8B, NF_16B} - }; - return ↦ - } - - // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar - // formats: NF_B, NF_H, NF_S, NF_D. - static const NEONFormatMap* ScalarFormatMap() { - static const NEONFormatMap map = { - {23, 22}, {NF_B, NF_H, NF_S, NF_D} - }; - return ↦ - } - - // The long scalar format map uses two bits (size<1:0>) to encode the longer - // NEON scalar formats: NF_H, NF_S, NF_D. - static const NEONFormatMap* LongScalarFormatMap() { - static const NEONFormatMap map = { - {23, 22}, {NF_H, NF_S, NF_D} - }; - return ↦ - } - - // The FP scalar format map assumes one bit (size<0>) is used to encode the - // NEON FP scalar formats: NF_S, NF_D. - static const NEONFormatMap* FPScalarFormatMap() { - static const NEONFormatMap map = { - {22}, {NF_S, NF_D} - }; - return ↦ - } - - // The triangular scalar format map uses between one and four bits to encode - // the NEON FP scalar formats: - // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined. - static const NEONFormatMap* TriangularScalarFormatMap() { - static const NEONFormatMap map = { - {19, 18, 17, 16}, - {NF_UNDEF, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B, - NF_D, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B} - }; - return ↦ - } - - private: - // Get a pointer to a string that represents the format or placeholder for - // the specified substitution index, based on the format map and instruction. - const char* GetSubstitute(int index, SubstitutionMode mode) { - if (mode == kFormat) { - return NEONFormatAsString(GetNEONFormat(formats_[index])); - } - VIXL_ASSERT(mode == kPlaceholder); - return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index])); - } - - // Get the NEONFormat enumerated value for bits obtained from the - // instruction based on the specified format mapping. - NEONFormat GetNEONFormat(const NEONFormatMap* format_map) { - return format_map->map[PickBits(format_map->bits)]; - } - - // Convert a NEONFormat into a string. - static const char* NEONFormatAsString(NEONFormat format) { - static const char* formats[] = { - "undefined", - "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d", - "b", "h", "s", "d" - }; - VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0]))); - return formats[format]; - } - - // Convert a NEONFormat into a register placeholder string. - static const char* NEONFormatAsPlaceholder(NEONFormat format) { - VIXL_ASSERT((format == NF_B) || (format == NF_H) || - (format == NF_S) || (format == NF_D) || - (format == NF_UNDEF)); - static const char* formats[] = { - "undefined", - "undefined", "undefined", "undefined", "undefined", - "undefined", "undefined", "undefined", "undefined", - "'B", "'H", "'S", "'D" - }; - return formats[format]; - } - - // Select bits from instrbits_ defined by the bits array, concatenate them, - // and return the value. - uint8_t PickBits(const uint8_t bits[]) { - uint8_t result = 0; - for (unsigned b = 0; b < kNEONFormatMaxBits; b++) { - if (bits[b] == 0) break; - result <<= 1; - result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1; - } - return result; - } - - Instr instrbits_; - const NEONFormatMap* formats_[3]; - char form_buffer_[64]; - char mne_buffer_[16]; -}; -} // namespace vixl - -#endif // VIXL_A64_INSTRUCTIONS_A64_H_ diff --git a/disas/libvixl/vixl/code-buffer.h b/disas/libvixl/vixl/code-buffer.h deleted file mode 100644 index b95babbdee26..000000000000 --- a/disas/libvixl/vixl/code-buffer.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2014, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_CODE_BUFFER_H -#define VIXL_CODE_BUFFER_H - -#include -#include "vixl/globals.h" - -namespace vixl { - -class CodeBuffer { - public: - explicit CodeBuffer(size_t capacity = 4 * KBytes); - CodeBuffer(void* buffer, size_t capacity); - ~CodeBuffer(); - - void Reset(); - - ptrdiff_t OffsetFrom(ptrdiff_t offset) const { - ptrdiff_t cursor_offset = cursor_ - buffer_; - VIXL_ASSERT((offset >= 0) && (offset <= cursor_offset)); - return cursor_offset - offset; - } - - ptrdiff_t CursorOffset() const { - return OffsetFrom(0); - } - - template - T GetOffsetAddress(ptrdiff_t offset) const { - VIXL_ASSERT((offset >= 0) && (offset <= (cursor_ - buffer_))); - return reinterpret_cast(buffer_ + offset); - } - - size_t RemainingBytes() const { - VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_))); - return (buffer_ + capacity_) - cursor_; - } - - // A code buffer can emit: - // * 32-bit data: instruction and constant. - // * 64-bit data: constant. - // * string: debug info. - void Emit32(uint32_t data) { Emit(data); } - - void Emit64(uint64_t data) { Emit(data); } - - void EmitString(const char* string); - - // Align to kInstructionSize. - void Align(); - - size_t capacity() const { return capacity_; } - - bool IsManaged() const { return managed_; } - - void Grow(size_t new_capacity); - - bool IsDirty() const { return dirty_; } - - void SetClean() { dirty_ = false; } - - private: - template - void Emit(T value) { - VIXL_ASSERT(RemainingBytes() >= sizeof(value)); - dirty_ = true; - memcpy(cursor_, &value, sizeof(value)); - cursor_ += sizeof(value); - } - - // Backing store of the buffer. - byte* buffer_; - // If true the backing store is allocated and deallocated by the buffer. The - // backing store can then grow on demand. If false the backing store is - // provided by the user and cannot be resized internally. - bool managed_; - // Pointer to the next location to be written. - byte* cursor_; - // True if there has been any write since the buffer was created or cleaned. - bool dirty_; - // Capacity in bytes of the backing store. - size_t capacity_; -}; - -} // namespace vixl - -#endif // VIXL_CODE_BUFFER_H - diff --git a/disas/libvixl/vixl/compiler-intrinsics.cc b/disas/libvixl/vixl/compiler-intrinsics.cc deleted file mode 100644 index fd551faeb1f7..000000000000 --- a/disas/libvixl/vixl/compiler-intrinsics.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "compiler-intrinsics.h" - -namespace vixl { - - -int CountLeadingSignBitsFallBack(int64_t value, int width) { - VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); - if (value >= 0) { - return CountLeadingZeros(value, width) - 1; - } else { - return CountLeadingZeros(~value, width) - 1; - } -} - - -int CountLeadingZerosFallBack(uint64_t value, int width) { - VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); - if (value == 0) { - return width; - } - int count = 0; - value = value << (64 - width); - if ((value & UINT64_C(0xffffffff00000000)) == 0) { - count += 32; - value = value << 32; - } - if ((value & UINT64_C(0xffff000000000000)) == 0) { - count += 16; - value = value << 16; - } - if ((value & UINT64_C(0xff00000000000000)) == 0) { - count += 8; - value = value << 8; - } - if ((value & UINT64_C(0xf000000000000000)) == 0) { - count += 4; - value = value << 4; - } - if ((value & UINT64_C(0xc000000000000000)) == 0) { - count += 2; - value = value << 2; - } - if ((value & UINT64_C(0x8000000000000000)) == 0) { - count += 1; - } - count += (value == 0); - return count; -} - - -int CountSetBitsFallBack(uint64_t value, int width) { - VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); - - // Mask out unused bits to ensure that they are not counted. - value &= (UINT64_C(0xffffffffffffffff) >> (64 - width)); - - // Add up the set bits. - // The algorithm works by adding pairs of bit fields together iteratively, - // where the size of each bit field doubles each time. - // An example for an 8-bit value: - // Bits: h g f e d c b a - // \ | \ | \ | \ | - // value = h+g f+e d+c b+a - // \ | \ | - // value = h+g+f+e d+c+b+a - // \ | - // value = h+g+f+e+d+c+b+a - const uint64_t kMasks[] = { - UINT64_C(0x5555555555555555), - UINT64_C(0x3333333333333333), - UINT64_C(0x0f0f0f0f0f0f0f0f), - UINT64_C(0x00ff00ff00ff00ff), - UINT64_C(0x0000ffff0000ffff), - UINT64_C(0x00000000ffffffff), - }; - - for (unsigned i = 0; i < (sizeof(kMasks) / sizeof(kMasks[0])); i++) { - int shift = 1 << i; - value = ((value >> shift) & kMasks[i]) + (value & kMasks[i]); - } - - return static_cast(value); -} - - -int CountTrailingZerosFallBack(uint64_t value, int width) { - VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); - int count = 0; - value = value << (64 - width); - if ((value & UINT64_C(0xffffffff)) == 0) { - count += 32; - value = value >> 32; - } - if ((value & 0xffff) == 0) { - count += 16; - value = value >> 16; - } - if ((value & 0xff) == 0) { - count += 8; - value = value >> 8; - } - if ((value & 0xf) == 0) { - count += 4; - value = value >> 4; - } - if ((value & 0x3) == 0) { - count += 2; - value = value >> 2; - } - if ((value & 0x1) == 0) { - count += 1; - } - count += (value == 0); - return count - (64 - width); -} - - -} // namespace vixl diff --git a/disas/libvixl/vixl/compiler-intrinsics.h b/disas/libvixl/vixl/compiler-intrinsics.h deleted file mode 100644 index 9431beddb9d9..000000000000 --- a/disas/libvixl/vixl/compiler-intrinsics.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -#ifndef VIXL_COMPILER_INTRINSICS_H -#define VIXL_COMPILER_INTRINSICS_H - -#include "globals.h" - -namespace vixl { - -// Helper to check whether the version of GCC used is greater than the specified -// requirement. -#define MAJOR 1000000 -#define MINOR 1000 -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \ - ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR + __GNUC_PATCHLEVEL__) >= \ - ((major) * MAJOR + (minor) * MINOR + (patchlevel))) -#elif defined(__GNUC__) && defined(__GNUC_MINOR__) -#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \ - ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR) >= \ - ((major) * MAJOR + (minor) * MINOR + (patchlevel))) -#else -#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) 0 -#endif - - -#if defined(__clang__) && !defined(VIXL_NO_COMPILER_BUILTINS) - -#define COMPILER_HAS_BUILTIN_CLRSB (__has_builtin(__builtin_clrsb)) -#define COMPILER_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz)) -#define COMPILER_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz)) -#define COMPILER_HAS_BUILTIN_FFS (__has_builtin(__builtin_ffs)) -#define COMPILER_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount)) - -#elif defined(__GNUC__) && !defined(VIXL_NO_COMPILER_BUILTINS) -// The documentation for these builtins is available at: -// https://gcc.gnu.org/onlinedocs/gcc-$MAJOR.$MINOR.$PATCHLEVEL/gcc//Other-Builtins.html - -# define COMPILER_HAS_BUILTIN_CLRSB (GCC_VERSION_OR_NEWER(4, 7, 0)) -# define COMPILER_HAS_BUILTIN_CLZ (GCC_VERSION_OR_NEWER(3, 4, 0)) -# define COMPILER_HAS_BUILTIN_CTZ (GCC_VERSION_OR_NEWER(3, 4, 0)) -# define COMPILER_HAS_BUILTIN_FFS (GCC_VERSION_OR_NEWER(3, 4, 0)) -# define COMPILER_HAS_BUILTIN_POPCOUNT (GCC_VERSION_OR_NEWER(3, 4, 0)) - -#else -// One can define VIXL_NO_COMPILER_BUILTINS to force using the manually -// implemented C++ methods. - -#define COMPILER_HAS_BUILTIN_BSWAP false -#define COMPILER_HAS_BUILTIN_CLRSB false -#define COMPILER_HAS_BUILTIN_CLZ false -#define COMPILER_HAS_BUILTIN_CTZ false -#define COMPILER_HAS_BUILTIN_FFS false -#define COMPILER_HAS_BUILTIN_POPCOUNT false - -#endif - - -template -inline bool IsPowerOf2(V value) { - return (value != 0) && ((value & (value - 1)) == 0); -} - - -// Declaration of fallback functions. -int CountLeadingSignBitsFallBack(int64_t value, int width); -int CountLeadingZerosFallBack(uint64_t value, int width); -int CountSetBitsFallBack(uint64_t value, int width); -int CountTrailingZerosFallBack(uint64_t value, int width); - - -// Implementation of intrinsics functions. -// TODO: The implementations could be improved for sizes different from 32bit -// and 64bit: we could mask the values and call the appropriate builtin. - -template -inline int CountLeadingSignBits(V value, int width = (sizeof(V) * 8)) { -#if COMPILER_HAS_BUILTIN_CLRSB - if (width == 32) { - return __builtin_clrsb(value); - } else if (width == 64) { - return __builtin_clrsbll(value); - } -#endif - return CountLeadingSignBitsFallBack(value, width); -} - - -template -inline int CountLeadingZeros(V value, int width = (sizeof(V) * 8)) { -#if COMPILER_HAS_BUILTIN_CLZ - if (width == 32) { - return (value == 0) ? 32 : __builtin_clz(static_cast(value)); - } else if (width == 64) { - return (value == 0) ? 64 : __builtin_clzll(value); - } -#endif - return CountLeadingZerosFallBack(value, width); -} - - -template -inline int CountSetBits(V value, int width = (sizeof(V) * 8)) { -#if COMPILER_HAS_BUILTIN_POPCOUNT - if (width == 32) { - return __builtin_popcount(static_cast(value)); - } else if (width == 64) { - return __builtin_popcountll(value); - } -#endif - return CountSetBitsFallBack(value, width); -} - - -template -inline int CountTrailingZeros(V value, int width = (sizeof(V) * 8)) { -#if COMPILER_HAS_BUILTIN_CTZ - if (width == 32) { - return (value == 0) ? 32 : __builtin_ctz(static_cast(value)); - } else if (width == 64) { - return (value == 0) ? 64 : __builtin_ctzll(value); - } -#endif - return CountTrailingZerosFallBack(value, width); -} - -} // namespace vixl - -#endif // VIXL_COMPILER_INTRINSICS_H - diff --git a/disas/libvixl/vixl/globals.h b/disas/libvixl/vixl/globals.h deleted file mode 100644 index 3a71942f1e53..000000000000 --- a/disas/libvixl/vixl/globals.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_GLOBALS_H -#define VIXL_GLOBALS_H - -// Get standard C99 macros for integer types. -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif - -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif - -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif - -extern "C" { -#include -#include -} - -#include -#include -#include -#include -#include - -#include "vixl/platform.h" - - -typedef uint8_t byte; - -// Type for half-precision (16 bit) floating point numbers. -typedef uint16_t float16; - -const int KBytes = 1024; -const int MBytes = 1024 * KBytes; - -#define VIXL_ABORT() \ - do { printf("in %s, line %i", __FILE__, __LINE__); abort(); } while (false) -#ifdef VIXL_DEBUG - #define VIXL_ASSERT(condition) assert(condition) - #define VIXL_CHECK(condition) VIXL_ASSERT(condition) - #define VIXL_UNIMPLEMENTED() \ - do { fprintf(stderr, "UNIMPLEMENTED\t"); VIXL_ABORT(); } while (false) - #define VIXL_UNREACHABLE() \ - do { fprintf(stderr, "UNREACHABLE\t"); VIXL_ABORT(); } while (false) -#else - #define VIXL_ASSERT(condition) ((void) 0) - #define VIXL_CHECK(condition) assert(condition) - #define VIXL_UNIMPLEMENTED() ((void) 0) - #define VIXL_UNREACHABLE() ((void) 0) -#endif -// This is not as powerful as template based assertions, but it is simple. -// It assumes that the descriptions are unique. If this starts being a problem, -// we can switch to a different implemention. -#define VIXL_CONCAT(a, b) a##b -#define VIXL_STATIC_ASSERT_LINE(line, condition) \ - typedef char VIXL_CONCAT(STATIC_ASSERT_LINE_, line)[(condition) ? 1 : -1] \ - __attribute__((unused)) -#define VIXL_STATIC_ASSERT(condition) \ - VIXL_STATIC_ASSERT_LINE(__LINE__, condition) - -template -inline void USE(T1) {} - -template -inline void USE(T1, T2) {} - -template -inline void USE(T1, T2, T3) {} - -template -inline void USE(T1, T2, T3, T4) {} - -#define VIXL_ALIGNMENT_EXCEPTION() \ - do { fprintf(stderr, "ALIGNMENT EXCEPTION\t"); VIXL_ABORT(); } while (0) - -// The clang::fallthrough attribute is used along with the Wimplicit-fallthrough -// argument to annotate intentional fall-through between switch labels. -// For more information please refer to: -// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough -#ifndef __has_warning - #define __has_warning(x) 0 -#endif - -// Fallthrough annotation for Clang and C++11(201103L). -#if __has_warning("-Wimplicit-fallthrough") && __cplusplus >= 201103L - #define VIXL_FALLTHROUGH() [[clang::fallthrough]] //NOLINT -// Fallthrough annotation for GCC >= 7. -#elif __GNUC__ >= 7 - #define VIXL_FALLTHROUGH() __attribute__((fallthrough)) -#else - #define VIXL_FALLTHROUGH() do {} while (0) -#endif - -#if __cplusplus >= 201103L - #define VIXL_NO_RETURN [[noreturn]] //NOLINT -#else - #define VIXL_NO_RETURN __attribute__((noreturn)) -#endif - -// Some functions might only be marked as "noreturn" for the DEBUG build. This -// macro should be used for such cases (for more details see what -// VIXL_UNREACHABLE expands to). -#ifdef VIXL_DEBUG - #define VIXL_DEBUG_NO_RETURN VIXL_NO_RETURN -#else - #define VIXL_DEBUG_NO_RETURN -#endif - -#ifdef VIXL_INCLUDE_SIMULATOR -#ifndef VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE - #define VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE 1 -#endif -#else -#ifndef VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE - #define VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE 0 -#endif -#if VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE - #warning "Generating Simulator instructions without Simulator support." -#endif -#endif - -#ifdef USE_SIMULATOR - #error "Please see the release notes for USE_SIMULATOR." -#endif - -#endif // VIXL_GLOBALS_H diff --git a/disas/libvixl/vixl/invalset.h b/disas/libvixl/vixl/invalset.h deleted file mode 100644 index 2e0871f8c3f9..000000000000 --- a/disas/libvixl/vixl/invalset.h +++ /dev/null @@ -1,775 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_INVALSET_H_ -#define VIXL_INVALSET_H_ - -#include - -#include -#include - -#include "vixl/globals.h" - -namespace vixl { - -// We define a custom data structure template and its iterator as `std` -// containers do not fit the performance requirements for some of our use cases. -// -// The structure behaves like an iterable unordered set with special properties -// and restrictions. "InvalSet" stands for "Invalidatable Set". -// -// Restrictions and requirements: -// - Adding an element already present in the set is illegal. In debug mode, -// this is checked at insertion time. -// - The templated class `ElementType` must provide comparison operators so that -// `std::sort()` can be used. -// - A key must be available to represent invalid elements. -// - Elements with an invalid key must compare higher or equal to any other -// element. -// -// Use cases and performance considerations: -// Our use cases present two specificities that allow us to design this -// structure to provide fast insertion *and* fast search and deletion -// operations: -// - Elements are (generally) inserted in order (sorted according to their key). -// - A key is available to mark elements as invalid (deleted). -// The backing `std::vector` allows for fast insertions. When -// searching for an element we ensure the elements are sorted (this is generally -// the case) and perform a binary search. When deleting an element we do not -// free the associated memory immediately. Instead, an element to be deleted is -// marked with the 'invalid' key. Other methods of the container take care of -// ignoring entries marked as invalid. -// To avoid the overhead of the `std::vector` container when only few entries -// are used, a number of elements are preallocated. - -// 'ElementType' and 'KeyType' are respectively the types of the elements and -// their key. The structure only reclaims memory when safe to do so, if the -// number of elements that can be reclaimed is greater than `RECLAIM_FROM` and -// greater than ` / RECLAIM_FACTOR. -#define TEMPLATE_INVALSET_P_DECL \ - class ElementType, \ - unsigned N_PREALLOCATED_ELEMENTS, \ - class KeyType, \ - KeyType INVALID_KEY, \ - size_t RECLAIM_FROM, \ - unsigned RECLAIM_FACTOR - -#define TEMPLATE_INVALSET_P_DEF \ -ElementType, N_PREALLOCATED_ELEMENTS, \ -KeyType, INVALID_KEY, RECLAIM_FROM, RECLAIM_FACTOR - -template class InvalSetIterator; // Forward declaration. - -template class InvalSet { - public: - InvalSet(); - ~InvalSet(); - - static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS; - static const KeyType kInvalidKey = INVALID_KEY; - - // It is illegal to insert an element already present in the set. - void insert(const ElementType& element); - - // Looks for the specified element in the set and - if found - deletes it. - void erase(const ElementType& element); - - // This indicates the number of (valid) elements stored in this set. - size_t size() const; - - // Returns true if no elements are stored in the set. - // Note that this does not mean the the backing storage is empty: it can still - // contain invalid elements. - bool empty() const; - - void clear(); - - const ElementType min_element(); - - // This returns the key of the minimum element in the set. - KeyType min_element_key(); - - static bool IsValid(const ElementType& element); - static KeyType Key(const ElementType& element); - static void SetKey(ElementType* element, KeyType key); - - protected: - // Returns a pointer to the element in vector_ if it was found, or NULL - // otherwise. - ElementType* Search(const ElementType& element); - - // The argument *must* point to an element stored in *this* set. - // This function is not allowed to move elements in the backing vector - // storage. - void EraseInternal(ElementType* element); - - // The elements in the range searched must be sorted. - ElementType* BinarySearch(const ElementType& element, - ElementType* start, - ElementType* end) const; - - // Sort the elements. - enum SortType { - // The 'hard' version guarantees that invalid elements are moved to the end - // of the container. - kHardSort, - // The 'soft' version only guarantees that the elements will be sorted. - // Invalid elements may still be present anywhere in the set. - kSoftSort - }; - void Sort(SortType sort_type); - - // Delete the elements that have an invalid key. The complexity is linear - // with the size of the vector. - void Clean(); - - const ElementType Front() const; - const ElementType Back() const; - - // Delete invalid trailing elements and return the last valid element in the - // set. - const ElementType CleanBack(); - - // Returns a pointer to the start or end of the backing storage. - const ElementType* StorageBegin() const; - const ElementType* StorageEnd() const; - ElementType* StorageBegin(); - ElementType* StorageEnd(); - - // Returns the index of the element within the backing storage. The element - // must belong to the backing storage. - size_t ElementIndex(const ElementType* element) const; - - // Returns the element at the specified index in the backing storage. - const ElementType* ElementAt(size_t index) const; - ElementType* ElementAt(size_t index); - - static const ElementType* FirstValidElement(const ElementType* from, - const ElementType* end); - - void CacheMinElement(); - const ElementType CachedMinElement() const; - - bool ShouldReclaimMemory() const; - void ReclaimMemory(); - - bool IsUsingVector() const { return vector_ != NULL; } - void set_sorted(bool sorted) { sorted_ = sorted; } - - // We cache some data commonly required by users to improve performance. - // We cannot cache pointers to elements as we do not control the backing - // storage. - bool valid_cached_min_; - size_t cached_min_index_; // Valid iff `valid_cached_min_` is true. - KeyType cached_min_key_; // Valid iff `valid_cached_min_` is true. - - // Indicates whether the elements are sorted. - bool sorted_; - - // This represents the number of (valid) elements in this set. - size_t size_; - - // The backing storage is either the array of preallocated elements or the - // vector. The structure starts by using the preallocated elements, and - // transitions (permanently) to using the vector once more than - // kNPreallocatedElements are used. - // Elements are only invalidated when using the vector. The preallocated - // storage always only contains valid elements. - ElementType preallocated_[kNPreallocatedElements]; - std::vector* vector_; - -#ifdef VIXL_DEBUG - // Iterators acquire and release this monitor. While a set is acquired, - // certain operations are illegal to ensure that the iterator will - // correctly iterate over the elements in the set. - int monitor_; - int monitor() const { return monitor_; } - void Acquire() { monitor_++; } - void Release() { - monitor_--; - VIXL_ASSERT(monitor_ >= 0); - } -#endif - - friend class InvalSetIterator >; - typedef ElementType _ElementType; - typedef KeyType _KeyType; -}; - - -template class InvalSetIterator { - private: - // Redefine types to mirror the associated set types. - typedef typename S::_ElementType ElementType; - typedef typename S::_KeyType KeyType; - - public: - explicit InvalSetIterator(S* inval_set); - ~InvalSetIterator(); - - ElementType* Current() const; - void Advance(); - bool Done() const; - - // Mark this iterator as 'done'. - void Finish(); - - // Delete the current element and advance the iterator to point to the next - // element. - void DeleteCurrentAndAdvance(); - - static bool IsValid(const ElementType& element); - static KeyType Key(const ElementType& element); - - protected: - void MoveToValidElement(); - - // Indicates if the iterator is looking at the vector or at the preallocated - // elements. - const bool using_vector_; - // Used when looking at the preallocated elements, or in debug mode when using - // the vector to track how many times the iterator has advanced. - size_t index_; - typename std::vector::iterator iterator_; - S* inval_set_; -}; - - -template -InvalSet::InvalSet() - : valid_cached_min_(false), - sorted_(true), size_(0), vector_(NULL) { -#ifdef VIXL_DEBUG - monitor_ = 0; -#endif -} - - -template -InvalSet::~InvalSet() { - VIXL_ASSERT(monitor_ == 0); - delete vector_; -} - - -template -void InvalSet::insert(const ElementType& element) { - VIXL_ASSERT(monitor() == 0); - VIXL_ASSERT(IsValid(element)); - VIXL_ASSERT(Search(element) == NULL); - set_sorted(empty() || (sorted_ && (element > CleanBack()))); - if (IsUsingVector()) { - vector_->push_back(element); - } else { - if (size_ < kNPreallocatedElements) { - preallocated_[size_] = element; - } else { - // Transition to using the vector. - vector_ = new std::vector(preallocated_, - preallocated_ + size_); - vector_->push_back(element); - } - } - size_++; - - if (valid_cached_min_ && (element < min_element())) { - cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1; - cached_min_key_ = Key(element); - valid_cached_min_ = true; - } - - if (ShouldReclaimMemory()) { - ReclaimMemory(); - } -} - - -template -void InvalSet::erase(const ElementType& element) { - VIXL_ASSERT(monitor() == 0); - VIXL_ASSERT(IsValid(element)); - ElementType* local_element = Search(element); - if (local_element != NULL) { - EraseInternal(local_element); - } -} - - -template -ElementType* InvalSet::Search( - const ElementType& element) { - VIXL_ASSERT(monitor() == 0); - if (empty()) { - return NULL; - } - if (ShouldReclaimMemory()) { - ReclaimMemory(); - } - if (!sorted_) { - Sort(kHardSort); - } - if (!valid_cached_min_) { - CacheMinElement(); - } - return BinarySearch(element, ElementAt(cached_min_index_), StorageEnd()); -} - - -template -size_t InvalSet::size() const { - return size_; -} - - -template -bool InvalSet::empty() const { - return size_ == 0; -} - - -template -void InvalSet::clear() { - VIXL_ASSERT(monitor() == 0); - size_ = 0; - if (IsUsingVector()) { - vector_->clear(); - } - set_sorted(true); - valid_cached_min_ = false; -} - - -template -const ElementType InvalSet::min_element() { - VIXL_ASSERT(monitor() == 0); - VIXL_ASSERT(!empty()); - CacheMinElement(); - return *ElementAt(cached_min_index_); -} - - -template -KeyType InvalSet::min_element_key() { - VIXL_ASSERT(monitor() == 0); - if (valid_cached_min_) { - return cached_min_key_; - } else { - return Key(min_element()); - } -} - - -template -bool InvalSet::IsValid(const ElementType& element) { - return Key(element) != kInvalidKey; -} - - -template -void InvalSet::EraseInternal(ElementType* element) { - // Note that this function must be safe even while an iterator has acquired - // this set. - VIXL_ASSERT(element != NULL); - size_t deleted_index = ElementIndex(element); - if (IsUsingVector()) { - VIXL_ASSERT((&(vector_->front()) <= element) && - (element <= &(vector_->back()))); - SetKey(element, kInvalidKey); - } else { - VIXL_ASSERT((preallocated_ <= element) && - (element < (preallocated_ + kNPreallocatedElements))); - ElementType* end = preallocated_ + kNPreallocatedElements; - size_t copy_size = sizeof(*element) * (end - element - 1); - memmove(element, element + 1, copy_size); - } - size_--; - - if (valid_cached_min_ && - (deleted_index == cached_min_index_)) { - if (sorted_ && !empty()) { - const ElementType* min = FirstValidElement(element, StorageEnd()); - cached_min_index_ = ElementIndex(min); - cached_min_key_ = Key(*min); - valid_cached_min_ = true; - } else { - valid_cached_min_ = false; - } - } -} - - -template -ElementType* InvalSet::BinarySearch( - const ElementType& element, ElementType* start, ElementType* end) const { - if (start == end) { - return NULL; - } - VIXL_ASSERT(sorted_); - VIXL_ASSERT(start < end); - VIXL_ASSERT(!empty()); - - // Perform a binary search through the elements while ignoring invalid - // elements. - ElementType* elements = start; - size_t low = 0; - size_t high = (end - start) - 1; - while (low < high) { - // Find valid bounds. - while (!IsValid(elements[low]) && (low < high)) ++low; - while (!IsValid(elements[high]) && (low < high)) --high; - VIXL_ASSERT(low <= high); - // Avoid overflow when computing the middle index. - size_t middle = low / 2 + high / 2 + (low & high & 1); - if ((middle == low) || (middle == high)) { - break; - } - while (!IsValid(elements[middle]) && (middle < high - 1)) ++middle; - while (!IsValid(elements[middle]) && (low + 1 < middle)) --middle; - if (!IsValid(elements[middle])) { - break; - } - if (elements[middle] < element) { - low = middle; - } else { - high = middle; - } - } - - if (elements[low] == element) return &elements[low]; - if (elements[high] == element) return &elements[high]; - return NULL; -} - - -template -void InvalSet::Sort(SortType sort_type) { - VIXL_ASSERT(monitor() == 0); - if (sort_type == kSoftSort) { - if (sorted_) { - return; - } - } - if (empty()) { - return; - } - - Clean(); - std::sort(StorageBegin(), StorageEnd()); - - set_sorted(true); - cached_min_index_ = 0; - cached_min_key_ = Key(Front()); - valid_cached_min_ = true; -} - - -template -void InvalSet::Clean() { - VIXL_ASSERT(monitor() == 0); - if (empty() || !IsUsingVector()) { - return; - } - // Manually iterate through the vector storage to discard invalid elements. - ElementType* start = &(vector_->front()); - ElementType* end = start + vector_->size(); - ElementType* c = start; - ElementType* first_invalid; - ElementType* first_valid; - ElementType* next_invalid; - - while (c < end && IsValid(*c)) { c++; } - first_invalid = c; - - while (c < end) { - while (c < end && !IsValid(*c)) { c++; } - first_valid = c; - while (c < end && IsValid(*c)) { c++; } - next_invalid = c; - - ptrdiff_t n_moved_elements = (next_invalid - first_valid); - memmove(first_invalid, first_valid, n_moved_elements * sizeof(*c)); - first_invalid = first_invalid + n_moved_elements; - c = next_invalid; - } - - // Delete the trailing invalid elements. - vector_->erase(vector_->begin() + (first_invalid - start), vector_->end()); - VIXL_ASSERT(vector_->size() == size_); - - if (sorted_) { - valid_cached_min_ = true; - cached_min_index_ = 0; - cached_min_key_ = Key(*ElementAt(0)); - } else { - valid_cached_min_ = false; - } -} - - -template -const ElementType InvalSet::Front() const { - VIXL_ASSERT(!empty()); - return IsUsingVector() ? vector_->front() : preallocated_[0]; -} - - -template -const ElementType InvalSet::Back() const { - VIXL_ASSERT(!empty()); - return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1]; -} - - -template -const ElementType InvalSet::CleanBack() { - VIXL_ASSERT(monitor() == 0); - if (IsUsingVector()) { - // Delete the invalid trailing elements. - typename std::vector::reverse_iterator it = vector_->rbegin(); - while (!IsValid(*it)) { - it++; - } - vector_->erase(it.base(), vector_->end()); - } - return Back(); -} - - -template -const ElementType* InvalSet::StorageBegin() const { - return IsUsingVector() ? &(vector_->front()) : preallocated_; -} - - -template -const ElementType* InvalSet::StorageEnd() const { - return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; -} - - -template -ElementType* InvalSet::StorageBegin() { - return IsUsingVector() ? &(vector_->front()) : preallocated_; -} - - -template -ElementType* InvalSet::StorageEnd() { - return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; -} - - -template -size_t InvalSet::ElementIndex( - const ElementType* element) const { - VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd())); - return element - StorageBegin(); -} - - -template -const ElementType* InvalSet::ElementAt( - size_t index) const { - VIXL_ASSERT( - (IsUsingVector() && (index < vector_->size())) || (index < size_)); - return StorageBegin() + index; -} - -template -ElementType* InvalSet::ElementAt(size_t index) { - VIXL_ASSERT( - (IsUsingVector() && (index < vector_->size())) || (index < size_)); - return StorageBegin() + index; -} - -template -const ElementType* InvalSet::FirstValidElement( - const ElementType* from, const ElementType* end) { - while ((from < end) && !IsValid(*from)) { - from++; - } - return from; -} - - -template -void InvalSet::CacheMinElement() { - VIXL_ASSERT(monitor() == 0); - VIXL_ASSERT(!empty()); - - if (valid_cached_min_) { - return; - } - - if (sorted_) { - const ElementType* min = FirstValidElement(StorageBegin(), StorageEnd()); - cached_min_index_ = ElementIndex(min); - cached_min_key_ = Key(*min); - valid_cached_min_ = true; - } else { - Sort(kHardSort); - } - VIXL_ASSERT(valid_cached_min_); -} - - -template -bool InvalSet::ShouldReclaimMemory() const { - if (!IsUsingVector()) { - return false; - } - size_t n_invalid_elements = vector_->size() - size_; - return (n_invalid_elements > RECLAIM_FROM) && - (n_invalid_elements > vector_->size() / RECLAIM_FACTOR); -} - - -template -void InvalSet::ReclaimMemory() { - VIXL_ASSERT(monitor() == 0); - Clean(); -} - - -template -InvalSetIterator::InvalSetIterator(S* inval_set) - : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()), - index_(0), - inval_set_(inval_set) { - if (inval_set != NULL) { - inval_set->Sort(S::kSoftSort); -#ifdef VIXL_DEBUG - inval_set->Acquire(); -#endif - if (using_vector_) { - iterator_ = typename std::vector::iterator( - inval_set_->vector_->begin()); - } - MoveToValidElement(); - } -} - - -template -InvalSetIterator::~InvalSetIterator() { -#ifdef VIXL_DEBUG - if (inval_set_ != NULL) { - inval_set_->Release(); - } -#endif -} - - -template -typename S::_ElementType* InvalSetIterator::Current() const { - VIXL_ASSERT(!Done()); - if (using_vector_) { - return &(*iterator_); - } else { - return &(inval_set_->preallocated_[index_]); - } -} - - -template -void InvalSetIterator::Advance() { - VIXL_ASSERT(!Done()); - if (using_vector_) { - iterator_++; -#ifdef VIXL_DEBUG - index_++; -#endif - MoveToValidElement(); - } else { - index_++; - } -} - - -template -bool InvalSetIterator::Done() const { - if (using_vector_) { - bool done = (iterator_ == inval_set_->vector_->end()); - VIXL_ASSERT(done == (index_ == inval_set_->size())); - return done; - } else { - return index_ == inval_set_->size(); - } -} - - -template -void InvalSetIterator::Finish() { - VIXL_ASSERT(inval_set_->sorted_); - if (using_vector_) { - iterator_ = inval_set_->vector_->end(); - } - index_ = inval_set_->size(); -} - - -template -void InvalSetIterator::DeleteCurrentAndAdvance() { - if (using_vector_) { - inval_set_->EraseInternal(&(*iterator_)); - MoveToValidElement(); - } else { - inval_set_->EraseInternal(inval_set_->preallocated_ + index_); - } -} - - -template -bool InvalSetIterator::IsValid(const ElementType& element) { - return S::IsValid(element); -} - - -template -typename S::_KeyType InvalSetIterator::Key(const ElementType& element) { - return S::Key(element); -} - - -template -void InvalSetIterator::MoveToValidElement() { - if (using_vector_) { - while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) { - iterator_++; - } - } else { - VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0])); - // Nothing to do. - } -} - -#undef TEMPLATE_INVALSET_P_DECL -#undef TEMPLATE_INVALSET_P_DEF - -} // namespace vixl - -#endif // VIXL_INVALSET_H_ diff --git a/disas/libvixl/vixl/platform.h b/disas/libvixl/vixl/platform.h deleted file mode 100644 index 26a74de81bbd..000000000000 --- a/disas/libvixl/vixl/platform.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef PLATFORM_H -#define PLATFORM_H - -// Define platform specific functionalities. -extern "C" { -#include -} - -namespace vixl { -inline void HostBreakpoint() { raise(SIGINT); } -} // namespace vixl - -#endif diff --git a/disas/libvixl/vixl/utils.cc b/disas/libvixl/vixl/utils.cc deleted file mode 100644 index 69304d266d7e..000000000000 --- a/disas/libvixl/vixl/utils.cc +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "vixl/utils.h" -#include - -namespace vixl { - -uint32_t float_to_rawbits(float value) { - uint32_t bits = 0; - memcpy(&bits, &value, 4); - return bits; -} - - -uint64_t double_to_rawbits(double value) { - uint64_t bits = 0; - memcpy(&bits, &value, 8); - return bits; -} - - -float rawbits_to_float(uint32_t bits) { - float value = 0.0; - memcpy(&value, &bits, 4); - return value; -} - - -double rawbits_to_double(uint64_t bits) { - double value = 0.0; - memcpy(&value, &bits, 8); - return value; -} - - -uint32_t float_sign(float val) { - uint32_t rawbits = float_to_rawbits(val); - return unsigned_bitextract_32(31, 31, rawbits); -} - - -uint32_t float_exp(float val) { - uint32_t rawbits = float_to_rawbits(val); - return unsigned_bitextract_32(30, 23, rawbits); -} - - -uint32_t float_mantissa(float val) { - uint32_t rawbits = float_to_rawbits(val); - return unsigned_bitextract_32(22, 0, rawbits); -} - - -uint32_t double_sign(double val) { - uint64_t rawbits = double_to_rawbits(val); - return static_cast(unsigned_bitextract_64(63, 63, rawbits)); -} - - -uint32_t double_exp(double val) { - uint64_t rawbits = double_to_rawbits(val); - return static_cast(unsigned_bitextract_64(62, 52, rawbits)); -} - - -uint64_t double_mantissa(double val) { - uint64_t rawbits = double_to_rawbits(val); - return unsigned_bitextract_64(51, 0, rawbits); -} - - -float float_pack(uint32_t sign, uint32_t exp, uint32_t mantissa) { - uint32_t bits = (sign << 31) | (exp << 23) | mantissa; - return rawbits_to_float(bits); -} - - -double double_pack(uint64_t sign, uint64_t exp, uint64_t mantissa) { - uint64_t bits = (sign << 63) | (exp << 52) | mantissa; - return rawbits_to_double(bits); -} - - -int float16classify(float16 value) { - uint16_t exponent_max = (1 << 5) - 1; - uint16_t exponent_mask = exponent_max << 10; - uint16_t mantissa_mask = (1 << 10) - 1; - - uint16_t exponent = (value & exponent_mask) >> 10; - uint16_t mantissa = value & mantissa_mask; - if (exponent == 0) { - if (mantissa == 0) { - return FP_ZERO; - } - return FP_SUBNORMAL; - } else if (exponent == exponent_max) { - if (mantissa == 0) { - return FP_INFINITE; - } - return FP_NAN; - } - return FP_NORMAL; -} - - -unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size) { - VIXL_ASSERT((reg_size % 8) == 0); - int count = 0; - for (unsigned i = 0; i < (reg_size / 16); i++) { - if ((imm & 0xffff) == 0) { - count++; - } - imm >>= 16; - } - return count; -} - -} // namespace vixl diff --git a/disas/libvixl/vixl/utils.h b/disas/libvixl/vixl/utils.h deleted file mode 100644 index ecb0f1014ab2..000000000000 --- a/disas/libvixl/vixl/utils.h +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2015, ARM Limited -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of ARM Limited nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef VIXL_UTILS_H -#define VIXL_UTILS_H - -#include -#include -#include "vixl/globals.h" -#include "vixl/compiler-intrinsics.h" - -namespace vixl { - -// Macros for compile-time format checking. -#if GCC_VERSION_OR_NEWER(4, 4, 0) -#define PRINTF_CHECK(format_index, varargs_index) \ - __attribute__((format(gnu_printf, format_index, varargs_index))) -#else -#define PRINTF_CHECK(format_index, varargs_index) -#endif - -// Check number width. -inline bool is_intn(unsigned n, int64_t x) { - VIXL_ASSERT((0 < n) && (n < 64)); - int64_t limit = INT64_C(1) << (n - 1); - return (-limit <= x) && (x < limit); -} - -inline bool is_uintn(unsigned n, int64_t x) { - VIXL_ASSERT((0 < n) && (n < 64)); - return !(x >> n); -} - -inline uint32_t truncate_to_intn(unsigned n, int64_t x) { - VIXL_ASSERT((0 < n) && (n < 64)); - return static_cast(x & ((INT64_C(1) << n) - 1)); -} - -#define INT_1_TO_63_LIST(V) \ -V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \ -V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \ -V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \ -V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32) \ -V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \ -V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \ -V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \ -V(57) V(58) V(59) V(60) V(61) V(62) V(63) - -#define DECLARE_IS_INT_N(N) \ -inline bool is_int##N(int64_t x) { return is_intn(N, x); } -#define DECLARE_IS_UINT_N(N) \ -inline bool is_uint##N(int64_t x) { return is_uintn(N, x); } -#define DECLARE_TRUNCATE_TO_INT_N(N) \ -inline uint32_t truncate_to_int##N(int x) { return truncate_to_intn(N, x); } -INT_1_TO_63_LIST(DECLARE_IS_INT_N) -INT_1_TO_63_LIST(DECLARE_IS_UINT_N) -INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N) -#undef DECLARE_IS_INT_N -#undef DECLARE_IS_UINT_N -#undef DECLARE_TRUNCATE_TO_INT_N - -// Bit field extraction. -inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) { - return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1); -} - -inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) { - return (x >> lsb) & ((static_cast(1) << (1 + msb - lsb)) - 1); -} - -inline int32_t signed_bitextract_32(int msb, int lsb, int32_t x) { - return (x << (31 - msb)) >> (lsb + 31 - msb); -} - -inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) { - return (x << (63 - msb)) >> (lsb + 63 - msb); -} - -// Floating point representation. -uint32_t float_to_rawbits(float value); -uint64_t double_to_rawbits(double value); -float rawbits_to_float(uint32_t bits); -double rawbits_to_double(uint64_t bits); - -uint32_t float_sign(float val); -uint32_t float_exp(float val); -uint32_t float_mantissa(float val); -uint32_t double_sign(double val); -uint32_t double_exp(double val); -uint64_t double_mantissa(double val); - -float float_pack(uint32_t sign, uint32_t exp, uint32_t mantissa); -double double_pack(uint64_t sign, uint64_t exp, uint64_t mantissa); - -// An fpclassify() function for 16-bit half-precision floats. -int float16classify(float16 value); - -// NaN tests. -inline bool IsSignallingNaN(double num) { - const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); - uint64_t raw = double_to_rawbits(num); - if (std::isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) { - return true; - } - return false; -} - - -inline bool IsSignallingNaN(float num) { - const uint32_t kFP32QuietNaNMask = 0x00400000; - uint32_t raw = float_to_rawbits(num); - if (std::isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) { - return true; - } - return false; -} - - -inline bool IsSignallingNaN(float16 num) { - const uint16_t kFP16QuietNaNMask = 0x0200; - return (float16classify(num) == FP_NAN) && - ((num & kFP16QuietNaNMask) == 0); -} - - -template -inline bool IsQuietNaN(T num) { - return std::isnan(num) && !IsSignallingNaN(num); -} - - -// Convert the NaN in 'num' to a quiet NaN. -inline double ToQuietNaN(double num) { - const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); - VIXL_ASSERT(std::isnan(num)); - return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask); -} - - -inline float ToQuietNaN(float num) { - const uint32_t kFP32QuietNaNMask = 0x00400000; - VIXL_ASSERT(std::isnan(num)); - return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask); -} - - -// Fused multiply-add. -inline double FusedMultiplyAdd(double op1, double op2, double a) { - return fma(op1, op2, a); -} - - -inline float FusedMultiplyAdd(float op1, float op2, float a) { - return fmaf(op1, op2, a); -} - - -inline uint64_t LowestSetBit(uint64_t value) { - return value & -value; -} - - -template -inline int HighestSetBitPosition(T value) { - VIXL_ASSERT(value != 0); - return (sizeof(value) * 8 - 1) - CountLeadingZeros(value); -} - - -template -inline int WhichPowerOf2(V value) { - VIXL_ASSERT(IsPowerOf2(value)); - return CountTrailingZeros(value); -} - - -unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size); - - -template -T ReverseBits(T value) { - VIXL_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) || - (sizeof(value) == 4) || (sizeof(value) == 8)); - T result = 0; - for (unsigned i = 0; i < (sizeof(value) * 8); i++) { - result = (result << 1) | (value & 1); - value >>= 1; - } - return result; -} - - -template -T ReverseBytes(T value, int block_bytes_log2) { - VIXL_ASSERT((sizeof(value) == 4) || (sizeof(value) == 8)); - VIXL_ASSERT((1U << block_bytes_log2) <= sizeof(value)); - // Split the 64-bit value into an 8-bit array, where b[0] is the least - // significant byte, and b[7] is the most significant. - uint8_t bytes[8]; - uint64_t mask = UINT64_C(0xff00000000000000); - for (int i = 7; i >= 0; i--) { - bytes[i] = (static_cast(value) & mask) >> (i * 8); - mask >>= 8; - } - - // Permutation tables for REV instructions. - // permute_table[0] is used by REV16_x, REV16_w - // permute_table[1] is used by REV32_x, REV_w - // permute_table[2] is used by REV_x - VIXL_ASSERT((0 < block_bytes_log2) && (block_bytes_log2 < 4)); - static const uint8_t permute_table[3][8] = { {6, 7, 4, 5, 2, 3, 0, 1}, - {4, 5, 6, 7, 0, 1, 2, 3}, - {0, 1, 2, 3, 4, 5, 6, 7} }; - T result = 0; - for (int i = 0; i < 8; i++) { - result <<= 8; - result |= bytes[permute_table[block_bytes_log2 - 1][i]]; - } - return result; -} - - -// Pointer alignment -// TODO: rename/refactor to make it specific to instructions. -template -bool IsWordAligned(T pointer) { - VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof) - return ((intptr_t)(pointer) & 3) == 0; -} - -// Increment a pointer (up to 64 bits) until it has the specified alignment. -template -T AlignUp(T pointer, size_t alignment) { - // Use C-style casts to get static_cast behaviour for integral types (T), and - // reinterpret_cast behaviour for other types. - - uint64_t pointer_raw = (uint64_t)pointer; - VIXL_STATIC_ASSERT(sizeof(pointer) <= sizeof(pointer_raw)); - - size_t align_step = (alignment - pointer_raw) % alignment; - VIXL_ASSERT((pointer_raw + align_step) % alignment == 0); - - return (T)(pointer_raw + align_step); -} - -// Decrement a pointer (up to 64 bits) until it has the specified alignment. -template -T AlignDown(T pointer, size_t alignment) { - // Use C-style casts to get static_cast behaviour for integral types (T), and - // reinterpret_cast behaviour for other types. - - uint64_t pointer_raw = (uint64_t)pointer; - VIXL_STATIC_ASSERT(sizeof(pointer) <= sizeof(pointer_raw)); - - size_t align_step = pointer_raw % alignment; - VIXL_ASSERT((pointer_raw - align_step) % alignment == 0); - - return (T)(pointer_raw - align_step); -} - -} // namespace vixl - -#endif // VIXL_UTILS_H diff --git a/disas/meson.build b/disas/meson.build index 449f99e1de63..1977f5cd92ef 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -1,22 +1,13 @@ -libvixl_ss = ss.source_set() -subdir('libvixl') - common_ss.add(when: 'CONFIG_ALPHA_DIS', if_true: files('alpha.c')) -common_ss.add(when: 'CONFIG_ARM_A64_DIS', if_true: files('arm-a64.cc')) -common_ss.add_all(when: 'CONFIG_ARM_A64_DIS', if_true: libvixl_ss) -common_ss.add(when: 'CONFIG_ARM_DIS', if_true: files('arm.c')) common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c')) common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) -common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) -common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp')) +common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.c')) common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) -common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c')) common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files('riscv.c')) -common_ss.add(when: 'CONFIG_S390_DIS', if_true: files('s390.c')) common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c')) diff --git a/disas/mips.c b/disas/mips.c index b9a520430411..5aacacb2c8f1 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -20,6 +20,7 @@ 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/bitops.h" #include "disas/dis-asm.h" /* mips.h. Mips opcode list for GDB, the GNU debugger. @@ -1334,9 +1335,9 @@ const struct mips_opcode mips_builtin_opcodes[] = {"balc", "+p", 0xe8000000, 0xfc000000, UBD|WR_31, 0, I32R6}, {"bc", "+p", 0xc8000000, 0xfc000000, UBD|WR_31, 0, I32R6}, {"jic", "t,o", 0xd8000000, 0xffe00000, UBD|RD_t, 0, I32R6}, -{"beqzc", "s,+p", 0xd8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, +{"beqzc", "s,+q", 0xd8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, {"jialc", "t,o", 0xf8000000, 0xffe00000, UBD|RD_t, 0, I32R6}, -{"bnezc", "s,+p", 0xf8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, +{"bnezc", "s,+q", 0xf8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, {"beqzalc", "s,t,p", 0x20000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, {"bovc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, {"beqc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, @@ -4462,6 +4463,13 @@ print_insn_args (const char *d, (*info->print_address_func) (info->target, info); break; + case 'q': + /* Sign extend the displacement with 21 bits. */ + delta = sextract32(l, OP_SH_DELTA, 21); + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + case 't': /* Coprocessor 0 reg name */ (*info->fprintf_func) (info->stream, "%s", mips_cp0_names[(l >> OP_SH_RT) & diff --git a/disas/nanomips.c b/disas/nanomips.c new file mode 100644 index 000000000000..a0253598dd65 --- /dev/null +++ b/disas/nanomips.c @@ -0,0 +1,21990 @@ +/* + * Source file for nanoMIPS disassembler component of QEMU + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Matthew Fortune + * Copyright (C) 2018 Aleksandar Markovic + * + * 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 . + * + */ + +/* + * Documentation used while implementing this component: + * + * [1] "MIPS® Architecture Base: nanoMIPS32(tm) Instruction Set Technical + * Reference Manual", Revision 01.01, April 27, 2018 + */ + +#include "qemu/osdep.h" +#include "disas/dis-asm.h" + +typedef int64_t int64; +typedef uint64_t uint64; +typedef uint32_t uint32; +typedef uint16_t uint16; +typedef uint64_t img_address; + +typedef enum { + instruction, + call_instruction, + branch_instruction, + return_instruction, + reserved_block, + pool, +} TABLE_ENTRY_TYPE; + +typedef enum { + MIPS64_ = 0x00000001, + XNP_ = 0x00000002, + XMMS_ = 0x00000004, + EVA_ = 0x00000008, + DSP_ = 0x00000010, + MT_ = 0x00000020, + EJTAG_ = 0x00000040, + TLBINV_ = 0x00000080, + CP0_ = 0x00000100, + CP1_ = 0x00000200, + CP2_ = 0x00000400, + UDI_ = 0x00000800, + MCU_ = 0x00001000, + VZ_ = 0x00002000, + TLB_ = 0x00004000, + MVH_ = 0x00008000, + ALL_ATTRIBUTES = 0xffffffffull, +} TABLE_ATTRIBUTE_TYPE; + +typedef struct Dis_info { + img_address m_pc; + fprintf_function fprintf_func; + FILE *stream; + sigjmp_buf buf; +} Dis_info; + +typedef bool (*conditional_function)(uint64 instruction); +typedef char * (*disassembly_function)(uint64 instruction, + Dis_info *info); + +typedef struct Pool { + TABLE_ENTRY_TYPE type; + const struct Pool *next_table; + int next_table_size; + int instructions_size; + uint64 mask; + uint64 value; + disassembly_function disassembly; + conditional_function condition; + uint64 attributes; +} Pool; + +#define IMGASSERTONCE(test) + + +static char * G_GNUC_PRINTF(1, 2) img_format(const char *format, ...) +{ + char *buffer; + va_list args; + va_start(args, format); + buffer = g_strdup_vprintf(format, args); + va_end(args); + return buffer; +} + + +static char *to_string(img_address a) +{ + return g_strdup_printf("0x%" PRIx64, a); +} + + +static uint64 extract_bits(uint64 data, uint32 bit_offset, uint32 bit_size) +{ + return (data << (64 - (bit_size + bit_offset))) >> (64 - bit_size); +} + + +static int64 sign_extend(int64 data, int msb) +{ + uint64 shift = 63 - msb; + return (data << shift) >> shift; +} + + +static uint64 renumber_registers(uint64 index, uint64 *register_list, + size_t register_list_size, Dis_info *info) +{ + if (index < register_list_size) { + return register_list[index]; + } + + info->fprintf_func(info->stream, "Invalid register mapping index %" PRIu64 + ", size of list = %zu", index, register_list_size); + siglongjmp(info->buf, 1); +} + + +/* + * decode_gpr_gpr4() - decoder for 'gpr4' gpr encoding type + * + * Map a 4-bit code to the 5-bit register space according to this pattern: + * + * 1 0 + * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * | | | | | | | | | | | | | | | | + * | | | | | | | | | | | | | | | | + * | | | | | | | | | | | └---------------┐ + * | | | | | | | | | | └---------------┐ | + * | | | | | | | | | └---------------┐ | | + * | | | | | | | | └---------------┐ | | | + * | | | | | | | | | | | | | | | | + * | | | | | | | | | | | | | | | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * Used in handling following instructions: + * + * - ADDU[4X4] + * - LW[4X4] + * - MOVEP[REV] + * - MUL[4X4] + * - SW[4X4] + */ +static uint64 decode_gpr_gpr4(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 8, 9, 10, 11, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +/* + * decode_gpr_gpr4_zero() - decoder for 'gpr4.zero' gpr encoding type + * + * Map a 4-bit code to the 5-bit register space according to this pattern: + * + * 1 0 + * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * | | | | | | | | | | | | | | | | + * | | | | | | | | | | | | └---------------------┐ + * | | | | | | | | | | | └---------------┐ | + * | | | | | | | | | | └---------------┐ | | + * | | | | | | | | | └---------------┐ | | | + * | | | | | | | | └---------------┐ | | | | + * | | | | | | | | | | | | | | | | + * | | | | | | | | | | | | | | | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * This pattern is the same one used for 'gpr4' gpr encoding type, except for + * the input value 3, that is mapped to the output value 0 instead of 11. + * + * Used in handling following instructions: + * + * - MOVE.BALC + * - MOVEP + * - SW[4X4] + */ +static uint64 decode_gpr_gpr4_zero(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 8, 9, 10, 0, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +/* + * decode_gpr_gpr3() - decoder for 'gpr3' gpr encoding type + * + * Map a 3-bit code to the 5-bit register space according to this pattern: + * + * 7 6 5 4 3 2 1 0 + * | | | | | | | | + * | | | | | | | | + * | | | └-----------------------┐ + * | | └-----------------------┐ | + * | └-----------------------┐ | | + * └-----------------------┐ | | | + * | | | | | | | | + * ┌-------┘ | | | | | | | + * | ┌-------┘ | | | | | | + * | | ┌-------┘ | | | | | + * | | | ┌-------┘ | | | | + * | | | | | | | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * Used in handling following instructions: + * + * - ADDIU[R1.SP] + * - ADDIU[R2] + * - ADDU[16] + * - AND[16] + * - ANDI[16] + * - BEQC[16] + * - BEQZC[16] + * - BNEC[16] + * - BNEZC[16] + * - LB[16] + * - LBU[16] + * - LH[16] + * - LHU[16] + * - LI[16] + * - LW[16] + * - LW[GP16] + * - LWXS[16] + * - NOT[16] + * - OR[16] + * - SB[16] + * - SH[16] + * - SLL[16] + * - SRL[16] + * - SUBU[16] + * - SW[16] + * - XOR[16] + */ +static uint64 decode_gpr_gpr3(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 16, 17, 18, 19, 4, 5, 6, 7 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +/* + * decode_gpr_gpr3_src_store() - decoder for 'gpr3.src.store' gpr encoding + * type + * + * Map a 3-bit code to the 5-bit register space according to this pattern: + * + * 7 6 5 4 3 2 1 0 + * | | | | | | | | + * | | | | | | | └-----------------------┐ + * | | | └-----------------------┐ | + * | | └-----------------------┐ | | + * | └-----------------------┐ | | | + * └-----------------------┐ | | | | + * | | | | | | | | + * ┌-------┘ | | | | | | | + * | ┌-------┘ | | | | | | + * | | ┌-------┘ | | | | | + * | | | | | | | | + * | | | | | | | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * This pattern is the same one used for 'gpr3' gpr encoding type, except for + * the input value 0, that is mapped to the output value 0 instead of 16. + * + * Used in handling following instructions: + * + * - SB[16] + * - SH[16] + * - SW[16] + * - SW[GP16] + */ +static uint64 decode_gpr_gpr3_src_store(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 0, 17, 18, 19, 4, 5, 6, 7 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +/* + * decode_gpr_gpr2_reg1() - decoder for 'gpr2.reg1' gpr encoding type + * + * Map a 2-bit code to the 5-bit register space according to this pattern: + * + * 3 2 1 0 + * | | | | + * | | | | + * | | | └-------------------┐ + * | | └-------------------┐ | + * | └-------------------┐ | | + * └-------------------┐ | | | + * | | | | + * | | | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * Used in handling following instructions: + * + * - MOVEP + * - MOVEP[REV] + */ +static uint64 decode_gpr_gpr2_reg1(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 4, 5, 6, 7 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +/* + * decode_gpr_gpr2_reg2() - decoder for 'gpr2.reg2' gpr encoding type + * + * Map a 2-bit code to the 5-bit register space according to this pattern: + * + * 3 2 1 0 + * | | | | + * | | | | + * | | | └-----------------┐ + * | | └-----------------┐ | + * | └-----------------┐ | | + * └-----------------┐ | | | + * | | | | + * | | | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * Used in handling following instructions: + * + * - MOVEP + * - MOVEP[REV] + */ +static uint64 decode_gpr_gpr2_reg2(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 5, 6, 7, 8 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +/* + * decode_gpr_gpr1() - decoder for 'gpr1' gpr encoding type + * + * Map a 1-bit code to the 5-bit register space according to this pattern: + * + * 1 0 + * | | + * | | + * | └---------------------┐ + * └---------------------┐ | + * | | + * | | + * | | + * | | + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * 3 2 1 0 + * + * Used in handling following instruction: + * + * - MOVE.BALC + */ +static uint64 decode_gpr_gpr1(uint64 d, Dis_info *info) +{ + static uint64 register_list[] = { 4, 5 }; + return renumber_registers(d, register_list, + sizeof(register_list) / sizeof(register_list[0]), info); +} + + +static int64 neg_copy(uint64 d) +{ + return 0ll - d; +} + + +static uint64 encode_count3_from_count(uint64 d) +{ + IMGASSERTONCE(d < 8); + return d == 0ull ? 8ull : d; +} + + +static uint64 encode_shift3_from_shift(uint64 d) +{ + IMGASSERTONCE(d < 8); + return d == 0ull ? 8ull : d; +} + + +/* special value for load literal */ +static int64 encode_eu_from_s_li16(uint64 d) +{ + IMGASSERTONCE(d < 128); + return d == 127 ? -1 : (int64)d; +} + + +static uint64 encode_msbd_from_size(uint64 d) +{ + IMGASSERTONCE(d < 32); + return d + 1; +} + + +static uint64 encode_eu_from_u_andi16(uint64 d) +{ + IMGASSERTONCE(d < 16); + if (d == 12) { + return 0x00ffull; + } + if (d == 13) { + return 0xffffull; + } + return d; +} + + +/* save16 / restore16 ???? */ +static uint64 encode_rt1_from_rt(uint64 d) +{ + return d ? 31 : 30; +} + + +static const char *GPR(uint64 reg, Dis_info *info) +{ + static const char *gpr_reg[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "r12", "r13", "r14", "r15", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "r24", "r25", "k0", "k1", "gp", "sp", "fp", "ra" + }; + + if (reg < 32) { + return gpr_reg[reg]; + } + + info->fprintf_func(info->stream, "Invalid GPR register index %" PRIu64, + reg); + siglongjmp(info->buf, 1); +} + + +static char *save_restore_list(uint64 rt, uint64 count, uint64 gp, + Dis_info *info) +{ + char *reg_list[34]; + reg_list[0] = (char *)""; + + assert(count <= 32); + for (uint64 counter = 0; counter != count; counter++) { + bool use_gp = gp && (counter == count - 1); + uint64 this_rt = use_gp ? 28 : ((rt & 0x10) | (rt + counter)) & 0x1f; + /* glib usage below requires casting away const */ + reg_list[counter + 1] = (char *)GPR(this_rt, info); + } + reg_list[count + 1] = NULL; + + return g_strjoinv(",", reg_list); +} + + +static const char *FPR(uint64 reg, Dis_info *info) +{ + static const char *fpr_reg[32] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }; + + if (reg < 32) { + return fpr_reg[reg]; + } + + info->fprintf_func(info->stream, "Invalid FPR register index %" PRIu64, + reg); + siglongjmp(info->buf, 1); +} + + +static const char *AC(uint64 reg, Dis_info *info) +{ + static const char *ac_reg[4] = { + "ac0", "ac1", "ac2", "ac3" + }; + + if (reg < 4) { + return ac_reg[reg]; + } + + info->fprintf_func(info->stream, "Invalid AC register index %" PRIu64, + reg); + siglongjmp(info->buf, 1); +} + + +static char *ADDRESS(uint64 value, int instruction_size, Dis_info *info) +{ + /* token for string replace */ + img_address address = info->m_pc + value + instruction_size; + /* symbol replacement */ + return to_string(address); +} + + +static uint64 extract_op_code_value(const uint16 *data, int size) +{ + switch (size) { + case 16: + return data[0]; + case 32: + return ((uint64)data[0] << 16) | data[1]; + case 48: + return ((uint64)data[0] << 32) | ((uint64)data[1] << 16) | data[2]; + default: + return data[0]; + } +} + + +/* + * Recurse through tables until the instruction is found then return + * the string and size + * + * inputs: + * pointer to a word stream, + * disassember table and size + * returns: + * instruction size - negative is error + * disassembly string - on error will constain error string + */ +static int Disassemble(const uint16 *data, char **dis, + TABLE_ENTRY_TYPE *type, const Pool *table, + int table_size, Dis_info *info) +{ + for (int i = 0; i < table_size; i++) { + uint64 op_code = extract_op_code_value(data, + table[i].instructions_size); + if ((op_code & table[i].mask) == table[i].value) { + /* possible match */ + conditional_function cond = table[i].condition; + if ((cond == NULL) || cond(op_code)) { + if (table[i].type == pool) { + return Disassemble(data, dis, type, + table[i].next_table, + table[i].next_table_size, + info); + } else if ((table[i].type == instruction) || + (table[i].type == call_instruction) || + (table[i].type == branch_instruction) || + (table[i].type == return_instruction)) { + disassembly_function dis_fn = table[i].disassembly; + if (dis_fn == 0) { + *dis = g_strdup( + "disassembler failure - bad table entry"); + return -6; + } + *type = table[i].type; + *dis = dis_fn(op_code, info); + return table[i].instructions_size; + } else { + *dis = g_strdup("reserved instruction"); + return -2; + } + } + } + } + *dis = g_strdup("failed to disassemble"); + return -1; /* failed to disassemble */ +} + + +static uint64 extract_code_18_to_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 19); + return value; +} + + +static uint64 extract_shift3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 3); + return value; +} + + +static uint64 extract_u_11_10_9_8_7_6_5_4_3__s3(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 9) << 3; + return value; +} + + +static uint64 extract_count_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 4); + return value; +} + + +static uint64 extract_rtz3_9_8_7(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 7, 3); + return value; +} + + +static uint64 extract_u_17_to_1__s1(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 1, 17) << 1; + return value; +} + + +static int64 extract_s__se9_20_19_18_17_16_15_14_13_12_11(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 11, 10); + value = sign_extend(value, 9); + return value; +} + + +static int64 extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 11; + value |= extract_bits(instruction, 1, 10) << 1; + value = sign_extend(value, 11); + return value; +} + + +static uint64 extract_u_10(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 10, 1); + return value; +} + + +static uint64 extract_rtz4_27_26_25_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 3); + value |= extract_bits(instruction, 25, 1) << 3; + return value; +} + + +static uint64 extract_sa_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 5); + return value; +} + + +static uint64 extract_shift_4_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 5); + return value; +} + + +static uint64 extract_shiftx_10_9_8_7__s1(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 7, 4) << 1; + return value; +} + + +static uint64 extract_hint_25_24_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 5); + return value; +} + + +static uint64 extract_count3_14_13_12(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 12, 3); + return value; +} + + +static int64 extract_s__se31_0_11_to_2_20_to_12_s12(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 31; + value |= extract_bits(instruction, 2, 10) << 21; + value |= extract_bits(instruction, 12, 9) << 12; + value = sign_extend(value, 31); + return value; +} + + +static int64 extract_s__se7_0_6_5_4_3_2_1_s1(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 7; + value |= extract_bits(instruction, 1, 6) << 1; + value = sign_extend(value, 7); + return value; +} + + +static uint64 extract_u2_10_9(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 9, 2); + return value; +} + + +static uint64 extract_code_25_24_23_22_21_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 10); + return value; +} + + +static uint64 extract_rs_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static uint64 extract_u_2_1__s1(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 1, 2) << 1; + return value; +} + + +static uint64 extract_stripe_6(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 6, 1); + return value; +} + + +static uint64 extract_ac_15_14(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 14, 2); + return value; +} + + +static uint64 extract_shift_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static uint64 extract_rdl_25_24(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 24, 1); + return value; +} + + +static int64 extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 10; + value |= extract_bits(instruction, 1, 9) << 1; + value = sign_extend(value, 10); + return value; +} + + +static uint64 extract_eu_6_5_4_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 7); + return value; +} + + +static uint64 extract_shift_5_4_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 6); + return value; +} + + +static uint64 extract_count_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 4); + return value; +} + + +static uint64 extract_code_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 3); + return value; +} + + +static uint64 extract_u_11_10_9_8_7_6_5_4_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 12); + return value; +} + + +static uint64 extract_rs_4_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 5); + return value; +} + + +static uint64 extract_u_20_to_3__s3(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 18) << 3; + return value; +} + + +static uint64 extract_u_3_2_1_0__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 4) << 2; + return value; +} + + +static uint64 extract_cofun_25_24_23(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 23); + return value; +} + + +static uint64 extract_u_2_1_0__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 3) << 2; + return value; +} + + +static uint64 extract_rd3_3_2_1(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 1, 3); + return value; +} + + +static uint64 extract_sa_15_14_13_12(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 12, 4); + return value; +} + + +static uint64 extract_rt_25_24_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 5); + return value; +} + + +static uint64 extract_ru_7_6_5_4_3(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 5); + return value; +} + + +static uint64 extract_u_17_to_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 18); + return value; +} + + +static uint64 extract_rsz4_4_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 3); + value |= extract_bits(instruction, 4, 1) << 3; + return value; +} + + +static int64 extract_s__se21_0_20_to_1_s1(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 21; + value |= extract_bits(instruction, 1, 20) << 1; + value = sign_extend(value, 21); + return value; +} + + +static uint64 extract_op_25_to_3(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 23); + return value; +} + + +static uint64 extract_rs4_4_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 3); + value |= extract_bits(instruction, 4, 1) << 3; + return value; +} + + +static uint64 extract_bit_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 3); + return value; +} + + +static uint64 extract_rt_41_40_39_38_37(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 37, 5); + return value; +} + + +static int64 extract_shift__se5_21_20_19_18_17_16(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 16, 6); + value = sign_extend(value, 5); + return value; +} + + +static uint64 extract_rd2_3_8(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 1) << 1; + value |= extract_bits(instruction, 8, 1); + return value; +} + + +static uint64 extract_code_17_to_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 18); + return value; +} + + +static uint64 extract_size_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static int64 extract_s__se8_15_7_6_5_4_3_2_s2(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 2, 6) << 2; + value |= extract_bits(instruction, 15, 1) << 8; + value = sign_extend(value, 8); + return value; +} + + +static uint64 extract_u_15_to_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 16); + return value; +} + + +static uint64 extract_fs_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static int64 extract_s__se8_15_7_6_5_4_3_2_1_0(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 8); + value |= extract_bits(instruction, 15, 1) << 8; + value = sign_extend(value, 8); + return value; +} + + +static uint64 extract_stype_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static uint64 extract_rtl_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 9, 1); + return value; +} + + +static uint64 extract_hs_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static uint64 extract_sel_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 3); + return value; +} + + +static uint64 extract_lsb_4_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 5); + return value; +} + + +static uint64 extract_gp_2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 2, 1); + return value; +} + + +static uint64 extract_rt3_9_8_7(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 7, 3); + return value; +} + + +static uint64 extract_ft_25_24_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 5); + return value; +} + + +static uint64 extract_u_17_16_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 7); + return value; +} + + +static uint64 extract_cs_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static uint64 extract_rt4_9_7_6_5(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 5, 3); + value |= extract_bits(instruction, 9, 1) << 3; + return value; +} + + +static uint64 extract_msbt_10_9_8_7_6(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 6, 5); + return value; +} + + +static uint64 extract_u_5_4_3_2_1_0__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 6) << 2; + return value; +} + + +static uint64 extract_sa_15_14_13(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 13, 3); + return value; +} + + +static int64 extract_s__se14_0_13_to_1_s1(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 14; + value |= extract_bits(instruction, 1, 13) << 1; + value = sign_extend(value, 14); + return value; +} + + +static uint64 extract_rs3_6_5_4(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 4, 3); + return value; +} + + +static uint64 extract_u_31_to_0__s32(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 32) << 32; + return value; +} + + +static uint64 extract_shift_10_9_8_7_6(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 6, 5); + return value; +} + + +static uint64 extract_cs_25_24_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 5); + return value; +} + + +static uint64 extract_shiftx_11_10_9_8_7_6(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 6, 6); + return value; +} + + +static uint64 extract_rt_9_8_7_6_5(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 5, 5); + return value; +} + + +static uint64 extract_op_25_24_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 5); + return value; +} + + +static uint64 extract_u_6_5_4_3_2_1_0__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 7) << 2; + return value; +} + + +static uint64 extract_bit_16_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 6); + return value; +} + + +static uint64 extract_mask_20_19_18_17_16_15_14(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 14, 7); + return value; +} + + +static uint64 extract_eu_3_2_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 4); + return value; +} + + +static uint64 extract_u_7_6_5_4__s4(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 4, 4) << 4; + return value; +} + + +static int64 extract_s__se8_15_7_6_5_4_3_s3(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 3, 5) << 3; + value |= extract_bits(instruction, 15, 1) << 8; + value = sign_extend(value, 8); + return value; +} + + +static uint64 extract_ft_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 5); + return value; +} + + +static int64 extract_s__se31_15_to_0_31_to_16(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 16) << 16; + value |= extract_bits(instruction, 16, 16); + value = sign_extend(value, 31); + return value; +} + + +static uint64 extract_u_20_19_18_17_16_15_14_13(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 13, 8); + return value; +} + + +static uint64 extract_u_17_to_2__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 2, 16) << 2; + return value; +} + + +static uint64 extract_rd_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 5); + return value; +} + + +static uint64 extract_c0s_20_19_18_17_16(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 16, 5); + return value; +} + + +static uint64 extract_code_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 2); + return value; +} + + +static int64 extract_s__se25_0_24_to_1_s1(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 1) << 25; + value |= extract_bits(instruction, 1, 24) << 1; + value = sign_extend(value, 25); + return value; +} + + +static uint64 extract_u_1_0(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 2); + return value; +} + + +static uint64 extract_u_3_8__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 3, 1) << 3; + value |= extract_bits(instruction, 8, 1) << 2; + return value; +} + + +static uint64 extract_fd_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 5); + return value; +} + + +static uint64 extract_u_4_3_2_1_0__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 5) << 2; + return value; +} + + +static uint64 extract_rtz4_9_7_6_5(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 5, 3); + value |= extract_bits(instruction, 9, 1) << 3; + return value; +} + + +static uint64 extract_sel_15_14_13_12_11(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 11, 5); + return value; +} + + +static uint64 extract_ct_25_24_23_22_21(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 21, 5); + return value; +} + + +static uint64 extract_u_20_to_2__s2(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 2, 19) << 2; + return value; +} + + +static int64 extract_s__se3_4_2_1_0(uint64 instruction) +{ + int64 value = 0; + value |= extract_bits(instruction, 0, 3); + value |= extract_bits(instruction, 4, 1) << 3; + value = sign_extend(value, 3); + return value; +} + + +static uint64 extract_u_3_2_1_0__s1(uint64 instruction) +{ + uint64 value = 0; + value |= extract_bits(instruction, 0, 4) << 1; + return value; +} + + + +static bool ADDIU_32__cond(uint64 instruction) +{ + uint64 rt = extract_rt_25_24_23_22_21(instruction); + return rt != 0; +} + + +static bool ADDIU_RS5__cond(uint64 instruction) +{ + uint64 rt = extract_rt_9_8_7_6_5(instruction); + return rt != 0; +} + + +static bool BALRSC_cond(uint64 instruction) +{ + uint64 rt = extract_rt_25_24_23_22_21(instruction); + return rt != 0; +} + + +static bool BEQC_16__cond(uint64 instruction) +{ + uint64 rs3 = extract_rs3_6_5_4(instruction); + uint64 rt3 = extract_rt3_9_8_7(instruction); + uint64 u = extract_u_3_2_1_0__s1(instruction); + return rs3 < rt3 && u != 0; +} + + +static bool BNEC_16__cond(uint64 instruction) +{ + uint64 rs3 = extract_rs3_6_5_4(instruction); + uint64 rt3 = extract_rt3_9_8_7(instruction); + uint64 u = extract_u_3_2_1_0__s1(instruction); + return rs3 >= rt3 && u != 0; +} + + +static bool MOVE_cond(uint64 instruction) +{ + uint64 rt = extract_rt_9_8_7_6_5(instruction); + return rt != 0; +} + + +static bool P16_BR1_cond(uint64 instruction) +{ + uint64 u = extract_u_3_2_1_0__s1(instruction); + return u != 0; +} + + +static bool PREF_S9__cond(uint64 instruction) +{ + uint64 hint = extract_hint_25_24_23_22_21(instruction); + return hint != 31; +} + + +static bool PREFE_cond(uint64 instruction) +{ + uint64 hint = extract_hint_25_24_23_22_21(instruction); + return hint != 31; +} + + +static bool SLTU_cond(uint64 instruction) +{ + uint64 rd = extract_rd_15_14_13_12_11(instruction); + return rd != 0; +} + + + +/* + * ABS.D fd, fs - Floating Point Absolute Value + * + * 3 2 1 + * 10987654321098765432109876543210 + * 010001 00000 000101 + * fmt ----- + * fs ----- + * fd ----- + */ +static char *ABS_D(uint64 instruction, Dis_info *info) +{ + uint64 fd_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *fs = FPR(fs_value, info); + const char *fd = FPR(fd_value, info); + + return img_format("ABS.D %s, %s", fd, fs); +} + + +/* + * ABS.S fd, fs - Floating Point Absolute Value + * + * 3 2 1 + * 10987654321098765432109876543210 + * 010001 00000 000101 + * fmt ----- + * fd ----- + * fs ----- + */ +static char *ABS_S(uint64 instruction, Dis_info *info) +{ + uint64 fd_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *fs = FPR(fs_value, info); + const char *fd = FPR(fd_value, info); + + return img_format("ABS.S %s, %s", fd, fs); +} + + +/* + * [DSP] ABSQ_S.PH rt, rs - Find absolute value of two fractional halfwords + * with 16-bit saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0001000100111111 + * rt ----- + * rs ----- + */ +static char *ABSQ_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ABSQ_S.PH %s, %s", rt, rs); +} + + +/* + * [DSP] ABSQ_S.QB rt, rs - Find absolute value of four fractional byte values + * with 8-bit saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0000000100111111 + * rt ----- + * rs ----- + */ +static char *ABSQ_S_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ABSQ_S.QB %s, %s", rt, rs); +} + + +/* + * [DSP] ABSQ_S.W rt, rs - Find absolute value of fractional word with 32-bit + * saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ABSQ_S_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ABSQ_S.W %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ACLR(uint64 instruction, Dis_info *info) +{ + uint64 bit_value = extract_bit_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("ACLR 0x%" PRIx64 ", %" PRId64 "(%s)", + bit_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADD %s, %s, %s", rd, rs, rt); +} + + +/* + * ADD.D fd, fs, ft - Floating Point Add + * + * 3 2 1 + * 10987654321098765432109876543210 + * 010001 000101 + * fmt ----- + * ft ----- + * fs ----- + * fd ----- + */ +static char *ADD_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + const char *fd = FPR(fd_value, info); + + return img_format("ADD.D %s, %s, %s", fd, fs, ft); +} + + +/* + * ADD.S fd, fs, ft - Floating Point Add + * + * 3 2 1 + * 10987654321098765432109876543210 + * 010001 000101 + * fmt ----- + * ft ----- + * fs ----- + * fd ----- + */ +static char *ADD_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + const char *fd = FPR(fd_value, info); + + return img_format("ADD.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_15_to_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ADDIU %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("ADDIU %s, %" PRId64, rt, s_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_GP48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("ADDIU %s, $%d, %" PRId64, rt, 28, s_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_GP_B_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_0(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("ADDIU %s, $%d, 0x%" PRIx64, rt, 28, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_GP_W_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_20_to_2__s2(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("ADDIU %s, $%d, 0x%" PRIx64, rt, 28, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_NEG_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + int64 u = neg_copy(u_value); + + return img_format("ADDIU %s, %s, %" PRId64, rt, rs, u); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_R1_SP_(uint64 instruction, Dis_info *info) +{ + uint64 u_value = extract_u_5_4_3_2_1_0__s2(instruction); + uint64 rt3_value = extract_rt3_9_8_7(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + + return img_format("ADDIU %s, $%d, 0x%" PRIx64, rt3, 29, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0010000100111111 + * rt ----- + * rs ----- + */ +static char *ADDIU_R2_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_2_1_0__s2(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("ADDIU %s, %s, 0x%" PRIx64, rt3, rs3, u_value); +} + + +/* + * ADDIU[RS5] rt, s5 - Add Signed Word and Set Carry Bit + * + * 5432109876543210 + * 100100 1 + * rt ----- + * s - --- + */ +static char *ADDIU_RS5_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_9_8_7_6_5(instruction); + int64 s_value = extract_s__se3_4_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("ADDIU %s, %" PRId64, rt, s_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDIUPC_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + int64 s_value = extract_s__se21_0_20_to_1_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("ADDIUPC %s, %s", rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDIUPC_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 6, info); + + return img_format("ADDIUPC %s, %s", rt, s); +} + + +/* + * [DSP] ADDQ.PH rd, rt, rs - Add fractional halfword vectors + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00000001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQ_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQ.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDQ_S.PH rd, rt, rs - Add fractional halfword vectors with 16-bit + * saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10000001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQ_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQ_S.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDQ_S.W rd, rt, rs - Add fractional words with 32-bit saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1100000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQ_S_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQ_S.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDQH.PH rd, rt, rs - Add fractional halfword vectors and shift + * right to halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQH_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQH.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDQH_R.PH rd, rt, rs - Add fractional halfword vectors and shift + * right to halve results with rounding + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQH_R_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQH_R.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDQH_R.W rd, rt, rs - Add fractional words and shift right to halve + * results with rounding + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQH_R_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQH_R.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDQH.W rd, rt, rs - Add fractional words and shift right to halve + * results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDQH_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDQH.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDSC rd, rt, rs - Add two signed words and set carry bit + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDSC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDSC %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDU[16] rd3, rs3, rt3 - + * + * 5432109876543210 + * 101100 0 + * rt3 --- + * rs3 --- + * rd3 --- + */ +static char *ADDU_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 rd3_value = extract_rd3_3_2_1(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + const char *rd3 = GPR(decode_gpr_gpr3(rd3_value, info), info); + + return img_format("ADDU %s, %s, %s", rd3, rs3, rt3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDU_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDU_4X4_(uint64 instruction, Dis_info *info) +{ + uint64 rt4_value = extract_rt4_9_7_6_5(instruction); + uint64 rs4_value = extract_rs4_4_2_1_0(instruction); + + const char *rs4 = GPR(decode_gpr_gpr4(rs4_value, info), info); + const char *rt4 = GPR(decode_gpr_gpr4(rt4_value, info), info); + + return img_format("ADDU %s, %s", rs4, rt4); +} + + +/* + * [DSP] ADDU.PH rd, rt, rs - Add two pairs of unsigned halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00100001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDU_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDU.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDU.QB rd, rt, rs - Unsigned Add Quad Byte Vectors + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00011001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDU_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDU.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] ADDU_S.PH rd, rt, rs - Add two pairs of unsigned halfwords with 16-bit + * saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10100001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDU_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDU_S.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDU_S.QB rd, rt, rs - Unsigned Add Quad Byte Vectors + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10011001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDU_S_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDU_S.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDUH.QB rd, rt, rs - Unsigned Add Vector Quad-Bytes And Right Shift + * to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00101001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDUH_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDUH.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDUH_R.QB rd, rt, rs - Unsigned Add Vector Quad-Bytes And Right Shift + * to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10101001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDUH_R_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDUH_R.QB %s, %s, %s", rd, rs, rt); +} + +/* + * ADDWC rd, rt, rs - Add Word with Carry Bit + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1111000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ADDWC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ADDWC %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ALUIPC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + int64 s_value = extract_s__se31_0_11_to_2_20_to_12_s12(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("ALUIPC %s, %%pcrel_hi(%s)", rt, s); +} + + +/* + * AND[16] rt3, rs3 - + * + * 5432109876543210 + * 101100 + * rt3 --- + * rs3 --- + * eu ---- + */ +static char *AND_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("AND %s, %s", rs3, rt3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *AND_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("AND %s, %s, %s", rd, rs, rt); +} + + +/* + * ANDI rt, rs, u - + * + * 5432109876543210 + * 101100 + * rt3 --- + * rs3 --- + * eu ---- + */ +static char *ANDI_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 eu_value = extract_eu_3_2_1_0(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + uint64 eu = encode_eu_from_u_andi16(eu_value); + + return img_format("ANDI %s, %s, 0x%" PRIx64, rt3, rs3, eu); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ANDI_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ANDI %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *APPEND(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("APPEND %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ASET(uint64 instruction, Dis_info *info) +{ + uint64 bit_value = extract_bit_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("ASET 0x%" PRIx64 ", %" PRId64 "(%s)", + bit_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BALC_16_(uint64 instruction, Dis_info *info) +{ + int64 s_value = extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 2, info); + + return img_format("BALC %s", s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BALC_32_(uint64 instruction, Dis_info *info) +{ + int64 s_value = extract_s__se25_0_24_to_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BALC %s", s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BALRSC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("BALRSC %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BBEQZC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 bit_value = extract_bit_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BBEQZC %s, 0x%" PRIx64 ", %s", rt, bit_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BBNEZC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 bit_value = extract_bit_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BBNEZC %s, 0x%" PRIx64 ", %s", rt, bit_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BC_16_(uint64 instruction, Dis_info *info) +{ + int64 s_value = extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 2, info); + + return img_format("BC %s", s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BC_32_(uint64 instruction, Dis_info *info) +{ + int64 s_value = extract_s__se25_0_24_to_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BC %s", s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BC1EQZC(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *ft = FPR(ft_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BC1EQZC %s, %s", ft, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BC1NEZC(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *ft = FPR(ft_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BC1NEZC %s, %s", ft, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BC2EQZC(uint64 instruction, Dis_info *info) +{ + uint64 ct_value = extract_ct_25_24_23_22_21(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BC2EQZC CP%" PRIu64 ", %s", ct_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BC2NEZC(uint64 instruction, Dis_info *info) +{ + uint64 ct_value = extract_ct_25_24_23_22_21(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BC2NEZC CP%" PRIu64 ", %s", ct_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BEQC_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_3_2_1_0__s1(instruction); + + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + g_autofree char *u = ADDRESS(u_value, 2, info); + + return img_format("BEQC %s, %s, %s", rs3, rt3, u); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BEQC_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BEQC %s, %s, %s", rs, rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BEQIC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BEQIC %s, 0x%" PRIx64 ", %s", rt, u_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BEQZC_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + int64 s_value = extract_s__se7_0_6_5_4_3_2_1_s1(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + g_autofree char *s = ADDRESS(s_value, 2, info); + + return img_format("BEQZC %s, %s", rt3, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BGEC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BGEC %s, %s, %s", rs, rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BGEIC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BGEIC %s, 0x%" PRIx64 ", %s", rt, u_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BGEIUC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BGEIUC %s, 0x%" PRIx64 ", %s", rt, u_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BGEUC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BGEUC %s, %s, %s", rs, rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BLTC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BLTC %s, %s, %s", rs, rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BLTIC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BLTIC %s, 0x%" PRIx64 ", %s", rt, u_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BLTIUC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BLTIUC %s, 0x%" PRIx64 ", %s", rt, u_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BLTUC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BLTUC %s, %s, %s", rs, rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BNEC_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_3_2_1_0__s1(instruction); + + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + g_autofree char *u = ADDRESS(u_value, 2, info); + + return img_format("BNEC %s, %s, %s", rs3, rt3, u); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BNEC_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BNEC %s, %s, %s", rs, rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BNEIC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); + int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BNEIC %s, 0x%" PRIx64 ", %s", rt, u_value, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BNEZC_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + int64 s_value = extract_s__se7_0_6_5_4_3_2_1_s1(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + g_autofree char *s = ADDRESS(s_value, 2, info); + + return img_format("BNEZC %s, %s", rt3, s); +} + + +/* + * [DSP] BPOSGE32C offset - Branch on greater than or equal to value 32 in + * DSPControl Pos field + * + * 3 2 1 + * 10987654321098765432109876543210 + * 100010xxxxx0010001 + * s[13:1] ------------- + * s[14] - + */ +static char *BPOSGE32C(uint64 instruction, Dis_info *info) +{ + int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); + + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("BPOSGE32C %s", s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BREAK_16_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_2_1_0(instruction); + + + return img_format("BREAK 0x%" PRIx64, code_value); +} + + +/* + * BREAK code - Break. Cause a Breakpoint exception + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BREAK_32_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_18_to_0(instruction); + + + return img_format("BREAK 0x%" PRIx64, code_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *BRSC(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("BRSC %s", rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CACHE(uint64 instruction, Dis_info *info) +{ + uint64 op_value = extract_op_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("CACHE 0x%" PRIx64 ", %" PRId64 "(%s)", + op_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CACHEE(uint64 instruction, Dis_info *info) +{ + uint64 op_value = extract_op_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("CACHEE 0x%" PRIx64 ", %" PRId64 "(%s)", + op_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CEIL_L_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CEIL.L.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CEIL_L_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CEIL.L.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CEIL_W_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CEIL.W.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CEIL_W_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CEIL.W.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CFC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("CFC1 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CFC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("CFC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CLASS_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CLASS.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CLASS_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CLASS.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CLO(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("CLO %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CLZ(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("CLZ %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_AF_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.AF.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_AF_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.AF.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_EQ_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.EQ.D %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] CMP.EQ.PH rs, rt - Compare vectors of signed integer halfword values + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxxx0000000101 + * rt ----- + * rs ----- + */ +static char *CMP_EQ_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMP.EQ.PH %s, %s", rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_EQ_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.EQ.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_LE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.LE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] CMP.LE.PH rs, rt - Compare vectors of signed integer halfword values + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxxx0010000101 + * rt ----- + * rs ----- + */ +static char *CMP_LE_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMP.LE.PH %s, %s", rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_LE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.LE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_LT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.LT.D %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] CMP.LT.PH rs, rt - Compare vectors of signed integer halfword values + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxxx0001000101 + * rt ----- + * rs ----- + */ +static char *CMP_LT_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMP.LT.PH %s, %s", rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_LT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.LT.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_NE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.NE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_NE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.NE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_OR_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.OR.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_OR_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.OR.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SAF_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SAF.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SAF_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SAF.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SEQ_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SEQ.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SEQ_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SEQ.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SLE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SLE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SLE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SLE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SLT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SLT.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SLT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SLT.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SNE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SNE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SNE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SNE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SOR_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SOR.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SOR_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SOR.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SUEQ_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SUEQ.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SUEQ_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SUEQ.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SULE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SULE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SULE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SULE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SULT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SULT.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SULT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SULT.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SUN_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SUN.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SUNE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SUNE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SUNE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SUNE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_SUN_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.SUN.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_UEQ_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.UEQ.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_UEQ_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.UEQ.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_ULE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.ULE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_ULE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.ULE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_ULT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.ULT.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_ULT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.ULT.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_UN_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.UN.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_UNE_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.UNE.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_UNE_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.UNE.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMP_UN_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("CMP.UN.S %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] CMPGDU.EQ.QB rd, rs, rt - Compare unsigned vector of + * four bytes and write result to GPR and DSPControl + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMPGDU_EQ_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPGDU.EQ.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] CMPGDU.LE.QB rd, rs, rt - Compare unsigned vector of + * four bytes and write result to GPR and DSPControl + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1000000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMPGDU_LE_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPGDU.LE.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] CMPGDU.EQ.QB rd, rs, rt - Compare unsigned vector of + * four bytes and write result to GPR and DSPControl + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0111000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMPGDU_LT_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPGDU.LT.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] CMPGU.EQ.QB rd, rs, rt - Compare vectors of unsigned + * byte values and write result to a GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0011000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMPGU_EQ_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPGU.EQ.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] CMPGU.LE.QB rd, rs, rt - Compare vectors of unsigned + * byte values and write result to a GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0101000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMPGU_LE_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPGU.LE.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] CMPGU.LT.QB rd, rs, rt - Compare vectors of unsigned + * byte values and write result to a GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0100000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CMPGU_LT_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPGU.LT.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] CMPU.EQ.QB rd, rs, rt - Compare vectors of unsigned + * byte values + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxxx1001000101 + * rt ----- + * rs ----- + */ +static char *CMPU_EQ_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPU.EQ.QB %s, %s", rs, rt); +} + + +/* + * [DSP] CMPU.LE.QB rd, rs, rt - Compare vectors of unsigned + * byte values + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxxx1011000101 + * rt ----- + * rs ----- + */ +static char *CMPU_LE_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPU.LE.QB %s, %s", rs, rt); +} + + +/* + * [DSP] CMPU.LT.QB rd, rs, rt - Compare vectors of unsigned + * byte values + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxxx1010000101 + * rt ----- + * rs ----- + */ +static char *CMPU_LT_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("CMPU.LT.QB %s, %s", rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *COP2_1(uint64 instruction, Dis_info *info) +{ + uint64 cofun_value = extract_cofun_25_24_23(instruction); + + + return img_format("COP2_1 0x%" PRIx64, cofun_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CTC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("CTC1 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CTC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("CTC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_D_L(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.D.L %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_D_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.D.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_D_W(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.D.W %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_L_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.L.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_L_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.L.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_S_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.S.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_S_L(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.S.L %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_S_PL(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.S.PL %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_S_PU(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.S.PU %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_S_W(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.S.W %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_W_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.W.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *CVT_W_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("CVT.W.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DADDIU_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DADDIU %s, %" PRId64, rt, s_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DADDIU_NEG_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + int64 u = neg_copy(u_value); + + return img_format("DADDIU %s, %s, %" PRId64, rt, rs, u); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DADDIU_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DADDIU %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DADD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DADD %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DADDU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DADDU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DCLO(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DCLO %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DCLZ(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DCLZ %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DDIV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DDIV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DDIVU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DDIVU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DERET(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("DERET "); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DEXTM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 msbd = encode_msbd_from_size(msbd_value); + + return img_format("DEXTM %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DEXT(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 msbd = encode_msbd_from_size(msbd_value); + + return img_format("DEXT %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DEXTU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 msbd = encode_msbd_from_size(msbd_value); + + return img_format("DEXTU %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DINSM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + /* !!!!!!!!!! - no conversion function */ + + return img_format("DINSM %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd_value); + /* hand edited */ +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DINS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + /* !!!!!!!!!! - no conversion function */ + + return img_format("DINS %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd_value); + /* hand edited */ +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DINSU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + /* !!!!!!!!!! - no conversion function */ + + return img_format("DINSU %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd_value); + /* hand edited */ +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DI %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DIV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DIV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DIV_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("DIV.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DIV_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("DIV.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DIVU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DIVU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DLSA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + uint64 u2_value = extract_u2_10_9(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DLSA %s, %s, %s, 0x%" PRIx64, rd, rs, rt, u2_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DLUI_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + uint64 u_value = extract_u_31_to_0__s32(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DLUI %s, 0x%" PRIx64, rt, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMFC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMFC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMFC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("DMFC1 %s, %s", rt, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMFC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMFC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMFGC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMFGC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMOD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DMOD %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMODU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DMODU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMTC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMTC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMTC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("DMTC1 %s, %s", rt, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMTC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMTC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMTGC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMTGC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMT(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DMT %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMUH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DMUH %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMUHU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DMUHU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMUL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DMUL %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DMULU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DMULU %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] DPA.W.PH ac, rs, rt - Dot product with accumulate on + * vector integer halfword elements + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00000010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *DPA_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPA.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAQ_SA_L_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAQ_SA.L.W %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAQ_S_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAQ_S.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAQX_SA_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAQX_SA.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAQX_S_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAQX_S.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAU_H_QBL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAU.H.QBL %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAU_H_QBR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAU.H.QBR %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPAX_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPAX.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPS_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPS.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSQ_SA_L_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSQ_SA.L.W %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSQ_S_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSQ_S.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSQX_SA_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSQX_SA.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSQX_S_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSQX_S.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSU_H_QBL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSU.H.QBL %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSU_H_QBR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSU.H.QBR %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DPSX_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DPSX.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * DROTR - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DROTR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DROTR %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * DROTR[32] - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0110 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DROTR32(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DROTR32 %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DROTRV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DROTRV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DROTX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shiftx_value = extract_shiftx_11_10_9_8_7_6(instruction); + uint64 shift_value = extract_shift_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DROTX %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, shift_value, shiftx_value); +} + + +/* + * DSLL - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0000 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DSLL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DSLL %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * DSLL[32] - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0000 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DSLL32(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DSLL32 %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DSLLV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DSLLV %s, %s, %s", rd, rs, rt); +} + + +/* + * DSRA - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0100 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DSRA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DSRA %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * DSRA[32] - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0100 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DSRA32(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DSRA32 %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DSRAV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DSRAV %s, %s, %s", rd, rs, rt); +} + + +/* + * DSRL - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0100 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DSRL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DSRL %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * DSRL[32] - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 10o000 1100xxx0010 + * rt ----- + * rs ----- + * shift ----- + */ +static char *DSRL32(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("DSRL32 %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DSRLV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DSRLV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DSUB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DSUB %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DSUBU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("DSUBU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DVPE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DVPE %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *DVP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("DVP %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EHB(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("EHB "); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("EI %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EMT(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("EMT %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ERET(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("ERET "); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ERETNC(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("ERETNC "); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EVP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("EVP %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EVPE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("EVPE %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXT(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 msbd = encode_msbd_from_size(msbd_value); + + return img_format("EXT %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXTD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + uint64 shift_value = extract_shift_10_9_8_7_6(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("EXTD %s, %s, %s, 0x%" PRIx64, rd, rs, rt, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXTD32(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + uint64 shift_value = extract_shift_10_9_8_7_6(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("EXTD32 %s, %s, %s, 0x%" PRIx64, rd, rs, rt, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXTPDP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 size_value = extract_size_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("EXTPDP %s, %s, 0x%" PRIx64, rt, ac, size_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXTPDPV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("EXTPDPV %s, %s, %s", rt, ac, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXTP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 size_value = extract_size_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("EXTP %s, %s, 0x%" PRIx64, rt, ac, size_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *EXTPV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("EXTPV %s, %s, %s", rt, ac, rs); +} + + +/* + * [DSP] EXTR_RS.W rt, ac, shift - Extract word value from accumulator to GPR + * with right shift + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10111001111111 + * rt ----- + * shift ----- + * ac -- + */ +static char *EXTR_RS_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 shift_value = extract_shift_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("EXTR_RS.W %s, %s, 0x%" PRIx64, rt, ac, shift_value); +} + + +/* + * [DSP] EXTR_R.W rt, ac, shift - Extract word value from accumulator to GPR + * with right shift + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01111001111111 + * rt ----- + * shift ----- + * ac -- + */ +static char *EXTR_R_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 shift_value = extract_shift_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("EXTR_R.W %s, %s, 0x%" PRIx64, rt, ac, shift_value); +} + + +/* + * [DSP] EXTR_S.H rt, ac, shift - Extract halfword value from accumulator + * to GPR with right shift and saturate + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11111001111111 + * rt ----- + * shift ----- + * ac -- + */ +static char *EXTR_S_H(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 shift_value = extract_shift_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("EXTR_S.H %s, %s, 0x%" PRIx64, rt, ac, shift_value); +} + + +/* + * [DSP] EXTR.W rt, ac, shift - Extract word value from accumulator to GPR + * with right shift + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00111001111111 + * rt ----- + * shift ----- + * ac -- + */ +static char *EXTR_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 shift_value = extract_shift_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("EXTR.W %s, %s, 0x%" PRIx64, rt, ac, shift_value); +} + + +/* + * [DSP] EXTRV_RS.W rt, ac, rs - Extract word value with variable + * right shift from accumulator to GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10111010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *EXTRV_RS_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("EXTRV_RS.W %s, %s, %s", rt, ac, rs); +} + + +/* + * [DSP] EXTRV_R.W rt, ac, rs - Extract word value with variable + * right shift from accumulator to GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01111010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *EXTRV_R_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("EXTRV_R.W %s, %s, %s", rt, ac, rs); +} + + +/* + * [DSP] EXTRV_S.H rt, ac, rs - Extract halfword value variable from + * accumulator to GPR with right shift and saturate + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11111010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *EXTRV_S_H(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("EXTRV_S.H %s, %s, %s", rt, ac, rs); +} + + +/* + * [DSP] EXTRV.W rt, ac, rs - Extract word value with variable + * right shift from accumulator to GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00111010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *EXTRV_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("EXTRV.W %s, %s, %s", rt, ac, rs); +} + + +/* + * EXTW - Extract Word + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 011111 + * rt ----- + * rs ----- + * rd ----- + * shift ----- + */ +static char *EXTW(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + uint64 shift_value = extract_shift_10_9_8_7_6(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("EXTW %s, %s, %s, 0x%" PRIx64, rd, rs, rt, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *FLOOR_L_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("FLOOR.L.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *FLOOR_L_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("FLOOR.L.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *FLOOR_W_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("FLOOR.W.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *FLOOR_W_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("FLOOR.W.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *FORK(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("FORK %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *HYPCALL(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_17_to_0(instruction); + + + return img_format("HYPCALL 0x%" PRIx64, code_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *HYPCALL_16_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_1_0(instruction); + + + return img_format("HYPCALL 0x%" PRIx64, code_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *INS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); + uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + /* !!!!!!!!!! - no conversion function */ + + return img_format("INS %s, %s, 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, lsb_value, msbd_value); + /* hand edited */ +} + + +/* + * [DSP] INSV rt, rs - Insert bit field variable + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0100000100111111 + * rt ----- + * rs ----- + */ +static char *INSV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("INSV %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *IRET(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("IRET "); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *JALRC_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_9_8_7_6_5(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("JALRC $%d, %s", 31, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *JALRC_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("JALRC %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *JALRC_HB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("JALRC.HB %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *JRC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_9_8_7_6_5(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("JRC %s", rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LB_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_1_0(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("LB %s, 0x%" PRIx64 "(%s)", rt3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LB_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_0(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LB %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LB_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LB %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LB_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LB %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LBE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBU_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_1_0(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("LBU %s, 0x%" PRIx64 "(%s)", rt3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBU_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_0(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LBU %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBU_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LBU %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBU_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LBU %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBUE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LBUE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBUX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LBUX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LBX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LBX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LD_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_20_to_3__s3(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LD %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LD_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LD %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LD_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LD %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDC1_GP_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_2__s2(instruction); + + const char *ft = FPR(ft_value, info); + + return img_format("LDC1 %s, 0x%" PRIx64 "($%d)", ft, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDC1_S9_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LDC1 %s, %" PRId64 "(%s)", ft, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDC1_U12_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LDC1 %s, 0x%" PRIx64 "(%s)", ft, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDC1XS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LDC1XS %s, %s(%s)", ft, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDC1X(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LDC1X %s, %s(%s)", ft, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDC2(uint64 instruction, Dis_info *info) +{ + uint64 ct_value = extract_ct_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("LDC2 CP%" PRIu64 ", %" PRId64 "(%s)", + ct_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("LDM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDPC_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 6, info); + + return img_format("LDPC %s, %s", rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LDX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LDXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LDXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LH_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_2_1__s1(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("LH %s, 0x%" PRIx64 "(%s)", rt3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LH_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_1__s1(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LH %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LH_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LH %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LH_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LH %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LHE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHU_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_2_1__s1(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("LHU %s, 0x%" PRIx64 "(%s)", rt3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHU_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_1__s1(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LHU %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHU_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LHU %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHU_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LHU %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHUE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LHUE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHUX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LHUX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHUXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LHUXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LHXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LHX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LHX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LI_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 eu_value = extract_eu_6_5_4_3_2_1_0(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + int64 eu = encode_eu_from_s_li16(eu_value); + + return img_format("LI %s, %" PRId64, rt3, eu); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LI_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LI %s, %" PRId64, rt, s_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LL %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LLD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_s3(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LLD %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LLDP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ru_value = extract_ru_7_6_5_4_3(instruction); + + const char *rt = GPR(rt_value, info); + const char *ru = GPR(ru_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LLDP %s, %s, (%s)", rt, ru, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LLE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LLE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LLWP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ru_value = extract_ru_7_6_5_4_3(instruction); + + const char *rt = GPR(rt_value, info); + const char *ru = GPR(ru_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LLWP %s, %s, (%s)", rt, ru, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LLWPE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ru_value = extract_ru_7_6_5_4_3(instruction); + + const char *rt = GPR(rt_value, info); + const char *ru = GPR(ru_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LLWPE %s, %s, (%s)", rt, ru, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LSA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + uint64 u2_value = extract_u2_10_9(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LSA %s, %s, %s, 0x%" PRIx64, rd, rs, rt, u2_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LUI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + int64 s_value = extract_s__se31_0_11_to_2_20_to_12_s12(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LUI %s, %%hi(%" PRId64 ")", rt, s_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_3_2_1_0__s2(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("LW %s, 0x%" PRIx64 "(%s)", rt3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_4X4_(uint64 instruction, Dis_info *info) +{ + uint64 rt4_value = extract_rt4_9_7_6_5(instruction); + uint64 rs4_value = extract_rs4_4_2_1_0(instruction); + uint64 u_value = extract_u_3_8__s2(instruction); + + const char *rt4 = GPR(decode_gpr_gpr4(rt4_value, info), info); + const char *rs4 = GPR(decode_gpr_gpr4(rs4_value, info), info); + + return img_format("LW %s, 0x%" PRIx64 "(%s)", rt4, u_value, rs4); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_20_to_2__s2(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LW %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_GP16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 u_value = extract_u_6_5_4_3_2_1_0__s2(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + + return img_format("LW %s, 0x%" PRIx64 "($%d)", rt3, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LW %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_SP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_9_8_7_6_5(instruction); + uint64 u_value = extract_u_4_3_2_1_0__s2(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LW %s, 0x%" PRIx64 "($%d)", rt, u_value, 29); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LW_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LW %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWC1_GP_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_2__s2(instruction); + + const char *ft = FPR(ft_value, info); + + return img_format("LWC1 %s, 0x%" PRIx64 "($%d)", ft, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWC1_S9_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LWC1 %s, %" PRId64 "(%s)", ft, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWC1_U12_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LWC1 %s, 0x%" PRIx64 "(%s)", ft, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWC1X(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LWC1X %s, %s(%s)", ft, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWC1XS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LWC1XS %s, %s(%s)", ft, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWC2(uint64 instruction, Dis_info *info) +{ + uint64 ct_value = extract_ct_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("LWC2 CP%" PRIu64 ", %" PRId64 "(%s)", + ct_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LWE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("LWM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWPC_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 6, info); + + return img_format("LWPC %s, %s", rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWU_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_2__s2(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("LWU %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWU_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LWU %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWU_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("LWU %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWUX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LWUX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWUXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LWUXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LWX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWXS_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 rd3_value = extract_rd3_3_2_1(instruction); + + const char *rd3 = GPR(decode_gpr_gpr3(rd3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + uint64 rt3 = decode_gpr_gpr3(rt3_value, info); + + return img_format("LWXS %s, %s(0x%" PRIx64 ")", rd3, rs3, rt3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *LWXS_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("LWXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * [DSP] MADD ac, rs, rt - Multiply two words and add to the specified + * accumulator + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MADD_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MADD %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MADDF_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MADDF.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MADDF_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MADDF.S %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] MADDU ac, rs, rt - Multiply two unsigned words and add to the + * specified accumulator + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MADDU_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MADDU %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MAQ_S.W.PHL ac, rs, rt - Multiply the left-most single vector + * fractional halfword elements with accumulation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAQ_S_W_PHL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MAQ_S.W.PHL %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MAQ_S.W.PHR ac, rs, rt - Multiply the right-most single vector + * fractional halfword elements with accumulation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAQ_S_W_PHR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MAQ_S.W.PHR %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MAQ_SA.W.PHL ac, rs, rt - Multiply the left-most single vector + * fractional halfword elements with saturating accumulation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAQ_SA_W_PHL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MAQ_SA.W.PHL %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MAQ_SA.W.PHR ac, rs, rt - Multiply the right-most single vector + * fractional halfword elements with saturating accumulation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAQ_SA_W_PHR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MAQ_SA.W.PHR %s, %s, %s", ac, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAX_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MAX.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAX_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MAX.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAXA_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MAXA.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MAXA_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MAXA.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("MFC1 %s, %s", rt, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFGC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFGC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFHC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFHC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFHC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("MFHC1 %s, %s", rt, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFHC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFHC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFHGC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFHGC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * [DSP] MFHI rs, ac - Move from HI register + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxx 00000001111111 + * rt ----- + * ac -- + */ +static char *MFHI_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("MFHI %s, %s", rt, ac); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFHTR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + uint64 u_value = extract_u_10(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFHTR %s, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64, + rt, c0s_value, u_value, sel_value); +} + + +/* + * [DSP] MFLO rs, ac - Move from HI register + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 xxxxx 01000001111111 + * rt ----- + * ac -- + */ +static char *MFLO_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rt = GPR(rt_value, info); + const char *ac = AC(ac_value, info); + + return img_format("MFLO %s, %s", rt, ac); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MFTR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + uint64 u_value = extract_u_10(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MFTR %s, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64, + rt, c0s_value, u_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MIN_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MIN.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MIN_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MIN.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MINA_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MINA.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MINA_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MINA.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MOD %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MODSUB rd, rs, rt - Modular subtraction on an index value + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MODSUB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MODSUB %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1010010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MODU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MODU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOV_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("MOV.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOV_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("MOV.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOVE_BALC(uint64 instruction, Dis_info *info) +{ + uint64 rtz4_value = extract_rtz4_27_26_25_23_22_21(instruction); + uint64 rd1_value = extract_rdl_25_24(instruction); + int64 s_value = extract_s__se21_0_20_to_1_s1(instruction); + + const char *rd1 = GPR(decode_gpr_gpr1(rd1_value, info), info); + const char *rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value, info), info); + g_autofree char *s = ADDRESS(s_value, 4, info); + + return img_format("MOVE.BALC %s, %s, %s", rd1, rtz4, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOVEP(uint64 instruction, Dis_info *info) +{ + uint64 rtz4_value = extract_rtz4_9_7_6_5(instruction); + uint64 rd2_value = extract_rd2_3_8(instruction); + uint64 rsz4_value = extract_rsz4_4_2_1_0(instruction); + + const char *rd2 = GPR(decode_gpr_gpr2_reg1(rd2_value, info), info); + const char *re2 = GPR(decode_gpr_gpr2_reg2(rd2_value, info), info); + /* !!!!!!!!!! - no conversion function */ + const char *rsz4 = GPR(decode_gpr_gpr4_zero(rsz4_value, info), info); + const char *rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value, info), info); + + return img_format("MOVEP %s, %s, %s, %s", rd2, re2, rsz4, rtz4); + /* hand edited */ +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOVEP_REV_(uint64 instruction, Dis_info *info) +{ + uint64 rt4_value = extract_rt4_9_7_6_5(instruction); + uint64 rd2_value = extract_rd2_3_8(instruction); + uint64 rs4_value = extract_rs4_4_2_1_0(instruction); + + const char *rs4 = GPR(decode_gpr_gpr4(rs4_value, info), info); + const char *rt4 = GPR(decode_gpr_gpr4(rt4_value, info), info); + const char *rd2 = GPR(decode_gpr_gpr2_reg1(rd2_value, info), info); + const char *rs2 = GPR(decode_gpr_gpr2_reg2(rd2_value, info), info); + /* !!!!!!!!!! - no conversion function */ + + return img_format("MOVEP %s, %s, %s, %s", rs4, rt4, rd2, rs2); + /* hand edited */ +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOVE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_9_8_7_6_5(instruction); + uint64 rs_value = extract_rs_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("MOVE %s, %s", rt, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOVN(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MOVN %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MOVZ(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MOVZ %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MSUB ac, rs, rt - Multiply word and subtract from accumulator + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10101010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *MSUB_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MSUB %s, %s, %s", ac, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MSUBF_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MSUBF.D %s, %s, %s", fd, fs, ft); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MSUBF_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MSUBF.S %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] MSUBU ac, rs, rt - Multiply word and add to accumulator + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11101010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *MSUBU_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MSUBU %s, %s, %s", ac, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("MTC1 %s, %s", rt, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTGC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTGC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTHC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTHC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTHC1(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("MTHC1 %s, %s", rt, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTHC2(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 cs_value = extract_cs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTHC2 %s, CP%" PRIu64, rt, cs_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTHGC0(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTHGC0 %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, c0s_value, sel_value); +} + + +/* + * [DSP] MTHI rs, ac - Move to HI register + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000xxxxx 10000001111111 + * rs ----- + * ac -- + */ +static char *MTHI_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rs = GPR(rs_value, info); + const char *ac = AC(ac_value, info); + + return img_format("MTHI %s, %s", rs, ac); +} + + +/* + * [DSP] MTHLIP rs, ac - Copy LO to HI and a GPR to LO and increment pos by 32 + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000xxxxx 00001001111111 + * rs ----- + * ac -- + */ +static char *MTHLIP(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rs = GPR(rs_value, info); + const char *ac = AC(ac_value, info); + + return img_format("MTHLIP %s, %s", rs, ac); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTHTR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + uint64 u_value = extract_u_10(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTHTR %s, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64, + rt, c0s_value, u_value, sel_value); +} + + +/* + * [DSP] MTLO rs, ac - Move to LO register + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000xxxxx 11000001111111 + * rs ----- + * ac -- + */ +static char *MTLO_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rs = GPR(rs_value, info); + const char *ac = AC(ac_value, info); + + return img_format("MTLO %s, %s", rs, ac); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MTTR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_15_14_13_12_11(instruction); + uint64 u_value = extract_u_10(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("MTTR %s, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64, + rt, c0s_value, u_value, sel_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MUH %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUHU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MUHU %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUL_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MUL %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUL_4X4_(uint64 instruction, Dis_info *info) +{ + uint64 rt4_value = extract_rt4_9_7_6_5(instruction); + uint64 rs4_value = extract_rs4_4_2_1_0(instruction); + + const char *rs4 = GPR(decode_gpr_gpr4(rs4_value, info), info); + const char *rt4 = GPR(decode_gpr_gpr4(rt4_value, info), info); + + return img_format("MUL %s, %s", rs4, rt4); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUL_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MUL.D %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] MUL.PH rd, rs, rt - Multiply vector integer half words to same size + * products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00000101101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUL_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MUL.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MUL_S.PH rd, rs, rt - Multiply vector integer half words to same size + * products (saturated) + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10000101101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUL_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MUL_S.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MUL_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("MUL.S %s, %s, %s", fd, fs, ft); +} + + +/* + * [DSP] MULEQ_S.W.PHL rd, rs, rt - Multiply vector fractional left halfwords + * to expanded width products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0000100101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULEQ_S_W_PHL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULEQ_S.W.PHL %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULEQ_S.W.PHR rd, rs, rt - Multiply vector fractional right halfwords + * to expanded width products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0001100101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULEQ_S_W_PHR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULEQ_S.W.PHR %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULEU_S.PH.QBL rd, rs, rt - Multiply vector fractional left bytes + * by halfwords to halfword products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0010010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULEU_S_PH_QBL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULEU_S.PH.QBL %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULEU_S.PH.QBR rd, rs, rt - Multiply vector fractional right bytes + * by halfwords to halfword products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0011010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULEU_S_PH_QBR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULEU_S.PH.QBR %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULQ_RS.PH rd, rs, rt - Multiply vector fractional halfwords + * to fractional halfword products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0100010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULQ_RS_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULQ_RS.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULQ_RS.W rd, rs, rt - Multiply fractional words to same size + * product with saturation and rounding + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0110010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULQ_RS_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULQ_RS.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULQ_S.PH rd, rs, rt - Multiply fractional halfwords to same size + * products + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0101010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULQ_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULQ_S.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULQ_S.W rd, rs, rt - Multiply fractional words to same size product + * with saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0111010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULQ_S_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULQ_S.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] MULSA.W.PH ac, rs, rt - Multiply and subtract vector integer halfword + * elements and accumulate + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 10110010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *MULSA_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULSA.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MULSAQ_S.W.PH ac, rs, rt - Multiply and subtract vector fractional + * halfwords and accumulate + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11110010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *MULSAQ_S_W_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULSAQ_S.W.PH %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MULT ac, rs, rt - Multiply word + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00110010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *MULT_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULT %s, %s, %s", ac, rs, rt); +} + + +/* + * [DSP] MULTU ac, rs, rt - Multiply unsigned word + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01110010111111 + * rt ----- + * rs ----- + * ac -- + */ +static char *MULTU_DSP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULTU %s, %s, %s", ac, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *MULU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("MULU %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *NEG_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("NEG.D %s, %s", ft, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *NEG_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("NEG.S %s, %s", ft, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *NOP_16_(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("NOP "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *NOP_32_(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("NOP "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *NOR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("NOR %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *NOT_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("NOT %s, %s", rt3, rs3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *OR_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + + return img_format("OR %s, %s", rs3, rt3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *OR_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("OR %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ORI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ORI %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * [DSP] PACKRL.PH rd, rs, rt - Pack a word using the right halfword from one + * source register and left halfword from another source register + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PACKRL_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PACKRL.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PAUSE(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("PAUSE "); +} + + +/* + * [DSP] PICK.PH rd, rs, rt - Pick a vector of halfwords based on condition + * code bits + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PICK_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PICK.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] PICK.QB rd, rs, rt - Pick a vector of byte values based on condition + * code bits + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PICK_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PICK.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] PRECEQ.W.PHL rt, rs - Expand the precision of the left-most element + * of a paired halfword + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEQ_W_PHL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEQ.W.PHL %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEQ.W.PHR rt, rs - Expand the precision of the right-most element + * of a paired halfword + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEQ_W_PHR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEQ.W.PHR %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEQU.PH.QBLA rt, rs - Expand the precision of the two + * left-alternate elements of a quad byte vector + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEQU_PH_QBLA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEQU.PH.QBLA %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEQU.PH.QBL rt, rs - Expand the precision of the two left-most + * elements of a quad byte vector + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEQU_PH_QBL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEQU.PH.QBL %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEQU.PH.QBRA rt, rs - Expand the precision of the two + * right-alternate elements of a quad byte vector + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEQU_PH_QBRA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEQU.PH.QBRA %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEQU.PH.QBR rt, rs - Expand the precision of the two right-most + * elements of a quad byte vector + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEQU_PH_QBR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEQU.PH.QBR %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEU.PH.QBLA rt, rs - Expand the precision of the two + * left-alternate elements of a quad byte vector to four unsigned + * halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEU_PH_QBLA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEU.PH.QBLA %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEU.PH.QBL rt, rs - Expand the precision of the two left-most + * elements of a quad byte vector to form unsigned halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEU_PH_QBL(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEU.PH.QBL %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEU.PH.QBRA rt, rs - Expand the precision of the two + * right-alternate elements of a quad byte vector to form four + * unsigned halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEU_PH_QBRA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEU.PH.QBRA %s, %s", rt, rs); +} + + +/* + * [DSP] PRECEU.PH.QBR rt, rs - Expand the precision of the two right-most + * elements of a quad byte vector to form unsigned halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECEU_PH_QBR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECEU.PH.QBR %s, %s", rt, rs); +} + + +/* + * [DSP] PRECR.QB.PH rd, rs, rt - Reduce the precision of four integer + * halfwords to four bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0001101101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECR_QB_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PRECR.QB.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] PRECR_SRA.PH.W rt, rs, sa - Reduce the precision of two integer + * words to halfwords after a right shift + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECR_SRA_PH_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECR_SRA.PH.W %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] PRECR_SRA_R.PH.W rt, rs, sa - Reduce the precision of two integer + * words to halfwords after a right shift with rounding + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECR_SRA_R_PH_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PRECR_SRA_R.PH.W %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] PRECRQ.PH.W rd, rs, rt - Reduce the precision of fractional + * words to fractional halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECRQ_PH_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PRECRQ.PH.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] PRECRQ.QB.PH rd, rs, rt - Reduce the precision of four fractional + * halfwords to four bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0010101101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECRQ_QB_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PRECRQ.QB.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] PRECRQ_RS.PH.W rd, rs, rt - Reduce the precision of fractional + * words to halfwords with rounding and saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECRQ_RS_PH_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PRECRQ_RS.PH.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] PRECRQU_S.QB.PH rd, rs, rt - Reduce the precision of fractional + * halfwords to unsigned bytes with saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PRECRQU_S_QB_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("PRECRQU_S.QB.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PREF_S9_(uint64 instruction, Dis_info *info) +{ + uint64 hint_value = extract_hint_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("PREF 0x%" PRIx64 ", %" PRId64 "(%s)", + hint_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PREF_U12_(uint64 instruction, Dis_info *info) +{ + uint64 hint_value = extract_hint_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("PREF 0x%" PRIx64 ", 0x%" PRIx64 "(%s)", + hint_value, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PREFE(uint64 instruction, Dis_info *info) +{ + uint64 hint_value = extract_hint_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("PREFE 0x%" PRIx64 ", %" PRId64 "(%s)", + hint_value, s_value, rs); +} + + +/* + * [DSP] PREPEND rt, rs, sa - Right shift and prepend bits to the MSB + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *PREPEND(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("PREPEND %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] RADDU.W.QB rt, rs - Unsigned reduction add of vector quad bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 1111000100111111 + * rt ----- + * rs ----- + */ +static char *RADDU_W_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("RADDU.W.QB %s, %s", rt, rs); +} + + +/* + * [DSP] RDDSP rt, mask - Read DSPControl register fields to a GPR + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00011001111111 + * rt ----- + * mask ------- + */ +static char *RDDSP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 mask_value = extract_mask_20_19_18_17_16_15_14(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("RDDSP %s, 0x%" PRIx64, rt, mask_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RDHWR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 hs_value = extract_hs_20_19_18_17_16(instruction); + uint64 sel_value = extract_sel_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("RDHWR %s, CP%" PRIu64 ", 0x%" PRIx64, + rt, hs_value, sel_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RDPGPR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("RDPGPR %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RECIP_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("RECIP.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RECIP_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("RECIP.S %s, %s", ft, fs); +} + + +/* + * [DSP] REPL.PH rd, s - Replicate immediate integer into all vector element + * positions + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x0000111101 + * rt ----- + * s ---------- + */ +static char *REPL_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + int64 s_value = extract_s__se9_20_19_18_17_16_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("REPL.PH %s, %" PRId64, rt, s_value); +} + + +/* + * [DSP] REPL.QB rd, u - Replicate immediate integer into all vector element + * positions + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x010111111111 + * rt ----- + * u -------- + */ +static char *REPL_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_20_19_18_17_16_15_14_13(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("REPL.QB %s, 0x%" PRIx64, rt, u_value); +} + + +/* + * [DSP] REPLV.PH rt, rs - Replicate a halfword into all vector element + * positions + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0000001100111111 + * rt ----- + * rs ----- + */ +static char *REPLV_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("REPLV.PH %s, %s", rt, rs); +} + + +/* + * [DSP] REPLV.QB rt, rs - Replicate byte into all vector element positions + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0001001100111111 + * rt ----- + * rs ----- + */ +static char *REPLV_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("REPLV.QB %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RESTORE_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 count_value = extract_count_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); + uint64 gp_value = extract_gp_2(instruction); + + g_autofree char *save_restore_str = save_restore_list( + rt_value, count_value, gp_value, info); + return img_format("RESTORE 0x%" PRIx64 "%s", u_value, save_restore_str); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RESTORE_JRC_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt1_value = extract_rtl_11(instruction); + uint64 u_value = extract_u_7_6_5_4__s4(instruction); + uint64 count_value = extract_count_3_2_1_0(instruction); + + g_autofree char *save_restore_str = save_restore_list( + encode_rt1_from_rt(rt1_value), count_value, 0, info); + return img_format("RESTORE.JRC 0x%" PRIx64 "%s", u_value, save_restore_str); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RESTORE_JRC_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 count_value = extract_count_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); + uint64 gp_value = extract_gp_2(instruction); + + g_autofree char *save_restore_str = save_restore_list( + rt_value, count_value, gp_value, info); + return img_format("RESTORE.JRC 0x%" PRIx64 "%s", u_value, + save_restore_str); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RESTOREF(uint64 instruction, Dis_info *info) +{ + uint64 count_value = extract_count_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); + + + return img_format("RESTOREF 0x%" PRIx64 ", 0x%" PRIx64, + u_value, count_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RINT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("RINT.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RINT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("RINT.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROTR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ROTR %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROTRV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("ROTRV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROTX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shiftx_value = extract_shiftx_10_9_8_7__s1(instruction); + uint64 stripe_value = extract_stripe_6(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("ROTX %s, %s, 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64, + rt, rs, shift_value, shiftx_value, stripe_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROUND_L_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("ROUND.L.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROUND_L_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("ROUND.L.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROUND_W_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("ROUND.W.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *ROUND_W_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("ROUND.W.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RSQRT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("RSQRT.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110000101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *RSQRT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("RSQRT.S %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SAVE_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt1_value = extract_rtl_11(instruction); + uint64 u_value = extract_u_7_6_5_4__s4(instruction); + uint64 count_value = extract_count_3_2_1_0(instruction); + + g_autofree char *save_restore_str = save_restore_list( + encode_rt1_from_rt(rt1_value), count_value, 0, info); + return img_format("SAVE 0x%" PRIx64 "%s", u_value, save_restore_str); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SAVE_32_(uint64 instruction, Dis_info *info) +{ + uint64 count_value = extract_count_19_18_17_16(instruction); + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); + uint64 gp_value = extract_gp_2(instruction); + + g_autofree char *save_restore_str = save_restore_list( + rt_value, count_value, gp_value, info); + return img_format("SAVE 0x%" PRIx64 "%s", u_value, save_restore_str); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SAVEF(uint64 instruction, Dis_info *info) +{ + uint64 count_value = extract_count_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); + + + return img_format("SAVEF 0x%" PRIx64 ", 0x%" PRIx64, u_value, count_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SB_16_(uint64 instruction, Dis_info *info) +{ + uint64 rtz3_value = extract_rtz3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_1_0(instruction); + + const char *rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("SB %s, 0x%" PRIx64 "(%s)", rtz3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SB_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_0(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("SB %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SB_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SB %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SB_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SB %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SBE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SBE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SBX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SBX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SC(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SC %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SCD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_s3(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SCD %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SCDP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ru_value = extract_ru_7_6_5_4_3(instruction); + + const char *rt = GPR(rt_value, info); + const char *ru = GPR(ru_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SCDP %s, %s, (%s)", rt, ru, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SCE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SCE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SCWP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ru_value = extract_ru_7_6_5_4_3(instruction); + + const char *rt = GPR(rt_value, info); + const char *ru = GPR(ru_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SCWP %s, %s, (%s)", rt, ru, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SCWPE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ru_value = extract_ru_7_6_5_4_3(instruction); + + const char *rt = GPR(rt_value, info); + const char *ru = GPR(ru_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SCWPE %s, %s, (%s)", rt, ru, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SD_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_20_to_3__s3(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("SD %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SD_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SD %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SD_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SD %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDBBP_16_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_2_1_0(instruction); + + + return img_format("SDBBP 0x%" PRIx64, code_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDBBP_32_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_18_to_0(instruction); + + + return img_format("SDBBP 0x%" PRIx64, code_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDC1_GP_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_2__s2(instruction); + + const char *ft = FPR(ft_value, info); + + return img_format("SDC1 %s, 0x%" PRIx64 "($%d)", ft, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDC1_S9_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SDC1 %s, %" PRId64 "(%s)", ft, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDC1_U12_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SDC1 %s, 0x%" PRIx64 "(%s)", ft, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDC1X(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SDC1X %s, %s(%s)", ft, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDC1XS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SDC1XS %s, %s(%s)", ft, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDC2(uint64 instruction, Dis_info *info) +{ + uint64 cs_value = extract_cs_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("SDC2 CP%" PRIu64 ", %" PRId64 "(%s)", + cs_value, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("SDM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDPC_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 6, info); + + return img_format("SDPC %s, %s", rt, s); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SDXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SDX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SDX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SEB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SEB %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SEH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SEH %s, %s", rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SEL_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SEL.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SEL_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SEL.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SELEQZ_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SELEQZ.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SELEQZ_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SELEQZ.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SELNEZ_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SELNEZ.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SELNEZ_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SELNEZ.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SEQI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SEQI %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SH_16_(uint64 instruction, Dis_info *info) +{ + uint64 rtz3_value = extract_rtz3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_2_1__s1(instruction); + + const char *rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("SH %s, 0x%" PRIx64 "(%s)", rtz3, u_value, rs3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SH_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_1__s1(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("SH %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SH_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SH %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SH_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SH %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * [DSP] SHILO ac, shift - Shift an accumulator value leaving the result in + * the same accumulator + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000xxxx xxxx0000011101 + * shift ------ + * ac -- + */ +static char *SHILO(uint64 instruction, Dis_info *info) +{ + int64 shift_value = extract_shift__se5_21_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *ac = AC(ac_value, info); + + return img_format("SHILO %s, 0x%" PRIx64, ac, shift_value); +} + + +/* + * [DSP] SHILOV ac, rs - Variable shift of accumulator value leaving the result + * in the same accumulator + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000xxxxx 01001001111111 + * rs ----- + * ac -- + */ +static char *SHILOV(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ac_value = extract_ac_15_14(instruction); + + const char *rs = GPR(rs_value, info); + const char *ac = AC(ac_value, info); + + return img_format("SHILOV %s, %s", ac, rs); +} + + +/* + * [DSP] SHLL.PH rt, rs, sa - Shift left logical vector pair halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 001110110101 + * rt ----- + * rs ----- + * sa ---- + */ +static char *SHLL_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLL.PH %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] SHLL.QB rt, rs, sa - Shift left logical vector quad bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 0100001111111 + * rt ----- + * rs ----- + * sa --- + */ +static char *SHLL_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLL.QB %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] SHLL_S.PH rt, rs, sa - Shift left logical vector pair halfwords + * with saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 001110110101 + * rt ----- + * rs ----- + * sa ---- + */ +static char *SHLL_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLL_S.PH %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] SHLL_S.PH rt, rs, sa - Shift left logical word with saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1111110101 + * rt ----- + * rs ----- + * sa ----- + */ +static char *SHLL_S_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLL_S.W %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] SHLLV.PH rd, rt, rs - Shift left logical variable vector pair + * halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01110001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHLLV_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLLV.PH %s, %s, %s", rd, rt, rs); +} + + +/* + * [DSP] SHLLV_S.QB rd, rt, rs - Shift left logical variable vector quad bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1110010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHLLV_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLLV.QB %s, %s, %s", rd, rt, rs); +} + + +/* + * [DSP] SHLLV.PH rd, rt, rs - Shift left logical variable vector pair + * halfwords with saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11110001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHLLV_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLLV_S.PH %s, %s, %s", rd, rt, rs); +} + + +/* + * [DSP] SHLLV_S.W rd, rt, rs - Shift left logical variable vector word + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1111010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHLLV_S_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHLLV_S.W %s, %s, %s", rd, rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRA_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRA.PH %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRA_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRA.QB %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRA_R_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRA_R.PH %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRA_R_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRA_R.QB %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRA_R_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12_11(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRA_R.W %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRAV_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRAV.PH %s, %s, %s", rd, rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRAV_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRAV.QB %s, %s, %s", rd, rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRAV_R_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRAV_R.PH %s, %s, %s", rd, rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRAV_R_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRAV_R.QB %s, %s, %s", rd, rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRAV_R_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRAV_R.W %s, %s, %s", rd, rt, rs); +} + + +/* + * [DSP] SHRL.PH rt, rs, sa - Shift right logical two halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 001111111111 + * rt ----- + * rs ----- + * sa ---- + */ +static char *SHRL_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRL.PH %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] SHRL.QB rt, rs, sa - Shift right logical vector quad bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 1100001111111 + * rt ----- + * rs ----- + * sa --- + */ +static char *SHRL_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 sa_value = extract_sa_15_14_13(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRL.QB %s, %s, 0x%" PRIx64, rt, rs, sa_value); +} + + +/* + * [DSP] SHLLV.PH rd, rt, rs - Shift right logical variable vector pair of + * halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1100010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRLV_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRLV.PH %s, %s, %s", rd, rt, rs); +} + + +/* + * [DSP] SHLLV.QB rd, rt, rs - Shift right logical variable vector quad bytes + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 x1101010101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHRLV_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SHRLV.QB %s, %s, %s", rd, rt, rs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SHX %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SHXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SHXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SIGRIE(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_18_to_0(instruction); + + + return img_format("SIGRIE 0x%" PRIx64, code_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLL_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 shift3_value = extract_shift3_2_1_0(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + uint64 shift3 = encode_shift3_from_shift(shift3_value); + + return img_format("SLL %s, %s, 0x%" PRIx64, rt3, rs3, shift3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLL_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SLL %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLLV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SLLV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLT(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SLT %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLTI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SLTI %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLTIU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SLTIU %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SLTU(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SLTU %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SOV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SOV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SPECIAL2(uint64 instruction, Dis_info *info) +{ + uint64 op_value = extract_op_25_to_3(instruction); + + + return img_format("SPECIAL2 0x%" PRIx64, op_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SQRT_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("SQRT.D %s, %s", ft, fs); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SQRT_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("SQRT.S %s, %s", ft, fs); +} + + +/* + * SRA rd, rt, sa - Shift Word Right Arithmetic + * + * 3 2 1 + * 10987654321098765432109876543210 + * 00000000000 000011 + * rt ----- + * rd ----- + * sa ----- + */ +static char *SRA(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SRA %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * SRAV rd, rt, rs - Shift Word Right Arithmetic Variable + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00000000111 + * rs ----- + * rt ----- + * rd ----- + */ +static char *SRAV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SRAV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00000000111 + * rs ----- + * rt ----- + * rd ----- + */ +static char *SRL_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 shift3_value = extract_shift3_2_1_0(instruction); + + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + uint64 shift3 = encode_shift3_from_shift(shift3_value); + + return img_format("SRL %s, %s, 0x%" PRIx64, rt3, rs3, shift3); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SRL_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 shift_value = extract_shift_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SRL %s, %s, 0x%" PRIx64, rt, rs, shift_value); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SRLV(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SRLV %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUB %s, %s, %s", rd, rs, rt); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUB_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SUB.D %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUB_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + uint64 fd_value = extract_fd_15_14_13_12_11(instruction); + + const char *fd = FPR(fd_value, info); + const char *fs = FPR(fs_value, info); + const char *ft = FPR(ft_value, info); + + return img_format("SUB.S %s, %s, %s", fd, fs, ft); +} + + +/* + * + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQ_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQ.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBQ.S.PH rd, rt, rs - Subtract fractional halfword vectors and shift + * right to halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQ_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQ_S.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBQ.S.W rd, rt, rs - Subtract fractional halfword vectors and shift + * right to halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQ_S_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQ_S.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBQH.PH rd, rt, rs - Subtract fractional halfword vectors and shift + * right to halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQH_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQH.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBQH_R.PH rd, rt, rs - Subtract fractional halfword vectors and shift + * right to halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQH_R_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQH_R.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBQH_R.W rd, rt, rs - Subtract fractional halfword vectors and shift + * right to halve results with rounding + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11001001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQH_R_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQH_R.W %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBQH.W rd, rs, rt - Subtract fractional words and shift right to + * halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBQH_W(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBQH.W %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBU_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 rd3_value = extract_rd3_3_2_1(instruction); + + const char *rd3 = GPR(decode_gpr_gpr3(rd3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + + return img_format("SUBU %s, %s, %s", rd3, rs3, rt3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBU_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBU %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBU.PH rd, rs, rt - Subtract unsigned unsigned halfwords + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01100001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBU_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBU.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBU.QB rd, rs, rt - Subtract unsigned quad byte vectors + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01011001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBU_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBU.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBU_S.PH rd, rs, rt - Subtract unsigned unsigned halfwords with + * 8-bit saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11100001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBU_S_PH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBU_S.PH %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBU_S.QB rd, rs, rt - Subtract unsigned quad byte vectors with + * 8-bit saturation + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11011001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBU_S_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBU_S.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBUH.QB rd, rs, rt - Subtract unsigned bytes and right shift + * to halve results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01101001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBUH_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBUH.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * [DSP] SUBUH_R.QB rd, rs, rt - Subtract unsigned bytes and right shift + * to halve results with rounding + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 11101001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SUBUH_R_QB(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SUBUH_R.QB %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_16_(uint64 instruction, Dis_info *info) +{ + uint64 rtz3_value = extract_rtz3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + uint64 u_value = extract_u_3_2_1_0__s2(instruction); + + const char *rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value, info), info); + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + + return img_format("SW %s, 0x%" PRIx64 "(%s)", rtz3, u_value, rs3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_4X4_(uint64 instruction, Dis_info *info) +{ + uint64 rtz4_value = extract_rtz4_9_7_6_5(instruction); + uint64 rs4_value = extract_rs4_4_2_1_0(instruction); + uint64 u_value = extract_u_3_8__s2(instruction); + + const char *rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value, info), info); + const char *rs4 = GPR(decode_gpr_gpr4(rs4_value, info), info); + + return img_format("SW %s, 0x%" PRIx64 "(%s)", rtz4, u_value, rs4); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_GP16_(uint64 instruction, Dis_info *info) +{ + uint64 u_value = extract_u_6_5_4_3_2_1_0__s2(instruction); + uint64 rtz3_value = extract_rtz3_9_8_7(instruction); + + const char *rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value, info), info); + + return img_format("SW %s, 0x%" PRIx64 "($%d)", rtz3, u_value, 28); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_GP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 u_value = extract_u_20_to_2__s2(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("SW %s, 0x%" PRIx64 "($%d)", rt, u_value, 28); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_S9_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SW %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_SP_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_9_8_7_6_5(instruction); + uint64 u_value = extract_u_4_3_2_1_0__s2(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("SW %s, 0x%" PRIx64 "($%d)", rt, u_value, 29); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SW_U12_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SW %s, 0x%" PRIx64 "(%s)", rt, u_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWC1_GP_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 u_value = extract_u_17_to_2__s2(instruction); + + const char *ft = FPR(ft_value, info); + + return img_format("SWC1 %s, 0x%" PRIx64 "($%d)", ft, u_value, 28); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWC1_S9_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SWC1 %s, %" PRId64 "(%s)", ft, s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWC1_U12_(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SWC1 %s, 0x%" PRIx64 "(%s)", ft, u_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWC1X(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SWC1X %s, %s(%s)", ft, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWC1XS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 ft_value = extract_ft_15_14_13_12_11(instruction); + + const char *ft = FPR(ft_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SWC1XS %s, %s(%s)", ft, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWC2(uint64 instruction, Dis_info *info) +{ + uint64 cs_value = extract_cs_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("SWC2 CP%" PRIu64 ", %" PRId64 "(%s)", + cs_value, s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("SWE %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("SWM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWPC_48_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_41_40_39_38_37(instruction); + int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); + + const char *rt = GPR(rt_value, info); + g_autofree char *s = ADDRESS(s_value, 6, info); + + return img_format("SWPC %s, %s", rt, s); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWX(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SWX %s, %s(%s)", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SWXS(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("SWXS %s, %s(%s)", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SYNC(uint64 instruction, Dis_info *info) +{ + uint64 stype_value = extract_stype_20_19_18_17_16(instruction); + + + return img_format("SYNC 0x%" PRIx64, stype_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SYNCI(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("SYNCI %" PRId64 "(%s)", s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SYNCIE(uint64 instruction, Dis_info *info) +{ + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rs = GPR(rs_value, info); + + return img_format("SYNCIE %" PRId64 "(%s)", s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *SYSCALL_16_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_1_0(instruction); + + + return img_format("SYSCALL 0x%" PRIx64, code_value); +} + + +/* + * SYSCALL code - System Call. Cause a System Call Exception + * + * 3 2 1 + * 10987654321098765432109876543210 + * 00000000000010 + * code ------------------ + */ +static char *SYSCALL_32_(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_17_to_0(instruction); + + + return img_format("SYSCALL 0x%" PRIx64, code_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TEQ(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("TEQ %s, %s", rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBGINV(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBGINV "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBGINVF(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBGINVF "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBGP(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBGP "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBGR(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBGR "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBGWI(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBGWI "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBGWR(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBGWR "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBINV(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBINV "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBINVF(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBINVF "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBP(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBP "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBR(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBR "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBWI(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBWI "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TLBWR(uint64 instruction, Dis_info *info) +{ + (void)instruction; + + return g_strdup("TLBWR "); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TNE(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("TNE %s, %s", rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TRUNC_L_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("TRUNC.L.D %s, %s", ft, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TRUNC_L_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("TRUNC.L.S %s, %s", ft, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TRUNC_W_D(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("TRUNC.W.D %s, %s", ft, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *TRUNC_W_S(uint64 instruction, Dis_info *info) +{ + uint64 ft_value = extract_ft_25_24_23_22_21(instruction); + uint64 fs_value = extract_fs_20_19_18_17_16(instruction); + + const char *ft = FPR(ft_value, info); + const char *fs = FPR(fs_value, info); + + return img_format("TRUNC.W.S %s, %s", ft, fs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UALDM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("UALDM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UALH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("UALH %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UALWM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("UALWM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UASDM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("UASDM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UASH(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("UASH %s, %" PRId64 "(%s)", rt, s_value, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UASWM(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); + uint64 count3_value = extract_count3_14_13_12(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + uint64 count3 = encode_count3_from_count(count3_value); + + return img_format("UASWM %s, %" PRId64 "(%s), 0x%" PRIx64, + rt, s_value, rs, count3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *UDI(uint64 instruction, Dis_info *info) +{ + uint64 op_value = extract_op_25_to_3(instruction); + + + return img_format("UDI 0x%" PRIx64, op_value); +} + + +/* + * WAIT code - Enter Wait State + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 1100001101111111 + * code ---------- + */ +static char *WAIT(uint64 instruction, Dis_info *info) +{ + uint64 code_value = extract_code_25_24_23_22_21_20_19_18_17_16(instruction); + + + return img_format("WAIT 0x%" PRIx64, code_value); +} + + +/* + * [DSP] WRDSP rt, mask - Write selected fields from a GPR to the DSPControl + * register + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 01011001111111 + * rt ----- + * mask ------- + */ +static char *WRDSP(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 mask_value = extract_mask_20_19_18_17_16_15_14(instruction); + + const char *rt = GPR(rt_value, info); + + return img_format("WRDSP %s, 0x%" PRIx64, rt, mask_value); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *WRPGPR(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("WRPGPR %s, %s", rt, rs); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *XOR_16_(uint64 instruction, Dis_info *info) +{ + uint64 rt3_value = extract_rt3_9_8_7(instruction); + uint64 rs3_value = extract_rs3_6_5_4(instruction); + + const char *rs3 = GPR(decode_gpr_gpr3(rs3_value, info), info); + const char *rt3 = GPR(decode_gpr_gpr3(rt3_value, info), info); + + return img_format("XOR %s, %s", rs3, rt3); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *XOR_32_(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 rd_value = extract_rd_15_14_13_12_11(instruction); + + const char *rd = GPR(rd_value, info); + const char *rs = GPR(rs_value, info); + const char *rt = GPR(rt_value, info); + + return img_format("XOR %s, %s, %s", rd, rs, rt); +} + + +/* + * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + * rd ----- + */ +static char *XORI(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("XORI %s, %s, 0x%" PRIx64, rt, rs, u_value); +} + + +/* + * YIELD rt, rs - + * + * 3 2 1 + * 10987654321098765432109876543210 + * 001000 00010001101 + * rt ----- + * rs ----- + */ +static char *YIELD(uint64 instruction, Dis_info *info) +{ + uint64 rt_value = extract_rt_25_24_23_22_21(instruction); + uint64 rs_value = extract_rs_20_19_18_17_16(instruction); + + const char *rt = GPR(rt_value, info); + const char *rs = GPR(rs_value, info); + + return img_format("YIELD %s, %s", rt, rs); +} + + + +/* + * nanoMIPS instruction pool organization + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * + * ┌─ P.ADDIU ─── P.RI ─── P.SYSCALL + * │ + * │ ┌─ P.TRAP + * │ │ + * │ ┌─ _POOL32A0_0 ─┼─ P.CMOVE + * │ │ │ + * │ │ └─ P.SLTU + * │ ┌─ _POOL32A0 ─┤ + * │ │ │ + * │ │ │ + * │ │ └─ _POOL32A0_1 ─── CRC32 + * │ │ + * ├─ P32A ─┤ + * │ │ ┌─ PP.LSX + * │ │ ┌─ P.LSX ─────┤ + * │ │ │ └─ PP.LSXS + * │ └─ _POOL32A7 ─┤ + * │ │ ┌─ POOL32Axf_4 + * │ └─ POOL32Axf ─┤ + * │ └─ POOL32Axf_5 + * │ + * ├─ PBAL + * │ + * ├─ P.GP.W ┌─ PP.LSX + * ┌─ P32 ─┤ │ + * │ ├─ P.GP.BH ─┴─ PP.LSXS + * │ │ + * │ ├─ P.J ─────── PP.BALRSC + * │ │ + * │ ├─ P48I + * │ │ ┌─ P.SR + * │ │ │ + * │ │ ├─ P.SHIFT + * │ │ │ + * │ ├─ P.U12 ───┼─ P.ROTX + * │ │ │ + * │ │ ├─ P.INS + * │ │ │ + * │ │ └─ P.EXT + * │ │ + * │ ├─ P.LS.U12 ── P.PREF.U12 + * │ │ + * │ ├─ P.BR1 ───── P.BR3A + * │ │ + * │ │ ┌─ P.LS.S0 ─── P16.SYSCALL + * │ │ │ + * │ │ │ ┌─ P.LL + * │ │ ├─ P.LS.S1 ─┤ + * │ │ │ └─ P.SC + * │ │ │ + * │ │ │ ┌─ P.PREFE + * MAJOR ─┤ ├─ P.LS.S9 ─┤ │ + * │ │ ├─ P.LS.E0 ─┼─ P.LLE + * │ │ │ │ + * │ │ │ └─ P.SCE + * │ │ │ + * │ │ ├─ P.LS.WM + * │ │ │ + * │ │ └─ P.LS.UAWM + * │ │ + * │ │ + * │ ├─ P.BR2 + * │ │ + * │ ├─ P.BRI + * │ │ + * │ └─ P.LUI + * │ + * │ + * │ ┌─ P16.MV ──── P16.RI ─── P16.SYSCALL + * │ │ + * │ ├─ P16.SR + * │ │ + * │ ├─ P16.SHIFT + * │ │ + * │ ├─ P16.4x4 + * │ │ + * │ ├─ P16C ────── POOL16C_0 ── POOL16C_00 + * │ │ + * └─ P16 ─┼─ P16.LB + * │ + * ├─ P16.A1 + * │ + * ├─ P16.LH + * │ + * ├─ P16.A2 ──── P.ADDIU[RS5] + * │ + * ├─ P16.ADDU + * │ + * └─ P16.BR ──┬─ P16.JRC + * │ + * └─ P16.BR1 + * + * + * (FP, DPS, and some minor instruction pools are omitted from the diagram) + * + */ + +static const Pool P_SYSCALL[2] = { + { instruction , 0 , 0 , 32, + 0xfffc0000, 0x00080000, &SYSCALL_32_ , 0, + 0x0 }, /* SYSCALL[32] */ + { instruction , 0 , 0 , 32, + 0xfffc0000, 0x000c0000, &HYPCALL , 0, + CP0_ | VZ_ }, /* HYPCALL */ +}; + + +static const Pool P_RI[4] = { + { instruction , 0 , 0 , 32, + 0xfff80000, 0x00000000, &SIGRIE , 0, + 0x0 }, /* SIGRIE */ + { pool , P_SYSCALL , 2 , 32, + 0xfff80000, 0x00080000, 0 , 0, + 0x0 }, /* P.SYSCALL */ + { instruction , 0 , 0 , 32, + 0xfff80000, 0x00100000, &BREAK_32_ , 0, + 0x0 }, /* BREAK[32] */ + { instruction , 0 , 0 , 32, + 0xfff80000, 0x00180000, &SDBBP_32_ , 0, + EJTAG_ }, /* SDBBP[32] */ +}; + + +static const Pool P_ADDIU[2] = { + { pool , P_RI , 4 , 32, + 0xffe00000, 0x00000000, 0 , 0, + 0x0 }, /* P.RI */ + { instruction , 0 , 0 , 32, + 0xfc000000, 0x00000000, &ADDIU_32_ , &ADDIU_32__cond , + 0x0 }, /* ADDIU[32] */ +}; + + +static const Pool P_TRAP[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000000, &TEQ , 0, + XMMS_ }, /* TEQ */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000400, &TNE , 0, + XMMS_ }, /* TNE */ +}; + + +static const Pool P_CMOVE[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000210, &MOVZ , 0, + 0x0 }, /* MOVZ */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000610, &MOVN , 0, + 0x0 }, /* MOVN */ +}; + + +static const Pool P_D_MT_VPE[2] = { + { instruction , 0 , 0 , 32, + 0xfc1f3fff, 0x20010ab0, &DMT , 0, + MT_ }, /* DMT */ + { instruction , 0 , 0 , 32, + 0xfc1f3fff, 0x20000ab0, &DVPE , 0, + MT_ }, /* DVPE */ +}; + + +static const Pool P_E_MT_VPE[2] = { + { instruction , 0 , 0 , 32, + 0xfc1f3fff, 0x20010eb0, &EMT , 0, + MT_ }, /* EMT */ + { instruction , 0 , 0 , 32, + 0xfc1f3fff, 0x20000eb0, &EVPE , 0, + MT_ }, /* EVPE */ +}; + + +static const Pool _P_MT_VPE[2] = { + { pool , P_D_MT_VPE , 2 , 32, + 0xfc003fff, 0x20000ab0, 0 , 0, + 0x0 }, /* P.D_MT_VPE */ + { pool , P_E_MT_VPE , 2 , 32, + 0xfc003fff, 0x20000eb0, 0 , 0, + 0x0 }, /* P.E_MT_VPE */ +}; + + +static const Pool P_MT_VPE[8] = { + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x200002b0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(0) */ + { pool , _P_MT_VPE , 2 , 32, + 0xfc003bff, 0x20000ab0, 0 , 0, + 0x0 }, /* _P.MT_VPE */ + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x200012b0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x20001ab0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x200022b0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x20002ab0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x200032b0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc003bff, 0x20003ab0, 0 , 0, + 0x0 }, /* P.MT_VPE~*(7) */ +}; + + +static const Pool P_DVP[2] = { + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20000390, &DVP , 0, + 0x0 }, /* DVP */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20000790, &EVP , 0, + 0x0 }, /* EVP */ +}; + + +static const Pool P_SLTU[2] = { + { pool , P_DVP , 2 , 32, + 0xfc00fbff, 0x20000390, 0 , 0, + 0x0 }, /* P.DVP */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000390, &SLTU , &SLTU_cond , + 0x0 }, /* SLTU */ +}; + + +static const Pool _POOL32A0[128] = { + { pool , P_TRAP , 2 , 32, + 0xfc0003ff, 0x20000000, 0 , 0, + 0x0 }, /* P.TRAP */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000008, &SEB , 0, + XMMS_ }, /* SEB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000010, &SLLV , 0, + 0x0 }, /* SLLV */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000018, &MUL_32_ , 0, + 0x0 }, /* MUL[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000020, 0 , 0, + 0x0 }, /* _POOL32A0~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000028, 0 , 0, + 0x0 }, /* _POOL32A0~*(5) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000030, &MFC0 , 0, + 0x0 }, /* MFC0 */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000038, &MFHC0 , 0, + CP0_ | MVH_ }, /* MFHC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000040, 0 , 0, + 0x0 }, /* _POOL32A0~*(8) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000048, &SEH , 0, + 0x0 }, /* SEH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000050, &SRLV , 0, + 0x0 }, /* SRLV */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000058, &MUH , 0, + 0x0 }, /* MUH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000060, 0 , 0, + 0x0 }, /* _POOL32A0~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000068, 0 , 0, + 0x0 }, /* _POOL32A0~*(13) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000070, &MTC0 , 0, + CP0_ }, /* MTC0 */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000078, &MTHC0 , 0, + CP0_ | MVH_ }, /* MTHC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000080, 0 , 0, + 0x0 }, /* _POOL32A0~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000088, 0 , 0, + 0x0 }, /* _POOL32A0~*(17) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000090, &SRAV , 0, + 0x0 }, /* SRAV */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000098, &MULU , 0, + 0x0 }, /* MULU */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000a0, 0 , 0, + 0x0 }, /* _POOL32A0~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000a8, 0 , 0, + 0x0 }, /* _POOL32A0~*(21) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000b0, &MFGC0 , 0, + CP0_ | VZ_ }, /* MFGC0 */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000b8, &MFHGC0 , 0, + CP0_ | VZ_ | MVH_ }, /* MFHGC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000c0, 0 , 0, + 0x0 }, /* _POOL32A0~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000c8, 0 , 0, + 0x0 }, /* _POOL32A0~*(25) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000d0, &ROTRV , 0, + 0x0 }, /* ROTRV */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000d8, &MUHU , 0, + 0x0 }, /* MUHU */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000e0, 0 , 0, + 0x0 }, /* _POOL32A0~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000e8, 0 , 0, + 0x0 }, /* _POOL32A0~*(29) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000f0, &MTGC0 , 0, + CP0_ | VZ_ }, /* MTGC0 */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000f8, &MTHGC0 , 0, + CP0_ | VZ_ | MVH_ }, /* MTHGC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000100, 0 , 0, + 0x0 }, /* _POOL32A0~*(32) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000108, 0 , 0, + 0x0 }, /* _POOL32A0~*(33) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000110, &ADD , 0, + XMMS_ }, /* ADD */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000118, &DIV , 0, + 0x0 }, /* DIV */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000120, 0 , 0, + 0x0 }, /* _POOL32A0~*(36) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000128, 0 , 0, + 0x0 }, /* _POOL32A0~*(37) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000130, &DMFC0 , 0, + CP0_ | MIPS64_ }, /* DMFC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000138, 0 , 0, + 0x0 }, /* _POOL32A0~*(39) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000140, 0 , 0, + 0x0 }, /* _POOL32A0~*(40) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000148, 0 , 0, + 0x0 }, /* _POOL32A0~*(41) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000150, &ADDU_32_ , 0, + 0x0 }, /* ADDU[32] */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000158, &MOD , 0, + 0x0 }, /* MOD */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000160, 0 , 0, + 0x0 }, /* _POOL32A0~*(44) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000168, 0 , 0, + 0x0 }, /* _POOL32A0~*(45) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000170, &DMTC0 , 0, + CP0_ | MIPS64_ }, /* DMTC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000178, 0 , 0, + 0x0 }, /* _POOL32A0~*(47) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000180, 0 , 0, + 0x0 }, /* _POOL32A0~*(48) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000188, 0 , 0, + 0x0 }, /* _POOL32A0~*(49) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000190, &SUB , 0, + XMMS_ }, /* SUB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000198, &DIVU , 0, + 0x0 }, /* DIVU */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001a0, 0 , 0, + 0x0 }, /* _POOL32A0~*(52) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001a8, 0 , 0, + 0x0 }, /* _POOL32A0~*(53) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001b0, &DMFGC0 , 0, + CP0_ | MIPS64_ | VZ_}, /* DMFGC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001b8, 0 , 0, + 0x0 }, /* _POOL32A0~*(55) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001c0, &RDHWR , 0, + XMMS_ }, /* RDHWR */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001c8, 0 , 0, + 0x0 }, /* _POOL32A0~*(57) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001d0, &SUBU_32_ , 0, + 0x0 }, /* SUBU[32] */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001d8, &MODU , 0, + 0x0 }, /* MODU */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001e0, 0 , 0, + 0x0 }, /* _POOL32A0~*(60) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001e8, 0 , 0, + 0x0 }, /* _POOL32A0~*(61) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001f0, &DMTGC0 , 0, + CP0_ | MIPS64_ | VZ_}, /* DMTGC0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001f8, 0 , 0, + 0x0 }, /* _POOL32A0~*(63) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000200, 0 , 0, + 0x0 }, /* _POOL32A0~*(64) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000208, 0 , 0, + 0x0 }, /* _POOL32A0~*(65) */ + { pool , P_CMOVE , 2 , 32, + 0xfc0003ff, 0x20000210, 0 , 0, + 0x0 }, /* P.CMOVE */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000218, 0 , 0, + 0x0 }, /* _POOL32A0~*(67) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000220, 0 , 0, + 0x0 }, /* _POOL32A0~*(68) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000228, &FORK , 0, + MT_ }, /* FORK */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000230, &MFTR , 0, + MT_ }, /* MFTR */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000238, &MFHTR , 0, + MT_ }, /* MFHTR */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000240, 0 , 0, + 0x0 }, /* _POOL32A0~*(72) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000248, 0 , 0, + 0x0 }, /* _POOL32A0~*(73) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000250, &AND_32_ , 0, + 0x0 }, /* AND[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000258, 0 , 0, + 0x0 }, /* _POOL32A0~*(75) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000260, 0 , 0, + 0x0 }, /* _POOL32A0~*(76) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000268, &YIELD , 0, + MT_ }, /* YIELD */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000270, &MTTR , 0, + MT_ }, /* MTTR */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000278, &MTHTR , 0, + MT_ }, /* MTHTR */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000280, 0 , 0, + 0x0 }, /* _POOL32A0~*(80) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000288, 0 , 0, + 0x0 }, /* _POOL32A0~*(81) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000290, &OR_32_ , 0, + 0x0 }, /* OR[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000298, 0 , 0, + 0x0 }, /* _POOL32A0~*(83) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002a0, 0 , 0, + 0x0 }, /* _POOL32A0~*(84) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002a8, 0 , 0, + 0x0 }, /* _POOL32A0~*(85) */ + { pool , P_MT_VPE , 8 , 32, + 0xfc0003ff, 0x200002b0, 0 , 0, + 0x0 }, /* P.MT_VPE */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002b8, 0 , 0, + 0x0 }, /* _POOL32A0~*(87) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002c0, 0 , 0, + 0x0 }, /* _POOL32A0~*(88) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002c8, 0 , 0, + 0x0 }, /* _POOL32A0~*(89) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200002d0, &NOR , 0, + 0x0 }, /* NOR */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002d8, 0 , 0, + 0x0 }, /* _POOL32A0~*(91) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002e0, 0 , 0, + 0x0 }, /* _POOL32A0~*(92) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002e8, 0 , 0, + 0x0 }, /* _POOL32A0~*(93) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002f0, 0 , 0, + 0x0 }, /* _POOL32A0~*(94) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002f8, 0 , 0, + 0x0 }, /* _POOL32A0~*(95) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000300, 0 , 0, + 0x0 }, /* _POOL32A0~*(96) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000308, 0 , 0, + 0x0 }, /* _POOL32A0~*(97) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000310, &XOR_32_ , 0, + 0x0 }, /* XOR[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000318, 0 , 0, + 0x0 }, /* _POOL32A0~*(99) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000320, 0 , 0, + 0x0 }, /* _POOL32A0~*(100) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000328, 0 , 0, + 0x0 }, /* _POOL32A0~*(101) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000330, 0 , 0, + 0x0 }, /* _POOL32A0~*(102) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000338, 0 , 0, + 0x0 }, /* _POOL32A0~*(103) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000340, 0 , 0, + 0x0 }, /* _POOL32A0~*(104) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000348, 0 , 0, + 0x0 }, /* _POOL32A0~*(105) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000350, &SLT , 0, + 0x0 }, /* SLT */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000358, 0 , 0, + 0x0 }, /* _POOL32A0~*(107) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000360, 0 , 0, + 0x0 }, /* _POOL32A0~*(108) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000368, 0 , 0, + 0x0 }, /* _POOL32A0~*(109) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000370, 0 , 0, + 0x0 }, /* _POOL32A0~*(110) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000378, 0 , 0, + 0x0 }, /* _POOL32A0~*(111) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000380, 0 , 0, + 0x0 }, /* _POOL32A0~*(112) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000388, 0 , 0, + 0x0 }, /* _POOL32A0~*(113) */ + { pool , P_SLTU , 2 , 32, + 0xfc0003ff, 0x20000390, 0 , 0, + 0x0 }, /* P.SLTU */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000398, 0 , 0, + 0x0 }, /* _POOL32A0~*(115) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003a0, 0 , 0, + 0x0 }, /* _POOL32A0~*(116) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003a8, 0 , 0, + 0x0 }, /* _POOL32A0~*(117) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003b0, 0 , 0, + 0x0 }, /* _POOL32A0~*(118) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003b8, 0 , 0, + 0x0 }, /* _POOL32A0~*(119) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003c0, 0 , 0, + 0x0 }, /* _POOL32A0~*(120) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003c8, 0 , 0, + 0x0 }, /* _POOL32A0~*(121) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200003d0, &SOV , 0, + 0x0 }, /* SOV */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003d8, 0 , 0, + 0x0 }, /* _POOL32A0~*(123) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003e0, 0 , 0, + 0x0 }, /* _POOL32A0~*(124) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003e8, 0 , 0, + 0x0 }, /* _POOL32A0~*(125) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003f0, 0 , 0, + 0x0 }, /* _POOL32A0~*(126) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003f8, 0 , 0, + 0x0 }, /* _POOL32A0~*(127) */ +}; + + +static const Pool ADDQ__S__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000000d, &ADDQ_PH , 0, + DSP_ }, /* ADDQ.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000040d, &ADDQ_S_PH , 0, + DSP_ }, /* ADDQ_S.PH */ +}; + + +static const Pool MUL__S__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000002d, &MUL_PH , 0, + DSP_ }, /* MUL.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000042d, &MUL_S_PH , 0, + DSP_ }, /* MUL_S.PH */ +}; + + +static const Pool ADDQH__R__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000004d, &ADDQH_PH , 0, + DSP_ }, /* ADDQH.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000044d, &ADDQH_R_PH , 0, + DSP_ }, /* ADDQH_R.PH */ +}; + + +static const Pool ADDQH__R__W[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000008d, &ADDQH_W , 0, + DSP_ }, /* ADDQH.W */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000048d, &ADDQH_R_W , 0, + DSP_ }, /* ADDQH_R.W */ +}; + + +static const Pool ADDU__S__QB[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200000cd, &ADDU_QB , 0, + DSP_ }, /* ADDU.QB */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200004cd, &ADDU_S_QB , 0, + DSP_ }, /* ADDU_S.QB */ +}; + + +static const Pool ADDU__S__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000010d, &ADDU_PH , 0, + DSP_ }, /* ADDU.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000050d, &ADDU_S_PH , 0, + DSP_ }, /* ADDU_S.PH */ +}; + + +static const Pool ADDUH__R__QB[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000014d, &ADDUH_QB , 0, + DSP_ }, /* ADDUH.QB */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000054d, &ADDUH_R_QB , 0, + DSP_ }, /* ADDUH_R.QB */ +}; + + +static const Pool SHRAV__R__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000018d, &SHRAV_PH , 0, + DSP_ }, /* SHRAV.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000058d, &SHRAV_R_PH , 0, + DSP_ }, /* SHRAV_R.PH */ +}; + + +static const Pool SHRAV__R__QB[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200001cd, &SHRAV_QB , 0, + DSP_ }, /* SHRAV.QB */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200005cd, &SHRAV_R_QB , 0, + DSP_ }, /* SHRAV_R.QB */ +}; + + +static const Pool SUBQ__S__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000020d, &SUBQ_PH , 0, + DSP_ }, /* SUBQ.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000060d, &SUBQ_S_PH , 0, + DSP_ }, /* SUBQ_S.PH */ +}; + + +static const Pool SUBQH__R__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000024d, &SUBQH_PH , 0, + DSP_ }, /* SUBQH.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000064d, &SUBQH_R_PH , 0, + DSP_ }, /* SUBQH_R.PH */ +}; + + +static const Pool SUBQH__R__W[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000028d, &SUBQH_W , 0, + DSP_ }, /* SUBQH.W */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000068d, &SUBQH_R_W , 0, + DSP_ }, /* SUBQH_R.W */ +}; + + +static const Pool SUBU__S__QB[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200002cd, &SUBU_QB , 0, + DSP_ }, /* SUBU.QB */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200006cd, &SUBU_S_QB , 0, + DSP_ }, /* SUBU_S.QB */ +}; + + +static const Pool SUBU__S__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000030d, &SUBU_PH , 0, + DSP_ }, /* SUBU.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000070d, &SUBU_S_PH , 0, + DSP_ }, /* SUBU_S.PH */ +}; + + +static const Pool SHRA__R__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000335, &SHRA_PH , 0, + DSP_ }, /* SHRA.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000735, &SHRA_R_PH , 0, + DSP_ }, /* SHRA_R.PH */ +}; + + +static const Pool SUBUH__R__QB[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000034d, &SUBUH_QB , 0, + DSP_ }, /* SUBUH.QB */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000074d, &SUBUH_R_QB , 0, + DSP_ }, /* SUBUH_R.QB */ +}; + + +static const Pool SHLLV__S__PH[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000038d, &SHLLV_PH , 0, + DSP_ }, /* SHLLV.PH */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x2000078d, &SHLLV_S_PH , 0, + DSP_ }, /* SHLLV_S.PH */ +}; + + +static const Pool SHLL__S__PH[4] = { + { instruction , 0 , 0 , 32, + 0xfc000fff, 0x200003b5, &SHLL_PH , 0, + DSP_ }, /* SHLL.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x200007b5, 0 , 0, + 0x0 }, /* SHLL[_S].PH~*(1) */ + { instruction , 0 , 0 , 32, + 0xfc000fff, 0x20000bb5, &SHLL_S_PH , 0, + DSP_ }, /* SHLL_S.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x20000fb5, 0 , 0, + 0x0 }, /* SHLL[_S].PH~*(3) */ +}; + + +static const Pool PRECR_SRA__R__PH_W[2] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200003cd, &PRECR_SRA_PH_W , 0, + DSP_ }, /* PRECR_SRA.PH.W */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200007cd, &PRECR_SRA_R_PH_W , 0, + DSP_ }, /* PRECR_SRA_R.PH.W */ +}; + + +static const Pool _POOL32A5[128] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000005, &CMP_EQ_PH , 0, + DSP_ }, /* CMP.EQ.PH */ + { pool , ADDQ__S__PH , 2 , 32, + 0xfc0003ff, 0x2000000d, 0 , 0, + 0x0 }, /* ADDQ[_S].PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000015, 0 , 0, + 0x0 }, /* _POOL32A5~*(2) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x2000001d, &SHILO , 0, + DSP_ }, /* SHILO */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000025, &MULEQ_S_W_PHL , 0, + DSP_ }, /* MULEQ_S.W.PHL */ + { pool , MUL__S__PH , 2 , 32, + 0xfc0003ff, 0x2000002d, 0 , 0, + 0x0 }, /* MUL[_S].PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000035, 0 , 0, + 0x0 }, /* _POOL32A5~*(6) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x2000003d, &REPL_PH , 0, + DSP_ }, /* REPL.PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000045, &CMP_LT_PH , 0, + DSP_ }, /* CMP.LT.PH */ + { pool , ADDQH__R__PH , 2 , 32, + 0xfc0003ff, 0x2000004d, 0 , 0, + 0x0 }, /* ADDQH[_R].PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000055, 0 , 0, + 0x0 }, /* _POOL32A5~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000005d, 0 , 0, + 0x0 }, /* _POOL32A5~*(11) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000065, &MULEQ_S_W_PHR , 0, + DSP_ }, /* MULEQ_S.W.PHR */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x2000006d, &PRECR_QB_PH , 0, + DSP_ }, /* PRECR.QB.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000075, 0 , 0, + 0x0 }, /* _POOL32A5~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000007d, 0 , 0, + 0x0 }, /* _POOL32A5~*(15) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000085, &CMP_LE_PH , 0, + DSP_ }, /* CMP.LE.PH */ + { pool , ADDQH__R__W , 2 , 32, + 0xfc0003ff, 0x2000008d, 0 , 0, + 0x0 }, /* ADDQH[_R].W */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000095, &MULEU_S_PH_QBL , 0, + DSP_ }, /* MULEU_S.PH.QBL */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000009d, 0 , 0, + 0x0 }, /* _POOL32A5~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000a5, 0 , 0, + 0x0 }, /* _POOL32A5~*(20) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000ad, &PRECRQ_QB_PH , 0, + DSP_ }, /* PRECRQ.QB.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000b5, 0 , 0, + 0x0 }, /* _POOL32A5~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000bd, 0 , 0, + 0x0 }, /* _POOL32A5~*(23) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000c5, &CMPGU_EQ_QB , 0, + DSP_ }, /* CMPGU.EQ.QB */ + { pool , ADDU__S__QB , 2 , 32, + 0xfc0003ff, 0x200000cd, 0 , 0, + 0x0 }, /* ADDU[_S].QB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000d5, &MULEU_S_PH_QBR , 0, + DSP_ }, /* MULEU_S.PH.QBR */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000dd, 0 , 0, + 0x0 }, /* _POOL32A5~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000e5, 0 , 0, + 0x0 }, /* _POOL32A5~*(28) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200000ed, &PRECRQ_PH_W , 0, + DSP_ }, /* PRECRQ.PH.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000f5, 0 , 0, + 0x0 }, /* _POOL32A5~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200000fd, 0 , 0, + 0x0 }, /* _POOL32A5~*(31) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000105, &CMPGU_LT_QB , 0, + DSP_ }, /* CMPGU.LT.QB */ + { pool , ADDU__S__PH , 2 , 32, + 0xfc0003ff, 0x2000010d, 0 , 0, + 0x0 }, /* ADDU[_S].PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000115, &MULQ_RS_PH , 0, + DSP_ }, /* MULQ_RS.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000011d, 0 , 0, + 0x0 }, /* _POOL32A5~*(35) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000125, 0 , 0, + 0x0 }, /* _POOL32A5~*(36) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x2000012d, &PRECRQ_RS_PH_W , 0, + DSP_ }, /* PRECRQ_RS.PH.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000135, 0 , 0, + 0x0 }, /* _POOL32A5~*(38) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000013d, 0 , 0, + 0x0 }, /* _POOL32A5~*(39) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000145, &CMPGU_LE_QB , 0, + DSP_ }, /* CMPGU.LE.QB */ + { pool , ADDUH__R__QB , 2 , 32, + 0xfc0003ff, 0x2000014d, 0 , 0, + 0x0 }, /* ADDUH[_R].QB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000155, &MULQ_S_PH , 0, + DSP_ }, /* MULQ_S.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000015d, 0 , 0, + 0x0 }, /* _POOL32A5~*(43) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000165, 0 , 0, + 0x0 }, /* _POOL32A5~*(44) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x2000016d, &PRECRQU_S_QB_PH , 0, + DSP_ }, /* PRECRQU_S.QB.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000175, 0 , 0, + 0x0 }, /* _POOL32A5~*(46) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000017d, 0 , 0, + 0x0 }, /* _POOL32A5~*(47) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000185, &CMPGDU_EQ_QB , 0, + DSP_ }, /* CMPGDU.EQ.QB */ + { pool , SHRAV__R__PH , 2 , 32, + 0xfc0003ff, 0x2000018d, 0 , 0, + 0x0 }, /* SHRAV[_R].PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000195, &MULQ_RS_W , 0, + DSP_ }, /* MULQ_RS.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000019d, 0 , 0, + 0x0 }, /* _POOL32A5~*(51) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001a5, 0 , 0, + 0x0 }, /* _POOL32A5~*(52) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001ad, &PACKRL_PH , 0, + DSP_ }, /* PACKRL.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001b5, 0 , 0, + 0x0 }, /* _POOL32A5~*(54) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001bd, 0 , 0, + 0x0 }, /* _POOL32A5~*(55) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001c5, &CMPGDU_LT_QB , 0, + DSP_ }, /* CMPGDU.LT.QB */ + { pool , SHRAV__R__QB , 2 , 32, + 0xfc0003ff, 0x200001cd, 0 , 0, + 0x0 }, /* SHRAV[_R].QB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001d5, &MULQ_S_W , 0, + DSP_ }, /* MULQ_S.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001dd, 0 , 0, + 0x0 }, /* _POOL32A5~*(59) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001e5, 0 , 0, + 0x0 }, /* _POOL32A5~*(60) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200001ed, &PICK_QB , 0, + DSP_ }, /* PICK.QB */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001f5, 0 , 0, + 0x0 }, /* _POOL32A5~*(62) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200001fd, 0 , 0, + 0x0 }, /* _POOL32A5~*(63) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000205, &CMPGDU_LE_QB , 0, + DSP_ }, /* CMPGDU.LE.QB */ + { pool , SUBQ__S__PH , 2 , 32, + 0xfc0003ff, 0x2000020d, 0 , 0, + 0x0 }, /* SUBQ[_S].PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000215, &APPEND , 0, + DSP_ }, /* APPEND */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000021d, 0 , 0, + 0x0 }, /* _POOL32A5~*(67) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000225, 0 , 0, + 0x0 }, /* _POOL32A5~*(68) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x2000022d, &PICK_PH , 0, + DSP_ }, /* PICK.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000235, 0 , 0, + 0x0 }, /* _POOL32A5~*(70) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000023d, 0 , 0, + 0x0 }, /* _POOL32A5~*(71) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000245, &CMPU_EQ_QB , 0, + DSP_ }, /* CMPU.EQ.QB */ + { pool , SUBQH__R__PH , 2 , 32, + 0xfc0003ff, 0x2000024d, 0 , 0, + 0x0 }, /* SUBQH[_R].PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000255, &PREPEND , 0, + DSP_ }, /* PREPEND */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000025d, 0 , 0, + 0x0 }, /* _POOL32A5~*(75) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000265, 0 , 0, + 0x0 }, /* _POOL32A5~*(76) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000026d, 0 , 0, + 0x0 }, /* _POOL32A5~*(77) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000275, 0 , 0, + 0x0 }, /* _POOL32A5~*(78) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000027d, 0 , 0, + 0x0 }, /* _POOL32A5~*(79) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000285, &CMPU_LT_QB , 0, + DSP_ }, /* CMPU.LT.QB */ + { pool , SUBQH__R__W , 2 , 32, + 0xfc0003ff, 0x2000028d, 0 , 0, + 0x0 }, /* SUBQH[_R].W */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000295, &MODSUB , 0, + DSP_ }, /* MODSUB */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000029d, 0 , 0, + 0x0 }, /* _POOL32A5~*(83) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002a5, 0 , 0, + 0x0 }, /* _POOL32A5~*(84) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002ad, 0 , 0, + 0x0 }, /* _POOL32A5~*(85) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002b5, 0 , 0, + 0x0 }, /* _POOL32A5~*(86) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002bd, 0 , 0, + 0x0 }, /* _POOL32A5~*(87) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200002c5, &CMPU_LE_QB , 0, + DSP_ }, /* CMPU.LE.QB */ + { pool , SUBU__S__QB , 2 , 32, + 0xfc0003ff, 0x200002cd, 0 , 0, + 0x0 }, /* SUBU[_S].QB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200002d5, &SHRAV_R_W , 0, + DSP_ }, /* SHRAV_R.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002dd, 0 , 0, + 0x0 }, /* _POOL32A5~*(91) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002e5, 0 , 0, + 0x0 }, /* _POOL32A5~*(92) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002ed, 0 , 0, + 0x0 }, /* _POOL32A5~*(93) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200002f5, &SHRA_R_W , 0, + DSP_ }, /* SHRA_R.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200002fd, 0 , 0, + 0x0 }, /* _POOL32A5~*(95) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000305, &ADDQ_S_W , 0, + DSP_ }, /* ADDQ_S.W */ + { pool , SUBU__S__PH , 2 , 32, + 0xfc0003ff, 0x2000030d, 0 , 0, + 0x0 }, /* SUBU[_S].PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000315, &SHRLV_PH , 0, + DSP_ }, /* SHRLV.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000031d, 0 , 0, + 0x0 }, /* _POOL32A5~*(99) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000325, 0 , 0, + 0x0 }, /* _POOL32A5~*(100) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000032d, 0 , 0, + 0x0 }, /* _POOL32A5~*(101) */ + { pool , SHRA__R__PH , 2 , 32, + 0xfc0003ff, 0x20000335, 0 , 0, + 0x0 }, /* SHRA[_R].PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000033d, 0 , 0, + 0x0 }, /* _POOL32A5~*(103) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000345, &SUBQ_S_W , 0, + DSP_ }, /* SUBQ_S.W */ + { pool , SUBUH__R__QB , 2 , 32, + 0xfc0003ff, 0x2000034d, 0 , 0, + 0x0 }, /* SUBUH[_R].QB */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000355, &SHRLV_QB , 0, + DSP_ }, /* SHRLV.QB */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000035d, 0 , 0, + 0x0 }, /* _POOL32A5~*(107) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000365, 0 , 0, + 0x0 }, /* _POOL32A5~*(108) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000036d, 0 , 0, + 0x0 }, /* _POOL32A5~*(109) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x20000375, 0 , 0, + 0x0 }, /* _POOL32A5~*(110) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000037d, 0 , 0, + 0x0 }, /* _POOL32A5~*(111) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000385, &ADDSC , 0, + DSP_ }, /* ADDSC */ + { pool , SHLLV__S__PH , 2 , 32, + 0xfc0003ff, 0x2000038d, 0 , 0, + 0x0 }, /* SHLLV[_S].PH */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x20000395, &SHLLV_QB , 0, + DSP_ }, /* SHLLV.QB */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x2000039d, 0 , 0, + 0x0 }, /* _POOL32A5~*(115) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003a5, 0 , 0, + 0x0 }, /* _POOL32A5~*(116) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003ad, 0 , 0, + 0x0 }, /* _POOL32A5~*(117) */ + { pool , SHLL__S__PH , 4 , 32, + 0xfc0003ff, 0x200003b5, 0 , 0, + 0x0 }, /* SHLL[_S].PH */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003bd, 0 , 0, + 0x0 }, /* _POOL32A5~*(119) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200003c5, &ADDWC , 0, + DSP_ }, /* ADDWC */ + { pool , PRECR_SRA__R__PH_W , 2 , 32, + 0xfc0003ff, 0x200003cd, 0 , 0, + 0x0 }, /* PRECR_SRA[_R].PH.W */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200003d5, &SHLLV_S_W , 0, + DSP_ }, /* SHLLV_S.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003dd, 0 , 0, + 0x0 }, /* _POOL32A5~*(123) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003e5, 0 , 0, + 0x0 }, /* _POOL32A5~*(124) */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003ed, 0 , 0, + 0x0 }, /* _POOL32A5~*(125) */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0x200003f5, &SHLL_S_W , 0, + DSP_ }, /* SHLL_S.W */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0x200003fd, 0 , 0, + 0x0 }, /* _POOL32A5~*(127) */ +}; + + +static const Pool PP_LSX[16] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000007, &LBX , 0, + 0x0 }, /* LBX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000087, &SBX , 0, + XMMS_ }, /* SBX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000107, &LBUX , 0, + 0x0 }, /* LBUX */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0x20000187, 0 , 0, + 0x0 }, /* PP.LSX~*(3) */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000207, &LHX , 0, + 0x0 }, /* LHX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000287, &SHX , 0, + XMMS_ }, /* SHX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000307, &LHUX , 0, + 0x0 }, /* LHUX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000387, &LWUX , 0, + MIPS64_ }, /* LWUX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000407, &LWX , 0, + 0x0 }, /* LWX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000487, &SWX , 0, + XMMS_ }, /* SWX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000507, &LWC1X , 0, + CP1_ }, /* LWC1X */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000587, &SWC1X , 0, + CP1_ }, /* SWC1X */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000607, &LDX , 0, + MIPS64_ }, /* LDX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000687, &SDX , 0, + MIPS64_ }, /* SDX */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000707, &LDC1X , 0, + CP1_ }, /* LDC1X */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000787, &SDC1X , 0, + CP1_ }, /* SDC1X */ +}; + + +static const Pool PP_LSXS[16] = { + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0x20000047, 0 , 0, + 0x0 }, /* PP.LSXS~*(0) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0x200000c7, 0 , 0, + 0x0 }, /* PP.LSXS~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0x20000147, 0 , 0, + 0x0 }, /* PP.LSXS~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0x200001c7, 0 , 0, + 0x0 }, /* PP.LSXS~*(3) */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000247, &LHXS , 0, + 0x0 }, /* LHXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200002c7, &SHXS , 0, + XMMS_ }, /* SHXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000347, &LHUXS , 0, + 0x0 }, /* LHUXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200003c7, &LWUXS , 0, + MIPS64_ }, /* LWUXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000447, &LWXS_32_ , 0, + 0x0 }, /* LWXS[32] */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200004c7, &SWXS , 0, + XMMS_ }, /* SWXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000547, &LWC1XS , 0, + CP1_ }, /* LWC1XS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200005c7, &SWC1XS , 0, + CP1_ }, /* SWC1XS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000647, &LDXS , 0, + MIPS64_ }, /* LDXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200006c7, &SDXS , 0, + MIPS64_ }, /* SDXS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x20000747, &LDC1XS , 0, + CP1_ }, /* LDC1XS */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0x200007c7, &SDC1XS , 0, + CP1_ }, /* SDC1XS */ +}; + + +static const Pool P_LSX[2] = { + { pool , PP_LSX , 16 , 32, + 0xfc00007f, 0x20000007, 0 , 0, + 0x0 }, /* PP.LSX */ + { pool , PP_LSXS , 16 , 32, + 0xfc00007f, 0x20000047, 0 , 0, + 0x0 }, /* PP.LSXS */ +}; + + +static const Pool POOL32Axf_1_0[4] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000007f, &MFHI_DSP_ , 0, + DSP_ }, /* MFHI[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000107f, &MFLO_DSP_ , 0, + DSP_ }, /* MFLO[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000207f, &MTHI_DSP_ , 0, + DSP_ }, /* MTHI[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000307f, &MTLO_DSP_ , 0, + DSP_ }, /* MTLO[DSP] */ +}; + + +static const Pool POOL32Axf_1_1[4] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000027f, &MTHLIP , 0, + DSP_ }, /* MTHLIP */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000127f, &SHILOV , 0, + DSP_ }, /* SHILOV */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0x2000227f, 0 , 0, + 0x0 }, /* POOL32Axf_1_1~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0x2000327f, 0 , 0, + 0x0 }, /* POOL32Axf_1_1~*(3) */ +}; + + +static const Pool POOL32Axf_1_3[4] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000067f, &RDDSP , 0, + DSP_ }, /* RDDSP */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000167f, &WRDSP , 0, + DSP_ }, /* WRDSP */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000267f, &EXTP , 0, + DSP_ }, /* EXTP */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x2000367f, &EXTPDP , 0, + DSP_ }, /* EXTPDP */ +}; + + +static const Pool POOL32Axf_1_4[2] = { + { instruction , 0 , 0 , 32, + 0xfc001fff, 0x2000087f, &SHLL_QB , 0, + DSP_ }, /* SHLL.QB */ + { instruction , 0 , 0 , 32, + 0xfc001fff, 0x2000187f, &SHRL_QB , 0, + DSP_ }, /* SHRL.QB */ +}; + + +static const Pool MAQ_S_A__W_PHR[2] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20000a7f, &MAQ_S_W_PHR , 0, + DSP_ }, /* MAQ_S.W.PHR */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20002a7f, &MAQ_SA_W_PHR , 0, + DSP_ }, /* MAQ_SA.W.PHR */ +}; + + +static const Pool MAQ_S_A__W_PHL[2] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20001a7f, &MAQ_S_W_PHL , 0, + DSP_ }, /* MAQ_S.W.PHL */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20003a7f, &MAQ_SA_W_PHL , 0, + DSP_ }, /* MAQ_SA.W.PHL */ +}; + + +static const Pool POOL32Axf_1_5[2] = { + { pool , MAQ_S_A__W_PHR , 2 , 32, + 0xfc001fff, 0x20000a7f, 0 , 0, + 0x0 }, /* MAQ_S[A].W.PHR */ + { pool , MAQ_S_A__W_PHL , 2 , 32, + 0xfc001fff, 0x20001a7f, 0 , 0, + 0x0 }, /* MAQ_S[A].W.PHL */ +}; + + +static const Pool POOL32Axf_1_7[4] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20000e7f, &EXTR_W , 0, + DSP_ }, /* EXTR.W */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20001e7f, &EXTR_R_W , 0, + DSP_ }, /* EXTR_R.W */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20002e7f, &EXTR_RS_W , 0, + DSP_ }, /* EXTR_RS.W */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20003e7f, &EXTR_S_H , 0, + DSP_ }, /* EXTR_S.H */ +}; + + +static const Pool POOL32Axf_1[8] = { + { pool , POOL32Axf_1_0 , 4 , 32, + 0xfc000fff, 0x2000007f, 0 , 0, + 0x0 }, /* POOL32Axf_1_0 */ + { pool , POOL32Axf_1_1 , 4 , 32, + 0xfc000fff, 0x2000027f, 0 , 0, + 0x0 }, /* POOL32Axf_1_1 */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x2000047f, 0 , 0, + 0x0 }, /* POOL32Axf_1~*(2) */ + { pool , POOL32Axf_1_3 , 4 , 32, + 0xfc000fff, 0x2000067f, 0 , 0, + 0x0 }, /* POOL32Axf_1_3 */ + { pool , POOL32Axf_1_4 , 2 , 32, + 0xfc000fff, 0x2000087f, 0 , 0, + 0x0 }, /* POOL32Axf_1_4 */ + { pool , POOL32Axf_1_5 , 2 , 32, + 0xfc000fff, 0x20000a7f, 0 , 0, + 0x0 }, /* POOL32Axf_1_5 */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x20000c7f, 0 , 0, + 0x0 }, /* POOL32Axf_1~*(6) */ + { pool , POOL32Axf_1_7 , 4 , 32, + 0xfc000fff, 0x20000e7f, 0 , 0, + 0x0 }, /* POOL32Axf_1_7 */ +}; + + +static const Pool POOL32Axf_2_DSP__0_7[8] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200000bf, &DPA_W_PH , 0, + DSP_ }, /* DPA.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200002bf, &DPAQ_S_W_PH , 0, + DSP_ }, /* DPAQ_S.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200004bf, &DPS_W_PH , 0, + DSP_ }, /* DPS.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200006bf, &DPSQ_S_W_PH , 0, + DSP_ }, /* DPSQ_S.W.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0x200008bf, 0 , 0, + 0x0 }, /* POOL32Axf_2(DSP)_0_7~*(4) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20000abf, &MADD_DSP_ , 0, + DSP_ }, /* MADD[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20000cbf, &MULT_DSP_ , 0, + DSP_ }, /* MULT[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20000ebf, &EXTRV_W , 0, + DSP_ }, /* EXTRV.W */ +}; + + +static const Pool POOL32Axf_2_DSP__8_15[8] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200010bf, &DPAX_W_PH , 0, + DSP_ }, /* DPAX.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200012bf, &DPAQ_SA_L_W , 0, + DSP_ }, /* DPAQ_SA.L.W */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200014bf, &DPSX_W_PH , 0, + DSP_ }, /* DPSX.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200016bf, &DPSQ_SA_L_W , 0, + DSP_ }, /* DPSQ_SA.L.W */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0x200018bf, 0 , 0, + 0x0 }, /* POOL32Axf_2(DSP)_8_15~*(4) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20001abf, &MADDU_DSP_ , 0, + DSP_ }, /* MADDU[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20001cbf, &MULTU_DSP_ , 0, + DSP_ }, /* MULTU[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20001ebf, &EXTRV_R_W , 0, + DSP_ }, /* EXTRV_R.W */ +}; + + +static const Pool POOL32Axf_2_DSP__16_23[8] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200020bf, &DPAU_H_QBL , 0, + DSP_ }, /* DPAU.H.QBL */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200022bf, &DPAQX_S_W_PH , 0, + DSP_ }, /* DPAQX_S.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200024bf, &DPSU_H_QBL , 0, + DSP_ }, /* DPSU.H.QBL */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200026bf, &DPSQX_S_W_PH , 0, + DSP_ }, /* DPSQX_S.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200028bf, &EXTPV , 0, + DSP_ }, /* EXTPV */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20002abf, &MSUB_DSP_ , 0, + DSP_ }, /* MSUB[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20002cbf, &MULSA_W_PH , 0, + DSP_ }, /* MULSA.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20002ebf, &EXTRV_RS_W , 0, + DSP_ }, /* EXTRV_RS.W */ +}; + + +static const Pool POOL32Axf_2_DSP__24_31[8] = { + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200030bf, &DPAU_H_QBR , 0, + DSP_ }, /* DPAU.H.QBR */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200032bf, &DPAQX_SA_W_PH , 0, + DSP_ }, /* DPAQX_SA.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200034bf, &DPSU_H_QBR , 0, + DSP_ }, /* DPSU.H.QBR */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200036bf, &DPSQX_SA_W_PH , 0, + DSP_ }, /* DPSQX_SA.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x200038bf, &EXTPDPV , 0, + DSP_ }, /* EXTPDPV */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20003abf, &MSUBU_DSP_ , 0, + DSP_ }, /* MSUBU[DSP] */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20003cbf, &MULSAQ_S_W_PH , 0, + DSP_ }, /* MULSAQ_S.W.PH */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0x20003ebf, &EXTRV_S_H , 0, + DSP_ }, /* EXTRV_S.H */ +}; + + +static const Pool POOL32Axf_2[4] = { + { pool , POOL32Axf_2_DSP__0_7, 8 , 32, + 0xfc0031ff, 0x200000bf, 0 , 0, + 0x0 }, /* POOL32Axf_2(DSP)_0_7 */ + { pool , POOL32Axf_2_DSP__8_15, 8 , 32, + 0xfc0031ff, 0x200010bf, 0 , 0, + 0x0 }, /* POOL32Axf_2(DSP)_8_15 */ + { pool , POOL32Axf_2_DSP__16_23, 8 , 32, + 0xfc0031ff, 0x200020bf, 0 , 0, + 0x0 }, /* POOL32Axf_2(DSP)_16_23 */ + { pool , POOL32Axf_2_DSP__24_31, 8 , 32, + 0xfc0031ff, 0x200030bf, 0 , 0, + 0x0 }, /* POOL32Axf_2(DSP)_24_31 */ +}; + + +static const Pool POOL32Axf_4[128] = { + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000013f, &ABSQ_S_QB , 0, + DSP_ }, /* ABSQ_S.QB */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000033f, &REPLV_PH , 0, + DSP_ }, /* REPLV.PH */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000053f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000073f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000093f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20000b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20000d3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20000f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(7) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000113f, &ABSQ_S_PH , 0, + DSP_ }, /* ABSQ_S.PH */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000133f, &REPLV_QB , 0, + DSP_ }, /* REPLV.QB */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000153f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000173f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(11) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000193f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20001b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20001d3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20001f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(15) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000213f, &ABSQ_S_W , 0, + DSP_ }, /* ABSQ_S.W */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000233f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(17) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000253f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000273f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000293f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20002b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20002d3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20002f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000313f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000333f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000353f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000373f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000393f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20003b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20003d3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20003f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(31) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000413f, &INSV , 0, + DSP_ }, /* INSV */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000433f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(33) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000453f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(34) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000473f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(35) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000493f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(36) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20004b3f, &CLO , 0, + XMMS_ }, /* CLO */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20004d3f, &MFC2 , 0, + CP2_ }, /* MFC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20004f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(39) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000513f, &PRECEQ_W_PHL , 0, + DSP_ }, /* PRECEQ.W.PHL */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000533f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(41) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000553f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(42) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000573f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(43) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000593f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(44) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20005b3f, &CLZ , 0, + XMMS_ }, /* CLZ */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20005d3f, &MTC2 , 0, + CP2_ }, /* MTC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20005f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(47) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000613f, &PRECEQ_W_PHR , 0, + DSP_ }, /* PRECEQ.W.PHR */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000633f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(49) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000653f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(50) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000673f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(51) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000693f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(52) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20006b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(53) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20006d3f, &DMFC2 , 0, + CP2_ }, /* DMFC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20006f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(55) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000713f, &PRECEQU_PH_QBL , 0, + DSP_ }, /* PRECEQU.PH.QBL */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000733f, &PRECEQU_PH_QBLA , 0, + DSP_ }, /* PRECEQU.PH.QBLA */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000753f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(58) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000773f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(59) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000793f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(60) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20007b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(61) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20007d3f, &DMTC2 , 0, + CP2_ }, /* DMTC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20007f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(63) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000813f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(64) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000833f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(65) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000853f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(66) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000873f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(67) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000893f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(68) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20008b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(69) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20008d3f, &MFHC2 , 0, + CP2_ }, /* MFHC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20008f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(71) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000913f, &PRECEQU_PH_QBR , 0, + DSP_ }, /* PRECEQU.PH.QBR */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000933f, &PRECEQU_PH_QBRA , 0, + DSP_ }, /* PRECEQU.PH.QBRA */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000953f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(74) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000973f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(75) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000993f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(76) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20009b3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(77) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x20009d3f, &MTHC2 , 0, + CP2_ }, /* MTHC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20009f3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(79) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000a13f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(80) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000a33f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(81) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000a53f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(82) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000a73f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(83) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000a93f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(84) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ab3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(85) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ad3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(86) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000af3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(87) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000b13f, &PRECEU_PH_QBL , 0, + DSP_ }, /* PRECEU.PH.QBL */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000b33f, &PRECEU_PH_QBLA , 0, + DSP_ }, /* PRECEU.PH.QBLA */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000b53f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(90) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000b73f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(91) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000b93f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(92) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000bb3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(93) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000bd3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(94) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000bf3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(95) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c13f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(96) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c33f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(97) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c53f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(98) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c73f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(99) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c93f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(100) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000cb3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(101) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000cd3f, &CFC2 , 0, + CP2_ }, /* CFC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000cf3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(103) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000d13f, &PRECEU_PH_QBR , 0, + DSP_ }, /* PRECEU.PH.QBR */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000d33f, &PRECEU_PH_QBRA , 0, + DSP_ }, /* PRECEU.PH.QBRA */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d53f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(106) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d73f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(107) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d93f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(108) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000db3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(109) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000dd3f, &CTC2 , 0, + CP2_ }, /* CTC2 */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000df3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(111) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e13f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(112) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e33f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(113) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e53f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(114) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e73f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(115) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e93f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(116) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000eb3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(117) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ed3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(118) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ef3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(119) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000f13f, &RADDU_W_QB , 0, + DSP_ }, /* RADDU.W.QB */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f33f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(121) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f53f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(122) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f73f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(123) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f93f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(124) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000fb3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(125) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000fd3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(126) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ff3f, 0 , 0, + 0x0 }, /* POOL32Axf_4~*(127) */ +}; + + +static const Pool POOL32Axf_5_group0[32] = { + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000017f, &TLBGP , 0, + CP0_ | VZ_ | TLB_ }, /* TLBGP */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000037f, &TLBP , 0, + CP0_ | TLB_ }, /* TLBP */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000057f, &TLBGINV , 0, + CP0_ | VZ_ | TLB_ | TLBINV_}, /* TLBGINV */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000077f, &TLBINV , 0, + CP0_ | TLB_ | TLBINV_}, /* TLBINV */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000097f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20000b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20000d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20000f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(7) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000117f, &TLBGR , 0, + CP0_ | VZ_ | TLB_ }, /* TLBGR */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000137f, &TLBR , 0, + CP0_ | TLB_ }, /* TLBR */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000157f, &TLBGINVF , 0, + CP0_ | VZ_ | TLB_ | TLBINV_}, /* TLBGINVF */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000177f, &TLBINVF , 0, + CP0_ | TLB_ | TLBINV_}, /* TLBINVF */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000197f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20001b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20001d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20001f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(15) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000217f, &TLBGWI , 0, + CP0_ | VZ_ | TLB_ }, /* TLBGWI */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000237f, &TLBWI , 0, + CP0_ | TLB_ }, /* TLBWI */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000257f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000277f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000297f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20002b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20002d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20002f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(23) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000317f, &TLBGWR , 0, + CP0_ | VZ_ | TLB_ }, /* TLBGWR */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000337f, &TLBWR , 0, + CP0_ | TLB_ }, /* TLBWR */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000357f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000377f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000397f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20003b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20003d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20003f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0~*(31) */ +}; + + +static const Pool POOL32Axf_5_group1[32] = { + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000417f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(0) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000437f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000457f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(2) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000477f, &DI , 0, + 0x0 }, /* DI */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000497f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20004b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20004d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20004f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000517f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(8) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000537f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(9) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000557f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(10) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000577f, &EI , 0, + 0x0 }, /* EI */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000597f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20005b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20005d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20005f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(15) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000617f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000637f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(17) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000657f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000677f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000697f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20006b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20006d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20006f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000717f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000737f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000757f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000777f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000797f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20007b7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20007d7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x20007f7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1~*(31) */ +}; + + +static const Pool ERETx[2] = { + { instruction , 0 , 0 , 32, + 0xfc01ffff, 0x2000f37f, &ERET , 0, + 0x0 }, /* ERET */ + { instruction , 0 , 0 , 32, + 0xfc01ffff, 0x2001f37f, &ERETNC , 0, + 0x0 }, /* ERETNC */ +}; + + +static const Pool POOL32Axf_5_group3[32] = { + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c17f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(0) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000c37f, &WAIT , 0, + 0x0 }, /* WAIT */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c57f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c77f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000c97f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000cb7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000cd7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000cf7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d17f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(8) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000d37f, &IRET , 0, + MCU_ }, /* IRET */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d57f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d77f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(11) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000d97f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000db7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000dd7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000df7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(15) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000e17f, &RDPGPR , 0, + CP0_ }, /* RDPGPR */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000e37f, &DERET , 0, + EJTAG_ }, /* DERET */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e57f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e77f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000e97f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000eb7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ed7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ef7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(23) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0x2000f17f, &WRPGPR , 0, + CP0_ }, /* WRPGPR */ + { pool , ERETx , 2 , 32, + 0xfc00ffff, 0x2000f37f, 0 , 0, + 0x0 }, /* ERETx */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f57f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f77f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000f97f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000fb7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000fd7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0x2000ff7f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3~*(31) */ +}; + + +static const Pool POOL32Axf_5[4] = { + { pool , POOL32Axf_5_group0 , 32 , 32, + 0xfc00c1ff, 0x2000017f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group0 */ + { pool , POOL32Axf_5_group1 , 32 , 32, + 0xfc00c1ff, 0x2000417f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group1 */ + { reserved_block , 0 , 0 , 32, + 0xfc00c1ff, 0x2000817f, 0 , 0, + 0x0 }, /* POOL32Axf_5~*(2) */ + { pool , POOL32Axf_5_group3 , 32 , 32, + 0xfc00c1ff, 0x2000c17f, 0 , 0, + 0x0 }, /* POOL32Axf_5_group3 */ +}; + + +static const Pool SHRA__R__QB[2] = { + { instruction , 0 , 0 , 32, + 0xfc001fff, 0x200001ff, &SHRA_QB , 0, + DSP_ }, /* SHRA.QB */ + { instruction , 0 , 0 , 32, + 0xfc001fff, 0x200011ff, &SHRA_R_QB , 0, + DSP_ }, /* SHRA_R.QB */ +}; + + +static const Pool POOL32Axf_7[8] = { + { pool , SHRA__R__QB , 2 , 32, + 0xfc000fff, 0x200001ff, 0 , 0, + 0x0 }, /* SHRA[_R].QB */ + { instruction , 0 , 0 , 32, + 0xfc000fff, 0x200003ff, &SHRL_PH , 0, + DSP_ }, /* SHRL.PH */ + { instruction , 0 , 0 , 32, + 0xfc000fff, 0x200005ff, &REPL_QB , 0, + DSP_ }, /* REPL.QB */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x200007ff, 0 , 0, + 0x0 }, /* POOL32Axf_7~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x200009ff, 0 , 0, + 0x0 }, /* POOL32Axf_7~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x20000bff, 0 , 0, + 0x0 }, /* POOL32Axf_7~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x20000dff, 0 , 0, + 0x0 }, /* POOL32Axf_7~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc000fff, 0x20000fff, 0 , 0, + 0x0 }, /* POOL32Axf_7~*(7) */ +}; + + +static const Pool POOL32Axf[8] = { + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0x2000003f, 0 , 0, + 0x0 }, /* POOL32Axf~*(0) */ + { pool , POOL32Axf_1 , 8 , 32, + 0xfc0001ff, 0x2000007f, 0 , 0, + 0x0 }, /* POOL32Axf_1 */ + { pool , POOL32Axf_2 , 4 , 32, + 0xfc0001ff, 0x200000bf, 0 , 0, + 0x0 }, /* POOL32Axf_2 */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0x200000ff, 0 , 0, + 0x0 }, /* POOL32Axf~*(3) */ + { pool , POOL32Axf_4 , 128 , 32, + 0xfc0001ff, 0x2000013f, 0 , 0, + 0x0 }, /* POOL32Axf_4 */ + { pool , POOL32Axf_5 , 4 , 32, + 0xfc0001ff, 0x2000017f, 0 , 0, + 0x0 }, /* POOL32Axf_5 */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0x200001bf, 0 , 0, + 0x0 }, /* POOL32Axf~*(6) */ + { pool , POOL32Axf_7 , 8 , 32, + 0xfc0001ff, 0x200001ff, 0 , 0, + 0x0 }, /* POOL32Axf_7 */ +}; + + +static const Pool _POOL32A7[8] = { + { pool , P_LSX , 2 , 32, + 0xfc00003f, 0x20000007, 0 , 0, + 0x0 }, /* P.LSX */ + { instruction , 0 , 0 , 32, + 0xfc00003f, 0x2000000f, &LSA , 0, + 0x0 }, /* LSA */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0x20000017, 0 , 0, + 0x0 }, /* _POOL32A7~*(2) */ + { instruction , 0 , 0 , 32, + 0xfc00003f, 0x2000001f, &EXTW , 0, + 0x0 }, /* EXTW */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0x20000027, 0 , 0, + 0x0 }, /* _POOL32A7~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0x2000002f, 0 , 0, + 0x0 }, /* _POOL32A7~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0x20000037, 0 , 0, + 0x0 }, /* _POOL32A7~*(6) */ + { pool , POOL32Axf , 8 , 32, + 0xfc00003f, 0x2000003f, 0 , 0, + 0x0 }, /* POOL32Axf */ +}; + + +static const Pool P32A[8] = { + { pool , _POOL32A0 , 128 , 32, + 0xfc000007, 0x20000000, 0 , 0, + 0x0 }, /* _POOL32A0 */ + { instruction , 0 , 0 , 32, + 0xfc000007, 0x20000001, &SPECIAL2 , 0, + UDI_ }, /* SPECIAL2 */ + { instruction , 0 , 0 , 32, + 0xfc000007, 0x20000002, &COP2_1 , 0, + CP2_ }, /* COP2_1 */ + { instruction , 0 , 0 , 32, + 0xfc000007, 0x20000003, &UDI , 0, + UDI_ }, /* UDI */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0x20000004, 0 , 0, + 0x0 }, /* P32A~*(4) */ + { pool , _POOL32A5 , 128 , 32, + 0xfc000007, 0x20000005, 0 , 0, + 0x0 }, /* _POOL32A5 */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0x20000006, 0 , 0, + 0x0 }, /* P32A~*(6) */ + { pool , _POOL32A7 , 8 , 32, + 0xfc000007, 0x20000007, 0 , 0, + 0x0 }, /* _POOL32A7 */ +}; + + +static const Pool P_GP_D[2] = { + { instruction , 0 , 0 , 32, + 0xfc000007, 0x40000001, &LD_GP_ , 0, + MIPS64_ }, /* LD[GP] */ + { instruction , 0 , 0 , 32, + 0xfc000007, 0x40000005, &SD_GP_ , 0, + MIPS64_ }, /* SD[GP] */ +}; + + +static const Pool P_GP_W[4] = { + { instruction , 0 , 0 , 32, + 0xfc000003, 0x40000000, &ADDIU_GP_W_ , 0, + 0x0 }, /* ADDIU[GP.W] */ + { pool , P_GP_D , 2 , 32, + 0xfc000003, 0x40000001, 0 , 0, + 0x0 }, /* P.GP.D */ + { instruction , 0 , 0 , 32, + 0xfc000003, 0x40000002, &LW_GP_ , 0, + 0x0 }, /* LW[GP] */ + { instruction , 0 , 0 , 32, + 0xfc000003, 0x40000003, &SW_GP_ , 0, + 0x0 }, /* SW[GP] */ +}; + + +static const Pool POOL48I[32] = { + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600000000000ull, &LI_48_ , 0, + XMMS_ }, /* LI[48] */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600100000000ull, &ADDIU_48_ , 0, + XMMS_ }, /* ADDIU[48] */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600200000000ull, &ADDIU_GP48_ , 0, + XMMS_ }, /* ADDIU[GP48] */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600300000000ull, &ADDIUPC_48_ , 0, + XMMS_ }, /* ADDIUPC[48] */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600400000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(4) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600500000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(5) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600600000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(6) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600700000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(7) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600800000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(8) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600900000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(9) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600a00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(10) */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600b00000000ull, &LWPC_48_ , 0, + XMMS_ }, /* LWPC[48] */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600c00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(12) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600d00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(13) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600e00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(14) */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x600f00000000ull, &SWPC_48_ , 0, + XMMS_ }, /* SWPC[48] */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601000000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(16) */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601100000000ull, &DADDIU_48_ , 0, + MIPS64_ }, /* DADDIU[48] */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601200000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(18) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601300000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(19) */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601400000000ull, &DLUI_48_ , 0, + MIPS64_ }, /* DLUI[48] */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601500000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(21) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601600000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(22) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601700000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(23) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601800000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(24) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601900000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(25) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601a00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(26) */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601b00000000ull, &LDPC_48_ , 0, + MIPS64_ }, /* LDPC[48] */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601c00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(28) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601d00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(29) */ + { reserved_block , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601e00000000ull, 0 , 0, + 0x0 }, /* POOL48I~*(30) */ + { instruction , 0 , 0 , 48, + 0xfc1f00000000ull, 0x601f00000000ull, &SDPC_48_ , 0, + MIPS64_ }, /* SDPC[48] */ +}; + + +static const Pool PP_SR[4] = { + { instruction , 0 , 0 , 32, + 0xfc10f003, 0x80003000, &SAVE_32_ , 0, + 0x0 }, /* SAVE[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc10f003, 0x80003001, 0 , 0, + 0x0 }, /* PP.SR~*(1) */ + { instruction , 0 , 0 , 32, + 0xfc10f003, 0x80003002, &RESTORE_32_ , 0, + 0x0 }, /* RESTORE[32] */ + { return_instruction , 0 , 0 , 32, + 0xfc10f003, 0x80003003, &RESTORE_JRC_32_ , 0, + 0x0 }, /* RESTORE.JRC[32] */ +}; + + +static const Pool P_SR_F[8] = { + { instruction , 0 , 0 , 32, + 0xfc10f007, 0x80103000, &SAVEF , 0, + CP1_ }, /* SAVEF */ + { instruction , 0 , 0 , 32, + 0xfc10f007, 0x80103001, &RESTOREF , 0, + CP1_ }, /* RESTOREF */ + { reserved_block , 0 , 0 , 32, + 0xfc10f007, 0x80103002, 0 , 0, + 0x0 }, /* P.SR.F~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc10f007, 0x80103003, 0 , 0, + 0x0 }, /* P.SR.F~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc10f007, 0x80103004, 0 , 0, + 0x0 }, /* P.SR.F~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc10f007, 0x80103005, 0 , 0, + 0x0 }, /* P.SR.F~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc10f007, 0x80103006, 0 , 0, + 0x0 }, /* P.SR.F~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc10f007, 0x80103007, 0 , 0, + 0x0 }, /* P.SR.F~*(7) */ +}; + + +static const Pool P_SR[2] = { + { pool , PP_SR , 4 , 32, + 0xfc10f000, 0x80003000, 0 , 0, + 0x0 }, /* PP.SR */ + { pool , P_SR_F , 8 , 32, + 0xfc10f000, 0x80103000, 0 , 0, + 0x0 }, /* P.SR.F */ +}; + + +static const Pool P_SLL[5] = { + { instruction , 0 , 0 , 32, + 0xffe0f1ff, 0x8000c000, &NOP_32_ , 0, + 0x0 }, /* NOP[32] */ + { instruction , 0 , 0 , 32, + 0xffe0f1ff, 0x8000c003, &EHB , 0, + 0x0 }, /* EHB */ + { instruction , 0 , 0 , 32, + 0xffe0f1ff, 0x8000c005, &PAUSE , 0, + 0x0 }, /* PAUSE */ + { instruction , 0 , 0 , 32, + 0xffe0f1ff, 0x8000c006, &SYNC , 0, + 0x0 }, /* SYNC */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c000, &SLL_32_ , 0, + 0x0 }, /* SLL[32] */ +}; + + +static const Pool P_SHIFT[16] = { + { pool , P_SLL , 5 , 32, + 0xfc00f1e0, 0x8000c000, 0 , 0, + 0x0 }, /* P.SLL */ + { reserved_block , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c020, 0 , 0, + 0x0 }, /* P.SHIFT~*(1) */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c040, &SRL_32_ , 0, + 0x0 }, /* SRL[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c060, 0 , 0, + 0x0 }, /* P.SHIFT~*(3) */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c080, &SRA , 0, + 0x0 }, /* SRA */ + { reserved_block , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c0a0, 0 , 0, + 0x0 }, /* P.SHIFT~*(5) */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c0c0, &ROTR , 0, + 0x0 }, /* ROTR */ + { reserved_block , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c0e0, 0 , 0, + 0x0 }, /* P.SHIFT~*(7) */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c100, &DSLL , 0, + MIPS64_ }, /* DSLL */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c120, &DSLL32 , 0, + MIPS64_ }, /* DSLL32 */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c140, &DSRL , 0, + MIPS64_ }, /* DSRL */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c160, &DSRL32 , 0, + MIPS64_ }, /* DSRL32 */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c180, &DSRA , 0, + MIPS64_ }, /* DSRA */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c1a0, &DSRA32 , 0, + MIPS64_ }, /* DSRA32 */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c1c0, &DROTR , 0, + MIPS64_ }, /* DROTR */ + { instruction , 0 , 0 , 32, + 0xfc00f1e0, 0x8000c1e0, &DROTR32 , 0, + MIPS64_ }, /* DROTR32 */ +}; + + +static const Pool P_ROTX[4] = { + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000d000, &ROTX , 0, + XMMS_ }, /* ROTX */ + { reserved_block , 0 , 0 , 32, + 0xfc00f820, 0x8000d020, 0 , 0, + 0x0 }, /* P.ROTX~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f820, 0x8000d800, 0 , 0, + 0x0 }, /* P.ROTX~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f820, 0x8000d820, 0 , 0, + 0x0 }, /* P.ROTX~*(3) */ +}; + + +static const Pool P_INS[4] = { + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000e000, &INS , 0, + XMMS_ }, /* INS */ + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000e020, &DINSU , 0, + MIPS64_ }, /* DINSU */ + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000e800, &DINSM , 0, + MIPS64_ }, /* DINSM */ + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000e820, &DINS , 0, + MIPS64_ }, /* DINS */ +}; + + +static const Pool P_EXT[4] = { + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000f000, &EXT , 0, + XMMS_ }, /* EXT */ + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000f020, &DEXTU , 0, + MIPS64_ }, /* DEXTU */ + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000f800, &DEXTM , 0, + MIPS64_ }, /* DEXTM */ + { instruction , 0 , 0 , 32, + 0xfc00f820, 0x8000f820, &DEXT , 0, + MIPS64_ }, /* DEXT */ +}; + + +static const Pool P_U12[16] = { + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80000000, &ORI , 0, + 0x0 }, /* ORI */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80001000, &XORI , 0, + 0x0 }, /* XORI */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80002000, &ANDI_32_ , 0, + 0x0 }, /* ANDI[32] */ + { pool , P_SR , 2 , 32, + 0xfc00f000, 0x80003000, 0 , 0, + 0x0 }, /* P.SR */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80004000, &SLTI , 0, + 0x0 }, /* SLTI */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80005000, &SLTIU , 0, + 0x0 }, /* SLTIU */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80006000, &SEQI , 0, + 0x0 }, /* SEQI */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x80007000, 0 , 0, + 0x0 }, /* P.U12~*(7) */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80008000, &ADDIU_NEG_ , 0, + 0x0 }, /* ADDIU[NEG] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x80009000, &DADDIU_U12_ , 0, + MIPS64_ }, /* DADDIU[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8000a000, &DADDIU_NEG_ , 0, + MIPS64_ }, /* DADDIU[NEG] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8000b000, &DROTX , 0, + MIPS64_ }, /* DROTX */ + { pool , P_SHIFT , 16 , 32, + 0xfc00f000, 0x8000c000, 0 , 0, + 0x0 }, /* P.SHIFT */ + { pool , P_ROTX , 4 , 32, + 0xfc00f000, 0x8000d000, 0 , 0, + 0x0 }, /* P.ROTX */ + { pool , P_INS , 4 , 32, + 0xfc00f000, 0x8000e000, 0 , 0, + 0x0 }, /* P.INS */ + { pool , P_EXT , 4 , 32, + 0xfc00f000, 0x8000f000, 0 , 0, + 0x0 }, /* P.EXT */ +}; + + +static const Pool RINT_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000020, &RINT_S , 0, + CP1_ }, /* RINT.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000220, &RINT_D , 0, + CP1_ }, /* RINT.D */ +}; + + +static const Pool ADD_fmt0[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000030, &ADD_S , 0, + CP1_ }, /* ADD.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa0000230, 0 , 0, + CP1_ }, /* ADD.fmt0~*(1) */ +}; + + +static const Pool SELEQZ_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000038, &SELEQZ_S , 0, + CP1_ }, /* SELEQZ.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000238, &SELEQZ_D , 0, + CP1_ }, /* SELEQZ.D */ +}; + + +static const Pool CLASS_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000060, &CLASS_S , 0, + CP1_ }, /* CLASS.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000260, &CLASS_D , 0, + CP1_ }, /* CLASS.D */ +}; + + +static const Pool SUB_fmt0[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000070, &SUB_S , 0, + CP1_ }, /* SUB.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa0000270, 0 , 0, + CP1_ }, /* SUB.fmt0~*(1) */ +}; + + +static const Pool SELNEZ_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000078, &SELNEZ_S , 0, + CP1_ }, /* SELNEZ.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000278, &SELNEZ_D , 0, + CP1_ }, /* SELNEZ.D */ +}; + + +static const Pool MUL_fmt0[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00000b0, &MUL_S , 0, + CP1_ }, /* MUL.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa00002b0, 0 , 0, + CP1_ }, /* MUL.fmt0~*(1) */ +}; + + +static const Pool SEL_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00000b8, &SEL_S , 0, + CP1_ }, /* SEL.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00002b8, &SEL_D , 0, + CP1_ }, /* SEL.D */ +}; + + +static const Pool DIV_fmt0[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00000f0, &DIV_S , 0, + CP1_ }, /* DIV.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa00002f0, 0 , 0, + CP1_ }, /* DIV.fmt0~*(1) */ +}; + + +static const Pool ADD_fmt1[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000130, &ADD_D , 0, + CP1_ }, /* ADD.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa0000330, 0 , 0, + CP1_ }, /* ADD.fmt1~*(1) */ +}; + + +static const Pool SUB_fmt1[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa0000170, &SUB_D , 0, + CP1_ }, /* SUB.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa0000370, 0 , 0, + CP1_ }, /* SUB.fmt1~*(1) */ +}; + + +static const Pool MUL_fmt1[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00001b0, &MUL_D , 0, + CP1_ }, /* MUL.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa00003b0, 0 , 0, + CP1_ }, /* MUL.fmt1~*(1) */ +}; + + +static const Pool MADDF_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00001b8, &MADDF_S , 0, + CP1_ }, /* MADDF.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00003b8, &MADDF_D , 0, + CP1_ }, /* MADDF.D */ +}; + + +static const Pool DIV_fmt1[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00001f0, &DIV_D , 0, + CP1_ }, /* DIV.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0003ff, 0xa00003f0, 0 , 0, + CP1_ }, /* DIV.fmt1~*(1) */ +}; + + +static const Pool MSUBF_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00001f8, &MSUBF_S , 0, + CP1_ }, /* MSUBF.S */ + { instruction , 0 , 0 , 32, + 0xfc0003ff, 0xa00003f8, &MSUBF_D , 0, + CP1_ }, /* MSUBF.D */ +}; + + +static const Pool POOL32F_0[64] = { + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000000, 0 , 0, + CP1_ }, /* POOL32F_0~*(0) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000008, 0 , 0, + CP1_ }, /* POOL32F_0~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000010, 0 , 0, + CP1_ }, /* POOL32F_0~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000018, 0 , 0, + CP1_ }, /* POOL32F_0~*(3) */ + { pool , RINT_fmt , 2 , 32, + 0xfc0001ff, 0xa0000020, 0 , 0, + CP1_ }, /* RINT.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000028, 0 , 0, + CP1_ }, /* POOL32F_0~*(5) */ + { pool , ADD_fmt0 , 2 , 32, + 0xfc0001ff, 0xa0000030, 0 , 0, + CP1_ }, /* ADD.fmt0 */ + { pool , SELEQZ_fmt , 2 , 32, + 0xfc0001ff, 0xa0000038, 0 , 0, + CP1_ }, /* SELEQZ.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000040, 0 , 0, + CP1_ }, /* POOL32F_0~*(8) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000048, 0 , 0, + CP1_ }, /* POOL32F_0~*(9) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000050, 0 , 0, + CP1_ }, /* POOL32F_0~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000058, 0 , 0, + CP1_ }, /* POOL32F_0~*(11) */ + { pool , CLASS_fmt , 2 , 32, + 0xfc0001ff, 0xa0000060, 0 , 0, + CP1_ }, /* CLASS.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000068, 0 , 0, + CP1_ }, /* POOL32F_0~*(13) */ + { pool , SUB_fmt0 , 2 , 32, + 0xfc0001ff, 0xa0000070, 0 , 0, + CP1_ }, /* SUB.fmt0 */ + { pool , SELNEZ_fmt , 2 , 32, + 0xfc0001ff, 0xa0000078, 0 , 0, + CP1_ }, /* SELNEZ.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000080, 0 , 0, + CP1_ }, /* POOL32F_0~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000088, 0 , 0, + CP1_ }, /* POOL32F_0~*(17) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000090, 0 , 0, + CP1_ }, /* POOL32F_0~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000098, 0 , 0, + CP1_ }, /* POOL32F_0~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000a0, 0 , 0, + CP1_ }, /* POOL32F_0~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000a8, 0 , 0, + CP1_ }, /* POOL32F_0~*(21) */ + { pool , MUL_fmt0 , 2 , 32, + 0xfc0001ff, 0xa00000b0, 0 , 0, + CP1_ }, /* MUL.fmt0 */ + { pool , SEL_fmt , 2 , 32, + 0xfc0001ff, 0xa00000b8, 0 , 0, + CP1_ }, /* SEL.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000c0, 0 , 0, + CP1_ }, /* POOL32F_0~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000c8, 0 , 0, + CP1_ }, /* POOL32F_0~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000d0, 0 , 0, + CP1_ }, /* POOL32F_0~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000d8, 0 , 0, + CP1_ }, /* POOL32F_0~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000e0, 0 , 0, + CP1_ }, /* POOL32F_0~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000e8, 0 , 0, + CP1_ }, /* POOL32F_0~*(29) */ + { pool , DIV_fmt0 , 2 , 32, + 0xfc0001ff, 0xa00000f0, 0 , 0, + CP1_ }, /* DIV.fmt0 */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00000f8, 0 , 0, + CP1_ }, /* POOL32F_0~*(31) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000100, 0 , 0, + CP1_ }, /* POOL32F_0~*(32) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000108, 0 , 0, + CP1_ }, /* POOL32F_0~*(33) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000110, 0 , 0, + CP1_ }, /* POOL32F_0~*(34) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000118, 0 , 0, + CP1_ }, /* POOL32F_0~*(35) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000120, 0 , 0, + CP1_ }, /* POOL32F_0~*(36) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000128, 0 , 0, + CP1_ }, /* POOL32F_0~*(37) */ + { pool , ADD_fmt1 , 2 , 32, + 0xfc0001ff, 0xa0000130, 0 , 0, + CP1_ }, /* ADD.fmt1 */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000138, 0 , 0, + CP1_ }, /* POOL32F_0~*(39) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000140, 0 , 0, + CP1_ }, /* POOL32F_0~*(40) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000148, 0 , 0, + CP1_ }, /* POOL32F_0~*(41) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000150, 0 , 0, + CP1_ }, /* POOL32F_0~*(42) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000158, 0 , 0, + CP1_ }, /* POOL32F_0~*(43) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000160, 0 , 0, + CP1_ }, /* POOL32F_0~*(44) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000168, 0 , 0, + CP1_ }, /* POOL32F_0~*(45) */ + { pool , SUB_fmt1 , 2 , 32, + 0xfc0001ff, 0xa0000170, 0 , 0, + CP1_ }, /* SUB.fmt1 */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000178, 0 , 0, + CP1_ }, /* POOL32F_0~*(47) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000180, 0 , 0, + CP1_ }, /* POOL32F_0~*(48) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000188, 0 , 0, + CP1_ }, /* POOL32F_0~*(49) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000190, 0 , 0, + CP1_ }, /* POOL32F_0~*(50) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa0000198, 0 , 0, + CP1_ }, /* POOL32F_0~*(51) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001a0, 0 , 0, + CP1_ }, /* POOL32F_0~*(52) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001a8, 0 , 0, + CP1_ }, /* POOL32F_0~*(53) */ + { pool , MUL_fmt1 , 2 , 32, + 0xfc0001ff, 0xa00001b0, 0 , 0, + CP1_ }, /* MUL.fmt1 */ + { pool , MADDF_fmt , 2 , 32, + 0xfc0001ff, 0xa00001b8, 0 , 0, + CP1_ }, /* MADDF.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001c0, 0 , 0, + CP1_ }, /* POOL32F_0~*(56) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001c8, 0 , 0, + CP1_ }, /* POOL32F_0~*(57) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001d0, 0 , 0, + CP1_ }, /* POOL32F_0~*(58) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001d8, 0 , 0, + CP1_ }, /* POOL32F_0~*(59) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001e0, 0 , 0, + CP1_ }, /* POOL32F_0~*(60) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xa00001e8, 0 , 0, + CP1_ }, /* POOL32F_0~*(61) */ + { pool , DIV_fmt1 , 2 , 32, + 0xfc0001ff, 0xa00001f0, 0 , 0, + CP1_ }, /* DIV.fmt1 */ + { pool , MSUBF_fmt , 2 , 32, + 0xfc0001ff, 0xa00001f8, 0 , 0, + CP1_ }, /* MSUBF.fmt */ +}; + + +static const Pool MIN_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa0000003, &MIN_S , 0, + CP1_ }, /* MIN.S */ + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa0000203, &MIN_D , 0, + CP1_ }, /* MIN.D */ +}; + + +static const Pool MAX_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa000000b, &MAX_S , 0, + CP1_ }, /* MAX.S */ + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa000020b, &MAX_D , 0, + CP1_ }, /* MAX.D */ +}; + + +static const Pool MINA_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa0000023, &MINA_S , 0, + CP1_ }, /* MINA.S */ + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa0000223, &MINA_D , 0, + CP1_ }, /* MINA.D */ +}; + + +static const Pool MAXA_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa000002b, &MAXA_S , 0, + CP1_ }, /* MAXA.S */ + { instruction , 0 , 0 , 32, + 0xfc00023f, 0xa000022b, &MAXA_D , 0, + CP1_ }, /* MAXA.D */ +}; + + +static const Pool CVT_L_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000013b, &CVT_L_S , 0, + CP1_ }, /* CVT.L.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000413b, &CVT_L_D , 0, + CP1_ }, /* CVT.L.D */ +}; + + +static const Pool RSQRT_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000023b, &RSQRT_S , 0, + CP1_ }, /* RSQRT.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000423b, &RSQRT_D , 0, + CP1_ }, /* RSQRT.D */ +}; + + +static const Pool FLOOR_L_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000033b, &FLOOR_L_S , 0, + CP1_ }, /* FLOOR.L.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000433b, &FLOOR_L_D , 0, + CP1_ }, /* FLOOR.L.D */ +}; + + +static const Pool CVT_W_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000093b, &CVT_W_S , 0, + CP1_ }, /* CVT.W.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000493b, &CVT_W_D , 0, + CP1_ }, /* CVT.W.D */ +}; + + +static const Pool SQRT_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0000a3b, &SQRT_S , 0, + CP1_ }, /* SQRT.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0004a3b, &SQRT_D , 0, + CP1_ }, /* SQRT.D */ +}; + + +static const Pool FLOOR_W_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0000b3b, &FLOOR_W_S , 0, + CP1_ }, /* FLOOR.W.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0004b3b, &FLOOR_W_D , 0, + CP1_ }, /* FLOOR.W.D */ +}; + + +static const Pool RECIP_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000123b, &RECIP_S , 0, + CP1_ }, /* RECIP.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000523b, &RECIP_D , 0, + CP1_ }, /* RECIP.D */ +}; + + +static const Pool CEIL_L_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000133b, &CEIL_L_S , 0, + CP1_ }, /* CEIL.L.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000533b, &CEIL_L_D , 0, + CP1_ }, /* CEIL.L.D */ +}; + + +static const Pool CEIL_W_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0001b3b, &CEIL_W_S , 0, + CP1_ }, /* CEIL.W.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0005b3b, &CEIL_W_D , 0, + CP1_ }, /* CEIL.W.D */ +}; + + +static const Pool TRUNC_L_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000233b, &TRUNC_L_S , 0, + CP1_ }, /* TRUNC.L.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000633b, &TRUNC_L_D , 0, + CP1_ }, /* TRUNC.L.D */ +}; + + +static const Pool TRUNC_W_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0002b3b, &TRUNC_W_S , 0, + CP1_ }, /* TRUNC.W.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0006b3b, &TRUNC_W_D , 0, + CP1_ }, /* TRUNC.W.D */ +}; + + +static const Pool ROUND_L_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000333b, &ROUND_L_S , 0, + CP1_ }, /* ROUND.L.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000733b, &ROUND_L_D , 0, + CP1_ }, /* ROUND.L.D */ +}; + + +static const Pool ROUND_W_fmt[2] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0003b3b, &ROUND_W_S , 0, + CP1_ }, /* ROUND.W.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0007b3b, &ROUND_W_D , 0, + CP1_ }, /* ROUND.W.D */ +}; + + +static const Pool POOL32Fxf_0[64] = { + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000003b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(0) */ + { pool , CVT_L_fmt , 2 , 32, + 0xfc003fff, 0xa000013b, 0 , 0, + CP1_ }, /* CVT.L.fmt */ + { pool , RSQRT_fmt , 2 , 32, + 0xfc003fff, 0xa000023b, 0 , 0, + CP1_ }, /* RSQRT.fmt */ + { pool , FLOOR_L_fmt , 2 , 32, + 0xfc003fff, 0xa000033b, 0 , 0, + CP1_ }, /* FLOOR.L.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000043b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000053b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000063b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000073b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000083b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(8) */ + { pool , CVT_W_fmt , 2 , 32, + 0xfc003fff, 0xa000093b, 0 , 0, + CP1_ }, /* CVT.W.fmt */ + { pool , SQRT_fmt , 2 , 32, + 0xfc003fff, 0xa0000a3b, 0 , 0, + CP1_ }, /* SQRT.fmt */ + { pool , FLOOR_W_fmt , 2 , 32, + 0xfc003fff, 0xa0000b3b, 0 , 0, + CP1_ }, /* FLOOR.W.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0000c3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0000d3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0000e3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0000f3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(15) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000103b, &CFC1 , 0, + CP1_ }, /* CFC1 */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000113b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(17) */ + { pool , RECIP_fmt , 2 , 32, + 0xfc003fff, 0xa000123b, 0 , 0, + CP1_ }, /* RECIP.fmt */ + { pool , CEIL_L_fmt , 2 , 32, + 0xfc003fff, 0xa000133b, 0 , 0, + CP1_ }, /* CEIL.L.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000143b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000153b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000163b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000173b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(23) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000183b, &CTC1 , 0, + CP1_ }, /* CTC1 */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000193b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0001a3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(26) */ + { pool , CEIL_W_fmt , 2 , 32, + 0xfc003fff, 0xa0001b3b, 0 , 0, + CP1_ }, /* CEIL.W.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0001c3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0001d3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0001e3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0001f3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(31) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000203b, &MFC1 , 0, + CP1_ }, /* MFC1 */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000213b, &CVT_S_PL , 0, + CP1_ }, /* CVT.S.PL */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000223b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(34) */ + { pool , TRUNC_L_fmt , 2 , 32, + 0xfc003fff, 0xa000233b, 0 , 0, + CP1_ }, /* TRUNC.L.fmt */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000243b, &DMFC1 , 0, + CP1_ | MIPS64_ }, /* DMFC1 */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000253b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(37) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000263b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(38) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000273b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(39) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000283b, &MTC1 , 0, + CP1_ }, /* MTC1 */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000293b, &CVT_S_PU , 0, + CP1_ }, /* CVT.S.PU */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0002a3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(42) */ + { pool , TRUNC_W_fmt , 2 , 32, + 0xfc003fff, 0xa0002b3b, 0 , 0, + CP1_ }, /* TRUNC.W.fmt */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa0002c3b, &DMTC1 , 0, + CP1_ | MIPS64_ }, /* DMTC1 */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0002d3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(45) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0002e3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(46) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0002f3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(47) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000303b, &MFHC1 , 0, + CP1_ }, /* MFHC1 */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000313b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(49) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000323b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(50) */ + { pool , ROUND_L_fmt , 2 , 32, + 0xfc003fff, 0xa000333b, 0 , 0, + CP1_ }, /* ROUND.L.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000343b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(52) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000353b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(53) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000363b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(54) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000373b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(55) */ + { instruction , 0 , 0 , 32, + 0xfc003fff, 0xa000383b, &MTHC1 , 0, + CP1_ }, /* MTHC1 */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa000393b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(57) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0003a3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(58) */ + { pool , ROUND_W_fmt , 2 , 32, + 0xfc003fff, 0xa0003b3b, 0 , 0, + CP1_ }, /* ROUND.W.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0003c3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(60) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0003d3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(61) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0003e3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(62) */ + { reserved_block , 0 , 0 , 32, + 0xfc003fff, 0xa0003f3b, 0 , 0, + CP1_ }, /* POOL32Fxf_0~*(63) */ +}; + + +static const Pool MOV_fmt[4] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000007b, &MOV_S , 0, + CP1_ }, /* MOV.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000207b, &MOV_D , 0, + CP1_ }, /* MOV.D */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa000407b, 0 , 0, + CP1_ }, /* MOV.fmt~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa000607b, 0 , 0, + CP1_ }, /* MOV.fmt~*(3) */ +}; + + +static const Pool ABS_fmt[4] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000037b, &ABS_S , 0, + CP1_ }, /* ABS.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000237b, &ABS_D , 0, + CP1_ }, /* ABS.D */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa000437b, 0 , 0, + CP1_ }, /* ABS.fmt~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa000637b, 0 , 0, + CP1_ }, /* ABS.fmt~*(3) */ +}; + + +static const Pool NEG_fmt[4] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0000b7b, &NEG_S , 0, + CP1_ }, /* NEG.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0002b7b, &NEG_D , 0, + CP1_ }, /* NEG.D */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa0004b7b, 0 , 0, + CP1_ }, /* NEG.fmt~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa0006b7b, 0 , 0, + CP1_ }, /* NEG.fmt~*(3) */ +}; + + +static const Pool CVT_D_fmt[4] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000137b, &CVT_D_S , 0, + CP1_ }, /* CVT.D.S */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000337b, &CVT_D_W , 0, + CP1_ }, /* CVT.D.W */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa000537b, &CVT_D_L , 0, + CP1_ }, /* CVT.D.L */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa000737b, 0 , 0, + CP1_ }, /* CVT.D.fmt~*(3) */ +}; + + +static const Pool CVT_S_fmt[4] = { + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0001b7b, &CVT_S_D , 0, + CP1_ }, /* CVT.S.D */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0003b7b, &CVT_S_W , 0, + CP1_ }, /* CVT.S.W */ + { instruction , 0 , 0 , 32, + 0xfc007fff, 0xa0005b7b, &CVT_S_L , 0, + CP1_ }, /* CVT.S.L */ + { reserved_block , 0 , 0 , 32, + 0xfc007fff, 0xa0007b7b, 0 , 0, + CP1_ }, /* CVT.S.fmt~*(3) */ +}; + + +static const Pool POOL32Fxf_1[32] = { + { pool , MOV_fmt , 4 , 32, + 0xfc001fff, 0xa000007b, 0 , 0, + CP1_ }, /* MOV.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000017b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000027b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(2) */ + { pool , ABS_fmt , 4 , 32, + 0xfc001fff, 0xa000037b, 0 , 0, + CP1_ }, /* ABS.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000047b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000057b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000067b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000077b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000087b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(8) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000097b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(9) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0000a7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(10) */ + { pool , NEG_fmt , 4 , 32, + 0xfc001fff, 0xa0000b7b, 0 , 0, + CP1_ }, /* NEG.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0000c7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0000d7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0000e7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0000f7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(15) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000107b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000117b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(17) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000127b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(18) */ + { pool , CVT_D_fmt , 4 , 32, + 0xfc001fff, 0xa000137b, 0 , 0, + CP1_ }, /* CVT.D.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000147b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000157b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000167b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000177b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000187b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa000197b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0001a7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(26) */ + { pool , CVT_S_fmt , 4 , 32, + 0xfc001fff, 0xa0001b7b, 0 , 0, + CP1_ }, /* CVT.S.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0001c7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0001d7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0001e7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc001fff, 0xa0001f7b, 0 , 0, + CP1_ }, /* POOL32Fxf_1~*(31) */ +}; + + +static const Pool POOL32Fxf[4] = { + { pool , POOL32Fxf_0 , 64 , 32, + 0xfc0000ff, 0xa000003b, 0 , 0, + CP1_ }, /* POOL32Fxf_0 */ + { pool , POOL32Fxf_1 , 32 , 32, + 0xfc0000ff, 0xa000007b, 0 , 0, + CP1_ }, /* POOL32Fxf_1 */ + { reserved_block , 0 , 0 , 32, + 0xfc0000ff, 0xa00000bb, 0 , 0, + CP1_ }, /* POOL32Fxf~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc0000ff, 0xa00000fb, 0 , 0, + CP1_ }, /* POOL32Fxf~*(3) */ +}; + + +static const Pool POOL32F_3[8] = { + { pool , MIN_fmt , 2 , 32, + 0xfc00003f, 0xa0000003, 0 , 0, + CP1_ }, /* MIN.fmt */ + { pool , MAX_fmt , 2 , 32, + 0xfc00003f, 0xa000000b, 0 , 0, + CP1_ }, /* MAX.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa0000013, 0 , 0, + CP1_ }, /* POOL32F_3~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa000001b, 0 , 0, + CP1_ }, /* POOL32F_3~*(3) */ + { pool , MINA_fmt , 2 , 32, + 0xfc00003f, 0xa0000023, 0 , 0, + CP1_ }, /* MINA.fmt */ + { pool , MAXA_fmt , 2 , 32, + 0xfc00003f, 0xa000002b, 0 , 0, + CP1_ }, /* MAXA.fmt */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa0000033, 0 , 0, + CP1_ }, /* POOL32F_3~*(6) */ + { pool , POOL32Fxf , 4 , 32, + 0xfc00003f, 0xa000003b, 0 , 0, + CP1_ }, /* POOL32Fxf */ +}; + + +static const Pool CMP_condn_S[32] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000005, &CMP_AF_S , 0, + CP1_ }, /* CMP.AF.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000045, &CMP_UN_S , 0, + CP1_ }, /* CMP.UN.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000085, &CMP_EQ_S , 0, + CP1_ }, /* CMP.EQ.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00000c5, &CMP_UEQ_S , 0, + CP1_ }, /* CMP.UEQ.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000105, &CMP_LT_S , 0, + CP1_ }, /* CMP.LT.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000145, &CMP_ULT_S , 0, + CP1_ }, /* CMP.ULT.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000185, &CMP_LE_S , 0, + CP1_ }, /* CMP.LE.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00001c5, &CMP_ULE_S , 0, + CP1_ }, /* CMP.ULE.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000205, &CMP_SAF_S , 0, + CP1_ }, /* CMP.SAF.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000245, &CMP_SUN_S , 0, + CP1_ }, /* CMP.SUN.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000285, &CMP_SEQ_S , 0, + CP1_ }, /* CMP.SEQ.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00002c5, &CMP_SUEQ_S , 0, + CP1_ }, /* CMP.SUEQ.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000305, &CMP_SLT_S , 0, + CP1_ }, /* CMP.SLT.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000345, &CMP_SULT_S , 0, + CP1_ }, /* CMP.SULT.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000385, &CMP_SLE_S , 0, + CP1_ }, /* CMP.SLE.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00003c5, &CMP_SULE_S , 0, + CP1_ }, /* CMP.SULE.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000405, 0 , 0, + CP1_ }, /* CMP.condn.S~*(16) */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000445, &CMP_OR_S , 0, + CP1_ }, /* CMP.OR.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000485, &CMP_UNE_S , 0, + CP1_ }, /* CMP.UNE.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00004c5, &CMP_NE_S , 0, + CP1_ }, /* CMP.NE.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000505, 0 , 0, + CP1_ }, /* CMP.condn.S~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000545, 0 , 0, + CP1_ }, /* CMP.condn.S~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000585, 0 , 0, + CP1_ }, /* CMP.condn.S~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa00005c5, 0 , 0, + CP1_ }, /* CMP.condn.S~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000605, 0 , 0, + CP1_ }, /* CMP.condn.S~*(24) */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000645, &CMP_SOR_S , 0, + CP1_ }, /* CMP.SOR.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000685, &CMP_SUNE_S , 0, + CP1_ }, /* CMP.SUNE.S */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00006c5, &CMP_SNE_S , 0, + CP1_ }, /* CMP.SNE.S */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000705, 0 , 0, + CP1_ }, /* CMP.condn.S~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000745, 0 , 0, + CP1_ }, /* CMP.condn.S~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000785, 0 , 0, + CP1_ }, /* CMP.condn.S~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa00007c5, 0 , 0, + CP1_ }, /* CMP.condn.S~*(31) */ +}; + + +static const Pool CMP_condn_D[32] = { + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000015, &CMP_AF_D , 0, + CP1_ }, /* CMP.AF.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000055, &CMP_UN_D , 0, + CP1_ }, /* CMP.UN.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000095, &CMP_EQ_D , 0, + CP1_ }, /* CMP.EQ.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00000d5, &CMP_UEQ_D , 0, + CP1_ }, /* CMP.UEQ.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000115, &CMP_LT_D , 0, + CP1_ }, /* CMP.LT.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000155, &CMP_ULT_D , 0, + CP1_ }, /* CMP.ULT.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000195, &CMP_LE_D , 0, + CP1_ }, /* CMP.LE.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00001d5, &CMP_ULE_D , 0, + CP1_ }, /* CMP.ULE.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000215, &CMP_SAF_D , 0, + CP1_ }, /* CMP.SAF.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000255, &CMP_SUN_D , 0, + CP1_ }, /* CMP.SUN.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000295, &CMP_SEQ_D , 0, + CP1_ }, /* CMP.SEQ.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00002d5, &CMP_SUEQ_D , 0, + CP1_ }, /* CMP.SUEQ.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000315, &CMP_SLT_D , 0, + CP1_ }, /* CMP.SLT.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000355, &CMP_SULT_D , 0, + CP1_ }, /* CMP.SULT.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000395, &CMP_SLE_D , 0, + CP1_ }, /* CMP.SLE.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00003d5, &CMP_SULE_D , 0, + CP1_ }, /* CMP.SULE.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000415, 0 , 0, + CP1_ }, /* CMP.condn.D~*(16) */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000455, &CMP_OR_D , 0, + CP1_ }, /* CMP.OR.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000495, &CMP_UNE_D , 0, + CP1_ }, /* CMP.UNE.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00004d5, &CMP_NE_D , 0, + CP1_ }, /* CMP.NE.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000515, 0 , 0, + CP1_ }, /* CMP.condn.D~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000555, 0 , 0, + CP1_ }, /* CMP.condn.D~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000595, 0 , 0, + CP1_ }, /* CMP.condn.D~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa00005d5, 0 , 0, + CP1_ }, /* CMP.condn.D~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000615, 0 , 0, + CP1_ }, /* CMP.condn.D~*(24) */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000655, &CMP_SOR_D , 0, + CP1_ }, /* CMP.SOR.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa0000695, &CMP_SUNE_D , 0, + CP1_ }, /* CMP.SUNE.D */ + { instruction , 0 , 0 , 32, + 0xfc0007ff, 0xa00006d5, &CMP_SNE_D , 0, + CP1_ }, /* CMP.SNE.D */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000715, 0 , 0, + CP1_ }, /* CMP.condn.D~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000755, 0 , 0, + CP1_ }, /* CMP.condn.D~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa0000795, 0 , 0, + CP1_ }, /* CMP.condn.D~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc0007ff, 0xa00007d5, 0 , 0, + CP1_ }, /* CMP.condn.D~*(31) */ +}; + + +static const Pool POOL32F_5[8] = { + { pool , CMP_condn_S , 32 , 32, + 0xfc00003f, 0xa0000005, 0 , 0, + CP1_ }, /* CMP.condn.S */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa000000d, 0 , 0, + CP1_ }, /* POOL32F_5~*(1) */ + { pool , CMP_condn_D , 32 , 32, + 0xfc00003f, 0xa0000015, 0 , 0, + CP1_ }, /* CMP.condn.D */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa000001d, 0 , 0, + CP1_ }, /* POOL32F_5~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa0000025, 0 , 0, + CP1_ }, /* POOL32F_5~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa000002d, 0 , 0, + CP1_ }, /* POOL32F_5~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa0000035, 0 , 0, + CP1_ }, /* POOL32F_5~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xa000003d, 0 , 0, + CP1_ }, /* POOL32F_5~*(7) */ +}; + + +static const Pool POOL32F[8] = { + { pool , POOL32F_0 , 64 , 32, + 0xfc000007, 0xa0000000, 0 , 0, + CP1_ }, /* POOL32F_0 */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xa0000001, 0 , 0, + CP1_ }, /* POOL32F~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xa0000002, 0 , 0, + CP1_ }, /* POOL32F~*(2) */ + { pool , POOL32F_3 , 8 , 32, + 0xfc000007, 0xa0000003, 0 , 0, + CP1_ }, /* POOL32F_3 */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xa0000004, 0 , 0, + CP1_ }, /* POOL32F~*(4) */ + { pool , POOL32F_5 , 8 , 32, + 0xfc000007, 0xa0000005, 0 , 0, + CP1_ }, /* POOL32F_5 */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xa0000006, 0 , 0, + CP1_ }, /* POOL32F~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xa0000007, 0 , 0, + CP1_ }, /* POOL32F~*(7) */ +}; + + +static const Pool POOL32S_0[64] = { + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000000, 0 , 0, + 0x0 }, /* POOL32S_0~*(0) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000008, &DLSA , 0, + MIPS64_ }, /* DLSA */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000010, &DSLLV , 0, + MIPS64_ }, /* DSLLV */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000018, &DMUL , 0, + MIPS64_ }, /* DMUL */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000020, 0 , 0, + 0x0 }, /* POOL32S_0~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000028, 0 , 0, + 0x0 }, /* POOL32S_0~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000030, 0 , 0, + 0x0 }, /* POOL32S_0~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000038, 0 , 0, + 0x0 }, /* POOL32S_0~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000040, 0 , 0, + 0x0 }, /* POOL32S_0~*(8) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000048, 0 , 0, + 0x0 }, /* POOL32S_0~*(9) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000050, &DSRLV , 0, + MIPS64_ }, /* DSRLV */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000058, &DMUH , 0, + MIPS64_ }, /* DMUH */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000060, 0 , 0, + 0x0 }, /* POOL32S_0~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000068, 0 , 0, + 0x0 }, /* POOL32S_0~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000070, 0 , 0, + 0x0 }, /* POOL32S_0~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000078, 0 , 0, + 0x0 }, /* POOL32S_0~*(15) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000080, 0 , 0, + 0x0 }, /* POOL32S_0~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000088, 0 , 0, + 0x0 }, /* POOL32S_0~*(17) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000090, &DSRAV , 0, + MIPS64_ }, /* DSRAV */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000098, &DMULU , 0, + MIPS64_ }, /* DMULU */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000a0, 0 , 0, + 0x0 }, /* POOL32S_0~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000a8, 0 , 0, + 0x0 }, /* POOL32S_0~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000b0, 0 , 0, + 0x0 }, /* POOL32S_0~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000b8, 0 , 0, + 0x0 }, /* POOL32S_0~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000c0, 0 , 0, + 0x0 }, /* POOL32S_0~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000c8, 0 , 0, + 0x0 }, /* POOL32S_0~*(25) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc00000d0, &DROTRV , 0, + MIPS64_ }, /* DROTRV */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc00000d8, &DMUHU , 0, + MIPS64_ }, /* DMUHU */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000e0, 0 , 0, + 0x0 }, /* POOL32S_0~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000e8, 0 , 0, + 0x0 }, /* POOL32S_0~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000f0, 0 , 0, + 0x0 }, /* POOL32S_0~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000f8, 0 , 0, + 0x0 }, /* POOL32S_0~*(31) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000100, 0 , 0, + 0x0 }, /* POOL32S_0~*(32) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000108, 0 , 0, + 0x0 }, /* POOL32S_0~*(33) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000110, &DADD , 0, + MIPS64_ }, /* DADD */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000118, &DDIV , 0, + MIPS64_ }, /* DDIV */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000120, 0 , 0, + 0x0 }, /* POOL32S_0~*(36) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000128, 0 , 0, + 0x0 }, /* POOL32S_0~*(37) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000130, 0 , 0, + 0x0 }, /* POOL32S_0~*(38) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000138, 0 , 0, + 0x0 }, /* POOL32S_0~*(39) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000140, 0 , 0, + 0x0 }, /* POOL32S_0~*(40) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000148, 0 , 0, + 0x0 }, /* POOL32S_0~*(41) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000150, &DADDU , 0, + MIPS64_ }, /* DADDU */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000158, &DMOD , 0, + MIPS64_ }, /* DMOD */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000160, 0 , 0, + 0x0 }, /* POOL32S_0~*(44) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000168, 0 , 0, + 0x0 }, /* POOL32S_0~*(45) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000170, 0 , 0, + 0x0 }, /* POOL32S_0~*(46) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000178, 0 , 0, + 0x0 }, /* POOL32S_0~*(47) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000180, 0 , 0, + 0x0 }, /* POOL32S_0~*(48) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc0000188, 0 , 0, + 0x0 }, /* POOL32S_0~*(49) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000190, &DSUB , 0, + MIPS64_ }, /* DSUB */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc0000198, &DDIVU , 0, + MIPS64_ }, /* DDIVU */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001a0, 0 , 0, + 0x0 }, /* POOL32S_0~*(52) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001a8, 0 , 0, + 0x0 }, /* POOL32S_0~*(53) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001b0, 0 , 0, + 0x0 }, /* POOL32S_0~*(54) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001b8, 0 , 0, + 0x0 }, /* POOL32S_0~*(55) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001c0, 0 , 0, + 0x0 }, /* POOL32S_0~*(56) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001c8, 0 , 0, + 0x0 }, /* POOL32S_0~*(57) */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc00001d0, &DSUBU , 0, + MIPS64_ }, /* DSUBU */ + { instruction , 0 , 0 , 32, + 0xfc0001ff, 0xc00001d8, &DMODU , 0, + MIPS64_ }, /* DMODU */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001e0, 0 , 0, + 0x0 }, /* POOL32S_0~*(60) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001e8, 0 , 0, + 0x0 }, /* POOL32S_0~*(61) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001f0, 0 , 0, + 0x0 }, /* POOL32S_0~*(62) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001f8, 0 , 0, + 0x0 }, /* POOL32S_0~*(63) */ +}; + + +static const Pool POOL32Sxf_4[128] = { + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000013c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(0) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000033c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000053c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000073c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000093c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0000b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0000d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0000f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000113c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(8) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000133c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(9) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000153c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000173c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(11) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000193c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0001b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0001d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0001f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(15) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000213c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000233c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(17) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000253c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000273c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000293c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0002b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0002d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0002f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000313c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000333c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000353c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000373c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000393c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0003b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0003d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0003f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(31) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000413c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(32) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000433c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(33) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000453c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(34) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000473c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(35) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000493c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(36) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0xc0004b3c, &DCLO , 0, + MIPS64_ }, /* DCLO */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0004d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(38) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0004f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(39) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000513c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(40) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000533c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(41) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000553c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(42) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000573c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(43) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000593c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(44) */ + { instruction , 0 , 0 , 32, + 0xfc00ffff, 0xc0005b3c, &DCLZ , 0, + MIPS64_ }, /* DCLZ */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0005d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(46) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0005f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(47) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000613c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(48) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000633c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(49) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000653c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(50) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000673c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(51) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000693c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(52) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0006b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(53) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0006d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(54) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0006f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(55) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000713c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(56) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000733c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(57) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000753c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(58) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000773c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(59) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000793c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(60) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0007b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(61) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0007d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(62) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0007f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(63) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000813c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(64) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000833c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(65) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000853c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(66) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000873c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(67) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000893c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(68) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0008b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(69) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0008d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(70) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0008f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(71) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000913c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(72) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000933c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(73) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000953c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(74) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000973c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(75) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000993c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(76) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0009b3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(77) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0009d3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(78) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc0009f3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(79) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000a13c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(80) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000a33c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(81) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000a53c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(82) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000a73c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(83) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000a93c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(84) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000ab3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(85) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000ad3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(86) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000af3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(87) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000b13c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(88) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000b33c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(89) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000b53c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(90) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000b73c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(91) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000b93c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(92) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000bb3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(93) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000bd3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(94) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000bf3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(95) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000c13c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(96) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000c33c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(97) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000c53c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(98) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000c73c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(99) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000c93c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(100) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000cb3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(101) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000cd3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(102) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000cf3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(103) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000d13c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(104) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000d33c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(105) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000d53c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(106) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000d73c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(107) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000d93c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(108) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000db3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(109) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000dd3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(110) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000df3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(111) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000e13c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(112) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000e33c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(113) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000e53c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(114) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000e73c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(115) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000e93c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(116) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000eb3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(117) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000ed3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(118) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000ef3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(119) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000f13c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(120) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000f33c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(121) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000f53c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(122) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000f73c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(123) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000f93c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(124) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000fb3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(125) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000fd3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(126) */ + { reserved_block , 0 , 0 , 32, + 0xfc00ffff, 0xc000ff3c, 0 , 0, + 0x0 }, /* POOL32Sxf_4~*(127) */ +}; + + +static const Pool POOL32Sxf[8] = { + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc000003c, 0 , 0, + 0x0 }, /* POOL32Sxf~*(0) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc000007c, 0 , 0, + 0x0 }, /* POOL32Sxf~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000bc, 0 , 0, + 0x0 }, /* POOL32Sxf~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00000fc, 0 , 0, + 0x0 }, /* POOL32Sxf~*(3) */ + { pool , POOL32Sxf_4 , 128 , 32, + 0xfc0001ff, 0xc000013c, 0 , 0, + 0x0 }, /* POOL32Sxf_4 */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc000017c, 0 , 0, + 0x0 }, /* POOL32Sxf~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001bc, 0 , 0, + 0x0 }, /* POOL32Sxf~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc0001ff, 0xc00001fc, 0 , 0, + 0x0 }, /* POOL32Sxf~*(7) */ +}; + + +static const Pool POOL32S_4[8] = { + { instruction , 0 , 0 , 32, + 0xfc00003f, 0xc0000004, &EXTD , 0, + MIPS64_ }, /* EXTD */ + { instruction , 0 , 0 , 32, + 0xfc00003f, 0xc000000c, &EXTD32 , 0, + MIPS64_ }, /* EXTD32 */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xc0000014, 0 , 0, + 0x0 }, /* POOL32S_4~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xc000001c, 0 , 0, + 0x0 }, /* POOL32S_4~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xc0000024, 0 , 0, + 0x0 }, /* POOL32S_4~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xc000002c, 0 , 0, + 0x0 }, /* POOL32S_4~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00003f, 0xc0000034, 0 , 0, + 0x0 }, /* POOL32S_4~*(6) */ + { pool , POOL32Sxf , 8 , 32, + 0xfc00003f, 0xc000003c, 0 , 0, + 0x0 }, /* POOL32Sxf */ +}; + + +static const Pool POOL32S[8] = { + { pool , POOL32S_0 , 64 , 32, + 0xfc000007, 0xc0000000, 0 , 0, + 0x0 }, /* POOL32S_0 */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xc0000001, 0 , 0, + 0x0 }, /* POOL32S~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xc0000002, 0 , 0, + 0x0 }, /* POOL32S~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xc0000003, 0 , 0, + 0x0 }, /* POOL32S~*(3) */ + { pool , POOL32S_4 , 8 , 32, + 0xfc000007, 0xc0000004, 0 , 0, + 0x0 }, /* POOL32S_4 */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xc0000005, 0 , 0, + 0x0 }, /* POOL32S~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xc0000006, 0 , 0, + 0x0 }, /* POOL32S~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc000007, 0xc0000007, 0 , 0, + 0x0 }, /* POOL32S~*(7) */ +}; + + +static const Pool P_LUI[2] = { + { instruction , 0 , 0 , 32, + 0xfc000002, 0xe0000000, &LUI , 0, + 0x0 }, /* LUI */ + { instruction , 0 , 0 , 32, + 0xfc000002, 0xe0000002, &ALUIPC , 0, + 0x0 }, /* ALUIPC */ +}; + + +static const Pool P_GP_LH[2] = { + { instruction , 0 , 0 , 32, + 0xfc1c0001, 0x44100000, &LH_GP_ , 0, + 0x0 }, /* LH[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0001, 0x44100001, &LHU_GP_ , 0, + 0x0 }, /* LHU[GP] */ +}; + + +static const Pool P_GP_SH[2] = { + { instruction , 0 , 0 , 32, + 0xfc1c0001, 0x44140000, &SH_GP_ , 0, + 0x0 }, /* SH[GP] */ + { reserved_block , 0 , 0 , 32, + 0xfc1c0001, 0x44140001, 0 , 0, + 0x0 }, /* P.GP.SH~*(1) */ +}; + + +static const Pool P_GP_CP1[4] = { + { instruction , 0 , 0 , 32, + 0xfc1c0003, 0x44180000, &LWC1_GP_ , 0, + CP1_ }, /* LWC1[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0003, 0x44180001, &SWC1_GP_ , 0, + CP1_ }, /* SWC1[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0003, 0x44180002, &LDC1_GP_ , 0, + CP1_ }, /* LDC1[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0003, 0x44180003, &SDC1_GP_ , 0, + CP1_ }, /* SDC1[GP] */ +}; + + +static const Pool P_GP_M64[4] = { + { instruction , 0 , 0 , 32, + 0xfc1c0003, 0x441c0000, &LWU_GP_ , 0, + MIPS64_ }, /* LWU[GP] */ + { reserved_block , 0 , 0 , 32, + 0xfc1c0003, 0x441c0001, 0 , 0, + 0x0 }, /* P.GP.M64~*(1) */ + { reserved_block , 0 , 0 , 32, + 0xfc1c0003, 0x441c0002, 0 , 0, + 0x0 }, /* P.GP.M64~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc1c0003, 0x441c0003, 0 , 0, + 0x0 }, /* P.GP.M64~*(3) */ +}; + + +static const Pool P_GP_BH[8] = { + { instruction , 0 , 0 , 32, + 0xfc1c0000, 0x44000000, &LB_GP_ , 0, + 0x0 }, /* LB[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0000, 0x44040000, &SB_GP_ , 0, + 0x0 }, /* SB[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0000, 0x44080000, &LBU_GP_ , 0, + 0x0 }, /* LBU[GP] */ + { instruction , 0 , 0 , 32, + 0xfc1c0000, 0x440c0000, &ADDIU_GP_B_ , 0, + 0x0 }, /* ADDIU[GP.B] */ + { pool , P_GP_LH , 2 , 32, + 0xfc1c0000, 0x44100000, 0 , 0, + 0x0 }, /* P.GP.LH */ + { pool , P_GP_SH , 2 , 32, + 0xfc1c0000, 0x44140000, 0 , 0, + 0x0 }, /* P.GP.SH */ + { pool , P_GP_CP1 , 4 , 32, + 0xfc1c0000, 0x44180000, 0 , 0, + 0x0 }, /* P.GP.CP1 */ + { pool , P_GP_M64 , 4 , 32, + 0xfc1c0000, 0x441c0000, 0 , 0, + 0x0 }, /* P.GP.M64 */ +}; + + +static const Pool P_LS_U12[16] = { + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84000000, &LB_U12_ , 0, + 0x0 }, /* LB[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84001000, &SB_U12_ , 0, + 0x0 }, /* SB[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84002000, &LBU_U12_ , 0, + 0x0 }, /* LBU[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84003000, &PREF_U12_ , 0, + 0x0 }, /* PREF[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84004000, &LH_U12_ , 0, + 0x0 }, /* LH[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84005000, &SH_U12_ , 0, + 0x0 }, /* SH[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84006000, &LHU_U12_ , 0, + 0x0 }, /* LHU[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84007000, &LWU_U12_ , 0, + MIPS64_ }, /* LWU[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84008000, &LW_U12_ , 0, + 0x0 }, /* LW[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x84009000, &SW_U12_ , 0, + 0x0 }, /* SW[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8400a000, &LWC1_U12_ , 0, + CP1_ }, /* LWC1[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8400b000, &SWC1_U12_ , 0, + CP1_ }, /* SWC1[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8400c000, &LD_U12_ , 0, + MIPS64_ }, /* LD[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8400d000, &SD_U12_ , 0, + MIPS64_ }, /* SD[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8400e000, &LDC1_U12_ , 0, + CP1_ }, /* LDC1[U12] */ + { instruction , 0 , 0 , 32, + 0xfc00f000, 0x8400f000, &SDC1_U12_ , 0, + CP1_ }, /* SDC1[U12] */ +}; + + +static const Pool P_PREF_S9_[2] = { + { instruction , 0 , 0 , 32, + 0xffe07f00, 0xa7e01800, &SYNCI , 0, + 0x0 }, /* SYNCI */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4001800, &PREF_S9_ , &PREF_S9__cond , + 0x0 }, /* PREF[S9] */ +}; + + +static const Pool P_LS_S0[16] = { + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4000000, &LB_S9_ , 0, + 0x0 }, /* LB[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4000800, &SB_S9_ , 0, + 0x0 }, /* SB[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4001000, &LBU_S9_ , 0, + 0x0 }, /* LBU[S9] */ + { pool , P_PREF_S9_ , 2 , 32, + 0xfc007f00, 0xa4001800, 0 , 0, + 0x0 }, /* P.PREF[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4002000, &LH_S9_ , 0, + 0x0 }, /* LH[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4002800, &SH_S9_ , 0, + 0x0 }, /* SH[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4003000, &LHU_S9_ , 0, + 0x0 }, /* LHU[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4003800, &LWU_S9_ , 0, + MIPS64_ }, /* LWU[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4004000, &LW_S9_ , 0, + 0x0 }, /* LW[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4004800, &SW_S9_ , 0, + 0x0 }, /* SW[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4005000, &LWC1_S9_ , 0, + CP1_ }, /* LWC1[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4005800, &SWC1_S9_ , 0, + CP1_ }, /* SWC1[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4006000, &LD_S9_ , 0, + MIPS64_ }, /* LD[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4006800, &SD_S9_ , 0, + MIPS64_ }, /* SD[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4007000, &LDC1_S9_ , 0, + CP1_ }, /* LDC1[S9] */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4007800, &SDC1_S9_ , 0, + CP1_ }, /* SDC1[S9] */ +}; + + +static const Pool ASET_ACLR[2] = { + { instruction , 0 , 0 , 32, + 0xfe007f00, 0xa4001100, &ASET , 0, + MCU_ }, /* ASET */ + { instruction , 0 , 0 , 32, + 0xfe007f00, 0xa6001100, &ACLR , 0, + MCU_ }, /* ACLR */ +}; + + +static const Pool P_LL[4] = { + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005100, &LL , 0, + 0x0 }, /* LL */ + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005101, &LLWP , 0, + XNP_ }, /* LLWP */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005102, 0 , 0, + 0x0 }, /* P.LL~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005103, 0 , 0, + 0x0 }, /* P.LL~*(3) */ +}; + + +static const Pool P_SC[4] = { + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005900, &SC , 0, + 0x0 }, /* SC */ + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005901, &SCWP , 0, + XNP_ }, /* SCWP */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005902, 0 , 0, + 0x0 }, /* P.SC~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005903, 0 , 0, + 0x0 }, /* P.SC~*(3) */ +}; + + +static const Pool P_LLD[8] = { + { instruction , 0 , 0 , 32, + 0xfc007f07, 0xa4007100, &LLD , 0, + MIPS64_ }, /* LLD */ + { instruction , 0 , 0 , 32, + 0xfc007f07, 0xa4007101, &LLDP , 0, + MIPS64_ }, /* LLDP */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007102, 0 , 0, + 0x0 }, /* P.LLD~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007103, 0 , 0, + 0x0 }, /* P.LLD~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007104, 0 , 0, + 0x0 }, /* P.LLD~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007105, 0 , 0, + 0x0 }, /* P.LLD~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007106, 0 , 0, + 0x0 }, /* P.LLD~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007107, 0 , 0, + 0x0 }, /* P.LLD~*(7) */ +}; + + +static const Pool P_SCD[8] = { + { instruction , 0 , 0 , 32, + 0xfc007f07, 0xa4007900, &SCD , 0, + MIPS64_ }, /* SCD */ + { instruction , 0 , 0 , 32, + 0xfc007f07, 0xa4007901, &SCDP , 0, + MIPS64_ }, /* SCDP */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007902, 0 , 0, + 0x0 }, /* P.SCD~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007903, 0 , 0, + 0x0 }, /* P.SCD~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007904, 0 , 0, + 0x0 }, /* P.SCD~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007905, 0 , 0, + 0x0 }, /* P.SCD~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007906, 0 , 0, + 0x0 }, /* P.SCD~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f07, 0xa4007907, 0 , 0, + 0x0 }, /* P.SCD~*(7) */ +}; + + +static const Pool P_LS_S1[16] = { + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4000100, 0 , 0, + 0x0 }, /* P.LS.S1~*(0) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4000900, 0 , 0, + 0x0 }, /* P.LS.S1~*(1) */ + { pool , ASET_ACLR , 2 , 32, + 0xfc007f00, 0xa4001100, 0 , 0, + 0x0 }, /* ASET_ACLR */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4001900, 0 , 0, + 0x0 }, /* P.LS.S1~*(3) */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4002100, &UALH , 0, + XMMS_ }, /* UALH */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4002900, &UASH , 0, + XMMS_ }, /* UASH */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4003100, 0 , 0, + 0x0 }, /* P.LS.S1~*(6) */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4003900, &CACHE , 0, + CP0_ }, /* CACHE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4004100, &LWC2 , 0, + CP2_ }, /* LWC2 */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4004900, &SWC2 , 0, + CP2_ }, /* SWC2 */ + { pool , P_LL , 4 , 32, + 0xfc007f00, 0xa4005100, 0 , 0, + 0x0 }, /* P.LL */ + { pool , P_SC , 4 , 32, + 0xfc007f00, 0xa4005900, 0 , 0, + 0x0 }, /* P.SC */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4006100, &LDC2 , 0, + CP2_ }, /* LDC2 */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4006900, &SDC2 , 0, + CP2_ }, /* SDC2 */ + { pool , P_LLD , 8 , 32, + 0xfc007f00, 0xa4007100, 0 , 0, + 0x0 }, /* P.LLD */ + { pool , P_SCD , 8 , 32, + 0xfc007f00, 0xa4007900, 0 , 0, + 0x0 }, /* P.SCD */ +}; + + +static const Pool P_PREFE[2] = { + { instruction , 0 , 0 , 32, + 0xffe07f00, 0xa7e01a00, &SYNCIE , 0, + CP0_ | EVA_ }, /* SYNCIE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4001a00, &PREFE , &PREFE_cond , + CP0_ | EVA_ }, /* PREFE */ +}; + + +static const Pool P_LLE[4] = { + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005200, &LLE , 0, + CP0_ | EVA_ }, /* LLE */ + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005201, &LLWPE , 0, + CP0_ | EVA_ }, /* LLWPE */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005202, 0 , 0, + 0x0 }, /* P.LLE~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005203, 0 , 0, + 0x0 }, /* P.LLE~*(3) */ +}; + + +static const Pool P_SCE[4] = { + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005a00, &SCE , 0, + CP0_ | EVA_ }, /* SCE */ + { instruction , 0 , 0 , 32, + 0xfc007f03, 0xa4005a01, &SCWPE , 0, + CP0_ | EVA_ }, /* SCWPE */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005a02, 0 , 0, + 0x0 }, /* P.SCE~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f03, 0xa4005a03, 0 , 0, + 0x0 }, /* P.SCE~*(3) */ +}; + + +static const Pool P_LS_E0[16] = { + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4000200, &LBE , 0, + CP0_ | EVA_ }, /* LBE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4000a00, &SBE , 0, + CP0_ | EVA_ }, /* SBE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4001200, &LBUE , 0, + CP0_ | EVA_ }, /* LBUE */ + { pool , P_PREFE , 2 , 32, + 0xfc007f00, 0xa4001a00, 0 , 0, + 0x0 }, /* P.PREFE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4002200, &LHE , 0, + CP0_ | EVA_ }, /* LHE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4002a00, &SHE , 0, + CP0_ | EVA_ }, /* SHE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4003200, &LHUE , 0, + CP0_ | EVA_ }, /* LHUE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4003a00, &CACHEE , 0, + CP0_ | EVA_ }, /* CACHEE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4004200, &LWE , 0, + CP0_ | EVA_ }, /* LWE */ + { instruction , 0 , 0 , 32, + 0xfc007f00, 0xa4004a00, &SWE , 0, + CP0_ | EVA_ }, /* SWE */ + { pool , P_LLE , 4 , 32, + 0xfc007f00, 0xa4005200, 0 , 0, + 0x0 }, /* P.LLE */ + { pool , P_SCE , 4 , 32, + 0xfc007f00, 0xa4005a00, 0 , 0, + 0x0 }, /* P.SCE */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4006200, 0 , 0, + 0x0 }, /* P.LS.E0~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4006a00, 0 , 0, + 0x0 }, /* P.LS.E0~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4007200, 0 , 0, + 0x0 }, /* P.LS.E0~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc007f00, 0xa4007a00, 0 , 0, + 0x0 }, /* P.LS.E0~*(15) */ +}; + + +static const Pool P_LS_WM[2] = { + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000400, &LWM , 0, + XMMS_ }, /* LWM */ + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000c00, &SWM , 0, + XMMS_ }, /* SWM */ +}; + + +static const Pool P_LS_UAWM[2] = { + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000500, &UALWM , 0, + XMMS_ }, /* UALWM */ + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000d00, &UASWM , 0, + XMMS_ }, /* UASWM */ +}; + + +static const Pool P_LS_DM[2] = { + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000600, &LDM , 0, + MIPS64_ }, /* LDM */ + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000e00, &SDM , 0, + MIPS64_ }, /* SDM */ +}; + + +static const Pool P_LS_UADM[2] = { + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000700, &UALDM , 0, + MIPS64_ }, /* UALDM */ + { instruction , 0 , 0 , 32, + 0xfc000f00, 0xa4000f00, &UASDM , 0, + MIPS64_ }, /* UASDM */ +}; + + +static const Pool P_LS_S9[8] = { + { pool , P_LS_S0 , 16 , 32, + 0xfc000700, 0xa4000000, 0 , 0, + 0x0 }, /* P.LS.S0 */ + { pool , P_LS_S1 , 16 , 32, + 0xfc000700, 0xa4000100, 0 , 0, + 0x0 }, /* P.LS.S1 */ + { pool , P_LS_E0 , 16 , 32, + 0xfc000700, 0xa4000200, 0 , 0, + 0x0 }, /* P.LS.E0 */ + { reserved_block , 0 , 0 , 32, + 0xfc000700, 0xa4000300, 0 , 0, + 0x0 }, /* P.LS.S9~*(3) */ + { pool , P_LS_WM , 2 , 32, + 0xfc000700, 0xa4000400, 0 , 0, + 0x0 }, /* P.LS.WM */ + { pool , P_LS_UAWM , 2 , 32, + 0xfc000700, 0xa4000500, 0 , 0, + 0x0 }, /* P.LS.UAWM */ + { pool , P_LS_DM , 2 , 32, + 0xfc000700, 0xa4000600, 0 , 0, + 0x0 }, /* P.LS.DM */ + { pool , P_LS_UADM , 2 , 32, + 0xfc000700, 0xa4000700, 0 , 0, + 0x0 }, /* P.LS.UADM */ +}; + + +static const Pool P_BAL[2] = { + { branch_instruction , 0 , 0 , 32, + 0xfe000000, 0x28000000, &BC_32_ , 0, + 0x0 }, /* BC[32] */ + { call_instruction , 0 , 0 , 32, + 0xfe000000, 0x2a000000, &BALC_32_ , 0, + 0x0 }, /* BALC[32] */ +}; + + +static const Pool P_BALRSC[2] = { + { branch_instruction , 0 , 0 , 32, + 0xffe0f000, 0x48008000, &BRSC , 0, + 0x0 }, /* BRSC */ + { call_instruction , 0 , 0 , 32, + 0xfc00f000, 0x48008000, &BALRSC , &BALRSC_cond , + 0x0 }, /* BALRSC */ +}; + + +static const Pool P_J[16] = { + { call_instruction , 0 , 0 , 32, + 0xfc00f000, 0x48000000, &JALRC_32_ , 0, + 0x0 }, /* JALRC[32] */ + { call_instruction , 0 , 0 , 32, + 0xfc00f000, 0x48001000, &JALRC_HB , 0, + 0x0 }, /* JALRC.HB */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48002000, 0 , 0, + 0x0 }, /* P.J~*(2) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48003000, 0 , 0, + 0x0 }, /* P.J~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48004000, 0 , 0, + 0x0 }, /* P.J~*(4) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48005000, 0 , 0, + 0x0 }, /* P.J~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48006000, 0 , 0, + 0x0 }, /* P.J~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48007000, 0 , 0, + 0x0 }, /* P.J~*(7) */ + { pool , P_BALRSC , 2 , 32, + 0xfc00f000, 0x48008000, 0 , 0, + 0x0 }, /* P.BALRSC */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x48009000, 0 , 0, + 0x0 }, /* P.J~*(9) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x4800a000, 0 , 0, + 0x0 }, /* P.J~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x4800b000, 0 , 0, + 0x0 }, /* P.J~*(11) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x4800c000, 0 , 0, + 0x0 }, /* P.J~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x4800d000, 0 , 0, + 0x0 }, /* P.J~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x4800e000, 0 , 0, + 0x0 }, /* P.J~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc00f000, 0x4800f000, 0 , 0, + 0x0 }, /* P.J~*(15) */ +}; + + +static const Pool P_BR3A[32] = { + { branch_instruction , 0 , 0 , 32, + 0xfc1fc000, 0x88004000, &BC1EQZC , 0, + CP1_ }, /* BC1EQZC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1fc000, 0x88014000, &BC1NEZC , 0, + CP1_ }, /* BC1NEZC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1fc000, 0x88024000, &BC2EQZC , 0, + CP2_ }, /* BC2EQZC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1fc000, 0x88034000, &BC2NEZC , 0, + CP2_ }, /* BC2NEZC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1fc000, 0x88044000, &BPOSGE32C , 0, + DSP_ }, /* BPOSGE32C */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88054000, 0 , 0, + 0x0 }, /* P.BR3A~*(5) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88064000, 0 , 0, + 0x0 }, /* P.BR3A~*(6) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88074000, 0 , 0, + 0x0 }, /* P.BR3A~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88084000, 0 , 0, + 0x0 }, /* P.BR3A~*(8) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88094000, 0 , 0, + 0x0 }, /* P.BR3A~*(9) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x880a4000, 0 , 0, + 0x0 }, /* P.BR3A~*(10) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x880b4000, 0 , 0, + 0x0 }, /* P.BR3A~*(11) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x880c4000, 0 , 0, + 0x0 }, /* P.BR3A~*(12) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x880d4000, 0 , 0, + 0x0 }, /* P.BR3A~*(13) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x880e4000, 0 , 0, + 0x0 }, /* P.BR3A~*(14) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x880f4000, 0 , 0, + 0x0 }, /* P.BR3A~*(15) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88104000, 0 , 0, + 0x0 }, /* P.BR3A~*(16) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88114000, 0 , 0, + 0x0 }, /* P.BR3A~*(17) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88124000, 0 , 0, + 0x0 }, /* P.BR3A~*(18) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88134000, 0 , 0, + 0x0 }, /* P.BR3A~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88144000, 0 , 0, + 0x0 }, /* P.BR3A~*(20) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88154000, 0 , 0, + 0x0 }, /* P.BR3A~*(21) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88164000, 0 , 0, + 0x0 }, /* P.BR3A~*(22) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88174000, 0 , 0, + 0x0 }, /* P.BR3A~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88184000, 0 , 0, + 0x0 }, /* P.BR3A~*(24) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x88194000, 0 , 0, + 0x0 }, /* P.BR3A~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x881a4000, 0 , 0, + 0x0 }, /* P.BR3A~*(26) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x881b4000, 0 , 0, + 0x0 }, /* P.BR3A~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x881c4000, 0 , 0, + 0x0 }, /* P.BR3A~*(28) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x881d4000, 0 , 0, + 0x0 }, /* P.BR3A~*(29) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x881e4000, 0 , 0, + 0x0 }, /* P.BR3A~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc1fc000, 0x881f4000, 0 , 0, + 0x0 }, /* P.BR3A~*(31) */ +}; + + +static const Pool P_BR1[4] = { + { branch_instruction , 0 , 0 , 32, + 0xfc00c000, 0x88000000, &BEQC_32_ , 0, + 0x0 }, /* BEQC[32] */ + { pool , P_BR3A , 32 , 32, + 0xfc00c000, 0x88004000, 0 , 0, + 0x0 }, /* P.BR3A */ + { branch_instruction , 0 , 0 , 32, + 0xfc00c000, 0x88008000, &BGEC , 0, + 0x0 }, /* BGEC */ + { branch_instruction , 0 , 0 , 32, + 0xfc00c000, 0x8800c000, &BGEUC , 0, + 0x0 }, /* BGEUC */ +}; + + +static const Pool P_BR2[4] = { + { branch_instruction , 0 , 0 , 32, + 0xfc00c000, 0xa8000000, &BNEC_32_ , 0, + 0x0 }, /* BNEC[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc00c000, 0xa8004000, 0 , 0, + 0x0 }, /* P.BR2~*(1) */ + { branch_instruction , 0 , 0 , 32, + 0xfc00c000, 0xa8008000, &BLTC , 0, + 0x0 }, /* BLTC */ + { branch_instruction , 0 , 0 , 32, + 0xfc00c000, 0xa800c000, &BLTUC , 0, + 0x0 }, /* BLTUC */ +}; + + +static const Pool P_BRI[8] = { + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc8000000, &BEQIC , 0, + 0x0 }, /* BEQIC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc8040000, &BBEQZC , 0, + XMMS_ }, /* BBEQZC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc8080000, &BGEIC , 0, + 0x0 }, /* BGEIC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc80c0000, &BGEIUC , 0, + 0x0 }, /* BGEIUC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc8100000, &BNEIC , 0, + 0x0 }, /* BNEIC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc8140000, &BBNEZC , 0, + XMMS_ }, /* BBNEZC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc8180000, &BLTIC , 0, + 0x0 }, /* BLTIC */ + { branch_instruction , 0 , 0 , 32, + 0xfc1c0000, 0xc81c0000, &BLTIUC , 0, + 0x0 }, /* BLTIUC */ +}; + + +static const Pool P32[32] = { + { pool , P_ADDIU , 2 , 32, + 0xfc000000, 0x00000000, 0 , 0, + 0x0 }, /* P.ADDIU */ + { pool , P32A , 8 , 32, + 0xfc000000, 0x20000000, 0 , 0, + 0x0 }, /* P32A */ + { pool , P_GP_W , 4 , 32, + 0xfc000000, 0x40000000, 0 , 0, + 0x0 }, /* P.GP.W */ + { pool , POOL48I , 32 , 48, + 0xfc0000000000ull, 0x600000000000ull, 0 , 0, + 0x0 }, /* POOL48I */ + { pool , P_U12 , 16 , 32, + 0xfc000000, 0x80000000, 0 , 0, + 0x0 }, /* P.U12 */ + { pool , POOL32F , 8 , 32, + 0xfc000000, 0xa0000000, 0 , 0, + CP1_ }, /* POOL32F */ + { pool , POOL32S , 8 , 32, + 0xfc000000, 0xc0000000, 0 , 0, + 0x0 }, /* POOL32S */ + { pool , P_LUI , 2 , 32, + 0xfc000000, 0xe0000000, 0 , 0, + 0x0 }, /* P.LUI */ + { instruction , 0 , 0 , 32, + 0xfc000000, 0x04000000, &ADDIUPC_32_ , 0, + 0x0 }, /* ADDIUPC[32] */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x24000000, 0 , 0, + 0x0 }, /* P32~*(5) */ + { pool , P_GP_BH , 8 , 32, + 0xfc000000, 0x44000000, 0 , 0, + 0x0 }, /* P.GP.BH */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x64000000, 0 , 0, + 0x0 }, /* P32~*(13) */ + { pool , P_LS_U12 , 16 , 32, + 0xfc000000, 0x84000000, 0 , 0, + 0x0 }, /* P.LS.U12 */ + { pool , P_LS_S9 , 8 , 32, + 0xfc000000, 0xa4000000, 0 , 0, + 0x0 }, /* P.LS.S9 */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0xc4000000, 0 , 0, + 0x0 }, /* P32~*(25) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0xe4000000, 0 , 0, + 0x0 }, /* P32~*(29) */ + { call_instruction , 0 , 0 , 32, + 0xfc000000, 0x08000000, &MOVE_BALC , 0, + XMMS_ }, /* MOVE.BALC */ + { pool , P_BAL , 2 , 32, + 0xfc000000, 0x28000000, 0 , 0, + 0x0 }, /* P.BAL */ + { pool , P_J , 16 , 32, + 0xfc000000, 0x48000000, 0 , 0, + 0x0 }, /* P.J */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x68000000, 0 , 0, + 0x0 }, /* P32~*(14) */ + { pool , P_BR1 , 4 , 32, + 0xfc000000, 0x88000000, 0 , 0, + 0x0 }, /* P.BR1 */ + { pool , P_BR2 , 4 , 32, + 0xfc000000, 0xa8000000, 0 , 0, + 0x0 }, /* P.BR2 */ + { pool , P_BRI , 8 , 32, + 0xfc000000, 0xc8000000, 0 , 0, + 0x0 }, /* P.BRI */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0xe8000000, 0 , 0, + 0x0 }, /* P32~*(30) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x0c000000, 0 , 0, + 0x0 }, /* P32~*(3) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x2c000000, 0 , 0, + 0x0 }, /* P32~*(7) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x4c000000, 0 , 0, + 0x0 }, /* P32~*(11) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x6c000000, 0 , 0, + 0x0 }, /* P32~*(15) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0x8c000000, 0 , 0, + 0x0 }, /* P32~*(19) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0xac000000, 0 , 0, + 0x0 }, /* P32~*(23) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0xcc000000, 0 , 0, + 0x0 }, /* P32~*(27) */ + { reserved_block , 0 , 0 , 32, + 0xfc000000, 0xec000000, 0 , 0, + 0x0 }, /* P32~*(31) */ +}; + + +static const Pool P16_SYSCALL[2] = { + { instruction , 0 , 0 , 16, + 0xfffc , 0x1008 , &SYSCALL_16_ , 0, + 0x0 }, /* SYSCALL[16] */ + { instruction , 0 , 0 , 16, + 0xfffc , 0x100c , &HYPCALL_16_ , 0, + CP0_ | VZ_ }, /* HYPCALL[16] */ +}; + + +static const Pool P16_RI[4] = { + { reserved_block , 0 , 0 , 16, + 0xfff8 , 0x1000 , 0 , 0, + 0x0 }, /* P16.RI~*(0) */ + { pool , P16_SYSCALL , 2 , 16, + 0xfff8 , 0x1008 , 0 , 0, + 0x0 }, /* P16.SYSCALL */ + { instruction , 0 , 0 , 16, + 0xfff8 , 0x1010 , &BREAK_16_ , 0, + 0x0 }, /* BREAK[16] */ + { instruction , 0 , 0 , 16, + 0xfff8 , 0x1018 , &SDBBP_16_ , 0, + EJTAG_ }, /* SDBBP[16] */ +}; + + +static const Pool P16_MV[2] = { + { pool , P16_RI , 4 , 16, + 0xffe0 , 0x1000 , 0 , 0, + 0x0 }, /* P16.RI */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0x1000 , &MOVE , &MOVE_cond , + 0x0 }, /* MOVE */ +}; + + +static const Pool P16_SHIFT[2] = { + { instruction , 0 , 0 , 16, + 0xfc08 , 0x3000 , &SLL_16_ , 0, + 0x0 }, /* SLL[16] */ + { instruction , 0 , 0 , 16, + 0xfc08 , 0x3008 , &SRL_16_ , 0, + 0x0 }, /* SRL[16] */ +}; + + +static const Pool POOL16C_00[4] = { + { instruction , 0 , 0 , 16, + 0xfc0f , 0x5000 , &NOT_16_ , 0, + 0x0 }, /* NOT[16] */ + { instruction , 0 , 0 , 16, + 0xfc0f , 0x5004 , &XOR_16_ , 0, + 0x0 }, /* XOR[16] */ + { instruction , 0 , 0 , 16, + 0xfc0f , 0x5008 , &AND_16_ , 0, + 0x0 }, /* AND[16] */ + { instruction , 0 , 0 , 16, + 0xfc0f , 0x500c , &OR_16_ , 0, + 0x0 }, /* OR[16] */ +}; + + +static const Pool POOL16C_0[2] = { + { pool , POOL16C_00 , 4 , 16, + 0xfc03 , 0x5000 , 0 , 0, + 0x0 }, /* POOL16C_00 */ + { reserved_block , 0 , 0 , 16, + 0xfc03 , 0x5002 , 0 , 0, + 0x0 }, /* POOL16C_0~*(1) */ +}; + + +static const Pool P16C[2] = { + { pool , POOL16C_0 , 2 , 16, + 0xfc01 , 0x5000 , 0 , 0, + 0x0 }, /* POOL16C_0 */ + { instruction , 0 , 0 , 16, + 0xfc01 , 0x5001 , &LWXS_16_ , 0, + 0x0 }, /* LWXS[16] */ +}; + + +static const Pool P16_A1[2] = { + { reserved_block , 0 , 0 , 16, + 0xfc40 , 0x7000 , 0 , 0, + 0x0 }, /* P16.A1~*(0) */ + { instruction , 0 , 0 , 16, + 0xfc40 , 0x7040 , &ADDIU_R1_SP_ , 0, + 0x0 }, /* ADDIU[R1.SP] */ +}; + + +static const Pool P_ADDIU_RS5_[2] = { + { instruction , 0 , 0 , 16, + 0xffe8 , 0x9008 , &NOP_16_ , 0, + 0x0 }, /* NOP[16] */ + { instruction , 0 , 0 , 16, + 0xfc08 , 0x9008 , &ADDIU_RS5_ , &ADDIU_RS5__cond , + 0x0 }, /* ADDIU[RS5] */ +}; + + +static const Pool P16_A2[2] = { + { instruction , 0 , 0 , 16, + 0xfc08 , 0x9000 , &ADDIU_R2_ , 0, + 0x0 }, /* ADDIU[R2] */ + { pool , P_ADDIU_RS5_ , 2 , 16, + 0xfc08 , 0x9008 , 0 , 0, + 0x0 }, /* P.ADDIU[RS5] */ +}; + + +static const Pool P16_ADDU[2] = { + { instruction , 0 , 0 , 16, + 0xfc01 , 0xb000 , &ADDU_16_ , 0, + 0x0 }, /* ADDU[16] */ + { instruction , 0 , 0 , 16, + 0xfc01 , 0xb001 , &SUBU_16_ , 0, + 0x0 }, /* SUBU[16] */ +}; + + +static const Pool P16_JRC[2] = { + { branch_instruction , 0 , 0 , 16, + 0xfc1f , 0xd800 , &JRC , 0, + 0x0 }, /* JRC */ + { call_instruction , 0 , 0 , 16, + 0xfc1f , 0xd810 , &JALRC_16_ , 0, + 0x0 }, /* JALRC[16] */ +}; + + +static const Pool P16_BR1[2] = { + { branch_instruction , 0 , 0 , 16, + 0xfc00 , 0xd800 , &BEQC_16_ , &BEQC_16__cond , + XMMS_ }, /* BEQC[16] */ + { branch_instruction , 0 , 0 , 16, + 0xfc00 , 0xd800 , &BNEC_16_ , &BNEC_16__cond , + XMMS_ }, /* BNEC[16] */ +}; + + +static const Pool P16_BR[2] = { + { pool , P16_JRC , 2 , 16, + 0xfc0f , 0xd800 , 0 , 0, + 0x0 }, /* P16.JRC */ + { pool , P16_BR1 , 2 , 16, + 0xfc00 , 0xd800 , 0 , &P16_BR1_cond , + 0x0 }, /* P16.BR1 */ +}; + + +static const Pool P16_SR[2] = { + { instruction , 0 , 0 , 16, + 0xfd00 , 0x1c00 , &SAVE_16_ , 0, + 0x0 }, /* SAVE[16] */ + { return_instruction , 0 , 0 , 16, + 0xfd00 , 0x1d00 , &RESTORE_JRC_16_ , 0, + 0x0 }, /* RESTORE.JRC[16] */ +}; + + +static const Pool P16_4X4[4] = { + { instruction , 0 , 0 , 16, + 0xfd08 , 0x3c00 , &ADDU_4X4_ , 0, + XMMS_ }, /* ADDU[4X4] */ + { instruction , 0 , 0 , 16, + 0xfd08 , 0x3c08 , &MUL_4X4_ , 0, + XMMS_ }, /* MUL[4X4] */ + { reserved_block , 0 , 0 , 16, + 0xfd08 , 0x3d00 , 0 , 0, + 0x0 }, /* P16.4X4~*(2) */ + { reserved_block , 0 , 0 , 16, + 0xfd08 , 0x3d08 , 0 , 0, + 0x0 }, /* P16.4X4~*(3) */ +}; + + +static const Pool P16_LB[4] = { + { instruction , 0 , 0 , 16, + 0xfc0c , 0x5c00 , &LB_16_ , 0, + 0x0 }, /* LB[16] */ + { instruction , 0 , 0 , 16, + 0xfc0c , 0x5c04 , &SB_16_ , 0, + 0x0 }, /* SB[16] */ + { instruction , 0 , 0 , 16, + 0xfc0c , 0x5c08 , &LBU_16_ , 0, + 0x0 }, /* LBU[16] */ + { reserved_block , 0 , 0 , 16, + 0xfc0c , 0x5c0c , 0 , 0, + 0x0 }, /* P16.LB~*(3) */ +}; + + +static const Pool P16_LH[4] = { + { instruction , 0 , 0 , 16, + 0xfc09 , 0x7c00 , &LH_16_ , 0, + 0x0 }, /* LH[16] */ + { instruction , 0 , 0 , 16, + 0xfc09 , 0x7c01 , &SH_16_ , 0, + 0x0 }, /* SH[16] */ + { instruction , 0 , 0 , 16, + 0xfc09 , 0x7c08 , &LHU_16_ , 0, + 0x0 }, /* LHU[16] */ + { reserved_block , 0 , 0 , 16, + 0xfc09 , 0x7c09 , 0 , 0, + 0x0 }, /* P16.LH~*(3) */ +}; + + +static const Pool P16[32] = { + { pool , P16_MV , 2 , 16, + 0xfc00 , 0x1000 , 0 , 0, + 0x0 }, /* P16.MV */ + { pool , P16_SHIFT , 2 , 16, + 0xfc00 , 0x3000 , 0 , 0, + 0x0 }, /* P16.SHIFT */ + { pool , P16C , 2 , 16, + 0xfc00 , 0x5000 , 0 , 0, + 0x0 }, /* P16C */ + { pool , P16_A1 , 2 , 16, + 0xfc00 , 0x7000 , 0 , 0, + 0x0 }, /* P16.A1 */ + { pool , P16_A2 , 2 , 16, + 0xfc00 , 0x9000 , 0 , 0, + 0x0 }, /* P16.A2 */ + { pool , P16_ADDU , 2 , 16, + 0xfc00 , 0xb000 , 0 , 0, + 0x0 }, /* P16.ADDU */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xd000 , &LI_16_ , 0, + 0x0 }, /* LI[16] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xf000 , &ANDI_16_ , 0, + 0x0 }, /* ANDI[16] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0x1400 , &LW_16_ , 0, + 0x0 }, /* LW[16] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0x3400 , &LW_SP_ , 0, + 0x0 }, /* LW[SP] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0x5400 , &LW_GP16_ , 0, + 0x0 }, /* LW[GP16] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0x7400 , &LW_4X4_ , 0, + XMMS_ }, /* LW[4X4] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0x9400 , &SW_16_ , 0, + 0x0 }, /* SW[16] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xb400 , &SW_SP_ , 0, + 0x0 }, /* SW[SP] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xd400 , &SW_GP16_ , 0, + 0x0 }, /* SW[GP16] */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xf400 , &SW_4X4_ , 0, + XMMS_ }, /* SW[4X4] */ + { branch_instruction , 0 , 0 , 16, + 0xfc00 , 0x1800 , &BC_16_ , 0, + 0x0 }, /* BC[16] */ + { call_instruction , 0 , 0 , 16, + 0xfc00 , 0x3800 , &BALC_16_ , 0, + 0x0 }, /* BALC[16] */ + { reserved_block , 0 , 0 , 16, + 0xfc00 , 0x5800 , 0 , 0, + 0x0 }, /* P16~*(10) */ + { reserved_block , 0 , 0 , 16, + 0xfc00 , 0x7800 , 0 , 0, + 0x0 }, /* P16~*(14) */ + { branch_instruction , 0 , 0 , 16, + 0xfc00 , 0x9800 , &BEQZC_16_ , 0, + 0x0 }, /* BEQZC[16] */ + { branch_instruction , 0 , 0 , 16, + 0xfc00 , 0xb800 , &BNEZC_16_ , 0, + 0x0 }, /* BNEZC[16] */ + { pool , P16_BR , 2 , 16, + 0xfc00 , 0xd800 , 0 , 0, + 0x0 }, /* P16.BR */ + { reserved_block , 0 , 0 , 16, + 0xfc00 , 0xf800 , 0 , 0, + 0x0 }, /* P16~*(30) */ + { pool , P16_SR , 2 , 16, + 0xfc00 , 0x1c00 , 0 , 0, + 0x0 }, /* P16.SR */ + { pool , P16_4X4 , 4 , 16, + 0xfc00 , 0x3c00 , 0 , 0, + 0x0 }, /* P16.4X4 */ + { pool , P16_LB , 4 , 16, + 0xfc00 , 0x5c00 , 0 , 0, + 0x0 }, /* P16.LB */ + { pool , P16_LH , 4 , 16, + 0xfc00 , 0x7c00 , 0 , 0, + 0x0 }, /* P16.LH */ + { reserved_block , 0 , 0 , 16, + 0xfc00 , 0x9c00 , 0 , 0, + 0x0 }, /* P16~*(19) */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xbc00 , &MOVEP , 0, + XMMS_ }, /* MOVEP */ + { reserved_block , 0 , 0 , 16, + 0xfc00 , 0xdc00 , 0 , 0, + 0x0 }, /* P16~*(27) */ + { instruction , 0 , 0 , 16, + 0xfc00 , 0xfc00 , &MOVEP_REV_ , 0, + XMMS_ }, /* MOVEP[REV] */ +}; + + +static const Pool MAJOR[2] = { + { pool , P32 , 32 , 32, + 0x10000000, 0x00000000, 0 , 0, + 0x0 }, /* P32 */ + { pool , P16 , 32 , 16, + 0x1000 , 0x1000 , 0 , 0, + 0x0 }, /* P16 */ +}; + +static bool nanomips_dis(const uint16_t *data, char **buf, Dis_info *info) +{ + TABLE_ENTRY_TYPE type; + + /* Handle runtime errors. */ + if (unlikely(sigsetjmp(info->buf, 0) != 0)) { + return false; + } + return Disassemble(data, buf, &type, MAJOR, ARRAY_SIZE(MAJOR), info) >= 0; +} + +static bool read_u16(uint16_t *ret, bfd_vma memaddr, + struct disassemble_info *info) +{ + int status = (*info->read_memory_func)(memaddr, (bfd_byte *)ret, 2, info); + if (status != 0) { + (*info->memory_error_func)(status, memaddr, info); + return false; + } + + if ((info->endian == BFD_ENDIAN_BIG) != HOST_BIG_ENDIAN) { + bswap16s(ret); + } + return true; +} + +int print_insn_nanomips(bfd_vma memaddr, struct disassemble_info *info) +{ + int length; + uint16_t words[3] = { }; + g_autofree char *buf = NULL; + + info->bytes_per_chunk = 2; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + Dis_info disassm_info; + disassm_info.m_pc = memaddr; + disassm_info.fprintf_func = info->fprintf_func; + disassm_info.stream = info->stream; + + if (!read_u16(&words[0], memaddr, info)) { + return -1; + } + length = 2; + + /* Handle 32-bit opcodes. */ + if ((words[0] & 0x1000) == 0) { + if (!read_u16(&words[1], memaddr + 2, info)) { + return -1; + } + length = 4; + + /* Handle 48-bit opcodes. */ + if ((words[0] >> 10) == 0x18) { + if (!read_u16(&words[1], memaddr + 4, info)) { + return -1; + } + length = 6; + } + } + + for (int i = 0; i < ARRAY_SIZE(words); i++) { + if (i * 2 < length) { + (*info->fprintf_func)(info->stream, "%04x ", words[i]); + } else { + (*info->fprintf_func)(info->stream, " "); + } + } + + if (nanomips_dis(words, &buf, &disassm_info)) { + (*info->fprintf_func) (info->stream, "%s", buf); + } + + return length; +} diff --git a/disas/nanomips.cpp b/disas/nanomips.cpp deleted file mode 100644 index 9be8df75dd60..000000000000 --- a/disas/nanomips.cpp +++ /dev/null @@ -1,22398 +0,0 @@ -/* - * Source file for nanoMIPS disassembler component of QEMU - * - * Copyright (C) 2018 Wave Computing, Inc. - * Copyright (C) 2018 Matthew Fortune - * Copyright (C) 2018 Aleksandar Markovic - * - * 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 . - * - */ - -/* - * Documentation used while implementing this component: - * - * [1] "MIPS® Architecture Base: nanoMIPS32(tm) Instruction Set Technical - * Reference Manual", Revision 01.01, April 27, 2018 - */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" - -#include -#include -#include -#include -#include - -#include "nanomips.h" - -#define IMGASSERTONCE(test) - - -int nanomips_dis(char *buf, - unsigned address, - unsigned short one, - unsigned short two, - unsigned short three) -{ - std::string disasm; - uint16 bits[3] = {one, two, three}; - - NMD::TABLE_ENTRY_TYPE type; - NMD d(address, NMD::ALL_ATTRIBUTES); - int size = d.Disassemble(bits, disasm, type); - - strcpy(buf, disasm.c_str()); - return size; -} - -int print_insn_nanomips(bfd_vma memaddr, struct disassemble_info *info) -{ - int status; - bfd_byte buffer[2]; - uint16_t insn1 = 0, insn2 = 0, insn3 = 0; - char buf[200]; - - info->bytes_per_chunk = 2; - info->display_endian = info->endian; - info->insn_info_valid = 1; - info->branch_delay_insns = 0; - info->data_size = 0; - info->insn_type = dis_nonbranch; - info->target = 0; - info->target2 = 0; - - status = (*info->read_memory_func)(memaddr, buffer, 2, info); - if (status != 0) { - (*info->memory_error_func)(status, memaddr, info); - return -1; - } - - if (info->endian == BFD_ENDIAN_BIG) { - insn1 = bfd_getb16(buffer); - } else { - insn1 = bfd_getl16(buffer); - } - (*info->fprintf_func)(info->stream, "%04x ", insn1); - - /* Handle 32-bit opcodes. */ - if ((insn1 & 0x1000) == 0) { - status = (*info->read_memory_func)(memaddr + 2, buffer, 2, info); - if (status != 0) { - (*info->memory_error_func)(status, memaddr + 2, info); - return -1; - } - - if (info->endian == BFD_ENDIAN_BIG) { - insn2 = bfd_getb16(buffer); - } else { - insn2 = bfd_getl16(buffer); - } - (*info->fprintf_func)(info->stream, "%04x ", insn2); - } else { - (*info->fprintf_func)(info->stream, " "); - } - /* Handle 48-bit opcodes. */ - if ((insn1 >> 10) == 0x18) { - status = (*info->read_memory_func)(memaddr + 4, buffer, 2, info); - if (status != 0) { - (*info->memory_error_func)(status, memaddr + 4, info); - return -1; - } - - if (info->endian == BFD_ENDIAN_BIG) { - insn3 = bfd_getb16(buffer); - } else { - insn3 = bfd_getl16(buffer); - } - (*info->fprintf_func)(info->stream, "%04x ", insn3); - } else { - (*info->fprintf_func)(info->stream, " "); - } - - int length = nanomips_dis(buf, memaddr, insn1, insn2, insn3); - - /* FIXME: Should probably use a hash table on the major opcode here. */ - - (*info->fprintf_func) (info->stream, "%s", buf); - if (length > 0) { - return length / 8; - } - - info->insn_type = dis_noninsn; - - return insn3 ? 6 : insn2 ? 4 : 2; -} - - -namespace img -{ - address addr32(address a) - { - return a; - } - - std::string format(const char *format, ...) - { - char buffer[256]; - va_list args; - va_start(args, format); - int err = vsprintf(buffer, format, args); - if (err < 0) { - perror(buffer); - } - va_end(args); - return buffer; - } - - std::string format(const char *format, - std::string s) - { - char buffer[256]; - - sprintf(buffer, format, s.c_str()); - - return buffer; - } - - std::string format(const char *format, - std::string s1, - std::string s2) - { - char buffer[256]; - - sprintf(buffer, format, s1.c_str(), s2.c_str()); - - return buffer; - } - - std::string format(const char *format, - std::string s1, - std::string s2, - std::string s3) - { - char buffer[256]; - - sprintf(buffer, format, s1.c_str(), s2.c_str(), s3.c_str()); - - return buffer; - } - - std::string format(const char *format, - std::string s1, - std::string s2, - std::string s3, - std::string s4) - { - char buffer[256]; - - sprintf(buffer, format, s1.c_str(), s2.c_str(), s3.c_str(), - s4.c_str()); - - return buffer; - } - - std::string format(const char *format, - std::string s1, - std::string s2, - std::string s3, - std::string s4, - std::string s5) - { - char buffer[256]; - - sprintf(buffer, format, s1.c_str(), s2.c_str(), s3.c_str(), - s4.c_str(), s5.c_str()); - - return buffer; - } - - std::string format(const char *format, - uint64 d, - std::string s2) - { - char buffer[256]; - - sprintf(buffer, format, d, s2.c_str()); - - return buffer; - } - - std::string format(const char *format, - std::string s1, - uint64 d, - std::string s2) - { - char buffer[256]; - - sprintf(buffer, format, s1.c_str(), d, s2.c_str()); - - return buffer; - } - - std::string format(const char *format, - std::string s1, - std::string s2, - uint64 d) - { - char buffer[256]; - - sprintf(buffer, format, s1.c_str(), s2.c_str(), d); - - return buffer; - } - - char as_char(int c) - { - return static_cast(c); - } -}; - - -std::string to_string(img::address a) -{ - char buffer[256]; - sprintf(buffer, "0x%" PRIx64, a); - return buffer; -} - - -uint64 extract_bits(uint64 data, uint32 bit_offset, uint32 bit_size) -{ - return (data << (64 - (bit_size + bit_offset))) >> (64 - bit_size); -} - - -int64 sign_extend(int64 data, int msb) -{ - uint64 shift = 63 - msb; - return (data << shift) >> shift; -} - - -uint64 NMD::renumber_registers(uint64 index, uint64 *register_list, - size_t register_list_size) -{ - if (index < register_list_size) { - return register_list[index]; - } - - throw std::runtime_error(img::format( - "Invalid register mapping index %" PRIu64 - ", size of list = %zu", - index, register_list_size)); -} - - -/* - * NMD::decode_gpr_gpr4() - decoder for 'gpr4' gpr encoding type - * - * Map a 4-bit code to the 5-bit register space according to this pattern: - * - * 1 0 - * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * | | | | | | | | | | | | | | | | - * | | | | | | | | | | | | | | | | - * | | | | | | | | | | | └---------------┐ - * | | | | | | | | | | └---------------┐ | - * | | | | | | | | | └---------------┐ | | - * | | | | | | | | └---------------┐ | | | - * | | | | | | | | | | | | | | | | - * | | | | | | | | | | | | | | | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * Used in handling following instructions: - * - * - ADDU[4X4] - * - LW[4X4] - * - MOVEP[REV] - * - MUL[4X4] - * - SW[4X4] - */ -uint64 NMD::decode_gpr_gpr4(uint64 d) -{ - static uint64 register_list[] = { 8, 9, 10, 11, 4, 5, 6, 7, - 16, 17, 18, 19, 20, 21, 22, 23 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -/* - * NMD::decode_gpr_gpr4_zero() - decoder for 'gpr4.zero' gpr encoding type - * - * Map a 4-bit code to the 5-bit register space according to this pattern: - * - * 1 0 - * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * | | | | | | | | | | | | | | | | - * | | | | | | | | | | | | └---------------------┐ - * | | | | | | | | | | | └---------------┐ | - * | | | | | | | | | | └---------------┐ | | - * | | | | | | | | | └---------------┐ | | | - * | | | | | | | | └---------------┐ | | | | - * | | | | | | | | | | | | | | | | - * | | | | | | | | | | | | | | | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * This pattern is the same one used for 'gpr4' gpr encoding type, except for - * the input value 3, that is mapped to the output value 0 instead of 11. - * - * Used in handling following instructions: - * - * - MOVE.BALC - * - MOVEP - * - SW[4X4] - */ -uint64 NMD::decode_gpr_gpr4_zero(uint64 d) -{ - static uint64 register_list[] = { 8, 9, 10, 0, 4, 5, 6, 7, - 16, 17, 18, 19, 20, 21, 22, 23 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -/* - * NMD::decode_gpr_gpr3() - decoder for 'gpr3' gpr encoding type - * - * Map a 3-bit code to the 5-bit register space according to this pattern: - * - * 7 6 5 4 3 2 1 0 - * | | | | | | | | - * | | | | | | | | - * | | | └-----------------------┐ - * | | └-----------------------┐ | - * | └-----------------------┐ | | - * └-----------------------┐ | | | - * | | | | | | | | - * ┌-------┘ | | | | | | | - * | ┌-------┘ | | | | | | - * | | ┌-------┘ | | | | | - * | | | ┌-------┘ | | | | - * | | | | | | | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * Used in handling following instructions: - * - * - ADDIU[R1.SP] - * - ADDIU[R2] - * - ADDU[16] - * - AND[16] - * - ANDI[16] - * - BEQC[16] - * - BEQZC[16] - * - BNEC[16] - * - BNEZC[16] - * - LB[16] - * - LBU[16] - * - LH[16] - * - LHU[16] - * - LI[16] - * - LW[16] - * - LW[GP16] - * - LWXS[16] - * - NOT[16] - * - OR[16] - * - SB[16] - * - SH[16] - * - SLL[16] - * - SRL[16] - * - SUBU[16] - * - SW[16] - * - XOR[16] - */ -uint64 NMD::decode_gpr_gpr3(uint64 d) -{ - static uint64 register_list[] = { 16, 17, 18, 19, 4, 5, 6, 7 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -/* - * NMD::decode_gpr_gpr3_src_store() - decoder for 'gpr3.src.store' gpr encoding - * type - * - * Map a 3-bit code to the 5-bit register space according to this pattern: - * - * 7 6 5 4 3 2 1 0 - * | | | | | | | | - * | | | | | | | └-----------------------┐ - * | | | └-----------------------┐ | - * | | └-----------------------┐ | | - * | └-----------------------┐ | | | - * └-----------------------┐ | | | | - * | | | | | | | | - * ┌-------┘ | | | | | | | - * | ┌-------┘ | | | | | | - * | | ┌-------┘ | | | | | - * | | | | | | | | - * | | | | | | | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * This pattern is the same one used for 'gpr3' gpr encoding type, except for - * the input value 0, that is mapped to the output value 0 instead of 16. - * - * Used in handling following instructions: - * - * - SB[16] - * - SH[16] - * - SW[16] - * - SW[GP16] - */ -uint64 NMD::decode_gpr_gpr3_src_store(uint64 d) -{ - static uint64 register_list[] = { 0, 17, 18, 19, 4, 5, 6, 7 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -/* - * NMD::decode_gpr_gpr2_reg1() - decoder for 'gpr2.reg1' gpr encoding type - * - * Map a 2-bit code to the 5-bit register space according to this pattern: - * - * 3 2 1 0 - * | | | | - * | | | | - * | | | └-------------------┐ - * | | └-------------------┐ | - * | └-------------------┐ | | - * └-------------------┐ | | | - * | | | | - * | | | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * Used in handling following instructions: - * - * - MOVEP - * - MOVEP[REV] - */ -uint64 NMD::decode_gpr_gpr2_reg1(uint64 d) -{ - static uint64 register_list[] = { 4, 5, 6, 7 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -/* - * NMD::decode_gpr_gpr2_reg2() - decoder for 'gpr2.reg2' gpr encoding type - * - * Map a 2-bit code to the 5-bit register space according to this pattern: - * - * 3 2 1 0 - * | | | | - * | | | | - * | | | └-----------------┐ - * | | └-----------------┐ | - * | └-----------------┐ | | - * └-----------------┐ | | | - * | | | | - * | | | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * Used in handling following instructions: - * - * - MOVEP - * - MOVEP[REV] - */ -uint64 NMD::decode_gpr_gpr2_reg2(uint64 d) -{ - static uint64 register_list[] = { 5, 6, 7, 8 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -/* - * NMD::decode_gpr_gpr1() - decoder for 'gpr1' gpr encoding type - * - * Map a 1-bit code to the 5-bit register space according to this pattern: - * - * 1 0 - * | | - * | | - * | └---------------------┐ - * └---------------------┐ | - * | | - * | | - * | | - * | | - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * 3 2 1 0 - * - * Used in handling following instruction: - * - * - MOVE.BALC - */ -uint64 NMD::decode_gpr_gpr1(uint64 d) -{ - static uint64 register_list[] = { 4, 5 }; - return renumber_registers(d, register_list, - sizeof(register_list) / sizeof(register_list[0])); -} - - -uint64 NMD::copy(uint64 d) -{ - return d; -} - - -int64 NMD::copy(int64 d) -{ - return d; -} - - -int64 NMD::neg_copy(uint64 d) -{ - return 0ll - d; -} - - -int64 NMD::neg_copy(int64 d) -{ - return -d; -} - - -/* strange wrapper around gpr3 */ -uint64 NMD::encode_rs3_and_check_rs3_ge_rt3(uint64 d) -{ -return decode_gpr_gpr3(d); -} - - -/* strange wrapper around gpr3 */ -uint64 NMD::encode_rs3_and_check_rs3_lt_rt3(uint64 d) -{ - return decode_gpr_gpr3(d); -} - - -/* nop - done by extraction function */ -uint64 NMD::encode_s_from_address(uint64 d) -{ - return d; -} - - -/* nop - done by extraction function */ -uint64 NMD::encode_u_from_address(uint64 d) -{ - return d; -} - - -/* nop - done by extraction function */ -uint64 NMD::encode_s_from_s_hi(uint64 d) -{ - return d; -} - - -uint64 NMD::encode_count3_from_count(uint64 d) -{ - IMGASSERTONCE(d < 8); - return d == 0ull ? 8ull : d; -} - - -uint64 NMD::encode_shift3_from_shift(uint64 d) -{ - IMGASSERTONCE(d < 8); - return d == 0ull ? 8ull : d; -} - - -/* special value for load literal */ -int64 NMD::encode_eu_from_s_li16(uint64 d) -{ - IMGASSERTONCE(d < 128); - return d == 127 ? -1 : (int64)d; -} - - -uint64 NMD::encode_msbd_from_size(uint64 d) -{ - IMGASSERTONCE(d < 32); - return d + 1; -} - - -uint64 NMD::encode_eu_from_u_andi16(uint64 d) -{ - IMGASSERTONCE(d < 16); - if (d == 12) { - return 0x00ffull; - } - if (d == 13) { - return 0xffffull; - } - return d; -} - - -uint64 NMD::encode_msbd_from_pos_and_size(uint64 d) -{ - IMGASSERTONCE(0); - return d; -} - - -/* save16 / restore16 ???? */ -uint64 NMD::encode_rt1_from_rt(uint64 d) -{ - return d ? 31 : 30; -} - - -/* ? */ -uint64 NMD::encode_lsb_from_pos_and_size(uint64 d) -{ - return d; -} - - -std::string NMD::save_restore_list(uint64 rt, uint64 count, uint64 gp) -{ - std::string str; - - for (uint64 counter = 0; counter != count; counter++) { - bool use_gp = gp && (counter == count - 1); - uint64 this_rt = use_gp ? 28 : ((rt & 0x10) | (rt + counter)) & 0x1f; - str += img::format(",%s", GPR(this_rt)); - } - - return str; -} - - -std::string NMD::GPR(uint64 reg) -{ - static const char *gpr_reg[32] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "a4", "a5", "a6", "a7", "r12", "r13", "r14", "r15", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "r24", "r25", "k0", "k1", "gp", "sp", "fp", "ra" - }; - - if (reg < 32) { - return gpr_reg[reg]; - } - - throw std::runtime_error(img::format("Invalid GPR register index %" PRIu64, - reg)); -} - - -std::string NMD::FPR(uint64 reg) -{ - static const char *fpr_reg[32] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" - }; - - if (reg < 32) { - return fpr_reg[reg]; - } - - throw std::runtime_error(img::format("Invalid FPR register index %" PRIu64, - reg)); -} - - -std::string NMD::AC(uint64 reg) -{ - static const char *ac_reg[4] = { - "ac0", "ac1", "ac2", "ac3" - }; - - if (reg < 4) { - return ac_reg[reg]; - } - - throw std::runtime_error(img::format("Invalid AC register index %" PRIu64, - reg)); -} - - -std::string NMD::IMMEDIATE(uint64 value) -{ - return img::format("0x%" PRIx64, value); -} - - -std::string NMD::IMMEDIATE(int64 value) -{ - return img::format("%" PRId64, value); -} - - -std::string NMD::CPR(uint64 reg) -{ - /* needs more work */ - return img::format("CP%" PRIu64, reg); -} - - -std::string NMD::ADDRESS(uint64 value, int instruction_size) -{ - /* token for string replace */ - /* const char TOKEN_REPLACE = (char)0xa2; */ - img::address address = m_pc + value + instruction_size; - /* symbol replacement */ - /* return img::as_char(TOKEN_REPLACE) + to_string(address); */ - return to_string(address); -} - - -uint64 NMD::extract_op_code_value(const uint16 * data, int size) -{ - switch (size) { - case 16: - return data[0]; - case 32: - return ((uint64)data[0] << 16) | data[1]; - case 48: - return ((uint64)data[0] << 32) | ((uint64)data[1] << 16) | data[2]; - default: - return data[0]; - } -} - - -int NMD::Disassemble(const uint16 * data, std::string & dis, - NMD::TABLE_ENTRY_TYPE & type) -{ - return Disassemble(data, dis, type, MAJOR, 2); -} - - -/* - * Recurse through tables until the instruction is found then return - * the string and size - * - * inputs: - * pointer to a word stream, - * disassember table and size - * returns: - * instruction size - negative is error - * disassembly string - on error will constain error string - */ -int NMD::Disassemble(const uint16 * data, std::string & dis, - NMD::TABLE_ENTRY_TYPE & type, const Pool *table, - int table_size) -{ - try - { - for (int i = 0; i < table_size; i++) { - uint64 op_code = extract_op_code_value(data, - table[i].instructions_size); - if ((op_code & table[i].mask) == table[i].value) { - /* possible match */ - conditional_function cond = table[i].condition; - if ((cond == 0) || (this->*cond)(op_code)) { - try - { - if (table[i].type == pool) { - return Disassemble(data, dis, type, - table[i].next_table, - table[i].next_table_size); - } else if ((table[i].type == instruction) || - (table[i].type == call_instruction) || - (table[i].type == branch_instruction) || - (table[i].type == return_instruction)) { - if ((table[i].attributes != 0) && - (m_requested_instruction_categories & - table[i].attributes) == 0) { - /* - * failed due to instruction having - * an ASE attribute and the requested version - * not having that attribute - */ - dis = "ASE attribute mismatch"; - return -5; - } - disassembly_function dis_fn = table[i].disassembly; - if (dis_fn == 0) { - dis = "disassembler failure - bad table entry"; - return -6; - } - type = table[i].type; - dis = (this->*dis_fn)(op_code); - return table[i].instructions_size; - } else { - dis = "reserved instruction"; - return -2; - } - } - catch (std::runtime_error & e) - { - dis = e.what(); - return -3; /* runtime error */ - } - } - } - } - } - catch (std::exception & e) - { - dis = e.what(); - return -4; /* runtime error */ - } - - dis = "failed to disassemble"; - return -1; /* failed to disassemble */ -} - - -uint64 NMD::extract_code_18_to_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 19); - return value; -} - - -uint64 NMD::extract_shift3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 3); - return value; -} - - -uint64 NMD::extract_u_11_10_9_8_7_6_5_4_3__s3(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 9) << 3; - return value; -} - - -uint64 NMD::extract_count_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 4); - return value; -} - - -uint64 NMD::extract_rtz3_9_8_7(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 7, 3); - return value; -} - - -uint64 NMD::extract_u_17_to_1__s1(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 1, 17) << 1; - return value; -} - - -int64 NMD::extract_s__se9_20_19_18_17_16_15_14_13_12_11(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 11, 10); - value = sign_extend(value, 9); - return value; -} - - -int64 NMD::extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 11; - value |= extract_bits(instruction, 1, 10) << 1; - value = sign_extend(value, 11); - return value; -} - - -uint64 NMD::extract_u_10(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 10, 1); - return value; -} - - -uint64 NMD::extract_rtz4_27_26_25_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 3); - value |= extract_bits(instruction, 25, 1) << 3; - return value; -} - - -uint64 NMD::extract_sa_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 5); - return value; -} - - -uint64 NMD::extract_shift_4_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 5); - return value; -} - - -uint64 NMD::extract_shiftx_10_9_8_7__s1(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 7, 4) << 1; - return value; -} - - -uint64 NMD::extract_hint_25_24_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 5); - return value; -} - - -uint64 NMD::extract_count3_14_13_12(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 12, 3); - return value; -} - - -int64 NMD::extract_s__se31_0_11_to_2_20_to_12_s12(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 31; - value |= extract_bits(instruction, 2, 10) << 21; - value |= extract_bits(instruction, 12, 9) << 12; - value = sign_extend(value, 31); - return value; -} - - -int64 NMD::extract_s__se7_0_6_5_4_3_2_1_s1(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 7; - value |= extract_bits(instruction, 1, 6) << 1; - value = sign_extend(value, 7); - return value; -} - - -uint64 NMD::extract_u2_10_9(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 9, 2); - return value; -} - - -uint64 NMD::extract_code_25_24_23_22_21_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 10); - return value; -} - - -uint64 NMD::extract_rs_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -uint64 NMD::extract_u_2_1__s1(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 1, 2) << 1; - return value; -} - - -uint64 NMD::extract_stripe_6(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 6, 1); - return value; -} - - -uint64 NMD::extract_ac_15_14(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 14, 2); - return value; -} - - -uint64 NMD::extract_shift_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -uint64 NMD::extract_rdl_25_24(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 24, 1); - return value; -} - - -int64 NMD::extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 10; - value |= extract_bits(instruction, 1, 9) << 1; - value = sign_extend(value, 10); - return value; -} - - -uint64 NMD::extract_eu_6_5_4_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 7); - return value; -} - - -uint64 NMD::extract_shift_5_4_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 6); - return value; -} - - -uint64 NMD::extract_count_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 4); - return value; -} - - -uint64 NMD::extract_code_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 3); - return value; -} - - -uint64 NMD::extract_u_11_10_9_8_7_6_5_4_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 12); - return value; -} - - -uint64 NMD::extract_rs_4_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 5); - return value; -} - - -uint64 NMD::extract_u_20_to_3__s3(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 18) << 3; - return value; -} - - -uint64 NMD::extract_u_3_2_1_0__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 4) << 2; - return value; -} - - -uint64 NMD::extract_cofun_25_24_23(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 23); - return value; -} - - -uint64 NMD::extract_u_2_1_0__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 3) << 2; - return value; -} - - -uint64 NMD::extract_rd3_3_2_1(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 1, 3); - return value; -} - - -uint64 NMD::extract_sa_15_14_13_12(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 12, 4); - return value; -} - - -uint64 NMD::extract_rt_25_24_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 5); - return value; -} - - -uint64 NMD::extract_ru_7_6_5_4_3(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 5); - return value; -} - - -uint64 NMD::extract_u_17_to_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 18); - return value; -} - - -uint64 NMD::extract_rsz4_4_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 3); - value |= extract_bits(instruction, 4, 1) << 3; - return value; -} - - -int64 NMD::extract_s__se21_0_20_to_1_s1(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 21; - value |= extract_bits(instruction, 1, 20) << 1; - value = sign_extend(value, 21); - return value; -} - - -uint64 NMD::extract_op_25_to_3(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 23); - return value; -} - - -uint64 NMD::extract_rs4_4_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 3); - value |= extract_bits(instruction, 4, 1) << 3; - return value; -} - - -uint64 NMD::extract_bit_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 3); - return value; -} - - -uint64 NMD::extract_rt_41_40_39_38_37(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 37, 5); - return value; -} - - -int64 NMD::extract_shift__se5_21_20_19_18_17_16(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 16, 6); - value = sign_extend(value, 5); - return value; -} - - -uint64 NMD::extract_rd2_3_8(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 1) << 1; - value |= extract_bits(instruction, 8, 1); - return value; -} - - -uint64 NMD::extract_code_17_to_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 18); - return value; -} - - -uint64 NMD::extract_size_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -int64 NMD::extract_s__se8_15_7_6_5_4_3_2_s2(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 2, 6) << 2; - value |= extract_bits(instruction, 15, 1) << 8; - value = sign_extend(value, 8); - return value; -} - - -uint64 NMD::extract_u_15_to_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 16); - return value; -} - - -uint64 NMD::extract_fs_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -int64 NMD::extract_s__se8_15_7_6_5_4_3_2_1_0(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 8); - value |= extract_bits(instruction, 15, 1) << 8; - value = sign_extend(value, 8); - return value; -} - - -uint64 NMD::extract_stype_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -uint64 NMD::extract_rtl_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 9, 1); - return value; -} - - -uint64 NMD::extract_hs_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -uint64 NMD::extract_sel_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 3); - return value; -} - - -uint64 NMD::extract_lsb_4_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 5); - return value; -} - - -uint64 NMD::extract_gp_2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 2, 1); - return value; -} - - -uint64 NMD::extract_rt3_9_8_7(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 7, 3); - return value; -} - - -uint64 NMD::extract_ft_25_24_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 5); - return value; -} - - -uint64 NMD::extract_u_17_16_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 7); - return value; -} - - -uint64 NMD::extract_cs_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -uint64 NMD::extract_rt4_9_7_6_5(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 5, 3); - value |= extract_bits(instruction, 9, 1) << 3; - return value; -} - - -uint64 NMD::extract_msbt_10_9_8_7_6(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 6, 5); - return value; -} - - -uint64 NMD::extract_u_5_4_3_2_1_0__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 6) << 2; - return value; -} - - -uint64 NMD::extract_sa_15_14_13(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 13, 3); - return value; -} - - -int64 NMD::extract_s__se14_0_13_to_1_s1(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 14; - value |= extract_bits(instruction, 1, 13) << 1; - value = sign_extend(value, 14); - return value; -} - - -uint64 NMD::extract_rs3_6_5_4(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 4, 3); - return value; -} - - -uint64 NMD::extract_u_31_to_0__s32(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 32) << 32; - return value; -} - - -uint64 NMD::extract_shift_10_9_8_7_6(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 6, 5); - return value; -} - - -uint64 NMD::extract_cs_25_24_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 5); - return value; -} - - -uint64 NMD::extract_shiftx_11_10_9_8_7_6(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 6, 6); - return value; -} - - -uint64 NMD::extract_rt_9_8_7_6_5(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 5, 5); - return value; -} - - -uint64 NMD::extract_op_25_24_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 5); - return value; -} - - -uint64 NMD::extract_u_6_5_4_3_2_1_0__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 7) << 2; - return value; -} - - -uint64 NMD::extract_bit_16_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 6); - return value; -} - - -uint64 NMD::extract_mask_20_19_18_17_16_15_14(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 14, 7); - return value; -} - - -uint64 NMD::extract_eu_3_2_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 4); - return value; -} - - -uint64 NMD::extract_u_7_6_5_4__s4(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 4, 4) << 4; - return value; -} - - -int64 NMD::extract_s__se8_15_7_6_5_4_3_s3(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 3, 5) << 3; - value |= extract_bits(instruction, 15, 1) << 8; - value = sign_extend(value, 8); - return value; -} - - -uint64 NMD::extract_ft_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 5); - return value; -} - - -int64 NMD::extract_s__se31_15_to_0_31_to_16(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 16) << 16; - value |= extract_bits(instruction, 16, 16); - value = sign_extend(value, 31); - return value; -} - - -uint64 NMD::extract_u_20_19_18_17_16_15_14_13(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 13, 8); - return value; -} - - -uint64 NMD::extract_u_17_to_2__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 2, 16) << 2; - return value; -} - - -uint64 NMD::extract_rd_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 5); - return value; -} - - -uint64 NMD::extract_c0s_20_19_18_17_16(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 16, 5); - return value; -} - - -uint64 NMD::extract_code_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 2); - return value; -} - - -int64 NMD::extract_s__se25_0_24_to_1_s1(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 1) << 25; - value |= extract_bits(instruction, 1, 24) << 1; - value = sign_extend(value, 25); - return value; -} - - -uint64 NMD::extract_u_1_0(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 2); - return value; -} - - -uint64 NMD::extract_u_3_8__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 3, 1) << 3; - value |= extract_bits(instruction, 8, 1) << 2; - return value; -} - - -uint64 NMD::extract_fd_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 5); - return value; -} - - -uint64 NMD::extract_u_4_3_2_1_0__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 5) << 2; - return value; -} - - -uint64 NMD::extract_rtz4_9_7_6_5(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 5, 3); - value |= extract_bits(instruction, 9, 1) << 3; - return value; -} - - -uint64 NMD::extract_sel_15_14_13_12_11(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 11, 5); - return value; -} - - -uint64 NMD::extract_ct_25_24_23_22_21(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 21, 5); - return value; -} - - -uint64 NMD::extract_u_20_to_2__s2(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 2, 19) << 2; - return value; -} - - -int64 NMD::extract_s__se3_4_2_1_0(uint64 instruction) -{ - int64 value = 0; - value |= extract_bits(instruction, 0, 3); - value |= extract_bits(instruction, 4, 1) << 3; - value = sign_extend(value, 3); - return value; -} - - -uint64 NMD::extract_u_3_2_1_0__s1(uint64 instruction) -{ - uint64 value = 0; - value |= extract_bits(instruction, 0, 4) << 1; - return value; -} - - - -bool NMD::ADDIU_32__cond(uint64 instruction) -{ - uint64 rt = extract_rt_25_24_23_22_21(instruction); - return rt != 0; -} - - -bool NMD::ADDIU_RS5__cond(uint64 instruction) -{ - uint64 rt = extract_rt_9_8_7_6_5(instruction); - return rt != 0; -} - - -bool NMD::BALRSC_cond(uint64 instruction) -{ - uint64 rt = extract_rt_25_24_23_22_21(instruction); - return rt != 0; -} - - -bool NMD::BEQC_16__cond(uint64 instruction) -{ - uint64 rs3 = extract_rs3_6_5_4(instruction); - uint64 rt3 = extract_rt3_9_8_7(instruction); - uint64 u = extract_u_3_2_1_0__s1(instruction); - return rs3 < rt3 && u != 0; -} - - -bool NMD::BNEC_16__cond(uint64 instruction) -{ - uint64 rs3 = extract_rs3_6_5_4(instruction); - uint64 rt3 = extract_rt3_9_8_7(instruction); - uint64 u = extract_u_3_2_1_0__s1(instruction); - return rs3 >= rt3 && u != 0; -} - - -bool NMD::MOVE_cond(uint64 instruction) -{ - uint64 rt = extract_rt_9_8_7_6_5(instruction); - return rt != 0; -} - - -bool NMD::P16_BR1_cond(uint64 instruction) -{ - uint64 u = extract_u_3_2_1_0__s1(instruction); - return u != 0; -} - - -bool NMD::PREF_S9__cond(uint64 instruction) -{ - uint64 hint = extract_hint_25_24_23_22_21(instruction); - return hint != 31; -} - - -bool NMD::PREFE_cond(uint64 instruction) -{ - uint64 hint = extract_hint_25_24_23_22_21(instruction); - return hint != 31; -} - - -bool NMD::SLTU_cond(uint64 instruction) -{ - uint64 rd = extract_rd_15_14_13_12_11(instruction); - return rd != 0; -} - - - -/* - * ABS.D fd, fs - Floating Point Absolute Value - * - * 3 2 1 - * 10987654321098765432109876543210 - * 010001 00000 000101 - * fmt ----- - * fs ----- - * fd ----- - */ -std::string NMD::ABS_D(uint64 instruction) -{ - uint64 fd_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string fs = FPR(copy(fs_value)); - std::string fd = FPR(copy(fd_value)); - - return img::format("ABS.D %s, %s", fd, fs); -} - - -/* - * ABS.S fd, fs - Floating Point Absolute Value - * - * 3 2 1 - * 10987654321098765432109876543210 - * 010001 00000 000101 - * fmt ----- - * fd ----- - * fs ----- - */ -std::string NMD::ABS_S(uint64 instruction) -{ - uint64 fd_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string fs = FPR(copy(fs_value)); - std::string fd = FPR(copy(fd_value)); - - return img::format("ABS.S %s, %s", fd, fs); -} - - -/* - * [DSP] ABSQ_S.PH rt, rs - Find absolute value of two fractional halfwords - * with 16-bit saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0001000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ABSQ_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("ABSQ_S.PH %s, %s", rt, rs); -} - - -/* - * [DSP] ABSQ_S.QB rt, rs - Find absolute value of four fractional byte values - * with 8-bit saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0000000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ABSQ_S_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("ABSQ_S.QB %s, %s", rt, rs); -} - - -/* - * [DSP] ABSQ_S.W rt, rs - Find absolute value of fractional word with 32-bit - * saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ABSQ_S_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("ABSQ_S.W %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ACLR(uint64 instruction) -{ - uint64 bit_value = extract_bit_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string bit = IMMEDIATE(copy(bit_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("ACLR %s, %s(%s)", bit, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADD %s, %s, %s", rd, rs, rt); -} - - -/* - * ADD.D fd, fs, ft - Floating Point Add - * - * 3 2 1 - * 10987654321098765432109876543210 - * 010001 000101 - * fmt ----- - * ft ----- - * fs ----- - * fd ----- - */ -std::string NMD::ADD_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - std::string fd = FPR(copy(fd_value)); - - return img::format("ADD.D %s, %s, %s", fd, fs, ft); -} - - -/* - * ADD.S fd, fs, ft - Floating Point Add - * - * 3 2 1 - * 10987654321098765432109876543210 - * 010001 000101 - * fmt ----- - * ft ----- - * fs ----- - * fd ----- - */ -std::string NMD::ADD_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - std::string fd = FPR(copy(fd_value)); - - return img::format("ADD.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_15_to_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ADDIU %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("ADDIU %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_GP48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("ADDIU %s, $%d, %s", rt, 28, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_GP_B_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ADDIU %s, $%d, %s", rt, 28, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_GP_W_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_20_to_2__s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ADDIU %s, $%d, %s", rt, 28, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_NEG_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(neg_copy(u_value)); - - return img::format("ADDIU %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_R1_SP_(uint64 instruction) -{ - uint64 u_value = extract_u_5_4_3_2_1_0__s2(instruction); - uint64 rt3_value = extract_rt3_9_8_7(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ADDIU %s, $%d, %s", rt3, 29, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0010000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::ADDIU_R2_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_2_1_0__s2(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ADDIU %s, %s, %s", rt3, rs3, u); -} - - -/* - * ADDIU[RS5] rt, s5 - Add Signed Word and Set Carry Bit - * - * 5432109876543210 - * 100100 1 - * rt ----- - * s - --- - */ -std::string NMD::ADDIU_RS5_(uint64 instruction) -{ - uint64 rt_value = extract_rt_9_8_7_6_5(instruction); - int64 s_value = extract_s__se3_4_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("ADDIU %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDIUPC_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - int64 s_value = extract_s__se21_0_20_to_1_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("ADDIUPC %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDIUPC_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 6); - - return img::format("ADDIUPC %s, %s", rt, s); -} - - -/* - * [DSP] ADDQ.PH rd, rt, rs - Add fractional halfword vectors - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00000001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQ_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQ.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDQ_S.PH rd, rt, rs - Add fractional halfword vectors with 16-bit - * saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10000001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQ_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQ_S.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDQ_S.W rd, rt, rs - Add fractional words with 32-bit saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1100000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQ_S_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQ_S.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDQH.PH rd, rt, rs - Add fractional halfword vectors and shift - * right to halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQH_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQH.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDQH_R.PH rd, rt, rs - Add fractional halfword vectors and shift - * right to halve results with rounding - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQH_R_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQH_R.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDQH_R.W rd, rt, rs - Add fractional words and shift right to halve - * results with rounding - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQH_R_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQH_R.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDQH.W rd, rt, rs - Add fractional words and shift right to halve - * results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDQH_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDQH.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDSC rd, rt, rs - Add two signed words and set carry bit - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDSC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDSC %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDU[16] rd3, rs3, rt3 - - * - * 5432109876543210 - * 101100 0 - * rt3 --- - * rs3 --- - * rd3 --- - */ -std::string NMD::ADDU_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 rd3_value = extract_rd3_3_2_1(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string rd3 = GPR(decode_gpr_gpr3(rd3_value)); - - return img::format("ADDU %s, %s, %s", rd3, rs3, rt3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDU_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDU_4X4_(uint64 instruction) -{ - uint64 rt4_value = extract_rt4_9_7_6_5(instruction); - uint64 rs4_value = extract_rs4_4_2_1_0(instruction); - - std::string rs4 = GPR(decode_gpr_gpr4(rs4_value)); - std::string rt4 = GPR(decode_gpr_gpr4(rt4_value)); - - return img::format("ADDU %s, %s", rs4, rt4); -} - - -/* - * [DSP] ADDU.PH rd, rt, rs - Add two pairs of unsigned halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00100001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDU_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDU.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDU.QB rd, rt, rs - Unsigned Add Quad Byte Vectors - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00011001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDU_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDU.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] ADDU_S.PH rd, rt, rs - Add two pairs of unsigned halfwords with 16-bit - * saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10100001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDU_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDU_S.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDU_S.QB rd, rt, rs - Unsigned Add Quad Byte Vectors - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10011001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDU_S_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDU_S.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDUH.QB rd, rt, rs - Unsigned Add Vector Quad-Bytes And Right Shift - * to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00101001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDUH_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDUH.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDUH_R.QB rd, rt, rs - Unsigned Add Vector Quad-Bytes And Right Shift - * to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10101001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDUH_R_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDUH_R.QB %s, %s, %s", rd, rs, rt); -} - -/* - * ADDWC rd, rt, rs - Add Word with Carry Bit - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1111000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ADDWC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ADDWC %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ALUIPC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - int64 s_value = extract_s__se31_0_11_to_2_20_to_12_s12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("ALUIPC %s, %%pcrel_hi(%s)", rt, s); -} - - -/* - * AND[16] rt3, rs3 - - * - * 5432109876543210 - * 101100 - * rt3 --- - * rs3 --- - * eu ---- - */ -std::string NMD::AND_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("AND %s, %s", rs3, rt3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::AND_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("AND %s, %s, %s", rd, rs, rt); -} - - -/* - * ANDI rt, rs, u - - * - * 5432109876543210 - * 101100 - * rt3 --- - * rs3 --- - * eu ---- - */ -std::string NMD::ANDI_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 eu_value = extract_eu_3_2_1_0(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string eu = IMMEDIATE(encode_eu_from_u_andi16(eu_value)); - - return img::format("ANDI %s, %s, %s", rt3, rs3, eu); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ANDI_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ANDI %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::APPEND(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("APPEND %s, %s, %s", rt, rs, sa); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ASET(uint64 instruction) -{ - uint64 bit_value = extract_bit_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string bit = IMMEDIATE(copy(bit_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("ASET %s, %s(%s)", bit, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BALC_16_(uint64 instruction) -{ - int64 s_value = extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(instruction); - - std::string s = ADDRESS(encode_s_from_address(s_value), 2); - - return img::format("BALC %s", s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BALC_32_(uint64 instruction) -{ - int64 s_value = extract_s__se25_0_24_to_1_s1(instruction); - - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BALC %s", s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BALRSC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("BALRSC %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BBEQZC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 bit_value = extract_bit_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string bit = IMMEDIATE(copy(bit_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BBEQZC %s, %s, %s", rt, bit, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BBNEZC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 bit_value = extract_bit_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string bit = IMMEDIATE(copy(bit_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BBNEZC %s, %s, %s", rt, bit, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BC_16_(uint64 instruction) -{ - int64 s_value = extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(instruction); - - std::string s = ADDRESS(encode_s_from_address(s_value), 2); - - return img::format("BC %s", s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BC_32_(uint64 instruction) -{ - int64 s_value = extract_s__se25_0_24_to_1_s1(instruction); - - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BC %s", s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BC1EQZC(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BC1EQZC %s, %s", ft, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BC1NEZC(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BC1NEZC %s, %s", ft, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BC2EQZC(uint64 instruction) -{ - uint64 ct_value = extract_ct_25_24_23_22_21(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string ct = CPR(copy(ct_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BC2EQZC %s, %s", ct, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BC2NEZC(uint64 instruction) -{ - uint64 ct_value = extract_ct_25_24_23_22_21(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string ct = CPR(copy(ct_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BC2NEZC %s, %s", ct, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BEQC_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_3_2_1_0__s1(instruction); - - std::string rs3 = GPR(encode_rs3_and_check_rs3_lt_rt3(rs3_value)); - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = ADDRESS(encode_u_from_address(u_value), 2); - - return img::format("BEQC %s, %s, %s", rs3, rt3, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BEQC_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BEQC %s, %s, %s", rs, rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BEQIC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BEQIC %s, %s, %s", rt, u, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BEQZC_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - int64 s_value = extract_s__se7_0_6_5_4_3_2_1_s1(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 2); - - return img::format("BEQZC %s, %s", rt3, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BGEC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BGEC %s, %s, %s", rs, rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BGEIC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BGEIC %s, %s, %s", rt, u, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BGEIUC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BGEIUC %s, %s, %s", rt, u, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BGEUC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BGEUC %s, %s, %s", rs, rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BLTC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BLTC %s, %s, %s", rs, rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BLTIC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BLTIC %s, %s, %s", rt, u, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BLTIUC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BLTIUC %s, %s, %s", rt, u, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BLTUC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BLTUC %s, %s, %s", rs, rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BNEC_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_3_2_1_0__s1(instruction); - - std::string rs3 = GPR(encode_rs3_and_check_rs3_ge_rt3(rs3_value)); - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = ADDRESS(encode_u_from_address(u_value), 2); - - return img::format("BNEC %s, %s, %s", rs3, rt3, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BNEC_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BNEC %s, %s, %s", rs, rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BNEIC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction); - int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BNEIC %s, %s, %s", rt, u, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BNEZC_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - int64 s_value = extract_s__se7_0_6_5_4_3_2_1_s1(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 2); - - return img::format("BNEZC %s, %s", rt3, s); -} - - -/* - * [DSP] BPOSGE32C offset - Branch on greater than or equal to value 32 in - * DSPControl Pos field - * - * 3 2 1 - * 10987654321098765432109876543210 - * 100010xxxxx0010001 - * s[13:1] ------------- - * s[14] - - */ -std::string NMD::BPOSGE32C(uint64 instruction) -{ - int64 s_value = extract_s__se14_0_13_to_1_s1(instruction); - - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("BPOSGE32C %s", s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BREAK_16_(uint64 instruction) -{ - uint64 code_value = extract_code_2_1_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("BREAK %s", code); -} - - -/* - * BREAK code - Break. Cause a Breakpoint exception - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BREAK_32_(uint64 instruction) -{ - uint64 code_value = extract_code_18_to_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("BREAK %s", code); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::BRSC(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - - return img::format("BRSC %s", rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CACHE(uint64 instruction) -{ - uint64 op_value = extract_op_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string op = IMMEDIATE(copy(op_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("CACHE %s, %s(%s)", op, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CACHEE(uint64 instruction) -{ - uint64 op_value = extract_op_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string op = IMMEDIATE(copy(op_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("CACHEE %s, %s(%s)", op, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CEIL_L_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CEIL.L.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CEIL_L_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CEIL.L.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CEIL_W_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CEIL.W.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CEIL_W_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CEIL.W.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CFC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("CFC1 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CFC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("CFC2 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CLASS_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CLASS.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CLASS_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CLASS.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CLO(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("CLO %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CLZ(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("CLZ %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_AF_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.AF.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_AF_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.AF.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_EQ_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.EQ.D %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] CMP.EQ.PH rs, rt - Compare vectors of signed integer halfword values - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxxx0000000101 - * rt ----- - * rs ----- - */ -std::string NMD::CMP_EQ_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMP.EQ.PH %s, %s", rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_EQ_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.EQ.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_LE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.LE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] CMP.LE.PH rs, rt - Compare vectors of signed integer halfword values - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxxx0010000101 - * rt ----- - * rs ----- - */ -std::string NMD::CMP_LE_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMP.LE.PH %s, %s", rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_LE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.LE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_LT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.LT.D %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] CMP.LT.PH rs, rt - Compare vectors of signed integer halfword values - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxxx0001000101 - * rt ----- - * rs ----- - */ -std::string NMD::CMP_LT_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMP.LT.PH %s, %s", rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_LT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.LT.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_NE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.NE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_NE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.NE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_OR_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.OR.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_OR_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.OR.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SAF_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SAF.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SAF_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SAF.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SEQ_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SEQ.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SEQ_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SEQ.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SLE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SLE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SLE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SLE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SLT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SLT.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SLT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SLT.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SNE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SNE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SNE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SNE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SOR_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SOR.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SOR_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SOR.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SUEQ_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SUEQ.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SUEQ_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SUEQ.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SULE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SULE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SULE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SULE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SULT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SULT.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SULT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SULT.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SUN_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SUN.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SUNE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SUNE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SUNE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SUNE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_SUN_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.SUN.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_UEQ_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.UEQ.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_UEQ_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.UEQ.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_ULE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.ULE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_ULE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.ULE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_ULT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.ULT.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_ULT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.ULT.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_UN_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.UN.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_UNE_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.UNE.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_UNE_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.UNE.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMP_UN_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("CMP.UN.S %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] CMPGDU.EQ.QB rd, rs, rt - Compare unsigned vector of - * four bytes and write result to GPR and DSPControl - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMPGDU_EQ_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPGDU.EQ.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] CMPGDU.LE.QB rd, rs, rt - Compare unsigned vector of - * four bytes and write result to GPR and DSPControl - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1000000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMPGDU_LE_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPGDU.LE.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] CMPGDU.EQ.QB rd, rs, rt - Compare unsigned vector of - * four bytes and write result to GPR and DSPControl - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0111000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMPGDU_LT_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPGDU.LT.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] CMPGU.EQ.QB rd, rs, rt - Compare vectors of unsigned - * byte values and write result to a GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0011000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMPGU_EQ_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPGU.EQ.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] CMPGU.LE.QB rd, rs, rt - Compare vectors of unsigned - * byte values and write result to a GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0101000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMPGU_LE_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPGU.LE.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] CMPGU.LT.QB rd, rs, rt - Compare vectors of unsigned - * byte values and write result to a GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0100000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CMPGU_LT_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPGU.LT.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] CMPU.EQ.QB rd, rs, rt - Compare vectors of unsigned - * byte values - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxxx1001000101 - * rt ----- - * rs ----- - */ -std::string NMD::CMPU_EQ_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPU.EQ.QB %s, %s", rs, rt); -} - - -/* - * [DSP] CMPU.LE.QB rd, rs, rt - Compare vectors of unsigned - * byte values - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxxx1011000101 - * rt ----- - * rs ----- - */ -std::string NMD::CMPU_LE_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPU.LE.QB %s, %s", rs, rt); -} - - -/* - * [DSP] CMPU.LT.QB rd, rs, rt - Compare vectors of unsigned - * byte values - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxxx1010000101 - * rt ----- - * rs ----- - */ -std::string NMD::CMPU_LT_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("CMPU.LT.QB %s, %s", rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::COP2_1(uint64 instruction) -{ - uint64 cofun_value = extract_cofun_25_24_23(instruction); - - std::string cofun = IMMEDIATE(copy(cofun_value)); - - return img::format("COP2_1 %s", cofun); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CTC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("CTC1 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CTC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("CTC2 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_D_L(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.D.L %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_D_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.D.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_D_W(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.D.W %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_L_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.L.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_L_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.L.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_S_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.S.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_S_L(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.S.L %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_S_PL(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.S.PL %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_S_PU(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.S.PU %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_S_W(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.S.W %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_W_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.W.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::CVT_W_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("CVT.W.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DADDIU_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("DADDIU %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DADDIU_NEG_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(neg_copy(u_value)); - - return img::format("DADDIU %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DADDIU_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("DADDIU %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DADD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DADD %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DADDU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DADDU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DCLO(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("DCLO %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DCLZ(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("DCLZ %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DDIV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DDIV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DDIVU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DDIVU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DERET(uint64 instruction) -{ - (void)instruction; - - return "DERET "; -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DEXTM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string lsb = IMMEDIATE(copy(lsb_value)); - std::string msbd = IMMEDIATE(encode_msbd_from_size(msbd_value)); - - return img::format("DEXTM %s, %s, %s, %s", rt, rs, lsb, msbd); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DEXT(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string lsb = IMMEDIATE(copy(lsb_value)); - std::string msbd = IMMEDIATE(encode_msbd_from_size(msbd_value)); - - return img::format("DEXT %s, %s, %s, %s", rt, rs, lsb, msbd); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DEXTU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string lsb = IMMEDIATE(copy(lsb_value)); - std::string msbd = IMMEDIATE(encode_msbd_from_size(msbd_value)); - - return img::format("DEXTU %s, %s, %s, %s", rt, rs, lsb, msbd); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DINSM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string pos = IMMEDIATE(encode_lsb_from_pos_and_size(lsb_value)); - std::string size = IMMEDIATE(encode_lsb_from_pos_and_size(msbd_value)); - /* !!!!!!!!!! - no conversion function */ - - return img::format("DINSM %s, %s, %s, %s", rt, rs, pos, size); - /* hand edited */ -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DINS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string pos = IMMEDIATE(encode_lsb_from_pos_and_size(lsb_value)); - std::string size = IMMEDIATE(encode_lsb_from_pos_and_size(msbd_value)); - /* !!!!!!!!!! - no conversion function */ - - return img::format("DINS %s, %s, %s, %s", rt, rs, pos, size); - /* hand edited */ -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DINSU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string pos = IMMEDIATE(encode_lsb_from_pos_and_size(lsb_value)); - std::string size = IMMEDIATE(encode_lsb_from_pos_and_size(msbd_value)); - /* !!!!!!!!!! - no conversion function */ - - return img::format("DINSU %s, %s, %s, %s", rt, rs, pos, size); - /* hand edited */ -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("DI %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DIV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DIV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DIV_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("DIV.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DIV_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("DIV.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DIVU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DIVU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DLSA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - uint64 u2_value = extract_u2_10_9(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string u2 = IMMEDIATE(copy(u2_value)); - - return img::format("DLSA %s, %s, %s, %s", rd, rs, rt, u2); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DLUI_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - uint64 u_value = extract_u_31_to_0__s32(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("DLUI %s, %s", rt, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMFC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("DMFC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMFC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("DMFC1 %s, %s", rt, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMFC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("DMFC2 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMFGC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("DMFGC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMOD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DMOD %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMODU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DMODU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMTC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("DMTC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMTC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("DMTC1 %s, %s", rt, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMTC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("DMTC2 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMTGC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("DMTGC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMT(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("DMT %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMUH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DMUH %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMUHU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DMUHU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMUL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DMUL %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DMULU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DMULU %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] DPA.W.PH ac, rs, rt - Dot product with accumulate on - * vector integer halfword elements - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00000010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::DPA_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPA.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAQ_SA_L_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAQ_SA.L.W %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAQ_S_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAQ_S.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAQX_SA_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAQX_SA.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAQX_S_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAQX_S.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAU_H_QBL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAU.H.QBL %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAU_H_QBR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAU.H.QBR %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPAX_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPAX.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPS_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPS.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSQ_SA_L_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSQ_SA.L.W %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSQ_S_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSQ_S.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSQX_SA_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSQX_SA.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSQX_S_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSQX_S.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSU_H_QBL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSU.H.QBL %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSU_H_QBR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSU.H.QBR %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DPSX_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DPSX.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * DROTR - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DROTR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DROTR %s, %s, %s", rt, rs, shift); -} - - -/* - * DROTR[32] - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0110 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DROTR32(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DROTR32 %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DROTRV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DROTRV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DROTX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shiftx_value = extract_shiftx_11_10_9_8_7_6(instruction); - uint64 shift_value = extract_shift_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - std::string shiftx = IMMEDIATE(copy(shiftx_value)); - - return img::format("DROTX %s, %s, %s, %s", rt, rs, shift, shiftx); -} - - -/* - * DSLL - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0000 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DSLL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DSLL %s, %s, %s", rt, rs, shift); -} - - -/* - * DSLL[32] - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0000 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DSLL32(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DSLL32 %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DSLLV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DSLLV %s, %s, %s", rd, rs, rt); -} - - -/* - * DSRA - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0100 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DSRA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DSRA %s, %s, %s", rt, rs, shift); -} - - -/* - * DSRA[32] - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0100 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DSRA32(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DSRA32 %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DSRAV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DSRAV %s, %s, %s", rd, rs, rt); -} - - -/* - * DSRL - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0100 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DSRL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DSRL %s, %s, %s", rt, rs, shift); -} - - -/* - * DSRL[32] - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 10o000 1100xxx0010 - * rt ----- - * rs ----- - * shift ----- - */ -std::string NMD::DSRL32(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("DSRL32 %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DSRLV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DSRLV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DSUB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DSUB %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DSUBU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("DSUBU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DVPE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("DVPE %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::DVP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("DVP %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EHB(uint64 instruction) -{ - (void)instruction; - - return "EHB "; -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("EI %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EMT(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("EMT %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ERET(uint64 instruction) -{ - (void)instruction; - - return "ERET "; -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ERETNC(uint64 instruction) -{ - (void)instruction; - - return "ERETNC "; -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EVP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("EVP %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EVPE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("EVPE %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXT(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string lsb = IMMEDIATE(copy(lsb_value)); - std::string msbd = IMMEDIATE(encode_msbd_from_size(msbd_value)); - - return img::format("EXT %s, %s, %s, %s", rt, rs, lsb, msbd); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXTD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - uint64 shift_value = extract_shift_10_9_8_7_6(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTD %s, %s, %s, %s", rd, rs, rt, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXTD32(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - uint64 shift_value = extract_shift_10_9_8_7_6(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTD32 %s, %s, %s, %s", rd, rs, rt, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXTPDP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 size_value = extract_size_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string size = IMMEDIATE(copy(size_value)); - - return img::format("EXTPDP %s, %s, %s", rt, ac, size); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXTPDPV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("EXTPDPV %s, %s, %s", rt, ac, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXTP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 size_value = extract_size_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string size = IMMEDIATE(copy(size_value)); - - return img::format("EXTP %s, %s, %s", rt, ac, size); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::EXTPV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("EXTPV %s, %s, %s", rt, ac, rs); -} - - -/* - * [DSP] EXTR_RS.W rt, ac, shift - Extract word value from accumulator to GPR - * with right shift - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10111001111111 - * rt ----- - * shift ----- - * ac -- - */ -std::string NMD::EXTR_RS_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTR_RS.W %s, %s, %s", rt, ac, shift); -} - - -/* - * [DSP] EXTR_R.W rt, ac, shift - Extract word value from accumulator to GPR - * with right shift - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01111001111111 - * rt ----- - * shift ----- - * ac -- - */ -std::string NMD::EXTR_R_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTR_R.W %s, %s, %s", rt, ac, shift); -} - - -/* - * [DSP] EXTR_S.H rt, ac, shift - Extract halfword value from accumulator - * to GPR with right shift and saturate - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11111001111111 - * rt ----- - * shift ----- - * ac -- - */ -std::string NMD::EXTR_S_H(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTR_S.H %s, %s, %s", rt, ac, shift); -} - - -/* - * [DSP] EXTR.W rt, ac, shift - Extract word value from accumulator to GPR - * with right shift - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00111001111111 - * rt ----- - * shift ----- - * ac -- - */ -std::string NMD::EXTR_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTR.W %s, %s, %s", rt, ac, shift); -} - - -/* - * [DSP] EXTRV_RS.W rt, ac, rs - Extract word value with variable - * right shift from accumulator to GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10111010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::EXTRV_RS_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("EXTRV_RS.W %s, %s, %s", rt, ac, rs); -} - - -/* - * [DSP] EXTRV_R.W rt, ac, rs - Extract word value with variable - * right shift from accumulator to GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01111010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::EXTRV_R_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("EXTRV_R.W %s, %s, %s", rt, ac, rs); -} - - -/* - * [DSP] EXTRV_S.H rt, ac, rs - Extract halfword value variable from - * accumulator to GPR with right shift and saturate - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11111010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::EXTRV_S_H(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("EXTRV_S.H %s, %s, %s", rt, ac, rs); -} - - -/* - * [DSP] EXTRV.W rt, ac, rs - Extract word value with variable - * right shift from accumulator to GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00111010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::EXTRV_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("EXTRV.W %s, %s, %s", rt, ac, rs); -} - - -/* - * EXTW - Extract Word - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 011111 - * rt ----- - * rs ----- - * rd ----- - * shift ----- - */ -std::string NMD::EXTW(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - uint64 shift_value = extract_shift_10_9_8_7_6(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("EXTW %s, %s, %s, %s", rd, rs, rt, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::FLOOR_L_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("FLOOR.L.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::FLOOR_L_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("FLOOR.L.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::FLOOR_W_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("FLOOR.W.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::FLOOR_W_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("FLOOR.W.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::FORK(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("FORK %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::HYPCALL(uint64 instruction) -{ - uint64 code_value = extract_code_17_to_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("HYPCALL %s", code); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::HYPCALL_16_(uint64 instruction) -{ - uint64 code_value = extract_code_1_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("HYPCALL %s", code); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::INS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction); - uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string pos = IMMEDIATE(encode_lsb_from_pos_and_size(lsb_value)); - std::string size = IMMEDIATE(encode_lsb_from_pos_and_size(msbd_value)); - /* !!!!!!!!!! - no conversion function */ - - return img::format("INS %s, %s, %s, %s", rt, rs, pos, size); - /* hand edited */ -} - - -/* - * [DSP] INSV rt, rs - Insert bit field variable - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0100000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::INSV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("INSV %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::IRET(uint64 instruction) -{ - (void)instruction; - - return "IRET "; -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::JALRC_16_(uint64 instruction) -{ - uint64 rt_value = extract_rt_9_8_7_6_5(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("JALRC $%d, %s", 31, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::JALRC_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("JALRC %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::JALRC_HB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("JALRC.HB %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::JRC(uint64 instruction) -{ - uint64 rt_value = extract_rt_9_8_7_6_5(instruction); - - std::string rt = GPR(copy(rt_value)); - - return img::format("JRC %s", rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LB_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_1_0(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("LB %s, %s(%s)", rt3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LB_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LB %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LB_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LB %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LB_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LB %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LBE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBU_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_1_0(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("LBU %s, %s(%s)", rt3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBU_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LBU %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBU_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LBU %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBU_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LBU %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBUE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LBUE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBUX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LBUX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LBX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LBX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LD_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_20_to_3__s3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LD %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LD_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LD %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LD_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LD %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDC1_GP_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_2__s2(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LDC1 %s, %s($%d)", ft, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDC1_S9_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LDC1 %s, %s(%s)", ft, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDC1_U12_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LDC1 %s, %s(%s)", ft, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDC1XS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LDC1XS %s, %s(%s)", ft, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDC1X(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LDC1X %s, %s(%s)", ft, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDC2(uint64 instruction) -{ - uint64 ct_value = extract_ct_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string ct = CPR(copy(ct_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LDC2 %s, %s(%s)", ct, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("LDM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDPC_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 6); - - return img::format("LDPC %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LDX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LDXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LDXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LH_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_2_1__s1(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("LH %s, %s(%s)", rt3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LH_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_1__s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LH %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LH_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LH %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LH_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LH %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LHE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHU_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_2_1__s1(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("LHU %s, %s(%s)", rt3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHU_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_1__s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LHU %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHU_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LHU %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHU_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LHU %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHUE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LHUE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHUX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LHUX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHUXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LHUXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LHXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LHX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LHX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LI_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 eu_value = extract_eu_6_5_4_3_2_1_0(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string eu = IMMEDIATE(encode_eu_from_s_li16(eu_value)); - - return img::format("LI %s, %s", rt3, eu); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LI_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("LI %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LL %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LLD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_s3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LLD %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LLDP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ru_value = extract_ru_7_6_5_4_3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ru = GPR(copy(ru_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LLDP %s, %s, (%s)", rt, ru, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LLE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LLE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LLWP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ru_value = extract_ru_7_6_5_4_3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ru = GPR(copy(ru_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LLWP %s, %s, (%s)", rt, ru, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LLWPE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ru_value = extract_ru_7_6_5_4_3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ru = GPR(copy(ru_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LLWPE %s, %s, (%s)", rt, ru, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LSA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - uint64 u2_value = extract_u2_10_9(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - std::string u2 = IMMEDIATE(copy(u2_value)); - - return img::format("LSA %s, %s, %s, %s", rd, rs, rt, u2); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LUI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - int64 s_value = extract_s__se31_0_11_to_2_20_to_12_s12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("LUI %s, %%hi(%s)", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_3_2_1_0__s2(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("LW %s, %s(%s)", rt3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_4X4_(uint64 instruction) -{ - uint64 rt4_value = extract_rt4_9_7_6_5(instruction); - uint64 rs4_value = extract_rs4_4_2_1_0(instruction); - uint64 u_value = extract_u_3_8__s2(instruction); - - std::string rt4 = GPR(decode_gpr_gpr4(rt4_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs4 = GPR(decode_gpr_gpr4(rs4_value)); - - return img::format("LW %s, %s(%s)", rt4, u, rs4); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_20_to_2__s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LW %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_GP16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 u_value = extract_u_6_5_4_3_2_1_0__s2(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LW %s, %s($%d)", rt3, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LW %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_SP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_9_8_7_6_5(instruction); - uint64 u_value = extract_u_4_3_2_1_0__s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LW %s, %s($%d)", rt, u, 29); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LW_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LW %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWC1_GP_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_2__s2(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LWC1 %s, %s($%d)", ft, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWC1_S9_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LWC1 %s, %s(%s)", ft, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWC1_U12_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LWC1 %s, %s(%s)", ft, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWC1X(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LWC1X %s, %s(%s)", ft, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWC1XS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LWC1XS %s, %s(%s)", ft, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWC2(uint64 instruction) -{ - uint64 ct_value = extract_ct_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string ct = CPR(copy(ct_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LWC2 %s, %s(%s)", ct, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LWE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("LWM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWPC_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 6); - - return img::format("LWPC %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWU_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_2__s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("LWU %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWU_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LWU %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWU_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("LWU %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWUX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LWUX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWUXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LWUXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LWX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWXS_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 rd3_value = extract_rd3_3_2_1(instruction); - - std::string rd3 = GPR(decode_gpr_gpr3(rd3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string rt3 = IMMEDIATE(decode_gpr_gpr3(rt3_value)); - - return img::format("LWXS %s, %s(%s)", rd3, rs3, rt3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::LWXS_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("LWXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * [DSP] MADD ac, rs, rt - Multiply two words and add to the specified - * accumulator - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MADD_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MADD %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MADDF_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MADDF.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MADDF_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MADDF.S %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] MADDU ac, rs, rt - Multiply two unsigned words and add to the - * specified accumulator - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MADDU_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MADDU %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MAQ_S.W.PHL ac, rs, rt - Multiply the left-most single vector - * fractional halfword elements with accumulation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAQ_S_W_PHL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MAQ_S.W.PHL %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MAQ_S.W.PHR ac, rs, rt - Multiply the right-most single vector - * fractional halfword elements with accumulation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAQ_S_W_PHR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MAQ_S.W.PHR %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MAQ_SA.W.PHL ac, rs, rt - Multiply the left-most single vector - * fractional halfword elements with saturating accumulation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAQ_SA_W_PHL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MAQ_SA.W.PHL %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MAQ_SA.W.PHR ac, rs, rt - Multiply the right-most single vector - * fractional halfword elements with saturating accumulation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAQ_SA_W_PHR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MAQ_SA.W.PHR %s, %s, %s", ac, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAX_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MAX.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAX_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MAX.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAXA_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MAXA.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MAXA_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MAXA.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MFC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("MFC1 %s, %s", rt, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("MFC2 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFGC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MFGC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFHC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MFHC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFHC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("MFHC1 %s, %s", rt, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFHC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("MFHC2 %s, %s", rt, cs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFHGC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MFHGC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * [DSP] MFHI rs, ac - Move from HI register - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxx 00000001111111 - * rt ----- - * ac -- - */ -std::string NMD::MFHI_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("MFHI %s, %s", rt, ac); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFHTR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - uint64 u_value = extract_u_10(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = IMMEDIATE(copy(c0s_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MFHTR %s, %s, %s, %s", rt, c0s, u, sel); -} - - -/* - * [DSP] MFLO rs, ac - Move from HI register - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 xxxxx 01000001111111 - * rt ----- - * ac -- - */ -std::string NMD::MFLO_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("MFLO %s, %s", rt, ac); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MFTR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - uint64 u_value = extract_u_10(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = IMMEDIATE(copy(c0s_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MFTR %s, %s, %s, %s", rt, c0s, u, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MIN_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MIN.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MIN_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MIN.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MINA_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MINA.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MINA_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MINA.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MOD %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MODSUB rd, rs, rt - Modular subtraction on an index value - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MODSUB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MODSUB %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1010010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MODU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MODU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOV_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("MOV.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOV_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("MOV.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOVE_BALC(uint64 instruction) -{ - uint64 rtz4_value = extract_rtz4_27_26_25_23_22_21(instruction); - uint64 rd1_value = extract_rdl_25_24(instruction); - int64 s_value = extract_s__se21_0_20_to_1_s1(instruction); - - std::string rd1 = GPR(decode_gpr_gpr1(rd1_value)); - std::string rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 4); - - return img::format("MOVE.BALC %s, %s, %s", rd1, rtz4, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOVEP(uint64 instruction) -{ - uint64 rtz4_value = extract_rtz4_9_7_6_5(instruction); - uint64 rd2_value = extract_rd2_3_8(instruction); - uint64 rsz4_value = extract_rsz4_4_2_1_0(instruction); - - std::string rd2 = GPR(decode_gpr_gpr2_reg1(rd2_value)); - std::string re2 = GPR(decode_gpr_gpr2_reg2(rd2_value)); - /* !!!!!!!!!! - no conversion function */ - std::string rsz4 = GPR(decode_gpr_gpr4_zero(rsz4_value)); - std::string rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value)); - - return img::format("MOVEP %s, %s, %s, %s", rd2, re2, rsz4, rtz4); - /* hand edited */ -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOVEP_REV_(uint64 instruction) -{ - uint64 rt4_value = extract_rt4_9_7_6_5(instruction); - uint64 rd2_value = extract_rd2_3_8(instruction); - uint64 rs4_value = extract_rs4_4_2_1_0(instruction); - - std::string rs4 = GPR(decode_gpr_gpr4(rs4_value)); - std::string rt4 = GPR(decode_gpr_gpr4(rt4_value)); - std::string rd2 = GPR(decode_gpr_gpr2_reg1(rd2_value)); - std::string rs2 = GPR(decode_gpr_gpr2_reg2(rd2_value)); - /* !!!!!!!!!! - no conversion function */ - - return img::format("MOVEP %s, %s, %s, %s", rs4, rt4, rd2, rs2); - /* hand edited */ -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOVE(uint64 instruction) -{ - uint64 rt_value = extract_rt_9_8_7_6_5(instruction); - uint64 rs_value = extract_rs_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("MOVE %s, %s", rt, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOVN(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MOVN %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MOVZ(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MOVZ %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MSUB ac, rs, rt - Multiply word and subtract from accumulator - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10101010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::MSUB_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MSUB %s, %s, %s", ac, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MSUBF_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MSUBF.D %s, %s, %s", fd, fs, ft); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MSUBF_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MSUBF.S %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] MSUBU ac, rs, rt - Multiply word and add to accumulator - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11101010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::MSUBU_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MSUBU %s, %s, %s", ac, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MTC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("MTC1 %s, %s", rt, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("MTC2 %s, %s", rt, cs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTGC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MTGC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTHC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MTHC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTHC1(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("MTHC1 %s, %s", rt, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTHC2(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 cs_value = extract_cs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string cs = CPR(copy(cs_value)); - - return img::format("MTHC2 %s, %s", rt, cs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTHGC0(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = CPR(copy(c0s_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MTHGC0 %s, %s, %s", rt, c0s, sel); -} - - -/* - * [DSP] MTHI rs, ac - Move to HI register - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000xxxxx 10000001111111 - * rs ----- - * ac -- - */ -std::string NMD::MTHI_DSP_(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("MTHI %s, %s", rs, ac); -} - - -/* - * [DSP] MTHLIP rs, ac - Copy LO to HI and a GPR to LO and increment pos by 32 - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000xxxxx 00001001111111 - * rs ----- - * ac -- - */ -std::string NMD::MTHLIP(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("MTHLIP %s, %s", rs, ac); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTHTR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - uint64 u_value = extract_u_10(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = IMMEDIATE(copy(c0s_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MTHTR %s, %s, %s, %s", rt, c0s, u, sel); -} - - -/* - * [DSP] MTLO rs, ac - Move to LO register - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000xxxxx 11000001111111 - * rs ----- - * ac -- - */ -std::string NMD::MTLO_DSP_(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("MTLO %s, %s", rs, ac); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MTTR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 c0s_value = extract_c0s_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_15_14_13_12_11(instruction); - uint64 u_value = extract_u_10(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string c0s = IMMEDIATE(copy(c0s_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("MTTR %s, %s, %s, %s", rt, c0s, u, sel); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MUH %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUHU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MUHU %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUL_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MUL %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUL_4X4_(uint64 instruction) -{ - uint64 rt4_value = extract_rt4_9_7_6_5(instruction); - uint64 rs4_value = extract_rs4_4_2_1_0(instruction); - - std::string rs4 = GPR(decode_gpr_gpr4(rs4_value)); - std::string rt4 = GPR(decode_gpr_gpr4(rt4_value)); - - return img::format("MUL %s, %s", rs4, rt4); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUL_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MUL.D %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] MUL.PH rd, rs, rt - Multiply vector integer half words to same size - * products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00000101101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUL_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MUL.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MUL_S.PH rd, rs, rt - Multiply vector integer half words to same size - * products (saturated) - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10000101101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUL_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MUL_S.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MUL_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("MUL.S %s, %s, %s", fd, fs, ft); -} - - -/* - * [DSP] MULEQ_S.W.PHL rd, rs, rt - Multiply vector fractional left halfwords - * to expanded width products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0000100101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULEQ_S_W_PHL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULEQ_S.W.PHL %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULEQ_S.W.PHR rd, rs, rt - Multiply vector fractional right halfwords - * to expanded width products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0001100101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULEQ_S_W_PHR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULEQ_S.W.PHR %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULEU_S.PH.QBL rd, rs, rt - Multiply vector fractional left bytes - * by halfwords to halfword products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0010010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULEU_S_PH_QBL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULEU_S.PH.QBL %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULEU_S.PH.QBR rd, rs, rt - Multiply vector fractional right bytes - * by halfwords to halfword products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0011010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULEU_S_PH_QBR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULEU_S.PH.QBR %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULQ_RS.PH rd, rs, rt - Multiply vector fractional halfwords - * to fractional halfword products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0100010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULQ_RS_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULQ_RS.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULQ_RS.W rd, rs, rt - Multiply fractional words to same size - * product with saturation and rounding - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0110010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULQ_RS_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULQ_RS.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULQ_S.PH rd, rs, rt - Multiply fractional halfwords to same size - * products - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0101010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULQ_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULQ_S.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULQ_S.W rd, rs, rt - Multiply fractional words to same size product - * with saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0111010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULQ_S_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULQ_S.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] MULSA.W.PH ac, rs, rt - Multiply and subtract vector integer halfword - * elements and accumulate - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 10110010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::MULSA_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULSA.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MULSAQ_S.W.PH ac, rs, rt - Multiply and subtract vector fractional - * halfwords and accumulate - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11110010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::MULSAQ_S_W_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULSAQ_S.W.PH %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MULT ac, rs, rt - Multiply word - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00110010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::MULT_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULT %s, %s, %s", ac, rs, rt); -} - - -/* - * [DSP] MULTU ac, rs, rt - Multiply unsigned word - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01110010111111 - * rt ----- - * rs ----- - * ac -- - */ -std::string NMD::MULTU_DSP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string ac = AC(copy(ac_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULTU %s, %s, %s", ac, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::MULU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("MULU %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::NEG_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("NEG.D %s, %s", ft, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::NEG_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("NEG.S %s, %s", ft, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::NOP_16_(uint64 instruction) -{ - (void)instruction; - - return "NOP "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::NOP_32_(uint64 instruction) -{ - (void)instruction; - - return "NOP "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::NOR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("NOR %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::NOT_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("NOT %s, %s", rt3, rs3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::OR_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - - return img::format("OR %s, %s", rs3, rt3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::OR_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("OR %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ORI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("ORI %s, %s, %s", rt, rs, u); -} - - -/* - * [DSP] PACKRL.PH rd, rs, rt - Pack a word using the right halfword from one - * source register and left halfword from another source register - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PACKRL_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PACKRL.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PAUSE(uint64 instruction) -{ - (void)instruction; - - return "PAUSE "; -} - - -/* - * [DSP] PICK.PH rd, rs, rt - Pick a vector of halfwords based on condition - * code bits - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PICK_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PICK.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] PICK.QB rd, rs, rt - Pick a vector of byte values based on condition - * code bits - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PICK_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PICK.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] PRECEQ.W.PHL rt, rs - Expand the precision of the left-most element - * of a paired halfword - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEQ_W_PHL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEQ.W.PHL %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEQ.W.PHR rt, rs - Expand the precision of the right-most element - * of a paired halfword - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEQ_W_PHR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEQ.W.PHR %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEQU.PH.QBLA rt, rs - Expand the precision of the two - * left-alternate elements of a quad byte vector - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEQU_PH_QBLA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEQU.PH.QBLA %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEQU.PH.QBL rt, rs - Expand the precision of the two left-most - * elements of a quad byte vector - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEQU_PH_QBL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEQU.PH.QBL %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEQU.PH.QBRA rt, rs - Expand the precision of the two - * right-alternate elements of a quad byte vector - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEQU_PH_QBRA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEQU.PH.QBRA %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEQU.PH.QBR rt, rs - Expand the precision of the two right-most - * elements of a quad byte vector - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEQU_PH_QBR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEQU.PH.QBR %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEU.PH.QBLA rt, rs - Expand the precision of the two - * left-alternate elements of a quad byte vector to four unsigned - * halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEU_PH_QBLA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEU.PH.QBLA %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEU.PH.QBL rt, rs - Expand the precision of the two left-most - * elements of a quad byte vector to form unsigned halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEU_PH_QBL(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEU.PH.QBL %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEU.PH.QBRA rt, rs - Expand the precision of the two - * right-alternate elements of a quad byte vector to form four - * unsigned halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEU_PH_QBRA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEU.PH.QBRA %s, %s", rt, rs); -} - - -/* - * [DSP] PRECEU.PH.QBR rt, rs - Expand the precision of the two right-most - * elements of a quad byte vector to form unsigned halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECEU_PH_QBR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PRECEU.PH.QBR %s, %s", rt, rs); -} - - -/* - * [DSP] PRECR.QB.PH rd, rs, rt - Reduce the precision of four integer - * halfwords to four bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0001101101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECR_QB_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PRECR.QB.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] PRECR_SRA.PH.W rt, rs, sa - Reduce the precision of two integer - * words to halfwords after a right shift - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECR_SRA_PH_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("PRECR_SRA.PH.W %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] PRECR_SRA_R.PH.W rt, rs, sa - Reduce the precision of two integer - * words to halfwords after a right shift with rounding - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECR_SRA_R_PH_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("PRECR_SRA_R.PH.W %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] PRECRQ.PH.W rd, rs, rt - Reduce the precision of fractional - * words to fractional halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECRQ_PH_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PRECRQ.PH.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] PRECRQ.QB.PH rd, rs, rt - Reduce the precision of four fractional - * halfwords to four bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0010101101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECRQ_QB_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PRECRQ.QB.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] PRECRQ_RS.PH.W rd, rs, rt - Reduce the precision of fractional - * words to halfwords with rounding and saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECRQ_RS_PH_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PRECRQ_RS.PH.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] PRECRQU_S.QB.PH rd, rs, rt - Reduce the precision of fractional - * halfwords to unsigned bytes with saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PRECRQU_S_QB_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("PRECRQU_S.QB.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PREF_S9_(uint64 instruction) -{ - uint64 hint_value = extract_hint_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string hint = IMMEDIATE(copy(hint_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PREF %s, %s(%s)", hint, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PREF_U12_(uint64 instruction) -{ - uint64 hint_value = extract_hint_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string hint = IMMEDIATE(copy(hint_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PREF %s, %s(%s)", hint, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PREFE(uint64 instruction) -{ - uint64 hint_value = extract_hint_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string hint = IMMEDIATE(copy(hint_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("PREFE %s, %s(%s)", hint, s, rs); -} - - -/* - * [DSP] PREPEND rt, rs, sa - Right shift and prepend bits to the MSB - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::PREPEND(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("PREPEND %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] RADDU.W.QB rt, rs - Unsigned reduction add of vector quad bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 1111000100111111 - * rt ----- - * rs ----- - */ -std::string NMD::RADDU_W_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("RADDU.W.QB %s, %s", rt, rs); -} - - -/* - * [DSP] RDDSP rt, mask - Read DSPControl register fields to a GPR - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00011001111111 - * rt ----- - * mask ------- - */ -std::string NMD::RDDSP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 mask_value = extract_mask_20_19_18_17_16_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string mask = IMMEDIATE(copy(mask_value)); - - return img::format("RDDSP %s, %s", rt, mask); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RDHWR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 hs_value = extract_hs_20_19_18_17_16(instruction); - uint64 sel_value = extract_sel_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string hs = CPR(copy(hs_value)); - std::string sel = IMMEDIATE(copy(sel_value)); - - return img::format("RDHWR %s, %s, %s", rt, hs, sel); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RDPGPR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("RDPGPR %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RECIP_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("RECIP.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RECIP_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("RECIP.S %s, %s", ft, fs); -} - - -/* - * [DSP] REPL.PH rd, s - Replicate immediate integer into all vector element - * positions - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x0000111101 - * rt ----- - * s ---------- - */ -std::string NMD::REPL_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - int64 s_value = extract_s__se9_20_19_18_17_16_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - - return img::format("REPL.PH %s, %s", rt, s); -} - - -/* - * [DSP] REPL.QB rd, u - Replicate immediate integer into all vector element - * positions - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x010111111111 - * rt ----- - * u -------- - */ -std::string NMD::REPL_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_20_19_18_17_16_15_14_13(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("REPL.QB %s, %s", rt, u); -} - - -/* - * [DSP] REPLV.PH rt, rs - Replicate a halfword into all vector element - * positions - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0000001100111111 - * rt ----- - * rs ----- - */ -std::string NMD::REPLV_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("REPLV.PH %s, %s", rt, rs); -} - - -/* - * [DSP] REPLV.QB rt, rs - Replicate byte into all vector element positions - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0001001100111111 - * rt ----- - * rs ----- - */ -std::string NMD::REPLV_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("REPLV.QB %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RESTORE_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 count_value = extract_count_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); - uint64 gp_value = extract_gp_2(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - return img::format("RESTORE %s%s", u, - save_restore_list(rt_value, count_value, gp_value)); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RESTORE_JRC_16_(uint64 instruction) -{ - uint64 rt1_value = extract_rtl_11(instruction); - uint64 u_value = extract_u_7_6_5_4__s4(instruction); - uint64 count_value = extract_count_3_2_1_0(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - return img::format("RESTORE.JRC %s%s", u, - save_restore_list(encode_rt1_from_rt(rt1_value), count_value, 0)); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RESTORE_JRC_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 count_value = extract_count_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); - uint64 gp_value = extract_gp_2(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - return img::format("RESTORE.JRC %s%s", u, - save_restore_list(rt_value, count_value, gp_value)); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RESTOREF(uint64 instruction) -{ - uint64 count_value = extract_count_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - std::string count = IMMEDIATE(copy(count_value)); - - return img::format("RESTOREF %s, %s", u, count); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RINT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("RINT.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RINT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("RINT.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROTR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("ROTR %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROTRV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("ROTRV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROTX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shiftx_value = extract_shiftx_10_9_8_7__s1(instruction); - uint64 stripe_value = extract_stripe_6(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - std::string shiftx = IMMEDIATE(copy(shiftx_value)); - std::string stripe = IMMEDIATE(copy(stripe_value)); - - return img::format("ROTX %s, %s, %s, %s, %s", - rt, rs, shift, shiftx, stripe); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROUND_L_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("ROUND.L.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROUND_L_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("ROUND.L.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROUND_W_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("ROUND.W.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::ROUND_W_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("ROUND.W.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RSQRT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("RSQRT.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110000101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::RSQRT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("RSQRT.S %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SAVE_16_(uint64 instruction) -{ - uint64 rt1_value = extract_rtl_11(instruction); - uint64 u_value = extract_u_7_6_5_4__s4(instruction); - uint64 count_value = extract_count_3_2_1_0(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - return img::format("SAVE %s%s", u, - save_restore_list(encode_rt1_from_rt(rt1_value), count_value, 0)); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SAVE_32_(uint64 instruction) -{ - uint64 count_value = extract_count_19_18_17_16(instruction); - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); - uint64 gp_value = extract_gp_2(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - return img::format("SAVE %s%s", u, - save_restore_list(rt_value, count_value, gp_value)); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SAVEF(uint64 instruction) -{ - uint64 count_value = extract_count_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction); - - std::string u = IMMEDIATE(copy(u_value)); - std::string count = IMMEDIATE(copy(count_value)); - - return img::format("SAVEF %s, %s", u, count); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SB_16_(uint64 instruction) -{ - uint64 rtz3_value = extract_rtz3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_1_0(instruction); - - std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("SB %s, %s(%s)", rtz3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SB_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SB %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SB_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SB %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SB_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SB %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SBE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SBE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SBX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SBX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SC(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SC %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SCD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_s3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SCD %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SCDP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ru_value = extract_ru_7_6_5_4_3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ru = GPR(copy(ru_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SCDP %s, %s, (%s)", rt, ru, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SCE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SCE %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SCWP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ru_value = extract_ru_7_6_5_4_3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ru = GPR(copy(ru_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SCWP %s, %s, (%s)", rt, ru, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SCWPE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ru_value = extract_ru_7_6_5_4_3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string ru = GPR(copy(ru_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SCWPE %s, %s, (%s)", rt, ru, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SD_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_20_to_3__s3(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SD %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SD_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SD %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SD_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SD %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDBBP_16_(uint64 instruction) -{ - uint64 code_value = extract_code_2_1_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("SDBBP %s", code); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDBBP_32_(uint64 instruction) -{ - uint64 code_value = extract_code_18_to_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("SDBBP %s", code); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDC1_GP_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_2__s2(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SDC1 %s, %s($%d)", ft, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDC1_S9_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SDC1 %s, %s(%s)", ft, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDC1_U12_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SDC1 %s, %s(%s)", ft, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDC1X(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SDC1X %s, %s(%s)", ft, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDC1XS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SDC1XS %s, %s(%s)", ft, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDC2(uint64 instruction) -{ - uint64 cs_value = extract_cs_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string cs = CPR(copy(cs_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SDC2 %s, %s(%s)", cs, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("SDM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDPC_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 6); - - return img::format("SDPC %s, %s", rt, s); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SDXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SDX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SDX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SEB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SEB %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SEH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SEH %s, %s", rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SEL_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SEL.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SEL_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SEL.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SELEQZ_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SELEQZ.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SELEQZ_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SELEQZ.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SELNEZ_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SELNEZ.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SELNEZ_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SELNEZ.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SEQI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SEQI %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SH_16_(uint64 instruction) -{ - uint64 rtz3_value = extract_rtz3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_2_1__s1(instruction); - - std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("SH %s, %s(%s)", rtz3, u, rs3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SH_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_1__s1(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SH %s, %s($%d)", rt, u, 28); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SH_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SH %s, %s(%s)", rt, s, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SH_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SH %s, %s(%s)", rt, u, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHE %s, %s(%s)", rt, s, rs); -} - - -/* - * [DSP] SHILO ac, shift - Shift an accumulator value leaving the result in - * the same accumulator - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000xxxx xxxx0000011101 - * shift ------ - * ac -- - */ -std::string NMD::SHILO(uint64 instruction) -{ - int64 shift_value = extract_shift__se5_21_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string shift = IMMEDIATE(copy(shift_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("SHILO %s, %s", ac, shift); -} - - -/* - * [DSP] SHILOV ac, rs - Variable shift of accumulator value leaving the result - * in the same accumulator - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000xxxxx 01001001111111 - * rs ----- - * ac -- - */ -std::string NMD::SHILOV(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_15_14(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string ac = AC(copy(ac_value)); - - return img::format("SHILOV %s, %s", ac, rs); -} - - -/* - * [DSP] SHLL.PH rt, rs, sa - Shift left logical vector pair halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 001110110101 - * rt ----- - * rs ----- - * sa ---- - */ -std::string NMD::SHLL_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHLL.PH %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] SHLL.QB rt, rs, sa - Shift left logical vector quad bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 0100001111111 - * rt ----- - * rs ----- - * sa --- - */ -std::string NMD::SHLL_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHLL.QB %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] SHLL_S.PH rt, rs, sa - Shift left logical vector pair halfwords - * with saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 001110110101 - * rt ----- - * rs ----- - * sa ---- - */ -std::string NMD::SHLL_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHLL_S.PH %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] SHLL_S.PH rt, rs, sa - Shift left logical word with saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1111110101 - * rt ----- - * rs ----- - * sa ----- - */ -std::string NMD::SHLL_S_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHLL_S.W %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] SHLLV.PH rd, rt, rs - Shift left logical variable vector pair - * halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01110001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHLLV_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHLLV.PH %s, %s, %s", rd, rt, rs); -} - - -/* - * [DSP] SHLLV_S.QB rd, rt, rs - Shift left logical variable vector quad bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1110010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHLLV_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHLLV.QB %s, %s, %s", rd, rt, rs); -} - - -/* - * [DSP] SHLLV.PH rd, rt, rs - Shift left logical variable vector pair - * halfwords with saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11110001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHLLV_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHLLV_S.PH %s, %s, %s", rd, rt, rs); -} - - -/* - * [DSP] SHLLV_S.W rd, rt, rs - Shift left logical variable vector word - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1111010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHLLV_S_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHLLV_S.W %s, %s, %s", rd, rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRA_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRA.PH %s, %s, %s", rt, rs, sa); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRA_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRA.QB %s, %s, %s", rt, rs, sa); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRA_R_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRA_R.PH %s, %s, %s", rt, rs, sa); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRA_R_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRA_R.QB %s, %s, %s", rt, rs, sa); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRA_R_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12_11(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRA_R.W %s, %s, %s", rt, rs, sa); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRAV_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRAV.PH %s, %s, %s", rd, rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRAV_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRAV.QB %s, %s, %s", rd, rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRAV_R_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRAV_R.PH %s, %s, %s", rd, rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRAV_R_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRAV_R.QB %s, %s, %s", rd, rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRAV_R_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRAV_R.W %s, %s, %s", rd, rt, rs); -} - - -/* - * [DSP] SHRL.PH rt, rs, sa - Shift right logical two halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 001111111111 - * rt ----- - * rs ----- - * sa ---- - */ -std::string NMD::SHRL_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRL.PH %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] SHRL.QB rt, rs, sa - Shift right logical vector quad bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 1100001111111 - * rt ----- - * rs ----- - * sa --- - */ -std::string NMD::SHRL_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 sa_value = extract_sa_15_14_13(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string sa = IMMEDIATE(copy(sa_value)); - - return img::format("SHRL.QB %s, %s, %s", rt, rs, sa); -} - - -/* - * [DSP] SHLLV.PH rd, rt, rs - Shift right logical variable vector pair of - * halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1100010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRLV_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRLV.PH %s, %s, %s", rd, rt, rs); -} - - -/* - * [DSP] SHLLV.QB rd, rt, rs - Shift right logical variable vector quad bytes - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 x1101010101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHRLV_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SHRLV.QB %s, %s, %s", rd, rt, rs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SHX %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SHXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SHXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SIGRIE(uint64 instruction) -{ - uint64 code_value = extract_code_18_to_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("SIGRIE %s", code); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLL_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 shift3_value = extract_shift3_2_1_0(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string shift3 = IMMEDIATE(encode_shift3_from_shift(shift3_value)); - - return img::format("SLL %s, %s, %s", rt3, rs3, shift3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLL_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("SLL %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLLV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SLLV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLT(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SLT %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLTI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SLTI %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLTIU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SLTIU %s, %s, %s", rt, rs, u); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SLTU(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SLTU %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SOV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SOV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SPECIAL2(uint64 instruction) -{ - uint64 op_value = extract_op_25_to_3(instruction); - - std::string op = IMMEDIATE(copy(op_value)); - - return img::format("SPECIAL2 %s", op); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SQRT_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("SQRT.D %s, %s", ft, fs); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SQRT_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("SQRT.S %s, %s", ft, fs); -} - - -/* - * SRA rd, rt, sa - Shift Word Right Arithmetic - * - * 3 2 1 - * 10987654321098765432109876543210 - * 00000000000 000011 - * rt ----- - * rd ----- - * sa ----- - */ -std::string NMD::SRA(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("SRA %s, %s, %s", rt, rs, shift); -} - - -/* - * SRAV rd, rt, rs - Shift Word Right Arithmetic Variable - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00000000111 - * rs ----- - * rt ----- - * rd ----- - */ -std::string NMD::SRAV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SRAV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00000000111 - * rs ----- - * rt ----- - * rd ----- - */ -std::string NMD::SRL_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 shift3_value = extract_shift3_2_1_0(instruction); - - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string shift3 = IMMEDIATE(encode_shift3_from_shift(shift3_value)); - - return img::format("SRL %s, %s, %s", rt3, rs3, shift3); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SRL_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 shift_value = extract_shift_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string shift = IMMEDIATE(copy(shift_value)); - - return img::format("SRL %s, %s, %s", rt, rs, shift); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SRLV(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SRLV %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUB %s, %s, %s", rd, rs, rt); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUB_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SUB.D %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUB_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - uint64 fd_value = extract_fd_15_14_13_12_11(instruction); - - std::string fd = FPR(copy(fd_value)); - std::string fs = FPR(copy(fs_value)); - std::string ft = FPR(copy(ft_value)); - - return img::format("SUB.S %s, %s, %s", fd, fs, ft); -} - - -/* - * - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQ_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQ.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBQ.S.PH rd, rt, rs - Subtract fractional halfword vectors and shift - * right to halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQ_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQ_S.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBQ.S.W rd, rt, rs - Subtract fractional halfword vectors and shift - * right to halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQ_S_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQ_S.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBQH.PH rd, rt, rs - Subtract fractional halfword vectors and shift - * right to halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQH_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQH.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBQH_R.PH rd, rt, rs - Subtract fractional halfword vectors and shift - * right to halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQH_R_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQH_R.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBQH_R.W rd, rt, rs - Subtract fractional halfword vectors and shift - * right to halve results with rounding - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11001001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQH_R_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQH_R.W %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBQH.W rd, rs, rt - Subtract fractional words and shift right to - * halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBQH_W(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBQH.W %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBU_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 rd3_value = extract_rd3_3_2_1(instruction); - - std::string rd3 = GPR(decode_gpr_gpr3(rd3_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - - return img::format("SUBU %s, %s, %s", rd3, rs3, rt3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBU_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBU %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBU.PH rd, rs, rt - Subtract unsigned unsigned halfwords - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01100001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBU_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBU.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBU.QB rd, rs, rt - Subtract unsigned quad byte vectors - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01011001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBU_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBU.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBU_S.PH rd, rs, rt - Subtract unsigned unsigned halfwords with - * 8-bit saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11100001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBU_S_PH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBU_S.PH %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBU_S.QB rd, rs, rt - Subtract unsigned quad byte vectors with - * 8-bit saturation - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11011001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBU_S_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBU_S.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBUH.QB rd, rs, rt - Subtract unsigned bytes and right shift - * to halve results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01101001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBUH_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBUH.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * [DSP] SUBUH_R.QB rd, rs, rt - Subtract unsigned bytes and right shift - * to halve results with rounding - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 11101001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SUBUH_R_QB(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SUBUH_R.QB %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_16_(uint64 instruction) -{ - uint64 rtz3_value = extract_rtz3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - uint64 u_value = extract_u_3_2_1_0__s2(instruction); - - std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - - return img::format("SW %s, %s(%s)", rtz3, u, rs3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_4X4_(uint64 instruction) -{ - uint64 rtz4_value = extract_rtz4_9_7_6_5(instruction); - uint64 rs4_value = extract_rs4_4_2_1_0(instruction); - uint64 u_value = extract_u_3_8__s2(instruction); - - std::string rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs4 = GPR(decode_gpr_gpr4(rs4_value)); - - return img::format("SW %s, %s(%s)", rtz4, u, rs4); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_GP16_(uint64 instruction) -{ - uint64 u_value = extract_u_6_5_4_3_2_1_0__s2(instruction); - uint64 rtz3_value = extract_rtz3_9_8_7(instruction); - - std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SW %s, %s($%d)", rtz3, u, 28); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_GP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 u_value = extract_u_20_to_2__s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SW %s, %s($%d)", rt, u, 28); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_S9_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SW %s, %s(%s)", rt, s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_SP_(uint64 instruction) -{ - uint64 rt_value = extract_rt_9_8_7_6_5(instruction); - uint64 u_value = extract_u_4_3_2_1_0__s2(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SW %s, %s($%d)", rt, u, 29); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SW_U12_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SW %s, %s(%s)", rt, u, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWC1_GP_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 u_value = extract_u_17_to_2__s2(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("SWC1 %s, %s($%d)", ft, u, 28); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWC1_S9_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SWC1 %s, %s(%s)", ft, s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWC1_U12_(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string u = IMMEDIATE(copy(u_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SWC1 %s, %s(%s)", ft, u, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWC1X(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SWC1X %s, %s(%s)", ft, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWC1XS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ft_value = extract_ft_15_14_13_12_11(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SWC1XS %s, %s(%s)", ft, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWC2(uint64 instruction) -{ - uint64 cs_value = extract_cs_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string cs = CPR(copy(cs_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SWC2 %s, %s(%s)", cs, s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SWE %s, %s(%s)", rt, s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("SWM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWPC_48_(uint64 instruction) -{ - uint64 rt_value = extract_rt_41_40_39_38_37(instruction); - int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = ADDRESS(encode_s_from_address(s_value), 6); - - return img::format("SWPC %s, %s", rt, s); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWX(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SWX %s, %s(%s)", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SWXS(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("SWXS %s, %s(%s)", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SYNC(uint64 instruction) -{ - uint64 stype_value = extract_stype_20_19_18_17_16(instruction); - - std::string stype = IMMEDIATE(copy(stype_value)); - - return img::format("SYNC %s", stype); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SYNCI(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SYNCI %s(%s)", s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SYNCIE(uint64 instruction) -{ - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("SYNCIE %s(%s)", s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::SYSCALL_16_(uint64 instruction) -{ - uint64 code_value = extract_code_1_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("SYSCALL %s", code); -} - - -/* - * SYSCALL code - System Call. Cause a System Call Exception - * - * 3 2 1 - * 10987654321098765432109876543210 - * 00000000000010 - * code ------------------ - */ -std::string NMD::SYSCALL_32_(uint64 instruction) -{ - uint64 code_value = extract_code_17_to_0(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("SYSCALL %s", code); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TEQ(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("TEQ %s, %s", rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBGINV(uint64 instruction) -{ - (void)instruction; - - return "TLBGINV "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBGINVF(uint64 instruction) -{ - (void)instruction; - - return "TLBGINVF "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBGP(uint64 instruction) -{ - (void)instruction; - - return "TLBGP "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBGR(uint64 instruction) -{ - (void)instruction; - - return "TLBGR "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBGWI(uint64 instruction) -{ - (void)instruction; - - return "TLBGWI "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBGWR(uint64 instruction) -{ - (void)instruction; - - return "TLBGWR "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBINV(uint64 instruction) -{ - (void)instruction; - - return "TLBINV "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBINVF(uint64 instruction) -{ - (void)instruction; - - return "TLBINVF "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBP(uint64 instruction) -{ - (void)instruction; - - return "TLBP "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBR(uint64 instruction) -{ - (void)instruction; - - return "TLBR "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBWI(uint64 instruction) -{ - (void)instruction; - - return "TLBWI "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TLBWR(uint64 instruction) -{ - (void)instruction; - - return "TLBWR "; -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TNE(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("TNE %s, %s", rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TRUNC_L_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("TRUNC.L.D %s, %s", ft, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TRUNC_L_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("TRUNC.L.S %s, %s", ft, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TRUNC_W_D(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("TRUNC.W.D %s, %s", ft, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::TRUNC_W_S(uint64 instruction) -{ - uint64 ft_value = extract_ft_25_24_23_22_21(instruction); - uint64 fs_value = extract_fs_20_19_18_17_16(instruction); - - std::string ft = FPR(copy(ft_value)); - std::string fs = FPR(copy(fs_value)); - - return img::format("TRUNC.W.S %s, %s", ft, fs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UALDM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("UALDM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UALH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("UALH %s, %s(%s)", rt, s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UALWM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("UALWM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UASDM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("UASDM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UASH(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("UASH %s, %s(%s)", rt, s, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UASWM(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction); - uint64 count3_value = extract_count3_14_13_12(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string s = IMMEDIATE(copy(s_value)); - std::string rs = GPR(copy(rs_value)); - std::string count3 = IMMEDIATE(encode_count3_from_count(count3_value)); - - return img::format("UASWM %s, %s(%s), %s", rt, s, rs, count3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::UDI(uint64 instruction) -{ - uint64 op_value = extract_op_25_to_3(instruction); - - std::string op = IMMEDIATE(copy(op_value)); - - return img::format("UDI %s", op); -} - - -/* - * WAIT code - Enter Wait State - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 1100001101111111 - * code ---------- - */ -std::string NMD::WAIT(uint64 instruction) -{ - uint64 code_value = extract_code_25_24_23_22_21_20_19_18_17_16(instruction); - - std::string code = IMMEDIATE(copy(code_value)); - - return img::format("WAIT %s", code); -} - - -/* - * [DSP] WRDSP rt, mask - Write selected fields from a GPR to the DSPControl - * register - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 01011001111111 - * rt ----- - * mask ------- - */ -std::string NMD::WRDSP(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 mask_value = extract_mask_20_19_18_17_16_15_14(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string mask = IMMEDIATE(copy(mask_value)); - - return img::format("WRDSP %s, %s", rt, mask); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::WRPGPR(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("WRPGPR %s, %s", rt, rs); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::XOR_16_(uint64 instruction) -{ - uint64 rt3_value = extract_rt3_9_8_7(instruction); - uint64 rs3_value = extract_rs3_6_5_4(instruction); - - std::string rs3 = GPR(decode_gpr_gpr3(rs3_value)); - std::string rt3 = GPR(decode_gpr_gpr3(rt3_value)); - - return img::format("XOR %s, %s", rs3, rt3); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::XOR_32_(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 rd_value = extract_rd_15_14_13_12_11(instruction); - - std::string rd = GPR(copy(rd_value)); - std::string rs = GPR(copy(rs_value)); - std::string rt = GPR(copy(rt_value)); - - return img::format("XOR %s, %s, %s", rd, rs, rt); -} - - -/* - * ADDQH_R.W rd, rt, rs - Add Fractional Words And Shift Right to Halve Results - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - * rd ----- - */ -std::string NMD::XORI(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - std::string u = IMMEDIATE(copy(u_value)); - - return img::format("XORI %s, %s, %s", rt, rs, u); -} - - -/* - * YIELD rt, rs - - * - * 3 2 1 - * 10987654321098765432109876543210 - * 001000 00010001101 - * rt ----- - * rs ----- - */ -std::string NMD::YIELD(uint64 instruction) -{ - uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - - std::string rt = GPR(copy(rt_value)); - std::string rs = GPR(copy(rs_value)); - - return img::format("YIELD %s, %s", rt, rs); -} - - - -/* - * nanoMIPS instruction pool organization - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * - * ┌─ P.ADDIU ─── P.RI ─── P.SYSCALL - * │ - * │ ┌─ P.TRAP - * │ │ - * │ ┌─ _POOL32A0_0 ─┼─ P.CMOVE - * │ │ │ - * │ │ └─ P.SLTU - * │ ┌─ _POOL32A0 ─┤ - * │ │ │ - * │ │ │ - * │ │ └─ _POOL32A0_1 ─── CRC32 - * │ │ - * ├─ P32A ─┤ - * │ │ ┌─ PP.LSX - * │ │ ┌─ P.LSX ─────┤ - * │ │ │ └─ PP.LSXS - * │ └─ _POOL32A7 ─┤ - * │ │ ┌─ POOL32Axf_4 - * │ └─ POOL32Axf ─┤ - * │ └─ POOL32Axf_5 - * │ - * ├─ PBAL - * │ - * ├─ P.GP.W ┌─ PP.LSX - * ┌─ P32 ─┤ │ - * │ ├─ P.GP.BH ─┴─ PP.LSXS - * │ │ - * │ ├─ P.J ─────── PP.BALRSC - * │ │ - * │ ├─ P48I - * │ │ ┌─ P.SR - * │ │ │ - * │ │ ├─ P.SHIFT - * │ │ │ - * │ ├─ P.U12 ───┼─ P.ROTX - * │ │ │ - * │ │ ├─ P.INS - * │ │ │ - * │ │ └─ P.EXT - * │ │ - * │ ├─ P.LS.U12 ── P.PREF.U12 - * │ │ - * │ ├─ P.BR1 ───── P.BR3A - * │ │ - * │ │ ┌─ P.LS.S0 ─── P16.SYSCALL - * │ │ │ - * │ │ │ ┌─ P.LL - * │ │ ├─ P.LS.S1 ─┤ - * │ │ │ └─ P.SC - * │ │ │ - * │ │ │ ┌─ P.PREFE - * MAJOR ─┤ ├─ P.LS.S9 ─┤ │ - * │ │ ├─ P.LS.E0 ─┼─ P.LLE - * │ │ │ │ - * │ │ │ └─ P.SCE - * │ │ │ - * │ │ ├─ P.LS.WM - * │ │ │ - * │ │ └─ P.LS.UAWM - * │ │ - * │ │ - * │ ├─ P.BR2 - * │ │ - * │ ├─ P.BRI - * │ │ - * │ └─ P.LUI - * │ - * │ - * │ ┌─ P16.MV ──── P16.RI ─── P16.SYSCALL - * │ │ - * │ ├─ P16.SR - * │ │ - * │ ├─ P16.SHIFT - * │ │ - * │ ├─ P16.4x4 - * │ │ - * │ ├─ P16C ────── POOL16C_0 ── POOL16C_00 - * │ │ - * └─ P16 ─┼─ P16.LB - * │ - * ├─ P16.A1 - * │ - * ├─ P16.LH - * │ - * ├─ P16.A2 ──── P.ADDIU[RS5] - * │ - * ├─ P16.ADDU - * │ - * └─ P16.BR ──┬─ P16.JRC - * │ - * └─ P16.BR1 - * - * - * (FP, DPS, and some minor instruction pools are omitted from the diagram) - * - */ - -NMD::Pool NMD::P_SYSCALL[2] = { - { instruction , 0 , 0 , 32, - 0xfffc0000, 0x00080000, &NMD::SYSCALL_32_ , 0, - 0x0 }, /* SYSCALL[32] */ - { instruction , 0 , 0 , 32, - 0xfffc0000, 0x000c0000, &NMD::HYPCALL , 0, - CP0_ | VZ_ }, /* HYPCALL */ -}; - - -NMD::Pool NMD::P_RI[4] = { - { instruction , 0 , 0 , 32, - 0xfff80000, 0x00000000, &NMD::SIGRIE , 0, - 0x0 }, /* SIGRIE */ - { pool , P_SYSCALL , 2 , 32, - 0xfff80000, 0x00080000, 0 , 0, - 0x0 }, /* P.SYSCALL */ - { instruction , 0 , 0 , 32, - 0xfff80000, 0x00100000, &NMD::BREAK_32_ , 0, - 0x0 }, /* BREAK[32] */ - { instruction , 0 , 0 , 32, - 0xfff80000, 0x00180000, &NMD::SDBBP_32_ , 0, - EJTAG_ }, /* SDBBP[32] */ -}; - - -NMD::Pool NMD::P_ADDIU[2] = { - { pool , P_RI , 4 , 32, - 0xffe00000, 0x00000000, 0 , 0, - 0x0 }, /* P.RI */ - { instruction , 0 , 0 , 32, - 0xfc000000, 0x00000000, &NMD::ADDIU_32_ , &NMD::ADDIU_32__cond , - 0x0 }, /* ADDIU[32] */ -}; - - -NMD::Pool NMD::P_TRAP[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000000, &NMD::TEQ , 0, - XMMS_ }, /* TEQ */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000400, &NMD::TNE , 0, - XMMS_ }, /* TNE */ -}; - - -NMD::Pool NMD::P_CMOVE[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000210, &NMD::MOVZ , 0, - 0x0 }, /* MOVZ */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000610, &NMD::MOVN , 0, - 0x0 }, /* MOVN */ -}; - - -NMD::Pool NMD::P_D_MT_VPE[2] = { - { instruction , 0 , 0 , 32, - 0xfc1f3fff, 0x20010ab0, &NMD::DMT , 0, - MT_ }, /* DMT */ - { instruction , 0 , 0 , 32, - 0xfc1f3fff, 0x20000ab0, &NMD::DVPE , 0, - MT_ }, /* DVPE */ -}; - - -NMD::Pool NMD::P_E_MT_VPE[2] = { - { instruction , 0 , 0 , 32, - 0xfc1f3fff, 0x20010eb0, &NMD::EMT , 0, - MT_ }, /* EMT */ - { instruction , 0 , 0 , 32, - 0xfc1f3fff, 0x20000eb0, &NMD::EVPE , 0, - MT_ }, /* EVPE */ -}; - - -NMD::Pool NMD::_P_MT_VPE[2] = { - { pool , P_D_MT_VPE , 2 , 32, - 0xfc003fff, 0x20000ab0, 0 , 0, - 0x0 }, /* P.D_MT_VPE */ - { pool , P_E_MT_VPE , 2 , 32, - 0xfc003fff, 0x20000eb0, 0 , 0, - 0x0 }, /* P.E_MT_VPE */ -}; - - -NMD::Pool NMD::P_MT_VPE[8] = { - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x200002b0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(0) */ - { pool , _P_MT_VPE , 2 , 32, - 0xfc003bff, 0x20000ab0, 0 , 0, - 0x0 }, /* _P.MT_VPE */ - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x200012b0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x20001ab0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x200022b0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x20002ab0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x200032b0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc003bff, 0x20003ab0, 0 , 0, - 0x0 }, /* P.MT_VPE~*(7) */ -}; - - -NMD::Pool NMD::P_DVP[2] = { - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20000390, &NMD::DVP , 0, - 0x0 }, /* DVP */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20000790, &NMD::EVP , 0, - 0x0 }, /* EVP */ -}; - - -NMD::Pool NMD::P_SLTU[2] = { - { pool , P_DVP , 2 , 32, - 0xfc00fbff, 0x20000390, 0 , 0, - 0x0 }, /* P.DVP */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000390, &NMD::SLTU , &NMD::SLTU_cond , - 0x0 }, /* SLTU */ -}; - - -NMD::Pool NMD::_POOL32A0[128] = { - { pool , P_TRAP , 2 , 32, - 0xfc0003ff, 0x20000000, 0 , 0, - 0x0 }, /* P.TRAP */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000008, &NMD::SEB , 0, - XMMS_ }, /* SEB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000010, &NMD::SLLV , 0, - 0x0 }, /* SLLV */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000018, &NMD::MUL_32_ , 0, - 0x0 }, /* MUL[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000020, 0 , 0, - 0x0 }, /* _POOL32A0~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000028, 0 , 0, - 0x0 }, /* _POOL32A0~*(5) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000030, &NMD::MFC0 , 0, - 0x0 }, /* MFC0 */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000038, &NMD::MFHC0 , 0, - CP0_ | MVH_ }, /* MFHC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000040, 0 , 0, - 0x0 }, /* _POOL32A0~*(8) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000048, &NMD::SEH , 0, - 0x0 }, /* SEH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000050, &NMD::SRLV , 0, - 0x0 }, /* SRLV */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000058, &NMD::MUH , 0, - 0x0 }, /* MUH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000060, 0 , 0, - 0x0 }, /* _POOL32A0~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000068, 0 , 0, - 0x0 }, /* _POOL32A0~*(13) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000070, &NMD::MTC0 , 0, - CP0_ }, /* MTC0 */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000078, &NMD::MTHC0 , 0, - CP0_ | MVH_ }, /* MTHC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000080, 0 , 0, - 0x0 }, /* _POOL32A0~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000088, 0 , 0, - 0x0 }, /* _POOL32A0~*(17) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000090, &NMD::SRAV , 0, - 0x0 }, /* SRAV */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000098, &NMD::MULU , 0, - 0x0 }, /* MULU */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000a0, 0 , 0, - 0x0 }, /* _POOL32A0~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000a8, 0 , 0, - 0x0 }, /* _POOL32A0~*(21) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000b0, &NMD::MFGC0 , 0, - CP0_ | VZ_ }, /* MFGC0 */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000b8, &NMD::MFHGC0 , 0, - CP0_ | VZ_ | MVH_ }, /* MFHGC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000c0, 0 , 0, - 0x0 }, /* _POOL32A0~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000c8, 0 , 0, - 0x0 }, /* _POOL32A0~*(25) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000d0, &NMD::ROTRV , 0, - 0x0 }, /* ROTRV */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000d8, &NMD::MUHU , 0, - 0x0 }, /* MUHU */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000e0, 0 , 0, - 0x0 }, /* _POOL32A0~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000e8, 0 , 0, - 0x0 }, /* _POOL32A0~*(29) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000f0, &NMD::MTGC0 , 0, - CP0_ | VZ_ }, /* MTGC0 */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000f8, &NMD::MTHGC0 , 0, - CP0_ | VZ_ | MVH_ }, /* MTHGC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000100, 0 , 0, - 0x0 }, /* _POOL32A0~*(32) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000108, 0 , 0, - 0x0 }, /* _POOL32A0~*(33) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000110, &NMD::ADD , 0, - XMMS_ }, /* ADD */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000118, &NMD::DIV , 0, - 0x0 }, /* DIV */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000120, 0 , 0, - 0x0 }, /* _POOL32A0~*(36) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000128, 0 , 0, - 0x0 }, /* _POOL32A0~*(37) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000130, &NMD::DMFC0 , 0, - CP0_ | MIPS64_ }, /* DMFC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000138, 0 , 0, - 0x0 }, /* _POOL32A0~*(39) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000140, 0 , 0, - 0x0 }, /* _POOL32A0~*(40) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000148, 0 , 0, - 0x0 }, /* _POOL32A0~*(41) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000150, &NMD::ADDU_32_ , 0, - 0x0 }, /* ADDU[32] */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000158, &NMD::MOD , 0, - 0x0 }, /* MOD */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000160, 0 , 0, - 0x0 }, /* _POOL32A0~*(44) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000168, 0 , 0, - 0x0 }, /* _POOL32A0~*(45) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000170, &NMD::DMTC0 , 0, - CP0_ | MIPS64_ }, /* DMTC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000178, 0 , 0, - 0x0 }, /* _POOL32A0~*(47) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000180, 0 , 0, - 0x0 }, /* _POOL32A0~*(48) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000188, 0 , 0, - 0x0 }, /* _POOL32A0~*(49) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000190, &NMD::SUB , 0, - XMMS_ }, /* SUB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000198, &NMD::DIVU , 0, - 0x0 }, /* DIVU */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001a0, 0 , 0, - 0x0 }, /* _POOL32A0~*(52) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001a8, 0 , 0, - 0x0 }, /* _POOL32A0~*(53) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001b0, &NMD::DMFGC0 , 0, - CP0_ | MIPS64_ | VZ_}, /* DMFGC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001b8, 0 , 0, - 0x0 }, /* _POOL32A0~*(55) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001c0, &NMD::RDHWR , 0, - XMMS_ }, /* RDHWR */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001c8, 0 , 0, - 0x0 }, /* _POOL32A0~*(57) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001d0, &NMD::SUBU_32_ , 0, - 0x0 }, /* SUBU[32] */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001d8, &NMD::MODU , 0, - 0x0 }, /* MODU */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001e0, 0 , 0, - 0x0 }, /* _POOL32A0~*(60) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001e8, 0 , 0, - 0x0 }, /* _POOL32A0~*(61) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001f0, &NMD::DMTGC0 , 0, - CP0_ | MIPS64_ | VZ_}, /* DMTGC0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001f8, 0 , 0, - 0x0 }, /* _POOL32A0~*(63) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000200, 0 , 0, - 0x0 }, /* _POOL32A0~*(64) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000208, 0 , 0, - 0x0 }, /* _POOL32A0~*(65) */ - { pool , P_CMOVE , 2 , 32, - 0xfc0003ff, 0x20000210, 0 , 0, - 0x0 }, /* P.CMOVE */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000218, 0 , 0, - 0x0 }, /* _POOL32A0~*(67) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000220, 0 , 0, - 0x0 }, /* _POOL32A0~*(68) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000228, &NMD::FORK , 0, - MT_ }, /* FORK */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000230, &NMD::MFTR , 0, - MT_ }, /* MFTR */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000238, &NMD::MFHTR , 0, - MT_ }, /* MFHTR */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000240, 0 , 0, - 0x0 }, /* _POOL32A0~*(72) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000248, 0 , 0, - 0x0 }, /* _POOL32A0~*(73) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000250, &NMD::AND_32_ , 0, - 0x0 }, /* AND[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000258, 0 , 0, - 0x0 }, /* _POOL32A0~*(75) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000260, 0 , 0, - 0x0 }, /* _POOL32A0~*(76) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000268, &NMD::YIELD , 0, - MT_ }, /* YIELD */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000270, &NMD::MTTR , 0, - MT_ }, /* MTTR */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000278, &NMD::MTHTR , 0, - MT_ }, /* MTHTR */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000280, 0 , 0, - 0x0 }, /* _POOL32A0~*(80) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000288, 0 , 0, - 0x0 }, /* _POOL32A0~*(81) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000290, &NMD::OR_32_ , 0, - 0x0 }, /* OR[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000298, 0 , 0, - 0x0 }, /* _POOL32A0~*(83) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002a0, 0 , 0, - 0x0 }, /* _POOL32A0~*(84) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002a8, 0 , 0, - 0x0 }, /* _POOL32A0~*(85) */ - { pool , P_MT_VPE , 8 , 32, - 0xfc0003ff, 0x200002b0, 0 , 0, - 0x0 }, /* P.MT_VPE */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002b8, 0 , 0, - 0x0 }, /* _POOL32A0~*(87) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002c0, 0 , 0, - 0x0 }, /* _POOL32A0~*(88) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002c8, 0 , 0, - 0x0 }, /* _POOL32A0~*(89) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200002d0, &NMD::NOR , 0, - 0x0 }, /* NOR */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002d8, 0 , 0, - 0x0 }, /* _POOL32A0~*(91) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002e0, 0 , 0, - 0x0 }, /* _POOL32A0~*(92) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002e8, 0 , 0, - 0x0 }, /* _POOL32A0~*(93) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002f0, 0 , 0, - 0x0 }, /* _POOL32A0~*(94) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002f8, 0 , 0, - 0x0 }, /* _POOL32A0~*(95) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000300, 0 , 0, - 0x0 }, /* _POOL32A0~*(96) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000308, 0 , 0, - 0x0 }, /* _POOL32A0~*(97) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000310, &NMD::XOR_32_ , 0, - 0x0 }, /* XOR[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000318, 0 , 0, - 0x0 }, /* _POOL32A0~*(99) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000320, 0 , 0, - 0x0 }, /* _POOL32A0~*(100) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000328, 0 , 0, - 0x0 }, /* _POOL32A0~*(101) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000330, 0 , 0, - 0x0 }, /* _POOL32A0~*(102) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000338, 0 , 0, - 0x0 }, /* _POOL32A0~*(103) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000340, 0 , 0, - 0x0 }, /* _POOL32A0~*(104) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000348, 0 , 0, - 0x0 }, /* _POOL32A0~*(105) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000350, &NMD::SLT , 0, - 0x0 }, /* SLT */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000358, 0 , 0, - 0x0 }, /* _POOL32A0~*(107) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000360, 0 , 0, - 0x0 }, /* _POOL32A0~*(108) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000368, 0 , 0, - 0x0 }, /* _POOL32A0~*(109) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000370, 0 , 0, - 0x0 }, /* _POOL32A0~*(110) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000378, 0 , 0, - 0x0 }, /* _POOL32A0~*(111) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000380, 0 , 0, - 0x0 }, /* _POOL32A0~*(112) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000388, 0 , 0, - 0x0 }, /* _POOL32A0~*(113) */ - { pool , P_SLTU , 2 , 32, - 0xfc0003ff, 0x20000390, 0 , 0, - 0x0 }, /* P.SLTU */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000398, 0 , 0, - 0x0 }, /* _POOL32A0~*(115) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003a0, 0 , 0, - 0x0 }, /* _POOL32A0~*(116) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003a8, 0 , 0, - 0x0 }, /* _POOL32A0~*(117) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003b0, 0 , 0, - 0x0 }, /* _POOL32A0~*(118) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003b8, 0 , 0, - 0x0 }, /* _POOL32A0~*(119) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003c0, 0 , 0, - 0x0 }, /* _POOL32A0~*(120) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003c8, 0 , 0, - 0x0 }, /* _POOL32A0~*(121) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200003d0, &NMD::SOV , 0, - 0x0 }, /* SOV */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003d8, 0 , 0, - 0x0 }, /* _POOL32A0~*(123) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003e0, 0 , 0, - 0x0 }, /* _POOL32A0~*(124) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003e8, 0 , 0, - 0x0 }, /* _POOL32A0~*(125) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003f0, 0 , 0, - 0x0 }, /* _POOL32A0~*(126) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003f8, 0 , 0, - 0x0 }, /* _POOL32A0~*(127) */ -}; - - -NMD::Pool NMD::ADDQ__S__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000000d, &NMD::ADDQ_PH , 0, - DSP_ }, /* ADDQ.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000040d, &NMD::ADDQ_S_PH , 0, - DSP_ }, /* ADDQ_S.PH */ -}; - - -NMD::Pool NMD::MUL__S__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000002d, &NMD::MUL_PH , 0, - DSP_ }, /* MUL.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000042d, &NMD::MUL_S_PH , 0, - DSP_ }, /* MUL_S.PH */ -}; - - -NMD::Pool NMD::ADDQH__R__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000004d, &NMD::ADDQH_PH , 0, - DSP_ }, /* ADDQH.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000044d, &NMD::ADDQH_R_PH , 0, - DSP_ }, /* ADDQH_R.PH */ -}; - - -NMD::Pool NMD::ADDQH__R__W[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000008d, &NMD::ADDQH_W , 0, - DSP_ }, /* ADDQH.W */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000048d, &NMD::ADDQH_R_W , 0, - DSP_ }, /* ADDQH_R.W */ -}; - - -NMD::Pool NMD::ADDU__S__QB[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200000cd, &NMD::ADDU_QB , 0, - DSP_ }, /* ADDU.QB */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200004cd, &NMD::ADDU_S_QB , 0, - DSP_ }, /* ADDU_S.QB */ -}; - - -NMD::Pool NMD::ADDU__S__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000010d, &NMD::ADDU_PH , 0, - DSP_ }, /* ADDU.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000050d, &NMD::ADDU_S_PH , 0, - DSP_ }, /* ADDU_S.PH */ -}; - - -NMD::Pool NMD::ADDUH__R__QB[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000014d, &NMD::ADDUH_QB , 0, - DSP_ }, /* ADDUH.QB */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000054d, &NMD::ADDUH_R_QB , 0, - DSP_ }, /* ADDUH_R.QB */ -}; - - -NMD::Pool NMD::SHRAV__R__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000018d, &NMD::SHRAV_PH , 0, - DSP_ }, /* SHRAV.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000058d, &NMD::SHRAV_R_PH , 0, - DSP_ }, /* SHRAV_R.PH */ -}; - - -NMD::Pool NMD::SHRAV__R__QB[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200001cd, &NMD::SHRAV_QB , 0, - DSP_ }, /* SHRAV.QB */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200005cd, &NMD::SHRAV_R_QB , 0, - DSP_ }, /* SHRAV_R.QB */ -}; - - -NMD::Pool NMD::SUBQ__S__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000020d, &NMD::SUBQ_PH , 0, - DSP_ }, /* SUBQ.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000060d, &NMD::SUBQ_S_PH , 0, - DSP_ }, /* SUBQ_S.PH */ -}; - - -NMD::Pool NMD::SUBQH__R__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000024d, &NMD::SUBQH_PH , 0, - DSP_ }, /* SUBQH.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000064d, &NMD::SUBQH_R_PH , 0, - DSP_ }, /* SUBQH_R.PH */ -}; - - -NMD::Pool NMD::SUBQH__R__W[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000028d, &NMD::SUBQH_W , 0, - DSP_ }, /* SUBQH.W */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000068d, &NMD::SUBQH_R_W , 0, - DSP_ }, /* SUBQH_R.W */ -}; - - -NMD::Pool NMD::SUBU__S__QB[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200002cd, &NMD::SUBU_QB , 0, - DSP_ }, /* SUBU.QB */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200006cd, &NMD::SUBU_S_QB , 0, - DSP_ }, /* SUBU_S.QB */ -}; - - -NMD::Pool NMD::SUBU__S__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000030d, &NMD::SUBU_PH , 0, - DSP_ }, /* SUBU.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000070d, &NMD::SUBU_S_PH , 0, - DSP_ }, /* SUBU_S.PH */ -}; - - -NMD::Pool NMD::SHRA__R__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000335, &NMD::SHRA_PH , 0, - DSP_ }, /* SHRA.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000735, &NMD::SHRA_R_PH , 0, - DSP_ }, /* SHRA_R.PH */ -}; - - -NMD::Pool NMD::SUBUH__R__QB[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000034d, &NMD::SUBUH_QB , 0, - DSP_ }, /* SUBUH.QB */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000074d, &NMD::SUBUH_R_QB , 0, - DSP_ }, /* SUBUH_R.QB */ -}; - - -NMD::Pool NMD::SHLLV__S__PH[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000038d, &NMD::SHLLV_PH , 0, - DSP_ }, /* SHLLV.PH */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x2000078d, &NMD::SHLLV_S_PH , 0, - DSP_ }, /* SHLLV_S.PH */ -}; - - -NMD::Pool NMD::SHLL__S__PH[4] = { - { instruction , 0 , 0 , 32, - 0xfc000fff, 0x200003b5, &NMD::SHLL_PH , 0, - DSP_ }, /* SHLL.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x200007b5, 0 , 0, - 0x0 }, /* SHLL[_S].PH~*(1) */ - { instruction , 0 , 0 , 32, - 0xfc000fff, 0x20000bb5, &NMD::SHLL_S_PH , 0, - DSP_ }, /* SHLL_S.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x20000fb5, 0 , 0, - 0x0 }, /* SHLL[_S].PH~*(3) */ -}; - - -NMD::Pool NMD::PRECR_SRA__R__PH_W[2] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200003cd, &NMD::PRECR_SRA_PH_W , 0, - DSP_ }, /* PRECR_SRA.PH.W */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200007cd, &NMD::PRECR_SRA_R_PH_W , 0, - DSP_ }, /* PRECR_SRA_R.PH.W */ -}; - - -NMD::Pool NMD::_POOL32A5[128] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000005, &NMD::CMP_EQ_PH , 0, - DSP_ }, /* CMP.EQ.PH */ - { pool , ADDQ__S__PH , 2 , 32, - 0xfc0003ff, 0x2000000d, 0 , 0, - 0x0 }, /* ADDQ[_S].PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000015, 0 , 0, - 0x0 }, /* _POOL32A5~*(2) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x2000001d, &NMD::SHILO , 0, - DSP_ }, /* SHILO */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000025, &NMD::MULEQ_S_W_PHL , 0, - DSP_ }, /* MULEQ_S.W.PHL */ - { pool , MUL__S__PH , 2 , 32, - 0xfc0003ff, 0x2000002d, 0 , 0, - 0x0 }, /* MUL[_S].PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000035, 0 , 0, - 0x0 }, /* _POOL32A5~*(6) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x2000003d, &NMD::REPL_PH , 0, - DSP_ }, /* REPL.PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000045, &NMD::CMP_LT_PH , 0, - DSP_ }, /* CMP.LT.PH */ - { pool , ADDQH__R__PH , 2 , 32, - 0xfc0003ff, 0x2000004d, 0 , 0, - 0x0 }, /* ADDQH[_R].PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000055, 0 , 0, - 0x0 }, /* _POOL32A5~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000005d, 0 , 0, - 0x0 }, /* _POOL32A5~*(11) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000065, &NMD::MULEQ_S_W_PHR , 0, - DSP_ }, /* MULEQ_S.W.PHR */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x2000006d, &NMD::PRECR_QB_PH , 0, - DSP_ }, /* PRECR.QB.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000075, 0 , 0, - 0x0 }, /* _POOL32A5~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000007d, 0 , 0, - 0x0 }, /* _POOL32A5~*(15) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000085, &NMD::CMP_LE_PH , 0, - DSP_ }, /* CMP.LE.PH */ - { pool , ADDQH__R__W , 2 , 32, - 0xfc0003ff, 0x2000008d, 0 , 0, - 0x0 }, /* ADDQH[_R].W */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000095, &NMD::MULEU_S_PH_QBL , 0, - DSP_ }, /* MULEU_S.PH.QBL */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000009d, 0 , 0, - 0x0 }, /* _POOL32A5~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000a5, 0 , 0, - 0x0 }, /* _POOL32A5~*(20) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000ad, &NMD::PRECRQ_QB_PH , 0, - DSP_ }, /* PRECRQ.QB.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000b5, 0 , 0, - 0x0 }, /* _POOL32A5~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000bd, 0 , 0, - 0x0 }, /* _POOL32A5~*(23) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000c5, &NMD::CMPGU_EQ_QB , 0, - DSP_ }, /* CMPGU.EQ.QB */ - { pool , ADDU__S__QB , 2 , 32, - 0xfc0003ff, 0x200000cd, 0 , 0, - 0x0 }, /* ADDU[_S].QB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000d5, &NMD::MULEU_S_PH_QBR , 0, - DSP_ }, /* MULEU_S.PH.QBR */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000dd, 0 , 0, - 0x0 }, /* _POOL32A5~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000e5, 0 , 0, - 0x0 }, /* _POOL32A5~*(28) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200000ed, &NMD::PRECRQ_PH_W , 0, - DSP_ }, /* PRECRQ.PH.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000f5, 0 , 0, - 0x0 }, /* _POOL32A5~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200000fd, 0 , 0, - 0x0 }, /* _POOL32A5~*(31) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000105, &NMD::CMPGU_LT_QB , 0, - DSP_ }, /* CMPGU.LT.QB */ - { pool , ADDU__S__PH , 2 , 32, - 0xfc0003ff, 0x2000010d, 0 , 0, - 0x0 }, /* ADDU[_S].PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000115, &NMD::MULQ_RS_PH , 0, - DSP_ }, /* MULQ_RS.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000011d, 0 , 0, - 0x0 }, /* _POOL32A5~*(35) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000125, 0 , 0, - 0x0 }, /* _POOL32A5~*(36) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x2000012d, &NMD::PRECRQ_RS_PH_W , 0, - DSP_ }, /* PRECRQ_RS.PH.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000135, 0 , 0, - 0x0 }, /* _POOL32A5~*(38) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000013d, 0 , 0, - 0x0 }, /* _POOL32A5~*(39) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000145, &NMD::CMPGU_LE_QB , 0, - DSP_ }, /* CMPGU.LE.QB */ - { pool , ADDUH__R__QB , 2 , 32, - 0xfc0003ff, 0x2000014d, 0 , 0, - 0x0 }, /* ADDUH[_R].QB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000155, &NMD::MULQ_S_PH , 0, - DSP_ }, /* MULQ_S.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000015d, 0 , 0, - 0x0 }, /* _POOL32A5~*(43) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000165, 0 , 0, - 0x0 }, /* _POOL32A5~*(44) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x2000016d, &NMD::PRECRQU_S_QB_PH , 0, - DSP_ }, /* PRECRQU_S.QB.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000175, 0 , 0, - 0x0 }, /* _POOL32A5~*(46) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000017d, 0 , 0, - 0x0 }, /* _POOL32A5~*(47) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000185, &NMD::CMPGDU_EQ_QB , 0, - DSP_ }, /* CMPGDU.EQ.QB */ - { pool , SHRAV__R__PH , 2 , 32, - 0xfc0003ff, 0x2000018d, 0 , 0, - 0x0 }, /* SHRAV[_R].PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000195, &NMD::MULQ_RS_W , 0, - DSP_ }, /* MULQ_RS.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000019d, 0 , 0, - 0x0 }, /* _POOL32A5~*(51) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001a5, 0 , 0, - 0x0 }, /* _POOL32A5~*(52) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001ad, &NMD::PACKRL_PH , 0, - DSP_ }, /* PACKRL.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001b5, 0 , 0, - 0x0 }, /* _POOL32A5~*(54) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001bd, 0 , 0, - 0x0 }, /* _POOL32A5~*(55) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001c5, &NMD::CMPGDU_LT_QB , 0, - DSP_ }, /* CMPGDU.LT.QB */ - { pool , SHRAV__R__QB , 2 , 32, - 0xfc0003ff, 0x200001cd, 0 , 0, - 0x0 }, /* SHRAV[_R].QB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001d5, &NMD::MULQ_S_W , 0, - DSP_ }, /* MULQ_S.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001dd, 0 , 0, - 0x0 }, /* _POOL32A5~*(59) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001e5, 0 , 0, - 0x0 }, /* _POOL32A5~*(60) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200001ed, &NMD::PICK_QB , 0, - DSP_ }, /* PICK.QB */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001f5, 0 , 0, - 0x0 }, /* _POOL32A5~*(62) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200001fd, 0 , 0, - 0x0 }, /* _POOL32A5~*(63) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000205, &NMD::CMPGDU_LE_QB , 0, - DSP_ }, /* CMPGDU.LE.QB */ - { pool , SUBQ__S__PH , 2 , 32, - 0xfc0003ff, 0x2000020d, 0 , 0, - 0x0 }, /* SUBQ[_S].PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000215, &NMD::APPEND , 0, - DSP_ }, /* APPEND */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000021d, 0 , 0, - 0x0 }, /* _POOL32A5~*(67) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000225, 0 , 0, - 0x0 }, /* _POOL32A5~*(68) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x2000022d, &NMD::PICK_PH , 0, - DSP_ }, /* PICK.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000235, 0 , 0, - 0x0 }, /* _POOL32A5~*(70) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000023d, 0 , 0, - 0x0 }, /* _POOL32A5~*(71) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000245, &NMD::CMPU_EQ_QB , 0, - DSP_ }, /* CMPU.EQ.QB */ - { pool , SUBQH__R__PH , 2 , 32, - 0xfc0003ff, 0x2000024d, 0 , 0, - 0x0 }, /* SUBQH[_R].PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000255, &NMD::PREPEND , 0, - DSP_ }, /* PREPEND */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000025d, 0 , 0, - 0x0 }, /* _POOL32A5~*(75) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000265, 0 , 0, - 0x0 }, /* _POOL32A5~*(76) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000026d, 0 , 0, - 0x0 }, /* _POOL32A5~*(77) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000275, 0 , 0, - 0x0 }, /* _POOL32A5~*(78) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000027d, 0 , 0, - 0x0 }, /* _POOL32A5~*(79) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000285, &NMD::CMPU_LT_QB , 0, - DSP_ }, /* CMPU.LT.QB */ - { pool , SUBQH__R__W , 2 , 32, - 0xfc0003ff, 0x2000028d, 0 , 0, - 0x0 }, /* SUBQH[_R].W */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000295, &NMD::MODSUB , 0, - DSP_ }, /* MODSUB */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000029d, 0 , 0, - 0x0 }, /* _POOL32A5~*(83) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002a5, 0 , 0, - 0x0 }, /* _POOL32A5~*(84) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002ad, 0 , 0, - 0x0 }, /* _POOL32A5~*(85) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002b5, 0 , 0, - 0x0 }, /* _POOL32A5~*(86) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002bd, 0 , 0, - 0x0 }, /* _POOL32A5~*(87) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200002c5, &NMD::CMPU_LE_QB , 0, - DSP_ }, /* CMPU.LE.QB */ - { pool , SUBU__S__QB , 2 , 32, - 0xfc0003ff, 0x200002cd, 0 , 0, - 0x0 }, /* SUBU[_S].QB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200002d5, &NMD::SHRAV_R_W , 0, - DSP_ }, /* SHRAV_R.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002dd, 0 , 0, - 0x0 }, /* _POOL32A5~*(91) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002e5, 0 , 0, - 0x0 }, /* _POOL32A5~*(92) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002ed, 0 , 0, - 0x0 }, /* _POOL32A5~*(93) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200002f5, &NMD::SHRA_R_W , 0, - DSP_ }, /* SHRA_R.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200002fd, 0 , 0, - 0x0 }, /* _POOL32A5~*(95) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000305, &NMD::ADDQ_S_W , 0, - DSP_ }, /* ADDQ_S.W */ - { pool , SUBU__S__PH , 2 , 32, - 0xfc0003ff, 0x2000030d, 0 , 0, - 0x0 }, /* SUBU[_S].PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000315, &NMD::SHRLV_PH , 0, - DSP_ }, /* SHRLV.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000031d, 0 , 0, - 0x0 }, /* _POOL32A5~*(99) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000325, 0 , 0, - 0x0 }, /* _POOL32A5~*(100) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000032d, 0 , 0, - 0x0 }, /* _POOL32A5~*(101) */ - { pool , SHRA__R__PH , 2 , 32, - 0xfc0003ff, 0x20000335, 0 , 0, - 0x0 }, /* SHRA[_R].PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000033d, 0 , 0, - 0x0 }, /* _POOL32A5~*(103) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000345, &NMD::SUBQ_S_W , 0, - DSP_ }, /* SUBQ_S.W */ - { pool , SUBUH__R__QB , 2 , 32, - 0xfc0003ff, 0x2000034d, 0 , 0, - 0x0 }, /* SUBUH[_R].QB */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000355, &NMD::SHRLV_QB , 0, - DSP_ }, /* SHRLV.QB */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000035d, 0 , 0, - 0x0 }, /* _POOL32A5~*(107) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000365, 0 , 0, - 0x0 }, /* _POOL32A5~*(108) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000036d, 0 , 0, - 0x0 }, /* _POOL32A5~*(109) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x20000375, 0 , 0, - 0x0 }, /* _POOL32A5~*(110) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000037d, 0 , 0, - 0x0 }, /* _POOL32A5~*(111) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000385, &NMD::ADDSC , 0, - DSP_ }, /* ADDSC */ - { pool , SHLLV__S__PH , 2 , 32, - 0xfc0003ff, 0x2000038d, 0 , 0, - 0x0 }, /* SHLLV[_S].PH */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x20000395, &NMD::SHLLV_QB , 0, - DSP_ }, /* SHLLV.QB */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x2000039d, 0 , 0, - 0x0 }, /* _POOL32A5~*(115) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003a5, 0 , 0, - 0x0 }, /* _POOL32A5~*(116) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003ad, 0 , 0, - 0x0 }, /* _POOL32A5~*(117) */ - { pool , SHLL__S__PH , 4 , 32, - 0xfc0003ff, 0x200003b5, 0 , 0, - 0x0 }, /* SHLL[_S].PH */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003bd, 0 , 0, - 0x0 }, /* _POOL32A5~*(119) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200003c5, &NMD::ADDWC , 0, - DSP_ }, /* ADDWC */ - { pool , PRECR_SRA__R__PH_W , 2 , 32, - 0xfc0003ff, 0x200003cd, 0 , 0, - 0x0 }, /* PRECR_SRA[_R].PH.W */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200003d5, &NMD::SHLLV_S_W , 0, - DSP_ }, /* SHLLV_S.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003dd, 0 , 0, - 0x0 }, /* _POOL32A5~*(123) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003e5, 0 , 0, - 0x0 }, /* _POOL32A5~*(124) */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003ed, 0 , 0, - 0x0 }, /* _POOL32A5~*(125) */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0x200003f5, &NMD::SHLL_S_W , 0, - DSP_ }, /* SHLL_S.W */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0x200003fd, 0 , 0, - 0x0 }, /* _POOL32A5~*(127) */ -}; - - -NMD::Pool NMD::PP_LSX[16] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000007, &NMD::LBX , 0, - 0x0 }, /* LBX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000087, &NMD::SBX , 0, - XMMS_ }, /* SBX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000107, &NMD::LBUX , 0, - 0x0 }, /* LBUX */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0x20000187, 0 , 0, - 0x0 }, /* PP.LSX~*(3) */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000207, &NMD::LHX , 0, - 0x0 }, /* LHX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000287, &NMD::SHX , 0, - XMMS_ }, /* SHX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000307, &NMD::LHUX , 0, - 0x0 }, /* LHUX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000387, &NMD::LWUX , 0, - MIPS64_ }, /* LWUX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000407, &NMD::LWX , 0, - 0x0 }, /* LWX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000487, &NMD::SWX , 0, - XMMS_ }, /* SWX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000507, &NMD::LWC1X , 0, - CP1_ }, /* LWC1X */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000587, &NMD::SWC1X , 0, - CP1_ }, /* SWC1X */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000607, &NMD::LDX , 0, - MIPS64_ }, /* LDX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000687, &NMD::SDX , 0, - MIPS64_ }, /* SDX */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000707, &NMD::LDC1X , 0, - CP1_ }, /* LDC1X */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000787, &NMD::SDC1X , 0, - CP1_ }, /* SDC1X */ -}; - - -NMD::Pool NMD::PP_LSXS[16] = { - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0x20000047, 0 , 0, - 0x0 }, /* PP.LSXS~*(0) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0x200000c7, 0 , 0, - 0x0 }, /* PP.LSXS~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0x20000147, 0 , 0, - 0x0 }, /* PP.LSXS~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0x200001c7, 0 , 0, - 0x0 }, /* PP.LSXS~*(3) */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000247, &NMD::LHXS , 0, - 0x0 }, /* LHXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200002c7, &NMD::SHXS , 0, - XMMS_ }, /* SHXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000347, &NMD::LHUXS , 0, - 0x0 }, /* LHUXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200003c7, &NMD::LWUXS , 0, - MIPS64_ }, /* LWUXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000447, &NMD::LWXS_32_ , 0, - 0x0 }, /* LWXS[32] */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200004c7, &NMD::SWXS , 0, - XMMS_ }, /* SWXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000547, &NMD::LWC1XS , 0, - CP1_ }, /* LWC1XS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200005c7, &NMD::SWC1XS , 0, - CP1_ }, /* SWC1XS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000647, &NMD::LDXS , 0, - MIPS64_ }, /* LDXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200006c7, &NMD::SDXS , 0, - MIPS64_ }, /* SDXS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x20000747, &NMD::LDC1XS , 0, - CP1_ }, /* LDC1XS */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0x200007c7, &NMD::SDC1XS , 0, - CP1_ }, /* SDC1XS */ -}; - - -NMD::Pool NMD::P_LSX[2] = { - { pool , PP_LSX , 16 , 32, - 0xfc00007f, 0x20000007, 0 , 0, - 0x0 }, /* PP.LSX */ - { pool , PP_LSXS , 16 , 32, - 0xfc00007f, 0x20000047, 0 , 0, - 0x0 }, /* PP.LSXS */ -}; - - -NMD::Pool NMD::POOL32Axf_1_0[4] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000007f, &NMD::MFHI_DSP_ , 0, - DSP_ }, /* MFHI[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000107f, &NMD::MFLO_DSP_ , 0, - DSP_ }, /* MFLO[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000207f, &NMD::MTHI_DSP_ , 0, - DSP_ }, /* MTHI[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000307f, &NMD::MTLO_DSP_ , 0, - DSP_ }, /* MTLO[DSP] */ -}; - - -NMD::Pool NMD::POOL32Axf_1_1[4] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000027f, &NMD::MTHLIP , 0, - DSP_ }, /* MTHLIP */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000127f, &NMD::SHILOV , 0, - DSP_ }, /* SHILOV */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0x2000227f, 0 , 0, - 0x0 }, /* POOL32Axf_1_1~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0x2000327f, 0 , 0, - 0x0 }, /* POOL32Axf_1_1~*(3) */ -}; - - -NMD::Pool NMD::POOL32Axf_1_3[4] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000067f, &NMD::RDDSP , 0, - DSP_ }, /* RDDSP */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000167f, &NMD::WRDSP , 0, - DSP_ }, /* WRDSP */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000267f, &NMD::EXTP , 0, - DSP_ }, /* EXTP */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x2000367f, &NMD::EXTPDP , 0, - DSP_ }, /* EXTPDP */ -}; - - -NMD::Pool NMD::POOL32Axf_1_4[2] = { - { instruction , 0 , 0 , 32, - 0xfc001fff, 0x2000087f, &NMD::SHLL_QB , 0, - DSP_ }, /* SHLL.QB */ - { instruction , 0 , 0 , 32, - 0xfc001fff, 0x2000187f, &NMD::SHRL_QB , 0, - DSP_ }, /* SHRL.QB */ -}; - - -NMD::Pool NMD::MAQ_S_A__W_PHR[2] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20000a7f, &NMD::MAQ_S_W_PHR , 0, - DSP_ }, /* MAQ_S.W.PHR */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20002a7f, &NMD::MAQ_SA_W_PHR , 0, - DSP_ }, /* MAQ_SA.W.PHR */ -}; - - -NMD::Pool NMD::MAQ_S_A__W_PHL[2] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20001a7f, &NMD::MAQ_S_W_PHL , 0, - DSP_ }, /* MAQ_S.W.PHL */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20003a7f, &NMD::MAQ_SA_W_PHL , 0, - DSP_ }, /* MAQ_SA.W.PHL */ -}; - - -NMD::Pool NMD::POOL32Axf_1_5[2] = { - { pool , MAQ_S_A__W_PHR , 2 , 32, - 0xfc001fff, 0x20000a7f, 0 , 0, - 0x0 }, /* MAQ_S[A].W.PHR */ - { pool , MAQ_S_A__W_PHL , 2 , 32, - 0xfc001fff, 0x20001a7f, 0 , 0, - 0x0 }, /* MAQ_S[A].W.PHL */ -}; - - -NMD::Pool NMD::POOL32Axf_1_7[4] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20000e7f, &NMD::EXTR_W , 0, - DSP_ }, /* EXTR.W */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20001e7f, &NMD::EXTR_R_W , 0, - DSP_ }, /* EXTR_R.W */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20002e7f, &NMD::EXTR_RS_W , 0, - DSP_ }, /* EXTR_RS.W */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20003e7f, &NMD::EXTR_S_H , 0, - DSP_ }, /* EXTR_S.H */ -}; - - -NMD::Pool NMD::POOL32Axf_1[8] = { - { pool , POOL32Axf_1_0 , 4 , 32, - 0xfc000fff, 0x2000007f, 0 , 0, - 0x0 }, /* POOL32Axf_1_0 */ - { pool , POOL32Axf_1_1 , 4 , 32, - 0xfc000fff, 0x2000027f, 0 , 0, - 0x0 }, /* POOL32Axf_1_1 */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x2000047f, 0 , 0, - 0x0 }, /* POOL32Axf_1~*(2) */ - { pool , POOL32Axf_1_3 , 4 , 32, - 0xfc000fff, 0x2000067f, 0 , 0, - 0x0 }, /* POOL32Axf_1_3 */ - { pool , POOL32Axf_1_4 , 2 , 32, - 0xfc000fff, 0x2000087f, 0 , 0, - 0x0 }, /* POOL32Axf_1_4 */ - { pool , POOL32Axf_1_5 , 2 , 32, - 0xfc000fff, 0x20000a7f, 0 , 0, - 0x0 }, /* POOL32Axf_1_5 */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x20000c7f, 0 , 0, - 0x0 }, /* POOL32Axf_1~*(6) */ - { pool , POOL32Axf_1_7 , 4 , 32, - 0xfc000fff, 0x20000e7f, 0 , 0, - 0x0 }, /* POOL32Axf_1_7 */ -}; - - -NMD::Pool NMD::POOL32Axf_2_DSP__0_7[8] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200000bf, &NMD::DPA_W_PH , 0, - DSP_ }, /* DPA.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200002bf, &NMD::DPAQ_S_W_PH , 0, - DSP_ }, /* DPAQ_S.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200004bf, &NMD::DPS_W_PH , 0, - DSP_ }, /* DPS.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200006bf, &NMD::DPSQ_S_W_PH , 0, - DSP_ }, /* DPSQ_S.W.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0x200008bf, 0 , 0, - 0x0 }, /* POOL32Axf_2(DSP)_0_7~*(4) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20000abf, &NMD::MADD_DSP_ , 0, - DSP_ }, /* MADD[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20000cbf, &NMD::MULT_DSP_ , 0, - DSP_ }, /* MULT[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20000ebf, &NMD::EXTRV_W , 0, - DSP_ }, /* EXTRV.W */ -}; - - -NMD::Pool NMD::POOL32Axf_2_DSP__8_15[8] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200010bf, &NMD::DPAX_W_PH , 0, - DSP_ }, /* DPAX.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200012bf, &NMD::DPAQ_SA_L_W , 0, - DSP_ }, /* DPAQ_SA.L.W */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200014bf, &NMD::DPSX_W_PH , 0, - DSP_ }, /* DPSX.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200016bf, &NMD::DPSQ_SA_L_W , 0, - DSP_ }, /* DPSQ_SA.L.W */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0x200018bf, 0 , 0, - 0x0 }, /* POOL32Axf_2(DSP)_8_15~*(4) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20001abf, &NMD::MADDU_DSP_ , 0, - DSP_ }, /* MADDU[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20001cbf, &NMD::MULTU_DSP_ , 0, - DSP_ }, /* MULTU[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20001ebf, &NMD::EXTRV_R_W , 0, - DSP_ }, /* EXTRV_R.W */ -}; - - -NMD::Pool NMD::POOL32Axf_2_DSP__16_23[8] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200020bf, &NMD::DPAU_H_QBL , 0, - DSP_ }, /* DPAU.H.QBL */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200022bf, &NMD::DPAQX_S_W_PH , 0, - DSP_ }, /* DPAQX_S.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200024bf, &NMD::DPSU_H_QBL , 0, - DSP_ }, /* DPSU.H.QBL */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200026bf, &NMD::DPSQX_S_W_PH , 0, - DSP_ }, /* DPSQX_S.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200028bf, &NMD::EXTPV , 0, - DSP_ }, /* EXTPV */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20002abf, &NMD::MSUB_DSP_ , 0, - DSP_ }, /* MSUB[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20002cbf, &NMD::MULSA_W_PH , 0, - DSP_ }, /* MULSA.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20002ebf, &NMD::EXTRV_RS_W , 0, - DSP_ }, /* EXTRV_RS.W */ -}; - - -NMD::Pool NMD::POOL32Axf_2_DSP__24_31[8] = { - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200030bf, &NMD::DPAU_H_QBR , 0, - DSP_ }, /* DPAU.H.QBR */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200032bf, &NMD::DPAQX_SA_W_PH , 0, - DSP_ }, /* DPAQX_SA.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200034bf, &NMD::DPSU_H_QBR , 0, - DSP_ }, /* DPSU.H.QBR */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200036bf, &NMD::DPSQX_SA_W_PH , 0, - DSP_ }, /* DPSQX_SA.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x200038bf, &NMD::EXTPDPV , 0, - DSP_ }, /* EXTPDPV */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20003abf, &NMD::MSUBU_DSP_ , 0, - DSP_ }, /* MSUBU[DSP] */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20003cbf, &NMD::MULSAQ_S_W_PH , 0, - DSP_ }, /* MULSAQ_S.W.PH */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0x20003ebf, &NMD::EXTRV_S_H , 0, - DSP_ }, /* EXTRV_S.H */ -}; - - -NMD::Pool NMD::POOL32Axf_2[4] = { - { pool , POOL32Axf_2_DSP__0_7, 8 , 32, - 0xfc0031ff, 0x200000bf, 0 , 0, - 0x0 }, /* POOL32Axf_2(DSP)_0_7 */ - { pool , POOL32Axf_2_DSP__8_15, 8 , 32, - 0xfc0031ff, 0x200010bf, 0 , 0, - 0x0 }, /* POOL32Axf_2(DSP)_8_15 */ - { pool , POOL32Axf_2_DSP__16_23, 8 , 32, - 0xfc0031ff, 0x200020bf, 0 , 0, - 0x0 }, /* POOL32Axf_2(DSP)_16_23 */ - { pool , POOL32Axf_2_DSP__24_31, 8 , 32, - 0xfc0031ff, 0x200030bf, 0 , 0, - 0x0 }, /* POOL32Axf_2(DSP)_24_31 */ -}; - - -NMD::Pool NMD::POOL32Axf_4[128] = { - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000013f, &NMD::ABSQ_S_QB , 0, - DSP_ }, /* ABSQ_S.QB */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000033f, &NMD::REPLV_PH , 0, - DSP_ }, /* REPLV.PH */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000053f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000073f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000093f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20000b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20000d3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20000f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(7) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000113f, &NMD::ABSQ_S_PH , 0, - DSP_ }, /* ABSQ_S.PH */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000133f, &NMD::REPLV_QB , 0, - DSP_ }, /* REPLV.QB */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000153f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000173f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(11) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000193f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20001b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20001d3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20001f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(15) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000213f, &NMD::ABSQ_S_W , 0, - DSP_ }, /* ABSQ_S.W */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000233f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(17) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000253f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000273f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000293f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20002b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20002d3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20002f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000313f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000333f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000353f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000373f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000393f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20003b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20003d3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20003f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(31) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000413f, &NMD::INSV , 0, - DSP_ }, /* INSV */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000433f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(33) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000453f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(34) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000473f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(35) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000493f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(36) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20004b3f, &NMD::CLO , 0, - XMMS_ }, /* CLO */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20004d3f, &NMD::MFC2 , 0, - CP2_ }, /* MFC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20004f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(39) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000513f, &NMD::PRECEQ_W_PHL , 0, - DSP_ }, /* PRECEQ.W.PHL */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000533f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(41) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000553f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(42) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000573f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(43) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000593f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(44) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20005b3f, &NMD::CLZ , 0, - XMMS_ }, /* CLZ */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20005d3f, &NMD::MTC2 , 0, - CP2_ }, /* MTC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20005f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(47) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000613f, &NMD::PRECEQ_W_PHR , 0, - DSP_ }, /* PRECEQ.W.PHR */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000633f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(49) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000653f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(50) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000673f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(51) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000693f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(52) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20006b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(53) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20006d3f, &NMD::DMFC2 , 0, - CP2_ }, /* DMFC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20006f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(55) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000713f, &NMD::PRECEQU_PH_QBL , 0, - DSP_ }, /* PRECEQU.PH.QBL */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000733f, &NMD::PRECEQU_PH_QBLA , 0, - DSP_ }, /* PRECEQU.PH.QBLA */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000753f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(58) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000773f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(59) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000793f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(60) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20007b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(61) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20007d3f, &NMD::DMTC2 , 0, - CP2_ }, /* DMTC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20007f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(63) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000813f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(64) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000833f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(65) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000853f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(66) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000873f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(67) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000893f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(68) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20008b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(69) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20008d3f, &NMD::MFHC2 , 0, - CP2_ }, /* MFHC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20008f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(71) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000913f, &NMD::PRECEQU_PH_QBR , 0, - DSP_ }, /* PRECEQU.PH.QBR */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000933f, &NMD::PRECEQU_PH_QBRA , 0, - DSP_ }, /* PRECEQU.PH.QBRA */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000953f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(74) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000973f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(75) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000993f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(76) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20009b3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(77) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x20009d3f, &NMD::MTHC2 , 0, - CP2_ }, /* MTHC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20009f3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(79) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000a13f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(80) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000a33f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(81) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000a53f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(82) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000a73f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(83) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000a93f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(84) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ab3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(85) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ad3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(86) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000af3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(87) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000b13f, &NMD::PRECEU_PH_QBL , 0, - DSP_ }, /* PRECEU.PH.QBL */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000b33f, &NMD::PRECEU_PH_QBLA , 0, - DSP_ }, /* PRECEU.PH.QBLA */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000b53f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(90) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000b73f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(91) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000b93f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(92) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000bb3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(93) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000bd3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(94) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000bf3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(95) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c13f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(96) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c33f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(97) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c53f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(98) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c73f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(99) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c93f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(100) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000cb3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(101) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000cd3f, &NMD::CFC2 , 0, - CP2_ }, /* CFC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000cf3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(103) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000d13f, &NMD::PRECEU_PH_QBR , 0, - DSP_ }, /* PRECEU.PH.QBR */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000d33f, &NMD::PRECEU_PH_QBRA , 0, - DSP_ }, /* PRECEU.PH.QBRA */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d53f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(106) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d73f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(107) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d93f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(108) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000db3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(109) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000dd3f, &NMD::CTC2 , 0, - CP2_ }, /* CTC2 */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000df3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(111) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e13f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(112) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e33f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(113) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e53f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(114) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e73f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(115) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e93f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(116) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000eb3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(117) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ed3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(118) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ef3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(119) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000f13f, &NMD::RADDU_W_QB , 0, - DSP_ }, /* RADDU.W.QB */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f33f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(121) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f53f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(122) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f73f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(123) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f93f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(124) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000fb3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(125) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000fd3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(126) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ff3f, 0 , 0, - 0x0 }, /* POOL32Axf_4~*(127) */ -}; - - -NMD::Pool NMD::POOL32Axf_5_group0[32] = { - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000017f, &NMD::TLBGP , 0, - CP0_ | VZ_ | TLB_ }, /* TLBGP */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000037f, &NMD::TLBP , 0, - CP0_ | TLB_ }, /* TLBP */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000057f, &NMD::TLBGINV , 0, - CP0_ | VZ_ | TLB_ | TLBINV_}, /* TLBGINV */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000077f, &NMD::TLBINV , 0, - CP0_ | TLB_ | TLBINV_}, /* TLBINV */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000097f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20000b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20000d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20000f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(7) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000117f, &NMD::TLBGR , 0, - CP0_ | VZ_ | TLB_ }, /* TLBGR */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000137f, &NMD::TLBR , 0, - CP0_ | TLB_ }, /* TLBR */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000157f, &NMD::TLBGINVF , 0, - CP0_ | VZ_ | TLB_ | TLBINV_}, /* TLBGINVF */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000177f, &NMD::TLBINVF , 0, - CP0_ | TLB_ | TLBINV_}, /* TLBINVF */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000197f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20001b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20001d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20001f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(15) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000217f, &NMD::TLBGWI , 0, - CP0_ | VZ_ | TLB_ }, /* TLBGWI */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000237f, &NMD::TLBWI , 0, - CP0_ | TLB_ }, /* TLBWI */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000257f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000277f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000297f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20002b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20002d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20002f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(23) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000317f, &NMD::TLBGWR , 0, - CP0_ | VZ_ | TLB_ }, /* TLBGWR */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000337f, &NMD::TLBWR , 0, - CP0_ | TLB_ }, /* TLBWR */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000357f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000377f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000397f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20003b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20003d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20003f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0~*(31) */ -}; - - -NMD::Pool NMD::POOL32Axf_5_group1[32] = { - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000417f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(0) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000437f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000457f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(2) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000477f, &NMD::DI , 0, - 0x0 }, /* DI */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000497f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20004b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20004d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20004f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000517f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(8) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000537f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(9) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000557f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(10) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000577f, &NMD::EI , 0, - 0x0 }, /* EI */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000597f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20005b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20005d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20005f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(15) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000617f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000637f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(17) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000657f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000677f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000697f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20006b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20006d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20006f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000717f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000737f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000757f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000777f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000797f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20007b7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20007d7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x20007f7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1~*(31) */ -}; - - -NMD::Pool NMD::ERETx[2] = { - { instruction , 0 , 0 , 32, - 0xfc01ffff, 0x2000f37f, &NMD::ERET , 0, - 0x0 }, /* ERET */ - { instruction , 0 , 0 , 32, - 0xfc01ffff, 0x2001f37f, &NMD::ERETNC , 0, - 0x0 }, /* ERETNC */ -}; - - -NMD::Pool NMD::POOL32Axf_5_group3[32] = { - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c17f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(0) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000c37f, &NMD::WAIT , 0, - 0x0 }, /* WAIT */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c57f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c77f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000c97f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000cb7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000cd7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000cf7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d17f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(8) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000d37f, &NMD::IRET , 0, - MCU_ }, /* IRET */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d57f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d77f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(11) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000d97f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000db7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000dd7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000df7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(15) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000e17f, &NMD::RDPGPR , 0, - CP0_ }, /* RDPGPR */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000e37f, &NMD::DERET , 0, - EJTAG_ }, /* DERET */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e57f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e77f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000e97f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000eb7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ed7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ef7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(23) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0x2000f17f, &NMD::WRPGPR , 0, - CP0_ }, /* WRPGPR */ - { pool , ERETx , 2 , 32, - 0xfc00ffff, 0x2000f37f, 0 , 0, - 0x0 }, /* ERETx */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f57f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f77f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000f97f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000fb7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000fd7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0x2000ff7f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3~*(31) */ -}; - - -NMD::Pool NMD::POOL32Axf_5[4] = { - { pool , POOL32Axf_5_group0 , 32 , 32, - 0xfc00c1ff, 0x2000017f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group0 */ - { pool , POOL32Axf_5_group1 , 32 , 32, - 0xfc00c1ff, 0x2000417f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group1 */ - { reserved_block , 0 , 0 , 32, - 0xfc00c1ff, 0x2000817f, 0 , 0, - 0x0 }, /* POOL32Axf_5~*(2) */ - { pool , POOL32Axf_5_group3 , 32 , 32, - 0xfc00c1ff, 0x2000c17f, 0 , 0, - 0x0 }, /* POOL32Axf_5_group3 */ -}; - - -NMD::Pool NMD::SHRA__R__QB[2] = { - { instruction , 0 , 0 , 32, - 0xfc001fff, 0x200001ff, &NMD::SHRA_QB , 0, - DSP_ }, /* SHRA.QB */ - { instruction , 0 , 0 , 32, - 0xfc001fff, 0x200011ff, &NMD::SHRA_R_QB , 0, - DSP_ }, /* SHRA_R.QB */ -}; - - -NMD::Pool NMD::POOL32Axf_7[8] = { - { pool , SHRA__R__QB , 2 , 32, - 0xfc000fff, 0x200001ff, 0 , 0, - 0x0 }, /* SHRA[_R].QB */ - { instruction , 0 , 0 , 32, - 0xfc000fff, 0x200003ff, &NMD::SHRL_PH , 0, - DSP_ }, /* SHRL.PH */ - { instruction , 0 , 0 , 32, - 0xfc000fff, 0x200005ff, &NMD::REPL_QB , 0, - DSP_ }, /* REPL.QB */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x200007ff, 0 , 0, - 0x0 }, /* POOL32Axf_7~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x200009ff, 0 , 0, - 0x0 }, /* POOL32Axf_7~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x20000bff, 0 , 0, - 0x0 }, /* POOL32Axf_7~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x20000dff, 0 , 0, - 0x0 }, /* POOL32Axf_7~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc000fff, 0x20000fff, 0 , 0, - 0x0 }, /* POOL32Axf_7~*(7) */ -}; - - -NMD::Pool NMD::POOL32Axf[8] = { - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0x2000003f, 0 , 0, - 0x0 }, /* POOL32Axf~*(0) */ - { pool , POOL32Axf_1 , 8 , 32, - 0xfc0001ff, 0x2000007f, 0 , 0, - 0x0 }, /* POOL32Axf_1 */ - { pool , POOL32Axf_2 , 4 , 32, - 0xfc0001ff, 0x200000bf, 0 , 0, - 0x0 }, /* POOL32Axf_2 */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0x200000ff, 0 , 0, - 0x0 }, /* POOL32Axf~*(3) */ - { pool , POOL32Axf_4 , 128 , 32, - 0xfc0001ff, 0x2000013f, 0 , 0, - 0x0 }, /* POOL32Axf_4 */ - { pool , POOL32Axf_5 , 4 , 32, - 0xfc0001ff, 0x2000017f, 0 , 0, - 0x0 }, /* POOL32Axf_5 */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0x200001bf, 0 , 0, - 0x0 }, /* POOL32Axf~*(6) */ - { pool , POOL32Axf_7 , 8 , 32, - 0xfc0001ff, 0x200001ff, 0 , 0, - 0x0 }, /* POOL32Axf_7 */ -}; - - -NMD::Pool NMD::_POOL32A7[8] = { - { pool , P_LSX , 2 , 32, - 0xfc00003f, 0x20000007, 0 , 0, - 0x0 }, /* P.LSX */ - { instruction , 0 , 0 , 32, - 0xfc00003f, 0x2000000f, &NMD::LSA , 0, - 0x0 }, /* LSA */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0x20000017, 0 , 0, - 0x0 }, /* _POOL32A7~*(2) */ - { instruction , 0 , 0 , 32, - 0xfc00003f, 0x2000001f, &NMD::EXTW , 0, - 0x0 }, /* EXTW */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0x20000027, 0 , 0, - 0x0 }, /* _POOL32A7~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0x2000002f, 0 , 0, - 0x0 }, /* _POOL32A7~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0x20000037, 0 , 0, - 0x0 }, /* _POOL32A7~*(6) */ - { pool , POOL32Axf , 8 , 32, - 0xfc00003f, 0x2000003f, 0 , 0, - 0x0 }, /* POOL32Axf */ -}; - - -NMD::Pool NMD::P32A[8] = { - { pool , _POOL32A0 , 128 , 32, - 0xfc000007, 0x20000000, 0 , 0, - 0x0 }, /* _POOL32A0 */ - { instruction , 0 , 0 , 32, - 0xfc000007, 0x20000001, &NMD::SPECIAL2 , 0, - UDI_ }, /* SPECIAL2 */ - { instruction , 0 , 0 , 32, - 0xfc000007, 0x20000002, &NMD::COP2_1 , 0, - CP2_ }, /* COP2_1 */ - { instruction , 0 , 0 , 32, - 0xfc000007, 0x20000003, &NMD::UDI , 0, - UDI_ }, /* UDI */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0x20000004, 0 , 0, - 0x0 }, /* P32A~*(4) */ - { pool , _POOL32A5 , 128 , 32, - 0xfc000007, 0x20000005, 0 , 0, - 0x0 }, /* _POOL32A5 */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0x20000006, 0 , 0, - 0x0 }, /* P32A~*(6) */ - { pool , _POOL32A7 , 8 , 32, - 0xfc000007, 0x20000007, 0 , 0, - 0x0 }, /* _POOL32A7 */ -}; - - -NMD::Pool NMD::P_GP_D[2] = { - { instruction , 0 , 0 , 32, - 0xfc000007, 0x40000001, &NMD::LD_GP_ , 0, - MIPS64_ }, /* LD[GP] */ - { instruction , 0 , 0 , 32, - 0xfc000007, 0x40000005, &NMD::SD_GP_ , 0, - MIPS64_ }, /* SD[GP] */ -}; - - -NMD::Pool NMD::P_GP_W[4] = { - { instruction , 0 , 0 , 32, - 0xfc000003, 0x40000000, &NMD::ADDIU_GP_W_ , 0, - 0x0 }, /* ADDIU[GP.W] */ - { pool , P_GP_D , 2 , 32, - 0xfc000003, 0x40000001, 0 , 0, - 0x0 }, /* P.GP.D */ - { instruction , 0 , 0 , 32, - 0xfc000003, 0x40000002, &NMD::LW_GP_ , 0, - 0x0 }, /* LW[GP] */ - { instruction , 0 , 0 , 32, - 0xfc000003, 0x40000003, &NMD::SW_GP_ , 0, - 0x0 }, /* SW[GP] */ -}; - - -NMD::Pool NMD::POOL48I[32] = { - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600000000000ull, &NMD::LI_48_ , 0, - XMMS_ }, /* LI[48] */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600100000000ull, &NMD::ADDIU_48_ , 0, - XMMS_ }, /* ADDIU[48] */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600200000000ull, &NMD::ADDIU_GP48_ , 0, - XMMS_ }, /* ADDIU[GP48] */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600300000000ull, &NMD::ADDIUPC_48_ , 0, - XMMS_ }, /* ADDIUPC[48] */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600400000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(4) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600500000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(5) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600600000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(6) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600700000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(7) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600800000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(8) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600900000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(9) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600a00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(10) */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600b00000000ull, &NMD::LWPC_48_ , 0, - XMMS_ }, /* LWPC[48] */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600c00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(12) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600d00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(13) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600e00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(14) */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x600f00000000ull, &NMD::SWPC_48_ , 0, - XMMS_ }, /* SWPC[48] */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601000000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(16) */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601100000000ull, &NMD::DADDIU_48_ , 0, - MIPS64_ }, /* DADDIU[48] */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601200000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(18) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601300000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(19) */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601400000000ull, &NMD::DLUI_48_ , 0, - MIPS64_ }, /* DLUI[48] */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601500000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(21) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601600000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(22) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601700000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(23) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601800000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(24) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601900000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(25) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601a00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(26) */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601b00000000ull, &NMD::LDPC_48_ , 0, - MIPS64_ }, /* LDPC[48] */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601c00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(28) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601d00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(29) */ - { reserved_block , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601e00000000ull, 0 , 0, - 0x0 }, /* POOL48I~*(30) */ - { instruction , 0 , 0 , 48, - 0xfc1f00000000ull, 0x601f00000000ull, &NMD::SDPC_48_ , 0, - MIPS64_ }, /* SDPC[48] */ -}; - - -NMD::Pool NMD::PP_SR[4] = { - { instruction , 0 , 0 , 32, - 0xfc10f003, 0x80003000, &NMD::SAVE_32_ , 0, - 0x0 }, /* SAVE[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc10f003, 0x80003001, 0 , 0, - 0x0 }, /* PP.SR~*(1) */ - { instruction , 0 , 0 , 32, - 0xfc10f003, 0x80003002, &NMD::RESTORE_32_ , 0, - 0x0 }, /* RESTORE[32] */ - { return_instruction , 0 , 0 , 32, - 0xfc10f003, 0x80003003, &NMD::RESTORE_JRC_32_ , 0, - 0x0 }, /* RESTORE.JRC[32] */ -}; - - -NMD::Pool NMD::P_SR_F[8] = { - { instruction , 0 , 0 , 32, - 0xfc10f007, 0x80103000, &NMD::SAVEF , 0, - CP1_ }, /* SAVEF */ - { instruction , 0 , 0 , 32, - 0xfc10f007, 0x80103001, &NMD::RESTOREF , 0, - CP1_ }, /* RESTOREF */ - { reserved_block , 0 , 0 , 32, - 0xfc10f007, 0x80103002, 0 , 0, - 0x0 }, /* P.SR.F~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc10f007, 0x80103003, 0 , 0, - 0x0 }, /* P.SR.F~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc10f007, 0x80103004, 0 , 0, - 0x0 }, /* P.SR.F~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc10f007, 0x80103005, 0 , 0, - 0x0 }, /* P.SR.F~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc10f007, 0x80103006, 0 , 0, - 0x0 }, /* P.SR.F~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc10f007, 0x80103007, 0 , 0, - 0x0 }, /* P.SR.F~*(7) */ -}; - - -NMD::Pool NMD::P_SR[2] = { - { pool , PP_SR , 4 , 32, - 0xfc10f000, 0x80003000, 0 , 0, - 0x0 }, /* PP.SR */ - { pool , P_SR_F , 8 , 32, - 0xfc10f000, 0x80103000, 0 , 0, - 0x0 }, /* P.SR.F */ -}; - - -NMD::Pool NMD::P_SLL[5] = { - { instruction , 0 , 0 , 32, - 0xffe0f1ff, 0x8000c000, &NMD::NOP_32_ , 0, - 0x0 }, /* NOP[32] */ - { instruction , 0 , 0 , 32, - 0xffe0f1ff, 0x8000c003, &NMD::EHB , 0, - 0x0 }, /* EHB */ - { instruction , 0 , 0 , 32, - 0xffe0f1ff, 0x8000c005, &NMD::PAUSE , 0, - 0x0 }, /* PAUSE */ - { instruction , 0 , 0 , 32, - 0xffe0f1ff, 0x8000c006, &NMD::SYNC , 0, - 0x0 }, /* SYNC */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c000, &NMD::SLL_32_ , 0, - 0x0 }, /* SLL[32] */ -}; - - -NMD::Pool NMD::P_SHIFT[16] = { - { pool , P_SLL , 5 , 32, - 0xfc00f1e0, 0x8000c000, 0 , 0, - 0x0 }, /* P.SLL */ - { reserved_block , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c020, 0 , 0, - 0x0 }, /* P.SHIFT~*(1) */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c040, &NMD::SRL_32_ , 0, - 0x0 }, /* SRL[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c060, 0 , 0, - 0x0 }, /* P.SHIFT~*(3) */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c080, &NMD::SRA , 0, - 0x0 }, /* SRA */ - { reserved_block , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c0a0, 0 , 0, - 0x0 }, /* P.SHIFT~*(5) */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c0c0, &NMD::ROTR , 0, - 0x0 }, /* ROTR */ - { reserved_block , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c0e0, 0 , 0, - 0x0 }, /* P.SHIFT~*(7) */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c100, &NMD::DSLL , 0, - MIPS64_ }, /* DSLL */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c120, &NMD::DSLL32 , 0, - MIPS64_ }, /* DSLL32 */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c140, &NMD::DSRL , 0, - MIPS64_ }, /* DSRL */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c160, &NMD::DSRL32 , 0, - MIPS64_ }, /* DSRL32 */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c180, &NMD::DSRA , 0, - MIPS64_ }, /* DSRA */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c1a0, &NMD::DSRA32 , 0, - MIPS64_ }, /* DSRA32 */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c1c0, &NMD::DROTR , 0, - MIPS64_ }, /* DROTR */ - { instruction , 0 , 0 , 32, - 0xfc00f1e0, 0x8000c1e0, &NMD::DROTR32 , 0, - MIPS64_ }, /* DROTR32 */ -}; - - -NMD::Pool NMD::P_ROTX[4] = { - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000d000, &NMD::ROTX , 0, - XMMS_ }, /* ROTX */ - { reserved_block , 0 , 0 , 32, - 0xfc00f820, 0x8000d020, 0 , 0, - 0x0 }, /* P.ROTX~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f820, 0x8000d800, 0 , 0, - 0x0 }, /* P.ROTX~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f820, 0x8000d820, 0 , 0, - 0x0 }, /* P.ROTX~*(3) */ -}; - - -NMD::Pool NMD::P_INS[4] = { - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000e000, &NMD::INS , 0, - XMMS_ }, /* INS */ - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000e020, &NMD::DINSU , 0, - MIPS64_ }, /* DINSU */ - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000e800, &NMD::DINSM , 0, - MIPS64_ }, /* DINSM */ - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000e820, &NMD::DINS , 0, - MIPS64_ }, /* DINS */ -}; - - -NMD::Pool NMD::P_EXT[4] = { - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000f000, &NMD::EXT , 0, - XMMS_ }, /* EXT */ - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000f020, &NMD::DEXTU , 0, - MIPS64_ }, /* DEXTU */ - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000f800, &NMD::DEXTM , 0, - MIPS64_ }, /* DEXTM */ - { instruction , 0 , 0 , 32, - 0xfc00f820, 0x8000f820, &NMD::DEXT , 0, - MIPS64_ }, /* DEXT */ -}; - - -NMD::Pool NMD::P_U12[16] = { - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80000000, &NMD::ORI , 0, - 0x0 }, /* ORI */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80001000, &NMD::XORI , 0, - 0x0 }, /* XORI */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80002000, &NMD::ANDI_32_ , 0, - 0x0 }, /* ANDI[32] */ - { pool , P_SR , 2 , 32, - 0xfc00f000, 0x80003000, 0 , 0, - 0x0 }, /* P.SR */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80004000, &NMD::SLTI , 0, - 0x0 }, /* SLTI */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80005000, &NMD::SLTIU , 0, - 0x0 }, /* SLTIU */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80006000, &NMD::SEQI , 0, - 0x0 }, /* SEQI */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x80007000, 0 , 0, - 0x0 }, /* P.U12~*(7) */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80008000, &NMD::ADDIU_NEG_ , 0, - 0x0 }, /* ADDIU[NEG] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x80009000, &NMD::DADDIU_U12_ , 0, - MIPS64_ }, /* DADDIU[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8000a000, &NMD::DADDIU_NEG_ , 0, - MIPS64_ }, /* DADDIU[NEG] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8000b000, &NMD::DROTX , 0, - MIPS64_ }, /* DROTX */ - { pool , P_SHIFT , 16 , 32, - 0xfc00f000, 0x8000c000, 0 , 0, - 0x0 }, /* P.SHIFT */ - { pool , P_ROTX , 4 , 32, - 0xfc00f000, 0x8000d000, 0 , 0, - 0x0 }, /* P.ROTX */ - { pool , P_INS , 4 , 32, - 0xfc00f000, 0x8000e000, 0 , 0, - 0x0 }, /* P.INS */ - { pool , P_EXT , 4 , 32, - 0xfc00f000, 0x8000f000, 0 , 0, - 0x0 }, /* P.EXT */ -}; - - -NMD::Pool NMD::RINT_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000020, &NMD::RINT_S , 0, - CP1_ }, /* RINT.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000220, &NMD::RINT_D , 0, - CP1_ }, /* RINT.D */ -}; - - -NMD::Pool NMD::ADD_fmt0[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000030, &NMD::ADD_S , 0, - CP1_ }, /* ADD.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa0000230, 0 , 0, - CP1_ }, /* ADD.fmt0~*(1) */ -}; - - -NMD::Pool NMD::SELEQZ_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000038, &NMD::SELEQZ_S , 0, - CP1_ }, /* SELEQZ.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000238, &NMD::SELEQZ_D , 0, - CP1_ }, /* SELEQZ.D */ -}; - - -NMD::Pool NMD::CLASS_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000060, &NMD::CLASS_S , 0, - CP1_ }, /* CLASS.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000260, &NMD::CLASS_D , 0, - CP1_ }, /* CLASS.D */ -}; - - -NMD::Pool NMD::SUB_fmt0[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000070, &NMD::SUB_S , 0, - CP1_ }, /* SUB.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa0000270, 0 , 0, - CP1_ }, /* SUB.fmt0~*(1) */ -}; - - -NMD::Pool NMD::SELNEZ_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000078, &NMD::SELNEZ_S , 0, - CP1_ }, /* SELNEZ.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000278, &NMD::SELNEZ_D , 0, - CP1_ }, /* SELNEZ.D */ -}; - - -NMD::Pool NMD::MUL_fmt0[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00000b0, &NMD::MUL_S , 0, - CP1_ }, /* MUL.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa00002b0, 0 , 0, - CP1_ }, /* MUL.fmt0~*(1) */ -}; - - -NMD::Pool NMD::SEL_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00000b8, &NMD::SEL_S , 0, - CP1_ }, /* SEL.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00002b8, &NMD::SEL_D , 0, - CP1_ }, /* SEL.D */ -}; - - -NMD::Pool NMD::DIV_fmt0[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00000f0, &NMD::DIV_S , 0, - CP1_ }, /* DIV.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa00002f0, 0 , 0, - CP1_ }, /* DIV.fmt0~*(1) */ -}; - - -NMD::Pool NMD::ADD_fmt1[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000130, &NMD::ADD_D , 0, - CP1_ }, /* ADD.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa0000330, 0 , 0, - CP1_ }, /* ADD.fmt1~*(1) */ -}; - - -NMD::Pool NMD::SUB_fmt1[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa0000170, &NMD::SUB_D , 0, - CP1_ }, /* SUB.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa0000370, 0 , 0, - CP1_ }, /* SUB.fmt1~*(1) */ -}; - - -NMD::Pool NMD::MUL_fmt1[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00001b0, &NMD::MUL_D , 0, - CP1_ }, /* MUL.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa00003b0, 0 , 0, - CP1_ }, /* MUL.fmt1~*(1) */ -}; - - -NMD::Pool NMD::MADDF_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00001b8, &NMD::MADDF_S , 0, - CP1_ }, /* MADDF.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00003b8, &NMD::MADDF_D , 0, - CP1_ }, /* MADDF.D */ -}; - - -NMD::Pool NMD::DIV_fmt1[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00001f0, &NMD::DIV_D , 0, - CP1_ }, /* DIV.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0003ff, 0xa00003f0, 0 , 0, - CP1_ }, /* DIV.fmt1~*(1) */ -}; - - -NMD::Pool NMD::MSUBF_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00001f8, &NMD::MSUBF_S , 0, - CP1_ }, /* MSUBF.S */ - { instruction , 0 , 0 , 32, - 0xfc0003ff, 0xa00003f8, &NMD::MSUBF_D , 0, - CP1_ }, /* MSUBF.D */ -}; - - -NMD::Pool NMD::POOL32F_0[64] = { - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000000, 0 , 0, - CP1_ }, /* POOL32F_0~*(0) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000008, 0 , 0, - CP1_ }, /* POOL32F_0~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000010, 0 , 0, - CP1_ }, /* POOL32F_0~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000018, 0 , 0, - CP1_ }, /* POOL32F_0~*(3) */ - { pool , RINT_fmt , 2 , 32, - 0xfc0001ff, 0xa0000020, 0 , 0, - CP1_ }, /* RINT.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000028, 0 , 0, - CP1_ }, /* POOL32F_0~*(5) */ - { pool , ADD_fmt0 , 2 , 32, - 0xfc0001ff, 0xa0000030, 0 , 0, - CP1_ }, /* ADD.fmt0 */ - { pool , SELEQZ_fmt , 2 , 32, - 0xfc0001ff, 0xa0000038, 0 , 0, - CP1_ }, /* SELEQZ.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000040, 0 , 0, - CP1_ }, /* POOL32F_0~*(8) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000048, 0 , 0, - CP1_ }, /* POOL32F_0~*(9) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000050, 0 , 0, - CP1_ }, /* POOL32F_0~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000058, 0 , 0, - CP1_ }, /* POOL32F_0~*(11) */ - { pool , CLASS_fmt , 2 , 32, - 0xfc0001ff, 0xa0000060, 0 , 0, - CP1_ }, /* CLASS.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000068, 0 , 0, - CP1_ }, /* POOL32F_0~*(13) */ - { pool , SUB_fmt0 , 2 , 32, - 0xfc0001ff, 0xa0000070, 0 , 0, - CP1_ }, /* SUB.fmt0 */ - { pool , SELNEZ_fmt , 2 , 32, - 0xfc0001ff, 0xa0000078, 0 , 0, - CP1_ }, /* SELNEZ.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000080, 0 , 0, - CP1_ }, /* POOL32F_0~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000088, 0 , 0, - CP1_ }, /* POOL32F_0~*(17) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000090, 0 , 0, - CP1_ }, /* POOL32F_0~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000098, 0 , 0, - CP1_ }, /* POOL32F_0~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000a0, 0 , 0, - CP1_ }, /* POOL32F_0~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000a8, 0 , 0, - CP1_ }, /* POOL32F_0~*(21) */ - { pool , MUL_fmt0 , 2 , 32, - 0xfc0001ff, 0xa00000b0, 0 , 0, - CP1_ }, /* MUL.fmt0 */ - { pool , SEL_fmt , 2 , 32, - 0xfc0001ff, 0xa00000b8, 0 , 0, - CP1_ }, /* SEL.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000c0, 0 , 0, - CP1_ }, /* POOL32F_0~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000c8, 0 , 0, - CP1_ }, /* POOL32F_0~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000d0, 0 , 0, - CP1_ }, /* POOL32F_0~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000d8, 0 , 0, - CP1_ }, /* POOL32F_0~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000e0, 0 , 0, - CP1_ }, /* POOL32F_0~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000e8, 0 , 0, - CP1_ }, /* POOL32F_0~*(29) */ - { pool , DIV_fmt0 , 2 , 32, - 0xfc0001ff, 0xa00000f0, 0 , 0, - CP1_ }, /* DIV.fmt0 */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00000f8, 0 , 0, - CP1_ }, /* POOL32F_0~*(31) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000100, 0 , 0, - CP1_ }, /* POOL32F_0~*(32) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000108, 0 , 0, - CP1_ }, /* POOL32F_0~*(33) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000110, 0 , 0, - CP1_ }, /* POOL32F_0~*(34) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000118, 0 , 0, - CP1_ }, /* POOL32F_0~*(35) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000120, 0 , 0, - CP1_ }, /* POOL32F_0~*(36) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000128, 0 , 0, - CP1_ }, /* POOL32F_0~*(37) */ - { pool , ADD_fmt1 , 2 , 32, - 0xfc0001ff, 0xa0000130, 0 , 0, - CP1_ }, /* ADD.fmt1 */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000138, 0 , 0, - CP1_ }, /* POOL32F_0~*(39) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000140, 0 , 0, - CP1_ }, /* POOL32F_0~*(40) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000148, 0 , 0, - CP1_ }, /* POOL32F_0~*(41) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000150, 0 , 0, - CP1_ }, /* POOL32F_0~*(42) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000158, 0 , 0, - CP1_ }, /* POOL32F_0~*(43) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000160, 0 , 0, - CP1_ }, /* POOL32F_0~*(44) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000168, 0 , 0, - CP1_ }, /* POOL32F_0~*(45) */ - { pool , SUB_fmt1 , 2 , 32, - 0xfc0001ff, 0xa0000170, 0 , 0, - CP1_ }, /* SUB.fmt1 */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000178, 0 , 0, - CP1_ }, /* POOL32F_0~*(47) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000180, 0 , 0, - CP1_ }, /* POOL32F_0~*(48) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000188, 0 , 0, - CP1_ }, /* POOL32F_0~*(49) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000190, 0 , 0, - CP1_ }, /* POOL32F_0~*(50) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa0000198, 0 , 0, - CP1_ }, /* POOL32F_0~*(51) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001a0, 0 , 0, - CP1_ }, /* POOL32F_0~*(52) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001a8, 0 , 0, - CP1_ }, /* POOL32F_0~*(53) */ - { pool , MUL_fmt1 , 2 , 32, - 0xfc0001ff, 0xa00001b0, 0 , 0, - CP1_ }, /* MUL.fmt1 */ - { pool , MADDF_fmt , 2 , 32, - 0xfc0001ff, 0xa00001b8, 0 , 0, - CP1_ }, /* MADDF.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001c0, 0 , 0, - CP1_ }, /* POOL32F_0~*(56) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001c8, 0 , 0, - CP1_ }, /* POOL32F_0~*(57) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001d0, 0 , 0, - CP1_ }, /* POOL32F_0~*(58) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001d8, 0 , 0, - CP1_ }, /* POOL32F_0~*(59) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001e0, 0 , 0, - CP1_ }, /* POOL32F_0~*(60) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xa00001e8, 0 , 0, - CP1_ }, /* POOL32F_0~*(61) */ - { pool , DIV_fmt1 , 2 , 32, - 0xfc0001ff, 0xa00001f0, 0 , 0, - CP1_ }, /* DIV.fmt1 */ - { pool , MSUBF_fmt , 2 , 32, - 0xfc0001ff, 0xa00001f8, 0 , 0, - CP1_ }, /* MSUBF.fmt */ -}; - - -NMD::Pool NMD::MIN_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa0000003, &NMD::MIN_S , 0, - CP1_ }, /* MIN.S */ - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa0000203, &NMD::MIN_D , 0, - CP1_ }, /* MIN.D */ -}; - - -NMD::Pool NMD::MAX_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa000000b, &NMD::MAX_S , 0, - CP1_ }, /* MAX.S */ - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa000020b, &NMD::MAX_D , 0, - CP1_ }, /* MAX.D */ -}; - - -NMD::Pool NMD::MINA_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa0000023, &NMD::MINA_S , 0, - CP1_ }, /* MINA.S */ - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa0000223, &NMD::MINA_D , 0, - CP1_ }, /* MINA.D */ -}; - - -NMD::Pool NMD::MAXA_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa000002b, &NMD::MAXA_S , 0, - CP1_ }, /* MAXA.S */ - { instruction , 0 , 0 , 32, - 0xfc00023f, 0xa000022b, &NMD::MAXA_D , 0, - CP1_ }, /* MAXA.D */ -}; - - -NMD::Pool NMD::CVT_L_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000013b, &NMD::CVT_L_S , 0, - CP1_ }, /* CVT.L.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000413b, &NMD::CVT_L_D , 0, - CP1_ }, /* CVT.L.D */ -}; - - -NMD::Pool NMD::RSQRT_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000023b, &NMD::RSQRT_S , 0, - CP1_ }, /* RSQRT.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000423b, &NMD::RSQRT_D , 0, - CP1_ }, /* RSQRT.D */ -}; - - -NMD::Pool NMD::FLOOR_L_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000033b, &NMD::FLOOR_L_S , 0, - CP1_ }, /* FLOOR.L.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000433b, &NMD::FLOOR_L_D , 0, - CP1_ }, /* FLOOR.L.D */ -}; - - -NMD::Pool NMD::CVT_W_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000093b, &NMD::CVT_W_S , 0, - CP1_ }, /* CVT.W.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000493b, &NMD::CVT_W_D , 0, - CP1_ }, /* CVT.W.D */ -}; - - -NMD::Pool NMD::SQRT_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0000a3b, &NMD::SQRT_S , 0, - CP1_ }, /* SQRT.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0004a3b, &NMD::SQRT_D , 0, - CP1_ }, /* SQRT.D */ -}; - - -NMD::Pool NMD::FLOOR_W_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0000b3b, &NMD::FLOOR_W_S , 0, - CP1_ }, /* FLOOR.W.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0004b3b, &NMD::FLOOR_W_D , 0, - CP1_ }, /* FLOOR.W.D */ -}; - - -NMD::Pool NMD::RECIP_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000123b, &NMD::RECIP_S , 0, - CP1_ }, /* RECIP.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000523b, &NMD::RECIP_D , 0, - CP1_ }, /* RECIP.D */ -}; - - -NMD::Pool NMD::CEIL_L_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000133b, &NMD::CEIL_L_S , 0, - CP1_ }, /* CEIL.L.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000533b, &NMD::CEIL_L_D , 0, - CP1_ }, /* CEIL.L.D */ -}; - - -NMD::Pool NMD::CEIL_W_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0001b3b, &NMD::CEIL_W_S , 0, - CP1_ }, /* CEIL.W.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0005b3b, &NMD::CEIL_W_D , 0, - CP1_ }, /* CEIL.W.D */ -}; - - -NMD::Pool NMD::TRUNC_L_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000233b, &NMD::TRUNC_L_S , 0, - CP1_ }, /* TRUNC.L.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000633b, &NMD::TRUNC_L_D , 0, - CP1_ }, /* TRUNC.L.D */ -}; - - -NMD::Pool NMD::TRUNC_W_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0002b3b, &NMD::TRUNC_W_S , 0, - CP1_ }, /* TRUNC.W.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0006b3b, &NMD::TRUNC_W_D , 0, - CP1_ }, /* TRUNC.W.D */ -}; - - -NMD::Pool NMD::ROUND_L_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000333b, &NMD::ROUND_L_S , 0, - CP1_ }, /* ROUND.L.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000733b, &NMD::ROUND_L_D , 0, - CP1_ }, /* ROUND.L.D */ -}; - - -NMD::Pool NMD::ROUND_W_fmt[2] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0003b3b, &NMD::ROUND_W_S , 0, - CP1_ }, /* ROUND.W.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0007b3b, &NMD::ROUND_W_D , 0, - CP1_ }, /* ROUND.W.D */ -}; - - -NMD::Pool NMD::POOL32Fxf_0[64] = { - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000003b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(0) */ - { pool , CVT_L_fmt , 2 , 32, - 0xfc003fff, 0xa000013b, 0 , 0, - CP1_ }, /* CVT.L.fmt */ - { pool , RSQRT_fmt , 2 , 32, - 0xfc003fff, 0xa000023b, 0 , 0, - CP1_ }, /* RSQRT.fmt */ - { pool , FLOOR_L_fmt , 2 , 32, - 0xfc003fff, 0xa000033b, 0 , 0, - CP1_ }, /* FLOOR.L.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000043b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000053b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000063b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000073b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000083b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(8) */ - { pool , CVT_W_fmt , 2 , 32, - 0xfc003fff, 0xa000093b, 0 , 0, - CP1_ }, /* CVT.W.fmt */ - { pool , SQRT_fmt , 2 , 32, - 0xfc003fff, 0xa0000a3b, 0 , 0, - CP1_ }, /* SQRT.fmt */ - { pool , FLOOR_W_fmt , 2 , 32, - 0xfc003fff, 0xa0000b3b, 0 , 0, - CP1_ }, /* FLOOR.W.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0000c3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0000d3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0000e3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0000f3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(15) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000103b, &NMD::CFC1 , 0, - CP1_ }, /* CFC1 */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000113b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(17) */ - { pool , RECIP_fmt , 2 , 32, - 0xfc003fff, 0xa000123b, 0 , 0, - CP1_ }, /* RECIP.fmt */ - { pool , CEIL_L_fmt , 2 , 32, - 0xfc003fff, 0xa000133b, 0 , 0, - CP1_ }, /* CEIL.L.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000143b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000153b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000163b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000173b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(23) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000183b, &NMD::CTC1 , 0, - CP1_ }, /* CTC1 */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000193b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0001a3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(26) */ - { pool , CEIL_W_fmt , 2 , 32, - 0xfc003fff, 0xa0001b3b, 0 , 0, - CP1_ }, /* CEIL.W.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0001c3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0001d3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0001e3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0001f3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(31) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000203b, &NMD::MFC1 , 0, - CP1_ }, /* MFC1 */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000213b, &NMD::CVT_S_PL , 0, - CP1_ }, /* CVT.S.PL */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000223b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(34) */ - { pool , TRUNC_L_fmt , 2 , 32, - 0xfc003fff, 0xa000233b, 0 , 0, - CP1_ }, /* TRUNC.L.fmt */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000243b, &NMD::DMFC1 , 0, - CP1_ | MIPS64_ }, /* DMFC1 */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000253b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(37) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000263b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(38) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000273b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(39) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000283b, &NMD::MTC1 , 0, - CP1_ }, /* MTC1 */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000293b, &NMD::CVT_S_PU , 0, - CP1_ }, /* CVT.S.PU */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0002a3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(42) */ - { pool , TRUNC_W_fmt , 2 , 32, - 0xfc003fff, 0xa0002b3b, 0 , 0, - CP1_ }, /* TRUNC.W.fmt */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa0002c3b, &NMD::DMTC1 , 0, - CP1_ | MIPS64_ }, /* DMTC1 */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0002d3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(45) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0002e3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(46) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0002f3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(47) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000303b, &NMD::MFHC1 , 0, - CP1_ }, /* MFHC1 */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000313b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(49) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000323b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(50) */ - { pool , ROUND_L_fmt , 2 , 32, - 0xfc003fff, 0xa000333b, 0 , 0, - CP1_ }, /* ROUND.L.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000343b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(52) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000353b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(53) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000363b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(54) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000373b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(55) */ - { instruction , 0 , 0 , 32, - 0xfc003fff, 0xa000383b, &NMD::MTHC1 , 0, - CP1_ }, /* MTHC1 */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa000393b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(57) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0003a3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(58) */ - { pool , ROUND_W_fmt , 2 , 32, - 0xfc003fff, 0xa0003b3b, 0 , 0, - CP1_ }, /* ROUND.W.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0003c3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(60) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0003d3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(61) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0003e3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(62) */ - { reserved_block , 0 , 0 , 32, - 0xfc003fff, 0xa0003f3b, 0 , 0, - CP1_ }, /* POOL32Fxf_0~*(63) */ -}; - - -NMD::Pool NMD::MOV_fmt[4] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000007b, &NMD::MOV_S , 0, - CP1_ }, /* MOV.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000207b, &NMD::MOV_D , 0, - CP1_ }, /* MOV.D */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa000407b, 0 , 0, - CP1_ }, /* MOV.fmt~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa000607b, 0 , 0, - CP1_ }, /* MOV.fmt~*(3) */ -}; - - -NMD::Pool NMD::ABS_fmt[4] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000037b, &NMD::ABS_S , 0, - CP1_ }, /* ABS.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000237b, &NMD::ABS_D , 0, - CP1_ }, /* ABS.D */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa000437b, 0 , 0, - CP1_ }, /* ABS.fmt~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa000637b, 0 , 0, - CP1_ }, /* ABS.fmt~*(3) */ -}; - - -NMD::Pool NMD::NEG_fmt[4] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0000b7b, &NMD::NEG_S , 0, - CP1_ }, /* NEG.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0002b7b, &NMD::NEG_D , 0, - CP1_ }, /* NEG.D */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa0004b7b, 0 , 0, - CP1_ }, /* NEG.fmt~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa0006b7b, 0 , 0, - CP1_ }, /* NEG.fmt~*(3) */ -}; - - -NMD::Pool NMD::CVT_D_fmt[4] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000137b, &NMD::CVT_D_S , 0, - CP1_ }, /* CVT.D.S */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000337b, &NMD::CVT_D_W , 0, - CP1_ }, /* CVT.D.W */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa000537b, &NMD::CVT_D_L , 0, - CP1_ }, /* CVT.D.L */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa000737b, 0 , 0, - CP1_ }, /* CVT.D.fmt~*(3) */ -}; - - -NMD::Pool NMD::CVT_S_fmt[4] = { - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0001b7b, &NMD::CVT_S_D , 0, - CP1_ }, /* CVT.S.D */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0003b7b, &NMD::CVT_S_W , 0, - CP1_ }, /* CVT.S.W */ - { instruction , 0 , 0 , 32, - 0xfc007fff, 0xa0005b7b, &NMD::CVT_S_L , 0, - CP1_ }, /* CVT.S.L */ - { reserved_block , 0 , 0 , 32, - 0xfc007fff, 0xa0007b7b, 0 , 0, - CP1_ }, /* CVT.S.fmt~*(3) */ -}; - - -NMD::Pool NMD::POOL32Fxf_1[32] = { - { pool , MOV_fmt , 4 , 32, - 0xfc001fff, 0xa000007b, 0 , 0, - CP1_ }, /* MOV.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000017b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000027b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(2) */ - { pool , ABS_fmt , 4 , 32, - 0xfc001fff, 0xa000037b, 0 , 0, - CP1_ }, /* ABS.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000047b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000057b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000067b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000077b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000087b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(8) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000097b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(9) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0000a7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(10) */ - { pool , NEG_fmt , 4 , 32, - 0xfc001fff, 0xa0000b7b, 0 , 0, - CP1_ }, /* NEG.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0000c7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0000d7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0000e7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0000f7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(15) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000107b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000117b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(17) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000127b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(18) */ - { pool , CVT_D_fmt , 4 , 32, - 0xfc001fff, 0xa000137b, 0 , 0, - CP1_ }, /* CVT.D.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000147b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000157b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000167b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000177b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000187b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa000197b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0001a7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(26) */ - { pool , CVT_S_fmt , 4 , 32, - 0xfc001fff, 0xa0001b7b, 0 , 0, - CP1_ }, /* CVT.S.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0001c7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0001d7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0001e7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc001fff, 0xa0001f7b, 0 , 0, - CP1_ }, /* POOL32Fxf_1~*(31) */ -}; - - -NMD::Pool NMD::POOL32Fxf[4] = { - { pool , POOL32Fxf_0 , 64 , 32, - 0xfc0000ff, 0xa000003b, 0 , 0, - CP1_ }, /* POOL32Fxf_0 */ - { pool , POOL32Fxf_1 , 32 , 32, - 0xfc0000ff, 0xa000007b, 0 , 0, - CP1_ }, /* POOL32Fxf_1 */ - { reserved_block , 0 , 0 , 32, - 0xfc0000ff, 0xa00000bb, 0 , 0, - CP1_ }, /* POOL32Fxf~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc0000ff, 0xa00000fb, 0 , 0, - CP1_ }, /* POOL32Fxf~*(3) */ -}; - - -NMD::Pool NMD::POOL32F_3[8] = { - { pool , MIN_fmt , 2 , 32, - 0xfc00003f, 0xa0000003, 0 , 0, - CP1_ }, /* MIN.fmt */ - { pool , MAX_fmt , 2 , 32, - 0xfc00003f, 0xa000000b, 0 , 0, - CP1_ }, /* MAX.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa0000013, 0 , 0, - CP1_ }, /* POOL32F_3~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa000001b, 0 , 0, - CP1_ }, /* POOL32F_3~*(3) */ - { pool , MINA_fmt , 2 , 32, - 0xfc00003f, 0xa0000023, 0 , 0, - CP1_ }, /* MINA.fmt */ - { pool , MAXA_fmt , 2 , 32, - 0xfc00003f, 0xa000002b, 0 , 0, - CP1_ }, /* MAXA.fmt */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa0000033, 0 , 0, - CP1_ }, /* POOL32F_3~*(6) */ - { pool , POOL32Fxf , 4 , 32, - 0xfc00003f, 0xa000003b, 0 , 0, - CP1_ }, /* POOL32Fxf */ -}; - - -NMD::Pool NMD::CMP_condn_S[32] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000005, &NMD::CMP_AF_S , 0, - CP1_ }, /* CMP.AF.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000045, &NMD::CMP_UN_S , 0, - CP1_ }, /* CMP.UN.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000085, &NMD::CMP_EQ_S , 0, - CP1_ }, /* CMP.EQ.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00000c5, &NMD::CMP_UEQ_S , 0, - CP1_ }, /* CMP.UEQ.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000105, &NMD::CMP_LT_S , 0, - CP1_ }, /* CMP.LT.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000145, &NMD::CMP_ULT_S , 0, - CP1_ }, /* CMP.ULT.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000185, &NMD::CMP_LE_S , 0, - CP1_ }, /* CMP.LE.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00001c5, &NMD::CMP_ULE_S , 0, - CP1_ }, /* CMP.ULE.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000205, &NMD::CMP_SAF_S , 0, - CP1_ }, /* CMP.SAF.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000245, &NMD::CMP_SUN_S , 0, - CP1_ }, /* CMP.SUN.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000285, &NMD::CMP_SEQ_S , 0, - CP1_ }, /* CMP.SEQ.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00002c5, &NMD::CMP_SUEQ_S , 0, - CP1_ }, /* CMP.SUEQ.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000305, &NMD::CMP_SLT_S , 0, - CP1_ }, /* CMP.SLT.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000345, &NMD::CMP_SULT_S , 0, - CP1_ }, /* CMP.SULT.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000385, &NMD::CMP_SLE_S , 0, - CP1_ }, /* CMP.SLE.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00003c5, &NMD::CMP_SULE_S , 0, - CP1_ }, /* CMP.SULE.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000405, 0 , 0, - CP1_ }, /* CMP.condn.S~*(16) */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000445, &NMD::CMP_OR_S , 0, - CP1_ }, /* CMP.OR.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000485, &NMD::CMP_UNE_S , 0, - CP1_ }, /* CMP.UNE.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00004c5, &NMD::CMP_NE_S , 0, - CP1_ }, /* CMP.NE.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000505, 0 , 0, - CP1_ }, /* CMP.condn.S~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000545, 0 , 0, - CP1_ }, /* CMP.condn.S~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000585, 0 , 0, - CP1_ }, /* CMP.condn.S~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa00005c5, 0 , 0, - CP1_ }, /* CMP.condn.S~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000605, 0 , 0, - CP1_ }, /* CMP.condn.S~*(24) */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000645, &NMD::CMP_SOR_S , 0, - CP1_ }, /* CMP.SOR.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000685, &NMD::CMP_SUNE_S , 0, - CP1_ }, /* CMP.SUNE.S */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00006c5, &NMD::CMP_SNE_S , 0, - CP1_ }, /* CMP.SNE.S */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000705, 0 , 0, - CP1_ }, /* CMP.condn.S~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000745, 0 , 0, - CP1_ }, /* CMP.condn.S~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000785, 0 , 0, - CP1_ }, /* CMP.condn.S~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa00007c5, 0 , 0, - CP1_ }, /* CMP.condn.S~*(31) */ -}; - - -NMD::Pool NMD::CMP_condn_D[32] = { - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000015, &NMD::CMP_AF_D , 0, - CP1_ }, /* CMP.AF.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000055, &NMD::CMP_UN_D , 0, - CP1_ }, /* CMP.UN.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000095, &NMD::CMP_EQ_D , 0, - CP1_ }, /* CMP.EQ.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00000d5, &NMD::CMP_UEQ_D , 0, - CP1_ }, /* CMP.UEQ.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000115, &NMD::CMP_LT_D , 0, - CP1_ }, /* CMP.LT.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000155, &NMD::CMP_ULT_D , 0, - CP1_ }, /* CMP.ULT.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000195, &NMD::CMP_LE_D , 0, - CP1_ }, /* CMP.LE.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00001d5, &NMD::CMP_ULE_D , 0, - CP1_ }, /* CMP.ULE.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000215, &NMD::CMP_SAF_D , 0, - CP1_ }, /* CMP.SAF.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000255, &NMD::CMP_SUN_D , 0, - CP1_ }, /* CMP.SUN.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000295, &NMD::CMP_SEQ_D , 0, - CP1_ }, /* CMP.SEQ.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00002d5, &NMD::CMP_SUEQ_D , 0, - CP1_ }, /* CMP.SUEQ.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000315, &NMD::CMP_SLT_D , 0, - CP1_ }, /* CMP.SLT.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000355, &NMD::CMP_SULT_D , 0, - CP1_ }, /* CMP.SULT.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000395, &NMD::CMP_SLE_D , 0, - CP1_ }, /* CMP.SLE.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00003d5, &NMD::CMP_SULE_D , 0, - CP1_ }, /* CMP.SULE.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000415, 0 , 0, - CP1_ }, /* CMP.condn.D~*(16) */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000455, &NMD::CMP_OR_D , 0, - CP1_ }, /* CMP.OR.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000495, &NMD::CMP_UNE_D , 0, - CP1_ }, /* CMP.UNE.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00004d5, &NMD::CMP_NE_D , 0, - CP1_ }, /* CMP.NE.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000515, 0 , 0, - CP1_ }, /* CMP.condn.D~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000555, 0 , 0, - CP1_ }, /* CMP.condn.D~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000595, 0 , 0, - CP1_ }, /* CMP.condn.D~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa00005d5, 0 , 0, - CP1_ }, /* CMP.condn.D~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000615, 0 , 0, - CP1_ }, /* CMP.condn.D~*(24) */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000655, &NMD::CMP_SOR_D , 0, - CP1_ }, /* CMP.SOR.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa0000695, &NMD::CMP_SUNE_D , 0, - CP1_ }, /* CMP.SUNE.D */ - { instruction , 0 , 0 , 32, - 0xfc0007ff, 0xa00006d5, &NMD::CMP_SNE_D , 0, - CP1_ }, /* CMP.SNE.D */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000715, 0 , 0, - CP1_ }, /* CMP.condn.D~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000755, 0 , 0, - CP1_ }, /* CMP.condn.D~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa0000795, 0 , 0, - CP1_ }, /* CMP.condn.D~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc0007ff, 0xa00007d5, 0 , 0, - CP1_ }, /* CMP.condn.D~*(31) */ -}; - - -NMD::Pool NMD::POOL32F_5[8] = { - { pool , CMP_condn_S , 32 , 32, - 0xfc00003f, 0xa0000005, 0 , 0, - CP1_ }, /* CMP.condn.S */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa000000d, 0 , 0, - CP1_ }, /* POOL32F_5~*(1) */ - { pool , CMP_condn_D , 32 , 32, - 0xfc00003f, 0xa0000015, 0 , 0, - CP1_ }, /* CMP.condn.D */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa000001d, 0 , 0, - CP1_ }, /* POOL32F_5~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa0000025, 0 , 0, - CP1_ }, /* POOL32F_5~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa000002d, 0 , 0, - CP1_ }, /* POOL32F_5~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa0000035, 0 , 0, - CP1_ }, /* POOL32F_5~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xa000003d, 0 , 0, - CP1_ }, /* POOL32F_5~*(7) */ -}; - - -NMD::Pool NMD::POOL32F[8] = { - { pool , POOL32F_0 , 64 , 32, - 0xfc000007, 0xa0000000, 0 , 0, - CP1_ }, /* POOL32F_0 */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xa0000001, 0 , 0, - CP1_ }, /* POOL32F~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xa0000002, 0 , 0, - CP1_ }, /* POOL32F~*(2) */ - { pool , POOL32F_3 , 8 , 32, - 0xfc000007, 0xa0000003, 0 , 0, - CP1_ }, /* POOL32F_3 */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xa0000004, 0 , 0, - CP1_ }, /* POOL32F~*(4) */ - { pool , POOL32F_5 , 8 , 32, - 0xfc000007, 0xa0000005, 0 , 0, - CP1_ }, /* POOL32F_5 */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xa0000006, 0 , 0, - CP1_ }, /* POOL32F~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xa0000007, 0 , 0, - CP1_ }, /* POOL32F~*(7) */ -}; - - -NMD::Pool NMD::POOL32S_0[64] = { - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000000, 0 , 0, - 0x0 }, /* POOL32S_0~*(0) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000008, &NMD::DLSA , 0, - MIPS64_ }, /* DLSA */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000010, &NMD::DSLLV , 0, - MIPS64_ }, /* DSLLV */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000018, &NMD::DMUL , 0, - MIPS64_ }, /* DMUL */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000020, 0 , 0, - 0x0 }, /* POOL32S_0~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000028, 0 , 0, - 0x0 }, /* POOL32S_0~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000030, 0 , 0, - 0x0 }, /* POOL32S_0~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000038, 0 , 0, - 0x0 }, /* POOL32S_0~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000040, 0 , 0, - 0x0 }, /* POOL32S_0~*(8) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000048, 0 , 0, - 0x0 }, /* POOL32S_0~*(9) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000050, &NMD::DSRLV , 0, - MIPS64_ }, /* DSRLV */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000058, &NMD::DMUH , 0, - MIPS64_ }, /* DMUH */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000060, 0 , 0, - 0x0 }, /* POOL32S_0~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000068, 0 , 0, - 0x0 }, /* POOL32S_0~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000070, 0 , 0, - 0x0 }, /* POOL32S_0~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000078, 0 , 0, - 0x0 }, /* POOL32S_0~*(15) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000080, 0 , 0, - 0x0 }, /* POOL32S_0~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000088, 0 , 0, - 0x0 }, /* POOL32S_0~*(17) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000090, &NMD::DSRAV , 0, - MIPS64_ }, /* DSRAV */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000098, &NMD::DMULU , 0, - MIPS64_ }, /* DMULU */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000a0, 0 , 0, - 0x0 }, /* POOL32S_0~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000a8, 0 , 0, - 0x0 }, /* POOL32S_0~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000b0, 0 , 0, - 0x0 }, /* POOL32S_0~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000b8, 0 , 0, - 0x0 }, /* POOL32S_0~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000c0, 0 , 0, - 0x0 }, /* POOL32S_0~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000c8, 0 , 0, - 0x0 }, /* POOL32S_0~*(25) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc00000d0, &NMD::DROTRV , 0, - MIPS64_ }, /* DROTRV */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc00000d8, &NMD::DMUHU , 0, - MIPS64_ }, /* DMUHU */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000e0, 0 , 0, - 0x0 }, /* POOL32S_0~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000e8, 0 , 0, - 0x0 }, /* POOL32S_0~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000f0, 0 , 0, - 0x0 }, /* POOL32S_0~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000f8, 0 , 0, - 0x0 }, /* POOL32S_0~*(31) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000100, 0 , 0, - 0x0 }, /* POOL32S_0~*(32) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000108, 0 , 0, - 0x0 }, /* POOL32S_0~*(33) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000110, &NMD::DADD , 0, - MIPS64_ }, /* DADD */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000118, &NMD::DDIV , 0, - MIPS64_ }, /* DDIV */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000120, 0 , 0, - 0x0 }, /* POOL32S_0~*(36) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000128, 0 , 0, - 0x0 }, /* POOL32S_0~*(37) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000130, 0 , 0, - 0x0 }, /* POOL32S_0~*(38) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000138, 0 , 0, - 0x0 }, /* POOL32S_0~*(39) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000140, 0 , 0, - 0x0 }, /* POOL32S_0~*(40) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000148, 0 , 0, - 0x0 }, /* POOL32S_0~*(41) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000150, &NMD::DADDU , 0, - MIPS64_ }, /* DADDU */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000158, &NMD::DMOD , 0, - MIPS64_ }, /* DMOD */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000160, 0 , 0, - 0x0 }, /* POOL32S_0~*(44) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000168, 0 , 0, - 0x0 }, /* POOL32S_0~*(45) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000170, 0 , 0, - 0x0 }, /* POOL32S_0~*(46) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000178, 0 , 0, - 0x0 }, /* POOL32S_0~*(47) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000180, 0 , 0, - 0x0 }, /* POOL32S_0~*(48) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc0000188, 0 , 0, - 0x0 }, /* POOL32S_0~*(49) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000190, &NMD::DSUB , 0, - MIPS64_ }, /* DSUB */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc0000198, &NMD::DDIVU , 0, - MIPS64_ }, /* DDIVU */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001a0, 0 , 0, - 0x0 }, /* POOL32S_0~*(52) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001a8, 0 , 0, - 0x0 }, /* POOL32S_0~*(53) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001b0, 0 , 0, - 0x0 }, /* POOL32S_0~*(54) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001b8, 0 , 0, - 0x0 }, /* POOL32S_0~*(55) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001c0, 0 , 0, - 0x0 }, /* POOL32S_0~*(56) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001c8, 0 , 0, - 0x0 }, /* POOL32S_0~*(57) */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc00001d0, &NMD::DSUBU , 0, - MIPS64_ }, /* DSUBU */ - { instruction , 0 , 0 , 32, - 0xfc0001ff, 0xc00001d8, &NMD::DMODU , 0, - MIPS64_ }, /* DMODU */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001e0, 0 , 0, - 0x0 }, /* POOL32S_0~*(60) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001e8, 0 , 0, - 0x0 }, /* POOL32S_0~*(61) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001f0, 0 , 0, - 0x0 }, /* POOL32S_0~*(62) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001f8, 0 , 0, - 0x0 }, /* POOL32S_0~*(63) */ -}; - - -NMD::Pool NMD::POOL32Sxf_4[128] = { - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000013c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(0) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000033c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000053c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000073c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000093c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0000b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0000d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0000f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000113c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(8) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000133c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(9) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000153c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000173c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(11) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000193c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0001b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0001d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0001f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(15) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000213c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000233c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(17) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000253c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000273c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000293c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0002b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0002d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0002f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000313c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000333c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000353c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000373c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000393c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0003b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0003d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0003f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(31) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000413c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(32) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000433c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(33) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000453c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(34) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000473c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(35) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000493c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(36) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0xc0004b3c, &NMD::DCLO , 0, - MIPS64_ }, /* DCLO */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0004d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(38) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0004f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(39) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000513c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(40) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000533c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(41) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000553c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(42) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000573c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(43) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000593c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(44) */ - { instruction , 0 , 0 , 32, - 0xfc00ffff, 0xc0005b3c, &NMD::DCLZ , 0, - MIPS64_ }, /* DCLZ */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0005d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(46) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0005f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(47) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000613c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(48) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000633c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(49) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000653c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(50) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000673c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(51) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000693c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(52) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0006b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(53) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0006d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(54) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0006f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(55) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000713c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(56) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000733c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(57) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000753c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(58) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000773c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(59) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000793c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(60) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0007b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(61) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0007d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(62) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0007f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(63) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000813c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(64) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000833c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(65) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000853c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(66) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000873c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(67) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000893c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(68) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0008b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(69) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0008d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(70) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0008f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(71) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000913c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(72) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000933c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(73) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000953c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(74) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000973c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(75) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000993c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(76) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0009b3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(77) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0009d3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(78) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc0009f3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(79) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000a13c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(80) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000a33c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(81) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000a53c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(82) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000a73c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(83) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000a93c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(84) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000ab3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(85) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000ad3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(86) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000af3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(87) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000b13c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(88) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000b33c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(89) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000b53c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(90) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000b73c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(91) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000b93c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(92) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000bb3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(93) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000bd3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(94) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000bf3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(95) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000c13c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(96) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000c33c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(97) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000c53c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(98) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000c73c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(99) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000c93c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(100) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000cb3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(101) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000cd3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(102) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000cf3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(103) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000d13c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(104) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000d33c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(105) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000d53c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(106) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000d73c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(107) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000d93c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(108) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000db3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(109) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000dd3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(110) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000df3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(111) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000e13c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(112) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000e33c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(113) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000e53c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(114) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000e73c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(115) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000e93c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(116) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000eb3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(117) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000ed3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(118) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000ef3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(119) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000f13c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(120) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000f33c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(121) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000f53c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(122) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000f73c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(123) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000f93c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(124) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000fb3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(125) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000fd3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(126) */ - { reserved_block , 0 , 0 , 32, - 0xfc00ffff, 0xc000ff3c, 0 , 0, - 0x0 }, /* POOL32Sxf_4~*(127) */ -}; - - -NMD::Pool NMD::POOL32Sxf[8] = { - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc000003c, 0 , 0, - 0x0 }, /* POOL32Sxf~*(0) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc000007c, 0 , 0, - 0x0 }, /* POOL32Sxf~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000bc, 0 , 0, - 0x0 }, /* POOL32Sxf~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00000fc, 0 , 0, - 0x0 }, /* POOL32Sxf~*(3) */ - { pool , POOL32Sxf_4 , 128 , 32, - 0xfc0001ff, 0xc000013c, 0 , 0, - 0x0 }, /* POOL32Sxf_4 */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc000017c, 0 , 0, - 0x0 }, /* POOL32Sxf~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001bc, 0 , 0, - 0x0 }, /* POOL32Sxf~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc0001ff, 0xc00001fc, 0 , 0, - 0x0 }, /* POOL32Sxf~*(7) */ -}; - - -NMD::Pool NMD::POOL32S_4[8] = { - { instruction , 0 , 0 , 32, - 0xfc00003f, 0xc0000004, &NMD::EXTD , 0, - MIPS64_ }, /* EXTD */ - { instruction , 0 , 0 , 32, - 0xfc00003f, 0xc000000c, &NMD::EXTD32 , 0, - MIPS64_ }, /* EXTD32 */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xc0000014, 0 , 0, - 0x0 }, /* POOL32S_4~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xc000001c, 0 , 0, - 0x0 }, /* POOL32S_4~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xc0000024, 0 , 0, - 0x0 }, /* POOL32S_4~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xc000002c, 0 , 0, - 0x0 }, /* POOL32S_4~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00003f, 0xc0000034, 0 , 0, - 0x0 }, /* POOL32S_4~*(6) */ - { pool , POOL32Sxf , 8 , 32, - 0xfc00003f, 0xc000003c, 0 , 0, - 0x0 }, /* POOL32Sxf */ -}; - - -NMD::Pool NMD::POOL32S[8] = { - { pool , POOL32S_0 , 64 , 32, - 0xfc000007, 0xc0000000, 0 , 0, - 0x0 }, /* POOL32S_0 */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xc0000001, 0 , 0, - 0x0 }, /* POOL32S~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xc0000002, 0 , 0, - 0x0 }, /* POOL32S~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xc0000003, 0 , 0, - 0x0 }, /* POOL32S~*(3) */ - { pool , POOL32S_4 , 8 , 32, - 0xfc000007, 0xc0000004, 0 , 0, - 0x0 }, /* POOL32S_4 */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xc0000005, 0 , 0, - 0x0 }, /* POOL32S~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xc0000006, 0 , 0, - 0x0 }, /* POOL32S~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc000007, 0xc0000007, 0 , 0, - 0x0 }, /* POOL32S~*(7) */ -}; - - -NMD::Pool NMD::P_LUI[2] = { - { instruction , 0 , 0 , 32, - 0xfc000002, 0xe0000000, &NMD::LUI , 0, - 0x0 }, /* LUI */ - { instruction , 0 , 0 , 32, - 0xfc000002, 0xe0000002, &NMD::ALUIPC , 0, - 0x0 }, /* ALUIPC */ -}; - - -NMD::Pool NMD::P_GP_LH[2] = { - { instruction , 0 , 0 , 32, - 0xfc1c0001, 0x44100000, &NMD::LH_GP_ , 0, - 0x0 }, /* LH[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0001, 0x44100001, &NMD::LHU_GP_ , 0, - 0x0 }, /* LHU[GP] */ -}; - - -NMD::Pool NMD::P_GP_SH[2] = { - { instruction , 0 , 0 , 32, - 0xfc1c0001, 0x44140000, &NMD::SH_GP_ , 0, - 0x0 }, /* SH[GP] */ - { reserved_block , 0 , 0 , 32, - 0xfc1c0001, 0x44140001, 0 , 0, - 0x0 }, /* P.GP.SH~*(1) */ -}; - - -NMD::Pool NMD::P_GP_CP1[4] = { - { instruction , 0 , 0 , 32, - 0xfc1c0003, 0x44180000, &NMD::LWC1_GP_ , 0, - CP1_ }, /* LWC1[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0003, 0x44180001, &NMD::SWC1_GP_ , 0, - CP1_ }, /* SWC1[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0003, 0x44180002, &NMD::LDC1_GP_ , 0, - CP1_ }, /* LDC1[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0003, 0x44180003, &NMD::SDC1_GP_ , 0, - CP1_ }, /* SDC1[GP] */ -}; - - -NMD::Pool NMD::P_GP_M64[4] = { - { instruction , 0 , 0 , 32, - 0xfc1c0003, 0x441c0000, &NMD::LWU_GP_ , 0, - MIPS64_ }, /* LWU[GP] */ - { reserved_block , 0 , 0 , 32, - 0xfc1c0003, 0x441c0001, 0 , 0, - 0x0 }, /* P.GP.M64~*(1) */ - { reserved_block , 0 , 0 , 32, - 0xfc1c0003, 0x441c0002, 0 , 0, - 0x0 }, /* P.GP.M64~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc1c0003, 0x441c0003, 0 , 0, - 0x0 }, /* P.GP.M64~*(3) */ -}; - - -NMD::Pool NMD::P_GP_BH[8] = { - { instruction , 0 , 0 , 32, - 0xfc1c0000, 0x44000000, &NMD::LB_GP_ , 0, - 0x0 }, /* LB[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0000, 0x44040000, &NMD::SB_GP_ , 0, - 0x0 }, /* SB[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0000, 0x44080000, &NMD::LBU_GP_ , 0, - 0x0 }, /* LBU[GP] */ - { instruction , 0 , 0 , 32, - 0xfc1c0000, 0x440c0000, &NMD::ADDIU_GP_B_ , 0, - 0x0 }, /* ADDIU[GP.B] */ - { pool , P_GP_LH , 2 , 32, - 0xfc1c0000, 0x44100000, 0 , 0, - 0x0 }, /* P.GP.LH */ - { pool , P_GP_SH , 2 , 32, - 0xfc1c0000, 0x44140000, 0 , 0, - 0x0 }, /* P.GP.SH */ - { pool , P_GP_CP1 , 4 , 32, - 0xfc1c0000, 0x44180000, 0 , 0, - 0x0 }, /* P.GP.CP1 */ - { pool , P_GP_M64 , 4 , 32, - 0xfc1c0000, 0x441c0000, 0 , 0, - 0x0 }, /* P.GP.M64 */ -}; - - -NMD::Pool NMD::P_LS_U12[16] = { - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84000000, &NMD::LB_U12_ , 0, - 0x0 }, /* LB[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84001000, &NMD::SB_U12_ , 0, - 0x0 }, /* SB[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84002000, &NMD::LBU_U12_ , 0, - 0x0 }, /* LBU[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84003000, &NMD::PREF_U12_ , 0, - 0x0 }, /* PREF[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84004000, &NMD::LH_U12_ , 0, - 0x0 }, /* LH[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84005000, &NMD::SH_U12_ , 0, - 0x0 }, /* SH[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84006000, &NMD::LHU_U12_ , 0, - 0x0 }, /* LHU[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84007000, &NMD::LWU_U12_ , 0, - MIPS64_ }, /* LWU[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84008000, &NMD::LW_U12_ , 0, - 0x0 }, /* LW[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x84009000, &NMD::SW_U12_ , 0, - 0x0 }, /* SW[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8400a000, &NMD::LWC1_U12_ , 0, - CP1_ }, /* LWC1[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8400b000, &NMD::SWC1_U12_ , 0, - CP1_ }, /* SWC1[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8400c000, &NMD::LD_U12_ , 0, - MIPS64_ }, /* LD[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8400d000, &NMD::SD_U12_ , 0, - MIPS64_ }, /* SD[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8400e000, &NMD::LDC1_U12_ , 0, - CP1_ }, /* LDC1[U12] */ - { instruction , 0 , 0 , 32, - 0xfc00f000, 0x8400f000, &NMD::SDC1_U12_ , 0, - CP1_ }, /* SDC1[U12] */ -}; - - -NMD::Pool NMD::P_PREF_S9_[2] = { - { instruction , 0 , 0 , 32, - 0xffe07f00, 0xa7e01800, &NMD::SYNCI , 0, - 0x0 }, /* SYNCI */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4001800, &NMD::PREF_S9_ , &NMD::PREF_S9__cond , - 0x0 }, /* PREF[S9] */ -}; - - -NMD::Pool NMD::P_LS_S0[16] = { - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4000000, &NMD::LB_S9_ , 0, - 0x0 }, /* LB[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4000800, &NMD::SB_S9_ , 0, - 0x0 }, /* SB[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4001000, &NMD::LBU_S9_ , 0, - 0x0 }, /* LBU[S9] */ - { pool , P_PREF_S9_ , 2 , 32, - 0xfc007f00, 0xa4001800, 0 , 0, - 0x0 }, /* P.PREF[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4002000, &NMD::LH_S9_ , 0, - 0x0 }, /* LH[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4002800, &NMD::SH_S9_ , 0, - 0x0 }, /* SH[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4003000, &NMD::LHU_S9_ , 0, - 0x0 }, /* LHU[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4003800, &NMD::LWU_S9_ , 0, - MIPS64_ }, /* LWU[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4004000, &NMD::LW_S9_ , 0, - 0x0 }, /* LW[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4004800, &NMD::SW_S9_ , 0, - 0x0 }, /* SW[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4005000, &NMD::LWC1_S9_ , 0, - CP1_ }, /* LWC1[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4005800, &NMD::SWC1_S9_ , 0, - CP1_ }, /* SWC1[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4006000, &NMD::LD_S9_ , 0, - MIPS64_ }, /* LD[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4006800, &NMD::SD_S9_ , 0, - MIPS64_ }, /* SD[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4007000, &NMD::LDC1_S9_ , 0, - CP1_ }, /* LDC1[S9] */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4007800, &NMD::SDC1_S9_ , 0, - CP1_ }, /* SDC1[S9] */ -}; - - -NMD::Pool NMD::ASET_ACLR[2] = { - { instruction , 0 , 0 , 32, - 0xfe007f00, 0xa4001100, &NMD::ASET , 0, - MCU_ }, /* ASET */ - { instruction , 0 , 0 , 32, - 0xfe007f00, 0xa6001100, &NMD::ACLR , 0, - MCU_ }, /* ACLR */ -}; - - -NMD::Pool NMD::P_LL[4] = { - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005100, &NMD::LL , 0, - 0x0 }, /* LL */ - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005101, &NMD::LLWP , 0, - XNP_ }, /* LLWP */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005102, 0 , 0, - 0x0 }, /* P.LL~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005103, 0 , 0, - 0x0 }, /* P.LL~*(3) */ -}; - - -NMD::Pool NMD::P_SC[4] = { - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005900, &NMD::SC , 0, - 0x0 }, /* SC */ - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005901, &NMD::SCWP , 0, - XNP_ }, /* SCWP */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005902, 0 , 0, - 0x0 }, /* P.SC~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005903, 0 , 0, - 0x0 }, /* P.SC~*(3) */ -}; - - -NMD::Pool NMD::P_LLD[8] = { - { instruction , 0 , 0 , 32, - 0xfc007f07, 0xa4007100, &NMD::LLD , 0, - MIPS64_ }, /* LLD */ - { instruction , 0 , 0 , 32, - 0xfc007f07, 0xa4007101, &NMD::LLDP , 0, - MIPS64_ }, /* LLDP */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007102, 0 , 0, - 0x0 }, /* P.LLD~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007103, 0 , 0, - 0x0 }, /* P.LLD~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007104, 0 , 0, - 0x0 }, /* P.LLD~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007105, 0 , 0, - 0x0 }, /* P.LLD~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007106, 0 , 0, - 0x0 }, /* P.LLD~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007107, 0 , 0, - 0x0 }, /* P.LLD~*(7) */ -}; - - -NMD::Pool NMD::P_SCD[8] = { - { instruction , 0 , 0 , 32, - 0xfc007f07, 0xa4007900, &NMD::SCD , 0, - MIPS64_ }, /* SCD */ - { instruction , 0 , 0 , 32, - 0xfc007f07, 0xa4007901, &NMD::SCDP , 0, - MIPS64_ }, /* SCDP */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007902, 0 , 0, - 0x0 }, /* P.SCD~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007903, 0 , 0, - 0x0 }, /* P.SCD~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007904, 0 , 0, - 0x0 }, /* P.SCD~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007905, 0 , 0, - 0x0 }, /* P.SCD~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007906, 0 , 0, - 0x0 }, /* P.SCD~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f07, 0xa4007907, 0 , 0, - 0x0 }, /* P.SCD~*(7) */ -}; - - -NMD::Pool NMD::P_LS_S1[16] = { - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4000100, 0 , 0, - 0x0 }, /* P.LS.S1~*(0) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4000900, 0 , 0, - 0x0 }, /* P.LS.S1~*(1) */ - { pool , ASET_ACLR , 2 , 32, - 0xfc007f00, 0xa4001100, 0 , 0, - 0x0 }, /* ASET_ACLR */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4001900, 0 , 0, - 0x0 }, /* P.LS.S1~*(3) */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4002100, &NMD::UALH , 0, - XMMS_ }, /* UALH */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4002900, &NMD::UASH , 0, - XMMS_ }, /* UASH */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4003100, 0 , 0, - 0x0 }, /* P.LS.S1~*(6) */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4003900, &NMD::CACHE , 0, - CP0_ }, /* CACHE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4004100, &NMD::LWC2 , 0, - CP2_ }, /* LWC2 */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4004900, &NMD::SWC2 , 0, - CP2_ }, /* SWC2 */ - { pool , P_LL , 4 , 32, - 0xfc007f00, 0xa4005100, 0 , 0, - 0x0 }, /* P.LL */ - { pool , P_SC , 4 , 32, - 0xfc007f00, 0xa4005900, 0 , 0, - 0x0 }, /* P.SC */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4006100, &NMD::LDC2 , 0, - CP2_ }, /* LDC2 */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4006900, &NMD::SDC2 , 0, - CP2_ }, /* SDC2 */ - { pool , P_LLD , 8 , 32, - 0xfc007f00, 0xa4007100, 0 , 0, - 0x0 }, /* P.LLD */ - { pool , P_SCD , 8 , 32, - 0xfc007f00, 0xa4007900, 0 , 0, - 0x0 }, /* P.SCD */ -}; - - -NMD::Pool NMD::P_PREFE[2] = { - { instruction , 0 , 0 , 32, - 0xffe07f00, 0xa7e01a00, &NMD::SYNCIE , 0, - CP0_ | EVA_ }, /* SYNCIE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4001a00, &NMD::PREFE , &NMD::PREFE_cond , - CP0_ | EVA_ }, /* PREFE */ -}; - - -NMD::Pool NMD::P_LLE[4] = { - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005200, &NMD::LLE , 0, - CP0_ | EVA_ }, /* LLE */ - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005201, &NMD::LLWPE , 0, - CP0_ | EVA_ }, /* LLWPE */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005202, 0 , 0, - 0x0 }, /* P.LLE~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005203, 0 , 0, - 0x0 }, /* P.LLE~*(3) */ -}; - - -NMD::Pool NMD::P_SCE[4] = { - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005a00, &NMD::SCE , 0, - CP0_ | EVA_ }, /* SCE */ - { instruction , 0 , 0 , 32, - 0xfc007f03, 0xa4005a01, &NMD::SCWPE , 0, - CP0_ | EVA_ }, /* SCWPE */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005a02, 0 , 0, - 0x0 }, /* P.SCE~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f03, 0xa4005a03, 0 , 0, - 0x0 }, /* P.SCE~*(3) */ -}; - - -NMD::Pool NMD::P_LS_E0[16] = { - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4000200, &NMD::LBE , 0, - CP0_ | EVA_ }, /* LBE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4000a00, &NMD::SBE , 0, - CP0_ | EVA_ }, /* SBE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4001200, &NMD::LBUE , 0, - CP0_ | EVA_ }, /* LBUE */ - { pool , P_PREFE , 2 , 32, - 0xfc007f00, 0xa4001a00, 0 , 0, - 0x0 }, /* P.PREFE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4002200, &NMD::LHE , 0, - CP0_ | EVA_ }, /* LHE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4002a00, &NMD::SHE , 0, - CP0_ | EVA_ }, /* SHE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4003200, &NMD::LHUE , 0, - CP0_ | EVA_ }, /* LHUE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4003a00, &NMD::CACHEE , 0, - CP0_ | EVA_ }, /* CACHEE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4004200, &NMD::LWE , 0, - CP0_ | EVA_ }, /* LWE */ - { instruction , 0 , 0 , 32, - 0xfc007f00, 0xa4004a00, &NMD::SWE , 0, - CP0_ | EVA_ }, /* SWE */ - { pool , P_LLE , 4 , 32, - 0xfc007f00, 0xa4005200, 0 , 0, - 0x0 }, /* P.LLE */ - { pool , P_SCE , 4 , 32, - 0xfc007f00, 0xa4005a00, 0 , 0, - 0x0 }, /* P.SCE */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4006200, 0 , 0, - 0x0 }, /* P.LS.E0~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4006a00, 0 , 0, - 0x0 }, /* P.LS.E0~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4007200, 0 , 0, - 0x0 }, /* P.LS.E0~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc007f00, 0xa4007a00, 0 , 0, - 0x0 }, /* P.LS.E0~*(15) */ -}; - - -NMD::Pool NMD::P_LS_WM[2] = { - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000400, &NMD::LWM , 0, - XMMS_ }, /* LWM */ - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000c00, &NMD::SWM , 0, - XMMS_ }, /* SWM */ -}; - - -NMD::Pool NMD::P_LS_UAWM[2] = { - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000500, &NMD::UALWM , 0, - XMMS_ }, /* UALWM */ - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000d00, &NMD::UASWM , 0, - XMMS_ }, /* UASWM */ -}; - - -NMD::Pool NMD::P_LS_DM[2] = { - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000600, &NMD::LDM , 0, - MIPS64_ }, /* LDM */ - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000e00, &NMD::SDM , 0, - MIPS64_ }, /* SDM */ -}; - - -NMD::Pool NMD::P_LS_UADM[2] = { - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000700, &NMD::UALDM , 0, - MIPS64_ }, /* UALDM */ - { instruction , 0 , 0 , 32, - 0xfc000f00, 0xa4000f00, &NMD::UASDM , 0, - MIPS64_ }, /* UASDM */ -}; - - -NMD::Pool NMD::P_LS_S9[8] = { - { pool , P_LS_S0 , 16 , 32, - 0xfc000700, 0xa4000000, 0 , 0, - 0x0 }, /* P.LS.S0 */ - { pool , P_LS_S1 , 16 , 32, - 0xfc000700, 0xa4000100, 0 , 0, - 0x0 }, /* P.LS.S1 */ - { pool , P_LS_E0 , 16 , 32, - 0xfc000700, 0xa4000200, 0 , 0, - 0x0 }, /* P.LS.E0 */ - { reserved_block , 0 , 0 , 32, - 0xfc000700, 0xa4000300, 0 , 0, - 0x0 }, /* P.LS.S9~*(3) */ - { pool , P_LS_WM , 2 , 32, - 0xfc000700, 0xa4000400, 0 , 0, - 0x0 }, /* P.LS.WM */ - { pool , P_LS_UAWM , 2 , 32, - 0xfc000700, 0xa4000500, 0 , 0, - 0x0 }, /* P.LS.UAWM */ - { pool , P_LS_DM , 2 , 32, - 0xfc000700, 0xa4000600, 0 , 0, - 0x0 }, /* P.LS.DM */ - { pool , P_LS_UADM , 2 , 32, - 0xfc000700, 0xa4000700, 0 , 0, - 0x0 }, /* P.LS.UADM */ -}; - - -NMD::Pool NMD::P_BAL[2] = { - { branch_instruction , 0 , 0 , 32, - 0xfe000000, 0x28000000, &NMD::BC_32_ , 0, - 0x0 }, /* BC[32] */ - { call_instruction , 0 , 0 , 32, - 0xfe000000, 0x2a000000, &NMD::BALC_32_ , 0, - 0x0 }, /* BALC[32] */ -}; - - -NMD::Pool NMD::P_BALRSC[2] = { - { branch_instruction , 0 , 0 , 32, - 0xffe0f000, 0x48008000, &NMD::BRSC , 0, - 0x0 }, /* BRSC */ - { call_instruction , 0 , 0 , 32, - 0xfc00f000, 0x48008000, &NMD::BALRSC , &NMD::BALRSC_cond , - 0x0 }, /* BALRSC */ -}; - - -NMD::Pool NMD::P_J[16] = { - { call_instruction , 0 , 0 , 32, - 0xfc00f000, 0x48000000, &NMD::JALRC_32_ , 0, - 0x0 }, /* JALRC[32] */ - { call_instruction , 0 , 0 , 32, - 0xfc00f000, 0x48001000, &NMD::JALRC_HB , 0, - 0x0 }, /* JALRC.HB */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48002000, 0 , 0, - 0x0 }, /* P.J~*(2) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48003000, 0 , 0, - 0x0 }, /* P.J~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48004000, 0 , 0, - 0x0 }, /* P.J~*(4) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48005000, 0 , 0, - 0x0 }, /* P.J~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48006000, 0 , 0, - 0x0 }, /* P.J~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48007000, 0 , 0, - 0x0 }, /* P.J~*(7) */ - { pool , P_BALRSC , 2 , 32, - 0xfc00f000, 0x48008000, 0 , 0, - 0x0 }, /* P.BALRSC */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x48009000, 0 , 0, - 0x0 }, /* P.J~*(9) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x4800a000, 0 , 0, - 0x0 }, /* P.J~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x4800b000, 0 , 0, - 0x0 }, /* P.J~*(11) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x4800c000, 0 , 0, - 0x0 }, /* P.J~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x4800d000, 0 , 0, - 0x0 }, /* P.J~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x4800e000, 0 , 0, - 0x0 }, /* P.J~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc00f000, 0x4800f000, 0 , 0, - 0x0 }, /* P.J~*(15) */ -}; - - -NMD::Pool NMD::P_BR3A[32] = { - { branch_instruction , 0 , 0 , 32, - 0xfc1fc000, 0x88004000, &NMD::BC1EQZC , 0, - CP1_ }, /* BC1EQZC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1fc000, 0x88014000, &NMD::BC1NEZC , 0, - CP1_ }, /* BC1NEZC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1fc000, 0x88024000, &NMD::BC2EQZC , 0, - CP2_ }, /* BC2EQZC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1fc000, 0x88034000, &NMD::BC2NEZC , 0, - CP2_ }, /* BC2NEZC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1fc000, 0x88044000, &NMD::BPOSGE32C , 0, - DSP_ }, /* BPOSGE32C */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88054000, 0 , 0, - 0x0 }, /* P.BR3A~*(5) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88064000, 0 , 0, - 0x0 }, /* P.BR3A~*(6) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88074000, 0 , 0, - 0x0 }, /* P.BR3A~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88084000, 0 , 0, - 0x0 }, /* P.BR3A~*(8) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88094000, 0 , 0, - 0x0 }, /* P.BR3A~*(9) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x880a4000, 0 , 0, - 0x0 }, /* P.BR3A~*(10) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x880b4000, 0 , 0, - 0x0 }, /* P.BR3A~*(11) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x880c4000, 0 , 0, - 0x0 }, /* P.BR3A~*(12) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x880d4000, 0 , 0, - 0x0 }, /* P.BR3A~*(13) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x880e4000, 0 , 0, - 0x0 }, /* P.BR3A~*(14) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x880f4000, 0 , 0, - 0x0 }, /* P.BR3A~*(15) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88104000, 0 , 0, - 0x0 }, /* P.BR3A~*(16) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88114000, 0 , 0, - 0x0 }, /* P.BR3A~*(17) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88124000, 0 , 0, - 0x0 }, /* P.BR3A~*(18) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88134000, 0 , 0, - 0x0 }, /* P.BR3A~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88144000, 0 , 0, - 0x0 }, /* P.BR3A~*(20) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88154000, 0 , 0, - 0x0 }, /* P.BR3A~*(21) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88164000, 0 , 0, - 0x0 }, /* P.BR3A~*(22) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88174000, 0 , 0, - 0x0 }, /* P.BR3A~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88184000, 0 , 0, - 0x0 }, /* P.BR3A~*(24) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x88194000, 0 , 0, - 0x0 }, /* P.BR3A~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x881a4000, 0 , 0, - 0x0 }, /* P.BR3A~*(26) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x881b4000, 0 , 0, - 0x0 }, /* P.BR3A~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x881c4000, 0 , 0, - 0x0 }, /* P.BR3A~*(28) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x881d4000, 0 , 0, - 0x0 }, /* P.BR3A~*(29) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x881e4000, 0 , 0, - 0x0 }, /* P.BR3A~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc1fc000, 0x881f4000, 0 , 0, - 0x0 }, /* P.BR3A~*(31) */ -}; - - -NMD::Pool NMD::P_BR1[4] = { - { branch_instruction , 0 , 0 , 32, - 0xfc00c000, 0x88000000, &NMD::BEQC_32_ , 0, - 0x0 }, /* BEQC[32] */ - { pool , P_BR3A , 32 , 32, - 0xfc00c000, 0x88004000, 0 , 0, - 0x0 }, /* P.BR3A */ - { branch_instruction , 0 , 0 , 32, - 0xfc00c000, 0x88008000, &NMD::BGEC , 0, - 0x0 }, /* BGEC */ - { branch_instruction , 0 , 0 , 32, - 0xfc00c000, 0x8800c000, &NMD::BGEUC , 0, - 0x0 }, /* BGEUC */ -}; - - -NMD::Pool NMD::P_BR2[4] = { - { branch_instruction , 0 , 0 , 32, - 0xfc00c000, 0xa8000000, &NMD::BNEC_32_ , 0, - 0x0 }, /* BNEC[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc00c000, 0xa8004000, 0 , 0, - 0x0 }, /* P.BR2~*(1) */ - { branch_instruction , 0 , 0 , 32, - 0xfc00c000, 0xa8008000, &NMD::BLTC , 0, - 0x0 }, /* BLTC */ - { branch_instruction , 0 , 0 , 32, - 0xfc00c000, 0xa800c000, &NMD::BLTUC , 0, - 0x0 }, /* BLTUC */ -}; - - -NMD::Pool NMD::P_BRI[8] = { - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc8000000, &NMD::BEQIC , 0, - 0x0 }, /* BEQIC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc8040000, &NMD::BBEQZC , 0, - XMMS_ }, /* BBEQZC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc8080000, &NMD::BGEIC , 0, - 0x0 }, /* BGEIC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc80c0000, &NMD::BGEIUC , 0, - 0x0 }, /* BGEIUC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc8100000, &NMD::BNEIC , 0, - 0x0 }, /* BNEIC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc8140000, &NMD::BBNEZC , 0, - XMMS_ }, /* BBNEZC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc8180000, &NMD::BLTIC , 0, - 0x0 }, /* BLTIC */ - { branch_instruction , 0 , 0 , 32, - 0xfc1c0000, 0xc81c0000, &NMD::BLTIUC , 0, - 0x0 }, /* BLTIUC */ -}; - - -NMD::Pool NMD::P32[32] = { - { pool , P_ADDIU , 2 , 32, - 0xfc000000, 0x00000000, 0 , 0, - 0x0 }, /* P.ADDIU */ - { pool , P32A , 8 , 32, - 0xfc000000, 0x20000000, 0 , 0, - 0x0 }, /* P32A */ - { pool , P_GP_W , 4 , 32, - 0xfc000000, 0x40000000, 0 , 0, - 0x0 }, /* P.GP.W */ - { pool , POOL48I , 32 , 48, - 0xfc0000000000ull, 0x600000000000ull, 0 , 0, - 0x0 }, /* POOL48I */ - { pool , P_U12 , 16 , 32, - 0xfc000000, 0x80000000, 0 , 0, - 0x0 }, /* P.U12 */ - { pool , POOL32F , 8 , 32, - 0xfc000000, 0xa0000000, 0 , 0, - CP1_ }, /* POOL32F */ - { pool , POOL32S , 8 , 32, - 0xfc000000, 0xc0000000, 0 , 0, - 0x0 }, /* POOL32S */ - { pool , P_LUI , 2 , 32, - 0xfc000000, 0xe0000000, 0 , 0, - 0x0 }, /* P.LUI */ - { instruction , 0 , 0 , 32, - 0xfc000000, 0x04000000, &NMD::ADDIUPC_32_ , 0, - 0x0 }, /* ADDIUPC[32] */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x24000000, 0 , 0, - 0x0 }, /* P32~*(5) */ - { pool , P_GP_BH , 8 , 32, - 0xfc000000, 0x44000000, 0 , 0, - 0x0 }, /* P.GP.BH */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x64000000, 0 , 0, - 0x0 }, /* P32~*(13) */ - { pool , P_LS_U12 , 16 , 32, - 0xfc000000, 0x84000000, 0 , 0, - 0x0 }, /* P.LS.U12 */ - { pool , P_LS_S9 , 8 , 32, - 0xfc000000, 0xa4000000, 0 , 0, - 0x0 }, /* P.LS.S9 */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0xc4000000, 0 , 0, - 0x0 }, /* P32~*(25) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0xe4000000, 0 , 0, - 0x0 }, /* P32~*(29) */ - { call_instruction , 0 , 0 , 32, - 0xfc000000, 0x08000000, &NMD::MOVE_BALC , 0, - XMMS_ }, /* MOVE.BALC */ - { pool , P_BAL , 2 , 32, - 0xfc000000, 0x28000000, 0 , 0, - 0x0 }, /* P.BAL */ - { pool , P_J , 16 , 32, - 0xfc000000, 0x48000000, 0 , 0, - 0x0 }, /* P.J */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x68000000, 0 , 0, - 0x0 }, /* P32~*(14) */ - { pool , P_BR1 , 4 , 32, - 0xfc000000, 0x88000000, 0 , 0, - 0x0 }, /* P.BR1 */ - { pool , P_BR2 , 4 , 32, - 0xfc000000, 0xa8000000, 0 , 0, - 0x0 }, /* P.BR2 */ - { pool , P_BRI , 8 , 32, - 0xfc000000, 0xc8000000, 0 , 0, - 0x0 }, /* P.BRI */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0xe8000000, 0 , 0, - 0x0 }, /* P32~*(30) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x0c000000, 0 , 0, - 0x0 }, /* P32~*(3) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x2c000000, 0 , 0, - 0x0 }, /* P32~*(7) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x4c000000, 0 , 0, - 0x0 }, /* P32~*(11) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x6c000000, 0 , 0, - 0x0 }, /* P32~*(15) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0x8c000000, 0 , 0, - 0x0 }, /* P32~*(19) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0xac000000, 0 , 0, - 0x0 }, /* P32~*(23) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0xcc000000, 0 , 0, - 0x0 }, /* P32~*(27) */ - { reserved_block , 0 , 0 , 32, - 0xfc000000, 0xec000000, 0 , 0, - 0x0 }, /* P32~*(31) */ -}; - - -NMD::Pool NMD::P16_SYSCALL[2] = { - { instruction , 0 , 0 , 16, - 0xfffc , 0x1008 , &NMD::SYSCALL_16_ , 0, - 0x0 }, /* SYSCALL[16] */ - { instruction , 0 , 0 , 16, - 0xfffc , 0x100c , &NMD::HYPCALL_16_ , 0, - CP0_ | VZ_ }, /* HYPCALL[16] */ -}; - - -NMD::Pool NMD::P16_RI[4] = { - { reserved_block , 0 , 0 , 16, - 0xfff8 , 0x1000 , 0 , 0, - 0x0 }, /* P16.RI~*(0) */ - { pool , P16_SYSCALL , 2 , 16, - 0xfff8 , 0x1008 , 0 , 0, - 0x0 }, /* P16.SYSCALL */ - { instruction , 0 , 0 , 16, - 0xfff8 , 0x1010 , &NMD::BREAK_16_ , 0, - 0x0 }, /* BREAK[16] */ - { instruction , 0 , 0 , 16, - 0xfff8 , 0x1018 , &NMD::SDBBP_16_ , 0, - EJTAG_ }, /* SDBBP[16] */ -}; - - -NMD::Pool NMD::P16_MV[2] = { - { pool , P16_RI , 4 , 16, - 0xffe0 , 0x1000 , 0 , 0, - 0x0 }, /* P16.RI */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0x1000 , &NMD::MOVE , &NMD::MOVE_cond , - 0x0 }, /* MOVE */ -}; - - -NMD::Pool NMD::P16_SHIFT[2] = { - { instruction , 0 , 0 , 16, - 0xfc08 , 0x3000 , &NMD::SLL_16_ , 0, - 0x0 }, /* SLL[16] */ - { instruction , 0 , 0 , 16, - 0xfc08 , 0x3008 , &NMD::SRL_16_ , 0, - 0x0 }, /* SRL[16] */ -}; - - -NMD::Pool NMD::POOL16C_00[4] = { - { instruction , 0 , 0 , 16, - 0xfc0f , 0x5000 , &NMD::NOT_16_ , 0, - 0x0 }, /* NOT[16] */ - { instruction , 0 , 0 , 16, - 0xfc0f , 0x5004 , &NMD::XOR_16_ , 0, - 0x0 }, /* XOR[16] */ - { instruction , 0 , 0 , 16, - 0xfc0f , 0x5008 , &NMD::AND_16_ , 0, - 0x0 }, /* AND[16] */ - { instruction , 0 , 0 , 16, - 0xfc0f , 0x500c , &NMD::OR_16_ , 0, - 0x0 }, /* OR[16] */ -}; - - -NMD::Pool NMD::POOL16C_0[2] = { - { pool , POOL16C_00 , 4 , 16, - 0xfc03 , 0x5000 , 0 , 0, - 0x0 }, /* POOL16C_00 */ - { reserved_block , 0 , 0 , 16, - 0xfc03 , 0x5002 , 0 , 0, - 0x0 }, /* POOL16C_0~*(1) */ -}; - - -NMD::Pool NMD::P16C[2] = { - { pool , POOL16C_0 , 2 , 16, - 0xfc01 , 0x5000 , 0 , 0, - 0x0 }, /* POOL16C_0 */ - { instruction , 0 , 0 , 16, - 0xfc01 , 0x5001 , &NMD::LWXS_16_ , 0, - 0x0 }, /* LWXS[16] */ -}; - - -NMD::Pool NMD::P16_A1[2] = { - { reserved_block , 0 , 0 , 16, - 0xfc40 , 0x7000 , 0 , 0, - 0x0 }, /* P16.A1~*(0) */ - { instruction , 0 , 0 , 16, - 0xfc40 , 0x7040 , &NMD::ADDIU_R1_SP_ , 0, - 0x0 }, /* ADDIU[R1.SP] */ -}; - - -NMD::Pool NMD::P_ADDIU_RS5_[2] = { - { instruction , 0 , 0 , 16, - 0xffe8 , 0x9008 , &NMD::NOP_16_ , 0, - 0x0 }, /* NOP[16] */ - { instruction , 0 , 0 , 16, - 0xfc08 , 0x9008 , &NMD::ADDIU_RS5_ , &NMD::ADDIU_RS5__cond , - 0x0 }, /* ADDIU[RS5] */ -}; - - -NMD::Pool NMD::P16_A2[2] = { - { instruction , 0 , 0 , 16, - 0xfc08 , 0x9000 , &NMD::ADDIU_R2_ , 0, - 0x0 }, /* ADDIU[R2] */ - { pool , P_ADDIU_RS5_ , 2 , 16, - 0xfc08 , 0x9008 , 0 , 0, - 0x0 }, /* P.ADDIU[RS5] */ -}; - - -NMD::Pool NMD::P16_ADDU[2] = { - { instruction , 0 , 0 , 16, - 0xfc01 , 0xb000 , &NMD::ADDU_16_ , 0, - 0x0 }, /* ADDU[16] */ - { instruction , 0 , 0 , 16, - 0xfc01 , 0xb001 , &NMD::SUBU_16_ , 0, - 0x0 }, /* SUBU[16] */ -}; - - -NMD::Pool NMD::P16_JRC[2] = { - { branch_instruction , 0 , 0 , 16, - 0xfc1f , 0xd800 , &NMD::JRC , 0, - 0x0 }, /* JRC */ - { call_instruction , 0 , 0 , 16, - 0xfc1f , 0xd810 , &NMD::JALRC_16_ , 0, - 0x0 }, /* JALRC[16] */ -}; - - -NMD::Pool NMD::P16_BR1[2] = { - { branch_instruction , 0 , 0 , 16, - 0xfc00 , 0xd800 , &NMD::BEQC_16_ , &NMD::BEQC_16__cond , - XMMS_ }, /* BEQC[16] */ - { branch_instruction , 0 , 0 , 16, - 0xfc00 , 0xd800 , &NMD::BNEC_16_ , &NMD::BNEC_16__cond , - XMMS_ }, /* BNEC[16] */ -}; - - -NMD::Pool NMD::P16_BR[2] = { - { pool , P16_JRC , 2 , 16, - 0xfc0f , 0xd800 , 0 , 0, - 0x0 }, /* P16.JRC */ - { pool , P16_BR1 , 2 , 16, - 0xfc00 , 0xd800 , 0 , &NMD::P16_BR1_cond , - 0x0 }, /* P16.BR1 */ -}; - - -NMD::Pool NMD::P16_SR[2] = { - { instruction , 0 , 0 , 16, - 0xfd00 , 0x1c00 , &NMD::SAVE_16_ , 0, - 0x0 }, /* SAVE[16] */ - { return_instruction , 0 , 0 , 16, - 0xfd00 , 0x1d00 , &NMD::RESTORE_JRC_16_ , 0, - 0x0 }, /* RESTORE.JRC[16] */ -}; - - -NMD::Pool NMD::P16_4X4[4] = { - { instruction , 0 , 0 , 16, - 0xfd08 , 0x3c00 , &NMD::ADDU_4X4_ , 0, - XMMS_ }, /* ADDU[4X4] */ - { instruction , 0 , 0 , 16, - 0xfd08 , 0x3c08 , &NMD::MUL_4X4_ , 0, - XMMS_ }, /* MUL[4X4] */ - { reserved_block , 0 , 0 , 16, - 0xfd08 , 0x3d00 , 0 , 0, - 0x0 }, /* P16.4X4~*(2) */ - { reserved_block , 0 , 0 , 16, - 0xfd08 , 0x3d08 , 0 , 0, - 0x0 }, /* P16.4X4~*(3) */ -}; - - -NMD::Pool NMD::P16_LB[4] = { - { instruction , 0 , 0 , 16, - 0xfc0c , 0x5c00 , &NMD::LB_16_ , 0, - 0x0 }, /* LB[16] */ - { instruction , 0 , 0 , 16, - 0xfc0c , 0x5c04 , &NMD::SB_16_ , 0, - 0x0 }, /* SB[16] */ - { instruction , 0 , 0 , 16, - 0xfc0c , 0x5c08 , &NMD::LBU_16_ , 0, - 0x0 }, /* LBU[16] */ - { reserved_block , 0 , 0 , 16, - 0xfc0c , 0x5c0c , 0 , 0, - 0x0 }, /* P16.LB~*(3) */ -}; - - -NMD::Pool NMD::P16_LH[4] = { - { instruction , 0 , 0 , 16, - 0xfc09 , 0x7c00 , &NMD::LH_16_ , 0, - 0x0 }, /* LH[16] */ - { instruction , 0 , 0 , 16, - 0xfc09 , 0x7c01 , &NMD::SH_16_ , 0, - 0x0 }, /* SH[16] */ - { instruction , 0 , 0 , 16, - 0xfc09 , 0x7c08 , &NMD::LHU_16_ , 0, - 0x0 }, /* LHU[16] */ - { reserved_block , 0 , 0 , 16, - 0xfc09 , 0x7c09 , 0 , 0, - 0x0 }, /* P16.LH~*(3) */ -}; - - -NMD::Pool NMD::P16[32] = { - { pool , P16_MV , 2 , 16, - 0xfc00 , 0x1000 , 0 , 0, - 0x0 }, /* P16.MV */ - { pool , P16_SHIFT , 2 , 16, - 0xfc00 , 0x3000 , 0 , 0, - 0x0 }, /* P16.SHIFT */ - { pool , P16C , 2 , 16, - 0xfc00 , 0x5000 , 0 , 0, - 0x0 }, /* P16C */ - { pool , P16_A1 , 2 , 16, - 0xfc00 , 0x7000 , 0 , 0, - 0x0 }, /* P16.A1 */ - { pool , P16_A2 , 2 , 16, - 0xfc00 , 0x9000 , 0 , 0, - 0x0 }, /* P16.A2 */ - { pool , P16_ADDU , 2 , 16, - 0xfc00 , 0xb000 , 0 , 0, - 0x0 }, /* P16.ADDU */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xd000 , &NMD::LI_16_ , 0, - 0x0 }, /* LI[16] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xf000 , &NMD::ANDI_16_ , 0, - 0x0 }, /* ANDI[16] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0x1400 , &NMD::LW_16_ , 0, - 0x0 }, /* LW[16] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0x3400 , &NMD::LW_SP_ , 0, - 0x0 }, /* LW[SP] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0x5400 , &NMD::LW_GP16_ , 0, - 0x0 }, /* LW[GP16] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0x7400 , &NMD::LW_4X4_ , 0, - XMMS_ }, /* LW[4X4] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0x9400 , &NMD::SW_16_ , 0, - 0x0 }, /* SW[16] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xb400 , &NMD::SW_SP_ , 0, - 0x0 }, /* SW[SP] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xd400 , &NMD::SW_GP16_ , 0, - 0x0 }, /* SW[GP16] */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xf400 , &NMD::SW_4X4_ , 0, - XMMS_ }, /* SW[4X4] */ - { branch_instruction , 0 , 0 , 16, - 0xfc00 , 0x1800 , &NMD::BC_16_ , 0, - 0x0 }, /* BC[16] */ - { call_instruction , 0 , 0 , 16, - 0xfc00 , 0x3800 , &NMD::BALC_16_ , 0, - 0x0 }, /* BALC[16] */ - { reserved_block , 0 , 0 , 16, - 0xfc00 , 0x5800 , 0 , 0, - 0x0 }, /* P16~*(10) */ - { reserved_block , 0 , 0 , 16, - 0xfc00 , 0x7800 , 0 , 0, - 0x0 }, /* P16~*(14) */ - { branch_instruction , 0 , 0 , 16, - 0xfc00 , 0x9800 , &NMD::BEQZC_16_ , 0, - 0x0 }, /* BEQZC[16] */ - { branch_instruction , 0 , 0 , 16, - 0xfc00 , 0xb800 , &NMD::BNEZC_16_ , 0, - 0x0 }, /* BNEZC[16] */ - { pool , P16_BR , 2 , 16, - 0xfc00 , 0xd800 , 0 , 0, - 0x0 }, /* P16.BR */ - { reserved_block , 0 , 0 , 16, - 0xfc00 , 0xf800 , 0 , 0, - 0x0 }, /* P16~*(30) */ - { pool , P16_SR , 2 , 16, - 0xfc00 , 0x1c00 , 0 , 0, - 0x0 }, /* P16.SR */ - { pool , P16_4X4 , 4 , 16, - 0xfc00 , 0x3c00 , 0 , 0, - 0x0 }, /* P16.4X4 */ - { pool , P16_LB , 4 , 16, - 0xfc00 , 0x5c00 , 0 , 0, - 0x0 }, /* P16.LB */ - { pool , P16_LH , 4 , 16, - 0xfc00 , 0x7c00 , 0 , 0, - 0x0 }, /* P16.LH */ - { reserved_block , 0 , 0 , 16, - 0xfc00 , 0x9c00 , 0 , 0, - 0x0 }, /* P16~*(19) */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xbc00 , &NMD::MOVEP , 0, - XMMS_ }, /* MOVEP */ - { reserved_block , 0 , 0 , 16, - 0xfc00 , 0xdc00 , 0 , 0, - 0x0 }, /* P16~*(27) */ - { instruction , 0 , 0 , 16, - 0xfc00 , 0xfc00 , &NMD::MOVEP_REV_ , 0, - XMMS_ }, /* MOVEP[REV] */ -}; - - -NMD::Pool NMD::MAJOR[2] = { - { pool , P32 , 32 , 32, - 0x10000000, 0x00000000, 0 , 0, - 0x0 }, /* P32 */ - { pool , P16 , 32 , 16, - 0x1000 , 0x1000 , 0 , 0, - 0x0 }, /* P16 */ -}; diff --git a/disas/nanomips.h b/disas/nanomips.h deleted file mode 100644 index a0a222530143..000000000000 --- a/disas/nanomips.h +++ /dev/null @@ -1,1076 +0,0 @@ -/* - * Header file for nanoMIPS disassembler component of QEMU - * - * Copyright (C) 2018 Wave Computing, Inc. - * Copyright (C) 2018 Matthew Fortune - * Copyright (C) 2018 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef DISAS_NANOMIPS_H -#define DISAS_NANOMIPS_H - -#include - -typedef int64_t int64; -typedef uint64_t uint64; -typedef uint32_t uint32; -typedef uint16_t uint16; - -namespace img -{ - typedef uint64_t address; -} - - -class NMD -{ -public: - - enum TABLE_ENTRY_TYPE { - instruction, - call_instruction, - branch_instruction, - return_instruction, - reserved_block, - pool, - }; - - enum TABLE_ATTRIBUTE_TYPE { - MIPS64_ = 0x00000001, - XNP_ = 0x00000002, - XMMS_ = 0x00000004, - EVA_ = 0x00000008, - DSP_ = 0x00000010, - MT_ = 0x00000020, - EJTAG_ = 0x00000040, - TLBINV_ = 0x00000080, - CP0_ = 0x00000100, - CP1_ = 0x00000200, - CP2_ = 0x00000400, - UDI_ = 0x00000800, - MCU_ = 0x00001000, - VZ_ = 0x00002000, - TLB_ = 0x00004000, - MVH_ = 0x00008000, - ALL_ATTRIBUTES = 0xffffffffull, - }; - - - NMD(img::address pc, TABLE_ATTRIBUTE_TYPE requested_instruction_categories) - : m_pc(pc) - , m_requested_instruction_categories(requested_instruction_categories) - { - } - - int Disassemble(const uint16 *data, std::string & dis, - TABLE_ENTRY_TYPE & type); - -private: - - img::address m_pc; - TABLE_ATTRIBUTE_TYPE m_requested_instruction_categories; - - typedef std::string(NMD:: *disassembly_function)(uint64 instruction); - typedef bool(NMD:: *conditional_function)(uint64 instruction); - - struct Pool { - TABLE_ENTRY_TYPE type; - struct Pool *next_table; - int next_table_size; - int instructions_size; - uint64 mask; - uint64 value; - disassembly_function disassembly; - conditional_function condition; - uint64 attributes; - }; - - uint64 extract_op_code_value(const uint16 *data, int size); - int Disassemble(const uint16 *data, std::string & dis, - TABLE_ENTRY_TYPE & type, const Pool *table, int table_size); - - uint64 renumber_registers(uint64 index, uint64 *register_list, - size_t register_list_size); - - uint64 decode_gpr_gpr4(uint64 d); - uint64 decode_gpr_gpr4_zero(uint64 d); - uint64 decode_gpr_gpr3(uint64 d); - uint64 decode_gpr_gpr3_src_store(uint64 d); - uint64 decode_gpr_gpr2_reg1(uint64 d); - uint64 decode_gpr_gpr2_reg2(uint64 d); - uint64 decode_gpr_gpr1(uint64 d); - - uint64 copy(uint64 d); - int64 copy(int64 d); - int64 neg_copy(uint64 d); - int64 neg_copy(int64 d); - uint64 encode_rs3_and_check_rs3_ge_rt3(uint64 d); - uint64 encode_rs3_and_check_rs3_lt_rt3(uint64 d); - uint64 encode_s_from_address(uint64 d); - uint64 encode_u_from_address(uint64 d); - uint64 encode_s_from_s_hi(uint64 d); - uint64 encode_count3_from_count(uint64 d); - uint64 encode_shift3_from_shift(uint64 d); - int64 encode_eu_from_s_li16(uint64 d); - uint64 encode_msbd_from_size(uint64 d); - uint64 encode_eu_from_u_andi16(uint64 d); - - uint64 encode_msbd_from_pos_and_size(uint64 d); - - uint64 encode_rt1_from_rt(uint64 d); - uint64 encode_lsb_from_pos_and_size(uint64 d); - - std::string save_restore_list(uint64 rt, uint64 count, uint64 gp); - - std::string GPR(uint64 reg); - std::string FPR(uint64 reg); - std::string AC(uint64 reg); - std::string IMMEDIATE(uint64 value); - std::string IMMEDIATE(int64 value); - std::string CPR(uint64 reg); - std::string ADDRESS(uint64 value, int instruction_size); - - int64 extract_s__se3_4_2_1_0(uint64 instruction); - int64 extract_s__se7_0_6_5_4_3_2_1_s1(uint64 instruction); - int64 extract_s__se8_15_7_6_5_4_3_s3(uint64 instruction); - int64 extract_s__se8_15_7_6_5_4_3_2_s2(uint64 instruction); - int64 extract_s__se8_15_7_6_5_4_3_2_1_0(uint64 instruction); - int64 extract_s__se9_20_19_18_17_16_15_14_13_12_11(uint64 instruction); - int64 extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(uint64 instruction); - int64 extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(uint64 instruction); - int64 extract_s__se14_0_13_to_1_s1(uint64 instruction); - int64 extract_s__se21_0_20_to_1_s1(uint64 instruction); - int64 extract_s__se25_0_24_to_1_s1(uint64 instruction); - int64 extract_s__se31_15_to_0_31_to_16(uint64 instruction); - int64 extract_s__se31_0_11_to_2_20_to_12_s12(uint64 instruction); - int64 extract_shift__se5_21_20_19_18_17_16(uint64 instruction); - - uint64 extract_ac_15_14(uint64 instruction); - uint64 extract_bit_16_15_14_13_12_11(uint64 instruction); - uint64 extract_bit_23_22_21(uint64 instruction); - uint64 extract_c0s_20_19_18_17_16(uint64 instruction); - uint64 extract_code_17_to_0(uint64 instruction); - uint64 extract_code_18_to_0(uint64 instruction); - uint64 extract_code_1_0(uint64 instruction); - uint64 extract_code_2_1_0(uint64 instruction); - uint64 extract_code_25_24_23_22_21_20_19_18_17_16(uint64 instruction); - uint64 extract_cofun_25_24_23(uint64 instruction); - uint64 extract_count3_14_13_12(uint64 instruction); - uint64 extract_count_3_2_1_0(uint64 instruction); - uint64 extract_count_19_18_17_16(uint64 instruction); - uint64 extract_cs_20_19_18_17_16(uint64 instruction); - uint64 extract_cs_25_24_23_22_21(uint64 instruction); - uint64 extract_ct_25_24_23_22_21(uint64 instruction); - uint64 extract_eu_3_2_1_0(uint64 instruction); - uint64 extract_eu_6_5_4_3_2_1_0(uint64 instruction); - uint64 extract_fd_15_14_13_12_11(uint64 instruction); - uint64 extract_fs_20_19_18_17_16(uint64 instruction); - uint64 extract_ft_15_14_13_12_11(uint64 instruction); - uint64 extract_ft_25_24_23_22_21(uint64 instruction); - uint64 extract_gp_2(uint64 instruction); - uint64 extract_hint_25_24_23_22_21(uint64 instruction); - uint64 extract_hs_20_19_18_17_16(uint64 instruction); - uint64 extract_lsb_4_3_2_1_0(uint64 instruction); - uint64 extract_mask_20_19_18_17_16_15_14(uint64 instruction); - uint64 extract_msbt_10_9_8_7_6(uint64 instruction); - uint64 extract_op_25_24_23_22_21(uint64 instruction); - uint64 extract_op_25_to_3(uint64 instruction); - uint64 extract_rdl_25_24(uint64 instruction); - uint64 extract_rd2_3_8(uint64 instruction); - uint64 extract_rd3_3_2_1(uint64 instruction); - uint64 extract_rd_15_14_13_12_11(uint64 instruction); - uint64 extract_rs3_6_5_4(uint64 instruction); - uint64 extract_rs4_4_2_1_0(uint64 instruction); - uint64 extract_rs_4_3_2_1_0(uint64 instruction); - uint64 extract_rs_20_19_18_17_16(uint64 instruction); - uint64 extract_rsz4_4_2_1_0(uint64 instruction); - uint64 extract_rtl_11(uint64 instruction); - uint64 extract_rt3_9_8_7(uint64 instruction); - uint64 extract_rt4_9_7_6_5(uint64 instruction); - uint64 extract_rt_25_24_23_22_21(uint64 instruction); - uint64 extract_rt_41_40_39_38_37(uint64 instruction); - uint64 extract_rt_9_8_7_6_5(uint64 instruction); - uint64 extract_rtz3_9_8_7(uint64 instruction); - uint64 extract_rtz4_27_26_25_23_22_21(uint64 instruction); - uint64 extract_rtz4_9_7_6_5(uint64 instruction); - uint64 extract_ru_7_6_5_4_3(uint64 instruction); - uint64 extract_sa_15_14_13_12_11(uint64 instruction); - uint64 extract_sa_15_14_13_12(uint64 instruction); - uint64 extract_sa_15_14_13(uint64 instruction); - uint64 extract_sel_13_12_11(uint64 instruction); - uint64 extract_sel_15_14_13_12_11(uint64 instruction); - uint64 extract_shift3_2_1_0(uint64 instruction); - uint64 extract_shift_4_3_2_1_0(uint64 instruction); - uint64 extract_shift_5_4_3_2_1_0(uint64 instruction); - uint64 extract_shift_20_19_18_17_16(uint64 instruction); - uint64 extract_shift_10_9_8_7_6(uint64 instruction); - uint64 extract_shiftx_11_10_9_8_7_6(uint64 instruction); - uint64 extract_shiftx_10_9_8_7__s1(uint64 instruction); - uint64 extract_size_20_19_18_17_16(uint64 instruction); - uint64 extract_stripe_6(uint64 instruction); - uint64 extract_stype_20_19_18_17_16(uint64 instruction); - uint64 extract_u2_10_9(uint64 instruction); - uint64 extract_u_11_10_9_8_7_6_5_4_3_2_1_0(uint64 instruction); - uint64 extract_u_15_to_0(uint64 instruction); - uint64 extract_u_17_to_0(uint64 instruction); - uint64 extract_u_1_0(uint64 instruction); - uint64 extract_u_3_2_1_0__s1(uint64 instruction); - uint64 extract_u_2_1_0__s2(uint64 instruction); - uint64 extract_u_3_2_1_0__s2(uint64 instruction); - uint64 extract_u_4_3_2_1_0__s2(uint64 instruction); - uint64 extract_u_5_4_3_2_1_0__s2(uint64 instruction); - uint64 extract_u_6_5_4_3_2_1_0__s2(uint64 instruction); - uint64 extract_u_31_to_0__s32(uint64 instruction); - uint64 extract_u_10(uint64 instruction); - uint64 extract_u_17_16_15_14_13_12_11(uint64 instruction); - uint64 extract_u_20_19_18_17_16_15_14_13(uint64 instruction); - uint64 extract_u_17_to_1__s1(uint64 instruction); - uint64 extract_u_2_1__s1(uint64 instruction); - uint64 extract_u_17_to_2__s2(uint64 instruction); - uint64 extract_u_20_to_2__s2(uint64 instruction); - uint64 extract_u_20_to_3__s3(uint64 instruction); - uint64 extract_u_3_8__s2(uint64 instruction); - uint64 extract_u_11_10_9_8_7_6_5_4_3__s3(uint64 instruction); - uint64 extract_u_7_6_5_4__s4(uint64 instruction); - - bool ADDIU_32__cond(uint64 instruction); - bool ADDIU_RS5__cond(uint64 instruction); - bool BALRSC_cond(uint64 instruction); - bool BEQC_16__cond(uint64 instruction); - bool BNEC_16__cond(uint64 instruction); - bool MOVE_cond(uint64 instruction); - bool P16_BR1_cond(uint64 instruction); - bool PREF_S9__cond(uint64 instruction); - bool PREFE_cond(uint64 instruction); - bool SLTU_cond(uint64 instruction); - - std::string ABS_D(uint64 instruction); - std::string ABS_S(uint64 instruction); - std::string ABSQ_S_PH(uint64 instruction); - std::string ABSQ_S_QB(uint64 instruction); - std::string ABSQ_S_W(uint64 instruction); - std::string ACLR(uint64 instruction); - std::string ADD(uint64 instruction); - std::string ADD_D(uint64 instruction); - std::string ADD_S(uint64 instruction); - std::string ADDIU_32_(uint64 instruction); - std::string ADDIU_48_(uint64 instruction); - std::string ADDIU_GP48_(uint64 instruction); - std::string ADDIU_GP_B_(uint64 instruction); - std::string ADDIU_GP_W_(uint64 instruction); - std::string ADDIU_NEG_(uint64 instruction); - std::string ADDIU_R1_SP_(uint64 instruction); - std::string ADDIU_R2_(uint64 instruction); - std::string ADDIU_RS5_(uint64 instruction); - std::string ADDIUPC_32_(uint64 instruction); - std::string ADDIUPC_48_(uint64 instruction); - std::string ADDQ_PH(uint64 instruction); - std::string ADDQ_S_PH(uint64 instruction); - std::string ADDQ_S_W(uint64 instruction); - std::string ADDQH_PH(uint64 instruction); - std::string ADDQH_R_PH(uint64 instruction); - std::string ADDQH_R_W(uint64 instruction); - std::string ADDQH_W(uint64 instruction); - std::string ADDSC(uint64 instruction); - std::string ADDU_16_(uint64 instruction); - std::string ADDU_32_(uint64 instruction); - std::string ADDU_4X4_(uint64 instruction); - std::string ADDU_PH(uint64 instruction); - std::string ADDU_QB(uint64 instruction); - std::string ADDU_S_PH(uint64 instruction); - std::string ADDU_S_QB(uint64 instruction); - std::string ADDUH_QB(uint64 instruction); - std::string ADDUH_R_QB(uint64 instruction); - std::string ADDWC(uint64 instruction); - std::string ALUIPC(uint64 instruction); - std::string AND_16_(uint64 instruction); - std::string AND_32_(uint64 instruction); - std::string ANDI_16_(uint64 instruction); - std::string ANDI_32_(uint64 instruction); - std::string APPEND(uint64 instruction); - std::string ASET(uint64 instruction); - std::string BALC_16_(uint64 instruction); - std::string BALC_32_(uint64 instruction); - std::string BALRSC(uint64 instruction); - std::string BBEQZC(uint64 instruction); - std::string BBNEZC(uint64 instruction); - std::string BC_16_(uint64 instruction); - std::string BC_32_(uint64 instruction); - std::string BC1EQZC(uint64 instruction); - std::string BC1NEZC(uint64 instruction); - std::string BC2EQZC(uint64 instruction); - std::string BC2NEZC(uint64 instruction); - std::string BEQC_16_(uint64 instruction); - std::string BEQC_32_(uint64 instruction); - std::string BEQIC(uint64 instruction); - std::string BEQZC_16_(uint64 instruction); - std::string BGEC(uint64 instruction); - std::string BGEIC(uint64 instruction); - std::string BGEIUC(uint64 instruction); - std::string BGEUC(uint64 instruction); - std::string BLTC(uint64 instruction); - std::string BLTIC(uint64 instruction); - std::string BLTIUC(uint64 instruction); - std::string BLTUC(uint64 instruction); - std::string BNEC_16_(uint64 instruction); - std::string BNEC_32_(uint64 instruction); - std::string BNEIC(uint64 instruction); - std::string BNEZC_16_(uint64 instruction); - std::string BPOSGE32C(uint64 instruction); - std::string BREAK_16_(uint64 instruction); - std::string BREAK_32_(uint64 instruction); - std::string BRSC(uint64 instruction); - std::string CACHE(uint64 instruction); - std::string CACHEE(uint64 instruction); - std::string CEIL_L_D(uint64 instruction); - std::string CEIL_L_S(uint64 instruction); - std::string CEIL_W_D(uint64 instruction); - std::string CEIL_W_S(uint64 instruction); - std::string CFC1(uint64 instruction); - std::string CFC2(uint64 instruction); - std::string CLASS_D(uint64 instruction); - std::string CLASS_S(uint64 instruction); - std::string CLO(uint64 instruction); - std::string CLZ(uint64 instruction); - std::string CMP_AF_D(uint64 instruction); - std::string CMP_AF_S(uint64 instruction); - std::string CMP_EQ_D(uint64 instruction); - std::string CMP_EQ_PH(uint64 instruction); - std::string CMP_EQ_S(uint64 instruction); - std::string CMP_LE_D(uint64 instruction); - std::string CMP_LE_PH(uint64 instruction); - std::string CMP_LE_S(uint64 instruction); - std::string CMP_LT_D(uint64 instruction); - std::string CMP_LT_PH(uint64 instruction); - std::string CMP_LT_S(uint64 instruction); - std::string CMP_NE_D(uint64 instruction); - std::string CMP_NE_S(uint64 instruction); - std::string CMP_OR_D(uint64 instruction); - std::string CMP_OR_S(uint64 instruction); - std::string CMP_SAF_D(uint64 instruction); - std::string CMP_SAF_S(uint64 instruction); - std::string CMP_SEQ_D(uint64 instruction); - std::string CMP_SEQ_S(uint64 instruction); - std::string CMP_SLE_D(uint64 instruction); - std::string CMP_SLE_S(uint64 instruction); - std::string CMP_SLT_D(uint64 instruction); - std::string CMP_SLT_S(uint64 instruction); - std::string CMP_SNE_D(uint64 instruction); - std::string CMP_SNE_S(uint64 instruction); - std::string CMP_SOR_D(uint64 instruction); - std::string CMP_SOR_S(uint64 instruction); - std::string CMP_SUEQ_D(uint64 instruction); - std::string CMP_SUEQ_S(uint64 instruction); - std::string CMP_SULE_D(uint64 instruction); - std::string CMP_SULE_S(uint64 instruction); - std::string CMP_SULT_D(uint64 instruction); - std::string CMP_SULT_S(uint64 instruction); - std::string CMP_SUN_D(uint64 instruction); - std::string CMP_SUN_S(uint64 instruction); - std::string CMP_SUNE_D(uint64 instruction); - std::string CMP_SUNE_S(uint64 instruction); - std::string CMP_UEQ_D(uint64 instruction); - std::string CMP_UEQ_S(uint64 instruction); - std::string CMP_ULE_D(uint64 instruction); - std::string CMP_ULE_S(uint64 instruction); - std::string CMP_ULT_D(uint64 instruction); - std::string CMP_ULT_S(uint64 instruction); - std::string CMP_UN_D(uint64 instruction); - std::string CMP_UN_S(uint64 instruction); - std::string CMP_UNE_D(uint64 instruction); - std::string CMP_UNE_S(uint64 instruction); - std::string CMPGDU_EQ_QB(uint64 instruction); - std::string CMPGDU_LE_QB(uint64 instruction); - std::string CMPGDU_LT_QB(uint64 instruction); - std::string CMPGU_EQ_QB(uint64 instruction); - std::string CMPGU_LE_QB(uint64 instruction); - std::string CMPGU_LT_QB(uint64 instruction); - std::string CMPU_EQ_QB(uint64 instruction); - std::string CMPU_LE_QB(uint64 instruction); - std::string CMPU_LT_QB(uint64 instruction); - std::string COP2_1(uint64 instruction); - std::string CTC1(uint64 instruction); - std::string CTC2(uint64 instruction); - std::string CVT_D_L(uint64 instruction); - std::string CVT_D_S(uint64 instruction); - std::string CVT_D_W(uint64 instruction); - std::string CVT_L_D(uint64 instruction); - std::string CVT_L_S(uint64 instruction); - std::string CVT_S_D(uint64 instruction); - std::string CVT_S_L(uint64 instruction); - std::string CVT_S_PL(uint64 instruction); - std::string CVT_S_PU(uint64 instruction); - std::string CVT_S_W(uint64 instruction); - std::string CVT_W_D(uint64 instruction); - std::string CVT_W_S(uint64 instruction); - std::string DADDIU_48_(uint64 instruction); - std::string DADDIU_NEG_(uint64 instruction); - std::string DADDIU_U12_(uint64 instruction); - std::string DADD(uint64 instruction); - std::string DADDU(uint64 instruction); - std::string DCLO(uint64 instruction); - std::string DCLZ(uint64 instruction); - std::string DDIV(uint64 instruction); - std::string DDIVU(uint64 instruction); - std::string DERET(uint64 instruction); - std::string DEXTM(uint64 instruction); - std::string DEXT(uint64 instruction); - std::string DEXTU(uint64 instruction); - std::string DINSM(uint64 instruction); - std::string DINS(uint64 instruction); - std::string DINSU(uint64 instruction); - std::string DI(uint64 instruction); - std::string DIV(uint64 instruction); - std::string DIV_D(uint64 instruction); - std::string DIV_S(uint64 instruction); - std::string DIVU(uint64 instruction); - std::string DLSA(uint64 instruction); - std::string DLUI_48_(uint64 instruction); - std::string DMFC0(uint64 instruction); - std::string DMFC1(uint64 instruction); - std::string DMFC2(uint64 instruction); - std::string DMFGC0(uint64 instruction); - std::string DMOD(uint64 instruction); - std::string DMODU(uint64 instruction); - std::string DMTC0(uint64 instruction); - std::string DMTC1(uint64 instruction); - std::string DMTC2(uint64 instruction); - std::string DMTGC0(uint64 instruction); - std::string DMT(uint64 instruction); - std::string DMUH(uint64 instruction); - std::string DMUHU(uint64 instruction); - std::string DMUL(uint64 instruction); - std::string DMULU(uint64 instruction); - std::string DPAQ_S_W_PH(uint64 instruction); - std::string DPAQ_SA_L_W(uint64 instruction); - std::string DPAQX_S_W_PH(uint64 instruction); - std::string DPAQX_SA_W_PH(uint64 instruction); - std::string DPAU_H_QBL(uint64 instruction); - std::string DPAU_H_QBR(uint64 instruction); - std::string DPA_W_PH(uint64 instruction); - std::string DPAX_W_PH(uint64 instruction); - std::string DPS_W_PH(uint64 instruction); - std::string DPSQ_SA_L_W(uint64 instruction); - std::string DPSQ_S_W_PH(uint64 instruction); - std::string DPSQX_SA_W_PH(uint64 instruction); - std::string DPSQX_S_W_PH(uint64 instruction); - std::string DPSU_H_QBL(uint64 instruction); - std::string DPSU_H_QBR(uint64 instruction); - std::string DPSX_W_PH(uint64 instruction); - std::string DROTR(uint64 instruction); - std::string DROTR32(uint64 instruction); - std::string DROTRV(uint64 instruction); - std::string DROTX(uint64 instruction); - std::string DSLL(uint64 instruction); - std::string DSLL32(uint64 instruction); - std::string DSLLV(uint64 instruction); - std::string DSRA(uint64 instruction); - std::string DSRA32(uint64 instruction); - std::string DSRAV(uint64 instruction); - std::string DSRL32(uint64 instruction); - std::string DSRL(uint64 instruction); - std::string DSRLV(uint64 instruction); - std::string DSUB(uint64 instruction); - std::string DSUBU(uint64 instruction); - std::string DVP(uint64 instruction); - std::string DVPE(uint64 instruction); - std::string EHB(uint64 instruction); - std::string EI(uint64 instruction); - std::string EMT(uint64 instruction); - std::string ERET(uint64 instruction); - std::string ERETNC(uint64 instruction); - std::string EVP(uint64 instruction); - std::string EVPE(uint64 instruction); - std::string EXT(uint64 instruction); - std::string EXTD(uint64 instruction); - std::string EXTD32(uint64 instruction); - std::string EXTP(uint64 instruction); - std::string EXTPDP(uint64 instruction); - std::string EXTPDPV(uint64 instruction); - std::string EXTPV(uint64 instruction); - std::string EXTR_RS_W(uint64 instruction); - std::string EXTR_R_W(uint64 instruction); - std::string EXTR_S_H(uint64 instruction); - std::string EXTR_W(uint64 instruction); - std::string EXTRV_R_W(uint64 instruction); - std::string EXTRV_RS_W(uint64 instruction); - std::string EXTRV_S_H(uint64 instruction); - std::string EXTRV_W(uint64 instruction); - std::string EXTW(uint64 instruction); - std::string FLOOR_L_D(uint64 instruction); - std::string FLOOR_L_S(uint64 instruction); - std::string FLOOR_W_D(uint64 instruction); - std::string FLOOR_W_S(uint64 instruction); - std::string FORK(uint64 instruction); - std::string HYPCALL(uint64 instruction); - std::string HYPCALL_16_(uint64 instruction); - std::string INS(uint64 instruction); - std::string INSV(uint64 instruction); - std::string IRET(uint64 instruction); - std::string JALRC_16_(uint64 instruction); - std::string JALRC_32_(uint64 instruction); - std::string JALRC_HB(uint64 instruction); - std::string JRC(uint64 instruction); - std::string LB_16_(uint64 instruction); - std::string LB_GP_(uint64 instruction); - std::string LB_S9_(uint64 instruction); - std::string LB_U12_(uint64 instruction); - std::string LBE(uint64 instruction); - std::string LBU_16_(uint64 instruction); - std::string LBU_GP_(uint64 instruction); - std::string LBU_S9_(uint64 instruction); - std::string LBU_U12_(uint64 instruction); - std::string LBUE(uint64 instruction); - std::string LBUX(uint64 instruction); - std::string LBX(uint64 instruction); - std::string LD_GP_(uint64 instruction); - std::string LD_S9_(uint64 instruction); - std::string LD_U12_(uint64 instruction); - std::string LDC1_GP_(uint64 instruction); - std::string LDC1_S9_(uint64 instruction); - std::string LDC1_U12_(uint64 instruction); - std::string LDC1X(uint64 instruction); - std::string LDC1XS(uint64 instruction); - std::string LDC2(uint64 instruction); - std::string LDM(uint64 instruction); - std::string LDPC_48_(uint64 instruction); - std::string LDX(uint64 instruction); - std::string LDXS(uint64 instruction); - std::string LH_16_(uint64 instruction); - std::string LH_GP_(uint64 instruction); - std::string LH_S9_(uint64 instruction); - std::string LH_U12_(uint64 instruction); - std::string LHE(uint64 instruction); - std::string LHU_16_(uint64 instruction); - std::string LHU_GP_(uint64 instruction); - std::string LHU_S9_(uint64 instruction); - std::string LHU_U12_(uint64 instruction); - std::string LHUE(uint64 instruction); - std::string LHUX(uint64 instruction); - std::string LHUXS(uint64 instruction); - std::string LHX(uint64 instruction); - std::string LHXS(uint64 instruction); - std::string LI_16_(uint64 instruction); - std::string LI_48_(uint64 instruction); - std::string LL(uint64 instruction); - std::string LLD(uint64 instruction); - std::string LLDP(uint64 instruction); - std::string LLE(uint64 instruction); - std::string LLWP(uint64 instruction); - std::string LLWPE(uint64 instruction); - std::string LSA(uint64 instruction); - std::string LUI(uint64 instruction); - std::string LW_16_(uint64 instruction); - std::string LW_4X4_(uint64 instruction); - std::string LWC1_GP_(uint64 instruction); - std::string LWC1_S9_(uint64 instruction); - std::string LWC1_U12_(uint64 instruction); - std::string LWC1X(uint64 instruction); - std::string LWC1XS(uint64 instruction); - std::string LWC2(uint64 instruction); - std::string LWE(uint64 instruction); - std::string LW_GP_(uint64 instruction); - std::string LW_GP16_(uint64 instruction); - std::string LWM(uint64 instruction); - std::string LWPC_48_(uint64 instruction); - std::string LW_S9_(uint64 instruction); - std::string LW_SP_(uint64 instruction); - std::string LW_U12_(uint64 instruction); - std::string LWU_GP_(uint64 instruction); - std::string LWU_S9_(uint64 instruction); - std::string LWU_U12_(uint64 instruction); - std::string LWUX(uint64 instruction); - std::string LWUXS(uint64 instruction); - std::string LWX(uint64 instruction); - std::string LWXS_16_(uint64 instruction); - std::string LWXS_32_(uint64 instruction); - std::string MADD_DSP_(uint64 instruction); - std::string MADDF_D(uint64 instruction); - std::string MADDF_S(uint64 instruction); - std::string MADDU_DSP_(uint64 instruction); - std::string MAQ_S_W_PHL(uint64 instruction); - std::string MAQ_S_W_PHR(uint64 instruction); - std::string MAQ_SA_W_PHL(uint64 instruction); - std::string MAQ_SA_W_PHR(uint64 instruction); - std::string MAX_D(uint64 instruction); - std::string MAX_S(uint64 instruction); - std::string MAXA_D(uint64 instruction); - std::string MAXA_S(uint64 instruction); - std::string MFC0(uint64 instruction); - std::string MFC1(uint64 instruction); - std::string MFC2(uint64 instruction); - std::string MFGC0(uint64 instruction); - std::string MFHC0(uint64 instruction); - std::string MFHC1(uint64 instruction); - std::string MFHC2(uint64 instruction); - std::string MFHGC0(uint64 instruction); - std::string MFHI_DSP_(uint64 instruction); - std::string MFHTR(uint64 instruction); - std::string MFLO_DSP_(uint64 instruction); - std::string MFTR(uint64 instruction); - std::string MIN_D(uint64 instruction); - std::string MIN_S(uint64 instruction); - std::string MINA_D(uint64 instruction); - std::string MINA_S(uint64 instruction); - std::string MOD(uint64 instruction); - std::string MODSUB(uint64 instruction); - std::string MODU(uint64 instruction); - std::string MOV_D(uint64 instruction); - std::string MOV_S(uint64 instruction); - std::string MOVE_BALC(uint64 instruction); - std::string MOVEP(uint64 instruction); - std::string MOVEP_REV_(uint64 instruction); - std::string MOVE(uint64 instruction); - std::string MOVN(uint64 instruction); - std::string MOVZ(uint64 instruction); - std::string MSUB_DSP_(uint64 instruction); - std::string MSUBF_D(uint64 instruction); - std::string MSUBF_S(uint64 instruction); - std::string MSUBU_DSP_(uint64 instruction); - std::string MTC0(uint64 instruction); - std::string MTC1(uint64 instruction); - std::string MTC2(uint64 instruction); - std::string MTGC0(uint64 instruction); - std::string MTHC0(uint64 instruction); - std::string MTHC1(uint64 instruction); - std::string MTHC2(uint64 instruction); - std::string MTHGC0(uint64 instruction); - std::string MTHI_DSP_(uint64 instruction); - std::string MTHLIP(uint64 instruction); - std::string MTHTR(uint64 instruction); - std::string MTLO_DSP_(uint64 instruction); - std::string MTTR(uint64 instruction); - std::string MUH(uint64 instruction); - std::string MUHU(uint64 instruction); - std::string MUL_32_(uint64 instruction); - std::string MUL_4X4_(uint64 instruction); - std::string MUL_D(uint64 instruction); - std::string MUL_PH(uint64 instruction); - std::string MUL_S(uint64 instruction); - std::string MUL_S_PH(uint64 instruction); - std::string MULEQ_S_W_PHL(uint64 instruction); - std::string MULEQ_S_W_PHR(uint64 instruction); - std::string MULEU_S_PH_QBL(uint64 instruction); - std::string MULEU_S_PH_QBR(uint64 instruction); - std::string MULQ_RS_PH(uint64 instruction); - std::string MULQ_RS_W(uint64 instruction); - std::string MULQ_S_PH(uint64 instruction); - std::string MULQ_S_W(uint64 instruction); - std::string MULSA_W_PH(uint64 instruction); - std::string MULSAQ_S_W_PH(uint64 instruction); - std::string MULT_DSP_(uint64 instruction); - std::string MULTU_DSP_(uint64 instruction); - std::string MULU(uint64 instruction); - std::string NEG_D(uint64 instruction); - std::string NEG_S(uint64 instruction); - std::string NOP_16_(uint64 instruction); - std::string NOP_32_(uint64 instruction); - std::string NOR(uint64 instruction); - std::string NOT_16_(uint64 instruction); - std::string OR_16_(uint64 instruction); - std::string OR_32_(uint64 instruction); - std::string ORI(uint64 instruction); - std::string PACKRL_PH(uint64 instruction); - std::string PAUSE(uint64 instruction); - std::string PICK_PH(uint64 instruction); - std::string PICK_QB(uint64 instruction); - std::string PRECEQ_W_PHL(uint64 instruction); - std::string PRECEQ_W_PHR(uint64 instruction); - std::string PRECEQU_PH_QBL(uint64 instruction); - std::string PRECEQU_PH_QBLA(uint64 instruction); - std::string PRECEQU_PH_QBR(uint64 instruction); - std::string PRECEQU_PH_QBRA(uint64 instruction); - std::string PRECEU_PH_QBL(uint64 instruction); - std::string PRECEU_PH_QBLA(uint64 instruction); - std::string PRECEU_PH_QBR(uint64 instruction); - std::string PRECEU_PH_QBRA(uint64 instruction); - std::string PRECR_QB_PH(uint64 instruction); - std::string PRECR_SRA_PH_W(uint64 instruction); - std::string PRECR_SRA_R_PH_W(uint64 instruction); - std::string PRECRQ_PH_W(uint64 instruction); - std::string PRECRQ_QB_PH(uint64 instruction); - std::string PRECRQ_RS_PH_W(uint64 instruction); - std::string PRECRQU_S_QB_PH(uint64 instruction); - std::string PREF_S9_(uint64 instruction); - std::string PREF_U12_(uint64 instruction); - std::string PREFE(uint64 instruction); - std::string PREPEND(uint64 instruction); - std::string RADDU_W_QB(uint64 instruction); - std::string RDDSP(uint64 instruction); - std::string RDHWR(uint64 instruction); - std::string RDPGPR(uint64 instruction); - std::string RECIP_D(uint64 instruction); - std::string RECIP_S(uint64 instruction); - std::string REPL_PH(uint64 instruction); - std::string REPL_QB(uint64 instruction); - std::string REPLV_PH(uint64 instruction); - std::string REPLV_QB(uint64 instruction); - std::string RESTORE_32_(uint64 instruction); - std::string RESTORE_JRC_16_(uint64 instruction); - std::string RESTORE_JRC_32_(uint64 instruction); - std::string RESTOREF(uint64 instruction); - std::string RINT_D(uint64 instruction); - std::string RINT_S(uint64 instruction); - std::string ROTR(uint64 instruction); - std::string ROTRV(uint64 instruction); - std::string ROTX(uint64 instruction); - std::string ROUND_L_D(uint64 instruction); - std::string ROUND_L_S(uint64 instruction); - std::string ROUND_W_D(uint64 instruction); - std::string ROUND_W_S(uint64 instruction); - std::string RSQRT_D(uint64 instruction); - std::string RSQRT_S(uint64 instruction); - std::string SAVE_16_(uint64 instruction); - std::string SAVE_32_(uint64 instruction); - std::string SAVEF(uint64 instruction); - std::string SB_16_(uint64 instruction); - std::string SB_GP_(uint64 instruction); - std::string SB_S9_(uint64 instruction); - std::string SB_U12_(uint64 instruction); - std::string SBE(uint64 instruction); - std::string SBX(uint64 instruction); - std::string SC(uint64 instruction); - std::string SCD(uint64 instruction); - std::string SCDP(uint64 instruction); - std::string SCE(uint64 instruction); - std::string SCWP(uint64 instruction); - std::string SCWPE(uint64 instruction); - std::string SD_GP_(uint64 instruction); - std::string SD_S9_(uint64 instruction); - std::string SD_U12_(uint64 instruction); - std::string SDBBP_16_(uint64 instruction); - std::string SDBBP_32_(uint64 instruction); - std::string SDC1_GP_(uint64 instruction); - std::string SDC1_S9_(uint64 instruction); - std::string SDC1_U12_(uint64 instruction); - std::string SDC1X(uint64 instruction); - std::string SDC1XS(uint64 instruction); - std::string SDC2(uint64 instruction); - std::string SDM(uint64 instruction); - std::string SDPC_48_(uint64 instruction); - std::string SDX(uint64 instruction); - std::string SDXS(uint64 instruction); - std::string SEB(uint64 instruction); - std::string SEH(uint64 instruction); - std::string SEL_D(uint64 instruction); - std::string SEL_S(uint64 instruction); - std::string SELEQZ_D(uint64 instruction); - std::string SELEQZ_S(uint64 instruction); - std::string SELNEZ_D(uint64 instruction); - std::string SELNEZ_S(uint64 instruction); - std::string SEQI(uint64 instruction); - std::string SH_16_(uint64 instruction); - std::string SH_GP_(uint64 instruction); - std::string SH_S9_(uint64 instruction); - std::string SH_U12_(uint64 instruction); - std::string SHE(uint64 instruction); - std::string SHILO(uint64 instruction); - std::string SHILOV(uint64 instruction); - std::string SHLL_PH(uint64 instruction); - std::string SHLL_QB(uint64 instruction); - std::string SHLL_S_PH(uint64 instruction); - std::string SHLL_S_W(uint64 instruction); - std::string SHLLV_PH(uint64 instruction); - std::string SHLLV_QB(uint64 instruction); - std::string SHLLV_S_PH(uint64 instruction); - std::string SHLLV_S_W(uint64 instruction); - std::string SHRA_PH(uint64 instruction); - std::string SHRA_QB(uint64 instruction); - std::string SHRA_R_PH(uint64 instruction); - std::string SHRA_R_QB(uint64 instruction); - std::string SHRA_R_W(uint64 instruction); - std::string SHRAV_PH(uint64 instruction); - std::string SHRAV_QB(uint64 instruction); - std::string SHRAV_R_PH(uint64 instruction); - std::string SHRAV_R_QB(uint64 instruction); - std::string SHRAV_R_W(uint64 instruction); - std::string SHRL_PH(uint64 instruction); - std::string SHRL_QB(uint64 instruction); - std::string SHRLV_PH(uint64 instruction); - std::string SHRLV_QB(uint64 instruction); - std::string SHX(uint64 instruction); - std::string SHXS(uint64 instruction); - std::string SIGRIE(uint64 instruction); - std::string SLL_16_(uint64 instruction); - std::string SLL_32_(uint64 instruction); - std::string SLLV(uint64 instruction); - std::string SLT(uint64 instruction); - std::string SLTI(uint64 instruction); - std::string SLTIU(uint64 instruction); - std::string SLTU(uint64 instruction); - std::string SOV(uint64 instruction); - std::string SPECIAL2(uint64 instruction); - std::string SQRT_D(uint64 instruction); - std::string SQRT_S(uint64 instruction); - std::string SRA(uint64 instruction); - std::string SRAV(uint64 instruction); - std::string SRL_16_(uint64 instruction); - std::string SRL_32_(uint64 instruction); - std::string SRLV(uint64 instruction); - std::string SUB(uint64 instruction); - std::string SUB_D(uint64 instruction); - std::string SUB_S(uint64 instruction); - std::string SUBQ_PH(uint64 instruction); - std::string SUBQ_S_PH(uint64 instruction); - std::string SUBQ_S_W(uint64 instruction); - std::string SUBQH_PH(uint64 instruction); - std::string SUBQH_R_PH(uint64 instruction); - std::string SUBQH_R_W(uint64 instruction); - std::string SUBQH_W(uint64 instruction); - std::string SUBU_16_(uint64 instruction); - std::string SUBU_32_(uint64 instruction); - std::string SUBU_PH(uint64 instruction); - std::string SUBU_QB(uint64 instruction); - std::string SUBU_S_PH(uint64 instruction); - std::string SUBU_S_QB(uint64 instruction); - std::string SUBUH_QB(uint64 instruction); - std::string SUBUH_R_QB(uint64 instruction); - std::string SW_16_(uint64 instruction); - std::string SW_4X4_(uint64 instruction); - std::string SW_GP16_(uint64 instruction); - std::string SW_GP_(uint64 instruction); - std::string SW_S9_(uint64 instruction); - std::string SW_SP_(uint64 instruction); - std::string SW_U12_(uint64 instruction); - std::string SWC1_GP_(uint64 instruction); - std::string SWC1_S9_(uint64 instruction); - std::string SWC1_U12_(uint64 instruction); - std::string SWC1X(uint64 instruction); - std::string SWC1XS(uint64 instruction); - std::string SWC2(uint64 instruction); - std::string SWE(uint64 instruction); - std::string SWM(uint64 instruction); - std::string SWPC_48_(uint64 instruction); - std::string SWX(uint64 instruction); - std::string SWXS(uint64 instruction); - std::string SYNC(uint64 instruction); - std::string SYNCI(uint64 instruction); - std::string SYNCIE(uint64 instruction); - std::string SYSCALL_16_(uint64 instruction); - std::string SYSCALL_32_(uint64 instruction); - std::string TEQ(uint64 instruction); - std::string TLBGINV(uint64 instruction); - std::string TLBGINVF(uint64 instruction); - std::string TLBGP(uint64 instruction); - std::string TLBGR(uint64 instruction); - std::string TLBGWI(uint64 instruction); - std::string TLBGWR(uint64 instruction); - std::string TLBINV(uint64 instruction); - std::string TLBINVF(uint64 instruction); - std::string TLBP(uint64 instruction); - std::string TLBR(uint64 instruction); - std::string TLBWI(uint64 instruction); - std::string TLBWR(uint64 instruction); - std::string TNE(uint64 instruction); - std::string TRUNC_L_D(uint64 instruction); - std::string TRUNC_L_S(uint64 instruction); - std::string TRUNC_W_D(uint64 instruction); - std::string TRUNC_W_S(uint64 instruction); - std::string UALDM(uint64 instruction); - std::string UALH(uint64 instruction); - std::string UALWM(uint64 instruction); - std::string UASDM(uint64 instruction); - std::string UASH(uint64 instruction); - std::string UASWM(uint64 instruction); - std::string UDI(uint64 instruction); - std::string WAIT(uint64 instruction); - std::string WRDSP(uint64 instruction); - std::string WRPGPR(uint64 instruction); - std::string XOR_16_(uint64 instruction); - std::string XOR_32_(uint64 instruction); - std::string XORI(uint64 instruction); - std::string YIELD(uint64 instruction); - - static Pool P_SYSCALL[2]; - static Pool P_RI[4]; - static Pool P_ADDIU[2]; - static Pool P_TRAP[2]; - static Pool P_CMOVE[2]; - static Pool P_D_MT_VPE[2]; - static Pool P_E_MT_VPE[2]; - static Pool _P_MT_VPE[2]; - static Pool P_MT_VPE[8]; - static Pool P_DVP[2]; - static Pool P_SLTU[2]; - static Pool _POOL32A0[128]; - static Pool ADDQ__S__PH[2]; - static Pool MUL__S__PH[2]; - static Pool ADDQH__R__PH[2]; - static Pool ADDQH__R__W[2]; - static Pool ADDU__S__QB[2]; - static Pool ADDU__S__PH[2]; - static Pool ADDUH__R__QB[2]; - static Pool SHRAV__R__PH[2]; - static Pool SHRAV__R__QB[2]; - static Pool SUBQ__S__PH[2]; - static Pool SUBQH__R__PH[2]; - static Pool SUBQH__R__W[2]; - static Pool SUBU__S__QB[2]; - static Pool SUBU__S__PH[2]; - static Pool SHRA__R__PH[2]; - static Pool SUBUH__R__QB[2]; - static Pool SHLLV__S__PH[2]; - static Pool SHLL__S__PH[4]; - static Pool PRECR_SRA__R__PH_W[2]; - static Pool _POOL32A5[128]; - static Pool PP_LSX[16]; - static Pool PP_LSXS[16]; - static Pool P_LSX[2]; - static Pool POOL32Axf_1_0[4]; - static Pool POOL32Axf_1_1[4]; - static Pool POOL32Axf_1_3[4]; - static Pool POOL32Axf_1_4[2]; - static Pool MAQ_S_A__W_PHR[2]; - static Pool MAQ_S_A__W_PHL[2]; - static Pool POOL32Axf_1_5[2]; - static Pool POOL32Axf_1_7[4]; - static Pool POOL32Axf_1[8]; - static Pool POOL32Axf_2_DSP__0_7[8]; - static Pool POOL32Axf_2_DSP__8_15[8]; - static Pool POOL32Axf_2_DSP__16_23[8]; - static Pool POOL32Axf_2_DSP__24_31[8]; - static Pool POOL32Axf_2[4]; - static Pool POOL32Axf_4[128]; - static Pool POOL32Axf_5_group0[32]; - static Pool POOL32Axf_5_group1[32]; - static Pool ERETx[2]; - static Pool POOL32Axf_5_group3[32]; - static Pool POOL32Axf_5[4]; - static Pool SHRA__R__QB[2]; - static Pool POOL32Axf_7[8]; - static Pool POOL32Axf[8]; - static Pool _POOL32A7[8]; - static Pool P32A[8]; - static Pool P_GP_D[2]; - static Pool P_GP_W[4]; - static Pool POOL48I[32]; - static Pool PP_SR[4]; - static Pool P_SR_F[8]; - static Pool P_SR[2]; - static Pool P_SLL[5]; - static Pool P_SHIFT[16]; - static Pool P_ROTX[4]; - static Pool P_INS[4]; - static Pool P_EXT[4]; - static Pool P_U12[16]; - static Pool RINT_fmt[2]; - static Pool ADD_fmt0[2]; - static Pool SELEQZ_fmt[2]; - static Pool CLASS_fmt[2]; - static Pool SUB_fmt0[2]; - static Pool SELNEZ_fmt[2]; - static Pool MUL_fmt0[2]; - static Pool SEL_fmt[2]; - static Pool DIV_fmt0[2]; - static Pool ADD_fmt1[2]; - static Pool SUB_fmt1[2]; - static Pool MUL_fmt1[2]; - static Pool MADDF_fmt[2]; - static Pool DIV_fmt1[2]; - static Pool MSUBF_fmt[2]; - static Pool POOL32F_0[64]; - static Pool MIN_fmt[2]; - static Pool MAX_fmt[2]; - static Pool MINA_fmt[2]; - static Pool MAXA_fmt[2]; - static Pool CVT_L_fmt[2]; - static Pool RSQRT_fmt[2]; - static Pool FLOOR_L_fmt[2]; - static Pool CVT_W_fmt[2]; - static Pool SQRT_fmt[2]; - static Pool FLOOR_W_fmt[2]; - static Pool RECIP_fmt[2]; - static Pool CEIL_L_fmt[2]; - static Pool CEIL_W_fmt[2]; - static Pool TRUNC_L_fmt[2]; - static Pool TRUNC_W_fmt[2]; - static Pool ROUND_L_fmt[2]; - static Pool ROUND_W_fmt[2]; - static Pool POOL32Fxf_0[64]; - static Pool MOV_fmt[4]; - static Pool ABS_fmt[4]; - static Pool NEG_fmt[4]; - static Pool CVT_D_fmt[4]; - static Pool CVT_S_fmt[4]; - static Pool POOL32Fxf_1[32]; - static Pool POOL32Fxf[4]; - static Pool POOL32F_3[8]; - static Pool CMP_condn_S[32]; - static Pool CMP_condn_D[32]; - static Pool POOL32F_5[8]; - static Pool POOL32F[8]; - static Pool POOL32S_0[64]; - static Pool POOL32Sxf_4[128]; - static Pool POOL32Sxf[8]; - static Pool POOL32S_4[8]; - static Pool POOL32S[8]; - static Pool P_LUI[2]; - static Pool P_GP_LH[2]; - static Pool P_GP_SH[2]; - static Pool P_GP_CP1[4]; - static Pool P_GP_M64[4]; - static Pool P_GP_BH[8]; - static Pool P_LS_U12[16]; - static Pool P_PREF_S9_[2]; - static Pool P_LS_S0[16]; - static Pool ASET_ACLR[2]; - static Pool P_LL[4]; - static Pool P_SC[4]; - static Pool P_LLD[8]; - static Pool P_SCD[8]; - static Pool P_LS_S1[16]; - static Pool P_PREFE[2]; - static Pool P_LLE[4]; - static Pool P_SCE[4]; - static Pool P_LS_E0[16]; - static Pool P_LS_WM[2]; - static Pool P_LS_UAWM[2]; - static Pool P_LS_DM[2]; - static Pool P_LS_UADM[2]; - static Pool P_LS_S9[8]; - static Pool P_BAL[2]; - static Pool P_BALRSC[2]; - static Pool P_J[16]; - static Pool P_BR3A[32]; - static Pool P_BR1[4]; - static Pool P_BR2[4]; - static Pool P_BRI[8]; - static Pool P32[32]; - static Pool P16_SYSCALL[2]; - static Pool P16_RI[4]; - static Pool P16_MV[2]; - static Pool P16_SHIFT[2]; - static Pool POOL16C_00[4]; - static Pool POOL16C_0[2]; - static Pool P16C[2]; - static Pool P16_A1[2]; - static Pool P_ADDIU_RS5_[2]; - static Pool P16_A2[2]; - static Pool P16_ADDU[2]; - static Pool P16_JRC[2]; - static Pool P16_BR1[2]; - static Pool P16_BR[2]; - static Pool P16_SR[2]; - static Pool P16_4X4[4]; - static Pool P16_LB[4]; - static Pool P16_LH[4]; - static Pool P16[32]; - static Pool MAJOR[2]; - -}; - -#endif diff --git a/disas/ppc.c b/disas/ppc.c deleted file mode 100644 index 02be87819832..000000000000 --- a/disas/ppc.c +++ /dev/null @@ -1,5435 +0,0 @@ -/* ppc-dis.c -- Disassemble PowerPC instructions - Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support - -This file is part of GDB, GAS, and the GNU binutils. - -GDB, GAS, and the GNU binutils are free software; you can redistribute -them and/or modify them under the terms of the GNU General Public -License as published by the Free Software Foundation; either version -2, or (at your option) any later version. - -GDB, GAS, and the GNU binutils are distributed in the hope that they -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 file; see the file COPYING. If not, -see . */ -#include "qemu/osdep.h" -#include "disas/dis-asm.h" -#define BFD_DEFAULT_TARGET_SIZE 64 - -/* ppc.h -- Header file for PowerPC opcode table - Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support - -This file is part of GDB, GAS, and the GNU binutils. - -GDB, GAS, and the GNU binutils are free software; you can redistribute -them and/or modify them under the terms of the GNU General Public -License as published by the Free Software Foundation; either version -1, or (at your option) any later version. - -GDB, GAS, and the GNU binutils are distributed in the hope that they -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 file; see the file COPYING. If not, -see . */ - -/* The opcode table is an array of struct powerpc_opcode. */ - -struct powerpc_opcode -{ - /* The opcode name. */ - const char *name; - - /* The opcode itself. Those bits which will be filled in with - operands are zeroes. */ - unsigned long opcode; - - /* The opcode mask. This is used by the disassembler. This is a - mask containing ones indicating those bits which must match the - opcode field, and zeroes indicating those bits which need not - match (and are presumably filled in by operands). */ - unsigned long mask; - - /* One bit flags for the opcode. These are used to indicate which - specific processors support the instructions. The defined values - are listed below. */ - unsigned long flags; - - /* An array of operand codes. Each code is an index into the - operand table. They appear in the order which the operands must - appear in assembly code, and are terminated by a zero. */ - unsigned char operands[8]; -}; - -/* The table itself is sorted by major opcode number, and is otherwise - in the order in which the disassembler should consider - instructions. */ -extern const struct powerpc_opcode powerpc_opcodes[]; -extern const int powerpc_num_opcodes; - -/* Values defined for the flags field of a struct powerpc_opcode. */ - -/* Opcode is defined for the PowerPC architecture. */ -#define PPC_OPCODE_PPC 1 - -/* Opcode is defined for the POWER (RS/6000) architecture. */ -#define PPC_OPCODE_POWER 2 - -/* Opcode is defined for the POWER2 (Rios 2) architecture. */ -#define PPC_OPCODE_POWER2 4 - -/* Opcode is only defined on 32 bit architectures. */ -#define PPC_OPCODE_32 8 - -/* Opcode is only defined on 64 bit architectures. */ -#define PPC_OPCODE_64 0x10 - -/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 - is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, - but it also supports many additional POWER instructions. */ -#define PPC_OPCODE_601 0x20 - -/* Opcode is supported in both the Power and PowerPC architectures - (ie, compiler's -mcpu=common or assembler's -mcom). */ -#define PPC_OPCODE_COMMON 0x40 - -/* Opcode is supported for any Power or PowerPC platform (this is - for the assembler's -many option, and it eliminates duplicates). */ -#define PPC_OPCODE_ANY 0x80 - -/* Opcode is supported as part of the 64-bit bridge. */ -#define PPC_OPCODE_64_BRIDGE 0x100 - -/* Opcode is supported by Altivec Vector Unit */ -#define PPC_OPCODE_ALTIVEC 0x200 - -/* Opcode is supported by PowerPC 403 processor. */ -#define PPC_OPCODE_403 0x400 - -/* Opcode is supported by PowerPC BookE processor. */ -#define PPC_OPCODE_BOOKE 0x800 - -/* Opcode is only supported by 64-bit PowerPC BookE processor. */ -#define PPC_OPCODE_BOOKE64 0x1000 - -/* Opcode is supported by PowerPC 440 processor. */ -#define PPC_OPCODE_440 0x2000 - -/* Opcode is only supported by Power4 architecture. */ -#define PPC_OPCODE_POWER4 0x4000 - -/* Opcode isn't supported by Power4 architecture. */ -#define PPC_OPCODE_NOPOWER4 0x8000 - -/* Opcode is only supported by POWERPC Classic architecture. */ -#define PPC_OPCODE_CLASSIC 0x10000 - -/* Opcode is only supported by e500x2 Core. */ -#define PPC_OPCODE_SPE 0x20000 - -/* Opcode is supported by e500x2 Integer select APU. */ -#define PPC_OPCODE_ISEL 0x40000 - -/* Opcode is an e500 SPE floating point instruction. */ -#define PPC_OPCODE_EFS 0x80000 - -/* Opcode is supported by branch locking APU. */ -#define PPC_OPCODE_BRLOCK 0x100000 - -/* Opcode is supported by performance monitor APU. */ -#define PPC_OPCODE_PMR 0x200000 - -/* Opcode is supported by cache locking APU. */ -#define PPC_OPCODE_CACHELCK 0x400000 - -/* Opcode is supported by machine check APU. */ -#define PPC_OPCODE_RFMCI 0x800000 - -/* Opcode is only supported by Power5 architecture. */ -#define PPC_OPCODE_POWER5 0x1000000 - -/* Opcode is supported by PowerPC e300 family. */ -#define PPC_OPCODE_E300 0x2000000 - -/* Opcode is only supported by Power6 architecture. */ -#define PPC_OPCODE_POWER6 0x4000000 - -/* Opcode is only supported by PowerPC Cell family. */ -#define PPC_OPCODE_CELL 0x8000000 - -/* A macro to extract the major opcode from an instruction. */ -#define PPC_OP(i) (((i) >> 26) & 0x3f) - -/* The operands table is an array of struct powerpc_operand. */ - -struct powerpc_operand -{ - /* A bitmask of bits in the operand. */ - unsigned int bitm; - - /* How far the operand is left shifted in the instruction. - -1 to indicate that BITM and SHIFT cannot be used to determine - where the operand goes in the insn. */ - int shift; - - /* Insertion function. This is used by the assembler. To insert an - operand value into an instruction, check this field. - - If it is NULL, execute - i |= (op & o->bitm) << o->shift; - (i is the instruction which we are filling in, o is a pointer to - this structure, and op is the operand value). - - If this field is not NULL, then simply call it with the - instruction and the operand value. It will return the new value - of the instruction. If the ERRMSG argument is not NULL, then if - the operand value is illegal, *ERRMSG will be set to a warning - string (the operand will be inserted in any case). If the - operand value is legal, *ERRMSG will be unchanged (most operands - can accept any value). */ - unsigned long (*insert) - (unsigned long instruction, long op, int dialect, const char **errmsg); - - /* Extraction function. This is used by the disassembler. To - extract this operand type from an instruction, check this field. - - If it is NULL, compute - op = (i >> o->shift) & o->bitm; - if ((o->flags & PPC_OPERAND_SIGNED) != 0) - sign_extend (op); - (i is the instruction, o is a pointer to this structure, and op - is the result). - - If this field is not NULL, then simply call it with the - instruction value. It will return the value of the operand. If - the INVALID argument is not NULL, *INVALID will be set to - non-zero if this operand type can not actually be extracted from - this operand (i.e., the instruction does not match). If the - operand is valid, *INVALID will not be changed. */ - long (*extract) (unsigned long instruction, int dialect, int *invalid); - - /* One bit syntax flags. */ - unsigned long flags; -}; - -/* Elements in the table are retrieved by indexing with values from - the operands field of the powerpc_opcodes table. */ - -extern const struct powerpc_operand powerpc_operands[]; -extern const unsigned int num_powerpc_operands; - -/* Values defined for the flags field of a struct powerpc_operand. */ - -/* This operand takes signed values. */ -#define PPC_OPERAND_SIGNED (0x1) - -/* This operand takes signed values, but also accepts a full positive - range of values when running in 32 bit mode. That is, if bits is - 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, - this flag is ignored. */ -#define PPC_OPERAND_SIGNOPT (0x2) - -/* This operand does not actually exist in the assembler input. This - is used to support extended mnemonics such as mr, for which two - operands fields are identical. The assembler should call the - insert function with any op value. The disassembler should call - the extract function, ignore the return value, and check the value - placed in the valid argument. */ -#define PPC_OPERAND_FAKE (0x4) - -/* The next operand should be wrapped in parentheses rather than - separated from this one by a comma. This is used for the load and - store instructions which want their operands to look like - reg,displacement(reg) - */ -#define PPC_OPERAND_PARENS (0x8) - -/* This operand may use the symbolic names for the CR fields, which - are - lt 0 gt 1 eq 2 so 3 un 3 - cr0 0 cr1 1 cr2 2 cr3 3 - cr4 4 cr5 5 cr6 6 cr7 7 - These may be combined arithmetically, as in cr2*4+gt. These are - only supported on the PowerPC, not the POWER. */ -#define PPC_OPERAND_CR (0x10) - -/* This operand names a register. The disassembler uses this to print - register names with a leading 'r'. */ -#define PPC_OPERAND_GPR (0x20) - -/* Like PPC_OPERAND_GPR, but don't print a leading 'r' for r0. */ -#define PPC_OPERAND_GPR_0 (0x40) - -/* This operand names a floating point register. The disassembler - prints these with a leading 'f'. */ -#define PPC_OPERAND_FPR (0x80) - -/* This operand is a relative branch displacement. The disassembler - prints these symbolically if possible. */ -#define PPC_OPERAND_RELATIVE (0x100) - -/* This operand is an absolute branch address. The disassembler - prints these symbolically if possible. */ -#define PPC_OPERAND_ABSOLUTE (0x200) - -/* This operand is optional, and is zero if omitted. This is used for - example, in the optional BF field in the comparison instructions. The - assembler must count the number of operands remaining on the line, - and the number of operands remaining for the opcode, and decide - whether this operand is present or not. The disassembler should - print this operand out only if it is not zero. */ -#define PPC_OPERAND_OPTIONAL (0x400) - -/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand - is omitted, then for the next operand use this operand value plus - 1, ignoring the next operand field for the opcode. This wretched - hack is needed because the Power rotate instructions can take - either 4 or 5 operands. The disassembler should print this operand - out regardless of the PPC_OPERAND_OPTIONAL field. */ -#define PPC_OPERAND_NEXT (0x800) - -/* This operand should be regarded as a negative number for the - purposes of overflow checking (i.e., the normal most negative - number is disallowed and one more than the normal most positive - number is allowed). This flag will only be set for a signed - operand. */ -#define PPC_OPERAND_NEGATIVE (0x1000) - -/* This operand names a vector unit register. The disassembler - prints these with a leading 'v'. */ -#define PPC_OPERAND_VR (0x2000) - -/* This operand is for the DS field in a DS form instruction. */ -#define PPC_OPERAND_DS (0x4000) - -/* This operand is for the DQ field in a DQ form instruction. */ -#define PPC_OPERAND_DQ (0x8000) - -/* Valid range of operand is 0..n rather than 0..n-1. */ -#define PPC_OPERAND_PLUS1 (0x10000) - -/* The POWER and PowerPC assemblers use a few macros. We keep them - with the operands table for simplicity. The macro table is an - array of struct powerpc_macro. */ - -struct powerpc_macro -{ - /* The macro name. */ - const char *name; - - /* The number of operands the macro takes. */ - unsigned int operands; - - /* One bit flags for the opcode. These are used to indicate which - specific processors support the instructions. The values are the - same as those for the struct powerpc_opcode flags field. */ - unsigned long flags; - - /* A format string to turn the macro into a normal instruction. - Each %N in the string is replaced with operand number N (zero - based). */ - const char *format; -}; - -extern const struct powerpc_macro powerpc_macros[]; -extern const int powerpc_num_macros; - -/* ppc-opc.c -- PowerPC opcode list - Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support - - This file is part of GDB, GAS, and the GNU binutils. - - GDB, GAS, and the GNU binutils are free software; you can redistribute - them and/or modify them under the terms of the GNU General Public - License as published by the Free Software Foundation; either version - 2, or (at your option) any later version. - - GDB, GAS, and the GNU binutils are distributed in the hope that they - 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 file; see the file COPYING. - If not, see . */ - -/* This file holds the PowerPC opcode table. The opcode table - includes almost all of the extended instruction mnemonics. This - permits the disassembler to use them, and simplifies the assembler - logic, at the cost of increasing the table size. The table is - strictly constant data, so the compiler should be able to put it in - the .text section. - - This file also holds the operand table. All knowledge about - inserting operands into instructions and vice-versa is kept in this - file. */ - -/* Local insertion and extraction functions. */ - -static unsigned long insert_bat (unsigned long, long, int, const char **); -static long extract_bat (unsigned long, int, int *); -static unsigned long insert_bba (unsigned long, long, int, const char **); -static long extract_bba (unsigned long, int, int *); -static unsigned long insert_bdm (unsigned long, long, int, const char **); -static long extract_bdm (unsigned long, int, int *); -static unsigned long insert_bdp (unsigned long, long, int, const char **); -static long extract_bdp (unsigned long, int, int *); -static unsigned long insert_bo (unsigned long, long, int, const char **); -static long extract_bo (unsigned long, int, int *); -static unsigned long insert_boe (unsigned long, long, int, const char **); -static long extract_boe (unsigned long, int, int *); -static unsigned long insert_fxm (unsigned long, long, int, const char **); -static long extract_fxm (unsigned long, int, int *); -static unsigned long insert_mbe (unsigned long, long, int, const char **); -static long extract_mbe (unsigned long, int, int *); -static unsigned long insert_mb6 (unsigned long, long, int, const char **); -static long extract_mb6 (unsigned long, int, int *); -static long extract_nb (unsigned long, int, int *); -static unsigned long insert_nsi (unsigned long, long, int, const char **); -static long extract_nsi (unsigned long, int, int *); -static unsigned long insert_ral (unsigned long, long, int, const char **); -static unsigned long insert_ram (unsigned long, long, int, const char **); -static unsigned long insert_raq (unsigned long, long, int, const char **); -static unsigned long insert_ras (unsigned long, long, int, const char **); -static unsigned long insert_rbs (unsigned long, long, int, const char **); -static long extract_rbs (unsigned long, int, int *); -static unsigned long insert_sh6 (unsigned long, long, int, const char **); -static long extract_sh6 (unsigned long, int, int *); -static unsigned long insert_spr (unsigned long, long, int, const char **); -static long extract_spr (unsigned long, int, int *); -static unsigned long insert_sprg (unsigned long, long, int, const char **); -static long extract_sprg (unsigned long, int, int *); -static unsigned long insert_tbr (unsigned long, long, int, const char **); -static long extract_tbr (unsigned long, int, int *); - -/* The operands table. - - The fields are bitm, shift, insert, extract, flags. - - We used to put parens around the various additions, like the one - for BA just below. However, that caused trouble with feeble - compilers with a limit on depth of a parenthesized expression, like - (reportedly) the compiler in Microsoft Developer Studio 5. So we - omit the parens, since the macros are never used in a context where - the addition will be ambiguous. */ - -const struct powerpc_operand powerpc_operands[] = -{ - /* The zero index is used to indicate the end of the list of - operands. */ -#define UNUSED 0 - { 0, 0, NULL, NULL, 0 }, - - /* The BA field in an XL form instruction. */ -#define BA UNUSED + 1 - /* The BI field in a B form or XL form instruction. */ -#define BI BA -#define BI_MASK (0x1f << 16) - { 0x1f, 16, NULL, NULL, PPC_OPERAND_CR }, - - /* The BA field in an XL form instruction when it must be the same - as the BT field in the same instruction. */ -#define BAT BA + 1 - { 0x1f, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE }, - - /* The BB field in an XL form instruction. */ -#define BB BAT + 1 -#define BB_MASK (0x1f << 11) - { 0x1f, 11, NULL, NULL, PPC_OPERAND_CR }, - - /* The BB field in an XL form instruction when it must be the same - as the BA field in the same instruction. */ -#define BBA BB + 1 - { 0x1f, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE }, - - /* The BD field in a B form instruction. The lower two bits are - forced to zero. */ -#define BD BBA + 1 - { 0xfffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when absolute addressing is - used. */ -#define BDA BD + 1 - { 0xfffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the - modifier is used. - This sets the y bit of the BO field appropriately. */ -#define BDM BDA + 1 - { 0xfffc, 0, insert_bdm, extract_bdm, - PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the - modifier is used - and absolute address is used. */ -#define BDMA BDM + 1 - { 0xfffc, 0, insert_bdm, extract_bdm, - PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the + modifier is used. - This sets the y bit of the BO field appropriately. */ -#define BDP BDMA + 1 - { 0xfffc, 0, insert_bdp, extract_bdp, - PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the + modifier is used - and absolute addressing is used. */ -#define BDPA BDP + 1 - { 0xfffc, 0, insert_bdp, extract_bdp, - PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The BF field in an X or XL form instruction. */ -#define BF BDPA + 1 - /* The CRFD field in an X form instruction. */ -#define CRFD BF - { 0x7, 23, NULL, NULL, PPC_OPERAND_CR }, - - /* The BF field in an X or XL form instruction. */ -#define BFF BF + 1 - { 0x7, 23, NULL, NULL, 0 }, - - /* An optional BF field. This is used for comparison instructions, - in which an omitted BF field is taken as zero. */ -#define OBF BFF + 1 - { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, - - /* The BFA field in an X or XL form instruction. */ -#define BFA OBF + 1 - { 0x7, 18, NULL, NULL, PPC_OPERAND_CR }, - - /* The BO field in a B form instruction. Certain values are - illegal. */ -#define BO BFA + 1 -#define BO_MASK (0x1f << 21) - { 0x1f, 21, insert_bo, extract_bo, 0 }, - - /* The BO field in a B form instruction when the + or - modifier is - used. This is like the BO field, but it must be even. */ -#define BOE BO + 1 - { 0x1e, 21, insert_boe, extract_boe, 0 }, - -#define BH BOE + 1 - { 0x3, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The BT field in an X or XL form instruction. */ -#define BT BH + 1 - { 0x1f, 21, NULL, NULL, PPC_OPERAND_CR }, - - /* The condition register number portion of the BI field in a B form - or XL form instruction. This is used for the extended - conditional branch mnemonics, which set the lower two bits of the - BI field. This field is optional. */ -#define CR BT + 1 - { 0x7, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, - - /* The CRB field in an X form instruction. */ -#define CRB CR + 1 - /* The MB field in an M form instruction. */ -#define MB CRB -#define MB_MASK (0x1f << 6) - { 0x1f, 6, NULL, NULL, 0 }, - - /* The CRFS field in an X form instruction. */ -#define CRFS CRB + 1 - { 0x7, 0, NULL, NULL, PPC_OPERAND_CR }, - - /* The CT field in an X form instruction. */ -#define CT CRFS + 1 - /* The MO field in an mbar instruction. */ -#define MO CT - { 0x1f, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The D field in a D form instruction. This is a displacement off - a register, and implies that the next operand is a register in - parentheses. */ -#define D CT + 1 - { 0xffff, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, - - /* The DE field in a DE form instruction. This is like D, but is 12 - bits only. */ -#define DE D + 1 - { 0xfff, 4, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, - - /* The DES field in a DES form instruction. This is like DS, but is 14 - bits only (12 stored.) */ -#define DES DE + 1 - { 0x3ffc, 2, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, - - /* The DQ field in a DQ form instruction. This is like D, but the - lower four bits are forced to zero. */ -#define DQ DES + 1 - { 0xfff0, 0, NULL, NULL, - PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ }, - - /* The DS field in a DS form instruction. This is like D, but the - lower two bits are forced to zero. */ -#undef DS -#define DS DQ + 1 - { 0xfffc, 0, NULL, NULL, - PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS }, - - /* The E field in a wrteei instruction. */ -#define E DS + 1 - { 0x1, 15, NULL, NULL, 0 }, - - /* The FL1 field in a POWER SC form instruction. */ -#define FL1 E + 1 - /* The U field in an X form instruction. */ -#define U FL1 - { 0xf, 12, NULL, NULL, 0 }, - - /* The FL2 field in a POWER SC form instruction. */ -#define FL2 FL1 + 1 - { 0x7, 2, NULL, NULL, 0 }, - - /* The FLM field in an XFL form instruction. */ -#define FLM FL2 + 1 - { 0xff, 17, NULL, NULL, 0 }, - - /* The FRA field in an X or A form instruction. */ -#define FRA FLM + 1 -#define FRA_MASK (0x1f << 16) - { 0x1f, 16, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FRB field in an X or A form instruction. */ -#define FRB FRA + 1 -#define FRB_MASK (0x1f << 11) - { 0x1f, 11, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FRC field in an A form instruction. */ -#define FRC FRB + 1 -#define FRC_MASK (0x1f << 6) - { 0x1f, 6, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FRS field in an X form instruction or the FRT field in a D, X - or A form instruction. */ -#define FRS FRC + 1 -#define FRT FRS - { 0x1f, 21, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FXM field in an XFX instruction. */ -#define FXM FRS + 1 - { 0xff, 12, insert_fxm, extract_fxm, 0 }, - - /* Power4 version for mfcr. */ -#define FXM4 FXM + 1 - { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL }, - - /* The L field in a D or X form instruction. */ -#define L FXM4 + 1 - { 0x1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The LEV field in a POWER SVC form instruction. */ -#define SVC_LEV L + 1 - { 0x7f, 5, NULL, NULL, 0 }, - - /* The LEV field in an SC form instruction. */ -#define LEV SVC_LEV + 1 - { 0x7f, 5, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The LI field in an I form instruction. The lower two bits are - forced to zero. */ -#define LI LEV + 1 - { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The LI field in an I form instruction when used as an absolute - address. */ -#define LIA LI + 1 - { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The LS field in an X (sync) form instruction. */ -#define LS LIA + 1 - { 0x3, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The ME field in an M form instruction. */ -#define ME LS + 1 -#define ME_MASK (0x1f << 1) - { 0x1f, 1, NULL, NULL, 0 }, - - /* The MB and ME fields in an M form instruction expressed a single - operand which is a bitmask indicating which bits to select. This - is a two operand form using PPC_OPERAND_NEXT. See the - description in opcode/ppc.h for what this means. */ -#define MBE ME + 1 - { 0x1f, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, - { -1, 0, insert_mbe, extract_mbe, 0 }, - - /* The MB or ME field in an MD or MDS form instruction. The high - bit is wrapped to the low end. */ -#define MB6 MBE + 2 -#define ME6 MB6 -#define MB6_MASK (0x3f << 5) - { 0x3f, 5, insert_mb6, extract_mb6, 0 }, - - /* The NB field in an X form instruction. The value 32 is stored as - 0. */ -#define NB MB6 + 1 - { 0x1f, 11, NULL, extract_nb, PPC_OPERAND_PLUS1 }, - - /* The NSI field in a D form instruction. This is the same as the - SI field, only negated. */ -#define NSI NB + 1 - { 0xffff, 0, insert_nsi, extract_nsi, - PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED }, - - /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */ -#define RA NSI + 1 -#define RA_MASK (0x1f << 16) - { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR }, - - /* As above, but 0 in the RA field means zero, not r0. */ -#define RA0 RA + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in the DQ form lq instruction, which has special - value restrictions. */ -#define RAQ RA0 + 1 - { 0x1f, 16, insert_raq, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in a D or X form instruction which is an updating - load, which means that the RA field may not be zero and may not - equal the RT field. */ -#define RAL RAQ + 1 - { 0x1f, 16, insert_ral, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in an lmw instruction, which has special value - restrictions. */ -#define RAM RAL + 1 - { 0x1f, 16, insert_ram, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in a D or X form instruction which is an updating - store or an updating floating point load, which means that the RA - field may not be zero. */ -#define RAS RAM + 1 - { 0x1f, 16, insert_ras, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field of the tlbwe instruction, which is optional. */ -#define RAOPT RAS + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, - - /* The RB field in an X, XO, M, or MDS form instruction. */ -#define RB RAOPT + 1 -#define RB_MASK (0x1f << 11) - { 0x1f, 11, NULL, NULL, PPC_OPERAND_GPR }, - - /* The RB field in an X form instruction when it must be the same as - the RS field in the instruction. This is used for extended - mnemonics like mr. */ -#define RBS RB + 1 - { 0x1f, 11, insert_rbs, extract_rbs, PPC_OPERAND_FAKE }, - - /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form - instruction or the RT field in a D, DS, X, XFX or XO form - instruction. */ -#define RS RBS + 1 -#define RT RS -#define RT_MASK (0x1f << 21) - { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR }, - - /* The RS and RT fields of the DS form stq instruction, which have - special value restrictions. */ -#define RSQ RS + 1 -#define RTQ RSQ - { 0x1e, 21, NULL, NULL, PPC_OPERAND_GPR_0 }, - - /* The RS field of the tlbwe instruction, which is optional. */ -#define RSO RSQ + 1 -#define RTO RSO - { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, - - /* The SH field in an X or M form instruction. */ -#define SH RSO + 1 -#define SH_MASK (0x1f << 11) - /* The other UIMM field in a EVX form instruction. */ -#define EVUIMM SH - { 0x1f, 11, NULL, NULL, 0 }, - - /* The SH field in an MD form instruction. This is split. */ -#define SH6 SH + 1 -#define SH6_MASK ((0x1f << 11) | (1 << 1)) - { 0x3f, -1, insert_sh6, extract_sh6, 0 }, - - /* The SH field of the tlbwe instruction, which is optional. */ -#define SHO SH6 + 1 - { 0x1f, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The SI field in a D form instruction. */ -#define SI SHO + 1 - { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED }, - - /* The SI field in a D form instruction when we accept a wide range - of positive values. */ -#define SISIGNOPT SI + 1 - { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, - - /* The SPR field in an XFX form instruction. This is flipped--the - lower 5 bits are stored in the upper 5 and vice- versa. */ -#define SPR SISIGNOPT + 1 -#define PMR SPR -#define SPR_MASK (0x3ff << 11) - { 0x3ff, 11, insert_spr, extract_spr, 0 }, - - /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ -#define SPRBAT SPR + 1 -#define SPRBAT_MASK (0x3 << 17) - { 0x3, 17, NULL, NULL, 0 }, - - /* The SPRG register number in an XFX form m[ft]sprg instruction. */ -#define SPRG SPRBAT + 1 - { 0x1f, 16, insert_sprg, extract_sprg, 0 }, - - /* The SR field in an X form instruction. */ -#define SR SPRG + 1 - { 0xf, 16, NULL, NULL, 0 }, - - /* The STRM field in an X AltiVec form instruction. */ -#define STRM SR + 1 - { 0x3, 21, NULL, NULL, 0 }, - - /* The SV field in a POWER SC form instruction. */ -#define SV STRM + 1 - { 0x3fff, 2, NULL, NULL, 0 }, - - /* The TBR field in an XFX form instruction. This is like the SPR - field, but it is optional. */ -#define TBR SV + 1 - { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, - - /* The TO field in a D or X form instruction. */ -#define TO TBR + 1 -#define TO_MASK (0x1f << 21) - { 0x1f, 21, NULL, NULL, 0 }, - - /* The UI field in a D form instruction. */ -#define UI TO + 1 - { 0xffff, 0, NULL, NULL, 0 }, - - /* The VA field in a VA, VX or VXR form instruction. */ -#define VA UI + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_VR }, - - /* The VB field in a VA, VX or VXR form instruction. */ -#define VB VA + 1 - { 0x1f, 11, NULL, NULL, PPC_OPERAND_VR }, - - /* The VC field in a VA form instruction. */ -#define VC VB + 1 - { 0x1f, 6, NULL, NULL, PPC_OPERAND_VR }, - - /* The VD or VS field in a VA, VX, VXR or X form instruction. */ -#define VD VC + 1 -#define VS VD - { 0x1f, 21, NULL, NULL, PPC_OPERAND_VR }, - - /* The SIMM field in a VX form instruction. */ -#define SIMM VD + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_SIGNED}, - - /* The UIMM field in a VX form instruction, and TE in Z form. */ -#define UIMM SIMM + 1 -#define TE UIMM - { 0x1f, 16, NULL, NULL, 0 }, - - /* The SHB field in a VA form instruction. */ -#define SHB UIMM + 1 - { 0xf, 6, NULL, NULL, 0 }, - - /* The other UIMM field in a half word EVX form instruction. */ -#define EVUIMM_2 SHB + 1 - { 0x3e, 10, NULL, NULL, PPC_OPERAND_PARENS }, - - /* The other UIMM field in a word EVX form instruction. */ -#define EVUIMM_4 EVUIMM_2 + 1 - { 0x7c, 9, NULL, NULL, PPC_OPERAND_PARENS }, - - /* The other UIMM field in a double EVX form instruction. */ -#define EVUIMM_8 EVUIMM_4 + 1 - { 0xf8, 8, NULL, NULL, PPC_OPERAND_PARENS }, - - /* The WS field. */ -#define WS EVUIMM_8 + 1 - { 0x7, 11, NULL, NULL, 0 }, - - /* The L field in an mtmsrd or A form instruction or W in an X form. */ -#define A_L WS + 1 -#define W A_L - { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL }, - -#define RMC A_L + 1 - { 0x3, 9, NULL, NULL, 0 }, - -#define R RMC + 1 - { 0x1, 16, NULL, NULL, 0 }, - -#define SP R + 1 - { 0x3, 19, NULL, NULL, 0 }, - -#define S SP + 1 - { 0x1, 20, NULL, NULL, 0 }, - - /* SH field starting at bit position 16. */ -#define SH16 S + 1 - /* The DCM and DGM fields in a Z form instruction. */ -#define DCM SH16 -#define DGM DCM - { 0x3f, 10, NULL, NULL, 0 }, - - /* The EH field in larx instruction. */ -#define EH SH16 + 1 - { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The L field in an mtfsf or XFL form instruction. */ -#define XFL_L EH + 1 - { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL}, -}; - -const unsigned int num_powerpc_operands = (sizeof (powerpc_operands) - / sizeof (powerpc_operands[0])); - -/* The functions used to insert and extract complicated operands. */ - -/* The BA field in an XL form instruction when it must be the same as - the BT field in the same instruction. This operand is marked FAKE. - The insertion function just copies the BT field into the BA field, - and the extraction function just checks that the fields are the - same. */ - -static unsigned long -insert_bat (unsigned long insn, - long value ATTRIBUTE_UNUSED, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (((insn >> 21) & 0x1f) << 16); -} - -static long -extract_bat (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - if (((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) - *invalid = 1; - return 0; -} - -/* The BB field in an XL form instruction when it must be the same as - the BA field in the same instruction. This operand is marked FAKE. - The insertion function just copies the BA field into the BB field, - and the extraction function just checks that the fields are the - same. */ - -static unsigned long -insert_bba (unsigned long insn, - long value ATTRIBUTE_UNUSED, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (((insn >> 16) & 0x1f) << 11); -} - -static long -extract_bba (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - if (((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) - *invalid = 1; - return 0; -} - -/* The BD field in a B form instruction when the - modifier is used. - This modifier means that the branch is not expected to be taken. - For chips built to versions of the architecture prior to version 2 - (ie. not Power4 compatible), we set the y bit of the BO field to 1 - if the offset is negative. When extracting, we require that the y - bit be 1 and that the offset be positive, since if the y bit is 0 - we just want to print the normal form of the instruction. - Power4 compatible targets use two bits, "a", and "t", instead of - the "y" bit. "at" == 00 => no hint, "at" == 01 => unpredictable, - "at" == 10 => not taken, "at" == 11 => taken. The "t" bit is 00001 - in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000 - for branch on CTR. We only handle the taken/not-taken hint here. - Note that we don't relax the conditions tested here when - disassembling with -Many because insns using extract_bdm and - extract_bdp always occur in pairs. One or the other will always - be valid. */ - -static unsigned long -insert_bdm (unsigned long insn, - long value, - int dialect, - const char **errmsg ATTRIBUTE_UNUSED) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if ((value & 0x8000) != 0) - insn |= 1 << 21; - } - else - { - if ((insn & (0x14 << 21)) == (0x04 << 21)) - insn |= 0x02 << 21; - else if ((insn & (0x14 << 21)) == (0x10 << 21)) - insn |= 0x08 << 21; - } - return insn | (value & 0xfffc); -} - -static long -extract_bdm (unsigned long insn, - int dialect, - int *invalid) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if (((insn & (1 << 21)) == 0) != ((insn & (1 << 15)) == 0)) - *invalid = 1; - } - else - { - if ((insn & (0x17 << 21)) != (0x06 << 21) - && (insn & (0x1d << 21)) != (0x18 << 21)) - *invalid = 1; - } - - return ((insn & 0xfffc) ^ 0x8000) - 0x8000; -} - -/* The BD field in a B form instruction when the + modifier is used. - This is like BDM, above, except that the branch is expected to be - taken. */ - -static unsigned long -insert_bdp (unsigned long insn, - long value, - int dialect, - const char **errmsg ATTRIBUTE_UNUSED) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if ((value & 0x8000) == 0) - insn |= 1 << 21; - } - else - { - if ((insn & (0x14 << 21)) == (0x04 << 21)) - insn |= 0x03 << 21; - else if ((insn & (0x14 << 21)) == (0x10 << 21)) - insn |= 0x09 << 21; - } - return insn | (value & 0xfffc); -} - -static long -extract_bdp (unsigned long insn, - int dialect, - int *invalid) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if (((insn & (1 << 21)) == 0) == ((insn & (1 << 15)) == 0)) - *invalid = 1; - } - else - { - if ((insn & (0x17 << 21)) != (0x07 << 21) - && (insn & (0x1d << 21)) != (0x19 << 21)) - *invalid = 1; - } - - return ((insn & 0xfffc) ^ 0x8000) - 0x8000; -} - -/* Check for legal values of a BO field. */ - -static int -valid_bo (long value, int dialect, int extract) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - int valid; - /* Certain encodings have bits that are required to be zero. - These are (z must be zero, y may be anything): - 001zy - 011zy - 1z00y - 1z01y - 1z1zz - */ - switch (value & 0x14) - { - default: - case 0: - valid = 1; - break; - case 0x4: - valid = (value & 0x2) == 0; - break; - case 0x10: - valid = (value & 0x8) == 0; - break; - case 0x14: - valid = value == 0x14; - break; - } - /* When disassembling with -Many, accept power4 encodings too. */ - if (valid - || (dialect & PPC_OPCODE_ANY) == 0 - || !extract) - return valid; - } - - /* Certain encodings have bits that are required to be zero. - These are (z must be zero, a & t may be anything): - 0000z - 0001z - 0100z - 0101z - 001at - 011at - 1a00t - 1a01t - 1z1zz - */ - if ((value & 0x14) == 0) - return (value & 0x1) == 0; - else if ((value & 0x14) == 0x14) - return value == 0x14; - else - return 1; -} - -/* The BO field in a B form instruction. Warn about attempts to set - the field to an illegal value. */ - -static unsigned long -insert_bo (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - if (!valid_bo (value, dialect, 0)) - *errmsg = "invalid conditional option"; - return insn | ((value & 0x1f) << 21); -} - -static long -extract_bo (unsigned long insn, - int dialect, - int *invalid) -{ - long value; - - value = (insn >> 21) & 0x1f; - if (!valid_bo (value, dialect, 1)) - *invalid = 1; - return value; -} - -/* The BO field in a B form instruction when the + or - modifier is - used. This is like the BO field, but it must be even. When - extracting it, we force it to be even. */ - -static unsigned long -insert_boe (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - if (!valid_bo (value, dialect, 0)) - *errmsg = "invalid conditional option"; - else if ((value & 1) != 0) - *errmsg = "attempt to set y bit when using + or - modifier"; - - return insn | ((value & 0x1f) << 21); -} - -static long -extract_boe (unsigned long insn, - int dialect, - int *invalid) -{ - long value; - - value = (insn >> 21) & 0x1f; - if (!valid_bo (value, dialect, 1)) - *invalid = 1; - return value & 0x1e; -} - -/* FXM mask in mfcr and mtcrf instructions. */ - -static unsigned long -insert_fxm (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - /* If we're handling the mfocrf and mtocrf insns ensure that exactly - one bit of the mask field is set. */ - if ((insn & (1 << 20)) != 0) - { - if (value == 0 || (value & -value) != value) - { - *errmsg = "invalid mask field"; - value = 0; - } - } - - /* If the optional field on mfcr is missing that means we want to use - the old form of the instruction that moves the whole cr. In that - case we'll have VALUE zero. There doesn't seem to be a way to - distinguish this from the case where someone writes mfcr %r3,0. */ - else if (value == 0) - ; - - /* If only one bit of the FXM field is set, we can use the new form - of the instruction, which is faster. Unlike the Power4 branch hint - encoding, this is not backward compatible. Do not generate the - new form unless -mpower4 has been given, or -many and the two - operand form of mfcr was used. */ - else if ((value & -value) == value - && ((dialect & PPC_OPCODE_POWER4) != 0 - || ((dialect & PPC_OPCODE_ANY) != 0 - && (insn & (0x3ff << 1)) == 19 << 1))) - insn |= 1 << 20; - - /* Any other value on mfcr is an error. */ - else if ((insn & (0x3ff << 1)) == 19 << 1) - { - *errmsg = "ignoring invalid mfcr mask"; - value = 0; - } - - return insn | ((value & 0xff) << 12); -} - -static long -extract_fxm (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - long mask = (insn >> 12) & 0xff; - - /* Is this a Power4 insn? */ - if ((insn & (1 << 20)) != 0) - { - /* Exactly one bit of MASK should be set. */ - if (mask == 0 || (mask & -mask) != mask) - *invalid = 1; - } - - /* Check that non-power4 form of mfcr has a zero MASK. */ - else if ((insn & (0x3ff << 1)) == 19 << 1) - { - if (mask != 0) - *invalid = 1; - } - - return mask; -} - -/* The MB and ME fields in an M form instruction expressed as a single - operand which is itself a bitmask. The extraction function always - marks it as invalid, since we never want to recognize an - instruction which uses a field of this type. */ - -static unsigned long -insert_mbe (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - unsigned long uval, mask; - int mb, me, mx, count, last; - - uval = value; - - if (uval == 0) - { - *errmsg = "illegal bitmask"; - return insn; - } - - mb = 0; - me = 32; - if ((uval & 1) != 0) - last = 1; - else - last = 0; - count = 0; - - /* mb: location of last 0->1 transition */ - /* me: location of last 1->0 transition */ - /* count: # transitions */ - - for (mx = 0, mask = 1L << 31; mx < 32; ++mx, mask >>= 1) - { - if ((uval & mask) && !last) - { - ++count; - mb = mx; - last = 1; - } - else if (!(uval & mask) && last) - { - ++count; - me = mx; - last = 0; - } - } - if (me == 0) - me = 32; - - if (count != 2 && (count != 0 || ! last)) - *errmsg = "illegal bitmask"; - - return insn | (mb << 6) | ((me - 1) << 1); -} - -static long -extract_mbe (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - long ret; - int mb, me; - int i; - - *invalid = 1; - - mb = (insn >> 6) & 0x1f; - me = (insn >> 1) & 0x1f; - if (mb < me + 1) - { - ret = 0; - for (i = mb; i <= me; i++) - ret |= 1L << (31 - i); - } - else if (mb == me + 1) - ret = ~0; - else /* (mb > me + 1) */ - { - ret = ~0; - for (i = me + 1; i < mb; i++) - ret &= ~(1L << (31 - i)); - } - return ret; -} - -/* The MB or ME field in an MD or MDS form instruction. The high bit - is wrapped to the low end. */ - -static unsigned long -insert_mb6 (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | ((value & 0x1f) << 6) | (value & 0x20); -} - -static long -extract_mb6 (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - return ((insn >> 6) & 0x1f) | (insn & 0x20); -} - -/* The NB field in an X form instruction. The value 32 is stored as - 0. */ - -static long -extract_nb (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - long ret; - - ret = (insn >> 11) & 0x1f; - if (ret == 0) - ret = 32; - return ret; -} - -/* The NSI field in a D form instruction. This is the same as the SI - field, only negated. The extraction function always marks it as - invalid, since we never want to recognize an instruction which uses - a field of this type. */ - -static unsigned long -insert_nsi (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (-value & 0xffff); -} - -static long -extract_nsi (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - *invalid = 1; - return -(((insn & 0xffff) ^ 0x8000) - 0x8000); -} - -/* The RA field in a D or X form instruction which is an updating - load, which means that the RA field may not be zero and may not - equal the RT field. */ - -static unsigned long -insert_ral (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - if (value == 0 - || (unsigned long) value == ((insn >> 21) & 0x1f)) - *errmsg = "invalid register operand when updating"; - return insn | ((value & 0x1f) << 16); -} - -/* The RA field in an lmw instruction, which has special value - restrictions. */ - -static unsigned long -insert_ram (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - if ((unsigned long) value >= ((insn >> 21) & 0x1f)) - *errmsg = "index register in load range"; - return insn | ((value & 0x1f) << 16); -} - -/* The RA field in the DQ form lq instruction, which has special - value restrictions. */ - -static unsigned long -insert_raq (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - long rtvalue = (insn & RT_MASK) >> 21; - - if (value == rtvalue) - *errmsg = "source and target register operands must be different"; - return insn | ((value & 0x1f) << 16); -} - -/* The RA field in a D or X form instruction which is an updating - store or an updating floating point load, which means that the RA - field may not be zero. */ - -static unsigned long -insert_ras (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - if (value == 0) - *errmsg = "invalid register operand when updating"; - return insn | ((value & 0x1f) << 16); -} - -/* The RB field in an X form instruction when it must be the same as - the RS field in the instruction. This is used for extended - mnemonics like mr. This operand is marked FAKE. The insertion - function just copies the BT field into the BA field, and the - extraction function just checks that the fields are the same. */ - -static unsigned long -insert_rbs (unsigned long insn, - long value ATTRIBUTE_UNUSED, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (((insn >> 21) & 0x1f) << 11); -} - -static long -extract_rbs (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - if (((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) - *invalid = 1; - return 0; -} - -/* The SH field in an MD form instruction. This is split. */ - -static unsigned long -insert_sh6 (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); -} - -static long -extract_sh6 (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); -} - -/* The SPR field in an XFX form instruction. This is flipped--the - lower 5 bits are stored in the upper 5 and vice- versa. */ - -static unsigned long -insert_spr (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); -} - -static long -extract_spr (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); -} - -/* Some dialects have 8 SPRG registers instead of the standard 4. */ - -static unsigned long -insert_sprg (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - /* This check uses PPC_OPCODE_403 because PPC405 is later defined - as a synonym. If ever a 405 specific dialect is added this - check should use that instead. */ - if (value > 7 - || (value > 3 - && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) - *errmsg = "invalid sprg number"; - - /* If this is mfsprg4..7 then use spr 260..263 which can be read in - user mode. Anything else must use spr 272..279. */ - if (value <= 3 || (insn & 0x100) != 0) - value |= 0x10; - - return insn | ((value & 0x17) << 16); -} - -static long -extract_sprg (unsigned long insn, - int dialect, - int *invalid) -{ - unsigned long val = (insn >> 16) & 0x1f; - - /* mfsprg can use 260..263 and 272..279. mtsprg only uses spr 272..279 - If not BOOKE or 405, then both use only 272..275. */ - if (val <= 3 - || (val < 0x10 && (insn & 0x100) != 0) - || (val - 0x10 > 3 - && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) - *invalid = 1; - return val & 7; -} - -/* The TBR field in an XFX instruction. This is just like SPR, but it - is optional. When TBR is omitted, it must be inserted as 268 (the - magic number of the TB register). These functions treat 0 - (indicating an omitted optional operand) as 268. This means that - ``mftb 4,0'' is not handled correctly. This does not matter very - much, since the architecture manual does not define mftb as - accepting any values other than 268 or 269. */ - -#define TB (268) - -static unsigned long -insert_tbr (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - if (value == 0) - value = TB; - return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); -} - -static long -extract_tbr (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - long ret; - - ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); - if (ret == TB) - ret = 0; - return ret; -} - -/* Macros used to form opcodes. */ - -/* The main opcode. */ -#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26) -#define OP_MASK OP (0x3f) - -/* The main opcode combined with a trap code in the TO field of a D - form instruction. Used for extended mnemonics for the trap - instructions. */ -#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21)) -#define OPTO_MASK (OP_MASK | TO_MASK) - -/* The main opcode combined with a comparison size bit in the L field - of a D form or X form instruction. Used for extended mnemonics for - the comparison instructions. */ -#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21)) -#define OPL_MASK OPL (0x3f,1) - -/* An A form instruction. */ -#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1)) -#define A_MASK A (0x3f, 0x1f, 1) - -/* An A_MASK with the FRB field fixed. */ -#define AFRB_MASK (A_MASK | FRB_MASK) - -/* An A_MASK with the FRC field fixed. */ -#define AFRC_MASK (A_MASK | FRC_MASK) - -/* An A_MASK with the FRA and FRC fields fixed. */ -#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK) - -/* An AFRAFRC_MASK, but with L bit clear. */ -#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16)) - -/* A B form instruction. */ -#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1)) -#define B_MASK B (0x3f, 1, 1) - -/* A B form instruction setting the BO field. */ -#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) -#define BBO_MASK BBO (0x3f, 0x1f, 1, 1) - -/* A BBO_MASK with the y bit of the BO field removed. This permits - matching a conditional branch regardless of the setting of the y - bit. Similarly for the 'at' bits used for power4 branch hints. */ -#define Y_MASK (((unsigned long) 1) << 21) -#define AT1_MASK (((unsigned long) 3) << 21) -#define AT2_MASK (((unsigned long) 9) << 21) -#define BBOY_MASK (BBO_MASK &~ Y_MASK) -#define BBOAT_MASK (BBO_MASK &~ AT1_MASK) - -/* A B form instruction setting the BO field and the condition bits of - the BI field. */ -#define BBOCB(op, bo, cb, aa, lk) \ - (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16)) -#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1) - -/* A BBOCB_MASK with the y bit of the BO field removed. */ -#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK) -#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK) -#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK) - -/* A BBOYCB_MASK in which the BI field is fixed. */ -#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) -#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK) - -/* A Context form instruction. */ -#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7)) -#define CTX_MASK CTX(0x3f, 0x7) - -/* A User Context form instruction. */ -#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) -#define UCTX_MASK UCTX(0x3f, 0x1f) - -/* The main opcode mask with the RA field clear. */ -#define DRA_MASK (OP_MASK | RA_MASK) - -/* A DS form instruction. */ -#define DSO(op, xop) (OP (op) | ((xop) & 0x3)) -#define DS_MASK DSO (0x3f, 3) - -/* A DE form instruction. */ -#define DEO(op, xop) (OP (op) | ((xop) & 0xf)) -#define DE_MASK DEO (0x3e, 0xf) - -/* An EVSEL form instruction. */ -#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3) -#define EVSEL_MASK EVSEL(0x3f, 0xff) - -/* An M form instruction. */ -#define M(op, rc) (OP (op) | ((rc) & 1)) -#define M_MASK M (0x3f, 1) - -/* An M form instruction with the ME field specified. */ -#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1)) - -/* An M_MASK with the MB and ME fields fixed. */ -#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK) - -/* An M_MASK with the SH and ME fields fixed. */ -#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK) - -/* An MD form instruction. */ -#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1)) -#define MD_MASK MD (0x3f, 0x7, 1) - -/* An MD_MASK with the MB field fixed. */ -#define MDMB_MASK (MD_MASK | MB6_MASK) - -/* An MD_MASK with the SH field fixed. */ -#define MDSH_MASK (MD_MASK | SH6_MASK) - -/* An MDS form instruction. */ -#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1)) -#define MDS_MASK MDS (0x3f, 0xf, 1) - -/* An MDS_MASK with the MB field fixed. */ -#define MDSMB_MASK (MDS_MASK | MB6_MASK) - -/* An SC form instruction. */ -#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1)) -#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1) - -/* A VX form instruction. */ -#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff)) - -/* The mask for an VX form instruction. */ -#define VX_MASK VX(0x3f, 0x7ff) - -/* A VA form instruction. */ -#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f)) - -/* The mask for a VA form instruction. */ -#define VXA_MASK VXA(0x3f, 0x3f) - -/* A VXR form instruction. */ -#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff)) - -/* The mask for a VXR form instruction. */ -#define VXR_MASK VXR(0x3f, 0x3ff, 1) - -/* An X form instruction. */ -#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) - -/* A Z form instruction. */ -#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1)) - -/* An X form instruction with the RC bit specified. */ -#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1)) - -/* A Z form instruction with the RC bit specified. */ -#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1)) - -/* The mask for an X form instruction. */ -#define X_MASK XRC (0x3f, 0x3ff, 1) - -/* The mask for a Z form instruction. */ -#define Z_MASK ZRC (0x3f, 0x1ff, 1) -#define Z2_MASK ZRC (0x3f, 0xff, 1) - -/* An X_MASK with the RA field fixed. */ -#define XRA_MASK (X_MASK | RA_MASK) - -/* An XRA_MASK with the W field clear. */ -#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16)) - -/* An X_MASK with the RB field fixed. */ -#define XRB_MASK (X_MASK | RB_MASK) - -/* An X_MASK with the RT field fixed. */ -#define XRT_MASK (X_MASK | RT_MASK) - -/* An XRT_MASK mask with the L bits clear. */ -#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21)) - -/* An X_MASK with the RA and RB fields fixed. */ -#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) - -/* An X form instruction with the RA field fixed. */ -#define XRA(op, xop, ra) (X((op), (xop)) | (((ra) << 16) & XRA_MASK)) - -/* An XRARB_MASK, but with the L bit clear. */ -#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16)) - -/* An X_MASK with the RT and RA fields fixed. */ -#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK) - -/* An XRTRA_MASK, but with L bit clear. */ -#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21)) - -/* An X form instruction with the L bit specified. */ -#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21)) - -/* The mask for an X form comparison instruction. */ -#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22)) - -/* The mask for an X form comparison instruction with the L field - fixed. */ -#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21)) - -/* An X form trap instruction with the TO field specified. */ -#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21)) -#define XTO_MASK (X_MASK | TO_MASK) - -/* An X form tlb instruction with the SH field specified. */ -#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11)) -#define XTLB_MASK (X_MASK | SH_MASK) - -/* An X form sync instruction. */ -#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21)) - -/* An X form sync instruction with everything filled in except the LS field. */ -#define XSYNC_MASK (0xff9fffff) - -/* An X_MASK, but with the EH bit clear. */ -#define XEH_MASK (X_MASK & ~((unsigned long )1)) - -/* An X form AltiVec dss instruction. */ -#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25)) -#define XDSS_MASK XDSS(0x3f, 0x3ff, 1) - -/* An XFL form instruction. */ -#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1)) -#define XFL_MASK XFL (0x3f, 0x3ff, 1) - -/* An X form isel instruction. */ -#define XISEL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1)) -#define XISEL_MASK XISEL(0x3f, 0x1f) - -/* An XL form instruction with the LK field set to 0. */ -#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) - -/* An XL form instruction which uses the LK field. */ -#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1)) - -/* The mask for an XL form instruction. */ -#define XL_MASK XLLK (0x3f, 0x3ff, 1) - -/* An XL form instruction which explicitly sets the BO field. */ -#define XLO(op, bo, xop, lk) \ - (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) -#define XLO_MASK (XL_MASK | BO_MASK) - -/* An XL form instruction which explicitly sets the y bit of the BO - field. */ -#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21)) -#define XLYLK_MASK (XL_MASK | Y_MASK) - -/* An XL form instruction which sets the BO field and the condition - bits of the BI field. */ -#define XLOCB(op, bo, cb, xop, lk) \ - (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16)) -#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1) - -/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */ -#define XLBB_MASK (XL_MASK | BB_MASK) -#define XLYBB_MASK (XLYLK_MASK | BB_MASK) -#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK) - -/* A mask for branch instructions using the BH field. */ -#define XLBH_MASK (XL_MASK | (0x1c << 11)) - -/* An XL_MASK with the BO and BB fields fixed. */ -#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK) - -/* An XL_MASK with the BO, BI and BB fields fixed. */ -#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK) - -/* An XO form instruction. */ -#define XO(op, xop, oe, rc) \ - (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1)) -#define XO_MASK XO (0x3f, 0x1ff, 1, 1) - -/* An XO_MASK with the RB field fixed. */ -#define XORB_MASK (XO_MASK | RB_MASK) - -/* An XS form instruction. */ -#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1)) -#define XS_MASK XS (0x3f, 0x1ff, 1) - -/* A mask for the FXM version of an XFX form instruction. */ -#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20)) - -/* An XFX form instruction with the FXM field filled in. */ -#define XFXM(op, xop, fxm, p4) \ - (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \ - | ((unsigned long)(p4) << 20)) - -/* An XFX form instruction with the SPR field filled in. */ -#define XSPR(op, xop, spr) \ - (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6)) -#define XSPR_MASK (X_MASK | SPR_MASK) - -/* An XFX form instruction with the SPR field filled in except for the - SPRBAT field. */ -#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK) - -/* An XFX form instruction with the SPR field filled in except for the - SPRG field. */ -#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16)) - -/* An X form instruction with everything filled in except the E field. */ -#define XE_MASK (0xffff7fff) - -/* An X form user context instruction. */ -#define XUC(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) -#define XUC_MASK XUC(0x3f, 0x1f) - -/* The BO encodings used in extended conditional branch mnemonics. */ -#define BODNZF (0x0) -#define BODNZFP (0x1) -#define BODZF (0x2) -#define BODZFP (0x3) -#define BODNZT (0x8) -#define BODNZTP (0x9) -#define BODZT (0xa) -#define BODZTP (0xb) - -#define BOF (0x4) -#define BOFP (0x5) -#define BOFM4 (0x6) -#define BOFP4 (0x7) -#define BOT (0xc) -#define BOTP (0xd) -#define BOTM4 (0xe) -#define BOTP4 (0xf) - -#define BODNZ (0x10) -#define BODNZP (0x11) -#define BODZ (0x12) -#define BODZP (0x13) -#define BODNZM4 (0x18) -#define BODNZP4 (0x19) -#define BODZM4 (0x1a) -#define BODZP4 (0x1b) - -#define BOU (0x14) - -/* The BI condition bit encodings used in extended conditional branch - mnemonics. */ -#define CBLT (0) -#define CBGT (1) -#define CBEQ (2) -#define CBSO (3) - -/* The TO encodings used in extended trap mnemonics. */ -#define TOLGT (0x1) -#define TOLLT (0x2) -#define TOEQ (0x4) -#define TOLGE (0x5) -#define TOLNL (0x5) -#define TOLLE (0x6) -#define TOLNG (0x6) -#define TOGT (0x8) -#define TOGE (0xc) -#define TONL (0xc) -#define TOLT (0x10) -#define TOLE (0x14) -#define TONG (0x14) -#define TONE (0x18) -#define TOU (0x1f) - -/* Smaller names for the flags so each entry in the opcodes table will - fit on a single line. */ -#undef PPC -#define PPC PPC_OPCODE_PPC -#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON -#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM -#define POWER4 PPC_OPCODE_POWER4 -#define POWER5 PPC_OPCODE_POWER5 -#define POWER6 PPC_OPCODE_POWER6 -/* Documentation purposes only; we don't actually check the isa for disas. */ -#define POWER7 PPC_OPCODE_POWER6 -#define POWER9 PPC_OPCODE_POWER6 -#define CELL PPC_OPCODE_CELL -#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC -#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC -#define PPC403 PPC_OPCODE_403 -#define PPC405 PPC403 -#define PPC440 PPC_OPCODE_440 -#define PPC750 PPC -#define PPC860 PPC -#define PPCVEC PPC_OPCODE_ALTIVEC -#define POWER PPC_OPCODE_POWER -#define POWER2 PPC_OPCODE_POWER | PPC_OPCODE_POWER2 -#define PPCPWR2 PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2 -#define POWER32 PPC_OPCODE_POWER | PPC_OPCODE_32 -#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON -#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32 -#define M601 PPC_OPCODE_POWER | PPC_OPCODE_601 -#define PWRCOM PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON -#define MFDEC1 PPC_OPCODE_POWER -#define MFDEC2 PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE -#define BOOKE PPC_OPCODE_BOOKE -#define BOOKE64 PPC_OPCODE_BOOKE64 -#define CLASSIC PPC_OPCODE_CLASSIC -#define PPCE300 PPC_OPCODE_E300 -#define PPCSPE PPC_OPCODE_SPE -#define PPCISEL PPC_OPCODE_ISEL -#define PPCEFS PPC_OPCODE_EFS -#define PPCBRLK PPC_OPCODE_BRLOCK -#define PPCPMR PPC_OPCODE_PMR -#define PPCCHLK PPC_OPCODE_CACHELCK -#define PPCCHLK64 PPC_OPCODE_CACHELCK | PPC_OPCODE_BOOKE64 -#define PPCRFMCI PPC_OPCODE_RFMCI - -/* The opcode table. - - The format of the opcode table is: - - NAME OPCODE MASK FLAGS { OPERANDS } - - NAME is the name of the instruction. - OPCODE is the instruction opcode. - MASK is the opcode mask; this is used to tell the disassembler - which bits in the actual opcode must match OPCODE. - FLAGS are flags indicated what processors support the instruction. - OPERANDS is the list of operands. - - The disassembler reads the table in order and prints the first - instruction which matches, so this table is sorted to put more - specific instructions before more general instructions. It is also - sorted by major opcode. */ - -const struct powerpc_opcode powerpc_opcodes[] = { -{ "attn", X(0,256), X_MASK, POWER4, { 0 } }, -{ "tdlgti", OPTO(2,TOLGT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdllti", OPTO(2,TOLLT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdeqi", OPTO(2,TOEQ), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlgei", OPTO(2,TOLGE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlnli", OPTO(2,TOLNL), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdllei", OPTO(2,TOLLE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlngi", OPTO(2,TOLNG), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdgti", OPTO(2,TOGT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdgei", OPTO(2,TOGE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdnli", OPTO(2,TONL), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlti", OPTO(2,TOLT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlei", OPTO(2,TOLE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdngi", OPTO(2,TONG), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdnei", OPTO(2,TONE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdi", OP(2), OP_MASK, PPC64, { TO, RA, SI } }, - -{ "twlgti", OPTO(3,TOLGT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlgti", OPTO(3,TOLGT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twllti", OPTO(3,TOLLT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tllti", OPTO(3,TOLLT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "tweqi", OPTO(3,TOEQ), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "teqi", OPTO(3,TOEQ), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlgei", OPTO(3,TOLGE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlgei", OPTO(3,TOLGE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlnli", OPTO(3,TOLNL), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlnli", OPTO(3,TOLNL), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twllei", OPTO(3,TOLLE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tllei", OPTO(3,TOLLE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlngi", OPTO(3,TOLNG), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlngi", OPTO(3,TOLNG), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twgti", OPTO(3,TOGT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tgti", OPTO(3,TOGT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twgei", OPTO(3,TOGE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tgei", OPTO(3,TOGE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twnli", OPTO(3,TONL), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tnli", OPTO(3,TONL), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlti", OPTO(3,TOLT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlti", OPTO(3,TOLT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlei", OPTO(3,TOLE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlei", OPTO(3,TOLE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twngi", OPTO(3,TONG), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tngi", OPTO(3,TONG), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twnei", OPTO(3,TONE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tnei", OPTO(3,TONE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twi", OP(3), OP_MASK, PPCCOM, { TO, RA, SI } }, -{ "ti", OP(3), OP_MASK, PWRCOM, { TO, RA, SI } }, - -{ "macchw", XO(4,172,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchw.", XO(4,172,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwo", XO(4,172,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwo.", XO(4,172,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchws", XO(4,236,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchws.", XO(4,236,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwso", XO(4,236,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwso.", XO(4,236,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsu", XO(4,204,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsu.", XO(4,204,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsuo", XO(4,204,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsuo.", XO(4,204,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwu", XO(4,140,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwu.", XO(4,140,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwuo", XO(4,140,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwuo.", XO(4,140,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhw", XO(4,44,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhw.", XO(4,44,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwo", XO(4,44,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwo.", XO(4,44,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhws", XO(4,108,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhws.", XO(4,108,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwso", XO(4,108,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwso.", XO(4,108,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsu", XO(4,76,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsu.", XO(4,76,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsuo", XO(4,76,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsuo.", XO(4,76,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwu", XO(4,12,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwu.", XO(4,12,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwuo", XO(4,12,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwuo.", XO(4,12,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhw", XO(4,428,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhw.", XO(4,428,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwo", XO(4,428,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwo.", XO(4,428,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhws", XO(4,492,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhws.", XO(4,492,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwso", XO(4,492,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwso.", XO(4,492,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsu", XO(4,460,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsu.", XO(4,460,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsuo", XO(4,460,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsuo.", XO(4,460,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwu", XO(4,396,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwu.", XO(4,396,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwuo", XO(4,396,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwuo.", XO(4,396,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchw", XRC(4,168,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchw.", XRC(4,168,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchwu", XRC(4,136,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchwu.", XRC(4,136,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhw", XRC(4,40,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhw.", XRC(4,40,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhwu", XRC(4,8,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhwu.", XRC(4,8,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhw", XRC(4,424,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhw.", XRC(4,424,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhwu", XRC(4,392,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhwu.", XRC(4,392,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchw", XO(4,174,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchw.", XO(4,174,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwo", XO(4,174,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwo.", XO(4,174,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchws", XO(4,238,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchws.", XO(4,238,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwso", XO(4,238,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwso.", XO(4,238,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhw", XO(4,46,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhw.", XO(4,46,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwo", XO(4,46,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwo.", XO(4,46,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhws", XO(4,110,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhws.", XO(4,110,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwso", XO(4,110,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwso.", XO(4,110,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhw", XO(4,430,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhw.", XO(4,430,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwo", XO(4,430,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwo.", XO(4,430,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhws", XO(4,494,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhws.", XO(4,494,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwso", XO(4,494,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwso.", XO(4,494,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mfvscr", VX(4, 1540), VX_MASK, PPCVEC, { VD } }, -{ "mtvscr", VX(4, 1604), VX_MASK, PPCVEC, { VB } }, - - /* Double-precision opcodes. */ - /* Some of these conflict with AltiVec, so move them before, since - PPCVEC includes the PPC_OPCODE_PPC set. */ -{ "efscfd", VX(4, 719), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdabs", VX(4, 740), VX_MASK, PPCEFS, { RS, RA } }, -{ "efdnabs", VX(4, 741), VX_MASK, PPCEFS, { RS, RA } }, -{ "efdneg", VX(4, 742), VX_MASK, PPCEFS, { RS, RA } }, -{ "efdadd", VX(4, 736), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efdsub", VX(4, 737), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efdmul", VX(4, 744), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efddiv", VX(4, 745), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efdcmpgt", VX(4, 748), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdcmplt", VX(4, 749), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdcmpeq", VX(4, 750), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdtstgt", VX(4, 764), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdtstlt", VX(4, 765), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdtsteq", VX(4, 766), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdcfsi", VX(4, 753), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfsid", VX(4, 739), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfui", VX(4, 752), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfuid", VX(4, 738), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfsf", VX(4, 755), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfuf", VX(4, 754), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsi", VX(4, 757), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsidz",VX(4, 747), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsiz", VX(4, 762), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctui", VX(4, 756), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctuidz",VX(4, 746), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctuiz", VX(4, 760), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsf", VX(4, 759), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctuf", VX(4, 758), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfs", VX(4, 751), VX_MASK, PPCEFS, { RS, RB } }, - /* End of double-precision opcodes. */ - -{ "vaddcuw", VX(4, 384), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddfp", VX(4, 10), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddsbs", VX(4, 768), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddshs", VX(4, 832), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddsws", VX(4, 896), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddubm", VX(4, 0), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddubs", VX(4, 512), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduhm", VX(4, 64), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduhs", VX(4, 576), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduwm", VX(4, 128), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduws", VX(4, 640), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vand", VX(4, 1028), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vandc", VX(4, 1092), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgsb", VX(4, 1282), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgsh", VX(4, 1346), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgsw", VX(4, 1410), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgub", VX(4, 1026), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavguh", VX(4, 1090), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavguw", VX(4, 1154), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcfsx", VX(4, 842), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vcfux", VX(4, 778), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vcmpbfp", VXR(4, 966, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpbfp.", VXR(4, 966, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpeqfp", VXR(4, 198, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequb", VXR(4, 6, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequb.", VXR(4, 6, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequh", VXR(4, 70, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequh.", VXR(4, 70, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequw", VXR(4, 134, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgefp", VXR(4, 454, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtfp", VXR(4, 710, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsb", VXR(4, 774, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsh", VXR(4, 838, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsw", VXR(4, 902, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtub", VXR(4, 518, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuh", VXR(4, 582, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuw", VXR(4, 646, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vctsxs", VX(4, 970), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vctuxs", VX(4, 906), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vexptefp", VX(4, 394), VX_MASK, PPCVEC, { VD, VB } }, -{ "vlogefp", VX(4, 458), VX_MASK, PPCVEC, { VD, VB } }, -{ "vmaddfp", VXA(4, 46), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, -{ "vmaxfp", VX(4, 1034), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxsb", VX(4, 258), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxsh", VX(4, 322), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxsw", VX(4, 386), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxub", VX(4, 2), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxuh", VX(4, 66), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxuw", VX(4, 130), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmhaddshs", VXA(4, 32), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmhraddshs", VXA(4, 33), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vminfp", VX(4, 1098), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminsb", VX(4, 770), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminsh", VX(4, 834), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminsw", VX(4, 898), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminub", VX(4, 514), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminuh", VX(4, 578), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminuw", VX(4, 642), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmladduhm", VXA(4, 34), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmrghb", VX(4, 12), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrghh", VX(4, 76), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrghw", VX(4, 140), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrglb", VX(4, 268), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrglh", VX(4, 332), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrglw", VX(4, 396), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmsummbm", VXA(4, 37), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumshm", VXA(4, 40), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumshs", VXA(4, 41), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumubm", VXA(4, 36), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumuhm", VXA(4, 38), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumuhs", VXA(4, 39), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmulesb", VX(4, 776), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulesh", VX(4, 840), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmuleub", VX(4, 520), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmuleuh", VX(4, 584), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulosb", VX(4, 264), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulosh", VX(4, 328), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmuloub", VX(4, 8), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulouh", VX(4, 72), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vnmsubfp", VXA(4, 47), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, -{ "vnor", VX(4, 1284), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vor", VX(4, 1156), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vperm", VXA(4, 43), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vpkpx", VX(4, 782), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkshss", VX(4, 398), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkshus", VX(4, 270), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkswss", VX(4, 462), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkswus", VX(4, 334), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuhum", VX(4, 14), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuhus", VX(4, 142), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuwum", VX(4, 78), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuwus", VX(4, 206), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrefp", VX(4, 266), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfim", VX(4, 714), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfin", VX(4, 522), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfip", VX(4, 650), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfiz", VX(4, 586), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrlb", VX(4, 4), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrlh", VX(4, 68), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrlw", VX(4, 132), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrsqrtefp", VX(4, 330), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrldmi", VX(4, 197), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrldnm", VX(4, 453), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrlwmi", VX(4, 133), VX_MASK, PPCVEC, { VD, VA, VB} }, -{ "vrlwnm", VX(4, 389), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsel", VXA(4, 42), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vslb", VX(4, 260), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsldoi", VXA(4, 44), VXA_MASK, PPCVEC, { VD, VA, VB, SHB } }, -{ "vslh", VX(4, 324), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vslo", VX(4, 1036), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vslw", VX(4, 388), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vspltb", VX(4, 524), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vsplth", VX(4, 588), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vspltisb", VX(4, 780), VX_MASK, PPCVEC, { VD, SIMM } }, -{ "vspltish", VX(4, 844), VX_MASK, PPCVEC, { VD, SIMM } }, -{ "vspltisw", VX(4, 908), VX_MASK, PPCVEC, { VD, SIMM } }, -{ "vspltw", VX(4, 652), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vsr", VX(4, 708), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrab", VX(4, 772), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrah", VX(4, 836), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsraw", VX(4, 900), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrb", VX(4, 516), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrh", VX(4, 580), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsro", VX(4, 1100), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrw", VX(4, 644), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubcuw", VX(4, 1408), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubfp", VX(4, 74), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubsbs", VX(4, 1792), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubshs", VX(4, 1856), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubsws", VX(4, 1920), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsububm", VX(4, 1024), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsububs", VX(4, 1536), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuhm", VX(4, 1088), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuhs", VX(4, 1600), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuwm", VX(4, 1152), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuws", VX(4, 1664), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsumsws", VX(4, 1928), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum2sws", VX(4, 1672), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum4sbs", VX(4, 1800), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum4shs", VX(4, 1608), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum4ubs", VX(4, 1544), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vupkhpx", VX(4, 846), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupkhsb", VX(4, 526), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupkhsh", VX(4, 590), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupklpx", VX(4, 974), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupklsb", VX(4, 654), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupklsh", VX(4, 718), VX_MASK, PPCVEC, { VD, VB } }, -{ "vxor", VX(4, 1220), VX_MASK, PPCVEC, { VD, VA, VB } }, - -{ "evaddw", VX(4, 512), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evaddiw", VX(4, 514), VX_MASK, PPCSPE, { RS, RB, UIMM } }, -{ "evsubfw", VX(4, 516), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evsubw", VX(4, 516), VX_MASK, PPCSPE, { RS, RB, RA } }, -{ "evsubifw", VX(4, 518), VX_MASK, PPCSPE, { RS, UIMM, RB } }, -{ "evsubiw", VX(4, 518), VX_MASK, PPCSPE, { RS, RB, UIMM } }, -{ "evabs", VX(4, 520), VX_MASK, PPCSPE, { RS, RA } }, -{ "evneg", VX(4, 521), VX_MASK, PPCSPE, { RS, RA } }, -{ "evextsb", VX(4, 522), VX_MASK, PPCSPE, { RS, RA } }, -{ "evextsh", VX(4, 523), VX_MASK, PPCSPE, { RS, RA } }, -{ "evrndw", VX(4, 524), VX_MASK, PPCSPE, { RS, RA } }, -{ "evcntlzw", VX(4, 525), VX_MASK, PPCSPE, { RS, RA } }, -{ "evcntlsw", VX(4, 526), VX_MASK, PPCSPE, { RS, RA } }, - -{ "brinc", VX(4, 527), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evand", VX(4, 529), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evandc", VX(4, 530), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmr", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, BBA } }, -{ "evor", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evorc", VX(4, 539), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evxor", VX(4, 534), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "eveqv", VX(4, 537), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evnand", VX(4, 542), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evnot", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, BBA } }, -{ "evnor", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evrlw", VX(4, 552), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evrlwi", VX(4, 554), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evslw", VX(4, 548), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evslwi", VX(4, 550), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evsrws", VX(4, 545), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evsrwu", VX(4, 544), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evsrwis", VX(4, 547), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evsrwiu", VX(4, 546), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evsplati", VX(4, 553), VX_MASK, PPCSPE, { RS, SIMM } }, -{ "evsplatfi", VX(4, 555), VX_MASK, PPCSPE, { RS, SIMM } }, -{ "evmergehi", VX(4, 556), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmergelo", VX(4, 557), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmergehilo",VX(4,558), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmergelohi",VX(4,559), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evcmpgts", VX(4, 561), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmpgtu", VX(4, 560), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmplts", VX(4, 563), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmpltu", VX(4, 562), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmpeq", VX(4, 564), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evsel", EVSEL(4,79),EVSEL_MASK, PPCSPE, { RS, RA, RB, CRFS } }, - -{ "evldd", VX(4, 769), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evlddx", VX(4, 768), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evldw", VX(4, 771), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evldwx", VX(4, 770), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evldh", VX(4, 773), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evldhx", VX(4, 772), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhe", VX(4, 785), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhex", VX(4, 784), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhou", VX(4, 789), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhoux", VX(4, 788), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhos", VX(4, 791), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhosx", VX(4, 790), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwwsplat",VX(4, 793), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwwsplatx",VX(4, 792), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhsplat",VX(4, 797), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhsplatx",VX(4, 796), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlhhesplat",VX(4, 777), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, -{ "evlhhesplatx",VX(4, 776), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlhhousplat",VX(4, 781), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, -{ "evlhhousplatx",VX(4, 780), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlhhossplat",VX(4, 783), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, -{ "evlhhossplatx",VX(4, 782), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evstdd", VX(4, 801), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evstddx", VX(4, 800), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstdw", VX(4, 803), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evstdwx", VX(4, 802), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstdh", VX(4, 805), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evstdhx", VX(4, 804), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwwe", VX(4, 825), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwwex", VX(4, 824), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwwo", VX(4, 829), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwwox", VX(4, 828), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwhe", VX(4, 817), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwhex", VX(4, 816), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwho", VX(4, 821), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwhox", VX(4, 820), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evfsabs", VX(4, 644), VX_MASK, PPCSPE, { RS, RA } }, -{ "evfsnabs", VX(4, 645), VX_MASK, PPCSPE, { RS, RA } }, -{ "evfsneg", VX(4, 646), VX_MASK, PPCSPE, { RS, RA } }, -{ "evfsadd", VX(4, 640), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfssub", VX(4, 641), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfsmul", VX(4, 648), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfsdiv", VX(4, 649), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfscmpgt", VX(4, 652), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfscmplt", VX(4, 653), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfscmpeq", VX(4, 654), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfststgt", VX(4, 668), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfststlt", VX(4, 669), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfststeq", VX(4, 670), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfscfui", VX(4, 656), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctuiz", VX(4, 664), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfscfsi", VX(4, 657), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfscfuf", VX(4, 658), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfscfsf", VX(4, 659), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctui", VX(4, 660), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctsi", VX(4, 661), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctsiz", VX(4, 666), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctuf", VX(4, 662), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctsf", VX(4, 663), VX_MASK, PPCSPE, { RS, RB } }, - -{ "efsabs", VX(4, 708), VX_MASK, PPCEFS, { RS, RA } }, -{ "efsnabs", VX(4, 709), VX_MASK, PPCEFS, { RS, RA } }, -{ "efsneg", VX(4, 710), VX_MASK, PPCEFS, { RS, RA } }, -{ "efsadd", VX(4, 704), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efssub", VX(4, 705), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efsmul", VX(4, 712), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efsdiv", VX(4, 713), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efscmpgt", VX(4, 716), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efscmplt", VX(4, 717), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efscmpeq", VX(4, 718), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efststgt", VX(4, 732), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efststlt", VX(4, 733), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efststeq", VX(4, 734), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efscfui", VX(4, 720), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctuiz", VX(4, 728), VX_MASK, PPCEFS, { RS, RB } }, -{ "efscfsi", VX(4, 721), VX_MASK, PPCEFS, { RS, RB } }, -{ "efscfuf", VX(4, 722), VX_MASK, PPCEFS, { RS, RB } }, -{ "efscfsf", VX(4, 723), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctui", VX(4, 724), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctsi", VX(4, 725), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctsiz", VX(4, 730), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctuf", VX(4, 726), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctsf", VX(4, 727), VX_MASK, PPCEFS, { RS, RB } }, - -{ "evmhossf", VX(4, 1031), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhossfa", VX(4, 1063), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmf", VX(4, 1039), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmfa", VX(4, 1071), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmi", VX(4, 1037), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmia", VX(4, 1069), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumi", VX(4, 1036), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumia", VX(4, 1068), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessf", VX(4, 1027), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessfa", VX(4, 1059), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmf", VX(4, 1035), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmfa", VX(4, 1067), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmi", VX(4, 1033), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmia", VX(4, 1065), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumi", VX(4, 1032), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumia", VX(4, 1064), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhossfaaw",VX(4, 1287), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhossiaaw",VX(4, 1285), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmfaaw",VX(4, 1295), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmiaaw",VX(4, 1293), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhousiaaw",VX(4, 1284), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumiaaw",VX(4, 1292), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessfaaw",VX(4, 1283), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessiaaw",VX(4, 1281), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmfaaw",VX(4, 1291), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmiaaw",VX(4, 1289), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheusiaaw",VX(4, 1280), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumiaaw",VX(4, 1288), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhossfanw",VX(4, 1415), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhossianw",VX(4, 1413), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmfanw",VX(4, 1423), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmianw",VX(4, 1421), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhousianw",VX(4, 1412), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumianw",VX(4, 1420), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessfanw",VX(4, 1411), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessianw",VX(4, 1409), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmfanw",VX(4, 1419), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmianw",VX(4, 1417), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheusianw",VX(4, 1408), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumianw",VX(4, 1416), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhogsmfaa",VX(4, 1327), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogsmiaa",VX(4, 1325), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogumiaa",VX(4, 1324), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmfaa",VX(4, 1323), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmiaa",VX(4, 1321), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegumiaa",VX(4, 1320), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhogsmfan",VX(4, 1455), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogsmian",VX(4, 1453), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogumian",VX(4, 1452), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmfan",VX(4, 1451), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmian",VX(4, 1449), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegumian",VX(4, 1448), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwhssf", VX(4, 1095), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhssfa", VX(4, 1127), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmf", VX(4, 1103), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmfa", VX(4, 1135), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmi", VX(4, 1101), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmia", VX(4, 1133), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhumi", VX(4, 1100), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhumia", VX(4, 1132), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwlumi", VX(4, 1096), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlumia", VX(4, 1128), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwlssiaaw",VX(4, 1345), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlsmiaaw",VX(4, 1353), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlusiaaw",VX(4, 1344), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlumiaaw",VX(4, 1352), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwlssianw",VX(4, 1473), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlsmianw",VX(4, 1481), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlusianw",VX(4, 1472), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlumianw",VX(4, 1480), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwssf", VX(4, 1107), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwssfa", VX(4, 1139), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmf", VX(4, 1115), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmfa", VX(4, 1147), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmi", VX(4, 1113), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmia", VX(4, 1145), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumi", VX(4, 1112), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumia", VX(4, 1144), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwssfaa", VX(4, 1363), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmfaa", VX(4, 1371), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmiaa", VX(4, 1369), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumiaa", VX(4, 1368), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwssfan", VX(4, 1491), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmfan", VX(4, 1499), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmian", VX(4, 1497), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumian", VX(4, 1496), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evaddssiaaw",VX(4, 1217), VX_MASK, PPCSPE, { RS, RA } }, -{ "evaddsmiaaw",VX(4, 1225), VX_MASK, PPCSPE, { RS, RA } }, -{ "evaddusiaaw",VX(4, 1216), VX_MASK, PPCSPE, { RS, RA } }, -{ "evaddumiaaw",VX(4, 1224), VX_MASK, PPCSPE, { RS, RA } }, - -{ "evsubfssiaaw",VX(4, 1219), VX_MASK, PPCSPE, { RS, RA } }, -{ "evsubfsmiaaw",VX(4, 1227), VX_MASK, PPCSPE, { RS, RA } }, -{ "evsubfusiaaw",VX(4, 1218), VX_MASK, PPCSPE, { RS, RA } }, -{ "evsubfumiaaw",VX(4, 1226), VX_MASK, PPCSPE, { RS, RA } }, - -{ "evmra", VX(4, 1220), VX_MASK, PPCSPE, { RS, RA } }, - -{ "evdivws", VX(4, 1222), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evdivwu", VX(4, 1223), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "mulli", OP(7), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "muli", OP(7), OP_MASK, PWRCOM, { RT, RA, SI } }, - -{ "subfic", OP(8), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "sfi", OP(8), OP_MASK, PWRCOM, { RT, RA, SI } }, - -{ "dozi", OP(9), OP_MASK, M601, { RT, RA, SI } }, - -{ "bce", B(9,0,0), B_MASK, BOOKE64, { BO, BI, BD } }, -{ "bcel", B(9,0,1), B_MASK, BOOKE64, { BO, BI, BD } }, -{ "bcea", B(9,1,0), B_MASK, BOOKE64, { BO, BI, BDA } }, -{ "bcela", B(9,1,1), B_MASK, BOOKE64, { BO, BI, BDA } }, - -{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } }, -{ "cmpldi", OPL(10,1), OPL_MASK, PPC64, { OBF, RA, UI } }, -{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } }, -{ "cmpli", OP(10), OP_MASK, PWRCOM, { BF, RA, UI } }, - -{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } }, -{ "cmpdi", OPL(11,1), OPL_MASK, PPC64, { OBF, RA, SI } }, -{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } }, -{ "cmpi", OP(11), OP_MASK, PWRCOM, { BF, RA, SI } }, - -{ "addic", OP(12), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "ai", OP(12), OP_MASK, PWRCOM, { RT, RA, SI } }, -{ "subic", OP(12), OP_MASK, PPCCOM, { RT, RA, NSI } }, - -{ "addic.", OP(13), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "ai.", OP(13), OP_MASK, PWRCOM, { RT, RA, SI } }, -{ "subic.", OP(13), OP_MASK, PPCCOM, { RT, RA, NSI } }, - -{ "li", OP(14), DRA_MASK, PPCCOM, { RT, SI } }, -{ "lil", OP(14), DRA_MASK, PWRCOM, { RT, SI } }, -{ "addi", OP(14), OP_MASK, PPCCOM, { RT, RA0, SI } }, -{ "cal", OP(14), OP_MASK, PWRCOM, { RT, D, RA0 } }, -{ "subi", OP(14), OP_MASK, PPCCOM, { RT, RA0, NSI } }, -{ "la", OP(14), OP_MASK, PPCCOM, { RT, D, RA0 } }, - -{ "lis", OP(15), DRA_MASK, PPCCOM, { RT, SISIGNOPT } }, -{ "liu", OP(15), DRA_MASK, PWRCOM, { RT, SISIGNOPT } }, -{ "addis", OP(15), OP_MASK, PPCCOM, { RT,RA0,SISIGNOPT } }, -{ "cau", OP(15), OP_MASK, PWRCOM, { RT,RA0,SISIGNOPT } }, -{ "subis", OP(15), OP_MASK, PPCCOM, { RT, RA0, NSI } }, - -{ "bdnz-", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdnz+", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdnz", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BD } }, -{ "bdn", BBO(16,BODNZ,0,0), BBOATBI_MASK, PWRCOM, { BD } }, -{ "bdnzl-", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdnzl+", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdnzl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BD } }, -{ "bdnl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PWRCOM, { BD } }, -{ "bdnza-", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdnza+", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdnza", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDA } }, -{ "bdna", BBO(16,BODNZ,1,0), BBOATBI_MASK, PWRCOM, { BDA } }, -{ "bdnzla-", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdnzla+", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdnzla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDA } }, -{ "bdnla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PWRCOM, { BDA } }, -{ "bdz-", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdz+", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdz", BBO(16,BODZ,0,0), BBOATBI_MASK, COM, { BD } }, -{ "bdzl-", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdzl+", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdzl", BBO(16,BODZ,0,1), BBOATBI_MASK, COM, { BD } }, -{ "bdza-", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdza+", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdza", BBO(16,BODZ,1,0), BBOATBI_MASK, COM, { BDA } }, -{ "bdzla-", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdzla+", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdzla", BBO(16,BODZ,1,1), BBOATBI_MASK, COM, { BDA } }, -{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "blt+", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "blt", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bltl-", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bltl+", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bltl", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "blta-", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "blta+", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "blta", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bltla-", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bltla+", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bltla", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bgt-", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bgt+", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bgt", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgtl-", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bgtl+", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bgtl", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgta-", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgta+", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgta", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bgtla-", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgtla+", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgtla", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "beq-", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "beq+", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "beq", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "beql-", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "beql+", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "beql", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "beqa-", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "beqa+", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "beqa", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "beqla-", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "beqla+", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "beqla", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bso-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bso+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bso", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bsol-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bsol+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bsol", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bsoa-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bsoa+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bsoa", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bsola-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bsola+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bsola", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bun-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bun+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bun", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "bunl-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bunl+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bunl", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "buna-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "buna+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "buna", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bunla-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bunla+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bunla", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bge-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bge+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bge", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgel-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bgel+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bgel", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgea-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgea+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgea", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bgela-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgela+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgela", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnl-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnl+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnl", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnll-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnll+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnll", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnla-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnla+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnla", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnlla-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnlla+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnlla", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "ble-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "ble+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "ble", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "blel-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "blel+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "blel", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "blea-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "blea+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "blea", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "blela-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "blela+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "blela", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bng-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bng+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bng", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bngl-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bngl+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bngl", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnga-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnga+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnga", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bngla-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bngla+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bngla", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bne-", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bne+", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bne", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnel-", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnel+", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnel", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnea-", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnea+", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnea", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnela-", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnela+", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnela", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bns-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bns+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bns", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnsl-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnsl+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnsl", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnsa-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnsa+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnsa", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnsla-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnsla+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnsla", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnu-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnu+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnu", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "bnul-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnul+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnul", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "bnua-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnua+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnua", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bnula-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnula+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnula", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bdnzt-", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnzt+", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnzt", BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnztl", BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnzta", BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdnzf-", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnzf+", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnzf", BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnzfl", BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnzfa", BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bt-", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "bt+", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "bt", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbt", BBO(16,BOT,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "btl-", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "btl+", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "btl", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbtl", BBO(16,BOT,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "bta-", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "bta+", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "bta", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbta", BBO(16,BOT,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "btla-", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "btla+", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "btla", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbtla", BBO(16,BOT,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "bf-", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "bf+", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "bf", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbf", BBO(16,BOF,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "bfl-", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "bfl+", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "bfl", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbfl", BBO(16,BOF,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "bfa-", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "bfa+", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "bfa", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbfa", BBO(16,BOF,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "bfla-", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "bfla+", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "bfla", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbfla", BBO(16,BOF,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "bdzt-", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdzt+", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdzt", BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdztl-", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdztl+", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdztl", BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdzta-", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdzta+", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdzta", BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdztla", BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdzf-", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdzf+", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdzf", BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdzfl-", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdzfl+", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdzfl", BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdzfa-", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdzfa+", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdzfa", BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdzfla", BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bc-", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDM } }, -{ "bc+", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDP } }, -{ "bc", B(16,0,0), B_MASK, COM, { BO, BI, BD } }, -{ "bcl-", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDM } }, -{ "bcl+", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDP } }, -{ "bcl", B(16,0,1), B_MASK, COM, { BO, BI, BD } }, -{ "bca-", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDMA } }, -{ "bca+", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDPA } }, -{ "bca", B(16,1,0), B_MASK, COM, { BO, BI, BDA } }, -{ "bcla-", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDMA } }, -{ "bcla+", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDPA } }, -{ "bcla", B(16,1,1), B_MASK, COM, { BO, BI, BDA } }, - -{ "sc", SC(17,1,0), SC_MASK, PPC, { LEV } }, -{ "svc", SC(17,0,0), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, -{ "svcl", SC(17,0,1), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, -{ "svca", SC(17,1,0), SC_MASK, PWRCOM, { SV } }, -{ "svcla", SC(17,1,1), SC_MASK, POWER, { SV } }, - -{ "b", B(18,0,0), B_MASK, COM, { LI } }, -{ "bl", B(18,0,1), B_MASK, COM, { LI } }, -{ "ba", B(18,1,0), B_MASK, COM, { LIA } }, -{ "bla", B(18,1,1), B_MASK, COM, { LIA } }, - -{ "mcrf", XL(19,0), XLBB_MASK|(3 << 21)|(3 << 16), COM, { BF, BFA } }, - -{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "br", XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM, { 0 } }, -{ "blrl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "brl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM, { 0 } }, -{ "bdnzlr", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlr-", XLO(19,BODNZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlr+", XLO(19,BODNZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlrl-",XLO(19,BODNZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlrl+",XLO(19,BODNZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlr", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdzlr-", XLO(19,BODZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlr-", XLO(19,BODZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlr+", XLO(19,BODZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlr+", XLO(19,BODZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlrl", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlrl-", XLO(19,BODZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlrl+", XLO(19,BODZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bltlr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltlr-", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlr-", XLOCB(19,BOTM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltlr+", XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlr+", XLOCB(19,BOTP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bltlrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlrl-", XLOCB(19,BOTM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlrl+", XLOCB(19,BOTP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bgtlr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtlr-", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlr-", XLOCB(19,BOTM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtlr+", XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlr+", XLOCB(19,BOTP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bgtlrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlrl-", XLOCB(19,BOTM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlrl+", XLOCB(19,BOTP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "beqlr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqlr-", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlr-", XLOCB(19,BOTM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqlr+", XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlr+", XLOCB(19,BOTP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "beqlrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlrl-", XLOCB(19,BOTM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlrl+", XLOCB(19,BOTP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bsolr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsolr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsolr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsor", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bsolrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsorl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bunlr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunlr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunlr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunlrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgelr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgelr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgelr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bger", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bgelrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgerl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnllr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnllr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnllr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnllrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "blelr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blelr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blelr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bler", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "blelrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blerl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnglr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnglr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnglr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnglrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnelr", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnelr-", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelr-", XLOCB(19,BOFM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnelr+", XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelr+", XLOCB(19,BOFP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bner", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnelrl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelrl-", XLOCB(19,BOFM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelrl+", XLOCB(19,BOFP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnerl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnslr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnslr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnslr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnslrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnulr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnulr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnulr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnulrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "btlr", XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btlr-", XLO(19,BOT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlr-", XLO(19,BOTM4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "btlr+", XLO(19,BOTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlr+", XLO(19,BOTP4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bbtr", XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM, { BI } }, -{ "btlrl", XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btlrl-", XLO(19,BOT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlrl-", XLO(19,BOTM4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "btlrl+", XLO(19,BOTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlrl+", XLO(19,BOTP4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bbtrl", XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM, { BI } }, -{ "bflr", XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bflr-", XLO(19,BOF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflr-", XLO(19,BOFM4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bflr+", XLO(19,BOFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflr+", XLO(19,BOFP4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bbfr", XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM, { BI } }, -{ "bflrl", XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bflrl-", XLO(19,BOF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflrl-", XLO(19,BOFM4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bflrl+", XLO(19,BOFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflrl+", XLO(19,BOFP4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bbfrl", XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM, { BI } }, -{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlr", XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflr", XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bclr+", XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclrl+", XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclr-", XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclrl-", XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclr", XLLK(19,16,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bclrl", XLLK(19,16,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bcr", XLLK(19,16,0), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bcrl", XLLK(19,16,1), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bclre", XLLK(19,17,0), XLBB_MASK, BOOKE64, { BO, BI } }, -{ "bclrel", XLLK(19,17,1), XLBB_MASK, BOOKE64, { BO, BI } }, - -{ "rfid", XL(19,18), 0xffffffff, PPC64, { 0 } }, - -{ "crnot", XL(19,33), XL_MASK, PPCCOM, { BT, BA, BBA } }, -{ "crnor", XL(19,33), XL_MASK, COM, { BT, BA, BB } }, -{ "rfmci", X(19,38), 0xffffffff, PPCRFMCI, { 0 } }, - -{ "rfi", XL(19,50), 0xffffffff, COM, { 0 } }, -{ "rfci", XL(19,51), 0xffffffff, PPC403 | BOOKE, { 0 } }, - -{ "rfsvc", XL(19,82), 0xffffffff, POWER, { 0 } }, - -{ "crandc", XL(19,129), XL_MASK, COM, { BT, BA, BB } }, - -{ "isync", XL(19,150), 0xffffffff, PPCCOM, { 0 } }, -{ "ics", XL(19,150), 0xffffffff, PWRCOM, { 0 } }, - -{ "crclr", XL(19,193), XL_MASK, PPCCOM, { BT, BAT, BBA } }, -{ "crxor", XL(19,193), XL_MASK, COM, { BT, BA, BB } }, - -{ "crnand", XL(19,225), XL_MASK, COM, { BT, BA, BB } }, - -{ "crand", XL(19,257), XL_MASK, COM, { BT, BA, BB } }, - -{ "hrfid", XL(19,274), 0xffffffff, POWER5 | CELL, { 0 } }, - -{ "crset", XL(19,289), XL_MASK, PPCCOM, { BT, BAT, BBA } }, -{ "creqv", XL(19,289), XL_MASK, COM, { BT, BA, BB } }, - -{ "doze", XL(19,402), 0xffffffff, POWER6, { 0 } }, - -{ "crorc", XL(19,417), XL_MASK, COM, { BT, BA, BB } }, - -{ "nap", XL(19,434), 0xffffffff, POWER6, { 0 } }, - -{ "crmove", XL(19,449), XL_MASK, PPCCOM, { BT, BA, BBA } }, -{ "cror", XL(19,449), XL_MASK, COM, { BT, BA, BB } }, - -{ "sleep", XL(19,466), 0xffffffff, POWER6, { 0 } }, -{ "rvwinkle", XL(19,498), 0xffffffff, POWER6, { 0 } }, - -{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, COM, { 0 } }, -{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, COM, { 0 } }, -{ "bltctr", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctr-", XLOCB(19,BOTM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctr+", XLOCB(19,BOTP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctrl-",XLOCB(19,BOTM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctrl+",XLOCB(19,BOTP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctr", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctr-", XLOCB(19,BOTM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctr+", XLOCB(19,BOTP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctrl-",XLOCB(19,BOTM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctrl+",XLOCB(19,BOTP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctr", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctr-", XLOCB(19,BOTM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctr+", XLOCB(19,BOTP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctrl-",XLOCB(19,BOTM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctrl+",XLOCB(19,BOTP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectr", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectr-", XLOCB(19,BOFM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectr+", XLOCB(19,BOFP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectrl-",XLOCB(19,BOFM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectrl+",XLOCB(19,BOFP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "btctr", XLO(19,BOT,528,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btctr-", XLO(19,BOT,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctr-", XLO(19,BOTM4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "btctr+", XLO(19,BOTP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctr+", XLO(19,BOTP4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "btctrl", XLO(19,BOT,528,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctrl-", XLO(19,BOTM4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctrl+", XLO(19,BOTP4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctr", XLO(19,BOF,528,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bfctr-", XLO(19,BOF,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctr-", XLO(19,BOFM4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctr+", XLO(19,BOFP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctr+", XLO(19,BOFP4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctrl", XLO(19,BOF,528,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctrl-", XLO(19,BOFM4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctrl+", XLO(19,BOFP4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bcctr-", XLYLK(19,528,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctr+", XLYLK(19,528,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctr", XLLK(19,528,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bcctrl", XLLK(19,528,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bcc", XLLK(19,528,0), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bccl", XLLK(19,528,1), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bcctre", XLLK(19,529,0), XLBB_MASK, BOOKE64, { BO, BI } }, -{ "bcctrel", XLLK(19,529,1), XLBB_MASK, BOOKE64, { BO, BI } }, - -{ "rlwimi", M(20,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlimi", M(20,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, - -{ "rlwimi.", M(20,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlimi.", M(20,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, - -{ "rotlwi", MME(21,31,0), MMBME_MASK, PPCCOM, { RA, RS, SH } }, -{ "clrlwi", MME(21,31,0), MSHME_MASK, PPCCOM, { RA, RS, MB } }, -{ "rlwinm", M(21,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlinm", M(21,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, -{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPCCOM, { RA,RS,SH } }, -{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPCCOM, { RA, RS, MB } }, -{ "rlwinm.", M(21,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlinm.", M(21,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, - -{ "rlmi", M(22,0), M_MASK, M601, { RA,RS,RB,MBE,ME } }, -{ "rlmi.", M(22,1), M_MASK, M601, { RA,RS,RB,MBE,ME } }, - -{ "be", B(22,0,0), B_MASK, BOOKE64, { LI } }, -{ "bel", B(22,0,1), B_MASK, BOOKE64, { LI } }, -{ "bea", B(22,1,0), B_MASK, BOOKE64, { LIA } }, -{ "bela", B(22,1,1), B_MASK, BOOKE64, { LIA } }, - -{ "rotlw", MME(23,31,0), MMBME_MASK, PPCCOM, { RA, RS, RB } }, -{ "rlwnm", M(23,0), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, -{ "rlnm", M(23,0), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, -{ "rotlw.", MME(23,31,1), MMBME_MASK, PPCCOM, { RA, RS, RB } }, -{ "rlwnm.", M(23,1), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, -{ "rlnm.", M(23,1), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, - -{ "nop", OP(24), 0xffffffff, PPCCOM, { 0 } }, -{ "ori", OP(24), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "oril", OP(24), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "oris", OP(25), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "oriu", OP(25), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "xori", OP(26), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "xoril", OP(26), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "xoris", OP(27), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "xoriu", OP(27), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "andi.", OP(28), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "andil.", OP(28), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "andis.", OP(29), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "andiu.", OP(29), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "rotldi", MD(30,0,0), MDMB_MASK, PPC64, { RA, RS, SH6 } }, -{ "clrldi", MD(30,0,0), MDSH_MASK, PPC64, { RA, RS, MB6 } }, -{ "rldicl", MD(30,0,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, -{ "rotldi.", MD(30,0,1), MDMB_MASK, PPC64, { RA, RS, SH6 } }, -{ "clrldi.", MD(30,0,1), MDSH_MASK, PPC64, { RA, RS, MB6 } }, -{ "rldicl.", MD(30,0,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, - -{ "rldicr", MD(30,1,0), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, -{ "rldicr.", MD(30,1,1), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, - -{ "rldic", MD(30,2,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, -{ "rldic.", MD(30,2,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, - -{ "rldimi", MD(30,3,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, -{ "rldimi.", MD(30,3,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, - -{ "rotld", MDS(30,8,0), MDSMB_MASK, PPC64, { RA, RS, RB } }, -{ "rldcl", MDS(30,8,0), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, -{ "rotld.", MDS(30,8,1), MDSMB_MASK, PPC64, { RA, RS, RB } }, -{ "rldcl.", MDS(30,8,1), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, - -{ "rldcr", MDS(30,9,0), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, -{ "rldcr.", MDS(30,9,1), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, - -{ "cmpw", XOPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, -{ "cmpd", XOPL(31,0,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, -{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } }, -{ "cmp", X(31,0), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, - -{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlgt", XTO(31,4,TOLGT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twllt", XTO(31,4,TOLLT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tllt", XTO(31,4,TOLLT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "tweq", XTO(31,4,TOEQ), XTO_MASK, PPCCOM, { RA, RB } }, -{ "teq", XTO(31,4,TOEQ), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlge", XTO(31,4,TOLGE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlge", XTO(31,4,TOLGE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlnl", XTO(31,4,TOLNL), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlnl", XTO(31,4,TOLNL), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlle", XTO(31,4,TOLLE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlle", XTO(31,4,TOLLE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlng", XTO(31,4,TOLNG), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlng", XTO(31,4,TOLNG), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twgt", XTO(31,4,TOGT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tgt", XTO(31,4,TOGT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twge", XTO(31,4,TOGE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tge", XTO(31,4,TOGE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twnl", XTO(31,4,TONL), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tnl", XTO(31,4,TONL), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlt", XTO(31,4,TOLT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlt", XTO(31,4,TOLT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twle", XTO(31,4,TOLE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tle", XTO(31,4,TOLE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twng", XTO(31,4,TONG), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tng", XTO(31,4,TONG), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twne", XTO(31,4,TONE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tne", XTO(31,4,TONE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "trap", XTO(31,4,TOU), 0xffffffff, PPCCOM, { 0 } }, -{ "tw", X(31,4), X_MASK, PPCCOM, { TO, RA, RB } }, -{ "t", X(31,4), X_MASK, PWRCOM, { TO, RA, RB } }, - -{ "subfc", XO(31,8,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sf", XO(31,8,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subc", XO(31,8,0,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sf.", XO(31,8,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RB, RA } }, -{ "subfco", XO(31,8,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfo", XO(31,8,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subco", XO(31,8,1,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfco.", XO(31,8,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfo.", XO(31,8,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RB, RA } }, - -{ "mulhdu", XO(31,9,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulhdu.", XO(31,9,0,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addc", XO(31,10,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "a", XO(31,10,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addc.", XO(31,10,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "a.", XO(31,10,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addco", XO(31,10,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ao", XO(31,10,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addco.", XO(31,10,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ao.", XO(31,10,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "mulhwu", XO(31,11,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "mulhwu.", XO(31,11,0,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "isellt", X(31,15), X_MASK, PPCISEL, { RT, RA, RB } }, -{ "iselgt", X(31,47), X_MASK, PPCISEL, { RT, RA, RB } }, -{ "iseleq", X(31,79), X_MASK, PPCISEL, { RT, RA, RB } }, -{ "isel", XISEL(31,15), XISEL_MASK, PPCISEL, { RT, RA, RB, CRB } }, - -{ "mfocrf", XFXM(31,19,0,1), XFXFXM_MASK, COM, { RT, FXM } }, -{ "mfcr", X(31,19), XRARB_MASK, NOPOWER4 | COM, { RT } }, -{ "mfcr", X(31,19), XFXFXM_MASK, POWER4, { RT, FXM4 } }, - -{ "lwarx", X(31,20), XEH_MASK, PPC, { RT, RA0, RB, EH } }, - -{ "ldx", X(31,21), X_MASK, PPC64, { RT, RA0, RB } }, - -{ "icbt", X(31,22), X_MASK, BOOKE|PPCE300, { CT, RA, RB } }, -{ "icbt", X(31,262), XRT_MASK, PPC403, { RA, RB } }, - -{ "lwzx", X(31,23), X_MASK, PPCCOM, { RT, RA0, RB } }, -{ "lx", X(31,23), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "slw", XRC(31,24,0), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sl", XRC(31,24,0), X_MASK, PWRCOM, { RA, RS, RB } }, -{ "slw.", XRC(31,24,1), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sl.", XRC(31,24,1), X_MASK, PWRCOM, { RA, RS, RB } }, - -{ "cntlzw", XRC(31,26,0), XRB_MASK, PPCCOM, { RA, RS } }, -{ "cntlz", XRC(31,26,0), XRB_MASK, PWRCOM, { RA, RS } }, -{ "cntlzw.", XRC(31,26,1), XRB_MASK, PPCCOM, { RA, RS } }, -{ "cntlz.", XRC(31,26,1), XRB_MASK, PWRCOM, { RA, RS } }, - -{ "sld", XRC(31,27,0), X_MASK, PPC64, { RA, RS, RB } }, -{ "sld.", XRC(31,27,1), X_MASK, PPC64, { RA, RS, RB } }, - -{ "and", XRC(31,28,0), X_MASK, COM, { RA, RS, RB } }, -{ "and.", XRC(31,28,1), X_MASK, COM, { RA, RS, RB } }, - -{ "maskg", XRC(31,29,0), X_MASK, M601, { RA, RS, RB } }, -{ "maskg.", XRC(31,29,1), X_MASK, M601, { RA, RS, RB } }, - -{ "icbte", X(31,30), X_MASK, BOOKE64, { CT, RA, RB } }, - -{ "lwzxe", X(31,31), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "cmplw", XOPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, -{ "cmpld", XOPL(31,32,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, -{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } }, -{ "cmpl", X(31,32), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, - -{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subf.", XO(31,40,0,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "sub.", XO(31,40,0,1), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfo", XO(31,40,1,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "subo", XO(31,40,1,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "subo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RB, RA } }, - -{ "ldux", X(31,53), X_MASK, PPC64, { RT, RAL, RB } }, - -{ "dcbst", X(31,54), XRT_MASK, PPC, { RA, RB } }, - -{ "lwzux", X(31,55), X_MASK, PPCCOM, { RT, RAL, RB } }, -{ "lux", X(31,55), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "dcbste", X(31,62), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lwzuxe", X(31,63), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "cntlzd", XRC(31,58,0), XRB_MASK, PPC64, { RA, RS } }, -{ "cntlzd.", XRC(31,58,1), XRB_MASK, PPC64, { RA, RS } }, - -{ "andc", XRC(31,60,0), X_MASK, COM, { RA, RS, RB } }, -{ "andc.", XRC(31,60,1), X_MASK, COM, { RA, RS, RB } }, - -{ "tdlgt", XTO(31,68,TOLGT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdllt", XTO(31,68,TOLLT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdeq", XTO(31,68,TOEQ), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlge", XTO(31,68,TOLGE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlnl", XTO(31,68,TOLNL), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlle", XTO(31,68,TOLLE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlng", XTO(31,68,TOLNG), XTO_MASK, PPC64, { RA, RB } }, -{ "tdgt", XTO(31,68,TOGT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdge", XTO(31,68,TOGE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdnl", XTO(31,68,TONL), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlt", XTO(31,68,TOLT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdle", XTO(31,68,TOLE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdng", XTO(31,68,TONG), XTO_MASK, PPC64, { RA, RB } }, -{ "tdne", XTO(31,68,TONE), XTO_MASK, PPC64, { RA, RB } }, -{ "td", X(31,68), X_MASK, PPC64, { TO, RA, RB } }, - -{ "mulhd", XO(31,73,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulhd.", XO(31,73,0,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "mulhw", XO(31,75,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "mulhw.", XO(31,75,0,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "dlmzb", XRC(31,78,0), X_MASK, PPC403|PPC440, { RA, RS, RB } }, -{ "dlmzb.", XRC(31,78,1), X_MASK, PPC403|PPC440, { RA, RS, RB } }, - -{ "mtsrd", X(31,82), XRB_MASK|(1<<20), PPC64, { SR, RS } }, - -{ "mfmsr", X(31,83), XRARB_MASK, COM, { RT } }, - -{ "ldarx", X(31,84), XEH_MASK, PPC64, { RT, RA0, RB, EH } }, - -{ "dcbfl", XOPL(31,86,1), XRT_MASK, POWER5, { RA, RB } }, -{ "dcbf", X(31,86), XLRT_MASK, PPC, { RA, RB, L } }, - -{ "lbzx", X(31,87), X_MASK, COM, { RT, RA0, RB } }, - -{ "dcbfe", X(31,94), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lbzxe", X(31,95), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "neg", XO(31,104,0,0), XORB_MASK, COM, { RT, RA } }, -{ "neg.", XO(31,104,0,1), XORB_MASK, COM, { RT, RA } }, -{ "nego", XO(31,104,1,0), XORB_MASK, COM, { RT, RA } }, -{ "nego.", XO(31,104,1,1), XORB_MASK, COM, { RT, RA } }, - -{ "mul", XO(31,107,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "mul.", XO(31,107,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "mulo", XO(31,107,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "mulo.", XO(31,107,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "mtsrdin", X(31,114), XRA_MASK, PPC64, { RS, RB } }, - -{ "clf", X(31,118), XTO_MASK, POWER, { RA, RB } }, - -{ "lbzux", X(31,119), X_MASK, COM, { RT, RAL, RB } }, - -{ "popcntb", X(31,122), XRB_MASK, POWER5, { RA, RS } }, -{ "popcntw", X(31,378), XRB_MASK, POWER7, { RA, RS } }, -{ "popcntd", X(31,506), XRB_MASK, POWER7, { RA, RS } }, - -{ "cnttzw", XRC(31,538,0), XRB_MASK, POWER9, { RA, RS } }, -{ "cnttzw.", XRC(31,538,1), XRB_MASK, POWER9, { RA, RS } }, -{ "cnttzd", XRC(31,570,0), XRB_MASK, POWER9, { RA, RS } }, -{ "cnttzd.", XRC(31,570,1), XRB_MASK, POWER9, { RA, RS } }, - -{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } }, -{ "nor", XRC(31,124,0), X_MASK, COM, { RA, RS, RB } }, -{ "not.", XRC(31,124,1), X_MASK, COM, { RA, RS, RBS } }, -{ "nor.", XRC(31,124,1), X_MASK, COM, { RA, RS, RB } }, - -{ "lwarxe", X(31,126), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "lbzuxe", X(31,127), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "wrtee", X(31,131), XRARB_MASK, PPC403 | BOOKE, { RS } }, - -{ "dcbtstls",X(31,134), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "subfe", XO(31,136,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfe", XO(31,136,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subfe.", XO(31,136,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfe.", XO(31,136,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subfeo", XO(31,136,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfeo", XO(31,136,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subfeo.", XO(31,136,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfeo.", XO(31,136,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "adde", XO(31,138,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ae", XO(31,138,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "adde.", XO(31,138,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ae.", XO(31,138,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addeo", XO(31,138,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "aeo", XO(31,138,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addeo.", XO(31,138,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "aeo.", XO(31,138,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "dcbtstlse",X(31,142),X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "mtocrf", XFXM(31,144,0,1), XFXFXM_MASK, COM, { FXM, RS } }, -{ "mtcr", XFXM(31,144,0xff,0), XRARB_MASK, COM, { RS }}, -{ "mtcrf", X(31,144), XFXFXM_MASK, COM, { FXM, RS } }, - -{ "mtmsr", X(31,146), XRARB_MASK, COM, { RS } }, - -{ "stdx", X(31,149), X_MASK, PPC64, { RS, RA0, RB } }, - -{ "stwcx.", XRC(31,150,1), X_MASK, PPC, { RS, RA0, RB } }, - -{ "stwx", X(31,151), X_MASK, PPCCOM, { RS, RA0, RB } }, -{ "stx", X(31,151), X_MASK, PWRCOM, { RS, RA, RB } }, - -{ "stwcxe.", XRC(31,158,1), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "stwxe", X(31,159), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "slq", XRC(31,152,0), X_MASK, M601, { RA, RS, RB } }, -{ "slq.", XRC(31,152,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sle", XRC(31,153,0), X_MASK, M601, { RA, RS, RB } }, -{ "sle.", XRC(31,153,1), X_MASK, M601, { RA, RS, RB } }, - -{ "prtyw", X(31,154), XRB_MASK, POWER6, { RA, RS } }, - -{ "wrteei", X(31,163), XE_MASK, PPC403 | BOOKE, { E } }, - -{ "dcbtls", X(31,166), X_MASK, PPCCHLK, { CT, RA, RB }}, -{ "dcbtlse", X(31,174), X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "mtmsrd", X(31,178), XRLARB_MASK, PPC64, { RS, A_L } }, - -{ "stdux", X(31,181), X_MASK, PPC64, { RS, RAS, RB } }, - -{ "stwux", X(31,183), X_MASK, PPCCOM, { RS, RAS, RB } }, -{ "stux", X(31,183), X_MASK, PWRCOM, { RS, RA0, RB } }, - -{ "sliq", XRC(31,184,0), X_MASK, M601, { RA, RS, SH } }, -{ "sliq.", XRC(31,184,1), X_MASK, M601, { RA, RS, SH } }, - -{ "prtyd", X(31,186), XRB_MASK, POWER6, { RA, RS } }, - -{ "stwuxe", X(31,191), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "subfze", XO(31,200,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfze", XO(31,200,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfze.", XO(31,200,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfzeo", XO(31,200,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfzeo.", XO(31,200,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "addze", XO(31,202,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "aze", XO(31,202,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addze.", XO(31,202,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "aze.", XO(31,202,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addzeo", XO(31,202,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "azeo", XO(31,202,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "azeo.", XO(31,202,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "mtsr", X(31,210), XRB_MASK|(1<<20), COM32, { SR, RS } }, - -{ "stdcx.", XRC(31,214,1), X_MASK, PPC64, { RS, RA0, RB } }, - -{ "stbx", X(31,215), X_MASK, COM, { RS, RA0, RB } }, - -{ "sllq", XRC(31,216,0), X_MASK, M601, { RA, RS, RB } }, -{ "sllq.", XRC(31,216,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sleq", XRC(31,217,0), X_MASK, M601, { RA, RS, RB } }, -{ "sleq.", XRC(31,217,1), X_MASK, M601, { RA, RS, RB } }, - -{ "stbxe", X(31,223), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "icblc", X(31,230), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "subfme", XO(31,232,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfme", XO(31,232,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfme.", XO(31,232,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfmeo", XO(31,232,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfmeo.", XO(31,232,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "mulld", XO(31,233,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulld.", XO(31,233,0,1), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulldo", XO(31,233,1,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulldo.", XO(31,233,1,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addme", XO(31,234,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ame", XO(31,234,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addme.", XO(31,234,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ame.", XO(31,234,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addmeo", XO(31,234,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ameo", XO(31,234,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ameo.", XO(31,234,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "addex", XO(31,170,0,0), XO_MASK, POWER9, { RT, RA, RB } }, - -{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "muls", XO(31,235,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "mullw.", XO(31,235,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "muls.", XO(31,235,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "mullwo", XO(31,235,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "mulso", XO(31,235,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "mullwo.", XO(31,235,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "mulso.", XO(31,235,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "icblce", X(31,238), X_MASK, PPCCHLK64, { CT, RA, RB }}, -{ "mtsrin", X(31,242), XRA_MASK, PPC32, { RS, RB } }, -{ "mtsri", X(31,242), XRA_MASK, POWER32, { RS, RB } }, - -{ "dcbtst", X(31,246), X_MASK, PPC, { CT, RA, RB } }, - -{ "stbux", X(31,247), X_MASK, COM, { RS, RAS, RB } }, - -{ "slliq", XRC(31,248,0), X_MASK, M601, { RA, RS, SH } }, -{ "slliq.", XRC(31,248,1), X_MASK, M601, { RA, RS, SH } }, - -{ "dcbtste", X(31,253), X_MASK, BOOKE64, { CT, RA, RB } }, - -{ "stbuxe", X(31,255), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "mfdcrx", X(31,259), X_MASK, BOOKE, { RS, RA } }, - -{ "doz", XO(31,264,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "doz.", XO(31,264,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "dozo", XO(31,264,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "dozo.", XO(31,264,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "add", XO(31,266,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "cax", XO(31,266,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "add.", XO(31,266,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "cax.", XO(31,266,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addo", XO(31,266,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "caxo", XO(31,266,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addo.", XO(31,266,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "caxo.", XO(31,266,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "tlbiel", X(31,274), XRTLRA_MASK, POWER4, { RB, L } }, - -{ "mfapidi", X(31,275), X_MASK, BOOKE, { RT, RA } }, - -{ "lscbx", XRC(31,277,0), X_MASK, M601, { RT, RA, RB } }, -{ "lscbx.", XRC(31,277,1), X_MASK, M601, { RT, RA, RB } }, - -{ "dcbt", X(31,278), X_MASK, PPC, { CT, RA, RB } }, - -{ "lhzx", X(31,279), X_MASK, COM, { RT, RA0, RB } }, - -{ "eqv", XRC(31,284,0), X_MASK, COM, { RA, RS, RB } }, -{ "eqv.", XRC(31,284,1), X_MASK, COM, { RA, RS, RB } }, - -{ "dcbte", X(31,286), X_MASK, BOOKE64, { CT, RA, RB } }, - -{ "lhzxe", X(31,287), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "tlbie", X(31,306), XRTLRA_MASK, PPC, { RB, L } }, -{ "tlbi", X(31,306), XRT_MASK, POWER, { RA0, RB } }, - -{ "eciwx", X(31,310), X_MASK, PPC, { RT, RA, RB } }, - -{ "lhzux", X(31,311), X_MASK, COM, { RT, RAL, RB } }, - -{ "xor", XRC(31,316,0), X_MASK, COM, { RA, RS, RB } }, -{ "xor.", XRC(31,316,1), X_MASK, COM, { RA, RS, RB } }, - -{ "lhzuxe", X(31,319), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "mfexisr", XSPR(31,323,64), XSPR_MASK, PPC403, { RT } }, -{ "mfexier", XSPR(31,323,66), XSPR_MASK, PPC403, { RT } }, -{ "mfbr0", XSPR(31,323,128), XSPR_MASK, PPC403, { RT } }, -{ "mfbr1", XSPR(31,323,129), XSPR_MASK, PPC403, { RT } }, -{ "mfbr2", XSPR(31,323,130), XSPR_MASK, PPC403, { RT } }, -{ "mfbr3", XSPR(31,323,131), XSPR_MASK, PPC403, { RT } }, -{ "mfbr4", XSPR(31,323,132), XSPR_MASK, PPC403, { RT } }, -{ "mfbr5", XSPR(31,323,133), XSPR_MASK, PPC403, { RT } }, -{ "mfbr6", XSPR(31,323,134), XSPR_MASK, PPC403, { RT } }, -{ "mfbr7", XSPR(31,323,135), XSPR_MASK, PPC403, { RT } }, -{ "mfbear", XSPR(31,323,144), XSPR_MASK, PPC403, { RT } }, -{ "mfbesr", XSPR(31,323,145), XSPR_MASK, PPC403, { RT } }, -{ "mfiocr", XSPR(31,323,160), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasr", XSPR(31,323,224), XSPR_MASK, PPC403, { RT } }, -{ "mfdcr", X(31,323), X_MASK, PPC403 | BOOKE, { RT, SPR } }, - -{ "div", XO(31,331,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "div.", XO(31,331,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "divo", XO(31,331,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "divo.", XO(31,331,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "mfpmr", X(31,334), X_MASK, PPCPMR, { RT, PMR }}, - -{ "mfmq", XSPR(31,339,0), XSPR_MASK, M601, { RT } }, -{ "mfxer", XSPR(31,339,1), XSPR_MASK, COM, { RT } }, -{ "mfrtcu", XSPR(31,339,4), XSPR_MASK, COM, { RT } }, -{ "mfrtcl", XSPR(31,339,5), XSPR_MASK, COM, { RT } }, -{ "mfdec", XSPR(31,339,6), XSPR_MASK, MFDEC1, { RT } }, -{ "mfdec", XSPR(31,339,22), XSPR_MASK, MFDEC2, { RT } }, -{ "mflr", XSPR(31,339,8), XSPR_MASK, COM, { RT } }, -{ "mfctr", XSPR(31,339,9), XSPR_MASK, COM, { RT } }, -{ "mftid", XSPR(31,339,17), XSPR_MASK, POWER, { RT } }, -{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, COM, { RT } }, -{ "mfdar", XSPR(31,339,19), XSPR_MASK, COM, { RT } }, -{ "mfsdr0", XSPR(31,339,24), XSPR_MASK, POWER, { RT } }, -{ "mfsdr1", XSPR(31,339,25), XSPR_MASK, COM, { RT } }, -{ "mfsrr0", XSPR(31,339,26), XSPR_MASK, COM, { RT } }, -{ "mfsrr1", XSPR(31,339,27), XSPR_MASK, COM, { RT } }, -{ "mfcfar", XSPR(31,339,28), XSPR_MASK, POWER6, { RT } }, -{ "mfpid", XSPR(31,339,48), XSPR_MASK, BOOKE, { RT } }, -{ "mfpid", XSPR(31,339,945), XSPR_MASK, PPC403, { RT } }, -{ "mfcsrr0", XSPR(31,339,58), XSPR_MASK, BOOKE, { RT } }, -{ "mfcsrr1", XSPR(31,339,59), XSPR_MASK, BOOKE, { RT } }, -{ "mfdear", XSPR(31,339,61), XSPR_MASK, BOOKE, { RT } }, -{ "mfdear", XSPR(31,339,981), XSPR_MASK, PPC403, { RT } }, -{ "mfesr", XSPR(31,339,62), XSPR_MASK, BOOKE, { RT } }, -{ "mfesr", XSPR(31,339,980), XSPR_MASK, PPC403, { RT } }, -{ "mfivpr", XSPR(31,339,63), XSPR_MASK, BOOKE, { RT } }, -{ "mfcmpa", XSPR(31,339,144), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpb", XSPR(31,339,145), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpc", XSPR(31,339,146), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpd", XSPR(31,339,147), XSPR_MASK, PPC860, { RT } }, -{ "mficr", XSPR(31,339,148), XSPR_MASK, PPC860, { RT } }, -{ "mfder", XSPR(31,339,149), XSPR_MASK, PPC860, { RT } }, -{ "mfcounta", XSPR(31,339,150), XSPR_MASK, PPC860, { RT } }, -{ "mfcountb", XSPR(31,339,151), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpe", XSPR(31,339,152), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpf", XSPR(31,339,153), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpg", XSPR(31,339,154), XSPR_MASK, PPC860, { RT } }, -{ "mfcmph", XSPR(31,339,155), XSPR_MASK, PPC860, { RT } }, -{ "mflctrl1", XSPR(31,339,156), XSPR_MASK, PPC860, { RT } }, -{ "mflctrl2", XSPR(31,339,157), XSPR_MASK, PPC860, { RT } }, -{ "mfictrl", XSPR(31,339,158), XSPR_MASK, PPC860, { RT } }, -{ "mfbar", XSPR(31,339,159), XSPR_MASK, PPC860, { RT } }, -{ "mfvrsave", XSPR(31,339,256), XSPR_MASK, PPCVEC, { RT } }, -{ "mfusprg0", XSPR(31,339,256), XSPR_MASK, BOOKE, { RT } }, -{ "mftb", X(31,371), X_MASK, CLASSIC, { RT, TBR } }, -{ "mftb", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, -{ "mftbl", XSPR(31,371,268), XSPR_MASK, CLASSIC, { RT } }, -{ "mftbl", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, -{ "mftbu", XSPR(31,371,269), XSPR_MASK, CLASSIC, { RT } }, -{ "mftbu", XSPR(31,339,269), XSPR_MASK, BOOKE, { RT } }, -{ "mfsprg", XSPR(31,339,256), XSPRG_MASK, PPC, { RT, SPRG } }, -{ "mfsprg0", XSPR(31,339,272), XSPR_MASK, PPC, { RT } }, -{ "mfsprg1", XSPR(31,339,273), XSPR_MASK, PPC, { RT } }, -{ "mfsprg2", XSPR(31,339,274), XSPR_MASK, PPC, { RT } }, -{ "mfsprg3", XSPR(31,339,275), XSPR_MASK, PPC, { RT } }, -{ "mfsprg4", XSPR(31,339,260), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfsprg5", XSPR(31,339,261), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfsprg6", XSPR(31,339,262), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfsprg7", XSPR(31,339,263), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfasr", XSPR(31,339,280), XSPR_MASK, PPC64, { RT } }, -{ "mfear", XSPR(31,339,282), XSPR_MASK, PPC, { RT } }, -{ "mfpir", XSPR(31,339,286), XSPR_MASK, BOOKE, { RT } }, -{ "mfpvr", XSPR(31,339,287), XSPR_MASK, PPC, { RT } }, -{ "mfdbsr", XSPR(31,339,304), XSPR_MASK, BOOKE, { RT } }, -{ "mfdbsr", XSPR(31,339,1008), XSPR_MASK, PPC403, { RT } }, -{ "mfdbcr0", XSPR(31,339,308), XSPR_MASK, BOOKE, { RT } }, -{ "mfdbcr0", XSPR(31,339,1010), XSPR_MASK, PPC405, { RT } }, -{ "mfdbcr1", XSPR(31,339,309), XSPR_MASK, BOOKE, { RT } }, -{ "mfdbcr1", XSPR(31,339,957), XSPR_MASK, PPC405, { RT } }, -{ "mfdbcr2", XSPR(31,339,310), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac1", XSPR(31,339,312), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac1", XSPR(31,339,1012), XSPR_MASK, PPC403, { RT } }, -{ "mfiac2", XSPR(31,339,313), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac2", XSPR(31,339,1013), XSPR_MASK, PPC403, { RT } }, -{ "mfiac3", XSPR(31,339,314), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac3", XSPR(31,339,948), XSPR_MASK, PPC405, { RT } }, -{ "mfiac4", XSPR(31,339,315), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac4", XSPR(31,339,949), XSPR_MASK, PPC405, { RT } }, -{ "mfdac1", XSPR(31,339,316), XSPR_MASK, BOOKE, { RT } }, -{ "mfdac1", XSPR(31,339,1014), XSPR_MASK, PPC403, { RT } }, -{ "mfdac2", XSPR(31,339,317), XSPR_MASK, BOOKE, { RT } }, -{ "mfdac2", XSPR(31,339,1015), XSPR_MASK, PPC403, { RT } }, -{ "mfdvc1", XSPR(31,339,318), XSPR_MASK, BOOKE, { RT } }, -{ "mfdvc1", XSPR(31,339,950), XSPR_MASK, PPC405, { RT } }, -{ "mfdvc2", XSPR(31,339,319), XSPR_MASK, BOOKE, { RT } }, -{ "mfdvc2", XSPR(31,339,951), XSPR_MASK, PPC405, { RT } }, -{ "mftsr", XSPR(31,339,336), XSPR_MASK, BOOKE, { RT } }, -{ "mftsr", XSPR(31,339,984), XSPR_MASK, PPC403, { RT } }, -{ "mftcr", XSPR(31,339,340), XSPR_MASK, BOOKE, { RT } }, -{ "mftcr", XSPR(31,339,986), XSPR_MASK, PPC403, { RT } }, -{ "mfivor0", XSPR(31,339,400), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor1", XSPR(31,339,401), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor2", XSPR(31,339,402), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor3", XSPR(31,339,403), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor4", XSPR(31,339,404), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor5", XSPR(31,339,405), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor6", XSPR(31,339,406), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor7", XSPR(31,339,407), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor8", XSPR(31,339,408), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor9", XSPR(31,339,409), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor10", XSPR(31,339,410), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor11", XSPR(31,339,411), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor12", XSPR(31,339,412), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor13", XSPR(31,339,413), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor14", XSPR(31,339,414), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor15", XSPR(31,339,415), XSPR_MASK, BOOKE, { RT } }, -{ "mfspefscr", XSPR(31,339,512), XSPR_MASK, PPCSPE, { RT } }, -{ "mfbbear", XSPR(31,339,513), XSPR_MASK, PPCBRLK, { RT } }, -{ "mfbbtar", XSPR(31,339,514), XSPR_MASK, PPCBRLK, { RT } }, -{ "mfivor32", XSPR(31,339,528), XSPR_MASK, PPCSPE, { RT } }, -{ "mfivor33", XSPR(31,339,529), XSPR_MASK, PPCSPE, { RT } }, -{ "mfivor34", XSPR(31,339,530), XSPR_MASK, PPCSPE, { RT } }, -{ "mfivor35", XSPR(31,339,531), XSPR_MASK, PPCPMR, { RT } }, -{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfic_cst", XSPR(31,339,560), XSPR_MASK, PPC860, { RT } }, -{ "mfic_adr", XSPR(31,339,561), XSPR_MASK, PPC860, { RT } }, -{ "mfic_dat", XSPR(31,339,562), XSPR_MASK, PPC860, { RT } }, -{ "mfdc_cst", XSPR(31,339,568), XSPR_MASK, PPC860, { RT } }, -{ "mfdc_adr", XSPR(31,339,569), XSPR_MASK, PPC860, { RT } }, -{ "mfmcsrr0", XSPR(31,339,570), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfdc_dat", XSPR(31,339,570), XSPR_MASK, PPC860, { RT } }, -{ "mfmcsrr1", XSPR(31,339,571), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfmcsr", XSPR(31,339,572), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfmcar", XSPR(31,339,573), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfdpdr", XSPR(31,339,630), XSPR_MASK, PPC860, { RT } }, -{ "mfdpir", XSPR(31,339,631), XSPR_MASK, PPC860, { RT } }, -{ "mfimmr", XSPR(31,339,638), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_ctr", XSPR(31,339,784), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_ap", XSPR(31,339,786), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_epn", XSPR(31,339,787), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_twc", XSPR(31,339,789), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_rpn", XSPR(31,339,790), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_ctr", XSPR(31,339,792), XSPR_MASK, PPC860, { RT } }, -{ "mfm_casid", XSPR(31,339,793), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_ap", XSPR(31,339,794), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_epn", XSPR(31,339,795), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_twb", XSPR(31,339,796), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_twc", XSPR(31,339,797), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_rpn", XSPR(31,339,798), XSPR_MASK, PPC860, { RT } }, -{ "mfm_tw", XSPR(31,339,799), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_dbcam", XSPR(31,339,816), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_dbram0",XSPR(31,339,817), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_dbram1",XSPR(31,339,818), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_dbcam", XSPR(31,339,824), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_dbram0",XSPR(31,339,825), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_dbram1",XSPR(31,339,826), XSPR_MASK, PPC860, { RT } }, -{ "mfummcr0", XSPR(31,339,936), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc1", XSPR(31,339,937), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc2", XSPR(31,339,938), XSPR_MASK, PPC750, { RT } }, -{ "mfusia", XSPR(31,339,939), XSPR_MASK, PPC750, { RT } }, -{ "mfummcr1", XSPR(31,339,940), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc3", XSPR(31,339,941), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc4", XSPR(31,339,942), XSPR_MASK, PPC750, { RT } }, -{ "mfzpr", XSPR(31,339,944), XSPR_MASK, PPC403, { RT } }, -{ "mfccr0", XSPR(31,339,947), XSPR_MASK, PPC405, { RT } }, -{ "mfmmcr0", XSPR(31,339,952), XSPR_MASK, PPC750, { RT } }, -{ "mfpmc1", XSPR(31,339,953), XSPR_MASK, PPC750, { RT } }, -{ "mfsgr", XSPR(31,339,953), XSPR_MASK, PPC403, { RT } }, -{ "mfpmc2", XSPR(31,339,954), XSPR_MASK, PPC750, { RT } }, -{ "mfdcwr", XSPR(31,339,954), XSPR_MASK, PPC403, { RT } }, -{ "mfsia", XSPR(31,339,955), XSPR_MASK, PPC750, { RT } }, -{ "mfsler", XSPR(31,339,955), XSPR_MASK, PPC405, { RT } }, -{ "mfmmcr1", XSPR(31,339,956), XSPR_MASK, PPC750, { RT } }, -{ "mfsu0r", XSPR(31,339,956), XSPR_MASK, PPC405, { RT } }, -{ "mfpmc3", XSPR(31,339,957), XSPR_MASK, PPC750, { RT } }, -{ "mfpmc4", XSPR(31,339,958), XSPR_MASK, PPC750, { RT } }, -{ "mficdbdr", XSPR(31,339,979), XSPR_MASK, PPC403, { RT } }, -{ "mfevpr", XSPR(31,339,982), XSPR_MASK, PPC403, { RT } }, -{ "mfcdbcr", XSPR(31,339,983), XSPR_MASK, PPC403, { RT } }, -{ "mfpit", XSPR(31,339,987), XSPR_MASK, PPC403, { RT } }, -{ "mftbhi", XSPR(31,339,988), XSPR_MASK, PPC403, { RT } }, -{ "mftblo", XSPR(31,339,989), XSPR_MASK, PPC403, { RT } }, -{ "mfsrr2", XSPR(31,339,990), XSPR_MASK, PPC403, { RT } }, -{ "mfsrr3", XSPR(31,339,991), XSPR_MASK, PPC403, { RT } }, -{ "mfl2cr", XSPR(31,339,1017), XSPR_MASK, PPC750, { RT } }, -{ "mfdccr", XSPR(31,339,1018), XSPR_MASK, PPC403, { RT } }, -{ "mficcr", XSPR(31,339,1019), XSPR_MASK, PPC403, { RT } }, -{ "mfictc", XSPR(31,339,1019), XSPR_MASK, PPC750, { RT } }, -{ "mfpbl1", XSPR(31,339,1020), XSPR_MASK, PPC403, { RT } }, -{ "mfthrm1", XSPR(31,339,1020), XSPR_MASK, PPC750, { RT } }, -{ "mfpbu1", XSPR(31,339,1021), XSPR_MASK, PPC403, { RT } }, -{ "mfthrm2", XSPR(31,339,1021), XSPR_MASK, PPC750, { RT } }, -{ "mfpbl2", XSPR(31,339,1022), XSPR_MASK, PPC403, { RT } }, -{ "mfthrm3", XSPR(31,339,1022), XSPR_MASK, PPC750, { RT } }, -{ "mfpbu2", XSPR(31,339,1023), XSPR_MASK, PPC403, { RT } }, -{ "mfspr", X(31,339), X_MASK, COM, { RT, SPR } }, - -{ "lwax", X(31,341), X_MASK, PPC64, { RT, RA0, RB } }, - -{ "dst", XDSS(31,342,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, -{ "dstt", XDSS(31,342,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, - -{ "lhax", X(31,343), X_MASK, COM, { RT, RA0, RB } }, - -{ "lhaxe", X(31,351), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "dstst", XDSS(31,374,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, -{ "dststt", XDSS(31,374,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, - -{ "dccci", X(31,454), XRT_MASK, PPC403|PPC440, { RA, RB } }, - -{ "abs", XO(31,360,0,0), XORB_MASK, M601, { RT, RA } }, -{ "abs.", XO(31,360,0,1), XORB_MASK, M601, { RT, RA } }, -{ "abso", XO(31,360,1,0), XORB_MASK, M601, { RT, RA } }, -{ "abso.", XO(31,360,1,1), XORB_MASK, M601, { RT, RA } }, - -{ "divs", XO(31,363,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "divs.", XO(31,363,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "divso", XO(31,363,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "divso.", XO(31,363,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "tlbia", X(31,370), 0xffffffff, PPC, { 0 } }, - -{ "lwaux", X(31,373), X_MASK, PPC64, { RT, RAL, RB } }, - -{ "lhaux", X(31,375), X_MASK, COM, { RT, RAL, RB } }, - -{ "lhauxe", X(31,383), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "mtdcrx", X(31,387), X_MASK, BOOKE, { RA, RS } }, - -{ "dcblc", X(31,390), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "subfe64", XO(31,392,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, -{ "subfe64o",XO(31,392,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, - -{ "adde64", XO(31,394,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, -{ "adde64o", XO(31,394,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, - -{ "dcblce", X(31,398), X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "slbmte", X(31,402), XRA_MASK, PPC64, { RS, RB } }, - -{ "sthx", X(31,407), X_MASK, COM, { RS, RA0, RB } }, - -{ "cmpb", X(31,508), X_MASK, POWER6, { RA, RS, RB } }, - -{ "lfqx", X(31,791), X_MASK, POWER2, { FRT, RA, RB } }, - -{ "lfdpx", X(31,791), X_MASK, POWER6, { FRT, RA, RB } }, - -{ "lfqux", X(31,823), X_MASK, POWER2, { FRT, RA, RB } }, - -{ "stfqx", X(31,919), X_MASK, POWER2, { FRS, RA, RB } }, - -{ "stfdpx", X(31,919), X_MASK, POWER6, { FRS, RA, RB } }, - -{ "stfqux", X(31,951), X_MASK, POWER2, { FRS, RA, RB } }, - -{ "orc", XRC(31,412,0), X_MASK, COM, { RA, RS, RB } }, -{ "orc.", XRC(31,412,1), X_MASK, COM, { RA, RS, RB } }, - -{ "sradi", XS(31,413,0), XS_MASK, PPC64, { RA, RS, SH6 } }, -{ "sradi.", XS(31,413,1), XS_MASK, PPC64, { RA, RS, SH6 } }, - -{ "sthxe", X(31,415), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "slbie", X(31,434), XRTRA_MASK, PPC64, { RB } }, - -{ "ecowx", X(31,438), X_MASK, PPC, { RT, RA, RB } }, - -{ "sthux", X(31,439), X_MASK, COM, { RS, RAS, RB } }, - -{ "sthuxe", X(31,447), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "cctpl", 0x7c210b78, 0xffffffff, CELL, { 0 }}, -{ "cctpm", 0x7c421378, 0xffffffff, CELL, { 0 }}, -{ "cctph", 0x7c631b78, 0xffffffff, CELL, { 0 }}, -{ "db8cyc", 0x7f9ce378, 0xffffffff, CELL, { 0 }}, -{ "db10cyc", 0x7fbdeb78, 0xffffffff, CELL, { 0 }}, -{ "db12cyc", 0x7fdef378, 0xffffffff, CELL, { 0 }}, -{ "db16cyc", 0x7ffffb78, 0xffffffff, CELL, { 0 }}, -{ "mr", XRC(31,444,0), X_MASK, COM, { RA, RS, RBS } }, -{ "or", XRC(31,444,0), X_MASK, COM, { RA, RS, RB } }, -{ "mr.", XRC(31,444,1), X_MASK, COM, { RA, RS, RBS } }, -{ "or.", XRC(31,444,1), X_MASK, COM, { RA, RS, RB } }, - -{ "mtexisr", XSPR(31,451,64), XSPR_MASK, PPC403, { RS } }, -{ "mtexier", XSPR(31,451,66), XSPR_MASK, PPC403, { RS } }, -{ "mtbr0", XSPR(31,451,128), XSPR_MASK, PPC403, { RS } }, -{ "mtbr1", XSPR(31,451,129), XSPR_MASK, PPC403, { RS } }, -{ "mtbr2", XSPR(31,451,130), XSPR_MASK, PPC403, { RS } }, -{ "mtbr3", XSPR(31,451,131), XSPR_MASK, PPC403, { RS } }, -{ "mtbr4", XSPR(31,451,132), XSPR_MASK, PPC403, { RS } }, -{ "mtbr5", XSPR(31,451,133), XSPR_MASK, PPC403, { RS } }, -{ "mtbr6", XSPR(31,451,134), XSPR_MASK, PPC403, { RS } }, -{ "mtbr7", XSPR(31,451,135), XSPR_MASK, PPC403, { RS } }, -{ "mtbear", XSPR(31,451,144), XSPR_MASK, PPC403, { RS } }, -{ "mtbesr", XSPR(31,451,145), XSPR_MASK, PPC403, { RS } }, -{ "mtiocr", XSPR(31,451,160), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasr", XSPR(31,451,224), XSPR_MASK, PPC403, { RS } }, -{ "mtdcr", X(31,451), X_MASK, PPC403 | BOOKE, { SPR, RS } }, - -{ "subfze64",XO(31,456,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "subfze64o",XO(31,456,1,0), XORB_MASK, BOOKE64, { RT, RA } }, - -{ "divdu", XO(31,457,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divdu.", XO(31,457,0,1), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divduo", XO(31,457,1,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divduo.", XO(31,457,1,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addze64", XO(31,458,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "addze64o",XO(31,458,1,0), XORB_MASK, BOOKE64, { RT, RA } }, - -{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwu.", XO(31,459,0,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwuo", XO(31,459,1,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwuo.", XO(31,459,1,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "mtmq", XSPR(31,467,0), XSPR_MASK, M601, { RS } }, -{ "mtxer", XSPR(31,467,1), XSPR_MASK, COM, { RS } }, -{ "mtlr", XSPR(31,467,8), XSPR_MASK, COM, { RS } }, -{ "mtctr", XSPR(31,467,9), XSPR_MASK, COM, { RS } }, -{ "mttid", XSPR(31,467,17), XSPR_MASK, POWER, { RS } }, -{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, COM, { RS } }, -{ "mtdar", XSPR(31,467,19), XSPR_MASK, COM, { RS } }, -{ "mtrtcu", XSPR(31,467,20), XSPR_MASK, COM, { RS } }, -{ "mtrtcl", XSPR(31,467,21), XSPR_MASK, COM, { RS } }, -{ "mtdec", XSPR(31,467,22), XSPR_MASK, COM, { RS } }, -{ "mtsdr0", XSPR(31,467,24), XSPR_MASK, POWER, { RS } }, -{ "mtsdr1", XSPR(31,467,25), XSPR_MASK, COM, { RS } }, -{ "mtsrr0", XSPR(31,467,26), XSPR_MASK, COM, { RS } }, -{ "mtsrr1", XSPR(31,467,27), XSPR_MASK, COM, { RS } }, -{ "mtcfar", XSPR(31,467,28), XSPR_MASK, POWER6, { RS } }, -{ "mtpid", XSPR(31,467,48), XSPR_MASK, BOOKE, { RS } }, -{ "mtpid", XSPR(31,467,945), XSPR_MASK, PPC403, { RS } }, -{ "mtdecar", XSPR(31,467,54), XSPR_MASK, BOOKE, { RS } }, -{ "mtcsrr0", XSPR(31,467,58), XSPR_MASK, BOOKE, { RS } }, -{ "mtcsrr1", XSPR(31,467,59), XSPR_MASK, BOOKE, { RS } }, -{ "mtdear", XSPR(31,467,61), XSPR_MASK, BOOKE, { RS } }, -{ "mtdear", XSPR(31,467,981), XSPR_MASK, PPC403, { RS } }, -{ "mtesr", XSPR(31,467,62), XSPR_MASK, BOOKE, { RS } }, -{ "mtesr", XSPR(31,467,980), XSPR_MASK, PPC403, { RS } }, -{ "mtivpr", XSPR(31,467,63), XSPR_MASK, BOOKE, { RS } }, -{ "mtcmpa", XSPR(31,467,144), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpb", XSPR(31,467,145), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpc", XSPR(31,467,146), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpd", XSPR(31,467,147), XSPR_MASK, PPC860, { RS } }, -{ "mticr", XSPR(31,467,148), XSPR_MASK, PPC860, { RS } }, -{ "mtder", XSPR(31,467,149), XSPR_MASK, PPC860, { RS } }, -{ "mtcounta", XSPR(31,467,150), XSPR_MASK, PPC860, { RS } }, -{ "mtcountb", XSPR(31,467,151), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpe", XSPR(31,467,152), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpf", XSPR(31,467,153), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpg", XSPR(31,467,154), XSPR_MASK, PPC860, { RS } }, -{ "mtcmph", XSPR(31,467,155), XSPR_MASK, PPC860, { RS } }, -{ "mtlctrl1", XSPR(31,467,156), XSPR_MASK, PPC860, { RS } }, -{ "mtlctrl2", XSPR(31,467,157), XSPR_MASK, PPC860, { RS } }, -{ "mtictrl", XSPR(31,467,158), XSPR_MASK, PPC860, { RS } }, -{ "mtbar", XSPR(31,467,159), XSPR_MASK, PPC860, { RS } }, -{ "mtvrsave", XSPR(31,467,256), XSPR_MASK, PPCVEC, { RS } }, -{ "mtusprg0", XSPR(31,467,256), XSPR_MASK, BOOKE, { RS } }, -{ "mtsprg", XSPR(31,467,256), XSPRG_MASK,PPC, { SPRG, RS } }, -{ "mtsprg0", XSPR(31,467,272), XSPR_MASK, PPC, { RS } }, -{ "mtsprg1", XSPR(31,467,273), XSPR_MASK, PPC, { RS } }, -{ "mtsprg2", XSPR(31,467,274), XSPR_MASK, PPC, { RS } }, -{ "mtsprg3", XSPR(31,467,275), XSPR_MASK, PPC, { RS } }, -{ "mtsprg4", XSPR(31,467,276), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtsprg5", XSPR(31,467,277), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtsprg6", XSPR(31,467,278), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtsprg7", XSPR(31,467,279), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtasr", XSPR(31,467,280), XSPR_MASK, PPC64, { RS } }, -{ "mtear", XSPR(31,467,282), XSPR_MASK, PPC, { RS } }, -{ "mttbl", XSPR(31,467,284), XSPR_MASK, PPC, { RS } }, -{ "mttbu", XSPR(31,467,285), XSPR_MASK, PPC, { RS } }, -{ "mtdbsr", XSPR(31,467,304), XSPR_MASK, BOOKE, { RS } }, -{ "mtdbsr", XSPR(31,467,1008), XSPR_MASK, PPC403, { RS } }, -{ "mtdbcr0", XSPR(31,467,308), XSPR_MASK, BOOKE, { RS } }, -{ "mtdbcr0", XSPR(31,467,1010), XSPR_MASK, PPC405, { RS } }, -{ "mtdbcr1", XSPR(31,467,309), XSPR_MASK, BOOKE, { RS } }, -{ "mtdbcr1", XSPR(31,467,957), XSPR_MASK, PPC405, { RS } }, -{ "mtdbcr2", XSPR(31,467,310), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac1", XSPR(31,467,312), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac1", XSPR(31,467,1012), XSPR_MASK, PPC403, { RS } }, -{ "mtiac2", XSPR(31,467,313), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac2", XSPR(31,467,1013), XSPR_MASK, PPC403, { RS } }, -{ "mtiac3", XSPR(31,467,314), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac3", XSPR(31,467,948), XSPR_MASK, PPC405, { RS } }, -{ "mtiac4", XSPR(31,467,315), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac4", XSPR(31,467,949), XSPR_MASK, PPC405, { RS } }, -{ "mtdac1", XSPR(31,467,316), XSPR_MASK, BOOKE, { RS } }, -{ "mtdac1", XSPR(31,467,1014), XSPR_MASK, PPC403, { RS } }, -{ "mtdac2", XSPR(31,467,317), XSPR_MASK, BOOKE, { RS } }, -{ "mtdac2", XSPR(31,467,1015), XSPR_MASK, PPC403, { RS } }, -{ "mtdvc1", XSPR(31,467,318), XSPR_MASK, BOOKE, { RS } }, -{ "mtdvc1", XSPR(31,467,950), XSPR_MASK, PPC405, { RS } }, -{ "mtdvc2", XSPR(31,467,319), XSPR_MASK, BOOKE, { RS } }, -{ "mtdvc2", XSPR(31,467,951), XSPR_MASK, PPC405, { RS } }, -{ "mttsr", XSPR(31,467,336), XSPR_MASK, BOOKE, { RS } }, -{ "mttsr", XSPR(31,467,984), XSPR_MASK, PPC403, { RS } }, -{ "mttcr", XSPR(31,467,340), XSPR_MASK, BOOKE, { RS } }, -{ "mttcr", XSPR(31,467,986), XSPR_MASK, PPC403, { RS } }, -{ "mtivor0", XSPR(31,467,400), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor1", XSPR(31,467,401), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor2", XSPR(31,467,402), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor3", XSPR(31,467,403), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor4", XSPR(31,467,404), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor5", XSPR(31,467,405), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor6", XSPR(31,467,406), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor7", XSPR(31,467,407), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor8", XSPR(31,467,408), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor9", XSPR(31,467,409), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor10", XSPR(31,467,410), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor11", XSPR(31,467,411), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor12", XSPR(31,467,412), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor13", XSPR(31,467,413), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor14", XSPR(31,467,414), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor15", XSPR(31,467,415), XSPR_MASK, BOOKE, { RS } }, -{ "mtspefscr", XSPR(31,467,512), XSPR_MASK, PPCSPE, { RS } }, -{ "mtbbear", XSPR(31,467,513), XSPR_MASK, PPCBRLK, { RS } }, -{ "mtbbtar", XSPR(31,467,514), XSPR_MASK, PPCBRLK, { RS } }, -{ "mtivor32", XSPR(31,467,528), XSPR_MASK, PPCSPE, { RS } }, -{ "mtivor33", XSPR(31,467,529), XSPR_MASK, PPCSPE, { RS } }, -{ "mtivor34", XSPR(31,467,530), XSPR_MASK, PPCSPE, { RS } }, -{ "mtivor35", XSPR(31,467,531), XSPR_MASK, PPCPMR, { RS } }, -{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtmcsrr0", XSPR(31,467,570), XSPR_MASK, PPCRFMCI, { RS } }, -{ "mtmcsrr1", XSPR(31,467,571), XSPR_MASK, PPCRFMCI, { RS } }, -{ "mtmcsr", XSPR(31,467,572), XSPR_MASK, PPCRFMCI, { RS } }, -{ "mtummcr0", XSPR(31,467,936), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc1", XSPR(31,467,937), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc2", XSPR(31,467,938), XSPR_MASK, PPC750, { RS } }, -{ "mtusia", XSPR(31,467,939), XSPR_MASK, PPC750, { RS } }, -{ "mtummcr1", XSPR(31,467,940), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc3", XSPR(31,467,941), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc4", XSPR(31,467,942), XSPR_MASK, PPC750, { RS } }, -{ "mtzpr", XSPR(31,467,944), XSPR_MASK, PPC403, { RS } }, -{ "mtccr0", XSPR(31,467,947), XSPR_MASK, PPC405, { RS } }, -{ "mtmmcr0", XSPR(31,467,952), XSPR_MASK, PPC750, { RS } }, -{ "mtsgr", XSPR(31,467,953), XSPR_MASK, PPC403, { RS } }, -{ "mtpmc1", XSPR(31,467,953), XSPR_MASK, PPC750, { RS } }, -{ "mtdcwr", XSPR(31,467,954), XSPR_MASK, PPC403, { RS } }, -{ "mtpmc2", XSPR(31,467,954), XSPR_MASK, PPC750, { RS } }, -{ "mtsler", XSPR(31,467,955), XSPR_MASK, PPC405, { RS } }, -{ "mtsia", XSPR(31,467,955), XSPR_MASK, PPC750, { RS } }, -{ "mtsu0r", XSPR(31,467,956), XSPR_MASK, PPC405, { RS } }, -{ "mtmmcr1", XSPR(31,467,956), XSPR_MASK, PPC750, { RS } }, -{ "mtpmc3", XSPR(31,467,957), XSPR_MASK, PPC750, { RS } }, -{ "mtpmc4", XSPR(31,467,958), XSPR_MASK, PPC750, { RS } }, -{ "mticdbdr", XSPR(31,467,979), XSPR_MASK, PPC403, { RS } }, -{ "mtevpr", XSPR(31,467,982), XSPR_MASK, PPC403, { RS } }, -{ "mtcdbcr", XSPR(31,467,983), XSPR_MASK, PPC403, { RS } }, -{ "mtpit", XSPR(31,467,987), XSPR_MASK, PPC403, { RS } }, -{ "mttbhi", XSPR(31,467,988), XSPR_MASK, PPC403, { RS } }, -{ "mttblo", XSPR(31,467,989), XSPR_MASK, PPC403, { RS } }, -{ "mtsrr2", XSPR(31,467,990), XSPR_MASK, PPC403, { RS } }, -{ "mtsrr3", XSPR(31,467,991), XSPR_MASK, PPC403, { RS } }, -{ "mtl2cr", XSPR(31,467,1017), XSPR_MASK, PPC750, { RS } }, -{ "mtdccr", XSPR(31,467,1018), XSPR_MASK, PPC403, { RS } }, -{ "mticcr", XSPR(31,467,1019), XSPR_MASK, PPC403, { RS } }, -{ "mtictc", XSPR(31,467,1019), XSPR_MASK, PPC750, { RS } }, -{ "mtpbl1", XSPR(31,467,1020), XSPR_MASK, PPC403, { RS } }, -{ "mtthrm1", XSPR(31,467,1020), XSPR_MASK, PPC750, { RS } }, -{ "mtpbu1", XSPR(31,467,1021), XSPR_MASK, PPC403, { RS } }, -{ "mtthrm2", XSPR(31,467,1021), XSPR_MASK, PPC750, { RS } }, -{ "mtpbl2", XSPR(31,467,1022), XSPR_MASK, PPC403, { RS } }, -{ "mtthrm3", XSPR(31,467,1022), XSPR_MASK, PPC750, { RS } }, -{ "mtpbu2", XSPR(31,467,1023), XSPR_MASK, PPC403, { RS } }, -{ "mtspr", X(31,467), X_MASK, COM, { SPR, RS } }, - -{ "dcbi", X(31,470), XRT_MASK, PPC, { RA, RB } }, - -{ "nand", XRC(31,476,0), X_MASK, COM, { RA, RS, RB } }, -{ "nand.", XRC(31,476,1), X_MASK, COM, { RA, RS, RB } }, - -{ "dcbie", X(31,478), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "dcread", X(31,486), X_MASK, PPC403|PPC440, { RT, RA, RB }}, - -{ "mtpmr", X(31,462), X_MASK, PPCPMR, { PMR, RS }}, - -{ "icbtls", X(31,486), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "nabs", XO(31,488,0,0), XORB_MASK, M601, { RT, RA } }, -{ "subfme64",XO(31,488,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "nabs.", XO(31,488,0,1), XORB_MASK, M601, { RT, RA } }, -{ "nabso", XO(31,488,1,0), XORB_MASK, M601, { RT, RA } }, -{ "subfme64o",XO(31,488,1,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "nabso.", XO(31,488,1,1), XORB_MASK, M601, { RT, RA } }, - -{ "divd", XO(31,489,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divd.", XO(31,489,0,1), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divdo", XO(31,489,1,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divdo.", XO(31,489,1,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addme64", XO(31,490,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "addme64o",XO(31,490,1,0), XORB_MASK, BOOKE64, { RT, RA } }, - -{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divw.", XO(31,491,0,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwo", XO(31,491,1,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwo.", XO(31,491,1,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "icbtlse", X(31,494), X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "slbia", X(31,498), 0xffffffff, PPC64, { 0 } }, - -{ "cli", X(31,502), XRB_MASK, POWER, { RT, RA } }, - -{ "stdcxe.", XRC(31,511,1), X_MASK, BOOKE64, { RS, RA, RB } }, - -{ "mcrxr", X(31,512), XRARB_MASK|(3<<21), COM, { BF } }, - -{ "bblels", X(31,518), X_MASK, PPCBRLK, { 0 }}, -{ "mcrxr64", X(31,544), XRARB_MASK|(3<<21), BOOKE64, { BF } }, - -{ "clcs", X(31,531), XRB_MASK, M601, { RT, RA } }, - -{ "ldbrx", X(31,532), X_MASK, CELL, { RT, RA0, RB } }, - -{ "lswx", X(31,533), X_MASK, PPCCOM, { RT, RA0, RB } }, -{ "lsx", X(31,533), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "lwbrx", X(31,534), X_MASK, PPCCOM, { RT, RA0, RB } }, -{ "lbrx", X(31,534), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "lfsx", X(31,535), X_MASK, COM, { FRT, RA0, RB } }, - -{ "srw", XRC(31,536,0), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sr", XRC(31,536,0), X_MASK, PWRCOM, { RA, RS, RB } }, -{ "srw.", XRC(31,536,1), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sr.", XRC(31,536,1), X_MASK, PWRCOM, { RA, RS, RB } }, - -{ "rrib", XRC(31,537,0), X_MASK, M601, { RA, RS, RB } }, -{ "rrib.", XRC(31,537,1), X_MASK, M601, { RA, RS, RB } }, - -{ "srd", XRC(31,539,0), X_MASK, PPC64, { RA, RS, RB } }, -{ "srd.", XRC(31,539,1), X_MASK, PPC64, { RA, RS, RB } }, - -{ "maskir", XRC(31,541,0), X_MASK, M601, { RA, RS, RB } }, -{ "maskir.", XRC(31,541,1), X_MASK, M601, { RA, RS, RB } }, - -{ "lwbrxe", X(31,542), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "lfsxe", X(31,543), X_MASK, BOOKE64, { FRT, RA0, RB } }, - -{ "bbelr", X(31,550), X_MASK, PPCBRLK, { 0 }}, - -{ "tlbsync", X(31,566), 0xffffffff, PPC, { 0 } }, - -{ "lfsux", X(31,567), X_MASK, COM, { FRT, RAS, RB } }, - -{ "lfsuxe", X(31,575), X_MASK, BOOKE64, { FRT, RAS, RB } }, - -{ "mfsr", X(31,595), XRB_MASK|(1<<20), COM32, { RT, SR } }, - -{ "lswi", X(31,597), X_MASK, PPCCOM, { RT, RA0, NB } }, -{ "lsi", X(31,597), X_MASK, PWRCOM, { RT, RA0, NB } }, - -{ "lwsync", XSYNC(31,598,1), 0xffffffff, PPC, { 0 } }, -{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64, { 0 } }, -{ "msync", X(31,598), 0xffffffff, BOOKE, { 0 } }, -{ "sync", X(31,598), XSYNC_MASK, PPCCOM, { LS } }, -{ "dcs", X(31,598), 0xffffffff, PWRCOM, { 0 } }, - -{ "lfdx", X(31,599), X_MASK, COM, { FRT, RA0, RB } }, - -{ "lfdxe", X(31,607), X_MASK, BOOKE64, { FRT, RA0, RB } }, - -{ "mffgpr", XRC(31,607,0), XRA_MASK, POWER6, { FRT, RB } }, - -{ "mfsri", X(31,627), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "dclst", X(31,630), XRB_MASK, PWRCOM, { RS, RA } }, - -{ "lfdux", X(31,631), X_MASK, COM, { FRT, RAS, RB } }, - -{ "lfduxe", X(31,639), X_MASK, BOOKE64, { FRT, RAS, RB } }, - -{ "mfsrin", X(31,659), XRA_MASK, PPC32, { RT, RB } }, - -{ "stdbrx", X(31,660), X_MASK, CELL, { RS, RA0, RB } }, - -{ "stswx", X(31,661), X_MASK, PPCCOM, { RS, RA0, RB } }, -{ "stsx", X(31,661), X_MASK, PWRCOM, { RS, RA0, RB } }, - -{ "stwbrx", X(31,662), X_MASK, PPCCOM, { RS, RA0, RB } }, -{ "stbrx", X(31,662), X_MASK, PWRCOM, { RS, RA0, RB } }, - -{ "stfsx", X(31,663), X_MASK, COM, { FRS, RA0, RB } }, - -{ "srq", XRC(31,664,0), X_MASK, M601, { RA, RS, RB } }, -{ "srq.", XRC(31,664,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sre", XRC(31,665,0), X_MASK, M601, { RA, RS, RB } }, -{ "sre.", XRC(31,665,1), X_MASK, M601, { RA, RS, RB } }, - -{ "stwbrxe", X(31,670), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "stfsxe", X(31,671), X_MASK, BOOKE64, { FRS, RA0, RB } }, - -{ "stfsux", X(31,695), X_MASK, COM, { FRS, RAS, RB } }, - -{ "sriq", XRC(31,696,0), X_MASK, M601, { RA, RS, SH } }, -{ "sriq.", XRC(31,696,1), X_MASK, M601, { RA, RS, SH } }, - -{ "stfsuxe", X(31,703), X_MASK, BOOKE64, { FRS, RAS, RB } }, - -{ "stswi", X(31,725), X_MASK, PPCCOM, { RS, RA0, NB } }, -{ "stsi", X(31,725), X_MASK, PWRCOM, { RS, RA0, NB } }, - -{ "stfdx", X(31,727), X_MASK, COM, { FRS, RA0, RB } }, - -{ "srlq", XRC(31,728,0), X_MASK, M601, { RA, RS, RB } }, -{ "srlq.", XRC(31,728,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sreq", XRC(31,729,0), X_MASK, M601, { RA, RS, RB } }, -{ "sreq.", XRC(31,729,1), X_MASK, M601, { RA, RS, RB } }, - -{ "stfdxe", X(31,735), X_MASK, BOOKE64, { FRS, RA0, RB } }, - -{ "mftgpr", XRC(31,735,0), XRA_MASK, POWER6, { RT, FRB } }, - -{ "dcba", X(31,758), XRT_MASK, PPC405 | BOOKE, { RA, RB } }, - -{ "stfdux", X(31,759), X_MASK, COM, { FRS, RAS, RB } }, - -{ "srliq", XRC(31,760,0), X_MASK, M601, { RA, RS, SH } }, -{ "srliq.", XRC(31,760,1), X_MASK, M601, { RA, RS, SH } }, - -{ "dcbae", X(31,766), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "stfduxe", X(31,767), X_MASK, BOOKE64, { FRS, RAS, RB } }, - -{ "tlbivax", X(31,786), XRT_MASK, BOOKE, { RA, RB } }, -{ "tlbivaxe",X(31,787), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lwzcix", X(31,789), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "lhbrx", X(31,790), X_MASK, COM, { RT, RA0, RB } }, - -{ "sraw", XRC(31,792,0), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sra", XRC(31,792,0), X_MASK, PWRCOM, { RA, RS, RB } }, -{ "sraw.", XRC(31,792,1), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sra.", XRC(31,792,1), X_MASK, PWRCOM, { RA, RS, RB } }, - -{ "srad", XRC(31,794,0), X_MASK, PPC64, { RA, RS, RB } }, -{ "srad.", XRC(31,794,1), X_MASK, PPC64, { RA, RS, RB } }, - -{ "lhbrxe", X(31,798), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "ldxe", X(31,799), X_MASK, BOOKE64, { RT, RA0, RB } }, -{ "lduxe", X(31,831), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "rac", X(31,818), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "lhzcix", X(31,821), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "dss", XDSS(31,822,0), XDSS_MASK, PPCVEC, { STRM } }, -{ "dssall", XDSS(31,822,1), XDSS_MASK, PPCVEC, { 0 } }, - -{ "srawi", XRC(31,824,0), X_MASK, PPCCOM, { RA, RS, SH } }, -{ "srai", XRC(31,824,0), X_MASK, PWRCOM, { RA, RS, SH } }, -{ "srawi.", XRC(31,824,1), X_MASK, PPCCOM, { RA, RS, SH } }, -{ "srai.", XRC(31,824,1), X_MASK, PWRCOM, { RA, RS, SH } }, - -{ "slbmfev", X(31,851), XRA_MASK, PPC64, { RT, RB } }, - -{ "lbzcix", X(31,853), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "mbar", X(31,854), X_MASK, BOOKE, { MO } }, -{ "eieio", X(31,854), 0xffffffff, PPC, { 0 } }, - -{ "lfiwax", X(31,855), X_MASK, POWER6, { FRT, RA0, RB } }, - -{ "ldcix", X(31,885), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "tlbsx", XRC(31,914,0), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, -{ "tlbsx.", XRC(31,914,1), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, -{ "tlbsxe", XRC(31,915,0), X_MASK, BOOKE64, { RTO, RA, RB } }, -{ "tlbsxe.", XRC(31,915,1), X_MASK, BOOKE64, { RTO, RA, RB } }, - -{ "slbmfee", X(31,915), XRA_MASK, PPC64, { RT, RB } }, - -{ "stwcix", X(31,917), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "sthbrx", X(31,918), X_MASK, COM, { RS, RA0, RB } }, - -{ "sraq", XRC(31,920,0), X_MASK, M601, { RA, RS, RB } }, -{ "sraq.", XRC(31,920,1), X_MASK, M601, { RA, RS, RB } }, - -{ "srea", XRC(31,921,0), X_MASK, M601, { RA, RS, RB } }, -{ "srea.", XRC(31,921,1), X_MASK, M601, { RA, RS, RB } }, - -{ "extsh", XRC(31,922,0), XRB_MASK, PPCCOM, { RA, RS } }, -{ "exts", XRC(31,922,0), XRB_MASK, PWRCOM, { RA, RS } }, -{ "extsh.", XRC(31,922,1), XRB_MASK, PPCCOM, { RA, RS } }, -{ "exts.", XRC(31,922,1), XRB_MASK, PWRCOM, { RA, RS } }, - -{ "sthbrxe", X(31,926), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "stdxe", X(31,927), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "tlbrehi", XTLB(31,946,0), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbrelo", XTLB(31,946,1), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbre", X(31,946), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, - -{ "sthcix", X(31,949), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "sraiq", XRC(31,952,0), X_MASK, M601, { RA, RS, SH } }, -{ "sraiq.", XRC(31,952,1), X_MASK, M601, { RA, RS, SH } }, - -{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} }, -{ "extsb.", XRC(31,954,1), XRB_MASK, PPC, { RA, RS} }, - -{ "stduxe", X(31,959), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "iccci", X(31,966), XRT_MASK, PPC403|PPC440, { RA, RB } }, - -{ "tlbwehi", XTLB(31,978,0), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbwelo", XTLB(31,978,1), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbwe", X(31,978), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, -{ "tlbld", X(31,978), XRTRA_MASK, PPC, { RB } }, - -{ "stbcix", X(31,981), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "icbi", X(31,982), XRT_MASK, PPC, { RA, RB } }, - -{ "stfiwx", X(31,983), X_MASK, PPC, { FRS, RA0, RB } }, - -{ "extsw", XRC(31,986,0), XRB_MASK, PPC64 | BOOKE64,{ RA, RS } }, -{ "extsw.", XRC(31,986,1), XRB_MASK, PPC64, { RA, RS } }, - -{ "icread", X(31,998), XRT_MASK, PPC403|PPC440, { RA, RB } }, - -{ "icbie", X(31,990), XRT_MASK, BOOKE64, { RA, RB } }, -{ "stfiwxe", X(31,991), X_MASK, BOOKE64, { FRS, RA0, RB } }, - -{ "tlbli", X(31,1010), XRTRA_MASK, PPC, { RB } }, - -{ "stdcix", X(31,1013), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "dcbzl", XOPL(31,1014,1), XRT_MASK,POWER4, { RA, RB } }, -{ "dcbz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, -{ "dclz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, - -{ "dcbze", X(31,1022), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lvebx", X(31, 7), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvehx", X(31, 39), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvewx", X(31, 71), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvsl", X(31, 6), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvsr", X(31, 38), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvx", X(31, 103), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvxl", X(31, 359), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "stvebx", X(31, 135), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvehx", X(31, 167), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvewx", X(31, 199), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvx", X(31, 231), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvxl", X(31, 487), X_MASK, PPCVEC, { VS, RA, RB } }, - -/* New load/store left/right index vector instructions that are in the Cell only. */ -{ "lvlx", X(31, 519), X_MASK, CELL, { VD, RA0, RB } }, -{ "lvlxl", X(31, 775), X_MASK, CELL, { VD, RA0, RB } }, -{ "lvrx", X(31, 551), X_MASK, CELL, { VD, RA0, RB } }, -{ "lvrxl", X(31, 807), X_MASK, CELL, { VD, RA0, RB } }, -{ "stvlx", X(31, 647), X_MASK, CELL, { VS, RA0, RB } }, -{ "stvlxl", X(31, 903), X_MASK, CELL, { VS, RA0, RB } }, -{ "stvrx", X(31, 679), X_MASK, CELL, { VS, RA0, RB } }, -{ "stvrxl", X(31, 935), X_MASK, CELL, { VS, RA0, RB } }, - -{ "lwz", OP(32), OP_MASK, PPCCOM, { RT, D, RA0 } }, -{ "l", OP(32), OP_MASK, PWRCOM, { RT, D, RA0 } }, - -{ "lwzu", OP(33), OP_MASK, PPCCOM, { RT, D, RAL } }, -{ "lu", OP(33), OP_MASK, PWRCOM, { RT, D, RA0 } }, - -{ "lbz", OP(34), OP_MASK, COM, { RT, D, RA0 } }, - -{ "lbzu", OP(35), OP_MASK, COM, { RT, D, RAL } }, - -{ "stw", OP(36), OP_MASK, PPCCOM, { RS, D, RA0 } }, -{ "st", OP(36), OP_MASK, PWRCOM, { RS, D, RA0 } }, - -{ "stwu", OP(37), OP_MASK, PPCCOM, { RS, D, RAS } }, -{ "stu", OP(37), OP_MASK, PWRCOM, { RS, D, RA0 } }, - -{ "stb", OP(38), OP_MASK, COM, { RS, D, RA0 } }, - -{ "stbu", OP(39), OP_MASK, COM, { RS, D, RAS } }, - -{ "lhz", OP(40), OP_MASK, COM, { RT, D, RA0 } }, - -{ "lhzu", OP(41), OP_MASK, COM, { RT, D, RAL } }, - -{ "lha", OP(42), OP_MASK, COM, { RT, D, RA0 } }, - -{ "lhau", OP(43), OP_MASK, COM, { RT, D, RAL } }, - -{ "sth", OP(44), OP_MASK, COM, { RS, D, RA0 } }, - -{ "sthu", OP(45), OP_MASK, COM, { RS, D, RAS } }, - -{ "lmw", OP(46), OP_MASK, PPCCOM, { RT, D, RAM } }, -{ "lm", OP(46), OP_MASK, PWRCOM, { RT, D, RA0 } }, - -{ "stmw", OP(47), OP_MASK, PPCCOM, { RS, D, RA0 } }, -{ "stm", OP(47), OP_MASK, PWRCOM, { RS, D, RA0 } }, - -{ "lfs", OP(48), OP_MASK, COM, { FRT, D, RA0 } }, - -{ "lfsu", OP(49), OP_MASK, COM, { FRT, D, RAS } }, - -{ "lfd", OP(50), OP_MASK, COM, { FRT, D, RA0 } }, - -{ "lfdu", OP(51), OP_MASK, COM, { FRT, D, RAS } }, - -{ "stfs", OP(52), OP_MASK, COM, { FRS, D, RA0 } }, - -{ "stfsu", OP(53), OP_MASK, COM, { FRS, D, RAS } }, - -{ "stfd", OP(54), OP_MASK, COM, { FRS, D, RA0 } }, - -{ "stfdu", OP(55), OP_MASK, COM, { FRS, D, RAS } }, - -{ "lq", OP(56), OP_MASK, POWER4, { RTQ, DQ, RAQ } }, - -{ "lfq", OP(56), OP_MASK, POWER2, { FRT, D, RA0 } }, - -{ "lfqu", OP(57), OP_MASK, POWER2, { FRT, D, RA0 } }, - -{ "lfdp", OP(57), OP_MASK, POWER6, { FRT, D, RA0 } }, - -{ "lbze", DEO(58,0), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lbzue", DEO(58,1), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "lhze", DEO(58,2), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lhzue", DEO(58,3), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "lhae", DEO(58,4), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lhaue", DEO(58,5), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "lwze", DEO(58,6), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lwzue", DEO(58,7), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "stbe", DEO(58,8), DE_MASK, BOOKE64, { RS, DE, RA0 } }, -{ "stbue", DEO(58,9), DE_MASK, BOOKE64, { RS, DE, RAS } }, -{ "sthe", DEO(58,10), DE_MASK, BOOKE64, { RS, DE, RA0 } }, -{ "sthue", DEO(58,11), DE_MASK, BOOKE64, { RS, DE, RAS } }, -{ "stwe", DEO(58,14), DE_MASK, BOOKE64, { RS, DE, RA0 } }, -{ "stwue", DEO(58,15), DE_MASK, BOOKE64, { RS, DE, RAS } }, - -{ "ld", DSO(58,0), DS_MASK, PPC64, { RT, DS, RA0 } }, - -{ "ldu", DSO(58,1), DS_MASK, PPC64, { RT, DS, RAL } }, - -{ "lwa", DSO(58,2), DS_MASK, PPC64, { RT, DS, RA0 } }, - -{ "dadd", XRC(59,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dadd.", XRC(59,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "dqua", ZRC(59,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "dqua.", ZRC(59,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, -{ "fdivs.", A(59,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, - -{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, -{ "fsubs.", A(59,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, - -{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, -{ "fadds.", A(59,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, - -{ "fsqrts", A(59,22,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, -{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, - -{ "fres", A(59,24,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, -{ "fres.", A(59,24,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, - -{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, -{ "fmuls.", A(59,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, - -{ "frsqrtes", A(59,26,0), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, -{ "frsqrtes.",A(59,26,1), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, - -{ "fmsubs", A(59,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fmsubs.", A(59,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fmadds", A(59,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fmadds.", A(59,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fnmsubs", A(59,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fnmsubs.",A(59,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fnmadds", A(59,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fnmadds.",A(59,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "dmul", XRC(59,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dmul.", XRC(59,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "drrnd", ZRC(59,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "drrnd.", ZRC(59,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "dscli", ZRC(59,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscli.", ZRC(59,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "dquai", ZRC(59,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, -{ "dquai.", ZRC(59,67,1), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, - -{ "dscri", ZRC(59,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscri.", ZRC(59,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "drintx", ZRC(59,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintx.", ZRC(59,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dcmpo", X(59,130), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "dtstex", X(59,162), X_MASK, POWER6, { BF, FRA, FRB } }, -{ "dtstdc", Z(59,194), Z_MASK, POWER6, { BF, FRA, DCM } }, -{ "dtstdg", Z(59,226), Z_MASK, POWER6, { BF, FRA, DGM } }, - -{ "drintn", ZRC(59,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintn.", ZRC(59,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dctdp", XRC(59,258,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctdp.", XRC(59,258,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dctfix", XRC(59,290,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctfix.", XRC(59,290,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "ddedpd", XRC(59,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, -{ "ddedpd.", XRC(59,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, - -{ "dxex", XRC(59,354,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dxex.", XRC(59,354,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dsub", XRC(59,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dsub.", XRC(59,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "ddiv", XRC(59,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "ddiv.", XRC(59,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "dcmpu", X(59,642), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "dtstsf", X(59,674), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "drsp", XRC(59,770,0), X_MASK, POWER6, { FRT, FRB } }, -{ "drsp.", XRC(59,770,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dcffix", XRC(59,802,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dcffix.", XRC(59,802,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "denbcd", XRC(59,834,0), X_MASK, POWER6, { S, FRT, FRB } }, -{ "denbcd.", XRC(59,834,1), X_MASK, POWER6, { S, FRT, FRB } }, - -{ "diex", XRC(59,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "diex.", XRC(59,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "stfq", OP(60), OP_MASK, POWER2, { FRS, D, RA } }, - -{ "stfqu", OP(61), OP_MASK, POWER2, { FRS, D, RA } }, - -{ "stfdp", OP(61), OP_MASK, POWER6, { FRT, D, RA0 } }, - -{ "lde", DEO(62,0), DE_MASK, BOOKE64, { RT, DES, RA0 } }, -{ "ldue", DEO(62,1), DE_MASK, BOOKE64, { RT, DES, RA0 } }, -{ "lfse", DEO(62,4), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, -{ "lfsue", DEO(62,5), DE_MASK, BOOKE64, { FRT, DES, RAS } }, -{ "lfde", DEO(62,6), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, -{ "lfdue", DEO(62,7), DE_MASK, BOOKE64, { FRT, DES, RAS } }, -{ "stde", DEO(62,8), DE_MASK, BOOKE64, { RS, DES, RA0 } }, -{ "stdue", DEO(62,9), DE_MASK, BOOKE64, { RS, DES, RAS } }, -{ "stfse", DEO(62,12), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, -{ "stfsue", DEO(62,13), DE_MASK, BOOKE64, { FRS, DES, RAS } }, -{ "stfde", DEO(62,14), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, -{ "stfdue", DEO(62,15), DE_MASK, BOOKE64, { FRS, DES, RAS } }, - -{ "std", DSO(62,0), DS_MASK, PPC64, { RS, DS, RA0 } }, - -{ "stdu", DSO(62,1), DS_MASK, PPC64, { RS, DS, RAS } }, - -{ "stq", DSO(62,2), DS_MASK, POWER4, { RSQ, DS, RA0 } }, - -{ "fcmpu", X(63,0), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, - -{ "daddq", XRC(63,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "daddq.", XRC(63,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "dquaq", ZRC(63,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "dquaq.", ZRC(63,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "fcpsgn", XRC(63,8,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "fcpsgn.", XRC(63,8,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "frsp", XRC(63,12,0), XRA_MASK, COM, { FRT, FRB } }, -{ "frsp.", XRC(63,12,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "fctiw", XRC(63,14,0), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcir", XRC(63,14,0), XRA_MASK, POWER2, { FRT, FRB } }, -{ "fctiw.", XRC(63,14,1), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcir.", XRC(63,14,1), XRA_MASK, POWER2, { FRT, FRB } }, - -{ "fctiwz", XRC(63,15,0), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcirz", XRC(63,15,0), XRA_MASK, POWER2, { FRT, FRB } }, -{ "fctiwz.", XRC(63,15,1), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcirz.", XRC(63,15,1), XRA_MASK, POWER2, { FRT, FRB } }, - -{ "fdiv", A(63,18,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fd", A(63,18,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, -{ "fdiv.", A(63,18,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fd.", A(63,18,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, - -{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fs", A(63,20,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, -{ "fsub.", A(63,20,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fs.", A(63,20,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, - -{ "fadd", A(63,21,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fa", A(63,21,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, -{ "fadd.", A(63,21,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fa.", A(63,21,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, - -{ "fsqrt", A(63,22,0), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, -{ "fsqrt.", A(63,22,1), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, - -{ "fsel", A(63,23,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fsel.", A(63,23,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fre", A(63,24,0), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, -{ "fre.", A(63,24,1), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, - -{ "fmul", A(63,25,0), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, -{ "fm", A(63,25,0), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, -{ "fmul.", A(63,25,1), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, -{ "fm.", A(63,25,1), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, - -{ "frsqrte", A(63,26,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, -{ "frsqrte.",A(63,26,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, - -{ "fmsub", A(63,28,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fms", A(63,28,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fmsub.", A(63,28,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fms.", A(63,28,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fmadd", A(63,29,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fma", A(63,29,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fmadd.", A(63,29,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fma.", A(63,29,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fnmsub", A(63,30,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnms", A(63,30,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fnmsub.", A(63,30,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnms.", A(63,30,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fnmadd", A(63,31,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnma", A(63,31,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fnmadd.", A(63,31,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnma.", A(63,31,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fcmpo", X(63,32), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, - -{ "dmulq", XRC(63,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dmulq.", XRC(63,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "drrndq", ZRC(63,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "drrndq.", ZRC(63,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "mtfsb1", XRC(63,38,0), XRARB_MASK, COM, { BT } }, -{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, COM, { BT } }, - -{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fneg.", XRC(63,40,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "mcrfs", X(63,64), XRB_MASK|(3<<21)|(3<<16), COM, { BF, BFA } }, - -{ "dscliq", ZRC(63,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscliq.", ZRC(63,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "dquaiq", ZRC(63,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, -{ "dquaiq.", ZRC(63,67,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "mtfsb0", XRC(63,70,0), XRARB_MASK, COM, { BT } }, -{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, COM, { BT } }, - -{ "fmr", XRC(63,72,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fmr.", XRC(63,72,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "dscriq", ZRC(63,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscriq.", ZRC(63,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "drintxq", ZRC(63,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintxq.",ZRC(63,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dcmpoq", X(63,130), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "mtfsfi", XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, -{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, - -{ "fnabs", XRC(63,136,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fnabs.", XRC(63,136,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "dtstexq", X(63,162), X_MASK, POWER6, { BF, FRA, FRB } }, -{ "dtstdcq", Z(63,194), Z_MASK, POWER6, { BF, FRA, DCM } }, -{ "dtstdgq", Z(63,226), Z_MASK, POWER6, { BF, FRA, DGM } }, - -{ "drintnq", ZRC(63,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintnq.",ZRC(63,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dctqpq", XRC(63,258,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctqpq.", XRC(63,258,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "fabs", XRC(63,264,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fabs.", XRC(63,264,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "dctfixq", XRC(63,290,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctfixq.",XRC(63,290,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "ddedpdq", XRC(63,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, -{ "ddedpdq.",XRC(63,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, - -{ "dxexq", XRC(63,354,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dxexq.", XRC(63,354,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "frin", XRC(63,392,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frin.", XRC(63,392,1), XRA_MASK, POWER5, { FRT, FRB } }, -{ "friz", XRC(63,424,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "friz.", XRC(63,424,1), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frip", XRC(63,456,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frip.", XRC(63,456,1), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frim", XRC(63,488,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frim.", XRC(63,488,1), XRA_MASK, POWER5, { FRT, FRB } }, - -{ "dsubq", XRC(63,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dsubq.", XRC(63,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "ddivq", XRC(63,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "ddivq.", XRC(63,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "mffsl", XRA(63,583,12), XRARB_MASK, POWER9, { FRT } }, - -{ "mffs", XRC(63,583,0), XRARB_MASK, COM, { FRT } }, -{ "mffs.", XRC(63,583,1), XRARB_MASK, COM, { FRT } }, - -{ "dcmpuq", X(63,642), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "dtstsfq", X(63,674), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "mtfsf", XFL(63,711,0), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, -{ "mtfsf.", XFL(63,711,1), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, - -{ "drdpq", XRC(63,770,0), X_MASK, POWER6, { FRT, FRB } }, -{ "drdpq.", XRC(63,770,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dcffixq", XRC(63,802,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dcffixq.",XRC(63,802,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "fctid", XRC(63,814,0), XRA_MASK, PPC64, { FRT, FRB } }, -{ "fctid.", XRC(63,814,1), XRA_MASK, PPC64, { FRT, FRB } }, - -{ "fctidz", XRC(63,815,0), XRA_MASK, PPC64, { FRT, FRB } }, -{ "fctidz.", XRC(63,815,1), XRA_MASK, PPC64, { FRT, FRB } }, - -{ "denbcdq", XRC(63,834,0), X_MASK, POWER6, { S, FRT, FRB } }, -{ "denbcdq.",XRC(63,834,1), X_MASK, POWER6, { S, FRT, FRB } }, - -{ "fcfid", XRC(63,846,0), XRA_MASK, PPC64, { FRT, FRB } }, -{ "fcfid.", XRC(63,846,1), XRA_MASK, PPC64, { FRT, FRB } }, - -{ "diexq", XRC(63,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "diexq.", XRC(63,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -}; - -const int powerpc_num_opcodes = - sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); - -/* The macro table. This is only used by the assembler. */ - -/* The expressions of the form (-x ! 31) & (x | 31) have the value 0 - when x=0; 32-x when x is between 1 and 31; are negative if x is - negative; and are 32 or more otherwise. This is what you want - when, for instance, you are emulating a right shift by a - rotate-left-and-mask, because the underlying instructions support - shifts of size 0 but not shifts of size 32. By comparison, when - extracting x bits from some word you want to use just 32-x, because - the underlying instructions don't support extracting 0 bits but do - support extracting the whole word (32 bits in this case). */ - -const struct powerpc_macro powerpc_macros[] = { -{ "extldi", 4, PPC64, "rldicr %0,%1,%3,(%2)-1" }, -{ "extldi.", 4, PPC64, "rldicr. %0,%1,%3,(%2)-1" }, -{ "extrdi", 4, PPC64, "rldicl %0,%1,(%2)+(%3),64-(%2)" }, -{ "extrdi.", 4, PPC64, "rldicl. %0,%1,(%2)+(%3),64-(%2)" }, -{ "insrdi", 4, PPC64, "rldimi %0,%1,64-((%2)+(%3)),%3" }, -{ "insrdi.", 4, PPC64, "rldimi. %0,%1,64-((%2)+(%3)),%3" }, -{ "rotrdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),0" }, -{ "rotrdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" }, -{ "sldi", 3, PPC64, "rldicr %0,%1,%2,63-(%2)" }, -{ "sldi.", 3, PPC64, "rldicr. %0,%1,%2,63-(%2)" }, -{ "srdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" }, -{ "srdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" }, -{ "clrrdi", 3, PPC64, "rldicr %0,%1,0,63-(%2)" }, -{ "clrrdi.", 3, PPC64, "rldicr. %0,%1,0,63-(%2)" }, -{ "clrlsldi",4, PPC64, "rldic %0,%1,%3,(%2)-(%3)" }, -{ "clrlsldi.",4, PPC64, "rldic. %0,%1,%3,(%2)-(%3)" }, - -{ "extlwi", 4, PPCCOM, "rlwinm %0,%1,%3,0,(%2)-1" }, -{ "extlwi.", 4, PPCCOM, "rlwinm. %0,%1,%3,0,(%2)-1" }, -{ "extrwi", 4, PPCCOM, "rlwinm %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, -{ "extrwi.", 4, PPCCOM, "rlwinm. %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, -{ "inslwi", 4, PPCCOM, "rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" }, -{ "inslwi.", 4, PPCCOM, "rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"}, -{ "insrwi", 4, PPCCOM, "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" }, -{ "insrwi.", 4, PPCCOM, "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"}, -{ "rotrwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" }, -{ "rotrwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" }, -{ "slwi", 3, PPCCOM, "rlwinm %0,%1,%2,0,31-(%2)" }, -{ "sli", 3, PWRCOM, "rlinm %0,%1,%2,0,31-(%2)" }, -{ "slwi.", 3, PPCCOM, "rlwinm. %0,%1,%2,0,31-(%2)" }, -{ "sli.", 3, PWRCOM, "rlinm. %0,%1,%2,0,31-(%2)" }, -{ "srwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "sri", 3, PWRCOM, "rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "srwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "sri.", 3, PWRCOM, "rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "clrrwi", 3, PPCCOM, "rlwinm %0,%1,0,0,31-(%2)" }, -{ "clrrwi.", 3, PPCCOM, "rlwinm. %0,%1,0,0,31-(%2)" }, -{ "clrlslwi",4, PPCCOM, "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" }, -{ "clrlslwi.",4, PPCCOM, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, -}; - -const int powerpc_num_macros = - sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); - - -/* This file provides several disassembler functions, all of which use - the disassembler interface defined in dis-asm.h. Several functions - are provided because this file handles disassembly for the PowerPC - in both big and little endian mode and also for the POWER (RS/6000) - chip. */ - -static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int); - -/* Determine which set of machines to disassemble for. PPC403/601 or - BookE. For convenience, also disassemble instructions supported - by the AltiVec vector unit. */ - -static int -powerpc_dialect (struct disassemble_info *info) -{ - int dialect = PPC_OPCODE_PPC; - - if (BFD_DEFAULT_TARGET_SIZE == 64) - dialect |= PPC_OPCODE_64; - - if (info->disassembler_options - && strstr (info->disassembler_options, "booke") != NULL) - dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; - else if ((info->mach == bfd_mach_ppc_e500) - || (info->disassembler_options - && strstr (info->disassembler_options, "e500") != NULL)) - dialect |= (PPC_OPCODE_BOOKE - | PPC_OPCODE_SPE | PPC_OPCODE_ISEL - | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK - | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK - | PPC_OPCODE_RFMCI); - else if (info->disassembler_options - && strstr (info->disassembler_options, "efs") != NULL) - dialect |= PPC_OPCODE_EFS; - else if (info->disassembler_options - && strstr (info->disassembler_options, "e300") != NULL) - dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON; - else if (info->disassembler_options - && strstr (info->disassembler_options, "440") != NULL) - dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32 - | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI; - else - dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC - | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC); - - if (info->disassembler_options - && strstr (info->disassembler_options, "power4") != NULL) - dialect |= PPC_OPCODE_POWER4; - - if (info->disassembler_options - && strstr (info->disassembler_options, "power5") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5; - - if (info->disassembler_options - && strstr (info->disassembler_options, "cell") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC; - - if (info->disassembler_options - && strstr (info->disassembler_options, "power6") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC; - - if (info->disassembler_options - && strstr (info->disassembler_options, "any") != NULL) - dialect |= PPC_OPCODE_ANY; - - if (info->disassembler_options) - { - if (strstr (info->disassembler_options, "32") != NULL) - dialect &= ~PPC_OPCODE_64; - else if (strstr (info->disassembler_options, "64") != NULL) - dialect |= PPC_OPCODE_64; - } - - info->private_data = (char *) 0 + dialect; - return dialect; -} - -/* QEMU default */ -int -print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info) -{ - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, info->endian == BFD_ENDIAN_BIG, - dialect); -} - -/* Print a big endian PowerPC instruction. */ - -int -print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) -{ - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, 1, dialect); -} - -/* Print a little endian PowerPC instruction. */ - -int -print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) -{ - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, 0, dialect); -} - -/* Print a POWER (RS/6000) instruction. */ - -int -print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) -{ - return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); -} - -/* Extract the operand value from the PowerPC or POWER instruction. */ - -static long -operand_value_powerpc (const struct powerpc_operand *operand, - unsigned long insn, int dialect) -{ - long value; - int invalid; - /* Extract the value from the instruction. */ - if (operand->extract) - value = (*operand->extract) (insn, dialect, &invalid); - else - { - value = (insn >> operand->shift) & operand->bitm; - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - { - /* BITM is always some number of zeros followed by some - number of ones, followed by some number of zeros. */ - unsigned long top = operand->bitm; - /* top & -top gives the rightmost 1 bit, so this - fills in any trailing zeros. */ - top |= (top & -top) - 1; - top &= ~(top >> 1); - value = (value ^ top) - top; - } - } - - return value; -} - -/* Determine whether the optional operand(s) should be printed. */ - -static int -skip_optional_operands (const unsigned char *opindex, - unsigned long insn, int dialect) -{ - const struct powerpc_operand *operand; - - for (; *opindex != 0; opindex++) - { - operand = &powerpc_operands[*opindex]; - if ((operand->flags & PPC_OPERAND_NEXT) != 0 - || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 - && operand_value_powerpc (operand, insn, dialect) != 0)) - return 0; - } - - return 1; -} - -/* Print a PowerPC or POWER instruction. */ - -static int -print_insn_powerpc (bfd_vma memaddr, - struct disassemble_info *info, - int bigendian, - int dialect) -{ - bfd_byte buffer[4]; - int status; - unsigned long insn; - const struct powerpc_opcode *opcode; - const struct powerpc_opcode *opcode_end; - unsigned long op; - - if (dialect == 0) - dialect = powerpc_dialect (info); - - status = (*info->read_memory_func) (memaddr, buffer, 4, info); - if (status != 0) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - - if (bigendian) - insn = bfd_getb32 (buffer); - else - insn = bfd_getl32 (buffer); - - /* Get the major opcode of the instruction. */ - op = PPC_OP (insn); - - /* Find the first match in the opcode table. We could speed this up - a bit by doing a binary search on the major opcode. */ - opcode_end = powerpc_opcodes + powerpc_num_opcodes; - again: - for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) - { - unsigned long table_op; - const unsigned char *opindex; - const struct powerpc_operand *operand; - int invalid; - int need_comma; - int need_paren; - int skip_optional; - - table_op = PPC_OP (opcode->opcode); - if (op < table_op) - break; - if (op > table_op) - continue; - - if ((insn & opcode->mask) != opcode->opcode - || (opcode->flags & dialect) == 0) - continue; - - /* Make two passes over the operands. First see if any of them - have extraction functions, and, if they do, make sure the - instruction is valid. */ - invalid = 0; - for (opindex = opcode->operands; *opindex != 0; opindex++) - { - operand = powerpc_operands + *opindex; - if (operand->extract) - (*operand->extract) (insn, dialect, &invalid); - } - if (invalid) - continue; - - /* The instruction is valid. */ - if (opcode->operands[0] != 0) - (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); - else - (*info->fprintf_func) (info->stream, "%s", opcode->name); - - /* Now extract and print the operands. */ - need_comma = 0; - need_paren = 0; - skip_optional = -1; - for (opindex = opcode->operands; *opindex != 0; opindex++) - { - long value; - - operand = powerpc_operands + *opindex; - - /* Operands that are marked FAKE are simply ignored. We - already made sure that the extract function considered - the instruction to be valid. */ - if ((operand->flags & PPC_OPERAND_FAKE) != 0) - continue; - - /* If all of the optional operands have the value zero, - then don't print any of them. */ - if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) - { - if (skip_optional < 0) - skip_optional = skip_optional_operands (opindex, insn, - dialect); - if (skip_optional) - continue; - } - - value = operand_value_powerpc (operand, insn, dialect); - - if (need_comma) - { - (*info->fprintf_func) (info->stream, ","); - need_comma = 0; - } - - /* Print the operand as directed by the flags. */ - if ((operand->flags & PPC_OPERAND_GPR) != 0 - || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) - (*info->fprintf_func) (info->stream, "r%ld", value); - else if ((operand->flags & PPC_OPERAND_FPR) != 0) - (*info->fprintf_func) (info->stream, "f%ld", value); - else if ((operand->flags & PPC_OPERAND_VR) != 0) - (*info->fprintf_func) (info->stream, "v%ld", value); - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) - (*info->print_address_func) (memaddr + value, info); - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); - else if ((operand->flags & PPC_OPERAND_CR) == 0 - || (dialect & PPC_OPCODE_PPC) == 0) - (*info->fprintf_func) (info->stream, "%ld", value); - else - { - if (operand->bitm == 7) - (*info->fprintf_func) (info->stream, "cr%ld", value); - else - { - static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; - int cr; - int cc; - - cr = value >> 2; - if (cr != 0) - (*info->fprintf_func) (info->stream, "4*cr%d+", cr); - cc = value & 3; - (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); - } - } - - if (need_paren) - { - (*info->fprintf_func) (info->stream, ")"); - need_paren = 0; - } - - if ((operand->flags & PPC_OPERAND_PARENS) == 0) - need_comma = 1; - else - { - (*info->fprintf_func) (info->stream, "("); - need_paren = 1; - } - } - - /* We have found and printed an instruction; return. */ - return 4; - } - - if ((dialect & PPC_OPCODE_ANY) != 0) - { - dialect = ~PPC_OPCODE_ANY; - goto again; - } - - /* We could not find a match. */ - (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); - - return 4; -} diff --git a/disas/riscv.c b/disas/riscv.c index 03c8dc9961b2..d216b9c39b7a 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -156,6 +156,13 @@ typedef enum { rv_codec_css_swsp, rv_codec_css_sdsp, rv_codec_css_sqsp, + rv_codec_k_bs, + rv_codec_k_rnum, + rv_codec_v_r, + rv_codec_v_ldst, + rv_codec_v_i, + rv_codec_vsetvli, + rv_codec_vsetivli, } rv_codec; typedef enum { @@ -521,6 +528,413 @@ typedef enum { rv_op_bclr = 359, rv_op_binv = 360, rv_op_bext = 361, + rv_op_aes32esmi = 362, + rv_op_aes32esi = 363, + rv_op_aes32dsmi = 364, + rv_op_aes32dsi = 365, + rv_op_aes64ks1i = 366, + rv_op_aes64ks2 = 367, + rv_op_aes64im = 368, + rv_op_aes64esm = 369, + rv_op_aes64es = 370, + rv_op_aes64dsm = 371, + rv_op_aes64ds = 372, + rv_op_sha256sig0 = 373, + rv_op_sha256sig1 = 374, + rv_op_sha256sum0 = 375, + rv_op_sha256sum1 = 376, + rv_op_sha512sig0 = 377, + rv_op_sha512sig1 = 378, + rv_op_sha512sum0 = 379, + rv_op_sha512sum1 = 380, + rv_op_sha512sum0r = 381, + rv_op_sha512sum1r = 382, + rv_op_sha512sig0l = 383, + rv_op_sha512sig0h = 384, + rv_op_sha512sig1l = 385, + rv_op_sha512sig1h = 386, + rv_op_sm3p0 = 387, + rv_op_sm3p1 = 388, + rv_op_sm4ed = 389, + rv_op_sm4ks = 390, + rv_op_brev8 = 391, + rv_op_pack = 392, + rv_op_packh = 393, + rv_op_packw = 394, + rv_op_unzip = 395, + rv_op_zip = 396, + rv_op_xperm4 = 397, + rv_op_xperm8 = 398, + rv_op_vle8_v = 399, + rv_op_vle16_v = 400, + rv_op_vle32_v = 401, + rv_op_vle64_v = 402, + rv_op_vse8_v = 403, + rv_op_vse16_v = 404, + rv_op_vse32_v = 405, + rv_op_vse64_v = 406, + rv_op_vlm_v = 407, + rv_op_vsm_v = 408, + rv_op_vlse8_v = 409, + rv_op_vlse16_v = 410, + rv_op_vlse32_v = 411, + rv_op_vlse64_v = 412, + rv_op_vsse8_v = 413, + rv_op_vsse16_v = 414, + rv_op_vsse32_v = 415, + rv_op_vsse64_v = 416, + rv_op_vluxei8_v = 417, + rv_op_vluxei16_v = 418, + rv_op_vluxei32_v = 419, + rv_op_vluxei64_v = 420, + rv_op_vloxei8_v = 421, + rv_op_vloxei16_v = 422, + rv_op_vloxei32_v = 423, + rv_op_vloxei64_v = 424, + rv_op_vsuxei8_v = 425, + rv_op_vsuxei16_v = 426, + rv_op_vsuxei32_v = 427, + rv_op_vsuxei64_v = 428, + rv_op_vsoxei8_v = 429, + rv_op_vsoxei16_v = 430, + rv_op_vsoxei32_v = 431, + rv_op_vsoxei64_v = 432, + rv_op_vle8ff_v = 433, + rv_op_vle16ff_v = 434, + rv_op_vle32ff_v = 435, + rv_op_vle64ff_v = 436, + rv_op_vl1re8_v = 437, + rv_op_vl1re16_v = 438, + rv_op_vl1re32_v = 439, + rv_op_vl1re64_v = 440, + rv_op_vl2re8_v = 441, + rv_op_vl2re16_v = 442, + rv_op_vl2re32_v = 443, + rv_op_vl2re64_v = 444, + rv_op_vl4re8_v = 445, + rv_op_vl4re16_v = 446, + rv_op_vl4re32_v = 447, + rv_op_vl4re64_v = 448, + rv_op_vl8re8_v = 449, + rv_op_vl8re16_v = 450, + rv_op_vl8re32_v = 451, + rv_op_vl8re64_v = 452, + rv_op_vs1r_v = 453, + rv_op_vs2r_v = 454, + rv_op_vs4r_v = 455, + rv_op_vs8r_v = 456, + rv_op_vadd_vv = 457, + rv_op_vadd_vx = 458, + rv_op_vadd_vi = 459, + rv_op_vsub_vv = 460, + rv_op_vsub_vx = 461, + rv_op_vrsub_vx = 462, + rv_op_vrsub_vi = 463, + rv_op_vwaddu_vv = 464, + rv_op_vwaddu_vx = 465, + rv_op_vwadd_vv = 466, + rv_op_vwadd_vx = 467, + rv_op_vwsubu_vv = 468, + rv_op_vwsubu_vx = 469, + rv_op_vwsub_vv = 470, + rv_op_vwsub_vx = 471, + rv_op_vwaddu_wv = 472, + rv_op_vwaddu_wx = 473, + rv_op_vwadd_wv = 474, + rv_op_vwadd_wx = 475, + rv_op_vwsubu_wv = 476, + rv_op_vwsubu_wx = 477, + rv_op_vwsub_wv = 478, + rv_op_vwsub_wx = 479, + rv_op_vadc_vvm = 480, + rv_op_vadc_vxm = 481, + rv_op_vadc_vim = 482, + rv_op_vmadc_vvm = 483, + rv_op_vmadc_vxm = 484, + rv_op_vmadc_vim = 485, + rv_op_vsbc_vvm = 486, + rv_op_vsbc_vxm = 487, + rv_op_vmsbc_vvm = 488, + rv_op_vmsbc_vxm = 489, + rv_op_vand_vv = 490, + rv_op_vand_vx = 491, + rv_op_vand_vi = 492, + rv_op_vor_vv = 493, + rv_op_vor_vx = 494, + rv_op_vor_vi = 495, + rv_op_vxor_vv = 496, + rv_op_vxor_vx = 497, + rv_op_vxor_vi = 498, + rv_op_vsll_vv = 499, + rv_op_vsll_vx = 500, + rv_op_vsll_vi = 501, + rv_op_vsrl_vv = 502, + rv_op_vsrl_vx = 503, + rv_op_vsrl_vi = 504, + rv_op_vsra_vv = 505, + rv_op_vsra_vx = 506, + rv_op_vsra_vi = 507, + rv_op_vnsrl_wv = 508, + rv_op_vnsrl_wx = 509, + rv_op_vnsrl_wi = 510, + rv_op_vnsra_wv = 511, + rv_op_vnsra_wx = 512, + rv_op_vnsra_wi = 513, + rv_op_vmseq_vv = 514, + rv_op_vmseq_vx = 515, + rv_op_vmseq_vi = 516, + rv_op_vmsne_vv = 517, + rv_op_vmsne_vx = 518, + rv_op_vmsne_vi = 519, + rv_op_vmsltu_vv = 520, + rv_op_vmsltu_vx = 521, + rv_op_vmslt_vv = 522, + rv_op_vmslt_vx = 523, + rv_op_vmsleu_vv = 524, + rv_op_vmsleu_vx = 525, + rv_op_vmsleu_vi = 526, + rv_op_vmsle_vv = 527, + rv_op_vmsle_vx = 528, + rv_op_vmsle_vi = 529, + rv_op_vmsgtu_vx = 530, + rv_op_vmsgtu_vi = 531, + rv_op_vmsgt_vx = 532, + rv_op_vmsgt_vi = 533, + rv_op_vminu_vv = 534, + rv_op_vminu_vx = 535, + rv_op_vmin_vv = 536, + rv_op_vmin_vx = 537, + rv_op_vmaxu_vv = 538, + rv_op_vmaxu_vx = 539, + rv_op_vmax_vv = 540, + rv_op_vmax_vx = 541, + rv_op_vmul_vv = 542, + rv_op_vmul_vx = 543, + rv_op_vmulh_vv = 544, + rv_op_vmulh_vx = 545, + rv_op_vmulhu_vv = 546, + rv_op_vmulhu_vx = 547, + rv_op_vmulhsu_vv = 548, + rv_op_vmulhsu_vx = 549, + rv_op_vdivu_vv = 550, + rv_op_vdivu_vx = 551, + rv_op_vdiv_vv = 552, + rv_op_vdiv_vx = 553, + rv_op_vremu_vv = 554, + rv_op_vremu_vx = 555, + rv_op_vrem_vv = 556, + rv_op_vrem_vx = 557, + rv_op_vwmulu_vv = 558, + rv_op_vwmulu_vx = 559, + rv_op_vwmulsu_vv = 560, + rv_op_vwmulsu_vx = 561, + rv_op_vwmul_vv = 562, + rv_op_vwmul_vx = 563, + rv_op_vmacc_vv = 564, + rv_op_vmacc_vx = 565, + rv_op_vnmsac_vv = 566, + rv_op_vnmsac_vx = 567, + rv_op_vmadd_vv = 568, + rv_op_vmadd_vx = 569, + rv_op_vnmsub_vv = 570, + rv_op_vnmsub_vx = 571, + rv_op_vwmaccu_vv = 572, + rv_op_vwmaccu_vx = 573, + rv_op_vwmacc_vv = 574, + rv_op_vwmacc_vx = 575, + rv_op_vwmaccsu_vv = 576, + rv_op_vwmaccsu_vx = 577, + rv_op_vwmaccus_vx = 578, + rv_op_vmv_v_v = 579, + rv_op_vmv_v_x = 580, + rv_op_vmv_v_i = 581, + rv_op_vmerge_vvm = 582, + rv_op_vmerge_vxm = 583, + rv_op_vmerge_vim = 584, + rv_op_vsaddu_vv = 585, + rv_op_vsaddu_vx = 586, + rv_op_vsaddu_vi = 587, + rv_op_vsadd_vv = 588, + rv_op_vsadd_vx = 589, + rv_op_vsadd_vi = 590, + rv_op_vssubu_vv = 591, + rv_op_vssubu_vx = 592, + rv_op_vssub_vv = 593, + rv_op_vssub_vx = 594, + rv_op_vaadd_vv = 595, + rv_op_vaadd_vx = 596, + rv_op_vaaddu_vv = 597, + rv_op_vaaddu_vx = 598, + rv_op_vasub_vv = 599, + rv_op_vasub_vx = 600, + rv_op_vasubu_vv = 601, + rv_op_vasubu_vx = 602, + rv_op_vsmul_vv = 603, + rv_op_vsmul_vx = 604, + rv_op_vssrl_vv = 605, + rv_op_vssrl_vx = 606, + rv_op_vssrl_vi = 607, + rv_op_vssra_vv = 608, + rv_op_vssra_vx = 609, + rv_op_vssra_vi = 610, + rv_op_vnclipu_wv = 611, + rv_op_vnclipu_wx = 612, + rv_op_vnclipu_wi = 613, + rv_op_vnclip_wv = 614, + rv_op_vnclip_wx = 615, + rv_op_vnclip_wi = 616, + rv_op_vfadd_vv = 617, + rv_op_vfadd_vf = 618, + rv_op_vfsub_vv = 619, + rv_op_vfsub_vf = 620, + rv_op_vfrsub_vf = 621, + rv_op_vfwadd_vv = 622, + rv_op_vfwadd_vf = 623, + rv_op_vfwadd_wv = 624, + rv_op_vfwadd_wf = 625, + rv_op_vfwsub_vv = 626, + rv_op_vfwsub_vf = 627, + rv_op_vfwsub_wv = 628, + rv_op_vfwsub_wf = 629, + rv_op_vfmul_vv = 630, + rv_op_vfmul_vf = 631, + rv_op_vfdiv_vv = 632, + rv_op_vfdiv_vf = 633, + rv_op_vfrdiv_vf = 634, + rv_op_vfwmul_vv = 635, + rv_op_vfwmul_vf = 636, + rv_op_vfmacc_vv = 637, + rv_op_vfmacc_vf = 638, + rv_op_vfnmacc_vv = 639, + rv_op_vfnmacc_vf = 640, + rv_op_vfmsac_vv = 641, + rv_op_vfmsac_vf = 642, + rv_op_vfnmsac_vv = 643, + rv_op_vfnmsac_vf = 644, + rv_op_vfmadd_vv = 645, + rv_op_vfmadd_vf = 646, + rv_op_vfnmadd_vv = 647, + rv_op_vfnmadd_vf = 648, + rv_op_vfmsub_vv = 649, + rv_op_vfmsub_vf = 650, + rv_op_vfnmsub_vv = 651, + rv_op_vfnmsub_vf = 652, + rv_op_vfwmacc_vv = 653, + rv_op_vfwmacc_vf = 654, + rv_op_vfwnmacc_vv = 655, + rv_op_vfwnmacc_vf = 656, + rv_op_vfwmsac_vv = 657, + rv_op_vfwmsac_vf = 658, + rv_op_vfwnmsac_vv = 659, + rv_op_vfwnmsac_vf = 660, + rv_op_vfsqrt_v = 661, + rv_op_vfrsqrt7_v = 662, + rv_op_vfrec7_v = 663, + rv_op_vfmin_vv = 664, + rv_op_vfmin_vf = 665, + rv_op_vfmax_vv = 666, + rv_op_vfmax_vf = 667, + rv_op_vfsgnj_vv = 668, + rv_op_vfsgnj_vf = 669, + rv_op_vfsgnjn_vv = 670, + rv_op_vfsgnjn_vf = 671, + rv_op_vfsgnjx_vv = 672, + rv_op_vfsgnjx_vf = 673, + rv_op_vfslide1up_vf = 674, + rv_op_vfslide1down_vf = 675, + rv_op_vmfeq_vv = 676, + rv_op_vmfeq_vf = 677, + rv_op_vmfne_vv = 678, + rv_op_vmfne_vf = 679, + rv_op_vmflt_vv = 680, + rv_op_vmflt_vf = 681, + rv_op_vmfle_vv = 682, + rv_op_vmfle_vf = 683, + rv_op_vmfgt_vf = 684, + rv_op_vmfge_vf = 685, + rv_op_vfclass_v = 686, + rv_op_vfmerge_vfm = 687, + rv_op_vfmv_v_f = 688, + rv_op_vfcvt_xu_f_v = 689, + rv_op_vfcvt_x_f_v = 690, + rv_op_vfcvt_f_xu_v = 691, + rv_op_vfcvt_f_x_v = 692, + rv_op_vfcvt_rtz_xu_f_v = 693, + rv_op_vfcvt_rtz_x_f_v = 694, + rv_op_vfwcvt_xu_f_v = 695, + rv_op_vfwcvt_x_f_v = 696, + rv_op_vfwcvt_f_xu_v = 697, + rv_op_vfwcvt_f_x_v = 698, + rv_op_vfwcvt_f_f_v = 699, + rv_op_vfwcvt_rtz_xu_f_v = 700, + rv_op_vfwcvt_rtz_x_f_v = 701, + rv_op_vfncvt_xu_f_w = 702, + rv_op_vfncvt_x_f_w = 703, + rv_op_vfncvt_f_xu_w = 704, + rv_op_vfncvt_f_x_w = 705, + rv_op_vfncvt_f_f_w = 706, + rv_op_vfncvt_rod_f_f_w = 707, + rv_op_vfncvt_rtz_xu_f_w = 708, + rv_op_vfncvt_rtz_x_f_w = 709, + rv_op_vredsum_vs = 710, + rv_op_vredand_vs = 711, + rv_op_vredor_vs = 712, + rv_op_vredxor_vs = 713, + rv_op_vredminu_vs = 714, + rv_op_vredmin_vs = 715, + rv_op_vredmaxu_vs = 716, + rv_op_vredmax_vs = 717, + rv_op_vwredsumu_vs = 718, + rv_op_vwredsum_vs = 719, + rv_op_vfredusum_vs = 720, + rv_op_vfredosum_vs = 721, + rv_op_vfredmin_vs = 722, + rv_op_vfredmax_vs = 723, + rv_op_vfwredusum_vs = 724, + rv_op_vfwredosum_vs = 725, + rv_op_vmand_mm = 726, + rv_op_vmnand_mm = 727, + rv_op_vmandn_mm = 728, + rv_op_vmxor_mm = 729, + rv_op_vmor_mm = 730, + rv_op_vmnor_mm = 731, + rv_op_vmorn_mm = 732, + rv_op_vmxnor_mm = 733, + rv_op_vcpop_m = 734, + rv_op_vfirst_m = 735, + rv_op_vmsbf_m = 736, + rv_op_vmsif_m = 737, + rv_op_vmsof_m = 738, + rv_op_viota_m = 739, + rv_op_vid_v = 740, + rv_op_vmv_x_s = 741, + rv_op_vmv_s_x = 742, + rv_op_vfmv_f_s = 743, + rv_op_vfmv_s_f = 744, + rv_op_vslideup_vx = 745, + rv_op_vslideup_vi = 746, + rv_op_vslide1up_vx = 747, + rv_op_vslidedown_vx = 748, + rv_op_vslidedown_vi = 749, + rv_op_vslide1down_vx = 750, + rv_op_vrgather_vv = 751, + rv_op_vrgatherei16_vv = 752, + rv_op_vrgather_vx = 753, + rv_op_vrgather_vi = 754, + rv_op_vcompress_vm = 755, + rv_op_vmv1r_v = 756, + rv_op_vmv2r_v = 757, + rv_op_vmv4r_v = 758, + rv_op_vmv8r_v = 759, + rv_op_vzext_vf2 = 760, + rv_op_vzext_vf4 = 761, + rv_op_vzext_vf8 = 762, + rv_op_vsext_vf2 = 763, + rv_op_vsext_vf4 = 764, + rv_op_vsext_vf8 = 765, + rv_op_vsetvli = 766, + rv_op_vsetivli = 767, + rv_op_vsetvl = 768, } rv_op; /* structures */ @@ -540,6 +954,10 @@ typedef struct { uint8_t succ; uint8_t aq; uint8_t rl; + uint8_t bs; + uint8_t rnum; + uint8_t vm; + uint32_t vzimm; } rv_decode; typedef struct { @@ -578,6 +996,13 @@ static const char rv_freg_name_sym[32][5] = { "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11", }; +static const char rv_vreg_name_sym[32][4] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" +}; + /* instruction formats */ #define rv_fmt_none "O\t" @@ -615,6 +1040,36 @@ static const char rv_freg_name_sym[32][5] = { #define rv_fmt_rd_rs2 "O\t0,2" #define rv_fmt_rs1_offset "O\t1,o" #define rv_fmt_rs2_offset "O\t2,o" +#define rv_fmt_rs1_rs2_bs "O\t1,2,b" +#define rv_fmt_rd_rs1_rnum "O\t0,1,n" +#define rv_fmt_ldst_vd_rs1_vm "O\tD,(1)m" +#define rv_fmt_ldst_vd_rs1_rs2_vm "O\tD,(1),2m" +#define rv_fmt_ldst_vd_rs1_vs2_vm "O\tD,(1),Fm" +#define rv_fmt_vd_vs2_vs1 "O\tD,F,E" +#define rv_fmt_vd_vs2_vs1_vl "O\tD,F,El" +#define rv_fmt_vd_vs2_vs1_vm "O\tD,F,Em" +#define rv_fmt_vd_vs2_rs1_vl "O\tD,F,1l" +#define rv_fmt_vd_vs2_fs1_vl "O\tD,F,4l" +#define rv_fmt_vd_vs2_rs1_vm "O\tD,F,1m" +#define rv_fmt_vd_vs2_fs1_vm "O\tD,F,4m" +#define rv_fmt_vd_vs2_imm_vl "O\tD,F,il" +#define rv_fmt_vd_vs2_imm_vm "O\tD,F,im" +#define rv_fmt_vd_vs2_uimm_vm "O\tD,F,um" +#define rv_fmt_vd_vs1_vs2_vm "O\tD,E,Fm" +#define rv_fmt_vd_rs1_vs2_vm "O\tD,1,Fm" +#define rv_fmt_vd_fs1_vs2_vm "O\tD,4,Fm" +#define rv_fmt_vd_vs1 "O\tD,E" +#define rv_fmt_vd_rs1 "O\tD,1" +#define rv_fmt_vd_fs1 "O\tD,4" +#define rv_fmt_vd_imm "O\tD,i" +#define rv_fmt_vd_vs2 "O\tD,F" +#define rv_fmt_vd_vs2_vm "O\tD,Fm" +#define rv_fmt_rd_vs2_vm "O\t0,Fm" +#define rv_fmt_rd_vs2 "O\t0,F" +#define rv_fmt_fd_vs2 "O\t3,F" +#define rv_fmt_vd_vm "O\tDm" +#define rv_fmt_vsetvli "O\t0,1,v" +#define rv_fmt_vsetivli "O\t0,u,v" /* pseudo-instruction constraints */ @@ -766,6 +1221,7 @@ static const rv_comp_data rvcp_csrrw[] = { { rv_op_illegal, NULL } }; + static const rv_comp_data rvcp_csrrs[] = { { rv_op_rdcycle, rvcc_rdcycle }, { rv_op_rdtime, rvcc_rdtime }, @@ -1203,6 +1659,413 @@ const rv_opcode_data opcode_data[] = { { "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "binv", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "bext", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, + { "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, + { "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, + { "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, + { "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum, NULL, 0, 0, 0 }, + { "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "aes64im", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha256sig0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "sha256sig1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "sha256sum0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "sha256sum1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "sha512sig0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sig0h", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sha512sig1h", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "sm3p0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "sm3p1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "sm4ed", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, + { "sm4ks", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, + { "brev8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "pack", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "packh", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "packw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "unzip", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "zip", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "xperm8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle8_v, rv_op_vle8_v, 0 }, + { "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle16_v, rv_op_vle16_v, 0 }, + { "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle32_v, rv_op_vle32_v, 0 }, + { "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle64_v, rv_op_vle64_v, 0 }, + { "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vse8_v, rv_op_vse8_v, 0 }, + { "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vse16_v, rv_op_vse16_v, 0 }, + { "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vse32_v, rv_op_vse32_v, 0 }, + { "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vse64_v, rv_op_vse64_v, 0 }, + { "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vlm_v, rv_op_vlm_v, 0 }, + { "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vsm_v, rv_op_vsm_v, 0 }, + { "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vlse8_v, rv_op_vlse8_v, 0 }, + { "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vlse16_v, rv_op_vlse16_v, 0 }, + { "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vlse32_v, rv_op_vlse32_v, 0 }, + { "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vlse64_v, rv_op_vlse64_v, 0 }, + { "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vsse8_v, rv_op_vsse8_v, 0 }, + { "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vsse16_v, rv_op_vsse16_v, 0 }, + { "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vsse32_v, rv_op_vsse32_v, 0 }, + { "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, rv_op_vsse64_v, rv_op_vsse64_v, 0 }, + { "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vluxei8_v, rv_op_vluxei8_v, 0 }, + { "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vluxei16_v, rv_op_vluxei16_v, 0 }, + { "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vluxei32_v, rv_op_vluxei32_v, 0 }, + { "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vluxei64_v, rv_op_vluxei64_v, 0 }, + { "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vloxei8_v, rv_op_vloxei8_v, 0 }, + { "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vloxei16_v, rv_op_vloxei16_v, 0 }, + { "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vloxei32_v, rv_op_vloxei32_v, 0 }, + { "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vloxei64_v, rv_op_vloxei64_v, 0 }, + { "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsuxei8_v, rv_op_vsuxei8_v, 0 }, + { "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsuxei16_v, rv_op_vsuxei16_v, 0 }, + { "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsuxei32_v, rv_op_vsuxei32_v, 0 }, + { "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsuxei64_v, rv_op_vsuxei64_v, 0 }, + { "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsoxei8_v, rv_op_vsoxei8_v, 0 }, + { "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsoxei16_v, rv_op_vsoxei16_v, 0 }, + { "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsoxei32_v, rv_op_vsoxei32_v, 0 }, + { "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, rv_op_vsoxei64_v, rv_op_vsoxei64_v, 0 }, + { "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle8ff_v, rv_op_vle8ff_v, 0 }, + { "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle16ff_v, rv_op_vle16ff_v, 0 }, + { "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle32ff_v, rv_op_vle32ff_v, 0 }, + { "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vle64ff_v, rv_op_vle64ff_v, 0 }, + { "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl1re8_v, rv_op_vl1re8_v, 0 }, + { "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl1re16_v, rv_op_vl1re16_v, 0 }, + { "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl1re32_v, rv_op_vl1re32_v, 0 }, + { "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl1re64_v, rv_op_vl1re64_v, 0 }, + { "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl2re8_v, rv_op_vl2re8_v, 0 }, + { "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl2re16_v, rv_op_vl2re16_v, 0 }, + { "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl2re32_v, rv_op_vl2re32_v, 0 }, + { "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl2re64_v, rv_op_vl2re64_v, 0 }, + { "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl4re8_v, rv_op_vl4re8_v, 0 }, + { "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl4re16_v, rv_op_vl4re16_v, 0 }, + { "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl4re32_v, rv_op_vl4re32_v, 0 }, + { "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl4re64_v, rv_op_vl4re64_v, 0 }, + { "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl8re8_v, rv_op_vl8re8_v, 0 }, + { "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl8re16_v, rv_op_vl8re16_v, 0 }, + { "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl8re32_v, rv_op_vl8re32_v, 0 }, + { "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vl8re64_v, rv_op_vl8re64_v, 0 }, + { "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vs1r_v, rv_op_vs1r_v, 0 }, + { "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vs2r_v, rv_op_vs2r_v, 0 }, + { "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vs4r_v, rv_op_vs4r_v, 0 }, + { "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, rv_op_vs8r_v, rv_op_vs8r_v, 0 }, + { "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vadd_vv, rv_op_vadd_vv, 0 }, + { "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vadd_vx, rv_op_vadd_vx, 0 }, + { "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vadd_vi, rv_op_vadd_vi, 0 }, + { "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsub_vv, rv_op_vsub_vv, 0 }, + { "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsub_vx, rv_op_vsub_vx, 0 }, + { "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vrsub_vx, rv_op_vrsub_vx, 0 }, + { "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vrsub_vi, rv_op_vrsub_vi, 0 }, + { "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwaddu_vv, rv_op_vwaddu_vv, 0 }, + { "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwaddu_vx, rv_op_vwaddu_vx, 0 }, + { "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwadd_vv, rv_op_vwadd_vv, 0 }, + { "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwadd_vx, rv_op_vwadd_vx, 0 }, + { "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwsubu_vv, rv_op_vwsubu_vv, 0 }, + { "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwsubu_vx, rv_op_vwsubu_vx, 0 }, + { "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwsub_vv, rv_op_vwsub_vv, 0 }, + { "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwsub_vx, rv_op_vwsub_vx, 0 }, + { "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwaddu_wv, rv_op_vwaddu_wv, 0 }, + { "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwaddu_wx, rv_op_vwaddu_wx, 0 }, + { "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwadd_wv, rv_op_vwadd_wv, 0 }, + { "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwadd_wx, rv_op_vwadd_wx, 0 }, + { "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwsubu_wv, rv_op_vwsubu_wv, 0 }, + { "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwsubu_wx, rv_op_vwsubu_wx, 0 }, + { "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwsub_wv, rv_op_vwsub_wv, 0 }, + { "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwsub_wx, rv_op_vwsub_wx, 0 }, + { "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, rv_op_vadc_vvm, rv_op_vadc_vvm, 0 }, + { "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, rv_op_vadc_vxm, rv_op_vadc_vxm, 0 }, + { "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl, NULL, rv_op_vadc_vim, rv_op_vadc_vim, 0 }, + { "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, rv_op_vmadc_vvm, rv_op_vmadc_vvm, 0 }, + { "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, rv_op_vmadc_vxm, rv_op_vmadc_vxm, 0 }, + { "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl, NULL, rv_op_vmadc_vim, rv_op_vmadc_vim, 0 }, + { "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, rv_op_vsbc_vvm, rv_op_vsbc_vvm, 0 }, + { "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, rv_op_vsbc_vxm, rv_op_vsbc_vxm, 0 }, + { "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, rv_op_vmsbc_vvm, rv_op_vmsbc_vvm, 0 }, + { "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, rv_op_vmsbc_vxm, rv_op_vmsbc_vxm, 0 }, + { "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vand_vv, rv_op_vand_vv, 0 }, + { "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vand_vx, rv_op_vand_vx, 0 }, + { "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vand_vi, rv_op_vand_vi, 0 }, + { "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vor_vv, rv_op_vor_vv, 0 }, + { "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vor_vx, rv_op_vor_vx, 0 }, + { "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vor_vi, rv_op_vor_vi, 0 }, + { "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vxor_vv, rv_op_vxor_vv, 0 }, + { "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vxor_vx, rv_op_vxor_vx, 0 }, + { "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vxor_vi, rv_op_vxor_vi, 0 }, + { "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsll_vv, rv_op_vsll_vv, 0 }, + { "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsll_vx, rv_op_vsll_vx, 0 }, + { "vsll.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vsll_vi, rv_op_vsll_vi, 0 }, + { "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsrl_vv, rv_op_vsrl_vv, 0 }, + { "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsrl_vx, rv_op_vsrl_vx, 0 }, + { "vsrl.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vsrl_vi, rv_op_vsrl_vi, 0 }, + { "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsra_vv, rv_op_vsra_vv, 0 }, + { "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsra_vx, rv_op_vsra_vx, 0 }, + { "vsra.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vsra_vi, rv_op_vsra_vi, 0 }, + { "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vnsrl_wv, rv_op_vnsrl_wv, 0 }, + { "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vnsrl_wx, rv_op_vnsrl_wx, 0 }, + { "vnsrl.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vnsrl_wi, rv_op_vnsrl_wi, 0 }, + { "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vnsra_wv, rv_op_vnsra_wv, 0 }, + { "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vnsra_wx, rv_op_vnsra_wx, 0 }, + { "vnsra.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vnsra_wi, rv_op_vnsra_wi, 0 }, + { "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmseq_vv, rv_op_vmseq_vv, 0 }, + { "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmseq_vx, rv_op_vmseq_vx, 0 }, + { "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vmseq_vi, rv_op_vmseq_vi, 0 }, + { "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmsne_vv, rv_op_vmsne_vv, 0 }, + { "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmsne_vx, rv_op_vmsne_vx, 0 }, + { "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vmsne_vi, rv_op_vmsne_vi, 0 }, + { "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmsltu_vv, rv_op_vmsltu_vv, 0 }, + { "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmsltu_vx, rv_op_vmsltu_vx, 0 }, + { "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmslt_vv, rv_op_vmslt_vv, 0 }, + { "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmslt_vx, rv_op_vmslt_vx, 0 }, + { "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmsleu_vv, rv_op_vmsleu_vv, 0 }, + { "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmsleu_vx, rv_op_vmsleu_vx, 0 }, + { "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vmsleu_vi, rv_op_vmsleu_vi, 0 }, + { "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmsle_vv, rv_op_vmsle_vv, 0 }, + { "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmsle_vx, rv_op_vmsle_vx, 0 }, + { "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vmsle_vi, rv_op_vmsle_vi, 0 }, + { "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmsgtu_vx, rv_op_vmsgtu_vx, 0 }, + { "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vmsgtu_vi, rv_op_vmsgtu_vi, 0 }, + { "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmsgt_vx, rv_op_vmsgt_vx, 0 }, + { "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vmsgt_vi, rv_op_vmsgt_vi, 0 }, + { "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vminu_vv, rv_op_vminu_vv, 0 }, + { "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vminu_vx, rv_op_vminu_vx, 0 }, + { "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmin_vv, rv_op_vmin_vv, 0 }, + { "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmin_vx, rv_op_vmin_vx, 0 }, + { "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmaxu_vv, rv_op_vmaxu_vv, 0 }, + { "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmaxu_vx, rv_op_vmaxu_vx, 0 }, + { "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmax_vv, rv_op_vmax_vv, 0 }, + { "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmax_vx, rv_op_vmax_vx, 0 }, + { "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmul_vv, rv_op_vmul_vv, 0 }, + { "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmul_vx, rv_op_vmul_vx, 0 }, + { "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmulh_vv, rv_op_vmulh_vv, 0 }, + { "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmulh_vx, rv_op_vmulh_vx, 0 }, + { "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmulhu_vv, rv_op_vmulhu_vv, 0 }, + { "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmulhu_vx, rv_op_vmulhu_vx, 0 }, + { "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmulhsu_vv, rv_op_vmulhsu_vv, 0 }, + { "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vmulhsu_vx, rv_op_vmulhsu_vx, 0 }, + { "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vdivu_vv, rv_op_vdivu_vv, 0 }, + { "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vdivu_vx, rv_op_vdivu_vx, 0 }, + { "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vdiv_vv, rv_op_vdiv_vv, 0 }, + { "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vdiv_vx, rv_op_vdiv_vx, 0 }, + { "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vremu_vv, rv_op_vremu_vv, 0 }, + { "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vremu_vx, rv_op_vremu_vx, 0 }, + { "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vrem_vv, rv_op_vrem_vv, 0 }, + { "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vrem_vx, rv_op_vrem_vx, 0 }, + { "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwmulu_vv, rv_op_vwmulu_vv, 0 }, + { "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwmulu_vx, rv_op_vwmulu_vx, 0 }, + { "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwmulsu_vv, rv_op_vwmulsu_vv, 0 }, + { "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwmulsu_vx, rv_op_vwmulsu_vx, 0 }, + { "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwmul_vv, rv_op_vwmul_vv, 0 }, + { "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vwmul_vx, rv_op_vwmul_vx, 0 }, + { "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vmacc_vv, rv_op_vmacc_vv, 0 }, + { "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vmacc_vx, rv_op_vmacc_vx, 0 }, + { "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vnmsac_vv, rv_op_vnmsac_vv, 0 }, + { "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vnmsac_vx, rv_op_vnmsac_vx, 0 }, + { "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vmadd_vv, rv_op_vmadd_vv, 0 }, + { "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vmadd_vx, rv_op_vmadd_vx, 0 }, + { "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vnmsub_vv, rv_op_vnmsub_vv, 0 }, + { "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vnmsub_vx, rv_op_vnmsub_vx, 0 }, + { "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vwmaccu_vv, rv_op_vwmaccu_vv, 0 }, + { "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vwmaccu_vx, rv_op_vwmaccu_vx, 0 }, + { "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vwmacc_vv, rv_op_vwmacc_vv, 0 }, + { "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vwmacc_vx, rv_op_vwmacc_vx, 0 }, + { "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vwmaccsu_vv, rv_op_vwmaccsu_vv, 0 }, + { "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vwmaccsu_vx, rv_op_vwmaccsu_vx, 0 }, + { "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, rv_op_vwmaccus_vx, rv_op_vwmaccus_vx, 0 }, + { "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1, NULL, rv_op_vmv_v_v, rv_op_vmv_v_v, 0 }, + { "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1, NULL, rv_op_vmv_v_x, rv_op_vmv_v_x, 0 }, + { "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm, NULL, rv_op_vmv_v_i, rv_op_vmv_v_i, 0 }, + { "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, rv_op_vmerge_vvm, rv_op_vmerge_vvm, 0 }, + { "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, rv_op_vmerge_vxm, rv_op_vmerge_vxm, 0 }, + { "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl, NULL, rv_op_vmerge_vim, rv_op_vmerge_vim, 0 }, + { "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsaddu_vv, rv_op_vsaddu_vv, 0 }, + { "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsaddu_vx, rv_op_vsaddu_vx, 0 }, + { "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vsaddu_vi, rv_op_vsaddu_vi, 0 }, + { "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsadd_vv, rv_op_vsadd_vv, 0 }, + { "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsadd_vx, rv_op_vsadd_vx, 0 }, + { "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, rv_op_vsadd_vi, rv_op_vsadd_vi, 0 }, + { "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vssubu_vv, rv_op_vssubu_vv, 0 }, + { "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vssubu_vx, rv_op_vssubu_vx, 0 }, + { "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vssub_vv, rv_op_vssub_vv, 0 }, + { "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vssub_vx, rv_op_vssub_vx, 0 }, + { "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vaadd_vv, rv_op_vaadd_vv, 0 }, + { "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vaadd_vx, rv_op_vaadd_vx, 0 }, + { "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vaaddu_vv, rv_op_vaaddu_vv, 0 }, + { "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vaaddu_vx, rv_op_vaaddu_vx, 0 }, + { "vasub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vasub_vv, rv_op_vasub_vv, 0 }, + { "vasub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vasub_vx, rv_op_vasub_vx, 0 }, + { "vasubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vasubu_vv, rv_op_vasubu_vv, 0 }, + { "vasubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vasubu_vx, rv_op_vasubu_vx, 0 }, + { "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vsmul_vv, rv_op_vsmul_vv, 0 }, + { "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vsmul_vx, rv_op_vsmul_vx, 0 }, + { "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vssrl_vv, rv_op_vssrl_vv, 0 }, + { "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vssrl_vx, rv_op_vssrl_vx, 0 }, + { "vssrl.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vssrl_vi, rv_op_vssrl_vi, 0 }, + { "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vssra_vv, rv_op_vssra_vv, 0 }, + { "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vssra_vx, rv_op_vssra_vx, 0 }, + { "vssra.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vssra_vi, rv_op_vssra_vi, 0 }, + { "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vnclipu_wv, rv_op_vnclipu_wv, 0 }, + { "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vnclipu_wx, rv_op_vnclipu_wx, 0 }, + { "vnclipu.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vnclipu_wi, rv_op_vnclipu_wi, 0 }, + { "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vnclip_wv, rv_op_vnclip_wv, 0 }, + { "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vnclip_wx, rv_op_vnclip_wx, 0 }, + { "vnclip.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vnclip_wi, rv_op_vnclip_wi, 0 }, + { "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfadd_vv, rv_op_vfadd_vv, 0 }, + { "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfadd_vf, rv_op_vfadd_vf, 0 }, + { "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfsub_vv, rv_op_vfsub_vv, 0 }, + { "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfsub_vf, rv_op_vfsub_vf, 0 }, + { "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfrsub_vf, rv_op_vfrsub_vf, 0 }, + { "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwadd_vv, rv_op_vfwadd_vv, 0 }, + { "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfwadd_vf, rv_op_vfwadd_vf, 0 }, + { "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwadd_wv, rv_op_vfwadd_wv, 0 }, + { "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfwadd_wf, rv_op_vfwadd_wf, 0 }, + { "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwsub_vv, rv_op_vfwsub_vv, 0 }, + { "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfwsub_vf, rv_op_vfwsub_vf, 0 }, + { "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwsub_wv, rv_op_vfwsub_wv, 0 }, + { "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfwsub_wf, rv_op_vfwsub_wf, 0 }, + { "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfmul_vv, rv_op_vfmul_vv, 0 }, + { "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfmul_vf, rv_op_vfmul_vf, 0 }, + { "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfdiv_vv, rv_op_vfdiv_vv, 0 }, + { "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfdiv_vf, rv_op_vfdiv_vf, 0 }, + { "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfrdiv_vf, rv_op_vfrdiv_vf, 0 }, + { "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwmul_vv, rv_op_vfwmul_vv, 0 }, + { "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfwmul_vf, rv_op_vfwmul_vf, 0 }, + { "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfmacc_vv, rv_op_vfmacc_vv, 0 }, + { "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfmacc_vf, rv_op_vfmacc_vf, 0 }, + { "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfnmacc_vv, rv_op_vfnmacc_vv, 0 }, + { "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfnmacc_vf, rv_op_vfnmacc_vf, 0 }, + { "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfmsac_vv, rv_op_vfmsac_vv, 0 }, + { "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfmsac_vf, rv_op_vfmsac_vf, 0 }, + { "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfnmsac_vv, rv_op_vfnmsac_vv, 0 }, + { "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfnmsac_vf, rv_op_vfnmsac_vf, 0 }, + { "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfmadd_vv, rv_op_vfmadd_vv, 0 }, + { "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfmadd_vf, rv_op_vfmadd_vf, 0 }, + { "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfnmadd_vv, rv_op_vfnmadd_vv, 0 }, + { "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfnmadd_vf, rv_op_vfnmadd_vf, 0 }, + { "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfmsub_vv, rv_op_vfmsub_vv, 0 }, + { "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfmsub_vf, rv_op_vfmsub_vf, 0 }, + { "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfnmsub_vv, rv_op_vfnmsub_vv, 0 }, + { "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfnmsub_vf, rv_op_vfnmsub_vf, 0 }, + { "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfwmacc_vv, rv_op_vfwmacc_vv, 0 }, + { "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfwmacc_vf, rv_op_vfwmacc_vf, 0 }, + { "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfwnmacc_vv, rv_op_vfwnmacc_vv, 0 }, + { "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfwnmacc_vf, rv_op_vfwnmacc_vf, 0 }, + { "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfwmsac_vv, rv_op_vfwmsac_vv, 0 }, + { "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfwmsac_vf, rv_op_vfwmsac_vf, 0 }, + { "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, rv_op_vfwnmsac_vv, rv_op_vfwnmsac_vv, 0 }, + { "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, rv_op_vfwnmsac_vf, rv_op_vfwnmsac_vf, 0 }, + { "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vfsqrt_v, rv_op_vfsqrt_v, 0 }, + { "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vfrsqrt7_v, rv_op_vfrsqrt7_v, 0 }, + { "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vfrec7_v, rv_op_vfrec7_v, 0 }, + { "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfmin_vv, rv_op_vfmin_vv, 0 }, + { "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfmin_vf, rv_op_vfmin_vf, 0 }, + { "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfmax_vv, rv_op_vfmax_vv, 0 }, + { "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfmax_vf, rv_op_vfmax_vf, 0 }, + { "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfsgnj_vv, rv_op_vfsgnj_vv, 0 }, + { "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfsgnj_vf, rv_op_vfsgnj_vf, 0 }, + { "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfsgnjn_vv, rv_op_vfsgnjn_vv, 0 }, + { "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfsgnjn_vf, rv_op_vfsgnjn_vf, 0 }, + { "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfsgnjx_vv, rv_op_vfsgnjx_vv, 0 }, + { "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfsgnjx_vf, rv_op_vfsgnjx_vf, 0 }, + { "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfslide1up_vf, rv_op_vfslide1up_vf, 0 }, + { "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vfslide1down_vf, rv_op_vfslide1down_vf, 0 }, + { "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmfeq_vv, rv_op_vmfeq_vv, 0 }, + { "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vmfeq_vf, rv_op_vmfeq_vf, 0 }, + { "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmfne_vv, rv_op_vmfne_vv, 0 }, + { "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vmfne_vf, rv_op_vmfne_vf, 0 }, + { "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmflt_vv, rv_op_vmflt_vv, 0 }, + { "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vmflt_vf, rv_op_vmflt_vf, 0 }, + { "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmfle_vv, rv_op_vmfle_vv, 0 }, + { "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vmfle_vf, rv_op_vmfle_vf, 0 }, + { "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vmfgt_vf, rv_op_vmfgt_vf, 0 }, + { "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, rv_op_vmfge_vf, rv_op_vmfge_vf, 0 }, + { "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfclass_v, rv_op_vfclass_v, 0 }, + { "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl, NULL, rv_op_vfmerge_vfm, rv_op_vfmerge_vfm, 0 }, + { "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1, NULL, rv_op_vfmv_v_f, rv_op_vfmv_v_f, 0 }, + { "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfcvt_xu_f_v, rv_op_vfcvt_xu_f_v, 0 }, + { "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfcvt_x_f_v, rv_op_vfcvt_x_f_v, 0 }, + { "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfcvt_f_xu_v, rv_op_vfcvt_f_xu_v, 0 }, + { "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfcvt_f_x_v, rv_op_vfcvt_f_x_v, 0 }, + { "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfcvt_rtz_xu_f_v, rv_op_vfcvt_rtz_xu_f_v, 0 }, + { "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfcvt_rtz_x_f_v, rv_op_vfcvt_rtz_x_f_v, 0 }, + { "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_xu_f_v, rv_op_vfwcvt_xu_f_v, 0 }, + { "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_x_f_v, rv_op_vfwcvt_x_f_v, 0 }, + { "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_f_xu_v, rv_op_vfwcvt_f_xu_v, 0 }, + { "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_f_x_v, rv_op_vfwcvt_f_x_v, 0 }, + { "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_f_f_v, rv_op_vfwcvt_f_f_v, 0 }, + { "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_rtz_xu_f_v, rv_op_vfwcvt_rtz_xu_f_v, 0 }, + { "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfwcvt_rtz_x_f_v, rv_op_vfwcvt_rtz_x_f_v, 0 }, + { "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_xu_f_w, rv_op_vfncvt_xu_f_w, 0 }, + { "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_x_f_w, rv_op_vfncvt_x_f_w, 0 }, + { "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_f_xu_w, rv_op_vfncvt_f_xu_w, 0 }, + { "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_f_x_w, rv_op_vfncvt_f_x_w, 0 }, + { "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_f_f_w, rv_op_vfncvt_f_f_w, 0 }, + { "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_rod_f_f_w, rv_op_vfncvt_rod_f_f_w, 0 }, + { "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_rtz_xu_f_w, rv_op_vfncvt_rtz_xu_f_w, 0 }, + { "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vfncvt_rtz_x_f_w, rv_op_vfncvt_rtz_x_f_w, 0 }, + { "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredsum_vs, rv_op_vredsum_vs, 0 }, + { "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredand_vs, rv_op_vredand_vs, 0 }, + { "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredor_vs, rv_op_vredor_vs, 0 }, + { "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredxor_vs, rv_op_vredxor_vs, 0 }, + { "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredminu_vs, rv_op_vredminu_vs, 0 }, + { "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredmin_vs, rv_op_vredmin_vs, 0 }, + { "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredmaxu_vs, rv_op_vredmaxu_vs, 0 }, + { "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vredmax_vs, rv_op_vredmax_vs, 0 }, + { "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwredsumu_vs, rv_op_vwredsumu_vs, 0 }, + { "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vwredsum_vs, rv_op_vwredsum_vs, 0 }, + { "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfredusum_vs, rv_op_vfredusum_vs, 0 }, + { "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfredosum_vs, rv_op_vfredosum_vs, 0 }, + { "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfredmin_vs, rv_op_vfredmin_vs, 0 }, + { "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfredmax_vs, rv_op_vfredmax_vs, 0 }, + { "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwredusum_vs, rv_op_vfwredusum_vs, 0 }, + { "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vfwredosum_vs, rv_op_vfwredosum_vs, 0 }, + { "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmand_mm, rv_op_vmand_mm, 0 }, + { "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmnand_mm, rv_op_vmnand_mm, 0 }, + { "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmandn_mm, rv_op_vmandn_mm, 0 }, + { "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmxor_mm, rv_op_vmxor_mm, 0 }, + { "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmor_mm, rv_op_vmor_mm, 0 }, + { "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmnor_mm, rv_op_vmnor_mm, 0 }, + { "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmorn_mm, rv_op_vmorn_mm, 0 }, + { "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vmxnor_mm, rv_op_vmxnor_mm, 0 }, + { "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm, NULL, rv_op_vcpop_m, rv_op_vcpop_m, 0 }, + { "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm, NULL, rv_op_vfirst_m, rv_op_vfirst_m, 0 }, + { "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vmsbf_m, rv_op_vmsbf_m, 0 }, + { "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vmsif_m, rv_op_vmsif_m, 0 }, + { "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vmsof_m, rv_op_vmsof_m, 0 }, + { "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_viota_m, rv_op_viota_m, 0 }, + { "vid.v", rv_codec_v_r, rv_fmt_vd_vm, NULL, rv_op_vid_v, rv_op_vid_v, 0 }, + { "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2, NULL, rv_op_vmv_x_s, rv_op_vmv_x_s, 0 }, + { "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1, NULL, rv_op_vmv_s_x, rv_op_vmv_s_x, 0 }, + { "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2, NULL, rv_op_vfmv_f_s, rv_op_vfmv_f_s, 0 }, + { "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1, NULL, rv_op_vfmv_s_f, rv_op_vfmv_s_f, 0 }, + { "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vslideup_vx, rv_op_vslideup_vx, 0 }, + { "vslideup.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vslideup_vi, rv_op_vslideup_vi, 0 }, + { "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vslide1up_vx, rv_op_vslide1up_vx, 0 }, + { "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vslidedown_vx, rv_op_vslidedown_vx, 0 }, + { "vslidedown.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vslidedown_vi, rv_op_vslidedown_vi, 0 }, + { "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vslide1down_vx, rv_op_vslide1down_vx, 0 }, + { "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vrgather_vv, rv_op_vrgather_vv, 0 }, + { "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, rv_op_vrgatherei16_vv, rv_op_vrgatherei16_vv, 0 }, + { "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, rv_op_vrgather_vx, rv_op_vrgather_vx, 0 }, + { "vrgather.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, rv_op_vrgather_vi, rv_op_vrgather_vi, 0 }, + { "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, rv_op_vcompress_vm, rv_op_vcompress_vm, 0 }, + { "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vmv1r_v, rv_op_vmv1r_v, 0 }, + { "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vmv2r_v, rv_op_vmv2r_v, 0 }, + { "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vmv4r_v, rv_op_vmv4r_v, 0 }, + { "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, rv_op_vmv8r_v, rv_op_vmv8r_v, 0 }, + { "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vzext_vf2, rv_op_vzext_vf2, 0 }, + { "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vzext_vf4, rv_op_vzext_vf4, 0 }, + { "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vzext_vf8, rv_op_vzext_vf8, 0 }, + { "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vsext_vf2, rv_op_vsext_vf2, 0 }, + { "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vsext_vf4, rv_op_vsext_vf4, 0 }, + { "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, rv_op_vsext_vf8, rv_op_vsext_vf8, 0 }, + { "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli, NULL, rv_op_vsetvli, rv_op_vsetvli, 0 }, + { "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli, NULL, rv_op_vsetivli, rv_op_vsetivli, 0 }, + { "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, rv_op_vsetvl, rv_op_vsetvl, 0 } }; /* CSR names */ @@ -1216,14 +2079,17 @@ static const char *csr_name(int csrno) case 0x0003: return "fcsr"; case 0x0004: return "uie"; case 0x0005: return "utvec"; + case 0x0008: return "vstart"; + case 0x0009: return "vxsat"; + case 0x000a: return "vxrm"; + case 0x000f: return "vcsr"; + case 0x0015: return "seed"; case 0x0040: return "uscratch"; case 0x0041: return "uepc"; case 0x0042: return "ucause"; 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"; @@ -1389,6 +2255,9 @@ static const char *csr_name(int csrno) case 0x0c00: return "cycle"; case 0x0c01: return "time"; case 0x0c02: return "instret"; + case 0x0c20: return "vl"; + case 0x0c21: return "vtype"; + case 0x0c22: return "vlenb"; case 0x0c80: return "cycleh"; case 0x0c81: return "timeh"; case 0x0c82: return "instreth"; @@ -1576,9 +2445,86 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; case 1: switch (((inst >> 12) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b111111111111)) { + case 40: op = rv_op_vl1re8_v; break; + case 552: op = rv_op_vl2re8_v; break; + case 1576: op = rv_op_vl4re8_v; break; + case 3624: op = rv_op_vl8re8_v; break; + } + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vle8_v; break; + case 11: op = rv_op_vlm_v; break; + case 16: op = rv_op_vle8ff_v; break; + } + break; + case 1: op = rv_op_vluxei8_v; break; + case 2: op = rv_op_vlse8_v; break; + case 3: op = rv_op_vloxei8_v; break; + } + break; case 2: op = rv_op_flw; break; case 3: op = rv_op_fld; break; case 4: op = rv_op_flq; break; + case 5: + switch (((inst >> 20) & 0b111111111111)) { + case 40: op = rv_op_vl1re16_v; break; + case 552: op = rv_op_vl2re16_v; break; + case 1576: op = rv_op_vl4re16_v; break; + case 3624: op = rv_op_vl8re16_v; break; + } + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vle16_v; break; + case 16: op = rv_op_vle16ff_v; break; + } + break; + case 1: op = rv_op_vluxei16_v; break; + case 2: op = rv_op_vlse16_v; break; + case 3: op = rv_op_vloxei16_v; break; + } + break; + case 6: + switch (((inst >> 20) & 0b111111111111)) { + case 40: op = rv_op_vl1re32_v; break; + case 552: op = rv_op_vl2re32_v; break; + case 1576: op = rv_op_vl4re32_v; break; + case 3624: op = rv_op_vl8re32_v; break; + } + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vle32_v; break; + case 16: op = rv_op_vle32ff_v; break; + } + break; + case 1: op = rv_op_vluxei32_v; break; + case 2: op = rv_op_vlse32_v; break; + case 3: op = rv_op_vloxei32_v; break; + } + break; + case 7: + switch (((inst >> 20) & 0b111111111111)) { + case 40: op = rv_op_vl1re64_v; break; + case 552: op = rv_op_vl2re64_v; break; + case 1576: op = rv_op_vl4re64_v; break; + case 3624: op = rv_op_vl8re64_v; break; + } + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vle64_v; break; + case 16: op = rv_op_vle64ff_v; break; + } + break; + case 1: op = rv_op_vluxei64_v; break; + case 2: op = rv_op_vlse64_v; break; + case 3: op = rv_op_vloxei64_v; break; + } + break; } break; case 3: @@ -1594,7 +2540,36 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 1: switch (((inst >> 27) & 0b11111)) { case 0b00000: op = rv_op_slli; break; + case 0b00001: + switch (((inst >> 20) & 0b1111111)) { + case 0b0001111: op = rv_op_zip; break; + } + break; + case 0b00010: + switch (((inst >> 20) & 0b1111111)) { + case 0b0000000: op = rv_op_sha256sum0; break; + case 0b0000001: op = rv_op_sha256sum1; break; + case 0b0000010: op = rv_op_sha256sig0; break; + case 0b0000011: op = rv_op_sha256sig1; break; + case 0b0000100: op = rv_op_sha512sum0; break; + case 0b0000101: op = rv_op_sha512sum1; break; + case 0b0000110: op = rv_op_sha512sig0; break; + case 0b0000111: op = rv_op_sha512sig1; break; + case 0b0001000: op = rv_op_sm3p0; break; + case 0b0001001: op = rv_op_sm3p1; break; + } + break; case 0b00101: op = rv_op_bseti; break; + case 0b00110: + switch (((inst >> 20) & 0b1111111)) { + case 0b0000000: op = rv_op_aes64im; break; + default: + if (((inst >> 24) & 0b0111) == 0b001) { + op = rv_op_aes64ks1i; + } + break; + } + break; case 0b01001: op = rv_op_bclri; break; case 0b01101: op = rv_op_binvi; break; case 0b01100: @@ -1615,13 +2590,20 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 5: switch (((inst >> 27) & 0b11111)) { case 0b00000: op = rv_op_srli; break; + case 0b00001: + switch (((inst >> 20) & 0b1111111)) { + case 0b0001111: op = rv_op_unzip; break; + } + break; case 0b00101: op = rv_op_orc_b; break; case 0b01000: op = rv_op_srai; break; case 0b01001: op = rv_op_bexti; break; case 0b01100: op = rv_op_rori; break; case 0b01101: switch ((inst >> 20) & 0b1111111) { + case 0b0011000: op = rv_op_rev8; break; case 0b0111000: op = rv_op_rev8; break; + case 0b0000111: op = rv_op_brev8; break; } break; } @@ -1667,9 +2649,64 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; case 9: switch (((inst >> 12) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b111111111111)) { + case 40: op = rv_op_vs1r_v; break; + case 552: op = rv_op_vs2r_v; break; + case 1576: op = rv_op_vs4r_v; break; + case 3624: op = rv_op_vs8r_v; break; + } + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vse8_v; break; + case 11: op = rv_op_vsm_v; break; + } + break; + case 1: op = rv_op_vsuxei8_v; break; + case 2: op = rv_op_vsse8_v; break; + case 3: op = rv_op_vsoxei8_v; break; + } + break; case 2: op = rv_op_fsw; break; case 3: op = rv_op_fsd; break; case 4: op = rv_op_fsq; break; + case 5: + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vse16_v; break; + } + break; + case 1: op = rv_op_vsuxei16_v; break; + case 2: op = rv_op_vsse16_v; break; + case 3: op = rv_op_vsoxei16_v; break; + } + break; + case 6: + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vse32_v; break; + } + break; + case 1: op = rv_op_vsuxei32_v; break; + case 2: op = rv_op_vsse32_v; break; + case 3: op = rv_op_vsoxei32_v; break; + } + break; + case 7: + switch (((inst >> 26) & 0b111)) { + case 0: + switch (((inst >> 20) & 0b11111)) { + case 0: op = rv_op_vse64_v; break; + } + break; + case 1: op = rv_op_vsuxei64_v; break; + case 2: op = rv_op_vsse64_v; break; + case 3: op = rv_op_vsoxei64_v; break; + } + break; } break; case 11: @@ -1742,8 +2779,11 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 36: switch ((inst >> 20) & 0b11111) { case 0: op = rv_op_zext_h; break; + default: op = rv_op_pack; break; } break; + case 39: op = rv_op_packh; break; + case 41: op = rv_op_clmul; break; case 42: op = rv_op_clmulr; break; case 43: op = rv_op_clmulh; break; @@ -1755,6 +2795,12 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 132: op = rv_op_sh2add; break; case 134: op = rv_op_sh3add; break; case 161: op = rv_op_bset; break; + case 162: op = rv_op_xperm4; break; + case 164: op = rv_op_xperm8; break; + case 200: op = rv_op_aes64es; break; + case 216: op = rv_op_aes64esm; break; + case 232: op = rv_op_aes64ds; break; + case 248: op = rv_op_aes64dsm; break; case 256: op = rv_op_sub; break; case 260: op = rv_op_xnor; break; case 261: op = rv_op_sra; break; @@ -1762,9 +2808,24 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 263: op = rv_op_andn; break; case 289: op = rv_op_bclr; break; case 293: op = rv_op_bext; break; + case 320: op = rv_op_sha512sum0r; break; + case 328: op = rv_op_sha512sum1r; break; + case 336: op = rv_op_sha512sig0l; break; + case 344: op = rv_op_sha512sig1l; break; + case 368: op = rv_op_sha512sig0h; break; + case 376: op = rv_op_sha512sig1h; break; case 385: op = rv_op_rol; break; - case 386: op = rv_op_ror; break; + case 389: op = rv_op_ror; break; case 417: op = rv_op_binv; break; + case 504: op = rv_op_aes64ks2; break; + } + switch ((inst >> 25) & 0b0011111) { + case 17: op = rv_op_aes32esi; break; + case 19: op = rv_op_aes32esmi; break; + case 21: op = rv_op_aes32dsi; break; + case 23: op = rv_op_aes32dsmi; break; + case 24: op = rv_op_sm4ed; break; + case 26: op = rv_op_sm4ks; break; } break; case 13: op = rv_op_lui; break; @@ -1782,6 +2843,7 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 36: switch ((inst >> 20) & 0b11111) { case 0: op = rv_op_zext_h; break; + default: op = rv_op_packw; break; } break; case 130: op = rv_op_sh1add_uw; break; @@ -2011,6 +3073,408 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; } break; + case 21: + switch (((inst >> 12) & 0b111)) { + case 0: + switch (((inst >> 26) & 0b111111)) { + case 0: op = rv_op_vadd_vv; break; + case 2: op = rv_op_vsub_vv; break; + case 4: op = rv_op_vminu_vv; break; + case 5: op = rv_op_vmin_vv; break; + case 6: op = rv_op_vmaxu_vv; break; + case 7: op = rv_op_vmax_vv; break; + case 9: op = rv_op_vand_vv; break; + case 10: op = rv_op_vor_vv; break; + case 11: op = rv_op_vxor_vv; break; + case 12: op = rv_op_vrgather_vv; break; + case 14: op = rv_op_vrgatherei16_vv; break; + case 16: if (((inst >> 25) & 1) == 0) op = rv_op_vadc_vvm; break; + case 17: op = rv_op_vmadc_vvm; break; + case 18: if (((inst >> 25) & 1) == 0) op = rv_op_vsbc_vvm; break; + case 19: op = rv_op_vmsbc_vvm; break; + case 23: + if (((inst >> 20) & 0b111111) == 32) + op = rv_op_vmv_v_v; + else if (((inst >> 25) & 1) == 0) + op = rv_op_vmerge_vvm; + break; + case 24: op = rv_op_vmseq_vv; break; + case 25: op = rv_op_vmsne_vv; break; + case 26: op = rv_op_vmsltu_vv; break; + case 27: op = rv_op_vmslt_vv; break; + case 28: op = rv_op_vmsleu_vv; break; + case 29: op = rv_op_vmsle_vv; break; + case 32: op = rv_op_vsaddu_vv; break; + case 33: op = rv_op_vsadd_vv; break; + case 34: op = rv_op_vssubu_vv; break; + case 35: op = rv_op_vssub_vv; break; + case 37: op = rv_op_vsll_vv; break; + case 39: op = rv_op_vsmul_vv; break; + case 40: op = rv_op_vsrl_vv; break; + case 41: op = rv_op_vsra_vv; break; + case 42: op = rv_op_vssrl_vv; break; + case 43: op = rv_op_vssra_vv; break; + case 44: op = rv_op_vnsrl_wv; break; + case 45: op = rv_op_vnsra_wv; break; + case 46: op = rv_op_vnclipu_wv; break; + case 47: op = rv_op_vnclip_wv; break; + case 48: op = rv_op_vwredsumu_vs; break; + case 49: op = rv_op_vwredsum_vs; break; + } + break; + case 1: + switch (((inst >> 26) & 0b111111)) { + case 0: op = rv_op_vfadd_vv; break; + case 1: op = rv_op_vfredusum_vs; break; + case 2: op = rv_op_vfsub_vv; break; + case 3: op = rv_op_vfredosum_vs; break; + case 4: op = rv_op_vfmin_vv; break; + case 5: op = rv_op_vfredmin_vs; break; + case 6: op = rv_op_vfmax_vv; break; + case 7: op = rv_op_vfredmax_vs; break; + case 8: op = rv_op_vfsgnj_vv; break; + case 9: op = rv_op_vfsgnjn_vv; break; + case 10: op = rv_op_vfsgnjx_vv; break; + case 16: + switch (((inst >> 15) & 0b11111)) { + case 0: if ((inst >> 25) & 1) op = rv_op_vfmv_f_s; break; + } + break; + case 18: + switch (((inst >> 15) & 0b11111)) { + case 0: op = rv_op_vfcvt_xu_f_v; break; + case 1: op = rv_op_vfcvt_x_f_v; break; + case 2: op = rv_op_vfcvt_f_xu_v; break; + case 3: op = rv_op_vfcvt_f_x_v; break; + case 6: op = rv_op_vfcvt_rtz_xu_f_v; break; + case 7: op = rv_op_vfcvt_rtz_x_f_v; break; + case 8: op = rv_op_vfwcvt_xu_f_v; break; + case 9: op = rv_op_vfwcvt_x_f_v; break; + case 10: op = rv_op_vfwcvt_f_xu_v; break; + case 11: op = rv_op_vfwcvt_f_x_v; break; + case 12: op = rv_op_vfwcvt_f_f_v; break; + case 14: op = rv_op_vfwcvt_rtz_xu_f_v; break; + case 15: op = rv_op_vfwcvt_rtz_x_f_v; break; + case 16: op = rv_op_vfncvt_xu_f_w; break; + case 17: op = rv_op_vfncvt_x_f_w; break; + case 18: op = rv_op_vfncvt_f_xu_w; break; + case 19: op = rv_op_vfncvt_f_x_w; break; + case 20: op = rv_op_vfncvt_f_f_w; break; + case 21: op = rv_op_vfncvt_rod_f_f_w; break; + case 22: op = rv_op_vfncvt_rtz_xu_f_w; break; + case 23: op = rv_op_vfncvt_rtz_x_f_w; break; + } + break; + case 19: + switch (((inst >> 15) & 0b11111)) { + case 0: op = rv_op_vfsqrt_v; break; + case 4: op = rv_op_vfrsqrt7_v; break; + case 5: op = rv_op_vfrec7_v; break; + case 16: op = rv_op_vfclass_v; break; + } + break; + case 24: op = rv_op_vmfeq_vv; break; + case 25: op = rv_op_vmfle_vv; break; + case 27: op = rv_op_vmflt_vv; break; + case 28: op = rv_op_vmfne_vv; break; + case 32: op = rv_op_vfdiv_vv; break; + case 36: op = rv_op_vfmul_vv; break; + case 40: op = rv_op_vfmadd_vv; break; + case 41: op = rv_op_vfnmadd_vv; break; + case 42: op = rv_op_vfmsub_vv; break; + case 43: op = rv_op_vfnmsub_vv; break; + case 44: op = rv_op_vfmacc_vv; break; + case 45: op = rv_op_vfnmacc_vv; break; + case 46: op = rv_op_vfmsac_vv; break; + case 47: op = rv_op_vfnmsac_vv; break; + case 48: op = rv_op_vfwadd_vv; break; + case 49: op = rv_op_vfwredusum_vs; break; + case 50: op = rv_op_vfwsub_vv; break; + case 51: op = rv_op_vfwredosum_vs; break; + case 52: op = rv_op_vfwadd_wv; break; + case 54: op = rv_op_vfwsub_wv; break; + case 56: op = rv_op_vfwmul_vv; break; + case 60: op = rv_op_vfwmacc_vv; break; + case 61: op = rv_op_vfwnmacc_vv; break; + case 62: op = rv_op_vfwmsac_vv; break; + case 63: op = rv_op_vfwnmsac_vv; break; + } + break; + case 2: + switch (((inst >> 26) & 0b111111)) { + case 0: op = rv_op_vredsum_vs; break; + case 1: op = rv_op_vredand_vs; break; + case 2: op = rv_op_vredor_vs; break; + case 3: op = rv_op_vredxor_vs; break; + case 4: op = rv_op_vredminu_vs; break; + case 5: op = rv_op_vredmin_vs; break; + case 6: op = rv_op_vredmaxu_vs; break; + case 7: op = rv_op_vredmax_vs; break; + case 8: op = rv_op_vaaddu_vv; break; + case 9: op = rv_op_vaadd_vv; break; + case 10: op = rv_op_vasubu_vv; break; + case 11: op = rv_op_vasub_vv; break; + case 16: + switch (((inst >> 15) & 0b11111)) { + case 0: if ((inst >> 25) & 1) op = rv_op_vmv_x_s; break; + case 16: op = rv_op_vcpop_m; break; + case 17: op = rv_op_vfirst_m; break; + } + break; + case 18: + switch (((inst >> 15) & 0b11111)) { + case 2: op = rv_op_vzext_vf8; break; + case 3: op = rv_op_vsext_vf8; break; + case 4: op = rv_op_vzext_vf4; break; + case 5: op = rv_op_vsext_vf4; break; + case 6: op = rv_op_vzext_vf2; break; + case 7: op = rv_op_vsext_vf2; break; + } + break; + case 20: + switch (((inst >> 15) & 0b11111)) { + case 1: op = rv_op_vmsbf_m; break; + case 2: op = rv_op_vmsof_m; break; + case 3: op = rv_op_vmsif_m; break; + case 16: op = rv_op_viota_m; break; + case 17: if (((inst >> 20) & 0b11111) == 0) op = rv_op_vid_v; break; + } + break; + case 23: if ((inst >> 25) & 1) op = rv_op_vcompress_vm; break; + case 24: if ((inst >> 25) & 1) op = rv_op_vmandn_mm; break; + case 25: if ((inst >> 25) & 1) op = rv_op_vmand_mm; break; + case 26: if ((inst >> 25) & 1) op = rv_op_vmor_mm; break; + case 27: if ((inst >> 25) & 1) op = rv_op_vmxor_mm; break; + case 28: if ((inst >> 25) & 1) op = rv_op_vmorn_mm; break; + case 29: if ((inst >> 25) & 1) op = rv_op_vmnand_mm; break; + case 30: if ((inst >> 25) & 1) op = rv_op_vmnor_mm; break; + case 31: if ((inst >> 25) & 1) op = rv_op_vmxnor_mm; break; + case 32: op = rv_op_vdivu_vv; break; + case 33: op = rv_op_vdiv_vv; break; + case 34: op = rv_op_vremu_vv; break; + case 35: op = rv_op_vrem_vv; break; + case 36: op = rv_op_vmulhu_vv; break; + case 37: op = rv_op_vmul_vv; break; + case 38: op = rv_op_vmulhsu_vv; break; + case 39: op = rv_op_vmulh_vv; break; + case 41: op = rv_op_vmadd_vv; break; + case 43: op = rv_op_vnmsub_vv; break; + case 45: op = rv_op_vmacc_vv; break; + case 47: op = rv_op_vnmsac_vv; break; + case 48: op = rv_op_vwaddu_vv; break; + case 49: op = rv_op_vwadd_vv; break; + case 50: op = rv_op_vwsubu_vv; break; + case 51: op = rv_op_vwsub_vv; break; + case 52: op = rv_op_vwaddu_wv; break; + case 53: op = rv_op_vwadd_wv; break; + case 54: op = rv_op_vwsubu_wv; break; + case 55: op = rv_op_vwsub_wv; break; + case 56: op = rv_op_vwmulu_vv; break; + case 58: op = rv_op_vwmulsu_vv; break; + case 59: op = rv_op_vwmul_vv; break; + case 60: op = rv_op_vwmaccu_vv; break; + case 61: op = rv_op_vwmacc_vv; break; + case 63: op = rv_op_vwmaccsu_vv; break; + } + break; + case 3: + switch (((inst >> 26) & 0b111111)) { + case 0: op = rv_op_vadd_vi; break; + case 3: op = rv_op_vrsub_vi; break; + case 9: op = rv_op_vand_vi; break; + case 10: op = rv_op_vor_vi; break; + case 11: op = rv_op_vxor_vi; break; + case 12: op = rv_op_vrgather_vi; break; + case 14: op = rv_op_vslideup_vi; break; + case 15: op = rv_op_vslidedown_vi; break; + case 16: if (((inst >> 25) & 1) == 0) op = rv_op_vadc_vim; break; + case 17: op = rv_op_vmadc_vim; break; + case 23: + if (((inst >> 20) & 0b111111) == 32) + op = rv_op_vmv_v_i; + else if (((inst >> 25) & 1) == 0) + op = rv_op_vmerge_vim; + break; + case 24: op = rv_op_vmseq_vi; break; + case 25: op = rv_op_vmsne_vi; break; + case 28: op = rv_op_vmsleu_vi; break; + case 29: op = rv_op_vmsle_vi; break; + case 30: op = rv_op_vmsgtu_vi; break; + case 31: op = rv_op_vmsgt_vi; break; + case 32: op = rv_op_vsaddu_vi; break; + case 33: op = rv_op_vsadd_vi; break; + case 37: op = rv_op_vsll_vi; break; + case 39: + switch (((inst >> 15) & 0b11111)) { + case 0: op = rv_op_vmv1r_v; break; + case 1: op = rv_op_vmv2r_v; break; + case 3: op = rv_op_vmv4r_v; break; + case 7: op = rv_op_vmv8r_v; break; + } + break; + case 40: op = rv_op_vsrl_vi; break; + case 41: op = rv_op_vsra_vi; break; + case 42: op = rv_op_vssrl_vi; break; + case 43: op = rv_op_vssra_vi; break; + case 44: op = rv_op_vnsrl_wi; break; + case 45: op = rv_op_vnsra_wi; break; + case 46: op = rv_op_vnclipu_wi; break; + case 47: op = rv_op_vnclip_wi; break; + } + break; + case 4: + switch (((inst >> 26) & 0b111111)) { + case 0: op = rv_op_vadd_vx; break; + case 2: op = rv_op_vsub_vx; break; + case 3: op = rv_op_vrsub_vx; break; + case 4: op = rv_op_vminu_vx; break; + case 5: op = rv_op_vmin_vx; break; + case 6: op = rv_op_vmaxu_vx; break; + case 7: op = rv_op_vmax_vx; break; + case 9: op = rv_op_vand_vx; break; + case 10: op = rv_op_vor_vx; break; + case 11: op = rv_op_vxor_vx; break; + case 12: op = rv_op_vrgather_vx; break; + case 14: op = rv_op_vslideup_vx; break; + case 15: op = rv_op_vslidedown_vx; break; + case 16: if (((inst >> 25) & 1) == 0) op = rv_op_vadc_vxm; break; + case 17: op = rv_op_vmadc_vxm; break; + case 18: if (((inst >> 25) & 1) == 0) op = rv_op_vsbc_vxm; break; + case 19: op = rv_op_vmsbc_vxm; break; + case 23: + if (((inst >> 20) & 0b111111) == 32) + op = rv_op_vmv_v_x; + else if (((inst >> 25) & 1) == 0) + op = rv_op_vmerge_vxm; + break; + case 24: op = rv_op_vmseq_vx; break; + case 25: op = rv_op_vmsne_vx; break; + case 26: op = rv_op_vmsltu_vx; break; + case 27: op = rv_op_vmslt_vx; break; + case 28: op = rv_op_vmsleu_vx; break; + case 29: op = rv_op_vmsle_vx; break; + case 30: op = rv_op_vmsgtu_vx; break; + case 31: op = rv_op_vmsgt_vx; break; + case 32: op = rv_op_vsaddu_vx; break; + case 33: op = rv_op_vsadd_vx; break; + case 34: op = rv_op_vssubu_vx; break; + case 35: op = rv_op_vssub_vx; break; + case 37: op = rv_op_vsll_vx; break; + case 39: op = rv_op_vsmul_vx; break; + case 40: op = rv_op_vsrl_vx; break; + case 41: op = rv_op_vsra_vx; break; + case 42: op = rv_op_vssrl_vx; break; + case 43: op = rv_op_vssra_vx; break; + case 44: op = rv_op_vnsrl_wx; break; + case 45: op = rv_op_vnsra_wx; break; + case 46: op = rv_op_vnclipu_wx; break; + case 47: op = rv_op_vnclip_wx; break; + } + break; + case 5: + switch (((inst >> 26) & 0b111111)) { + case 0: op = rv_op_vfadd_vf; break; + case 2: op = rv_op_vfsub_vf; break; + case 4: op = rv_op_vfmin_vf; break; + case 6: op = rv_op_vfmax_vf; break; + case 8: op = rv_op_vfsgnj_vf; break; + case 9: op = rv_op_vfsgnjn_vf; break; + case 10: op = rv_op_vfsgnjx_vf; break; + case 14: op = rv_op_vfslide1up_vf; break; + case 15: op = rv_op_vfslide1down_vf; break; + case 16: + switch (((inst >> 20) & 0b11111)) { + case 0: if ((inst >> 25) & 1) op = rv_op_vfmv_s_f; break; + } + break; + case 23: + if (((inst >> 25) & 1) == 0) + op = rv_op_vfmerge_vfm; + else if (((inst >> 20) & 0b111111) == 32) + op = rv_op_vfmv_v_f; + break; + case 24: op = rv_op_vmfeq_vf; break; + case 25: op = rv_op_vmfle_vf; break; + case 27: op = rv_op_vmflt_vf; break; + case 28: op = rv_op_vmfne_vf; break; + case 29: op = rv_op_vmfgt_vf; break; + case 31: op = rv_op_vmfge_vf; break; + case 32: op = rv_op_vfdiv_vf; break; + case 33: op = rv_op_vfrdiv_vf; break; + case 36: op = rv_op_vfmul_vf; break; + case 39: op = rv_op_vfrsub_vf; break; + case 40: op = rv_op_vfmadd_vf; break; + case 41: op = rv_op_vfnmadd_vf; break; + case 42: op = rv_op_vfmsub_vf; break; + case 43: op = rv_op_vfnmsub_vf; break; + case 44: op = rv_op_vfmacc_vf; break; + case 45: op = rv_op_vfnmacc_vf; break; + case 46: op = rv_op_vfmsac_vf; break; + case 47: op = rv_op_vfnmsac_vf; break; + case 48: op = rv_op_vfwadd_vf; break; + case 50: op = rv_op_vfwsub_vf; break; + case 52: op = rv_op_vfwadd_wf; break; + case 54: op = rv_op_vfwsub_wf; break; + case 56: op = rv_op_vfwmul_vf; break; + case 60: op = rv_op_vfwmacc_vf; break; + case 61: op = rv_op_vfwnmacc_vf; break; + case 62: op = rv_op_vfwmsac_vf; break; + case 63: op = rv_op_vfwnmsac_vf; break; + } + break; + case 6: + switch (((inst >> 26) & 0b111111)) { + case 8: op = rv_op_vaaddu_vx; break; + case 9: op = rv_op_vaadd_vx; break; + case 10: op = rv_op_vasubu_vx; break; + case 11: op = rv_op_vasub_vx; break; + case 14: op = rv_op_vslide1up_vx; break; + case 15: op = rv_op_vslide1down_vx; break; + case 16: + switch (((inst >> 20) & 0b11111)) { + case 0: if ((inst >> 25) & 1) op = rv_op_vmv_s_x; break; + } + break; + case 32: op = rv_op_vdivu_vx; break; + case 33: op = rv_op_vdiv_vx; break; + case 34: op = rv_op_vremu_vx; break; + case 35: op = rv_op_vrem_vx; break; + case 36: op = rv_op_vmulhu_vx; break; + case 37: op = rv_op_vmul_vx; break; + case 38: op = rv_op_vmulhsu_vx; break; + case 39: op = rv_op_vmulh_vx; break; + case 41: op = rv_op_vmadd_vx; break; + case 43: op = rv_op_vnmsub_vx; break; + case 45: op = rv_op_vmacc_vx; break; + case 47: op = rv_op_vnmsac_vx; break; + case 48: op = rv_op_vwaddu_vx; break; + case 49: op = rv_op_vwadd_vx; break; + case 50: op = rv_op_vwsubu_vx; break; + case 51: op = rv_op_vwsub_vx; break; + case 52: op = rv_op_vwaddu_wx; break; + case 53: op = rv_op_vwadd_wx; break; + case 54: op = rv_op_vwsubu_wx; break; + case 55: op = rv_op_vwsub_wx; break; + case 56: op = rv_op_vwmulu_vx; break; + case 58: op = rv_op_vwmulsu_vx; break; + case 59: op = rv_op_vwmul_vx; break; + case 60: op = rv_op_vwmaccu_vx; break; + case 61: op = rv_op_vwmacc_vx; break; + case 62: op = rv_op_vwmaccus_vx; break; + case 63: op = rv_op_vwmaccsu_vx; break; + } + break; + case 7: + if (((inst >> 31) & 1) == 0) { + op = rv_op_vsetvli; + } else if ((inst >> 30) & 1) { + op = rv_op_vsetivli; + } else if (((inst >> 25) & 0b11111) == 0) { + op = rv_op_vsetvl; + } + break; + } + break; case 22: switch (((inst >> 12) & 0b111)) { case 0: op = rv_op_addid; break; @@ -2259,10 +3723,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) @@ -2374,9 +3853,39 @@ static uint32_t operand_cimmq(rv_inst inst) ((inst << 57) >> 62) << 6; } +static uint32_t operand_vimm(rv_inst inst) +{ + return (int64_t)(inst << 44) >> 59; +} + +static uint32_t operand_vzimm11(rv_inst inst) +{ + return (inst << 33) >> 53; +} + +static uint32_t operand_vzimm10(rv_inst inst) +{ + return (inst << 34) >> 54; +} + +static uint32_t operand_bs(rv_inst inst) +{ + return (inst << 32) >> 62; +} + +static uint32_t operand_rnum(rv_inst inst) +{ + return (inst << 40) >> 60; +} + +static uint32_t operand_vm(rv_inst inst) +{ + return (inst << 38) >> 63; +} + /* 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; @@ -2499,7 +4008,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); @@ -2514,7 +4023,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; @@ -2653,6 +4162,43 @@ static void decode_inst_operands(rv_decode *dec) dec->rs2 = operand_crs2(inst); dec->imm = operand_cimmsqsp(inst); break; + case rv_codec_k_bs: + dec->rs1 = operand_rs1(inst); + dec->rs2 = operand_rs2(inst); + dec->bs = operand_bs(inst); + break; + case rv_codec_k_rnum: + dec->rd = operand_rd(inst); + dec->rs1 = operand_rs1(inst); + dec->rnum = operand_rnum(inst); + break; + case rv_codec_v_r: + dec->rd = operand_rd(inst); + dec->rs1 = operand_rs1(inst); + dec->rs2 = operand_rs2(inst); + dec->vm = operand_vm(inst); + break; + case rv_codec_v_ldst: + dec->rd = operand_rd(inst); + dec->rs1 = operand_rs1(inst); + dec->vm = operand_vm(inst); + break; + case rv_codec_v_i: + dec->rd = operand_rd(inst); + dec->rs2 = operand_rs2(inst); + dec->imm = operand_vimm(inst); + dec->vm = operand_vm(inst); + break; + case rv_codec_vsetvli: + dec->rd = operand_rd(inst); + dec->rs1 = operand_rs1(inst); + dec->vzimm = operand_vzimm11(inst); + break; + case rv_codec_vsetivli: + dec->rd = operand_rd(inst); + dec->imm = operand_vimm(inst); + dec->vzimm = operand_vzimm10(inst); + break; }; } @@ -2812,6 +4358,14 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec) case ')': append(buf, ")", buflen); break; + case 'b': + snprintf(tmp, sizeof(tmp), "%d", dec->bs); + append(buf, tmp, buflen); + break; + case 'n': + snprintf(tmp, sizeof(tmp), "%d", dec->rnum); + append(buf, tmp, buflen); + break; case '0': append(buf, rv_ireg_name_sym[dec->rd], buflen); break; @@ -2841,6 +4395,10 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec) snprintf(tmp, sizeof(tmp), "%d", dec->imm); append(buf, tmp, buflen); break; + case 'u': + snprintf(tmp, sizeof(tmp), "%u", ((uint32_t)dec->imm & 0b11111)); + append(buf, tmp, buflen); + break; case 'o': snprintf(tmp, sizeof(tmp), "%d", dec->imm); append(buf, tmp, buflen); @@ -2929,6 +4487,60 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec) append(buf, ".rl", buflen); } break; + case 'l': + append(buf, ",v0", buflen); + break; + case 'm': + if (dec->vm == 0) { + append(buf, ",v0.t", buflen); + } + break; + case 'D': + append(buf, rv_vreg_name_sym[dec->rd], buflen); + break; + case 'E': + append(buf, rv_vreg_name_sym[dec->rs1], buflen); + break; + case 'F': + append(buf, rv_vreg_name_sym[dec->rs2], buflen); + break; + case 'G': + append(buf, rv_vreg_name_sym[dec->rs3], buflen); + break; + case 'v': { + char nbuf[32] = {0}; + const int sew = 1 << (((dec->vzimm >> 3) & 0b111) + 3); + sprintf(nbuf, "%d", sew); + const int lmul = dec->vzimm & 0b11; + const int flmul = (dec->vzimm >> 2) & 1; + const char *vta = (dec->vzimm >> 6) & 1 ? "ta" : "tu"; + const char *vma = (dec->vzimm >> 7) & 1 ? "ma" : "mu"; + append(buf, "e", buflen); + append(buf, nbuf, buflen); + append(buf, ",m", buflen); + if (flmul) { + switch (lmul) { + case 3: + sprintf(nbuf, "f2"); + break; + case 2: + sprintf(nbuf, "f4"); + break; + case 1: + sprintf(nbuf, "f8"); + break; + } + append(buf, nbuf, buflen); + } else { + sprintf(nbuf, "%d", 1 << lmul); + append(buf, nbuf, buflen); + } + append(buf, ",", buflen); + append(buf, vta, buflen); + append(buf, ",", buflen); + append(buf, vma, buflen); + break; + } default: break; } @@ -3022,10 +4634,10 @@ 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); + format_inst(buf, buflen, 24, &dec); } #define INST_FMT_2 "%04" PRIx64 " " diff --git a/disas/s390.c b/disas/s390.c deleted file mode 100644 index a9ec8fa593c0..000000000000 --- a/disas/s390.c +++ /dev/null @@ -1,1892 +0,0 @@ -/* opcodes/s390-dis.c revision 1.12 */ -/* s390-dis.c -- Disassemble S390 instructions - Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. - Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). - - This file is part of GDB, GAS and the GNU binutils. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" - -/* include/opcode/s390.h revision 1.9 */ -/* s390.h -- Header file for S390 opcode table - Copyright 2000, 2001, 2003 Free Software Foundation, Inc. - Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#ifndef S390_H -#define S390_H - -/* List of instruction sets variations. */ - -enum s390_opcode_mode_val - { - S390_OPCODE_ESA = 0, - S390_OPCODE_ZARCH - }; - -enum s390_opcode_cpu_val - { - S390_OPCODE_G5 = 0, - S390_OPCODE_G6, - S390_OPCODE_Z900, - S390_OPCODE_Z990, - S390_OPCODE_Z9_109, - S390_OPCODE_Z9_EC, - S390_OPCODE_Z10 - }; - -/* The opcode table is an array of struct s390_opcode. */ - -struct s390_opcode - { - /* The opcode name. */ - const char * name; - - /* The opcode itself. Those bits which will be filled in with - operands are zeroes. */ - unsigned char opcode[6]; - - /* The opcode mask. This is used by the disassembler. This is a - mask containing ones indicating those bits which must match the - opcode field, and zeroes indicating those bits which need not - match (and are presumably filled in by operands). */ - unsigned char mask[6]; - - /* The opcode length in bytes. */ - int oplen; - - /* An array of operand codes. Each code is an index into the - operand table. They appear in the order which the operands must - appear in assembly code, and are terminated by a zero. */ - unsigned char operands[6]; - - /* Bitmask of execution modes this opcode is available for. */ - unsigned int modes; - - /* First cpu this opcode is available for. */ - enum s390_opcode_cpu_val min_cpu; - }; - -/* The table itself is sorted by major opcode number, and is otherwise - in the order in which the disassembler should consider - instructions. */ -/* QEMU: Mark these static. */ -static const struct s390_opcode s390_opcodes[]; -static const int s390_num_opcodes; - -/* Values defined for the flags field of a struct powerpc_opcode. */ - -/* The operands table is an array of struct s390_operand. */ - -struct s390_operand - { - /* The number of bits in the operand. */ - int bits; - - /* How far the operand is left shifted in the instruction. */ - int shift; - - /* One bit syntax flags. */ - unsigned long flags; - }; - -/* Elements in the table are retrieved by indexing with values from - the operands field of the powerpc_opcodes table. */ - -static const struct s390_operand s390_operands[]; - -/* Values defined for the flags field of a struct s390_operand. */ - -/* This operand names a register. The disassembler uses this to print - register names with a leading 'r'. */ -#define S390_OPERAND_GPR 0x1 - -/* This operand names a floating point register. The disassembler - prints these with a leading 'f'. */ -#define S390_OPERAND_FPR 0x2 - -/* This operand names an access register. The disassembler - prints these with a leading 'a'. */ -#define S390_OPERAND_AR 0x4 - -/* This operand names a control register. The disassembler - prints these with a leading 'c'. */ -#define S390_OPERAND_CR 0x8 - -/* This operand is a displacement. */ -#define S390_OPERAND_DISP 0x10 - -/* This operand names a base register. */ -#define S390_OPERAND_BASE 0x20 - -/* This operand names an index register, it can be skipped. */ -#define S390_OPERAND_INDEX 0x40 - -/* This operand is a relative branch displacement. The disassembler - prints these symbolically if possible. */ -#define S390_OPERAND_PCREL 0x80 - -/* This operand takes signed values. */ -#define S390_OPERAND_SIGNED 0x100 - -/* This operand is a length. */ -#define S390_OPERAND_LENGTH 0x200 - -/* This operand is optional. Only a single operand at the end of - the instruction may be optional. */ -#define S390_OPERAND_OPTIONAL 0x400 - -/* QEMU-ADD */ -/* ??? Not quite the format the assembler takes, but easy to implement - without recourse to the table generator. */ -#define S390_OPERAND_CCODE 0x800 - -static const char s390_ccode_name[16][4] = { - "n", /* 0000 */ - "o", /* 0001 */ - "h", /* 0010 */ - "nle", /* 0011 */ - "l", /* 0100 */ - "nhe", /* 0101 */ - "lh", /* 0110 */ - "ne", /* 0111 */ - "e", /* 1000 */ - "nlh", /* 1001 */ - "he", /* 1010 */ - "nl", /* 1011 */ - "le", /* 1100 */ - "nh", /* 1101 */ - "no", /* 1110 */ - "a" /* 1111 */ -}; -/* QEMU-END */ - -#endif /* S390_H */ - -static int init_flag = 0; -static int opc_index[256]; - -/* QEMU: We've disabled the architecture check below. */ -/* static int current_arch_mask = 0; */ - -/* Set up index table for first opcode byte. */ - -static void -init_disasm (struct disassemble_info *info) -{ - int i; - - memset (opc_index, 0, sizeof (opc_index)); - - /* Reverse order, such that each opc_index ends up pointing to the - first matching entry instead of the last. */ - for (i = s390_num_opcodes; i--; ) - opc_index[s390_opcodes[i].opcode[0]] = i; - -#ifdef QEMU_DISABLE - switch (info->mach) - { - case bfd_mach_s390_31: - current_arch_mask = 1 << S390_OPCODE_ESA; - break; - case bfd_mach_s390_64: - current_arch_mask = 1 << S390_OPCODE_ZARCH; - break; - default: - abort (); - } -#endif /* QEMU_DISABLE */ - - init_flag = 1; -} - -/* Extracts an operand value from an instruction. */ - -static inline unsigned int -s390_extract_operand (unsigned char *insn, const struct s390_operand *operand) -{ - unsigned int val; - int bits; - - /* Extract fragments of the operand byte for byte. */ - insn += operand->shift / 8; - bits = (operand->shift & 7) + operand->bits; - val = 0; - do - { - val <<= 8; - val |= (unsigned int) *insn++; - bits -= 8; - } - while (bits > 0); - val >>= -bits; - val &= ((1U << (operand->bits - 1)) << 1) - 1; - - /* Check for special long displacement case. */ - if (operand->bits == 20 && operand->shift == 20) - val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; - - /* Sign extend value if the operand is signed or pc relative. */ - if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) - && (val & (1U << (operand->bits - 1)))) - val |= (-1U << (operand->bits - 1)) << 1; - - /* Double value if the operand is pc relative. */ - if (operand->flags & S390_OPERAND_PCREL) - val <<= 1; - - /* Length x in an instructions has real length x + 1. */ - if (operand->flags & S390_OPERAND_LENGTH) - val++; - return val; -} - -/* Print a S390 instruction. */ - -int -print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) -{ - bfd_byte buffer[6]; - const struct s390_opcode *opcode; - const struct s390_opcode *opcode_end; - unsigned int value; - int status, opsize, bufsize; - char separator; - - if (init_flag == 0) - init_disasm (info); - - /* The output looks better if we put 6 bytes on a line. */ - info->bytes_per_line = 6; - - /* Every S390 instruction is max 6 bytes long. */ - memset (buffer, 0, 6); - status = (*info->read_memory_func) (memaddr, buffer, 6, info); - if (status != 0) - { - for (bufsize = 0; bufsize < 6; bufsize++) - if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0) - break; - if (bufsize <= 0) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - /* Opsize calculation looks strange but it works - 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes, - 11xxxxxx -> 6 bytes. */ - opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; - status = opsize > bufsize; - } - else - { - bufsize = 6; - opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; - } - - if (status == 0) - { - /* Find the first match in the opcode table. */ - opcode_end = s390_opcodes + s390_num_opcodes; - for (opcode = s390_opcodes + opc_index[(int) buffer[0]]; - (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]); - opcode++) - { - const struct s390_operand *operand; - const unsigned char *opindex; - -#ifdef QEMU_DISABLE - /* Check architecture. */ - if (!(opcode->modes & current_arch_mask)) - continue; -#endif /* QEMU_DISABLE */ - - /* Check signature of the opcode. */ - if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1] - || (buffer[2] & opcode->mask[2]) != opcode->opcode[2] - || (buffer[3] & opcode->mask[3]) != opcode->opcode[3] - || (buffer[4] & opcode->mask[4]) != opcode->opcode[4] - || (buffer[5] & opcode->mask[5]) != opcode->opcode[5]) - continue; - - /* The instruction is valid. */ -/* QEMU-MOD */ - (*info->fprintf_func) (info->stream, "%s", opcode->name); - - if (s390_operands[opcode->operands[0]].flags & S390_OPERAND_CCODE) - separator = 0; - else - separator = '\t'; -/* QEMU-END */ - - /* Extract the operands. */ - for (opindex = opcode->operands; *opindex != 0; opindex++) - { - unsigned int value; - - operand = s390_operands + *opindex; - value = s390_extract_operand (buffer, operand); - - if ((operand->flags & S390_OPERAND_INDEX) && value == 0) - continue; - if ((operand->flags & S390_OPERAND_BASE) && - value == 0 && separator == '(') - { - separator = ','; - continue; - } - - if (separator) - (*info->fprintf_func) (info->stream, "%c", separator); - - if (operand->flags & S390_OPERAND_GPR) - (*info->fprintf_func) (info->stream, "%%r%i", value); - else if (operand->flags & S390_OPERAND_FPR) - (*info->fprintf_func) (info->stream, "%%f%i", value); - else if (operand->flags & S390_OPERAND_AR) - (*info->fprintf_func) (info->stream, "%%a%i", value); - else if (operand->flags & S390_OPERAND_CR) - (*info->fprintf_func) (info->stream, "%%c%i", value); - else if (operand->flags & S390_OPERAND_PCREL) - (*info->print_address_func) (memaddr + (int) value, info); - else if (operand->flags & S390_OPERAND_SIGNED) - (*info->fprintf_func) (info->stream, "%i", (int) value); -/* QEMU-ADD */ - else if (operand->flags & S390_OPERAND_CCODE) - { - (*info->fprintf_func) (info->stream, "%s", - s390_ccode_name[(int) value]); - separator = '\t'; - continue; - } -/* QEMU-END */ - else - (*info->fprintf_func) (info->stream, "%u", value); - - if (operand->flags & S390_OPERAND_DISP) - { - separator = '('; - } - else if (operand->flags & S390_OPERAND_BASE) - { - (*info->fprintf_func) (info->stream, ")"); - separator = ','; - } - else - separator = ','; - } - - /* Found instruction, printed it, return its size. */ - return opsize; - } - /* No matching instruction found, fall through to hex print. */ - } - - if (bufsize >= 4) - { - value = (unsigned int) buffer[0]; - value = (value << 8) + (unsigned int) buffer[1]; - value = (value << 8) + (unsigned int) buffer[2]; - value = (value << 8) + (unsigned int) buffer[3]; - (*info->fprintf_func) (info->stream, ".long\t0x%08x", value); - return 4; - } - else if (bufsize >= 2) - { - value = (unsigned int) buffer[0]; - value = (value << 8) + (unsigned int) buffer[1]; - (*info->fprintf_func) (info->stream, ".short\t0x%04x", value); - return 2; - } - else - { - value = (unsigned int) buffer[0]; - (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); - return 1; - } -} - -/* opcodes/s390-opc.c revision 1.16 */ -/* s390-opc.c -- S390 opcode list - Copyright 2000, 2001, 2003 Free Software Foundation, Inc. - Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). - - This file is part of GDB, GAS, and the GNU binutils. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -/* This file holds the S390 opcode table. The opcode table - includes almost all of the extended instruction mnemonics. This - permits the disassembler to use them, and simplifies the assembler - logic, at the cost of increasing the table size. The table is - strictly constant data, so the compiler should be able to put it in - the .text section. - - This file also holds the operand table. All knowledge about - inserting operands into instructions and vice-versa is kept in this - file. */ - -/* The operands table. - The fields are bits, shift, insert, extract, flags. */ - -static const struct s390_operand s390_operands[] = -{ -#define UNUSED 0 - { 0, 0, 0 }, /* Indicates the end of the operand list */ - -#define R_8 1 /* GPR starting at position 8 */ - { 4, 8, S390_OPERAND_GPR }, -#define R_12 2 /* GPR starting at position 12 */ - { 4, 12, S390_OPERAND_GPR }, -#define R_16 3 /* GPR starting at position 16 */ - { 4, 16, S390_OPERAND_GPR }, -#define R_20 4 /* GPR starting at position 20 */ - { 4, 20, S390_OPERAND_GPR }, -#define R_24 5 /* GPR starting at position 24 */ - { 4, 24, S390_OPERAND_GPR }, -#define R_28 6 /* GPR starting at position 28 */ - { 4, 28, S390_OPERAND_GPR }, -#define R_32 7 /* GPR starting at position 32 */ - { 4, 32, S390_OPERAND_GPR }, - -#define F_8 8 /* FPR starting at position 8 */ - { 4, 8, S390_OPERAND_FPR }, -#define F_12 9 /* FPR starting at position 12 */ - { 4, 12, S390_OPERAND_FPR }, -#define F_16 10 /* FPR starting at position 16 */ - { 4, 16, S390_OPERAND_FPR }, -#define F_20 11 /* FPR starting at position 16 */ - { 4, 16, S390_OPERAND_FPR }, -#define F_24 12 /* FPR starting at position 24 */ - { 4, 24, S390_OPERAND_FPR }, -#define F_28 13 /* FPR starting at position 28 */ - { 4, 28, S390_OPERAND_FPR }, -#define F_32 14 /* FPR starting at position 32 */ - { 4, 32, S390_OPERAND_FPR }, - -#define A_8 15 /* Access reg. starting at position 8 */ - { 4, 8, S390_OPERAND_AR }, -#define A_12 16 /* Access reg. starting at position 12 */ - { 4, 12, S390_OPERAND_AR }, -#define A_24 17 /* Access reg. starting at position 24 */ - { 4, 24, S390_OPERAND_AR }, -#define A_28 18 /* Access reg. starting at position 28 */ - { 4, 28, S390_OPERAND_AR }, - -#define C_8 19 /* Control reg. starting at position 8 */ - { 4, 8, S390_OPERAND_CR }, -#define C_12 20 /* Control reg. starting at position 12 */ - { 4, 12, S390_OPERAND_CR }, - -#define B_16 21 /* Base register starting at position 16 */ - { 4, 16, S390_OPERAND_BASE|S390_OPERAND_GPR }, -#define B_32 22 /* Base register starting at position 32 */ - { 4, 32, S390_OPERAND_BASE|S390_OPERAND_GPR }, - -#define X_12 23 /* Index register starting at position 12 */ - { 4, 12, S390_OPERAND_INDEX|S390_OPERAND_GPR }, - -#define D_20 24 /* Displacement starting at position 20 */ - { 12, 20, S390_OPERAND_DISP }, -#define D_36 25 /* Displacement starting at position 36 */ - { 12, 36, S390_OPERAND_DISP }, -#define D20_20 26 /* 20 bit displacement starting at 20 */ - { 20, 20, S390_OPERAND_DISP|S390_OPERAND_SIGNED }, - -#define L4_8 27 /* 4 bit length starting at position 8 */ - { 4, 8, S390_OPERAND_LENGTH }, -#define L4_12 28 /* 4 bit length starting at position 12 */ - { 4, 12, S390_OPERAND_LENGTH }, -#define L8_8 29 /* 8 bit length starting at position 8 */ - { 8, 8, S390_OPERAND_LENGTH }, - -#define U4_8 30 /* 4 bit unsigned value starting at 8 */ - { 4, 8, 0 }, -#define U4_12 31 /* 4 bit unsigned value starting at 12 */ - { 4, 12, 0 }, -#define U4_16 32 /* 4 bit unsigned value starting at 16 */ - { 4, 16, 0 }, -#define U4_20 33 /* 4 bit unsigned value starting at 20 */ - { 4, 20, 0 }, -#define U8_8 34 /* 8 bit unsigned value starting at 8 */ - { 8, 8, 0 }, -#define U8_16 35 /* 8 bit unsigned value starting at 16 */ - { 8, 16, 0 }, -#define I16_16 36 /* 16 bit signed value starting at 16 */ - { 16, 16, S390_OPERAND_SIGNED }, -#define U16_16 37 /* 16 bit unsigned value starting at 16 */ - { 16, 16, 0 }, -#define J16_16 38 /* PC relative jump offset at 16 */ - { 16, 16, S390_OPERAND_PCREL }, -#define J32_16 39 /* PC relative long offset at 16 */ - { 32, 16, S390_OPERAND_PCREL }, -#define I32_16 40 /* 32 bit signed value starting at 16 */ - { 32, 16, S390_OPERAND_SIGNED }, -#define U32_16 41 /* 32 bit unsigned value starting at 16 */ - { 32, 16, 0 }, -#define M_16 42 /* 4 bit optional mask starting at 16 */ - { 4, 16, S390_OPERAND_OPTIONAL }, -#define RO_28 43 /* optional GPR starting at position 28 */ - { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) }, - -/* QEMU-ADD: */ -#define M4_12 44 /* 4-bit condition-code starting at 12 */ - { 4, 12, S390_OPERAND_CCODE }, -#define M4_32 45 /* 4-bit condition-code starting at 32 */ - { 4, 32, S390_OPERAND_CCODE }, -#define I8_32 46 /* 8 bit signed value starting at 32 */ - { 8, 32, S390_OPERAND_SIGNED }, -#define U8_24 47 /* 8 bit unsigned value starting at 24 */ - { 8, 24, 0 }, -#define U8_32 48 /* 8 bit unsigned value starting at 32 */ - { 8, 32, 0 }, -#define I16_32 49 - { 16, 32, S390_OPERAND_SIGNED }, -#define M4_16 50 /* 4-bit condition-code starting at 12 */ - { 4, 16, S390_OPERAND_CCODE }, -#define I8_16 51 - { 8, 16, S390_OPERAND_SIGNED }, -/* QEMU-END */ -}; - - -/* Macros used to form opcodes. */ - -/* 8/16/48 bit opcodes. */ -#define OP8(x) { x, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define OP16(x) { x >> 8, x & 255, 0x00, 0x00, 0x00, 0x00 } -#define OP48(x) { x >> 40, (x >> 32) & 255, (x >> 24) & 255, \ - (x >> 16) & 255, (x >> 8) & 255, x & 255} - -/* The new format of the INSTR_x_y and MASK_x_y defines is based - on the following rules: - 1) the middle part of the definition (x in INSTR_x_y) is the official - names of the instruction format that you can find in the principals - of operation. - 2) the last part of the definition (y in INSTR_x_y) gives you an idea - which operands the binary representation of the instruction has. - The meanings of the letters in y are: - a - access register - c - control register - d - displacement, 12 bit - f - floating pointer register - i - signed integer, 4, 8, 16 or 32 bit - l - length, 4 or 8 bit - p - pc relative - r - general purpose register - u - unsigned integer, 4, 8, 16 or 32 bit - m - mode field, 4 bit - 0 - operand skipped. - The order of the letters reflects the layout of the format in - storage and not the order of the parameters of the instructions. - The use of the letters is not a 100% match with the PoP but it is - quite close. - - For example the instruction "mvo" is defined in the PoP as follows: - - MVO D1(L1,B1),D2(L2,B2) [SS] - - -------------------------------------- - | 'F1' | L1 | L2 | B1 | D1 | B2 | D2 | - -------------------------------------- - 0 8 12 16 20 32 36 - - The instruction format is: INSTR_SS_LLRDRD / MASK_SS_LLRDRD. */ - -#define INSTR_E 2, { 0,0,0,0,0,0 } /* e.g. pr */ -#define INSTR_RIE_RRP 6, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxhg */ -#define INSTR_RIL_0P 6, { J32_16,0,0,0,0 } /* e.g. jg */ -#define INSTR_RIL_RP 6, { R_8,J32_16,0,0,0,0 } /* e.g. brasl */ -#define INSTR_RIL_UP 6, { U4_8,J32_16,0,0,0,0 } /* e.g. brcl */ -#define INSTR_RIL_RI 6, { R_8,I32_16,0,0,0,0 } /* e.g. afi */ -#define INSTR_RIL_RU 6, { R_8,U32_16,0,0,0,0 } /* e.g. alfi */ -#define INSTR_RI_0P 4, { J16_16,0,0,0,0,0 } /* e.g. j */ -#define INSTR_RI_RI 4, { R_8,I16_16,0,0,0,0 } /* e.g. ahi */ -#define INSTR_RI_RP 4, { R_8,J16_16,0,0,0,0 } /* e.g. brct */ -#define INSTR_RI_RU 4, { R_8,U16_16,0,0,0,0 } /* e.g. tml */ -#define INSTR_RI_UP 4, { U4_8,J16_16,0,0,0,0 } /* e.g. brc */ -#define INSTR_RRE_00 4, { 0,0,0,0,0,0 } /* e.g. palb */ -#define INSTR_RRE_0R 4, { R_28,0,0,0,0,0 } /* e.g. tb */ -#define INSTR_RRE_AA 4, { A_24,A_28,0,0,0,0 } /* e.g. cpya */ -#define INSTR_RRE_AR 4, { A_24,R_28,0,0,0,0 } /* e.g. sar */ -#define INSTR_RRE_F0 4, { F_24,0,0,0,0,0 } /* e.g. sqer */ -#define INSTR_RRE_FF 4, { F_24,F_28,0,0,0,0 } /* e.g. debr */ -#define INSTR_RRE_R0 4, { R_24,0,0,0,0,0 } /* e.g. ipm */ -#define INSTR_RRE_RA 4, { R_24,A_28,0,0,0,0 } /* e.g. ear */ -#define INSTR_RRE_RF 4, { R_24,F_28,0,0,0,0 } /* e.g. cefbr */ -#define INSTR_RRE_RR 4, { R_24,R_28,0,0,0,0 } /* e.g. lura */ -#define INSTR_RRE_FR 4, { F_24,R_28,0,0,0,0 } /* e.g. ldgr */ -/* Actually efpc and sfpc do not take an optional operand. - This is just a workaround for existing code e.g. glibc. */ -#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ -#define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ -/* QEMU-MOD */ -#define INSTR_RRF_F0FF2 4, { F_24,F_28,F_16,0,0,0 } /* e.g. cpsdr */ -/* QEMU-END */ -#define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ -#define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ -#define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ -#define INSTR_RRF_R0RR 4, { R_24,R_28,R_16,0,0,0 } /* e.g. idte */ -#define INSTR_RRF_U0FF 4, { F_24,U4_16,F_28,0,0,0 } /* e.g. fixr */ -#define INSTR_RRF_U0RF 4, { R_24,U4_16,F_28,0,0,0 } /* e.g. cfebr */ -#define INSTR_RRF_UUFF 4, { F_24,U4_16,F_28,U4_20,0,0 } /* e.g. fidtr */ -#define INSTR_RRF_0UFF 4, { F_24,F_28,U4_20,0,0,0 } /* e.g. ldetr */ -#define INSTR_RRF_FFFU 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. qadtr */ -#define INSTR_RRF_M0RR 4, { R_24,R_28,M_16,0,0,0 } /* e.g. sske */ -#define INSTR_RR_0R 2, { R_12, 0,0,0,0,0 } /* e.g. br */ -#define INSTR_RR_FF 2, { F_8,F_12,0,0,0,0 } /* e.g. adr */ -#define INSTR_RR_R0 2, { R_8, 0,0,0,0,0 } /* e.g. spm */ -#define INSTR_RR_RR 2, { R_8,R_12,0,0,0,0 } /* e.g. lr */ -#define INSTR_RR_U0 2, { U8_8, 0,0,0,0,0 } /* e.g. svc */ -#define INSTR_RR_UR 2, { U4_8,R_12,0,0,0,0 } /* e.g. bcr */ -#define INSTR_RRR_F0FF 4, { F_24,F_28,F_16,0,0,0 } /* e.g. ddtr */ -#define INSTR_RSE_RRRD 6, { R_8,R_12,D_20,B_16,0,0 } /* e.g. lmh */ -#define INSTR_RSE_CCRD 6, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lmh */ -#define INSTR_RSE_RURD 6, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icmh */ -#define INSTR_RSL_R0RD 6, { R_8,D_20,B_16,0,0,0 } /* e.g. tp */ -#define INSTR_RSI_RRP 4, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxh */ -#define INSTR_RSY_RRRD 6, { R_8,R_12,D20_20,B_16,0,0 } /* e.g. stmy */ -#define INSTR_RSY_RURD 6, { R_8,U4_12,D20_20,B_16,0,0 } /* e.g. icmh */ -#define INSTR_RSY_AARD 6, { A_8,A_12,D20_20,B_16,0,0 } /* e.g. lamy */ -#define INSTR_RSY_CCRD 6, { C_8,C_12,D20_20,B_16,0,0 } /* e.g. lamy */ -#define INSTR_RS_AARD 4, { A_8,A_12,D_20,B_16,0,0 } /* e.g. lam */ -#define INSTR_RS_CCRD 4, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lctl */ -#define INSTR_RS_R0RD 4, { R_8,D_20,B_16,0,0,0 } /* e.g. sll */ -#define INSTR_RS_RRRD 4, { R_8,R_12,D_20,B_16,0,0 } /* e.g. cs */ -#define INSTR_RS_RURD 4, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icm */ -#define INSTR_RXE_FRRD 6, { F_8,D_20,X_12,B_16,0,0 } /* e.g. axbr */ -#define INSTR_RXE_RRRD 6, { R_8,D_20,X_12,B_16,0,0 } /* e.g. lg */ -#define INSTR_RXF_FRRDF 6, { F_32,F_8,D_20,X_12,B_16,0 } /* e.g. madb */ -#define INSTR_RXF_RRRDR 6, { R_32,R_8,D_20,X_12,B_16,0 } /* e.g. .insn */ -#define INSTR_RXY_RRRD 6, { R_8,D20_20,X_12,B_16,0,0 } /* e.g. ly */ -#define INSTR_RXY_FRRD 6, { F_8,D20_20,X_12,B_16,0,0 } /* e.g. ley */ -#define INSTR_RX_0RRD 4, { D_20,X_12,B_16,0,0,0 } /* e.g. be */ -#define INSTR_RX_FRRD 4, { F_8,D_20,X_12,B_16,0,0 } /* e.g. ae */ -#define INSTR_RX_RRRD 4, { R_8,D_20,X_12,B_16,0,0 } /* e.g. l */ -#define INSTR_RX_URRD 4, { U4_8,D_20,X_12,B_16,0,0 } /* e.g. bc */ -#define INSTR_SI_URD 4, { D_20,B_16,U8_8,0,0,0 } /* e.g. cli */ -#define INSTR_SIY_URD 6, { D20_20,B_16,U8_8,0,0,0 } /* e.g. tmy */ -#define INSTR_SSE_RDRD 6, { D_20,B_16,D_36,B_32,0,0 } /* e.g. mvsdk */ -#define INSTR_SS_L0RDRD 6, { D_20,L8_8,B_16,D_36,B_32,0 } /* e.g. mvc */ -#define INSTR_SS_L2RDRD 6, { D_20,B_16,D_36,L8_8,B_32,0 } /* e.g. pka */ -#define INSTR_SS_LIRDRD 6, { D_20,L4_8,B_16,D_36,B_32,U4_12 } /* e.g. srp */ -#define INSTR_SS_LLRDRD 6, { D_20,L4_8,B_16,D_36,L4_12,B_32 } /* e.g. pack */ -#define INSTR_SS_RRRDRD 6, { D_20,R_8,B_16,D_36,B_32,R_12 } /* e.g. mvck */ -#define INSTR_SS_RRRDRD2 6, { R_8,D_20,B_16,R_12,D_36,B_32 } /* e.g. plo */ -#define INSTR_SS_RRRDRD3 6, { R_8,R_12,D_20,B_16,D_36,B_32 } /* e.g. lmd */ -#define INSTR_S_00 4, { 0,0,0,0,0,0 } /* e.g. hsch */ -#define INSTR_S_RD 4, { D_20,B_16,0,0,0,0 } /* e.g. lpsw */ -#define INSTR_SSF_RRDRD 6, { D_20,B_16,D_36,B_32,R_8,0 } /* e.g. mvcos */ - -#define MASK_E { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RIE_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RIL_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RIL_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RIL_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RIL_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RIL_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RI_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RI_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RI_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RI_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RI_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRE_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } -#define MASK_RRE_0R { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 } -#define MASK_RRE_AA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_AR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_F0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } -#define MASK_RRE_FF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_R0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } -#define MASK_RRE_RA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_RF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_RR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_FR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRE_RR_OPT { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } -#define MASK_RRF_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RRF_F0FF2 { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RRF_F0FR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RRF_FUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRF_RURR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRF_R0RR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRF_U0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RRF_U0RF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RRF_UUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRF_0UFF { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 } -#define MASK_RRF_FFFU { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRF_M0RR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RR_0R { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RR_FF { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RR_R0 { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RR_RR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RR_U0 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RR_UR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RRR_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } -#define MASK_RSE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSE_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSE_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSL_R0RD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSI_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RS_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RS_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RS_R0RD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RS_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RS_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RSY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSY_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSY_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RSY_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RXE_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RXE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RXF_FRRDF { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RXF_RRRDR { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RXY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RXY_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_RX_0RRD { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RX_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RX_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_RX_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SI_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SIY_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define MASK_SSE_RDRD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_L0RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_L2RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_LIRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_LLRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_RRRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_RRRDRD2 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SS_RRRDRD3 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } -#define MASK_S_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } -#define MASK_S_RD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } -#define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } - -/* QEMU-ADD: */ -#define INSTR_RIE_MRRP 6, { M4_32, R_8, R_12, J16_16, 0, 0 } /* e.g. crj */ -#define MASK_RIE_MRRP { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff } - -#define INSTR_RIE_MRIP 6, { M4_12, R_8, I8_32, J16_16, 0, 0 } /* e.g. cij */ -#define MASK_RIE_MRIP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } - -#define INSTR_RIE_RRIII 6, { R_8, R_12, U8_16, U8_24, U8_32, 0 } /* risbg */ -#define MASK_RIE_RRIII { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define INSTR_RIE_MRI 6, { M4_32, R_8, I16_16, 0, 0, 0 } /* e.g. cit */ -#define MASK_RIE_MRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define INSTR_RIE_MRU 6, { M4_32, R_8, U16_16, 0, 0, 0 } /* e.g. clfit */ -#define MASK_RIE_MRU { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -#define INSTR_RIE_RRI 6, { R_8, R_12, I16_16, 0, 0, 0 } -#define MASK_RIE_RRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } - -#define INSTR_RXY_URRD 6, { U8_8, D20_20, X_12, B_16, 0, 0 } -#define MASK_RXY_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } - -#define INSTR_SIL_DRI 6, { D_20, B_16, I16_32, 0, 0, 0 } -#define MASK_SIL_DRI { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } - -#define INSTR_RSY_MRRD 6, { M4_12, R_8, D20_20, B_16, 0, 0 } -#define MASK_SRY_MRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } - -#define INSTR_RRF_MRR 6, { M4_16, R_24, R_28, 0, 0, 0 } -#define MASK_RRF_MRR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } - -#define INSTR_SIY_DRI 6, { D20_20, B_16, I8_16, 0, 0, 0 } -#define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } -/* QEMU-END */ - -/* include "s390-opc.tab" generated from opcodes/s390-opc.txt rev 1.17 */ -/* The opcode table. This file was generated by s390-mkopc. - - The format of the opcode table is: - - NAME OPCODE MASK OPERANDS - - Name is the name of the instruction. - OPCODE is the instruction opcode. - MASK is the opcode mask; this is used to tell the disassembler - which bits in the actual opcode must match OPCODE. - OPERANDS is the list of operands. - - The disassembler reads the table in order and prints the first - instruction which matches. */ - -static const struct s390_opcode s390_opcodes[] = - { - { "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "sp", OP8(0xfbLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "ap", OP8(0xfaLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "cp", OP8(0xf9LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "zap", OP8(0xf8LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "unpk", OP8(0xf3LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "pack", OP8(0xf2LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "mvo", OP8(0xf1LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, - { "srp", OP8(0xf0LL), MASK_SS_LIRDRD, INSTR_SS_LIRDRD, 3, 0}, - { "lmd", OP8(0xefLL), MASK_SS_RRRDRD3, INSTR_SS_RRRDRD3, 2, 2}, - { "plo", OP8(0xeeLL), MASK_SS_RRRDRD2, INSTR_SS_RRRDRD2, 3, 0}, - { "stdy", OP48(0xed0000000067LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, - { "stey", OP48(0xed0000000066LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, - { "ldy", OP48(0xed0000000065LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, - { "ley", OP48(0xed0000000064LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, - { "tgxt", OP48(0xed0000000059LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, - { "tcxt", OP48(0xed0000000058LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, - { "tgdt", OP48(0xed0000000055LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, - { "tcdt", OP48(0xed0000000054LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, - { "tget", OP48(0xed0000000051LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, - { "tcet", OP48(0xed0000000050LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, - { "srxt", OP48(0xed0000000049LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, - { "slxt", OP48(0xed0000000048LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, - { "srdt", OP48(0xed0000000041LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, - { "sldt", OP48(0xed0000000040LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, - { "msd", OP48(0xed000000003fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, - { "mad", OP48(0xed000000003eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, - { "myh", OP48(0xed000000003dLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, - { "mayh", OP48(0xed000000003cLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, - { "my", OP48(0xed000000003bLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, - { "may", OP48(0xed000000003aLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, - { "myl", OP48(0xed0000000039LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, - { "mayl", OP48(0xed0000000038LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, - { "mee", OP48(0xed0000000037LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "sqe", OP48(0xed0000000034LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "mse", OP48(0xed000000002fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, - { "mae", OP48(0xed000000002eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, - { "lxe", OP48(0xed0000000026LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "lxd", OP48(0xed0000000025LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "lde", OP48(0xed0000000024LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "msdb", OP48(0xed000000001fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, - { "madb", OP48(0xed000000001eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, - { "ddb", OP48(0xed000000001dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "mdb", OP48(0xed000000001cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "sdb", OP48(0xed000000001bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "adb", OP48(0xed000000001aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "cdb", OP48(0xed0000000019LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "kdb", OP48(0xed0000000018LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "meeb", OP48(0xed0000000017LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "sqdb", OP48(0xed0000000015LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "sqeb", OP48(0xed0000000014LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "tcxb", OP48(0xed0000000012LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "tcdb", OP48(0xed0000000011LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "tceb", OP48(0xed0000000010LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "mseb", OP48(0xed000000000fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, - { "maeb", OP48(0xed000000000eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, - { "deb", OP48(0xed000000000dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "mdeb", OP48(0xed000000000cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "seb", OP48(0xed000000000bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "aeb", OP48(0xed000000000aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "ceb", OP48(0xed0000000009LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "keb", OP48(0xed0000000008LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "mxdb", OP48(0xed0000000007LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "lxeb", OP48(0xed0000000006LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "lxdb", OP48(0xed0000000005LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, - { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, - { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, -/* QEMU-ADD: */ - { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "risbg", OP48(0xec0000000055LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, - { "risbhg", OP48(0xec000000005dLL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, - { "risblg", OP48(0xec0000000051LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, - { "rnsbg", OP48(0xec0000000054LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, - { "rosbg", OP48(0xec0000000056LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, - { "rxsbg", OP48(0xec0000000057LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, - { "cit", OP48(0xec0000000072LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, - { "cgit", OP48(0xec0000000070LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, - { "clfit", OP48(0xec0000000073LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, - { "clgit", OP48(0xec0000000071LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, - { "ahik", OP48(0xec00000000d8LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, - { "aghik", OP48(0xec00000000d9LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, - { "alhsik", OP48(0xec00000000daLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, - { "alghsik", OP48(0xec00000000dbLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, -/* QEMU-END */ - { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, - { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, - { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, - { "lmy", OP48(0xeb0000000098LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "lmh", OP48(0xeb0000000096LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "lmh", OP48(0xeb0000000096LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "stmy", OP48(0xeb0000000090LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "clclu", OP48(0xeb000000008fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "mvclu", OP48(0xeb000000008eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, - { "mvclu", OP48(0xeb000000008eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0}, - { "icmy", OP48(0xeb0000000081LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, - { "icmh", OP48(0xeb0000000080LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, - { "icmh", OP48(0xeb0000000080LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, - { "xiy", OP48(0xeb0000000057LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, - { "oiy", OP48(0xeb0000000056LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, - { "cliy", OP48(0xeb0000000055LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, - { "niy", OP48(0xeb0000000054LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, - { "mviy", OP48(0xeb0000000052LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, - { "tmy", OP48(0xeb0000000051LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, - { "bxleg", OP48(0xeb0000000045LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "bxleg", OP48(0xeb0000000045LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "bxhg", OP48(0xeb0000000044LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "bxhg", OP48(0xeb0000000044LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "cdsg", OP48(0xeb000000003eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "cdsg", OP48(0xeb000000003eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "cdsy", OP48(0xeb0000000031LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "csg", OP48(0xeb0000000030LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "csg", OP48(0xeb0000000030LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "lctlg", OP48(0xeb000000002fLL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, - { "lctlg", OP48(0xeb000000002fLL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, - { "stcmy", OP48(0xeb000000002dLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, - { "stcmh", OP48(0xeb000000002cLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, - { "stcmh", OP48(0xeb000000002cLL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, - { "stmh", OP48(0xeb0000000026LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "stmh", OP48(0xeb0000000026LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "stctg", OP48(0xeb0000000025LL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, - { "stctg", OP48(0xeb0000000025LL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, - { "stmg", OP48(0xeb0000000024LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "stmg", OP48(0xeb0000000024LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "clmy", OP48(0xeb0000000021LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, - { "clmh", OP48(0xeb0000000020LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, - { "clmh", OP48(0xeb0000000020LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, - { "rll", OP48(0xeb000000001dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, - { "rll", OP48(0xeb000000001dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 2}, - { "rllg", OP48(0xeb000000001cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "rllg", OP48(0xeb000000001cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "csy", OP48(0xeb0000000014LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "tracg", OP48(0xeb000000000fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "tracg", OP48(0xeb000000000fLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "sllg", OP48(0xeb000000000dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "sllg", OP48(0xeb000000000dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "srlg", OP48(0xeb000000000cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "srlg", OP48(0xeb000000000cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "slag", OP48(0xeb000000000bLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "slag", OP48(0xeb000000000bLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "srag", OP48(0xeb000000000aLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, - { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, - { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, -/* QEMU-ADD: */ - { "loc", OP48(0xeb00000000f2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, - { "locg", OP48(0xeb00000000e2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, - { "stoc", OP48(0xeb00000000f3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, - { "stocg", OP48(0xeb00000000e3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, - { "srak", OP48(0xeb00000000dcLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, - { "slak", OP48(0xeb00000000ddLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, - { "srlk", OP48(0xeb00000000deLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, - { "sllk", OP48(0xeb00000000dfLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, - { "asi", OP48(0xeb000000006aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, - { "alsi", OP48(0xeb000000006eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, - { "agsi", OP48(0xeb000000007aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, - { "algsi", OP48(0xeb000000007eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, -/* QEMU-END */ - { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, - { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "mvcdk", OP16(0xe50fLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, - { "mvcsk", OP16(0xe50eLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, - { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, - { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, - { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, -/* QEMU-ADD: */ - { "mvhhi", OP16(0xe544LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "mvghi", OP16(0xe548LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "mvhi", OP16(0xe54cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "chhsi", OP16(0xe554LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "clhhsi", OP16(0xe555LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "cghsi", OP16(0xe558LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "clghsi", OP16(0xe559LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "chsi", OP16(0xe55cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, - { "clfhsi", OP16(0xe55dLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, -/* QEMU-END */ - { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "alc", OP48(0xe30000000098LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "dl", OP48(0xe30000000097LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "dl", OP48(0xe30000000097LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "ml", OP48(0xe30000000096LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "ml", OP48(0xe30000000096LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "llh", OP48(0xe30000000095LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, - { "llc", OP48(0xe30000000094LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, - { "llgh", OP48(0xe30000000091LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "llgh", OP48(0xe30000000091LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "llgc", OP48(0xe30000000090LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "llgc", OP48(0xe30000000090LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "lpq", OP48(0xe3000000008fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lpq", OP48(0xe3000000008fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "stpq", OP48(0xe3000000008eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "stpq", OP48(0xe3000000008eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "slbg", OP48(0xe30000000089LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "slbg", OP48(0xe30000000089LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "alcg", OP48(0xe30000000088LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "alcg", OP48(0xe30000000088LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "dlg", OP48(0xe30000000087LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "dlg", OP48(0xe30000000087LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "mlg", OP48(0xe30000000086LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "mlg", OP48(0xe30000000086LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "xg", OP48(0xe30000000082LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "xg", OP48(0xe30000000082LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "og", OP48(0xe30000000081LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "og", OP48(0xe30000000081LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "ng", OP48(0xe30000000080LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "ng", OP48(0xe30000000080LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "shy", OP48(0xe3000000007bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "ahy", OP48(0xe3000000007aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "chy", OP48(0xe30000000079LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lhy", OP48(0xe30000000078LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lgb", OP48(0xe30000000077LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lb", OP48(0xe30000000076LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "icy", OP48(0xe30000000073LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "stcy", OP48(0xe30000000072LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lay", OP48(0xe30000000071LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "sthy", OP48(0xe30000000070LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "sly", OP48(0xe3000000005fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "aly", OP48(0xe3000000005eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "sy", OP48(0xe3000000005bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "ay", OP48(0xe3000000005aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "cy", OP48(0xe30000000059LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "ly", OP48(0xe30000000058LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "xy", OP48(0xe30000000057LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "oy", OP48(0xe30000000056LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "cly", OP48(0xe30000000055LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "ny", OP48(0xe30000000054LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "msy", OP48(0xe30000000051LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "sty", OP48(0xe30000000050LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "bctg", OP48(0xe30000000046LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "bctg", OP48(0xe30000000046LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "strvh", OP48(0xe3000000003fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "strvh", OP48(0xe3000000003fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "strv", OP48(0xe3000000003eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "strv", OP48(0xe3000000003eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "clgf", OP48(0xe30000000031LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "clgf", OP48(0xe30000000031LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "cgf", OP48(0xe30000000030LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "cgf", OP48(0xe30000000030LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "strvg", OP48(0xe3000000002fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "strvg", OP48(0xe3000000002fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "cvdg", OP48(0xe3000000002eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "cvdg", OP48(0xe3000000002eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "cvdy", OP48(0xe30000000026LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "stg", OP48(0xe30000000024LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "stg", OP48(0xe30000000024LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "clg", OP48(0xe30000000021LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "clg", OP48(0xe30000000021LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "cg", OP48(0xe30000000020LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "cg", OP48(0xe30000000020LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "lrvh", OP48(0xe3000000001fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "lrvh", OP48(0xe3000000001fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "lrv", OP48(0xe3000000001eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, - { "lrv", OP48(0xe3000000001eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, - { "dsgf", OP48(0xe3000000001dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "dsgf", OP48(0xe3000000001dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "msgf", OP48(0xe3000000001cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "msgf", OP48(0xe3000000001cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "slgf", OP48(0xe3000000001bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "slgf", OP48(0xe3000000001bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "algf", OP48(0xe3000000001aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "algf", OP48(0xe3000000001aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "sgf", OP48(0xe30000000019LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "sgf", OP48(0xe30000000019LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "agf", OP48(0xe30000000018LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "agf", OP48(0xe30000000018LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "llgt", OP48(0xe30000000017LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "llgt", OP48(0xe30000000017LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "llgf", OP48(0xe30000000016LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "llgf", OP48(0xe30000000016LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "lgh", OP48(0xe30000000015LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lgh", OP48(0xe30000000015LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "lgf", OP48(0xe30000000014LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lgf", OP48(0xe30000000014LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "lray", OP48(0xe30000000013LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lt", OP48(0xe30000000012LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, - { "lrvg", OP48(0xe3000000000fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lrvg", OP48(0xe3000000000fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "cvbg", OP48(0xe3000000000eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "cvbg", OP48(0xe3000000000eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "dsg", OP48(0xe3000000000dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "dsg", OP48(0xe3000000000dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "msg", OP48(0xe3000000000cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "msg", OP48(0xe3000000000cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "slg", OP48(0xe3000000000bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "slg", OP48(0xe3000000000bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "alg", OP48(0xe3000000000aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "alg", OP48(0xe3000000000aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "sg", OP48(0xe30000000009LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "sg", OP48(0xe30000000009LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "ag", OP48(0xe30000000008LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "ag", OP48(0xe30000000008LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "cvby", OP48(0xe30000000006LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lg", OP48(0xe30000000004LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lg", OP48(0xe30000000004LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, - { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, - { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, -/* QEMU-ADD: */ - { "pfd", OP48(0xe30000000036LL), MASK_RXY_URRD, INSTR_RXY_URRD, 3, 6}, -/* QEMU-END */ - { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "ed", OP8(0xdeLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "trt", OP8(0xddLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "tr", OP8(0xdcLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "mvcs", OP8(0xdbLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, - { "mvcp", OP8(0xdaLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, - { "mvck", OP8(0xd9LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, - { "xc", OP8(0xd7LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "oc", OP8(0xd6LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "clc", OP8(0xd5LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "nc", OP8(0xd4LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "mvz", OP8(0xd3LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "mvc", OP8(0xd2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "mvn", OP8(0xd1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, - { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, - { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, - { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, -/* QEMU-ADD: */ - { "exrl", OP16(0xc600ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "pfdrl", OP16(0xc602ll), MASK_RIL_UP, INSTR_RIL_UP, 3, 6}, - { "cghrl", OP16(0xc604ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "chrl", OP16(0xc605ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "clghrl", OP16(0xc606ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "clhrl", OP16(0xc607ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "cgrl", OP16(0xc608ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "clgrl", OP16(0xc60all), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "cgfrl", OP16(0xc60cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "crl", OP16(0xc60dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "clgfrl", OP16(0xc60ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "clrl", OP16(0xc60fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - - { "llhrl", OP16(0xc400ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lghrl", OP16(0xc404ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lhrl", OP16(0xc405ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "llghrl", OP16(0xc406ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "sthrl", OP16(0xc407ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "stgrl", OP16(0xc40bll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "llgfrl", OP16(0xc40ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "strl", OP16(0xc40fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, -/* QEMU-END */ - { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, - { "cgfi", OP16(0xc20cLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, - { "alfi", OP16(0xc20bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "algfi", OP16(0xc20aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "afi", OP16(0xc209LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, - { "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, - { "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, -/* QEMU-ADD: */ - { "msfi", OP16(0xc201ll), MASK_RIL_RI, INSTR_RIL_RI, 3, 6}, - { "msgfi", OP16(0xc200ll), MASK_RIL_RI, INSTR_RIL_RI, 3, 6}, -/* QEMU-END */ - { "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnp", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgle", OP16(0xc0c4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnl", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnm", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jghe", OP16(0xc0a4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnlh", OP16(0xc094LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jge", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgz", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgne", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnz", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jglh", OP16(0xc064LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnhe", OP16(0xc054LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgl", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgm", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgnle", OP16(0xc034LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgh", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgp", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "jgo", OP16(0xc014LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, - { "llilf", OP16(0xc00fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "llihf", OP16(0xc00eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "oilf", OP16(0xc00dLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "oihf", OP16(0xc00cLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "nilf", OP16(0xc00bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "nihf", OP16(0xc00aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "iilf", OP16(0xc009LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "iihf", OP16(0xc008LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "xilf", OP16(0xc007LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "xihf", OP16(0xc006LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, - { "brasl", OP16(0xc005LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, - { "brcl", OP16(0xc004LL), MASK_RIL_UP, INSTR_RIL_UP, 3, 2}, - { "lgfi", OP16(0xc001LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, - { "larl", OP16(0xc000LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, - { "icm", OP8(0xbfLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, - { "stcm", OP8(0xbeLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, - { "clm", OP8(0xbdLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, - { "cds", OP8(0xbbLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "cs", OP8(0xbaLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "cu42", OP16(0xb9b3LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cu41", OP16(0xb9b2LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cu24", OP16(0xb9b1LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cu14", OP16(0xb9b0LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "lptea", OP16(0xb9aaLL), MASK_RRF_RURR, INSTR_RRF_RURR, 2, 4}, - { "esea", OP16(0xb99dLL), MASK_RRE_R0, INSTR_RRE_R0, 2, 2}, - { "slbr", OP16(0xb999LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, - { "alcr", OP16(0xb998LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, - { "dlr", OP16(0xb997LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, - { "mlr", OP16(0xb996LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, - { "llhr", OP16(0xb995LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "llcr", OP16(0xb994LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "troo", OP16(0xb993LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, - { "troo", OP16(0xb993LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "trot", OP16(0xb992LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, - { "trot", OP16(0xb992LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "trto", OP16(0xb991LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, - { "trto", OP16(0xb991LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "trtt", OP16(0xb990LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, - { "trtt", OP16(0xb990LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "idte", OP16(0xb98eLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 2, 3}, - { "epsw", OP16(0xb98dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, - { "cspg", OP16(0xb98aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 3}, - { "slbgr", OP16(0xb989LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "alcgr", OP16(0xb988LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "dlgr", OP16(0xb987LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "mlgr", OP16(0xb986LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "llghr", OP16(0xb985LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "llgcr", OP16(0xb984LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "flogr", OP16(0xb983LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "xgr", OP16(0xb982LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "ogr", OP16(0xb981LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "ngr", OP16(0xb980LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "bctgr", OP16(0xb946LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "klmd", OP16(0xb93fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, - { "kimd", OP16(0xb93eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, - { "clgfr", OP16(0xb931LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cgfr", OP16(0xb930LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "kmc", OP16(0xb92fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, - { "km", OP16(0xb92eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, - { "lhr", OP16(0xb927LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "lbr", OP16(0xb926LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "sturg", OP16(0xb925LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "clgr", OP16(0xb921LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cgr", OP16(0xb920LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lrvr", OP16(0xb91fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, - { "kmac", OP16(0xb91eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, - { "dsgfr", OP16(0xb91dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "msgfr", OP16(0xb91cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "slgfr", OP16(0xb91bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "algfr", OP16(0xb91aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "sgfr", OP16(0xb919LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "agfr", OP16(0xb918LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "llgtr", OP16(0xb917LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "llgfr", OP16(0xb916LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lgfr", OP16(0xb914LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lcgfr", OP16(0xb913LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "ltgfr", OP16(0xb912LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lngfr", OP16(0xb911LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lpgfr", OP16(0xb910LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lrvgr", OP16(0xb90fLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "eregg", OP16(0xb90eLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "dsgr", OP16(0xb90dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "msgr", OP16(0xb90cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "slgr", OP16(0xb90bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "algr", OP16(0xb90aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "sgr", OP16(0xb909LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "agr", OP16(0xb908LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lghr", OP16(0xb907LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "lgbr", OP16(0xb906LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, - { "lurag", OP16(0xb905LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lgr", OP16(0xb904LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lcgr", OP16(0xb903LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, -/* QEMU-ADD: */ - { "crt", OP16(0xb972LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, - { "cgrt", OP16(0xb960LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, - { "clrt", OP16(0xb973LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, - { "clgrt", OP16(0xb961LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, - { "locr", OP16(0xb9f2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, - { "locgr", OP16(0xb9e2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, - { "popcnt", OP16(0xb9e1LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 6}, - { "ngrk", OP16(0xb9e4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "ogrk", OP16(0xb9e6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "xgrk", OP16(0xb9e7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "agrk", OP16(0xb9e8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "sgrk", OP16(0xb9e9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "algrk", OP16(0xb9eaLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "slgrk", OP16(0xb9ebLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "nrk", OP16(0xb9f4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "ork", OP16(0xb9f6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "xrk", OP16(0xb9f7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "ark", OP16(0xb9f8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "srk", OP16(0xb9f9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "alrk", OP16(0xb9faLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, - { "slrk", OP16(0xb9fbLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, -/* QEMU-END */ - { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, - { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, - { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, - { "iextr", OP16(0xb3feLL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, - { "qaxtr", OP16(0xb3fdLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, - { "cextr", OP16(0xb3fcLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "cxstr", OP16(0xb3fbLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "cxutr", OP16(0xb3faLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "cxgtr", OP16(0xb3f9LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "rrdtr", OP16(0xb3f7LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, - { "iedtr", OP16(0xb3f6LL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, - { "qadtr", OP16(0xb3f5LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, - { "cedtr", OP16(0xb3f4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "cdstr", OP16(0xb3f3LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "cdutr", OP16(0xb3f2LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "cdgtr", OP16(0xb3f1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "esxtr", OP16(0xb3efLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "eextr", OP16(0xb3edLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cxtr", OP16(0xb3ecLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "csxtr", OP16(0xb3ebLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cuxtr", OP16(0xb3eaLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cgxtr", OP16(0xb3e9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, - { "kxtr", OP16(0xb3e8LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "esdtr", OP16(0xb3e7LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "eedtr", OP16(0xb3e5LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cdtr", OP16(0xb3e4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "csdtr", OP16(0xb3e3LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cudtr", OP16(0xb3e2LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cgdtr", OP16(0xb3e1LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, - { "kdtr", OP16(0xb3e0LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "fixtr", OP16(0xb3dfLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, - { "ltxtr", OP16(0xb3deLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "ldxtr", OP16(0xb3ddLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, - { "lxdtr", OP16(0xb3dcLL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, - { "sxtr", OP16(0xb3dbLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "axtr", OP16(0xb3daLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "dxtr", OP16(0xb3d9LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "mxtr", OP16(0xb3d8LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "fidtr", OP16(0xb3d7LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, - { "ltdtr", OP16(0xb3d6LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "ledtr", OP16(0xb3d5LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, - { "ldetr", OP16(0xb3d4LL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, - { "sdtr", OP16(0xb3d3LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "adtr", OP16(0xb3d2LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "ddtr", OP16(0xb3d1LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "mdtr", OP16(0xb3d0LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, - { "lgdr", OP16(0xb3cdLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, - { "cgxr", OP16(0xb3caLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cgdr", OP16(0xb3c9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cger", OP16(0xb3c8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cxgr", OP16(0xb3c6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cdgr", OP16(0xb3c5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cegr", OP16(0xb3c4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "ldgr", OP16(0xb3c1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, - { "cfxr", OP16(0xb3baLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cfdr", OP16(0xb3b9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cfer", OP16(0xb3b8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cxfr", OP16(0xb3b6LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, - { "cdfr", OP16(0xb3b5LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, - { "cefr", OP16(0xb3b4LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, - { "cgxbr", OP16(0xb3aaLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cgdbr", OP16(0xb3a9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cgebr", OP16(0xb3a8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, - { "cxgbr", OP16(0xb3a6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cdgbr", OP16(0xb3a5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cegbr", OP16(0xb3a4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, - { "cfxbr", OP16(0xb39aLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, - { "cfdbr", OP16(0xb399LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, - { "cfebr", OP16(0xb398LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, - { "cxfbr", OP16(0xb396LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, - { "cdfbr", OP16(0xb395LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, - { "cefbr", OP16(0xb394LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, - { "efpc", OP16(0xb38cLL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, - { "sfasr", OP16(0xb385LL), MASK_RRE_R0, INSTR_RRE_R0, 2, 5}, - { "sfpc", OP16(0xb384LL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, - { "fidr", OP16(0xb37fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "fier", OP16(0xb377LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "lzxr", OP16(0xb376LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "lzdr", OP16(0xb375LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "lzer", OP16(0xb374LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "lcdfr", OP16(0xb373LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "cpsdr", OP16(0xb372LL), MASK_RRF_F0FF2, INSTR_RRF_F0FF2, 2, 5}, - { "lndfr", OP16(0xb371LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "lpdfr", OP16(0xb370LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, - { "cxr", OP16(0xb369LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "fixr", OP16(0xb367LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "lexr", OP16(0xb366LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lxr", OP16(0xb365LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "lcxr", OP16(0xb363LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ltxr", OP16(0xb362LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lnxr", OP16(0xb361LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lpxr", OP16(0xb360LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "fidbr", OP16(0xb35fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "didbr", OP16(0xb35bLL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, - { "thdr", OP16(0xb359LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "thder", OP16(0xb358LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "fiebr", OP16(0xb357LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "diebr", OP16(0xb353LL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, - { "tbdr", OP16(0xb351LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "tbedr", OP16(0xb350LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "dxbr", OP16(0xb34dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "mxbr", OP16(0xb34cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sxbr", OP16(0xb34bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "axbr", OP16(0xb34aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "cxbr", OP16(0xb349LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "kxbr", OP16(0xb348LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "fixbr", OP16(0xb347LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, - { "lexbr", OP16(0xb346LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ldxbr", OP16(0xb345LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ledbr", OP16(0xb344LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lcxbr", OP16(0xb343LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ltxbr", OP16(0xb342LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lnxbr", OP16(0xb341LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lpxbr", OP16(0xb340LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "msdr", OP16(0xb33fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, - { "madr", OP16(0xb33eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, - { "myhr", OP16(0xb33dLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, - { "mayhr", OP16(0xb33cLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, - { "myr", OP16(0xb33bLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, - { "mayr", OP16(0xb33aLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, - { "mylr", OP16(0xb339LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, - { "maylr", OP16(0xb338LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, - { "meer", OP16(0xb337LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sqxr", OP16(0xb336LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "mser", OP16(0xb32fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, - { "maer", OP16(0xb32eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, - { "lxer", OP16(0xb326LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lxdr", OP16(0xb325LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lder", OP16(0xb324LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "msdbr", OP16(0xb31fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, - { "madbr", OP16(0xb31eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, - { "ddbr", OP16(0xb31dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "mdbr", OP16(0xb31cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sdbr", OP16(0xb31bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "adbr", OP16(0xb31aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "cdbr", OP16(0xb319LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "kdbr", OP16(0xb318LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "meebr", OP16(0xb317LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sqxbr", OP16(0xb316LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sqdbr", OP16(0xb315LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sqebr", OP16(0xb314LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lcdbr", OP16(0xb313LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ltdbr", OP16(0xb312LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lndbr", OP16(0xb311LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lpdbr", OP16(0xb310LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "msebr", OP16(0xb30fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, - { "maebr", OP16(0xb30eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, - { "debr", OP16(0xb30dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "mdebr", OP16(0xb30cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "sebr", OP16(0xb30bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "aebr", OP16(0xb30aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "cebr", OP16(0xb309LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "kebr", OP16(0xb308LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "mxdbr", OP16(0xb307LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lxebr", OP16(0xb306LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lxdbr", OP16(0xb305LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ldebr", OP16(0xb304LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lcebr", OP16(0xb303LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, - { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, -/* QEMU-ADD: */ - { "clfebr", OP16(0xb39cLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "clfdbr", OP16(0xb39dLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "clfxbr", OP16(0xb39eLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "clgebr", OP16(0xb3acLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "clgdbr", OP16(0xb3adLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "clgxbr", OP16(0xb3aeLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "celfbr", OP16(0xb390LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "cdlfbr", OP16(0xb391LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "cxlfbr", OP16(0xb392LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "celgbr", OP16(0xb3a0LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "cdlgbr", OP16(0xb3a1LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, - { "cxlgbr", OP16(0xb3a2LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, -/* QEMU-END */ - { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, - { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, - { "lpswe", OP16(0xb2b2LL), MASK_S_RD, INSTR_S_RD, 2, 2}, - { "stfl", OP16(0xb2b1LL), MASK_S_RD, INSTR_S_RD, 3, 2}, - { "stfle", OP16(0xb2b0LL), MASK_S_RD, INSTR_S_RD, 2, 4}, - { "cu12", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cutfu", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cutfu", OP16(0xb2a7LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "cu21", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cuutf", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "cuutf", OP16(0xb2a6LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "tre", OP16(0xb2a5LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "lfpc", OP16(0xb29dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stfpc", OP16(0xb29cLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "srnm", OP16(0xb299LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stsi", OP16(0xb27dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stckf", OP16(0xb27cLL), MASK_S_RD, INSTR_S_RD, 2, 4}, - { "sacf", OP16(0xb279LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stcke", OP16(0xb278LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "rp", OP16(0xb277LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "xsch", OP16(0xb276LL), MASK_S_00, INSTR_S_00, 3, 0}, - { "siga", OP16(0xb274LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "srst", OP16(0xb25eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "clst", OP16(0xb25dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "bsa", OP16(0xb25aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "bsg", OP16(0xb258LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "cuse", OP16(0xb257LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "mvst", OP16(0xb255LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "mvpg", OP16(0xb254LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "msr", OP16(0xb252LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "csp", OP16(0xb250LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "ear", OP16(0xb24fLL), MASK_RRE_RA, INSTR_RRE_RA, 3, 0}, - { "sar", OP16(0xb24eLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, - { "cpya", OP16(0xb24dLL), MASK_RRE_AA, INSTR_RRE_AA, 3, 0}, - { "tar", OP16(0xb24cLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, - { "lura", OP16(0xb24bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "esta", OP16(0xb24aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "ereg", OP16(0xb249LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "palb", OP16(0xb248LL), MASK_RRE_00, INSTR_RRE_00, 3, 0}, - { "msta", OP16(0xb247LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "stura", OP16(0xb246LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "sqer", OP16(0xb245LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, - { "sqdr", OP16(0xb244LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, - { "cksm", OP16(0xb241LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "bakr", OP16(0xb240LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "schm", OP16(0xb23cLL), MASK_S_00, INSTR_S_00, 3, 0}, - { "rchp", OP16(0xb23bLL), MASK_S_00, INSTR_S_00, 3, 0}, - { "stcps", OP16(0xb23aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stcrw", OP16(0xb239LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "rsch", OP16(0xb238LL), MASK_S_00, INSTR_S_00, 3, 0}, - { "sal", OP16(0xb237LL), MASK_S_00, INSTR_S_00, 3, 0}, - { "tpi", OP16(0xb236LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "tsch", OP16(0xb235LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stsch", OP16(0xb234LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "ssch", OP16(0xb233LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "msch", OP16(0xb232LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "hsch", OP16(0xb231LL), MASK_S_00, INSTR_S_00, 3, 0}, - { "csch", OP16(0xb230LL), MASK_S_00, INSTR_S_00, 3, 0}, - { "pgout", OP16(0xb22fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "pgin", OP16(0xb22eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "dxr", OP16(0xb22dLL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, - { "tb", OP16(0xb22cLL), MASK_RRE_0R, INSTR_RRE_0R, 3, 0}, - { "sske", OP16(0xb22bLL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, - { "sske", OP16(0xb22bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "rrbe", OP16(0xb22aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "iske", OP16(0xb229LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "pt", OP16(0xb228LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "esar", OP16(0xb227LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "epar", OP16(0xb226LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "ssar", OP16(0xb225LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "iac", OP16(0xb224LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "ivsk", OP16(0xb223LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "ipm", OP16(0xb222LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, - { "ipte", OP16(0xb221LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, - { "cfc", OP16(0xb21aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "sac", OP16(0xb219LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "pc", OP16(0xb218LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "sie", OP16(0xb214LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stap", OP16(0xb212LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stpx", OP16(0xb211LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "spx", OP16(0xb210LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "ptlb", OP16(0xb20dLL), MASK_S_00, INSTR_S_00, 3, 0}, - { "ipk", OP16(0xb20bLL), MASK_S_00, INSTR_S_00, 3, 0}, - { "spka", OP16(0xb20aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stpt", OP16(0xb209LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "spt", OP16(0xb208LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stckc", OP16(0xb207LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "sckc", OP16(0xb206LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stck", OP16(0xb205LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "sck", OP16(0xb204LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "stidp", OP16(0xb202LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "lra", OP8(0xb1LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "mc", OP8(0xafLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "sigp", OP8(0xaeLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "stosm", OP8(0xadLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "stnsm", OP8(0xacLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "clcle", OP8(0xa9LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "mvcle", OP8(0xa8LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "j", OP16(0xa7f4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jno", OP16(0xa7e4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnh", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnp", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jle", OP16(0xa7c4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnl", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnm", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jhe", OP16(0xa7a4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnlh", OP16(0xa794LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "je", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jz", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jne", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnz", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jlh", OP16(0xa764LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnhe", OP16(0xa754LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jl", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jm", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jnle", OP16(0xa734LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jh", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jp", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "jo", OP16(0xa714LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, - { "cghi", OP16(0xa70fLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, - { "chi", OP16(0xa70eLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, - { "mghi", OP16(0xa70dLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, - { "mhi", OP16(0xa70cLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, - { "aghi", OP16(0xa70bLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, - { "ahi", OP16(0xa70aLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, - { "lghi", OP16(0xa709LL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, - { "lhi", OP16(0xa708LL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, - { "brctg", OP16(0xa707LL), MASK_RI_RP, INSTR_RI_RP, 2, 2}, - { "brct", OP16(0xa706LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, - { "bras", OP16(0xa705LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, - { "brc", OP16(0xa704LL), MASK_RI_UP, INSTR_RI_UP, 3, 0}, - { "tmhl", OP16(0xa703LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "tmhh", OP16(0xa702LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "tml", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, - { "tmll", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, - { "tmh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, - { "tmlh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, - { "llill", OP16(0xa50fLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "llilh", OP16(0xa50eLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "llihl", OP16(0xa50dLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "llihh", OP16(0xa50cLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "oill", OP16(0xa50bLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "oilh", OP16(0xa50aLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "oihl", OP16(0xa509LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "oihh", OP16(0xa508LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "nill", OP16(0xa507LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "nilh", OP16(0xa506LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "nihl", OP16(0xa505LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "nihh", OP16(0xa504LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "iill", OP16(0xa503LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "iilh", OP16(0xa502LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "iihl", OP16(0xa501LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "iihh", OP16(0xa500LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, - { "stam", OP8(0x9bLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, - { "lam", OP8(0x9aLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, - { "trace", OP8(0x99LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "lm", OP8(0x98LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "xi", OP8(0x97LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "oi", OP8(0x96LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "cli", OP8(0x95LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "ni", OP8(0x94LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "ts", OP8(0x93LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "mvi", OP8(0x92LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "tm", OP8(0x91LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, - { "stm", OP8(0x90LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "slda", OP8(0x8fLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "srda", OP8(0x8eLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "sldl", OP8(0x8dLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "srdl", OP8(0x8cLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "sla", OP8(0x8bLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "sra", OP8(0x8aLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "sll", OP8(0x89LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "srl", OP8(0x88LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, - { "bxle", OP8(0x87LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "bxh", OP8(0x86LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "brxle", OP8(0x85LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, - { "brxh", OP8(0x84LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, - { "diag", OP8(0x83LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, - { "lpsw", OP8(0x82LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "ssm", OP8(0x80LL), MASK_S_RD, INSTR_S_RD, 3, 0}, - { "su", OP8(0x7fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "au", OP8(0x7eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "de", OP8(0x7dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "me", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "mde", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "se", OP8(0x7bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "ae", OP8(0x7aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "ce", OP8(0x79LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "le", OP8(0x78LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "ms", OP8(0x71LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "ste", OP8(0x70LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "sw", OP8(0x6fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "aw", OP8(0x6eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "dd", OP8(0x6dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "md", OP8(0x6cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "sd", OP8(0x6bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "ad", OP8(0x6aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "cd", OP8(0x69LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "ld", OP8(0x68LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "mxd", OP8(0x67LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "std", OP8(0x60LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, - { "sl", OP8(0x5fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "al", OP8(0x5eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "d", OP8(0x5dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "m", OP8(0x5cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "s", OP8(0x5bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "a", OP8(0x5aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "c", OP8(0x59LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "l", OP8(0x58LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "x", OP8(0x57LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "o", OP8(0x56LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "cl", OP8(0x55LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "n", OP8(0x54LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "lae", OP8(0x51LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "st", OP8(0x50LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "cvb", OP8(0x4fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "cvd", OP8(0x4eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "bas", OP8(0x4dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "mh", OP8(0x4cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "sh", OP8(0x4bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "ah", OP8(0x4aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "ch", OP8(0x49LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "lh", OP8(0x48LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "b", OP16(0x47f0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bno", OP16(0x47e0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnh", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnp", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "ble", OP16(0x47c0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnl", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnm", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bhe", OP16(0x47a0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnlh", OP16(0x4790LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "be", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bz", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bne", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnz", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "blh", OP16(0x4760LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnhe", OP16(0x4750LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bl", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bm", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bnle", OP16(0x4730LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bh", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bp", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bo", OP16(0x4710LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bc", OP8(0x47LL), MASK_RX_URRD, INSTR_RX_URRD, 3, 0}, - { "nop", OP16(0x4700LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, - { "bct", OP8(0x46LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "bal", OP8(0x45LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "ex", OP8(0x44LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "ic", OP8(0x43LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "stc", OP8(0x42LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "la", OP8(0x41LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "sth", OP8(0x40LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, - { "sur", OP8(0x3fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "aur", OP8(0x3eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "der", OP8(0x3dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "mer", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "mder", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ser", OP8(0x3bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "aer", OP8(0x3aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "cer", OP8(0x39LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ler", OP8(0x38LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "sxr", OP8(0x37LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "axr", OP8(0x36LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lrer", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ledr", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "her", OP8(0x34LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lcer", OP8(0x33LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lter", OP8(0x32LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lner", OP8(0x31LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lper", OP8(0x30LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "swr", OP8(0x2fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "awr", OP8(0x2eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ddr", OP8(0x2dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "mdr", OP8(0x2cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "sdr", OP8(0x2bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "adr", OP8(0x2aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "cdr", OP8(0x29LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ldr", OP8(0x28LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "mxdr", OP8(0x27LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "mxr", OP8(0x26LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lrdr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ldxr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "hdr", OP8(0x24LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lcdr", OP8(0x23LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "ltdr", OP8(0x22LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lndr", OP8(0x21LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "lpdr", OP8(0x20LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, - { "slr", OP8(0x1fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "alr", OP8(0x1eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "dr", OP8(0x1dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "mr", OP8(0x1cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "sr", OP8(0x1bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "ar", OP8(0x1aLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "cr", OP8(0x19LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "lr", OP8(0x18LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "xr", OP8(0x17LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "or", OP8(0x16LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "clr", OP8(0x15LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "nr", OP8(0x14LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "lcr", OP8(0x13LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "ltr", OP8(0x12LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "lnr", OP8(0x11LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "lpr", OP8(0x10LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "clcl", OP8(0x0fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "mvcl", OP8(0x0eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "basr", OP8(0x0dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "bassm", OP8(0x0cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "bsm", OP8(0x0bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "svc", OP8(0x0aLL), MASK_RR_U0, INSTR_RR_U0, 3, 0}, - { "br", OP16(0x07f0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnor", OP16(0x07e0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnhr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnpr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bler", OP16(0x07c0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnlr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnmr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bher", OP16(0x07a0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnlhr", OP16(0x0790LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "ber", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bzr", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bner", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnzr", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "blhr", OP16(0x0760LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnher", OP16(0x0750LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "blr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bmr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bnler", OP16(0x0730LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bhr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bpr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bor", OP16(0x0710LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bcr", OP8(0x07LL), MASK_RR_UR, INSTR_RR_UR, 3, 0}, - { "nopr", OP16(0x0700LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, - { "bctr", OP8(0x06LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "balr", OP8(0x05LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, - { "spm", OP8(0x04LL), MASK_RR_R0, INSTR_RR_R0, 3, 0}, - { "trap2", OP16(0x01ffLL), MASK_E, INSTR_E, 3, 0}, - { "sam64", OP16(0x010eLL), MASK_E, INSTR_E, 2, 2}, - { "sam31", OP16(0x010dLL), MASK_E, INSTR_E, 3, 2}, - { "sam24", OP16(0x010cLL), MASK_E, INSTR_E, 3, 2}, - { "tam", OP16(0x010bLL), MASK_E, INSTR_E, 3, 2}, - { "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5}, - { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, - { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, - { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0}, -}; - -static const int s390_num_opcodes = - sizeof (s390_opcodes) / sizeof (s390_opcodes[0]); diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index c29a4b8fe649..1c1e7b9e11c3 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 @@ -80,18 +83,30 @@ Ubuntu LTS. Other distros will be assumed to ship similar software versions. For FreeBSD and OpenBSD, decisions will be made based on the contents of the respective ports repository, while NetBSD will use the pkgsrc repository. -For macOS, `HomeBrew`_ will be used, although `MacPorts`_ is expected to carry +For macOS, `Homebrew`_ will be used, although `MacPorts`_ is expected to carry similar versions. Windows ------- -The project supports building with current versions of the MinGW toolchain, -hosted on Linux (Debian/Fedora). - -The version of the Windows API that's currently targeted is Vista / Server -2008. - -.. _HomeBrew: https://brew.sh/ +The project aims to support the two most recent versions of Windows that are +still supported by the vendor. The minimum Windows API that is currently +targeted is "Windows 8", so theoretically the QEMU binaries can still be run +on older versions of Windows, too. However, such old versions of Windows are +not tested anymore, so it is recommended to use one of the latest versions of +Windows instead. + +The project supports building QEMU with current versions of the MinGW +toolchain, either hosted on Linux (Debian/Fedora) or via `MSYS2`_ on Windows. +A more recent Windows version is always preferred as it is less likely to have +problems with building via MSYS2. The building process of QEMU involves some +Python scripts that call os.symlink() which needs special attention for the +build process to successfully complete. On newer versions of Windows 10, +unprivileged accounts can create symlinks if Developer Mode is enabled. +When Developer Mode is not available/enabled, the SeCreateSymbolicLinkPrivilege +privilege is required, or the process must be run as an administrator. + +.. _Homebrew: https://brew.sh/ .. _MacPorts: https://www.macports.org/ +.. _MSYS2: https://www.msys2.org/ .. _Repology: https://repology.org/ diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index cf02ef6821e4..68d29642d7c0 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -39,21 +39,6 @@ should specify an ``audiodev=`` property. Additionally, when using vnc, you should specify an ``audiodev=`` property if you plan to transmit audio through the VNC protocol. -Creating sound card devices using ``-soundhw`` (since 5.1) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Sound card devices should be created using ``-device`` instead. The -names are the same for most devices. The exceptions are ``hda`` which -needs two devices (``-device intel-hda -device hda-duplex``) and -``pcspk`` which can be activated using ``-machine -pcspk-audiodev=``. - -``-chardev`` backend aliases ``tty`` and ``parport`` (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -``tty`` and ``parport`` are aliases that will be removed. Instead, the -actual backend names ``serial`` and ``parallel`` should be used. - Short-form boolean options (since 6.0) '''''''''''''''''''''''''''''''''''''' @@ -67,40 +52,6 @@ and will cause a warning. The replacement for the ``nodelay`` short-form boolean option is ``nodelay=on`` rather than ``delay=off``. -``--enable-fips`` (since 6.0) -''''''''''''''''''''''''''''' - -This option restricts usage of certain cryptographic algorithms when -the host is operating in FIPS mode. - -If FIPS compliance is required, QEMU should be built with the ``libgcrypt`` -library enabled as a cryptography provider. - -Neither the ``nettle`` library, or the built-in cryptography provider are -supported on FIPS enabled hosts. - -``-writeconfig`` (since 6.0) -''''''''''''''''''''''''''''' - -The ``-writeconfig`` option is not able to serialize the entire contents -of the QEMU command line. It is thus considered a failed experiment -and deprecated, with no current replacement. - -Userspace local APIC with KVM (x86, since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''' - -Using ``-M kernel-irqchip=off`` with x86 machine types that include a local -APIC is deprecated. The ``split`` setting is supported, as is using -``-M kernel-irqchip=off`` with the ISA PC machine type. - -hexadecimal sizes with scaling multipliers (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Input parameters that take a size value should only use a size suffix -(such as 'k' or 'M') when the base is written in decimal, and not when -the value is hexadecimal. That is, '0x20M' is deprecated, and should -be written either as '32M' or as '0x2000000'. - ``-spice password=string`` (since 6.0) '''''''''''''''''''''''''''''''''''''' @@ -109,56 +60,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. -``opened`` property of ``rng-*`` objects (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''' - -The only effect of specifying ``opened=on`` in the command line or QMP -``object-add`` is that the device is opened immediately, possibly before all -other options have been processed. This will either have no effect (if -``opened`` was the last option) or cause errors. The property is therefore -useless and should not be specified. - -``loaded`` property of ``secret`` and ``secret_keyring`` objects (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The only effect of specifying ``loaded=on`` in the command line or QMP -``object-add`` is that the secret is loaded immediately, possibly before all -other options have been processed. This will either have no effect (if -``loaded`` was the last option) or cause options to be effectively ignored as -if they were not given. The property is therefore useless and should not be -specified. - -``-display sdl,window_close=...`` (since 6.1) -''''''''''''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,window-close=...`` instead (i.e. with a minus instead of -an underscore between "window" and "close"). - -``-alt-grab`` and ``-display sdl,alt_grab=on`` (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. - -``-ctrl-grab`` and ``-display sdl,ctrl_grab=on`` (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,grab-mod=rctrl`` instead. - -``-sdl`` (since 6.2) -'''''''''''''''''''' - -Use ``-display sdl`` instead. - -``-curses`` (since 6.2) -''''''''''''''''''''''' - -Use ``-display curses`` instead. - -``-watchdog`` (since 6.2) -''''''''''''''''''''''''' - -Use ``-device`` instead. - ``-smp`` ("parameter=0" SMP configurations) (since 6.2) ''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -192,6 +93,12 @@ form is preferred. Using ``-drive if=none`` to configure the OTP device of the sifive_u RISC-V machine is deprecated. Use ``-drive if=pflash`` instead. +``-no-hpet`` (since 8.0) +'''''''''''''''''''''''' + +The HPET setting has been turned into a machine property. +Use ``-machine hpet=off`` instead. + QEMU Machine Protocol (QMP) commands ------------------------------------ @@ -264,19 +171,6 @@ accepted incorrect commands will return an error. Users should make sure that all arguments passed to ``device_add`` are consistent with the documented property types. -``query-sgx`` return value member ``section-size`` (since 7.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Member ``section-size`` in return value elements with meta-type ``uint64`` is -deprecated. Use ``sections`` instead. - - -``query-sgx-capabilities`` return value member ``section-size`` (since 7.0) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Member ``section-size`` in return value elements with meta-type ``uint64`` is -deprecated. Use ``sections`` instead. - System accelerators ------------------- @@ -286,22 +180,18 @@ 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. -System emulator CPUS --------------------- - -``Icelake-Client`` CPU Model (since 5.2) -'''''''''''''''''''''''''''''''''''''''' +Host Architectures +------------------ -``Icelake-Client`` CPU Models are deprecated. Use ``Icelake-Server`` CPU -Models instead. - -MIPS ``I7200`` CPU Model (since 5.2) -'''''''''''''''''''''''''''''''''''' - -The ``I7200`` guest CPU relies on the nanoMIPS ISA, which is deprecated -(the ISA has never been upstreamed to a compiler toolchain). Therefore -this CPU is also deprecated. +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 ---------------------- @@ -315,14 +205,13 @@ Use the more generic event ``DEVICE_UNPLUG_GUEST_ERROR`` instead. System emulator machines ------------------------ -PPC 405 ``taihu`` machine (since 7.0) -''''''''''''''''''''''''''''''''''''' +Arm ``virt`` machine ``dtb-kaslr-seed`` property +'''''''''''''''''''''''''''''''''''''''''''''''' -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. +The ``dtb-kaslr-seed`` property on the ``virt`` board has been +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. ``pc-i440fx-1.4`` up to ``pc-i440fx-1.7`` (since 7.0) ''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -375,6 +264,21 @@ contains native support for this feature and thus use of the option ROM approach is obsolete. The native SeaBIOS support can be activated by using ``-machine graphics=off``. +``-device nvme-ns,eui64-default=on|off`` (since 7.1) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In QEMU versions 6.1, 6.2 and 7.0, the ``nvme-ns`` generates an EUI-64 +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) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``nvme`` device originally used a PCI Vendor/Device Identifier combination +from Intel that was not properly allocated. Since version 5.2, the controller +has used a properly allocated identifier. Deprecate the ``use-intel-id`` +machine compatibility parameter. + Block device options '''''''''''''''''''' @@ -401,16 +305,6 @@ The above, converted to the current supported format:: json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"} -linux-user mode CPUs --------------------- - -MIPS ``I7200`` CPU (since 5.2) -'''''''''''''''''''''''''''''' - -The ``I7200`` guest CPU relies on the nanoMIPS ISA, which is deprecated -(the ISA has never been upstreamed to a compiler toolchain). Therefore -this CPU is also deprecated. - Backwards compatibility ----------------------- @@ -440,15 +334,6 @@ versions, aliases will point to newer CPU model versions depending on the machine type, so management software must resolve CPU model aliases before starting a virtual machine. -Guest Emulator ISAs -------------------- - -nanoMIPS ISA -'''''''''''' - -The ``nanoMIPS`` ISA has never been upstreamed to any compiler toolchain. -As it is hard to generate binaries for it, declare it deprecated. - Tools ----- @@ -465,3 +350,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 4b831ea29176..c918cabd1aaa 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -336,6 +336,91 @@ for the RISC-V ``virt`` machine and ``sifive_u`` machine. The ``-no-quit`` was a synonym for ``-display ...,window-close=off`` which should be used instead. +``--enable-fips`` (removed in 7.1) +'''''''''''''''''''''''''''''''''' + +This option restricted usage of certain cryptographic algorithms when +the host is operating in FIPS mode. + +If FIPS compliance is required, QEMU should be built with the ``libgcrypt`` +or ``gnutls`` library enabled as a cryptography provider. + +Neither the ``nettle`` library, or the built-in cryptography provider are +supported on FIPS enabled hosts. + +``-writeconfig`` (removed in 7.1) +''''''''''''''''''''''''''''''''' + +The ``-writeconfig`` option was not able to serialize the entire contents +of the QEMU command line. It is thus considered a failed experiment +and removed without a replacement. + +``loaded`` property of ``secret`` and ``secret_keyring`` objects (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``loaded=on`` option in the command line or QMP ``object-add`` either had +no effect (if ``loaded`` was the last option) or caused options to be +effectively ignored as if they were not given. The property is therefore +useless and should simply be removed. + +``opened`` property of ``rng-*`` objects (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``opened=on`` option in the command line or QMP ``object-add`` either had +no effect (if ``opened`` was the last option) or caused errors. The property +is therefore useless and should simply be removed. + +``-display sdl,window_close=...`` (removed in 7.1) +'''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,window-close=...`` instead (i.e. with a minus instead of +an underscore between "window" and "close"). + +``-alt-grab`` and ``-display sdl,alt_grab=on`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. + +``-ctrl-grab`` and ``-display sdl,ctrl_grab=on`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,grab-mod=rctrl`` instead. + +``-sdl`` (removed in 7.1) +''''''''''''''''''''''''' + +Use ``-display sdl`` instead. + +``-curses`` (removed in 7.1) +'''''''''''''''''''''''''''' + +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. + +Hexadecimal sizes with scaling multipliers (since 8.0) +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Input parameters that take a size value should only use a size suffix +(such as 'k' or 'M') when the base is written in decimal, and not when +the value is hexadecimal. That is, '0x20M' should be written either as +'32M' or as '0x2000000'. + +``-chardev`` backend aliases ``tty`` and ``parport`` (removed in 8.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +``tty`` and ``parport`` used to be aliases for ``serial`` and ``parallel`` +respectively. The actual backend names should be used instead. QEMU Machine Protocol (QMP) commands ------------------------------------ @@ -355,7 +440,8 @@ documentation of ``query-hotpluggable-cpus`` for additional details. ``change`` (removed in 6.0) ''''''''''''''''''''''''''' -Use ``blockdev-change-medium`` or ``change-vnc-password`` instead. +Use ``blockdev-change-medium`` or ``change-vnc-password`` or +``display-update`` instead. ``query-events`` (removed in 6.0) ''''''''''''''''''''''''''''''''' @@ -421,6 +507,19 @@ type of array items in query-named-block-nodes. Specify the properties for the object as top-level arguments instead. +``query-sgx`` return value member ``section-size`` (removed in 8.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Member ``section-size`` in the return value of ``query-sgx`` +was superseded by ``sections``. + + +``query-sgx-capabilities`` return value member ``section-size`` (removed in 8.0) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Member ``section-size`` in the return value of ``query-sgx-capabilities`` +was superseded by ``sections``. + Human Monitor Protocol (HMP) commands ------------------------------------- @@ -492,9 +591,8 @@ KVM guest support on 32-bit Arm hosts (removed in 5.2) '''''''''''''''''''''''''''''''''''''''''''''''''''''' The Linux kernel has dropped support for allowing 32-bit Arm systems -to host KVM guests as of the 5.7 kernel. Accordingly, QEMU is deprecating -its support for this configuration and will remove it in a future version. -Running 32-bit guests on a 64-bit Arm host remains supported. +to host KVM guests as of the 5.7 kernel, and was thus removed from QEMU +as well. Running 32-bit guests on a 64-bit Arm host remains supported. RISC-V ISA Specific CPUs (removed in 5.1) ''''''''''''''''''''''''''''''''''''''''' @@ -538,6 +636,22 @@ Support for this CPU was removed from the upstream Linux kernel, and there is no available upstream toolchain to build binaries for it. Removed without replacement. +x86 ``Icelake-Client`` CPU (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''' + +There isn't ever Icelake Client CPU, it is some wrong and imaginary one. +Use ``Icelake-Server`` instead. + +System accelerators +------------------- + +Userspace local APIC with KVM (x86, removed 8.0) +'''''''''''''''''''''''''''''''''''''''''''''''' + +``-M kernel-irqchip=off`` cannot be used on KVM if the CPU model includes +a local APIC. The ``split`` setting is supported, as is using ``-M +kernel-irqchip=off`` when the CPU does not have a local APIC. + System emulator machines ------------------------ @@ -594,6 +708,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 -------------------- diff --git a/docs/ccid.txt b/docs/ccid.txt deleted file mode 100644 index 2b85b1bd42c1..000000000000 --- a/docs/ccid.txt +++ /dev/null @@ -1,182 +0,0 @@ -QEMU CCID Device Documentation. - -Contents -1. USB CCID device -2. Building -3. Using ccid-card-emulated with hardware -4. Using ccid-card-emulated with certificates -5. Using ccid-card-passthru with client side hardware -6. Using ccid-card-passthru with client side certificates -7. Passthrough protocol scenario -8. libcacard - -1. USB CCID device - -The USB CCID device is a USB device implementing the CCID specification, which -lets one connect smart card readers that implement the same spec. For more -information see the specification: - - Universal Serial Bus - Device Class: Smart Card - CCID - Specification for - Integrated Circuit(s) Cards Interface Devices - Revision 1.1 - April 22rd, 2005 - -Smartcards are used for authentication, single sign on, decryption in -public/private schemes and digital signatures. A smartcard reader on the client -cannot be used on a guest with simple usb passthrough since it will then not be -available on the client, possibly locking the computer when it is "removed". On -the other hand this device can let you use the smartcard on both the client and -the guest machine. It is also possible to have a completely virtual smart card -reader and smart card (i.e. not backed by a physical device) using this device. - -2. Building - -The cryptographic functions and access to the physical card is done via the -libcacard library, whose development package must be installed prior to -building QEMU: - -In redhat/fedora: - yum install libcacard-devel -In ubuntu: - apt-get install libcacard-dev - -Configuring and building: - ./configure --enable-smartcard && make - - -3. Using ccid-card-emulated with hardware - -Assuming you have a working smartcard on the host with the current -user, using libcacard, QEMU acts as another client using ccid-card-emulated: - - qemu -usb -device usb-ccid -device ccid-card-emulated - - -4. Using ccid-card-emulated with certificates stored in files - -You must create the CA and card certificates. This is a one time process. -We use NSS certificates: - - mkdir fake-smartcard - cd fake-smartcard - certutil -N -d sql:$PWD - certutil -S -d sql:$PWD -s "CN=Fake Smart Card CA" -x -t TC,TC,TC -n fake-smartcard-ca - certutil -S -d sql:$PWD -t ,, -s "CN=John Doe" -n id-cert -c fake-smartcard-ca - certutil -S -d sql:$PWD -t ,, -s "CN=John Doe (signing)" --nsCertType smime -n signing-cert -c fake-smartcard-ca - certutil -S -d sql:$PWD -t ,, -s "CN=John Doe (encryption)" --nsCertType sslClient -n encryption-cert -c fake-smartcard-ca - -Note: you must have exactly three certificates. - -You can use the emulated card type with the certificates backend: - - qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,db=sql:$PWD,cert1=id-cert,cert2=signing-cert,cert3=encryption-cert - -To use the certificates in the guest, export the CA certificate: - - certutil -L -r -d sql:$PWD -o fake-smartcard-ca.cer -n fake-smartcard-ca - -and import it in the guest: - - certutil -A -d /etc/pki/nssdb -i fake-smartcard-ca.cer -t TC,TC,TC -n fake-smartcard-ca - -In a Linux guest you can then use the CoolKey PKCS #11 module to access -the card: - - certutil -d /etc/pki/nssdb -L -h all - -It will prompt you for the PIN (which is the password you assigned to the -certificate database early on), and then show you all three certificates -together with the manually imported CA cert: - - Certificate Nickname Trust Attributes - fake-smartcard-ca CT,C,C - John Doe:CAC ID Certificate u,u,u - John Doe:CAC Email Signature Certificate u,u,u - John Doe:CAC Email Encryption Certificate u,u,u - -If this does not happen, CoolKey is not installed or not registered with -NSS. Registration can be done from Firefox or the command line: - - modutil -dbdir /etc/pki/nssdb -add "CAC Module" -libfile /usr/lib64/pkcs11/libcoolkeypk11.so - modutil -dbdir /etc/pki/nssdb -list - - -5. Using ccid-card-passthru with client side hardware - -on the host specify the ccid-card-passthru device with a suitable chardev: - - qemu -chardev socket,server=on,host=0.0.0.0,port=2001,id=ccid,wait=off \ - -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid - -on the client run vscclient, built when you built QEMU: - - vscclient 2001 - - -6. Using ccid-card-passthru with client side certificates - -This case is not particularly useful, but you can use it to debug -your setup if #4 works but #5 does not. - -Follow instructions as per #4, except run QEMU and vscclient as follows: -Run qemu as per #5, and run vscclient from the "fake-smartcard" -directory as follows: - - qemu -chardev socket,server=on,host=0.0.0.0,port=2001,id=ccid,wait=off \ - -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid - vscclient -e "db=\"sql:$PWD\" use_hw=no soft=(,Test,CAC,,id-cert,signing-cert,encryption-cert)" 2001 - - -7. Passthrough protocol scenario - -This is a typical interchange of messages when using the passthru card device. -usb-ccid is a usb device. It defaults to an unattached usb device on startup. -usb-ccid expects a chardev and expects the protocol defined in -cac_card/vscard_common.h to be passed over that. -The usb-ccid device can be in one of three modes: - * detached - * attached with no card - * attached with card - -A typical interchange is: (the arrow shows who started each exchange, it can be client -originated or guest originated) - -client event | vscclient | passthru | usb-ccid | guest event ----------------------------------------------------------------------------------------------- - | VSC_Init | | | - | VSC_ReaderAdd | | attach | - | | | | sees new usb device. -card inserted -> | | | | - | VSC_ATR | insert | insert | see new card - | | | | - | VSC_APDU | VSC_APDU | | <- guest sends APDU -client<->physical | | | | -card APDU exchange| | | | -client response ->| VSC_APDU | VSC_APDU | | receive APDU response - ... - [APDU<->APDU repeats several times] - ... -card removed -> | | | | - | VSC_CardRemove | remove | remove | card removed - ... - [(card insert, apdu's, card remove) repeat] - ... -kill/quit | | | | - vscclient | | | | - | VSC_ReaderRemove | | detach | - | | | | usb device removed. - - -8. libcacard - -Both ccid-card-emulated and vscclient use libcacard as the card emulator. -libcacard implements a completely virtual CAC (DoD standard for smart -cards) compliant card and uses NSS to retrieve certificates and do -any encryption. The backend can then be a real reader and card, or -certificates stored in files. - -For documentation of the library see docs/libcacard.txt. - diff --git a/docs/conf.py b/docs/conf.py index 49dab44cca5a..e33cf3d38121 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -126,7 +126,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/docs/devel/acpi-bits.rst b/docs/devel/acpi-bits.rst new file mode 100644 index 000000000000..9eb4b9e6669b --- /dev/null +++ b/docs/devel/acpi-bits.rst @@ -0,0 +1,144 @@ +============================================================================= +ACPI/SMBIOS avocado tests using biosbits +============================================================================= + +Biosbits is a software written by Josh Triplett that can be downloaded +from https://biosbits.org/. The github codebase can be found +`here `__. It is a software that executes +the bios components such as acpi and smbios tables directly through acpica +bios interpreter (a freely available C based library written by Intel, +downloadable from https://acpica.org/ and is included with biosbits) without an +operating system getting involved in between. +There are several advantages to directly testing the bios in a real physical +machine or VM as opposed to indirectly discovering bios issues through the +operating system. For one thing, the OSes tend to hide bios problems from the +end user. The other is that we have more control of what we wanted to test +and how by directly using acpica interpreter on top of the bios on a running +system. More details on the inspiration for developing biosbits and its real +life uses can be found in [#a]_ and [#b]_. +For QEMU, we maintain a fork of bios bits in gitlab along with all the +dependent submodules here: https://gitlab.com/qemu-project/biosbits-bits +This fork contains numerous fixes, a newer acpica and changes specific to +running this avocado QEMU tests using bits. The author of this document +is the sole maintainer of the QEMU fork of bios bits repo. + +Under the directory ``tests/avocado/``, ``acpi-bits.py`` is a QEMU avocado +test that drives all this. + +A brief description of the various test files follows. + +Under ``tests/avocado/`` as the root we have: + +:: + + ├── acpi-bits + │ ├── bits-config + │ │ └── bits-cfg.txt + │ ├── bits-tests + │ ├── smbios.py2 + │ ├── testacpi.py2 + │ └── testcpuid.py2 + ├── acpi-bits.py + +* ``tests/avocado``: + + ``acpi-bits.py``: + This is the main python avocado test script that generates a + biosbits iso. It then spawns a QEMU VM with it, collects the log and reports + test failures. This is the script one would be interested in if they wanted + to add or change some component of the log parsing, add a new command line + to alter how QEMU is spawned etc. Test writers typically would not need to + modify this script unless they wanted to enhance or change the log parsing + for their tests. In order to enable debugging, you can set **V=1** + environment variable. This enables verbose mode for the test and also dumps + the entire log from bios bits and more information in case failure happens. + You can also set **BITS_DEBUG=1** to turn on debug mode. It will enable + verbose logs and also retain the temporary work directory the test used for + you to inspect and run the specific commands manually. + + In order to run this test, please perform the following steps from the QEMU + build directory: + :: + + $ make check-venv (needed only the first time to create the venv) + $ ./tests/venv/bin/avocado run -t acpi tests/avocado + + The above will run all acpi avocado tests including this one. + In order to run the individual tests, perform the following: + :: + + $ ./tests/venv/bin/avocado run tests/avocado/acpi-bits.py --tap - + + The above will produce output in tap format. You can omit "--tap -" in the + end and it will produce output like the following: + :: + + $ ./tests/venv/bin/avocado run tests/avocado/acpi-bits.py + Fetching asset from tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits + JOB ID : eab225724da7b64c012c65705dc2fa14ab1defef + JOB LOG : /home/anisinha/avocado/job-results/job-2022-10-10T17.58-eab2257/job.log + (1/1) tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits: PASS (33.09 s) + RESULTS : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0 + JOB TIME : 39.22 s + + You can inspect the log file for more information about the run or in order + to diagnoze issues. If you pass V=1 in the environment, more diagnostic logs + would be found in the test log. + +* ``tests/avocado/acpi-bits/bits-config``: + + This location contains biosbits configuration files that determine how the + software runs the tests. + + ``bits-config.txt``: + This is the biosbits config file that determines what tests + or actions are performed by bits. The description of the config options are + provided in the file itself. + +* ``tests/avocado/acpi-bits/bits-tests``: + + This directory contains biosbits python based tests that are run from within + the biosbits environment in the spawned VM. New additions of test cases can + be made in the appropriate test file. For example, new acpi tests can go + into testacpi.py2 and one would call testsuite.add_test() to register the new + test so that it gets executed as a part of the ACPI tests. + It might be occasionally necessary to disable some subtests or add a new + test that belongs to a test suite not already present in this directory. To + do this, please clone the bits source from + https://gitlab.com/qemu-project/biosbits-bits/-/tree/qemu-bits. + Note that this is the "qemu-bits" branch and not the "bits" branch of the + repository. "qemu-bits" is the branch where we have made all the QEMU + specific enhancements and we must use the source from this branch only. + Copy the test suite/script that needs modification (addition of new tests + or disabling them) from python directory into this directory. For + example, in order to change cpuid related tests, copy the following + file into this directory and rename it with .py2 extension: + https://gitlab.com/qemu-project/biosbits-bits/-/blob/qemu-bits/python/testcpuid.py + Then make your additions and changes here. Therefore, the steps are: + + (a) Copy unmodified test script to this directory from bits source. + (b) Add a SPDX license header. + (c) Perform modifications to the test. + + Commits (a), (b) and (c) should go under separate commits so that the original + test script and the changes we have made are separated and clear. + + The test framework will then use your modified test script to run the test. + No further changes would be needed. Please check the logs to make sure that + appropriate changes have taken effect. + + The tests have an extension .py2 in order to indicate that: + + (a) They are python2.7 based scripts and not python 3 scripts. + (b) They are run from within the bios bits VM and is not subjected to QEMU + build/test python script maintenance and dependency resolutions. + (c) They need not be loaded by avocado framework when running tests. + + +Author: Ani Sinha + +References: +----------- +.. [#a] https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf +.. [#b] https://www.youtube.com/watch?v=36QIepyUuhg + diff --git a/docs/devel/atomics.rst b/docs/devel/atomics.rst index 52baa0736d2f..7957310071d9 100644 --- a/docs/devel/atomics.rst +++ b/docs/devel/atomics.rst @@ -1,3 +1,5 @@ +.. _atomics-ref: + ========================= Atomic operations in QEMU ========================= diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst index 412851986b1a..6dd2cdcab370 100644 --- a/docs/devel/block-coroutine-wrapper.rst +++ b/docs/devel/block-coroutine-wrapper.rst @@ -26,12 +26,12 @@ called ``bdrv_foo()``. In this case the script can help. To trigger the generation: 1. You need ``bdrv_foo`` declaration somewhere (for example, in - ``block/coroutines.h``) with the ``generated_co_wrapper`` mark, + ``block/coroutines.h``) with the ``co_wrapper`` mark, like this: .. code-block:: c - int generated_co_wrapper bdrv_foo(); + int co_wrapper bdrv_foo(); 2. You need to feed this declaration to block-coroutine-wrapper script. For this, add the .h (or .c) file with the declaration to the @@ -46,7 +46,7 @@ Links 1. The script location is ``scripts/block-coroutine-wrapper.py``. -2. Generic place for private ``generated_co_wrapper`` declarations is +2. Generic place for private ``co_wrapper`` declarations is ``block/coroutines.h``, for public declarations: ``include/block/block.h`` diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index 431caba7aa06..189472174340 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/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 92e25872aa14..1f28fec0d0bb 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -1,3 +1,5 @@ +.. _ci_var: + Custom CI/CD variables ====================== @@ -28,7 +30,113 @@ For further information about how to set these variables, please refer to:: https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd -Here is a list of the most used variables: +Setting aliases in your git config +---------------------------------- + +You can use aliases to make it easier to push branches with different +CI configurations. For example define an alias for triggering CI: + +.. code:: + + git config --local alias.push-ci "push -o ci.variable=QEMU_CI=1" + git config --local alias.push-ci-now "push -o ci.variable=QEMU_CI=2" + +Which lets you run: + +.. code:: + + git push-ci + +to create the pipeline, or: + +.. code:: + + git push-ci-now + +to create and run the pipeline + + +Variable naming and grouping +---------------------------- + +The variables used by QEMU's CI configuration are grouped together +in a handful of namespaces + + * QEMU_JOB_nnnn - variables to be defined in individual jobs + or templates, to influence the shared rules defined in the + .base_job_template. + + * QEMU_CI_nnn - variables to be set by contributors in their + repository CI settings, or as git push variables, to influence + which jobs get run in a pipeline + + * nnn - other misc variables not falling into the above + categories, or using different names for historical reasons + and not yet converted. + +Maintainer controlled job variables +----------------------------------- + +The following variables may be set when defining a job in the +CI configuration file. + +QEMU_JOB_CIRRUS +~~~~~~~~~~~~~~~ + +The job makes use of Cirrus CI infrastructure, requiring the +configuration setup for cirrus-run to be present in the repository + +QEMU_JOB_OPTIONAL +~~~~~~~~~~~~~~~~~ + +The job is expected to be successful in general, but is not run +by default due to need to conserve limited CI resources. It is +available to be started manually by the contributor in the CI +pipelines UI. + +QEMU_JOB_ONLY_FORKS +~~~~~~~~~~~~~~~~~~~ + +The job results are only of interest to contributors prior to +submitting code. They are not required as part of the gating +CI pipeline. + +QEMU_JOB_SKIPPED +~~~~~~~~~~~~~~~~ + +The job is not reliably successsful in general, so is not +currently suitable to be run by default. Ideally this should +be a temporary marker until the problems can be addressed, or +the job permanently removed. + +QEMU_JOB_PUBLISH +~~~~~~~~~~~~~~~~ + +The job is for publishing content after a branch has been +merged into the upstream default branch. + +QEMU_JOB_AVOCADO +~~~~~~~~~~~~~~~~ + +The job runs the Avocado integration test suite + +Contributor controlled runtime variables +---------------------------------------- + +The following variables may be set by contributors to control +job execution + +QEMU_CI +~~~~~~~ + +By default, no pipelines will be created on contributor forks +in order to preserve CI credits + +Set this variable to 1 to create the pipelines, but leave all +the jobs to be manually started from the UI + +Set this variable to 2 to create the pipelines and run all +the jobs immediately, as was historicaly behaviour QEMU_CI_AVOCADO_TESTING ~~~~~~~~~~~~~~~~~~~~~~~ @@ -38,6 +146,12 @@ these artifacts are not already cached, downloading them make the jobs reach the timeout limit). Set this variable to have the tests using the Avocado framework run automatically. +Other misc variables +-------------------- + +These variables are primarily to control execution of jobs on +private runners + AARCH64_RUNNER_AVAILABLE ~~~~~~~~~~~~~~~~~~~~~~~~ If you've got access to an aarch64 host that can be used as a gitlab-CI diff --git a/docs/devel/ci.rst b/docs/devel/ci.rst index d106610096eb..ed88a2010be1 100644 --- a/docs/devel/ci.rst +++ b/docs/devel/ci.rst @@ -1,12 +1,13 @@ +.. _ci: + == CI == -QEMU has configurations enabled for a number of different CI services. -The most up to date information about them and their status can be -found at:: - - https://wiki.qemu.org/Testing/CI +Most of QEMU's CI is run on GitLab's infrastructure although a number +of other CI services are used for specialised purposes. The most up to +date information about them and their status can be found on the +`project wiki testing page `_. .. include:: ci-definitions.rst.inc .. include:: ci-jobs.rst.inc diff --git a/docs/devel/code-of-conduct.rst b/docs/devel/code-of-conduct.rst index 195444d1b485..f734ed031742 100644 --- a/docs/devel/code-of-conduct.rst +++ b/docs/devel/code-of-conduct.rst @@ -1,3 +1,5 @@ +.. _code_of_conduct: + Code of Conduct =============== diff --git a/docs/devel/fuzzing.rst b/docs/devel/fuzzing.rst index 784ecb99e667..715330c85613 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/index-api.rst b/docs/devel/index-api.rst index b749240272b9..60c0d7459de8 100644 --- a/docs/devel/index-api.rst +++ b/docs/devel/index-api.rst @@ -6,7 +6,6 @@ generated from in-code annotations to function prototypes. .. toctree:: :maxdepth: 2 - :includehidden: bitops loads-stores diff --git a/docs/devel/index-build.rst b/docs/devel/index-build.rst index d96894f07c93..57e8d39d9856 100644 --- a/docs/devel/index-build.rst +++ b/docs/devel/index-build.rst @@ -6,12 +6,12 @@ into our testing infrastructure. You will need to understand some of the basics if you are adding new files and targets to the build. .. toctree:: - :maxdepth: 2 - :includehidden: + :maxdepth: 3 build-system kconfig testing + acpi-bits qtest ci qapi-code-gen diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index bb118b8eaf8d..e1a93df26392 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -5,7 +5,6 @@ Details about QEMU's various subsystems including how to add features to them. .. toctree:: :maxdepth: 2 - :includehidden: qom atomics @@ -19,3 +18,4 @@ Details about QEMU's various subsystems including how to add features to them. tracing vfio-migration writing-monitor-commands + virtio-backends diff --git a/docs/devel/index-process.rst b/docs/devel/index-process.rst index 314e9e94cc0e..d50dd74c3e28 100644 --- a/docs/devel/index-process.rst +++ b/docs/devel/index-process.rst @@ -5,10 +5,10 @@ Notes about how to interact with the community and how and where to submit patch .. toctree:: :maxdepth: 2 - :includehidden: code-of-conduct conflict-resolution + maintainers style submitting-a-patch trivial-patches diff --git a/docs/devel/index-tcg.rst b/docs/devel/index-tcg.rst index 3acbd95d362f..b44ff8b5a423 100644 --- a/docs/devel/index-tcg.rst +++ b/docs/devel/index-tcg.rst @@ -7,10 +7,11 @@ are only implementing things for HW accelerated hypervisors. .. toctree:: :maxdepth: 2 - :includehidden: tcg + tcg-ops decodetree multi-thread-tcg tcg-icount tcg-plugins + replay diff --git a/docs/devel/index.rst b/docs/devel/index.rst index a68207052d87..09cfb322beba 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -8,8 +8,6 @@ modifying QEMU's source code. .. toctree:: :maxdepth: 1 - :includehidden: - index-process index-build diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst index 8f0035c821bf..ad5dfe133e15 100644 --- a/docs/devel/loads-stores.rst +++ b/docs/devel/loads-stores.rst @@ -275,7 +275,7 @@ called during the translator callback ``translate_insn``. There is a set of functions ending in ``_swap`` which, if the parameter is true, returns the value in the endianness that is the reverse of -the guest native endianness, as determined by ``TARGET_WORDS_BIGENDIAN``. +the guest native endianness, as determined by ``TARGET_BIG_ENDIAN``. Function names follow the pattern: diff --git a/docs/devel/maintainers.rst b/docs/devel/maintainers.rst new file mode 100644 index 000000000000..5c907d901cd5 --- /dev/null +++ b/docs/devel/maintainers.rst @@ -0,0 +1,107 @@ +.. _maintainers: + +The Role of Maintainers +======================= + +Maintainers are a critical part of the project's contributor ecosystem. +They come from a wide range of backgrounds from unpaid hobbyists +working in their spare time to employees who work on the project as +part of their job. Maintainer activities include: + + - reviewing patches and suggesting changes + - collecting patches and preparing pull requests + - tending to the long term health of their area + - participating in other project activities + +They are also human and subject to the same pressures as everyone else +including overload and burnout. Like everyone else they are subject +to project's :ref:`code_of_conduct` and should also be exemplars of +excellent community collaborators. + +The MAINTAINERS file +-------------------- + +The `MAINTAINERS +`__ +file contains the canonical list of who is a maintainer. The file +is machine readable so an appropriately configured git (see +:ref:`cc_the_relevant_maintainer`) can automatically Cc them on +patches that touch their area of code. + +The file also describes the status of the area of code to give an idea +of how actively that section is maintained. + +.. list-table:: Meaning of support status in MAINTAINERS + :widths: 25 75 + :header-rows: 1 + + * - Status + - Meaning + * - Supported + - Someone is actually paid to look after this. + * - Maintained + - Someone actually looks after it. + * - Odd Fixes + - It has a maintainer but they don't have time to do + much other than throw the odd patch in. + * - Orphan + - No current maintainer. + * - Obsolete + - Old obsolete code, should use something else. + +Please bear in mind that even if someone is paid to support something +it does not mean they are paid to support you. This is open source and +the code comes with no warranty and the project makes no guarantees +about dealing with bugs or features requests. + + + +Becoming a reviewer +------------------- + +Most maintainers start by becoming subsystem reviewers. While anyone +is welcome to review code on the mailing list getting added to the +MAINTAINERS file with a line like:: + + R: Random Hacker + +marks you as a 'designated reviewer' - expected to provide regular +spontaneous feedback. This will ensure that patches touching a given +subsystem will automatically be CC'd to you. + +Becoming a maintainer +--------------------- + +Maintainers are volunteers who put themselves forward or have been +asked by others to keep an eye on an area of code. They have generally +demonstrated to the community, usually via contributions and code +reviews, that they have a good understanding of the subsystem. They +are also trusted to make a positive contribution to the project and +work well with the other contributors. + +The process is simple - simply send a patch to the list that updates +the ``MAINTAINERS`` file. Sometimes this is done as part of a larger +series when a new sub-system is being added to the code base. This can +also be done by a retiring maintainer who nominates their replacement +after discussion with other contributors. + +Once the patch is reviewed and merged the only other step is to make +sure your GPG key is signed. + +.. _maintainer_keys: + +Maintainer GPG Keys +~~~~~~~~~~~~~~~~~~~ + +GPG is used to sign pull requests so they can be identified as really +coming from the maintainer. If your key is not already signed by +members of the QEMU community, you should make arrangements to attend +a `KeySigningParty `__ (for +example at KVM Forum) or make alternative arrangements to have your +key signed by an attendee. Key signing requires meeting another +community member **in person** [#]_ so please make appropriate +arrangements. + +.. [#] In recent pandemic times we have had to exercise some + flexibility here. Maintainers still need to sign their pull + requests though. diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt index aeb997bed5f0..343120f2ef77 100644 --- a/docs/devel/multiple-iothreads.txt +++ b/docs/devel/multiple-iothreads.txt @@ -109,7 +109,7 @@ The AioContext originates from the QEMU block layer, even though nowadays AioContext is a generic event loop that can be used by any QEMU subsystem. The block layer has support for AioContext integrated. Each BlockDriverState -is associated with an AioContext using bdrv_try_set_aio_context() and +is associated with an AioContext using bdrv_try_change_aio_context() and bdrv_get_aio_context(). This allows block layer code to process I/O inside the right AioContext. Other subsystems may wish to follow a similar approach. @@ -134,5 +134,5 @@ Long-running jobs (usually in the form of coroutines) are best scheduled in the BlockDriverState's AioContext to avoid the need to acquire/release around each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier, or alternatively blk_add/remove_aio_context_notifier if you use BlockBackends, -can be used to get a notification whenever bdrv_try_set_aio_context() moves a +can be used to get a notification whenever bdrv_try_change_aio_context() moves a BlockDriverState to a different AioContext. diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index 246709ede895..5edc49aa7497 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -41,8 +41,8 @@ used internally. There are several kinds of types: simple types (a number of built-in types, such as ``int`` and ``str``; as well as enumerations), arrays, -complex types (structs and two flavors of unions), and alternate types -(a choice between other types). +complex types (structs and unions), and alternate types (a choice +between other types). Schema syntax @@ -739,10 +739,11 @@ Type names ending with ``Kind`` or ``List`` are reserved for the generator, which uses them for implicit union enums and array types, respectively. -Command names, and member names within a type, should be all lower -case with words separated by a hyphen. However, some existing older -commands and complex types use underscore; when extending them, -consistency is preferred over blindly avoiding underscore. +Command names, member names within a type, and feature names should be +all lower case with words separated by a hyphen. However, some +existing older commands and complex types use underscore; when +extending them, consistency is preferred over blindly avoiding +underscore. Event names should be ALL_CAPS with words separated by underscore. @@ -1356,7 +1357,7 @@ qmp_my_command(); everything else is produced by the generator. :: $ cat example-schema.json { 'struct': 'UserDefOne', - 'data': { 'integer': 'int', '*string': 'str' } } + 'data': { 'integer': 'int', '*string': 'str', '*flag': 'bool' } } { 'command': 'my-command', 'data': { 'arg1': ['UserDefOne'] }, @@ -1409,8 +1410,9 @@ Example:: struct UserDefOne { int64_t integer; - bool has_string; char *string; + bool has_flag; + bool flag; }; void qapi_free_UserDefOne(UserDefOne *obj); @@ -1522,14 +1524,21 @@ Example:: bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp) { + bool has_string = !!obj->string; + if (!visit_type_int(v, "integer", &obj->integer, errp)) { return false; } - if (visit_optional(v, "string", &obj->has_string)) { + if (visit_optional(v, "string", &has_string)) { if (!visit_type_str(v, "string", &obj->string, errp)) { return false; } } + if (visit_optional(v, "flag", &obj->has_flag)) { + if (!visit_type_bool(v, "flag", &obj->flag, errp)) { + return false; + } + } return true; } @@ -1663,7 +1672,6 @@ Example:: $ cat qapi-generated/example-qapi-commands.c [Uninteresting stuff omitted...] - static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp) { @@ -1747,7 +1755,7 @@ Example:: QTAILQ_INIT(cmds); qmp_register_command(cmds, "my-command", - qmp_marshal_my_command, QCO_NO_OPTIONS); + qmp_marshal_my_command, 0, 0); } [Uninteresting stuff omitted...] @@ -1916,6 +1924,12 @@ Example:: { "type", QLIT_QSTR("str"), }, {} })), + QLIT_QDICT(((QLitDictEntry[]) { + { "default", QLIT_QNULL, }, + { "name", QLIT_QSTR("flag"), }, + { "type", QLIT_QSTR("bool"), }, + {} + })), {} })), }, { "meta-type", QLIT_QSTR("object"), }, @@ -1949,6 +1963,12 @@ Example:: { "name", QLIT_QSTR("str"), }, {} })), + QLIT_QDICT(((QLitDictEntry[]) { + { "json-type", QLIT_QSTR("boolean"), }, + { "meta-type", QLIT_QSTR("builtin"), }, + { "name", QLIT_QSTR("bool"), }, + {} + })), {} })); diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst index e5fe3597cd82..3e34b07c98e6 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/qtest.rst b/docs/devel/qtest.rst index c3dceb6c8a1d..0455aa06ab28 100644 --- a/docs/devel/qtest.rst +++ b/docs/devel/qtest.rst @@ -3,7 +3,6 @@ QTest Device Emulation Testing Framework ======================================== .. toctree:: - :hidden: qgraph @@ -89,4 +88,4 @@ QTest Protocol libqtest API reference ---------------------- -.. kernel-doc:: tests/qtest/libqos/libqtest.h +.. kernel-doc:: tests/qtest/libqtest.h diff --git a/docs/devel/replay.rst b/docs/devel/replay.rst new file mode 100644 index 000000000000..0244be8b9c4d --- /dev/null +++ b/docs/devel/replay.rst @@ -0,0 +1,306 @@ +.. + Copyright (c) 2022, ISP RAS + Written by Pavel Dovgalyuk and Alex Bennée + +======================= +Execution Record/Replay +======================= + +Core concepts +============= + +Record/replay functions are used for the deterministic replay of qemu +execution. Execution recording writes a non-deterministic events log, which +can be later used for replaying the execution anywhere and for unlimited +number of times. Execution replaying reads the log and replays all +non-deterministic events including external input, hardware clocks, +and interrupts. + +Several parts of QEMU include function calls to make event log recording +and replaying. +Devices' models that have non-deterministic input from external devices were +changed to write every external event into the execution log immediately. +E.g. network packets are written into the log when they arrive into the virtual +network adapter. + +All non-deterministic events are coming from these devices. But to +replay them we need to know at which moments they occur. We specify +these moments by counting the number of instructions executed between +every pair of consecutive events. + +Academic papers with description of deterministic replay implementation: + +* `Deterministic Replay of System's Execution with Multi-target QEMU Simulator for Dynamic Analysis and Reverse Debugging `_ +* `Don't panic: reverse debugging of kernel drivers `_ + +Modifications of qemu include: + + * wrappers for clock and time functions to save their return values in the log + * saving different asynchronous events (e.g. system shutdown) into the log + * synchronization of the bottom halves execution + * synchronization of the threads from thread pool + * recording/replaying user input (mouse, keyboard, and microphone) + * adding internal checkpoints for cpu and io synchronization + * network filter for recording and replaying the packets + * block driver for making block layer deterministic + * serial port input record and replay + * recording of random numbers obtained from the external sources + +Instruction counting +-------------------- + +QEMU should work in icount mode to use record/replay feature. icount was +designed to allow deterministic execution in absence of external inputs +of the virtual machine. We also use icount to control the occurrence of the +non-deterministic events. The number of instructions elapsed from the last event +is written to the log while recording the execution. In replay mode we +can predict when to inject that event using the instruction counter. + +Locking and thread synchronisation +---------------------------------- + +Previously the synchronisation of the main thread and the vCPU thread +was ensured by the holding of the BQL. However the trend has been to +reduce the time the BQL was held across the system including under TCG +system emulation. As it is important that batches of events are kept +in sequence (e.g. expiring timers and checkpoints in the main thread +while instruction checkpoints are written by the vCPU thread) we need +another lock to keep things in lock-step. This role is now handled by +the replay_mutex_lock. It used to be held only for each event being +written but now it is held for a whole execution period. This results +in a deterministic ping-pong between the two main threads. + +As the BQL is now a finer grained lock than the replay_lock it is almost +certainly a bug, and a source of deadlocks, to take the +replay_mutex_lock while the BQL is held. This is enforced by an assert. +While the unlocks are usually in the reverse order, this is not +necessary; you can drop the replay_lock while holding the BQL, without +doing a more complicated unlock_iothread/replay_unlock/lock_iothread +sequence. + +Checkpoints +----------- + +Replaying the execution of virtual machine is bound by sources of +non-determinism. These are inputs from clock and peripheral devices, +and QEMU thread scheduling. Thread scheduling affect on processing events +from timers, asynchronous input-output, and bottom halves. + +Invocations of timers are coupled with clock reads and changing the state +of the virtual machine. Reads produce non-deterministic data taken from +host clock. And VM state changes should preserve their order. Their relative +order in replay mode must replicate the order of callbacks in record mode. +To preserve this order we use checkpoints. When a specific clock is processed +in record mode we save to the log special "checkpoint" event. +Checkpoints here do not refer to virtual machine snapshots. They are just +record/replay events used for synchronization. + +QEMU in replay mode will try to invoke timers processing in random moment +of time. That's why we do not process a group of timers until the checkpoint +event will be read from the log. Such an event allows synchronizing CPU +execution and timer events. + +Two other checkpoints govern the "warping" of the virtual clock. +While the virtual machine is idle, the virtual clock increments at +1 ns per *real time* nanosecond. This is done by setting up a timer +(called the warp timer) on the virtual real time clock, so that the +timer fires at the next deadline of the virtual clock; the virtual clock +is then incremented (which is called "warping" the virtual clock) as +soon as the timer fires or the CPUs need to go out of the idle state. +Two functions are used for this purpose; because these actions change +virtual machine state and must be deterministic, each of them creates a +checkpoint. ``icount_start_warp_timer`` checks if the CPUs are idle and if so +starts accounting real time to virtual clock. ``icount_account_warp_timer`` +is called when the CPUs get an interrupt or when the warp timer fires, +and it warps the virtual clock by the amount of real time that has passed +since ``icount_start_warp_timer``. + +Virtual devices +=============== + +Record/replay mechanism, that could be enabled through icount mode, expects +the virtual devices to satisfy the following requirement: +everything that affects +the guest state during execution in icount mode should be deterministic. + +Timers +------ + +Timers are used to execute callbacks from different subsystems of QEMU +at the specified moments of time. There are several kinds of timers: + + * Real time clock. Based on host time and used only for callbacks that + do not change the virtual machine state. For this reason real time + clock and timers does not affect deterministic replay at all. + * Virtual clock. These timers run only during the emulation. In icount + mode virtual clock value is calculated using executed instructions counter. + That is why it is completely deterministic and does not have to be recorded. + * Host clock. This clock is used by device models that simulate real time + sources (e.g. real time clock chip). Host clock is the one of the sources + of non-determinism. Host clock read operations should be logged to + make the execution deterministic. + * Virtual real time clock. This clock is similar to real time clock but + it is used only for increasing virtual clock while virtual machine is + sleeping. Due to its nature it is also non-deterministic as the host clock + and has to be logged too. + +All virtual devices should use virtual clock for timers that change the guest +state. Virtual clock is deterministic, therefore such timers are deterministic +too. + +Virtual devices can also use realtime clock for the events that do not change +the guest state directly. When the clock ticking should depend on VM execution +speed, use virtual clock with EXTERNAL attribute. It is not deterministic, +but its speed depends on the guest execution. This clock is used by +the virtual devices (e.g., slirp routing device) that lie outside the +replayed guest. + +Block devices +------------- + +Block devices record/replay module (``blkreplay``) intercepts calls of +bdrv coroutine functions at the top of block drivers stack. + +All block completion operations are added to the queue in the coroutines. +When the queue is flushed the information about processed requests +is recorded to the log. In replay phase the queue is matched with +events read from the log. Therefore block devices requests are processed +deterministically. + +Bottom halves +------------- + +Bottom half callbacks, that affect the guest state, should be invoked through +``replay_bh_schedule_event`` or ``replay_bh_schedule_oneshot_event`` functions. +Their invocations are saved in record mode and synchronized with the existing +log in replay mode. + +Disk I/O events are completely deterministic in our model, because +in both record and replay modes we start virtual machine from the same +disk state. But callbacks that virtual disk controller uses for reading and +writing the disk may occur at different moments of time in record and replay +modes. + +Reading and writing requests are created by CPU thread of QEMU. Later these +requests proceed to block layer which creates "bottom halves". Bottom +halves consist of callback and its parameters. They are processed when +main loop locks the global mutex. These locks are not synchronized with +replaying process because main loop also processes the events that do not +affect the virtual machine state (like user interaction with monitor). + +That is why we had to implement saving and replaying bottom halves callbacks +synchronously to the CPU execution. When the callback is about to execute +it is added to the queue in the replay module. This queue is written to the +log when its callbacks are executed. In replay mode callbacks are not processed +until the corresponding event is read from the events log file. + +Sometimes the block layer uses asynchronous callbacks for its internal purposes +(like reading or writing VM snapshots or disk image cluster tables). In this +case bottom halves are not marked as "replayable" and do not saved +into the log. + +Saving/restoring the VM state +----------------------------- + +All fields in the device state structure (including virtual timers) +should be restored by loadvm to the same values they had before savevm. + +Avoid accessing other devices' state, because the order of saving/restoring +is not defined. It means that you should not call functions like +``update_irq`` in ``post_load`` callback. Save everything explicitly to avoid +the dependencies that may make restoring the VM state non-deterministic. + +Stopping the VM +--------------- + +Stopping the guest should not interfere with its state (with the exception +of the network connections, that could be broken by the remote timeouts). +VM can be stopped at any moment of replay by the user. Restarting the VM +after that stop should not break the replay by the unneeded guest state change. + +Replay log format +================= + +Record/replay log consists of the header and the sequence of execution +events. The header includes 4-byte replay version id and 8-byte reserved +field. Version is updated every time replay log format changes to prevent +using replay log created by another build of qemu. + +The sequence of the events describes virtual machine state changes. +It includes all non-deterministic inputs of VM, synchronization marks and +instruction counts used to correctly inject inputs at replay. + +Synchronization marks (checkpoints) are used for synchronizing qemu threads +that perform operations with virtual hardware. These operations may change +system's state (e.g., change some register or generate interrupt) and +therefore should execute synchronously with CPU thread. + +Every event in the log includes 1-byte event id and optional arguments. +When argument is an array, it is stored as 4-byte array length +and corresponding number of bytes with data. +Here is the list of events that are written into the log: + + - EVENT_INSTRUCTION. Instructions executed since last event. Followed by: + + - 4-byte number of executed instructions. + + - EVENT_INTERRUPT. Used to synchronize interrupt processing. + - EVENT_EXCEPTION. Used to synchronize exception handling. + - EVENT_ASYNC. This is a group of events. When such an event is generated, + it is stored in the queue and processed in icount_account_warp_timer(). + Every such event has it's own id from the following list: + + - REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes + callbacks that affect virtual machine state, but normally called + asynchronously. Followed by: + + - 8-byte operation id. + + - REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains + parameters of keyboard and mouse input operations + (key press/release, mouse pointer movement). Followed by: + + - 9-16 bytes depending of input event. + + - REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event. + - REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input + initiated by the sender. Followed by: + + - 1-byte character device id. + - Array with bytes were read. + + - REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize + operations with disk and flash drives with CPU. Followed by: + + - 8-byte operation id. + + - REPLAY_ASYNC_EVENT_NET. Incoming network packet. Followed by: + + - 1-byte network adapter id. + - 4-byte packet flags. + - Array with packet bytes. + + - EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu, + e.g., by closing the window. + - EVENT_CHAR_WRITE. Used to synchronize character output operations. Followed by: + + - 4-byte output function return value. + - 4-byte offset in the output array. + + - EVENT_CHAR_READ_ALL. Used to synchronize character input operations, + initiated by qemu. Followed by: + + - Array with bytes that were read. + + - EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation, + initiated by qemu. Followed by: + + - 4-byte error code. + + - EVENT_CLOCK + clock_id. Group of events for host clock read operations. Followed by: + + - 8-byte clock value. + + - EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of + CPU, internal threads, and asynchronous input events. + - EVENT_END. Last event in the log. diff --git a/docs/devel/replay.txt b/docs/devel/replay.txt deleted file mode 100644 index e641c35add5e..000000000000 --- a/docs/devel/replay.txt +++ /dev/null @@ -1,46 +0,0 @@ -Record/replay mechanism, that could be enabled through icount mode, expects -the virtual devices to satisfy the following requirements. - -The main idea behind this document is that everything that affects -the guest state during execution in icount mode should be deterministic. - -Timers -====== - -All virtual devices should use virtual clock for timers that change the guest -state. Virtual clock is deterministic, therefore such timers are deterministic -too. - -Virtual devices can also use realtime clock for the events that do not change -the guest state directly. When the clock ticking should depend on VM execution -speed, use virtual clock with EXTERNAL attribute. It is not deterministic, -but its speed depends on the guest execution. This clock is used by -the virtual devices (e.g., slirp routing device) that lie outside the -replayed guest. - -Bottom halves -============= - -Bottom half callbacks, that affect the guest state, should be invoked through -replay_bh_schedule_event or replay_bh_schedule_oneshot_event functions. -Their invocations are saved in record mode and synchronized with the existing -log in replay mode. - -Saving/restoring the VM state -============================= - -All fields in the device state structure (including virtual timers) -should be restored by loadvm to the same values they had before savevm. - -Avoid accessing other devices' state, because the order of saving/restoring -is not defined. It means that you should not call functions like -'update_irq' in post_load callback. Save everything explicitly to avoid -the dependencies that may make restoring the VM state non-deterministic. - -Stopping the VM -=============== - -Stopping the guest should not interfere with its state (with the exception -of the network connections, that could be broken by the remote timeouts). -VM can be stopped at any moment of replay by the user. Restarting the VM -after that stop should not break the replay by the unneeded guest state change. diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst index abea1102dc4c..7cc6a6b31402 100644 --- a/docs/devel/reset.rst +++ b/docs/devel/reset.rst @@ -210,9 +210,11 @@ Polling the reset state Resettable interface provides the ``resettable_is_in_reset()`` function. This function returns true if the object parameter is currently under reset. -An object is under reset from the beginning of the *init* phase to the end of -the *exit* phase. During all three phases, the function will return that the -object is in reset. +An object is under reset from the beginning of the *enter* phase (before +either its children or its own enter method is called) to the *exit* +phase. During *enter* and *hold* phase only, the function will return that the +object is in reset. The state is changed after the *exit* is propagated to +its children and just before calling the object's own *exit* method. This function may be used if the object behavior has to be adapted while in reset state. For example if a device has an irq input, diff --git a/docs/devel/style.rst b/docs/devel/style.rst index 9e66d133e15b..68aa77693078 100644 --- a/docs/devel/style.rst +++ b/docs/devel/style.rst @@ -293,6 +293,13 @@ that QEMU depends on. Do not include "qemu/osdep.h" from header files since the .c file will have already included it. +Headers should normally include everything they need beyond osdep.h. +If exceptions are needed for some reason, they must be documented in +the header. If all that's needed from a header is typedefs, consider +putting those into qemu/typedefs.h instead of including the header. + +Cyclic inclusion is forbidden. + C types ======= @@ -522,7 +529,7 @@ documented in the GNU Compiler Collection manual starting at version 4.0. Automatic memory deallocation ============================= -QEMU has a mandatory dependency either the GCC or CLang compiler. As +QEMU has a mandatory dependency on either the GCC or the Clang compiler. As such it has the freedom to make use of a C language extension for automatically running a cleanup function when a stack variable goes out of scope. This can be used to simplify function cleanup paths, diff --git a/docs/devel/submitting-a-patch.rst b/docs/devel/submitting-a-patch.rst index e51259eb9cac..c641d948f160 100644 --- a/docs/devel/submitting-a-patch.rst +++ b/docs/devel/submitting-a-patch.rst @@ -3,34 +3,27 @@ Submitting a Patch ================== -QEMU welcomes contributions of code (either fixing bugs or adding new -functionality). However, we get a lot of patches, and so we have some -guidelines about submitting patches. If you follow these, you'll help -make our task of code review easier and your patch is likely to be -committed faster. +QEMU welcomes contributions to fix bugs, add functionality or improve +the documentation. However, we get a lot of patches, and so we have +some guidelines about submitting them. If you follow these, you'll +help make our task of contribution review easier and your change is +likely to be accepted and committed faster. This page seems very long, so if you are only trying to post a quick one-shot fix, the bare minimum we ask is that: -- You **must** provide a Signed-off-by: line (this is a hard - requirement because it's how you say "I'm legally okay to contribute - this and happy for it to go into QEMU", modeled after the `Linux kernel - `__ - policy.) ``git commit -s`` or ``git format-patch -s`` will add one. -- All contributions to QEMU must be **sent as patches** to the - qemu-devel `mailing list `__. Patch contributions - should not be posted on the bug tracker, posted on forums, or - externally hosted and linked to. (We have other mailing lists too, - but all patches must go to qemu-devel, possibly with a Cc: to another - list.) ``git send-email`` (`step-by-step setup - guide `__ and `hints and - tips `__) - works best for delivering the patch without mangling it, but - attachments can be used as a last resort on a first-time submission. -- You must read replies to your message, and be willing to act on them. - Note, however, that maintainers are often willing to manually fix up - first-time contributions, since there is a learning curve involved in - making an ideal patch submission. +.. list-table:: Minimal Checklist for Patches + :widths: 35 65 + :header-rows: 1 + + * - Check + - Reason + * - Patches contain Signed-off-by: Real Name + - States you are legally able to contribute the code. See :ref:`patch_emails_must_include_a_signed_off_by_line` + * - Sent as patch emails to ``qemu-devel@nongnu.org`` + - The project uses an email list based workflow. See :ref:`submitting_your_patches` + * - Be prepared to respond to review comments + - Code that doesn't pass review will not get merged. See :ref:`participating_in_code_review` You do not have to subscribe to post (list policy is to reply-to-all to preserve CCs and keep non-subscribers in the loop on the threads they @@ -39,7 +32,7 @@ ideas from other posts. If you do subscribe, be prepared for a high volume of email, often over one thousand messages in a week. The list is moderated; first-time posts from an email address (whether or not you subscribed) may be subject to some delay while waiting for a moderator -to whitelist your address. +to allow your address. The larger your contribution is, or if you plan on becoming a long-term contributor, then the more important the rest of this page becomes. @@ -204,29 +197,44 @@ log`` for these keywords for example usage. Test your patches ~~~~~~~~~~~~~~~~~ -Although QEMU has `continuous integration -services `__ that attempt to test -patches submitted to the list, it still saves everyone time if you have -already tested that your patch compiles and works. Because QEMU is such -a large project, it's okay to use configure arguments to limit what is -built for faster turnaround during your development time; but it is -still wise to also check that your patches work with a full build before -submitting a series, especially if your changes might have an unintended -effect on other areas of the code you don't normally experiment with. -See `Testing `__ for more details on what tests are available. -Also, it is a wise idea to include a testsuite addition as part of your -patches - either to ensure that future changes won't regress your new -feature, or to add a test which exposes the bug that the rest of your -series fixes. Keeping separate commits for the test and the fix allows -reviewers to rebase the test to occur first to prove it catches the -problem, then again to place it last in the series so that bisection -doesn't land on a known-broken state. +Although QEMU uses various :ref:`ci` services that attempt to test +patches submitted to the list, it still saves everyone time if you +have already tested that your patch compiles and works. Because QEMU +is such a large project the default configuration won't create a +testing pipeline on GitLab when a branch is pushed. See the :ref:`CI +variable documentation` for details on how to control the +running of tests; but it is still wise to also check that your patches +work with a full build before submitting a series, especially if your +changes might have an unintended effect on other areas of the code you +don't normally experiment with. See :ref:`testing` for more details on +what tests are available. + +Also, it is a wise idea to include a testsuite addition as part of +your patches - either to ensure that future changes won't regress your +new feature, or to add a test which exposes the bug that the rest of +your series fixes. Keeping separate commits for the test and the fix +allows reviewers to rebase the test to occur first to prove it catches +the problem, then again to place it last in the series so that +bisection doesn't land on a known-broken state. .. _submitting_your_patches: Submitting your Patches ----------------------- +The QEMU project uses a public email based workflow for reviewing and +merging patches. As a result all contributions to QEMU must be **sent +as patches** to the qemu-devel `mailing list +`__. Patch +contributions should not be posted on the bug tracker, posted on +forums, or externally hosted and linked to. (We have other mailing +lists too, but all patches must go to qemu-devel, possibly with a Cc: +to another list.) ``git send-email`` (`step-by-step setup guide +`__ and `hints and tips +`__) +works best for delivering the patch without mangling it, but +attachments can be used as a last resort on a first-time submission. + .. _if_you_cannot_send_patch_emails: If you cannot send patch emails @@ -312,10 +320,12 @@ git repository to fetch the original commit. Patch emails must include a ``Signed-off-by:`` line ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For more information see `SubmittingPatches 1.12 -`__. -This is vital or we will not be able to apply your patch! Please use -your real name to sign a patch (not an alias or acronym). +Your patches **must** include a Signed-off-by: line. This is a hard +requirement because it's how you say "I'm legally okay to contribute +this and happy for it to go into QEMU". The process is modelled after +the `Linux kernel +`__ +policy. If you wrote the patch, make sure your "From:" and "Signed-off-by:" lines use the same spelling. It's okay if you subscribe or contribute to @@ -325,6 +335,11 @@ include a "From:" line in the body of the email (different from your envelope From:) that will give credit to the correct author; but again, that author's Signed-off-by: line is mandatory, with the same spelling. +There are various tooling options for automatically adding these tags +include using ``git commit -s`` or ``git format-patch -s``. For more +information see `SubmittingPatches 1.12 +`__. + .. _include_a_meaningful_cover_letter: Include a meaningful cover letter @@ -395,9 +410,19 @@ Participating in Code Review ---------------------------- All patches submitted to the QEMU project go through a code review -process before they are accepted. Some areas of code that are well -maintained may review patches quickly, lesser-loved areas of code may -have a longer delay. +process before they are accepted. This will often mean a series will +go through a number of iterations before being picked up by +:ref:`maintainers`. You therefore should be prepared to +read replies to your messages and be willing to act on them. + +Maintainers are often willing to manually fix up first-time +contributions, since there is a learning curve involved in making an +ideal patch submission. However for the best results you should +proactively respond to suggestions with changes or justifications for +your current approach. + +Some areas of code that are well maintained may review patches +quickly, lesser-loved areas of code may have a longer delay. .. _stay_around_to_fix_problems_raised_in_code_review: @@ -409,14 +434,20 @@ developers will identify bugs, or suggest a cleaner approach, or even just point out code style issues or commit message typos. You'll need to respond to these, and then send a second version of your patches with the issues fixed. This takes a little time and effort on your part, but -if you don't do it then your changes will never get into QEMU. It's also -just polite -- it is quite disheartening for a developer to spend time -reviewing your code and suggesting improvements, only to find that -you're not going to do anything further and it was all wasted effort. +if you don't do it then your changes will never get into QEMU. + +Remember that a maintainer is under no obligation to take your +patches. If someone has spent the time reviewing your code and +suggesting improvements and you simply re-post without either +addressing the comment directly or providing additional justification +for the change then it becomes wasted effort. You cannot demand others +merge and then fix up your code after the fact. When replying to comments on your patches **reply to all and not just the sender** -- keeping discussion on the mailing list means everybody -can follow it. +can follow it. Remember the spirit of the :ref:`code_of_conduct` and +keep discussions respectful and collaborative and avoid making +personal comments. .. _pay_attention_to_review_comments: diff --git a/docs/devel/submitting-a-pull-request.rst b/docs/devel/submitting-a-pull-request.rst index c9d1e8afd91a..a4cd7ebbb6aa 100644 --- a/docs/devel/submitting-a-pull-request.rst +++ b/docs/devel/submitting-a-pull-request.rst @@ -53,14 +53,10 @@ series) and that "make check" passes before sending out the pull request. As a submaintainer you're one of QEMU's lines of defense against bad code, so double check the details. -**All pull requests must be signed**. If your key is not already signed -by members of the QEMU community, you should make arrangements to attend -a `KeySigningParty `__ (for -example at KVM Forum) or make alternative arrangements to have your key -signed by an attendee. Key signing requires meeting another community -member \*in person\* so please make appropriate arrangements. By -"signed" here we mean that the pullreq email should quote a tag which is -a GPG-signed tag (as created with 'gpg tag -s ...'). +**All pull requests must be signed**. By "signed" here we mean that +the pullreq email should quote a tag which is a GPG-signed tag (as +created with 'gpg tag -s ...'). See :ref:`maintainer_keys` for +details. **Pull requests not for master should say "not for master" and have "PULL SUBSYSTEM whatever" in the subject tag**. If your pull request is diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst new file mode 100644 index 000000000000..9adc0c9b6cc2 --- /dev/null +++ b/docs/devel/tcg-ops.rst @@ -0,0 +1,941 @@ +.. _tcg-ops-ref: + +******************************* +TCG Intermediate Representation +******************************* + +Introduction +============ + +TCG (Tiny Code Generator) began as a generic backend for a C +compiler. It was simplified to be used in QEMU. It also has its roots +in the QOP code generator written by Paul Brook. + +Definitions +=========== + +TCG receives RISC-like *TCG ops* and performs some optimizations on them, +including liveness analysis and trivial constant expression +evaluation. TCG ops are then implemented in the host CPU back end, +also known as the TCG target. + +The TCG *target* is the architecture for which we generate the +code. It is of course not the same as the "target" of QEMU which is +the emulated architecture. As TCG started as a generic C backend used +for cross compiling, it is assumed that the TCG target is different +from the host, although it is never the case for QEMU. + +In this document, we use *guest* to specify what architecture we are +emulating; *target* always means the TCG target, the machine on which +we are running QEMU. + +A TCG *function* corresponds to a QEMU Translated Block (TB). + +A TCG *temporary* is a variable only live in a basic block. Temporaries are allocated explicitly in each function. + +A TCG *local temporary* is a variable only live in a function. Local temporaries are allocated explicitly in each function. + +A TCG *global* is a variable which is live in all the functions +(equivalent of a C global variable). They are defined before the +functions defined. A TCG global can be a memory location (e.g. a QEMU +CPU register), a fixed host register (e.g. the QEMU CPU state pointer) +or a memory location which is stored in a register outside QEMU TBs +(not implemented yet). + +A TCG *basic block* corresponds to a list of instructions terminated +by a branch instruction. + +An operation with *undefined behavior* may result in a crash. + +An operation with *unspecified behavior* shall not crash. However, +the result may be one of several possibilities so may be considered +an *undefined result*. + +Intermediate representation +=========================== + +Introduction +------------ + +TCG instructions operate on variables which are temporaries, local +temporaries or globals. TCG instructions and variables are strongly +typed. Two types are supported: 32 bit integers and 64 bit +integers. Pointers are defined as an alias to 32 bit or 64 bit +integers depending on the TCG target word size. + +Each instruction has a fixed number of output variable operands, input +variable operands and always constant operands. + +The notable exception is the call instruction which has a variable +number of outputs and inputs. + +In the textual form, output operands usually come first, followed by +input operands, followed by constant operands. The output type is +included in the instruction name. Constants are prefixed with a '$'. + +.. code-block:: none + + add_i32 t0, t1, t2 /* (t0 <- t1 + t2) */ + + +Assumptions +----------- + +Basic blocks +^^^^^^^^^^^^ + +* Basic blocks end after branches (e.g. brcond_i32 instruction), + goto_tb and exit_tb instructions. + +* Basic blocks start after the end of a previous basic block, or at a + set_label instruction. + +After the end of a basic block, the content of temporaries is +destroyed, but local temporaries and globals are preserved. + +Floating point types +^^^^^^^^^^^^^^^^^^^^ + +* Floating point types are not supported yet + +Pointers +^^^^^^^^ + +* Depending on the TCG target, pointer size is 32 bit or 64 + bit. The type ``TCG_TYPE_PTR`` is an alias to ``TCG_TYPE_I32`` or + ``TCG_TYPE_I64``. + +Helpers +^^^^^^^ + +* Using the tcg_gen_helper_x_y it is possible to call any function + taking i32, i64 or pointer types. By default, before calling a helper, + all globals are stored at their canonical location and it is assumed + that the function can modify them. By default, the helper is allowed to + modify the CPU state or raise an exception. + + This can be overridden using the following function modifiers: + + - ``TCG_CALL_NO_READ_GLOBALS`` means that the helper does not read globals, + either directly or via an exception. They will not be saved to their + canonical locations before calling the helper. + + - ``TCG_CALL_NO_WRITE_GLOBALS`` means that the helper does not modify any globals. + They will only be saved to their canonical location before calling helpers, + but they won't be reloaded afterwards. + + - ``TCG_CALL_NO_SIDE_EFFECTS`` means that the call to the function is removed if + the return value is not used. + + Note that ``TCG_CALL_NO_READ_GLOBALS`` implies ``TCG_CALL_NO_WRITE_GLOBALS``. + + On some TCG targets (e.g. x86), several calling conventions are + supported. + +Branches +^^^^^^^^ + +* Use the instruction 'br' to jump to a label. + +Code Optimizations +------------------ + +When generating instructions, you can count on at least the following +optimizations: + +- Single instructions are simplified, e.g. + + .. code-block:: none + + and_i32 t0, t0, $0xffffffff + + is suppressed. + +- A liveness analysis is done at the basic block level. The + information is used to suppress moves from a dead variable to + another one. It is also used to remove instructions which compute + dead results. The later is especially useful for condition code + optimization in QEMU. + + In the following example: + + .. code-block:: none + + add_i32 t0, t1, t2 + add_i32 t0, t0, $1 + mov_i32 t0, $1 + + only the last instruction is kept. + + +Instruction Reference +===================== + +Function call +------------- + +.. list-table:: + + * - call ** ** ptr + + - | call function 'ptr' (pointer type) + | + | ** optional 32 bit or 64 bit return value + | ** optional 32 bit or 64 bit parameters + +Jumps/Labels +------------ + +.. list-table:: + + * - set_label $label + + - | Define label 'label' at the current program point. + + * - br $label + + - | Jump to label. + + * - brcond_i32/i64 *t0*, *t1*, *cond*, *label* + + - | Conditional jump if *t0* *cond* *t1* is true. *cond* can be: + | + | ``TCG_COND_EQ`` + | ``TCG_COND_NE`` + | ``TCG_COND_LT /* signed */`` + | ``TCG_COND_GE /* signed */`` + | ``TCG_COND_LE /* signed */`` + | ``TCG_COND_GT /* signed */`` + | ``TCG_COND_LTU /* unsigned */`` + | ``TCG_COND_GEU /* unsigned */`` + | ``TCG_COND_LEU /* unsigned */`` + | ``TCG_COND_GTU /* unsigned */`` + +Arithmetic +---------- + +.. list-table:: + + * - add_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* + *t2* + + * - sub_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* - *t2* + + * - neg_i32/i64 *t0*, *t1* + + - | *t0* = -*t1* (two's complement) + + * - mul_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* * *t2* + + * - div_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* / *t2* (signed) + | Undefined behavior if division by zero or overflow. + + * - divu_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* / *t2* (unsigned) + | Undefined behavior if division by zero. + + * - rem_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* % *t2* (signed) + | Undefined behavior if division by zero or overflow. + + * - remu_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* % *t2* (unsigned) + | Undefined behavior if division by zero. + + +Logical +------- + +.. list-table:: + + * - and_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* & *t2* + + * - or_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* | *t2* + + * - xor_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* ^ *t2* + + * - not_i32/i64 *t0*, *t1* + + - | *t0* = ~\ *t1* + + * - andc_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* & ~\ *t2* + + * - eqv_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = ~(*t1* ^ *t2*), or equivalently, *t0* = *t1* ^ ~\ *t2* + + * - nand_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = ~(*t1* & *t2*) + + * - nor_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = ~(*t1* | *t2*) + + * - orc_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* | ~\ *t2* + + * - clz_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* ? clz(*t1*) : *t2* + + * - ctz_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* ? ctz(*t1*) : *t2* + + * - ctpop_i32/i64 *t0*, *t1* + + - | *t0* = number of bits set in *t1* + | + | With *ctpop* short for "count population", matching + | the function name used in ``include/qemu/host-utils.h``. + + +Shifts/Rotates +-------------- + +.. list-table:: + + * - shl_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* << *t2* + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + + * - shr_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* >> *t2* (unsigned) + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + + * - sar_i32/i64 *t0*, *t1*, *t2* + + - | *t0* = *t1* >> *t2* (signed) + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + + * - rotl_i32/i64 *t0*, *t1*, *t2* + + - | Rotation of *t2* bits to the left + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + + * - rotr_i32/i64 *t0*, *t1*, *t2* + + - | Rotation of *t2* bits to the right. + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + + +Misc +---- + +.. list-table:: + + * - mov_i32/i64 *t0*, *t1* + + - | *t0* = *t1* + | Move *t1* to *t0* (both operands must have the same type). + + * - ext8s_i32/i64 *t0*, *t1* + + ext8u_i32/i64 *t0*, *t1* + + ext16s_i32/i64 *t0*, *t1* + + ext16u_i32/i64 *t0*, *t1* + + ext32s_i64 *t0*, *t1* + + ext32u_i64 *t0*, *t1* + + - | 8, 16 or 32 bit sign/zero extension (both operands must have the same type) + + * - bswap16_i32/i64 *t0*, *t1*, *flags* + + - | 16 bit byte swap on the low bits of a 32/64 bit input. + | + | If *flags* & ``TCG_BSWAP_IZ``, then *t1* is known to be zero-extended from bit 15. + | If *flags* & ``TCG_BSWAP_OZ``, then *t0* will be zero-extended from bit 15. + | If *flags* & ``TCG_BSWAP_OS``, then *t0* will be sign-extended from bit 15. + | + | If neither ``TCG_BSWAP_OZ`` nor ``TCG_BSWAP_OS`` are set, then the bits of *t0* above bit 15 may contain any value. + + * - bswap32_i64 *t0*, *t1*, *flags* + + - | 32 bit byte swap on a 64-bit value. The flags are the same as for bswap16, + except they apply from bit 31 instead of bit 15. + + * - bswap32_i32 *t0*, *t1*, *flags* + + bswap64_i64 *t0*, *t1*, *flags* + + - | 32/64 bit byte swap. The flags are ignored, but still present + for consistency with the other bswap opcodes. + + * - discard_i32/i64 *t0* + + - | Indicate that the value of *t0* won't be used later. It is useful to + force dead code elimination. + + * - deposit_i32/i64 *dest*, *t1*, *t2*, *pos*, *len* + + - | Deposit *t2* as a bitfield into *t1*, placing the result in *dest*. + | + | The bitfield is described by *pos*/*len*, which are immediate values: + | + | *len* - the length of the bitfield + | *pos* - the position of the first bit, counting from the LSB + | + | For example, "deposit_i32 dest, t1, t2, 8, 4" indicates a 4-bit field + at bit 8. This operation would be equivalent to + | + | *dest* = (*t1* & ~0x0f00) | ((*t2* << 8) & 0x0f00) + + * - extract_i32/i64 *dest*, *t1*, *pos*, *len* + + sextract_i32/i64 *dest*, *t1*, *pos*, *len* + + - | Extract a bitfield from *t1*, placing the result in *dest*. + | + | The bitfield is described by *pos*/*len*, which are immediate values, + as above for deposit. For extract_*, the result will be extended + to the left with zeros; for sextract_*, the result will be extended + to the left with copies of the bitfield sign bit at *pos* + *len* - 1. + | + | For example, "sextract_i32 dest, t1, 8, 4" indicates a 4-bit field + at bit 8. This operation would be equivalent to + | + | *dest* = (*t1* << 20) >> 28 + | + | (using an arithmetic right shift). + + * - extract2_i32/i64 *dest*, *t1*, *t2*, *pos* + + - | For N = {32,64}, extract an N-bit quantity from the concatenation + of *t2*:*t1*, beginning at *pos*. The tcg_gen_extract2_{i32,i64} expander + accepts 0 <= *pos* <= N as inputs. The backend code generator will + not see either 0 or N as inputs for these opcodes. + + * - extrl_i64_i32 *t0*, *t1* + + - | For 64-bit hosts only, extract the low 32-bits of input *t1* and place it + into 32-bit output *t0*. Depending on the host, this may be a simple move, + or may require additional canonicalization. + + * - extrh_i64_i32 *t0*, *t1* + + - | For 64-bit hosts only, extract the high 32-bits of input *t1* and place it + into 32-bit output *t0*. Depending on the host, this may be a simple shift, + or may require additional canonicalization. + + +Conditional moves +----------------- + +.. list-table:: + + * - setcond_i32/i64 *dest*, *t1*, *t2*, *cond* + + - | *dest* = (*t1* *cond* *t2*) + | + | Set *dest* to 1 if (*t1* *cond* *t2*) is true, otherwise set to 0. + + * - movcond_i32/i64 *dest*, *c1*, *c2*, *v1*, *v2*, *cond* + + - | *dest* = (*c1* *cond* *c2* ? *v1* : *v2*) + | + | Set *dest* to *v1* if (*c1* *cond* *c2*) is true, otherwise set to *v2*. + + +Type conversions +---------------- + +.. list-table:: + + * - ext_i32_i64 *t0*, *t1* + + - | Convert *t1* (32 bit) to *t0* (64 bit) and does sign extension + + * - extu_i32_i64 *t0*, *t1* + + - | Convert *t1* (32 bit) to *t0* (64 bit) and does zero extension + + * - trunc_i64_i32 *t0*, *t1* + + - | Truncate *t1* (64 bit) to *t0* (32 bit) + + * - concat_i32_i64 *t0*, *t1*, *t2* + + - | Construct *t0* (64-bit) taking the low half from *t1* (32 bit) and the high half + from *t2* (32 bit). + + * - concat32_i64 *t0*, *t1*, *t2* + + - | Construct *t0* (64-bit) taking the low half from *t1* (64 bit) and the high half + from *t2* (64 bit). + + +Load/Store +---------- + +.. list-table:: + + * - ld_i32/i64 *t0*, *t1*, *offset* + + ld8s_i32/i64 *t0*, *t1*, *offset* + + ld8u_i32/i64 *t0*, *t1*, *offset* + + ld16s_i32/i64 *t0*, *t1*, *offset* + + ld16u_i32/i64 *t0*, *t1*, *offset* + + ld32s_i64 t0, *t1*, *offset* + + ld32u_i64 t0, *t1*, *offset* + + - | *t0* = read(*t1* + *offset*) + | + | Load 8, 16, 32 or 64 bits with or without sign extension from host memory. + *offset* must be a constant. + + * - st_i32/i64 *t0*, *t1*, *offset* + + st8_i32/i64 *t0*, *t1*, *offset* + + st16_i32/i64 *t0*, *t1*, *offset* + + st32_i64 *t0*, *t1*, *offset* + + - | write(*t0*, *t1* + *offset*) + | + | Write 8, 16, 32 or 64 bits to host memory. + +All this opcodes assume that the pointed host memory doesn't correspond +to a global. In the latter case the behaviour is unpredictable. + + +Multiword arithmetic support +---------------------------- + +.. list-table:: + + * - add2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* + + sub2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* + + - | Similar to add/sub, except that the double-word inputs *t1* and *t2* are + formed from two single-word arguments, and the double-word output *t0* + is returned in two single-word outputs. + + * - mulu2_i32/i64 *t0_low*, *t0_high*, *t1*, *t2* + + - | Similar to mul, except two unsigned inputs *t1* and *t2* yielding the full + double-word product *t0*. The latter is returned in two single-word outputs. + + * - muls2_i32/i64 *t0_low*, *t0_high*, *t1*, *t2* + + - | Similar to mulu2, except the two inputs *t1* and *t2* are signed. + + * - mulsh_i32/i64 *t0*, *t1*, *t2* + + muluh_i32/i64 *t0*, *t1*, *t2* + + - | Provide the high part of a signed or unsigned multiply, respectively. + | + | If mulu2/muls2 are not provided by the backend, the tcg-op generator + can obtain the same results by emitting a pair of opcodes, mul + muluh/mulsh. + + +Memory Barrier support +---------------------- + +.. list-table:: + + * - mb *<$arg>* + + - | Generate a target memory barrier instruction to ensure memory ordering + as being enforced by a corresponding guest memory barrier instruction. + | + | The ordering enforced by the backend may be stricter than the ordering + required by the guest. It cannot be weaker. This opcode takes a constant + argument which is required to generate the appropriate barrier + instruction. The backend should take care to emit the target barrier + instruction only when necessary i.e., for SMP guests and when MTTCG is + enabled. + | + | The guest translators should generate this opcode for all guest instructions + which have ordering side effects. + | + | Please see :ref:`atomics-ref` for more information on memory barriers. + + +64-bit guest on 32-bit host support +----------------------------------- + +The following opcodes are internal to TCG. Thus they are to be implemented by +32-bit host code generators, but are not to be emitted by guest translators. +They are emitted as needed by inline functions within ``tcg-op.h``. + +.. list-table:: + + * - brcond2_i32 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *cond*, *label* + + - | Similar to brcond, except that the 64-bit values *t0* and *t1* + are formed from two 32-bit arguments. + + * - setcond2_i32 *dest*, *t1_low*, *t1_high*, *t2_low*, *t2_high*, *cond* + + - | Similar to setcond, except that the 64-bit values *t1* and *t2* are + formed from two 32-bit arguments. The result is a 32-bit value. + + +QEMU specific operations +------------------------ + +.. list-table:: + + * - exit_tb *t0* + + - | Exit the current TB and return the value *t0* (word type). + + * - goto_tb *index* + + - | Exit the current TB and jump to the TB index *index* (constant) if the + current TB was linked to this TB. Otherwise execute the next + instructions. Only indices 0 and 1 are valid and tcg_gen_goto_tb may be issued + at most once with each slot index per TB. + + * - lookup_and_goto_ptr *tb_addr* + + - | Look up a TB address *tb_addr* and jump to it if valid. If not valid, + jump to the TCG epilogue to go back to the exec loop. + | + | This operation is optional. If the TCG backend does not implement the + goto_ptr opcode, emitting this op is equivalent to emitting exit_tb(0). + + * - qemu_ld_i32/i64 *t0*, *t1*, *flags*, *memidx* + + qemu_st_i32/i64 *t0*, *t1*, *flags*, *memidx* + + qemu_st8_i32 *t0*, *t1*, *flags*, *memidx* + + - | Load data at the guest address *t1* into *t0*, or store data in *t0* at guest + address *t1*. The _i32/_i64 size applies to the size of the input/output + register *t0* only. The address *t1* is always sized according to the guest, + and the width of the memory operation is controlled by *flags*. + | + | Both *t0* and *t1* may be split into little-endian ordered pairs of registers + if dealing with 64-bit quantities on a 32-bit host. + | + | The *memidx* selects the qemu tlb index to use (e.g. user or kernel access). + The flags are the MemOp bits, selecting the sign, width, and endianness + of the memory access. + | + | For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a + 64-bit memory access specified in *flags*. + | + | For i386, qemu_st8_i32 is exactly like qemu_st_i32, except the size of + the memory operation is known to be 8-bit. This allows the backend to + provide a different set of register constraints. + + +Host vector operations +---------------------- + +All of the vector ops have two parameters, ``TCGOP_VECL`` & ``TCGOP_VECE``. +The former specifies the length of the vector in log2 64-bit units; the +latter specifies the length of the element (if applicable) in log2 8-bit units. +E.g. VECL = 1 -> 64 << 1 -> v128, and VECE = 2 -> 1 << 2 -> i32. + +.. list-table:: + + * - mov_vec *v0*, *v1* + ld_vec *v0*, *t1* + st_vec *v0*, *t1* + + - | Move, load and store. + + * - dup_vec *v0*, *r1* + + - | Duplicate the low N bits of *r1* into VECL/VECE copies across *v0*. + + * - dupi_vec *v0*, *c* + + - | Similarly, for a constant. + | Smaller values will be replicated to host register size by the expanders. + + * - dup2_vec *v0*, *r1*, *r2* + + - | Duplicate *r2*:*r1* into VECL/64 copies across *v0*. This opcode is + only present for 32-bit hosts. + + * - add_vec *v0*, *v1*, *v2* + + - | *v0* = *v1* + *v2*, in elements across the vector. + + * - sub_vec *v0*, *v1*, *v2* + + - | Similarly, *v0* = *v1* - *v2*. + + * - mul_vec *v0*, *v1*, *v2* + + - | Similarly, *v0* = *v1* * *v2*. + + * - neg_vec *v0*, *v1* + + - | Similarly, *v0* = -*v1*. + + * - abs_vec *v0*, *v1* + + - | Similarly, *v0* = *v1* < 0 ? -*v1* : *v1*, in elements across the vector. + + * - smin_vec *v0*, *v1*, *v2* + + umin_vec *v0*, *v1*, *v2* + + - | Similarly, *v0* = MIN(*v1*, *v2*), for signed and unsigned element types. + + * - smax_vec *v0*, *v1*, *v2* + + umax_vec *v0*, *v1*, *v2* + + - | Similarly, *v0* = MAX(*v1*, *v2*), for signed and unsigned element types. + + * - ssadd_vec *v0*, *v1*, *v2* + + sssub_vec *v0*, *v1*, *v2* + + usadd_vec *v0*, *v1*, *v2* + + ussub_vec *v0*, *v1*, *v2* + + - | Signed and unsigned saturating addition and subtraction. + | + | If the true result is not representable within the element type, the + element is set to the minimum or maximum value for the type. + + * - and_vec *v0*, *v1*, *v2* + + or_vec *v0*, *v1*, *v2* + + xor_vec *v0*, *v1*, *v2* + + andc_vec *v0*, *v1*, *v2* + + orc_vec *v0*, *v1*, *v2* + + not_vec *v0*, *v1* + + - | Similarly, logical operations with and without complement. + | + | Note that VECE is unused. + + * - shli_vec *v0*, *v1*, *i2* + + shls_vec *v0*, *v1*, *s2* + + - | Shift all elements from v1 by a scalar *i2*/*s2*. I.e. + + .. code-block:: c + + for (i = 0; i < VECL/VECE; ++i) { + v0[i] = v1[i] << s2; + } + + * - shri_vec *v0*, *v1*, *i2* + + sari_vec *v0*, *v1*, *i2* + + rotli_vec *v0*, *v1*, *i2* + + shrs_vec *v0*, *v1*, *s2* + + sars_vec *v0*, *v1*, *s2* + + - | Similarly for logical and arithmetic right shift, and left rotate. + + * - shlv_vec *v0*, *v1*, *v2* + + - | Shift elements from *v1* by elements from *v2*. I.e. + + .. code-block:: c + + for (i = 0; i < VECL/VECE; ++i) { + v0[i] = v1[i] << v2[i]; + } + + * - shrv_vec *v0*, *v1*, *v2* + + sarv_vec *v0*, *v1*, *v2* + + rotlv_vec *v0*, *v1*, *v2* + + rotrv_vec *v0*, *v1*, *v2* + + - | Similarly for logical and arithmetic right shift, and rotates. + + * - cmp_vec *v0*, *v1*, *v2*, *cond* + + - | Compare vectors by element, storing -1 for true and 0 for false. + + * - bitsel_vec *v0*, *v1*, *v2*, *v3* + + - | Bitwise select, *v0* = (*v2* & *v1*) | (*v3* & ~\ *v1*), across the entire vector. + + * - cmpsel_vec *v0*, *c1*, *c2*, *v3*, *v4*, *cond* + + - | Select elements based on comparison results: + + .. code-block:: c + + for (i = 0; i < n; ++i) { + v0[i] = (c1[i] cond c2[i]) ? v3[i] : v4[i]. + } + +**Note 1**: Some shortcuts are defined when the last operand is known to be +a constant (e.g. addi for add, movi for mov). + +**Note 2**: When using TCG, the opcodes must never be generated directly +as some of them may not be available as "real" opcodes. Always use the +function tcg_gen_xxx(args). + + +Backend +======= + +``tcg-target.h`` contains the target specific definitions. ``tcg-target.c.inc`` +contains the target specific code; it is #included by ``tcg/tcg.c``, rather +than being a standalone C file. + +Assumptions +----------- + +The target word size (``TCG_TARGET_REG_BITS``) is expected to be 32 bit or +64 bit. It is expected that the pointer has the same size as the word. + +On a 32 bit target, all 64 bit operations are converted to 32 bits. A +few specific operations must be implemented to allow it (see add2_i32, +sub2_i32, brcond2_i32). + +On a 64 bit target, the values are transferred between 32 and 64-bit +registers using the following ops: + +- trunc_shr_i64_i32 +- ext_i32_i64 +- extu_i32_i64 + +They ensure that the values are correctly truncated or extended when +moved from a 32-bit to a 64-bit register or vice-versa. Note that the +trunc_shr_i64_i32 is an optional op. It is not necessary to implement +it if all the following conditions are met: + +- 64-bit registers can hold 32-bit values +- 32-bit values in a 64-bit register do not need to stay zero or + sign extended +- all 32-bit TCG ops ignore the high part of 64-bit registers + +Floating point operations are not supported in this version. A +previous incarnation of the code generator had full support of them, +but it is better to concentrate on integer operations first. + +Constraints +---------------- + +GCC like constraints are used to define the constraints of every +instruction. Memory constraints are not supported in this +version. Aliases are specified in the input operands as for GCC. + +The same register may be used for both an input and an output, even when +they are not explicitly aliased. If an op expands to multiple target +instructions then care must be taken to avoid clobbering input values. +GCC style "early clobber" outputs are supported, with '``&``'. + +A target can define specific register or constant constraints. If an +operation uses a constant input constraint which does not allow all +constants, it must also accept registers in order to have a fallback. +The constraint '``i``' is defined generically to accept any constant. +The constraint '``r``' is not defined generically, but is consistently +used by each backend to indicate all registers. + +The movi_i32 and movi_i64 operations must accept any constants. + +The mov_i32 and mov_i64 operations must accept any registers of the +same type. + +The ld/st/sti instructions must accept signed 32 bit constant offsets. +This can be implemented by reserving a specific register in which to +compute the address if the offset is too big. + +The ld/st instructions must accept any destination (ld) or source (st) +register. + +The sti instruction may fail if it cannot store the given constant. + +Function call assumptions +------------------------- + +- The only supported types for parameters and return value are: 32 and + 64 bit integers and pointer. +- The stack grows downwards. +- The first N parameters are passed in registers. +- The next parameters are passed on the stack by storing them as words. +- Some registers are clobbered during the call. +- The function can return 0 or 1 value in registers. On a 32 bit + target, functions must be able to return 2 values in registers for + 64 bit return type. + + +Recommended coding rules for best performance +============================================= + +- Use globals to represent the parts of the QEMU CPU state which are + often modified, e.g. the integer registers and the condition + codes. TCG will be able to use host registers to store them. + +- Avoid globals stored in fixed registers. They must be used only to + store the pointer to the CPU state and possibly to store a pointer + to a register window. + +- Use temporaries. Use local temporaries only when really needed, + e.g. when you need to use a value after a jump. Local temporaries + introduce a performance hit in the current TCG implementation: their + content is saved to memory at end of each basic block. + +- Free temporaries and local temporaries when they are no longer used + (tcg_temp_free). Since tcg_const_x() also creates a temporary, you + should free it after it is used. Freeing temporaries does not yield + a better generated code, but it reduces the memory usage of TCG and + the speed of the translation. + +- Don't hesitate to use helpers for complicated or seldom used guest + instructions. There is little performance advantage in using TCG to + implement guest instructions taking more than about twenty TCG + instructions. Note that this rule of thumb is more applicable to + helpers doing complex logic or arithmetic, where the C compiler has + scope to do a good job of optimisation; it is less relevant where + the instruction is mostly doing loads and stores, and in those cases + inline TCG may still be faster for longer sequences. + +- The hard limit on the number of TCG instructions you can generate + per guest instruction is set by ``MAX_OP_PER_INSTR`` in ``exec-all.h`` -- + you cannot exceed this without risking a buffer overrun. + +- Use the 'discard' instruction if you know that TCG won't be able to + prove that a given global is "dead" at a given program point. The + x86 guest uses it to improve the condition codes optimisation. diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index a7cc44aa20f8..9740a7040643 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/empty.c + +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= -- tests/plugins + Only instrument instructions matching the string prefix. Will show + some basic stats including how many instructions have executed since + the last execution. For example:: -These are some basic plugins that are used to test and exercise the -API during the ``make check-tcg`` target. + $ 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/tcg.rst b/docs/devel/tcg.rst index a65fb7b1c442..136a7a0d9628 100644 --- a/docs/devel/tcg.rst +++ b/docs/devel/tcg.rst @@ -9,7 +9,7 @@ which make it relatively easily portable and simple while achieving good performances. QEMU's dynamic translation backend is called TCG, for "Tiny Code -Generator". For more information, please take a look at ``tcg/README``. +Generator". For more information, please take a look at :ref:`tcg-ops-ref`. The following sections outline some notable features and implementation details of QEMU's dynamic translator. diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 92d40cdd19bf..e10c47b5a7ca 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -1,3 +1,5 @@ +.. _testing: + Testing in QEMU =============== @@ -79,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 command 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 ~~~~~~~~~~~~~~~~~ @@ -295,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. @@ -373,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 ~~~~~~ @@ -637,6 +669,44 @@ The full set of annotations can be found here: https://github.com/llvm/llvm-project/blob/master/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp +docker-binfmt-image-debian-% targets +------------------------------------ + +It is possible to combine Debian's bootstrap scripts with a configured +``binfmt_misc`` to bootstrap a number of Debian's distros including +experimental ports not yet supported by a released OS. This can +simplify setting up a rootfs by using docker to contain the foreign +rootfs rather than manually invoking chroot. + +Setting up ``binfmt_misc`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the script ``qemu-binfmt-conf.sh`` to configure a QEMU +user binary to automatically run binaries for the foreign +architecture. While the scripts will try their best to work with +dynamically linked QEMU's a statically linked one will present less +potential complications when copying into the docker image. Modern +kernels support the ``F`` (fix binary) flag which will open the QEMU +executable on setup and avoids the need to find and re-open in the +chroot environment. This is triggered with the ``--persistent`` flag. + +Example invocation +~~~~~~~~~~~~~~~~~~ + +For example to setup the HPPA ports builds of Debian:: + + make docker-binfmt-image-debian-sid-hppa \ + DEB_TYPE=sid DEB_ARCH=hppa \ + DEB_URL=http://ftp.ports.debian.org/debian-ports/ \ + DEB_KEYRING=/usr/share/keyrings/debian-ports-archive-keyring.gpg \ + EXECUTABLE=(pwd)/qemu-hppa V=1 + +The ``DEB_`` variables are substitutions used by +``debian-boostrap.pre`` which is called to do the initial debootstrap +of the rootfs before it is copied into the container. The second stage +is run as part of the build. The final image will be tagged as +``qemu/debian-sid-hppa``. + VM testing ---------- diff --git a/docs/devel/tracing.rst b/docs/devel/tracing.rst index ec9a687cfdc9..d288480db11f 100644 --- a/docs/devel/tracing.rst +++ b/docs/devel/tracing.rst @@ -48,7 +48,7 @@ file. During build, the "trace-events" file in each listed subdirectory will be processed by the "tracetool" script to generate code for the trace events. The individual "trace-events" files are merged into a "trace-events-all" file, -which is also installed into "/usr/share/qemu" with the name "trace-events". +which is also installed into "/usr/share/qemu". This merged file is to be used by the "simpletrace.py" script to later analyse traces in the simpletrace data format. diff --git a/docs/devel/virtio-backends.rst b/docs/devel/virtio-backends.rst new file mode 100644 index 000000000000..9ff092e7a048 --- /dev/null +++ b/docs/devel/virtio-backends.rst @@ -0,0 +1,214 @@ +.. + Copyright (c) 2022, Linaro Limited + Written by Alex Bennée + +Writing VirtIO backends for QEMU +================================ + +This document attempts to outline the information a developer needs to +know to write device emulations in QEMU. It is specifically focused on +implementing VirtIO devices. For VirtIO the frontend is the driver +running on the guest. The backend is the everything that QEMU needs to +do to handle the emulation of the VirtIO device. This can be done +entirely in QEMU, divided between QEMU and the kernel (vhost) or +handled by a separate process which is configured by QEMU +(vhost-user). + +VirtIO Transports +----------------- + +VirtIO supports a number of different transports. While the details of +the configuration and operation of the device will generally be the +same QEMU represents them as different devices depending on the +transport they use. For example -device virtio-foo represents the foo +device using mmio and -device virtio-foo-pci is the same class of +device using the PCI transport. + +Using the QEMU Object Model (QOM) +--------------------------------- + +Generally all devices in QEMU are super classes of ``TYPE_DEVICE`` +however VirtIO devices should be based on ``TYPE_VIRTIO_DEVICE`` which +itself is derived from the base class. For example: + +.. code:: c + + static const TypeInfo virtio_blk_info = { + .name = TYPE_VIRTIO_BLK, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOBlock), + .instance_init = virtio_blk_instance_init, + .class_init = virtio_blk_class_init, + }; + +The author may decide to have a more expansive class hierarchy to +support multiple device types. For example the Virtio GPU device: + +.. code:: c + + static const TypeInfo virtio_gpu_base_info = { + .name = TYPE_VIRTIO_GPU_BASE, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOGPUBase), + .class_size = sizeof(VirtIOGPUBaseClass), + .class_init = virtio_gpu_base_class_init, + .abstract = true + }; + + static const TypeInfo vhost_user_gpu_info = { + .name = TYPE_VHOST_USER_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VhostUserGPU), + .instance_init = vhost_user_gpu_instance_init, + .instance_finalize = vhost_user_gpu_instance_finalize, + .class_init = vhost_user_gpu_class_init, + }; + + static const TypeInfo virtio_gpu_info = { + .name = TYPE_VIRTIO_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VirtIOGPU), + .class_size = sizeof(VirtIOGPUClass), + .class_init = virtio_gpu_class_init, + }; + +defines a base class for the VirtIO GPU and then specialises two +versions, one for the internal implementation and the other for the +vhost-user version. + +VirtIOPCIProxy +^^^^^^^^^^^^^^ + +[AJB: the following is supposition and welcomes more informed +opinions] + +Probably due to legacy from the pre-QOM days PCI VirtIO devices don't +follow the normal hierarchy. Instead the a standalone object is based +on the VirtIOPCIProxy class and the specific VirtIO instance is +manually instantiated: + +.. code:: c + + /* + * virtio-blk-pci: This extends VirtioPCIProxy. + */ + #define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" + DECLARE_INSTANCE_CHECKER(VirtIOBlkPCI, VIRTIO_BLK_PCI, + TYPE_VIRTIO_BLK_PCI) + + struct VirtIOBlkPCI { + VirtIOPCIProxy parent_obj; + VirtIOBlock vdev; + }; + + static Property virtio_blk_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), + }; + + static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + { + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + ... + + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); + } + + static void virtio_blk_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); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + device_class_set_props(dc, virtio_blk_pci_properties); + k->realize = virtio_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; + } + + static void virtio_blk_pci_instance_init(Object *obj) + { + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex"); + } + + static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { + .base_name = TYPE_VIRTIO_BLK_PCI, + .generic_name = "virtio-blk-pci", + .transitional_name = "virtio-blk-pci-transitional", + .non_transitional_name = "virtio-blk-pci-non-transitional", + .instance_size = sizeof(VirtIOBlkPCI), + .instance_init = virtio_blk_pci_instance_init, + .class_init = virtio_blk_pci_class_init, + }; + +Here you can see the instance_init has to manually instantiate the +underlying ``TYPE_VIRTIO_BLOCK`` object and link an alias for one of +it's properties to the PCI device. + + +Back End Implementations +------------------------ + +There are a number of places where the implementation of the backend +can be done: + +* in QEMU itself +* in the host kernel (a.k.a vhost) +* in a separate process (a.k.a. vhost-user) + +vhost_ops vs TYPE_VHOST_USER_BACKEND +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are two choices to how to implement vhost code. Most of the code +which has to work with either vhost or vhost-user uses +``vhost_dev_init()`` to instantiate the appropriate backend. This +means including a ``struct vhost_dev`` in the main object structure. + +For vhost-user devices you also need to add code to track the +initialisation of the ``chardev`` device used for the control socket +between QEMU and the external vhost-user process. + +If you only need to implement a vhost-user backed the other option is +a use a QOM-ified version of vhost-user. + +.. code:: c + + static void + vhost_user_gpu_instance_init(Object *obj) + { + VhostUserGPU *g = VHOST_USER_GPU(obj); + + g->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND)); + object_property_add_alias(obj, "chardev", + OBJECT(g->vhost), "chardev"); + } + + static const TypeInfo vhost_user_gpu_info = { + .name = TYPE_VHOST_USER_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VhostUserGPU), + .instance_init = vhost_user_gpu_instance_init, + .instance_finalize = vhost_user_gpu_instance_finalize, + .class_init = vhost_user_gpu_class_init, + }; + +Using it this way entails adding a ``struct VhostUserBackend`` to your +core object structure and manually instantiating the backend. This +sub-structure tracks both the ``vhost_dev`` and ``CharDev`` types +needed for the connection. Instead of calling ``vhost_dev_init`` you +would call ``vhost_user_backend_dev_init`` which does what is needed +on your behalf. diff --git a/docs/devel/writing-monitor-commands.rst b/docs/devel/writing-monitor-commands.rst index 1693822f8f93..2c11e7166519 100644 --- a/docs/devel/writing-monitor-commands.rst +++ b/docs/devel/writing-monitor-commands.rst @@ -166,9 +166,9 @@ and user defined types. Now, let's update our C implementation in monitor/qmp-cmds.c:: - void qmp_hello_world(bool has_message, const char *message, Error **errp) + void qmp_hello_world(const char *message, Error **errp) { - if (has_message) { + if (message) { printf("%s\n", message); } else { printf("Hello, world\n"); @@ -210,9 +210,9 @@ file. Basically, most errors are set by calling the error_setg() function. Let's say we don't accept the string "message" to contain the word "love". If it does contain it, we want the "hello-world" command to return an error:: - void qmp_hello_world(bool has_message, const char *message, Error **errp) + void qmp_hello_world(const char *message, Error **errp) { - if (has_message) { + if (message) { if (strstr(message, "love")) { error_setg(errp, "the word 'love' is not allowed"); return; @@ -331,13 +331,10 @@ we should add it to the hmp-commands.hx file:: .cmd = hmp_hello_world, }, -:: - - STEXI - @item hello_world @var{message} - @findex hello_world - Print message to the standard output - ETEXI + SRST + ``hello_world`` *message* + Print message to the standard output + ERST To test this you have to open a user monitor and issue the "hello-world" command. It might be instructive to check the command's documentation with @@ -470,9 +467,9 @@ There are a number of things to be noticed: allocated by the regular g_malloc0() function. Note that we chose to initialize the memory to zero. This is recommended for all QAPI types, as it helps avoiding bad surprises (specially with booleans) -4. Remember that "next_deadline" is optional? All optional members have a - 'has_TYPE_NAME' member that should be properly set by the implementation, - as shown above +4. Remember that "next_deadline" is optional? Non-pointer optional + members have a 'has_TYPE_NAME' member that should be properly set + by the implementation, as shown above 5. Even static strings, such as "alarm_timer->name", should be dynamically allocated by the implementation. This is so because the QAPI also generates a function to free its types and it cannot distinguish between dynamically @@ -719,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/hyperv.txt b/docs/hyperv.txt deleted file mode 100644 index 0417c183a3b0..000000000000 --- a/docs/hyperv.txt +++ /dev/null @@ -1,255 +0,0 @@ -Hyper-V Enlightenments -====================== - - -1. Description -=============== -In some cases when implementing a hardware interface in software is slow, KVM -implements its own paravirtualized interfaces. This works well for Linux as -guest support for such features is added simultaneously with the feature itself. -It may, however, be hard-to-impossible to add support for these interfaces to -proprietary OSes, namely, Microsoft Windows. - -KVM on x86 implements Hyper-V Enlightenments for Windows guests. These features -make Windows and Hyper-V guests think they're running on top of a Hyper-V -compatible hypervisor and use Hyper-V specific features. - - -2. Setup -========= -No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In -QEMU, individual enlightenments can be enabled through CPU flags, e.g: - - qemu-system-x86_64 --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ... - -Sometimes there are dependencies between enlightenments, QEMU is supposed to -check that the supplied configuration is sane. - -When any set of the Hyper-V enlightenments is enabled, QEMU changes hypervisor -identification (CPUID 0x40000000..0x4000000A) to Hyper-V. KVM identification -and features are kept in leaves 0x40000100..0x40000101. - - -3. Existing enlightenments -=========================== - -3.1. hv-relaxed -================ -This feature tells guest OS to disable watchdog timeouts as it is running on a -hypervisor. It is known that some Windows versions will do this even when they -see 'hypervisor' CPU flag. - -3.2. hv-vapic -============== -Provides so-called VP Assist page MSR to guest allowing it to work with APIC -more efficiently. In particular, this enlightenment allows paravirtualized -(exit-less) EOI processing. - -3.3. hv-spinlocks=xxx -====================== -Enables paravirtualized spinlocks. The parameter indicates how many times -spinlock acquisition should be attempted before indicating the situation to the -hypervisor. A special value 0xffffffff indicates "never notify". - -3.4. hv-vpindex -================ -Provides HV_X64_MSR_VP_INDEX (0x40000002) MSR to the guest which has Virtual -processor index information. This enlightenment makes sense in conjunction with -hv-synic, hv-stimer and other enlightenments which require the guest to know its -Virtual Processor indices (e.g. when VP index needs to be passed in a -hypercall). - -3.5. hv-runtime -================ -Provides HV_X64_MSR_VP_RUNTIME (0x40000010) MSR to the guest. The MSR keeps the -virtual processor run time in 100ns units. This gives guest operating system an -idea of how much time was 'stolen' from it (when the virtual CPU was preempted -to perform some other work). - -3.6. hv-crash -============== -Provides HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 (0x40000100..0x40000105) and -HV_X64_MSR_CRASH_CTL (0x40000105) MSRs to the guest. These MSRs are written to -by the guest when it crashes, HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 MSRs -contain additional crash information. This information is outputted in QEMU log -and through QAPI. -Note: unlike under genuine Hyper-V, write to HV_X64_MSR_CRASH_CTL causes guest -to shutdown. This effectively blocks crash dump generation by Windows. - -3.7. hv-time -============= -Enables two Hyper-V-specific clocksources available to the guest: MSR-based -Hyper-V clocksource (HV_X64_MSR_TIME_REF_COUNT, 0x40000020) and Reference TSC -page (enabled via MSR HV_X64_MSR_REFERENCE_TSC, 0x40000021). Both clocksources -are per-guest, Reference TSC page clocksource allows for exit-less time stamp -readings. Using this enlightenment leads to significant speedup of all timestamp -related operations. - -3.8. hv-synic -============== -Enables Hyper-V Synthetic interrupt controller - an extension of a local APIC. -When enabled, this enlightenment provides additional communication facilities -to the guest: SynIC messages and Events. This is a pre-requisite for -implementing VMBus devices (not yet in QEMU). Additionally, this enlightenment -is needed to enable Hyper-V synthetic timers. SynIC is controlled through MSRs -HV_X64_MSR_SCONTROL..HV_X64_MSR_EOM (0x40000080..0x40000084) and -HV_X64_MSR_SINT0..HV_X64_MSR_SINT15 (0x40000090..0x4000009F) - -Requires: hv-vpindex - -3.9. hv-stimer -=============== -Enables Hyper-V synthetic timers. There are four synthetic timers per virtual -CPU controlled through HV_X64_MSR_STIMER0_CONFIG..HV_X64_MSR_STIMER3_COUNT -(0x400000B0..0x400000B7) MSRs. These timers can work either in single-shot or -periodic mode. It is known that certain Windows versions revert to using HPET -(or even RTC when HPET is unavailable) extensively when this enlightenment is -not provided; this can lead to significant CPU consumption, even when virtual -CPU is idle. - -Requires: hv-vpindex, hv-synic, hv-time - -3.10. hv-tlbflush -================== -Enables paravirtualized TLB shoot-down mechanism. On x86 architecture, remote -TLB flush procedure requires sending IPIs and waiting for other CPUs to perform -local TLB flush. In virtualized environment some virtual CPUs may not even be -scheduled at the time of the call and may not require flushing (or, flushing -may be postponed until the virtual CPU is scheduled). hv-tlbflush enlightenment -implements TLB shoot-down through hypervisor enabling the optimization. - -Requires: hv-vpindex - -3.11. hv-ipi -============= -Enables paravirtualized IPI send mechanism. HvCallSendSyntheticClusterIpi -hypercall may target more than 64 virtual CPUs simultaneously, doing the same -through APIC requires more than one access (and thus exit to the hypervisor). - -Requires: hv-vpindex - -3.12. hv-vendor-id=xxx -======================= -This changes Hyper-V identification in CPUID 0x40000000.EBX-EDX from the default -"Microsoft Hv". The parameter should be no longer than 12 characters. According -to the specification, guests shouldn't use this information and it is unknown -if there is a Windows version which acts differently. -Note: hv-vendor-id is not an enlightenment and thus doesn't enable Hyper-V -identification when specified without some other enlightenment. - -3.13. hv-reset -=============== -Provides HV_X64_MSR_RESET (0x40000003) MSR to the guest allowing it to reset -itself by writing to it. Even when this MSR is enabled, it is not a recommended -way for Windows to perform system reboot and thus it may not be used. - -3.14. hv-frequencies -============================================ -Provides HV_X64_MSR_TSC_FREQUENCY (0x40000022) and HV_X64_MSR_APIC_FREQUENCY -(0x40000023) allowing the guest to get its TSC/APIC frequencies without doing -measurements. - -3.15 hv-reenlightenment -======================== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106), -HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)and HV_X64_MSR_TSC_EMULATION_STATUS -(0x40000108) MSRs allowing the guest to get notified when TSC frequency changes -(only happens on migration) and keep using old frequency (through emulation in -the hypervisor) until it is ready to switch to the new one. This, in conjunction -with hv-frequencies, allows Hyper-V on KVM to pass stable clocksource (Reference -TSC page) to its own guests. - -Note, KVM doesn't fully support re-enlightenment notifications and doesn't -emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to -be specified to make migration succeed. The destination host has to either have -the same TSC frequency or support TSC scaling CPU feature. - -Recommended: hv-frequencies - -3.16. hv-evmcs -=============== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature -implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) -hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. -Note: some virtualization features (e.g. Posted Interrupts) are disabled when -hv-evmcs is enabled. It may make sense to measure your nested workload with and -without the feature to find out if enabling it is beneficial. - -Requires: hv-vapic - -3.17. hv-stimer-direct -======================= -Hyper-V specification allows synthetic timer operation in two modes: "classic", -when expiration event is delivered as SynIC message and "direct", when the event -is delivered via normal interrupt. It is known that nested Hyper-V can only -use synthetic timers in direct mode and thus 'hv-stimer-direct' needs to be -enabled. - -Requires: hv-vpindex, hv-synic, hv-time, hv-stimer - -3.18. hv-avic (hv-apicv) -======================= -The enlightenment allows to use Hyper-V SynIC with hardware APICv/AVIC enabled. -Normally, Hyper-V SynIC disables these hardware feature and suggests the guest -to use paravirtualized AutoEOI feature. -Note: enabling this feature on old hardware (without APICv/AVIC support) may -have negative effect on guest's performance. - -3.19. hv-no-nonarch-coresharing=on/off/auto -=========================================== -This enlightenment tells guest OS that virtual processors will never share a -physical core unless they are reported as sibling SMT threads. This information -is required by Windows and Hyper-V guests to properly mitigate SMT related CPU -vulnerabilities. -When the option is set to 'auto' QEMU will enable the feature only when KVM -reports that non-architectural coresharing is impossible, this means that -hyper-threading is not supported or completely disabled on the host. This -setting also prevents migration as SMT settings on the destination may differ. -When the option is set to 'on' QEMU will always enable the feature, regardless -of host setup. To keep guests secure, this can only be used in conjunction with -exposing correct vCPU topology and vCPU pinning. - -3.20. hv-version-id-{build,major,minor,spack,sbranch,snumber} -============================================================= -This changes Hyper-V version identification in CPUID 0x40000002.EAX-EDX from the -default (WS2016). -- hv-version-id-build sets 'Build Number' (32 bits) -- hv-version-id-major sets 'Major Version' (16 bits) -- hv-version-id-minor sets 'Minor Version' (16 bits) -- hv-version-id-spack sets 'Service Pack' (32 bits) -- hv-version-id-sbranch sets 'Service Branch' (8 bits) -- hv-version-id-snumber sets 'Service Number' (24 bits) - -Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V -identification when specified without any other enlightenments. - -4. Supplementary features -========================= - -4.1. hv-passthrough -=================== -In some cases (e.g. during development) it may make sense to use QEMU in -'pass-through' mode and give Windows guests all enlightenments currently -supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU -flag. -Note: "hv-passthrough" flag only enables enlightenments which are known to QEMU -(have corresponding "hv-*" flag) and copies "hv-spinlocks="/"hv-vendor-id=" -values from KVM to QEMU. "hv-passthrough" overrides all other "hv-*" settings on -the command line. Also, enabling this flag effectively prevents migration as the -list of enabled enlightenments may differ between target and destination hosts. - -4.2. hv-enforce-cpuid -===================== -By default, KVM allows the guest to use all currently supported Hyper-V -enlightenments when Hyper-V CPUID interface was exposed, regardless of if -some features were not announced in guest visible CPUIDs. 'hv-enforce-cpuid' -feature alters this behavior and only allows the guest to use exposed Hyper-V -enlightenments. - - -5. Useful links -================ -Hyper-V Top Level Functional specification and other information: -https://github.com/MicrosoftDocs/Virtualization-Documentation diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json index 4e049b1c7ca0..56814f02b3c0 100644 --- a/docs/interop/firmware.json +++ b/docs/interop/firmware.json @@ -113,13 +113,22 @@ # Virtualization, as specified in the AMD64 Architecture # Programmer's Manual. QEMU command line options related to # this feature are documented in -# "docs/amd-memory-encryption.txt". +# "docs/system/i386/amd-memory-encryption.rst". # # @amd-sev-es: The firmware supports running under AMD Secure Encrypted # Virtualization - Encrypted State, as specified in the AMD64 # Architecture Programmer's Manual. QEMU command line options # related to this feature are documented in -# "docs/amd-memory-encryption.txt". +# "docs/system/i386/amd-memory-encryption.rst". +# +# @amd-sev-snp: The firmware supports running under AMD Secure Encrypted +# Virtualization - Secure Nested Paging, as specified in the +# AMD64 Architecture Programmer's Manual. QEMU command line +# options related to this feature are documented in +# "docs/system/i386/amd-memory-encryption.rst". +# +# @intel-tdx: The firmware supports running under Intel Trust Domain +# Extensions (TDX). # # @enrolled-keys: The variable store (NVRAM) template associated with # the firmware binary has the UEFI Secure Boot @@ -185,9 +194,11 @@ # Since: 3.0 ## { 'enum' : 'FirmwareFeature', - 'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'enrolled-keys', - 'requires-smm', 'secure-boot', 'verbose-dynamic', - 'verbose-static' ] } + 'data' : [ 'acpi-s3', 'acpi-s4', + 'amd-sev', 'amd-sev-es', 'amd-sev-snp', + 'intel-tdx', + 'enrolled-keys', 'requires-smm', 'secure-boot', + 'verbose-dynamic', 'verbose-static' ] } ## # @FirmwareFlashFile: diff --git a/docs/interop/index.rst b/docs/interop/index.rst index b7632acb7ba3..6351ff9ba6e6 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -23,3 +23,4 @@ are useful for making QEMU interoperate with other software. vhost-user-gpu vhost-vdpa virtio-balloon-stats + vnc-ledstate-pseudo-encoding diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst index 39e62c991514..135784ab3371 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/nbd.txt b/docs/interop/nbd.txt index bdb0f2a41aca..f5ca25174a65 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -68,3 +68,4 @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE * 4.2: NBD_FLAG_CAN_MULTI_CONN for shareable read-only exports, NBD_CMD_FLAG_FAST_ZERO * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" +* 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst index 3063357bb5d6..a9183802d107 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/interop/vhost-user-gpu.rst b/docs/interop/vhost-user-gpu.rst index 71a2c52b3135..164055372985 100644 --- a/docs/interop/vhost-user-gpu.rst +++ b/docs/interop/vhost-user-gpu.rst @@ -13,10 +13,10 @@ Introduction ============ The vhost-user-gpu protocol is aiming at sharing the rendering result -of a virtio-gpu, done from a vhost-user slave process to a vhost-user -master process (such as QEMU). It bears a resemblance to a display +of a virtio-gpu, done from a vhost-user back-end process to a vhost-user +front-end process (such as QEMU). It bears a resemblance to a display server protocol, if you consider QEMU as the display server and the -slave as the client, but in a very limited way. Typically, it will +back-end as the client, but in a very limited way. Typically, it will work by setting a scanout/display configuration, before sending flush events for the display updates. It will also update the cursor shape and position. @@ -26,8 +26,8 @@ socket ancillary data to share opened file descriptors (DMABUF fds or shared memory). The socket is usually obtained via ``VHOST_USER_GPU_SET_SOCKET``. -Requests are sent by the *slave*, and the optional replies by the -*master*. +Requests are sent by the *back-end*, and the optional replies by the +*front-end*. Wire format =========== diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 4dbc84fd001e..3f18ab424eb0 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -23,19 +23,19 @@ space process on the same host. It uses communication over a Unix domain socket to share file descriptors in the ancillary data of the message. -The protocol defines 2 sides of the communication, *master* and -*slave*. *Master* is the application that shares its virtqueues, in -our case QEMU. *Slave* is the consumer of the virtqueues. +The protocol defines 2 sides of the communication, *front-end* and +*back-end*. The *front-end* is the application that shares its virtqueues, in +our case QEMU. The *back-end* is the consumer of the virtqueues. -In the current implementation QEMU is the *master*, and the *slave* is -the external process consuming the virtio queues, for example a +In the current implementation QEMU is the *front-end*, and the *back-end* +is the external process consuming the virtio queues, for example a software Ethernet switch running in user space, such as Snabbswitch, -or a block device backend processing read & write to a virtual -disk. In order to facilitate interoperability between various backend +or a block device back-end processing read & write to a virtual +disk. In order to facilitate interoperability between various back-end implementations, it is recommended to follow the :ref:`Backend program conventions `. -*Master* and *slave* can be either a client (i.e. connecting) or +The *front-end* and *back-end* can be either a client (i.e. connecting) or server (listening) in the socket communication. Support for platforms other than Linux @@ -77,7 +77,7 @@ Header :flags: 32-bit bit field - Lower 2 bits are the version (currently 0x01) -- Bit 2 is the reply flag - needs to be sent on each reply from the slave +- Bit 2 is the reply flag - needs to be sent on each reply from the back-end - Bit 3 is the need_reply flag - see :ref:`REPLY_ACK ` for details. @@ -222,8 +222,8 @@ Virtio device config space :size: a 32-bit configuration space access size in bytes :flags: a 32-bit value: - - 0: Vhost master messages used for writeable fields - - 1: Vhost master messages used for live migration + - 0: Vhost front-end messages used for writable fields + - 1: Vhost front-end messages used for live migration :payload: Size bytes array holding the contents of the virtio device's configuration space @@ -290,8 +290,8 @@ vhost for the Linux Kernel. Most messages that can be sent via the Unix domain socket implementing vhost-user have an equivalent ioctl to the kernel implementation. -The communication consists of *master* sending message requests and -*slave* sending message replies. Most of the requests don't require +The communication consists of the *front-end* sending message requests and +the *back-end* sending message replies. Most of the requests don't require replies. Here is a list of the ones that do: * ``VHOST_USER_GET_FEATURES`` @@ -305,9 +305,10 @@ replies. Here is a list of the ones that do: :ref:`REPLY_ACK ` The section on ``REPLY_ACK`` protocol extension. -There are several messages that the master sends with file descriptors passed +There are several messages that the front-end sends with file descriptors passed in the ancillary data: +* ``VHOST_USER_ADD_MEM_REG`` * ``VHOST_USER_SET_MEM_TABLE`` * ``VHOST_USER_SET_LOG_BASE`` (if ``VHOST_USER_PROTOCOL_F_LOG_SHMFD``) * ``VHOST_USER_SET_LOG_FD`` @@ -317,100 +318,108 @@ in the ancillary data: * ``VHOST_USER_SET_SLAVE_REQ_FD`` * ``VHOST_USER_SET_INFLIGHT_FD`` (if ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD``) -If *master* is unable to send the full message or receives a wrong +If *front-end* is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented. -If *slave* detects some error such as incompatible features, it may also +If *back-end* detects some error such as incompatible features, it may also close the connection. This should only happen in exceptional circumstances. Any protocol extensions are gated by protocol feature bits, which -allows full backwards compatibility on both master and slave. As -older slaves don't support negotiating protocol features, a feature +allows full backwards compatibility on both front-end and back-end. As +older back-ends don't support negotiating protocol features, a feature bit was dedicated for this purpose:: #define VHOST_USER_F_PROTOCOL_FEATURES 30 -Starting and stopping rings ---------------------------- +Note that VHOST_USER_F_PROTOCOL_FEATURES is the UNUSED (30) feature +bit defined in `VIRTIO 1.1 6.3 Legacy Interface: Reserved Feature Bits +`_. +VIRTIO devices do not advertise this feature bit and therefore VIRTIO +drivers cannot negotiate it. -Client must only process each ring when it is started. +This reserved feature bit was reused by the vhost-user protocol to add +vhost-user protocol feature negotiation in a backwards compatible +fashion. Old vhost-user front-end and back-end implementations continue to +work even though they are not aware of vhost-user protocol feature +negotiation. -Client must only pass data between the ring and the backend, when the -ring is enabled. +Ring states +----------- -If ring is started but disabled, client must process the ring without -talking to the backend. +Rings can be in one of three states: -For example, for a networking device, in the disabled state client -must not supply any new RX packets, but must process and discard any -TX packets. +* stopped: the back-end must not process the ring at all. -If ``VHOST_USER_F_PROTOCOL_FEATURES`` has not been negotiated, the -ring is initialized in an enabled state. +* started but disabled: the back-end must process the ring without + causing any side effects. For example, for a networking device, + in the disabled state the back-end must not supply any new RX packets, + but must process and discard any TX packets. -If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is -initialized in a disabled state. Client must not pass data to/from the -backend until ring is enabled by ``VHOST_USER_SET_VRING_ENABLE`` with -parameter 1, or after it has been disabled by -``VHOST_USER_SET_VRING_ENABLE`` with parameter 0. +* started and enabled. + +Each ring is initialized in a stopped state. The back-end must start +ring upon receiving a kick (that is, detecting that file descriptor is +readable) on the descriptor specified by ``VHOST_USER_SET_VRING_KICK`` +or receiving the in-band message ``VHOST_USER_VRING_KICK`` if negotiated, +and stop ring upon receiving ``VHOST_USER_GET_VRING_BASE``. -Each ring is initialized in a stopped state, client must not process -it until ring is started, or after it has been stopped. +Rings can be enabled or disabled by ``VHOST_USER_SET_VRING_ENABLE``. -Client must start ring upon receiving a kick (that is, detecting that -file descriptor is readable) on the descriptor specified by -``VHOST_USER_SET_VRING_KICK`` or receiving the in-band message -``VHOST_USER_VRING_KICK`` if negotiated, and stop ring upon receiving -``VHOST_USER_GET_VRING_BASE``. +If ``VHOST_USER_F_PROTOCOL_FEATURES`` has not been negotiated, the +ring starts directly in the enabled state. + +If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is +initialized in a disabled state and is enabled by +``VHOST_USER_SET_VRING_ENABLE`` with parameter 1. -While processing the rings (whether they are enabled or not), client +While processing the rings (whether they are enabled or not), the back-end must support changing some configuration aspects on the fly. Multiple queue support ---------------------- -Many devices have a fixed number of virtqueues. In this case the master +Many devices have a fixed number of virtqueues. In this case the front-end already knows the number of available virtqueues without communicating with the -slave. +back-end. Some devices do not have a fixed number of virtqueues. Instead the maximum -number of virtqueues is chosen by the slave. The number can depend on host -resource availability or slave implementation details. Such devices are called +number of virtqueues is chosen by the back-end. The number can depend on host +resource availability or back-end implementation details. Such devices are called multiple queue devices. -Multiple queue support allows the slave to advertise the maximum number of -queues. This is treated as a protocol extension, hence the slave has to +Multiple queue support allows the back-end to advertise the maximum number of +queues. This is treated as a protocol extension, hence the back-end has to implement protocol features first. The multiple queues feature is supported only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ`` (bit 0) is set. -The max number of queues the slave supports can be queried with message -``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the number of requested +The max number of queues the back-end supports can be queried with message +``VHOST_USER_GET_QUEUE_NUM``. Front-end should stop when the number of requested queues is bigger than that. -As all queues share one connection, the master uses a unique index for each +As all queues share one connection, the front-end uses a unique index for each queue in the sent message to identify a specified queue. -The master enables queues by sending message ``VHOST_USER_SET_VRING_ENABLE``. +The front-end enables queues by sending message ``VHOST_USER_SET_VRING_ENABLE``. vhost-user-net has historically automatically enabled the first queue pair. -Slaves should always implement the ``VHOST_USER_PROTOCOL_F_MQ`` protocol +Back-ends should always implement the ``VHOST_USER_PROTOCOL_F_MQ`` protocol feature, even for devices with a fixed number of virtqueues, since it is simple to implement and offers a degree of introspection. -Masters must not rely on the ``VHOST_USER_PROTOCOL_F_MQ`` protocol feature for +Front-ends must not rely on the ``VHOST_USER_PROTOCOL_F_MQ`` protocol feature for devices with a fixed number of virtqueues. Only true multiqueue devices require this protocol feature. Migration --------- -During live migration, the master may need to track the modifications -the slave makes to the memory mapped regions. The client should mark +During live migration, the front-end may need to track the modifications +the back-end makes to the memory mapped regions. The front-end should mark the dirty pages in a log. Once it complies to this logging, it may declare the ``VHOST_F_LOG_ALL`` vhost feature. -To start/stop logging of data/used ring writes, server may send +To start/stop logging of data/used ring writes, the front-end may send messages ``VHOST_USER_SET_FEATURES`` with ``VHOST_F_LOG_ALL`` and ``VHOST_USER_SET_VRING_ADDR`` with ``VHOST_VRING_F_LOG`` in ring's flags set to 1/0, respectively. @@ -424,7 +433,7 @@ Dirty pages are of size:: #define VHOST_LOG_PAGE 0x1000 The log memory fd is provided in the ancillary data of -``VHOST_USER_SET_LOG_BASE`` message when the slave has +``VHOST_USER_SET_LOG_BASE`` message when the back-end has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature. The size of the log is supplied as part of ``VhostUserMsg`` which @@ -450,26 +459,26 @@ the bit offset of the last byte of the ring must fall within the size supplied by ``VhostUserLog``. ``VHOST_USER_SET_LOG_FD`` is an optional message with an eventfd in -ancillary data, it may be used to inform the master that the log has +ancillary data, it may be used to inform the front-end that the log has been modified. Once the source has finished migration, rings will be stopped by the source. No further update must be done before rings are restarted. -In postcopy migration the slave is started before all the memory has +In postcopy migration the back-end is started before all the memory has been received from the source host, and care must be taken to avoid -accessing pages that have yet to be received. The slave opens a +accessing pages that have yet to be received. The back-end opens a 'userfault'-fd and registers the memory with it; this fd is then -passed back over to the master. The master services requests on the +passed back over to the front-end. The front-end services requests on the userfaultfd for pages that are accessed and when the page is available it performs WAKE ioctl's on the userfaultfd to wake the stalled -slave. The client indicates support for this via the +back-end. The front-end indicates support for this via the ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` feature. Memory access ------------- -The master sends a list of vhost memory regions to the slave using the +The front-end sends a list of vhost memory regions to the back-end using the ``VHOST_USER_SET_MEM_TABLE`` message. Each region has two base addresses: a guest address and a user address. @@ -494,60 +503,60 @@ IOMMU support ------------- When the ``VIRTIO_F_IOMMU_PLATFORM`` feature has been negotiated, the -master sends IOTLB entries update & invalidation by sending -``VHOST_USER_IOTLB_MSG`` requests to the slave with a ``struct +front-end sends IOTLB entries update & invalidation by sending +``VHOST_USER_IOTLB_MSG`` requests to the back-end with a ``struct vhost_iotlb_msg`` as payload. For update events, the ``iotlb`` payload has to be filled with the update message type (2), the I/O virtual address, the size, the user virtual address, and the permissions flags. Addresses and size must be within vhost memory regions set via the ``VHOST_USER_SET_MEM_TABLE`` request. For invalidation events, the ``iotlb`` payload has to be filled with the invalidation message type -(3), the I/O virtual address and the size. On success, the slave is +(3), the I/O virtual address and the size. On success, the back-end is expected to reply with a zero payload, non-zero otherwise. -The slave relies on the slave communication channel (see :ref:`Slave -communication ` section below) to send IOTLB miss +The back-end relies on the back-end communication channel (see :ref:`Back-end +communication ` section below) to send IOTLB miss and access failure events, by sending ``VHOST_USER_SLAVE_IOTLB_MSG`` -requests to the master with a ``struct vhost_iotlb_msg`` as +requests to the front-end with a ``struct vhost_iotlb_msg`` as payload. For miss events, the iotlb payload has to be filled with the miss message type (1), the I/O virtual address and the permissions flags. For access failure event, the iotlb payload has to be filled with the access failure message type (4), the I/O virtual address and -the permissions flags. For synchronization purpose, the slave may -rely on the reply-ack feature, so the master may send a reply when +the permissions flags. For synchronization purpose, the back-end may +rely on the reply-ack feature, so the front-end may send a reply when operation is completed if the reply-ack feature is negotiated and -slaves requests a reply. For miss events, completed operation means -either master sent an update message containing the IOTLB entry -containing requested address and permission, or master sent nothing if +back-ends requests a reply. For miss events, completed operation means +either front-end sent an update message containing the IOTLB entry +containing requested address and permission, or front-end sent nothing if the IOTLB miss message is invalid (invalid IOVA or permission). -The master isn't expected to take the initiative to send IOTLB update -messages, as the slave sends IOTLB miss messages for the guest virtual +The front-end isn't expected to take the initiative to send IOTLB update +messages, as the back-end sends IOTLB miss messages for the guest virtual memory areas it needs to access. -.. _slave_communication: +.. _backend_communication: -Slave communication -------------------- +Back-end communication +---------------------- -An optional communication channel is provided if the slave declares +An optional communication channel is provided if the back-end declares ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` protocol feature, to allow the -slave to make requests to the master. +back-end to make requests to the front-end. The fd is provided via ``VHOST_USER_SET_SLAVE_REQ_FD`` ancillary data. -A slave may then send ``VHOST_USER_SLAVE_*`` messages to the master +A back-end may then send ``VHOST_USER_SLAVE_*`` messages to the front-end using this fd communication channel. If ``VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD`` protocol feature is -negotiated, slave can send file descriptors (at most 8 descriptors in -each message) to master via ancillary data using this fd communication +negotiated, back-end can send file descriptors (at most 8 descriptors in +each message) to front-end via ancillary data using this fd communication channel. Inflight I/O tracking --------------------- -To support reconnecting after restart or crash, slave may need to +To support reconnecting after restart or crash, back-end may need to resubmit inflight I/Os. If virtqueue is processed in order, we can easily achieve that by getting the inflight descriptors from descriptor table (split virtqueue) or descriptor ring (packed @@ -555,18 +564,18 @@ virtqueue). However, it can't work when we process descriptors out-of-order because some entries which store the information of inflight descriptors in available ring (split virtqueue) or descriptor ring (packed virtqueue) might be overridden by new entries. To solve -this problem, slave need to allocate an extra buffer to store this -information of inflight descriptors and share it with master for +this problem, the back-end need to allocate an extra buffer to store this +information of inflight descriptors and share it with front-end for persistent. ``VHOST_USER_GET_INFLIGHT_FD`` and ``VHOST_USER_SET_INFLIGHT_FD`` are used to transfer this buffer -between master and slave. And the format of this buffer is described +between front-end and back-end. And the format of this buffer is described below: +---------------+---------------+-----+---------------+ | queue0 region | queue1 region | ... | queueN region | +---------------+---------------+-----+---------------+ -N is the number of available virtqueues. Slave could get it from num +N is the number of available virtqueues. The back-end could get it from num queues field of ``VhostUserInflight``. For split virtqueue, queue region can be implemented as: @@ -598,8 +607,8 @@ For split virtqueue, queue region can be implemented as: * Zero value indicates an uninitialized buffer */ uint16_t version; - /* The size of DescStateSplit array. It's equal to the virtqueue - * size. Slave could get it from queue size field of VhostUserInflight. */ + /* The size of DescStateSplit array. It's equal to the virtqueue size. + * The back-end could get it from queue size field of VhostUserInflight. */ uint16_t desc_num; /* The head of list that track the last batch of used descriptors. */ @@ -705,8 +714,8 @@ For packed virtqueue, queue region can be implemented as: * Zero value indicates an uninitialized buffer */ uint16_t version; - /* The size of DescStatePacked array. It's equal to the virtqueue - * size. Slave could get it from queue size field of VhostUserInflight. */ + /* The size of DescStatePacked array. It's equal to the virtqueue size. + * The back-end could get it from queue size field of VhostUserInflight. */ uint16_t desc_num; /* The head of free DescStatePacked entry list */ @@ -798,7 +807,7 @@ When reconnecting: #. Use ``old_used_wrap_counter`` to calculate the available flags #. If ``d.flags`` is not equal to the calculated flags value (means - slave has submitted the buffer to guest driver before crash, so + back-end has submitted the buffer to guest driver before crash, so it has to commit the in-progres update), set ``old_free_head``, ``old_used_idx``, ``old_used_wrap_counter`` to ``free_head``, ``used_idx``, ``used_wrap_counter`` @@ -827,11 +836,11 @@ cause the sending application(s) to block, it is not advised to use this feature unless absolutely necessary. It is also considered an error to negotiate this feature without also negotiating ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` and ``VHOST_USER_PROTOCOL_F_REPLY_ACK``, -the former is necessary for getting a message channel from the slave -to the master, while the latter needs to be used with the in-band +the former is necessary for getting a message channel from the back-end +to the front-end, while the latter needs to be used with the in-band notification messages to block until they are processed, both to avoid blocking later and for proper processing (at least in the simulation -use case.) As it has no other way of signalling this error, the slave +use case.) As it has no other way of signalling this error, the back-end should close the connection as a response to a ``VHOST_USER_SET_PROTOCOL_FEATURES`` message that sets the in-band notifications feature flag without the other two. @@ -859,95 +868,101 @@ Protocol features #define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15 #define VHOST_USER_PROTOCOL_F_STATUS 16 -Master message types --------------------- +Front-end message types +----------------------- ``VHOST_USER_GET_FEATURES`` :id: 1 :equivalent ioctl: ``VHOST_GET_FEATURES`` - :master payload: N/A - :slave payload: ``u64`` + :request payload: N/A + :reply payload: ``u64`` Get from the underlying vhost implementation the features bitmask. - Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals slave support + Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals back-end support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and ``VHOST_USER_SET_PROTOCOL_FEATURES``. ``VHOST_USER_SET_FEATURES`` :id: 2 :equivalent ioctl: ``VHOST_SET_FEATURES`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Enable features in the underlying vhost implementation using a bitmask. Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals - slave support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and + back-end support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and ``VHOST_USER_SET_PROTOCOL_FEATURES``. ``VHOST_USER_GET_PROTOCOL_FEATURES`` :id: 15 :equivalent ioctl: ``VHOST_GET_FEATURES`` - :master payload: N/A - :slave payload: ``u64`` + :request payload: N/A + :reply payload: ``u64`` Get the protocol feature bitmask from the underlying vhost implementation. Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is present in - ``VHOST_USER_GET_FEATURES``. + ``VHOST_USER_GET_FEATURES``. It does not need to be acknowledged by + ``VHOST_USER_SET_FEATURES``. .. Note:: - Slave that reported ``VHOST_USER_F_PROTOCOL_FEATURES`` must + Back-ends that report ``VHOST_USER_F_PROTOCOL_FEATURES`` must support this message even before ``VHOST_USER_SET_FEATURES`` was called. ``VHOST_USER_SET_PROTOCOL_FEATURES`` :id: 16 :equivalent ioctl: ``VHOST_SET_FEATURES`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Enable protocol features in the underlying vhost implementation. Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is present in - ``VHOST_USER_GET_FEATURES``. + ``VHOST_USER_GET_FEATURES``. It does not need to be acknowledged by + ``VHOST_USER_SET_FEATURES``. .. Note:: - Slave that reported ``VHOST_USER_F_PROTOCOL_FEATURES`` must support + Back-ends that report ``VHOST_USER_F_PROTOCOL_FEATURES`` must support this message even before ``VHOST_USER_SET_FEATURES`` was called. ``VHOST_USER_SET_OWNER`` :id: 3 :equivalent ioctl: ``VHOST_SET_OWNER`` - :master payload: N/A + :request payload: N/A + :reply payload: N/A - Issued when a new connection is established. It sets the current - *master* as an owner of the session. This can be used on the *slave* + Issued when a new connection is established. It marks the sender + as the front-end that owns of the session. This can be used on the *back-end* as a "session start" flag. ``VHOST_USER_RESET_OWNER`` :id: 4 - :master payload: N/A + :request payload: N/A + :reply payload: N/A .. admonition:: Deprecated This is no longer used. Used to be sent to request disabling all - rings, but some clients interpreted it to also discard connection + rings, but some back-ends interpreted it to also discard connection state (this interpretation would lead to bugs). It is recommended - that clients either ignore this message, or use it to disable all + that back-ends either ignore this message, or use it to disable all rings. ``VHOST_USER_SET_MEM_TABLE`` :id: 5 :equivalent ioctl: ``VHOST_SET_MEM_TABLE`` - :master payload: memory regions description - :slave payload: (postcopy only) memory regions description + :request payload: memory regions description + :reply payload: (postcopy only) memory regions description - Sets the memory map regions on the slave so it can translate the + Sets the memory map regions on the back-end so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. When ``VHOST_USER_POSTCOPY_LISTEN`` has been received, ``SET_MEM_TABLE`` replies with the bases of the memory mapped - regions to the master. The slave must have mmap'd the regions but + regions to the front-end. The back-end must have mmap'd the regions but not yet accessed them and should not yet generate a userfault event. @@ -961,12 +976,12 @@ Master message types ``VHOST_USER_SET_LOG_BASE`` :id: 6 :equivalent ioctl: ``VHOST_SET_LOG_BASE`` - :master payload: u64 - :slave payload: N/A + :request payload: u64 + :reply payload: N/A Sets logging shared memory space. - When slave has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature, + When the back-end has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature, the log memory fd is provided in the ancillary data of ``VHOST_USER_SET_LOG_BASE`` message, the size and offset of shared memory area provided in the message. @@ -974,44 +989,48 @@ Master message types ``VHOST_USER_SET_LOG_FD`` :id: 7 :equivalent ioctl: ``VHOST_SET_LOG_FD`` - :master payload: N/A + :request payload: N/A + :reply payload: N/A Sets the logging file descriptor, which is passed as ancillary data. ``VHOST_USER_SET_VRING_NUM`` :id: 8 :equivalent ioctl: ``VHOST_SET_VRING_NUM`` - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Set the size of the queue. ``VHOST_USER_SET_VRING_ADDR`` :id: 9 :equivalent ioctl: ``VHOST_SET_VRING_ADDR`` - :master payload: vring address description - :slave payload: N/A + :request payload: vring address description + :reply payload: N/A Sets the addresses of the different aspects of the vring. ``VHOST_USER_SET_VRING_BASE`` :id: 10 :equivalent ioctl: ``VHOST_SET_VRING_BASE`` - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Sets the base offset in the available vring. ``VHOST_USER_GET_VRING_BASE`` :id: 11 :equivalent ioctl: ``VHOST_USER_GET_VRING_BASE`` - :master payload: vring state description - :slave payload: vring state description + :request payload: vring state description + :reply payload: vring state description Get the available vring base offset. ``VHOST_USER_SET_VRING_KICK`` :id: 12 :equivalent ioctl: ``VHOST_SET_VRING_KICK`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set the event file descriptor for adding buffers to the vring. It is passed in the ancillary data. @@ -1029,7 +1048,8 @@ Master message types ``VHOST_USER_SET_VRING_CALL`` :id: 13 :equivalent ioctl: ``VHOST_SET_VRING_CALL`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set the event file descriptor to signal when buffers are used. It is passed in the ancillary data. @@ -1047,7 +1067,8 @@ Master message types ``VHOST_USER_SET_VRING_ERR`` :id: 14 :equivalent ioctl: ``VHOST_SET_VRING_ERR`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set the event file descriptor to signal when error occurs. It is passed in the ancillary data. @@ -1064,10 +1085,10 @@ Master message types ``VHOST_USER_GET_QUEUE_NUM`` :id: 17 :equivalent ioctl: N/A - :master payload: N/A - :slave payload: u64 + :request payload: N/A + :reply payload: u64 - Query how many queues the backend supports. + Query how many queues the back-end supports. This request should be sent only when ``VHOST_USER_PROTOCOL_F_MQ`` is set in queried protocol features by @@ -1076,9 +1097,10 @@ Master message types ``VHOST_USER_SET_VRING_ENABLE`` :id: 18 :equivalent ioctl: N/A - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A - Signal slave to enable or disable corresponding vring. + Signal the back-end to enable or disable corresponding vring. This request should be sent only when ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated. @@ -1086,9 +1108,10 @@ Master message types ``VHOST_USER_SEND_RARP`` :id: 19 :equivalent ioctl: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A - Ask vhost user backend to broadcast a fake RARP to notify the migration + Ask vhost user back-end to broadcast a fake RARP to notify the migration is terminated for guest that does not support GUEST_ANNOUNCE. Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is @@ -1096,12 +1119,13 @@ Master message types ``VHOST_USER_PROTOCOL_F_RARP`` is present in ``VHOST_USER_GET_PROTOCOL_FEATURES``. The first 6 bytes of the payload contain the mac address of the guest to allow the vhost user - backend to construct and broadcast the fake RARP. + back-end to construct and broadcast the fake RARP. ``VHOST_USER_NET_SET_MTU`` :id: 20 :equivalent ioctl: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set host MTU value exposed to the guest. @@ -1111,35 +1135,36 @@ Master message types ``VHOST_USER_PROTOCOL_F_NET_MTU`` is present in ``VHOST_USER_GET_PROTOCOL_FEATURES``. - If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, slave must + If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, the back-end must respond with zero in case the specified MTU is valid, or non-zero otherwise. ``VHOST_USER_SET_SLAVE_REQ_FD`` :id: 21 :equivalent ioctl: N/A - :master payload: N/A + :request payload: N/A + :reply payload: N/A - Set the socket file descriptor for slave initiated requests. It is passed + Set the socket file descriptor for back-end initiated requests. It is passed in the ancillary data. This request should be sent only when ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, and protocol feature bit ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` bit is present in ``VHOST_USER_GET_PROTOCOL_FEATURES``. If - ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, slave must + ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, the back-end must respond with zero for success, non-zero otherwise. ``VHOST_USER_IOTLB_MSG`` :id: 22 :equivalent ioctl: N/A (equivalent to ``VHOST_IOTLB_MSG`` message type) - :master payload: ``struct vhost_iotlb_msg`` - :slave payload: ``u64`` + :request payload: ``struct vhost_iotlb_msg`` + :reply payload: ``u64`` Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload. - Master sends such requests to update and invalidate entries in the - device IOTLB. The slave has to acknowledge the request with sending + The front-end sends such requests to update and invalidate entries in the + device IOTLB. The back-end has to acknowledge the request with sending zero as ``u64`` payload for success, non-zero otherwise. This request should be send only when ``VIRTIO_F_IOMMU_PLATFORM`` @@ -1148,7 +1173,8 @@ Master message types ``VHOST_USER_SET_VRING_ENDIAN`` :id: 23 :equivalent ioctl: ``VHOST_SET_VRING_ENDIAN`` - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Set the endianness of a VQ for legacy devices. Little-endian is indicated with state.num set to 0 and big-endian is indicated with @@ -1158,42 +1184,42 @@ Master message types ``VHOST_USER_PROTOCOL_F_CROSS_ENDIAN`` has been negotiated. Backends that negotiated this feature should handle both endiannesses and expect this message once (per VQ) during device - configuration (ie. before the master starts the VQ). + configuration (ie. before the front-end starts the VQ). ``VHOST_USER_GET_CONFIG`` :id: 24 :equivalent ioctl: N/A - :master payload: virtio device config space - :slave payload: virtio device config space + :request payload: virtio device config space + :reply payload: virtio device config space When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is - submitted by the vhost-user master to fetch the contents of the - virtio device configuration space, vhost-user slave's payload size - MUST match master's request, vhost-user slave uses zero length of - payload to indicate an error to vhost-user master. The vhost-user - master may cache the contents to avoid repeated + submitted by the vhost-user front-end to fetch the contents of the + virtio device configuration space, vhost-user back-end's payload size + MUST match the front-end's request, vhost-user back-end uses zero length of + payload to indicate an error to the vhost-user front-end. The vhost-user + front-end may cache the contents to avoid repeated ``VHOST_USER_GET_CONFIG`` calls. ``VHOST_USER_SET_CONFIG`` :id: 25 :equivalent ioctl: N/A - :master payload: virtio device config space - :slave payload: N/A + :request payload: virtio device config space + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is - submitted by the vhost-user master when the Guest changes the virtio + submitted by the vhost-user front-end when the Guest changes the virtio device configuration space and also can be used for live migration - on the destination host. The vhost-user slave must check the flags - field, and slaves MUST NOT accept SET_CONFIG for read-only + on the destination host. The vhost-user back-end must check the flags + field, and back-ends MUST NOT accept SET_CONFIG for read-only configuration space fields unless the live migration bit is set. ``VHOST_USER_CREATE_CRYPTO_SESSION`` :id: 26 :equivalent ioctl: N/A - :master payload: crypto session description - :slave payload: crypto session description + :request payload: crypto session description + :reply payload: crypto session description - Create a session for crypto operation. The server side must return + Create a session for crypto operation. The back-end must return the session id, 0 or positive for success, negative for failure. This request should be sent only when ``VHOST_USER_PROTOCOL_F_CRYPTO_SESSION`` feature has been @@ -1203,7 +1229,8 @@ Master message types ``VHOST_USER_CLOSE_CRYPTO_SESSION`` :id: 27 :equivalent ioctl: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Close a session for crypto operation which was previously created by ``VHOST_USER_CREATE_CRYPTO_SESSION``. @@ -1215,20 +1242,21 @@ Master message types ``VHOST_USER_POSTCOPY_ADVISE`` :id: 28 - :master payload: N/A - :slave payload: userfault fd + :request payload: N/A + :reply payload: userfault fd - When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, the master - advises slave that a migration with postcopy enabled is underway, - the slave must open a userfaultfd for later use. Note that at this + When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, the front-end + advises back-end that a migration with postcopy enabled is underway, + the back-end must open a userfaultfd for later use. Note that at this stage the migration is still in precopy mode. ``VHOST_USER_POSTCOPY_LISTEN`` :id: 29 - :master payload: N/A + :request payload: N/A + :reply payload: N/A - Master advises slave that a transition to postcopy mode has - happened. The slave must ensure that shared memory is registered + The front-end advises back-end that a transition to postcopy mode has + happened. The back-end must ensure that shared memory is registered with userfaultfd to cause faulting of non-present pages. This is always sent sometime after a ``VHOST_USER_POSTCOPY_ADVISE``, @@ -1236,10 +1264,11 @@ Master message types ``VHOST_USER_POSTCOPY_END`` :id: 30 - :slave payload: ``u64`` + :request payload: N/A + :reply payload: ``u64`` - Master advises that postcopy migration has now completed. The slave - must disable the userfaultfd. The response is an acknowledgement + The front-end advises that postcopy migration has now completed. The back-end + must disable the userfaultfd. The reply is an acknowledgement only. When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, this message @@ -1251,140 +1280,165 @@ Master message types ``VHOST_USER_GET_INFLIGHT_FD`` :id: 31 :equivalent ioctl: N/A - :master payload: inflight description + :request payload: inflight description + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has - been successfully negotiated, this message is submitted by master to - get a shared buffer from slave. The shared buffer will be used to - track inflight I/O by slave. QEMU should retrieve a new one when vm + been successfully negotiated, this message is submitted by the front-end to + get a shared buffer from back-end. The shared buffer will be used to + track inflight I/O by back-end. QEMU should retrieve a new one when vm reset. ``VHOST_USER_SET_INFLIGHT_FD`` :id: 32 :equivalent ioctl: N/A - :master payload: inflight description + :request payload: inflight description + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has - been successfully negotiated, this message is submitted by master to - send the shared inflight buffer back to slave so that slave could - get inflight I/O after a crash or restart. + been successfully negotiated, this message is submitted by the front-end to + send the shared inflight buffer back to the back-end so that the back-end + could get inflight I/O after a crash or restart. ``VHOST_USER_GPU_SET_SOCKET`` :id: 33 :equivalent ioctl: N/A - :master payload: N/A + :request payload: N/A + :reply payload: N/A Sets the GPU protocol socket file descriptor, which is passed as - ancillary data. The GPU protocol is used to inform the master of + ancillary data. The GPU protocol is used to inform the front-end of rendering state and updates. See vhost-user-gpu.rst for details. ``VHOST_USER_RESET_DEVICE`` :id: 34 :equivalent ioctl: N/A - :master payload: N/A - :slave payload: N/A + :request payload: N/A + :reply payload: N/A - Ask the vhost user backend to disable all rings and reset all + Ask the vhost user back-end to disable all rings and reset all internal device state to the initial state, ready to be - reinitialized. The backend retains ownership of the device + reinitialized. The back-end retains ownership of the device throughout the reset operation. Only valid if the ``VHOST_USER_PROTOCOL_F_RESET_DEVICE`` protocol - feature is set by the backend. + feature is set by the back-end. ``VHOST_USER_VRING_KICK`` :id: 35 :equivalent ioctl: N/A - :slave payload: vring state description - :master payload: N/A + :request payload: vring state description + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be - submitted by the master to indicate that a buffer was added to + submitted by the front-end to indicate that a buffer was added to the vring instead of signalling it using the vring's kick file - descriptor or having the slave rely on polling. + descriptor or having the back-end rely on polling. The state.num field is currently reserved and must be set to 0. ``VHOST_USER_GET_MAX_MEM_SLOTS`` :id: 36 :equivalent ioctl: N/A - :slave payload: u64 + :request payload: N/A + :reply payload: u64 When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted - by master to the slave. The slave should return the message with a + by the front-end to the back-end. The back-end should return the message with a u64 payload containing the maximum number of memory slots for - QEMU to expose to the guest. The value returned by the backend + QEMU to expose to the guest. The value returned by the back-end will be capped at the maximum number of ram slots which can be supported by the target platform. ``VHOST_USER_ADD_MEM_REG`` :id: 37 :equivalent ioctl: N/A - :slave payload: single memory region description + :request payload: N/A + :reply payload: single memory region description When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted - by the master to the slave. The message payload contains a memory + by the front-end to the back-end. The message payload contains a memory region descriptor struct, describing a region of guest memory which - the slave device must map in. When the + the back-end device must map in. When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, along with the ``VHOST_USER_REM_MEM_REG`` message, this message is used to set and - update the memory tables of the slave device. + update the memory tables of the back-end device. + + Exactly one file descriptor from which the memory is mapped is + passed in the ancillary data. + + In postcopy mode (see ``VHOST_USER_POSTCOPY_LISTEN``), the back-end + replies with the bases of the memory mapped region to the front-end. + For further details on postcopy, see ``VHOST_USER_SET_MEM_TABLE``. + They apply to ``VHOST_USER_ADD_MEM_REG`` accordingly. ``VHOST_USER_REM_MEM_REG`` :id: 38 :equivalent ioctl: N/A - :slave payload: single memory region description + :request payload: N/A + :reply payload: single memory region description When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted - by the master to the slave. The message payload contains a memory + by the front-end to the back-end. The message payload contains a memory region descriptor struct, describing a region of guest memory which - the slave device must unmap. When the + the back-end device must unmap. When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, along with the ``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and - update the memory tables of the slave device. + update the memory tables of the back-end device. + + The memory region to be removed is identified by its guest address, + user address and size. The mmap offset is ignored. + + No file descriptors SHOULD be passed in the ancillary data. For + compatibility with existing incorrect implementations, the back-end MAY + accept messages with one file descriptor. If a file descriptor is + passed, the back-end MUST close it without using it otherwise. ``VHOST_USER_SET_STATUS`` :id: 39 :equivalent ioctl: VHOST_VDPA_SET_STATUS - :slave payload: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been - successfully negotiated, this message is submitted by the master to - notify the backend with updated device status as defined in the Virtio + successfully negotiated, this message is submitted by the front-end to + notify the back-end with updated device status as defined in the Virtio specification. ``VHOST_USER_GET_STATUS`` :id: 40 :equivalent ioctl: VHOST_VDPA_GET_STATUS - :slave payload: ``u64`` - :master payload: N/A + :request payload: N/A + :reply payload: ``u64`` When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been - successfully negotiated, this message is submitted by the master to - query the backend for its device status as defined in the Virtio + successfully negotiated, this message is submitted by the front-end to + query the back-end for its device status as defined in the Virtio specification. -Slave message types -------------------- +Back-end message types +---------------------- + +For this type of message, the request is sent by the back-end and the reply +is sent by the front-end. ``VHOST_USER_SLAVE_IOTLB_MSG`` :id: 1 :equivalent ioctl: N/A (equivalent to ``VHOST_IOTLB_MSG`` message type) - :slave payload: ``struct vhost_iotlb_msg`` - :master payload: N/A + :request payload: ``struct vhost_iotlb_msg`` + :reply payload: N/A Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload. - Slave sends such requests to notify of an IOTLB miss, or an IOTLB + The back-end sends such requests to notify of an IOTLB miss, or an IOTLB access failure. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is - negotiated, and slave set the ``VHOST_USER_NEED_REPLY`` flag, master + negotiated, and back-end set the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond with zero when operation is successfully completed, or non-zero otherwise. This request should be send only when ``VIRTIO_F_IOMMU_PLATFORM`` feature has been successfully @@ -1393,23 +1447,23 @@ Slave message types ``VHOST_USER_SLAVE_CONFIG_CHANGE_MSG`` :id: 2 :equivalent ioctl: N/A - :slave payload: N/A - :master payload: N/A + :request payload: N/A + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, vhost-user - slave sends such messages to notify that the virtio device's + back-end sends such messages to notify that the virtio device's configuration space has changed, for those host devices which can support such feature, host driver can send ``VHOST_USER_GET_CONFIG`` - message to slave to get the latest content. If - ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and slave set the - ``VHOST_USER_NEED_REPLY`` flag, master must respond with zero when + message to the back-end to get the latest content. If + ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the back-end sets the + ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond with zero when operation is successfully completed, or non-zero otherwise. ``VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG`` :id: 3 :equivalent ioctl: N/A - :slave payload: vring area description - :master payload: N/A + :request payload: vring area description + :reply payload: N/A Sets host notifier for a specified queue. The queue index is contained in the ``u64`` field of the vring area description. The @@ -1420,7 +1474,7 @@ Slave message types description. QEMU can mmap the file descriptor based on the size and offset to get a memory range. Registering a host notifier means mapping this memory range to the VM as the specified queue's notify - MMIO region. Slave sends this request to tell QEMU to de-register + MMIO region. The back-end sends this request to tell QEMU to de-register the existing notifier if any and register the new notifier if the request is sent with a file descriptor. @@ -1431,28 +1485,28 @@ Slave message types ``VHOST_USER_SLAVE_VRING_CALL`` :id: 4 :equivalent ioctl: N/A - :slave payload: vring state description - :master payload: N/A + :request payload: vring state description + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be - submitted by the slave to indicate that a buffer was used from + submitted by the back-end to indicate that a buffer was used from the vring instead of signalling this using the vring's call file - descriptor or having the master relying on polling. + descriptor or having the front-end relying on polling. The state.num field is currently reserved and must be set to 0. ``VHOST_USER_SLAVE_VRING_ERR`` :id: 5 :equivalent ioctl: N/A - :slave payload: vring state description - :master payload: N/A + :request payload: vring state description + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be - submitted by the slave to indicate that an error occurred on the + submitted by the back-end to indicate that an error occurred on the specific vring, instead of signalling the error file descriptor - set by the master via ``VHOST_USER_SET_VRING_ERR``. + set by the front-end via ``VHOST_USER_SET_VRING_ERR``. The state.num field is currently reserved and must be set to 0. @@ -1463,21 +1517,21 @@ VHOST_USER_PROTOCOL_F_REPLY_ACK The original vhost-user specification only demands replies for certain commands. This differs from the vhost protocol implementation where -commands are sent over an ``ioctl()`` call and block until the client +commands are sent over an ``ioctl()`` call and block until the back-end has completed. With this protocol extension negotiated, the sender (QEMU) can set the ``need_reply`` [Bit 3] flag to any command. This indicates that the -client MUST respond with a Payload ``VhostUserMsg`` indicating success +back-end MUST respond with a Payload ``VhostUserMsg`` indicating success or failure. The payload should be set to zero on success or non-zero on failure, unless the message already has an explicit reply body. -The response payload gives QEMU a deterministic indication of the result +The reply payload gives QEMU a deterministic indication of the result of the command. Today, QEMU is expected to terminate the main vhost-user loop upon receiving such errors. In future, qemu could be taught to be more resilient for selective requests. -For the message types that already solicit a reply from the client, +For the message types that already solicit a reply from the back-end, the presence of ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` or need_reply bit being set brings no behavioural change. (See the Communication_ section for details.) @@ -1487,26 +1541,26 @@ section for details.) Backend program conventions =========================== -vhost-user backends can provide various devices & services and may +vhost-user back-ends can provide various devices & services and may need to be configured manually depending on the use case. However, it is a good idea to follow the conventions listed here when possible. Users, QEMU or libvirt, can then rely on some common behaviour to avoid heterogeneous configuration and management of the -backend programs and facilitate interoperability. +back-end programs and facilitate interoperability. -Each backend installed on a host system should come with at least one +Each back-end installed on a host system should come with at least one JSON file that conforms to the vhost-user.json schema. Each file -informs the management applications about the backend type, and binary +informs the management applications about the back-end type, and binary location. In addition, it defines rules for management apps for -picking the highest priority backend when multiple match the search +picking the highest priority back-end when multiple match the search criteria (see ``@VhostUserBackend`` documentation in the schema file). -If the backend is not capable of enabling a requested feature on the +If the back-end is not capable of enabling a requested feature on the host (such as 3D acceleration with virgl), or the initialization -failed, the backend should fail to start early and exit with a status +failed, the back-end should fail to start early and exit with a status != 0. It may also print a message to stderr for further details. -The backend program must not daemonize itself, but it may be +The back-end program must not daemonize itself, but it may be daemonized by the management layer. It may also have a restricted access to the system. @@ -1514,7 +1568,7 @@ File descriptors 0, 1 and 2 will exist, and have regular stdin/stdout/stderr usage (they may have been redirected to /dev/null by the management layer, or to a log handler). -The backend program must end (as quickly and cleanly as possible) when +The back-end program must end (as quickly and cleanly as possible) when the SIGTERM signal is received. Eventually, it may receive SIGKILL by the management layer after a few seconds. @@ -1528,15 +1582,15 @@ are mandatory, unless explicitly said differently: --fd=FDNUM - When this argument is given, the backend program is started with the + When this argument is given, the back-end program is started with the vhost-user socket as file descriptor FDNUM. It is incompatible with --socket-path. --print-capabilities - Output to stdout the backend capabilities in JSON format, and then + Output to stdout the back-end capabilities in JSON format, and then exit successfully. Other options and arguments should be ignored, and - the backend program should not perform its normal function. The + the back-end program should not perform its normal function. The capabilities can be reported dynamically depending on the host capabilities. diff --git a/docs/interop/vnc-ledstate-Pseudo-encoding.txt b/docs/interop/vnc-ledstate-pseudo-encoding.rst similarity index 100% rename from docs/interop/vnc-ledstate-Pseudo-encoding.txt rename to docs/interop/vnc-ledstate-pseudo-encoding.rst diff --git a/docs/meson.build b/docs/meson.build index 831d4aea2bb5..9136fed3b730 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -35,7 +35,7 @@ if sphinx_build.found() endif if build_docs - SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' + config_host['PKGVERSION']] + SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' + get_option('pkgversion')] man_pages = { 'qemu-ga.8': (have_ga ? 'man8' : ''), diff --git a/docs/pcie_sriov.txt b/docs/pcie_sriov.txt index f5e891e1d451..11158dbf8890 100644 --- a/docs/pcie_sriov.txt +++ b/docs/pcie_sriov.txt @@ -8,8 +8,8 @@ of a PCI Express device. It allows a single physical function (PF) to appear as virtual functions (VFs) for the main purpose of eliminating software overhead in I/O from virtual machines. -Qemu now implements the basic common functionality to enable an emulated device -to support SR/IOV. Yet no fully implemented devices exists in Qemu, but a +QEMU now implements the basic common functionality to enable an emulated device +to support SR/IOV. Yet no fully implemented devices exists in QEMU, but a proof-of-concept hack of the Intel igb can be found here: git://github.com/knuto/qemu.git sriov_patches_v5 @@ -18,7 +18,7 @@ Implementation ============== Implementing emulation of an SR/IOV capable device typically consists of implementing support for two types of device classes; the "normal" physical device -(PF) and the virtual device (VF). From Qemu's perspective, the VFs are just +(PF) and the virtual device (VF). From QEMU's perspective, the VFs are just like other devices, except that some of their properties are derived from the PF. diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt index 240888933482..c98c86d82802 100644 --- a/docs/qdev-device-use.txt +++ b/docs/qdev-device-use.txt @@ -216,11 +216,11 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows: * unix:FNAME becomes -chardev socket,path=FNAME -* /dev/parportN becomes -chardev parport,file=/dev/parportN +* /dev/parportN becomes -chardev parallel,file=/dev/parportN * /dev/ppiN likewise -* Any other /dev/FNAME becomes -chardev tty,path=/dev/FNAME +* Any other /dev/FNAME becomes -chardev serial,path=/dev/FNAME * mon:LEGACY-CHARDEV is special: it multiplexes the monitor onto the character device defined by LEGACY-CHARDEV. -chardev provides more diff --git a/docs/replay.txt b/docs/replay.txt deleted file mode 100644 index 5b008ca4911f..000000000000 --- a/docs/replay.txt +++ /dev/null @@ -1,410 +0,0 @@ -Copyright (c) 2010-2015 Institute for System Programming - of the Russian Academy of Sciences. - -This work is licensed under the terms of the GNU GPL, version 2 or later. -See the COPYING file in the top-level directory. - -Record/replay -------------- - -Record/replay functions are used for the deterministic replay of qemu execution. -Execution recording writes a non-deterministic events log, which can be later -used for replaying the execution anywhere and for unlimited number of times. -It also supports checkpointing for faster rewind to the specific replay moment. -Execution replaying reads the log and replays all non-deterministic events -including external input, hardware clocks, and interrupts. - -Deterministic replay has the following features: - * Deterministically replays whole system execution and all contents of - the memory, state of the hardware devices, clocks, and screen of the VM. - * Writes execution log into the file for later replaying for multiple times - on different machines. - * Supports i386, x86_64, and Arm hardware platforms. - * Performs deterministic replay of all operations with keyboard and mouse - input devices. - -Usage of the record/replay: - * First, record the execution with the following command line: - qemu-system-i386 \ - -icount shift=7,rr=record,rrfile=replay.bin \ - -drive file=disk.qcow2,if=none,snapshot,id=img-direct \ - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ - -device ide-hd,drive=img-blkreplay \ - -netdev user,id=net1 -device rtl8139,netdev=net1 \ - -object filter-replay,id=replay,netdev=net1 - * After recording, you can replay it by using another command line: - qemu-system-i386 \ - -icount shift=7,rr=replay,rrfile=replay.bin \ - -drive file=disk.qcow2,if=none,snapshot,id=img-direct \ - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ - -device ide-hd,drive=img-blkreplay \ - -netdev user,id=net1 -device rtl8139,netdev=net1 \ - -object filter-replay,id=replay,netdev=net1 - The only difference with recording is changing the rr option - from record to replay. - * Block device images are not actually changed in the recording mode, - because all of the changes are written to the temporary overlay file. - This behavior is enabled by using blkreplay driver. It should be used - for every enabled block device, as described in 'Block devices' section. - * '-net none' option should be specified when network is not used, - because QEMU adds network card by default. When network is needed, - it should be configured explicitly with replay filter, as described - in 'Network devices' section. - * Interaction with audio devices and serial ports are recorded and replayed - automatically when such devices are enabled. - -Academic papers with description of deterministic replay implementation: -http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html -http://dl.acm.org/citation.cfm?id=2786805.2803179 - -Modifications of qemu include: - * wrappers for clock and time functions to save their return values in the log - * saving different asynchronous events (e.g. system shutdown) into the log - * synchronization of the bottom halves execution - * synchronization of the threads from thread pool - * recording/replaying user input (mouse, keyboard, and microphone) - * adding internal checkpoints for cpu and io synchronization - * network filter for recording and replaying the packets - * block driver for making block layer deterministic - * serial port input record and replay - * recording of random numbers obtained from the external sources - -Locking and thread synchronisation ----------------------------------- - -Previously the synchronisation of the main thread and the vCPU thread -was ensured by the holding of the BQL. However the trend has been to -reduce the time the BQL was held across the system including under TCG -system emulation. As it is important that batches of events are kept -in sequence (e.g. expiring timers and checkpoints in the main thread -while instruction checkpoints are written by the vCPU thread) we need -another lock to keep things in lock-step. This role is now handled by -the replay_mutex_lock. It used to be held only for each event being -written but now it is held for a whole execution period. This results -in a deterministic ping-pong between the two main threads. - -As the BQL is now a finer grained lock than the replay_lock it is almost -certainly a bug, and a source of deadlocks, to take the -replay_mutex_lock while the BQL is held. This is enforced by an assert. -While the unlocks are usually in the reverse order, this is not -necessary; you can drop the replay_lock while holding the BQL, without -doing a more complicated unlock_iothread/replay_unlock/lock_iothread -sequence. - -Non-deterministic events ------------------------- - -Our record/replay system is based on saving and replaying non-deterministic -events (e.g. keyboard input) and simulating deterministic ones (e.g. reading -from HDD or memory of the VM). Saving only non-deterministic events makes -log file smaller and simulation faster. - -The following non-deterministic data from peripheral devices is saved into -the log: mouse and keyboard input, network packets, audio controller input, -serial port input, and hardware clocks (they are non-deterministic -too, because their values are taken from the host machine). Inputs from -simulated hardware, memory of VM, software interrupts, and execution of -instructions are not saved into the log, because they are deterministic and -can be replayed by simulating the behavior of virtual machine starting from -initial state. - -We had to solve three tasks to implement deterministic replay: recording -non-deterministic events, replaying non-deterministic events, and checking -that there is no divergence between record and replay modes. - -We changed several parts of QEMU to make event log recording and replaying. -Devices' models that have non-deterministic input from external devices were -changed to write every external event into the execution log immediately. -E.g. network packets are written into the log when they arrive into the virtual -network adapter. - -All non-deterministic events are coming from these devices. But to -replay them we need to know at which moments they occur. We specify -these moments by counting the number of instructions executed between -every pair of consecutive events. - -Instruction counting --------------------- - -QEMU should work in icount mode to use record/replay feature. icount was -designed to allow deterministic execution in absence of external inputs -of the virtual machine. We also use icount to control the occurrence of the -non-deterministic events. The number of instructions elapsed from the last event -is written to the log while recording the execution. In replay mode we -can predict when to inject that event using the instruction counter. - -Timers ------- - -Timers are used to execute callbacks from different subsystems of QEMU -at the specified moments of time. There are several kinds of timers: - * Real time clock. Based on host time and used only for callbacks that - do not change the virtual machine state. For this reason real time - clock and timers does not affect deterministic replay at all. - * Virtual clock. These timers run only during the emulation. In icount - mode virtual clock value is calculated using executed instructions counter. - That is why it is completely deterministic and does not have to be recorded. - * Host clock. This clock is used by device models that simulate real time - sources (e.g. real time clock chip). Host clock is the one of the sources - of non-determinism. Host clock read operations should be logged to - make the execution deterministic. - * Virtual real time clock. This clock is similar to real time clock but - it is used only for increasing virtual clock while virtual machine is - sleeping. Due to its nature it is also non-deterministic as the host clock - and has to be logged too. - -Checkpoints ------------ - -Replaying of the execution of virtual machine is bound by sources of -non-determinism. These are inputs from clock and peripheral devices, -and QEMU thread scheduling. Thread scheduling affect on processing events -from timers, asynchronous input-output, and bottom halves. - -Invocations of timers are coupled with clock reads and changing the state -of the virtual machine. Reads produce non-deterministic data taken from -host clock. And VM state changes should preserve their order. Their relative -order in replay mode must replicate the order of callbacks in record mode. -To preserve this order we use checkpoints. When a specific clock is processed -in record mode we save to the log special "checkpoint" event. -Checkpoints here do not refer to virtual machine snapshots. They are just -record/replay events used for synchronization. - -QEMU in replay mode will try to invoke timers processing in random moment -of time. That's why we do not process a group of timers until the checkpoint -event will be read from the log. Such an event allows synchronizing CPU -execution and timer events. - -Two other checkpoints govern the "warping" of the virtual clock. -While the virtual machine is idle, the virtual clock increments at -1 ns per *real time* nanosecond. This is done by setting up a timer -(called the warp timer) on the virtual real time clock, so that the -timer fires at the next deadline of the virtual clock; the virtual clock -is then incremented (which is called "warping" the virtual clock) as -soon as the timer fires or the CPUs need to go out of the idle state. -Two functions are used for this purpose; because these actions change -virtual machine state and must be deterministic, each of them creates a -checkpoint. icount_start_warp_timer checks if the CPUs are idle and if so -starts accounting real time to virtual clock. icount_account_warp_timer -is called when the CPUs get an interrupt or when the warp timer fires, -and it warps the virtual clock by the amount of real time that has passed -since icount_start_warp_timer. - -Bottom halves -------------- - -Disk I/O events are completely deterministic in our model, because -in both record and replay modes we start virtual machine from the same -disk state. But callbacks that virtual disk controller uses for reading and -writing the disk may occur at different moments of time in record and replay -modes. - -Reading and writing requests are created by CPU thread of QEMU. Later these -requests proceed to block layer which creates "bottom halves". Bottom -halves consist of callback and its parameters. They are processed when -main loop locks the global mutex. These locks are not synchronized with -replaying process because main loop also processes the events that do not -affect the virtual machine state (like user interaction with monitor). - -That is why we had to implement saving and replaying bottom halves callbacks -synchronously to the CPU execution. When the callback is about to execute -it is added to the queue in the replay module. This queue is written to the -log when its callbacks are executed. In replay mode callbacks are not processed -until the corresponding event is read from the events log file. - -Sometimes the block layer uses asynchronous callbacks for its internal purposes -(like reading or writing VM snapshots or disk image cluster tables). In this -case bottom halves are not marked as "replayable" and do not saved -into the log. - -Block devices -------------- - -Block devices record/replay module intercepts calls of -bdrv coroutine functions at the top of block drivers stack. -To record and replay block operations the drive must be configured -as following: - -drive file=disk.qcow2,if=none,snapshot,id=img-direct - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay - -device ide-hd,drive=img-blkreplay - -blkreplay driver should be inserted between disk image and virtual driver -controller. Therefore all disk requests may be recorded and replayed. - -All block completion operations are added to the queue in the coroutines. -Queue is flushed at checkpoints and information about processed requests -is recorded to the log. In replay phase the queue is matched with -events read from the log. Therefore block devices requests are processed -deterministically. - -Snapshotting ------------- - -New VM snapshots may be created in replay mode. They can be used later -to recover the desired VM state. All VM states created in replay mode -are associated with the moment of time in the replay scenario. -After recovering the VM state replay will start from that position. - -Default starting snapshot name may be specified with icount field -rrsnapshot as follows: - -icount shift=7,rr=record,rrfile=replay.bin,rrsnapshot=snapshot_name - -This snapshot is created at start of recording and restored at start -of replaying. It also can be loaded while replaying to roll back -the execution. - -'snapshot' flag of the disk image must be removed to save the snapshots -in the overlay (or original image) instead of using the temporary overlay. - -drive file=disk.ovl,if=none,id=img-direct - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay - -device ide-hd,drive=img-blkreplay - -Use QEMU monitor to create additional snapshots. 'savevm ' command -created the snapshot and 'loadvm ' restores it. To prevent corruption -of the original disk image, use overlay files linked to the original images. -Therefore all new snapshots (including the starting one) will be saved in -overlays and the original image remains unchanged. - -When you need to use snapshots with diskless virtual machine, -it must be started with 'orphan' qcow2 image. This image will be used -for storing VM snapshots. Here is the example of the command line for this: - - qemu-system-i386 -icount shift=3,rr=replay,rrfile=record.bin,rrsnapshot=init \ - -net none -drive file=empty.qcow2,if=none,id=rr - -empty.qcow2 drive does not connected to any virtual block device and used -for VM snapshots only. - -Network devices ---------------- - -Record and replay for network interactions is performed with the network filter. -Each backend must have its own instance of the replay filter as follows: - -netdev user,id=net1 -device rtl8139,netdev=net1 - -object filter-replay,id=replay,netdev=net1 - -Replay network filter is used to record and replay network packets. While -recording the virtual machine this filter puts all packets coming from -the outer world into the log. In replay mode packets from the log are -injected into the network device. All interactions with network backend -in replay mode are disabled. - -Audio devices -------------- - -Audio data is recorded and replay automatically. The command line for recording -and replaying must contain identical specifications of audio hardware, e.g.: - -soundhw ac97 - -Serial ports ------------- - -Serial ports input is recorded and replay automatically. The command lines -for recording and replaying must contain identical number of ports in record -and replay modes, but their backends may differ. -E.g., '-serial stdio' in record mode, and '-serial null' in replay mode. - -Reverse debugging ------------------ - -Reverse debugging allows "executing" the program in reverse direction. -GDB remote protocol supports "reverse step" and "reverse continue" -commands. The first one steps single instruction backwards in time, -and the second one finds the last breakpoint in the past. - -Recorded executions may be used to enable reverse debugging. QEMU can't -execute the code in backwards direction, but can load a snapshot and -replay forward to find the desired position or breakpoint. - -The following GDB commands are supported: - - reverse-stepi (or rsi) - step one instruction backwards - - reverse-continue (or rc) - find last breakpoint in the past - -Reverse step loads the nearest snapshot and replays the execution until -the required instruction is met. - -Reverse continue may include several passes of examining the execution -between the snapshots. Each of the passes include the following steps: - 1. loading the snapshot - 2. replaying to examine the breakpoints - 3. if breakpoint or watchpoint was met - - loading the snapshot again - - replaying to the required breakpoint - 4. else - - proceeding to the p.1 with the earlier snapshot - -Therefore usage of the reverse debugging requires at least one snapshot -created in advance. This can be done by omitting 'snapshot' option -for the block drives and adding 'rrsnapshot' for both record and replay -command lines. -See the "Snapshotting" section to learn more about running record/replay -and creating the snapshot in these modes. - -Replay log format ------------------ - -Record/replay log consists of the header and the sequence of execution -events. The header includes 4-byte replay version id and 8-byte reserved -field. Version is updated every time replay log format changes to prevent -using replay log created by another build of qemu. - -The sequence of the events describes virtual machine state changes. -It includes all non-deterministic inputs of VM, synchronization marks and -instruction counts used to correctly inject inputs at replay. - -Synchronization marks (checkpoints) are used for synchronizing qemu threads -that perform operations with virtual hardware. These operations may change -system's state (e.g., change some register or generate interrupt) and -therefore should execute synchronously with CPU thread. - -Every event in the log includes 1-byte event id and optional arguments. -When argument is an array, it is stored as 4-byte array length -and corresponding number of bytes with data. -Here is the list of events that are written into the log: - - - EVENT_INSTRUCTION. Instructions executed since last event. - Argument: 4-byte number of executed instructions. - - EVENT_INTERRUPT. Used to synchronize interrupt processing. - - EVENT_EXCEPTION. Used to synchronize exception handling. - - EVENT_ASYNC. This is a group of events. They are always processed - together with checkpoints. When such an event is generated, it is - stored in the queue and processed only when checkpoint occurs. - Every such event is followed by 1-byte checkpoint id and 1-byte - async event id from the following list: - - REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes - callbacks that affect virtual machine state, but normally called - asynchronously. - Argument: 8-byte operation id. - - REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains - parameters of keyboard and mouse input operations - (key press/release, mouse pointer movement). - Arguments: 9-16 bytes depending of input event. - - REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event. - - REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input - initiated by the sender. - Arguments: 1-byte character device id. - Array with bytes were read. - - REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize - operations with disk and flash drives with CPU. - Argument: 8-byte operation id. - - REPLAY_ASYNC_EVENT_NET. Incoming network packet. - Arguments: 1-byte network adapter id. - 4-byte packet flags. - Array with packet bytes. - - EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu, - e.g., by closing the window. - - EVENT_CHAR_WRITE. Used to synchronize character output operations. - Arguments: 4-byte output function return value. - 4-byte offset in the output array. - - EVENT_CHAR_READ_ALL. Used to synchronize character input operations, - initiated by qemu. - Argument: Array with bytes that were read. - - EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation, - initiated by qemu. - Argument: 4-byte error code. - - EVENT_CLOCK + clock_id. Group of events for host clock read operations. - Argument: 8-byte clock value. - - EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of - CPU, internal threads, and asynchronous input events. May be followed - by one or more EVENT_ASYNC events. - - EVENT_END. Last event in the log. diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst index a8a9d22d2541..2339b60ad74d 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/fw_cfg.rst b/docs/specs/fw_cfg.rst new file mode 100644 index 000000000000..5ad47a901c9f --- /dev/null +++ b/docs/specs/fw_cfg.rst @@ -0,0 +1,290 @@ +=========================================== +QEMU Firmware Configuration (fw_cfg) Device +=========================================== + +Guest-side Hardware Interface +============================= + +This hardware interface allows the guest to retrieve various data items +(blobs) that can influence how the firmware configures itself, or may +contain tables to be installed for the guest OS. Examples include device +boot order, ACPI and SMBIOS tables, virtual machine UUID, SMP and NUMA +information, kernel/initrd images for direct (Linux) kernel booting, etc. + +Selector (Control) Register +--------------------------- + +* Write only +* Location: platform dependent (IOport or MMIO) +* Width: 16-bit +* Endianness: little-endian (if IOport), or big-endian (if MMIO) + +A write to this register sets the index of a firmware configuration +item which can subsequently be accessed via the data register. + +Setting the selector register will cause the data offset to be set +to zero. The data offset impacts which data is accessed via the data +register, and is explained below. + +Bit14 of the selector register indicates whether the configuration +setting is being written. A value of 0 means the item is only being +read, and all write access to the data port will be ignored. A value +of 1 means the item's data can be overwritten by writes to the data +register. In other words, configuration write mode is enabled when +the selector value is between 0x4000-0x7fff or 0xc000-0xffff. + +.. NOTE:: + As of QEMU v2.4, writes to the fw_cfg data register are no + longer supported, and will be ignored (treated as no-ops)! + +.. NOTE:: + As of QEMU v2.9, writes are reinstated, but only through the DMA + interface (see below). Furthermore, writeability of any specific item is + governed independently of Bit14 in the selector key value. + +Bit15 of the selector register indicates whether the configuration +setting is architecture specific. A value of 0 means the item is a +generic configuration item. A value of 1 means the item is specific +to a particular architecture. In other words, generic configuration +items are accessed with a selector value between 0x0000-0x7fff, and +architecture specific configuration items are accessed with a selector +value between 0x8000-0xffff. + +Data Register +------------- + +* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface) +* Location: platform dependent (IOport [#]_ or MMIO) +* Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO) +* Endianness: string-preserving + +.. [#] + On platforms where the data register is exposed as an IOport, its + port number will always be one greater than the port number of the + selector register. In other words, the two ports overlap, and can not + be mapped separately. + +The data register allows access to an array of bytes for each firmware +configuration data item. The specific item is selected by writing to +the selector register, as described above. + +Initially following a write to the selector register, the data offset +will be set to zero. Each successful access to the data register will +increment the data offset by the appropriate access width. + +Each firmware configuration item has a maximum length of data +associated with the item. After the data offset has passed the +end of this maximum data length, then any reads will return a data +value of 0x00, and all writes will be ignored. + +An N-byte wide read of the data register will return the next available +N bytes of the selected firmware configuration item, as a substring, in +increasing address order, similar to memcpy(). + +Register Locations +------------------ + +x86, x86_64 + * Selector Register IOport: 0x510 + * Data Register IOport: 0x511 + * DMA Address IOport: 0x514 + +Arm + * Selector Register address: Base + 8 (2 bytes) + * Data Register address: Base + 0 (8 bytes) + * DMA Address address: Base + 16 (8 bytes) + +ACPI Interface +-------------- + +The fw_cfg device is defined with ACPI ID ``QEMU0002``. Since we expect +ACPI tables to be passed into the guest through the fw_cfg device itself, +the guest-side firmware can not use ACPI to find fw_cfg. However, once the +firmware is finished setting up ACPI tables and hands control over to the +guest kernel, the latter can use the fw_cfg ACPI node for a more accurate +inventory of in-use IOport or MMIO regions. + +Firmware Configuration Items +---------------------------- + +Signature (Key 0x0000, ``FW_CFG_SIGNATURE``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The presence of the fw_cfg selector and data registers can be verified +by selecting the "signature" item using key 0x0000 (``FW_CFG_SIGNATURE``), +and reading four bytes from the data register. If the fw_cfg device is +present, the four bytes read will contain the characters ``QEMU``. + +If the DMA interface is available, then reading the DMA Address +Register returns 0x51454d5520434647 (``QEMU CFG`` in big-endian format). + +Revision / feature bitmap (Key 0x0001, ``FW_CFG_ID``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 32-bit little-endian unsigned int, this item is used to check for enabled +features. + +- Bit 0: traditional interface. Always set. +- Bit 1: DMA interface. + +File Directory (Key 0x0019, ``FW_CFG_FILE_DIR``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. highlight:: c + +Firmware configuration items stored at selector keys 0x0020 or higher +(``FW_CFG_FILE_FIRST`` or higher) have an associated entry in a directory +structure, which makes it easier for guest-side firmware to identify +and retrieve them. The format of this file directory (from ``fw_cfg.h`` in +the QEMU source tree) is shown here, slightly annotated for clarity:: + + struct FWCfgFiles { /* the entire file directory fw_cfg item */ + uint32_t count; /* number of entries, in big-endian format */ + struct FWCfgFile f[]; /* array of file entries, see below */ + }; + + struct FWCfgFile { /* an individual file entry, 64 bytes total */ + uint32_t size; /* size of referenced fw_cfg item, big-endian */ + uint16_t select; /* selector key of fw_cfg item, big-endian */ + uint16_t reserved; + char name[56]; /* fw_cfg item name, NUL-terminated ascii */ + }; + +All Other Data Items +~~~~~~~~~~~~~~~~~~~~ + +Please consult the QEMU source for the most up-to-date and authoritative list +of selector keys and their respective items' purpose, format and writeability. + +Ranges +~~~~~~ + +Theoretically, there may be up to 0x4000 generic firmware configuration +items, and up to 0x4000 architecturally specific ones. + +=============== =========== +Selector Reg. Range Usage +=============== =========== +0x0000 - 0x3fff Generic (0x0000 - 0x3fff, generally RO, possibly RW through + the DMA interface in QEMU v2.9+) +0x4000 - 0x7fff Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+) +0x8000 - 0xbfff Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW + through the DMA interface in QEMU v2.9+) +0xc000 - 0xffff Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+) +=============== =========== + +In practice, the number of allowed firmware configuration items depends on the +machine type/version. + +Guest-side DMA Interface +======================== + +If bit 1 of the feature bitmap is set, the DMA interface is present. This does +not replace the existing fw_cfg interface, it is an add-on. This interface +can be used through the 64-bit wide address register. + +The address register is in big-endian format. The value for the register is 0 +at startup and after an operation. A write to the least significant half (at +offset 4) triggers an operation. This means that operations with 32-bit +addresses can be triggered with just one write, whereas operations with +64-bit addresses can be triggered with one 64-bit write or two 32-bit writes, +starting with the most significant half (at offset 0). + +In this register, the physical address of a ``FWCfgDmaAccess`` structure in RAM +should be written. This is the format of the ``FWCfgDmaAccess`` structure:: + + typedef struct FWCfgDmaAccess { + uint32_t control; + uint32_t length; + uint64_t address; + } FWCfgDmaAccess; + +The fields of the structure are in big endian mode, and the field at the lowest +address is the ``control`` field. + +The ``control`` field has the following bits: + +- Bit 0: Error +- Bit 1: Read +- Bit 2: Skip +- Bit 3: Select. The upper 16 bits are the selected index. +- Bit 4: Write + +When an operation is triggered, if the ``control`` field has bit 3 set, the +upper 16 bits are interpreted as an index of a firmware configuration item. +This has the same effect as writing the selector register. + +If the ``control`` field has bit 1 set, a read operation will be performed. +``length`` bytes for the current selector and offset will be copied into the +physical RAM address specified by the ``address`` field. + +If the ``control`` field has bit 4 set (and not bit 1), a write operation will be +performed. ``length`` bytes will be copied from the physical RAM address +specified by the ``address`` field to the current selector and offset. QEMU +prevents starting or finishing the write beyond the end of the item associated +with the current selector (i.e., the item cannot be resized). Truncated writes +are dropped entirely. Writes to read-only items are also rejected. All of these +write errors set bit 0 (the error bit) in the ``control`` field. + +If the ``control`` field has bit 2 set (and neither bit 1 nor bit 4), a skip +operation will be performed. The offset for the current selector will be +advanced ``length`` bytes. + +To check the result, read the ``control`` field: + +Error bit set + Something went wrong. +All bits cleared + Transfer finished successfully. +Otherwise + Transfer still in progress + (doesn't happen today due to implementation not being async, + but may in the future). + +Externally Provided Items +========================= + +Since v2.4, "file" fw_cfg items (i.e., items with selector keys above +``FW_CFG_FILE_FIRST``, and with a corresponding entry in the fw_cfg file +directory structure) may be inserted via the QEMU command line, using +the following syntax:: + + -fw_cfg [name=],file= + +Or:: + + -fw_cfg [name=],string= + +Since v5.1, QEMU allows some objects to generate fw_cfg-specific content, +the content is then associated with a "file" item using the 'gen_id' option +in the command line, using the following syntax:: + + -object ,id=,[generator-specific-options] \ + -fw_cfg [name=],gen_id= + +See QEMU man page for more documentation. + +Using item_name with plain ASCII characters only is recommended. + +Item names beginning with ``opt/`` are reserved for users. QEMU will +never create entries with such names unless explicitly ordered by the +user. + +To avoid clashes among different users, it is strongly recommended +that you use names beginning with ``opt/RFQDN/``, where RFQDN is a reverse +fully qualified domain name you control. For instance, if SeaBIOS +wanted to define additional names, the prefix ``opt/org.seabios/`` would +be appropriate. + +For historical reasons, ``opt/ovmf/`` is reserved for OVMF firmware. + +Prefix ``opt/org.qemu/`` is reserved for QEMU itself. + +Use of names not beginning with ``opt/`` is potentially dangerous and +entirely unsupported. QEMU will warn if you try. + +Use of names not beginning with ``opt/`` is tolerated with 'gen_id' (that +is, the warning is suppressed), but you must know exactly what you're +doing. + +All externally provided fw_cfg items are read-only to the guest. diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt deleted file mode 100644 index 3e6d586f66bf..000000000000 --- a/docs/specs/fw_cfg.txt +++ /dev/null @@ -1,265 +0,0 @@ -QEMU Firmware Configuration (fw_cfg) Device -=========================================== - -= Guest-side Hardware Interface = - -This hardware interface allows the guest to retrieve various data items -(blobs) that can influence how the firmware configures itself, or may -contain tables to be installed for the guest OS. Examples include device -boot order, ACPI and SMBIOS tables, virtual machine UUID, SMP and NUMA -information, kernel/initrd images for direct (Linux) kernel booting, etc. - -== Selector (Control) Register == - -* Write only -* Location: platform dependent (IOport or MMIO) -* Width: 16-bit -* Endianness: little-endian (if IOport), or big-endian (if MMIO) - -A write to this register sets the index of a firmware configuration -item which can subsequently be accessed via the data register. - -Setting the selector register will cause the data offset to be set -to zero. The data offset impacts which data is accessed via the data -register, and is explained below. - -Bit14 of the selector register indicates whether the configuration -setting is being written. A value of 0 means the item is only being -read, and all write access to the data port will be ignored. A value -of 1 means the item's data can be overwritten by writes to the data -register. In other words, configuration write mode is enabled when -the selector value is between 0x4000-0x7fff or 0xc000-0xffff. - -NOTE: As of QEMU v2.4, writes to the fw_cfg data register are no - longer supported, and will be ignored (treated as no-ops)! - -NOTE: As of QEMU v2.9, writes are reinstated, but only through the DMA - interface (see below). Furthermore, writeability of any specific item is - governed independently of Bit14 in the selector key value. - -Bit15 of the selector register indicates whether the configuration -setting is architecture specific. A value of 0 means the item is a -generic configuration item. A value of 1 means the item is specific -to a particular architecture. In other words, generic configuration -items are accessed with a selector value between 0x0000-0x7fff, and -architecture specific configuration items are accessed with a selector -value between 0x8000-0xffff. - -== Data Register == - -* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface) -* Location: platform dependent (IOport [*] or MMIO) -* Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO) -* Endianness: string-preserving - -[*] On platforms where the data register is exposed as an IOport, its -port number will always be one greater than the port number of the -selector register. In other words, the two ports overlap, and can not -be mapped separately. - -The data register allows access to an array of bytes for each firmware -configuration data item. The specific item is selected by writing to -the selector register, as described above. - -Initially following a write to the selector register, the data offset -will be set to zero. Each successful access to the data register will -increment the data offset by the appropriate access width. - -Each firmware configuration item has a maximum length of data -associated with the item. After the data offset has passed the -end of this maximum data length, then any reads will return a data -value of 0x00, and all writes will be ignored. - -An N-byte wide read of the data register will return the next available -N bytes of the selected firmware configuration item, as a substring, in -increasing address order, similar to memcpy(). - -== Register Locations == - -=== x86, x86_64 Register Locations === - -Selector Register IOport: 0x510 -Data Register IOport: 0x511 -DMA Address IOport: 0x514 - -=== Arm Register Locations === - -Selector Register address: Base + 8 (2 bytes) -Data Register address: Base + 0 (8 bytes) -DMA Address address: Base + 16 (8 bytes) - -== ACPI Interface == - -The fw_cfg device is defined with ACPI ID "QEMU0002". Since we expect -ACPI tables to be passed into the guest through the fw_cfg device itself, -the guest-side firmware can not use ACPI to find fw_cfg. However, once the -firmware is finished setting up ACPI tables and hands control over to the -guest kernel, the latter can use the fw_cfg ACPI node for a more accurate -inventory of in-use IOport or MMIO regions. - -== Firmware Configuration Items == - -=== Signature (Key 0x0000, FW_CFG_SIGNATURE) === - -The presence of the fw_cfg selector and data registers can be verified -by selecting the "signature" item using key 0x0000 (FW_CFG_SIGNATURE), -and reading four bytes from the data register. If the fw_cfg device is -present, the four bytes read will contain the characters "QEMU". - -If the DMA interface is available, then reading the DMA Address -Register returns 0x51454d5520434647 ("QEMU CFG" in big-endian format). - -=== Revision / feature bitmap (Key 0x0001, FW_CFG_ID) === - -A 32-bit little-endian unsigned int, this item is used to check for enabled -features. - - Bit 0: traditional interface. Always set. - - Bit 1: DMA interface. - -=== File Directory (Key 0x0019, FW_CFG_FILE_DIR) === - -Firmware configuration items stored at selector keys 0x0020 or higher -(FW_CFG_FILE_FIRST or higher) have an associated entry in a directory -structure, which makes it easier for guest-side firmware to identify -and retrieve them. The format of this file directory (from fw_cfg.h in -the QEMU source tree) is shown here, slightly annotated for clarity: - -struct FWCfgFiles { /* the entire file directory fw_cfg item */ - uint32_t count; /* number of entries, in big-endian format */ - struct FWCfgFile f[]; /* array of file entries, see below */ -}; - -struct FWCfgFile { /* an individual file entry, 64 bytes total */ - uint32_t size; /* size of referenced fw_cfg item, big-endian */ - uint16_t select; /* selector key of fw_cfg item, big-endian */ - uint16_t reserved; - char name[56]; /* fw_cfg item name, NUL-terminated ascii */ -}; - -=== All Other Data Items === - -Please consult the QEMU source for the most up-to-date and authoritative list -of selector keys and their respective items' purpose, format and writeability. - -=== Ranges === - -Theoretically, there may be up to 0x4000 generic firmware configuration -items, and up to 0x4000 architecturally specific ones. - -Selector Reg. Range Usage ---------------- ----------- -0x0000 - 0x3fff Generic (0x0000 - 0x3fff, generally RO, possibly RW through - the DMA interface in QEMU v2.9+) -0x4000 - 0x7fff Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+) -0x8000 - 0xbfff Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW - through the DMA interface in QEMU v2.9+) -0xc000 - 0xffff Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+) - -In practice, the number of allowed firmware configuration items depends on the -machine type/version. - -= Guest-side DMA Interface = - -If bit 1 of the feature bitmap is set, the DMA interface is present. This does -not replace the existing fw_cfg interface, it is an add-on. This interface -can be used through the 64-bit wide address register. - -The address register is in big-endian format. The value for the register is 0 -at startup and after an operation. A write to the least significant half (at -offset 4) triggers an operation. This means that operations with 32-bit -addresses can be triggered with just one write, whereas operations with -64-bit addresses can be triggered with one 64-bit write or two 32-bit writes, -starting with the most significant half (at offset 0). - -In this register, the physical address of a FWCfgDmaAccess structure in RAM -should be written. This is the format of the FWCfgDmaAccess structure: - -typedef struct FWCfgDmaAccess { - uint32_t control; - uint32_t length; - uint64_t address; -} FWCfgDmaAccess; - -The fields of the structure are in big endian mode, and the field at the lowest -address is the "control" field. - -The "control" field has the following bits: - - Bit 0: Error - - Bit 1: Read - - Bit 2: Skip - - Bit 3: Select. The upper 16 bits are the selected index. - - Bit 4: Write - -When an operation is triggered, if the "control" field has bit 3 set, the -upper 16 bits are interpreted as an index of a firmware configuration item. -This has the same effect as writing the selector register. - -If the "control" field has bit 1 set, a read operation will be performed. -"length" bytes for the current selector and offset will be copied into the -physical RAM address specified by the "address" field. - -If the "control" field has bit 4 set (and not bit 1), a write operation will be -performed. "length" bytes will be copied from the physical RAM address -specified by the "address" field to the current selector and offset. QEMU -prevents starting or finishing the write beyond the end of the item associated -with the current selector (i.e., the item cannot be resized). Truncated writes -are dropped entirely. Writes to read-only items are also rejected. All of these -write errors set bit 0 (the error bit) in the "control" field. - -If the "control" field has bit 2 set (and neither bit 1 nor bit 4), a skip -operation will be performed. The offset for the current selector will be -advanced "length" bytes. - -To check the result, read the "control" field: - error bit set -> something went wrong. - all bits cleared -> transfer finished successfully. - otherwise -> transfer still in progress (doesn't happen - today due to implementation not being async, - but may in the future). - -= Externally Provided Items = - -Since v2.4, "file" fw_cfg items (i.e., items with selector keys above -FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file -directory structure) may be inserted via the QEMU command line, using -the following syntax: - - -fw_cfg [name=],file= - -Or - - -fw_cfg [name=],string= - -Since v5.1, QEMU allows some objects to generate fw_cfg-specific content, -the content is then associated with a "file" item using the 'gen_id' option -in the command line, using the following syntax: - - -object ,id=,[generator-specific-options] \ - -fw_cfg [name=],gen_id= - -See QEMU man page for more documentation. - -Using item_name with plain ASCII characters only is recommended. - -Item names beginning with "opt/" are reserved for users. QEMU will -never create entries with such names unless explicitly ordered by the -user. - -To avoid clashes among different users, it is strongly recommended -that you use names beginning with opt/RFQDN/, where RFQDN is a reverse -fully qualified domain name you control. For instance, if SeaBIOS -wanted to define additional names, the prefix "opt/org.seabios/" would -be appropriate. - -For historical reasons, "opt/ovmf/" is reserved for OVMF firmware. - -Prefix "opt/org.qemu/" is reserved for QEMU itself. - -Use of names not beginning with "opt/" is potentially dangerous and -entirely unsupported. QEMU will warn if you try. - -Use of names not beginning with "opt/" is tolerated with 'gen_id' (that -is, the warning is suppressed), but you must know exactly what you're -doing. - -All externally provided fw_cfg items are read-only to the guest. diff --git a/docs/specs/index.rst b/docs/specs/index.rst index e10684bf5353..a58d9311cb36 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -20,3 +20,4 @@ guest hardware that is specific to QEMU. acpi_nvdimm acpi_erst sev-guest-firmware + fw_cfg diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index dd6859d039d0..e463c4cb3a22 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -22,16 +22,14 @@ maintained as part of the virtio specification. 1af4:1004 SCSI host bus adapter device (legacy) 1af4:1005 entropy generator device (legacy) 1af4:1009 9p filesystem device (legacy) - -1af4:1041 network device (modern) -1af4:1042 block device (modern) -1af4:1043 console device (modern) -1af4:1044 entropy generator device (modern) -1af4:1045 balloon device (modern) -1af4:1048 SCSI host bus adapter device (modern) -1af4:1049 9p filesystem device (modern) -1af4:1050 virtio gpu device (modern) -1af4:1052 virtio input device (modern) +1af4:1012 vsock device (bug compatibility) + +1af4:1040 Start of ID range for modern virtio devices. The PCI device + to ID is calculated from the virtio device ID by adding the +1af4:10ef 0x1040 offset. The virtio IDs are defined in the virtio + specification. The Linux kernel has a header file with + defines for all virtio IDs (linux/virtio_ids.h), qemu has a + copy in include/standard-headers/. 1af4:10f0 Available for experimental usage without registration. Must get to official ID when the code leaves the test lab (i.e. when seeking diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 3be190343a02..535912a92b81 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/specs/vmgenid.txt b/docs/specs/vmgenid.txt index aa9f5186767c..80ff69f31cc2 100644 --- a/docs/specs/vmgenid.txt +++ b/docs/specs/vmgenid.txt @@ -153,7 +153,7 @@ change the contents of the memory at runtime, specifically when starting a backed-up or snapshotted image. In order to do this, QEMU must know the address that has been allocated. -The mechanism chosen for this memory sharing is writeable fw_cfg blobs. +The mechanism chosen for this memory sharing is writable fw_cfg blobs. These are data object that are visible to both QEMU and guests, and are addressable as sequential files. @@ -164,7 +164,7 @@ Two fw_cfg blobs are used in this case: /etc/vmgenid_guid - contains the actual VM Generation ID GUID - read-only to the guest /etc/vmgenid_addr - contains the address of the downloaded vmgenid blob - - writeable by the guest + - writable by the guest QEMU sends the following commands to the guest at startup: diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 60ed94f18759..6c5b05128ea8 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -31,6 +31,10 @@ AST2600 SoC based machines : - ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC - ``rainier-bmc`` IBM Rainier POWER10 BMC - ``fuji-bmc`` Facebook Fuji BMC +- ``bletchley-bmc`` Facebook Bletchley BMC +- ``fby35-bmc`` Facebook fby35 BMC +- ``qcom-dc-scm-v1-bmc`` Qualcomm DC-SCM V1 BMC +- ``qcom-firework-bmc`` Qualcomm Firework BMC Supported devices ----------------- @@ -39,7 +43,7 @@ Supported devices * Interrupt Controller (VIC) * Timer Controller * RTC Controller - * I2C Controller + * I2C Controller, including the new register interface of the AST2600 * System Control Unit (SCU) * SRAM mapping * X-DMA Controller (basic interface) @@ -56,6 +60,10 @@ Supported devices * LPC Peripheral Controller (a subset of subdevices are supported) * Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA * ADC + * Secure Boot Controller (AST2600) + * eMMC Boot Controller (dummy) + * PECI Controller (minimal) + * I3C Controller Missing devices @@ -67,12 +75,10 @@ Missing devices * Super I/O Controller * PCI-Express 1 Controller * Graphic Display Controller - * PECI Controller * MCTP Controller * Mailbox Controller * Virtual UART * eSPI Controller - * I3C Controller Boot options ------------ @@ -120,3 +126,113 @@ FMC chip and a bigger (64M) SPI chip, use : .. code-block:: bash -M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f + + +Aspeed minibmc family boards (``ast1030-evb``) +================================================================== + +The QEMU Aspeed machines model mini BMCs of various Aspeed evaluation +boards. They are based on different releases of the +Aspeed SoC : the AST1030 integrating an ARM Cortex M4F CPU (200MHz). + +The SoC comes with SRAM, SPI, I2C, etc. + +AST1030 SoC based machines : + +- ``ast1030-evb`` Aspeed AST1030 Evaluation board (Cortex-M4F) + +Supported devices +----------------- + + * SMP (for the AST1030 Cortex-M4F) + * Interrupt Controller (VIC) + * Timer Controller + * I2C Controller + * System Control Unit (SCU) + * SRAM mapping + * Static Memory Controller (SMC or FMC) - Only SPI Flash support + * SPI Memory Controller + * USB 2.0 Controller + * Watchdog Controller + * GPIO Controller (Master only) + * UART + * LPC Peripheral Controller (a subset of subdevices are supported) + * Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA + * ADC + * Secure Boot Controller + * PECI Controller (minimal) + + +Missing devices +--------------- + + * PWM and Fan Controller + * Slave GPIO Controller + * Mailbox Controller + * Virtual UART + * eSPI Controller + * I3C Controller + +Boot options +------------ + +The Aspeed machines can be started using the ``-kernel`` to load a +Zephyr OS or from a firmware. Images can be downloaded from the +ASPEED GitHub release repository : + + https://github.com/AspeedTech-BMC/zephyr/releases + +To boot a kernel directly from a Zephyr build tree: + +.. code-block:: bash + + $ qemu-system-arm -M ast1030-evb -nographic \ + -kernel zephyr.elf + +Facebook Yosemite v3.5 Platform and CraterLake Server (``fby35``) +================================================================== + +Facebook has a series of multi-node compute server designs named +Yosemite. The most recent version released was +`Yosemite v3 `__. + +Yosemite v3.5 is an iteration on this design, and is very similar: there's a +baseboard with a BMC, and 4 server slots. The new server board design termed +"CraterLake" includes a Bridge IC (BIC), with room for expansion boards to +include various compute accelerators (video, inferencing, etc). At the moment, +only the first server slot's BIC is included. + +Yosemite v3.5 is itself a sled which fits into a 40U chassis, and 3 sleds +can be fit into a chassis. See `here `__ +for an example. + +In this generation, the BMC is an AST2600 and each BIC is an AST1030. The BMC +runs `OpenBMC `__, and the BIC runs +`OpenBIC `__. + +Firmware images can be retrieved from the Github releases or built from the +source code, see the README's for instructions on that. This image uses the +"fby35" machine recipe from OpenBMC, and the "yv35-cl" target from OpenBIC. +Some reference images can also be found here: + +.. code-block:: bash + + $ wget https://github.com/facebook/openbmc/releases/download/openbmc-e2294ff5d31d/fby35.mtd + $ wget https://github.com/peterdelevoryas/OpenBIC/releases/download/oby35-cl-2022.13.01/Y35BCL.elf + +Since this machine has multiple SoC's, each with their own serial console, the +recommended way to run it is to allocate a pseudoterminal for each serial +console and let the monitor use stdio. Also, starting in a paused state is +useful because it allows you to attach to the pseudoterminals before the boot +process starts. + +.. code-block:: bash + + $ qemu-system-arm -machine fby35 \ + -drive file=fby35.mtd,format=raw,if=mtd \ + -device loader,file=Y35BCL.elf,addr=0,cpu-num=2 \ + -serial pty -serial pty -serial mon:stdio \ + -display none -S + $ screen /dev/tty0 # In a separate TMUX pane, terminal window, etc. + $ screen /dev/tty1 + $ (qemu) c # Start the boot process once screen is setup. diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index 3e626c4b68af..00c444042ff5 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"). @@ -372,6 +372,31 @@ verbose command lines. However, the recommended way to select vector lengths is to explicitly enable each desired length. Therefore only example's (1), (4), and (6) exhibit recommended uses of the properties. +SME CPU Property Examples +------------------------- + + 1) Disable SME:: + + $ qemu-system-aarch64 -M virt -cpu max,sme=off + + 2) Implicitly enable all vector lengths for the ``max`` CPU type:: + + $ qemu-system-aarch64 -M virt -cpu max + + 3) Only enable the 256-bit vector length:: + + $ qemu-system-aarch64 -M virt -cpu max,sme256=on + + 3) Enable the 256-bit and 1024-bit vector lengths:: + + $ qemu-system-aarch64 -M virt -cpu max,sme256=on,sme1024=on + + 4) Disable the 512-bit vector length. This results in all the other + lengths supported by ``max`` defaulting to enabled + (128, 256, 1024 and 2048):: + + $ qemu-system-aarch64 -M virt -cpu max,sve512=off + SVE User-mode Default Vector Length Property -------------------------------------------- @@ -387,3 +412,34 @@ length supported by QEMU is 256. If this property is set to ``-1`` then the default vector length is set to the maximum possible length. + +SME CPU Properties +================== + +The SME CPU properties are much like the SVE properties: ``sme`` is +used to enable or disable the entire SME feature, and ``sme`` is +used to enable or disable specific vector lengths. Finally, +``sme_fa64`` is used to enable or disable ``FEAT_SME_FA64``, which +allows execution of the "full a64" instruction set while Streaming +SVE mode is enabled. + +SME is not supported by KVM at this time. + +At least one vector length must be enabled when ``sme`` is enabled, +and all vector lengths must be powers of 2. The maximum vector +length supported by qemu is 2048 bits. Otherwise, there are no +additional constraints on the set of vector lengths supported by SME. + +SME User-mode Default Vector Length Property +-------------------------------------------- + +For qemu-aarch64, the cpu property ``sme-default-vector-length=N`` is +defined to mirror the Linux kernel parameter file +``/proc/sys/abi/sme_default_vector_length``. The default length, ``N``, +is in units of bytes and must be between 16 and 8192. +If not specified, the default vector length is 32. + +As with ``sve-default-vector-length``, if the default length is larger +than the maximum vector length enabled, the actual vector length will +be reduced. If this property is set to ``-1`` then the default vector +length is set to the maximum possible length. diff --git a/docs/system/arm/cubieboard.rst b/docs/system/arm/cubieboard.rst index 344ff8cef994..8d485f5435a0 100644 --- a/docs/system/arm/cubieboard.rst +++ b/docs/system/arm/cubieboard.rst @@ -14,3 +14,4 @@ Emulated devices: - SDHCI - USB controller - SATA controller +- TWI (I2C) controller diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 520fd39071e1..b33d7c28dc16 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -9,19 +9,37 @@ the following architecture extensions: - FEAT_AA32HPD (AArch32 hierarchical permission disables) - FEAT_AA32I8MM (AArch32 Int8 matrix multiplication instructions) - FEAT_AES (AESD and AESE instructions) +- FEAT_BBM at level 2 (Translation table break-before-make levels) - FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BTI (Branch Target Identification) +- FEAT_CSV2 (Cache speculation variant 2) +- FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1) +- FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2) +- FEAT_CSV2_2 (Cache speculation variant 2, version 2) +- FEAT_CSV3 (Cache speculation variant 3) +- FEAT_DGH (Data gathering hint) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) +- FEAT_Debugv8p2 (Debug changes for v8.2) +- FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_DotProd (Advanced SIMD dot product instructions) +- FEAT_DoubleFault (Double Fault Extension) +- FEAT_E0PD (Preventing EL0 access to halves of address maps) +- FEAT_ETS (Enhanced Translation Synchronization) +- FEAT_EVT (Enhanced Virtualization Traps) - 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_HAFDBS (Hardware management of the access flag and dirty bit state) +- FEAT_HCX (Support for the HCRX_EL2 register) - FEAT_HPDS (Hierarchical permission disables) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) +- FEAT_IDST (ID space trap handling) +- FEAT_IESB (Implicit error synchronization event) - FEAT_JSCVT (JavaScript conversion instructions) - FEAT_LOR (Limited ordering regions) - FEAT_LPA (Large Physical Address space) @@ -39,8 +57,12 @@ 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) - FEAT_RNG (Random number generator) +- FEAT_S2FWB (Stage 2 forced Write-Back) - FEAT_SB (Speculation Barrier) - FEAT_SEL2 (Secure EL2) - FEAT_SHA1 (SHA1 instructions) @@ -49,11 +71,16 @@ the following architecture extensions: - FEAT_SHA512 (Advanced SIMD SHA512 instructions) - FEAT_SM3 (Advanced SIMD SM3 instructions) - FEAT_SM4 (Advanced SIMD SM4 instructions) +- FEAT_SME (Scalable Matrix Extension) +- FEAT_SME_FA64 (Full A64 instruction set in Streaming SVE mode) +- FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) +- FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - FEAT_SPECRES (Speculation restriction instructions) - FEAT_SSBS (Speculative Store Bypass Safe) - FEAT_TLBIOS (TLB invalidate instructions in Outer Shareable domain) - FEAT_TLBIRANGE (TLB invalidate range instructions) - FEAT_TTCNP (Translation table Common not private translations) +- FEAT_TTL (Translation Table Level) - FEAT_TTST (Small translation tables) - FEAT_UAO (Unprivileged Access Override control) - FEAT_VHE (Virtualization Host Extensions) diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst index ef2792076aa8..c38df32bde07 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/orangepi.rst b/docs/system/arm/orangepi.rst index 83c7445197b3..e5973600a152 100644 --- a/docs/system/arm/orangepi.rst +++ b/docs/system/arm/orangepi.rst @@ -25,6 +25,7 @@ The Orange Pi PC machine supports the following devices: * Clock Control Unit * System Control module * Security Identifier device + * TWI (I2C) Limitations """"""""""" diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst index 508b92cf862b..d7265b763d47 100644 --- a/docs/system/arm/stm32.rst +++ b/docs/system/arm/stm32.rst @@ -20,6 +20,7 @@ The STM32F4 series is based on ARM Cortex-M4F core. This series is pin-to-pin compatible with STM32F2 series. The following machines are based on this chip : - ``netduinoplus2`` Netduino Plus 2 board with STM32F405RGT6 microcontroller +- ``olimex-stm32-h405`` Olimex STM32 H405 board with STM32F405RGT6 microcontroller There are many other STM32 series that are currently not supported by QEMU. diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 1544632b6743..1cab33f02e34 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -52,11 +52,15 @@ Supported guest CPU types: - ``cortex-a7`` (32-bit) - ``cortex-a15`` (32-bit; the default) +- ``cortex-a35`` (64-bit) - ``cortex-a53`` (64-bit) +- ``cortex-a55`` (64-bit) - ``cortex-a57`` (64-bit) - ``cortex-a72`` (64-bit) +- ``cortex-a76`` (64-bit) - ``a64fx`` (64-bit) - ``host`` (with KVM only) +- ``neoverse-n1`` (64-bit) - ``max`` (same as ``host`` for KVM; best possible emulation with TCG) Note that the default is ``cortex-a15``, so for an AArch64 guest you must @@ -91,19 +95,39 @@ highmem address space above 32 bits. The default is ``on`` for machine types later than ``virt-2.12``. +compact-highmem + Set ``on``/``off`` to enable/disable the compact layout for high memory regions. + The default is ``on`` for machine types later than ``virt-7.2``. + +highmem-redists + Set ``on``/``off`` to enable/disable the high memory region for GICv3 or + GICv4 redistributor. The default is ``on``. Setting this to ``off`` will + limit the maximum number of CPUs when GICv3 or GICv4 is used. + +highmem-ecam + Set ``on``/``off`` to enable/disable the high memory region for PCI ECAM. + The default is ``on`` for machine types later than ``virt-3.0``. + +highmem-mmio + Set ``on``/``off`` to enable/disable the high memory region for PCI MMIO. + The default is ``on``. + gic-version Specify the version of the Generic Interrupt Controller (GIC) to provide. Valid values are: ``2`` - GICv2 + GICv2. Note that this limits the number of CPUs to 8. ``3`` - GICv3 + GICv3. This allows up to 512 CPUs. + ``4`` + GICv4. Requires ``virtualization`` to be ``on``; allows up to 317 CPUs. ``host`` Use the same GIC version the host provides, when using KVM ``max`` Use the best GIC version possible (same as host when using KVM; - currently same as ``3``` for TCG, but this may change in future) + with TCG this is currently ``3`` if ``virtualization`` is ``off`` and + ``4`` if ``virtualization`` is ``on``, but this may change in future) its Set ``on``/``off`` to enable/disable ITS instantiation. The default is ``on`` @@ -121,13 +145,18 @@ ras Set ``on``/``off`` to enable/disable reporting host memory errors to a guest using ACPI and guest external abort exceptions. The default is off. +dtb-randomness + Set ``on``/``off`` to pass random seeds via the guest DTB + rng-seed and kaslr-seed nodes (in both "/chosen" and + "/secure-chosen") to use for features like the random number + generator and address space randomisation. The default is + ``on``. You will want to disable it if your trusted boot chain + will verify the DTB it is passed, since this option causes the + DTB to be non-deterministic. It would be the responsibility of + the firmware to come up with a seed and pass it on if it wants to. + dtb-kaslr-seed - Set ``on``/``off`` to pass a random seed via the guest dtb - kaslr-seed node (in both "/chosen" and /secure-chosen) to use - for features like address space randomisation. The default is - ``on``. You will want to disable it if your trusted boot chain will - verify the DTB it is passed. It would be the responsibility of the - firmware to come up with a seed and pass it on if it wants to. + A deprecated synonym for dtb-randomness. Linux guest kernel configuration """""""""""""""""""""""""""""""" diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst index 0b3a3d73ad1f..05060060563f 100644 --- a/docs/system/device-emulation.rst +++ b/docs/system/device-emulation.rst @@ -83,6 +83,8 @@ Emulated Devices :maxdepth: 1 devices/can.rst + devices/ccid.rst + devices/cxl.rst devices/ivshmem.rst devices/net.rst devices/nvme.rst @@ -90,3 +92,4 @@ Emulated Devices devices/vhost-user.rst devices/virtio-pmem.rst devices/vhost-user-rng.rst + devices/canokey.rst diff --git a/docs/system/devices/can.rst b/docs/system/devices/can.rst index fe37af822372..0af3d9912a69 100644 --- a/docs/system/devices/can.rst +++ b/docs/system/devices/can.rst @@ -169,8 +169,9 @@ and with bitrate switch:: cangen can0 -b -The test can be run viceversa, generate messages in the guest system and capture them -in the host one and much more combinations. +The test can also be run the other way around, generating messages in the +guest system and capturing them in the host system. Other combinations are +also possible. Links to other resources ------------------------ diff --git a/docs/system/devices/canokey.rst b/docs/system/devices/canokey.rst new file mode 100644 index 000000000000..cfa6186e483d --- /dev/null +++ b/docs/system/devices/canokey.rst @@ -0,0 +1,158 @@ +.. _canokey: + +CanoKey QEMU +------------ + +CanoKey [1]_ is an open-source secure key with supports of + +* U2F / FIDO2 with Ed25519 and HMAC-secret +* OpenPGP Card V3.4 with RSA4096, Ed25519 and more [2]_ +* PIV (NIST SP 800-73-4) +* HOTP / TOTP +* NDEF + +All these platform-independent features are in canokey-core [3]_. + +For different platforms, CanoKey has different implementations, +including both hardware implementions and virtual cards: + +* CanoKey STM32 [4]_ +* CanoKey Pigeon [5]_ +* (virt-card) CanoKey USB/IP +* (virt-card) CanoKey FunctionFS + +In QEMU, yet another CanoKey virt-card is implemented. +CanoKey QEMU exposes itself as a USB device to the guest OS. + +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 debugging: + +* 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 + and key can be captured and analysed + +Then for developers: + +* For developers on software with secure key support (e.g. FIDO2, OpenPGP), + they can see what happens inside the secure key +* For secure key developers, USB packets between guest OS and CanoKey + can be easily captured and analysed + +Also since this is a virtual card, it can be easily used in CI for testing +on code coping with secure key. + +Building +======== + +libcanokey-qemu is required to use CanoKey QEMU. + +.. code-block:: shell + + git clone https://github.com/canokeys/canokey-qemu + mkdir canokey-qemu/build + pushd canokey-qemu/build + +If you want to install libcanokey-qemu in a different place, +add ``-DCMAKE_INSTALL_PREFIX=/path/to/your/place`` to cmake below. + +.. code-block:: shell + + cmake .. + make + make install # may need sudo + popd + +Then configuring and building: + +.. code-block:: shell + + # depending on your env, lib/pkgconfig can be lib64/pkgconfig + export PKG_CONFIG_PATH=/path/to/your/place/lib/pkgconfig:$PKG_CONFIG_PATH + ./configure --enable-canokey && make + +Using CanoKey QEMU +================== + +CanoKey QEMU stores all its data on a file of the host specified by the argument +when invoking qemu. + +.. parsed-literal:: + + |qemu_system| -usb -device canokey,file=$HOME/.canokey-file + +Note: you should keep this file carefully as it may contain your private key! + +The first time when the file is used, it is created and initialized by CanoKey, +afterwards CanoKey QEMU would just read this file. + +After the guest OS boots, you can check that there is a USB device. + +For example, If the guest OS is an Linux machine. You may invoke lsusb +and find CanoKey QEMU there: + +.. code-block:: shell + + $ lsusb + Bus 001 Device 002: ID 20a0:42d4 Clay Logic CanoKey QEMU + +You may setup the key as guided in [6]_. The console for the key is at [7]_. + +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 +of a secure key while the latter provides platform-dependent functions: +USB packet handling. + +If you want to trace what happens inside the secure key, when compiling +libcanokey-qemu, you should add ``-DQEMU_DEBUG_OUTPUT=ON`` in cmake command +line: + +.. code-block:: shell + + cmake .. -DQEMU_DEBUG_OUTPUT=ON + +If you want to trace events happened in canokey.c, use + +.. parsed-literal:: + + |qemu_system| --trace "canokey_*" \\ + -usb -device canokey,file=$HOME/.canokey-file + +If you want to capture USB packets between the guest and the host, you can: + +.. parsed-literal:: + + |qemu_system| -usb -device canokey,file=$HOME/.canokey-file,pcap=key.pcap + +Limitations +=========== + +Currently libcanokey-qemu.so has dozens of global variables as it was originally +designed for embedded systems. Thus one qemu instance can not have +multiple CanoKey QEMU running, namely you can not + +.. parsed-literal:: + + |qemu_system| -usb -device canokey,file=$HOME/.canokey-file \\ + -device canokey,file=$HOME/.canokey-file2 + +Also, there is no lock on canokey-file, thus two CanoKey QEMU instance +can not read one canokey-file at the same time. + +References +========== + +.. [1] ``_ +.. [2] ``_ +.. [3] ``_ +.. [4] ``_ +.. [5] ``_ +.. [6] ``_ +.. [7] ``_ diff --git a/docs/system/devices/ccid.rst b/docs/system/devices/ccid.rst new file mode 100644 index 000000000000..3b8c2ab46a68 --- /dev/null +++ b/docs/system/devices/ccid.rst @@ -0,0 +1,171 @@ +Chip Card Interface Device (CCID) +================================= + +USB CCID device +--------------- +The USB CCID device is a USB device implementing the CCID specification, which +lets one connect smart card readers that implement the same spec. For more +information see the specification:: + + Universal Serial Bus + Device Class: Smart Card + CCID + Specification for + Integrated Circuit(s) Cards Interface Devices + Revision 1.1 + April 22rd, 2005 + +Smartcards are used for authentication, single sign on, decryption in +public/private schemes and digital signatures. A smartcard reader on the client +cannot be used on a guest with simple usb passthrough since it will then not be +available on the client, possibly locking the computer when it is "removed". On +the other hand this device can let you use the smartcard on both the client and +the guest machine. It is also possible to have a completely virtual smart card +reader and smart card (i.e. not backed by a physical device) using this device. + +Building +-------- +The cryptographic functions and access to the physical card is done via the +libcacard library, whose development package must be installed prior to +building QEMU: + +In redhat/fedora:: + + yum install libcacard-devel + +In ubuntu:: + + apt-get install libcacard-dev + +Configuring and building:: + + ./configure --enable-smartcard && make + +Using ccid-card-emulated with hardware +-------------------------------------- +Assuming you have a working smartcard on the host with the current +user, using libcacard, QEMU acts as another client using ccid-card-emulated:: + + qemu -usb -device usb-ccid -device ccid-card-emulated + +Using ccid-card-emulated with certificates stored in files +---------------------------------------------------------- +You must create the CA and card certificates. This is a one time process. +We use NSS certificates:: + + mkdir fake-smartcard + cd fake-smartcard + certutil -N -d sql:$PWD + certutil -S -d sql:$PWD -s "CN=Fake Smart Card CA" -x -t TC,TC,TC -n fake-smartcard-ca + certutil -S -d sql:$PWD -t ,, -s "CN=John Doe" -n id-cert -c fake-smartcard-ca + certutil -S -d sql:$PWD -t ,, -s "CN=John Doe (signing)" --nsCertType smime -n signing-cert -c fake-smartcard-ca + certutil -S -d sql:$PWD -t ,, -s "CN=John Doe (encryption)" --nsCertType sslClient -n encryption-cert -c fake-smartcard-ca + +Note: you must have exactly three certificates. + +You can use the emulated card type with the certificates backend:: + + qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,db=sql:$PWD,cert1=id-cert,cert2=signing-cert,cert3=encryption-cert + +To use the certificates in the guest, export the CA certificate:: + + certutil -L -r -d sql:$PWD -o fake-smartcard-ca.cer -n fake-smartcard-ca + +and import it in the guest:: + + certutil -A -d /etc/pki/nssdb -i fake-smartcard-ca.cer -t TC,TC,TC -n fake-smartcard-ca + +In a Linux guest you can then use the CoolKey PKCS #11 module to access +the card:: + + certutil -d /etc/pki/nssdb -L -h all + +It will prompt you for the PIN (which is the password you assigned to the +certificate database early on), and then show you all three certificates +together with the manually imported CA cert:: + + Certificate Nickname Trust Attributes + fake-smartcard-ca CT,C,C + John Doe:CAC ID Certificate u,u,u + John Doe:CAC Email Signature Certificate u,u,u + John Doe:CAC Email Encryption Certificate u,u,u + +If this does not happen, CoolKey is not installed or not registered with +NSS. Registration can be done from Firefox or the command line:: + + modutil -dbdir /etc/pki/nssdb -add "CAC Module" -libfile /usr/lib64/pkcs11/libcoolkeypk11.so + modutil -dbdir /etc/pki/nssdb -list + +Using ccid-card-passthru with client side hardware +-------------------------------------------------- +On the host specify the ccid-card-passthru device with a suitable chardev:: + + qemu -chardev socket,server=on,host=0.0.0.0,port=2001,id=ccid,wait=off \ + -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid + +On the client run vscclient, built when you built QEMU:: + + vscclient 2001 + +Using ccid-card-passthru with client side certificates +------------------------------------------------------ +This case is not particularly useful, but you can use it to debug +your setup. + +Follow instructions above, except run QEMU and vscclient as follows. + +Run qemu as per above, and run vscclient from the "fake-smartcard" +directory as follows:: + + qemu -chardev socket,server=on,host=0.0.0.0,port=2001,id=ccid,wait=off \ + -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid + vscclient -e "db=\"sql:$PWD\" use_hw=no soft=(,Test,CAC,,id-cert,signing-cert,encryption-cert)" 2001 + + +Passthrough protocol scenario +----------------------------- +This is a typical interchange of messages when using the passthru card device. +usb-ccid is a usb device. It defaults to an unattached usb device on startup. +usb-ccid expects a chardev and expects the protocol defined in +cac_card/vscard_common.h to be passed over that. +The usb-ccid device can be in one of three modes: + +* detached +* attached with no card +* attached with card + +A typical interchange is (the arrow shows who started each exchange, it can be client +originated or guest originated):: + + client event | vscclient | passthru | usb-ccid | guest event + ------------------------------------------------------------------------------------------------ + | VSC_Init | | | + | VSC_ReaderAdd | | attach | + | | | | sees new usb device. + card inserted -> | | | | + | VSC_ATR | insert | insert | see new card + | | | | + | VSC_APDU | VSC_APDU | | <- guest sends APDU + client <-> physical | | | | + card APDU exchange | | | | + client response -> | VSC_APDU | VSC_APDU | | receive APDU response + ... + [APDU<->APDU repeats several times] + ... + card removed -> | | | | + | VSC_CardRemove | remove | remove | card removed + ... + [(card insert, apdu's, card remove) repeat] + ... + kill/quit | | | | + vscclient | | | | + | VSC_ReaderRemove | | detach | + | | | | usb device removed. + +libcacard +--------- +Both ccid-card-emulated and vscclient use libcacard as the card emulator. +libcacard implements a completely virtual CAC (DoD standard for smart +cards) compliant card and uses NSS to retrieve certificates and do +any encryption. The backend can then be a real reader and card, or +certificates stored in files. diff --git a/docs/system/devices/cxl.rst b/docs/system/devices/cxl.rst new file mode 100644 index 000000000000..f25783a4ecf0 --- /dev/null +++ b/docs/system/devices/cxl.rst @@ -0,0 +1,386 @@ +Compute Express Link (CXL) +========================== +From the view of a single host, CXL is an interconnect standard that +targets accelerators and memory devices attached to a CXL host. +This description will focus on those aspects visible either to +software running on a QEMU emulated host or to the internals of +functional emulation. As such, it will skip over many of the +electrical and protocol elements that would be more of interest +for real hardware and will dominate more general introductions to CXL. +It will also completely ignore the fabric management aspects of CXL +by considering only a single host and a static configuration. + +CXL shares many concepts and much of the infrastructure of PCI Express, +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 reflected +in how the devices are emulated in QEMU. In most cases the various +CXL elements are built upon an equivalent PCIe devices. + +CXL devices support the following interfaces: + +* Most conventional PCIe interfaces + + - Configuration space access + - BAR mapped memory accesses used for registers and mailboxes. + - MSI/MSI-X + - AER + - DOE mailboxes + - IDE + - Many other PCI express defined interfaces.. + +* Memory operations + + - Equivalent of accessing DRAM / NVDIMMs. Any access / feature + supported by the host for normal memory should also work for + CXL attached memory devices. + +* Cache operations. The are mostly irrelevant to QEMU emulation as + QEMU is not emulating a coherency protocol. Any emulation related + to these will be device specific and is out of the scope of this + document. + +CXL 2.0 Device Types +-------------------- +CXL 2.0 End Points are often categorized into three types. + +**Type 1:** These support coherent caching of host memory. Example might +be a crypto accelerators. May also have device private memory accessible +via means such as PCI memory reads and writes to BARs. + +**Type 2:** These support coherent caching of host memory and host +managed device memory (HDM) for which the coherency protocol is managed +by the host. This is a complex topic, so for more information on CXL +coherency see the CXL 2.0 specification. + +**Type 3 Memory devices:** These devices act as a means of attaching +additional memory (HDM) to a CXL host including both volatile and +persistent memory. The CXL topology may support interleaving across a +number of Type 3 memory devices using HDM Decoders in the host, host +bridge, switch upstream port and endpoints. + +Scope of CXL emulation in QEMU +------------------------------ +The focus of CXL emulation is CXL revision 2.0 and later. Earlier CXL +revisions defined a smaller set of features, leaving much of the control +interface as implementation defined or device specific, making generic +emulation challenging with host specific firmware being responsible +for setup and the Endpoints being presented to operating systems +as Root Complex Integrated End Points. CXL rev 2.0 looks a lot +more like PCI Express, with fully specified discoverability +of the CXL topology. + +CXL System components +---------------------- +A CXL system is made up a Host with a number of 'standard components' +the control and capabilities of which are discoverable by system software +using means described in the CXL 2.0 specification. + +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 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 +the CXL Early Discovery Table, an ACPI table. + +Note: QTG 0 is the only one currently supported in QEMU. + +CXL Host Bridge (CXL HB) +~~~~~~~~~~~~~~~~~~~~~~~~ +A CXL host bridge is similar to the PCIe equivalent, but with a +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 hierarchy +as CXL Component Registers in PCI BARs. + +Interfaces provided include: + +* Configuration of HDM Decoders to route CXL Memory accesses with + a particularly Host Physical Address range to the target port + below which the CXL device servicing that address lies. This + may be a mapping to a single Root Port (RP) or across a set of + target RPs. + +CXL Root Ports (CXL RP) +~~~~~~~~~~~~~~~~~~~~~~~ +A CXL Root Port servers te same purpose as a PCIe Root Port. +There are a number of CXL specific Designated Vendor Specific +Extended Capabilities (DVSEC) in PCIe Configuration Space +and associated component register access via PCI bars. + +CXL Switch +~~~~~~~~~~ +Here we consider a simple CXL switch with only a single +virtual hierarchy. Whilst more complex devices exist, their +visibility to a particular host is generally the same as for +a simple switch design. Hosts often have no awareness +of complex rerouting and device pooling, they simply see +devices being hot added or hot removed. + +A CXL switch has a similar architecture to those in PCIe, +with a single upstream port, internal PCI bus and multiple +downstream ports. + +Both the CXL upstream and downstream ports have CXL specific +DVSECs in configuration space, and component registers in PCI +BARs. The Upstream Port has the configuration interfaces for +the HDM decoders which route incoming memory accesses to the +appropriate downstream port. + +A CXL switch is created in a similar fashion to PCI switches +by creating an upstream port (cxl-upstream) and a number of +downstream ports on the internal switch bus (cxl-downstream). + +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 responsible not for +routing but for translation of the incoming host physical address (HPA) +into a Device Physical Address (DPA). + +CXL Memory Interleave +--------------------- +To understand the interaction of different CXL hardware components which +are emulated in QEMU, let us consider a memory read in a fully configured +CXL topology. Note that system software is responsible for configuration +of all components with the exception of the CFMWs. System software is +responsible for allocating appropriate ranges from within the CFMWs +and exposing those via normal memory configurations as would be done +for system RAM. + +Example system Topology. x marks the match in each decoder level:: + + |<------------------SYSTEM PHYSICAL ADDRESS MAP (1)----------------->| + | __________ __________________________________ __________ | + | | | | | | | | + | | CFMW 0 | | CXL Fixed Memory Window 1 | | CFMW 1 | | + | | HB0 only | | Configured to interleave memory | | HB1 only | | + | | | | memory accesses across HB0/HB1 | | | | + | |__________| |_____x____________________________| |__________| | + | | | | + | | | | + | | | | + | Interleave Decoder | | + | Matches this HB | | + \_____________| |_____________/ + __________|__________ _____|_______________ + | | | | + (2) | CXL HB 0 | | CXL HB 1 | + | HB IntLv Decoders | | HB IntLv Decoders | + | PCI/CXL Root Bus 0c | | PCI/CXL Root Bus 0d | + | | | | + |___x_________________| |_____________________| + | | | | + | | | | + A HB 0 HDM Decoder | | | + matches this Port | | | + | | | | + ___________|___ __________|__ __|_________ ___|_________ + (3)| Root Port 0 | | Root Port 1 | | Root Port 2| | Root Port 3 | + | Appears in | | Appears in | | Appears in | | Appear in | + | PCI topology | | PCI Topology| | PCI Topo | | PCI Topo | + | As 0c:00.0 | | as 0c:01.0 | | as de:00.0 | | as de:01.0 | + |_______________| |_____________| |____________| |_____________| + | | | | + | | | | + _____|_________ ______|______ ______|_____ ______|_______ + (4)| x | | | | | | | + | CXL Type3 0 | | CXL Type3 1 | | CXL type3 2| | CLX Type 3 3 | + | | | | | | | | + | PMEM0(Vol LSA)| | PMEM1 (...) | | PMEM2 (...)| | PMEM3 (...) | + | Decoder to go | | | | | | | + | from host PA | | PCI 0e:00.0 | | PCI df:00.0| | PCI e0:00.0 | + | to device PA | | | | | | | + | PCI as 0d:00.0| | | | | | | + |_______________| |_____________| |____________| |______________| + +Notes: + +(1) **3 CXL Fixed Memory Windows (CFMW)** corresponding to different + 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 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 + programmable HDM decoders to route memory accesses either to + a single port or interleave them across multiple ports. + A complex configuration here, might be to use the following HDM + decoders in HB0. HDM0 routes CFMW0 requests to RP0 and hence + part of CXL Type3 0. HDM1 routes CFMW0 requests from a + different region of the CFMW0 PA range to RP2 and hence part + of CXL Type 3 1. HDM2 routes yet another PA range from within + CFMW0 to be interleaved across RP0 and RP1, providing 2 way + interleave of part of the memory provided by CXL Type3 0 and + CXL Type 3 1. HDM3 routes those interleaved accesses from + CFMW1 that target HB0 to RP 0 and another part of the memory of + CXL Type 3 0 (as part of a 2 way interleave at the system level + across for example CXL Type3 0 and CXL Type3 2. + HDM4 is used to enable system wide 4 way interleave across all + the present CXL type3 devices, by interleaving those (interleaved) + requests that HB0 receives from from CFMW1 across RP 0 and + RP 1 and hence to yet more regions of the memory of the + attached Type3 devices. Note this is a representative subset + of the full range of possible HDM decoder configurations in this + topology. + +(3) **Four CXL Root Ports.** In this case the CXL Type 3 devices are + directly attached to these ports. + +(4) **Four CXL Type3 memory expansion devices.** These will each have + HDM decoders, but in this case rather than performing interleave + they will take the Host Physical Addresses of accesses and map + them to their own local Device Physical Address Space (DPA). + +Example topology involving a switch:: + + |<------------------SYSTEM PHYSICAL ADDRESS MAP (1)----------------->| + | __________ __________________________________ __________ | + | | | | | | | | + | | CFMW 0 | | CXL Fixed Memory Window 1 | | CFMW 1 | | + | | HB0 only | | Configured to interleave memory | | HB1 only | | + | | | | memory accesses across HB0/HB1 | | | | + | |____x_____| |__________________________________| |__________| | + | | | | + | | | | + | | | + Interleave Decoder | | | + Matches this HB | | | + \_____________| |_____________/ + __________|__________ _____|_______________ + | | | | + | CXL HB 0 | | CXL HB 1 | + | HB IntLv Decoders | | HB IntLv Decoders | + | PCI/CXL Root Bus 0c | | PCI/CXL Root Bus 0d | + | | | | + |___x_________________| |_____________________| + | | | | + | + A HB 0 HDM Decoder + matches this Port + ___________|___ + | Root Port 0 | + | Appears in | + | PCI topology | + | As 0c:00.0 | + |___________x___| + | + | + \_____________________ + | + | + --------------------------------------------------- + | Switch 0 USP as PCI 0d:00.0 | + | USP has HDM decoder which direct traffic to | + | appropriate downstream port | + | Switch BUS appears as 0e | + |x__________________________________________________| + | | | | + | | | | + _____|_________ ______|______ ______|_____ ______|_______ + (4)| x | | | | | | | + | CXL Type3 0 | | CXL Type3 1 | | CXL type3 2| | CLX Type 3 3 | + | | | | | | | | + | PMEM0(Vol LSA)| | PMEM1 (...) | | PMEM2 (...)| | PMEM3 (...) | + | Decoder to go | | | | | | | + | from host PA | | PCI 10:00.0 | | PCI 11:00.0| | PCI 12:00.0 | + | to device PA | | | | | | | + | PCI as 0f:00.0| | | | | | | + |_______________| |_____________| |____________| |______________| + +Example command lines +--------------------- +A very simple setup with just one directly attached CXL Type 3 device:: + + qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \ + ... + -object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \ + -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ + -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \ + -device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \ + -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G + +A setup suitable for 4 way interleave. Only one fixed window provided, to enable 2 way +interleave across 2 CXL host bridges. Each host bridge has 2 CXL Root Ports, with +the CXL Type3 device directly attached (no switches).:: + + qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \ + ... + -object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest.raw,size=256M \ + -object memory-backend-file,id=cxl-mem2,share=on,mem-path=/tmp/cxltest2.raw,size=256M \ + -object memory-backend-file,id=cxl-mem3,share=on,mem-path=/tmp/cxltest3.raw,size=256M \ + -object memory-backend-file,id=cxl-mem4,share=on,mem-path=/tmp/cxltest4.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa2,share=on,mem-path=/tmp/lsa2.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa3,share=on,mem-path=/tmp/lsa3.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa4,share=on,mem-path=/tmp/lsa4.raw,size=256M \ + -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ + -device pxb-cxl,bus_nr=222,bus=pcie.0,id=cxl.2 \ + -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \ + -device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \ + -device cxl-rp,port=1,bus=cxl.1,id=root_port14,chassis=0,slot=3 \ + -device cxl-type3,bus=root_port14,memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem1 \ + -device cxl-rp,port=0,bus=cxl.2,id=root_port15,chassis=0,slot=5 \ + -device cxl-type3,bus=root_port15,memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem2 \ + -device cxl-rp,port=1,bus=cxl.2,id=root_port16,chassis=0,slot=6 \ + -device cxl-type3,bus=root_port16,memdev=cxl-mem4,lsa=cxl-lsa4,id=cxl-pmem3 \ + -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.targets.1=cxl.2,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=8k + +An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave:: + + qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \ + ... + -object memory-backend-file,id=cxl-mem0,share=on,mem-path=/tmp/cxltest.raw,size=256M \ + -object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest1.raw,size=256M \ + -object memory-backend-file,id=cxl-mem2,share=on,mem-path=/tmp/cxltest2.raw,size=256M \ + -object memory-backend-file,id=cxl-mem3,share=on,mem-path=/tmp/cxltest3.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa0,share=on,mem-path=/tmp/lsa0.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa1.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa2,share=on,mem-path=/tmp/lsa2.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa3,share=on,mem-path=/tmp/lsa3.raw,size=256M \ + -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ + -device cxl-rp,port=0,bus=cxl.1,id=root_port0,chassis=0,slot=0 \ + -device cxl-rp,port=1,bus=cxl.1,id=root_port1,chassis=0,slot=1 \ + -device cxl-upstream,bus=root_port0,id=us0 \ + -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \ + -device cxl-type3,bus=swport0,memdev=cxl-mem0,lsa=cxl-lsa0,id=cxl-pmem0,size=256M \ + -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \ + -device cxl-type3,bus=swport1,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem1,size=256M \ + -device cxl-downstream,port=2,bus=us0,id=swport2,chassis=0,slot=6 \ + -device cxl-type3,bus=swport2,memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem2,size=256M \ + -device cxl-downstream,port=3,bus=us0,id=swport3,chassis=0,slot=7 \ + -device cxl-type3,bus=swport3,memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem3,size=256M \ + -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k + +Kernel Configuration Options +---------------------------- + +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 +* CONFIG_CXL_PCI +* CONFIG_CXL_ACPI +* CONFIG_CXL_PMEM +* CONFIG_CXL_MEM +* CONFIG_CXL_PORT +* CONFIG_CXL_REGION + +References +---------- + + - Consortium website for specifications etc: + http://www.computeexpresslink.org + - Compute Express link Revision 2 specification, October 2020 + - CEDT CFMWS & QTG _DSM ECN May 2021 diff --git a/docs/system/devices/nvme.rst b/docs/system/devices/nvme.rst index b5acb2a9c19d..30f841ef6222 100644 --- a/docs/system/devices/nvme.rst +++ b/docs/system/devices/nvme.rst @@ -104,8 +104,8 @@ multipath I/O. .. code-block:: console -device nvme-subsys,id=nvme-subsys-0,nqn=subsys0 - -device nvme,serial=a,subsys=nvme-subsys-0 - -device nvme,serial=b,subsys=nvme-subsys-0 + -device nvme,serial=deadbeef,subsys=nvme-subsys-0 + -device nvme,serial=deadbeef,subsys=nvme-subsys-0 This will create an NVM subsystem with two controllers. Having controllers linked to an ``nvme-subsys`` device allows additional ``nvme-ns`` parameters: @@ -239,3 +239,85 @@ The virtual namespace device supports DIF- and DIX-based protection information to ``1`` to transfer protection information as the first eight bytes of metadata. Otherwise, the protection information is transferred as the last eight bytes. + +Virtualization Enhancements and SR-IOV (Experimental Support) +------------------------------------------------------------- + +The ``nvme`` device supports Single Root I/O Virtualization and Sharing +along with Virtualization Enhancements. The controller has to be linked to +an NVM Subsystem device (``nvme-subsys``) for use with SR-IOV. + +A number of parameters are present (**please note, that they may be +subject to change**): + +``sriov_max_vfs`` (default: ``0``) + Indicates the maximum number of PCIe virtual functions supported + by the controller. Specifying a non-zero value enables reporting of both + SR-IOV and ARI (Alternative Routing-ID Interpretation) capabilities + by the NVMe device. Virtual function controllers will not report SR-IOV. + +``sriov_vq_flexible`` + Indicates the total number of flexible queue resources assignable to all + the secondary controllers. Implicitly sets the number of primary + controller's private resources to ``(max_ioqpairs - sriov_vq_flexible)``. + +``sriov_vi_flexible`` + Indicates the total number of flexible interrupt resources assignable to + all the secondary controllers. Implicitly sets the number of primary + controller's private resources to ``(msix_qsize - sriov_vi_flexible)``. + +``sriov_max_vi_per_vf`` (default: ``0``) + Indicates the maximum number of virtual interrupt resources assignable + to a secondary controller. The default ``0`` resolves to + ``(sriov_vi_flexible / sriov_max_vfs)`` + +``sriov_max_vq_per_vf`` (default: ``0``) + Indicates the maximum number of virtual queue resources assignable to + a secondary controller. The default ``0`` resolves to + ``(sriov_vq_flexible / sriov_max_vfs)`` + +The simplest possible invocation enables the capability to set up one VF +controller and assign an admin queue, an IO queue, and a MSI-X interrupt. + +.. code-block:: console + + -device nvme-subsys,id=subsys0 + -device nvme,serial=deadbeef,subsys=subsys0,sriov_max_vfs=1, + sriov_vq_flexible=2,sriov_vi_flexible=1 + +The minimum steps required to configure a functional NVMe secondary +controller are: + + * unbind flexible resources from the primary controller + +.. code-block:: console + + nvme virt-mgmt /dev/nvme0 -c 0 -r 1 -a 1 -n 0 + nvme virt-mgmt /dev/nvme0 -c 0 -r 0 -a 1 -n 0 + + * perform a Function Level Reset on the primary controller to actually + release the resources + +.. code-block:: console + + echo 1 > /sys/bus/pci/devices/0000:01:00.0/reset + + * enable VF + +.. code-block:: console + + echo 1 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs + + * assign the flexible resources to the VF and set it ONLINE + +.. code-block:: console + + nvme virt-mgmt /dev/nvme0 -c 1 -r 1 -a 8 -n 1 + nvme virt-mgmt /dev/nvme0 -c 1 -r 0 -a 8 -n 2 + nvme virt-mgmt /dev/nvme0 -c 1 -r 0 -a 9 -n 0 + + * bind the NVMe driver to the VF + +.. code-block:: console + + echo 0000:01:00.1 > /sys/bus/pci/drivers/nvme/bind \ No newline at end of file diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst index afb7d6c2268d..37cb9b33aea4 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 @@ -199,6 +211,10 @@ option or the ``device_add`` monitor command. Available devices are: ``u2f-{emulated,passthru}`` Universal Second Factor device +``canokey`` + An Open-source Secure Key implementing FIDO2, OpenPGP, PIV and more. + For more information, see :ref:`canokey`. + Physical port addressing ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,3 +365,44 @@ and also assign it to the correct USB bus in QEMU like this: -device usb-ehci,id=ehci \\ -device usb-host,bus=usb-bus.0,hostbus=3,hostport=1 \\ -device usb-host,bus=ehci.0,hostbus=1,hostport=1 + +``usb-host`` properties for reset behavior +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``guest-reset`` and ``guest-reset-all`` properties control +whenever the guest is allowed to reset the physical usb device on the +host. There are three cases: + +``guest-reset=false`` + The guest is not allowed to reset the (physical) usb device. + +``guest-reset=true,guest-resets-all=false`` + The guest is allowed to reset the device when it is not yet + initialized (aka no usb bus address assigned). Usually this results + in one guest reset being allowed. This is the default behavior. + +``guest-reset=true,guest-resets-all=true`` + The guest is allowed to reset the device as it pleases. + +The reason for this existing are broken usb devices. In theory one +should be able to reset (and re-initialize) usb devices at any time. +In practice that may result in shitty usb device firmware crashing and +the device not responding any more until you power-cycle (aka un-plug +and re-plug) it. + +What works best pretty much depends on the behavior of the specific +usb device at hand, so it's a trial-and-error game. If the default +doesn't work, try another option and see whenever the situation +improves. + +record usb transfers +^^^^^^^^^^^^^^^^^^^^ + +All usb devices have support for recording the usb traffic. This can +be enabled using the ``pcap=`` property, for example: + +``-device usb-mouse,pcap=mouse.pcap`` + +The pcap files are compatible with the linux kernels usbmon. Many +tools, including ``wireshark``, can decode and inspect these trace +files. diff --git a/docs/system/i386/hyperv.rst b/docs/system/i386/hyperv.rst new file mode 100644 index 000000000000..2505dc4c86e0 --- /dev/null +++ b/docs/system/i386/hyperv.rst @@ -0,0 +1,288 @@ +Hyper-V Enlightenments +====================== + + +Description +----------- + +In some cases when implementing a hardware interface in software is slow, KVM +implements its own paravirtualized interfaces. This works well for Linux as +guest support for such features is added simultaneously with the feature itself. +It may, however, be hard-to-impossible to add support for these interfaces to +proprietary OSes, namely, Microsoft Windows. + +KVM on x86 implements Hyper-V Enlightenments for Windows guests. These features +make Windows and Hyper-V guests think they're running on top of a Hyper-V +compatible hypervisor and use Hyper-V specific features. + + +Setup +----- + +No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In +QEMU, individual enlightenments can be enabled through CPU flags, e.g: + +.. parsed-literal:: + + |qemu_system| --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ... + +Sometimes there are dependencies between enlightenments, QEMU is supposed to +check that the supplied configuration is sane. + +When any set of the Hyper-V enlightenments is enabled, QEMU changes hypervisor +identification (CPUID 0x40000000..0x4000000A) to Hyper-V. KVM identification +and features are kept in leaves 0x40000100..0x40000101. + + +Existing enlightenments +----------------------- + +``hv-relaxed`` + This feature tells guest OS to disable watchdog timeouts as it is running on a + hypervisor. It is known that some Windows versions will do this even when they + see 'hypervisor' CPU flag. + +``hv-vapic`` + Provides so-called VP Assist page MSR to guest allowing it to work with APIC + more efficiently. In particular, this enlightenment allows paravirtualized + (exit-less) EOI processing. + +``hv-spinlocks`` = xxx + Enables paravirtualized spinlocks. The parameter indicates how many times + spinlock acquisition should be attempted before indicating the situation to the + hypervisor. A special value 0xffffffff indicates "never notify". + +``hv-vpindex`` + Provides HV_X64_MSR_VP_INDEX (0x40000002) MSR to the guest which has Virtual + processor index information. This enlightenment makes sense in conjunction with + hv-synic, hv-stimer and other enlightenments which require the guest to know its + Virtual Processor indices (e.g. when VP index needs to be passed in a + hypercall). + +``hv-runtime`` + Provides HV_X64_MSR_VP_RUNTIME (0x40000010) MSR to the guest. The MSR keeps the + virtual processor run time in 100ns units. This gives guest operating system an + idea of how much time was 'stolen' from it (when the virtual CPU was preempted + to perform some other work). + +``hv-crash`` + Provides HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 (0x40000100..0x40000105) and + HV_X64_MSR_CRASH_CTL (0x40000105) MSRs to the guest. These MSRs are written to + by the guest when it crashes, HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 MSRs + contain additional crash information. This information is outputted in QEMU log + and through QAPI. + Note: unlike under genuine Hyper-V, write to HV_X64_MSR_CRASH_CTL causes guest + to shutdown. This effectively blocks crash dump generation by Windows. + +``hv-time`` + Enables two Hyper-V-specific clocksources available to the guest: MSR-based + Hyper-V clocksource (HV_X64_MSR_TIME_REF_COUNT, 0x40000020) and Reference TSC + page (enabled via MSR HV_X64_MSR_REFERENCE_TSC, 0x40000021). Both clocksources + are per-guest, Reference TSC page clocksource allows for exit-less time stamp + readings. Using this enlightenment leads to significant speedup of all timestamp + related operations. + +``hv-synic`` + Enables Hyper-V Synthetic interrupt controller - an extension of a local APIC. + When enabled, this enlightenment provides additional communication facilities + to the guest: SynIC messages and Events. This is a pre-requisite for + implementing VMBus devices (not yet in QEMU). Additionally, this enlightenment + is needed to enable Hyper-V synthetic timers. SynIC is controlled through MSRs + HV_X64_MSR_SCONTROL..HV_X64_MSR_EOM (0x40000080..0x40000084) and + HV_X64_MSR_SINT0..HV_X64_MSR_SINT15 (0x40000090..0x4000009F) + + Requires: ``hv-vpindex`` + +``hv-stimer`` + Enables Hyper-V synthetic timers. There are four synthetic timers per virtual + CPU controlled through HV_X64_MSR_STIMER0_CONFIG..HV_X64_MSR_STIMER3_COUNT + (0x400000B0..0x400000B7) MSRs. These timers can work either in single-shot or + periodic mode. It is known that certain Windows versions revert to using HPET + (or even RTC when HPET is unavailable) extensively when this enlightenment is + not provided; this can lead to significant CPU consumption, even when virtual + CPU is idle. + + Requires: ``hv-vpindex``, ``hv-synic``, ``hv-time`` + +``hv-tlbflush`` + Enables paravirtualized TLB shoot-down mechanism. On x86 architecture, remote + TLB flush procedure requires sending IPIs and waiting for other CPUs to perform + local TLB flush. In virtualized environment some virtual CPUs may not even be + scheduled at the time of the call and may not require flushing (or, flushing + may be postponed until the virtual CPU is scheduled). hv-tlbflush enlightenment + implements TLB shoot-down through hypervisor enabling the optimization. + + Requires: ``hv-vpindex`` + +``hv-ipi`` + Enables paravirtualized IPI send mechanism. HvCallSendSyntheticClusterIpi + hypercall may target more than 64 virtual CPUs simultaneously, doing the same + through APIC requires more than one access (and thus exit to the hypervisor). + + Requires: ``hv-vpindex`` + +``hv-vendor-id`` = xxx + This changes Hyper-V identification in CPUID 0x40000000.EBX-EDX from the default + "Microsoft Hv". The parameter should be no longer than 12 characters. According + to the specification, guests shouldn't use this information and it is unknown + if there is a Windows version which acts differently. + Note: hv-vendor-id is not an enlightenment and thus doesn't enable Hyper-V + identification when specified without some other enlightenment. + +``hv-reset`` + Provides HV_X64_MSR_RESET (0x40000003) MSR to the guest allowing it to reset + itself by writing to it. Even when this MSR is enabled, it is not a recommended + way for Windows to perform system reboot and thus it may not be used. + +``hv-frequencies`` + Provides HV_X64_MSR_TSC_FREQUENCY (0x40000022) and HV_X64_MSR_APIC_FREQUENCY + (0x40000023) allowing the guest to get its TSC/APIC frequencies without doing + measurements. + +``hv-reenlightenment`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it provides HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106), + HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)and HV_X64_MSR_TSC_EMULATION_STATUS + (0x40000108) MSRs allowing the guest to get notified when TSC frequency changes + (only happens on migration) and keep using old frequency (through emulation in + the hypervisor) until it is ready to switch to the new one. This, in conjunction + with ``hv-frequencies``, allows Hyper-V on KVM to pass stable clocksource + (Reference TSC page) to its own guests. + + Note, KVM doesn't fully support re-enlightenment notifications and doesn't + emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to + be specified to make migration succeed. The destination host has to either have + the same TSC frequency or support TSC scaling CPU feature. + + Recommended: ``hv-frequencies`` + +``hv-evmcs`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature + implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) + hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. + + Note: some virtualization features (e.g. Posted Interrupts) are disabled when + hv-evmcs is enabled. It may make sense to measure your nested workload with and + without the feature to find out if enabling it is beneficial. + + Requires: ``hv-vapic`` + +``hv-stimer-direct`` + Hyper-V specification allows synthetic timer operation in two modes: "classic", + when expiration event is delivered as SynIC message and "direct", when the event + is delivered via normal interrupt. It is known that nested Hyper-V can only + use synthetic timers in direct mode and thus ``hv-stimer-direct`` needs to be + enabled. + + Requires: ``hv-vpindex``, ``hv-synic``, ``hv-time``, ``hv-stimer`` + +``hv-avic`` (``hv-apicv``) + The enlightenment allows to use Hyper-V SynIC with hardware APICv/AVIC enabled. + Normally, Hyper-V SynIC disables these hardware feature and suggests the guest + to use paravirtualized AutoEOI feature. + Note: enabling this feature on old hardware (without APICv/AVIC support) may + have negative effect on guest's performance. + +``hv-no-nonarch-coresharing`` = on/off/auto + This enlightenment tells guest OS that virtual processors will never share a + physical core unless they are reported as sibling SMT threads. This information + is required by Windows and Hyper-V guests to properly mitigate SMT related CPU + vulnerabilities. + + When the option is set to 'auto' QEMU will enable the feature only when KVM + reports that non-architectural coresharing is impossible, this means that + hyper-threading is not supported or completely disabled on the host. This + setting also prevents migration as SMT settings on the destination may differ. + When the option is set to 'on' QEMU will always enable the feature, regardless + of host setup. To keep guests secure, this can only be used in conjunction with + exposing correct vCPU topology and vCPU pinning. + +``hv-version-id-build``, ``hv-version-id-major``, ``hv-version-id-minor``, ``hv-version-id-spack``, ``hv-version-id-sbranch``, ``hv-version-id-snumber`` + This changes Hyper-V version identification in CPUID 0x40000002.EAX-EDX from the + default (WS2016). + + - ``hv-version-id-build`` sets 'Build Number' (32 bits) + - ``hv-version-id-major`` sets 'Major Version' (16 bits) + - ``hv-version-id-minor`` sets 'Minor Version' (16 bits) + - ``hv-version-id-spack`` sets 'Service Pack' (32 bits) + - ``hv-version-id-sbranch`` sets 'Service Branch' (8 bits) + - ``hv-version-id-snumber`` sets 'Service Number' (24 bits) + + Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V + identification when specified without any other enlightenments. + +``hv-syndbg`` + Enables Hyper-V synthetic debugger interface, this is a special interface used + by Windows Kernel debugger to send the packets through, rather than sending + them via serial/network . + When enabled, this enlightenment provides additional communication facilities + to the guest: SynDbg messages. + This new communication is used by Windows Kernel debugger rather than sending + packets via serial/network, adding significant performance boost over the other + comm channels. + This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15). + + Requires: ``hv-relaxed``, ``hv_time``, ``hv-vapic``, ``hv-vpindex``, ``hv-synic``, ``hv-runtime``, ``hv-stimer`` + +``hv-emsr-bitmap`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to + avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is + supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires + Enlightened VMCS (``hv-evmcs``) feature to also be enabled. + + Recommended: ``hv-evmcs`` (Intel) + +``hv-xmm-input`` + Hyper-V specification allows to pass parameters for certain hypercalls using XMM + registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows + for faster hypercalls processing as KVM can avoid reading guest's memory. + +``hv-tlbflush-ext`` + Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls + (HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). + + Requires: ``hv-tlbflush`` + +``hv-tlbflush-direct`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 + guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is + supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires + Enlightened VMCS (``hv-evmcs``) feature to also be enabled. + + Requires: ``hv-vapic`` + + Recommended: ``hv-evmcs`` (Intel) + +Supplementary features +---------------------- + +``hv-passthrough`` + In some cases (e.g. during development) it may make sense to use QEMU in + 'pass-through' mode and give Windows guests all enlightenments currently + supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU + flag. + + Note: ``hv-passthrough`` flag only enables enlightenments which are known to QEMU + (have corresponding 'hv-' flag) and copies ``hv-spinlocks`` and ``hv-vendor-id`` + values from KVM to QEMU. ``hv-passthrough`` overrides all other 'hv-' settings on + the command line. Also, enabling this flag effectively prevents migration as the + list of enabled enlightenments may differ between target and destination hosts. + +``hv-enforce-cpuid`` + By default, KVM allows the guest to use all currently supported Hyper-V + enlightenments when Hyper-V CPUID interface was exposed, regardless of if + some features were not announced in guest visible CPUIDs. ``hv-enforce-cpuid`` + feature alters this behavior and only allows the guest to use exposed Hyper-V + enlightenments. + + +Useful links +------------ +Hyper-V Top Level Functional specification and other information: + +- https://github.com/MicrosoftDocs/Virtualization-Documentation +- https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs + diff --git a/docs/system/index.rst b/docs/system/index.rst index 23e30e26e5e6..e3695649c529 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -27,6 +27,7 @@ or Hypervisor.Framework. secrets authz gdb + replay managed-startup bootindex cpu-hotplug diff --git a/docs/system/loongarch/loongson3.rst b/docs/system/loongarch/loongson3.rst new file mode 100644 index 000000000000..489ea20f8ff7 --- /dev/null +++ b/docs/system/loongarch/loongson3.rst @@ -0,0 +1,129 @@ +:orphan: + +========================================== +loongson3 virt generic platform (``virt``) +========================================== + +The ``virt`` machine use gpex host bridge, and there are some +emulated devices on virt board, such as loongson7a RTC device, +IOAPIC device, ACPI device and so on. + +Supported devices +----------------- + +The ``virt`` machine supports: +- Gpex host bridge +- Ls7a RTC device +- Ls7a IOAPIC device +- ACPI GED device +- Fw_cfg device +- PCI/PCIe devices +- Memory device +- 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 ``la464-loongarch-cpu``. + +Boot options +------------ + +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 la464-loongarch-cpu \ + -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd initrd.img \ + -append "root=/dev/ram rdinit=/sbin/init console=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 000000000000..aeb65e22ff9b --- /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 000000000000..0af898ab20be --- /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 000000000000..ef10439737fd --- /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 000000000000..2fe61ac94255 --- /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 cfffbda24da9..af3b3d9fa460 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/ppce500.rst b/docs/system/ppc/ppce500.rst index 9beef391717a..c9fe0915dc56 100644 --- a/docs/system/ppc/ppce500.rst +++ b/docs/system/ppc/ppce500.rst @@ -19,6 +19,7 @@ The ``ppce500`` machine supports the following devices: * Power-off functionality via one GPIO pin * 1 Freescale MPC8xxx PCI host controller * VirtIO devices via PCI bus +* 1 Freescale Enhanced Secure Digital Host controller (eSDHC) * 1 Freescale Enhanced Triple Speed Ethernet controller (eTSEC) Hardware configuration information @@ -113,7 +114,7 @@ To boot the 32-bit Linux kernel: .. code-block:: bash - $ qemu-system-ppc{64|32} -M ppce500 -cpu e500mc -smp 4 -m 2G \ + $ qemu-system-ppc64 -M ppce500 -cpu e500mc -smp 4 -m 2G \ -display none -serial stdio \ -kernel vmlinux \ -initrd /path/to/rootfs.cpio \ @@ -146,15 +147,18 @@ You can specify a real world SoC device that QEMU has built-in support but all these SoCs are e500v2 based MPC85xx series, hence you cannot test anything built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500). +Networking +---------- + By default a VirtIO standard PCI networking device is connected as an ethernet interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by: .. code-block:: bash - $ qemu-system-ppc -M ppce500 -smp 4 -m 2G \ - -display none -serial stdio \ - -bios u-boot \ - -nic tap,ifname=tap0,script=no,downscript=no,model=e1000 + $ qemu-system-ppc64 -M ppce500 -smp 4 -m 2G \ + -display none -serial stdio \ + -bios u-boot \ + -nic tap,ifname=tap0,script=no,downscript=no,model=e1000 The QEMU ``ppce500`` machine can also dynamically instantiate an eTSEC device if “-device eTSEC” is given to QEMU: @@ -162,3 +166,30 @@ if “-device eTSEC” is given to QEMU: .. code-block:: bash -netdev tap,ifname=tap0,script=no,downscript=no,id=net0 -device eTSEC,netdev=net0 + +Root file system on flash drive +------------------------------- + +Rather than using a root file system on ram disk, it is possible to have it on +CFI flash. Given an ext2 image whose size must be a power of two, it can be used +as follows: + +.. code-block:: bash + + $ qemu-system-ppc64 -M ppce500 -cpu e500mc -smp 4 -m 2G \ + -display none -serial stdio \ + -kernel vmlinux \ + -drive if=pflash,file=/path/to/rootfs.ext2,format=raw \ + -append "rootwait root=/dev/mtdblock0" + +Alternatively, the root file system can also reside on an emulated SD card +whose size must again be a power of two: + +.. code-block:: bash + + $ qemu-system-ppc64 -M ppce500 -cpu e500mc -smp 4 -m 2G \ + -display none -serial stdio \ + -kernel vmlinux \ + -device sd-card,drive=mydrive \ + -drive id=mydrive,if=none,file=/path/to/rootfs.ext2,format=raw \ + -append "rootwait root=/dev/mmcblk0" diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst index d9b65ad4e850..a876d897b6e4 100644 --- a/docs/system/ppc/pseries.rst +++ b/docs/system/ppc/pseries.rst @@ -32,14 +32,43 @@ Missing devices Firmware ======== +The pSeries platform in QEMU comes with 2 firmwares: + `SLOF `_ (Slimline Open Firmware) is an implementation of the `IEEE 1275-1994, Standard for Boot (Initialization Configuration) Firmware: Core Requirements and Practices `_. +SLOF performs bus scanning, PCI resource allocation, provides the client +interface to boot from block devices and network. + QEMU includes a prebuilt image of SLOF which is updated when a more recent version is required. +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 QEMU implements parts of the IEEE 1275 Open Firmware interface. + +VOF does not have device drivers, does not do PCI resource allocation and +relies on ``-kernel`` used with Linux kernels recent enough (v5.4+) +to PCI resource assignment. It is ideal to use with petitboot. + +Booting via ``-kernel`` supports the following: + ++-------------------+-------------------+------------------+ +| kernel | pseries,x-vof=off | pseries,x-vof=on | ++===================+===================+==================+ +| vmlinux BE | ✓ | ✓ | ++-------------------+-------------------+------------------+ +| vmlinux LE | ✓ | ✓ | ++-------------------+-------------------+------------------+ +| zImage.pseries BE | ✓¹ | ✓¹ | ++-------------------+-------------------+------------------+ +| zImage.pseries LE | ✓ | ✓ | ++-------------------+-------------------+------------------+ + +¹ must set kernel-addr=0 + Build directions ================ diff --git a/docs/system/replay.rst b/docs/system/replay.rst new file mode 100644 index 000000000000..3105327423c3 --- /dev/null +++ b/docs/system/replay.rst @@ -0,0 +1,237 @@ +.. _replay: + +.. + Copyright (c) 2010-2022 Institute for System Programming + of the Russian Academy of Sciences. + + This work is licensed under the terms of the GNU GPL, version 2 or later. + See the COPYING file in the top-level directory. + +Record/replay +============= + +Record/replay functions are used for the deterministic replay of qemu execution. +Execution recording writes a non-deterministic events log, which can be later +used for replaying the execution anywhere and for unlimited number of times. +It also supports checkpointing for faster rewind to the specific replay moment. +Execution replaying reads the log and replays all non-deterministic events +including external input, hardware clocks, and interrupts. + +Deterministic replay has the following features: + + * Deterministically replays whole system execution and all contents of + the memory, state of the hardware devices, clocks, and screen of the VM. + * Writes execution log into the file for later replaying for multiple times + on different machines. + * Supports i386, x86_64, ARM, AArch64, Risc-V, MIPS, MIPS64, S390X, Alpha, + PowerPC, PowerPC64, M68000, Microblaze, OpenRISC, Nios II, SPARC, + and Xtensa hardware platforms. + * Performs deterministic replay of all operations with keyboard and mouse + input devices, serial ports, and network. + +Usage of the record/replay: + + * First, record the execution with the following command line: + + .. parsed-literal:: + |qemu_system| \\ + -icount shift=auto,rr=record,rrfile=replay.bin \\ + -drive file=disk.qcow2,if=none,snapshot,id=img-direct \\ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \\ + -device ide-hd,drive=img-blkreplay \\ + -netdev user,id=net1 -device rtl8139,netdev=net1 \\ + -object filter-replay,id=replay,netdev=net1 + + * After recording, you can replay it by using another command line: + + .. parsed-literal:: + |qemu_system| \\ + -icount shift=auto,rr=replay,rrfile=replay.bin \\ + -drive file=disk.qcow2,if=none,snapshot,id=img-direct \\ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \\ + -device ide-hd,drive=img-blkreplay \\ + -netdev user,id=net1 -device rtl8139,netdev=net1 \\ + -object filter-replay,id=replay,netdev=net1 + + The only difference with recording is changing the rr option + from record to replay. + * Block device images are not actually changed in the recording mode, + because all of the changes are written to the temporary overlay file. + This behavior is enabled by using blkreplay driver. It should be used + for every enabled block device, as described in :ref:`block-label` section. + * ``-net none`` option should be specified when network is not used, + because QEMU adds network card by default. When network is needed, + it should be configured explicitly with replay filter, as described + in :ref:`network-label` section. + * Interaction with audio devices and serial ports are recorded and replayed + automatically when such devices are enabled. + +Core idea +--------- + +Record/replay system is based on saving and replaying non-deterministic +events (e.g. keyboard input) and simulating deterministic ones (e.g. reading +from HDD or memory of the VM). Saving only non-deterministic events makes +log file smaller and simulation faster. + +The following non-deterministic data from peripheral devices is saved into +the log: mouse and keyboard input, network packets, audio controller input, +serial port input, and hardware clocks (they are non-deterministic +too, because their values are taken from the host machine). Inputs from +simulated hardware, memory of VM, software interrupts, and execution of +instructions are not saved into the log, because they are deterministic and +can be replayed by simulating the behavior of virtual machine starting from +initial state. + +Instruction counting +-------------------- + +QEMU should work in icount mode to use record/replay feature. icount was +designed to allow deterministic execution in absence of external inputs +of the virtual machine. Record/replay feature is enabled through ``-icount`` +command-line option, making possible deterministic execution of the machine, +interacting with user or network. + +.. _block-label: + +Block devices +------------- + +Block devices record/replay module intercepts calls of +bdrv coroutine functions at the top of block drivers stack. +To record and replay block operations the drive must be configured +as following: + +.. parsed-literal:: + -drive file=disk.qcow2,if=none,snapshot,id=img-direct + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay + -device ide-hd,drive=img-blkreplay + +blkreplay driver should be inserted between disk image and virtual driver +controller. Therefore all disk requests may be recorded and replayed. + +.. _snapshotting-label: + +Snapshotting +------------ + +New VM snapshots may be created in replay mode. They can be used later +to recover the desired VM state. All VM states created in replay mode +are associated with the moment of time in the replay scenario. +After recovering the VM state replay will start from that position. + +Default starting snapshot name may be specified with icount field +rrsnapshot as follows: + +.. parsed-literal:: + -icount shift=auto,rr=record,rrfile=replay.bin,rrsnapshot=snapshot_name + +This snapshot is created at start of recording and restored at start +of replaying. It also can be loaded while replaying to roll back +the execution. + +``snapshot`` flag of the disk image must be removed to save the snapshots +in the overlay (or original image) instead of using the temporary overlay. + +.. parsed-literal:: + -drive file=disk.ovl,if=none,id=img-direct + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay + -device ide-hd,drive=img-blkreplay + +Use QEMU monitor to create additional snapshots. ``savevm `` command +created the snapshot and ``loadvm `` restores it. To prevent corruption +of the original disk image, use overlay files linked to the original images. +Therefore all new snapshots (including the starting one) will be saved in +overlays and the original image remains unchanged. + +When you need to use snapshots with diskless virtual machine, +it must be started with "orphan" qcow2 image. This image will be used +for storing VM snapshots. Here is the example of the command line for this: + +.. parsed-literal:: + |qemu_system| \\ + -icount shift=auto,rr=replay,rrfile=record.bin,rrsnapshot=init \\ + -net none -drive file=empty.qcow2,if=none,id=rr + +``empty.qcow2`` drive does not connected to any virtual block device and used +for VM snapshots only. + +.. _network-label: + +Network devices +--------------- + +Record and replay for network interactions is performed with the network filter. +Each backend must have its own instance of the replay filter as follows: + +.. parsed-literal:: + -netdev user,id=net1 -device rtl8139,netdev=net1 + -object filter-replay,id=replay,netdev=net1 + +Replay network filter is used to record and replay network packets. While +recording the virtual machine this filter puts all packets coming from +the outer world into the log. In replay mode packets from the log are +injected into the network device. All interactions with network backend +in replay mode are disabled. + +Audio devices +------------- + +Audio data is recorded and replay automatically. The command line for recording +and replaying must contain identical specifications of audio hardware, e.g.: + +.. parsed-literal:: + -soundhw ac97 + +Serial ports +------------ + +Serial ports input is recorded and replay automatically. The command lines +for recording and replaying must contain identical number of ports in record +and replay modes, but their backends may differ. +E.g., ``-serial stdio`` in record mode, and ``-serial null`` in replay mode. + +Reverse debugging +----------------- + +Reverse debugging allows "executing" the program in reverse direction. +GDB remote protocol supports "reverse step" and "reverse continue" +commands. The first one steps single instruction backwards in time, +and the second one finds the last breakpoint in the past. + +Recorded executions may be used to enable reverse debugging. QEMU can't +execute the code in backwards direction, but can load a snapshot and +replay forward to find the desired position or breakpoint. + +The following GDB commands are supported: + + - ``reverse-stepi`` (or ``rsi``) - step one instruction backwards + - ``reverse-continue`` (or ``rc``) - find last breakpoint in the past + +Reverse step loads the nearest snapshot and replays the execution until +the required instruction is met. + +Reverse continue may include several passes of examining the execution +between the snapshots. Each of the passes include the following steps: + + #. loading the snapshot + #. replaying to examine the breakpoints + #. if breakpoint or watchpoint was met + + * loading the snapshot again + * replaying to the required breakpoint + + #. else + + * proceeding to the p.1 with the earlier snapshot + +Therefore usage of the reverse debugging requires at least one snapshot +created. This can be done by omitting ``snapshot`` option +for the block drives and adding ``rrsnapshot`` for both record and replay +command lines. +See the :ref:`snapshotting-label` section to learn more about running record/replay +and creating the snapshot in these modes. + +When ``rrsnapshot`` is not used, then snapshot named ``start_debugging`` +created in temporary overlay. This allows using reverse debugging, but with +temporary snapshots (existing within the session). diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index 1272b6659e45..4b16e41d7f58 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -162,3 +162,28 @@ The minimal QEMU commands to run U-Boot SPL are: To test 32-bit U-Boot images, switch to use qemu-riscv32_smode_defconfig and riscv32_spl_defconfig builds, and replace ``qemu-system-riscv64`` with ``qemu-system-riscv32`` in the command lines above to boot the 32-bit U-Boot. + +Enabling TPM +------------ + +A TPM device can be connected to the virt board by following the steps below. + +First launch the TPM emulator: + +.. code-block:: bash + + $ swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \ + --ctrl type=unixio,path=swtpm-sock + +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 + +The TPM device can be seen in the memory tree and the generated device +tree and should be accessible from the guest software. diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst index 9e591cb9dc36..1a7a18b43b09 100644 --- a/docs/system/s390x/bootdevices.rst +++ b/docs/system/s390x/bootdevices.rst @@ -53,6 +53,32 @@ recommended to specify a CD-ROM device via ``-device scsi-cd`` (as mentioned above) instead. +Selecting kernels with the ``loadparm`` property +------------------------------------------------ + +The ``s390-ccw-virtio`` machine supports the so-called ``loadparm`` parameter +which can be used to select the kernel on the disk of the guest that the +s390-ccw bios should boot. When starting QEMU, it can be specified like this:: + + qemu-system-s390x -machine s390-ccw-virtio,loadparm= + +The first way to use this parameter is to use the word ``PROMPT`` as the +```` here. In that case the s390-ccw bios will show a list of +installed kernels on the disk of the guest and ask the user to enter a number +to chose which kernel should be booted -- similar to what can be achieved by +specifying the ``-boot menu=on`` option when starting QEMU. Note that the menu +list will only show the names of the installed kernels when using a DASD-like +disk image with 4k byte sectors. On normal SCSI-style disks with 512-byte +sectors, there is not enough space for the zipl loader on the disk to store +the kernel names, so you only get a list without names here. + +The second way to use this parameter is to use a number in the range from 0 +to 31. The numbers that can be used here correspond to the numbers that are +shown when using the ``PROMPT`` option, and the s390-ccw bios will then try +to automatically boot the kernel that is associated with the given number. +Note that ``0`` can be used to boot the default entry. + + Booting from a network device ----------------------------- @@ -65,7 +91,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-i386.rst b/docs/system/target-i386.rst index 96bf54889a82..e64c0130772d 100644 --- a/docs/system/target-i386.rst +++ b/docs/system/target-i386.rst @@ -26,6 +26,7 @@ Architectural features :maxdepth: 1 i386/cpu + i386/hyperv i386/kvm-pv i386/sgx i386/amd-memory-encryption diff --git a/docs/system/target-openrisc.rst b/docs/system/target-openrisc.rst new file mode 100644 index 000000000000..22cb2217a68d --- /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 9dcd95dd8421..224fadae71c4 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 1a04674362e8..e284c8280106 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 8885ea11cfd0..15aeddc6d8b3 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 @@ -332,8 +332,8 @@ Command description: ``-r all`` fixes all kinds of errors, with a higher risk of choosing the wrong fix or hiding corruption that has already occurred. - Only the formats ``qcow2``, ``qed`` and ``vdi`` support - consistency checks. + Only the formats ``qcow2``, ``qed``, ``parallels``, ``vhdx``, ``vmdk`` and + ``vdi`` support consistency checks. In case the image does not have any inconsistencies, check exits with ``0``. Other exit codes indicate the kind of inconsistency found or if another error diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst index 4c950f61998e..faf6349ea51e 100644 --- a/docs/tools/qemu-nbd.rst +++ b/docs/tools/qemu-nbd.rst @@ -139,8 +139,7 @@ driver options if :option:`--image-opts` is specified. .. option:: -e, --shared=NUM Allow up to *NUM* clients to share the device (default - ``1``), 0 for unlimited. Safe for readers, but for now, - consistency is not guaranteed between multiple writers. + ``1``), 0 for unlimited. .. option:: -t, --persistent @@ -226,7 +225,7 @@ disconnects: qemu-nbd -f qcow2 file.qcow2 Start a long-running server listening with encryption on port 10810, -and whitelist clients with a specific X.509 certificate to connect to +and allow clients with a specific X.509 certificate to connect to a 1 megabyte subset of a raw file, using the export name 'subset': :: diff --git a/docs/tools/qemu-pr-helper.rst b/docs/tools/qemu-pr-helper.rst index eaebe40da0ea..c32867cfc611 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/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst index 8b975926637e..ea00149a63ac 100644 --- a/docs/tools/qemu-storage-daemon.rst +++ b/docs/tools/qemu-storage-daemon.rst @@ -77,6 +77,7 @@ Standard options: --export [type=]vhost-user-blk,id=,node-name=,addr.type=unix,addr.path=[,writable=on|off][,logical-block-size=][,num-queues=] --export [type=]vhost-user-blk,id=,node-name=,addr.type=fd,addr.str=[,writable=on|off][,logical-block-size=][,num-queues=] --export [type=]fuse,id=,node-name=,mountpoint=[,growable=on|off][,writable=on|off][,allow-other=on|off|auto] + --export [type=]vduse-blk,id=,node-name=,name=[,writable=on|off][,num-queues=][,queue-size=][,logical-block-size=][,serial=] is a block export definition. ``node-name`` is the block node that should be exported. ``writable`` determines whether or not the export allows write @@ -110,6 +111,27 @@ Standard options: ``allow-other`` to auto (the default) will try enabling this option, and on error fall back to disabling it. + The ``vduse-blk`` export type takes a ``name`` (must be unique across the host) + to create the VDUSE device. + ``num-queues`` sets the number of virtqueues (the default is 1). + ``queue-size`` sets the virtqueue descriptor table size (the default is 256). + + The instantiated VDUSE device must then be added to the vDPA bus using the + vdpa(8) command from the iproute2 project:: + + # vdpa dev add name mgmtdev vduse + + The device can be removed from the vDPA bus later as follows:: + + # vdpa dev del + + For more information about attaching vDPA devices to the host with + virtio_vdpa.ko or attaching them to guests with vhost_vdpa.ko, see + https://vdpa-dev.gitlab.io/. + + For more information about VDUSE, see + https://docs.kernel.org/userspace-api/vduse.html. + .. option:: --monitor MONITORDEF is a QMP monitor definition. See the :manpage:`qemu(1)` manual page for diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst index 0c0560203c7c..995a754a7bf9 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst @@ -111,6 +111,11 @@ Options label. Server will try to set that label on newly created file atomically wherever possible. + * killpriv_v2|no_killpriv_v2 - + Enable/disable ``FUSE_HANDLE_KILLPRIV_V2`` support. KILLPRIV_V2 is enabled + by default as long as the client supports it. Enabling this option helps + with performance in write path. + .. option:: --socket-path=PATH Listen on vhost-user UNIX domain socket at PATH. @@ -127,7 +132,7 @@ Options .. option:: --thread-pool-size=NUM Restrict the number of worker threads per request queue to NUM. The default - is 64. + is 0. .. option:: --cache=none|auto|always @@ -227,7 +232,7 @@ e.g.: ``:ok:server::security.:`` - will pass 'securty.' xattr's in listxattr from the server + will pass 'security.' xattr's in listxattr from the server and ignore following rules. ``:ok:all:::`` diff --git a/dump/dump.c b/dump/dump.c index f57ed76fa76d..279b07f09b18 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "elf.h" #include "exec/hwaddr.h" @@ -55,6 +54,16 @@ static Error *dump_migration_blocker; DIV_ROUND_UP((name_size), 4) + \ DIV_ROUND_UP((desc_size), 4)) * 4) +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) { @@ -94,6 +103,7 @@ static int dump_cleanup(DumpState *s) memory_mapping_list_free(&s->list); close(s->fd); g_free(s->guest_note); + g_array_unref(s->string_table_buf); s->guest_note = NULL; if (s->resume) { if (s->detached) { @@ -122,63 +132,81 @@ 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) { - Elf64_Ehdr elf_header; - int ret; + /* + * phnum in the elf header is 16 bit, if we have more segments we + * set phnum to PN_XNUM and write the real number of segments to a + * special section. + */ + uint16_t phnum = MIN(s->phdr_num, PN_XNUM); + + 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); + 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); + elf_header->e_shstrndx = cpu_to_dump16(s, s->shdr_num - 1); +} - 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, sizeof(Elf64_Ehdr)); - elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); - elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num); - if (s->have_section) { - uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info; - - elf_header.e_shoff = cpu_to_dump64(s, shoff); - elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); - elf_header.e_shnum = cpu_to_dump16(s, 1); - } - - ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); - if (ret < 0) { - error_setg_errno(errp, -ret, "dump: failed to write elf header"); - } +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 + * set phnum to PN_XNUM and write the real number of segments to a + * special section. + */ + uint16_t phnum = MIN(s->phdr_num, PN_XNUM); + + 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); + 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); + elf_header->e_shstrndx = cpu_to_dump16(s, s->shdr_num - 1); } -static void write_elf32_header(DumpState *s, Error **errp) +static void write_elf_header(DumpState *s, Error **errp) { - Elf32_Ehdr elf_header; + 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, sizeof(Elf32_Ehdr)); - elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); - elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num); - if (s->have_section) { - uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info; - - elf_header.e_shoff = cpu_to_dump32(s, shoff); - elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); - elf_header.e_shnum = cpu_to_dump16(s, 1); - } - - ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + /* The NULL header and the shstrtab are always defined */ + assert(s->shdr_num >= 2); + 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(header_ptr, header_size, s); if (ret < 0) { error_setg_errno(errp, -ret, "dump: failed to write elf header"); } @@ -233,25 +261,15 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, } } -static void write_elf64_note(DumpState *s, Error **errp) +static void prepare_elf64_phdr_note(DumpState *s, Elf64_Phdr *phdr) { - Elf64_Phdr phdr; - hwaddr begin = s->memory_offset - s->note_size; - int ret; - - memset(&phdr, 0, sizeof(Elf64_Phdr)); - phdr.p_type = cpu_to_dump32(s, PT_NOTE); - phdr.p_offset = cpu_to_dump64(s, begin); - phdr.p_paddr = 0; - phdr.p_filesz = cpu_to_dump64(s, s->note_size); - phdr.p_memsz = cpu_to_dump64(s, s->note_size); - phdr.p_vaddr = 0; - - ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); - if (ret < 0) { - error_setg_errno(errp, -ret, - "dump: failed to write program header table"); - } + memset(phdr, 0, sizeof(*phdr)); + phdr->p_type = cpu_to_dump32(s, PT_NOTE); + phdr->p_offset = cpu_to_dump64(s, s->note_offset); + phdr->p_paddr = 0; + phdr->p_filesz = cpu_to_dump64(s, s->note_size); + phdr->p_memsz = cpu_to_dump64(s, s->note_size); + phdr->p_vaddr = 0; } static inline int cpu_index(CPUState *cpu) @@ -299,25 +317,15 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, write_guest_note(f, s, errp); } -static void write_elf32_note(DumpState *s, Error **errp) +static void prepare_elf32_phdr_note(DumpState *s, Elf32_Phdr *phdr) { - hwaddr begin = s->memory_offset - s->note_size; - Elf32_Phdr phdr; - int ret; - - memset(&phdr, 0, sizeof(Elf32_Phdr)); - phdr.p_type = cpu_to_dump32(s, PT_NOTE); - phdr.p_offset = cpu_to_dump32(s, begin); - phdr.p_paddr = 0; - phdr.p_filesz = cpu_to_dump32(s, s->note_size); - phdr.p_memsz = cpu_to_dump32(s, s->note_size); - phdr.p_vaddr = 0; - - ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); - if (ret < 0) { - error_setg_errno(errp, -ret, - "dump: failed to write program header table"); - } + memset(phdr, 0, sizeof(*phdr)); + phdr->p_type = cpu_to_dump32(s, PT_NOTE); + phdr->p_offset = cpu_to_dump32(s, s->note_offset); + phdr->p_paddr = 0; + phdr->p_filesz = cpu_to_dump32(s, s->note_size); + phdr->p_memsz = cpu_to_dump32(s, s->note_size); + phdr->p_vaddr = 0; } static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, @@ -347,30 +355,161 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, write_guest_note(f, s, errp); } -static void write_elf_section(DumpState *s, int type, Error **errp) +static void write_elf_phdr_note(DumpState *s, Error **errp) { - Elf32_Shdr shdr32; - Elf64_Shdr shdr64; - int shdr_size; - void *shdr; + Elf32_Phdr phdr32; + Elf64_Phdr phdr64; + void *phdr; + size_t size; int ret; - if (type == 0) { - shdr_size = sizeof(Elf32_Shdr); - memset(&shdr32, 0, shdr_size); - shdr32.sh_info = cpu_to_dump32(s, s->sh_info); - shdr = &shdr32; + if (dump_is_64bit(s)) { + prepare_elf64_phdr_note(s, &phdr64); + size = sizeof(phdr64); + phdr = &phdr64; + } else { + prepare_elf32_phdr_note(s, &phdr32); + size = sizeof(phdr32); + phdr = &phdr32; + } + + ret = fd_write_vmcore(phdr, size, s); + if (ret < 0) { + error_setg_errno(errp, -ret, + "dump: failed to write program header table"); + } +} + +static void prepare_elf_section_hdr_zero(DumpState *s) +{ + if (dump_is_64bit(s)) { + Elf64_Shdr *shdr64 = s->elf_section_hdrs; + + shdr64->sh_info = cpu_to_dump32(s, s->phdr_num); } else { + Elf32_Shdr *shdr32 = s->elf_section_hdrs; + + shdr32->sh_info = cpu_to_dump32(s, s->phdr_num); + } +} + +static void prepare_elf_section_hdr_string(DumpState *s, void *buff) +{ + uint64_t index = s->string_table_buf->len; + const char strtab[] = ".shstrtab"; + Elf32_Shdr shdr32 = {}; + Elf64_Shdr shdr64 = {}; + int shdr_size; + void *shdr; + + g_array_append_vals(s->string_table_buf, strtab, sizeof(strtab)); + if (dump_is_64bit(s)) { shdr_size = sizeof(Elf64_Shdr); - memset(&shdr64, 0, shdr_size); - shdr64.sh_info = cpu_to_dump32(s, s->sh_info); + shdr64.sh_type = SHT_STRTAB; + shdr64.sh_offset = s->section_offset + s->elf_section_data_size; + shdr64.sh_name = index; + shdr64.sh_size = s->string_table_buf->len; shdr = &shdr64; + } else { + shdr_size = sizeof(Elf32_Shdr); + shdr32.sh_type = SHT_STRTAB; + shdr32.sh_offset = s->section_offset + s->elf_section_data_size; + shdr32.sh_name = index; + shdr32.sh_size = s->string_table_buf->len; + shdr = &shdr32; + } + memcpy(buff, shdr, shdr_size); +} + +static bool prepare_elf_section_hdrs(DumpState *s, Error **errp) +{ + size_t len, sizeof_shdr; + void *buff_hdr; + + /* + * Section ordering: + * - HDR zero + * - Arch section hdrs + * - String table hdr + */ + sizeof_shdr = dump_is_64bit(s) ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr); + len = sizeof_shdr * s->shdr_num; + s->elf_section_hdrs = g_malloc0(len); + buff_hdr = s->elf_section_hdrs; + + /* + * The first section header is ALWAYS a special initial section + * header. + * + * The header should be 0 with one exception being that if + * phdr_num is PN_XNUM then the sh_info field contains the real + * number of segment entries. + * + * As we zero allocate the buffer we will only need to modify + * sh_info for the PN_XNUM case. + */ + if (s->phdr_num >= PN_XNUM) { + prepare_elf_section_hdr_zero(s); + } + buff_hdr += sizeof_shdr; + + /* Add architecture defined section headers */ + if (s->dump_info.arch_sections_write_hdr_fn + && s->shdr_num > 2) { + buff_hdr += s->dump_info.arch_sections_write_hdr_fn(s, buff_hdr); + + if (s->shdr_num >= SHN_LORESERVE) { + error_setg_errno(errp, EINVAL, + "dump: too many architecture defined sections"); + return false; + } + } + + /* + * String table is the last section since strings are added via + * arch_sections_write_hdr(). + */ + prepare_elf_section_hdr_string(s, buff_hdr); + return true; +} + +static void write_elf_section_headers(DumpState *s, Error **errp) +{ + size_t sizeof_shdr = dump_is_64bit(s) ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr); + int ret; + + if (!prepare_elf_section_hdrs(s, errp)) { + return; } - ret = fd_write_vmcore(shdr, shdr_size, s); + ret = fd_write_vmcore(s->elf_section_hdrs, s->shdr_num * sizeof_shdr, s); if (ret < 0) { - error_setg_errno(errp, -ret, - "dump: failed to write section header table"); + error_setg_errno(errp, -ret, "dump: failed to write section headers"); + } + + g_free(s->elf_section_hdrs); +} + +static void write_elf_sections(DumpState *s, Error **errp) +{ + int ret; + + if (s->elf_section_data_size) { + /* Write architecture section data */ + ret = fd_write_vmcore(s->elf_section_data, + s->elf_section_data_size, s); + if (ret < 0) { + error_setg_errno(errp, -ret, + "dump: failed to write architecture section data"); + return; + } + } + + /* Write string table */ + ret = fd_write_vmcore(s->string_table_buf->data, + s->string_table_buf->len, s); + if (ret < 0) { + error_setg_errno(errp, -ret, "dump: failed to write string table data"); } } @@ -390,23 +529,21 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp) static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, int64_t size, Error **errp) { + ERRP_GUARD(); int64_t i; - Error *local_err = NULL; for (i = 0; i < size / s->dump_info.page_size; i++) { write_data(s, block->host_addr + start + i * s->dump_info.page_size, - s->dump_info.page_size, &local_err); - if (local_err) { - error_propagate(errp, local_err); + s->dump_info.page_size, errp); + if (*errp) { return; } } if ((size % s->dump_info.page_size) != 0) { write_data(s, block->host_addr + start + i * s->dump_info.page_size, - size % s->dump_info.page_size, &local_err); - if (local_err) { - error_propagate(errp, local_err); + size % s->dump_info.page_size, errp); + if (*errp) { return; } } @@ -427,29 +564,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; @@ -474,53 +612,56 @@ 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; MemoryMapping *memory_mapping; uint32_t phdr_index = 1; - uint32_t max_index; - Error *local_err = NULL; - - if (s->have_section) { - max_index = s->sh_info; - } else { - max_index = s->phdr_num; - } QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { get_offset_range(memory_mapping->phys_addr, memory_mapping->length, s, &offset, &filesz); - if (s->dump_info.d_class == ELFCLASS64) { + if (dump_is_64bit(s)) { write_elf64_load(s, memory_mapping, phdr_index++, offset, - filesz, &local_err); + filesz, errp); } else { write_elf32_load(s, memory_mapping, phdr_index++, offset, - filesz, &local_err); + filesz, errp); } - if (local_err) { - error_propagate(errp, local_err); + if (*errp) { return; } - if (phdr_index >= max_index) { + if (phdr_index >= s->phdr_num) { break; } } } +static void write_elf_notes(DumpState *s, Error **errp) +{ + if (dump_is_64bit(s)) { + write_elf64_notes(fd_write_vmcore, s, errp); + } else { + write_elf32_notes(fd_write_vmcore, s, errp); + } +} + /* write elf header, PT_NOTE and elf note to vmcore. */ static void dump_begin(DumpState *s, Error **errp) { - Error *local_err = NULL; + ERRP_GUARD(); /* * the vmcore's format is: * -------------- * | elf header | * -------------- + * | sctn_hdr | + * -------------- * | PT_NOTE | * -------------- * | PT_LOAD | @@ -529,8 +670,6 @@ static void dump_begin(DumpState *s, Error **errp) * -------------- * | PT_LOAD | * -------------- - * | sec_hdr | - * -------------- * | elf note | * -------------- * | memory | @@ -541,143 +680,136 @@ static void dump_begin(DumpState *s, Error **errp) */ /* write elf header to vmcore */ - if (s->dump_info.d_class == ELFCLASS64) { - write_elf64_header(s, &local_err); - } else { - write_elf32_header(s, &local_err); + write_elf_header(s, errp); + if (*errp) { + return; } - if (local_err) { - error_propagate(errp, local_err); + + /* write section headers to vmcore */ + write_elf_section_headers(s, errp); + if (*errp) { return; } - if (s->dump_info.d_class == ELFCLASS64) { - /* write PT_NOTE to vmcore */ - write_elf64_note(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + /* write PT_NOTE to vmcore */ + write_elf_phdr_note(s, errp); + if (*errp) { + return; + } - /* write all PT_LOAD to vmcore */ - write_elf_loads(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + /* write all PT_LOADs to vmcore */ + write_elf_phdr_loads(s, errp); + if (*errp) { + return; + } - /* write section to vmcore */ - if (s->have_section) { - write_elf_section(s, 1, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } + /* write notes to vmcore */ + write_elf_notes(s, errp); +} - /* write notes to vmcore */ - write_elf64_notes(fd_write_vmcore, s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } else { - /* write PT_NOTE to vmcore */ - write_elf32_note(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } +int64_t dump_filtered_memblock_size(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) +{ + int64_t size, left, right; - /* write all PT_LOAD to vmcore */ - write_elf_loads(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + /* No filter, return full size */ + if (!filter_area_length) { + return block->target_end - block->target_start; + } - /* write section to vmcore */ - if (s->have_section) { - write_elf_section(s, 0, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } + /* 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; - /* write notes to vmcore */ - write_elf32_notes(fd_write_vmcore, s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } + return size; } -static int get_next_block(DumpState *s, GuestPhysBlock *block) +int64_t dump_filtered_memblock_start(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; + 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; } - 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; - } + if (filter_area_start > block->target_start) { + return filter_area_start - block->target_start; } - - return 0; } + + return 0; } /* write all memory to vmcore */ static void dump_iterate(DumpState *s, Error **errp) { + ERRP_GUARD(); GuestPhysBlock *block; - int64_t size; - Error *local_err = NULL; + int64_t memblock_size, memblock_start; - do { - block = s->next_block; + 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; + } - 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); - } + 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; } - write_memory(s, block, s->start, size, &local_err); - if (local_err) { - error_propagate(errp, local_err); + } +} + +static void dump_end(DumpState *s, Error **errp) +{ + int rc; + + if (s->elf_section_data_size) { + s->elf_section_data = g_malloc0(s->elf_section_data_size); + } + + /* Adds the architecture defined section data to s->elf_section_data */ + if (s->dump_info.arch_sections_write_fn && + s->elf_section_data_size) { + rc = s->dump_info.arch_sections_write_fn(s, s->elf_section_data); + if (rc) { + error_setg_errno(errp, rc, + "dump: failed to get arch section data"); + g_free(s->elf_section_data); return; } + } - } while (!get_next_block(s, block)); + /* write sections to vmcore */ + write_elf_sections(s, errp); } static void create_vmcore(DumpState *s, Error **errp) { - Error *local_err = NULL; + ERRP_GUARD(); - dump_begin(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + dump_begin(s, errp); + if (*errp) { return; } + /* Iterate over memory and dump it to file */ dump_iterate(s, errp); + if (*errp) { + return; + } + + /* Write the section data */ + dump_end(s, errp); } static int write_start_flat_header(int fd) @@ -772,7 +904,7 @@ static void get_note_sizes(DumpState *s, const void *note, uint64_t name_sz; uint64_t desc_sz; - if (s->dump_info.d_class == ELFCLASS64) { + if (dump_is_64bit(s)) { const Elf64_Nhdr *hdr = note; note_head_sz = sizeof(Elf64_Nhdr); name_sz = tswap64(hdr->n_namesz); @@ -810,6 +942,7 @@ static bool note_name_equal(DumpState *s, /* write common header, sub header and elf note to vmcore */ static void create_header32(DumpState *s, Error **errp) { + ERRP_GUARD(); DiskDumpHeader32 *dh = NULL; KdumpSubHeader32 *kh = NULL; size_t size; @@ -818,7 +951,6 @@ static void create_header32(DumpState *s, Error **errp) uint32_t bitmap_blocks; uint32_t status = 0; uint64_t offset_note; - Error *local_err = NULL; /* write common header, the version of kdump-compressed format is 6th */ size = sizeof(DiskDumpHeader32); @@ -894,9 +1026,8 @@ static void create_header32(DumpState *s, Error **errp) s->note_buf_offset = 0; /* use s->note_buf to store notes temporarily */ - write_elf32_notes(buf_write_note, s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + write_elf32_notes(buf_write_note, s, errp); + if (*errp) { goto out; } if (write_buffer(s->fd, offset_note, s->note_buf, @@ -922,6 +1053,7 @@ static void create_header32(DumpState *s, Error **errp) /* write common header, sub header and elf note to vmcore */ static void create_header64(DumpState *s, Error **errp) { + ERRP_GUARD(); DiskDumpHeader64 *dh = NULL; KdumpSubHeader64 *kh = NULL; size_t size; @@ -930,7 +1062,6 @@ static void create_header64(DumpState *s, Error **errp) uint32_t bitmap_blocks; uint32_t status = 0; uint64_t offset_note; - Error *local_err = NULL; /* write common header, the version of kdump-compressed format is 6th */ size = sizeof(DiskDumpHeader64); @@ -1006,9 +1137,8 @@ static void create_header64(DumpState *s, Error **errp) s->note_buf_offset = 0; /* use s->note_buf to store notes temporarily */ - write_elf64_notes(buf_write_note, s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + write_elf64_notes(buf_write_note, s, errp); + if (*errp) { goto out; } @@ -1034,10 +1164,10 @@ static void create_header64(DumpState *s, Error **errp) static void write_dump_header(DumpState *s, Error **errp) { - if (s->dump_info.d_class == ELFCLASS32) { - create_header32(s, errp); - } else { + if (dump_is_64bit(s)) { create_header64(s, errp); + } else { + create_header32(s, errp); } } @@ -1121,55 +1251,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; + addr = block->target_start; + *pfnptr = dump_paddr_to_pfn(s, addr); + } else { + *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; + } + } - *pfnptr = *pfnptr + 1; - addr = dump_pfn_to_paddr(s, *pfnptr); + 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; + } - if ((addr >= block->target_start) && - (addr + s->dump_info.page_size <= block->target_end)) { - buf = block->host_addr + (addr - block->target_start); - } else { - /* the next page is in the next block */ - block = QTAILQ_NEXT(block, next); - *blockptr = block; - if (!block) { - return false; + 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) @@ -1307,6 +1463,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; @@ -1342,12 +1499,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), @@ -1464,8 +1622,8 @@ static void write_dump_pages(DumpState *s, Error **errp) static void create_kdump_vmcore(DumpState *s, Error **errp) { + ERRP_GUARD(); int ret; - Error *local_err = NULL; /* * the kdump-compressed format is: @@ -1495,21 +1653,18 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) return; } - write_dump_header(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + write_dump_header(s, errp); + if (*errp) { return; } - write_dump_bitmap(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + write_dump_bitmap(s, errp); + if (*errp) { return; } - write_dump_pages(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + write_dump_pages(s, errp); + if (*errp) { return; } @@ -1520,30 +1675,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; } @@ -1564,31 +1711,25 @@ static void dump_state_prepare(DumpState *s) *s = (DumpState) { .status = DUMP_STATUS_ACTIVE }; } -bool dump_in_progress(void) +bool qemu_system_dump_in_progress(void) { DumpState *state = &dump_state_global; 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; @@ -1639,10 +1780,10 @@ static void dump_init(DumpState *s, int fd, bool has_format, DumpGuestMemoryFormat format, bool paging, bool has_filter, int64_t begin, int64_t length, Error **errp) { + ERRP_GUARD(); VMCoreInfoState *vmci = vmcoreinfo_find(); CPUState *cpu; int nr_cpus; - Error *err = NULL; int ret; s->has_format = has_format; @@ -1671,9 +1812,20 @@ 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; + + /* First index is 0, it's the special null name */ + s->string_table_buf = g_array_new(FALSE, TRUE, 1); + /* + * Allocate the null name, due to the clearing option set to true + * it will be 0. + */ + g_array_set_size(s->string_table_buf, 1); memory_mapping_list_init(&s->list); @@ -1690,8 +1842,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; } @@ -1727,8 +1879,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, uint32_t size; uint16_t format; - note_head_size = s->dump_info.d_class == ELFCLASS32 ? - sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr); + note_head_size = dump_is_64bit(s) ? + sizeof(Elf64_Nhdr) : sizeof(Elf32_Nhdr); format = le16_to_cpu(vmci->vmcoreinfo.guest_format); size = le32_to_cpu(vmci->vmcoreinfo.size); @@ -1761,9 +1913,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, /* get memory mapping */ if (paging) { - qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); - if (err != NULL) { - error_propagate(errp, err); + qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, errp); + if (*errp) { goto cleanup; } } else { @@ -1807,51 +1958,58 @@ 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); + } + + /* + * The first section header is always a special one in which most + * fields are 0. The section header string table is also always + * set. + */ + s->shdr_num = 2; + + /* + * Adds the number of architecture sections to shdr_num and sets + * elf_section_data_size so we know the offsets and sizes of all + * parts. + */ + if (s->dump_info.arch_sections_add_fn) { + s->dump_info.arch_sections_add_fn(s); } /* - * calculate phdr_num + * calculate shdr_num so we know the offsets and sizes of all + * parts. + * Calculate phdr_num * - * the type of ehdr->e_phnum is uint16_t, so we should avoid overflow + * The absolute maximum amount of phdrs is UINT32_MAX - 1 as + * sh_info is 32 bit. There's special handling once we go over + * UINT16_MAX - 1 but that is handled in the ehdr and section + * code. */ - s->phdr_num = 1; /* PT_NOTE */ - if (s->list.num < UINT16_MAX - 2) { + s->phdr_num = 1; /* Reserve PT_NOTE */ + if (s->list.num <= UINT32_MAX - 1) { s->phdr_num += s->list.num; - s->have_section = false; } else { - s->have_section = true; - s->phdr_num = PN_XNUM; - s->sh_info = 1; /* PT_NOTE */ - - /* the type of shdr->sh_info is uint32_t, so we should avoid overflow */ - if (s->list.num <= UINT32_MAX - 1) { - s->sh_info += s->list.num; - } else { - s->sh_info = UINT32_MAX; - } + s->phdr_num = UINT32_MAX; } - if (s->dump_info.d_class == ELFCLASS64) { - if (s->have_section) { - s->memory_offset = sizeof(Elf64_Ehdr) + - sizeof(Elf64_Phdr) * s->sh_info + - sizeof(Elf64_Shdr) + s->note_size; - } else { - s->memory_offset = sizeof(Elf64_Ehdr) + - sizeof(Elf64_Phdr) * s->phdr_num + s->note_size; - } + /* + * Now that the number of section and program headers is known we + * can calculate the offsets of the headers and data. + */ + if (dump_is_64bit(s)) { + s->shdr_offset = sizeof(Elf64_Ehdr); + s->phdr_offset = s->shdr_offset + sizeof(Elf64_Shdr) * s->shdr_num; + s->note_offset = s->phdr_offset + sizeof(Elf64_Phdr) * s->phdr_num; } else { - if (s->have_section) { - s->memory_offset = sizeof(Elf32_Ehdr) + - sizeof(Elf32_Phdr) * s->sh_info + - sizeof(Elf32_Shdr) + s->note_size; - } else { - s->memory_offset = sizeof(Elf32_Ehdr) + - sizeof(Elf32_Phdr) * s->phdr_num + s->note_size; - } + s->shdr_offset = sizeof(Elf32_Ehdr); + s->phdr_offset = s->shdr_offset + sizeof(Elf32_Shdr) * s->shdr_num; + s->note_offset = s->phdr_offset + sizeof(Elf32_Phdr) * s->phdr_num; } + s->memory_offset = s->note_offset + s->note_size; + s->section_offset = s->memory_offset + s->total_size; return; @@ -1862,33 +2020,32 @@ static void dump_init(DumpState *s, int fd, bool has_format, /* this operation might be time consuming. */ static void dump_process(DumpState *s, Error **errp) { - Error *local_err = NULL; + ERRP_GUARD(); DumpQueryResult *result = NULL; if (s->has_format && s->format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP) { #ifdef TARGET_X86_64 - create_win_dump(s, &local_err); + create_win_dump(s, errp); #endif } else if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) { - create_kdump_vmcore(s, &local_err); + create_kdump_vmcore(s, errp); } else { - create_vmcore(s, &local_err); + create_vmcore(s, errp); } /* make sure status is written after written_size updates */ smp_wmb(); qatomic_set(&s->status, - (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED)); + (*errp ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED)); /* send DUMP_COMPLETED message (unconditionally) */ result = qmp_query_dump(NULL); /* should never fail */ assert(result); - qapi_event_send_dump_completed(result, !!local_err, (local_err ? - error_get_pretty(local_err) : NULL)); + qapi_event_send_dump_completed(result, + *errp ? error_get_pretty(*errp) : NULL); qapi_free_DumpQueryResult(result); - error_propagate(errp, local_err); dump_cleanup(s); } @@ -1917,10 +2074,10 @@ void qmp_dump_guest_memory(bool paging, const char *file, int64_t length, bool has_format, DumpGuestMemoryFormat format, Error **errp) { + ERRP_GUARD(); const char *p; int fd = -1; DumpState *s; - Error *local_err = NULL; bool detach_p = false; if (runstate_check(RUN_STATE_INMIGRATE)) { @@ -1930,7 +2087,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, /* if there is a dump in background, we should wait until the dump * finished */ - if (dump_in_progress()) { + if (qemu_system_dump_in_progress()) { error_setg(errp, "There is a dump in process, please wait."); return; } @@ -2020,9 +2177,8 @@ void qmp_dump_guest_memory(bool paging, const char *file, dump_state_prepare(s); dump_init(s, fd, has_format, format, paging, has_begin, - begin, length, &local_err); - if (local_err) { - error_propagate(errp, local_err); + begin, length, errp); + if (*errp) { qatomic_set(&s->status, DUMP_STATUS_FAILED); return; } diff --git a/dump/win_dump.c b/dump/win_dump.c index c5eb5a9aacd7..f20b6051b6c8 100644 --- a/dump/win_dump.c +++ b/dump/win_dump.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "elf.h" #include "exec/hwaddr.h" @@ -24,11 +23,31 @@ #include "hw/misc/vmcoreinfo.h" #include "win_dump.h" -static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp) +static size_t win_dump_ptr_size(bool x64) +{ + return x64 ? sizeof(uint64_t) : sizeof(uint32_t); +} + +#define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f) +#define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field) + +#define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f) +#define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field) + +#define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f)) +#define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field) + +static size_t win_dump_ctx_size(bool x64) +{ + return x64 ? sizeof(WinContext64) : sizeof(WinContext32); +} + +static size_t write_run(uint64_t base_page, uint64_t page_count, + int fd, Error **errp) { void *buf; - uint64_t addr = run->BasePage << TARGET_PAGE_BITS; - uint64_t size = run->PageCount << TARGET_PAGE_BITS; + uint64_t addr = base_page << TARGET_PAGE_BITS; + uint64_t size = page_count << TARGET_PAGE_BITS; uint64_t len, l; size_t total = 0; @@ -57,15 +76,16 @@ static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp) return total; } -static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp) +static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp) { - WinDumpPhyMemDesc64 *desc = &h->PhysicalMemoryBlock; - WinDumpPhyMemRun64 *run = desc->Run; + uint64_t BasePage, PageCount; Error *local_err = NULL; int i; - for (i = 0; i < desc->NumberOfRuns; i++) { - s->written_size += write_run(run + i, s->fd, &local_err); + for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) { + BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage); + PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount); + s->written_size += write_run(BasePage, PageCount, s->fd, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -73,30 +93,45 @@ static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp) } } -static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp) +static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr) +{ + int ret; + uint32_t ptr32; + uint64_t ptr64; + + ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32, + win_dump_ptr_size(x64), 0); + + *ptr = x64 ? ptr64 : ptr32; + + return ret; +} + +static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp) { if (cpu_memory_rw_debug(first_cpu, - h->KdDebuggerDataBlock + KDBG_MM_PFN_DATABASE_OFFSET64, - (uint8_t *)&h->PfnDatabase, sizeof(h->PfnDatabase), 0)) { + WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET, + WIN_DUMP_FIELD_PTR(PfnDatabase), + WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) { error_setg(errp, "win-dump: failed to read MmPfnDatabase"); return; } } -static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp) +static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp) { uint64_t KiBugcheckData; - if (cpu_memory_rw_debug(first_cpu, - h->KdDebuggerDataBlock + KDBG_KI_BUGCHECK_DATA_OFFSET64, - (uint8_t *)&KiBugcheckData, sizeof(KiBugcheckData), 0)) { + if (cpu_read_ptr(x64, first_cpu, + WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET, + &KiBugcheckData)) { error_setg(errp, "win-dump: failed to read KiBugcheckData"); return; } - if (cpu_memory_rw_debug(first_cpu, - KiBugcheckData, - h->BugcheckData, sizeof(h->BugcheckData), 0)) { + if (cpu_memory_rw_debug(first_cpu, KiBugcheckData, + WIN_DUMP_FIELD(BugcheckData), + WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) { error_setg(errp, "win-dump: failed to read bugcheck data"); return; } @@ -105,62 +140,72 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp) * If BugcheckCode wasn't saved, we consider guest OS as alive. */ - if (!h->BugcheckCode) { - h->BugcheckCode = LIVE_SYSTEM_DUMP; + if (!WIN_DUMP_FIELD(BugcheckCode)) { + *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP; } } /* * This routine tries to correct mistakes in crashdump header. */ -static void patch_header(WinDumpHeader64 *h) +static void patch_header(WinDumpHeader *h, bool x64) { Error *local_err = NULL; - h->RequiredDumpSpace = sizeof(WinDumpHeader64) + - (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); - h->PhysicalMemoryBlock.unused = 0; - h->unused1 = 0; + if (x64) { + h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) + + (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); + h->x64.PhysicalMemoryBlock.unused = 0; + h->x64.unused1 = 0; + } else { + h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) + + (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); + } - patch_mm_pfn_database(h, &local_err); + patch_mm_pfn_database(h, x64, &local_err); if (local_err) { warn_report_err(local_err); local_err = NULL; } - patch_bugcheck_data(h, &local_err); + patch_bugcheck_data(h, x64, &local_err); if (local_err) { warn_report_err(local_err); } } -static void check_header(WinDumpHeader64 *h, Error **errp) +static bool check_header(WinDumpHeader *h, bool *x64, Error **errp) { const char Signature[] = "PAGE"; - const char ValidDump[] = "DU64"; if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { error_setg(errp, "win-dump: invalid header, expected '%.4s'," " got '%.4s'", Signature, h->Signature); - return; + return false; } - if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) { - error_setg(errp, "win-dump: invalid header, expected '%.4s'," - " got '%.4s'", ValidDump, h->ValidDump); - return; + if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) { + *x64 = false; + } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) { + *x64 = true; + } else { + error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64'," + " got '%.4s'", h->ValidDump); + return false; } + + return true; } -static void check_kdbg(WinDumpHeader64 *h, Error **errp) +static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp) { const char OwnerTag[] = "KDBG"; char read_OwnerTag[4]; - uint64_t KdDebuggerDataBlock = h->KdDebuggerDataBlock; + uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); bool try_fallback = true; try_again: if (cpu_memory_rw_debug(first_cpu, - KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64, + KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET, (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { error_setg(errp, "win-dump: failed to read OwnerTag"); return; @@ -174,7 +219,7 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp) * we try to use KDBG obtained by guest driver. */ - KdDebuggerDataBlock = h->BugcheckParameter1; + KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1); try_fallback = false; goto try_again; } else { @@ -185,7 +230,11 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp) } } - h->KdDebuggerDataBlock = KdDebuggerDataBlock; + if (x64) { + h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock; + } else { + h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock; + } } struct saved_context { @@ -193,24 +242,25 @@ struct saved_context { uint64_t addr; }; -static void patch_and_save_context(WinDumpHeader64 *h, +static void patch_and_save_context(WinDumpHeader *h, bool x64, struct saved_context *saved_ctx, Error **errp) { + uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); uint64_t KiProcessorBlock; uint16_t OffsetPrcbContext; CPUState *cpu; int i = 0; - if (cpu_memory_rw_debug(first_cpu, - h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64, - (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) { + if (cpu_read_ptr(x64, first_cpu, + KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET, + &KiProcessorBlock)) { error_setg(errp, "win-dump: failed to read KiProcessorBlock"); return; } if (cpu_memory_rw_debug(first_cpu, - h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64, + KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET, (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) { error_setg(errp, "win-dump: failed to read OffsetPrcbContext"); return; @@ -223,17 +273,24 @@ static void patch_and_save_context(WinDumpHeader64 *h, uint64_t Context; WinContext ctx; - if (cpu_memory_rw_debug(first_cpu, - KiProcessorBlock + i * sizeof(uint64_t), - (uint8_t *)&Prcb, sizeof(Prcb), 0)) { + if (i >= WIN_DUMP_FIELD(NumberProcessors)) { + warn_report("win-dump: number of QEMU CPUs is bigger than" + " NumberProcessors (%u) in guest Windows", + WIN_DUMP_FIELD(NumberProcessors)); + return; + } + + if (cpu_read_ptr(x64, first_cpu, + KiProcessorBlock + i * win_dump_ptr_size(x64), + &Prcb)) { error_setg(errp, "win-dump: failed to read" " CPU #%d PRCB location", i); return; } - if (cpu_memory_rw_debug(first_cpu, + if (cpu_read_ptr(x64, first_cpu, Prcb + OffsetPrcbContext, - (uint8_t *)&Context, sizeof(Context), 0)) { + &Context)) { error_setg(errp, "win-dump: failed to read" " CPU #%d ContextFrame location", i); return; @@ -241,56 +298,88 @@ static void patch_and_save_context(WinDumpHeader64 *h, saved_ctx[i].addr = Context; - ctx = (WinContext){ - .ContextFlags = WIN_CTX_ALL, - .MxCsr = env->mxcsr, - - .SegEs = env->segs[0].selector, - .SegCs = env->segs[1].selector, - .SegSs = env->segs[2].selector, - .SegDs = env->segs[3].selector, - .SegFs = env->segs[4].selector, - .SegGs = env->segs[5].selector, - .EFlags = cpu_compute_eflags(env), - - .Dr0 = env->dr[0], - .Dr1 = env->dr[1], - .Dr2 = env->dr[2], - .Dr3 = env->dr[3], - .Dr6 = env->dr[6], - .Dr7 = env->dr[7], - - .Rax = env->regs[R_EAX], - .Rbx = env->regs[R_EBX], - .Rcx = env->regs[R_ECX], - .Rdx = env->regs[R_EDX], - .Rsp = env->regs[R_ESP], - .Rbp = env->regs[R_EBP], - .Rsi = env->regs[R_ESI], - .Rdi = env->regs[R_EDI], - .R8 = env->regs[8], - .R9 = env->regs[9], - .R10 = env->regs[10], - .R11 = env->regs[11], - .R12 = env->regs[12], - .R13 = env->regs[13], - .R14 = env->regs[14], - .R15 = env->regs[15], - - .Rip = env->eip, - .FltSave = { + if (x64) { + ctx.x64 = (WinContext64){ + .ContextFlags = WIN_CTX64_ALL, .MxCsr = env->mxcsr, - }, - }; + + .SegEs = env->segs[0].selector, + .SegCs = env->segs[1].selector, + .SegSs = env->segs[2].selector, + .SegDs = env->segs[3].selector, + .SegFs = env->segs[4].selector, + .SegGs = env->segs[5].selector, + .EFlags = cpu_compute_eflags(env), + + .Dr0 = env->dr[0], + .Dr1 = env->dr[1], + .Dr2 = env->dr[2], + .Dr3 = env->dr[3], + .Dr6 = env->dr[6], + .Dr7 = env->dr[7], + + .Rax = env->regs[R_EAX], + .Rbx = env->regs[R_EBX], + .Rcx = env->regs[R_ECX], + .Rdx = env->regs[R_EDX], + .Rsp = env->regs[R_ESP], + .Rbp = env->regs[R_EBP], + .Rsi = env->regs[R_ESI], + .Rdi = env->regs[R_EDI], + .R8 = env->regs[8], + .R9 = env->regs[9], + .R10 = env->regs[10], + .R11 = env->regs[11], + .R12 = env->regs[12], + .R13 = env->regs[13], + .R14 = env->regs[14], + .R15 = env->regs[15], + + .Rip = env->eip, + .FltSave = { + .MxCsr = env->mxcsr, + }, + }; + } else { + ctx.x32 = (WinContext32){ + .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG, + + .SegEs = env->segs[0].selector, + .SegCs = env->segs[1].selector, + .SegSs = env->segs[2].selector, + .SegDs = env->segs[3].selector, + .SegFs = env->segs[4].selector, + .SegGs = env->segs[5].selector, + .EFlags = cpu_compute_eflags(env), + + .Dr0 = env->dr[0], + .Dr1 = env->dr[1], + .Dr2 = env->dr[2], + .Dr3 = env->dr[3], + .Dr6 = env->dr[6], + .Dr7 = env->dr[7], + + .Eax = env->regs[R_EAX], + .Ebx = env->regs[R_EBX], + .Ecx = env->regs[R_ECX], + .Edx = env->regs[R_EDX], + .Esp = env->regs[R_ESP], + .Ebp = env->regs[R_EBP], + .Esi = env->regs[R_ESI], + .Edi = env->regs[R_EDI], + + .Eip = env->eip, + }; + } if (cpu_memory_rw_debug(first_cpu, Context, - (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) { + &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) { error_setg(errp, "win-dump: failed to save CPU #%d context", i); return; } if (cpu_memory_rw_debug(first_cpu, Context, - (uint8_t *)&ctx, sizeof(WinContext), 1)) { + &ctx, win_dump_ctx_size(x64), 1)) { error_setg(errp, "win-dump: failed to write CPU #%d context", i); return; } @@ -299,14 +388,14 @@ static void patch_and_save_context(WinDumpHeader64 *h, } } -static void restore_context(WinDumpHeader64 *h, +static void restore_context(WinDumpHeader *h, bool x64, struct saved_context *saved_ctx) { int i; - for (i = 0; i < h->NumberProcessors; i++) { + for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) { if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr, - (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) { + &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) { warn_report("win-dump: failed to restore CPU #%d context", i); } } @@ -314,69 +403,71 @@ static void restore_context(WinDumpHeader64 *h, void create_win_dump(DumpState *s, Error **errp) { - WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note + - VMCOREINFO_ELF_NOTE_HDR_SIZE); + WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE); X86CPU *first_x86_cpu = X86_CPU(first_cpu); uint64_t saved_cr3 = first_x86_cpu->env.cr[3]; struct saved_context *saved_ctx = NULL; Error *local_err = NULL; + bool x64 = true; + size_t hdr_size; - if (s->guest_note_size != sizeof(WinDumpHeader64) + - VMCOREINFO_ELF_NOTE_HDR_SIZE) { + if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && + s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { error_setg(errp, "win-dump: invalid vmcoreinfo note size"); return; } - check_header(h, &local_err); - if (local_err) { + if (!check_header(h, &x64, &local_err)) { error_propagate(errp, local_err); return; } + hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32); + /* * Further access to kernel structures by virtual addresses * should be made from system context. */ - first_x86_cpu->env.cr[3] = h->DirectoryTableBase; + first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase); - check_kdbg(h, &local_err); + check_kdbg(h, x64, &local_err); if (local_err) { error_propagate(errp, local_err); goto out_cr3; } - patch_header(h); + patch_header(h, x64); - saved_ctx = g_new(struct saved_context, h->NumberProcessors); + saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors)); /* * Always patch context because there is no way * to determine if the system-saved context is valid */ - patch_and_save_context(h, saved_ctx, &local_err); + patch_and_save_context(h, x64, saved_ctx, &local_err); if (local_err) { error_propagate(errp, local_err); goto out_free; } - s->total_size = h->RequiredDumpSpace; + s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace); - s->written_size = qemu_write_full(s->fd, h, sizeof(*h)); - if (s->written_size != sizeof(*h)) { + s->written_size = qemu_write_full(s->fd, h, hdr_size); + if (s->written_size != hdr_size) { error_setg(errp, QERR_IO_ERROR); goto out_restore; } - write_runs(s, h, &local_err); + write_runs(s, h, x64, &local_err); if (local_err) { error_propagate(errp, local_err); goto out_restore; } out_restore: - restore_context(h, saved_ctx); + restore_context(h, x64, saved_ctx); out_free: g_free(saved_ctx); out_cr3: diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c index 118c68da831d..cee658c158b2 100644 --- a/ebpf/ebpf_rss.c +++ b/ebpf/ebpf_rss.c @@ -49,7 +49,7 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx) goto error; } - bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog); + bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER); if (rss_bpf__load(rss_bpf_ctx)) { trace_ebpf_error("eBPF RSS", "can not load RSS program"); diff --git a/event-loop-base.c b/event-loop-base.c new file mode 100644 index 000000000000..d5be4dc6fcf1 --- /dev/null +++ b/event-loop-base.c @@ -0,0 +1,140 @@ +/* + * QEMU event-loop base + * + * Copyright (C) 2022 Red Hat Inc + * + * Authors: + * Stefan Hajnoczi + * Nicolas Saenz Julienne + * + * 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 "qom/object_interfaces.h" +#include "qapi/error.h" +#include "block/thread-pool.h" +#include "sysemu/event-loop-base.h" + +typedef struct { + const char *name; + ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */ +} EventLoopBaseParamInfo; + +static void event_loop_base_instance_init(Object *obj) +{ + EventLoopBase *base = EVENT_LOOP_BASE(obj); + + base->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT; +} + +static EventLoopBaseParamInfo aio_max_batch_info = { + "aio-max-batch", offsetof(EventLoopBase, aio_max_batch), +}; +static EventLoopBaseParamInfo thread_pool_min_info = { + "thread-pool-min", offsetof(EventLoopBase, thread_pool_min), +}; +static EventLoopBaseParamInfo thread_pool_max_info = { + "thread-pool-max", offsetof(EventLoopBase, thread_pool_max), +}; + +static void event_loop_base_get_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + EventLoopBase *event_loop_base = EVENT_LOOP_BASE(obj); + EventLoopBaseParamInfo *info = opaque; + int64_t *field = (void *)event_loop_base + info->offset; + + visit_type_int64(v, name, field, errp); +} + +static void event_loop_base_set_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj); + EventLoopBase *base = EVENT_LOOP_BASE(obj); + EventLoopBaseParamInfo *info = opaque; + int64_t *field = (void *)base + info->offset; + int64_t value; + + if (!visit_type_int64(v, name, &value, errp)) { + return; + } + + if (value < 0) { + error_setg(errp, "%s value must be in range [0, %" PRId64 "]", + info->name, INT64_MAX); + return; + } + + *field = value; + + if (bc->update_params) { + bc->update_params(base, errp); + } + + return; +} + +static void event_loop_base_complete(UserCreatable *uc, Error **errp) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc); + EventLoopBase *base = EVENT_LOOP_BASE(uc); + + if (bc->init) { + bc->init(base, errp); + } +} + +static bool event_loop_base_can_be_deleted(UserCreatable *uc) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc); + EventLoopBase *backend = EVENT_LOOP_BASE(uc); + + if (bc->can_be_deleted) { + return bc->can_be_deleted(backend); + } + + return true; +} + +static void event_loop_base_class_init(ObjectClass *klass, void *class_data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); + ucc->complete = event_loop_base_complete; + ucc->can_be_deleted = event_loop_base_can_be_deleted; + + object_class_property_add(klass, "aio-max-batch", "int", + event_loop_base_get_param, + event_loop_base_set_param, + NULL, &aio_max_batch_info); + object_class_property_add(klass, "thread-pool-min", "int", + event_loop_base_get_param, + event_loop_base_set_param, + NULL, &thread_pool_min_info); + object_class_property_add(klass, "thread-pool-max", "int", + event_loop_base_get_param, + event_loop_base_set_param, + NULL, &thread_pool_max_info); +} + +static const TypeInfo event_loop_base_info = { + .name = TYPE_EVENT_LOOP_BASE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(EventLoopBase), + .instance_init = event_loop_base_instance_init, + .class_size = sizeof(EventLoopBaseClass), + .class_init = event_loop_base_class_init, + .abstract = true, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&event_loop_base_info); +} +type_init(register_types); diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index db3e1f393dfb..247400031c30 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; @@ -1327,16 +1344,19 @@ static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b, float_status *s, bool is_quiet) { int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); - int cmp; if (likely(ab_mask == float_cmask_normal)) { + FloatRelation cmp; + if (a->sign != b->sign) { goto a_sign; } - if (a->exp != b->exp) { - cmp = a->exp < b->exp ? -1 : 1; - } else { + if (a->exp == b->exp) { cmp = frac_cmp(a, b); + } else if (a->exp < b->exp) { + cmp = float_relation_less; + } else { + cmp = float_relation_greater; } if (a->sign) { cmp = -cmp; @@ -1416,6 +1436,7 @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt) parts_return_nan(a, s); return; case float_class_zero: + float_raise(float_flag_divbyzero, s); /* log2(0) = -inf */ a->cls = float_class_inf; a->sign = 1; diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 943e3301d209..1610472cfc47 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -390,7 +390,8 @@ bool float32_is_signaling_nan(float32 a_, float_status *status) static int pickNaN(FloatClass a_cls, FloatClass b_cls, bool aIsLargerSignificand, float_status *status) { -#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA) || \ + defined(TARGET_LOONGARCH64) || defined(TARGET_S390X) /* ARM mandated NaN propagation rules (see FPProcessNaNs()), take * the first of: * 1. A if it is signaling @@ -574,6 +575,29 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, return 1; } } +#elif defined(TARGET_LOONGARCH64) + /* + * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) + * case sets InvalidOp and returns the input value 'c' + */ + if (infzero) { + float_raise(float_flag_invalid | float_flag_invalid_imz, status); + return 2; + } + /* Prefer sNaN over qNaN, in the c, a, b order. */ + if (is_snan(c_cls)) { + return 2; + } else if (is_snan(a_cls)) { + return 0; + } else if (is_snan(b_cls)) { + return 1; + } else if (is_qnan(c_cls)) { + return 2; + } else if (is_qnan(a_cls)) { + return 0; + } else { + return 1; + } #elif defined(TARGET_PPC) /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer * to return an input NaN if we have one (ie c) rather than generating diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 7f524d437767..c7454c3eb1a1 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) \ @@ -874,10 +876,10 @@ static FloatParts128 *parts128_minmax(FloatParts128 *a, FloatParts128 *b, #define parts_minmax(A, B, S, F) \ PARTS_GENERIC_64_128(minmax, A)(A, B, S, F) -static int parts64_compare(FloatParts64 *a, FloatParts64 *b, - float_status *s, bool q); -static int parts128_compare(FloatParts128 *a, FloatParts128 *b, - float_status *s, bool q); +static FloatRelation parts64_compare(FloatParts64 *a, FloatParts64 *b, + float_status *s, bool q); +static FloatRelation parts128_compare(FloatParts128 *a, FloatParts128 *b, + float_status *s, bool q); #define parts_compare(A, B, S, Q) \ PARTS_GENERIC_64_128(compare, A)(A, B, S, Q) @@ -957,21 +959,23 @@ static void frac128_allones(FloatParts128 *a) #define frac_allones(A) FRAC_GENERIC_64_128(allones, A)(A) -static int frac64_cmp(FloatParts64 *a, FloatParts64 *b) +static FloatRelation frac64_cmp(FloatParts64 *a, FloatParts64 *b) { - return a->frac == b->frac ? 0 : a->frac < b->frac ? -1 : 1; + return (a->frac == b->frac ? float_relation_equal + : a->frac < b->frac ? float_relation_less + : float_relation_greater); } -static int frac128_cmp(FloatParts128 *a, FloatParts128 *b) +static FloatRelation frac128_cmp(FloatParts128 *a, FloatParts128 *b) { uint64_t ta = a->frac_hi, tb = b->frac_hi; if (ta == tb) { ta = a->frac_lo, tb = b->frac_lo; if (ta == tb) { - return 0; + return float_relation_equal; } } - return ta < tb ? -1 : 1; + return ta < tb ? float_relation_less : float_relation_greater; } #define frac_cmp(A, B) FRAC_GENERIC_64_128(cmp, A)(A, B) @@ -3154,6 +3158,60 @@ static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } +static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode, + int scale, float_status *s) +{ + int flags = 0; + Int128 r; + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + + switch (p.cls) { + case float_class_snan: + flags |= float_flag_invalid_snan; + /* fall through */ + case float_class_qnan: + flags |= float_flag_invalid; + r = UINT128_MAX; + break; + + case float_class_inf: + flags = float_flag_invalid | float_flag_invalid_cvti; + r = p.sign ? INT128_MIN : INT128_MAX; + break; + + case float_class_zero: + return int128_zero(); + + case float_class_normal: + if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) { + flags = float_flag_inexact; + } + + if (p.exp < 127) { + int shift = 127 - p.exp; + r = int128_urshift(int128_make128(p.frac_lo, p.frac_hi), shift); + if (p.sign) { + r = int128_neg(r); + } + } else if (p.exp == 127 && p.sign && p.frac_lo == 0 && + p.frac_hi == DECOMPOSED_IMPLICIT_BIT) { + r = INT128_MIN; + } else { + flags = float_flag_invalid | float_flag_invalid_cvti; + r = p.sign ? INT128_MIN : INT128_MAX; + } + break; + + default: + g_assert_not_reached(); + } + + float_raise(flags, s); + return r; +} + static int32_t floatx80_to_int32_scalbn(floatx80 a, FloatRoundMode rmode, int scale, float_status *s) { @@ -3236,6 +3294,11 @@ int64_t float128_to_int64(float128 a, float_status *s) return float128_to_int64_scalbn(a, s->float_rounding_mode, 0, s); } +Int128 float128_to_int128(float128 a, float_status *s) +{ + return float128_to_int128_scalbn(a, s->float_rounding_mode, 0, s); +} + int32_t floatx80_to_int32(floatx80 a, float_status *s) { return floatx80_to_int32_scalbn(a, s->float_rounding_mode, 0, s); @@ -3301,6 +3364,11 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *s) return float128_to_int64_scalbn(a, float_round_to_zero, 0, s); } +Int128 float128_to_int128_round_to_zero(float128 a, float_status *s) +{ + return float128_to_int128_scalbn(a, float_round_to_zero, 0, s); +} + int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *s) { return floatx80_to_int32_scalbn(a, float_round_to_zero, 0, s); @@ -3480,6 +3548,61 @@ static uint64_t float128_to_uint64_scalbn(float128 a, FloatRoundMode rmode, return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } +static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode, + int scale, float_status *s) +{ + int flags = 0; + Int128 r; + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + + switch (p.cls) { + case float_class_snan: + flags |= float_flag_invalid_snan; + /* fall through */ + case float_class_qnan: + flags |= float_flag_invalid; + r = UINT128_MAX; + break; + + case float_class_inf: + flags = float_flag_invalid | float_flag_invalid_cvti; + r = p.sign ? int128_zero() : UINT128_MAX; + break; + + case float_class_zero: + return int128_zero(); + + case float_class_normal: + if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) { + flags = float_flag_inexact; + if (p.cls == float_class_zero) { + r = int128_zero(); + break; + } + } + + if (p.sign) { + flags = float_flag_invalid | float_flag_invalid_cvti; + r = int128_zero(); + } else if (p.exp <= 127) { + int shift = 127 - p.exp; + r = int128_urshift(int128_make128(p.frac_lo, p.frac_hi), shift); + } else { + flags = float_flag_invalid | float_flag_invalid_cvti; + r = UINT128_MAX; + } + break; + + default: + g_assert_not_reached(); + } + + float_raise(flags, s); + return r; +} + uint8_t float16_to_uint8(float16 a, float_status *s) { return float16_to_uint8_scalbn(a, s->float_rounding_mode, 0, s); @@ -3540,6 +3663,11 @@ uint64_t float128_to_uint64(float128 a, float_status *s) return float128_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); } +Int128 float128_to_uint128(float128 a, float_status *s) +{ + return float128_to_uint128_scalbn(a, s->float_rounding_mode, 0, s); +} + uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *s) { return float16_to_uint16_scalbn(a, float_round_to_zero, 0, s); @@ -3595,6 +3723,11 @@ uint64_t float128_to_uint64_round_to_zero(float128 a, float_status *s) return float128_to_uint64_scalbn(a, float_round_to_zero, 0, s); } +Int128 float128_to_uint128_round_to_zero(float128 a, float_status *s) +{ + return float128_to_uint128_scalbn(a, float_round_to_zero, 0, s); +} + uint16_t bfloat16_to_uint16(bfloat16 a, float_status *s) { return bfloat16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s); @@ -3780,6 +3913,35 @@ bfloat16 int16_to_bfloat16(int16_t a, float_status *status) return int64_to_bfloat16_scalbn(a, 0, status); } +float128 int128_to_float128(Int128 a, float_status *status) +{ + FloatParts128 p = { }; + int shift; + + if (int128_nz(a)) { + p.cls = float_class_normal; + if (!int128_nonneg(a)) { + p.sign = true; + a = int128_neg(a); + } + + shift = clz64(int128_gethi(a)); + if (shift == 64) { + shift += clz64(int128_getlo(a)); + } + + p.exp = 127 - shift; + a = int128_lshift(a, shift); + + p.frac_hi = int128_gethi(a); + p.frac_lo = int128_getlo(a); + } else { + p.cls = float_class_zero; + } + + return float128_round_pack_canonical(&p, status); +} + float128 int64_to_float128(int64_t a, float_status *status) { FloatParts128 p; @@ -3969,6 +4131,31 @@ float128 uint64_to_float128(uint64_t a, float_status *status) return float128_round_pack_canonical(&p, status); } +float128 uint128_to_float128(Int128 a, float_status *status) +{ + FloatParts128 p = { }; + int shift; + + if (int128_nz(a)) { + p.cls = float_class_normal; + + shift = clz64(int128_gethi(a)); + if (shift == 64) { + shift += clz64(int128_getlo(a)); + } + + p.exp = 127 - shift; + a = int128_lshift(a, shift); + + p.frac_hi = int128_gethi(a); + p.frac_lo = int128_getlo(a); + } else { + p.cls = float_class_zero; + } + + return float128_round_pack_canonical(&p, status); +} + /* * Minimum and maximum */ diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index d06a0f7b8326..5cafcd770318 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -10,6 +10,7 @@ */ #include "qemu/osdep.h" +#include #include #include #include @@ -21,7 +22,6 @@ #include #endif #include -#include "qemu-common.h" #include "qemu/sockets.h" #include "qemu/xattr.h" #include "9p-iov-marshal.h" @@ -640,7 +640,7 @@ static int do_create_others(int type, struct iovec *iovec) if (retval < 0) { goto err_out; } - retval = mkdir(path.data, mode); + retval = g_mkdir(path.data, mode); break; case T_SYMLINK: retval = proxy_unmarshal(iovec, offset, "ss", &oldpath, &path); diff --git a/gdb-xml/i386-32bit.xml b/gdb-xml/i386-32bit.xml index 872fcea9c25a..7a66a02b67e3 100644 --- a/gdb-xml/i386-32bit.xml +++ b/gdb-xml/i386-32bit.xml @@ -110,7 +110,7 @@ - + diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml new file mode 100644 index 000000000000..2d8a1f6b7349 --- /dev/null +++ b/gdb-xml/loongarch-base64.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb-xml/loongarch-fpu.xml b/gdb-xml/loongarch-fpu.xml new file mode 100644 index 000000000000..78e42cf5ddbf --- /dev/null +++ b/gdb-xml/loongarch-fpu.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb-xml/riscv-32bit-cpu.xml b/gdb-xml/riscv-32bit-cpu.xml index 0d07aaec857b..466f2c06485f 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 1eaae9119e38..24aa0870312f 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 b8aa424ae4b3..c4d83de09b98 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 794854cc011b..d0f17f9984b3 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.c deleted file mode 100644 index c8375e3c3ffe..000000000000 --- a/gdbstub.c +++ /dev/null @@ -1,3594 +0,0 @@ -/* - * gdb server stub - * - * This implements a subset of the remote protocol as described in: - * - * https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * SPDX-License-Identifier: LGPL-2.0+ - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/ctype.h" -#include "qemu/cutils.h" -#include "qemu/module.h" -#include "trace/trace-root.h" -#include "exec/gdbstub.h" -#ifdef CONFIG_USER_ONLY -#include "qemu.h" -#else -#include "monitor/monitor.h" -#include "chardev/char.h" -#include "chardev/char-fe.h" -#include "hw/cpu/cluster.h" -#include "hw/boards.h" -#endif - -#define MAX_PACKET_LENGTH 4096 - -#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 "sysemu/replay.h" - -#ifdef CONFIG_USER_ONLY -#define GDB_ATTACHED "0" -#else -#define GDB_ATTACHED "1" -#endif - -#ifndef CONFIG_USER_ONLY -static int phy_memory_mode; -#endif - -static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr, - uint8_t *buf, int len, bool is_write) -{ - CPUClass *cc; - -#ifndef CONFIG_USER_ONLY - if (phy_memory_mode) { - if (is_write) { - cpu_physical_memory_write(addr, buf, len); - } else { - cpu_physical_memory_read(addr, buf, len); - } - return 0; - } -#endif - - cc = CPU_GET_CLASS(cpu); - if (cc->memory_rw_debug) { - return cc->memory_rw_debug(cpu, addr, buf, len, is_write); - } - return cpu_memory_rw_debug(cpu, addr, buf, len, is_write); -} - -/* Return the GDB index for a given vCPU state. - * - * For user mode this is simply the thread id. In system mode GDB - * numbers CPUs from 1 as 0 is reserved as an "any cpu" index. - */ -static inline int cpu_gdb_index(CPUState *cpu) -{ -#if defined(CONFIG_USER_ONLY) - TaskState *ts = (TaskState *) cpu->opaque; - return ts ? ts->ts_tid : -1; -#else - return cpu->cpu_index + 1; -#endif -} - -enum { - GDB_SIGNAL_0 = 0, - GDB_SIGNAL_INT = 2, - GDB_SIGNAL_QUIT = 3, - GDB_SIGNAL_TRAP = 5, - GDB_SIGNAL_ABRT = 6, - GDB_SIGNAL_ALRM = 14, - GDB_SIGNAL_IO = 23, - GDB_SIGNAL_XCPU = 24, - GDB_SIGNAL_UNKNOWN = 143 -}; - -#ifdef CONFIG_USER_ONLY - -/* Map target signal numbers to GDB protocol signal numbers and vice - * versa. For user emulation's currently supported systems, we can - * assume most signals are defined. - */ - -static int gdb_signal_table[] = { - 0, - TARGET_SIGHUP, - TARGET_SIGINT, - TARGET_SIGQUIT, - TARGET_SIGILL, - TARGET_SIGTRAP, - TARGET_SIGABRT, - -1, /* SIGEMT */ - TARGET_SIGFPE, - TARGET_SIGKILL, - TARGET_SIGBUS, - TARGET_SIGSEGV, - TARGET_SIGSYS, - TARGET_SIGPIPE, - TARGET_SIGALRM, - TARGET_SIGTERM, - TARGET_SIGURG, - TARGET_SIGSTOP, - TARGET_SIGTSTP, - TARGET_SIGCONT, - TARGET_SIGCHLD, - TARGET_SIGTTIN, - TARGET_SIGTTOU, - TARGET_SIGIO, - TARGET_SIGXCPU, - TARGET_SIGXFSZ, - TARGET_SIGVTALRM, - TARGET_SIGPROF, - TARGET_SIGWINCH, - -1, /* SIGLOST */ - TARGET_SIGUSR1, - TARGET_SIGUSR2, -#ifdef TARGET_SIGPWR - TARGET_SIGPWR, -#else - -1, -#endif - -1, /* SIGPOLL */ - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, -#ifdef __SIGRTMIN - __SIGRTMIN + 1, - __SIGRTMIN + 2, - __SIGRTMIN + 3, - __SIGRTMIN + 4, - __SIGRTMIN + 5, - __SIGRTMIN + 6, - __SIGRTMIN + 7, - __SIGRTMIN + 8, - __SIGRTMIN + 9, - __SIGRTMIN + 10, - __SIGRTMIN + 11, - __SIGRTMIN + 12, - __SIGRTMIN + 13, - __SIGRTMIN + 14, - __SIGRTMIN + 15, - __SIGRTMIN + 16, - __SIGRTMIN + 17, - __SIGRTMIN + 18, - __SIGRTMIN + 19, - __SIGRTMIN + 20, - __SIGRTMIN + 21, - __SIGRTMIN + 22, - __SIGRTMIN + 23, - __SIGRTMIN + 24, - __SIGRTMIN + 25, - __SIGRTMIN + 26, - __SIGRTMIN + 27, - __SIGRTMIN + 28, - __SIGRTMIN + 29, - __SIGRTMIN + 30, - __SIGRTMIN + 31, - -1, /* SIGCANCEL */ - __SIGRTMIN, - __SIGRTMIN + 32, - __SIGRTMIN + 33, - __SIGRTMIN + 34, - __SIGRTMIN + 35, - __SIGRTMIN + 36, - __SIGRTMIN + 37, - __SIGRTMIN + 38, - __SIGRTMIN + 39, - __SIGRTMIN + 40, - __SIGRTMIN + 41, - __SIGRTMIN + 42, - __SIGRTMIN + 43, - __SIGRTMIN + 44, - __SIGRTMIN + 45, - __SIGRTMIN + 46, - __SIGRTMIN + 47, - __SIGRTMIN + 48, - __SIGRTMIN + 49, - __SIGRTMIN + 50, - __SIGRTMIN + 51, - __SIGRTMIN + 52, - __SIGRTMIN + 53, - __SIGRTMIN + 54, - __SIGRTMIN + 55, - __SIGRTMIN + 56, - __SIGRTMIN + 57, - __SIGRTMIN + 58, - __SIGRTMIN + 59, - __SIGRTMIN + 60, - __SIGRTMIN + 61, - __SIGRTMIN + 62, - __SIGRTMIN + 63, - __SIGRTMIN + 64, - __SIGRTMIN + 65, - __SIGRTMIN + 66, - __SIGRTMIN + 67, - __SIGRTMIN + 68, - __SIGRTMIN + 69, - __SIGRTMIN + 70, - __SIGRTMIN + 71, - __SIGRTMIN + 72, - __SIGRTMIN + 73, - __SIGRTMIN + 74, - __SIGRTMIN + 75, - __SIGRTMIN + 76, - __SIGRTMIN + 77, - __SIGRTMIN + 78, - __SIGRTMIN + 79, - __SIGRTMIN + 80, - __SIGRTMIN + 81, - __SIGRTMIN + 82, - __SIGRTMIN + 83, - __SIGRTMIN + 84, - __SIGRTMIN + 85, - __SIGRTMIN + 86, - __SIGRTMIN + 87, - __SIGRTMIN + 88, - __SIGRTMIN + 89, - __SIGRTMIN + 90, - __SIGRTMIN + 91, - __SIGRTMIN + 92, - __SIGRTMIN + 93, - __SIGRTMIN + 94, - __SIGRTMIN + 95, - -1, /* SIGINFO */ - -1, /* UNKNOWN */ - -1, /* DEFAULT */ - -1, - -1, - -1, - -1, - -1, - -1 -#endif -}; -#else -/* In system mode we only need SIGINT and SIGTRAP; other signals - are not yet supported. */ - -enum { - TARGET_SIGINT = 2, - TARGET_SIGTRAP = 5 -}; - -static int gdb_signal_table[] = { - -1, - -1, - TARGET_SIGINT, - -1, - -1, - TARGET_SIGTRAP -}; -#endif - -#ifdef CONFIG_USER_ONLY -static int target_signal_to_gdb (int sig) -{ - int i; - for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++) - if (gdb_signal_table[i] == sig) - return i; - return GDB_SIGNAL_UNKNOWN; -} -#endif - -static int gdb_signal_to_target (int sig) -{ - if (sig < ARRAY_SIZE (gdb_signal_table)) - return gdb_signal_table[sig]; - else - return -1; -} - -typedef struct GDBRegisterState { - int base_reg; - int num_regs; - gdb_get_reg_cb get_reg; - gdb_set_reg_cb set_reg; - const char *xml; - struct GDBRegisterState *next; -} GDBRegisterState; - -typedef struct GDBProcess { - uint32_t pid; - bool attached; - - char target_xml[1024]; -} GDBProcess; - -enum RSState { - RS_INACTIVE, - RS_IDLE, - RS_GETLINE, - RS_GETLINE_ESC, - RS_GETLINE_RLE, - RS_CHKSUM1, - RS_CHKSUM2, -}; -typedef struct GDBState { - bool init; /* have we been initialised? */ - CPUState *c_cpu; /* current CPU for step/continue ops */ - CPUState *g_cpu; /* current CPU for other ops */ - CPUState *query_cpu; /* for q{f|s}ThreadInfo */ - enum RSState state; /* parsing state */ - char line_buf[MAX_PACKET_LENGTH]; - int line_buf_index; - int line_sum; /* running checksum */ - int line_csum; /* checksum at the end of the packet */ - GByteArray *last_packet; - int signal; -#ifdef CONFIG_USER_ONLY - int fd; - char *socket_path; - int running_state; -#else - CharBackend chr; - Chardev *mon_chr; -#endif - bool multiprocess; - GDBProcess *processes; - int process_num; - char syscall_buf[256]; - gdb_syscall_complete_cb current_syscall_cb; - GString *str_buf; - GByteArray *mem_buf; - int sstep_flags; - int supported_sstep_flags; -} GDBState; - -static GDBState gdbserver_state; - -static void init_gdbserver_state(void) -{ - g_assert(!gdbserver_state.init); - memset(&gdbserver_state, 0, sizeof(GDBState)); - gdbserver_state.init = true; - gdbserver_state.str_buf = g_string_new(NULL); - gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH); - 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. - */ - gdbserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; - gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags; - -} - -#ifndef CONFIG_USER_ONLY -static void reset_gdbserver_state(void) -{ - g_free(gdbserver_state.processes); - gdbserver_state.processes = NULL; - gdbserver_state.process_num = 0; -} -#endif - -bool gdb_has_xml; - -#ifdef CONFIG_USER_ONLY - -static int get_char(void) -{ - uint8_t ch; - int ret; - - for(;;) { - ret = recv(gdbserver_state.fd, &ch, 1, 0); - if (ret < 0) { - if (errno == ECONNRESET) - gdbserver_state.fd = -1; - if (errno != EINTR) - return -1; - } else if (ret == 0) { - close(gdbserver_state.fd); - gdbserver_state.fd = -1; - return -1; - } else { - break; - } - } - return ch; -} -#endif - -static enum { - GDB_SYS_UNKNOWN, - GDB_SYS_ENABLED, - GDB_SYS_DISABLED, -} gdb_syscall_mode; - -/* Decide if either remote gdb syscalls or native file IO should be used. */ -int use_gdb_syscalls(void) -{ - SemihostingTarget target = semihosting_get_target(); - if (target == SEMIHOSTING_TARGET_NATIVE) { - /* -semihosting-config target=native */ - return false; - } else if (target == SEMIHOSTING_TARGET_GDB) { - /* -semihosting-config target=gdb */ - return true; - } - - /* -semihosting-config target=auto */ - /* On the first call check if gdb is connected and remember. */ - if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { - gdb_syscall_mode = gdbserver_state.init ? - GDB_SYS_ENABLED : GDB_SYS_DISABLED; - } - return gdb_syscall_mode == GDB_SYS_ENABLED; -} - -static bool stub_can_reverse(void) -{ -#ifdef CONFIG_USER_ONLY - return false; -#else - return replay_mode == REPLAY_MODE_PLAY; -#endif -} - -/* Resume execution. */ -static inline void gdb_continue(void) -{ - -#ifdef CONFIG_USER_ONLY - gdbserver_state.running_state = 1; - trace_gdbstub_op_continue(); -#else - if (!runstate_needs_reset()) { - trace_gdbstub_op_continue(); - vm_start(); - } -#endif -} - -/* - * Resume execution, per CPU actions. For user-mode emulation it's - * equivalent to gdb_continue. - */ -static int gdb_continue_partial(char *newstates) -{ - CPUState *cpu; - int res = 0; -#ifdef CONFIG_USER_ONLY - /* - * This is not exactly accurate, but it's an improvement compared to the - * previous situation, where only one CPU would be single-stepped. - */ - CPU_FOREACH(cpu) { - if (newstates[cpu->cpu_index] == 's') { - trace_gdbstub_op_stepping(cpu->cpu_index); - cpu_single_step(cpu, gdbserver_state.sstep_flags); - } - } - gdbserver_state.running_state = 1; -#else - int flag = 0; - - if (!runstate_needs_reset()) { - if (vm_prepare_start()) { - return 0; - } - - CPU_FOREACH(cpu) { - switch (newstates[cpu->cpu_index]) { - case 0: - case 1: - break; /* nothing to do here */ - case 's': - trace_gdbstub_op_stepping(cpu->cpu_index); - cpu_single_step(cpu, gdbserver_state.sstep_flags); - cpu_resume(cpu); - flag = 1; - break; - case 'c': - trace_gdbstub_op_continue_cpu(cpu->cpu_index); - cpu_resume(cpu); - flag = 1; - break; - default: - res = -1; - break; - } - } - } - if (flag) { - qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); - } -#endif - return res; -} - -static void put_buffer(const uint8_t *buf, int len) -{ -#ifdef CONFIG_USER_ONLY - int ret; - - while (len > 0) { - ret = send(gdbserver_state.fd, buf, len, 0); - if (ret < 0) { - if (errno != EINTR) - return; - } else { - buf += ret; - len -= ret; - } - } -#else - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ - qemu_chr_fe_write_all(&gdbserver_state.chr, buf, len); -#endif -} - -static inline int fromhex(int v) -{ - if (v >= '0' && v <= '9') - return v - '0'; - else if (v >= 'A' && v <= 'F') - return v - 'A' + 10; - else if (v >= 'a' && v <= 'f') - return v - 'a' + 10; - else - return 0; -} - -static inline int tohex(int v) -{ - if (v < 10) - return v + '0'; - else - return v - 10 + 'a'; -} - -/* writes 2*len+1 bytes in buf */ -static void memtohex(GString *buf, const uint8_t *mem, int len) -{ - int i, c; - for(i = 0; i < len; i++) { - c = mem[i]; - g_string_append_c(buf, tohex(c >> 4)); - g_string_append_c(buf, tohex(c & 0xf)); - } - g_string_append_c(buf, '\0'); -} - -static void hextomem(GByteArray *mem, const char *buf, int len) -{ - int i; - - for(i = 0; i < len; i++) { - guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]); - g_byte_array_append(mem, &byte, 1); - buf += 2; - } -} - -static void hexdump(const char *buf, int len, - void (*trace_fn)(size_t ofs, char const *text)) -{ - char line_buffer[3 * 16 + 4 + 16 + 1]; - - size_t i; - for (i = 0; i < len || (i & 0xF); ++i) { - size_t byte_ofs = i & 15; - - if (byte_ofs == 0) { - memset(line_buffer, ' ', 3 * 16 + 4 + 16); - line_buffer[3 * 16 + 4 + 16] = 0; - } - - size_t col_group = (i >> 2) & 3; - size_t hex_col = byte_ofs * 3 + col_group; - size_t txt_col = 3 * 16 + 4 + byte_ofs; - - if (i < len) { - char value = buf[i]; - - line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF); - line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF); - line_buffer[txt_col + 0] = (value >= ' ' && value < 127) - ? value - : '.'; - } - - if (byte_ofs == 0xF) - trace_fn(i & -16, line_buffer); - } -} - -/* return -1 if error, 0 if OK */ -static int put_packet_binary(const char *buf, int len, bool dump) -{ - int csum, i; - uint8_t footer[3]; - - if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) { - hexdump(buf, len, trace_gdbstub_io_binaryreply); - } - - for(;;) { - g_byte_array_set_size(gdbserver_state.last_packet, 0); - g_byte_array_append(gdbserver_state.last_packet, - (const uint8_t *) "$", 1); - g_byte_array_append(gdbserver_state.last_packet, - (const uint8_t *) buf, len); - csum = 0; - for(i = 0; i < len; i++) { - csum += buf[i]; - } - footer[0] = '#'; - footer[1] = tohex((csum >> 4) & 0xf); - footer[2] = tohex((csum) & 0xf); - g_byte_array_append(gdbserver_state.last_packet, footer, 3); - - put_buffer(gdbserver_state.last_packet->data, - gdbserver_state.last_packet->len); - -#ifdef CONFIG_USER_ONLY - i = get_char(); - if (i < 0) - return -1; - if (i == '+') - break; -#else - break; -#endif - } - return 0; -} - -/* return -1 if error, 0 if OK */ -static int put_packet(const char *buf) -{ - trace_gdbstub_io_reply(buf); - - return put_packet_binary(buf, strlen(buf), false); -} - -static void put_strbuf(void) -{ - put_packet(gdbserver_state.str_buf->str); -} - -/* Encode data using the encoding for 'x' packets. */ -static void memtox(GString *buf, const char *mem, int len) -{ - char c; - - while (len--) { - c = *(mem++); - switch (c) { - case '#': case '$': case '*': case '}': - g_string_append_c(buf, '}'); - g_string_append_c(buf, c ^ 0x20); - break; - default: - g_string_append_c(buf, c); - break; - } - } -} - -static uint32_t gdb_get_cpu_pid(CPUState *cpu) -{ - /* TODO: In user mode, we should use the task state PID */ - if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) { - /* Return the default process' PID */ - int index = gdbserver_state.process_num - 1; - return gdbserver_state.processes[index].pid; - } - return cpu->cluster_index + 1; -} - -static GDBProcess *gdb_get_process(uint32_t pid) -{ - int i; - - if (!pid) { - /* 0 means any process, we take the first one */ - return &gdbserver_state.processes[0]; - } - - for (i = 0; i < gdbserver_state.process_num; i++) { - if (gdbserver_state.processes[i].pid == pid) { - return &gdbserver_state.processes[i]; - } - } - - return NULL; -} - -static GDBProcess *gdb_get_cpu_process(CPUState *cpu) -{ - return gdb_get_process(gdb_get_cpu_pid(cpu)); -} - -static CPUState *find_cpu(uint32_t thread_id) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - if (cpu_gdb_index(cpu) == thread_id) { - return cpu; - } - } - - return NULL; -} - -static CPUState *get_first_cpu_in_process(GDBProcess *process) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - if (gdb_get_cpu_pid(cpu) == process->pid) { - return cpu; - } - } - - return NULL; -} - -static CPUState *gdb_next_cpu_in_process(CPUState *cpu) -{ - uint32_t pid = gdb_get_cpu_pid(cpu); - cpu = CPU_NEXT(cpu); - - while (cpu) { - if (gdb_get_cpu_pid(cpu) == pid) { - break; - } - - cpu = CPU_NEXT(cpu); - } - - return cpu; -} - -/* Return the cpu following @cpu, while ignoring unattached processes. */ -static CPUState *gdb_next_attached_cpu(CPUState *cpu) -{ - cpu = CPU_NEXT(cpu); - - while (cpu) { - if (gdb_get_cpu_process(cpu)->attached) { - break; - } - - cpu = CPU_NEXT(cpu); - } - - return cpu; -} - -/* Return the first attached cpu */ -static CPUState *gdb_first_attached_cpu(void) -{ - CPUState *cpu = first_cpu; - GDBProcess *process = gdb_get_cpu_process(cpu); - - if (!process->attached) { - return gdb_next_attached_cpu(cpu); - } - - return cpu; -} - -static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) -{ - GDBProcess *process; - CPUState *cpu; - - if (!pid && !tid) { - /* 0 means any process/thread, we take the first attached one */ - return gdb_first_attached_cpu(); - } else if (pid && !tid) { - /* any thread in a specific process */ - process = gdb_get_process(pid); - - if (process == NULL) { - return NULL; - } - - if (!process->attached) { - return NULL; - } - - return get_first_cpu_in_process(process); - } else { - /* a specific thread */ - cpu = find_cpu(tid); - - if (cpu == NULL) { - return NULL; - } - - process = gdb_get_cpu_process(cpu); - - if (pid && process->pid != pid) { - return NULL; - } - - if (!process->attached) { - return NULL; - } - - return cpu; - } -} - -static const char *get_feature_xml(const char *p, const char **newp, - GDBProcess *process) -{ - size_t len; - int i; - const char *name; - CPUState *cpu = get_first_cpu_in_process(process); - CPUClass *cc = CPU_GET_CLASS(cpu); - - len = 0; - while (p[len] && p[len] != ':') - len++; - *newp = p + len; - - name = NULL; - if (strncmp(p, "target.xml", len) == 0) { - char *buf = process->target_xml; - const size_t buf_sz = sizeof(process->target_xml); - - /* Generate the XML description for this CPU. */ - if (!buf[0]) { - GDBRegisterState *r; - - pstrcat(buf, buf_sz, - "" - "" - ""); - if (cc->gdb_arch_name) { - gchar *arch = cc->gdb_arch_name(cpu); - pstrcat(buf, buf_sz, ""); - pstrcat(buf, buf_sz, arch); - pstrcat(buf, buf_sz, ""); - g_free(arch); - } - pstrcat(buf, buf_sz, "gdb_core_xml_file); - pstrcat(buf, buf_sz, "\"/>"); - for (r = cpu->gdb_regs; r; r = r->next) { - pstrcat(buf, buf_sz, "xml); - pstrcat(buf, buf_sz, "\"/>"); - } - pstrcat(buf, buf_sz, ""); - } - return buf; - } - if (cc->gdb_get_dynamic_xml) { - char *xmlname = g_strndup(p, len); - const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname); - - g_free(xmlname); - if (xml) { - return xml; - } - } - for (i = 0; ; i++) { - name = xml_builtin[i][0]; - if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len)) - break; - } - return name ? xml_builtin[i][1] : NULL; -} - -static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - CPUArchState *env = cpu->env_ptr; - GDBRegisterState *r; - - if (reg < cc->gdb_num_core_regs) { - return cc->gdb_read_register(cpu, buf, reg); - } - - for (r = cpu->gdb_regs; r; r = r->next) { - if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { - return r->get_reg(env, buf, reg - r->base_reg); - } - } - return 0; -} - -static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - CPUArchState *env = cpu->env_ptr; - GDBRegisterState *r; - - if (reg < cc->gdb_num_core_regs) { - return cc->gdb_write_register(cpu, mem_buf, reg); - } - - for (r = cpu->gdb_regs; r; r = r->next) { - if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { - return r->set_reg(env, mem_buf, reg - r->base_reg); - } - } - return 0; -} - -/* Register a supplemental set of CPU registers. If g_pos is nonzero it - specifies the first register number and these registers are included in - a standard "g" packet. Direction is relative to gdb, i.e. get_reg is - gdb reading a CPU register, and set_reg is gdb modifying a CPU register. - */ - -void gdb_register_coprocessor(CPUState *cpu, - gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, - int num_regs, const char *xml, int g_pos) -{ - GDBRegisterState *s; - GDBRegisterState **p; - - p = &cpu->gdb_regs; - while (*p) { - /* Check for duplicates. */ - if (strcmp((*p)->xml, xml) == 0) - return; - p = &(*p)->next; - } - - s = g_new0(GDBRegisterState, 1); - s->base_reg = cpu->gdb_num_regs; - s->num_regs = num_regs; - s->get_reg = get_reg; - s->set_reg = set_reg; - s->xml = xml; - - /* Add to end of list. */ - cpu->gdb_num_regs += num_regs; - *p = s; - if (g_pos) { - if (g_pos != s->base_reg) { - error_report("Error: Bad gdb register numbering for '%s', " - "expected %d got %d", xml, g_pos, s->base_reg); - } else { - cpu->gdb_num_g_regs = cpu->gdb_num_regs; - } - } -} - -#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); - 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) -{ - CPUState *cpu = gdbserver_state.c_cpu; - - cpu_synchronize_state(cpu); - cpu_set_pc(cpu, pc); -} - -static void gdb_append_thread_id(CPUState *cpu, GString *buf) -{ - if (gdbserver_state.multiprocess) { - g_string_append_printf(buf, "p%02x.%02x", - gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu)); - } else { - g_string_append_printf(buf, "%02x", cpu_gdb_index(cpu)); - } -} - -typedef enum GDBThreadIdKind { - GDB_ONE_THREAD = 0, - GDB_ALL_THREADS, /* One process, all threads */ - GDB_ALL_PROCESSES, - GDB_READ_THREAD_ERR -} GDBThreadIdKind; - -static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf, - uint32_t *pid, uint32_t *tid) -{ - unsigned long p, t; - int ret; - - if (*buf == 'p') { - buf++; - ret = qemu_strtoul(buf, &buf, 16, &p); - - if (ret) { - return GDB_READ_THREAD_ERR; - } - - /* Skip '.' */ - buf++; - } else { - p = 1; - } - - ret = qemu_strtoul(buf, &buf, 16, &t); - - if (ret) { - return GDB_READ_THREAD_ERR; - } - - *end_buf = buf; - - if (p == -1) { - return GDB_ALL_PROCESSES; - } - - if (pid) { - *pid = p; - } - - if (t == -1) { - return GDB_ALL_THREADS; - } - - if (tid) { - *tid = t; - } - - return GDB_ONE_THREAD; -} - -/** - * gdb_handle_vcont - Parses and handles a vCont packet. - * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is - * a format error, 0 on success. - */ -static int gdb_handle_vcont(const char *p) -{ - int res, signal = 0; - char cur_action; - char *newstates; - unsigned long tmp; - uint32_t pid, tid; - GDBProcess *process; - CPUState *cpu; - GDBThreadIdKind kind; -#ifdef CONFIG_USER_ONLY - int max_cpus = 1; /* global variable max_cpus exists only in system mode */ - - CPU_FOREACH(cpu) { - max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus; - } -#else - MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int max_cpus = ms->smp.max_cpus; -#endif - /* uninitialised CPUs stay 0 */ - newstates = g_new0(char, max_cpus); - - /* mark valid CPUs with 1 */ - CPU_FOREACH(cpu) { - newstates[cpu->cpu_index] = 1; - } - - /* - * res keeps track of what error we are returning, with -ENOTSUP meaning - * that the command is unknown or unsupported, thus returning an empty - * packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid, - * or incorrect parameters passed. - */ - res = 0; - while (*p) { - if (*p++ != ';') { - res = -ENOTSUP; - goto out; - } - - cur_action = *p++; - if (cur_action == 'C' || cur_action == 'S') { - cur_action = qemu_tolower(cur_action); - res = qemu_strtoul(p, &p, 16, &tmp); - if (res) { - goto out; - } - signal = gdb_signal_to_target(tmp); - } else if (cur_action != 'c' && cur_action != 's') { - /* unknown/invalid/unsupported command */ - res = -ENOTSUP; - goto out; - } - - if (*p == '\0' || *p == ';') { - /* - * No thread specifier, action is on "all threads". The - * specification is unclear regarding the process to act on. We - * choose all processes. - */ - kind = GDB_ALL_PROCESSES; - } else if (*p++ == ':') { - kind = read_thread_id(p, &p, &pid, &tid); - } else { - res = -ENOTSUP; - goto out; - } - - switch (kind) { - case GDB_READ_THREAD_ERR: - res = -EINVAL; - goto out; - - case GDB_ALL_PROCESSES: - cpu = gdb_first_attached_cpu(); - while (cpu) { - if (newstates[cpu->cpu_index] == 1) { - newstates[cpu->cpu_index] = cur_action; - } - - cpu = gdb_next_attached_cpu(cpu); - } - break; - - case GDB_ALL_THREADS: - process = gdb_get_process(pid); - - if (!process->attached) { - res = -EINVAL; - goto out; - } - - cpu = get_first_cpu_in_process(process); - while (cpu) { - if (newstates[cpu->cpu_index] == 1) { - newstates[cpu->cpu_index] = cur_action; - } - - cpu = gdb_next_cpu_in_process(cpu); - } - break; - - case GDB_ONE_THREAD: - cpu = gdb_get_cpu(pid, tid); - - /* invalid CPU/thread specified */ - if (!cpu) { - res = -EINVAL; - goto out; - } - - /* only use if no previous match occourred */ - if (newstates[cpu->cpu_index] == 1) { - newstates[cpu->cpu_index] = cur_action; - } - break; - } - } - gdbserver_state.signal = signal; - gdb_continue_partial(newstates); - -out: - g_free(newstates); - - return res; -} - -typedef union GdbCmdVariant { - const char *data; - uint8_t opcode; - unsigned long val_ul; - unsigned long long val_ull; - struct { - GDBThreadIdKind kind; - uint32_t pid; - uint32_t tid; - } thread_id; -} GdbCmdVariant; - -#define get_param(p, i) (&g_array_index(p, GdbCmdVariant, i)) - -static const char *cmd_next_param(const char *param, const char delimiter) -{ - static const char all_delimiters[] = ",;:="; - char curr_delimiters[2] = {0}; - const char *delimiters; - - if (delimiter == '?') { - delimiters = all_delimiters; - } else if (delimiter == '0') { - return strchr(param, '\0'); - } else if (delimiter == '.' && *param) { - return param + 1; - } else { - curr_delimiters[0] = delimiter; - delimiters = curr_delimiters; - } - - param += strcspn(param, delimiters); - if (*param) { - param++; - } - return param; -} - -static int cmd_parse_params(const char *data, const char *schema, - GArray *params) -{ - const char *curr_schema, *curr_data; - - g_assert(schema); - g_assert(params->len == 0); - - curr_schema = schema; - curr_data = data; - while (curr_schema[0] && curr_schema[1] && *curr_data) { - GdbCmdVariant this_param; - - switch (curr_schema[0]) { - case 'l': - if (qemu_strtoul(curr_data, &curr_data, 16, - &this_param.val_ul)) { - return -EINVAL; - } - curr_data = cmd_next_param(curr_data, curr_schema[1]); - g_array_append_val(params, this_param); - break; - case 'L': - if (qemu_strtou64(curr_data, &curr_data, 16, - (uint64_t *)&this_param.val_ull)) { - return -EINVAL; - } - curr_data = cmd_next_param(curr_data, curr_schema[1]); - g_array_append_val(params, this_param); - break; - case 's': - this_param.data = curr_data; - curr_data = cmd_next_param(curr_data, curr_schema[1]); - g_array_append_val(params, this_param); - break; - case 'o': - this_param.opcode = *(uint8_t *)curr_data; - curr_data = cmd_next_param(curr_data, curr_schema[1]); - g_array_append_val(params, this_param); - break; - case 't': - this_param.thread_id.kind = - read_thread_id(curr_data, &curr_data, - &this_param.thread_id.pid, - &this_param.thread_id.tid); - curr_data = cmd_next_param(curr_data, curr_schema[1]); - g_array_append_val(params, this_param); - break; - case '?': - curr_data = cmd_next_param(curr_data, curr_schema[1]); - break; - default: - return -EINVAL; - } - curr_schema += 2; - } - - return 0; -} - -typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx); - -/* - * cmd_startswith -> cmd is compared using startswith - * - * - * schema definitions: - * Each schema parameter entry consists of 2 chars, - * the first char represents the parameter type handling - * the second char represents the delimiter for the next parameter - * - * Currently supported schema types: - * 'l' -> unsigned long (stored in .val_ul) - * 'L' -> unsigned long long (stored in .val_ull) - * 's' -> string (stored in .data) - * 'o' -> single char (stored in .opcode) - * 't' -> thread id (stored in .thread_id) - * '?' -> skip according to delimiter - * - * Currently supported delimiters: - * '?' -> Stop at any delimiter (",;:=\0") - * '0' -> Stop at "\0" - * '.' -> Skip 1 char unless reached "\0" - * Any other value is treated as the delimiter value itself - */ -typedef struct GdbCmdParseEntry { - GdbCmdHandler handler; - const char *cmd; - bool cmd_startswith; - const char *schema; -} GdbCmdParseEntry; - -static inline int startswith(const char *string, const char *pattern) -{ - return !strncmp(string, pattern, strlen(pattern)); -} - -static int process_string_cmd(void *user_ctx, const char *data, - const GdbCmdParseEntry *cmds, int num_cmds) -{ - int i; - g_autoptr(GArray) params = g_array_new(false, true, sizeof(GdbCmdVariant)); - - if (!cmds) { - return -1; - } - - for (i = 0; i < num_cmds; i++) { - const GdbCmdParseEntry *cmd = &cmds[i]; - g_assert(cmd->handler && cmd->cmd); - - if ((cmd->cmd_startswith && !startswith(data, cmd->cmd)) || - (!cmd->cmd_startswith && strcmp(cmd->cmd, data))) { - continue; - } - - if (cmd->schema) { - if (cmd_parse_params(&data[strlen(cmd->cmd)], - cmd->schema, params)) { - return -1; - } - } - - cmd->handler(params, user_ctx); - return 0; - } - - return -1; -} - -static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd) -{ - if (!data) { - return; - } - - g_string_set_size(gdbserver_state.str_buf, 0); - g_byte_array_set_size(gdbserver_state.mem_buf, 0); - - /* In case there was an error during the command parsing we must - * send a NULL packet to indicate the command is not supported */ - if (process_string_cmd(NULL, data, cmd, 1)) { - put_packet(""); - } -} - -static void handle_detach(GArray *params, void *user_ctx) -{ - GDBProcess *process; - uint32_t pid = 1; - - if (gdbserver_state.multiprocess) { - if (!params->len) { - put_packet("E22"); - return; - } - - pid = get_param(params, 0)->val_ul; - } - - process = gdb_get_process(pid); - gdb_process_breakpoint_remove_all(process); - process->attached = false; - - if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) { - gdbserver_state.c_cpu = gdb_first_attached_cpu(); - } - - if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) { - gdbserver_state.g_cpu = gdb_first_attached_cpu(); - } - - if (!gdbserver_state.c_cpu) { - /* No more process attached */ - gdb_syscall_mode = GDB_SYS_DISABLED; - gdb_continue(); - } - put_packet("OK"); -} - -static void handle_thread_alive(GArray *params, void *user_ctx) -{ - CPUState *cpu; - - if (!params->len) { - put_packet("E22"); - return; - } - - if (get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) { - put_packet("E22"); - return; - } - - cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid, - get_param(params, 0)->thread_id.tid); - if (!cpu) { - put_packet("E22"); - return; - } - - put_packet("OK"); -} - -static void handle_continue(GArray *params, void *user_ctx) -{ - if (params->len) { - gdb_set_cpu_pc(get_param(params, 0)->val_ull); - } - - gdbserver_state.signal = 0; - gdb_continue(); -} - -static void handle_cont_with_sig(GArray *params, void *user_ctx) -{ - unsigned long signal = 0; - - /* - * Note: C sig;[addr] is currently unsupported and we simply - * omit the addr parameter - */ - if (params->len) { - signal = get_param(params, 0)->val_ul; - } - - gdbserver_state.signal = gdb_signal_to_target(signal); - if (gdbserver_state.signal == -1) { - gdbserver_state.signal = 0; - } - gdb_continue(); -} - -static void handle_set_thread(GArray *params, void *user_ctx) -{ - CPUState *cpu; - - if (params->len != 2) { - put_packet("E22"); - return; - } - - if (get_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) { - put_packet("E22"); - return; - } - - if (get_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) { - put_packet("OK"); - return; - } - - cpu = gdb_get_cpu(get_param(params, 1)->thread_id.pid, - get_param(params, 1)->thread_id.tid); - if (!cpu) { - put_packet("E22"); - return; - } - - /* - * Note: This command is deprecated and modern gdb's will be using the - * vCont command instead. - */ - switch (get_param(params, 0)->opcode) { - case 'c': - gdbserver_state.c_cpu = cpu; - put_packet("OK"); - break; - case 'g': - gdbserver_state.g_cpu = cpu; - put_packet("OK"); - break; - default: - put_packet("E22"); - break; - } -} - -static void handle_insert_bp(GArray *params, void *user_ctx) -{ - int res; - - if (params->len != 3) { - put_packet("E22"); - return; - } - - res = gdb_breakpoint_insert(get_param(params, 0)->val_ul, - get_param(params, 1)->val_ull, - get_param(params, 2)->val_ull); - if (res >= 0) { - put_packet("OK"); - return; - } else if (res == -ENOSYS) { - put_packet(""); - return; - } - - put_packet("E22"); -} - -static void handle_remove_bp(GArray *params, void *user_ctx) -{ - int res; - - if (params->len != 3) { - put_packet("E22"); - return; - } - - res = gdb_breakpoint_remove(get_param(params, 0)->val_ul, - get_param(params, 1)->val_ull, - get_param(params, 2)->val_ull); - if (res >= 0) { - put_packet("OK"); - return; - } else if (res == -ENOSYS) { - put_packet(""); - return; - } - - put_packet("E22"); -} - -/* - * handle_set/get_reg - * - * Older gdb are really dumb, and don't use 'G/g' if 'P/p' is available. - * This works, but can be very slow. Anything new enough to understand - * XML also knows how to use this properly. However to use this we - * need to define a local XML file as well as be talking to a - * reasonably modern gdb. Responding with an empty packet will cause - * the remote gdb to fallback to older methods. - */ - -static void handle_set_reg(GArray *params, void *user_ctx) -{ - int reg_size; - - if (!gdb_has_xml) { - put_packet(""); - return; - } - - if (params->len != 2) { - put_packet("E22"); - return; - } - - reg_size = strlen(get_param(params, 1)->data) / 2; - hextomem(gdbserver_state.mem_buf, get_param(params, 1)->data, reg_size); - gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data, - get_param(params, 0)->val_ull); - put_packet("OK"); -} - -static void handle_get_reg(GArray *params, void *user_ctx) -{ - int reg_size; - - if (!gdb_has_xml) { - put_packet(""); - return; - } - - if (!params->len) { - put_packet("E14"); - return; - } - - reg_size = gdb_read_register(gdbserver_state.g_cpu, - gdbserver_state.mem_buf, - get_param(params, 0)->val_ull); - if (!reg_size) { - put_packet("E14"); - return; - } else { - g_byte_array_set_size(gdbserver_state.mem_buf, reg_size); - } - - memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, reg_size); - put_strbuf(); -} - -static void handle_write_mem(GArray *params, void *user_ctx) -{ - if (params->len != 3) { - put_packet("E22"); - return; - } - - /* hextomem() reads 2*len bytes */ - if (get_param(params, 1)->val_ull > - strlen(get_param(params, 2)->data) / 2) { - put_packet("E22"); - return; - } - - hextomem(gdbserver_state.mem_buf, get_param(params, 2)->data, - get_param(params, 1)->val_ull); - if (target_memory_rw_debug(gdbserver_state.g_cpu, - get_param(params, 0)->val_ull, - gdbserver_state.mem_buf->data, - gdbserver_state.mem_buf->len, true)) { - put_packet("E14"); - return; - } - - put_packet("OK"); -} - -static void handle_read_mem(GArray *params, void *user_ctx) -{ - if (params->len != 2) { - put_packet("E22"); - return; - } - - /* memtohex() doubles the required space */ - if (get_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) { - put_packet("E22"); - return; - } - - g_byte_array_set_size(gdbserver_state.mem_buf, - get_param(params, 1)->val_ull); - - if (target_memory_rw_debug(gdbserver_state.g_cpu, - get_param(params, 0)->val_ull, - gdbserver_state.mem_buf->data, - gdbserver_state.mem_buf->len, false)) { - put_packet("E14"); - return; - } - - memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, - gdbserver_state.mem_buf->len); - put_strbuf(); -} - -static void handle_write_all_regs(GArray *params, void *user_ctx) -{ - target_ulong addr, len; - uint8_t *registers; - int reg_size; - - if (!params->len) { - return; - } - - cpu_synchronize_state(gdbserver_state.g_cpu); - len = strlen(get_param(params, 0)->data) / 2; - hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len); - registers = gdbserver_state.mem_buf->data; - for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0; - addr++) { - reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, addr); - len -= reg_size; - registers += reg_size; - } - put_packet("OK"); -} - -static void handle_read_all_regs(GArray *params, void *user_ctx) -{ - target_ulong addr, len; - - cpu_synchronize_state(gdbserver_state.g_cpu); - g_byte_array_set_size(gdbserver_state.mem_buf, 0); - len = 0; - for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) { - len += gdb_read_register(gdbserver_state.g_cpu, - gdbserver_state.mem_buf, - addr); - } - g_assert(len == gdbserver_state.mem_buf->len); - - memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len); - put_strbuf(); -} - -static void handle_file_io(GArray *params, void *user_ctx) -{ - if (params->len >= 1 && gdbserver_state.current_syscall_cb) { - target_ulong ret, err; - - ret = (target_ulong)get_param(params, 0)->val_ull; - if (params->len >= 2) { - err = (target_ulong)get_param(params, 1)->val_ull; - } else { - err = 0; - } - gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err); - gdbserver_state.current_syscall_cb = NULL; - } - - if (params->len >= 3 && get_param(params, 2)->opcode == (uint8_t)'C') { - put_packet("T02"); - return; - } - - gdb_continue(); -} - -static void handle_step(GArray *params, void *user_ctx) -{ - if (params->len) { - gdb_set_cpu_pc((target_ulong)get_param(params, 0)->val_ull); - } - - cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags); - gdb_continue(); -} - -static void handle_backward(GArray *params, void *user_ctx) -{ - if (!stub_can_reverse()) { - put_packet("E22"); - } - if (params->len == 1) { - switch (get_param(params, 0)->opcode) { - case 's': - if (replay_reverse_step()) { - gdb_continue(); - } else { - put_packet("E14"); - } - return; - case 'c': - if (replay_reverse_continue()) { - gdb_continue(); - } else { - put_packet("E14"); - } - return; - } - } - - /* Default invalid command */ - put_packet(""); -} - -static void handle_v_cont_query(GArray *params, void *user_ctx) -{ - put_packet("vCont;c;C;s;S"); -} - -static void handle_v_cont(GArray *params, void *user_ctx) -{ - int res; - - if (!params->len) { - return; - } - - res = gdb_handle_vcont(get_param(params, 0)->data); - if ((res == -EINVAL) || (res == -ERANGE)) { - put_packet("E22"); - } else if (res) { - put_packet(""); - } -} - -static void handle_v_attach(GArray *params, void *user_ctx) -{ - GDBProcess *process; - CPUState *cpu; - - g_string_assign(gdbserver_state.str_buf, "E22"); - if (!params->len) { - goto cleanup; - } - - process = gdb_get_process(get_param(params, 0)->val_ul); - if (!process) { - goto cleanup; - } - - cpu = get_first_cpu_in_process(process); - if (!cpu) { - goto cleanup; - } - - process->attached = true; - gdbserver_state.g_cpu = cpu; - gdbserver_state.c_cpu = cpu; - - g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP); - gdb_append_thread_id(cpu, gdbserver_state.str_buf); - g_string_append_c(gdbserver_state.str_buf, ';'); -cleanup: - put_strbuf(); -} - -static void handle_v_kill(GArray *params, void *user_ctx) -{ - /* Kill the target */ - put_packet("OK"); - error_report("QEMU: Terminated via GDBstub"); - gdb_exit(0); - exit(0); -} - -static const GdbCmdParseEntry gdb_v_commands_table[] = { - /* Order is important if has same prefix */ - { - .handler = handle_v_cont_query, - .cmd = "Cont?", - .cmd_startswith = 1 - }, - { - .handler = handle_v_cont, - .cmd = "Cont", - .cmd_startswith = 1, - .schema = "s0" - }, - { - .handler = handle_v_attach, - .cmd = "Attach;", - .cmd_startswith = 1, - .schema = "l0" - }, - { - .handler = handle_v_kill, - .cmd = "Kill;", - .cmd_startswith = 1 - }, -}; - -static void handle_v_commands(GArray *params, void *user_ctx) -{ - if (!params->len) { - return; - } - - if (process_string_cmd(NULL, get_param(params, 0)->data, - gdb_v_commands_table, - ARRAY_SIZE(gdb_v_commands_table))) { - put_packet(""); - } -} - -static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx) -{ - g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE); - - if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) { - g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x", - SSTEP_NOIRQ); - } - - if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) { - g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x", - SSTEP_NOTIMER); - } - - put_strbuf(); -} - -static void handle_set_qemu_sstep(GArray *params, void *user_ctx) -{ - int new_sstep_flags; - - if (!params->len) { - return; - } - - new_sstep_flags = get_param(params, 0)->val_ul; - - if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) { - put_packet("E22"); - return; - } - - gdbserver_state.sstep_flags = new_sstep_flags; - put_packet("OK"); -} - -static void handle_query_qemu_sstep(GArray *params, void *user_ctx) -{ - g_string_printf(gdbserver_state.str_buf, "0x%x", - gdbserver_state.sstep_flags); - put_strbuf(); -} - -static void handle_query_curr_tid(GArray *params, void *user_ctx) -{ - CPUState *cpu; - GDBProcess *process; - - /* - * "Current thread" remains vague in the spec, so always return - * the first thread of the current process (gdb returns the - * first thread). - */ - process = gdb_get_cpu_process(gdbserver_state.g_cpu); - cpu = get_first_cpu_in_process(process); - g_string_assign(gdbserver_state.str_buf, "QC"); - gdb_append_thread_id(cpu, gdbserver_state.str_buf); - put_strbuf(); -} - -static void handle_query_threads(GArray *params, void *user_ctx) -{ - if (!gdbserver_state.query_cpu) { - put_packet("l"); - return; - } - - g_string_assign(gdbserver_state.str_buf, "m"); - gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf); - put_strbuf(); - gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu); -} - -static void handle_query_first_threads(GArray *params, void *user_ctx) -{ - gdbserver_state.query_cpu = gdb_first_attached_cpu(); - handle_query_threads(params, user_ctx); -} - -static void handle_query_thread_extra(GArray *params, void *user_ctx) -{ - g_autoptr(GString) rs = g_string_new(NULL); - CPUState *cpu; - - if (!params->len || - get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) { - put_packet("E22"); - return; - } - - cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid, - get_param(params, 0)->thread_id.tid); - if (!cpu) { - return; - } - - cpu_synchronize_state(cpu); - - if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) { - /* Print the CPU model and name in multiprocess mode */ - ObjectClass *oc = object_get_class(OBJECT(cpu)); - const char *cpu_model = object_class_get_name(oc); - const char *cpu_name = - object_get_canonical_path_component(OBJECT(cpu)); - g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name, - cpu->halted ? "halted " : "running"); - } else { - g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index, - cpu->halted ? "halted " : "running"); - } - trace_gdbstub_op_extra_info(rs->str); - memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len); - put_strbuf(); -} - -#ifdef CONFIG_USER_ONLY -static void handle_query_offsets(GArray *params, void *user_ctx) -{ - TaskState *ts; - - ts = gdbserver_state.c_cpu->opaque; - g_string_printf(gdbserver_state.str_buf, - "Text=" TARGET_ABI_FMT_lx - ";Data=" TARGET_ABI_FMT_lx - ";Bss=" TARGET_ABI_FMT_lx, - ts->info->code_offset, - ts->info->data_offset, - ts->info->data_offset); - put_strbuf(); -} -#else -static void handle_query_rcmd(GArray *params, void *user_ctx) -{ - const guint8 zero = 0; - int len; - - if (!params->len) { - put_packet("E22"); - return; - } - - len = strlen(get_param(params, 0)->data); - if (len % 2) { - put_packet("E01"); - return; - } - - g_assert(gdbserver_state.mem_buf->len == 0); - len = len / 2; - hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len); - g_byte_array_append(gdbserver_state.mem_buf, &zero, 1); - qemu_chr_be_write(gdbserver_state.mon_chr, gdbserver_state.mem_buf->data, - gdbserver_state.mem_buf->len); - put_packet("OK"); -} -#endif - -static void handle_query_supported(GArray *params, void *user_ctx) -{ - CPUClass *cc; - - g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH); - cc = CPU_GET_CLASS(first_cpu); - if (cc->gdb_core_xml_file) { - g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+"); - } - - if (stub_can_reverse()) { - g_string_append(gdbserver_state.str_buf, - ";ReverseStep+;ReverseContinue+"); - } - -#ifdef CONFIG_USER_ONLY - if (gdbserver_state.c_cpu->opaque) { - g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+"); - } -#endif - - if (params->len && - strstr(get_param(params, 0)->data, "multiprocess+")) { - gdbserver_state.multiprocess = true; - } - - g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+"); - put_strbuf(); -} - -static void handle_query_xfer_features(GArray *params, void *user_ctx) -{ - GDBProcess *process; - CPUClass *cc; - unsigned long len, total_len, addr; - const char *xml; - const char *p; - - if (params->len < 3) { - put_packet("E22"); - return; - } - - process = gdb_get_cpu_process(gdbserver_state.g_cpu); - cc = CPU_GET_CLASS(gdbserver_state.g_cpu); - if (!cc->gdb_core_xml_file) { - put_packet(""); - return; - } - - gdb_has_xml = true; - p = get_param(params, 0)->data; - xml = get_feature_xml(p, &p, process); - if (!xml) { - put_packet("E00"); - return; - } - - addr = get_param(params, 1)->val_ul; - len = get_param(params, 2)->val_ul; - total_len = strlen(xml); - if (addr > total_len) { - put_packet("E00"); - return; - } - - if (len > (MAX_PACKET_LENGTH - 5) / 2) { - len = (MAX_PACKET_LENGTH - 5) / 2; - } - - if (len < total_len - addr) { - g_string_assign(gdbserver_state.str_buf, "m"); - memtox(gdbserver_state.str_buf, xml + addr, len); - } else { - g_string_assign(gdbserver_state.str_buf, "l"); - memtox(gdbserver_state.str_buf, xml + addr, total_len - addr); - } - - put_packet_binary(gdbserver_state.str_buf->str, - gdbserver_state.str_buf->len, true); -} - -#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER) -static void handle_query_xfer_auxv(GArray *params, void *user_ctx) -{ - TaskState *ts; - unsigned long offset, len, saved_auxv, auxv_len; - - if (params->len < 2) { - put_packet("E22"); - return; - } - - offset = get_param(params, 0)->val_ul; - len = get_param(params, 1)->val_ul; - ts = gdbserver_state.c_cpu->opaque; - saved_auxv = ts->info->saved_auxv; - auxv_len = ts->info->auxv_len; - - if (offset >= auxv_len) { - put_packet("E00"); - return; - } - - if (len > (MAX_PACKET_LENGTH - 5) / 2) { - len = (MAX_PACKET_LENGTH - 5) / 2; - } - - if (len < auxv_len - offset) { - g_string_assign(gdbserver_state.str_buf, "m"); - } else { - g_string_assign(gdbserver_state.str_buf, "l"); - len = auxv_len - offset; - } - - g_byte_array_set_size(gdbserver_state.mem_buf, len); - if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset, - gdbserver_state.mem_buf->data, len, false)) { - put_packet("E14"); - return; - } - - memtox(gdbserver_state.str_buf, - (const char *)gdbserver_state.mem_buf->data, len); - put_packet_binary(gdbserver_state.str_buf->str, - gdbserver_state.str_buf->len, true); -} -#endif - -static void handle_query_attached(GArray *params, void *user_ctx) -{ - put_packet(GDB_ATTACHED); -} - -static void handle_query_qemu_supported(GArray *params, void *user_ctx) -{ - g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep"); -#ifndef CONFIG_USER_ONLY - g_string_append(gdbserver_state.str_buf, ";PhyMemMode"); -#endif - put_strbuf(); -} - -#ifndef CONFIG_USER_ONLY -static void handle_query_qemu_phy_mem_mode(GArray *params, - void *user_ctx) -{ - g_string_printf(gdbserver_state.str_buf, "%d", phy_memory_mode); - put_strbuf(); -} - -static void handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx) -{ - if (!params->len) { - put_packet("E22"); - return; - } - - if (!get_param(params, 0)->val_ul) { - phy_memory_mode = 0; - } else { - phy_memory_mode = 1; - } - put_packet("OK"); -} -#endif - -static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = { - /* Order is important if has same prefix */ - { - .handler = handle_query_qemu_sstepbits, - .cmd = "qemu.sstepbits", - }, - { - .handler = handle_query_qemu_sstep, - .cmd = "qemu.sstep", - }, - { - .handler = handle_set_qemu_sstep, - .cmd = "qemu.sstep=", - .cmd_startswith = 1, - .schema = "l0" - }, -}; - -static const GdbCmdParseEntry gdb_gen_query_table[] = { - { - .handler = handle_query_curr_tid, - .cmd = "C", - }, - { - .handler = handle_query_threads, - .cmd = "sThreadInfo", - }, - { - .handler = handle_query_first_threads, - .cmd = "fThreadInfo", - }, - { - .handler = handle_query_thread_extra, - .cmd = "ThreadExtraInfo,", - .cmd_startswith = 1, - .schema = "t0" - }, -#ifdef CONFIG_USER_ONLY - { - .handler = handle_query_offsets, - .cmd = "Offsets", - }, -#else - { - .handler = handle_query_rcmd, - .cmd = "Rcmd,", - .cmd_startswith = 1, - .schema = "s0" - }, -#endif - { - .handler = handle_query_supported, - .cmd = "Supported:", - .cmd_startswith = 1, - .schema = "s0" - }, - { - .handler = handle_query_supported, - .cmd = "Supported", - .schema = "s0" - }, - { - .handler = handle_query_xfer_features, - .cmd = "Xfer:features:read:", - .cmd_startswith = 1, - .schema = "s:l,l0" - }, -#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER) - { - .handler = handle_query_xfer_auxv, - .cmd = "Xfer:auxv:read::", - .cmd_startswith = 1, - .schema = "l,l0" - }, -#endif - { - .handler = handle_query_attached, - .cmd = "Attached:", - .cmd_startswith = 1 - }, - { - .handler = handle_query_attached, - .cmd = "Attached", - }, - { - .handler = handle_query_qemu_supported, - .cmd = "qemu.Supported", - }, -#ifndef CONFIG_USER_ONLY - { - .handler = handle_query_qemu_phy_mem_mode, - .cmd = "qemu.PhyMemMode", - }, -#endif -}; - -static const GdbCmdParseEntry gdb_gen_set_table[] = { - /* Order is important if has same prefix */ - { - .handler = handle_set_qemu_sstep, - .cmd = "qemu.sstep:", - .cmd_startswith = 1, - .schema = "l0" - }, -#ifndef CONFIG_USER_ONLY - { - .handler = handle_set_qemu_phy_mem_mode, - .cmd = "qemu.PhyMemMode:", - .cmd_startswith = 1, - .schema = "l0" - }, -#endif -}; - -static void handle_gen_query(GArray *params, void *user_ctx) -{ - if (!params->len) { - return; - } - - if (!process_string_cmd(NULL, get_param(params, 0)->data, - gdb_gen_query_set_common_table, - ARRAY_SIZE(gdb_gen_query_set_common_table))) { - return; - } - - if (process_string_cmd(NULL, get_param(params, 0)->data, - gdb_gen_query_table, - ARRAY_SIZE(gdb_gen_query_table))) { - put_packet(""); - } -} - -static void handle_gen_set(GArray *params, void *user_ctx) -{ - if (!params->len) { - return; - } - - if (!process_string_cmd(NULL, get_param(params, 0)->data, - gdb_gen_query_set_common_table, - ARRAY_SIZE(gdb_gen_query_set_common_table))) { - return; - } - - if (process_string_cmd(NULL, get_param(params, 0)->data, - gdb_gen_set_table, - ARRAY_SIZE(gdb_gen_set_table))) { - put_packet(""); - } -} - -static void handle_target_halt(GArray *params, void *user_ctx) -{ - g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP); - gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf); - g_string_append_c(gdbserver_state.str_buf, ';'); - put_strbuf(); - /* - * Remove all the breakpoints when this query is issued, - * because gdb is doing an initial connect and the state - * should be cleaned up. - */ - gdb_breakpoint_remove_all(); -} - -static int gdb_handle_packet(const char *line_buf) -{ - const GdbCmdParseEntry *cmd_parser = NULL; - - trace_gdbstub_io_command(line_buf); - - switch (line_buf[0]) { - case '!': - put_packet("OK"); - break; - case '?': - { - static const GdbCmdParseEntry target_halted_cmd_desc = { - .handler = handle_target_halt, - .cmd = "?", - .cmd_startswith = 1 - }; - cmd_parser = &target_halted_cmd_desc; - } - break; - case 'c': - { - static const GdbCmdParseEntry continue_cmd_desc = { - .handler = handle_continue, - .cmd = "c", - .cmd_startswith = 1, - .schema = "L0" - }; - cmd_parser = &continue_cmd_desc; - } - break; - case 'C': - { - static const GdbCmdParseEntry cont_with_sig_cmd_desc = { - .handler = handle_cont_with_sig, - .cmd = "C", - .cmd_startswith = 1, - .schema = "l0" - }; - cmd_parser = &cont_with_sig_cmd_desc; - } - break; - case 'v': - { - static const GdbCmdParseEntry v_cmd_desc = { - .handler = handle_v_commands, - .cmd = "v", - .cmd_startswith = 1, - .schema = "s0" - }; - cmd_parser = &v_cmd_desc; - } - break; - case 'k': - /* Kill the target */ - error_report("QEMU: Terminated via GDBstub"); - gdb_exit(0); - exit(0); - case 'D': - { - static const GdbCmdParseEntry detach_cmd_desc = { - .handler = handle_detach, - .cmd = "D", - .cmd_startswith = 1, - .schema = "?.l0" - }; - cmd_parser = &detach_cmd_desc; - } - break; - case 's': - { - static const GdbCmdParseEntry step_cmd_desc = { - .handler = handle_step, - .cmd = "s", - .cmd_startswith = 1, - .schema = "L0" - }; - cmd_parser = &step_cmd_desc; - } - break; - case 'b': - { - static const GdbCmdParseEntry backward_cmd_desc = { - .handler = handle_backward, - .cmd = "b", - .cmd_startswith = 1, - .schema = "o0" - }; - cmd_parser = &backward_cmd_desc; - } - break; - case 'F': - { - static const GdbCmdParseEntry file_io_cmd_desc = { - .handler = handle_file_io, - .cmd = "F", - .cmd_startswith = 1, - .schema = "L,L,o0" - }; - cmd_parser = &file_io_cmd_desc; - } - break; - case 'g': - { - static const GdbCmdParseEntry read_all_regs_cmd_desc = { - .handler = handle_read_all_regs, - .cmd = "g", - .cmd_startswith = 1 - }; - cmd_parser = &read_all_regs_cmd_desc; - } - break; - case 'G': - { - static const GdbCmdParseEntry write_all_regs_cmd_desc = { - .handler = handle_write_all_regs, - .cmd = "G", - .cmd_startswith = 1, - .schema = "s0" - }; - cmd_parser = &write_all_regs_cmd_desc; - } - break; - case 'm': - { - static const GdbCmdParseEntry read_mem_cmd_desc = { - .handler = handle_read_mem, - .cmd = "m", - .cmd_startswith = 1, - .schema = "L,L0" - }; - cmd_parser = &read_mem_cmd_desc; - } - break; - case 'M': - { - static const GdbCmdParseEntry write_mem_cmd_desc = { - .handler = handle_write_mem, - .cmd = "M", - .cmd_startswith = 1, - .schema = "L,L:s0" - }; - cmd_parser = &write_mem_cmd_desc; - } - break; - case 'p': - { - static const GdbCmdParseEntry get_reg_cmd_desc = { - .handler = handle_get_reg, - .cmd = "p", - .cmd_startswith = 1, - .schema = "L0" - }; - cmd_parser = &get_reg_cmd_desc; - } - break; - case 'P': - { - static const GdbCmdParseEntry set_reg_cmd_desc = { - .handler = handle_set_reg, - .cmd = "P", - .cmd_startswith = 1, - .schema = "L?s0" - }; - cmd_parser = &set_reg_cmd_desc; - } - break; - case 'Z': - { - static const GdbCmdParseEntry insert_bp_cmd_desc = { - .handler = handle_insert_bp, - .cmd = "Z", - .cmd_startswith = 1, - .schema = "l?L?L0" - }; - cmd_parser = &insert_bp_cmd_desc; - } - break; - case 'z': - { - static const GdbCmdParseEntry remove_bp_cmd_desc = { - .handler = handle_remove_bp, - .cmd = "z", - .cmd_startswith = 1, - .schema = "l?L?L0" - }; - cmd_parser = &remove_bp_cmd_desc; - } - break; - case 'H': - { - static const GdbCmdParseEntry set_thread_cmd_desc = { - .handler = handle_set_thread, - .cmd = "H", - .cmd_startswith = 1, - .schema = "o.t0" - }; - cmd_parser = &set_thread_cmd_desc; - } - break; - case 'T': - { - static const GdbCmdParseEntry thread_alive_cmd_desc = { - .handler = handle_thread_alive, - .cmd = "T", - .cmd_startswith = 1, - .schema = "t0" - }; - cmd_parser = &thread_alive_cmd_desc; - } - break; - case 'q': - { - static const GdbCmdParseEntry gen_query_cmd_desc = { - .handler = handle_gen_query, - .cmd = "q", - .cmd_startswith = 1, - .schema = "s0" - }; - cmd_parser = &gen_query_cmd_desc; - } - break; - case 'Q': - { - static const GdbCmdParseEntry gen_set_cmd_desc = { - .handler = handle_gen_set, - .cmd = "Q", - .cmd_startswith = 1, - .schema = "s0" - }; - cmd_parser = &gen_set_cmd_desc; - } - break; - default: - /* put empty packet */ - put_packet(""); - break; - } - - if (cmd_parser) { - run_cmd_parser(line_buf, cmd_parser); - } - - return RS_IDLE; -} - -void gdb_set_stop_cpu(CPUState *cpu) -{ - GDBProcess *p = gdb_get_cpu_process(cpu); - - if (!p->attached) { - /* - * Having a stop CPU corresponding to a process that is not attached - * confuses GDB. So we ignore the request. - */ - return; - } - - gdbserver_state.c_cpu = cpu; - gdbserver_state.g_cpu = cpu; -} - -#ifndef CONFIG_USER_ONLY -static void gdb_vm_state_change(void *opaque, bool running, RunState state) -{ - CPUState *cpu = gdbserver_state.c_cpu; - g_autoptr(GString) buf = g_string_new(NULL); - g_autoptr(GString) tid = g_string_new(NULL); - const char *type; - int ret; - - if (running || gdbserver_state.state == RS_INACTIVE) { - return; - } - /* Is there a GDB syscall waiting to be sent? */ - if (gdbserver_state.current_syscall_cb) { - put_packet(gdbserver_state.syscall_buf); - return; - } - - if (cpu == NULL) { - /* No process attached */ - return; - } - - gdb_append_thread_id(cpu, tid); - - switch (state) { - case RUN_STATE_DEBUG: - if (cpu->watchpoint_hit) { - switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) { - case BP_MEM_READ: - type = "r"; - break; - case BP_MEM_ACCESS: - type = "a"; - break; - default: - type = ""; - break; - } - trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu), - (target_ulong)cpu->watchpoint_hit->vaddr); - g_string_printf(buf, "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";", - GDB_SIGNAL_TRAP, tid->str, type, - (target_ulong)cpu->watchpoint_hit->vaddr); - cpu->watchpoint_hit = NULL; - goto send_packet; - } else { - trace_gdbstub_hit_break(); - } - tb_flush(cpu); - ret = GDB_SIGNAL_TRAP; - break; - case RUN_STATE_PAUSED: - trace_gdbstub_hit_paused(); - ret = GDB_SIGNAL_INT; - break; - case RUN_STATE_SHUTDOWN: - trace_gdbstub_hit_shutdown(); - ret = GDB_SIGNAL_QUIT; - break; - case RUN_STATE_IO_ERROR: - trace_gdbstub_hit_io_error(); - ret = GDB_SIGNAL_IO; - break; - case RUN_STATE_WATCHDOG: - trace_gdbstub_hit_watchdog(); - ret = GDB_SIGNAL_ALRM; - break; - case RUN_STATE_INTERNAL_ERROR: - trace_gdbstub_hit_internal_error(); - ret = GDB_SIGNAL_ABRT; - break; - case RUN_STATE_SAVE_VM: - case RUN_STATE_RESTORE_VM: - return; - case RUN_STATE_FINISH_MIGRATE: - ret = GDB_SIGNAL_XCPU; - break; - default: - trace_gdbstub_hit_unknown(state); - ret = GDB_SIGNAL_UNKNOWN; - break; - } - gdb_set_stop_cpu(cpu); - g_string_printf(buf, "T%02xthread:%s;", ret, tid->str); - -send_packet: - put_packet(buf->str); - - /* disable single step if it was enabled */ - cpu_single_step(cpu, 0); -} -#endif - -/* Send a gdb syscall request. - This accepts limited printf-style format specifiers, specifically: - %x - target_ulong argument printed in hex. - %lx - 64-bit argument printed in hex. - %s - string pointer (target_ulong) and length (int) pair. */ -void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va) -{ - char *p; - char *p_end; - target_ulong addr; - uint64_t i64; - - if (!gdbserver_state.init) { - return; - } - - gdbserver_state.current_syscall_cb = cb; -#ifndef CONFIG_USER_ONLY - vm_stop(RUN_STATE_DEBUG); -#endif - p = &gdbserver_state.syscall_buf[0]; - p_end = &gdbserver_state.syscall_buf[sizeof(gdbserver_state.syscall_buf)]; - *(p++) = 'F'; - while (*fmt) { - if (*fmt == '%') { - fmt++; - switch (*fmt++) { - case 'x': - addr = va_arg(va, target_ulong); - p += snprintf(p, p_end - p, TARGET_FMT_lx, addr); - break; - case 'l': - if (*(fmt++) != 'x') - goto bad_format; - i64 = va_arg(va, uint64_t); - p += snprintf(p, p_end - p, "%" PRIx64, i64); - break; - case 's': - addr = va_arg(va, target_ulong); - p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x", - addr, va_arg(va, int)); - break; - default: - bad_format: - error_report("gdbstub: Bad syscall format string '%s'", - fmt - 1); - break; - } - } else { - *(p++) = *(fmt++); - } - } - *p = 0; -#ifdef CONFIG_USER_ONLY - put_packet(gdbserver_state.syscall_buf); - /* Return control to gdb for it to process the syscall request. - * Since the protocol requires that gdb hands control back to us - * using a "here are the results" F packet, we don't need to check - * gdb_handlesig's return value (which is the signal to deliver if - * execution was resumed via a continue packet). - */ - gdb_handlesig(gdbserver_state.c_cpu, 0); -#else - /* In this case wait to send the syscall packet until notification that - the CPU has stopped. This must be done because if the packet is sent - now the reply from the syscall request could be received while the CPU - is still in the running state, which can cause packets to be dropped - and state transition 'T' packets to be sent while the syscall is still - being processed. */ - qemu_cpu_kick(gdbserver_state.c_cpu); -#endif -} - -void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - gdb_do_syscallv(cb, fmt, va); - va_end(va); -} - -static void gdb_read_byte(uint8_t ch) -{ - uint8_t reply; - -#ifndef CONFIG_USER_ONLY - if (gdbserver_state.last_packet->len) { - /* Waiting for a response to the last packet. If we see the start - of a new command then abandon the previous response. */ - if (ch == '-') { - trace_gdbstub_err_got_nack(); - put_buffer(gdbserver_state.last_packet->data, - gdbserver_state.last_packet->len); - } else if (ch == '+') { - trace_gdbstub_io_got_ack(); - } else { - trace_gdbstub_io_got_unexpected(ch); - } - - if (ch == '+' || ch == '$') { - g_byte_array_set_size(gdbserver_state.last_packet, 0); - } - if (ch != '$') - return; - } - if (runstate_is_running()) { - /* when the CPU is running, we cannot do anything except stop - it when receiving a char */ - vm_stop(RUN_STATE_PAUSED); - } else -#endif - { - switch(gdbserver_state.state) { - case RS_IDLE: - if (ch == '$') { - /* start of command packet */ - gdbserver_state.line_buf_index = 0; - gdbserver_state.line_sum = 0; - gdbserver_state.state = RS_GETLINE; - } else { - trace_gdbstub_err_garbage(ch); - } - break; - case RS_GETLINE: - if (ch == '}') { - /* start escape sequence */ - gdbserver_state.state = RS_GETLINE_ESC; - gdbserver_state.line_sum += ch; - } else if (ch == '*') { - /* start run length encoding sequence */ - gdbserver_state.state = RS_GETLINE_RLE; - gdbserver_state.line_sum += ch; - } else if (ch == '#') { - /* end of command, start of checksum*/ - gdbserver_state.state = RS_CHKSUM1; - } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) { - trace_gdbstub_err_overrun(); - gdbserver_state.state = RS_IDLE; - } else { - /* unescaped command character */ - gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch; - gdbserver_state.line_sum += ch; - } - break; - case RS_GETLINE_ESC: - if (ch == '#') { - /* unexpected end of command in escape sequence */ - gdbserver_state.state = RS_CHKSUM1; - } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) { - /* command buffer overrun */ - trace_gdbstub_err_overrun(); - gdbserver_state.state = RS_IDLE; - } else { - /* parse escaped character and leave escape state */ - gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20; - gdbserver_state.line_sum += ch; - gdbserver_state.state = RS_GETLINE; - } - break; - case RS_GETLINE_RLE: - /* - * Run-length encoding is explained in "Debugging with GDB / - * Appendix E GDB Remote Serial Protocol / Overview". - */ - if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) { - /* invalid RLE count encoding */ - trace_gdbstub_err_invalid_repeat(ch); - gdbserver_state.state = RS_GETLINE; - } else { - /* decode repeat length */ - int repeat = ch - ' ' + 3; - if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) { - /* that many repeats would overrun the command buffer */ - trace_gdbstub_err_overrun(); - gdbserver_state.state = RS_IDLE; - } else if (gdbserver_state.line_buf_index < 1) { - /* got a repeat but we have nothing to repeat */ - trace_gdbstub_err_invalid_rle(); - gdbserver_state.state = RS_GETLINE; - } else { - /* repeat the last character */ - memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index, - gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat); - gdbserver_state.line_buf_index += repeat; - gdbserver_state.line_sum += ch; - gdbserver_state.state = RS_GETLINE; - } - } - break; - case RS_CHKSUM1: - /* get high hex digit of checksum */ - if (!isxdigit(ch)) { - trace_gdbstub_err_checksum_invalid(ch); - gdbserver_state.state = RS_GETLINE; - break; - } - gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0'; - gdbserver_state.line_csum = fromhex(ch) << 4; - gdbserver_state.state = RS_CHKSUM2; - break; - case RS_CHKSUM2: - /* get low hex digit of checksum */ - if (!isxdigit(ch)) { - trace_gdbstub_err_checksum_invalid(ch); - gdbserver_state.state = RS_GETLINE; - break; - } - gdbserver_state.line_csum |= fromhex(ch); - - if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) { - trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum); - /* send NAK reply */ - reply = '-'; - put_buffer(&reply, 1); - gdbserver_state.state = RS_IDLE; - } else { - /* send ACK reply */ - reply = '+'; - put_buffer(&reply, 1); - gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf); - } - break; - default: - abort(); - } - } -} - -/* Tell the remote gdb that the process has exited. */ -void gdb_exit(int code) -{ - char buf[4]; - - if (!gdbserver_state.init) { - return; - } -#ifdef CONFIG_USER_ONLY - if (gdbserver_state.socket_path) { - unlink(gdbserver_state.socket_path); - } - if (gdbserver_state.fd < 0) { - return; - } -#endif - - trace_gdbstub_op_exiting((uint8_t)code); - - snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code); - put_packet(buf); - -#ifndef CONFIG_USER_ONLY - qemu_chr_fe_deinit(&gdbserver_state.chr, true); -#endif -} - -/* - * Create the process that will contain all the "orphan" CPUs (that are not - * part of a CPU cluster). Note that if this process contains no CPUs, it won't - * be attachable and thus will be invisible to the user. - */ -static void create_default_process(GDBState *s) -{ - GDBProcess *process; - int max_pid = 0; - - if (gdbserver_state.process_num) { - max_pid = s->processes[s->process_num - 1].pid; - } - - s->processes = g_renew(GDBProcess, s->processes, ++s->process_num); - process = &s->processes[s->process_num - 1]; - - /* We need an available PID slot for this process */ - assert(max_pid < UINT32_MAX); - - process->pid = max_pid + 1; - process->attached = false; - process->target_xml[0] = '\0'; -} - -#ifdef CONFIG_USER_ONLY -int -gdb_handlesig(CPUState *cpu, int sig) -{ - char buf[256]; - int n; - - if (!gdbserver_state.init || gdbserver_state.fd < 0) { - return sig; - } - - /* disable single step if it was enabled */ - cpu_single_step(cpu, 0); - tb_flush(cpu); - - if (sig != 0) { - gdb_set_stop_cpu(cpu); - g_string_printf(gdbserver_state.str_buf, - "T%02xthread:", target_signal_to_gdb(sig)); - gdb_append_thread_id(cpu, gdbserver_state.str_buf); - g_string_append_c(gdbserver_state.str_buf, ';'); - put_strbuf(); - } - /* put_packet() might have detected that the peer terminated the - connection. */ - if (gdbserver_state.fd < 0) { - return sig; - } - - sig = 0; - gdbserver_state.state = RS_IDLE; - gdbserver_state.running_state = 0; - while (gdbserver_state.running_state == 0) { - n = read(gdbserver_state.fd, buf, 256); - if (n > 0) { - int i; - - for (i = 0; i < n; i++) { - gdb_read_byte(buf[i]); - } - } else { - /* XXX: Connection closed. Should probably wait for another - connection before continuing. */ - if (n == 0) { - close(gdbserver_state.fd); - } - gdbserver_state.fd = -1; - return sig; - } - } - sig = gdbserver_state.signal; - gdbserver_state.signal = 0; - return sig; -} - -/* Tell the remote gdb that the process has exited due to SIG. */ -void gdb_signalled(CPUArchState *env, int sig) -{ - char buf[4]; - - if (!gdbserver_state.init || gdbserver_state.fd < 0) { - return; - } - - snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig)); - put_packet(buf); -} - -static void gdb_accept_init(int fd) -{ - init_gdbserver_state(); - create_default_process(&gdbserver_state); - gdbserver_state.processes[0].attached = true; - gdbserver_state.c_cpu = gdb_first_attached_cpu(); - gdbserver_state.g_cpu = gdbserver_state.c_cpu; - gdbserver_state.fd = fd; - gdb_has_xml = false; -} - -static bool gdb_accept_socket(int gdb_fd) -{ - int fd; - - for(;;) { - fd = accept(gdb_fd, NULL, NULL); - if (fd < 0 && errno != EINTR) { - perror("accept socket"); - return false; - } else if (fd >= 0) { - qemu_set_cloexec(fd); - break; - } - } - - gdb_accept_init(fd); - return true; -} - -static int gdbserver_open_socket(const char *path) -{ - struct sockaddr_un sockaddr = {}; - int fd, ret; - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - perror("create socket"); - return -1; - } - - sockaddr.sun_family = AF_UNIX; - pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path); - ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); - if (ret < 0) { - perror("bind socket"); - close(fd); - return -1; - } - ret = listen(fd, 1); - if (ret < 0) { - perror("listen socket"); - close(fd); - return -1; - } - - return fd; -} - -static bool gdb_accept_tcp(int gdb_fd) -{ - struct sockaddr_in sockaddr = {}; - socklen_t len; - int fd; - - for(;;) { - len = sizeof(sockaddr); - fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len); - if (fd < 0 && errno != EINTR) { - perror("accept"); - return false; - } else if (fd >= 0) { - qemu_set_cloexec(fd); - break; - } - } - - /* set short latency */ - if (socket_set_nodelay(fd)) { - perror("setsockopt"); - close(fd); - return false; - } - - gdb_accept_init(fd); - return true; -} - -static int gdbserver_open_port(int port) -{ - struct sockaddr_in sockaddr; - int fd, ret; - - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - qemu_set_cloexec(fd); - - socket_set_fast_reuse(fd); - - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - sockaddr.sin_addr.s_addr = 0; - ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); - if (ret < 0) { - perror("bind"); - close(fd); - return -1; - } - ret = listen(fd, 1); - if (ret < 0) { - perror("listen"); - close(fd); - return -1; - } - - return fd; -} - -int gdbserver_start(const char *port_or_path) -{ - int port = g_ascii_strtoull(port_or_path, NULL, 10); - int gdb_fd; - - if (port > 0) { - gdb_fd = gdbserver_open_port(port); - } else { - gdb_fd = gdbserver_open_socket(port_or_path); - } - - if (gdb_fd < 0) { - return -1; - } - - if (port > 0 && gdb_accept_tcp(gdb_fd)) { - return 0; - } else if (gdb_accept_socket(gdb_fd)) { - gdbserver_state.socket_path = g_strdup(port_or_path); - return 0; - } - - /* gone wrong */ - close(gdb_fd); - return -1; -} - -/* Disable gdb stub for child processes. */ -void gdbserver_fork(CPUState *cpu) -{ - if (!gdbserver_state.init || gdbserver_state.fd < 0) { - return; - } - close(gdbserver_state.fd); - gdbserver_state.fd = -1; - cpu_breakpoint_remove_all(cpu, BP_GDB); - cpu_watchpoint_remove_all(cpu, BP_GDB); -} -#else -static int gdb_chr_can_receive(void *opaque) -{ - /* We can handle an arbitrarily large amount of data. - Pick the maximum packet size, which is as good as anything. */ - return MAX_PACKET_LENGTH; -} - -static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size) -{ - int i; - - for (i = 0; i < size; i++) { - gdb_read_byte(buf[i]); - } -} - -static void gdb_chr_event(void *opaque, QEMUChrEvent event) -{ - int i; - GDBState *s = (GDBState *) opaque; - - switch (event) { - case CHR_EVENT_OPENED: - /* Start with first process attached, others detached */ - for (i = 0; i < s->process_num; i++) { - s->processes[i].attached = !i; - } - - s->c_cpu = gdb_first_attached_cpu(); - s->g_cpu = s->c_cpu; - - vm_stop(RUN_STATE_PAUSED); - replay_gdb_attached(); - gdb_has_xml = false; - break; - default: - break; - } -} - -static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len) -{ - g_autoptr(GString) hex_buf = g_string_new("O"); - memtohex(hex_buf, buf, len); - put_packet(hex_buf->str); - return len; -} - -#ifndef _WIN32 -static void gdb_sigterm_handler(int signal) -{ - if (runstate_is_running()) { - vm_stop(RUN_STATE_PAUSED); - } -} -#endif - -static void gdb_monitor_open(Chardev *chr, ChardevBackend *backend, - bool *be_opened, Error **errp) -{ - *be_opened = false; -} - -static void char_gdb_class_init(ObjectClass *oc, void *data) -{ - ChardevClass *cc = CHARDEV_CLASS(oc); - - cc->internal = true; - cc->open = gdb_monitor_open; - cc->chr_write = gdb_monitor_write; -} - -#define TYPE_CHARDEV_GDB "chardev-gdb" - -static const TypeInfo char_gdb_type_info = { - .name = TYPE_CHARDEV_GDB, - .parent = TYPE_CHARDEV, - .class_init = char_gdb_class_init, -}; - -static int find_cpu_clusters(Object *child, void *opaque) -{ - if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) { - GDBState *s = (GDBState *) opaque; - CPUClusterState *cluster = CPU_CLUSTER(child); - GDBProcess *process; - - s->processes = g_renew(GDBProcess, s->processes, ++s->process_num); - - process = &s->processes[s->process_num - 1]; - - /* - * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at - * runtime, we enforce here that the machine does not use a cluster ID - * that would lead to PID 0. - */ - assert(cluster->cluster_id != UINT32_MAX); - process->pid = cluster->cluster_id + 1; - process->attached = false; - process->target_xml[0] = '\0'; - - return 0; - } - - return object_child_foreach(child, find_cpu_clusters, opaque); -} - -static int pid_order(const void *a, const void *b) -{ - GDBProcess *pa = (GDBProcess *) a; - GDBProcess *pb = (GDBProcess *) b; - - if (pa->pid < pb->pid) { - return -1; - } else if (pa->pid > pb->pid) { - return 1; - } else { - return 0; - } -} - -static void create_processes(GDBState *s) -{ - object_child_foreach(object_get_root(), find_cpu_clusters, s); - - if (gdbserver_state.processes) { - /* Sort by PID */ - qsort(gdbserver_state.processes, gdbserver_state.process_num, sizeof(gdbserver_state.processes[0]), pid_order); - } - - create_default_process(s); -} - -int gdbserver_start(const char *device) -{ - trace_gdbstub_op_start(device); - - char gdbstub_device_name[128]; - Chardev *chr = NULL; - Chardev *mon_chr; - - if (!first_cpu) { - error_report("gdbstub: meaningless to attach gdb to a " - "machine without any CPU."); - return -1; - } - - if (kvm_enabled() && !kvm_supports_guest_debug()) { - error_report("gdbstub: KVM doesn't support guest debugging"); - return -1; - } - - if (!device) - return -1; - if (strcmp(device, "none") != 0) { - if (strstart(device, "tcp:", NULL)) { - /* enforce required TCP attributes */ - snprintf(gdbstub_device_name, sizeof(gdbstub_device_name), - "%s,wait=off,nodelay=on,server=on", device); - device = gdbstub_device_name; - } -#ifndef _WIN32 - else if (strcmp(device, "stdio") == 0) { - struct sigaction act; - - memset(&act, 0, sizeof(act)); - act.sa_handler = gdb_sigterm_handler; - sigaction(SIGINT, &act, NULL); - } -#endif - /* - * FIXME: it's a bit weird to allow using a mux chardev here - * and implicitly setup a monitor. We may want to break this. - */ - chr = qemu_chr_new_noreplay("gdb", device, true, NULL); - if (!chr) - return -1; - } - - if (!gdbserver_state.init) { - init_gdbserver_state(); - - qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); - - /* Initialize a monitor terminal for gdb */ - mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB, - NULL, NULL, &error_abort); - monitor_init_hmp(mon_chr, false, &error_abort); - } else { - qemu_chr_fe_deinit(&gdbserver_state.chr, true); - mon_chr = gdbserver_state.mon_chr; - reset_gdbserver_state(); - } - - create_processes(&gdbserver_state); - - if (chr) { - qemu_chr_fe_init(&gdbserver_state.chr, chr, &error_abort); - qemu_chr_fe_set_handlers(&gdbserver_state.chr, gdb_chr_can_receive, - gdb_chr_receive, gdb_chr_event, - NULL, &gdbserver_state, NULL, true); - } - gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE; - gdbserver_state.mon_chr = mon_chr; - gdbserver_state.current_syscall_cb = NULL; - - return 0; -} - -static void register_types(void) -{ - type_register_static(&char_gdb_type_info); -} - -type_init(register_types); -#endif diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c new file mode 100644 index 000000000000..be88ca0d7182 --- /dev/null +++ b/gdbstub/gdbstub.c @@ -0,0 +1,3517 @@ +/* + * gdb server stub + * + * This implements a subset of the remote protocol as described in: + * + * https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/ctype.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "trace.h" +#include "exec/gdbstub.h" +#ifdef CONFIG_USER_ONLY +#include "qemu.h" +#else +#include "monitor/monitor.h" +#include "chardev/char.h" +#include "chardev/char-fe.h" +#include "hw/cpu/cluster.h" +#include "hw/boards.h" +#endif + +#define MAX_PACKET_LENGTH 4096 + +#include "qemu/sockets.h" +#include "sysemu/hw_accel.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 +#define GDB_ATTACHED "1" +#endif + +#ifndef CONFIG_USER_ONLY +static int phy_memory_mode; +#endif + +static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr, + uint8_t *buf, int len, bool is_write) +{ + CPUClass *cc; + +#ifndef CONFIG_USER_ONLY + if (phy_memory_mode) { + if (is_write) { + cpu_physical_memory_write(addr, buf, len); + } else { + cpu_physical_memory_read(addr, buf, len); + } + return 0; + } +#endif + + cc = CPU_GET_CLASS(cpu); + if (cc->memory_rw_debug) { + return cc->memory_rw_debug(cpu, addr, buf, len, is_write); + } + return cpu_memory_rw_debug(cpu, addr, buf, len, is_write); +} + +/* Return the GDB index for a given vCPU state. + * + * For user mode this is simply the thread id. In system mode GDB + * numbers CPUs from 1 as 0 is reserved as an "any cpu" index. + */ +static inline int cpu_gdb_index(CPUState *cpu) +{ +#if defined(CONFIG_USER_ONLY) + TaskState *ts = (TaskState *) cpu->opaque; + return ts ? ts->ts_tid : -1; +#else + return cpu->cpu_index + 1; +#endif +} + +enum { + GDB_SIGNAL_0 = 0, + GDB_SIGNAL_INT = 2, + GDB_SIGNAL_QUIT = 3, + GDB_SIGNAL_TRAP = 5, + GDB_SIGNAL_ABRT = 6, + GDB_SIGNAL_ALRM = 14, + GDB_SIGNAL_IO = 23, + GDB_SIGNAL_XCPU = 24, + GDB_SIGNAL_UNKNOWN = 143 +}; + +#ifdef CONFIG_USER_ONLY + +/* Map target signal numbers to GDB protocol signal numbers and vice + * versa. For user emulation's currently supported systems, we can + * assume most signals are defined. + */ + +static int gdb_signal_table[] = { + 0, + TARGET_SIGHUP, + TARGET_SIGINT, + TARGET_SIGQUIT, + TARGET_SIGILL, + TARGET_SIGTRAP, + TARGET_SIGABRT, + -1, /* SIGEMT */ + TARGET_SIGFPE, + TARGET_SIGKILL, + TARGET_SIGBUS, + TARGET_SIGSEGV, + TARGET_SIGSYS, + TARGET_SIGPIPE, + TARGET_SIGALRM, + TARGET_SIGTERM, + TARGET_SIGURG, + TARGET_SIGSTOP, + TARGET_SIGTSTP, + TARGET_SIGCONT, + TARGET_SIGCHLD, + TARGET_SIGTTIN, + TARGET_SIGTTOU, + TARGET_SIGIO, + TARGET_SIGXCPU, + TARGET_SIGXFSZ, + TARGET_SIGVTALRM, + TARGET_SIGPROF, + TARGET_SIGWINCH, + -1, /* SIGLOST */ + TARGET_SIGUSR1, + TARGET_SIGUSR2, +#ifdef TARGET_SIGPWR + TARGET_SIGPWR, +#else + -1, +#endif + -1, /* SIGPOLL */ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, +#ifdef __SIGRTMIN + __SIGRTMIN + 1, + __SIGRTMIN + 2, + __SIGRTMIN + 3, + __SIGRTMIN + 4, + __SIGRTMIN + 5, + __SIGRTMIN + 6, + __SIGRTMIN + 7, + __SIGRTMIN + 8, + __SIGRTMIN + 9, + __SIGRTMIN + 10, + __SIGRTMIN + 11, + __SIGRTMIN + 12, + __SIGRTMIN + 13, + __SIGRTMIN + 14, + __SIGRTMIN + 15, + __SIGRTMIN + 16, + __SIGRTMIN + 17, + __SIGRTMIN + 18, + __SIGRTMIN + 19, + __SIGRTMIN + 20, + __SIGRTMIN + 21, + __SIGRTMIN + 22, + __SIGRTMIN + 23, + __SIGRTMIN + 24, + __SIGRTMIN + 25, + __SIGRTMIN + 26, + __SIGRTMIN + 27, + __SIGRTMIN + 28, + __SIGRTMIN + 29, + __SIGRTMIN + 30, + __SIGRTMIN + 31, + -1, /* SIGCANCEL */ + __SIGRTMIN, + __SIGRTMIN + 32, + __SIGRTMIN + 33, + __SIGRTMIN + 34, + __SIGRTMIN + 35, + __SIGRTMIN + 36, + __SIGRTMIN + 37, + __SIGRTMIN + 38, + __SIGRTMIN + 39, + __SIGRTMIN + 40, + __SIGRTMIN + 41, + __SIGRTMIN + 42, + __SIGRTMIN + 43, + __SIGRTMIN + 44, + __SIGRTMIN + 45, + __SIGRTMIN + 46, + __SIGRTMIN + 47, + __SIGRTMIN + 48, + __SIGRTMIN + 49, + __SIGRTMIN + 50, + __SIGRTMIN + 51, + __SIGRTMIN + 52, + __SIGRTMIN + 53, + __SIGRTMIN + 54, + __SIGRTMIN + 55, + __SIGRTMIN + 56, + __SIGRTMIN + 57, + __SIGRTMIN + 58, + __SIGRTMIN + 59, + __SIGRTMIN + 60, + __SIGRTMIN + 61, + __SIGRTMIN + 62, + __SIGRTMIN + 63, + __SIGRTMIN + 64, + __SIGRTMIN + 65, + __SIGRTMIN + 66, + __SIGRTMIN + 67, + __SIGRTMIN + 68, + __SIGRTMIN + 69, + __SIGRTMIN + 70, + __SIGRTMIN + 71, + __SIGRTMIN + 72, + __SIGRTMIN + 73, + __SIGRTMIN + 74, + __SIGRTMIN + 75, + __SIGRTMIN + 76, + __SIGRTMIN + 77, + __SIGRTMIN + 78, + __SIGRTMIN + 79, + __SIGRTMIN + 80, + __SIGRTMIN + 81, + __SIGRTMIN + 82, + __SIGRTMIN + 83, + __SIGRTMIN + 84, + __SIGRTMIN + 85, + __SIGRTMIN + 86, + __SIGRTMIN + 87, + __SIGRTMIN + 88, + __SIGRTMIN + 89, + __SIGRTMIN + 90, + __SIGRTMIN + 91, + __SIGRTMIN + 92, + __SIGRTMIN + 93, + __SIGRTMIN + 94, + __SIGRTMIN + 95, + -1, /* SIGINFO */ + -1, /* UNKNOWN */ + -1, /* DEFAULT */ + -1, + -1, + -1, + -1, + -1, + -1 +#endif +}; +#else +/* In system mode we only need SIGINT and SIGTRAP; other signals + are not yet supported. */ + +enum { + TARGET_SIGINT = 2, + TARGET_SIGTRAP = 5 +}; + +static int gdb_signal_table[] = { + -1, + -1, + TARGET_SIGINT, + -1, + -1, + TARGET_SIGTRAP +}; +#endif + +#ifdef CONFIG_USER_ONLY +static int target_signal_to_gdb (int sig) +{ + int i; + for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++) + if (gdb_signal_table[i] == sig) + return i; + return GDB_SIGNAL_UNKNOWN; +} +#endif + +static int gdb_signal_to_target (int sig) +{ + if (sig < ARRAY_SIZE (gdb_signal_table)) + return gdb_signal_table[sig]; + else + return -1; +} + +typedef struct GDBRegisterState { + int base_reg; + int num_regs; + gdb_get_reg_cb get_reg; + gdb_set_reg_cb set_reg; + const char *xml; + struct GDBRegisterState *next; +} GDBRegisterState; + +typedef struct GDBProcess { + uint32_t pid; + bool attached; + + char target_xml[1024]; +} GDBProcess; + +enum RSState { + RS_INACTIVE, + RS_IDLE, + RS_GETLINE, + RS_GETLINE_ESC, + RS_GETLINE_RLE, + RS_CHKSUM1, + RS_CHKSUM2, +}; +typedef struct GDBState { + bool init; /* have we been initialised? */ + CPUState *c_cpu; /* current CPU for step/continue ops */ + CPUState *g_cpu; /* current CPU for other ops */ + CPUState *query_cpu; /* for q{f|s}ThreadInfo */ + enum RSState state; /* parsing state */ + char line_buf[MAX_PACKET_LENGTH]; + int line_buf_index; + int line_sum; /* running checksum */ + int line_csum; /* checksum at the end of the packet */ + GByteArray *last_packet; + int signal; +#ifdef CONFIG_USER_ONLY + int fd; + char *socket_path; + int running_state; +#else + CharBackend chr; + Chardev *mon_chr; +#endif + bool multiprocess; + GDBProcess *processes; + int process_num; + char syscall_buf[256]; + gdb_syscall_complete_cb current_syscall_cb; + GString *str_buf; + GByteArray *mem_buf; + int sstep_flags; + int supported_sstep_flags; +} GDBState; + +static GDBState gdbserver_state; + +static void init_gdbserver_state(void) +{ + g_assert(!gdbserver_state.init); + memset(&gdbserver_state, 0, sizeof(GDBState)); + gdbserver_state.init = true; + gdbserver_state.str_buf = g_string_new(NULL); + gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH); + gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4); + + /* + * 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 +static void reset_gdbserver_state(void) +{ + g_free(gdbserver_state.processes); + gdbserver_state.processes = NULL; + gdbserver_state.process_num = 0; +} +#endif + +bool gdb_has_xml; + +#ifdef CONFIG_USER_ONLY + +static int get_char(void) +{ + uint8_t ch; + int ret; + + for(;;) { + ret = recv(gdbserver_state.fd, &ch, 1, 0); + if (ret < 0) { + if (errno == ECONNRESET) + gdbserver_state.fd = -1; + if (errno != EINTR) + return -1; + } else if (ret == 0) { + close(gdbserver_state.fd); + gdbserver_state.fd = -1; + return -1; + } else { + break; + } + } + return ch; +} +#endif + +/* + * Return true if there is a GDB currently connected to the stub + * and attached to a CPU + */ +static bool gdb_attached(void) +{ + return gdbserver_state.init && gdbserver_state.c_cpu; +} + +static enum { + GDB_SYS_UNKNOWN, + GDB_SYS_ENABLED, + GDB_SYS_DISABLED, +} gdb_syscall_mode; + +/* Decide if either remote gdb syscalls or native file IO should be used. */ +int use_gdb_syscalls(void) +{ + SemihostingTarget target = semihosting_get_target(); + if (target == SEMIHOSTING_TARGET_NATIVE) { + /* -semihosting-config target=native */ + return false; + } else if (target == SEMIHOSTING_TARGET_GDB) { + /* -semihosting-config target=gdb */ + return true; + } + + /* -semihosting-config target=auto */ + /* On the first call check if gdb is connected and remember. */ + if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { + gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED; + } + return gdb_syscall_mode == GDB_SYS_ENABLED; +} + +static bool stub_can_reverse(void) +{ +#ifdef CONFIG_USER_ONLY + return false; +#else + return replay_mode == REPLAY_MODE_PLAY; +#endif +} + +/* Resume execution. */ +static inline void gdb_continue(void) +{ + +#ifdef CONFIG_USER_ONLY + gdbserver_state.running_state = 1; + trace_gdbstub_op_continue(); +#else + if (!runstate_needs_reset()) { + trace_gdbstub_op_continue(); + vm_start(); + } +#endif +} + +/* + * Resume execution, per CPU actions. For user-mode emulation it's + * equivalent to gdb_continue. + */ +static int gdb_continue_partial(char *newstates) +{ + CPUState *cpu; + int res = 0; +#ifdef CONFIG_USER_ONLY + /* + * This is not exactly accurate, but it's an improvement compared to the + * previous situation, where only one CPU would be single-stepped. + */ + CPU_FOREACH(cpu) { + if (newstates[cpu->cpu_index] == 's') { + trace_gdbstub_op_stepping(cpu->cpu_index); + cpu_single_step(cpu, gdbserver_state.sstep_flags); + } + } + gdbserver_state.running_state = 1; +#else + int flag = 0; + + if (!runstate_needs_reset()) { + bool step_requested = false; + CPU_FOREACH(cpu) { + if (newstates[cpu->cpu_index] == 's') { + step_requested = true; + break; + } + } + + if (vm_prepare_start(step_requested)) { + return 0; + } + + CPU_FOREACH(cpu) { + switch (newstates[cpu->cpu_index]) { + case 0: + case 1: + break; /* nothing to do here */ + case 's': + trace_gdbstub_op_stepping(cpu->cpu_index); + cpu_single_step(cpu, gdbserver_state.sstep_flags); + cpu_resume(cpu); + flag = 1; + break; + case 'c': + trace_gdbstub_op_continue_cpu(cpu->cpu_index); + cpu_resume(cpu); + flag = 1; + break; + default: + res = -1; + break; + } + } + } + if (flag) { + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + } +#endif + return res; +} + +static void put_buffer(const uint8_t *buf, int len) +{ +#ifdef CONFIG_USER_ONLY + int ret; + + while (len > 0) { + ret = send(gdbserver_state.fd, buf, len, 0); + if (ret < 0) { + if (errno != EINTR) + return; + } else { + buf += ret; + len -= ret; + } + } +#else + /* XXX this blocks entire thread. Rewrite to use + * qemu_chr_fe_write and background I/O callbacks */ + qemu_chr_fe_write_all(&gdbserver_state.chr, buf, len); +#endif +} + +static inline int fromhex(int v) +{ + if (v >= '0' && v <= '9') + return v - '0'; + else if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + else if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + else + return 0; +} + +static inline int tohex(int v) +{ + if (v < 10) + return v + '0'; + else + return v - 10 + 'a'; +} + +/* writes 2*len+1 bytes in buf */ +static void memtohex(GString *buf, const uint8_t *mem, int len) +{ + int i, c; + for(i = 0; i < len; i++) { + c = mem[i]; + g_string_append_c(buf, tohex(c >> 4)); + g_string_append_c(buf, tohex(c & 0xf)); + } + g_string_append_c(buf, '\0'); +} + +static void hextomem(GByteArray *mem, const char *buf, int len) +{ + int i; + + for(i = 0; i < len; i++) { + guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]); + g_byte_array_append(mem, &byte, 1); + buf += 2; + } +} + +static void hexdump(const char *buf, int len, + void (*trace_fn)(size_t ofs, char const *text)) +{ + char line_buffer[3 * 16 + 4 + 16 + 1]; + + size_t i; + for (i = 0; i < len || (i & 0xF); ++i) { + size_t byte_ofs = i & 15; + + if (byte_ofs == 0) { + memset(line_buffer, ' ', 3 * 16 + 4 + 16); + line_buffer[3 * 16 + 4 + 16] = 0; + } + + size_t col_group = (i >> 2) & 3; + size_t hex_col = byte_ofs * 3 + col_group; + size_t txt_col = 3 * 16 + 4 + byte_ofs; + + if (i < len) { + char value = buf[i]; + + line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF); + line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF); + line_buffer[txt_col + 0] = (value >= ' ' && value < 127) + ? value + : '.'; + } + + if (byte_ofs == 0xF) + trace_fn(i & -16, line_buffer); + } +} + +/* return -1 if error, 0 if OK */ +static int put_packet_binary(const char *buf, int len, bool dump) +{ + int csum, i; + uint8_t footer[3]; + + if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) { + hexdump(buf, len, trace_gdbstub_io_binaryreply); + } + + for(;;) { + g_byte_array_set_size(gdbserver_state.last_packet, 0); + g_byte_array_append(gdbserver_state.last_packet, + (const uint8_t *) "$", 1); + g_byte_array_append(gdbserver_state.last_packet, + (const uint8_t *) buf, len); + csum = 0; + for(i = 0; i < len; i++) { + csum += buf[i]; + } + footer[0] = '#'; + footer[1] = tohex((csum >> 4) & 0xf); + footer[2] = tohex((csum) & 0xf); + g_byte_array_append(gdbserver_state.last_packet, footer, 3); + + put_buffer(gdbserver_state.last_packet->data, + gdbserver_state.last_packet->len); + +#ifdef CONFIG_USER_ONLY + i = get_char(); + if (i < 0) + return -1; + if (i == '+') + break; +#else + break; +#endif + } + return 0; +} + +/* return -1 if error, 0 if OK */ +static int put_packet(const char *buf) +{ + trace_gdbstub_io_reply(buf); + + return put_packet_binary(buf, strlen(buf), false); +} + +static void put_strbuf(void) +{ + put_packet(gdbserver_state.str_buf->str); +} + +/* Encode data using the encoding for 'x' packets. */ +static void memtox(GString *buf, const char *mem, int len) +{ + char c; + + while (len--) { + c = *(mem++); + switch (c) { + case '#': case '$': case '*': case '}': + g_string_append_c(buf, '}'); + g_string_append_c(buf, c ^ 0x20); + break; + default: + g_string_append_c(buf, c); + break; + } + } +} + +static uint32_t gdb_get_cpu_pid(CPUState *cpu) +{ + /* TODO: In user mode, we should use the task state PID */ + if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) { + /* Return the default process' PID */ + int index = gdbserver_state.process_num - 1; + return gdbserver_state.processes[index].pid; + } + return cpu->cluster_index + 1; +} + +static GDBProcess *gdb_get_process(uint32_t pid) +{ + int i; + + if (!pid) { + /* 0 means any process, we take the first one */ + return &gdbserver_state.processes[0]; + } + + for (i = 0; i < gdbserver_state.process_num; i++) { + if (gdbserver_state.processes[i].pid == pid) { + return &gdbserver_state.processes[i]; + } + } + + return NULL; +} + +static GDBProcess *gdb_get_cpu_process(CPUState *cpu) +{ + return gdb_get_process(gdb_get_cpu_pid(cpu)); +} + +static CPUState *find_cpu(uint32_t thread_id) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + if (cpu_gdb_index(cpu) == thread_id) { + return cpu; + } + } + + return NULL; +} + +static CPUState *get_first_cpu_in_process(GDBProcess *process) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + if (gdb_get_cpu_pid(cpu) == process->pid) { + return cpu; + } + } + + return NULL; +} + +static CPUState *gdb_next_cpu_in_process(CPUState *cpu) +{ + uint32_t pid = gdb_get_cpu_pid(cpu); + cpu = CPU_NEXT(cpu); + + while (cpu) { + if (gdb_get_cpu_pid(cpu) == pid) { + break; + } + + cpu = CPU_NEXT(cpu); + } + + return cpu; +} + +/* Return the cpu following @cpu, while ignoring unattached processes. */ +static CPUState *gdb_next_attached_cpu(CPUState *cpu) +{ + cpu = CPU_NEXT(cpu); + + while (cpu) { + if (gdb_get_cpu_process(cpu)->attached) { + break; + } + + cpu = CPU_NEXT(cpu); + } + + return cpu; +} + +/* Return the first attached cpu */ +static CPUState *gdb_first_attached_cpu(void) +{ + CPUState *cpu = first_cpu; + GDBProcess *process = gdb_get_cpu_process(cpu); + + if (!process->attached) { + return gdb_next_attached_cpu(cpu); + } + + return cpu; +} + +static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) +{ + GDBProcess *process; + CPUState *cpu; + + if (!pid && !tid) { + /* 0 means any process/thread, we take the first attached one */ + return gdb_first_attached_cpu(); + } else if (pid && !tid) { + /* any thread in a specific process */ + process = gdb_get_process(pid); + + if (process == NULL) { + return NULL; + } + + if (!process->attached) { + return NULL; + } + + return get_first_cpu_in_process(process); + } else { + /* a specific thread */ + cpu = find_cpu(tid); + + if (cpu == NULL) { + return NULL; + } + + process = gdb_get_cpu_process(cpu); + + if (pid && process->pid != pid) { + return NULL; + } + + if (!process->attached) { + return NULL; + } + + return cpu; + } +} + +static const char *get_feature_xml(const char *p, const char **newp, + GDBProcess *process) +{ + size_t len; + int i; + const char *name; + CPUState *cpu = get_first_cpu_in_process(process); + CPUClass *cc = CPU_GET_CLASS(cpu); + + len = 0; + while (p[len] && p[len] != ':') + len++; + *newp = p + len; + + name = NULL; + if (strncmp(p, "target.xml", len) == 0) { + char *buf = process->target_xml; + const size_t buf_sz = sizeof(process->target_xml); + + /* Generate the XML description for this CPU. */ + if (!buf[0]) { + GDBRegisterState *r; + + pstrcat(buf, buf_sz, + "" + "" + ""); + if (cc->gdb_arch_name) { + gchar *arch = cc->gdb_arch_name(cpu); + pstrcat(buf, buf_sz, ""); + pstrcat(buf, buf_sz, arch); + pstrcat(buf, buf_sz, ""); + g_free(arch); + } + pstrcat(buf, buf_sz, "gdb_core_xml_file); + pstrcat(buf, buf_sz, "\"/>"); + for (r = cpu->gdb_regs; r; r = r->next) { + pstrcat(buf, buf_sz, "xml); + pstrcat(buf, buf_sz, "\"/>"); + } + pstrcat(buf, buf_sz, ""); + } + return buf; + } + if (cc->gdb_get_dynamic_xml) { + char *xmlname = g_strndup(p, len); + const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname); + + g_free(xmlname); + if (xml) { + return xml; + } + } + for (i = 0; ; i++) { + name = xml_builtin[i][0]; + if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len)) + break; + } + return name ? xml_builtin[i][1] : NULL; +} + +static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + CPUArchState *env = cpu->env_ptr; + GDBRegisterState *r; + + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_read_register(cpu, buf, reg); + } + + for (r = cpu->gdb_regs; r; r = r->next) { + if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { + return r->get_reg(env, buf, reg - r->base_reg); + } + } + return 0; +} + +static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + CPUArchState *env = cpu->env_ptr; + GDBRegisterState *r; + + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_write_register(cpu, mem_buf, reg); + } + + for (r = cpu->gdb_regs; r; r = r->next) { + if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { + return r->set_reg(env, mem_buf, reg - r->base_reg); + } + } + return 0; +} + +/* Register a supplemental set of CPU registers. If g_pos is nonzero it + specifies the first register number and these registers are included in + a standard "g" packet. Direction is relative to gdb, i.e. get_reg is + gdb reading a CPU register, and set_reg is gdb modifying a CPU register. + */ + +void gdb_register_coprocessor(CPUState *cpu, + gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, + int num_regs, const char *xml, int g_pos) +{ + GDBRegisterState *s; + GDBRegisterState **p; + + p = &cpu->gdb_regs; + while (*p) { + /* Check for duplicates. */ + if (strcmp((*p)->xml, xml) == 0) + return; + p = &(*p)->next; + } + + s = g_new0(GDBRegisterState, 1); + s->base_reg = cpu->gdb_num_regs; + s->num_regs = num_regs; + s->get_reg = get_reg; + s->set_reg = set_reg; + s->xml = xml; + + /* Add to end of list. */ + cpu->gdb_num_regs += num_regs; + *p = s; + if (g_pos) { + if (g_pos != s->base_reg) { + error_report("Error: Bad gdb register numbering for '%s', " + "expected %d got %d", xml, g_pos, s->base_reg); + } else { + cpu->gdb_num_g_regs = cpu->gdb_num_regs; + } + } +} + +static void gdb_process_breakpoint_remove_all(GDBProcess *p) +{ + CPUState *cpu = get_first_cpu_in_process(p); + + while (cpu) { + gdb_breakpoint_remove_all(cpu); + cpu = gdb_next_cpu_in_process(cpu); + } +} + + +static void gdb_set_cpu_pc(target_ulong pc) +{ + CPUState *cpu = gdbserver_state.c_cpu; + + cpu_synchronize_state(cpu); + cpu_set_pc(cpu, pc); +} + +static void gdb_append_thread_id(CPUState *cpu, GString *buf) +{ + if (gdbserver_state.multiprocess) { + g_string_append_printf(buf, "p%02x.%02x", + gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu)); + } else { + g_string_append_printf(buf, "%02x", cpu_gdb_index(cpu)); + } +} + +typedef enum GDBThreadIdKind { + GDB_ONE_THREAD = 0, + GDB_ALL_THREADS, /* One process, all threads */ + GDB_ALL_PROCESSES, + GDB_READ_THREAD_ERR +} GDBThreadIdKind; + +static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf, + uint32_t *pid, uint32_t *tid) +{ + unsigned long p, t; + int ret; + + if (*buf == 'p') { + buf++; + ret = qemu_strtoul(buf, &buf, 16, &p); + + if (ret) { + return GDB_READ_THREAD_ERR; + } + + /* Skip '.' */ + buf++; + } else { + p = 1; + } + + ret = qemu_strtoul(buf, &buf, 16, &t); + + if (ret) { + return GDB_READ_THREAD_ERR; + } + + *end_buf = buf; + + if (p == -1) { + return GDB_ALL_PROCESSES; + } + + if (pid) { + *pid = p; + } + + if (t == -1) { + return GDB_ALL_THREADS; + } + + if (tid) { + *tid = t; + } + + return GDB_ONE_THREAD; +} + +/** + * gdb_handle_vcont - Parses and handles a vCont packet. + * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is + * a format error, 0 on success. + */ +static int gdb_handle_vcont(const char *p) +{ + int res, signal = 0; + char cur_action; + char *newstates; + unsigned long tmp; + uint32_t pid, tid; + GDBProcess *process; + CPUState *cpu; + GDBThreadIdKind kind; +#ifdef CONFIG_USER_ONLY + int max_cpus = 1; /* global variable max_cpus exists only in system mode */ + + CPU_FOREACH(cpu) { + max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus; + } +#else + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int max_cpus = ms->smp.max_cpus; +#endif + /* uninitialised CPUs stay 0 */ + newstates = g_new0(char, max_cpus); + + /* mark valid CPUs with 1 */ + CPU_FOREACH(cpu) { + newstates[cpu->cpu_index] = 1; + } + + /* + * res keeps track of what error we are returning, with -ENOTSUP meaning + * that the command is unknown or unsupported, thus returning an empty + * packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid, + * or incorrect parameters passed. + */ + res = 0; + while (*p) { + if (*p++ != ';') { + res = -ENOTSUP; + goto out; + } + + cur_action = *p++; + if (cur_action == 'C' || cur_action == 'S') { + cur_action = qemu_tolower(cur_action); + res = qemu_strtoul(p, &p, 16, &tmp); + if (res) { + goto out; + } + signal = gdb_signal_to_target(tmp); + } else if (cur_action != 'c' && cur_action != 's') { + /* unknown/invalid/unsupported command */ + res = -ENOTSUP; + goto out; + } + + if (*p == '\0' || *p == ';') { + /* + * No thread specifier, action is on "all threads". The + * specification is unclear regarding the process to act on. We + * choose all processes. + */ + kind = GDB_ALL_PROCESSES; + } else if (*p++ == ':') { + kind = read_thread_id(p, &p, &pid, &tid); + } else { + res = -ENOTSUP; + goto out; + } + + switch (kind) { + case GDB_READ_THREAD_ERR: + res = -EINVAL; + goto out; + + case GDB_ALL_PROCESSES: + cpu = gdb_first_attached_cpu(); + while (cpu) { + if (newstates[cpu->cpu_index] == 1) { + newstates[cpu->cpu_index] = cur_action; + } + + cpu = gdb_next_attached_cpu(cpu); + } + break; + + case GDB_ALL_THREADS: + process = gdb_get_process(pid); + + if (!process->attached) { + res = -EINVAL; + goto out; + } + + cpu = get_first_cpu_in_process(process); + while (cpu) { + if (newstates[cpu->cpu_index] == 1) { + newstates[cpu->cpu_index] = cur_action; + } + + cpu = gdb_next_cpu_in_process(cpu); + } + break; + + case GDB_ONE_THREAD: + cpu = gdb_get_cpu(pid, tid); + + /* invalid CPU/thread specified */ + if (!cpu) { + res = -EINVAL; + goto out; + } + + /* only use if no previous match occourred */ + if (newstates[cpu->cpu_index] == 1) { + newstates[cpu->cpu_index] = cur_action; + } + break; + } + } + gdbserver_state.signal = signal; + gdb_continue_partial(newstates); + +out: + g_free(newstates); + + return res; +} + +typedef union GdbCmdVariant { + const char *data; + uint8_t opcode; + unsigned long val_ul; + unsigned long long val_ull; + struct { + GDBThreadIdKind kind; + uint32_t pid; + uint32_t tid; + } thread_id; +} GdbCmdVariant; + +#define get_param(p, i) (&g_array_index(p, GdbCmdVariant, i)) + +static const char *cmd_next_param(const char *param, const char delimiter) +{ + static const char all_delimiters[] = ",;:="; + char curr_delimiters[2] = {0}; + const char *delimiters; + + if (delimiter == '?') { + delimiters = all_delimiters; + } else if (delimiter == '0') { + return strchr(param, '\0'); + } else if (delimiter == '.' && *param) { + return param + 1; + } else { + curr_delimiters[0] = delimiter; + delimiters = curr_delimiters; + } + + param += strcspn(param, delimiters); + if (*param) { + param++; + } + return param; +} + +static int cmd_parse_params(const char *data, const char *schema, + GArray *params) +{ + const char *curr_schema, *curr_data; + + g_assert(schema); + g_assert(params->len == 0); + + curr_schema = schema; + curr_data = data; + while (curr_schema[0] && curr_schema[1] && *curr_data) { + GdbCmdVariant this_param; + + switch (curr_schema[0]) { + case 'l': + if (qemu_strtoul(curr_data, &curr_data, 16, + &this_param.val_ul)) { + return -EINVAL; + } + curr_data = cmd_next_param(curr_data, curr_schema[1]); + g_array_append_val(params, this_param); + break; + case 'L': + if (qemu_strtou64(curr_data, &curr_data, 16, + (uint64_t *)&this_param.val_ull)) { + return -EINVAL; + } + curr_data = cmd_next_param(curr_data, curr_schema[1]); + g_array_append_val(params, this_param); + break; + case 's': + this_param.data = curr_data; + curr_data = cmd_next_param(curr_data, curr_schema[1]); + g_array_append_val(params, this_param); + break; + case 'o': + this_param.opcode = *(uint8_t *)curr_data; + curr_data = cmd_next_param(curr_data, curr_schema[1]); + g_array_append_val(params, this_param); + break; + case 't': + this_param.thread_id.kind = + read_thread_id(curr_data, &curr_data, + &this_param.thread_id.pid, + &this_param.thread_id.tid); + curr_data = cmd_next_param(curr_data, curr_schema[1]); + g_array_append_val(params, this_param); + break; + case '?': + curr_data = cmd_next_param(curr_data, curr_schema[1]); + break; + default: + return -EINVAL; + } + curr_schema += 2; + } + + return 0; +} + +typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx); + +/* + * cmd_startswith -> cmd is compared using startswith + * + * + * schema definitions: + * Each schema parameter entry consists of 2 chars, + * the first char represents the parameter type handling + * the second char represents the delimiter for the next parameter + * + * Currently supported schema types: + * 'l' -> unsigned long (stored in .val_ul) + * 'L' -> unsigned long long (stored in .val_ull) + * 's' -> string (stored in .data) + * 'o' -> single char (stored in .opcode) + * 't' -> thread id (stored in .thread_id) + * '?' -> skip according to delimiter + * + * Currently supported delimiters: + * '?' -> Stop at any delimiter (",;:=\0") + * '0' -> Stop at "\0" + * '.' -> Skip 1 char unless reached "\0" + * Any other value is treated as the delimiter value itself + */ +typedef struct GdbCmdParseEntry { + GdbCmdHandler handler; + const char *cmd; + bool cmd_startswith; + const char *schema; +} GdbCmdParseEntry; + +static inline int startswith(const char *string, const char *pattern) +{ + return !strncmp(string, pattern, strlen(pattern)); +} + +static int process_string_cmd(void *user_ctx, const char *data, + const GdbCmdParseEntry *cmds, int num_cmds) +{ + int i; + g_autoptr(GArray) params = g_array_new(false, true, sizeof(GdbCmdVariant)); + + if (!cmds) { + return -1; + } + + for (i = 0; i < num_cmds; i++) { + const GdbCmdParseEntry *cmd = &cmds[i]; + g_assert(cmd->handler && cmd->cmd); + + if ((cmd->cmd_startswith && !startswith(data, cmd->cmd)) || + (!cmd->cmd_startswith && strcmp(cmd->cmd, data))) { + continue; + } + + if (cmd->schema) { + if (cmd_parse_params(&data[strlen(cmd->cmd)], + cmd->schema, params)) { + return -1; + } + } + + cmd->handler(params, user_ctx); + return 0; + } + + return -1; +} + +static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd) +{ + if (!data) { + return; + } + + g_string_set_size(gdbserver_state.str_buf, 0); + g_byte_array_set_size(gdbserver_state.mem_buf, 0); + + /* In case there was an error during the command parsing we must + * send a NULL packet to indicate the command is not supported */ + if (process_string_cmd(NULL, data, cmd, 1)) { + put_packet(""); + } +} + +static void handle_detach(GArray *params, void *user_ctx) +{ + GDBProcess *process; + uint32_t pid = 1; + + if (gdbserver_state.multiprocess) { + if (!params->len) { + put_packet("E22"); + return; + } + + pid = get_param(params, 0)->val_ul; + } + + process = gdb_get_process(pid); + gdb_process_breakpoint_remove_all(process); + process->attached = false; + + if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) { + gdbserver_state.c_cpu = gdb_first_attached_cpu(); + } + + if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) { + gdbserver_state.g_cpu = gdb_first_attached_cpu(); + } + + if (!gdbserver_state.c_cpu) { + /* No more process attached */ + gdb_syscall_mode = GDB_SYS_DISABLED; + gdb_continue(); + } + put_packet("OK"); +} + +static void handle_thread_alive(GArray *params, void *user_ctx) +{ + CPUState *cpu; + + if (!params->len) { + put_packet("E22"); + return; + } + + if (get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) { + put_packet("E22"); + return; + } + + cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid, + get_param(params, 0)->thread_id.tid); + if (!cpu) { + put_packet("E22"); + return; + } + + put_packet("OK"); +} + +static void handle_continue(GArray *params, void *user_ctx) +{ + if (params->len) { + gdb_set_cpu_pc(get_param(params, 0)->val_ull); + } + + gdbserver_state.signal = 0; + gdb_continue(); +} + +static void handle_cont_with_sig(GArray *params, void *user_ctx) +{ + unsigned long signal = 0; + + /* + * Note: C sig;[addr] is currently unsupported and we simply + * omit the addr parameter + */ + if (params->len) { + signal = get_param(params, 0)->val_ul; + } + + gdbserver_state.signal = gdb_signal_to_target(signal); + if (gdbserver_state.signal == -1) { + gdbserver_state.signal = 0; + } + gdb_continue(); +} + +static void handle_set_thread(GArray *params, void *user_ctx) +{ + CPUState *cpu; + + if (params->len != 2) { + put_packet("E22"); + return; + } + + if (get_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) { + put_packet("E22"); + return; + } + + if (get_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) { + put_packet("OK"); + return; + } + + cpu = gdb_get_cpu(get_param(params, 1)->thread_id.pid, + get_param(params, 1)->thread_id.tid); + if (!cpu) { + put_packet("E22"); + return; + } + + /* + * Note: This command is deprecated and modern gdb's will be using the + * vCont command instead. + */ + switch (get_param(params, 0)->opcode) { + case 'c': + gdbserver_state.c_cpu = cpu; + put_packet("OK"); + break; + case 'g': + gdbserver_state.g_cpu = cpu; + put_packet("OK"); + break; + default: + put_packet("E22"); + break; + } +} + +static void handle_insert_bp(GArray *params, void *user_ctx) +{ + int res; + + if (params->len != 3) { + put_packet("E22"); + return; + } + + 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) { + put_packet("OK"); + return; + } else if (res == -ENOSYS) { + put_packet(""); + return; + } + + put_packet("E22"); +} + +static void handle_remove_bp(GArray *params, void *user_ctx) +{ + int res; + + if (params->len != 3) { + put_packet("E22"); + return; + } + + 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) { + put_packet("OK"); + return; + } else if (res == -ENOSYS) { + put_packet(""); + return; + } + + put_packet("E22"); +} + +/* + * handle_set/get_reg + * + * Older gdb are really dumb, and don't use 'G/g' if 'P/p' is available. + * This works, but can be very slow. Anything new enough to understand + * XML also knows how to use this properly. However to use this we + * need to define a local XML file as well as be talking to a + * reasonably modern gdb. Responding with an empty packet will cause + * the remote gdb to fallback to older methods. + */ + +static void handle_set_reg(GArray *params, void *user_ctx) +{ + int reg_size; + + if (!gdb_has_xml) { + put_packet(""); + return; + } + + if (params->len != 2) { + put_packet("E22"); + return; + } + + reg_size = strlen(get_param(params, 1)->data) / 2; + hextomem(gdbserver_state.mem_buf, get_param(params, 1)->data, reg_size); + gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data, + get_param(params, 0)->val_ull); + put_packet("OK"); +} + +static void handle_get_reg(GArray *params, void *user_ctx) +{ + int reg_size; + + if (!gdb_has_xml) { + put_packet(""); + return; + } + + if (!params->len) { + put_packet("E14"); + return; + } + + reg_size = gdb_read_register(gdbserver_state.g_cpu, + gdbserver_state.mem_buf, + get_param(params, 0)->val_ull); + if (!reg_size) { + put_packet("E14"); + return; + } else { + g_byte_array_set_size(gdbserver_state.mem_buf, reg_size); + } + + memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, reg_size); + put_strbuf(); +} + +static void handle_write_mem(GArray *params, void *user_ctx) +{ + if (params->len != 3) { + put_packet("E22"); + return; + } + + /* hextomem() reads 2*len bytes */ + if (get_param(params, 1)->val_ull > + strlen(get_param(params, 2)->data) / 2) { + put_packet("E22"); + return; + } + + hextomem(gdbserver_state.mem_buf, get_param(params, 2)->data, + get_param(params, 1)->val_ull); + if (target_memory_rw_debug(gdbserver_state.g_cpu, + get_param(params, 0)->val_ull, + gdbserver_state.mem_buf->data, + gdbserver_state.mem_buf->len, true)) { + put_packet("E14"); + return; + } + + put_packet("OK"); +} + +static void handle_read_mem(GArray *params, void *user_ctx) +{ + if (params->len != 2) { + put_packet("E22"); + return; + } + + /* memtohex() doubles the required space */ + if (get_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) { + put_packet("E22"); + return; + } + + g_byte_array_set_size(gdbserver_state.mem_buf, + get_param(params, 1)->val_ull); + + if (target_memory_rw_debug(gdbserver_state.g_cpu, + get_param(params, 0)->val_ull, + gdbserver_state.mem_buf->data, + gdbserver_state.mem_buf->len, false)) { + put_packet("E14"); + return; + } + + memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, + gdbserver_state.mem_buf->len); + put_strbuf(); +} + +static void handle_write_all_regs(GArray *params, void *user_ctx) +{ + target_ulong addr, len; + uint8_t *registers; + int reg_size; + + if (!params->len) { + return; + } + + cpu_synchronize_state(gdbserver_state.g_cpu); + len = strlen(get_param(params, 0)->data) / 2; + hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len); + registers = gdbserver_state.mem_buf->data; + for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0; + addr++) { + reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, addr); + len -= reg_size; + registers += reg_size; + } + put_packet("OK"); +} + +static void handle_read_all_regs(GArray *params, void *user_ctx) +{ + target_ulong addr, len; + + cpu_synchronize_state(gdbserver_state.g_cpu); + g_byte_array_set_size(gdbserver_state.mem_buf, 0); + len = 0; + for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) { + len += gdb_read_register(gdbserver_state.g_cpu, + gdbserver_state.mem_buf, + addr); + } + g_assert(len == gdbserver_state.mem_buf->len); + + memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len); + put_strbuf(); +} + +static void handle_file_io(GArray *params, void *user_ctx) +{ + if (params->len >= 1 && gdbserver_state.current_syscall_cb) { + uint64_t ret; + int err; + + ret = get_param(params, 0)->val_ull; + if (params->len >= 2) { + err = get_param(params, 1)->val_ull; + } else { + err = 0; + } + + /* Convert GDB error numbers back to host error numbers. */ +#define E(X) case GDB_E##X: err = E##X; break + switch (err) { + case 0: + break; + 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: + err = EINVAL; + break; + } +#undef E + + gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err); + gdbserver_state.current_syscall_cb = NULL; + } + + if (params->len >= 3 && get_param(params, 2)->opcode == (uint8_t)'C') { + put_packet("T02"); + return; + } + + gdb_continue(); +} + +static void handle_step(GArray *params, void *user_ctx) +{ + if (params->len) { + gdb_set_cpu_pc((target_ulong)get_param(params, 0)->val_ull); + } + + cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags); + gdb_continue(); +} + +static void handle_backward(GArray *params, void *user_ctx) +{ + if (!stub_can_reverse()) { + put_packet("E22"); + } + if (params->len == 1) { + switch (get_param(params, 0)->opcode) { + case 's': + if (replay_reverse_step()) { + gdb_continue(); + } else { + put_packet("E14"); + } + return; + case 'c': + if (replay_reverse_continue()) { + gdb_continue(); + } else { + put_packet("E14"); + } + return; + } + } + + /* Default invalid command */ + put_packet(""); +} + +static void handle_v_cont_query(GArray *params, void *user_ctx) +{ + put_packet("vCont;c;C;s;S"); +} + +static void handle_v_cont(GArray *params, void *user_ctx) +{ + int res; + + if (!params->len) { + return; + } + + res = gdb_handle_vcont(get_param(params, 0)->data); + if ((res == -EINVAL) || (res == -ERANGE)) { + put_packet("E22"); + } else if (res) { + put_packet(""); + } +} + +static void handle_v_attach(GArray *params, void *user_ctx) +{ + GDBProcess *process; + CPUState *cpu; + + g_string_assign(gdbserver_state.str_buf, "E22"); + if (!params->len) { + goto cleanup; + } + + process = gdb_get_process(get_param(params, 0)->val_ul); + if (!process) { + goto cleanup; + } + + cpu = get_first_cpu_in_process(process); + if (!cpu) { + goto cleanup; + } + + process->attached = true; + gdbserver_state.g_cpu = cpu; + gdbserver_state.c_cpu = cpu; + + g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP); + gdb_append_thread_id(cpu, gdbserver_state.str_buf); + g_string_append_c(gdbserver_state.str_buf, ';'); +cleanup: + put_strbuf(); +} + +static void handle_v_kill(GArray *params, void *user_ctx) +{ + /* Kill the target */ + put_packet("OK"); + error_report("QEMU: Terminated via GDBstub"); + gdb_exit(0); + exit(0); +} + +static const GdbCmdParseEntry gdb_v_commands_table[] = { + /* Order is important if has same prefix */ + { + .handler = handle_v_cont_query, + .cmd = "Cont?", + .cmd_startswith = 1 + }, + { + .handler = handle_v_cont, + .cmd = "Cont", + .cmd_startswith = 1, + .schema = "s0" + }, + { + .handler = handle_v_attach, + .cmd = "Attach;", + .cmd_startswith = 1, + .schema = "l0" + }, + { + .handler = handle_v_kill, + .cmd = "Kill;", + .cmd_startswith = 1 + }, +}; + +static void handle_v_commands(GArray *params, void *user_ctx) +{ + if (!params->len) { + return; + } + + if (process_string_cmd(NULL, get_param(params, 0)->data, + gdb_v_commands_table, + ARRAY_SIZE(gdb_v_commands_table))) { + put_packet(""); + } +} + +static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx) +{ + g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE); + + if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) { + g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x", + SSTEP_NOIRQ); + } + + if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) { + g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x", + SSTEP_NOTIMER); + } + + put_strbuf(); +} + +static void handle_set_qemu_sstep(GArray *params, void *user_ctx) +{ + int new_sstep_flags; + + if (!params->len) { + return; + } + + new_sstep_flags = get_param(params, 0)->val_ul; + + if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) { + put_packet("E22"); + return; + } + + gdbserver_state.sstep_flags = new_sstep_flags; + put_packet("OK"); +} + +static void handle_query_qemu_sstep(GArray *params, void *user_ctx) +{ + g_string_printf(gdbserver_state.str_buf, "0x%x", + gdbserver_state.sstep_flags); + put_strbuf(); +} + +static void handle_query_curr_tid(GArray *params, void *user_ctx) +{ + CPUState *cpu; + GDBProcess *process; + + /* + * "Current thread" remains vague in the spec, so always return + * the first thread of the current process (gdb returns the + * first thread). + */ + process = gdb_get_cpu_process(gdbserver_state.g_cpu); + cpu = get_first_cpu_in_process(process); + g_string_assign(gdbserver_state.str_buf, "QC"); + gdb_append_thread_id(cpu, gdbserver_state.str_buf); + put_strbuf(); +} + +static void handle_query_threads(GArray *params, void *user_ctx) +{ + if (!gdbserver_state.query_cpu) { + put_packet("l"); + return; + } + + g_string_assign(gdbserver_state.str_buf, "m"); + gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf); + put_strbuf(); + gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu); +} + +static void handle_query_first_threads(GArray *params, void *user_ctx) +{ + gdbserver_state.query_cpu = gdb_first_attached_cpu(); + handle_query_threads(params, user_ctx); +} + +static void handle_query_thread_extra(GArray *params, void *user_ctx) +{ + g_autoptr(GString) rs = g_string_new(NULL); + CPUState *cpu; + + if (!params->len || + get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) { + put_packet("E22"); + return; + } + + cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid, + get_param(params, 0)->thread_id.tid); + if (!cpu) { + return; + } + + cpu_synchronize_state(cpu); + + if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) { + /* Print the CPU model and name in multiprocess mode */ + ObjectClass *oc = object_get_class(OBJECT(cpu)); + const char *cpu_model = object_class_get_name(oc); + const char *cpu_name = + object_get_canonical_path_component(OBJECT(cpu)); + g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name, + cpu->halted ? "halted " : "running"); + } else { + g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index, + cpu->halted ? "halted " : "running"); + } + trace_gdbstub_op_extra_info(rs->str); + memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len); + put_strbuf(); +} + +#ifdef CONFIG_USER_ONLY +static void handle_query_offsets(GArray *params, void *user_ctx) +{ + TaskState *ts; + + ts = gdbserver_state.c_cpu->opaque; + g_string_printf(gdbserver_state.str_buf, + "Text=" TARGET_ABI_FMT_lx + ";Data=" TARGET_ABI_FMT_lx + ";Bss=" TARGET_ABI_FMT_lx, + ts->info->code_offset, + ts->info->data_offset, + ts->info->data_offset); + put_strbuf(); +} +#else +static void handle_query_rcmd(GArray *params, void *user_ctx) +{ + const guint8 zero = 0; + int len; + + if (!params->len) { + put_packet("E22"); + return; + } + + len = strlen(get_param(params, 0)->data); + if (len % 2) { + put_packet("E01"); + return; + } + + g_assert(gdbserver_state.mem_buf->len == 0); + len = len / 2; + hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len); + g_byte_array_append(gdbserver_state.mem_buf, &zero, 1); + qemu_chr_be_write(gdbserver_state.mon_chr, gdbserver_state.mem_buf->data, + gdbserver_state.mem_buf->len); + put_packet("OK"); +} +#endif + +static void handle_query_supported(GArray *params, void *user_ctx) +{ + CPUClass *cc; + + g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH); + cc = CPU_GET_CLASS(first_cpu); + if (cc->gdb_core_xml_file) { + g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+"); + } + + if (stub_can_reverse()) { + g_string_append(gdbserver_state.str_buf, + ";ReverseStep+;ReverseContinue+"); + } + +#ifdef CONFIG_USER_ONLY + if (gdbserver_state.c_cpu->opaque) { + g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+"); + } +#endif + + if (params->len && + strstr(get_param(params, 0)->data, "multiprocess+")) { + gdbserver_state.multiprocess = true; + } + + g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+"); + put_strbuf(); +} + +static void handle_query_xfer_features(GArray *params, void *user_ctx) +{ + GDBProcess *process; + CPUClass *cc; + unsigned long len, total_len, addr; + const char *xml; + const char *p; + + if (params->len < 3) { + put_packet("E22"); + return; + } + + process = gdb_get_cpu_process(gdbserver_state.g_cpu); + cc = CPU_GET_CLASS(gdbserver_state.g_cpu); + if (!cc->gdb_core_xml_file) { + put_packet(""); + return; + } + + gdb_has_xml = true; + p = get_param(params, 0)->data; + xml = get_feature_xml(p, &p, process); + if (!xml) { + put_packet("E00"); + return; + } + + addr = get_param(params, 1)->val_ul; + len = get_param(params, 2)->val_ul; + total_len = strlen(xml); + if (addr > total_len) { + put_packet("E00"); + return; + } + + if (len > (MAX_PACKET_LENGTH - 5) / 2) { + len = (MAX_PACKET_LENGTH - 5) / 2; + } + + if (len < total_len - addr) { + g_string_assign(gdbserver_state.str_buf, "m"); + memtox(gdbserver_state.str_buf, xml + addr, len); + } else { + g_string_assign(gdbserver_state.str_buf, "l"); + memtox(gdbserver_state.str_buf, xml + addr, total_len - addr); + } + + put_packet_binary(gdbserver_state.str_buf->str, + gdbserver_state.str_buf->len, true); +} + +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER) +static void handle_query_xfer_auxv(GArray *params, void *user_ctx) +{ + TaskState *ts; + unsigned long offset, len, saved_auxv, auxv_len; + + if (params->len < 2) { + put_packet("E22"); + return; + } + + offset = get_param(params, 0)->val_ul; + len = get_param(params, 1)->val_ul; + ts = gdbserver_state.c_cpu->opaque; + saved_auxv = ts->info->saved_auxv; + auxv_len = ts->info->auxv_len; + + if (offset >= auxv_len) { + put_packet("E00"); + return; + } + + if (len > (MAX_PACKET_LENGTH - 5) / 2) { + len = (MAX_PACKET_LENGTH - 5) / 2; + } + + if (len < auxv_len - offset) { + g_string_assign(gdbserver_state.str_buf, "m"); + } else { + g_string_assign(gdbserver_state.str_buf, "l"); + len = auxv_len - offset; + } + + g_byte_array_set_size(gdbserver_state.mem_buf, len); + if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset, + gdbserver_state.mem_buf->data, len, false)) { + put_packet("E14"); + return; + } + + memtox(gdbserver_state.str_buf, + (const char *)gdbserver_state.mem_buf->data, len); + put_packet_binary(gdbserver_state.str_buf->str, + gdbserver_state.str_buf->len, true); +} +#endif + +static void handle_query_attached(GArray *params, void *user_ctx) +{ + put_packet(GDB_ATTACHED); +} + +static void handle_query_qemu_supported(GArray *params, void *user_ctx) +{ + g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep"); +#ifndef CONFIG_USER_ONLY + g_string_append(gdbserver_state.str_buf, ";PhyMemMode"); +#endif + put_strbuf(); +} + +#ifndef CONFIG_USER_ONLY +static void handle_query_qemu_phy_mem_mode(GArray *params, + void *user_ctx) +{ + g_string_printf(gdbserver_state.str_buf, "%d", phy_memory_mode); + put_strbuf(); +} + +static void handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx) +{ + if (!params->len) { + put_packet("E22"); + return; + } + + if (!get_param(params, 0)->val_ul) { + phy_memory_mode = 0; + } else { + phy_memory_mode = 1; + } + put_packet("OK"); +} +#endif + +static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = { + /* Order is important if has same prefix */ + { + .handler = handle_query_qemu_sstepbits, + .cmd = "qemu.sstepbits", + }, + { + .handler = handle_query_qemu_sstep, + .cmd = "qemu.sstep", + }, + { + .handler = handle_set_qemu_sstep, + .cmd = "qemu.sstep=", + .cmd_startswith = 1, + .schema = "l0" + }, +}; + +static const GdbCmdParseEntry gdb_gen_query_table[] = { + { + .handler = handle_query_curr_tid, + .cmd = "C", + }, + { + .handler = handle_query_threads, + .cmd = "sThreadInfo", + }, + { + .handler = handle_query_first_threads, + .cmd = "fThreadInfo", + }, + { + .handler = handle_query_thread_extra, + .cmd = "ThreadExtraInfo,", + .cmd_startswith = 1, + .schema = "t0" + }, +#ifdef CONFIG_USER_ONLY + { + .handler = handle_query_offsets, + .cmd = "Offsets", + }, +#else + { + .handler = handle_query_rcmd, + .cmd = "Rcmd,", + .cmd_startswith = 1, + .schema = "s0" + }, +#endif + { + .handler = handle_query_supported, + .cmd = "Supported:", + .cmd_startswith = 1, + .schema = "s0" + }, + { + .handler = handle_query_supported, + .cmd = "Supported", + .schema = "s0" + }, + { + .handler = handle_query_xfer_features, + .cmd = "Xfer:features:read:", + .cmd_startswith = 1, + .schema = "s:l,l0" + }, +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER) + { + .handler = handle_query_xfer_auxv, + .cmd = "Xfer:auxv:read::", + .cmd_startswith = 1, + .schema = "l,l0" + }, +#endif + { + .handler = handle_query_attached, + .cmd = "Attached:", + .cmd_startswith = 1 + }, + { + .handler = handle_query_attached, + .cmd = "Attached", + }, + { + .handler = handle_query_qemu_supported, + .cmd = "qemu.Supported", + }, +#ifndef CONFIG_USER_ONLY + { + .handler = handle_query_qemu_phy_mem_mode, + .cmd = "qemu.PhyMemMode", + }, +#endif +}; + +static const GdbCmdParseEntry gdb_gen_set_table[] = { + /* Order is important if has same prefix */ + { + .handler = handle_set_qemu_sstep, + .cmd = "qemu.sstep:", + .cmd_startswith = 1, + .schema = "l0" + }, +#ifndef CONFIG_USER_ONLY + { + .handler = handle_set_qemu_phy_mem_mode, + .cmd = "qemu.PhyMemMode:", + .cmd_startswith = 1, + .schema = "l0" + }, +#endif +}; + +static void handle_gen_query(GArray *params, void *user_ctx) +{ + if (!params->len) { + return; + } + + if (!process_string_cmd(NULL, get_param(params, 0)->data, + gdb_gen_query_set_common_table, + ARRAY_SIZE(gdb_gen_query_set_common_table))) { + return; + } + + if (process_string_cmd(NULL, get_param(params, 0)->data, + gdb_gen_query_table, + ARRAY_SIZE(gdb_gen_query_table))) { + put_packet(""); + } +} + +static void handle_gen_set(GArray *params, void *user_ctx) +{ + if (!params->len) { + return; + } + + if (!process_string_cmd(NULL, get_param(params, 0)->data, + gdb_gen_query_set_common_table, + ARRAY_SIZE(gdb_gen_query_set_common_table))) { + return; + } + + if (process_string_cmd(NULL, get_param(params, 0)->data, + gdb_gen_set_table, + ARRAY_SIZE(gdb_gen_set_table))) { + put_packet(""); + } +} + +static void handle_target_halt(GArray *params, void *user_ctx) +{ + g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP); + gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf); + g_string_append_c(gdbserver_state.str_buf, ';'); + put_strbuf(); + /* + * Remove all the breakpoints when this query is issued, + * because gdb is doing an initial connect and the state + * should be cleaned up. + */ + gdb_breakpoint_remove_all(gdbserver_state.c_cpu); +} + +static int gdb_handle_packet(const char *line_buf) +{ + const GdbCmdParseEntry *cmd_parser = NULL; + + trace_gdbstub_io_command(line_buf); + + switch (line_buf[0]) { + case '!': + put_packet("OK"); + break; + case '?': + { + static const GdbCmdParseEntry target_halted_cmd_desc = { + .handler = handle_target_halt, + .cmd = "?", + .cmd_startswith = 1 + }; + cmd_parser = &target_halted_cmd_desc; + } + break; + case 'c': + { + static const GdbCmdParseEntry continue_cmd_desc = { + .handler = handle_continue, + .cmd = "c", + .cmd_startswith = 1, + .schema = "L0" + }; + cmd_parser = &continue_cmd_desc; + } + break; + case 'C': + { + static const GdbCmdParseEntry cont_with_sig_cmd_desc = { + .handler = handle_cont_with_sig, + .cmd = "C", + .cmd_startswith = 1, + .schema = "l0" + }; + cmd_parser = &cont_with_sig_cmd_desc; + } + break; + case 'v': + { + static const GdbCmdParseEntry v_cmd_desc = { + .handler = handle_v_commands, + .cmd = "v", + .cmd_startswith = 1, + .schema = "s0" + }; + cmd_parser = &v_cmd_desc; + } + break; + case 'k': + /* Kill the target */ + error_report("QEMU: Terminated via GDBstub"); + gdb_exit(0); + exit(0); + case 'D': + { + static const GdbCmdParseEntry detach_cmd_desc = { + .handler = handle_detach, + .cmd = "D", + .cmd_startswith = 1, + .schema = "?.l0" + }; + cmd_parser = &detach_cmd_desc; + } + break; + case 's': + { + static const GdbCmdParseEntry step_cmd_desc = { + .handler = handle_step, + .cmd = "s", + .cmd_startswith = 1, + .schema = "L0" + }; + cmd_parser = &step_cmd_desc; + } + break; + case 'b': + { + static const GdbCmdParseEntry backward_cmd_desc = { + .handler = handle_backward, + .cmd = "b", + .cmd_startswith = 1, + .schema = "o0" + }; + cmd_parser = &backward_cmd_desc; + } + break; + case 'F': + { + static const GdbCmdParseEntry file_io_cmd_desc = { + .handler = handle_file_io, + .cmd = "F", + .cmd_startswith = 1, + .schema = "L,L,o0" + }; + cmd_parser = &file_io_cmd_desc; + } + break; + case 'g': + { + static const GdbCmdParseEntry read_all_regs_cmd_desc = { + .handler = handle_read_all_regs, + .cmd = "g", + .cmd_startswith = 1 + }; + cmd_parser = &read_all_regs_cmd_desc; + } + break; + case 'G': + { + static const GdbCmdParseEntry write_all_regs_cmd_desc = { + .handler = handle_write_all_regs, + .cmd = "G", + .cmd_startswith = 1, + .schema = "s0" + }; + cmd_parser = &write_all_regs_cmd_desc; + } + break; + case 'm': + { + static const GdbCmdParseEntry read_mem_cmd_desc = { + .handler = handle_read_mem, + .cmd = "m", + .cmd_startswith = 1, + .schema = "L,L0" + }; + cmd_parser = &read_mem_cmd_desc; + } + break; + case 'M': + { + static const GdbCmdParseEntry write_mem_cmd_desc = { + .handler = handle_write_mem, + .cmd = "M", + .cmd_startswith = 1, + .schema = "L,L:s0" + }; + cmd_parser = &write_mem_cmd_desc; + } + break; + case 'p': + { + static const GdbCmdParseEntry get_reg_cmd_desc = { + .handler = handle_get_reg, + .cmd = "p", + .cmd_startswith = 1, + .schema = "L0" + }; + cmd_parser = &get_reg_cmd_desc; + } + break; + case 'P': + { + static const GdbCmdParseEntry set_reg_cmd_desc = { + .handler = handle_set_reg, + .cmd = "P", + .cmd_startswith = 1, + .schema = "L?s0" + }; + cmd_parser = &set_reg_cmd_desc; + } + break; + case 'Z': + { + static const GdbCmdParseEntry insert_bp_cmd_desc = { + .handler = handle_insert_bp, + .cmd = "Z", + .cmd_startswith = 1, + .schema = "l?L?L0" + }; + cmd_parser = &insert_bp_cmd_desc; + } + break; + case 'z': + { + static const GdbCmdParseEntry remove_bp_cmd_desc = { + .handler = handle_remove_bp, + .cmd = "z", + .cmd_startswith = 1, + .schema = "l?L?L0" + }; + cmd_parser = &remove_bp_cmd_desc; + } + break; + case 'H': + { + static const GdbCmdParseEntry set_thread_cmd_desc = { + .handler = handle_set_thread, + .cmd = "H", + .cmd_startswith = 1, + .schema = "o.t0" + }; + cmd_parser = &set_thread_cmd_desc; + } + break; + case 'T': + { + static const GdbCmdParseEntry thread_alive_cmd_desc = { + .handler = handle_thread_alive, + .cmd = "T", + .cmd_startswith = 1, + .schema = "t0" + }; + cmd_parser = &thread_alive_cmd_desc; + } + break; + case 'q': + { + static const GdbCmdParseEntry gen_query_cmd_desc = { + .handler = handle_gen_query, + .cmd = "q", + .cmd_startswith = 1, + .schema = "s0" + }; + cmd_parser = &gen_query_cmd_desc; + } + break; + case 'Q': + { + static const GdbCmdParseEntry gen_set_cmd_desc = { + .handler = handle_gen_set, + .cmd = "Q", + .cmd_startswith = 1, + .schema = "s0" + }; + cmd_parser = &gen_set_cmd_desc; + } + break; + default: + /* put empty packet */ + put_packet(""); + break; + } + + if (cmd_parser) { + run_cmd_parser(line_buf, cmd_parser); + } + + return RS_IDLE; +} + +void gdb_set_stop_cpu(CPUState *cpu) +{ + GDBProcess *p = gdb_get_cpu_process(cpu); + + if (!p->attached) { + /* + * Having a stop CPU corresponding to a process that is not attached + * confuses GDB. So we ignore the request. + */ + return; + } + + gdbserver_state.c_cpu = cpu; + gdbserver_state.g_cpu = cpu; +} + +#ifndef CONFIG_USER_ONLY +static void gdb_vm_state_change(void *opaque, bool running, RunState state) +{ + CPUState *cpu = gdbserver_state.c_cpu; + g_autoptr(GString) buf = g_string_new(NULL); + g_autoptr(GString) tid = g_string_new(NULL); + const char *type; + int ret; + + if (running || gdbserver_state.state == RS_INACTIVE) { + return; + } + /* Is there a GDB syscall waiting to be sent? */ + if (gdbserver_state.current_syscall_cb) { + put_packet(gdbserver_state.syscall_buf); + return; + } + + if (cpu == NULL) { + /* No process attached */ + return; + } + + gdb_append_thread_id(cpu, tid); + + switch (state) { + case RUN_STATE_DEBUG: + if (cpu->watchpoint_hit) { + switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) { + case BP_MEM_READ: + type = "r"; + break; + case BP_MEM_ACCESS: + type = "a"; + break; + default: + type = ""; + break; + } + trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu), + (target_ulong)cpu->watchpoint_hit->vaddr); + g_string_printf(buf, "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";", + GDB_SIGNAL_TRAP, tid->str, type, + (target_ulong)cpu->watchpoint_hit->vaddr); + cpu->watchpoint_hit = NULL; + goto send_packet; + } else { + trace_gdbstub_hit_break(); + } + tb_flush(cpu); + ret = GDB_SIGNAL_TRAP; + break; + case RUN_STATE_PAUSED: + trace_gdbstub_hit_paused(); + ret = GDB_SIGNAL_INT; + break; + case RUN_STATE_SHUTDOWN: + trace_gdbstub_hit_shutdown(); + ret = GDB_SIGNAL_QUIT; + break; + case RUN_STATE_IO_ERROR: + trace_gdbstub_hit_io_error(); + ret = GDB_SIGNAL_IO; + break; + case RUN_STATE_WATCHDOG: + trace_gdbstub_hit_watchdog(); + ret = GDB_SIGNAL_ALRM; + break; + case RUN_STATE_INTERNAL_ERROR: + trace_gdbstub_hit_internal_error(); + ret = GDB_SIGNAL_ABRT; + break; + case RUN_STATE_SAVE_VM: + case RUN_STATE_RESTORE_VM: + return; + case RUN_STATE_FINISH_MIGRATE: + ret = GDB_SIGNAL_XCPU; + break; + default: + trace_gdbstub_hit_unknown(state); + ret = GDB_SIGNAL_UNKNOWN; + break; + } + gdb_set_stop_cpu(cpu); + g_string_printf(buf, "T%02xthread:%s;", ret, tid->str); + +send_packet: + put_packet(buf->str); + + /* disable single step if it was enabled */ + cpu_single_step(cpu, 0); +} +#endif + +/* Send a gdb syscall request. + This accepts limited printf-style format specifiers, specifically: + %x - target_ulong argument printed in hex. + %lx - 64-bit argument printed in hex. + %s - string pointer (target_ulong) and length (int) pair. */ +void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va) +{ + char *p; + char *p_end; + target_ulong addr; + uint64_t i64; + + if (!gdb_attached()) { + return; + } + + gdbserver_state.current_syscall_cb = cb; +#ifndef CONFIG_USER_ONLY + vm_stop(RUN_STATE_DEBUG); +#endif + p = &gdbserver_state.syscall_buf[0]; + p_end = &gdbserver_state.syscall_buf[sizeof(gdbserver_state.syscall_buf)]; + *(p++) = 'F'; + while (*fmt) { + if (*fmt == '%') { + fmt++; + switch (*fmt++) { + case 'x': + addr = va_arg(va, target_ulong); + p += snprintf(p, p_end - p, TARGET_FMT_lx, addr); + break; + case 'l': + if (*(fmt++) != 'x') + goto bad_format; + i64 = va_arg(va, uint64_t); + p += snprintf(p, p_end - p, "%" PRIx64, i64); + break; + case 's': + addr = va_arg(va, target_ulong); + p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x", + addr, va_arg(va, int)); + break; + default: + bad_format: + error_report("gdbstub: Bad syscall format string '%s'", + fmt - 1); + break; + } + } else { + *(p++) = *(fmt++); + } + } + *p = 0; +#ifdef CONFIG_USER_ONLY + put_packet(gdbserver_state.syscall_buf); + /* Return control to gdb for it to process the syscall request. + * Since the protocol requires that gdb hands control back to us + * using a "here are the results" F packet, we don't need to check + * gdb_handlesig's return value (which is the signal to deliver if + * execution was resumed via a continue packet). + */ + gdb_handlesig(gdbserver_state.c_cpu, 0); +#else + /* In this case wait to send the syscall packet until notification that + the CPU has stopped. This must be done because if the packet is sent + now the reply from the syscall request could be received while the CPU + is still in the running state, which can cause packets to be dropped + and state transition 'T' packets to be sent while the syscall is still + being processed. */ + qemu_cpu_kick(gdbserver_state.c_cpu); +#endif +} + +void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + gdb_do_syscallv(cb, fmt, va); + va_end(va); +} + +static void gdb_read_byte(uint8_t ch) +{ + uint8_t reply; + +#ifndef CONFIG_USER_ONLY + if (gdbserver_state.last_packet->len) { + /* Waiting for a response to the last packet. If we see the start + of a new command then abandon the previous response. */ + if (ch == '-') { + trace_gdbstub_err_got_nack(); + put_buffer(gdbserver_state.last_packet->data, + gdbserver_state.last_packet->len); + } else if (ch == '+') { + trace_gdbstub_io_got_ack(); + } else { + trace_gdbstub_io_got_unexpected(ch); + } + + if (ch == '+' || ch == '$') { + g_byte_array_set_size(gdbserver_state.last_packet, 0); + } + if (ch != '$') + return; + } + if (runstate_is_running()) { + /* when the CPU is running, we cannot do anything except stop + it when receiving a char */ + vm_stop(RUN_STATE_PAUSED); + } else +#endif + { + switch(gdbserver_state.state) { + case RS_IDLE: + if (ch == '$') { + /* start of command packet */ + gdbserver_state.line_buf_index = 0; + gdbserver_state.line_sum = 0; + gdbserver_state.state = RS_GETLINE; + } else { + trace_gdbstub_err_garbage(ch); + } + break; + case RS_GETLINE: + if (ch == '}') { + /* start escape sequence */ + gdbserver_state.state = RS_GETLINE_ESC; + gdbserver_state.line_sum += ch; + } else if (ch == '*') { + /* start run length encoding sequence */ + gdbserver_state.state = RS_GETLINE_RLE; + gdbserver_state.line_sum += ch; + } else if (ch == '#') { + /* end of command, start of checksum*/ + gdbserver_state.state = RS_CHKSUM1; + } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) { + trace_gdbstub_err_overrun(); + gdbserver_state.state = RS_IDLE; + } else { + /* unescaped command character */ + gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch; + gdbserver_state.line_sum += ch; + } + break; + case RS_GETLINE_ESC: + if (ch == '#') { + /* unexpected end of command in escape sequence */ + gdbserver_state.state = RS_CHKSUM1; + } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) { + /* command buffer overrun */ + trace_gdbstub_err_overrun(); + gdbserver_state.state = RS_IDLE; + } else { + /* parse escaped character and leave escape state */ + gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20; + gdbserver_state.line_sum += ch; + gdbserver_state.state = RS_GETLINE; + } + break; + case RS_GETLINE_RLE: + /* + * Run-length encoding is explained in "Debugging with GDB / + * Appendix E GDB Remote Serial Protocol / Overview". + */ + if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) { + /* invalid RLE count encoding */ + trace_gdbstub_err_invalid_repeat(ch); + gdbserver_state.state = RS_GETLINE; + } else { + /* decode repeat length */ + int repeat = ch - ' ' + 3; + if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) { + /* that many repeats would overrun the command buffer */ + trace_gdbstub_err_overrun(); + gdbserver_state.state = RS_IDLE; + } else if (gdbserver_state.line_buf_index < 1) { + /* got a repeat but we have nothing to repeat */ + trace_gdbstub_err_invalid_rle(); + gdbserver_state.state = RS_GETLINE; + } else { + /* repeat the last character */ + memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index, + gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat); + gdbserver_state.line_buf_index += repeat; + gdbserver_state.line_sum += ch; + gdbserver_state.state = RS_GETLINE; + } + } + break; + case RS_CHKSUM1: + /* get high hex digit of checksum */ + if (!isxdigit(ch)) { + trace_gdbstub_err_checksum_invalid(ch); + gdbserver_state.state = RS_GETLINE; + break; + } + gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0'; + gdbserver_state.line_csum = fromhex(ch) << 4; + gdbserver_state.state = RS_CHKSUM2; + break; + case RS_CHKSUM2: + /* get low hex digit of checksum */ + if (!isxdigit(ch)) { + trace_gdbstub_err_checksum_invalid(ch); + gdbserver_state.state = RS_GETLINE; + break; + } + gdbserver_state.line_csum |= fromhex(ch); + + if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) { + trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum); + /* send NAK reply */ + reply = '-'; + put_buffer(&reply, 1); + gdbserver_state.state = RS_IDLE; + } else { + /* send ACK reply */ + reply = '+'; + put_buffer(&reply, 1); + gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf); + } + break; + default: + abort(); + } + } +} + +/* Tell the remote gdb that the process has exited. */ +void gdb_exit(int code) +{ + char buf[4]; + + if (!gdbserver_state.init) { + return; + } +#ifdef CONFIG_USER_ONLY + if (gdbserver_state.socket_path) { + unlink(gdbserver_state.socket_path); + } + if (gdbserver_state.fd < 0) { + return; + } +#endif + + trace_gdbstub_op_exiting((uint8_t)code); + + snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code); + put_packet(buf); + +#ifndef CONFIG_USER_ONLY + qemu_chr_fe_deinit(&gdbserver_state.chr, true); +#endif +} + +/* + * Create the process that will contain all the "orphan" CPUs (that are not + * part of a CPU cluster). Note that if this process contains no CPUs, it won't + * be attachable and thus will be invisible to the user. + */ +static void create_default_process(GDBState *s) +{ + GDBProcess *process; + int max_pid = 0; + + if (gdbserver_state.process_num) { + max_pid = s->processes[s->process_num - 1].pid; + } + + s->processes = g_renew(GDBProcess, s->processes, ++s->process_num); + process = &s->processes[s->process_num - 1]; + + /* We need an available PID slot for this process */ + assert(max_pid < UINT32_MAX); + + process->pid = max_pid + 1; + process->attached = false; + process->target_xml[0] = '\0'; +} + +#ifdef CONFIG_USER_ONLY +int +gdb_handlesig(CPUState *cpu, int sig) +{ + char buf[256]; + int n; + + if (!gdbserver_state.init || gdbserver_state.fd < 0) { + return sig; + } + + /* disable single step if it was enabled */ + cpu_single_step(cpu, 0); + tb_flush(cpu); + + if (sig != 0) { + gdb_set_stop_cpu(cpu); + g_string_printf(gdbserver_state.str_buf, + "T%02xthread:", target_signal_to_gdb(sig)); + gdb_append_thread_id(cpu, gdbserver_state.str_buf); + g_string_append_c(gdbserver_state.str_buf, ';'); + put_strbuf(); + } + /* put_packet() might have detected that the peer terminated the + connection. */ + if (gdbserver_state.fd < 0) { + return sig; + } + + sig = 0; + gdbserver_state.state = RS_IDLE; + gdbserver_state.running_state = 0; + while (gdbserver_state.running_state == 0) { + n = read(gdbserver_state.fd, buf, 256); + if (n > 0) { + int i; + + for (i = 0; i < n; i++) { + gdb_read_byte(buf[i]); + } + } else { + /* XXX: Connection closed. Should probably wait for another + connection before continuing. */ + if (n == 0) { + close(gdbserver_state.fd); + } + gdbserver_state.fd = -1; + return sig; + } + } + sig = gdbserver_state.signal; + gdbserver_state.signal = 0; + return sig; +} + +/* Tell the remote gdb that the process has exited due to SIG. */ +void gdb_signalled(CPUArchState *env, int sig) +{ + char buf[4]; + + if (!gdbserver_state.init || gdbserver_state.fd < 0) { + return; + } + + snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig)); + put_packet(buf); +} + +static void gdb_accept_init(int fd) +{ + init_gdbserver_state(); + create_default_process(&gdbserver_state); + gdbserver_state.processes[0].attached = true; + gdbserver_state.c_cpu = gdb_first_attached_cpu(); + gdbserver_state.g_cpu = gdbserver_state.c_cpu; + gdbserver_state.fd = fd; + gdb_has_xml = false; +} + +static bool gdb_accept_socket(int gdb_fd) +{ + int fd; + + for(;;) { + fd = accept(gdb_fd, NULL, NULL); + if (fd < 0 && errno != EINTR) { + perror("accept socket"); + return false; + } else if (fd >= 0) { + qemu_set_cloexec(fd); + break; + } + } + + gdb_accept_init(fd); + return true; +} + +static int gdbserver_open_socket(const char *path) +{ + struct sockaddr_un sockaddr = {}; + int fd, ret; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + perror("create socket"); + return -1; + } + + sockaddr.sun_family = AF_UNIX; + pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path); + ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); + if (ret < 0) { + perror("bind socket"); + close(fd); + return -1; + } + ret = listen(fd, 1); + if (ret < 0) { + perror("listen socket"); + close(fd); + return -1; + } + + return fd; +} + +static bool gdb_accept_tcp(int gdb_fd) +{ + struct sockaddr_in sockaddr = {}; + socklen_t len; + int fd; + + for(;;) { + len = sizeof(sockaddr); + fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len); + if (fd < 0 && errno != EINTR) { + perror("accept"); + return false; + } else if (fd >= 0) { + qemu_set_cloexec(fd); + break; + } + } + + /* set short latency */ + if (socket_set_nodelay(fd)) { + perror("setsockopt"); + close(fd); + return false; + } + + gdb_accept_init(fd); + return true; +} + +static int gdbserver_open_port(int port) +{ + struct sockaddr_in sockaddr; + int fd, ret; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + qemu_set_cloexec(fd); + + socket_set_fast_reuse(fd); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr.s_addr = 0; + ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); + if (ret < 0) { + perror("bind"); + close(fd); + return -1; + } + ret = listen(fd, 1); + if (ret < 0) { + perror("listen"); + close(fd); + return -1; + } + + return fd; +} + +int gdbserver_start(const char *port_or_path) +{ + int port = g_ascii_strtoull(port_or_path, NULL, 10); + int gdb_fd; + + if (port > 0) { + gdb_fd = gdbserver_open_port(port); + } else { + gdb_fd = gdbserver_open_socket(port_or_path); + } + + if (gdb_fd < 0) { + return -1; + } + + if (port > 0 && gdb_accept_tcp(gdb_fd)) { + return 0; + } else if (gdb_accept_socket(gdb_fd)) { + gdbserver_state.socket_path = g_strdup(port_or_path); + return 0; + } + + /* gone wrong */ + close(gdb_fd); + return -1; +} + +/* Disable gdb stub for child processes. */ +void gdbserver_fork(CPUState *cpu) +{ + if (!gdbserver_state.init || gdbserver_state.fd < 0) { + return; + } + close(gdbserver_state.fd); + gdbserver_state.fd = -1; + cpu_breakpoint_remove_all(cpu, BP_GDB); + cpu_watchpoint_remove_all(cpu, BP_GDB); +} +#else +static int gdb_chr_can_receive(void *opaque) +{ + /* We can handle an arbitrarily large amount of data. + Pick the maximum packet size, which is as good as anything. */ + return MAX_PACKET_LENGTH; +} + +static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size) +{ + int i; + + for (i = 0; i < size; i++) { + gdb_read_byte(buf[i]); + } +} + +static void gdb_chr_event(void *opaque, QEMUChrEvent event) +{ + int i; + GDBState *s = (GDBState *) opaque; + + switch (event) { + case CHR_EVENT_OPENED: + /* Start with first process attached, others detached */ + for (i = 0; i < s->process_num; i++) { + s->processes[i].attached = !i; + } + + s->c_cpu = gdb_first_attached_cpu(); + s->g_cpu = s->c_cpu; + + vm_stop(RUN_STATE_PAUSED); + replay_gdb_attached(); + gdb_has_xml = false; + break; + default: + break; + } +} + +static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len) +{ + g_autoptr(GString) hex_buf = g_string_new("O"); + memtohex(hex_buf, buf, len); + put_packet(hex_buf->str); + return len; +} + +#ifndef _WIN32 +static void gdb_sigterm_handler(int signal) +{ + if (runstate_is_running()) { + vm_stop(RUN_STATE_PAUSED); + } +} +#endif + +static void gdb_monitor_open(Chardev *chr, ChardevBackend *backend, + bool *be_opened, Error **errp) +{ + *be_opened = false; +} + +static void char_gdb_class_init(ObjectClass *oc, void *data) +{ + ChardevClass *cc = CHARDEV_CLASS(oc); + + cc->internal = true; + cc->open = gdb_monitor_open; + cc->chr_write = gdb_monitor_write; +} + +#define TYPE_CHARDEV_GDB "chardev-gdb" + +static const TypeInfo char_gdb_type_info = { + .name = TYPE_CHARDEV_GDB, + .parent = TYPE_CHARDEV, + .class_init = char_gdb_class_init, +}; + +static int find_cpu_clusters(Object *child, void *opaque) +{ + if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) { + GDBState *s = (GDBState *) opaque; + CPUClusterState *cluster = CPU_CLUSTER(child); + GDBProcess *process; + + s->processes = g_renew(GDBProcess, s->processes, ++s->process_num); + + process = &s->processes[s->process_num - 1]; + + /* + * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at + * runtime, we enforce here that the machine does not use a cluster ID + * that would lead to PID 0. + */ + assert(cluster->cluster_id != UINT32_MAX); + process->pid = cluster->cluster_id + 1; + process->attached = false; + process->target_xml[0] = '\0'; + + return 0; + } + + return object_child_foreach(child, find_cpu_clusters, opaque); +} + +static int pid_order(const void *a, const void *b) +{ + GDBProcess *pa = (GDBProcess *) a; + GDBProcess *pb = (GDBProcess *) b; + + if (pa->pid < pb->pid) { + return -1; + } else if (pa->pid > pb->pid) { + return 1; + } else { + return 0; + } +} + +static void create_processes(GDBState *s) +{ + object_child_foreach(object_get_root(), find_cpu_clusters, s); + + if (gdbserver_state.processes) { + /* Sort by PID */ + qsort(gdbserver_state.processes, gdbserver_state.process_num, sizeof(gdbserver_state.processes[0]), pid_order); + } + + create_default_process(s); +} + +int gdbserver_start(const char *device) +{ + trace_gdbstub_op_start(device); + + char gdbstub_device_name[128]; + Chardev *chr = NULL; + Chardev *mon_chr; + + if (!first_cpu) { + error_report("gdbstub: meaningless to attach gdb to a " + "machine without any CPU."); + return -1; + } + + if (!gdb_supports_guest_debug()) { + error_report("gdbstub: current accelerator doesn't support guest debugging"); + return -1; + } + + if (!device) + return -1; + if (strcmp(device, "none") != 0) { + if (strstart(device, "tcp:", NULL)) { + /* enforce required TCP attributes */ + snprintf(gdbstub_device_name, sizeof(gdbstub_device_name), + "%s,wait=off,nodelay=on,server=on", device); + device = gdbstub_device_name; + } +#ifndef _WIN32 + else if (strcmp(device, "stdio") == 0) { + struct sigaction act; + + memset(&act, 0, sizeof(act)); + act.sa_handler = gdb_sigterm_handler; + sigaction(SIGINT, &act, NULL); + } +#endif + /* + * FIXME: it's a bit weird to allow using a mux chardev here + * and implicitly setup a monitor. We may want to break this. + */ + chr = qemu_chr_new_noreplay("gdb", device, true, NULL); + if (!chr) + return -1; + } + + if (!gdbserver_state.init) { + init_gdbserver_state(); + + qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); + + /* Initialize a monitor terminal for gdb */ + mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB, + NULL, NULL, &error_abort); + monitor_init_hmp(mon_chr, false, &error_abort); + } else { + qemu_chr_fe_deinit(&gdbserver_state.chr, true); + mon_chr = gdbserver_state.mon_chr; + reset_gdbserver_state(); + } + + create_processes(&gdbserver_state); + + if (chr) { + qemu_chr_fe_init(&gdbserver_state.chr, chr, &error_abort); + qemu_chr_fe_set_handlers(&gdbserver_state.chr, gdb_chr_can_receive, + gdb_chr_receive, gdb_chr_event, + NULL, &gdbserver_state, NULL, true); + } + gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE; + gdbserver_state.mon_chr = mon_chr; + gdbserver_state.current_syscall_cb = NULL; + + return 0; +} + +static void register_types(void) +{ + type_register_static(&char_gdb_type_info); +} + +type_init(register_types); +#endif diff --git a/gdbstub/internals.h b/gdbstub/internals.h new file mode 100644 index 000000000000..eabb0341d16f --- /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 000000000000..fc895a2c3933 --- /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 000000000000..f208c6cf159f --- /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 000000000000..03f0c303bfe3 --- /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 000000000000..dee87b1238fc --- /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 000000000000..033e5fdd71f7 --- /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 adfa085a9b13..754b1e840822 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, }, @@ -865,6 +867,19 @@ SRST Display the vcpu dirty rate information. ERST + { + .name = "vcpu_dirty_limit", + .args_type = "", + .params = "", + .help = "show dirty page limit information of all vCPU", + .cmd = hmp_info_vcpu_dirty_limit, + }, + +SRST + ``info vcpu_dirty_limit`` + Display the vcpu dirty page limit information. +ERST + #if defined(TARGET_I386) { .name = "sgx", @@ -880,7 +895,7 @@ SRST Show intel SGX information. ERST -#if defined(TARGET_M68K) || defined(TARGET_PPC) +#if defined(CONFIG_MOS6522) { .name = "via", .args_type = "", @@ -894,3 +909,87 @@ SRST ``info via`` Show guest mos6522 VIA devices. ERST + + { + .name = "stats", + .args_type = "target:s,names:s?,provider:s?", + .params = "target [names] [provider]", + .help = "show statistics for the given target (vm or vcpu); optionally filter by" + "name (comma-separated list, or * for all) and provider", + .cmd = hmp_info_stats, + }, + +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 8476277aa9c9..673e39a69797 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -78,6 +78,7 @@ ERST .help = "resize a block image", .cmd = hmp_block_resize, .coroutine = true, + .flags = "p", }, SRST @@ -94,6 +95,7 @@ ERST .params = "device [speed [base]]", .help = "copy data from a backing file into a block device", .cmd = hmp_block_stream, + .flags = "p", }, SRST @@ -107,6 +109,7 @@ ERST .params = "device speed", .help = "set maximum speed for a background block operation", .cmd = hmp_block_job_set_speed, + .flags = "p", }, SRST @@ -122,6 +125,7 @@ ERST "\n\t\t\t if you want to abort the operation immediately" "\n\t\t\t instead of keep running until data is in sync)", .cmd = hmp_block_job_cancel, + .flags = "p", }, SRST @@ -135,6 +139,7 @@ ERST .params = "device", .help = "stop an active background block operation", .cmd = hmp_block_job_complete, + .flags = "p", }, SRST @@ -149,6 +154,7 @@ ERST .params = "device", .help = "pause an active background block operation", .cmd = hmp_block_job_pause, + .flags = "p", }, SRST @@ -162,6 +168,7 @@ ERST .params = "device", .help = "resume a paused background block operation", .cmd = hmp_block_job_resume, + .flags = "p", }, SRST @@ -202,9 +209,9 @@ ERST { .name = "change", - .args_type = "device:B,target:F,arg:s?,read-only-mode:s?", - .params = "device filename [format [read-only-mode]]", - .help = "change a removable medium, optional format", + .args_type = "device:B,force:-f,target:F,arg:s?,read-only-mode:s?", + .params = "device [-f] filename [format [read-only-mode]]", + .help = "change a removable medium, optional format, use -f to force the operation", .cmd = hmp_change, }, @@ -212,11 +219,14 @@ SRST ``change`` *device* *setting* Change the configuration of a device. - ``change`` *diskdevice* *filename* [*format* [*read-only-mode*]] + ``change`` *diskdevice* [-f] *filename* [*format* [*read-only-mode*]] Change the medium for a removable disk device to point to *filename*. eg:: (qemu) change ide1-cd0 /path/to/some.iso + ``-f`` + forces the operation even if the guest has locked the tray. + *format* is optional. *read-only-mode* may be used to change the read-only status of the device. @@ -244,11 +254,12 @@ ERST { .name = "screendump", - .args_type = "filename:F,device:s?,head:i?", - .params = "filename [device [head]]", - .help = "save screen from head 'head' of display device 'device' " - "into PPM image 'filename'", - .cmd = hmp_screendump, + .args_type = "filename:F,format:-fs,device:s?,head:i?", + .params = "filename [-f format] [device [head]]", + .help = "save screen from head 'head' of display device 'device'" + "in specified format 'format' as image 'filename'." + "Currently only 'png' and 'ppm' formats are supported.", + .cmd = hmp_screendump, .coroutine = true, }, @@ -1064,7 +1075,7 @@ ERST "-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t" "-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t" "-w: dump in Windows crashdump format (can be used instead of ELF-dump converting),\n\t\t\t" - " for Windows x64 guests with vmcoreinfo driver only.\n\t\t\t" + " for Windows x86 and x64 guests with vmcoreinfo driver only.\n\t\t\t" "begin: the starting physical address.\n\t\t\t" "length: the memory size, in bytes.", .cmd = hmp_dump_guest_memory, @@ -1265,7 +1276,11 @@ ERST { .name = "netdev_add", .args_type = "netdev:O", - .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]", + .params = "[user|tap|socket|stream|dgram|vde|bridge|hubport|netmap|vhost-user" +#ifdef CONFIG_VMNET + "|vmnet-host|vmnet-shared|vmnet-bridged" +#endif + "],id=str[,prop=value][,...]", .help = "add host network device", .cmd = hmp_netdev_add, .command_completion = netdev_add_completion, @@ -1398,6 +1413,7 @@ ERST .params = "nbd_server_start [-a] [-w] host:port", .help = "serve block devices on the given host and port", .cmd = hmp_nbd_server_start, + .flags = "p", }, SRST ``nbd_server_start`` *host*:*port* @@ -1413,6 +1429,7 @@ ERST .params = "nbd_server_add [-w] device [name]", .help = "export a block device via NBD", .cmd = hmp_nbd_server_add, + .flags = "p", }, SRST ``nbd_server_add`` *device* [ *name* ] @@ -1428,6 +1445,7 @@ ERST .params = "nbd_server_remove [-f] name", .help = "remove an export previously exposed via NBD", .cmd = hmp_nbd_server_remove, + .flags = "p", }, SRST ``nbd_server_remove [-f]`` *name* @@ -1444,6 +1462,7 @@ ERST .params = "nbd_server_stop", .help = "stop serving block devices using the NBD protocol", .cmd = hmp_nbd_server_stop, + .flags = "p", }, SRST ``nbd_server_stop`` @@ -1473,6 +1492,7 @@ ERST .params = "getfd name", .help = "receive a file descriptor via SCM rights and assign it a name", .cmd = hmp_getfd, + .flags = "p", }, SRST @@ -1488,6 +1508,7 @@ ERST .params = "closefd name", .help = "close a file descriptor previously passed via SCM rights", .cmd = hmp_closefd, + .flags = "p", }, SRST @@ -1503,6 +1524,7 @@ ERST .params = "device bps bps_rd bps_wr iops iops_rd iops_wr", .help = "change I/O throttle limits for a block drive", .cmd = hmp_block_set_io_throttle, + .flags = "p", }, SRST @@ -1721,13 +1743,13 @@ SRST 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", + .name = "calc_dirty_rate", + .args_type = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?", + .params = "[-r] [-b] second [sample_pages_per_GB]", + .help = "start a round of guest dirty rate measurement (using -r to" + "\n\t\t\t specify dirty ring as the method of calculation and" + "\n\t\t\t -b to specify dirty bitmap as method of calculation)", + .cmd = hmp_calc_dirty_rate, }, SRST @@ -1738,11 +1760,58 @@ SRST ERST { - .name = "calc_dirty_rate", - .args_type = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?", - .params = "[-r] [-b] second [sample_pages_per_GB]", - .help = "start a round of guest dirty rate measurement (using -r to" - "\n\t\t\t specify dirty ring as the method of calculation and" - "\n\t\t\t -b to specify dirty bitmap as method of calculation)", - .cmd = hmp_calc_dirty_rate, + .name = "set_vcpu_dirty_limit", + .args_type = "dirty_rate:l,cpu_index:l?", + .params = "dirty_rate [cpu_index]", + .help = "set dirty page rate limit, use cpu_index to set limit" + "\n\t\t\t\t\t on a specified virtual cpu", + .cmd = hmp_set_vcpu_dirty_limit, + }, + +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. +ERST + + { + .name = "cancel_vcpu_dirty_limit", + .args_type = "cpu_index:l?", + .params = "[cpu_index]", + .help = "cancel dirty page rate limit, use cpu_index to cancel" + "\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", + }, + +#if defined(CONFIG_FDT) + { + .name = "dumpdtb", + .args_type = "filename:F", + .params = "filename", + .help = "dump the FDT in dtb format to 'filename'", + .cmd = hmp_dumpdtb, }, + +SRST +``dumpdtb`` *filename* + Dump the FDT in dtb format to *filename*. +ERST +#endif diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index d42ce6d8b822..9d07620235c2 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -103,14 +103,14 @@ static void renameat_preserve_errno(int odirfd, const char *opath, int ndirfd, const char *npath) { int serrno = errno; - renameat(odirfd, opath, ndirfd, npath); + qemu_renameat(odirfd, opath, ndirfd, npath); errno = serrno; } static void unlinkat_preserve_errno(int dirfd, const char *path, int flags) { int serrno = errno; - unlinkat(dirfd, path, flags); + qemu_unlinkat(dirfd, path, flags); errno = serrno; } @@ -194,7 +194,7 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) goto out; } - err = fstatat(dirfd, name, stbuf, AT_SYMLINK_NOFOLLOW); + err = qemu_fstatat(dirfd, name, stbuf, AT_SYMLINK_NOFOLLOW); if (err) { goto err_out; } @@ -253,7 +253,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name, } } } else { - ret = mkdirat(dirfd, VIRTFS_META_DIR, 0700); + ret = qemu_mkdirat(dirfd, VIRTFS_META_DIR, 0700); if (ret < 0 && errno != EEXIST) { return -1; } @@ -349,7 +349,7 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode) */ /* First, we clear non-racing symlinks out of the way. */ - if (fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW)) { + if (qemu_fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW)) { return -1; } if (S_ISLNK(stbuf.st_mode)) { @@ -470,9 +470,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, if (fd == -1) { return -1; } - do { - tsize = read(fd, (void *)buf, bufsz); - } while (tsize == -1 && errno == EINTR); + tsize = RETRY_ON_EINTR(read(fd, (void *)buf, bufsz)); close_preserve_errno(fd); } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { @@ -734,7 +732,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, if (fs_ctx->export_flags & V9FS_SM_MAPPED || fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - err = mkdirat(dirfd, name, fs_ctx->dmode); + err = qemu_mkdirat(dirfd, name, fs_ctx->dmode); if (err == -1) { goto out; } @@ -750,7 +748,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, } } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH || fs_ctx->export_flags & V9FS_SM_NONE) { - err = mkdirat(dirfd, name, credp->fc_mode); + err = qemu_mkdirat(dirfd, name, credp->fc_mode); if (err == -1) { goto out; } @@ -908,9 +906,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, } /* Write the oldpath (target) to the file. */ oldpath_size = strlen(oldpath); - do { - write_size = write(fd, (void *)oldpath, oldpath_size); - } while (write_size == -1 && errno == EINTR); + write_size = RETRY_ON_EINTR(write(fd, (void *)oldpath, oldpath_size)); close_preserve_errno(fd); if (write_size != oldpath_size) { @@ -990,7 +986,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { int omap_dirfd, nmap_dirfd; - ret = mkdirat(ndirfd, VIRTFS_META_DIR, 0700); + ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700); if (ret < 0 && errno != EEXIST) { goto err_undo_link; } @@ -1085,7 +1081,7 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path, goto out; } - ret = utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW); + ret = qemu_utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW); close_preserve_errno(dirfd); out: g_free(dirpath); @@ -1116,7 +1112,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, if (fd == -1) { return -1; } - ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR); + ret = qemu_unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR); close_preserve_errno(fd); if (ret < 0 && errno != ENOENT) { return -1; @@ -1124,7 +1120,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, } map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR); if (map_dirfd != -1) { - ret = unlinkat(map_dirfd, name, 0); + ret = qemu_unlinkat(map_dirfd, name, 0); close_preserve_errno(map_dirfd); if (ret < 0 && errno != ENOENT) { return -1; @@ -1134,7 +1130,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, } } - return unlinkat(dirfd, name, flags); + return qemu_unlinkat(dirfd, name, flags); } static int local_remove(FsContext *ctx, const char *path) @@ -1151,7 +1147,7 @@ static int local_remove(FsContext *ctx, const char *path) goto out; } - if (fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) { + if (qemu_fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) { goto err_out; } @@ -1296,7 +1292,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir, return -1; } - ret = renameat(odirfd, old_name, ndirfd, new_name); + ret = qemu_renameat(odirfd, old_name, ndirfd, new_name); if (ret < 0) { goto out; } @@ -1304,7 +1300,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir, if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { int omap_dirfd, nmap_dirfd; - ret = mkdirat(ndirfd, VIRTFS_META_DIR, 0700); + ret = qemu_mkdirat(ndirfd, VIRTFS_META_DIR, 0700); if (ret < 0 && errno != EEXIST) { goto err_undo_rename; } @@ -1321,7 +1317,7 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir, } /* rename the .virtfs_metadata files */ - ret = renameat(omap_dirfd, old_name, nmap_dirfd, new_name); + ret = qemu_renameat(omap_dirfd, old_name, nmap_dirfd, new_name); close_preserve_errno(nmap_dirfd); close_preserve_errno(omap_dirfd); if (ret < 0 && errno != ENOENT) { diff --git a/hw/9pfs/9p-posix-acl.c b/hw/9pfs/9p-posix-acl.c index eadae270dde2..4b2cb3c66cfe 100644 --- a/hw/9pfs/9p-posix-acl.c +++ b/hw/9pfs/9p-posix-acl.c @@ -65,7 +65,11 @@ static int mp_pacl_removexattr(FsContext *ctx, int ret; ret = local_removexattr_nofollow(ctx, path, MAP_ACL_ACCESS); - if (ret == -1 && errno == ENODATA) { + /* + * macOS returns ENOATTR (!=ENODATA on macOS), whereas Linux returns + * ENODATA (==ENOATTR on Linux), so checking for ENOATTR is fine + */ + if (ret == -1 && errno == ENOATTR) { /* * We don't get ENODATA error when trying to remove a * posix acl that is not present. So don't throw the error @@ -115,7 +119,11 @@ static int mp_dacl_removexattr(FsContext *ctx, int ret; ret = local_removexattr_nofollow(ctx, path, MAP_ACL_DEFAULT); - if (ret == -1 && errno == ENODATA) { + /* + * macOS returns ENOATTR (!=ENODATA on macOS), whereas Linux returns + * ENODATA (==ENOATTR on Linux), so checking for ENOATTR is fine + */ + if (ret == -1 && errno == ENOATTR) { /* * We don't get ENODATA error when trying to remove a * posix acl that is not present. So don't throw the error diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 4c5e0fc217eb..99d115ff0db4 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include #include -#include "qemu-common.h" #include "9p.h" #include "qapi/error.h" #include "qemu/cutils.h" diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index d99d26398552..f62c40b639fc 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -72,14 +72,13 @@ static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode, int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, const char *name, V9fsSynthNode **result) { - int ret; V9fsSynthNode *node, *tmp; if (!synth_fs) { - return EAGAIN; + return -EAGAIN; } if (!name || (strlen(name) >= NAME_MAX)) { - return EINVAL; + return -EINVAL; } if (!parent) { parent = &synth_root; @@ -87,33 +86,30 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, QEMU_LOCK_GUARD(&synth_mutex); QLIST_FOREACH(tmp, &parent->child, sibling) { if (!strcmp(tmp->name, name)) { - ret = EEXIST; - return ret; + return -EEXIST; } } /* Add the name */ - node = v9fs_add_dir_node(parent, mode, name, NULL, synth_node_count++); + node = v9fs_add_dir_node(parent, mode, name, NULL, ++synth_node_count); v9fs_add_dir_node(node, parent->attr->mode, "..", parent->attr, parent->attr->inode); v9fs_add_dir_node(node, node->attr->mode, ".", node->attr, node->attr->inode); *result = node; - ret = 0; - return ret; + return 0; } int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, const char *name, v9fs_synth_read read, v9fs_synth_write write, void *arg) { - int ret; V9fsSynthNode *node, *tmp; if (!synth_fs) { - return EAGAIN; + return -EAGAIN; } if (!name || (strlen(name) >= NAME_MAX)) { - return EINVAL; + return -EINVAL; } if (!parent) { parent = &synth_root; @@ -122,15 +118,14 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, QEMU_LOCK_GUARD(&synth_mutex); QLIST_FOREACH(tmp, &parent->child, sibling) { if (!strcmp(tmp->name, name)) { - ret = EEXIST; - return ret; + return -EEXIST; } } /* Add file type and remove write bits */ mode = ((mode & 0777) | S_IFREG); node = g_new0(V9fsSynthNode, 1); node->attr = &node->actual_attr; - node->attr->inode = synth_node_count++; + node->attr->inode = ++synth_node_count; node->attr->nlink = 1; node->attr->read = read; node->attr->write = write; @@ -138,8 +133,7 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, node->private = arg; pstrcpy(node->name, sizeof(node->name), name); QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); - ret = 0; - return ret; + return 0; } static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf) diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c index bec0253474db..95146e73546a 100644 --- a/hw/9pfs/9p-util-darwin.c +++ b/hw/9pfs/9p-util-darwin.c @@ -74,17 +74,67 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, */ #if defined CONFIG_PTHREAD_FCHDIR_NP +static int create_socket_file_at_cwd(const char *filename, mode_t mode) { + int fd, err; + struct sockaddr_un addr = { + .sun_family = AF_UNIX + }; + + err = snprintf(addr.sun_path, sizeof(addr.sun_path), "./%s", filename); + if (err < 0 || err >= sizeof(addr.sun_path)) { + errno = ENAMETOOLONG; + return -1; + } + fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (fd == -1) { + return fd; + } + err = bind(fd, (struct sockaddr *) &addr, sizeof(addr)); + if (err == -1) { + goto out; + } + /* + * FIXME: Should rather be using descriptor-based fchmod() on the + * socket file descriptor above (preferably before bind() call), + * instead of path-based fchmodat(), to prevent concurrent transient + * state issues between creating the named FIFO file at bind() and + * delayed adjustment of permissions at fchmodat(). However currently + * macOS (12.x) does not support such operations on socket file + * descriptors yet. + * + * Filed report with Apple: FB9997731 + */ + err = fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW); +out: + close_preserve_errno(fd); + return err; +} + int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) { int preserved_errno, err; + + if (S_ISREG(mode) || !(mode & S_IFMT)) { + int fd = openat_file(dirfd, filename, O_CREAT, mode); + if (fd == -1) { + return fd; + } + close(fd); + return 0; + } if (!pthread_fchdir_np) { error_report_once("pthread_fchdir_np() not available on this version of macOS"); - return -ENOTSUP; + errno = ENOTSUP; + return -1; } if (pthread_fchdir_np(dirfd) < 0) { return -1; } - err = mknod(filename, mode, dev); + if (S_ISSOCK(mode)) { + err = create_socket_file_at_cwd(filename, mode); + } else { + err = mknod(filename, mode, dev); + } preserved_errno = errno; /* Stop using the thread-local cwd */ pthread_fchdir_np(-1); diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index 97e681e1672f..c314cf381d41 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -19,23 +19,88 @@ #define O_PATH_9P_UTIL 0 #endif +#if !defined(CONFIG_LINUX) + +/* + * Generates a Linux device number (a.k.a. dev_t) for given device major + * and minor numbers. + * + * To be more precise: it generates a device number in glibc's format + * (MMMM_Mmmm_mmmM_MMmm, 64 bits) actually, which is compatible with + * Linux's format (mmmM_MMmm, 32 bits), as described in . + */ +static inline uint64_t makedev_dotl(uint32_t dev_major, uint32_t dev_minor) +{ + uint64_t dev; + + // from glibc sysmacros.h: + dev = (((uint64_t) (dev_major & 0x00000fffu)) << 8); + dev |= (((uint64_t) (dev_major & 0xfffff000u)) << 32); + dev |= (((uint64_t) (dev_minor & 0x000000ffu)) << 0); + dev |= (((uint64_t) (dev_minor & 0xffffff00u)) << 12); + return dev; +} + +#endif + +/* + * Converts given device number from host's device number format to Linux + * device number format. As both the size of type dev_t and encoding of + * dev_t is system dependant, we have to convert them for Linux guests if + * host is not running Linux. + */ +static inline uint64_t host_dev_to_dotl_dev(dev_t dev) +{ +#ifdef CONFIG_LINUX + return dev; +#else + return makedev_dotl(major(dev), minor(dev)); +#endif +} + +/* Translates errno from host -> Linux if needed */ +static inline int errno_to_dotl(int err) { +#if defined(CONFIG_LINUX) + /* nothing to translate (Linux -> Linux) */ +#elif defined(CONFIG_DARWIN) + /* + * translation mandatory for macOS hosts + * + * FIXME: Only most important errnos translated here yet, this should be + * extended to as many errnos being translated as possible in future. + */ + if (err == ENAMETOOLONG) { + err = 36; /* ==ENAMETOOLONG on Linux */ + } else if (err == ENOTEMPTY) { + err = 39; /* ==ENOTEMPTY on Linux */ + } else if (err == ELOOP) { + err = 40; /* ==ELOOP on Linux */ + } else if (err == ENOATTR) { + err = 61; /* ==ENODATA on Linux */ + } else if (err == ENOTSUP) { + err = 95; /* ==EOPNOTSUPP on Linux */ + } else if (err == EOPNOTSUPP) { + err = 95; /* ==EOPNOTSUPP on Linux */ + } +#else +#error Missing errno translation to Linux for this host system +#endif + return err; +} + #ifdef CONFIG_DARWIN #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0) -#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW) -#define qemu_llistxattr(...) listxattr(__VA_ARGS__, XATTR_NOFOLLOW) -#define qemu_lremovexattr(...) removexattr(__VA_ARGS__, XATTR_NOFOLLOW) -static inline int qemu_lsetxattr(const char *path, const char *name, - const void *value, size_t size, int flags) { - return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW); -} #else #define qemu_fgetxattr fgetxattr -#define qemu_lgetxattr lgetxattr -#define qemu_llistxattr llistxattr -#define qemu_lremovexattr lremovexattr -#define qemu_lsetxattr lsetxattr #endif +#define qemu_openat openat +#define qemu_fstatat fstatat +#define qemu_mkdirat mkdirat +#define qemu_renameat renameat +#define qemu_utimensat utimensat +#define qemu_unlinkat unlinkat + static inline void close_preserve_errno(int fd) { int serrno = errno; @@ -45,8 +110,8 @@ static inline void close_preserve_errno(int fd) static inline int openat_dir(int dirfd, const char *name) { - return openat(dirfd, name, - O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL); + return qemu_openat(dirfd, name, + O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL); } static inline int openat_file(int dirfd, const char *name, int flags, @@ -57,8 +122,8 @@ static inline int openat_file(int dirfd, const char *name, int flags, #ifndef CONFIG_DARWIN again: #endif - fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, - mode); + fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, + mode); if (fd == -1) { #ifndef CONFIG_DARWIN if (errno == EPERM && (flags & O_NOATIME)) { diff --git a/hw/9pfs/9p-xattr-user.c b/hw/9pfs/9p-xattr-user.c index f2ae9582e610..535677ed609b 100644 --- a/hw/9pfs/9p-xattr-user.c +++ b/hw/9pfs/9p-xattr-user.c @@ -27,7 +27,7 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path, { if (strncmp(name, "user.virtfs.", 12) == 0) { /* - * Don't allow fetch of user.virtfs namesapce + * Don't allow fetch of user.virtfs namespace * in case of mapped security */ errno = ENOATTR; @@ -49,7 +49,7 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path, name_size -= 12; } else { /* - * Don't allow fetch of user.virtfs namesapce + * Don't allow fetch of user.virtfs namespace * in case of mapped security */ return 0; @@ -74,7 +74,7 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name, { if (strncmp(name, "user.virtfs.", 12) == 0) { /* - * Don't allow fetch of user.virtfs namesapce + * Don't allow fetch of user.virtfs namespace * in case of mapped security */ errno = EACCES; @@ -88,7 +88,7 @@ static int mp_user_removexattr(FsContext *ctx, { if (strncmp(name, "user.virtfs.", 12) == 0) { /* - * Don't allow fetch of user.virtfs namesapce + * Don't allow fetch of user.virtfs namespace * in case of mapped security */ errno = EACCES; diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 225f31fc31ed..072cf67956a0 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -256,7 +256,8 @@ static size_t v9fs_string_size(V9fsString *str) } /* - * returns 0 if fid got re-opened, 1 if not, < 0 on error */ + * returns 0 if fid got re-opened, 1 if not, < 0 on error + */ static int coroutine_fn v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f) { int err = 1; @@ -282,33 +283,32 @@ static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid) V9fsFidState *f; V9fsState *s = pdu->s; - QSIMPLEQ_FOREACH(f, &s->fid_list, next) { + f = g_hash_table_lookup(s->fids, GINT_TO_POINTER(fid)); + if (f) { BUG_ON(f->clunked); - if (f->fid == fid) { - /* - * Update the fid ref upfront so that - * we don't get reclaimed when we yield - * in open later. - */ - f->ref++; - /* - * check whether we need to reopen the - * file. We might have closed the fd - * while trying to free up some file - * descriptors. - */ - err = v9fs_reopen_fid(pdu, f); - if (err < 0) { - f->ref--; - return NULL; - } - /* - * Mark the fid as referenced so that the LRU - * reclaim won't close the file descriptor - */ - f->flags |= FID_REFERENCED; - return f; + /* + * Update the fid ref upfront so that + * we don't get reclaimed when we yield + * in open later. + */ + f->ref++; + /* + * check whether we need to reopen the + * file. We might have closed the fd + * while trying to free up some file + * descriptors. + */ + err = v9fs_reopen_fid(pdu, f); + if (err < 0) { + f->ref--; + return NULL; } + /* + * Mark the fid as referenced so that the LRU + * reclaim won't close the file descriptor + */ + f->flags |= FID_REFERENCED; + return f; } return NULL; } @@ -317,12 +317,11 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) { V9fsFidState *f; - QSIMPLEQ_FOREACH(f, &s->fid_list, next) { + f = g_hash_table_lookup(s->fids, GINT_TO_POINTER(fid)); + if (f) { /* If fid is already there return NULL */ BUG_ON(f->clunked); - if (f->fid == fid) { - return NULL; - } + return NULL; } f = g_new0(V9fsFidState, 1); f->fid = fid; @@ -333,7 +332,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) * reclaim won't close the file descriptor */ f->flags |= FID_REFERENCED; - QSIMPLEQ_INSERT_TAIL(&s->fid_list, f, next); + g_hash_table_insert(s->fids, GINT_TO_POINTER(fid), f); v9fs_readdir_init(s->proto_version, &f->fs.dir); v9fs_readdir_init(s->proto_version, &f->fs_reclaim.dir); @@ -424,12 +423,12 @@ static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid) { V9fsFidState *fidp; - QSIMPLEQ_FOREACH(fidp, &s->fid_list, next) { - if (fidp->fid == fid) { - QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next); - fidp->clunked = true; - return fidp; - } + /* TODO: Use g_hash_table_steal_extended() instead? */ + fidp = g_hash_table_lookup(s->fids, GINT_TO_POINTER(fid)); + if (fidp) { + g_hash_table_remove(s->fids, GINT_TO_POINTER(fid)); + fidp->clunked = true; + return fidp; } return NULL; } @@ -439,10 +438,15 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) int reclaim_count = 0; V9fsState *s = pdu->s; V9fsFidState *f; + GHashTableIter iter; + gpointer fid; + + g_hash_table_iter_init(&iter, s->fids); + QSLIST_HEAD(, V9fsFidState) reclaim_list = QSLIST_HEAD_INITIALIZER(reclaim_list); - QSIMPLEQ_FOREACH(f, &s->fid_list, next) { + while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) { /* * Unlink fids cannot be reclaimed. Check * for them and skip them. Also skip fids @@ -514,72 +518,85 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) } } +/* + * This is used when a path is removed from the directory tree. Any + * fids that still reference it must not be closed from then on, since + * they cannot be reopened. + */ static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) { - int err; + int err = 0; V9fsState *s = pdu->s; - V9fsFidState *fidp, *fidp_next; + V9fsFidState *fidp; + gpointer fid; + GHashTableIter iter; + /* + * The most common case is probably that we have exactly one + * fid for the given path, so preallocate exactly one. + */ + g_autoptr(GArray) to_reopen = g_array_sized_new(FALSE, FALSE, + sizeof(V9fsFidState *), 1); + gint i; - fidp = QSIMPLEQ_FIRST(&s->fid_list); - if (!fidp) { - return 0; - } + g_hash_table_iter_init(&iter, s->fids); /* - * v9fs_reopen_fid() can yield : a reference on the fid must be held - * to ensure its pointer remains valid and we can safely pass it to - * QSIMPLEQ_NEXT(). The corresponding put_fid() can also yield so - * we must keep a reference on the next fid as well. So the logic here - * is to get a reference on a fid and only put it back during the next - * iteration after we could get a reference on the next fid. Start with - * the first one. + * We iterate over the fid table looking for the entries we need + * to reopen, and store them in to_reopen. This is because + * v9fs_reopen_fid() and put_fid() yield. This allows the fid table + * to be modified in the meantime, invalidating our iterator. */ - for (fidp->ref++; fidp; fidp = fidp_next) { + while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &fidp)) { if (fidp->path.size == path->size && !memcmp(fidp->path.data, path->data, path->size)) { - /* Mark the fid non reclaimable. */ - fidp->flags |= FID_NON_RECLAIMABLE; - - /* reopen the file/dir if already closed */ - err = v9fs_reopen_fid(pdu, fidp); - if (err < 0) { - put_fid(pdu, fidp); - return err; - } - } - - fidp_next = QSIMPLEQ_NEXT(fidp, next); - - if (fidp_next) { /* - * Ensure the next fid survives a potential clunk request during - * put_fid() below and v9fs_reopen_fid() in the next iteration. + * Ensure the fid survives a potential clunk request during + * v9fs_reopen_fid or put_fid. */ - fidp_next->ref++; + fidp->ref++; + fidp->flags |= FID_NON_RECLAIMABLE; + g_array_append_val(to_reopen, fidp); } + } - /* We're done with this fid */ - put_fid(pdu, fidp); + for (i = 0; i < to_reopen->len; i++) { + fidp = g_array_index(to_reopen, V9fsFidState*, i); + /* reopen the file/dir if already closed */ + err = v9fs_reopen_fid(pdu, fidp); + if (err < 0) { + break; + } } - return 0; + for (i = 0; i < to_reopen->len; i++) { + put_fid(pdu, g_array_index(to_reopen, V9fsFidState*, i)); + } + return err; } static void coroutine_fn virtfs_reset(V9fsPDU *pdu) { V9fsState *s = pdu->s; V9fsFidState *fidp; + GList *freeing; + /* + * Get a list of all the values (fid states) in the table, which + * we then... + */ + g_autoptr(GList) fids = g_hash_table_get_values(s->fids); - /* Free all fids */ - while (!QSIMPLEQ_EMPTY(&s->fid_list)) { - /* Get fid */ - fidp = QSIMPLEQ_FIRST(&s->fid_list); - fidp->ref++; + /* ... remove from the table, taking over ownership. */ + g_hash_table_steal_all(s->fids); - /* Clunk fid */ - QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next); + /* + * This allows us to release our references to them asynchronously without + * iterating over the hash table and risking iterator invalidation + * through concurrent modifications. + */ + for (freeing = fids; freeing; freeing = freeing->next) { + fidp = freeing->data; + fidp->ref++; fidp->clunked = true; - put_fid(pdu, fidp); } } @@ -1054,6 +1071,8 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len) } len += ret; id = P9_RERROR; + } else { + err = errno_to_dotl(err); } ret = pdu_marshal(pdu, len, "d", err); @@ -1327,7 +1346,7 @@ static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf, v9lstat->st_nlink = stbuf->st_nlink; v9lstat->st_uid = stbuf->st_uid; v9lstat->st_gid = stbuf->st_gid; - v9lstat->st_rdev = stbuf->st_rdev; + v9lstat->st_rdev = host_dev_to_dotl_dev(stbuf->st_rdev); v9lstat->st_size = stbuf->st_size; v9lstat->st_blksize = stat_to_iounit(pdu, stbuf); v9lstat->st_blocks = stbuf->st_blocks; @@ -1764,9 +1783,9 @@ static bool same_stat_id(const struct stat *a, const struct stat *b) static void coroutine_fn v9fs_walk(void *opaque) { - int name_idx; + int name_idx, nwalked; g_autofree V9fsQID *qids = NULL; - int i, err = 0; + int i, err = 0, any_err = 0; V9fsPath dpath, path; P9ARRAY_REF(V9fsPath) pathes = NULL; uint16_t nwnames; @@ -1784,7 +1803,7 @@ static void coroutine_fn v9fs_walk(void *opaque) err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); if (err < 0) { pdu_complete(pdu, err); - return ; + return; } offset += err; @@ -1832,54 +1851,61 @@ static void coroutine_fn v9fs_walk(void *opaque) * driver code altogether inside the following block. */ v9fs_co_run_in_worker({ + nwalked = 0; if (v9fs_request_cancelled(pdu)) { - err = -EINTR; + any_err |= err = -EINTR; break; } err = s->ops->lstat(&s->ctx, &dpath, &fidst); if (err < 0) { - err = -errno; + any_err |= err = -errno; break; } stbuf = fidst; - for (name_idx = 0; name_idx < nwnames; name_idx++) { + for (; nwalked < nwnames; nwalked++) { if (v9fs_request_cancelled(pdu)) { - err = -EINTR; + any_err |= err = -EINTR; break; } if (!same_stat_id(&pdu->s->root_st, &stbuf) || - strcmp("..", wnames[name_idx].data)) + strcmp("..", wnames[nwalked].data)) { err = s->ops->name_to_path(&s->ctx, &dpath, - wnames[name_idx].data, - &pathes[name_idx]); + wnames[nwalked].data, + &pathes[nwalked]); if (err < 0) { - err = -errno; + any_err |= err = -errno; break; } if (v9fs_request_cancelled(pdu)) { - err = -EINTR; + any_err |= err = -EINTR; break; } - err = s->ops->lstat(&s->ctx, &pathes[name_idx], &stbuf); + err = s->ops->lstat(&s->ctx, &pathes[nwalked], &stbuf); if (err < 0) { - err = -errno; + any_err |= err = -errno; break; } - stbufs[name_idx] = stbuf; - v9fs_path_copy(&dpath, &pathes[name_idx]); + stbufs[nwalked] = stbuf; + v9fs_path_copy(&dpath, &pathes[nwalked]); } } }); /* * Handle all the rest of this Twalk request on main thread ... + * + * NOTE: -EINTR is an exception where we deviate from the protocol spec + * and simply send a (R)Lerror response instead of bothering to assemble + * a (deducted) Rwalk response; because -EINTR is always the result of a + * Tflush request, so client would no longer wait for a response in this + * case anyway. */ - if (err < 0) { + if ((err < 0 && !nwalked) || err == -EINTR) { goto out; } - err = stat_to_qid(pdu, &fidst, &qid); - if (err < 0) { + any_err |= err = stat_to_qid(pdu, &fidst, &qid); + if (err < 0 && !nwalked) { goto out; } stbuf = fidst; @@ -1888,20 +1914,29 @@ static void coroutine_fn v9fs_walk(void *opaque) v9fs_path_copy(&dpath, &fidp->path); v9fs_path_copy(&path, &fidp->path); - for (name_idx = 0; name_idx < nwnames; name_idx++) { + for (name_idx = 0; name_idx < nwalked; name_idx++) { if (!same_stat_id(&pdu->s->root_st, &stbuf) || strcmp("..", wnames[name_idx].data)) { stbuf = stbufs[name_idx]; - err = stat_to_qid(pdu, &stbuf, &qid); + any_err |= err = stat_to_qid(pdu, &stbuf, &qid); if (err < 0) { - goto out; + break; } v9fs_path_copy(&path, &pathes[name_idx]); v9fs_path_copy(&dpath, &path); } memcpy(&qids[name_idx], &qid, sizeof(qid)); } + if (any_err < 0) { + if (!name_idx) { + /* don't send any QIDs, send Rlerror instead */ + goto out; + } else { + /* send QIDs (not Rlerror), but fid MUST remain unaffected */ + goto send_qids; + } + } if (fid == newfid) { if (fidp->fid_type != P9_FID_NONE) { err = -EINVAL; @@ -1919,8 +1954,9 @@ static void coroutine_fn v9fs_walk(void *opaque) newfidp->uid = fidp->uid; v9fs_path_copy(&newfidp->path, &path); } - err = v9fs_walk_marshal(pdu, nwnames, qids); - trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids); +send_qids: + err = v9fs_walk_marshal(pdu, name_idx, qids); + trace_v9fs_walk_return(pdu->tag, pdu->id, name_idx, qids); out: put_fid(pdu, fidp); if (newfidp) { @@ -3186,6 +3222,8 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, V9fsFidState *tfidp; V9fsState *s = pdu->s; V9fsFidState *dirfidp = NULL; + GHashTableIter iter; + gpointer fid; v9fs_path_init(&new_path); if (newdirfid != -1) { @@ -3219,11 +3257,13 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, if (err < 0) { goto out; } + /* * Fixup fid's pointing to the old name to * start pointing to the new name */ - QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) { + g_hash_table_iter_init(&iter, s->fids); + while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &tfidp)) { if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) { /* replace the name */ v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data)); @@ -3301,6 +3341,8 @@ static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, V9fsPath oldpath, newpath; V9fsState *s = pdu->s; int err; + GHashTableIter iter; + gpointer fid; v9fs_path_init(&oldpath); v9fs_path_init(&newpath); @@ -3317,7 +3359,8 @@ static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, * Fixup fid's pointing to the old name to * start pointing to the new name */ - QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) { + g_hash_table_iter_init(&iter, s->fids); + while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &tfidp)) { if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) { /* replace the name */ v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data)); @@ -4207,7 +4250,7 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, s->ctx.fmode = fse->fmode; s->ctx.dmode = fse->dmode; - QSIMPLEQ_INIT(&s->fid_list); + s->fids = g_hash_table_new(NULL, NULL); qemu_co_rwlock_init(&s->rename_lock); if (s->ops->init(&s->ctx, errp) < 0) { @@ -4267,6 +4310,10 @@ void v9fs_device_unrealize_common(V9fsState *s) if (s->ctx.fst) { fsdev_throttle_cleanup(s->ctx.fst); } + if (s->fids) { + g_hash_table_destroy(s->fids); + s->fids = NULL; + } g_free(s->tag); qp_table_destroy(&s->qpd_table); qp_table_destroy(&s->qpp_table); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 994f95260013..2fce4140d1e9 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -339,7 +339,7 @@ typedef struct { struct V9fsState { QLIST_HEAD(, V9fsPDU) free_list; QLIST_HEAD(, V9fsPDU) active_list; - QSIMPLEQ_HEAD(, V9fsFidState) fid_list; + GHashTable *fids; FileOperations *ops; FsContext ctx; char *tag; @@ -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/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 54ee93b71fc1..5f522e68e9f2 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -216,7 +216,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp) } v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); - virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); + virtio_init(vdev, VIRTIO_ID_9P, v->config_size); v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); } diff --git a/hw/Kconfig b/hw/Kconfig index ad20cce0a953..38233bbb0f13 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -6,6 +6,7 @@ source audio/Kconfig source block/Kconfig source char/Kconfig source core/Kconfig +source cxl/Kconfig source display/Kconfig source dma/Kconfig source gpio/Kconfig @@ -49,6 +50,7 @@ source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig +source loongarch/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 19caebde6c1d..1f7803fdab87 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -5,16 +5,18 @@ config ACPI_X86 bool select ACPI select ACPI_NVDIMM + select ACPI_CXL select ACPI_CPU_HOTPLUG select ACPI_MEMORY_HOTPLUG select ACPI_HMAT - select ACPI_PIIX4 select ACPI_PCIHP select ACPI_ERST -config ACPI_X86_ICH +config ACPI_ICH9 bool + select ACPI_SMBUS select ACPI_X86 + select APM config ACPI_CPU_HOTPLUG bool @@ -29,7 +31,9 @@ config ACPI_NVDIMM config ACPI_PIIX4 bool - depends on ACPI + select ACPI + select ACPI_SMBUS + select APM config ACPI_PCIHP bool @@ -66,3 +70,7 @@ config ACPI_ERST bool default y depends on ACPI && PCI + +config ACPI_CXL + bool + depends on ACPI diff --git a/hw/acpi/acpi_interface.c b/hw/acpi/acpi_interface.c index 6583917b8e4c..c668d361f64f 100644 --- a/hw/acpi/acpi_interface.c +++ b/hw/acpi/acpi_interface.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "hw/acpi/acpi_dev_interface.h" +#include "hw/acpi/acpi_aml_interface.h" #include "qemu/module.h" void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event) @@ -18,8 +19,15 @@ static void register_types(void) .parent = TYPE_INTERFACE, .class_size = sizeof(AcpiDeviceIfClass), }; + static const TypeInfo acpi_dev_aml_if_info = { + .name = TYPE_ACPI_DEV_AML_IF, + .parent = TYPE_INTERFACE, + .class_size = sizeof(AcpiDevAmlIfClass), + }; + type_register_static(&acpi_dev_if_info); + type_register_static(&acpi_dev_aml_if_info); } type_init(register_types) diff --git a/hw/acpi/aml-build-stub.c b/hw/acpi/aml-build-stub.c index 8d8ad1a31497..89a8fec4afa8 100644 --- a/hw/acpi/aml-build-stub.c +++ b/hw/acpi/aml-build-stub.c @@ -26,6 +26,16 @@ void aml_append(Aml *parent_ctx, Aml *child) { } +Aml *aml_return(Aml *val) +{ + return NULL; +} + +Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag) +{ + return NULL; +} + Aml *aml_resource_template(void) { return NULL; diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 4086879ebff9..ea331a20d131 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2002,90 +2002,75 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, const char *oem_id, const char *oem_table_id) { MachineClass *mc = MACHINE_GET_CLASS(ms); - GQueue *list = g_queue_new(); - guint pptt_start = table_data->len; - guint parent_offset; - guint length, i; - int uid = 0; - int socket; + CPUArchIdList *cpus = ms->possible_cpus; + int64_t socket_id = -1, cluster_id = -1, core_id = -1; + uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0; + uint32_t pptt_start = table_data->len; + int n; AcpiTable table = { .sig = "PPTT", .rev = 2, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(&table, table_data); - for (socket = 0; socket < ms->smp.sockets; socket++) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - /* - * Physical package - represents the boundary - * of a physical package - */ - (1 << 0), - 0, socket, NULL, 0); - } - - if (mc->smp_props.clusters_supported) { - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int cluster; - - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (cluster = 0; cluster < ms->smp.clusters; cluster++) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - (0 << 0), /* not a physical package */ - parent_offset, cluster, NULL, 0); - } + /* + * This works with the assumption that cpus[n].props.*_id has been + * sorted from top to down levels in mc->possible_cpu_arch_ids(). + * Otherwise, the unexpected and duplicated containers will be + * created. + */ + for (n = 0; n < cpus->len; n++) { + if (cpus->cpus[n].props.socket_id != socket_id) { + assert(cpus->cpus[n].props.socket_id > socket_id); + socket_id = cpus->cpus[n].props.socket_id; + cluster_id = -1; + core_id = -1; + socket_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (1 << 0), /* Physical package */ + 0, socket_id, NULL, 0); } - } - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int core; - - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (core = 0; core < ms->smp.cores; core++) { - if (ms->smp.threads > 1) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - (0 << 0), /* not a physical package */ - parent_offset, core, NULL, 0); - } else { - build_processor_hierarchy_node( - table_data, - (1 << 1) | /* ACPI Processor ID valid */ - (1 << 3), /* Node is a Leaf */ - parent_offset, uid++, NULL, 0); + if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters) { + if (cpus->cpus[n].props.cluster_id != cluster_id) { + assert(cpus->cpus[n].props.cluster_id > cluster_id); + cluster_id = cpus->cpus[n].props.cluster_id; + core_id = -1; + cluster_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (0 << 0), /* Not a physical package */ + socket_offset, cluster_id, NULL, 0); } + } else { + cluster_offset = socket_offset; } - } - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int thread; + if (ms->smp.threads == 1) { + build_processor_hierarchy_node(table_data, + (1 << 1) | /* ACPI Processor ID valid */ + (1 << 3), /* Node is a Leaf */ + cluster_offset, n, NULL, 0); + } else { + if (cpus->cpus[n].props.core_id != core_id) { + assert(cpus->cpus[n].props.core_id > core_id); + core_id = cpus->cpus[n].props.core_id; + core_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (0 << 0), /* Not a physical package */ + cluster_offset, core_id, NULL, 0); + } - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (thread = 0; thread < ms->smp.threads; thread++) { - build_processor_hierarchy_node( - table_data, + build_processor_hierarchy_node(table_data, (1 << 1) | /* ACPI Processor ID valid */ (1 << 2) | /* Processor is a Thread */ (1 << 3), /* Node is a Leaf */ - parent_offset, uid++, NULL, 0); + core_offset, n, NULL, 0); } } - g_queue_free(list); acpi_table_end(linker, &table); } -/* build rev1/rev3/rev5.1 FADT */ +/* build rev1/rev3/rev5.1/rev6.0 FADT */ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, const char *oem_id, const char *oem_table_id) { @@ -2208,8 +2193,15 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, /* SLEEP_STATUS_REG */ build_append_gas_from_struct(tbl, &f->sleep_sts); - /* TODO: extra fields need to be added to support revisions above rev5 */ - assert(f->rev == 5); + if (f->rev == 5) { + goto done; + } + + /* Hypervisor Vendor Identity */ + build_append_padded_str(tbl, "QEMU", 8, '\0'); + + /* TODO: extra fields need to be added to support revisions above rev6 */ + assert(f->rev == 6); done: acpi_table_end(linker, &table); diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 3e811bf03cac..6da275c599c6 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -185,7 +185,7 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen, changed_fields = 0; ext_hdr->_length = cpu_to_le16(acpi_payload_size); - if (hdrs->has_sig) { + if (hdrs->sig) { strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig); ++changed_fields; } @@ -204,11 +204,11 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen, ext_hdr->checksum = 0; - if (hdrs->has_oem_id) { + if (hdrs->oem_id) { strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id); ++changed_fields; } - if (hdrs->has_oem_table_id) { + if (hdrs->oem_table_id) { strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id, sizeof ext_hdr->oem_table_id); ++changed_fields; @@ -217,7 +217,7 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen, ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev); ++changed_fields; } - if (hdrs->has_asl_compiler_id) { + if (hdrs->asl_compiler_id) { strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id, sizeof ext_hdr->asl_compiler_id); ++changed_fields; @@ -255,12 +255,12 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) if (!hdrs) { goto out; } - if (hdrs->has_file == hdrs->has_data) { + if (!hdrs->file == !hdrs->data) { error_setg(errp, "'-acpitable' requires one of 'data' or 'file'"); goto out; } - pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0); + pathnames = g_strsplit(hdrs->file ?: hdrs->data, ":", 0); if (pathnames == NULL || pathnames[0] == NULL) { error_setg(errp, "'-acpitable' requires at least one pathname"); goto out; @@ -297,7 +297,7 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) close(fd); } - acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, errp); + acpi_table_install(blob, bloblen, !!hdrs->file, hdrs, errp); out: g_free(blob); diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 3646dbfe68a5..4e580959a26e 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -35,7 +35,6 @@ static ACPIOSTInfo *acpi_cpu_device_status(int idx, AcpiCpuStatus *cdev) DeviceState *dev = DEVICE(cdev->cpu); if (dev->id) { info->device = g_strdup(dev->id); - info->has_device = true; } } return info; diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index 53654f863830..ff14c3f4106f 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -52,6 +52,9 @@ static const MemoryRegionOps AcpiCpuHotplug_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, + .max_access_size = 4, + }, + .impl = { .max_access_size = 1, }, }; diff --git a/hw/acpi/cxl-stub.c b/hw/acpi/cxl-stub.c new file mode 100644 index 000000000000..15bc21076bff --- /dev/null +++ b/hw/acpi/cxl-stub.c @@ -0,0 +1,12 @@ + +/* + * Stubs for ACPI platforms that don't support CXl + */ +#include "qemu/osdep.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/cxl.h" + +void build_cxl_osc_method(Aml *dev) +{ + g_assert_not_reached(); +} diff --git a/hw/acpi/cxl.c b/hw/acpi/cxl.c new file mode 100644 index 000000000000..2bf8c0799359 --- /dev/null +++ b/hw/acpi/cxl.c @@ -0,0 +1,256 @@ +/* + * CXL ACPI Implementation + * + * Copyright(C) 2020 Intel 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 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 + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_host.h" +#include "hw/cxl/cxl.h" +#include "hw/mem/memory-device.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/cxl.h" +#include "qapi/error.h" +#include "qemu/uuid.h" + +static void cedt_build_chbs(GArray *table_data, PXBDev *cxl) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(cxl->cxl.cxl_host_bridge); + struct MemoryRegion *mr = sbd->mmio[0].memory; + + /* Type */ + build_append_int_noprefix(table_data, 0, 1); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + + /* Record Length */ + build_append_int_noprefix(table_data, 32, 2); + + /* UID - currently equal to bus number */ + build_append_int_noprefix(table_data, cxl->bus_nr, 4); + + /* Version */ + build_append_int_noprefix(table_data, 1, 4); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); + + /* Base - subregion within a container that is in PA space */ + build_append_int_noprefix(table_data, mr->container->addr + mr->addr, 8); + + /* Length */ + build_append_int_noprefix(table_data, memory_region_size(mr), 8); +} + +/* + * CFMWS entries in CXL 2.0 ECN: CEDT CFMWS & QTG _DSM. + * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory + * interleaving. + */ +static void cedt_build_cfmws(GArray *table_data, CXLState *cxls) +{ + GList *it; + + for (it = cxls->fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + int i; + + /* Type */ + build_append_int_noprefix(table_data, 1, 1); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + + /* Record Length */ + build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); + + /* Base HPA */ + build_append_int_noprefix(table_data, fw->mr.addr, 8); + + /* Window Size */ + build_append_int_noprefix(table_data, fw->size, 8); + + /* Host Bridge Interleave Ways */ + build_append_int_noprefix(table_data, fw->enc_int_ways, 1); + + /* Host Bridge Interleave Arithmetic */ + build_append_int_noprefix(table_data, 0, 1); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 2); + + /* Host Bridge Interleave Granularity */ + build_append_int_noprefix(table_data, fw->enc_int_gran, 4); + + /* Window Restrictions */ + build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */ + + /* QTG ID */ + build_append_int_noprefix(table_data, 0, 2); + + /* Host Bridge List (list of UIDs - currently bus_nr) */ + for (i = 0; i < fw->num_targets; i++) { + g_assert(fw->target_hbs[i]); + build_append_int_noprefix(table_data, fw->target_hbs[i]->bus_nr, 4); + } + } +} + +static int cxl_foreach_pxb_hb(Object *obj, void *opaque) +{ + Aml *cedt = opaque; + + if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEVICE)) { + cedt_build_chbs(cedt->buf, PXB_CXL_DEV(obj)); + } + + return 0; +} + +void cxl_build_cedt(GArray *table_offsets, GArray *table_data, + BIOSLinker *linker, const char *oem_id, + const char *oem_table_id, CXLState *cxl_state) +{ + Aml *cedt; + AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id, + .oem_table_id = oem_table_id }; + + acpi_add_table(table_offsets, table_data); + acpi_table_begin(&table, table_data); + cedt = init_aml_allocator(); + + /* reserve space for CEDT header */ + + object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt); + cedt_build_cfmws(cedt->buf, cxl_state); + + /* copy AML table into ACPI tables blob and patch header there */ + g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len); + free_aml_allocator(); + + acpi_table_end(linker, &table); +} + +static Aml *__build_cxl_osc_method(void) +{ + Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked; + Aml *a_ctrl = aml_local(0); + Aml *a_cdw1 = aml_name("CDW1"); + + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); + /* CDW1 is used for the return value so is present whether or not a match occurs */ + aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); + + /* + * Generate shared section between: + * CXL 2.0 - 9.14.2.1.4 and + * PCI Firmware Specification 3.0 + * 4.5.1. _OSC Interface for PCI Host Bridge Devices + * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is + * identified by the Universal Unique IDentifier (UUID) + * 33DB4D5B-1FF7-401C-9657-7441C03DD766 + * The _OSC interface for a CXL Host bridge is + * identified by the UUID 68F2D50B-C469-4D8A-BD3D-941A103FD3FC + * A CXL Host bridge is compatible with a PCI host bridge so + * for the shared section match both. + */ + if_uuid = aml_if( + aml_lor(aml_equal(aml_arg(0), + aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")), + aml_equal(aml_arg(0), + aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC")))); + aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); + aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); + + aml_append(if_uuid, aml_store(aml_name("CDW3"), a_ctrl)); + + /* + * + * Allows OS control for all 5 features: + * PCIeHotplug SHPCHotplug PME AER PCIeCapability + */ + aml_append(if_uuid, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); + + /* + * Check _OSC revision. + * PCI Firmware specification 3.3 and CXL 2.0 both use revision 1 + * Unknown Revision is CDW1 - BIT (3) + */ + if_arg1_not_1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); + aml_append(if_arg1_not_1, aml_or(a_cdw1, aml_int(0x08), a_cdw1)); + aml_append(if_uuid, if_arg1_not_1); + + if_caps_masked = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); + + /* Capability bits were masked */ + aml_append(if_caps_masked, aml_or(a_cdw1, aml_int(0x10), a_cdw1)); + aml_append(if_uuid, if_caps_masked); + + aml_append(if_uuid, aml_store(aml_name("CDW2"), aml_name("SUPP"))); + aml_append(if_uuid, aml_store(aml_name("CDW3"), aml_name("CTRL"))); + + /* Update DWORD3 (the return value) */ + aml_append(if_uuid, aml_store(a_ctrl, aml_name("CDW3"))); + + /* CXL only section as per CXL 2.0 - 9.14.2.1.4 */ + if_cxl = aml_if(aml_equal( + aml_arg(0), aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC"))); + /* CXL support field */ + aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(12), "CDW4")); + /* CXL capabilities */ + aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(16), "CDW5")); + aml_append(if_cxl, aml_store(aml_name("CDW4"), aml_name("SUPC"))); + aml_append(if_cxl, aml_store(aml_name("CDW5"), aml_name("CTRC"))); + + /* CXL 2.0 Port/Device Register access */ + aml_append(if_cxl, + aml_or(aml_name("CDW5"), aml_int(0x1), aml_name("CDW5"))); + aml_append(if_uuid, if_cxl); + + aml_append(if_uuid, aml_return(aml_arg(3))); + aml_append(method, if_uuid); + + /* + * If no UUID matched, return Unrecognized UUID via Arg3 DWord 1 + * ACPI 6.4 - 6.2.11 + * Unrecognised UUID - BIT(2) + */ + else_uuid = aml_else(); + + aml_append(else_uuid, + aml_or(aml_name("CDW1"), aml_int(0x4), aml_name("CDW1"))); + aml_append(else_uuid, aml_return(aml_arg(3))); + aml_append(method, else_uuid); + + return method; +} + +void build_cxl_osc_method(Aml *dev) +{ + aml_append(dev, aml_name_decl("SUPP", aml_int(0))); + aml_append(dev, aml_name_decl("CTRL", aml_int(0))); + aml_append(dev, aml_name_decl("SUPC", aml_int(0))); + aml_append(dev, aml_name_decl("CTRC", aml_int(0))); + aml_append(dev, __build_cxl_osc_method()); +} diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index de509c2b48f6..35007d801731 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -14,7 +14,7 @@ #include "hw/qdev-core.h" #include "exec/memory.h" #include "qom/object.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "qom/object_interfaces.h" #include "qemu/error-report.h" #include "migration/vmstate.h" @@ -440,6 +440,7 @@ static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) (record_size >= 4096) /* PAGE_SIZE */ )) { error_setg(errp, "ERST record_size %u is invalid", record_size); + return; } /* Validity check header */ @@ -450,6 +451,7 @@ static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) (le16_to_cpu(header->reserved) == 0) )) { error_setg(errp, "ERST backend storage header is invalid"); + return; } /* Check storage_size against record_size */ @@ -457,6 +459,7 @@ static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) (record_size > s->storage_size)) { error_setg(errp, "ACPI ERST requires storage size be multiple of " "record size (%uKiB)", record_size); + return; } /* Compute offset of first and last record storage slot */ @@ -632,7 +635,7 @@ static unsigned read_erst_record(ERSTDeviceState *s) if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { rc = STATUS_FAILED; } - if ((s->record_offset + record_length) > exchange_length) { + if (record_length > exchange_length - s->record_offset) { rc = STATUS_FAILED; } /* If all is ok, copy the record to the exchange buffer */ @@ -681,7 +684,7 @@ static unsigned write_erst_record(ERSTDeviceState *s) if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { return STATUS_FAILED; } - if ((s->record_offset + record_length) > exchange_length) { + if (record_length > exchange_length - s->record_offset) { return STATUS_FAILED; } @@ -713,7 +716,7 @@ static unsigned write_erst_record(ERSTDeviceState *s) if (nvram) { /* Write the record into the slot */ memcpy(nvram, exchange, record_length); - memset(nvram + record_length, exchange_length - record_length, 0xFF); + memset(nvram + record_length, 0xFF, exchange_length - record_length); /* If a new record, increment the record_count */ if (!record_found) { uint32_t record_count; diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index e28457a7d103..a3d31631fe0d 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/ghes.c b/hw/acpi/ghes.c index 45d9a809cc98..e9511d9b8f71 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -249,7 +249,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker) for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { /* * Initialize the value of read_ack_register to 1, so GHES can be - * writeable after (re)boot. + * writable after (re)boot. * ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2 * (GHESv2 - Type 10) */ diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index bd9bbade7051..a93c470e9df3 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -34,7 +34,7 @@ #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "hw/acpi/acpi.h" -#include "hw/acpi/tco.h" +#include "hw/acpi/ich9_tco.h" #include "hw/i386/ich9.h" #include "hw/mem/pc-dimm.h" @@ -316,8 +316,9 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, pm->smm_enabled = smm_enabled; - pm->enable_tco = true; - acpi_pm_tco_init(&pm->tco_regs, &pm->io); + if (pm->enable_tco) { + acpi_pm_tco_init(&pm->tco_regs, &pm->io); + } if (pm->use_acpi_hotplug_bridge) { acpi_pcihp_init(OBJECT(lpc_pci), @@ -440,6 +441,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) pm->s4_val = 2; pm->use_acpi_hotplug_bridge = true; pm->keep_pci_slot_hpc = true; + pm->enable_tco = true; object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, &pm->pm_io_base, OBJ_PROP_FLAG_READ); diff --git a/hw/acpi/ich9_tco.c b/hw/acpi/ich9_tco.c new file mode 100644 index 000000000000..fbf97f81f4a0 --- /dev/null +++ b/hw/acpi/ich9_tco.c @@ -0,0 +1,275 @@ +/* + * QEMU ICH9 TCO emulation + * + * Copyright (c) 2015 Paulo Alcantara + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/watchdog.h" +#include "hw/i386/ich9.h" +#include "migration/vmstate.h" + +#include "hw/acpi/ich9_tco.h" +#include "trace.h" + +enum { + TCO_RLD_DEFAULT = 0x0000, + TCO_DAT_IN_DEFAULT = 0x00, + TCO_DAT_OUT_DEFAULT = 0x00, + TCO1_STS_DEFAULT = 0x0000, + TCO2_STS_DEFAULT = 0x0000, + TCO1_CNT_DEFAULT = 0x0000, + TCO2_CNT_DEFAULT = 0x0008, + TCO_MESSAGE1_DEFAULT = 0x00, + TCO_MESSAGE2_DEFAULT = 0x00, + TCO_WDCNT_DEFAULT = 0x00, + TCO_TMR_DEFAULT = 0x0004, + SW_IRQ_GEN_DEFAULT = 0x03, +}; + +static inline void tco_timer_reload(TCOIORegs *tr) +{ + int ticks = tr->tco.tmr & TCO_TMR_MASK; + int64_t nsec = (int64_t)ticks * TCO_TICK_NSEC; + + trace_tco_timer_reload(ticks, nsec / 1000000); + tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + nsec; + timer_mod(tr->tco_timer, tr->expire_time); +} + +static inline void tco_timer_stop(TCOIORegs *tr) +{ + tr->expire_time = -1; + timer_del(tr->tco_timer); +} + +static void tco_timer_expired(void *opaque) +{ + TCOIORegs *tr = opaque; + ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs); + ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm); + uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_CC_GCS); + + trace_tco_timer_expired(tr->timeouts_no, + lpc->pin_strap.spkr_hi, + !!(gcs & ICH9_CC_GCS_NO_REBOOT)); + tr->tco.rld = 0; + tr->tco.sts1 |= TCO_TIMEOUT; + if (++tr->timeouts_no == 2) { + tr->tco.sts2 |= TCO_SECOND_TO_STS; + tr->tco.sts2 |= TCO_BOOT_STS; + tr->timeouts_no = 0; + + if (!lpc->pin_strap.spkr_hi && !(gcs & ICH9_CC_GCS_NO_REBOOT)) { + watchdog_perform_action(); + tco_timer_stop(tr); + return; + } + } + + if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) { + ich9_generate_smi(); + } + tr->tco.rld = tr->tco.tmr; + tco_timer_reload(tr); +} + +/* NOTE: values of 0 or 1 will be ignored by ICH */ +static inline int can_start_tco_timer(TCOIORegs *tr) +{ + return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1; +} + +static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr) +{ + uint16_t rld; + uint32_t ret = 0; + + switch (addr) { + case TCO_RLD: + if (tr->expire_time != -1) { + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC; + rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK); + } else { + rld = tr->tco.rld; + } + ret = rld; + break; + case TCO_DAT_IN: + ret = tr->tco.din; + break; + case TCO_DAT_OUT: + ret = tr->tco.dout; + break; + case TCO1_STS: + ret = tr->tco.sts1; + break; + case TCO2_STS: + ret = tr->tco.sts2; + break; + case TCO1_CNT: + ret = tr->tco.cnt1; + break; + case TCO2_CNT: + ret = tr->tco.cnt2; + break; + case TCO_MESSAGE1: + ret = tr->tco.msg1; + break; + case TCO_MESSAGE2: + ret = tr->tco.msg2; + break; + case TCO_WDCNT: + ret = tr->tco.wdcnt; + break; + case TCO_TMR: + ret = tr->tco.tmr; + break; + case SW_IRQ_GEN: + ret = tr->sw_irq_gen; + break; + } + trace_tco_io_read(addr, ret); + return ret; +} + +static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val) +{ + trace_tco_io_write(addr, val); + switch (addr) { + case TCO_RLD: + tr->timeouts_no = 0; + if (can_start_tco_timer(tr)) { + tr->tco.rld = tr->tco.tmr; + tco_timer_reload(tr); + } else { + tr->tco.rld = val; + } + break; + case TCO_DAT_IN: + tr->tco.din = val; + tr->tco.sts1 |= SW_TCO_SMI; + ich9_generate_smi(); + break; + case TCO_DAT_OUT: + tr->tco.dout = val; + tr->tco.sts1 |= TCO_INT_STS; + /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */ + break; + case TCO1_STS: + tr->tco.sts1 = val & TCO1_STS_MASK; + break; + case TCO2_STS: + tr->tco.sts2 = val & TCO2_STS_MASK; + break; + case TCO1_CNT: + val &= TCO1_CNT_MASK; + /* + * once TCO_LOCK bit is set, it can not be cleared by software. a reset + * is required to change this bit from 1 to 0 -- it defaults to 0. + */ + tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK); + if (can_start_tco_timer(tr)) { + tr->tco.rld = tr->tco.tmr; + tco_timer_reload(tr); + } else { + tco_timer_stop(tr); + } + break; + case TCO2_CNT: + tr->tco.cnt2 = val; + break; + case TCO_MESSAGE1: + tr->tco.msg1 = val; + break; + case TCO_MESSAGE2: + tr->tco.msg2 = val; + break; + case TCO_WDCNT: + tr->tco.wdcnt = val; + break; + case TCO_TMR: + tr->tco.tmr = val; + break; + case SW_IRQ_GEN: + tr->sw_irq_gen = val; + break; + } +} + +static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width) +{ + TCOIORegs *tr = opaque; + return tco_ioport_readw(tr, addr); +} + +static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + TCOIORegs *tr = opaque; + tco_ioport_writew(tr, addr, val); +} + +static const MemoryRegionOps tco_io_ops = { + .read = tco_io_readw, + .write = tco_io_writew, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent) +{ + *tr = (TCOIORegs) { + .tco = { + .rld = TCO_RLD_DEFAULT, + .din = TCO_DAT_IN_DEFAULT, + .dout = TCO_DAT_OUT_DEFAULT, + .sts1 = TCO1_STS_DEFAULT, + .sts2 = TCO2_STS_DEFAULT, + .cnt1 = TCO1_CNT_DEFAULT, + .cnt2 = TCO2_CNT_DEFAULT, + .msg1 = TCO_MESSAGE1_DEFAULT, + .msg2 = TCO_MESSAGE2_DEFAULT, + .wdcnt = TCO_WDCNT_DEFAULT, + .tmr = TCO_TMR_DEFAULT, + }, + .sw_irq_gen = SW_IRQ_GEN_DEFAULT, + .tco_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tco_timer_expired, tr), + .expire_time = -1, + .timeouts_no = 0, + }; + memory_region_init_io(&tr->io, memory_region_owner(parent), + &tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN); + memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io); +} + +const VMStateDescription vmstate_tco_io_sts = { + .name = "tco io device status", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT16(tco.rld, TCOIORegs), + VMSTATE_UINT8(tco.din, TCOIORegs), + VMSTATE_UINT8(tco.dout, TCOIORegs), + VMSTATE_UINT16(tco.sts1, TCOIORegs), + VMSTATE_UINT16(tco.sts2, TCOIORegs), + VMSTATE_UINT16(tco.cnt1, TCOIORegs), + VMSTATE_UINT16(tco.cnt2, TCOIORegs), + VMSTATE_UINT8(tco.msg1, TCOIORegs), + VMSTATE_UINT8(tco.msg2, TCOIORegs), + VMSTATE_UINT8(tco.wdcnt, TCOIORegs), + VMSTATE_UINT16(tco.tmr, TCOIORegs), + VMSTATE_UINT8(sw_irq_gen, TCOIORegs), + VMSTATE_TIMER_PTR(tco_timer, TCOIORegs), + VMSTATE_INT64(expire_time, TCOIORegs), + VMSTATE_UINT8(timeouts_no, TCOIORegs), + VMSTATE_END_OF_LIST() + } +}; diff --git a/hw/acpi/ipmi-stub.c b/hw/acpi/ipmi-stub.c index 8634fb325c71..befaf0a882a3 100644 --- a/hw/acpi/ipmi-stub.c +++ b/hw/acpi/ipmi-stub.c @@ -10,6 +10,6 @@ #include "qemu/osdep.h" #include "hw/acpi/ipmi.h" -void build_acpi_ipmi_devices(Aml *table, BusState *bus, const char *resource) +void build_ipmi_dev_aml(AcpiDevAmlIf *adev, Aml *scope) { } diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c index 96e48eba15ea..a20e57d465cb 100644 --- a/hw/acpi/ipmi.c +++ b/hw/acpi/ipmi.c @@ -13,7 +13,7 @@ #include "hw/acpi/acpi.h" #include "hw/acpi/ipmi.h" -static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource) +static Aml *aml_ipmi_crs(IPMIFwInfo *info) { Aml *crs = aml_resource_template(); @@ -49,7 +49,7 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource) break; case IPMI_MEMSPACE_SMBUS: aml_append(crs, aml_i2c_serial_bus_device(info->base_address, - resource)); + "^")); break; default: abort(); @@ -62,46 +62,27 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource) return crs; } -static Aml *aml_ipmi_device(IPMIFwInfo *info, const char *resource) +void build_ipmi_dev_aml(AcpiDevAmlIf *adev, Aml *scope) { Aml *dev; - uint16_t version = ((info->ipmi_spec_major_revision << 8) - | (info->ipmi_spec_minor_revision << 4)); + IPMIFwInfo info = {}; + IPMIInterface *ii = IPMI_INTERFACE(adev); + IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); + uint16_t version; - assert(info->ipmi_spec_minor_revision <= 15); + iic->get_fwinfo(ii, &info); + assert(info.ipmi_spec_minor_revision <= 15); + version = ((info.ipmi_spec_major_revision << 8) + | (info.ipmi_spec_minor_revision << 4)); - dev = aml_device("MI%d", info->uuid); + dev = aml_device("MI%d", info.uuid); aml_append(dev, aml_name_decl("_HID", aml_eisaid("IPI0001"))); aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s", - info->interface_name))); - aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid))); - aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info, resource))); - aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type))); + info.interface_name))); + aml_append(dev, aml_name_decl("_UID", aml_int(info.uuid))); + aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(&info))); + aml_append(dev, aml_name_decl("_IFT", aml_int(info.interface_type))); aml_append(dev, aml_name_decl("_SRV", aml_int(version))); - return dev; -} - -void build_acpi_ipmi_devices(Aml *scope, BusState *bus, const char *resource) -{ - - BusChild *kid; - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - IPMIInterface *ii; - IPMIInterfaceClass *iic; - IPMIFwInfo info; - Object *obj = object_dynamic_cast(OBJECT(kid->child), - TYPE_IPMI_INTERFACE); - - if (!obj) { - continue; - } - - ii = IPMI_INTERFACE(obj); - iic = IPMI_INTERFACE_GET_CLASS(obj); - memset(&info, 0, sizeof(info)); - iic->get_fwinfo(ii, &info); - aml_append(scope, aml_ipmi_device(&info, resource)); - } + aml_append(scope, dev); } diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 0a7e89a13eec..d926f4f77dd1 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -44,7 +44,6 @@ static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev) DeviceState *dev = DEVICE(mdev->dimm); if (dev->id) { info->device = g_strdup(dev->id); - info->has_device = true; } } return info; @@ -186,7 +185,7 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, */ qapi_event_send_mem_unplug_error(dev->id ? : "", error_get_pretty(local_err)); - qapi_event_send_device_unplug_guest_error(!!dev->id, dev->id, + qapi_event_send_device_unplug_guest_error(dev->id, dev->canonical_path); error_free(local_err); break; diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 8bea2e693341..30054a8cdc2d 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -13,6 +13,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_false: files('acpi-mem-hotplu acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_true: files('nvdimm.c')) acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_false: files('acpi-nvdimm-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c')) +acpi_ss.add(when: 'CONFIG_ACPI_CXL', if_true: files('cxl.c'), if_false: files('cxl-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c')) acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device.c')) acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c')) @@ -21,16 +22,17 @@ acpi_ss.add(when: 'CONFIG_ACPI_PIIX4', if_true: files('piix4.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c')) -acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c')) +acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c')) acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c')) acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) if have_tpm acpi_ss.add(files('tpm.c')) endif -softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c')) +softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c')) softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', 'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c', 'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c', - 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c')) + 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c', + 'cxl-stub.c')) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index 0d43da19ea42..a3b25a92f3fa 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 @@ -476,7 +477,7 @@ struct NvdimmFuncGetLabelDataOut { /* the size of buffer filled by QEMU. */ uint32_t len; uint32_t func_ret_status; /* return status code. */ - uint8_t out_buf[]; /* the data got via Get Namesapce Label function. */ + uint8_t out_buf[]; /* the data got via Get Namespace Label function. */ } QEMU_PACKED; typedef struct NvdimmFuncGetLabelDataOut NvdimmFuncGetLabelDataOut; QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelDataOut) > NVDIMM_DSM_MEMORY_SIZE); @@ -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; } @@ -925,6 +922,7 @@ void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io, #define NVDIMM_DSM_RFIT_STATUS "RSTA" #define NVDIMM_QEMU_RSVD_UUID "648B9CF2-CDA1-4312-8AD9-49C4AF32BD62" +#define NVDIMM_DEVICE_DSM_UUID "4309AC30-0D11-11E4-9191-0800200C9A66" static void nvdimm_build_common_dsm(Aml *dev, NVDIMMState *nvdimm_state) @@ -1032,15 +1030,14 @@ static void nvdimm_build_common_dsm(Aml *dev, /* UUID for QEMU internal use */), expected_uuid)); aml_append(elsectx, ifctx); elsectx2 = aml_else(); - aml_append(elsectx2, aml_store( - aml_touuid("4309AC30-0D11-11E4-9191-0800200C9A66") + aml_append(elsectx2, aml_store(aml_touuid(NVDIMM_DEVICE_DSM_UUID) /* UUID for NVDIMM Devices */, expected_uuid)); aml_append(elsectx, elsectx2); aml_append(method, elsectx); uuid_invalid = aml_lnot(aml_equal(uuid, expected_uuid)); - unsupport = aml_if(aml_or(unpatched, uuid_invalid, NULL)); + unsupport = aml_if(aml_lor(unpatched, uuid_invalid)); /* * function 0 is called to inquire what functions are supported by @@ -1072,10 +1069,9 @@ static void nvdimm_build_common_dsm(Aml *dev, * in the DSM Spec. */ pckg = aml_arg(3); - ifctx = aml_if(aml_and(aml_equal(aml_object_type(pckg), + ifctx = aml_if(aml_land(aml_equal(aml_object_type(pckg), aml_int(4 /* Package */)) /* It is a Package? */, - aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? */, - NULL)); + aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? */)); pckg_index = aml_local(2); pckg_buf = aml_local(3); @@ -1247,6 +1243,7 @@ static void nvdimm_build_fit(Aml *dev) static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots) { uint32_t slot; + Aml *method, *pkg, *field, *com_call; for (slot = 0; slot < ram_slots; slot++) { uint32_t handle = nvdimm_slot_to_handle(slot); @@ -1264,6 +1261,100 @@ static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots) */ aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle))); + /* + * ACPI v6.4: Section 6.5.10 NVDIMM Label Methods + */ + /* _LSI */ + method = aml_method("_LSI", 0, AML_SERIALIZED); + com_call = aml_call5(NVDIMM_COMMON_DSM, + aml_touuid(NVDIMM_DEVICE_DSM_UUID), + aml_int(1), aml_int(4), aml_int(0), + aml_int(handle)); + aml_append(method, aml_store(com_call, aml_local(0))); + + aml_append(method, aml_create_dword_field(aml_local(0), + aml_int(0), "STTS")); + aml_append(method, aml_create_dword_field(aml_local(0), aml_int(4), + "SLSA")); + aml_append(method, aml_create_dword_field(aml_local(0), aml_int(8), + "MAXT")); + + pkg = aml_package(3); + aml_append(pkg, aml_name("STTS")); + aml_append(pkg, aml_name("SLSA")); + aml_append(pkg, aml_name("MAXT")); + aml_append(method, aml_store(pkg, aml_local(1))); + aml_append(method, aml_return(aml_local(1))); + + aml_append(nvdimm_dev, method); + + /* _LSR */ + method = aml_method("_LSR", 2, AML_SERIALIZED); + aml_append(method, aml_name_decl("INPT", aml_buffer(8, NULL))); + + aml_append(method, aml_create_dword_field(aml_name("INPT"), + aml_int(0), "OFST")); + aml_append(method, aml_create_dword_field(aml_name("INPT"), + aml_int(4), "LEN")); + aml_append(method, aml_store(aml_arg(0), aml_name("OFST"))); + aml_append(method, aml_store(aml_arg(1), aml_name("LEN"))); + + pkg = aml_package(1); + aml_append(pkg, aml_name("INPT")); + aml_append(method, aml_store(pkg, aml_local(0))); + + com_call = aml_call5(NVDIMM_COMMON_DSM, + aml_touuid(NVDIMM_DEVICE_DSM_UUID), + aml_int(1), aml_int(5), aml_local(0), + aml_int(handle)); + aml_append(method, aml_store(com_call, aml_local(3))); + field = aml_create_dword_field(aml_local(3), aml_int(0), "STTS"); + aml_append(method, field); + field = aml_create_field(aml_local(3), aml_int(32), + aml_shiftleft(aml_name("LEN"), aml_int(3)), + "LDAT"); + aml_append(method, field); + aml_append(method, aml_name_decl("LSA", aml_buffer(0, NULL))); + aml_append(method, aml_to_buffer(aml_name("LDAT"), aml_name("LSA"))); + + pkg = aml_package(2); + aml_append(pkg, aml_name("STTS")); + aml_append(pkg, aml_name("LSA")); + + aml_append(method, aml_store(pkg, aml_local(1))); + aml_append(method, aml_return(aml_local(1))); + + aml_append(nvdimm_dev, method); + + /* _LSW */ + method = aml_method("_LSW", 3, AML_SERIALIZED); + aml_append(method, aml_store(aml_arg(2), aml_local(2))); + aml_append(method, aml_name_decl("INPT", aml_buffer(8, NULL))); + field = aml_create_dword_field(aml_name("INPT"), + aml_int(0), "OFST"); + aml_append(method, field); + field = aml_create_dword_field(aml_name("INPT"), + aml_int(4), "TLEN"); + aml_append(method, field); + aml_append(method, aml_store(aml_arg(0), aml_name("OFST"))); + aml_append(method, aml_store(aml_arg(1), aml_name("TLEN"))); + + aml_append(method, aml_concatenate(aml_name("INPT"), aml_local(2), + aml_name("INPT"))); + pkg = aml_package(1); + aml_append(pkg, aml_name("INPT")); + aml_append(method, aml_store(pkg, aml_local(0))); + com_call = aml_call5(NVDIMM_COMMON_DSM, + aml_touuid(NVDIMM_DEVICE_DSM_UUID), + aml_int(1), aml_int(6), aml_local(0), + aml_int(handle)); + aml_append(method, aml_store(com_call, aml_local(3))); + field = aml_create_dword_field(aml_local(3), aml_int(0), "STTS"); + aml_append(method, field); + aml_append(method, aml_return(aml_name("STTS"))); + + aml_append(nvdimm_dev, method); + nvdimm_build_device_dsm(nvdimm_dev, handle); aml_append(root_dev, nvdimm_dev); } diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index bf65bbea4940..99a898d9ae63 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -186,14 +186,17 @@ static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel) static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev) { - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); DeviceClass *dc = DEVICE_GET_CLASS(dev); /* * ACPI doesn't allow hotplug of bridge devices. Don't allow * hot-unplug of bridge devices unless they were added by hotplug * (and so, not described by acpi). + * + * Don't allow hot-unplug of SR-IOV Virtual Functions, as they + * will be removed implicitly, when Physical Function is unplugged. */ - return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable; + return (IS_PCI_BRIDGE(dev) && !dev->qdev.hotplugged) || !dc->hotpluggable || + pci_is_vf(dev); } static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index fe5625d07a28..0a81f1ad93c0 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -28,6 +28,8 @@ #include "hw/pci/pci.h" #include "hw/qdev-properties.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/pcihp.h" +#include "hw/acpi/piix4.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "sysemu/xen.h" @@ -56,47 +58,6 @@ struct pci_status { uint32_t down; }; -struct PIIX4PMState { - /*< private >*/ - PCIDevice parent_obj; - /*< public >*/ - - MemoryRegion io; - uint32_t io_base; - - MemoryRegion io_gpe; - ACPIREGS ar; - - APMState apm; - - PMSMBus smb; - uint32_t smb_io_base; - - qemu_irq irq; - qemu_irq smi_irq; - int smm_enabled; - bool smm_compat; - Notifier machine_ready; - Notifier powerdown_notifier; - - AcpiPciHpState acpi_pci_hotplug; - bool use_acpi_hotplug_bridge; - bool use_acpi_root_pci_hotplug; - bool not_migrate_acpi_index; - - uint8_t disable_s3; - uint8_t disable_s4; - uint8_t s4_val; - - bool cpu_hotplug_legacy; - AcpiCpuHotplug gpe_cpu; - CPUHotplugState cpuhp_state; - - MemHotplugState acpi_memory_hotplug; -}; - -OBJECT_DECLARE_SIMPLE_TYPE(PIIX4PMState, PIIX4_PM) - static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, PCIBus *bus, PIIX4PMState *s); @@ -525,6 +486,10 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp) s->machine_ready.notify = piix4_pm_machine_ready; qemu_add_machine_init_done_notifier(&s->machine_ready); + if (xen_enabled()) { + s->use_acpi_hotplug_bridge = false; + } + piix4_acpi_system_hot_add_init(pci_address_space_io(dev), pci_get_bus(dev), s); qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s)); @@ -532,32 +497,12 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp) piix4_pm_add_properties(s); } -I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, - qemu_irq sci_irq, qemu_irq smi_irq, - int smm_enabled, DeviceState **piix4_pm) +static void piix4_pm_init(Object *obj) { - PCIDevice *pci_dev; - DeviceState *dev; - PIIX4PMState *s; - - pci_dev = pci_new(devfn, TYPE_PIIX4_PM); - dev = DEVICE(pci_dev); - qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base); - if (piix4_pm) { - *piix4_pm = dev; - } - - s = PIIX4_PM(dev); - s->irq = sci_irq; - s->smi_irq = smi_irq; - s->smm_enabled = smm_enabled; - if (xen_enabled()) { - s->use_acpi_hotplug_bridge = false; - } - - pci_realize_and_unref(pci_dev, bus, &error_fatal); + PIIX4PMState *s = PIIX4_PM(obj); - return s->smb.smbus; + qdev_init_gpio_out(DEVICE(obj), &s->irq, 1); + qdev_init_gpio_out_named(DEVICE(obj), &s->smi_irq, "smi-irq", 1); } static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) @@ -663,6 +608,7 @@ static Property piix4_pm_properties[] = { DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState, acpi_memory_hotplug.is_enabled, true), DEFINE_PROP_BOOL("smm-compat", PIIX4PMState, smm_compat, false), + DEFINE_PROP_BOOL("smm-enabled", PIIX4PMState, smm_enabled, false), DEFINE_PROP_BOOL("x-not-migrate-acpi-index", PIIX4PMState, not_migrate_acpi_index, false), DEFINE_PROP_END_OF_LIST(), @@ -703,6 +649,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) static const TypeInfo piix4_pm_info = { .name = TYPE_PIIX4_PM, .parent = TYPE_PCI_DEVICE, + .instance_init = piix4_pm_init, .instance_size = sizeof(PIIX4PMState), .class_init = piix4_pm_class_init, .interfaces = (InterfaceInfo[]) { diff --git a/hw/acpi/tco.c b/hw/acpi/tco.c deleted file mode 100644 index 4783721e4e74..000000000000 --- a/hw/acpi/tco.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * QEMU ICH9 TCO emulation - * - * Copyright (c) 2015 Paulo Alcantara - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "sysemu/watchdog.h" -#include "hw/i386/ich9.h" -#include "migration/vmstate.h" - -#include "hw/acpi/tco.h" -#include "trace.h" - -enum { - TCO_RLD_DEFAULT = 0x0000, - TCO_DAT_IN_DEFAULT = 0x00, - TCO_DAT_OUT_DEFAULT = 0x00, - TCO1_STS_DEFAULT = 0x0000, - TCO2_STS_DEFAULT = 0x0000, - TCO1_CNT_DEFAULT = 0x0000, - TCO2_CNT_DEFAULT = 0x0008, - TCO_MESSAGE1_DEFAULT = 0x00, - TCO_MESSAGE2_DEFAULT = 0x00, - TCO_WDCNT_DEFAULT = 0x00, - TCO_TMR_DEFAULT = 0x0004, - SW_IRQ_GEN_DEFAULT = 0x03, -}; - -static inline void tco_timer_reload(TCOIORegs *tr) -{ - int ticks = tr->tco.tmr & TCO_TMR_MASK; - int64_t nsec = (int64_t)ticks * TCO_TICK_NSEC; - - trace_tco_timer_reload(ticks, nsec / 1000000); - tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + nsec; - timer_mod(tr->tco_timer, tr->expire_time); -} - -static inline void tco_timer_stop(TCOIORegs *tr) -{ - tr->expire_time = -1; - timer_del(tr->tco_timer); -} - -static void tco_timer_expired(void *opaque) -{ - TCOIORegs *tr = opaque; - ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs); - ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm); - uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_CC_GCS); - - trace_tco_timer_expired(tr->timeouts_no, - lpc->pin_strap.spkr_hi, - !!(gcs & ICH9_CC_GCS_NO_REBOOT)); - tr->tco.rld = 0; - tr->tco.sts1 |= TCO_TIMEOUT; - if (++tr->timeouts_no == 2) { - tr->tco.sts2 |= TCO_SECOND_TO_STS; - tr->tco.sts2 |= TCO_BOOT_STS; - tr->timeouts_no = 0; - - if (!lpc->pin_strap.spkr_hi && !(gcs & ICH9_CC_GCS_NO_REBOOT)) { - watchdog_perform_action(); - tco_timer_stop(tr); - return; - } - } - - if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) { - ich9_generate_smi(); - } - tr->tco.rld = tr->tco.tmr; - tco_timer_reload(tr); -} - -/* NOTE: values of 0 or 1 will be ignored by ICH */ -static inline int can_start_tco_timer(TCOIORegs *tr) -{ - return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1; -} - -static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr) -{ - uint16_t rld; - - switch (addr) { - case TCO_RLD: - if (tr->expire_time != -1) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC; - rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK); - } else { - rld = tr->tco.rld; - } - return rld; - case TCO_DAT_IN: - return tr->tco.din; - case TCO_DAT_OUT: - return tr->tco.dout; - case TCO1_STS: - return tr->tco.sts1; - case TCO2_STS: - return tr->tco.sts2; - case TCO1_CNT: - return tr->tco.cnt1; - case TCO2_CNT: - return tr->tco.cnt2; - case TCO_MESSAGE1: - return tr->tco.msg1; - case TCO_MESSAGE2: - return tr->tco.msg2; - case TCO_WDCNT: - return tr->tco.wdcnt; - case TCO_TMR: - return tr->tco.tmr; - case SW_IRQ_GEN: - return tr->sw_irq_gen; - } - return 0; -} - -static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val) -{ - switch (addr) { - case TCO_RLD: - tr->timeouts_no = 0; - if (can_start_tco_timer(tr)) { - tr->tco.rld = tr->tco.tmr; - tco_timer_reload(tr); - } else { - tr->tco.rld = val; - } - break; - case TCO_DAT_IN: - tr->tco.din = val; - tr->tco.sts1 |= SW_TCO_SMI; - ich9_generate_smi(); - break; - case TCO_DAT_OUT: - tr->tco.dout = val; - tr->tco.sts1 |= TCO_INT_STS; - /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */ - break; - case TCO1_STS: - tr->tco.sts1 = val & TCO1_STS_MASK; - break; - case TCO2_STS: - tr->tco.sts2 = val & TCO2_STS_MASK; - break; - case TCO1_CNT: - val &= TCO1_CNT_MASK; - /* - * once TCO_LOCK bit is set, it can not be cleared by software. a reset - * is required to change this bit from 1 to 0 -- it defaults to 0. - */ - tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK); - if (can_start_tco_timer(tr)) { - tr->tco.rld = tr->tco.tmr; - tco_timer_reload(tr); - } else { - tco_timer_stop(tr); - } - break; - case TCO2_CNT: - tr->tco.cnt2 = val; - break; - case TCO_MESSAGE1: - tr->tco.msg1 = val; - break; - case TCO_MESSAGE2: - tr->tco.msg2 = val; - break; - case TCO_WDCNT: - tr->tco.wdcnt = val; - break; - case TCO_TMR: - tr->tco.tmr = val; - break; - case SW_IRQ_GEN: - tr->sw_irq_gen = val; - break; - } -} - -static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width) -{ - TCOIORegs *tr = opaque; - return tco_ioport_readw(tr, addr); -} - -static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - TCOIORegs *tr = opaque; - tco_ioport_writew(tr, addr, val); -} - -static const MemoryRegionOps tco_io_ops = { - .read = tco_io_readw, - .write = tco_io_writew, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .impl.min_access_size = 1, - .impl.max_access_size = 2, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent) -{ - *tr = (TCOIORegs) { - .tco = { - .rld = TCO_RLD_DEFAULT, - .din = TCO_DAT_IN_DEFAULT, - .dout = TCO_DAT_OUT_DEFAULT, - .sts1 = TCO1_STS_DEFAULT, - .sts2 = TCO2_STS_DEFAULT, - .cnt1 = TCO1_CNT_DEFAULT, - .cnt2 = TCO2_CNT_DEFAULT, - .msg1 = TCO_MESSAGE1_DEFAULT, - .msg2 = TCO_MESSAGE2_DEFAULT, - .wdcnt = TCO_WDCNT_DEFAULT, - .tmr = TCO_TMR_DEFAULT, - }, - .sw_irq_gen = SW_IRQ_GEN_DEFAULT, - .tco_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tco_timer_expired, tr), - .expire_time = -1, - .timeouts_no = 0, - }; - memory_region_init_io(&tr->io, memory_region_owner(parent), - &tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN); - memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io); -} - -const VMStateDescription vmstate_tco_io_sts = { - .name = "tco io device status", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT16(tco.rld, TCOIORegs), - VMSTATE_UINT8(tco.din, TCOIORegs), - VMSTATE_UINT8(tco.dout, TCOIORegs), - VMSTATE_UINT16(tco.sts1, TCOIORegs), - VMSTATE_UINT16(tco.sts2, TCOIORegs), - VMSTATE_UINT16(tco.cnt1, TCOIORegs), - VMSTATE_UINT16(tco.cnt2, TCOIORegs), - VMSTATE_UINT8(tco.msg1, TCOIORegs), - VMSTATE_UINT8(tco.msg2, TCOIORegs), - VMSTATE_UINT8(tco.wdcnt, TCOIORegs), - VMSTATE_UINT16(tco.tmr, TCOIORegs), - VMSTATE_UINT8(sw_irq_gen, TCOIORegs), - VMSTATE_TIMER_PTR(tco_timer, TCOIORegs), - VMSTATE_INT64(expire_time, TCOIORegs), - VMSTATE_UINT8(timeouts_no, TCOIORegs), - VMSTATE_END_OF_LIST() - } -}; diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events index 2250126a22b2..78e0a8670e9b 100644 --- a/hw/acpi/trace-events +++ b/hw/acpi/trace-events @@ -55,6 +55,8 @@ piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 # tco.c tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)" tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d" +tco_io_write(uint64_t addr, uint32_t val) "addr=0x%" PRIx64 " val=0x%" PRIx32 +tco_io_read(uint64_t addr, uint32_t val) "addr=0x%" PRIx64 " val=0x%" PRIx32 # erst.c acpi_erst_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%04" PRIx64 " <== 0x%016" PRIx64 " (size: %u)" @@ -70,3 +72,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/acpi/viot.c b/hw/acpi/viot.c index c1af75206e50..4e0bf6906738 100644 --- a/hw/acpi/viot.c +++ b/hw/acpi/viot.c @@ -10,17 +10,40 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" -struct viot_pci_ranges { - GArray *blob; - size_t count; - uint16_t output_node; +struct viot_pci_host_range { + int min_bus; + int max_bus; }; +static void build_pci_host_range(GArray *table_data, int min_bus, int max_bus, + uint16_t output_node) +{ + /* Type */ + build_append_int_noprefix(table_data, 1 /* PCI range */, 1); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + /* Length */ + build_append_int_noprefix(table_data, 24, 2); + /* Endpoint start */ + build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 4); + /* PCI Segment start */ + build_append_int_noprefix(table_data, 0, 2); + /* PCI Segment end */ + build_append_int_noprefix(table_data, 0, 2); + /* PCI BDF start */ + build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 2); + /* PCI BDF end */ + build_append_int_noprefix(table_data, PCI_BUILD_BDF(max_bus, 0xff), 2); + /* Output node */ + build_append_int_noprefix(table_data, output_node, 2); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 6); +} + /* Build PCI range for a given PCI host bridge */ -static int build_pci_range_node(Object *obj, void *opaque) +static int enumerate_pci_host_bridges(Object *obj, void *opaque) { - struct viot_pci_ranges *pci_ranges = opaque; - GArray *blob = pci_ranges->blob; + GArray *pci_host_ranges = opaque; if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; @@ -30,34 +53,31 @@ static int build_pci_range_node(Object *obj, void *opaque) pci_bus_range(bus, &min_bus, &max_bus); - /* Type */ - build_append_int_noprefix(blob, 1 /* PCI range */, 1); - /* Reserved */ - build_append_int_noprefix(blob, 0, 1); - /* Length */ - build_append_int_noprefix(blob, 24, 2); - /* Endpoint start */ - build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 4); - /* PCI Segment start */ - build_append_int_noprefix(blob, 0, 2); - /* PCI Segment end */ - build_append_int_noprefix(blob, 0, 2); - /* PCI BDF start */ - build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 2); - /* PCI BDF end */ - build_append_int_noprefix(blob, PCI_BUILD_BDF(max_bus, 0xff), 2); - /* Output node */ - build_append_int_noprefix(blob, pci_ranges->output_node, 2); - /* Reserved */ - build_append_int_noprefix(blob, 0, 6); - - pci_ranges->count++; + const struct viot_pci_host_range pci_host_range = { + .min_bus = min_bus, + .max_bus = max_bus, + }; + g_array_append_val(pci_host_ranges, pci_host_range); } } return 0; } +static gint pci_host_range_compare(gconstpointer a, gconstpointer b) +{ + struct viot_pci_host_range *range_a = (struct viot_pci_host_range *)a; + struct viot_pci_host_range *range_b = (struct viot_pci_host_range *)b; + + if (range_a->min_bus < range_b->min_bus) { + return -1; + } else if (range_a->min_bus > range_b->min_bus) { + return 1; + } else { + return 0; + } +} + /* * Generate a VIOT table with one PCI-based virtio-iommu that manages PCI * endpoints. @@ -72,19 +92,22 @@ void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker, int viommu_off = 48; AcpiTable table = { .sig = "VIOT", .rev = 0, .oem_id = oem_id, .oem_table_id = oem_table_id }; - struct viot_pci_ranges pci_ranges = { - .output_node = viommu_off, - .blob = g_array_new(false, true /* clear */, 1), - }; + GArray *pci_host_ranges = g_array_new(false, true, + sizeof(struct viot_pci_host_range)); + struct viot_pci_host_range *pci_host_range; + int i; /* Build the list of PCI ranges that this viommu manages */ - object_child_foreach_recursive(OBJECT(ms), build_pci_range_node, - &pci_ranges); + object_child_foreach_recursive(OBJECT(ms), enumerate_pci_host_bridges, + pci_host_ranges); + + /* Sort the pci host ranges by min_bus */ + g_array_sort(pci_host_ranges, pci_host_range_compare); /* ACPI table header */ acpi_table_begin(&table, table_data); /* Node count */ - build_append_int_noprefix(table_data, pci_ranges.count + 1, 2); + build_append_int_noprefix(table_data, pci_host_ranges->len + 1, 2); /* Node offset */ build_append_int_noprefix(table_data, viommu_off, 2); /* Reserved */ @@ -105,9 +128,15 @@ void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker, build_append_int_noprefix(table_data, 0, 8); /* PCI ranges found above */ - g_array_append_vals(table_data, pci_ranges.blob->data, - pci_ranges.blob->len); - g_array_free(pci_ranges.blob, true); + for (i = 0; i < pci_host_ranges->len; i++) { + pci_host_range = &g_array_index(pci_host_ranges, + struct viot_pci_host_range, i); + + build_pci_host_range(table_data, pci_host_range->min_bus, + pci_host_range->max_bus, viommu_off); + } + + g_array_free(pci_host_ranges, true); acpi_table_end(linker, &table); } diff --git a/hw/adc/Kconfig b/hw/adc/Kconfig index a825bd3d343d..d9c3abdff82c 100644 --- a/hw/adc/Kconfig +++ b/hw/adc/Kconfig @@ -3,3 +3,6 @@ config STM32F2XX_ADC config MAX111X bool + +config RT_LPADC + bool diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c index c5fcae29f635..0d2966312954 100644 --- a/hw/adc/aspeed_adc.c +++ b/hw/adc/aspeed_adc.c @@ -389,6 +389,15 @@ static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data) aac->nr_engines = 2; } +static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); + + dc->desc = "ASPEED 1030 ADC Controller"; + aac->nr_engines = 2; +} + static const TypeInfo aspeed_adc_info = { .name = TYPE_ASPEED_ADC, .parent = TYPE_SYS_BUS_DEVICE, @@ -415,6 +424,12 @@ static const TypeInfo aspeed_2600_adc_info = { .class_init = aspeed_2600_adc_class_init, }; +static const TypeInfo aspeed_1030_adc_info = { + .name = TYPE_ASPEED_1030_ADC, + .parent = TYPE_ASPEED_ADC, + .class_init = aspeed_1030_adc_class_init, /* No change since AST2600 */ +}; + static void aspeed_adc_register_types(void) { type_register_static(&aspeed_adc_engine_info); @@ -422,6 +437,7 @@ static void aspeed_adc_register_types(void) type_register_static(&aspeed_2400_adc_info); type_register_static(&aspeed_2500_adc_info); type_register_static(&aspeed_2600_adc_info); + type_register_static(&aspeed_1030_adc_info); } type_init(aspeed_adc_register_types); diff --git a/hw/adc/meson.build b/hw/adc/meson.build index b29ac7ccdf53..4f356a409c60 100644 --- a/hw/adc/meson.build +++ b/hw/adc/meson.build @@ -3,3 +3,4 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_adc.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq-xadc.c')) softmmu_ss.add(when: 'CONFIG_MAX111X', if_true: files('max111x.c')) +softmmu_ss.add(when: 'CONFIG_RT_LPADC', if_true: files('rt_lpadc.c')) diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c index 0f0a9f63e206..bc6f3f55e643 100644 --- a/hw/adc/npcm7xx_adc.c +++ b/hw/adc/npcm7xx_adc.c @@ -36,7 +36,7 @@ REG32(NPCM7XX_ADC_DATA, 0x4) #define NPCM7XX_ADC_CON_INT BIT(18) #define NPCM7XX_ADC_CON_EN BIT(17) #define NPCM7XX_ADC_CON_RST BIT(16) -#define NPCM7XX_ADC_CON_CONV BIT(14) +#define NPCM7XX_ADC_CON_CONV BIT(13) #define NPCM7XX_ADC_CON_DIV(rv) extract32(rv, 1, 8) #define NPCM7XX_ADC_MAX_RESULT 1023 @@ -242,7 +242,7 @@ static void npcm7xx_adc_init(Object *obj) for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) { object_property_add_uint32_ptr(obj, "adci[*]", - &s->adci[i], OBJ_PROP_FLAG_WRITE); + &s->adci[i], OBJ_PROP_FLAG_READWRITE); } object_property_add_uint32_ptr(obj, "vref", &s->vref, OBJ_PROP_FLAG_WRITE); diff --git a/hw/adc/rt_lpadc.c b/hw/adc/rt_lpadc.c new file mode 100644 index 000000000000..c2d2dd2206c5 --- /dev/null +++ b/hw/adc/rt_lpadc.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" +#include "qemu/dma_notifier.h" +#include "qemu/fifo32.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qemu/typedefs.h" +#include "hw/irq.h" +#include "hw/adc/rt_lpadc.h" + +#ifndef RT_LPADC_ERR_DEBUG +#define RT_LPADC_ERR_DEBUG 0 +#endif + +#define DB_PRINT_L(lvl, fmt, args...) do { \ + if (RT_LPADC_ERR_DEBUG >= lvl) { \ + qemu_log("%s: " fmt, __func__, ## args); \ + } \ +} while (0) + +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) + + +static void rt_lpadc_reset(DeviceState *dev) +{ + RTLPADCState *s = RT_LPADC(dev); + int i = 0; + + s->VERID = 0x0200201A; + s->PARAM = 0x0F041010; + s->CTRL = 0x00000000; + s->STAT = 0x00000000; + s->IE = 0x00000000; + s->DE = 0x00000000; + s->CFG = 0x00800000; + s->PAUSE = 0x00000000; + s->SWTRIG = 0x00000000; + s->TSTAT = 0x00000000; + for (i = 0; i < 16; i++) { + s->TCTRL[i] = 0x00000000; + } + s->FCTRL[0] = 0x00000000; + s->FCTRL[1] = 0x00000000; + for (i = 0; i < ADC_COMMAND_BUF_NUM; i++) { + s->CMDL[i] = 0x00002000; + s->CMDH[i] = 0x00000000; + } + for (i = 0; i < ADC_CMP_VALUE_NUM; i++) { + s->CV[i] = 0x00000000; + } + fifo32_reset(&s->RESFIFO[0]); + fifo32_reset(&s->RESFIFO[1]); +} + +static void rt_lpadc_run_cmds(RTLPADCState *s, uint32_t ch) +{ + uint32_t status = s->STAT; + uint32_t next = ch; + + status = (status & (~CMDACT_MASK)) | (ch<STAT = status | ADC_ACTIVE_MASK; + + while(next != 0) + { + uint32_t fifo_sel = FROM_REG(s->TCTRL[next], FIFO_SEL_A); + uint32_t cmdsrc = FROM_REG(s->TCTRL[next], TCMD); + uint32_t data = 0x8000FFFF; /* faked value in low 16 bits*/ + + data = TO_REG(data, CMDSRC, cmdsrc); + data = TO_REG(data, TSRC, next); + fifo32_push(&s->RESFIFO[fifo_sel], data); + next = FROM_REG(s->CMDH[next], NEXT); + if (s->PAUSE & PAUSEEN_MASK) { + uint32_t delay = s->PAUSE & PAUSEDLY_MASK; + if (delay > 0) { + while(delay--); + } + } + } + + s->STAT &= (~ADC_ACTIVE_MASK) & (~CMDACT_MASK); +} + +static void rt_lpadc_update_state(void *opaque) +{ + RTLPADCState *s = RT_LPADC(opaque); + + if ((s->CTRL & ADCEN_MASK) != ADCEN_MASK) { + s->state = eLPADC_Stop; + } else { + s->state = eLPADC_Run; + } + + if ((s->CTRL & DOZEN_MASK) == DOZEN_MASK) { + s->state = eLPADC_Dozen; + } + + if (s->DE & FWMDE1_MASK) { + uint32_t rdy = FROM_REG(s->STAT, RDY1); + if (rdy){ + dma_trigger_notify(&s->dma_trigger_nr); + } + } + if (s->DE & FWMDE0_MASK) { + uint32_t rdy = FROM_REG(s->STAT, RDY0); + + if (rdy){ + dma_trigger_notify(&s->dma_trigger_nr); + } + } + +} + +static void rt_lpadc_timer_event_fsm_cb(void *opaque) +{ + RTLPADCState *s = RT_LPADC(opaque); + + switch(s->state) { + case eLPADC_Run: + break; + case eLPADC_Stop: + break; + case eLPADC_Dozen: + break; + default: + break; + } + + rt_lpadc_update_state(s); +} + + +static void rt_lpadc_realize(DeviceState *dev, Error **errp) +{ + RTLPADCState *s = RT_LPADC(dev); + + fifo32_create(&s->RESFIFO[0], RESFIFO_SIZE); + fifo32_create(&s->RESFIFO[1], RESFIFO_SIZE); + + s->timer_interval = 2; /* every 2 ms*/ + s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, rt_lpadc_timer_event_fsm_cb, s); + int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + + timer_mod(s->timer, now + s->timer_interval); + + s->state = eLPADC_Stop; +} + + +static void rt_lpadc_unrealize(DeviceState *dev) +{ + RTLPADCState *s = RT_LPADC(dev); + + fifo32_destroy(&s->RESFIFO[0]); + fifo32_destroy(&s->RESFIFO[1]); + + if(s->timer) { + timer_del(s->timer); + s->timer = NULL; + } +} + +static uint64_t rt_lpadc_read(void *opaque, hwaddr offset, + unsigned int size) +{ + RTLPADCState *s = opaque; + uint32_t value = 0; + + DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", offset); + + switch (offset) { + case 0x0: + value = s->VERID; + break; + case 0x4: + value = s->PARAM; + break; + case 0x10: + value = s->CTRL; + break; + case 0x14: + break; + case 0x18: + value = s->IE; + break; + case 0x1C: + value = s->DE; + break; + case 0x20: + value = s->CFG; + break; + case 0x24: + value = s->PAUSE; + break; + case 0x34: + value = 0; + break; + case 0x38: + break; + case 0xA0 ... 0xDC: + value = s->TCTRL[(offset - 0xA0) / 4]; + break; + case 0xE0: + value = s->FCTRL[0]; + break; + case 0xE4: + value = s->FCTRL[1]; + break; + case 0x100 ... 0x174: + { + int reg_id = (offset - 0x100) / 4; + if ((reg_id % 2) == 0) { + int idx = reg_id>>1; + value = s->CMDL[idx]; + } else { + int idx = (reg_id + 1)>>1; + value = s->CMDH[idx]; + } + } + break; + case 0x200 ... 0x20C: + value = s->CV[(offset - 0x200)/4]; + break; + case 0x300 ... 0x304: + { + int reg_id = (offset - 0x300)/4; + if (!fifo32_is_empty(&s->RESFIFO[reg_id])) + { + value = fifo32_pop(&s->RESFIFO[reg_id]); + s->FCTRL[reg_id] |= fifo32_num_used(&s->RESFIFO[reg_id]); + } + } + break; + } + + return value; +} + +static void rt_lpadc_ctrl_reg_cb(void *opaque) +{ + RTLPADCState *s = opaque; + + if (s->CTRL & RSTFIFO0_MASK) { + fifo32_reset(&s->RESFIFO[0]); + } + + if (s->CTRL & RSTFIFO1_MASK) { + fifo32_reset(&s->RESFIFO[1]); + } + + if (s->CTRL & RST_MASK) { + uint32_t temp_r = s->CTRL; + rt_lpadc_reset(DEVICE(s)); + s->CTRL |= temp_r; + } + + if (s->CTRL & ADCEN_MASK) { + s->state = eLPADC_Run; + } +} + +static void rt_lpadc_status_cb(void *opaque) +{ + RTLPADCState *s = opaque; + int raise_irq = 0; + uint32_t count = 0; + + + if (fifo32_is_full(&s->RESFIFO[0])) { + s->STAT |= FOF0_MASK; + if (s->IE & FOF0_MASK) + { + raise_irq = 1; + } + } + + if (fifo32_is_full(&s->RESFIFO[1])) { + s->STAT |= FOF1_MASK; + if (s->IE & FOF1_MASK) + { + raise_irq = 1; + } + } + + count = fifo32_num_used(&s->RESFIFO[0]); + if (count > (s->FCTRL[0]>>FWMARK_OFFSET)) + { + if (s->IE & FWMIE0_MASK) + { + raise_irq = 1; + } + } + + count = fifo32_num_used(&s->RESFIFO[1]); + if (count > (s->FCTRL[1]>>FWMARK_OFFSET)) + { + if (s->IE & FWMIE1_MASK) + { + raise_irq = 1; + } + + } + + qemu_set_irq(s->irq, raise_irq); +} + +static void lp_adc_swtrigger(void *opaque) +{ + RTLPADCState *s = opaque; + uint32_t ids = s->SWTRIG; + int i = 0; + + for (i = 0; i < TST_REG_NUM; i++) { + if (ids && (ids&(1<STAT; + status = status & (~TRGACT_MASK); + status = status | (i<STAT = status; + rt_lpadc_run_cmds(s, i); + ids &= ~(1<STAT &= (~TRGACT_MASK); + s->STAT |= TCOMP_INT_MASK; + } + } +} + +static void rt_lpadc_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned int size) +{ + RTLPADCState *s = opaque; + uint32_t value = (uint32_t) val64; + + DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", + offset, value); + + switch (offset) { + case 0x0: + /* RO */ + break; + case 0x4: + /* RO */ + break; + case 0x10: + s->CTRL = value; + rt_lpadc_ctrl_reg_cb(s); + break; + case 0x14: + s->STAT &= (~value); + break; + case 0x18: + s->IE = value; + break; + case 0x1C: + s->DE = value; + break; + case 0x20: + s->CFG = value; + break; + case 0x24: + s->PAUSE = value; + break; + case 0x34: + s->SWTRIG = value; + lp_adc_swtrigger(s); + break; + case 0x38: + s->TSTAT &= (~value); + break; + case 0xA0 ... 0xDC: + s->TCTRL[(offset - 0xa0)/4] = value; + break; + case 0xE0: + s->FCTRL[0] = value & FWMARK_MASK; + break; + case 0xE4: + s->FCTRL[1] = value & FWMARK_MASK; + break; + case 0x100 ... 0x174: + { + int reg_id = (offset - 0x100) / 4; + if ((reg_id % 2) == 0) { + int idx = reg_id>>1; + s->CMDL[idx] = value; + } else { + int idx = (reg_id + 1)>>1; + s->CMDH[idx] = value; + } + } + break; + case 0x200 ... 0x20C: + s->CV[(offset - 0x200)/4] = value; + break; + case 0x300 ... 0x304: + /* RO */ + break; + default: + break; + } + rt_lpadc_status_cb(s); +} + +static Property rt_lpadc_properties[] = { + DEFINE_PROP_UINT32("dma_hw_trigger_nr", RTLPADCState, dma_trigger_nr, 24), + DEFINE_PROP_END_OF_LIST(), +}; + +static const MemoryRegionOps rt_lpadc_ops = { + .read = rt_lpadc_read, + .write = rt_lpadc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_rt_lpadc = { + .name = TYPE_RT_LPADC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(VERID, RTLPADCState), + VMSTATE_UINT32(PARAM, RTLPADCState), + VMSTATE_UINT32(CTRL, RTLPADCState), + VMSTATE_UINT32(STAT, RTLPADCState), + VMSTATE_UINT32(IE, RTLPADCState), + VMSTATE_UINT32(DE, RTLPADCState), + VMSTATE_UINT32(CFG, RTLPADCState), + VMSTATE_UINT32(PAUSE, RTLPADCState), + VMSTATE_UINT32(SWTRIG, RTLPADCState), + VMSTATE_UINT32(TSTAT, RTLPADCState), + VMSTATE_UINT32_ARRAY(TCTRL, RTLPADCState, TST_REG_NUM), + VMSTATE_UINT32_ARRAY(FCTRL, RTLPADCState, FIFO_CTL_NUM), + VMSTATE_UINT32_ARRAY(CMDL, RTLPADCState, ADC_COMMAND_BUF_NUM), + VMSTATE_UINT32_ARRAY(CMDH, RTLPADCState, ADC_COMMAND_BUF_NUM), + VMSTATE_UINT32_ARRAY(CV, RTLPADCState, ADC_CMP_VALUE_NUM), + VMSTATE_STRUCT_ARRAY(RESFIFO, RTLPADCState, FIFO_CTL_NUM, 1, vmstate_fifo8, Fifo32), + VMSTATE_UINT32(timer_interval, RTLPADCState), + VMSTATE_TIMER_PTR(timer, RTLPADCState), + VMSTATE_UINT32(state, RTLPADCState), + VMSTATE_UINT32(dma_trigger_nr, RTLPADCState), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_lpadc_init(Object *obj) +{ + RTLPADCState *s = RT_LPADC(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->mmio, obj, &rt_lpadc_ops, s, + TYPE_RT_LPADC, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void rt_lpadc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = rt_lpadc_reset; + dc->vmsd = &vmstate_rt_lpadc; + dc->realize = rt_lpadc_realize; + dc->unrealize = rt_lpadc_unrealize; + dc->user_creatable = true; + dc->hotpluggable = true; + + device_class_set_props(dc, rt_lpadc_properties); +} + +static const TypeInfo rt_lpadc_info = { + .name = TYPE_RT_LPADC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTLPADCState), + .instance_init = rt_lpadc_init, + .class_init = rt_lpadc_class_init, +}; + +static void rt_lpadc_register_types(void) +{ + type_register_static(&rt_lpadc_info); +} + +type_init(rt_lpadc_register_types) diff --git a/hw/adc/zynq-xadc.c b/hw/adc/zynq-xadc.c index cfc7bab06515..032e19cbd0af 100644 --- a/hw/adc/zynq-xadc.c +++ b/hw/adc/zynq-xadc.c @@ -86,7 +86,7 @@ static void zynq_xadc_update_ints(ZynqXADCState *s) s->regs[INT_STS] |= INT_DFIFO_GTH; } - qemu_set_irq(s->qemu_irq, !!(s->regs[INT_STS] & ~s->regs[INT_MASK])); + qemu_set_irq(s->irq, !!(s->regs[INT_STS] & ~s->regs[INT_MASK])); } static void zynq_xadc_reset(DeviceState *d) @@ -262,7 +262,7 @@ static void zynq_xadc_init(Object *obj) memory_region_init_io(&s->iomem, obj, &xadc_ops, s, "zynq-xadc", ZYNQ_XADC_MMIO_SIZE); sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->qemu_irq); + sysbus_init_irq(sbd, &s->irq); } static const VMStateDescription vmstate_zynq_xadc = { diff --git a/hw/alpha/alpha_sys.h b/hw/alpha/alpha_sys.h index 2263e821da54..a303c5843831 100644 --- a/hw/alpha/alpha_sys.h +++ b/hw/alpha/alpha_sys.h @@ -5,7 +5,6 @@ #include "target/alpha/cpu-qom.h" #include "hw/pci/pci.h" -#include "hw/pci/pci_host.h" #include "hw/boards.h" #include "hw/intc/i8259.h" diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index c78ed96d0eca..c502c8c62ae6 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -7,7 +7,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "elf.h" #include "hw/loader.h" @@ -21,8 +20,6 @@ #include "qemu/datadir.h" #include "net/net.h" -#define MAX_IDE_BUS 2 - static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) { if (((addr >> 41) & 3) == 2) { diff --git a/hw/alpha/pci.c b/hw/alpha/pci.c index 72251fcdf004..7c18297177b4 100644 --- a/hw/alpha/pci.c +++ b/hw/alpha/pci.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "hw/pci/pci_host.h" #include "alpha_sys.h" #include "qemu/log.h" #include "trace.h" diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index bd39c8ca8621..49a80550c54d 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -10,10 +10,10 @@ #include "qemu/module.h" #include "qemu/units.h" #include "qapi/error.h" +#include "hw/pci/pci_host.h" #include "cpu.h" #include "hw/irq.h" #include "alpha_sys.h" -#include "qom/object.h" #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 97f3b38019e9..44b2a8826684 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -29,6 +29,8 @@ config ARM_VIRT select ACPI_APEI select ACPI_VIOT select VIRTIO_MEM_SUPPORTED + select ACPI_CXL + select ACPI_HMAT config CHEETAH bool @@ -117,6 +119,10 @@ config NETDUINOPLUS2 bool select STM32F405_SOC +config OLIMEX_STM32_H405 + bool + select STM32F405_SOC + config NSERIES bool select OMAP @@ -317,7 +323,11 @@ config ALLWINNER_A10 select AHCI select ALLWINNER_A10_PIT select ALLWINNER_A10_PIC + select ALLWINNER_A10_CCM + select ALLWINNER_A10_DRAMC select ALLWINNER_EMAC + select ALLWINNER_I2C + select AXP209_PMU select SERIAL select UNIMP @@ -325,6 +335,7 @@ config ALLWINNER_H3 bool select ALLWINNER_A10_PIT select ALLWINNER_SUN8I_EMAC + select ALLWINNER_I2C select SERIAL select ARM_TIMER select ARM_GIC @@ -454,6 +465,8 @@ config ASPEED_SOC select EMC141X select UNIMP select LED + select PMBUS + select MAX31785 config MPS2 bool @@ -564,3 +577,26 @@ config ARMSSE select UNIMP select SSE_COUNTER select SSE_TIMER + +config NXP_RT595 + bool + select ARM_V7M + select ARM_GIC + select ARM_SMMUV3 + select PLATFORM_BUS + select MEM_DEVICE + select RT_SYSCTL + select RT_RSTCTL + select RT_CLKCTL + select RT_PMC + select RT_FLEXSPI + select RT_FLEXCOMM + select RT_FLEXCOMM_I2C + select RT_LPADC + select RT_OSTIMER + select FXOS8700 + select PCA9420 + select DBUS_CLIENT + select SDHCI + select RT_PMC + select RT_PINT diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 05e84728cb34..dc1966ff7a23 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -24,8 +24,12 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/usb/hcd-ohci.h" +#include "hw/loader.h" +#define AW_A10_SRAM_A_BASE 0x00000000 +#define AW_A10_DRAMC_BASE 0x01c01000 #define AW_A10_MMC0_BASE 0x01c0f000 +#define AW_A10_CCM_BASE 0x01c20000 #define AW_A10_PIC_REG_BASE 0x01c20400 #define AW_A10_PIT_REG_BASE 0x01c20c00 #define AW_A10_UART0_REG_BASE 0x01c28000 @@ -34,6 +38,23 @@ #define AW_A10_OHCI_BASE 0x01c14400 #define AW_A10_SATA_BASE 0x01c18000 #define AW_A10_RTC_BASE 0x01c20d00 +#define AW_A10_I2C0_BASE 0x01c2ac00 + +void allwinner_a10_bootrom_setup(AwA10State *s, BlockBackend *blk) +{ + const int64_t rom_size = 32 * KiB; + g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size); + + if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) { + error_setg(&error_fatal, "%s: failed to read BlockBackend data", + __func__); + return; + } + + rom_add_blob("allwinner-a10.bootrom", buffer, rom_size, + rom_size, AW_A10_SRAM_A_BASE, + NULL, NULL, NULL, NULL, false); +} static void aw_a10_init(Object *obj) { @@ -46,10 +67,16 @@ static void aw_a10_init(Object *obj) object_initialize_child(obj, "timer", &s->timer, TYPE_AW_A10_PIT); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_AW_A10_CCM); + + object_initialize_child(obj, "dramc", &s->dramc, TYPE_AW_A10_DRAMC); + object_initialize_child(obj, "emac", &s->emac, TYPE_AW_EMAC); object_initialize_child(obj, "sata", &s->sata, TYPE_ALLWINNER_AHCI); + object_initialize_child(obj, "i2c0", &s->i2c0, TYPE_AW_I2C); + if (machine_usb(current_machine)) { int i; @@ -103,6 +130,14 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), 0x00000000, &s->sram_a); create_unimplemented_device("a10-sram-ctrl", 0x01c00000, 4 * KiB); + /* Clock Control Module */ + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, AW_A10_CCM_BASE); + + /* DRAM Control Module */ + sysbus_realize(SYS_BUS_DEVICE(&s->dramc), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 0, AW_A10_DRAMC_BASE); + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); @@ -130,9 +165,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) int i; for (i = 0; i < AW_A10_NUM_USB; i++) { - char bus[16]; - - sprintf(bus, "usb-bus.%d", i); + g_autofree char *bus = g_strdup_printf("usb-bus.%d", i); object_property_set_bool(OBJECT(&s->ehci[i]), "companion-enable", true, &error_fatal); @@ -164,6 +197,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) /* RTC */ sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->rtc), 0, AW_A10_RTC_BASE, 10); + + /* I2C */ + sysbus_realize(SYS_BUS_DEVICE(&s->i2c0), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, AW_A10_I2C0_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0, qdev_get_gpio_in(dev, 7)); } static void aw_a10_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 318ed4348c78..bfce3c8d92af 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -53,6 +53,7 @@ const hwaddr allwinner_h3_memmap[] = { [AW_H3_DEV_UART1] = 0x01c28400, [AW_H3_DEV_UART2] = 0x01c28800, [AW_H3_DEV_UART3] = 0x01c28c00, + [AW_H3_DEV_TWI0] = 0x01c2ac00, [AW_H3_DEV_EMAC] = 0x01c30000, [AW_H3_DEV_DRAMCOM] = 0x01c62000, [AW_H3_DEV_DRAMCTL] = 0x01c63000, @@ -106,7 +107,6 @@ struct AwH3Unimplemented { { "uart1", 0x01c28400, 1 * KiB }, { "uart2", 0x01c28800, 1 * KiB }, { "uart3", 0x01c28c00, 1 * KiB }, - { "twi0", 0x01c2ac00, 1 * KiB }, { "twi1", 0x01c2b000, 1 * KiB }, { "twi2", 0x01c2b400, 1 * KiB }, { "scr", 0x01c2c400, 1 * KiB }, @@ -150,6 +150,7 @@ enum { AW_H3_GIC_SPI_UART1 = 1, AW_H3_GIC_SPI_UART2 = 2, AW_H3_GIC_SPI_UART3 = 3, + AW_H3_GIC_SPI_TWI0 = 6, AW_H3_GIC_SPI_TIMER0 = 18, AW_H3_GIC_SPI_TIMER1 = 19, AW_H3_GIC_SPI_MMC0 = 60, @@ -174,7 +175,7 @@ void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk) const int64_t rom_size = 32 * KiB; g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size); - if (blk_pread(blk, 8 * KiB, buffer, rom_size) < 0) { + if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) { error_setg(&error_fatal, "%s: failed to read BlockBackend data", __func__); return; @@ -225,6 +226,8 @@ static void allwinner_h3_init(Object *obj) "ram-size"); object_initialize_child(obj, "rtc", &s->rtc, TYPE_AW_RTC_SUN6I); + + object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C); } static void allwinner_h3_realize(DeviceState *dev, Error **errp) @@ -423,6 +426,12 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, s->memmap[AW_H3_DEV_RTC]); + /* I2C */ + sysbus_realize(SYS_BUS_DEVICE(&s->i2c0), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, s->memmap[AW_H3_DEV_TWI0]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0, + qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TWI0)); + /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(unimplemented); i++) { create_unimplemented_device(unimplemented[i].device_name, diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index aecdeb9815a9..aa9d188145b9 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -88,6 +88,18 @@ static Property iotkit_properties[] = { DEFINE_PROP_END_OF_LIST() }; + +static Property rt500_m33_properties[] = { + DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 74), + DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15), + DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), + DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true), + DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true), + DEFINE_PROP_END_OF_LIST() +}; + static Property sse200_properties[] = { DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, MemoryRegion *), @@ -196,6 +208,68 @@ static const ARMSSEDeviceInfo iotkit_devices[] = { } }; + +static const ARMSSEDeviceInfo rt595_m33_devices[] ={ + { + .name = "CACHE_Control_0", + .type = TYPE_UNIMPLEMENTED_DEVICE, + .index = 0, + .addr = 0x40033000, + .size = 0x1000, + .ppc = NO_PPC, + .irq = NO_IRQ, + }, + { + .name = "CACHE_Control_1", + .type = TYPE_UNIMPLEMENTED_DEVICE, + .index = 1, + .addr = 0x40034000, + .size = 0x1000, + .ppc = NO_PPC, + .irq = NO_IRQ, + }, + { + .name = "IOPCTL", + .type = TYPE_UNIMPLEMENTED_DEVICE, + .index = 2, + .addr = 0x40004000, + .size = 0x1000, + .ppc = NO_PPC, + .irq = NO_IRQ, + }, + { + .name = "PERIPHERAL_MUXES", + .type = TYPE_UNIMPLEMENTED_DEVICE, + .index = 3, + .addr = 0x40026000, + .size = 0x1000, + .ppc = NO_PPC, + .irq = NO_IRQ, + }, + { + .name = "HS_GPIO", + .type = TYPE_UNIMPLEMENTED_DEVICE, + .index = 4, + .addr = 0x40100000, + .size = 0x3000, + .ppc = NO_PPC, + .irq = NO_IRQ, + }, + { + .name = "SEC_HS_GPIO", + .type = TYPE_UNIMPLEMENTED_DEVICE, + .index = 5, + .addr = 0x40204000, + .size = 0x3000, + .ppc = NO_PPC, + .irq = NO_IRQ, + }, + { + .name = NULL, + } +}; + + static const ARMSSEDeviceInfo sse200_devices[] = { { .name = "timer0", @@ -565,6 +639,27 @@ static const ARMSSEInfo armsse_variants[] = { .devinfo = sse300_devices, .irq_is_common = sse300_irq_is_common, }, + { + .name = TYPE_RT500_M33, + .sse_version = ARMSSE_IOTKIT, + .cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"), + .sram_banks = 1, + .sram_bank_base = 0x22000000, + .num_cpus = 1, + .sys_version = 0x41743, + .iidr = 0, + .cpuwait_rst = 0, + .has_mhus = false, + .has_cachectrl = true, + .has_cpusecctrl = true, + .has_cpuid = true, + .has_cpu_pwrctrl = true, + .has_sse_counter = false, + .has_tcms = false, + .props = rt500_m33_properties, + .devinfo = rt595_m33_devices, + .irq_is_common = sse200_irq_is_common, + }, }; static uint32_t armsse_sys_config_value(ARMSSE *s, const ARMSSEInfo *info) @@ -900,6 +995,7 @@ static qemu_irq armsse_get_common_irq_in(ARMSSE *s, int irqno) static void armsse_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); ARMSSE *s = ARM_SSE(dev); ARMSSEClass *asc = ARM_SSE_GET_CLASS(dev); const ARMSSEInfo *info = asc->info; @@ -914,8 +1010,6 @@ static void armsse_realize(DeviceState *dev, Error **errp) DeviceState *dev_splitter; uint32_t addr_width_max; - ERRP_GUARD(); - if (!s->board_memory) { error_setg(errp, "memory property was not set"); return; diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 41cfca0f2236..50a9507c0bde 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) { - int image_size; + ssize_t image_size; uint64_t entry; - int big_endian; AddressSpace *as; int asidx; CPUState *cs = CPU(cpu); -#ifdef TARGET_WORDS_BIGENDIAN - 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 d205384d986f..55f114ef729f 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -21,9 +21,12 @@ #include "hw/misc/led.h" #include "hw/qdev-properties.h" #include "sysemu/block-backend.h" +#include "sysemu/reset.h" #include "hw/loader.h" #include "qemu/error-report.h" #include "qemu/units.h" +#include "hw/qdev-clock.h" +#include "sysemu/sysemu.h" static struct arm_boot_info aspeed_board_binfo = { .board_id = -1, /* device-tree-only board */ @@ -35,8 +38,6 @@ struct AspeedMachineState { /* Public */ AspeedSoCState soc; - MemoryRegion ram_container; - MemoryRegion max_ram; bool mmio_exec; char *fmc_model; char *spi_model; @@ -172,26 +173,9 @@ struct AspeedMachineState { #define BLETCHLEY_BMC_HW_STRAP1 AST2600_EVB_HW_STRAP1 #define BLETCHLEY_BMC_HW_STRAP2 AST2600_EVB_HW_STRAP2 -/* - * The max ram region is for firmwares that scan the address space - * with load/store to guess how much RAM the SoC has. - */ -static uint64_t max_ram_read(void *opaque, hwaddr offset, unsigned size) -{ - return 0; -} - -static void max_ram_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - /* Discard writes */ -} - -static const MemoryRegionOps max_ram_ops = { - .read = max_ram_read, - .write = max_ram_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; +/* Qualcomm DC-SCM hardware value */ +#define QCOM_DC_SCM_V1_BMC_HW_STRAP1 0x00000000 +#define QCOM_DC_SCM_V1_BMC_HW_STRAP2 0x00000041 #define AST_SMP_MAILBOX_BASE 0x1e6e2180 #define AST_SMP_MBOX_FIELD_ENTRY (AST_SMP_MAILBOX_BASE + 0x0) @@ -268,7 +252,7 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size, } storage = g_malloc0(rom_size); - if (blk_pread(blk, 0, storage, rom_size) < 0) { + if (blk_pread(blk, 0, rom_size, storage, 0) < 0) { error_setg(errp, "failed to read the initial flash content"); return; } @@ -276,7 +260,7 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size, rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr); } -static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, +void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, unsigned int count, int unit0) { int i; @@ -316,26 +300,37 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) &error_fatal); } +static void connect_serial_hds_to_uarts(AspeedMachineState *bmc) +{ + AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc); + AspeedSoCState *s = &bmc->soc; + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + + aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0)); + for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) { + if (uart == amc->uart_default) { + continue; + } + aspeed_soc_uart_set_chr(s, uart, serial_hd(i)); + } +} + static void aspeed_machine_init(MachineState *machine) { AspeedMachineState *bmc = ASPEED_MACHINE(machine); AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine); AspeedSoCClass *sc; DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); - ram_addr_t max_ram_size; int i; NICInfo *nd = &nd_table[0]; - memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container", - 4 * GiB); - memory_region_add_subregion(&bmc->ram_container, 0, machine->ram); - object_initialize_child(OBJECT(machine), "soc", &bmc->soc, amc->soc_name); sc = ASPEED_SOC_GET_CLASS(&bmc->soc); /* - * This will error out if isize is not supported by memory controller. + * This will error out if the RAM size is not supported by the + * memory controller of the SoC. */ object_property_set_uint(OBJECT(&bmc->soc), "ram-size", machine->ram_size, &error_fatal); @@ -352,6 +347,8 @@ static void aspeed_machine_init(MachineState *machine) &error_abort); object_property_set_int(OBJECT(&bmc->soc), "hw-strap2", amc->hw_strap2, &error_abort); + object_property_set_link(OBJECT(&bmc->soc), "memory", + OBJECT(get_system_memory()), &error_abort); object_property_set_link(OBJECT(&bmc->soc), "dram", OBJECT(machine->ram), &error_abort); if (machine->kernel_filename) { @@ -363,20 +360,9 @@ static void aspeed_machine_init(MachineState *machine) object_property_set_int(OBJECT(&bmc->soc), "hw-prot-key", ASPEED_SCU_PROT_KEY, &error_abort); } - qdev_prop_set_uint32(DEVICE(&bmc->soc), "uart-default", - amc->uart_default); + connect_serial_hds_to_uarts(bmc); qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); - memory_region_add_subregion(get_system_memory(), - sc->memmap[ASPEED_DEV_SDRAM], - &bmc->ram_container); - - max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size", - &error_abort); - memory_region_init_io(&bmc->max_ram, NULL, &max_ram_ops, NULL, - "max_ram", max_ram_size - machine->ram_size); - memory_region_add_subregion(&bmc->ram_container, machine->ram_size, &bmc->max_ram); - aspeed_board_init_flashes(&bmc->soc.fmc, bmc->fmc_model ? bmc->fmc_model : amc->fmc_model, amc->num_cs, 0); @@ -517,16 +503,19 @@ static void ast2500_evb_i2c_init(AspeedMachineState *bmc) /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, 0x4d); - - /* The AST2500 EVB does not have an RTC. Let's pretend that one is - * plugged on the I2C bus header */ - i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); } static void ast2600_evb_i2c_init(AspeedMachineState *bmc) { - /* Start with some devices on our I2C busses */ - ast2500_evb_i2c_init(bmc); + AspeedSoCState *soc = &bmc->soc; + uint8_t *eeprom_buf = g_malloc0(8 * 1024); + + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 7), 0x50, + eeprom_buf); + + /* LM75 is compatible with TMP105 driver */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), + TYPE_TMP105, 0x4d); } static void romulus_bmc_i2c_init(AspeedMachineState *bmc) @@ -606,7 +595,6 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) LEDState *led; /* Bus 3: TODO bmp280@77 */ - /* Bus 3: TODO max31785@52 */ dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60)); qdev_prop_set_string(dev, "description", "pca1"); i2c_slave_realize_and_unref(I2C_SLAVE(dev), @@ -622,6 +610,7 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) qdev_get_gpio_in(DEVICE(led), 0)); } i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 3), "dps310", 0x76); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 3), "max31785", 0x52); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c); @@ -766,13 +755,13 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) create_pca9552(soc, 7, 0x31); create_pca9552(soc, 7, 0x32); create_pca9552(soc, 7, 0x33); - /* Bus 7: TODO max31785@52 */ create_pca9552(soc, 7, 0x60); create_pca9552(soc, 7, 0x61); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "dps310", 0x76); /* Bus 7: TODO si7021-a20@20 */ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "max31785", 0x52); aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x50, 64 * KiB); aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x51, 64 * KiB); @@ -950,6 +939,74 @@ static void bletchley_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(i2c[12], TYPE_PCA9552, 0x67); } +static void fby35_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + I2CBus *i2c[16]; + + for (int i = 0; i < 16; i++) { + i2c[i] = aspeed_i2c_get_bus(&soc->i2c, i); + } + + i2c_slave_create_simple(i2c[2], TYPE_LM75, 0x4f); + i2c_slave_create_simple(i2c[8], TYPE_TMP421, 0x1f); + /* Hotswap controller is actually supposed to be mp5920 or ltc4282. */ + i2c_slave_create_simple(i2c[11], "adm1272", 0x44); + i2c_slave_create_simple(i2c[12], TYPE_LM75, 0x4e); + i2c_slave_create_simple(i2c[12], TYPE_LM75, 0x4f); + + aspeed_eeprom_init(i2c[4], 0x51, 128 * KiB); + aspeed_eeprom_init(i2c[6], 0x51, 128 * KiB); + aspeed_eeprom_init(i2c[8], 0x50, 32 * KiB); + aspeed_eeprom_init(i2c[11], 0x51, 128 * KiB); + aspeed_eeprom_init(i2c[11], 0x54, 128 * KiB); + + /* + * TODO: There is a multi-master i2c connection to an AST1030 MiniBMC on + * buses 0, 1, 2, 3, and 9. Source address 0x10, target address 0x20 on + * each. + */ +} + +static void qcom_dc_scm_bmc_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 15), "tmp105", 0x4d); +} + +static void qcom_dc_scm_firework_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + I2CSlave *therm_mux, *cpuvr_mux; + + /* Create the generic DC-SCM hardware */ + qcom_dc_scm_bmc_i2c_init(bmc); + + /* Now create the Firework specific hardware */ + + /* I2C7 CPUVR MUX */ + cpuvr_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), + "pca9546", 0x70); + i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 0), "pca9548", 0x72); + i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 1), "pca9548", 0x72); + i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 2), "pca9548", 0x72); + i2c_slave_create_simple(pca954x_i2c_get_bus(cpuvr_mux, 3), "pca9548", 0x72); + + /* I2C8 Thermal Diodes*/ + therm_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), + "pca9548", 0x70); + i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 0), TYPE_LM75, 0x4C); + i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 1), TYPE_LM75, 0x4C); + i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 2), TYPE_LM75, 0x48); + i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 3), TYPE_LM75, 0x48); + i2c_slave_create_simple(pca954x_i2c_get_bus(therm_mux, 4), TYPE_LM75, 0x48); + + /* I2C9 Fan Controller (MAX31785) */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "max31785", 0x52); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "max31785", 0x54); +} + static bool aspeed_get_mmio_exec(Object *obj, Error **errp) { return ASPEED_MACHINE(obj)->mmio_exec; @@ -1042,7 +1099,7 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data) amc->soc_name = "ast2400-a1"; amc->hw_strap1 = PALMETTO_BMC_HW_STRAP1; amc->fmc_model = "n25q256a"; - amc->spi_model = "mx25l25635e"; + amc->spi_model = "mx25l25635f"; amc->num_cs = 1; amc->i2c_init = palmetto_bmc_i2c_init; mc->default_ram_size = 256 * MiB; @@ -1092,8 +1149,8 @@ static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) mc->desc = "Aspeed AST2500 EVB (ARM1176)"; amc->soc_name = "ast2500-a1"; amc->hw_strap1 = AST2500_EVB_HW_STRAP1; - amc->fmc_model = "w25q256"; - amc->spi_model = "mx25l25635e"; + amc->fmc_model = "mx25l25635e"; + amc->spi_model = "mx25l25635f"; amc->num_cs = 1; amc->i2c_init = ast2500_evb_i2c_init; mc->default_ram_size = 512 * MiB; @@ -1143,7 +1200,7 @@ static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) mc->desc = "OpenPOWER Witherspoon BMC (ARM1176)"; amc->soc_name = "ast2500-a1"; amc->hw_strap1 = WITHERSPOON_BMC_HW_STRAP1; - amc->fmc_model = "mx25l25635e"; + amc->fmc_model = "mx25l25635f"; amc->spi_model = "mx66l1g45g"; amc->num_cs = 2; amc->i2c_init = witherspoon_bmc_i2c_init; @@ -1161,7 +1218,7 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) amc->soc_name = "ast2600-a3"; amc->hw_strap1 = AST2600_EVB_HW_STRAP1; amc->hw_strap2 = AST2600_EVB_HW_STRAP2; - amc->fmc_model = "w25q512jv"; + amc->fmc_model = "mx66u51235f"; amc->spi_model = "mx66u51235f"; amc->num_cs = 1; amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON | @@ -1273,6 +1330,13 @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; +/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ +#if HOST_LONG_BITS == 32 +#define BLETCHLEY_BMC_RAM_SIZE (1 * GiB) +#else +#define BLETCHLEY_BMC_RAM_SIZE (2 * GiB) +#endif + static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1287,11 +1351,168 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->macs_mask = ASPEED_MAC2_ON; amc->i2c_init = bletchley_bmc_i2c_init; - mc->default_ram_size = 512 * MiB; + mc->default_ram_size = BLETCHLEY_BMC_RAM_SIZE; mc->default_cpus = mc->min_cpus = mc->max_cpus = aspeed_soc_num_cpus(amc->soc_name); } +static void fby35_reset(MachineState *state, ShutdownCause reason) +{ + AspeedMachineState *bmc = ASPEED_MACHINE(state); + AspeedGPIOState *gpio = &bmc->soc.gpio; + + qemu_devices_reset(reason); + + /* Board ID: 7 (Class-1, 4 slots) */ + object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioV5", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioV6", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioV7", false, &error_fatal); + + /* Slot presence pins, inverse polarity. (False means present) */ + object_property_set_bool(OBJECT(gpio), "gpioH4", false, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioH5", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioH6", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioH7", true, &error_fatal); + + /* Slot 12v power pins, normal polarity. (True means powered-on) */ + object_property_set_bool(OBJECT(gpio), "gpioB2", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioB3", false, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioB4", false, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioB5", false, &error_fatal); +} + +static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Facebook fby35 BMC (Cortex-A7)"; + mc->reset = fby35_reset; + amc->fmc_model = "mx66l1g45g"; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC3_ON; + amc->i2c_init = fby35_i2c_init; + /* FIXME: Replace this macro with something more general */ + mc->default_ram_size = FUJI_BMC_RAM_SIZE; +} + +#define AST1030_INTERNAL_FLASH_SIZE (1024 * 1024) +/* Main SYSCLK frequency in Hz (200MHz) */ +#define SYSCLK_FRQ 200000000ULL + +static void aspeed_minibmc_machine_init(MachineState *machine) +{ + AspeedMachineState *bmc = ASPEED_MACHINE(machine); + AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine); + Clock *sysclk; + + sysclk = clock_new(OBJECT(machine), "SYSCLK"); + clock_set_hz(sysclk, SYSCLK_FRQ); + + object_initialize_child(OBJECT(machine), "soc", &bmc->soc, amc->soc_name); + qdev_connect_clock_in(DEVICE(&bmc->soc), "sysclk", sysclk); + + object_property_set_link(OBJECT(&bmc->soc), "memory", + OBJECT(get_system_memory()), &error_abort); + connect_serial_hds_to_uarts(bmc); + qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); + + aspeed_board_init_flashes(&bmc->soc.fmc, + bmc->fmc_model ? bmc->fmc_model : amc->fmc_model, + amc->num_cs, + 0); + + aspeed_board_init_flashes(&bmc->soc.spi[0], + bmc->spi_model ? bmc->spi_model : amc->spi_model, + amc->num_cs, amc->num_cs); + + aspeed_board_init_flashes(&bmc->soc.spi[1], + bmc->spi_model ? bmc->spi_model : amc->spi_model, + amc->num_cs, (amc->num_cs * 2)); + + if (amc->i2c_init) { + amc->i2c_init(bmc); + } + + armv7m_load_kernel(ARM_CPU(first_cpu), + machine->kernel_filename, + 0, + AST1030_INTERNAL_FLASH_SIZE); +} + +static void ast1030_evb_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + + /* U10 24C08 connects to SDA/SCL Groupt 1 by default */ + uint8_t *eeprom_buf = g_malloc0(32 * 1024); + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf); + + /* U11 LM75 connects to SDA/SCL Group 2 by default */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4d); +} + +static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc, + void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Aspeed AST1030 MiniBMC (Cortex-M4)"; + amc->soc_name = "ast1030-a1"; + amc->hw_strap1 = 0; + amc->hw_strap2 = 0; + mc->init = aspeed_minibmc_machine_init; + amc->i2c_init = ast1030_evb_i2c_init; + mc->default_ram_size = 0; + mc->default_cpus = mc->min_cpus = mc->max_cpus = 1; + amc->fmc_model = "sst25vf032b"; + amc->spi_model = "sst25vf032b"; + amc->num_cs = 2; + amc->macs_mask = 0; +} + +static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, + void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Qualcomm DC-SCM V1 BMC (Cortex A7)"; + amc->soc_name = "ast2600-a3"; + amc->hw_strap1 = QCOM_DC_SCM_V1_BMC_HW_STRAP1; + amc->hw_strap2 = QCOM_DC_SCM_V1_BMC_HW_STRAP2; + amc->fmc_model = "n25q512a"; + amc->spi_model = "n25q512a"; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; + amc->i2c_init = qcom_dc_scm_bmc_i2c_init; + mc->default_ram_size = 1 * GiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); +}; + +static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc, + void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Qualcomm DC-SCM V1/Firework BMC (Cortex A7)"; + amc->soc_name = "ast2600-a3"; + amc->hw_strap1 = QCOM_DC_SCM_V1_BMC_HW_STRAP1; + amc->hw_strap2 = QCOM_DC_SCM_V1_BMC_HW_STRAP2; + amc->fmc_model = "n25q512a"; + amc->spi_model = "n25q512a"; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; + amc->i2c_init = qcom_dc_scm_firework_i2c_init; + mc->default_ram_size = 1 * GiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); +}; + static const TypeInfo aspeed_machine_types[] = { { .name = MACHINE_TYPE_NAME("palmetto-bmc"), @@ -1329,6 +1550,14 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("g220a-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_g220a_class_init, + }, { + .name = MACHINE_TYPE_NAME("qcom-dc-scm-v1-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_qcom_dc_scm_v1_class_init, + }, { + .name = MACHINE_TYPE_NAME("qcom-firework-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_qcom_firework_class_init, }, { .name = MACHINE_TYPE_NAME("fp5280g2-bmc"), .parent = TYPE_ASPEED_MACHINE, @@ -1349,6 +1578,14 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("bletchley-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_bletchley_class_init, + }, { + .name = MACHINE_TYPE_NAME("fby35-bmc"), + .parent = MACHINE_TYPE_NAME("ast2600-evb"), + .class_init = aspeed_machine_fby35_class_init, + }, { + .name = MACHINE_TYPE_NAME("ast1030-evb"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_minibmc_machine_ast1030_evb_class_init, }, { .name = TYPE_ASPEED_MACHINE, .parent = TYPE_MACHINE, diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c new file mode 100644 index 000000000000..4d0b9b115f0d --- /dev/null +++ b/hw/arm/aspeed_ast10x0.c @@ -0,0 +1,377 @@ +/* + * ASPEED Ast10x0 SoC + * + * Copyright (C) 2022 ASPEED Technology Inc. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + * Implementation extracted from the AST2600 and adapted for Ast10x0. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-clock.h" +#include "hw/misc/unimp.h" +#include "hw/arm/aspeed_soc.h" + +#define ASPEED_SOC_IOMEM_SIZE 0x00200000 + +static const hwaddr aspeed_soc_ast1030_memmap[] = { + [ASPEED_DEV_SRAM] = 0x00000000, + [ASPEED_DEV_SBC] = 0x79000000, + [ASPEED_DEV_IOMEM] = 0x7E600000, + [ASPEED_DEV_PWM] = 0x7E610000, + [ASPEED_DEV_FMC] = 0x7E620000, + [ASPEED_DEV_SPI1] = 0x7E630000, + [ASPEED_DEV_SPI2] = 0x7E640000, + [ASPEED_DEV_SCU] = 0x7E6E2000, + [ASPEED_DEV_ADC] = 0x7E6E9000, + [ASPEED_DEV_SBC] = 0x7E6F2000, + [ASPEED_DEV_GPIO] = 0x7E780000, + [ASPEED_DEV_TIMER1] = 0x7E782000, + [ASPEED_DEV_UART1] = 0x7E783000, + [ASPEED_DEV_UART2] = 0x7E78D000, + [ASPEED_DEV_UART3] = 0x7E78E000, + [ASPEED_DEV_UART4] = 0x7E78F000, + [ASPEED_DEV_UART5] = 0x7E784000, + [ASPEED_DEV_UART6] = 0x7E790000, + [ASPEED_DEV_UART7] = 0x7E790100, + [ASPEED_DEV_UART8] = 0x7E790200, + [ASPEED_DEV_UART9] = 0x7E790300, + [ASPEED_DEV_UART10] = 0x7E790400, + [ASPEED_DEV_UART11] = 0x7E790500, + [ASPEED_DEV_UART12] = 0x7E790600, + [ASPEED_DEV_UART13] = 0x7E790700, + [ASPEED_DEV_WDT] = 0x7E785000, + [ASPEED_DEV_LPC] = 0x7E789000, + [ASPEED_DEV_PECI] = 0x7E78B000, + [ASPEED_DEV_I2C] = 0x7E7B0000, +}; + +static const int aspeed_soc_ast1030_irqmap[] = { + [ASPEED_DEV_UART1] = 47, + [ASPEED_DEV_UART2] = 48, + [ASPEED_DEV_UART3] = 49, + [ASPEED_DEV_UART4] = 50, + [ASPEED_DEV_UART5] = 8, + [ASPEED_DEV_UART6] = 57, + [ASPEED_DEV_UART7] = 58, + [ASPEED_DEV_UART8] = 59, + [ASPEED_DEV_UART9] = 60, + [ASPEED_DEV_UART10] = 61, + [ASPEED_DEV_UART11] = 62, + [ASPEED_DEV_UART12] = 63, + [ASPEED_DEV_UART13] = 64, + [ASPEED_DEV_GPIO] = 11, + [ASPEED_DEV_TIMER1] = 16, + [ASPEED_DEV_TIMER2] = 17, + [ASPEED_DEV_TIMER3] = 18, + [ASPEED_DEV_TIMER4] = 19, + [ASPEED_DEV_TIMER5] = 20, + [ASPEED_DEV_TIMER6] = 21, + [ASPEED_DEV_TIMER7] = 22, + [ASPEED_DEV_TIMER8] = 23, + [ASPEED_DEV_WDT] = 24, + [ASPEED_DEV_LPC] = 35, + [ASPEED_DEV_PECI] = 38, + [ASPEED_DEV_FMC] = 39, + [ASPEED_DEV_PWM] = 44, + [ASPEED_DEV_ADC] = 46, + [ASPEED_DEV_SPI1] = 65, + [ASPEED_DEV_SPI2] = 66, + [ASPEED_DEV_I2C] = 110, /* 110 ~ 123 */ + [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ +}; + +static qemu_irq aspeed_soc_ast1030_get_irq(AspeedSoCState *s, int dev) +{ + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + + return qdev_get_gpio_in(DEVICE(&s->armv7m), sc->irqmap[dev]); +} + +static void aspeed_soc_ast1030_init(Object *obj) +{ + AspeedSoCState *s = ASPEED_SOC(obj); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + char socname[8]; + char typename[64]; + int i; + + if (sscanf(sc->name, "%7s", socname) != 1) { + g_assert_not_reached(); + } + + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); + + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + + snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); + object_initialize_child(obj, "scu", &s->scu, typename); + qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); + + object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1"); + object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2"); + + snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); + object_initialize_child(obj, "i2c", &s->i2c, typename); + + snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname); + object_initialize_child(obj, "timerctrl", &s->timerctrl, typename); + + snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname); + object_initialize_child(obj, "adc", &s->adc, typename); + + snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); + object_initialize_child(obj, "fmc", &s->fmc, typename); + + for (i = 0; i < sc->spis_num; i++) { + snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); + object_initialize_child(obj, "spi[*]", &s->spi[i], typename); + } + + object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC); + + object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI); + + object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC); + + for (i = 0; i < sc->wdts_num; i++) { + snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); + object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename); + } + + for (i = 0; i < sc->uarts_num; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM); + } + + snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); + object_initialize_child(obj, "gpio", &s->gpio, typename); + + object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "sbc-unimplemented", &s->sbc_unimplemented, + TYPE_UNIMPLEMENTED_DEVICE); +} + +static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) +{ + AspeedSoCState *s = ASPEED_SOC(dev_soc); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + DeviceState *armv7m; + Error *err = NULL; + int i; + g_autofree char *sram_name = NULL; + + if (!clock_has_source(s->sysclk)) { + error_setg(errp, "sysclk clock must be wired up by the board code"); + return; + } + + /* General I/O memory space to catch all unimplemented device */ + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", + sc->memmap[ASPEED_DEV_IOMEM], + ASPEED_SOC_IOMEM_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->sbc_unimplemented), + "aspeed.sbc", sc->memmap[ASPEED_DEV_SBC], + 0x40000); + + /* AST1030 CPU Core */ + armv7m = DEVICE(&s->armv7m); + qdev_prop_set_uint32(armv7m, "num-irq", 256); + qdev_prop_set_string(armv7m, "cpu-type", sc->cpu_type); + qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); + object_property_set_link(OBJECT(&s->armv7m), "memory", + OBJECT(s->memory), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &error_abort); + + /* Internal SRAM */ + sram_name = g_strdup_printf("aspeed.sram.%d", + CPU(s->armv7m.cpu)->cpu_index); + memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(s->memory, + sc->memmap[ASPEED_DEV_SRAM], + &s->sram); + + /* SCU */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + + /* I2C */ + + object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(&s->sram), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) { + qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m), + sc->irqmap[ASPEED_DEV_I2C] + i); + /* The AST1030 I2C controller has one IRQ per bus. */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq); + } + + /* PECI */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0, + sc->memmap[ASPEED_DEV_PECI]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_PECI)); + + /* LPC */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); + + /* Connect the LPC IRQ to the GIC. It is otherwise unused. */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_LPC)); + + /* + * On the AST1030 LPC subdevice IRQs are connected straight to the GIC. + */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_1, + qdev_get_gpio_in(DEVICE(&s->armv7m), + sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_1)); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_2, + qdev_get_gpio_in(DEVICE(&s->armv7m), + sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_2)); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_3, + qdev_get_gpio_in(DEVICE(&s->armv7m), + sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_3)); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4, + qdev_get_gpio_in(DEVICE(&s->armv7m), + sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4)); + + /* UART */ + if (!aspeed_soc_uart_realize(s, errp)) { + return; + } + + /* Timer */ + object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, + sc->memmap[ASPEED_DEV_TIMER1]); + for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { + qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); + } + + /* ADC */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); + + /* FMC, The number of CS is set at the board level */ + object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(&s->sram), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, + ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); + + /* SPI */ + for (i = 0; i < sc->spis_num; i++) { + object_property_set_link(OBJECT(&s->spi[i]), "dram", + OBJECT(&s->sram), &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, + sc->memmap[ASPEED_DEV_SPI1 + i]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, + ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); + } + + /* Secure Boot Controller */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); + + /* Watch dog */ + for (i = 0; i < sc->wdts_num; i++) { + AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); + + object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, + sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); + } + + /* GPIO */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, + sc->memmap[ASPEED_DEV_GPIO]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); +} + +static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc); + + dc->realize = aspeed_soc_ast1030_realize; + + sc->name = "ast1030-a1"; + sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); + sc->silicon_rev = AST1030_A1_SILICON_REV; + sc->sram_size = 0xc0000; + sc->spis_num = 2; + sc->ehcis_num = 0; + sc->wdts_num = 4; + sc->macs_num = 1; + sc->uarts_num = 13; + sc->irqmap = aspeed_soc_ast1030_irqmap; + sc->memmap = aspeed_soc_ast1030_memmap; + sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast1030_get_irq; +} + +static const TypeInfo aspeed_soc_ast1030_type_info = { + .name = "ast1030-a1", + .parent = TYPE_ASPEED_SOC, + .instance_size = sizeof(AspeedSoCState), + .instance_init = aspeed_soc_ast1030_init, + .class_init = aspeed_soc_ast1030_class_init, + .class_size = sizeof(AspeedSoCClass), +}; + +static void aspeed_soc_register_types(void) +{ + type_register_static(&aspeed_soc_ast1030_type_info); +} + +type_init(aspeed_soc_register_types) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index c1e15e37739c..cd75465c2bdd 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -11,7 +11,6 @@ #include "qapi/error.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" -#include "hw/char/serial.h" #include "qemu/module.h" #include "qemu/error-report.h" #include "hw/i2c/aspeed_i2c.h" @@ -48,6 +47,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_DEV_ADC] = 0x1E6E9000, [ASPEED_DEV_DP] = 0x1E6EB000, [ASPEED_DEV_SBC] = 0x1E6F2000, + [ASPEED_DEV_EMMC_BC] = 0x1E6f5000, [ASPEED_DEV_VIDEO] = 0x1E700000, [ASPEED_DEV_SDHCI] = 0x1E740000, [ASPEED_DEV_EMMC] = 0x1E750000, @@ -59,8 +59,20 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_DEV_LPC] = 0x1E789000, [ASPEED_DEV_IBT] = 0x1E789140, [ASPEED_DEV_I2C] = 0x1E78A000, + [ASPEED_DEV_PECI] = 0x1E78B000, [ASPEED_DEV_UART1] = 0x1E783000, + [ASPEED_DEV_UART2] = 0x1E78D000, + [ASPEED_DEV_UART3] = 0x1E78E000, + [ASPEED_DEV_UART4] = 0x1E78F000, [ASPEED_DEV_UART5] = 0x1E784000, + [ASPEED_DEV_UART6] = 0x1E790000, + [ASPEED_DEV_UART7] = 0x1E790100, + [ASPEED_DEV_UART8] = 0x1E790200, + [ASPEED_DEV_UART9] = 0x1E790300, + [ASPEED_DEV_UART10] = 0x1E790400, + [ASPEED_DEV_UART11] = 0x1E790500, + [ASPEED_DEV_UART12] = 0x1E790600, + [ASPEED_DEV_UART13] = 0x1E790700, [ASPEED_DEV_VUART] = 0x1E787000, [ASPEED_DEV_I3C] = 0x1E7A0000, [ASPEED_DEV_SDRAM] = 0x80000000, @@ -77,6 +89,14 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_UART3] = 49, [ASPEED_DEV_UART4] = 50, [ASPEED_DEV_UART5] = 8, + [ASPEED_DEV_UART6] = 57, + [ASPEED_DEV_UART7] = 58, + [ASPEED_DEV_UART8] = 59, + [ASPEED_DEV_UART9] = 60, + [ASPEED_DEV_UART10] = 61, + [ASPEED_DEV_UART11] = 62, + [ASPEED_DEV_UART12] = 63, + [ASPEED_DEV_UART13] = 64, [ASPEED_DEV_VUART] = 8, [ASPEED_DEV_FMC] = 39, [ASPEED_DEV_SDMC] = 0, @@ -103,6 +123,7 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_LPC] = 35, [ASPEED_DEV_IBT] = 143, [ASPEED_DEV_I2C] = 110, /* 110 -> 125 */ + [ASPEED_DEV_PECI] = 38, [ASPEED_DEV_ETH1] = 2, [ASPEED_DEV_ETH2] = 3, [ASPEED_DEV_HACE] = 4, @@ -113,11 +134,11 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_I3C] = 102, /* 102 -> 107 */ }; -static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl) +static qemu_irq aspeed_soc_ast2600_get_irq(AspeedSoCState *s, int dev) { AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - return qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[ctrl]); + return qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[dev]); } static void aspeed_soc_ast2600_init(Object *obj) @@ -161,6 +182,8 @@ static void aspeed_soc_ast2600_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); object_initialize_child(obj, "i2c", &s->i2c, typename); + object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI); + snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); object_initialize_child(obj, "fmc", &s->fmc, typename); @@ -178,8 +201,6 @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "sdmc", &s->sdmc, typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size"); - object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), - "max-ram-size"); for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); @@ -193,6 +214,10 @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII); } + for (i = 0; i < sc->uarts_num; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM); + } + snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname); object_initialize_child(obj, "xdma", &s->xdma, typename); @@ -229,6 +254,13 @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "i3c", &s->i3c, TYPE_ASPEED_I3C); object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC); + + object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "dpmcu", &s->dpmcu, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "emmc-boot-controller", + &s->emmc_boot_controller, + TYPE_UNIMPLEMENTED_DEVICE); } /* @@ -248,14 +280,21 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); Error *err = NULL; qemu_irq irq; + g_autofree char *sram_name = NULL; /* IO space */ - create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_DEV_IOMEM], - ASPEED_SOC_IOMEM_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", + sc->memmap[ASPEED_DEV_IOMEM], + ASPEED_SOC_IOMEM_SIZE); /* Video engine stub */ - create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_DEV_VIDEO], - 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video", + sc->memmap[ASPEED_DEV_VIDEO], 0x1000); + + /* eMMC Boot Controller stub */ + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->emmc_boot_controller), + "aspeed.emmc-boot-controller", + sc->memmap[ASPEED_DEV_EMMC_BC], 0x1000); /* CPU */ for (i = 0; i < sc->num_cpus; i++) { @@ -268,6 +307,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 1125000000, &error_abort); + object_property_set_bool(OBJECT(&s->cpu[i]), "neon", false, + &error_abort); + object_property_set_link(OBJECT(&s->cpu[i]), "memory", + OBJECT(s->memory), &error_abort); if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { return; @@ -282,11 +325,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR); for (i = 0; i < sc->num_cpus; i++) { SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore); - DeviceState *d = DEVICE(qemu_get_cpu(i)); + DeviceState *d = DEVICE(&s->cpu[i]); irq = qdev_get_gpio_in(d, ARM_CPU_IRQ); sysbus_connect_irq(sbd, i, irq); @@ -299,30 +342,31 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* SRAM */ - memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram", - sc->sram_size, &err); + sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&s->cpu[0])->cpu_index); + memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err); if (err) { error_propagate(errp, err); return; } - memory_region_add_subregion(get_system_memory(), + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SRAM], &s->sram); /* DPMCU */ - create_unimplemented_device("aspeed.dpmcu", sc->memmap[ASPEED_DEV_DPMCU], - ASPEED_SOC_DPMCU_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu), "aspeed.dpmcu", + sc->memmap[ASPEED_DEV_DPMCU], + ASPEED_SOC_DPMCU_SIZE); /* SCU */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); /* RTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_RTC)); @@ -332,7 +376,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); @@ -343,14 +387,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); - /* UART - attach an 8250 to the IO space as our UART */ - serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, - aspeed_soc_get_irq(s, s->uart_default), 38400, - serial_hd(0), DEVICE_LITTLE_ENDIAN); + /* UART */ + if (!aspeed_soc_uart_realize(s, errp)) { + return; + } /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), @@ -358,7 +402,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[ASPEED_DEV_I2C] + i); @@ -366,14 +410,23 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq); } + /* PECI */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0, + sc->memmap[ASPEED_DEV_PECI]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_PECI)); + /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); @@ -385,9 +438,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } @@ -396,7 +449,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0, sc->memmap[ASPEED_DEV_EHCI1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i)); @@ -406,7 +459,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0, + sc->memmap[ASPEED_DEV_SDMC]); /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { @@ -417,10 +471,15 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); } + /* RAM */ + if (!aspeed_soc_dram_init(s, errp)) { + return; + } + /* Net */ for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true, @@ -428,7 +487,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_DEV_ETH1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i)); @@ -439,7 +498,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->mii[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0, sc->memmap[ASPEED_DEV_MII1 + i]); } @@ -447,7 +506,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0, sc->memmap[ASPEED_DEV_XDMA]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0, aspeed_soc_get_irq(s, ASPEED_DEV_XDMA)); @@ -456,14 +515,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio_1_8v), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio_1_8v), 0, sc->memmap[ASPEED_DEV_GPIO_1_8V]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio_1_8v), 0, aspeed_soc_get_irq(s, ASPEED_DEV_GPIO_1_8V)); @@ -472,7 +531,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0, sc->memmap[ASPEED_DEV_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI)); @@ -481,7 +540,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_DEV_EMMC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0, + sc->memmap[ASPEED_DEV_EMMC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_EMMC)); @@ -489,7 +549,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); /* Connect the LPC IRQ to the GIC. It is otherwise unused. */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0, @@ -525,7 +585,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + sc->memmap[ASPEED_DEV_HACE]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); @@ -533,7 +594,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]); for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[ASPEED_DEV_I3C] + i); @@ -545,7 +606,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); } static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) @@ -563,9 +624,11 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) sc->ehcis_num = 2; sc->wdts_num = 4; sc->macs_num = 4; + sc->uarts_num = 13; sc->irqmap = aspeed_soc_ast2600_irqmap; sc->memmap = aspeed_soc_ast2600_memmap; sc->num_cpus = 2; + sc->get_irq = aspeed_soc_ast2600_get_irq; } static const TypeInfo aspeed_soc_ast2600_type_info = { diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 58714cb2a01d..b05b9dd41602 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" @@ -45,9 +46,13 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = { [ASPEED_DEV_LPC] = 0x1E789000, [ASPEED_DEV_IBT] = 0x1E789140, [ASPEED_DEV_I2C] = 0x1E78A000, + [ASPEED_DEV_PECI] = 0x1E78B000, [ASPEED_DEV_ETH1] = 0x1E660000, [ASPEED_DEV_ETH2] = 0x1E680000, [ASPEED_DEV_UART1] = 0x1E783000, + [ASPEED_DEV_UART2] = 0x1E78D000, + [ASPEED_DEV_UART3] = 0x1E78E000, + [ASPEED_DEV_UART4] = 0x1E78F000, [ASPEED_DEV_UART5] = 0x1E784000, [ASPEED_DEV_VUART] = 0x1E787000, [ASPEED_DEV_SDRAM] = 0x40000000, @@ -77,9 +82,13 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = { [ASPEED_DEV_LPC] = 0x1E789000, [ASPEED_DEV_IBT] = 0x1E789140, [ASPEED_DEV_I2C] = 0x1E78A000, + [ASPEED_DEV_PECI] = 0x1E78B000, [ASPEED_DEV_ETH1] = 0x1E660000, [ASPEED_DEV_ETH2] = 0x1E680000, [ASPEED_DEV_UART1] = 0x1E783000, + [ASPEED_DEV_UART2] = 0x1E78D000, + [ASPEED_DEV_UART3] = 0x1E78E000, + [ASPEED_DEV_UART4] = 0x1E78F000, [ASPEED_DEV_UART5] = 0x1E784000, [ASPEED_DEV_VUART] = 0x1E787000, [ASPEED_DEV_SDRAM] = 0x80000000, @@ -112,6 +121,7 @@ static const int aspeed_soc_ast2400_irqmap[] = { [ASPEED_DEV_PWM] = 28, [ASPEED_DEV_LPC] = 8, [ASPEED_DEV_I2C] = 12, + [ASPEED_DEV_PECI] = 15, [ASPEED_DEV_ETH1] = 2, [ASPEED_DEV_ETH2] = 3, [ASPEED_DEV_XDMA] = 6, @@ -121,11 +131,11 @@ static const int aspeed_soc_ast2400_irqmap[] = { #define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap -static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl) +static qemu_irq aspeed_soc_ast2400_get_irq(AspeedSoCState *s, int dev) { AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - return qdev_get_gpio_in(DEVICE(&s->vic), sc->irqmap[ctrl]); + return qdev_get_gpio_in(DEVICE(&s->vic), sc->irqmap[dev]); } static void aspeed_soc_init(Object *obj) @@ -168,6 +178,8 @@ static void aspeed_soc_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); object_initialize_child(obj, "i2c", &s->i2c, typename); + object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI); + snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); object_initialize_child(obj, "fmc", &s->fmc, typename); @@ -185,8 +197,6 @@ static void aspeed_soc_init(Object *obj) object_initialize_child(obj, "sdmc", &s->sdmc, typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size"); - object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), - "max-ram-size"); for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); @@ -198,6 +208,10 @@ static void aspeed_soc_init(Object *obj) TYPE_FTGMAC100); } + for (i = 0; i < sc->uarts_num; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM); + } + snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname); object_initialize_child(obj, "xdma", &s->xdma, typename); @@ -218,6 +232,9 @@ static void aspeed_soc_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname); object_initialize_child(obj, "hace", &s->hace, typename); + + object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DEVICE); } static void aspeed_soc_realize(DeviceState *dev, Error **errp) @@ -226,43 +243,47 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) AspeedSoCState *s = ASPEED_SOC(dev); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); Error *err = NULL; + g_autofree char *sram_name = NULL; /* IO space */ - create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_DEV_IOMEM], - ASPEED_SOC_IOMEM_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", + sc->memmap[ASPEED_DEV_IOMEM], + ASPEED_SOC_IOMEM_SIZE); /* Video engine stub */ - create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_DEV_VIDEO], - 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video", + sc->memmap[ASPEED_DEV_VIDEO], 0x1000); /* CPU */ for (i = 0; i < sc->num_cpus; i++) { + object_property_set_link(OBJECT(&s->cpu[i]), "memory", + OBJECT(s->memory), &error_abort); if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { return; } } /* SRAM */ - memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram", - sc->sram_size, &err); + sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&s->cpu[0])->cpu_index); + memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err); if (err) { error_propagate(errp, err); return; } - memory_region_add_subregion(get_system_memory(), + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SRAM], &s->sram); /* SCU */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); /* VIC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->vic), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->memmap[ASPEED_DEV_VIC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->vic), 0, sc->memmap[ASPEED_DEV_VIC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, @@ -272,7 +293,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_RTC)); @@ -282,7 +303,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); @@ -293,14 +314,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); - /* UART - attach an 8250 to the IO space as our UART */ - serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, - aspeed_soc_get_irq(s, s->uart_default), 38400, - serial_hd(0), DEVICE_LITTLE_ENDIAN); + /* UART */ + if (!aspeed_soc_uart_realize(s, errp)) { + return; + } /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), @@ -308,18 +329,27 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, aspeed_soc_get_irq(s, ASPEED_DEV_I2C)); + /* PECI */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0, + sc->memmap[ASPEED_DEV_PECI]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_PECI)); + /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); @@ -329,9 +359,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } @@ -340,7 +370,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0, sc->memmap[ASPEED_DEV_EHCI1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i)); @@ -350,7 +380,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0, + sc->memmap[ASPEED_DEV_SDMC]); /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { @@ -361,10 +392,15 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); } + /* RAM */ + if (!aspeed_soc_dram_init(s, errp)) { + return; + } + /* Net */ for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true, @@ -372,7 +408,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_DEV_ETH1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i)); @@ -382,7 +418,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0, sc->memmap[ASPEED_DEV_XDMA]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0, aspeed_soc_get_irq(s, ASPEED_DEV_XDMA)); @@ -391,7 +427,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, + sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); @@ -399,7 +436,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0, sc->memmap[ASPEED_DEV_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI)); @@ -408,7 +445,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); /* Connect the LPC IRQ to the VIC */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0, @@ -441,15 +478,16 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + sc->memmap[ASPEED_DEV_HACE]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); } static Property aspeed_soc_properties[] = { + DEFINE_PROP_LINK("memory", AspeedSoCState, memory, TYPE_MEMORY_REGION, + MemoryRegion *), DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), - DEFINE_PROP_UINT32("uart-default", AspeedSoCState, uart_default, - ASPEED_DEV_UART5), DEFINE_PROP_END_OF_LIST(), }; @@ -484,9 +522,11 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) sc->ehcis_num = 1; sc->wdts_num = 2; sc->macs_num = 2; + sc->uarts_num = 5; sc->irqmap = aspeed_soc_ast2400_irqmap; sc->memmap = aspeed_soc_ast2400_memmap; sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast2400_get_irq; } static const TypeInfo aspeed_soc_ast2400_type_info = { @@ -509,9 +549,11 @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data) sc->ehcis_num = 2; sc->wdts_num = 3; sc->macs_num = 2; + sc->uarts_num = 5; sc->irqmap = aspeed_soc_ast2500_irqmap; sc->memmap = aspeed_soc_ast2500_memmap; sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast2400_get_irq; } static const TypeInfo aspeed_soc_ast2500_type_info = { @@ -528,4 +570,100 @@ static void aspeed_soc_register_types(void) type_register_static(&aspeed_soc_ast2500_type_info); }; -type_init(aspeed_soc_register_types) +type_init(aspeed_soc_register_types); + +qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) +{ + return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev); +} + +bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp) +{ + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + SerialMM *smm; + + for (int i = 0, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) { + smm = &s->uart[i]; + + /* Chardev property is set by the machine. */ + qdev_prop_set_uint8(DEVICE(smm), "regshift", 2); + qdev_prop_set_uint32(DEVICE(smm), "baudbase", 38400); + qdev_set_legacy_instance_id(DEVICE(smm), sc->memmap[uart], 2); + qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); + if (!sysbus_realize(SYS_BUS_DEVICE(smm), errp)) { + return false; + } + + sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, aspeed_soc_get_irq(s, uart)); + aspeed_mmio_map(s, SYS_BUS_DEVICE(smm), 0, sc->memmap[uart]); + } + + return true; +} + +void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr) +{ + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + int i = dev - ASPEED_DEV_UART1; + + g_assert(0 <= i && i < ARRAY_SIZE(s->uart) && i < sc->uarts_num); + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); +} + +/* + * SDMC should be realized first to get correct RAM size and max size + * values + */ +bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp) +{ + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + ram_addr_t ram_size, max_ram_size; + + ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size", + &error_abort); + max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size", + &error_abort); + + memory_region_init(&s->dram_container, OBJECT(s), "ram-container", + max_ram_size); + memory_region_add_subregion(&s->dram_container, 0, s->dram_mr); + + /* + * Add a memory region beyond the RAM region to let firmwares scan + * the address space with load/store and guess how much RAM the + * SoC has. + */ + if (ram_size < max_ram_size) { + DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE); + + qdev_prop_set_string(dev, "name", "ram-empty"); + qdev_prop_set_uint64(dev, "size", max_ram_size - ram_size); + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) { + return false; + } + + memory_region_add_subregion_overlap(&s->dram_container, ram_size, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0), -1000); + } + + memory_region_add_subregion(s->memory, + sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container); + return true; +} + +void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr) +{ + memory_region_add_subregion(s->memory, addr, + sysbus_mmio_get_region(dev, n)); +} + +void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev, + const char *name, hwaddr addr, uint64_t size) +{ + qdev_prop_set_string(DEVICE(dev), "name", name); + qdev_prop_set_uint64(DEVICE(dev), "size", size); + sysbus_realize(dev, &error_abort); + + memory_region_add_subregion_overlap(s->memory, addr, + sysbus_mmio_get_region(dev, 0), -1000); +} diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 48538c9360ce..3c2a4160cd1a 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -23,6 +23,13 @@ /* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */ #define BCM2835_SDHC_CAPAREG 0x52134b4 +/* + * According to Linux driver & DTS, dma channels 0--10 have separate IRQ, + * while channels 11--14 share one IRQ: + */ +#define SEPARATE_DMA_IRQ_MAX 10 +#define ORGATED_DMA_IRQ_COUNT 4 + static void create_unimp(BCM2835PeripheralState *ps, UnimplementedDeviceState *uds, const char *name, hwaddr ofs, hwaddr size) @@ -101,6 +108,11 @@ static void bcm2835_peripherals_init(Object *obj) /* DMA Channels */ object_initialize_child(obj, "dma", &s->dma, TYPE_BCM2835_DMA); + object_initialize_child(obj, "orgated-dma-irq", + &s->orgated_dma_irq, TYPE_OR_IRQ); + object_property_set_int(OBJECT(&s->orgated_dma_irq), "num-lines", + ORGATED_DMA_IRQ_COUNT, &error_abort); + object_property_add_const_link(OBJECT(&s->dma), "dma-mr", OBJECT(&s->gpu_bus_mr)); @@ -322,12 +334,24 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1)); - for (n = 0; n <= 12; n++) { + for (n = 0; n <= SEPARATE_DMA_IRQ_MAX; n++) { sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n, qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_DMA0 + n)); } + if (!qdev_realize(DEVICE(&s->orgated_dma_irq), NULL, errp)) { + return; + } + for (n = 0; n < ORGATED_DMA_IRQ_COUNT; n++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), + SEPARATE_DMA_IRQ_MAX + 1 + n, + qdev_get_gpio_in(DEVICE(&s->orgated_dma_irq), n)); + } + qdev_connect_gpio_out(DEVICE(&s->orgated_dma_irq), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), + BCM2835_IC_GPU_IRQ, + INTERRUPT_DMA0 + SEPARATE_DMA_IRQ_MAX + 1)); /* THERMAL */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->thermal), errp)) { diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 24354338cad9..f894338fc6a3 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -16,7 +16,7 @@ #include "hw/arm/raspi_platform.h" #include "hw/sysbus.h" -typedef struct BCM283XClass { +struct BCM283XClass { /*< private >*/ DeviceClass parent_class; /*< public >*/ @@ -26,12 +26,7 @@ typedef struct BCM283XClass { hwaddr peri_base; /* Peripheral base address seen by the CPU */ hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */ int clusterid; -} BCM283XClass; - -#define BCM283X_CLASS(klass) \ - OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X) -#define BCM283X_GET_CLASS(obj) \ - OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X) +}; static Property bcm2836_enabled_cores_property = DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0); diff --git a/hw/arm/boot.c b/hw/arm/boot.c index a47f38dfc905..3d7d11f782fe 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -656,15 +656,17 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, } if (binfo->initrd_size) { - rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", - binfo->initrd_start); + rc = qemu_fdt_setprop_sized_cells(fdt, "/chosen", "linux,initrd-start", + acells, binfo->initrd_start); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); goto fail; } - rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", - binfo->initrd_start + binfo->initrd_size); + rc = qemu_fdt_setprop_sized_cells(fdt, "/chosen", "linux,initrd-end", + acells, + binfo->initrd_start + + binfo->initrd_size); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); goto fail; @@ -683,6 +685,8 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, * the DTB is copied again upon reset, even if addr points into RAM. */ rom_add_blob_fixed_as("dtb", fdt, size, addr, as); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, + rom_ptr_for_as(as, addr, size)); g_free(fdt); @@ -761,7 +765,16 @@ static void do_cpu_reset(void *opaque) env->cp15.scr_el3 |= SCR_ATA; } if (cpu_isar_feature(aa64_sve, cpu)) { - env->cp15.cptr_el[3] |= CPTR_EZ; + env->cp15.cptr_el[3] |= R_CPTR_EL3_EZ_MASK; + env->vfp.zcr_el[3] = 0xf; + } + if (cpu_isar_feature(aa64_sme, cpu)) { + env->cp15.cptr_el[3] |= R_CPTR_EL3_ESM_MASK; + env->cp15.scr_el3 |= SCR_ENTP2; + env->vfp.smcr_el[3] = 0xf; + } + if (cpu_isar_feature(aa64_hcx, cpu)) { + env->cp15.scr_el3 |= SCR_HXEN; } /* AArch64 kernels never boot in secure mode */ assert(!info->secure_boot); @@ -818,55 +831,6 @@ static void do_cpu_reset(void *opaque) } } -/** - * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified - * by key. - * @fw_cfg: The firmware config instance to store the data in. - * @size_key: The firmware config key to store the size of the loaded - * data under, with fw_cfg_add_i32(). - * @data_key: The firmware config key to store the loaded data under, - * with fw_cfg_add_bytes(). - * @image_name: The name of the image file to load. If it is NULL, the - * function returns without doing anything. - * @try_decompress: Whether the image should be decompressed (gunzipped) before - * adding it to fw_cfg. If decompression fails, the image is - * loaded as-is. - * - * In case of failure, the function prints an error message to stderr and the - * process exits with status 1. - */ -static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, - uint16_t data_key, const char *image_name, - bool try_decompress) -{ - size_t size = -1; - uint8_t *data; - - if (image_name == NULL) { - return; - } - - if (try_decompress) { - size = load_image_gzipped_buffer(image_name, - LOAD_IMAGE_MAX_GUNZIP_BYTES, &data); - } - - if (size == (size_t)-1) { - gchar *contents; - gsize length; - - if (!g_file_get_contents(image_name, &contents, &length, NULL)) { - error_report("failed to load \"%s\"", image_name); - exit(1); - } - size = length; - data = (uint8_t *)contents; - } - - fw_cfg_add_i32(fw_cfg, size_key, size); - fw_cfg_add_bytes(fw_cfg, data_key, data, size); -} - static int do_arm_linux_init(Object *obj, void *opaque) { if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) { @@ -881,7 +845,7 @@ static int do_arm_linux_init(Object *obj, void *opaque) return 0; } -static int64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, +static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int elf_machine, AddressSpace *as) { @@ -892,7 +856,7 @@ static int64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, } elf_header; int data_swab = 0; bool big_endian; - int64_t ret = -1; + ssize_t ret = -1; Error *err = NULL; @@ -1014,7 +978,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, /* Set up for a direct boot of a kernel image file. */ CPUState *cs; AddressSpace *as = arm_boot_address_space(cpu, info); - int kernel_size; + ssize_t kernel_size; int initrd_size; int is_linux = 0; uint64_t elf_entry; @@ -1093,7 +1057,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, if (kernel_size > info->ram_size) { error_report("kernel '%s' is too large to fit in RAM " - "(kernel size %d, RAM size %" PRId64 ")", + "(kernel size %zd, RAM size %" PRId64 ")", info->kernel_filename, kernel_size, info->ram_size); exit(1); } diff --git a/hw/arm/collie.c b/hw/arm/collie.c index 8df31e27932a..9edff593708e 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -20,6 +20,10 @@ #include "cpu.h" #include "qom/object.h" +#define RAM_SIZE (512 * MiB) +#define FLASH_SIZE (32 * MiB) +#define FLASH_SECTOR_SIZE (64 * KiB) + struct CollieMachineState { MachineState parent; @@ -31,12 +35,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(CollieMachineState, COLLIE_MACHINE) static struct arm_boot_info collie_binfo = { .loader_start = SA_SDCS0, - .ram_size = 0x20000000, + .ram_size = RAM_SIZE, }; static void collie_init(MachineState *machine) { - DriveInfo *dinfo; MachineClass *mc = MACHINE_GET_CLASS(machine); CollieMachineState *cms = COLLIE_MACHINE(machine); @@ -51,15 +54,13 @@ static void collie_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), SA_SDCS0, machine->ram); - dinfo = drive_get(IF_PFLASH, 0, 0); - pflash_cfi01_register(SA_CS0, "collie.fl1", 0x02000000, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - 64 * KiB, 4, 0x00, 0x00, 0x00, 0x00, 0); - - dinfo = drive_get(IF_PFLASH, 0, 1); - pflash_cfi01_register(SA_CS1, "collie.fl2", 0x02000000, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - 64 * KiB, 4, 0x00, 0x00, 0x00, 0x00, 0); + for (unsigned i = 0; i < 2; i++) { + DriveInfo *dinfo = drive_get(IF_PFLASH, 0, i); + pflash_cfi01_register(i ? SA_CS1 : SA_CS0, + i ? "collie.fl2" : "collie.fl1", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + FLASH_SECTOR_SIZE, 4, 0x00, 0x00, 0x00, 0x00, 0); + } sysbus_create_simple("scoop", 0x40800000, NULL); @@ -75,7 +76,7 @@ static void collie_machine_class_init(ObjectClass *oc, void *data) mc->init = collie_init; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("sa1110"); - mc->default_ram_size = 0x20000000; + mc->default_ram_size = RAM_SIZE; mc->default_ram_id = "strongarm.sdram"; } diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 5e3372a3c7bd..71a7df150833 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -20,6 +20,7 @@ #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-a10.h" +#include "hw/i2c/i2c.h" static struct arm_boot_info cubieboard_binfo = { .loader_start = AW_A10_SDRAM_BASE, @@ -34,6 +35,7 @@ static void cubieboard_init(MachineState *machine) BlockBackend *blk; BusState *bus; DeviceState *carddev; + I2CBus *i2c; /* BIOS is not supported by this board */ if (machine->firmware) { @@ -80,6 +82,10 @@ static void cubieboard_init(MachineState *machine) exit(1); } + /* Connect AXP 209 */ + i2c = I2C_BUS(qdev_get_child_bus(DEVICE(&a10->i2c0), "i2c")); + i2c_slave_create_simple(i2c, "axp209_pmu", 0x34); + /* Retrieve SD bus */ di = drive_get(IF_SD, 0, 0); blk = di ? blk_by_legacy_dinfo(di) : NULL; @@ -93,6 +99,11 @@ static void cubieboard_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, machine->ram); + /* Load target kernel or start using BootROM */ + if (!machine->kernel_filename && blk && blk_is_available(blk)) { + /* Use Boot ROM to copy data from SD card to SRAM */ + allwinner_a10_bootrom_setup(a10, blk); + } /* TODO create and connect IDE devices for ide_drive_get() */ cubieboard_binfo.ram_size = machine->ram_size; diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 614232165cdc..6df554797734 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -39,10 +39,7 @@ static void digic_init(Object *obj) object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm946")); for (i = 0; i < DIGIC4_NB_TIMERS; i++) { -#define DIGIC_TIMER_NAME_MLEN 11 - char name[DIGIC_TIMER_NAME_MLEN]; - - snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i); + g_autofree char *name = g_strdup_printf("timer[%d]", i); object_initialize_child(obj, name, &s->timer[i], TYPE_DIGIC_TIMER); } diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 0299e81f853f..8dafa2215b62 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -101,6 +101,348 @@ #define EXYNOS4210_PL330_BASE1_ADDR 0x12690000 #define EXYNOS4210_PL330_BASE2_ADDR 0x12850000 +enum ExtGicId { + EXT_GIC_ID_MDMA_LCD0 = 66, + EXT_GIC_ID_PDMA0, + EXT_GIC_ID_PDMA1, + EXT_GIC_ID_TIMER0, + EXT_GIC_ID_TIMER1, + EXT_GIC_ID_TIMER2, + EXT_GIC_ID_TIMER3, + EXT_GIC_ID_TIMER4, + EXT_GIC_ID_MCT_L0, + EXT_GIC_ID_WDT, + EXT_GIC_ID_RTC_ALARM, + EXT_GIC_ID_RTC_TIC, + EXT_GIC_ID_GPIO_XB, + EXT_GIC_ID_GPIO_XA, + EXT_GIC_ID_MCT_L1, + EXT_GIC_ID_IEM_APC, + EXT_GIC_ID_IEM_IEC, + EXT_GIC_ID_NFC, + EXT_GIC_ID_UART0, + EXT_GIC_ID_UART1, + EXT_GIC_ID_UART2, + EXT_GIC_ID_UART3, + EXT_GIC_ID_UART4, + EXT_GIC_ID_MCT_G0, + EXT_GIC_ID_I2C0, + EXT_GIC_ID_I2C1, + EXT_GIC_ID_I2C2, + EXT_GIC_ID_I2C3, + EXT_GIC_ID_I2C4, + EXT_GIC_ID_I2C5, + EXT_GIC_ID_I2C6, + EXT_GIC_ID_I2C7, + EXT_GIC_ID_SPI0, + EXT_GIC_ID_SPI1, + EXT_GIC_ID_SPI2, + EXT_GIC_ID_MCT_G1, + EXT_GIC_ID_USB_HOST, + EXT_GIC_ID_USB_DEVICE, + EXT_GIC_ID_MODEMIF, + EXT_GIC_ID_HSMMC0, + EXT_GIC_ID_HSMMC1, + EXT_GIC_ID_HSMMC2, + EXT_GIC_ID_HSMMC3, + EXT_GIC_ID_SDMMC, + EXT_GIC_ID_MIPI_CSI_4LANE, + EXT_GIC_ID_MIPI_DSI_4LANE, + EXT_GIC_ID_MIPI_CSI_2LANE, + EXT_GIC_ID_MIPI_DSI_2LANE, + EXT_GIC_ID_ONENAND_AUDI, + EXT_GIC_ID_ROTATOR, + EXT_GIC_ID_FIMC0, + EXT_GIC_ID_FIMC1, + EXT_GIC_ID_FIMC2, + EXT_GIC_ID_FIMC3, + EXT_GIC_ID_JPEG, + EXT_GIC_ID_2D, + EXT_GIC_ID_PCIe, + EXT_GIC_ID_MIXER, + EXT_GIC_ID_HDMI, + EXT_GIC_ID_HDMI_I2C, + EXT_GIC_ID_MFC, + EXT_GIC_ID_TVENC, +}; + +enum ExtInt { + EXT_GIC_ID_EXTINT0 = 48, + EXT_GIC_ID_EXTINT1, + EXT_GIC_ID_EXTINT2, + EXT_GIC_ID_EXTINT3, + EXT_GIC_ID_EXTINT4, + EXT_GIC_ID_EXTINT5, + EXT_GIC_ID_EXTINT6, + EXT_GIC_ID_EXTINT7, + EXT_GIC_ID_EXTINT8, + EXT_GIC_ID_EXTINT9, + EXT_GIC_ID_EXTINT10, + EXT_GIC_ID_EXTINT11, + EXT_GIC_ID_EXTINT12, + EXT_GIC_ID_EXTINT13, + EXT_GIC_ID_EXTINT14, + EXT_GIC_ID_EXTINT15 +}; + +/* + * External GIC sources which are not from External Interrupt Combiner or + * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ, + * which is INTG16 in Internal Interrupt Combiner. + */ + +static const uint32_t +combiner_grp_to_gic_id[64 - EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { + /* int combiner groups 16-19 */ + { }, { }, { }, { }, + /* int combiner group 20 */ + { 0, EXT_GIC_ID_MDMA_LCD0 }, + /* int combiner group 21 */ + { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 }, + /* int combiner group 22 */ + { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2, + EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 }, + /* int combiner group 23 */ + { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC }, + /* int combiner group 24 */ + { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA }, + /* int combiner group 25 */ + { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC }, + /* int combiner group 26 */ + { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3, + EXT_GIC_ID_UART4 }, + /* int combiner group 27 */ + { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3, + EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, + EXT_GIC_ID_I2C7 }, + /* int combiner group 28 */ + { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, + /* int combiner group 29 */ + { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, + EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, + /* int combiner group 30 */ + { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE }, + /* int combiner group 31 */ + { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE }, + /* int combiner group 32 */ + { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 }, + /* int combiner group 33 */ + { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 }, + /* int combiner group 34 */ + { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC }, + /* int combiner group 35 */ + { 0, 0, 0, EXT_GIC_ID_MCT_L1 }, + /* int combiner group 36 */ + { EXT_GIC_ID_MIXER }, + /* int combiner group 37 */ + { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6, + EXT_GIC_ID_EXTINT7 }, + /* groups 38-50 */ + { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, + /* int combiner group 51 */ + { EXT_GIC_ID_MCT_L0 }, + /* group 52 */ + { }, + /* int combiner group 53 */ + { EXT_GIC_ID_WDT }, + /* groups 54-63 */ + { }, { }, { }, { }, { }, { }, { }, { }, { }, { } +}; + +#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp) * 8 + (bit)) +#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8) +#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \ + ((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq)) + +/* + * Some interrupt lines go to multiple combiner inputs. + * This data structure defines those: each array element is + * a list of combiner inputs which are connected together; + * the one with the smallest interrupt ID value must be first. + * As with combiner_grp_to_gic_id[], we rely on (0, 0) not being + * wired to anything so we can use 0 as a terminator. + */ +#define IRQNO(G, B) EXYNOS4210_COMBINER_GET_IRQ_NUM(G, B) +#define IRQNONE 0 + +#define COMBINERMAP_SIZE 16 + +static const int combinermap[COMBINERMAP_SIZE][6] = { + /* MDNIE_LCD1 */ + { IRQNO(0, 4), IRQNO(1, 0), IRQNONE }, + { IRQNO(0, 5), IRQNO(1, 1), IRQNONE }, + { IRQNO(0, 6), IRQNO(1, 2), IRQNONE }, + { IRQNO(0, 7), IRQNO(1, 3), IRQNONE }, + /* TMU */ + { IRQNO(2, 4), IRQNO(3, 4), IRQNONE }, + { IRQNO(2, 5), IRQNO(3, 5), IRQNONE }, + { IRQNO(2, 6), IRQNO(3, 6), IRQNONE }, + { IRQNO(2, 7), IRQNO(3, 7), IRQNONE }, + /* LCD1 */ + { IRQNO(11, 4), IRQNO(12, 0), IRQNONE }, + { IRQNO(11, 5), IRQNO(12, 1), IRQNONE }, + { IRQNO(11, 6), IRQNO(12, 2), IRQNONE }, + { IRQNO(11, 7), IRQNO(12, 3), IRQNONE }, + /* Multi-core timer */ + { IRQNO(1, 4), IRQNO(12, 4), IRQNO(35, 4), IRQNO(51, 4), IRQNO(53, 4), IRQNONE }, + { IRQNO(1, 5), IRQNO(12, 5), IRQNO(35, 5), IRQNO(51, 5), IRQNO(53, 5), IRQNONE }, + { IRQNO(1, 6), IRQNO(12, 6), IRQNO(35, 6), IRQNO(51, 6), IRQNO(53, 6), IRQNONE }, + { IRQNO(1, 7), IRQNO(12, 7), IRQNO(35, 7), IRQNO(51, 7), IRQNO(53, 7), IRQNONE }, +}; + +#undef IRQNO + +static const int *combinermap_entry(int irq) +{ + /* + * If the interrupt number passed in is the first entry in some + * line of the combinermap, return a pointer to that line; + * otherwise return NULL. + */ + int i; + for (i = 0; i < COMBINERMAP_SIZE; i++) { + if (combinermap[i][0] == irq) { + return combinermap[i]; + } + } + return NULL; +} + +static int mapline_size(const int *mapline) +{ + /* Return number of entries in this mapline in total */ + int i = 0; + + if (!mapline) { + /* Not in the map? IRQ goes to exactly one combiner input */ + return 1; + } + while (*mapline != IRQNONE) { + mapline++; + i++; + } + return i; +} + +/* + * Initialize board IRQs. + * These IRQs contain splitted Int/External Combiner and External Gic IRQs. + */ +static void exynos4210_init_board_irqs(Exynos4210State *s) +{ + uint32_t grp, bit, irq_id, n; + DeviceState *extgicdev = DEVICE(&s->ext_gic); + DeviceState *intcdev = DEVICE(&s->int_combiner); + DeviceState *extcdev = DEVICE(&s->ext_combiner); + int splitcount = 0; + DeviceState *splitter; + const int *mapline; + int numlines, splitin, in; + + for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) { + irq_id = 0; + if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4)) { + /* MCT_G0 is passed to External GIC */ + irq_id = EXT_GIC_ID_MCT_G0; + } + if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5)) { + /* MCT_G1 is passed to External and GIC */ + irq_id = EXT_GIC_ID_MCT_G1; + } + + if (s->irq_table[n]) { + /* + * This must be some non-first entry in a combinermap line, + * and we've already filled it in. + */ + continue; + } + mapline = combinermap_entry(n); + /* + * We need to connect the IRQ to multiple inputs on both combiners + * and possibly also to the external GIC. + */ + numlines = 2 * mapline_size(mapline); + if (irq_id) { + numlines++; + } + assert(splitcount < EXYNOS4210_NUM_SPLITTERS); + splitter = DEVICE(&s->splitter[splitcount]); + qdev_prop_set_uint16(splitter, "num-lines", numlines); + qdev_realize(splitter, NULL, &error_abort); + splitcount++; + + in = n; + splitin = 0; + for (;;) { + s->irq_table[in] = qdev_get_gpio_in(splitter, 0); + qdev_connect_gpio_out(splitter, splitin, + qdev_get_gpio_in(intcdev, in)); + qdev_connect_gpio_out(splitter, splitin + 1, + qdev_get_gpio_in(extcdev, in)); + splitin += 2; + if (!mapline) { + break; + } + mapline++; + in = *mapline; + if (in == IRQNONE) { + break; + } + } + if (irq_id) { + qdev_connect_gpio_out(splitter, splitin, + qdev_get_gpio_in(extgicdev, irq_id - 32)); + } + } + for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) { + /* these IDs are passed to Internal Combiner and External GIC */ + grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n); + bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); + irq_id = combiner_grp_to_gic_id[grp - + EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit]; + + if (s->irq_table[n]) { + /* + * This must be some non-first entry in a combinermap line, + * and we've already filled it in. + */ + continue; + } + + if (irq_id) { + assert(splitcount < EXYNOS4210_NUM_SPLITTERS); + splitter = DEVICE(&s->splitter[splitcount]); + qdev_prop_set_uint16(splitter, "num-lines", 2); + qdev_realize(splitter, NULL, &error_abort); + splitcount++; + s->irq_table[n] = qdev_get_gpio_in(splitter, 0); + qdev_connect_gpio_out(splitter, 0, qdev_get_gpio_in(intcdev, n)); + qdev_connect_gpio_out(splitter, 1, + qdev_get_gpio_in(extgicdev, irq_id - 32)); + } else { + s->irq_table[n] = qdev_get_gpio_in(intcdev, n); + } + } + /* + * We check this here to avoid a more obscure assert later when + * qdev_assert_realized_properly() checks that we realized every + * child object we initialized. + */ + assert(splitcount == EXYNOS4210_NUM_SPLITTERS); +} + +/* + * Get IRQ number from exynos4210 IRQ subsystem stub. + * To identify IRQ source use internal combiner group and bit number + * grp - group number + * bit - bit number inside group + */ +uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) +{ + return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit); +} + static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; @@ -205,7 +547,6 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) { Exynos4210State *s = EXYNOS4210_SOC(socdev); MemoryRegion *system_mem = get_system_memory(); - qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; SysBusDevice *busdev; DeviceState *dev, *uart[4], *pl330[3]; int i, n; @@ -229,81 +570,63 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); } - /*** IRQs ***/ - - s->irq_table = exynos4210_init_irq(&s->irqs); - /* IRQ Gate */ for (i = 0; i < EXYNOS4210_NCPUS; i++) { - dev = qdev_new("exynos4210.irq_gate"); - qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - /* Get IRQ Gate input in gate_irq */ - for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { - gate_irq[i][n] = qdev_get_gpio_in(dev, n); - } - busdev = SYS_BUS_DEVICE(dev); - - /* Connect IRQ Gate output to CPU's IRQ line */ - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ)); + DeviceState *orgate = DEVICE(&s->cpu_irq_orgate[i]); + object_property_set_int(OBJECT(orgate), "num-lines", + EXYNOS4210_IRQ_GATE_NINPUTS, + &error_abort); + qdev_realize(orgate, NULL, &error_abort); + qdev_connect_gpio_out(orgate, 0, + qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ)); } /* Private memory region and Internal GIC */ - dev = qdev_new(TYPE_A9MPCORE_PRIV); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + qdev_prop_set_uint32(DEVICE(&s->a9mpcore), "num-cpu", EXYNOS4210_NCPUS); + busdev = SYS_BUS_DEVICE(&s->a9mpcore); + sysbus_realize(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][0]); - } - for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) { - s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n); + sysbus_connect_irq(busdev, n, + qdev_get_gpio_in(DEVICE(&s->cpu_irq_orgate[n]), 0)); } /* Cache controller */ sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); /* External GIC */ - dev = qdev_new("exynos4210.gic"); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + qdev_prop_set_uint32(DEVICE(&s->ext_gic), "num-cpu", EXYNOS4210_NCPUS); + busdev = SYS_BUS_DEVICE(&s->ext_gic); + sysbus_realize(busdev, &error_fatal); /* Map CPU interface */ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); /* Map Distributer interface */ sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][1]); - } - for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) { - s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n); + sysbus_connect_irq(busdev, n, + qdev_get_gpio_in(DEVICE(&s->cpu_irq_orgate[n]), 1)); } /* Internal Interrupt Combiner */ - dev = qdev_new("exynos4210.combiner"); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + busdev = SYS_BUS_DEVICE(&s->int_combiner); + sysbus_realize(busdev, &error_fatal); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); + sysbus_connect_irq(busdev, n, + qdev_get_gpio_in(DEVICE(&s->a9mpcore), n)); } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 0); sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); /* External Interrupt Combiner */ - dev = qdev_new("exynos4210.combiner"); - qdev_prop_set_uint32(dev, "external", 1); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + qdev_prop_set_uint32(DEVICE(&s->ext_combiner), "external", 1); + busdev = SYS_BUS_DEVICE(&s->ext_combiner); + sysbus_realize(busdev, &error_fatal); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); + sysbus_connect_irq(busdev, n, qdev_get_gpio_in(DEVICE(&s->ext_gic), n)); } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 1); sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR); /* Initialize board IRQs. */ - exynos4210_init_board_irqs(&s->irqs); + exynos4210_init_board_irqs(s); /*** Memory ***/ @@ -488,6 +811,23 @@ static void exynos4210_init(Object *obj) object_initialize_child(obj, name, orgate, TYPE_OR_IRQ); g_free(name); } + + for (i = 0; i < ARRAY_SIZE(s->cpu_irq_orgate); i++) { + g_autofree char *name = g_strdup_printf("cpu-irq-orgate%d", i); + object_initialize_child(obj, name, &s->cpu_irq_orgate[i], TYPE_OR_IRQ); + } + + for (i = 0; i < ARRAY_SIZE(s->splitter); i++) { + g_autofree char *name = g_strdup_printf("irq-splitter%d", i); + object_initialize_child(obj, name, &s->splitter[i], TYPE_SPLIT_IRQ); + } + + object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV); + object_initialize_child(obj, "ext-gic", &s->ext_gic, TYPE_EXYNOS4210_GIC); + object_initialize_child(obj, "int-combiner", &s->int_combiner, + TYPE_EXYNOS4210_COMBINER); + object_initialize_child(obj, "ext-combiner", &s->ext_combiner, + TYPE_EXYNOS4210_COMBINER); } static void exynos4210_class_init(ObjectClass *klass, void *data) diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c new file mode 100644 index 000000000000..90c04bbc3389 --- /dev/null +++ b/hw/arm/fby35.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com) + * + * 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/units.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" +#include "hw/boards.h" +#include "hw/qdev-clock.h" +#include "hw/arm/aspeed_soc.h" +#include "hw/arm/boot.h" + +#define TYPE_FBY35 MACHINE_TYPE_NAME("fby35") +OBJECT_DECLARE_SIMPLE_TYPE(Fby35State, FBY35); + +struct Fby35State { + MachineState parent_obj; + + MemoryRegion bmc_memory; + MemoryRegion bmc_dram; + MemoryRegion bmc_boot_rom; + MemoryRegion bic_memory; + Clock *bic_sysclk; + + AspeedSoCState bmc; + AspeedSoCState bic; + + bool mmio_exec; +}; + +#define FBY35_BMC_RAM_SIZE (2 * GiB) +#define FBY35_BMC_FIRMWARE_ADDR 0x0 + +static void fby35_bmc_write_boot_rom(DriveInfo *dinfo, MemoryRegion *mr, + hwaddr offset, size_t rom_size, + Error **errp) +{ + BlockBackend *blk = blk_by_legacy_dinfo(dinfo); + g_autofree void *storage = NULL; + int64_t size; + + /* + * The block backend size should have already been 'validated' by + * the creation of the m25p80 object. + */ + size = blk_getlength(blk); + if (size <= 0) { + error_setg(errp, "failed to get flash size"); + return; + } + + if (rom_size > size) { + rom_size = size; + } + + storage = g_malloc0(rom_size); + if (blk_pread(blk, 0, rom_size, storage, 0) < 0) { + error_setg(errp, "failed to read the initial flash content"); + return; + } + + /* TODO: find a better way to install the ROM */ + memcpy(memory_region_get_ram_ptr(mr) + offset, storage, rom_size); +} + +static void fby35_bmc_init(Fby35State *s) +{ + DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); + + 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_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), + &error_abort); + object_property_set_link(OBJECT(&s->bmc), "dram", OBJECT(&s->bmc_dram), + &error_abort); + object_property_set_int(OBJECT(&s->bmc), "hw-strap1", 0x000000C0, + &error_abort); + object_property_set_int(OBJECT(&s->bmc), "hw-strap2", 0x00000003, + &error_abort); + aspeed_soc_uart_set_chr(&s->bmc, ASPEED_DEV_UART5, serial_hd(0)); + qdev_realize(DEVICE(&s->bmc), NULL, &error_abort); + + aspeed_board_init_flashes(&s->bmc.fmc, "n25q00", 2, 0); + + /* Install first FMC flash content as a boot rom. */ + if (drive0) { + AspeedSMCFlash *fl = &s->bmc.fmc.flashes[0]; + MemoryRegion *boot_rom = g_new(MemoryRegion, 1); + uint64_t size = memory_region_size(&fl->mmio); + + if (s->mmio_exec) { + memory_region_init_alias(boot_rom, NULL, "aspeed.boot_rom", + &fl->mmio, 0, size); + memory_region_add_subregion(&s->bmc_memory, FBY35_BMC_FIRMWARE_ADDR, + boot_rom); + } else { + + memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom", + size, &error_abort); + memory_region_add_subregion(&s->bmc_memory, FBY35_BMC_FIRMWARE_ADDR, + boot_rom); + fby35_bmc_write_boot_rom(drive0, boot_rom, FBY35_BMC_FIRMWARE_ADDR, + size, &error_abort); + } + } +} + +static void fby35_bic_init(Fby35State *s) +{ + s->bic_sysclk = clock_new(OBJECT(s), "SYSCLK"); + clock_set_hz(s->bic_sysclk, 200000000ULL); + + 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); + aspeed_soc_uart_set_chr(&s->bic, ASPEED_DEV_UART5, serial_hd(1)); + qdev_realize(DEVICE(&s->bic), NULL, &error_abort); + + aspeed_board_init_flashes(&s->bic.fmc, "sst25vf032b", 2, 2); + aspeed_board_init_flashes(&s->bic.spi[0], "sst25vf032b", 2, 4); + aspeed_board_init_flashes(&s->bic.spi[1], "sst25vf032b", 2, 6); +} + +static void fby35_init(MachineState *machine) +{ + Fby35State *s = FBY35(machine); + + fby35_bmc_init(s); + fby35_bic_init(s); +} + + +static bool fby35_get_mmio_exec(Object *obj, Error **errp) +{ + return FBY35(obj)->mmio_exec; +} + +static void fby35_set_mmio_exec(Object *obj, bool value, Error **errp) +{ + FBY35(obj)->mmio_exec = value; +} + +static void fby35_instance_init(Object *obj) +{ + FBY35(obj)->mmio_exec = false; +} + +static void fby35_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Meta Platforms fby35"; + mc->init = fby35_init; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->min_cpus = mc->max_cpus = mc->default_cpus = 3; + + object_class_property_add_bool(oc, "execute-in-place", + fby35_get_mmio_exec, + fby35_set_mmio_exec); + object_class_property_set_description(oc, "execute-in-place", + "boot directly from CE0 flash device"); +} + +static const TypeInfo fby35_types[] = { + { + .name = MACHINE_TYPE_NAME("fby35"), + .parent = TYPE_MACHINE, + .class_init = fby35_class_init, + .instance_size = sizeof(Fby35State), + .instance_init = fby35_instance_init, + }, +}; + +DEFINE_TYPES(fby35_types); diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index f18971232947..d88d6cc1c5f9 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -81,7 +81,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) { snprintf(name, NAME_SIZE, "gpt%d", i); - object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX7_GPT); + object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX6UL_GPT); } /* diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index cc6fdb9373fa..afc74807990f 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -219,9 +219,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_GPT4_ADDR, }; + static const int FSL_IMX7_GPTn_IRQ[FSL_IMX7_NUM_GPTS] = { + FSL_IMX7_GPT1_IRQ, + FSL_IMX7_GPT2_IRQ, + FSL_IMX7_GPT3_IRQ, + FSL_IMX7_GPT4_IRQ, + }; + s->gpt[i].ccm = IMX_CCM(&s->ccm); sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->a7mpcore), + FSL_IMX7_GPTn_IRQ[i])); } for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) { @@ -235,8 +245,37 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_GPIO7_ADDR, }; + static const int FSL_IMX7_GPIOn_LOW_IRQ[FSL_IMX7_NUM_GPIOS] = { + FSL_IMX7_GPIO1_LOW_IRQ, + FSL_IMX7_GPIO2_LOW_IRQ, + FSL_IMX7_GPIO3_LOW_IRQ, + FSL_IMX7_GPIO4_LOW_IRQ, + FSL_IMX7_GPIO5_LOW_IRQ, + FSL_IMX7_GPIO6_LOW_IRQ, + FSL_IMX7_GPIO7_LOW_IRQ, + }; + + static const int FSL_IMX7_GPIOn_HIGH_IRQ[FSL_IMX7_NUM_GPIOS] = { + FSL_IMX7_GPIO1_HIGH_IRQ, + FSL_IMX7_GPIO2_HIGH_IRQ, + FSL_IMX7_GPIO3_HIGH_IRQ, + FSL_IMX7_GPIO4_HIGH_IRQ, + FSL_IMX7_GPIO5_HIGH_IRQ, + FSL_IMX7_GPIO6_HIGH_IRQ, + FSL_IMX7_GPIO7_HIGH_IRQ, + }; + sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, FSL_IMX7_GPIOn_ADDR[i]); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, + FSL_IMX7_GPIOn_ADDR[i]); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, + qdev_get_gpio_in(DEVICE(&s->a7mpcore), + FSL_IMX7_GPIOn_LOW_IRQ[i])); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1, + qdev_get_gpio_in(DEVICE(&s->a7mpcore), + FSL_IMX7_GPIOn_HIGH_IRQ[i])); } /* diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c index 3a4bc332c42d..2ca4140c9fcc 100644 --- a/hw/arm/gumstix.c +++ b/hw/arm/gumstix.c @@ -10,7 +10,7 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ - + /* * Example usage: * @@ -35,6 +35,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qemu/error-report.h" #include "hw/arm/pxa.h" #include "net/net.h" @@ -45,18 +46,20 @@ #include "sysemu/qtest.h" #include "cpu.h" -static const int sector_len = 128 * 1024; +#define CONNEX_FLASH_SIZE (16 * MiB) +#define CONNEX_RAM_SIZE (64 * MiB) + +#define VERDEX_FLASH_SIZE (32 * MiB) +#define VERDEX_RAM_SIZE (256 * MiB) + +#define FLASH_SECTOR_SIZE (128 * KiB) static void connex_init(MachineState *machine) { PXA2xxState *cpu; DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - uint32_t connex_rom = 0x01000000; - uint32_t connex_ram = 0x04000000; - - cpu = pxa255_init(address_space_mem, connex_ram); + cpu = pxa255_init(CONNEX_RAM_SIZE); dinfo = drive_get(IF_PFLASH, 0, 0); if (!dinfo && !qtest_enabled()) { @@ -65,12 +68,10 @@ static void connex_init(MachineState *machine) exit(1); } - if (!pflash_cfi01_register(0x00000000, "connext.rom", connex_rom, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 2, 0, 0, 0, 0, 0)) { - error_report("Error registering flash memory"); - exit(1); - } + /* Numonyx RC28F128J3F75 */ + pflash_cfi01_register(0x00000000, "connext.rom", CONNEX_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0); /* Interrupt line of NIC is connected to GPIO line 36 */ smc91c111_init(&nd_table[0], 0x04000300, @@ -81,12 +82,8 @@ static void verdex_init(MachineState *machine) { PXA2xxState *cpu; DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - - uint32_t verdex_rom = 0x02000000; - uint32_t verdex_ram = 0x10000000; - cpu = pxa270_init(address_space_mem, verdex_ram, machine->cpu_type); + cpu = pxa270_init(VERDEX_RAM_SIZE, machine->cpu_type); dinfo = drive_get(IF_PFLASH, 0, 0); if (!dinfo && !qtest_enabled()) { @@ -95,12 +92,10 @@ static void verdex_init(MachineState *machine) exit(1); } - if (!pflash_cfi01_register(0x00000000, "verdex.rom", verdex_rom, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 2, 0, 0, 0, 0, 0)) { - error_report("Error registering flash memory"); - exit(1); - } + /* Micron RC28F256P30TFA */ + pflash_cfi01_register(0x00000000, "verdex.rom", VERDEX_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0); /* Interrupt line of NIC is connected to GPIO line 99 */ smc91c111_init(&nd_table[0], 0x04000300, @@ -126,7 +121,7 @@ static void verdex_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "Gumstix Verdex (PXA270)"; + mc->desc = "Gumstix Verdex Pro XL6P COMs (PXA270)"; mc->init = verdex_init; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0"); diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index 8454b6545853..68329c461782 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -12,6 +12,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "hw/arm/pxa.h" @@ -99,20 +100,20 @@ static const struct keymap map[0xE0] = { enum mainstone_model_e { mainstone }; -#define MAINSTONE_RAM 0x04000000 -#define MAINSTONE_ROM 0x00800000 -#define MAINSTONE_FLASH 0x02000000 +#define MAINSTONE_RAM_SIZE (64 * MiB) +#define MAINSTONE_ROM_SIZE (8 * MiB) +#define MAINSTONE_FLASH_SIZE (32 * MiB) static struct arm_boot_info mainstone_binfo = { .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, + .ram_size = MAINSTONE_RAM_SIZE, }; -static void mainstone_common_init(MemoryRegion *address_space_mem, - MachineState *machine, +#define FLASH_SECTOR_SIZE (256 * KiB) + +static void mainstone_common_init(MachineState *machine, enum mainstone_model_e model, int arm_id) { - uint32_t sector_len = 256 * 1024; hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; PXA2xxState *mpu; DeviceState *mst_irq; @@ -121,23 +122,19 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, MemoryRegion *rom = g_new(MemoryRegion, 1); /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, - machine->cpu_type); - memory_region_init_rom(rom, NULL, "mainstone.rom", MAINSTONE_ROM, + mpu = pxa270_init(mainstone_binfo.ram_size, machine->cpu_type); + memory_region_init_rom(rom, NULL, "mainstone.rom", MAINSTONE_ROM_SIZE, &error_fatal); - memory_region_add_subregion(address_space_mem, 0, rom); + memory_region_add_subregion(get_system_memory(), 0x00000000, rom); /* There are two 32MiB flash devices on the board */ for (i = 0; i < 2; i ++) { dinfo = drive_get(IF_PFLASH, 0, i); - if (!pflash_cfi01_register(mainstone_flash_base[i], - i ? "mainstone.flash1" : "mainstone.flash0", - MAINSTONE_FLASH, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 4, 0, 0, 0, 0, 0)) { - error_report("Error registering flash memory"); - exit(1); - } + pflash_cfi01_register(mainstone_flash_base[i], + i ? "mainstone.flash1" : "mainstone.flash0", + MAINSTONE_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0); } mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, @@ -165,7 +162,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, static void mainstone_init(MachineState *machine) { - mainstone_common_init(get_system_memory(), machine, mainstone, 0x196); + mainstone_common_init(machine, mainstone, 0x196); } static void mainstone2_machine_init(MachineClass *mc) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 721a8eb8bedd..af72683dcb3e 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -1,6 +1,5 @@ arm_ss = ss.source_set() arm_ss.add(files('boot.c'), fdt) -arm_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c')) arm_ss.add(when: 'CONFIG_ARM_VIRT', if_true: files('virt.c')) arm_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c')) arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c')) @@ -13,6 +12,7 @@ arm_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c')) arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c')) arm_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c')) arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c')) +arm_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c')) arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c')) arm_ss.add(when: 'CONFIG_NSERIES', if_true: files('nseries.c')) arm_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) @@ -48,7 +48,12 @@ arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-ver arm_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c')) arm_ss.add(when: 'CONFIG_FSL_IMX31', if_true: files('fsl-imx31.c', 'kzm.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6', if_true: files('fsl-imx6.c')) -arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_soc.c', 'aspeed.c', 'aspeed_ast2600.c')) +arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( + 'aspeed_soc.c', + 'aspeed.c', + 'aspeed_ast2600.c', + 'aspeed_ast10x0.c', + 'fby35.c')) arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c')) arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c')) arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c')) @@ -58,5 +63,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) +arm_ss.add(when: 'CONFIG_NXP_RT595', if_true: files('nxp_rt595_m33.c')) hw_arch += {'arm': arm_ss} diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index e9494334ce78..50df3620882b 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 4017392bf5a9..284c09c91d33 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, @@ -1239,7 +1239,7 @@ static void mps2_set_remap(Object *obj, const char *value, Error **errp) } } -static void mps2_machine_reset(MachineState *machine) +static void mps2_machine_reset(MachineState *machine, ShutdownCause reason) { MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); @@ -1249,7 +1249,7 @@ static void mps2_machine_reset(MachineState *machine) * reset see the correct mapping. */ remap_memory(mms, mms->remap); - qemu_devices_reset(); + qemu_devices_reset(reason); } static void mps2tz_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index bb76fa688903..a86a994dbac1 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 d9f881690e02..a6df473ec90e 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 7a83f7dda7dc..6eeee57c9ddb 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/musicpal.c b/hw/arm/musicpal.c index 7c840fb4283e..73e2b7e4cef6 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -10,6 +10,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "cpu.h" #include "hw/sysbus.h" @@ -464,7 +465,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, sysbus_init_irq(dev, &s->irq); s->freq = freq; - s->ptimer = ptimer_init(mv88w8618_timer_tick, s, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(mv88w8618_timer_tick, s, PTIMER_POLICY_LEGACY); } static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, @@ -1196,6 +1197,8 @@ static const TypeInfo musicpal_key_info = { .class_init = musicpal_key_class_init, }; +#define FLASH_SECTOR_SIZE (64 * KiB) + static struct arm_boot_info musicpal_binfo = { .loader_start = 0x0, .board_id = 0x20e, @@ -1264,8 +1267,8 @@ static void musicpal_init(MachineState *machine) BlockBackend *blk = blk_by_legacy_dinfo(dinfo); flash_size = blk_getlength(blk); - if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 && - flash_size != 32*1024*1024) { + if (flash_size != 8 * MiB && flash_size != 16 * MiB && + flash_size != 32 * MiB) { error_report("Invalid flash image size"); exit(1); } @@ -1277,7 +1280,7 @@ static void musicpal_init(MachineState *machine) */ pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, "musicpal.flash", flash_size, - blk, 0x10000, + blk, FLASH_SECTOR_SIZE, MP_FLASH_SIZE_MAX / flash_size, 2, 0x00BF, 0x236D, 0x0000, 0x0000, 0x5555, 0x2AAA, 0); diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c index 3365da11bf75..83753d53a3f4 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 76cea8e4891c..515c08160540 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/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index 0678a56156f5..6bc6f5d2fe29 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -30,11 +30,25 @@ #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" -#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7 -#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff -#define QUANTA_GBS_POWER_ON_STRAPS 0x000017ff -#define KUDO_BMC_POWER_ON_STRAPS 0x00001fff -#define MORI_BMC_POWER_ON_STRAPS 0x00001fff +#define NPCM7XX_POWER_ON_STRAPS_DEFAULT ( \ + NPCM7XX_PWRON_STRAP_SPI0F18 | \ + NPCM7XX_PWRON_STRAP_SFAB | \ + NPCM7XX_PWRON_STRAP_BSPA | \ + NPCM7XX_PWRON_STRAP_FUP(FUP_NORM_UART2) | \ + NPCM7XX_PWRON_STRAP_SECEN | \ + NPCM7XX_PWRON_STRAP_HIZ | \ + NPCM7XX_PWRON_STRAP_ECC | \ + NPCM7XX_PWRON_STRAP_RESERVE1 | \ + NPCM7XX_PWRON_STRAP_J2EN | \ + NPCM7XX_PWRON_STRAP_CKFRQ(CKFRQ_DEFAULT)) + +#define NPCM750_EVB_POWER_ON_STRAPS ( \ + NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_J2EN) +#define QUANTA_GSJ_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT +#define QUANTA_GBS_POWER_ON_STRAPS ( \ + NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_SFAB) +#define KUDO_BMC_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT +#define MORI_BMC_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin"; diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 9c1cafae86be..c9df063a082e 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -230,13 +230,13 @@ static void n8x0_i2c_setup(struct n800_s *s) } /* Touchscreen and keypad controller */ -static MouseTransformInfo n800_pointercal = { +static const MouseTransformInfo n800_pointercal = { .x = 800, .y = 480, .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, }; -static MouseTransformInfo n810_pointercal = { +static const MouseTransformInfo n810_pointercal = { .x = 800, .y = 480, .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, @@ -334,7 +334,7 @@ static void n810_key_event(void *opaque, int keycode) #define M 0 -static int n810_keys[0x80] = { +static const int n810_keys[0x80] = { [0x01] = 16, /* Q */ [0x02] = 37, /* K */ [0x03] = 24, /* O */ @@ -702,7 +702,7 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) static void *mipid_init(void) { - struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s)); + struct mipid_s *s = g_malloc0(sizeof(*s)); s->id = 0x838f03; mipid_reset(s); @@ -810,7 +810,7 @@ static void n8x0_usb_setup(struct n800_s *s) /* Setup done before the main bootloader starts by some early setup code * - used when we want to run the main bootloader in emulation. This * isn't documented. */ -static uint32_t n800_pinout[104] = { +static const uint32_t n800_pinout[104] = { 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, @@ -1060,7 +1060,7 @@ static void n8x0_boot_init(void *opaque) #define OMAP_TAG_CBUS 0x4e03 #define OMAP_TAG_EM_ASIC_BB5 0x4e04 -static struct omap_gpiosw_info_s { +static const struct omap_gpiosw_info_s { const char *name; int line; int type; @@ -1078,7 +1078,7 @@ static struct omap_gpiosw_info_s { "headphone", N8X0_HEADPHONE_GPIO, OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, }, - { NULL } + { /* end of list */ } }, n810_gpiosw_info[] = { { "gps_reset", N810_GPS_RESET_GPIO, @@ -1099,10 +1099,10 @@ static struct omap_gpiosw_info_s { "slide", N810_SLIDE_GPIO, OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, }, - { NULL } + { /* end of list */ } }; -static struct omap_partition_info_s { +static const struct omap_partition_info_s { uint32_t offset; uint32_t size; int mask; @@ -1113,27 +1113,25 @@ static struct omap_partition_info_s { { 0x00080000, 0x00200000, 0x0, "kernel" }, { 0x00280000, 0x00200000, 0x3, "initfs" }, { 0x00480000, 0x0fb80000, 0x3, "rootfs" }, - - { 0, 0, 0, NULL } + { /* end of list */ } }, n810_part_info[] = { { 0x00000000, 0x00020000, 0x3, "bootloader" }, { 0x00020000, 0x00060000, 0x0, "config" }, { 0x00080000, 0x00220000, 0x0, "kernel" }, { 0x002a0000, 0x00400000, 0x0, "initfs" }, { 0x006a0000, 0x0f960000, 0x0, "rootfs" }, - - { 0, 0, 0, NULL } + { /* end of list */ } }; -static uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR }; +static const uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR }; static int n8x0_atag_setup(void *p, int model) { uint8_t *b; uint16_t *w; uint32_t *l; - struct omap_gpiosw_info_s *gpiosw; - struct omap_partition_info_s *partition; + const struct omap_gpiosw_info_s *gpiosw; + const struct omap_partition_info_s *partition; const char *tag; w = p; @@ -1300,7 +1298,7 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p) static void n8x0_init(MachineState *machine, struct arm_boot_info *binfo, int model) { - struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); + struct n800_s *s = g_malloc0(sizeof(*s)); MachineClass *mc = MACHINE_GET_CLASS(machine); if (machine->ram_size != mc->default_ram_size) { @@ -1365,7 +1363,7 @@ static void n8x0_init(MachineState *machine, } if (option_rom[0].name && - (machine->boot_order[0] == 'n' || !machine->kernel_filename)) { + (machine->boot_config.order[0] == 'n' || !machine->kernel_filename)) { uint8_t *nolo_tags = g_new(uint8_t, 0x10000); /* No, wait, better start at the ROM. */ s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; diff --git a/hw/arm/nxp_rt595_m33.c b/hw/arm/nxp_rt595_m33.c new file mode 100755 index 000000000000..54c7ca9719bf --- /dev/null +++ b/hw/arm/nxp_rt595_m33.c @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/dma_notifier.h" +#include "qemu/error-report.h" +#include "qemu/module.h" +#include "qemu/notify.h" +#include "qemu/units.h" +#include "qemu/cutils.h" +#include "qemu/timer.h" +#include "migration/vmstate.h" +#include "hw/qdev-core.h" +#include "hw/sysbus.h" +#include "hw/char/serial.h" +#include "hw/misc/unimp.h" +#include "hw/usb/hcd-ehci.h" +#include "hw/loader.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-clock.h" +#include "sysemu/hostmem.h" +#include "hw/adc/rt_lpadc.h" +#include "hw/arm/boot.h" +#include "hw/arm/nxp_rt595.h" +#include "hw/misc/rt_sysctl.h" +#include "hw/misc/rt_rstctl.h" +#include "hw/misc/rt_clkctl.h" +#include "hw/misc/rt_pmc.h" +#include "hw/ssi/rt_flexspi.h" +#include "hw/char/rt_flexcomm.h" +#include "hw/i2c/rt_flexcomm_i2c.h" +#include "hw/timer/rt_ostimer.h" +#include "hw/misc/fxos8700.h" +#include "hw/misc/pca9420.h" +#include "hw/misc/dbus_client.h" +#include "hw/gpio/rt_pint.h" + +static rt595_m33_memmap_t _memmap; + +static qemu_irq rt595_irq_init(void * opaque, int n, int cpu_id); + +#define RT595_SDIO_CAPABILITIES 0x057834b4 + +/*======================================= + RT595 M33 CORE module Start + ========================================*/ +static void rt595_m33_mmap_init(MachineState *machine) +{ + int i = 0; + int j = 0; + uint32_t base = 0x0; + + _memmap.pflash.start = 0x00000000; + for(i = 0; i < 8; i++) + { + _memmap.sram_part[i].start = 0x0 + (0x8000 * i); + _memmap.sram_part[i].size = 0x8000; /* 32K */ + } + base = 0x40000; + for(i = 8, j = 0; i < 12; i++, j++) + { + _memmap.sram_part[i].start = (0x10000 * j) + base; + _memmap.sram_part[i].size = 0x10000; /* 64K */ + } + base = 0x80000; + for(i = 12, j = 0; i < 16; i++, j++) + { + _memmap.sram_part[i].start = (0x20000 * j) + base; + _memmap.sram_part[i].size = 0x20000; /* 128K */ + } + base = 0x100000; + for(i = 16, j = 0; i < RT595_M33_SRAM_BANKS; i++, j++) + { + _memmap.sram_part[i].start = (0x40000 * j) + base; + _memmap.sram_part[i].size = 0x40000; /* 256K */ + } + _memmap.rom.start = 0x03000000; + _memmap.rom.size = 0x30000; /* 192KiB */ + _memmap.CLKCTL0.start = 0x40001000; + _memmap.CLKCTL0.size = 0x1000; + _memmap.CLKCTL1.start = 0x40021000; + _memmap.CLKCTL1.size = 0x1000; + _memmap.RSTCTL0.start = 0x40000000; + _memmap.RSTCTL0.size = 0x1000; + _memmap.RSTCTL1.start = 0x40020000; + _memmap.RSTCTL1.size = 0x1000; + _memmap.SYSCTL0.start = 0x40002000; + _memmap.SYSCTL0.size = 0x1000; + _memmap.SYSCTL1.start = 0x40022000; + _memmap.SYSCTL1.size = 0x1000; + _memmap.PMC.start = 0x40135000; + _memmap.PMC.size = 0x1000; + _memmap.GPIO_INT.start = 0x40025000; + _memmap.GPIO_INT.size = 0x1000; + _memmap.flexspi.start = 0x08000000; + _memmap.flexspi.size = 0x08000000; + _memmap.flexspi_ctl.start = 0x40134000; + _memmap.flexspi_ctl.size = 0x1000; + _memmap.flexspi1_ctl.start = 0x4013C000; + _memmap.flexspi1_ctl.size = 0x1000; + _memmap.flexcomm[0].start = 0x40106000; + _memmap.flexcomm[0].size = 0x1000; + _memmap.flexcomm[0].irq_num = 14; + _memmap.flexcomm[1].start = 0x40107000; + _memmap.flexcomm[1].size = 0x1000; + _memmap.flexcomm[1].irq_num = 15; + _memmap.flexcomm[2].start = 0x40108000; + _memmap.flexcomm[2].size = 0x1000; + _memmap.flexcomm[2].irq_num = 16; + _memmap.flexcomm[3].start = 0x40109000; + _memmap.flexcomm[3].size = 0x1000; + _memmap.flexcomm[3].irq_num = 17; + _memmap.flexcomm[4].start = 0x40122000; + _memmap.flexcomm[4].size = 0x1000; + _memmap.flexcomm[4].irq_num = 18; + _memmap.flexcomm[5].start = 0x40123000; + _memmap.flexcomm[5].size = 0x1000; + _memmap.flexcomm[5].irq_num = 19; + _memmap.flexcomm[6].start = 0x40124000; + _memmap.flexcomm[6].size = 0x1000; + _memmap.flexcomm[6].irq_num = 43; + _memmap.flexcomm[7].start = 0x40125000; + _memmap.flexcomm[7].size = 0x1000; + _memmap.flexcomm[7].irq_num = 44; + _memmap.flexcomm[8].start = 0x40209000; + _memmap.flexcomm[8].size = 0x1000; + _memmap.flexcomm[8].irq_num = 60; + _memmap.flexcomm[9].start = 0x4020A000; + _memmap.flexcomm[9].size = 0x1000; + _memmap.flexcomm[9].irq_num = 61; + _memmap.flexcomm[10].start = 0x4020B000; + _memmap.flexcomm[10].size = 0x1000; + _memmap.flexcomm[10].irq_num = 62; + _memmap.flexcomm[11].start = 0x4020C000; + _memmap.flexcomm[11].size = 0x1000; + _memmap.flexcomm[11].irq_num = 63; + _memmap.flexcomm[12].start = 0x4020D000; + _memmap.flexcomm[12].size = 0x1000; + _memmap.flexcomm[12].irq_num = 64; + _memmap.flexcomm[13].start = 0x4020E000; + _memmap.flexcomm[13].size = 0x1000; + _memmap.flexcomm[13].irq_num = 65; + _memmap.flexcomm[14].start = 0x40126000; + _memmap.flexcomm[14].size = 0x1000; + _memmap.flexcomm[14].irq_num = 20; + _memmap.flexcomm[15].start = 0x40127000; + _memmap.flexcomm[15].size = 0x1000; + _memmap.flexcomm[15].irq_num = 21; + _memmap.flexcomm[16].start = 0x40128000; + _memmap.flexcomm[16].size = 0x1000; + _memmap.flexcomm[16].irq_num = 66; + _memmap.lpadc.start = 0x4013A000; + _memmap.lpadc.size = 0x1000; + _memmap.lpadc.irq_num = 22; + _memmap.lpadc.dma_hwtrg_nr = 24; + _memmap.ostimer[0].start = 0x40113000; + _memmap.ostimer[0].irq_num = 41; + _memmap.sdio[0].start = 0x40136000; + _memmap.sdio[0].size = 0x1000; + _memmap.sdio[0].irq_num = 45; + _memmap.sdio[1].start = 0x40137000; + _memmap.sdio[1].size = 0x1000; + _memmap.sdio[1].irq_num = 46; + _memmap.pmc.start = 0x40135000; + _memmap.pmc.size = 0x1000; + _memmap.pmc.irq_num = 58; + _memmap.mua.start = 0x40110000; + _memmap.mua.size = 0x1000; + _memmap.mua.irq_num = 34; + _memmap.pint[0].start = 0x40025000; + _memmap.pint[0].size = 0x1000; + _memmap.pint[0].irq_num = 4; + _memmap.pint[1].irq_num = 5; + _memmap.pint[2].irq_num = 6; + _memmap.pint[3].irq_num = 7; + _memmap.pint[4].irq_num = 35; + _memmap.pint[5].irq_num = 36; + _memmap.pint[6].irq_num = 37; + _memmap.pint[7].irq_num = 38; + +} + +static void rt595_dma_hwtrigger_req(Notifier *n, void *opaque) +{ + /* move to dma mux maybe better */ + /* do DMA here*/ +} + + + +/* + * Create an alias region in @container of @size bytes starting at @base + * which mirrors the memory starting at @orig. + */ +static void make_alias(MemoryRegion *mr, MemoryRegion *container, + const char *name, hwaddr base, hwaddr size, hwaddr orig) +{ + memory_region_init_alias(mr, NULL, name, container, orig, size); + /* The alias is even lower priority than unimplemented_device regions */ + memory_region_add_subregion_overlap(container, base, mr, -1500); +} + +static void rt595_resolve_machine_pint(RT595_M33_MachineState *mms) +{ + qemu_irq irq_0 = rt595_irq_init(mms, _memmap.pint[0].irq_num, 0); + qemu_irq irq_1 = rt595_irq_init(mms, _memmap.pint[1].irq_num, 0); + qemu_irq irq_2 = rt595_irq_init(mms, _memmap.pint[2].irq_num, 0); + qemu_irq irq_3 = rt595_irq_init(mms, _memmap.pint[3].irq_num, 0); + qemu_irq irq_4 = rt595_irq_init(mms, _memmap.pint[4].irq_num, 0); + qemu_irq irq_5 = rt595_irq_init(mms, _memmap.pint[5].irq_num, 0); + qemu_irq irq_6 = rt595_irq_init(mms, _memmap.pint[6].irq_num, 0); + qemu_irq irq_7 = rt595_irq_init(mms, _memmap.pint[7].irq_num, 0); + + sysbus_create_varargs(TYPE_RT_PINT, (hwaddr)_memmap.pint[0].start, irq_0, + irq_1, irq_2, irq_3, irq_4, irq_5, irq_6, irq_7, NULL); + make_alias(&mms->pint_s, get_system_memory(), "pint sec", 0x10000000 + _memmap.pint[0].start, + _memmap.pint[0].size, _memmap.pint[0].start); +} + +static void rt595_resolve_machine_mu(RT595_M33_MachineState *mms) +{ + qemu_irq irq = rt595_irq_init(mms, _memmap.mua.irq_num, 0); + + sysbus_create_simple(TYPE_DBUS_CLIENT_MUA, (hwaddr)_memmap.mua.start, irq); + make_alias(&mms->mua_s, get_system_memory(), "mua sec", 0x10000000 + _memmap.mua.start, + _memmap.mua.size, _memmap.mua.start); +} + +static void rt595_resolve_machine_sdio(RT595_M33_MachineState *mms, uint32_t sdio_id) +{ + char *sdio_name = g_strdup_printf("sdio%d", sdio_id); + char *sdio_name_s = g_strdup_printf("sdio%d_s", sdio_id); + qemu_irq irq = rt595_irq_init(mms, _memmap.sdio[sdio_id].irq_num, 0); + + object_initialize_child(OBJECT(mms), sdio_name, &mms->sdio[sdio_id], TYPE_IMX_USDHC); + //object_initialize_child(OBJECT(mms), sdio_name, &mms->sdio[sdio_id], TYPE_SYSBUS_SDHCI); + /* UHS-I SDIO3.0 SDR104 1.8V ADMA */ + object_property_set_uint(OBJECT(&mms->sdio[sdio_id]), "sd-spec-version", 3, + &error_abort); + object_property_set_uint(OBJECT(&mms->sdio[sdio_id]), "capareg", + RT595_SDIO_CAPABILITIES, &error_abort); + object_property_set_uint(OBJECT(&mms->sdio[sdio_id]), "vendor", + SDHCI_VENDOR_IMX, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&mms->sdio[sdio_id]), &error_fatal)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&mms->sdio[sdio_id]), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(&mms->sdio[sdio_id]), 0, _memmap.sdio[sdio_id].start); + g_free(sdio_name); + + make_alias(&mms->sdio_s[sdio_id], get_system_memory(), sdio_name_s, 0x10000000 + _memmap.sdio[sdio_id].start, + _memmap.sdio[sdio_id].size, _memmap.sdio[sdio_id].start); + g_free(sdio_name_s); + + BusState *bus; + DeviceState *carddev; + DriveInfo *di; + BlockBackend *blk; + + di = drive_get(IF_SD, 0, sdio_id); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + bus = qdev_get_child_bus(DEVICE(&mms->sdio[sdio_id]), "sd-bus"); + carddev = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); +} + +static void rt595_resolve_machine_flexspi_nor(RT595_M33_MachineState *mms) +{ + HostMemoryBackend *backend; + + //memory_region_init_ram(&mms->flexspi_ahb, NULL, "flexspi_ahb.ram", 0x08000000, &error_fatal); + //memory_region_add_subregion(system_memory, m_imx9_memmap.flexspi_ahb_start, &mms->flexspi_ahb); + /* hardcode dtcm backend id */ + backend = (HostMemoryBackend *)object_resolve_path_type("rt595_flexspi_nor", + TYPE_MEMORY_BACKEND, NULL); + + if (!backend) { + info_report("[ROM_EMU] not backend for flexspi nor found, use mem fallback"); + memory_region_init_ram(&mms->flexspi_ns, NULL, "flexspi", _memmap.flexspi.size, &error_fatal); /* 128M */ + memory_region_add_subregion(get_system_memory(), _memmap.flexspi.start, &mms->flexspi_ns); + return; + } + + MemoryRegion *ret = host_memory_backend_get_memory(backend); + + if (host_memory_backend_is_mapped(backend)) { + error_report("memory backend %s can't be used multiple times.", + object_get_canonical_path_component(OBJECT(backend))); + exit(EXIT_FAILURE); + } + host_memory_backend_set_mapped(backend, true); + vmstate_register_ram_global(ret); + memory_region_add_subregion(get_system_memory(), _memmap.flexspi.start, ret); + info_report("[ROM_EMU] backend for flexspi nor mapped"); + return; +} + +static I2CBus *rt595_i2c_get_bus(RT595_M33_MachineState *soc, uint32_t num) +{ + BusState * bus; + g_assert(soc->flexcomm_i2c_ctl[num]!= NULL); + bus = qdev_get_child_bus(DEVICE(soc->flexcomm_i2c_ctl[num]), "i2c-bus"); + return I2C_BUS(bus); +} + +static void rt595_evk_i2c_init(RT595_M33_MachineState *soc) +{ + /* fxos8700 */ + i2c_slave_create_simple(rt595_i2c_get_bus(soc, 4), TYPE_FXOS8700, (0x1e<<1)); + /* pmic */ + i2c_slave_create_simple(rt595_i2c_get_bus(soc, 15), TYPE_PCA9420, (0x61<<1)); +} + +static qemu_irq rt595_irq_init(void * opaque, int n, int cpu_id) +{ + RT595_M33_MachineState *mms = RT595_M33_MACHINE(opaque); + ARMSSE *s = ARM_SSE(&mms->iotkit); + + qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m[cpu_id]), n); + return irq; +} + +static void rt595_resolve_flexcomm_uart(RT595_M33_MachineState *mms, int flexcomm_num, int uart_id) +{ + char *flexcomm_name = g_strdup_printf("flexcomm%d_s", flexcomm_num); + qemu_irq irq = rt595_irq_init(mms, _memmap.flexcomm[flexcomm_num].irq_num, 0); + Chardev *chrdrv = serial_hd(uart_id); + DeviceState * dev = qdev_new(TYPE_RT_FLEXCOMM); + + qdev_prop_set_chr(dev, "chardev", chrdrv); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, (hwaddr)_memmap.flexcomm[flexcomm_num].start); + //sysbus_create_simple(TYPE_RT_FLEXCOMM, (hwaddr)_memmap.flexcomm[flexcomm_num].start, irq); + make_alias(&mms->flexcomm_s[flexcomm_num], get_system_memory(), flexcomm_name, 0x10000000 + _memmap.flexcomm[flexcomm_num].start, + _memmap.flexcomm[flexcomm_num].size, _memmap.flexcomm[flexcomm_num].start); + g_free(flexcomm_name); +} + +static void rt595_resolve_flexcomm_i2c(RT595_M33_MachineState *mms, int flexcomm_num) +{ + char *flexcomm_name = g_strdup_printf("flexcomm%d_s", flexcomm_num); + qemu_irq irq = rt595_irq_init(mms, _memmap.flexcomm[flexcomm_num].irq_num, 0); + + mms->flexcomm_i2c_ctl[flexcomm_num] = (RTFLEXCOMMI2CState *)sysbus_create_simple(TYPE_RT_FLEXCOMMI2C, + (hwaddr)_memmap.flexcomm[flexcomm_num].start, irq); + make_alias(&mms->flexcomm_s[flexcomm_num], get_system_memory(), flexcomm_name, + 0x10000000 + _memmap.flexcomm[flexcomm_num].start, + _memmap.flexcomm[flexcomm_num].size, _memmap.flexcomm[flexcomm_num].start); + g_free(flexcomm_name); +} + + +static void rt595_resolve_lpadc(RT595_M33_MachineState *mms, int id) +{ + char *lpadc_name = g_strdup_printf("lpadc%d_s", id); + qemu_irq irq = rt595_irq_init(mms, _memmap.lpadc.irq_num, 0); + + sysbus_create_simple(TYPE_RT_LPADC, (hwaddr)_memmap.lpadc.start, irq); + make_alias(&mms->lpadc_s, get_system_memory(), lpadc_name, 0x10000000 + _memmap.lpadc.start, + _memmap.lpadc.size, _memmap.lpadc.start); + g_free(lpadc_name); +} + +static void rt595_resolve_ostimer(RT595_M33_MachineState *mms, int id) +{ + char *ostimer_name = g_strdup_printf("ostimer%d_s", id); + qemu_irq irq = rt595_irq_init(mms, _memmap.ostimer[id].irq_num, 0); + + sysbus_create_simple(TYPE_RT_OSTIMER, (hwaddr)_memmap.ostimer[id].start, irq); + make_alias(&mms->os_timer_sec[id], get_system_memory(), ostimer_name, 0x10000000 + _memmap.ostimer[id].start, + _memmap.ostimer[id].size, _memmap.ostimer[id].start); + g_free(ostimer_name); +} + +static void rt595_resolve_pmc(RT595_M33_MachineState *mms, int id) +{ + char *pmc_name = g_strdup_printf("pmc%d_s", id); + qemu_irq irq = rt595_irq_init(mms, _memmap.pmc.irq_num, 0); + + sysbus_create_simple(TYPE_RT_PMC, (hwaddr)_memmap.pmc.start, irq); + make_alias(&mms->pmc_s, get_system_memory(), pmc_name, 0x10000000 + _memmap.pmc.start, + _memmap.pmc.size, _memmap.pmc.start); + g_free(pmc_name); +} + +static void rt595_m33_common_init(MachineState *machine) +{ + RT595_M33_MachineState *mms = RT595_M33_MACHINE(machine); + MachineClass *mmc = MACHINE_GET_CLASS(machine); + RT595_M33_MachineClass *mc = RT595_MACHINE_GET_CLASS(mms); + MemoryRegion *system_memory = get_system_memory(); + DeviceState *iotkitdev; + + if (strcmp(machine->cpu_type, mmc->default_cpu_type) != 0) { + error_report("This board can only be used with CPU %s", + mmc->default_cpu_type); + exit(EXIT_FAILURE); + } + + rt595_m33_mmap_init(machine); + + /* These clocks don't need migration because they are fixed-frequency */ + mms->sysclk = clock_new(OBJECT(machine), "SYSCLK"); + clock_set_hz(mms->sysclk, SYSCLK_FRQ); + mms->s32kclk = clock_new(OBJECT(machine), "S32KCLK"); + clock_set_hz(mms->s32kclk, S32KCLK_FRQ); + + //memory_region_init(system_memory, OBJECT(machine), "rt595 amba", UINT64_MAX); + + object_initialize_child(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit, mc->armsse_type); + iotkitdev = DEVICE(&mms->iotkit); + object_property_set_link(OBJECT(&mms->iotkit), "memory", OBJECT(system_memory), &error_abort); + //qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", RT595_M33_NUMIRQ); + printf("init-svtor= 0x%x\n", mms->boot_base_addr); + qdev_prop_set_uint32(iotkitdev, "init-svtor", mms->boot_base_addr); + qdev_prop_set_uint32(iotkitdev, "SRAM_ADDR_WIDTH", 15); + qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk); + qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk); + sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal); + +#ifdef CONFIG_POSIX + Object *backend = NULL; + backend = object_property_get_link(OBJECT(mms), "memory-backend", &error_fatal); + if (backend != NULL) { + printf("[ROM_EMU]: backend file init\n"); + } +#endif + int i = 0; + for (i=0; i < RT595_M33_SRAM_BANKS; i++) { + char *sram_name = g_strdup_printf("sram%d", i); + memory_region_init_ram(&mms->sram[i], NULL, sram_name, _memmap.sram_part[i].size, &error_fatal); + memory_region_add_subregion(system_memory, _memmap.sram_part[i].start, &mms->sram[i]); + make_alias(&mms->sram_alias[i], system_memory, "sram alias", 0x10000000 + _memmap.sram_part[i].start, + _memmap.sram_part[i].size, _memmap.sram_part[i].start); + make_alias(&mms->sram_data_alias[i], system_memory, "sram data alias", 0x30000000 + _memmap.sram_part[i].start, + _memmap.sram_part[i].size, _memmap.sram_part[i].start); + make_alias(&mms->sram_data_alias_ns[i], system_memory, "sram alias", 0x20000000 + _memmap.sram_part[i].start, + _memmap.sram_part[i].size, _memmap.sram_part[i].start); + g_free(sram_name); + } + +#if 1 + /* TODO need get from DTS */ + rt595_resolve_flexcomm_uart(mms, 0, 0); /* dbug uart */ + rt595_resolve_flexcomm_i2c(mms, 4); /* i2c accelerator meter*/ + rt595_resolve_flexcomm_uart(mms, 12, 1); /* arduio uart*/ + rt595_resolve_flexcomm_i2c(mms, 15); /* pmic i2c */ + rt595_resolve_lpadc(mms, 0); + rt595_resolve_ostimer(mms, 0); + rt595_evk_i2c_init(mms); + rt595_resolve_pmc(mms, 0); + rt595_resolve_machine_mu(mms); + rt595_resolve_machine_pint(mms); +#endif + + rt595_resolve_machine_flexspi_nor(mms); + make_alias(&mms->flexspi_s, system_memory, "flexspi sec", 0x10000000 + _memmap.flexspi.start, + _memmap.flexspi.size, _memmap.flexspi.start); + + sysbus_create_simple(TYPE_RT_SYSCTL0, (hwaddr)_memmap.SYSCTL0.start, NULL); + make_alias(&mms->SYSCTL0_s, system_memory, "sysctrl0 sec", 0x10000000 + _memmap.SYSCTL0.start, + _memmap.SYSCTL0.size, _memmap.SYSCTL0.start); + + sysbus_create_simple(TYPE_RT_SYSCTL1, (hwaddr)_memmap.SYSCTL1.start, NULL); + make_alias(&mms->SYSCTL1_s, system_memory, "sysctrl1 sec", 0x10000000 + _memmap.SYSCTL1.start, + _memmap.SYSCTL1.size, _memmap.SYSCTL1.start); + + sysbus_create_simple(TYPE_RT_RSTCTL0, (hwaddr)_memmap.RSTCTL0.start, NULL); + make_alias(&mms->RSTCTL0_s, system_memory, "rstctrl0 sec", 0x10000000 + _memmap.RSTCTL0.start, + _memmap.RSTCTL0.size, _memmap.RSTCTL0.start); + + sysbus_create_simple(TYPE_RT_RSTCTL1, (hwaddr)_memmap.RSTCTL1.start, NULL); + make_alias(&mms->RSTCTL1_s, system_memory, "rstctrl1 sec", 0x10000000 + _memmap.RSTCTL1.start, + _memmap.RSTCTL1.size, _memmap.RSTCTL1.start); + + sysbus_create_simple(TYPE_RT_CLKCTL0, (hwaddr)_memmap.CLKCTL0.start, NULL); + make_alias(&mms->CLKCTL0_s, system_memory, "clkctrl0 sec", 0x10000000 + _memmap.CLKCTL0.start, + _memmap.CLKCTL0.size, _memmap.CLKCTL0.start); + + sysbus_create_simple(TYPE_RT_CLKCTL1, (hwaddr)_memmap.CLKCTL1.start, NULL); + make_alias(&mms->CLKCTL1_s, system_memory, "clkctrl1 sec", 0x10000000 + _memmap.CLKCTL1.start, + _memmap.CLKCTL1.size, _memmap.CLKCTL1.start); + + //sysbus_create_simple(TYPE_RT_PMC, (hwaddr)_memmap.PMC.start, NULL); + //make_alias(&mms->PMC_s, system_memory, "PMC sec", 0x10000000 + _memmap.PMC.start, + // _memmap.PMC.size, _memmap.PMC.start); + + sysbus_create_simple(TYPE_RT_FLEXSPI, (hwaddr)_memmap.flexspi_ctl.start, NULL); + make_alias(&mms->flexspi_ctl_s, system_memory, "flexspi ctl sec", 0x10000000 + _memmap.flexspi_ctl.start, + _memmap.flexspi_ctl.size, _memmap.flexspi_ctl.start); + + sysbus_create_simple(TYPE_RT_FLEXSPI, (hwaddr)_memmap.flexspi1_ctl.start, NULL); + make_alias(&mms->flexspi1_ctl_s, system_memory, "flexspi1 ctl sec", 0x10000000 + _memmap.flexspi1_ctl.start, + _memmap.flexspi_ctl.size, _memmap.flexspi1_ctl.start); + + make_alias(&mms->IOPCTL_s, system_memory, "IOPCTL_s sec", 0x10000000 + _memmap.IOPCTL.start, + _memmap.IOPCTL.size, _memmap.IOPCTL.start); + make_alias(&mms->PERIPHERAL_MUXES_s, system_memory, "flexspi ctl sec", 0x10000000 + _memmap.PERIPHERAL_MUXES.start, + _memmap.PERIPHERAL_MUXES.size, _memmap.PERIPHERAL_MUXES.start); + + /* DMA hwtrigger */ + dma_trigger_init_notifier_list(&mms->dma_hwtrigger_notifiers); + mms->hwtrigger_notifier.notify = rt595_dma_hwtrigger_req; + dma_trigger_notifier_connect(&mms->hwtrigger_notifier); + + rt595_resolve_machine_sdio(mms, 0); + rt595_resolve_machine_sdio(mms, 1); + /* ram boot */ + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x00000000, 0x400000); +} + +static void rt595_m33_idau_check(IDAUInterface *ii, uint32_t address, + int *iregion, bool *exempt, bool *ns, bool *nsc) +{ + int region = extract32(address, 28, 4); + + *ns = !(region & 1); + *nsc = false; + /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */ + *exempt = (address & 0xeff00000) == 0xe0000000; + *iregion = region; +} + +static Property rt595_m33_soc_properties[] = { + DEFINE_PROP_UINT32("boot-base-addr", RT595_M33_MachineState, boot_base_addr, + 0x18001000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rt595_m33_class_init(ObjectClass *oc, void *data) +{ + IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); + MachineClass *mc = MACHINE_CLASS(oc); + RT595_M33_MachineClass *mmc = RT595_MACHINE_CLASS(oc); + + iic->check = rt595_m33_idau_check; + + mc->default_cpus = 1; + mc->max_cpus = 1; + mc->min_cpus = mc->default_cpus; + mc->minimum_page_bits = 10; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); + mc->desc = "RT595 for Cortex-M33"; + mc->default_ram_size = 128 * MiB; + mc->init = rt595_m33_common_init; + mmc->armsse_type = TYPE_RT500_M33; + device_class_set_props(DEVICE_CLASS(oc), rt595_m33_soc_properties); +} + +static const TypeInfo rt595_m33_info = { + .name = TYPE_RT595_M33_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(RT595_M33_MachineState), + .class_size = sizeof(RT595_M33_MachineClass), + .class_init = rt595_m33_class_init, +}; + +static void rt595_m33_machine_init(void) +{ + type_register_static(&rt595_m33_info); +} + +type_init(rt595_m33_machine_init); diff --git a/hw/arm/olimex-stm32-h405.c b/hw/arm/olimex-stm32-h405.c new file mode 100644 index 000000000000..3aa61c91b759 --- /dev/null +++ b/hw/arm/olimex-stm32-h405.c @@ -0,0 +1,69 @@ +/* + * ST STM32VLDISCOVERY machine + * Olimex STM32-H405 machine + * + * Copyright (c) 2022 Felipe Balbi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" +#include "qemu/error-report.h" +#include "hw/arm/stm32f405_soc.h" +#include "hw/arm/boot.h" + +/* olimex-stm32-h405 implementation is derived from netduinoplus2 */ + +/* Main SYSCLK frequency in Hz (168MHz) */ +#define SYSCLK_FRQ 168000000ULL + +static void olimex_stm32_h405_init(MachineState *machine) +{ + DeviceState *dev; + Clock *sysclk; + + /* This clock doesn't need migration because it is fixed-frequency */ + sysclk = clock_new(OBJECT(machine), "SYSCLK"); + clock_set_hz(sysclk, SYSCLK_FRQ); + + dev = qdev_new(TYPE_STM32F405_SOC); + qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); + qdev_connect_clock_in(dev, "sysclk", sysclk); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + armv7m_load_kernel(ARM_CPU(first_cpu), + machine->kernel_filename, + 0, FLASH_SIZE); +} + +static void olimex_stm32_h405_machine_init(MachineClass *mc) +{ + mc->desc = "Olimex STM32-H405 (Cortex-M4)"; + mc->init = olimex_stm32_h405_init; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); + + /* SRAM pre-allocated as part of the SoC instantiation */ + mc->default_ram_size = 0; +} + +DEFINE_MACHINE("olimex-stm32-h405", olimex_stm32_h405_machine_init) diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index f693faa43e08..559c066ce903 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -176,7 +176,7 @@ static void omap_timer_fire(void *opaque) static void omap_timer_tick(void *opaque) { - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + struct omap_mpu_timer_s *timer = opaque; omap_timer_sync(timer); omap_timer_fire(timer); @@ -185,7 +185,7 @@ static void omap_timer_tick(void *opaque) static void omap_timer_clk_update(void *opaque, int line, int on) { - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + struct omap_mpu_timer_s *timer = opaque; omap_timer_sync(timer); timer->rate = on ? omap_clk_getrate(timer->clk) : 0; @@ -202,7 +202,7 @@ static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + struct omap_mpu_timer_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); @@ -226,7 +226,7 @@ static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, static void omap_mpu_timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + struct omap_mpu_timer_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -308,7 +308,7 @@ struct omap_watchdog_timer_s { static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + struct omap_watchdog_timer_s *s = opaque; if (size != 2) { return omap_badwidth_read16(opaque, addr); @@ -333,7 +333,7 @@ static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, static void omap_wd_timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + struct omap_watchdog_timer_s *s = opaque; if (size != 2) { omap_badwidth_write16(opaque, addr, value); @@ -431,7 +431,7 @@ struct omap_32khz_timer_s { static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + struct omap_32khz_timer_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 4) { @@ -458,7 +458,7 @@ static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, static void omap_os_timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + struct omap_32khz_timer_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 4) { @@ -532,7 +532,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; uint16_t ret; if (size != 2) { @@ -600,7 +600,7 @@ static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, static void omap_ulpd_pm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; int64_t now, ticks; int div, mult; static const int bypass_div[4] = { 1, 2, 4, 4 }; @@ -765,7 +765,7 @@ static void omap_ulpd_pm_init(MemoryRegion *system_memory, static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); @@ -876,7 +876,7 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, static void omap_pin_cfg_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; uint32_t diff; if (size != 4) { @@ -988,7 +988,7 @@ static void omap_pin_cfg_init(MemoryRegion *system_memory, static uint64_t omap_id_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); @@ -1070,7 +1070,7 @@ static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu) static uint64_t omap_mpui_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); @@ -1103,7 +1103,7 @@ static uint64_t omap_mpui_read(void *opaque, hwaddr addr, static void omap_mpui_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -1168,7 +1168,7 @@ struct omap_tipb_bridge_s { static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + struct omap_tipb_bridge_s *s = opaque; if (size < 2) { return omap_badwidth_read16(opaque, addr); @@ -1198,7 +1198,7 @@ static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, static void omap_tipb_bridge_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + struct omap_tipb_bridge_s *s = opaque; if (size < 2) { omap_badwidth_write16(opaque, addr, value); @@ -1269,7 +1269,7 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init( static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; uint32_t ret; if (size != 4) { @@ -1307,7 +1307,7 @@ static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, static void omap_tcmi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -1384,7 +1384,7 @@ struct dpll_ctl_s { static uint64_t omap_dpll_read(void *opaque, hwaddr addr, unsigned size) { - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + struct dpll_ctl_s *s = opaque; if (size != 2) { return omap_badwidth_read16(opaque, addr); @@ -1400,7 +1400,7 @@ static uint64_t omap_dpll_read(void *opaque, hwaddr addr, static void omap_dpll_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + struct dpll_ctl_s *s = opaque; uint16_t diff; static const int bypass_div[4] = { 1, 2, 4, 4 }; int div, mult; @@ -1464,7 +1464,7 @@ static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory, static uint64_t omap_clkm_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 2) { return omap_badwidth_read16(opaque, addr); @@ -1668,7 +1668,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, static void omap_clkm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; uint16_t diff; omap_clk clk; static const char *clkschemename[8] = { @@ -1756,7 +1756,7 @@ static const MemoryRegionOps omap_clkm_ops = { static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; CPUState *cpu = CPU(s->cpu); if (size != 2) { @@ -1801,7 +1801,7 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, static void omap_clkdsp_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; uint16_t diff; if (size != 2) { @@ -1911,7 +1911,7 @@ struct omap_mpuio_s { static void omap_mpuio_set(void *opaque, int line, int level) { - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + struct omap_mpuio_s *s = opaque; uint16_t prev = s->inputs; if (level) @@ -1947,7 +1947,7 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + struct omap_mpuio_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; @@ -2007,7 +2007,7 @@ static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, static void omap_mpuio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + struct omap_mpuio_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t diff; int ln; @@ -2104,7 +2104,7 @@ static void omap_mpuio_reset(struct omap_mpuio_s *s) static void omap_mpuio_onoff(void *opaque, int line, int on) { - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + struct omap_mpuio_s *s = opaque; s->clk = on; if (on) @@ -2198,10 +2198,9 @@ static void omap_uwire_transfer_start(struct omap_uwire_s *s) } } -static uint64_t omap_uwire_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_uwire_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + struct omap_uwire_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 2) { @@ -2235,7 +2234,7 @@ static uint64_t omap_uwire_read(void *opaque, hwaddr addr, static void omap_uwire_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + struct omap_uwire_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 2) { @@ -2351,10 +2350,9 @@ static void omap_pwl_update(struct omap_pwl_s *s) } } -static uint64_t omap_pwl_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_pwl_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; + struct omap_pwl_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { @@ -2374,7 +2372,7 @@ static uint64_t omap_pwl_read(void *opaque, hwaddr addr, static void omap_pwl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; + struct omap_pwl_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { @@ -2414,7 +2412,7 @@ static void omap_pwl_reset(struct omap_pwl_s *s) static void omap_pwl_clk_update(void *opaque, int line, int on) { - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; + struct omap_pwl_s *s = opaque; s->clk = on; omap_pwl_update(s); @@ -2445,10 +2443,9 @@ struct omap_pwt_s { omap_clk clk; }; -static uint64_t omap_pwt_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_pwt_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; + struct omap_pwt_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { @@ -2470,7 +2467,7 @@ static uint64_t omap_pwt_read(void *opaque, hwaddr addr, static void omap_pwt_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; + struct omap_pwt_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { @@ -2577,10 +2574,9 @@ static void omap_rtc_alarm_update(struct omap_rtc_s *s) printf("%s: conversion failed\n", __func__); } -static uint64_t omap_rtc_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_rtc_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + struct omap_rtc_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint8_t i; @@ -2662,7 +2658,7 @@ static uint64_t omap_rtc_read(void *opaque, hwaddr addr, static void omap_rtc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + struct omap_rtc_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; struct tm new_tm; time_t ti[2]; @@ -3034,7 +3030,7 @@ static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) static void omap_mcbsp_source_tick(void *opaque) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; if (!s->rx_rate) @@ -3080,7 +3076,7 @@ static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) static void omap_mcbsp_sink_tick(void *opaque) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; if (!s->tx_rate) @@ -3173,7 +3169,7 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; @@ -3271,7 +3267,7 @@ static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, static void omap_mcbsp_writeh(void *opaque, hwaddr addr, uint32_t value) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { @@ -3407,7 +3403,7 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, static void omap_mcbsp_writew(void *opaque, hwaddr addr, uint32_t value) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (offset == 0x04) { /* DXR */ @@ -3498,7 +3494,7 @@ static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; if (s->rx_rate) { s->rx_req = s->codec->in.len; @@ -3508,7 +3504,7 @@ static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) static void omap_mcbsp_i2s_start(void *opaque, int line, int level) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + struct omap_mcbsp_s *s = opaque; if (s->tx_rate) { s->tx_req = s->codec->out.size; @@ -3590,10 +3586,9 @@ static void omap_lpg_reset(struct omap_lpg_s *s) omap_lpg_update(s); } -static uint64_t omap_lpg_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_lpg_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + struct omap_lpg_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { @@ -3615,7 +3610,7 @@ static uint64_t omap_lpg_read(void *opaque, hwaddr addr, static void omap_lpg_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + struct omap_lpg_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { @@ -3650,7 +3645,7 @@ static const MemoryRegionOps omap_lpg_ops = { static void omap_lpg_clk_update(void *opaque, int line, int on) { - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + struct omap_lpg_s *s = opaque; s->clk = on; omap_lpg_update(s); @@ -3713,7 +3708,7 @@ static void omap_setup_mpui_io(MemoryRegion *system_memory, /* General chip reset */ static void omap1_mpu_reset(void *opaque) { - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *mpu = opaque; omap_dma_reset(mpu->dma); omap_mpu_timer_reset(mpu->timer[0]); @@ -3793,7 +3788,7 @@ static void omap_setup_dsp_mapping(MemoryRegion *system_memory, void omap_mpu_wakeup(void *opaque, int irq, int req) { - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *mpu = opaque; CPUState *cpu = CPU(mpu->cpu); if (cpu->halted) { diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index 02b1aa8c974b..366d6af1b660 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -167,7 +167,7 @@ static inline void omap_eac_out_empty(struct omap_eac_s *s) static void omap_eac_in_cb(void *opaque, int avail_b) { - struct omap_eac_s *s = (struct omap_eac_s *) opaque; + struct omap_eac_s *s = opaque; s->codec.rxavail = avail_b >> 2; omap_eac_in_refill(s); @@ -177,7 +177,7 @@ static void omap_eac_in_cb(void *opaque, int avail_b) static void omap_eac_out_cb(void *opaque, int free_b) { - struct omap_eac_s *s = (struct omap_eac_s *) opaque; + struct omap_eac_s *s = opaque; s->codec.txavail = free_b >> 2; if (s->codec.txlen) @@ -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; @@ -333,10 +333,9 @@ static void omap_eac_reset(struct omap_eac_s *s) omap_eac_interrupt_update(s); } -static uint64_t omap_eac_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_eac_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_eac_s *s = (struct omap_eac_s *) opaque; + struct omap_eac_s *s = opaque; uint32_t ret; if (size != 2) { @@ -452,7 +451,7 @@ static uint64_t omap_eac_read(void *opaque, hwaddr addr, static void omap_eac_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_eac_s *s = (struct omap_eac_s *) opaque; + struct omap_eac_s *s = opaque; if (size != 2) { omap_badwidth_write16(opaque, addr, value); @@ -656,7 +655,7 @@ static void omap_sti_reset(struct omap_sti_s *s) static uint64_t omap_sti_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_sti_s *s = (struct omap_sti_s *) opaque; + struct omap_sti_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); @@ -697,7 +696,7 @@ static uint64_t omap_sti_read(void *opaque, hwaddr addr, static void omap_sti_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_sti_s *s = (struct omap_sti_s *) opaque; + struct omap_sti_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -751,8 +750,7 @@ static const MemoryRegionOps omap_sti_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, unsigned size) { OMAP_BAD_REG(addr); return 0; @@ -761,7 +759,7 @@ static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, static void omap_sti_fifo_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_sti_s *s = (struct omap_sti_s *) opaque; + struct omap_sti_s *s = opaque; int ch = addr >> 6; uint8_t byte = value; @@ -1057,7 +1055,7 @@ static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) static uint64_t omap_prcm_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; + struct omap_prcm_s *s = opaque; uint32_t ret; if (size != 4) { @@ -1369,7 +1367,7 @@ static void omap_prcm_dpll_update(struct omap_prcm_s *s) static void omap_prcm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; + struct omap_prcm_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -1849,7 +1847,7 @@ struct omap_sysctl_s { static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr) { - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + struct omap_sysctl_s *s = opaque; int pad_offset, byte_offset; int value; @@ -1873,7 +1871,7 @@ static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr) static uint32_t omap_sysctl_read(void *opaque, hwaddr addr) { - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + struct omap_sysctl_s *s = opaque; switch (addr) { case 0x000: /* CONTROL_REVISION */ @@ -1971,10 +1969,9 @@ static uint32_t omap_sysctl_read(void *opaque, hwaddr addr) return 0; } -static void omap_sysctl_write8(void *opaque, hwaddr addr, - uint32_t value) +static void omap_sysctl_write8(void *opaque, hwaddr addr, uint32_t value) { - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + struct omap_sysctl_s *s = opaque; int pad_offset, byte_offset; int prev_value; @@ -1995,10 +1992,9 @@ static void omap_sysctl_write8(void *opaque, hwaddr addr, } } -static void omap_sysctl_write(void *opaque, hwaddr addr, - uint32_t value) +static void omap_sysctl_write(void *opaque, hwaddr addr, uint32_t value) { - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; + struct omap_sysctl_s *s = opaque; switch (addr) { case 0x000: /* CONTROL_REVISION */ @@ -2233,7 +2229,7 @@ static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, /* General chip reset */ static void omap2_mpu_reset(void *opaque) { - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *mpu = opaque; omap_dma_reset(mpu->dma); omap_prcm_reset(mpu->prcm); diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 57829b37441e..e7212920797a 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -26,6 +26,7 @@ * with this program; if not, see . */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "ui/console.h" #include "hw/arm/omap.h" @@ -65,7 +66,7 @@ static uint64_t static_read(void *opaque, hwaddr offset, unsigned size) { - uint32_t *val = (uint32_t *) opaque; + uint32_t *val = opaque; uint32_t mask = (4 / size) - 1; return *val >> ((offset & mask) << 3); @@ -86,17 +87,15 @@ static const MemoryRegionOps static_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -#define sdram_size 0x02000000 -#define sector_size (128 * 1024) -#define flash0_size (16 * 1024 * 1024) -#define flash1_size ( 8 * 1024 * 1024) -#define flash2_size (32 * 1024 * 1024) -#define total_ram_v1 (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE) -#define total_ram_v2 (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE) +#define SDRAM_SIZE (32 * MiB) +#define SECTOR_SIZE (128 * KiB) +#define FLASH0_SIZE (16 * MiB) +#define FLASH1_SIZE (8 * MiB) +#define FLASH2_SIZE (32 * MiB) static struct arm_boot_info sx1_binfo = { .loader_start = OMAP_EMIFF_BASE, - .ram_size = sdram_size, + .ram_size = SDRAM_SIZE, .board_id = 0x265, }; @@ -113,7 +112,7 @@ static void sx1_init(MachineState *machine, const int version) static uint32_t cs3val = 0x00001139; DriveInfo *dinfo; int fl_idx; - uint32_t flash_size = flash0_size; + uint32_t flash_size = FLASH0_SIZE; if (machine->ram_size != mc->default_ram_size) { char *sz = size_to_str(mc->default_ram_size); @@ -123,7 +122,7 @@ static void sx1_init(MachineState *machine, const int version) } if (version == 2) { - flash_size = flash2_size; + flash_size = FLASH2_SIZE; } memory_region_add_subregion(address_space, OMAP_EMIFF_BASE, machine->ram); @@ -153,13 +152,10 @@ static void sx1_init(MachineState *machine, const int version) fl_idx = 0; if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { - if (!pflash_cfi01_register(OMAP_CS0_BASE, - "omap_sx1.flash0-1", flash_size, - blk_by_legacy_dinfo(dinfo), - sector_size, 4, 0, 0, 0, 0, 0)) { - fprintf(stderr, "qemu: Error registering flash memory %d.\n", - fl_idx); - } + pflash_cfi01_register(OMAP_CS0_BASE, + "omap_sx1.flash0-1", flash_size, + blk_by_legacy_dinfo(dinfo), + SECTOR_SIZE, 4, 0, 0, 0, 0, 0); fl_idx++; } @@ -167,21 +163,18 @@ static void sx1_init(MachineState *machine, const int version) (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { MemoryRegion *flash_1 = g_new(MemoryRegion, 1); memory_region_init_rom(flash_1, NULL, "omap_sx1.flash1-0", - flash1_size, &error_fatal); + FLASH1_SIZE, &error_fatal); memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1); memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, - "sx1.cs1", OMAP_CS1_SIZE - flash1_size); + "sx1.cs1", OMAP_CS1_SIZE - FLASH1_SIZE); memory_region_add_subregion(address_space, - OMAP_CS1_BASE + flash1_size, &cs[1]); - - if (!pflash_cfi01_register(OMAP_CS1_BASE, - "omap_sx1.flash1-1", flash1_size, - blk_by_legacy_dinfo(dinfo), - sector_size, 4, 0, 0, 0, 0, 0)) { - fprintf(stderr, "qemu: Error registering flash memory %d.\n", - fl_idx); - } + OMAP_CS1_BASE + FLASH1_SIZE, &cs[1]); + + pflash_cfi01_register(OMAP_CS1_BASE, + "omap_sx1.flash1-1", FLASH1_SIZE, + blk_by_legacy_dinfo(dinfo), + SECTOR_SIZE, 4, 0, 0, 0, 0, 0); fl_idx++; } else { memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, @@ -220,7 +213,7 @@ static void sx1_machine_v2_class_init(ObjectClass *oc, void *data) mc->init = sx1_init_v2; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t"); - mc->default_ram_size = sdram_size; + mc->default_ram_size = SDRAM_SIZE; mc->default_ram_id = "omap1.dram"; } @@ -238,7 +231,7 @@ static void sx1_machine_v1_class_init(ObjectClass *oc, void *data) mc->init = sx1_init_v1; mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t"); - mc->default_ram_size = sdram_size; + mc->default_ram_size = SDRAM_SIZE; mc->default_ram_id = "omap1.dram"; } diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 68e11dd1ecc1..1457f10c83a3 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -115,7 +115,7 @@ static struct { static void palmte_button_event(void *opaque, int keycode) { - struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *cpu = opaque; if (palmte_keymap[keycode & 0x7f].row != -1) omap_mpuio_key(cpu->mpuio, diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index a6f938f1152d..07d5dd8691f9 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -11,6 +11,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" +#include "exec/address-spaces.h" #include "cpu.h" #include "hw/sysbus.h" #include "migration/vmstate.h" @@ -30,6 +31,7 @@ #include "qemu/cutils.h" #include "qemu/log.h" #include "qom/object.h" +#include "target/arm/cpregs.h" static struct { hwaddr io_base; @@ -383,7 +385,6 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = { { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_IO, .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, - REGINFO_SENTINEL }; static void pxa2xx_setup_cp14(PXA2xxState *s) @@ -1305,6 +1306,8 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) case I2C_NACK: s->status |= 1 << 1; /* set ACKNAK */ break; + default: + return -1; } pxa2xx_i2c_update(s); @@ -2089,9 +2092,9 @@ static void pxa2xx_reset(void *opaque, int line, int level) } /* Initialise a PXA270 integrated chip (ARM based core). */ -PXA2xxState *pxa270_init(MemoryRegion *address_space, - unsigned int sdram_size, const char *cpu_type) +PXA2xxState *pxa270_init(unsigned int sdram_size, const char *cpu_type) { + MemoryRegion *address_space = get_system_memory(); PXA2xxState *s; int i; DriveInfo *dinfo; @@ -2228,8 +2231,9 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, } /* Initialise a PXA255 integrated chip (ARM based core). */ -PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) +PXA2xxState *pxa255_init(unsigned int sdram_size) { + MemoryRegion *address_space = get_system_memory(); PXA2xxState *s; int i; DriveInfo *dinfo; diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index ed032fed548d..47132ab982b6 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -17,6 +17,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qom/object.h" +#include "target/arm/cpregs.h" #define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ #define ICMR 0x04 /* Interrupt Controller Mask register */ @@ -256,7 +257,6 @@ static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { REGINFO_FOR_PIC_CP("ICLR2", 8), REGINFO_FOR_PIC_CP("ICFP2", 9), REGINFO_FOR_PIC_CP("ICPR2", 0xa), - REGINFO_SENTINEL }; static const MemoryRegionOps pxa2xx_pic_ops = { diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 7b424e94a5f9..d2dc8a895258 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -13,9 +13,11 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "hw/arm/primecell.h" +#include "hw/core/split-irq.h" #include "hw/net/lan9118.h" #include "hw/net/smc91c111.h" #include "hw/pci/pci.h" +#include "hw/qdev-core.h" #include "net/net.h" #include "sysemu/sysemu.h" #include "hw/boards.h" @@ -53,6 +55,20 @@ static const int realview_board_id[] = { 0x76d }; +static void split_irq_from_named(DeviceState *src, const char* outname, + qemu_irq out1, qemu_irq out2) { + DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); + + qdev_prop_set_uint32(splitter, "num-lines", 2); + + qdev_realize_and_unref(splitter, NULL, &error_fatal); + + qdev_connect_gpio_out(splitter, 0, out1); + qdev_connect_gpio_out(splitter, 1, out2); + qdev_connect_gpio_out_named(src, outname, 0, + qdev_get_gpio_in(splitter, 0)); +} + static void realview_init(MachineState *machine, enum realview_board_type board_type) { @@ -66,7 +82,6 @@ static void realview_init(MachineState *machine, DeviceState *dev, *sysctl, *gpio2, *pl041; SysBusDevice *busdev; qemu_irq pic[64]; - qemu_irq mmc_irq[2]; PCIBus *pci_bus = NULL; NICInfo *nd; DriveInfo *dinfo; @@ -229,14 +244,14 @@ static void realview_init(MachineState *machine, * and the PL061 has them the other way about. Also the card * detect line is inverted. */ - mmc_irq[0] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), - qdev_get_gpio_in(gpio2, 1)); - mmc_irq[1] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), - qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); - qdev_connect_gpio_out_named(dev, "card-read-only", 0, mmc_irq[0]); - qdev_connect_gpio_out_named(dev, "card-inserted", 0, mmc_irq[1]); + split_irq_from_named(dev, "card-read-only", + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), + qdev_get_gpio_in(gpio2, 1)); + + split_irq_from_named(dev, "card-inserted", + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), + qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); + dinfo = drive_get(IF_SD, 0, 0); if (dinfo) { DeviceState *card; diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 238740196395..4bb444684f40 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -145,6 +145,8 @@ static const int sbsa_ref_irqmap[] = { static const char * const valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("cortex-a76"), + ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("max"), }; @@ -190,6 +192,20 @@ static void create_fdt(SBSAMachineState *sms) qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); + /* + * This versioning scheme is for informing platform fw only. It is neither: + * - A QEMU versioned machine type; a given version of QEMU will emulate + * a given version of the platform. + * - A reflection of level of SBSA (now SystemReady SR) support provided. + * + * machine-version-major: updated when changes breaking fw compatibility + * are introduced. + * machine-version-minor: updated when features are added that don't break + * fw compatibility. + */ + qemu_fdt_setprop_cell(fdt, "/", "machine-version-major", 0); + qemu_fdt_setprop_cell(fdt, "/", "machine-version-minor", 0); + if (ms->numa_state->have_numa_distance) { int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); uint32_t *matrix = g_malloc0(size); diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index e09b9c13b745..54186f31cb52 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -116,7 +116,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new) g_hash_table_insert(bs->iotlb, key, new); } -inline void smmu_iotlb_inv_all(SMMUState *s) +void smmu_iotlb_inv_all(SMMUState *s) { trace_smmu_iotlb_inv_all(); g_hash_table_remove_all(s->iotlb); @@ -146,9 +146,8 @@ static gboolean smmu_hash_remove_by_asid_iova(gpointer key, gpointer value, ((entry->iova & ~info->mask) == info->iova); } -inline void -smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova, - uint8_t tg, uint64_t num_pages, uint8_t ttl) +void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova, + uint8_t tg, uint64_t num_pages, uint8_t ttl) { /* if tg is not set we use 4KB range invalidation */ uint8_t granule = tg ? tg * 2 + 10 : 12; @@ -174,7 +173,7 @@ smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova, &info); } -inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid) +void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid) { trace_smmu_iotlb_inv_asid(asid); g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid); @@ -374,8 +373,8 @@ static int smmu_ptw_64(SMMUTransCfg *cfg, * * return 0 on success */ -inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm, - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info) +int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm, + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info) { if (!cfg->aa64) { /* @@ -483,7 +482,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n) } /* Unmap all notifiers attached to @mr */ -inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr) +static void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr) { IOMMUNotifier *n; @@ -526,9 +525,9 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) } } -static void smmu_base_reset(DeviceState *dev) +static void smmu_base_reset_hold(Object *obj) { - SMMUState *s = ARM_SMMU(dev); + SMMUState *s = ARM_SMMU(obj); g_hash_table_remove_all(s->configs); g_hash_table_remove_all(s->iotlb); @@ -543,12 +542,13 @@ static Property smmu_dev_properties[] = { static void smmu_base_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); SMMUBaseClass *sbc = ARM_SMMU_CLASS(klass); device_class_set_props(dc, smmu_dev_properties); device_class_set_parent_realize(dc, smmu_base_realize, &sbc->parent_realize); - dc->reset = smmu_base_reset; + rc->phases.hold = smmu_base_reset_hold; } static const TypeInfo smmu_base_info = { diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index d1885ae3f25e..bce161870f69 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -56,6 +56,7 @@ REG32(IDR2, 0x8) REG32(IDR3, 0xc) FIELD(IDR3, HAD, 2, 1); FIELD(IDR3, RIL, 10, 1); + FIELD(IDR3, BBML, 11, 2); REG32(IDR4, 0x10) REG32(IDR5, 0x14) FIELD(IDR5, OAS, 0, 3); @@ -387,7 +388,6 @@ typedef struct SMMUEventInfo { SMMUEventType type; uint32_t sid; bool recorded; - bool record_trans_faults; bool inval_ste_allowed; union { struct { diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 674623aabea5..955b89c8d592 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -259,6 +259,7 @@ static void smmuv3_init_regs(SMMUv3State *s) s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1); + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2); /* 4K, 16K and 64K granule support */ s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1); @@ -527,7 +528,7 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event) trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had); } - event->record_trans_faults = CD_R(cd); + cfg->record_faults = CD_R(cd); return 0; @@ -680,7 +681,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, tt = select_tt(cfg, addr); if (!tt) { - if (event.record_trans_faults) { + if (cfg->record_faults) { event.type = SMMU_EVT_F_TRANSLATION; event.u.f_translation.addr = addr; event.u.f_translation.rnw = flag & 0x1; @@ -696,7 +697,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, if (cached_entry) { if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) { status = SMMU_TRANS_ERROR; - if (event.record_trans_faults) { + if (cfg->record_faults) { event.type = SMMU_EVT_F_PERMISSION; event.u.f_permission.addr = addr; event.u.f_permission.rnw = flag & 0x1; @@ -720,28 +721,28 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, event.u.f_walk_eabt.addr2 = ptw_info.addr; break; case SMMU_PTW_ERR_TRANSLATION: - if (event.record_trans_faults) { + if (cfg->record_faults) { event.type = SMMU_EVT_F_TRANSLATION; event.u.f_translation.addr = addr; event.u.f_translation.rnw = flag & 0x1; } break; case SMMU_PTW_ERR_ADDR_SIZE: - if (event.record_trans_faults) { + if (cfg->record_faults) { event.type = SMMU_EVT_F_ADDR_SIZE; event.u.f_addr_size.addr = addr; event.u.f_addr_size.rnw = flag & 0x1; } break; case SMMU_PTW_ERR_ACCESS: - if (event.record_trans_faults) { + if (cfg->record_faults) { event.type = SMMU_EVT_F_ACCESS; event.u.f_access.addr = addr; event.u.f_access.rnw = flag & 0x1; } break; case SMMU_PTW_ERR_PERMISSION: - if (event.record_trans_faults) { + if (cfg->record_faults) { event.type = SMMU_EVT_F_PERMISSION; event.u.f_permission.addr = addr; event.u.f_permission.rnw = flag & 0x1; @@ -760,7 +761,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, qemu_mutex_unlock(&s->mutex); switch (status) { case SMMU_TRANS_SUCCESS: - entry.perm = flag; + entry.perm = cached_entry->entry.perm; entry.translated_addr = cached_entry->entry.translated_addr + (addr & cached_entry->entry.addr_mask); entry.addr_mask = cached_entry->entry.addr_mask; @@ -786,7 +787,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, break; case SMMU_TRANS_ERROR: qemu_log_mask(LOG_GUEST_ERROR, - "%s translation failed for iova=0x%"PRIx64"(%s)\n", + "%s translation failed for iova=0x%"PRIx64" (%s)\n", mr->parent_obj.name, addr, smmu_event_string(event.type)); smmuv3_record_event(s, &event); break; @@ -1430,12 +1431,14 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev) } } -static void smmu_reset(DeviceState *dev) +static void smmu_reset_hold(Object *obj) { - SMMUv3State *s = ARM_SMMUV3(dev); + SMMUv3State *s = ARM_SMMUV3(obj); SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s); - c->parent_reset(dev); + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } smmuv3_init_regs(s); } @@ -1519,10 +1522,12 @@ static void smmuv3_instance_init(Object *obj) static void smmuv3_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); SMMUv3Class *c = ARM_SMMUV3_CLASS(klass); dc->vmsd = &vmstate_smmuv3; - device_class_set_parent_reset(dc, smmu_reset, &c->parent_reset); + resettable_class_set_parent_phases(rc, NULL, smmu_reset_hold, NULL, + &c->parent_phases); c->parent_realize = dc->realize; dc->realize = smmu_realize; } diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 5aab0b856574..f732fe0acf90 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -986,18 +986,16 @@ static void spitz_common_init(MachineState *machine) SpitzMachineState *sms = SPITZ_MACHINE(machine); enum spitz_model_e model = smc->model; PXA2xxState *mpu; - MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, - machine->cpu_type); + mpu = pxa270_init(spitz_binfo.ram_size, machine->cpu_type); sms->mpu = mpu; sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); memory_region_init_rom(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal); - memory_region_add_subregion(address_space_mem, 0, rom); + memory_region_add_subregion(get_system_memory(), 0, rom); /* Setup peripherals */ spitz_keyboard_register(mpu); diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index b6c8a5d60983..67a2293d35f3 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "hw/core/split-irq.h" #include "hw/sysbus.h" #include "hw/sd/sd.h" #include "hw/ssi/ssi.h" @@ -673,9 +674,8 @@ static void stellaris_i2c_init(Object *obj) #define STELLARIS_ADC_FIFO_FULL 0x1000 #define TYPE_STELLARIS_ADC "stellaris-adc" -typedef struct StellarisADCState stellaris_adc_state; -DECLARE_INSTANCE_CHECKER(stellaris_adc_state, STELLARIS_ADC, - TYPE_STELLARIS_ADC) +typedef struct StellarisADCState StellarisADCState; +DECLARE_INSTANCE_CHECKER(StellarisADCState, STELLARIS_ADC, TYPE_STELLARIS_ADC) struct StellarisADCState { SysBusDevice parent_obj; @@ -699,7 +699,7 @@ struct StellarisADCState { qemu_irq irq[4]; }; -static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) +static uint32_t stellaris_adc_fifo_read(StellarisADCState *s, int n) { int tail; @@ -715,7 +715,7 @@ static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) return s->fifo[n].data[tail]; } -static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, +static void stellaris_adc_fifo_write(StellarisADCState *s, int n, uint32_t value) { int head; @@ -735,7 +735,7 @@ static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; } -static void stellaris_adc_update(stellaris_adc_state *s) +static void stellaris_adc_update(StellarisADCState *s) { int level; int n; @@ -748,7 +748,7 @@ static void stellaris_adc_update(stellaris_adc_state *s) static void stellaris_adc_trigger(void *opaque, int irq, int level) { - stellaris_adc_state *s = (stellaris_adc_state *)opaque; + StellarisADCState *s = opaque; int n; for (n = 0; n < 4; n++) { @@ -770,7 +770,7 @@ static void stellaris_adc_trigger(void *opaque, int irq, int level) } } -static void stellaris_adc_reset(stellaris_adc_state *s) +static void stellaris_adc_reset(StellarisADCState *s) { int n; @@ -784,7 +784,7 @@ static void stellaris_adc_reset(stellaris_adc_state *s) static uint64_t stellaris_adc_read(void *opaque, hwaddr offset, unsigned size) { - stellaris_adc_state *s = (stellaris_adc_state *)opaque; + StellarisADCState *s = opaque; /* TODO: Implement this. */ if (offset >= 0x40 && offset < 0xc0) { @@ -832,7 +832,7 @@ static uint64_t stellaris_adc_read(void *opaque, hwaddr offset, static void stellaris_adc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - stellaris_adc_state *s = (stellaris_adc_state *)opaque; + StellarisADCState *s = opaque; /* TODO: Implement this. */ if (offset >= 0x40 && offset < 0xc0) { @@ -900,31 +900,31 @@ static const VMStateDescription vmstate_stellaris_adc = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(actss, stellaris_adc_state), - VMSTATE_UINT32(ris, stellaris_adc_state), - VMSTATE_UINT32(im, stellaris_adc_state), - VMSTATE_UINT32(emux, stellaris_adc_state), - VMSTATE_UINT32(ostat, stellaris_adc_state), - VMSTATE_UINT32(ustat, stellaris_adc_state), - VMSTATE_UINT32(sspri, stellaris_adc_state), - VMSTATE_UINT32(sac, stellaris_adc_state), - VMSTATE_UINT32(fifo[0].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[0], stellaris_adc_state), - VMSTATE_UINT32(ssctl[0], stellaris_adc_state), - VMSTATE_UINT32(fifo[1].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[1], stellaris_adc_state), - VMSTATE_UINT32(ssctl[1], stellaris_adc_state), - VMSTATE_UINT32(fifo[2].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[2], stellaris_adc_state), - VMSTATE_UINT32(ssctl[2], stellaris_adc_state), - VMSTATE_UINT32(fifo[3].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[3], stellaris_adc_state), - VMSTATE_UINT32(ssctl[3], stellaris_adc_state), - VMSTATE_UINT32(noise, stellaris_adc_state), + VMSTATE_UINT32(actss, StellarisADCState), + VMSTATE_UINT32(ris, StellarisADCState), + VMSTATE_UINT32(im, StellarisADCState), + VMSTATE_UINT32(emux, StellarisADCState), + VMSTATE_UINT32(ostat, StellarisADCState), + VMSTATE_UINT32(ustat, StellarisADCState), + VMSTATE_UINT32(sspri, StellarisADCState), + VMSTATE_UINT32(sac, StellarisADCState), + VMSTATE_UINT32(fifo[0].state, StellarisADCState), + VMSTATE_UINT32_ARRAY(fifo[0].data, StellarisADCState, 16), + VMSTATE_UINT32(ssmux[0], StellarisADCState), + VMSTATE_UINT32(ssctl[0], StellarisADCState), + VMSTATE_UINT32(fifo[1].state, StellarisADCState), + VMSTATE_UINT32_ARRAY(fifo[1].data, StellarisADCState, 16), + VMSTATE_UINT32(ssmux[1], StellarisADCState), + VMSTATE_UINT32(ssctl[1], StellarisADCState), + VMSTATE_UINT32(fifo[2].state, StellarisADCState), + VMSTATE_UINT32_ARRAY(fifo[2].data, StellarisADCState, 16), + VMSTATE_UINT32(ssmux[2], StellarisADCState), + VMSTATE_UINT32(ssctl[2], StellarisADCState), + VMSTATE_UINT32(fifo[3].state, StellarisADCState), + VMSTATE_UINT32_ARRAY(fifo[3].data, StellarisADCState, 16), + VMSTATE_UINT32(ssmux[3], StellarisADCState), + VMSTATE_UINT32(ssctl[3], StellarisADCState), + VMSTATE_UINT32(noise, StellarisADCState), VMSTATE_END_OF_LIST() } }; @@ -932,7 +932,7 @@ static const VMStateDescription vmstate_stellaris_adc = { static void stellaris_adc_init(Object *obj) { DeviceState *dev = DEVICE(obj); - stellaris_adc_state *s = STELLARIS_ADC(obj); + StellarisADCState *s = STELLARIS_ADC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); int n; @@ -1160,6 +1160,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) DeviceState *ssddev; DriveInfo *dinfo; DeviceState *carddev; + DeviceState *gpio_d_splitter; BlockBackend *blk; /* @@ -1237,9 +1238,18 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) &error_fatal); ssddev = ssi_create_peripheral(bus, "ssd0323"); - gpio_out[GPIO_D][0] = qemu_irq_split( - qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0), + + gpio_d_splitter = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint32(gpio_d_splitter, "num-lines", 2); + qdev_realize_and_unref(gpio_d_splitter, NULL, &error_fatal); + qdev_connect_gpio_out( + gpio_d_splitter, 0, + qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0)); + qdev_connect_gpio_out( + gpio_d_splitter, 1, qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0)); + gpio_out[GPIO_D][0] = qdev_get_gpio_in(gpio_d_splitter, 0); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0); /* Make sure the select pin is high. */ @@ -1291,7 +1301,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. */ @@ -1370,7 +1380,7 @@ static void stellaris_adc_class_init(ObjectClass *klass, void *data) static const TypeInfo stellaris_adc_info = { .name = TYPE_STELLARIS_ADC, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(stellaris_adc_state), + .instance_size = sizeof(StellarisADCState), .instance_init = stellaris_adc_init, .class_init = stellaris_adc_class_init, }; diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index c07947d9f8b1..cef23d7ee41a 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -139,6 +139,14 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) } memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram); + memory_region_init_ram(&s->ccm, NULL, "STM32F405.ccm", CCM_SIZE, + &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(system_memory, CCM_BASE_ADDRESS, &s->ccm); + armv7m = DEVICE(&s->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 96); qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c index 04036da3ee03..67675e952fca 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/tosa.c b/hw/arm/tosa.c index d5a6763cf9ac..3ca2e4459ca5 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -242,7 +242,7 @@ static void tosa_init(MachineState *machine) TC6393xbState *tmio; DeviceState *scp0, *scp1; - mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); + mpu = pxa255_init(tosa_binfo.ram_size); memory_region_init_rom(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal); memory_region_add_subregion(address_space_mem, 0, rom); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index ecc1f6cf74ff..43172d72ea44 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -385,13 +385,11 @@ static void versatile_init(MachineState *machine, int board_id) /* 0x34000000 NOR Flash */ dinfo = drive_get(IF_PFLASH, 0, 0); - if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, "versatile.flash", + pflash_cfi01_register(VERSATILE_FLASH_ADDR, "versatile.flash", VERSATILE_FLASH_SIZE, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, VERSATILE_FLASH_SECT_SIZE, - 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - } + 4, 0x0089, 0x0018, 0x0000, 0x0, 0); versatile_binfo.ram_size = machine->ram_size; versatile_binfo.board_id = board_id; diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index e1d1983ae657..757236767b06 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -659,10 +659,6 @@ static void vexpress_common_init(MachineState *machine) dinfo = drive_get(IF_PFLASH, 0, 0); pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0", dinfo); - if (!pflash0) { - error_report("vexpress: error registering flash 0"); - exit(1); - } if (map[VE_NORFLASHALIAS] != -1) { /* Map flash 0 as an alias into low memory */ @@ -673,11 +669,7 @@ static void vexpress_common_init(MachineState *machine) } dinfo = drive_get(IF_PFLASH, 0, 1); - if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1", - dinfo)) { - error_report("vexpress: error registering flash 1"); - exit(1); - } + ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1", dinfo); sram_size = 0x2000000; memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size, diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 449fab00805a..4156111d49f0 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -42,6 +42,7 @@ #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/generic_event_device.h" #include "hw/acpi/tpm.h" +#include "hw/acpi/hmat.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" @@ -592,8 +593,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 +618,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 */ @@ -686,7 +686,7 @@ build_dbg2(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) }; /* - * ACPI spec, Revision 5.1 Errata A + * ACPI spec, Revision 6.0 Errata A * 5.2.12 Multiple APIC Description Table (MADT) */ static void build_append_gicr(GArray *table_data, uint64_t base, uint32_t size) @@ -705,7 +705,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) int i; VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); const MemMapEntry *memmap = vms->memmap; - AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = vms->oem_id, + AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; acpi_table_begin(&table, table_data); @@ -732,7 +732,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; @@ -740,7 +740,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) /* 5.2.12.14 GIC Structure */ build_append_int_noprefix(table_data, 0xB, 1); /* Type */ - build_append_int_noprefix(table_data, 76, 1); /* Length */ + build_append_int_noprefix(table_data, 80, 1); /* Length */ build_append_int_noprefix(table_data, 0, 2); /* Reserved */ build_append_int_noprefix(table_data, i, 4); /* GIC ID */ build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ @@ -760,9 +760,13 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_append_int_noprefix(table_data, 0, 8); /* GICR Base Address*/ /* MPIDR */ build_append_int_noprefix(table_data, armcpu->mp_affinity, 8); + /* Processor Power Efficiency Class */ + build_append_int_noprefix(table_data, 0, 1); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 3); } - 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) { @@ -771,12 +775,6 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } if (its_class_name() && !vmc->no_its) { - /* - * FIXME: Structure is from Revision 6.0 where 'GIC Structure' - * has additional fields on top of implemented 5.1 Errata A, - * to make it consistent with v6.0 we need to bump everything - * to v6.0 - */ /* * ACPI spec, Revision 6.0 Errata A * (original 6.0 definition has invalid Length) @@ -809,13 +807,13 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } /* FADT */ -static void build_fadt_rev5(GArray *table_data, BIOSLinker *linker, +static void build_fadt_rev6(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms, unsigned dsdt_tbl_offset) { - /* ACPI v5.1 */ + /* ACPI v6.0 */ AcpiFadtData fadt = { - .rev = 5, - .minor_ver = 1, + .rev = 6, + .minor_ver = 0, .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI, .xdsdt_tbl_offset = &dsdt_tbl_offset, }; @@ -945,7 +943,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) /* FADT MADT PPTT GTDT MCFG SPCR DBG2 pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); - build_fadt_rev5(tables_blob, tables->linker, vms, dsdt); + build_fadt_rev6(tables_blob, tables->linker, vms, dsdt); acpi_add_table(table_offsets, tables_blob); build_madt(tables_blob, tables->linker, vms); @@ -990,6 +988,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) build_slit(tables_blob, tables->linker, ms, vms->oem_id, vms->oem_table_id); } + + if (ms->numa_state->hmat_enabled) { + acpi_add_table(table_offsets, tables_blob); + build_hmat(tables_blob, tables->linker, ms->numa_state, + vms->oem_id, vms->oem_table_id); + } } if (ms->nvdimms_state->is_enabled) { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d2e5ecd234a9..ea2413a0bad7 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -56,7 +56,7 @@ #include "qemu/module.h" #include "hw/pci-host/gpex.h" #include "hw/virtio/virtio-pci.h" -#include "hw/arm/sysbus-fdt.h" +#include "hw/core/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/qdev-properties.h" #include "hw/arm/fdt.h" @@ -174,6 +174,12 @@ static const MemMapEntry base_memmap[] = { * Note the extended_memmap is sized so that it eventually also includes the * base_memmap entries (VIRT_HIGH_GIC_REDIST2 index is greater than the last * index of base_memmap). + * + * The memory map for these Highmem IO Regions can be in legacy or compact + * layout, depending on 'compact-highmem' property. With legacy layout, the + * PA space for one specific region is always reserved, even if the region + * has been disabled or doesn't fit into the PA space. However, the PA space + * for the region won't be reserved in these circumstances with compact layout. */ static MemMapEntry extended_memmap[] = { /* Additional 64 MB redist region (can contain up to 512 redistributors) */ @@ -199,10 +205,14 @@ 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-a55"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("a64fx"), + ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), }; @@ -219,14 +229,18 @@ static bool cpu_type_valid(const char *cpu) return false; } -static void create_kaslr_seed(MachineState *ms, const char *node) +static void create_randomness(MachineState *ms, const char *node) { - uint64_t seed; + struct { + uint64_t kaslr; + uint8_t rng[32]; + } seed; if (qemu_guest_getrandom(&seed, sizeof(seed), NULL)) { return; } - qemu_fdt_setprop_u64(ms->fdt, node, "kaslr-seed", seed); + qemu_fdt_setprop_u64(ms->fdt, node, "kaslr-seed", seed.kaslr); + qemu_fdt_setprop(ms->fdt, node, "rng-seed", seed.rng, sizeof(seed.rng)); } static void create_fdt(VirtMachineState *vms) @@ -246,17 +260,18 @@ 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"); - if (vms->dtb_kaslr_seed) { - create_kaslr_seed(ms, "/chosen"); + if (vms->dtb_randomness) { + create_randomness(ms, "/chosen"); } if (vms->secure) { qemu_fdt_add_subnode(fdt, "/secure-chosen"); - if (vms->dtb_kaslr_seed) { - create_kaslr_seed(ms, "/secure-chosen"); + if (vms->dtb_randomness) { + create_randomness(ms, "/secure-chosen"); } } @@ -480,6 +495,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); @@ -522,7 +538,7 @@ static void fdt_add_gic_node(VirtMachineState *vms) 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); - if (vms->gic_version == VIRT_GIC_VERSION_3) { + if (vms->gic_version != VIRT_GIC_VERSION_2) { int nb_redist_regions = virt_gicv3_redist_region_count(vms); qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", @@ -690,14 +706,32 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) /* We create a standalone GIC */ SysBusDevice *gicbusdev; const char *gictype; - int type = vms->gic_version, i; + int i; unsigned int smp_cpus = ms->smp.cpus; uint32_t nb_redist_regions = 0; + int revision; - gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); + if (vms->gic_version == VIRT_GIC_VERSION_2) { + gictype = gic_class_name(); + } else { + gictype = gicv3_class_name(); + } + switch (vms->gic_version) { + case VIRT_GIC_VERSION_2: + revision = 2; + break; + case VIRT_GIC_VERSION_3: + revision = 3; + break; + case VIRT_GIC_VERSION_4: + revision = 4; + break; + default: + g_assert_not_reached(); + } vms->gic = qdev_new(gictype); - qdev_prop_set_uint32(vms->gic, "revision", type); + qdev_prop_set_uint32(vms->gic, "revision", revision); qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); /* Note that the num-irq property counts both internal and external * interrupts; there are always 32 of the former (mandated by GIC spec). @@ -707,9 +741,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) qdev_prop_set_bit(vms->gic, "has-security-extensions", vms->secure); } - if (type == 3) { - uint32_t redist0_capacity = - vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; + if (vms->gic_version != VIRT_GIC_VERSION_2) { + uint32_t redist0_capacity = virt_redist_capacity(vms, VIRT_GIC_REDIST); uint32_t redist0_count = MIN(smp_cpus, redist0_capacity); nb_redist_regions = virt_gicv3_redist_region_count(vms); @@ -728,7 +761,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) if (nb_redist_regions == 2) { uint32_t redist1_capacity = - vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; + virt_redist_capacity(vms, VIRT_HIGH_GIC_REDIST2); qdev_prop_set_uint32(vms->gic, "redist-region-count[1]", MIN(smp_cpus - redist0_count, redist1_capacity)); @@ -742,7 +775,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) gicbusdev = SYS_BUS_DEVICE(vms->gic); sysbus_realize_and_unref(gicbusdev, &error_fatal); sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); - if (type == 3) { + if (vms->gic_version != VIRT_GIC_VERSION_2) { sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); if (nb_redist_regions == 2) { sysbus_mmio_map(gicbusdev, 2, @@ -780,7 +813,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) ppibase + timer_irq[irq])); } - if (type == 3) { + if (vms->gic_version != VIRT_GIC_VERSION_2) { qemu_irq irq = qdev_get_gpio_in(vms->gic, ppibase + ARCH_GIC_MAINT_IRQ); qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", @@ -806,9 +839,9 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) fdt_add_gic_node(vms); - if (type == 3 && vms->its) { + if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) { create_its(vms); - } else if (type == 2) { + } else if (vms->gic_version == VIRT_GIC_VERSION_2) { create_v2m(vms); } } @@ -906,8 +939,6 @@ static void create_gpio_keys(char *fdt, DeviceState *pl061_dev, qemu_fdt_add_subnode(fdt, "/gpio-keys"); qemu_fdt_setprop_string(fdt, "/gpio-keys", "compatible", "gpio-keys"); - qemu_fdt_setprop_cell(fdt, "/gpio-keys", "#size-cells", 0); - qemu_fdt_setprop_cell(fdt, "/gpio-keys", "#address-cells", 1); qemu_fdt_add_subnode(fdt, "/gpio-keys/poweroff"); qemu_fdt_setprop_string(fdt, "/gpio-keys/poweroff", @@ -1176,7 +1207,7 @@ static void virt_flash_fdt(VirtMachineState *vms, qemu_fdt_setprop_string(ms->fdt, nodename, "secure-status", "okay"); g_free(nodename); - nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); + nodename = g_strdup_printf("/flash@%" PRIx64, flashbase + flashsize); qemu_fdt_add_subnode(ms->fdt, nodename); qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash"); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", @@ -1337,8 +1368,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); @@ -1349,14 +1378,15 @@ static void create_smmu(const VirtMachineState *vms, static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) { - const char compat[] = "virtio,pci-iommu"; + const char compat[] = "virtio,pci-iommu\0pci1af4,1057"; uint16_t bdf = vms->virtio_iommu_bdf; MachineState *ms = MACHINE(vms); char *node; vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt); - node = g_strdup_printf("%s/virtio_iommu@%d", vms->pciehb_nodename, bdf); + node = g_strdup_printf("%s/virtio_iommu@%x,%x", vms->pciehb_nodename, + PCI_SLOT(bdf), PCI_FUNC(bdf)); qemu_fdt_add_subnode(ms->fdt, node); qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat)); qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", @@ -1466,8 +1496,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", @@ -1585,9 +1615,11 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) static void virt_build_smbios(VirtMachineState *vms) { MachineClass *mc = MACHINE_GET_CLASS(vms); + MachineState *ms = MACHINE(vms); VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; + struct smbios_phys_mem_area mem_array; const char *product = "QEMU Virtual Machine"; if (kvm_enabled()) { @@ -1598,7 +1630,11 @@ static void virt_build_smbios(VirtMachineState *vms) vmc->smbios_old_sys_ver ? "1.0" : mc->name, false, true, SMBIOS_ENTRY_POINT_TYPE_64); - smbios_get_tables(MACHINE(vms), NULL, 0, + /* build the array of physical mem area from base_memmap */ + mem_array.address = vms->memmap[VIRT_MEM].base; + mem_array.length = ms->ram_size; + + smbios_get_tables(ms, &mem_array, 1, &smbios_tables, &smbios_tables_len, &smbios_anchor, &smbios_anchor_len, &error_fatal); @@ -1658,15 +1694,67 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) * purposes are to make TCG consistent (with 64-bit KVM hosts) * and to improve SGI efficiency. */ - if (vms->gic_version == VIRT_GIC_VERSION_3) { - clustersz = GICV3_TARGETLIST_BITS; - } else { + if (vms->gic_version == VIRT_GIC_VERSION_2) { clustersz = GIC_TARGETLIST_BITS; + } else { + clustersz = GICV3_TARGETLIST_BITS; } } return arm_cpu_mp_affinity(idx, clustersz); } +static inline bool *virt_get_high_memmap_enabled(VirtMachineState *vms, + int index) +{ + bool *enabled_array[] = { + &vms->highmem_redists, + &vms->highmem_ecam, + &vms->highmem_mmio, + }; + + assert(ARRAY_SIZE(extended_memmap) - VIRT_LOWMEMMAP_LAST == + ARRAY_SIZE(enabled_array)); + assert(index - VIRT_LOWMEMMAP_LAST < ARRAY_SIZE(enabled_array)); + + return enabled_array[index - VIRT_LOWMEMMAP_LAST]; +} + +static void virt_set_high_memmap(VirtMachineState *vms, + hwaddr base, int pa_bits) +{ + hwaddr region_base, region_size; + bool *region_enabled, fits; + int i; + + for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { + region_enabled = virt_get_high_memmap_enabled(vms, i); + region_base = ROUND_UP(base, extended_memmap[i].size); + region_size = extended_memmap[i].size; + + vms->memmap[i].base = region_base; + vms->memmap[i].size = region_size; + + /* + * Check each device to see if it fits in the PA space, + * moving highest_gpa as we go. For compatibility, move + * highest_gpa for disabled fitting devices as well, if + * the compact layout has been disabled. + * + * For each device that doesn't fit, disable it. + */ + fits = (region_base + region_size) <= BIT_ULL(pa_bits); + *region_enabled &= fits; + if (vms->highmem_compact && !*region_enabled) { + continue; + } + + base = region_base + region_size; + if (fits) { + vms->highest_gpa = base - 1; + } + } +} + static void virt_set_memmap(VirtMachineState *vms, int pa_bits) { MachineState *ms = MACHINE(vms); @@ -1722,39 +1810,7 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits) /* We know for sure that at least the memory fits in the PA space */ vms->highest_gpa = memtop - 1; - for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { - hwaddr size = extended_memmap[i].size; - bool fits; - - base = ROUND_UP(base, size); - vms->memmap[i].base = base; - vms->memmap[i].size = size; - - /* - * Check each device to see if they fit in the PA space, - * moving highest_gpa as we go. - * - * For each device that doesn't fit, disable it. - */ - fits = (base + size) <= BIT_ULL(pa_bits); - if (fits) { - vms->highest_gpa = base + size - 1; - } - - switch (i) { - case VIRT_HIGH_GIC_REDIST2: - vms->highmem_redists &= fits; - break; - case VIRT_HIGH_PCIE_ECAM: - vms->highmem_ecam &= fits; - break; - case VIRT_HIGH_PCIE_MMIO: - vms->highmem_mmio &= fits; - break; - } - - base += size; - } + virt_set_high_memmap(vms, base, pa_bits); if (device_memory_size > 0) { ms->device_memory = g_malloc0(sizeof(*ms->device_memory)); @@ -1794,6 +1850,10 @@ static void finalize_gic_version(VirtMachineState *vms) error_report( "gic-version=3 is not supported with kernel-irqchip=off"); exit(1); + case VIRT_GIC_VERSION_4: + error_report( + "gic-version=4 is not supported with kernel-irqchip=off"); + exit(1); } } @@ -1831,6 +1891,9 @@ static void finalize_gic_version(VirtMachineState *vms) case VIRT_GIC_VERSION_2: case VIRT_GIC_VERSION_3: break; + case VIRT_GIC_VERSION_4: + error_report("gic-version=4 is not supported with KVM"); + exit(1); } /* Check chosen version is effectively supported by the host */ @@ -1854,7 +1917,12 @@ static void finalize_gic_version(VirtMachineState *vms) case VIRT_GIC_VERSION_MAX: if (module_object_class_by_name("arm-gicv3")) { /* CONFIG_ARM_GICV3_TCG was set */ - vms->gic_version = VIRT_GIC_VERSION_3; + if (vms->virt) { + /* GICv4 only makes sense if CPU has EL2 */ + vms->gic_version = VIRT_GIC_VERSION_4; + } else { + vms->gic_version = VIRT_GIC_VERSION_3; + } } else { vms->gic_version = VIRT_GIC_VERSION_2; } @@ -1862,6 +1930,12 @@ static void finalize_gic_version(VirtMachineState *vms) case VIRT_GIC_VERSION_HOST: error_report("gic-version=host requires KVM"); exit(1); + case VIRT_GIC_VERSION_4: + if (!vms->virt) { + error_report("gic-version=4 requires virtualization enabled"); + exit(1); + } + break; case VIRT_GIC_VERSION_2: case VIRT_GIC_VERSION_3: break; @@ -1975,15 +2049,7 @@ static void machvirt_init(MachineState *machine) cpuobj = object_new(possible_cpus->cpus[0].type); armcpu = ARM_CPU(cpuobj); - if (object_property_get_bool(cpuobj, "aarch64", NULL)) { - pa_bits = arm_pamax(armcpu); - } else if (arm_feature(&armcpu->env, ARM_FEATURE_LPAE)) { - /* v7 with LPAE */ - pa_bits = 40; - } else { - /* Anything else */ - pa_bits = 32; - } + pa_bits = arm_pamax(armcpu); object_unref(cpuobj); @@ -2029,22 +2095,35 @@ static void machvirt_init(MachineState *machine) vms->psci_conduit = QEMU_PSCI_CONDUIT_HVC; } - /* The maximum number of CPUs depends on the GIC version, or on how - * many redistributors we can fit into the memory map. + /* + * The maximum number of CPUs depends on the GIC version, or on how + * many redistributors we can fit into the memory map (which in turn + * depends on whether this is a GICv3 or v4). */ - if (vms->gic_version == VIRT_GIC_VERSION_3) { - virt_max_cpus = - vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; - virt_max_cpus += - vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; - } else { + if (vms->gic_version == VIRT_GIC_VERSION_2) { virt_max_cpus = GIC_NCPU; + } else { + virt_max_cpus = virt_redist_capacity(vms, VIRT_GIC_REDIST); + if (vms->highmem_redists) { + virt_max_cpus += virt_redist_capacity(vms, VIRT_HIGH_GIC_REDIST2); + } } if (max_cpus > virt_max_cpus) { error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " "supported by machine 'mach-virt' (%d)", max_cpus, virt_max_cpus); + if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->highmem_redists) { + error_printf("Try 'highmem-redists=on' for more CPUs\n"); + } + + exit(1); + } + + if (vms->secure && (kvm_enabled() || hvf_enabled())) { + error_report("mach-virt: %s does not support providing " + "Security extensions (TrustZone) to the guest CPU", + kvm_enabled() ? "KVM" : "HVF"); exit(1); } @@ -2292,6 +2371,63 @@ static void virt_set_highmem(Object *obj, bool value, Error **errp) vms->highmem = value; } +static bool virt_get_compact_highmem(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_compact; +} + +static void virt_set_compact_highmem(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_compact = value; +} + +static bool virt_get_highmem_redists(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_redists; +} + +static void virt_set_highmem_redists(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_redists = value; +} + +static bool virt_get_highmem_ecam(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_ecam; +} + +static void virt_set_highmem_ecam(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_ecam = value; +} + +static bool virt_get_highmem_mmio(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_mmio; +} + +static void virt_set_highmem_mmio(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_mmio = value; +} + + static bool virt_get_its(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -2306,18 +2442,18 @@ static void virt_set_its(Object *obj, bool value, Error **errp) vms->its = value; } -static bool virt_get_dtb_kaslr_seed(Object *obj, Error **errp) +static bool virt_get_dtb_randomness(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); - return vms->dtb_kaslr_seed; + return vms->dtb_randomness; } -static void virt_set_dtb_kaslr_seed(Object *obj, bool value, Error **errp) +static void virt_set_dtb_randomness(Object *obj, bool value, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); - vms->dtb_kaslr_seed = value; + vms->dtb_randomness = value; } static char *virt_get_oem_id(Object *obj, Error **errp) @@ -2419,8 +2555,19 @@ static void virt_set_mte(Object *obj, bool value, Error **errp) static char *virt_get_gic_version(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); - const char *val = vms->gic_version == VIRT_GIC_VERSION_3 ? "3" : "2"; + const char *val; + switch (vms->gic_version) { + case VIRT_GIC_VERSION_4: + val = "4"; + break; + case VIRT_GIC_VERSION_3: + val = "3"; + break; + default: + val = "2"; + break; + } return g_strdup(val); } @@ -2428,7 +2575,9 @@ static void virt_set_gic_version(Object *obj, const char *value, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); - if (!strcmp(value, "3")) { + if (!strcmp(value, "4")) { + vms->gic_version = VIRT_GIC_VERSION_4; + } else if (!strcmp(value, "3")) { vms->gic_version = VIRT_GIC_VERSION_3; } else if (!strcmp(value, "2")) { vms->gic_version = VIRT_GIC_VERSION_2; @@ -2497,7 +2646,9 @@ virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) { - return idx % ms->numa_state->num_nodes; + int64_t socket_id = ms->possible_cpus->cpus[idx].props.socket_id; + + return socket_id % ms->numa_state->num_nodes; } static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) @@ -2505,6 +2656,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) int n; unsigned int max_cpus = ms->smp.max_cpus; VirtMachineState *vms = VIRT_MACHINE(ms); + MachineClass *mc = MACHINE_GET_CLASS(vms); if (ms->possible_cpus) { assert(ms->possible_cpus->len == max_cpus); @@ -2518,8 +2670,20 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) ms->possible_cpus->cpus[n].type = ms->cpu_type; ms->possible_cpus->cpus[n].arch_id = virt_cpu_mp_affinity(vms, n); + + assert(!mc->smp_props.dies_supported); + ms->possible_cpus->cpus[n].props.has_socket_id = true; + ms->possible_cpus->cpus[n].props.socket_id = + n / (ms->smp.clusters * ms->smp.cores * ms->smp.threads); + ms->possible_cpus->cpus[n].props.has_cluster_id = true; + ms->possible_cpus->cpus[n].props.cluster_id = + (n / (ms->smp.cores * ms->smp.threads)) % ms->smp.clusters; + ms->possible_cpus->cpus[n].props.has_core_id = true; + ms->possible_cpus->cpus[n].props.core_id = + (n / ms->smp.threads) % ms->smp.cores; ms->possible_cpus->cpus[n].props.has_thread_id = true; - ms->possible_cpus->cpus[n].props.thread_id = n; + ms->possible_cpus->cpus[n].props.thread_id = + n % ms->smp.threads; } return ms->possible_cpus; } @@ -2703,24 +2867,20 @@ static void virt_dimm_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); - Error *local_err = NULL; if (!vms->acpi_dev) { - error_setg(&local_err, + error_setg(errp, "memory hotplug is not enabled: missing acpi-ged device"); - goto out; + return; } if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { - error_setg(&local_err, - "nvdimm device hot unplug is not supported yet."); - goto out; + error_setg(errp, "nvdimm device hot unplug is not supported yet."); + return; } hotplug_handler_unplug_request(HOTPLUG_HANDLER(vms->acpi_dev), dev, - &local_err); -out: - error_propagate(errp, local_err); + errp); } static void virt_dimm_unplug(HotplugHandler *hotplug_dev, @@ -2882,11 +3042,40 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) "Set on/off to enable/disable using " "physical address space above 32 bits"); + object_class_property_add_bool(oc, "compact-highmem", + virt_get_compact_highmem, + virt_set_compact_highmem); + object_class_property_set_description(oc, "compact-highmem", + "Set on/off to enable/disable compact " + "layout for high memory regions"); + + object_class_property_add_bool(oc, "highmem-redists", + virt_get_highmem_redists, + virt_set_highmem_redists); + object_class_property_set_description(oc, "highmem-redists", + "Set on/off to enable/disable high " + "memory region for GICv3 or GICv4 " + "redistributor"); + + object_class_property_add_bool(oc, "highmem-ecam", + virt_get_highmem_ecam, + virt_set_highmem_ecam); + object_class_property_set_description(oc, "highmem-ecam", + "Set on/off to enable/disable high " + "memory region for PCI ECAM"); + + object_class_property_add_bool(oc, "highmem-mmio", + virt_get_highmem_mmio, + virt_set_highmem_mmio); + object_class_property_set_description(oc, "highmem-mmio", + "Set on/off to enable/disable high " + "memory region for PCI MMIO"); + object_class_property_add_str(oc, "gic-version", virt_get_gic_version, virt_set_gic_version); object_class_property_set_description(oc, "gic-version", "Set GIC version. " - "Valid values are 2, 3, host and max"); + "Valid values are 2, 3, 4, host and max"); object_class_property_add_str(oc, "iommu", virt_get_iommu, virt_set_iommu); object_class_property_set_description(oc, "iommu", @@ -2918,12 +3107,18 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) "Set on/off to enable/disable " "ITS instantiation"); + object_class_property_add_bool(oc, "dtb-randomness", + virt_get_dtb_randomness, + virt_set_dtb_randomness); + object_class_property_set_description(oc, "dtb-randomness", + "Set off to disable passing random or " + "non-deterministic dtb nodes to guest"); + object_class_property_add_bool(oc, "dtb-kaslr-seed", - virt_get_dtb_kaslr_seed, - virt_set_dtb_kaslr_seed); + virt_get_dtb_randomness, + virt_set_dtb_randomness); object_class_property_set_description(oc, "dtb-kaslr-seed", - "Set off to disable passing of kaslr-seed " - "dtb node to guest"); + "Deprecated synonym of dtb-randomness"); object_class_property_add_str(oc, "x-oem-id", virt_get_oem_id, @@ -2960,6 +3155,7 @@ static void virt_instance_init(Object *obj) /* High memory is enabled by default */ vms->highmem = true; + vms->highmem_compact = !vmc->no_highmem_compact; vms->gic_version = VIRT_GIC_VERSION_NOSEL; vms->highmem_ecam = !vmc->no_highmem_ecam; @@ -2991,8 +3187,8 @@ static void virt_instance_init(Object *obj) /* MTE is disabled by default. */ vms->mte = false; - /* Supply a kaslr-seed by default */ - vms->dtb_kaslr_seed = true; + /* Supply kaslr-seed and rng-seed by default */ + vms->dtb_randomness = true; vms->irqmap = a15irqmap; @@ -3022,10 +3218,35 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); +static void virt_machine_8_0_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(8, 0) + +static void virt_machine_7_2_options(MachineClass *mc) +{ + virt_machine_8_0_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len); +} +DEFINE_VIRT_MACHINE(7, 2) + +static void virt_machine_7_1_options(MachineClass *mc) +{ + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + + virt_machine_7_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); + /* Compact layout for high memory regions was introduced with 7.2 */ + vmc->no_highmem_compact = true; +} +DEFINE_VIRT_MACHINE(7, 1) + static void virt_machine_7_0_options(MachineClass *mc) { + virt_machine_7_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len); } -DEFINE_VIRT_MACHINE_AS_LATEST(7, 0) +DEFINE_VIRT_MACHINE(7, 0) static void virt_machine_6_2_options(MachineClass *mc) { diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 7c7baff8b7f9..37fc9b919c07 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -15,7 +15,6 @@ #include "sysemu/device_tree.h" #include "hw/boards.h" #include "hw/sysbus.h" -#include "hw/arm/sysbus-fdt.h" #include "hw/arm/fdt.h" #include "cpu.h" #include "hw/qdev-properties.h" @@ -721,9 +720,9 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data) mc->desc = "Xilinx Versal Virtual development board"; mc->init = versal_virt_init; - mc->min_cpus = XLNX_VERSAL_NR_ACPUS; - mc->max_cpus = XLNX_VERSAL_NR_ACPUS; - mc->default_cpus = XLNX_VERSAL_NR_ACPUS; + mc->min_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; + mc->max_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; + mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; mc->no_cdrom = true; mc->default_ram_id = "ddr"; } diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 2551dfc22d6f..57276e1506fe 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72") +#define XLNX_VERSAL_RCPU_TYPE ARM_CPU_TYPE_NAME("cortex-r5f") #define GEM_REVISION 0x40070106 #define VERSAL_NUM_PMC_APB_IRQS 3 @@ -34,10 +35,15 @@ static void versal_create_apu_cpus(Versal *s) { int i; + object_initialize_child(OBJECT(s), "apu-cluster", &s->fpd.apu.cluster, + TYPE_CPU_CLUSTER); + qdev_prop_set_uint32(DEVICE(&s->fpd.apu.cluster), "cluster-id", 0); + for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) { Object *obj; - object_initialize_child(OBJECT(s), "apu-cpu[*]", &s->fpd.apu.cpu[i], + object_initialize_child(OBJECT(&s->fpd.apu.cluster), + "apu-cpu[*]", &s->fpd.apu.cpu[i], XLNX_VERSAL_ACPU_TYPE); obj = OBJECT(&s->fpd.apu.cpu[i]); if (i) { @@ -52,6 +58,8 @@ static void versal_create_apu_cpus(Versal *s) &error_abort); qdev_realize(DEVICE(obj), NULL, &error_fatal); } + + qdev_realize(DEVICE(&s->fpd.apu.cluster), NULL, &error_fatal); } static void versal_create_apu_gic(Versal *s, qemu_irq *pic) @@ -123,6 +131,35 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic) } } +static void versal_create_rpu_cpus(Versal *s) +{ + int i; + + object_initialize_child(OBJECT(s), "rpu-cluster", &s->lpd.rpu.cluster, + TYPE_CPU_CLUSTER); + qdev_prop_set_uint32(DEVICE(&s->lpd.rpu.cluster), "cluster-id", 1); + + for (i = 0; i < ARRAY_SIZE(s->lpd.rpu.cpu); i++) { + Object *obj; + + object_initialize_child(OBJECT(&s->lpd.rpu.cluster), + "rpu-cpu[*]", &s->lpd.rpu.cpu[i], + XLNX_VERSAL_RCPU_TYPE); + obj = OBJECT(&s->lpd.rpu.cpu[i]); + object_property_set_bool(obj, "start-powered-off", true, + &error_abort); + + object_property_set_int(obj, "mp-affinity", 0x100 | i, &error_abort); + object_property_set_int(obj, "core-count", ARRAY_SIZE(s->lpd.rpu.cpu), + &error_abort); + object_property_set_link(obj, "memory", OBJECT(&s->lpd.rpu.mr), + &error_abort); + qdev_realize(DEVICE(obj), NULL, &error_fatal); + } + + qdev_realize(DEVICE(&s->lpd.rpu.cluster), NULL, &error_fatal); +} + static void versal_create_uarts(Versal *s, qemu_irq *pic) { int i; @@ -502,6 +539,57 @@ static void versal_create_ospi(Versal *s, qemu_irq *pic) qdev_connect_gpio_out(orgate, 0, pic[VERSAL_OSPI_IRQ]); } +static void versal_create_crl(Versal *s, qemu_irq *pic) +{ + SysBusDevice *sbd; + int i; + + object_initialize_child(OBJECT(s), "crl", &s->lpd.crl, + TYPE_XLNX_VERSAL_CRL); + sbd = SYS_BUS_DEVICE(&s->lpd.crl); + + for (i = 0; i < ARRAY_SIZE(s->lpd.rpu.cpu); i++) { + g_autofree gchar *name = g_strdup_printf("cpu_r5[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.rpu.cpu[i]), + &error_abort); + } + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) { + g_autofree gchar *name = g_strdup_printf("gem[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.iou.gem[i]), + &error_abort); + } + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) { + g_autofree gchar *name = g_strdup_printf("adma[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.iou.adma[i]), + &error_abort); + } + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.uart); i++) { + g_autofree gchar *name = g_strdup_printf("uart[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.iou.uart[i]), + &error_abort); + } + + object_property_set_link(OBJECT(&s->lpd.crl), + "usb", OBJECT(&s->lpd.iou.usb), + &error_abort); + + sysbus_realize(sbd, &error_fatal); + memory_region_add_subregion(&s->mr_ps, MM_CRL, + sysbus_mmio_get_region(sbd, 0)); + sysbus_connect_irq(sbd, 0, pic[VERSAL_CRL_IRQ]); +} + /* This takes the board allocated linear DDR memory and creates aliases * for each split DDR range/aperture on the Versal address map. */ @@ -585,8 +673,6 @@ static void versal_unimp(Versal *s) versal_unimp_area(s, "psm", &s->mr_ps, MM_PSM_START, MM_PSM_END - MM_PSM_START); - versal_unimp_area(s, "crl", &s->mr_ps, - MM_CRL, MM_CRL_SIZE); versal_unimp_area(s, "crf", &s->mr_ps, MM_FPD_CRF, MM_FPD_CRF_SIZE); versal_unimp_area(s, "apu", &s->mr_ps, @@ -631,6 +717,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_apu_cpus(s); versal_create_apu_gic(s, pic); + versal_create_rpu_cpus(s); versal_create_uarts(s, pic); versal_create_usbs(s, pic); versal_create_gems(s, pic); @@ -643,6 +730,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_efuse(s, pic); versal_create_pmc_iou_slcr(s, pic); versal_create_ospi(s, pic); + versal_create_crl(s, pic); versal_map_ddr(s); versal_unimp(s); @@ -652,6 +740,8 @@ static void versal_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->mr_ps, MM_OCM, &s->lpd.mr_ocm, 0); memory_region_add_subregion_overlap(&s->fpd.apu.mr, 0, &s->mr_ps, 0); + memory_region_add_subregion_overlap(&s->lpd.rpu.mr, 0, + &s->lpd.rpu.mr_ps_alias, 0); } static void versal_init(Object *obj) @@ -659,7 +749,10 @@ static void versal_init(Object *obj) Versal *s = XLNX_VERSAL(obj); memory_region_init(&s->fpd.apu.mr, obj, "mr-apu", UINT64_MAX); + memory_region_init(&s->lpd.rpu.mr, obj, "mr-rpu", UINT64_MAX); memory_region_init(&s->mr_ps, obj, "mr-ps-switch", UINT64_MAX); + memory_region_init_alias(&s->lpd.rpu.mr_ps_alias, OBJECT(s), + "mr-rpu-ps-alias", &s->mr_ps, 0, UINT64_MAX); } static Property versal_properties[] = { diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 5bfe285a191c..335cfc417d70 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -60,14 +60,17 @@ #define SERDES_SIZE 0x20000 #define DP_ADDR 0xfd4a0000 -#define DP_IRQ 113 +#define DP_IRQ 0x77 #define DPDMA_ADDR 0xfd4c0000 -#define DPDMA_IRQ 116 +#define DPDMA_IRQ 0x7a #define APU_ADDR 0xfd5c0000 #define APU_IRQ 153 +#define TTC0_ADDR 0xFF110000 +#define TTC0_IRQ 36 + #define IPI_ADDR 0xFF300000 #define IPI_IRQ 64 @@ -140,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; @@ -316,6 +327,24 @@ static void xlnx_zynqmp_create_crf(XlnxZynqMPState *s, qemu_irq *gic) sysbus_connect_irq(sbd, 0, gic[CRF_IRQ]); } +static void xlnx_zynqmp_create_ttc(XlnxZynqMPState *s, qemu_irq *gic) +{ + SysBusDevice *sbd; + int i, irq; + + for (i = 0; i < XLNX_ZYNQMP_NUM_TTC; i++) { + object_initialize_child(OBJECT(s), "ttc[*]", &s->ttc[i], + TYPE_CADENCE_TTC); + sbd = SYS_BUS_DEVICE(&s->ttc[i]); + + sysbus_realize(sbd, &error_fatal); + sysbus_mmio_map(sbd, 0, TTC0_ADDR + i * 0x10000); + for (irq = 0; irq < 3; irq++) { + sysbus_connect_irq(sbd, irq, gic[TTC0_IRQ + i * 3 + irq]); + } + } +} + static void xlnx_zynqmp_create_unimp_mmio(XlnxZynqMPState *s) { static const struct UnimpInfo { @@ -407,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) @@ -721,6 +754,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) xlnx_zynqmp_create_efuse(s, gic_spi); xlnx_zynqmp_create_apu_ctrl(s, gic_spi); xlnx_zynqmp_create_crf(s, gic_spi); + xlnx_zynqmp_create_ttc(s, gic_spi); xlnx_zynqmp_create_unimp_mmio(s); for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) { @@ -792,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/arm/z2.c b/hw/arm/z2.c index 9c1e876207b3..dc25304290aa 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "hw/arm/pxa.h" #include "hw/arm/boot.h" #include "hw/i2c/i2c.h" @@ -297,10 +298,10 @@ static const TypeInfo aer915_info = { .class_init = aer915_class_init, }; +#define FLASH_SECTOR_SIZE (64 * KiB) + static void z2_init(MachineState *machine) { - MemoryRegion *address_space_mem = get_system_memory(); - uint32_t sector_len = 0x10000; PXA2xxState *mpu; DriveInfo *dinfo; void *z2_lcd; @@ -308,15 +309,12 @@ static void z2_init(MachineState *machine) DeviceState *wm; /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, machine->cpu_type); + mpu = pxa270_init(z2_binfo.ram_size, machine->cpu_type); dinfo = drive_get(IF_PFLASH, 0, 0); - if (!pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 4, 0, 0, 0, 0, 0)) { - error_report("Error registering flash memory"); - exit(1); - } + pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0); /* setup keypad */ pxa27x_register_keypad(mpu->kp, map, 0x100); diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 3cb81310607f..364cdfa7333b 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "hw/audio/soundhw.h" #include "audio/audio.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/module.h" @@ -87,39 +87,39 @@ enum { #define GC_CR 2 /* rw */ #define GC_VALID_MASK ((1 << 6) - 1) -#define GS_MD3 (1<<17) /* rw */ -#define GS_AD3 (1<<16) /* rw */ -#define GS_RCS (1<<15) /* rwc */ -#define GS_B3S12 (1<<14) /* ro */ -#define GS_B2S12 (1<<13) /* ro */ -#define GS_B1S12 (1<<12) /* ro */ -#define GS_S1R1 (1<<11) /* rwc */ -#define GS_S0R1 (1<<10) /* rwc */ -#define GS_S1CR (1<<9) /* ro */ -#define GS_S0CR (1<<8) /* ro */ -#define GS_MINT (1<<7) /* ro */ -#define GS_POINT (1<<6) /* ro */ -#define GS_PIINT (1<<5) /* ro */ -#define GS_RSRVD ((1<<4)|(1<<3)) -#define GS_MOINT (1<<2) /* ro */ -#define GS_MIINT (1<<1) /* ro */ +#define GS_MD3 (1 << 17) /* rw */ +#define GS_AD3 (1 << 16) /* rw */ +#define GS_RCS (1 << 15) /* rwc */ +#define GS_B3S12 (1 << 14) /* ro */ +#define GS_B2S12 (1 << 13) /* ro */ +#define GS_B1S12 (1 << 12) /* ro */ +#define GS_S1R1 (1 << 11) /* rwc */ +#define GS_S0R1 (1 << 10) /* rwc */ +#define GS_S1CR (1 << 9) /* ro */ +#define GS_S0CR (1 << 8) /* ro */ +#define GS_MINT (1 << 7) /* ro */ +#define GS_POINT (1 << 6) /* ro */ +#define GS_PIINT (1 << 5) /* ro */ +#define GS_RSRVD ((1 << 4) | (1 << 3)) +#define GS_MOINT (1 << 2) /* ro */ +#define GS_MIINT (1 << 1) /* ro */ #define GS_GSCI 1 /* rwc */ -#define GS_RO_MASK (GS_B3S12| \ - GS_B2S12| \ - GS_B1S12| \ - GS_S1CR| \ - GS_S0CR| \ - GS_MINT| \ - GS_POINT| \ - GS_PIINT| \ - GS_RSRVD| \ - GS_MOINT| \ +#define GS_RO_MASK (GS_B3S12 | \ + GS_B2S12 | \ + GS_B1S12 | \ + GS_S1CR | \ + GS_S0CR | \ + GS_MINT | \ + GS_POINT | \ + GS_PIINT | \ + GS_RSRVD | \ + GS_MOINT | \ GS_MIINT) #define GS_VALID_MASK ((1 << 18) - 1) -#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI) +#define GS_WCLEAR_MASK (GS_RCS | GS_S1R1 | GS_S0R1 | GS_GSCI) -#define BD_IOC (1<<31) -#define BD_BUP (1<<30) +#define BD_IOC (1 << 31) +#define BD_BUP (1 << 30) #define EACS_VRA 1 #define EACS_VRM 8 @@ -183,7 +183,7 @@ enum { }; #ifdef DEBUG_AC97 -#define dolog(...) AUD_log ("ac97", __VA_ARGS__) +#define dolog(...) AUD_log("ac97", __VA_ARGS__) #else #define dolog(...) #endif @@ -206,9 +206,9 @@ enum { LAST_INDEX }; -MKREGS (PI, PI_INDEX * 16); -MKREGS (PO, PO_INDEX * 16); -MKREGS (MC, MC_INDEX * 16); +MKREGS(PI, PI_INDEX * 16); +MKREGS(PO, PO_INDEX * 16); +MKREGS(MC, MC_INDEX * 16); enum { GLOB_CNT = 0x2c, @@ -218,36 +218,25 @@ enum { #define GET_BM(index) (((index) >> 4) & 3) -static void po_callback (void *opaque, int free); -static void pi_callback (void *opaque, int avail); -static void mc_callback (void *opaque, int avail); +static void po_callback(void *opaque, int free); +static void pi_callback(void *opaque, int avail); +static void mc_callback(void *opaque, int avail); -static void warm_reset (AC97LinkState *s) -{ - (void) s; -} - -static void cold_reset (AC97LinkState * s) -{ - (void) s; -} - -static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) +static void fetch_bd(AC97LinkState *s, AC97BusMasterRegs *r) { uint8_t b[8]; - pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8); + pci_dma_read(&s->dev, r->bdbar + r->civ * 8, b, 8); r->bd_valid = 1; - r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3; - r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]); + r->bd.addr = le32_to_cpu(*(uint32_t *) &b[0]) & ~3; + r->bd.ctl_len = le32_to_cpu(*(uint32_t *) &b[4]); r->picb = r->bd.ctl_len & 0xffff; - dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", - r->civ, r->bd.addr, r->bd.ctl_len >> 16, - r->bd.ctl_len & 0xffff, - (r->bd.ctl_len & 0xffff) << 1); + dolog("bd %2d addr=0x%x ctl=0x%06x len=0x%x(%d bytes)\n", + r->civ, r->bd.addr, r->bd.ctl_len >> 16, + r->bd.ctl_len & 0xffff, (r->bd.ctl_len & 0xffff) << 1); } -static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) +static void update_sr(AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) { int event = 0; int level = 0; @@ -260,8 +249,7 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) if (!new_mask) { event = 1; level = 0; - } - else { + } else { if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) { event = 1; level = 1; @@ -275,69 +263,67 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) r->sr = new_sr; - dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n", - r->sr & SR_BCIS, r->sr & SR_LVBCI, - r->sr, - event, level); + dolog("IOC%d LVB%d sr=0x%x event=%d level=%d\n", + r->sr & SR_BCIS, r->sr & SR_LVBCI, r->sr, event, level); - if (!event) + if (!event) { return; + } if (level) { s->glob_sta |= masks[r - s->bm_regs]; - dolog ("set irq level=1\n"); + dolog("set irq level=1\n"); pci_irq_assert(&s->dev); - } - else { + } else { s->glob_sta &= ~masks[r - s->bm_regs]; - dolog ("set irq level=0\n"); + dolog("set irq level=0\n"); pci_irq_deassert(&s->dev); } } -static void voice_set_active (AC97LinkState *s, int bm_index, int on) +static void voice_set_active(AC97LinkState *s, int bm_index, int on) { switch (bm_index) { case PI_INDEX: - AUD_set_active_in (s->voice_pi, on); + AUD_set_active_in(s->voice_pi, on); break; case PO_INDEX: - AUD_set_active_out (s->voice_po, on); + AUD_set_active_out(s->voice_po, on); break; case MC_INDEX: - AUD_set_active_in (s->voice_mc, on); + AUD_set_active_in(s->voice_mc, on); break; default: - AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); + AUD_log("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); break; } } -static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) +static void reset_bm_regs(AC97LinkState *s, AC97BusMasterRegs *r) { - dolog ("reset_bm_regs\n"); + dolog("reset_bm_regs\n"); r->bdbar = 0; r->civ = 0; r->lvi = 0; /** todo do we need to do that? */ - update_sr (s, r, SR_DCH); + update_sr(s, r, SR_DCH); r->picb = 0; r->piv = 0; r->cr = r->cr & CR_DONT_CLEAR_MASK; r->bd_valid = 0; - voice_set_active (s, r - s->bm_regs, 0); - memset (s->silence, 0, sizeof (s->silence)); + voice_set_active(s, r - s->bm_regs, 0); + memset(s->silence, 0, sizeof(s->silence)); } -static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) +static void mixer_store(AC97LinkState *s, uint32_t i, uint16_t v) { - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); + if (i + 2 > sizeof(s->mixer_data)) { + dolog("mixer_store: index %d out of bounds %zd\n", + i, sizeof(s->mixer_data)); return; } @@ -345,22 +331,21 @@ static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) s->mixer_data[i + 1] = v >> 8; } -static uint16_t mixer_load (AC97LinkState *s, uint32_t i) +static uint16_t mixer_load(AC97LinkState *s, uint32_t i) { uint16_t val = 0xffff; - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_load: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); - } - else { + if (i + 2 > sizeof(s->mixer_data)) { + dolog("mixer_load: index %d out of bounds %zd\n", + i, sizeof(s->mixer_data)); + } else { val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8); } return val; } -static void open_voice (AC97LinkState *s, int index, int freq) +static void open_voice(AC97LinkState *s, int index, int freq) { struct audsettings as; @@ -373,7 +358,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) s->invalid_freq[index] = 0; switch (index) { case PI_INDEX: - s->voice_pi = AUD_open_in ( + s->voice_pi = AUD_open_in( &s->card, s->voice_pi, "ac97.pi", @@ -384,7 +369,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) break; case PO_INDEX: - s->voice_po = AUD_open_out ( + s->voice_po = AUD_open_out( &s->card, s->voice_po, "ac97.po", @@ -395,7 +380,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) break; case MC_INDEX: - s->voice_mc = AUD_open_in ( + s->voice_mc = AUD_open_in( &s->card, s->voice_mc, "ac97.mc", @@ -405,47 +390,46 @@ static void open_voice (AC97LinkState *s, int index, int freq) ); break; } - } - else { + } else { s->invalid_freq[index] = freq; switch (index) { case PI_INDEX: - AUD_close_in (&s->card, s->voice_pi); + AUD_close_in(&s->card, s->voice_pi); s->voice_pi = NULL; break; case PO_INDEX: - AUD_close_out (&s->card, s->voice_po); + AUD_close_out(&s->card, s->voice_po); s->voice_po = NULL; break; case MC_INDEX: - AUD_close_in (&s->card, s->voice_mc); + AUD_close_in(&s->card, s->voice_mc); s->voice_mc = NULL; break; } } } -static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) +static void reset_voices(AC97LinkState *s, uint8_t active[LAST_INDEX]) { uint16_t freq; - freq = mixer_load (s, AC97_PCM_LR_ADC_Rate); - open_voice (s, PI_INDEX, freq); - AUD_set_active_in (s->voice_pi, active[PI_INDEX]); + freq = mixer_load(s, AC97_PCM_LR_ADC_Rate); + open_voice(s, PI_INDEX, freq); + AUD_set_active_in(s->voice_pi, active[PI_INDEX]); - freq = mixer_load (s, AC97_PCM_Front_DAC_Rate); - open_voice (s, PO_INDEX, freq); - AUD_set_active_out (s->voice_po, active[PO_INDEX]); + freq = mixer_load(s, AC97_PCM_Front_DAC_Rate); + open_voice(s, PO_INDEX, freq); + AUD_set_active_out(s->voice_po, active[PO_INDEX]); - freq = mixer_load (s, AC97_MIC_ADC_Rate); - open_voice (s, MC_INDEX, freq); - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + freq = mixer_load(s, AC97_MIC_ADC_Rate); + open_voice(s, MC_INDEX, freq); + AUD_set_active_in(s->voice_mc, active[MC_INDEX]); } -static void get_volume (uint16_t vol, uint16_t mask, int inverse, - int *mute, uint8_t *lvol, uint8_t *rvol) +static void get_volume(uint16_t vol, uint16_t mask, int inverse, + int *mute, uint8_t *lvol, uint8_t *rvol) { *mute = (vol >> MUTE_SHIFT) & 1; *rvol = (255 * (vol & mask)) / mask; @@ -457,131 +441,130 @@ static void get_volume (uint16_t vol, uint16_t mask, int inverse, } } -static void update_combined_volume_out (AC97LinkState *s) +static void update_combined_volume_out(AC97LinkState *s) { uint8_t lvol, rvol, plvol, prvol; int mute, pmute; - get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, - &mute, &lvol, &rvol); - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, - &pmute, &plvol, &prvol); + get_volume(mixer_load(s, AC97_Master_Volume_Mute), 0x3f, 1, + &mute, &lvol, &rvol); + get_volume(mixer_load(s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, + &pmute, &plvol, &prvol); mute = mute | pmute; lvol = (lvol * plvol) / 255; rvol = (rvol * prvol) / 255; - AUD_set_volume_out (s->voice_po, mute, lvol, rvol); + AUD_set_volume_out(s->voice_po, mute, lvol, rvol); } -static void update_volume_in (AC97LinkState *s) +static void update_volume_in(AC97LinkState *s) { uint8_t lvol, rvol; int mute; - get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, - &mute, &lvol, &rvol); + get_volume(mixer_load(s, AC97_Record_Gain_Mute), 0x0f, 0, + &mute, &lvol, &rvol); - AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); + AUD_set_volume_in(s->voice_pi, mute, lvol, rvol); } -static void set_volume (AC97LinkState *s, int index, uint32_t val) +static void set_volume(AC97LinkState *s, int index, uint32_t val) { switch (index) { case AC97_Master_Volume_Mute: val &= 0xbf3f; - mixer_store (s, index, val); - update_combined_volume_out (s); + mixer_store(s, index, val); + update_combined_volume_out(s); break; case AC97_PCM_Out_Volume_Mute: val &= 0x9f1f; - mixer_store (s, index, val); - update_combined_volume_out (s); + mixer_store(s, index, val); + update_combined_volume_out(s); break; case AC97_Record_Gain_Mute: val &= 0x8f0f; - mixer_store (s, index, val); - update_volume_in (s); + mixer_store(s, index, val); + update_volume_in(s); break; } } -static void record_select (AC97LinkState *s, uint32_t val) +static void record_select(AC97LinkState *s, uint32_t val) { uint8_t rs = val & REC_MASK; uint8_t ls = (val >> 8) & REC_MASK; - mixer_store (s, AC97_Record_Select, rs | (ls << 8)); + mixer_store(s, AC97_Record_Select, rs | (ls << 8)); } -static void mixer_reset (AC97LinkState *s) +static void mixer_reset(AC97LinkState *s) { uint8_t active[LAST_INDEX]; - dolog ("mixer_reset\n"); - memset (s->mixer_data, 0, sizeof (s->mixer_data)); - memset (active, 0, sizeof (active)); - mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000); - mixer_store (s, AC97_Master_Tone_RL, 0x0000); - mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - mixer_store (s, AC97_Phone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Mic_Volume_Mute , 0x0000); - mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000); - mixer_store (s, AC97_CD_Volume_Mute , 0x0000); - mixer_store (s, AC97_Video_Volume_Mute , 0x0000); - mixer_store (s, AC97_Aux_Volume_Mute , 0x0000); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000); - mixer_store (s, AC97_General_Purpose , 0x0000); - mixer_store (s, AC97_3D_Control , 0x0000); - mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); + dolog("mixer_reset\n"); + memset(s->mixer_data, 0, sizeof(s->mixer_data)); + memset(active, 0, sizeof(active)); + mixer_store(s, AC97_Reset, 0x0000); /* 6940 */ + mixer_store(s, AC97_Headphone_Volume_Mute, 0x0000); + mixer_store(s, AC97_Master_Volume_Mono_Mute, 0x0000); + mixer_store(s, AC97_Master_Tone_RL, 0x0000); + mixer_store(s, AC97_PC_BEEP_Volume_Mute, 0x0000); + mixer_store(s, AC97_Phone_Volume_Mute, 0x0000); + mixer_store(s, AC97_Mic_Volume_Mute, 0x0000); + mixer_store(s, AC97_Line_In_Volume_Mute, 0x0000); + mixer_store(s, AC97_CD_Volume_Mute, 0x0000); + mixer_store(s, AC97_Video_Volume_Mute, 0x0000); + mixer_store(s, AC97_Aux_Volume_Mute, 0x0000); + mixer_store(s, AC97_Record_Gain_Mic_Mute, 0x0000); + mixer_store(s, AC97_General_Purpose, 0x0000); + mixer_store(s, AC97_3D_Control, 0x0000); + mixer_store(s, AC97_Powerdown_Ctrl_Stat, 0x000f); /* * Sigmatel 9700 (STAC9700) */ - mixer_store (s, AC97_Vendor_ID1 , 0x8384); - mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */ - - mixer_store (s, AC97_Extended_Audio_ID , 0x0809); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); - mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); - - record_select (s, 0); - set_volume (s, AC97_Master_Volume_Mute, 0x8000); - set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); - set_volume (s, AC97_Record_Gain_Mute, 0x8808); - - reset_voices (s, active); + mixer_store(s, AC97_Vendor_ID1, 0x8384); + mixer_store(s, AC97_Vendor_ID2, 0x7600); /* 7608 */ + + mixer_store(s, AC97_Extended_Audio_ID, 0x0809); + mixer_store(s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); + mixer_store(s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_Surround_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LFE_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LR_ADC_Rate, 0xbb80); + mixer_store(s, AC97_MIC_ADC_Rate, 0xbb80); + + record_select(s, 0); + set_volume(s, AC97_Master_Volume_Mute, 0x8000); + set_volume(s, AC97_PCM_Out_Volume_Mute, 0x8808); + set_volume(s, AC97_Record_Gain_Mute, 0x8808); + + reset_voices(s, active); } /** * Native audio mixer * I/O Reads */ -static uint32_t nam_readb (void *opaque, uint32_t addr) +static uint32_t nam_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - dolog ("U nam readb %#x\n", addr); + dolog("U nam readb 0x%x\n", addr); s->cas = 0; return ~0U; } -static uint32_t nam_readw (void *opaque, uint32_t addr) +static uint32_t nam_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - uint32_t index = addr; s->cas = 0; - return mixer_load(s, index); + return mixer_load(s, addr); } -static uint32_t nam_readl (void *opaque, uint32_t addr) +static uint32_t nam_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - dolog ("U nam readl %#x\n", addr); + dolog("U nam readl 0x%x\n", addr); s->cas = 0; return ~0U; } @@ -590,89 +573,84 @@ static uint32_t nam_readl (void *opaque, uint32_t addr) * Native audio mixer * I/O Writes */ -static void nam_writeb (void *opaque, uint32_t addr, uint32_t val) +static void nam_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - dolog ("U nam writeb %#x <- %#x\n", addr, val); + dolog("U nam writeb 0x%x <- 0x%x\n", addr, val); s->cas = 0; } -static void nam_writew (void *opaque, uint32_t addr, uint32_t val) +static void nam_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - uint32_t index = addr; + s->cas = 0; - switch (index) { + switch (addr) { case AC97_Reset: - mixer_reset (s); + mixer_reset(s); break; case AC97_Powerdown_Ctrl_Stat: val &= ~0x800f; - val |= mixer_load (s, index) & 0xf; - mixer_store (s, index, val); + val |= mixer_load(s, addr) & 0xf; + mixer_store(s, addr, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - set_volume (s, index, val); + set_volume(s, addr, val); break; case AC97_Record_Select: - record_select (s, val); + record_select(s, val); break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: - dolog ("Attempt to write vendor ID to %#x\n", val); + dolog("Attempt to write vendor ID to 0x%x\n", val); break; case AC97_Extended_Audio_ID: - dolog ("Attempt to write extended audio ID to %#x\n", val); + dolog("Attempt to write extended audio ID to 0x%x\n", val); break; case AC97_Extended_Audio_Ctrl_Stat: if (!(val & EACS_VRA)) { - mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); - open_voice (s, PI_INDEX, 48000); - open_voice (s, PO_INDEX, 48000); + mixer_store(s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LR_ADC_Rate, 0xbb80); + open_voice(s, PI_INDEX, 48000); + open_voice(s, PO_INDEX, 48000); } if (!(val & EACS_VRM)) { - mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); - open_voice (s, MC_INDEX, 48000); + mixer_store(s, AC97_MIC_ADC_Rate, 0xbb80); + open_voice(s, MC_INDEX, 48000); } - dolog ("Setting extended audio control to %#x\n", val); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val); + dolog("Setting extended audio control to 0x%x\n", val); + mixer_store(s, AC97_Extended_Audio_Ctrl_Stat, val); break; case AC97_PCM_Front_DAC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front DAC rate to %d\n", val); - open_voice (s, PO_INDEX, val); - } - else { - dolog ("Attempt to set front DAC rate to %d, " - "but VRA is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store(s, addr, val); + dolog("Set front DAC rate to %d\n", val); + open_voice(s, PO_INDEX, val); + } else { + dolog("Attempt to set front DAC rate to %d, but VRA is not set\n", + val); } break; case AC97_MIC_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store (s, index, val); - dolog ("Set MIC ADC rate to %d\n", val); - open_voice (s, MC_INDEX, val); - } - else { - dolog ("Attempt to set MIC ADC rate to %d, " - "but VRM is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { + mixer_store(s, addr, val); + dolog("Set MIC ADC rate to %d\n", val); + open_voice(s, MC_INDEX, val); + } else { + dolog("Attempt to set MIC ADC rate to %d, but VRM is not set\n", + val); } break; case AC97_PCM_LR_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front LR ADC rate to %d\n", val); - open_voice (s, PI_INDEX, val); - } - else { - dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store(s, addr, val); + dolog("Set front LR ADC rate to %d\n", val); + open_voice(s, PI_INDEX, val); + } else { + dolog("Attempt to set LR ADC rate to %d, but VRA is not set\n", + val); } break; case AC97_Headphone_Volume_Mute: @@ -693,16 +671,16 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) /* None of the features in these regs are emulated, so they are RO */ break; default: - dolog ("U nam writew %#x <- %#x\n", addr, val); - mixer_store (s, index, val); + dolog("U nam writew 0x%x <- 0x%x\n", addr, val); + mixer_store(s, addr, val); break; } } -static void nam_writel (void *opaque, uint32_t addr, uint32_t val) +static void nam_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - dolog ("U nam writel %#x <- %#x\n", addr, val); + dolog("U nam writel 0x%x <- 0x%x\n", addr, val); s->cas = 0; } @@ -710,131 +688,128 @@ static void nam_writel (void *opaque, uint32_t addr, uint32_t val) * Native audio bus master * I/O Reads */ -static uint32_t nabm_readb (void *opaque, uint32_t addr) +static uint32_t nabm_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case CAS: - dolog ("CAS %d\n", s->cas); + dolog("CAS %d\n", s->cas); val = s->cas; s->cas = 1; break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->civ; - dolog ("CIV[%d] -> %#x\n", GET_BM (index), val); + dolog("CIV[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->lvi; - dolog ("LVI[%d] -> %#x\n", GET_BM (index), val); + dolog("LVI[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_PIV: case PO_PIV: case MC_PIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->piv; - dolog ("PIV[%d] -> %#x\n", GET_BM (index), val); + dolog("PIV[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->cr; - dolog ("CR[%d] -> %#x\n", GET_BM (index), val); + dolog("CR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->sr & 0xff; - dolog ("SRb[%d] -> %#x\n", GET_BM (index), val); + dolog("SRb[%d] -> 0x%x\n", GET_BM(addr), val); break; default: - dolog ("U nabm readb %#x -> %#x\n", addr, val); + dolog("U nabm readb 0x%x -> 0x%x\n", addr, val); break; } return val; } -static uint32_t nabm_readw (void *opaque, uint32_t addr) +static uint32_t nabm_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->sr; - dolog ("SR[%d] -> %#x\n", GET_BM (index), val); + dolog("SR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->picb; - dolog ("PICB[%d] -> %#x\n", GET_BM (index), val); + dolog("PICB[%d] -> 0x%x\n", GET_BM(addr), val); break; default: - dolog ("U nabm readw %#x -> %#x\n", addr, val); + dolog("U nabm readw 0x%x -> 0x%x\n", addr, val); break; } return val; } -static uint32_t nabm_readl (void *opaque, uint32_t addr) +static uint32_t nabm_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->bdbar; - dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val); + dolog("BMADDR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->civ | (r->lvi << 8) | (r->sr << 16); - dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index), + dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(addr), r->civ, r->lvi, r->sr); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->picb | (r->piv << 16) | (r->cr << 24); - dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index), + dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(addr), val, r->picb, r->piv, r->cr); break; case GLOB_CNT: val = s->glob_cnt; - dolog ("glob_cnt -> %#x\n", val); + dolog("glob_cnt -> 0x%x\n", val); break; case GLOB_STA: val = s->glob_sta | GS_S0CR; - dolog ("glob_sta -> %#x\n", val); + dolog("glob_sta -> 0x%x\n", val); break; default: - dolog ("U nabm readl %#x -> %#x\n", addr, val); + dolog("U nabm readl 0x%x -> 0x%x\n", addr, val); break; } return val; @@ -844,125 +819,120 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr) * Native audio bus master * I/O Writes */ -static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { r->sr &= ~(SR_DCH | SR_CELV); r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); } r->lvi = val % 32; - dolog ("LVI[%d] <- %#x\n", GET_BM (index), val); + dolog("LVI[%d] <- 0x%x\n", GET_BM(addr), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; if (val & CR_RR) { - reset_bm_regs (s, r); - } - else { + reset_bm_regs(s, r); + } else { r->cr = val & CR_VALID_MASK; if (!(r->cr & CR_RPBM)) { - voice_set_active (s, r - s->bm_regs, 0); + voice_set_active(s, r - s->bm_regs, 0); r->sr |= SR_DCH; - } - else { + } else { r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); r->sr &= ~SR_DCH; - voice_set_active (s, r - s->bm_regs, 1); + voice_set_active(s, r - s->bm_regs, 1); } } - dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr); + dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(addr), val, r->cr); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(addr), val, r->sr); break; default: - dolog ("U nabm writeb %#x <- %#x\n", addr, val); + dolog("U nabm writeb 0x%x <- 0x%x\n", addr, val); break; } } -static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(addr), val, r->sr); break; default: - dolog ("U nabm writew %#x <- %#x\n", addr, val); + dolog("U nabm writew 0x%x <- 0x%x\n", addr, val); break; } } -static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(addr)]; r->bdbar = val & ~3; - dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n", - GET_BM (index), val, r->bdbar); + dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(addr), val, r->bdbar); break; case GLOB_CNT: - if (val & GC_WR) - warm_reset (s); - if (val & GC_CR) - cold_reset (s); - if (!(val & (GC_WR | GC_CR))) + /* TODO: Handle WR or CR being set (warm/cold reset requests) */ + if (!(val & (GC_WR | GC_CR))) { s->glob_cnt = val & GC_VALID_MASK; - dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt); + } + dolog("glob_cnt <- 0x%x (glob_cnt 0x%x)\n", val, s->glob_cnt); break; case GLOB_STA: s->glob_sta &= ~(val & GS_WCLEAR_MASK); s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; - dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta); + dolog("glob_sta <- 0x%x (glob_sta 0x%x)\n", val, s->glob_sta); break; default: - dolog ("U nabm writel %#x <- %#x\n", addr, val); + dolog("U nabm writel 0x%x <- 0x%x\n", addr, val); break; } } -static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int write_audio(AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) { uint8_t tmpbuf[4096]; uint32_t addr = r->bd.addr; uint32_t temp = r->picb << 1; uint32_t written = 0; int to_copy = 0; - temp = MIN (temp, max); + temp = MIN(temp, max); if (!temp) { *stop = 1; @@ -971,11 +941,11 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int copied; - to_copy = MIN (temp, sizeof (tmpbuf)); - pci_dma_read (&s->dev, addr, tmpbuf, to_copy); - copied = AUD_write (s->voice_po, tmpbuf, to_copy); - dolog ("write_audio max=%x to_copy=%x copied=%x\n", - max, to_copy, copied); + to_copy = MIN(temp, sizeof(tmpbuf)); + pci_dma_read(&s->dev, addr, tmpbuf, to_copy); + copied = AUD_write(s->voice_po, tmpbuf, to_copy); + dolog("write_audio max=%x to_copy=%x copied=%x\n", + max, to_copy, copied); if (!copied) { *stop = 1; break; @@ -987,11 +957,10 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, if (!temp) { if (to_copy < 4) { - dolog ("whoops\n"); + dolog("whoops\n"); s->last_samp = 0; - } - else { - s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4]; + } else { + s->last_samp = *(uint32_t *)&tmpbuf[to_copy - 4]; } } @@ -999,37 +968,37 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, return written; } -static void write_bup (AC97LinkState *s, int elapsed) +static void write_bup(AC97LinkState *s, int elapsed) { - dolog ("write_bup\n"); + dolog("write_bup\n"); if (!(s->bup_flag & BUP_SET)) { if (s->bup_flag & BUP_LAST) { int i; uint8_t *p = s->silence; - for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) { + for (i = 0; i < sizeof(s->silence) / 4; i++, p += 4) { *(uint32_t *) p = s->last_samp; } - } - else { - memset (s->silence, 0, sizeof (s->silence)); + } else { + memset(s->silence, 0, sizeof(s->silence)); } s->bup_flag |= BUP_SET; } while (elapsed) { - int temp = MIN (elapsed, sizeof (s->silence)); + int temp = MIN(elapsed, sizeof(s->silence)); while (temp) { - int copied = AUD_write (s->voice_po, s->silence, temp); - if (!copied) + int copied = AUD_write(s->voice_po, s->silence, temp); + if (!copied) { return; + } temp -= copied; elapsed -= copied; } } } -static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int read_audio(AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) { uint8_t tmpbuf[4096]; uint32_t addr = r->bd.addr; @@ -1038,7 +1007,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, int to_copy = 0; SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi; - temp = MIN (temp, max); + temp = MIN(temp, max); if (!temp) { *stop = 1; @@ -1047,13 +1016,13 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int acquired; - to_copy = MIN (temp, sizeof (tmpbuf)); - acquired = AUD_read (voice, tmpbuf, to_copy); + to_copy = MIN(temp, sizeof(tmpbuf)); + acquired = AUD_read(voice, tmpbuf, to_copy); if (!acquired) { *stop = 1; break; } - pci_dma_write (&s->dev, addr, tmpbuf, acquired); + pci_dma_write(&s->dev, addr, tmpbuf, acquired); temp -= acquired; addr += acquired; nread += acquired; @@ -1063,14 +1032,14 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, return nread; } -static void transfer_audio (AC97LinkState *s, int index, int elapsed) +static void transfer_audio(AC97LinkState *s, int index, int elapsed) { AC97BusMasterRegs *r = &s->bm_regs[index]; int stop = 0; if (s->invalid_freq[index]) { - AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n", - index, s->invalid_freq[index]); + AUD_log("ac97", "attempt to use voice %d with invalid frequency %d\n", + index, s->invalid_freq[index]); return; } @@ -1078,7 +1047,7 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) if (r->cr & CR_RPBM) { switch (index) { case PO_INDEX: - write_bup (s, elapsed); + write_bup(s, elapsed); break; } } @@ -1089,13 +1058,13 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) int temp; if (!r->bd_valid) { - dolog ("invalid bd\n"); - fetch_bd (s, r); + dolog("invalid bd\n"); + fetch_bd(s, r); } if (!r->picb) { - dolog ("fresh bd %d is empty %#x %#x\n", - r->civ, r->bd.addr, r->bd.ctl_len); + dolog("fresh bd %d is empty 0x%x 0x%x\n", + r->civ, r->bd.addr, r->bd.ctl_len); if (r->civ == r->lvi) { r->sr |= SR_DCH; /* CELV? */ s->bup_flag = 0; @@ -1104,20 +1073,20 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) r->sr &= ~SR_CELV; r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); return; } switch (index) { case PO_INDEX: - temp = write_audio (s, r, elapsed, &stop); + temp = write_audio(s, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; case PI_INDEX: case MC_INDEX: - temp = read_audio (s, r, elapsed, &stop); + temp = read_audio(s, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; @@ -1131,36 +1100,35 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) } if (r->civ == r->lvi) { - dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); + dolog("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); new_sr |= SR_LVBCI | SR_DCH | SR_CELV; stop = 1; s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; - } - else { + } else { r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); } - update_sr (s, r, new_sr); + update_sr(s, r, new_sr); } } } -static void pi_callback (void *opaque, int avail) +static void pi_callback(void *opaque, int avail) { - transfer_audio (opaque, PI_INDEX, avail); + transfer_audio(opaque, PI_INDEX, avail); } -static void mc_callback (void *opaque, int avail) +static void mc_callback(void *opaque, int avail) { - transfer_audio (opaque, MC_INDEX, avail); + transfer_audio(opaque, MC_INDEX, avail); } -static void po_callback (void *opaque, int free) +static void po_callback(void *opaque, int free) { - transfer_audio (opaque, PO_INDEX, free); + transfer_audio(opaque, PO_INDEX, free); } static const VMStateDescription vmstate_ac97_bm_regs = { @@ -1168,44 +1136,44 @@ static const VMStateDescription vmstate_ac97_bm_regs = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32 (bdbar, AC97BusMasterRegs), - VMSTATE_UINT8 (civ, AC97BusMasterRegs), - VMSTATE_UINT8 (lvi, AC97BusMasterRegs), - VMSTATE_UINT16 (sr, AC97BusMasterRegs), - VMSTATE_UINT16 (picb, AC97BusMasterRegs), - VMSTATE_UINT8 (piv, AC97BusMasterRegs), - VMSTATE_UINT8 (cr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs), - VMSTATE_END_OF_LIST () + VMSTATE_UINT32(bdbar, AC97BusMasterRegs), + VMSTATE_UINT8(civ, AC97BusMasterRegs), + VMSTATE_UINT8(lvi, AC97BusMasterRegs), + VMSTATE_UINT16(sr, AC97BusMasterRegs), + VMSTATE_UINT16(picb, AC97BusMasterRegs), + VMSTATE_UINT8(piv, AC97BusMasterRegs), + VMSTATE_UINT8(cr, AC97BusMasterRegs), + VMSTATE_UINT32(bd_valid, AC97BusMasterRegs), + VMSTATE_UINT32(bd.addr, AC97BusMasterRegs), + VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs), + VMSTATE_END_OF_LIST() } }; -static int ac97_post_load (void *opaque, int version_id) +static int ac97_post_load(void *opaque, int version_id) { uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; - record_select (s, mixer_load (s, AC97_Record_Select)); - set_volume (s, AC97_Master_Volume_Mute, - mixer_load (s, AC97_Master_Volume_Mute)); - set_volume (s, AC97_PCM_Out_Volume_Mute, - mixer_load (s, AC97_PCM_Out_Volume_Mute)); - set_volume (s, AC97_Record_Gain_Mute, - mixer_load (s, AC97_Record_Gain_Mute)); + record_select(s, mixer_load(s, AC97_Record_Select)); + set_volume(s, AC97_Master_Volume_Mute, + mixer_load(s, AC97_Master_Volume_Mute)); + set_volume(s, AC97_PCM_Out_Volume_Mute, + mixer_load(s, AC97_PCM_Out_Volume_Mute)); + set_volume(s, AC97_Record_Gain_Mute, + mixer_load(s, AC97_Record_Gain_Mute)); active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); - reset_voices (s, active); + reset_voices(s, active); s->bup_flag = 0; s->last_samp = 0; return 0; } -static bool is_version_2 (void *opaque, int version_id) +static bool is_version_2(void *opaque, int version_id) { return version_id == 2; } @@ -1216,15 +1184,15 @@ static const VMStateDescription vmstate_ac97 = { .minimum_version_id = 2, .post_load = ac97_post_load, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE (dev, AC97LinkState), - VMSTATE_UINT32 (glob_cnt, AC97LinkState), - VMSTATE_UINT32 (glob_sta, AC97LinkState), - VMSTATE_UINT32 (cas, AC97LinkState), - VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1, - vmstate_ac97_bm_regs, AC97BusMasterRegs), - VMSTATE_BUFFER (mixer_data, AC97LinkState), - VMSTATE_UNUSED_TEST (is_version_2, 3), - VMSTATE_END_OF_LIST () + VMSTATE_PCI_DEVICE(dev, AC97LinkState), + VMSTATE_UINT32(glob_cnt, AC97LinkState), + VMSTATE_UINT32(glob_sta, AC97LinkState), + VMSTATE_UINT32(cas, AC97LinkState), + VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1, + vmstate_ac97_bm_regs, AC97BusMasterRegs), + VMSTATE_BUFFER(mixer_data, AC97LinkState), + VMSTATE_UNUSED_TEST(is_version_2, 3), + VMSTATE_END_OF_LIST() } }; @@ -1295,7 +1263,7 @@ static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size) } static void nabm_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) + unsigned size) { if ((addr / size) > 64) { return; @@ -1325,20 +1293,20 @@ static const MemoryRegionOps ac97_io_nabm_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void ac97_on_reset (DeviceState *dev) +static void ac97_on_reset(DeviceState *dev) { AC97LinkState *s = container_of(dev, AC97LinkState, dev.qdev); - reset_bm_regs (s, &s->bm_regs[0]); - reset_bm_regs (s, &s->bm_regs[1]); - reset_bm_regs (s, &s->bm_regs[2]); + reset_bm_regs(s, &s->bm_regs[0]); + reset_bm_regs(s, &s->bm_regs[1]); + reset_bm_regs(s, &s->bm_regs[2]); /* * Reset the mixer too. The Windows XP driver seems to rely on * this. At least it wants to read the vendor id before it resets * the codec manually. */ - mixer_reset (s); + mixer_reset(s); } static void ac97_realize(PCIDevice *dev, Error **errp) @@ -1373,13 +1341,13 @@ static void ac97_realize(PCIDevice *dev, Error **errp) c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */ c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */ - memory_region_init_io (&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, - "ac97-nam", 1024); - memory_region_init_io (&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, - "ac97-nabm", 256); - pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); - pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); - AUD_register_card ("ac97", &s->card); + memory_region_init_io(&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, + "ac97-nam", 1024); + memory_region_init_io(&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, + "ac97-nabm", 256); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); + AUD_register_card("ac97", &s->card); ac97_on_reset(DEVICE(s)); } @@ -1395,13 +1363,13 @@ static void ac97_exit(PCIDevice *dev) static Property ac97_properties[] = { DEFINE_AUDIO_PROPERTIES(AC97LinkState, card), - DEFINE_PROP_END_OF_LIST (), + DEFINE_PROP_END_OF_LIST(), }; -static void ac97_class_init (ObjectClass *klass, void *data) +static void ac97_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS (klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = ac97_realize; k->exit = ac97_exit; @@ -1419,7 +1387,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) static const TypeInfo ac97_info = { .name = TYPE_AC97, .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (AC97LinkState), + .instance_size = sizeof(AC97LinkState), .class_init = ac97_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, @@ -1427,11 +1395,11 @@ static const TypeInfo ac97_info = { }, }; -static void ac97_register_types (void) +static void ac97_register_types(void) { - type_register_static (&ac97_info); + type_register_static(&ac97_info); deprecated_register_soundhw("ac97", "Intel 82801AA AC97 Audio", 0, TYPE_AC97); } -type_init (ac97_register_types) +type_init(ac97_register_types) diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 0723e3943044..7f17a72a9cb7 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -84,7 +84,7 @@ struct CSState { int transferred; int aci_counter; SWVoiceOut *voice; - int16_t *tab; + const int16_t *tab; }; #define MODE2 (1 << 6) @@ -142,13 +142,13 @@ enum { Capture_Lower_Base_Count }; -static int freqs[2][8] = { +static const int freqs[2][8] = { { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 }, { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 } }; /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */ -static int16_t MuLawDecompressTable[256] = +static const int16_t MuLawDecompressTable[256] = { -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, @@ -184,7 +184,7 @@ static int16_t MuLawDecompressTable[256] = 56, 48, 40, 32, 24, 16, 8, 0 }; -static int16_t ALawDecompressTable[256] = +static const int16_t ALawDecompressTable[256] = { -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 690458981471..54cc19a63765 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -29,7 +29,7 @@ #include "qemu/osdep.h" #include "hw/audio/soundhw.h" #include "audio/audio.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "migration/vmstate.h" #include "qemu/module.h" #include "sysemu/dma.h" diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index bc77e3d8c9dc..b9ed231fe849 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -220,8 +220,6 @@ struct IntelHDAReg { void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg); }; -static void intel_hda_reset(DeviceState *dev); - /* --------------------------------------------------------------------- */ static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase) @@ -516,7 +514,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) { if ((d->g_ctl & ICH6_GCTL_RESET) == 0) { - intel_hda_reset(DEVICE(d)); + device_cold_reset(DEVICE(d)); } } @@ -1083,11 +1081,9 @@ static void intel_hda_reset(DeviceState *dev) intel_hda_regs_reset(d); d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - /* reset codecs */ QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { DeviceState *qdev = kid->child; cdev = HDA_CODEC_DEVICE(qdev); - device_legacy_reset(DEVICE(cdev)); d->state_sts |= (1 << cdev->cad); } intel_hda_update_irq(d); @@ -1311,17 +1307,16 @@ static const TypeInfo hda_codec_device_type_info = { * create intel hda controller with codec attached to it, * so '-soundhw hda' works. */ -static int intel_hda_and_codec_init(PCIBus *bus) +static int intel_hda_and_codec_init(PCIBus *bus, const char *audiodev) { DeviceState *controller; BusState *hdabus; DeviceState *codec; - warn_report("'-soundhw hda' is deprecated, " - "please use '-device intel-hda -device hda-duplex' instead"); controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); hdabus = QLIST_FIRST(&controller->child_bus); codec = qdev_new("hda-duplex"); + qdev_prop_set_string(codec, "audiodev", audiodev); qdev_realize_and_unref(codec, hdabus, &error_fatal); return 0; } diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index dfc7ebca4e17..daf92a4ce117 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -245,18 +245,8 @@ static const TypeInfo pcspk_info = { .class_init = pcspk_class_initfn, }; -static int pcspk_audio_init_soundhw(ISABus *bus) -{ - PCSpkState *s = pcspk_state; - - warn_report("'-soundhw pcspk' is deprecated, " - "please set a backend using '-machine pcspk-audiodev=' instead"); - return pcspk_audio_init(s); -} - static void pcspk_register(void) { type_register_static(&pcspk_info); - isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init_soundhw); } type_init(pcspk_register) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index 173b674ff53a..94d9463e42d8 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -25,7 +25,9 @@ #include "qemu/option.h" #include "qemu/help_option.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "qom/object.h" +#include "hw/qdev-properties.h" #include "hw/isa/isa.h" #include "hw/pci/pci.h" #include "hw/audio/soundhw.h" @@ -34,36 +36,21 @@ struct soundhw { const char *name; const char *descr; const char *typename; - int enabled; int isa; - union { - int (*init_isa) (ISABus *bus); - int (*init_pci) (PCIBus *bus); - } init; + int (*init_pci) (PCIBus *bus, const char *audiodev); }; static struct soundhw soundhw[9]; static int soundhw_count; -void isa_register_soundhw(const char *name, const char *descr, - int (*init_isa)(ISABus *bus)) -{ - assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); - soundhw[soundhw_count].name = name; - soundhw[soundhw_count].descr = descr; - soundhw[soundhw_count].isa = 1; - soundhw[soundhw_count].init.init_isa = init_isa; - soundhw_count++; -} - void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)) + int (*init_pci)(PCIBus *bus, const char *audiodev)) { assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); soundhw[soundhw_count].name = name; soundhw[soundhw_count].descr = descr; soundhw[soundhw_count].isa = 0; - soundhw[soundhw_count].init.init_pci = init_pci; + soundhw[soundhw_count].init_pci = init_pci; soundhw_count++; } @@ -78,100 +65,78 @@ void deprecated_register_soundhw(const char *name, const char *descr, soundhw_count++; } -void select_soundhw(const char *optarg) +void show_valid_soundhw(void) { struct soundhw *c; - if (is_help_option(optarg)) { - show_valid_cards: - - if (soundhw_count) { - printf("Valid sound card names (comma separated):\n"); - for (c = soundhw; c->name; ++c) { - printf ("%-11s %s\n", c->name, c->descr); - } - printf("\n-soundhw all will enable all of the above\n"); - } else { - printf("Machine has no user-selectable audio hardware " - "(it may or may not have always-present audio hardware).\n"); - } - exit(!is_help_option(optarg)); + if (soundhw_count) { + printf("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + } else { + printf("Machine has no user-selectable audio hardware " + "(it may or may not have always-present audio hardware).\n"); } - else { - size_t l; - const char *p; - char *e; - int bad_card = 0; +} - if (!strcmp(optarg, "all")) { - for (c = soundhw; c->name; ++c) { - c->enabled = 1; - } - return; - } +static struct soundhw *selected = NULL; +static const char *audiodev_id; - p = optarg; - while (*p) { - e = strchr(p, ','); - l = !e ? strlen(p) : (size_t) (e - p); +void select_soundhw(const char *optarg, const char *audiodev) +{ + struct soundhw *c; - for (c = soundhw; c->name; ++c) { - if (!strncmp(c->name, p, l) && !c->name[l]) { - c->enabled = 1; - break; - } - } + if (selected) { + error_setg(&error_fatal, "only one -soundhw option is allowed"); + } - if (!c->name) { - if (l > 80) { - error_report("Unknown sound card name (too big to show)"); - } - else { - error_report("Unknown sound card name `%.*s'", - (int) l, p); - } - bad_card = 1; - } - p += l + (e != NULL); + for (c = soundhw; c->name; ++c) { + if (g_str_equal(c->name, optarg)) { + selected = c; + audiodev_id = audiodev; + break; } + } - if (bad_card) { - goto show_valid_cards; - } + if (!c->name) { + error_report("Unknown sound card name `%s'", optarg); + show_valid_soundhw(); + exit(1); } } void soundhw_init(void) { - struct soundhw *c; + struct soundhw *c = selected; ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL); PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); + BusState *bus; - for (c = soundhw; c->name; ++c) { - if (c->enabled) { - if (c->typename) { - warn_report("'-soundhw %s' is deprecated, " - "please use '-device %s' instead", - c->name, c->typename); - if (c->isa) { - isa_create_simple(isa_bus, c->typename); - } else { - pci_create_simple(pci_bus, -1, c->typename); - } - } else if (c->isa) { - if (!isa_bus) { - error_report("ISA bus not available for %s", c->name); - exit(1); - } - c->init.init_isa(isa_bus); - } else { - if (!pci_bus) { - error_report("PCI bus not available for %s", c->name); - exit(1); - } - c->init.init_pci(pci_bus); - } + if (!c) { + return; + } + if (c->isa) { + if (!isa_bus) { + error_report("ISA bus not available for %s", c->name); + exit(1); + } + bus = BUS(isa_bus); + } else { + if (!pci_bus) { + error_report("PCI bus not available for %s", c->name); + exit(1); } + bus = BUS(pci_bus); + } + + if (c->typename) { + DeviceState *dev = qdev_new(c->typename); + qdev_prop_set_string(dev, "audiodev", audiodev_id); + qdev_realize_and_unref(dev, bus, &error_fatal); + } else { + assert(!c->isa); + c->init_pci(pci_bus, audiodev_id); } } diff --git a/hw/audio/via-ac97.c b/hw/audio/via-ac97.c index 6d556f74fc9d..d1a856f63dea 100644 --- a/hw/audio/via-ac97.c +++ b/hw/audio/via-ac97.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "hw/isa/vt82c686.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" static void via_ac97_realize(PCIDevice *pci_dev, Error **errp) { diff --git a/hw/avr/boot.c b/hw/avr/boot.c index cbede775cee2..617f3a144c85 100644 --- a/hw/avr/boot.c +++ b/hw/avr/boot.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "hw/loader.h" #include "elf.h" diff --git a/hw/block/block.c b/hw/block/block.c index 25f45df7232d..f9c4fe67673b 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -53,7 +53,7 @@ bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size, * block device and read only on demand. */ assert(size <= BDRV_REQUEST_MAX_BYTES); - ret = blk_pread(blk, 0, buf, size); + ret = blk_pread(blk, 0, size, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "can't read block backend"); return false; @@ -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 49276e46f269..26f965cabcfa 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/fdc-isa.c b/hw/block/fdc-isa.c index fa2045074732..fee1ca68a8a4 100644 --- a/hw/block/fdc-isa.c +++ b/hw/block/fdc-isa.c @@ -32,7 +32,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" @@ -214,9 +214,9 @@ int cmos_get_fd_drive_type(FloppyDriveType fd0) return val; } -static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope) +static void build_fdc_aml(AcpiDevAmlIf *adev, Aml *scope) { - FDCtrlISABus *isa = ISA_FDC(isadev); + FDCtrlISABus *isa = ISA_FDC(adev); Aml *dev; Aml *crs; int i; @@ -241,7 +241,7 @@ static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope) aml_append(dev, aml_name_decl("_CRS", crs)); for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) { - FloppyDriveType type = isa_fdc_get_drive_type(isadev, i); + FloppyDriveType type = isa_fdc_get_drive_type(ISA_DEVICE(adev), i); if (type < FLOPPY_DRIVE_TYPE_NONE) { fde_buf[i] = cpu_to_le32(1); /* drive present */ @@ -283,14 +283,14 @@ static Property isa_fdc_properties[] = { static void isabus_fdc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); dc->desc = "virtual floppy controller"; dc->realize = isabus_fdc_realize; dc->fw_name = "fdc"; dc->reset = fdctrl_external_reset_isa; dc->vmsd = &vmstate_isa_fdc; - isa->build_aml = fdc_isa_build_aml; + adevc->build_dev_aml = build_fdc_aml; device_class_set_props(dc, isa_fdc_properties); set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } @@ -313,6 +313,10 @@ static const TypeInfo isa_fdc_info = { .instance_size = sizeof(FDCtrlISABus), .class_init = isabus_fdc_class_init, .instance_init = isabus_fdc_instance_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void isa_fdc_register_types(void) diff --git a/hw/block/fdc-sysbus.c b/hw/block/fdc-sysbus.c index 57fc8773f124..86ea51d00346 100644 --- a/hw/block/fdc-sysbus.c +++ b/hw/block/fdc-sysbus.c @@ -94,18 +94,14 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level) trace_fdctrl_tc_pulse(level); } -void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, - hwaddr mmio_base, DriveInfo **fds) +void fdctrl_init_sysbus(qemu_irq irq, hwaddr mmio_base, DriveInfo **fds) { - FDCtrl *fdctrl; DeviceState *dev; SysBusDevice *sbd; FDCtrlSysBus *sys; dev = qdev_new("sysbus-fdc"); sys = SYSBUS_FDC(dev); - fdctrl = &sys->state; - fdctrl->dma_chann = dma_chann; /* FIXME */ sbd = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sbd, &error_fatal); sysbus_connect_irq(sbd, 0, irq); @@ -138,6 +134,16 @@ static void sysbus_fdc_common_instance_init(Object *obj) FDCtrlSysBus *sys = SYSBUS_FDC(obj); FDCtrl *fdctrl = &sys->state; + /* + * DMA is not currently supported for sysbus floppy controllers. + * If we wanted to add support then probably the best approach is + * to have a QOM link property 'dma-controller' which the board + * code can set to an instance of IsaDmaClass, and an integer + * property 'dma-channel', so that we can set fdctrl->dma and + * fdctrl->dma_chann accordingly. + */ + fdctrl->dma_chann = -1; + qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */ memory_region_init_io(&fdctrl->iomem, obj, diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 347875a0cdae..64ae4a6899d4 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -1530,6 +1530,14 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) int tmp; fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); tmp = (fdctrl->fifo[6] - ks + 1); + if (tmp < 0) { + FLOPPY_DPRINTF("invalid EOT: %d\n", tmp); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; + } if (fdctrl->fifo[0] & 0x80) tmp += fdctrl->fifo[6]; fdctrl->data_len *= tmp; @@ -1620,8 +1628,8 @@ int fdctrl_transfer_handler(void *opaque, int nchan, int dma_pos, int dma_len) if (fdctrl->data_dir != FD_DIR_WRITE || len < FD_SECTOR_LEN || rel_pos != 0) { /* READ & SCAN commands and realign to a sector for WRITE */ - if (blk_pread(cur_drv->blk, fd_offset(cur_drv), - fdctrl->fifo, BDRV_SECTOR_SIZE) < 0) { + if (blk_pread(cur_drv->blk, fd_offset(cur_drv), BDRV_SECTOR_SIZE, + fdctrl->fifo, 0) < 0) { FLOPPY_DPRINTF("Floppy: error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ @@ -1648,8 +1656,8 @@ int fdctrl_transfer_handler(void *opaque, int nchan, int dma_pos, int dma_len) k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos, fdctrl->data_pos, len); - if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), - fdctrl->fifo, BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), BDRV_SECTOR_SIZE, + fdctrl->fifo, 0) < 0) { FLOPPY_DPRINTF("error writing sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); @@ -1732,8 +1740,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl) fd_sector(cur_drv)); return 0; } - if (blk_pread(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo, - BDRV_SECTOR_SIZE) + if (blk_pread(cur_drv->blk, fd_offset(cur_drv), BDRV_SECTOR_SIZE, + fdctrl->fifo, 0) < 0) { FLOPPY_DPRINTF("error getting sector %d\n", fd_sector(cur_drv)); @@ -1812,8 +1820,8 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) } memset(fdctrl->fifo, 0, FD_SECTOR_LEN); if (cur_drv->blk == NULL || - blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo, - BDRV_SECTOR_SIZE, 0) < 0) { + blk_pwrite(cur_drv->blk, fd_offset(cur_drv), BDRV_SECTOR_SIZE, + fdctrl->fifo, 0) < 0) { FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); } else { @@ -2236,8 +2244,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value) if (pos == FD_SECTOR_LEN - 1 || fdctrl->data_pos == fdctrl->data_len) { cur_drv = get_cur_drv(fdctrl); - if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), BDRV_SECTOR_SIZE, + fdctrl->fifo, 0) < 0) { FLOPPY_DPRINTF("error writing sector %d\n", fd_sector(cur_drv)); break; diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c index dcbccee294ca..dae13ab14d7c 100644 --- a/hw/block/hd-geometry.c +++ b/hw/block/hd-geometry.c @@ -63,7 +63,7 @@ static int guess_disk_lchs(BlockBackend *blk, blk_get_geometry(blk, &nb_sectors); - if (blk_pread(blk, 0, buf, BDRV_SECTOR_SIZE) < 0) { + if (blk_pread(blk, 0, BDRV_SECTOR_SIZE, buf, 0) < 0) { return -1; } /* test msdos magic */ @@ -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/m25p80.c b/hw/block/m25p80.c index 7d3d8b12e01f..02adc8752736 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -35,22 +35,21 @@ #include "qapi/error.h" #include "trace.h" #include "qom/object.h" - -/* Fields for FlashPartInfo->flags */ - -/* erase capabilities */ -#define ER_4K 1 -#define ER_32K 2 -/* set to allow the page program command to write 0s back to 1. Useful for - * modelling EEPROM with SPI flash command set - */ -#define EEPROM 0x100 +#include "m25p80_sfdp.h" /* 16 MiB max in 3 byte address mode */ #define MAX_3BYTES_SIZE 0x1000000 - #define SPI_NOR_MAX_ID_LEN 6 +/* Fields for FlashPartInfo->flags */ +enum spi_flash_option_flags { + ER_4K = BIT(0), + ER_32K = BIT(1), + EEPROM = BIT(2), + HAS_SR_TB = BIT(3), + HAS_SR_BP3_BIT6 = BIT(4), +}; + typedef struct FlashPartInfo { const char *part_name; /* @@ -74,6 +73,7 @@ typedef struct FlashPartInfo { * This field inform how many die is in the chip. */ uint8_t die_cnt; + uint8_t (*sfdp_read)(uint32_t sfdp_addr); } FlashPartInfo; /* adapted from linux */ @@ -232,12 +232,16 @@ static const FlashPartInfo known_devices[] = { { INFO("mx25l6405d", 0xc22017, 0, 64 << 10, 128, 0) }, { INFO("mx25l12805d", 0xc22018, 0, 64 << 10, 256, 0) }, { INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) }, - { INFO6("mx25l25635e", 0xc22019, 0xc22019, 64 << 10, 512, 0) }, + { INFO6("mx25l25635e", 0xc22019, 0xc22019, 64 << 10, 512, + ER_4K | ER_32K), .sfdp_read = m25p80_sfdp_mx25l25635e }, + { INFO6("mx25l25635f", 0xc22019, 0xc22019, 64 << 10, 512, + ER_4K | ER_32K), .sfdp_read = m25p80_sfdp_mx25l25635f }, { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, { INFO("mx66l51235f", 0xc2201a, 0, 64 << 10, 1024, ER_4K | ER_32K) }, { INFO("mx66u51235f", 0xc2253a, 0, 64 << 10, 1024, ER_4K | ER_32K) }, { INFO("mx66u1g45g", 0xc2253b, 0, 64 << 10, 2048, ER_4K | ER_32K) }, - { INFO("mx66l1g45g", 0xc2201b, 0, 64 << 10, 2048, ER_4K | ER_32K) }, + { INFO("mx66l1g45g", 0xc2201b, 0, 64 << 10, 2048, ER_4K | ER_32K), + .sfdp_read = m25p80_sfdp_mx66l1g45g }, /* Micron */ { INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) }, @@ -247,12 +251,15 @@ static const FlashPartInfo known_devices[] = { { INFO("n25q128a11", 0x20bb18, 0, 64 << 10, 256, ER_4K) }, { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) }, { INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) }, - { INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, + { INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K), + .sfdp_read = m25p80_sfdp_n25q256a }, { INFO("n25q512a11", 0x20bb20, 0, 64 << 10, 1024, ER_4K) }, { INFO("n25q512a13", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, - { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, - { INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, + { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, + ER_4K | HAS_SR_BP3_BIT6 | HAS_SR_TB), + .sfdp_read = m25p80_sfdp_n25q256a }, + { INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, { INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) }, { INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) }, { INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024, @@ -338,9 +345,12 @@ static const FlashPartInfo known_devices[] = { { INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) }, { INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) }, { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) }, - { INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) }, - { INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K) }, - { INFO("w25q01jvq", 0xef4021, 0, 64 << 10, 2048, ER_4K) }, + { INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K), + .sfdp_read = m25p80_sfdp_w25q256 }, + { INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K), + .sfdp_read = m25p80_sfdp_w25q512jv }, + { INFO("w25q01jvq", 0xef4021, 0, 64 << 10, 2048, ER_4K), + .sfdp_read = m25p80_sfdp_w25q01jvq }, }; typedef enum { @@ -356,6 +366,7 @@ typedef enum { BULK_ERASE = 0xc7, READ_FSR = 0x70, RDCR = 0x15, + RDSFDP = 0x5a, READ = 0x03, READ4 = 0x13, @@ -422,6 +433,7 @@ typedef enum { STATE_COLLECTING_DATA, STATE_COLLECTING_VAR_LEN_DATA, STATE_READING_DATA, + STATE_READING_SFDP, } CMDState; typedef enum { @@ -472,11 +484,18 @@ struct Flash { uint8_t spansion_cr2v; uint8_t spansion_cr3v; uint8_t spansion_cr4v; + bool wp_level; bool write_enable; bool four_bytes_address_mode; bool reset_enable; bool quad_enable; bool aai_enable; + bool block_protect0; + bool block_protect1; + bool block_protect2; + bool block_protect3; + bool top_bottom_bit; + bool status_register_write_disabled; uint8_t ear; int64_t dirty_page; @@ -621,12 +640,36 @@ void flash_write8(Flash *s, uint32_t addr, uint8_t data) { uint32_t page = addr / s->pi->page_size; uint8_t prev = s->storage[s->cur_addr]; + uint32_t block_protect_value = (s->block_protect3 << 3) | + (s->block_protect2 << 2) | + (s->block_protect1 << 1) | + (s->block_protect0 << 0); if (!s->write_enable) { qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n"); return; } + if (block_protect_value > 0) { + uint32_t num_protected_sectors = 1 << (block_protect_value - 1); + uint32_t sector = addr / s->pi->sector_size; + + /* top_bottom_bit == 0 means TOP */ + if (!s->top_bottom_bit) { + if (s->pi->n_sectors <= sector + num_protected_sectors) { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: write with write protect!\n"); + return; + } + } else { + if (sector < num_protected_sectors) { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: write with write protect!\n"); + return; + } + } + } + if ((prev ^ data) & data) { trace_m25p80_programming_zero_to_one(s, addr, prev, data); } @@ -649,6 +692,8 @@ static inline int get_addr_length(Flash *s) } switch (s->cmd_in_progress) { + case RDSFDP: + return 3; case PP4: case PP4_4: case QPP_4: @@ -723,6 +768,17 @@ static void complete_collecting_data(Flash *s) flash_erase(s, s->cur_addr, s->cmd_in_progress); break; case WRSR: + s->status_register_write_disabled = extract32(s->data[0], 7, 1); + s->block_protect0 = extract32(s->data[0], 2, 1); + s->block_protect1 = extract32(s->data[0], 3, 1); + s->block_protect2 = extract32(s->data[0], 4, 1); + if (s->pi->flags & HAS_SR_TB) { + s->top_bottom_bit = extract32(s->data[0], 5, 1); + } + if (s->pi->flags & HAS_SR_BP3_BIT6) { + s->block_protect3 = extract32(s->data[0], 6, 1); + } + switch (get_man(s)) { case MAN_SPANSION: s->quad_enable = !!(s->data[1] & 0x02); @@ -782,6 +838,11 @@ static void complete_collecting_data(Flash *s) " by device\n"); } break; + + case RDSFDP: + s->state = STATE_READING_SFDP; + break; + default: break; } @@ -1165,22 +1226,34 @@ static void decode_new_cmd(Flash *s, uint32_t value) break; case WRSR: - if (s->write_enable) { - switch (get_man(s)) { - case MAN_SPANSION: - s->needed_bytes = 2; - s->state = STATE_COLLECTING_DATA; - break; - case MAN_MACRONIX: - s->needed_bytes = 2; - s->state = STATE_COLLECTING_VAR_LEN_DATA; - break; - default: - s->needed_bytes = 1; - s->state = STATE_COLLECTING_DATA; - } - s->pos = 0; + /* + * If WP# is low and status_register_write_disabled is high, + * status register writes are disabled. + * This is also called "hardware protected mode" (HPM). All other + * combinations of the two states are called "software protected mode" + * (SPM), and status register writes are permitted. + */ + if ((s->wp_level == 0 && s->status_register_write_disabled) + || !s->write_enable) { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: Status register write is disabled!\n"); + break; } + + switch (get_man(s)) { + case MAN_SPANSION: + s->needed_bytes = 2; + s->state = STATE_COLLECTING_DATA; + break; + case MAN_MACRONIX: + s->needed_bytes = 2; + s->state = STATE_COLLECTING_VAR_LEN_DATA; + break; + default: + s->needed_bytes = 1; + s->state = STATE_COLLECTING_DATA; + } + s->pos = 0; break; case WRDI: @@ -1195,6 +1268,17 @@ static void decode_new_cmd(Flash *s, uint32_t value) case RDSR: s->data[0] = (!!s->write_enable) << 1; + s->data[0] |= (!!s->status_register_write_disabled) << 7; + s->data[0] |= (!!s->block_protect0) << 2; + s->data[0] |= (!!s->block_protect1) << 3; + s->data[0] |= (!!s->block_protect2) << 4; + if (s->pi->flags & HAS_SR_TB) { + s->data[0] |= (!!s->top_bottom_bit) << 5; + } + if (s->pi->flags & HAS_SR_BP3_BIT6) { + s->data[0] |= (!!s->block_protect3) << 6; + } + if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) { s->data[0] |= (!!s->quad_enable) << 6; } @@ -1367,6 +1451,16 @@ static void decode_new_cmd(Flash *s, uint32_t value) qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value); } break; + case RDSFDP: + if (s->pi->sfdp_read) { + s->needed_bytes = get_addr_length(s) + 1; /* SFDP addr + dummy */ + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + } + /* Fallthrough */ + default: s->pos = 0; s->len = 1; @@ -1474,6 +1568,12 @@ static uint32_t m25p80_transfer8(SSIPeripheral *ss, uint32_t tx) } } break; + case STATE_READING_SFDP: + assert(s->pi->sfdp_read); + r = s->pi->sfdp_read(s->cur_addr); + trace_m25p80_read_sfdp(s, s->cur_addr, (uint8_t)r); + s->cur_addr = (s->cur_addr + 1) & (M25P80_SFDP_MAX_SIZE - 1); + break; default: case STATE_IDLE: @@ -1484,6 +1584,14 @@ static uint32_t m25p80_transfer8(SSIPeripheral *ss, uint32_t tx) return r; } +static void m25p80_write_protect_pin_irq_handler(void *opaque, int n, int level) +{ + Flash *s = M25P80(opaque); + /* WP# is just a single pin. */ + assert(n == 0); + s->wp_level = !!level; +} + static void m25p80_realize(SSIPeripheral *ss, Error **errp) { Flash *s = M25P80(ss); @@ -1506,7 +1614,7 @@ static void m25p80_realize(SSIPeripheral *ss, Error **errp) trace_m25p80_binding(s); s->storage = blk_blockalign(s->blk, s->size); - if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) { + if (blk_pread(s->blk, 0, s->size, s->storage, 0) < 0) { error_setg(errp, "failed to read the initial flash content"); return; } @@ -1515,12 +1623,23 @@ static void m25p80_realize(SSIPeripheral *ss, Error **errp) s->storage = blk_blockalign(NULL, s->size); memset(s->storage, 0xFF, s->size); } + + qdev_init_gpio_in_named(DEVICE(s), + m25p80_write_protect_pin_irq_handler, "WP#", 1); } static void m25p80_reset(DeviceState *d) { Flash *s = M25P80(d); + s->wp_level = true; + s->status_register_write_disabled = false; + s->block_protect0 = false; + s->block_protect1 = false; + s->block_protect2 = false; + s->block_protect3 = false; + s->top_bottom_bit = false; + reset_memory(s); } @@ -1533,6 +1652,7 @@ static int m25p80_pre_save(void *opaque) static Property m25p80_properties[] = { /* This is default value for Micron flash */ + DEFINE_PROP_BOOL("write-enable", Flash, write_enable, false), DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF), DEFINE_PROP_UINT8("spansion-cr1nv", Flash, spansion_cr1nv, 0x0), DEFINE_PROP_UINT8("spansion-cr2nv", Flash, spansion_cr2nv, 0x8), @@ -1586,6 +1706,51 @@ static const VMStateDescription vmstate_m25p80_aai_enable = { } }; +static bool m25p80_wp_level_srwd_needed(void *opaque) +{ + Flash *s = (Flash *)opaque; + + return !s->wp_level || s->status_register_write_disabled; +} + +static const VMStateDescription vmstate_m25p80_write_protect = { + .name = "m25p80/write_protect", + .version_id = 1, + .minimum_version_id = 1, + .needed = m25p80_wp_level_srwd_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(wp_level, Flash), + VMSTATE_BOOL(status_register_write_disabled, Flash), + VMSTATE_END_OF_LIST() + } +}; + +static bool m25p80_block_protect_needed(void *opaque) +{ + Flash *s = (Flash *)opaque; + + return s->block_protect0 || + s->block_protect1 || + s->block_protect2 || + s->block_protect3 || + s->top_bottom_bit; +} + +static const VMStateDescription vmstate_m25p80_block_protect = { + .name = "m25p80/block_protect", + .version_id = 1, + .minimum_version_id = 1, + .needed = m25p80_block_protect_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(block_protect0, Flash), + VMSTATE_BOOL(block_protect1, Flash), + VMSTATE_BOOL(block_protect2, Flash), + VMSTATE_BOOL(block_protect3, Flash), + VMSTATE_BOOL(top_bottom_bit, Flash), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_m25p80 = { .name = "m25p80", .version_id = 0, @@ -1617,6 +1782,8 @@ static const VMStateDescription vmstate_m25p80 = { .subsections = (const VMStateDescription * []) { &vmstate_m25p80_data_read_loop, &vmstate_m25p80_aai_enable, + &vmstate_m25p80_write_protect, + &vmstate_m25p80_block_protect, NULL } }; diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c new file mode 100644 index 000000000000..77615fa29e5b --- /dev/null +++ b/hw/block/m25p80_sfdp.c @@ -0,0 +1,332 @@ +/* + * M25P80 Serial Flash Discoverable Parameter (SFDP) + * + * Copyright (c) 2020, 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/host-utils.h" +#include "m25p80_sfdp.h" + +#define define_sfdp_read(model) \ + uint8_t m25p80_sfdp_##model(uint32_t addr) \ + { \ + assert(is_power_of_2(sizeof(sfdp_##model))); \ + return sfdp_##model[addr & (sizeof(sfdp_##model) - 1)]; \ + } + +/* + * Micron + */ +static const uint8_t sfdp_n25q256a[] = { + 0x53, 0x46, 0x44, 0x50, 0x00, 0x01, 0x00, 0xff, + 0x00, 0x00, 0x01, 0x09, 0x30, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x29, 0xeb, 0x27, 0x6b, 0x08, 0x3b, 0x27, 0xbb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0xbb, + 0xff, 0xff, 0x29, 0xeb, 0x0c, 0x20, 0x10, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(n25q256a); + + +/* + * Matronix + */ + +/* mx25l25635e. No 4B opcodes */ +static const uint8_t sfdp_mx25l25635e[] = { + 0x53, 0x46, 0x44, 0x50, 0x00, 0x01, 0x01, 0xff, + 0x00, 0x00, 0x01, 0x09, 0x30, 0x00, 0x00, 0xff, + 0xc2, 0x00, 0x01, 0x04, 0x60, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x04, 0xbb, + 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x36, 0x00, 0x27, 0xf7, 0x4f, 0xff, 0xff, + 0xd9, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(mx25l25635e) + +static const uint8_t sfdp_mx25l25635f[] = { + 0x53, 0x46, 0x44, 0x50, 0x00, 0x01, 0x01, 0xff, + 0x00, 0x00, 0x01, 0x09, 0x30, 0x00, 0x00, 0xff, + 0xc2, 0x00, 0x01, 0x04, 0x60, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x04, 0xbb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x44, 0xeb, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x36, 0x00, 0x27, 0x9d, 0xf9, 0xc0, 0x64, + 0x85, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc2, 0xf5, 0x08, 0x0a, + 0x08, 0x04, 0x03, 0x06, 0x00, 0x00, 0x07, 0x29, + 0x17, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(mx25l25635f); + +static const uint8_t sfdp_mx66l1g45g[] = { + 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x02, 0xff, + 0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff, + 0xc2, 0x00, 0x01, 0x04, 0x10, 0x01, 0x00, 0xff, + 0x84, 0x00, 0x01, 0x02, 0xc0, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x04, 0xbb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x44, 0xeb, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0xff, 0xd6, 0x49, 0xc5, 0x00, + 0x85, 0xdf, 0x04, 0xe3, 0x44, 0x03, 0x67, 0x38, + 0x30, 0xb0, 0x30, 0xb0, 0xf7, 0xbd, 0xd5, 0x5c, + 0x4a, 0x9e, 0x29, 0xff, 0xf0, 0x50, 0xf9, 0x85, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0xef, 0xff, 0xff, 0x21, 0x5c, 0xdc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x36, 0x00, 0x27, 0x9d, 0xf9, 0xc0, 0x64, + 0x85, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc2, 0xf5, 0x08, 0x00, 0x0c, 0x04, 0x08, 0x08, + 0x01, 0x00, 0x19, 0x0f, 0x01, 0x01, 0x06, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(mx66l1g45g); + +/* + * Windbond + */ + +static const uint8_t sfdp_w25q256[] = { + 0x53, 0x46, 0x44, 0x50, 0x00, 0x01, 0x00, 0xff, + 0x00, 0x00, 0x01, 0x09, 0x80, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x21, 0xeb, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(w25q256); + +static const uint8_t sfdp_w25q512jv[] = { + 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff, + 0x00, 0x06, 0x01, 0x10, 0x80, 0x00, 0x00, 0xff, + 0x84, 0x00, 0x01, 0x02, 0xd0, 0x00, 0x00, 0xff, + 0x03, 0x00, 0x01, 0x02, 0xf0, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x40, 0xeb, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0x00, 0x36, 0x02, 0xa6, 0x00, + 0x82, 0xea, 0x14, 0xe2, 0xe9, 0x63, 0x76, 0x33, + 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xa2, 0xd5, 0x5c, + 0x19, 0xf7, 0x4d, 0xff, 0xe9, 0x70, 0xf9, 0xa5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0a, 0xf0, 0xff, 0x21, 0xff, 0xdc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(w25q512jv); + +static const uint8_t sfdp_w25q01jvq[] = { + 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff, + 0x00, 0x06, 0x01, 0x10, 0x80, 0x00, 0x00, 0xff, + 0x84, 0x00, 0x01, 0x02, 0xd0, 0x00, 0x00, 0xff, + 0x03, 0x00, 0x01, 0x02, 0xf0, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x40, 0xeb, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0x00, 0x36, 0x02, 0xa6, 0x00, + 0x82, 0xea, 0x14, 0xe2, 0xe9, 0x63, 0x76, 0x33, + 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xa2, 0xd5, 0x5c, + 0x19, 0xf7, 0x4d, 0xff, 0xe9, 0x70, 0xf9, 0xa5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0a, 0xf0, 0xff, 0x21, 0xff, 0xdc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(w25q01jvq); diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h new file mode 100644 index 000000000000..df7adfb5cec6 --- /dev/null +++ b/hw/block/m25p80_sfdp.h @@ -0,0 +1,29 @@ +/* + * M25P80 SFDP + * + * Copyright (c) 2020, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef HW_M25P80_SFDP_H +#define HW_M25P80_SFDP_H + +/* + * SFDP area has a 3 bytes address space. + */ +#define M25P80_SFDP_MAX_SIZE (1 << 24) + +uint8_t m25p80_sfdp_n25q256a(uint32_t addr); + +uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr); +uint8_t m25p80_sfdp_mx25l25635f(uint32_t addr); +uint8_t m25p80_sfdp_mx66l1g45g(uint32_t addr); + +uint8_t m25p80_sfdp_w25q256(uint32_t addr); +uint8_t m25p80_sfdp_w25q512jv(uint32_t addr); + +uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr); + +#endif diff --git a/hw/block/meson.build b/hw/block/meson.build index 2389326112ae..b434d5654caf 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -12,11 +12,12 @@ softmmu_ss.add(when: 'CONFIG_ONENAND', if_true: files('onenand.c')) softmmu_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c')) softmmu_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c')) softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) +softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80_sfdp.c')) 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/nand.c b/hw/block/nand.c index 8bc80e351442..1aee1cb2b1c7 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -666,8 +666,8 @@ static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s) sector = SECTOR(s->addr); off = (s->addr & PAGE_MASK) + s->offset; soff = SECTOR_OFFSET(s->addr); - if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) { + if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, + PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); return; } @@ -679,24 +679,24 @@ static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s) MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE)); } - if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) { + if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, + PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); } } else { off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; sector = off >> 9; soff = off & 0x1ff; - if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) { + if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, + (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); return; } mem_and(iobuf + soff, s->io, s->iolen); - if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) { + if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, + (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); } } @@ -723,20 +723,20 @@ static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s) i = SECTOR(addr); page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift))); for (; i < page; i ++) - if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, iobuf, 0) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i); } } else { addr = PAGE_START(addr); page = addr >> 9; - if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE) < 0) { + if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, iobuf, 0) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, page); } memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); - if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, iobuf, 0) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, page); } @@ -744,20 +744,20 @@ static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s) i = (addr & ~0x1ff) + 0x200; for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; i < addr; i += 0x200) { - if (blk_pwrite(s->blk, i, iobuf, BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(s->blk, i, BDRV_SECTOR_SIZE, iobuf, 0) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i >> 9); } } page = i >> 9; - if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE) < 0) { + if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, iobuf, 0) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, page); } memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); - if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, iobuf, 0) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, page); } } @@ -772,8 +772,8 @@ static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s, if (s->blk) { if (s->mem_oob) { - if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, s->io, - PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) { + if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, + PAGE_SECTORS << BDRV_SECTOR_BITS, s->io, 0) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, SECTOR(addr)); } @@ -782,8 +782,9 @@ static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s, OOB_SIZE); s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; } else { - if (blk_pread(s->blk, PAGE_START(addr), s->io, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) { + if (blk_pread(s->blk, PAGE_START(addr), + (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, s->io, 0) + < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, PAGE_START(addr) >> 9); } diff --git a/hw/block/onenand.c b/hw/block/onenand.c index afc0cd3a0ff1..1fde9750249c 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -229,8 +229,8 @@ static void onenand_reset(OneNANDState *s, int cold) /* Lock the whole flash */ memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks); - if (s->blk_cur && blk_pread(s->blk_cur, 0, s->boot[0], - 8 << BDRV_SECTOR_BITS) < 0) { + if (s->blk_cur && blk_pread(s->blk_cur, 0, 8 << BDRV_SECTOR_BITS, + s->boot[0], 0) < 0) { hw_error("%s: Loading the BootRAM failed.\n", __func__); } } @@ -249,8 +249,8 @@ static inline int onenand_load_main(OneNANDState *s, int sec, int secn, assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec); assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn); if (s->blk_cur) { - return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS, dest, - secn << BDRV_SECTOR_BITS) < 0; + return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS, + secn << BDRV_SECTOR_BITS, dest, 0) < 0; } else if (sec + secn > s->secs_cur) { return 1; } @@ -274,7 +274,7 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn, uint8_t *dp = 0; if (s->blk_cur) { dp = g_malloc(size); - if (!dp || blk_pread(s->blk_cur, offset, dp, size) < 0) { + if (!dp || blk_pread(s->blk_cur, offset, size, dp, 0) < 0) { result = 1; } } else { @@ -290,7 +290,7 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn, dp[i] &= sp[i]; } if (s->blk_cur) { - result = blk_pwrite(s->blk_cur, offset, dp, size, 0) < 0; + result = blk_pwrite(s->blk_cur, offset, size, dp, 0) < 0; } } if (dp && s->blk_cur) { @@ -308,7 +308,7 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn, if (s->blk_cur) { uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS; - if (blk_pread(s->blk_cur, offset, buf, BDRV_SECTOR_SIZE) < 0) { + if (blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, buf, 0) < 0) { return 1; } memcpy(dest, buf + ((sec & 31) << 4), secn << 4); @@ -333,7 +333,7 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn, if (s->blk_cur) { dp = g_malloc(512); if (!dp - || blk_pread(s->blk_cur, offset, dp, BDRV_SECTOR_SIZE) < 0) { + || blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp, 0) < 0) { result = 1; } else { dpp = dp + ((sec & 31) << 4); @@ -351,8 +351,8 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn, dpp[i] &= sp[i]; } if (s->blk_cur) { - result = blk_pwrite(s->blk_cur, offset, dp, - BDRV_SECTOR_SIZE, 0) < 0; + result = blk_pwrite(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp, + 0) < 0; } } g_free(dp); @@ -370,17 +370,17 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num) for (; num > 0; num--, sec++) { if (s->blk_cur) { int erasesec = s->secs_cur + (sec >> 5); - if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS, blankbuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, blankbuf, 0) < 0) { goto fail; } - if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf, - BDRV_SECTOR_SIZE) < 0) { + if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) { goto fail; } memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4); - if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS, + BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) { goto fail; } } else { diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 74c7190302bd..0cbc2fb4cbf6 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -392,8 +392,8 @@ static void pflash_update(PFlashCFI01 *pfl, int offset, /* widen to sector boundaries */ offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - ret = blk_pwrite(pfl->blk, offset, pfl->storage + offset, - offset_end - offset, 0); + ret = blk_pwrite(pfl->blk, offset, offset_end - offset, + pfl->storage + offset, 0); if (ret < 0) { /* TODO set error bit in status */ error_report("Could not update PFLASH: %s", strerror(-ret)); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 02c514fb6e0b..2a99b286b073 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -400,8 +400,8 @@ static void pflash_update(PFlashCFI02 *pfl, int offset, int size) /* widen to sector boundaries */ offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - ret = blk_pwrite(pfl->blk, offset, pfl->storage + offset, - offset_end - offset, 0); + ret = blk_pwrite(pfl->blk, offset, offset_end - offset, + pfl->storage + offset, 0); if (ret < 0) { /* TODO set error bit in status */ error_report("Could not update PFLASH: %s", strerror(-ret)); diff --git a/hw/block/trace-events b/hw/block/trace-events index d86b53520cc5..2c45a62bd59c 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -80,5 +80,6 @@ m25p80_page_program(void *s, uint32_t addr, uint8_t tx) "[%p] page program cur_a m25p80_transfer(void *s, uint8_t state, uint32_t len, uint8_t needed, uint32_t pos, uint32_t cur_addr, uint8_t t) "[%p] Transfer state 0x%"PRIx8" len 0x%"PRIx32" needed 0x%"PRIx8" pos 0x%"PRIx32" addr 0x%"PRIx32" tx 0x%"PRIx8 m25p80_read_byte(void *s, uint32_t addr, uint8_t v) "[%p] Read byte 0x%"PRIx32"=0x%"PRIx8 m25p80_read_data(void *s, uint32_t pos, uint8_t v) "[%p] Read data 0x%"PRIx32"=0x%"PRIx8 +m25p80_read_sfdp(void *s, uint32_t addr, uint8_t v) "[%p] Read SFDP 0x%"PRIx32"=0x%"PRIx8 m25p80_binding(void *s) "[%p] Binding to IF_MTD drive" m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM" diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 1a42ae918705..aff4d2b8cbdf 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" @@ -51,6 +52,7 @@ static const int user_feature_bits[] = { VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_RING_PACKED, VIRTIO_F_IOMMU_PLATFORM, + VIRTIO_F_RING_RESET, VHOST_INVALID_FEATURE_BIT }; @@ -63,7 +65,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 +94,16 @@ 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; + if (!dev->started) { + return 0; + } + 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 +112,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); } @@ -163,13 +169,6 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp) goto err_guest_notifiers; } - ret = vhost_dev_start(&s->dev, vdev); - if (ret < 0) { - error_setg_errno(errp, -ret, "Error starting vhost"); - goto err_guest_notifiers; - } - s->started_vu = true; - /* guest_notifier_mask/pending not used yet, so just unmask * everything here. virtio-pci will do the right thing by * enabling/disabling irqfd. @@ -178,9 +177,20 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp) vhost_virtqueue_mask(&s->dev, vdev, i, false); } + s->dev.vq_index_end = s->dev.nvqs; + ret = vhost_dev_start(&s->dev, vdev, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; + } + s->started_vu = true; + return ret; err_guest_notifiers: + for (i = 0; i < s->dev.nvqs; i++) { + vhost_virtqueue_mask(&s->dev, vdev, i, true); + } k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); err_host_notifiers: vhost_dev_disable_notifiers(&s->dev, vdev); @@ -203,7 +213,7 @@ static void vhost_user_blk_stop(VirtIODevice *vdev) return; } - vhost_dev_stop(&s->dev, vdev); + vhost_dev_stop(&s->dev, vdev, true); ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); if (ret < 0) { @@ -217,19 +227,15 @@ static void vhost_user_blk_stop(VirtIODevice *vdev) static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserBlk *s = VHOST_USER_BLK(vdev); - bool should_start = virtio_device_started(vdev, status); + bool should_start = virtio_device_should_start(vdev, status); Error *local_err = NULL; int ret; - if (!vdev->vm_running) { - should_start = false; - } - if (!s->connected) { return; } - if (s->dev.started == should_start) { + if (vhost_dev_is_started(&s->dev) == should_start) { return; } @@ -259,12 +265,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 +287,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; } @@ -337,6 +338,7 @@ static int vhost_user_blk_connect(DeviceState *dev, Error **errp) vhost_dev_set_config_notifier(&s->dev, &blk_ops); + s->vhost_user.supports_config = true; ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0, errp); if (ret < 0) { @@ -367,17 +369,10 @@ static void vhost_user_blk_disconnect(DeviceState *dev) vhost_user_blk_stop(vdev); vhost_dev_cleanup(&s->dev); -} -static void vhost_user_blk_chr_closed_bh(void *opaque) -{ - DeviceState *dev = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VHostUserBlk *s = VHOST_USER_BLK(vdev); - - vhost_user_blk_disconnect(dev); + /* Re-instate the event handler for new connections */ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, - NULL, opaque, NULL, true); + NULL, dev, NULL, true); } static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) @@ -396,27 +391,9 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) } break; case CHR_EVENT_CLOSED: - if (!runstate_check(RUN_STATE_SHUTDOWN)) { - /* - * A close event may happen during a read/write, but vhost - * code assumes the vhost_dev remains setup, so delay the - * stop & clear. - */ - AioContext *ctx = qemu_get_current_aio_context(); - - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL, - NULL, NULL, false); - aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque); - - /* - * Move vhost device to the stopped state. The vhost-user device - * will be clean up and disconnected in BH. This can be useful in - * 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). - */ - s->dev.started = false; - } + /* defer close until later to avoid circular close */ + vhost_user_async_close(dev, &s->chardev, &s->dev, + vhost_user_blk_disconnect); break; case CHR_EVENT_BREAK: case CHR_EVENT_MUX_IN: @@ -446,7 +423,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); @@ -461,6 +438,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; @@ -491,8 +469,9 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-blk", 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++) { @@ -569,6 +548,12 @@ static void vhost_user_blk_instance_init(Object *obj) "/disk@0,0", DEVICE(obj)); } +static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev) +{ + VHostUserBlk *s = VHOST_USER_BLK(vdev); + return &s->dev; +} + static const VMStateDescription vmstate_vhost_user_blk = { .name = "vhost-user-blk", .minimum_version_id = 1, @@ -584,7 +569,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(), }; @@ -603,6 +593,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data) vdc->get_features = vhost_user_blk_get_features; vdc->set_status = vhost_user_blk_set_status; vdc->reset = vhost_user_blk_reset; + vdc->get_vhost = vhost_user_blk_get_vhost; } static const TypeInfo vhost_user_blk_info = { diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c new file mode 100644 index 000000000000..ac52d7c176e7 --- /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 540c38f829f6..f717550fdc22 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -21,6 +21,7 @@ #include "hw/block/block.h" #include "hw/qdev-properties.h" #include "sysemu/blockdev.h" +#include "sysemu/block-ram-registrar.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" #include "hw/virtio/virtio-blk.h" @@ -32,31 +33,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) { @@ -384,12 +363,14 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) } } -static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb, +static inline void submit_requests(VirtIOBlock *s, MultiReqBuffer *mrb, int start, int num_reqs, int niov) { + BlockBackend *blk = s->blk; QEMUIOVector *qiov = &mrb->reqs[start]->qiov; int64_t sector_num = mrb->reqs[start]->sector_num; bool is_write = mrb->is_write; + BdrvRequestFlags flags = 0; if (num_reqs > 1) { int i; @@ -420,12 +401,18 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb, num_reqs - 1); } + if (blk_ram_registrar_ok(&s->blk_ram_registrar)) { + flags |= BDRV_REQ_REGISTERED_BUF; + } + if (is_write) { - blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0, - virtio_blk_rw_complete, mrb->reqs[start]); + blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov, + flags, virtio_blk_rw_complete, + mrb->reqs[start]); } else { - blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0, - virtio_blk_rw_complete, mrb->reqs[start]); + blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov, + flags, virtio_blk_rw_complete, + mrb->reqs[start]); } } @@ -447,14 +434,14 @@ static int multireq_compare(const void *a, const void *b) } } -static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) +static void virtio_blk_submit_multireq(VirtIOBlock *s, MultiReqBuffer *mrb) { int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0; uint32_t max_transfer; int64_t sector_num = 0; if (mrb->num_reqs == 1) { - submit_requests(blk, mrb, 0, 1, -1); + submit_requests(s, mrb, 0, 1, -1); mrb->num_reqs = 0; return; } @@ -474,11 +461,11 @@ static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) * 3. merge would exceed maximum transfer length of backend device */ if (sector_num + nb_sectors != req->sector_num || - niov > blk_get_max_iov(blk) - req->qiov.niov || + niov > blk_get_max_iov(s->blk) - req->qiov.niov || req->qiov.size > max_transfer || nb_sectors > (max_transfer - req->qiov.size) / BDRV_SECTOR_SIZE) { - submit_requests(blk, mrb, start, num_reqs, niov); + submit_requests(s, mrb, start, num_reqs, niov); num_reqs = 0; } } @@ -494,7 +481,7 @@ static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) num_reqs++; } - submit_requests(blk, mrb, start, num_reqs, niov); + submit_requests(s, mrb, start, num_reqs, niov); mrb->num_reqs = 0; } @@ -509,7 +496,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb) * Make sure all outstanding writes are posted to the backing device. */ if (mrb->is_write && mrb->num_reqs > 0) { - virtio_blk_submit_multireq(s->blk, mrb); + virtio_blk_submit_multireq(s, mrb); } blk_aio_flush(s->blk, virtio_blk_flush_complete, req); } @@ -689,7 +676,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS || is_write != mrb->is_write || !s->conf.request_merging)) { - virtio_blk_submit_multireq(s->blk, mrb); + virtio_blk_submit_multireq(s, mrb); } assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS); @@ -796,7 +783,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) } while (!virtio_queue_empty(vq)); if (mrb.num_reqs) { - virtio_blk_submit_multireq(s->blk, &mrb); + virtio_blk_submit_multireq(s, &mrb); } blk_io_unplug(s->blk); @@ -845,7 +832,7 @@ void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) } if (mrb.num_reqs) { - virtio_blk_submit_multireq(s->blk, &mrb); + virtio_blk_submit_multireq(s, &mrb); } if (is_bh) { blk_dec_in_flight(s->conf.conf.blk); @@ -1204,9 +1191,9 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) return; } - virtio_blk_set_config_size(s, s->host_features); - - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size); + 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; s->rq = NULL; @@ -1215,8 +1202,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) for (i = 0; i < conf->num_queues; i++) { virtio_add_queue(vdev, conf->queue_size, virtio_blk_handle_output); } - qemu_coroutine_increase_pool_batch_size(conf->num_queues * conf->queue_size - / 2); + qemu_coroutine_inc_pool_size(conf->num_queues * conf->queue_size / 2); virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); @@ -1228,8 +1214,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) } s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); + blk_ram_registrar_init(&s->blk_ram_registrar, s->blk); blk_set_dev_ops(s->blk, &virtio_block_ops, s); - blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size); blk_iostatus_enable(s->blk); @@ -1253,8 +1239,8 @@ static void virtio_blk_device_unrealize(DeviceState *dev) for (i = 0; i < conf->num_queues; i++) { virtio_del_queue(vdev, i); } - qemu_coroutine_decrease_pool_batch_size(conf->num_queues * conf->queue_size - / 2); + qemu_coroutine_dec_pool_size(conf->num_queues * conf->queue_size / 2); + blk_ram_registrar_destroy(&s->blk_ram_registrar); qemu_del_vm_change_state_handler(s->change); blockdev_mark_auto_del(s->blk); virtio_cleanup(vdev); diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 674953f1adee..345b284d7018 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -243,7 +243,6 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) } blk_set_dev_ops(blk, &xen_block_dev_ops, blockdev); - blk_set_guest_block_size(blk, conf->logical_block_size); if (conf->discard_granularity == -1) { conf->discard_granularity = conf->physical_block_size; diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 6b6cf2fc1dff..b471053309bd 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -71,3 +71,6 @@ config GOLDFISH_TTY config SHAKTI_UART bool + +config RT_FLEXCOMM + bool diff --git a/hw/char/escc.c b/hw/char/escc.c index 8755d8d34f3f..17a908c59b91 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -828,7 +828,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, } } - if (qcode > qemu_input_map_qcode_to_sun_len) { + if (qcode >= qemu_input_map_qcode_to_sun_len) { return; } diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index addcd59b028b..7b7c56b6ef47 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -211,7 +211,7 @@ static void fifo_reset(Exynos4210UartFIFO *q) g_free(q->data); q->data = NULL; - q->data = (uint8_t *)g_malloc0(q->size); + q->data = g_malloc0(q->size); q->sp = 0; q->rp = 0; diff --git a/hw/char/meson.build b/hw/char/meson.build index 7b594f51b86f..af8f9b78d748 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -32,6 +32,7 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c')) softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c')) softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c')) +softmmu_ss.add(when: 'CONFIG_RT_FLEXCOMM', if_true: files('rt_flexcomm.c')) specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c')) specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c')) diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c index e8da9333782c..1c890b92018a 100644 --- a/hw/char/omap_uart.c +++ b/hw/char/omap_uart.c @@ -67,10 +67,9 @@ struct omap_uart_s *omap_uart_init(hwaddr base, return s; } -static uint64_t omap_uart_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_uart_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_uart_s *s = (struct omap_uart_s *) opaque; + struct omap_uart_s *s = opaque; if (size == 4) { return omap_badwidth_read8(opaque, addr); @@ -108,7 +107,7 @@ static uint64_t omap_uart_read(void *opaque, hwaddr addr, static void omap_uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_uart_s *s = (struct omap_uart_s *) opaque; + struct omap_uart_s *s = opaque; if (size == 4) { omap_badwidth_write8(opaque, addr, value); diff --git a/hw/char/parallel.c b/hw/char/parallel.c index f735a6cd7f4d..1c9ca47820bb 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -28,7 +28,7 @@ #include "qemu/module.h" #include "chardev/char-parallel.h" #include "chardev/char-fe.h" -#include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" @@ -570,9 +570,9 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp) s, "parallel"); } -static void parallel_isa_build_aml(ISADevice *isadev, Aml *scope) +static void parallel_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope) { - ISAParallelState *isa = ISA_PARALLEL(isadev); + ISAParallelState *isa = ISA_PARALLEL(adev); Aml *dev; Aml *crs; @@ -645,11 +645,11 @@ static Property parallel_isa_properties[] = { static void parallel_isa_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); dc->realize = parallel_isa_realizefn; dc->vmsd = &vmstate_parallel_isa; - isa->build_aml = parallel_isa_build_aml; + adevc->build_dev_aml = parallel_isa_build_aml; device_class_set_props(dc, parallel_isa_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } @@ -659,6 +659,10 @@ static const TypeInfo parallel_isa_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAParallelState), .class_init = parallel_isa_class_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void parallel_register_types(void) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 6e2d7f75095c..c076813423fc 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -176,7 +176,7 @@ static unsigned int pl011_get_baudrate(const PL011State *s) { uint64_t clk; - if (s->fbrd == 0) { + if (s->ibrd == 0) { return 0; } diff --git a/hw/char/rt_flexcomm.c b/hw/char/rt_flexcomm.c new file mode 100644 index 000000000000..3003e45d8386 --- /dev/null +++ b/hw/char/rt_flexcomm.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "chardev/char-fe.h" +#include "chardev/char-serial.h" +#include "hw/char/rt_flexcomm.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/fifo8.h" +#include "sysemu/sysemu.h" + +static void rt_flexcomm_update(RTFLEXCOMMState *s); + +static void uart_update_parameters(RTFLEXCOMMState *s) +{ + QEMUSerialSetParams ssp; + + /* FIXME hardcode to 115200 8N1 */ + ssp.data_bits = 8; + ssp.parity = 'N'; + ssp.stop_bits = 1; + ssp.speed = 115200; + qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); +} + +static int rt_flexcomm_post_load(void *opaque, int version_id) +{ + RTFLEXCOMMState *s = (RTFLEXCOMMState *)opaque; + + uart_update_parameters(s); + return 0; +} + +static const VMStateDescription vmstate_rt_flexcomm = { + .name = TYPE_RT_FLEXCOMM, + .version_id = 1, + .minimum_version_id = 0, + .post_load = rt_flexcomm_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(USART_CFG, RTFLEXCOMMState), + VMSTATE_UINT32(USART_CTL, RTFLEXCOMMState), + VMSTATE_UINT32(USART_STAT, RTFLEXCOMMState), + VMSTATE_UINT32(USART_INTENSET, RTFLEXCOMMState), + VMSTATE_UINT32(USART_INTENCLR, RTFLEXCOMMState), + VMSTATE_UINT32(USART_BRG, RTFLEXCOMMState), + VMSTATE_UINT32(USART_INTSTAT, RTFLEXCOMMState), + VMSTATE_UINT32(USART_OSR, RTFLEXCOMMState), + VMSTATE_UINT32(USART_ADDR, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOCFG, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOSTAT, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOTRIG, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOINTENSET, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOINTENCLR, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOINTSTAT, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOWR, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFORD, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFORDNOPOP, RTFLEXCOMMState), + VMSTATE_UINT32(USART_FIFOSIZE, RTFLEXCOMMState), + VMSTATE_UINT32(PSELID, RTFLEXCOMMState), + VMSTATE_UINT32(ID, RTFLEXCOMMState), + VMSTATE_UINT32(FIFO_SIZE, RTFLEXCOMMState), + VMSTATE_END_OF_LIST() + }, +}; + +/* Try to send tx data, and arrange to be called back later if + * we can't (ie the char backend is busy/blocking). + */ +static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) +{ + RTFLEXCOMMState *s = RT_FLEXCOMM(opaque); + int ret; + uint32_t num = fifo8_num_used(s->TXFIFO); + + if (num == 0) { + return FALSE; + } + const uint8_t * txbuf = fifo8_pop_buf(s->TXFIFO, num, &num); + ret = qemu_chr_fe_write(&s->chr, txbuf, num); + if (ret <= 0) { + printf("fw_write error %d\n", ret); + fifo8_push_all(s->TXFIFO, txbuf, num); + guint _r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, + uart_transmit, s); + if (!_r) { + printf("schedule fw_write error %d\n", _r); + /* Most common reason to be here is "no chardev backend": + * just insta-drain the buffer, so the serial output + * goes into a void, rather than blocking the guest. + */ + goto buffer_drained; + } + return FALSE; + } + rt_flexcomm_update(s); + +buffer_drained: + /* Going from TXFULL set to clear triggers the tx interrupt */ + return FALSE; +} + +static void rt_flexcomm_update(RTFLEXCOMMState *s) +{ + uint32_t psel = s->PSELID & PERSEL_MASK; + int raise_irq = 0; + + switch (psel) { + case 0: + break; + case 1: + s->PSELID |= USARTPRESE_MASK; + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + default: + break; + } + + if(fifo8_is_full(s->TXFIFO)) + { + s->USART_FIFOSTAT &= ~USART_STAT_TXNOTFULL_MASK; + } + + if(fifo8_is_full(s->RXFIFO)) + { + s->USART_FIFOSTAT |= USART_STAT_RXFULL_MASK; + } + + if(fifo8_is_empty(s->RXFIFO)) + { + s->USART_FIFOSTAT &= ~USART_STAT_RXNOTEMPTY_MASK; + } else { + s->USART_FIFOSTAT |= USART_STAT_RXNOTEMPTY_MASK; + } + + if(fifo8_is_empty(s->TXFIFO)) + { + s->USART_FIFOSTAT |= USART_STAT_TXNOTFULL_MASK; + } else { + s->USART_FIFOSTAT &= ~USART_STAT_TXNOTFULL_MASK; + uart_transmit(NULL, G_IO_OUT, s); + } + + if(fifo8_num_used(s->RXFIFO) >= FIFOTRIG_RXLVL(s)) + { + s->USART_FIFOINTSTAT |= USART_FIFOINTSTAT_RXLVL; + } else { + s->USART_FIFOINTSTAT &= ~USART_FIFOINTSTAT_RXLVL; + } + + if(fifo8_num_used(s->TXFIFO) >= FIFOTRIG_TXLVL(s)) + { + s->USART_FIFOINTSTAT |= USART_FIFOINTSTAT_TXLVL; + } else { + s->USART_FIFOINTSTAT &= ~USART_FIFOINTSTAT_TXLVL; + } + + if((s->USART_FIFOINTENSET & USART_FIFOINTSTAT_RXLVL) == USART_FIFOINTSTAT_RXLVL) + { + if ((s->USART_FIFOINTSTAT & USART_FIFOINTSTAT_RXLVL) == USART_FIFOINTSTAT_RXLVL) + { + raise_irq = 1; + } + } + + if((s->USART_FIFOINTENSET & USART_FIFOINTSTAT_TXLVL) == USART_FIFOINTSTAT_TXLVL) + { + if ((s->USART_FIFOINTSTAT & USART_FIFOINTSTAT_TXLVL) == USART_FIFOINTSTAT_TXLVL) + { + raise_irq = 1; + } + } + qemu_set_irq(s->irq, raise_irq); +} + +static void rt_flexcomm_reset(RTFLEXCOMMState *s) +{ + s->USART_CFG = 0x0; + s->USART_CTL = 0x0; + s->USART_STAT = 0xA; + s->USART_INTENSET = 0x0; + s->USART_INTENCLR = 0x0; + s->USART_BRG = 0x0; + s->USART_INTSTAT = 0x0; + s->USART_OSR = 0xF; + s->USART_ADDR = 0x0; + s->USART_FIFOCFG = 0x0; + s->USART_FIFOSTAT = 0x30; + s->USART_FIFOTRIG = 0x0; + s->USART_FIFOINTENSET = 0x0; + s->USART_FIFOINTENCLR = 0x0; + s->USART_FIFOINTSTAT = 0x0; + s->USART_FIFOWR = 0x0; + s->USART_FIFORD = 0x0; + s->USART_FIFORDNOPOP = 0x0; + s->USART_FIFOSIZE = 0x10; + s->ID = 0x0FFC0000; + s->PSELID = 0x1020f0; +} + +static void rt_flexcomm_reset_at_boot(DeviceState *dev) +{ + RTFLEXCOMMState *s = RT_FLEXCOMM(dev); + + rt_flexcomm_reset(s); +} + +static int uart_can_receive(void *opaque) +{ + RTFLEXCOMMState *s = RT_FLEXCOMM(opaque); + + /* We can take a char if RX is enabled and the buffer is empty */ + if ((s->USART_FIFOSTAT & USART_STAT_RXFULL_MASK) == 0x0) { + return 1; + } + return 0; +} + +static void uart_receive(void *opaque, const uint8_t *buf, int size) +{ + RTFLEXCOMMState *s = RT_FLEXCOMM(opaque); + + int i = 0; + while(i < size) { + fifo8_push(s->RXFIFO, buf[i]); + rt_flexcomm_update(s); + qemu_chr_fe_accept_input(&s->chr); + i++; + } +} + +static uint64_t rt_flexcomm_read(void *opaque, hwaddr offset, + unsigned size) +{ + RTFLEXCOMMState *s = (RTFLEXCOMMState *)opaque; + uint32_t v = 0; + + switch (offset) { + case 0x0: + v = s->USART_CFG; + break; + case 0x4: + v = s->USART_CTL; + break; + case 0x8: + v = s->USART_STAT; + break; + case 0xC: + v = s->USART_INTENSET; + break; + case 0x10: + v = s->USART_INTENCLR; + break; + case 0x20: + v = s->USART_BRG; + break; + case 0x24: + v = s->USART_INTSTAT; + break; + case 0x28: + v = s->USART_OSR; + break; + case 0x2C: + v = s->USART_ADDR; + break; + case 0xE00: + v = s->USART_FIFOCFG; + break; + case 0xE04: + v = s->USART_FIFOSTAT; + break; + case 0xE08: + v = s->USART_FIFOTRIG; + break; + case 0xE10: + v = s->USART_FIFOINTENSET; + break; + case 0xE14: + v = s->USART_FIFOINTENCLR; + break; + case 0xE18: + v = s->USART_FIFOINTSTAT; + break; + case 0xE20: + v = s->USART_FIFOWR; + break; + case 0xE30: + if (fifo8_num_used(s->RXFIFO)) { + s->USART_FIFORD = fifo8_pop(s->RXFIFO); + } + v = s->USART_FIFORD; + break; + case 0xE40: + v = s->USART_FIFORDNOPOP; + break; + case 0xE48: + v = s->USART_FIFOSIZE; + break; + case 0xFFC: + v = s->ID; + break; + case 0xFF8: + v = s->PSELID; + break; + default: + break;; + } + rt_flexcomm_update(s); + return v; +} + + +static void rt_flexcomm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + RTFLEXCOMMState *s = (RTFLEXCOMMState *)opaque; + + switch (offset) { + case 0x0: + s->USART_CFG = value; + break; + case 0x4: + s->USART_CTL = value; + break; + case 0x8: + s->USART_STAT = value; + break; + case 0xC: + s->USART_INTENSET = value; + break; + case 0x10: + s->USART_INTENCLR = value; + break; + case 0x20: + s->USART_BRG = value; + break; + case 0x24: + // s->INTSTAT read only + break; + case 0x28: + s->USART_OSR = value; + break; + case 0x2C: + s->USART_ADDR = value; + break; + case 0xE00: + s->USART_FIFOCFG = value; + break; + case 0xE04: + //s->FIFOSTAT read only + break; + case 0xE08: + s->USART_FIFOTRIG = value; + break; + case 0xE10: + s->USART_FIFOINTENSET = value; + break; + case 0xE14: + s->USART_FIFOINTENCLR = value; + break; + case 0xE18: + // s->FIFOINTSTAT read only + break; + case 0xE20: + s->USART_FIFOWR = value; + if (s->USART_CTL && USARTD_TXDIS_MASK) + { + break; + } + printf("%c", (char)value); + if ((s->USART_FIFOSTAT & USART_STAT_TXNOTFULL_MASK) == USART_STAT_TXNOTFULL_MASK) + { + fifo8_push(s->TXFIFO, s->USART_FIFOWR); + } + break; + case 0xE30: + // s->FIFORD read only + break; + case 0xE40: + // s->FIFORDNOPOP read only; + break; + case 0xE48: + // s->FIFOSIZE read only + break; + case 0xFF8: + s->PSELID = value; + break; + default: + break; + } + + rt_flexcomm_update(s); +} + +static const struct MemoryRegionOps rt_flexcomm_ops = { + .read = rt_flexcomm_read, + .write = rt_flexcomm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_flexcomm_realize(DeviceState *dev, Error **errp) +{ + RTFLEXCOMMState *s = RT_FLEXCOMM(dev); + + s->RXFIFO = (Fifo8 *)g_malloc0(sizeof(Fifo8)); + s->TXFIFO = (Fifo8 *)g_malloc0(sizeof(Fifo8)); + + fifo8_create(s->RXFIFO, s->FIFO_SIZE); + fifo8_create(s->TXFIFO, s->FIFO_SIZE); + + qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive, + NULL, NULL, s, NULL, true); + +} + +static void rt_flexcomm_unrealize(DeviceState *dev) +{ + RTFLEXCOMMState *s = RT_FLEXCOMM(dev); + + fifo8_destroy(s->RXFIFO); + fifo8_destroy(s->TXFIFO); + + g_free(s->RXFIFO); + g_free(s->TXFIFO); +} + +static void rt_flexcomm_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RTFLEXCOMMState *s = (RTFLEXCOMMState *)obj; + + memory_region_init_io(&s->iomem, obj, &rt_flexcomm_ops, s, + TYPE_RT_FLEXCOMM, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static Property rt_flexcomm_properties[] = { + DEFINE_PROP_UINT32("FIFO_SIZE", RTFLEXCOMMState, FIFO_SIZE, 16), + DEFINE_PROP_CHR("chardev", RTFLEXCOMMState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rt_flexcomm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_flexcomm_realize; + dc->vmsd = &vmstate_rt_flexcomm; + dc->reset = rt_flexcomm_reset_at_boot; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + dc->desc = "RT FLEXCOMM"; + dc->unrealize = rt_flexcomm_unrealize; + device_class_set_props(dc, rt_flexcomm_properties); +} + +static const TypeInfo rt_flexcomm_info = { + .name = TYPE_RT_FLEXCOMM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTFLEXCOMMState), + .instance_init = rt_flexcomm_init, + .class_init = rt_flexcomm_class_init, +}; + +static void rt_flexcomm_register_types(void) +{ + type_register_static(&rt_flexcomm_info); +} + +type_init(rt_flexcomm_register_types) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index 7a7ed239cd10..141a6cb16849 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -27,7 +27,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "sysemu/sysemu.h" -#include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/char/serial.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" @@ -83,9 +83,9 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &s->io, isa->iobase); } -static void serial_isa_build_aml(ISADevice *isadev, Aml *scope) +static void serial_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope) { - ISASerialState *isa = ISA_SERIAL(isadev); + ISASerialState *isa = ISA_SERIAL(adev); Aml *dev; Aml *crs; @@ -122,11 +122,11 @@ static Property serial_isa_properties[] = { static void serial_isa_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); dc->realize = serial_isa_realizefn; dc->vmsd = &vmstate_isa_serial; - isa->build_aml = serial_isa_build_aml; + adevc->build_dev_aml = serial_isa_build_aml; device_class_set_props(dc, serial_isa_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } @@ -146,6 +146,10 @@ static const TypeInfo serial_isa_info = { .instance_size = sizeof(ISASerialState), .instance_init = serial_isa_initfn, .class_init = serial_isa_class_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void serial_register_types(void) diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 3a9f96c2d115..f18b8dcce5fe 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -31,7 +31,7 @@ #include "qapi/error.h" #include "hw/char/serial.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "migration/vmstate.h" diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 93d6f9924425..801b769ababd 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -30,7 +30,7 @@ #include "qemu/module.h" #include "hw/char/serial.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qom/object.h" diff --git a/hw/char/serial.c b/hw/char/serial.c index 7061aacbce9c..41b5e61977d3 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/char/sifive_uart.c b/hw/char/sifive_uart.c index 1c75f792b352..f2684e57bccb 100644 --- a/hw/char/sifive_uart.c +++ b/hw/char/sifive_uart.c @@ -274,7 +274,6 @@ SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base, { DeviceState *dev; SysBusDevice *s; - SiFiveUARTState *r; dev = qdev_new("riscv.sifive.uart"); s = SYS_BUS_DEVICE(dev); @@ -284,6 +283,5 @@ SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base, sysbus_mmio_get_region(s, 0)); sysbus_connect_irq(s, 0, irq); - r = SIFIVE_UART(dev); - return r; + return SIFIVE_UART(dev); } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 6048d408b8b1..7d4601cb5dca 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1044,8 +1044,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) VIRTIO_CONSOLE_F_EMERG_WRITE)) { config_size = offsetof(struct virtio_console_config, emerg_wr); } - virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE, - config_size); + virtio_init(vdev, VIRTIO_ID_CONSOLE, config_size); /* Spawn a new virtio-serial bus on which the ports will ride as devices */ qbus_init(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, diff --git a/hw/core/clock.c b/hw/core/clock.c index 916875e07a26..d82e44cd1aa8 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 9e3241b43085..5ccc3837b678 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -116,9 +116,9 @@ void cpu_reset(CPUState *cpu) trace_guest_cpu_reset(cpu); } -static void cpu_common_reset(DeviceState *dev) +static void cpu_common_reset_hold(Object *obj) { - CPUState *cpu = CPU(dev); + CPUState *cpu = CPU(obj); CPUClass *cc = CPU_GET_CLASS(cpu); if (qemu_loglevel_mask(CPU_LOG_RESET)) { @@ -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); } } @@ -236,8 +235,10 @@ static void cpu_common_initfn(Object *obj) /* the default value is changed by qemu_init_vcpu() for softmmu */ cpu->nr_cores = 1; cpu->nr_threads = 1; + cpu->cflags_next_tb = -1; qemu_mutex_init(&cpu->work_mutex); + qemu_lockcnt_init(&cpu->in_ioctl_lock); QSIMPLEQ_INIT(&cpu->work_list); QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); @@ -249,6 +250,7 @@ static void cpu_common_finalize(Object *obj) { CPUState *cpu = CPU(obj); + qemu_lockcnt_destroy(&cpu->in_ioctl_lock); qemu_mutex_destroy(&cpu->work_mutex); } @@ -260,6 +262,7 @@ static int64_t cpu_common_get_arch_id(CPUState *cpu) static void cpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); CPUClass *k = CPU_CLASS(klass); k->parse_features = cpu_common_parse_features; @@ -270,7 +273,7 @@ static void cpu_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_CPU, dc->categories); dc->realize = cpu_common_realizefn; dc->unrealize = cpu_common_unrealizefn; - dc->reset = cpu_common_reset; + rc->phases.hold = cpu_common_reset_hold; cpu_class_init_props(dc); /* * Reason: CPUs still need special care by board code: wiring up diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c index 00253f89293a..5eaf2e79e66c 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/generic-loader.c b/hw/core/generic-loader.c index c666545aa00a..4f4d77908dad 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -67,7 +67,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) GenericLoaderState *s = GENERIC_LOADER(dev); hwaddr entry; int big_endian; - int size = 0; + ssize_t size = 0; s->set_pc = false; diff --git a/hw/core/irq.c b/hw/core/irq.c index 741219277b1b..3623f711fe62 100644 --- a/hw/core/irq.c +++ b/hw/core/irq.c @@ -106,21 +106,6 @@ qemu_irq qemu_irq_invert(qemu_irq irq) return qemu_allocate_irq(qemu_notirq, irq, 0); } -static void qemu_splitirq(void *opaque, int line, int level) -{ - struct IRQState **irq = opaque; - irq[0]->handler(irq[0]->opaque, irq[0]->n, level); - irq[1]->handler(irq[1]->opaque, irq[1]->n, level); -} - -qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2) -{ - qemu_irq *s = g_new0(qemu_irq, 2); - s[0] = irq1; - s[1] = irq2; - return qemu_allocate_irq(qemu_splitirq, s, 0); -} - void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n) { int i; diff --git a/hw/core/loader.c b/hw/core/loader.c index ca2f2431fba7..0548830733e6 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -43,7 +43,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" @@ -115,17 +114,17 @@ ssize_t read_targphys(const char *name, return did; } -int load_image_targphys(const char *filename, - hwaddr addr, uint64_t max_sz) +ssize_t load_image_targphys(const char *filename, + hwaddr addr, uint64_t max_sz) { return load_image_targphys_as(filename, addr, max_sz, NULL); } /* return the size or -1 if error */ -int load_image_targphys_as(const char *filename, - hwaddr addr, uint64_t max_sz, AddressSpace *as) +ssize_t load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as) { - int size; + ssize_t size; size = get_image_size(filename); if (size < 0 || size > max_sz) { @@ -139,9 +138,9 @@ int load_image_targphys_as(const char *filename, return size; } -int load_image_mr(const char *filename, MemoryRegion *mr) +ssize_t load_image_mr(const char *filename, MemoryRegion *mr) { - int size; + ssize_t size; if (!memory_access_is_direct(mr, false)) { /* Can only load an image into RAM or ROM */ @@ -223,8 +222,8 @@ static void bswap_ahdr(struct exec *e) : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size))) -int load_aout(const char *filename, hwaddr addr, int max_sz, - int bswap_needed, hwaddr target_page_size) +ssize_t load_aout(const char *filename, hwaddr addr, int max_sz, + int bswap_needed, hwaddr target_page_size) { int fd; ssize_t size, ret; @@ -474,7 +473,7 @@ ssize_t load_elf_ram_sym(const char *filename, ret = ELF_LOAD_NOT_ELF; goto fail; } -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN data_order = ELFDATA2MSB; #else data_order = ELFDATA2LSB; @@ -511,7 +510,7 @@ ssize_t load_elf_ram_sym(const char *filename, static void bswap_uboot_header(uboot_image_header_t *hdr) { -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN bswap32s(&hdr->ih_magic); bswap32s(&hdr->ih_hcrc); bswap32s(&hdr->ih_time); @@ -618,13 +617,14 @@ ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen) } /* Load a U-Boot image. */ -static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, - int *is_linux, uint8_t image_type, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque, AddressSpace *as) +static ssize_t load_uboot_image(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint8_t image_type, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as) { int fd; - int size; + ssize_t size; hwaddr address; uboot_image_header_t h; uboot_image_header_t *hdr = &h; @@ -697,6 +697,21 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, if (is_linux) { if (hdr->ih_os == IH_OS_LINUX) { *is_linux = 1; + } else if (hdr->ih_os == IH_OS_VXWORKS) { + /* + * VxWorks 7 uses the same boot interface as the Linux kernel + * on Arm (64-bit only), PowerPC and RISC-V architectures. + */ + switch (hdr->ih_arch) { + case IH_ARCH_ARM64: + case IH_ARCH_PPC: + case IH_ARCH_RISCV: + *is_linux = 1; + break; + default: + *is_linux = 0; + break; + } } else { *is_linux = 0; } @@ -746,40 +761,40 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, return ret; } -int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, - int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque) +ssize_t load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, + int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque) { return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, translate_fn, translate_opaque, NULL); } -int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, - int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque, AddressSpace *as) +ssize_t load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, + int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as) { return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, translate_fn, translate_opaque, as); } /* Load a ramdisk. */ -int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) +ssize_t load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) { return load_ramdisk_as(filename, addr, max_sz, NULL); } -int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, - AddressSpace *as) +ssize_t load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, + AddressSpace *as) { return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK, NULL, NULL, as); } /* Load a gzip-compressed kernel to a dynamically allocated buffer. */ -int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, - uint8_t **buffer) +ssize_t load_image_gzipped_buffer(const char *filename, uint64_t max_sz, + uint8_t **buffer) { uint8_t *compressed_data = NULL; uint8_t *data = NULL; @@ -824,9 +839,9 @@ int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, } /* Load a gzip-compressed kernel. */ -int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz) +ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz) { - int bytes; + ssize_t bytes; uint8_t *data; bytes = load_image_gzipped_buffer(filename, max_sz, &data); @@ -956,14 +971,15 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name, bool ro) return data; } -int rom_add_file(const char *file, const char *fw_dir, - hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr, - AddressSpace *as) +ssize_t rom_add_file(const char *file, const char *fw_dir, + hwaddr addr, int32_t bootindex, + bool option_rom, MemoryRegion *mr, + AddressSpace *as) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); Rom *rom; - int rc, fd = -1; + ssize_t rc; + int fd = -1; char devpath[100]; if (as && mr) { @@ -1005,7 +1021,7 @@ int rom_add_file(const char *file, const char *fw_dir, lseek(fd, 0, SEEK_SET); rc = read(fd, rom->data, rom->datasize); if (rc != rom->datasize) { - fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", + fprintf(stderr, "rom: file %-20s: read error: rc=%zd (expected %zd)\n", rom->name, rc, rom->datasize); goto err; } @@ -1124,12 +1140,12 @@ int rom_add_elf_program(const char *name, GMappedFile *mapped_file, void *data, return 0; } -int rom_add_vga(const char *file) +ssize_t rom_add_vga(const char *file) { return rom_add_file(file, "vgaroms", 0, -1, true, NULL, NULL); } -int rom_add_option(const char *file, int32_t bootindex) +ssize_t rom_add_option(const char *file, int32_t bootindex) { return rom_add_file(file, "genroms", 0, bootindex, true, NULL, NULL); } @@ -1832,11 +1848,12 @@ static int parse_hex_blob(const char *filename, hwaddr *addr, uint8_t *hex_blob, } /* return size or -1 if error */ -int load_targphys_hex_as(const char *filename, hwaddr *entry, AddressSpace *as) +ssize_t load_targphys_hex_as(const char *filename, hwaddr *entry, + AddressSpace *as) { gsize hex_blob_size; gchar *hex_blob; - int total_size = 0; + ssize_t total_size = 0; if (!g_file_get_contents(filename, &hex_blob, &hex_blob_size, NULL)) { return -1; diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 4e2f319aebda..a1a51e97780d 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -62,7 +62,7 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) monitor_printf(mon, " type: \"%s\"\n", l->value->type); monitor_printf(mon, " vcpus_count: \"%" PRIu64 "\"\n", l->value->vcpus_count); - if (l->value->has_qom_path) { + if (l->value->qom_path) { monitor_printf(mon, " qom_path: \"%s\"\n", l->value->qom_path); } @@ -77,6 +77,10 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) if (c->has_die_id) { monitor_printf(mon, " die-id: \"%" PRIu64 "\"\n", c->die_id); } + if (c->has_cluster_id) { + monitor_printf(mon, " cluster-id: \"%" PRIu64 "\"\n", + c->cluster_id); + } if (c->has_core_id) { monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id); } diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 4f4ab30f8c3b..80d5e59651b5 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -55,8 +55,7 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp) value->qom_path = object_get_canonical_path(OBJECT(cpu)); value->thread_id = cpu->thread_id; - value->has_props = !!mc->cpu_index_to_instance_props; - if (value->has_props) { + if (mc->cpu_index_to_instance_props) { CpuInstanceProperties *props; props = g_malloc0(sizeof(*props)); *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index); @@ -90,7 +89,6 @@ MachineInfoList *qmp_query_machines(Error **errp) } if (mc->alias) { - info->has_alias = true; info->alias = g_strdup(mc->alias); } @@ -101,11 +99,9 @@ MachineInfoList *qmp_query_machines(Error **errp) info->deprecated = !!mc->deprecation_reason; if (mc->default_cpu_type) { info->default_cpu_type = g_strdup(mc->default_cpu_type); - info->has_default_cpu_type = true; } if (mc->default_ram_id) { info->default_ram_id = g_strdup(mc->default_ram_id); - info->has_default_ram_id = true; } QAPI_LIST_PREPEND(mach_list, info); @@ -168,7 +164,6 @@ static int query_memdev(Object *obj, void *opaque) m = g_malloc0(sizeof(*m)); m->id = g_strdup(object_get_canonical_path_component(obj)); - m->has_id = !!m->id; m->size = object_property_get_uint(obj, "size", &error_abort); m->merge = object_property_get_bool(obj, "merge", &error_abort); @@ -227,7 +222,7 @@ HumanReadableText *qmp_x_query_numa(Error **errp) for (i = 0; i < nb_numa_nodes; i++) { g_string_append_printf(buf, "node %d cpus:", i); for (cpu = cpu_list; cpu; cpu = cpu->next) { - if (cpu->value->has_props && cpu->value->props->has_node_id && + if (cpu->value->props && cpu->value->props->has_node_id && cpu->value->props->node_id == i) { g_string_append_printf(buf, " %" PRIi64, cpu->value->cpu_index); } diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c index b39ed21e6540..c3dab007dadc 100644 --- a/hw/core/machine-smp.c +++ b/hw/core/machine-smp.c @@ -158,6 +158,8 @@ void machine_parse_smp_config(MachineState *ms, ms->smp.threads = threads; ms->smp.max_cpus = maxcpus; + mc->smp_props.has_clusters = config->has_clusters; + /* sanity-check of the computed topology */ if (sockets * dies * clusters * cores * threads != maxcpus) { g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); diff --git a/hw/core/machine.c b/hw/core/machine.c index 1e23fdc14b67..616f3a207c4d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qemu/option.h" +#include "qemu/accel.h" #include "qapi/qmp/qerror.h" #include "sysemu/replay.h" #include "qemu/units.h" @@ -21,12 +22,14 @@ #include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-machine.h" #include "qapi/visitor.h" +#include "qom/object_interfaces.h" #include "hw/sysbus.h" #include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "sysemu/numa.h" +#include "sysemu/xen.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "hw/pci/pci.h" @@ -36,6 +39,21 @@ #include "exec/confidential-guest-support.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" +#include "qom/object_interfaces.h" + +GlobalProperty hw_compat_7_2[] = {}; +const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2); + +GlobalProperty hw_compat_7_1[] = { + { "virtio-device", "queue_reset", "false" }, +}; +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"}, +}; +const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0); GlobalProperty hw_compat_6_2[] = { { "PIIX4_PM", "x-not-migrate-acpi-index", "on"}, @@ -520,6 +538,77 @@ static void machine_set_hmat(Object *obj, bool value, Error **errp) ms->numa_state->hmat_enabled = value; } +static void machine_get_mem(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + MemorySizeConfiguration mem = { + .has_size = true, + .size = ms->ram_size, + .has_max_size = !!ms->ram_slots, + .max_size = ms->maxram_size, + .has_slots = !!ms->ram_slots, + .slots = ms->ram_slots, + }; + MemorySizeConfiguration *p_mem = &mem; + + visit_type_MemorySizeConfiguration(v, name, &p_mem, &error_abort); +} + +static void machine_set_mem(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ERRP_GUARD(); + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + MemorySizeConfiguration *mem; + + if (!visit_type_MemorySizeConfiguration(v, name, &mem, errp)) { + return; + } + + if (!mem->has_size) { + mem->has_size = true; + mem->size = mc->default_ram_size; + } + mem->size = QEMU_ALIGN_UP(mem->size, 8192); + if (mc->fixup_ram_size) { + mem->size = mc->fixup_ram_size(mem->size); + } + if ((ram_addr_t)mem->size != mem->size) { + error_setg(errp, "ram size too large"); + goto out_free; + } + + if (mem->has_max_size) { + if (mem->max_size < mem->size) { + error_setg(errp, "invalid value of maxmem: " + "maximum memory size (0x%" PRIx64 ") must be at least " + "the initial memory size (0x%" PRIx64 ")", + mem->max_size, mem->size); + goto out_free; + } + if (mem->has_slots && mem->slots && mem->max_size == mem->size) { + error_setg(errp, "invalid value of maxmem: " + "memory slots were specified but maximum memory size " + "(0x%" PRIx64 ") is equal to the initial memory size " + "(0x%" PRIx64 ")", mem->max_size, mem->size); + goto out_free; + } + ms->maxram_size = mem->max_size; + } else { + if (mem->has_slots) { + error_setg(errp, "slots specified but no max-size"); + goto out_free; + } + ms->maxram_size = mem->size; + } + ms->ram_size = mem->size; + ms->ram_slots = mem->has_slots ? mem->slots : 0; +out_free: + qapi_free_MemorySizeConfiguration(mem); +} + static char *machine_get_nvdimm_persistence(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -578,21 +667,6 @@ bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type) return allowed; } -static char *machine_get_memdev(Object *obj, Error **errp) -{ - MachineState *ms = MACHINE(obj); - - return g_strdup(ms->ram_memdev_id); -} - -static void machine_set_memdev(Object *obj, const char *value, Error **errp) -{ - MachineState *ms = MACHINE(obj); - - g_free(ms->ram_memdev_id); - ms->ram_memdev_id = g_strdup(value); -} - HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) { int i; @@ -613,7 +687,6 @@ HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) cpu = machine->possible_cpus->cpus[i].cpu; if (cpu) { - cpu_item->has_qom_path = true; cpu_item->qom_path = object_get_canonical_path(cpu); } QAPI_LIST_PREPEND(head, cpu_item); @@ -679,6 +752,11 @@ void machine_set_cpu_numa_node(MachineState *machine, return; } + if (props->has_cluster_id && !slot->props.has_cluster_id) { + error_setg(errp, "cluster-id is not supported"); + return; + } + if (props->has_socket_id && !slot->props.has_socket_id) { error_setg(errp, "socket-id is not supported"); return; @@ -698,6 +776,11 @@ void machine_set_cpu_numa_node(MachineState *machine, continue; } + if (props->has_cluster_id && + props->cluster_id != slot->props.cluster_id) { + continue; + } + if (props->has_die_id && props->die_id != slot->props.die_id) { continue; } @@ -771,6 +854,64 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, machine_parse_smp_config(ms, config, errp); } +static void machine_get_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + BootConfiguration *config = &ms->boot_config; + visit_type_BootConfiguration(v, name, &config, &error_abort); +} + +static void machine_free_boot_config(MachineState *ms) +{ + g_free(ms->boot_config.order); + g_free(ms->boot_config.once); + g_free(ms->boot_config.splash); +} + +static void machine_copy_boot_config(MachineState *ms, BootConfiguration *config) +{ + MachineClass *machine_class = MACHINE_GET_CLASS(ms); + + machine_free_boot_config(ms); + ms->boot_config = *config; + if (!config->order) { + ms->boot_config.order = g_strdup(machine_class->default_boot_order); + } +} + +static void machine_set_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ERRP_GUARD(); + MachineState *ms = MACHINE(obj); + BootConfiguration *config = NULL; + + if (!visit_type_BootConfiguration(v, name, &config, errp)) { + return; + } + if (config->order) { + validate_bootdevices(config->order, errp); + if (*errp) { + goto out_free; + } + } + if (config->once) { + validate_bootdevices(config->once, errp); + if (*errp) { + goto out_free; + } + } + + machine_copy_boot_config(ms, config); + /* Strings live in ms->boot_config. */ + free(config); + return; + +out_free: + qapi_free_BootConfiguration(config); +} + static void machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -809,6 +950,12 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "dumpdtb", "Dump current dtb to a file and quit"); + object_class_property_add(oc, "boot", "BootConfiguration", + machine_get_boot, machine_set_boot, + NULL, NULL); + object_class_property_set_description(oc, "boot", + "Boot configuration"); + object_class_property_add(oc, "smp", "SMPConfiguration", machine_get_smp, machine_set_smp, NULL, NULL); @@ -870,11 +1017,18 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "memory-encryption", "Set memory encryption object to use"); - object_class_property_add_str(oc, "memory-backend", - machine_get_memdev, machine_set_memdev); + object_class_property_add_link(oc, "memory-backend", TYPE_MEMORY_BACKEND, + offsetof(MachineState, memdev), object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); object_class_property_set_description(oc, "memory-backend", "Set RAM backend" "Valid value is ID of hostmem based backend"); + + object_class_property_add(oc, "memory", "MemorySizeConfiguration", + machine_get_mem, machine_set_mem, + NULL, NULL); + object_class_property_set_description(oc, "memory", + "Memory size configuration"); } static void machine_class_base_init(ObjectClass *oc, void *data) @@ -905,6 +1059,8 @@ static void machine_initfn(Object *obj) ms->mem_merge = true; ms->enable_graphics = true; ms->kernel_cmdline = g_strdup(""); + ms->ram_size = mc->default_ram_size; + ms->maxram_size = mc->default_ram_size; if (mc->nvdimm_supported) { Object *obj = OBJECT(ms); @@ -942,12 +1098,15 @@ static void machine_initfn(Object *obj) ms->smp.clusters = 1; ms->smp.cores = 1; ms->smp.threads = 1; + + machine_copy_boot_config(ms, &(BootConfiguration){ 0 }); } static void machine_finalize(Object *obj) { MachineState *ms = MACHINE(obj); + machine_free_boot_config(ms); g_free(ms->kernel_filename); g_free(ms->initrd_filename); g_free(ms->kernel_cmdline); @@ -992,6 +1151,12 @@ static char *cpu_slot_to_string(const CPUArchId *cpu) } g_string_append_printf(s, "die-id: %"PRId64, cpu->props.die_id); } + if (cpu->props.has_cluster_id) { + if (s->len) { + g_string_append_printf(s, ", "); + } + g_string_append_printf(s, "cluster-id: %"PRId64, cpu->props.cluster_id); + } if (cpu->props.has_core_id) { if (s->len) { g_string_append_printf(s, ", "); @@ -1014,9 +1179,7 @@ static void numa_validate_initiator(NumaState *numa_state) for (i = 0; i < numa_state->num_nodes; i++) { if (numa_info[i].initiator == MAX_NODES) { - error_report("The initiator of NUMA node %d is missing, use " - "'-numa node,initiator' option to declare it", i); - exit(1); + continue; } if (!numa_info[numa_info[i].initiator].present) { @@ -1103,7 +1266,40 @@ MemoryRegion *machine_consume_memdev(MachineState *machine, return ret; } -void machine_run_board_init(MachineState *machine) +static bool create_default_memdev(MachineState *ms, const char *path, Error **errp) +{ + Object *obj; + MachineClass *mc = MACHINE_GET_CLASS(ms); + bool r = false; + + obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); + if (path) { + if (!object_property_set_str(obj, "mem-path", path, errp)) { + goto out; + } + } + if (!object_property_set_int(obj, "size", ms->ram_size, errp)) { + goto out; + } + object_property_add_child(object_get_objects_root(), mc->default_ram_id, + obj); + /* Ensure backend's memory region name is equal to mc->default_ram_id */ + if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", + false, errp)) { + goto out; + } + if (!user_creatable_complete(USER_CREATABLE(obj), errp)) { + goto out; + } + r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp); + +out: + object_unref(obj); + return r; +} + + +void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp) { MachineClass *machine_class = MACHINE_GET_CLASS(machine); ObjectClass *oc = object_class_by_name(machine->cpu_type); @@ -1114,11 +1310,26 @@ void machine_run_board_init(MachineState *machine) clock values from the log. */ replay_checkpoint(CHECKPOINT_INIT); - if (machine->ram_memdev_id) { - Object *o; - o = object_resolve_path_type(machine->ram_memdev_id, - TYPE_MEMORY_BACKEND, NULL); - machine->ram = machine_consume_memdev(machine, MEMORY_BACKEND(o)); + if (!xen_enabled()) { + /* On 32-bit hosts, QEMU is limited by virtual address space */ + if (machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { + error_setg(errp, "at most 2047 MB RAM can be simulated"); + return; + } + } + + if (machine->memdev) { + ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev), + "size", &error_abort); + if (backend_size != machine->ram_size) { + error_setg(errp, "Machine memory size does not match the size of the memory backend"); + return; + } + } else if (machine_class->default_ram_id && machine->ram_size && + numa_uses_legacy_mem()) { + if (!create_default_memdev(current_machine, mem_path, errp)) { + return; + } } if (machine->numa_state) { @@ -1128,6 +1339,10 @@ void machine_run_board_init(MachineState *machine) } } + if (!machine->ram && machine->memdev) { + machine->ram = machine_consume_memdev(machine, machine->memdev); + } + /* If the machine supports the valid_cpu_types check and the user * specified a CPU with -cpu check here that the user CPU is supported. */ @@ -1210,9 +1425,9 @@ void qdev_machine_creation_done(void) { cpu_synchronize_all_post_init(); - if (current_machine->boot_once) { - qemu_boot_set(current_machine->boot_once, &error_fatal); - qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order)); + if (current_machine->boot_config.once) { + qemu_boot_set(current_machine->boot_config.once, &error_fatal); + qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_config.order)); } /* diff --git a/hw/core/meson.build b/hw/core/meson.build index 0f884d6fd4d2..7a4d02b6c050 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -33,6 +33,7 @@ softmmu_ss.add(when: 'CONFIG_PTIMER', if_true: files('ptimer.c')) softmmu_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c')) softmmu_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) softmmu_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) +softmmu_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c')) softmmu_ss.add(files( 'cpu-sysemu.c', diff --git a/hw/core/numa.c b/hw/core/numa.c index 1aa05dcf425f..d8d36b16d80b 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -130,9 +130,9 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, } } - have_memdevs = have_memdevs ? : node->has_memdev; - have_mem = have_mem ? : node->has_mem; - if ((node->has_mem && have_memdevs) || (node->has_memdev && have_mem)) { + have_memdevs = have_memdevs || node->memdev; + have_mem = have_mem || node->has_mem; + if ((node->has_mem && have_memdevs) || (node->memdev && have_mem)) { error_setg(errp, "numa configuration should use either mem= or memdev=," "mixing both is not allowed"); return; @@ -152,7 +152,7 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, " use -numa node,memdev instead"); } } - if (node->has_memdev) { + if (node->memdev) { Object *o; o = object_resolve_path_type(node->memdev, TYPE_MEMORY_BACKEND, NULL); if (!o) { @@ -695,7 +695,7 @@ void numa_complete_configuration(MachineState *ms) } if (!numa_uses_legacy_mem() && mc->default_ram_id) { - if (ms->ram_memdev_id) { + if (ms->memdev) { error_report("'-machine memory-backend' and '-numa memdev'" " properties are mutually exclusive"); exit(1); @@ -822,6 +822,19 @@ static int ram_block_notify_add_single(RAMBlock *rb, void *opaque) return 0; } +static int ram_block_notify_remove_single(RAMBlock *rb, void *opaque) +{ + const ram_addr_t max_size = qemu_ram_get_max_length(rb); + const ram_addr_t size = qemu_ram_get_used_length(rb); + void *host = qemu_ram_get_host_addr(rb); + RAMBlockNotifier *notifier = opaque; + + if (host) { + notifier->ram_block_removed(notifier, host, size, max_size); + } + return 0; +} + void ram_block_notifier_add(RAMBlockNotifier *n) { QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next); @@ -835,13 +848,18 @@ void ram_block_notifier_add(RAMBlockNotifier *n) void ram_block_notifier_remove(RAMBlockNotifier *n) { QLIST_REMOVE(n, next); + + if (n->ram_block_removed) { + qemu_ram_foreach_block(ram_block_notify_remove_single, n); + } } void ram_block_notify_add(void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; + RAMBlockNotifier *next; - QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { + QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next) { if (notifier->ram_block_added) { notifier->ram_block_added(notifier, host, size, max_size); } @@ -851,8 +869,9 @@ void ram_block_notify_add(void *host, size_t size, size_t max_size) void ram_block_notify_remove(void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; + RAMBlockNotifier *next; - QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { + QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next) { if (notifier->ram_block_removed) { notifier->ram_block_removed(notifier, host, size, max_size); } @@ -862,8 +881,9 @@ void ram_block_notify_remove(void *host, size_t size, size_t max_size) void ram_block_notify_resize(void *host, size_t old_size, size_t new_size) { RAMBlockNotifier *notifier; + RAMBlockNotifier *next; - QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { + QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next) { if (notifier->ram_block_resized) { notifier->ram_block_resized(notifier, host, old_size, new_size); } diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index 117f4c6ea4a2..82799577f3e9 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -134,7 +134,7 @@ void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks) Clock **clkp; /* offset cannot be inside the DeviceState part */ assert(elem->offset > sizeof(DeviceState)); - clkp = (Clock **)(((void *) dev) + elem->offset); + clkp = ((void *)dev) + elem->offset; if (elem->is_output) { *clkp = qdev_init_clock_out(dev, elem->name); } else { diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index a91f60567aa5..54a09fa9acc1 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -32,6 +32,7 @@ #include "sysemu/blockdev.h" #include "net/net.h" #include "hw/pci/pci.h" +#include "hw/pci/pcie.h" #include "util/block-helpers.h" static bool check_prop_still_unset(Object *obj, const char *name, @@ -679,14 +680,11 @@ static void set_reserved_region(Object *obj, Visitor *v, const char *name, { Property *prop = opaque; ReservedRegion *rr = object_field_prop_ptr(obj, prop); - Error *local_err = NULL; const char *endptr; char *str; int ret; - visit_type_str(v, name, &str, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index c34aac6ebc91..357b8761b546 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -428,6 +428,25 @@ const PropertyInfo qdev_prop_int64 = { .set_default_value = qdev_propinfo_set_default_value_int, }; +static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + Property *prop = opaque; + uint64_t *ptr = object_field_prop_ptr(obj, prop); + + visit_type_uint64(v, name, ptr, errp); + if (*ptr & ~prop->bitmask) { + error_setg(errp, "Property value for '%s' has bits outside mask '0x%" PRIx64 "'", + name, prop->bitmask); + } +} + +const PropertyInfo qdev_prop_uint64_checkmask = { + .name = "uint64", + .get = get_uint64, + .set = set_uint64_checkmask, +}; + /* --- string --- */ static void release_string(Object *obj, const char *name, void *opaque) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 84f3019440fc..d759c4602c25 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -147,8 +147,21 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp) DeviceState *qdev_new(const char *name) { - if (!object_class_by_name(name)) { - module_load_qom_one(name); + ObjectClass *oc = object_class_by_name(name); +#ifdef CONFIG_MODULES + if (!oc) { + int rv = module_load_qom(name, &error_fatal); + if (rv > 0) { + oc = object_class_by_name(name); + } else { + error_report("could not find a module for type '%s'", name); + exit(1); + } + } +#endif + if (!oc) { + error_report("unknown type '%s'", name); + abort(); } return DEVICE(object_new(name)); } @@ -237,60 +250,6 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, dev->alias_required_for_version = required_for_version; } -static int qdev_prereset(DeviceState *dev, void *opaque) -{ - trace_qdev_reset_tree(dev, object_get_typename(OBJECT(dev))); - return 0; -} - -static int qbus_prereset(BusState *bus, void *opaque) -{ - trace_qbus_reset_tree(bus, object_get_typename(OBJECT(bus))); - return 0; -} - -static int qdev_reset_one(DeviceState *dev, void *opaque) -{ - device_legacy_reset(dev); - - return 0; -} - -static int qbus_reset_one(BusState *bus, void *opaque) -{ - BusClass *bc = BUS_GET_CLASS(bus); - trace_qbus_reset(bus, object_get_typename(OBJECT(bus))); - if (bc->reset) { - bc->reset(bus); - } - return 0; -} - -void qdev_reset_all(DeviceState *dev) -{ - trace_qdev_reset_all(dev, object_get_typename(OBJECT(dev))); - qdev_walk_children(dev, qdev_prereset, qbus_prereset, - qdev_reset_one, qbus_reset_one, NULL); -} - -void qdev_reset_all_fn(void *opaque) -{ - qdev_reset_all(DEVICE(opaque)); -} - -void qbus_reset_all(BusState *bus) -{ - trace_qbus_reset_all(bus, object_get_typename(OBJECT(bus))); - qbus_walk_children(bus, qdev_prereset, qbus_prereset, - qdev_reset_one, qbus_reset_one, NULL); -} - -void qbus_reset_all_fn(void *opaque) -{ - BusState *bus = opaque; - qbus_reset_all(bus); -} - void device_cold_reset(DeviceState *dev) { resettable_reset(OBJECT(dev), RESET_TYPE_COLD); @@ -468,6 +427,26 @@ char *qdev_get_dev_path(DeviceState *dev) return NULL; } +void qdev_add_unplug_blocker(DeviceState *dev, Error *reason) +{ + dev->unplug_blockers = g_slist_prepend(dev->unplug_blockers, reason); +} + +void qdev_del_unplug_blocker(DeviceState *dev, Error *reason) +{ + dev->unplug_blockers = g_slist_remove(dev->unplug_blockers, reason); +} + +bool qdev_unplug_blocked(DeviceState *dev, Error **errp) +{ + if (dev->unplug_blockers) { + error_propagate(errp, error_copy(dev->unplug_blockers->data)); + return true; + } + + return false; +} + static bool device_get_realized(Object *obj, Error **errp) { DeviceState *dev = DEVICE(obj); @@ -704,6 +683,8 @@ static void device_finalize(Object *obj) DeviceState *dev = DEVICE(obj); + g_assert(!dev->unplug_blockers); + QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { QLIST_REMOVE(ngl, node); qemu_free_irqs(ngl->in, ngl->num_in); @@ -720,7 +701,7 @@ static void device_finalize(Object *obj) if (dev->pending_deleted_event) { g_assert(dev->canonical_path); - qapi_event_send_device_deleted(!!dev->id, dev->id, dev->canonical_path); + qapi_event_send_device_deleted(dev->id, dev->canonical_path); g_free(dev->canonical_path); dev->canonical_path = NULL; } @@ -887,16 +868,6 @@ void device_class_set_parent_unrealize(DeviceClass *dc, dc->unrealize = dev_unrealize; } -void device_legacy_reset(DeviceState *dev) -{ - DeviceClass *klass = DEVICE_GET_CLASS(dev); - - trace_qdev_reset(dev, object_get_typename(OBJECT(dev))); - if (klass->reset) { - klass->reset(dev); - } -} - Object *qdev_get_machine(void) { static Object *dev; diff --git a/hw/core/reset.c b/hw/core/reset.c index 36be82c491ab..d3263b613e66 100644 --- a/hw/core/reset.c +++ b/hw/core/reset.c @@ -33,6 +33,7 @@ typedef struct QEMUResetEntry { QTAILQ_ENTRY(QEMUResetEntry) entry; QEMUResetHandler *func; void *opaque; + bool skip_on_snapshot_load; } QEMUResetEntry; static QTAILQ_HEAD(, QEMUResetEntry) reset_handlers = @@ -47,6 +48,16 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque) QTAILQ_INSERT_TAIL(&reset_handlers, re, entry); } +void qemu_register_reset_nosnapshotload(QEMUResetHandler *func, void *opaque) +{ + QEMUResetEntry *re = g_new0(QEMUResetEntry, 1); + + re->func = func; + re->opaque = opaque; + re->skip_on_snapshot_load = true; + QTAILQ_INSERT_TAIL(&reset_handlers, re, entry); +} + void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) { QEMUResetEntry *re; @@ -60,12 +71,16 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) } } -void qemu_devices_reset(void) +void qemu_devices_reset(ShutdownCause reason) { QEMUResetEntry *re, *nre; /* reset all devices */ QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) { + if (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD && + re->skip_on_snapshot_load) { + continue; + } re->func(re->opaque); } } diff --git a/hw/core/resettable.c b/hw/core/resettable.c index 96a99ce39ea3..c3df75c6ba85 100644 --- a/hw/core/resettable.c +++ b/hw/core/resettable.c @@ -201,12 +201,11 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type) resettable_child_foreach(rc, obj, resettable_phase_exit, NULL, type); assert(s->count > 0); - if (s->count == 1) { + if (--s->count == 0) { trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit); if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) { rc->phases.exit(obj); } - s->count = 0; } s->exit_phase_in_progress = false; trace_resettable_phase_exit_end(obj, obj_typename, s->count); diff --git a/hw/arm/sysbus-fdt.c b/hw/core/sysbus-fdt.c similarity index 98% rename from hw/arm/sysbus-fdt.c rename to hw/core/sysbus-fdt.c index 48c5fe9bf18b..eebcd28f9a37 100644 --- a/hw/arm/sysbus-fdt.c +++ b/hw/core/sysbus-fdt.c @@ -27,7 +27,7 @@ #ifdef CONFIG_LINUX #include #endif -#include "hw/arm/sysbus-fdt.h" +#include "hw/core/sysbus-fdt.h" #include "qemu/error-report.h" #include "sysemu/device_tree.h" #include "sysemu/tpm.h" @@ -299,7 +299,8 @@ static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque) void *guest_fdt = data->fdt, *host_fdt; const void *r; int i, prop_len; - uint32_t *irq_attr, *reg_attr, *host_clock_phandles; + uint32_t *irq_attr, *reg_attr; + const uint32_t *host_clock_phandles; uint64_t mmio_base, irq_number; uint32_t guest_clock_phandles[2]; @@ -339,7 +340,7 @@ static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque) error_report("%s clocks property should contain 2 handles", __func__); exit(1); } - host_clock_phandles = (uint32_t *)r; + host_clock_phandles = r; guest_clock_phandles[0] = qemu_fdt_alloc_phandle(guest_fdt); guest_clock_phandles[1] = qemu_fdt_alloc_phandle(guest_fdt); @@ -539,7 +540,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/core/trace-events b/hw/core/trace-events index 9b3ecce3b2fd..56da55bd71d0 100644 --- a/hw/core/trace-events +++ b/hw/core/trace-events @@ -2,12 +2,6 @@ loader_write_rom(const char *name, uint64_t gpa, uint64_t size, bool isrom) "%s: @0x%"PRIx64" size=0x%"PRIx64" ROM=%d" # qdev.c -qdev_reset(void *obj, const char *objtype) "obj=%p(%s)" -qdev_reset_all(void *obj, const char *objtype) "obj=%p(%s)" -qdev_reset_tree(void *obj, const char *objtype) "obj=%p(%s)" -qbus_reset(void *obj, const char *objtype) "obj=%p(%s)" -qbus_reset_all(void *obj, const char *objtype) "obj=%p(%s)" -qbus_reset_tree(void *obj, const char *objtype) "obj=%p(%s)" qdev_update_parent_bus(void *obj, const char *objtype, void *oldp, const char *oldptype, void *newp, const char *newptype) "obj=%p(%s) old_parent=%p(%s) new_parent=%p(%s)" # resettable.c diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h index 608022de6ece..18ac293359db 100644 --- a/hw/core/uboot_image.h +++ b/hw/core/uboot_image.h @@ -1,23 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* + * (C) Copyright 2008 Semihalf + * * (C) Copyright 2000-2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 . - * ******************************************************************** * NOTE: This header file defines an interface to U-Boot. Including * this (unmodified) header file in another file is considered normal @@ -31,50 +17,83 @@ /* * Operating System Codes + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_OS_INVALID 0 /* Invalid OS */ -#define IH_OS_OPENBSD 1 /* OpenBSD */ -#define IH_OS_NETBSD 2 /* NetBSD */ -#define IH_OS_FREEBSD 3 /* FreeBSD */ -#define IH_OS_4_4BSD 4 /* 4.4BSD */ -#define IH_OS_LINUX 5 /* Linux */ -#define IH_OS_SVR4 6 /* SVR4 */ -#define IH_OS_ESIX 7 /* Esix */ -#define IH_OS_SOLARIS 8 /* Solaris */ -#define IH_OS_IRIX 9 /* Irix */ -#define IH_OS_SCO 10 /* SCO */ -#define IH_OS_DELL 11 /* Dell */ -#define IH_OS_NCR 12 /* NCR */ -#define IH_OS_LYNXOS 13 /* LynxOS */ -#define IH_OS_VXWORKS 14 /* VxWorks */ -#define IH_OS_PSOS 15 /* pSOS */ -#define IH_OS_QNX 16 /* QNX */ -#define IH_OS_U_BOOT 17 /* Firmware */ -#define IH_OS_RTEMS 18 /* RTEMS */ -#define IH_OS_ARTOS 19 /* ARTOS */ -#define IH_OS_UNITY 20 /* Unity OS */ +enum { + IH_OS_INVALID = 0, /* Invalid OS */ + IH_OS_OPENBSD, /* OpenBSD */ + IH_OS_NETBSD, /* NetBSD */ + IH_OS_FREEBSD, /* FreeBSD */ + IH_OS_4_4BSD, /* 4.4BSD */ + IH_OS_LINUX, /* Linux */ + IH_OS_SVR4, /* SVR4 */ + IH_OS_ESIX, /* Esix */ + IH_OS_SOLARIS, /* Solaris */ + IH_OS_IRIX, /* Irix */ + IH_OS_SCO, /* SCO */ + IH_OS_DELL, /* Dell */ + IH_OS_NCR, /* NCR */ + IH_OS_LYNXOS, /* LynxOS */ + IH_OS_VXWORKS, /* VxWorks */ + IH_OS_PSOS, /* pSOS */ + IH_OS_QNX, /* QNX */ + IH_OS_U_BOOT, /* Firmware */ + IH_OS_RTEMS, /* RTEMS */ + IH_OS_ARTOS, /* ARTOS */ + IH_OS_UNITY, /* Unity OS */ + IH_OS_INTEGRITY, /* INTEGRITY */ + IH_OS_OSE, /* OSE */ + IH_OS_PLAN9, /* Plan 9 */ + IH_OS_OPENRTOS, /* OpenRTOS */ + IH_OS_ARM_TRUSTED_FIRMWARE, /* ARM Trusted Firmware */ + IH_OS_TEE, /* Trusted Execution Environment */ + IH_OS_OPENSBI, /* RISC-V OpenSBI */ + IH_OS_EFI, /* EFI Firmware (e.g. GRUB2) */ + + IH_OS_COUNT, +}; /* * CPU Architecture Codes (supported by Linux) + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_CPU_INVALID 0 /* Invalid CPU */ -#define IH_CPU_ALPHA 1 /* Alpha */ -#define IH_CPU_ARM 2 /* ARM */ -#define IH_CPU_I386 3 /* Intel x86 */ -#define IH_CPU_IA64 4 /* IA64 */ -#define IH_CPU_MIPS 5 /* MIPS */ -#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */ -#define IH_CPU_PPC 7 /* PowerPC */ -#define IH_CPU_S390 8 /* IBM S390 */ -#define IH_CPU_SH 9 /* SuperH */ -#define IH_CPU_SPARC 10 /* Sparc */ -#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */ -#define IH_CPU_M68K 12 /* M68K */ -#define IH_CPU_NIOS 13 /* Nios-32 */ -#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */ -#define IH_CPU_NIOS2 15 /* Nios-II */ -#define IH_CPU_BLACKFIN 16 /* Blackfin */ -#define IH_CPU_AVR32 17 /* AVR32 */ +enum { + IH_ARCH_INVALID = 0, /* Invalid CPU */ + IH_ARCH_ALPHA, /* Alpha */ + IH_ARCH_ARM, /* ARM */ + IH_ARCH_I386, /* Intel x86 */ + IH_ARCH_IA64, /* IA64 */ + IH_ARCH_MIPS, /* MIPS */ + IH_ARCH_MIPS64, /* MIPS 64 Bit */ + IH_ARCH_PPC, /* PowerPC */ + IH_ARCH_S390, /* IBM S390 */ + IH_ARCH_SH, /* SuperH */ + IH_ARCH_SPARC, /* Sparc */ + IH_ARCH_SPARC64, /* Sparc 64 Bit */ + IH_ARCH_M68K, /* M68K */ + IH_ARCH_NIOS, /* Nios-32 */ + IH_ARCH_MICROBLAZE, /* MicroBlaze */ + IH_ARCH_NIOS2, /* Nios-II */ + IH_ARCH_BLACKFIN, /* Blackfin */ + IH_ARCH_AVR32, /* AVR32 */ + IH_ARCH_ST200, /* STMicroelectronics ST200 */ + IH_ARCH_SANDBOX, /* Sandbox architecture (test only) */ + IH_ARCH_NDS32, /* ANDES Technology - NDS32 */ + IH_ARCH_OPENRISC, /* OpenRISC 1000 */ + IH_ARCH_ARM64, /* ARM64 */ + IH_ARCH_ARC, /* Synopsys DesignWare ARC */ + IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */ + IH_ARCH_XTENSA, /* Xtensa */ + IH_ARCH_RISCV, /* RISC-V */ + + IH_ARCH_COUNT, +}; /* * Image Types @@ -113,33 +132,85 @@ * U-Boot's command interpreter; this feature is especially * useful when you configure U-Boot to use a real shell (hush) * as command interpreter (=> Shell Scripts). + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_TYPE_INVALID 0 /* Invalid Image */ -#define IH_TYPE_STANDALONE 1 /* Standalone Program */ -#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ -#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ -#define IH_TYPE_MULTI 4 /* Multi-File Image */ -#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ -#define IH_TYPE_SCRIPT 6 /* Script file */ -#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ -#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ -#define IH_TYPE_KERNEL_NOLOAD 14 /* OS Kernel Image (noload) */ +enum { + IH_TYPE_INVALID = 0, /* Invalid Image */ + IH_TYPE_STANDALONE, /* Standalone Program */ + IH_TYPE_KERNEL, /* OS Kernel Image */ + IH_TYPE_RAMDISK, /* RAMDisk Image */ + IH_TYPE_MULTI, /* Multi-File Image */ + IH_TYPE_FIRMWARE, /* Firmware Image */ + IH_TYPE_SCRIPT, /* Script file */ + IH_TYPE_FILESYSTEM, /* Filesystem Image (any type) */ + IH_TYPE_FLATDT, /* Binary Flat Device Tree Blob */ + IH_TYPE_KWBIMAGE, /* Kirkwood Boot Image */ + IH_TYPE_IMXIMAGE, /* Freescale IMXBoot Image */ + IH_TYPE_UBLIMAGE, /* Davinci UBL Image */ + IH_TYPE_OMAPIMAGE, /* TI OMAP Config Header Image */ + IH_TYPE_AISIMAGE, /* TI Davinci AIS Image */ + /* OS Kernel Image, can run from any load address */ + IH_TYPE_KERNEL_NOLOAD, + IH_TYPE_PBLIMAGE, /* Freescale PBL Boot Image */ + IH_TYPE_MXSIMAGE, /* Freescale MXSBoot Image */ + IH_TYPE_GPIMAGE, /* TI Keystone GPHeader Image */ + IH_TYPE_ATMELIMAGE, /* ATMEL ROM bootable Image */ + IH_TYPE_SOCFPGAIMAGE, /* Altera SOCFPGA CV/AV Preloader */ + IH_TYPE_X86_SETUP, /* x86 setup.bin Image */ + IH_TYPE_LPC32XXIMAGE, /* x86 setup.bin Image */ + IH_TYPE_LOADABLE, /* A list of typeless images */ + IH_TYPE_RKIMAGE, /* Rockchip Boot Image */ + IH_TYPE_RKSD, /* Rockchip SD card */ + IH_TYPE_RKSPI, /* Rockchip SPI image */ + IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ + IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ + IH_TYPE_ZYNQMPBIF, /* Xilinx ZynqMP Boot Image (bif) */ + IH_TYPE_FPGA, /* FPGA Image */ + IH_TYPE_VYBRIDIMAGE, /* VYBRID .vyb Image */ + IH_TYPE_TEE, /* Trusted Execution Environment OS Image */ + IH_TYPE_FIRMWARE_IVT, /* Firmware Image with HABv4 IVT */ + IH_TYPE_PMMC, /* TI Power Management Micro-Controller Firmware */ + IH_TYPE_STM32IMAGE, /* STMicroelectronics STM32 Image */ + IH_TYPE_SOCFPGAIMAGE_V1, /* Altera SOCFPGA A10 Preloader */ + IH_TYPE_MTKIMAGE, /* MediaTek BootROM loadable Image */ + IH_TYPE_IMX8MIMAGE, /* Freescale IMX8MBoot Image */ + IH_TYPE_IMX8IMAGE, /* Freescale IMX8Boot Image */ + IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/ + IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */ + + IH_TYPE_COUNT, /* Number of image types */ +}; /* * Compression Types + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_COMP_NONE 0 /* No Compression Used */ -#define IH_COMP_GZIP 1 /* gzip Compression Used */ -#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ +enum { + IH_COMP_NONE = 0, /* No Compression Used */ + IH_COMP_GZIP, /* gzip Compression Used */ + IH_COMP_BZIP2, /* bzip2 Compression Used */ + IH_COMP_LZMA, /* lzma Compression Used */ + IH_COMP_LZO, /* lzo Compression Used */ + IH_COMP_LZ4, /* lz4 Compression Used */ + IH_COMP_ZSTD, /* zstd Compression Used */ + + IH_COMP_COUNT, +}; #define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ /* - * all data in network byte order (aka natural aka bigendian) + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). */ - typedef struct uboot_image_header { uint32_t ih_magic; /* Image Header Magic Number */ uint32_t ih_hcrc; /* Image Header CRC Checksum */ diff --git a/hw/cxl/Kconfig b/hw/cxl/Kconfig new file mode 100644 index 000000000000..8e67519b1610 --- /dev/null +++ b/hw/cxl/Kconfig @@ -0,0 +1,3 @@ +config CXL + bool + default y if PCI_EXPRESS diff --git a/hw/cxl/cxl-cdat.c b/hw/cxl/cxl-cdat.c new file mode 100644 index 000000000000..3653aa56f0d4 --- /dev/null +++ b/hw/cxl/cxl-cdat.c @@ -0,0 +1,224 @@ +/* + * CXL CDAT Structure + * + * Copyright (C) 2021 Avery Design Systems, 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 "hw/pci/pci.h" +#include "hw/cxl/cxl.h" +#include "qapi/error.h" +#include "qemu/error-report.h" + +static void cdat_len_check(CDATSubHeader *hdr, Error **errp) +{ + assert(hdr->length); + assert(hdr->reserved == 0); + + switch (hdr->type) { + case CDAT_TYPE_DSMAS: + assert(hdr->length == sizeof(CDATDsmas)); + break; + case CDAT_TYPE_DSLBIS: + assert(hdr->length == sizeof(CDATDslbis)); + break; + case CDAT_TYPE_DSMSCIS: + assert(hdr->length == sizeof(CDATDsmscis)); + break; + case CDAT_TYPE_DSIS: + assert(hdr->length == sizeof(CDATDsis)); + break; + case CDAT_TYPE_DSEMTS: + assert(hdr->length == sizeof(CDATDsemts)); + break; + case CDAT_TYPE_SSLBIS: + assert(hdr->length >= sizeof(CDATSslbisHeader)); + assert((hdr->length - sizeof(CDATSslbisHeader)) % + sizeof(CDATSslbe) == 0); + break; + default: + error_setg(errp, "Type %d is reserved", hdr->type); + } +} + +static void ct3_build_cdat(CDATObject *cdat, Error **errp) +{ + g_autofree CDATTableHeader *cdat_header = NULL; + g_autofree CDATEntry *cdat_st = NULL; + uint8_t sum = 0; + int ent, i; + + /* Use default table if fopen == NULL */ + assert(cdat->build_cdat_table); + + cdat_header = g_malloc0(sizeof(*cdat_header)); + if (!cdat_header) { + error_setg(errp, "Failed to allocate CDAT header"); + return; + } + + cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf, cdat->private); + + if (!cdat->built_buf_len) { + /* Build later as not all data available yet */ + cdat->to_update = true; + return; + } + cdat->to_update = false; + + cdat_st = g_malloc0(sizeof(*cdat_st) * (cdat->built_buf_len + 1)); + if (!cdat_st) { + error_setg(errp, "Failed to allocate CDAT entry array"); + return; + } + + /* Entry 0 for CDAT header, starts with Entry 1 */ + for (ent = 1; ent < cdat->built_buf_len + 1; ent++) { + CDATSubHeader *hdr = cdat->built_buf[ent - 1]; + uint8_t *buf = (uint8_t *)cdat->built_buf[ent - 1]; + + cdat_st[ent].base = hdr; + cdat_st[ent].length = hdr->length; + + cdat_header->length += hdr->length; + for (i = 0; i < hdr->length; i++) { + sum += buf[i]; + } + } + + /* CDAT header */ + cdat_header->revision = CXL_CDAT_REV; + /* For now, no runtime updates */ + cdat_header->sequence = 0; + cdat_header->length += sizeof(CDATTableHeader); + sum += cdat_header->revision + cdat_header->sequence + + cdat_header->length; + /* Sum of all bytes including checksum must be 0 */ + cdat_header->checksum = ~sum + 1; + + cdat_st[0].base = g_steal_pointer(&cdat_header); + cdat_st[0].length = sizeof(*cdat_header); + cdat->entry_len = 1 + cdat->built_buf_len; + cdat->entry = g_steal_pointer(&cdat_st); +} + +static void ct3_load_cdat(CDATObject *cdat, Error **errp) +{ + g_autofree CDATEntry *cdat_st = NULL; + uint8_t sum = 0; + int num_ent; + int i = 0, ent = 1, file_size = 0; + CDATSubHeader *hdr; + FILE *fp = NULL; + + /* Read CDAT file and create its cache */ + fp = fopen(cdat->filename, "r"); + if (!fp) { + error_setg(errp, "CDAT: Unable to open file"); + return; + } + + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + cdat->buf = g_malloc0(file_size); + + if (fread(cdat->buf, file_size, 1, fp) == 0) { + error_setg(errp, "CDAT: File read failed"); + return; + } + + fclose(fp); + + if (file_size < sizeof(CDATTableHeader)) { + error_setg(errp, "CDAT: File too short"); + return; + } + i = sizeof(CDATTableHeader); + num_ent = 1; + while (i < file_size) { + hdr = (CDATSubHeader *)(cdat->buf + i); + cdat_len_check(hdr, errp); + i += hdr->length; + num_ent++; + } + if (i != file_size) { + error_setg(errp, "CDAT: File length missmatch"); + return; + } + + cdat_st = g_malloc0(sizeof(*cdat_st) * num_ent); + if (!cdat_st) { + error_setg(errp, "CDAT: Failed to allocate entry array"); + return; + } + + /* Set CDAT header, Entry = 0 */ + cdat_st[0].base = cdat->buf; + cdat_st[0].length = sizeof(CDATTableHeader); + i = 0; + + while (i < cdat_st[0].length) { + sum += cdat->buf[i++]; + } + + /* Read CDAT structures */ + while (i < file_size) { + hdr = (CDATSubHeader *)(cdat->buf + i); + cdat_len_check(hdr, errp); + + cdat_st[ent].base = hdr; + cdat_st[ent].length = hdr->length; + + while (cdat->buf + i < + (uint8_t *)cdat_st[ent].base + cdat_st[ent].length) { + assert(i < file_size); + sum += cdat->buf[i++]; + } + + ent++; + } + + if (sum != 0) { + warn_report("CDAT: Found checksum mismatch in %s", cdat->filename); + } + cdat->entry_len = num_ent; + cdat->entry = g_steal_pointer(&cdat_st); +} + +void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp) +{ + CDATObject *cdat = &cxl_cstate->cdat; + + if (cdat->filename) { + ct3_load_cdat(cdat, errp); + } else { + ct3_build_cdat(cdat, errp); + } +} + +void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp) +{ + CDATObject *cdat = &cxl_cstate->cdat; + + if (cdat->to_update) { + ct3_build_cdat(cdat, errp); + } +} + +void cxl_doe_cdat_release(CXLComponentState *cxl_cstate) +{ + CDATObject *cdat = &cxl_cstate->cdat; + + free(cdat->entry); + if (cdat->built_buf) { + cdat->free_cdat_table(cdat->built_buf, cdat->built_buf_len, + cdat->private); + } + if (cdat->buf) { + free(cdat->buf); + } +} diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c new file mode 100644 index 000000000000..3edd303a33ac --- /dev/null +++ b/hw/cxl/cxl-component-utils.c @@ -0,0 +1,405 @@ +/* + * CXL Utility library for components + * + * Copyright(C) 2020 Intel Corporation. + * + * 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 "qemu/log.h" +#include "qapi/error.h" +#include "hw/pci/pci.h" +#include "hw/cxl/cxl.h" + +static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset, + unsigned size) +{ + CXLComponentState *cxl_cstate = opaque; + ComponentRegisters *cregs = &cxl_cstate->crb; + + if (size == 8) { + qemu_log_mask(LOG_UNIMP, + "CXL 8 byte cache mem registers not implemented\n"); + return 0; + } + + if (cregs->special_ops && cregs->special_ops->read) { + return cregs->special_ops->read(cxl_cstate, offset, size); + } else { + return cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; + } +} + +static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset, + uint32_t value) +{ + ComponentRegisters *cregs = &cxl_cstate->crb; + uint32_t *cache_mem = cregs->cache_mem_registers; + bool should_commit = false; + + switch (offset) { + case A_CXL_HDM_DECODER0_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + break; + default: + break; + } + + memory_region_transaction_begin(); + stl_le_p((uint8_t *)cache_mem + offset, value); + if (should_commit) { + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMIT, 0); + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, ERR, 0); + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); + } + memory_region_transaction_commit(); +} + +static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CXLComponentState *cxl_cstate = opaque; + ComponentRegisters *cregs = &cxl_cstate->crb; + uint32_t mask; + + if (size == 8) { + qemu_log_mask(LOG_UNIMP, + "CXL 8 byte cache mem registers not implemented\n"); + return; + } + mask = cregs->cache_mem_regs_write_mask[offset / sizeof(*cregs->cache_mem_regs_write_mask)]; + value &= mask; + /* RO bits should remain constant. Done by reading existing value */ + value |= ~mask & cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; + if (cregs->special_ops && cregs->special_ops->write) { + cregs->special_ops->write(cxl_cstate, offset, value, size); + return; + } + + if (offset >= A_CXL_HDM_DECODER_CAPABILITY && + offset <= A_CXL_HDM_DECODER0_TARGET_LIST_HI) { + dumb_hdm_handler(cxl_cstate, offset, value); + } else { + cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)] = value; + } +} + +/* + * 8.2.3 + * The access restrictions specified in Section 8.2.2 also apply to CXL 2.0 + * Component Registers. + * + * 8.2.2 + * • A 32 bit register shall be accessed as a 4 Bytes quantity. Partial + * reads are not permitted. + * • A 64 bit register shall be accessed as a 8 Bytes quantity. Partial + * reads are not permitted. + * + * As of the spec defined today, only 4 byte registers exist. + */ +static const MemoryRegionOps cache_mem_ops = { + .read = cxl_cache_mem_read_reg, + .write = cxl_cache_mem_write_reg, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +void cxl_component_register_block_init(Object *obj, + CXLComponentState *cxl_cstate, + const char *type) +{ + ComponentRegisters *cregs = &cxl_cstate->crb; + + memory_region_init(&cregs->component_registers, obj, type, + CXL2_COMPONENT_BLOCK_SIZE); + + /* io registers controls link which we don't care about in QEMU */ + memory_region_init_io(&cregs->io, obj, NULL, cregs, ".io", + CXL2_COMPONENT_IO_REGION_SIZE); + memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cregs, + ".cache_mem", CXL2_COMPONENT_CM_REGION_SIZE); + + memory_region_add_subregion(&cregs->component_registers, 0, &cregs->io); + memory_region_add_subregion(&cregs->component_registers, + CXL2_COMPONENT_IO_REGION_SIZE, + &cregs->cache_mem); +} + +static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk) +{ + /* + * Error status is RW1C but given bits are not yet set, it can + * be handled as RO. + */ + reg_state[R_CXL_RAS_UNC_ERR_STATUS] = 0; + /* Bits 12-13 and 17-31 reserved in CXL 2.0 */ + reg_state[R_CXL_RAS_UNC_ERR_MASK] = 0x1cfff; + write_msk[R_CXL_RAS_UNC_ERR_MASK] = 0x1cfff; + reg_state[R_CXL_RAS_UNC_ERR_SEVERITY] = 0x1cfff; + write_msk[R_CXL_RAS_UNC_ERR_SEVERITY] = 0x1cfff; + reg_state[R_CXL_RAS_COR_ERR_STATUS] = 0; + reg_state[R_CXL_RAS_COR_ERR_MASK] = 0x7f; + write_msk[R_CXL_RAS_COR_ERR_MASK] = 0x7f; + /* CXL switches and devices must set */ + reg_state[R_CXL_RAS_ERR_CAP_CTRL] = 0x00; +} + +static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, + enum reg_type type) +{ + int decoder_count = 1; + int i; + + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, + cxl_decoder_count_enc(decoder_count)); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 1); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 1); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 1); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, POISON_ON_ERR_CAP, 0); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_GLOBAL_CONTROL, + HDM_DECODER_ENABLE, 0); + write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3; + for (i = 0; i < decoder_count; i++) { + write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * 0x20] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * 0x20] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * 0x20] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * 0x20] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_CTRL + i * 0x20] = 0x13ff; + if (type == CXL2_DEVICE || + type == CXL2_TYPE3_DEVICE || + type == CXL2_LOGICAL_DEVICE) { + write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xf0000000; + } else { + write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xffffffff; + } + write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * 0x20] = 0xffffffff; + } +} + +void cxl_component_register_init_common(uint32_t *reg_state, uint32_t *write_msk, + enum reg_type type) +{ + int caps = 0; + + /* + * In CXL 2.0 the capabilities required for each CXL component are such that, + * with the ordering chosen here, a single number can be used to define + * which capabilities should be provided. + */ + switch (type) { + case CXL2_DOWNSTREAM_PORT: + case CXL2_DEVICE: + /* RAS, Link */ + caps = 2; + break; + case CXL2_UPSTREAM_PORT: + case CXL2_TYPE3_DEVICE: + case CXL2_LOGICAL_DEVICE: + /* + HDM */ + caps = 3; + break; + case CXL2_ROOT_PORT: + /* + Extended Security, + Snoop */ + caps = 5; + break; + default: + abort(); + } + + memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE); + + /* CXL Capability Header Register */ + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ID, 1); + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION, 1); + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1); + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); + +#define init_cap_reg(reg, id, version) \ + QEMU_BUILD_BUG_ON(CXL_##reg##_REGISTERS_OFFSET == 0); \ + do { \ + int which = R_CXL_##reg##_CAPABILITY_HEADER; \ + reg_state[which] = FIELD_DP32(reg_state[which], \ + CXL_##reg##_CAPABILITY_HEADER, ID, id); \ + reg_state[which] = \ + FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, \ + VERSION, version); \ + reg_state[which] = \ + FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, PTR, \ + CXL_##reg##_REGISTERS_OFFSET); \ + } while (0) + + init_cap_reg(RAS, 2, 2); + ras_init_common(reg_state, write_msk); + + init_cap_reg(LINK, 4, 2); + + if (caps < 3) { + return; + } + + init_cap_reg(HDM, 5, 1); + hdm_init_common(reg_state, write_msk, type); + + if (caps < 5) { + return; + } + + init_cap_reg(EXTSEC, 6, 1); + init_cap_reg(SNOOP, 8, 1); + +#undef init_cap_reg +} + +/* + * Helper to creates a DVSEC header for a CXL entity. The caller is responsible + * for tracking the valid offset. + * + * This function will build the DVSEC header on behalf of the caller and then + * copy in the remaining data for the vendor specific bits. + * It will also set up appropriate write masks. + */ +void cxl_component_create_dvsec(CXLComponentState *cxl, + enum reg_type cxl_dev_type, uint16_t length, + uint16_t type, uint8_t rev, uint8_t *body) +{ + PCIDevice *pdev = cxl->pdev; + uint16_t offset = cxl->dvsec_offset; + uint8_t *wmask = pdev->wmask; + + assert(offset >= PCI_CFG_SPACE_SIZE && + ((offset + length) < PCI_CFG_SPACE_EXP_SIZE)); + assert((length & 0xf000) == 0); + assert((rev & ~0xf) == 0); + + /* Create the DVSEC in the MCFG space */ + pcie_add_capability(pdev, PCI_EXT_CAP_ID_DVSEC, 1, offset, length); + pci_set_long(pdev->config + offset + PCIE_DVSEC_HEADER1_OFFSET, + (length << 20) | (rev << 16) | CXL_VENDOR_ID); + pci_set_word(pdev->config + offset + PCIE_DVSEC_ID_OFFSET, type); + memcpy(pdev->config + offset + sizeof(DVSECHeader), + body + sizeof(DVSECHeader), + length - sizeof(DVSECHeader)); + + /* Configure write masks */ + switch (type) { + case PCIE_CXL_DEVICE_DVSEC: + /* Cntrl RW Lock - so needs explicit blocking when lock is set */ + wmask[offset + offsetof(CXLDVSECDevice, ctrl)] = 0xFD; + wmask[offset + offsetof(CXLDVSECDevice, ctrl) + 1] = 0x4F; + /* Status is RW1CS */ + wmask[offset + offsetof(CXLDVSECDevice, ctrl2)] = 0x0F; + /* Lock is RW Once */ + wmask[offset + offsetof(CXLDVSECDevice, lock)] = 0x01; + /* range1/2_base_high/low is RW Lock */ + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi)] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 3] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_lo) + 3] = 0xF0; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi)] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 3] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_lo) + 3] = 0xF0; + break; + case NON_CXL_FUNCTION_MAP_DVSEC: + break; /* Not yet implemented */ + case EXTENSIONS_PORT_DVSEC: + wmask[offset + offsetof(CXLDVSECPortExtensions, control)] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortExtensions, control) + 1] = 0x40; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_base)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_limit)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 3] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 3] = 0xFF; + break; + case GPF_PORT_DVSEC: + wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl)] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl) + 1] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl)] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl) + 1] = 0x0F; + break; + case GPF_DEVICE_DVSEC: + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration)] = 0x0F; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration) + 1] = 0x0F; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power)] = 0xFF; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 3] = 0xFF; + break; + case PCIE_FLEXBUS_PORT_DVSEC: + switch (cxl_dev_type) { + case CXL2_ROOT_PORT: + /* No MLD */ + wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xbd; + break; + case CXL2_DOWNSTREAM_PORT: + wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xfd; + break; + default: /* Registers are RO for other component types */ + break; + } + /* There are rw1cs bits in the status register but never set currently */ + break; + } + + /* Update state for future DVSEC additions */ + range_init_nofail(&cxl->dvsecs[type], cxl->dvsec_offset, length); + cxl->dvsec_offset += length; +} + +uint8_t cxl_interleave_ways_enc(int iw, Error **errp) +{ + switch (iw) { + case 1: return 0x0; + case 2: return 0x1; + case 4: return 0x2; + case 8: return 0x3; + case 16: return 0x4; + case 3: return 0x8; + case 6: return 0x9; + case 12: return 0xa; + default: + error_setg(errp, "Interleave ways: %d not supported", iw); + return 0; + } +} + +uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp) +{ + switch (gran) { + case 256: return 0; + case 512: return 1; + case 1024: return 2; + case 2048: return 3; + case 4096: return 4; + case 8192: return 5; + case 16384: return 6; + default: + error_setg(errp, "Interleave granularity: %" PRIu64 " invalid", gran); + return 0; + } +} diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c new file mode 100644 index 000000000000..83ce7a827086 --- /dev/null +++ b/hw/cxl/cxl-device-utils.c @@ -0,0 +1,271 @@ +/* + * CXL Utility library for devices + * + * Copyright(C) 2020 Intel Corporation. + * + * 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 "qemu/log.h" +#include "hw/cxl/cxl.h" + +/* + * Device registers have no restrictions per the spec, and so fall back to the + * default memory mapped register rules in 8.2: + * Software shall use CXL.io Memory Read and Write to access memory mapped + * register defined in this section. Unless otherwise specified, software + * shall restrict the accesses width based on the following: + * • A 32 bit register shall be accessed as a 1 Byte, 2 Bytes or 4 Bytes + * quantity. + * • A 64 bit register shall be accessed as a 1 Byte, 2 Bytes, 4 Bytes or 8 + * Bytes + * • The address shall be a multiple of the access width, e.g. when + * accessing a register as a 4 Byte quantity, the address shall be + * multiple of 4. + * • The accesses shall map to contiguous bytes.If these rules are not + * followed, the behavior is undefined + */ + +static uint64_t caps_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + CXLDeviceState *cxl_dstate = opaque; + + if (size == 4) { + return cxl_dstate->caps_reg_state32[offset / sizeof(*cxl_dstate->caps_reg_state32)]; + } else { + return cxl_dstate->caps_reg_state64[offset / sizeof(*cxl_dstate->caps_reg_state64)]; + } +} + +static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + return 0; +} + +static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + CXLDeviceState *cxl_dstate = opaque; + + switch (size) { + case 1: + return cxl_dstate->mbox_reg_state[offset]; + case 2: + return cxl_dstate->mbox_reg_state16[offset / size]; + case 4: + return cxl_dstate->mbox_reg_state32[offset / size]; + case 8: + return cxl_dstate->mbox_reg_state64[offset / size]; + default: + g_assert_not_reached(); + } +} + +static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset, + uint64_t value) +{ + switch (offset) { + case A_CXL_DEV_MAILBOX_CTRL: + /* fallthrough */ + case A_CXL_DEV_MAILBOX_CAP: + /* RO register */ + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n", + __func__, offset); + return; + } + + reg_state[offset / sizeof(*reg_state)] = value; +} + +static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset, + uint64_t value) +{ + switch (offset) { + case A_CXL_DEV_MAILBOX_CMD: + break; + case A_CXL_DEV_BG_CMD_STS: + /* BG not supported */ + /* fallthrough */ + case A_CXL_DEV_MAILBOX_STS: + /* Read only register, will get updated by the state machine */ + return; + default: + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n", + __func__, offset); + return; + } + + + reg_state[offset / sizeof(*reg_state)] = value; +} + +static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CXLDeviceState *cxl_dstate = opaque; + + if (offset >= A_CXL_DEV_CMD_PAYLOAD) { + memcpy(cxl_dstate->mbox_reg_state + offset, &value, size); + return; + } + + switch (size) { + case 4: + mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value); + break; + case 8: + mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value); + break; + default: + g_assert_not_reached(); + } + + if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, + DOORBELL)) { + cxl_process_mailbox(cxl_dstate); + } +} + +static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t retval = 0; + + retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MEDIA_STATUS, 1); + retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MBOX_READY, 1); + + 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 = ro_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static const MemoryRegionOps mailbox_ops = { + .read = mailbox_reg_read, + .write = mailbox_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static const MemoryRegionOps dev_ops = { + .read = dev_reg_read, + .write = ro_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static const MemoryRegionOps caps_ops = { + .read = caps_reg_read, + .write = ro_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) +{ + /* This will be a BAR, so needs to be rounded up to pow2 for PCI spec */ + memory_region_init(&cxl_dstate->device_registers, obj, "device-registers", + pow2ceil(CXL_MMIO_SIZE)); + + memory_region_init_io(&cxl_dstate->caps, obj, &caps_ops, cxl_dstate, + "cap-array", CXL_CAPS_SIZE); + memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate, + "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH); + memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cxl_dstate, + "mailbox", CXL_MAILBOX_REGISTERS_LENGTH); + memory_region_init_io(&cxl_dstate->memory_device, obj, &mdev_ops, + cxl_dstate, "memory device caps", + CXL_MEMORY_DEVICE_REGISTERS_LENGTH); + + memory_region_add_subregion(&cxl_dstate->device_registers, 0, + &cxl_dstate->caps); + memory_region_add_subregion(&cxl_dstate->device_registers, + CXL_DEVICE_STATUS_REGISTERS_OFFSET, + &cxl_dstate->device); + memory_region_add_subregion(&cxl_dstate->device_registers, + CXL_MAILBOX_REGISTERS_OFFSET, + &cxl_dstate->mailbox); + memory_region_add_subregion(&cxl_dstate->device_registers, + CXL_MEMORY_DEVICE_REGISTERS_OFFSET, + &cxl_dstate->memory_device); +} + +static void device_reg_init_common(CXLDeviceState *cxl_dstate) { } + +static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate) +{ + /* 2048 payload size, with no interrupt or background support */ + ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, + PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT); + cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE; +} + +static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) { } + +void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) +{ + uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64; + const int cap_count = 3; + + /* CXL Device Capabilities Array Register */ + ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0); + ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); + ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); + + cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1); + device_reg_init_common(cxl_dstate); + + cxl_device_cap_init(cxl_dstate, MAILBOX, 2); + mailbox_reg_init_common(cxl_dstate); + + cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000); + memdev_reg_init_common(cxl_dstate); + + assert(cxl_initialize_mailbox(cxl_dstate) == 0); +} diff --git a/hw/cxl/cxl-host-stubs.c b/hw/cxl/cxl-host-stubs.c new file mode 100644 index 000000000000..cae4afcdde26 --- /dev/null +++ b/hw/cxl/cxl-host-stubs.c @@ -0,0 +1,15 @@ +/* + * CXL host parameter parsing routine stubs + * + * Copyright (c) 2022 Huawei + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/cxl/cxl.h" +#include "hw/cxl/cxl_host.h" + +void cxl_fmws_link_targets(CXLState *stat, Error **errp) {}; +void cxl_machine_init(Object *obj, CXLState *state) {}; +void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp) {}; + +const MemoryRegionOps cfmws_ops; diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c new file mode 100644 index 000000000000..1adf61231ad5 --- /dev/null +++ b/hw/cxl/cxl-host.c @@ -0,0 +1,340 @@ +/* + * CXL host parameter parsing routines + * + * Copyright (c) 2022 Huawei + * Modeled loosely on the NUMA options handling in hw/core/numa.c + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/bitmap.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "sysemu/qtest.h" +#include "hw/boards.h" + +#include "qapi/qapi-visit-machine.h" +#include "hw/cxl/cxl.h" +#include "hw/cxl/cxl_host.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pcie_port.h" +#include "hw/pci-bridge/pci_expander_bridge.h" + +static void cxl_fixed_memory_window_config(CXLState *cxl_state, + CXLFixedMemoryWindowOptions *object, + Error **errp) +{ + g_autofree CXLFixedWindow *fw = g_malloc0(sizeof(*fw)); + strList *target; + int i; + + for (target = object->targets; target; target = target->next) { + fw->num_targets++; + } + + fw->enc_int_ways = cxl_interleave_ways_enc(fw->num_targets, errp); + if (*errp) { + return; + } + + fw->targets = g_malloc0_n(fw->num_targets, sizeof(*fw->targets)); + for (i = 0, target = object->targets; target; i++, target = target->next) { + /* This link cannot be resolved yet, so stash the name for now */ + fw->targets[i] = g_strdup(target->value); + } + + if (object->size % (256 * MiB)) { + error_setg(errp, + "Size of a CXL fixed memory window must my a multiple of 256MiB"); + return; + } + fw->size = object->size; + + if (object->has_interleave_granularity) { + fw->enc_int_gran = + cxl_interleave_granularity_enc(object->interleave_granularity, + errp); + if (*errp) { + return; + } + } else { + /* Default to 256 byte interleave */ + fw->enc_int_gran = 0; + } + + cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows, + g_steal_pointer(&fw)); + + return; +} + +void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp) +{ + if (cxl_state && cxl_state->fixed_windows) { + GList *it; + + for (it = cxl_state->fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + int i; + + for (i = 0; i < fw->num_targets; i++) { + Object *o; + bool ambig; + + o = object_resolve_path_type(fw->targets[i], + TYPE_PXB_CXL_DEVICE, + &ambig); + if (!o) { + error_setg(errp, "Could not resolve CXLFM target %s", + fw->targets[i]); + return; + } + fw->target_hbs[i] = PXB_CXL_DEV(o); + } + } + } +} + +/* TODO: support, multiple hdm decoders */ +static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, + uint8_t *target) +{ + uint32_t ctrl; + uint32_t ig_enc; + uint32_t iw_enc; + uint32_t target_idx; + + ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; + if (!FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) { + return false; + } + + ig_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IG); + 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 = extract32(cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO], + target_idx * 8, 8); + } else { + *target = extract32(cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_HI], + (target_idx - 4) * 8, 8); + } + + return true; +} + +static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr) +{ + CXLComponentState *hb_cstate, *usp_cstate; + PCIHostState *hb; + CXLUpstreamPort *usp; + int rb_index; + uint32_t *cache_mem; + uint8_t target; + bool target_found; + PCIDevice *rp, *d; + + /* Address is relative to memory region. Convert to HPA */ + addr += fw->base; + + rb_index = (addr / cxl_decode_ig(fw->enc_int_gran)) % fw->num_targets; + hb = PCI_HOST_BRIDGE(fw->target_hbs[rb_index]->cxl.cxl_host_bridge); + if (!hb || !hb->bus || !pci_bus_is_cxl(hb->bus)) { + return NULL; + } + + hb_cstate = cxl_get_hb_cstate(hb); + if (!hb_cstate) { + return NULL; + } + + cache_mem = hb_cstate->crb.cache_mem_registers; + + target_found = cxl_hdm_find_target(cache_mem, addr, &target); + if (!target_found) { + return NULL; + } + + rp = pcie_find_port_by_pn(hb->bus, target); + if (!rp) { + return NULL; + } + + d = pci_bridge_get_sec_bus(PCI_BRIDGE(rp))->devices[0]; + if (!d) { + return NULL; + } + + if (object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) { + return d; + } + + /* + * Could also be a switch. Note only one level of switching currently + * supported. + */ + if (!object_dynamic_cast(OBJECT(d), TYPE_CXL_USP)) { + return NULL; + } + usp = CXL_USP(d); + + usp_cstate = cxl_usp_to_cstate(usp); + if (!usp_cstate) { + return NULL; + } + + cache_mem = usp_cstate->crb.cache_mem_registers; + + target_found = cxl_hdm_find_target(cache_mem, addr, &target); + if (!target_found) { + return NULL; + } + + d = pcie_find_port_by_pn(&PCI_BRIDGE(d)->sec_bus, target); + if (!d) { + return NULL; + } + + d = pci_bridge_get_sec_bus(PCI_BRIDGE(d))->devices[0]; + if (!d) { + return NULL; + } + + if (!object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) { + return NULL; + } + + return d; +} + +static MemTxResult cxl_read_cfmws(void *opaque, hwaddr addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + CXLFixedWindow *fw = opaque; + PCIDevice *d; + + d = cxl_cfmws_find_device(fw, addr); + if (d == NULL) { + *data = 0; + /* Reads to invalid address return poison */ + return MEMTX_ERROR; + } + + return cxl_type3_read(d, addr + fw->base, data, size, attrs); +} + +static MemTxResult cxl_write_cfmws(void *opaque, hwaddr addr, + uint64_t data, unsigned size, + MemTxAttrs attrs) +{ + CXLFixedWindow *fw = opaque; + PCIDevice *d; + + d = cxl_cfmws_find_device(fw, addr); + if (d == NULL) { + /* Writes to invalid address are silent */ + return MEMTX_OK; + } + + return cxl_type3_write(d, addr + fw->base, data, size, attrs); +} + +const MemoryRegionOps cfmws_ops = { + .read_with_attrs = cxl_read_cfmws, + .write_with_attrs = cxl_write_cfmws, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, +}; + +static void machine_get_cxl(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CXLState *cxl_state = opaque; + bool value = cxl_state->is_enabled; + + visit_type_bool(v, name, &value, errp); +} + +static void machine_set_cxl(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CXLState *cxl_state = opaque; + bool value; + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + cxl_state->is_enabled = value; +} + +static void machine_get_cfmw(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CXLFixedMemoryWindowOptionsList **list = opaque; + + visit_type_CXLFixedMemoryWindowOptionsList(v, name, list, errp); +} + +static void machine_set_cfmw(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + CXLState *state = opaque; + CXLFixedMemoryWindowOptionsList *cfmw_list = NULL; + CXLFixedMemoryWindowOptionsList *it; + + visit_type_CXLFixedMemoryWindowOptionsList(v, name, &cfmw_list, errp); + if (!cfmw_list) { + return; + } + + for (it = cfmw_list; it; it = it->next) { + cxl_fixed_memory_window_config(state, it->value, errp); + } + state->cfmw_list = cfmw_list; +} + +void cxl_machine_init(Object *obj, CXLState *state) +{ + object_property_add(obj, "cxl", "bool", machine_get_cxl, + machine_set_cxl, NULL, state); + object_property_set_description(obj, "cxl", + "Set on/off to enable/disable " + "CXL instantiation"); + + object_property_add(obj, "cxl-fmw", "CXLFixedMemoryWindow", + machine_get_cfmw, machine_set_cfmw, + NULL, state); + object_property_set_description(obj, "cxl-fmw", + "CXL Fixed Memory Windows (array)"); +} + +void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp) +{ + /* Walk the pci busses looking for pxb busses to hook up */ + if (bus) { + QLIST_FOREACH(bus, &bus->child, sibling) { + if (!pci_bus_is_root(bus)) { + continue; + } + if (pci_bus_is_cxl(bus)) { + if (!state->is_enabled) { + error_setg(errp, "CXL host bridges present, but cxl=off"); + return; + } + pxb_cxl_hook_up_registers(state, bus, errp); + } + } + } +} diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c new file mode 100644 index 000000000000..bc1bb18844be --- /dev/null +++ b/hw/cxl/cxl-mailbox-utils.c @@ -0,0 +1,478 @@ +/* + * CXL Utility library for mailbox interface + * + * Copyright(C) 2020 Intel Corporation. + * + * 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 "hw/cxl/cxl.h" +#include "hw/pci/pci.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "qemu/uuid.h" + +/* + * How to add a new command, example. The command set FOO, with cmd BAR. + * 1. Add the command set and cmd to the enum. + * FOO = 0x7f, + * #define BAR 0 + * 2. Implement the handler + * static ret_code cmd_foo_bar(struct cxl_cmd *cmd, + * CXLDeviceState *cxl_dstate, uint16_t *len) + * 3. Add the command to the cxl_cmd_set[][] + * [FOO][BAR] = { "FOO_BAR", cmd_foo_bar, x, y }, + * 4. Implement your handler + * define_mailbox_handler(FOO_BAR) { ... return CXL_MBOX_SUCCESS; } + * + * + * Writing the handler: + * The handler will provide the &struct cxl_cmd, the &CXLDeviceState, and the + * in/out length of the payload. The handler is responsible for consuming the + * payload from cmd->payload and operating upon it as necessary. It must then + * fill the output data into cmd->payload (overwriting what was there), + * setting the length, and returning a valid return code. + * + * XXX: The handler need not worry about endianess. The payload is read out of + * a register interface that already deals with it. + */ + +enum { + EVENTS = 0x01, + #define GET_RECORDS 0x0 + #define CLEAR_RECORDS 0x1 + #define GET_INTERRUPT_POLICY 0x2 + #define SET_INTERRUPT_POLICY 0x3 + FIRMWARE_UPDATE = 0x02, + #define GET_INFO 0x0 + TIMESTAMP = 0x03, + #define GET 0x0 + #define SET 0x1 + LOGS = 0x04, + #define GET_SUPPORTED 0x0 + #define GET_LOG 0x1 + IDENTIFY = 0x40, + #define MEMORY_DEVICE 0x0 + CCLS = 0x41, + #define GET_PARTITION_INFO 0x0 + #define GET_LSA 0x2 + #define SET_LSA 0x3 +}; + +/* 8.2.8.4.5.1 Command Return Codes */ +typedef enum { + CXL_MBOX_SUCCESS = 0x0, + CXL_MBOX_BG_STARTED = 0x1, + CXL_MBOX_INVALID_INPUT = 0x2, + CXL_MBOX_UNSUPPORTED = 0x3, + CXL_MBOX_INTERNAL_ERROR = 0x4, + CXL_MBOX_RETRY_REQUIRED = 0x5, + CXL_MBOX_BUSY = 0x6, + CXL_MBOX_MEDIA_DISABLED = 0x7, + CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8, + CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9, + CXL_MBOX_FW_AUTH_FAILED = 0xa, + CXL_MBOX_FW_INVALID_SLOT = 0xb, + CXL_MBOX_FW_ROLLEDBACK = 0xc, + CXL_MBOX_FW_REST_REQD = 0xd, + CXL_MBOX_INVALID_HANDLE = 0xe, + CXL_MBOX_INVALID_PA = 0xf, + CXL_MBOX_INJECT_POISON_LIMIT = 0x10, + CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11, + CXL_MBOX_ABORTED = 0x12, + CXL_MBOX_INVALID_SECURITY_STATE = 0x13, + CXL_MBOX_INCORRECT_PASSPHRASE = 0x14, + CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15, + CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16, + CXL_MBOX_MAX = 0x17 +} ret_code; + +struct cxl_cmd; +typedef ret_code (*opcode_handler)(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, uint16_t *len); +struct cxl_cmd { + const char *name; + opcode_handler handler; + ssize_t in; + uint16_t effect; /* Reported in CEL */ + uint8_t *payload; +}; + +#define DEFINE_MAILBOX_HANDLER_ZEROED(name, size) \ + uint16_t __zero##name = size; \ + static ret_code cmd_##name(struct cxl_cmd *cmd, \ + CXLDeviceState *cxl_dstate, uint16_t *len) \ + { \ + *len = __zero##name; \ + memset(cmd->payload, 0, *len); \ + return CXL_MBOX_SUCCESS; \ + } +#define DEFINE_MAILBOX_HANDLER_NOP(name) \ + static ret_code cmd_##name(struct cxl_cmd *cmd, \ + CXLDeviceState *cxl_dstate, uint16_t *len) \ + { \ + return CXL_MBOX_SUCCESS; \ + } + +DEFINE_MAILBOX_HANDLER_ZEROED(events_get_records, 0x20); +DEFINE_MAILBOX_HANDLER_NOP(events_clear_records); +DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4); +DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy); + +/* 8.2.9.2.1 */ +static ret_code cmd_firmware_update_get_info(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint8_t slots_supported; + uint8_t slot_info; + uint8_t caps; + uint8_t rsvd[0xd]; + char fw_rev1[0x10]; + char fw_rev2[0x10]; + char fw_rev3[0x10]; + char fw_rev4[0x10]; + } QEMU_PACKED *fw_info; + QEMU_BUILD_BUG_ON(sizeof(*fw_info) != 0x50); + + if (cxl_dstate->pmem_size < (256 << 20)) { + return CXL_MBOX_INTERNAL_ERROR; + } + + fw_info = (void *)cmd->payload; + memset(fw_info, 0, sizeof(*fw_info)); + + fw_info->slots_supported = 2; + fw_info->slot_info = BIT(0) | BIT(3); + fw_info->caps = 0; + pstrcpy(fw_info->fw_rev1, sizeof(fw_info->fw_rev1), "BWFW VERSION 0"); + + *len = sizeof(*fw_info); + return CXL_MBOX_SUCCESS; +} + +/* 8.2.9.3.1 */ +static ret_code cmd_timestamp_get(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + uint64_t time, delta; + uint64_t final_time = 0; + + if (cxl_dstate->timestamp.set) { + /* First find the delta from the last time the host set the time. */ + time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + delta = time - cxl_dstate->timestamp.last_set; + final_time = cxl_dstate->timestamp.host_set + delta; + } + + /* Then adjust the actual time */ + stq_le_p(cmd->payload, final_time); + *len = 8; + + return CXL_MBOX_SUCCESS; +} + +/* 8.2.9.3.2 */ +static ret_code cmd_timestamp_set(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + cxl_dstate->timestamp.set = true; + cxl_dstate->timestamp.last_set = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + cxl_dstate->timestamp.host_set = le64_to_cpu(*(uint64_t *)cmd->payload); + + *len = 0; + return CXL_MBOX_SUCCESS; +} + +static QemuUUID cel_uuid; + +/* 8.2.9.4.1 */ +static ret_code cmd_logs_get_supported(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint16_t entries; + uint8_t rsvd[6]; + struct { + QemuUUID uuid; + uint32_t size; + } log_entries[1]; + } QEMU_PACKED *supported_logs = (void *)cmd->payload; + QEMU_BUILD_BUG_ON(sizeof(*supported_logs) != 0x1c); + + supported_logs->entries = 1; + supported_logs->log_entries[0].uuid = cel_uuid; + supported_logs->log_entries[0].size = 4 * cxl_dstate->cel_size; + + *len = sizeof(*supported_logs); + return CXL_MBOX_SUCCESS; +} + +/* 8.2.9.4.2 */ +static ret_code cmd_logs_get_log(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + QemuUUID uuid; + uint32_t offset; + uint32_t length; + } QEMU_PACKED QEMU_ALIGNED(16) *get_log = (void *)cmd->payload; + + /* + * 8.2.9.4.2 + * The device shall return Invalid Parameter if the Offset or Length + * fields attempt to access beyond the size of the log as reported by Get + * Supported Logs. + * + * XXX: Spec is wrong, "Invalid Parameter" isn't a thing. + * XXX: Spec doesn't address incorrect UUID incorrectness. + * + * The CEL buffer is large enough to fit all commands in the emulation, so + * the only possible failure would be if the mailbox itself isn't big + * enough. + */ + if (get_log->offset + get_log->length > cxl_dstate->payload_size) { + return CXL_MBOX_INVALID_INPUT; + } + + if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) { + return CXL_MBOX_UNSUPPORTED; + } + + /* Store off everything to local variables so we can wipe out the payload */ + *len = get_log->length; + + memmove(cmd->payload, cxl_dstate->cel_log + get_log->offset, + get_log->length); + + return CXL_MBOX_SUCCESS; +} + +/* 8.2.9.5.1.1 */ +static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + char fw_revision[0x10]; + uint64_t total_capacity; + uint64_t volatile_capacity; + uint64_t persistent_capacity; + uint64_t partition_align; + uint16_t info_event_log_size; + uint16_t warning_event_log_size; + uint16_t failure_event_log_size; + uint16_t fatal_event_log_size; + uint32_t lsa_size; + uint8_t poison_list_max_mer[3]; + uint16_t inject_poison_limit; + uint8_t poison_caps; + uint8_t qos_telemetry_caps; + } QEMU_PACKED *id; + QEMU_BUILD_BUG_ON(sizeof(*id) != 0x43); + + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); + uint64_t size = cxl_dstate->pmem_size; + + if (!QEMU_IS_ALIGNED(size, 256 << 20)) { + return CXL_MBOX_INTERNAL_ERROR; + } + + id = (void *)cmd->payload; + memset(id, 0, sizeof(*id)); + + /* PMEM only */ + snprintf(id->fw_revision, 0x10, "BWFW VERSION %02d", 0); + + id->total_capacity = size / (256 << 20); + id->persistent_capacity = size / (256 << 20); + id->lsa_size = cvc->get_lsa_size(ct3d); + + *len = sizeof(*id); + return CXL_MBOX_SUCCESS; +} + +static ret_code cmd_ccls_get_partition_info(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint64_t active_vmem; + uint64_t active_pmem; + uint64_t next_vmem; + uint64_t next_pmem; + } QEMU_PACKED *part_info = (void *)cmd->payload; + QEMU_BUILD_BUG_ON(sizeof(*part_info) != 0x20); + uint64_t size = cxl_dstate->pmem_size; + + if (!QEMU_IS_ALIGNED(size, 256 << 20)) { + return CXL_MBOX_INTERNAL_ERROR; + } + + /* PMEM only */ + part_info->active_vmem = 0; + part_info->next_vmem = 0; + part_info->active_pmem = size / (256 << 20); + part_info->next_pmem = 0; + + *len = sizeof(*part_info); + return CXL_MBOX_SUCCESS; +} + +static ret_code cmd_ccls_get_lsa(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint32_t offset; + uint32_t length; + } QEMU_PACKED *get_lsa; + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); + uint32_t offset, length; + + get_lsa = (void *)cmd->payload; + offset = get_lsa->offset; + length = get_lsa->length; + + if (offset + length > cvc->get_lsa_size(ct3d)) { + *len = 0; + return CXL_MBOX_INVALID_INPUT; + } + + *len = cvc->get_lsa(ct3d, get_lsa, length, offset); + return CXL_MBOX_SUCCESS; +} + +static ret_code cmd_ccls_set_lsa(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct set_lsa_pl { + uint32_t offset; + uint32_t rsvd; + uint8_t data[]; + } QEMU_PACKED; + struct set_lsa_pl *set_lsa_payload = (void *)cmd->payload; + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); + const size_t hdr_len = offsetof(struct set_lsa_pl, data); + uint16_t plen = *len; + + *len = 0; + if (!plen) { + return CXL_MBOX_SUCCESS; + } + + if (set_lsa_payload->offset + plen > cvc->get_lsa_size(ct3d) + hdr_len) { + return CXL_MBOX_INVALID_INPUT; + } + plen -= hdr_len; + + cvc->set_lsa(ct3d, set_lsa_payload->data, plen, set_lsa_payload->offset); + return CXL_MBOX_SUCCESS; +} + +#define IMMEDIATE_CONFIG_CHANGE (1 << 1) +#define IMMEDIATE_DATA_CHANGE (1 << 2) +#define IMMEDIATE_POLICY_CHANGE (1 << 3) +#define IMMEDIATE_LOG_CHANGE (1 << 4) + +static struct cxl_cmd cxl_cmd_set[256][256] = { + [EVENTS][GET_RECORDS] = { "EVENTS_GET_RECORDS", + cmd_events_get_records, 1, 0 }, + [EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS", + cmd_events_clear_records, ~0, IMMEDIATE_LOG_CHANGE }, + [EVENTS][GET_INTERRUPT_POLICY] = { "EVENTS_GET_INTERRUPT_POLICY", + cmd_events_get_interrupt_policy, 0, 0 }, + [EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY", + cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE }, + [FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO", + cmd_firmware_update_get_info, 0, 0 }, + [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, + [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, IMMEDIATE_POLICY_CHANGE }, + [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0, 0 }, + [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 }, + [IDENTIFY][MEMORY_DEVICE] = { "IDENTIFY_MEMORY_DEVICE", + 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, 8, 0 }, + [CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa, + ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE }, +}; + +void cxl_process_mailbox(CXLDeviceState *cxl_dstate) +{ + uint16_t ret = CXL_MBOX_SUCCESS; + struct cxl_cmd *cxl_cmd; + uint64_t status_reg; + opcode_handler h; + uint64_t command_reg = cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD]; + + uint8_t set = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND_SET); + uint8_t cmd = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND); + uint16_t len = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH); + cxl_cmd = &cxl_cmd_set[set][cmd]; + h = cxl_cmd->handler; + if (h) { + 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); + assert(len <= cxl_dstate->payload_size); + } else { + ret = CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + } else { + qemu_log_mask(LOG_UNIMP, "Command %04xh not implemented\n", + set << 8 | cmd); + ret = CXL_MBOX_UNSUPPORTED; + } + + /* Set the return code */ + status_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_STS, ERRNO, ret); + + /* Set the return length */ + command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND_SET, 0); + command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND, 0); + command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH, len); + + cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD] = command_reg; + cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_STS] = status_reg; + + /* Tell the host we're done */ + ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, + DOORBELL, 0); +} + +int cxl_initialize_mailbox(CXLDeviceState *cxl_dstate) +{ + /* CXL 2.0: Table 169 Get Supported Logs Log Entry */ + const char *cel_uuidstr = "0da9c0b5-bf41-4b78-8f79-96b1623b3f17"; + + for (int set = 0; set < 256; set++) { + for (int cmd = 0; cmd < 256; cmd++) { + if (cxl_cmd_set[set][cmd].handler) { + struct cxl_cmd *c = &cxl_cmd_set[set][cmd]; + struct cel_log *log = + &cxl_dstate->cel_log[cxl_dstate->cel_size]; + + log->opcode = (set << 8) | cmd; + log->effect = c->effect; + cxl_dstate->cel_size++; + } + } + } + + return qemu_uuid_parse(cel_uuidstr, &cel_uuid); +} diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build new file mode 100644 index 000000000000..cfa95ffd40b7 --- /dev/null +++ b/hw/cxl/meson.build @@ -0,0 +1,13 @@ +softmmu_ss.add(when: 'CONFIG_CXL', + if_true: files( + 'cxl-component-utils.c', + 'cxl-device-utils.c', + 'cxl-mailbox-utils.c', + 'cxl-host.c', + 'cxl-cdat.c', + ), + if_false: files( + 'cxl-host-stubs.c', + )) + +softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('cxl-host-stubs.c')) diff --git a/hw/display/Kconfig b/hw/display/Kconfig index a1b159becd76..7b3da68d1c0a 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -55,7 +55,7 @@ config VGA_MMIO config VMWARE_VGA bool - default y if PCI_DEVICES + default y if PCI_DEVICES && PC_PCI depends on PCI select VGA diff --git a/hw/display/acpi-vga-stub.c b/hw/display/acpi-vga-stub.c new file mode 100644 index 000000000000..a9b0ecf76d04 --- /dev/null +++ b/hw/display/acpi-vga-stub.c @@ -0,0 +1,7 @@ +#include "qemu/osdep.h" +#include "hw/acpi/acpi_aml_interface.h" +#include "vga_int.h" + +void build_vga_aml(AcpiDevAmlIf *adev, Aml *scope) +{ +} diff --git a/hw/display/acpi-vga.c b/hw/display/acpi-vga.c new file mode 100644 index 000000000000..f0e9ef1fcf8e --- /dev/null +++ b/hw/display/acpi-vga.c @@ -0,0 +1,26 @@ +#include "qemu/osdep.h" +#include "hw/acpi/acpi_aml_interface.h" +#include "hw/pci/pci.h" +#include "vga_int.h" + +void build_vga_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + int s3d = 0; + Aml *method; + + if (object_dynamic_cast(OBJECT(adev), "qxl-vga")) { + s3d = 3; + } + + method = aml_method("_S1D", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0))); + aml_append(scope, method); + + method = aml_method("_S2D", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0))); + aml_append(scope, method); + + method = aml_method("_S3D", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(s3d))); + aml_append(scope, method); +} diff --git a/hw/display/artist.c b/hw/display/artist.c index 1d877998b9ae..fde050c882b0 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -1,13 +1,13 @@ /* * QEMU HP Artist Emulation * - * Copyright (c) 2019 Sven Schnelle + * Copyright (c) 2019-2022 Sven Schnelle + * Copyright (c) 2022 Helge Deller * * This work is licensed under the terms of the GNU GPL, version 2 or later. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" @@ -26,12 +26,6 @@ #define TYPE_ARTIST "artist" OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST) -#ifdef HOST_WORDS_BIGENDIAN -#define ROP8OFF(_i) (3 - (_i)) -#else -#define ROP8OFF -#endif - struct vram_buffer { MemoryRegion mr; uint8_t *data; @@ -88,9 +82,10 @@ struct ARTISTState { uint32_t plane_mask; uint32_t reg_100080; - uint32_t reg_300200; - uint32_t reg_300208; - uint32_t reg_300218; + uint32_t horiz_backporch; + uint32_t active_lines_low; + uint32_t misc_video; + uint32_t misc_ctrl; uint32_t dst_bm_access; uint32_t src_bm_access; @@ -105,6 +100,9 @@ struct ARTISTState { int draw_line_pattern; }; +/* hardware allows up to 64x64, but we emulate 32x32 only. */ +#define NGLE_MAX_SPRITE_SIZE 32 + typedef enum { ARTIST_BUFFER_AP = 1, ARTIST_BUFFER_OVERLAY = 2, @@ -142,8 +140,14 @@ typedef enum { BG_COLOR = 0x118014, PLANE_MASK = 0x118018, IMAGE_BITMAP_OP = 0x11801c, - CURSOR_POS = 0x300100, - CURSOR_CTRL = 0x300104, + CURSOR_POS = 0x300100, /* reg17 */ + CURSOR_CTRL = 0x300104, /* reg18 */ + MISC_VIDEO = 0x300218, /* reg21 */ + MISC_CTRL = 0x300308, /* reg27 */ + HORIZ_BACKPORCH = 0x300200, /* reg19 */ + ACTIVE_LINES_LOW = 0x300208,/* reg20 */ + FIFO1 = 0x300008, /* reg34 */ + FIFO2 = 0x380008, } artist_reg_t; typedef enum { @@ -181,17 +185,25 @@ static const char *artist_reg_name(uint64_t addr) REG_NAME(SRC_BM_ACCESS); REG_NAME(CURSOR_POS); REG_NAME(CURSOR_CTRL); + REG_NAME(HORIZ_BACKPORCH); + REG_NAME(ACTIVE_LINES_LOW); + REG_NAME(MISC_VIDEO); + REG_NAME(MISC_CTRL); REG_NAME(LINE_XY); REG_NAME(PATTERN_LINE_START); REG_NAME(LINE_SIZE); REG_NAME(LINE_END); REG_NAME(FONT_WRITE_INCR_Y); REG_NAME(FONT_WRITE_START); + REG_NAME(FIFO1); + REG_NAME(FIFO2); } return ""; } #undef REG_NAME +static void artist_invalidate(void *opaque); + /* artist has a fixed line length of 2048 bytes. */ #define ADDR_TO_Y(addr) extract32(addr, 11, 11) #define ADDR_TO_X(addr) extract32(addr, 0, 11) @@ -212,8 +224,9 @@ static void artist_invalidate_lines(struct vram_buffer *buf, int start = starty * buf->width; int size; - if (starty + height > buf->height) + if (starty + height > buf->height) { height = buf->height - starty; + } size = height * buf->width; @@ -301,19 +314,15 @@ static void artist_rop8(ARTISTState *s, struct vram_buffer *buf, static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) { /* - * Don't know whether these magic offset values are configurable via - * some register. They seem to be the same for all resolutions. - * The cursor values provided in the registers are: - * X-value: -295 (for HP-UX 11) and 338 (for HP-UX 10.20) up to 2265 - * Y-value: 1146 down to 0 * The emulated Artist graphic is like a CRX graphic, and as such * it's usually fixed at 1280x1024 pixels. - * Because of the maximum Y-value of 1146 you can not choose a higher - * vertical resolution on HP-UX (unless you disable the mouse). + * Other resolutions may work, but no guarantee. */ - static int offset = 338; - int lx; + unsigned int hbp_times_vi, horizBackPorch; + int16_t xHi, xLo; + const int videoInterleave = 4; + const int pipelineDelay = 4; /* ignore if uninitialized */ if (s->cursor_pos == 0) { @@ -321,15 +330,24 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) return; } - lx = artist_get_x(s->cursor_pos); - if (lx < offset) - offset = lx; - *x = (lx - offset) / 2; + /* + * Calculate X position based on backporch and interleave values. + * Based on code from Xorg X11R6.6 + */ + horizBackPorch = ((s->horiz_backporch & 0xff0000) >> 16) + + ((s->horiz_backporch & 0xff00) >> 8) + 2; + hbp_times_vi = horizBackPorch * videoInterleave; + xHi = s->cursor_pos >> 19; + *x = ((xHi + pipelineDelay) * videoInterleave) - hbp_times_vi; - *y = 1146 - artist_get_y(s->cursor_pos); + xLo = (s->cursor_pos >> 16) & 0x07; + *x += ((xLo - hbp_times_vi) & (videoInterleave - 1)) + 8 - 1; /* subtract cursor offset from cursor control register */ *x -= (s->cursor_cntrl & 0xf0) >> 4; + + /* Calculate Y position */ + *y = s->height - artist_get_y(s->cursor_pos); *y -= (s->cursor_cntrl & 0x0f); if (*x > s->width) { @@ -341,9 +359,20 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) } } +static inline bool cursor_visible(ARTISTState *s) +{ + /* cursor is visible if bit 0x80 is set in cursor_cntrl */ + return s->cursor_cntrl & 0x80; +} + static void artist_invalidate_cursor(ARTISTState *s) { int x, y; + + if (!cursor_visible(s)) { + return; + } + artist_get_cursor_pos(s, &x, &y); artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP], y, s->cursor_height); @@ -471,10 +500,9 @@ static void draw_line(ARTISTState *s, if ((x1 >= buf->width && x2 >= buf->width) || (y1 >= buf->height && y2 >= buf->height)) { - return; + return; } - if (update_start) { s->vram_start = (x2 << 16) | y2; } @@ -554,15 +582,15 @@ static void draw_line(ARTISTState *s, x++; } while (x <= x2 && (max_pix == -1 || --max_pix > 0)); - if (c1) + if (c1) { artist_invalidate_lines(buf, x1, x2 - x1); - else + } else { artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1); + } } static void draw_line_pattern_start(ARTISTState *s) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->blockmove_size); @@ -575,7 +603,6 @@ static void draw_line_pattern_start(ARTISTState *s) static void draw_line_pattern_next(ARTISTState *s) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->blockmove_size); @@ -590,7 +617,6 @@ static void draw_line_pattern_next(ARTISTState *s) static void draw_line_size(ARTISTState *s, bool update_start) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->line_size); @@ -601,7 +627,6 @@ static void draw_line_size(ARTISTState *s, bool update_start) static void draw_line_xy(ARTISTState *s, bool update_start) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int sizex = artist_get_x(s->blockmove_size); @@ -651,7 +676,6 @@ static void draw_line_xy(ARTISTState *s, bool update_start) static void draw_line_end(ARTISTState *s, bool update_start) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->line_end); @@ -712,7 +736,7 @@ static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out) * FIXME: is there a qemu helper for this? */ -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN addr ^= 3; #endif @@ -836,6 +860,7 @@ static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { ARTISTState *s = opaque; + s->vram_char_y = 0; trace_artist_vram_write(size, addr, val); vram_bit_write(opaque, addr, 0, val, size); @@ -884,6 +909,7 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, { ARTISTState *s = opaque; int width, height; + uint64_t oldval; trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val); @@ -1033,16 +1059,33 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, combine_write_reg(addr, val, size, &s->transfer_data); break; - case 0x300200: - combine_write_reg(addr, val, size, &s->reg_300200); + case HORIZ_BACKPORCH: + /* overwrite HP-UX settings to fix X cursor position. */ + val = (NGLE_MAX_SPRITE_SIZE << 16) + (NGLE_MAX_SPRITE_SIZE << 8); + combine_write_reg(addr, val, size, &s->horiz_backporch); break; - case 0x300208: - combine_write_reg(addr, val, size, &s->reg_300208); + case ACTIVE_LINES_LOW: + combine_write_reg(addr, val, size, &s->active_lines_low); break; - case 0x300218: - combine_write_reg(addr, val, size, &s->reg_300218); + case MISC_VIDEO: + oldval = s->misc_video; + combine_write_reg(addr, val, size, &s->misc_video); + /* Invalidate and hide screen if graphics signal is turned off. */ + if (((oldval & 0x0A000000) == 0x0A000000) && + ((val & 0x0A000000) != 0x0A000000)) { + artist_invalidate(s); + } + /* Invalidate and redraw screen if graphics signal is turned back on. */ + if (((oldval & 0x0A000000) != 0x0A000000) && + ((val & 0x0A000000) == 0x0A000000)) { + artist_invalidate(s); + } + break; + + case MISC_CTRL: + combine_write_reg(addr, val, size, &s->misc_ctrl); break; case CURSOR_POS: @@ -1087,7 +1130,7 @@ static uint64_t combine_read_reg(hwaddr addr, int size, void *in) * FIXME: is there a qemu helper for this? */ -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN addr ^= 3; #endif @@ -1127,12 +1170,11 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) case 0x100000: case 0x300000: case 0x300004: - case 0x300308: case 0x380000: break; - case 0x300008: - case 0x380008: + case FIFO1: + case FIFO2: /* * FIFO ready flag. we're not emulating the FIFOs * so we're always ready @@ -1140,16 +1182,28 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) val = 0x10; break; - case 0x300200: - val = s->reg_300200; + case HORIZ_BACKPORCH: + val = s->horiz_backporch; + break; + + case ACTIVE_LINES_LOW: + val = s->active_lines_low; + /* activeLinesLo for cursor is in reg20.b.b0 */ + val &= ~(0xff << 24); + val |= (s->height & 0xff) << 24; break; - case 0x300208: - val = s->reg_300208; + case MISC_VIDEO: + /* emulate V-blank */ + s->misc_video ^= 0x00040000; + /* activeLinesHi for cursor is in reg21.b.b2 */ + val = s->misc_video; + val &= ~0xff00UL; + val |= (s->height & 0xff00); break; - case 0x300218: - val = s->reg_300218; + case MISC_CTRL: + val = s->misc_ctrl; break; case 0x30023c: @@ -1194,6 +1248,10 @@ static void artist_draw_cursor(ARTISTState *s) struct vram_buffer *cursor0, *cursor1 , *buf; int cx, cy, cursor_pos_x, cursor_pos_y; + if (!cursor_visible(s)) { + return; + } + cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1]; cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2]; buf = &s->vram_buffer[ARTIST_BUFFER_AP]; @@ -1225,6 +1283,12 @@ static void artist_draw_cursor(ARTISTState *s) } } +static bool artist_screen_enabled(ARTISTState *s) +{ + /* We could check for (s->misc_ctrl & 0x00800000) too... */ + return ((s->misc_video & 0x0A000000) == 0x0A000000); +} + static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src, int width, int pitch) { @@ -1232,6 +1296,12 @@ static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src, uint32_t *cmap, *data = (uint32_t *)d; int x; + if (!artist_screen_enabled(s)) { + /* clear screen */ + memset(data, 0, s->width * sizeof(uint32_t)); + return; + } + cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400); for (x = 0; x < s->width; x++) { @@ -1245,20 +1315,22 @@ static void artist_update_display(void *opaque) DisplaySurface *surface = qemu_console_surface(s->con); int first = 0, last; - framebuffer_update_display(surface, &s->fbsection, s->width, s->height, s->width, s->width * 4, 0, 0, artist_draw_line, s, &first, &last); artist_draw_cursor(s); - dpy_gfx_update(s->con, 0, 0, s->width, s->height); + if (first >= 0) { + dpy_gfx_update(s->con, 0, first, s->width, last - first + 1); + } } static void artist_invalidate(void *opaque) { ARTISTState *s = ARTIST(opaque); struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP]; + memory_region_set_dirty(&buf->mr, 0, buf->size); } @@ -1286,7 +1358,7 @@ static void artist_create_buffer(ARTISTState *s, const char *name, { struct vram_buffer *buf = s->vram_buffer + idx; - memory_region_init_ram(&buf->mr, NULL, name, width * height, + memory_region_init_ram(&buf->mr, OBJECT(s), name, width * height, &error_fatal); memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0); @@ -1331,11 +1403,10 @@ static void artist_realizefn(DeviceState *dev, Error **errp) framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0, buf->width, buf->height); /* - * no idea whether the cursor is fixed size or not, so assume 32x32 which - * seems sufficient for HP-UX X11. + * Artist cursor max size */ - s->cursor_height = 32; - s->cursor_width = 32; + s->cursor_height = NGLE_MAX_SPRITE_SIZE; + s->cursor_width = NGLE_MAX_SPRITE_SIZE; /* * These two registers are not initialized by seabios's STI implementation. @@ -1345,6 +1416,10 @@ static void artist_realizefn(DeviceState *dev, Error **errp) s->image_bitmap_op = 0x23000300; s->plane_mask = 0xff; + /* enable screen */ + s->misc_video |= 0x0A000000; + s->misc_ctrl |= 0x00800000; + s->con = graphic_console_init(dev, 0, &artist_ops, s); qemu_console_resize(s->con, s->width, s->height); } @@ -1383,9 +1458,10 @@ static const VMStateDescription vmstate_artist = { VMSTATE_UINT32(cursor_width, ARTISTState), VMSTATE_UINT32(plane_mask, ARTISTState), VMSTATE_UINT32(reg_100080, ARTISTState), - VMSTATE_UINT32(reg_300200, ARTISTState), - VMSTATE_UINT32(reg_300208, ARTISTState), - VMSTATE_UINT32(reg_300218, ARTISTState), + VMSTATE_UINT32(horiz_backporch, ARTISTState), + VMSTATE_UINT32(active_lines_low, ARTISTState), + VMSTATE_UINT32(misc_video, ARTISTState), + VMSTATE_UINT32(misc_ctrl, ARTISTState), VMSTATE_UINT32(dst_bm_access, ARTISTState), VMSTATE_UINT32(src_bm_access, ARTISTState), VMSTATE_UINT32(control_plane, ARTISTState), diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index 4dc10ea79529..7d786653e870 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -12,6 +12,7 @@ #include "ati_regs.h" #include "qemu/log.h" #include "ui/pixel_ops.h" +#include "ui/console.h" /* * NOTE: @@ -84,7 +85,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 +181,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/ati_int.h b/hw/display/ati_int.h index 8acb9c746697..e8d3c7af7521 100644 --- a/hw/display/ati_int.h +++ b/hw/display/ati_int.h @@ -10,7 +10,7 @@ #define ATI_INT_H #include "qemu/timer.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/i2c/bitbang_i2c.h" #include "vga_int.h" #include "qom/object.h" diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index 088fc3d51c59..a05277674f2c 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/blizzard.c b/hw/display/blizzard.c index 105241577de1..030abbe7d4da 100644 --- a/hw/display/blizzard.c +++ b/hw/display/blizzard.c @@ -123,14 +123,14 @@ typedef struct { /* Bytes(!) per pixel */ static const int blizzard_iformat_bpp[0x10] = { 0, - 2, /* RGB 5:6:5*/ - 3, /* RGB 6:6:6 mode 1 */ - 3, /* RGB 8:8:8 mode 1 */ + 2, /* RGB 5:6:5*/ + 3, /* RGB 6:6:6 mode 1 */ + 3, /* RGB 8:8:8 mode 1 */ 0, 0, - 4, /* RGB 6:6:6 mode 2 */ - 4, /* RGB 8:8:8 mode 2 */ - 0, /* YUV 4:2:2 */ - 0, /* YUV 4:2:0 */ + 4, /* RGB 6:6:6 mode 2 */ + 4, /* RGB 8:8:8 mode 2 */ + 0, /* YUV 4:2:2 */ + 0, /* YUV 4:2:0 */ 0, 0, 0, 0, 0, 0, }; @@ -281,196 +281,196 @@ static uint16_t blizzard_reg_read(void *opaque, uint8_t reg) BlizzardState *s = (BlizzardState *) opaque; switch (reg) { - case 0x00: /* Revision Code */ + case 0x00: /* Revision Code */ return 0xa5; - case 0x02: /* Configuration Readback */ - return 0x83; /* Macrovision OK, CNF[2:0] = 3 */ + case 0x02: /* Configuration Readback */ + return 0x83; /* Macrovision OK, CNF[2:0] = 3 */ - case 0x04: /* PLL M-Divider */ + case 0x04: /* PLL M-Divider */ return (s->pll - 1) | (1 << 7); - case 0x06: /* PLL Lock Range Control */ + case 0x06: /* PLL Lock Range Control */ return s->pll_range; - case 0x08: /* PLL Lock Synthesis Control 0 */ + case 0x08: /* PLL Lock Synthesis Control 0 */ return s->pll_ctrl & 0xff; - case 0x0a: /* PLL Lock Synthesis Control 1 */ + case 0x0a: /* PLL Lock Synthesis Control 1 */ return s->pll_ctrl >> 8; - case 0x0c: /* PLL Mode Control 0 */ + case 0x0c: /* PLL Mode Control 0 */ return s->pll_mode; - case 0x0e: /* Clock-Source Select */ + case 0x0e: /* Clock-Source Select */ return s->clksel; - case 0x10: /* Memory Controller Activate */ - case 0x14: /* Memory Controller Bank 0 Status Flag */ + case 0x10: /* Memory Controller Activate */ + case 0x14: /* Memory Controller Bank 0 Status Flag */ return s->memenable; - case 0x18: /* Auto-Refresh Interval Setting 0 */ + case 0x18: /* Auto-Refresh Interval Setting 0 */ return s->memrefresh & 0xff; - case 0x1a: /* Auto-Refresh Interval Setting 1 */ + case 0x1a: /* Auto-Refresh Interval Setting 1 */ return s->memrefresh >> 8; - case 0x1c: /* Power-On Sequence Timing Control */ + case 0x1c: /* Power-On Sequence Timing Control */ return s->timing[0]; - case 0x1e: /* Timing Control 0 */ + case 0x1e: /* Timing Control 0 */ return s->timing[1]; - case 0x20: /* Timing Control 1 */ + case 0x20: /* Timing Control 1 */ return s->timing[2]; - case 0x24: /* Arbitration Priority Control */ + case 0x24: /* Arbitration Priority Control */ return s->priority; - case 0x28: /* LCD Panel Configuration */ + case 0x28: /* LCD Panel Configuration */ return s->lcd_config; - case 0x2a: /* LCD Horizontal Display Width */ + case 0x2a: /* LCD Horizontal Display Width */ return s->x >> 3; - case 0x2c: /* LCD Horizontal Non-display Period */ + case 0x2c: /* LCD Horizontal Non-display Period */ return s->hndp; - case 0x2e: /* LCD Vertical Display Height 0 */ + case 0x2e: /* LCD Vertical Display Height 0 */ return s->y & 0xff; - case 0x30: /* LCD Vertical Display Height 1 */ + case 0x30: /* LCD Vertical Display Height 1 */ return s->y >> 8; - case 0x32: /* LCD Vertical Non-display Period */ + case 0x32: /* LCD Vertical Non-display Period */ return s->vndp; - case 0x34: /* LCD HS Pulse-width */ + case 0x34: /* LCD HS Pulse-width */ return s->hsync; - case 0x36: /* LCd HS Pulse Start Position */ + case 0x36: /* LCd HS Pulse Start Position */ return s->skipx >> 3; - case 0x38: /* LCD VS Pulse-width */ + case 0x38: /* LCD VS Pulse-width */ return s->vsync; - case 0x3a: /* LCD VS Pulse Start Position */ + case 0x3a: /* LCD VS Pulse Start Position */ return s->skipy; - case 0x3c: /* PCLK Polarity */ + case 0x3c: /* PCLK Polarity */ return s->pclk; - case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ + case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ return s->hssi_config[0]; - case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ + case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ return s->hssi_config[1]; - case 0x42: /* High-speed Serial Interface Tx Mode */ + case 0x42: /* High-speed Serial Interface Tx Mode */ return s->hssi_config[2]; - case 0x44: /* TV Display Configuration */ + case 0x44: /* TV Display Configuration */ return s->tv_config; - case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */ + case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */ return s->tv_timing[(reg - 0x46) >> 1]; - case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ + case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ return s->vbi; - case 0x50: /* TV Horizontal Start Position */ + case 0x50: /* TV Horizontal Start Position */ return s->tv_x; - case 0x52: /* TV Vertical Start Position */ + case 0x52: /* TV Vertical Start Position */ return s->tv_y; - case 0x54: /* TV Test Pattern Setting */ + case 0x54: /* TV Test Pattern Setting */ return s->tv_test; - case 0x56: /* TV Filter Setting */ + case 0x56: /* TV Filter Setting */ return s->tv_filter_config; - case 0x58: /* TV Filter Coefficient Index */ + case 0x58: /* TV Filter Coefficient Index */ return s->tv_filter_idx; - case 0x5a: /* TV Filter Coefficient Data */ + case 0x5a: /* TV Filter Coefficient Data */ if (s->tv_filter_idx < 0x20) return s->tv_filter_coeff[s->tv_filter_idx ++]; return 0; - case 0x60: /* Input YUV/RGB Translate Mode 0 */ + case 0x60: /* Input YUV/RGB Translate Mode 0 */ return s->yrc[0]; - case 0x62: /* Input YUV/RGB Translate Mode 1 */ + case 0x62: /* Input YUV/RGB Translate Mode 1 */ return s->yrc[1]; - case 0x64: /* U Data Fix */ + case 0x64: /* U Data Fix */ return s->u; - case 0x66: /* V Data Fix */ + case 0x66: /* V Data Fix */ return s->v; - case 0x68: /* Display Mode */ + case 0x68: /* Display Mode */ return s->mode; - case 0x6a: /* Special Effects */ + case 0x6a: /* Special Effects */ return s->effect; - case 0x6c: /* Input Window X Start Position 0 */ + case 0x6c: /* Input Window X Start Position 0 */ return s->ix[0] & 0xff; - case 0x6e: /* Input Window X Start Position 1 */ + case 0x6e: /* Input Window X Start Position 1 */ return s->ix[0] >> 3; - case 0x70: /* Input Window Y Start Position 0 */ + case 0x70: /* Input Window Y Start Position 0 */ return s->ix[0] & 0xff; - case 0x72: /* Input Window Y Start Position 1 */ + case 0x72: /* Input Window Y Start Position 1 */ return s->ix[0] >> 3; - case 0x74: /* Input Window X End Position 0 */ + case 0x74: /* Input Window X End Position 0 */ return s->ix[1] & 0xff; - case 0x76: /* Input Window X End Position 1 */ + case 0x76: /* Input Window X End Position 1 */ return s->ix[1] >> 3; - case 0x78: /* Input Window Y End Position 0 */ + case 0x78: /* Input Window Y End Position 0 */ return s->ix[1] & 0xff; - case 0x7a: /* Input Window Y End Position 1 */ + case 0x7a: /* Input Window Y End Position 1 */ return s->ix[1] >> 3; - case 0x7c: /* Output Window X Start Position 0 */ + case 0x7c: /* Output Window X Start Position 0 */ return s->ox[0] & 0xff; - case 0x7e: /* Output Window X Start Position 1 */ + case 0x7e: /* Output Window X Start Position 1 */ return s->ox[0] >> 3; - case 0x80: /* Output Window Y Start Position 0 */ + case 0x80: /* Output Window Y Start Position 0 */ return s->oy[0] & 0xff; - case 0x82: /* Output Window Y Start Position 1 */ + case 0x82: /* Output Window Y Start Position 1 */ return s->oy[0] >> 3; - case 0x84: /* Output Window X End Position 0 */ + case 0x84: /* Output Window X End Position 0 */ return s->ox[1] & 0xff; - case 0x86: /* Output Window X End Position 1 */ + case 0x86: /* Output Window X End Position 1 */ return s->ox[1] >> 3; - case 0x88: /* Output Window Y End Position 0 */ + case 0x88: /* Output Window Y End Position 0 */ return s->oy[1] & 0xff; - case 0x8a: /* Output Window Y End Position 1 */ + case 0x8a: /* Output Window Y End Position 1 */ return s->oy[1] >> 3; - case 0x8c: /* Input Data Format */ + case 0x8c: /* Input Data Format */ return s->iformat; - case 0x8e: /* Data Source Select */ + case 0x8e: /* Data Source Select */ return s->source; - case 0x90: /* Display Memory Data Port */ + case 0x90: /* Display Memory Data Port */ return 0; - case 0xa8: /* Border Color 0 */ + case 0xa8: /* Border Color 0 */ return s->border_r; - case 0xaa: /* Border Color 1 */ + case 0xaa: /* Border Color 1 */ return s->border_g; - case 0xac: /* Border Color 2 */ + case 0xac: /* Border Color 2 */ return s->border_b; - case 0xb4: /* Gamma Correction Enable */ + case 0xb4: /* Gamma Correction Enable */ return s->gamma_config; - case 0xb6: /* Gamma Correction Table Index */ + case 0xb6: /* Gamma Correction Table Index */ return s->gamma_idx; - case 0xb8: /* Gamma Correction Table Data */ + case 0xb8: /* Gamma Correction Table Data */ return s->gamma_lut[s->gamma_idx ++]; - case 0xba: /* 3x3 Matrix Enable */ + case 0xba: /* 3x3 Matrix Enable */ return s->matrix_ena; - case 0xbc ... 0xde: /* Coefficient Registers */ + case 0xbc ... 0xde: /* Coefficient Registers */ return s->matrix_coeff[(reg - 0xbc) >> 1]; - case 0xe0: /* 3x3 Matrix Red Offset */ + case 0xe0: /* 3x3 Matrix Red Offset */ return s->matrix_r; - case 0xe2: /* 3x3 Matrix Green Offset */ + case 0xe2: /* 3x3 Matrix Green Offset */ return s->matrix_g; - case 0xe4: /* 3x3 Matrix Blue Offset */ + case 0xe4: /* 3x3 Matrix Blue Offset */ return s->matrix_b; - case 0xe6: /* Power-save */ + case 0xe6: /* Power-save */ return s->pm; - case 0xe8: /* Non-display Period Control / Status */ + case 0xe8: /* Non-display Period Control / Status */ return s->status | (1 << 5); - case 0xea: /* RGB Interface Control */ + case 0xea: /* RGB Interface Control */ return s->rgbgpio_dir; - case 0xec: /* RGB Interface Status */ + case 0xec: /* RGB Interface Status */ return s->rgbgpio; - case 0xee: /* General-purpose IO Pins Configuration */ + case 0xee: /* General-purpose IO Pins Configuration */ return s->gpio_dir; - case 0xf0: /* General-purpose IO Pins Status / Control */ + case 0xf0: /* General-purpose IO Pins Status / Control */ return s->gpio; - case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ + case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ return s->gpio_edge[0]; - case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ + case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ return s->gpio_edge[1]; - case 0xf6: /* GPIO Interrupt Status */ + case 0xf6: /* GPIO Interrupt Status */ return s->gpio_irq; - case 0xf8: /* GPIO Pull-down Control */ + case 0xf8: /* GPIO Pull-down Control */ return s->gpio_pdown; default: @@ -484,157 +484,157 @@ static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) BlizzardState *s = (BlizzardState *) opaque; switch (reg) { - case 0x04: /* PLL M-Divider */ + case 0x04: /* PLL M-Divider */ s->pll = (value & 0x3f) + 1; break; - case 0x06: /* PLL Lock Range Control */ + case 0x06: /* PLL Lock Range Control */ s->pll_range = value & 3; break; - case 0x08: /* PLL Lock Synthesis Control 0 */ + case 0x08: /* PLL Lock Synthesis Control 0 */ s->pll_ctrl &= 0xf00; s->pll_ctrl |= (value << 0) & 0x0ff; break; - case 0x0a: /* PLL Lock Synthesis Control 1 */ + case 0x0a: /* PLL Lock Synthesis Control 1 */ s->pll_ctrl &= 0x0ff; s->pll_ctrl |= (value << 8) & 0xf00; break; - case 0x0c: /* PLL Mode Control 0 */ + case 0x0c: /* PLL Mode Control 0 */ s->pll_mode = value & 0x77; if ((value & 3) == 0 || (value & 3) == 3) fprintf(stderr, "%s: wrong PLL Control bits (%i)\n", __func__, value & 3); break; - case 0x0e: /* Clock-Source Select */ + case 0x0e: /* Clock-Source Select */ s->clksel = value & 0xff; break; - case 0x10: /* Memory Controller Activate */ + case 0x10: /* Memory Controller Activate */ s->memenable = value & 1; break; - case 0x14: /* Memory Controller Bank 0 Status Flag */ + case 0x14: /* Memory Controller Bank 0 Status Flag */ break; - case 0x18: /* Auto-Refresh Interval Setting 0 */ + case 0x18: /* Auto-Refresh Interval Setting 0 */ s->memrefresh &= 0xf00; s->memrefresh |= (value << 0) & 0x0ff; break; - case 0x1a: /* Auto-Refresh Interval Setting 1 */ + case 0x1a: /* Auto-Refresh Interval Setting 1 */ s->memrefresh &= 0x0ff; s->memrefresh |= (value << 8) & 0xf00; break; - case 0x1c: /* Power-On Sequence Timing Control */ + case 0x1c: /* Power-On Sequence Timing Control */ s->timing[0] = value & 0x7f; break; - case 0x1e: /* Timing Control 0 */ + case 0x1e: /* Timing Control 0 */ s->timing[1] = value & 0x17; break; - case 0x20: /* Timing Control 1 */ + case 0x20: /* Timing Control 1 */ s->timing[2] = value & 0x35; break; - case 0x24: /* Arbitration Priority Control */ + case 0x24: /* Arbitration Priority Control */ s->priority = value & 1; break; - case 0x28: /* LCD Panel Configuration */ + case 0x28: /* LCD Panel Configuration */ s->lcd_config = value & 0xff; if (value & (1 << 7)) fprintf(stderr, "%s: data swap not supported!\n", __func__); break; - case 0x2a: /* LCD Horizontal Display Width */ + case 0x2a: /* LCD Horizontal Display Width */ s->x = value << 3; break; - case 0x2c: /* LCD Horizontal Non-display Period */ + case 0x2c: /* LCD Horizontal Non-display Period */ s->hndp = value & 0xff; break; - case 0x2e: /* LCD Vertical Display Height 0 */ + case 0x2e: /* LCD Vertical Display Height 0 */ s->y &= 0x300; s->y |= (value << 0) & 0x0ff; break; - case 0x30: /* LCD Vertical Display Height 1 */ + case 0x30: /* LCD Vertical Display Height 1 */ s->y &= 0x0ff; s->y |= (value << 8) & 0x300; break; - case 0x32: /* LCD Vertical Non-display Period */ + case 0x32: /* LCD Vertical Non-display Period */ s->vndp = value & 0xff; break; - case 0x34: /* LCD HS Pulse-width */ + case 0x34: /* LCD HS Pulse-width */ s->hsync = value & 0xff; break; - case 0x36: /* LCD HS Pulse Start Position */ + case 0x36: /* LCD HS Pulse Start Position */ s->skipx = value & 0xff; break; - case 0x38: /* LCD VS Pulse-width */ + case 0x38: /* LCD VS Pulse-width */ s->vsync = value & 0xbf; break; - case 0x3a: /* LCD VS Pulse Start Position */ + case 0x3a: /* LCD VS Pulse Start Position */ s->skipy = value & 0xff; break; - case 0x3c: /* PCLK Polarity */ + case 0x3c: /* PCLK Polarity */ s->pclk = value & 0x82; /* Affects calculation of s->hndp, s->hsync and s->skipx. */ break; - case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ + case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ s->hssi_config[0] = value; break; - case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ + case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ s->hssi_config[1] = value; if (((value >> 4) & 3) == 3) fprintf(stderr, "%s: Illegal active-data-links value\n", __func__); break; - case 0x42: /* High-speed Serial Interface Tx Mode */ + case 0x42: /* High-speed Serial Interface Tx Mode */ s->hssi_config[2] = value & 0xbd; break; - case 0x44: /* TV Display Configuration */ + case 0x44: /* TV Display Configuration */ s->tv_config = value & 0xfe; break; - case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */ + case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */ s->tv_timing[(reg - 0x46) >> 1] = value; break; - case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ + case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ s->vbi = value; break; - case 0x50: /* TV Horizontal Start Position */ + case 0x50: /* TV Horizontal Start Position */ s->tv_x = value; break; - case 0x52: /* TV Vertical Start Position */ + case 0x52: /* TV Vertical Start Position */ s->tv_y = value & 0x7f; break; - case 0x54: /* TV Test Pattern Setting */ + case 0x54: /* TV Test Pattern Setting */ s->tv_test = value; break; - case 0x56: /* TV Filter Setting */ + case 0x56: /* TV Filter Setting */ s->tv_filter_config = value & 0xbf; break; - case 0x58: /* TV Filter Coefficient Index */ + case 0x58: /* TV Filter Coefficient Index */ s->tv_filter_idx = value & 0x1f; break; - case 0x5a: /* TV Filter Coefficient Data */ + case 0x5a: /* TV Filter Coefficient Data */ if (s->tv_filter_idx < 0x20) s->tv_filter_coeff[s->tv_filter_idx ++] = value; break; - case 0x60: /* Input YUV/RGB Translate Mode 0 */ + case 0x60: /* Input YUV/RGB Translate Mode 0 */ s->yrc[0] = value & 0xb0; break; - case 0x62: /* Input YUV/RGB Translate Mode 1 */ + case 0x62: /* Input YUV/RGB Translate Mode 1 */ s->yrc[1] = value & 0x30; break; - case 0x64: /* U Data Fix */ + case 0x64: /* U Data Fix */ s->u = value & 0xff; break; - case 0x66: /* V Data Fix */ + case 0x66: /* V Data Fix */ s->v = value & 0xff; break; - case 0x68: /* Display Mode */ + case 0x68: /* Display Mode */ if ((s->mode ^ value) & 3) s->invalidate = 1; s->mode = value & 0xb7; @@ -644,83 +644,83 @@ static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) fprintf(stderr, "%s: Macrovision enable attempt!\n", __func__); break; - case 0x6a: /* Special Effects */ + case 0x6a: /* Special Effects */ s->effect = value & 0xfb; break; - case 0x6c: /* Input Window X Start Position 0 */ + case 0x6c: /* Input Window X Start Position 0 */ s->ix[0] &= 0x300; s->ix[0] |= (value << 0) & 0x0ff; break; - case 0x6e: /* Input Window X Start Position 1 */ + case 0x6e: /* Input Window X Start Position 1 */ s->ix[0] &= 0x0ff; s->ix[0] |= (value << 8) & 0x300; break; - case 0x70: /* Input Window Y Start Position 0 */ + case 0x70: /* Input Window Y Start Position 0 */ s->iy[0] &= 0x300; s->iy[0] |= (value << 0) & 0x0ff; break; - case 0x72: /* Input Window Y Start Position 1 */ + case 0x72: /* Input Window Y Start Position 1 */ s->iy[0] &= 0x0ff; s->iy[0] |= (value << 8) & 0x300; break; - case 0x74: /* Input Window X End Position 0 */ + case 0x74: /* Input Window X End Position 0 */ s->ix[1] &= 0x300; s->ix[1] |= (value << 0) & 0x0ff; break; - case 0x76: /* Input Window X End Position 1 */ + case 0x76: /* Input Window X End Position 1 */ s->ix[1] &= 0x0ff; s->ix[1] |= (value << 8) & 0x300; break; - case 0x78: /* Input Window Y End Position 0 */ + case 0x78: /* Input Window Y End Position 0 */ s->iy[1] &= 0x300; s->iy[1] |= (value << 0) & 0x0ff; break; - case 0x7a: /* Input Window Y End Position 1 */ + case 0x7a: /* Input Window Y End Position 1 */ s->iy[1] &= 0x0ff; s->iy[1] |= (value << 8) & 0x300; break; - case 0x7c: /* Output Window X Start Position 0 */ + case 0x7c: /* Output Window X Start Position 0 */ s->ox[0] &= 0x300; s->ox[0] |= (value << 0) & 0x0ff; break; - case 0x7e: /* Output Window X Start Position 1 */ + case 0x7e: /* Output Window X Start Position 1 */ s->ox[0] &= 0x0ff; s->ox[0] |= (value << 8) & 0x300; break; - case 0x80: /* Output Window Y Start Position 0 */ + case 0x80: /* Output Window Y Start Position 0 */ s->oy[0] &= 0x300; s->oy[0] |= (value << 0) & 0x0ff; break; - case 0x82: /* Output Window Y Start Position 1 */ + case 0x82: /* Output Window Y Start Position 1 */ s->oy[0] &= 0x0ff; s->oy[0] |= (value << 8) & 0x300; break; - case 0x84: /* Output Window X End Position 0 */ + case 0x84: /* Output Window X End Position 0 */ s->ox[1] &= 0x300; s->ox[1] |= (value << 0) & 0x0ff; break; - case 0x86: /* Output Window X End Position 1 */ + case 0x86: /* Output Window X End Position 1 */ s->ox[1] &= 0x0ff; s->ox[1] |= (value << 8) & 0x300; break; - case 0x88: /* Output Window Y End Position 0 */ + case 0x88: /* Output Window Y End Position 0 */ s->oy[1] &= 0x300; s->oy[1] |= (value << 0) & 0x0ff; break; - case 0x8a: /* Output Window Y End Position 1 */ + case 0x8a: /* Output Window Y End Position 1 */ s->oy[1] &= 0x0ff; s->oy[1] |= (value << 8) & 0x300; break; - case 0x8c: /* Input Data Format */ + case 0x8c: /* Input Data Format */ s->iformat = value & 0xf; s->bpp = blizzard_iformat_bpp[s->iformat]; if (!s->bpp) fprintf(stderr, "%s: Illegal or unsupported input format %x\n", __func__, s->iformat); break; - case 0x8e: /* Data Source Select */ + case 0x8e: /* Data Source Select */ s->source = value & 7; /* Currently all windows will be "destructive overlays". */ if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] || @@ -735,7 +735,7 @@ static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) blizzard_transfer_setup(s); break; - case 0x90: /* Display Memory Data Port */ + case 0x90: /* Display Memory Data Port */ if (!s->data.len && !blizzard_transfer_setup(s)) break; @@ -744,73 +744,73 @@ static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) blizzard_window(s); break; - case 0xa8: /* Border Color 0 */ + case 0xa8: /* Border Color 0 */ s->border_r = value; break; - case 0xaa: /* Border Color 1 */ + case 0xaa: /* Border Color 1 */ s->border_g = value; break; - case 0xac: /* Border Color 2 */ + case 0xac: /* Border Color 2 */ s->border_b = value; break; - case 0xb4: /* Gamma Correction Enable */ + case 0xb4: /* Gamma Correction Enable */ s->gamma_config = value & 0x87; break; - case 0xb6: /* Gamma Correction Table Index */ + case 0xb6: /* Gamma Correction Table Index */ s->gamma_idx = value; break; - case 0xb8: /* Gamma Correction Table Data */ + case 0xb8: /* Gamma Correction Table Data */ s->gamma_lut[s->gamma_idx ++] = value; break; - case 0xba: /* 3x3 Matrix Enable */ + case 0xba: /* 3x3 Matrix Enable */ s->matrix_ena = value & 1; break; - case 0xbc ... 0xde: /* Coefficient Registers */ + case 0xbc ... 0xde: /* Coefficient Registers */ s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff); break; - case 0xe0: /* 3x3 Matrix Red Offset */ + case 0xe0: /* 3x3 Matrix Red Offset */ s->matrix_r = value; break; - case 0xe2: /* 3x3 Matrix Green Offset */ + case 0xe2: /* 3x3 Matrix Green Offset */ s->matrix_g = value; break; - case 0xe4: /* 3x3 Matrix Blue Offset */ + case 0xe4: /* 3x3 Matrix Blue Offset */ s->matrix_b = value; break; - case 0xe6: /* Power-save */ + case 0xe6: /* Power-save */ s->pm = value & 0x83; if (value & s->mode & 1) fprintf(stderr, "%s: The display must be disabled before entering " "Standby Mode\n", __func__); break; - case 0xe8: /* Non-display Period Control / Status */ + case 0xe8: /* Non-display Period Control / Status */ s->status = value & 0x1b; break; - case 0xea: /* RGB Interface Control */ + case 0xea: /* RGB Interface Control */ s->rgbgpio_dir = value & 0x8f; break; - case 0xec: /* RGB Interface Status */ + case 0xec: /* RGB Interface Status */ s->rgbgpio = value & 0xcf; break; - case 0xee: /* General-purpose IO Pins Configuration */ + case 0xee: /* General-purpose IO Pins Configuration */ s->gpio_dir = value; break; - case 0xf0: /* General-purpose IO Pins Status / Control */ + case 0xf0: /* General-purpose IO Pins Status / Control */ s->gpio = value; break; - case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ + case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ s->gpio_edge[0] = value; break; - case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ + case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ s->gpio_edge[1] = value; break; - case 0xf6: /* GPIO Interrupt Status */ + case 0xf6: /* GPIO Interrupt Status */ s->gpio_irq &= value; break; - case 0xf8: /* GPIO Pull-down Control */ + case 0xf8: /* GPIO Pull-down Control */ s->gpio_pdown = value; break; @@ -1007,7 +1007,7 @@ static const GraphicHwOps blizzard_ops = { void *s1d13745_init(qemu_irq gpio_int) { - BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s)); + BlizzardState *s = g_malloc0(sizeof(*s)); DisplaySurface *surface; s->fb = g_malloc(0x180000); diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 8ed734b19568..e7ec268184d1 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "qemu/units.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/display/bochs-vbe.h" diff --git a/hw/display/cg3.c b/hw/display/cg3.c index 4b7e78d91924..2e9656ae1c39 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "qemu/error-report.h" diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 3bb6a58698c1..55c32e3e406f 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -39,12 +39,13 @@ #include "sysemu/reset.h" #include "qapi/error.h" #include "trace.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "ui/pixel_ops.h" #include "cirrus_vga_internal.h" #include "qom/object.h" +#include "ui/console.h" /* * TODO: @@ -76,12 +77,12 @@ #define CIRRUS_MEMSIZE_512k 0x08 #define CIRRUS_MEMSIZE_1M 0x10 #define CIRRUS_MEMSIZE_2M 0x18 -#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled. +#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled. // sequencer 0x12 #define CIRRUS_CURSOR_SHOW 0x01 #define CIRRUS_CURSOR_HIDDENPEL 0x02 -#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear +#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear // sequencer 0x17 #define CIRRUS_BUSTYPE_VLBFAST 0x10 @@ -89,12 +90,12 @@ #define CIRRUS_BUSTYPE_VLBSLOW 0x30 #define CIRRUS_BUSTYPE_ISA 0x38 #define CIRRUS_MMIO_ENABLE 0x04 -#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared. +#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared. #define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 // control 0x0b #define CIRRUS_BANKING_DUAL 0x01 -#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k +#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k // control 0x30 #define CIRRUS_BLTMODE_BACKWARDS 0x01 @@ -143,35 +144,35 @@ #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 // memory-mapped IO -#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword -#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword -#define CIRRUS_MMIO_BLTWIDTH 0x08 // word -#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word -#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word -#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word -#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword -#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword -#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte -#define CIRRUS_MMIO_BLTMODE 0x18 // byte -#define CIRRUS_MMIO_BLTROP 0x1a // byte -#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte -#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word? -#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word? -#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word -#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word -#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word -#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte -#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word -#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word -#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word -#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word -#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte -#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte -#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte +#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword +#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword +#define CIRRUS_MMIO_BLTWIDTH 0x08 // word +#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word +#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word +#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word +#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword +#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword +#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte +#define CIRRUS_MMIO_BLTMODE 0x18 // byte +#define CIRRUS_MMIO_BLTROP 0x1a // byte +#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte +#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word? +#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word? +#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word +#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word +#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word +#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte +#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word +#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word +#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word +#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word +#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte +#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte +#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte #define CIRRUS_PNPMMIO_SIZE 0x1000 @@ -628,8 +629,8 @@ static inline void cirrus_bitblt_bgcol(CirrusVGAState *s) } static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, - int off_pitch, int bytesperline, - int lines) + int off_pitch, int bytesperline, + int lines) { int y; int off_cur; @@ -708,8 +709,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); cirrus_bitblt_reset(s); return 1; } @@ -773,8 +774,8 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) (*s->cirrus_rop) (s, s->cirrus_blt_dstaddr, s->cirrus_blt_srcaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); if (notify) { dpy_gfx_update(s->vga.con, dx, dy, @@ -786,8 +787,8 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) changed since qemu_console_copy implies this */ cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); return 1; } @@ -834,7 +835,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) word alignment, so we keep them for the next line */ /* XXX: keep alignment to speed up transfer */ end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; - copy_count = s->cirrus_srcptr_end - end_ptr; + copy_count = MIN(s->cirrus_srcptr_end - end_ptr, CIRRUS_BLTBUFSIZE); memmove(s->cirrus_bltbuf, end_ptr, copy_count); s->cirrus_srcptr = s->cirrus_bltbuf + copy_count; s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; @@ -854,7 +855,7 @@ static void cirrus_bitblt_reset(CirrusVGAState * s) int need_update; s->vga.gr[0x31] &= - ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED); + ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED); need_update = s->cirrus_srcptr != &s->cirrus_bltbuf[0] || s->cirrus_srcptr_end != &s->cirrus_bltbuf[0]; s->cirrus_srcptr = &s->cirrus_bltbuf[0]; @@ -878,24 +879,24 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - s->cirrus_blt_srcpitch = 8; - } else { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + s->cirrus_blt_srcpitch = 8; + } else { /* XXX: check for 24 bpp */ - s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth; - } - s->cirrus_srccounter = s->cirrus_blt_srcpitch; + s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth; + } + s->cirrus_srccounter = s->cirrus_blt_srcpitch; } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth; if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) s->cirrus_blt_srcpitch = ((w + 31) >> 5); else s->cirrus_blt_srcpitch = ((w + 7) >> 3); - } else { + } else { /* always align input size to 32 bits */ - s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3; - } + s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3; + } s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height; } @@ -921,12 +922,12 @@ static int cirrus_bitblt_videotovideo(CirrusVGAState * s) int ret; if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - ret = cirrus_bitblt_videotovideo_patterncopy(s); + ret = cirrus_bitblt_videotovideo_patterncopy(s); } else { - ret = cirrus_bitblt_videotovideo_copy(s); + ret = cirrus_bitblt_videotovideo_copy(s); } if (ret) - cirrus_bitblt_reset(s); + cirrus_bitblt_reset(s); return ret; } @@ -945,9 +946,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_dstpitch = (s->vga.gr[0x24] | (s->vga.gr[0x25] << 8)); s->cirrus_blt_srcpitch = (s->vga.gr[0x26] | (s->vga.gr[0x27] << 8)); s->cirrus_blt_dstaddr = - (s->vga.gr[0x28] | (s->vga.gr[0x29] << 8) | (s->vga.gr[0x2a] << 16)); + (s->vga.gr[0x28] | (s->vga.gr[0x29] << 8) | (s->vga.gr[0x2a] << 16)); s->cirrus_blt_srcaddr = - (s->vga.gr[0x2c] | (s->vga.gr[0x2d] << 8) | (s->vga.gr[0x2e] << 16)); + (s->vga.gr[0x2c] | (s->vga.gr[0x2d] << 8) | (s->vga.gr[0x2e] << 16)); s->cirrus_blt_mode = s->vga.gr[0x30]; s->cirrus_blt_modeext = s->vga.gr[0x33]; blt_rop = s->vga.gr[0x32]; @@ -968,31 +969,31 @@ static void cirrus_bitblt_start(CirrusVGAState * s) switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: - s->cirrus_blt_pixelwidth = 1; - break; + s->cirrus_blt_pixelwidth = 1; + break; case CIRRUS_BLTMODE_PIXELWIDTH16: - s->cirrus_blt_pixelwidth = 2; - break; + s->cirrus_blt_pixelwidth = 2; + break; case CIRRUS_BLTMODE_PIXELWIDTH24: - s->cirrus_blt_pixelwidth = 3; - break; + s->cirrus_blt_pixelwidth = 3; + break; case CIRRUS_BLTMODE_PIXELWIDTH32: - s->cirrus_blt_pixelwidth = 4; - break; + s->cirrus_blt_pixelwidth = 4; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: bitblt - pixel width is unknown\n"); - goto bitblt_ignore; + goto bitblt_ignore; } s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK; if ((s-> - cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC | - CIRRUS_BLTMODE_MEMSYSDEST)) - == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) { + cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC | + CIRRUS_BLTMODE_MEMSYSDEST)) + == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) { qemu_log_mask(LOG_UNIMP, "cirrus: bitblt - memory-to-memory copy requested\n"); - goto bitblt_ignore; + goto bitblt_ignore; } if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) && @@ -1036,30 +1037,30 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { - if (s->cirrus_blt_pixelwidth > 2) { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + if (s->cirrus_blt_pixelwidth > 2) { qemu_log_mask(LOG_GUEST_ERROR, "cirrus: src transparent without colorexpand " "must be 8bpp or 16bpp\n"); - goto bitblt_ignore; - } - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } else { - s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } - } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; - } else { - s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; - } - } - } + goto bitblt_ignore; + } + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } else { + s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } + } else { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; + } else { + s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; + } + } + } // setup bitblt engine. if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { if (!cirrus_bitblt_cputovideo(s)) @@ -1085,11 +1086,11 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) s->vga.gr[0x31] = reg_value; if (((old_value & CIRRUS_BLT_RESET) != 0) && - ((reg_value & CIRRUS_BLT_RESET) == 0)) { - cirrus_bitblt_reset(s); + ((reg_value & CIRRUS_BLT_RESET) == 0)) { + cirrus_bitblt_reset(s); } else if (((old_value & CIRRUS_BLT_START) == 0) && - ((reg_value & CIRRUS_BLT_START) != 0)) { - cirrus_bitblt_start(s); + ((reg_value & CIRRUS_BLT_START) != 0)) { + cirrus_bitblt_start(s); } } @@ -1109,15 +1110,15 @@ static void cirrus_get_offsets(VGACommonState *s1, uint32_t start_addr, line_offset, line_compare; line_offset = s->vga.cr[0x13] - | ((s->vga.cr[0x1b] & 0x10) << 4); + | ((s->vga.cr[0x1b] & 0x10) << 4); line_offset <<= 3; *pline_offset = line_offset; start_addr = (s->vga.cr[0x0c] << 8) - | s->vga.cr[0x0d] - | ((s->vga.cr[0x1b] & 0x01) << 16) - | ((s->vga.cr[0x1b] & 0x0c) << 15) - | ((s->vga.cr[0x1d] & 0x80) << 12); + | s->vga.cr[0x0d] + | ((s->vga.cr[0x1b] & 0x01) << 16) + | ((s->vga.cr[0x1b] & 0x0c) << 15) + | ((s->vga.cr[0x1d] & 0x80) << 12); *pstart_addr = start_addr; line_compare = s->vga.cr[0x18] | @@ -1132,17 +1133,17 @@ static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s) switch (s->cirrus_hidden_dac_data & 0xf) { case 0: - ret = 15; - break; /* Sierra HiColor */ + ret = 15; + break; /* Sierra HiColor */ case 1: - ret = 16; - break; /* XGA HiColor */ + ret = 16; + break; /* XGA HiColor */ default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: invalid DAC value 0x%x in 16bpp\n", (s->cirrus_hidden_dac_data & 0xf)); - ret = 15; /* XXX */ - break; + ret = 15; /* XXX */ + break; } return ret; } @@ -1153,33 +1154,33 @@ static int cirrus_get_bpp(VGACommonState *s1) uint32_t ret = 8; if ((s->vga.sr[0x07] & 0x01) != 0) { - /* Cirrus SVGA */ - switch (s->vga.sr[0x07] & CIRRUS_SR7_BPP_MASK) { - case CIRRUS_SR7_BPP_8: - ret = 8; - break; - case CIRRUS_SR7_BPP_16_DOUBLEVCLK: - ret = cirrus_get_bpp16_depth(s); - break; - case CIRRUS_SR7_BPP_24: - ret = 24; - break; - case CIRRUS_SR7_BPP_16: - ret = cirrus_get_bpp16_depth(s); - break; - case CIRRUS_SR7_BPP_32: - ret = 32; - break; - default: + /* Cirrus SVGA */ + switch (s->vga.sr[0x07] & CIRRUS_SR7_BPP_MASK) { + case CIRRUS_SR7_BPP_8: + ret = 8; + break; + case CIRRUS_SR7_BPP_16_DOUBLEVCLK: + ret = cirrus_get_bpp16_depth(s); + break; + case CIRRUS_SR7_BPP_24: + ret = 24; + break; + case CIRRUS_SR7_BPP_16: + ret = cirrus_get_bpp16_depth(s); + break; + case CIRRUS_SR7_BPP_32: + ret = 32; + break; + default: #ifdef DEBUG_CIRRUS - printf("cirrus: unknown bpp - sr7=%x\n", s->vga.sr[0x7]); + printf("cirrus: unknown bpp - sr7=%x\n", s->vga.sr[0x7]); #endif - ret = 8; - break; - } + ret = 8; + break; + } } else { - /* VGA */ - ret = 0; + /* VGA */ + ret = 0; } return ret; @@ -1212,36 +1213,36 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) unsigned offset; unsigned limit; - if ((s->vga.gr[0x0b] & 0x01) != 0) /* dual bank */ - offset = s->vga.gr[0x09 + bank_index]; - else /* single bank */ - offset = s->vga.gr[0x09]; + if ((s->vga.gr[0x0b] & 0x01) != 0) /* dual bank */ + offset = s->vga.gr[0x09 + bank_index]; + else /* single bank */ + offset = s->vga.gr[0x09]; if ((s->vga.gr[0x0b] & 0x20) != 0) - offset <<= 14; + offset <<= 14; else - offset <<= 12; + offset <<= 12; if (s->real_vram_size <= offset) - limit = 0; + limit = 0; else - limit = s->real_vram_size - offset; + limit = s->real_vram_size - offset; if (((s->vga.gr[0x0b] & 0x01) == 0) && (bank_index != 0)) { - if (limit > 0x8000) { - offset += 0x8000; - limit -= 0x8000; - } else { - limit = 0; - } + if (limit > 0x8000) { + offset += 0x8000; + limit -= 0x8000; + } else { + limit = 0; + } } if (limit > 0) { - s->cirrus_bank_base[bank_index] = offset; - s->cirrus_bank_limit[bank_index] = limit; + s->cirrus_bank_base[bank_index] = offset; + s->cirrus_bank_limit[bank_index] = limit; } else { - s->cirrus_bank_base[bank_index] = 0; - s->cirrus_bank_limit[bank_index] = 0; + s->cirrus_bank_base[bank_index] = 0; + s->cirrus_bank_limit[bank_index] = 0; } } @@ -1254,148 +1255,148 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) static int cirrus_vga_read_sr(CirrusVGAState * s) { switch (s->vga.sr_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - return s->vga.sr[s->vga.sr_index]; - case 0x06: // Unlock Cirrus extensions - return s->vga.sr[s->vga.sr_index]; + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + return s->vga.sr[s->vga.sr_index]; + case 0x06: // Unlock Cirrus extensions + return s->vga.sr[s->vga.sr_index]; case 0x10: case 0x30: case 0x50: - case 0x70: // Graphics Cursor X + case 0x70: // Graphics Cursor X case 0x90: case 0xb0: case 0xd0: - case 0xf0: // Graphics Cursor X - return s->vga.sr[0x10]; + case 0xf0: // Graphics Cursor X + return s->vga.sr[0x10]; case 0x11: case 0x31: case 0x51: - case 0x71: // Graphics Cursor Y + case 0x71: // Graphics Cursor Y case 0x91: case 0xb1: case 0xd1: - case 0xf1: // Graphics Cursor Y - return s->vga.sr[0x11]; - case 0x05: // ??? - case 0x07: // Extended Sequencer Mode - case 0x08: // EEPROM Control - case 0x09: // Scratch Register 0 - case 0x0a: // Scratch Register 1 - case 0x0b: // VCLK 0 - case 0x0c: // VCLK 1 - case 0x0d: // VCLK 2 - case 0x0e: // VCLK 3 - case 0x0f: // DRAM Control - case 0x12: // Graphics Cursor Attribute - case 0x13: // Graphics Cursor Pattern Address - case 0x14: // Scratch Register 2 - case 0x15: // Scratch Register 3 - case 0x16: // Performance Tuning Register - case 0x17: // Configuration Readback and Extended Control - case 0x18: // Signature Generator Control - case 0x19: // Signal Generator Result - case 0x1a: // Signal Generator Result - case 0x1b: // VCLK 0 Denominator & Post - case 0x1c: // VCLK 1 Denominator & Post - case 0x1d: // VCLK 2 Denominator & Post - case 0x1e: // VCLK 3 Denominator & Post - case 0x1f: // BIOS Write Enable and MCLK select + case 0xf1: // Graphics Cursor Y + return s->vga.sr[0x11]; + case 0x05: // ??? + case 0x07: // Extended Sequencer Mode + case 0x08: // EEPROM Control + case 0x09: // Scratch Register 0 + case 0x0a: // Scratch Register 1 + case 0x0b: // VCLK 0 + case 0x0c: // VCLK 1 + case 0x0d: // VCLK 2 + case 0x0e: // VCLK 3 + case 0x0f: // DRAM Control + case 0x12: // Graphics Cursor Attribute + case 0x13: // Graphics Cursor Pattern Address + case 0x14: // Scratch Register 2 + case 0x15: // Scratch Register 3 + case 0x16: // Performance Tuning Register + case 0x17: // Configuration Readback and Extended Control + case 0x18: // Signature Generator Control + case 0x19: // Signal Generator Result + case 0x1a: // Signal Generator Result + case 0x1b: // VCLK 0 Denominator & Post + case 0x1c: // VCLK 1 Denominator & Post + case 0x1d: // VCLK 2 Denominator & Post + case 0x1e: // VCLK 3 Denominator & Post + case 0x1f: // BIOS Write Enable and MCLK select #ifdef DEBUG_CIRRUS - printf("cirrus: handled inport sr_index %02x\n", s->vga.sr_index); + printf("cirrus: handled inport sr_index %02x\n", s->vga.sr_index); #endif - return s->vga.sr[s->vga.sr_index]; + return s->vga.sr[s->vga.sr_index]; default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: inport sr_index 0x%02x\n", s->vga.sr_index); - return 0xff; + return 0xff; } } static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val) { switch (s->vga.sr_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index]; - if (s->vga.sr_index == 1) + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index]; + if (s->vga.sr_index == 1) s->vga.update_retrace_info(&s->vga); break; - case 0x06: // Unlock Cirrus extensions - val &= 0x17; - if (val == 0x12) { - s->vga.sr[s->vga.sr_index] = 0x12; - } else { - s->vga.sr[s->vga.sr_index] = 0x0f; - } - break; + case 0x06: // Unlock Cirrus extensions + val &= 0x17; + if (val == 0x12) { + s->vga.sr[s->vga.sr_index] = 0x12; + } else { + s->vga.sr[s->vga.sr_index] = 0x0f; + } + break; case 0x10: case 0x30: case 0x50: - case 0x70: // Graphics Cursor X + case 0x70: // Graphics Cursor X case 0x90: case 0xb0: case 0xd0: - case 0xf0: // Graphics Cursor X - s->vga.sr[0x10] = val; + case 0xf0: // Graphics Cursor X + s->vga.sr[0x10] = val; s->vga.hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5); - break; + break; case 0x11: case 0x31: case 0x51: - case 0x71: // Graphics Cursor Y + case 0x71: // Graphics Cursor Y case 0x91: case 0xb1: case 0xd1: - case 0xf1: // Graphics Cursor Y - s->vga.sr[0x11] = val; + case 0xf1: // Graphics Cursor Y + s->vga.sr[0x11] = val; s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5); - break; - case 0x07: // Extended Sequencer Mode + break; + case 0x07: // Extended Sequencer Mode cirrus_update_memory_access(s); /* fall through */ - case 0x08: // EEPROM Control - case 0x09: // Scratch Register 0 - case 0x0a: // Scratch Register 1 - case 0x0b: // VCLK 0 - case 0x0c: // VCLK 1 - case 0x0d: // VCLK 2 - case 0x0e: // VCLK 3 - case 0x0f: // DRAM Control - case 0x13: // Graphics Cursor Pattern Address - case 0x14: // Scratch Register 2 - case 0x15: // Scratch Register 3 - case 0x16: // Performance Tuning Register - case 0x18: // Signature Generator Control - case 0x19: // Signature Generator Result - case 0x1a: // Signature Generator Result - case 0x1b: // VCLK 0 Denominator & Post - case 0x1c: // VCLK 1 Denominator & Post - case 0x1d: // VCLK 2 Denominator & Post - case 0x1e: // VCLK 3 Denominator & Post - case 0x1f: // BIOS Write Enable and MCLK select - s->vga.sr[s->vga.sr_index] = val; + case 0x08: // EEPROM Control + case 0x09: // Scratch Register 0 + case 0x0a: // Scratch Register 1 + case 0x0b: // VCLK 0 + case 0x0c: // VCLK 1 + case 0x0d: // VCLK 2 + case 0x0e: // VCLK 3 + case 0x0f: // DRAM Control + case 0x13: // Graphics Cursor Pattern Address + case 0x14: // Scratch Register 2 + case 0x15: // Scratch Register 3 + case 0x16: // Performance Tuning Register + case 0x18: // Signature Generator Control + case 0x19: // Signature Generator Result + case 0x1a: // Signature Generator Result + case 0x1b: // VCLK 0 Denominator & Post + case 0x1c: // VCLK 1 Denominator & Post + case 0x1d: // VCLK 2 Denominator & Post + case 0x1e: // VCLK 3 Denominator & Post + case 0x1f: // BIOS Write Enable and MCLK select + s->vga.sr[s->vga.sr_index] = val; #ifdef DEBUG_CIRRUS - printf("cirrus: handled outport sr_index %02x, sr_value %02x\n", - s->vga.sr_index, val); + printf("cirrus: handled outport sr_index %02x, sr_value %02x\n", + s->vga.sr_index, val); #endif - break; - case 0x12: // Graphics Cursor Attribute - s->vga.sr[0x12] = val; + break; + case 0x12: // Graphics Cursor Attribute + s->vga.sr[0x12] = val; s->vga.force_shadow = !!(val & CIRRUS_CURSOR_SHOW); #ifdef DEBUG_CIRRUS printf("cirrus: cursor ctl SR12=%02x (force shadow: %d)\n", val, s->vga.force_shadow); #endif break; - case 0x17: // Configuration Readback and Extended Control - s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38) + case 0x17: // Configuration Readback and Extended Control + s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38) | (val & 0xc7); cirrus_update_memory_access(s); break; @@ -1403,7 +1404,7 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val) qemu_log_mask(LOG_GUEST_ERROR, "cirrus: outport sr_index 0x%02x, sr_value 0x%02x\n", s->vga.sr_index, val); - break; + break; } } @@ -1425,9 +1426,9 @@ static int cirrus_read_hidden_dac(CirrusVGAState * s) static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value) { if (s->cirrus_hidden_dac_lockindex == 4) { - s->cirrus_hidden_dac_data = reg_value; + s->cirrus_hidden_dac_data = reg_value; #if defined(DEBUG_CIRRUS) - printf("cirrus: outport hidden DAC, value %02x\n", reg_value); + printf("cirrus: outport hidden DAC, value %02x\n", reg_value); #endif } s->cirrus_hidden_dac_lockindex = 0; @@ -1450,8 +1451,8 @@ static int cirrus_vga_read_palette(CirrusVGAState * s) val = s->vga.palette[s->vga.dac_read_index * 3 + s->vga.dac_sub_index]; } if (++s->vga.dac_sub_index == 3) { - s->vga.dac_sub_index = 0; - s->vga.dac_read_index++; + s->vga.dac_sub_index = 0; + s->vga.dac_read_index++; } return val; } @@ -1467,8 +1468,8 @@ static void cirrus_vga_write_palette(CirrusVGAState * s, int reg_value) memcpy(&s->vga.palette[s->vga.dac_write_index * 3], s->vga.dac_cache, 3); } /* XXX update cursor */ - s->vga.dac_sub_index = 0; - s->vga.dac_write_index++; + s->vga.dac_sub_index = 0; + s->vga.dac_write_index++; } } @@ -1485,24 +1486,24 @@ static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index) return s->cirrus_shadow_gr0; case 0x01: // Standard VGA, FGCOLOR 0x000000ff return s->cirrus_shadow_gr1; - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA return s->vga.gr[s->vga.gr_index]; - case 0x05: // Standard VGA, Cirrus extended mode + case 0x05: // Standard VGA, Cirrus extended mode default: - break; + break; } if (reg_index < 0x3a) { - return s->vga.gr[reg_index]; + return s->vga.gr[reg_index]; } else { qemu_log_mask(LOG_GUEST_ERROR, "cirrus: inport gr_index 0x%02x\n", reg_index); - return 0xff; + return 0xff; } } @@ -1511,87 +1512,87 @@ cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) { trace_vga_cirrus_write_gr(reg_index, reg_value); switch (reg_index) { - case 0x00: // Standard VGA, BGCOLOR 0x000000ff - s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; - s->cirrus_shadow_gr0 = reg_value; - break; - case 0x01: // Standard VGA, FGCOLOR 0x000000ff - s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; - s->cirrus_shadow_gr1 = reg_value; - break; - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; - break; - case 0x05: // Standard VGA, Cirrus extended mode - s->vga.gr[reg_index] = reg_value & 0x7f; + case 0x00: // Standard VGA, BGCOLOR 0x000000ff + s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; + s->cirrus_shadow_gr0 = reg_value; + break; + case 0x01: // Standard VGA, FGCOLOR 0x000000ff + s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; + s->cirrus_shadow_gr1 = reg_value; + break; + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; + break; + case 0x05: // Standard VGA, Cirrus extended mode + s->vga.gr[reg_index] = reg_value & 0x7f; cirrus_update_memory_access(s); - break; - case 0x09: // bank offset #0 - case 0x0A: // bank offset #1 - s->vga.gr[reg_index] = reg_value; - cirrus_update_bank_ptr(s, 0); - cirrus_update_bank_ptr(s, 1); + break; + case 0x09: // bank offset #0 + case 0x0A: // bank offset #1 + s->vga.gr[reg_index] = reg_value; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); cirrus_update_memory_access(s); break; case 0x0B: - s->vga.gr[reg_index] = reg_value; - cirrus_update_bank_ptr(s, 0); - cirrus_update_bank_ptr(s, 1); + s->vga.gr[reg_index] = reg_value; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); cirrus_update_memory_access(s); - break; - case 0x10: // BGCOLOR 0x0000ff00 - case 0x11: // FGCOLOR 0x0000ff00 - case 0x12: // BGCOLOR 0x00ff0000 - case 0x13: // FGCOLOR 0x00ff0000 - case 0x14: // BGCOLOR 0xff000000 - case 0x15: // FGCOLOR 0xff000000 - case 0x20: // BLT WIDTH 0x0000ff - case 0x22: // BLT HEIGHT 0x0000ff - case 0x24: // BLT DEST PITCH 0x0000ff - case 0x26: // BLT SRC PITCH 0x0000ff - case 0x28: // BLT DEST ADDR 0x0000ff - case 0x29: // BLT DEST ADDR 0x00ff00 - case 0x2c: // BLT SRC ADDR 0x0000ff - case 0x2d: // BLT SRC ADDR 0x00ff00 + break; + case 0x10: // BGCOLOR 0x0000ff00 + case 0x11: // FGCOLOR 0x0000ff00 + case 0x12: // BGCOLOR 0x00ff0000 + case 0x13: // FGCOLOR 0x00ff0000 + case 0x14: // BGCOLOR 0xff000000 + case 0x15: // FGCOLOR 0xff000000 + case 0x20: // BLT WIDTH 0x0000ff + case 0x22: // BLT HEIGHT 0x0000ff + case 0x24: // BLT DEST PITCH 0x0000ff + case 0x26: // BLT SRC PITCH 0x0000ff + case 0x28: // BLT DEST ADDR 0x0000ff + case 0x29: // BLT DEST ADDR 0x00ff00 + case 0x2c: // BLT SRC ADDR 0x0000ff + case 0x2d: // BLT SRC ADDR 0x00ff00 case 0x2f: // BLT WRITEMASK - case 0x30: // BLT MODE - case 0x32: // RASTER OP - case 0x33: // BLT MODEEXT - case 0x34: // BLT TRANSPARENT COLOR 0x00ff - case 0x35: // BLT TRANSPARENT COLOR 0xff00 - case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff - case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00 - s->vga.gr[reg_index] = reg_value; - break; - case 0x21: // BLT WIDTH 0x001f00 - case 0x23: // BLT HEIGHT 0x001f00 - case 0x25: // BLT DEST PITCH 0x001f00 - case 0x27: // BLT SRC PITCH 0x001f00 - s->vga.gr[reg_index] = reg_value & 0x1f; - break; - case 0x2a: // BLT DEST ADDR 0x3f0000 - s->vga.gr[reg_index] = reg_value & 0x3f; + case 0x30: // BLT MODE + case 0x32: // RASTER OP + case 0x33: // BLT MODEEXT + case 0x34: // BLT TRANSPARENT COLOR 0x00ff + case 0x35: // BLT TRANSPARENT COLOR 0xff00 + case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff + case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00 + s->vga.gr[reg_index] = reg_value; + break; + case 0x21: // BLT WIDTH 0x001f00 + case 0x23: // BLT HEIGHT 0x001f00 + case 0x25: // BLT DEST PITCH 0x001f00 + case 0x27: // BLT SRC PITCH 0x001f00 + s->vga.gr[reg_index] = reg_value & 0x1f; + break; + case 0x2a: // BLT DEST ADDR 0x3f0000 + s->vga.gr[reg_index] = reg_value & 0x3f; /* if auto start mode, starts bit blt now */ if (s->vga.gr[0x31] & CIRRUS_BLT_AUTOSTART) { cirrus_bitblt_start(s); } - break; - case 0x2e: // BLT SRC ADDR 0x3f0000 - s->vga.gr[reg_index] = reg_value & 0x3f; - break; - case 0x31: // BLT STATUS/START - cirrus_write_bitblt(s, reg_value); - break; + break; + case 0x2e: // BLT SRC ADDR 0x3f0000 + s->vga.gr[reg_index] = reg_value & 0x3f; + break; + case 0x31: // BLT STATUS/START + cirrus_write_bitblt(s, reg_value); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: outport gr_index 0x%02x, gr_value 0x%02x\n", reg_index, reg_value); - break; + break; } } @@ -1604,122 +1605,122 @@ cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index) { switch (reg_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x05: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - case 0x09: // Standard VGA - case 0x0a: // Standard VGA - case 0x0b: // Standard VGA - case 0x0c: // Standard VGA - case 0x0d: // Standard VGA - case 0x0e: // Standard VGA - case 0x0f: // Standard VGA - case 0x10: // Standard VGA - case 0x11: // Standard VGA - case 0x12: // Standard VGA - case 0x13: // Standard VGA - case 0x14: // Standard VGA - case 0x15: // Standard VGA - case 0x16: // Standard VGA - case 0x17: // Standard VGA - case 0x18: // Standard VGA - return s->vga.cr[s->vga.cr_index]; - case 0x24: // Attribute Controller Toggle Readback (R) + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x05: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + case 0x09: // Standard VGA + case 0x0a: // Standard VGA + case 0x0b: // Standard VGA + case 0x0c: // Standard VGA + case 0x0d: // Standard VGA + case 0x0e: // Standard VGA + case 0x0f: // Standard VGA + case 0x10: // Standard VGA + case 0x11: // Standard VGA + case 0x12: // Standard VGA + case 0x13: // Standard VGA + case 0x14: // Standard VGA + case 0x15: // Standard VGA + case 0x16: // Standard VGA + case 0x17: // Standard VGA + case 0x18: // Standard VGA + return s->vga.cr[s->vga.cr_index]; + case 0x24: // Attribute Controller Toggle Readback (R) return (s->vga.ar_flip_flop << 7); - case 0x19: // Interlace End - case 0x1a: // Miscellaneous Control - case 0x1b: // Extended Display Control - case 0x1c: // Sync Adjust and Genlock - case 0x1d: // Overlay Extended Control - case 0x22: // Graphics Data Latches Readback (R) - case 0x25: // Part Status - case 0x27: // Part ID (R) - return s->vga.cr[s->vga.cr_index]; - case 0x26: // Attribute Controller Index Readback (R) - return s->vga.ar_index & 0x3f; + case 0x19: // Interlace End + case 0x1a: // Miscellaneous Control + case 0x1b: // Extended Display Control + case 0x1c: // Sync Adjust and Genlock + case 0x1d: // Overlay Extended Control + case 0x22: // Graphics Data Latches Readback (R) + case 0x25: // Part Status + case 0x27: // Part ID (R) + return s->vga.cr[s->vga.cr_index]; + case 0x26: // Attribute Controller Index Readback (R) + return s->vga.ar_index & 0x3f; default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: inport cr_index 0x%02x\n", reg_index); - return 0xff; + return 0xff; } } static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value) { switch (s->vga.cr_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x05: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - case 0x09: // Standard VGA - case 0x0a: // Standard VGA - case 0x0b: // Standard VGA - case 0x0c: // Standard VGA - case 0x0d: // Standard VGA - case 0x0e: // Standard VGA - case 0x0f: // Standard VGA - case 0x10: // Standard VGA - case 0x11: // Standard VGA - case 0x12: // Standard VGA - case 0x13: // Standard VGA - case 0x14: // Standard VGA - case 0x15: // Standard VGA - case 0x16: // Standard VGA - case 0x17: // Standard VGA - case 0x18: // Standard VGA - /* handle CR0-7 protection */ - if ((s->vga.cr[0x11] & 0x80) && s->vga.cr_index <= 7) { - /* can always write bit 4 of CR7 */ - if (s->vga.cr_index == 7) - s->vga.cr[7] = (s->vga.cr[7] & ~0x10) | (reg_value & 0x10); - return; - } - s->vga.cr[s->vga.cr_index] = reg_value; - switch(s->vga.cr_index) { - case 0x00: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x11: - case 0x17: - s->vga.update_retrace_info(&s->vga); - break; - } - break; - case 0x19: // Interlace End - case 0x1a: // Miscellaneous Control - case 0x1b: // Extended Display Control - case 0x1c: // Sync Adjust and Genlock - case 0x1d: // Overlay Extended Control - s->vga.cr[s->vga.cr_index] = reg_value; + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x05: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + case 0x09: // Standard VGA + case 0x0a: // Standard VGA + case 0x0b: // Standard VGA + case 0x0c: // Standard VGA + case 0x0d: // Standard VGA + case 0x0e: // Standard VGA + case 0x0f: // Standard VGA + case 0x10: // Standard VGA + case 0x11: // Standard VGA + case 0x12: // Standard VGA + case 0x13: // Standard VGA + case 0x14: // Standard VGA + case 0x15: // Standard VGA + case 0x16: // Standard VGA + case 0x17: // Standard VGA + case 0x18: // Standard VGA + /* handle CR0-7 protection */ + if ((s->vga.cr[0x11] & 0x80) && s->vga.cr_index <= 7) { + /* can always write bit 4 of CR7 */ + if (s->vga.cr_index == 7) + s->vga.cr[7] = (s->vga.cr[7] & ~0x10) | (reg_value & 0x10); + return; + } + s->vga.cr[s->vga.cr_index] = reg_value; + switch(s->vga.cr_index) { + case 0x00: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x11: + case 0x17: + s->vga.update_retrace_info(&s->vga); + break; + } + break; + case 0x19: // Interlace End + case 0x1a: // Miscellaneous Control + case 0x1b: // Extended Display Control + case 0x1c: // Sync Adjust and Genlock + case 0x1d: // Overlay Extended Control + s->vga.cr[s->vga.cr_index] = reg_value; #ifdef DEBUG_CIRRUS - printf("cirrus: handled outport cr_index %02x, cr_value %02x\n", - s->vga.cr_index, reg_value); + printf("cirrus: handled outport cr_index %02x, cr_value %02x\n", + s->vga.cr_index, reg_value); #endif - break; - case 0x22: // Graphics Data Latches Readback (R) - case 0x24: // Attribute Controller Toggle Readback (R) - case 0x26: // Attribute Controller Index Readback (R) - case 0x27: // Part ID (R) - break; - case 0x25: // Part Status + break; + case 0x22: // Graphics Data Latches Readback (R) + case 0x24: // Attribute Controller Toggle Readback (R) + case 0x26: // Attribute Controller Index Readback (R) + case 0x27: // Part ID (R) + break; + case 0x25: // Part Status default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: outport cr_index 0x%02x, cr_value 0x%02x\n", s->vga.cr_index, reg_value); - break; + break; } } @@ -1735,102 +1736,102 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address) switch (address) { case (CIRRUS_MMIO_BLTBGCOLOR + 0): - value = cirrus_vga_read_gr(s, 0x00); - break; + value = cirrus_vga_read_gr(s, 0x00); + break; case (CIRRUS_MMIO_BLTBGCOLOR + 1): - value = cirrus_vga_read_gr(s, 0x10); - break; + value = cirrus_vga_read_gr(s, 0x10); + break; case (CIRRUS_MMIO_BLTBGCOLOR + 2): - value = cirrus_vga_read_gr(s, 0x12); - break; + value = cirrus_vga_read_gr(s, 0x12); + break; case (CIRRUS_MMIO_BLTBGCOLOR + 3): - value = cirrus_vga_read_gr(s, 0x14); - break; + value = cirrus_vga_read_gr(s, 0x14); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 0): - value = cirrus_vga_read_gr(s, 0x01); - break; + value = cirrus_vga_read_gr(s, 0x01); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 1): - value = cirrus_vga_read_gr(s, 0x11); - break; + value = cirrus_vga_read_gr(s, 0x11); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 2): - value = cirrus_vga_read_gr(s, 0x13); - break; + value = cirrus_vga_read_gr(s, 0x13); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 3): - value = cirrus_vga_read_gr(s, 0x15); - break; + value = cirrus_vga_read_gr(s, 0x15); + break; case (CIRRUS_MMIO_BLTWIDTH + 0): - value = cirrus_vga_read_gr(s, 0x20); - break; + value = cirrus_vga_read_gr(s, 0x20); + break; case (CIRRUS_MMIO_BLTWIDTH + 1): - value = cirrus_vga_read_gr(s, 0x21); - break; + value = cirrus_vga_read_gr(s, 0x21); + break; case (CIRRUS_MMIO_BLTHEIGHT + 0): - value = cirrus_vga_read_gr(s, 0x22); - break; + value = cirrus_vga_read_gr(s, 0x22); + break; case (CIRRUS_MMIO_BLTHEIGHT + 1): - value = cirrus_vga_read_gr(s, 0x23); - break; + value = cirrus_vga_read_gr(s, 0x23); + break; case (CIRRUS_MMIO_BLTDESTPITCH + 0): - value = cirrus_vga_read_gr(s, 0x24); - break; + value = cirrus_vga_read_gr(s, 0x24); + break; case (CIRRUS_MMIO_BLTDESTPITCH + 1): - value = cirrus_vga_read_gr(s, 0x25); - break; + value = cirrus_vga_read_gr(s, 0x25); + break; case (CIRRUS_MMIO_BLTSRCPITCH + 0): - value = cirrus_vga_read_gr(s, 0x26); - break; + value = cirrus_vga_read_gr(s, 0x26); + break; case (CIRRUS_MMIO_BLTSRCPITCH + 1): - value = cirrus_vga_read_gr(s, 0x27); - break; + value = cirrus_vga_read_gr(s, 0x27); + break; case (CIRRUS_MMIO_BLTDESTADDR + 0): - value = cirrus_vga_read_gr(s, 0x28); - break; + value = cirrus_vga_read_gr(s, 0x28); + break; case (CIRRUS_MMIO_BLTDESTADDR + 1): - value = cirrus_vga_read_gr(s, 0x29); - break; + value = cirrus_vga_read_gr(s, 0x29); + break; case (CIRRUS_MMIO_BLTDESTADDR + 2): - value = cirrus_vga_read_gr(s, 0x2a); - break; + value = cirrus_vga_read_gr(s, 0x2a); + break; case (CIRRUS_MMIO_BLTSRCADDR + 0): - value = cirrus_vga_read_gr(s, 0x2c); - break; + value = cirrus_vga_read_gr(s, 0x2c); + break; case (CIRRUS_MMIO_BLTSRCADDR + 1): - value = cirrus_vga_read_gr(s, 0x2d); - break; + value = cirrus_vga_read_gr(s, 0x2d); + break; case (CIRRUS_MMIO_BLTSRCADDR + 2): - value = cirrus_vga_read_gr(s, 0x2e); - break; + value = cirrus_vga_read_gr(s, 0x2e); + break; case CIRRUS_MMIO_BLTWRITEMASK: - value = cirrus_vga_read_gr(s, 0x2f); - break; + value = cirrus_vga_read_gr(s, 0x2f); + break; case CIRRUS_MMIO_BLTMODE: - value = cirrus_vga_read_gr(s, 0x30); - break; + value = cirrus_vga_read_gr(s, 0x30); + break; case CIRRUS_MMIO_BLTROP: - value = cirrus_vga_read_gr(s, 0x32); - break; + value = cirrus_vga_read_gr(s, 0x32); + break; case CIRRUS_MMIO_BLTMODEEXT: - value = cirrus_vga_read_gr(s, 0x33); - break; + value = cirrus_vga_read_gr(s, 0x33); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): - value = cirrus_vga_read_gr(s, 0x34); - break; + value = cirrus_vga_read_gr(s, 0x34); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1): - value = cirrus_vga_read_gr(s, 0x35); - break; + value = cirrus_vga_read_gr(s, 0x35); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0): - value = cirrus_vga_read_gr(s, 0x38); - break; + value = cirrus_vga_read_gr(s, 0x38); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): - value = cirrus_vga_read_gr(s, 0x39); - break; + value = cirrus_vga_read_gr(s, 0x39); + break; case CIRRUS_MMIO_BLTSTATUS: - value = cirrus_vga_read_gr(s, 0x31); - break; + value = cirrus_vga_read_gr(s, 0x31); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: mmio read - address 0x%04x\n", address); - break; + break; } trace_vga_cirrus_write_blt(address, value); @@ -1838,111 +1839,111 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address) } static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, - uint8_t value) + uint8_t value) { trace_vga_cirrus_write_blt(address, value); switch (address) { case (CIRRUS_MMIO_BLTBGCOLOR + 0): - cirrus_vga_write_gr(s, 0x00, value); - break; + cirrus_vga_write_gr(s, 0x00, value); + break; case (CIRRUS_MMIO_BLTBGCOLOR + 1): - cirrus_vga_write_gr(s, 0x10, value); - break; + cirrus_vga_write_gr(s, 0x10, value); + break; case (CIRRUS_MMIO_BLTBGCOLOR + 2): - cirrus_vga_write_gr(s, 0x12, value); - break; + cirrus_vga_write_gr(s, 0x12, value); + break; case (CIRRUS_MMIO_BLTBGCOLOR + 3): - cirrus_vga_write_gr(s, 0x14, value); - break; + cirrus_vga_write_gr(s, 0x14, value); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 0): - cirrus_vga_write_gr(s, 0x01, value); - break; + cirrus_vga_write_gr(s, 0x01, value); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 1): - cirrus_vga_write_gr(s, 0x11, value); - break; + cirrus_vga_write_gr(s, 0x11, value); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 2): - cirrus_vga_write_gr(s, 0x13, value); - break; + cirrus_vga_write_gr(s, 0x13, value); + break; case (CIRRUS_MMIO_BLTFGCOLOR + 3): - cirrus_vga_write_gr(s, 0x15, value); - break; + cirrus_vga_write_gr(s, 0x15, value); + break; case (CIRRUS_MMIO_BLTWIDTH + 0): - cirrus_vga_write_gr(s, 0x20, value); - break; + cirrus_vga_write_gr(s, 0x20, value); + break; case (CIRRUS_MMIO_BLTWIDTH + 1): - cirrus_vga_write_gr(s, 0x21, value); - break; + cirrus_vga_write_gr(s, 0x21, value); + break; case (CIRRUS_MMIO_BLTHEIGHT + 0): - cirrus_vga_write_gr(s, 0x22, value); - break; + cirrus_vga_write_gr(s, 0x22, value); + break; case (CIRRUS_MMIO_BLTHEIGHT + 1): - cirrus_vga_write_gr(s, 0x23, value); - break; + cirrus_vga_write_gr(s, 0x23, value); + break; case (CIRRUS_MMIO_BLTDESTPITCH + 0): - cirrus_vga_write_gr(s, 0x24, value); - break; + cirrus_vga_write_gr(s, 0x24, value); + break; case (CIRRUS_MMIO_BLTDESTPITCH + 1): - cirrus_vga_write_gr(s, 0x25, value); - break; + cirrus_vga_write_gr(s, 0x25, value); + break; case (CIRRUS_MMIO_BLTSRCPITCH + 0): - cirrus_vga_write_gr(s, 0x26, value); - break; + cirrus_vga_write_gr(s, 0x26, value); + break; case (CIRRUS_MMIO_BLTSRCPITCH + 1): - cirrus_vga_write_gr(s, 0x27, value); - break; + cirrus_vga_write_gr(s, 0x27, value); + break; case (CIRRUS_MMIO_BLTDESTADDR + 0): - cirrus_vga_write_gr(s, 0x28, value); - break; + cirrus_vga_write_gr(s, 0x28, value); + break; case (CIRRUS_MMIO_BLTDESTADDR + 1): - cirrus_vga_write_gr(s, 0x29, value); - break; + cirrus_vga_write_gr(s, 0x29, value); + break; case (CIRRUS_MMIO_BLTDESTADDR + 2): - cirrus_vga_write_gr(s, 0x2a, value); - break; + cirrus_vga_write_gr(s, 0x2a, value); + break; case (CIRRUS_MMIO_BLTDESTADDR + 3): - /* ignored */ - break; + /* ignored */ + break; case (CIRRUS_MMIO_BLTSRCADDR + 0): - cirrus_vga_write_gr(s, 0x2c, value); - break; + cirrus_vga_write_gr(s, 0x2c, value); + break; case (CIRRUS_MMIO_BLTSRCADDR + 1): - cirrus_vga_write_gr(s, 0x2d, value); - break; + cirrus_vga_write_gr(s, 0x2d, value); + break; case (CIRRUS_MMIO_BLTSRCADDR + 2): - cirrus_vga_write_gr(s, 0x2e, value); - break; + cirrus_vga_write_gr(s, 0x2e, value); + break; case CIRRUS_MMIO_BLTWRITEMASK: - cirrus_vga_write_gr(s, 0x2f, value); - break; + cirrus_vga_write_gr(s, 0x2f, value); + break; case CIRRUS_MMIO_BLTMODE: - cirrus_vga_write_gr(s, 0x30, value); - break; + cirrus_vga_write_gr(s, 0x30, value); + break; case CIRRUS_MMIO_BLTROP: - cirrus_vga_write_gr(s, 0x32, value); - break; + cirrus_vga_write_gr(s, 0x32, value); + break; case CIRRUS_MMIO_BLTMODEEXT: - cirrus_vga_write_gr(s, 0x33, value); - break; + cirrus_vga_write_gr(s, 0x33, value); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): - cirrus_vga_write_gr(s, 0x34, value); - break; + cirrus_vga_write_gr(s, 0x34, value); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1): - cirrus_vga_write_gr(s, 0x35, value); - break; + cirrus_vga_write_gr(s, 0x35, value); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0): - cirrus_vga_write_gr(s, 0x38, value); - break; + cirrus_vga_write_gr(s, 0x38, value); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): - cirrus_vga_write_gr(s, 0x39, value); - break; + cirrus_vga_write_gr(s, 0x39, value); + break; case CIRRUS_MMIO_BLTSTATUS: - cirrus_vga_write_gr(s, 0x31, value); - break; + cirrus_vga_write_gr(s, 0x31, value); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n", address, value); - break; + break; } } @@ -1953,9 +1954,9 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, ***************************************/ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, - unsigned mode, - unsigned offset, - uint32_t mem_value) + unsigned mode, + unsigned offset, + uint32_t mem_value) { int x; unsigned val = mem_value; @@ -1963,20 +1964,20 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, for (x = 0; x < 8; x++) { dst = s->vga.vram_ptr + ((offset + x) & s->cirrus_addr_mask); - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; - } else if (mode == 5) { - *dst = s->cirrus_shadow_gr0; - } - val <<= 1; + if (val & 0x80) { + *dst = s->cirrus_shadow_gr1; + } else if (mode == 5) { + *dst = s->cirrus_shadow_gr0; + } + val <<= 1; } memory_region_set_dirty(&s->vga.vram, offset, 8); } static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, - unsigned mode, - unsigned offset, - uint32_t mem_value) + unsigned mode, + unsigned offset, + uint32_t mem_value) { int x; unsigned val = mem_value; @@ -1984,14 +1985,14 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, for (x = 0; x < 8; x++) { dst = s->vga.vram_ptr + ((offset + 2 * x) & s->cirrus_addr_mask & ~1); - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; - *(dst + 1) = s->vga.gr[0x11]; - } else if (mode == 5) { - *dst = s->cirrus_shadow_gr0; - *(dst + 1) = s->vga.gr[0x10]; - } - val <<= 1; + if (val & 0x80) { + *dst = s->cirrus_shadow_gr1; + *(dst + 1) = s->vga.gr[0x11]; + } else if (mode == 5) { + *dst = s->cirrus_shadow_gr0; + *(dst + 1) = s->vga.gr[0x10]; + } + val <<= 1; } memory_region_set_dirty(&s->vga.vram, offset, 16); } @@ -2016,29 +2017,29 @@ static uint64_t cirrus_vga_mem_read(void *opaque, } if (addr < 0x10000) { - /* XXX handle bitblt */ - /* video memory */ - bank_index = addr >> 15; - bank_offset = addr & 0x7fff; - if (bank_offset < s->cirrus_bank_limit[bank_index]) { - bank_offset += s->cirrus_bank_base[bank_index]; - if ((s->vga.gr[0x0B] & 0x14) == 0x14) { - bank_offset <<= 4; - } else if (s->vga.gr[0x0B] & 0x02) { - bank_offset <<= 3; - } - bank_offset &= s->cirrus_addr_mask; - val = *(s->vga.vram_ptr + bank_offset); - } else - val = 0xff; + /* XXX handle bitblt */ + /* video memory */ + bank_index = addr >> 15; + bank_offset = addr & 0x7fff; + if (bank_offset < s->cirrus_bank_limit[bank_index]) { + bank_offset += s->cirrus_bank_base[bank_index]; + if ((s->vga.gr[0x0B] & 0x14) == 0x14) { + bank_offset <<= 4; + } else if (s->vga.gr[0x0B] & 0x02) { + bank_offset <<= 3; + } + bank_offset &= s->cirrus_addr_mask; + val = *(s->vga.vram_ptr + bank_offset); + } else + val = 0xff; } else if (addr >= 0x18000 && addr < 0x18100) { - /* memory-mapped I/O */ - val = 0xff; - if ((s->vga.sr[0x17] & 0x44) == 0x04) { - val = cirrus_mmio_blt_read(s, addr & 0xff); - } + /* memory-mapped I/O */ + val = 0xff; + if ((s->vga.sr[0x17] & 0x44) == 0x04) { + val = cirrus_mmio_blt_read(s, addr & 0xff); + } } else { - val = 0xff; + val = 0xff; qemu_log_mask(LOG_GUEST_ERROR, "cirrus: mem_readb 0x" TARGET_FMT_plx "\n", addr); } @@ -2061,47 +2062,47 @@ static void cirrus_vga_mem_write(void *opaque, } if (addr < 0x10000) { - if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - /* bitblt */ - *s->cirrus_srcptr++ = (uint8_t) mem_value; - if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { - cirrus_bitblt_cputovideo_next(s); - } - } else { - /* video memory */ - bank_index = addr >> 15; - bank_offset = addr & 0x7fff; - if (bank_offset < s->cirrus_bank_limit[bank_index]) { - bank_offset += s->cirrus_bank_base[bank_index]; - if ((s->vga.gr[0x0B] & 0x14) == 0x14) { - bank_offset <<= 4; - } else if (s->vga.gr[0x0B] & 0x02) { - bank_offset <<= 3; - } - bank_offset &= s->cirrus_addr_mask; - mode = s->vga.gr[0x05] & 0x7; - if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { - *(s->vga.vram_ptr + bank_offset) = mem_value; + if (s->cirrus_srcptr != s->cirrus_srcptr_end) { + /* bitblt */ + *s->cirrus_srcptr++ = (uint8_t) mem_value; + if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { + cirrus_bitblt_cputovideo_next(s); + } + } else { + /* video memory */ + bank_index = addr >> 15; + bank_offset = addr & 0x7fff; + if (bank_offset < s->cirrus_bank_limit[bank_index]) { + bank_offset += s->cirrus_bank_base[bank_index]; + if ((s->vga.gr[0x0B] & 0x14) == 0x14) { + bank_offset <<= 4; + } else if (s->vga.gr[0x0B] & 0x02) { + bank_offset <<= 3; + } + bank_offset &= s->cirrus_addr_mask; + mode = s->vga.gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { + *(s->vga.vram_ptr + bank_offset) = mem_value; memory_region_set_dirty(&s->vga.vram, bank_offset, sizeof(mem_value)); - } else { - if ((s->vga.gr[0x0B] & 0x14) != 0x14) { - cirrus_mem_writeb_mode4and5_8bpp(s, mode, - bank_offset, - mem_value); - } else { - cirrus_mem_writeb_mode4and5_16bpp(s, mode, - bank_offset, - mem_value); - } - } - } - } + } else { + if ((s->vga.gr[0x0B] & 0x14) != 0x14) { + cirrus_mem_writeb_mode4and5_8bpp(s, mode, + bank_offset, + mem_value); + } else { + cirrus_mem_writeb_mode4and5_16bpp(s, mode, + bank_offset, + mem_value); + } + } + } + } } else if (addr >= 0x18000 && addr < 0x18100) { - /* memory-mapped I/O */ - if ((s->vga.sr[0x17] & 0x44) == 0x04) { - cirrus_mmio_blt_write(s, addr & 0xff, mem_value); - } + /* memory-mapped I/O */ + if ((s->vga.sr[0x17] & 0x44) == 0x04) { + cirrus_mmio_blt_write(s, addr & 0xff, mem_value); + } } else { qemu_log_mask(LOG_GUEST_ERROR, "cirrus: mem_writeb 0x" TARGET_FMT_plx " " @@ -2326,20 +2327,20 @@ static uint64_t cirrus_linear_read(void *opaque, hwaddr addr, if (((s->vga.sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { - /* memory-mapped I/O */ - ret = cirrus_mmio_blt_read(s, addr & 0xff); + /* memory-mapped I/O */ + ret = cirrus_mmio_blt_read(s, addr & 0xff); } else if (0) { - /* XXX handle bitblt */ - ret = 0xff; + /* XXX handle bitblt */ + ret = 0xff; } else { - /* video memory */ - if ((s->vga.gr[0x0B] & 0x14) == 0x14) { - addr <<= 4; - } else if (s->vga.gr[0x0B] & 0x02) { - addr <<= 3; - } - addr &= s->cirrus_addr_mask; - ret = *(s->vga.vram_ptr + addr); + /* video memory */ + if ((s->vga.gr[0x0B] & 0x14) == 0x14) { + addr <<= 4; + } else if (s->vga.gr[0x0B] & 0x02) { + addr <<= 3; + } + addr &= s->cirrus_addr_mask; + ret = *(s->vga.vram_ptr + addr); } return ret; @@ -2355,34 +2356,34 @@ static void cirrus_linear_write(void *opaque, hwaddr addr, if (((s->vga.sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { - /* memory-mapped I/O */ - cirrus_mmio_blt_write(s, addr & 0xff, val); + /* memory-mapped I/O */ + cirrus_mmio_blt_write(s, addr & 0xff, val); } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - /* bitblt */ - *s->cirrus_srcptr++ = (uint8_t) val; - if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { - cirrus_bitblt_cputovideo_next(s); - } + /* bitblt */ + *s->cirrus_srcptr++ = (uint8_t) val; + if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { + cirrus_bitblt_cputovideo_next(s); + } } else { - /* video memory */ - if ((s->vga.gr[0x0B] & 0x14) == 0x14) { - addr <<= 4; - } else if (s->vga.gr[0x0B] & 0x02) { - addr <<= 3; - } - addr &= s->cirrus_addr_mask; - - mode = s->vga.gr[0x05] & 0x7; - if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { - *(s->vga.vram_ptr + addr) = (uint8_t) val; + /* video memory */ + if ((s->vga.gr[0x0B] & 0x14) == 0x14) { + addr <<= 4; + } else if (s->vga.gr[0x0B] & 0x02) { + addr <<= 3; + } + addr &= s->cirrus_addr_mask; + + mode = s->vga.gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { + *(s->vga.vram_ptr + addr) = (uint8_t) val; memory_region_set_dirty(&s->vga.vram, addr, 1); - } else { - if ((s->vga.gr[0x0B] & 0x14) != 0x14) { - cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val); - } else { - cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val); - } - } + } else { + if ((s->vga.gr[0x0B] & 0x14) != 0x14) { + cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val); + } else { + cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val); + } + } } } @@ -2415,11 +2416,11 @@ static void cirrus_linear_bitblt_write(void *opaque, CirrusVGAState *s = opaque; if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - /* bitblt */ - *s->cirrus_srcptr++ = (uint8_t) val; - if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { - cirrus_bitblt_cputovideo_next(s); - } + /* bitblt */ + *s->cirrus_srcptr++ = (uint8_t) val; + if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { + cirrus_bitblt_cputovideo_next(s); + } } } @@ -2476,14 +2477,14 @@ static void cirrus_update_memory_access(CirrusVGAState *s) } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { goto generic_io; } else { - if ((s->vga.gr[0x0B] & 0x14) == 0x14) { + if ((s->vga.gr[0x0B] & 0x14) == 0x14) { goto generic_io; - } else if (s->vga.gr[0x0B] & 0x02) { + } else if (s->vga.gr[0x0B] & 0x02) { goto generic_io; } - mode = s->vga.gr[0x05] & 0x7; - if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { + mode = s->vga.gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { map_linear_vram(s); } else { generic_io: @@ -2506,76 +2507,76 @@ static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr, addr += 0x3b0; if (vga_ioport_invalid(s, addr)) { - val = 0xff; + val = 0xff; } else { - switch (addr) { - case 0x3c0: - if (s->ar_flip_flop == 0) { - val = s->ar_index; - } else { - val = 0; - } - break; - case 0x3c1: - index = s->ar_index & 0x1f; - if (index < 21) - val = s->ar[index]; - else - val = 0; - break; - case 0x3c2: - val = s->st00; - break; - case 0x3c4: - val = s->sr_index; - break; - case 0x3c5: - val = cirrus_vga_read_sr(c); + switch (addr) { + case 0x3c0: + if (s->ar_flip_flop == 0) { + val = s->ar_index; + } else { + val = 0; + } + break; + case 0x3c1: + index = s->ar_index & 0x1f; + if (index < 21) + val = s->ar[index]; + else + val = 0; + break; + case 0x3c2: + val = s->st00; + break; + case 0x3c4: + val = s->sr_index; + break; + case 0x3c5: + val = cirrus_vga_read_sr(c); + break; + break; + case 0x3c6: + val = cirrus_read_hidden_dac(c); + break; + case 0x3c7: + val = s->dac_state; + break; + case 0x3c8: + val = s->dac_write_index; + c->cirrus_hidden_dac_lockindex = 0; break; - break; - case 0x3c6: - val = cirrus_read_hidden_dac(c); - break; - case 0x3c7: - val = s->dac_state; - break; - case 0x3c8: - val = s->dac_write_index; - c->cirrus_hidden_dac_lockindex = 0; - break; case 0x3c9: val = cirrus_vga_read_palette(c); break; - case 0x3ca: - val = s->fcr; - break; - case 0x3cc: - val = s->msr; - break; - case 0x3ce: - val = s->gr_index; - break; - case 0x3cf: - val = cirrus_vga_read_gr(c, s->gr_index); - break; - case 0x3b4: - case 0x3d4: - val = s->cr_index; - break; - case 0x3b5: - case 0x3d5: + case 0x3ca: + val = s->fcr; + break; + case 0x3cc: + val = s->msr; + break; + case 0x3ce: + val = s->gr_index; + break; + case 0x3cf: + val = cirrus_vga_read_gr(c, s->gr_index); + break; + case 0x3b4: + case 0x3d4: + val = s->cr_index; + break; + case 0x3b5: + case 0x3d5: val = cirrus_vga_read_cr(c, s->cr_index); - break; - case 0x3ba: - case 0x3da: - /* just toggle to fool polling */ - val = s->st01 = s->retrace(s); - s->ar_flip_flop = 0; - break; - default: - val = 0x00; - break; - } + break; + case 0x3ba: + case 0x3da: + /* just toggle to fool polling */ + val = s->st01 = s->retrace(s); + s->ar_flip_flop = 0; + break; + default: + val = 0x00; + break; + } } trace_vga_cirrus_read_io(addr, val); return val; @@ -2592,86 +2593,86 @@ static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val, /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { - return; + return; } trace_vga_cirrus_write_io(addr, val); switch (addr) { case 0x3c0: - if (s->ar_flip_flop == 0) { - val &= 0x3f; - s->ar_index = val; - } else { - index = s->ar_index & 0x1f; - switch (index) { - case 0x00 ... 0x0f: - s->ar[index] = val & 0x3f; - break; - case 0x10: - s->ar[index] = val & ~0x10; - break; - case 0x11: - s->ar[index] = val; - break; - case 0x12: - s->ar[index] = val & ~0xc0; - break; - case 0x13: - s->ar[index] = val & ~0xf0; - break; - case 0x14: - s->ar[index] = val & ~0xf0; - break; - default: - break; - } - } - s->ar_flip_flop ^= 1; - break; + if (s->ar_flip_flop == 0) { + val &= 0x3f; + s->ar_index = val; + } else { + index = s->ar_index & 0x1f; + switch (index) { + case 0x00 ... 0x0f: + s->ar[index] = val & 0x3f; + break; + case 0x10: + s->ar[index] = val & ~0x10; + break; + case 0x11: + s->ar[index] = val; + break; + case 0x12: + s->ar[index] = val & ~0xc0; + break; + case 0x13: + s->ar[index] = val & ~0xf0; + break; + case 0x14: + s->ar[index] = val & ~0xf0; + break; + default: + break; + } + } + s->ar_flip_flop ^= 1; + break; case 0x3c2: - s->msr = val & ~0x10; - s->update_retrace_info(s); - break; + s->msr = val & ~0x10; + s->update_retrace_info(s); + break; case 0x3c4: - s->sr_index = val; - break; + s->sr_index = val; + break; case 0x3c5: - cirrus_vga_write_sr(c, val); + cirrus_vga_write_sr(c, val); break; case 0x3c6: - cirrus_write_hidden_dac(c, val); - break; + cirrus_write_hidden_dac(c, val); + break; case 0x3c7: - s->dac_read_index = val; - s->dac_sub_index = 0; - s->dac_state = 3; - break; + s->dac_read_index = val; + s->dac_sub_index = 0; + s->dac_state = 3; + break; case 0x3c8: - s->dac_write_index = val; - s->dac_sub_index = 0; - s->dac_state = 0; - break; + s->dac_write_index = val; + s->dac_sub_index = 0; + s->dac_state = 0; + break; case 0x3c9: cirrus_vga_write_palette(c, val); break; case 0x3ce: - s->gr_index = val; - break; + s->gr_index = val; + break; case 0x3cf: - cirrus_vga_write_gr(c, s->gr_index, val); - break; + cirrus_vga_write_gr(c, s->gr_index, val); + break; case 0x3b4: case 0x3d4: - s->cr_index = val; - break; + s->cr_index = val; + break; case 0x3b5: case 0x3d5: - cirrus_vga_write_cr(c, val); - break; + cirrus_vga_write_cr(c, val); + break; case 0x3ba: case 0x3da: - s->fcr = val & 0x10; - break; + s->fcr = val & 0x10; + break; } } @@ -2699,7 +2700,7 @@ static void cirrus_mmio_write(void *opaque, hwaddr addr, CirrusVGAState *s = opaque; if (addr >= 0x100) { - cirrus_mmio_blt_write(s, addr - 0x100, val); + cirrus_mmio_blt_write(s, addr - 0x100, val); } else { cirrus_vga_ioport_write(s, addr + 0x10, val, size); } @@ -2799,13 +2800,13 @@ static void cirrus_reset(void *opaque) s->vga.sr[0x06] = 0x0f; if (s->device_id == CIRRUS_ID_CLGD5446) { /* 4MB 64 bit memory config, always PCI */ - s->vga.sr[0x1F] = 0x2d; // MemClock + s->vga.sr[0x1F] = 0x2d; // MemClock s->vga.gr[0x18] = 0x0f; // fastest memory configuration s->vga.sr[0x0f] = 0x98; s->vga.sr[0x17] = 0x20; s->vga.sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */ } else { - s->vga.sr[0x1F] = 0x22; // MemClock + s->vga.sr[0x1F] = 0x22; // MemClock s->vga.sr[0x0F] = CIRRUS_MEMSIZE_2M; s->vga.sr[0x17] = s->bustype; s->vga.sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */ diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c index 96144bd69060..84be51670ed8 100644 --- a/hw/display/cirrus_vga_isa.c +++ b/hw/display/cirrus_vga_isa.c @@ -31,6 +31,7 @@ #include "hw/isa/isa.h" #include "cirrus_vga_internal.h" #include "qom/object.h" +#include "ui/console.h" #define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga" OBJECT_DECLARE_SIMPLE_TYPE(ISACirrusVGAState, ISA_CIRRUS_VGA) diff --git a/hw/display/meson.build b/hw/display/meson.build index adc53dd8b6cc..f860c2c562ac 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -38,10 +38,21 @@ softmmu_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c')) specific_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c')) +if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or + config_all_devices.has_key('CONFIG_VGA_PCI') or + config_all_devices.has_key('CONFIG_VMWARE_VGA') or + config_all_devices.has_key('CONFIG_ATI_VGA') + ) + softmmu_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'), + if_false: files('acpi-vga-stub.c')) +endif + if config_all_devices.has_key('CONFIG_QXL') qxl_ss = ss.source_set() qxl_ss.add(when: 'CONFIG_QXL', if_true: [files('qxl.c', 'qxl-logger.c', 'qxl-render.c'), pixman, spice]) + qxl_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'), + if_false: files('acpi-vga-stub.c')) hw_display_modules += {'qxl': qxl_ss} endif @@ -52,6 +63,7 @@ softmmu_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c')) softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d.c', 'ati_dbg.c')) + if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss = ss.source_set() virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU', @@ -61,10 +73,12 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c')) hw_display_modules += {'virtio-gpu': virtio_gpu_ss} - virtio_gpu_gl_ss = ss.source_set() - virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', virgl, opengl], - if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) - hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss} + if virgl.found() and opengl.found() + virtio_gpu_gl_ss = ss.source_set() + virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', virgl, opengl], + if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) + hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss} + endif endif if config_all_devices.has_key('CONFIG_VIRTIO_PCI') @@ -75,10 +89,12 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI') if_true: files('vhost-user-gpu-pci.c')) hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss} - virtio_gpu_pci_gl_ss = ss.source_set() - virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', virgl, opengl], - if_true: [files('virtio-gpu-pci-gl.c'), pixman]) - hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss} + if virgl.found() and opengl.found() + virtio_gpu_pci_gl_ss = ss.source_set() + virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', virgl, opengl], + if_true: [files('virtio-gpu-pci-gl.c'), pixman]) + hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss} + endif endif if config_all_devices.has_key('CONFIG_VIRTIO_VGA') @@ -87,14 +103,19 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA') if_true: [files('virtio-vga.c'), pixman]) virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA', if_true: files('vhost-user-vga.c')) + virtio_vga_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'), + if_false: files('acpi-vga-stub.c')) hw_display_modules += {'virtio-vga': virtio_vga_ss} virtio_vga_gl_ss = ss.source_set() virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', virgl, opengl], if_true: [files('virtio-vga-gl.c'), pixman]) + virtio_vga_gl_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'), + if_false: files('acpi-vga-stub.c')) hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} endif specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c')) +softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-vga-stub.c')) modules += { 'hw-display': hw_display_modules } diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c index dd6a1aa8aeeb..8446ff3c00e2 100644 --- a/hw/display/next-fb.c +++ b/hw/display/next-fb.c @@ -126,7 +126,7 @@ static void nextfb_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->realize = nextfb_realize; - /* Note: This device does not any state that we have to reset or migrate */ + /* Note: This device does not have any state that we have to reset or migrate */ } static const TypeInfo nextfb_info = { diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c index 8c0e9ee70077..f33fc7606d35 100644 --- a/hw/display/omap_dss.c +++ b/hw/display/omap_dss.c @@ -175,32 +175,32 @@ void omap_dss_reset(struct omap_dss_s *s) static uint64_t omap_diss_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_dss_s *s = (struct omap_dss_s *) opaque; + struct omap_dss_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); } switch (addr) { - case 0x00: /* DSS_REVISIONNUMBER */ + case 0x00: /* DSS_REVISIONNUMBER */ return 0x20; - case 0x10: /* DSS_SYSCONFIG */ + case 0x10: /* DSS_SYSCONFIG */ return s->autoidle; - case 0x14: /* DSS_SYSSTATUS */ - return 1; /* RESETDONE */ + case 0x14: /* DSS_SYSSTATUS */ + return 1; /* RESETDONE */ - case 0x40: /* DSS_CONTROL */ + case 0x40: /* DSS_CONTROL */ return s->control; - case 0x50: /* DSS_PSA_LCD_REG_1 */ - case 0x54: /* DSS_PSA_LCD_REG_2 */ - case 0x58: /* DSS_PSA_VIDEO_REG */ + case 0x50: /* DSS_PSA_LCD_REG_1 */ + case 0x54: /* DSS_PSA_LCD_REG_2 */ + case 0x58: /* DSS_PSA_VIDEO_REG */ /* TODO: fake some values when appropriate s->control bits are set */ return 0; - case 0x5c: /* DSS_STATUS */ + case 0x5c: /* DSS_STATUS */ return 1 + (s->control & 1); default: @@ -213,7 +213,7 @@ static uint64_t omap_diss_read(void *opaque, hwaddr addr, static void omap_diss_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_dss_s *s = (struct omap_dss_s *) opaque; + struct omap_dss_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -221,22 +221,22 @@ static void omap_diss_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* DSS_REVISIONNUMBER */ - case 0x14: /* DSS_SYSSTATUS */ - case 0x50: /* DSS_PSA_LCD_REG_1 */ - case 0x54: /* DSS_PSA_LCD_REG_2 */ - case 0x58: /* DSS_PSA_VIDEO_REG */ - case 0x5c: /* DSS_STATUS */ + case 0x00: /* DSS_REVISIONNUMBER */ + case 0x14: /* DSS_SYSSTATUS */ + case 0x50: /* DSS_PSA_LCD_REG_1 */ + case 0x54: /* DSS_PSA_LCD_REG_2 */ + case 0x58: /* DSS_PSA_VIDEO_REG */ + case 0x5c: /* DSS_STATUS */ OMAP_RO_REG(addr); break; - case 0x10: /* DSS_SYSCONFIG */ - if (value & 2) /* SOFTRESET */ + case 0x10: /* DSS_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ omap_dss_reset(s); s->autoidle = value & 1; break; - case 0x40: /* DSS_CONTROL */ + case 0x40: /* DSS_CONTROL */ s->control = value & 0x3dd; break; @@ -254,119 +254,119 @@ static const MemoryRegionOps omap_diss_ops = { static uint64_t omap_disc_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_dss_s *s = (struct omap_dss_s *) opaque; + struct omap_dss_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); } switch (addr) { - case 0x000: /* DISPC_REVISION */ + case 0x000: /* DISPC_REVISION */ return 0x20; - case 0x010: /* DISPC_SYSCONFIG */ + case 0x010: /* DISPC_SYSCONFIG */ return s->dispc.idlemode; - case 0x014: /* DISPC_SYSSTATUS */ - return 1; /* RESETDONE */ + case 0x014: /* DISPC_SYSSTATUS */ + return 1; /* RESETDONE */ - case 0x018: /* DISPC_IRQSTATUS */ + case 0x018: /* DISPC_IRQSTATUS */ return s->dispc.irqst; - case 0x01c: /* DISPC_IRQENABLE */ + case 0x01c: /* DISPC_IRQENABLE */ return s->dispc.irqen; - case 0x040: /* DISPC_CONTROL */ + case 0x040: /* DISPC_CONTROL */ return s->dispc.control; - case 0x044: /* DISPC_CONFIG */ + case 0x044: /* DISPC_CONFIG */ return s->dispc.config; - case 0x048: /* DISPC_CAPABLE */ + case 0x048: /* DISPC_CAPABLE */ return s->dispc.capable; - case 0x04c: /* DISPC_DEFAULT_COLOR0 */ + case 0x04c: /* DISPC_DEFAULT_COLOR0 */ return s->dispc.bg[0]; - case 0x050: /* DISPC_DEFAULT_COLOR1 */ + case 0x050: /* DISPC_DEFAULT_COLOR1 */ return s->dispc.bg[1]; - case 0x054: /* DISPC_TRANS_COLOR0 */ + case 0x054: /* DISPC_TRANS_COLOR0 */ return s->dispc.trans[0]; - case 0x058: /* DISPC_TRANS_COLOR1 */ + case 0x058: /* DISPC_TRANS_COLOR1 */ return s->dispc.trans[1]; - case 0x05c: /* DISPC_LINE_STATUS */ + case 0x05c: /* DISPC_LINE_STATUS */ return 0x7ff; - case 0x060: /* DISPC_LINE_NUMBER */ + case 0x060: /* DISPC_LINE_NUMBER */ return s->dispc.line; - case 0x064: /* DISPC_TIMING_H */ + case 0x064: /* DISPC_TIMING_H */ return s->dispc.timing[0]; - case 0x068: /* DISPC_TIMING_V */ + case 0x068: /* DISPC_TIMING_V */ return s->dispc.timing[1]; - case 0x06c: /* DISPC_POL_FREQ */ + case 0x06c: /* DISPC_POL_FREQ */ return s->dispc.timing[2]; - case 0x070: /* DISPC_DIVISOR */ + case 0x070: /* DISPC_DIVISOR */ return s->dispc.timing[3]; - case 0x078: /* DISPC_SIZE_DIG */ + case 0x078: /* DISPC_SIZE_DIG */ return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1); - case 0x07c: /* DISPC_SIZE_LCD */ + case 0x07c: /* DISPC_SIZE_LCD */ return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1); - case 0x080: /* DISPC_GFX_BA0 */ + case 0x080: /* DISPC_GFX_BA0 */ return s->dispc.l[0].addr[0]; - case 0x084: /* DISPC_GFX_BA1 */ + case 0x084: /* DISPC_GFX_BA1 */ return s->dispc.l[0].addr[1]; - case 0x088: /* DISPC_GFX_POSITION */ + case 0x088: /* DISPC_GFX_POSITION */ return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx; - case 0x08c: /* DISPC_GFX_SIZE */ + case 0x08c: /* DISPC_GFX_SIZE */ return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1); - case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ + case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ return s->dispc.l[0].attr; - case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ + case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ return s->dispc.l[0].tresh; - case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */ + case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */ return 256; - case 0x0ac: /* DISPC_GFX_ROW_INC */ + case 0x0ac: /* DISPC_GFX_ROW_INC */ return s->dispc.l[0].rowinc; - case 0x0b0: /* DISPC_GFX_PIXEL_INC */ + case 0x0b0: /* DISPC_GFX_PIXEL_INC */ return s->dispc.l[0].colinc; - case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ + case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ return s->dispc.l[0].wininc; - case 0x0b8: /* DISPC_GFX_TABLE_BA */ + case 0x0b8: /* DISPC_GFX_TABLE_BA */ return s->dispc.l[0].addr[2]; - case 0x0bc: /* DISPC_VID1_BA0 */ - case 0x0c0: /* DISPC_VID1_BA1 */ - case 0x0c4: /* DISPC_VID1_POSITION */ - case 0x0c8: /* DISPC_VID1_SIZE */ - case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ - case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ - case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */ - case 0x0d8: /* DISPC_VID1_ROW_INC */ - case 0x0dc: /* DISPC_VID1_PIXEL_INC */ - case 0x0e0: /* DISPC_VID1_FIR */ - case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ - case 0x0e8: /* DISPC_VID1_ACCU0 */ - case 0x0ec: /* DISPC_VID1_ACCU1 */ - case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ - case 0x14c: /* DISPC_VID2_BA0 */ - case 0x150: /* DISPC_VID2_BA1 */ - case 0x154: /* DISPC_VID2_POSITION */ - case 0x158: /* DISPC_VID2_SIZE */ - case 0x15c: /* DISPC_VID2_ATTRIBUTES */ - case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ - case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */ - case 0x168: /* DISPC_VID2_ROW_INC */ - case 0x16c: /* DISPC_VID2_PIXEL_INC */ - case 0x170: /* DISPC_VID2_FIR */ - case 0x174: /* DISPC_VID2_PICTURE_SIZE */ - case 0x178: /* DISPC_VID2_ACCU0 */ - case 0x17c: /* DISPC_VID2_ACCU1 */ - case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ - case 0x1d4: /* DISPC_DATA_CYCLE1 */ - case 0x1d8: /* DISPC_DATA_CYCLE2 */ - case 0x1dc: /* DISPC_DATA_CYCLE3 */ + case 0x0bc: /* DISPC_VID1_BA0 */ + case 0x0c0: /* DISPC_VID1_BA1 */ + case 0x0c4: /* DISPC_VID1_POSITION */ + case 0x0c8: /* DISPC_VID1_SIZE */ + case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ + case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ + case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */ + case 0x0d8: /* DISPC_VID1_ROW_INC */ + case 0x0dc: /* DISPC_VID1_PIXEL_INC */ + case 0x0e0: /* DISPC_VID1_FIR */ + case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ + case 0x0e8: /* DISPC_VID1_ACCU0 */ + case 0x0ec: /* DISPC_VID1_ACCU1 */ + case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ + case 0x14c: /* DISPC_VID2_BA0 */ + case 0x150: /* DISPC_VID2_BA1 */ + case 0x154: /* DISPC_VID2_POSITION */ + case 0x158: /* DISPC_VID2_SIZE */ + case 0x15c: /* DISPC_VID2_ATTRIBUTES */ + case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ + case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */ + case 0x168: /* DISPC_VID2_ROW_INC */ + case 0x16c: /* DISPC_VID2_PIXEL_INC */ + case 0x170: /* DISPC_VID2_FIR */ + case 0x174: /* DISPC_VID2_PICTURE_SIZE */ + case 0x178: /* DISPC_VID2_ACCU0 */ + case 0x17c: /* DISPC_VID2_ACCU1 */ + case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ + case 0x1d4: /* DISPC_DATA_CYCLE1 */ + case 0x1d8: /* DISPC_DATA_CYCLE2 */ + case 0x1dc: /* DISPC_DATA_CYCLE3 */ return 0; default: @@ -379,7 +379,7 @@ static uint64_t omap_disc_read(void *opaque, hwaddr addr, static void omap_disc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_dss_s *s = (struct omap_dss_s *) opaque; + struct omap_dss_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -387,33 +387,33 @@ static void omap_disc_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x010: /* DISPC_SYSCONFIG */ - if (value & 2) /* SOFTRESET */ + case 0x010: /* DISPC_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ omap_dss_reset(s); s->dispc.idlemode = value & 0x301b; break; - case 0x018: /* DISPC_IRQSTATUS */ + case 0x018: /* DISPC_IRQSTATUS */ s->dispc.irqst &= ~value; omap_dispc_interrupt_update(s); break; - case 0x01c: /* DISPC_IRQENABLE */ + case 0x01c: /* DISPC_IRQENABLE */ s->dispc.irqen = value & 0xffff; omap_dispc_interrupt_update(s); break; - case 0x040: /* DISPC_CONTROL */ + case 0x040: /* DISPC_CONTROL */ s->dispc.control = value & 0x07ff9fff; s->dig.enable = (value >> 1) & 1; s->lcd.enable = (value >> 0) & 1; - if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */ + if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */ if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) { fprintf(stderr, "%s: Overlay Optimization when no overlay " "region effectively exists leads to " "unpredictable behaviour!\n", __func__); } - if (value & (1 << 6)) { /* GODIGITAL */ + if (value & (1 << 6)) { /* GODIGITAL */ /* XXX: Shadowed fields are: * s->dispc.config * s->dispc.capable @@ -444,13 +444,13 @@ static void omap_disc_write(void *opaque, hwaddr addr, * All they need to be loaded here from their shadow registers. */ } - if (value & (1 << 5)) { /* GOLCD */ + if (value & (1 << 5)) { /* GOLCD */ /* XXX: Likewise for LCD here. */ } s->dispc.invalidate = 1; break; - case 0x044: /* DISPC_CONFIG */ + case 0x044: /* DISPC_CONFIG */ s->dispc.config = value & 0x3fff; /* XXX: * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded @@ -459,73 +459,73 @@ static void omap_disc_write(void *opaque, hwaddr addr, s->dispc.invalidate = 1; break; - case 0x048: /* DISPC_CAPABLE */ + case 0x048: /* DISPC_CAPABLE */ s->dispc.capable = value & 0x3ff; break; - case 0x04c: /* DISPC_DEFAULT_COLOR0 */ + case 0x04c: /* DISPC_DEFAULT_COLOR0 */ s->dispc.bg[0] = value & 0xffffff; s->dispc.invalidate = 1; break; - case 0x050: /* DISPC_DEFAULT_COLOR1 */ + case 0x050: /* DISPC_DEFAULT_COLOR1 */ s->dispc.bg[1] = value & 0xffffff; s->dispc.invalidate = 1; break; - case 0x054: /* DISPC_TRANS_COLOR0 */ + case 0x054: /* DISPC_TRANS_COLOR0 */ s->dispc.trans[0] = value & 0xffffff; s->dispc.invalidate = 1; break; - case 0x058: /* DISPC_TRANS_COLOR1 */ + case 0x058: /* DISPC_TRANS_COLOR1 */ s->dispc.trans[1] = value & 0xffffff; s->dispc.invalidate = 1; break; - case 0x060: /* DISPC_LINE_NUMBER */ + case 0x060: /* DISPC_LINE_NUMBER */ s->dispc.line = value & 0x7ff; break; - case 0x064: /* DISPC_TIMING_H */ + case 0x064: /* DISPC_TIMING_H */ s->dispc.timing[0] = value & 0x0ff0ff3f; break; - case 0x068: /* DISPC_TIMING_V */ + case 0x068: /* DISPC_TIMING_V */ s->dispc.timing[1] = value & 0x0ff0ff3f; break; - case 0x06c: /* DISPC_POL_FREQ */ + case 0x06c: /* DISPC_POL_FREQ */ s->dispc.timing[2] = value & 0x0003ffff; break; - case 0x070: /* DISPC_DIVISOR */ + case 0x070: /* DISPC_DIVISOR */ s->dispc.timing[3] = value & 0x00ff00ff; break; - case 0x078: /* DISPC_SIZE_DIG */ - s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ - s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ + case 0x078: /* DISPC_SIZE_DIG */ + s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ + s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ s->dispc.invalidate = 1; break; - case 0x07c: /* DISPC_SIZE_LCD */ - s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ - s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ + case 0x07c: /* DISPC_SIZE_LCD */ + s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ + s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ s->dispc.invalidate = 1; break; - case 0x080: /* DISPC_GFX_BA0 */ + case 0x080: /* DISPC_GFX_BA0 */ s->dispc.l[0].addr[0] = (hwaddr) value; s->dispc.invalidate = 1; break; - case 0x084: /* DISPC_GFX_BA1 */ + case 0x084: /* DISPC_GFX_BA1 */ s->dispc.l[0].addr[1] = (hwaddr) value; s->dispc.invalidate = 1; break; - case 0x088: /* DISPC_GFX_POSITION */ - s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */ - s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */ + case 0x088: /* DISPC_GFX_POSITION */ + s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */ + s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */ s->dispc.invalidate = 1; break; - case 0x08c: /* DISPC_GFX_SIZE */ - s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */ - s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */ + case 0x08c: /* DISPC_GFX_SIZE */ + s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */ + s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */ s->dispc.invalidate = 1; break; - case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ + case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ s->dispc.l[0].attr = value & 0x7ff; if (value & (3 << 9)) fprintf(stderr, "%s: Big-endian pixel format not supported\n", @@ -534,54 +534,54 @@ static void omap_disc_write(void *opaque, hwaddr addr, s->dispc.l[0].bpp = (value >> 1) & 0xf; s->dispc.invalidate = 1; break; - case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ + case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ s->dispc.l[0].tresh = value & 0x01ff01ff; break; - case 0x0ac: /* DISPC_GFX_ROW_INC */ + case 0x0ac: /* DISPC_GFX_ROW_INC */ s->dispc.l[0].rowinc = value; s->dispc.invalidate = 1; break; - case 0x0b0: /* DISPC_GFX_PIXEL_INC */ + case 0x0b0: /* DISPC_GFX_PIXEL_INC */ s->dispc.l[0].colinc = value; s->dispc.invalidate = 1; break; - case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ + case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ s->dispc.l[0].wininc = value; break; - case 0x0b8: /* DISPC_GFX_TABLE_BA */ + case 0x0b8: /* DISPC_GFX_TABLE_BA */ s->dispc.l[0].addr[2] = (hwaddr) value; s->dispc.invalidate = 1; break; - case 0x0bc: /* DISPC_VID1_BA0 */ - case 0x0c0: /* DISPC_VID1_BA1 */ - case 0x0c4: /* DISPC_VID1_POSITION */ - case 0x0c8: /* DISPC_VID1_SIZE */ - case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ - case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ - case 0x0d8: /* DISPC_VID1_ROW_INC */ - case 0x0dc: /* DISPC_VID1_PIXEL_INC */ - case 0x0e0: /* DISPC_VID1_FIR */ - case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ - case 0x0e8: /* DISPC_VID1_ACCU0 */ - case 0x0ec: /* DISPC_VID1_ACCU1 */ - case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ - case 0x14c: /* DISPC_VID2_BA0 */ - case 0x150: /* DISPC_VID2_BA1 */ - case 0x154: /* DISPC_VID2_POSITION */ - case 0x158: /* DISPC_VID2_SIZE */ - case 0x15c: /* DISPC_VID2_ATTRIBUTES */ - case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ - case 0x168: /* DISPC_VID2_ROW_INC */ - case 0x16c: /* DISPC_VID2_PIXEL_INC */ - case 0x170: /* DISPC_VID2_FIR */ - case 0x174: /* DISPC_VID2_PICTURE_SIZE */ - case 0x178: /* DISPC_VID2_ACCU0 */ - case 0x17c: /* DISPC_VID2_ACCU1 */ - case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ - case 0x1d4: /* DISPC_DATA_CYCLE1 */ - case 0x1d8: /* DISPC_DATA_CYCLE2 */ - case 0x1dc: /* DISPC_DATA_CYCLE3 */ + case 0x0bc: /* DISPC_VID1_BA0 */ + case 0x0c0: /* DISPC_VID1_BA1 */ + case 0x0c4: /* DISPC_VID1_POSITION */ + case 0x0c8: /* DISPC_VID1_SIZE */ + case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ + case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ + case 0x0d8: /* DISPC_VID1_ROW_INC */ + case 0x0dc: /* DISPC_VID1_PIXEL_INC */ + case 0x0e0: /* DISPC_VID1_FIR */ + case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ + case 0x0e8: /* DISPC_VID1_ACCU0 */ + case 0x0ec: /* DISPC_VID1_ACCU1 */ + case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ + case 0x14c: /* DISPC_VID2_BA0 */ + case 0x150: /* DISPC_VID2_BA1 */ + case 0x154: /* DISPC_VID2_POSITION */ + case 0x158: /* DISPC_VID2_SIZE */ + case 0x15c: /* DISPC_VID2_ATTRIBUTES */ + case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ + case 0x168: /* DISPC_VID2_ROW_INC */ + case 0x16c: /* DISPC_VID2_PIXEL_INC */ + case 0x170: /* DISPC_VID2_FIR */ + case 0x174: /* DISPC_VID2_PICTURE_SIZE */ + case 0x178: /* DISPC_VID2_ACCU0 */ + case 0x17c: /* DISPC_VID2_ACCU1 */ + case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ + case 0x1d4: /* DISPC_DATA_CYCLE1 */ + case 0x1d8: /* DISPC_DATA_CYCLE2 */ + case 0x1dc: /* DISPC_DATA_CYCLE3 */ break; default: @@ -617,14 +617,14 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s) if (!s->rfbi.enable || s->rfbi.busy) return; - if (s->rfbi.control & (1 << 1)) { /* BYPASS */ + if (s->rfbi.control & (1 << 1)) { /* BYPASS */ /* TODO: in non-Bypass mode we probably need to just assert the * DRQ and wait for DMA to write the pixels. */ qemu_log_mask(LOG_UNIMP, "%s: Bypass mode unimplemented\n", __func__); return; } - if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */ + if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */ return; /* TODO: check that LCD output is enabled in DISPC. */ @@ -665,71 +665,70 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s) omap_rfbi_transfer_stop(s); /* TODO */ - s->dispc.irqst |= 1; /* FRAMEDONE */ + s->dispc.irqst |= 1; /* FRAMEDONE */ omap_dispc_interrupt_update(s); } -static uint64_t omap_rfbi_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_rfbi_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_dss_s *s = (struct omap_dss_s *) opaque; + struct omap_dss_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); } switch (addr) { - case 0x00: /* RFBI_REVISION */ + case 0x00: /* RFBI_REVISION */ return 0x10; - case 0x10: /* RFBI_SYSCONFIG */ + case 0x10: /* RFBI_SYSCONFIG */ return s->rfbi.idlemode; - case 0x14: /* RFBI_SYSSTATUS */ - return 1 | (s->rfbi.busy << 8); /* RESETDONE */ + case 0x14: /* RFBI_SYSSTATUS */ + return 1 | (s->rfbi.busy << 8); /* RESETDONE */ - case 0x40: /* RFBI_CONTROL */ + case 0x40: /* RFBI_CONTROL */ return s->rfbi.control; - case 0x44: /* RFBI_PIXELCNT */ + case 0x44: /* RFBI_PIXELCNT */ return s->rfbi.pixels; - case 0x48: /* RFBI_LINE_NUMBER */ + case 0x48: /* RFBI_LINE_NUMBER */ return s->rfbi.skiplines; - case 0x58: /* RFBI_READ */ - case 0x5c: /* RFBI_STATUS */ + case 0x58: /* RFBI_READ */ + case 0x5c: /* RFBI_STATUS */ return s->rfbi.rxbuf; - case 0x60: /* RFBI_CONFIG0 */ + case 0x60: /* RFBI_CONFIG0 */ return s->rfbi.config[0]; - case 0x64: /* RFBI_ONOFF_TIME0 */ + case 0x64: /* RFBI_ONOFF_TIME0 */ return s->rfbi.time[0]; - case 0x68: /* RFBI_CYCLE_TIME0 */ + case 0x68: /* RFBI_CYCLE_TIME0 */ return s->rfbi.time[1]; - case 0x6c: /* RFBI_DATA_CYCLE1_0 */ + case 0x6c: /* RFBI_DATA_CYCLE1_0 */ return s->rfbi.data[0]; - case 0x70: /* RFBI_DATA_CYCLE2_0 */ + case 0x70: /* RFBI_DATA_CYCLE2_0 */ return s->rfbi.data[1]; - case 0x74: /* RFBI_DATA_CYCLE3_0 */ + case 0x74: /* RFBI_DATA_CYCLE3_0 */ return s->rfbi.data[2]; - case 0x78: /* RFBI_CONFIG1 */ + case 0x78: /* RFBI_CONFIG1 */ return s->rfbi.config[1]; - case 0x7c: /* RFBI_ONOFF_TIME1 */ + case 0x7c: /* RFBI_ONOFF_TIME1 */ return s->rfbi.time[2]; - case 0x80: /* RFBI_CYCLE_TIME1 */ + case 0x80: /* RFBI_CYCLE_TIME1 */ return s->rfbi.time[3]; - case 0x84: /* RFBI_DATA_CYCLE1_1 */ + case 0x84: /* RFBI_DATA_CYCLE1_1 */ return s->rfbi.data[3]; - case 0x88: /* RFBI_DATA_CYCLE2_1 */ + case 0x88: /* RFBI_DATA_CYCLE2_1 */ return s->rfbi.data[4]; - case 0x8c: /* RFBI_DATA_CYCLE3_1 */ + case 0x8c: /* RFBI_DATA_CYCLE3_1 */ return s->rfbi.data[5]; - case 0x90: /* RFBI_VSYNC_WIDTH */ + case 0x90: /* RFBI_VSYNC_WIDTH */ return s->rfbi.vsync; - case 0x94: /* RFBI_HSYNC_WIDTH */ + case 0x94: /* RFBI_HSYNC_WIDTH */ return s->rfbi.hsync; } OMAP_BAD_REG(addr); @@ -739,7 +738,7 @@ static uint64_t omap_rfbi_read(void *opaque, hwaddr addr, static void omap_rfbi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_dss_s *s = (struct omap_dss_s *) opaque; + struct omap_dss_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); @@ -747,41 +746,41 @@ static void omap_rfbi_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x10: /* RFBI_SYSCONFIG */ - if (value & 2) /* SOFTRESET */ + case 0x10: /* RFBI_SYSCONFIG */ + if (value & 2) /* SOFTRESET */ omap_rfbi_reset(s); s->rfbi.idlemode = value & 0x19; break; - case 0x40: /* RFBI_CONTROL */ + case 0x40: /* RFBI_CONTROL */ s->rfbi.control = value & 0xf; s->rfbi.enable = value & 1; - if (value & (1 << 4) && /* ITE */ + if (value & (1 << 4) && /* ITE */ !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc)) omap_rfbi_transfer_start(s); break; - case 0x44: /* RFBI_PIXELCNT */ + case 0x44: /* RFBI_PIXELCNT */ s->rfbi.pixels = value; break; - case 0x48: /* RFBI_LINE_NUMBER */ + case 0x48: /* RFBI_LINE_NUMBER */ s->rfbi.skiplines = value & 0x7ff; break; - case 0x4c: /* RFBI_CMD */ + case 0x4c: /* RFBI_CMD */ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff); if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff); break; - case 0x50: /* RFBI_PARAM */ + case 0x50: /* RFBI_PARAM */ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff); if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff); break; - case 0x54: /* RFBI_DATA */ + case 0x54: /* RFBI_DATA */ /* TODO: take into account the format set up in s->rfbi.config[?] and * s->rfbi.data[?], but special-case the most usual scenario so that * speed doesn't suffer. */ @@ -796,7 +795,7 @@ static void omap_rfbi_write(void *opaque, hwaddr addr, if (!-- s->rfbi.pixels) omap_rfbi_transfer_stop(s); break; - case 0x58: /* RFBI_READ */ + case 0x58: /* RFBI_READ */ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1); else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) @@ -805,7 +804,7 @@ static void omap_rfbi_write(void *opaque, hwaddr addr, omap_rfbi_transfer_stop(s); break; - case 0x5c: /* RFBI_STATUS */ + case 0x5c: /* RFBI_STATUS */ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0); else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) @@ -814,49 +813,49 @@ static void omap_rfbi_write(void *opaque, hwaddr addr, omap_rfbi_transfer_stop(s); break; - case 0x60: /* RFBI_CONFIG0 */ + case 0x60: /* RFBI_CONFIG0 */ s->rfbi.config[0] = value & 0x003f1fff; break; - case 0x64: /* RFBI_ONOFF_TIME0 */ + case 0x64: /* RFBI_ONOFF_TIME0 */ s->rfbi.time[0] = value & 0x3fffffff; break; - case 0x68: /* RFBI_CYCLE_TIME0 */ + case 0x68: /* RFBI_CYCLE_TIME0 */ s->rfbi.time[1] = value & 0x0fffffff; break; - case 0x6c: /* RFBI_DATA_CYCLE1_0 */ + case 0x6c: /* RFBI_DATA_CYCLE1_0 */ s->rfbi.data[0] = value & 0x0f1f0f1f; break; - case 0x70: /* RFBI_DATA_CYCLE2_0 */ + case 0x70: /* RFBI_DATA_CYCLE2_0 */ s->rfbi.data[1] = value & 0x0f1f0f1f; break; - case 0x74: /* RFBI_DATA_CYCLE3_0 */ + case 0x74: /* RFBI_DATA_CYCLE3_0 */ s->rfbi.data[2] = value & 0x0f1f0f1f; break; - case 0x78: /* RFBI_CONFIG1 */ + case 0x78: /* RFBI_CONFIG1 */ s->rfbi.config[1] = value & 0x003f1fff; break; - case 0x7c: /* RFBI_ONOFF_TIME1 */ + case 0x7c: /* RFBI_ONOFF_TIME1 */ s->rfbi.time[2] = value & 0x3fffffff; break; - case 0x80: /* RFBI_CYCLE_TIME1 */ + case 0x80: /* RFBI_CYCLE_TIME1 */ s->rfbi.time[3] = value & 0x0fffffff; break; - case 0x84: /* RFBI_DATA_CYCLE1_1 */ + case 0x84: /* RFBI_DATA_CYCLE1_1 */ s->rfbi.data[3] = value & 0x0f1f0f1f; break; - case 0x88: /* RFBI_DATA_CYCLE2_1 */ + case 0x88: /* RFBI_DATA_CYCLE2_1 */ s->rfbi.data[4] = value & 0x0f1f0f1f; break; - case 0x8c: /* RFBI_DATA_CYCLE3_1 */ + case 0x8c: /* RFBI_DATA_CYCLE3_1 */ s->rfbi.data[5] = value & 0x0f1f0f1f; break; - case 0x90: /* RFBI_VSYNC_WIDTH */ + case 0x90: /* RFBI_VSYNC_WIDTH */ s->rfbi.vsync = value & 0xffff; break; - case 0x94: /* RFBI_HSYNC_WIDTH */ + case 0x94: /* RFBI_HSYNC_WIDTH */ s->rfbi.hsync = value & 0xffff; break; @@ -879,49 +878,49 @@ static uint64_t omap_venc_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* REV_ID */ - case 0x04: /* STATUS */ - case 0x08: /* F_CONTROL */ - case 0x10: /* VIDOUT_CTRL */ - case 0x14: /* SYNC_CTRL */ - case 0x1c: /* LLEN */ - case 0x20: /* FLENS */ - case 0x24: /* HFLTR_CTRL */ - case 0x28: /* CC_CARR_WSS_CARR */ - case 0x2c: /* C_PHASE */ - case 0x30: /* GAIN_U */ - case 0x34: /* GAIN_V */ - case 0x38: /* GAIN_Y */ - case 0x3c: /* BLACK_LEVEL */ - case 0x40: /* BLANK_LEVEL */ - case 0x44: /* X_COLOR */ - case 0x48: /* M_CONTROL */ - case 0x4c: /* BSTAMP_WSS_DATA */ - case 0x50: /* S_CARR */ - case 0x54: /* LINE21 */ - case 0x58: /* LN_SEL */ - case 0x5c: /* L21__WC_CTL */ - case 0x60: /* HTRIGGER_VTRIGGER */ - case 0x64: /* SAVID__EAVID */ - case 0x68: /* FLEN__FAL */ - case 0x6c: /* LAL__PHASE_RESET */ - case 0x70: /* HS_INT_START_STOP_X */ - case 0x74: /* HS_EXT_START_STOP_X */ - case 0x78: /* VS_INT_START_X */ - case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ - case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ - case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ - case 0x88: /* VS_EXT_STOP_Y */ - case 0x90: /* AVID_START_STOP_X */ - case 0x94: /* AVID_START_STOP_Y */ - case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ - case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ - case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ - case 0xb0: /* TVDETGP_INT_START_STOP_X */ - case 0xb4: /* TVDETGP_INT_START_STOP_Y */ - case 0xb8: /* GEN_CTRL */ - case 0xc4: /* DAC_TST__DAC_A */ - case 0xc8: /* DAC_B__DAC_C */ + case 0x00: /* REV_ID */ + case 0x04: /* STATUS */ + case 0x08: /* F_CONTROL */ + case 0x10: /* VIDOUT_CTRL */ + case 0x14: /* SYNC_CTRL */ + case 0x1c: /* LLEN */ + case 0x20: /* FLENS */ + case 0x24: /* HFLTR_CTRL */ + case 0x28: /* CC_CARR_WSS_CARR */ + case 0x2c: /* C_PHASE */ + case 0x30: /* GAIN_U */ + case 0x34: /* GAIN_V */ + case 0x38: /* GAIN_Y */ + case 0x3c: /* BLACK_LEVEL */ + case 0x40: /* BLANK_LEVEL */ + case 0x44: /* X_COLOR */ + case 0x48: /* M_CONTROL */ + case 0x4c: /* BSTAMP_WSS_DATA */ + case 0x50: /* S_CARR */ + case 0x54: /* LINE21 */ + case 0x58: /* LN_SEL */ + case 0x5c: /* L21__WC_CTL */ + case 0x60: /* HTRIGGER_VTRIGGER */ + case 0x64: /* SAVID__EAVID */ + case 0x68: /* FLEN__FAL */ + case 0x6c: /* LAL__PHASE_RESET */ + case 0x70: /* HS_INT_START_STOP_X */ + case 0x74: /* HS_EXT_START_STOP_X */ + case 0x78: /* VS_INT_START_X */ + case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ + case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ + case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ + case 0x88: /* VS_EXT_STOP_Y */ + case 0x90: /* AVID_START_STOP_X */ + case 0x94: /* AVID_START_STOP_Y */ + case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ + case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ + case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ + case 0xb0: /* TVDETGP_INT_START_STOP_X */ + case 0xb4: /* TVDETGP_INT_START_STOP_Y */ + case 0xb8: /* GEN_CTRL */ + case 0xc4: /* DAC_TST__DAC_A */ + case 0xc8: /* DAC_B__DAC_C */ return 0; default: @@ -940,47 +939,47 @@ static void omap_venc_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x08: /* F_CONTROL */ - case 0x10: /* VIDOUT_CTRL */ - case 0x14: /* SYNC_CTRL */ - case 0x1c: /* LLEN */ - case 0x20: /* FLENS */ - case 0x24: /* HFLTR_CTRL */ - case 0x28: /* CC_CARR_WSS_CARR */ - case 0x2c: /* C_PHASE */ - case 0x30: /* GAIN_U */ - case 0x34: /* GAIN_V */ - case 0x38: /* GAIN_Y */ - case 0x3c: /* BLACK_LEVEL */ - case 0x40: /* BLANK_LEVEL */ - case 0x44: /* X_COLOR */ - case 0x48: /* M_CONTROL */ - case 0x4c: /* BSTAMP_WSS_DATA */ - case 0x50: /* S_CARR */ - case 0x54: /* LINE21 */ - case 0x58: /* LN_SEL */ - case 0x5c: /* L21__WC_CTL */ - case 0x60: /* HTRIGGER_VTRIGGER */ - case 0x64: /* SAVID__EAVID */ - case 0x68: /* FLEN__FAL */ - case 0x6c: /* LAL__PHASE_RESET */ - case 0x70: /* HS_INT_START_STOP_X */ - case 0x74: /* HS_EXT_START_STOP_X */ - case 0x78: /* VS_INT_START_X */ - case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ - case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ - case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ - case 0x88: /* VS_EXT_STOP_Y */ - case 0x90: /* AVID_START_STOP_X */ - case 0x94: /* AVID_START_STOP_Y */ - case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ - case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ - case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ - case 0xb0: /* TVDETGP_INT_START_STOP_X */ - case 0xb4: /* TVDETGP_INT_START_STOP_Y */ - case 0xb8: /* GEN_CTRL */ - case 0xc4: /* DAC_TST__DAC_A */ - case 0xc8: /* DAC_B__DAC_C */ + case 0x08: /* F_CONTROL */ + case 0x10: /* VIDOUT_CTRL */ + case 0x14: /* SYNC_CTRL */ + case 0x1c: /* LLEN */ + case 0x20: /* FLENS */ + case 0x24: /* HFLTR_CTRL */ + case 0x28: /* CC_CARR_WSS_CARR */ + case 0x2c: /* C_PHASE */ + case 0x30: /* GAIN_U */ + case 0x34: /* GAIN_V */ + case 0x38: /* GAIN_Y */ + case 0x3c: /* BLACK_LEVEL */ + case 0x40: /* BLANK_LEVEL */ + case 0x44: /* X_COLOR */ + case 0x48: /* M_CONTROL */ + case 0x4c: /* BSTAMP_WSS_DATA */ + case 0x50: /* S_CARR */ + case 0x54: /* LINE21 */ + case 0x58: /* LN_SEL */ + case 0x5c: /* L21__WC_CTL */ + case 0x60: /* HTRIGGER_VTRIGGER */ + case 0x64: /* SAVID__EAVID */ + case 0x68: /* FLEN__FAL */ + case 0x6c: /* LAL__PHASE_RESET */ + case 0x70: /* HS_INT_START_STOP_X */ + case 0x74: /* HS_EXT_START_STOP_X */ + case 0x78: /* VS_INT_START_X */ + case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ + case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ + case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ + case 0x88: /* VS_EXT_STOP_Y */ + case 0x90: /* AVID_START_STOP_X */ + case 0x94: /* AVID_START_STOP_Y */ + case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ + case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ + case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ + case 0xb0: /* TVDETGP_INT_START_STOP_X */ + case 0xb4: /* TVDETGP_INT_START_STOP_Y */ + case 0xb8: /* GEN_CTRL */ + case 0xc4: /* DAC_TST__DAC_A */ + case 0xc8: /* DAC_B__DAC_C */ break; default: @@ -1002,15 +1001,15 @@ static uint64_t omap_im3_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x0a8: /* SBIMERRLOGA */ - case 0x0b0: /* SBIMERRLOG */ - case 0x190: /* SBIMSTATE */ - case 0x198: /* SBTMSTATE_L */ - case 0x19c: /* SBTMSTATE_H */ - case 0x1a8: /* SBIMCONFIG_L */ - case 0x1ac: /* SBIMCONFIG_H */ - case 0x1f8: /* SBID_L */ - case 0x1fc: /* SBID_H */ + case 0x0a8: /* SBIMERRLOGA */ + case 0x0b0: /* SBIMERRLOG */ + case 0x190: /* SBIMSTATE */ + case 0x198: /* SBTMSTATE_L */ + case 0x19c: /* SBTMSTATE_H */ + case 0x1a8: /* SBIMCONFIG_L */ + case 0x1ac: /* SBIMCONFIG_H */ + case 0x1f8: /* SBID_L */ + case 0x1fc: /* SBID_H */ return 0; default: @@ -1029,12 +1028,12 @@ static void omap_im3_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x0b0: /* SBIMERRLOG */ - case 0x190: /* SBIMSTATE */ - case 0x198: /* SBTMSTATE_L */ - case 0x19c: /* SBTMSTATE_H */ - case 0x1a8: /* SBIMCONFIG_L */ - case 0x1ac: /* SBIMCONFIG_H */ + case 0x0b0: /* SBIMERRLOG */ + case 0x190: /* SBIMSTATE */ + case 0x198: /* SBTMSTATE_L */ + case 0x19c: /* SBTMSTATE_H */ + case 0x1a8: /* SBIMCONFIG_L */ + case 0x1ac: /* SBIMCONFIG_H */ break; default: diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c index 0ba42ef637c4..3532a801be29 100644 --- a/hw/display/omap_lcdc.c +++ b/hw/display/omap_lcdc.c @@ -198,7 +198,7 @@ static void draw_line16_32(void *opaque, uint8_t *d, const uint8_t *s, static void omap_update_display(void *opaque) { - struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; + struct omap_lcd_panel_s *omap_lcd = opaque; DisplaySurface *surface; drawfn draw_line; int size, height, first, last; @@ -376,10 +376,9 @@ static void omap_lcd_update(struct omap_lcd_panel_s *s) { } } -static uint64_t omap_lcdc_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_lcdc_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; + struct omap_lcd_panel_s *s = opaque; switch (addr) { case 0x00: /* LCD_CONTROL */ @@ -412,7 +411,7 @@ static uint64_t omap_lcdc_read(void *opaque, hwaddr addr, static void omap_lcdc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; + struct omap_lcd_panel_s *s = opaque; switch (addr) { case 0x00: /* LCD_CONTROL */ diff --git a/hw/display/pl110_template.h b/hw/display/pl110_template.h index 877419aa817a..00877853225d 100644 --- a/hw/display/pl110_template.h +++ b/hw/display/pl110_template.h @@ -15,18 +15,18 @@ #if ORDER == 0 #define NAME glue(lblp_, BORDER) -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define SWAP_WORDS 1 #endif #elif ORDER == 1 #define NAME glue(bbbp_, BORDER) -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN #define SWAP_WORDS 1 #endif #else #define SWAP_PIXELS 1 #define NAME glue(lbbp_, BORDER) -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define SWAP_WORDS 1 #endif #endif diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index 0f06ed6e9f3d..eb83d882222e 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -86,106 +86,106 @@ typedef struct QEMU_PACKED { uint32_t ldcmd; } PXAFrameDescriptor; -#define LCCR0 0x000 /* LCD Controller Control register 0 */ -#define LCCR1 0x004 /* LCD Controller Control register 1 */ -#define LCCR2 0x008 /* LCD Controller Control register 2 */ -#define LCCR3 0x00c /* LCD Controller Control register 3 */ -#define LCCR4 0x010 /* LCD Controller Control register 4 */ -#define LCCR5 0x014 /* LCD Controller Control register 5 */ - -#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */ -#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */ -#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */ -#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */ -#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */ -#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */ -#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */ - -#define LCSR1 0x034 /* LCD Controller Status register 1 */ -#define LCSR0 0x038 /* LCD Controller Status register 0 */ -#define LIIDR 0x03c /* LCD Controller Interrupt ID register */ - -#define TRGBR 0x040 /* TMED RGB Seed register */ -#define TCR 0x044 /* TMED Control register */ - -#define OVL1C1 0x050 /* Overlay 1 Control register 1 */ -#define OVL1C2 0x060 /* Overlay 1 Control register 2 */ -#define OVL2C1 0x070 /* Overlay 2 Control register 1 */ -#define OVL2C2 0x080 /* Overlay 2 Control register 2 */ -#define CCR 0x090 /* Cursor Control register */ - -#define CMDCR 0x100 /* Command Control register */ -#define PRSR 0x104 /* Panel Read Status register */ - -#define PXA_LCDDMA_CHANS 7 -#define DMA_FDADR 0x00 /* Frame Descriptor Address register */ -#define DMA_FSADR 0x04 /* Frame Source Address register */ -#define DMA_FIDR 0x08 /* Frame ID register */ -#define DMA_LDCMD 0x0c /* Command register */ +#define LCCR0 0x000 /* LCD Controller Control register 0 */ +#define LCCR1 0x004 /* LCD Controller Control register 1 */ +#define LCCR2 0x008 /* LCD Controller Control register 2 */ +#define LCCR3 0x00c /* LCD Controller Control register 3 */ +#define LCCR4 0x010 /* LCD Controller Control register 4 */ +#define LCCR5 0x014 /* LCD Controller Control register 5 */ + +#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */ +#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */ +#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */ +#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */ +#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */ +#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */ +#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */ + +#define LCSR1 0x034 /* LCD Controller Status register 1 */ +#define LCSR0 0x038 /* LCD Controller Status register 0 */ +#define LIIDR 0x03c /* LCD Controller Interrupt ID register */ + +#define TRGBR 0x040 /* TMED RGB Seed register */ +#define TCR 0x044 /* TMED Control register */ + +#define OVL1C1 0x050 /* Overlay 1 Control register 1 */ +#define OVL1C2 0x060 /* Overlay 1 Control register 2 */ +#define OVL2C1 0x070 /* Overlay 2 Control register 1 */ +#define OVL2C2 0x080 /* Overlay 2 Control register 2 */ +#define CCR 0x090 /* Cursor Control register */ + +#define CMDCR 0x100 /* Command Control register */ +#define PRSR 0x104 /* Panel Read Status register */ + +#define PXA_LCDDMA_CHANS 7 +#define DMA_FDADR 0x00 /* Frame Descriptor Address register */ +#define DMA_FSADR 0x04 /* Frame Source Address register */ +#define DMA_FIDR 0x08 /* Frame ID register */ +#define DMA_LDCMD 0x0c /* Command register */ /* LCD Buffer Strength Control register */ -#define BSCNTR 0x04000054 +#define BSCNTR 0x04000054 /* Bitfield masks */ -#define LCCR0_ENB (1 << 0) -#define LCCR0_CMS (1 << 1) -#define LCCR0_SDS (1 << 2) -#define LCCR0_LDM (1 << 3) -#define LCCR0_SOFM0 (1 << 4) -#define LCCR0_IUM (1 << 5) -#define LCCR0_EOFM0 (1 << 6) -#define LCCR0_PAS (1 << 7) -#define LCCR0_DPD (1 << 9) -#define LCCR0_DIS (1 << 10) -#define LCCR0_QDM (1 << 11) -#define LCCR0_PDD (0xff << 12) -#define LCCR0_BSM0 (1 << 20) -#define LCCR0_OUM (1 << 21) -#define LCCR0_LCDT (1 << 22) -#define LCCR0_RDSTM (1 << 23) -#define LCCR0_CMDIM (1 << 24) -#define LCCR0_OUC (1 << 25) -#define LCCR0_LDDALT (1 << 26) -#define LCCR1_PPL(x) ((x) & 0x3ff) -#define LCCR2_LPP(x) ((x) & 0x3ff) -#define LCCR3_API (15 << 16) -#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8)) -#define LCCR3_PDFOR(x) (((x) >> 30) & 3) -#define LCCR4_K1(x) (((x) >> 0) & 7) -#define LCCR4_K2(x) (((x) >> 3) & 7) -#define LCCR4_K3(x) (((x) >> 6) & 7) -#define LCCR4_PALFOR(x) (((x) >> 15) & 3) -#define LCCR5_SOFM(ch) (1 << (ch - 1)) -#define LCCR5_EOFM(ch) (1 << (ch + 7)) -#define LCCR5_BSM(ch) (1 << (ch + 15)) -#define LCCR5_IUM(ch) (1 << (ch + 23)) -#define OVLC1_EN (1 << 31) -#define CCR_CEN (1 << 31) -#define FBR_BRA (1 << 0) -#define FBR_BINT (1 << 1) -#define FBR_SRCADDR (0xfffffff << 4) -#define LCSR0_LDD (1 << 0) -#define LCSR0_SOF0 (1 << 1) -#define LCSR0_BER (1 << 2) -#define LCSR0_ABC (1 << 3) -#define LCSR0_IU0 (1 << 4) -#define LCSR0_IU1 (1 << 5) -#define LCSR0_OU (1 << 6) -#define LCSR0_QD (1 << 7) -#define LCSR0_EOF0 (1 << 8) -#define LCSR0_BS0 (1 << 9) -#define LCSR0_SINT (1 << 10) -#define LCSR0_RDST (1 << 11) -#define LCSR0_CMDINT (1 << 12) -#define LCSR0_BERCH(x) (((x) & 7) << 28) -#define LCSR1_SOF(ch) (1 << (ch - 1)) -#define LCSR1_EOF(ch) (1 << (ch + 7)) -#define LCSR1_BS(ch) (1 << (ch + 15)) -#define LCSR1_IU(ch) (1 << (ch + 23)) -#define LDCMD_LENGTH(x) ((x) & 0x001ffffc) -#define LDCMD_EOFINT (1 << 21) -#define LDCMD_SOFINT (1 << 22) -#define LDCMD_PAL (1 << 26) +#define LCCR0_ENB (1 << 0) +#define LCCR0_CMS (1 << 1) +#define LCCR0_SDS (1 << 2) +#define LCCR0_LDM (1 << 3) +#define LCCR0_SOFM0 (1 << 4) +#define LCCR0_IUM (1 << 5) +#define LCCR0_EOFM0 (1 << 6) +#define LCCR0_PAS (1 << 7) +#define LCCR0_DPD (1 << 9) +#define LCCR0_DIS (1 << 10) +#define LCCR0_QDM (1 << 11) +#define LCCR0_PDD (0xff << 12) +#define LCCR0_BSM0 (1 << 20) +#define LCCR0_OUM (1 << 21) +#define LCCR0_LCDT (1 << 22) +#define LCCR0_RDSTM (1 << 23) +#define LCCR0_CMDIM (1 << 24) +#define LCCR0_OUC (1 << 25) +#define LCCR0_LDDALT (1 << 26) +#define LCCR1_PPL(x) ((x) & 0x3ff) +#define LCCR2_LPP(x) ((x) & 0x3ff) +#define LCCR3_API (15 << 16) +#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8)) +#define LCCR3_PDFOR(x) (((x) >> 30) & 3) +#define LCCR4_K1(x) (((x) >> 0) & 7) +#define LCCR4_K2(x) (((x) >> 3) & 7) +#define LCCR4_K3(x) (((x) >> 6) & 7) +#define LCCR4_PALFOR(x) (((x) >> 15) & 3) +#define LCCR5_SOFM(ch) (1 << (ch - 1)) +#define LCCR5_EOFM(ch) (1 << (ch + 7)) +#define LCCR5_BSM(ch) (1 << (ch + 15)) +#define LCCR5_IUM(ch) (1 << (ch + 23)) +#define OVLC1_EN (1 << 31) +#define CCR_CEN (1 << 31) +#define FBR_BRA (1 << 0) +#define FBR_BINT (1 << 1) +#define FBR_SRCADDR (0xfffffff << 4) +#define LCSR0_LDD (1 << 0) +#define LCSR0_SOF0 (1 << 1) +#define LCSR0_BER (1 << 2) +#define LCSR0_ABC (1 << 3) +#define LCSR0_IU0 (1 << 4) +#define LCSR0_IU1 (1 << 5) +#define LCSR0_OU (1 << 6) +#define LCSR0_QD (1 << 7) +#define LCSR0_EOF0 (1 << 8) +#define LCSR0_BS0 (1 << 9) +#define LCSR0_SINT (1 << 10) +#define LCSR0_RDST (1 << 11) +#define LCSR0_CMDINT (1 << 12) +#define LCSR0_BERCH(x) (((x) & 7) << 28) +#define LCSR1_SOF(ch) (1 << (ch - 1)) +#define LCSR1_EOF(ch) (1 << (ch + 7)) +#define LCSR1_BS(ch) (1 << (ch + 15)) +#define LCSR1_IU(ch) (1 << (ch + 23)) +#define LDCMD_LENGTH(x) ((x) & 0x001ffffc) +#define LDCMD_EOFINT (1 << 21) +#define LDCMD_SOFINT (1 << 22) +#define LDCMD_PAL (1 << 26) /* Size of a pixel in the QEMU UI output surface, in bytes */ #define DEST_PIXEL_WIDTH 4 @@ -199,7 +199,7 @@ typedef struct QEMU_PACKED { SKIP_PIXEL(to); \ } while (0) -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define SWAP_WORDS 1 #endif @@ -788,7 +788,7 @@ static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset, case TCR: return s->tcr; - case 0x200 ... 0x1000: /* DMA per-channel registers */ + case 0x200 ... 0x1000: /* DMA per-channel registers */ ch = (offset - 0x200) >> 4; if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) goto fail; @@ -938,7 +938,7 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, s->tcr = value & 0x7fff; break; - case 0x200 ... 0x1000: /* DMA per-channel registers */ + case 0x200 ... 0x1000: /* DMA per-channel registers */ ch = (offset - 0x200) >> 4; if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) goto fail; diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c index 68bfa4756802..35c38f62525d 100644 --- a/hw/display/qxl-logger.c +++ b/hw/display/qxl-logger.c @@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) QXLImage *image; QXLImageDescriptor *desc; - image = qxl_phys2virt(qxl, addr, group_id); + image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage)); if (!image) { return 1; } @@ -214,7 +214,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) cmd->u.set.position.y, cmd->u.set.visible ? "yes" : "no", cmd->u.set.shape); - cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id, + sizeof(QXLCursor)); if (!cursor) { return 1; } @@ -236,6 +237,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) { bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; void *data; + size_t datasz; int ret; if (!qxl->cmdlog) { @@ -247,7 +249,20 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) qxl_name(qxl_type, ext->cmd.type), compat ? "(compat)" : ""); - data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + switch (ext->cmd.type) { + case QXL_CMD_DRAW: + datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable); + break; + case QXL_CMD_SURFACE: + datasz = sizeof(QXLSurfaceCmd); + break; + case QXL_CMD_CURSOR: + datasz = sizeof(QXLCursorCmd); + break; + default: + goto out; + } + data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz); if (!data) { return 1; } @@ -269,6 +284,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) qxl_log_cmd_cursor(qxl, data, ext->group_id); break; } +out: fprintf(stderr, "\n"); return 0; } diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c index ca217004bf72..fcfd40c3ac1d 100644 --- a/hw/display/qxl-render.c +++ b/hw/display/qxl-render.c @@ -107,7 +107,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.resized = 0; qxl->guest_primary.data = qxl_phys2virt(qxl, qxl->guest_primary.surface.mem, - MEMSLOT_GROUP_GUEST); + MEMSLOT_GROUP_GUEST, + qxl->guest_primary.abs_stride + * height); if (!qxl->guest_primary.data) { goto end; } @@ -228,7 +230,8 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl, if (offset == size) { return; } - chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id); + chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, + sizeof(QXLDataChunk) + chunk->data_size); if (!chunk) { return; } @@ -295,7 +298,8 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor, /* called from spice server thread context only */ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) { - QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, + sizeof(QXLCursorCmd)); QXLCursor *cursor; QEMUCursor *c; @@ -314,7 +318,15 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) } switch (cmd->type) { case QXL_CURSOR_SET: - cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); + /* First read the QXLCursor to get QXLDataChunk::data_size ... */ + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, + sizeof(QXLCursor)); + if (!cursor) { + return 1; + } + /* Then read including the chunked data following QXLCursor. */ + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, + sizeof(QXLCursor) + cursor->chunk.data_size); if (!cursor) { return 1; } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index adbdbcaeb612..6772849dec28 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -274,7 +274,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) QXL_IO_MONITORS_CONFIG_ASYNC)); } - cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST); + cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST, + sizeof(QXLMonitorsConfig)); if (cfg != NULL && cfg->count == 1) { qxl->guest_primary.resized = 1; qxl->guest_head0_width = cfg->heads[0].width; @@ -320,7 +321,7 @@ static ram_addr_t qxl_rom_size(void) #define QXL_ROM_SZ 8192 QEMU_BUILD_BUG_ON(QXL_REQUIRED_SZ > QXL_ROM_SZ); - return QEMU_ALIGN_UP(QXL_REQUIRED_SZ, qemu_real_host_page_size); + return QEMU_ALIGN_UP(QXL_REQUIRED_SZ, qemu_real_host_page_size()); } static void init_qxl_rom(PCIQXLDevice *d) @@ -459,7 +460,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) switch (le32_to_cpu(ext->cmd.type)) { case QXL_CMD_SURFACE: { - QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, + sizeof(QXLSurfaceCmd)); if (!cmd) { return 1; @@ -494,7 +496,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) } case QXL_CMD_CURSOR: { - QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, + sizeof(QXLCursorCmd)); if (!cmd) { return 1; @@ -1381,6 +1384,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region); return 1; } + assert(guest_end - pci_start <= memory_region_size(mr)); virt_start = (intptr_t)memory_region_get_ram_ptr(mr); memslot.slot_id = slot_id; @@ -1421,11 +1425,13 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) /* can be also called from spice server thread context */ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, - uint32_t *s, uint64_t *o) + uint32_t *s, uint64_t *o, + size_t size_requested) { uint64_t phys = le64_to_cpu(pqxl); uint32_t slot = (phys >> (64 - 8)) & 0xff; uint64_t offset = phys & 0xffffffffffff; + uint64_t size_available; if (slot >= NUM_MEMSLOTS) { qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, @@ -1449,6 +1455,23 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, slot, offset, qxl->guest_slots[slot].size); return false; } + size_available = memory_region_size(qxl->guest_slots[slot].mr); + if (qxl->guest_slots[slot].offset + offset >= size_available) { + qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" > region size %"PRIu64"\n", + slot, qxl->guest_slots[slot].offset + offset, + size_available); + return false; + } + size_available -= qxl->guest_slots[slot].offset + offset; + if (size_requested > size_available) { + qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" size %zu: " + "overrun by %"PRIu64" bytes\n", + slot, offset, size_requested, + size_requested - size_available); + return false; + } *s = slot; *o = offset; @@ -1456,7 +1479,8 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, } /* can be also called from spice server thread context */ -void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id, + size_t size) { uint64_t offset; uint32_t slot; @@ -1467,7 +1491,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) offset = le64_to_cpu(pqxl) & 0xffffffffffff; return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: - if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { + if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size)) { return NULL; } ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); @@ -1933,9 +1957,9 @@ static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, uint32_t slot; bool rc; - rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); - assert(rc == true); size = (uint64_t)height * abs(stride); + rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size); + assert(rc == true); trace_qxl_surfaces_dirty(qxl->id, offset, size); qxl_set_dirty(qxl->guest_slots[slot].mr, qxl->guest_slots[slot].offset + offset, @@ -1964,7 +1988,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) } cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], - MEMSLOT_GROUP_GUEST); + MEMSLOT_GROUP_GUEST, sizeof(QXLSurfaceCmd)); assert(cmd); assert(cmd->type == QXL_SURFACE_CMD_CREATE); qxl_dirty_one_surface(qxl, cmd->u.surface_create.data, @@ -2515,6 +2539,7 @@ static const TypeInfo qxl_primary_info = { .class_init = qxl_primary_class_init, }; module_obj("qxl-vga"); +module_kconfig(QXL); static void qxl_secondary_class_init(ObjectClass *klass, void *data) { diff --git a/hw/display/qxl.h b/hw/display/qxl.h index e74de9579df3..cd82c7a6fe6c 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -1,8 +1,7 @@ #ifndef HW_QXL_H #define HW_QXL_H - -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "vga_int.h" #include "qemu/thread.h" @@ -147,7 +146,28 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL) #define QXL_DEFAULT_REVISION (QXL_REVISION_STABLE_V12 + 1) /* qxl.c */ -void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); +/** + * qxl_phys2virt: Get a pointer within a PCI VRAM memory region. + * + * @qxl: QXL device + * @phys: physical offset of buffer within the VRAM + * @group_id: memory slot group + * @size: size of the buffer + * + * Returns a host pointer to a buffer placed at offset @phys within the + * active slot @group_id of the PCI VGA RAM memory region associated with + * the @qxl device. If the slot is inactive, or the offset + size are out + * of the memory region, returns NULL. + * + * Use with care; by the time this function returns, the returned pointer is + * not protected by RCU anymore. If the caller is not within an RCU critical + * section and does not hold the iothread lock, it must have other means of + * protecting the pointer, such as a reference to the region that includes + * the incoming ram_addr_t. + * + */ +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id, + size_t size); void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) G_GNUC_PRINTF(2, 3); diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c index b591a5878901..664fd4046d82 100644 --- a/hw/display/sii9022.c +++ b/hw/display/sii9022.c @@ -76,6 +76,8 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event) break; case I2C_NACK: break; + default: + return -1; } return 0; diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 663c37e7f288..52e42585af57 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -32,7 +32,7 @@ #include "ui/console.h" #include "hw/sysbus.h" #include "migration/vmstate.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "hw/i2c/i2c.h" #include "hw/display/i2c-ddc.h" diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index aeae22da9c29..d67b0ad7b529 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -196,6 +196,8 @@ static int ssd0303_event(I2CSlave *i2c, enum i2c_event event) case I2C_NACK: /* Nothing to do. */ break; + default: + return -1; } return 0; diff --git a/hw/display/tcx.c b/hw/display/tcx.c index d4d09d0df8d5..1b27b64f6d14 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "ui/console.h" diff --git a/hw/display/trace-events b/hw/display/trace-events index 91efc88f04f5..0c0ffcbe42c1 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -24,6 +24,7 @@ vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" vmware_verify_rect_less_than_zero(const char *name, const char *param, int x) "%s: %s was < 0 (%d)" vmware_verify_rect_greater_than_bound(const char *name, const char *param, int bound, int x) "%s: %s was > %d (%d)" vmware_verify_rect_surface_bound_exceeded(const char *name, const char *component, int bound, const char *param1, int value1, const char *param2, int value2) "%s: %s > %d (%s: %d, %s: %d)" +vmware_update_rect_delayed_flush(void) "display update FIFO full - forcing flush" # virtio-gpu-base.c virtio_gpu_features(bool virgl) "virgl %d" diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 46abbc56534c..2a5437d80370 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -32,6 +32,7 @@ #include "qemu/timer.h" #include "hw/loader.h" #include "hw/qdev-properties.h" +#include "ui/console.h" #include "qom/object.h" #define TYPE_ISA_VGA "isa-vga" diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c index 75dfcedea510..cd2c46776dc8 100644 --- a/hw/display/vga-mmio.c +++ b/hw/display/vga-mmio.c @@ -27,6 +27,7 @@ #include "hw/sysbus.h" #include "hw/display/vga.h" #include "hw/qdev-properties.h" +#include "ui/console.h" #include "vga_int.h" /* diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 3e5bc259f7a5..b351b8f299d9 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -25,16 +25,18 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "vga_int.h" #include "ui/pixel_ops.h" +#include "ui/console.h" #include "qemu/module.h" #include "qemu/timer.h" #include "hw/loader.h" #include "hw/display/edid.h" #include "qom/object.h" +#include "hw/acpi/acpi_aml_interface.h" enum vga_pci_flags { PCI_VGA_FLAG_ENABLE_MMIO = 1, @@ -354,11 +356,13 @@ static void vga_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); k->vendor_id = PCI_VENDOR_ID_QEMU; k->device_id = PCI_DEVICE_ID_QEMU_VGA; dc->vmsd = &vmstate_vga_pci; set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + adevc->build_dev_aml = build_vga_aml; } static const TypeInfo vga_pci_type_info = { @@ -369,6 +373,7 @@ static const TypeInfo vga_pci_type_info = { .class_init = vga_pci_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { TYPE_ACPI_DEV_AML_IF }, { }, }, }; diff --git a/hw/display/vga.c b/hw/display/vga.c index a7a291fa2089..0cb26a791bd1 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -31,6 +31,7 @@ #include "vga_int.h" #include "vga_regs.h" #include "ui/pixel_ops.h" +#include "ui/console.h" #include "qemu/timer.h" #include "hw/xen/xen.h" #include "migration/vmstate.h" @@ -94,19 +95,19 @@ const uint8_t gr_mask[16] = { (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define PAT(x) cbswap_32(x) #else #define PAT(x) (x) #endif -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define BIG 1 #else #define BIG 0 #endif -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) #else #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) @@ -133,7 +134,7 @@ static const uint32_t mask16[16] = { #undef PAT -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define PAT(x) (x) #else #define PAT(x) cbswap_32(x) @@ -1296,7 +1297,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) if (cx > cx_max) cx_max = cx; *ch_attr_ptr = ch_attr; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN ch = ch_attr >> 8; cattr = ch_attr & 0xff; #else @@ -1477,7 +1478,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) vga_draw_line_func *vga_draw_line = NULL; bool share_surface, force_shadow = false; pixman_format_code_t format; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN bool byteswap = !s->big_endian_fb; #else bool byteswap = s->big_endian_fb; @@ -1514,9 +1515,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 { @@ -2242,7 +2244,7 @@ bool vga_common_init(VGACommonState *s, Object *obj, Error **errp) * into a device attribute set by the machine/platform to remove * all target endian dependencies from this file. */ -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN s->default_endian_fb = true; #else s->default_endian_fb = false; diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 305e700014d8..7cf0d11201ac 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -27,9 +27,9 @@ #include "exec/ioport.h" #include "exec/memory.h" -#include "ui/console.h" #include "hw/display/bochs-vbe.h" +#include "hw/acpi/acpi_aml_interface.h" #define ST01_V_RETRACE 0x08 #define ST01_DISP_ENABLE 0x01 @@ -195,4 +195,5 @@ void pci_std_vga_mmio_region_init(VGACommonState *s, MemoryRegion *subs, bool qext, bool edid); +void build_vga_aml(AcpiDevAmlIf *adev, Aml *scope); #endif diff --git a/hw/display/vga_regs.h b/hw/display/vga_regs.h index 30a98b8736e4..7fdba34b9b14 100644 --- a/hw/display/vga_regs.h +++ b/hw/display/vga_regs.h @@ -4,9 +4,9 @@ * Copyright 1999 Jeff Garzik * * Copyright history from vga16fb.c: - * Copyright 1999 Ben Pfaff and Petr Vandrovec - * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm - * Based on VESA framebuffer (c) 1998 Gerd Knorr + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm + * Based on VESA framebuffer (c) 1998 Gerd Knorr * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this diff --git a/hw/display/vhost-user-gpu-pci.c b/hw/display/vhost-user-gpu-pci.c index daefcf710159..d119bcae45d4 100644 --- a/hw/display/vhost-user-gpu-pci.c +++ b/hw/display/vhost-user-gpu-pci.c @@ -44,6 +44,7 @@ static const VirtioPCIDeviceTypeInfo vhost_user_gpu_pci_info = { .instance_init = vhost_user_gpu_pci_initfn, }; module_obj(TYPE_VHOST_USER_GPU_PCI); +module_kconfig(VHOST_USER_GPU); static void vhost_user_gpu_pci_register_types(void) { diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 09818231bd24..4380a5e67264 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; } @@ -485,6 +486,15 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) { VhostUserGPU *g = VHOST_USER_GPU(vdev); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return false; + } return vhost_virtqueue_pending(&g->vhost->dev, idx); } @@ -493,6 +503,15 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) { VhostUserGPU *g = VHOST_USER_GPU(vdev); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return; + } vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); } @@ -565,6 +584,12 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp) g->vhost_gpu_fd = -1; } +static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev) +{ + VhostUserGPU *g = VHOST_USER_GPU(vdev); + return &g->vhost->dev; +} + static Property vhost_user_gpu_properties[] = { VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf), DEFINE_PROP_END_OF_LIST(), @@ -586,6 +611,7 @@ vhost_user_gpu_class_init(ObjectClass *klass, void *data) vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending; vdc->get_config = vhost_user_gpu_get_config; vdc->set_config = vhost_user_gpu_set_config; + vdc->get_vhost = vhost_user_gpu_get_vhost; device_class_set_props(dc, vhost_user_gpu_properties); } @@ -599,6 +625,7 @@ static const TypeInfo vhost_user_gpu_info = { .class_init = vhost_user_gpu_class_init, }; module_obj(TYPE_VHOST_USER_GPU); +module_kconfig(VHOST_USER_GPU); static void vhost_user_gpu_register_types(void) { diff --git a/hw/display/vhost-user-vga.c b/hw/display/vhost-user-vga.c index 072c9c65bc75..0c146080fd2c 100644 --- a/hw/display/vhost-user-vga.c +++ b/hw/display/vhost-user-vga.c @@ -45,6 +45,7 @@ static const VirtioPCIDeviceTypeInfo vhost_user_vga_info = { .instance_init = vhost_user_vga_inst_initfn, }; module_obj(TYPE_VHOST_USER_VGA); +module_kconfig(VHOST_USER_VGA); static void vhost_user_vga_register_types(void) { diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index fff0fb4a828a..a29f191aa82e 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -69,16 +69,17 @@ static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type) virtio_notify_config(&g->parent_obj); } -static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) { VirtIOGPUBase *g = opaque; if (idx >= g->conf.max_outputs) { - return -1; + return; } g->req_state[idx].x = info->xoff; g->req_state[idx].y = info->yoff; + g->req_state[idx].refresh_rate = info->refresh_rate; g->req_state[idx].width = info->width; g->req_state[idx].height = info->height; g->req_state[idx].width_mm = info->width_mm; @@ -92,7 +93,7 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) /* send event to guest */ virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); - return 0; + return; } static void @@ -173,7 +174,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev, } g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); - virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, + virtio_init(VIRTIO_DEVICE(g), VIRTIO_ID_GPU, sizeof(struct virtio_gpu_config)); if (virtio_gpu_virgl_enabled(g->conf)) { @@ -260,6 +261,7 @@ static const TypeInfo virtio_gpu_base_info = { .abstract = true }; module_obj(TYPE_VIRTIO_GPU_BASE); +module_kconfig(VIRTIO_GPU); static void virtio_register_types(void) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 6cc4313b1af2..e06be60dfbfc 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -108,7 +108,7 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) { VirtIOGPU *g = VIRTIO_GPU(qdev); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN error_setg(errp, "virgl is not supported on bigendian platforms"); return; #endif @@ -160,6 +160,7 @@ static const TypeInfo virtio_gpu_gl_info = { .class_init = virtio_gpu_gl_class_init, }; module_obj(TYPE_VIRTIO_GPU_GL); +module_kconfig(VIRTIO_GPU); static void virtio_register_types(void) { diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c index 99b14a07185e..a2819e1ca93f 100644 --- a/hw/display/virtio-gpu-pci-gl.c +++ b/hw/display/virtio-gpu-pci-gl.c @@ -47,6 +47,7 @@ static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = { .instance_init = virtio_gpu_gl_initfn, }; module_obj(TYPE_VIRTIO_GPU_GL_PCI); +module_kconfig(VIRTIO_PCI); static void virtio_gpu_gl_pci_register_types(void) { diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index e36eee0c409b..93f214ff5812 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -65,6 +65,7 @@ static const TypeInfo virtio_gpu_pci_base_info = { .abstract = true }; module_obj(TYPE_VIRTIO_GPU_PCI_BASE); +module_kconfig(VIRTIO_PCI); #define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" typedef struct VirtIOGPUPCI VirtIOGPUPCI; diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 1597921c51fc..8bdf4bac6e4b 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu-common.h" #include "qemu/iov.h" #include "ui/console.h" #include "hw/virtio/virtio-gpu.h" diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 529b5246b2b5..5e15c79b94a5 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -217,6 +217,7 @@ virtio_gpu_generate_edid(VirtIOGPU *g, int scanout, .height_mm = b->req_state[scanout].height_mm, .prefx = b->req_state[scanout].width, .prefy = b->req_state[scanout].height, + .refresh_rate = b->req_state[scanout].refresh_rate, }; edid->size = cpu_to_le32(sizeof(edid->edid)); @@ -514,6 +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 + 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); @@ -1452,6 +1457,7 @@ static const TypeInfo virtio_gpu_info = { .class_init = virtio_gpu_class_init, }; module_obj(TYPE_VIRTIO_GPU); +module_kconfig(VIRTIO_GPU); static void virtio_register_types(void) { diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c index f22549097c5e..984faa6b39a8 100644 --- a/hw/display/virtio-vga-gl.c +++ b/hw/display/virtio-vga-gl.c @@ -37,6 +37,7 @@ static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = { .instance_init = virtio_vga_gl_inst_initfn, }; module_obj(TYPE_VIRTIO_VGA_GL); +module_kconfig(VIRTIO_VGA); static void virtio_vga_register_types(void) { diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 7b55c8d0e723..e6fb0aa876cb 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -47,15 +47,14 @@ static void virtio_vga_base_text_update(void *opaque, console_ch_t *chardata) } } -static int virtio_vga_base_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +static void virtio_vga_base_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) { VirtIOVGABase *vvga = opaque; VirtIOGPUBase *g = vvga->vgpu; if (g->hw_ops->ui_info) { - return g->hw_ops->ui_info(g, idx, info); + g->hw_ops->ui_info(g, idx, info); } - return -1; } static void virtio_vga_base_gl_block(void *opaque, bool block) @@ -166,13 +165,15 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_vga_base_reset(DeviceState *dev) +static void virtio_vga_base_reset_hold(Object *obj) { - VirtIOVGABaseClass *klass = VIRTIO_VGA_BASE_GET_CLASS(dev); - VirtIOVGABase *vvga = VIRTIO_VGA_BASE(dev); + VirtIOVGABaseClass *klass = VIRTIO_VGA_BASE_GET_CLASS(obj); + VirtIOVGABase *vvga = VIRTIO_VGA_BASE(obj); /* reset virtio-gpu */ - klass->parent_reset(dev); + if (klass->parent_phases.hold) { + klass->parent_phases.hold(obj); + } /* reset vga */ vga_common_reset(&vvga->vga); @@ -204,13 +205,14 @@ static void virtio_vga_base_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); VirtIOVGABaseClass *v = VIRTIO_VGA_BASE_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); device_class_set_props(dc, virtio_vga_base_properties); dc->vmsd = &vmstate_virtio_vga_base; dc->hotpluggable = false; - device_class_set_parent_reset(dc, virtio_vga_base_reset, - &v->parent_reset); + resettable_class_set_parent_phases(rc, NULL, virtio_vga_base_reset_hold, + NULL, &v->parent_phases); k->realize = virtio_vga_base_realize; pcidev_k->romfile = "vgabios-virtio.bin"; @@ -231,6 +233,7 @@ static const TypeInfo virtio_vga_base_info = { .abstract = true, }; module_obj(TYPE_VIRTIO_VGA_BASE); +module_kconfig(VIRTIO_VGA); #define TYPE_VIRTIO_VGA "virtio-vga" diff --git a/hw/display/virtio-vga.h b/hw/display/virtio-vga.h index 977ad5edc293..0bd9db1ceea6 100644 --- a/hw/display/virtio-vga.h +++ b/hw/display/virtio-vga.h @@ -23,7 +23,7 @@ struct VirtIOVGABase { struct VirtIOVGABaseClass { VirtioPCIClass parent_class; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; #endif /* VIRTIO_VGA_H */ diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 45d06cbe2544..59ae7f74b8d8 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -29,10 +29,11 @@ #include "qemu/log.h" #include "hw/loader.h" #include "trace.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qom/object.h" +#include "ui/console.h" #undef VERBOSE #define HW_RECT_ACCEL @@ -80,7 +81,7 @@ struct vmsvga_state_s { struct vmsvga_rect_s { int x, y, w, h; } redraw_fifo[REDRAW_FIFO_LEN]; - int redraw_fifo_first, redraw_fifo_last; + int redraw_fifo_last; }; #define TYPE_VMWARE_SVGA "vmware-svga" @@ -380,33 +381,39 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, dpy_gfx_update(s->vga.con, x, y, w, h); } -static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, - int x, int y, int w, int h) -{ - struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last++]; - - s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1; - rect->x = x; - rect->y = y; - rect->w = w; - rect->h = h; -} - static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s) { struct vmsvga_rect_s *rect; if (s->invalidated) { - s->redraw_fifo_first = s->redraw_fifo_last; + s->redraw_fifo_last = 0; return; } /* Overlapping region updates can be optimised out here - if someone * knows a smart algorithm to do that, please share. */ - while (s->redraw_fifo_first != s->redraw_fifo_last) { - rect = &s->redraw_fifo[s->redraw_fifo_first++]; - s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1; + for (int i = 0; i < s->redraw_fifo_last; i++) { + rect = &s->redraw_fifo[i]; vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h); } + + s->redraw_fifo_last = 0; +} + +static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, + int x, int y, int w, int h) +{ + + if (s->redraw_fifo_last >= REDRAW_FIFO_LEN) { + trace_vmware_update_rect_delayed_flush(); + vmsvga_update_rect_flush(s); + } + + struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last++]; + + rect->x = x; + rect->y = y; + rect->w = w; + rect->h = h; } #ifdef HW_RECT_ACCEL @@ -1161,7 +1168,6 @@ static void vmsvga_reset(DeviceState *dev) s->config = 0; s->svgaid = SVGA_ID; s->cursor.on = 0; - s->redraw_fifo_first = 0; s->redraw_fifo_last = 0; s->syncing = 0; diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index cea10fe3c780..260eb38a76e2 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -76,7 +76,7 @@ struct XenFB { int do_resize; struct { - int x,y,w,h; + int x,y,w,h; } up_rects[UP_QUEUE]; int up_count; int up_fullscreen; @@ -116,32 +116,32 @@ static void common_unbind(struct common *c) xen_pv_unbind_evtchn(&c->xendev); if (c->page) { xenforeignmemory_unmap(xen_fmem, c->page, 1); - c->page = NULL; + c->page = NULL; } } /* -------------------------------------------------------------------- */ /* Send an event to the keyboard frontend driver */ static int xenfb_kbd_event(struct XenInput *xenfb, - union xenkbd_in_event *event) + union xenkbd_in_event *event) { struct xenkbd_page *page = xenfb->c.page; uint32_t prod; if (xenfb->c.xendev.be_state != XenbusStateConnected) - return 0; + return 0; if (!page) return 0; prod = page->in_prod; if (prod - page->in_cons == XENKBD_IN_RING_LEN) { - errno = EAGAIN; - return -1; + errno = EAGAIN; + return -1; } - xen_mb(); /* ensure ring space available */ + xen_mb(); /* ensure ring space available */ XENKBD_IN_RING_REF(page, prod) = *event; - xen_wmb(); /* ensure ring contents visible */ + xen_wmb(); /* ensure ring contents visible */ page->in_prod = prod + 1; return xen_pv_send_notify(&xenfb->c.xendev); } @@ -161,7 +161,7 @@ static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode) /* Send a relative mouse movement event */ static int xenfb_send_motion(struct XenInput *xenfb, - int rel_x, int rel_y, int rel_z) + int rel_x, int rel_y, int rel_z) { union xenkbd_in_event event; @@ -176,7 +176,7 @@ static int xenfb_send_motion(struct XenInput *xenfb, /* Send an absolute mouse movement event */ static int xenfb_send_position(struct XenInput *xenfb, - int abs_x, int abs_y, int z) + int abs_x, int abs_y, int z) { union xenkbd_in_event event; @@ -354,7 +354,7 @@ static int input_initialise(struct XenLegacyDevice *xendev) rc = common_bind(&in->c); if (rc != 0) - return rc; + return rc; return 0; } @@ -415,7 +415,7 @@ static void input_event(struct XenLegacyDevice *xendev) /* We don't understand any keyboard events, so just ignore them. */ if (page->out_prod == page->out_cons) - return; + return; page->out_cons = page->out_prod; xen_pv_send_notify(&xenfb->c.xendev); } @@ -429,7 +429,7 @@ static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src) int i; for (i = 0; i < count; i++) - dst[i] = (mode == 32) ? src32[i] : src64[i]; + dst[i] = (mode == 32) ? src32[i] : src64[i]; } static int xenfb_map_fb(struct XenFB *xenfb) @@ -447,43 +447,43 @@ static int xenfb_map_fb(struct XenFB *xenfb) mode = sizeof(unsigned long) * 8; if (!protocol) { - /* - * Undefined protocol, some guesswork needed. - * - * Old frontends which don't set the protocol use - * one page directory only, thus pd[1] must be zero. - * pd[1] of the 32bit struct layout and the lower - * 32 bits of pd[0] of the 64bit struct layout have - * the same location, so we can check that ... - */ - uint32_t *ptr32 = NULL; - uint32_t *ptr64 = NULL; + /* + * Undefined protocol, some guesswork needed. + * + * Old frontends which don't set the protocol use + * one page directory only, thus pd[1] must be zero. + * pd[1] of the 32bit struct layout and the lower + * 32 bits of pd[0] of the 64bit struct layout have + * the same location, so we can check that ... + */ + uint32_t *ptr32 = NULL; + uint32_t *ptr64 = NULL; #if defined(__i386__) - ptr32 = (void*)page->pd; - ptr64 = ((void*)page->pd) + 4; + ptr32 = (void*)page->pd; + ptr64 = ((void*)page->pd) + 4; #elif defined(__x86_64__) - ptr32 = ((void*)page->pd) - 4; - ptr64 = (void*)page->pd; + ptr32 = ((void*)page->pd) - 4; + ptr64 = (void*)page->pd; #endif - if (ptr32) { - if (ptr32[1] == 0) { - mode = 32; - pd = ptr32; - } else { - mode = 64; - pd = ptr64; - } - } + if (ptr32) { + if (ptr32[1] == 0) { + mode = 32; + pd = ptr32; + } else { + mode = 64; + pd = ptr64; + } + } #if defined(__x86_64__) } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { - /* 64bit dom0, 32bit domU */ - mode = 32; - pd = ((void*)page->pd) - 4; + /* 64bit dom0, 32bit domU */ + mode = 32; + pd = ((void*)page->pd) - 4; #elif defined(__i386__) } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { - /* 32bit dom0, 64bit domU */ - mode = 64; - pd = ((void*)page->pd) + 4; + /* 32bit dom0, 64bit domU */ + mode = 64; + pd = ((void*)page->pd) + 4; #endif } @@ -503,14 +503,14 @@ static int xenfb_map_fb(struct XenFB *xenfb) map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom, PROT_READ, n_fbdirs, pgmfns, NULL); if (map == NULL) - goto out; + goto out; xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map); xenforeignmemory_unmap(xen_fmem, map, n_fbdirs); xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom, PROT_READ, xenfb->fbpages, fbmfns, NULL); if (xenfb->pixels == NULL) - goto out; + goto out; ret = 0; /* all is fine */ @@ -589,35 +589,35 @@ static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim, /* A convenient function for munging pixels between different depths */ #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \ - for (line = y ; line < (y+h) ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels \ - + xenfb->offset \ - + (line * xenfb->row_stride) \ - + (x * xenfb->depth / 8)); \ - DST_T *dst = (DST_T *)(data \ - + (line * linesize) \ - + (x * bpp / 8)); \ - int col; \ - const int RSS = 32 - (RSB + GSB + BSB); \ - const int GSS = 32 - (GSB + BSB); \ - const int BSS = 32 - (BSB); \ - const uint32_t RSM = (~0U) << (32 - RSB); \ - const uint32_t GSM = (~0U) << (32 - GSB); \ - const uint32_t BSM = (~0U) << (32 - BSB); \ - const int RDS = 32 - (RDB + GDB + BDB); \ - const int GDS = 32 - (GDB + BDB); \ - const int BDS = 32 - (BDB); \ - const uint32_t RDM = (~0U) << (32 - RDB); \ - const uint32_t GDM = (~0U) << (32 - GDB); \ - const uint32_t BDM = (~0U) << (32 - BDB); \ - for (col = x ; col < (x+w) ; col++) { \ - uint32_t spix = *src; \ - *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \ - (((spix << GSS) & GSM & GDM) >> GDS) | \ - (((spix << BSS) & BSM & BDM) >> BDS); \ - src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \ - dst = (DST_T *) ((unsigned long) dst + bpp / 8); \ - } \ + for (line = y ; line < (y+h) ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->pixels \ + + xenfb->offset \ + + (line * xenfb->row_stride) \ + + (x * xenfb->depth / 8)); \ + DST_T *dst = (DST_T *)(data \ + + (line * linesize) \ + + (x * bpp / 8)); \ + int col; \ + const int RSS = 32 - (RSB + GSB + BSB); \ + const int GSS = 32 - (GSB + BSB); \ + const int BSS = 32 - (BSB); \ + const uint32_t RSM = (~0U) << (32 - RSB); \ + const uint32_t GSM = (~0U) << (32 - GSB); \ + const uint32_t BSM = (~0U) << (32 - BSB); \ + const int RDS = 32 - (RDB + GDB + BDB); \ + const int GDS = 32 - (GDB + BDB); \ + const int BDS = 32 - (BDB); \ + const uint32_t RDM = (~0U) << (32 - RDB); \ + const uint32_t GDM = (~0U) << (32 - GDB); \ + const uint32_t BDM = (~0U) << (32 - BDB); \ + for (col = x ; col < (x+w) ; col++) { \ + uint32_t spix = *src; \ + *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \ + (((spix << GSS) & GSM & GDM) >> GDS) | \ + (((spix << BSS) & BSM & BDM) >> BDS); \ + src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \ + dst = (DST_T *) ((unsigned long) dst + bpp / 8); \ + } \ } @@ -657,7 +657,7 @@ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) break; default: oops = 1; - } + } } if (oops) /* should not happen */ xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n", @@ -777,16 +777,24 @@ static void xenfb_update(void *opaque) xenfb->up_fullscreen = 0; } -static void xenfb_update_interval(void *opaque, uint64_t interval) +static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) { struct XenFB *xenfb = opaque; + uint32_t refresh_rate; if (xenfb->feature_update) { #ifdef XENFB_TYPE_REFRESH_PERIOD if (xenfb_queue_full(xenfb)) { return; } - xenfb_send_refresh_period(xenfb, interval); + + refresh_rate = info->refresh_rate; + if (!refresh_rate) { + refresh_rate = 75; + } + + /* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */ + xenfb_send_refresh_period(xenfb, 1000 * 1000 / refresh_rate); #endif } } @@ -808,60 +816,60 @@ static void xenfb_handle_events(struct XenFB *xenfb) if (prod - out_cons > XENFB_OUT_RING_LEN) { return; } - xen_rmb(); /* ensure we see ring contents up to prod */ + xen_rmb(); /* ensure we see ring contents up to prod */ for (cons = out_cons; cons != prod; cons++) { - union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); + union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); uint8_t type = event->type; - int x, y, w, h; - - switch (type) { - case XENFB_TYPE_UPDATE: - if (xenfb->up_count == UP_QUEUE) - xenfb->up_fullscreen = 1; - if (xenfb->up_fullscreen) - break; - x = MAX(event->update.x, 0); - y = MAX(event->update.y, 0); - w = MIN(event->update.width, xenfb->width - x); - h = MIN(event->update.height, xenfb->height - y); - if (w < 0 || h < 0) { + int x, y, w, h; + + switch (type) { + case XENFB_TYPE_UPDATE: + if (xenfb->up_count == UP_QUEUE) + xenfb->up_fullscreen = 1; + if (xenfb->up_fullscreen) + break; + x = MAX(event->update.x, 0); + y = MAX(event->update.y, 0); + w = MIN(event->update.width, xenfb->width - x); + h = MIN(event->update.height, xenfb->height - y); + if (w < 0 || h < 0) { xen_pv_printf(&xenfb->c.xendev, 1, "bogus update ignored\n"); - break; - } - if (x != event->update.x || + break; + } + if (x != event->update.x || y != event->update.y || - w != event->update.width || - h != event->update.height) { + w != event->update.width || + h != event->update.height) { xen_pv_printf(&xenfb->c.xendev, 1, "bogus update clipped\n"); - } - if (w == xenfb->width && h > xenfb->height / 2) { - /* scroll detector: updated more than 50% of the lines, - * don't bother keeping track of the rectangles then */ - xenfb->up_fullscreen = 1; - } else { - xenfb->up_rects[xenfb->up_count].x = x; - xenfb->up_rects[xenfb->up_count].y = y; - xenfb->up_rects[xenfb->up_count].w = w; - xenfb->up_rects[xenfb->up_count].h = h; - xenfb->up_count++; - } - break; + } + if (w == xenfb->width && h > xenfb->height / 2) { + /* scroll detector: updated more than 50% of the lines, + * don't bother keeping track of the rectangles then */ + xenfb->up_fullscreen = 1; + } else { + xenfb->up_rects[xenfb->up_count].x = x; + xenfb->up_rects[xenfb->up_count].y = y; + xenfb->up_rects[xenfb->up_count].w = w; + xenfb->up_rects[xenfb->up_count].h = h; + xenfb->up_count++; + } + break; #ifdef XENFB_TYPE_RESIZE - case XENFB_TYPE_RESIZE: - if (xenfb_configure_fb(xenfb, xenfb->fb_len, - event->resize.width, - event->resize.height, - event->resize.depth, - xenfb->fb_len, - event->resize.offset, - event->resize.stride) < 0) - break; - xenfb_invalidate(xenfb); - break; + case XENFB_TYPE_RESIZE: + if (xenfb_configure_fb(xenfb, xenfb->fb_len, + event->resize.width, + event->resize.height, + event->resize.depth, + xenfb->fb_len, + event->resize.offset, + event->resize.stride) < 0) + break; + xenfb_invalidate(xenfb); + break; #endif - } + } } - xen_mb(); /* ensure we're done with ring contents */ + xen_mb(); /* ensure we're done with ring contents */ page->out_cons = cons; } @@ -881,32 +889,32 @@ static int fb_initialise(struct XenLegacyDevice *xendev) int rc; if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1) - videoram = 0; + videoram = 0; rc = common_bind(&fb->c); if (rc != 0) - return rc; + return rc; fb_page = fb->c.page; rc = xenfb_configure_fb(fb, videoram * MiB, - fb_page->width, fb_page->height, fb_page->depth, - fb_page->mem_length, 0, fb_page->line_length); + fb_page->width, fb_page->height, fb_page->depth, + fb_page->mem_length, 0, fb_page->line_length); if (rc != 0) - return rc; + return rc; rc = xenfb_map_fb(fb); if (rc != 0) - return rc; + return rc; fb->con = graphic_console_init(NULL, 0, &xenfb_ops, fb); if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1) - fb->feature_update = 0; + fb->feature_update = 0; if (fb->feature_update) - xenstore_write_be_int(xendev, "request-update", 1); + xenstore_write_be_int(xendev, "request-update", 1); xen_pv_printf(xendev, 1, "feature-update=%d, videoram=%d\n", - fb->feature_update, videoram); + fb->feature_update, videoram); return 0; } @@ -983,5 +991,5 @@ struct XenDevOps xen_framebuffer_ops = { static const GraphicHwOps xenfb_ops = { .invalidate = xenfb_invalidate, .gfx_update = xenfb_update, - .update_interval = xenfb_update_interval, + .ui_info = xenfb_ui_info, }; diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 9bb781e31254..b0828d65aa86 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -114,6 +114,7 @@ #define DP_TX_N_AUD (0x032C >> 2) #define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2) #define DP_INT_STATUS (0x03A0 >> 2) +#define DP_INT_VBLNK_START (1 << 13) #define DP_INT_MASK (0x03A4 >> 2) #define DP_INT_EN (0x03A8 >> 2) #define DP_INT_DS (0x03AC >> 2) @@ -260,7 +261,7 @@ typedef enum DPVideoFmt DPVideoFmt; static const VMStateDescription vmstate_dp = { .name = TYPE_XLNX_DP, - .version_id = 1, + .version_id = 2, .fields = (VMStateField[]){ VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState, DP_CORE_REG_ARRAY_SIZE), @@ -270,10 +271,15 @@ static const VMStateDescription vmstate_dp = { DP_VBLEND_REG_ARRAY_SIZE), VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState, DP_AUDIO_REG_ARRAY_SIZE), + VMSTATE_PTIMER(vblank, XlnxDPState), VMSTATE_END_OF_LIST() } }; +#define DP_VBLANK_PTIMER_POLICY (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \ + PTIMER_POLICY_CONTINUOUS_TRIGGER | \ + PTIMER_POLICY_NO_IMMEDIATE_TRIGGER) + static void xlnx_dp_update_irq(XlnxDPState *s); static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size) @@ -526,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; @@ -773,6 +779,13 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value, break; case DP_TRANSMITTER_ENABLE: s->core_registers[offset] = value & 0x01; + ptimer_transaction_begin(s->vblank); + if (value & 0x1) { + ptimer_run(s->vblank, 0); + } else { + ptimer_stop(s->vblank); + } + ptimer_transaction_commit(s->vblank); break; case DP_FORCE_SCRAMBLER_RESET: /* @@ -876,7 +889,7 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value, xlnx_dp_update_irq(s); break; case DP_INT_DS: - s->core_registers[DP_INT_MASK] |= ~value; + s->core_registers[DP_INT_MASK] |= value; xlnx_dp_update_irq(s); break; default: @@ -1177,9 +1190,6 @@ static void xlnx_dp_update_display(void *opaque) return; } - s->core_registers[DP_INT_STATUS] |= (1 << 13); - xlnx_dp_update_irq(s); - xlnx_dpdma_trigger_vsync_irq(s->dpdma); /* @@ -1219,19 +1229,22 @@ static void xlnx_dp_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); XlnxDPState *s = XLNX_DP(obj); - memory_region_init(&s->container, obj, TYPE_XLNX_DP, 0xC050); + memory_region_init(&s->container, obj, TYPE_XLNX_DP, DP_CONTAINER_SIZE); memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP - ".core", 0x3AF); - memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem); + ".core", sizeof(s->core_registers)); + memory_region_add_subregion(&s->container, DP_CORE_REG_OFFSET, + &s->core_iomem); memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP - ".v_blend", 0x1DF); - memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem); + ".v_blend", sizeof(s->vblend_registers)); + memory_region_add_subregion(&s->container, DP_VBLEND_REG_OFFSET, + &s->vblend_iomem); memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP - ".av_buffer_manager", 0x238); - memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem); + ".av_buffer_manager", sizeof(s->avbufm_registers)); + memory_region_add_subregion(&s->container, DP_AVBUF_REG_OFFSET, + &s->avbufm_iomem); memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP ".audio", sizeof(s->audio_registers)); @@ -1272,6 +1285,14 @@ static void xlnx_dp_finalize(Object *obj) fifo8_destroy(&s->rx_fifo); } +static void vblank_hit(void *opaque) +{ + XlnxDPState *s = XLNX_DP(opaque); + + s->core_registers[DP_INT_STATUS] |= DP_INT_VBLNK_START; + xlnx_dp_update_irq(s); +} + static void xlnx_dp_realize(DeviceState *dev, Error **errp) { XlnxDPState *s = XLNX_DP(dev); @@ -1306,6 +1327,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) &as); AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255); xlnx_dp_audio_activate(s); + s->vblank = ptimer_init(vblank_hit, s, DP_VBLANK_PTIMER_POLICY); + ptimer_transaction_begin(s->vblank); + ptimer_set_freq(s->vblank, 30); + ptimer_transaction_commit(s->vblank); } static void xlnx_dp_reset(DeviceState *dev) diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index 6677237d42a4..c6e35ba4b807 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -1454,10 +1454,9 @@ static int omap_dma_sys_read(struct omap_dma_s *s, int offset, return 0; } -static uint64_t omap_dma_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_dma_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; + struct omap_dma_s *s = opaque; int reg, ch; uint16_t ret; @@ -1505,7 +1504,7 @@ static uint64_t omap_dma_read(void *opaque, hwaddr addr, static void omap_dma_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; + struct omap_dma_s *s = opaque; int reg, ch; if (size != 2) { @@ -1557,7 +1556,7 @@ static const MemoryRegionOps omap_dma_ops = { static void omap_dma_request(void *opaque, int drq, int req) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; + struct omap_dma_s *s = opaque; /* The request pins are level triggered in QEMU. */ if (req) { if (~s->dma->drqbmp & (1ULL << drq)) { @@ -1571,7 +1570,7 @@ static void omap_dma_request(void *opaque, int drq, int req) /* XXX: this won't be needed once soc_dma knows about clocks. */ static void omap_dma_clk_update(void *opaque, int line, int on) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; + struct omap_dma_s *s = opaque; int i; s->dma->freq = omap_clk_getrate(s->clk); @@ -1703,7 +1702,7 @@ static void omap_dma_interrupts_4_update(struct omap_dma_s *s) static uint64_t omap_dma4_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; + struct omap_dma_s *s = opaque; int irqn = 0, chnum; struct omap_dma_channel_s *ch; @@ -1859,7 +1858,7 @@ static uint64_t omap_dma4_read(void *opaque, hwaddr addr, static void omap_dma4_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; + struct omap_dma_s *s = opaque; int chnum, irqn = 0; struct omap_dma_channel_s *ch; diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 31ce01b7c57c..e5d521c32997 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -15,7 +15,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" @@ -1329,7 +1328,7 @@ static void pl330_debug_exec(PL330State *s) } if (!insn) { pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR); - return ; + return; } ch->stall = 0; insn->exec(ch, opcode, args, insn->size - 1); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index bc383f53cca3..cbb8f0f16963 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -552,7 +552,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) st->dma = s; st->nr = i; - st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); + st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(st->ptimer); ptimer_set_freq(st->ptimer, s->freqhz); ptimer_transaction_commit(st->ptimer); diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 60ada3286b43..1ce52ea5a2ba 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -666,7 +666,7 @@ static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp) sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); s->src_timer = ptimer_init(xlnx_csu_dma_src_timeout_hit, - s, PTIMER_POLICY_DEFAULT); + s, PTIMER_POLICY_LEGACY); s->attr = MEMTXATTRS_UNSPECIFIED; diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c index 2d7eae72cd23..dd66be5265df 100644 --- a/hw/dma/xlnx_dpdma.c +++ b/hw/dma/xlnx_dpdma.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/dma/xlnx_dpdma.h" diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig index f0e7405f6e64..fd938bc4fe00 100644 --- a/hw/gpio/Kconfig +++ b/hw/gpio/Kconfig @@ -1,15 +1,21 @@ -config MAX7310 - bool - depends on I2C - -config PL061 - bool - -config GPIO_KEY - bool - -config GPIO_PWR - bool - -config SIFIVE_GPIO - bool +config MAX7310 + bool + depends on I2C + +config PL061 + bool + +config GPIO_KEY + bool + +config GPIO_MPC8XXX + bool + +config GPIO_PWR + bool + +config SIFIVE_GPIO + bool + +config RT_PINT + bool diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index c63634d3d3e2..1e267dd48203 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -15,6 +15,8 @@ #include "qapi/visitor.h" #include "hw/irq.h" #include "migration/vmstate.h" +#include "trace.h" +#include "hw/registerfields.h" #define GPIOS_PER_GROUP 8 @@ -203,6 +205,28 @@ #define GPIO_1_8V_MEM_SIZE 0x1D8 #define GPIO_1_8V_REG_ARRAY_SIZE (GPIO_1_8V_MEM_SIZE >> 2) +/* + * GPIO index mode support + * It only supports write operation + */ +REG32(GPIO_INDEX_REG, 0x2AC) + FIELD(GPIO_INDEX_REG, NUMBER, 0, 8) + FIELD(GPIO_INDEX_REG, COMMAND, 12, 1) + FIELD(GPIO_INDEX_REG, TYPE, 16, 4) + FIELD(GPIO_INDEX_REG, DATA_VALUE, 20, 1) + FIELD(GPIO_INDEX_REG, DIRECTION, 20, 1) + FIELD(GPIO_INDEX_REG, INT_ENABLE, 20, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_0, 21, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_1, 22, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_2, 23, 1) + FIELD(GPIO_INDEX_REG, INT_STATUS, 24, 1) + FIELD(GPIO_INDEX_REG, DEBOUNCE_1, 20, 1) + FIELD(GPIO_INDEX_REG, DEBOUNCE_2, 21, 1) + FIELD(GPIO_INDEX_REG, RESET_TOLERANT, 20, 1) + FIELD(GPIO_INDEX_REG, COMMAND_SRC_0, 20, 1) + FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1) + FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1) + static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio) { uint32_t falling_edge = 0, rising_edge = 0; @@ -244,7 +268,7 @@ static ptrdiff_t aspeed_gpio_set_idx(AspeedGPIOState *s, GPIOSets *regs) } static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs, - uint32_t value) + uint32_t value, uint32_t mode_mask) { uint32_t input_mask = regs->input_mask; uint32_t direction = regs->direction; @@ -253,7 +277,8 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs, uint32_t diff; int gpio; - diff = old ^ new; + diff = (old ^ new); + diff &= mode_mask; if (diff) { for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) { uint32_t mask = 1 << gpio; @@ -312,10 +337,10 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t set_idx, if (level) { value |= pin_mask; } else { - value &= !pin_mask; + value &= ~pin_mask; } - aspeed_gpio_update(s, &s->sets[set_idx], value); + aspeed_gpio_update(s, &s->sets[set_idx], value, ~s->sets[set_idx].direction); } /* @@ -523,55 +548,214 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size) uint64_t idx = -1; const AspeedGPIOReg *reg; GPIOSets *set; + uint32_t value = 0; + uint64_t debounce_value; idx = offset >> 2; if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) { idx -= GPIO_DEBOUNCE_TIME_1; - return (uint64_t) s->debounce_regs[idx]; + debounce_value = (uint64_t) s->debounce_regs[idx]; + trace_aspeed_gpio_read(offset, debounce_value); + return debounce_value; } reg = &agc->reg_table[idx]; if (reg->set_idx >= agc->nr_gpio_sets) { qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return 0; } set = &s->sets[reg->set_idx]; switch (reg->type) { case gpio_reg_data_value: - return set->data_value; + value = set->data_value; + break; case gpio_reg_direction: - return set->direction; + value = set->direction; + break; case gpio_reg_int_enable: - return set->int_enable; + value = set->int_enable; + break; case gpio_reg_int_sens_0: - return set->int_sens_0; + value = set->int_sens_0; + break; case gpio_reg_int_sens_1: - return set->int_sens_1; + value = set->int_sens_1; + break; case gpio_reg_int_sens_2: - return set->int_sens_2; + value = set->int_sens_2; + break; case gpio_reg_int_status: - return set->int_status; + value = set->int_status; + break; case gpio_reg_reset_tolerant: - return set->reset_tol; + value = set->reset_tol; + break; case gpio_reg_debounce_1: - return set->debounce_1; + value = set->debounce_1; + break; case gpio_reg_debounce_2: - return set->debounce_2; + value = set->debounce_2; + break; case gpio_reg_cmd_source_0: - return set->cmd_source_0; + value = set->cmd_source_0; + break; case gpio_reg_cmd_source_1: - return set->cmd_source_1; + value = set->cmd_source_1; + break; case gpio_reg_data_read: - return set->data_read; + value = set->data_read; + break; case gpio_reg_input_mask: - return set->input_mask; + value = set->input_mask; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return 0; } + + trace_aspeed_gpio_read(offset, value); + return value; +} + +static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset, + uint64_t data, uint32_t size) +{ + + AspeedGPIOState *s = ASPEED_GPIO(opaque); + AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s); + const GPIOSetProperties *props; + GPIOSets *set; + uint32_t reg_idx_number = FIELD_EX32(data, GPIO_INDEX_REG, NUMBER); + uint32_t reg_idx_type = FIELD_EX32(data, GPIO_INDEX_REG, TYPE); + uint32_t reg_idx_command = FIELD_EX32(data, GPIO_INDEX_REG, COMMAND); + uint32_t set_idx = reg_idx_number / ASPEED_GPIOS_PER_SET; + uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET; + uint32_t group_idx = pin_idx / GPIOS_PER_GROUP; + uint32_t reg_value = 0; + uint32_t cleared; + + set = &s->sets[set_idx]; + props = &agc->props[set_idx]; + + if (reg_idx_command) + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" PRIx64 "data 0x%" + PRIx64 "index mode wrong command 0x%x\n", + __func__, offset, data, reg_idx_command); + + switch (reg_idx_type) { + case gpio_reg_idx_data: + reg_value = set->data_read; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DATA_VALUE)); + reg_value &= props->output; + reg_value = update_value_control_source(set, set->data_value, + reg_value); + set->data_read = reg_value; + aspeed_gpio_update(s, set, reg_value, set->direction); + return; + case gpio_reg_idx_direction: + reg_value = set->direction; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DIRECTION)); + /* + * where data is the value attempted to be written to the pin: + * pin type | input mask | output mask | expected value + * ------------------------------------------------------------ + * bidirectional | 1 | 1 | data + * input only | 1 | 0 | 0 + * output only | 0 | 1 | 1 + * no pin | 0 | 0 | 0 + * + * which is captured by: + * data = ( data | ~input) & output; + */ + reg_value = (reg_value | ~props->input) & props->output; + set->direction = update_value_control_source(set, set->direction, + reg_value); + break; + case gpio_reg_idx_interrupt: + reg_value = set->int_enable; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_ENABLE)); + set->int_enable = update_value_control_source(set, set->int_enable, + reg_value); + reg_value = set->int_sens_0; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_0)); + set->int_sens_0 = update_value_control_source(set, set->int_sens_0, + reg_value); + reg_value = set->int_sens_1; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_1)); + set->int_sens_1 = update_value_control_source(set, set->int_sens_1, + reg_value); + reg_value = set->int_sens_2; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2)); + set->int_sens_2 = update_value_control_source(set, set->int_sens_2, + reg_value); + /* set interrupt status */ + reg_value = set->int_status; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)); + cleared = ctpop32(reg_value & set->int_status); + if (s->pending && cleared) { + assert(s->pending >= cleared); + s->pending -= cleared; + } + set->int_status &= ~reg_value; + break; + case gpio_reg_idx_debounce: + reg_value = set->debounce_1; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_1)); + set->debounce_1 = update_value_control_source(set, set->debounce_1, + reg_value); + reg_value = set->debounce_2; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_2)); + set->debounce_2 = update_value_control_source(set, set->debounce_2, + reg_value); + return; + case gpio_reg_idx_tolerance: + reg_value = set->reset_tol; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, RESET_TOLERANT)); + set->reset_tol = update_value_control_source(set, set->reset_tol, + reg_value); + return; + case gpio_reg_idx_cmd_src: + reg_value = set->cmd_source_0; + reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_0)); + set->cmd_source_0 = reg_value & ASPEED_CMD_SRC_MASK; + reg_value = set->cmd_source_1; + reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_1)); + set->cmd_source_1 = reg_value & ASPEED_CMD_SRC_MASK; + return; + case gpio_reg_idx_input_mask: + reg_value = set->input_mask; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INPUT_MASK)); + /* + * feeds into interrupt generation + * 0: read from data value reg will be updated + * 1: read from data value reg will not be updated + */ + set->input_mask = reg_value & props->input; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" PRIx64 "data 0x%" + PRIx64 "index mode wrong type 0x%x\n", + __func__, offset, data, reg_idx_type); + return; + } + aspeed_gpio_update(s, set, set->data_value, UINT32_MAX); + return; } static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, @@ -585,7 +769,16 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, GPIOSets *set; uint32_t cleared; + trace_aspeed_gpio_write(offset, data); + idx = offset >> 2; + + /* check gpio index mode */ + if (idx == R_GPIO_INDEX_REG) { + aspeed_gpio_write_index_mode(opaque, offset, data, size); + return; + } + if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) { idx -= GPIO_DEBOUNCE_TIME_1; s->debounce_regs[idx] = (uint32_t) data; @@ -595,7 +788,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, reg = &agc->reg_table[idx]; if (reg->set_idx >= agc->nr_gpio_sets) { qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return; } @@ -607,7 +800,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, data &= props->output; data = update_value_control_source(set, set->data_value, data); set->data_read = data; - aspeed_gpio_update(s, set, data); + aspeed_gpio_update(s, set, data, set->direction); return; case gpio_reg_direction: /* @@ -680,10 +873,10 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return; } - aspeed_gpio_update(s, set, set->data_value); + aspeed_gpio_update(s, set, set->data_value, UINT32_MAX); return; } @@ -795,6 +988,15 @@ static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = { [1] = {0x0000000f, 0x0000000f, {"18E"} }, }; +static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = { + [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, + [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, + [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, + [3] = {0xffffff3f, 0xffffff3f, {"M", "N", "O", "P"} }, + [4] = {0xff060c1f, 0x00060c1f, {"Q", "R", "S", "T"} }, + [5] = {0x000000ff, 0x00000000, {"U"} }, +}; + static const MemoryRegionOps aspeed_gpio_ops = { .read = aspeed_gpio_read, .write = aspeed_gpio_write, @@ -947,6 +1149,16 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data) agc->reg_table = aspeed_1_8v_gpios; } +static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data) +{ + AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); + + agc->props = ast1030_set_props; + agc->nr_gpio_pins = 151; + agc->nr_gpio_sets = 6; + agc->reg_table = aspeed_3_3v_gpios; +} + static const TypeInfo aspeed_gpio_info = { .name = TYPE_ASPEED_GPIO, .parent = TYPE_SYS_BUS_DEVICE, @@ -984,6 +1196,13 @@ static const TypeInfo aspeed_gpio_ast2600_1_8v_info = { .instance_init = aspeed_gpio_init, }; +static const TypeInfo aspeed_gpio_ast1030_info = { + .name = TYPE_ASPEED_GPIO "-ast1030", + .parent = TYPE_ASPEED_GPIO, + .class_init = aspeed_gpio_1030_class_init, + .instance_init = aspeed_gpio_init, +}; + static void aspeed_gpio_register_types(void) { type_register_static(&aspeed_gpio_info); @@ -991,6 +1210,7 @@ static void aspeed_gpio_register_types(void) type_register_static(&aspeed_gpio_ast2500_info); type_register_static(&aspeed_gpio_ast2600_3_3v_info); type_register_static(&aspeed_gpio_ast2600_1_8v_info); + type_register_static(&aspeed_gpio_ast1030_info); } type_init(aspeed_gpio_register_types); diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 7bd6a57264bc..2433eea2a46d 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -1,14 +1,16 @@ -softmmu_ss.add(when: 'CONFIG_E500', if_true: files('mpc8xxx.c')) -softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c')) -softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c')) -softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) -softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) -softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c')) - -softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c')) -softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c')) -softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c')) -softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c')) -softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c')) -softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c')) -softmmu_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c')) +softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c')) +softmmu_ss.add(when: 'CONFIG_GPIO_MPC8XXX', if_true: files('mpc8xxx.c')) +softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c')) +softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) +softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) +softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c')) + +softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c')) +softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c')) +softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c')) +softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c')) +softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c')) +softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c')) +softmmu_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c')) + +softmmu_ss.add(when: 'CONFIG_RT_PINT', if_true: files('rt_pint.c')) diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index bd0841d57fe0..a3341d70f169 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -41,7 +41,7 @@ struct omap_gpio_s { uint16_t pins; }; -struct omap_gpif_s { +struct Omap1GpioState { SysBusDevice parent_obj; MemoryRegion iomem; @@ -53,7 +53,8 @@ struct omap_gpif_s { /* General-Purpose I/O of OMAP1 */ static void omap_gpio_set(void *opaque, int line, int level) { - struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1; + Omap1GpioState *p = opaque; + struct omap_gpio_s *s = &p->omap1; uint16_t prev = s->inputs; if (level) @@ -71,7 +72,7 @@ static void omap_gpio_set(void *opaque, int line, int level) static uint64_t omap_gpio_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + struct omap_gpio_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; if (size != 2) { @@ -109,7 +110,7 @@ static uint64_t omap_gpio_read(void *opaque, hwaddr addr, static void omap_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + struct omap_gpio_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t diff; int ln; @@ -209,7 +210,7 @@ struct omap2_gpio_s { uint8_t delay; }; -struct omap2_gpif_s { +struct Omap2GpioState { SysBusDevice parent_obj; MemoryRegion iomem; @@ -273,7 +274,7 @@ static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line) static void omap2_gpio_set(void *opaque, int line, int level) { - struct omap2_gpif_s *p = opaque; + Omap2GpioState *p = opaque; struct omap2_gpio_s *s = &p->modules[line >> 5]; line &= 31; @@ -308,7 +309,7 @@ static void omap2_gpio_module_reset(struct omap2_gpio_s *s) static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr) { - struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + struct omap2_gpio_s *s = opaque; switch (addr) { case 0x00: /* GPIO_REVISION */ @@ -381,7 +382,7 @@ static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr) static void omap2_gpio_module_write(void *opaque, hwaddr addr, uint32_t value) { - struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + struct omap2_gpio_s *s = opaque; uint32_t diff; int ln; @@ -593,14 +594,14 @@ static const MemoryRegionOps omap2_gpio_module_ops = { static void omap_gpif_reset(DeviceState *dev) { - struct omap_gpif_s *s = OMAP1_GPIO(dev); + Omap1GpioState *s = OMAP1_GPIO(dev); omap_gpio_reset(&s->omap1); } static void omap2_gpif_reset(DeviceState *dev) { - struct omap2_gpif_s *s = OMAP2_GPIO(dev); + Omap2GpioState *s = OMAP2_GPIO(dev); int i; for (i = 0; i < s->modulecount; i++) { @@ -610,10 +611,9 @@ static void omap2_gpif_reset(DeviceState *dev) s->gpo = 0; } -static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size) { - struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; + Omap2GpioState *s = opaque; switch (addr) { case 0x00: /* IPGENERICOCPSPL_REVISION */ @@ -642,7 +642,7 @@ static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, static void omap2_gpif_top_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; + Omap2GpioState *s = opaque; switch (addr) { case 0x00: /* IPGENERICOCPSPL_REVISION */ @@ -677,7 +677,7 @@ static const MemoryRegionOps omap2_gpif_top_ops = { static void omap_gpio_init(Object *obj) { DeviceState *dev = DEVICE(obj); - struct omap_gpif_s *s = OMAP1_GPIO(obj); + Omap1GpioState *s = OMAP1_GPIO(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); qdev_init_gpio_in(dev, omap_gpio_set, 16); @@ -690,7 +690,7 @@ static void omap_gpio_init(Object *obj) static void omap_gpio_realize(DeviceState *dev, Error **errp) { - struct omap_gpif_s *s = OMAP1_GPIO(dev); + Omap1GpioState *s = OMAP1_GPIO(dev); if (!s->clk) { error_setg(errp, "omap-gpio: clk not connected"); @@ -699,7 +699,7 @@ static void omap_gpio_realize(DeviceState *dev, Error **errp) static void omap2_gpio_realize(DeviceState *dev, Error **errp) { - struct omap2_gpif_s *s = OMAP2_GPIO(dev); + Omap2GpioState *s = OMAP2_GPIO(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); int i; @@ -742,13 +742,13 @@ static void omap2_gpio_realize(DeviceState *dev, Error **errp) } } -void omap_gpio_set_clk(omap_gpif *gpio, omap_clk clk) +void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk) { gpio->clk = clk; } static Property omap_gpio_properties[] = { - DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0), + DEFINE_PROP_INT32("mpu_model", Omap1GpioState, mpu_model, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -766,24 +766,24 @@ static void omap_gpio_class_init(ObjectClass *klass, void *data) static const TypeInfo omap_gpio_info = { .name = TYPE_OMAP1_GPIO, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct omap_gpif_s), + .instance_size = sizeof(Omap1GpioState), .instance_init = omap_gpio_init, .class_init = omap_gpio_class_init, }; -void omap2_gpio_set_iclk(omap2_gpif *gpio, omap_clk clk) +void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk) { gpio->iclk = clk; } -void omap2_gpio_set_fclk(omap2_gpif *gpio, uint8_t i, omap_clk clk) +void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk) { assert(i <= 5); gpio->fclk[i] = clk; } static Property omap2_gpio_properties[] = { - DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0), + DEFINE_PROP_INT32("mpu_model", Omap2GpioState, mpu_model, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -801,7 +801,7 @@ static void omap2_gpio_class_init(ObjectClass *klass, void *data) static const TypeInfo omap2_gpio_info = { .name = TYPE_OMAP2_GPIO, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct omap2_gpif_s), + .instance_size = sizeof(Omap2GpioState), .class_init = omap2_gpio_class_init, }; diff --git a/hw/gpio/rt_pint.c b/hw/gpio/rt_pint.c new file mode 100644 index 000000000000..9878b07c26f4 --- /dev/null +++ b/hw/gpio/rt_pint.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2023, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/gpio/rt_pint.h" +#include "migration/vmstate.h" + + +#define RT_PINT_NAME "Pin Interrupt and Pattern Match" + +static uint64_t rt_pint_read(void *opaque, hwaddr offset, unsigned size) +{ + RTPINTState *s = RT_PINT(opaque); + uint32_t value = 0; + + switch(offset) { + case 0x0: + value = s->ISEL; + break; + case 0x4: + value = s->IENR; + break; + case 0x8: + value = s->SIENR; + break; + case 0xc: + value = s->CIENR; + break; + case 0x10: + value = s->IENF; + break; + case 0x14: + value = s->SIENF; + break; + case 0x18: + value = s->CIENF; + break; + case 0x1c: + value = s->RISE; + break; + case 0x20: + value = s->FALL; + break; + case 0x24: + value = s->IST; + break; + case 0x28: + value = s->ISEL; + break; + case 0x2c: + value = s->PMSRC; + break; + case 0x30: + value = s->PMCFG; + break; + } + + return value; +} + +static void rt_pint_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTPINTState *s = RT_PINT(opaque); + + switch(offset) { + case 0x0: + s->ISEL = value; + break; + case 0x4: + s->IENR = value; + break; + case 0x8: + s->SIENR = value; + break; + case 0xc: + s->CIENR = value; + break; + case 0x10: + s->IENF = value; + break; + case 0x14: + s->SIENF = value; + break; + case 0x18: + s->CIENF = value; + break; + case 0x1c: + s->RISE = value; + break; + case 0x20: + s->FALL = value; + break; + case 0x24: + s->IST = value; + break; + case 0x28: + s->ISEL = value; + break; + case 0x2c: + s->PMSRC = value; + break; + case 0x30: + s->PMCFG = value; + break; + default: + break; + } +} + +static const MemoryRegionOps rt_pint_ops = { + .read = rt_pint_read, + .write = rt_pint_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_pint_realize(DeviceState *dev, Error **errp) +{ + RTPINTState *s = RT_PINT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_pint_ops, s, + TYPE_RT_PINT, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_rt_pint = { + .name = RT_PINT_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ISEL, RTPINTState), + VMSTATE_UINT32(IENR, RTPINTState), + VMSTATE_UINT32(SIENR, RTPINTState), + VMSTATE_UINT32(CIENR, RTPINTState), + VMSTATE_UINT32(IENF, RTPINTState), + VMSTATE_UINT32(SIENF, RTPINTState), + VMSTATE_UINT32(CIENF, RTPINTState), + VMSTATE_UINT32(RISE, RTPINTState), + VMSTATE_UINT32(FALL, RTPINTState), + VMSTATE_UINT32(IST, RTPINTState), + VMSTATE_UINT32(PMCTRL, RTPINTState), + VMSTATE_UINT32(PMSRC, RTPINTState), + VMSTATE_UINT32(PMCFG, RTPINTState), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_pint_init(Object *obj) +{ + RTPINTState *s = RT_PINT(obj); + + qdev_init_gpio_out_named(DEVICE(SYS_BUS_DEVICE(obj)), s->irq, SYSBUS_DEVICE_GPIO_IRQ, 8); + + memory_region_init_io(&s->iomem, obj, &rt_pint_ops, s, TYPE_RT_PINT, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_pint_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_pint_realize; + dc->vmsd = &vmstate_rt_pint; +} + +static const TypeInfo rt_pint_info = { + .name = TYPE_RT_PINT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTPINTState), + .instance_init = rt_pint_init, + .class_init = rt_pint_class_init, +}; + +static void rt_pint_register_types(void) +{ + type_register_static(&rt_pint_info); +} + +type_init(rt_pint_register_types) + diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events index 1dab99c5604d..9736b362ac18 100644 --- a/hw/gpio/trace-events +++ b/hw/gpio/trace-events @@ -27,3 +27,7 @@ sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" P sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 + +# aspeed_gpio.c +aspeed_gpio_read(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64 +aspeed_gpio_write(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64 diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig index 22948db02560..5dd8b5b21e25 100644 --- a/hw/hppa/Kconfig +++ b/hw/hppa/Kconfig @@ -1,9 +1,10 @@ -config DINO +config HPPA_B160L bool imply PCI_DEVICES imply E1000_PCI imply VIRTIO_VGA - select PCI + select DINO + select LASI select SERIAL select ISA_BUS select I8259 diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c deleted file mode 100644 index eab96dd84ef0..000000000000 --- a/hw/hppa/dino.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines - * - * (C) 2017-2019 by Helge Deller - * - * This work is licensed under the GNU GPL license version 2 or later. - * - * Documentation available at: - * https://parisc.wiki.kernel.org/images-parisc/9/91/Dino_ers.pdf - * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf - */ - -#include "qemu/osdep.h" -#include "qemu/module.h" -#include "qemu/units.h" -#include "qapi/error.h" -#include "hw/irq.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_bus.h" -#include "migration/vmstate.h" -#include "hppa_sys.h" -#include "trace.h" -#include "qom/object.h" - - -#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" - -#define DINO_IAR0 0x004 -#define DINO_IODC 0x008 -#define DINO_IRR0 0x00C /* RO */ -#define DINO_IAR1 0x010 -#define DINO_IRR1 0x014 /* RO */ -#define DINO_IMR 0x018 -#define DINO_IPR 0x01C -#define DINO_TOC_ADDR 0x020 -#define DINO_ICR 0x024 -#define DINO_ILR 0x028 /* RO */ -#define DINO_IO_COMMAND 0x030 /* WO */ -#define DINO_IO_STATUS 0x034 /* RO */ -#define DINO_IO_CONTROL 0x038 -#define DINO_IO_GSC_ERR_RESP 0x040 /* RO */ -#define DINO_IO_ERR_INFO 0x044 /* RO */ -#define DINO_IO_PCI_ERR_RESP 0x048 /* RO */ -#define DINO_IO_FBB_EN 0x05c -#define DINO_IO_ADDR_EN 0x060 -#define DINO_PCI_CONFIG_ADDR 0x064 -#define DINO_PCI_CONFIG_DATA 0x068 -#define DINO_PCI_IO_DATA 0x06c -#define DINO_PCI_MEM_DATA 0x070 /* Dino 3.x only */ -#define DINO_GSC2X_CONFIG 0x7b4 /* RO */ -#define DINO_GMASK 0x800 -#define DINO_PAMR 0x804 -#define DINO_PAPR 0x808 -#define DINO_DAMODE 0x80c -#define DINO_PCICMD 0x810 -#define DINO_PCISTS 0x814 /* R/WC */ -#define DINO_MLTIM 0x81c -#define DINO_BRDG_FEAT 0x820 -#define DINO_PCIROR 0x824 -#define DINO_PCIWOR 0x828 -#define DINO_TLTIM 0x830 - -#define DINO_IRQS 11 /* bits 0-10 are architected */ -#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ -#define DINO_LOCAL_IRQS (DINO_IRQS + 1) -#define DINO_MASK_IRQ(x) (1 << (x)) - -#define PCIINTA 0x001 -#define PCIINTB 0x002 -#define PCIINTC 0x004 -#define PCIINTD 0x008 -#define PCIINTE 0x010 -#define PCIINTF 0x020 -#define GSCEXTINT 0x040 -/* #define xxx 0x080 - bit 7 is "default" */ -/* #define xxx 0x100 - bit 8 not used */ -/* #define xxx 0x200 - bit 9 not used */ -#define RS232INT 0x400 - -#define DINO_MEM_CHUNK_SIZE (8 * MiB) - -OBJECT_DECLARE_SIMPLE_TYPE(DinoState, DINO_PCI_HOST_BRIDGE) - -#define DINO800_REGS (1 + (DINO_TLTIM - DINO_GMASK) / 4) -static const uint32_t reg800_keep_bits[DINO800_REGS] = { - MAKE_64BIT_MASK(0, 1), /* GMASK */ - MAKE_64BIT_MASK(0, 7), /* PAMR */ - MAKE_64BIT_MASK(0, 7), /* PAPR */ - MAKE_64BIT_MASK(0, 8), /* DAMODE */ - MAKE_64BIT_MASK(0, 7), /* PCICMD */ - MAKE_64BIT_MASK(0, 9), /* PCISTS */ - MAKE_64BIT_MASK(0, 32), /* Undefined */ - MAKE_64BIT_MASK(0, 8), /* MLTIM */ - MAKE_64BIT_MASK(0, 30), /* BRDG_FEAT */ - MAKE_64BIT_MASK(0, 24), /* PCIROR */ - MAKE_64BIT_MASK(0, 22), /* PCIWOR */ - MAKE_64BIT_MASK(0, 32), /* Undocumented */ - MAKE_64BIT_MASK(0, 9), /* TLTIM */ -}; - -struct DinoState { - PCIHostState parent_obj; - - /* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, - so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. */ - uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ - - uint32_t iar0; - uint32_t iar1; - uint32_t imr; - uint32_t ipr; - uint32_t icr; - uint32_t ilr; - uint32_t io_fbb_en; - uint32_t io_addr_en; - uint32_t io_control; - uint32_t toc_addr; - - uint32_t reg800[DINO800_REGS]; - - MemoryRegion this_mem; - MemoryRegion pci_mem; - MemoryRegion pci_mem_alias[32]; - - AddressSpace bm_as; - MemoryRegion bm; - MemoryRegion bm_ram_alias; - MemoryRegion bm_pci_alias; - MemoryRegion bm_cpu_alias; -}; - -/* - * Dino can forward memory accesses from the CPU in the range between - * 0xf0800000 and 0xff000000 to the PCI bus. - */ -static void gsc_to_pci_forwarding(DinoState *s) -{ - uint32_t io_addr_en, tmp; - int enabled, i; - - tmp = extract32(s->io_control, 7, 2); - enabled = (tmp == 0x01); - io_addr_en = s->io_addr_en; - /* Mask out first (=firmware) and last (=Dino) areas. */ - io_addr_en &= ~(BIT(31) | BIT(0)); - - memory_region_transaction_begin(); - for (i = 1; i < 31; i++) { - MemoryRegion *mem = &s->pci_mem_alias[i]; - if (enabled && (io_addr_en & (1U << i))) { - if (!memory_region_is_mapped(mem)) { - uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; - memory_region_add_subregion(get_system_memory(), addr, mem); - } - } else if (memory_region_is_mapped(mem)) { - memory_region_del_subregion(get_system_memory(), mem); - } - } - memory_region_transaction_commit(); -} - -static bool dino_chip_mem_valid(void *opaque, hwaddr addr, - unsigned size, bool is_write, - MemTxAttrs attrs) -{ - bool ret = false; - - switch (addr) { - case DINO_IAR0: - case DINO_IAR1: - case DINO_IRR0: - case DINO_IRR1: - case DINO_IMR: - case DINO_IPR: - case DINO_ICR: - case DINO_ILR: - case DINO_IO_CONTROL: - case DINO_IO_FBB_EN: - case DINO_IO_ADDR_EN: - case DINO_PCI_IO_DATA: - case DINO_TOC_ADDR: - case DINO_GMASK ... DINO_PCISTS: - case DINO_MLTIM ... DINO_PCIWOR: - case DINO_TLTIM: - ret = true; - break; - case DINO_PCI_IO_DATA + 2: - ret = (size <= 2); - break; - case DINO_PCI_IO_DATA + 1: - case DINO_PCI_IO_DATA + 3: - ret = (size == 1); - } - trace_dino_chip_mem_valid(addr, ret); - return ret; -} - -static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, - uint64_t *data, unsigned size, - MemTxAttrs attrs) -{ - DinoState *s = opaque; - MemTxResult ret = MEMTX_OK; - AddressSpace *io; - uint16_t ioaddr; - uint32_t val; - - switch (addr) { - case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3: - /* Read from PCI IO space. */ - io = &address_space_io; - ioaddr = s->parent_obj.config_reg + (addr & 3); - switch (size) { - case 1: - val = address_space_ldub(io, ioaddr, attrs, &ret); - break; - case 2: - val = address_space_lduw_be(io, ioaddr, attrs, &ret); - break; - case 4: - val = address_space_ldl_be(io, ioaddr, attrs, &ret); - break; - default: - g_assert_not_reached(); - } - break; - - case DINO_IO_FBB_EN: - val = s->io_fbb_en; - break; - case DINO_IO_ADDR_EN: - val = s->io_addr_en; - break; - case DINO_IO_CONTROL: - val = s->io_control; - break; - - case DINO_IAR0: - val = s->iar0; - break; - case DINO_IAR1: - val = s->iar1; - break; - case DINO_IMR: - val = s->imr; - break; - case DINO_ICR: - val = s->icr; - break; - case DINO_IPR: - val = s->ipr; - /* Any read to IPR clears the register. */ - s->ipr = 0; - break; - case DINO_ILR: - val = s->ilr; - break; - case DINO_IRR0: - val = s->ilr & s->imr & ~s->icr; - break; - case DINO_IRR1: - val = s->ilr & s->imr & s->icr; - break; - case DINO_TOC_ADDR: - val = s->toc_addr; - break; - case DINO_GMASK ... DINO_TLTIM: - val = s->reg800[(addr - DINO_GMASK) / 4]; - if (addr == DINO_PAMR) { - val &= ~0x01; /* LSB is hardwired to 0 */ - } - if (addr == DINO_MLTIM) { - val &= ~0x07; /* 3 LSB are hardwired to 0 */ - } - if (addr == DINO_BRDG_FEAT) { - val &= ~(0x10710E0ul | 8); /* bits 5-7, 24 & 15 reserved */ - } - break; - - default: - /* Controlled by dino_chip_mem_valid above. */ - g_assert_not_reached(); - } - - trace_dino_chip_read(addr, val); - *data = val; - return ret; -} - -static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr, - uint64_t val, unsigned size, - MemTxAttrs attrs) -{ - DinoState *s = opaque; - AddressSpace *io; - MemTxResult ret; - uint16_t ioaddr; - int i; - - trace_dino_chip_write(addr, val); - - switch (addr) { - case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3: - /* Write into PCI IO space. */ - io = &address_space_io; - ioaddr = s->parent_obj.config_reg + (addr & 3); - switch (size) { - case 1: - address_space_stb(io, ioaddr, val, attrs, &ret); - break; - case 2: - address_space_stw_be(io, ioaddr, val, attrs, &ret); - break; - case 4: - address_space_stl_be(io, ioaddr, val, attrs, &ret); - break; - default: - g_assert_not_reached(); - } - return ret; - - case DINO_IO_FBB_EN: - s->io_fbb_en = val & 0x03; - break; - case DINO_IO_ADDR_EN: - s->io_addr_en = val; - gsc_to_pci_forwarding(s); - break; - case DINO_IO_CONTROL: - s->io_control = val; - gsc_to_pci_forwarding(s); - break; - - case DINO_IAR0: - s->iar0 = val; - break; - case DINO_IAR1: - s->iar1 = val; - break; - case DINO_IMR: - s->imr = val; - break; - case DINO_ICR: - s->icr = val; - break; - case DINO_IPR: - /* Any write to IPR clears the register. */ - s->ipr = 0; - break; - case DINO_TOC_ADDR: - /* IO_COMMAND of CPU with client_id bits */ - s->toc_addr = 0xFFFA0030 | (val & 0x1e000); - break; - - case DINO_ILR: - case DINO_IRR0: - case DINO_IRR1: - /* These registers are read-only. */ - break; - - case DINO_GMASK ... DINO_TLTIM: - i = (addr - DINO_GMASK) / 4; - val &= reg800_keep_bits[i]; - s->reg800[i] = val; - break; - - default: - /* Controlled by dino_chip_mem_valid above. */ - g_assert_not_reached(); - } - return MEMTX_OK; -} - -static const MemoryRegionOps dino_chip_ops = { - .read_with_attrs = dino_chip_read_with_attrs, - .write_with_attrs = dino_chip_write_with_attrs, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - .accepts = dino_chip_mem_valid, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -static const VMStateDescription vmstate_dino = { - .name = "Dino", - .version_id = 2, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(iar0, DinoState), - VMSTATE_UINT32(iar1, DinoState), - VMSTATE_UINT32(imr, DinoState), - VMSTATE_UINT32(ipr, DinoState), - VMSTATE_UINT32(icr, DinoState), - VMSTATE_UINT32(ilr, DinoState), - VMSTATE_UINT32(io_fbb_en, DinoState), - VMSTATE_UINT32(io_addr_en, DinoState), - VMSTATE_UINT32(io_control, DinoState), - VMSTATE_UINT32(toc_addr, DinoState), - VMSTATE_END_OF_LIST() - } -}; - -/* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */ - -static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len) -{ - PCIHostState *s = opaque; - return pci_data_read(s->bus, s->config_reg | (addr & 3), len); -} - -static void dino_config_data_write(void *opaque, hwaddr addr, - uint64_t val, unsigned len) -{ - PCIHostState *s = opaque; - pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); -} - -static const MemoryRegionOps dino_config_data_ops = { - .read = dino_config_data_read, - .write = dino_config_data_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len) -{ - DinoState *s = opaque; - return s->config_reg_dino; -} - -static void dino_config_addr_write(void *opaque, hwaddr addr, - uint64_t val, unsigned len) -{ - PCIHostState *s = opaque; - DinoState *ds = opaque; - ds->config_reg_dino = val; /* keep a copy of original value */ - s->config_reg = val & ~3U; -} - -static const MemoryRegionOps dino_config_addr_ops = { - .read = dino_config_addr_read, - .write = dino_config_addr_write, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque, - int devfn) -{ - DinoState *s = opaque; - - return &s->bm_as; -} - -/* - * Dino interrupts are connected as shown on Page 78, Table 23 - * (Little-endian bit numbers) - * 0 PCI INTA - * 1 PCI INTB - * 2 PCI INTC - * 3 PCI INTD - * 4 PCI INTE - * 5 PCI INTF - * 6 GSC External Interrupt - * 7 Bus Error for "less than fatal" mode - * 8 PS2 - * 9 Unused - * 10 RS232 - */ - -static void dino_set_irq(void *opaque, int irq, int level) -{ - DinoState *s = opaque; - uint32_t bit = 1u << irq; - uint32_t old_ilr = s->ilr; - - if (level) { - uint32_t ena = bit & ~old_ilr; - s->ipr |= ena; - s->ilr = old_ilr | bit; - if (ena & s->imr) { - uint32_t iar = (ena & s->icr ? s->iar1 : s->iar0); - stl_be_phys(&address_space_memory, iar & -32, iar & 31); - } - } else { - s->ilr = old_ilr & ~bit; - } -} - -static int dino_pci_map_irq(PCIDevice *d, int irq_num) -{ - int slot = PCI_SLOT(d->devfn); - - assert(irq_num >= 0 && irq_num <= 3); - - return slot & 0x03; -} - -static void dino_set_timer_irq(void *opaque, int irq, int level) -{ - /* ??? Not connected. */ -} - -static void dino_set_serial_irq(void *opaque, int irq, int level) -{ - dino_set_irq(opaque, 10, level); -} - -PCIBus *dino_init(MemoryRegion *addr_space, - qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq) -{ - DeviceState *dev; - DinoState *s; - PCIBus *b; - int i; - - dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); - s = DINO_PCI_HOST_BRIDGE(dev); - s->iar0 = s->iar1 = CPU_HPA + 3; - s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ - - /* Dino PCI access from main memory. */ - memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, - s, "dino", 4096); - memory_region_add_subregion(addr_space, DINO_HPA, &s->this_mem); - - /* Dino PCI config. */ - memory_region_init_io(&s->parent_obj.conf_mem, OBJECT(&s->parent_obj), - &dino_config_addr_ops, dev, "pci-conf-idx", 4); - memory_region_init_io(&s->parent_obj.data_mem, OBJECT(&s->parent_obj), - &dino_config_data_ops, dev, "pci-conf-data", 4); - memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR, - &s->parent_obj.conf_mem); - memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, - &s->parent_obj.data_mem); - - /* Dino PCI bus memory. */ - memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); - - b = pci_register_root_bus(dev, "pci", dino_set_irq, dino_pci_map_irq, s, - &s->pci_mem, get_system_io(), - PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); - s->parent_obj.bus = b; - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - /* Set up windows into PCI bus memory. */ - for (i = 1; i < 31; i++) { - uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; - char *name = g_strdup_printf("PCI Outbound Window %d", i); - memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), - name, &s->pci_mem, addr, - DINO_MEM_CHUNK_SIZE); - g_free(name); - } - - /* Set up PCI view of memory: Bus master address space. */ - memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); - memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), - "bm-system", addr_space, 0, - 0xf0000000 + DINO_MEM_CHUNK_SIZE); - memory_region_init_alias(&s->bm_pci_alias, OBJECT(s), - "bm-pci", &s->pci_mem, - 0xf0000000 + DINO_MEM_CHUNK_SIZE, - 30 * DINO_MEM_CHUNK_SIZE); - memory_region_init_alias(&s->bm_cpu_alias, OBJECT(s), - "bm-cpu", addr_space, 0xfff00000, - 0xfffff); - memory_region_add_subregion(&s->bm, 0, - &s->bm_ram_alias); - memory_region_add_subregion(&s->bm, - 0xf0000000 + DINO_MEM_CHUNK_SIZE, - &s->bm_pci_alias); - memory_region_add_subregion(&s->bm, 0xfff00000, - &s->bm_cpu_alias); - address_space_init(&s->bm_as, &s->bm, "pci-bm"); - pci_setup_iommu(b, dino_pcihost_set_iommu, s); - - *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); - *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); - - return b; -} - -static void dino_pcihost_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_dino; -} - -static const TypeInfo dino_pcihost_info = { - .name = TYPE_DINO_PCI_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, - .instance_size = sizeof(DinoState), - .class_init = dino_pcihost_class_init, -}; - -static void dino_register_types(void) -{ - type_register_static(&dino_pcihost_info); -} - -type_init(dino_register_types) diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index 5edf577563a2..a5ac3dd0fd17 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -1,4 +1,5 @@ /* HPPA cores and system support chips. */ +/* Be aware: QEMU and seabios-hppa repositories share this file as-is. */ #ifndef HW_HPPA_HPPA_HARDWARE_H #define HW_HPPA_HPPA_HARDWARE_H @@ -40,8 +41,8 @@ #define FW_CFG_IO_BASE 0xfffa0000 -#define PORT_SERIAL1 (DINO_UART_HPA + 0x800) -#define PORT_SERIAL2 (LASI_UART_HPA + 0x800) +#define PORT_SERIAL1 (LASI_UART_HPA + 0x800) +#define PORT_SERIAL2 (DINO_UART_HPA + 0x800) #define HPPA_MAX_CPUS 16 /* max. number of SMP CPUs */ #define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */ diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h deleted file mode 100644 index 0b18271cc9bf..000000000000 --- a/hw/hppa/hppa_sys.h +++ /dev/null @@ -1,24 +0,0 @@ -/* HPPA cores and system support chips. */ - -#ifndef HW_HPPA_SYS_H -#define HW_HPPA_SYS_H - -#include "hw/pci/pci.h" -#include "hw/pci/pci_host.h" -#include "hw/boards.h" -#include "hw/intc/i8259.h" - -#include "hppa_hardware.h" - -PCIBus *dino_init(MemoryRegion *, qemu_irq *, qemu_irq *); -DeviceState *lasi_init(MemoryRegion *); -#define enable_lasi_lan() 0 - -#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" - -/* hppa_pci.c. */ -extern const MemoryRegionOps hppa_pci_ignore_ops; -extern const MemoryRegionOps hppa_pci_conf1_ops; -extern const MemoryRegionOps hppa_pci_iack_ops; - -#endif diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c deleted file mode 100644 index 88c3791eb683..000000000000 --- a/hw/hppa/lasi.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * HP-PARISC Lasi chipset emulation. - * - * (C) 2019 by Helge Deller - * - * This work is licensed under the GNU GPL license version 2 or later. - * - * Documentation available at: - * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf - */ - -#include "qemu/osdep.h" -#include "qemu/units.h" -#include "qemu/log.h" -#include "qapi/error.h" -#include "trace.h" -#include "hw/irq.h" -#include "sysemu/sysemu.h" -#include "sysemu/runstate.h" -#include "hppa_sys.h" -#include "hw/net/lasi_82596.h" -#include "hw/char/parallel.h" -#include "hw/char/serial.h" -#include "hw/input/lasips2.h" -#include "migration/vmstate.h" -#include "qom/object.h" - -#define TYPE_LASI_CHIP "lasi-chip" - -#define LASI_IRR 0x00 /* RO */ -#define LASI_IMR 0x04 -#define LASI_IPR 0x08 -#define LASI_ICR 0x0c -#define LASI_IAR 0x10 - -#define LASI_PCR 0x0C000 /* LASI Power Control register */ -#define LASI_ERRLOG 0x0C004 /* LASI Error Logging register */ -#define LASI_VER 0x0C008 /* LASI Version Control register */ -#define LASI_IORESET 0x0C00C /* LASI I/O Reset register */ -#define LASI_AMR 0x0C010 /* LASI Arbitration Mask register */ -#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */ -#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */ - -#define LASI_BIT(x) (1ul << (x)) -#define LASI_IRQ_BITS (LASI_BIT(5) | LASI_BIT(7) | LASI_BIT(8) | LASI_BIT(9) \ - | LASI_BIT(13) | LASI_BIT(14) | LASI_BIT(16) | LASI_BIT(17) \ - | LASI_BIT(18) | LASI_BIT(19) | LASI_BIT(20) | LASI_BIT(21) \ - | LASI_BIT(26)) - -#define ICR_BUS_ERROR_BIT LASI_BIT(8) /* bit 8 in ICR */ -#define ICR_TOC_BIT LASI_BIT(1) /* bit 1 in ICR */ - -OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) - -struct LasiState { - PCIHostState parent_obj; - - uint32_t irr; - uint32_t imr; - uint32_t ipr; - uint32_t icr; - uint32_t iar; - - uint32_t errlog; - uint32_t amr; - uint32_t rtc; - time_t rtc_ref; - - MemoryRegion this_mem; -}; - -static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, - unsigned size, bool is_write, - MemTxAttrs attrs) -{ - bool ret = false; - - switch (addr) { - case LASI_IRR: - case LASI_IMR: - case LASI_IPR: - case LASI_ICR: - case LASI_IAR: - - case (LASI_LAN_HPA - LASI_HPA): - case (LASI_LPT_HPA - LASI_HPA): - case (LASI_UART_HPA - LASI_HPA): - case (LASI_RTC_HPA - LASI_HPA): - - case LASI_PCR ... LASI_AMR: - ret = true; - } - - trace_lasi_chip_mem_valid(addr, ret); - return ret; -} - -static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr, - uint64_t *data, unsigned size, - MemTxAttrs attrs) -{ - LasiState *s = opaque; - MemTxResult ret = MEMTX_OK; - uint32_t val; - - switch (addr) { - case LASI_IRR: - val = s->irr; - break; - case LASI_IMR: - val = s->imr; - break; - case LASI_IPR: - val = s->ipr; - /* Any read to IPR clears the register. */ - s->ipr = 0; - break; - case LASI_ICR: - val = s->icr & ICR_BUS_ERROR_BIT; /* bus_error */ - break; - case LASI_IAR: - val = s->iar; - break; - - case (LASI_LAN_HPA - LASI_HPA): - case (LASI_LPT_HPA - LASI_HPA): - case (LASI_UART_HPA - LASI_HPA): - val = 0; - break; - case (LASI_RTC_HPA - LASI_HPA): - val = time(NULL); - val += s->rtc_ref; - break; - - case LASI_PCR: - case LASI_VER: /* only version 0 existed. */ - case LASI_IORESET: - val = 0; - break; - case LASI_ERRLOG: - val = s->errlog; - break; - case LASI_AMR: - val = s->amr; - break; - - default: - /* Controlled by lasi_chip_mem_valid above. */ - g_assert_not_reached(); - } - - trace_lasi_chip_read(addr, val); - - *data = val; - return ret; -} - -static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, - uint64_t val, unsigned size, - MemTxAttrs attrs) -{ - LasiState *s = opaque; - - trace_lasi_chip_write(addr, val); - - switch (addr) { - case LASI_IRR: - /* read-only. */ - break; - case LASI_IMR: - s->imr = val; - if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) - qemu_log_mask(LOG_GUEST_ERROR, - "LASI: tried to set invalid %lx IMR value.\n", - (unsigned long) val); - break; - case LASI_IPR: - /* Any write to IPR clears the register. */ - s->ipr = 0; - break; - case LASI_ICR: - s->icr = val; - /* if (val & ICR_TOC_BIT) issue_toc(); */ - break; - case LASI_IAR: - s->iar = val; - break; - - case (LASI_LAN_HPA - LASI_HPA): - /* XXX: reset LAN card */ - break; - case (LASI_LPT_HPA - LASI_HPA): - /* XXX: reset parallel port */ - break; - case (LASI_UART_HPA - LASI_HPA): - /* XXX: reset serial port */ - break; - case (LASI_RTC_HPA - LASI_HPA): - s->rtc_ref = val - time(NULL); - break; - - case LASI_PCR: - if (val == 0x02) /* immediately power off */ - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); - break; - case LASI_ERRLOG: - s->errlog = val; - break; - case LASI_VER: - /* read-only. */ - break; - case LASI_IORESET: - break; /* XXX: TODO: Reset various devices. */ - case LASI_AMR: - s->amr = val; - break; - - default: - /* Controlled by lasi_chip_mem_valid above. */ - g_assert_not_reached(); - } - return MEMTX_OK; -} - -static const MemoryRegionOps lasi_chip_ops = { - .read_with_attrs = lasi_chip_read_with_attrs, - .write_with_attrs = lasi_chip_write_with_attrs, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - .accepts = lasi_chip_mem_valid, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -static const VMStateDescription vmstate_lasi = { - .name = "Lasi", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(irr, LasiState), - VMSTATE_UINT32(imr, LasiState), - VMSTATE_UINT32(ipr, LasiState), - VMSTATE_UINT32(icr, LasiState), - VMSTATE_UINT32(iar, LasiState), - VMSTATE_UINT32(errlog, LasiState), - VMSTATE_UINT32(amr, LasiState), - VMSTATE_END_OF_LIST() - } -}; - - -static void lasi_set_irq(void *opaque, int irq, int level) -{ - LasiState *s = opaque; - uint32_t bit = 1u << irq; - - if (level) { - s->ipr |= bit; - if (bit & s->imr) { - uint32_t iar = s->iar; - s->irr |= bit; - if ((s->icr & ICR_BUS_ERROR_BIT) == 0) { - stl_be_phys(&address_space_memory, iar & -32, iar & 31); - } - } - } -} - -static int lasi_get_irq(unsigned long hpa) -{ - switch (hpa) { - case LASI_HPA: - return 14; - case LASI_UART_HPA: - return 5; - case LASI_LPT_HPA: - return 7; - case LASI_LAN_HPA: - return 8; - case LASI_SCSI_HPA: - return 9; - case LASI_AUDIO_HPA: - return 13; - case LASI_PS2KBD_HPA: - case LASI_PS2MOU_HPA: - return 26; - default: - g_assert_not_reached(); - } -} - -DeviceState *lasi_init(MemoryRegion *address_space) -{ - DeviceState *dev; - LasiState *s; - - dev = qdev_new(TYPE_LASI_CHIP); - s = LASI_CHIP(dev); - s->iar = CPU_HPA + 3; - - /* Lasi access from main memory. */ - memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops, - s, "lasi", 0x100000); - memory_region_add_subregion(address_space, LASI_HPA, &s->this_mem); - - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - /* LAN */ - if (enable_lasi_lan()) { - qemu_irq lan_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_LAN_HPA)); - lasi_82596_init(address_space, LASI_LAN_HPA, lan_irq); - } - - /* Parallel port */ - qemu_irq lpt_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_LPT_HPA)); - parallel_mm_init(address_space, LASI_LPT_HPA + 0x800, 0, - lpt_irq, parallel_hds[0]); - - /* Real time clock (RTC), it's only one 32-bit counter @9000 */ - - s->rtc = time(NULL); - s->rtc_ref = 0; - - if (serial_hd(1)) { - /* Serial port */ - qemu_irq serial_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_UART_HPA)); - serial_mm_init(address_space, LASI_UART_HPA + 0x800, 0, - serial_irq, 8000000 / 16, - serial_hd(0), DEVICE_NATIVE_ENDIAN); - } - - /* PS/2 Keyboard/Mouse */ - qemu_irq ps2kbd_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_PS2KBD_HPA)); - lasips2_init(address_space, LASI_PS2KBD_HPA, ps2kbd_irq); - - return dev; -} - -static void lasi_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_lasi; -} - -static const TypeInfo lasi_pcihost_info = { - .name = TYPE_LASI_CHIP, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LasiState), - .class_init = lasi_class_init, -}; - -static void lasi_register_types(void) -{ - type_register_static(&lasi_pcihost_info); -} - -type_init(lasi_register_types) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 98b30e0395ee..de1cc7ab7102 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -4,7 +4,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #include "elf.h" @@ -16,21 +15,28 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" +#include "hw/intc/i8259.h" +#include "hw/input/lasips2.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" -#include "hppa_sys.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/dino.h" +#include "hw/misc/lasi.h" +#include "hppa_hardware.h" #include "qemu/units.h" #include "qapi/error.h" #include "net/net.h" #include "qemu/log.h" #include "net/net.h" -#define MAX_IDE_BUS 2 - -#define MIN_SEABIOS_HPPA_VERSION 1 /* require at least this fw version */ +#define MIN_SEABIOS_HPPA_VERSION 6 /* require at least this fw version */ #define HPA_POWER_BUTTON (FIRMWARE_END - 0x10) +#define enable_lasi_lan() 0 + + static void hppa_powerdown_req(Notifier *n, void *opaque) { hwaddr soft_power_reg = HPA_POWER_BUTTON; @@ -52,6 +58,29 @@ static Notifier hppa_system_powerdown_notifier = { .notify = hppa_powerdown_req }; +/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */ +static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) +{ +} + +static const MemoryRegionOps hppa_pci_ignore_ops = { + .read = ignore_read, + .write = ignore_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; static ISABus *hppa_isa_bus(void) { @@ -116,21 +145,42 @@ static FWCfgState *create_fw_cfg(MachineState *ms) fw_cfg_add_file(fw_cfg, "/etc/power-button-addr", g_memdup(&val, sizeof(val)), sizeof(val)); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); return fw_cfg; } +static LasiState *lasi_init(void) +{ + DeviceState *dev; + + dev = qdev_new(TYPE_LASI_CHIP); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + return LASI_CHIP(dev); +} + +static DinoState *dino_init(MemoryRegion *addr_space) +{ + DeviceState *dev; + + dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); + object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), + &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + return DINO_PCI_HOST_BRIDGE(dev); +} + static void machine_hppa_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; - DeviceState *dev; + DeviceState *dev, *dino_dev, *lasi_dev; PCIBus *pci_bus; ISABus *isa_bus; - qemu_irq rtc_irq, serial_irq; char *firmware_filename; uint64_t firmware_low, firmware_high; long size; @@ -164,10 +214,17 @@ static void machine_hppa_init(MachineState *machine) /* Init Lasi chip */ - lasi_init(addr_space); + lasi_dev = DEVICE(lasi_init()); + memory_region_add_subregion(addr_space, LASI_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(lasi_dev), 0)); /* Init Dino (PCI host bus chip). */ - pci_bus = dino_init(addr_space, &rtc_irq, &serial_irq); + dino_dev = DEVICE(dino_init(addr_space)); + memory_region_add_subregion(addr_space, DINO_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(dino_dev), 0)); + pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci")); assert(pci_bus); /* Create ISA bus. */ @@ -175,14 +232,21 @@ static void machine_hppa_init(MachineState *machine) assert(isa_bus); /* Realtime clock, used by firmware for PDC_TOD call. */ - mc146818_rtc_init(isa_bus, 2000, rtc_irq); + mc146818_rtc_init(isa_bus, 2000, NULL); - /* Serial code setup. */ - if (serial_hd(0)) { - uint32_t addr = DINO_UART_HPA + 0x800; - serial_mm_init(addr_space, addr, 0, serial_irq, - 115200, serial_hd(0), DEVICE_BIG_ENDIAN); - } + /* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */ + serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16, + serial_hd(0), DEVICE_BIG_ENDIAN); + + serial_mm_init(addr_space, DINO_UART_HPA + 0x800, 0, + qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16, + serial_hd(1), DEVICE_BIG_ENDIAN); + + /* Parallel port */ + parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA), + parallel_hds[0]); /* fw_cfg configuration interface */ create_fw_cfg(machine); @@ -193,6 +257,7 @@ static void machine_hppa_init(MachineState *machine) /* Graphics setup. */ if (machine->enable_graphics && vga_interface_type != VGA_NONE) { + vga_interface_created = true; dev = qdev_new("artist"); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); @@ -201,12 +266,29 @@ static void machine_hppa_init(MachineState *machine) } /* Network setup. */ + if (enable_lasi_lan()) { + lasi_82596_init(addr_space, LASI_LAN_HPA, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA)); + } + for (i = 0; i < nb_nics; i++) { if (!enable_lasi_lan()) { pci_nic_init_nofail(&nd_table[i], pci_bus, "tulip", NULL); } } + /* PS/2 Keyboard/Mouse */ + dev = qdev_new(TYPE_LASIPS2); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA)); + memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), + 0)); + memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA + 0x100, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), + 1)); + /* register power switch emulation */ qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier); @@ -309,8 +391,8 @@ static void machine_hppa_init(MachineState *machine) * mode (kernel_entry=1), and to boot from CD (gr[24]='d') * or hard disc * (gr[24]='c'). */ - kernel_entry = boot_menu ? 1 : 0; - cpu[0]->env.gr[24] = machine->boot_order[0]; + kernel_entry = machine->boot_config.has_menu ? machine->boot_config.menu : 0; + cpu[0]->env.gr[24] = machine->boot_config.order[0]; } /* We jump to the firmware entry routine and pass the @@ -327,12 +409,12 @@ static void machine_hppa_init(MachineState *machine) cpu[0]->env.gr[19] = FW_CFG_IO_BASE; } -static void hppa_machine_reset(MachineState *ms) +static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) { unsigned int smp_cpus = ms->smp.cpus; int i; - qemu_devices_reset(); + qemu_devices_reset(reason); /* Start all CPUs at the firmware entry point. * Monarch CPU will initialize firmware, secondary CPUs @@ -365,9 +447,12 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) } } -static void machine_hppa_machine_init(MachineClass *mc) +static void hppa_machine_init_class_init(ObjectClass *oc, void *data) { - mc->desc = "HPPA generic machine"; + MachineClass *mc = MACHINE_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); + + mc->desc = "HPPA B160L machine"; mc->default_cpu_type = TYPE_HPPA_CPU; mc->init = machine_hppa_init; mc->reset = hppa_machine_reset; @@ -378,30 +463,23 @@ static void machine_hppa_machine_init(MachineClass *mc) mc->default_ram_size = 512 * MiB; mc->default_boot_order = "cd"; mc->default_ram_id = "ram"; -} -static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - machine_hppa_machine_init(mc); - - NMIClass *nc = NMI_CLASS(oc); nc->nmi_monitor_handler = hppa_nmi; } -static const TypeInfo machine_hppa_machine_init_typeinfo = { - .name = ("hppa" "-machine"), - .parent = "machine", - .class_init = machine_hppa_machine_init_class_init, +static const TypeInfo hppa_machine_init_typeinfo = { + .name = MACHINE_TYPE_NAME("hppa"), + .parent = TYPE_MACHINE, + .class_init = hppa_machine_init_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_NMI }, { } }, }; -static void machine_hppa_machine_init_register_types(void) +static void hppa_machine_init_register_types(void) { - type_register_static(&machine_hppa_machine_init_typeinfo); + type_register_static(&hppa_machine_init_typeinfo); } -type_init(machine_hppa_machine_init_register_types) +type_init(hppa_machine_init_register_types) diff --git a/hw/hppa/meson.build b/hw/hppa/meson.build index 1deae83aee82..3d0c586c309a 100644 --- a/hw/hppa/meson.build +++ b/hw/hppa/meson.build @@ -1,4 +1,4 @@ hppa_ss = ss.source_set() -hppa_ss.add(when: 'CONFIG_DINO', if_true: files('pci.c', 'machine.c', 'dino.c', 'lasi.c')) +hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('machine.c')) hw_arch += {'hppa': hppa_ss} diff --git a/hw/hppa/pci.c b/hw/hppa/pci.c deleted file mode 100644 index 32609aba63e7..000000000000 --- a/hw/hppa/pci.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * QEMU HP-PARISC PCI support functions. - * - */ - -#include "qemu/osdep.h" -#include "hppa_sys.h" -#include "qemu/log.h" -#include "trace.h" - - -/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */ - -static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) -{ - return 0; -} - -static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) -{ -} - -const MemoryRegionOps hppa_pci_ignore_ops = { - .read = ignore_read, - .write = ignore_write, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - }, -}; - - -/* PCI config space reads/writes, to byte-word addressable memory. */ -static uint64_t bw_conf1_read(void *opaque, hwaddr addr, - unsigned size) -{ - PCIBus *b = opaque; - return pci_data_read(b, addr, size); -} - -static void bw_conf1_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PCIBus *b = opaque; - pci_data_write(b, addr, val, size); -} - -const MemoryRegionOps hppa_pci_conf1_ops = { - .read = bw_conf1_read, - .write = bw_conf1_write, - .endianness = DEVICE_BIG_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -/* PCI/EISA Interrupt Acknowledge Cycle. */ - -static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size) -{ - return pic_read_irq(isa_pic); -} - -static void special_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - trace_hppa_pci_iack_write(); -} - -const MemoryRegionOps hppa_pci_iack_ops = { - .read = iack_read, - .write = special_write, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events deleted file mode 100644 index 3f42be9056f8..000000000000 --- a/hw/hppa/trace-events +++ /dev/null @@ -1,14 +0,0 @@ -# See docs/devel/tracing.rst for syntax documentation. - -# pci.c -hppa_pci_iack_write(void) "" - -# dino.c -dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" -dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" -dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" - -# lasi.c -lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" -lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" -lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig index 3fbfe41c9e55..fcf65903bd05 100644 --- a/hw/hyperv/Kconfig +++ b/hw/hyperv/Kconfig @@ -11,3 +11,8 @@ config VMBUS bool default y depends on HYPERV + +config SYNDBG + bool + default y + depends on VMBUS diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index cb1074f234c8..57b402b95610 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -27,13 +27,16 @@ struct SynICState { CPUState *cs; - bool enabled; + bool sctl_enabled; hwaddr msg_page_addr; hwaddr event_page_addr; MemoryRegion msg_page_mr; MemoryRegion event_page_mr; struct hyperv_message_page *msg_page; struct hyperv_event_flags_page *event_page; + + QemuMutex sint_routes_mutex; + QLIST_HEAD(, HvSintRoute) sint_routes; }; #define TYPE_SYNIC "hyperv-synic" @@ -51,11 +54,11 @@ static SynICState *get_synic(CPUState *cs) return SYNIC(object_resolve_path_component(OBJECT(cs), "synic")); } -static void synic_update(SynICState *synic, bool enable, +static void synic_update(SynICState *synic, bool sctl_enable, hwaddr msg_page_addr, hwaddr event_page_addr) { - synic->enabled = enable; + synic->sctl_enabled = sctl_enable; if (synic->msg_page_addr != msg_page_addr) { if (synic->msg_page_addr) { memory_region_del_subregion(get_system_memory(), @@ -80,7 +83,7 @@ static void synic_update(SynICState *synic, bool enable, } } -void hyperv_synic_update(CPUState *cs, bool enable, +void hyperv_synic_update(CPUState *cs, bool sctl_enable, hwaddr msg_page_addr, hwaddr event_page_addr) { SynICState *synic = get_synic(cs); @@ -89,7 +92,7 @@ void hyperv_synic_update(CPUState *cs, bool enable, return; } - synic_update(synic, enable, msg_page_addr, event_page_addr); + synic_update(synic, sctl_enable, msg_page_addr, event_page_addr); } static void synic_realize(DeviceState *dev, Error **errp) @@ -110,16 +113,20 @@ static void synic_realize(DeviceState *dev, Error **errp) sizeof(*synic->event_page), &error_abort); synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr); synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr); + qemu_mutex_init(&synic->sint_routes_mutex); + QLIST_INIT(&synic->sint_routes); g_free(msgp_name); g_free(eventp_name); } + static void synic_reset(DeviceState *dev) { SynICState *synic = SYNIC(dev); memset(synic->msg_page, 0, sizeof(*synic->msg_page)); memset(synic->event_page, 0, sizeof(*synic->event_page)); synic_update(synic, false, 0, 0); + assert(QLIST_EMPTY(&synic->sint_routes)); } static void synic_class_init(ObjectClass *klass, void *data) @@ -150,7 +157,7 @@ void hyperv_synic_reset(CPUState *cs) SynICState *synic = get_synic(cs); if (synic) { - device_legacy_reset(DEVICE(synic)); + device_cold_reset(DEVICE(synic)); } } @@ -214,6 +221,7 @@ struct HvSintRoute { HvSintStagedMessage *staged_msg; unsigned refcount; + QLIST_ENTRY(HvSintRoute) link; }; static CPUState *hyperv_find_vcpu(uint32_t vp_index) @@ -259,7 +267,7 @@ static void cpu_post_msg(CPUState *cs, run_on_cpu_data data) assert(staged_msg->state == HV_STAGED_MSG_BUSY); - if (!synic->enabled || !synic->msg_page_addr) { + if (!synic->msg_page_addr) { staged_msg->status = -ENXIO; goto posted; } @@ -343,7 +351,7 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno) if (eventno > HV_EVENT_FLAGS_COUNT) { return -EINVAL; } - if (!synic->enabled || !synic->event_page_addr) { + if (!synic->sctl_enabled || !synic->event_page_addr) { return -ENXIO; } @@ -364,11 +372,12 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno) HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, HvSintMsgCb cb, void *cb_data) { - HvSintRoute *sint_route; - EventNotifier *ack_notifier; + HvSintRoute *sint_route = NULL; + EventNotifier *ack_notifier = NULL; int r, gsi; CPUState *cs; SynICState *synic; + bool ack_event_initialized = false; cs = hyperv_find_vcpu(vp_index); if (!cs) { @@ -381,57 +390,77 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, } sint_route = g_new0(HvSintRoute, 1); - r = event_notifier_init(&sint_route->sint_set_notifier, false); - if (r) { - goto err; + if (!sint_route) { + return NULL; } + sint_route->synic = synic; + sint_route->sint = sint; + sint_route->refcount = 1; ack_notifier = cb ? &sint_route->sint_ack_notifier : NULL; if (ack_notifier) { sint_route->staged_msg = g_new0(HvSintStagedMessage, 1); + if (!sint_route->staged_msg) { + goto cleanup_err_sint; + } sint_route->staged_msg->cb = cb; sint_route->staged_msg->cb_data = cb_data; r = event_notifier_init(ack_notifier, false); if (r) { - goto err_sint_set_notifier; + goto cleanup_err_sint; } - event_notifier_set_handler(ack_notifier, sint_ack_handler); + ack_event_initialized = true; + } + + /* See if we are done or we need to setup a GSI for this SintRoute */ + if (!synic->sctl_enabled) { + goto cleanup; + } + + /* We need to setup a GSI for this SintRoute */ + r = event_notifier_init(&sint_route->sint_set_notifier, false); + if (r) { + goto cleanup_err_sint; } gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint); if (gsi < 0) { - goto err_gsi; + goto cleanup_err_sint_notifier; } r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &sint_route->sint_set_notifier, ack_notifier, gsi); if (r) { - goto err_irqfd; + goto cleanup_err_irqfd; } sint_route->gsi = gsi; - sint_route->synic = synic; - sint_route->sint = sint; - sint_route->refcount = 1; - +cleanup: + qemu_mutex_lock(&synic->sint_routes_mutex); + QLIST_INSERT_HEAD(&synic->sint_routes, sint_route, link); + qemu_mutex_unlock(&synic->sint_routes_mutex); return sint_route; -err_irqfd: +cleanup_err_irqfd: kvm_irqchip_release_virq(kvm_state, gsi); -err_gsi: + +cleanup_err_sint_notifier: + event_notifier_cleanup(&sint_route->sint_set_notifier); + +cleanup_err_sint: if (ack_notifier) { - event_notifier_set_handler(ack_notifier, NULL); - event_notifier_cleanup(ack_notifier); + if (ack_event_initialized) { + event_notifier_set_handler(ack_notifier, NULL); + event_notifier_cleanup(ack_notifier); + } + g_free(sint_route->staged_msg); } -err_sint_set_notifier: - event_notifier_cleanup(&sint_route->sint_set_notifier); -err: - g_free(sint_route); + g_free(sint_route); return NULL; } @@ -442,6 +471,8 @@ void hyperv_sint_route_ref(HvSintRoute *sint_route) void hyperv_sint_route_unref(HvSintRoute *sint_route) { + SynICState *synic; + if (!sint_route) { return; } @@ -452,21 +483,33 @@ void hyperv_sint_route_unref(HvSintRoute *sint_route) return; } - kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, - &sint_route->sint_set_notifier, - sint_route->gsi); - kvm_irqchip_release_virq(kvm_state, sint_route->gsi); + synic = sint_route->synic; + qemu_mutex_lock(&synic->sint_routes_mutex); + QLIST_REMOVE(sint_route, link); + qemu_mutex_unlock(&synic->sint_routes_mutex); + + if (sint_route->gsi) { + kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + sint_route->gsi); + kvm_irqchip_release_virq(kvm_state, sint_route->gsi); + event_notifier_cleanup(&sint_route->sint_set_notifier); + } + if (sint_route->staged_msg) { event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); event_notifier_cleanup(&sint_route->sint_ack_notifier); g_free(sint_route->staged_msg); } - event_notifier_cleanup(&sint_route->sint_set_notifier); g_free(sint_route); } int hyperv_sint_route_set_sint(HvSintRoute *sint_route) { + if (!sint_route->gsi) { + return 0; + } + return event_notifier_set(&sint_route->sint_set_notifier); } @@ -661,3 +704,246 @@ uint16_t hyperv_hcall_signal_event(uint64_t param, bool fast) } return HV_STATUS_INVALID_CONNECTION_ID; } + +static HvSynDbgHandler hv_syndbg_handler; +static void *hv_syndbg_context; + +void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context) +{ + assert(!hv_syndbg_handler); + hv_syndbg_handler = handler; + hv_syndbg_context = context; +} + +uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa) +{ + uint16_t ret; + HvSynDbgMsg msg; + struct hyperv_reset_debug_session_output *reset_dbg_session = NULL; + hwaddr len; + + if (!hv_syndbg_handler) { + ret = HV_STATUS_INVALID_HYPERCALL_CODE; + goto cleanup; + } + + len = sizeof(*reset_dbg_session); + reset_dbg_session = cpu_physical_memory_map(outgpa, &len, 1); + if (!reset_dbg_session || len < sizeof(*reset_dbg_session)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + msg.type = HV_SYNDBG_MSG_CONNECTION_INFO; + ret = hv_syndbg_handler(hv_syndbg_context, &msg); + if (ret) { + goto cleanup; + } + + reset_dbg_session->host_ip = msg.u.connection_info.host_ip; + reset_dbg_session->host_port = msg.u.connection_info.host_port; + /* The following fields are only used as validation for KDVM */ + memset(&reset_dbg_session->host_mac, 0, + sizeof(reset_dbg_session->host_mac)); + reset_dbg_session->target_ip = msg.u.connection_info.host_ip; + reset_dbg_session->target_port = msg.u.connection_info.host_port; + memset(&reset_dbg_session->target_mac, 0, + sizeof(reset_dbg_session->target_mac)); +cleanup: + if (reset_dbg_session) { + cpu_physical_memory_unmap(reset_dbg_session, + sizeof(*reset_dbg_session), 1, len); + } + + return ret; +} + +uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa, + bool fast) +{ + uint16_t ret; + struct hyperv_retrieve_debug_data_input *debug_data_in = NULL; + struct hyperv_retrieve_debug_data_output *debug_data_out = NULL; + hwaddr in_len, out_len; + HvSynDbgMsg msg; + + if (fast || !hv_syndbg_handler) { + ret = HV_STATUS_INVALID_HYPERCALL_CODE; + goto cleanup; + } + + in_len = sizeof(*debug_data_in); + debug_data_in = cpu_physical_memory_map(ingpa, &in_len, 0); + if (!debug_data_in || in_len < sizeof(*debug_data_in)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + out_len = sizeof(*debug_data_out); + debug_data_out = cpu_physical_memory_map(outgpa, &out_len, 1); + if (!debug_data_out || out_len < sizeof(*debug_data_out)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + msg.type = HV_SYNDBG_MSG_RECV; + msg.u.recv.buf_gpa = outgpa + sizeof(*debug_data_out); + msg.u.recv.count = TARGET_PAGE_SIZE - sizeof(*debug_data_out); + msg.u.recv.options = debug_data_in->options; + msg.u.recv.timeout = debug_data_in->timeout; + msg.u.recv.is_raw = true; + ret = hv_syndbg_handler(hv_syndbg_context, &msg); + if (ret == HV_STATUS_NO_DATA) { + debug_data_out->retrieved_count = 0; + debug_data_out->remaining_count = debug_data_in->count; + goto cleanup; + } else if (ret != HV_STATUS_SUCCESS) { + goto cleanup; + } + + debug_data_out->retrieved_count = msg.u.recv.retrieved_count; + debug_data_out->remaining_count = + debug_data_in->count - msg.u.recv.retrieved_count; +cleanup: + if (debug_data_out) { + cpu_physical_memory_unmap(debug_data_out, sizeof(*debug_data_out), 1, + out_len); + } + + if (debug_data_in) { + cpu_physical_memory_unmap(debug_data_in, sizeof(*debug_data_in), 0, + in_len); + } + + return ret; +} + +uint16_t hyperv_hcall_post_dbg_data(uint64_t ingpa, uint64_t outgpa, bool fast) +{ + uint16_t ret; + struct hyperv_post_debug_data_input *post_data_in = NULL; + struct hyperv_post_debug_data_output *post_data_out = NULL; + hwaddr in_len, out_len; + HvSynDbgMsg msg; + + if (fast || !hv_syndbg_handler) { + ret = HV_STATUS_INVALID_HYPERCALL_CODE; + goto cleanup; + } + + in_len = sizeof(*post_data_in); + post_data_in = cpu_physical_memory_map(ingpa, &in_len, 0); + if (!post_data_in || in_len < sizeof(*post_data_in)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + if (post_data_in->count > TARGET_PAGE_SIZE - sizeof(*post_data_in)) { + ret = HV_STATUS_INVALID_PARAMETER; + goto cleanup; + } + + out_len = sizeof(*post_data_out); + post_data_out = cpu_physical_memory_map(outgpa, &out_len, 1); + if (!post_data_out || out_len < sizeof(*post_data_out)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + msg.type = HV_SYNDBG_MSG_SEND; + msg.u.send.buf_gpa = ingpa + sizeof(*post_data_in); + msg.u.send.count = post_data_in->count; + msg.u.send.is_raw = true; + ret = hv_syndbg_handler(hv_syndbg_context, &msg); + if (ret != HV_STATUS_SUCCESS) { + goto cleanup; + } + + post_data_out->pending_count = msg.u.send.pending_count; + ret = post_data_out->pending_count ? HV_STATUS_INSUFFICIENT_BUFFERS : + HV_STATUS_SUCCESS; +cleanup: + if (post_data_out) { + cpu_physical_memory_unmap(post_data_out, + sizeof(*post_data_out), 1, out_len); + } + + if (post_data_in) { + cpu_physical_memory_unmap(post_data_in, + sizeof(*post_data_in), 0, in_len); + } + + return ret; +} + +uint32_t hyperv_syndbg_send(uint64_t ingpa, uint32_t count) +{ + HvSynDbgMsg msg; + + if (!hv_syndbg_handler) { + return HV_SYNDBG_STATUS_INVALID; + } + + msg.type = HV_SYNDBG_MSG_SEND; + msg.u.send.buf_gpa = ingpa; + msg.u.send.count = count; + msg.u.send.is_raw = false; + if (hv_syndbg_handler(hv_syndbg_context, &msg)) { + return HV_SYNDBG_STATUS_INVALID; + } + + return HV_SYNDBG_STATUS_SEND_SUCCESS; +} + +uint32_t hyperv_syndbg_recv(uint64_t ingpa, uint32_t count) +{ + uint16_t ret; + HvSynDbgMsg msg; + + if (!hv_syndbg_handler) { + return HV_SYNDBG_STATUS_INVALID; + } + + msg.type = HV_SYNDBG_MSG_RECV; + msg.u.recv.buf_gpa = ingpa; + msg.u.recv.count = count; + msg.u.recv.options = 0; + msg.u.recv.timeout = 0; + msg.u.recv.is_raw = false; + ret = hv_syndbg_handler(hv_syndbg_context, &msg); + if (ret != HV_STATUS_SUCCESS) { + return 0; + } + + return HV_SYNDBG_STATUS_SET_SIZE(HV_SYNDBG_STATUS_RECV_SUCCESS, + msg.u.recv.retrieved_count); +} + +void hyperv_syndbg_set_pending_page(uint64_t ingpa) +{ + HvSynDbgMsg msg; + + if (!hv_syndbg_handler) { + return; + } + + msg.type = HV_SYNDBG_MSG_SET_PENDING_PAGE; + msg.u.pending_page.buf_gpa = ingpa; + hv_syndbg_handler(hv_syndbg_context, &msg); +} + +uint64_t hyperv_syndbg_query_options(void) +{ + HvSynDbgMsg msg; + + if (!hv_syndbg_handler) { + return 0; + } + + msg.type = HV_SYNDBG_MSG_QUERY_OPTIONS; + if (hv_syndbg_handler(hv_syndbg_context, &msg) != HV_STATUS_SUCCESS) { + return 0; + } + + return msg.u.query_options.options; +} diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build index 1367e2994f25..b43f119ea56c 100644 --- a/hw/hyperv/meson.build +++ b/hw/hyperv/meson.build @@ -1,3 +1,4 @@ specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c')) specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: files('hyperv_testdev.c')) specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c')) +specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c')) diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c new file mode 100644 index 000000000000..16d04cfdc669 --- /dev/null +++ b/hw/hyperv/syndbg.c @@ -0,0 +1,401 @@ +/* + * QEMU Hyper-V Synthetic Debugging device + * + * 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/ctype.h" +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/loader.h" +#include "cpu.h" +#include "hw/hyperv/hyperv.h" +#include "hw/hyperv/vmbus-bridge.h" +#include "hw/hyperv/hyperv-proto.h" +#include "net/net.h" +#include "net/eth.h" +#include "net/checksum.h" +#include "trace.h" + +#define TYPE_HV_SYNDBG "hv-syndbg" + +typedef struct HvSynDbg { + DeviceState parent_obj; + + char *host_ip; + uint16_t host_port; + bool use_hcalls; + + uint32_t target_ip; + struct sockaddr_in servaddr; + int socket; + bool has_data_pending; + uint64_t pending_page_gpa; +} HvSynDbg; + +#define HVSYNDBG(obj) OBJECT_CHECK(HvSynDbg, (obj), TYPE_HV_SYNDBG) + +/* returns NULL unless there is exactly one HV Synth debug device */ +static HvSynDbg *hv_syndbg_find(void) +{ + /* Returns NULL unless there is exactly one hvsd device */ + return HVSYNDBG(object_resolve_path_type("", TYPE_HV_SYNDBG, NULL)); +} + +static void set_pending_state(HvSynDbg *syndbg, bool has_pending) +{ + hwaddr out_len; + void *out_data; + + syndbg->has_data_pending = has_pending; + + if (!syndbg->pending_page_gpa) { + return; + } + + out_len = 1; + out_data = cpu_physical_memory_map(syndbg->pending_page_gpa, &out_len, 1); + if (out_data) { + *(uint8_t *)out_data = !!has_pending; + cpu_physical_memory_unmap(out_data, out_len, 1, out_len); + } +} + +static bool get_udb_pkt_data(void *p, uint32_t len, uint32_t *data_ofs, + uint32_t *src_ip) +{ + uint32_t offset, curr_len = len; + + if (curr_len < sizeof(struct eth_header) || + (be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto) != ETH_P_IP)) { + return false; + } + offset = sizeof(struct eth_header); + curr_len -= sizeof(struct eth_header); + + if (curr_len < sizeof(struct ip_header) || + PKT_GET_IP_HDR(p)->ip_p != IP_PROTO_UDP) { + return false; + } + offset += PKT_GET_IP_HDR_LEN(p); + curr_len -= PKT_GET_IP_HDR_LEN(p); + + if (curr_len < sizeof(struct udp_header)) { + return false; + } + + offset += sizeof(struct udp_header); + *data_ofs = offset; + *src_ip = PKT_GET_IP_HDR(p)->ip_src; + return true; +} + +static uint16_t handle_send_msg(HvSynDbg *syndbg, uint64_t ingpa, + uint32_t count, bool is_raw, + uint32_t *pending_count) +{ + uint16_t ret; + hwaddr data_len; + void *debug_data = NULL; + uint32_t udp_data_ofs = 0; + const void *pkt_data; + int sent_count; + + data_len = count; + debug_data = cpu_physical_memory_map(ingpa, &data_len, 0); + if (!debug_data || data_len < count) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + if (is_raw && + !get_udb_pkt_data(debug_data, count, &udp_data_ofs, + &syndbg->target_ip)) { + ret = HV_STATUS_SUCCESS; + goto cleanup; + } + + pkt_data = (const void *)((uintptr_t)debug_data + udp_data_ofs); + sent_count = sendto(syndbg->socket, pkt_data, count - udp_data_ofs, + MSG_NOSIGNAL, NULL, 0); + if (sent_count == -1) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup; + } + + *pending_count = count - (sent_count + udp_data_ofs); + ret = HV_STATUS_SUCCESS; +cleanup: + if (debug_data) { + cpu_physical_memory_unmap(debug_data, count, 0, data_len); + } + + return ret; +} + +#define UDP_PKT_HEADER_SIZE \ + (sizeof(struct eth_header) + sizeof(struct ip_header) +\ + sizeof(struct udp_header)) + +static bool create_udp_pkt(HvSynDbg *syndbg, void *pkt, uint32_t pkt_len, + void *udp_data, uint32_t udp_data_len) +{ + struct udp_header *udp_part; + + if (pkt_len < (UDP_PKT_HEADER_SIZE + udp_data_len)) { + return false; + } + + /* Setup the eth */ + memset(&PKT_GET_ETH_HDR(pkt)->h_source, 0, ETH_ALEN); + memset(&PKT_GET_ETH_HDR(pkt)->h_dest, 0, ETH_ALEN); + PKT_GET_ETH_HDR(pkt)->h_proto = cpu_to_be16(ETH_P_IP); + + /* Setup the ip */ + PKT_GET_IP_HDR(pkt)->ip_ver_len = + (4 << 4) | (sizeof(struct ip_header) >> 2); + PKT_GET_IP_HDR(pkt)->ip_tos = 0; + PKT_GET_IP_HDR(pkt)->ip_id = 0; + PKT_GET_IP_HDR(pkt)->ip_off = 0; + PKT_GET_IP_HDR(pkt)->ip_ttl = 64; /* IPDEFTTL */ + PKT_GET_IP_HDR(pkt)->ip_p = IP_PROTO_UDP; + PKT_GET_IP_HDR(pkt)->ip_src = syndbg->servaddr.sin_addr.s_addr; + PKT_GET_IP_HDR(pkt)->ip_dst = syndbg->target_ip; + PKT_GET_IP_HDR(pkt)->ip_len = + cpu_to_be16(sizeof(struct ip_header) + sizeof(struct udp_header) + + udp_data_len); + eth_fix_ip4_checksum(PKT_GET_IP_HDR(pkt), PKT_GET_IP_HDR_LEN(pkt)); + + udp_part = (struct udp_header *)((uintptr_t)pkt + + sizeof(struct eth_header) + + PKT_GET_IP_HDR_LEN(pkt)); + udp_part->uh_sport = syndbg->servaddr.sin_port; + udp_part->uh_dport = syndbg->servaddr.sin_port; + udp_part->uh_ulen = cpu_to_be16(sizeof(struct udp_header) + udp_data_len); + memcpy(udp_part + 1, udp_data, udp_data_len); + net_checksum_calculate(pkt, UDP_PKT_HEADER_SIZE + udp_data_len, CSUM_ALL); + return true; +} + +static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa, + uint32_t count, bool is_raw, uint32_t options, + uint64_t timeout, uint32_t *retrieved_count) +{ + uint16_t ret; + uint8_t data_buf[TARGET_PAGE_SIZE - UDP_PKT_HEADER_SIZE]; + hwaddr out_len; + void *out_data; + ssize_t recv_byte_count; + + /* TODO: Handle options and timeout */ + (void)options; + (void)timeout; + + if (!syndbg->has_data_pending) { + recv_byte_count = 0; + } else { + recv_byte_count = recv(syndbg->socket, data_buf, + MIN(sizeof(data_buf), count), MSG_WAITALL); + if (recv_byte_count == -1) { + return HV_STATUS_INVALID_PARAMETER; + } + } + + if (!recv_byte_count) { + *retrieved_count = 0; + return HV_STATUS_NO_DATA; + } + + set_pending_state(syndbg, false); + + out_len = recv_byte_count; + if (is_raw) { + out_len += UDP_PKT_HEADER_SIZE; + } + out_data = cpu_physical_memory_map(outgpa, &out_len, 1); + if (!out_data) { + return HV_STATUS_INSUFFICIENT_MEMORY; + } + + if (is_raw && + !create_udp_pkt(syndbg, out_data, + recv_byte_count + UDP_PKT_HEADER_SIZE, + data_buf, recv_byte_count)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto cleanup_out_data; + } else if (!is_raw) { + memcpy(out_data, data_buf, recv_byte_count); + } + + *retrieved_count = recv_byte_count; + if (is_raw) { + *retrieved_count += UDP_PKT_HEADER_SIZE; + } + ret = HV_STATUS_SUCCESS; + +cleanup_out_data: + cpu_physical_memory_unmap(out_data, out_len, 1, out_len); + return ret; +} + +static uint16_t hv_syndbg_handler(void *context, HvSynDbgMsg *msg) +{ + HvSynDbg *syndbg = context; + uint16_t ret = HV_STATUS_INVALID_HYPERCALL_CODE; + + switch (msg->type) { + case HV_SYNDBG_MSG_CONNECTION_INFO: + msg->u.connection_info.host_ip = + ntohl(syndbg->servaddr.sin_addr.s_addr); + msg->u.connection_info.host_port = + ntohs(syndbg->servaddr.sin_port); + ret = HV_STATUS_SUCCESS; + break; + case HV_SYNDBG_MSG_SEND: + ret = handle_send_msg(syndbg, msg->u.send.buf_gpa, msg->u.send.count, + msg->u.send.is_raw, &msg->u.send.pending_count); + break; + case HV_SYNDBG_MSG_RECV: + ret = handle_recv_msg(syndbg, msg->u.recv.buf_gpa, msg->u.recv.count, + msg->u.recv.is_raw, msg->u.recv.options, + msg->u.recv.timeout, + &msg->u.recv.retrieved_count); + break; + case HV_SYNDBG_MSG_SET_PENDING_PAGE: + syndbg->pending_page_gpa = msg->u.pending_page.buf_gpa; + ret = HV_STATUS_SUCCESS; + break; + case HV_SYNDBG_MSG_QUERY_OPTIONS: + msg->u.query_options.options = 0; + if (syndbg->use_hcalls) { + msg->u.query_options.options = HV_X64_SYNDBG_OPTION_USE_HCALLS; + } + ret = HV_STATUS_SUCCESS; + break; + default: + break; + } + + return ret; +} + +static void hv_syndbg_recv_event(void *opaque) +{ + HvSynDbg *syndbg = opaque; + struct timeval tv; + fd_set rfds; + + tv.tv_sec = 0; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(syndbg->socket, &rfds); + if (select(syndbg->socket + 1, &rfds, NULL, NULL, &tv) > 0) { + set_pending_state(syndbg, true); + } +} + +static void hv_syndbg_realize(DeviceState *dev, Error **errp) +{ + HvSynDbg *syndbg = HVSYNDBG(dev); + + if (!hv_syndbg_find()) { + error_setg(errp, "at most one %s device is permitted", TYPE_HV_SYNDBG); + return; + } + + if (!vmbus_bridge_find()) { + error_setg(errp, "%s device requires vmbus-bridge device", + TYPE_HV_SYNDBG); + return; + } + + /* Parse and host_ip */ + if (qemu_isdigit(syndbg->host_ip[0])) { + syndbg->servaddr.sin_addr.s_addr = inet_addr(syndbg->host_ip); + } else { + struct hostent *he = gethostbyname(syndbg->host_ip); + if (!he) { + error_setg(errp, "%s failed to resolve host name %s", + TYPE_HV_SYNDBG, syndbg->host_ip); + return; + } + syndbg->servaddr.sin_addr = *(struct in_addr *)he->h_addr; + } + + syndbg->socket = socket(AF_INET, SOCK_DGRAM, 0); + if (syndbg->socket < 0) { + error_setg(errp, "%s failed to create socket", TYPE_HV_SYNDBG); + return; + } + + qemu_socket_set_nonblock(syndbg->socket); + + syndbg->servaddr.sin_port = htons(syndbg->host_port); + syndbg->servaddr.sin_family = AF_INET; + if (connect(syndbg->socket, (struct sockaddr *)&syndbg->servaddr, + sizeof(syndbg->servaddr)) < 0) { + closesocket(syndbg->socket); + error_setg(errp, "%s failed to connect to socket", TYPE_HV_SYNDBG); + return; + } + + syndbg->pending_page_gpa = 0; + syndbg->has_data_pending = false; + hyperv_set_syndbg_handler(hv_syndbg_handler, syndbg); + qemu_set_fd_handler(syndbg->socket, hv_syndbg_recv_event, NULL, syndbg); +} + +static void hv_syndbg_unrealize(DeviceState *dev) +{ + HvSynDbg *syndbg = HVSYNDBG(dev); + + if (syndbg->socket > 0) { + qemu_set_fd_handler(syndbg->socket, NULL, NULL, NULL); + closesocket(syndbg->socket); + } +} + +static const VMStateDescription vmstate_hv_syndbg = { + .name = TYPE_HV_SYNDBG, + .unmigratable = 1, +}; + +static Property hv_syndbg_properties[] = { + DEFINE_PROP_STRING("host_ip", HvSynDbg, host_ip), + DEFINE_PROP_UINT16("host_port", HvSynDbg, host_port, 50000), + DEFINE_PROP_BOOL("use_hcalls", HvSynDbg, use_hcalls, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void hv_syndbg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, hv_syndbg_properties); + dc->fw_name = TYPE_HV_SYNDBG; + dc->vmsd = &vmstate_hv_syndbg; + dc->realize = hv_syndbg_realize; + dc->unrealize = hv_syndbg_unrealize; + dc->user_creatable = true; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo hv_syndbg_type_info = { + .name = TYPE_HV_SYNDBG, + .parent = TYPE_DEVICE, + .instance_size = sizeof(HvSynDbg), + .class_init = hv_syndbg_class_init, +}; + +static void hv_syndbg_register_types(void) +{ + type_register_static(&hv_syndbg_type_info); +} + +type_init(hv_syndbg_register_types) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 8aad29f1bb23..271289f902f8 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -1273,105 +1273,6 @@ void vmbus_free_req(void *req) g_free(req); } -static const VMStateDescription vmstate_sgent = { - .name = "vmbus/sgentry", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT64(base, ScatterGatherEntry), - VMSTATE_UINT64(len, ScatterGatherEntry), - VMSTATE_END_OF_LIST() - } -}; - -typedef struct VMBusChanReqSave { - uint16_t chan_idx; - uint16_t pkt_type; - uint32_t msglen; - void *msg; - uint64_t transaction_id; - bool need_comp; - uint32_t num; - ScatterGatherEntry *sgl; -} VMBusChanReqSave; - -static const VMStateDescription vmstate_vmbus_chan_req = { - .name = "vmbus/vmbus_chan_req", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT16(chan_idx, VMBusChanReqSave), - VMSTATE_UINT16(pkt_type, VMBusChanReqSave), - VMSTATE_UINT32(msglen, VMBusChanReqSave), - VMSTATE_VBUFFER_ALLOC_UINT32(msg, VMBusChanReqSave, 0, NULL, msglen), - VMSTATE_UINT64(transaction_id, VMBusChanReqSave), - VMSTATE_BOOL(need_comp, VMBusChanReqSave), - VMSTATE_UINT32(num, VMBusChanReqSave), - VMSTATE_STRUCT_VARRAY_POINTER_UINT32(sgl, VMBusChanReqSave, num, - vmstate_sgent, ScatterGatherEntry), - VMSTATE_END_OF_LIST() - } -}; - -void vmbus_save_req(QEMUFile *f, VMBusChanReq *req) -{ - VMBusChanReqSave req_save; - - req_save.chan_idx = req->chan->subchan_idx; - req_save.pkt_type = req->pkt_type; - req_save.msglen = req->msglen; - req_save.msg = req->msg; - req_save.transaction_id = req->transaction_id; - req_save.need_comp = req->need_comp; - req_save.num = req->sgl.nsg; - req_save.sgl = g_memdup(req->sgl.sg, - req_save.num * sizeof(ScatterGatherEntry)); - - vmstate_save_state(f, &vmstate_vmbus_chan_req, &req_save, NULL); - - g_free(req_save.sgl); -} - -void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size) -{ - VMBusChanReqSave req_save; - VMBusChanReq *req = NULL; - VMBusChannel *chan = NULL; - uint32_t i; - - vmstate_load_state(f, &vmstate_vmbus_chan_req, &req_save, 0); - - if (req_save.chan_idx >= dev->num_channels) { - error_report("%s: %u(chan_idx) > %u(num_channels)", __func__, - req_save.chan_idx, dev->num_channels); - goto out; - } - chan = &dev->channels[req_save.chan_idx]; - - if (vmbus_channel_reserve(chan, 0, req_save.msglen)) { - goto out; - } - - req = vmbus_alloc_req(chan, size, req_save.pkt_type, req_save.msglen, - req_save.transaction_id, req_save.need_comp); - if (req_save.msglen) { - memcpy(req->msg, req_save.msg, req_save.msglen); - } - - for (i = 0; i < req_save.num; i++) { - qemu_sglist_add(&req->sgl, req_save.sgl[i].base, req_save.sgl[i].len); - } - -out: - if (req_save.msglen) { - g_free(req_save.msg); - } - if (req_save.num) { - g_free(req_save.sgl); - } - return req; -} - static void channel_event_cb(EventNotifier *e) { VMBusChannel *chan = container_of(e, VMBusChannel, notifier); @@ -1677,7 +1578,7 @@ static bool vmbus_initialized(VMBus *vmbus) static void vmbus_reset_all(VMBus *vmbus) { - qbus_reset_all(BUS(vmbus)); + bus_cold_reset(BUS(vmbus)); } static void post_msg(VMBus *vmbus, void *msgdata, uint32_t msglen) @@ -2134,7 +2035,7 @@ static void vdev_reset_on_close(VMBusDevice *vdev) } /* all channels closed -- reset device */ - qdev_reset_all(DEVICE(vdev)); + device_cold_reset(DEVICE(vdev)); } static void handle_close_channel(VMBus *vmbus, vmbus_message_close_channel *msg, @@ -2203,7 +2104,7 @@ static void process_message(VMBus *vmbus) goto out; } msgdata = hv_msg->payload; - msg = (struct vmbus_message_header *)msgdata; + msg = msgdata; trace_vmbus_process_incoming_message(msg->message_type); @@ -2503,7 +2404,6 @@ static const TypeInfo vmbus_dev_type_info = { static void vmbus_realize(BusState *bus, Error **errp) { int ret = 0; - Error *local_err = NULL; VMBus *vmbus = VMBUS(bus); qemu_mutex_init(&vmbus->rx_queue_lock); @@ -2514,13 +2414,13 @@ static void vmbus_realize(BusState *bus, Error **errp) ret = hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, vmbus_recv_message, vmbus); if (ret != 0) { - error_setg(&local_err, "hyperv set message handler failed: %d", ret); + error_setg(errp, "hyperv set message handler failed: %d", ret); goto error_out; } ret = event_notifier_init(&vmbus->notifier, 0); if (ret != 0) { - error_setg(&local_err, "event notifier failed to init with %d", ret); + error_setg(errp, "event notifier failed to init with %d", ret); goto remove_msg_handler; } @@ -2528,7 +2428,7 @@ static void vmbus_realize(BusState *bus, Error **errp) ret = hyperv_set_event_flag_handler(VMBUS_EVENT_CONNECTION_ID, &vmbus->notifier); if (ret != 0) { - error_setg(&local_err, "hyperv set event handler failed with %d", ret); + error_setg(errp, "hyperv set event handler failed with %d", ret); goto clear_event_notifier; } @@ -2540,7 +2440,6 @@ static void vmbus_realize(BusState *bus, Error **errp) hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, NULL, NULL); error_out: qemu_mutex_destroy(&vmbus->rx_queue_lock); - error_propagate(errp, local_err); } static void vmbus_unrealize(BusState *bus) diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 9bb8870517f8..90b6244befd5 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -34,6 +34,10 @@ config MPC_I2C bool select I2C +config ALLWINNER_I2C + bool + select I2C + config PCA954X bool select I2C @@ -41,3 +45,7 @@ config PCA954X config PMBUS bool select SMBUS + +config RT_FLEXCOMM_I2C + bool + select I2C diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c new file mode 100644 index 000000000000..a43596583628 --- /dev/null +++ b/hw/i2c/allwinner-i2c.c @@ -0,0 +1,459 @@ +/* + * Allwinner I2C Bus Serial Interface Emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from IMX I2C controller, + * by Jean-Christophe DUBOIS . + * + * 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 . + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" +#include "hw/i2c/allwinner-i2c.h" +#include "hw/irq.h" +#include "migration/vmstate.h" +#include "hw/i2c/i2c.h" +#include "qemu/log.h" +#include "trace.h" +#include "qemu/module.h" + +/* Allwinner I2C memory map */ +#define TWI_ADDR_REG 0x00 /* slave address register */ +#define TWI_XADDR_REG 0x04 /* extended slave address register */ +#define TWI_DATA_REG 0x08 /* data register */ +#define TWI_CNTR_REG 0x0c /* control register */ +#define TWI_STAT_REG 0x10 /* status register */ +#define TWI_CCR_REG 0x14 /* clock control register */ +#define TWI_SRST_REG 0x18 /* software reset register */ +#define TWI_EFR_REG 0x1c /* enhance feature register */ +#define TWI_LCR_REG 0x20 /* line control register */ + +/* Used only in slave mode, do not set */ +#define TWI_ADDR_RESET 0 +#define TWI_XADDR_RESET 0 + +/* Data register */ +#define TWI_DATA_MASK 0xFF +#define TWI_DATA_RESET 0 + +/* Control register */ +#define TWI_CNTR_INT_EN (1 << 7) +#define TWI_CNTR_BUS_EN (1 << 6) +#define TWI_CNTR_M_STA (1 << 5) +#define TWI_CNTR_M_STP (1 << 4) +#define TWI_CNTR_INT_FLAG (1 << 3) +#define TWI_CNTR_A_ACK (1 << 2) +#define TWI_CNTR_MASK 0xFC +#define TWI_CNTR_RESET 0 + +/* Status register */ +#define TWI_STAT_MASK 0xF8 +#define TWI_STAT_RESET 0xF8 + +/* Clock register */ +#define TWI_CCR_CLK_M_MASK 0x78 +#define TWI_CCR_CLK_N_MASK 0x07 +#define TWI_CCR_MASK 0x7F +#define TWI_CCR_RESET 0 + +/* Soft reset */ +#define TWI_SRST_MASK 0x01 +#define TWI_SRST_RESET 0 + +/* Enhance feature */ +#define TWI_EFR_MASK 0x03 +#define TWI_EFR_RESET 0 + +/* Line control */ +#define TWI_LCR_SCL_STATE (1 << 5) +#define TWI_LCR_SDA_STATE (1 << 4) +#define TWI_LCR_SCL_CTL (1 << 3) +#define TWI_LCR_SCL_CTL_EN (1 << 2) +#define TWI_LCR_SDA_CTL (1 << 1) +#define TWI_LCR_SDA_CTL_EN (1 << 0) +#define TWI_LCR_MASK 0x3F +#define TWI_LCR_RESET 0x3A + +/* Status value in STAT register is shifted by 3 bits */ +#define TWI_STAT_SHIFT 3 +#define STAT_FROM_STA(x) ((x) << TWI_STAT_SHIFT) +#define STAT_TO_STA(x) ((x) >> TWI_STAT_SHIFT) + +enum { + STAT_BUS_ERROR = 0, + /* Master mode */ + STAT_M_STA_TX, + STAT_M_RSTA_TX, + STAT_M_ADDR_WR_ACK, + STAT_M_ADDR_WR_NACK, + STAT_M_DATA_TX_ACK, + STAT_M_DATA_TX_NACK, + STAT_M_ARB_LOST, + STAT_M_ADDR_RD_ACK, + STAT_M_ADDR_RD_NACK, + STAT_M_DATA_RX_ACK, + STAT_M_DATA_RX_NACK, + /* Slave mode */ + STAT_S_ADDR_WR_ACK, + STAT_S_ARB_LOST_AW_ACK, + STAT_S_GCA_ACK, + STAT_S_ARB_LOST_GCA_ACK, + STAT_S_DATA_RX_SA_ACK, + STAT_S_DATA_RX_SA_NACK, + STAT_S_DATA_RX_GCA_ACK, + STAT_S_DATA_RX_GCA_NACK, + STAT_S_STP_RSTA, + STAT_S_ADDR_RD_ACK, + STAT_S_ARB_LOST_AR_ACK, + STAT_S_DATA_TX_ACK, + STAT_S_DATA_TX_NACK, + STAT_S_LB_TX_ACK, + /* Master mode, 10-bit */ + STAT_M_2ND_ADDR_WR_ACK, + STAT_M_2ND_ADDR_WR_NACK, + /* Idle */ + STAT_IDLE = 0x1f +} TWI_STAT_STA; + +static const char *allwinner_i2c_get_regname(unsigned offset) +{ + switch (offset) { + case TWI_ADDR_REG: + return "ADDR"; + case TWI_XADDR_REG: + return "XADDR"; + case TWI_DATA_REG: + return "DATA"; + case TWI_CNTR_REG: + return "CNTR"; + case TWI_STAT_REG: + return "STAT"; + case TWI_CCR_REG: + return "CCR"; + case TWI_SRST_REG: + return "SRST"; + case TWI_EFR_REG: + return "EFR"; + case TWI_LCR_REG: + return "LCR"; + default: + return "[?]"; + } +} + +static inline bool allwinner_i2c_is_reset(AWI2CState *s) +{ + return s->srst & TWI_SRST_MASK; +} + +static inline bool allwinner_i2c_bus_is_enabled(AWI2CState *s) +{ + return s->cntr & TWI_CNTR_BUS_EN; +} + +static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s) +{ + return s->cntr & TWI_CNTR_INT_EN; +} + +static void allwinner_i2c_reset_hold(Object *obj) +{ + AWI2CState *s = AW_I2C(obj); + + if (STAT_TO_STA(s->stat) != STAT_IDLE) { + i2c_end_transfer(s->bus); + } + + s->addr = TWI_ADDR_RESET; + s->xaddr = TWI_XADDR_RESET; + s->data = TWI_DATA_RESET; + s->cntr = TWI_CNTR_RESET; + s->stat = TWI_STAT_RESET; + s->ccr = TWI_CCR_RESET; + s->srst = TWI_SRST_RESET; + s->efr = TWI_EFR_RESET; + s->lcr = TWI_LCR_RESET; +} + +static inline void allwinner_i2c_raise_interrupt(AWI2CState *s) +{ + /* + * Raise an interrupt if the device is not reset and it is configured + * to generate some interrupts. + */ + if (!allwinner_i2c_is_reset(s) && allwinner_i2c_bus_is_enabled(s)) { + if (STAT_TO_STA(s->stat) != STAT_IDLE) { + s->cntr |= TWI_CNTR_INT_FLAG; + if (allwinner_i2c_interrupt_is_enabled(s)) { + qemu_irq_raise(s->irq); + } + } + } +} + +static uint64_t allwinner_i2c_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint16_t value; + AWI2CState *s = AW_I2C(opaque); + + switch (offset) { + case TWI_ADDR_REG: + value = s->addr; + break; + case TWI_XADDR_REG: + value = s->xaddr; + break; + case TWI_DATA_REG: + if ((STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) || + (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) || + (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK)) { + /* Get the next byte */ + s->data = i2c_recv(s->bus); + + if (s->cntr & TWI_CNTR_A_ACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); + } else { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); + } + allwinner_i2c_raise_interrupt(s); + } + value = s->data; + break; + case TWI_CNTR_REG: + value = s->cntr; + break; + case TWI_STAT_REG: + value = s->stat; + /* + * If polling when reading then change state to indicate data + * is available + */ + if (STAT_TO_STA(s->stat) == STAT_M_ADDR_RD_ACK) { + if (s->cntr & TWI_CNTR_A_ACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); + } else { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); + } + allwinner_i2c_raise_interrupt(s); + } + break; + case TWI_CCR_REG: + value = s->ccr; + break; + case TWI_SRST_REG: + value = s->srst; + break; + case TWI_EFR_REG: + value = s->efr; + break; + case TWI_LCR_REG: + value = s->lcr; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); + value = 0; + break; + } + + trace_allwinner_i2c_read(allwinner_i2c_get_regname(offset), offset, value); + + return (uint64_t)value; +} + +static void allwinner_i2c_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + AWI2CState *s = AW_I2C(opaque); + + value &= 0xff; + + trace_allwinner_i2c_write(allwinner_i2c_get_regname(offset), offset, value); + + switch (offset) { + case TWI_ADDR_REG: + s->addr = (uint8_t)value; + break; + case TWI_XADDR_REG: + s->xaddr = (uint8_t)value; + break; + case TWI_DATA_REG: + /* If the device is in reset or not enabled, nothing to do */ + if (allwinner_i2c_is_reset(s) || (!allwinner_i2c_bus_is_enabled(s))) { + break; + } + + s->data = value & TWI_DATA_MASK; + + switch (STAT_TO_STA(s->stat)) { + case STAT_M_STA_TX: + case STAT_M_RSTA_TX: + /* Send address */ + if (i2c_start_transfer(s->bus, extract32(s->data, 1, 7), + extract32(s->data, 0, 1))) { + /* If non zero is returned, the address is not valid */ + s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_NACK); + } else { + /* Determine if read of write */ + if (extract32(s->data, 0, 1)) { + s->stat = STAT_FROM_STA(STAT_M_ADDR_RD_ACK); + } else { + s->stat = STAT_FROM_STA(STAT_M_ADDR_WR_ACK); + } + allwinner_i2c_raise_interrupt(s); + } + break; + case STAT_M_ADDR_WR_ACK: + case STAT_M_DATA_TX_ACK: + if (i2c_send(s->bus, s->data)) { + /* If the target return non zero then end the transfer */ + s->stat = STAT_FROM_STA(STAT_M_DATA_TX_NACK); + i2c_end_transfer(s->bus); + } else { + s->stat = STAT_FROM_STA(STAT_M_DATA_TX_ACK); + allwinner_i2c_raise_interrupt(s); + } + break; + default: + break; + } + break; + case TWI_CNTR_REG: + if (!allwinner_i2c_is_reset(s)) { + /* Do something only if not in software reset */ + s->cntr = value & TWI_CNTR_MASK; + + /* Check if start condition should be sent */ + if (s->cntr & TWI_CNTR_M_STA) { + /* Update status */ + if (STAT_TO_STA(s->stat) == STAT_IDLE) { + /* Send start condition */ + s->stat = STAT_FROM_STA(STAT_M_STA_TX); + } else { + /* Send repeated start condition */ + s->stat = STAT_FROM_STA(STAT_M_RSTA_TX); + } + /* Clear start condition */ + s->cntr &= ~TWI_CNTR_M_STA; + } + if (s->cntr & TWI_CNTR_M_STP) { + /* Update status */ + i2c_end_transfer(s->bus); + s->stat = STAT_FROM_STA(STAT_IDLE); + s->cntr &= ~TWI_CNTR_M_STP; + } + if ((s->cntr & TWI_CNTR_INT_FLAG) == 0) { + /* Interrupt flag cleared */ + qemu_irq_lower(s->irq); + } + if ((s->cntr & TWI_CNTR_A_ACK) == 0) { + if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK); + } + } else { + if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_NACK) { + s->stat = STAT_FROM_STA(STAT_M_DATA_RX_ACK); + } + } + allwinner_i2c_raise_interrupt(s); + + } + break; + case TWI_CCR_REG: + s->ccr = value & TWI_CCR_MASK; + break; + case TWI_SRST_REG: + if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) { + /* Perform reset */ + allwinner_i2c_reset_hold(OBJECT(s)); + } + s->srst = value & TWI_SRST_MASK; + break; + case TWI_EFR_REG: + s->efr = value & TWI_EFR_MASK; + break; + case TWI_LCR_REG: + s->lcr = value & TWI_LCR_MASK; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_AW_I2C, __func__, offset); + break; + } +} + +static const MemoryRegionOps allwinner_i2c_ops = { + .read = allwinner_i2c_read, + .write = allwinner_i2c_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription allwinner_i2c_vmstate = { + .name = TYPE_AW_I2C, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(addr, AWI2CState), + VMSTATE_UINT8(xaddr, AWI2CState), + VMSTATE_UINT8(data, AWI2CState), + VMSTATE_UINT8(cntr, AWI2CState), + VMSTATE_UINT8(ccr, AWI2CState), + VMSTATE_UINT8(srst, AWI2CState), + VMSTATE_UINT8(efr, AWI2CState), + VMSTATE_UINT8(lcr, AWI2CState), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_i2c_realize(DeviceState *dev, Error **errp) +{ + AWI2CState *s = AW_I2C(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_i2c_ops, s, + TYPE_AW_I2C, AW_I2C_MEM_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + s->bus = i2c_init_bus(dev, "i2c"); +} + +static void allwinner_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = allwinner_i2c_reset_hold; + dc->vmsd = &allwinner_i2c_vmstate; + dc->realize = allwinner_i2c_realize; + dc->desc = "Allwinner I2C Controller"; +} + +static const TypeInfo allwinner_i2c_type_info = { + .name = TYPE_AW_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AWI2CState), + .class_init = allwinner_i2c_class_init, +}; + +static void allwinner_i2c_register_types(void) +{ + type_register_static(&allwinner_i2c_type_info); +} + +type_init(allwinner_i2c_register_types) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 03a4f5a91010..c166fd20fa11 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" +#include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/module.h" #include "qemu/error-report.h" @@ -28,196 +29,98 @@ #include "hw/i2c/aspeed_i2c.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "hw/registerfields.h" #include "trace.h" -/* I2C Global Register */ - -#define I2C_CTRL_STATUS 0x00 /* Device Interrupt Status */ -#define I2C_CTRL_ASSIGN 0x08 /* Device Interrupt Target - Assignment */ -#define I2C_CTRL_GLOBAL 0x0C /* Global Control Register */ -#define I2C_CTRL_SRAM_EN BIT(0) - -/* I2C Device (Bus) Register */ - -#define I2CD_FUN_CTRL_REG 0x00 /* I2CD Function Control */ -#define I2CD_POOL_PAGE_SEL(x) (((x) >> 20) & 0x7) /* AST2400 */ -#define I2CD_M_SDA_LOCK_EN (0x1 << 16) -#define I2CD_MULTI_MASTER_DIS (0x1 << 15) -#define I2CD_M_SCL_DRIVE_EN (0x1 << 14) -#define I2CD_MSB_STS (0x1 << 9) -#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8) -#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) -#define I2CD_M_HIGH_SPEED_EN (0x1 << 6) -#define I2CD_DEF_ADDR_EN (0x1 << 5) -#define I2CD_DEF_ALERT_EN (0x1 << 4) -#define I2CD_DEF_ARP_EN (0x1 << 3) -#define I2CD_DEF_GCALL_EN (0x1 << 2) -#define I2CD_SLAVE_EN (0x1 << 1) -#define I2CD_MASTER_EN (0x1) - -#define I2CD_AC_TIMING_REG1 0x04 /* Clock and AC Timing Control #1 */ -#define I2CD_AC_TIMING_REG2 0x08 /* Clock and AC Timing Control #1 */ -#define I2CD_INTR_CTRL_REG 0x0c /* I2CD Interrupt Control */ -#define I2CD_INTR_STS_REG 0x10 /* I2CD Interrupt Status */ - -#define I2CD_INTR_SLAVE_ADDR_MATCH (0x1 << 31) /* 0: addr1 1: addr2 */ -#define I2CD_INTR_SLAVE_ADDR_RX_PENDING (0x1 << 30) -/* bits[19-16] Reserved */ - -/* All bits below are cleared by writing 1 */ -#define I2CD_INTR_SLAVE_INACTIVE_TIMEOUT (0x1 << 15) -#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) -#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) -#define I2CD_INTR_SMBUS_ALERT (0x1 << 12) /* Bus [0-3] only */ -#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11) /* Removed */ -#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) /* Removed */ -#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) /* Removed */ -#define I2CD_INTR_GCALL_ADDR (0x1 << 8) /* Removed */ -#define I2CD_INTR_SLAVE_ADDR_RX_MATCH (0x1 << 7) /* use RX_DONE */ -#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) -#define I2CD_INTR_ABNORMAL (0x1 << 5) -#define I2CD_INTR_NORMAL_STOP (0x1 << 4) -#define I2CD_INTR_ARBIT_LOSS (0x1 << 3) -#define I2CD_INTR_RX_DONE (0x1 << 2) -#define I2CD_INTR_TX_NAK (0x1 << 1) -#define I2CD_INTR_TX_ACK (0x1 << 0) - -#define I2CD_CMD_REG 0x14 /* I2CD Command/Status */ -#define I2CD_SDA_OE (0x1 << 28) -#define I2CD_SDA_O (0x1 << 27) -#define I2CD_SCL_OE (0x1 << 26) -#define I2CD_SCL_O (0x1 << 25) -#define I2CD_TX_TIMING (0x1 << 24) -#define I2CD_TX_STATUS (0x1 << 23) - -#define I2CD_TX_STATE_SHIFT 19 /* Tx State Machine */ -#define I2CD_TX_STATE_MASK 0xf -#define I2CD_IDLE 0x0 -#define I2CD_MACTIVE 0x8 -#define I2CD_MSTART 0x9 -#define I2CD_MSTARTR 0xa -#define I2CD_MSTOP 0xb -#define I2CD_MTXD 0xc -#define I2CD_MRXACK 0xd -#define I2CD_MRXD 0xe -#define I2CD_MTXACK 0xf -#define I2CD_SWAIT 0x1 -#define I2CD_SRXD 0x4 -#define I2CD_STXACK 0x5 -#define I2CD_STXD 0x6 -#define I2CD_SRXACK 0x7 -#define I2CD_RECOVER 0x3 - -#define I2CD_SCL_LINE_STS (0x1 << 18) -#define I2CD_SDA_LINE_STS (0x1 << 17) -#define I2CD_BUS_BUSY_STS (0x1 << 16) -#define I2CD_SDA_OE_OUT_DIR (0x1 << 15) -#define I2CD_SDA_O_OUT_DIR (0x1 << 14) -#define I2CD_SCL_OE_OUT_DIR (0x1 << 13) -#define I2CD_SCL_O_OUT_DIR (0x1 << 12) -#define I2CD_BUS_RECOVER_CMD_EN (0x1 << 11) -#define I2CD_S_ALT_EN (0x1 << 10) - -/* Command Bit */ -#define I2CD_RX_DMA_ENABLE (0x1 << 9) -#define I2CD_TX_DMA_ENABLE (0x1 << 8) -#define I2CD_RX_BUFF_ENABLE (0x1 << 7) -#define I2CD_TX_BUFF_ENABLE (0x1 << 6) -#define I2CD_M_STOP_CMD (0x1 << 5) -#define I2CD_M_S_RX_CMD_LAST (0x1 << 4) -#define I2CD_M_RX_CMD (0x1 << 3) -#define I2CD_S_TX_CMD (0x1 << 2) -#define I2CD_M_TX_CMD (0x1 << 1) -#define I2CD_M_START_CMD (0x1) - -#define I2CD_DEV_ADDR_REG 0x18 /* Slave Device Address */ -#define I2CD_POOL_CTRL_REG 0x1c /* Pool Buffer Control */ -#define I2CD_POOL_RX_COUNT(x) (((x) >> 24) & 0xff) -#define I2CD_POOL_RX_SIZE(x) ((((x) >> 16) & 0xff) + 1) -#define I2CD_POOL_TX_COUNT(x) ((((x) >> 8) & 0xff) + 1) -#define I2CD_POOL_OFFSET(x) (((x) & 0x3f) << 2) /* AST2400 */ -#define I2CD_BYTE_BUF_REG 0x20 /* Transmit/Receive Byte Buffer */ -#define I2CD_BYTE_BUF_TX_SHIFT 0 -#define I2CD_BYTE_BUF_TX_MASK 0xff -#define I2CD_BYTE_BUF_RX_SHIFT 8 -#define I2CD_BYTE_BUF_RX_MASK 0xff -#define I2CD_DMA_ADDR 0x24 /* DMA Buffer Address */ -#define I2CD_DMA_LEN 0x28 /* DMA Transfer Length < 4KB */ - -static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus) -{ - return bus->ctrl & I2CD_MASTER_EN; -} - -static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus) -{ - return bus->ctrl & (I2CD_MASTER_EN | I2CD_SLAVE_EN); -} +/* Enable SLAVE_ADDR_RX_MATCH always */ +#define R_I2CD_INTR_STS_ALWAYS_ENABLE R_I2CD_INTR_STS_SLAVE_ADDR_RX_MATCH_MASK static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) { AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); + uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); + uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus); + uint32_t intr_ctrl_mask = bus->regs[intr_ctrl_reg] | + R_I2CD_INTR_STS_ALWAYS_ENABLE; + bool raise_irq; + + if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) { + g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s%s", + aspeed_i2c_bus_pkt_mode_en(bus) && + ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ? + "pktdone|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? + "nak|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? + "ack|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? + "done|" : "", + ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH) ? + "slave-match|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ? + "stop|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? + "abnormal" : ""); + + trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], buf); + } - trace_aspeed_i2c_bus_raise_interrupt(bus->intr_status, - bus->intr_status & I2CD_INTR_TX_NAK ? "nak|" : "", - bus->intr_status & I2CD_INTR_TX_ACK ? "ack|" : "", - bus->intr_status & I2CD_INTR_RX_DONE ? "done|" : "", - bus->intr_status & I2CD_INTR_NORMAL_STOP ? "normal|" : "", - bus->intr_status & I2CD_INTR_ABNORMAL ? "abnormal" : ""); + raise_irq = bus->regs[reg_intr_sts] & intr_ctrl_mask ; + + /* In packet mode we don't mask off INTR_STS */ + if (!aspeed_i2c_bus_pkt_mode_en(bus)) { + bus->regs[reg_intr_sts] &= intr_ctrl_mask; + } - bus->intr_status &= bus->intr_ctrl; - if (bus->intr_status) { + if (raise_irq) { bus->controller->intr_status |= 1 << bus->id; qemu_irq_raise(aic->bus_get_irq(bus)); } } -static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, - unsigned size) +static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus) { - AspeedI2CBus *bus = opaque; AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); - uint64_t value = -1; + + if (!bus->regs[R_I2CS_INTR_STS]) { + return; + } + + bus->controller->intr_status |= 1 << bus->id; + qemu_irq_raise(aic->bus_get_irq(bus)); +} + +static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset, + unsigned size) +{ + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); + uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; switch (offset) { - case I2CD_FUN_CTRL_REG: - value = bus->ctrl; - break; - case I2CD_AC_TIMING_REG1: - value = bus->timing[0]; - break; - case I2CD_AC_TIMING_REG2: - value = bus->timing[1]; - break; - case I2CD_INTR_CTRL_REG: - value = bus->intr_ctrl; - break; - case I2CD_INTR_STS_REG: - value = bus->intr_status; - break; - case I2CD_POOL_CTRL_REG: - value = bus->pool_ctrl; + case A_I2CD_FUN_CTRL: + case A_I2CD_AC_TIMING1: + case A_I2CD_AC_TIMING2: + case A_I2CD_INTR_CTRL: + case A_I2CD_INTR_STS: + case A_I2CD_DEV_ADDR: + case A_I2CD_POOL_CTRL: + case A_I2CD_BYTE_BUF: + /* Value is already set, don't do anything. */ break; - case I2CD_BYTE_BUF_REG: - value = bus->buf; + case A_I2CD_CMD: + value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); break; - case I2CD_CMD_REG: - value = bus->cmd | (i2c_bus_busy(bus->bus) << 16); - break; - case I2CD_DMA_ADDR: + case A_I2CD_DMA_ADDR: if (!aic->has_dma) { qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); - break; + value = -1; } - value = bus->dma_addr; break; - case I2CD_DMA_LEN: + case A_I2CD_DMA_LEN: if (!aic->has_dma) { qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); - break; + value = -1; } - value = bus->dma_len; break; default: @@ -231,32 +134,95 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, return value; } +static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset, + unsigned size) +{ + uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; + + switch (offset) { + case A_I2CC_FUN_CTRL: + case A_I2CC_AC_TIMING: + case A_I2CC_POOL_CTRL: + case A_I2CM_INTR_CTRL: + case A_I2CM_INTR_STS: + case A_I2CC_MS_TXRX_BYTE_BUF: + case A_I2CM_DMA_LEN: + case A_I2CM_DMA_TX_ADDR: + case A_I2CM_DMA_RX_ADDR: + case A_I2CM_DMA_LEN_STS: + case A_I2CC_DMA_ADDR: + case A_I2CC_DMA_LEN: + + case A_I2CS_DEV_ADDR: + case A_I2CS_DMA_RX_ADDR: + case A_I2CS_DMA_LEN: + case A_I2CS_CMD: + case A_I2CS_INTR_CTRL: + case A_I2CS_DMA_LEN_STS: + /* Value is already set, don't do anything. */ + break; + case A_I2CS_INTR_STS: + break; + case A_I2CM_CMD: + value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); + value = -1; + break; + } + + trace_aspeed_i2c_bus_read(bus->id, offset, size, value); + return value; +} + +static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, + unsigned size) +{ + AspeedI2CBus *bus = opaque; + if (aspeed_i2c_is_new_mode(bus->controller)) { + return aspeed_i2c_bus_new_read(bus, offset, size); + } + return aspeed_i2c_bus_old_read(bus, offset, size); +} + static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state) { - bus->cmd &= ~(I2CD_TX_STATE_MASK << I2CD_TX_STATE_SHIFT); - bus->cmd |= (state & I2CD_TX_STATE_MASK) << I2CD_TX_STATE_SHIFT; + if (aspeed_i2c_is_new_mode(bus->controller)) { + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_STATE, + state); + } else { + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_CMD, TX_STATE, state); + } } static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) { - return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK; + if (aspeed_i2c_is_new_mode(bus->controller)) { + return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, + TX_STATE); + } + return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE); } static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) { MemTxResult result; AspeedI2CState *s = bus->controller; + uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); - result = address_space_read(&s->dram_as, bus->dma_addr, + result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr], MEMTXATTRS_UNSPECIFIED, data, 1); if (result != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n", - __func__, bus->dma_addr); + __func__, bus->regs[reg_dma_addr]); return -1; } - bus->dma_addr++; - bus->dma_len--; + bus->regs[reg_dma_addr]++; + bus->regs[reg_dma_len]--; return 0; } @@ -265,34 +231,51 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); int ret = -1; int i; - - if (bus->cmd & I2CD_TX_BUFF_ENABLE) { - for (i = pool_start; i < I2CD_POOL_TX_COUNT(bus->pool_ctrl); i++) { + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); + uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); + int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, + TX_COUNT); + + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { + for (i = pool_start; i < pool_tx_count; i++) { uint8_t *pool_base = aic->bus_pool_base(bus); - trace_aspeed_i2c_bus_send("BUF", i + 1, - I2CD_POOL_TX_COUNT(bus->pool_ctrl), + trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, pool_base[i]); ret = i2c_send(bus->bus, pool_base[i]); if (ret) { break; } } - bus->cmd &= ~I2CD_TX_BUFF_ENABLE; - } else if (bus->cmd & I2CD_TX_DMA_ENABLE) { - while (bus->dma_len) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0); + } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { + /* In new mode, clear how many bytes we TXed */ + if (aspeed_i2c_is_new_mode(bus->controller)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); + } + while (bus->regs[reg_dma_len]) { uint8_t data; aspeed_i2c_dma_read(bus, &data); - trace_aspeed_i2c_bus_send("DMA", bus->dma_len, bus->dma_len, data); + trace_aspeed_i2c_bus_send("DMA", bus->regs[reg_dma_len], + bus->regs[reg_dma_len], data); ret = i2c_send(bus->bus, data); if (ret) { break; } + /* In new mode, keep track of how many bytes we TXed */ + if (aspeed_i2c_is_new_mode(bus->controller)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, + ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, + TX_LEN) + 1); + } } - bus->cmd &= ~I2CD_TX_DMA_ENABLE; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); } else { - trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, bus->buf); - ret = i2c_send(bus->bus, bus->buf); + trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, + bus->regs[reg_byte_buf]); + ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); } return ret; @@ -304,74 +287,100 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); uint8_t data; int i; - - if (bus->cmd & I2CD_RX_BUFF_ENABLE) { + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); + uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); + uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); + int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, + RX_COUNT); + + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { uint8_t *pool_base = aic->bus_pool_base(bus); - for (i = 0; i < I2CD_POOL_RX_SIZE(bus->pool_ctrl); i++) { + for (i = 0; i < pool_rx_count; i++) { pool_base[i] = i2c_recv(bus->bus); - trace_aspeed_i2c_bus_recv("BUF", i + 1, - I2CD_POOL_RX_SIZE(bus->pool_ctrl), + trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count, pool_base[i]); } /* Update RX count */ - bus->pool_ctrl &= ~(0xff << 24); - bus->pool_ctrl |= (i & 0xff) << 24; - bus->cmd &= ~I2CD_RX_BUFF_ENABLE; - } else if (bus->cmd & I2CD_RX_DMA_ENABLE) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); + } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { uint8_t data; + /* In new mode, clear how many bytes we RXed */ + if (aspeed_i2c_is_new_mode(bus->controller)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); + } - while (bus->dma_len) { + while (bus->regs[reg_dma_len]) { MemTxResult result; data = i2c_recv(bus->bus); - trace_aspeed_i2c_bus_recv("DMA", bus->dma_len, bus->dma_len, data); - result = address_space_write(&s->dram_as, bus->dma_addr, + trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], + bus->regs[reg_dma_len], data); + result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], MEMTXATTRS_UNSPECIFIED, &data, 1); if (result != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", - __func__, bus->dma_addr); + __func__, bus->regs[reg_dma_addr]); return; } - bus->dma_addr++; - bus->dma_len--; + bus->regs[reg_dma_addr]++; + bus->regs[reg_dma_len]--; + /* In new mode, keep track of how many bytes we RXed */ + if (aspeed_i2c_is_new_mode(bus->controller)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, + ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, + RX_LEN) + 1); + } } - bus->cmd &= ~I2CD_RX_DMA_ENABLE; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); } else { data = i2c_recv(bus->bus); - trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->buf); - bus->buf = (data & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; + trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); } } static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) { + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); + aspeed_i2c_set_state(bus, I2CD_MRXD); aspeed_i2c_bus_recv(bus); - bus->intr_status |= I2CD_INTR_RX_DONE; - if (bus->cmd & I2CD_M_S_RX_CMD_LAST) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { i2c_nack(bus->bus); } - bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); aspeed_i2c_set_state(bus, I2CD_MACTIVE); } static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) { AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); + uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); - if (bus->cmd & I2CD_TX_BUFF_ENABLE) { + if (aspeed_i2c_bus_pkt_mode_en(bus)) { + return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); + } + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { uint8_t *pool_base = aic->bus_pool_base(bus); return pool_base[0]; - } else if (bus->cmd & I2CD_TX_DMA_ENABLE) { + } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { uint8_t data; aspeed_i2c_dma_read(bus, &data); return data; } else { - return bus->buf; + return bus->regs[reg_byte_buf]; } } @@ -379,7 +388,11 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) { AspeedI2CState *s = bus->controller; AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); - + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); if (!aic->check_sram) { return true; } @@ -388,9 +401,7 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) * AST2500: SRAM must be enabled before using the Buffer Pool or * DMA mode. */ - if (!(s->ctrl_global & I2C_CTRL_SRAM_EN) && - (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE | - I2CD_RX_BUFF_ENABLE | I2CD_TX_BUFF_ENABLE))) { + if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); return false; } @@ -402,27 +413,31 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) { g_autofree char *cmd_flags = NULL; uint32_t count; - - if (bus->cmd & (I2CD_RX_BUFF_ENABLE | I2CD_RX_BUFF_ENABLE)) { - count = I2CD_POOL_TX_COUNT(bus->pool_ctrl); - } else if (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_RX_DMA_ENABLE)) { - count = bus->dma_len; + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); + uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { + count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); + } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { + count = bus->regs[reg_dma_len]; } else { /* BYTE mode */ count = 1; } cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", - bus->cmd & I2CD_M_START_CMD ? "start|" : "", - bus->cmd & I2CD_RX_DMA_ENABLE ? "rxdma|" : "", - bus->cmd & I2CD_TX_DMA_ENABLE ? "txdma|" : "", - bus->cmd & I2CD_RX_BUFF_ENABLE ? "rxbuf|" : "", - bus->cmd & I2CD_TX_BUFF_ENABLE ? "txbuf|" : "", - bus->cmd & I2CD_M_TX_CMD ? "tx|" : "", - bus->cmd & I2CD_M_RX_CMD ? "rx|" : "", - bus->cmd & I2CD_M_S_RX_CMD_LAST ? "last|" : "", - bus->cmd & I2CD_M_STOP_CMD ? "stop" : ""); - - trace_aspeed_i2c_bus_cmd(bus->cmd, cmd_flags, count, bus->intr_status); + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); + + trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, + bus->regs[reg_intr_sts]); } /* @@ -432,9 +447,10 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) { uint8_t pool_start = 0; - - bus->cmd &= ~0xFFFF; - bus->cmd |= value & 0xFFFF; + uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); if (!aspeed_i2c_check_sram(bus)) { return; @@ -444,7 +460,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) aspeed_i2c_bus_cmd_dump(bus); } - if (bus->cmd & I2CD_M_START_CMD) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? I2CD_MSTARTR : I2CD_MSTART; uint8_t addr; @@ -452,24 +468,30 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) aspeed_i2c_set_state(bus, state); addr = aspeed_i2c_get_addr(bus); - if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), extract32(addr, 0, 1))) { - bus->intr_status |= I2CD_INTR_TX_NAK; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); + if (aspeed_i2c_bus_pkt_mode_en(bus)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); + } } else { - bus->intr_status |= I2CD_INTR_TX_ACK; + /* START doesn't set TX_ACK in packet mode */ + if (!aspeed_i2c_bus_pkt_mode_en(bus)) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); + } } - bus->cmd &= ~I2CD_M_START_CMD; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); /* * The START command is also a TX command, as the slave * address is sent on the bus. Drop the TX flag if nothing * else needs to be sent in this sequence. */ - if (bus->cmd & I2CD_TX_BUFF_ENABLE) { - if (I2CD_POOL_TX_COUNT(bus->pool_ctrl) == 1) { - bus->cmd &= ~I2CD_M_TX_CMD; + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) + == 1) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } else { /* * Increase the start index in the TX pool buffer to @@ -477,141 +499,342 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) */ pool_start++; } - } else if (bus->cmd & I2CD_TX_DMA_ENABLE) { - if (bus->dma_len == 0) { - bus->cmd &= ~I2CD_M_TX_CMD; + } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { + if (bus->regs[reg_dma_len] == 0) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } } else { - bus->cmd &= ~I2CD_M_TX_CMD; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } /* No slave found */ if (!i2c_bus_busy(bus->bus)) { + if (aspeed_i2c_bus_pkt_mode_en(bus)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); + ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); + } return; } aspeed_i2c_set_state(bus, I2CD_MACTIVE); } - if (bus->cmd & I2CD_M_TX_CMD) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { aspeed_i2c_set_state(bus, I2CD_MTXD); if (aspeed_i2c_bus_send(bus, pool_start)) { - bus->intr_status |= (I2CD_INTR_TX_NAK); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); i2c_end_transfer(bus->bus); } else { - bus->intr_status |= I2CD_INTR_TX_ACK; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); } - bus->cmd &= ~I2CD_M_TX_CMD; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); aspeed_i2c_set_state(bus, I2CD_MACTIVE); } - if ((bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) && - !(bus->intr_status & I2CD_INTR_RX_DONE)) { + if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || + SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && + !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { aspeed_i2c_handle_rx_cmd(bus); } - if (bus->cmd & I2CD_M_STOP_CMD) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); - bus->intr_status |= I2CD_INTR_ABNORMAL; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); + if (aspeed_i2c_bus_pkt_mode_en(bus)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); + } } else { aspeed_i2c_set_state(bus, I2CD_MSTOP); i2c_end_transfer(bus->bus); - bus->intr_status |= I2CD_INTR_NORMAL_STOP; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); } - bus->cmd &= ~I2CD_M_STOP_CMD; + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); aspeed_i2c_set_state(bus, I2CD_IDLE); } + + if (aspeed_i2c_bus_pkt_mode_en(bus)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); + } } -static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) +static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, + uint64_t value, unsigned size) { - AspeedI2CBus *bus = opaque; AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); bool handle_rx; + bool w1t; trace_aspeed_i2c_bus_write(bus->id, offset, size, value); switch (offset) { - case I2CD_FUN_CTRL_REG: - if (value & I2CD_SLAVE_EN) { - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", - __func__); - break; - } - bus->ctrl = value & 0x0071C3FF; + case A_I2CC_FUN_CTRL: + bus->regs[R_I2CC_FUN_CTRL] = value; + break; + case A_I2CC_AC_TIMING: + bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; break; - case I2CD_AC_TIMING_REG1: - bus->timing[0] = value & 0xFFFFF0F; + case A_I2CC_MS_TXRX_BYTE_BUF: + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, + value); break; - case I2CD_AC_TIMING_REG2: - bus->timing[1] = value & 0x7; + case A_I2CC_POOL_CTRL: + bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; + bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); break; - case I2CD_INTR_CTRL_REG: - bus->intr_ctrl = value & 0x7FFF; + case A_I2CM_INTR_CTRL: + bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; break; - case I2CD_INTR_STS_REG: - handle_rx = (bus->intr_status & I2CD_INTR_RX_DONE) && - (value & I2CD_INTR_RX_DONE); - bus->intr_status &= ~(value & 0x7FFF); - if (!bus->intr_status) { + case A_I2CM_INTR_STS: + handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) + && SHARED_FIELD_EX32(value, RX_DONE); + + /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ + if (aspeed_i2c_bus_pkt_mode_en(bus) && + FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { + bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; + if (!bus->regs[R_I2CM_INTR_STS]) { + bus->controller->intr_status &= ~(1 << bus->id); + qemu_irq_lower(aic->bus_get_irq(bus)); + } + aspeed_i2c_bus_raise_slave_interrupt(bus); + break; + } + bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); + if (!bus->regs[R_I2CM_INTR_STS]) { bus->controller->intr_status &= ~(1 << bus->id); qemu_irq_lower(aic->bus_get_irq(bus)); } - if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) { + if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, + M_RX_CMD) || + SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, + M_S_RX_CMD_LAST))) { aspeed_i2c_handle_rx_cmd(bus); aspeed_i2c_bus_raise_interrupt(bus); } break; - case I2CD_DEV_ADDR_REG: - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", + case A_I2CM_CMD: + if (!aspeed_i2c_bus_is_enabled(bus)) { + break; + } + + if (!aspeed_i2c_bus_is_master(bus)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", + __func__); + break; + } + + if (!aic->has_dma && + (SHARED_FIELD_EX32(value, RX_DMA_EN) || + SHARED_FIELD_EX32(value, TX_DMA_EN))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); + break; + } + + if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { + qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", + __func__); + break; + } + + value &= 0xff0ffbfb; + if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { + bus->regs[R_I2CM_CMD] |= value; + } else { + bus->regs[R_I2CM_CMD] = value; + } + + aspeed_i2c_bus_handle_cmd(bus, value); + aspeed_i2c_bus_raise_interrupt(bus); + break; + case A_I2CM_DMA_TX_ADDR: + bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, + ADDR); + bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); + bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, + TX_BUF_LEN) + 1; + break; + case A_I2CM_DMA_RX_ADDR: + bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, + ADDR); + bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); + bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, + RX_BUF_LEN) + 1; + break; + case A_I2CM_DMA_LEN: + w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || + FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T); + /* If none of the w1t bits are set, just write to the reg as normal. */ + if (!w1t) { + bus->regs[R_I2CM_DMA_LEN] = value; + break; + } + if (FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, + FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); + } + if (FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, + FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); + } + break; + case A_I2CM_DMA_LEN_STS: + /* Writes clear to 0 */ + bus->regs[R_I2CM_DMA_LEN_STS] = 0; + break; + case A_I2CC_DMA_ADDR: + case A_I2CC_DMA_LEN: + /* RO */ + break; + case A_I2CS_DEV_ADDR: + bus->regs[R_I2CS_DEV_ADDR] = value; + break; + case A_I2CS_DMA_RX_ADDR: + bus->regs[R_I2CS_DMA_RX_ADDR] = value; + break; + case A_I2CS_DMA_LEN: + assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0); + if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) { + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN, + FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN)); + } else { + bus->regs[R_I2CS_DMA_LEN] = value; + } + break; + case A_I2CS_CMD: + if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) { + bus->regs[R_I2CS_CMD] |= value; + } else { + bus->regs[R_I2CS_CMD] = value; + } + i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]); + break; + case A_I2CS_INTR_CTRL: + bus->regs[R_I2CS_INTR_CTRL] = value; + break; + + case A_I2CS_INTR_STS: + if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) { + if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) && + FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) { + bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000; + } + } else { + bus->regs[R_I2CS_INTR_STS] &= ~value; + } + if (!bus->regs[R_I2CS_INTR_STS]) { + bus->controller->intr_status &= ~(1 << bus->id); + qemu_irq_lower(aic->bus_get_irq(bus)); + } + aspeed_i2c_bus_raise_interrupt(bus); + break; + case A_I2CS_DMA_LEN_STS: + bus->regs[R_I2CS_DMA_LEN_STS] = 0; + break; + case A_I2CS_DMA_TX_ADDR: + qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n", __func__); break; - case I2CD_POOL_CTRL_REG: - bus->pool_ctrl &= ~0xffffff; - bus->pool_ctrl |= (value & 0xffffff); + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } +} + +static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, + uint64_t value, unsigned size) +{ + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); + bool handle_rx; + + trace_aspeed_i2c_bus_write(bus->id, offset, size, value); + + switch (offset) { + case A_I2CD_FUN_CTRL: + if (SHARED_FIELD_EX32(value, SLAVE_EN)) { + i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]); + } + bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; + break; + case A_I2CD_AC_TIMING1: + bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; + break; + case A_I2CD_AC_TIMING2: + bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; + break; + case A_I2CD_INTR_CTRL: + bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; + break; + case A_I2CD_INTR_STS: + handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) + && SHARED_FIELD_EX32(value, RX_DONE); + bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); + if (!bus->regs[R_I2CD_INTR_STS]) { + bus->controller->intr_status &= ~(1 << bus->id); + qemu_irq_lower(aic->bus_get_irq(bus)); + } + if (handle_rx) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) || + SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, + M_S_RX_CMD_LAST)) { + aspeed_i2c_handle_rx_cmd(bus); + aspeed_i2c_bus_raise_interrupt(bus); + } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) { + i2c_ack(bus->bus); + } + } + break; + case A_I2CD_DEV_ADDR: + bus->regs[R_I2CD_DEV_ADDR] = value; + break; + case A_I2CD_POOL_CTRL: + bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; + bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); break; - case I2CD_BYTE_BUF_REG: - bus->buf = (value & I2CD_BYTE_BUF_TX_MASK) << I2CD_BYTE_BUF_TX_SHIFT; + case A_I2CD_BYTE_BUF: + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); break; - case I2CD_CMD_REG: + case A_I2CD_CMD: if (!aspeed_i2c_bus_is_enabled(bus)) { break; } if (!aspeed_i2c_bus_is_master(bus)) { - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", + qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", __func__); break; } if (!aic->has_dma && - value & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE)) { + (SHARED_FIELD_EX32(value, RX_DMA_EN) || + SHARED_FIELD_EX32(value, TX_DMA_EN))) { qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); break; } + bus->regs[R_I2CD_CMD] &= ~0xFFFF; + bus->regs[R_I2CD_CMD] |= value & 0xFFFF; + aspeed_i2c_bus_handle_cmd(bus, value); aspeed_i2c_bus_raise_interrupt(bus); break; - case I2CD_DMA_ADDR: + case A_I2CD_DMA_ADDR: if (!aic->has_dma) { qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); break; } - bus->dma_addr = value & 0x3ffffffc; + bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; break; - case I2CD_DMA_LEN: + case A_I2CD_DMA_LEN: if (!aic->has_dma) { qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); break; } - bus->dma_len = value & 0xfff; - if (!bus->dma_len) { + bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; + if (!bus->regs[R_I2CD_DMA_LEN]) { qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); } break; @@ -622,16 +845,34 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, } } +static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + AspeedI2CBus *bus = opaque; + if (aspeed_i2c_is_new_mode(bus->controller)) { + aspeed_i2c_bus_new_write(bus, offset, value, size); + } else { + aspeed_i2c_bus_old_write(bus, offset, value, size); + } +} + static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, unsigned size) { AspeedI2CState *s = opaque; switch (offset) { - case I2C_CTRL_STATUS: + case A_I2C_CTRL_STATUS: return s->intr_status; - case I2C_CTRL_GLOBAL: + case A_I2C_CTRL_GLOBAL: return s->ctrl_global; + case A_I2C_CTRL_NEW_CLK_DIVIDER: + if (aspeed_i2c_is_new_mode(s)) { + return s->new_clk_divider; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -647,10 +888,18 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, AspeedI2CState *s = opaque; switch (offset) { - case I2C_CTRL_GLOBAL: + case A_I2C_CTRL_GLOBAL: s->ctrl_global = value; break; - case I2C_CTRL_STATUS: + case A_I2C_CTRL_NEW_CLK_DIVIDER: + if (aspeed_i2c_is_new_mode(s)) { + s->new_clk_divider = value; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx + "\n", __func__, offset); + } + break; + case A_I2C_CTRL_STATUS: default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -707,19 +956,10 @@ static const MemoryRegionOps aspeed_i2c_pool_ops = { static const VMStateDescription aspeed_i2c_bus_vmstate = { .name = TYPE_ASPEED_I2C, - .version_id = 3, - .minimum_version_id = 3, + .version_id = 5, + .minimum_version_id = 5, .fields = (VMStateField[]) { - VMSTATE_UINT8(id, AspeedI2CBus), - VMSTATE_UINT32(ctrl, AspeedI2CBus), - VMSTATE_UINT32_ARRAY(timing, AspeedI2CBus, 2), - VMSTATE_UINT32(intr_ctrl, AspeedI2CBus), - VMSTATE_UINT32(intr_status, AspeedI2CBus), - VMSTATE_UINT32(cmd, AspeedI2CBus), - VMSTATE_UINT32(buf, AspeedI2CBus), - VMSTATE_UINT32(pool_ctrl, AspeedI2CBus), - VMSTATE_UINT32(dma_addr, AspeedI2CBus), - VMSTATE_UINT32(dma_len, AspeedI2CBus), + VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), VMSTATE_END_OF_LIST() } }; @@ -852,16 +1092,134 @@ static const TypeInfo aspeed_i2c_info = { .abstract = true, }; +static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus, + enum i2c_event event) +{ + switch (event) { + case I2C_START_SEND_ASYNC: + if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Slave mode RX DMA is not enabled\n", __func__); + return -1; + } + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0); + bus->regs[R_I2CC_DMA_ADDR] = + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR); + bus->regs[R_I2CC_DMA_LEN] = + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1; + i2c_ack(bus->bus); + break; + case I2C_FINISH: + ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1); + ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1); + SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1); + aspeed_i2c_bus_raise_slave_interrupt(bus); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n", + __func__, event); + return -1; + } + + return 0; +} + +static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event) +{ + BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); + AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); + uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); + uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); + uint32_t reg_dev_addr = aspeed_i2c_bus_dev_addr_offset(bus); + uint32_t dev_addr = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_dev_addr, + SLAVE_DEV_ADDR1); + + if (aspeed_i2c_is_new_mode(bus->controller)) { + return aspeed_i2c_bus_new_slave_event(bus, event); + } + + switch (event) { + case I2C_START_SEND_ASYNC: + /* Bit[0] == 0 indicates "send". */ + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, dev_addr << 1); + + ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); + + aspeed_i2c_set_state(bus, I2CD_STXD); + + break; + + case I2C_FINISH: + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); + + aspeed_i2c_set_state(bus, I2CD_IDLE); + + break; + + default: + return -1; + } + + aspeed_i2c_bus_raise_interrupt(bus); + + return 0; +} + +static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data) +{ + assert(address_space_write(&bus->controller->dram_as, + bus->regs[R_I2CC_DMA_ADDR], + MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK); + + bus->regs[R_I2CC_DMA_ADDR]++; + bus->regs[R_I2CC_DMA_LEN]--; + ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, + ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1); + i2c_ack(bus->bus); +} + +static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) +{ + BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); + AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); + uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); + uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); + + if (aspeed_i2c_is_new_mode(bus->controller)) { + return aspeed_i2c_bus_new_slave_send_async(bus, data); + } + + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); + + aspeed_i2c_bus_raise_interrupt(bus); +} + +static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + + dc->desc = "Aspeed I2C Bus Slave"; + + sc->event = aspeed_i2c_bus_slave_event; + sc->send_async = aspeed_i2c_bus_slave_send_async; +} + +static const TypeInfo aspeed_i2c_bus_slave_info = { + .name = TYPE_ASPEED_I2C_BUS_SLAVE, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AspeedI2CBusSlave), + .class_init = aspeed_i2c_bus_slave_class_init, +}; + static void aspeed_i2c_bus_reset(DeviceState *dev) { AspeedI2CBus *s = ASPEED_I2C_BUS(dev); - s->intr_ctrl = 0; - s->intr_status = 0; - s->cmd = 0; - s->buf = 0; - s->dma_addr = 0; - s->dma_len = 0; + memset(s->regs, 0, sizeof(s->regs)); i2c_end_transfer(s->bus); } @@ -881,6 +1239,8 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); s->bus = i2c_init_bus(dev, name); + s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE, + 0xff); memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, s, name, aic->reg_size); @@ -919,9 +1279,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) { uint8_t *pool_page = - &bus->controller->pool[I2CD_POOL_PAGE_SEL(bus->ctrl) * 0x100]; + &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, + POOL_PAGE_SEL) * 0x100]; - return &pool_page[I2CD_POOL_OFFSET(bus->pool_ctrl)]; + return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; } static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) @@ -1013,13 +1374,38 @@ static const TypeInfo aspeed_2600_i2c_info = { .class_init = aspeed_2600_i2c_class_init, }; +static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); + + dc->desc = "ASPEED 1030 I2C Controller"; + + aic->num_busses = 14; + aic->reg_size = 0x80; + aic->gap = -1; /* no gap */ + aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; + aic->pool_size = 0x200; + aic->pool_base = 0xC00; + aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; + aic->has_dma = true; +} + +static const TypeInfo aspeed_1030_i2c_info = { + .name = TYPE_ASPEED_1030_I2C, + .parent = TYPE_ASPEED_I2C, + .class_init = aspeed_1030_i2c_class_init, +}; + static void aspeed_i2c_register_types(void) { type_register_static(&aspeed_i2c_bus_info); + type_register_static(&aspeed_i2c_bus_slave_info); type_register_static(&aspeed_i2c_info); type_register_static(&aspeed_2400_i2c_info); type_register_static(&aspeed_2500_i2c_info); type_register_static(&aspeed_2600_i2c_info); + type_register_static(&aspeed_1030_i2c_info); } type_init(aspeed_i2c_register_types) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index d0cb2d32fa44..d4ba8146bffb 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -13,6 +13,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/module.h" +#include "qemu/main-loop.h" #include "trace.h" #define I2C_BROADCAST 0x00 @@ -62,6 +63,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name) bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name)); QLIST_INIT(&bus->current_devs); + QSIMPLEQ_INIT(&bus->pending_masters); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus); return bus; } @@ -74,7 +76,7 @@ void i2c_slave_set_address(I2CSlave *dev, uint8_t address) /* Return nonzero if bus is busy. */ int i2c_bus_busy(I2CBus *bus) { - return !QLIST_EMPTY(&bus->current_devs); + return !QLIST_EMPTY(&bus->current_devs) || bus->bh; } bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, @@ -159,7 +161,8 @@ static int i2c_do_start_transfer(I2CBus *bus, uint8_t address, start condition. */ if (sc->event) { - trace_i2c_event("start", s->address); + trace_i2c_event(event == I2C_START_SEND ? "start" : "start_async", + s->address); rv = sc->event(s, event); if (rv && !bus->broadcast) { if (bus_scanned) { @@ -180,6 +183,26 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool is_recv) : I2C_START_SEND); } +void i2c_bus_master(I2CBus *bus, QEMUBH *bh) +{ + if (i2c_bus_busy(bus)) { + I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1); + node->bh = bh; + + QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry); + + return; + } + + bus->bh = bh; + qemu_bh_schedule(bus->bh); +} + +void i2c_bus_release(I2CBus *bus) +{ + bus->bh = NULL; +} + int i2c_start_recv(I2CBus *bus, uint8_t address) { return i2c_do_start_transfer(bus, address, I2C_START_RECV); @@ -190,6 +213,11 @@ int i2c_start_send(I2CBus *bus, uint8_t address) return i2c_do_start_transfer(bus, address, I2C_START_SEND); } +int i2c_start_send_async(I2CBus *bus, uint8_t address) +{ + return i2c_do_start_transfer(bus, address, I2C_START_SEND_ASYNC); +} + void i2c_end_transfer(I2CBus *bus) { I2CSlaveClass *sc; @@ -206,6 +234,16 @@ void i2c_end_transfer(I2CBus *bus) g_free(node); } bus->broadcast = false; + + if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) { + I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters); + bus->bh = node->bh; + + QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry); + g_free(node); + + qemu_bh_schedule(bus->bh); + } } int i2c_send(I2CBus *bus, uint8_t data) @@ -229,6 +267,23 @@ int i2c_send(I2CBus *bus, uint8_t data) return ret ? -1 : 0; } +int i2c_send_async(I2CBus *bus, uint8_t data) +{ + I2CNode *node = QLIST_FIRST(&bus->current_devs); + I2CSlave *slave = node->elt; + I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(slave); + + if (!sc->send_async) { + return -1; + } + + trace_i2c_send_async(slave->address, data); + + sc->send_async(slave, data); + + return 0; +} + uint8_t i2c_recv(I2CBus *bus) { uint8_t data = 0xff; @@ -265,6 +320,17 @@ void i2c_nack(I2CBus *bus) } } +void i2c_ack(I2CBus *bus) +{ + if (!bus->bh) { + return; + } + + trace_i2c_ack(); + + qemu_bh_schedule(bus->bh); +} + static int i2c_slave_post_load(void *opaque, int version_id) { I2CSlave *dev = opaque; diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index d3df273251f7..53ead7185f9f 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -2,12 +2,13 @@ i2c_ss = ss.source_set() i2c_ss.add(when: 'CONFIG_I2C', if_true: files('core.c')) i2c_ss.add(when: 'CONFIG_SMBUS', if_true: files('smbus_slave.c', 'smbus_master.c')) i2c_ss.add(when: 'CONFIG_ACPI_SMBUS', if_true: files('pm_smbus.c')) -i2c_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('smbus_ich9.c')) +i2c_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('smbus_ich9.c')) i2c_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_i2c.c')) i2c_ss.add(when: 'CONFIG_BITBANG_I2C', if_true: files('bitbang_i2c.c')) i2c_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_i2c.c')) i2c_ss.add(when: 'CONFIG_IMX_I2C', if_true: files('imx_i2c.c')) i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c')) +i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c')) i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c')) i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c')) i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c')) @@ -16,4 +17,5 @@ i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c')) i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) i2c_ss.add(when: 'CONFIG_PMBUS', if_true: files('pmbus_device.c')) +i2c_ss.add(when: 'CONFIG_RT_FLEXCOMM_I2C', if_true: files('rt_flexcomm_i2c.c')) softmmu_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c index 62885fa6a15e..4071a88cfcd1 100644 --- a/hw/i2c/pmbus_device.c +++ b/hw/i2c/pmbus_device.c @@ -261,6 +261,11 @@ void pmbus_check_limits(PMBusDevice *pmdev) } } +void pmbus_idle(PMBusDevice *pmdev) +{ + pmdev->code = PMBUS_IDLE_STATE; +} + /* assert the status_cml error upon receipt of malformed command */ static void pmbus_cml_error(PMBusDevice *pmdev) { @@ -284,14 +289,10 @@ static uint8_t pmbus_receive_byte(SMBusDevice *smd) /* * Reading from all pages will return the value from page 0, - * this is unspecified behaviour in general. + * means that all subsequent commands are to be applied to all output. */ if (pmdev->page == PB_ALL_PAGES) { index = 0; - qemu_log_mask(LOG_GUEST_ERROR, - "%s: tried to read from all pages\n", - __func__); - pmbus_cml_error(pmdev); } else if (pmdev->page > pmdev->num_pages - 1) { qemu_log_mask(LOG_GUEST_ERROR, "%s: page %d is out of range\n", @@ -984,6 +985,10 @@ static uint8_t pmbus_receive_byte(SMBusDevice *smd) } break; + case PMBUS_IDLE_STATE: + pmbus_send8(pmdev, PMBUS_ERR_BYTE); + break; + case PMBUS_CLEAR_FAULTS: /* Send Byte */ case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */ case PMBUS_STORE_DEFAULT_ALL: /* Send Byte */ diff --git a/hw/i2c/rt_flexcomm_i2c.c b/hw/i2c/rt_flexcomm_i2c.c new file mode 100644 index 000000000000..06b96c7a9c33 --- /dev/null +++ b/hw/i2c/rt_flexcomm_i2c.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/rt_flexcomm_i2c.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" + +/* + TODO I2C slave mode is not implement +*/ + +static const VMStateDescription vmstate_rt_flexcomm = { + .name = TYPE_RT_FLEXCOMMI2C, + .version_id = 1, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ID, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_CFG, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_STAT, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_INTENSET, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_INTENCLR, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_TIMEOUT, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_CLKDIV, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_INTSTAT, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_MSTCTL, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_MSTTIME, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_MSTDAT, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVCTL, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVDAT, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVADR0, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVADR1, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVADR2, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVADR3, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_SLVQUAL0, RTFLEXCOMMI2CState), + VMSTATE_UINT32(I2C_MONRXDAT, RTFLEXCOMMI2CState), + VMSTATE_UINT32(PSELID, RTFLEXCOMMI2CState), + VMSTATE_END_OF_LIST() + }, +}; + +static void rt_flexcomm_update(RTFLEXCOMMI2CState *s) +{ + + uint32_t psel = s->PSELID & PERSEL_MASK; + + switch (psel) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + s->PSELID |= I2CPRESENT_MASK; + break; + case 4: + break; + case 5: + break; + default: + break; + } + + if (((s->I2C_CFG & 0x7) != 0) && s->I2C_INTENSET) + { + if ((s->I2C_STAT & s->I2C_INTENSET) != 0) { + qemu_irq_raise(s->irq); + qemu_log("flexcomm raise irq 0x%x\n", s->I2C_STAT); + } else { + qemu_irq_lower(s->irq); + } + } else { + qemu_irq_lower(s->irq); + } + +} + +static void rt_flexcomm_reset(RTFLEXCOMMI2CState *s) +{ + + s->ID = 0x0FFC0000; + s->I2C_CFG = 0; + s->I2C_STAT = 0x801; + s->I2C_INTENSET = 0x0; + s->I2C_INTENCLR = 0x0; + s->I2C_TIMEOUT = 0xFFFF; + s->I2C_CLKDIV = 0x0; + s->I2C_INTSTAT = 0x801; + s->I2C_MSTCTL = 0x0; + s->I2C_MSTTIME = 0x77; + s->I2C_MSTDAT = 0x0; + s->I2C_SLVCTL = 0x0; + s->I2C_SLVDAT = 0x0; + s->I2C_SLVADR0 = 0x1; + s->I2C_SLVADR1 = 0x1; + s->I2C_SLVADR2 = 0x1; + s->I2C_SLVADR3 = 0x1; + s->I2C_SLVQUAL0 = 0x0; + s->I2C_MONRXDAT = 0x0; + s->PSELID = 0x1000; + +} + +static void rt_flexcomm_reset_at_boot(DeviceState *dev) +{ + RTFLEXCOMMI2CState *s = RT_FLEXCOMMI2C(dev); + + rt_flexcomm_reset(s); +} + +static uint64_t rt_flexcomm_i2c_read(void *opaque, hwaddr offset, + unsigned size) +{ + RTFLEXCOMMI2CState *s = (RTFLEXCOMMI2CState *)opaque; + uint32_t v = 0; + + switch (offset) { + case 0x800: + v = s->I2C_CFG; + break; + case 0x804: + v = s->I2C_STAT; + break; + case 0x808: + v = s->I2C_INTENSET; + break; + case 0x80C: + /* Write only */ + break; + case 0x810: + v = s->I2C_TIMEOUT; + break; + case 0x814: + v = s->I2C_CLKDIV; + break; + case 0x818: + v = s->I2C_INTSTAT; + break; + case 0x820: + v = s->I2C_MSTCTL; + break; + case 0x824: + v = s->I2C_MSTTIME; + break; + case 0x828: + v = s->I2C_MSTDAT; + break; + case 0x840: + v = s->I2C_SLVCTL; + break; + case 0x844: + v = s->I2C_SLVDAT; + break; + case 0x848: + v = s->I2C_SLVADR0; + break; + case 0x84C: + v = s->I2C_SLVADR1; + break; + case 0x850: + v = s->I2C_SLVADR2; + break; + case 0x854: + v = s->I2C_SLVADR3; + break; + case 0x858: + v = s->I2C_SLVQUAL0; + break; + case 0x880: + v = s->I2C_MONRXDAT; + break; + case 0xFF8: + v = s->PSELID; + break; + default: + break; + } + + printf("[FLEXCOMM_I2C]: read 0x%lx = 0x%x\n", offset, v); + return v; +} + +static uint64_t rt_flexcomm_read(void *opaque, hwaddr offset, + unsigned size) +{ + return rt_flexcomm_i2c_read(opaque, offset, size); +} + +static void rt_flexcomm_i2c_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + RTFLEXCOMMI2CState *s = (RTFLEXCOMMI2CState *)opaque; + uint32_t v32 = (uint32_t)value; + + printf("[FLEXCOMM_I2C]: write 0x%lx = 0x%lx\n", offset, value); + switch (offset) { + case 0x800: + s->I2C_CFG = v32; + if ((v32 & MSTEN_MASK) == MSTEN_MASK){ + /* set the pending bit */ + s->I2C_STAT |= MSTPENDING_MASK; + } else if((v32 & SLVEN_MASK) == SLVEN_MASK) { + /* set the pending bit */ + s->I2C_STAT |= SLVPENDING_MASK; + } + break; + case 0x804: + s->I2C_STAT &= ~v32; + break; + case 0x808: + s->I2C_INTENSET = v32; + break; + case 0x80C: + s->I2C_INTENSET &= ~v32; /* WOC */ + break; + case 0x810: + s->I2C_TIMEOUT = v32; + break; + case 0x814: + s->I2C_CLKDIV = v32; + break; + case 0x818: + break; + case 0x820: + s->I2C_MSTCTL = v32 & 0x80; + if ((v32 & MSTSTART_MASK) == MSTSTART_MASK) + { + /* clear the pending status */ + s->I2C_STAT &= ~MSTPENDING_MASK; + if (i2c_start_transfer(s->bus, s->I2C_MSTDAT, s->I2C_MSTDAT & 0x1)) + { + /* invalide address */ + uint32_t status = s->I2C_STAT; + + s->I2C_STAT = deposit32(status, MSTSTATE_OFFSET, MSTSTATE_LENGTH, MST_NAK_ADDR); + i2c_end_transfer(s->bus); + + } else { + if ((s->I2C_MSTDAT & 0x1) == 0x0) { + /* master recv*/ + s->I2C_MSTDAT = i2c_recv(s->bus); + } + } + /* set the pending bit */ + s->I2C_STAT |= MSTPENDING_MASK; + } else if ((v32 & MSTCONTINUE_MASK) == MSTCONTINUE_MASK) { + /* clear the pending status */ + s->I2C_STAT &= ~MSTPENDING_MASK; + s->I2C_STAT &= ~(MSTARBLOSS_MASK|MSTSTSTPERR_MASK); + if (i2c_send(s->bus, s->I2C_MSTDAT)) + { + /* no ack from slave */ + uint32_t status = s->I2C_STAT; + + s->I2C_STAT = deposit32(status, MSTSTATE_OFFSET, MSTSTATE_LENGTH, MST_NAK_DATA); + i2c_end_transfer(s->bus); + } + /* set the pending bit */ + s->I2C_STAT |= MSTPENDING_MASK; + } else if ((v32 & MSTSTOP_MASK) == MSTSTOP_MASK){ + i2c_end_transfer(s->bus); + } + break; + case 0x824: + s->I2C_MSTTIME = v32; + break; + case 0x828: + s->I2C_MSTDAT = v32; + break; + case 0x840: + s->I2C_SLVCTL = v32; + + break; + case 0x844: + s->I2C_SLVDAT = v32; + break; + case 0x848: + s->I2C_SLVADR0 = v32; + break; + case 0x84C: + s->I2C_SLVADR1 = v32; + break; + case 0x850: + s->I2C_SLVADR2 = v32; + break; + case 0x854: + s->I2C_SLVADR3 = v32; + break; + case 0x858: + s->I2C_SLVQUAL0 = v32; + break; + case 0x880: + break; + case 0xFF8: + s->PSELID = value; + break; + default: + return; + } +} + +static void rt_flexcomm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + RTFLEXCOMMI2CState *s = (RTFLEXCOMMI2CState *)opaque; + + rt_flexcomm_i2c_write(opaque, offset, value, size); + + rt_flexcomm_update(s); +} + +static const struct MemoryRegionOps rt_flexcomm_ops = { + .read = rt_flexcomm_read, + .write = rt_flexcomm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_flexcomm_realize(DeviceState *dev, Error **errp) +{ + RTFLEXCOMMI2CState *s = RT_FLEXCOMMI2C(dev); + + s->bus = i2c_init_bus(dev, "i2c-bus"); +} + +static void rt_flexcomm_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RTFLEXCOMMI2CState *s = RT_FLEXCOMMI2C(obj); + + memory_region_init_io(&s->iomem, obj, &rt_flexcomm_ops, s, + TYPE_RT_FLEXCOMMI2C, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static Property rt_flexcomm_i2c_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void rt_flexcomm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_flexcomm_realize; + dc->vmsd = &vmstate_rt_flexcomm; + dc->reset = rt_flexcomm_reset_at_boot; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + dc->desc = "RT FLEXCOMM I2C"; + device_class_set_props(dc, rt_flexcomm_i2c_properties); +} + +static const TypeInfo rt_flexcomm_info = { + .name = TYPE_RT_FLEXCOMMI2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTFLEXCOMMI2CState), + .instance_init = rt_flexcomm_init, + .class_init = rt_flexcomm_class_init, +}; + +static void rt_flexcomm_register_types(void) +{ + type_register_static(&rt_flexcomm_info); +} + +type_init(rt_flexcomm_register_types) diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 44dd5653b7f1..ee50ba1f2c3c 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -29,6 +29,7 @@ #include "hw/i386/ich9.h" #include "qom/object.h" +#include "hw/acpi/acpi_aml_interface.h" OBJECT_DECLARE_SIMPLE_TYPE(ICH9SMBState, ICH9_SMB_DEVICE) @@ -94,10 +95,22 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp) &s->smb.io); } +static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + BusChild *kid; + ICH9SMBState *s = ICH9_SMB_DEVICE(adev); + BusState *bus = BUS(s->smb.smbus); + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + call_dev_aml_func(DEVICE(kid->child), scope); + } +} + static void ich9_smb_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6; @@ -112,6 +125,7 @@ static void ich9_smb_class_init(ObjectClass *klass, void *data) * pc_q35_init() */ dc->user_creatable = false; + adevc->build_dev_aml = build_ich9_smb_aml; } static void ich9_smb_set_irq(PMSMBus *pmsmb, bool enabled) @@ -143,6 +157,7 @@ static const TypeInfo ich9_smb_info = { .class_init = ich9_smb_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { TYPE_ACPI_DEV_AML_IF }, { }, }, }; diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c index 5d10e27664db..feb3ec633350 100644 --- a/hw/i2c/smbus_slave.c +++ b/hw/i2c/smbus_slave.c @@ -143,6 +143,10 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) dev->mode = SMBUS_CONFUSED; break; } + break; + + default: + return -1; } return 0; diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 7d8907c1eede..52dbd53a234a 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -4,12 +4,19 @@ i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)" i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x" +i2c_send_async(uint8_t address, uint8_t data) "send_async(addr:0x%02x) data:0x%02x" i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x" +i2c_ack(void) "" + +# allwinner_i2c.c + +allwinner_i2c_read(const char* reg_name, uint64_t offset, uint64_t value) "read %s [0x%" PRIx64 "]: -> 0x%" PRIx64 +allwinner_i2c_write(const char* reg_name, uint64_t offset, uint64_t value) "write %s [0x%" PRIx64 "]: <- 0x%" PRIx64 # aspeed_i2c.c aspeed_i2c_bus_cmd(uint32_t cmd, const char *cmd_flags, uint32_t count, uint32_t intr_status) "handling cmd=0x%x %s count=%d intr=0x%x" -aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const char *str2, const char *str3, const char *str4, const char *str5) "handled intr=0x%x %s%s%s%s%s" +aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *s) "handled intr=0x%x %s" aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64 aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64 aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x" diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index d22ac4a4b952..c4fb5b49bd4c 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -51,7 +51,6 @@ config PC_PCI bool select APIC select IOAPIC - select APM select PC config PC_ACPI @@ -69,9 +68,9 @@ config I440FX imply E1000_PCI imply VMPORT imply VMMOUSE + select ACPI_PIIX4 select PC_PCI select PC_ACPI - select ACPI_SMBUS select PCI_I440FX select PIIX3 select IDE_PIIX diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index dcf6ece3d043..127c4e2d5044 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -27,24 +27,24 @@ #include "acpi-common.h" #include "qemu/bitmap.h" #include "qemu/error-report.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" +#include "hw/cxl/cxl.h" #include "hw/core/cpu.h" #include "target/i386/cpu.h" -#include "hw/misc/pvpanic.h" #include "hw/timer/hpet.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" #include "hw/acpi/cpu.h" #include "hw/nvram/fw_cfg.h" #include "hw/acpi/bios-linker-loader.h" -#include "hw/isa/isa.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/input/i8042.h" -#include "hw/block/fdc.h" #include "hw/acpi/memory_hotplug.h" #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "hw/acpi/vmgenid.h" #include "hw/acpi/erst.h" +#include "hw/acpi/piix4.h" #include "sysemu/tpm_backend.h" #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" @@ -60,21 +60,23 @@ #include "hw/i386/fw_cfg.h" #include "hw/i386/ich9.h" #include "hw/pci/pci_bus.h" +#include "hw/pci-host/i440fx.h" #include "hw/pci-host/q35.h" #include "hw/i386/x86-iommu.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/utils.h" #include "hw/acpi/pci.h" +#include "hw/acpi/cxl.h" #include "qom/qom-qobject.h" #include "hw/i386/amd_iommu.h" #include "hw/i386/intel_iommu.h" #include "hw/virtio/virtio-iommu.h" -#include "hw/acpi/ipmi.h" #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" +#include "hw/acpi/cxl.h" #include CONFIG_DEVICES @@ -111,24 +113,14 @@ typedef struct AcpiPmInfo { } AcpiPmInfo; typedef struct AcpiMiscInfo { - bool is_piix4; bool has_hpet; #ifdef CONFIG_TPM TPMVersion tpm_version; #endif const unsigned char *dsdt_code; unsigned dsdt_size; - uint16_t pvpanic_port; - uint16_t applesmc_io_base; } AcpiMiscInfo; -typedef struct AcpiBuildPciBusHotplugState { - GArray *device_table; - GArray *notify_table; - struct AcpiBuildPciBusHotplugState *parent; - bool pcihp_bridge_en; -} AcpiBuildPciBusHotplugState; - typedef struct FwCfgTPMConfig { uint32_t tpmppi_address; uint8_t tpm_version; @@ -289,23 +281,10 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) static void acpi_get_misc_info(AcpiMiscInfo *info) { - Object *piix = object_resolve_type_unambiguous(TYPE_PIIX4_PM); - Object *lpc = object_resolve_type_unambiguous(TYPE_ICH9_LPC_DEVICE); - assert(!!piix != !!lpc); - - if (piix) { - info->is_piix4 = true; - } - if (lpc) { - info->is_piix4 = false; - } - info->has_hpet = hpet_find(); #ifdef CONFIG_TPM info->tpm_version = tpm_get_version(tpm_find()); #endif - info->pvpanic_port = pvpanic_port(); - info->applesmc_io_base = applesmc_port(); } /* @@ -377,6 +356,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; @@ -405,19 +403,40 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { DeviceClass *dc; - PCIDeviceClass *pc; PCIDevice *pdev = bus->devices[devfn]; int slot = PCI_SLOT(devfn); 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; + + if (pdev) { + dc = DEVICE_GET_CLASS(pdev); - 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 = IS_PCI_BRIDGE(pdev) && + !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, and for other + * functions if device on function provides its own AML + */ + if (func && !bridge_in_acpi && !get_dev_aml_func(DEVICE(pdev))) { + continue; + } + } else { + /* * hotplug is supported only for non-multifunction device * so generate device description only for function 0 */ @@ -425,51 +444,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 */ @@ -482,36 +461,23 @@ 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) { - /* add VGA specific AML methods */ - int s3d; + call_dev_aml_func(DEVICE(pdev), dev); - if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) { - s3d = 3; - } else { - s3d = 0; - } - - method = aml_method("_S1D", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(0))); - aml_append(dev, method); + bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; + if (bridge_in_acpi) { + /* + * device is coldplugged bridge, + * add child device descriptions into its scope + */ + PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); - method = aml_method("_S2D", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(0))); - aml_append(dev, method); + build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); + } - method = aml_method("_S3D", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(s3d))); - aml_append(dev, method); - } else if (hotplug_enabled_dev) { + 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); @@ -520,18 +486,9 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, ); aml_append(dev, method); - if (bsel) { - build_append_pcihp_notify_entry(notify_method, slot); - } - } else if (bridge_in_acpi) { - /* - * device is coldplugged bridge, - * add child device descriptions into its scope - */ - PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); - - build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); + build_append_pcihp_notify_entry(notify_method, slot); } + /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); } @@ -575,84 +532,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); - - 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(pkg, zero); + /* + * optional, if not impl. should return null string + */ + aml_append(pkg, aml_string("%s", "")); + aml_append(ifctx, aml_store(pkg, ret)); + + 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; } @@ -862,21 +835,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) return dev; } -static void build_isa_devices_aml(Aml *table) -{ - bool ambiguous; - Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); - Aml *scope; - - assert(obj && !ambiguous); - - scope = aml_scope("_SB.PCI0.ISA"); - build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA"); - isa_build_aml(ISA_BUS(obj), scope); - - aml_append(table, scope); -} - static void build_dbg_aml(Aml *table) { Aml *field; @@ -1026,7 +984,6 @@ static void build_piix4_pci0_int(Aml *table) { Aml *dev; Aml *crs; - Aml *field; Aml *method; uint32_t irqs; Aml *sb_scope = aml_scope("_SB"); @@ -1035,13 +992,6 @@ static void build_piix4_pci0_int(Aml *table) aml_append(pci0_scope, build_prt(true)); aml_append(sb_scope, pci0_scope); - field = aml_field("PCI0.ISA.P40C", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("PRQ0", 8)); - aml_append(field, aml_named_field("PRQ1", 8)); - aml_append(field, aml_named_field("PRQ2", 8)); - aml_append(field, aml_named_field("PRQ3", 8)); - aml_append(sb_scope, field); - aml_append(sb_scope, build_irq_status_method()); aml_append(sb_scope, build_iqcr_method(true)); @@ -1145,7 +1095,6 @@ static Aml *build_q35_routing_table(const char *str) static void build_q35_pci0_int(Aml *table) { - Aml *field; Aml *method; Aml *sb_scope = aml_scope("_SB"); Aml *pci0_scope = aml_scope("PCI0"); @@ -1182,18 +1131,6 @@ static void build_q35_pci0_int(Aml *table) aml_append(pci0_scope, method); aml_append(sb_scope, pci0_scope); - field = aml_field("PCI0.ISA.PIRQ", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("PRQA", 8)); - aml_append(field, aml_named_field("PRQB", 8)); - aml_append(field, aml_named_field("PRQC", 8)); - aml_append(field, aml_named_field("PRQD", 8)); - aml_append(field, aml_reserved_field(0x20)); - aml_append(field, aml_named_field("PRQE", 8)); - aml_append(field, aml_named_field("PRQF", 8)); - aml_append(field, aml_named_field("PRQG", 8)); - aml_append(field, aml_named_field("PRQH", 8)); - aml_append(sb_scope, field); - aml_append(sb_scope, build_irq_status_method()); aml_append(sb_scope, build_iqcr_method(false)); @@ -1258,40 +1195,6 @@ static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg) return dev; } -static void build_q35_isa_bridge(Aml *table) -{ - Aml *dev; - Aml *scope; - - scope = aml_scope("_SB.PCI0"); - dev = aml_device("ISA"); - aml_append(dev, aml_name_decl("_ADR", aml_int(0x001F0000))); - - /* ICH9 PCI to ISA irq remapping */ - aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG, - aml_int(0x60), 0x0C)); - - aml_append(scope, dev); - aml_append(table, scope); -} - -static void build_piix4_isa_bridge(Aml *table) -{ - Aml *dev; - Aml *scope; - - scope = aml_scope("_SB.PCI0"); - dev = aml_device("ISA"); - aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010000))); - - /* PIIX PCI to ISA irq remapping */ - aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG, - aml_int(0x60), 0x04)); - - aml_append(scope, dev); - aml_append(table, scope); -} - static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) { Aml *scope; @@ -1343,7 +1246,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); } @@ -1398,13 +1301,18 @@ static Aml *build_q35_osc_method(bool enable_native_pcie_hotplug) return method; } -static void build_smb0(Aml *table, I2CBus *smbus, int devnr, int func) +static void build_acpi0017(Aml *table) { - Aml *scope = aml_scope("_SB.PCI0"); - Aml *dev = aml_device("SMB0"); + Aml *dev, *scope, *method; + + scope = aml_scope("_SB"); + dev = aml_device("CXLM"); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0017"))); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0x01))); + aml_append(dev, method); - aml_append(dev, aml_name_decl("_ADR", aml_int(devnr << 16 | func))); - build_acpi_ipmi_devices(dev, BUS(smbus), "\\_SB.PCI0.SMB0"); aml_append(scope, dev); aml_append(table, scope); } @@ -1414,6 +1322,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc, Range *pci_hole, Range *pci_hole64, MachineState *machine) { + Object *i440fx = object_resolve_type_unambiguous(TYPE_I440FX_PCI_HOST_BRIDGE); + Object *q35 = object_resolve_type_unambiguous(TYPE_Q35_HOST_DEVICE); CrsRangeEntry *entry; Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs; CrsRangeSet crs_range_set; @@ -1428,16 +1338,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, #ifdef CONFIG_TPM TPMIf *tpm = tpm_find(); #endif + bool cxl_present = false; int i; VMBusBridge *vmbus_bridge = vmbus_bridge_find(); AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = x86ms->oem_id, .oem_table_id = x86ms->oem_table_id }; + assert(!!i440fx != !!q35); + acpi_table_begin(&table, table_data); dsdt = init_aml_allocator(); build_dbg_aml(dsdt); - if (misc->is_piix4) { + if (i440fx) { sb_scope = aml_scope("_SB"); dev = aml_device("PCI0"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); @@ -1446,16 +1359,11 @@ 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); - build_isa_devices_aml(dsdt); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); } build_piix4_pci0_int(dsdt); - } else { + } else if (q35) { sb_scope = aml_scope("_SB"); dev = aml_device("PCI0"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); @@ -1495,18 +1403,14 @@ 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); - build_isa_devices_aml(dsdt); if (pm->pcihp_bridge_en) { build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); } build_q35_pci0_int(dsdt); - if (pcms->smbus && !pcmc->do_not_add_smb_acpi) { - build_smb0(dsdt, pcms->smbus, ICH9_SMB_DEV, ICH9_SMB_FUNC); - } + } + + if (misc->has_hpet) { + build_hpet_aml(dsdt); } if (vmbus_bridge) { @@ -1515,6 +1419,18 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); } + scope = aml_scope("_GPE"); + { + aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); + if (machine->nvdimms_state->is_enabled) { + method = aml_method("_E04", 0, AML_NOTSERIALIZED); + aml_append(method, aml_notify(aml_name("\\_SB.NVDR"), + aml_int(0x80))); + aml_append(scope, method); + } + } + aml_append(dsdt, scope); + if (pcmc->legacy_cpu_hotplug) { build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base); } else { @@ -1533,28 +1449,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, pcms->memhp_io_base); } - scope = aml_scope("_GPE"); - { - aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); - - if (pm->pcihp_bridge_en || pm->pcihp_root_en) { - method = aml_method("_E01", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); - aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); - aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); - aml_append(scope, method); - } - - if (machine->nvdimms_state->is_enabled) { - method = aml_method("_E04", 0, AML_NOTSERIALIZED); - aml_append(method, aml_notify(aml_name("\\_SB.NVDR"), - aml_int(0x80))); - aml_append(scope, method); - } - } - aml_append(dsdt, scope); - crs_range_set_init(&crs_range_set); bus = PC_MACHINE(machine)->bus; if (bus) { @@ -1572,10 +1466,25 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } scope = aml_scope("\\_SB"); - dev = aml_device("PC%.02X", bus_num); + + if (pci_bus_is_cxl(bus)) { + dev = aml_device("CL%.02X", bus_num); + } else { + dev = aml_device("PC%.02X", bus_num); + } aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); - if (pci_bus_is_express(bus)) { + if (pci_bus_is_cxl(bus)) { + struct Aml *pkg = aml_package(2); + + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0016"))); + aml_append(pkg, aml_eisaid("PNP0A08")); + aml_append(pkg, aml_eisaid("PNP0A03")); + aml_append(dev, aml_name_decl("_CID", pkg)); + aml_append(dev, aml_name_decl("_ADR", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); + build_cxl_osc_method(dev); + } else if (pci_bus_is_express(bus)) { aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); @@ -1595,9 +1504,23 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); aml_append(dsdt, scope); + + /* Handle the ranges for the PXB expanders */ + if (pci_bus_is_cxl(bus)) { + MemoryRegion *mr = &pcms->cxl_devices_state.host_mr; + uint64_t base = mr->addr; + + cxl_present = true; + crs_range_insert(crs_range_set.mem_ranges, base, + base + memory_region_size(mr) - 1); + } } } + if (cxl_present) { + build_acpi0017(dsdt); + } + /* * At this point crs_range_set has all the ranges used by pci * busses *other* than PCI0. These ranges will be excluded from @@ -1747,110 +1670,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, scope); } - if (misc->applesmc_io_base) { - scope = aml_scope("\\_SB.PCI0.ISA"); - dev = aml_device("SMC"); - - aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0001"))); - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, misc->applesmc_io_base, misc->applesmc_io_base, - 0x01, APPLESMC_MAX_DATA_LENGTH) - ); - aml_append(crs, aml_irq_no_flags(6)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - aml_append(scope, dev); - aml_append(dsdt, scope); - } - - if (misc->pvpanic_port) { - scope = aml_scope("\\_SB.PCI0.ISA"); - - dev = aml_device("PEVT"); - aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001"))); - - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, misc->pvpanic_port, misc->pvpanic_port, 1, 1) - ); - aml_append(dev, aml_name_decl("_CRS", crs)); - - aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO, - aml_int(misc->pvpanic_port), 1)); - field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("PEPT", 8)); - aml_append(dev, field); - - /* device present, functioning, decoding, shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); - - method = aml_method("RDPT", 0, AML_NOTSERIALIZED); - aml_append(method, aml_store(aml_name("PEPT"), aml_local(0))); - aml_append(method, aml_return(aml_local(0))); - aml_append(dev, method); - - method = aml_method("WRPT", 1, AML_NOTSERIALIZED); - aml_append(method, aml_store(aml_arg(0), aml_name("PEPT"))); - aml_append(dev, method); - - aml_append(scope, dev); - aml_append(dsdt, scope); - } - sb_scope = aml_scope("\\_SB"); { - Object *pci_host; - PCIBus *bus = NULL; - - pci_host = acpi_get_i386_pci_host(); + Object *pci_host = acpi_get_i386_pci_host(); if (pci_host) { - bus = PCI_HOST_BRIDGE(pci_host)->bus; - } - - if (bus) { + PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; Aml *scope = aml_scope("PCI0"); /* Scan all PCI buses. Generate tables to support hotplug. */ build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); - -#ifdef CONFIG_TPM - if (TPM_IS_TIS_ISA(tpm)) { - if (misc->tpm_version == TPM_VERSION_2_0) { - dev = aml_device("TPM"); - aml_append(dev, aml_name_decl("_HID", - aml_string("MSFT0101"))); - aml_append(dev, - aml_name_decl("_STR", - aml_string("TPM 2.0 Device"))); - } else { - dev = aml_device("ISA.TPM"); - aml_append(dev, aml_name_decl("_HID", - aml_eisaid("PNP0C31"))); - } - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - - aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); - crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, - TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); - /* - FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs, - Rewrite to take IRQ from TPM device model and - fix default IRQ value there to use some unused IRQ - */ - /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */ - aml_append(dev, aml_name_decl("_CRS", crs)); - - tpm_build_ppi_acpi(tpm, dev); - - aml_append(scope, dev); - } -#endif - aml_append(sb_scope, scope); } } @@ -1899,6 +1727,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } aml_append(dsdt, sb_scope); + if (pm->pcihp_bridge_en || pm->pcihp_root_en) { + scope = aml_scope("_GPE"); + { + method = aml_method("_E01", 0, AML_NOTSERIALIZED); + aml_append(method, + aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); + aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); + aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + aml_append(scope, method); + } + aml_append(dsdt, scope); + } + /* copy AML table into ACPI tables blob and patch header there */ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); acpi_table_end(linker, &table); @@ -2071,7 +1912,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; } @@ -2662,6 +2503,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) machine->nvdimms_state, machine->ram_slots, x86ms->oem_id, x86ms->oem_table_id); } + if (pcms->cxl_devices_state.is_enabled) { + cxl_build_cedt(table_offsets, tables_blob, tables->linker, + x86ms->oem_id, x86ms->oem_table_id, &pcms->cxl_devices_state); + } acpi_add_table(table_offsets, tables_blob); build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id); diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index ea8eaeb330b6..bcd016f5c5a5 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -201,15 +201,18 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start, /* * AMDVi event structure * 0:15 -> DeviceID - * 55:63 -> event type + miscellaneous info - * 63:127 -> related address + * 48:63 -> event type + miscellaneous info + * 64:127 -> related address */ static void amdvi_encode_event(uint64_t *evt, uint16_t devid, uint64_t addr, uint16_t info) { + evt[0] = 0; + evt[1] = 0; + amdvi_setevent_bits(evt, devid, 0, 16); - amdvi_setevent_bits(evt, info, 55, 8); - amdvi_setevent_bits(evt, addr, 63, 64); + amdvi_setevent_bits(evt, info, 48, 16); + amdvi_setevent_bits(evt, addr, 64, 64); } /* log an error encountered during a page walk * @@ -218,7 +221,7 @@ static void amdvi_encode_event(uint64_t *evt, uint16_t devid, uint64_t addr, static void amdvi_page_fault(AMDVIState *s, uint16_t devid, hwaddr addr, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_IOPF_I | AMDVI_EVENT_IOPF; amdvi_encode_event(evt, devid, addr, info); @@ -234,7 +237,7 @@ static void amdvi_page_fault(AMDVIState *s, uint16_t devid, static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid, hwaddr devtab, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_DEV_TAB_HW_ERROR; @@ -248,7 +251,8 @@ static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid, */ static void amdvi_log_command_error(AMDVIState *s, hwaddr addr) { - uint64_t evt[4], info = AMDVI_EVENT_COMMAND_HW_ERROR; + uint64_t evt[2]; + uint16_t info = AMDVI_EVENT_COMMAND_HW_ERROR; amdvi_encode_event(evt, 0, addr, info); amdvi_log_event(s, evt); @@ -261,7 +265,7 @@ static void amdvi_log_command_error(AMDVIState *s, hwaddr addr) static void amdvi_log_illegalcom_error(AMDVIState *s, uint16_t info, hwaddr addr) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_ILLEGAL_COMMAND_ERROR; amdvi_encode_event(evt, 0, addr, info); @@ -276,7 +280,7 @@ static void amdvi_log_illegalcom_error(AMDVIState *s, uint16_t info, static void amdvi_log_illegaldevtab_error(AMDVIState *s, uint16_t devid, hwaddr addr, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY; amdvi_encode_event(evt, devid, addr, info); @@ -288,7 +292,7 @@ static void amdvi_log_illegaldevtab_error(AMDVIState *s, uint16_t devid, static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid, hwaddr addr, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_PAGE_TAB_HW_ERROR; amdvi_encode_event(evt, devid, addr, info); @@ -1364,7 +1368,7 @@ static MemTxResult amdvi_mem_ir_write(void *opaque, hwaddr addr, return MEMTX_ERROR; } - apic_get_class()->send_msi(&to); + apic_get_class(NULL)->send_msi(&to); trace_amdvi_mem_ir_write(to.address, to.data); return MEMTX_OK; diff --git a/hw/i386/e820_memory_layout.c b/hw/i386/e820_memory_layout.c index bcf9eaf83762..06970ac44a2e 100644 --- a/hw/i386/e820_memory_layout.c +++ b/hw/i386/e820_memory_layout.c @@ -11,29 +11,11 @@ #include "e820_memory_layout.h" static size_t e820_entries; -struct e820_table e820_reserve; struct e820_entry *e820_table; int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) { - int index = le32_to_cpu(e820_reserve.count); - struct e820_entry *entry; - - if (type != E820_RAM) { - /* old FW_CFG_E820_TABLE entry -- reservations only */ - if (index >= E820_NR_ENTRIES) { - return -EBUSY; - } - entry = &e820_reserve.entry[index++]; - - entry->address = cpu_to_le64(address); - entry->length = cpu_to_le64(length); - entry->type = cpu_to_le32(type); - - e820_reserve.count = cpu_to_le32(index); - } - - /* new "etc/e820" file -- include ram too */ + /* new "etc/e820" file -- include ram and reserved entries */ e820_table = g_renew(struct e820_entry, e820_table, e820_entries + 1); e820_table[e820_entries].address = cpu_to_le64(address); e820_table[e820_entries].length = cpu_to_le64(length); diff --git a/hw/i386/e820_memory_layout.h b/hw/i386/e820_memory_layout.h index 2a0ceb8b9cc1..7c239aa033f5 100644 --- a/hw/i386/e820_memory_layout.h +++ b/hw/i386/e820_memory_layout.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: MIT */ -#ifndef HW_I386_E820_H -#define HW_I386_E820_H +#ifndef HW_I386_E820_MEMORY_LAYOUT_H +#define HW_I386_E820_MEMORY_LAYOUT_H /* e820 types */ #define E820_RAM 1 @@ -16,20 +16,12 @@ #define E820_NVS 4 #define E820_UNUSABLE 5 -#define E820_NR_ENTRIES 16 - struct e820_entry { uint64_t address; uint64_t length; uint32_t type; } QEMU_PACKED __attribute((__aligned__(4))); -struct e820_table { - uint32_t count; - struct e820_entry entry[E820_NR_ENTRIES]; -} QEMU_PACKED __attribute((__aligned__(4))); - -extern struct e820_table e820_reserve; extern struct e820_entry *e820_table; int e820_add_entry(uint64_t address, uint64_t length, uint32_t type); diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c index a283785a8de4..72a42f3c66d2 100644 --- a/hw/i386/fw_cfg.c +++ b/hw/i386/fw_cfg.c @@ -36,7 +36,6 @@ const char *fw_cfg_arch_key_name(uint16_t key) {FW_CFG_ACPI_TABLES, "acpi_tables"}, {FW_CFG_SMBIOS_ENTRIES, "smbios_entries"}, {FW_CFG_IRQ0_OVERRIDE, "irq0_override"}, - {FW_CFG_E820_TABLE, "e820_table"}, {FW_CFG_HPET, "hpet"}, }; @@ -127,8 +126,6 @@ FWCfgState *fw_cfg_arch_create(MachineState *ms, #endif fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, 1); - fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, - &e820_reserve, sizeof(e820_reserve)); fw_cfg_add_file(fw_cfg, "etc/e820", e820_table, sizeof(struct e820_entry) * e820_get_num_entries()); diff --git a/hw/i386/fw_cfg.h b/hw/i386/fw_cfg.h index 275f15c1c5e8..86ca7c1c0cba 100644 --- a/hw/i386/fw_cfg.h +++ b/hw/i386/fw_cfg.h @@ -17,7 +17,6 @@ #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) -#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) #define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4) FWCfgState *fw_cfg_arch_create(MachineState *ms, diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c64aa81a83fc..98a5c304a7d7 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -49,17 +49,24 @@ /* pe operations */ #define VTD_PE_GET_TYPE(pe) ((pe)->val[0] & VTD_SM_PASID_ENTRY_PGTT) #define VTD_PE_GET_LEVEL(pe) (2 + (((pe)->val[0] >> 2) & VTD_SM_PASID_ENTRY_AW)) -#define VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write) {\ - if (ret_fr) { \ - ret_fr = -ret_fr; \ - if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) { \ - trace_vtd_fault_disabled(); \ - } else { \ - vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write); \ - } \ - goto error; \ - } \ -} + +/* + * PCI bus number (or SID) is not reliable since the device is usaully + * initalized before guest can configure the PCI bridge + * (SECONDARY_BUS_NUMBER). + */ +struct vtd_as_key { + PCIBus *bus; + uint8_t devfn; + uint32_t pasid; +}; + +struct vtd_iotlb_key { + uint64_t gfn; + uint32_t pasid; + uint32_t level; + uint16_t sid; +}; static void vtd_address_space_refresh_all(IntelIOMMUState *s); static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n); @@ -181,6 +188,18 @@ static void vtd_update_scalable_state(IntelIOMMUState *s) } } +static void vtd_update_iq_dw(IntelIOMMUState *s) +{ + uint64_t val = vtd_get_quad_raw(s, DMAR_IQA_REG); + + if (s->ecap & VTD_ECAP_SMTS && + val & VTD_IQA_DW_MASK) { + s->iq_dw = true; + } else { + s->iq_dw = false; + } +} + /* Whether the address space needs to notify new mappings */ static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as) { @@ -188,14 +207,46 @@ static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as) } /* GHashTable functions */ -static gboolean vtd_uint64_equal(gconstpointer v1, gconstpointer v2) +static gboolean vtd_iotlb_equal(gconstpointer v1, gconstpointer v2) +{ + const struct vtd_iotlb_key *key1 = v1; + const struct vtd_iotlb_key *key2 = v2; + + return key1->sid == key2->sid && + key1->pasid == key2->pasid && + key1->level == key2->level && + key1->gfn == key2->gfn; +} + +static guint vtd_iotlb_hash(gconstpointer v) { - return *((const uint64_t *)v1) == *((const uint64_t *)v2); + const struct vtd_iotlb_key *key = v; + + return key->gfn | ((key->sid) << VTD_IOTLB_SID_SHIFT) | + (key->level) << VTD_IOTLB_LVL_SHIFT | + (key->pasid) << VTD_IOTLB_PASID_SHIFT; } -static guint vtd_uint64_hash(gconstpointer v) +static gboolean vtd_as_equal(gconstpointer v1, gconstpointer v2) { - return (guint)*(const uint64_t *)v; + const struct vtd_as_key *key1 = v1; + const struct vtd_as_key *key2 = v2; + + return (key1->bus == key2->bus) && (key1->devfn == key2->devfn) && + (key1->pasid == key2->pasid); +} + +/* + * Note that we use pointer to PCIBus as the key, so hashing/shifting + * based on the pointer value is intended. Note that we deal with + * collisions through vtd_as_equal(). + */ +static guint vtd_as_hash(gconstpointer v) +{ + const struct vtd_as_key *key = v; + guint value = (guint)(uintptr_t)key->bus; + + return (guint)(value << 8 | key->devfn); } static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value, @@ -236,22 +287,14 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value, static void vtd_reset_context_cache_locked(IntelIOMMUState *s) { VTDAddressSpace *vtd_as; - VTDBus *vtd_bus; - GHashTableIter bus_it; - uint32_t devfn_it; + GHashTableIter as_it; trace_vtd_context_cache_reset(); - g_hash_table_iter_init(&bus_it, s->vtd_as_by_busptr); + g_hash_table_iter_init(&as_it, s->vtd_address_spaces); - while (g_hash_table_iter_next (&bus_it, NULL, (void**)&vtd_bus)) { - for (devfn_it = 0; devfn_it < PCI_DEVFN_MAX; ++devfn_it) { - vtd_as = vtd_bus->dev_as[devfn_it]; - if (!vtd_as) { - continue; - } - vtd_as->context_cache_entry.context_cache_gen = 0; - } + while (g_hash_table_iter_next(&as_it, NULL, (void **)&vtd_as)) { + vtd_as->context_cache_entry.context_cache_gen = 0; } s->context_cache_gen = 1; } @@ -278,13 +321,6 @@ static void vtd_reset_caches(IntelIOMMUState *s) vtd_iommu_unlock(s); } -static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint16_t source_id, - uint32_t level) -{ - return gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT) | - ((uint64_t)(level) << VTD_IOTLB_LVL_SHIFT); -} - static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level) { return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K; @@ -292,15 +328,17 @@ static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level) /* Must be called with IOMMU lock held */ static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id, - hwaddr addr) + uint32_t pasid, hwaddr addr) { + struct vtd_iotlb_key key; VTDIOTLBEntry *entry; - uint64_t key; int level; for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) { - key = vtd_get_iotlb_key(vtd_get_iotlb_gfn(addr, level), - source_id, level); + key.gfn = vtd_get_iotlb_gfn(addr, level); + key.level = level; + key.sid = source_id; + key.pasid = pasid; entry = g_hash_table_lookup(s->iotlb, &key); if (entry) { goto out; @@ -314,10 +352,11 @@ static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id, /* Must be with IOMMU lock held */ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, uint16_t domain_id, hwaddr addr, uint64_t slpte, - uint8_t access_flags, uint32_t level) + uint8_t access_flags, uint32_t level, + uint32_t pasid) { VTDIOTLBEntry *entry = g_malloc(sizeof(*entry)); - uint64_t *key = g_malloc(sizeof(*key)); + struct vtd_iotlb_key *key = g_malloc(sizeof(*key)); uint64_t gfn = vtd_get_iotlb_gfn(addr, level); trace_vtd_iotlb_page_update(source_id, addr, slpte, domain_id); @@ -331,7 +370,13 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, entry->slpte = slpte; entry->access_flags = access_flags; entry->mask = vtd_slpt_level_page_mask(level); - *key = vtd_get_iotlb_key(gfn, source_id, level); + entry->pasid = pasid; + + key->gfn = gfn; + key->sid = source_id; + key->level = level; + key->pasid = pasid; + g_hash_table_replace(s->iotlb, key, entry); } @@ -351,7 +396,7 @@ static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg, trace_vtd_irq_generate(msi.address, msi.data); - apic_get_class()->send_msi(&msi); + apic_get_class(NULL)->send_msi(&msi); } /* Generate a fault event to software via MSI if conditions are met. @@ -424,7 +469,8 @@ static void vtd_set_frcd_and_update_ppf(IntelIOMMUState *s, uint16_t index) /* Must not update F field now, should be done later */ static void vtd_record_frcd(IntelIOMMUState *s, uint16_t index, uint16_t source_id, hwaddr addr, - VTDFaultReason fault, bool is_write) + VTDFaultReason fault, bool is_write, + bool is_pasid, uint32_t pasid) { uint64_t hi = 0, lo; hwaddr frcd_reg_addr = DMAR_FRCD_REG_OFFSET + (((uint64_t)index) << 4); @@ -432,7 +478,8 @@ static void vtd_record_frcd(IntelIOMMUState *s, uint16_t index, assert(index < DMAR_FRCD_REG_NR); lo = VTD_FRCD_FI(addr); - hi = VTD_FRCD_SID(source_id) | VTD_FRCD_FR(fault); + hi = VTD_FRCD_SID(source_id) | VTD_FRCD_FR(fault) | + VTD_FRCD_PV(pasid) | VTD_FRCD_PP(is_pasid); if (!is_write) { hi |= VTD_FRCD_T; } @@ -463,17 +510,13 @@ static bool vtd_try_collapse_fault(IntelIOMMUState *s, uint16_t source_id) /* Log and report an DMAR (address translation) fault to software */ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, hwaddr addr, VTDFaultReason fault, - bool is_write) + bool is_write, bool is_pasid, + uint32_t pasid) { uint32_t fsts_reg = vtd_get_long_raw(s, DMAR_FSTS_REG); assert(fault < VTD_FR_MAX); - if (fault == VTD_FR_RESERVED_ERR) { - /* This is not a normal fault reason case. Drop it. */ - return; - } - trace_vtd_dmar_fault(source_id, fault, addr, is_write); if (fsts_reg & VTD_FSTS_PFO) { @@ -495,7 +538,8 @@ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, return; } - vtd_record_frcd(s, s->next_frcd_reg, source_id, addr, fault, is_write); + vtd_record_frcd(s, s->next_frcd_reg, source_id, addr, fault, + is_write, is_pasid, pasid); if (fsts_reg & VTD_FSTS_PPF) { error_report_once("There are pending faults already, " @@ -800,13 +844,15 @@ static int vtd_get_pe_from_pasid_table(IntelIOMMUState *s, static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s, VTDContextEntry *ce, - VTDPASIDEntry *pe) + VTDPASIDEntry *pe, + uint32_t pasid) { - uint32_t pasid; dma_addr_t pasid_dir_base; int ret = 0; - pasid = VTD_CE_GET_RID2PASID(ce); + if (pasid == PCI_NO_PASID) { + pasid = VTD_CE_GET_RID2PASID(ce); + } pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce); ret = vtd_get_pe_from_pasid_table(s, pasid_dir_base, pasid, pe); @@ -815,15 +861,17 @@ static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s, static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s, VTDContextEntry *ce, - bool *pe_fpd_set) + bool *pe_fpd_set, + uint32_t pasid) { int ret; - uint32_t pasid; dma_addr_t pasid_dir_base; VTDPASIDDirEntry pdire; VTDPASIDEntry pe; - pasid = VTD_CE_GET_RID2PASID(ce); + if (pasid == PCI_NO_PASID) { + pasid = VTD_CE_GET_RID2PASID(ce); + } pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce); /* @@ -869,12 +917,13 @@ static inline uint32_t vtd_ce_get_level(VTDContextEntry *ce) } static uint32_t vtd_get_iova_level(IntelIOMMUState *s, - VTDContextEntry *ce) + VTDContextEntry *ce, + uint32_t pasid) { VTDPASIDEntry pe; if (s->root_scalable) { - vtd_ce_get_rid2pasid_entry(s, ce, &pe); + vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid); return VTD_PE_GET_LEVEL(&pe); } @@ -887,12 +936,13 @@ static inline uint32_t vtd_ce_get_agaw(VTDContextEntry *ce) } static uint32_t vtd_get_iova_agaw(IntelIOMMUState *s, - VTDContextEntry *ce) + VTDContextEntry *ce, + uint32_t pasid) { VTDPASIDEntry pe; if (s->root_scalable) { - vtd_ce_get_rid2pasid_entry(s, ce, &pe); + vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid); return 30 + ((pe.val[0] >> 2) & VTD_SM_PASID_ENTRY_AW) * 9; } @@ -934,31 +984,33 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu, } static inline uint64_t vtd_iova_limit(IntelIOMMUState *s, - VTDContextEntry *ce, uint8_t aw) + VTDContextEntry *ce, uint8_t aw, + uint32_t pasid) { - uint32_t ce_agaw = vtd_get_iova_agaw(s, ce); + uint32_t ce_agaw = vtd_get_iova_agaw(s, ce, pasid); return 1ULL << MIN(ce_agaw, aw); } /* Return true if IOVA passes range check, otherwise false. */ static inline bool vtd_iova_range_check(IntelIOMMUState *s, uint64_t iova, VTDContextEntry *ce, - uint8_t aw) + uint8_t aw, uint32_t pasid) { /* * Check if @iova is above 2^X-1, where X is the minimum of MGAW * in CAP_REG and AW in context-entry. */ - return !(iova & ~(vtd_iova_limit(s, ce, aw) - 1)); + return !(iova & ~(vtd_iova_limit(s, ce, aw, pasid) - 1)); } static dma_addr_t vtd_get_iova_pgtbl_base(IntelIOMMUState *s, - VTDContextEntry *ce) + VTDContextEntry *ce, + uint32_t pasid) { VTDPASIDEntry pe; if (s->root_scalable) { - vtd_ce_get_rid2pasid_entry(s, ce, &pe); + vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid); return pe.val[0] & VTD_SM_PASID_ENTRY_SLPTPTR; } @@ -986,49 +1038,25 @@ static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level) return slpte & rsvd_mask; } -/* Find the VTD address space associated with a given bus number */ -static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num) -{ - VTDBus *vtd_bus = s->vtd_as_by_bus_num[bus_num]; - GHashTableIter iter; - - if (vtd_bus) { - return vtd_bus; - } - - /* - * Iterate over the registered buses to find the one which - * currently holds this bus number and update the bus_num - * lookup table. - */ - g_hash_table_iter_init(&iter, s->vtd_as_by_busptr); - while (g_hash_table_iter_next(&iter, NULL, (void **)&vtd_bus)) { - if (pci_bus_num(vtd_bus->bus) == bus_num) { - s->vtd_as_by_bus_num[bus_num] = vtd_bus; - return vtd_bus; - } - } - - return NULL; -} - /* Given the @iova, get relevant @slptep. @slpte_level will be the last level * of the translation, can be used for deciding the size of large page. */ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce, uint64_t iova, bool is_write, uint64_t *slptep, uint32_t *slpte_level, - bool *reads, bool *writes, uint8_t aw_bits) + bool *reads, bool *writes, uint8_t aw_bits, + uint32_t pasid) { - dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce); - uint32_t level = vtd_get_iova_level(s, ce); + dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid); + uint32_t level = vtd_get_iova_level(s, ce, pasid); uint32_t offset; uint64_t slpte; uint64_t access_right_check; + uint64_t xlat, size; - if (!vtd_iova_range_check(s, iova, ce, aw_bits)) { - error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ")", - __func__, iova); + if (!vtd_iova_range_check(s, iova, ce, aw_bits, pasid)) { + error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 "," + "pasid=0x%" PRIx32 ")", __func__, iova, pasid); return -VTD_FR_ADDR_BEYOND_MGAW; } @@ -1041,8 +1069,9 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce, if (slpte == (uint64_t)-1) { error_report_once("%s: detected read error on DMAR slpte " - "(iova=0x%" PRIx64 ")", __func__, iova); - if (level == vtd_get_iova_level(s, ce)) { + "(iova=0x%" PRIx64 ", pasid=0x%" PRIx32 ")", + __func__, iova, pasid); + if (level == vtd_get_iova_level(s, ce, pasid)) { /* Invalid programming of context-entry */ return -VTD_FR_CONTEXT_ENTRY_INV; } else { @@ -1054,26 +1083,50 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce, if (!(slpte & access_right_check)) { error_report_once("%s: detected slpte permission error " "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", " - "slpte=0x%" PRIx64 ", write=%d)", __func__, - iova, level, slpte, is_write); + "slpte=0x%" PRIx64 ", write=%d, pasid=0x%" + PRIx32 ")", __func__, iova, level, + slpte, is_write, pasid); return is_write ? -VTD_FR_WRITE : -VTD_FR_READ; } if (vtd_slpte_nonzero_rsvd(slpte, level)) { error_report_once("%s: detected splte reserve non-zero " "iova=0x%" PRIx64 ", level=0x%" PRIx32 - "slpte=0x%" PRIx64 ")", __func__, iova, - level, slpte); + "slpte=0x%" PRIx64 ", pasid=0x%" PRIX32 ")", + __func__, iova, level, slpte, pasid); return -VTD_FR_PAGING_ENTRY_RSVD; } if (vtd_is_last_slpte(slpte, level)) { *slptep = slpte; *slpte_level = level; - return 0; + break; } addr = vtd_get_slpte_addr(slpte, aw_bits); level--; } + + xlat = vtd_get_slpte_addr(*slptep, aw_bits); + size = ~vtd_slpt_level_page_mask(level) + 1; + + /* + * From VT-d spec 3.14: Untranslated requests and translation + * requests that result in an address in the interrupt range will be + * blocked with condition code LGN.4 or SGN.8. + */ + if ((xlat > VTD_INTERRUPT_ADDR_LAST || + xlat + size - 1 < VTD_INTERRUPT_ADDR_FIRST)) { + return 0; + } else { + error_report_once("%s: xlat address is in interrupt range " + "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", " + "slpte=0x%" PRIx64 ", write=%d, " + "xlat=0x%" PRIx64 ", size=0x%" PRIx64 ", " + "pasid=0x%" PRIx32 ")", + __func__, iova, level, slpte, is_write, + xlat, size, pasid); + return s->scalable_mode ? -VTD_FR_SM_INTERRUPT_ADDR : + -VTD_FR_INTERRUPT_ADDR; + } } typedef int (*vtd_page_walk_hook)(IOMMUTLBEvent *event, void *private); @@ -1157,7 +1210,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; @@ -1170,7 +1223,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, @@ -1284,18 +1337,19 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, */ static int vtd_page_walk(IntelIOMMUState *s, VTDContextEntry *ce, uint64_t start, uint64_t end, - vtd_page_walk_info *info) + vtd_page_walk_info *info, + uint32_t pasid) { - dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce); - uint32_t level = vtd_get_iova_level(s, ce); + dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid); + uint32_t level = vtd_get_iova_level(s, ce, pasid); - if (!vtd_iova_range_check(s, start, ce, info->aw)) { + if (!vtd_iova_range_check(s, start, ce, info->aw, pasid)) { return -VTD_FR_ADDR_BEYOND_MGAW; } - if (!vtd_iova_range_check(s, end, ce, info->aw)) { + if (!vtd_iova_range_check(s, end, ce, info->aw, pasid)) { /* Fix end so that it reaches the maximum */ - end = vtd_iova_limit(s, ce, info->aw); + end = vtd_iova_limit(s, ce, info->aw, pasid); } return vtd_page_walk_level(addr, start, end, level, true, true, info); @@ -1363,7 +1417,7 @@ static int vtd_ce_rid2pasid_check(IntelIOMMUState *s, * has valid rid2pasid setting, which includes valid * rid2pasid field and corresponding pasid entry setting */ - return vtd_ce_get_rid2pasid_entry(s, ce, &pe); + return vtd_ce_get_rid2pasid_entry(s, ce, &pe, PCI_NO_PASID); } /* Map a device to its corresponding domain (context-entry) */ @@ -1446,12 +1500,13 @@ static int vtd_sync_shadow_page_hook(IOMMUTLBEvent *event, } static uint16_t vtd_get_domain_id(IntelIOMMUState *s, - VTDContextEntry *ce) + VTDContextEntry *ce, + uint32_t pasid) { VTDPASIDEntry pe; if (s->root_scalable) { - vtd_ce_get_rid2pasid_entry(s, ce, &pe); + vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid); return VTD_SM_PASID_ENTRY_DID(pe.val[1]); } @@ -1469,10 +1524,10 @@ static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, .notify_unmap = true, .aw = s->aw_bits, .as = vtd_as, - .domain_id = vtd_get_domain_id(s, ce), + .domain_id = vtd_get_domain_id(s, ce, vtd_as->pasid), }; - return vtd_page_walk(s, ce, addr, addr + size, &info); + return vtd_page_walk(s, ce, addr, addr + size, &info, vtd_as->pasid); } static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) @@ -1516,16 +1571,19 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) * 1st-level translation or 2nd-level translation, it depends * on PGTT setting. */ -static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce) +static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce, + uint32_t pasid) { VTDPASIDEntry pe; int ret; if (s->root_scalable) { - ret = vtd_ce_get_rid2pasid_entry(s, ce, &pe); + ret = vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid); if (ret) { - error_report_once("%s: vtd_ce_get_rid2pasid_entry error: %"PRId32, - __func__, ret); + /* + * This error is guest triggerable. We should assumt PT + * not enabled for safety. + */ return false; } return (VTD_PE_GET_TYPE(&pe) == VTD_SM_PASID_ENTRY_PT); @@ -1539,14 +1597,12 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as) { IntelIOMMUState *s; VTDContextEntry ce; - int ret; assert(as); s = as->iommu_state; - ret = vtd_dev_to_context_entry(s, pci_bus_num(as->bus), - as->devfn, &ce); - if (ret) { + if (vtd_dev_to_context_entry(s, pci_bus_num(as->bus), as->devfn, + &ce)) { /* * Possibly failed to parse the context entry for some reason * (e.g., during init, or any guest configuration errors on @@ -1556,19 +1612,20 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as) return false; } - return vtd_dev_pt_enabled(s, &ce); + return vtd_dev_pt_enabled(s, &ce, as->pasid); } /* Return whether the device is using IOMMU translation. */ static bool vtd_switch_address_space(VTDAddressSpace *as) { - bool use_iommu; + bool use_iommu, pt; /* Whether we need to take the BQL on our own */ bool take_bql = !qemu_mutex_iothread_locked(); assert(as); use_iommu = as->iommu_state->dmar_enabled && !vtd_as_pt_enabled(as); + pt = as->iommu_state->dmar_enabled && vtd_as_pt_enabled(as); trace_vtd_switch_address_space(pci_bus_num(as->bus), VTD_PCI_SLOT(as->devfn), @@ -1588,11 +1645,53 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) if (use_iommu) { memory_region_set_enabled(&as->nodmar, false); memory_region_set_enabled(MEMORY_REGION(&as->iommu), true); + /* + * vt-d spec v3.4 3.14: + * + * """ + * Requests-with-PASID with input address in range 0xFEEx_xxxx + * are translated normally like any other request-with-PASID + * through DMA-remapping hardware. + * """ + * + * Need to disable ir for as with PASID. + */ + if (as->pasid != PCI_NO_PASID) { + memory_region_set_enabled(&as->iommu_ir, false); + } else { + memory_region_set_enabled(&as->iommu_ir, true); + } } else { memory_region_set_enabled(MEMORY_REGION(&as->iommu), false); memory_region_set_enabled(&as->nodmar, true); } + /* + * vtd-spec v3.4 3.14: + * + * """ + * Requests-with-PASID with input address in range 0xFEEx_xxxx are + * translated normally like any other request-with-PASID through + * DMA-remapping hardware. However, if such a request is processed + * using pass-through translation, it will be blocked as described + * in the paragraph below. + * + * Software must not program paging-structure entries to remap any + * address to the interrupt address range. Untranslated requests + * and translation requests that result in an address in the + * interrupt range will be blocked with condition code LGN.4 or + * SGN.8. + * """ + * + * We enable per as memory region (iommu_ir_fault) for catching + * the tranlsation for interrupt range through PASID + PT. + */ + if (pt && as->pasid != PCI_NO_PASID) { + memory_region_set_enabled(&as->iommu_ir_fault, true); + } else { + memory_region_set_enabled(&as->iommu_ir_fault, false); + } + if (take_bql) { qemu_mutex_unlock_iothread(); } @@ -1602,24 +1701,13 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) static void vtd_switch_address_space_all(IntelIOMMUState *s) { + VTDAddressSpace *vtd_as; GHashTableIter iter; - VTDBus *vtd_bus; - int i; - - g_hash_table_iter_init(&iter, s->vtd_as_by_busptr); - while (g_hash_table_iter_next(&iter, NULL, (void **)&vtd_bus)) { - for (i = 0; i < PCI_DEVFN_MAX; i++) { - if (!vtd_bus->dev_as[i]) { - continue; - } - vtd_switch_address_space(vtd_bus->dev_as[i]); - } - } -} -static inline uint16_t vtd_make_source_id(uint8_t bus_num, uint8_t devfn) -{ - return ((bus_num & 0xffUL) << 8) | (devfn & 0xffUL); + g_hash_table_iter_init(&iter, s->vtd_address_spaces); + while (g_hash_table_iter_next(&iter, NULL, (void **)&vtd_as)) { + vtd_switch_address_space(vtd_as); + } } static const bool vtd_qualified_faults[] = { @@ -1633,11 +1721,12 @@ static const bool vtd_qualified_faults[] = { [VTD_FR_PAGING_ENTRY_INV] = true, [VTD_FR_ROOT_TABLE_INV] = false, [VTD_FR_CONTEXT_TABLE_INV] = false, + [VTD_FR_INTERRUPT_ADDR] = true, [VTD_FR_ROOT_ENTRY_RSVD] = false, [VTD_FR_PAGING_ENTRY_RSVD] = true, [VTD_FR_CONTEXT_ENTRY_TT] = true, [VTD_FR_PASID_TABLE_INV] = false, - [VTD_FR_RESERVED_ERR] = false, + [VTD_FR_SM_INTERRUPT_ADDR] = true, [VTD_FR_MAX] = false, }; @@ -1655,18 +1744,37 @@ static inline bool vtd_is_interrupt_addr(hwaddr addr) return VTD_INTERRUPT_ADDR_FIRST <= addr && addr <= VTD_INTERRUPT_ADDR_LAST; } +static gboolean vtd_find_as_by_sid(gpointer key, gpointer value, + gpointer user_data) +{ + struct vtd_as_key *as_key = (struct vtd_as_key *)key; + uint16_t target_sid = *(uint16_t *)user_data; + uint16_t sid = PCI_BUILD_BDF(pci_bus_num(as_key->bus), as_key->devfn); + return sid == target_sid; +} + +static VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid) +{ + uint8_t bus_num = PCI_BUS_NUM(sid); + VTDAddressSpace *vtd_as = s->vtd_as_cache[bus_num]; + + if (vtd_as && + (sid == PCI_BUILD_BDF(pci_bus_num(vtd_as->bus), vtd_as->devfn))) { + return vtd_as; + } + + vtd_as = g_hash_table_find(s->vtd_address_spaces, vtd_find_as_by_sid, &sid); + s->vtd_as_cache[bus_num] = vtd_as; + + return vtd_as; +} + static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id) { - VTDBus *vtd_bus; VTDAddressSpace *vtd_as; bool success = false; - vtd_bus = vtd_find_as_from_bus_num(s, VTD_SID_TO_BUS(source_id)); - if (!vtd_bus) { - goto out; - } - - vtd_as = vtd_bus->dev_as[VTD_SID_TO_DEVFN(source_id)]; + vtd_as = vtd_get_as_by_sid(s, source_id); if (!vtd_as) { goto out; } @@ -1680,6 +1788,22 @@ static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id) trace_vtd_pt_enable_fast_path(source_id, success); } +static void vtd_report_fault(IntelIOMMUState *s, + int err, bool is_fpd_set, + uint16_t source_id, + hwaddr addr, + bool is_write, + bool is_pasid, + uint32_t pasid) +{ + if (is_fpd_set && vtd_is_qualified_fault(err)) { + trace_vtd_fault_disabled(); + } else { + vtd_report_dmar_fault(s, source_id, addr, err, is_write, + is_pasid, pasid); + } +} + /* Map dev to context-entry then do a paging-structures walk to do a iommu * translation. * @@ -1701,13 +1825,14 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, uint8_t bus_num = pci_bus_num(bus); VTDContextCacheEntry *cc_entry; uint64_t slpte, page_mask; - uint32_t level; - uint16_t source_id = vtd_make_source_id(bus_num, devfn); + uint32_t level, pasid = vtd_as->pasid; + uint16_t source_id = PCI_BUILD_BDF(bus_num, devfn); int ret_fr; bool is_fpd_set = false; bool reads = true; bool writes = true; uint8_t access_flags; + bool rid2pasid = (pasid == PCI_NO_PASID) && s->root_scalable; VTDIOTLBEntry *iotlb_entry; /* @@ -1720,15 +1845,17 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, cc_entry = &vtd_as->context_cache_entry; - /* Try to fetch slpte form IOTLB */ - iotlb_entry = vtd_lookup_iotlb(s, source_id, addr); - if (iotlb_entry) { - trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte, - iotlb_entry->domain_id); - slpte = iotlb_entry->slpte; - access_flags = iotlb_entry->access_flags; - page_mask = iotlb_entry->mask; - goto out; + /* Try to fetch slpte form IOTLB, we don't need RID2PASID logic */ + if (!rid2pasid) { + iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr); + if (iotlb_entry) { + trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte, + iotlb_entry->domain_id); + slpte = iotlb_entry->slpte; + access_flags = iotlb_entry->access_flags; + page_mask = iotlb_entry->mask; + goto out; + } } /* Try to fetch context-entry from cache first */ @@ -1739,16 +1866,26 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, ce = cc_entry->context_entry; is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD; if (!is_fpd_set && s->root_scalable) { - ret_fr = vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set); - VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write); + ret_fr = vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set, pasid); + if (ret_fr) { + vtd_report_fault(s, -ret_fr, is_fpd_set, + source_id, addr, is_write, + false, 0); + goto error; + } } } else { ret_fr = vtd_dev_to_context_entry(s, bus_num, devfn, &ce); is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD; if (!ret_fr && !is_fpd_set && s->root_scalable) { - ret_fr = vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set); + ret_fr = vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set, pasid); + } + if (ret_fr) { + vtd_report_fault(s, -ret_fr, is_fpd_set, + source_id, addr, is_write, + false, 0); + goto error; } - VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write); /* Update context-cache */ trace_vtd_iotlb_cc_update(bus_num, devfn, ce.hi, ce.lo, cc_entry->context_cache_gen, @@ -1757,11 +1894,15 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, cc_entry->context_cache_gen = s->context_cache_gen; } + if (rid2pasid) { + pasid = VTD_CE_GET_RID2PASID(&ce); + } + /* * We don't need to translate for pass-through context entries. * Also, let's ignore IOTLB caching as well for PT devices. */ - if (vtd_dev_pt_enabled(s, &ce)) { + if (vtd_dev_pt_enabled(s, &ce, pasid)) { entry->iova = addr & VTD_PAGE_MASK_4K; entry->translated_addr = entry->iova; entry->addr_mask = ~VTD_PAGE_MASK_4K; @@ -1782,14 +1923,31 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, return true; } + /* Try to fetch slpte form IOTLB for RID2PASID slow path */ + if (rid2pasid) { + iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr); + if (iotlb_entry) { + trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte, + iotlb_entry->domain_id); + slpte = iotlb_entry->slpte; + access_flags = iotlb_entry->access_flags; + page_mask = iotlb_entry->mask; + goto out; + } + } + ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &slpte, &level, - &reads, &writes, s->aw_bits); - VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write); + &reads, &writes, s->aw_bits, pasid); + if (ret_fr) { + vtd_report_fault(s, -ret_fr, is_fpd_set, source_id, + addr, is_write, pasid != PCI_NO_PASID, pasid); + goto error; + } page_mask = vtd_slpt_level_page_mask(level); access_flags = IOMMU_ACCESS_FLAG(reads, writes); - vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce), addr, slpte, - access_flags, level); + vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid), + addr, slpte, access_flags, level, pasid); out: vtd_iommu_unlock(s); entry->iova = addr & page_mask; @@ -1874,11 +2032,10 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, uint16_t source_id, uint16_t func_mask) { + GHashTableIter as_it; uint16_t mask; - VTDBus *vtd_bus; VTDAddressSpace *vtd_as; uint8_t bus_n, devfn; - uint16_t devfn_it; trace_vtd_inv_desc_cc_devices(source_id, func_mask); @@ -1901,32 +2058,31 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, mask = ~mask; bus_n = VTD_SID_TO_BUS(source_id); - vtd_bus = vtd_find_as_from_bus_num(s, bus_n); - if (vtd_bus) { - devfn = VTD_SID_TO_DEVFN(source_id); - for (devfn_it = 0; devfn_it < PCI_DEVFN_MAX; ++devfn_it) { - vtd_as = vtd_bus->dev_as[devfn_it]; - if (vtd_as && ((devfn_it & mask) == (devfn & mask))) { - trace_vtd_inv_desc_cc_device(bus_n, VTD_PCI_SLOT(devfn_it), - VTD_PCI_FUNC(devfn_it)); - vtd_iommu_lock(s); - vtd_as->context_cache_entry.context_cache_gen = 0; - vtd_iommu_unlock(s); - /* - * Do switch address space when needed, in case if the - * device passthrough bit is switched. - */ - vtd_switch_address_space(vtd_as); - /* - * So a device is moving out of (or moving into) a - * domain, resync the shadow page table. - * This won't bring bad even if we have no such - * notifier registered - the IOMMU notification - * framework will skip MAP notifications if that - * happened. - */ - vtd_sync_shadow_page_table(vtd_as); - } + devfn = VTD_SID_TO_DEVFN(source_id); + + g_hash_table_iter_init(&as_it, s->vtd_address_spaces); + while (g_hash_table_iter_next(&as_it, NULL, (void **)&vtd_as)) { + if ((pci_bus_num(vtd_as->bus) == bus_n) && + (vtd_as->devfn & mask) == (devfn & mask)) { + trace_vtd_inv_desc_cc_device(bus_n, VTD_PCI_SLOT(vtd_as->devfn), + VTD_PCI_FUNC(vtd_as->devfn)); + vtd_iommu_lock(s); + vtd_as->context_cache_entry.context_cache_gen = 0; + vtd_iommu_unlock(s); + /* + * Do switch address space when needed, in case if the + * device passthrough bit is switched. + */ + vtd_switch_address_space(vtd_as); + /* + * So a device is moving out of (or moving into) a + * domain, resync the shadow page table. + * This won't bring bad even if we have no such + * notifier registered - the IOMMU notification + * framework will skip MAP notifications if that + * happened. + */ + vtd_sync_shadow_page_table(vtd_as); } } } @@ -1983,7 +2139,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), vtd_as->devfn, &ce) && - domain_id == vtd_get_domain_id(s, &ce)) { + domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) { vtd_sync_shadow_page_table(vtd_as); } } @@ -1991,7 +2147,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, uint16_t domain_id, hwaddr addr, - uint8_t am) + uint8_t am, uint32_t pasid) { VTDAddressSpace *vtd_as; VTDContextEntry ce; @@ -1999,9 +2155,12 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, hwaddr size = (1 << am) * VTD_PAGE_SIZE; QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) { + if (pasid != PCI_NO_PASID && pasid != vtd_as->pasid) { + continue; + } ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), vtd_as->devfn, &ce); - if (!ret && domain_id == vtd_get_domain_id(s, &ce)) { + if (!ret && domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) { if (vtd_as_has_map_notifier(vtd_as)) { /* * As long as we have MAP notifications registered in @@ -2045,7 +2204,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, vtd_iommu_lock(s); g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info); vtd_iommu_unlock(s); - vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am); + vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am, PCI_NO_PASID); } /* Flush IOTLB @@ -2209,12 +2368,13 @@ static void vtd_handle_gcmd_ire(IntelIOMMUState *s, bool en) /* Handle write to Global Command Register */ static void vtd_handle_gcmd_write(IntelIOMMUState *s) { + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); uint32_t status = vtd_get_long_raw(s, DMAR_GSTS_REG); uint32_t val = vtd_get_long_raw(s, DMAR_GCMD_REG); uint32_t changed = status ^ val; trace_vtd_reg_write_gcmd(status, val); - if (changed & VTD_GCMD_TE) { + if ((changed & VTD_GCMD_TE) && s->dma_translation) { /* Translation enable/disable */ vtd_handle_gcmd_te(s, val & VTD_GCMD_TE); } @@ -2230,7 +2390,8 @@ static void vtd_handle_gcmd_write(IntelIOMMUState *s) /* Set/update the interrupt remapping root-table pointer */ vtd_handle_gcmd_sirtp(s); } - if (changed & VTD_GCMD_IRE) { + if ((changed & VTD_GCMD_IRE) && + x86_iommu_ir_supported(x86_iommu)) { /* Interrupt remap enable/disable */ vtd_handle_gcmd_ire(s, val & VTD_GCMD_IRE); } @@ -2440,18 +2601,13 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, { VTDAddressSpace *vtd_dev_as; IOMMUTLBEvent event; - struct VTDBus *vtd_bus; hwaddr addr; uint64_t sz; uint16_t sid; - uint8_t devfn; bool size; - uint8_t bus_num; addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi); sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo); - devfn = sid & 0xff; - bus_num = sid >> 8; size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi); if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) || @@ -2462,12 +2618,11 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, return false; } - vtd_bus = vtd_find_as_from_bus_num(s, bus_num); - if (!vtd_bus) { - goto done; - } - - vtd_dev_as = vtd_bus->dev_as[devfn]; + /* + * Using sid is OK since the guest should have finished the + * initialization of both the bus and device. + */ + vtd_dev_as = vtd_get_as_by_sid(s, sid); if (!vtd_dev_as) { goto done; } @@ -2883,12 +3038,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr, } else { vtd_set_quad(s, addr, val); } - if (s->ecap & VTD_ECAP_SMTS && - val & VTD_IQA_DW_MASK) { - s->iq_dw = true; - } else { - s->iq_dw = false; - } + vtd_update_iq_dw(s); break; case DMAR_IQA_REG_HI: @@ -3032,7 +3182,7 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, /* TODO: add support for VFIO and vhost users */ if (s->snoop_control) { - error_setg_errno(errp, -ENOTSUP, + error_setg_errno(errp, ENOTSUP, "Snoop Control with vhost or VFIO is not supported"); return -ENOTSUP; } @@ -3052,13 +3202,6 @@ static int vtd_post_load(void *opaque, int version_id) { IntelIOMMUState *iommu = opaque; - /* - * Memory regions are dynamically turned on/off depending on - * context entry configurations from the guest. After migration, - * we need to make sure the memory regions are still correct. - */ - vtd_switch_address_space_all(iommu); - /* * We don't need to migrate the root_scalable because we can * simply do the calculation after the loading is complete. We @@ -3068,6 +3211,15 @@ static int vtd_post_load(void *opaque, int version_id) */ vtd_update_scalable_state(iommu); + vtd_update_iq_dw(iommu); + + /* + * Memory regions are dynamically turned on/off depending on + * context entry configurations from the guest. After migration, + * we need to make sure the memory regions are still correct. + */ + vtd_switch_address_space_all(iommu); + return 0; } @@ -3121,7 +3273,9 @@ static Property vtd_properties[] = { DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE), DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE), DEFINE_PROP_BOOL("snoop-control", IntelIOMMUState, snoop_control, false), + DEFINE_PROP_BOOL("x-pasid-mode", IntelIOMMUState, pasid, false), DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true), + DEFINE_PROP_BOOL("dma-translation", IntelIOMMUState, dma_translation, true), DEFINE_PROP_END_OF_LIST(), }; @@ -3375,7 +3529,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, return MEMTX_ERROR; } - apic_get_class()->send_msi(&to); + apic_get_class(NULL)->send_msi(&to); return MEMTX_OK; } @@ -3394,32 +3548,98 @@ static const MemoryRegionOps vtd_mem_ir_ops = { }, }; -VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) +static void vtd_report_ir_illegal_access(VTDAddressSpace *vtd_as, + hwaddr addr, bool is_write) { - uintptr_t key = (uintptr_t)bus; - VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key); - VTDAddressSpace *vtd_dev_as; - char name[128]; + IntelIOMMUState *s = vtd_as->iommu_state; + uint8_t bus_n = pci_bus_num(vtd_as->bus); + uint16_t sid = PCI_BUILD_BDF(bus_n, vtd_as->devfn); + bool is_fpd_set = false; + VTDContextEntry ce; - if (!vtd_bus) { - uintptr_t *new_key = g_malloc(sizeof(*new_key)); - *new_key = (uintptr_t)bus; - /* No corresponding free() */ - vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * \ - PCI_DEVFN_MAX); - vtd_bus->bus = bus; - g_hash_table_insert(s->vtd_as_by_busptr, new_key, vtd_bus); + assert(vtd_as->pasid != PCI_NO_PASID); + + /* Try out best to fetch FPD, we can't do anything more */ + if (vtd_dev_to_context_entry(s, bus_n, vtd_as->devfn, &ce) == 0) { + is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD; + if (!is_fpd_set && s->root_scalable) { + vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set, vtd_as->pasid); + } } - vtd_dev_as = vtd_bus->dev_as[devfn]; + vtd_report_fault(s, VTD_FR_SM_INTERRUPT_ADDR, + is_fpd_set, sid, addr, is_write, + true, vtd_as->pasid); +} + +static MemTxResult vtd_mem_ir_fault_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + vtd_report_ir_illegal_access(opaque, addr, false); + + return MEMTX_ERROR; +} + +static MemTxResult vtd_mem_ir_fault_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + vtd_report_ir_illegal_access(opaque, addr, true); + + return MEMTX_ERROR; +} + +static const MemoryRegionOps vtd_mem_ir_fault_ops = { + .read_with_attrs = vtd_mem_ir_fault_read, + .write_with_attrs = vtd_mem_ir_fault_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; +VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, + int devfn, unsigned int pasid) +{ + /* + * We can't simply use sid here since the bus number might not be + * initialized by the guest. + */ + struct vtd_as_key key = { + .bus = bus, + .devfn = devfn, + .pasid = pasid, + }; + VTDAddressSpace *vtd_dev_as; + char name[128]; + + vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key); if (!vtd_dev_as) { - snprintf(name, sizeof(name), "vtd-%02x.%x", PCI_SLOT(devfn), - PCI_FUNC(devfn)); - vtd_bus->dev_as[devfn] = vtd_dev_as = g_new0(VTDAddressSpace, 1); + struct vtd_as_key *new_key = g_malloc(sizeof(*new_key)); + + new_key->bus = bus; + new_key->devfn = devfn; + new_key->pasid = pasid; + + if (pasid == PCI_NO_PASID) { + snprintf(name, sizeof(name), "vtd-%02x.%x", PCI_SLOT(devfn), + PCI_FUNC(devfn)); + } else { + snprintf(name, sizeof(name), "vtd-%02x.%x-pasid-%x", PCI_SLOT(devfn), + PCI_FUNC(devfn), pasid); + } + + vtd_dev_as = g_new0(VTDAddressSpace, 1); vtd_dev_as->bus = bus; vtd_dev_as->devfn = (uint8_t)devfn; + vtd_dev_as->pasid = pasid; vtd_dev_as->iommu_state = s; vtd_dev_as->context_cache_entry.context_cache_gen = 0; vtd_dev_as->iova_tree = iova_tree_new(); @@ -3460,6 +3680,24 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) VTD_INTERRUPT_ADDR_FIRST, &vtd_dev_as->iommu_ir, 1); + /* + * This region is used for catching fault to access interrupt + * range via passthrough + PASID. See also + * vtd_switch_address_space(). We can't use alias since we + * need to know the sid which is valid for MSI who uses + * bus_master_as (see msi_send_message()). + */ + memory_region_init_io(&vtd_dev_as->iommu_ir_fault, OBJECT(s), + &vtd_mem_ir_fault_ops, vtd_dev_as, "vtd-no-ir", + VTD_INTERRUPT_ADDR_SIZE); + /* + * Hook to root since when PT is enabled vtd_dev_as->iommu + * will be disabled. + */ + memory_region_add_subregion_overlap(MEMORY_REGION(&vtd_dev_as->root), + VTD_INTERRUPT_ADDR_FIRST, + &vtd_dev_as->iommu_ir_fault, 2); + /* * Hook both the containers under the root container, we * switch between DMAR & noDMAR by enable/disable @@ -3472,6 +3710,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) &vtd_dev_as->nodmar, 0); vtd_switch_address_space(vtd_dev_as); + + g_hash_table_insert(s->vtd_address_spaces, new_key, vtd_dev_as); } return vtd_dev_as; } @@ -3532,7 +3772,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) @@ -3578,7 +3818,7 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) "legacy mode", bus_n, PCI_SLOT(vtd_as->devfn), PCI_FUNC(vtd_as->devfn), - vtd_get_domain_id(s, &ce), + vtd_get_domain_id(s, &ce, vtd_as->pasid), ce.hi, ce.lo); if (vtd_as_has_map_notifier(vtd_as)) { /* This is required only for MAP typed notifiers */ @@ -3588,10 +3828,10 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) .notify_unmap = false, .aw = s->aw_bits, .as = vtd_as, - .domain_id = vtd_get_domain_id(s, &ce), + .domain_id = vtd_get_domain_id(s, &ce, vtd_as->pasid), }; - vtd_page_walk(s, &ce, 0, ~0ULL, &info); + vtd_page_walk(s, &ce, 0, ~0ULL, &info, vtd_as->pasid); } } else { trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn), @@ -3627,12 +3867,17 @@ static void vtd_init(IntelIOMMUState *s) s->next_frcd_reg = 0; s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS | - VTD_CAP_SAGAW_39bit | VTD_CAP_MGAW(s->aw_bits); + VTD_CAP_MGAW(s->aw_bits); if (s->dma_drain) { s->cap |= VTD_CAP_DRAIN; } - if (s->aw_bits == VTD_HOST_AW_48BIT) { - s->cap |= VTD_CAP_SAGAW_48bit; + if (s->dma_translation) { + if (s->aw_bits >= VTD_HOST_AW_39BIT) { + s->cap |= VTD_CAP_SAGAW_39bit; + } + if (s->aw_bits >= VTD_HOST_AW_48BIT) { + s->cap |= VTD_CAP_SAGAW_48bit; + } } s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO; @@ -3686,6 +3931,10 @@ static void vtd_init(IntelIOMMUState *s) s->ecap |= VTD_ECAP_SC; } + if (s->pasid) { + s->ecap |= VTD_ECAP_PASID; + } + vtd_reset_caches(s); /* Define registers with default values and bit semantics */ @@ -3759,7 +4008,7 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) assert(0 <= devfn && devfn < PCI_DEVFN_MAX); - vtd_as = vtd_find_add_as(s, bus, devfn); + vtd_as = vtd_find_add_as(s, bus, devfn, PCI_NO_PASID); return &vtd_as->as; } @@ -3778,7 +4027,7 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) { - if (!kvm_irqchip_in_kernel()) { + if (!kvm_irqchip_is_split()) { error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split"); return false; } @@ -3802,6 +4051,11 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) return false; } + if (s->pasid && !s->scalable_mode) { + error_setg(errp, "Need to set scalable mode for PASID"); + return false; + } + return true; } @@ -3838,6 +4092,17 @@ static void vtd_realize(DeviceState *dev, Error **errp) X86MachineState *x86ms = X86_MACHINE(ms); PCIBus *bus = pcms->bus; IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev); + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); + + if (s->pasid && x86_iommu->dt_supported) { + /* + * PASID-based-Device-TLB Invalidate Descriptor is not + * implemented and it requires support from vhost layer which + * needs to be implemented in the future. + */ + error_setg(errp, "PASID based device IOTLB is not supported"); + return; + } if (!vtd_decide_config(s, errp)) { return; @@ -3845,7 +4110,6 @@ static void vtd_realize(DeviceState *dev, Error **errp) QLIST_INIT(&s->vtd_as_with_notifiers); qemu_mutex_init(&s->iommu_lock); - memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); @@ -3865,10 +4129,10 @@ static void vtd_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem); /* No corresponding destroy */ - s->iotlb = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal, + s->iotlb = g_hash_table_new_full(vtd_iotlb_hash, vtd_iotlb_equal, g_free, g_free); - s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal, - g_free, g_free); + s->vtd_address_spaces = g_hash_table_new_full(vtd_as_hash, vtd_as_equal, + g_free, g_free); vtd_init(s); sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); pci_setup_iommu(bus, vtd_host_dma_iommu, dev); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 1ff13b40f9bb..f090e61e1171 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -114,8 +114,9 @@ VTD_INTERRUPT_ADDR_FIRST + 1) /* The shift of source_id in the key of IOTLB hash table */ -#define VTD_IOTLB_SID_SHIFT 36 -#define VTD_IOTLB_LVL_SHIFT 52 +#define VTD_IOTLB_SID_SHIFT 20 +#define VTD_IOTLB_LVL_SHIFT 28 +#define VTD_IOTLB_PASID_SHIFT 30 #define VTD_IOTLB_MAX_SIZE 1024 /* Max size of the hash table */ /* IOTLB_REG */ @@ -191,6 +192,7 @@ #define VTD_ECAP_SC (1ULL << 7) #define VTD_ECAP_MHMV (15ULL << 20) #define VTD_ECAP_SRS (1ULL << 31) +#define VTD_ECAP_PASID (1ULL << 40) #define VTD_ECAP_SMTS (1ULL << 43) #define VTD_ECAP_SLTS (1ULL << 46) @@ -211,6 +213,8 @@ #define VTD_CAP_DRAIN_READ (1ULL << 55) #define VTD_CAP_DRAIN (VTD_CAP_DRAIN_READ | VTD_CAP_DRAIN_WRITE) #define VTD_CAP_CM (1ULL << 7) +#define VTD_PASID_ID_SHIFT 20 +#define VTD_PASID_ID_MASK ((1ULL << VTD_PASID_ID_SHIFT) - 1) /* Supported Adjusted Guest Address Widths */ #define VTD_CAP_SAGAW_SHIFT 8 @@ -262,6 +266,8 @@ #define VTD_FRCD_SID(val) ((val) & VTD_FRCD_SID_MASK) /* For the low 64-bit of 128-bit */ #define VTD_FRCD_FI(val) ((val) & ~0xfffULL) +#define VTD_FRCD_PV(val) (((val) & 0xffffULL) << 40) +#define VTD_FRCD_PP(val) (((val) & 0x1) << 31) /* DMA Remapping Fault Conditions */ typedef enum VTDFaultReason { @@ -289,6 +295,8 @@ typedef enum VTDFaultReason { * context-entry. */ VTD_FR_CONTEXT_ENTRY_TT, + /* Output address in the interrupt address range */ + VTD_FR_INTERRUPT_ADDR = 0xE, /* Interrupt remapping transition faults */ VTD_FR_IR_REQ_RSVD = 0x20, /* One or more IR request reserved @@ -304,11 +312,8 @@ typedef enum VTDFaultReason { VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */ - /* This is not a normal fault reason. We use this to indicate some faults - * that are not referenced by the VT-d specification. - * Fault event with such reason should not be recorded. - */ - VTD_FR_RESERVED_ERR, + /* Output address in the interrupt address range for scalable mode */ + VTD_FR_SM_INTERRUPT_ADDR = 0x87, VTD_FR_MAX, /* Guard */ } VTDFaultReason; @@ -380,6 +385,11 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL) #define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL #define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL +#define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4) +#define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4) +#define VTD_INV_DESC_IOTLB_PASID(val) (((val) >> 32) & VTD_PASID_ID_MASK) +#define VTD_INV_DESC_IOTLB_PASID_RSVD_LO 0xfff00000000001c0ULL +#define VTD_INV_DESC_IOTLB_PASID_RSVD_HI 0xf80ULL /* Mask for Device IOTLB Invalidate Descriptor */ #define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL) @@ -414,6 +424,7 @@ typedef union VTDInvDesc VTDInvDesc; /* Information about page-selective IOTLB invalidate */ struct VTDIOTLBPageInvInfo { uint16_t domain_id; + uint32_t pasid; uint64_t addr; uint8_t mask; }; diff --git a/hw/i386/microvm-dt.c b/hw/i386/microvm-dt.c index 9c3c4995b41d..b3049e4f9f26 100644 --- a/hw/i386/microvm-dt.c +++ b/hw/i386/microvm-dt.c @@ -32,6 +32,7 @@ */ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qapi/error.h" #include "sysemu/device_tree.h" #include "hw/char/serial.h" #include "hw/i386/fw_cfg.h" @@ -187,8 +188,8 @@ static void dt_add_ioapic(MicrovmMachineState *mms, SysBusDevice *dev) static void dt_add_isa_serial(MicrovmMachineState *mms, ISADevice *dev) { const char compat[] = "ns16550"; - uint32_t irq = object_property_get_int(OBJECT(dev), "irq", NULL); - hwaddr base = object_property_get_int(OBJECT(dev), "iobase", NULL); + uint32_t irq = object_property_get_int(OBJECT(dev), "irq", &error_fatal); + hwaddr base = object_property_get_int(OBJECT(dev), "iobase", &error_fatal); hwaddr size = 8; char *nodename; @@ -208,8 +209,8 @@ static void dt_add_isa_serial(MicrovmMachineState *mms, ISADevice *dev) static void dt_add_isa_rtc(MicrovmMachineState *mms, ISADevice *dev) { const char compat[] = "motorola,mc146818"; - uint32_t irq = RTC_ISA_IRQ; - hwaddr base = RTC_ISA_BASE; + uint32_t irq = object_property_get_uint(OBJECT(dev), "irq", &error_fatal); + hwaddr base = object_property_get_uint(OBJECT(dev), "iobase", &error_fatal); hwaddr size = 8; char *nodename; diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 4b3b1dd262f1..170a331e3fce 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -247,7 +247,7 @@ static void microvm_devices_init(MicrovmMachineState *mms) x86ms->pci_irq_mask = 0; } - if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) { + if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { qemu_irq *i8259; i8259 = i8259_init(isa_bus, x86_allocate_cpu_irq()); @@ -257,7 +257,7 @@ static void microvm_devices_init(MicrovmMachineState *mms) g_free(i8259); } - if (mms->pit == ON_OFF_AUTO_ON || mms->pit == ON_OFF_AUTO_AUTO) { + if (x86ms->pit == ON_OFF_AUTO_ON || x86ms->pit == ON_OFF_AUTO_AUTO) { if (kvm_pit_in_kernel()) { kvm_pit_init(isa_bus, 0x40); } else { @@ -324,15 +324,13 @@ static void microvm_memory_init(MicrovmMachineState *mms) fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, machine->smp.max_cpus); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, 1); - fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, - &e820_reserve, sizeof(e820_reserve)); fw_cfg_add_file(fw_cfg, "etc/e820", e820_table, sizeof(struct e820_entry) * e820_get_num_entries()); rom_set_fw(fw_cfg); if (machine->kernel_filename != NULL) { - x86_load_linux(x86ms, fw_cfg, 0, true); + x86_load_linux(x86ms, fw_cfg, 0, true, false); } if (mms->option_roms) { @@ -467,7 +465,7 @@ static void microvm_machine_state_init(MachineState *machine) microvm_devices_init(mms); } -static void microvm_machine_reset(MachineState *machine) +static void microvm_machine_reset(MachineState *machine, ShutdownCause reason) { MicrovmMachineState *mms = MICROVM_MACHINE(machine); CPUState *cs; @@ -480,51 +478,15 @@ static void microvm_machine_reset(MachineState *machine) mms->kernel_cmdline_fixed = true; } - qemu_devices_reset(); + qemu_devices_reset(reason); CPU_FOREACH(cs) { cpu = X86_CPU(cs); - if (cpu->apic_state) { - device_legacy_reset(cpu->apic_state); - } + x86_cpu_after_reset(cpu); } } -static void microvm_machine_get_pic(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - OnOffAuto pic = mms->pic; - - visit_type_OnOffAuto(v, name, &pic, errp); -} - -static void microvm_machine_set_pic(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - - visit_type_OnOffAuto(v, name, &mms->pic, errp); -} - -static void microvm_machine_get_pit(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - OnOffAuto pit = mms->pit; - - visit_type_OnOffAuto(v, name, &pit, errp); -} - -static void microvm_machine_set_pit(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - - visit_type_OnOffAuto(v, name, &mms->pit, errp); -} - static void microvm_machine_get_rtc(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -649,8 +611,6 @@ static void microvm_machine_initfn(Object *obj) MicrovmMachineState *mms = MICROVM_MACHINE(obj); /* Configuration */ - mms->pic = ON_OFF_AUTO_AUTO; - mms->pit = ON_OFF_AUTO_AUTO; mms->rtc = ON_OFF_AUTO_AUTO; mms->pcie = ON_OFF_AUTO_AUTO; mms->ioapic2 = ON_OFF_AUTO_AUTO; @@ -667,6 +627,14 @@ static void microvm_machine_initfn(Object *obj) qemu_register_powerdown_notifier(&mms->powerdown_req); } +GlobalProperty microvm_properties[] = { + /* + * pcie host bridge (gpex) on microvm has no io address window, + * so reserving io space is not going to work. Turn it off. + */ + { "pcie-root-port", "io-reserve", "0" }, +}; + static void microvm_class_init(ObjectClass *oc, void *data) { X86MachineClass *x86mc = X86_MACHINE_CLASS(oc); @@ -702,20 +670,6 @@ static void microvm_class_init(ObjectClass *oc, void *data) x86mc->fwcfg_dma_enabled = true; - object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto", - microvm_machine_get_pic, - microvm_machine_set_pic, - NULL, NULL); - object_class_property_set_description(oc, MICROVM_MACHINE_PIC, - "Enable i8259 PIC"); - - object_class_property_add(oc, MICROVM_MACHINE_PIT, "OnOffAuto", - microvm_machine_get_pit, - microvm_machine_set_pit, - NULL, NULL); - object_class_property_set_description(oc, MICROVM_MACHINE_PIT, - "Enable i8254 PIT"); - object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto", microvm_machine_get_rtc, microvm_machine_set_rtc, @@ -757,6 +711,9 @@ static void microvm_class_init(ObjectClass *oc, void *data) "Set off to disable adding virtio-mmio devices to the kernel cmdline"); machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + + compat_props_add(mc->compat_props, microvm_properties, + G_N_ELEMENTS(microvm_properties)); } static const TypeInfo microvm_machine_info = { diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index 0a10089f14b4..963e29362e4b 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 fd55fc725caf..d489ecc0d1cd 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -37,6 +37,7 @@ #include "hw/ide.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" +#include "hw/pci-bridge/pci_expander_bridge.h" #include "hw/nvram/fw_cfg.h" #include "hw/timer/hpet.h" #include "hw/firmware/smbios.h" @@ -46,7 +47,6 @@ #include "multiboot.h" #include "hw/rtc/mc146818rtc.h" #include "hw/intc/i8259.h" -#include "hw/dma/i8257.h" #include "hw/timer/i8254.h" #include "hw/input/i8042.h" #include "hw/irq.h" @@ -75,6 +75,8 @@ #include "acpi-build.h" #include "hw/mem/pc-dimm.h" #include "hw/mem/nvdimm.h" +#include "hw/cxl/cxl.h" +#include "hw/cxl/cxl_host.h" #include "qapi/error.h" #include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-machine.h" @@ -89,12 +91,33 @@ #include "hw/virtio/virtio-mem-pci.h" #include "hw/mem/memory-device.h" #include "sysemu/replay.h" +#include "target/i386/cpu.h" #include "qapi/qmp/qerror.h" #include "e820_memory_layout.h" #include "fw_cfg.h" #include "trace.h" #include CONFIG_DEVICES +/* + * Helper for setting model-id for CPU models that changed model-id + * depending on QEMU versions up to QEMU 2.4. + */ +#define PC_CPU_MODEL_IDS(v) \ + { "qemu32-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ + { "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_2[] = { + { "ICH9-LPC", "noreboot", "true" }, +}; +const size_t pc_compat_7_2_len = G_N_ELEMENTS(pc_compat_7_2); + +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); + GlobalProperty pc_compat_6_2[] = { { "virtio-mem", "unplugged-inaccessible", "off" }, }; @@ -557,7 +580,7 @@ static const char * const fdc_container_path[] = { * Locate the FDC at IO address 0x3f0, in order to configure the CMOS registers * and ACPI objects. */ -ISADevice *pc_find_fdc0(void) +static ISADevice *pc_find_fdc0(void) { int i; Object *container; @@ -672,7 +695,7 @@ void pc_cmos_init(PCMachineState *pcms, object_property_set_link(OBJECT(pcms), "rtc_state", OBJECT(s), &error_abort); - set_boot_dev(s, MACHINE(pcms)->boot_order, &error_fatal); + set_boot_dev(s, MACHINE(pcms)->boot_config.order, &error_fatal); val = 0; val |= 0x02; /* FPU is there */ @@ -701,7 +724,7 @@ static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; -void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd) +static void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd) { static int nb_ne2k = 0; @@ -728,6 +751,13 @@ void pc_machine_done(Notifier *notifier, void *data) PCMachineState, machine_done); X86MachineState *x86ms = X86_MACHINE(pcms); + cxl_hook_up_pxb_registers(pcms->bus, &pcms->cxl_devices_state, + &error_fatal); + + if (pcms->cxl_devices_state.is_enabled) { + cxl_fmws_link_targets(&pcms->cxl_devices_state, &error_fatal); + } + /* set the number of CPUs */ x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); @@ -740,14 +770,6 @@ void pc_machine_done(Notifier *notifier, void *data) /* update FW_CFG_NB_CPUS to account for -device added CPUs */ fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); } - - - if (x86ms->apic_id_limit > 255 && !xen_enabled() && - !kvm_irqchip_in_kernel()) { - error_report("current -smp configuration requires kernel " - "irqchip support."); - exit(EXIT_FAILURE); - } } void pc_guest_info_init(PCMachineState *pcms) @@ -782,7 +804,7 @@ void xen_load_linux(PCMachineState *pcms) rom_set_fw(fw_cfg); x86_load_linux(x86ms, fw_cfg, pcmc->acpi_data_size, - pcmc->pvh_enabled); + pcmc->pvh_enabled, pcmc->legacy_no_rng_seed); for (i = 0; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "linuxboot_dma.bin") || @@ -800,10 +822,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; @@ -813,12 +947,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. @@ -835,9 +1006,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) { @@ -859,7 +1031,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, @@ -874,20 +1046,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) { @@ -902,6 +1061,32 @@ void pc_memory_init(PCMachineState *pcms, &machine->device_memory->mr); } + if (pcms->cxl_devices_state.is_enabled) { + MemoryRegion *mr = &pcms->cxl_devices_state.host_mr; + hwaddr cxl_size = MiB; + + cxl_base = pc_get_cxl_range_start(pcms); + memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size); + memory_region_add_subregion(system_memory, cxl_base, mr); + cxl_resv_end = cxl_base + cxl_size; + if (pcms->cxl_devices_state.fixed_windows) { + hwaddr cxl_fmw_base; + GList *it; + + cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB); + for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + + fw->base = cxl_fmw_base; + memory_region_init_io(&fw->mr, OBJECT(machine), &cfmws_ops, fw, + "cxl-fixed-memory-region", fw->size); + memory_region_add_subregion(system_memory, fw->base, &fw->mr); + cxl_fmw_base += fw->size; + cxl_resv_end = cxl_fmw_base; + } + } + } + /* Initialize PC system firmware */ pc_system_firmware_init(pcms, rom_memory); @@ -929,13 +1114,17 @@ void pc_memory_init(PCMachineState *pcms, if (!pcmc->broken_reserved_end) { res_mem_end += memory_region_size(&machine->device_memory->mr); } + + if (pcms->cxl_devices_state.is_enabled) { + res_mem_end = cxl_resv_end; + } *val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB)); fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val)); } if (linux_boot) { x86_load_linux(x86ms, fw_cfg, pcmc->acpi_data_size, - pcmc->pvh_enabled); + pcmc->pvh_enabled, pcmc->legacy_no_rng_seed); } for (i = 0; i < nb_option_roms; i++) { @@ -959,18 +1148,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 (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); @@ -1039,7 +1228,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, return; } - i8042 = isa_create_simple(isa_bus, "i8042"); + i8042 = isa_create_simple(isa_bus, TYPE_I8042); if (!no_vmport) { isa_create_simple(isa_bus, TYPE_VMPORT); vmmouse = isa_try_new("vmmouse"); @@ -1047,7 +1236,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, vmmouse = NULL; } if (vmmouse) { - object_property_set_link(OBJECT(vmmouse), "i8042", OBJECT(i8042), + object_property_set_link(OBJECT(vmmouse), TYPE_I8042, OBJECT(i8042), &error_abort); isa_realize_and_unref(vmmouse, isa_bus, &error_fatal); } @@ -1074,6 +1263,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISADevice *pit = NULL; MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); + X86MachineState *x86ms = X86_MACHINE(pcms); memory_region_init_io(ioport80_io, NULL, &ioport80_io_ops, NULL, "ioport80", 1); memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); @@ -1118,7 +1308,8 @@ void pc_basic_device_init(struct PCMachineState *pcms, qemu_register_boot_set(pc_boot_set, *rtc_state); - if (!xen_enabled() && pcms->pit_enabled) { + if (!xen_enabled() && + (x86ms->pit == ON_OFF_AUTO_AUTO || x86ms->pit == ON_OFF_AUTO_ON)) { if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { @@ -1131,8 +1322,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, pcspk_init(pcms->pcspk, isa_bus, pit); } - i8257_dma_init(isa_bus, 0); - /* Super I/O */ pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled, pcms->vmport != ON_OFF_AUTO_ON); @@ -1488,20 +1677,6 @@ static void pc_machine_set_sata(Object *obj, bool value, Error **errp) pcms->sata_enabled = value; } -static bool pc_machine_get_pit(Object *obj, Error **errp) -{ - PCMachineState *pcms = PC_MACHINE(obj); - - return pcms->pit_enabled; -} - -static void pc_machine_set_pit(Object *obj, bool value, Error **errp) -{ - PCMachineState *pcms = PC_MACHINE(obj); - - pcms->pit_enabled = value; -} - static bool pc_machine_get_hpet(Object *obj, Error **errp) { PCMachineState *pcms = PC_MACHINE(obj); @@ -1612,12 +1787,9 @@ static void pc_machine_set_max_fw_size(Object *obj, Visitor *v, Error **errp) { PCMachineState *pcms = PC_MACHINE(obj); - Error *error = NULL; uint64_t value; - visit_type_size(v, name, &value, &error); - if (error) { - error_propagate(errp, error); + if (!visit_type_size(v, name, &value, errp)) { return; } @@ -1658,7 +1830,6 @@ static void pc_machine_initfn(Object *obj) pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; pcms->smbus_enabled = true; pcms->sata_enabled = true; - pcms->pit_enabled = true; pcms->i8042_enabled = true; pcms->max_fw_size = 8 * MiB; #ifdef CONFIG_HPET @@ -1670,14 +1841,15 @@ static void pc_machine_initfn(Object *obj) pcms->pcspk = isa_new(TYPE_PC_SPEAKER); object_property_add_alias(OBJECT(pcms), "pcspk-audiodev", OBJECT(pcms->pcspk), "audiodev"); + cxl_machine_init(obj, &pcms->cxl_devices_state); } -static void pc_machine_reset(MachineState *machine) +static void pc_machine_reset(MachineState *machine, ShutdownCause reason) { CPUState *cs; X86CPU *cpu; - qemu_devices_reset(); + qemu_devices_reset(reason); /* Reset APIC after devices have been reset to cancel * any changes that qemu_devices_reset() might have done. @@ -1685,16 +1857,14 @@ static void pc_machine_reset(MachineState *machine) CPU_FOREACH(cs) { cpu = X86_CPU(cs); - if (cpu->apic_state) { - device_legacy_reset(cpu->apic_state); - } + x86_cpu_after_reset(cpu); } } static void pc_machine_wakeup(MachineState *machine) { cpu_synchronize_all_states(); - pc_machine_reset(machine); + pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE); cpu_synchronize_all_post_reset(); } @@ -1732,6 +1902,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; @@ -1786,11 +1957,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, PC_MACHINE_SATA, "Enable/disable Serial ATA bus"); - object_class_property_add_bool(oc, PC_MACHINE_PIT, - pc_machine_get_pit, pc_machine_set_pit); - object_class_property_set_description(oc, PC_MACHINE_PIT, - "Enable/disable Intel 8254 programmable interval timer emulation"); - object_class_property_add_bool(oc, "hpet", pc_machine_get_hpet, pc_machine_set_hpet); object_class_property_set_description(oc, "hpet", diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index b72c03d0a626..b48047f50caf 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -26,6 +26,7 @@ #include CONFIG_DEVICES #include "qemu/units.h" +#include "hw/dma/i8257.h" #include "hw/loader.h" #include "hw/i386/x86.h" #include "hw/i386/pc.h" @@ -39,6 +40,7 @@ #include "hw/usb.h" #include "net/net.h" #include "hw/ide/pci.h" +#include "hw/ide/piix.h" #include "hw/irq.h" #include "sysemu/kvm.h" #include "hw/kvm/clock.h" @@ -47,6 +49,7 @@ #include "hw/xen/xen-x86.h" #include "exec/memory.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/piix4.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/xen.h" @@ -81,7 +84,6 @@ static void pc_init1(MachineState *machine, MemoryRegion *system_io = get_system_io(); PCIBus *pci_bus; ISABus *isa_bus; - PCII440FXState *i440fx_state; int piix3_devfn = -1; qemu_irq smi_irq; GSIState *gsi_state; @@ -91,6 +93,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 +168,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 +193,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) { @@ -196,29 +206,35 @@ static void pc_init1(MachineState *machine, if (pcmc->pci_enabled) { PIIX3State *piix3; + PCIDevice *pci_dev; + const char *type = xen_enabled() ? TYPE_PIIX3_XEN_DEVICE + : TYPE_PIIX3_DEVICE; - pci_bus = i440fx_init(host_type, - pci_type, - &i440fx_state, + 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, pci_memory, ram_memory); pcms->bus = pci_bus; - piix3 = piix3_create(pci_bus, &isa_bus); + pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, type); + piix3 = PIIX3_PCI_DEVICE(pci_dev); piix3->pic = x86ms->gsi; piix3_devfn = piix3->dev.devfn; + isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); } else { pci_bus = NULL; - i440fx_state = NULL; isa_bus = isa_bus_new(NULL, get_system_memory(), system_io, &error_abort); + i8257_dma_init(isa_bus, 0); pcms->hpet_enabled = false; } isa_bus_irqs(isa_bus, x86ms->gsi); - pc_i8259_create(isa_bus, gsi_state->i8259_irq); + if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { + pc_i8259_create(isa_bus, gsi_state->i8259_irq); + } if (pcmc->pci_enabled) { ioapic_init_gsi(gsi_state, "i440fx"); @@ -244,8 +260,7 @@ static void pc_init1(MachineState *machine, if (pcmc->pci_enabled) { PCIDevice *dev; - dev = pci_create_simple(pci_bus, piix3_devfn + 1, - xen_enabled() ? "piix3-ide-xen" : "piix3-ide"); + dev = pci_create_simple(pci_bus, piix3_devfn + 1, TYPE_PIIX3_IDE); pci_ide_create_devs(dev); idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); @@ -279,14 +294,19 @@ static void pc_init1(MachineState *machine, } if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { - DeviceState *piix4_pm; + PCIDevice *piix4_pm; smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0); + piix4_pm = pci_new(piix3_devfn + 3, TYPE_PIIX4_PM); + qdev_prop_set_uint32(DEVICE(piix4_pm), "smb_io_base", 0xb100); + qdev_prop_set_bit(DEVICE(piix4_pm), "smm-enabled", + x86_machine_is_smm_enabled(x86ms)); + pci_realize_and_unref(piix4_pm, pci_bus, &error_fatal); + + qdev_connect_gpio_out(DEVICE(piix4_pm), 0, x86ms->gsi[9]); + qdev_connect_gpio_out_named(DEVICE(piix4_pm), "smi-irq", 0, smi_irq); + pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(piix4_pm), "i2c")); /* TODO: Populate SPD eeprom data. */ - pcms->smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, - x86ms->gsi[9], smi_irq, - x86_machine_is_smm_enabled(x86ms), - &piix4_pm); smbus_eeprom_init(pcms->smbus, 8, NULL, 0); object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, @@ -406,6 +426,7 @@ static void pc_i440fx_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pcmc->default_nic_model = "e1000"; pcmc->pci_root_uid = 0; + pcmc->default_cpu_version = 1; m->family = "pc_piix"; m->desc = "Standard PC (i440FX + PIIX, 1996)"; @@ -415,13 +436,47 @@ static void pc_i440fx_machine_options(MachineClass *m) machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); } -static void pc_i440fx_7_0_machine_options(MachineClass *m) +static void pc_i440fx_8_0_machine_options(MachineClass *m) { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); m->alias = "pc"; m->is_default = true; - pcmc->default_cpu_version = 1; +} + +DEFINE_I440FX_MACHINE(v8_0, "pc-i440fx-8.0", NULL, + pc_i440fx_8_0_machine_options); + +static void pc_i440fx_7_2_machine_options(MachineClass *m) +{ + pc_i440fx_8_0_machine_options(m); + m->alias = NULL; + m->is_default = false; + compat_props_add(m->compat_props, hw_compat_7_2, hw_compat_7_2_len); + compat_props_add(m->compat_props, pc_compat_7_2, pc_compat_7_2_len); +} + +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); + 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); + +static void pc_i440fx_7_0_machine_options(MachineClass *m) +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_i440fx_7_1_machine_options(m); + 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); } DEFINE_I440FX_MACHINE(v7_0, "pc-i440fx-7.0", NULL, @@ -430,8 +485,6 @@ DEFINE_I440FX_MACHINE(v7_0, "pc-i440fx-7.0", NULL, static void pc_i440fx_6_2_machine_options(MachineClass *m) { pc_i440fx_7_0_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_6_2, hw_compat_6_2_len); compat_props_add(m->compat_props, pc_compat_6_2, pc_compat_6_2_len); } @@ -442,8 +495,6 @@ DEFINE_I440FX_MACHINE(v6_2, "pc-i440fx-6.2", NULL, static void pc_i440fx_6_1_machine_options(MachineClass *m) { pc_i440fx_6_2_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_6_1, hw_compat_6_1_len); compat_props_add(m->compat_props, pc_compat_6_1, pc_compat_6_1_len); m->smp_props.prefer_sockets = true; @@ -455,8 +506,6 @@ DEFINE_I440FX_MACHINE(v6_1, "pc-i440fx-6.1", NULL, static void pc_i440fx_6_0_machine_options(MachineClass *m) { pc_i440fx_6_1_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_6_0, hw_compat_6_0_len); compat_props_add(m->compat_props, pc_compat_6_0, pc_compat_6_0_len); } @@ -467,8 +516,6 @@ DEFINE_I440FX_MACHINE(v6_0, "pc-i440fx-6.0", NULL, static void pc_i440fx_5_2_machine_options(MachineClass *m) { pc_i440fx_6_0_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_5_2, hw_compat_5_2_len); compat_props_add(m->compat_props, pc_compat_5_2, pc_compat_5_2_len); } @@ -481,8 +528,6 @@ static void pc_i440fx_5_1_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_5_2_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len); compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len); pcmc->kvmclock_create_always = false; @@ -495,8 +540,6 @@ DEFINE_I440FX_MACHINE(v5_1, "pc-i440fx-5.1", NULL, static void pc_i440fx_5_0_machine_options(MachineClass *m) { pc_i440fx_5_1_machine_options(m); - m->alias = NULL; - m->is_default = false; m->numa_mem_supported = true; compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); @@ -509,8 +552,6 @@ DEFINE_I440FX_MACHINE(v5_0, "pc-i440fx-5.0", NULL, static void pc_i440fx_4_2_machine_options(MachineClass *m) { pc_i440fx_5_0_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_4_2, hw_compat_4_2_len); compat_props_add(m->compat_props, pc_compat_4_2, pc_compat_4_2_len); } @@ -521,8 +562,6 @@ DEFINE_I440FX_MACHINE(v4_2, "pc-i440fx-4.2", NULL, static void pc_i440fx_4_1_machine_options(MachineClass *m) { pc_i440fx_4_2_machine_options(m); - m->alias = NULL; - m->is_default = false; compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len); } @@ -534,8 +573,6 @@ static void pc_i440fx_4_0_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_4_1_machine_options(m); - m->alias = NULL; - m->is_default = false; pcmc->default_cpu_version = CPU_VERSION_LEGACY; compat_props_add(m->compat_props, hw_compat_4_0, hw_compat_4_0_len); compat_props_add(m->compat_props, pc_compat_4_0, pc_compat_4_0_len); @@ -549,10 +586,7 @@ static void pc_i440fx_3_1_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_4_0_machine_options(m); - m->is_default = false; - pcmc->do_not_add_smb_acpi = true; m->smbus_no_migration_support = true; - m->alias = NULL; pcmc->pvh_enabled = false; compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len); compat_props_add(m->compat_props, pc_compat_3_1, pc_compat_3_1_len); @@ -801,124 +835,6 @@ static void pc_i440fx_1_4_machine_options(MachineClass *m) DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn, pc_i440fx_1_4_machine_options); -typedef struct { - uint16_t gpu_device_id; - uint16_t pch_device_id; - uint8_t pch_revision_id; -} IGDDeviceIDInfo; - -/* In real world different GPU should have different PCH. But actually - * the different PCH DIDs likely map to different PCH SKUs. We do the - * same thing for the GPU. For PCH, the different SKUs are going to be - * all the same silicon design and implementation, just different - * features turn on and off with fuses. The SW interfaces should be - * consistent across all SKUs in a given family (eg LPT). But just same - * features may not be supported. - * - * Most of these different PCH features probably don't matter to the - * Gfx driver, but obviously any difference in display port connections - * will so it should be fine with any PCH in case of passthrough. - * - * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) - * scenarios, 0x9cc3 for BDW(Broadwell). - */ -static const IGDDeviceIDInfo igd_combo_id_infos[] = { - /* HSW Classic */ - {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */ - {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */ - {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */ - {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */ - {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */ - /* HSW ULT */ - {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */ - {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */ - {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */ - {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */ - {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */ - {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */ - /* HSW CRW */ - {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */ - {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */ - /* HSW Server */ - {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */ - /* HSW SRVR */ - {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */ - /* BSW */ - {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */ - {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */ - {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */ - {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */ - {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */ - {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */ - {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */ - {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */ - {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */ - {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */ - {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */ -}; - -static void isa_bridge_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "ISA bridge faked to support IGD PT"; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->class_id = PCI_CLASS_BRIDGE_ISA; -}; - -static const TypeInfo isa_bridge_info = { - .name = "igd-passthrough-isa-bridge", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = isa_bridge_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static void pt_graphics_register_types(void) -{ - type_register_static(&isa_bridge_info); -} -type_init(pt_graphics_register_types) - -void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id) -{ - struct PCIDevice *bridge_dev; - int i, num; - uint16_t pch_dev_id = 0xffff; - uint8_t pch_rev_id = 0; - - num = ARRAY_SIZE(igd_combo_id_infos); - for (i = 0; i < num; i++) { - if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) { - pch_dev_id = igd_combo_id_infos[i].pch_device_id; - pch_rev_id = igd_combo_id_infos[i].pch_revision_id; - } - } - - if (pch_dev_id == 0xffff) { - return; - } - - /* Currently IGD drivers always need to access PCH by 1f.0. */ - bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0), - "igd-passthrough-isa-bridge"); - - /* - * Note that vendor id is always PCI_VENDOR_ID_INTEL. - */ - if (!bridge_dev) { - fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n"); - return; - } - pci_config_set_device_id(bridge_dev->config, pch_dev_id); - pci_config_set_revision(bridge_dev->config, pch_rev_id); -} - #ifdef CONFIG_ISAPC static void isapc_machine_options(MachineClass *m) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 1780f79bc127..67ceb04bcc2d 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); @@ -265,7 +273,9 @@ static void pc_q35_init(MachineState *machine) pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); isa_bus = ich9_lpc->isa_bus; - pc_i8259_create(isa_bus, gsi_state->i8259_irq); + if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { + pc_i8259_create(isa_bus, gsi_state->i8259_irq); + } if (pcmc->pci_enabled) { ioapic_init_gsi(gsi_state, "q35"); @@ -345,6 +355,7 @@ static void pc_q35_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pcmc->default_nic_model = "e1000e"; pcmc->pci_root_uid = 0; + pcmc->default_cpu_version = 1; m->family = "pc_q35"; m->desc = "Standard PC (Q35 + ICH9, 2009)"; @@ -360,12 +371,45 @@ static void pc_q35_machine_options(MachineClass *m) m->max_cpus = 288; } -static void pc_q35_7_0_machine_options(MachineClass *m) +static void pc_q35_8_0_machine_options(MachineClass *m) { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_machine_options(m); m->alias = "q35"; - pcmc->default_cpu_version = 1; +} + +DEFINE_Q35_MACHINE(v8_0, "pc-q35-8.0", NULL, + pc_q35_8_0_machine_options); + +static void pc_q35_7_2_machine_options(MachineClass *m) +{ + pc_q35_8_0_machine_options(m); + m->alias = NULL; + compat_props_add(m->compat_props, hw_compat_7_2, hw_compat_7_2_len); + compat_props_add(m->compat_props, pc_compat_7_2, pc_compat_7_2_len); +} + +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); + 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); + +static void pc_q35_7_0_machine_options(MachineClass *m) +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_7_1_machine_options(m); + 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); } DEFINE_Q35_MACHINE(v7_0, "pc-q35-7.0", NULL, @@ -374,7 +418,6 @@ DEFINE_Q35_MACHINE(v7_0, "pc-q35-7.0", NULL, static void pc_q35_6_2_machine_options(MachineClass *m) { pc_q35_7_0_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_6_2, hw_compat_6_2_len); compat_props_add(m->compat_props, pc_compat_6_2, pc_compat_6_2_len); } @@ -385,7 +428,6 @@ DEFINE_Q35_MACHINE(v6_2, "pc-q35-6.2", NULL, static void pc_q35_6_1_machine_options(MachineClass *m) { pc_q35_6_2_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_6_1, hw_compat_6_1_len); compat_props_add(m->compat_props, pc_compat_6_1, pc_compat_6_1_len); m->smp_props.prefer_sockets = true; @@ -397,7 +439,6 @@ DEFINE_Q35_MACHINE(v6_1, "pc-q35-6.1", NULL, static void pc_q35_6_0_machine_options(MachineClass *m) { pc_q35_6_1_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_6_0, hw_compat_6_0_len); compat_props_add(m->compat_props, pc_compat_6_0, pc_compat_6_0_len); } @@ -408,7 +449,6 @@ DEFINE_Q35_MACHINE(v6_0, "pc-q35-6.0", NULL, static void pc_q35_5_2_machine_options(MachineClass *m) { pc_q35_6_0_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_5_2, hw_compat_5_2_len); compat_props_add(m->compat_props, pc_compat_5_2, pc_compat_5_2_len); } @@ -421,7 +461,6 @@ static void pc_q35_5_1_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_5_2_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len); compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len); pcmc->kvmclock_create_always = false; @@ -434,7 +473,6 @@ DEFINE_Q35_MACHINE(v5_1, "pc-q35-5.1", NULL, static void pc_q35_5_0_machine_options(MachineClass *m) { pc_q35_5_1_machine_options(m); - m->alias = NULL; m->numa_mem_supported = true; compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); @@ -447,7 +485,6 @@ DEFINE_Q35_MACHINE(v5_0, "pc-q35-5.0", NULL, static void pc_q35_4_2_machine_options(MachineClass *m) { pc_q35_5_0_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_4_2, hw_compat_4_2_len); compat_props_add(m->compat_props, pc_compat_4_2, pc_compat_4_2_len); } @@ -458,7 +495,6 @@ DEFINE_Q35_MACHINE(v4_2, "pc-q35-4.2", NULL, static void pc_q35_4_1_machine_options(MachineClass *m) { pc_q35_4_2_machine_options(m); - m->alias = NULL; compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len); } @@ -470,7 +506,6 @@ static void pc_q35_4_0_1_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_4_1_machine_options(m); - m->alias = NULL; pcmc->default_cpu_version = CPU_VERSION_LEGACY; /* * This is the default machine for the 4.0-stable branch. It is basically @@ -488,7 +523,6 @@ static void pc_q35_4_0_machine_options(MachineClass *m) { pc_q35_4_0_1_machine_options(m); m->default_kernel_irqchip_split = true; - m->alias = NULL; /* Compat props are applied by the 4.0.1 machine */ } @@ -501,9 +535,7 @@ static void pc_q35_3_1_machine_options(MachineClass *m) pc_q35_4_0_machine_options(m); m->default_kernel_irqchip_split = false; - pcmc->do_not_add_smb_acpi = true; m->smbus_no_migration_support = true; - m->alias = NULL; pcmc->pvh_enabled = false; compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len); compat_props_add(m->compat_props, pc_compat_3_1, pc_compat_3_1_len); diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index c8b17af95353..c8d9e71b889b 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "sysemu/block-backend.h" #include "qemu/error-report.h" @@ -148,7 +147,6 @@ static void pc_system_flash_map(PCMachineState *pcms, MemoryRegion *flash_mem; void *flash_ptr; int flash_size; - int ret; assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled); @@ -196,19 +194,7 @@ static void pc_system_flash_map(PCMachineState *pcms, if (sev_enabled()) { flash_ptr = memory_region_get_ram_ptr(flash_mem); flash_size = memory_region_size(flash_mem); - /* - * OVMF places a GUIDed structures in the flash, so - * search for them - */ - pc_system_parse_ovmf_flash(flash_ptr, flash_size); - - ret = sev_es_save_reset_vector(flash_ptr, flash_size); - if (ret) { - error_report("failed to locate and/or save reset vector"); - exit(1); - } - - sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); + x86_firmware_configure(flash_ptr, flash_size); } } } @@ -260,3 +246,24 @@ void pc_system_firmware_init(PCMachineState *pcms, pc_system_flash_cleanup_unused(pcms); } + +void x86_firmware_configure(void *ptr, int size) +{ + int ret; + + /* + * OVMF places a GUIDed structures in the flash, so + * search for them + */ + pc_system_parse_ovmf_flash(ptr, size); + + if (sev_enabled()) { + ret = sev_es_save_reset_vector(ptr, size); + if (ret) { + error_report("failed to locate and/or save reset vector"); + exit(1); + } + + sev_encrypt_flash(ptr, size, &error_fatal); + } +} diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index a44d66ba2afc..db004d17a65d 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -83,7 +83,7 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) ((high & MAKE_64BIT_MASK(0, 20)) << 32); } -static SGXEPCSectionList *sgx_calc_host_epc_sections(uint64_t *size) +static SGXEPCSectionList *sgx_calc_host_epc_sections(void) { SGXEPCSectionList *head = NULL, **tail = &head; SGXEPCSection *section; @@ -106,7 +106,6 @@ static SGXEPCSectionList *sgx_calc_host_epc_sections(uint64_t *size) section = g_new0(SGXEPCSection, 1); section->node = j++; section->size = sgx_calc_section_metric(ecx, edx); - *size += section->size; QAPI_LIST_APPEND(tail, section); } @@ -157,7 +156,6 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) { SGXInfo *info = NULL; uint32_t eax, ebx, ecx, edx; - uint64_t size = 0; int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR); if (fd < 0) { @@ -175,8 +173,7 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) info->sgx1 = eax & (1U << 0) ? true : false; info->sgx2 = eax & (1U << 1) ? true : false; - info->sections = sgx_calc_host_epc_sections(&size); - info->section_size = size; + info->sections = sgx_calc_host_epc_sections(); close(fd); @@ -223,14 +220,12 @@ SGXInfo *qmp_query_sgx(Error **errp) return NULL; } - SGXEPCState *sgx_epc = &pcms->sgx_epc; info = g_new0(SGXInfo, 1); info->sgx = true; info->sgx1 = true; info->sgx2 = true; info->flc = true; - info->section_size = sgx_epc->size; info->sections = sgx_get_epc_sections_list(); return info; @@ -241,6 +236,7 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) Error *err = NULL; SGXEPCSectionList *section_list, *section; g_autoptr(SGXInfo) info = qmp_query_sgx(&err); + uint64_t size = 0; if (err) { error_report_err(err); @@ -254,8 +250,6 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) info->sgx2 ? "enabled" : "disabled"); monitor_printf(mon, "FLC support: %s\n", info->flc ? "enabled" : "disabled"); - monitor_printf(mon, "size: %" PRIu64 "\n", - info->section_size); section_list = info->sections; for (section = section_list; section; section = section->next) { @@ -263,7 +257,10 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) section->value->node); monitor_printf(mon, "size=%" PRIu64 "\n", section->value->size); + size += section->value->size; } + monitor_printf(mon, "total size=%" PRIu64 "\n", + size); } bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) @@ -295,7 +292,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/trace-events b/hw/i386/trace-events index e49814dd642d..04fd71bfc480 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -12,6 +12,8 @@ vtd_inv_desc_cc_devices(uint16_t sid, uint16_t fmask) "context invalidate device vtd_inv_desc_iotlb_global(void) "iotlb invalidate global" vtd_inv_desc_iotlb_domain(uint16_t domain) "iotlb invalidate whole domain 0x%"PRIx16 vtd_inv_desc_iotlb_pages(uint16_t domain, uint64_t addr, uint8_t mask) "iotlb invalidate domain 0x%"PRIx16" addr 0x%"PRIx64" mask 0x%"PRIx8 +vtd_inv_desc_iotlb_pasid_pages(uint16_t domain, uint64_t addr, uint8_t mask, uint32_t pasid) "iotlb invalidate domain 0x%"PRIx16" addr 0x%"PRIx64" mask 0x%"PRIx8" pasid 0x%"PRIx32 +vtd_inv_desc_iotlb_pasid(uint16_t domain, uint32_t pasid) "iotlb invalidate domain 0x%"PRIx16" pasid 0x%"PRIx32 vtd_inv_desc_wait_sw(uint64_t addr, uint32_t data) "wait invalidate status write addr 0x%"PRIx64" data 0x%"PRIx32 vtd_inv_desc_wait_irq(const char *msg) "%s" vtd_inv_desc_wait_write_fail(uint64_t hi, uint64_t lo) "write fail for wait desc hi 0x%"PRIx64" lo 0x%"PRIx64 diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 4cf107baea34..78cc131926c8 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -25,8 +25,8 @@ #include "qemu/option.h" #include "qemu/cutils.h" #include "qemu/units.h" -#include "qemu-common.h" #include "qemu/datadir.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" #include "qapi/qapi-visit-common.h" @@ -37,8 +37,10 @@ #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" #include "trace.h" #include "hw/i386/x86.h" @@ -123,6 +125,25 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) */ x86ms->apic_id_limit = x86_cpu_apic_id_from_index(x86ms, ms->smp.max_cpus - 1) + 1; + + /* + * Can we support APIC ID 255 or higher? + * + * Under Xen: yes. + * With userspace emulated lapic: no + * With KVM's in-kernel lapic: only if X2APIC API is enabled. + */ + if (x86ms->apic_id_limit > 255 && !xen_enabled() && + (!kvm_irqchip_in_kernel() || !kvm_enable_x2apic())) { + error_report("current -smp configuration requires kernel " + "irqchip and X2APIC API support."); + exit(EXIT_FAILURE); + } + + if (kvm_enabled()) { + kvm_set_max_apic_id(x86ms->apic_id_limit); + } + possible_cpus = mc->possible_cpu_arch_ids(ms); for (i = 0; i < ms->smp.cpus; i++) { x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); @@ -636,12 +657,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; /* @@ -748,10 +769,35 @@ 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, - bool pvh_enabled) + bool pvh_enabled, + bool legacy_no_rng_seed) { bool linuxboot_dma_enabled = X86_MACHINE_GET_CLASS(x86ms)->fwcfg_dma_enabled; uint16_t protocol; @@ -759,16 +805,17 @@ void x86_load_linux(X86MachineState *x86ms, int dtb_size, setup_data_offset; uint32_t initrd_max; uint8_t header[8192], *setup, *kernel; - hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; + hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0, first_setup_data = 0; 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; const char *kernel_cmdline = machine->kernel_cmdline; SevKernelLoaderContext sev_load_ctx = {}; + enum { RNG_SEED_LENGTH = 32 }; /* Align to 16 bytes as a paranoia measure */ cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; @@ -1045,19 +1092,41 @@ 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); - stq_p(header + 0x250, prot_addr + setup_data_offset); - setup_data = (struct setup_data *)(kernel + setup_data_offset); - setup_data->next = 0; + 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); setup_data->len = cpu_to_le32(dtb_size); load_image_size(dtb_filename, setup_data->data, dtb_size); } + if (!legacy_no_rng_seed) { + setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); + kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH; + kernel = g_realloc(kernel, kernel_size); + 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_nosnapshotload(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); + } + + 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 * efi stub for booting and doesn't require any values to be placed in the @@ -1066,16 +1135,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; @@ -1100,7 +1173,7 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware, char *filename; MemoryRegion *bios, *isa_bios; int bios_size, isa_bios_size; - int ret; + ssize_t ret; /* BIOS load */ bios_name = ms->firmware ?: default_firmware; @@ -1116,14 +1189,25 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware, } bios = g_malloc(sizeof(*bios)); memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal); - if (!isapc_ram_fw) { - memory_region_set_readonly(bios, true); - } - ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); - if (ret != 0) { - bios_error: - fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); - exit(1); + if (sev_enabled()) { + /* + * The concept of a "reset" simply doesn't exist for + * confidential computing guests, we have to destroy and + * re-launch them instead. So there is no need to register + * the firmware as rom to properly re-initialize on reset. + * Just go for a straight file load instead. + */ + void *ptr = memory_region_get_ram_ptr(bios); + load_image_size(filename, ptr, bios_size); + x86_firmware_configure(ptr, bios_size); + } else { + if (!isapc_ram_fw) { + memory_region_set_readonly(bios, true); + } + ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); + if (ret != 0) { + goto bios_error; + } } g_free(filename); @@ -1144,6 +1228,11 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware, memory_region_add_subregion(rom_memory, (uint32_t)(-bios_size), bios); + return; + +bios_error: + fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); + exit(1); } bool x86_machine_is_smm_enabled(const X86MachineState *x86ms) @@ -1213,6 +1302,40 @@ static void x86_machine_set_acpi(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &x86ms->acpi, errp); } +static void x86_machine_get_pit(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj); + OnOffAuto pit = x86ms->pit; + + visit_type_OnOffAuto(v, name, &pit, errp); +} + +static void x86_machine_set_pit(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj);; + + visit_type_OnOffAuto(v, name, &x86ms->pit, errp); +} + +static void x86_machine_get_pic(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj); + OnOffAuto pic = x86ms->pic; + + visit_type_OnOffAuto(v, name, &pic, errp); +} + +static void x86_machine_set_pic(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj); + + visit_type_OnOffAuto(v, name, &x86ms->pic, errp); +} + static char *x86_machine_get_oem_id(Object *obj, Error **errp) { X86MachineState *x86ms = X86_MACHINE(obj); @@ -1302,10 +1425,13 @@ static void x86_machine_initfn(Object *obj) x86ms->smm = ON_OFF_AUTO_AUTO; x86ms->acpi = ON_OFF_AUTO_AUTO; + x86ms->pit = ON_OFF_AUTO_AUTO; + x86ms->pic = ON_OFF_AUTO_AUTO; x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS; 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) @@ -1333,6 +1459,20 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, X86_MACHINE_ACPI, "Enable ACPI"); + object_class_property_add(oc, X86_MACHINE_PIT, "OnOffAuto", + x86_machine_get_pit, + x86_machine_set_pit, + NULL, NULL); + object_class_property_set_description(oc, X86_MACHINE_PIT, + "Enable i8254 PIT"); + + object_class_property_add(oc, X86_MACHINE_PIC, "OnOffAuto", + x86_machine_get_pic, + x86_machine_set_pic, + NULL, NULL); + object_class_property_set_description(oc, X86_MACHINE_PIC, + "Enable i8259 PIC"); + object_class_property_add_str(oc, X86_MACHINE_OEM_ID, x86_machine_get_oem_id, x86_machine_set_oem_id); diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 0731f7041069..e4293d6d666a 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -15,7 +15,6 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" #include "hw/i386/pc.h" -#include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/hw.h" #include "hw/i386/apic-msidef.h" @@ -149,21 +148,9 @@ void xen_piix3_set_irq(void *opaque, int irq_num, int level) irq_num & 3, level); } -void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) +int xen_set_pci_link_route(uint8_t link, uint8_t irq) { - int i; - - /* Scan for updates to PCI link routes (0x60-0x63). */ - for (i = 0; i < len; i++) { - uint8_t v = (val >> (8 * i)) & 0xff; - if (v & 0x80) { - v = 0; - } - v &= 0xf; - if (((address + i) >= PIIX_PIRQCA) && ((address + i) <= PIIX_PIRQCD)) { - xen_set_pci_link_route(xen_domid, address + i - PIIX_PIRQCA, v); - } - } + return xendevicemodel_set_pci_link_route(xen_dmod, xen_domid, link, irq); } int xen_is_pirq_msi(uint32_t msi_data) diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 72028449bae0..7db0d94ec289 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/ide.h" +#include "hw/ide/pci.h" #include "hw/pci/pci.h" #include "hw/xen/xen_common.h" #include "migration/vmstate.h" @@ -134,6 +135,51 @@ static void pci_unplug_nics(PCIBus *bus) pci_for_each_device(bus, 0, unplug_nic, NULL); } +/* + * The Xen HVM unplug protocol [1] specifies a mechanism to allow guests to + * request unplug of 'aux' disks (which is stated to mean all IDE disks, + * except the primary master). + * + * NOTE: The semantics of what happens if unplug of all disks and 'aux' disks + * is simultaneously requested is not clear. The implementation assumes + * that an 'all' request overrides an 'aux' request. + * + * [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc + */ +static void pci_xen_ide_unplug(DeviceState *dev, bool aux) +{ + PCIIDEState *pci_ide; + int i; + IDEDevice *idedev; + IDEBus *idebus; + BlockBackend *blk; + + pci_ide = PCI_IDE(dev); + + for (i = aux ? 1 : 0; i < 4; i++) { + idebus = &pci_ide->bus[i / 2]; + blk = idebus->ifs[i % 2].blk; + + if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) { + if (!(i % 2)) { + idedev = idebus->master; + } else { + idedev = idebus->slave; + } + + blk_drain(blk); + blk_flush(blk); + + blk_detach_dev(blk, DEVICE(idedev)); + idebus->ifs[i % 2].blk = NULL; + idedev->conf.blk = NULL; + monitor_remove_blk(blk); + blk_unref(blk); + } + } + device_cold_reset(dev); +} + static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque) { uint32_t flags = *(uint32_t *)opaque; @@ -147,7 +193,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque) switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) { case PCI_CLASS_STORAGE_IDE: - pci_piix3_xen_ide_unplug(DEVICE(d), aux); + pci_xen_ide_unplug(DEVICE(d), aux); break; case PCI_CLASS_STORAGE_SCSI: diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c index 1ea95fa6012f..e62e06622b09 100644 --- a/hw/i386/xen/xen_pvdevice.c +++ b/hw/i386/xen/xen_pvdevice.c @@ -32,7 +32,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "trace.h" diff --git a/hw/ide/ahci_internal.h b/hw/ide/ahci_internal.h index 109de9e2d112..303fcd7235b1 100644 --- a/hw/ide/ahci_internal.h +++ b/hw/ide/ahci_internal.h @@ -26,7 +26,7 @@ #include "hw/ide/ahci.h" #include "hw/ide/internal.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #define AHCI_MEM_BAR_SIZE 0x1000 #define AHCI_MAX_PORTS 32 diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index b626199e3def..0a9aa6f0091b 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -98,11 +98,11 @@ cd_read_sector_sync(IDEState *s) switch (s->cd_sector_size) { case 2048: ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS, - s->io_buffer, ATAPI_SECTOR_SIZE); + ATAPI_SECTOR_SIZE, s->io_buffer, 0); break; case 2352: ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS, - s->io_buffer + 16, ATAPI_SECTOR_SIZE); + ATAPI_SECTOR_SIZE, s->io_buffer + 16, 0); if (ret >= 0) { cd_data_to_raw(s->io_buffer, s->lba); } @@ -318,7 +318,7 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) } } -/* start a CD-CDROM read command */ +/* start a CD-ROM read command */ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, int sector_size) { @@ -417,7 +417,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) ide_set_inactive(s, false); } -/* start a CD-CDROM read command with DMA */ +/* start a CD-ROM read command with DMA */ /* XXX: test if DMA is available */ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, int sector_size) diff --git a/hw/ide/core.c b/hw/ide/core.c index 3a5afff5d70d..5d1039378f1d 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; @@ -1629,6 +1648,13 @@ static bool cmd_set_features(IDEState *s, uint8_t cmd) /* XXX: valid for CDROM ? */ switch (s->feature) { + case 0x01: /* 8-bit I/O enable (CompactFlash) */ + case 0x81: /* 8-bit I/O disable (CompactFlash) */ + if (s->drive_kind != IDE_CFATA) { + goto abort_cmd; + } + s->io8 = !(s->feature & 0x80); + return true; case 0x02: /* write cache enable */ blk_set_enable_write_cache(s->blk, true); identify_data = (uint16_t *)s->identify_data; @@ -1641,7 +1667,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 +1734,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 +2081,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 }, @@ -2166,7 +2202,11 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr) hob = bus->cmd & (IDE_CTRL_HOB); switch (reg_num) { case ATA_IOPORT_RR_DATA: - ret = 0xff; + /* + * The pre-GRUB Solaris x86 bootloader relies upon inb + * consuming a word from the drive's sector buffer. + */ + ret = ide_data_readw(bus, addr) & 0xff; break; case ATA_IOPORT_RR_ERROR: if ((!bus->ifs[0].blk && !bus->ifs[1].blk) || @@ -2341,12 +2381,20 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) } p = s->data_ptr; - if (p + 2 > s->data_end) { - return; - } + if (s->io8) { + if (p + 1 > s->data_end) { + return; + } - *(uint16_t *)p = le16_to_cpu(val); - p += 2; + *p++ = val; + } else { + if (p + 2 > s->data_end) { + return; + } + + *(uint16_t *)p = le16_to_cpu(val); + p += 2; + } s->data_ptr = p; if (p >= s->data_end) { s->status &= ~DRQ_STAT; @@ -2368,12 +2416,20 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr) } p = s->data_ptr; - if (p + 2 > s->data_end) { - return 0; - } + if (s->io8) { + if (p + 1 > s->data_end) { + return 0; + } - ret = cpu_to_le16(*(uint16_t *)p); - p += 2; + ret = *p++; + } else { + if (p + 2 > s->data_end) { + return 0; + } + + ret = cpu_to_le16(*(uint16_t *)p); + p += 2; + } s->data_ptr = p; if (p >= s->data_end) { s->status &= ~DRQ_STAT; @@ -2531,8 +2587,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; @@ -2544,7 +2600,6 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, s->smart_selftest_count = 0; if (kind == IDE_CD) { blk_set_dev_ops(blk, &ide_cd_block_ops, s); - blk_set_guest_block_size(blk, 2048); } else { if (!blk_is_inserted(s->blk)) { error_setg(errp, "Device needs media, but drive is empty"); diff --git a/hw/ide/macio.c b/hw/ide/macio.c index f08318cf97f9..e604466acb11 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "hw/ppc/mac.h" #include "hw/ppc/mac_dbdma.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -267,7 +266,9 @@ static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size) switch (reg) { case 0x0: - if (size == 2) { + if (size == 1) { + retval = ide_data_readw(&d->bus, 0) & 0xFF; + } else if (size == 2) { retval = ide_data_readw(&d->bus, 0); } else if (size == 4) { retval = ide_data_readl(&d->bus, 0); diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 6df9b4cbbe1d..56c5be365514 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -175,7 +175,7 @@ static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value) case 0x00: /* Configuration Option Register */ s->opt = value & 0xcf; if (value & OPT_SRESET) { - device_legacy_reset(DEVICE(s)); + device_cold_reset(DEVICE(s)); } md_interrupt_update(s); break; @@ -318,7 +318,7 @@ static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value) case 0xe: /* Device Control */ s->ctrl = value; if (value & CTRL_SRST) { - device_legacy_reset(DEVICE(s)); + device_cold_reset(DEVICE(s)); } md_interrupt_update(s); break; @@ -543,7 +543,7 @@ static int dscm1xxxx_attach(PCMCIACardState *card) md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8); md->io_base = 0x0; - device_legacy_reset(DEVICE(md)); + device_cold_reset(DEVICE(md)); md_interrupt_update(md); return 0; @@ -553,7 +553,7 @@ static int dscm1xxxx_detach(PCMCIACardState *card) { MicroDriveState *md = MICRODRIVE(card); - device_legacy_reset(DEVICE(md)); + device_cold_reset(DEVICE(md)); return 0; } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index ce89fd0aa368..267dbf37db3a 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" @@ -32,6 +36,7 @@ #include "sysemu/blockdev.h" #include "sysemu/dma.h" +#include "hw/ide/piix.h" #include "hw/ide/pci.h" #include "trace.h" @@ -114,14 +119,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) @@ -173,41 +175,6 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp) } } -int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux) -{ - PCIIDEState *pci_ide; - int i; - IDEDevice *idedev; - IDEBus *idebus; - BlockBackend *blk; - - pci_ide = PCI_IDE(dev); - - for (i = aux ? 1 : 0; i < 4; i++) { - idebus = &pci_ide->bus[i / 2]; - blk = idebus->ifs[i % 2].blk; - - if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) { - if (!(i % 2)) { - idedev = idebus->master; - } else { - idedev = idebus->slave; - } - - blk_drain(blk); - blk_flush(blk); - - blk_detach_dev(blk, DEVICE(idedev)); - idebus->ifs[i % 2].blk = NULL; - idedev->conf.blk = NULL; - monitor_remove_blk(blk); - blk_unref(blk); - } - } - qdev_reset_all(dev); - return 0; -} - static void pci_piix_ide_exitfn(PCIDevice *dev) { PCIIDEState *d = PCI_IDE(dev); @@ -236,13 +203,7 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) } static const TypeInfo piix3_ide_info = { - .name = "piix3-ide", - .parent = TYPE_PCI_IDE, - .class_init = piix3_ide_class_init, -}; - -static const TypeInfo piix3_ide_xen_info = { - .name = "piix3-ide-xen", + .name = TYPE_PIIX3_IDE, .parent = TYPE_PCI_IDE, .class_init = piix3_ide_class_init, }; @@ -264,7 +225,7 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) } static const TypeInfo piix4_ide_info = { - .name = "piix4-ide", + .name = TYPE_PIIX4_IDE, .parent = TYPE_PCI_IDE, .class_init = piix4_ide_class_init, }; @@ -272,7 +233,6 @@ static const TypeInfo piix4_ide_info = { static void piix_ide_register_types(void) { type_register_static(&piix3_ide_info); - type_register_static(&piix3_ide_xen_info); type_register_static(&piix4_ide_info); } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 618045b85ace..6f6c7462f3b6 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -283,6 +283,11 @@ static void ide_cd_realize(IDEDevice *dev, Error **errp) ide_dev_initfn(dev, IDE_CD, errp); } +static void ide_cf_realize(IDEDevice *dev, Error **errp) +{ + ide_dev_initfn(dev, IDE_CFATA, errp); +} + #define DEFINE_IDE_DEV_PROPERTIES() \ DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \ DEFINE_BLOCK_ERROR_PROPERTIES(IDEDrive, dev.conf), \ @@ -341,6 +346,32 @@ static const TypeInfo ide_cd_info = { .class_init = ide_cd_class_init, }; +static Property ide_cf_properties[] = { + DEFINE_IDE_DEV_PROPERTIES(), + DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf), + DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans", + IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ide_cf_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); + + k->realize = ide_cf_realize; + dc->fw_name = "drive"; + dc->desc = "virtual CompactFlash card"; + device_class_set_props(dc, ide_cf_properties); +} + +static const TypeInfo ide_cf_info = { + .name = "ide-cf", + .parent = TYPE_IDE_DEVICE, + .instance_size = sizeof(IDEDrive), + .class_init = ide_cf_class_init, +}; + static void ide_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -365,6 +396,7 @@ static void ide_register_types(void) type_register_static(&ide_bus_info); type_register_static(&ide_hd_info); type_register_static(&ide_cd_info); + type_register_static(&ide_cf_info); type_register_static(&ide_device_type_info); } diff --git a/hw/ide/via.c b/hw/ide/via.c index 82def819c411..e1a429405db6 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -230,7 +230,7 @@ static void via_ide_class_init(ObjectClass *klass, void *data) } static const TypeInfo via_ide_info = { - .name = "via-ide", + .name = TYPE_VIA_IDE, .parent = TYPE_PCI_IDE, .class_init = via_ide_class_init, }; diff --git a/hw/input/adb.c b/hw/input/adb.c index 84331b9fce6f..214ae6f42b3e 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -43,7 +43,7 @@ static const char *adb_commands[] = { static void adb_device_reset(ADBDevice *d) { - qdev_reset_all(DEVICE(d)); + device_cold_reset(DEVICE(d)); } static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index 94f18be4cd51..ea7c07a2ba43 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/qdev-properties.h" +#include "hw/sysbus.h" #include "hw/input/ps2.h" #include "hw/input/lasips2.h" #include "exec/hwaddr.h" @@ -31,37 +32,31 @@ #include "exec/address-spaces.h" #include "migration/vmstate.h" #include "hw/irq.h" +#include "qapi/error.h" -struct LASIPS2State; -typedef struct LASIPS2Port { - struct LASIPS2State *parent; - MemoryRegion reg; - void *dev; - uint8_t id; - uint8_t control; - uint8_t buf; - bool loopback_rbne; - bool irq; -} LASIPS2Port; - -typedef struct LASIPS2State { - LASIPS2Port kbd; - LASIPS2Port mouse; - qemu_irq irq; -} LASIPS2State; +static const VMStateDescription vmstate_lasips2_port = { + .name = "lasips2-port", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(control, LASIPS2Port), + VMSTATE_UINT8(buf, LASIPS2Port), + VMSTATE_BOOL(loopback_rbne, LASIPS2Port), + VMSTATE_END_OF_LIST() + } +}; static const VMStateDescription vmstate_lasips2 = { .name = "lasips2", - .version_id = 0, - .minimum_version_id = 0, + .version_id = 1, + .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT8(kbd.control, LASIPS2State), - VMSTATE_UINT8(kbd.id, LASIPS2State), - VMSTATE_BOOL(kbd.irq, LASIPS2State), - VMSTATE_UINT8(mouse.control, LASIPS2State), - VMSTATE_UINT8(mouse.id, LASIPS2State), - VMSTATE_BOOL(mouse.irq, LASIPS2State), + VMSTATE_UINT8(int_status, LASIPS2State), + VMSTATE_STRUCT(kbd_port.parent_obj, LASIPS2State, 1, + vmstate_lasips2_port, LASIPS2Port), + VMSTATE_STRUCT(mouse_port.parent_obj, LASIPS2State, 1, + vmstate_lasips2_port, LASIPS2Port), VMSTATE_END_OF_LIST() } }; @@ -135,36 +130,50 @@ static const char *lasips2_write_reg_name(uint64_t addr) static void lasips2_update_irq(LASIPS2State *s) { - trace_lasips2_intr(s->kbd.irq | s->mouse.irq); - qemu_set_irq(s->irq, s->kbd.irq | s->mouse.irq); + int level = s->int_status ? 1 : 0; + + trace_lasips2_intr(level); + qemu_set_irq(s->irq, level); +} + +static void lasips2_set_irq(void *opaque, int n, int level) +{ + LASIPS2State *s = LASIPS2(opaque); + + if (level) { + s->int_status |= BIT(n); + } else { + s->int_status &= ~BIT(n); + } + + lasips2_update_irq(s); } static void lasips2_reg_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - LASIPS2Port *port = opaque; + LASIPS2Port *lp = LASIPS2_PORT(opaque); - trace_lasips2_reg_write(size, port->id, addr, + trace_lasips2_reg_write(size, lp->id, addr, lasips2_write_reg_name(addr), val); switch (addr & 0xc) { case REG_PS2_CONTROL: - port->control = val; + lp->control = val; break; case REG_PS2_XMTDATA: - if (port->control & LASIPS2_CONTROL_LOOPBACK) { - port->buf = val; - port->irq = true; - port->loopback_rbne = true; - lasips2_update_irq(port->parent); + if (lp->control & LASIPS2_CONTROL_LOOPBACK) { + lp->buf = val; + lp->loopback_rbne = true; + qemu_set_irq(lp->irq, 1); break; } - if (port->id) { - ps2_write_mouse(port->dev, val); + if (lp->id) { + ps2_write_mouse(PS2_MOUSE_DEVICE(lp->ps2dev), val); } else { - ps2_write_keyboard(port->dev, val); + ps2_write_keyboard(PS2_KBD_DEVICE(lp->ps2dev), val); } break; @@ -180,55 +189,53 @@ static void lasips2_reg_write(void *opaque, hwaddr addr, uint64_t val, static uint64_t lasips2_reg_read(void *opaque, hwaddr addr, unsigned size) { - LASIPS2Port *port = opaque; + LASIPS2Port *lp = LASIPS2_PORT(opaque); uint64_t ret = 0; switch (addr & 0xc) { case REG_PS2_ID: - ret = port->id; + ret = lp->id; break; case REG_PS2_RCVDATA: - if (port->control & LASIPS2_CONTROL_LOOPBACK) { - port->irq = false; - port->loopback_rbne = false; - lasips2_update_irq(port->parent); - ret = port->buf; + if (lp->control & LASIPS2_CONTROL_LOOPBACK) { + lp->loopback_rbne = false; + qemu_set_irq(lp->irq, 0); + ret = lp->buf; break; } - ret = ps2_read_data(port->dev); + ret = ps2_read_data(lp->ps2dev); break; case REG_PS2_CONTROL: - ret = port->control; + ret = lp->control; break; case REG_PS2_STATUS: - ret = LASIPS2_STATUS_DATSHD | LASIPS2_STATUS_CLKSHD; - if (port->control & LASIPS2_CONTROL_DIAG) { - if (!(port->control & LASIPS2_CONTROL_DATDIR)) { + if (lp->control & LASIPS2_CONTROL_DIAG) { + if (!(lp->control & LASIPS2_CONTROL_DATDIR)) { ret &= ~LASIPS2_STATUS_DATSHD; } - if (!(port->control & LASIPS2_CONTROL_CLKDIR)) { + if (!(lp->control & LASIPS2_CONTROL_CLKDIR)) { ret &= ~LASIPS2_STATUS_CLKSHD; } } - if (port->control & LASIPS2_CONTROL_LOOPBACK) { - if (port->loopback_rbne) { + if (lp->control & LASIPS2_CONTROL_LOOPBACK) { + if (lp->loopback_rbne) { ret |= LASIPS2_STATUS_RBNE; } } else { - if (!ps2_queue_empty(port->dev)) { + if (!ps2_queue_empty(lp->ps2dev)) { ret |= LASIPS2_STATUS_RBNE; } } - if (port->parent->kbd.irq || port->parent->mouse.irq) { + if (lp->lasips2->int_status) { ret |= LASIPS2_STATUS_CMPINTR; } break; @@ -238,9 +245,9 @@ static uint64_t lasips2_reg_read(void *opaque, hwaddr addr, unsigned size) __func__, addr); break; } - trace_lasips2_reg_read(size, port->id, addr, - lasips2_read_reg_name(addr), ret); + trace_lasips2_reg_read(size, lp->id, addr, + lasips2_read_reg_name(addr), ret); return ret; } @@ -251,38 +258,208 @@ static const MemoryRegionOps lasips2_reg_ops = { .min_access_size = 1, .max_access_size = 4, }, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void lasips2_realize(DeviceState *dev, Error **errp) +{ + LASIPS2State *s = LASIPS2(dev); + LASIPS2Port *lp; + + lp = LASIPS2_PORT(&s->kbd_port); + if (!(qdev_realize(DEVICE(lp), NULL, errp))) { + return; + } + + qdev_connect_gpio_out(DEVICE(lp), 0, + qdev_get_gpio_in_named(dev, "lasips2-port-input-irq", + lp->id)); + + lp = LASIPS2_PORT(&s->mouse_port); + if (!(qdev_realize(DEVICE(lp), NULL, errp))) { + return; + } + + qdev_connect_gpio_out(DEVICE(lp), 0, + qdev_get_gpio_in_named(dev, "lasips2-port-input-irq", + lp->id)); +} + +static void lasips2_init(Object *obj) +{ + LASIPS2State *s = LASIPS2(obj); + LASIPS2Port *lp; + + object_initialize_child(obj, "lasips2-kbd-port", &s->kbd_port, + TYPE_LASIPS2_KBD_PORT); + object_initialize_child(obj, "lasips2-mouse-port", &s->mouse_port, + TYPE_LASIPS2_MOUSE_PORT); + + lp = LASIPS2_PORT(&s->kbd_port); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &lp->reg); + lp = LASIPS2_PORT(&s->mouse_port); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &lp->reg); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + qdev_init_gpio_in_named(DEVICE(obj), lasips2_set_irq, + "lasips2-port-input-irq", 2); +} + +static void lasips2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = lasips2_realize; + dc->vmsd = &vmstate_lasips2; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static const TypeInfo lasips2_info = { + .name = TYPE_LASIPS2, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = lasips2_init, + .instance_size = sizeof(LASIPS2State), + .class_init = lasips2_class_init, +}; + +static void lasips2_port_set_irq(void *opaque, int n, int level) +{ + LASIPS2Port *s = LASIPS2_PORT(opaque); + + qemu_set_irq(s->irq, level); +} + +static void lasips2_port_realize(DeviceState *dev, Error **errp) +{ + LASIPS2Port *s = LASIPS2_PORT(dev); + + qdev_connect_gpio_out(DEVICE(s->ps2dev), PS2_DEVICE_IRQ, + qdev_get_gpio_in_named(dev, "ps2-input-irq", 0)); +} + +static void lasips2_port_init(Object *obj) +{ + LASIPS2Port *s = LASIPS2_PORT(obj); + + qdev_init_gpio_out(DEVICE(obj), &s->irq, 1); + qdev_init_gpio_in_named(DEVICE(obj), lasips2_port_set_irq, + "ps2-input-irq", 1); +} + +static void lasips2_port_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = lasips2_port_realize; +} + +static const TypeInfo lasips2_port_info = { + .name = TYPE_LASIPS2_PORT, + .parent = TYPE_DEVICE, + .instance_init = lasips2_port_init, + .instance_size = sizeof(LASIPS2Port), + .class_init = lasips2_port_class_init, + .class_size = sizeof(LASIPS2PortDeviceClass), + .abstract = true, }; -static void ps2dev_update_irq(void *opaque, int level) +static void lasips2_kbd_port_realize(DeviceState *dev, Error **errp) { - LASIPS2Port *port = opaque; - port->irq = level; - lasips2_update_irq(port->parent); + LASIPS2KbdPort *s = LASIPS2_KBD_PORT(dev); + LASIPS2Port *lp = LASIPS2_PORT(dev); + LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_GET_CLASS(lp); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->kbd), errp)) { + return; + } + + lp->ps2dev = PS2_DEVICE(&s->kbd); + lpdc->parent_realize(dev, errp); } -void lasips2_init(MemoryRegion *address_space, - hwaddr base, qemu_irq irq) +static void lasips2_kbd_port_init(Object *obj) { - LASIPS2State *s; + LASIPS2KbdPort *s = LASIPS2_KBD_PORT(obj); + LASIPS2Port *lp = LASIPS2_PORT(obj); - s = g_new0(LASIPS2State, 1); + memory_region_init_io(&lp->reg, obj, &lasips2_reg_ops, lp, "lasips2-kbd", + 0x100); - s->irq = irq; - s->mouse.id = 1; - s->kbd.parent = s; - s->mouse.parent = s; + object_initialize_child(obj, "kbd", &s->kbd, TYPE_PS2_KBD_DEVICE); - vmstate_register(NULL, base, &vmstate_lasips2, s); + lp->id = 0; + lp->lasips2 = container_of(s, LASIPS2State, kbd_port); +} - s->kbd.dev = ps2_kbd_init(ps2dev_update_irq, &s->kbd); - s->mouse.dev = ps2_mouse_init(ps2dev_update_irq, &s->mouse); +static void lasips2_kbd_port_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass); - memory_region_init_io(&s->kbd.reg, NULL, &lasips2_reg_ops, &s->kbd, - "lasips2-kbd", 0x100); - memory_region_add_subregion(address_space, base, &s->kbd.reg); + device_class_set_parent_realize(dc, lasips2_kbd_port_realize, + &lpdc->parent_realize); +} + +static const TypeInfo lasips2_kbd_port_info = { + .name = TYPE_LASIPS2_KBD_PORT, + .parent = TYPE_LASIPS2_PORT, + .instance_size = sizeof(LASIPS2KbdPort), + .instance_init = lasips2_kbd_port_init, + .class_init = lasips2_kbd_port_class_init, +}; - memory_region_init_io(&s->mouse.reg, NULL, &lasips2_reg_ops, &s->mouse, - "lasips2-mouse", 0x100); - memory_region_add_subregion(address_space, base + 0x100, &s->mouse.reg); +static void lasips2_mouse_port_realize(DeviceState *dev, Error **errp) +{ + LASIPS2MousePort *s = LASIPS2_MOUSE_PORT(dev); + LASIPS2Port *lp = LASIPS2_PORT(dev); + LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_GET_CLASS(lp); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mouse), errp)) { + return; + } + + lp->ps2dev = PS2_DEVICE(&s->mouse); + lpdc->parent_realize(dev, errp); +} + +static void lasips2_mouse_port_init(Object *obj) +{ + LASIPS2MousePort *s = LASIPS2_MOUSE_PORT(obj); + LASIPS2Port *lp = LASIPS2_PORT(obj); + + memory_region_init_io(&lp->reg, obj, &lasips2_reg_ops, lp, "lasips2-mouse", + 0x100); + + object_initialize_child(obj, "mouse", &s->mouse, TYPE_PS2_MOUSE_DEVICE); + + lp->id = 1; + lp->lasips2 = container_of(s, LASIPS2State, mouse_port); } + +static void lasips2_mouse_port_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass); + + device_class_set_parent_realize(dc, lasips2_mouse_port_realize, + &lpdc->parent_realize); +} + +static const TypeInfo lasips2_mouse_port_info = { + .name = TYPE_LASIPS2_MOUSE_PORT, + .parent = TYPE_LASIPS2_PORT, + .instance_size = sizeof(LASIPS2MousePort), + .instance_init = lasips2_mouse_port_init, + .class_init = lasips2_mouse_port_class_init, +}; + +static void lasips2_register_types(void) +{ + type_register_static(&lasips2_info); + type_register_static(&lasips2_port_info); + type_register_static(&lasips2_kbd_port_info); + type_register_static(&lasips2_mouse_port_info); +} + +type_init(lasips2_register_types) diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 4efdf75620fa..b92b63bedca3 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -29,7 +29,7 @@ #include "qapi/error.h" #include "hw/isa/isa.h" #include "migration/vmstate.h" -#include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/input/ps2.h" #include "hw/irq.h" #include "hw/input/i8042.h" @@ -39,49 +39,86 @@ #include "trace.h" -/* Keyboard Controller Commands */ -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ -#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ -#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ -#define KBD_CCMD_WRITE_OBUF 0xD2 -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ -#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ -#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ -#define KBD_CCMD_PULSE_BITS_3_0 0xF0 /* Pulse bits 3-0 of the output port P2. */ -#define KBD_CCMD_RESET 0xFE /* Pulse bit 0 of the output port P2 = CPU reset. */ -#define KBD_CCMD_NO_OP 0xFF /* Pulse no bits of the output port P2. */ +/* Keyboard Controller Commands */ + +/* Read mode bits */ +#define KBD_CCMD_READ_MODE 0x20 +/* Write mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 +/* Get controller version */ +#define KBD_CCMD_GET_VERSION 0xA1 +/* Disable mouse interface */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 +/* Enable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 +/* Mouse interface test */ +#define KBD_CCMD_TEST_MOUSE 0xA9 +/* Controller self test */ +#define KBD_CCMD_SELF_TEST 0xAA +/* Keyboard interface test */ +#define KBD_CCMD_KBD_TEST 0xAB +/* Keyboard interface disable */ +#define KBD_CCMD_KBD_DISABLE 0xAD +/* Keyboard interface enable */ +#define KBD_CCMD_KBD_ENABLE 0xAE +/* read input port */ +#define KBD_CCMD_READ_INPORT 0xC0 +/* read output port */ +#define KBD_CCMD_READ_OUTPORT 0xD0 +/* write output port */ +#define KBD_CCMD_WRITE_OUTPORT 0xD1 +#define KBD_CCMD_WRITE_OBUF 0xD2 +/* Write to output buffer as if initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 +/* Write the following byte to the mouse */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 +/* HP vectra only ? */ +#define KBD_CCMD_DISABLE_A20 0xDD +/* HP vectra only ? */ +#define KBD_CCMD_ENABLE_A20 0xDF +/* Pulse bits 3-0 of the output port P2. */ +#define KBD_CCMD_PULSE_BITS_3_0 0xF0 +/* Pulse bit 0 of the output port P2 = CPU reset. */ +#define KBD_CCMD_RESET 0xFE +/* Pulse no bits of the output port P2. */ +#define KBD_CCMD_NO_OP 0xFF /* Status Register Bits */ -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ + +/* Keyboard output buffer full */ +#define KBD_STAT_OBF 0x01 +/* Keyboard input buffer full */ +#define KBD_STAT_IBF 0x02 +/* Self test successful */ +#define KBD_STAT_SELFTEST 0x04 +/* Last write was a command write (0=data) */ +#define KBD_STAT_CMD 0x08 +/* Zero if keyboard locked */ +#define KBD_STAT_UNLOCKED 0x10 +/* Mouse output buffer full */ +#define KBD_STAT_MOUSE_OBF 0x20 +/* General receive/xmit timeout */ +#define KBD_STAT_GTO 0x40 +/* Parity error */ +#define KBD_STAT_PERR 0x80 /* Controller Mode Register Bits */ -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 + +/* Keyboard data generate IRQ1 */ +#define KBD_MODE_KBD_INT 0x01 +/* Mouse data generate IRQ12 */ +#define KBD_MODE_MOUSE_INT 0x02 +/* The system flag (?) */ +#define KBD_MODE_SYS 0x04 +/* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_NO_KEYLOCK 0x08 +/* Disable keyboard interface */ +#define KBD_MODE_DISABLE_KBD 0x10 +/* Disable mouse interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 +/* Scan code conversion to PC format */ +#define KBD_MODE_KCC 0x40 +#define KBD_MODE_RFU 0x80 /* Output Port Bits */ #define KBD_OUT_RESET 0x01 /* 1=normal mode, 0=reset */ @@ -89,7 +126,8 @@ #define KBD_OUT_OBF 0x10 /* Keyboard output buffer full */ #define KBD_OUT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -/* OSes typically write 0xdd/0xdf to turn the A20 line off and on. +/* + * OSes typically write 0xdd/0xdf to turn the A20 line off and on. * We make the default value of the outport include these four bits, * so that the subsection is rarely necessary. */ @@ -108,33 +146,11 @@ #define KBD_OBSRC_MOUSE 0x02 #define KBD_OBSRC_CTRL 0x04 -typedef struct KBDState { - uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ - uint8_t status; - uint8_t mode; - uint8_t outport; - uint32_t migration_flags; - uint32_t obsrc; - bool outport_present; - bool extended_state; - bool extended_state_loaded; - /* Bitmask of devices with data available. */ - uint8_t pending; - uint8_t obdata; - uint8_t cbdata; - uint8_t pending_tmp; - void *kbd; - void *mouse; - QEMUTimer *throttle_timer; - - qemu_irq irq_kbd; - qemu_irq irq_mouse; - qemu_irq a20_out; - hwaddr mask; -} KBDState; - -/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be - incorrect, but it avoids having to simulate exact delays */ + +/* + * XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be + * incorrect, but it avoids having to simulate exact delays + */ static void kbd_update_irq_lines(KBDState *s) { int irq_kbd_level, irq_mouse_level; @@ -154,8 +170,8 @@ static void kbd_update_irq_lines(KBDState *s) } } } - qemu_set_irq(s->irq_kbd, irq_kbd_level); - qemu_set_irq(s->irq_mouse, irq_mouse_level); + qemu_set_irq(s->irqs[I8042_KBD_IRQ], irq_kbd_level); + qemu_set_irq(s->irqs[I8042_MOUSE_IRQ], irq_mouse_level); } static void kbd_deassert_irq(KBDState *s) @@ -270,7 +286,7 @@ static void kbd_queue(KBDState *s, int b, int aux) s->pending |= aux ? KBD_PENDING_CTRL_AUX : KBD_PENDING_CTRL_KBD; kbd_safe_update_irq(s); } else { - ps2_queue(aux ? s->mouse : s->kbd, b); + ps2_queue(aux ? PS2_DEVICE(&s->ps2mouse) : PS2_DEVICE(&s->ps2kbd), b); } } @@ -302,21 +318,23 @@ static void kbd_write_command(void *opaque, hwaddr addr, trace_pckbd_kbd_write_command(val); - /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed + /* + * Bits 3-0 of the output port P2 of the keyboard controller may be pulsed * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE * command specify the output port bits to be pulsed. * 0: Bit should be pulsed. 1: Bit should not be modified. * The only useful version of this command is pulsing bit 0, * which does a CPU reset. */ - if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) { - if(!(val & 1)) + if ((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) { + if (!(val & 1)) { val = KBD_CCMD_RESET; - else + } else { val = KBD_CCMD_NO_OP; + } } - switch(val) { + switch (val) { case KBD_CCMD_READ_MODE: kbd_queue(s, s->mode, 0); break; @@ -390,9 +408,9 @@ static uint64_t kbd_read_data(void *opaque, hwaddr addr, timer_mod(s->throttle_timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000); } - s->obdata = ps2_read_data(s->kbd); + s->obdata = ps2_read_data(PS2_DEVICE(&s->ps2kbd)); } else if (s->obsrc & KBD_OBSRC_MOUSE) { - s->obdata = ps2_read_data(s->mouse); + s->obdata = ps2_read_data(PS2_DEVICE(&s->ps2mouse)); } else if (s->obsrc & KBD_OBSRC_CTRL) { s->obdata = kbd_dequeue(s); } @@ -409,16 +427,17 @@ static void kbd_write_data(void *opaque, hwaddr addr, trace_pckbd_kbd_write_data(val); - switch(s->write_cmd) { + switch (s->write_cmd) { case 0: - ps2_write_keyboard(s->kbd, val); + ps2_write_keyboard(&s->ps2kbd, val); /* sending data to the keyboard reenables PS/2 communication */ s->mode &= ~KBD_MODE_DISABLE_KBD; kbd_safe_update_irq(s); break; case KBD_CCMD_WRITE_MODE: s->mode = val; - ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0); + ps2_keyboard_set_translation(&s->ps2kbd, + (s->mode & KBD_MODE_KCC) != 0); /* * a write to the mode byte interrupt enable flags directly updates * the irq lines @@ -440,7 +459,7 @@ static void kbd_write_data(void *opaque, hwaddr addr, outport_write(s, val); break; case KBD_CCMD_WRITE_MOUSE: - ps2_write_mouse(s->mouse, val); + ps2_write_mouse(&s->ps2mouse, val); /* sending data to the mouse reenables PS/2 communication */ s->mode &= ~KBD_MODE_DISABLE_MOUSE; kbd_safe_update_irq(s); @@ -607,7 +626,7 @@ static const VMStateDescription vmstate_kbd = { VMSTATE_UINT8(pending_tmp, KBDState), VMSTATE_END_OF_LIST() }, - .subsections = (const VMStateDescription*[]) { + .subsections = (const VMStateDescription * []) { &vmstate_kbd_outport, &vmstate_kbd_extended_state, NULL @@ -619,10 +638,11 @@ static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size) { KBDState *s = opaque; - if (addr & s->mask) + if (addr & s->mask) { return kbd_read_status(s, 0, 1) & 0xff; - else + } else { return kbd_read_data(s, 0, 1) & 0xff; + } } static void kbd_mm_writefn(void *opaque, hwaddr addr, @@ -630,10 +650,11 @@ static void kbd_mm_writefn(void *opaque, hwaddr addr, { KBDState *s = opaque; - if (addr & s->mask) + if (addr & s->mask) { kbd_write_command(s, 0, value & 0xff, 1); - else + } else { kbd_write_data(s, 0, value & 0xff, 1); + } } @@ -645,42 +666,115 @@ static const MemoryRegionOps i8042_mmio_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, - MemoryRegion *region, ram_addr_t size, - hwaddr mask) +static void i8042_mmio_set_kbd_irq(void *opaque, int n, int level) +{ + MMIOKBDState *s = I8042_MMIO(opaque); + KBDState *ks = &s->kbd; + + kbd_update_kbd_irq(ks, level); +} + +static void i8042_mmio_set_mouse_irq(void *opaque, int n, int level) +{ + MMIOKBDState *s = I8042_MMIO(opaque); + KBDState *ks = &s->kbd; + + kbd_update_aux_irq(ks, level); +} + +static void i8042_mmio_reset(DeviceState *dev) +{ + MMIOKBDState *s = I8042_MMIO(dev); + KBDState *ks = &s->kbd; + + kbd_reset(ks); +} + +static void i8042_mmio_realize(DeviceState *dev, Error **errp) { - KBDState *s = g_new0(KBDState, 1); + MMIOKBDState *s = I8042_MMIO(dev); + KBDState *ks = &s->kbd; - s->irq_kbd = kbd_irq; - s->irq_mouse = mouse_irq; - s->mask = mask; + memory_region_init_io(&s->region, OBJECT(dev), &i8042_mmio_ops, ks, + "i8042", s->size); - s->extended_state = true; + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->region); - vmstate_register(NULL, 0, &vmstate_kbd, s); + if (!sysbus_realize(SYS_BUS_DEVICE(&ks->ps2kbd), errp)) { + return; + } - memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size); + if (!sysbus_realize(SYS_BUS_DEVICE(&ks->ps2mouse), errp)) { + return; + } - s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); - s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); - qemu_register_reset(kbd_reset, s); + qdev_connect_gpio_out(DEVICE(&ks->ps2kbd), PS2_DEVICE_IRQ, + qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq", + 0)); + + qdev_connect_gpio_out(DEVICE(&ks->ps2mouse), PS2_DEVICE_IRQ, + qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq", + 0)); } -struct ISAKBDState { - ISADevice parent_obj; +static void i8042_mmio_init(Object *obj) +{ + MMIOKBDState *s = I8042_MMIO(obj); + KBDState *ks = &s->kbd; + + ks->extended_state = true; - KBDState kbd; - bool kbd_throttle; - MemoryRegion io[2]; - uint8_t kbd_irq; - uint8_t mouse_irq; + object_initialize_child(obj, "ps2kbd", &ks->ps2kbd, TYPE_PS2_KBD_DEVICE); + object_initialize_child(obj, "ps2mouse", &ks->ps2mouse, + TYPE_PS2_MOUSE_DEVICE); + + qdev_init_gpio_out(DEVICE(obj), ks->irqs, 2); + qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_kbd_irq, + "ps2-kbd-input-irq", 1); + qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_mouse_irq, + "ps2-mouse-input-irq", 1); +} + +static Property i8042_mmio_properties[] = { + DEFINE_PROP_UINT64("mask", MMIOKBDState, kbd.mask, UINT64_MAX), + DEFINE_PROP_UINT32("size", MMIOKBDState, size, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_kbd_mmio = { + .name = "pckbd-mmio", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(kbd, MMIOKBDState, 0, vmstate_kbd, KBDState), + VMSTATE_END_OF_LIST() + } +}; + +static void i8042_mmio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = i8042_mmio_realize; + dc->reset = i8042_mmio_reset; + dc->vmsd = &vmstate_kbd_mmio; + device_class_set_props(dc, i8042_mmio_properties); + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static const TypeInfo i8042_mmio_info = { + .name = TYPE_I8042_MMIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = i8042_mmio_init, + .instance_size = sizeof(MMIOKBDState), + .class_init = i8042_mmio_class_init }; void i8042_isa_mouse_fake_event(ISAKBDState *isa) { KBDState *s = &isa->kbd; - ps2_mouse_fake_event(s->mouse); + ps2_mouse_fake_event(&s->ps2mouse); } void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out) @@ -718,6 +812,31 @@ static const MemoryRegionOps i8042_cmd_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static void i8042_set_kbd_irq(void *opaque, int n, int level) +{ + ISAKBDState *s = I8042(opaque); + KBDState *ks = &s->kbd; + + kbd_update_kbd_irq(ks, level); +} + +static void i8042_set_mouse_irq(void *opaque, int n, int level) +{ + ISAKBDState *s = I8042(opaque); + KBDState *ks = &s->kbd; + + kbd_update_aux_irq(ks, level); +} + + +static void i8042_reset(DeviceState *dev) +{ + ISAKBDState *s = I8042(dev); + KBDState *ks = &s->kbd; + + kbd_reset(ks); +} + static void i8042_initfn(Object *obj) { ISAKBDState *isa_s = I8042(obj); @@ -728,7 +847,17 @@ static void i8042_initfn(Object *obj) memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s, "i8042-cmd", 1); + object_initialize_child(obj, "ps2kbd", &s->ps2kbd, TYPE_PS2_KBD_DEVICE); + object_initialize_child(obj, "ps2mouse", &s->ps2mouse, + TYPE_PS2_MOUSE_DEVICE); + qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1); + + qdev_init_gpio_out(DEVICE(obj), s->irqs, 2); + qdev_init_gpio_in_named(DEVICE(obj), i8042_set_kbd_irq, + "ps2-kbd-input-irq", 1); + qdev_init_gpio_in_named(DEVICE(obj), i8042_set_mouse_irq, + "ps2-mouse-input-irq", 1); } static void i8042_realizefn(DeviceState *dev, Error **errp) @@ -749,14 +878,28 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) return; } - s->irq_kbd = isa_get_irq(isadev, isa_s->kbd_irq); - s->irq_mouse = isa_get_irq(isadev, isa_s->mouse_irq); + isa_connect_gpio_out(isadev, I8042_KBD_IRQ, isa_s->kbd_irq); + isa_connect_gpio_out(isadev, I8042_MOUSE_IRQ, isa_s->mouse_irq); isa_register_ioport(isadev, isa_s->io + 0, 0x60); isa_register_ioport(isadev, isa_s->io + 1, 0x64); - s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); - s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ps2kbd), errp)) { + return; + } + + qdev_connect_gpio_out(DEVICE(&s->ps2kbd), PS2_DEVICE_IRQ, + qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq", + 0)); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ps2mouse), errp)) { + return; + } + + qdev_connect_gpio_out(DEVICE(&s->ps2mouse), PS2_DEVICE_IRQ, + qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq", + 0)); + if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) { warn_report(TYPE_I8042 ": can't enable kbd-throttle without" " extended-state, disabling kbd-throttle"); @@ -764,12 +907,11 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, kbd_throttle_timeout, s); } - qemu_register_reset(kbd_reset, s); } -static void i8042_build_aml(ISADevice *isadev, Aml *scope) +static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope) { - ISAKBDState *isa_s = I8042(isadev); + ISAKBDState *isa_s = I8042(adev); Aml *kbd; Aml *mou; Aml *crs; @@ -807,12 +949,13 @@ static Property i8042_properties[] = { static void i8042_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); device_class_set_props(dc, i8042_properties); + dc->reset = i8042_reset; dc->realize = i8042_realizefn; dc->vmsd = &vmstate_kbd_isa; - isa->build_aml = i8042_build_aml; + adevc->build_dev_aml = i8042_build_aml; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } @@ -822,11 +965,16 @@ static const TypeInfo i8042_info = { .instance_size = sizeof(ISAKBDState), .instance_init = i8042_initfn, .class_init = i8042_class_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void i8042_register_types(void) { type_register_static(&i8042_info); + type_register_static(&i8042_mmio_info); } type_init(i8042_register_types) diff --git a/hw/input/pl050.c b/hw/input/pl050.c index d279b6c1488c..ec5e19285e3b 100644 --- a/hw/input/pl050.c +++ b/hw/input/pl050.c @@ -7,30 +7,24 @@ * This code is licensed under the GPL. */ +/* + * QEMU interface: + * + sysbus MMIO region 0: MemoryRegion defining the PL050 registers + * + Named GPIO input "ps2-input-irq": set to 1 if the downstream PS2 device + * has asserted its irq + * + sysbus IRQ 0: PL050 output irq + */ + #include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/input/ps2.h" +#include "hw/input/pl050.h" #include "hw/irq.h" #include "qemu/log.h" #include "qemu/module.h" #include "qom/object.h" -#define TYPE_PL050 "pl050" -OBJECT_DECLARE_SIMPLE_TYPE(PL050State, PL050) - -struct PL050State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - void *dev; - uint32_t cr; - uint32_t clk; - uint32_t last; - int pending; - qemu_irq irq; - bool is_mouse; -}; static const VMStateDescription vmstate_pl050 = { .name = "pl050", @@ -53,26 +47,34 @@ static const VMStateDescription vmstate_pl050 = { #define PL050_KMIC (1 << 1) #define PL050_KMID (1 << 0) -static const unsigned char pl050_id[] = -{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; +static const unsigned char pl050_id[] = { + 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 +}; -static void pl050_update(void *opaque, int level) +static void pl050_update_irq(PL050State *s) +{ + int level = (s->pending && (s->cr & 0x10) != 0) + || (s->cr & 0x08) != 0; + + qemu_set_irq(s->irq, level); +} + +static void pl050_set_irq(void *opaque, int n, int level) { PL050State *s = (PL050State *)opaque; - int raise; s->pending = level; - raise = (s->pending && (s->cr & 0x10) != 0) - || (s->cr & 0x08) != 0; - qemu_set_irq(s->irq, raise); + pl050_update_irq(s); } static uint64_t pl050_read(void *opaque, hwaddr offset, unsigned size) { PL050State *s = (PL050State *)opaque; - if (offset >= 0xfe0 && offset < 0x1000) + + if (offset >= 0xfe0 && offset < 0x1000) { return pl050_id[(offset - 0xfe0) >> 2]; + } switch (offset >> 2) { case 0: /* KMICR */ @@ -88,16 +90,19 @@ static uint64_t pl050_read(void *opaque, hwaddr offset, val = (val ^ (val >> 1)) & 1; stat = PL050_TXEMPTY; - if (val) + if (val) { stat |= PL050_RXPARITY; - if (s->pending) + } + if (s->pending) { stat |= PL050_RXFULL; + } return stat; } case 2: /* KMIDATA */ - if (s->pending) - s->last = ps2_read_data(s->dev); + if (s->pending) { + s->last = ps2_read_data(s->ps2dev); + } return s->last; case 3: /* KMICLKDIV */ return s->clk; @@ -114,19 +119,20 @@ static void pl050_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PL050State *s = (PL050State *)opaque; + switch (offset >> 2) { case 0: /* KMICR */ s->cr = value; - pl050_update(s, s->pending); + pl050_update_irq(s); /* ??? Need to implement the enable/disable bit. */ break; case 2: /* KMIDATA */ /* ??? This should toggle the TX interrupt line. */ /* ??? This means kbd/mouse can block each other. */ if (s->is_mouse) { - ps2_write_mouse(s->dev, value); + ps2_write_mouse(PS2_MOUSE_DEVICE(s->ps2dev), value); } else { - ps2_write_keyboard(s->dev, value); + ps2_write_keyboard(PS2_KBD_DEVICE(s->ps2dev), value); } break; case 3: /* KMICLKDIV */ @@ -146,44 +152,103 @@ static const MemoryRegionOps pl050_ops = { static void pl050_realize(DeviceState *dev, Error **errp) { PL050State *s = PL050(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - memory_region_init_io(&s->iomem, OBJECT(s), &pl050_ops, s, "pl050", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - if (s->is_mouse) { - s->dev = ps2_mouse_init(pl050_update, s); - } else { - s->dev = ps2_kbd_init(pl050_update, s); + qdev_connect_gpio_out(DEVICE(s->ps2dev), PS2_DEVICE_IRQ, + qdev_get_gpio_in_named(dev, "ps2-input-irq", 0)); +} + +static void pl050_kbd_realize(DeviceState *dev, Error **errp) +{ + PL050DeviceClass *pdc = PL050_GET_CLASS(dev); + PL050KbdState *s = PL050_KBD_DEVICE(dev); + PL050State *ps = PL050(dev); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->kbd), errp)) { + return; } + + ps->ps2dev = PS2_DEVICE(&s->kbd); + pdc->parent_realize(dev, errp); } -static void pl050_keyboard_init(Object *obj) +static void pl050_kbd_init(Object *obj) { - PL050State *s = PL050(obj); + PL050KbdState *s = PL050_KBD_DEVICE(obj); + PL050State *ps = PL050(obj); - s->is_mouse = false; + ps->is_mouse = false; + object_initialize_child(obj, "kbd", &s->kbd, TYPE_PS2_KBD_DEVICE); +} + +static void pl050_mouse_realize(DeviceState *dev, Error **errp) +{ + PL050DeviceClass *pdc = PL050_GET_CLASS(dev); + PL050MouseState *s = PL050_MOUSE_DEVICE(dev); + PL050State *ps = PL050(dev); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mouse), errp)) { + return; + } + + ps->ps2dev = PS2_DEVICE(&s->mouse); + pdc->parent_realize(dev, errp); } static void pl050_mouse_init(Object *obj) { - PL050State *s = PL050(obj); + PL050MouseState *s = PL050_MOUSE_DEVICE(obj); + PL050State *ps = PL050(obj); - s->is_mouse = true; + ps->is_mouse = true; + object_initialize_child(obj, "mouse", &s->mouse, TYPE_PS2_MOUSE_DEVICE); +} + +static void pl050_kbd_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PL050DeviceClass *pdc = PL050_CLASS(oc); + + device_class_set_parent_realize(dc, pl050_kbd_realize, + &pdc->parent_realize); } static const TypeInfo pl050_kbd_info = { - .name = "pl050_keyboard", + .name = TYPE_PL050_KBD_DEVICE, .parent = TYPE_PL050, - .instance_init = pl050_keyboard_init, + .instance_init = pl050_kbd_init, + .instance_size = sizeof(PL050KbdState), + .class_init = pl050_kbd_class_init, }; +static void pl050_mouse_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PL050DeviceClass *pdc = PL050_CLASS(oc); + + device_class_set_parent_realize(dc, pl050_mouse_realize, + &pdc->parent_realize); +} + static const TypeInfo pl050_mouse_info = { - .name = "pl050_mouse", + .name = TYPE_PL050_MOUSE_DEVICE, .parent = TYPE_PL050, .instance_init = pl050_mouse_init, + .instance_size = sizeof(PL050MouseState), + .class_init = pl050_mouse_class_init, }; +static void pl050_init(Object *obj) +{ + PL050State *s = PL050(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &pl050_ops, s, "pl050", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + qdev_init_gpio_in_named(DEVICE(obj), pl050_set_irq, "ps2-input-irq", 1); +} + static void pl050_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -195,7 +260,10 @@ static void pl050_class_init(ObjectClass *oc, void *data) static const TypeInfo pl050_type_info = { .name = TYPE_PL050, .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = pl050_init, .instance_size = sizeof(PL050State), + .class_init = pl050_class_init, + .class_size = sizeof(PL050DeviceClass), .abstract = true, .class_init = pl050_class_init, }; diff --git a/hw/input/ps2.c b/hw/input/ps2.c index c16df1de7aee..3253ab6a92cd 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -24,61 +24,59 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "hw/irq.h" +#include "hw/sysbus.h" #include "hw/input/ps2.h" #include "migration/vmstate.h" #include "ui/console.h" #include "ui/input.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" +#include "qapi/error.h" #include "trace.h" /* Keyboard Commands */ -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_ECHO 0xEE -#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ -#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ -#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_ECHO 0xEE +#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ #define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */ #define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */ /* Keyboard Replies */ -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ID 0xAB /* Keyboard ID */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ID 0xAB /* Keyboard ID */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ /* Mouse Commands */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_POLL 0xEB /* Poll */ -#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ -#define AUX_SET_WRAP 0xEE /* Set wrap mode */ -#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ -#define AUX_GET_TYPE 0xF2 /* Get type */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_SET_DEFAULT 0xF6 -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_POLL 0xEB /* Poll */ +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ +#define AUX_GET_TYPE 0xF2 /* Get type */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_SET_DEFAULT 0xF6 +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ #define MOUSE_STATUS_REMOTE 0x40 #define MOUSE_STATUS_ENABLED 0x20 #define MOUSE_STATUS_SCALE21 0x10 -/* - * PS/2 buffer size. Keep 256 bytes for compatibility with - * older QEMU versions. - */ -#define PS2_BUFFER_SIZE 256 #define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */ #define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */ @@ -90,43 +88,6 @@ #define MOD_SHIFT_R (1 << 4) #define MOD_ALT_R (1 << 5) -typedef struct { - uint8_t data[PS2_BUFFER_SIZE]; - int rptr, wptr, cwptr, count; -} PS2Queue; - -struct PS2State { - PS2Queue queue; - int32_t write_cmd; - void (*update_irq)(void *, int); - void *update_arg; -}; - -typedef struct { - PS2State common; - int scan_enabled; - int translate; - int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ - int ledstate; - bool need_high_bit; - unsigned int modifiers; /* bitmask of MOD_* constants above */ -} PS2KbdState; - -typedef struct { - PS2State common; - uint8_t mouse_status; - uint8_t mouse_resolution; - uint8_t mouse_sample_rate; - uint8_t mouse_wrap; - uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ - uint8_t mouse_detect_state; - int mouse_dx; /* current values, needed for 'poll' mode */ - int mouse_dy; - int mouse_dz; - int mouse_dw; - uint8_t mouse_buttons; -} PS2MouseState; - static uint8_t translate_table[256] = { 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, @@ -212,9 +173,14 @@ void ps2_queue_noirq(PS2State *s, int b) q->count++; } -void ps2_raise_irq(PS2State *s) +static void ps2_raise_irq(PS2State *s) +{ + qemu_set_irq(s->irq, 1); +} + +static void ps2_lower_irq(PS2State *s) { - s->update_irq(s->update_arg, 1); + qemu_set_irq(s->irq, 0); } void ps2_queue(PS2State *s, int b) @@ -324,6 +290,7 @@ static void ps2_cqueue_reset(PS2State *s) static void ps2_put_keycode(void *opaque, int keycode) { PS2KbdState *s = opaque; + PS2State *ps = PS2_DEVICE(s); trace_ps2_put_keycode(opaque, keycode); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); @@ -332,13 +299,13 @@ static void ps2_put_keycode(void *opaque, int keycode) if (keycode == 0xf0) { s->need_high_bit = true; } else if (s->need_high_bit) { - ps2_queue(&s->common, translate_table[keycode] | 0x80); + ps2_queue(ps, translate_table[keycode] | 0x80); s->need_high_bit = false; } else { - ps2_queue(&s->common, translate_table[keycode]); + ps2_queue(ps, translate_table[keycode]); } } else { - ps2_queue(&s->common, keycode); + ps2_queue(ps, keycode); } } @@ -436,8 +403,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, } } } else { - if (qcode < qemu_input_map_qcode_to_atset1_len) + if (qcode < qemu_input_map_qcode_to_atset1_len) { keycode = qemu_input_map_qcode_to_atset1[qcode]; + } if (keycode) { if (keycode & 0xff00) { ps2_put_keycode(s, keycode >> 8); @@ -530,8 +498,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, } } } else { - if (qcode < qemu_input_map_qcode_to_atset2_len) + if (qcode < qemu_input_map_qcode_to_atset2_len) { keycode = qemu_input_map_qcode_to_atset2[qcode]; + } if (keycode) { if (keycode & 0xff00) { ps2_put_keycode(s, keycode >> 8); @@ -546,8 +515,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, } } } else if (s->scancode_set == 3) { - if (qcode < qemu_input_map_qcode_to_atset3_len) + if (qcode < qemu_input_map_qcode_to_atset3_len) { keycode = qemu_input_map_qcode_to_atset3[qcode]; + } if (keycode) { /* FIXME: break code should be configured on a key by key basis */ if (!key->down) { @@ -569,8 +539,10 @@ uint32_t ps2_read_data(PS2State *s) trace_ps2_read_data(s); q = &s->queue; if (q->count == 0) { - /* NOTE: if no data left, we return the last keyboard one - (needed for EMM386) */ + /* + * NOTE: if no data left, we return the last keyboard one + * (needed for EMM386) + */ /* XXX: need a timer to do things correctly */ index = q->rptr - 1; if (index < 0) { @@ -588,10 +560,10 @@ uint32_t ps2_read_data(PS2State *s) q->cwptr = -1; } /* reading deasserts IRQ */ - s->update_irq(s->update_arg, 0); + ps2_lower_irq(s); /* reassert IRQs if data left */ if (q->count) { - s->update_irq(s->update_arg, 1); + ps2_raise_irq(s); } } return val; @@ -606,119 +578,123 @@ static void ps2_set_ledstate(PS2KbdState *s, int ledstate) static void ps2_reset_keyboard(PS2KbdState *s) { + PS2State *ps2 = PS2_DEVICE(s); + trace_ps2_reset_keyboard(s); s->scan_enabled = 1; s->scancode_set = 2; - ps2_reset_queue(&s->common); + ps2_reset_queue(ps2); ps2_set_ledstate(s, 0); } -void ps2_write_keyboard(void *opaque, int val) +void ps2_write_keyboard(PS2KbdState *s, int val) { - PS2KbdState *s = (PS2KbdState *)opaque; + PS2State *ps2 = PS2_DEVICE(s); - trace_ps2_write_keyboard(opaque, val); - ps2_cqueue_reset(&s->common); - switch(s->common.write_cmd) { + trace_ps2_write_keyboard(s, val); + ps2_cqueue_reset(ps2); + switch (ps2->write_cmd) { default: case -1: - switch(val) { + switch (val) { case 0x00: - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; case 0x05: - ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); + ps2_cqueue_1(ps2, KBD_REPLY_RESEND); break; case KBD_CMD_GET_ID: /* We emulate a MF2 AT keyboard here */ - ps2_cqueue_3(&s->common, KBD_REPLY_ACK, KBD_REPLY_ID, - s->translate ? 0x41 : 0x83); + ps2_cqueue_3(ps2, KBD_REPLY_ACK, KBD_REPLY_ID, + s->translate ? 0x41 : 0x83); break; case KBD_CMD_ECHO: - ps2_cqueue_1(&s->common, KBD_CMD_ECHO); + ps2_cqueue_1(ps2, KBD_CMD_ECHO); break; case KBD_CMD_ENABLE: s->scan_enabled = 1; - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; case KBD_CMD_SCANCODE: case KBD_CMD_SET_LEDS: case KBD_CMD_SET_RATE: case KBD_CMD_SET_MAKE_BREAK: - s->common.write_cmd = val; - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2->write_cmd = val; + ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; case KBD_CMD_RESET_DISABLE: ps2_reset_keyboard(s); s->scan_enabled = 0; - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; case KBD_CMD_RESET_ENABLE: ps2_reset_keyboard(s); s->scan_enabled = 1; - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; case KBD_CMD_RESET: ps2_reset_keyboard(s); - ps2_cqueue_2(&s->common, - KBD_REPLY_ACK, - KBD_REPLY_POR); + ps2_cqueue_2(ps2, + KBD_REPLY_ACK, + KBD_REPLY_POR); break; case KBD_CMD_SET_TYPEMATIC: - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; default: - ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); + ps2_cqueue_1(ps2, KBD_REPLY_RESEND); break; } break; case KBD_CMD_SET_MAKE_BREAK: - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; + ps2_cqueue_1(ps2, KBD_REPLY_ACK); + ps2->write_cmd = -1; break; case KBD_CMD_SCANCODE: if (val == 0) { - ps2_cqueue_2(&s->common, KBD_REPLY_ACK, s->translate ? + ps2_cqueue_2(ps2, KBD_REPLY_ACK, s->translate ? translate_table[s->scancode_set] : s->scancode_set); } else if (val >= 1 && val <= 3) { s->scancode_set = val; - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); + ps2_cqueue_1(ps2, KBD_REPLY_ACK); } else { - ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); + ps2_cqueue_1(ps2, KBD_REPLY_RESEND); } - s->common.write_cmd = -1; + ps2->write_cmd = -1; break; case KBD_CMD_SET_LEDS: ps2_set_ledstate(s, val); - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; + ps2_cqueue_1(ps2, KBD_REPLY_ACK); + ps2->write_cmd = -1; break; case KBD_CMD_SET_RATE: - ps2_cqueue_1(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; + ps2_cqueue_1(ps2, KBD_REPLY_ACK); + ps2->write_cmd = -1; break; } } -/* Set the scancode translation mode. - 0 = raw scancodes. - 1 = translated scancodes (used by qemu internally). */ +/* + * Set the scancode translation mode. + * 0 = raw scancodes. + * 1 = translated scancodes (used by qemu internally). + */ -void ps2_keyboard_set_translation(void *opaque, int mode) +void ps2_keyboard_set_translation(PS2KbdState *s, int mode) { - PS2KbdState *s = (PS2KbdState *)opaque; - trace_ps2_keyboard_set_translation(opaque, mode); + trace_ps2_keyboard_set_translation(s, mode); s->translate = mode; } static int ps2_mouse_send_packet(PS2MouseState *s) { + PS2State *ps2 = PS2_DEVICE(s); /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ const int needed = s->mouse_type ? 4 : 3; unsigned int b; int dx1, dy1, dz1, dw1; - if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { + if (PS2_QUEUE_SIZE - ps2->queue.count < needed) { return 0; } @@ -727,31 +703,34 @@ static int ps2_mouse_send_packet(PS2MouseState *s) dz1 = s->mouse_dz; dw1 = s->mouse_dw; /* XXX: increase range to 8 bits ? */ - if (dx1 > 127) + if (dx1 > 127) { dx1 = 127; - else if (dx1 < -127) + } else if (dx1 < -127) { dx1 = -127; - if (dy1 > 127) + } + if (dy1 > 127) { dy1 = 127; - else if (dy1 < -127) + } else if (dy1 < -127) { dy1 = -127; + } b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); - ps2_queue_noirq(&s->common, b); - ps2_queue_noirq(&s->common, dx1 & 0xff); - ps2_queue_noirq(&s->common, dy1 & 0xff); + ps2_queue_noirq(ps2, b); + ps2_queue_noirq(ps2, dx1 & 0xff); + ps2_queue_noirq(ps2, dy1 & 0xff); /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { + switch (s->mouse_type) { default: /* Just ignore the wheels if not supported */ s->mouse_dz = 0; s->mouse_dw = 0; break; case 3: - if (dz1 > 127) + if (dz1 > 127) { dz1 = 127; - else if (dz1 < -127) - dz1 = -127; - ps2_queue_noirq(&s->common, dz1 & 0xff); + } else if (dz1 < -127) { + dz1 = -127; + } + ps2_queue_noirq(ps2, dz1 & 0xff); s->mouse_dz -= dz1; s->mouse_dw = 0; break; @@ -787,11 +766,11 @@ static int ps2_mouse_send_packet(PS2MouseState *s) b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); s->mouse_dz -= dz1; } - ps2_queue_noirq(&s->common, b); + ps2_queue_noirq(ps2, b); break; } - ps2_raise_irq(&s->common); + ps2_raise_irq(ps2); trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); /* update deltas */ @@ -816,8 +795,9 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, InputBtnEvent *btn; /* check if deltas are recorded when disabled */ - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { return; + } switch (evt->type) { case INPUT_EVENT_KIND_REL: @@ -868,8 +848,10 @@ static void ps2_mouse_sync(DeviceState *dev) qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); } if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ + /* + * if not remote, send event. Multiple events are sent if + * too big deltas + */ while (ps2_mouse_send_packet(s)) { if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && s->mouse_dw == 0) { @@ -879,96 +861,95 @@ static void ps2_mouse_sync(DeviceState *dev) } } -void ps2_mouse_fake_event(void *opaque) +void ps2_mouse_fake_event(PS2MouseState *s) { - PS2MouseState *s = opaque; - trace_ps2_mouse_fake_event(opaque); + trace_ps2_mouse_fake_event(s); s->mouse_dx++; - ps2_mouse_sync(opaque); + ps2_mouse_sync(DEVICE(s)); } -void ps2_write_mouse(void *opaque, int val) +void ps2_write_mouse(PS2MouseState *s, int val) { - PS2MouseState *s = (PS2MouseState *)opaque; + PS2State *ps2 = PS2_DEVICE(s); - trace_ps2_write_mouse(opaque, val); - switch(s->common.write_cmd) { + trace_ps2_write_mouse(s, val); + switch (ps2->write_cmd) { default: case -1: /* mouse command */ if (s->mouse_wrap) { if (val == AUX_RESET_WRAP) { s->mouse_wrap = 0; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); return; } else if (val != AUX_RESET) { - ps2_queue(&s->common, val); + ps2_queue(ps2, val); return; } } - switch(val) { + switch (val) { case AUX_SET_SCALE11: s->mouse_status &= ~MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_SET_SCALE21: s->mouse_status |= MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_SET_STREAM: s->mouse_status &= ~MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_SET_WRAP: s->mouse_wrap = 1; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_SET_REMOTE: s->mouse_status |= MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_GET_TYPE: - ps2_queue_2(&s->common, + ps2_queue_2(ps2, AUX_ACK, s->mouse_type); break; case AUX_SET_RES: case AUX_SET_SAMPLE: - s->common.write_cmd = val; - ps2_queue(&s->common, AUX_ACK); + ps2->write_cmd = val; + ps2_queue(ps2, AUX_ACK); break; case AUX_GET_SCALE: - ps2_queue_4(&s->common, + ps2_queue_4(ps2, AUX_ACK, s->mouse_status, s->mouse_resolution, s->mouse_sample_rate); break; case AUX_POLL: - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); ps2_mouse_send_packet(s); break; case AUX_ENABLE_DEV: s->mouse_status |= MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_DISABLE_DEV: s->mouse_status &= ~MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_SET_DEFAULT: s->mouse_sample_rate = 100; s->mouse_resolution = 2; s->mouse_status = 0; - ps2_queue(&s->common, AUX_ACK); + ps2_queue(ps2, AUX_ACK); break; case AUX_RESET: s->mouse_sample_rate = 100; s->mouse_resolution = 2; s->mouse_status = 0; s->mouse_type = 0; - ps2_reset_queue(&s->common); - ps2_queue_3(&s->common, + ps2_reset_queue(ps2); + ps2_queue_3(ps2, AUX_ACK, 0xaa, s->mouse_type); @@ -980,47 +961,59 @@ void ps2_write_mouse(void *opaque, int val) case AUX_SET_SAMPLE: s->mouse_sample_rate = val; /* detect IMPS/2 or IMEX */ - switch(s->mouse_detect_state) { + switch (s->mouse_detect_state) { default: case 0: - if (val == 200) + if (val == 200) { s->mouse_detect_state = 1; + } break; case 1: - if (val == 100) + if (val == 100) { s->mouse_detect_state = 2; - else if (val == 200) + } else if (val == 200) { s->mouse_detect_state = 3; - else + } else { s->mouse_detect_state = 0; + } break; case 2: - if (val == 80) + if (val == 80) { s->mouse_type = 3; /* IMPS/2 */ + } s->mouse_detect_state = 0; break; case 3: - if (val == 80) + if (val == 80) { s->mouse_type = 4; /* IMEX */ + } s->mouse_detect_state = 0; break; } - ps2_queue(&s->common, AUX_ACK); - s->common.write_cmd = -1; + ps2_queue(ps2, AUX_ACK); + ps2->write_cmd = -1; break; case AUX_SET_RES: s->mouse_resolution = val; - ps2_queue(&s->common, AUX_ACK); - s->common.write_cmd = -1; + ps2_queue(ps2, AUX_ACK); + ps2->write_cmd = -1; break; } } -static void ps2_common_reset(PS2State *s) +static void ps2_reset_hold(Object *obj) { + PS2State *s = PS2_DEVICE(obj); + s->write_cmd = -1; ps2_reset_queue(s); - s->update_irq(s->update_arg, 0); +} + +static void ps2_reset_exit(Object *obj) +{ + PS2State *s = PS2_DEVICE(obj); + + ps2_lower_irq(s); } static void ps2_common_post_load(PS2State *s) @@ -1049,24 +1042,34 @@ static void ps2_common_post_load(PS2State *s) q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1; } -static void ps2_kbd_reset(void *opaque) +static void ps2_kbd_reset_hold(Object *obj) { - PS2KbdState *s = (PS2KbdState *) opaque; + PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj); + PS2KbdState *s = PS2_KBD_DEVICE(obj); + + trace_ps2_kbd_reset(s); + + if (ps2dc->parent_phases.hold) { + ps2dc->parent_phases.hold(obj); + } - trace_ps2_kbd_reset(opaque); - ps2_common_reset(&s->common); s->scan_enabled = 1; s->translate = 0; s->scancode_set = 2; s->modifiers = 0; } -static void ps2_mouse_reset(void *opaque) +static void ps2_mouse_reset_hold(Object *obj) { - PS2MouseState *s = (PS2MouseState *) opaque; + PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj); + PS2MouseState *s = PS2_MOUSE_DEVICE(obj); + + trace_ps2_mouse_reset(s); + + if (ps2dc->parent_phases.hold) { + ps2dc->parent_phases.hold(obj); + } - trace_ps2_mouse_reset(opaque); - ps2_common_reset(&s->common); s->mouse_status = 0; s->mouse_resolution = 0; s->mouse_sample_rate = 0; @@ -1141,26 +1144,28 @@ static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { static bool ps2_keyboard_cqueue_needed(void *opaque) { PS2KbdState *s = opaque; + PS2State *ps2 = PS2_DEVICE(s); - return s->common.queue.cwptr != -1; /* the queue is mostly empty */ + return ps2->queue.cwptr != -1; /* the queue is mostly empty */ } static const VMStateDescription vmstate_ps2_keyboard_cqueue = { .name = "ps2kbd/command_reply_queue", .needed = ps2_keyboard_cqueue_needed, .fields = (VMStateField[]) { - VMSTATE_INT32(common.queue.cwptr, PS2KbdState), + VMSTATE_INT32(parent_obj.queue.cwptr, PS2KbdState), VMSTATE_END_OF_LIST() } }; -static int ps2_kbd_post_load(void* opaque, int version_id) +static int ps2_kbd_post_load(void *opaque, int version_id) { - PS2KbdState *s = (PS2KbdState*)opaque; - PS2State *ps2 = &s->common; + PS2KbdState *s = (PS2KbdState *)opaque; + PS2State *ps2 = PS2_DEVICE(s); - if (version_id == 2) - s->scancode_set=2; + if (version_id == 2) { + s->scancode_set = 2; + } ps2_common_post_load(ps2); @@ -1173,13 +1178,14 @@ static const VMStateDescription vmstate_ps2_keyboard = { .minimum_version_id = 2, .post_load = ps2_kbd_post_load, .fields = (VMStateField[]) { - VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), + VMSTATE_STRUCT(parent_obj, PS2KbdState, 0, vmstate_ps2_common, + PS2State), VMSTATE_INT32(scan_enabled, PS2KbdState), VMSTATE_INT32(translate, PS2KbdState), - VMSTATE_INT32_V(scancode_set, PS2KbdState,3), + VMSTATE_INT32_V(scancode_set, PS2KbdState, 3), VMSTATE_END_OF_LIST() }, - .subsections = (const VMStateDescription*[]) { + .subsections = (const VMStateDescription * []) { &vmstate_ps2_keyboard_ledstate, &vmstate_ps2_keyboard_need_high_bit, &vmstate_ps2_keyboard_cqueue, @@ -1190,7 +1196,7 @@ static const VMStateDescription vmstate_ps2_keyboard = { static int ps2_mouse_post_load(void *opaque, int version_id) { PS2MouseState *s = (PS2MouseState *)opaque; - PS2State *ps2 = &s->common; + PS2State *ps2 = PS2_DEVICE(s); ps2_common_post_load(ps2); @@ -1203,7 +1209,8 @@ static const VMStateDescription vmstate_ps2_mouse = { .minimum_version_id = 2, .post_load = ps2_mouse_post_load, .fields = (VMStateField[]) { - VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), + VMSTATE_STRUCT(parent_obj, PS2MouseState, 0, vmstate_ps2_common, + PS2State), VMSTATE_UINT8(mouse_status, PS2MouseState), VMSTATE_UINT8(mouse_resolution, PS2MouseState), VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), @@ -1224,19 +1231,9 @@ static QemuInputHandler ps2_keyboard_handler = { .event = ps2_keyboard_event, }; -void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) +static void ps2_kbd_realize(DeviceState *dev, Error **errp) { - PS2KbdState *s = g_new0(PS2KbdState, 1); - - trace_ps2_kbd_init(s); - s->common.update_irq = update_irq; - s->common.update_arg = update_arg; - s->scancode_set = 2; - vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); - qemu_input_handler_register((DeviceState *)s, - &ps2_keyboard_handler); - qemu_register_reset(ps2_kbd_reset, s); - return s; + qemu_input_handler_register(dev, &ps2_keyboard_handler); } static QemuInputHandler ps2_mouse_handler = { @@ -1246,16 +1243,81 @@ static QemuInputHandler ps2_mouse_handler = { .sync = ps2_mouse_sync, }; -void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) +static void ps2_mouse_realize(DeviceState *dev, Error **errp) +{ + qemu_input_handler_register(dev, &ps2_mouse_handler); +} + +static void ps2_kbd_class_init(ObjectClass *klass, void *data) { - PS2MouseState *s = g_new0(PS2MouseState, 1); - - trace_ps2_mouse_init(s); - s->common.update_irq = update_irq; - s->common.update_arg = update_arg; - vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); - qemu_input_handler_register((DeviceState *)s, - &ps2_mouse_handler); - qemu_register_reset(ps2_mouse_reset, s); - return s; + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass); + + dc->realize = ps2_kbd_realize; + resettable_class_set_parent_phases(rc, NULL, ps2_kbd_reset_hold, NULL, + &ps2dc->parent_phases); + dc->vmsd = &vmstate_ps2_keyboard; } + +static const TypeInfo ps2_kbd_info = { + .name = TYPE_PS2_KBD_DEVICE, + .parent = TYPE_PS2_DEVICE, + .instance_size = sizeof(PS2KbdState), + .class_init = ps2_kbd_class_init +}; + +static void ps2_mouse_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass); + + dc->realize = ps2_mouse_realize; + resettable_class_set_parent_phases(rc, NULL, ps2_mouse_reset_hold, NULL, + &ps2dc->parent_phases); + dc->vmsd = &vmstate_ps2_mouse; +} + +static const TypeInfo ps2_mouse_info = { + .name = TYPE_PS2_MOUSE_DEVICE, + .parent = TYPE_PS2_DEVICE, + .instance_size = sizeof(PS2MouseState), + .class_init = ps2_mouse_class_init +}; + +static void ps2_init(Object *obj) +{ + PS2State *s = PS2_DEVICE(obj); + + qdev_init_gpio_out(DEVICE(obj), &s->irq, 1); +} + +static void ps2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = ps2_reset_hold; + rc->phases.exit = ps2_reset_exit; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static const TypeInfo ps2_info = { + .name = TYPE_PS2_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = ps2_init, + .instance_size = sizeof(PS2State), + .class_init = ps2_class_init, + .class_size = sizeof(PS2DeviceClass), + .abstract = true +}; + +static void ps2_register_types(void) +{ + type_register_static(&ps2_info); + type_register_static(&ps2_kbd_info); + type_register_static(&ps2_mouse_info); +} + +type_init(ps2_register_types) diff --git a/hw/input/trace-events b/hw/input/trace-events index e0bfe7f3ee41..29001a827d91 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -41,8 +41,6 @@ ps2_mouse_fake_event(void *opaque) "%p" ps2_write_mouse(void *opaque, int val) "%p val %d" ps2_kbd_reset(void *opaque) "%p" ps2_mouse_reset(void *opaque) "%p" -ps2_kbd_init(void *s) "%p" -ps2_mouse_init(void *s) "%p" # hid.c hid_kbd_queue_full(void) "queue full" diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c index 14698ce1097c..555b6771738d 100644 --- a/hw/input/tsc2005.c +++ b/hw/input/tsc2005.c @@ -523,7 +523,7 @@ void *tsc2005_init(qemu_irq pintdav) * from the touchscreen. Assuming 12-bit precision was used during * tslib calibration. */ -void tsc2005_set_transform(void *opaque, MouseTransformInfo *info) +void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info) { TSC2005State *s = (TSC2005State *) opaque; diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index df7313db5d7f..fdd5ff87d946 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -1176,8 +1176,7 @@ I2SCodec *tsc210x_codec(uWireSlave *chip) * from the touchscreen. Assuming 12-bit precision was used during * tslib calibration. */ -void tsc210x_set_transform(uWireSlave *chip, - MouseTransformInfo *info) +void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info) { TSC210xState *s = (TSC210xState *) chip->opaque; #if 0 diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c index 273e96a7b12d..1352e372ff39 100644 --- a/hw/input/vhost-user-input.c +++ b/hw/input/vhost-user-input.c @@ -7,7 +7,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qapi/error.h" -#include "qemu-common.h" #include "hw/virtio/virtio-input.h" @@ -79,6 +78,12 @@ static void vhost_input_set_config(VirtIODevice *vdev, virtio_notify_config(vdev); } +static struct vhost_dev *vhost_input_get_vhost(VirtIODevice *vdev) +{ + VHostUserInput *vhi = VHOST_USER_INPUT(vdev); + return &vhi->vhost->dev; +} + static const VMStateDescription vmstate_vhost_input = { .name = "vhost-user-input", .unmigratable = 1, @@ -93,6 +98,7 @@ static void vhost_input_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_vhost_input; vdc->get_config = vhost_input_get_config; vdc->set_config = vhost_input_set_config; + vdc->get_vhost = vhost_input_get_vhost; vic->realize = vhost_input_realize; vic->change_active = vhost_input_change_active; } diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 137efba57b0f..fea7139382a1 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -114,7 +114,10 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp) error_setg_file_open(errp, errno, vih->evdev); return; } - qemu_set_nonblock(vih->fd); + if (!g_unix_set_fd_nonblocking(vih->fd, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + goto err_close; + } rc = ioctl(vih->fd, EVIOCGVERSION, &ver); if (rc < 0) { diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 54bcb46c7469..5b5398b3cacf 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -257,8 +257,7 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp) vinput->cfg_size += 8; assert(vinput->cfg_size <= sizeof(virtio_input_config)); - virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT, - vinput->cfg_size); + virtio_init(vdev, VIRTIO_ID_INPUT, vinput->cfg_size); vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt); vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts); } diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index a7cf301eab25..21441d0a0c43 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -72,15 +72,36 @@ config RISCV_ACLINT config RISCV_APLIC bool + select MSI_NONBROKEN config RISCV_IMSIC bool + select MSI_NONBROKEN config SIFIVE_PLIC bool + select MSI_NONBROKEN config GOLDFISH_PIC bool config M68K_IRQC bool + +config NIOS2_VIC + bool + +config LOONGARCH_IPI + bool + +config LOONGARCH_PCH_PIC + bool + select UNIMP + +config LOONGARCH_PCH_MSI + select MSI_NONBROKEN + bool + select UNIMP + +config LOONGARCH_EXTIOI + bool diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 492b2421ab40..7a34bc0998a4 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -941,7 +941,7 @@ static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) gic_update(s); } -static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) +static uint8_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) { GICState *s = (GICState *)opaque; uint32_t res; @@ -955,6 +955,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) cm = 1 << cpu; if (offset < 0x100) { if (offset == 0) { /* GICD_CTLR */ + /* We rely here on the only non-zero bits being in byte 0 */ if (s->security_extn && !attrs.secure) { /* The NS bank of this register is just an alias of the * EnableGrp1 bit in the S bank version. @@ -964,13 +965,26 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) return s->ctlr; } } - if (offset == 4) - /* Interrupt Controller Type Register */ - return ((s->num_irq / 32) - 1) - | ((s->num_cpu - 1) << 5) - | (s->security_extn << 10); - if (offset < 0x08) + if (offset == 4) { + /* GICD_TYPER byte 0 */ + return ((s->num_irq / 32) - 1) | ((s->num_cpu - 1) << 5); + } + if (offset == 5) { + /* GICD_TYPER byte 1 */ + return (s->security_extn << 2); + } + if (offset == 8) { + /* GICD_IIDR byte 0 */ + return 0x3b; /* Arm JEP106 identity */ + } + if (offset == 9) { + /* GICD_IIDR byte 1 */ + return 0x04; /* Arm JEP106 identity */ + } + if (offset < 0x0c) { + /* All other bytes in this range are RAZ */ return 0; + } if (offset >= 0x80) { /* Interrupt Group Registers: these RAZ/WI if this is an NS * access to a GIC with the security extensions, or if the GIC diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 7b44d5625b62..a379cea3959a 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -261,9 +261,9 @@ static inline void arm_gic_common_reset_irq_state(GICState *s, int first_cpu, } } -static void arm_gic_common_reset(DeviceState *dev) +static void arm_gic_common_reset_hold(Object *obj) { - GICState *s = ARM_GIC_COMMON(dev); + GICState *s = ARM_GIC_COMMON(obj); int i, j; int resetprio; @@ -364,9 +364,10 @@ static Property arm_gic_common_properties[] = { static void arm_gic_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); - dc->reset = arm_gic_common_reset; + rc->phases.hold = arm_gic_common_reset_hold; dc->realize = arm_gic_common_realize; device_class_set_props(dc, arm_gic_common_properties); dc->vmsd = &vmstate_gic; diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 7d2a13273a47..1d588946bce1 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -38,7 +38,7 @@ DECLARE_OBJ_CHECKERS(GICState, KVMARMGICClass, struct KVMARMGICClass { ARMGICCommonClass parent_class; DeviceRealize parent_realize; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level) @@ -473,12 +473,14 @@ static void kvm_arm_gic_get(GICState *s) } } -static void kvm_arm_gic_reset(DeviceState *dev) +static void kvm_arm_gic_reset_hold(Object *obj) { - GICState *s = ARM_GIC_COMMON(dev); + GICState *s = ARM_GIC_COMMON(obj); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); - kgc->parent_reset(dev); + if (kgc->parent_phases.hold) { + kgc->parent_phases.hold(obj); + } if (kvm_arm_gic_can_save_restore(s)) { kvm_arm_gic_put(s); @@ -593,6 +595,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass); KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass); @@ -600,7 +603,8 @@ static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) agcc->post_load = kvm_arm_gic_put; device_class_set_parent_realize(dc, kvm_arm_gic_realize, &kgc->parent_realize); - device_class_set_parent_reset(dc, kvm_arm_gic_reset, &kgc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, kvm_arm_gic_reset_hold, NULL, + &kgc->parent_phases); } static const TypeInfo kvm_arm_gic_info = { diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 4ca5ae9bc564..642a8243ed4f 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -144,6 +144,25 @@ const VMStateDescription vmstate_gicv3_cpu_sre_el1 = { } }; +static bool gicv4_needed(void *opaque) +{ + GICv3CPUState *cs = opaque; + + return cs->gic->revision > 3; +} + +const VMStateDescription vmstate_gicv3_gicv4 = { + .name = "arm_gicv3_cpu/gicv4", + .version_id = 1, + .minimum_version_id = 1, + .needed = gicv4_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(gicr_vpropbaser, GICv3CPUState), + VMSTATE_UINT64(gicr_vpendbaser, GICv3CPUState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gicv3_cpu = { .name = "arm_gicv3_cpu", .version_id = 1, @@ -175,6 +194,7 @@ static const VMStateDescription vmstate_gicv3_cpu = { .subsections = (const VMStateDescription * []) { &vmstate_gicv3_cpu_virt, &vmstate_gicv3_cpu_sre_el1, + &vmstate_gicv3_gicv4, NULL } }; @@ -295,7 +315,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, memory_region_init_io(®ion->iomem, OBJECT(s), ops ? &ops[1] : NULL, region, name, - s->redist_region_count[i] * GICV3_REDIST_SIZE); + s->redist_region_count[i] * gicv3_redist_size(s)); sysbus_init_mmio(sbd, ®ion->iomem); g_free(name); } @@ -306,12 +326,14 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) GICv3State *s = ARM_GICV3_COMMON(dev); int i, rdist_capacity, cpuidx; - /* revision property is actually reserved and currently used only in order - * to keep the interface compatible with GICv2 code, avoiding extra - * conditions. However, in future it could be used, for example, if we - * implement GICv4. + /* + * This GIC device supports only revisions 3 and 4. The GICv1/v2 + * is a separate device. + * Note that subclasses of this device may impose further restrictions + * on the GIC revision: notably, the in-kernel KVM GIC doesn't + * support GICv4. */ - if (s->revision != 3) { + if (s->revision != 3 && s->revision != 4) { error_setg(errp, "unsupported GIC revision %d", s->revision); return; } @@ -328,6 +350,10 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) s->num_irq, GIC_INTERNAL); return; } + if (s->num_cpu == 0) { + error_setg(errp, "num-cpu must be at least 1"); + return; + } /* ITLinesNumber is represented as (N / 32) - 1, so this is an * implementation imposed restriction, not an architectural one, @@ -350,9 +376,9 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->nb_redist_regions; i++) { rdist_capacity += s->redist_region_count[i]; } - if (rdist_capacity < s->num_cpu) { + if (rdist_capacity != s->num_cpu) { error_setg(errp, "Capacity of the redist regions(%d) " - "is less than number of vcpus(%d)", + "does not match the number of vcpus(%d)", rdist_capacity, s->num_cpu); return; } @@ -382,8 +408,8 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) * Last == 1 if this is the last redistributor in a series of * contiguous redistributor pages * DirectLPI == 0 (direct injection of LPIs not supported) - * VLPIS == 0 (virtual LPIs not supported) - * PLPIS == 0 (physical LPIs not supported) + * VLPIS == 1 if vLPIs supported (GICv4 and up) + * PLPIS == 1 if LPIs supported */ cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL); @@ -398,6 +424,9 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) if (s->lpi_enable) { s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS; + if (s->revision > 3) { + s->cpu[i].gicr_typer |= GICR_TYPER_VLPIS; + } } } @@ -410,6 +439,8 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) cpuidx += s->redist_region_count[i]; s->cpu[cpuidx - 1].gicr_typer |= GICR_TYPER_LAST; } + + s->itslist = g_ptr_array_new(); } static void arm_gicv3_finalize(Object *obj) @@ -419,9 +450,9 @@ static void arm_gicv3_finalize(Object *obj) g_free(s->redist_region_count); } -static void arm_gicv3_common_reset(DeviceState *dev) +static void arm_gicv3_common_reset_hold(Object *obj) { - GICv3State *s = ARM_GICV3_COMMON(dev); + GICv3State *s = ARM_GICV3_COMMON(obj); int i; for (i = 0; i < s->num_cpu; i++) { @@ -438,6 +469,8 @@ static void arm_gicv3_common_reset(DeviceState *dev) cs->gicr_waker = GICR_WAKER_ProcessorSleep | GICR_WAKER_ChildrenAsleep; cs->gicr_propbaser = 0; cs->gicr_pendbaser = 0; + cs->gicr_vpropbaser = 0; + cs->gicr_vpendbaser = 0; /* If we're resetting a TZ-aware GIC as if secure firmware * had set it up ready to start a kernel in non-secure, we * need to set interrupts to group 1 so the kernel can use them. @@ -459,6 +492,7 @@ static void arm_gicv3_common_reset(DeviceState *dev) cs->hppi.prio = 0xff; cs->hpplpi.prio = 0xff; + cs->hppvlpi.prio = 0xff; /* State in the CPU interface must *not* be reset here, because it * is part of the CPU's reset domain, not the GIC device's. @@ -529,6 +563,11 @@ static Property arm_gicv3_common_properties[] = { DEFINE_PROP_UINT32("revision", GICv3State, revision, 3), DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0), DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0), + /* + * Compatibility property: force 8 bits of physical priority, even + * if the CPU being emulated should have fewer. + */ + DEFINE_PROP_BOOL("force-8-bit-prio", GICv3State, force_8bit_prio, 0), DEFINE_PROP_ARRAY("redist-region-count", GICv3State, nb_redist_regions, redist_region_count, qdev_prop_uint32, uint32_t), DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION, @@ -539,9 +578,10 @@ static Property arm_gicv3_common_properties[] = { static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); - dc->reset = arm_gicv3_common_reset; + rc->phases.hold = arm_gicv3_common_reset_hold; dc->realize = arm_gicv3_common_realize; device_class_set_props(dc, arm_gicv3_common_properties); dc->vmsd = &vmstate_gicv3; diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 1a3d440a54b0..b17b29288c73 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -20,6 +20,13 @@ #include "gicv3_internal.h" #include "hw/irq.h" #include "cpu.h" +#include "target/arm/cpregs.h" + +/* + * Special case return value from hppvi_index(); must be larger than + * the architecturally maximum possible list register index (which is 15) + */ +#define HPPVI_INDEX_VLPI 16 static GICv3CPUState *icc_cs_from_env(CPUARMState *env) { @@ -42,6 +49,14 @@ static inline int icv_min_vbpr(GICv3CPUState *cs) return 7 - cs->vprebits; } +static inline int ich_num_aprs(GICv3CPUState *cs) +{ + /* Return the number of virtual APR registers (1, 2, or 4) */ + int aprmax = 1 << (cs->vprebits - 5); + assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0])); + return aprmax; +} + /* Simple accessor functions for LR fields */ static uint32_t ich_lr_vintid(uint64_t lr) { @@ -138,9 +153,7 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs) * in the ICH Active Priority Registers. */ int i; - int aprmax = 1 << (cs->vprebits - 5); - - assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0])); + int aprmax = ich_num_aprs(cs); for (i = 0; i < aprmax; i++) { uint32_t apr = cs->ich_apr[GICV3_G0][i] | @@ -157,10 +170,18 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs) static int hppvi_index(GICv3CPUState *cs) { - /* Return the list register index of the highest priority pending + /* + * Return the list register index of the highest priority pending * virtual interrupt, as per the HighestPriorityVirtualInterrupt * pseudocode. If no pending virtual interrupts, return -1. + * If the highest priority pending virtual interrupt is a vLPI, + * return HPPVI_INDEX_VLPI. + * (The pseudocode handles checking whether the vLPI is higher + * priority than the highest priority list register at every + * callsite of HighestPriorityVirtualInterrupt; we check it here.) */ + ARMCPU *cpu = ARM_CPU(cs->cpu); + CPUARMState *env = &cpu->env; int idx = -1; int i; /* Note that a list register entry with a priority of 0xff will @@ -202,6 +223,23 @@ static int hppvi_index(GICv3CPUState *cs) } } + /* + * "no pending vLPI" is indicated with prio = 0xff, which always + * fails the priority check here. vLPIs are only considered + * when we are in Non-Secure state. + */ + if (cs->hppvlpi.prio < prio && !arm_is_secure(env)) { + if (cs->hppvlpi.grp == GICV3_G0) { + if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG0) { + return HPPVI_INDEX_VLPI; + } + } else { + if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG1) { + return HPPVI_INDEX_VLPI; + } + } + } + return idx; } @@ -289,6 +327,47 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr) return false; } +static bool icv_hppvlpi_can_preempt(GICv3CPUState *cs) +{ + /* + * Return true if we can signal the highest priority pending vLPI. + * We can assume we're Non-secure because hppvi_index() already + * tested for that. + */ + uint32_t mask, rprio, vpmr; + + if (!(cs->ich_hcr_el2 & ICH_HCR_EL2_EN)) { + /* Virtual interface disabled */ + return false; + } + + vpmr = extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT, + ICH_VMCR_EL2_VPMR_LENGTH); + + if (cs->hppvlpi.prio >= vpmr) { + /* Priority mask masks this interrupt */ + return false; + } + + rprio = ich_highest_active_virt_prio(cs); + if (rprio == 0xff) { + /* No running interrupt so we can preempt */ + return true; + } + + mask = icv_gprio_mask(cs, cs->hppvlpi.grp); + + /* + * We only preempt a running interrupt if the pending interrupt's + * group priority is sufficient (the subpriorities are not considered). + */ + if ((cs->hppvlpi.prio & mask) < (rprio & mask)) { + return true; + } + + return false; +} + static uint32_t eoi_maintenance_interrupt_state(GICv3CPUState *cs, uint32_t *misr) { @@ -370,9 +449,55 @@ static uint32_t maintenance_interrupt_state(GICv3CPUState *cs) return value; } +void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs) +{ + /* + * Tell the CPU about any pending virtual interrupts. + * This should only be called for changes that affect the + * vIRQ and vFIQ status and do not change the maintenance + * interrupt status. This means that unlike gicv3_cpuif_virt_update() + * this function won't recursively call back into the GIC code. + * The main use of this is when the redistributor has changed the + * highest priority pending virtual LPI. + */ + int idx; + int irqlevel = 0; + int fiqlevel = 0; + + idx = hppvi_index(cs); + trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx, + cs->hppvlpi.irq, cs->hppvlpi.grp, + cs->hppvlpi.prio); + if (idx == HPPVI_INDEX_VLPI) { + if (icv_hppvlpi_can_preempt(cs)) { + if (cs->hppvlpi.grp == GICV3_G0) { + fiqlevel = 1; + } else { + irqlevel = 1; + } + } + } else if (idx >= 0) { + uint64_t lr = cs->ich_lr_el2[idx]; + + if (icv_hppi_can_preempt(cs, lr)) { + /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */ + if (lr & ICH_LR_EL2_GROUP) { + irqlevel = 1; + } else { + fiqlevel = 1; + } + } + } + + trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel); + qemu_set_irq(cs->parent_vfiq, fiqlevel); + qemu_set_irq(cs->parent_virq, irqlevel); +} + static void gicv3_cpuif_virt_update(GICv3CPUState *cs) { - /* Tell the CPU about any pending virtual interrupts or + /* + * Tell the CPU about any pending virtual interrupts or * maintenance interrupts, following a change to the state * of the CPU interface relevant to virtual interrupts. * @@ -389,37 +514,17 @@ static void gicv3_cpuif_virt_update(GICv3CPUState *cs) * naturally as a result of there being no architectural * linkage between the physical and virtual GIC logic. */ - int idx; - int irqlevel = 0; - int fiqlevel = 0; - int maintlevel = 0; ARMCPU *cpu = ARM_CPU(cs->cpu); + int maintlevel = 0; - idx = hppvi_index(cs); - trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx); - if (idx >= 0) { - uint64_t lr = cs->ich_lr_el2[idx]; - - if (icv_hppi_can_preempt(cs, lr)) { - /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */ - if (lr & ICH_LR_EL2_GROUP) { - irqlevel = 1; - } else { - fiqlevel = 1; - } - } - } + gicv3_cpuif_virt_irq_fiq_update(cs); if ((cs->ich_hcr_el2 & ICH_HCR_EL2_EN) && maintenance_interrupt_state(cs) != 0) { maintlevel = 1; } - trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, - irqlevel, maintlevel); - - qemu_set_irq(cs->parent_vfiq, fiqlevel); - qemu_set_irq(cs->parent_virq, irqlevel); + trace_gicv3_cpuif_virt_set_maint_irq(gicv3_redist_affid(cs), maintlevel); qemu_set_irq(cpu->gicv3_maintenance_interrupt, maintlevel); } @@ -445,7 +550,7 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU; - gicv3_cpuif_virt_update(cs); + gicv3_cpuif_virt_irq_fiq_update(cs); return; } @@ -490,7 +595,7 @@ static void icv_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri, write_vbpr(cs, grp, value); - gicv3_cpuif_virt_update(cs); + gicv3_cpuif_virt_irq_fiq_update(cs); } static uint64_t icv_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -517,7 +622,7 @@ static void icv_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri, cs->ich_vmcr_el2 = deposit64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT, ICH_VMCR_EL2_VPMR_LENGTH, value); - gicv3_cpuif_virt_update(cs); + gicv3_cpuif_virt_irq_fiq_update(cs); } static uint64_t icv_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -558,7 +663,7 @@ static uint64_t icv_ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) * should match the ones reported in ich_vtr_read(). */ value = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); + ((cs->vpribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT); if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VEOIM) { value |= ICC_CTLR_EL1_EOIMODE; @@ -584,7 +689,7 @@ static void icv_ctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, cs->ich_vmcr_el2 = deposit64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VEOIM_SHIFT, 1, value & ICC_CTLR_EL1_EOIMODE ? 1 : 0); - gicv3_cpuif_virt_update(cs); + gicv3_cpuif_virt_irq_fiq_update(cs); } static uint64_t icv_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -603,7 +708,11 @@ static uint64_t icv_hppir_read(CPUARMState *env, const ARMCPRegInfo *ri) int idx = hppvi_index(cs); uint64_t value = INTID_SPURIOUS; - if (idx >= 0) { + if (idx == HPPVI_INDEX_VLPI) { + if (cs->hppvlpi.grp == grp) { + value = cs->hppvlpi.irq; + } + } else if (idx >= 0) { uint64_t lr = cs->ich_lr_el2[idx]; int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; @@ -634,6 +743,18 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp) cs->ich_apr[grp][regno] |= (1 << regbit); } +static void icv_activate_vlpi(GICv3CPUState *cs) +{ + uint32_t mask = icv_gprio_mask(cs, cs->hppvlpi.grp); + int prio = cs->hppvlpi.prio & mask; + int aprbit = prio >> (8 - cs->vprebits); + int regno = aprbit / 32; + int regbit = aprbit % 32; + + cs->ich_apr[cs->hppvlpi.grp][regno] |= (1 << regbit); + gicv3_redist_vlpi_pending(cs, cs->hppvlpi.irq, 0); +} + static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); @@ -641,7 +762,12 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) int idx = hppvi_index(cs); uint64_t intid = INTID_SPURIOUS; - if (idx >= 0) { + if (idx == HPPVI_INDEX_VLPI) { + if (cs->hppvlpi.grp == grp && icv_hppvlpi_can_preempt(cs)) { + intid = cs->hppvlpi.irq; + icv_activate_vlpi(cs); + } + } else if (idx >= 0) { uint64_t lr = cs->ich_lr_el2[idx]; int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; @@ -667,6 +793,36 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) return intid; } +static uint32_t icc_fullprio_mask(GICv3CPUState *cs) +{ + /* + * Return a mask word which clears the unimplemented priority bits + * from a priority value for a physical interrupt. (Not to be confused + * with the group priority, whose mask depends on the value of BPR + * for the interrupt group.) + */ + return ~0U << (8 - cs->pribits); +} + +static inline int icc_min_bpr(GICv3CPUState *cs) +{ + /* The minimum BPR for the physical interface. */ + return 7 - cs->prebits; +} + +static inline int icc_min_bpr_ns(GICv3CPUState *cs) +{ + return icc_min_bpr(cs) + 1; +} + +static inline int icc_num_aprs(GICv3CPUState *cs) +{ + /* Return the number of APR registers (1, 2, or 4) */ + int aprmax = 1 << MAX(cs->prebits - 5, 0); + assert(aprmax <= ARRAY_SIZE(cs->icc_apr[0])); + return aprmax; +} + static int icc_highest_active_prio(GICv3CPUState *cs) { /* Calculate the current running priority based on the set bits @@ -674,14 +830,14 @@ static int icc_highest_active_prio(GICv3CPUState *cs) */ int i; - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) { + for (i = 0; i < icc_num_aprs(cs); i++) { uint32_t apr = cs->icc_apr[GICV3_G0][i] | cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i]; if (!apr) { continue; } - return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); + return (i * 32 + ctz32(apr)) << (icc_min_bpr(cs) + 1); } /* No current active interrupts: return idle priority */ return 0xff; @@ -860,8 +1016,6 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); - value &= 0xff; - if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) && (env->cp15.scr_el3 & SCR_FIQ)) { /* NS access and Group 0 is inaccessible to NS: return the @@ -873,6 +1027,7 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri, } value = (value >> 1) | 0x80; } + value &= icc_fullprio_mask(cs); cs->icc_pmr_el1 = value; gicv3_cpuif_update(cs); } @@ -884,7 +1039,7 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq) */ uint32_t mask = icc_gprio_mask(cs, cs->hppi.grp); int prio = cs->hppi.prio & mask; - int aprbit = prio >> 1; + int aprbit = prio >> (8 - cs->prebits); int regno = aprbit / 32; int regbit = aprbit % 32; @@ -1042,7 +1197,7 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp) */ int i; - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[grp]); i++) { + for (i = 0; i < icc_num_aprs(cs); i++) { uint64_t *papr = &cs->icc_apr[grp][i]; if (!*papr) { @@ -1183,9 +1338,7 @@ static int icv_drop_prio(GICv3CPUState *cs) * 32 bits are actually relevant. */ int i; - int aprmax = 1 << (cs->vprebits - 5); - - assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0])); + int aprmax = ich_num_aprs(cs); for (i = 0; i < aprmax; i++) { uint64_t *papr0 = &cs->ich_apr[GICV3_G0][i]; @@ -1470,7 +1623,7 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri, return; } - minval = (grp == GICV3_G1NS) ? GIC_MIN_BPR_NS : GIC_MIN_BPR; + minval = (grp == GICV3_G1NS) ? icc_min_bpr_ns(cs) : icc_min_bpr(cs); if (value < minval) { value = minval; } @@ -1893,7 +2046,7 @@ static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR; } - /* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */ + /* The only bit stored in icc_ctlr_el3 which is writable is EOIMODE_EL3: */ mask = ICC_CTLR_EL3_EOIMODE_EL3; cs->icc_ctlr_el3 &= ~mask; @@ -2051,19 +2204,19 @@ static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) cs->icc_ctlr_el1[GICV3_S] = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); + ((cs->pribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT); cs->icc_ctlr_el1[GICV3_NS] = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); + ((cs->pribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT); cs->icc_pmr_el1 = 0; - cs->icc_bpr[GICV3_G0] = GIC_MIN_BPR; - cs->icc_bpr[GICV3_G1] = GIC_MIN_BPR; - cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR_NS; + cs->icc_bpr[GICV3_G0] = icc_min_bpr(cs); + cs->icc_bpr[GICV3_G1] = icc_min_bpr(cs); + cs->icc_bpr[GICV3_G1NS] = icc_min_bpr_ns(cs); memset(cs->icc_apr, 0, sizeof(cs->icc_apr)); memset(cs->icc_igrpen, 0, sizeof(cs->icc_igrpen)); cs->icc_ctlr_el3 = ICC_CTLR_EL3_NDS | ICC_CTLR_EL3_A3V | (1 << ICC_CTLR_EL3_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL3_PRIBITS_SHIFT); + ((cs->pribits - 1) << ICC_CTLR_EL3_PRIBITS_SHIFT); memset(cs->ich_apr, 0, sizeof(cs->ich_apr)); cs->ich_hcr_el2 = 0; @@ -2118,27 +2271,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .readfn = icc_ap_read, .writefn = icc_ap_write, }, - { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, /* All the ICC_AP1R*_EL1 registers are banked */ { .name = "ICC_AP1R0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 0, @@ -2147,27 +2279,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .readfn = icc_ap_read, .writefn = icc_ap_write, }, - { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, { .name = "ICC_DIR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 1, .type = ARM_CP_IO | ARM_CP_NO_RAW, @@ -2308,7 +2419,54 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .readfn = icc_igrpen1_el3_read, .writefn = icc_igrpen1_el3_write, }, - REGINFO_SENTINEL +}; + +static const ARMCPRegInfo gicv3_cpuif_icc_apxr1_reginfo[] = { + { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_fiq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_irq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, +}; + +static const ARMCPRegInfo gicv3_cpuif_icc_apxr23_reginfo[] = { + { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_fiq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_fiq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_irq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_irq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, }; static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -2333,7 +2491,7 @@ static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value); cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU; - gicv3_cpuif_virt_update(cs); + gicv3_cpuif_virt_irq_fiq_update(cs); } static uint64_t ich_hcr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -2459,11 +2617,15 @@ static uint64_t ich_vtr_read(CPUARMState *env, const ARMCPRegInfo *ri) uint64_t value; value = ((cs->num_list_regs - 1) << ICH_VTR_EL2_LISTREGS_SHIFT) - | ICH_VTR_EL2_TDS | ICH_VTR_EL2_NV4 | ICH_VTR_EL2_A3V + | ICH_VTR_EL2_TDS | ICH_VTR_EL2_A3V | (1 << ICH_VTR_EL2_IDBITS_SHIFT) | ((cs->vprebits - 1) << ICH_VTR_EL2_PREBITS_SHIFT) | ((cs->vpribits - 1) << ICH_VTR_EL2_PRIBITS_SHIFT); + if (cs->gic->revision < 4) { + value |= ICH_VTR_EL2_NV4; + } + trace_gicv3_ich_vtr_read(gicv3_redist_affid(cs), value); return value; } @@ -2558,7 +2720,6 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = { .readfn = ich_vmcr_read, .writefn = ich_vmcr_write, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = { @@ -2576,7 +2737,6 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = { .readfn = ich_ap_read, .writefn = ich_ap_write, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { @@ -2608,7 +2768,6 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { .readfn = ich_ap_read, .writefn = ich_ap_write, }, - REGINFO_SENTINEL }; static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) @@ -2616,6 +2775,12 @@ static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) GICv3CPUState *cs = opaque; gicv3_cpuif_update(cs); + /* + * Because vLPIs are only pending in NonSecure state, + * an EL change can change the VIRQ/VFIQ status (but + * cannot affect the maintenance interrupt state) + */ + gicv3_cpuif_virt_irq_fiq_update(cs); } void gicv3_init_cpuif(GICv3State *s) @@ -2629,6 +2794,16 @@ void gicv3_init_cpuif(GICv3State *s) ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); GICv3CPUState *cs = &s->cpu[i]; + /* + * If the CPU doesn't define a GICv3 configuration, probably because + * in real hardware it doesn't have one, then we use default values + * matching the one used by most Arm CPUs. This applies to: + * cpu->gic_num_lrs + * cpu->gic_vpribits + * cpu->gic_vprebits + * cpu->gic_pribits + */ + /* Note that we can't just use the GICv3CPUState as an opaque pointer * in define_arm_cp_regs_with_opaque(), because when we're called back * it might be with code translated by CPU 0 but run by CPU 1, in @@ -2637,13 +2812,56 @@ void gicv3_init_cpuif(GICv3State *s) * get back to the GICv3CPUState from the CPUARMState. */ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); - if (arm_feature(&cpu->env, ARM_FEATURE_EL2) - && cpu->gic_num_lrs) { + + /* + * The CPU implementation specifies the number of supported + * bits of physical priority. For backwards compatibility + * of migration, we have a compat property that forces use + * of 8 priority bits regardless of what the CPU really has. + */ + if (s->force_8bit_prio) { + cs->pribits = 8; + } else { + cs->pribits = cpu->gic_pribits ?: 5; + } + + /* + * The GICv3 has separate ID register fields for virtual priority + * and preemption bit values, but only a single ID register field + * for the physical priority bits. The preemption bit count is + * always the same as the priority bit count, except that 8 bits + * of priority means 7 preemption bits. We precalculate the + * preemption bits because it simplifies the code and makes the + * parallels between the virtual and physical bits of the GIC + * a bit clearer. + */ + cs->prebits = cs->pribits; + if (cs->prebits == 8) { + cs->prebits--; + } + /* + * Check that CPU code defining pribits didn't violate + * architectural constraints our implementation relies on. + */ + g_assert(cs->pribits >= 4 && cs->pribits <= 8); + + /* + * gicv3_cpuif_reginfo[] defines ICC_AP*R0_EL1; add definitions + * for ICC_AP*R{1,2,3}_EL1 if the prebits value requires them. + */ + if (cs->prebits >= 6) { + define_arm_cp_regs(cpu, gicv3_cpuif_icc_apxr1_reginfo); + } + if (cs->prebits == 7) { + define_arm_cp_regs(cpu, gicv3_cpuif_icc_apxr23_reginfo); + } + + if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { int j; - cs->num_list_regs = cpu->gic_num_lrs; - cs->vpribits = cpu->gic_vpribits; - cs->vprebits = cpu->gic_vprebits; + cs->num_list_regs = cpu->gic_num_lrs ?: 4; + cs->vpribits = cpu->gic_vpribits ?: 5; + cs->vprebits = cpu->gic_vprebits ?: 5; /* Check against architectural constraints: getting these * wrong would be a bug in the CPU code defining these, @@ -2677,7 +2895,6 @@ void gicv3_init_cpuif(GICv3State *s) .readfn = ich_lr_read, .writefn = ich_lr_write, }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, lr_regset); } diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 28d913b2114c..d599fefcbcf0 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -383,24 +383,25 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, * No1N == 1 (1-of-N SPI interrupts not supported) * A3V == 1 (non-zero values of Affinity level 3 supported) * IDbits == 0xf (we support 16-bit interrupt identifiers) - * DVIS == 0 (Direct virtual LPI injection not supported) + * DVIS == 1 (Direct virtual LPI injection supported) if GICv4 * LPIS == 1 (LPIs are supported if affinity routing is enabled) * num_LPIs == 0b00000 (bits [15:11],Number of LPIs as indicated * by GICD_TYPER.IDbits) * MBIS == 0 (message-based SPIs not supported) * SecurityExtn == 1 if security extns supported * CPUNumber == 0 since for us ARE is always 1 - * ITLinesNumber == (num external irqs / 32) - 1 + * ITLinesNumber == (((max SPI IntID + 1) / 32) - 1) */ - int itlinesnumber = ((s->num_irq - GIC_INTERNAL) / 32) - 1; + int itlinesnumber = (s->num_irq / 32) - 1; /* * SecurityExtn must be RAZ if GICD_CTLR.DS == 1, and * "security extensions not supported" always implies DS == 1, * so we only need to check the DS bit. */ bool sec_extn = !(s->gicd_ctlr & GICD_CTLR_DS); + bool dvis = s->revision >= 4; - *data = (1 << 25) | (1 << 24) | (sec_extn << 10) | + *data = (1 << 25) | (1 << 24) | (dvis << 18) | (sec_extn << 10) | (s->lpi_enable << GICD_TYPER_LPIS_SHIFT) | (0xf << 19) | itlinesnumber; return true; @@ -557,7 +558,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, } case GICD_IDREGS ... GICD_IDREGS + 0x2f: /* ID registers */ - *data = gicv3_idreg(offset - GICD_IDREGS); + *data = gicv3_idreg(s, offset - GICD_IDREGS, GICV3_PIDR0_DIST); return true; case GICD_SGIR: /* WO registers, return unknown value */ @@ -610,7 +611,7 @@ static bool gicd_writel(GICv3State *s, hwaddr offset, if (value & mask & GICD_CTLR_DS) { /* We just set DS, so the ARE_NS and EnG1S bits are now RES0. * Note that this is a one-way transition because if DS is set - * then it's not writeable, so it can only go back to 0 with a + * then it's not writable, so it can only go back to 0 with a * hardware reset. */ s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS); diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 87466732139f..57c79da5c55a 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -27,7 +27,7 @@ DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass, struct GICv3ITSClass { GICv3ITSCommonClass parent_class; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; /* @@ -61,6 +61,12 @@ typedef struct ITEntry { uint32_t vpeid; } ITEntry; +typedef struct VTEntry { + bool valid; + unsigned vptsize; + uint32_t rdbase; + uint64_t vptaddr; +} VTEntry; /* * The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options @@ -72,13 +78,33 @@ typedef struct ITEntry { * and continue processing. * The process_* functions which handle individual ITS commands all * return an ItsCmdResult which tells process_cmdq() whether it should - * stall or keep going. + * stall, keep going because of an error, or keep going because the + * command was a success. */ typedef enum ItsCmdResult { CMD_STALL = 0, CMD_CONTINUE = 1, + CMD_CONTINUE_OK = 2, } ItsCmdResult; +/* True if the ITS supports the GICv4 virtual LPI feature */ +static bool its_feature_virtual(GICv3ITSState *s) +{ + return s->typer & R_GITS_TYPER_VIRTUAL_MASK; +} + +static inline bool intid_in_lpi_range(uint32_t id) +{ + return id >= GICV3_LPI_INTID_START && + id < (1 << (GICD_TYPER_IDBITS + 1)); +} + +static inline bool valid_doorbell(uint32_t id) +{ + /* Doorbell fields may be an LPI, or 1023 to mean "no doorbell" */ + return id == INTID_SPURIOUS || intid_in_lpi_range(id); +} + static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz) { uint64_t result = 0; @@ -289,97 +315,247 @@ static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte) } /* - * This function handles the processing of following commands based on - * the ItsCmdType parameter passed:- - * 1. triggering of lpi interrupt translation via ITS INT command - * 2. triggering of lpi interrupt translation via gits_translater register - * 3. handling of ITS CLEAR command - * 4. handling of ITS DISCARD command + * Read the vPE Table entry at index @vpeid. On success (including + * successfully determining that there is no valid entry for this index), + * we return MEMTX_OK and populate the VTEntry struct accordingly. + * If there is an error reading memory then we return the error code. */ -static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid, - uint32_t eventid, ItsCmdType cmd) +static MemTxResult get_vte(GICv3ITSState *s, uint32_t vpeid, VTEntry *vte) +{ + MemTxResult res = MEMTX_OK; + AddressSpace *as = &s->gicv3->dma_as; + uint64_t entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res); + uint64_t vteval; + + if (entry_addr == -1) { + /* No L2 table entry, i.e. no valid VTE, or a memory error */ + vte->valid = false; + goto out; + } + vteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res); + if (res != MEMTX_OK) { + goto out; + } + vte->valid = FIELD_EX64(vteval, VTE, VALID); + vte->vptsize = FIELD_EX64(vteval, VTE, VPTSIZE); + vte->vptaddr = FIELD_EX64(vteval, VTE, VPTADDR); + vte->rdbase = FIELD_EX64(vteval, VTE, RDBASE); +out: + if (res != MEMTX_OK) { + trace_gicv3_its_vte_read_fault(vpeid); + } else { + trace_gicv3_its_vte_read(vpeid, vte->valid, vte->vptsize, + vte->vptaddr, vte->rdbase); + } + return res; +} + +/* + * Given a (DeviceID, EventID), look up the corresponding ITE, including + * checking for the various invalid-value cases. If we find a valid ITE, + * fill in @ite and @dte and return CMD_CONTINUE_OK. Otherwise return + * CMD_STALL or CMD_CONTINUE as appropriate (and the contents of @ite + * should not be relied on). + * + * The string @who is purely for the LOG_GUEST_ERROR messages, + * and should indicate the name of the calling function or similar. + */ +static ItsCmdResult lookup_ite(GICv3ITSState *s, const char *who, + uint32_t devid, uint32_t eventid, ITEntry *ite, + DTEntry *dte) { uint64_t num_eventids; - DTEntry dte; - CTEntry cte; - ITEntry ite; if (devid >= s->dt.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid command attributes: devid %d>=%d", - __func__, devid, s->dt.num_entries); + who, devid, s->dt.num_entries); return CMD_CONTINUE; } - if (get_dte(s, devid, &dte) != MEMTX_OK) { + if (get_dte(s, devid, dte) != MEMTX_OK) { return CMD_STALL; } - if (!dte.valid) { + if (!dte->valid) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid command attributes: " - "invalid dte for %d\n", __func__, devid); + "invalid dte for %d\n", who, devid); return CMD_CONTINUE; } - num_eventids = 1ULL << (dte.size + 1); + num_eventids = 1ULL << (dte->size + 1); if (eventid >= num_eventids) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid command attributes: eventid %d >= %" - PRId64 "\n", - __func__, eventid, num_eventids); + PRId64 "\n", who, eventid, num_eventids); return CMD_CONTINUE; } - if (get_ite(s, eventid, &dte, &ite) != MEMTX_OK) { + if (get_ite(s, eventid, dte, ite) != MEMTX_OK) { return CMD_STALL; } - if (!ite.valid || ite.inttype != ITE_INTTYPE_PHYSICAL) { + if (!ite->valid) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: invalid ITE\n", - __func__); + "%s: invalid command attributes: invalid ITE\n", who); return CMD_CONTINUE; } - if (ite.icid >= s->ct.num_entries) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid ICID 0x%x in ITE (table corrupted?)\n", - __func__, ite.icid); + return CMD_CONTINUE_OK; +} + +/* + * Given an ICID, look up the corresponding CTE, including checking for various + * invalid-value cases. If we find a valid CTE, fill in @cte and return + * CMD_CONTINUE_OK; otherwise return CMD_STALL or CMD_CONTINUE (and the + * contents of @cte should not be relied on). + * + * The string @who is purely for the LOG_GUEST_ERROR messages, + * and should indicate the name of the calling function or similar. + */ +static ItsCmdResult lookup_cte(GICv3ITSState *s, const char *who, + uint32_t icid, CTEntry *cte) +{ + if (icid >= s->ct.num_entries) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid ICID 0x%x\n", who, icid); + return CMD_CONTINUE; + } + if (get_cte(s, icid, cte) != MEMTX_OK) { + return CMD_STALL; + } + if (!cte->valid) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid CTE\n", who); + return CMD_CONTINUE; + } + if (cte->rdbase >= s->gicv3->num_cpu) { return CMD_CONTINUE; } + return CMD_CONTINUE_OK; +} - if (get_cte(s, ite.icid, &cte) != MEMTX_OK) { +/* + * Given a VPEID, look up the corresponding VTE, including checking + * for various invalid-value cases. if we find a valid VTE, fill in @vte + * and return CMD_CONTINUE_OK; otherwise return CMD_STALL or CMD_CONTINUE + * (and the contents of @vte should not be relied on). + * + * The string @who is purely for the LOG_GUEST_ERROR messages, + * and should indicate the name of the calling function or similar. + */ +static ItsCmdResult lookup_vte(GICv3ITSState *s, const char *who, + uint32_t vpeid, VTEntry *vte) +{ + if (vpeid >= s->vpet.num_entries) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid VPEID 0x%x\n", who, vpeid); + return CMD_CONTINUE; + } + + if (get_vte(s, vpeid, vte) != MEMTX_OK) { return CMD_STALL; } - if (!cte.valid) { + if (!vte->valid) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: invalid CTE\n", - __func__); + "%s: invalid VTE for VPEID 0x%x\n", who, vpeid); + return CMD_CONTINUE; + } + + if (vte->rdbase >= s->gicv3->num_cpu) { + return CMD_CONTINUE; + } + return CMD_CONTINUE_OK; +} + +static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite, + int irqlevel) +{ + CTEntry cte; + ItsCmdResult cmdres; + + cmdres = lookup_cte(s, __func__, ite->icid, &cte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite->intid, irqlevel); + return CMD_CONTINUE_OK; +} + +static ItsCmdResult process_its_cmd_virt(GICv3ITSState *s, const ITEntry *ite, + int irqlevel) +{ + VTEntry vte; + ItsCmdResult cmdres; + + cmdres = lookup_vte(s, __func__, ite->vpeid, &vte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + + if (!intid_in_lpi_range(ite->intid) || + ite->intid >= (1ULL << (vte.vptsize + 1))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: intid 0x%x out of range\n", + __func__, ite->intid); return CMD_CONTINUE; } /* - * Current implementation only supports rdbase == procnum - * Hence rdbase physical address is ignored + * For QEMU the actual pending of the vLPI is handled in the + * redistributor code */ - if (cte.rdbase >= s->gicv3->num_cpu) { - return CMD_CONTINUE; + gicv3_redist_process_vlpi(&s->gicv3->cpu[vte.rdbase], ite->intid, + vte.vptaddr << 16, ite->doorbell, irqlevel); + return CMD_CONTINUE_OK; +} + +/* + * This function handles the processing of following commands based on + * the ItsCmdType parameter passed:- + * 1. triggering of lpi interrupt translation via ITS INT command + * 2. triggering of lpi interrupt translation via gits_translater register + * 3. handling of ITS CLEAR command + * 4. handling of ITS DISCARD command + */ +static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid, + uint32_t eventid, ItsCmdType cmd) +{ + DTEntry dte; + ITEntry ite; + ItsCmdResult cmdres; + int irqlevel; + + cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; } - if ((cmd == CLEAR) || (cmd == DISCARD)) { - gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 0); - } else { - gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 1); + irqlevel = (cmd == CLEAR || cmd == DISCARD) ? 0 : 1; + + switch (ite.inttype) { + case ITE_INTTYPE_PHYSICAL: + cmdres = process_its_cmd_phys(s, &ite, irqlevel); + break; + case ITE_INTTYPE_VIRTUAL: + if (!its_feature_virtual(s)) { + /* Can't happen unless guest is illegally writing to table memory */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid type %d in ITE (table corrupted?)\n", + __func__, ite.inttype); + return CMD_CONTINUE; + } + cmdres = process_its_cmd_virt(s, &ite, irqlevel); + break; + default: + g_assert_not_reached(); } - if (cmd == DISCARD) { + if (cmdres == CMD_CONTINUE_OK && cmd == DISCARD) { ITEntry ite = {}; /* remove mapping from interrupt translation table */ ite.valid = false; - return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL; + return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL; } - return CMD_CONTINUE; + return CMD_CONTINUE_OK; } + static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt, ItsCmdType cmd) { @@ -409,7 +585,6 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt, uint32_t devid, eventid; uint32_t pIntid = 0; uint64_t num_eventids; - uint32_t num_intids; uint16_t icid = 0; DTEntry dte; ITEntry ite; @@ -437,7 +612,6 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt, return CMD_STALL; } num_eventids = 1ULL << (dte.size + 1); - num_intids = 1ULL << (GICD_TYPER_IDBITS + 1); if (icid >= s->ct.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, @@ -459,7 +633,7 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt, return CMD_CONTINUE; } - if (pIntid < GICV3_LPI_INTID_START || pIntid >= num_intids) { + if (!intid_in_lpi_range(pIntid)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid interrupt ID 0x%x\n", __func__, pIntid); return CMD_CONTINUE; @@ -472,7 +646,86 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt, ite.icid = icid; ite.doorbell = INTID_SPURIOUS; ite.vpeid = 0; - return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL; + return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL; +} + +static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt, + bool ignore_vintid) +{ + uint32_t devid, eventid, vintid, doorbell, vpeid; + uint32_t num_eventids; + DTEntry dte; + ITEntry ite; + + if (!its_feature_virtual(s)) { + return CMD_CONTINUE; + } + + devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID); + eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID); + vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID); + doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL); + if (ignore_vintid) { + vintid = eventid; + trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell); + } else { + vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID); + trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell); + } + + if (devid >= s->dt.num_entries) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n", + __func__, devid, s->dt.num_entries); + return CMD_CONTINUE; + } + + if (get_dte(s, devid, &dte) != MEMTX_OK) { + return CMD_STALL; + } + + if (!dte.valid) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: no entry in device table for DeviceID 0x%x\n", + __func__, devid); + return CMD_CONTINUE; + } + + num_eventids = 1ULL << (dte.size + 1); + + if (eventid >= num_eventids) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: EventID 0x%x too large for DeviceID 0x%x " + "(must be less than 0x%x)\n", + __func__, eventid, devid, num_eventids); + return CMD_CONTINUE; + } + if (!intid_in_lpi_range(vintid)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: VIntID 0x%x not a valid LPI\n", + __func__, vintid); + return CMD_CONTINUE; + } + if (!valid_doorbell(doorbell)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Doorbell %d not 1023 and not a valid LPI\n", + __func__, doorbell); + return CMD_CONTINUE; + } + if (vpeid >= s->vpet.num_entries) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: VPEID 0x%x out of range (must be less than 0x%x)\n", + __func__, vpeid, s->vpet.num_entries); + return CMD_CONTINUE; + } + /* add ite entry to interrupt translation table */ + ite.valid = true; + ite.inttype = ITE_INTTYPE_VIRTUAL; + ite.intid = vintid; + ite.icid = 0; + ite.doorbell = doorbell; + ite.vpeid = vpeid; + return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL; } /* @@ -533,7 +786,7 @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt) return CMD_CONTINUE; } - return update_cte(s, icid, &cte) ? CMD_CONTINUE : CMD_STALL; + return update_cte(s, icid, &cte) ? CMD_CONTINUE_OK : CMD_STALL; } /* @@ -594,7 +847,7 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt) return CMD_CONTINUE; } - return update_dte(s, devid, &dte) ? CMD_CONTINUE : CMD_STALL; + return update_dte(s, devid, &dte) ? CMD_CONTINUE_OK : CMD_STALL; } static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt) @@ -623,23 +876,23 @@ static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt) if (rd1 == rd2) { /* Move to same target must succeed as a no-op */ - return CMD_CONTINUE; + return CMD_CONTINUE_OK; } /* Move all pending LPIs from redistributor 1 to redistributor 2 */ gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]); - return CMD_CONTINUE; + return CMD_CONTINUE_OK; } static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt) { uint32_t devid, eventid; uint16_t new_icid; - uint64_t num_eventids; DTEntry dte; CTEntry old_cte, new_cte; ITEntry old_ite; + ItsCmdResult cmdres; devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID); eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID); @@ -647,103 +900,346 @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt) trace_gicv3_its_cmd_movi(devid, eventid, new_icid); - if (devid >= s->dt.num_entries) { + cmdres = lookup_ite(s, __func__, devid, eventid, &old_ite, &dte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + + if (old_ite.inttype != ITE_INTTYPE_PHYSICAL) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: devid %d>=%d", - __func__, devid, s->dt.num_entries); + "%s: invalid command attributes: invalid ITE\n", + __func__); return CMD_CONTINUE; } - if (get_dte(s, devid, &dte) != MEMTX_OK) { - return CMD_STALL; + + cmdres = lookup_cte(s, __func__, old_ite.icid, &old_cte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + cmdres = lookup_cte(s, __func__, new_icid, &new_cte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; } - if (!dte.valid) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: " - "invalid dte for %d\n", __func__, devid); + if (old_cte.rdbase != new_cte.rdbase) { + /* Move the LPI from the old redistributor to the new one */ + gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase], + &s->gicv3->cpu[new_cte.rdbase], + old_ite.intid); + } + + /* Update the ICID field in the interrupt translation table entry */ + old_ite.icid = new_icid; + return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE_OK : CMD_STALL; +} + +/* + * Update the vPE Table entry at index @vpeid with the entry @vte. + * Returns true on success, false if there was a memory access error. + */ +static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte) +{ + AddressSpace *as = &s->gicv3->dma_as; + uint64_t entry_addr; + uint64_t vteval = 0; + MemTxResult res = MEMTX_OK; + + trace_gicv3_its_vte_write(vpeid, vte->valid, vte->vptsize, vte->vptaddr, + vte->rdbase); + + if (vte->valid) { + vteval = FIELD_DP64(vteval, VTE, VALID, 1); + vteval = FIELD_DP64(vteval, VTE, VPTSIZE, vte->vptsize); + vteval = FIELD_DP64(vteval, VTE, VPTADDR, vte->vptaddr); + vteval = FIELD_DP64(vteval, VTE, RDBASE, vte->rdbase); + } + + entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res); + if (res != MEMTX_OK) { + return false; + } + if (entry_addr == -1) { + /* No L2 table for this index: discard write and continue */ + return true; + } + address_space_stq_le(as, entry_addr, vteval, MEMTXATTRS_UNSPECIFIED, &res); + return res == MEMTX_OK; +} + +static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt) +{ + VTEntry vte; + uint32_t vpeid; + + if (!its_feature_virtual(s)) { return CMD_CONTINUE; } - num_eventids = 1ULL << (dte.size + 1); - if (eventid >= num_eventids) { + vpeid = FIELD_EX64(cmdpkt[1], VMAPP_1, VPEID); + vte.rdbase = FIELD_EX64(cmdpkt[2], VMAPP_2, RDBASE); + vte.valid = FIELD_EX64(cmdpkt[2], VMAPP_2, V); + vte.vptsize = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTSIZE); + vte.vptaddr = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTADDR); + + trace_gicv3_its_cmd_vmapp(vpeid, vte.rdbase, vte.valid, + vte.vptaddr, vte.vptsize); + + /* + * For GICv4.0 the VPT_size field is only 5 bits, whereas we + * define our field macros to include the full GICv4.1 8 bits. + * The range check on VPT_size will catch the cases where + * the guest set the RES0-in-GICv4.0 bits [7:6]. + */ + if (vte.vptsize > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: eventid %d >= %" - PRId64 "\n", - __func__, eventid, num_eventids); + "%s: invalid VPT_size 0x%x\n", __func__, vte.vptsize); return CMD_CONTINUE; } - if (get_ite(s, eventid, &dte, &old_ite) != MEMTX_OK) { - return CMD_STALL; + if (vte.valid && vte.rdbase >= s->gicv3->num_cpu) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid rdbase 0x%x\n", __func__, vte.rdbase); + return CMD_CONTINUE; } - if (!old_ite.valid || old_ite.inttype != ITE_INTTYPE_PHYSICAL) { + if (vpeid >= s->vpet.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: invalid ITE\n", - __func__); + "%s: VPEID 0x%x out of range (must be less than 0x%x)\n", + __func__, vpeid, s->vpet.num_entries); return CMD_CONTINUE; } - if (old_ite.icid >= s->ct.num_entries) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid ICID 0x%x in ITE (table corrupted?)\n", - __func__, old_ite.icid); + return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL; +} + +typedef struct VmovpCallbackData { + uint64_t rdbase; + uint32_t vpeid; + /* + * Overall command result. If more than one callback finds an + * error, STALL beats CONTINUE. + */ + ItsCmdResult result; +} VmovpCallbackData; + +static void vmovp_callback(gpointer data, gpointer opaque) +{ + /* + * This function is called to update the VPEID field in a VPE + * table entry for this ITS. This might be because of a VMOVP + * command executed on any ITS that is connected to the same GIC + * as this ITS. We need to read the VPE table entry for the VPEID + * and update its RDBASE field. + */ + GICv3ITSState *s = data; + VmovpCallbackData *cbdata = opaque; + VTEntry vte; + ItsCmdResult cmdres; + + cmdres = lookup_vte(s, __func__, cbdata->vpeid, &vte); + switch (cmdres) { + case CMD_STALL: + cbdata->result = CMD_STALL; + return; + case CMD_CONTINUE: + if (cbdata->result != CMD_STALL) { + cbdata->result = CMD_CONTINUE; + } + return; + case CMD_CONTINUE_OK: + break; + } + + vte.rdbase = cbdata->rdbase; + if (!update_vte(s, cbdata->vpeid, &vte)) { + cbdata->result = CMD_STALL; + } +} + +static ItsCmdResult process_vmovp(GICv3ITSState *s, const uint64_t *cmdpkt) +{ + VmovpCallbackData cbdata; + + if (!its_feature_virtual(s)) { return CMD_CONTINUE; } - if (new_icid >= s->ct.num_entries) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: ICID 0x%x\n", - __func__, new_icid); + cbdata.vpeid = FIELD_EX64(cmdpkt[1], VMOVP_1, VPEID); + cbdata.rdbase = FIELD_EX64(cmdpkt[2], VMOVP_2, RDBASE); + + trace_gicv3_its_cmd_vmovp(cbdata.vpeid, cbdata.rdbase); + + if (cbdata.rdbase >= s->gicv3->num_cpu) { return CMD_CONTINUE; } - if (get_cte(s, old_ite.icid, &old_cte) != MEMTX_OK) { - return CMD_STALL; + /* + * Our ITS implementation reports GITS_TYPER.VMOVP == 1, which means + * that when the VMOVP command is executed on an ITS to change the + * VPEID field in a VPE table entry the change must be propagated + * to all the ITSes connected to the same GIC. + */ + cbdata.result = CMD_CONTINUE_OK; + gicv3_foreach_its(s->gicv3, vmovp_callback, &cbdata); + return cbdata.result; +} + +static ItsCmdResult process_vmovi(GICv3ITSState *s, const uint64_t *cmdpkt) +{ + uint32_t devid, eventid, vpeid, doorbell; + bool doorbell_valid; + DTEntry dte; + ITEntry ite; + VTEntry old_vte, new_vte; + ItsCmdResult cmdres; + + if (!its_feature_virtual(s)) { + return CMD_CONTINUE; } - if (!old_cte.valid) { + + devid = FIELD_EX64(cmdpkt[0], VMOVI_0, DEVICEID); + eventid = FIELD_EX64(cmdpkt[1], VMOVI_1, EVENTID); + vpeid = FIELD_EX64(cmdpkt[1], VMOVI_1, VPEID); + doorbell_valid = FIELD_EX64(cmdpkt[2], VMOVI_2, D); + doorbell = FIELD_EX64(cmdpkt[2], VMOVI_2, DOORBELL); + + trace_gicv3_its_cmd_vmovi(devid, eventid, vpeid, doorbell_valid, doorbell); + + if (doorbell_valid && !valid_doorbell(doorbell)) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: " - "invalid CTE for old ICID 0x%x\n", - __func__, old_ite.icid); + "%s: invalid doorbell 0x%x\n", __func__, doorbell); return CMD_CONTINUE; } - if (get_cte(s, new_icid, &new_cte) != MEMTX_OK) { - return CMD_STALL; + cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; } - if (!new_cte.valid) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: " - "invalid CTE for new ICID 0x%x\n", - __func__, new_icid); + + if (ite.inttype != ITE_INTTYPE_VIRTUAL) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: ITE is not for virtual interrupt\n", + __func__); return CMD_CONTINUE; } - if (old_cte.rdbase >= s->gicv3->num_cpu) { + cmdres = lookup_vte(s, __func__, ite.vpeid, &old_vte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + cmdres = lookup_vte(s, __func__, vpeid, &new_vte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + + if (!intid_in_lpi_range(ite.intid) || + ite.intid >= (1ULL << (old_vte.vptsize + 1)) || + ite.intid >= (1ULL << (new_vte.vptsize + 1))) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: CTE has invalid rdbase 0x%x\n", - __func__, old_cte.rdbase); + "%s: ITE intid 0x%x out of range\n", + __func__, ite.intid); return CMD_CONTINUE; } - if (new_cte.rdbase >= s->gicv3->num_cpu) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: CTE has invalid rdbase 0x%x\n", - __func__, new_cte.rdbase); + ite.vpeid = vpeid; + if (doorbell_valid) { + ite.doorbell = doorbell; + } + + /* + * Move the LPI from the old redistributor to the new one. We don't + * need to do anything if the guest somehow specified the + * same pending table for source and destination. + */ + if (old_vte.vptaddr != new_vte.vptaddr) { + gicv3_redist_mov_vlpi(&s->gicv3->cpu[old_vte.rdbase], + old_vte.vptaddr << 16, + &s->gicv3->cpu[new_vte.rdbase], + new_vte.vptaddr << 16, + ite.intid, + ite.doorbell); + } + + /* Update the ITE to the new VPEID and possibly doorbell values */ + return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL; +} + +static ItsCmdResult process_vinvall(GICv3ITSState *s, const uint64_t *cmdpkt) +{ + VTEntry vte; + uint32_t vpeid; + ItsCmdResult cmdres; + + if (!its_feature_virtual(s)) { return CMD_CONTINUE; } - if (old_cte.rdbase != new_cte.rdbase) { - /* Move the LPI from the old redistributor to the new one */ - gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase], - &s->gicv3->cpu[new_cte.rdbase], - old_ite.intid); + vpeid = FIELD_EX64(cmdpkt[1], VINVALL_1, VPEID); + + trace_gicv3_its_cmd_vinvall(vpeid); + + cmdres = lookup_vte(s, __func__, vpeid, &vte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; } - /* Update the ICID field in the interrupt translation table entry */ - old_ite.icid = new_icid; - return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE : CMD_STALL; + gicv3_redist_vinvall(&s->gicv3->cpu[vte.rdbase], vte.vptaddr << 16); + return CMD_CONTINUE_OK; +} + +static ItsCmdResult process_inv(GICv3ITSState *s, const uint64_t *cmdpkt) +{ + uint32_t devid, eventid; + ITEntry ite; + DTEntry dte; + CTEntry cte; + VTEntry vte; + ItsCmdResult cmdres; + + devid = FIELD_EX64(cmdpkt[0], INV_0, DEVICEID); + eventid = FIELD_EX64(cmdpkt[1], INV_1, EVENTID); + + trace_gicv3_its_cmd_inv(devid, eventid); + + cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + + switch (ite.inttype) { + case ITE_INTTYPE_PHYSICAL: + cmdres = lookup_cte(s, __func__, ite.icid, &cte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + gicv3_redist_inv_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid); + break; + case ITE_INTTYPE_VIRTUAL: + if (!its_feature_virtual(s)) { + /* Can't happen unless guest is illegally writing to table memory */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid type %d in ITE (table corrupted?)\n", + __func__, ite.inttype); + return CMD_CONTINUE; + } + + cmdres = lookup_vte(s, __func__, ite.vpeid, &vte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + if (!intid_in_lpi_range(ite.intid) || + ite.intid >= (1ULL << (vte.vptsize + 1))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: intid 0x%x out of range\n", + __func__, ite.intid); + return CMD_CONTINUE; + } + gicv3_redist_inv_vlpi(&s->gicv3->cpu[vte.rdbase], ite.intid, + vte.vptaddr << 16); + break; + default: + g_assert_not_reached(); + } + + return CMD_CONTINUE_OK; } /* @@ -782,7 +1278,7 @@ static void process_cmdq(GICv3ITSState *s) } while (wr_offset != rd_offset) { - ItsCmdResult result = CMD_CONTINUE; + ItsCmdResult result = CMD_CONTINUE_OK; void *hostmem; hwaddr buflen; uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS]; @@ -827,6 +1323,17 @@ static void process_cmdq(GICv3ITSState *s) */ trace_gicv3_its_cmd_sync(); break; + case GITS_CMD_VSYNC: + /* + * VSYNC also is a nop, because our implementation is always + * in sync. + */ + if (!its_feature_virtual(s)) { + result = CMD_CONTINUE; + break; + } + trace_gicv3_its_cmd_vsync(); + break; case GITS_CMD_MAPD: result = process_mapd(s, cmdpkt); break; @@ -843,14 +1350,18 @@ static void process_cmdq(GICv3ITSState *s) result = process_its_cmd(s, cmdpkt, DISCARD); break; case GITS_CMD_INV: + result = process_inv(s, cmdpkt); + break; case GITS_CMD_INVALL: /* * Current implementation doesn't cache any ITS tables, * but the calculated lpi priority information. We only * need to trigger lpi priority re-calculation to be in * sync with LPI config table or pending table changes. + * INVALL operates on a collection specified by ICID so + * it only affects physical LPIs. */ - trace_gicv3_its_cmd_inv(); + trace_gicv3_its_cmd_invall(); for (i = 0; i < s->gicv3->num_cpu; i++) { gicv3_redist_update_lpi(&s->gicv3->cpu[i]); } @@ -861,11 +1372,30 @@ static void process_cmdq(GICv3ITSState *s) case GITS_CMD_MOVALL: result = process_movall(s, cmdpkt); break; + case GITS_CMD_VMAPTI: + result = process_vmapti(s, cmdpkt, false); + break; + case GITS_CMD_VMAPI: + result = process_vmapti(s, cmdpkt, true); + break; + case GITS_CMD_VMAPP: + result = process_vmapp(s, cmdpkt); + break; + case GITS_CMD_VMOVP: + result = process_vmovp(s, cmdpkt); + break; + case GITS_CMD_VMOVI: + result = process_vmovi(s, cmdpkt); + break; + case GITS_CMD_VINVALL: + result = process_vinvall(s, cmdpkt); + break; default: trace_gicv3_its_cmd_unknown(cmd); break; } - if (result == CMD_CONTINUE) { + if (result != CMD_STALL) { + /* CMD_CONTINUE or CMD_CONTINUE_OK */ rd_offset++; rd_offset %= s->cq.num_entries; s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset); @@ -941,6 +1471,15 @@ static void extract_table_params(GICv3ITSState *s) idbits = 16; } break; + case GITS_BASER_TYPE_VPE: + td = &s->vpet; + /* + * For QEMU vPEIDs are always 16 bits. (GICv4.1 allows an + * implementation to implement fewer bits and report this + * via GICD_TYPER2.) + */ + idbits = 16; + break; default: /* * GITS_BASER.TYPE is read-only, so GITS_BASER_RO_MASK @@ -1160,7 +1699,7 @@ static bool its_readl(GICv3ITSState *s, hwaddr offset, break; case GITS_IDREGS ... GITS_IDREGS + 0x2f: /* ID registers */ - *data = gicv3_idreg(offset - GITS_IDREGS); + *data = gicv3_idreg(s->gicv3, offset - GITS_IDREGS, GICV3_PIDR0_ITS); break; case GITS_TYPER: *data = extract64(s->typer, 0, 32); @@ -1395,6 +1934,8 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp) } } + gicv3_add_its(s->gicv3, dev); + gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops); /* set the ITS default features supported */ @@ -1405,14 +1946,21 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp) s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS); s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1); s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS); + if (s->gicv3->revision >= 4) { + /* Our VMOVP handles cross-ITS synchronization itself */ + s->typer = FIELD_DP64(s->typer, GITS_TYPER, VMOVP, 1); + s->typer = FIELD_DP64(s->typer, GITS_TYPER, VIRTUAL, 1); + } } -static void gicv3_its_reset(DeviceState *dev) +static void gicv3_its_reset_hold(Object *obj) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s); - c->parent_reset(dev); + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } /* Quiescent bit reset to 1 */ s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1); @@ -1420,6 +1968,7 @@ static void gicv3_its_reset(DeviceState *dev) /* * setting GITS_BASER0.Type = 0b001 (Device) * GITS_BASER1.Type = 0b100 (Collection Table) + * GITS_BASER2.Type = 0b010 (vPE) for GICv4 and later * GITS_BASER.Type,where n = 3 to 7 are 0b00 (Unimplemented) * GITS_BASER<0,1>.Page_Size = 64KB * and default translation table entry size to 16 bytes @@ -1437,6 +1986,15 @@ static void gicv3_its_reset(DeviceState *dev) GITS_BASER_PAGESIZE_64K); s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE, GITS_CTE_SIZE - 1); + + if (its_feature_virtual(s)) { + s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, TYPE, + GITS_BASER_TYPE_VPE); + s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, PAGESIZE, + GITS_BASER_PAGESIZE_64K); + s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, ENTRYSIZE, + GITS_VPE_SIZE - 1); + } } static void gicv3_its_post_load(GICv3ITSState *s) @@ -1456,12 +2014,14 @@ static Property gicv3_its_props[] = { static void gicv3_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass); GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); dc->realize = gicv3_arm_its_realize; device_class_set_props(dc, gicv3_its_props); - device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset); + resettable_class_set_parent_phases(rc, NULL, gicv3_its_reset_hold, NULL, + &ic->parent_phases); icc->post_load = gicv3_its_post_load; } diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 90b85f1e25c2..d7532a7a8997 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -122,9 +122,9 @@ void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops, msi_nonbroken = true; } -static void gicv3_its_common_reset(DeviceState *dev) +static void gicv3_its_common_reset_hold(Object *obj) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); s->ctlr = 0; s->cbaser = 0; @@ -137,8 +137,9 @@ static void gicv3_its_common_reset(DeviceState *dev) static void gicv3_its_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - dc->reset = gicv3_its_common_reset; + rc->phases.hold = gicv3_its_common_reset_hold; dc->vmsd = &vmstate_its; } diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 0b4cbed28b3b..7eda9fb86eac 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -37,7 +37,7 @@ DECLARE_OBJ_CHECKERS(GICv3ITSState, KVMARMITSClass, struct KVMARMITSClass { GICv3ITSCommonClass parent_class; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; @@ -106,6 +106,8 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd, 0); + gicv3_add_its(s->gicv3, dev); + gicv3_its_init_mmio(s, NULL, NULL); if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, @@ -195,13 +197,15 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) GITS_CTLR, &s->ctlr, true, &error_abort); } -static void kvm_arm_its_reset(DeviceState *dev) +static void kvm_arm_its_reset_hold(Object *obj) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s); int i; - c->parent_reset(dev); + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_ITS_CTRL_RESET)) { @@ -239,12 +243,14 @@ static Property kvm_arm_its_props[] = { static void kvm_arm_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); KVMARMITSClass *ic = KVM_ARM_ITS_CLASS(klass); dc->realize = kvm_arm_its_realize; device_class_set_props(dc, kvm_arm_its_props); - device_class_set_parent_reset(dc, kvm_arm_its_reset, &ic->parent_reset); + resettable_class_set_parent_phases(rc, NULL, kvm_arm_its_reset_hold, NULL, + &ic->parent_phases); icc->send_msi = kvm_its_send_msi; icc->pre_save = kvm_arm_its_pre_save; icc->post_load = kvm_arm_its_post_load; diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 5ec5ff9ef6e8..72ad916d3db4 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -31,6 +31,8 @@ #include "vgic_common.h" #include "migration/blocker.h" #include "qom/object.h" +#include "target/arm/cpregs.h" + #ifdef DEBUG_GICV3_KVM #define DPRINTF(fmt, ...) \ @@ -75,7 +77,7 @@ DECLARE_OBJ_CHECKERS(GICv3State, KVMARMGICv3Class, struct KVMARMGICv3Class { ARMGICv3CommonClass parent_class; DeviceRealize parent_realize; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) @@ -671,9 +673,19 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) s = c->gic; c->icc_pmr_el1 = 0; - c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; - c->icc_bpr[GICV3_G1] = GIC_MIN_BPR; - c->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR; + /* + * Architecturally the reset value of the ICC_BPR registers + * is UNKNOWN. We set them all to 0 here; when the kernel + * uses these values to program the ICH_VMCR_EL2 fields that + * determine the guest-visible ICC_BPR register values, the + * hardware's "writing a value less than the minimum sets + * the field to the minimum value" behaviour will result in + * them effectively resetting to the correct minimum value + * for the host GIC. + */ + c->icc_bpr[GICV3_G0] = 0; + c->icc_bpr[GICV3_G1] = 0; + c->icc_bpr[GICV3_G1NS] = 0; c->icc_sre_el1 = 0x7; memset(c->icc_apr, 0, sizeof(c->icc_apr)); @@ -691,14 +703,16 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } -static void kvm_arm_gicv3_reset(DeviceState *dev) +static void kvm_arm_gicv3_reset_hold(Object *obj) { - GICv3State *s = ARM_GICV3_COMMON(dev); + GICv3State *s = ARM_GICV3_COMMON(obj); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); DPRINTF("Reset\n"); - kgc->parent_reset(dev); + if (kgc->parent_phases.hold) { + kgc->parent_phases.hold(obj); + } if (s->migration_blocker) { DPRINTF("Cannot put kernel gic state, no kernel interface\n"); @@ -733,7 +747,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { */ .resetfn = arm_gicv3_icc_reset, }, - REGINFO_SENTINEL }; /** @@ -781,6 +794,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) return; } + if (s->revision != 3) { + error_setg(errp, "unsupported GIC revision %d for in-kernel GIC", + s->revision); + } + if (s->security_extn) { error_setg(errp, "the in-kernel VGICv3 does not implement the " "security extensions"); @@ -874,6 +892,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass); @@ -881,7 +900,8 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) agcc->post_load = kvm_arm_gicv3_put; device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, &kgc->parent_realize); - device_class_set_parent_reset(dc, kvm_arm_gicv3_reset, &kgc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, kvm_arm_gicv3_reset_hold, NULL, + &kgc->parent_phases); } static const TypeInfo kvm_arm_gicv3_info = { diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index 412a04f59cf2..c92ceecc1687 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -60,6 +60,132 @@ static uint32_t gicr_read_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, return reg; } +static bool vcpu_resident(GICv3CPUState *cs, uint64_t vptaddr) +{ + /* + * Return true if a vCPU is resident, which is defined by + * whether the GICR_VPENDBASER register is marked VALID and + * has the right virtual pending table address. + */ + if (!FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID)) { + return false; + } + return vptaddr == (cs->gicr_vpendbaser & R_GICR_VPENDBASER_PHYADDR_MASK); +} + +/** + * update_for_one_lpi: Update pending information if this LPI is better + * + * @cs: GICv3CPUState + * @irq: interrupt to look up in the LPI Configuration table + * @ctbase: physical address of the LPI Configuration table to use + * @ds: true if priority value should not be shifted + * @hpp: points to pending information to update + * + * Look up @irq in the Configuration table specified by @ctbase + * to see if it is enabled and what its priority is. If it is an + * enabled interrupt with a higher priority than that currently + * recorded in @hpp, update @hpp. + */ +static void update_for_one_lpi(GICv3CPUState *cs, int irq, + uint64_t ctbase, bool ds, PendingIrq *hpp) +{ + uint8_t lpite; + uint8_t prio; + + address_space_read(&cs->gic->dma_as, + ctbase + ((irq - GICV3_LPI_INTID_START) * sizeof(lpite)), + MEMTXATTRS_UNSPECIFIED, &lpite, sizeof(lpite)); + + if (!(lpite & LPI_CTE_ENABLED)) { + return; + } + + if (ds) { + prio = lpite & LPI_PRIORITY_MASK; + } else { + prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80; + } + + if ((prio < hpp->prio) || + ((prio == hpp->prio) && (irq <= hpp->irq))) { + hpp->irq = irq; + hpp->prio = prio; + /* LPIs and vLPIs are always non-secure Grp1 interrupts */ + hpp->grp = GICV3_G1NS; + } +} + +/** + * update_for_all_lpis: Fully scan LPI tables and find best pending LPI + * + * @cs: GICv3CPUState + * @ptbase: physical address of LPI Pending table + * @ctbase: physical address of LPI Configuration table + * @ptsizebits: size of tables, specified as number of interrupt ID bits minus 1 + * @ds: true if priority value should not be shifted + * @hpp: points to pending information to set + * + * Recalculate the highest priority pending enabled LPI from scratch, + * and set @hpp accordingly. + * + * We scan the LPI pending table @ptbase; for each pending LPI, we read the + * corresponding entry in the LPI configuration table @ctbase to extract + * the priority and enabled information. + * + * We take @ptsizebits in the form idbits-1 because this is the way that + * LPI table sizes are architecturally specified in GICR_PROPBASER.IDBits + * and in the VMAPP command's VPT_size field. + */ +static void update_for_all_lpis(GICv3CPUState *cs, uint64_t ptbase, + uint64_t ctbase, unsigned ptsizebits, + bool ds, PendingIrq *hpp) +{ + AddressSpace *as = &cs->gic->dma_as; + uint8_t pend; + uint32_t pendt_size = (1ULL << (ptsizebits + 1)); + int i, bit; + + hpp->prio = 0xff; + + for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) { + address_space_read(as, ptbase + i, MEMTXATTRS_UNSPECIFIED, &pend, 1); + while (pend) { + bit = ctz32(pend); + update_for_one_lpi(cs, i * 8 + bit, ctbase, ds, hpp); + pend &= ~(1 << bit); + } + } +} + +/** + * set_lpi_pending_bit: Set or clear pending bit for an LPI + * + * @cs: GICv3CPUState + * @ptbase: physical address of LPI Pending table + * @irq: LPI to change pending state for + * @level: false to clear pending state, true to set + * + * Returns true if we needed to do something, false if the pending bit + * was already at @level. + */ +static bool set_pending_table_bit(GICv3CPUState *cs, uint64_t ptbase, + int irq, bool level) +{ + AddressSpace *as = &cs->gic->dma_as; + uint64_t addr = ptbase + irq / 8; + uint8_t pend; + + address_space_read(as, addr, MEMTXATTRS_UNSPECIFIED, &pend, 1); + if (extract32(pend, irq % 8, 1) == level) { + /* Bit already at requested state, no action required */ + return false; + } + pend = deposit32(pend, irq % 8, 1, level ? 1 : 0); + address_space_write(as, addr, MEMTXATTRS_UNSPECIFIED, &pend, 1); + return true; +} + static uint8_t gicr_read_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, int irq) { @@ -100,6 +226,87 @@ static void gicr_write_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, int irq, cs->gicr_ipriorityr[irq] = value; } +static void gicv3_redist_update_vlpi_only(GICv3CPUState *cs) +{ + uint64_t ptbase, ctbase, idbits; + + if (!FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID)) { + cs->hppvlpi.prio = 0xff; + return; + } + + ptbase = cs->gicr_vpendbaser & R_GICR_VPENDBASER_PHYADDR_MASK; + ctbase = cs->gicr_vpropbaser & R_GICR_VPROPBASER_PHYADDR_MASK; + idbits = FIELD_EX64(cs->gicr_vpropbaser, GICR_VPROPBASER, IDBITS); + + update_for_all_lpis(cs, ptbase, ctbase, idbits, true, &cs->hppvlpi); +} + +static void gicv3_redist_update_vlpi(GICv3CPUState *cs) +{ + gicv3_redist_update_vlpi_only(cs); + gicv3_cpuif_virt_irq_fiq_update(cs); +} + +static void gicr_write_vpendbaser(GICv3CPUState *cs, uint64_t newval) +{ + /* Write @newval to GICR_VPENDBASER, handling its effects */ + bool oldvalid = FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID); + bool newvalid = FIELD_EX64(newval, GICR_VPENDBASER, VALID); + bool pendinglast; + + /* + * The DIRTY bit is read-only and for us is always zero; + * other fields are writable. + */ + newval &= R_GICR_VPENDBASER_INNERCACHE_MASK | + R_GICR_VPENDBASER_SHAREABILITY_MASK | + R_GICR_VPENDBASER_PHYADDR_MASK | + R_GICR_VPENDBASER_OUTERCACHE_MASK | + R_GICR_VPENDBASER_PENDINGLAST_MASK | + R_GICR_VPENDBASER_IDAI_MASK | + R_GICR_VPENDBASER_VALID_MASK; + + if (oldvalid && newvalid) { + /* + * Changing other fields while VALID is 1 is UNPREDICTABLE; + * we choose to log and ignore the write. + */ + if (cs->gicr_vpendbaser ^ newval) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Changing GICR_VPENDBASER when VALID=1 " + "is UNPREDICTABLE\n", __func__); + } + return; + } + if (!oldvalid && !newvalid) { + cs->gicr_vpendbaser = newval; + return; + } + + if (newvalid) { + /* + * Valid going from 0 to 1: update hppvlpi from tables. + * If IDAI is 0 we are allowed to use the info we cached in + * the IMPDEF area of the table. + * PendingLast is RES1 when we make this transition. + */ + pendinglast = true; + } else { + /* + * Valid going from 1 to 0: + * Set PendingLast if there was a pending enabled interrupt + * for the vPE that was just descheduled. + * If we cache info in the IMPDEF area, write it out here. + */ + pendinglast = cs->hppvlpi.prio != 0xff; + } + + newval = FIELD_DP64(newval, GICR_VPENDBASER, PENDINGLAST, pendinglast); + cs->gicr_vpendbaser = newval; + gicv3_redist_update_vlpi(cs); +} + static MemTxResult gicr_readb(GICv3CPUState *cs, hwaddr offset, uint64_t *data, MemTxAttrs attrs) { @@ -234,7 +441,24 @@ static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset, *data = cs->gicr_nsacr; return MEMTX_OK; case GICR_IDREGS ... GICR_IDREGS + 0x2f: - *data = gicv3_idreg(offset - GICR_IDREGS); + *data = gicv3_idreg(cs->gic, offset - GICR_IDREGS, GICV3_PIDR0_REDIST); + return MEMTX_OK; + /* + * VLPI frame registers. We don't need a version check for + * VPROPBASER and VPENDBASER because gicv3_redist_size() will + * prevent pre-v4 GIC from passing us offsets this high. + */ + case GICR_VPROPBASER: + *data = extract64(cs->gicr_vpropbaser, 0, 32); + return MEMTX_OK; + case GICR_VPROPBASER + 4: + *data = extract64(cs->gicr_vpropbaser, 32, 32); + return MEMTX_OK; + case GICR_VPENDBASER: + *data = extract64(cs->gicr_vpendbaser, 0, 32); + return MEMTX_OK; + case GICR_VPENDBASER + 4: + *data = extract64(cs->gicr_vpendbaser, 32, 32); return MEMTX_OK; default: return MEMTX_ERROR; @@ -267,8 +491,8 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, /* RAZ/WI for our implementation */ return MEMTX_OK; case GICR_WAKER: - /* Only the ProcessorSleep bit is writeable. When the guest sets - * it it requests that we transition the channel between the + /* Only the ProcessorSleep bit is writable. When the guest sets + * 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. @@ -379,6 +603,23 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, "%s: invalid guest write to RO register at offset " TARGET_FMT_plx "\n", __func__, offset); return MEMTX_OK; + /* + * VLPI frame registers. We don't need a version check for + * VPROPBASER and VPENDBASER because gicv3_redist_size() will + * prevent pre-v4 GIC from passing us offsets this high. + */ + case GICR_VPROPBASER: + cs->gicr_vpropbaser = deposit64(cs->gicr_vpropbaser, 0, 32, value); + return MEMTX_OK; + case GICR_VPROPBASER + 4: + cs->gicr_vpropbaser = deposit64(cs->gicr_vpropbaser, 32, 32, value); + return MEMTX_OK; + case GICR_VPENDBASER: + gicr_write_vpendbaser(cs, deposit64(cs->gicr_vpendbaser, 0, 32, value)); + return MEMTX_OK; + case GICR_VPENDBASER + 4: + gicr_write_vpendbaser(cs, deposit64(cs->gicr_vpendbaser, 32, 32, value)); + return MEMTX_OK; default: return MEMTX_ERROR; } @@ -397,6 +638,17 @@ static MemTxResult gicr_readll(GICv3CPUState *cs, hwaddr offset, case GICR_PENDBASER: *data = cs->gicr_pendbaser; return MEMTX_OK; + /* + * VLPI frame registers. We don't need a version check for + * VPROPBASER and VPENDBASER because gicv3_redist_size() will + * prevent pre-v4 GIC from passing us offsets this high. + */ + case GICR_VPROPBASER: + *data = cs->gicr_vpropbaser; + return MEMTX_OK; + case GICR_VPENDBASER: + *data = cs->gicr_vpendbaser; + return MEMTX_OK; default: return MEMTX_ERROR; } @@ -418,6 +670,17 @@ static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset, "%s: invalid guest write to RO register at offset " TARGET_FMT_plx "\n", __func__, offset); return MEMTX_OK; + /* + * VLPI frame registers. We don't need a version check for + * VPROPBASER and VPENDBASER because gicv3_redist_size() will + * prevent pre-v4 GIC from passing us offsets this high. + */ + case GICR_VPROPBASER: + cs->gicr_vpropbaser = value; + return MEMTX_OK; + case GICR_VPENDBASER: + gicr_write_vpendbaser(cs, value); + return MEMTX_OK; default: return MEMTX_ERROR; } @@ -442,8 +705,8 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, * in the memory map); if so then the GIC has multiple MemoryRegions * for the redistributors. */ - cpuidx = region->cpuidx + offset / GICV3_REDIST_SIZE; - offset %= GICV3_REDIST_SIZE; + cpuidx = region->cpuidx + offset / gicv3_redist_size(s); + offset %= gicv3_redist_size(s); cs = &s->cpu[cpuidx]; @@ -501,8 +764,8 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, * in the memory map); if so then the GIC has multiple MemoryRegions * for the redistributors. */ - cpuidx = region->cpuidx + offset / GICV3_REDIST_SIZE; - offset %= GICV3_REDIST_SIZE; + cpuidx = region->cpuidx + offset / gicv3_redist_size(s); + offset %= gicv3_redist_size(s); cs = &s->cpu[cpuidx]; @@ -542,34 +805,11 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq) { - AddressSpace *as = &cs->gic->dma_as; - uint64_t lpict_baddr; - uint8_t lpite; - uint8_t prio; - - lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK; + uint64_t lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK; - address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) * - sizeof(lpite)), MEMTXATTRS_UNSPECIFIED, &lpite, - sizeof(lpite)); - - if (!(lpite & LPI_CTE_ENABLED)) { - return; - } - - if (cs->gic->gicd_ctlr & GICD_CTLR_DS) { - prio = lpite & LPI_PRIORITY_MASK; - } else { - prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80; - } - - if ((prio < cs->hpplpi.prio) || - ((prio == cs->hpplpi.prio) && (irq <= cs->hpplpi.irq))) { - cs->hpplpi.irq = irq; - cs->hpplpi.prio = prio; - /* LPIs are always non-secure Grp1 interrupts */ - cs->hpplpi.grp = GICV3_G1NS; - } + update_for_one_lpi(cs, irq, lpict_baddr, + cs->gic->gicd_ctlr & GICD_CTLR_DS, + &cs->hpplpi); } void gicv3_redist_update_lpi_only(GICv3CPUState *cs) @@ -581,11 +821,7 @@ void gicv3_redist_update_lpi_only(GICv3CPUState *cs) * priority is lower than the last computed high priority lpi interrupt. * If yes, replace current LPI as the new high priority lpi interrupt. */ - AddressSpace *as = &cs->gic->dma_as; - uint64_t lpipt_baddr; - uint32_t pendt_size = 0; - uint8_t pend; - int i, bit; + uint64_t lpipt_baddr, lpict_baddr; uint64_t idbits; idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS), @@ -595,23 +831,11 @@ void gicv3_redist_update_lpi_only(GICv3CPUState *cs) return; } - cs->hpplpi.prio = 0xff; - lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; + lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK; - /* Determine the highest priority pending interrupt among LPIs */ - pendt_size = (1ULL << (idbits + 1)); - - for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) { - address_space_read(as, lpipt_baddr + i, MEMTXATTRS_UNSPECIFIED, &pend, - sizeof(pend)); - - while (pend) { - bit = ctz32(pend); - gicv3_redist_check_lpi_priority(cs, i * 8 + bit); - pend &= ~(1 << bit); - } - } + update_for_all_lpis(cs, lpipt_baddr, lpict_baddr, idbits, + cs->gic->gicd_ctlr & GICD_CTLR_DS, &cs->hpplpi); } void gicv3_redist_update_lpi(GICv3CPUState *cs) @@ -626,30 +850,13 @@ void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) * This function updates the pending bit in lpi pending table for * the irq being activated or deactivated. */ - AddressSpace *as = &cs->gic->dma_as; uint64_t lpipt_baddr; - bool ispend = false; - uint8_t pend; - /* - * get the bit value corresponding to this irq in the - * lpi pending table - */ lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; - - address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)), - MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend)); - - ispend = extract32(pend, irq % 8, 1); - - /* no change in the value of pending bit, return */ - if (ispend == level) { + if (!set_pending_table_bit(cs, lpipt_baddr, irq, level)) { + /* no change in the value of pending bit, return */ return; } - pend = deposit32(pend, irq % 8, 1, level ? 1 : 0); - - address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)), - MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend)); /* * check if this LPI is better than the current hpplpi, if yes @@ -681,6 +888,17 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level) gicv3_redist_lpi_pending(cs, irq, level); } +void gicv3_redist_inv_lpi(GICv3CPUState *cs, int irq) +{ + /* + * The only cached information for LPIs we have is the HPPLPI. + * We could be cleverer about identifying when we don't need + * to do a full rescan of the pending table, but until we find + * this is a performance issue, just always recalculate. + */ + gicv3_redist_update_lpi(cs); +} + void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq) { /* @@ -691,11 +909,9 @@ void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq) * we choose to NOP. If LPIs are disabled on source there's nothing * to be transferred anyway. */ - AddressSpace *as = &src->gic->dma_as; uint64_t idbits; uint32_t pendt_size; uint64_t src_baddr; - uint8_t src_pend; if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) { @@ -714,15 +930,10 @@ void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq) src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; - address_space_read(as, src_baddr + (irq / 8), - MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend)); - if (!extract32(src_pend, irq % 8, 1)) { + if (!set_pending_table_bit(src, src_baddr, irq, 0)) { /* Not pending on source, nothing to do */ return; } - src_pend &= ~(1 << (irq % 8)); - address_space_write(as, src_baddr + (irq / 8), - MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend)); if (irq == src->hpplpi.irq) { /* * We just made this LPI not-pending so only need to update @@ -788,6 +999,117 @@ void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest) gicv3_redist_update_lpi(dest); } +void gicv3_redist_vlpi_pending(GICv3CPUState *cs, int irq, int level) +{ + /* + * Change the pending state of the specified vLPI. + * Unlike gicv3_redist_process_vlpi(), we know here that the + * vCPU is definitely resident on this redistributor, and that + * the irq is in range. + */ + uint64_t vptbase, ctbase; + + vptbase = FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, PHYADDR) << 16; + + if (set_pending_table_bit(cs, vptbase, irq, level)) { + if (level) { + /* Check whether this vLPI is now the best */ + ctbase = cs->gicr_vpropbaser & R_GICR_VPROPBASER_PHYADDR_MASK; + update_for_one_lpi(cs, irq, ctbase, true, &cs->hppvlpi); + gicv3_cpuif_virt_irq_fiq_update(cs); + } else { + /* Only need to recalculate if this was previously the best vLPI */ + if (irq == cs->hppvlpi.irq) { + gicv3_redist_update_vlpi(cs); + } + } + } +} + +void gicv3_redist_process_vlpi(GICv3CPUState *cs, int irq, uint64_t vptaddr, + int doorbell, int level) +{ + bool bit_changed; + bool resident = vcpu_resident(cs, vptaddr); + uint64_t ctbase; + + if (resident) { + uint32_t idbits = FIELD_EX64(cs->gicr_vpropbaser, GICR_VPROPBASER, IDBITS); + if (irq >= (1ULL << (idbits + 1))) { + return; + } + } + + bit_changed = set_pending_table_bit(cs, vptaddr, irq, level); + if (resident && bit_changed) { + if (level) { + /* Check whether this vLPI is now the best */ + ctbase = cs->gicr_vpropbaser & R_GICR_VPROPBASER_PHYADDR_MASK; + update_for_one_lpi(cs, irq, ctbase, true, &cs->hppvlpi); + gicv3_cpuif_virt_irq_fiq_update(cs); + } else { + /* Only need to recalculate if this was previously the best vLPI */ + if (irq == cs->hppvlpi.irq) { + gicv3_redist_update_vlpi(cs); + } + } + } + + if (!resident && level && doorbell != INTID_SPURIOUS && + (cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) { + /* vCPU is not currently resident: ring the doorbell */ + gicv3_redist_process_lpi(cs, doorbell, 1); + } +} + +void gicv3_redist_mov_vlpi(GICv3CPUState *src, uint64_t src_vptaddr, + GICv3CPUState *dest, uint64_t dest_vptaddr, + int irq, int doorbell) +{ + /* + * Move the specified vLPI's pending state from the source redistributor + * to the destination. + */ + if (!set_pending_table_bit(src, src_vptaddr, irq, 0)) { + /* Not pending on source, nothing to do */ + return; + } + if (vcpu_resident(src, src_vptaddr) && irq == src->hppvlpi.irq) { + /* + * Update src's cached highest-priority pending vLPI if we just made + * it not-pending + */ + gicv3_redist_update_vlpi(src); + } + /* + * Mark the vLPI pending on the destination (ringing the doorbell + * if the vCPU isn't resident) + */ + gicv3_redist_process_vlpi(dest, irq, dest_vptaddr, doorbell, irq); +} + +void gicv3_redist_vinvall(GICv3CPUState *cs, uint64_t vptaddr) +{ + if (!vcpu_resident(cs, vptaddr)) { + /* We don't have anything cached if the vCPU isn't resident */ + return; + } + + /* Otherwise, our only cached information is the HPPVLPI info */ + gicv3_redist_update_vlpi(cs); +} + +void gicv3_redist_inv_vlpi(GICv3CPUState *cs, int irq, uint64_t vptaddr) +{ + /* + * The only cached information for LPIs we have is the HPPLPI. + * We could be cleverer about identifying when we don't need + * to do a full rescan of the pending table, but until we find + * this is a performance issue, just always recalculate. + */ + gicv3_redist_vinvall(cs, vptaddr); +} + void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) { /* Update redistributor state for a change in an external PPI input line */ diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 13df002ce4db..1f7763964c37 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2389,8 +2389,15 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, startvec = 8 * (offset - 0x280) + NVIC_FIRST_IRQ; /* vector # */ for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++) { + /* + * Note that if the input line is still held high and the interrupt + * is not active then rule R_CVJS requires that the Pending state + * remains set; in that case we mustn't let it be cleared. + */ if (value & (1 << i) && - (attrs.secure || s->itns[startvec + i])) { + (attrs.secure || s->itns[startvec + i]) && + !(setval == 0 && s->vectors[startvec + i].level && + !s->vectors[startvec + i].active)) { s->vectors[startvec + i].pending = setval; } } diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index 4534ee248db2..a289510bdb88 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -31,7 +31,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/module.h" - +#include "hw/intc/exynos4210_combiner.h" #include "hw/arm/exynos4210.h" #include "hw/hw.h" #include "hw/irq.h" @@ -48,36 +48,7 @@ #define DPRINTF(fmt, ...) do {} while (0) #endif -#define IIC_NGRP 64 /* Internal Interrupt Combiner - Groups number */ -#define IIC_NIRQ (IIC_NGRP * 8)/* Internal Interrupt Combiner - Interrupts number */ #define IIC_REGION_SIZE 0x108 /* Size of memory mapped region */ -#define IIC_REGSET_SIZE 0x41 - -/* - * State for each output signal of internal combiner - */ -typedef struct CombinerGroupState { - uint8_t src_mask; /* 1 - source enabled, 0 - disabled */ - uint8_t src_pending; /* Pending source interrupts before masking */ -} CombinerGroupState; - -#define TYPE_EXYNOS4210_COMBINER "exynos4210.combiner" -OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210CombinerState, EXYNOS4210_COMBINER) - -struct Exynos4210CombinerState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - struct CombinerGroupState group[IIC_NGRP]; - uint32_t reg_set[IIC_REGSET_SIZE]; - uint32_t icipsr[2]; - uint32_t external; /* 1 means that this combiner is external */ - - qemu_irq output_irq[IIC_NGRP]; -}; static const VMStateDescription vmstate_exynos4210_combiner_group_state = { .name = "exynos4210.combiner.groupstate", @@ -105,83 +76,6 @@ static const VMStateDescription vmstate_exynos4210_combiner = { } }; -/* - * Get Combiner input GPIO into irqs structure - */ -void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, - int ext) -{ - int n; - int bit; - int max; - qemu_irq *irq; - - max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ : - EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; - irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq; - - /* - * Some IRQs of Int/External Combiner are going to two Combiners groups, - * so let split them. - */ - for (n = 0; n < max; n++) { - - bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); - - switch (n) { - /* MDNIE_LCD1 INTG1 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]); - continue; - - /* TMU INTG3 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]); - continue; - - /* LCD1 INTG12 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]); - continue; - - /* Multi-Core Timer INTG12 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - - /* Multi-Core Timer INTG35 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - - /* Multi-Core Timer INTG51 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - - /* Multi-Core Timer INTG53 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - } - - irq[n] = qdev_get_gpio_in(dev, n); - } -} - static uint64_t exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size) { diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index bc73d1f11524..fcca85c6c694 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -27,157 +27,10 @@ #include "qemu/module.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "hw/intc/exynos4210_gic.h" #include "hw/arm/exynos4210.h" #include "qom/object.h" -enum ExtGicId { - EXT_GIC_ID_MDMA_LCD0 = 66, - EXT_GIC_ID_PDMA0, - EXT_GIC_ID_PDMA1, - EXT_GIC_ID_TIMER0, - EXT_GIC_ID_TIMER1, - EXT_GIC_ID_TIMER2, - EXT_GIC_ID_TIMER3, - EXT_GIC_ID_TIMER4, - EXT_GIC_ID_MCT_L0, - EXT_GIC_ID_WDT, - EXT_GIC_ID_RTC_ALARM, - EXT_GIC_ID_RTC_TIC, - EXT_GIC_ID_GPIO_XB, - EXT_GIC_ID_GPIO_XA, - EXT_GIC_ID_MCT_L1, - EXT_GIC_ID_IEM_APC, - EXT_GIC_ID_IEM_IEC, - EXT_GIC_ID_NFC, - EXT_GIC_ID_UART0, - EXT_GIC_ID_UART1, - EXT_GIC_ID_UART2, - EXT_GIC_ID_UART3, - EXT_GIC_ID_UART4, - EXT_GIC_ID_MCT_G0, - EXT_GIC_ID_I2C0, - EXT_GIC_ID_I2C1, - EXT_GIC_ID_I2C2, - EXT_GIC_ID_I2C3, - EXT_GIC_ID_I2C4, - EXT_GIC_ID_I2C5, - EXT_GIC_ID_I2C6, - EXT_GIC_ID_I2C7, - EXT_GIC_ID_SPI0, - EXT_GIC_ID_SPI1, - EXT_GIC_ID_SPI2, - EXT_GIC_ID_MCT_G1, - EXT_GIC_ID_USB_HOST, - EXT_GIC_ID_USB_DEVICE, - EXT_GIC_ID_MODEMIF, - EXT_GIC_ID_HSMMC0, - EXT_GIC_ID_HSMMC1, - EXT_GIC_ID_HSMMC2, - EXT_GIC_ID_HSMMC3, - EXT_GIC_ID_SDMMC, - EXT_GIC_ID_MIPI_CSI_4LANE, - EXT_GIC_ID_MIPI_DSI_4LANE, - EXT_GIC_ID_MIPI_CSI_2LANE, - EXT_GIC_ID_MIPI_DSI_2LANE, - EXT_GIC_ID_ONENAND_AUDI, - EXT_GIC_ID_ROTATOR, - EXT_GIC_ID_FIMC0, - EXT_GIC_ID_FIMC1, - EXT_GIC_ID_FIMC2, - EXT_GIC_ID_FIMC3, - EXT_GIC_ID_JPEG, - EXT_GIC_ID_2D, - EXT_GIC_ID_PCIe, - EXT_GIC_ID_MIXER, - EXT_GIC_ID_HDMI, - EXT_GIC_ID_HDMI_I2C, - EXT_GIC_ID_MFC, - EXT_GIC_ID_TVENC, -}; - -enum ExtInt { - EXT_GIC_ID_EXTINT0 = 48, - EXT_GIC_ID_EXTINT1, - EXT_GIC_ID_EXTINT2, - EXT_GIC_ID_EXTINT3, - EXT_GIC_ID_EXTINT4, - EXT_GIC_ID_EXTINT5, - EXT_GIC_ID_EXTINT6, - EXT_GIC_ID_EXTINT7, - EXT_GIC_ID_EXTINT8, - EXT_GIC_ID_EXTINT9, - EXT_GIC_ID_EXTINT10, - EXT_GIC_ID_EXTINT11, - EXT_GIC_ID_EXTINT12, - EXT_GIC_ID_EXTINT13, - EXT_GIC_ID_EXTINT14, - EXT_GIC_ID_EXTINT15 -}; - -/* - * External GIC sources which are not from External Interrupt Combiner or - * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ, - * which is INTG16 in Internal Interrupt Combiner. - */ - -static const uint32_t -combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { - /* int combiner groups 16-19 */ - { }, { }, { }, { }, - /* int combiner group 20 */ - { 0, EXT_GIC_ID_MDMA_LCD0 }, - /* int combiner group 21 */ - { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 }, - /* int combiner group 22 */ - { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2, - EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 }, - /* int combiner group 23 */ - { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC }, - /* int combiner group 24 */ - { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA }, - /* int combiner group 25 */ - { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC }, - /* int combiner group 26 */ - { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3, - EXT_GIC_ID_UART4 }, - /* int combiner group 27 */ - { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3, - EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, - EXT_GIC_ID_I2C7 }, - /* int combiner group 28 */ - { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, - /* int combiner group 29 */ - { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, - EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, - /* int combiner group 30 */ - { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE }, - /* int combiner group 31 */ - { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE }, - /* int combiner group 32 */ - { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 }, - /* int combiner group 33 */ - { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 }, - /* int combiner group 34 */ - { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC }, - /* int combiner group 35 */ - { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, - /* int combiner group 36 */ - { EXT_GIC_ID_MIXER }, - /* int combiner group 37 */ - { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6, - EXT_GIC_ID_EXTINT7 }, - /* groups 38-50 */ - { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, - /* int combiner group 51 */ - { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, - /* group 52 */ - { }, - /* int combiner group 53 */ - { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, - /* groups 54-63 */ - { }, { }, { }, { }, { }, { }, { }, { }, { }, { } -}; - #define EXYNOS4210_GIC_NIRQ 160 #define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000 @@ -192,92 +45,6 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { #define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100 #define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000 -static void exynos4210_irq_handler(void *opaque, int irq, int level) -{ - Exynos4210Irq *s = (Exynos4210Irq *)opaque; - - /* Bypass */ - qemu_set_irq(s->board_irqs[irq], level); -} - -/* - * Initialize exynos4210 IRQ subsystem stub. - */ -qemu_irq *exynos4210_init_irq(Exynos4210Irq *s) -{ - return qemu_allocate_irqs(exynos4210_irq_handler, s, - EXYNOS4210_MAX_INT_COMBINER_IN_IRQ); -} - -/* - * Initialize board IRQs. - * These IRQs contain splitted Int/External Combiner and External Gic IRQs. - */ -void exynos4210_init_board_irqs(Exynos4210Irq *s) -{ - uint32_t grp, bit, irq_id, n; - - for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) { - irq_id = 0; - if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) || - n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) { - /* MCT_G0 is passed to External GIC */ - irq_id = EXT_GIC_ID_MCT_G0; - } - if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) || - n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) { - /* MCT_G1 is passed to External and GIC */ - irq_id = EXT_GIC_ID_MCT_G1; - } - if (irq_id) { - s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], - s->ext_gic_irq[irq_id-32]); - } else { - s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], - s->ext_combiner_irq[n]); - } - } - for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) { - /* these IDs are passed to Internal Combiner and External GIC */ - grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n); - bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); - irq_id = combiner_grp_to_gic_id[grp - - EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit]; - - if (irq_id) { - s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], - s->ext_gic_irq[irq_id-32]); - } - } -} - -/* - * Get IRQ number from exynos4210 IRQ subsystem stub. - * To identify IRQ source use internal combiner group and bit number - * grp - group number - * bit - bit number inside group - */ -uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) -{ - return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit); -} - -/********* GIC part *********/ - -#define TYPE_EXYNOS4210_GIC "exynos4210.gic" -OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210GicState, EXYNOS4210_GIC) - -struct Exynos4210GicState { - SysBusDevice parent_obj; - - MemoryRegion cpu_container; - MemoryRegion dist_container; - MemoryRegion cpu_alias[EXYNOS4210_NCPUS]; - MemoryRegion dist_alias[EXYNOS4210_NCPUS]; - uint32_t num_cpu; - DeviceState *gic; -}; - static void exynos4210_gic_set_irq(void *opaque, int irq, int level) { Exynos4210GicState *s = (Exynos4210GicState *)opaque; @@ -289,10 +56,6 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp) Object *obj = OBJECT(dev); Exynos4210GicState *s = EXYNOS4210_GIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; - const char dist_prefix[] = "exynos4210-gic-alias_dist"; - char cpu_alias_name[sizeof(cpu_prefix) + 3]; - char dist_alias_name[sizeof(cpu_prefix) + 3]; SysBusDevice *gicbusdev; uint32_t n = s->num_cpu; uint32_t i; @@ -320,10 +83,12 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp) * enough room for the cpu numbers. gcc 9.2.1 on 32-bit x86 * doesn't figure this out, otherwise and gives spurious warnings. */ - assert(n <= EXYNOS4210_NCPUS); + assert(n <= EXYNOS4210_GIC_NCPUS); for (i = 0; i < n; i++) { + g_autofree char *cpu_alias_name = g_strdup_printf("exynos4210-gic-alias_cpu%u", i); + g_autofree char *dist_alias_name = g_strdup_printf("exynos4210-gic-alias_dist%u", i); + /* Map CPU interface per SMP Core */ - sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); memory_region_init_alias(&s->cpu_alias[i], obj, cpu_alias_name, sysbus_mmio_get_region(gicbusdev, 1), @@ -333,7 +98,6 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp) EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]); /* Map Distributor per SMP Core */ - sprintf(dist_alias_name, "%s%x", dist_prefix, i); memory_region_init_alias(&s->dist_alias[i], obj, dist_alias_name, sysbus_mmio_get_region(gicbusdev, 0), @@ -373,110 +137,3 @@ static void exynos4210_gic_register_types(void) } type_init(exynos4210_gic_register_types) - -/* IRQ OR Gate struct. - * - * This device models an OR gate. There are n_in input qdev gpio lines and one - * output sysbus IRQ line. The output IRQ level is formed as OR between all - * gpio inputs. - */ - -#define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate" -OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210IRQGateState, EXYNOS4210_IRQ_GATE) - -struct Exynos4210IRQGateState { - SysBusDevice parent_obj; - - uint32_t n_in; /* inputs amount */ - uint32_t *level; /* input levels */ - qemu_irq out; /* output IRQ */ -}; - -static Property exynos4210_irq_gate_properties[] = { - DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1), - DEFINE_PROP_END_OF_LIST(), -}; - -static const VMStateDescription vmstate_exynos4210_irq_gate = { - .name = "exynos4210.irq_gate", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, n_in), - VMSTATE_END_OF_LIST() - } -}; - -/* Process a change in IRQ input. */ -static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) -{ - Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque; - uint32_t i; - - assert(irq < s->n_in); - - s->level[irq] = level; - - for (i = 0; i < s->n_in; i++) { - if (s->level[i] >= 1) { - qemu_irq_raise(s->out); - return; - } - } - - qemu_irq_lower(s->out); -} - -static void exynos4210_irq_gate_reset(DeviceState *d) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d); - - memset(s->level, 0, s->n_in * sizeof(*s->level)); -} - -/* - * IRQ Gate initialization. - */ -static void exynos4210_irq_gate_init(Object *obj) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(sbd, &s->out); -} - -static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev); - - /* Allocate general purpose input signals and connect a handler to each of - * them */ - qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in); - - s->level = g_malloc0(s->n_in * sizeof(*s->level)); -} - -static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = exynos4210_irq_gate_reset; - dc->vmsd = &vmstate_exynos4210_irq_gate; - device_class_set_props(dc, exynos4210_irq_gate_properties); - dc->realize = exynos4210_irq_gate_realize; -} - -static const TypeInfo exynos4210_irq_gate_info = { - .name = TYPE_EXYNOS4210_IRQ_GATE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210IRQGateState), - .instance_init = exynos4210_irq_gate_init, - .class_init = exynos4210_irq_gate_class_init, -}; - -static void exynos4210_irq_gate_register_types(void) -{ - type_register_static(&exynos4210_irq_gate_info); -} - -type_init(exynos4210_irq_gate_register_types) diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index 2bf1baef0471..29d5cdc1b698 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -77,6 +77,7 @@ * Redistributor frame offsets from RD_base */ #define GICR_SGI_OFFSET 0x10000 +#define GICR_VLPI_OFFSET 0x20000 /* * Redistributor registers, offsets from RD_base @@ -109,6 +110,10 @@ #define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00) #define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00) +/* VLPI redistributor registers, offsets from VLPI_base */ +#define GICR_VPROPBASER (GICR_VLPI_OFFSET + 0x70) +#define GICR_VPENDBASER (GICR_VLPI_OFFSET + 0x78) + #define GICR_CTLR_ENABLE_LPIS (1U << 0) #define GICR_CTLR_CES (1U << 1) #define GICR_CTLR_RWP (1U << 3) @@ -143,6 +148,22 @@ FIELD(GICR_PENDBASER, PTZ, 62, 1) #define GICR_PROPBASER_IDBITS_THRESHOLD 0xd +/* These are the GICv4 VPROPBASER and VPENDBASER layouts; v4.1 is different */ +FIELD(GICR_VPROPBASER, IDBITS, 0, 5) +FIELD(GICR_VPROPBASER, INNERCACHE, 7, 3) +FIELD(GICR_VPROPBASER, SHAREABILITY, 10, 2) +FIELD(GICR_VPROPBASER, PHYADDR, 12, 40) +FIELD(GICR_VPROPBASER, OUTERCACHE, 56, 3) + +FIELD(GICR_VPENDBASER, INNERCACHE, 7, 3) +FIELD(GICR_VPENDBASER, SHAREABILITY, 10, 2) +FIELD(GICR_VPENDBASER, PHYADDR, 16, 36) +FIELD(GICR_VPENDBASER, OUTERCACHE, 56, 3) +FIELD(GICR_VPENDBASER, DIRTY, 60, 1) +FIELD(GICR_VPENDBASER, PENDINGLAST, 61, 1) +FIELD(GICR_VPENDBASER, IDAI, 62, 1) +FIELD(GICR_VPENDBASER, VALID, 63, 1) + #define ICC_CTLR_EL1_CBPR (1U << 0) #define ICC_CTLR_EL1_EOIMODE (1U << 1) #define ICC_CTLR_EL1_PMHE (1U << 6) @@ -280,6 +301,7 @@ FIELD(GITS_CTLR, ENABLED, 0, 1) FIELD(GITS_CTLR, QUIESCENT, 31, 1) FIELD(GITS_TYPER, PHYSICAL, 0, 1) +FIELD(GITS_TYPER, VIRTUAL, 1, 1) FIELD(GITS_TYPER, ITT_ENTRY_SIZE, 4, 4) FIELD(GITS_TYPER, IDBITS, 8, 5) FIELD(GITS_TYPER, DEVBITS, 13, 5) @@ -287,6 +309,7 @@ FIELD(GITS_TYPER, SEIS, 18, 1) FIELD(GITS_TYPER, PTA, 19, 1) FIELD(GITS_TYPER, CIDBITS, 32, 4) FIELD(GITS_TYPER, CIL, 36, 1) +FIELD(GITS_TYPER, VMOVP, 37, 1) #define GITS_IDREGS 0xFFD0 @@ -298,6 +321,7 @@ FIELD(GITS_TYPER, CIL, 36, 1) #define GITS_BASER_PAGESIZE_64K 2 #define GITS_BASER_TYPE_DEVICE 1ULL +#define GITS_BASER_TYPE_VPE 2ULL #define GITS_BASER_TYPE_COLLECTION 4ULL #define GITS_PAGE_SIZE_4K 0x1000 @@ -327,6 +351,13 @@ FIELD(GITS_TYPER, CIL, 36, 1) #define GITS_CMD_INVALL 0x0D #define GITS_CMD_MOVALL 0x0E #define GITS_CMD_DISCARD 0x0F +#define GITS_CMD_VMOVI 0x21 +#define GITS_CMD_VMOVP 0x22 +#define GITS_CMD_VSYNC 0x25 +#define GITS_CMD_VMAPP 0x29 +#define GITS_CMD_VMAPTI 0x2A +#define GITS_CMD_VMAPI 0x2B +#define GITS_CMD_VINVALL 0x2D /* MAPC command fields */ #define ICID_LENGTH 16 @@ -366,6 +397,46 @@ FIELD(MOVI_0, DEVICEID, 32, 32) FIELD(MOVI_1, EVENTID, 0, 32) FIELD(MOVI_2, ICID, 0, 16) +/* INV command fields */ +FIELD(INV_0, DEVICEID, 32, 32) +FIELD(INV_1, EVENTID, 0, 32) + +/* VMAPI, VMAPTI command fields */ +FIELD(VMAPTI_0, DEVICEID, 32, 32) +FIELD(VMAPTI_1, EVENTID, 0, 32) +FIELD(VMAPTI_1, VPEID, 32, 16) +FIELD(VMAPTI_2, VINTID, 0, 32) /* VMAPTI only */ +FIELD(VMAPTI_2, DOORBELL, 32, 32) + +/* VMAPP command fields */ +FIELD(VMAPP_0, ALLOC, 8, 1) /* GICv4.1 only */ +FIELD(VMAPP_0, PTZ, 9, 1) /* GICv4.1 only */ +FIELD(VMAPP_0, VCONFADDR, 16, 36) /* GICv4.1 only */ +FIELD(VMAPP_1, DEFAULT_DOORBELL, 0, 32) /* GICv4.1 only */ +FIELD(VMAPP_1, VPEID, 32, 16) +FIELD(VMAPP_2, RDBASE, 16, 36) +FIELD(VMAPP_2, V, 63, 1) +FIELD(VMAPP_3, VPTSIZE, 0, 8) /* For GICv4.0, bits [7:6] are RES0 */ +FIELD(VMAPP_3, VPTADDR, 16, 36) + +/* VMOVP command fields */ +FIELD(VMOVP_0, SEQNUM, 32, 16) /* not used for GITS_TYPER.VMOVP == 1 */ +FIELD(VMOVP_1, ITSLIST, 0, 16) /* not used for GITS_TYPER.VMOVP == 1 */ +FIELD(VMOVP_1, VPEID, 32, 16) +FIELD(VMOVP_2, RDBASE, 16, 36) +FIELD(VMOVP_2, DB, 63, 1) /* GICv4.1 only */ +FIELD(VMOVP_3, DEFAULT_DOORBELL, 0, 32) /* GICv4.1 only */ + +/* VMOVI command fields */ +FIELD(VMOVI_0, DEVICEID, 32, 32) +FIELD(VMOVI_1, EVENTID, 0, 32) +FIELD(VMOVI_1, VPEID, 32, 16) +FIELD(VMOVI_2, D, 0, 1) +FIELD(VMOVI_2, DOORBELL, 32, 32) + +/* VINVALL command fields */ +FIELD(VINVALL_1, VPEID, 32, 16) + /* * 12 bytes Interrupt translation Table Entry size * as per Table 5.3 in GICv3 spec @@ -419,6 +490,20 @@ FIELD(DTE, ITTADDR, 6, 44) FIELD(CTE, VALID, 0, 1) FIELD(CTE, RDBASE, 1, RDBASE_PROCNUM_LENGTH) +/* + * 8 bytes VPE table entry size: + * Valid = 1 bit, VPTsize = 5 bits, VPTaddr = 36 bits, RDbase = 16 bits + * + * Field sizes for Valid and size are mandated; field sizes for RDbase + * and VPT_addr are IMPDEF. + */ +#define GITS_VPE_SIZE 0x8ULL + +FIELD(VTE, VALID, 0, 1) +FIELD(VTE, VPTSIZE, 1, 5) +FIELD(VTE, VPTADDR, 6, 36) +FIELD(VTE, RDBASE, 42, RDBASE_PROCNUM_LENGTH) + /* Special interrupt IDs */ #define INTID_SECURE 1020 #define INTID_NONSECURE 1021 @@ -426,6 +511,27 @@ FIELD(CTE, RDBASE, 1, RDBASE_PROCNUM_LENGTH) /* Functions internal to the emulated GICv3 */ +/** + * gicv3_redist_size: + * @s: GICv3State + * + * Return the size of the redistributor register frame in bytes + * (which depends on what GIC version this is) + */ +static inline int gicv3_redist_size(GICv3State *s) +{ + /* + * Redistributor size is controlled by the redistributor GICR_TYPER.VLPIS. + * It's the same for every redistributor in the GIC, so arbitrarily + * use the register field in the first one. + */ + if (s->cpu[0].gicr_typer & GICR_TYPER_VLPIS) { + return GICV4_REDIST_SIZE; + } else { + return GICV3_REDIST_SIZE; + } +} + /** * gicv3_intid_is_special: * @intid: interrupt ID @@ -490,6 +596,36 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, void gicv3_dist_set_irq(GICv3State *s, int irq, int level); void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level); +/** + * gicv3_redist_process_vlpi: + * @cs: GICv3CPUState + * @irq: (virtual) interrupt number + * @vptaddr: (guest) address of VLPI table + * @doorbell: doorbell (physical) interrupt number (1023 for "no doorbell") + * @level: level to set @irq to + * + * Process a virtual LPI being directly injected by the ITS. This function + * will update the VLPI table specified by @vptaddr and @vptsize. If the + * vCPU corresponding to that VLPI table is currently running on + * the CPU associated with this redistributor, directly inject the VLPI + * @irq. If the vCPU is not running on this CPU, raise the doorbell + * interrupt instead. + */ +void gicv3_redist_process_vlpi(GICv3CPUState *cs, int irq, uint64_t vptaddr, + int doorbell, int level); +/** + * gicv3_redist_vlpi_pending: + * @cs: GICv3CPUState + * @irq: (virtual) interrupt number + * @level: level to set @irq to + * + * Set/clear the pending status of a virtual LPI in the vLPI table + * that this redistributor is currently using. (The difference between + * this and gicv3_redist_process_vlpi() is that this is called from + * the cpuif and does not need to do the not-running-on-this-vcpu checks.) + */ +void gicv3_redist_vlpi_pending(GICv3CPUState *cs, int irq, int level); + void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level); /** * gicv3_redist_update_lpi: @@ -509,6 +645,23 @@ void gicv3_redist_update_lpi(GICv3CPUState *cs); * an incoming migration has loaded new state. */ void gicv3_redist_update_lpi_only(GICv3CPUState *cs); +/** + * gicv3_redist_inv_lpi: + * @cs: GICv3CPUState + * @irq: LPI to invalidate cached information for + * + * Forget or update any cached information associated with this LPI. + */ +void gicv3_redist_inv_lpi(GICv3CPUState *cs, int irq); +/** + * gicv3_redist_inv_vlpi: + * @cs: GICv3CPUState + * @irq: vLPI to invalidate cached information for + * @vptaddr: (guest) address of vLPI table + * + * Forget or update any cached information associated with this vLPI. + */ +void gicv3_redist_inv_vlpi(GICv3CPUState *cs, int irq, uint64_t vptaddr); /** * gicv3_redist_mov_lpi: * @src: source redistributor @@ -529,6 +682,30 @@ void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq); * by the ITS MOVALL command. */ void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest); +/** + * gicv3_redist_mov_vlpi: + * @src: source redistributor + * @src_vptaddr: (guest) address of source VLPI table + * @dest: destination redistributor + * @dest_vptaddr: (guest) address of destination VLPI table + * @irq: VLPI to update + * @doorbell: doorbell for destination (1023 for "no doorbell") + * + * Move the pending state of the specified VLPI from @src to @dest, + * as required by the ITS VMOVI command. + */ +void gicv3_redist_mov_vlpi(GICv3CPUState *src, uint64_t src_vptaddr, + GICv3CPUState *dest, uint64_t dest_vptaddr, + int irq, int doorbell); +/** + * gicv3_redist_vinvall: + * @cs: GICv3CPUState + * @vptaddr: address of VLPI pending table + * + * On redistributor @cs, invalidate all cached information associated + * with the vCPU defined by @vptaddr. + */ +void gicv3_redist_vinvall(GICv3CPUState *cs, uint64_t vptaddr); void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); void gicv3_init_cpuif(GICv3State *s); @@ -544,6 +721,17 @@ void gicv3_init_cpuif(GICv3State *s); */ void gicv3_cpuif_update(GICv3CPUState *cs); +/* + * gicv3_cpuif_virt_irq_fiq_update: + * @cs: GICv3CPUState for the CPU to update + * + * Recalculate whether to assert the virtual IRQ or FIQ lines after + * a change to the current highest priority pending virtual interrupt. + * Note that this does not recalculate and change the maintenance + * interrupt status (for that, see gicv3_cpuif_virt_update()). + */ +void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs); + static inline uint32_t gicv3_iidr(void) { /* Return the Implementer Identification Register value @@ -555,17 +743,34 @@ static inline uint32_t gicv3_iidr(void) return 0x43b; } -static inline uint32_t gicv3_idreg(int regoffset) +/* CoreSight PIDR0 values for ARM GICv3 implementations */ +#define GICV3_PIDR0_DIST 0x92 +#define GICV3_PIDR0_REDIST 0x93 +#define GICV3_PIDR0_ITS 0x94 + +static inline uint32_t gicv3_idreg(GICv3State *s, int regoffset, uint8_t pidr0) { /* Return the value of the CoreSight ID register at the specified * offset from the first ID register (as found in the distributor * and redistributor register banks). - * These values indicate an ARM implementation of a GICv3. + * These values indicate an ARM implementation of a GICv3 or v4. */ static const uint8_t gicd_ids[] = { - 0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1 + 0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x0B, 0x00, 0x0D, 0xF0, 0x05, 0xB1 }; - return gicd_ids[regoffset / 4]; + uint32_t id; + + regoffset /= 4; + + if (regoffset == 4) { + return pidr0; + } + id = gicd_ids[regoffset]; + if (regoffset == 6) { + /* PIDR2 bits [7:4] are the GIC architecture revision */ + id |= s->revision << 4; + } + return id; } /** diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c index cb97c315dac5..13048a273540 100644 --- a/hw/intc/heathrow_pic.c +++ b/hw/intc/heathrow_pic.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "hw/ppc/mac.h" #include "migration/vmstate.h" #include "qemu/module.h" #include "hw/intc/heathrow_pic.h" diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c new file mode 100644 index 000000000000..4b8ec3f28a0e --- /dev/null +++ b/hw/intc/loongarch_extioi.c @@ -0,0 +1,317 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Loongson 3A5000 ext interrupt controller emulation + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "hw/intc/loongarch_extioi.h" +#include "migration/vmstate.h" +#include "trace.h" + + +static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level) +{ + int ipnum, cpu, found, irq_index, irq_mask; + + ipnum = s->sw_ipmap[irq / 32]; + cpu = s->sw_coremap[irq]; + irq_index = irq / 32; + irq_mask = 1 << (irq & 0x1f); + + if (level) { + /* if not enable return false */ + if (((s->enable[irq_index]) & irq_mask) == 0) { + return; + } + s->coreisr[cpu][irq_index] |= irq_mask; + found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS); + set_bit(irq, s->sw_isr[cpu][ipnum]); + if (found < EXTIOI_IRQS) { + /* other irq is handling, need not update parent irq level */ + return; + } + } else { + s->coreisr[cpu][irq_index] &= ~irq_mask; + clear_bit(irq, s->sw_isr[cpu][ipnum]); + found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS); + if (found < EXTIOI_IRQS) { + /* other irq is handling, need not update parent irq level */ + return; + } + } + qemu_set_irq(s->parent_irq[cpu][ipnum], level); +} + +static void extioi_setirq(void *opaque, int irq, int level) +{ + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); + trace_loongarch_extioi_setirq(irq, level); + if (level) { + /* + * s->isr should be used in vmstate structure, + * but it not support 'unsigned long', + * so we have to switch it. + */ + set_bit(irq, (unsigned long *)s->isr); + } else { + clear_bit(irq, (unsigned long *)s->isr); + } + extioi_update_irq(s, irq, level); +} + +static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); + unsigned long offset = addr & 0xffff; + uint32_t index, cpu; + + switch (offset) { + case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1: + index = (offset - EXTIOI_NODETYPE_START) >> 2; + *data = s->nodetype[index]; + break; + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1: + index = (offset - EXTIOI_IPMAP_START) >> 2; + *data = s->ipmap[index]; + break; + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1: + index = (offset - EXTIOI_ENABLE_START) >> 2; + *data = s->enable[index]; + break; + case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1: + index = (offset - EXTIOI_BOUNCE_START) >> 2; + *data = s->bounce[index]; + break; + case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1: + index = (offset - EXTIOI_COREISR_START) >> 2; + /* using attrs to get current cpu index */ + cpu = attrs.requester_id; + *data = s->coreisr[cpu][index]; + break; + case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1: + index = (offset - EXTIOI_COREMAP_START) >> 2; + *data = s->coremap[index]; + break; + default: + break; + } + + trace_loongarch_extioi_readw(addr, *data); + return MEMTX_OK; +} + +static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\ + uint32_t mask, int level) +{ + uint32_t val; + int irq; + + val = mask & s->isr[index]; + irq = ctz32(val); + while (irq != 32) { + /* + * enable bit change from 0 to 1, + * need to update irq by pending bits + */ + extioi_update_irq(s, irq + index * 32, level); + val &= ~(1 << irq); + irq = ctz32(val); + } +} + +static MemTxResult extioi_writew(void *opaque, hwaddr addr, + uint64_t val, unsigned size, + MemTxAttrs attrs) +{ + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); + int i, cpu, index, old_data, irq; + uint32_t offset; + + trace_loongarch_extioi_writew(addr, val); + offset = addr & 0xffff; + + switch (offset) { + case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1: + index = (offset - EXTIOI_NODETYPE_START) >> 2; + s->nodetype[index] = val; + break; + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1: + /* + * ipmap cannot be set at runtime, can be set only at the beginning + * of intr driver, need not update upper irq level + */ + index = (offset - EXTIOI_IPMAP_START) >> 2; + s->ipmap[index] = val; + /* + * loongarch only support little endian, + * so we paresd the value with little endian. + */ + val = cpu_to_le64(val); + for (i = 0; i < 4; i++) { + uint8_t ipnum; + ipnum = val & 0xff; + ipnum = ctz32(ipnum); + ipnum = (ipnum >= 4) ? 0 : ipnum; + s->sw_ipmap[index * 4 + i] = ipnum; + val = val >> 8; + } + + break; + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1: + index = (offset - EXTIOI_ENABLE_START) >> 2; + old_data = s->enable[index]; + s->enable[index] = val; + + /* unmask irq */ + val = s->enable[index] & ~old_data; + extioi_enable_irq(s, index, val, 1); + + /* mask irq */ + val = ~s->enable[index] & old_data; + extioi_enable_irq(s, index, val, 0); + break; + case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1: + /* do not emulate hw bounced irq routing */ + index = (offset - EXTIOI_BOUNCE_START) >> 2; + s->bounce[index] = val; + break; + case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1: + index = (offset - EXTIOI_COREISR_START) >> 2; + /* using attrs to get current cpu index */ + cpu = attrs.requester_id; + old_data = s->coreisr[cpu][index]; + s->coreisr[cpu][index] = old_data & ~val; + /* write 1 to clear interrrupt */ + old_data &= val; + irq = ctz32(old_data); + while (irq != 32) { + extioi_update_irq(s, irq + index * 32, 0); + old_data &= ~(1 << irq); + irq = ctz32(old_data); + } + break; + case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1: + irq = offset - EXTIOI_COREMAP_START; + index = irq / 4; + s->coremap[index] = val; + /* + * loongarch only support little endian, + * so we paresd the value with little endian. + */ + val = cpu_to_le64(val); + + for (i = 0; i < 4; i++) { + cpu = val & 0xff; + cpu = ctz32(cpu); + cpu = (cpu >= 4) ? 0 : cpu; + val = val >> 8; + + if (s->sw_coremap[irq + i] == cpu) { + continue; + } + + if (test_bit(irq, (unsigned long *)s->isr)) { + /* + * lower irq at old cpu and raise irq at new cpu + */ + extioi_update_irq(s, irq + i, 0); + s->sw_coremap[irq + i] = cpu; + extioi_update_irq(s, irq + i, 1); + } else { + s->sw_coremap[irq + i] = cpu; + } + } + break; + default: + break; + } + return MEMTX_OK; +} + +static const MemoryRegionOps extioi_ops = { + .read_with_attrs = extioi_readw, + .write_with_attrs = extioi_writew, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 4, + .valid.max_access_size = 8, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const VMStateDescription vmstate_loongarch_extioi = { + .name = TYPE_LOONGARCH_EXTIOI, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT), + VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, LOONGARCH_MAX_VCPUS, + EXTIOI_IRQS_GROUP_COUNT), + VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI, + EXTIOI_IRQS_NODETYPE_COUNT / 2), + VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32), + VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32), + VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4), + VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4), + VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE), + VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS), + + VMSTATE_END_OF_LIST() + } +}; + +static void loongarch_extioi_instance_init(Object *obj) +{ + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj); + int i, cpu, pin; + + for (i = 0; i < EXTIOI_IRQS; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + + qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS); + + for (cpu = 0; cpu < LOONGARCH_MAX_VCPUS; cpu++) { + memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops, + s, "extioi_iocsr", 0x900); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_iocsr_mem[cpu]); + for (pin = 0; pin < LS3A_INTC_IP; pin++) { + qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1); + } + } + memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops, + s, "extioi_system_mem", 0x900); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_system_mem); +} + +static void loongarch_extioi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_loongarch_extioi; +} + +static const TypeInfo loongarch_extioi_info = { + .name = TYPE_LOONGARCH_EXTIOI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = loongarch_extioi_instance_init, + .instance_size = sizeof(struct LoongArchExtIOI), + .class_init = loongarch_extioi_class_init, +}; + +static void loongarch_extioi_register_types(void) +{ + type_register_static(&loongarch_extioi_info); +} + +type_init(loongarch_extioi_register_types) diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c new file mode 100644 index 000000000000..aa4bf9eb747b --- /dev/null +++ b/hw/intc/loongarch_ipi.c @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch ipi interrupt support + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/intc/loongarch_ipi.h" +#include "hw/irq.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" +#include "hw/loongarch/virt.h" +#include "migration/vmstate.h" +#include "target/loongarch/internals.h" +#include "trace.h" + +static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size) +{ + IPICore *s = opaque; + uint64_t ret = 0; + int index = 0; + + addr &= 0xff; + switch (addr) { + case CORE_STATUS_OFF: + ret = s->status; + break; + case CORE_EN_OFF: + ret = s->en; + break; + case CORE_SET_OFF: + ret = 0; + break; + case CORE_CLEAR_OFF: + ret = 0; + break; + case CORE_BUF_20 ... CORE_BUF_38 + 4: + index = (addr - CORE_BUF_20) >> 2; + ret = s->buf[index]; + break; + default: + qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr); + break; + } + + trace_loongarch_ipi_read(size, (uint64_t)addr, ret); + return ret; +} + +static void send_ipi_data(CPULoongArchState *env, target_ulong val, target_ulong addr) +{ + int i, mask = 0, data = 0; + + /* + * bit 27-30 is mask for byte writing, + * if the mask is 0, we need not to do anything. + */ + if ((val >> 27) & 0xf) { + data = address_space_ldl(&env->address_space_iocsr, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + for (i = 0; i < 4; i++) { + /* get mask for byte writing */ + if (val & (0x1 << (27 + i))) { + mask |= 0xff << (i * 8); + } + } + } + + data &= mask; + data |= (val >> 32) & ~mask; + address_space_stl(&env->address_space_iocsr, addr, + data, MEMTXATTRS_UNSPECIFIED, NULL); +} + +static void ipi_send(uint64_t val) +{ + int cpuid, data; + CPULoongArchState *env; + CPUState *cs; + LoongArchCPU *cpu; + + cpuid = (val >> 16) & 0x3ff; + /* IPI status vector */ + data = 1 << (val & 0x1f); + cs = qemu_get_cpu(cpuid); + cpu = LOONGARCH_CPU(cs); + env = &cpu->env; + address_space_stl(&env->address_space_iocsr, 0x1008, + data, MEMTXATTRS_UNSPECIFIED, NULL); + +} + +static void mail_send(uint64_t val) +{ + int cpuid; + hwaddr addr; + CPULoongArchState *env; + CPUState *cs; + LoongArchCPU *cpu; + + cpuid = (val >> 16) & 0x3ff; + addr = 0x1020 + (val & 0x1c); + cs = qemu_get_cpu(cpuid); + cpu = LOONGARCH_CPU(cs); + env = &cpu->env; + send_ipi_data(env, val, addr); +} + +static void any_send(uint64_t val) +{ + int cpuid; + hwaddr addr; + CPULoongArchState *env; + + cpuid = (val >> 16) & 0x3ff; + addr = val & 0xffff; + CPUState *cs = qemu_get_cpu(cpuid); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + env = &cpu->env; + send_ipi_data(env, val, addr); +} + +static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + IPICore *s = opaque; + int index = 0; + + addr &= 0xff; + trace_loongarch_ipi_write(size, (uint64_t)addr, val); + switch (addr) { + case CORE_STATUS_OFF: + qemu_log_mask(LOG_GUEST_ERROR, "can not be written"); + break; + case CORE_EN_OFF: + s->en = val; + break; + case CORE_SET_OFF: + s->status |= val; + if (s->status != 0 && (s->status & s->en) != 0) { + qemu_irq_raise(s->irq); + } + break; + case CORE_CLEAR_OFF: + s->status &= ~val; + if (s->status == 0 && s->en != 0) { + qemu_irq_lower(s->irq); + } + break; + case CORE_BUF_20 ... CORE_BUF_38 + 4: + index = (addr - CORE_BUF_20) >> 2; + s->buf[index] = val; + break; + case IOCSR_IPI_SEND: + ipi_send(val); + break; + default: + qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr); + break; + } +} + +static const MemoryRegionOps loongarch_ipi_ops = { + .read = loongarch_ipi_readl, + .write = loongarch_ipi_writel, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 4, + .valid.max_access_size = 8, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +/* mail send and any send only support writeq */ +static void loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + addr &= 0xfff; + switch (addr) { + case MAIL_SEND_OFFSET: + mail_send(val); + break; + case ANY_SEND_OFFSET: + any_send(val); + break; + default: + break; + } +} + +static const MemoryRegionOps loongarch_ipi64_ops = { + .write = loongarch_ipi_writeq, + .impl.min_access_size = 8, + .impl.max_access_size = 8, + .valid.min_access_size = 8, + .valid.max_access_size = 8, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void loongarch_ipi_init(Object *obj) +{ + int cpu; + LoongArchMachineState *lams; + LoongArchIPI *s = LOONGARCH_IPI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + Object *machine = qdev_get_machine(); + ObjectClass *mc = object_get_class(machine); + /* 'lams' should be initialized */ + if (!strcmp(MACHINE_CLASS(mc)->name, "none")) { + return; + } + lams = LOONGARCH_MACHINE(machine); + for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) { + memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops, + &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x48); + sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]); + + memory_region_init_io(&s->ipi64_iocsr_mem[cpu], obj, &loongarch_ipi64_ops, + &lams->ipi_core[cpu], "loongarch_ipi64_iocsr", 0x118); + sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem[cpu]); + qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1); + } +} + +static const VMStateDescription vmstate_ipi_core = { + .name = "ipi-single", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(status, IPICore), + VMSTATE_UINT32(en, IPICore), + VMSTATE_UINT32(set, IPICore), + VMSTATE_UINT32(clear, IPICore), + VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_loongarch_ipi = { + .name = TYPE_LOONGARCH_IPI, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState, + MAX_IPI_CORE_NUM, 0, + vmstate_ipi_core, IPICore), + VMSTATE_END_OF_LIST() + } +}; + +static void loongarch_ipi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_loongarch_ipi; +} + +static const TypeInfo loongarch_ipi_info = { + .name = TYPE_LOONGARCH_IPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchIPI), + .instance_init = loongarch_ipi_init, + .class_init = loongarch_ipi_class_init, +}; + +static void loongarch_ipi_register_types(void) +{ + type_register_static(&loongarch_ipi_info); +} + +type_init(loongarch_ipi_register_types) diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c new file mode 100644 index 000000000000..ecf3ed0267e4 --- /dev/null +++ b/hw/intc/loongarch_pch_msi.c @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU Loongson 7A1000 msi interrupt controller. + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/intc/loongarch_pch_msi.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/pci/msi.h" +#include "hw/misc/unimp.h" +#include "migration/vmstate.h" +#include "trace.h" + +static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void loongarch_msi_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque; + int irq_num; + + /* + * vector number is irq number from upper extioi intc + * need subtract irq base to get msi vector offset + */ + irq_num = (val & 0xff) - s->irq_base; + trace_loongarch_msi_set_irq(irq_num); + assert(irq_num < s->irq_num); + qemu_set_irq(s->pch_msi_irq[irq_num], 1); +} + +static const MemoryRegionOps loongarch_pch_msi_ops = { + .read = loongarch_msi_mem_read, + .write = loongarch_msi_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void pch_msi_irq_handler(void *opaque, int irq, int level) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); + + qemu_set_irq(s->pch_msi_irq[irq], level); +} + +static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(dev); + + if (!s->irq_num || s->irq_num > PCH_MSI_IRQ_NUM) { + error_setg(errp, "Invalid 'msi_irq_num'"); + return; + } + + s->pch_msi_irq = g_new(qemu_irq, s->irq_num); + + qdev_init_gpio_out(dev, s->pch_msi_irq, s->irq_num); + qdev_init_gpio_in(dev, pch_msi_irq_handler, s->irq_num); +} + +static void loongarch_pch_msi_unrealize(DeviceState *dev) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(dev); + + g_free(s->pch_msi_irq); +} + +static void loongarch_pch_msi_init(Object *obj) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops, + s, TYPE_LOONGARCH_PCH_MSI, 0x8); + sysbus_init_mmio(sbd, &s->msi_mmio); + msi_nonbroken = true; + +} + +static Property loongarch_msi_properties[] = { + DEFINE_PROP_UINT32("msi_irq_base", LoongArchPCHMSI, irq_base, 0), + DEFINE_PROP_UINT32("msi_irq_num", LoongArchPCHMSI, irq_num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void loongarch_pch_msi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = loongarch_pch_msi_realize; + dc->unrealize = loongarch_pch_msi_unrealize; + device_class_set_props(dc, loongarch_msi_properties); +} + +static const TypeInfo loongarch_pch_msi_info = { + .name = TYPE_LOONGARCH_PCH_MSI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchPCHMSI), + .instance_init = loongarch_pch_msi_init, + .class_init = loongarch_pch_msi_class_init, +}; + +static void loongarch_pch_msi_register_types(void) +{ + type_register_static(&loongarch_pch_msi_info); +} + +type_init(loongarch_pch_msi_register_types) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c new file mode 100644 index 000000000000..9208fc4460e7 --- /dev/null +++ b/hw/intc/loongarch_pch_pic.c @@ -0,0 +1,458 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU Loongson 7A1000 I/O interrupt controller. + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" +#include "hw/pci-host/ls7a.h" +#include "hw/irq.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "trace.h" +#include "qapi/error.h" + +static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) +{ + uint64_t val; + int irq; + + if (level) { + val = mask & s->intirr & ~s->int_mask; + if (val) { + irq = ctz64(val); + s->intisr |= MAKE_64BIT_MASK(irq, 1); + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); + } + } else { + val = mask & s->intisr; + if (val) { + irq = ctz64(val); + s->intisr &= ~MAKE_64BIT_MASK(irq, 1); + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); + } + } +} + +static void pch_pic_irq_handler(void *opaque, int irq, int level) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t mask = 1ULL << irq; + + assert(irq < s->irq_num); + trace_loongarch_pch_pic_irq_handler(irq, level); + + if (s->intedge & mask) { + /* Edge triggered */ + if (level) { + if ((s->last_intirr & mask) == 0) { + s->intirr |= mask; + } + s->last_intirr |= mask; + } else { + s->last_intirr &= ~mask; + } + } else { + /* Level triggered */ + if (level) { + s->intirr |= mask; + s->last_intirr |= mask; + } else { + s->intirr &= ~mask; + s->last_intirr &= ~mask; + } + } + pch_pic_update_irq(s, mask, level); +} + +static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, + unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t val = 0; + uint32_t offset = addr & 0xfff; + + switch (offset) { + case PCH_PIC_INT_ID_LO: + val = PCH_PIC_INT_ID_VAL; + break; + case PCH_PIC_INT_ID_HI: + /* + * With 7A1000 manual + * bit 0-15 pch irqchip version + * bit 16-31 irq number supported with pch irqchip + */ + val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1); + break; + case PCH_PIC_INT_MASK_LO: + val = (uint32_t)s->int_mask; + break; + case PCH_PIC_INT_MASK_HI: + val = s->int_mask >> 32; + break; + case PCH_PIC_INT_EDGE_LO: + val = (uint32_t)s->intedge; + break; + case PCH_PIC_INT_EDGE_HI: + val = s->intedge >> 32; + break; + case PCH_PIC_HTMSI_EN_LO: + val = (uint32_t)s->htmsi_en; + break; + case PCH_PIC_HTMSI_EN_HI: + val = s->htmsi_en >> 32; + break; + case PCH_PIC_AUTO_CTRL0_LO: + case PCH_PIC_AUTO_CTRL0_HI: + case PCH_PIC_AUTO_CTRL1_LO: + case PCH_PIC_AUTO_CTRL1_HI: + break; + default: + break; + } + + trace_loongarch_pch_pic_low_readw(size, addr, val); + return val; +} + +static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi) +{ + uint64_t mask = 0xffffffff00000000; + uint64_t data = target; + + return hi ? (value & ~mask) | (data << 32) : (value & mask) | data; +} + +static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint32_t offset, old_valid, data = (uint32_t)value; + uint64_t old, int_mask; + offset = addr & 0xfff; + + trace_loongarch_pch_pic_low_writew(size, addr, data); + + switch (offset) { + case PCH_PIC_INT_MASK_LO: + old = s->int_mask; + s->int_mask = get_writew_val(old, data, 0); + old_valid = (uint32_t)old; + if (old_valid & ~data) { + pch_pic_update_irq(s, (old_valid & ~data), 1); + } + if (~old_valid & data) { + pch_pic_update_irq(s, (~old_valid & data), 0); + } + break; + case PCH_PIC_INT_MASK_HI: + old = s->int_mask; + s->int_mask = get_writew_val(old, data, 1); + old_valid = (uint32_t)(old >> 32); + int_mask = old_valid & ~data; + if (int_mask) { + pch_pic_update_irq(s, int_mask << 32, 1); + } + int_mask = ~old_valid & data; + if (int_mask) { + pch_pic_update_irq(s, int_mask << 32, 0); + } + break; + case PCH_PIC_INT_EDGE_LO: + s->intedge = get_writew_val(s->intedge, data, 0); + break; + case PCH_PIC_INT_EDGE_HI: + s->intedge = get_writew_val(s->intedge, data, 1); + break; + case PCH_PIC_INT_CLEAR_LO: + if (s->intedge & data) { + s->intirr &= (~data); + pch_pic_update_irq(s, data, 0); + s->intisr &= (~data); + } + break; + case PCH_PIC_INT_CLEAR_HI: + value <<= 32; + if (s->intedge & value) { + s->intirr &= (~value); + pch_pic_update_irq(s, value, 0); + s->intisr &= (~value); + } + break; + case PCH_PIC_HTMSI_EN_LO: + s->htmsi_en = get_writew_val(s->htmsi_en, data, 0); + break; + case PCH_PIC_HTMSI_EN_HI: + s->htmsi_en = get_writew_val(s->htmsi_en, data, 1); + break; + case PCH_PIC_AUTO_CTRL0_LO: + case PCH_PIC_AUTO_CTRL0_HI: + case PCH_PIC_AUTO_CTRL1_LO: + case PCH_PIC_AUTO_CTRL1_HI: + break; + default: + break; + } +} + +static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, + unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t val = 0; + uint32_t offset = addr & 0xfff; + + switch (offset) { + case STATUS_LO_START: + val = (uint32_t)(s->intisr & (~s->int_mask)); + break; + case STATUS_HI_START: + val = (s->intisr & (~s->int_mask)) >> 32; + break; + case POL_LO_START: + val = (uint32_t)s->int_polarity; + break; + case POL_HI_START: + val = s->int_polarity >> 32; + break; + default: + break; + } + + trace_loongarch_pch_pic_high_readw(size, addr, val); + return val; +} + +static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint32_t offset, data = (uint32_t)value; + offset = addr & 0xfff; + + trace_loongarch_pch_pic_high_writew(size, addr, data); + + switch (offset) { + case STATUS_LO_START: + s->intisr = get_writew_val(s->intisr, data, 0); + break; + case STATUS_HI_START: + s->intisr = get_writew_val(s->intisr, data, 1); + break; + case POL_LO_START: + s->int_polarity = get_writew_val(s->int_polarity, data, 0); + break; + case POL_HI_START: + s->int_polarity = get_writew_val(s->int_polarity, data, 1); + break; + default: + break; + } +} + +static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, + unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t val = 0; + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; + int64_t offset_tmp; + + switch (offset) { + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + val = s->htmsi_vector[offset_tmp]; + } + break; + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + val = s->route_entry[offset_tmp]; + } + break; + default: + break; + } + + trace_loongarch_pch_pic_readb(size, addr, val); + return val; +} + +static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + int32_t offset_tmp; + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; + + trace_loongarch_pch_pic_writeb(size, addr, data); + + switch (offset) { + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); + } + break; + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); + } + break; + default: + break; + } +} + +static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { + .read = loongarch_pch_pic_low_readw, + .write = loongarch_pch_pic_low_writew, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = { + .read = loongarch_pch_pic_high_readw, + .write = loongarch_pch_pic_high_writew, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { + .read = loongarch_pch_pic_readb, + .write = loongarch_pch_pic_writeb, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void loongarch_pch_pic_reset(DeviceState *d) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d); + int i; + + s->int_mask = -1; + s->htmsi_en = 0x0; + s->intedge = 0x0; + s->intclr = 0x0; + s->auto_crtl0 = 0x0; + s->auto_crtl1 = 0x0; + for (i = 0; i < 64; i++) { + s->route_entry[i] = 0x1; + s->htmsi_vector[i] = 0x0; + } + s->intirr = 0x0; + s->intisr = 0x0; + s->last_intirr = 0x0; + s->int_polarity = 0x0; +} + +static void loongarch_pch_pic_realize(DeviceState *dev, Error **errp) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(dev); + + if (!s->irq_num || s->irq_num > VIRT_PCH_PIC_IRQ_NUM) { + error_setg(errp, "Invalid 'pic_irq_num'"); + return; + } + + qdev_init_gpio_out(dev, s->parent_irq, s->irq_num); + qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num); +} + +static void loongarch_pch_pic_init(Object *obj) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem32_low, obj, + &loongarch_pch_pic_reg32_low_ops, + s, PCH_PIC_NAME(.reg32_part1), 0x100); + memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops, + s, PCH_PIC_NAME(.reg8), 0x2a0); + memory_region_init_io(&s->iomem32_high, obj, + &loongarch_pch_pic_reg32_high_ops, + s, PCH_PIC_NAME(.reg32_part2), 0xc60); + sysbus_init_mmio(sbd, &s->iomem32_low); + sysbus_init_mmio(sbd, &s->iomem8); + sysbus_init_mmio(sbd, &s->iomem32_high); + +} + +static Property loongarch_pch_pic_properties[] = { + DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPCHPIC, irq_num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_loongarch_pch_pic = { + .name = TYPE_LOONGARCH_PCH_PIC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(int_mask, LoongArchPCHPIC), + VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC), + VMSTATE_UINT64(intedge, LoongArchPCHPIC), + VMSTATE_UINT64(intclr, LoongArchPCHPIC), + VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC), + VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC), + VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64), + VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64), + VMSTATE_UINT64(last_intirr, LoongArchPCHPIC), + VMSTATE_UINT64(intirr, LoongArchPCHPIC), + VMSTATE_UINT64(intisr, LoongArchPCHPIC), + VMSTATE_UINT64(int_polarity, LoongArchPCHPIC), + VMSTATE_END_OF_LIST() + } +}; + +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = loongarch_pch_pic_realize; + dc->reset = loongarch_pch_pic_reset; + dc->vmsd = &vmstate_loongarch_pch_pic; + device_class_set_props(dc, loongarch_pch_pic_properties); +} + +static const TypeInfo loongarch_pch_pic_info = { + .name = TYPE_LOONGARCH_PCH_PIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchPCHPIC), + .instance_init = loongarch_pch_pic_init, + .class_init = loongarch_pch_pic_class_init, +}; + +static void loongarch_pch_pic_register_types(void) +{ + type_register_static(&loongarch_pch_pic_info); +} + +type_init(loongarch_pch_pic_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index d6d012fb264e..bcbf22ff512b 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -62,3 +62,8 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], if_true: files('spapr_xive_kvm.c')) specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) +specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) diff --git a/hw/intc/nios2_vic.c b/hw/intc/nios2_vic.c new file mode 100644 index 000000000000..cf63212a8869 --- /dev/null +++ b/hw/intc/nios2_vic.c @@ -0,0 +1,313 @@ +/* + * Vectored Interrupt Controller for nios2 processor + * + * Copyright (c) 2022 Neuroblade + * + * Interface: + * QOM property "cpu": link to the Nios2 CPU (must be set) + * Unnamed GPIO inputs 0..NIOS2_VIC_MAX_IRQ-1: input IRQ lines + * IRQ should be connected to nios2 IRQ0. + * + * Reference: "Embedded Peripherals IP User Guide + * for Intel® Quartus® Prime Design Suite: 21.4" + * Chapter 38 "Vectored Interrupt Controller Core" + * See: https://www.intel.com/content/www/us/en/docs/programmable/683130/21-4/vectored-interrupt-controller-core.html + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "hw/intc/nios2_vic.h" +#include "cpu.h" + + +enum { + INT_CONFIG0 = 0, + INT_CONFIG31 = 31, + INT_ENABLE = 32, + INT_ENABLE_SET = 33, + INT_ENABLE_CLR = 34, + INT_PENDING = 35, + INT_RAW_STATUS = 36, + SW_INTERRUPT = 37, + SW_INTERRUPT_SET = 38, + SW_INTERRUPT_CLR = 39, + VIC_CONFIG = 40, + VIC_STATUS = 41, + VEC_TBL_BASE = 42, + VEC_TBL_ADDR = 43, + CSR_COUNT /* Last! */ +}; + +/* Requested interrupt level (INT_CONFIG[0:5]) */ +static inline uint32_t vic_int_config_ril(const Nios2VIC *vic, int irq_num) +{ + return extract32(vic->int_config[irq_num], 0, 6); +} + +/* Requested NMI (INT_CONFIG[6]) */ +static inline uint32_t vic_int_config_rnmi(const Nios2VIC *vic, int irq_num) +{ + return extract32(vic->int_config[irq_num], 6, 1); +} + +/* Requested register set (INT_CONFIG[7:12]) */ +static inline uint32_t vic_int_config_rrs(const Nios2VIC *vic, int irq_num) +{ + return extract32(vic->int_config[irq_num], 7, 6); +} + +static inline uint32_t vic_config_vec_size(const Nios2VIC *vic) +{ + return 1 << (2 + extract32(vic->vic_config, 0, 3)); +} + +static inline uint32_t vic_int_pending(const Nios2VIC *vic) +{ + return (vic->int_raw_status | vic->sw_int) & vic->int_enable; +} + +static void vic_update_irq(Nios2VIC *vic) +{ + Nios2CPU *cpu = NIOS2_CPU(vic->cpu); + uint32_t pending = vic_int_pending(vic); + int irq = -1; + int max_ril = 0; + /* Note that if RIL is 0 for an interrupt it is effectively disabled */ + + vic->vec_tbl_addr = 0; + vic->vic_status = 0; + + if (pending == 0) { + qemu_irq_lower(vic->output_int); + return; + } + + for (int i = 0; i < NIOS2_VIC_MAX_IRQ; i++) { + if (pending & BIT(i)) { + int ril = vic_int_config_ril(vic, i); + if (ril > max_ril) { + irq = i; + max_ril = ril; + } + } + } + + if (irq < 0) { + qemu_irq_lower(vic->output_int); + return; + } + + vic->vec_tbl_addr = irq * vic_config_vec_size(vic) + vic->vec_tbl_base; + vic->vic_status = irq | BIT(31); + + /* + * In hardware, the interface between the VIC and the CPU is via the + * External Interrupt Controller interface, where the interrupt controller + * presents the CPU with a packet of data containing: + * - Requested Handler Address (RHA): 32 bits + * - Requested Register Set (RRS) : 6 bits + * - Requested Interrupt Level (RIL) : 6 bits + * - Requested NMI flag (RNMI) : 1 bit + * In our emulation, we implement this by writing the data directly to + * fields in the CPU object and then raising the IRQ line to tell + * the CPU that we've done so. + */ + + cpu->rha = vic->vec_tbl_addr; + cpu->ril = max_ril; + cpu->rrs = vic_int_config_rrs(vic, irq); + cpu->rnmi = vic_int_config_rnmi(vic, irq); + + qemu_irq_raise(vic->output_int); +} + +static void vic_set_irq(void *opaque, int irq_num, int level) +{ + Nios2VIC *vic = opaque; + + vic->int_raw_status = deposit32(vic->int_raw_status, irq_num, 1, !!level); + vic_update_irq(vic); +} + +static void nios2_vic_reset(DeviceState *dev) +{ + Nios2VIC *vic = NIOS2_VIC(dev); + + memset(&vic->int_config, 0, sizeof(vic->int_config)); + vic->vic_config = 0; + vic->int_raw_status = 0; + vic->int_enable = 0; + vic->sw_int = 0; + vic->vic_status = 0; + vic->vec_tbl_base = 0; + vic->vec_tbl_addr = 0; +} + +static uint64_t nios2_vic_csr_read(void *opaque, hwaddr offset, unsigned size) +{ + Nios2VIC *vic = opaque; + int index = offset / 4; + + switch (index) { + case INT_CONFIG0 ... INT_CONFIG31: + return vic->int_config[index - INT_CONFIG0]; + case INT_ENABLE: + return vic->int_enable; + case INT_PENDING: + return vic_int_pending(vic); + case INT_RAW_STATUS: + return vic->int_raw_status; + case SW_INTERRUPT: + return vic->sw_int; + case VIC_CONFIG: + return vic->vic_config; + case VIC_STATUS: + return vic->vic_status; + case VEC_TBL_BASE: + return vic->vec_tbl_base; + case VEC_TBL_ADDR: + return vic->vec_tbl_addr; + default: + return 0; + } +} + +static void nios2_vic_csr_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + Nios2VIC *vic = opaque; + int index = offset / 4; + + switch (index) { + case INT_CONFIG0 ... INT_CONFIG31: + vic->int_config[index - INT_CONFIG0] = value; + break; + case INT_ENABLE: + vic->int_enable = value; + break; + case INT_ENABLE_SET: + vic->int_enable |= value; + break; + case INT_ENABLE_CLR: + vic->int_enable &= ~value; + break; + case SW_INTERRUPT: + vic->sw_int = value; + break; + case SW_INTERRUPT_SET: + vic->sw_int |= value; + break; + case SW_INTERRUPT_CLR: + vic->sw_int &= ~value; + break; + case VIC_CONFIG: + vic->vic_config = value; + break; + case VEC_TBL_BASE: + vic->vec_tbl_base = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "nios2-vic: write to invalid CSR address %#" + HWADDR_PRIx "\n", offset); + } + + vic_update_irq(vic); +} + +static const MemoryRegionOps nios2_vic_csr_ops = { + .read = nios2_vic_csr_read, + .write = nios2_vic_csr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { .min_access_size = 4, .max_access_size = 4 } +}; + +static void nios2_vic_realize(DeviceState *dev, Error **errp) +{ + Nios2VIC *vic = NIOS2_VIC(dev); + + if (!vic->cpu) { + /* This is a programming error in the code using this device */ + error_setg(errp, "nios2-vic 'cpu' link property was not set"); + return; + } + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &vic->output_int); + qdev_init_gpio_in(dev, vic_set_irq, NIOS2_VIC_MAX_IRQ); + + memory_region_init_io(&vic->csr, OBJECT(dev), &nios2_vic_csr_ops, vic, + "nios2.vic.csr", CSR_COUNT * sizeof(uint32_t)); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &vic->csr); +} + +static Property nios2_vic_properties[] = { + DEFINE_PROP_LINK("cpu", Nios2VIC, cpu, TYPE_CPU, CPUState *), + DEFINE_PROP_END_OF_LIST() +}; + +static const VMStateDescription nios2_vic_vmstate = { + .name = "nios2-vic", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]){ + VMSTATE_UINT32_ARRAY(int_config, Nios2VIC, 32), + VMSTATE_UINT32(vic_config, Nios2VIC), + VMSTATE_UINT32(int_raw_status, Nios2VIC), + VMSTATE_UINT32(int_enable, Nios2VIC), + VMSTATE_UINT32(sw_int, Nios2VIC), + VMSTATE_UINT32(vic_status, Nios2VIC), + VMSTATE_UINT32(vec_tbl_base, Nios2VIC), + VMSTATE_UINT32(vec_tbl_addr, Nios2VIC), + VMSTATE_END_OF_LIST() + }, +}; + +static void nios2_vic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = nios2_vic_reset; + dc->realize = nios2_vic_realize; + dc->vmsd = &nios2_vic_vmstate; + device_class_set_props(dc, nios2_vic_properties); +} + +static const TypeInfo nios2_vic_info = { + .name = TYPE_NIOS2_VIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Nios2VIC), + .class_init = nios2_vic_class_init, +}; + +static void nios2_vic_register_types(void) +{ + type_register_static(&nios2_vic_info); +} + +type_init(nios2_vic_register_types); diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c index d7183d035e9a..647bf324a8ea 100644 --- a/hw/intc/omap_intc.c +++ b/hw/intc/omap_intc.c @@ -38,7 +38,7 @@ struct omap_intr_handler_bank_s { unsigned char priority[32]; }; -struct omap_intr_handler_s { +struct OMAPIntcState { SysBusDevice parent_obj; qemu_irq *pins; @@ -60,7 +60,7 @@ struct omap_intr_handler_s { struct omap_intr_handler_bank_s bank[3]; }; -static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) +static void omap_inth_sir_update(OMAPIntcState *s, int is_fiq) { int i, j, sir_intr, p_intr, p; uint32_t level; @@ -88,7 +88,7 @@ static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) s->sir_intr[is_fiq] = sir_intr; } -static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) +static inline void omap_inth_update(OMAPIntcState *s, int is_fiq) { int i; uint32_t has_intr = 0; @@ -109,7 +109,7 @@ static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) static void omap_set_intr(void *opaque, int irq, int req) { - struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; + OMAPIntcState *ih = opaque; uint32_t rise; struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; @@ -136,7 +136,7 @@ static void omap_set_intr(void *opaque, int irq, int req) /* Simplified version with no edge detection */ static void omap_set_intr_noedge(void *opaque, int irq, int req) { - struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; + OMAPIntcState *ih = opaque; uint32_t rise; struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; @@ -156,7 +156,7 @@ static void omap_set_intr_noedge(void *opaque, int irq, int req) static uint64_t omap_inth_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + OMAPIntcState *s = opaque; int i, offset = addr; int bank_no = offset >> 8; int line_no; @@ -234,7 +234,7 @@ static uint64_t omap_inth_read(void *opaque, hwaddr addr, static void omap_inth_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + OMAPIntcState *s = opaque; int i, offset = addr; int bank_no = offset >> 8; struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; @@ -336,7 +336,7 @@ static const MemoryRegionOps omap_inth_mem_ops = { static void omap_inth_reset(DeviceState *dev) { - struct omap_intr_handler_s *s = OMAP_INTC(dev); + OMAPIntcState *s = OMAP_INTC(dev); int i; for (i = 0; i < s->nbanks; ++i){ @@ -366,7 +366,7 @@ static void omap_inth_reset(DeviceState *dev) static void omap_intc_init(Object *obj) { DeviceState *dev = DEVICE(obj); - struct omap_intr_handler_s *s = OMAP_INTC(obj); + OMAPIntcState *s = OMAP_INTC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); s->nbanks = 1; @@ -380,25 +380,25 @@ static void omap_intc_init(Object *obj) static void omap_intc_realize(DeviceState *dev, Error **errp) { - struct omap_intr_handler_s *s = OMAP_INTC(dev); + OMAPIntcState *s = OMAP_INTC(dev); if (!s->iclk) { error_setg(errp, "omap-intc: clk not connected"); } } -void omap_intc_set_iclk(omap_intr_handler *intc, omap_clk clk) +void omap_intc_set_iclk(OMAPIntcState *intc, omap_clk clk) { intc->iclk = clk; } -void omap_intc_set_fclk(omap_intr_handler *intc, omap_clk clk) +void omap_intc_set_fclk(OMAPIntcState *intc, omap_clk clk) { intc->fclk = clk; } static Property omap_intc_properties[] = { - DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100), + DEFINE_PROP_UINT32("size", OMAPIntcState, size, 0x100), DEFINE_PROP_END_OF_LIST(), }; @@ -423,7 +423,7 @@ static const TypeInfo omap_intc_info = { static uint64_t omap2_inth_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + OMAPIntcState *s = opaque; int offset = addr; int bank_no, line_no; struct omap_intr_handler_bank_s *bank = NULL; @@ -504,7 +504,7 @@ static uint64_t omap2_inth_read(void *opaque, hwaddr addr, static void omap2_inth_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + OMAPIntcState *s = opaque; int offset = addr; int bank_no, line_no; struct omap_intr_handler_bank_s *bank = NULL; @@ -622,7 +622,7 @@ static const MemoryRegionOps omap2_inth_mem_ops = { static void omap2_intc_init(Object *obj) { DeviceState *dev = DEVICE(obj); - struct omap_intr_handler_s *s = OMAP_INTC(obj); + OMAPIntcState *s = OMAP_INTC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); s->level_only = 1; @@ -637,7 +637,7 @@ static void omap2_intc_init(Object *obj) static void omap2_intc_realize(DeviceState *dev, Error **errp) { - struct omap_intr_handler_s *s = OMAP_INTC(dev); + OMAPIntcState *s = OMAP_INTC(dev); if (!s->iclk) { error_setg(errp, "omap2-intc: iclk not connected"); @@ -650,7 +650,7 @@ static void omap2_intc_realize(DeviceState *dev, Error **errp) } static Property omap2_intc_properties[] = { - DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s, + DEFINE_PROP_UINT8("revision", OMAPIntcState, revision, 0x21), DEFINE_PROP_END_OF_LIST(), }; @@ -676,7 +676,7 @@ static const TypeInfo omap2_intc_info = { static const TypeInfo omap_intc_type_info = { .name = TYPE_OMAP_INTC, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(omap_intr_handler), + .instance_size = sizeof(OMAPIntcState), .abstract = true, }; diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 49504e740f33..c757adbe5382 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -32,7 +32,6 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/ppc/mac.h" #include "hw/pci/pci.h" #include "hw/ppc/openpic.h" #include "hw/ppc/ppc_e500.h" @@ -729,7 +728,7 @@ static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled) } /* - * Returns the currrent tccr value, i.e., timer value (in clocks) with + * Returns the current tccr value, i.e., timer value (in clocks) with * appropriate TOG. */ static uint64_t openpic_tmr_get_timer(OpenPICTimer *tmr) diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index 1ce1d7b07d63..c7b75ed12ee0 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -66,26 +66,6 @@ static const XiveVstInfo vst_infos[] = { qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n", \ (xive)->chip->chip_id, ## __VA_ARGS__); -/* - * QEMU version of the GETFIELD/SETFIELD macros - * - * TODO: It might be better to use the existing extract64() and - * deposit64() but this means that all the register definitions will - * change and become incompatible with the ones found in skiboot. - * - * Keep it as it is for now until we find a common ground. - */ -static inline uint64_t GETFIELD(uint64_t mask, uint64_t word) -{ - return (word & mask) >> ctz64(mask); -} - -static inline uint64_t SETFIELD(uint64_t mask, uint64_t word, - uint64_t value) -{ - return (word & ~mask) | ((value << ctz64(mask)) & mask); -} - /* * When PC_TCTXT_CHIPID_OVERRIDE is configured, the PC_TCTXT_CHIPID * field overrides the hardwired chip ID in the Powerbus operations diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index 87303b40641b..f22ce5ca59ae 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -75,26 +75,6 @@ static const XiveVstInfo vst_infos[] = { qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n", \ (xive)->chip->chip_id, ## __VA_ARGS__); -/* - * QEMU version of the GETFIELD/SETFIELD macros - * - * TODO: It might be better to use the existing extract64() and - * deposit64() but this means that all the register definitions will - * change and become incompatible with the ones found in skiboot. - * - * Keep it as it is for now until we find a common ground. - */ -static inline uint64_t GETFIELD(uint64_t mask, uint64_t word) -{ - return (word & mask) >> ctz64(mask); -} - -static inline uint64_t SETFIELD(uint64_t mask, uint64_t word, - uint64_t value) -{ - return (word & ~mask) | ((value << ctz64(mask)) & mask); -} - /* * TODO: Document block id override */ @@ -1295,7 +1275,6 @@ static void pnv_xive2_ic_tctxt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { PnvXive2 *xive = PNV_XIVE2(opaque); - uint32_t reg = offset >> 3; switch (offset) { /* @@ -1322,8 +1301,6 @@ static void pnv_xive2_ic_tctxt_write(void *opaque, hwaddr offset, xive2_error(xive, "TCTXT: invalid write @%"HWADDR_PRIx, offset); return; } - - xive->pc_regs[reg] = val; } static const MemoryRegionOps pnv_xive2_ic_tctxt_ops = { @@ -1577,6 +1554,12 @@ static const MemoryRegionOps pnv_xive2_ic_sync_ops = { * When the TM direct pages of the IC controller are accessed, the * target HW thread is deduced from the page offset. */ +static uint32_t pnv_xive2_ic_tm_get_pir(PnvXive2 *xive, hwaddr offset) +{ + /* On P10, the node ID shift in the PIR register is 8 bits */ + return xive->chip->chip_id << 8 | offset >> xive->ic_shift; +} + static XiveTCTX *pnv_xive2_get_indirect_tctx(PnvXive2 *xive, uint32_t pir) { PnvChip *chip = xive->chip; @@ -1599,10 +1582,12 @@ static uint64_t pnv_xive2_ic_tm_indirect_read(void *opaque, hwaddr offset, unsigned size) { PnvXive2 *xive = PNV_XIVE2(opaque); - uint32_t pir = offset >> xive->ic_shift; - XiveTCTX *tctx = pnv_xive2_get_indirect_tctx(xive, pir); + uint32_t pir; + XiveTCTX *tctx; uint64_t val = -1; + pir = pnv_xive2_ic_tm_get_pir(xive, offset); + tctx = pnv_xive2_get_indirect_tctx(xive, pir); if (tctx) { val = xive_tctx_tm_read(NULL, tctx, offset, size); } @@ -1614,9 +1599,11 @@ static void pnv_xive2_ic_tm_indirect_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { PnvXive2 *xive = PNV_XIVE2(opaque); - uint32_t pir = offset >> xive->ic_shift; - XiveTCTX *tctx = pnv_xive2_get_indirect_tctx(xive, pir); + uint32_t pir; + XiveTCTX *tctx; + pir = pnv_xive2_ic_tm_get_pir(xive, offset); + tctx = pnv_xive2_get_indirect_tctx(xive, pir); if (tctx) { xive_tctx_tm_write(NULL, tctx, offset, val, size); } diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c index 60013f2dde34..dcf5de5d43ca 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 e43b050e9290..eee04643cb19 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -32,18 +32,25 @@ #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; int num; } riscv_aclint_mtimer_callback; -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) +static uint64_t cpu_riscv_read_rtc_raw(uint32_t timebase_freq) { return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), timebase_freq, NANOSECONDS_PER_SECOND); } +static uint64_t cpu_riscv_read_rtc(void *opaque) +{ + RISCVAclintMTimerState *mtimer = opaque; + return cpu_riscv_read_rtc_raw(mtimer->timebase_freq) + mtimer->time_delta; +} + /* * Called when timecmp is written to update the QEMU timer or immediately * trigger timer interrupt if mtimecmp <= current timer value. @@ -51,27 +58,30 @@ static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, RISCVCPU *cpu, int hartid, - uint64_t value, - uint32_t timebase_freq) + uint64_t value) { + uint32_t timebase_freq = mtimer->timebase_freq; uint64_t next; uint64_t diff; - uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq); + uint64_t rtc_r = cpu_riscv_read_rtc(mtimer); + + /* Compute the relative hartid w.r.t the socket */ + hartid = hartid - mtimer->hartid_base; - cpu->env.timecmp = value; - if (cpu->env.timecmp <= rtc_r) { + 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); @@ -96,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); } /* @@ -126,12 +136,12 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr, qemu_log_mask(LOG_GUEST_ERROR, "aclint-mtimer: invalid hartid: %zu", hartid); } else if ((addr & 0x7) == 0) { - /* timecmp_lo */ - uint64_t timecmp = env->timecmp; - return timecmp & 0xFFFFFFFF; + /* timecmp_lo for RV32/RV64 or timecmp for RV64 */ + 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, @@ -139,11 +149,12 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr, return 0; } } else if (addr == mtimer->time_base) { - /* time_lo */ - return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF; + /* time_lo for RV32/RV64 or timecmp for RV64 */ + uint64_t rtc = cpu_riscv_read_rtc(mtimer); + return (size == 4) ? (rtc & 0xFFFFFFFF) : rtc; } else if (addr == mtimer->time_base + 4) { /* time_hi */ - return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF; + return (cpu_riscv_read_rtc(mtimer) >> 32) & 0xFFFFFFFF; } qemu_log_mask(LOG_UNIMP, @@ -156,6 +167,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { RISCVAclintMTimerState *mtimer = opaque; + int i; if (addr >= mtimer->timecmp_base && addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) { @@ -167,33 +179,67 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, qemu_log_mask(LOG_GUEST_ERROR, "aclint-mtimer: invalid hartid: %zu", hartid); } else if ((addr & 0x7) == 0) { - /* timecmp_lo */ - uint64_t timecmp_hi = env->timecmp >> 32; - riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, - timecmp_hi << 32 | (value & 0xFFFFFFFF), - mtimer->timebase_freq); - return; + if (size == 4) { + /* timecmp_lo for RV32/RV64 */ + uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32; + riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, + timecmp_hi << 32 | (value & 0xFFFFFFFF)); + } else { + /* timecmp for RV64 */ + riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, + value); + } } else if ((addr & 0x7) == 4) { - /* timecmp_hi */ - uint64_t timecmp_lo = env->timecmp; - riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, - value << 32 | (timecmp_lo & 0xFFFFFFFF), - mtimer->timebase_freq); + if (size == 4) { + /* timecmp_hi for RV32/RV64 */ + uint64_t timecmp_lo = mtimer->timecmp[hartid]; + riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, + value << 32 | (timecmp_lo & 0xFFFFFFFF)); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "aclint-mtimer: invalid timecmp_hi write: %08x", + (uint32_t)addr); + } } else { qemu_log_mask(LOG_UNIMP, "aclint-mtimer: invalid timecmp write: %08x", (uint32_t)addr); } return; - } else if (addr == mtimer->time_base) { - /* time_lo */ - qemu_log_mask(LOG_UNIMP, - "aclint-mtimer: time_lo write not implemented"); - return; - } else if (addr == mtimer->time_base + 4) { - /* time_hi */ - qemu_log_mask(LOG_UNIMP, - "aclint-mtimer: time_hi write not implemented"); + } else if (addr == mtimer->time_base || addr == mtimer->time_base + 4) { + uint64_t rtc_r = cpu_riscv_read_rtc_raw(mtimer->timebase_freq); + + if (addr == mtimer->time_base) { + if (size == 4) { + /* time_lo for RV32/RV64 */ + mtimer->time_delta = ((rtc_r & ~0xFFFFFFFFULL) | value) - rtc_r; + } else { + /* time for RV64 */ + mtimer->time_delta = value - rtc_r; + } + } else { + if (size == 4) { + /* time_hi for RV32/RV64 */ + mtimer->time_delta = (value << 32 | (rtc_r & 0xFFFFFFFF)) - rtc_r; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "aclint-mtimer: invalid time_hi write: %08x", + (uint32_t)addr); + return; + } + } + + /* Check if timer interrupt is triggered for each hart. */ + for (i = 0; i < mtimer->num_harts; i++) { + CPUState *cpu = qemu_get_cpu(mtimer->hartid_base + i); + CPURISCVState *env = cpu ? cpu->env_ptr : NULL; + if (!env) { + continue; + } + riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), + mtimer->hartid_base + i, + mtimer->timecmp[i]); + } return; } @@ -208,6 +254,10 @@ static const MemoryRegionOps riscv_aclint_mtimer_ops = { .valid = { .min_access_size = 4, .max_access_size = 8 + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, } }; @@ -238,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)); @@ -248,11 +300,42 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp) } } +static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type) +{ + /* + * According to RISC-V ACLINT spec: + * - On MTIMER device reset, the MTIME register is cleared to zero. + * - On MTIMER device reset, the MTIMECMP registers are in unknown state. + */ + RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(obj); + + /* + * Clear mtime register by writing to 0 it. + * Pending mtime interrupts will also be cleared at the same time. + */ + 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); dc->realize = riscv_aclint_mtimer_realize; 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 = { @@ -272,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)); @@ -299,14 +383,14 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, continue; } if (provide_rdtime) { - riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq); + 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)); @@ -399,7 +483,7 @@ static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp) /* Claim software interrupt bits */ for (i = 0; i < swi->num_harts; i++) { RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i)); - /* We don't claim mip.SSIP because it is writeable by software */ + /* We don't claim mip.SSIP because it is writable by software */ if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) { error_report("MSIP already claimed"); exit(1); @@ -407,11 +491,32 @@ static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp) } } +static void riscv_aclint_swi_reset_enter(Object *obj, ResetType type) +{ + /* + * According to RISC-V ACLINT spec: + * - On MSWI device reset, each MSIP register is cleared to zero. + * + * p.s. SSWI device reset does nothing since SETSIP register always reads 0. + */ + RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(obj); + int i; + + if (!swi->sswi) { + for (i = 0; i < swi->num_harts; i++) { + /* Clear MSIP registers by lowering software interrupts. */ + qemu_irq_lower(swi->soft_irqs[i]); + } + } +} + static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = riscv_aclint_swi_realize; device_class_set_props(dc, riscv_aclint_swi_properties); + ResettableClass *rc = RESETTABLE_CLASS(klass); + rc->phases.enter = riscv_aclint_swi_reset_enter; } static const TypeInfo riscv_aclint_swi_info = { diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index e7809fb6b2c7..cfd007e629ca 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -646,7 +646,7 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value, } if (addr == APLIC_DOMAINCFG) { - /* Only IE bit writeable at the moment */ + /* Only IE bit writable at the moment */ value &= APLIC_DOMAINCFG_IE; aplic->domaincfg = value; } else if ((APLIC_SOURCECFG_BASE <= addr) && diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c index 8615e4cc1d9c..4d4d5b50cabf 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/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index efe5054182c3..4e86d2d43670 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -24,7 +24,7 @@ #include "trace.h" #include "qom/object.h" -#define FLIC_SAVE_INITIAL_SIZE qemu_real_host_page_size +#define FLIC_SAVE_INITIAL_SIZE qemu_real_host_page_size() #define FLIC_FAILED (-1UL) #define FLIC_SAVEVM_VERSION 1 diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index eebbcf33d4f6..5522ede2cf85 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -42,7 +42,6 @@ static PLICMode char_to_mode(char c) switch (c) { case 'U': return PLICMode_U; case 'S': return PLICMode_S; - case 'H': return PLICMode_H; case 'M': return PLICMode_M; default: error_report("plic: invalid mode '%c'", c); @@ -78,6 +77,7 @@ static uint32_t sifive_plic_claimed(SiFivePLICState *plic, uint32_t addrid) uint32_t max_irq = 0; uint32_t max_prio = plic->target_priority[addrid]; int i, j; + int num_irq_in_word = 32; for (i = 0; i < plic->bitfield_words; i++) { uint32_t pending_enabled_not_claimed = @@ -88,7 +88,16 @@ static uint32_t sifive_plic_claimed(SiFivePLICState *plic, uint32_t addrid) continue; } - for (j = 0; j < 32; j++) { + if (i == (plic->bitfield_words - 1)) { + /* + * If plic->num_sources is not multiple of 32, num-of-irq in last + * word is not 32. Compute the num-of-irq of last word to avoid + * out-of-bound access of source_priority array. + */ + num_irq_in_word = plic->num_sources - ((plic->bitfield_words - 1) << 5); + } + + for (j = 0; j < num_irq_in_word; j++) { int irq = (i << 5) + j; uint32_t prio = plic->source_priority[irq]; int enabled = pending_enabled_not_claimed & (1 << j); @@ -131,10 +140,11 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) SiFivePLICState *plic = opaque; if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) { - uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; + uint32_t irq = (addr - plic->priority_base) >> 2; return plic->source_priority[irq]; - } else if (addr_between(addr, plic->pending_base, plic->num_sources >> 3)) { + } else if (addr_between(addr, plic->pending_base, + (plic->num_sources + 31) >> 3)) { uint32_t word = (addr - plic->pending_base) >> 2; return plic->pending[word]; @@ -178,12 +188,22 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, SiFivePLICState *plic = opaque; if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) { - uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; - - plic->source_priority[irq] = value & 7; - sifive_plic_update(plic); + uint32_t irq = (addr - plic->priority_base) >> 2; + + if (((plic->num_priorities + 1) & plic->num_priorities) == 0) { + /* + * if "num_priorities + 1" is power-of-2, make each register bit of + * interrupt priority WARL (Write-Any-Read-Legal). Just filter + * out the access to unsupported priority bits. + */ + plic->source_priority[irq] = value % (plic->num_priorities + 1); + sifive_plic_update(plic); + } else if (value <= plic->num_priorities) { + plic->source_priority[irq] = value; + sifive_plic_update(plic); + } } else if (addr_between(addr, plic->pending_base, - plic->num_sources >> 3)) { + (plic->num_sources + 31) >> 3)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pending write: 0x%" HWADDR_PRIx "", __func__, addr); @@ -205,7 +225,16 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, uint32_t contextid = (addr & (plic->context_stride - 1)); if (contextid == 0) { - if (value <= plic->num_priorities) { + if (((plic->num_priorities + 1) & plic->num_priorities) == 0) { + /* + * if "num_priorities + 1" is power-of-2, each register bit of + * interrupt priority is WARL (Write-Any-Read-Legal). Just + * filter out the access to unsupported priority bits. + */ + plic->target_priority[addrid] = value % + (plic->num_priorities + 1); + sifive_plic_update(plic); + } else if (value <= plic->num_priorities) { plic->target_priority[addrid] = value; sifive_plic_update(plic); } @@ -262,7 +291,7 @@ static void sifive_plic_reset(DeviceState *dev) */ static void parse_hart_config(SiFivePLICState *plic) { - int addrid, hartid, modes; + int addrid, hartid, modes, m; const char *p; char c; @@ -271,11 +300,13 @@ static void parse_hart_config(SiFivePLICState *plic) p = plic->hart_config; while ((c = *p++)) { if (c == ',') { - addrid += ctpop8(modes); - modes = 0; - hartid++; + if (modes) { + addrid += ctpop8(modes); + hartid++; + modes = 0; + } } else { - int m = 1 << char_to_mode(c); + m = 1 << char_to_mode(c); if (modes == (modes | m)) { error_report("plic: duplicate mode '%c' in config: %s", c, plic->hart_config); @@ -286,8 +317,9 @@ static void parse_hart_config(SiFivePLICState *plic) } if (modes) { addrid += ctpop8(modes); + hartid++; + modes = 0; } - hartid++; plic->num_addrs = addrid; plic->num_harts = hartid; @@ -298,11 +330,16 @@ static void parse_hart_config(SiFivePLICState *plic) p = plic->hart_config; while ((c = *p++)) { if (c == ',') { - hartid++; + if (modes) { + hartid++; + modes = 0; + } } else { + m = char_to_mode(c); plic->addr_config[addrid].addrid = addrid; plic->addr_config[addrid].hartid = hartid; - plic->addr_config[addrid].mode = char_to_mode(c); + plic->addr_config[addrid].mode = m; + modes |= (1 << m); addrid++; } } @@ -327,6 +364,11 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp) parse_hart_config(s); + if (!s->num_sources) { + error_setg(errp, "plic: invalid number of interrupt sources"); + return; + } + s->bitfield_words = (s->num_sources + 31) >> 5; s->num_enables = s->bitfield_words * s->num_addrs; s->source_priority = g_new0(uint32_t, s->num_sources); @@ -343,7 +385,8 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp) s->m_external_irqs = g_malloc(sizeof(qemu_irq) * s->num_harts); qdev_init_gpio_out(dev, s->m_external_irqs, s->num_harts); - /* We can't allow the supervisor to control SEIP as this would allow the + /* + * We can't allow the supervisor to control SEIP as this would allow the * supervisor to clear a pending external interrupt which will result in * lost a interrupt in the case a PLIC is attached. The SEIP bit must be * hardware controlled when a PLIC is attached. @@ -351,8 +394,8 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_harts; i++) { RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i)); if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { - error_report("SEIP already claimed"); - exit(1); + error_setg(errp, "SEIP already claimed"); + return; } } @@ -383,8 +426,10 @@ static const VMStateDescription vmstate_sifive_plic = { static Property sifive_plic_properties[] = { DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config), DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0), - DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0), + /* number of interrupt sources including interrupt source 0 */ + DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 1), DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0), + /* interrupt priority register base starting from source 0 */ DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0), DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0), DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0), @@ -431,7 +476,7 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, uint32_t context_stride, uint32_t aperture_size) { DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC); - int i, j = 0; + int i; SiFivePLICState *plic; assert(enable_stride == (enable_stride & -enable_stride)); @@ -451,18 +496,17 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); plic = SIFIVE_PLIC(dev); - for (i = 0; i < num_harts; i++) { - CPUState *cpu = qemu_get_cpu(hartid_base + i); - if (plic->addr_config[j].mode == PLICMode_M) { - j++; - qdev_connect_gpio_out(dev, num_harts + i, + for (i = 0; i < plic->num_addrs; i++) { + int cpu_num = plic->addr_config[i].hartid; + CPUState *cpu = qemu_get_cpu(cpu_num); + + if (plic->addr_config[i].mode == PLICMode_M) { + qdev_connect_gpio_out(dev, cpu_num - hartid_base + num_harts, qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT)); } - - if (plic->addr_config[j].mode == PLICMode_S) { - j++; - qdev_connect_gpio_out(dev, i, + if (plic->addr_config[i].mode == PLICMode_S) { + qdev_connect_gpio_out(dev, cpu_num - hartid_base, qdev_get_gpio_in(DEVICE(cpu), IRQ_S_EXT)); } } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 53414aa19792..6fbc2045e618 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -151,8 +151,9 @@ gicv3_icv_hppir_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_HPPIR%d rea gicv3_icv_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICV_DIR write cpu 0x%x value 0x%" PRIx64 gicv3_icv_iar_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IAR%d read cpu 0x%x value 0x%" PRIx64 gicv3_icv_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_EOIR%d write cpu 0x%x value 0x%" PRIx64 -gicv3_cpuif_virt_update(uint32_t cpuid, int idx) "GICv3 CPU i/f 0x%x virt HPPI update LR index %d" -gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel, int maintlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d maintenance-irq %d" +gicv3_cpuif_virt_update(uint32_t cpuid, int idx, int hppvlpi, int grp, int prio) "GICv3 CPU i/f 0x%x virt HPPI update LR index %d HPPVLPI %d grp %d prio %d" +gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d" +gicv3_cpuif_virt_set_maint_irq(uint32_t cpuid, int maintlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting maintenance-irq %d" # arm_gicv3_dist.c gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" @@ -184,9 +185,17 @@ gicv3_its_cmd_mapd(uint32_t devid, uint32_t size, uint64_t ittaddr, int valid) " gicv3_its_cmd_mapc(uint32_t icid, uint64_t rdbase, int valid) "GICv3 ITS: command MAPC ICID 0x%x RDbase 0x%" PRIx64 " V %d" gicv3_its_cmd_mapi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MAPI DeviceID 0x%x EventID 0x%x ICID 0x%x" gicv3_its_cmd_mapti(uint32_t devid, uint32_t eventid, uint32_t icid, uint32_t intid) "GICv3 ITS: command MAPTI DeviceID 0x%x EventID 0x%x ICID 0x%x pINTID 0x%x" -gicv3_its_cmd_inv(void) "GICv3 ITS: command INV or INVALL" +gicv3_its_cmd_inv(uint32_t devid, uint32_t eventid) "GICv3 ITS: command INV DeviceID 0x%x EventID 0x%x" +gicv3_its_cmd_invall(void) "GICv3 ITS: command INVALL" gicv3_its_cmd_movall(uint64_t rd1, uint64_t rd2) "GICv3 ITS: command MOVALL RDbase1 0x%" PRIx64 " RDbase2 0x%" PRIx64 gicv3_its_cmd_movi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MOVI DeviceID 0x%x EventID 0x%x ICID 0x%x" +gicv3_its_cmd_vmapi(uint32_t devid, uint32_t eventid, uint32_t vpeid, uint32_t doorbell) "GICv3 ITS: command VMAPI DeviceID 0x%x EventID 0x%x vPEID 0x%x Dbell_pINTID 0x%x" +gicv3_its_cmd_vmapti(uint32_t devid, uint32_t eventid, uint32_t vpeid, uint32_t vintid, uint32_t doorbell) "GICv3 ITS: command VMAPI DeviceID 0x%x EventID 0x%x vPEID 0x%x vINTID 0x%x Dbell_pINTID 0x%x" +gicv3_its_cmd_vmapp(uint32_t vpeid, uint64_t rdbase, int valid, uint64_t vptaddr, uint32_t vptsize) "GICv3 ITS: command VMAPP vPEID 0x%x RDbase 0x%" PRIx64 " V %d VPT_addr 0x%" PRIx64 " VPT_size 0x%x" +gicv3_its_cmd_vmovp(uint32_t vpeid, uint64_t rdbase) "GICv3 ITS: command VMOVP vPEID 0x%x RDbase 0x%" PRIx64 +gicv3_its_cmd_vsync(void) "GICv3 ITS: command VSYNC" +gicv3_its_cmd_vmovi(uint32_t devid, uint32_t eventid, uint32_t vpeid, int dbvalid, uint32_t doorbell) "GICv3 ITS: command VMOVI DeviceID 0x%x EventID 0x%x vPEID 0x%x D %d Dbell_pINTID 0x%x" +gicv3_its_cmd_vinvall(uint32_t vpeid) "GICv3 ITS: command VINVALL vPEID 0x%x" gicv3_its_cmd_unknown(unsigned cmd) "GICv3 ITS: unknown command 0x%x" gicv3_its_cte_read(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS: Collection Table read for ICID 0x%x: valid %d RDBase 0x%x" gicv3_its_cte_write(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS: Collection Table write for ICID 0x%x: valid %d RDBase 0x%x" @@ -197,6 +206,9 @@ gicv3_its_ite_write(uint64_t ittaddr, uint32_t eventid, int valid, int inttype, gicv3_its_dte_read(uint32_t devid, int valid, uint32_t size, uint64_t ittaddr) "GICv3 ITS: Device Table read for DeviceID 0x%x: valid %d size 0x%x ITTaddr 0x%" PRIx64 gicv3_its_dte_write(uint32_t devid, int valid, uint32_t size, uint64_t ittaddr) "GICv3 ITS: Device Table write for DeviceID 0x%x: valid %d size 0x%x ITTaddr 0x%" PRIx64 gicv3_its_dte_read_fault(uint32_t devid) "GICv3 ITS: Device Table read for DeviceID 0x%x: faulted" +gicv3_its_vte_read(uint32_t vpeid, int valid, uint32_t vptsize, uint64_t vptaddr, uint32_t rdbase) "GICv3 ITS: vPE Table read for vPEID 0x%x: valid %d VPTsize 0x%x VPTaddr 0x%" PRIx64 " RDbase 0x%x" +gicv3_its_vte_read_fault(uint32_t vpeid) "GICv3 ITS: vPE Table read for vPEID 0x%x: faulted" +gicv3_its_vte_write(uint32_t vpeid, int valid, uint32_t vptsize, uint64_t vptaddr, uint32_t rdbase) "GICv3 ITS: vPE Table write for vPEID 0x%x: valid %d VPTsize 0x%x VPTaddr 0x%" PRIx64 " RDbase 0x%x" # armv7m_nvic.c nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d" @@ -275,3 +287,24 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u - sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx" sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx" sh_intc_set(int id, int enable) "setting interrupt group %d to %d" + +# loongarch_ipi.c +loongarch_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 +loongarch_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 + +# loongarch_pch_pic.c +loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d" +loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 + +# loongarch_pch_msi.c +loongarch_msi_set_irq(int irq_num) "set msi irq %d" + +# loongarch_extioi.c +loongarch_extioi_setirq(int irq, int level) "set extirq irq %d level %d" +loongarch_extioi_readw(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_extioi_writew(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64 diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 24e67020dbf3..c7f8abd71e49 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -301,23 +301,25 @@ void icp_reset(ICPState *icp) static void icp_realize(DeviceState *dev, Error **errp) { ICPState *icp = ICP(dev); + PowerPCCPU *cpu; CPUPPCState *env; Error *err = NULL; assert(icp->xics); assert(icp->cs); - env = &POWERPC_CPU(icp->cs)->env; + cpu = POWERPC_CPU(icp->cs); + env = &cpu->env; switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_POWER7: - icp->output = env->irq_inputs[POWER7_INPUT_INT]; + icp->output = qdev_get_gpio_in(DEVICE(cpu), POWER7_INPUT_INT); break; case PPC_FLAGS_INPUT_POWER9: /* For SPAPR xics emulation */ - icp->output = env->irq_inputs[POWER9_INPUT_INT]; + icp->output = qdev_get_gpio_in(DEVICE(cpu), POWER9_INPUT_INT); break; case PPC_FLAGS_INPUT_970: - icp->output = env->irq_inputs[PPC970_INPUT_INT]; + icp->output = qdev_get_gpio_in(DEVICE(cpu), PPC970_INPUT_INT); break; default: @@ -562,11 +564,11 @@ static void ics_reset_irq(ICSIRQState *irq) irq->saved_priority = 0xff; } -static void ics_reset(DeviceState *dev) +static void ics_reset_hold(Object *obj) { - ICSState *ics = ICS(dev); + ICSState *ics = ICS(obj); + 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; @@ -582,7 +584,7 @@ static void ics_reset(DeviceState *dev) if (kvm_irqchip_in_kernel()) { Error *local_err = NULL; - ics_set_kvm_state(ICS(dev), &local_err); + ics_set_kvm_state(ics, &local_err); if (local_err) { error_report_err(local_err); } @@ -591,7 +593,7 @@ static void ics_reset(DeviceState *dev) static void ics_reset_handler(void *dev) { - ics_reset(dev); + device_cold_reset(dev); } static void ics_realize(DeviceState *dev, Error **errp) @@ -686,16 +688,17 @@ static Property ics_properties[] = { static void ics_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); dc->realize = ics_realize; device_class_set_props(dc, ics_properties); - dc->reset = ics_reset; dc->vmsd = &vmstate_ics; /* * Reason: part of XICS interrupt controller, needs to be wired up, * e.g. by spapr_irq_init(). */ dc->user_creatable = false; + rc->phases.hold = ics_reset_hold; } static const TypeInfo ics_info = { diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index f5bfc501bc15..9719d98a179e 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "trace.h" #include "sysemu/kvm.h" #include "hw/ppc/spapr.h" diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index 4c4397b3d2c3..6e5012e66eb5 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -42,10 +42,10 @@ #define R_MAX 8 #define TYPE_XILINX_INTC "xlnx.xps-intc" -DECLARE_INSTANCE_CHECKER(struct xlx_pic, XILINX_INTC, - TYPE_XILINX_INTC) +typedef struct XpsIntc XpsIntc; +DECLARE_INSTANCE_CHECKER(XpsIntc, XILINX_INTC, TYPE_XILINX_INTC) -struct xlx_pic +struct XpsIntc { SysBusDevice parent_obj; @@ -62,7 +62,7 @@ struct xlx_pic uint32_t irq_pin_state; }; -static void update_irq(struct xlx_pic *p) +static void update_irq(XpsIntc *p) { uint32_t i; @@ -87,10 +87,9 @@ static void update_irq(struct xlx_pic *p) qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]); } -static uint64_t -pic_read(void *opaque, hwaddr addr, unsigned int size) +static uint64_t pic_read(void *opaque, hwaddr addr, unsigned int size) { - struct xlx_pic *p = opaque; + XpsIntc *p = opaque; uint32_t r = 0; addr >>= 2; @@ -106,11 +105,10 @@ pic_read(void *opaque, hwaddr addr, unsigned int size) return r; } -static void -pic_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) +static void pic_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) { - struct xlx_pic *p = opaque; + XpsIntc *p = opaque; uint32_t value = val64; addr >>= 2; @@ -154,7 +152,7 @@ static const MemoryRegionOps pic_ops = { static void irq_handler(void *opaque, int irq, int level) { - struct xlx_pic *p = opaque; + XpsIntc *p = opaque; /* edge triggered interrupt */ if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) { @@ -168,7 +166,7 @@ static void irq_handler(void *opaque, int irq, int level) static void xilinx_intc_init(Object *obj) { - struct xlx_pic *p = XILINX_INTC(obj); + XpsIntc *p = XILINX_INTC(obj); qdev_init_gpio_in(DEVICE(obj), irq_handler, 32); sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq); @@ -179,7 +177,7 @@ static void xilinx_intc_init(Object *obj) } static Property xilinx_intc_properties[] = { - DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0), + DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -193,7 +191,7 @@ static void xilinx_intc_class_init(ObjectClass *klass, void *data) static const TypeInfo xilinx_intc_info = { .name = TYPE_XILINX_INTC, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct xlx_pic), + .instance_size = sizeof(XpsIntc), .instance_init = xilinx_intc_init, .class_init = xilinx_intc_class_init, }; diff --git a/hw/intc/xive.c b/hw/intc/xive.c index b8e4c7294d59..a986b96843e7 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -114,6 +114,17 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring) } } +void xive_tctx_reset_os_signal(XiveTCTX *tctx) +{ + /* + * Lower the External interrupt. Used when pulling an OS + * context. It is necessary to avoid catching it in the hypervisor + * context. It should be raised again when re-pushing the OS + * context. + */ + qemu_irq_lower(xive_tctx_output(tctx, TM_QW1_OS)); +} + static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr) { uint8_t *regs = &tctx->regs[ring]; @@ -388,6 +399,8 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, /* Invalidate CAM line */ qw1w2_new = xive_set_field32(TM_QW1W2_VO, qw1w2, 0); xive_tctx_set_os_cam(tctx, qw1w2_new); + + xive_tctx_reset_os_signal(tctx); return qw1w2; } @@ -413,10 +426,16 @@ static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx, /* Reset the NVT value */ nvt.w4 = xive_set_field32(NVT_W4_IPB, nvt.w4, 0); xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4); - - /* Merge in current context */ - xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } + /* + * Always call xive_tctx_ipb_update(). Even if there were no + * escalation triggered, there could be a pending interrupt which + * was saved when the context was pulled and that we need to take + * into account by recalculating the PIPR (which is not + * saved/restored). + * It will also raise the External interrupt signal if needed. + */ + xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } /* @@ -676,8 +695,8 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) env = &cpu->env; switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_POWER9: - tctx->hv_output = env->irq_inputs[POWER9_INPUT_HINT]; - tctx->os_output = env->irq_inputs[POWER9_INPUT_INT]; + tctx->hv_output = qdev_get_gpio_in(DEVICE(cpu), POWER9_INPUT_HINT); + tctx->os_output = qdev_get_gpio_in(DEVICE(cpu), POWER9_INPUT_INT); break; default: diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index 3aff42a69ef5..4d9ff4195603 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -269,6 +269,7 @@ uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, xive2_tctx_save_os_ctx(xrtr, tctx, nvp_blk, nvp_idx); } + xive_tctx_reset_os_signal(tctx); return qw1w2; } @@ -316,7 +317,6 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, { Xive2Nvp nvp; uint8_t ipb; - uint8_t cppr = 0; /* * Grab the associated thread interrupt context registers in the @@ -337,7 +337,7 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, /* Automatically restore thread context registers */ if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_restore) { - cppr = xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp); + xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp); } ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2); @@ -345,11 +345,15 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, 0); xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2); } - - /* An IPB or CPPR change can trigger a resend */ - if (ipb || cppr) { - xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); - } + /* + * Always call xive_tctx_ipb_update(). Even if there were no + * escalation triggered, there could be a pending interrupt which + * was saved when the context was pulled and that we need to take + * into account by recalculating the PIPR (which is not + * saved/restored). + * It will also raise the External interrupt signal if needed. + */ + xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } /* diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index 1f764fc85ba9..6b3edbf01765 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -12,7 +12,7 @@ #include "qemu/units.h" #include "hw/ipack/ipack.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "migration/vmstate.h" #include "qemu/bitops.h" #include "qemu/module.h" diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index 88aa734e9e41..a83e7243d6cb 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -31,6 +31,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qom/object.h" +#include "hw/acpi/ipmi.h" #define TYPE_ISA_IPMI_BT "isa-ipmi-bt" OBJECT_DECLARE_SIMPLE_TYPE(ISAIPMIBTDevice, ISA_IPMI_BT) @@ -144,6 +145,7 @@ static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc); dc->realize = isa_ipmi_bt_realize; device_class_set_props(dc, ipmi_isa_properties); @@ -151,6 +153,7 @@ static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data) iic->get_backend_data = isa_ipmi_bt_get_backend_data; ipmi_bt_class_init(iic); iic->get_fwinfo = isa_ipmi_bt_get_fwinfo; + adevc->build_dev_aml = build_ipmi_dev_aml; } static const TypeInfo isa_ipmi_bt_info = { @@ -161,6 +164,7 @@ static const TypeInfo isa_ipmi_bt_info = { .class_init = isa_ipmi_bt_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, + { TYPE_ACPI_DEV_AML_IF }, { } } }; diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index afabb95ebec3..b2ed70b9da56 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -31,6 +31,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qom/object.h" +#include "hw/acpi/ipmi.h" #define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs" OBJECT_DECLARE_SIMPLE_TYPE(ISAIPMIKCSDevice, ISA_IPMI_KCS) @@ -151,6 +152,7 @@ static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc); dc->realize = ipmi_isa_realize; device_class_set_props(dc, ipmi_isa_properties); @@ -158,6 +160,7 @@ static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data) iic->get_backend_data = isa_ipmi_kcs_get_backend_data; ipmi_kcs_class_init(iic); iic->get_fwinfo = isa_ipmi_kcs_get_fwinfo; + adevc->build_dev_aml = build_ipmi_dev_aml; } static const TypeInfo isa_ipmi_kcs_info = { @@ -168,6 +171,7 @@ static const TypeInfo isa_ipmi_kcs_info = { .class_init = isa_ipmi_kcs_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, + { TYPE_ACPI_DEV_AML_IF }, { } } }; diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c index b6e52730d389..633931b82571 100644 --- a/hw/ipmi/pci_ipmi_bt.c +++ b/hw/ipmi/pci_ipmi_bt.c @@ -25,7 +25,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "hw/ipmi/ipmi_bt.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "qom/object.h" #define TYPE_PCI_IPMI_BT "pci-ipmi-bt" diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c index de13418862fe..1a581413c265 100644 --- a/hw/ipmi/pci_ipmi_kcs.c +++ b/hw/ipmi/pci_ipmi_kcs.c @@ -25,7 +25,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "hw/ipmi/ipmi_kcs.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "qom/object.h" #define TYPE_PCI_IPMI_KCS "pci-ipmi-kcs" diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c index 1fdf0a66b698..d0991ab7f939 100644 --- a/hw/ipmi/smbus_ipmi.c +++ b/hw/ipmi/smbus_ipmi.c @@ -28,6 +28,7 @@ #include "qemu/error-report.h" #include "hw/ipmi/ipmi.h" #include "qom/object.h" +#include "hw/acpi/ipmi.h" #define TYPE_SMBUS_IPMI "smbus-ipmi" OBJECT_DECLARE_SIMPLE_TYPE(SMBusIPMIDevice, SMBUS_IPMI) @@ -280,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; } @@ -353,6 +356,7 @@ static void smbus_ipmi_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(oc); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc); sc->receive_byte = ipmi_receive_byte; sc->write_data = ipmi_write_data; @@ -363,6 +367,7 @@ static void smbus_ipmi_class_init(ObjectClass *oc, void *data) iic->handle_if_event = smbus_ipmi_handle_event; iic->set_irq_enable = smbus_ipmi_set_irq_enable; iic->get_fwinfo = smbus_ipmi_get_fwinfo; + adevc->build_dev_aml = build_ipmi_dev_aml; } static const TypeInfo smbus_ipmi_info = { @@ -373,6 +378,7 @@ static const TypeInfo smbus_ipmi_info = { .class_init = smbus_ipmi_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, + { TYPE_ACPI_DEV_AML_IF }, { } } }; diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index d42143a991e7..0156a66889a8 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -33,18 +33,26 @@ config PC87312 config PIIX3 bool + select I8257 select ISA_BUS config PIIX4 bool # For historical reasons, SuperIO devices are created in the board # for PIIX4. + select ACPI_PIIX4 + select I8254 + select I8257 + select I8259 + select IDE_PIIX select ISA_BUS + select MC146818RTC select USB_UHCI config VT82C686 bool select ISA_SUPERIO + select ACPI select ACPI_SMBUS select SERIAL_ISA select FDC_ISA @@ -53,6 +61,7 @@ config VT82C686 select I8254 select I8257 select I8259 + select IDE_VIA select MC146818RTC select PARALLEL @@ -67,6 +76,6 @@ config LPC_ICH9 bool # For historical reasons, SuperIO devices are created in the board # for ICH9. + select I8257 select ISA_BUS - select ACPI_SMBUS - select ACPI_X86_ICH + select ACPI_ICH9 diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index 2a2ff05b9372..e3322e03bf0c 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/irq.h" #include "hw/intc/i8259.h" #include "hw/timer/i8254.h" diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 0ad1c5fd6542..1bee1a47f101 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -24,6 +24,7 @@ #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "hw/isa/isa.h" +#include "hw/acpi/acpi_aml_interface.h" static ISABus *isabus; @@ -166,6 +167,7 @@ bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp) ISADevice *isa_vga_init(ISABus *bus) { + vga_interface_created = true; switch (vga_interface_type) { case VGA_CIRRUS: return isa_create_simple(bus, "isa-cirrus-vga"); @@ -189,15 +191,9 @@ ISADevice *isa_vga_init(ISABus *bus) void isa_build_aml(ISABus *bus, Aml *scope) { BusChild *kid; - ISADevice *dev; - ISADeviceClass *dc; QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) { - dev = ISA_DEVICE(kid->child); - dc = ISA_DEVICE_GET_CLASS(dev); - if (dc->build_aml) { - dc->build_aml(dev, scope); - } + call_dev_aml_func(DEVICE(kid->child), scope); } } diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 5f143dca17aa..8d541e2b54cf 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -34,6 +34,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/range.h" +#include "hw/dma/i8257.h" #include "hw/isa/isa.h" #include "migration/vmstate.h" #include "hw/irq.h" @@ -50,6 +51,8 @@ #include "hw/core/cpu.h" #include "hw/nvram/fw_cfg.h" #include "qemu/cutils.h" +#include "hw/acpi/acpi_aml_interface.h" +#include "trace.h" /*****************************************************************************/ /* ICH9 LPC PCI to ISA bridge */ @@ -160,6 +163,7 @@ static void ich9_cc_write(void *opaque, hwaddr addr, { ICH9LPCState *lpc = (ICH9LPCState *)opaque; + trace_ich9_cc_write(addr, val, len); ich9_cc_addr_len(&addr, &len); memcpy(lpc->chip_config + addr, &val, len); pci_bus_fire_intx_routing_notifier(pci_get_bus(&lpc->d)); @@ -175,6 +179,7 @@ static uint64_t ich9_cc_read(void *opaque, hwaddr addr, uint32_t val = 0; ich9_cc_addr_len(&addr, &len); memcpy(&val, lpc->chip_config + addr, len); + trace_ich9_cc_read(addr, val, len); return val; } @@ -721,6 +726,8 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) qdev_init_gpio_out_named(dev, lpc->gsi, ICH9_GPIO_GSI, GSI_NUM_PINS); isa_bus_irqs(isa_bus, lpc->gsi); + + i8257_dma_init(isa_bus, 0); } static bool ich9_rst_cnt_needed(void *opaque) @@ -785,7 +792,7 @@ static const VMStateDescription vmstate_ich9_lpc = { }; static Property ich9_lpc_properties[] = { - DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, true), + DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, false), DEFINE_PROP_BOOL("smm-compat", ICH9LPCState, pm.smm_compat, false), DEFINE_PROP_BIT64("x-smi-broadcast", ICH9LPCState, smi_host_features, ICH9_LPC_SMI_F_BROADCAST_BIT, true), @@ -803,12 +810,43 @@ static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) acpi_send_gpe_event(&s->pm.acpi_regs, s->pm.irq, ev); } +static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + Aml *field; + BusChild *kid; + ICH9LPCState *s = ICH9_LPC_DEVICE(adev); + BusState *bus = BUS(s->isa_bus); + Aml *sb_scope = aml_scope("\\_SB"); + + /* ICH9 PCI to ISA irq remapping */ + aml_append(scope, aml_operation_region("PIRQ", AML_PCI_CONFIG, + aml_int(0x60), 0x0C)); + /* Fields declarion has to happen *after* operation region */ + field = aml_field("PCI0.SF8.PIRQ", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("PRQA", 8)); + aml_append(field, aml_named_field("PRQB", 8)); + aml_append(field, aml_named_field("PRQC", 8)); + aml_append(field, aml_named_field("PRQD", 8)); + aml_append(field, aml_reserved_field(0x20)); + aml_append(field, aml_named_field("PRQE", 8)); + aml_append(field, aml_named_field("PRQF", 8)); + aml_append(field, aml_named_field("PRQG", 8)); + aml_append(field, aml_named_field("PRQH", 8)); + aml_append(sb_scope, field); + aml_append(scope, sb_scope); + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + call_dev_aml_func(DEVICE(kid->child), scope); + } +} + static void ich9_lpc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); + AcpiDevAmlIfClass *amldevc = ACPI_DEV_AML_IF_CLASS(klass); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = ich9_lpc_reset; @@ -833,6 +871,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) adevc->ospm_status = ich9_pm_ospm_status; adevc->send_event = ich9_send_gpe; adevc->madt_cpu = pc_madt_cpu_entry; + amldevc->build_dev_aml = build_ich9_isa_aml; } static const TypeInfo ich9_lpc_info = { @@ -845,6 +884,7 @@ static const TypeInfo ich9_lpc_info = { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { TYPE_ACPI_DEV_AML_IF }, { } } }; diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index dab901c9ad99..eabad7ba58be 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -24,20 +24,18 @@ #include "qemu/osdep.h" #include "qemu/range.h" +#include "qapi/error.h" +#include "hw/dma/i8257.h" #include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/xen/xen.h" -#include "sysemu/xen.h" -#include "sysemu/reset.h" #include "sysemu/runstate.h" #include "migration/vmstate.h" +#include "hw/acpi/acpi_aml_interface.h" #define XEN_PIIX_NUM_PIRQS 128ULL -#define TYPE_PIIX3_DEVICE "PIIX3" -#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen" - static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) { qemu_set_irq(piix3->pic[pic_irq], @@ -81,6 +79,17 @@ static void piix3_set_irq(void *opaque, int pirq, int level) piix3_set_irq_level(piix3, pirq, level); } +/* + * Return the global irq number corresponding to a given device irq + * pin. We could also use the bus number to have a more precise mapping. + */ +static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) +{ + int slot_addend; + slot_addend = PCI_SLOT(pci_dev->devfn) - 1; + return (pci_intx + slot_addend) & 3; +} + static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) { PIIX3State *piix3 = opaque; @@ -128,13 +137,26 @@ static void piix3_write_config(PCIDevice *dev, static void piix3_write_config_xen(PCIDevice *dev, uint32_t address, uint32_t val, int len) { - xen_piix_pci_write_config_client(address, val, len); + int i; + + /* Scan for updates to PCI link routes (0x60-0x63). */ + for (i = 0; i < len; i++) { + uint8_t v = (val >> (8 * i)) & 0xff; + if (v & 0x80) { + v = 0; + } + v &= 0xf; + if (((address + i) >= PIIX_PIRQCA) && ((address + i) <= PIIX_PIRQCD)) { + xen_set_pci_link_route(address + i - PIIX_PIRQCA, v); + } + } + piix3_write_config(dev, address, val, len); } -static void piix3_reset(void *opaque) +static void piix3_reset(DeviceState *dev) { - PIIX3State *d = opaque; + PIIX3State *d = PIIX3_PCI_DEVICE(dev); uint8_t *pci_conf = d->dev.config; pci_conf[0x04] = 0x07; /* master, memory and I/O */ @@ -266,15 +288,21 @@ static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len) static const MemoryRegionOps rcr_ops = { .read = rcr_read, .write = rcr_write, - .endianness = DEVICE_LITTLE_ENDIAN + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, }; -static void piix3_realize(PCIDevice *dev, Error **errp) +static void pci_piix3_realize(PCIDevice *dev, Error **errp) { PIIX3State *d = PIIX3_PCI_DEVICE(dev); + ISABus *isa_bus; - if (!isa_bus_new(DEVICE(d), get_system_memory(), - pci_address_space_io(dev), errp)) { + isa_bus = isa_bus_new(DEVICE(d), pci_address_space(dev), + pci_address_space_io(dev), errp); + if (!isa_bus) { return; } @@ -283,18 +311,43 @@ static void piix3_realize(PCIDevice *dev, Error **errp) memory_region_add_subregion_overlap(pci_address_space_io(dev), PIIX_RCR_IOPORT, &d->rcr_mem, 1); - qemu_register_reset(piix3_reset, d); + i8257_dma_init(isa_bus, 0); +} + +static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + Aml *field; + BusChild *kid; + Aml *sb_scope = aml_scope("\\_SB"); + BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0"); + + /* PIIX PCI to ISA irq remapping */ + aml_append(scope, aml_operation_region("P40C", AML_PCI_CONFIG, + aml_int(0x60), 0x04)); + /* Fields declarion has to happen *after* operation region */ + field = aml_field("PCI0.S08.P40C", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("PRQ0", 8)); + aml_append(field, aml_named_field("PRQ1", 8)); + aml_append(field, aml_named_field("PRQ2", 8)); + aml_append(field, aml_named_field("PRQ3", 8)); + aml_append(sb_scope, field); + aml_append(scope, sb_scope); + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + call_dev_aml_func(DEVICE(kid->child), scope); + } } static void pci_piix3_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); + dc->reset = piix3_reset; dc->desc = "ISA bridge"; dc->vmsd = &vmstate_piix3; dc->hotpluggable = false; - k->realize = piix3_realize; k->vendor_id = PCI_VENDOR_ID_INTEL; /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; @@ -304,6 +357,7 @@ static void pci_piix3_class_init(ObjectClass *klass, void *data) * pc_piix.c's pc_init1() */ dc->user_creatable = false; + adevc->build_dev_aml = build_pci_isa_aml; } static const TypeInfo piix3_pci_type_info = { @@ -314,15 +368,33 @@ static const TypeInfo piix3_pci_type_info = { .class_init = pci_piix3_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { TYPE_ACPI_DEV_AML_IF }, { }, }, }; +static void piix3_realize(PCIDevice *dev, Error **errp) +{ + ERRP_GUARD(); + PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); + PCIBus *pci_bus = pci_get_bus(dev); + + pci_piix3_realize(dev, errp); + if (*errp) { + return; + } + + pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq, + piix3, PIIX_NUM_PIRQS); + pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); +} + static void piix3_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->config_write = piix3_write_config; + k->realize = piix3_realize; } static const TypeInfo piix3_info = { @@ -331,12 +403,34 @@ static const TypeInfo piix3_info = { .class_init = piix3_class_init, }; +static void piix3_xen_realize(PCIDevice *dev, Error **errp) +{ + ERRP_GUARD(); + PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); + PCIBus *pci_bus = pci_get_bus(dev); + + pci_piix3_realize(dev, errp); + if (*errp) { + return; + } + + /* + * Xen supports additional interrupt routes from the PCI devices to + * the IOAPIC: the four pins of each PCI device on the bus are also + * connected to the IOAPIC directly. + * These additional routes can be discovered through ACPI. + */ + pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq, + piix3, XEN_PIIX_NUM_PIRQS); +} + static void piix3_xen_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->config_write = piix3_write_config_xen; -}; + k->realize = piix3_xen_realize; +} static const TypeInfo piix3_xen_info = { .name = TYPE_PIIX3_XEN_DEVICE, @@ -352,44 +446,3 @@ static void piix3_register_types(void) } type_init(piix3_register_types) - -/* - * Return the global irq number corresponding to a given device irq - * pin. We could also use the bus number to have a more precise mapping. - */ -static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) -{ - int slot_addend; - slot_addend = PCI_SLOT(pci_dev->devfn) - 1; - return (pci_intx + slot_addend) & 3; -} - -PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus) -{ - PIIX3State *piix3; - PCIDevice *pci_dev; - - /* - * Xen supports additional interrupt routes from the PCI devices to - * the IOAPIC: the four pins of each PCI device on the bus are also - * connected to the IOAPIC directly. - * These additional routes can be discovered through ACPI. - */ - if (xen_enabled()) { - pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, - TYPE_PIIX3_XEN_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); - pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq, - piix3, XEN_PIIX_NUM_PIRQS); - } else { - pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, - TYPE_PIIX3_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); - pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq, - piix3, PIIX_NUM_PIRQS); - pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); - } - *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); - - return piix3; -} diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 8607e0ac36ad..8fc1db6dc977 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -28,12 +28,15 @@ #include "hw/irq.h" #include "hw/southbridge/piix.h" #include "hw/pci/pci.h" +#include "hw/ide/piix.h" #include "hw/isa/isa.h" #include "hw/intc/i8259.h" #include "hw/dma/i8257.h" #include "hw/timer/i8254.h" #include "hw/rtc/mc146818rtc.h" #include "hw/ide/pci.h" +#include "hw/acpi/piix4.h" +#include "hw/usb/hcd-uhci.h" #include "migration/vmstate.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" @@ -45,6 +48,9 @@ struct PIIX4State { qemu_irq *isa; RTCState rtc; + PCIIDEState ide; + UHCIState uhci; + PIIX4PMState pm; /* Reset Control Register */ MemoryRegion rcr_mem; uint8_t rcr; @@ -73,6 +79,31 @@ static void piix4_set_irq(void *opaque, int irq_num, int level) } } +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot; + + slot = PCI_SLOT(pci_dev->devfn); + + switch (slot) { + /* PIIX4 USB */ + case 10: + return 3; + /* AMD 79C973 Ethernet */ + case 11: + return 1; + /* Crystal 4281 Sound */ + case 12: + return 2; + /* PCI slot 1 to 4 */ + case 18 ... 21: + return ((slot - 18) + irq_num) & 0x03; + /* Unknown device, don't do any translation */ + default: + return irq_num; + } +} + static void piix4_isa_reset(DeviceState *dev) { PIIX4State *d = PIIX4_PCI_DEVICE(dev); @@ -109,9 +140,11 @@ static void piix4_isa_reset(DeviceState *dev) pci_conf[0xab] = 0x00; pci_conf[0xac] = 0x00; pci_conf[0xae] = 0x00; + + d->rcr = 0; } -static int piix4_ide_post_load(void *opaque, int version_id) +static int piix4_post_load(void *opaque, int version_id) { PIIX4State *s = opaque; @@ -126,7 +159,7 @@ static const VMStateDescription vmstate_piix4 = { .name = "PIIX4", .version_id = 3, .minimum_version_id = 2, - .post_load = piix4_ide_post_load, + .post_load = piix4_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, PIIX4State), VMSTATE_UINT8_V(rcr, PIIX4State, 3), @@ -179,6 +212,7 @@ static const MemoryRegionOps piix4_rcr_ops = { static void piix4_realize(PCIDevice *dev, Error **errp) { PIIX4State *s = PIIX4_PCI_DEVICE(dev); + PCIBus *pci_bus = pci_get_bus(dev); ISABus *isa_bus; qemu_irq *i8259_out_irq; @@ -217,13 +251,40 @@ static void piix4_realize(PCIDevice *dev, Error **errp) return; } s->rtc.irq = isa_get_irq(ISA_DEVICE(&s->rtc), s->rtc.isairq); + + /* IDE */ + qdev_prop_set_int32(DEVICE(&s->ide), "addr", dev->devfn + 1); + if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) { + return; + } + + /* USB */ + qdev_prop_set_int32(DEVICE(&s->uhci), "addr", dev->devfn + 2); + if (!qdev_realize(DEVICE(&s->uhci), BUS(pci_bus), errp)) { + return; + } + + /* ACPI controller */ + qdev_prop_set_int32(DEVICE(&s->pm), "addr", dev->devfn + 3); + if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) { + return; + } + qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa[9]); + + pci_bus_irqs(pci_bus, piix4_set_irq, pci_slot_get_pirq, s, PIIX_NUM_PIRQS); } static void piix4_init(Object *obj) { PIIX4State *s = PIIX4_PCI_DEVICE(obj); - object_initialize(&s->rtc, sizeof(s->rtc), TYPE_MC146818_RTC); + object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC); + object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); + object_initialize_child(obj, "uhci", &s->uhci, "piix4-usb-uhci"); + + object_initialize_child(obj, "pm", &s->pm, TYPE_PIIX4_PM); + qdev_prop_set_uint32(DEVICE(&s->pm), "smb_io_base", 0x1100); + qdev_prop_set_bit(DEVICE(&s->pm), "smm-enabled", 0); } static void piix4_class_init(ObjectClass *klass, void *data) @@ -264,58 +325,3 @@ static void piix4_register_types(void) } type_init(piix4_register_types) - -static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - int slot; - - slot = PCI_SLOT(pci_dev->devfn); - - switch (slot) { - /* PIIX4 USB */ - case 10: - return 3; - /* AMD 79C973 Ethernet */ - case 11: - return 1; - /* Crystal 4281 Sound */ - case 12: - return 2; - /* PCI slot 1 to 4 */ - case 18 ... 21: - return ((slot - 18) + irq_num) & 0x03; - /* Unknown device, don't do any translation */ - default: - return irq_num; - } -} - -DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus) -{ - PIIX4State *s; - PCIDevice *pci; - DeviceState *dev; - int devfn = PCI_DEVFN(10, 0); - - pci = pci_create_simple_multifunction(pci_bus, devfn, true, - TYPE_PIIX4_PCI_DEVICE); - dev = DEVICE(pci); - s = PIIX4_PCI_DEVICE(pci); - if (isa_bus) { - *isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0")); - } - - pci = pci_create_simple(pci_bus, devfn + 1, "piix4-ide"); - pci_ide_create_devs(pci); - - pci_create_simple(pci_bus, devfn + 2, "piix4-usb-uhci"); - if (smbus) { - *smbus = piix4_pm_init(pci_bus, devfn + 3, 0x1100, - qdev_get_gpio_in_named(dev, "isa", 9), - NULL, 0, NULL); - } - - pci_bus_irqs(pci_bus, piix4_set_irq, pci_slot_get_pirq, s, PIIX_NUM_PIRQS); - - return dev; -} diff --git a/hw/isa/trace-events b/hw/isa/trace-events index b8f877e1ed8e..c4567a9b47c2 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -21,3 +21,7 @@ via_pm_io_read(uint32_t addr, uint32_t val, int len) "addr 0x%x val 0x%x len 0x% via_pm_io_write(uint32_t addr, uint32_t val, int len) "addr 0x%x val 0x%x len 0x%x" via_superio_read(uint8_t addr, uint8_t val) "addr 0x%x val 0x%x" via_superio_write(uint8_t addr, uint32_t val) "addr 0x%x val 0x%x" + +# lpc_ich9.c +ich9_cc_write(uint64_t addr, uint64_t val, unsigned len) "addr=0x%"PRIx64 " val=0x%"PRIx64 " len=%u" +ich9_cc_read(uint64_t addr, uint64_t val, unsigned len) "addr=0x%"PRIx64 " val=0x%"PRIx64 " len=%u" diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 8f656251b8dc..3f9bd0c04d1e 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -17,11 +17,13 @@ #include "hw/isa/vt82c686.h" #include "hw/pci/pci.h" #include "hw/qdev-properties.h" +#include "hw/ide/pci.h" #include "hw/isa/isa.h" #include "hw/isa/superio.h" #include "hw/intc/i8259.h" #include "hw/irq.h" #include "hw/dma/i8257.h" +#include "hw/usb/hcd-uhci.h" #include "hw/timer/i8254.h" #include "hw/rtc/mc146818rtc.h" #include "migration/vmstate.h" @@ -248,6 +250,8 @@ static const ViaPMInitInfo vt82c686b_pm_init_info = { .device_id = PCI_DEVICE_ID_VIA_82C686B_PM, }; +#define TYPE_VT82C686B_PM "vt82c686b-pm" + static const TypeInfo vt82c686b_pm_info = { .name = TYPE_VT82C686B_PM, .parent = TYPE_VIA_PM, @@ -259,6 +263,8 @@ static const ViaPMInitInfo vt8231_pm_init_info = { .device_id = PCI_DEVICE_ID_VIA_8231_PM, }; +#define TYPE_VT8231_PM "vt8231-pm" + static const TypeInfo vt8231_pm_info = { .name = TYPE_VT8231_PM, .parent = TYPE_VIA_PM, @@ -543,8 +549,13 @@ struct ViaISAState { PCIDevice dev; qemu_irq cpu_intr; qemu_irq *isa_irqs; - ISABus *isa_bus; - ViaSuperIOState *via_sio; + ViaSuperIOState via_sio; + RTCState rtc; + PCIIDEState ide; + UHCIState uhci[2]; + ViaPMState pm; + PCIDevice ac97; + PCIDevice mc97; }; static const VMStateDescription vmstate_via = { @@ -557,10 +568,23 @@ static const VMStateDescription vmstate_via = { } }; +static void via_isa_init(Object *obj) +{ + ViaISAState *s = VIA_ISA(obj); + + object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC); + object_initialize_child(obj, "ide", &s->ide, TYPE_VIA_IDE); + object_initialize_child(obj, "uhci1", &s->uhci[0], TYPE_VT82C686B_USB_UHCI); + object_initialize_child(obj, "uhci2", &s->uhci[1], TYPE_VT82C686B_USB_UHCI); + object_initialize_child(obj, "ac97", &s->ac97, TYPE_VIA_AC97); + object_initialize_child(obj, "mc97", &s->mc97, TYPE_VIA_MC97); +} + static const TypeInfo via_isa_info = { .name = TYPE_VIA_ISA, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ViaISAState), + .instance_init = via_isa_init, .abstract = true, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, @@ -584,24 +608,74 @@ static void via_isa_realize(PCIDevice *d, Error **errp) { ViaISAState *s = VIA_ISA(d); DeviceState *dev = DEVICE(d); + PCIBus *pci_bus = pci_get_bus(d); qemu_irq *isa_irq; + ISABus *isa_bus; int i; qdev_init_gpio_out(dev, &s->cpu_intr, 1); isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1); - s->isa_bus = isa_bus_new(dev, get_system_memory(), pci_address_space_io(d), - &error_fatal); - s->isa_irqs = i8259_init(s->isa_bus, *isa_irq); - isa_bus_irqs(s->isa_bus, s->isa_irqs); - i8254_pit_init(s->isa_bus, 0x40, 0, NULL); - i8257_dma_init(s->isa_bus, 0); - mc146818_rtc_init(s->isa_bus, 2000, NULL); + isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d), + errp); + + if (!isa_bus) { + return; + } + + s->isa_irqs = i8259_init(isa_bus, *isa_irq); + isa_bus_irqs(isa_bus, s->isa_irqs); + i8254_pit_init(isa_bus, 0x40, 0, NULL); + i8257_dma_init(isa_bus, 0); + + /* RTC */ + qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); + if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) { + return; + } + isa_connect_gpio_out(ISA_DEVICE(&s->rtc), 0, s->rtc.isairq); for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) { if (i < PCI_COMMAND || i >= PCI_REVISION_ID) { d->wmask[i] = 0; } } + + /* Super I/O */ + if (!qdev_realize(DEVICE(&s->via_sio), BUS(isa_bus), errp)) { + return; + } + + /* Function 1: IDE */ + qdev_prop_set_int32(DEVICE(&s->ide), "addr", d->devfn + 1); + if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) { + return; + } + + /* Functions 2-3: USB Ports */ + for (i = 0; i < ARRAY_SIZE(s->uhci); i++) { + qdev_prop_set_int32(DEVICE(&s->uhci[i]), "addr", d->devfn + 2 + i); + if (!qdev_realize(DEVICE(&s->uhci[i]), BUS(pci_bus), errp)) { + return; + } + } + + /* Function 4: Power Management */ + qdev_prop_set_int32(DEVICE(&s->pm), "addr", d->devfn + 4); + if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) { + return; + } + + /* Function 5: AC97 Audio */ + qdev_prop_set_int32(DEVICE(&s->ac97), "addr", d->devfn + 5); + if (!qdev_realize(DEVICE(&s->ac97), BUS(pci_bus), errp)) { + return; + } + + /* Function 6: MC97 Modem */ + qdev_prop_set_int32(DEVICE(&s->mc97), "addr", d->devfn + 6); + if (!qdev_realize(DEVICE(&s->mc97), BUS(pci_bus), errp)) { + return; + } } /* TYPE_VT82C686B_ISA */ @@ -615,7 +689,7 @@ static void vt82c686b_write_config(PCIDevice *d, uint32_t addr, pci_default_write_config(d, addr, val, len); if (addr == 0x85) { /* BIT(1): enable or disable superio config io ports */ - via_superio_io_enable(s->via_sio, val & BIT(1)); + via_superio_io_enable(&s->via_sio, val & BIT(1)); } } @@ -639,13 +713,12 @@ static void vt82c686b_isa_reset(DeviceState *dev) pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */ } -static void vt82c686b_realize(PCIDevice *d, Error **errp) +static void vt82c686b_init(Object *obj) { - ViaISAState *s = VIA_ISA(d); + ViaISAState *s = VIA_ISA(obj); - via_isa_realize(d, errp); - s->via_sio = VIA_SUPERIO(isa_create_simple(s->isa_bus, - TYPE_VT82C686B_SUPERIO)); + object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT82C686B_SUPERIO); + object_initialize_child(obj, "pm", &s->pm, TYPE_VT82C686B_PM); } static void vt82c686b_class_init(ObjectClass *klass, void *data) @@ -653,7 +726,7 @@ static void vt82c686b_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->realize = vt82c686b_realize; + k->realize = via_isa_realize; k->config_write = vt82c686b_write_config; k->vendor_id = PCI_VENDOR_ID_VIA; k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA; @@ -670,6 +743,7 @@ static const TypeInfo vt82c686b_isa_info = { .name = TYPE_VT82C686B_ISA, .parent = TYPE_VIA_ISA, .instance_size = sizeof(ViaISAState), + .instance_init = vt82c686b_init, .class_init = vt82c686b_class_init, }; @@ -684,7 +758,7 @@ static void vt8231_write_config(PCIDevice *d, uint32_t addr, pci_default_write_config(d, addr, val, len); if (addr == 0x50) { /* BIT(2): enable or disable superio config io ports */ - via_superio_io_enable(s->via_sio, val & BIT(2)); + via_superio_io_enable(&s->via_sio, val & BIT(2)); } } @@ -703,13 +777,12 @@ static void vt8231_isa_reset(DeviceState *dev) pci_conf[0x6b] = 0x01; /* Fast IR I/O Base */ } -static void vt8231_realize(PCIDevice *d, Error **errp) +static void vt8231_init(Object *obj) { - ViaISAState *s = VIA_ISA(d); + ViaISAState *s = VIA_ISA(obj); - via_isa_realize(d, errp); - s->via_sio = VIA_SUPERIO(isa_create_simple(s->isa_bus, - TYPE_VT8231_SUPERIO)); + object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT8231_SUPERIO); + object_initialize_child(obj, "pm", &s->pm, TYPE_VT8231_PM); } static void vt8231_class_init(ObjectClass *klass, void *data) @@ -717,7 +790,7 @@ static void vt8231_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->realize = vt8231_realize; + k->realize = via_isa_realize; k->config_write = vt8231_write_config; k->vendor_id = PCI_VENDOR_ID_VIA; k->device_id = PCI_DEVICE_ID_VIA_8231_ISA; @@ -734,6 +807,7 @@ static const TypeInfo vt8231_isa_info = { .name = TYPE_VT8231_ISA, .parent = TYPE_VIA_ISA, .instance_size = sizeof(ViaISAState), + .instance_init = vt8231_init, .class_init = vt8231_class_init, }; diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig new file mode 100644 index 000000000000..eb112af9902d --- /dev/null +++ b/hw/loongarch/Kconfig @@ -0,0 +1,23 @@ +config LOONGARCH_VIRT + bool + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE + 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 + select LOONGARCH_EXTIOI + select LS7A_RTC + select SMBIOS + select ACPI_PCI + select ACPI_HW_REDUCED + select FW_CFG_DMA + select DIMM + select PFLASH_CFI01 diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c new file mode 100644 index 000000000000..c2b237736d52 --- /dev/null +++ b/hw/loongarch/acpi-build.c @@ -0,0 +1,567 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for generating ACPI tables and passing them to Guests + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/bitmap.h" +#include "hw/pci/pci.h" +#include "hw/core/cpu.h" +#include "target/loongarch/cpu.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/acpi.h" +#include "hw/nvram/fw_cfg.h" +#include "hw/acpi/bios-linker-loader.h" +#include "migration/vmstate.h" +#include "hw/mem/memory-device.h" +#include "sysemu/reset.h" + +/* Supported chipsets: */ +#include "hw/pci-host/ls7a.h" +#include "hw/loongarch/virt.h" +#include "hw/acpi/aml-build.h" + +#include "hw/acpi/utils.h" +#include "hw/acpi/pci.h" + +#include "qom/qom-qobject.h" + +#include "hw/acpi/generic_event_device.h" +#include "hw/pci-host/gpex.h" +#include "sysemu/tpm.h" +#include "hw/platform-bus.h" +#include "hw/acpi/aml-build.h" + +#define ACPI_BUILD_ALIGN_SIZE 0x1000 +#define ACPI_BUILD_TABLE_SIZE 0x20000 + +#ifdef DEBUG_ACPI_BUILD +#define ACPI_BUILD_DPRINTF(fmt, ...) \ + do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0) +#else +#define ACPI_BUILD_DPRINTF(fmt, ...) +#endif + +/* build FADT */ +static void init_common_fadt_data(AcpiFadtData *data) +{ + AcpiFadtData fadt = { + /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */ + .rev = 5, + .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) | + (1 << ACPI_FADT_F_RESET_REG_SUP)), + + /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */ + .sleep_ctl = { + .space_id = AML_AS_SYSTEM_MEMORY, + .bit_width = 8, + .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL, + }, + .sleep_sts = { + .space_id = AML_AS_SYSTEM_MEMORY, + .bit_width = 8, + .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS, + }, + + /* ACPI 5.0: 4.8.3.6 Reset Register */ + .reset_reg = { + .space_id = AML_AS_SYSTEM_MEMORY, + .bit_width = 8, + .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_RESET, + }, + .reset_val = ACPI_GED_RESET_VALUE, + }; + *data = fadt; +} + +static void acpi_align_size(GArray *blob, unsigned align) +{ + /* + * Align size to multiple of given size. This reduces the chance + * we need to change size in the future (breaking cross version migration). + */ + g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); +} + +/* build FACS */ +static void +build_facs(GArray *table_data) +{ + const char *sig = "FACS"; + const uint8_t reserved[40] = {}; + + g_array_append_vals(table_data, sig, 4); /* Signature */ + build_append_int_noprefix(table_data, 64, 4); /* Length */ + build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */ + build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */ + build_append_int_noprefix(table_data, 0, 4); /* Global Lock */ + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + g_array_append_vals(table_data, reserved, 40); /* Reserved */ +} + +/* build MADT */ +static void +build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + int i; + AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id, + .oem_table_id = lams->oem_table_id }; + + acpi_table_begin(&table, table_data); + + /* Local APIC Address */ + build_append_int_noprefix(table_data, 0, 4); + build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ + + for (i = 0; i < ms->smp.cpus; i++) { + /* Processor Core Interrupt Controller Structure */ + build_append_int_noprefix(table_data, 17, 1); /* Type */ + build_append_int_noprefix(table_data, 15, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, i + 1, 4); /* ACPI Processor ID */ + build_append_int_noprefix(table_data, i, 4); /* Core ID */ + build_append_int_noprefix(table_data, 1, 4); /* Flags */ + } + + /* Extend I/O Interrupt Controller Structure */ + build_append_int_noprefix(table_data, 20, 1); /* Type */ + build_append_int_noprefix(table_data, 13, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, 3, 1); /* Cascade */ + build_append_int_noprefix(table_data, 0, 1); /* Node */ + build_append_int_noprefix(table_data, 0xffff, 8); /* Node map */ + + /* MSI Interrupt Controller Structure */ + 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, 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 */ + + /* Bridge I/O Interrupt Controller Structure */ + 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, 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 */ + + acpi_table_end(linker, &table); +} + +/* build SRAT */ +static void +build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) +{ + uint64_t i; + LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); + MachineState *ms = MACHINE(lams); + AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id, + .oem_table_id = lams->oem_table_id }; + + acpi_table_begin(&table, table_data); + build_append_int_noprefix(table_data, 1, 4); /* Reserved */ + build_append_int_noprefix(table_data, 0, 8); /* Reserved */ + + for (i = 0; i < ms->smp.cpus; ++i) { + /* Processor Local APIC/SAPIC Affinity Structure */ + build_append_int_noprefix(table_data, 0, 1); /* Type */ + build_append_int_noprefix(table_data, 16, 1); /* Length */ + /* Proximity Domain [7:0] */ + build_append_int_noprefix(table_data, 0, 1); + build_append_int_noprefix(table_data, i, 1); /* APIC ID */ + /* Flags, Table 5-36 */ + build_append_int_noprefix(table_data, 1, 4); + build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */ + /* Proximity Domain [31:8] */ + build_append_int_noprefix(table_data, 0, 3); + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + } + + build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, + 0, MEM_AFFINITY_ENABLED); + + 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); +} + +typedef +struct AcpiBuildState { + /* Copy of table in RAM (for patching). */ + MemoryRegion *table_mr; + /* Is table patched? */ + uint8_t patched; + void *rsdp; + MemoryRegion *rsdp_mr; + MemoryRegion *linker_mr; +} AcpiBuildState; + +static void build_uart_device_aml(Aml *table) +{ + Aml *dev; + Aml *crs; + Aml *pkg0, *pkg1, *pkg2; + uint32_t uart_irq = VIRT_UART_IRQ; + + Aml *scope = aml_scope("_SB"); + dev = aml_device("COMA"); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1, + 0, VIRT_UART_SIZE)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &uart_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_int(0x05F5E100)); + aml_append(pkg0, aml_string("clock-frenquency")); + pkg1 = aml_package(0x1); + aml_append(pkg1, pkg0); + pkg2 = aml_package(0x2); + aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg2, pkg1); + aml_append(dev, aml_name_decl("_DSD", pkg2)); + aml_append(scope, dev); + 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); +} + +static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) +{ + Aml *dev, *crs; + + hwaddr flash_base = VIRT_FLASH_BASE; + hwaddr flash_size = VIRT_FLASH_SIZE; + + dev = aml_device("FLS0"); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(flash_base, flash_size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +#ifdef CONFIG_TPM +static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) +{ + PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); + hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; + SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find()); + MemoryRegion *sbdev_mr; + hwaddr tpm_base; + + if (!sbdev) { + return; + } + + tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); + assert(tpm_base != -1); + + tpm_base += pbus_base; + + sbdev_mr = sysbus_mmio_get_region(sbdev, 0); + + Aml *dev = aml_device("TPM0"); + aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); + aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, + aml_memory32_fixed(tpm_base, + (uint32_t)memory_region_size(sbdev_mr), + AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} +#endif + +/* build DSDT */ +static void +build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) +{ + 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_uart_device_aml(dsdt); + build_pci_device_aml(dsdt, lams); + build_la_ged_aml(dsdt, machine); + build_flash_aml(dsdt, lams); +#ifdef CONFIG_TPM + acpi_dsdt_add_tpm(dsdt, lams); +#endif + /* System State Package */ + scope = aml_scope("\\"); + pkg = aml_package(4); + aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5)); + aml_append(pkg, aml_int(0)); /* ignored */ + aml_append(pkg, aml_int(0)); /* reserved */ + aml_append(pkg, aml_int(0)); /* reserved */ + aml_append(scope, aml_name_decl("_S5", pkg)); + aml_append(dsdt, scope); + /* Copy AML table into ACPI tables blob and patch header there */ + g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); + acpi_table_end(linker, &table); + free_aml_allocator(); +} + +static void acpi_build(AcpiBuildTables *tables, MachineState *machine) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); + GArray *table_offsets; + AcpiFadtData fadt_data; + unsigned facs, rsdt, dsdt; + uint8_t *u; + GArray *tables_blob = tables->table_data; + + init_common_fadt_data(&fadt_data); + + table_offsets = g_array_new(false, true, sizeof(uint32_t)); + ACPI_BUILD_DPRINTF("init ACPI tables\n"); + + bios_linker_loader_alloc(tables->linker, + ACPI_BUILD_TABLE_FILE, tables_blob, + 64, false); + + /* + * FACS is pointed to by FADT. + * We place it first since it's the only table that has alignment + * requirements. + */ + facs = tables_blob->len; + build_facs(tables_blob); + + /* DSDT is pointed to by FADT */ + dsdt = tables_blob->len; + build_dsdt(tables_blob, tables->linker, machine); + + /* ACPI tables pointed to by RSDT */ + 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); + + acpi_add_table(table_offsets, tables_blob); + build_madt(tables_blob, tables->linker, lams); + + acpi_add_table(table_offsets, tables_blob); + build_srat(tables_blob, tables->linker, machine); + + acpi_add_table(table_offsets, tables_blob); + { + AcpiMcfgInfo mcfg = { + .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); + } + +#ifdef CONFIG_TPM + /* TPM info */ + if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { + acpi_add_table(table_offsets, tables_blob); + build_tpm2(tables_blob, tables->linker, + tables->tcpalog, lams->oem_id, + lams->oem_table_id); + } +#endif + /* Add tables supplied by user (if any) */ + for (u = acpi_table_first(); u; u = acpi_table_next(u)) { + unsigned len = acpi_table_len(u); + + acpi_add_table(table_offsets, tables_blob); + g_array_append_vals(tables_blob, u, len); + } + + /* RSDT is pointed to by RSDP */ + rsdt = tables_blob->len; + build_rsdt(tables_blob, tables->linker, table_offsets, + lams->oem_id, lams->oem_table_id); + + /* RSDP is in FSEG memory, so allocate it separately */ + { + AcpiRsdpData rsdp_data = { + .revision = 0, + .oem_id = lams->oem_id, + .xsdt_tbl_offset = NULL, + .rsdt_tbl_offset = &rsdt, + }; + build_rsdp(tables->rsdp, tables->linker, &rsdp_data); + } + + /* + * The align size is 128, warn if 64k is not enough therefore + * the align size could be resized. + */ + if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { + warn_report("ACPI table size %u exceeds %d bytes," + " migration may not work", + tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); + error_printf("Try removing CPUs, NUMA nodes, memory slots" + " or PCI bridges."); + } + + acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); + + /* Cleanup memory that's no longer used. */ + g_array_free(table_offsets, true); +} + +static void acpi_ram_update(MemoryRegion *mr, GArray *data) +{ + uint32_t size = acpi_data_len(data); + + /* + * Make sure RAM size is correct - in case it got changed + * e.g. by migration + */ + memory_region_ram_resize(mr, size, &error_abort); + + memcpy(memory_region_get_ram_ptr(mr), data->data, size); + memory_region_set_dirty(mr, 0, size); +} + +static void acpi_build_update(void *build_opaque) +{ + AcpiBuildState *build_state = build_opaque; + AcpiBuildTables tables; + + /* No state to update or already patched? Nothing to do. */ + if (!build_state || build_state->patched) { + return; + } + build_state->patched = 1; + + acpi_build_tables_init(&tables); + + acpi_build(&tables, MACHINE(qdev_get_machine())); + + acpi_ram_update(build_state->table_mr, tables.table_data); + acpi_ram_update(build_state->rsdp_mr, tables.rsdp); + acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); + + acpi_build_tables_cleanup(&tables, true); +} + +static void acpi_build_reset(void *build_opaque) +{ + AcpiBuildState *build_state = build_opaque; + build_state->patched = 0; +} + +static const VMStateDescription vmstate_acpi_build = { + .name = "acpi_build", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(patched, AcpiBuildState), + VMSTATE_END_OF_LIST() + }, +}; + +void loongarch_acpi_setup(LoongArchMachineState *lams) +{ + AcpiBuildTables tables; + AcpiBuildState *build_state; + + if (!lams->fw_cfg) { + ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); + return; + } + + if (!loongarch_is_acpi_enabled(lams)) { + ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); + return; + } + + build_state = g_malloc0(sizeof *build_state); + + acpi_build_tables_init(&tables); + acpi_build(&tables, MACHINE(lams)); + + /* Now expose it all to Guest */ + build_state->table_mr = acpi_add_rom_blob(acpi_build_update, + build_state, tables.table_data, + ACPI_BUILD_TABLE_FILE); + assert(build_state->table_mr != NULL); + + build_state->linker_mr = + acpi_add_rom_blob(acpi_build_update, build_state, + tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE); + + build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update, + build_state, tables.rsdp, + ACPI_BUILD_RSDP_FILE); + + qemu_register_reset(acpi_build_reset, build_state); + acpi_build_reset(build_state); + vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); + + /* + * Cleanup tables but don't free the memory: we track it + * in build_state. + */ + acpi_build_tables_cleanup(&tables, false); +} diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c new file mode 100644 index 000000000000..f15a17416c48 --- /dev/null +++ b/hw/loongarch/fw_cfg.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU fw_cfg helpers (LoongArch specific) + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/loongarch/fw_cfg.h" +#include "hw/loongarch/virt.h" +#include "hw/nvram/fw_cfg.h" +#include "sysemu/sysemu.h" + +static void fw_cfg_boot_set(void *opaque, const char *boot_device, + Error **errp) +{ + fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); +} + +FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) +{ + FWCfgState *fw_cfg; + 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, + 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); + + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); + return fw_cfg; +} diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h new file mode 100644 index 000000000000..7c0de4db4ad4 --- /dev/null +++ b/hw/loongarch/fw_cfg.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU fw_cfg helpers (LoongArch specific) + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LOONGARCH_FW_CFG_H +#define HW_LOONGARCH_FW_CFG_H + +#include "hw/boards.h" +#include "hw/nvram/fw_cfg.h" + +FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms); +#endif diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build new file mode 100644 index 000000000000..c0421502abab --- /dev/null +++ b/hw/loongarch/meson.build @@ -0,0 +1,8 @@ +loongarch_ss = ss.source_set() +loongarch_ss.add(files( + 'fw_cfg.c', +)) +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/virt.c b/hw/loongarch/virt.c new file mode 100644 index 000000000000..66be9250684e --- /dev/null +++ b/hw/loongarch/virt.c @@ -0,0 +1,1052 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU loongson 3a5000 develop board emulation + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/datadir.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/runstate.h" +#include "sysemu/reset.h" +#include "sysemu/rtc.h" +#include "hw/loongarch/virt.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "net/net.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/intc/loongarch_ipi.h" +#include "hw/intc/loongarch_extioi.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/intc/loongarch_pch_msi.h" +#include "hw/pci-host/ls7a.h" +#include "hw/pci-host/gpex.h" +#include "hw/misc/unimp.h" +#include "hw/loongarch/fw_cfg.h" +#include "target/loongarch/cpu.h" +#include "hw/firmware/smbios.h" +#include "hw/acpi/aml-build.h" +#include "qapi/qapi-visit-common.h" +#include "hw/acpi/generic_event_device.h" +#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" +#include "sysemu/tpm.h" +#include "sysemu/block-backend.h" +#include "hw/block/flash.h" + +static void virt_flash_create(LoongArchMachineState *lams) +{ + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); + + qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); + qdev_prop_set_uint8(dev, "width", 4); + qdev_prop_set_uint8(dev, "device-width", 2); + qdev_prop_set_bit(dev, "big-endian", false); + qdev_prop_set_uint16(dev, "id0", 0x89); + qdev_prop_set_uint16(dev, "id1", 0x18); + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_string(dev, "name", "virt.flash"); + object_property_add_child(OBJECT(lams), "virt.flash", OBJECT(dev)); + object_property_add_alias(OBJECT(lams), "pflash", + OBJECT(dev), "drive"); + + lams->flash = PFLASH_CFI01(dev); +} + +static void virt_flash_map(LoongArchMachineState *lams, + MemoryRegion *sysmem) +{ + PFlashCFI01 *flash = lams->flash; + DeviceState *dev = DEVICE(flash); + hwaddr base = VIRT_FLASH_BASE; + hwaddr size = VIRT_FLASH_SIZE; + + assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); + assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); + + qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + memory_region_add_subregion(sysmem, base, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); + +} + +static void fdt_add_flash_node(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + char *nodename; + + hwaddr flash_base = VIRT_FLASH_BASE; + hwaddr flash_size = VIRT_FLASH_SIZE; + + nodename = g_strdup_printf("/flash@%" PRIx64, flash_base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", + 2, flash_base, 2, flash_size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4); + g_free(nodename); +} + +static void fdt_add_rtc_node(LoongArchMachineState *lams) +{ + char *nodename; + hwaddr base = VIRT_RTC_REG_BASE; + hwaddr size = VIRT_RTC_LEN; + MachineState *ms = MACHINE(lams); + + nodename = g_strdup_printf("/rtc@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "loongson,ls7a-rtc"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); + g_free(nodename); +} + +static void fdt_add_uart_node(LoongArchMachineState *lams) +{ + char *nodename; + hwaddr base = VIRT_UART_BASE; + hwaddr size = VIRT_UART_SIZE; + MachineState *ms = MACHINE(lams); + + nodename = g_strdup_printf("/serial@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a"); + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); + g_free(nodename); +} + +static void create_fdt(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + + ms->fdt = create_device_tree(&lams->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + /* Header */ + qemu_fdt_setprop_string(ms->fdt, "/", "compatible", + "linux,dummy-loongson3"); + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + qemu_fdt_add_subnode(ms->fdt, "/chosen"); +} + +static void fdt_add_cpu_nodes(const LoongArchMachineState *lams) +{ + int num; + const MachineState *ms = MACHINE(lams); + int smp_cpus = ms->smp.cpus; + + qemu_fdt_add_subnode(ms->fdt, "/cpus"); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + + /* cpu nodes */ + for (num = smp_cpus - 1; num >= 0; num--) { + char *nodename = g_strdup_printf("/cpus/cpu@%d", num); + LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num)); + + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", + cpu->dtb_compatible); + qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num); + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(ms->fdt)); + g_free(nodename); + } + + /*cpu map */ + qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); + + for (num = smp_cpus - 1; num >= 0; num--) { + char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num); + char *map_path; + + if (ms->smp.threads > 1) { + map_path = g_strdup_printf( + "/cpus/cpu-map/socket%d/core%d/thread%d", + num / (ms->smp.cores * ms->smp.threads), + (num / ms->smp.threads) % ms->smp.cores, + num % ms->smp.threads); + } else { + map_path = g_strdup_printf( + "/cpus/cpu-map/socket%d/core%d", + num / ms->smp.cores, + num % ms->smp.cores); + } + qemu_fdt_add_path(ms->fdt, map_path); + qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path); + + g_free(map_path); + g_free(cpu_path); + } +} + +static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) +{ + char *nodename; + hwaddr base = VIRT_FWCFG_BASE; + const MachineState *ms = MACHINE(lams); + + nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "qemu,fw-cfg-mmio"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", + 2, base, 2, 0x18); + qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); + g_free(nodename); +} + +static void fdt_add_pcie_node(const LoongArchMachineState *lams) +{ + char *nodename; + 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); + + nodename = g_strdup_printf("/pcie@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "pci-host-ecam-generic"); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3); + 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(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, VIRT_PCI_IO_OFFSET, + 2, base_pio, 2, size_pio, + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, + 2, base_mmio, 2, size_mmio); + g_free(nodename); +} + +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 +#define PM_CTRL 0x10 + +static void virt_build_smbios(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + MachineClass *mc = MACHINE_GET_CLASS(lams); + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; + + if (!lams->fw_cfg) { + return; + } + + smbios_set_defaults("QEMU", product, mc->name, false, + true, SMBIOS_ENTRY_POINT_TYPE_64); + + smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, &error_fatal); + + if (smbios_anchor) { + fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } +} + +static void virt_machine_done(Notifier *notifier, void *data) +{ + LoongArchMachineState *lams = container_of(notifier, + LoongArchMachineState, machine_done); + virt_build_smbios(lams); + loongarch_acpi_setup(lams); +} + +struct memmap_entry { + uint64_t address; + uint64_t length; + uint32_t type; + uint32_t reserved; +}; + +static struct memmap_entry *memmap_table; +static unsigned memmap_entries; + +static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) +{ + /* Ensure there are no duplicate entries. */ + for (unsigned i = 0; i < memmap_entries; i++) { + assert(memmap_table[i].address != address); + } + + memmap_table = g_renew(struct memmap_entry, memmap_table, + memmap_entries + 1); + memmap_table[memmap_entries].address = cpu_to_le64(address); + memmap_table[memmap_entries].length = cpu_to_le64(length); + memmap_table[memmap_entries].type = cpu_to_le32(type); + memmap_table[memmap_entries].reserved = 0; + memmap_entries++; +} + +/* + * This is a placeholder for missing ACPI, + * and will eventually be replaced. + */ +static uint64_t loongarch_virt_pm_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void loongarch_virt_pm_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + if (addr != PM_CTRL) { + return; + } + + switch (val) { + case 0x00: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + case 0xff: + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + return; + default: + return; + } +} + +static const MemoryRegionOps loongarch_virt_pm_ops = { + .read = loongarch_virt_pm_read, + .write = loongarch_virt_pm_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1 + } +}; + +static struct _loaderparams { + uint64_t ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + +static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) +{ + return addr & 0x1fffffffll; +} + +static int64_t load_kernel_info(void) +{ + uint64_t kernel_entry, kernel_low, kernel_high; + ssize_t kernel_size; + + kernel_size = load_elf(loaderparams.kernel_filename, NULL, + cpu_loongarch_virt_to_phys, NULL, + &kernel_entry, &kernel_low, + &kernel_high, NULL, 0, + EM_LOONGARCH, 1, 0); + + if (kernel_size < 0) { + error_report("could not load kernel '%s': %s", + loaderparams.kernel_filename, + load_elf_strerror(kernel_size)); + exit(1); + } + return kernel_entry; +} + +static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState *lams) +{ + DeviceState *dev; + MachineState *ms = MACHINE(lams); + uint32_t event = ACPI_GED_PWR_DOWN_EVT; + + if (ms->ram_slots) { + event |= ACPI_GED_MEM_HOTPLUG_EVT; + } + dev = qdev_new(TYPE_ACPI_GED); + qdev_prop_set_uint32(dev, "ged-event", event); + + /* ged event */ + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, VIRT_GED_EVT_ADDR); + /* memory hotplug */ + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, VIRT_GED_MEM_ADDR); + /* ged regs used for reset and power down */ + 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, 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; + SysBusDevice *d; + PCIBus *pci_bus; + MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg; + MemoryRegion *mmio_alias, *mmio_reg, *pm_mem; + int i; + + gpex_dev = qdev_new(TYPE_GPEX_HOST); + 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, 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, 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, + 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++) { + sysbus_connect_irq(d, i, + qdev_get_gpio_in(pch_pic, 16 + i)); + gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); + } + + serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0, + qdev_get_gpio_in(pch_pic, + VIRT_UART_IRQ - PCH_PIC_IRQ_OFFSET), + 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); + fdt_add_uart_node(lams); + + /* Network init */ + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); + } + + /* + * 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", VIRT_RTC_REG_BASE, + qdev_get_gpio_in(pch_pic, + VIRT_RTC_IRQ - PCH_PIC_IRQ_OFFSET)); + fdt_add_rtc_node(lams); + + pm_mem = g_new(MemoryRegion, 1); + memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops, + NULL, "loongarch_virt_pm", PM_SIZE); + 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) +{ + MachineState *ms = MACHINE(lams); + DeviceState *pch_pic, *pch_msi, *cpudev; + DeviceState *ipi, *extioi; + SysBusDevice *d; + LoongArchCPU *lacpu; + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i, start, num; + + ipi = qdev_new(TYPE_LOONGARCH_IPI); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); + sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); + + /* + * The connection of interrupts: + * +-----+ +---------+ +-------+ + * | IPI |--> | CPUINTC | <-- | Timer | + * +-----+ +---------+ +-------+ + * ^ + * | + * +---------+ + * | EIOINTC | + * +---------+ + * ^ ^ + * | | + * +---------+ +---------+ + * | PCH-PIC | | PCH-MSI | + * +---------+ +---------+ + * ^ ^ ^ + * | | | + * +--------+ +---------+ +---------+ + * | UARTs | | Devices | | Devices | + * +--------+ +---------+ +---------+ + */ + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpu_state = qemu_get_cpu(cpu); + cpudev = DEVICE(cpu_state); + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); + + /* connect ipi irq to cpu irq */ + qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); + /* IPI iocsr memory region */ + memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), + cpu * 2)); + memory_region_add_subregion(&env->system_iocsr, MAIL_SEND_ADDR, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), + cpu * 2 + 1)); + /* extioi iocsr memory region */ + memory_region_add_subregion(&env->system_iocsr, APIC_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), + cpu)); + } + + /* + * connect ext irq to the cpu irq + * cpu_pin[9:2] <= intc_pin[7:0] + */ + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpudev = DEVICE(qemu_get_cpu(cpu)); + for (pin = 0; pin < LS3A_INTC_IP; pin++) { + qdev_connect_gpio_out(extioi, (cpu * 8 + pin), + qdev_get_gpio_in(cpudev, pin + 2)); + } + } + + pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); + num = VIRT_PCH_PIC_IRQ_NUM; + qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); + d = SYS_BUS_DEVICE(pch_pic); + sysbus_realize_and_unref(d, &error_fatal); + memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, + sysbus_mmio_get_region(d, 0)); + memory_region_add_subregion(get_system_memory(), + VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, + sysbus_mmio_get_region(d, 1)); + memory_region_add_subregion(get_system_memory(), + VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, + sysbus_mmio_get_region(d, 2)); + + /* Connect pch_pic irqs to extioi */ + for (int i = 0; i < num; i++) { + qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); + } + + pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); + start = num; + num = EXTIOI_IRQS - start; + qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); + qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); + d = SYS_BUS_DEVICE(pch_msi); + sysbus_realize_and_unref(d, &error_fatal); + sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); + for (i = 0; i < num; i++) { + /* Connect pch_msi irqs to extioi */ + qdev_connect_gpio_out(DEVICE(d), i, + qdev_get_gpio_in(extioi, i + start)); + } + + loongarch_devices_init(pch_pic, lams); +} + +static void loongarch_firmware_init(LoongArchMachineState *lams) +{ + char *filename = MACHINE(lams)->firmware; + char *bios_name = NULL; + int bios_size; + + lams->bios_loaded = false; + + virt_flash_map(lams, get_system_memory()); + + if (filename) { + bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename); + if (!bios_name) { + error_report("Could not find ROM image '%s'", filename); + exit(1); + } + + bios_size = load_image_targphys(bios_name, VIRT_BIOS_BASE, VIRT_BIOS_SIZE); + if (bios_size < 0) { + error_report("Could not load ROM image '%s'", bios_name); + exit(1); + } + + g_free(bios_name); + + memory_region_init_ram(&lams->bios, NULL, "loongarch.bios", + VIRT_BIOS_SIZE, &error_fatal); + memory_region_set_readonly(&lams->bios, true); + memory_region_add_subregion(get_system_memory(), VIRT_BIOS_BASE, &lams->bios); + lams->bios_loaded = true; + } + +} + +static void reset_load_elf(void *opaque) +{ + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + if (env->load_elf) { + cpu_set_pc(CPU(cpu), env->elf_address); + } +} + +static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg) +{ + /* + * Expose the kernel, the command line, and the initrd in fw_cfg. + * We don't process them here at all, it's all left to the + * firmware. + */ + load_image_to_fw_cfg(fw_cfg, + FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, + loaderparams.kernel_filename, + false); + + if (loaderparams.initrd_filename) { + load_image_to_fw_cfg(fw_cfg, + FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, + loaderparams.initrd_filename, false); + } + + if (loaderparams.kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, + strlen(loaderparams.kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, + loaderparams.kernel_cmdline); + } +} + +static void loongarch_firmware_boot(LoongArchMachineState *lams) +{ + fw_cfg_add_kernel_info(lams->fw_cfg); +} + +static void loongarch_direct_kernel_boot(LoongArchMachineState *lams) +{ + MachineState *machine = MACHINE(lams); + int64_t kernel_addr = 0; + LoongArchCPU *lacpu; + int i; + + kernel_addr = load_kernel_info(); + if (!machine->firmware) { + for (i = 0; i < machine->smp.cpus; i++) { + lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); + lacpu->env.load_elf = true; + lacpu->env.elf_address = kernel_addr; + } + } +} + +static void loongarch_init(MachineState *machine) +{ + LoongArchCPU *lacpu; + const char *cpu_model = machine->cpu_type; + ram_addr_t offset = 0; + ram_addr_t ram_size = machine->ram_size; + uint64_t highram_size = 0; + MemoryRegion *address_space_mem = get_system_memory(); + LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); + int i; + hwaddr fdt_base; + + if (!cpu_model) { + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); + } + + if (!strstr(cpu_model, "la464")) { + error_report("LoongArch/TCG needs cpu type la464"); + exit(1); + } + + if (ram_size < 1 * GiB) { + error_report("ram_size must be greater than 1G."); + exit(1); + } + create_fdt(lams); + /* Init CPUs */ + for (i = 0; i < machine->smp.cpus; i++) { + cpu_create(machine->cpu_type); + } + fdt_add_cpu_nodes(lams); + /* Add memory region */ + memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram", + machine->ram, 0, 256 * MiB); + memory_region_add_subregion(address_space_mem, offset, &lams->lowmem); + offset += 256 * MiB; + memmap_add_entry(0, 256 * MiB, 1); + highram_size = ram_size - 256 * MiB; + memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem", + 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, 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); + + /* fw_cfg init */ + lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine); + rom_set_fw(lams->fw_cfg); + if (lams->fw_cfg != NULL) { + fw_cfg_add_file(lams->fw_cfg, "etc/memmap", + memmap_table, + sizeof(struct memmap_entry) * (memmap_entries)); + } + fdt_add_fw_cfg_node(lams); + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = machine->kernel_filename; + loaderparams.kernel_cmdline = machine->kernel_cmdline; + loaderparams.initrd_filename = machine->initrd_filename; + /* load the kernel. */ + if (loaderparams.kernel_filename) { + if (lams->bios_loaded) { + loongarch_firmware_boot(lams); + } else { + loongarch_direct_kernel_boot(lams); + } + } + fdt_add_flash_node(lams); + /* register reset function */ + for (i = 0; i < machine->smp.cpus; i++) { + lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); + qemu_register_reset(reset_load_elf, lacpu); + } + /* 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); + /* + * Since lowmem region starts from 0 and Linux kernel legacy start address + * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer + * access. FDT size limit with 1 MiB. + * Put the FDT into the memory map as a ROM image: this will ensure + * the FDT is copied again upon reset, even if addr points into RAM. + */ + fdt_base = 1 * MiB; + qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size); + rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, fdt_base); +} + +bool loongarch_is_acpi_enabled(LoongArchMachineState *lams) +{ + if (lams->acpi == ON_OFF_AUTO_OFF) { + return false; + } + return true; +} + +static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); + OnOffAuto acpi = lams->acpi; + + visit_type_OnOffAuto(v, name, &acpi, errp); +} + +static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); + + visit_type_OnOffAuto(v, name, &lams->acpi, errp); +} + +static void loongarch_machine_initfn(Object *obj) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); + + lams->acpi = ON_OFF_AUTO_AUTO; + lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); + lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); + virt_flash_create(lams); +} + +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; + mc->default_ram_size = 1 * GiB; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); + mc->default_ram_id = "loongarch.ram"; + mc->max_cpus = LOONGARCH_MAX_VCPUS; + mc->is_default = 1; + mc->default_kernel_irqchip_split = false; + 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); +#ifdef CONFIG_TPM + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); +#endif +} + +static const TypeInfo loongarch_machine_types[] = { + { + .name = TYPE_LOONGARCH_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(LoongArchMachineState), + .class_init = loongarch_class_init, + .instance_init = loongarch_machine_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, + } +}; + +DEFINE_TYPES(loongarch_machine_types) diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h index adbf0c5521e5..a3d37e3c8094 100644 --- a/hw/m68k/bootinfo.h +++ b/hw/m68k/bootinfo.h @@ -12,48 +12,66 @@ #ifndef HW_M68K_BOOTINFO_H #define HW_M68K_BOOTINFO_H -#define BOOTINFO0(as, base, id) \ +#define BOOTINFO0(base, id) \ do { \ - stw_phys(as, base, id); \ + stw_p(base, id); \ base += 2; \ - stw_phys(as, base, sizeof(struct bi_record)); \ + stw_p(base, sizeof(struct bi_record)); \ base += 2; \ } while (0) -#define BOOTINFO1(as, base, id, value) \ +#define BOOTINFO1(base, id, value) \ do { \ - stw_phys(as, base, id); \ + stw_p(base, id); \ base += 2; \ - stw_phys(as, base, sizeof(struct bi_record) + 4); \ + stw_p(base, sizeof(struct bi_record) + 4); \ base += 2; \ - stl_phys(as, base, value); \ + stl_p(base, value); \ base += 4; \ } while (0) -#define BOOTINFO2(as, base, id, value1, value2) \ +#define BOOTINFO2(base, id, value1, value2) \ do { \ - stw_phys(as, base, id); \ + stw_p(base, id); \ base += 2; \ - stw_phys(as, base, sizeof(struct bi_record) + 8); \ + stw_p(base, sizeof(struct bi_record) + 8); \ base += 2; \ - stl_phys(as, base, value1); \ + stl_p(base, value1); \ base += 4; \ - stl_phys(as, base, value2); \ + stl_p(base, value2); \ base += 4; \ } while (0) -#define BOOTINFOSTR(as, base, id, string) \ +#define BOOTINFOSTR(base, id, string) \ do { \ int i; \ - stw_phys(as, base, id); \ + stw_p(base, id); \ base += 2; \ - stw_phys(as, base, \ - (sizeof(struct bi_record) + strlen(string) + 2) & ~1); \ + stw_p(base, \ + (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_p(base++, string[i]); \ } \ - stb_phys(as, base++, 0); \ - base = (parameters_base + 1) & ~1; \ + stb_p(base++, 0); \ + base = QEMU_ALIGN_PTR_UP(base, 4); \ + } while (0) + +#define BOOTINFODATA(base, id, data, len) \ + do { \ + int i; \ + stw_p(base, id); \ + base += 2; \ + stw_p(base, \ + (sizeof(struct bi_record) + len + \ + 2 /* length field */ + 3 /* padding */) & ~3); \ + base += 2; \ + stw_p(base, len); \ + base += 2; \ + for (i = 0; i < len; ++i) { \ + stb_p(base++, data[i]); \ + } \ + base = QEMU_ALIGN_PTR_UP(base, 4); \ } while (0) #endif diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index 6d93d761a5e2..2ab1b4f0593b 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -152,7 +152,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) m5206_timer_state *s; s = g_new0(m5206_timer_state, 1); - s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_LEGACY); s->irq = irq; m5206_timer_reset(s); return s; diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 93812ee206ea..be1033f84f87 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -11,7 +11,6 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #include "hw/irq.h" @@ -198,7 +197,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) /* Timers. */ for (i = 0; i < 2; i++) { s = g_new0(m5208_timer_state, 1); - s->timer = ptimer_init(m5208_timer_trigger, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(m5208_timer_trigger, s, PTIMER_POLICY_LEGACY); memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s, "m5208-timer", 0x00004000); memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i, diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 66ca5c0df6ef..9d52ca661317 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -22,8 +22,8 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu-common.h" #include "qemu/datadir.h" +#include "qemu/guest-random.h" #include "sysemu/sysemu.h" #include "cpu.h" #include "hw/boards.h" @@ -331,6 +331,13 @@ static void main_cpu_reset(void *opaque) cpu->env.pc = ldl_phys(cs->as, 4); } +static void rerandomize_rng_seed(void *opaque) +{ + struct bi_record *rng_seed = opaque; + qemu_guest_getrandom_nofail((void *)rng_seed->data + 2, + be16_to_cpu(*(uint16_t *)rng_seed->data)); +} + static uint8_t fake_mac_rom[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -386,6 +393,7 @@ static void q800_init(MachineState *machine) NubusBus *nubus; DeviceState *glue; DriveInfo *dinfo; + uint8_t rng_seed[32]; linux_boot = (kernel_filename != NULL); @@ -597,6 +605,14 @@ static void q800_init(MachineState *machine) cs = CPU(cpu); if (linux_boot) { uint64_t high; + void *param_blob, *param_ptr, *param_rng_seed; + + if (kernel_cmdline) { + param_blob = g_malloc(strlen(kernel_cmdline) + 1024); + } else { + param_blob = g_malloc(1024); + } + kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry, NULL, &high, NULL, 1, EM_68K, 0, 0); @@ -606,23 +622,24 @@ static void q800_init(MachineState *machine) } stl_phys(cs->as, 4, elf_entry); /* reset initial PC */ parameters_base = (high + 1) & ~1; - - BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_MAC); - BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, FPU_68040); - BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, MMU_68040); - BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, CPU_68040); - BOOTINFO1(cs->as, parameters_base, BI_MAC_CPUID, CPUB_68040); - BOOTINFO1(cs->as, parameters_base, BI_MAC_MODEL, MAC_MODEL_Q800); - BOOTINFO1(cs->as, parameters_base, + param_ptr = param_blob; + + BOOTINFO1(param_ptr, BI_MACHTYPE, MACH_MAC); + BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68040); + BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68040); + BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68040); + BOOTINFO1(param_ptr, BI_MAC_CPUID, CPUB_68040); + BOOTINFO1(param_ptr, BI_MAC_MODEL, MAC_MODEL_Q800); + BOOTINFO1(param_ptr, BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */ - BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size); - BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR, + BOOTINFO2(param_ptr, BI_MEMCHUNK, 0, ram_size); + BOOTINFO1(param_ptr, BI_MAC_VADDR, VIDEO_BASE + macfb_mode->offset); - BOOTINFO1(cs->as, parameters_base, BI_MAC_VDEPTH, graphic_depth); - BOOTINFO1(cs->as, parameters_base, BI_MAC_VDIM, + BOOTINFO1(param_ptr, BI_MAC_VDEPTH, graphic_depth); + BOOTINFO1(param_ptr, BI_MAC_VDIM, (graphic_height << 16) | graphic_width); - BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW, macfb_mode->stride); - BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE); + BOOTINFO1(param_ptr, BI_MAC_VROW, macfb_mode->stride); + BOOTINFO1(param_ptr, BI_MAC_SCCBASE, SCC_BASE); rom = g_malloc(sizeof(*rom)); memory_region_init_ram_ptr(rom, NULL, "m68k_fake_mac.rom", @@ -631,10 +648,16 @@ static void q800_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom); if (kernel_cmdline) { - BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE, + BOOTINFOSTR(param_ptr, BI_COMMAND_LINE, kernel_cmdline); } + /* Pass seed to RNG. */ + param_rng_seed = param_ptr; + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + BOOTINFODATA(param_ptr, BI_RNG_SEED, + rng_seed, sizeof(rng_seed)); + /* load initrd */ if (initrd_filename) { initrd_size = get_image_size(initrd_filename); @@ -647,13 +670,20 @@ static void q800_init(MachineState *machine) initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); - BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base, + BOOTINFO2(param_ptr, BI_RAMDISK, initrd_base, initrd_size); } else { initrd_base = 0; initrd_size = 0; } - BOOTINFO0(cs->as, parameters_base, BI_LAST); + BOOTINFO0(param_ptr, BI_LAST); + rom_add_blob_fixed_as("bootinfo", param_blob, param_ptr - param_blob, + parameters_base, cs->as); + qemu_register_reset_nosnapshotload(rerandomize_rng_seed, + rom_ptr_for_as(cs->as, parameters_base, + param_ptr - param_blob) + + (param_rng_seed - param_blob)); + g_free(param_blob); } else { uint8_t *ptr; /* allocate and load BIOS */ @@ -687,6 +717,21 @@ static void q800_init(MachineState *machine) } } +static GlobalProperty hw_compat_q800[] = { + { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-hd", "vendor", " SEAGATE" }, + { "scsi-hd", "product", " ST225N" }, + { "scsi-hd", "ver", "1.0 " }, + { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, + { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, + { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-cd", "quirk_mode_page_truncated", "on"}, + { "scsi-cd", "vendor", "MATSHITA" }, + { "scsi-cd", "product", "CD-ROM CR-8005" }, + { "scsi-cd", "ver", "1.0k" }, +}; +static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); + static void q800_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -696,6 +741,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->max_cpus = 1; mc->block_default_type = IF_SCSI; mc->default_ram_id = "m68k_mac.ram"; + compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len); } static const TypeInfo q800_machine_typeinfo = { diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 8e630282e02c..4cb5beef1a0c 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu-common.h" +#include "qemu/guest-random.h" #include "sysemu/sysemu.h" #include "cpu.h" #include "hw/boards.h" @@ -102,6 +102,13 @@ static void main_cpu_reset(void *opaque) cpu->env.pc = reset_info->initial_pc; } +static void rerandomize_rng_seed(void *opaque) +{ + struct bi_record *rng_seed = opaque; + qemu_guest_getrandom_nofail((void *)rng_seed->data + 2, + be16_to_cpu(*(uint16_t *)rng_seed->data)); +} + static void virt_init(MachineState *machine) { M68kCPU *cpu = NULL; @@ -121,6 +128,7 @@ static void virt_init(MachineState *machine) hwaddr io_base; int i; ResetInfo *reset_info; + uint8_t rng_seed[32]; if (ram_size > 3399672 * KiB) { /* @@ -172,6 +180,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); @@ -210,6 +219,13 @@ static void virt_init(MachineState *machine) if (kernel_filename) { CPUState *cs = CPU(cpu); uint64_t high; + void *param_blob, *param_ptr, *param_rng_seed; + + if (kernel_cmdline) { + param_blob = g_malloc(strlen(kernel_cmdline) + 1024); + } else { + param_blob = g_malloc(1024); + } kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry, NULL, &high, NULL, 1, @@ -220,32 +236,39 @@ static void virt_init(MachineState *machine) } reset_info->initial_pc = elf_entry; parameters_base = (high + 1) & ~1; + param_ptr = param_blob; - BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_VIRT); - BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, FPU_68040); - BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, MMU_68040); - BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, CPU_68040); - BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size); + BOOTINFO1(param_ptr, BI_MACHTYPE, MACH_VIRT); + BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68040); + BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68040); + BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68040); + BOOTINFO2(param_ptr, BI_MEMCHUNK, 0, ram_size); - BOOTINFO1(cs->as, parameters_base, BI_VIRT_QEMU_VERSION, + BOOTINFO1(param_ptr, BI_VIRT_QEMU_VERSION, ((QEMU_VERSION_MAJOR << 24) | (QEMU_VERSION_MINOR << 16) | (QEMU_VERSION_MICRO << 8))); - BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_PIC_BASE, + BOOTINFO2(param_ptr, BI_VIRT_GF_PIC_BASE, VIRT_GF_PIC_MMIO_BASE, VIRT_GF_PIC_IRQ_BASE); - BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_RTC_BASE, + BOOTINFO2(param_ptr, BI_VIRT_GF_RTC_BASE, VIRT_GF_RTC_MMIO_BASE, VIRT_GF_RTC_IRQ_BASE); - BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_TTY_BASE, + BOOTINFO2(param_ptr, BI_VIRT_GF_TTY_BASE, VIRT_GF_TTY_MMIO_BASE, VIRT_GF_TTY_IRQ_BASE); - BOOTINFO2(cs->as, parameters_base, BI_VIRT_CTRL_BASE, + BOOTINFO2(param_ptr, BI_VIRT_CTRL_BASE, VIRT_CTRL_MMIO_BASE, VIRT_CTRL_IRQ_BASE); - BOOTINFO2(cs->as, parameters_base, BI_VIRT_VIRTIO_BASE, + BOOTINFO2(param_ptr, BI_VIRT_VIRTIO_BASE, VIRT_VIRTIO_MMIO_BASE, VIRT_VIRTIO_IRQ_BASE); if (kernel_cmdline) { - BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE, + BOOTINFOSTR(param_ptr, BI_COMMAND_LINE, kernel_cmdline); } + /* Pass seed to RNG. */ + param_rng_seed = param_ptr; + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + BOOTINFODATA(param_ptr, BI_RNG_SEED, + rng_seed, sizeof(rng_seed)); + /* load initrd */ if (initrd_filename) { initrd_size = get_image_size(initrd_filename); @@ -258,13 +281,20 @@ static void virt_init(MachineState *machine) initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); - BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base, + BOOTINFO2(param_ptr, BI_RAMDISK, initrd_base, initrd_size); } else { initrd_base = 0; initrd_size = 0; } - BOOTINFO0(cs->as, parameters_base, BI_LAST); + BOOTINFO0(param_ptr, BI_LAST); + rom_add_blob_fixed_as("bootinfo", param_blob, param_ptr - param_blob, + parameters_base, cs->as); + qemu_register_reset_nosnapshotload(rerandomize_rng_seed, + rom_ptr_for_as(cs->as, parameters_base, + param_ptr - param_blob) + + (param_rng_seed - param_blob)); + g_free(param_blob); } } @@ -316,10 +346,31 @@ type_init(virt_machine_register_types) } \ type_init(machvirt_machine_##major##_##minor##_init); +static void virt_machine_8_0_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE(8, 0, true) + +static void virt_machine_7_2_options(MachineClass *mc) +{ + virt_machine_8_0_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len); +} +DEFINE_VIRT_MACHINE(7, 2, false) + +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) { + virt_machine_7_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len); } -DEFINE_VIRT_MACHINE(7, 0, true) +DEFINE_VIRT_MACHINE(7, 0, false) static void virt_machine_6_2_options(MachineClass *mc) { diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig index 03dbb3c7df59..73c5ae8ad969 100644 --- a/hw/mem/Kconfig +++ b/hw/mem/Kconfig @@ -11,3 +11,8 @@ config NVDIMM config SPARSE_MEM bool + +config CXL_MEM_DEVICE + bool + default y if CXL + select MEM_DEVICE diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c new file mode 100644 index 000000000000..dae4fd89ca92 --- /dev/null +++ b/hw/mem/cxl_type3.c @@ -0,0 +1,658 @@ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/error-report.h" +#include "hw/mem/memory-device.h" +#include "hw/mem/pc-dimm.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/pmem.h" +#include "qemu/range.h" +#include "qemu/rcu.h" +#include "sysemu/hostmem.h" +#include "sysemu/numa.h" +#include "hw/cxl/cxl.h" +#include "hw/pci/msix.h" + +#define DWORD_BYTE 4 + +/* Default CDAT entries for a memory region */ +enum { + CT3_CDAT_DSMAS, + CT3_CDAT_DSLBIS0, + CT3_CDAT_DSLBIS1, + CT3_CDAT_DSLBIS2, + CT3_CDAT_DSLBIS3, + CT3_CDAT_DSEMTS, + CT3_CDAT_NUM_ENTRIES +}; + +static int ct3_build_cdat_entries_for_mr(CDATSubHeader **cdat_table, + int dsmad_handle, MemoryRegion *mr) +{ + g_autofree CDATDsmas *dsmas = NULL; + g_autofree CDATDslbis *dslbis0 = NULL; + g_autofree CDATDslbis *dslbis1 = NULL; + g_autofree CDATDslbis *dslbis2 = NULL; + g_autofree CDATDslbis *dslbis3 = NULL; + g_autofree CDATDsemts *dsemts = NULL; + + dsmas = g_malloc(sizeof(*dsmas)); + if (!dsmas) { + return -ENOMEM; + } + *dsmas = (CDATDsmas) { + .header = { + .type = CDAT_TYPE_DSMAS, + .length = sizeof(*dsmas), + }, + .DSMADhandle = dsmad_handle, + .flags = CDAT_DSMAS_FLAG_NV, + .DPA_base = 0, + .DPA_length = int128_get64(mr->size), + }; + + /* For now, no memory side cache, plausiblish numbers */ + dslbis0 = g_malloc(sizeof(*dslbis0)); + if (!dslbis0) { + return -ENOMEM; + } + *dslbis0 = (CDATDslbis) { + .header = { + .type = CDAT_TYPE_DSLBIS, + .length = sizeof(*dslbis0), + }, + .handle = dsmad_handle, + .flags = HMAT_LB_MEM_MEMORY, + .data_type = HMAT_LB_DATA_READ_LATENCY, + .entry_base_unit = 10000, /* 10ns base */ + .entry[0] = 15, /* 150ns */ + }; + + dslbis1 = g_malloc(sizeof(*dslbis1)); + if (!dslbis1) { + return -ENOMEM; + } + *dslbis1 = (CDATDslbis) { + .header = { + .type = CDAT_TYPE_DSLBIS, + .length = sizeof(*dslbis1), + }, + .handle = dsmad_handle, + .flags = HMAT_LB_MEM_MEMORY, + .data_type = HMAT_LB_DATA_WRITE_LATENCY, + .entry_base_unit = 10000, + .entry[0] = 25, /* 250ns */ + }; + + dslbis2 = g_malloc(sizeof(*dslbis2)); + if (!dslbis2) { + return -ENOMEM; + } + *dslbis2 = (CDATDslbis) { + .header = { + .type = CDAT_TYPE_DSLBIS, + .length = sizeof(*dslbis2), + }, + .handle = dsmad_handle, + .flags = HMAT_LB_MEM_MEMORY, + .data_type = HMAT_LB_DATA_READ_BANDWIDTH, + .entry_base_unit = 1000, /* GB/s */ + .entry[0] = 16, + }; + + dslbis3 = g_malloc(sizeof(*dslbis3)); + if (!dslbis3) { + return -ENOMEM; + } + *dslbis3 = (CDATDslbis) { + .header = { + .type = CDAT_TYPE_DSLBIS, + .length = sizeof(*dslbis3), + }, + .handle = dsmad_handle, + .flags = HMAT_LB_MEM_MEMORY, + .data_type = HMAT_LB_DATA_WRITE_BANDWIDTH, + .entry_base_unit = 1000, /* GB/s */ + .entry[0] = 16, + }; + + dsemts = g_malloc(sizeof(*dsemts)); + if (!dsemts) { + return -ENOMEM; + } + *dsemts = (CDATDsemts) { + .header = { + .type = CDAT_TYPE_DSEMTS, + .length = sizeof(*dsemts), + }, + .DSMAS_handle = dsmad_handle, + /* Reserved - the non volatile from DSMAS matters */ + .EFI_memory_type_attr = 2, + .DPA_offset = 0, + .DPA_length = int128_get64(mr->size), + }; + + /* Header always at start of structure */ + cdat_table[CT3_CDAT_DSMAS] = g_steal_pointer(&dsmas); + cdat_table[CT3_CDAT_DSLBIS0] = g_steal_pointer(&dslbis0); + cdat_table[CT3_CDAT_DSLBIS1] = g_steal_pointer(&dslbis1); + cdat_table[CT3_CDAT_DSLBIS2] = g_steal_pointer(&dslbis2); + cdat_table[CT3_CDAT_DSLBIS3] = g_steal_pointer(&dslbis3); + cdat_table[CT3_CDAT_DSEMTS] = g_steal_pointer(&dsemts); + + return 0; +} + +static int ct3_build_cdat_table(CDATSubHeader ***cdat_table, void *priv) +{ + g_autofree CDATSubHeader **table = NULL; + MemoryRegion *nonvolatile_mr; + CXLType3Dev *ct3d = priv; + int dsmad_handle = 0; + int rc; + + if (!ct3d->hostmem) { + return 0; + } + + nonvolatile_mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!nonvolatile_mr) { + return -EINVAL; + } + + table = g_malloc0(CT3_CDAT_NUM_ENTRIES * sizeof(*table)); + if (!table) { + return -ENOMEM; + } + + rc = ct3_build_cdat_entries_for_mr(table, dsmad_handle++, nonvolatile_mr); + if (rc < 0) { + return rc; + } + + *cdat_table = g_steal_pointer(&table); + + return CT3_CDAT_NUM_ENTRIES; +} + +static void ct3_free_cdat_table(CDATSubHeader **cdat_table, int num, void *priv) +{ + int i; + + for (i = 0; i < num; i++) { + g_free(cdat_table[i]); + } + g_free(cdat_table); +} + +static bool cxl_doe_cdat_rsp(DOECap *doe_cap) +{ + CDATObject *cdat = &CXL_TYPE3(doe_cap->pdev)->cxl_cstate.cdat; + uint16_t ent; + void *base; + uint32_t len; + CDATReq *req = pcie_doe_get_write_mbox_ptr(doe_cap); + CDATRsp rsp; + + assert(cdat->entry_len); + + /* Discard if request length mismatched */ + if (pcie_doe_get_obj_len(req) < + DIV_ROUND_UP(sizeof(CDATReq), DWORD_BYTE)) { + return false; + } + + ent = req->entry_handle; + base = cdat->entry[ent].base; + len = cdat->entry[ent].length; + + rsp = (CDATRsp) { + .header = { + .vendor_id = CXL_VENDOR_ID, + .data_obj_type = CXL_DOE_TABLE_ACCESS, + .reserved = 0x0, + .length = DIV_ROUND_UP((sizeof(rsp) + len), DWORD_BYTE), + }, + .rsp_code = CXL_DOE_TAB_RSP, + .table_type = CXL_DOE_TAB_TYPE_CDAT, + .entry_handle = (ent < cdat->entry_len - 1) ? + ent + 1 : CXL_DOE_TAB_ENT_MAX, + }; + + memcpy(doe_cap->read_mbox, &rsp, sizeof(rsp)); + memcpy(doe_cap->read_mbox + DIV_ROUND_UP(sizeof(rsp), DWORD_BYTE), + base, len); + + doe_cap->read_mbox_len += rsp.header.length; + + return true; +} + +static uint32_t ct3d_config_read(PCIDevice *pci_dev, uint32_t addr, int size) +{ + CXLType3Dev *ct3d = CXL_TYPE3(pci_dev); + uint32_t val; + + if (pcie_doe_read_config(&ct3d->doe_cdat, addr, size, &val)) { + return val; + } + + return pci_default_read_config(pci_dev, addr, size); +} + +static void ct3d_config_write(PCIDevice *pci_dev, uint32_t addr, uint32_t val, + int size) +{ + CXLType3Dev *ct3d = CXL_TYPE3(pci_dev); + + pcie_doe_write_config(&ct3d->doe_cdat, addr, val, size); + pci_default_write_config(pci_dev, addr, val, size); +} + +/* + * 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; + uint8_t *dvsec; + + dvsec = (uint8_t *)&(CXLDVSECDevice){ + .cap = 0x1e, + .ctrl = 0x2, + .status2 = 0x2, + .range1_size_hi = ct3d->hostmem->size >> 32, + .range1_size_lo = (2 << 5) | (2 << 2) | 0x3 | + (ct3d->hostmem->size & 0xF0000000), + .range1_base_hi = 0, + .range1_base_lo = 0, + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + PCIE_CXL_DEVICE_DVSEC_LENGTH, + PCIE_CXL_DEVICE_DVSEC, + PCIE_CXL2_DEVICE_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){ + .rsvd = 0, + .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX, + .reg0_base_hi = 0, + .reg1_base_lo = RBI_CXL_DEVICE_REG | CXL_DEVICE_REG_BAR_IDX, + .reg1_base_hi = 0, + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC, + REG_LOC_DVSEC_REVID, dvsec); + dvsec = (uint8_t *)&(CXLDVSECDeviceGPF){ + .phase2_duration = 0x603, /* 3 seconds */ + .phase2_power = 0x33, /* 0x33 miliwatts */ + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + GPF_DEVICE_DVSEC_LENGTH, GPF_DEVICE_DVSEC, + GPF_DEVICE_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){ + .cap = 0x26, /* 68B, IO, Mem, non-MLD */ + .ctrl = 0x02, /* IO always enabled */ + .status = 0x26, /* same as capabilities */ + .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */ + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0, + PCIE_FLEXBUS_PORT_DVSEC, + PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec); +} + +static void hdm_decoder_commit(CXLType3Dev *ct3d, int which) +{ + ComponentRegisters *cregs = &ct3d->cxl_cstate.crb; + uint32_t *cache_mem = cregs->cache_mem_registers; + + assert(which == 0); + + /* TODO: Sanity checks that the decoder is possible */ + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMIT, 0); + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, ERR, 0); + + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); +} + +static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CXLComponentState *cxl_cstate = opaque; + ComponentRegisters *cregs = &cxl_cstate->crb; + CXLType3Dev *ct3d = container_of(cxl_cstate, CXLType3Dev, cxl_cstate); + uint32_t *cache_mem = cregs->cache_mem_registers; + bool should_commit = false; + int which_hdm = -1; + + assert(size == 4); + g_assert(offset < CXL2_COMPONENT_CM_REGION_SIZE); + + switch (offset) { + case A_CXL_HDM_DECODER0_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + which_hdm = 0; + break; + default: + break; + } + + stl_le_p((uint8_t *)cache_mem + offset, value); + if (should_commit) { + hdm_decoder_commit(ct3d, which_hdm); + } +} + +static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp) +{ + DeviceState *ds = DEVICE(ct3d); + MemoryRegion *mr; + char *name; + + if (!ct3d->hostmem) { + error_setg(errp, "memdev property must be set"); + return false; + } + + mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!mr) { + error_setg(errp, "memdev property must be set"); + return false; + } + memory_region_set_nonvolatile(mr, true); + memory_region_set_enabled(mr, true); + host_memory_backend_set_mapped(ct3d->hostmem, true); + + if (ds->id) { + name = g_strdup_printf("cxl-type3-dpa-space:%s", ds->id); + } else { + name = g_strdup("cxl-type3-dpa-space"); + } + address_space_init(&ct3d->hostmem_as, mr, name); + g_free(name); + + ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size; + + if (!ct3d->lsa) { + error_setg(errp, "lsa property must be set"); + return false; + } + + return true; +} + +static DOEProtocol doe_cdat_prot[] = { + { CXL_VENDOR_ID, CXL_DOE_TABLE_ACCESS, cxl_doe_cdat_rsp }, + { } +}; + +static void ct3_realize(PCIDevice *pci_dev, Error **errp) +{ + CXLType3Dev *ct3d = CXL_TYPE3(pci_dev); + CXLComponentState *cxl_cstate = &ct3d->cxl_cstate; + ComponentRegisters *regs = &cxl_cstate->crb; + MemoryRegion *mr = ®s->component_registers; + uint8_t *pci_conf = pci_dev->config; + unsigned short msix_num = 1; + int i; + + if (!cxl_setup_memory(ct3d, errp)) { + return; + } + + pci_config_set_prog_interface(pci_conf, 0x10); + pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL); + + pcie_endpoint_cap_init(pci_dev, 0x80); + 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); + + regs->special_ops = g_new0(MemoryRegionOps, 1); + regs->special_ops->write = ct3d_reg_write; + + cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate, + TYPE_CXL_TYPE3); + + pci_register_bar( + pci_dev, CXL_COMPONENT_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, mr); + + cxl_device_register_block_init(OBJECT(pci_dev), &ct3d->cxl_dstate); + pci_register_bar(pci_dev, CXL_DEVICE_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + &ct3d->cxl_dstate.device_registers); + + /* MSI(-X) Initailization */ + msix_init_exclusive_bar(pci_dev, msix_num, 4, NULL); + for (i = 0; i < msix_num; i++) { + msix_vector_use(pci_dev, i); + } + + /* DOE Initailization */ + pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x190, doe_cdat_prot, true, 0); + + cxl_cstate->cdat.build_cdat_table = ct3_build_cdat_table; + cxl_cstate->cdat.free_cdat_table = ct3_free_cdat_table; + cxl_cstate->cdat.private = ct3d; + cxl_doe_cdat_init(cxl_cstate, errp); +} + +static void ct3_exit(PCIDevice *pci_dev) +{ + CXLType3Dev *ct3d = CXL_TYPE3(pci_dev); + CXLComponentState *cxl_cstate = &ct3d->cxl_cstate; + ComponentRegisters *regs = &cxl_cstate->crb; + + cxl_doe_cdat_release(cxl_cstate); + g_free(regs->special_ops); + address_space_destroy(&ct3d->hostmem_as); +} + +/* TODO: Support multiple HDM decoders and DPA skip */ +static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa) +{ + uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers; + uint64_t decoder_base, decoder_size, hpa_offset; + uint32_t hdm0_ctrl; + int ig, iw; + + decoder_base = (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI] << 32) | + cache_mem[R_CXL_HDM_DECODER0_BASE_LO]); + if ((uint64_t)host_addr < decoder_base) { + return false; + } + + hpa_offset = (uint64_t)host_addr - decoder_base; + + decoder_size = ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI] << 32) | + cache_mem[R_CXL_HDM_DECODER0_SIZE_LO]; + if (hpa_offset >= decoder_size) { + return false; + } + + hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; + iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW); + ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG); + + *dpa = (MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) | + ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) >> iw); + + return true; +} + +MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + CXLType3Dev *ct3d = CXL_TYPE3(d); + uint64_t dpa_offset; + MemoryRegion *mr; + + /* TODO support volatile region */ + mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!mr) { + return MEMTX_ERROR; + } + + if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) { + return MEMTX_ERROR; + } + + if (dpa_offset > int128_get64(mr->size)) { + return MEMTX_ERROR; + } + + return address_space_read(&ct3d->hostmem_as, dpa_offset, attrs, data, size); +} + +MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, + unsigned size, MemTxAttrs attrs) +{ + CXLType3Dev *ct3d = CXL_TYPE3(d); + uint64_t dpa_offset; + MemoryRegion *mr; + + mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!mr) { + return MEMTX_OK; + } + + if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) { + return MEMTX_OK; + } + + if (dpa_offset > int128_get64(mr->size)) { + return MEMTX_OK; + } + return address_space_write(&ct3d->hostmem_as, dpa_offset, attrs, + &data, size); +} + +static void ct3d_reset(DeviceState *dev) +{ + CXLType3Dev *ct3d = CXL_TYPE3(dev); + uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers; + uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE); + cxl_device_register_init_common(&ct3d->cxl_dstate); +} + +static Property ct3_props[] = { + DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND, + HostMemoryBackend *), + DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND, + HostMemoryBackend *), + DEFINE_PROP_UINT64("sn", CXLType3Dev, sn, UI64_NULL), + DEFINE_PROP_STRING("cdat", CXLType3Dev, cxl_cstate.cdat.filename), + DEFINE_PROP_END_OF_LIST(), +}; + +static uint64_t get_lsa_size(CXLType3Dev *ct3d) +{ + MemoryRegion *mr; + + mr = host_memory_backend_get_memory(ct3d->lsa); + return memory_region_size(mr); +} + +static void validate_lsa_access(MemoryRegion *mr, uint64_t size, + uint64_t offset) +{ + assert(offset + size <= memory_region_size(mr)); + assert(offset + size > offset); +} + +static uint64_t get_lsa(CXLType3Dev *ct3d, void *buf, uint64_t size, + uint64_t offset) +{ + MemoryRegion *mr; + void *lsa; + + mr = host_memory_backend_get_memory(ct3d->lsa); + validate_lsa_access(mr, size, offset); + + lsa = memory_region_get_ram_ptr(mr) + offset; + memcpy(buf, lsa, size); + + return size; +} + +static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size, + uint64_t offset) +{ + MemoryRegion *mr; + void *lsa; + + mr = host_memory_backend_get_memory(ct3d->lsa); + validate_lsa_access(mr, size, offset); + + lsa = memory_region_get_ram_ptr(mr) + offset; + memcpy(lsa, buf, size); + memory_region_set_dirty(mr, offset, size); + + /* + * Just like the PMEM, if the guest is not allowed to exit gracefully, label + * updates will get lost. + */ +} + +static void ct3_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); + CXLType3Class *cvc = CXL_TYPE3_CLASS(oc); + + pc->realize = ct3_realize; + pc->exit = ct3_exit; + pc->class_id = PCI_CLASS_STORAGE_EXPRESS; + pc->vendor_id = PCI_VENDOR_ID_INTEL; + pc->device_id = 0xd93; /* LVF for now */ + pc->revision = 1; + + pc->config_write = ct3d_config_write; + pc->config_read = ct3d_config_read; + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->desc = "CXL PMEM Device (Type 3)"; + dc->reset = ct3d_reset; + device_class_set_props(dc, ct3_props); + + cvc->get_lsa_size = get_lsa_size; + cvc->get_lsa = get_lsa; + cvc->set_lsa = set_lsa; +} + +static const TypeInfo ct3d_info = { + .name = TYPE_CXL_TYPE3, + .parent = TYPE_PCI_DEVICE, + .class_size = sizeof(struct CXLType3Class), + .class_init = ct3_class_init, + .instance_size = sizeof(CXLType3Dev), + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CXL_DEVICE }, + { INTERFACE_PCIE_DEVICE }, + {} + }, +}; + +static void ct3d_registers(void) +{ + type_register_static(&ct3d_info); +} + +type_init(ct3d_registers); diff --git a/hw/mem/meson.build b/hw/mem/meson.build index 82f86d117e66..609b2b36fcbe 100644 --- a/hw/mem/meson.build +++ b/hw/mem/meson.build @@ -3,6 +3,7 @@ mem_ss.add(files('memory-device.c')) mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c')) mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c')) mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c')) +mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c')) softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss) diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 7c7d777781ba..31080c22c91a 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -149,7 +149,7 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp) if (!nvdimm->unarmed && memory_region_is_rom(mr)) { HostMemoryBackend *hostmem = dimm->hostmem; - error_setg(errp, "'unarmed' property must be off since memdev %s " + error_setg(errp, "'unarmed' property must be 'on' since memdev %s " "is read-only", object_get_canonical_path_component(OBJECT(hostmem))); return; diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index f27e1a11babf..50ef83215cc4 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -252,7 +252,6 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md, const DeviceState *dev = DEVICE(md); if (dev->id) { - di->has_id = true; di->id = g_strdup(dev->id); } di->hotplugged = dev->hotplugged; diff --git a/hw/meson.build b/hw/meson.build index b3366c888ef6..c7ac7d3d75ba 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -6,6 +6,7 @@ subdir('block') subdir('char') subdir('core') subdir('cpu') +subdir('cxl') subdir('display') subdir('dma') subdir('gpio') @@ -49,6 +50,7 @@ subdir('avr') subdir('cris') subdir('hppa') subdir('i386') +subdir('loongarch') subdir('m68k') subdir('microblaze') subdir('mips') diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 8821d009f1a9..25ad54754ed8 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -25,12 +25,12 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #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" @@ -76,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); @@ -84,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); @@ -138,7 +142,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, uint32_t base32; int big_endian = 0; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN big_endian = 1; #endif diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c index 99991f8b2b5c..f5f42f2bf2d1 100644 --- a/hw/mips/bootloader.c +++ b/hw/mips/bootloader.c @@ -165,15 +165,29 @@ void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr) bl_gen_nop(p); /* delay slot */ } -void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0, - target_ulong a1, target_ulong a2, target_ulong a3, +void bl_gen_jump_kernel(uint32_t **p, + bool set_sp, target_ulong sp, + bool set_a0, target_ulong a0, + bool set_a1, target_ulong a1, + bool set_a2, target_ulong a2, + bool set_a3, target_ulong a3, target_ulong kernel_addr) { - bl_gen_load_ulong(p, BL_REG_SP, sp); - bl_gen_load_ulong(p, BL_REG_A0, a0); - bl_gen_load_ulong(p, BL_REG_A1, a1); - bl_gen_load_ulong(p, BL_REG_A2, a2); - bl_gen_load_ulong(p, BL_REG_A3, a3); + if (set_sp) { + bl_gen_load_ulong(p, BL_REG_SP, sp); + } + if (set_a0) { + bl_gen_load_ulong(p, BL_REG_A0, a0); + } + if (set_a1) { + bl_gen_load_ulong(p, BL_REG_A1, a1); + } + if (set_a2) { + bl_gen_load_ulong(p, BL_REG_A2, a2); + } + if (set_a3) { + bl_gen_load_ulong(p, BL_REG_A3, a3); + } bl_gen_jump_to(p, kernel_addr); } diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 59ca08b93a90..edda87e23ca6 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -34,12 +34,14 @@ #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qemu/log.h" #include "chardev/char.h" #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "sysemu/runstate.h" +#include "sysemu/reset.h" #include #include "qom/object.h" @@ -350,7 +352,10 @@ static void gen_firmware(uint32_t *p, hwaddr kernel_entry, hwaddr fdt_addr) * a2/$6 = 0 * a3/$7 = 0 */ - bl_gen_jump_kernel(&p, 0, (int32_t)-2, fdt_addr, 0, 0, kernel_entry); + bl_gen_jump_kernel(&p, + true, 0, true, (int32_t)-2, + true, fdt_addr, true, 0, true, 0, + kernel_entry); } static const void *boston_fdt_filter(void *opaque, const void *fdt_orig, @@ -363,6 +368,7 @@ static const void *boston_fdt_filter(void *opaque, const void *fdt_orig, size_t ram_low_sz, ram_high_sz; size_t fdt_sz = fdt_totalsize(fdt_orig) * 2; g_autofree void *fdt = g_malloc0(fdt_sz); + uint8_t rng_seed[32]; err = fdt_open_into(fdt_orig, fdt, fdt_sz); if (err) { @@ -370,6 +376,9 @@ static const void *boston_fdt_filter(void *opaque, const void *fdt_orig, return NULL; } + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + cmdline = (machine->kernel_cmdline && machine->kernel_cmdline[0]) ? machine->kernel_cmdline : " "; err = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); @@ -419,7 +428,7 @@ static inline XilinxPCIEHost * xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, hwaddr cfg_base, uint64_t cfg_size, hwaddr mmio_base, uint64_t mmio_size, - qemu_irq irq, bool link_up) + qemu_irq irq) { DeviceState *dev; MemoryRegion *cfg, *mmio; @@ -431,7 +440,6 @@ xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, qdev_prop_set_uint64(dev, "cfg_size", cfg_size); qdev_prop_set_uint64(dev, "mmio_base", mmio_base); qdev_prop_set_uint64(dev, "mmio_size", mmio_size); - qdev_prop_set_bit(dev, "link_up", link_up); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); @@ -724,21 +732,21 @@ static void boston_mach_init(MachineState *machine) boston_memmap[BOSTON_PCIE0].size, boston_memmap[BOSTON_PCIE0_MMIO].base, boston_memmap[BOSTON_PCIE0_MMIO].size, - get_cps_irq(&s->cps, 2), false); + get_cps_irq(&s->cps, 2)); xilinx_pcie_init(sys_mem, 1, boston_memmap[BOSTON_PCIE1].base, boston_memmap[BOSTON_PCIE1].size, boston_memmap[BOSTON_PCIE1_MMIO].base, boston_memmap[BOSTON_PCIE1_MMIO].size, - get_cps_irq(&s->cps, 1), false); + get_cps_irq(&s->cps, 1)); pcie2 = xilinx_pcie_init(sys_mem, 2, boston_memmap[BOSTON_PCIE2].base, boston_memmap[BOSTON_PCIE2].size, boston_memmap[BOSTON_PCIE2_MMIO].base, boston_memmap[BOSTON_PCIE2_MMIO].size, - get_cps_irq(&s->cps, 0), true); + get_cps_irq(&s->cps, 0)); platreg = g_new(MemoryRegion, 1); memory_region_init_io(platreg, NULL, &boston_platreg_ops, s, @@ -787,7 +795,8 @@ static void boston_mach_init(MachineState *machine) if (kernel_size > 0) { int dt_size; - g_autofree const void *dtb_file_data, *dtb_load_data; + g_autofree const void *dtb_file_data = NULL; + g_autofree const void *dtb_load_data = NULL; hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB); hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr); @@ -804,6 +813,8 @@ static void boston_mach_init(MachineState *machine) /* Calculate real fdt size after filter */ dt_size = fdt_totalsize(dtb_load_data); rom_add_blob_fixed("dtb", dtb_load_data, dt_size, dtb_paddr); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, + rom_ptr(dtb_paddr, dt_size)); } else { /* Try to load file as FIT */ fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s); diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index c9f14e70a077..34befa5dd532 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "qapi/error.h" @@ -50,7 +49,6 @@ /* Fuloong 2e has a 512k flash: Winbond W39L040AP70Z */ #define BIOS_SIZE (512 * KiB) -#define MAX_IDE_BUS 2 /* * PMON is not part of qemu and released with BSD license, anyone @@ -181,8 +179,12 @@ static void write_bootloader(CPUMIPSState *env, uint8_t *base, /* Second part of the bootloader */ p = (uint32_t *)(base + 0x040); - bl_gen_jump_kernel(&p, ENVP_VADDR - 64, 2, ENVP_VADDR, ENVP_VADDR + 8, - loaderparams.ram_size, kernel_addr); + bl_gen_jump_kernel(&p, + true, ENVP_VADDR - 64, + true, 2, true, ENVP_VADDR, + true, ENVP_VADDR + 8, + true, loaderparams.ram_size, + kernel_addr); } static void main_cpu_reset(void *opaque) @@ -197,29 +199,6 @@ static void main_cpu_reset(void *opaque) } } -static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, - I2CBus **i2c_bus) -{ - PCIDevice *dev; - - dev = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(slot, 0), true, - TYPE_VT82C686B_ISA); - qdev_connect_gpio_out(DEVICE(dev), 0, intc); - - dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 1), "via-ide"); - pci_ide_create_devs(dev); - - pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci"); - pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci"); - - dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 4), TYPE_VT82C686B_PM); - *i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c")); - - /* Audio support */ - pci_create_simple(pci_bus, PCI_DEVFN(slot, 5), TYPE_VIA_AC97); - pci_create_simple(pci_bus, PCI_DEVFN(slot, 6), TYPE_VIA_MC97); -} - /* Network support */ static void network_init(PCIBus *pci_bus) { @@ -316,11 +295,24 @@ static void mips_fuloong2e_init(MachineState *machine) pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); /* South bridge -> IP5 */ - vt82c686b_southbridge_init(pci_bus, FULOONG2E_VIA_SLOT, env->irq[5], - &smbus); + pci_dev = pci_create_simple_multifunction(pci_bus, + PCI_DEVFN(FULOONG2E_VIA_SLOT, 0), + true, TYPE_VT82C686B_ISA); + object_property_add_alias(OBJECT(machine), "rtc-time", + object_resolve_path_component(OBJECT(pci_dev), + "rtc"), + "date"); + qdev_connect_gpio_out(DEVICE(pci_dev), 0, env->irq[5]); + + dev = DEVICE(object_resolve_path_component(OBJECT(pci_dev), "ide")); + pci_ide_create_devs(PCI_DEVICE(dev)); + + dev = DEVICE(object_resolve_path_component(OBJECT(pci_dev), "pm")); + smbus = I2C_BUS(qdev_get_child_bus(dev, "i2c")); /* GPU */ if (vga_interface_type != VGA_NONE) { + vga_interface_created = true; pci_dev = pci_new(-1, "ati-vga"); dev = DEVICE(pci_dev); qdev_prop_set_uint32(dev, "vgamem_mb", 16); diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index e0ff1b556603..164866cf3e31 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -26,7 +26,7 @@ #include "qapi/error.h" #include "qemu/units.h" #include "qemu/log.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "migration/vmstate.h" #include "hw/intc/i8259.h" @@ -986,7 +986,7 @@ static void gt64120_reset(DeviceState *dev) /* FIXME: Malta specific hw assumptions ahead */ /* CPU Configuration */ -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN s->regs[GT_CPU] = 0x00000000; #else s->regs[GT_CPU] = 0x00001000; @@ -1097,7 +1097,7 @@ static void gt64120_reset(DeviceState *dev) s->regs[GT_TC_CONTROL] = 0x00000000; /* PCI Internal */ -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN s->regs[GT_PCI0_CMD] = 0x00000000; #else s->regs[GT_PCI0_CMD] = 0x00010001; @@ -1118,7 +1118,7 @@ static void gt64120_reset(DeviceState *dev) s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000; s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000; s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN s->regs[GT_PCI1_CMD] = 0x00000000; #else s->regs[GT_PCI1_CMD] = 0x00010001; diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index 44f0d48bfd75..6aefe9a61b90 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "hw/clock.h" #include "hw/mips/mips.h" @@ -137,11 +136,11 @@ static void mips_jazz_init(MachineState *machine, MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1); - MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1); NICInfo *nd; DeviceState *dev, *rc4030; + MMIOKBDState *i8042; SysBusDevice *sysbus; ISABus *isa_bus; ISADevice *pit; @@ -158,7 +157,7 @@ static void mips_jazz_init(MachineState *machine, [JAZZ_PICA61] = {33333333, 4}, }; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN big_endian = 1; #else big_endian = 0; @@ -354,7 +353,7 @@ static void mips_jazz_init(MachineState *machine, fds[n] = drive_get(IF_FLOPPY, 0, n); } /* FIXME: we should enable DMA with a custom IsaDma device */ - fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), -1, 0x80003000, fds); + fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0x80003000, fds); /* Real time clock */ mc146818_rtc_init(isa_bus, 1980, NULL); @@ -362,9 +361,19 @@ static void mips_jazz_init(MachineState *machine, memory_region_add_subregion(address_space, 0x80004000, rtc); /* Keyboard (i8042) */ - i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7), - i8042, 0x1000, 0x1); - memory_region_add_subregion(address_space, 0x80005000, i8042); + i8042 = I8042_MMIO(qdev_new(TYPE_I8042_MMIO)); + qdev_prop_set_uint64(DEVICE(i8042), "mask", 1); + qdev_prop_set_uint32(DEVICE(i8042), "size", 0x1000); + sysbus_realize_and_unref(SYS_BUS_DEVICE(i8042), &error_fatal); + + qdev_connect_gpio_out(DEVICE(i8042), I8042_KBD_IRQ, + qdev_get_gpio_in(rc4030, 6)); + qdev_connect_gpio_out(DEVICE(i8042), I8042_MOUSE_IRQ, + qdev_get_gpio_in(rc4030, 7)); + + memory_region_add_subregion(address_space, 0x80005000, + sysbus_mmio_get_region(SYS_BUS_DEVICE(i8042), + 0)); /* Serial ports */ serial_mm_init(address_space, 0x80006000, 0, diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index ae192db0c8b9..25534288dd81 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/units.h" #include "qemu/cutils.h" #include "qemu/datadir.h" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 6288511723e1..c0a2e0ab041b 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -25,8 +25,8 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/bitops.h" -#include "qemu-common.h" #include "qemu/datadir.h" +#include "qemu/guest-random.h" #include "hw/clock.h" #include "hw/southbridge/piix.h" #include "hw/isa/superio.h" @@ -36,11 +36,12 @@ #include "hw/i2c/smbus_eeprom.h" #include "hw/block/flash.h" #include "hw/mips/mips.h" +#include "hw/mips/bootloader.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" #include "qemu/log.h" #include "hw/mips/bios.h" -#include "hw/ide.h" +#include "hw/ide/pci.h" #include "hw/irq.h" #include "hw/loader.h" #include "elf.h" @@ -70,8 +71,6 @@ #define FLASH_SIZE 0x400000 -#define MAX_IDE_BUS 2 - typedef struct { MemoryRegion iomem; MemoryRegion iomem_lo; /* 0 - 0x900 */ @@ -367,7 +366,7 @@ static uint64_t malta_fpga_read(void *opaque, hwaddr addr, /* STATUS Register */ case 0x00208: -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN val = 0x00000012; #else val = 0x00000010; @@ -695,7 +694,7 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0xe040); stw_p(p++, 0x0681); /* lui t1, %hi(0xb4000000) */ -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN stw_p(p++, 0xe020); stw_p(p++, 0x0be1); /* lui t0, %hi(0xdf000000) */ @@ -867,88 +866,63 @@ static void write_bootloader(uint8_t *base, uint64_t run_addr, /* Second part of the bootloader */ p = (uint32_t *) (base + 0x580); - if (semihosting_get_argc()) { - /* Preserve a0 content as arguments have been passed */ - stl_p(p++, 0x00000000); /* nop */ - } else { - stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */ - } - - /* lui sp, high(ENVP_VADDR) */ - stl_p(p++, 0x3c1d0000 | (((ENVP_VADDR - 64) >> 16) & 0xffff)); - /* ori sp, sp, low(ENVP_VADDR) */ - stl_p(p++, 0x37bd0000 | ((ENVP_VADDR - 64) & 0xffff)); - /* lui a1, high(ENVP_VADDR) */ - stl_p(p++, 0x3c050000 | ((ENVP_VADDR >> 16) & 0xffff)); - /* ori a1, a1, low(ENVP_VADDR) */ - stl_p(p++, 0x34a50000 | (ENVP_VADDR & 0xffff)); - /* lui a2, high(ENVP_VADDR + 8) */ - stl_p(p++, 0x3c060000 | (((ENVP_VADDR + 8) >> 16) & 0xffff)); - /* ori a2, a2, low(ENVP_VADDR + 8) */ - stl_p(p++, 0x34c60000 | ((ENVP_VADDR + 8) & 0xffff)); - /* lui a3, high(ram_low_size) */ - stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); - /* ori a3, a3, low(ram_low_size) */ - stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); - - /* Load BAR registers as done by YAMON */ - stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c08df00); /* lui t0, 0xdf00 */ -#else - stl_p(p++, 0x340800df); /* ori t0, r0, 0x00df */ -#endif - stl_p(p++, 0xad280068); /* sw t0, 0x0068(t1) */ - - stl_p(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c08c000); /* lui t0, 0xc000 */ -#else - stl_p(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */ -#endif - stl_p(p++, 0xad280048); /* sw t0, 0x0048(t1) */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c084000); /* lui t0, 0x4000 */ -#else - stl_p(p++, 0x34080040); /* ori t0, r0, 0x0040 */ -#endif - stl_p(p++, 0xad280050); /* sw t0, 0x0050(t1) */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c088000); /* lui t0, 0x8000 */ -#else - stl_p(p++, 0x34080080); /* ori t0, r0, 0x0080 */ -#endif - stl_p(p++, 0xad280058); /* sw t0, 0x0058(t1) */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c083f00); /* lui t0, 0x3f00 */ -#else - stl_p(p++, 0x3408003f); /* ori t0, r0, 0x003f */ -#endif - stl_p(p++, 0xad280060); /* sw t0, 0x0060(t1) */ + /* + * Load BAR registers as done by YAMON: + * + * - set up PCI0 I/O BARs from 0x18000000 to 0x181fffff + * - set up PCI0 MEM0 at 0x10000000, size 0x7e00000 + * - set up PCI0 MEM1 at 0x18200000, size 0xbc00000 + * + */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c08c100); /* lui t0, 0xc100 */ -#else - stl_p(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */ -#endif - stl_p(p++, 0xad280080); /* sw t0, 0x0080(t1) */ -#ifdef TARGET_WORDS_BIGENDIAN - stl_p(p++, 0x3c085e00); /* lui t0, 0x5e00 */ + /* Bus endianess is always reversed */ +#if TARGET_BIG_ENDIAN +#define cpu_to_gt32 cpu_to_le32 #else - stl_p(p++, 0x3408005e); /* ori t0, r0, 0x005e */ +#define cpu_to_gt32 cpu_to_be32 #endif - stl_p(p++, 0xad280088); /* sw t0, 0x0088(t1) */ - /* Jump to kernel code */ - stl_p(p++, 0x3c1f0000 | - ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ - stl_p(p++, 0x37ff0000 | - (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ - stl_p(p++, 0x03e00009); /* jalr ra */ - stl_p(p++, 0x00000000); /* nop */ + /* move GT64120 registers from 0x14000000 to 0x1be00000 */ + bl_gen_write_u32(&p, /* GT_ISD */ + cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68), + cpu_to_gt32(0x1be00000 << 3)); + + /* setup MEM-to-PCI0 mapping */ + /* setup PCI0 io window to 0x18000000-0x181fffff */ + bl_gen_write_u32(&p, /* GT_PCI0IOLD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), + cpu_to_gt32(0x18000000 << 3)); + bl_gen_write_u32(&p, /* GT_PCI0IOHD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50), + cpu_to_gt32(0x08000000 << 3)); + /* setup PCI0 mem windows */ + bl_gen_write_u32(&p, /* GT_PCI0M0LD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), + cpu_to_gt32(0x10000000 << 3)); + bl_gen_write_u32(&p, /* GT_PCI0M0HD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60), + cpu_to_gt32(0x07e00000 << 3)); + + bl_gen_write_u32(&p, /* GT_PCI0M1LD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), + cpu_to_gt32(0x18200000 << 3)); + bl_gen_write_u32(&p, /* GT_PCI0M1HD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), + cpu_to_gt32(0x0bc00000 << 3)); + +#undef cpu_to_gt32 + + bl_gen_jump_kernel(&p, + true, ENVP_VADDR - 64, + /* + * If semihosting is used, arguments have already been + * passed, so we preserve $a0. + */ + !semihosting_get_argc(), 2, + true, ENVP_VADDR, + true, ENVP_VADDR + 8, + true, loaderparams.ram_low_size, + kernel_entry); /* YAMON subroutines */ p = (uint32_t *) (base + 0x800); @@ -1018,6 +992,17 @@ static void G_GNUC_PRINTF(3, 4) prom_set(uint32_t *prom_buf, int index, va_end(ap); } +static void reinitialize_rng_seed(void *opaque) +{ + char *rng_seed_hex = opaque; + uint8_t rng_seed[32]; + + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + for (size_t i = 0; i < sizeof(rng_seed); ++i) { + sprintf(rng_seed_hex + i * 2, "%02x", rng_seed[i]); + } +} + /* Kernel */ static uint64_t load_kernel(void) { @@ -1029,8 +1014,11 @@ static uint64_t load_kernel(void) long prom_size; int prom_index = 0; uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr); + uint8_t rng_seed[32]; + char rng_seed_hex[sizeof(rng_seed) * 2 + 1]; + size_t rng_seed_prom_offset; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN big_endian = 1; #else big_endian = 0; @@ -1116,9 +1104,21 @@ static uint64_t load_kernel(void) prom_set(prom_buf, prom_index++, "modetty0"); prom_set(prom_buf, prom_index++, "38400n8r"); + + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + for (size_t i = 0; i < sizeof(rng_seed); ++i) { + sprintf(rng_seed_hex + i * 2, "%02x", rng_seed[i]); + } + prom_set(prom_buf, prom_index++, "rngseed"); + rng_seed_prom_offset = prom_index * ENVP_ENTRY_SIZE + + sizeof(uint32_t) * ENVP_NB_ENTRIES; + prom_set(prom_buf, prom_index++, "%s", rng_seed_hex); + prom_set(prom_buf, prom_index++, NULL); rom_add_blob_fixed("prom", prom_buf, prom_size, ENVP_PADDR); + qemu_register_reset_nosnapshotload(reinitialize_rng_seed, + rom_ptr(ENVP_PADDR, prom_size) + rng_seed_prom_offset); g_free(prom_buf); return kernel_entry; @@ -1238,6 +1238,7 @@ void mips_malta_init(MachineState *machine) int fl_idx = 0; int be; MaltaState *s; + PCIDevice *piix4; DeviceState *dev; s = MIPS_MALTA(qdev_new(TYPE_MIPS_MALTA)); @@ -1272,7 +1273,7 @@ void mips_malta_init(MachineState *machine) ram_low_postio); } -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN be = 1; #else be = 0; @@ -1353,7 +1354,7 @@ void mips_malta_init(MachineState *machine) * In little endian mode the 32bit words in the bios are swapped, * a neat trick which allows bi-endian firmware. */ -#ifndef TARGET_WORDS_BIGENDIAN +#if !TARGET_BIG_ENDIAN { uint32_t *end, *addr; const size_t swapsize = MIN(bios_size, 0x3e0000); @@ -1400,12 +1401,19 @@ void mips_malta_init(MachineState *machine) empty_slot_init("GT64120", 0, 0x20000000); /* Southbridge */ - dev = piix4_create(pci_bus, &isa_bus, &smbus); + piix4 = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), true, + TYPE_PIIX4_PCI_DEVICE); + isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0")); + + dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "ide")); + pci_ide_create_devs(PCI_DEVICE(dev)); /* Interrupt controller */ - qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq); + qdev_connect_gpio_out_named(DEVICE(piix4), "intr", 0, i8259_irq); /* generate SPD EEPROM data */ + dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "pm")); + smbus = I2C_BUS(qdev_get_child_bus(dev, "i2c")); generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]); smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); @@ -1436,6 +1444,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"; @@ -1449,6 +1465,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/mips/mips_int.c b/hw/mips/mips_int.c index 2db5e10fe0bd..73437cd90f45 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -32,17 +32,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) MIPSCPU *cpu = opaque; CPUMIPSState *env = &cpu->env; CPUState *cs = CPU(cpu); - bool locked = false; if (irq < 0 || irq > 7) { return; } - /* Make sure locking works even if BQL is already held by the caller */ - if (!qemu_mutex_iothread_locked()) { - locked = true; - qemu_mutex_lock_iothread(); - } + QEMU_IOTHREAD_LOCK_GUARD(); if (level) { env->CP0_Cause |= 1 << (irq + CP0Ca_IP); @@ -59,10 +54,6 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } - - if (locked) { - qemu_mutex_unlock_iothread(); - } } void cpu_mips_irq_init_cpu(MIPSCPU *cpu) diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index 27a46bd5380b..39f64448f244 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "hw/clock.h" #include "hw/mips/mips.h" @@ -65,7 +64,7 @@ static uint64_t load_kernel(void) ram_addr_t initrd_offset; int big_endian; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN big_endian = 1; #else big_endian = 0; diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 507058d8bffb..687a8b009a36 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -171,4 +171,40 @@ config SIFIVE_U_PRCI config VIRT_CTRL bool +config LASI + bool + +config ALLWINNER_A10_CCM + bool + +config ALLWINNER_A10_DRAMC + bool + +config AXP209_PMU + bool + depends on I2C + +config RT_SYSCTL + bool + +config RT_RSTCTL + bool + +config RT_CLKCTL + bool + +config RT_PMC + bool + +config FXOS8700 + bool + depends on I2C + +config PCA9420 + bool + depends on I2C + +config DBUS_CLIENT + bool + source macio/Kconfig diff --git a/hw/misc/allwinner-a10-ccm.c b/hw/misc/allwinner-a10-ccm.c new file mode 100644 index 000000000000..68146ee34015 --- /dev/null +++ b/hw/misc/allwinner-a10-ccm.c @@ -0,0 +1,224 @@ +/* + * Allwinner A10 Clock Control Module emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 CCU, + * by Niek Linnenbank. + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/allwinner-a10-ccm.h" + +/* CCM register offsets */ +enum { + REG_PLL1_CFG = 0x0000, /* PLL1 Control */ + REG_PLL1_TUN = 0x0004, /* PLL1 Tuning */ + REG_PLL2_CFG = 0x0008, /* PLL2 Control */ + REG_PLL2_TUN = 0x000C, /* PLL2 Tuning */ + REG_PLL3_CFG = 0x0010, /* PLL3 Control */ + REG_PLL4_CFG = 0x0018, /* PLL4 Control */ + REG_PLL5_CFG = 0x0020, /* PLL5 Control */ + REG_PLL5_TUN = 0x0024, /* PLL5 Tuning */ + REG_PLL6_CFG = 0x0028, /* PLL6 Control */ + REG_PLL6_TUN = 0x002C, /* PLL6 Tuning */ + REG_PLL7_CFG = 0x0030, /* PLL7 Control */ + REG_PLL1_TUN2 = 0x0038, /* PLL1 Tuning2 */ + REG_PLL5_TUN2 = 0x003C, /* PLL5 Tuning2 */ + REG_PLL8_CFG = 0x0040, /* PLL8 Control */ + REG_OSC24M_CFG = 0x0050, /* OSC24M Control */ + REG_CPU_AHB_APB0_CFG = 0x0054, /* CPU, AHB and APB0 Divide Ratio */ +}; + +#define REG_INDEX(offset) (offset / sizeof(uint32_t)) + +/* CCM register reset values */ +enum { + REG_PLL1_CFG_RST = 0x21005000, + REG_PLL1_TUN_RST = 0x0A101000, + REG_PLL2_CFG_RST = 0x08100010, + REG_PLL2_TUN_RST = 0x00000000, + REG_PLL3_CFG_RST = 0x0010D063, + REG_PLL4_CFG_RST = 0x21009911, + REG_PLL5_CFG_RST = 0x11049280, + REG_PLL5_TUN_RST = 0x14888000, + REG_PLL6_CFG_RST = 0x21009911, + REG_PLL6_TUN_RST = 0x00000000, + REG_PLL7_CFG_RST = 0x0010D063, + REG_PLL1_TUN2_RST = 0x00000000, + REG_PLL5_TUN2_RST = 0x00000000, + REG_PLL8_CFG_RST = 0x21009911, + REG_OSC24M_CFG_RST = 0x00138013, + REG_CPU_AHB_APB0_CFG_RST = 0x00010010, +}; + +static uint64_t allwinner_a10_ccm_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwA10ClockCtlState *s = AW_A10_CCM(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_PLL1_CFG: + case REG_PLL1_TUN: + case REG_PLL2_CFG: + case REG_PLL2_TUN: + case REG_PLL3_CFG: + case REG_PLL4_CFG: + case REG_PLL5_CFG: + case REG_PLL5_TUN: + case REG_PLL6_CFG: + case REG_PLL6_TUN: + case REG_PLL7_CFG: + case REG_PLL1_TUN2: + case REG_PLL5_TUN2: + case REG_PLL8_CFG: + case REG_OSC24M_CFG: + case REG_CPU_AHB_APB0_CFG: + break; + case 0x158 ... AW_A10_CCM_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented read offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + return s->regs[idx]; +} + +static void allwinner_a10_ccm_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwA10ClockCtlState *s = AW_A10_CCM(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_PLL1_CFG: + case REG_PLL1_TUN: + case REG_PLL2_CFG: + case REG_PLL2_TUN: + case REG_PLL3_CFG: + case REG_PLL4_CFG: + case REG_PLL5_CFG: + case REG_PLL5_TUN: + case REG_PLL6_CFG: + case REG_PLL6_TUN: + case REG_PLL7_CFG: + case REG_PLL1_TUN2: + case REG_PLL5_TUN2: + case REG_PLL8_CFG: + case REG_OSC24M_CFG: + case REG_CPU_AHB_APB0_CFG: + break; + case 0x158 ... AW_A10_CCM_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + } + + s->regs[idx] = (uint32_t) val; +} + +static const MemoryRegionOps allwinner_a10_ccm_ops = { + .read = allwinner_a10_ccm_read, + .write = allwinner_a10_ccm_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static void allwinner_a10_ccm_reset_enter(Object *obj, ResetType type) +{ + AwA10ClockCtlState *s = AW_A10_CCM(obj); + + /* Set default values for registers */ + s->regs[REG_INDEX(REG_PLL1_CFG)] = REG_PLL1_CFG_RST; + s->regs[REG_INDEX(REG_PLL1_TUN)] = REG_PLL1_TUN_RST; + s->regs[REG_INDEX(REG_PLL2_CFG)] = REG_PLL2_CFG_RST; + s->regs[REG_INDEX(REG_PLL2_TUN)] = REG_PLL2_TUN_RST; + s->regs[REG_INDEX(REG_PLL3_CFG)] = REG_PLL3_CFG_RST; + s->regs[REG_INDEX(REG_PLL4_CFG)] = REG_PLL4_CFG_RST; + s->regs[REG_INDEX(REG_PLL5_CFG)] = REG_PLL5_CFG_RST; + s->regs[REG_INDEX(REG_PLL5_TUN)] = REG_PLL5_TUN_RST; + s->regs[REG_INDEX(REG_PLL6_CFG)] = REG_PLL6_CFG_RST; + s->regs[REG_INDEX(REG_PLL6_TUN)] = REG_PLL6_TUN_RST; + s->regs[REG_INDEX(REG_PLL7_CFG)] = REG_PLL7_CFG_RST; + s->regs[REG_INDEX(REG_PLL1_TUN2)] = REG_PLL1_TUN2_RST; + s->regs[REG_INDEX(REG_PLL5_TUN2)] = REG_PLL5_TUN2_RST; + s->regs[REG_INDEX(REG_PLL8_CFG)] = REG_PLL8_CFG_RST; + s->regs[REG_INDEX(REG_OSC24M_CFG)] = REG_OSC24M_CFG_RST; + s->regs[REG_INDEX(REG_CPU_AHB_APB0_CFG)] = REG_CPU_AHB_APB0_CFG_RST; +} + +static void allwinner_a10_ccm_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwA10ClockCtlState *s = AW_A10_CCM(obj); + + /* Memory mapping */ + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_ccm_ops, s, + TYPE_AW_A10_CCM, AW_A10_CCM_IOSIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription allwinner_a10_ccm_vmstate = { + .name = "allwinner-a10-ccm", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AwA10ClockCtlState, AW_A10_CCM_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_a10_ccm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = allwinner_a10_ccm_reset_enter; + dc->vmsd = &allwinner_a10_ccm_vmstate; +} + +static const TypeInfo allwinner_a10_ccm_info = { + .name = TYPE_AW_A10_CCM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_a10_ccm_init, + .instance_size = sizeof(AwA10ClockCtlState), + .class_init = allwinner_a10_ccm_class_init, +}; + +static void allwinner_a10_ccm_register(void) +{ + type_register_static(&allwinner_a10_ccm_info); +} + +type_init(allwinner_a10_ccm_register) diff --git a/hw/misc/allwinner-a10-dramc.c b/hw/misc/allwinner-a10-dramc.c new file mode 100644 index 000000000000..e118b0c2fd45 --- /dev/null +++ b/hw/misc/allwinner-a10-dramc.c @@ -0,0 +1,179 @@ +/* + * Allwinner A10 DRAM Controller emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 DRAMC, + * by Niek Linnenbank. + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/allwinner-a10-dramc.h" + +/* DRAMC register offsets */ +enum { + REG_SDR_CCR = 0x0000, + REG_SDR_ZQCR0 = 0x00a8, + REG_SDR_ZQSR = 0x00b0 +}; + +#define REG_INDEX(offset) (offset / sizeof(uint32_t)) + +/* DRAMC register flags */ +enum { + REG_SDR_CCR_DATA_TRAINING = (1 << 30), + REG_SDR_CCR_DRAM_INIT = (1 << 31), +}; +enum { + REG_SDR_ZQSR_ZCAL = (1 << 31), +}; + +/* DRAMC register reset values */ +enum { + REG_SDR_CCR_RESET = 0x80020000, + REG_SDR_ZQCR0_RESET = 0x07b00000, + REG_SDR_ZQSR_RESET = 0x80000000 +}; + +static uint64_t allwinner_a10_dramc_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwA10DramControllerState *s = AW_A10_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_SDR_CCR: + case REG_SDR_ZQCR0: + case REG_SDR_ZQSR: + break; + case 0x2e4 ... AW_A10_DRAMC_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented read offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + return s->regs[idx]; +} + +static void allwinner_a10_dramc_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwA10DramControllerState *s = AW_A10_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case REG_SDR_CCR: + if (val & REG_SDR_CCR_DRAM_INIT) { + /* Clear DRAM_INIT to indicate process is done. */ + val &= ~REG_SDR_CCR_DRAM_INIT; + } + if (val & REG_SDR_CCR_DATA_TRAINING) { + /* Clear DATA_TRAINING to indicate process is done. */ + val &= ~REG_SDR_CCR_DATA_TRAINING; + } + break; + case REG_SDR_ZQCR0: + /* Set ZCAL in ZQSR to indicate calibration is done. */ + s->regs[REG_INDEX(REG_SDR_ZQSR)] |= REG_SDR_ZQSR_ZCAL; + break; + case 0x2e4 ... AW_A10_DRAMC_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + } + + s->regs[idx] = (uint32_t) val; +} + +static const MemoryRegionOps allwinner_a10_dramc_ops = { + .read = allwinner_a10_dramc_read, + .write = allwinner_a10_dramc_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static void allwinner_a10_dramc_reset_enter(Object *obj, ResetType type) +{ + AwA10DramControllerState *s = AW_A10_DRAMC(obj); + + /* Set default values for registers */ + s->regs[REG_INDEX(REG_SDR_CCR)] = REG_SDR_CCR_RESET; + s->regs[REG_INDEX(REG_SDR_ZQCR0)] = REG_SDR_ZQCR0_RESET; + s->regs[REG_INDEX(REG_SDR_ZQSR)] = REG_SDR_ZQSR_RESET; +} + +static void allwinner_a10_dramc_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwA10DramControllerState *s = AW_A10_DRAMC(obj); + + /* Memory mapping */ + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_dramc_ops, s, + TYPE_AW_A10_DRAMC, AW_A10_DRAMC_IOSIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription allwinner_a10_dramc_vmstate = { + .name = "allwinner-a10-dramc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AwA10DramControllerState, + AW_A10_DRAMC_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_a10_dramc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = allwinner_a10_dramc_reset_enter; + dc->vmsd = &allwinner_a10_dramc_vmstate; +} + +static const TypeInfo allwinner_a10_dramc_info = { + .name = TYPE_AW_A10_DRAMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_a10_dramc_init, + .instance_size = sizeof(AwA10DramControllerState), + .class_init = allwinner_a10_dramc_class_init, +}; + +static void allwinner_a10_dramc_register(void) +{ + type_register_static(&allwinner_a10_dramc_info); +} + +type_init(allwinner_a10_dramc_register) diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 81cd6b6423ff..5f9c742e504b 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -37,10 +37,14 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "qom/object.h" +#include "hw/acpi/acpi_aml_interface.h" /* #define DEBUG_SMC */ #define APPLESMC_DEFAULT_IOBASE 0x300 +#define TYPE_APPLE_SMC "isa-applesmc" +#define APPLESMC_MAX_DATA_LENGTH 32 +#define APPLESMC_PROP_IO_BASE "iobase" enum { APPLESMC_DATA_PORT = 0x00, @@ -347,14 +351,35 @@ static Property applesmc_isa_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void build_applesmc_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + Aml *crs; + AppleSMCState *s = APPLE_SMC(adev); + uint32_t iobase = s->iobase; + Aml *dev = aml_device("SMC"); + + aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0001"))); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + crs = aml_resource_template(); + aml_append(crs, + aml_io(AML_DECODE16, iobase, iobase, 0x01, APPLESMC_MAX_DATA_LENGTH) + ); + aml_append(crs, aml_irq_no_flags(6)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + static void qdev_applesmc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); dc->realize = applesmc_isa_realize; dc->reset = qdev_applesmc_isa_reset; device_class_set_props(dc, applesmc_isa_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); + adevc->build_dev_aml = build_applesmc_aml; } static const TypeInfo applesmc_isa_info = { @@ -362,6 +387,10 @@ static const TypeInfo applesmc_isa_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(AppleSMCState), .class_init = qdev_applesmc_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void applesmc_register_types(void) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 10f00e65f4e1..ac21be306c69 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -27,6 +27,7 @@ #define R_HASH_SRC (0x20 / 4) #define R_HASH_DEST (0x24 / 4) +#define R_HASH_KEY_BUFF (0x28 / 4) #define R_HASH_SRC_LEN (0x2c / 4) #define R_HASH_CMD (0x30 / 4) @@ -64,7 +65,6 @@ #define SG_LIST_ADDR_SIZE 4 #define SG_LIST_ADDR_MASK 0x7FFFFFFF #define SG_LIST_ENTRY_SIZE (SG_LIST_LEN_SIZE + SG_LIST_ADDR_SIZE) -#define ASPEED_HACE_MAX_SG 256 /* max number of entries */ static const struct { uint32_t mask; @@ -94,11 +94,104 @@ static int hash_algo_lookup(uint32_t reg) return -1; } -static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode) +/** + * Check whether the request contains padding message. + * + * @param s aspeed hace state object + * @param iov iov of current request + * @param req_len length of the current request + * @param total_msg_len length of all acc_mode requests(excluding padding msg) + * @param pad_offset start offset of padding message + */ +static bool has_padding(AspeedHACEState *s, struct iovec *iov, + hwaddr req_len, uint32_t *total_msg_len, + uint32_t *pad_offset) +{ + *total_msg_len = (uint32_t)(ldq_be_p(iov->iov_base + req_len - 8) / 8); + /* + * SG_LIST_LEN_LAST asserted in the request length doesn't mean it is the + * last request. The last request should contain padding message. + * We check whether message contains padding by + * 1. Get total message length. If the current message contains + * padding, the last 8 bytes are total message length. + * 2. Check whether the total message length is valid. + * If it is valid, the value should less than or equal to + * total_req_len. + * 3. Current request len - padding_size to get padding offset. + * The padding message's first byte should be 0x80 + */ + if (*total_msg_len <= s->total_req_len) { + uint32_t padding_size = s->total_req_len - *total_msg_len; + uint8_t *padding = iov->iov_base; + *pad_offset = req_len - padding_size; + if (padding[*pad_offset] == 0x80) { + return true; + } + } + + return false; +} + +static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id, + uint32_t *pad_offset) +{ + int i, iov_count; + if (*pad_offset != 0) { + s->iov_cache[s->iov_count].iov_base = iov[id].iov_base; + s->iov_cache[s->iov_count].iov_len = *pad_offset; + ++s->iov_count; + } + for (i = 0; i < s->iov_count; i++) { + iov[i].iov_base = s->iov_cache[i].iov_base; + iov[i].iov_len = s->iov_cache[i].iov_len; + } + iov_count = s->iov_count; + s->iov_count = 0; + s->total_req_len = 0; + return iov_count; +} + +/** + * Generate iov for accumulative mode. + * + * @param s aspeed hace state object + * @param iov iov of the current request + * @param id index of the current iov + * @param req_len length of the current request + * + * @return count of iov + */ +static int gen_acc_mode_iov(AspeedHACEState *s, struct iovec *iov, int id, + hwaddr *req_len) +{ + uint32_t pad_offset; + uint32_t total_msg_len; + s->total_req_len += *req_len; + + if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) { + if (s->iov_count) { + return reconstruct_iov(s, iov, id, &pad_offset); + } + + *req_len -= s->total_req_len - total_msg_len; + s->total_req_len = 0; + iov[id].iov_len = *req_len; + } else { + s->iov_cache[s->iov_count].iov_base = iov->iov_base; + s->iov_cache[s->iov_count].iov_len = *req_len; + ++s->iov_count; + } + + return id + 1; +} + +static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, + bool acc_mode) { struct iovec iov[ASPEED_HACE_MAX_SG]; g_autofree uint8_t *digest_buf; size_t digest_len = 0; + int niov = 0; int i; if (sg_mode) { @@ -123,10 +216,16 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode) MEMTXATTRS_UNSPECIFIED, NULL); addr &= SG_LIST_ADDR_MASK; - iov[i].iov_len = len & SG_LIST_LEN_MASK; - plen = iov[i].iov_len; + plen = len & SG_LIST_LEN_MASK; iov[i].iov_base = address_space_map(&s->dram_as, addr, &plen, false, MEMTXATTRS_UNSPECIFIED); + + if (acc_mode) { + niov = gen_acc_mode_iov(s, iov, i, &plen); + + } else { + iov[i].iov_len = plen; + } } } else { hwaddr len = s->regs[R_HASH_SRC_LEN]; @@ -136,6 +235,25 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode) &len, false, MEMTXATTRS_UNSPECIFIED); i = 1; + + if (s->iov_count) { + /* + * In aspeed sdk kernel driver, sg_mode is disabled in hash_final(). + * Thus if we received a request with sg_mode disabled, it is + * required to check whether cache is empty. If no, we should + * combine cached iov and the current iov. + */ + uint32_t total_msg_len; + uint32_t pad_offset; + s->total_req_len += len; + if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) { + niov = reconstruct_iov(s, iov, 0, &pad_offset); + } + } + } + + if (niov) { + i = niov; } if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) { @@ -210,6 +328,9 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, case R_HASH_DEST: data &= ahc->dest_mask; break; + case R_HASH_KEY_BUFF: + data &= ahc->key_mask; + break; case R_HASH_SRC_LEN: data &= 0x0FFFFFFF; break; @@ -217,14 +338,14 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, int algo; data &= ahc->hash_mask; - if ((data & HASH_HMAC_MASK)) { + if ((data & HASH_DIGEST_HMAC)) { qemu_log_mask(LOG_UNIMP, - "%s: HMAC engine command mode %"PRIx64" not implemented", - __func__, (data & HASH_HMAC_MASK) >> 8); + "%s: HMAC mode not implemented\n", + __func__); } if (data & BIT(1)) { qemu_log_mask(LOG_UNIMP, - "%s: Cascaded mode not implemented", + "%s: Cascaded mode not implemented\n", __func__); } algo = hash_algo_lookup(data); @@ -234,7 +355,8 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, __func__, data & ahc->hash_mask); break; } - do_hash_operation(s, algo, data & HASH_SG_EN); + do_hash_operation(s, algo, data & HASH_SG_EN, + ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); if (data & HASH_IRQ_EN) { qemu_irq_raise(s->irq); @@ -267,6 +389,8 @@ static void aspeed_hace_reset(DeviceState *dev) struct AspeedHACEState *s = ASPEED_HACE(dev); memset(s->regs, 0, sizeof(s->regs)); + s->iov_count = 0; + s->total_req_len = 0; } static void aspeed_hace_realize(DeviceState *dev, Error **errp) @@ -302,6 +426,8 @@ static const VMStateDescription vmstate_aspeed_hace = { .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), + VMSTATE_UINT32(total_req_len, AspeedHACEState), + VMSTATE_UINT32(iov_count, AspeedHACEState), VMSTATE_END_OF_LIST(), } }; @@ -333,6 +459,7 @@ static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data) ahc->src_mask = 0x0FFFFFFF; ahc->dest_mask = 0x0FFFFFF8; + ahc->key_mask = 0x0FFFFFC0; ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ } @@ -351,6 +478,7 @@ static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data) ahc->src_mask = 0x3fffffff; ahc->dest_mask = 0x3ffffff8; + ahc->key_mask = 0x3FFFFFC0; ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ } @@ -369,6 +497,7 @@ static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data) ahc->src_mask = 0x7FFFFFFF; ahc->dest_mask = 0x7FFFFFF8; + ahc->key_mask = 0x7FFFFFF8; ahc->hash_mask = 0x00147FFF; } @@ -378,11 +507,31 @@ static const TypeInfo aspeed_ast2600_hace_info = { .class_init = aspeed_ast2600_hace_class_init, }; +static void aspeed_ast1030_hace_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); + + dc->desc = "AST1030 Hash and Crypto Engine"; + + ahc->src_mask = 0x7FFFFFFF; + ahc->dest_mask = 0x7FFFFFF8; + ahc->key_mask = 0x7FFFFFF8; + ahc->hash_mask = 0x00147FFF; +} + +static const TypeInfo aspeed_ast1030_hace_info = { + .name = TYPE_ASPEED_AST1030_HACE, + .parent = TYPE_ASPEED_HACE, + .class_init = aspeed_ast1030_hace_class_init, +}; + static void aspeed_hace_register_types(void) { type_register_static(&aspeed_ast2400_hace_info); type_register_static(&aspeed_ast2500_hace_info); type_register_static(&aspeed_ast2600_hace_info); + type_register_static(&aspeed_ast1030_hace_info); type_register_static(&aspeed_hace_info); } diff --git a/hw/misc/aspeed_peci.c b/hw/misc/aspeed_peci.c new file mode 100644 index 000000000000..93cc672e9681 --- /dev/null +++ b/hw/misc/aspeed_peci.c @@ -0,0 +1,152 @@ +/* + * Aspeed PECI Controller + * + * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com) + * + * 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 "hw/irq.h" +#include "hw/misc/aspeed_peci.h" +#include "hw/registerfields.h" +#include "trace.h" + +#define ASPEED_PECI_CC_RSP_SUCCESS (0x40U) + +/* Command Register */ +REG32(PECI_CMD, 0x08) + FIELD(PECI_CMD, FIRE, 0, 1) + +/* Interrupt Control Register */ +REG32(PECI_INT_CTRL, 0x18) + +/* Interrupt Status Register */ +REG32(PECI_INT_STS, 0x1C) + FIELD(PECI_INT_STS, CMD_DONE, 0, 1) + +/* Rx/Tx Data Buffer Registers */ +REG32(PECI_WR_DATA0, 0x20) +REG32(PECI_RD_DATA0, 0x30) + +static void aspeed_peci_raise_interrupt(AspeedPECIState *s, uint32_t status) +{ + trace_aspeed_peci_raise_interrupt(s->regs[R_PECI_INT_CTRL], status); + + s->regs[R_PECI_INT_STS] = s->regs[R_PECI_INT_CTRL] & status; + if (!s->regs[R_PECI_INT_STS]) { + return; + } + qemu_irq_raise(s->irq); +} + +static uint64_t aspeed_peci_read(void *opaque, hwaddr offset, unsigned size) +{ + AspeedPECIState *s = ASPEED_PECI(opaque); + uint64_t data; + + if (offset >= ASPEED_PECI_NR_REGS << 2) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + return 0; + } + data = s->regs[offset >> 2]; + + trace_aspeed_peci_read(offset, data); + return data; +} + +static void aspeed_peci_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + AspeedPECIState *s = ASPEED_PECI(opaque); + + trace_aspeed_peci_write(offset, data); + + if (offset >= ASPEED_PECI_NR_REGS << 2) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + return; + } + + switch (offset) { + case A_PECI_INT_STS: + s->regs[R_PECI_INT_STS] &= ~data; + if (!s->regs[R_PECI_INT_STS]) { + qemu_irq_lower(s->irq); + } + break; + case A_PECI_CMD: + /* + * Only the FIRE bit is writable. Once the command is complete, it + * should be cleared. Since we complete the command immediately, the + * value is not stored in the register array. + */ + if (!FIELD_EX32(data, PECI_CMD, FIRE)) { + break; + } + if (s->regs[R_PECI_INT_STS]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Interrupt status must be " + "cleared before firing another command: 0x%08x\n", + __func__, s->regs[R_PECI_INT_STS]); + break; + } + s->regs[R_PECI_RD_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS; + s->regs[R_PECI_WR_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS; + aspeed_peci_raise_interrupt(s, + FIELD_DP32(0, PECI_INT_STS, CMD_DONE, 1)); + break; + default: + s->regs[offset / sizeof(s->regs[0])] = data; + break; + } +} + +static const MemoryRegionOps aspeed_peci_ops = { + .read = aspeed_peci_read, + .write = aspeed_peci_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void aspeed_peci_realize(DeviceState *dev, Error **errp) +{ + AspeedPECIState *s = ASPEED_PECI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_peci_ops, s, + TYPE_ASPEED_PECI, 0x1000); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); +} + +static void aspeed_peci_reset(DeviceState *dev) +{ + AspeedPECIState *s = ASPEED_PECI(dev); + + memset(s->regs, 0, sizeof(s->regs)); +} + +static void aspeed_peci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = aspeed_peci_realize; + dc->reset = aspeed_peci_reset; + dc->desc = "Aspeed PECI Controller"; +} + +static const TypeInfo aspeed_peci_types[] = { + { + .name = TYPE_ASPEED_PECI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedPECIState), + .class_init = aspeed_peci_class_init, + .abstract = false, + }, +}; + +DEFINE_TYPES(aspeed_peci_types); diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c index 40f2a8c6312f..c6f328e3be23 100644 --- a/hw/misc/aspeed_sbc.c +++ b/hw/misc/aspeed_sbc.c @@ -11,12 +11,35 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/error-report.h" +#include "hw/qdev-properties.h" #include "hw/misc/aspeed_sbc.h" #include "qapi/error.h" #include "migration/vmstate.h" #define R_PROT (0x000 / 4) #define R_STATUS (0x014 / 4) +#define R_QSR (0x040 / 4) + +/* R_STATUS */ +#define ABR_EN BIT(14) /* Mirrors SCU510[11] */ +#define ABR_IMAGE_SOURCE BIT(13) +#define SPI_ABR_IMAGE_SOURCE BIT(12) +#define SB_CRYPTO_KEY_EXP_DONE BIT(11) +#define SB_CRYPTO_BUSY BIT(10) +#define OTP_WP_EN BIT(9) +#define OTP_ADDR_WP_EN BIT(8) +#define LOW_SEC_KEY_EN BIT(7) +#define SECURE_BOOT_EN BIT(6) +#define UART_BOOT_EN BIT(5) +/* bit 4 reserved*/ +#define OTP_CHARGE_PUMP_READY BIT(3) +#define OTP_IDLE BIT(2) +#define OTP_MEM_IDLE BIT(1) +#define OTP_COMPARE_STATUS BIT(0) + +/* QSR */ +#define QSR_RSA_MASK (0x3 << 12) +#define QSR_HASH_MASK (0x3 << 10) static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size) { @@ -50,6 +73,7 @@ static void aspeed_sbc_write(void *opaque, hwaddr addr, uint64_t data, switch (addr) { case R_STATUS: + case R_QSR: qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read only register 0x%" HWADDR_PRIx "\n", __func__, addr << 2); @@ -77,8 +101,18 @@ static void aspeed_sbc_reset(DeviceState *dev) memset(s->regs, 0, sizeof(s->regs)); - /* Set secure boot enabled, and boot from emmc/spi */ - s->regs[R_STATUS] = 1 << 6 | 1 << 5; + /* Set secure boot enabled with RSA4096_SHA256 and enable eMMC ABR */ + s->regs[R_STATUS] = OTP_IDLE | OTP_MEM_IDLE; + + if (s->emmc_abr) { + s->regs[R_STATUS] &= ABR_EN; + } + + if (s->signing_settings) { + s->regs[R_STATUS] &= SECURE_BOOT_EN; + } + + s->regs[R_QSR] = s->signing_settings; } static void aspeed_sbc_realize(DeviceState *dev, Error **errp) @@ -102,6 +136,12 @@ static const VMStateDescription vmstate_aspeed_sbc = { } }; +static Property aspeed_sbc_properties[] = { + DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0), + DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void aspeed_sbc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -109,6 +149,7 @@ static void aspeed_sbc_class_init(ObjectClass *klass, void *data) dc->realize = aspeed_sbc_realize; dc->reset = aspeed_sbc_reset; dc->vmsd = &vmstate_aspeed_sbc; + device_class_set_props(dc, aspeed_sbc_properties); } static const TypeInfo aspeed_sbc_info = { diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index d06e179a6e65..83353649064a 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -213,6 +213,11 @@ static uint32_t aspeed_scu_get_random(void) } uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s) +{ + return ASPEED_SCU_GET_CLASS(s)->get_apb(s); +} + +static uint32_t aspeed_2400_scu_get_apb_freq(AspeedSCUState *s) { AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); uint32_t hpll = asc->calc_hpll(s, s->regs[HPLL_PARAM]); @@ -221,6 +226,24 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s) / asc->apb_divider; } +static uint32_t aspeed_2600_scu_get_apb_freq(AspeedSCUState *s) +{ + AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); + uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]); + + return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL]) + 1) + / asc->apb_divider; +} + +static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s) +{ + AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); + uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]); + + return hpll / (SCU_AST1030_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL4]) + 1) + / asc->apb_divider; +} + static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) { AspeedSCUState *s = ASPEED_SCU(opaque); @@ -247,6 +270,7 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) break; } + trace_aspeed_scu_read(offset, size, s->regs[reg]); return s->regs[reg]; } @@ -357,7 +381,8 @@ static const MemoryRegionOps aspeed_ast2500_scu_ops = { static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s) { - if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN) { + if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN || + ASPEED_SCU_GET_CLASS(s)->clkin_25Mhz) { return 25000000; } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) { return 48000000; @@ -426,6 +451,26 @@ static uint32_t aspeed_2500_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) return clkin * multiplier; } +static uint32_t aspeed_2600_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) +{ + uint32_t multiplier = 1; + uint32_t clkin = aspeed_scu_get_clkin(s); + + if (hpll_reg & SCU_AST2600_H_PLL_OFF) { + return 0; + } + + if (!(hpll_reg & SCU_AST2600_H_PLL_BYPASS_EN)) { + uint32_t p = (hpll_reg >> 19) & 0xf; + uint32_t n = (hpll_reg >> 13) & 0x3f; + uint32_t m = hpll_reg & 0x1fff; + + multiplier = ((m + 1) / (n + 1)) / (p + 1); + } + + return clkin * multiplier; +} + static void aspeed_scu_reset(DeviceState *dev) { AspeedSCUState *s = ASPEED_SCU(dev); @@ -447,6 +492,8 @@ static uint32_t aspeed_silicon_revs[] = { AST2600_A1_SILICON_REV, AST2600_A2_SILICON_REV, AST2600_A3_SILICON_REV, + AST1030_A0_SILICON_REV, + AST1030_A1_SILICON_REV, }; bool is_supported_silicon_rev(uint32_t silicon_rev) @@ -525,8 +572,10 @@ static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data) dc->desc = "ASPEED 2400 System Control Unit"; asc->resets = ast2400_a0_resets; asc->calc_hpll = aspeed_2400_scu_calc_hpll; + asc->get_apb = aspeed_2400_scu_get_apb_freq; asc->apb_divider = 2; asc->nr_regs = ASPEED_SCU_NR_REGS; + asc->clkin_25Mhz = false; asc->ops = &aspeed_ast2400_scu_ops; } @@ -545,8 +594,10 @@ static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data) dc->desc = "ASPEED 2500 System Control Unit"; asc->resets = ast2500_a1_resets; asc->calc_hpll = aspeed_2500_scu_calc_hpll; + asc->get_apb = aspeed_2400_scu_get_apb_freq; asc->apb_divider = 4; asc->nr_regs = ASPEED_SCU_NR_REGS; + asc->clkin_25Mhz = false; asc->ops = &aspeed_ast2500_scu_ops; } @@ -587,6 +638,7 @@ static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset, break; } + trace_aspeed_scu_read(offset, size, s->regs[reg]); return s->regs[reg]; } @@ -716,9 +768,11 @@ static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) dc->desc = "ASPEED 2600 System Control Unit"; dc->reset = aspeed_ast2600_scu_reset; asc->resets = ast2600_a3_resets; - asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */ + asc->calc_hpll = aspeed_2600_scu_calc_hpll; + asc->get_apb = aspeed_2600_scu_get_apb_freq; asc->apb_divider = 4; asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; + asc->clkin_25Mhz = true; asc->ops = &aspeed_ast2600_scu_ops; } @@ -729,12 +783,64 @@ static const TypeInfo aspeed_2600_scu_info = { .class_init = aspeed_2600_scu_class_init, }; +static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = { + [AST2600_SYS_RST_CTRL] = 0xFFC3FED8, + [AST2600_SYS_RST_CTRL2] = 0x09FFFFFC, + [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, + [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, + [AST2600_DEBUG_CTRL2] = 0x00000000, + [AST2600_HPLL_PARAM] = 0x10004077, + [AST2600_HPLL_EXT] = 0x00000031, + [AST2600_CLK_SEL4] = 0x43F90900, + [AST2600_CLK_SEL5] = 0x40000000, + [AST2600_CHIP_ID0] = 0xDEADBEEF, + [AST2600_CHIP_ID1] = 0x0BADCAFE, +}; + +static void aspeed_ast1030_scu_reset(DeviceState *dev) +{ + AspeedSCUState *s = ASPEED_SCU(dev); + AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); + + memcpy(s->regs, asc->resets, asc->nr_regs * 4); + + s->regs[AST2600_SILICON_REV] = AST1030_A1_SILICON_REV; + s->regs[AST2600_SILICON_REV2] = s->silicon_rev; + s->regs[AST2600_HW_STRAP1] = s->hw_strap1; + s->regs[AST2600_HW_STRAP2] = s->hw_strap2; + s->regs[PROT_KEY] = s->hw_prot_key; +} + +static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); + + dc->desc = "ASPEED 1030 System Control Unit"; + dc->reset = aspeed_ast1030_scu_reset; + asc->resets = ast1030_a1_resets; + asc->calc_hpll = aspeed_2600_scu_calc_hpll; + asc->get_apb = aspeed_1030_scu_get_apb_freq; + asc->apb_divider = 2; + asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; + asc->clkin_25Mhz = true; + asc->ops = &aspeed_ast2600_scu_ops; +} + +static const TypeInfo aspeed_1030_scu_info = { + .name = TYPE_ASPEED_1030_SCU, + .parent = TYPE_ASPEED_SCU, + .instance_size = sizeof(AspeedSCUState), + .class_init = aspeed_1030_scu_class_init, +}; + static void aspeed_scu_register_types(void) { type_register_static(&aspeed_scu_info); type_register_static(&aspeed_2400_scu_info); type_register_static(&aspeed_2500_scu_info); type_register_static(&aspeed_2600_scu_info); + type_register_static(&aspeed_1030_scu_info); } type_init(aspeed_scu_register_types); diff --git a/hw/misc/axp209.c b/hw/misc/axp209.c new file mode 100644 index 000000000000..2908ed99a6ff --- /dev/null +++ b/hw/misc/axp209.c @@ -0,0 +1,238 @@ +/* + * AXP-209 PMU Emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "hw/i2c/i2c.h" +#include "migration/vmstate.h" + +#define TYPE_AXP209_PMU "axp209_pmu" + +#define AXP209(obj) \ + OBJECT_CHECK(AXP209I2CState, (obj), TYPE_AXP209_PMU) + +/* registers */ +enum { + REG_POWER_STATUS = 0x0u, + REG_OPERATING_MODE, + REG_OTG_VBUS_STATUS, + REG_CHIP_VERSION, + REG_DATA_CACHE_0, + REG_DATA_CACHE_1, + REG_DATA_CACHE_2, + REG_DATA_CACHE_3, + REG_DATA_CACHE_4, + REG_DATA_CACHE_5, + REG_DATA_CACHE_6, + REG_DATA_CACHE_7, + REG_DATA_CACHE_8, + REG_DATA_CACHE_9, + REG_DATA_CACHE_A, + REG_DATA_CACHE_B, + REG_POWER_OUTPUT_CTRL = 0x12u, + REG_DC_DC2_OUT_V_CTRL = 0x23u, + REG_DC_DC2_DVS_CTRL = 0x25u, + REG_DC_DC3_OUT_V_CTRL = 0x27u, + REG_LDO2_4_OUT_V_CTRL, + REG_LDO3_OUT_V_CTRL, + REG_VBUS_CH_MGMT = 0x30u, + REG_SHUTDOWN_V_CTRL, + REG_SHUTDOWN_CTRL, + REG_CHARGE_CTRL_1, + REG_CHARGE_CTRL_2, + REG_SPARE_CHARGE_CTRL, + REG_PEK_KEY_CTRL, + REG_DC_DC_FREQ_SET, + REG_CHR_TEMP_TH_SET, + REG_CHR_HIGH_TEMP_TH_CTRL, + REG_IPSOUT_WARN_L1, + REG_IPSOUT_WARN_L2, + REG_DISCHR_TEMP_TH_SET, + REG_DISCHR_HIGH_TEMP_TH_CTRL, + REG_IRQ_BANK_1_CTRL = 0x40u, + REG_IRQ_BANK_2_CTRL, + REG_IRQ_BANK_3_CTRL, + REG_IRQ_BANK_4_CTRL, + REG_IRQ_BANK_5_CTRL, + REG_IRQ_BANK_1_STAT = 0x48u, + REG_IRQ_BANK_2_STAT, + REG_IRQ_BANK_3_STAT, + REG_IRQ_BANK_4_STAT, + REG_IRQ_BANK_5_STAT, + REG_ADC_ACIN_V_H = 0x56u, + REG_ADC_ACIN_V_L, + REG_ADC_ACIN_CURR_H, + REG_ADC_ACIN_CURR_L, + REG_ADC_VBUS_V_H, + REG_ADC_VBUS_V_L, + REG_ADC_VBUS_CURR_H, + REG_ADC_VBUS_CURR_L, + REG_ADC_INT_TEMP_H, + REG_ADC_INT_TEMP_L, + REG_ADC_TEMP_SENS_V_H = 0x62u, + REG_ADC_TEMP_SENS_V_L, + REG_ADC_BAT_V_H = 0x78u, + REG_ADC_BAT_V_L, + REG_ADC_BAT_DISCHR_CURR_H, + REG_ADC_BAT_DISCHR_CURR_L, + REG_ADC_BAT_CHR_CURR_H, + REG_ADC_BAT_CHR_CURR_L, + REG_ADC_IPSOUT_V_H, + REG_ADC_IPSOUT_V_L, + REG_DC_DC_MOD_SEL = 0x80u, + REG_ADC_EN_1, + REG_ADC_EN_2, + REG_ADC_SR_CTRL, + REG_ADC_IN_RANGE, + REG_GPIO1_ADC_IRQ_RISING_TH, + REG_GPIO1_ADC_IRQ_FALLING_TH, + REG_TIMER_CTRL = 0x8au, + REG_VBUS_CTRL_MON_SRP, + REG_OVER_TEMP_SHUTDOWN = 0x8fu, + REG_GPIO0_FEAT_SET, + REG_GPIO_OUT_HIGH_SET, + REG_GPIO1_FEAT_SET, + REG_GPIO2_FEAT_SET, + REG_GPIO_SIG_STATE_SET_MON, + REG_GPIO3_SET, + REG_COULOMB_CNTR_CTRL = 0xb8u, + REG_POWER_MEAS_RES, + NR_REGS +}; + +#define AXP209_CHIP_VERSION_ID (0x01) +#define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16) +#define AXP209_IRQ_BANK_1_CTRL_RESET (0xd8) + +/* A simple I2C slave which returns values of ID or CNT register. */ +typedef struct AXP209I2CState { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + uint8_t regs[NR_REGS]; /* peripheral registers */ + uint8_t ptr; /* current register index */ + uint8_t count; /* counter used for tx/rx */ +} AXP209I2CState; + +/* Reset all counters and load ID register */ +static void axp209_reset_enter(Object *obj, ResetType type) +{ + AXP209I2CState *s = AXP209(obj); + + memset(s->regs, 0, NR_REGS); + s->ptr = 0; + s->count = 0; + s->regs[REG_CHIP_VERSION] = AXP209_CHIP_VERSION_ID; + s->regs[REG_DC_DC2_OUT_V_CTRL] = AXP209_DC_DC2_OUT_V_CTRL_RESET; + s->regs[REG_IRQ_BANK_1_CTRL] = AXP209_IRQ_BANK_1_CTRL_RESET; +} + +/* Handle events from master. */ +static int axp209_event(I2CSlave *i2c, enum i2c_event event) +{ + AXP209I2CState *s = AXP209(i2c); + + s->count = 0; + + return 0; +} + +/* Called when master requests read */ +static uint8_t axp209_rx(I2CSlave *i2c) +{ + AXP209I2CState *s = AXP209(i2c); + uint8_t ret = 0xff; + + if (s->ptr < NR_REGS) { + ret = s->regs[s->ptr++]; + } + + trace_axp209_rx(s->ptr - 1, ret); + + return ret; +} + +/* + * Called when master sends write. + * Update ptr with byte 0, then perform write with second byte. + */ +static int axp209_tx(I2CSlave *i2c, uint8_t data) +{ + AXP209I2CState *s = AXP209(i2c); + + if (s->count == 0) { + /* Store register address */ + s->ptr = data; + s->count++; + trace_axp209_select(data); + } else { + trace_axp209_tx(s->ptr, data); + if (s->ptr == REG_DC_DC2_OUT_V_CTRL) { + s->regs[s->ptr++] = data; + } + } + + return 0; +} + +static const VMStateDescription vmstate_axp209 = { + .name = TYPE_AXP209_PMU, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(regs, AXP209I2CState, NR_REGS), + VMSTATE_UINT8(count, AXP209I2CState), + VMSTATE_UINT8(ptr, AXP209I2CState), + VMSTATE_END_OF_LIST() + } +}; + +static void axp209_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + rc->phases.enter = axp209_reset_enter; + dc->vmsd = &vmstate_axp209; + isc->event = axp209_event; + isc->recv = axp209_rx; + isc->send = axp209_tx; +} + +static const TypeInfo axp209_info = { + .name = TYPE_AXP209_PMU, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AXP209I2CState), + .class_init = axp209_class_init +}; + +static void axp209_register_devices(void) +{ + type_register_static(&axp209_info); +} + +type_init(axp209_register_devices); diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index e94e951057ec..890ae7bae56c 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/cbus.c b/hw/misc/cbus.c index 3c3721ad2dd2..653e8ddcd5b5 100644 --- a/hw/misc/cbus.c +++ b/hw/misc/cbus.c @@ -133,7 +133,7 @@ static void cbus_sel(void *opaque, int line, int level) CBus *cbus_init(qemu_irq dat) { - CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s)); + CBusPriv *s = g_malloc0(sizeof(*s)); s->dat_out = dat; s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0); @@ -388,7 +388,7 @@ static void retu_io(void *opaque, int rw, int reg, uint16_t *val) void *retu_init(qemu_irq irq, int vilma) { - CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s)); + CBusRetu *s = g_malloc0(sizeof(*s)); s->irq = irq; s->irqen = 0xffff; @@ -604,7 +604,7 @@ static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val) void *tahvo_init(qemu_irq irq, int betty) { - CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s)); + CBusTahvo *s = g_malloc0(sizeof(*s)); s->irq = irq; s->irqen = 0xffff; diff --git a/hw/misc/dbus_client_mua.c b/hw/misc/dbus_client_mua.c new file mode 100644 index 000000000000..b6e9f984d20c --- /dev/null +++ b/hw/misc/dbus_client_mua.c @@ -0,0 +1,184 @@ +/* + * QEMU dbus_client_mua.c + * + * Copyright (C) 2022 NXP + * + * 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 +#include +#include +#include + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/dbus.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qapi/qmp/qerror.h" +#include "qom/object.h" +#include "hw/misc/dbus_client.h" +#include "hw/irq.h" +#include "migration/vmstate.h" + +static uint64_t dbus_client_mua_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint32_t ret = 0; + g_autoptr(GError) err = NULL; + g_autoptr(GVariant) result = NULL; + g_autoptr(GVariant) value = NULL; + DBUSCLIENTMUAState *s = DBUS_CLIENT_MUA(opaque); + + if (!s->dbus.proxy) { + return ret; + } else { + result = g_dbus_proxy_call_sync(s->dbus.proxy, "MUARead", + g_variant_new("(t)", offset), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &err); + + if (!result) { + error_report("%s: Failed to Load: %s", __func__, err->message); + return -1; + } + + g_variant_get(result, "(u)", &ret); + } + + return ret; +} + + +static void dbus_client_mua_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + DBUSCLIENTMUAState *s = DBUS_CLIENT_MUA(opaque); + + if (!s->dbus.proxy) { + return; + } else { + g_autoptr(GError) err = NULL; + g_autoptr(GVariant) result = NULL; + + /* TODO need process clear irq if needed */ + + /* write to dbus */ + result = g_dbus_proxy_call_sync(s->dbus.proxy, "MUAWrite", + g_variant_new("(tt)", + offset, value), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &err); + if (!result) { + error_report("%s: Failed to Load: %s", __func__, err->message); + } + } + return; +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + gchar *parameters_str; + DBUSCLIENTMUAState *s = (DBUSCLIENTMUAState *)user_data; + + parameters_str = g_variant_print (parameters, TRUE); + g_print (" *** Received Signal: %s: %s\n", + signal_name, + parameters_str); + g_free (parameters_str); + + + qemu_irq_raise(s->irq); + +} + + +static const MemoryRegionOps dbus_client_mua_ops = { + .read = dbus_client_mua_read, + .write = dbus_client_mua_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription dbus_client_mua_vm = { + .name = TYPE_DBUS_CLIENT_MUA, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + + +static void dbus_client_mua_init(Object *obj) +{ + g_autoptr(GHashTable) proxies = NULL; + g_autoptr(GError) err = NULL; + DBUSCLIENTMUAState *s = DBUS_CLIENT_MUA(obj); + g_autoptr(GVariant) result = NULL; + + /*find the TYPE_DBUS_OBJ object*/ + s->dbus.dbus_conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err); + g_assert_no_error(err); + + s->dbus.proxy = g_dbus_proxy_new_sync(s->dbus.dbus_conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* GDBusInterfaceInfo */ + "org.qemu.client", /* name */ + "/org/qemu/client", /* object path */ + "org.qemu.client.mua", /* interface */ + NULL, /* GCancellable */ + &err); + g_assert_no_error(err); + if (!s->dbus.proxy) { + warn_report("%s: Failed to find proxy Id 0", __func__); + } else { + result = g_dbus_proxy_call_sync(s->dbus.proxy, "MUA_init", + g_variant_new ("(s)", "1234"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &err); + if (!result) { + error_report("%s: Failed to Load: %s", __func__, err->message); + g_object_unref(s->dbus.proxy); + s->dbus.proxy = NULL; + } + g_signal_connect(s->dbus.proxy, + "g-signal", + G_CALLBACK (on_signal), + s); + } + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + memory_region_init_io(&s->iomem, obj, &dbus_client_mua_ops, s, TYPE_DBUS_CLIENT_MUA, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); +} + +static void dbus_client_mua_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &dbus_client_mua_vm; +} + +static const TypeInfo dbus_client_mua_info = { + .name = TYPE_DBUS_CLIENT_MUA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DBUSCLIENTMUAState), + .instance_init = dbus_client_mua_init, + .class_init = dbus_client_mua_class_init +}; + + +static void dbus_client_mua_types(void) +{ + type_register_static(&dbus_client_mua_info); +} + +type_init(dbus_client_mua_types) diff --git a/hw/misc/dbus_client_mub.c b/hw/misc/dbus_client_mub.c new file mode 100644 index 000000000000..47a5e625471f --- /dev/null +++ b/hw/misc/dbus_client_mub.c @@ -0,0 +1,181 @@ +/* + * QEMU dbus_client_mub.c + * + * Copyright (C) 2022 NXP + * + * 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 +#include +#include +#include + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/dbus.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qapi/qmp/qerror.h" +#include "qom/object.h" +#include "hw/misc/dbus_client.h" +#include "hw/irq.h" +#include "migration/vmstate.h" + +static uint64_t dbus_client_mub_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint32_t ret = 0; + g_autoptr(GError) err = NULL; + g_autoptr(GVariant) result = NULL; + g_autoptr(GVariant) value = NULL; + DBUSCLIENTMUBState *s = DBUS_CLIENT_MUB(opaque); + + if (!s->dbus.proxy) { + return ret; + } else { + result = g_dbus_proxy_call_sync(s->dbus.proxy, "MUBRead", + g_variant_new("(t)", offset), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &err); + + if (!result) { + error_report("%s: Failed to Load: %s", __func__, err->message); + return -1; + } + + g_variant_get(result, "(u)", &ret); + } + + return ret; +} + + +static void dbus_client_mub_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + DBUSCLIENTMUBState *s = DBUS_CLIENT_MUB(opaque); + + if (!s->dbus.proxy) { + return; + } else { + g_autoptr(GError) err = NULL; + g_autoptr(GVariant) result = NULL; + + /* TODO need process clear irq if needed */ + + /* write to dbus */ + result = g_dbus_proxy_call_sync(s->dbus.proxy, "MUBWrite", + g_variant_new("(tt)", + offset, value), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &err); + if (!result) { + error_report("%s: Failed to Load: %s", __func__, err->message); + } + } + return; +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + gchar *parameters_str; + DBUSCLIENTMUBState *s = (DBUSCLIENTMUBState *)user_data; + + parameters_str = g_variant_print (parameters, TRUE); + g_print (" *** Received Signal: %s: %s\n", + signal_name, + parameters_str); + g_free (parameters_str); + + qemu_irq_raise(s->irq); +} + + +static const MemoryRegionOps dbus_client_mub_ops = { + .read = dbus_client_mub_read, + .write = dbus_client_mub_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription dbus_client_mub_vm = { + .name = TYPE_DBUS_CLIENT_MUB, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + + +static void dbus_client_mub_init(Object *obj) +{ + g_autoptr(GHashTable) proxies = NULL; + g_autoptr(GError) err = NULL; + DBUSCLIENTMUBState *s = DBUS_CLIENT_MUB(obj); + g_autoptr(GVariant) result = NULL; + + /*find the TYPE_DBUS_OBJ object*/ + s->dbus.dbus_conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err); + g_assert_no_error(err); + + s->dbus.proxy = g_dbus_proxy_new_sync(s->dbus.dbus_conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* GDBusInterfaceInfo */ + "org.qemu.client", /* name */ + "/org/qemu/client", /* object path */ + "org.qemu.client.mub", /* interface */ + NULL, /* GCancellable */ + &err); + g_assert_no_error(err); + if (!s->dbus.proxy) { + warn_report("%s: Failed to find proxy Id 0", __func__); + } else { + result = g_dbus_proxy_call_sync(s->dbus.proxy, "MUB_init", + g_variant_new ("(s)", "1234"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &err); + if (!result) { + error_report("%s: Failed to call: %s", __func__, err->message); + g_object_unref(s->dbus.proxy); + s->dbus.proxy = NULL; + } + g_signal_connect(s->dbus.proxy, + "g-signal", + G_CALLBACK (on_signal), + s); + } + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + memory_region_init_io(&s->iomem, obj, &dbus_client_mub_ops, s, TYPE_DBUS_CLIENT_MUB, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); +} + + +static void dbus_client_mub_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &dbus_client_mub_vm; +} + +static const TypeInfo dbus_client_mub_info = { + .name = TYPE_DBUS_CLIENT_MUB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DBUSCLIENTMUBState), + .instance_init = dbus_client_mub_init, + .class_init = dbus_client_mub_class_init +}; + +static void dbus_client_mub_types(void) +{ + type_register_static(&dbus_client_mub_info); +} + +type_init(dbus_client_mub_types) diff --git a/hw/misc/fxos8700.c b/hw/misc/fxos8700.c new file mode 100644 index 000000000000..92638f8d38d2 --- /dev/null +++ b/hw/misc/fxos8700.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/misc/fxos8700.h" +#include "migration/vmstate.h" + + +static int fxos8700_event(I2CSlave *i2c, enum i2c_event event) +{ + FXOS8700State *s = FXOS8700(i2c); + + switch (event) { + case I2C_START_RECV: + break; + case I2C_START_SEND: + s->addr_byte = true; + break; + default: + break; + } + + return 0; +} + +static uint8_t fxos8700_recv(I2CSlave *i2c) +{ + FXOS8700State *s = FXOS8700(i2c); + uint8_t res; + + res = s->reg[s->reg_idx]; + s->reg_idx++; + + return res; +} + +static int fxos8700_send(I2CSlave *i2c, uint8_t data) +{ + FXOS8700State *s = FXOS8700(i2c); + + if (s->addr_byte) { + s->reg_idx = data; + s->addr_byte = false; + return 0; + } + + s->reg[s->reg_idx] = data; + s->reg_idx++; + return 0; +} + +static void fxos8700_reset(DeviceState *dev) +{ + FXOS8700State *s = FXOS8700(dev); + int i = 0; + + s->reg_idx = 0; + for (i = 0; i < FXOS8700_REG_SIZE; i++) { + s->reg[i] = 0; + } + /* STATUS register */ + s->reg[0] = 0xFF; /* data is always ready */ + + /* FAKE DATA */ + s->reg[1] = 0x5F; /* 8 MSBs of 14-bit sample */ + s->reg[2] = 0x1F; /* 6 LSBs of 14-bit real-time sample */ + s->reg[3] = 0x5F; /* 8 MSBs */ + s->reg[4] = 0x1F; /* 6 LSBS */ + s->reg[5] = 0x5F; /* 8 MSBs */ + s->reg[6] = 0x1F; /* 6 LSBs */ + s->reg[0x0D] = 0xC7; /* WHO_AMI_I */ + s->reg[0x11] = 0x80; /* Landscape/portrait configuration */ + s->reg[0x13] = 0x84; /* Back/front trip angle threshold */ + s->reg[0x14] = 0x44; /* Portrait to landscape trip threshold angle and hysteresis settings */ + /* magnetic data */ + s->reg[0x33] = 0x55; + s->reg[0x34] = 0x55; + s->reg[0x35] = 0x55; + s->reg[0x36] = 0x55; + s->reg[0x37] = 0x55; + s->reg[0x38] = 0x55; + /* accerleration data */ + s->reg[0x39] = 0x55; + s->reg[0x3A] = 0x55; + s->reg[0x3B] = 0x55; + s->reg[0x3C] = 0x55; + s->reg[0x3D] = 0x55; + s->reg[0x3E] = 0x55; + /* Magnetometer */ + s->reg[0x45] = 0x55; + s->reg[0x46] = 0x55; + s->reg[0x47] = 0x55; + s->reg[0x48] = 0x55; + s->reg[0x49] = 0x55; + s->reg[0x4A] = 0x55; + s->reg[0x4B] = 0x55; + s->reg[0x4C] = 0x55; + s->reg[0x4D] = 0x55; + s->reg[0x4E] = 0x55; + s->reg[0x4F] = 0x55; + s->reg[0x50] = 0x55; + +} + +static const VMStateDescription vmstate_fxos8700 = { + .name = "fxos8700", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_I2C_SLAVE(parent_obj, FXOS8700State), + VMSTATE_UINT8_ARRAY(reg, FXOS8700State, FXOS8700_REG_SIZE), + VMSTATE_UINT32(reg_idx, FXOS8700State), + VMSTATE_BOOL(addr_byte, FXOS8700State), + VMSTATE_END_OF_LIST() + } +}; + +static void fxos8700_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = fxos8700_event; + k->recv = fxos8700_recv; + k->send = fxos8700_send; + dc->reset = fxos8700_reset; + dc->vmsd = &vmstate_fxos8700; +} + +static const TypeInfo fxos8700_info = { + .name = TYPE_FXOS8700, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(FXOS8700State), + .class_init = fxos8700_class_init, +}; + +static void fxos8700_register_types(void) +{ + type_register_static(&fxos8700_info); +} + +type_init(fxos8700_register_types) diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index 43e001c3c7b7..5b05f158592f 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/imx6_src.c b/hw/misc/imx6_src.c index 7b0e968804a7..a9c64d06ebcf 100644 --- a/hw/misc/imx6_src.c +++ b/hw/misc/imx6_src.c @@ -15,7 +15,7 @@ #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" -#include "arm-powerctl.h" +#include "target/arm/arm-powerctl.h" #include "hw/core/cpu.h" #ifndef DEBUG_IMX6_SRC diff --git a/hw/misc/imx6ul_ccm.c b/hw/misc/imx6ul_ccm.c index a65d03145567..e01bb68ac729 100644 --- a/hw/misc/imx6ul_ccm.c +++ b/hw/misc/imx6ul_ccm.c @@ -522,12 +522,6 @@ static uint32_t imx6ul_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) case CLK_32k: freq = CKIL_FREQ; break; - case CLK_HIGH: - freq = CKIH_FREQ; - break; - case CLK_HIGH_DIV: - freq = CKIH_FREQ / 8; - break; default: qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n", TYPE_IMX6UL_CCM, __func__, clock); diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c index 075159e497b1..f135ec7b7e40 100644 --- a/hw/misc/imx7_ccm.c +++ b/hw/misc/imx7_ccm.c @@ -16,6 +16,10 @@ #include "hw/misc/imx7_ccm.h" #include "migration/vmstate.h" +#include "trace.h" + +#define CKIH_FREQ 24000000 /* 24MHz crystal input */ + static void imx7_analog_reset(DeviceState *dev) { IMX7AnalogState *s = IMX7_ANALOG(dev); @@ -219,16 +223,43 @@ static const VMStateDescription vmstate_imx7_ccm = { static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) { /* - * This function is "consumed" by GPT emulation code, however on - * i.MX7 each GPT block can have their own clock root. This means - * that this functions needs somehow to know requester's identity - * and the way to pass it: be it via additional IMXClk constants - * or by adding another argument to this method needs to be - * figured out + * This function is "consumed" by GPT emulation code. Some clocks + * have fixed frequencies and we can provide requested frequency + * easily. However for CCM provided clocks (like IPG) each GPT + * timer can have its own clock root. + * This means we need additionnal information when calling this + * function to know the requester's identity. */ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n", - TYPE_IMX7_CCM, __func__); - return 0; + uint32_t freq = 0; + + switch (clock) { + case CLK_NONE: + break; + case CLK_32k: + freq = CKIL_FREQ; + break; + case CLK_HIGH: + freq = CKIH_FREQ; + break; + case CLK_IPG: + case CLK_IPG_HIGH: + /* + * For now we don't have a way to figure out the device this + * function is called for. Until then the IPG derived clocks + * are left unimplemented. + */ + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n", + TYPE_IMX7_CCM, __func__, clock); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n", + TYPE_IMX7_CCM, __func__, clock); + break; + } + + trace_ccm_clock_freq(clock, freq); + + return freq; } static void imx7_ccm_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index 7b41cfa8fc50..b5a9e30a2c69 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 9ee8fe8495ce..e664215ee678 100644 --- a/hw/misc/iotkit-sysctl.c +++ b/hw/misc/iotkit-sysctl.c @@ -30,7 +30,6 @@ #include "hw/qdev-properties.h" #include "hw/arm/armsse-version.h" #include "target/arm/arm-powerctl.h" -#include "target/arm/cpu.h" REG32(SECDBGSTAT, 0x0) REG32(SECDBGSET, 0x4) @@ -237,7 +236,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 +554,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/ivshmem.c b/hw/misc/ivshmem.c index e7c0099bdaf6..8270db53cda7 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -537,7 +537,7 @@ static void process_msg_connect(IVShmemState *s, uint16_t posn, int fd, IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd); event_notifier_init_fd(&peer->eventfds[vector], fd); - fcntl_setfl(fd, O_NONBLOCK); /* msix/irqfd poll non block */ + g_unix_set_fd_nonblocking(fd, true, NULL); /* msix/irqfd poll non block */ if (posn == s->vm_id) { setup_interrupt(s, vector, errp); diff --git a/hw/misc/lasi.c b/hw/misc/lasi.c new file mode 100644 index 000000000000..23a7634a8c3a --- /dev/null +++ b/hw/misc/lasi.c @@ -0,0 +1,274 @@ +/* + * HP-PARISC Lasi chipset emulation. + * + * (C) 2019 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Documentation available at: + * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/irq.h" +#include "sysemu/sysemu.h" +#include "sysemu/runstate.h" +#include "migration/vmstate.h" +#include "qom/object.h" +#include "hw/misc/lasi.h" + + +static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, + unsigned size, bool is_write, + MemTxAttrs attrs) +{ + bool ret = false; + + switch (addr) { + case LASI_IRR: + case LASI_IMR: + case LASI_IPR: + case LASI_ICR: + case LASI_IAR: + + case LASI_LPT: + case LASI_UART: + case LASI_LAN: + case LASI_RTC: + + case LASI_PCR ... LASI_AMR: + ret = true; + } + + trace_lasi_chip_mem_valid(addr, ret); + return ret; +} + +static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + LasiState *s = opaque; + MemTxResult ret = MEMTX_OK; + uint32_t val; + + switch (addr) { + case LASI_IRR: + val = s->irr; + break; + case LASI_IMR: + val = s->imr; + break; + case LASI_IPR: + val = s->ipr; + /* Any read to IPR clears the register. */ + s->ipr = 0; + break; + case LASI_ICR: + val = s->icr & ICR_BUS_ERROR_BIT; /* bus_error */ + break; + case LASI_IAR: + val = s->iar; + break; + + case LASI_LPT: + case LASI_UART: + case LASI_LAN: + val = 0; + break; + case LASI_RTC: + val = time(NULL); + val += s->rtc_ref; + break; + + case LASI_PCR: + case LASI_VER: /* only version 0 existed. */ + case LASI_IORESET: + val = 0; + break; + case LASI_ERRLOG: + val = s->errlog; + break; + case LASI_AMR: + val = s->amr; + break; + + default: + /* Controlled by lasi_chip_mem_valid above. */ + g_assert_not_reached(); + } + + trace_lasi_chip_read(addr, val); + + *data = val; + return ret; +} + +static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, + uint64_t val, unsigned size, + MemTxAttrs attrs) +{ + LasiState *s = opaque; + + trace_lasi_chip_write(addr, val); + + switch (addr) { + case LASI_IRR: + /* read-only. */ + break; + case LASI_IMR: + s->imr = val; + if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) { + qemu_log_mask(LOG_GUEST_ERROR, + "LASI: tried to set invalid %lx IMR value.\n", + (unsigned long) val); + } + break; + case LASI_IPR: + /* Any write to IPR clears the register. */ + s->ipr = 0; + break; + case LASI_ICR: + s->icr = val; + /* if (val & ICR_TOC_BIT) issue_toc(); */ + break; + case LASI_IAR: + s->iar = val; + break; + + case LASI_LPT: + /* XXX: reset parallel port */ + break; + case LASI_UART: + /* XXX: reset serial port */ + break; + case LASI_LAN: + /* XXX: reset LAN card */ + break; + case LASI_RTC: + s->rtc_ref = val - time(NULL); + break; + + case LASI_PCR: + if (val == 0x02) { /* immediately power off */ + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } + break; + case LASI_ERRLOG: + s->errlog = val; + break; + case LASI_VER: + /* read-only. */ + break; + case LASI_IORESET: + break; /* XXX: TODO: Reset various devices. */ + case LASI_AMR: + s->amr = val; + break; + + default: + /* Controlled by lasi_chip_mem_valid above. */ + g_assert_not_reached(); + } + return MEMTX_OK; +} + +static const MemoryRegionOps lasi_chip_ops = { + .read_with_attrs = lasi_chip_read_with_attrs, + .write_with_attrs = lasi_chip_write_with_attrs, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .accepts = lasi_chip_mem_valid, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +static const VMStateDescription vmstate_lasi = { + .name = "Lasi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(irr, LasiState), + VMSTATE_UINT32(imr, LasiState), + VMSTATE_UINT32(ipr, LasiState), + VMSTATE_UINT32(icr, LasiState), + VMSTATE_UINT32(iar, LasiState), + VMSTATE_UINT32(errlog, LasiState), + VMSTATE_UINT32(amr, LasiState), + VMSTATE_END_OF_LIST() + } +}; + + +static void lasi_set_irq(void *opaque, int irq, int level) +{ + LasiState *s = opaque; + uint32_t bit = 1u << irq; + + if (level) { + s->ipr |= bit; + if (bit & s->imr) { + uint32_t iar = s->iar; + s->irr |= bit; + if ((s->icr & ICR_BUS_ERROR_BIT) == 0) { + stl_be_phys(&address_space_memory, iar & -32, iar & 31); + } + } + } +} + +static void lasi_reset(DeviceState *dev) +{ + LasiState *s = LASI_CHIP(dev); + + s->iar = 0xFFFB0000 + 3; /* CPU_HPA + 3 */ + + /* Real time clock (RTC), it's only one 32-bit counter @9000 */ + s->rtc = time(NULL); + s->rtc_ref = 0; +} + +static void lasi_init(Object *obj) +{ + LasiState *s = LASI_CHIP(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops, + s, "lasi", 0x100000); + + sysbus_init_mmio(sbd, &s->this_mem); + + qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS); +} + +static void lasi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = lasi_reset; + dc->vmsd = &vmstate_lasi; +} + +static const TypeInfo lasi_pcihost_info = { + .name = TYPE_LASI_CHIP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = lasi_init, + .instance_size = sizeof(LasiState), + .class_init = lasi_class_init, +}; + +static void lasi_register_types(void) +{ + type_register_static(&lasi_pcihost_info); +} + +type_init(lasi_register_types) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 525e38ce9322..076d18e5fd9f 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -351,7 +351,7 @@ static void via1_one_second(void *opaque) static void pram_update(MOS6522Q800VIA1State *v1s) { if (v1s->blk) { - if (blk_pwrite(v1s->blk, 0, v1s->PRAM, sizeof(v1s->PRAM), 0) < 0) { + if (blk_pwrite(v1s->blk, 0, sizeof(v1s->PRAM), v1s->PRAM, 0) < 0) { qemu_log("pram_update: cannot write to file\n"); } } @@ -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; @@ -975,14 +975,16 @@ static int via1_post_load(void *opaque, int version_id) } /* VIA 1 */ -static void mos6522_q800_via1_reset(DeviceState *dev) +static void mos6522_q800_via1_reset_hold(Object *obj) { - MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(dev); + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(obj); MOS6522State *ms = MOS6522(v1s); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); ADBBusState *adb_bus = &v1s->adb_bus; - mdc->parent_reset(dev); + if (mdc->parent_phases.hold) { + mdc->parent_phases.hold(obj); + } ms->timers[0].frequency = VIA_TIMER_FREQ; ms->timers[1].frequency = VIA_TIMER_FREQ; @@ -1029,8 +1031,8 @@ static void mos6522_q800_via1_realize(DeviceState *dev, Error **errp) return; } - len = blk_pread(v1s->blk, 0, v1s->PRAM, sizeof(v1s->PRAM)); - if (len != sizeof(v1s->PRAM)) { + ret = blk_pread(v1s->blk, 0, sizeof(v1s->PRAM), v1s->PRAM, 0); + if (ret < 0) { error_setg(errp, "can't read PRAM contents"); return; } @@ -1097,11 +1099,12 @@ static Property mos6522_q800_via1_properties[] = { static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); dc->realize = mos6522_q800_via1_realize; - device_class_set_parent_reset(dc, mos6522_q800_via1_reset, - &mdc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, mos6522_q800_via1_reset_hold, + NULL, &mdc->parent_phases); dc->vmsd = &vmstate_q800_via1; device_class_set_props(dc, mos6522_q800_via1_properties); } @@ -1123,12 +1126,14 @@ static void mos6522_q800_via2_portB_write(MOS6522State *s) } } -static void mos6522_q800_via2_reset(DeviceState *dev) +static void mos6522_q800_via2_reset_hold(Object *obj) { - MOS6522State *ms = MOS6522(dev); + MOS6522State *ms = MOS6522(obj); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); - mdc->parent_reset(dev); + if (mdc->parent_phases.hold) { + mdc->parent_phases.hold(obj); + } ms->timers[0].frequency = VIA_TIMER_FREQ; ms->timers[1].frequency = VIA_TIMER_FREQ; @@ -1183,10 +1188,11 @@ static const VMStateDescription vmstate_q800_via2 = { static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); - device_class_set_parent_reset(dc, mos6522_q800_via2_reset, - &mdc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, mos6522_q800_via2_reset_hold, + NULL, &mdc->parent_phases); dc->vmsd = &vmstate_q800_via2; mdc->portB_write = mos6522_q800_via2_portB_write; } diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 1498113cfc51..853e88bfeddc 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/ppc/mac.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/input/adb.h" @@ -590,12 +589,14 @@ static void mos6522_cuda_portB_write(MOS6522State *s) cuda_update(cs); } -static void mos6522_cuda_reset(DeviceState *dev) +static void mos6522_cuda_reset_hold(Object *obj) { - MOS6522State *ms = MOS6522(dev); + MOS6522State *ms = MOS6522(obj); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); - mdc->parent_reset(dev); + if (mdc->parent_phases.hold) { + mdc->parent_phases.hold(obj); + } ms->timers[0].frequency = CUDA_TIMER_FREQ; ms->timers[1].frequency = (SCALE_US * 6000) / 4700; @@ -603,11 +604,11 @@ static void mos6522_cuda_reset(DeviceState *dev) static void mos6522_cuda_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); - device_class_set_parent_reset(dc, mos6522_cuda_reset, - &mdc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, mos6522_cuda_reset_hold, + NULL, &mdc->parent_phases); mdc->portB_write = mos6522_cuda_portB_write; mdc->get_timer1_counter_value = cuda_get_counter_value; mdc->get_timer2_counter_value = cuda_get_counter_value; diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index b1bcf830c38a..c8ac5633b2f4 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "hw/ppc/mac.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/misc/macio/macio.h" diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index c1fad43f6c68..08dbdd7fc05b 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "hw/ppc/mac.h" #include "hw/misc/macio/cuda.h" #include "hw/pci/pci.h" #include "hw/ppc/mac_dbdma.h" @@ -37,8 +36,9 @@ #include "hw/intc/heathrow_pic.h" #include "trace.h" -/* Note: this code is strongly inspirated from the corresponding code - * in PearPC */ +#define ESCC_CLOCK 3686400 + +/* Note: this code is strongly inspired by the corresponding code in PearPC */ /* * The mac-io has two interfaces to the ESCC. One is called "escc-legacy", @@ -226,7 +226,7 @@ static void macio_oldworld_init(Object *obj) object_initialize_child(OBJECT(s), "nvram", &os->nvram, TYPE_MACIO_NVRAM); dev = DEVICE(&os->nvram); - qdev_prop_set_uint32(dev, "size", 0x2000); + qdev_prop_set_uint32(dev, "size", MACIO_NVRAM_SIZE); qdev_prop_set_uint32(dev, "it_shift", 4); for (i = 0; i < 2; i++) { diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 336502a84b58..97ef8c771b65 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -29,7 +29,6 @@ */ #include "qemu/osdep.h" -#include "hw/ppc/mac.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/input/adb.h" @@ -798,14 +797,16 @@ static void mos6522_pmu_portB_write(MOS6522State *s) pmu_update(ps); } -static void mos6522_pmu_reset(DeviceState *dev) +static void mos6522_pmu_reset_hold(Object *obj) { - MOS6522State *ms = MOS6522(dev); + MOS6522State *ms = MOS6522(obj); MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj); PMUState *s = container_of(mps, PMUState, mos6522_pmu); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); - mdc->parent_reset(dev); + if (mdc->parent_phases.hold) { + mdc->parent_phases.hold(obj); + } ms->timers[0].frequency = VIA_TIMER_FREQ; ms->timers[1].frequency = (SCALE_US * 6000) / 4700; @@ -815,11 +816,11 @@ static void mos6522_pmu_reset(DeviceState *dev) static void mos6522_pmu_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); - device_class_set_parent_reset(dc, mos6522_pmu_reset, - &mdc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, mos6522_pmu_reset_hold, + NULL, &mdc->parent_phases); mdc->portB_write = mos6522_pmu_portB_write; } diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c index f4fd55a0e5c7..a71d134295ab 100644 --- a/hw/misc/mchp_pfsoc_ioscb.c +++ b/hw/misc/mchp_pfsoc_ioscb.c @@ -24,6 +24,7 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qapi/error.h" +#include "hw/irq.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_ioscb.h" @@ -33,6 +34,10 @@ */ #define IOSCB_WHOLE_REG_SIZE 0x10000000 #define IOSCB_SUBMOD_REG_SIZE 0x1000 +#define IOSCB_CCC_REG_SIZE 0x2000000 +#define IOSCB_CTRL_REG_SIZE 0x800 +#define IOSCB_QSPIXIP_REG_SIZE 0x200 + /* * There are many sub-modules in the IOSCB module. @@ -44,7 +49,10 @@ #define IOSCB_LANE01_BASE 0x06500000 #define IOSCB_LANE23_BASE 0x06510000 #define IOSCB_CTRL_BASE 0x07020000 +#define IOSCB_QSPIXIP_BASE 0x07020100 +#define IOSCB_MAILBOX_BASE 0x07020800 #define IOSCB_CFG_BASE 0x07080000 +#define IOSCB_CCC_BASE 0x08000000 #define IOSCB_PLL_MSS_BASE 0x0E001000 #define IOSCB_CFM_MSS_BASE 0x0E002000 #define IOSCB_PLL_DDR_BASE 0x0E010000 @@ -141,6 +149,58 @@ static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +#define SERVICES_CR 0x50 +#define SERVICES_SR 0x54 +#define SERVICES_STATUS_SHIFT 16 + +static uint64_t mchp_pfsoc_ctrl_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint32_t val = 0; + + switch (offset) { + case SERVICES_SR: + /* + * Although some services have no error codes, most do. All services + * that do implement errors, begin their error codes at 1. Treat all + * service requests as failures & return 1. + * See the "PolarFire® FPGA and PolarFire SoC FPGA System Services" + * user guide for more information on service error codes. + */ + val = 1u << SERVICES_STATUS_SHIFT; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " + "(size %d, offset 0x%" HWADDR_PRIx ")\n", + __func__, size, offset); + } + + return val; +} + +static void mchp_pfsoc_ctrl_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + MchpPfSoCIoscbState *s = opaque; + + switch (offset) { + case SERVICES_CR: + qemu_irq_raise(s->irq); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " + "(size %d, value 0x%" PRIx64 + ", offset 0x%" HWADDR_PRIx ")\n", + __func__, size, value, offset); + } +} + +static const MemoryRegionOps mchp_pfsoc_ctrl_ops = { + .read = mchp_pfsoc_ctrl_read, + .write = mchp_pfsoc_ctrl_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) { MchpPfSoCIoscbState *s = MCHP_PFSOC_IOSCB(dev); @@ -160,14 +220,26 @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) "mchp.pfsoc.ioscb.lane23", IOSCB_SUBMOD_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_LANE23_BASE, &s->lane23); - memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_dummy_ops, s, - "mchp.pfsoc.ioscb.ctrl", IOSCB_SUBMOD_REG_SIZE); + memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_ctrl_ops, s, + "mchp.pfsoc.ioscb.ctrl", IOSCB_CTRL_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_CTRL_BASE, &s->ctrl); + memory_region_init_io(&s->qspixip, OBJECT(s), &mchp_pfsoc_dummy_ops, s, + "mchp.pfsoc.ioscb.qspixip", IOSCB_QSPIXIP_REG_SIZE); + memory_region_add_subregion(&s->container, IOSCB_QSPIXIP_BASE, &s->qspixip); + + memory_region_init_io(&s->mailbox, OBJECT(s), &mchp_pfsoc_dummy_ops, s, + "mchp.pfsoc.ioscb.mailbox", IOSCB_SUBMOD_REG_SIZE); + memory_region_add_subregion(&s->container, IOSCB_MAILBOX_BASE, &s->mailbox); + memory_region_init_io(&s->cfg, OBJECT(s), &mchp_pfsoc_dummy_ops, s, "mchp.pfsoc.ioscb.cfg", IOSCB_SUBMOD_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_CFG_BASE, &s->cfg); + memory_region_init_io(&s->ccc, OBJECT(s), &mchp_pfsoc_dummy_ops, s, + "mchp.pfsoc.ioscb.ccc", IOSCB_CCC_REG_SIZE); + memory_region_add_subregion(&s->container, IOSCB_CCC_BASE, &s->ccc); + memory_region_init_io(&s->pll_mss, OBJECT(s), &mchp_pfsoc_pll_ops, s, "mchp.pfsoc.ioscb.pll_mss", IOSCB_SUBMOD_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_PLL_MSS_BASE, &s->pll_mss); @@ -216,6 +288,8 @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) IOSCB_SUBMOD_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_SGMII_BASE, &s->io_calib_sgmii); + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); } static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c index 89571eded53f..7876fe0c5ba3 100644 --- a/hw/misc/mchp_pfsoc_sysreg.c +++ b/hw/misc/mchp_pfsoc_sysreg.c @@ -24,10 +24,12 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qapi/error.h" +#include "hw/irq.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_sysreg.h" #define ENVM_CR 0xb8 +#define MESSAGE_INT 0x118c static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset, unsigned size) @@ -52,10 +54,17 @@ static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset, static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " - "(size %d, value 0x%" PRIx64 - ", offset 0x%" HWADDR_PRIx ")\n", - __func__, size, value, offset); + MchpPfSoCSysregState *s = opaque; + switch (offset) { + case MESSAGE_INT: + qemu_irq_lower(s->irq); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " + "(size %d, value 0x%" PRIx64 + ", offset 0x%" HWADDR_PRIx ")\n", + __func__, size, value, offset); + } } static const MemoryRegionOps mchp_pfsoc_sysreg_ops = { @@ -73,6 +82,7 @@ static void mchp_pfsoc_sysreg_realize(DeviceState *dev, Error **errp) "mchp.pfsoc.sysreg", MCHP_PFSOC_SYSREG_REG_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sysreg); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); } static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 6fb69612e064..11704b34222a 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -38,11 +38,14 @@ subdir('macio') softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) +softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c')) +softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_DRAMC', if_true: files('allwinner-a10-dramc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-ccu.c')) specific_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-cpucfg.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c')) +softmmu_ss.add(when: 'CONFIG_AXP209_PMU', if_true: files('axp209.c')) softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c')) softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c')) softmmu_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c')) @@ -51,6 +54,7 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx25_ccm.c', 'imx31_ccm.c', 'imx6_ccm.c', + 'imx6_src.c', 'imx6ul_ccm.c', 'imx7_ccm.c', 'imx7_gpr.c', @@ -84,8 +88,9 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( )) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c')) -specific_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) -specific_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) +specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-crl.c')) softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files( 'xlnx-versal-xramc.c', 'xlnx-versal-pmc-iou-slcr.c', @@ -100,6 +105,7 @@ softmmu_ss.add(when: 'CONFIG_TZ_MPC', if_true: files('tz-mpc.c')) softmmu_ss.add(when: 'CONFIG_TZ_MSC', if_true: files('tz-msc.c')) softmmu_ss.add(when: 'CONFIG_TZ_PPC', if_true: files('tz-ppc.c')) softmmu_ss.add(when: 'CONFIG_IOTKIT_SECCTL', if_true: files('iotkit-secctl.c')) +softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSCTL', if_true: files('iotkit-sysctl.c')) softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSINFO', if_true: files('iotkit-sysinfo.c')) softmmu_ss.add(when: 'CONFIG_ARMSSE_CPU_PWRCTRL', if_true: files('armsse-cpu-pwrctrl.c')) softmmu_ss.add(when: 'CONFIG_ARMSSE_CPUID', if_true: files('armsse-cpuid.c')) @@ -115,21 +121,29 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_scu.c', 'aspeed_sbc.c', 'aspeed_sdmc.c', - 'aspeed_xdma.c')) + 'aspeed_xdma.c', + 'aspeed_peci.c')) softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c')) softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) +softmmu_ss.add(when: 'CONFIG_DBUS_CLIENT', if_true: files('dbus_client_mua.c', 'dbus_client_mub.c')) +softmmu_ss.add(when: 'CONFIG_RT_SYSCTL', if_true: files('rt_sysctl.c')) +softmmu_ss.add(when: 'CONFIG_RT_RSTCTL', if_true: files('rt_rstctl.c')) +softmmu_ss.add(when: 'CONFIG_RT_CLKCTL', if_true: files('rt_clkctl.c')) +softmmu_ss.add(when: 'CONFIG_RT_PMC', if_true: files('rt_pmc.c')) +softmmu_ss.add(when: 'CONFIG_FXOS8700', if_true: files('fxos8700.c')) +softmmu_ss.add(when: 'CONFIG_PCA9420', if_true: files('pca9420.c')) specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c')) -specific_ss.add(when: 'CONFIG_IMX', if_true: files('imx6_src.c')) -specific_ss.add(when: 'CONFIG_IOTKIT_SYSCTL', if_true: files('iotkit-sysctl.c')) - specific_ss.add(when: 'CONFIG_MAC_VIA', if_true: files('mac_via.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cpc.c')) specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) -specific_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) +softmmu_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) + +# HPPA devices +softmmu_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c index 80683fed318b..badef5c214af 100644 --- a/hw/misc/mips_itu.c +++ b/hw/misc/mips_itu.c @@ -189,7 +189,8 @@ static void wake_blocked_threads(ITCStorageCell *c) c->blocked_threads = 0; } -static void QEMU_NORETURN block_thread_and_exit(ITCStorageCell *c) +static G_NORETURN +void block_thread_and_exit(ITCStorageCell *c) { c->blocked_threads |= 1ULL << current_cpu->cpu_index; current_cpu->halted = 1; diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index f9e646350e67..0ed631186c35 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 = { @@ -643,9 +643,9 @@ const VMStateDescription vmstate_mos6522 = { } }; -static void mos6522_reset(DeviceState *dev) +static void mos6522_reset_hold(Object *obj) { - MOS6522State *s = MOS6522(dev); + MOS6522State *s = MOS6522(obj); s->b = 0; s->a = 0; @@ -705,9 +705,10 @@ static Property mos6522_properties[] = { static void mos6522_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); - dc->reset = mos6522_reset; + rc->phases.hold = mos6522_reset_hold; dc->vmsd = &vmstate_mos6522; device_class_set_props(dc, mos6522_properties); mdc->portB_write = mos6522_portB_write; diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c index 10de7a55236a..67158eb16497 100644 --- a/hw/misc/omap_gpmc.c +++ b/hw/misc/omap_gpmc.c @@ -126,7 +126,7 @@ static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value) static uint64_t omap_nand_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; + struct omap_gpmc_cs_file_s *f = opaque; uint64_t v; nand_setpins(f->dev, 0, 0, 0, 1, 0); switch (omap_gpmc_devsize(f)) { @@ -205,7 +205,7 @@ static void omap_nand_setio(DeviceState *dev, uint64_t value, static void omap_nand_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; + struct omap_gpmc_cs_file_s *f = opaque; nand_setpins(f->dev, 0, 0, 0, 1, 0); omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); } @@ -290,7 +290,7 @@ static void fill_prefetch_fifo(struct omap_gpmc_s *s) static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + struct omap_gpmc_s *s = opaque; uint32_t data; if (s->prefetch.config1 & 1) { /* The TRM doesn't define the behaviour if you read from the @@ -320,7 +320,7 @@ static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr, static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + struct omap_gpmc_s *s = opaque; int cs = prefetch_cs(s->prefetch.config1); if ((s->prefetch.config1 & 1) == 0) { /* The TRM doesn't define the behaviour of writing to the @@ -509,7 +509,7 @@ static int gpmc_wordaccess_only(hwaddr addr) static uint64_t omap_gpmc_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + struct omap_gpmc_s *s = opaque; int cs; struct omap_gpmc_cs_file_s *f; @@ -621,7 +621,7 @@ static uint64_t omap_gpmc_read(void *opaque, hwaddr addr, static void omap_gpmc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + struct omap_gpmc_s *s = opaque; int cs; struct omap_gpmc_cs_file_s *f; diff --git a/hw/misc/omap_l4.c b/hw/misc/omap_l4.c index 54aeaecd6963..b7875489da31 100644 --- a/hw/misc/omap_l4.c +++ b/hw/misc/omap_l4.c @@ -52,10 +52,9 @@ hwaddr omap_l4_region_size(struct omap_target_agent_s *ta, return ta->start[region].size; } -static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; + struct omap_target_agent_s *s = opaque; if (size != 2) { return omap_badwidth_read16(opaque, addr); @@ -79,7 +78,7 @@ static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, static void omap_l4ta_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; + struct omap_target_agent_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); diff --git a/hw/misc/omap_sdrc.c b/hw/misc/omap_sdrc.c index f2f72f6810bb..6aa1b3ef7fb8 100644 --- a/hw/misc/omap_sdrc.c +++ b/hw/misc/omap_sdrc.c @@ -31,10 +31,9 @@ void omap_sdrc_reset(struct omap_sdrc_s *s) s->config = 0x10; } -static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; + struct omap_sdrc_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); @@ -89,7 +88,7 @@ static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, static void omap_sdrc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; + struct omap_sdrc_s *s = opaque; if (size != 4) { omap_badwidth_write32(opaque, addr, value); diff --git a/hw/misc/omap_tap.c b/hw/misc/omap_tap.c index 3f595e8df7e4..4d7fb7d85f10 100644 --- a/hw/misc/omap_tap.c +++ b/hw/misc/omap_tap.c @@ -23,10 +23,9 @@ #include "hw/arm/omap.h" /* TEST-Chip-level TAP */ -static uint64_t omap_tap_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_tap_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + struct omap_mpu_state_s *s = opaque; if (size != 4) { return omap_badwidth_read32(opaque, addr); diff --git a/hw/misc/pca9420.c b/hw/misc/pca9420.c new file mode 100644 index 000000000000..691ced20f0d3 --- /dev/null +++ b/hw/misc/pca9420.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/misc/pca9420.h" +#include "migration/vmstate.h" + + +static int pca9420_event(I2CSlave *i2c, enum i2c_event event) +{ + PCA9420State *s = PCA9420(i2c); + + switch (event) { + case I2C_START_RECV: + break; + case I2C_START_SEND: + s->addr_byte = true; + break; + default: + break; + } + + return 0; +} + +static uint8_t pca9420_recv(I2CSlave *i2c) +{ + PCA9420State *s = PCA9420(i2c); + uint8_t res; + + res = s->reg[s->reg_idx]; + s->reg_idx++; + + return res; +} + +static int pca9420_send(I2CSlave *i2c, uint8_t data) +{ + PCA9420State *s = PCA9420(i2c); + + if (s->addr_byte) { + s->reg_idx = data; + s->addr_byte = false; + return 0; + } + + s->reg[s->reg_idx] = data; + s->reg_idx++; + return 0; +} + +static void pca9420_reset(DeviceState *dev) +{ + PCA9420State *s = PCA9420(dev); + int i = 0; + + s->addr_byte = false; + s->reg_idx = 0; + for (i = 0; i < PCA9420_REG_SIZE; i++) { + s->reg[i] = 0; + } + s->reg[3] = 0x3F; + s->reg[5] = 0x7F; + s->reg[7] = 0xFF; + s->reg[9] = 0x41; + + s->reg[0xA] = 0x89; + s->reg[0xB] = 0xAE; + s->reg[0xC] = 0x1; + s->reg[0x10] = 0x3; + s->reg[0x11] = 0x8; + s->reg[0x12] = 0x4; + s->reg[0x13] = 0x8; + s->reg[0x14] = 0x4; + + s->reg[0x15] = 0x1E; + s->reg[0x16] = 0x95; + s->reg[0x17] = 0x24; + s->reg[0x18] = 0x10; + + s->reg[0x1A] = 0x78; + s->reg[0x22] = 0x14; + s->reg[0x23] = 0x0C; + s->reg[0x24] = 0x4F; + + s->reg[0x25] = 0x39; + s->reg[0x26] = 0x1C; + s->reg[0x27] = 0x4C; + s->reg[0x28] = 0x4F; + s->reg[0x29] = 0x0C; + s->reg[0x2A] = 0x1C; + s->reg[0x2B] = 0x4C; + s->reg[0x2C] = 0x4F; + s->reg[0x2D] = 0x0C; + s->reg[0x2E] = 0x1C; + s->reg[0x2F] = 0x4C; + s->reg[0x30] = 0x4F; + s->reg[0x31] = 0x0C; +} + +static const VMStateDescription vmstate_pca9420 = { + .name = "pca9420", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_I2C_SLAVE(parent_obj, PCA9420State), + VMSTATE_UINT8_ARRAY(reg, PCA9420State, PCA9420_REG_SIZE), + VMSTATE_UINT32(reg_idx, PCA9420State), + VMSTATE_BOOL(addr_byte, PCA9420State), + VMSTATE_END_OF_LIST() + } +}; + +static void pca9420_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = pca9420_event; + k->recv = pca9420_recv; + k->send = pca9420_send; + dc->reset = pca9420_reset; + dc->vmsd = &vmstate_pca9420; +} + +static const TypeInfo pca9420_info = { + .name = TYPE_PCA9420, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(PCA9420State), + .class_init = pca9420_class_init, +}; + +static void pca9420_register_types(void) +{ + type_register_static(&pca9420_info); +} + +type_init(pca9420_register_types) diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 03845c8de343..49303134e4cb 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -19,7 +19,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "qemu/event_notifier.h" #include "qemu/module.h" diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c index b84d4d458d65..ccec50f61bbd 100644 --- a/hw/misc/pvpanic-isa.c +++ b/hw/misc/pvpanic-isa.c @@ -22,6 +22,7 @@ #include "qom/object.h" #include "hw/isa/isa.h" #include "standard-headers/linux/pvpanic.h" +#include "hw/acpi/acpi_aml_interface.h" OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE) @@ -63,6 +64,41 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(d, &ps->mr, s->ioport); } +static void build_pvpanic_isa_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + Aml *crs, *field, *method; + PVPanicISAState *s = PVPANIC_ISA_DEVICE(adev); + Aml *dev = aml_device("PEVT"); + + aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001"))); + + crs = aml_resource_template(); + aml_append(crs, + aml_io(AML_DECODE16, s->ioport, s->ioport, 1, 1) + ); + aml_append(dev, aml_name_decl("_CRS", crs)); + + aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO, + aml_int(s->ioport), 1)); + field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("PEPT", 8)); + aml_append(dev, field); + + /* device present, functioning, decoding, shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); + + method = aml_method("RDPT", 0, AML_NOTSERIALIZED); + aml_append(method, aml_store(aml_name("PEPT"), aml_local(0))); + aml_append(method, aml_return(aml_local(0))); + aml_append(dev, method); + + method = aml_method("WRPT", 1, AML_NOTSERIALIZED); + aml_append(method, aml_store(aml_arg(0), aml_name("PEPT"))); + aml_append(dev, method); + + aml_append(scope, dev); +} + static Property pvpanic_isa_properties[] = { DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505), DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events, @@ -73,10 +109,12 @@ static Property pvpanic_isa_properties[] = { static void pvpanic_isa_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); dc->realize = pvpanic_isa_realizefn; device_class_set_props(dc, pvpanic_isa_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); + adevc->build_dev_aml = build_pvpanic_isa_aml; } static const TypeInfo pvpanic_isa_info = { @@ -85,6 +123,10 @@ static const TypeInfo pvpanic_isa_info = { .instance_size = sizeof(PVPanicISAState), .instance_init = pvpanic_isa_initfn, .class_init = pvpanic_isa_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void pvpanic_register_types(void) diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c index 99cf7e20412b..fbcaa50731b3 100644 --- a/hw/misc/pvpanic-pci.c +++ b/hw/misc/pvpanic-pci.c @@ -20,7 +20,7 @@ #include "migration/vmstate.h" #include "hw/misc/pvpanic.h" #include "qom/object.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "standard-headers/linux/pvpanic.h" OBJECT_DECLARE_SIMPLE_TYPE(PVPanicPCIState, PVPANIC_PCI_DEVICE) diff --git a/hw/misc/rt_clkctl.c b/hw/misc/rt_clkctl.c new file mode 100644 index 000000000000..ae13bf565eab --- /dev/null +++ b/hw/misc/rt_clkctl.c @@ -0,0 +1,1502 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/misc/rt_clkctl.h" +#include "migration/vmstate.h" + + +#define RT_CLKCTL0_NAME "clock controllor0 for NXP RTxxx series" +#define RT_CLKCTL1_NAME "clock controllor1 for NXP RTxxx series" + +static uint64_t rt_clkctl0_read(void *opaque, hwaddr offset, unsigned size) +{ + RTCLKCTL0State *s = RT_CLKCTL0(opaque); + uint32_t value = 0xFEFEFEFE; + + switch(offset) { + case 0x10: + value = s->PSCCTL0; + break; + case 0x14: + value = s->PSCCTL1; + break; + case 0x18: + value = s->PSCCTL2; + break; + case 0x40: /* WO */ + break; + case 0x44: + break; + case 0x48: + break; + case 0x70: + break; + case 0x74: + break; + case 0x78: + break; + case 0x80: /* Enable Tuning */ + /* in qemu turning does not take time */ + value = s->FRO_CONTROL & (~0x80000000); + break; + case 0x84: + /* data is always valid */ + value = s->FRO_CAPVAL | 0x80000000; + break; + case 0x8C: + value = s->FRO_RDTRIM; + break; + case 0x90: + value = s->FRO_SCTRIM; + break; + case 0x108: + value = s->FRODIVSEL; + break; + case 0x10C: + /* always locked */ + value = 0x1; + break; + case 0x110: + value = s->FRODIVOEN; + break; + case 0x130: + value = s->LOWFREQCLKDIV & (~0xE0000000); + break; + case 0x160: + value = s->SYSOSCCTL0; + break; + case 0x168: + value = s->SYSOSCBYPASS; + break; + case 0x190: + value = s->LPOSCCTL0 | 0x80000000; + break; + case 0x1C0: + value = s->OSC32KHZCTL0; + break; + case 0x200: + value = s->SYSPLL0CLKSEL; + break; + case 0x204: + /* bit1 is reset status */ + value = s->SYSPLL0CTL0 & (~0x2); + break; + case 0x20C: + value = s->SYSPLL0LOCKTIMEDIV2; + break; + case 0x210: + value = s->SYSPLL0NUM; + break; + case 0x214: + value = s->SYSPLL0DENOM; + break; + case 0x218: + value = s->SYSPLL0PFD | 0x40404040; + break; + case 0x240: + value = s->MAINPLLCLKDIV & (~0xE0000000); + break; + case 0x244: + value = s->DSPPLLCLKDIV & (~0xE0000000); + break; + case 0x248: + value = s->AUX0PLLCLKDIV & (~0xE0000000); + break; + case 0x24C: + value = s->AUX1PLLCLKDIV & (~0xE0000000); + break; + case 0x400: + value = s->SYSCPUAHBCLKDIV & (~0x80000000); + break; + case 0x430: + value = s->MAINCLKSELA; + break; + case 0x434: + value = s->MAINCLKSELB; + break; + case 0x500: + value = s->PFC0DIV & (~0xE0000000); + break; + case 0x504: + value = s->PFC1DIV & (~0xE0000000); + break; + case 0x620: + value = s->FLEXSPI0FCLKSEL; + break; + case 0x624: + value = s->FLEXSPI0FCLKDIV & (~0xE0000000); + break; + case 0x630: + value = s->FLEXSPI1FCLKSEL; + break; + case 0x634: + value = s->FLEXSPI1FCLKDIV & (~0xE0000000); + break; + case 0x640: + value = s->SCTFCLKSEL; + break; + case 0x644: + value = s->SCTIN7CLKDIV & (~0xE0000000); + break; + case 0x660: + value = s->USBHSFCLKSEL; + break; + case 0x664: + value = s->USBHSFCLKDIV & (~0xE0000000); + break; + case 0x680: + value = s->SDIO0FCLKSEL; + break; + case 0x684: + value = s->SDIO0FCLKDIV & (~0xE0000000); + break; + case 0x690: + value = s->SDIO1FCLKSEL; + break; + case 0x694: + value = s->SDIO1FCLKDIV & (~0xE0000000); + break; + case 0x6D0: + value = s->ADC0FCLKSEL0; + break; + case 0x6D4: + value = s->ADC0FCLKSEL1; + break; + case 0x6D8: + value = s->ADC0FCLKDIV & (~0xE0000000); + break; + case 0x700: + value = s->UTICKFCLKSEL; + break; + case 0x720: + value = s->WDT0FCLKSEL; + break; + case 0x730: + value = s->A32KHZWAKECLKSEL; + break; + case 0x734: + value = s->A32KHZWAKECLKDIV & (~0xE0000000); + break; + case 0x760: + value = s->SYSTICKFCLKSEL; + break; + case 0x764: + value = s->SYSTICKFCLKDIV & (~0xE0000000); + break; + case 0x770: + value = s->DPHYCLKSEL; + break; + case 0x774: + value = s->DPHYCLKDIV & (~0xE0000000); + break; + case 0x778: + value = s->DPHYESCCLKSEL; + break; + case 0x77C: + value = s->DPHYESCRXCLKDIV & (~0xE0000000); + break; + case 0x780: + value = s->DPHYESCTXCLKDIV & (~0xE0000000); + break; + case 0x790: + value = s->GPUCLKSEL; + break; + case 0x794: + value = s->GPUCLKDIV & (~0xE0000000); + break; + case 0x7A0: + value = s->DCPIXELCLKSEL; + break; + case 0x7A4: + value = s->DCPIXELCLKDIV & (~0xE0000000); + break; + default: + break; + } + + return value; +} + +static void rt_clkctl0_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTCLKCTL0State *s = RT_CLKCTL0(opaque); + uint32_t v32 = (uint32_t)value; + + switch(offset) { + case 0x10: + s->PSCCTL0 = v32; + break; + case 0x14: + s->PSCCTL1 = v32; + break; + case 0x18: + s->PSCCTL2 = v32; + break; + case 0x40: /* WO */ + s->PSCCTL0 |= v32; + break; + case 0x44: + s->PSCCTL1 |= v32; + break; + case 0x48: + s->PSCCTL2 |= v32; + break; + case 0x70: + s->PSCCTL0 &= ~v32; + break; + case 0x74: + s->PSCCTL1 &= ~v32; + break; + case 0x78: + s->PSCCTL2 &= ~v32; + break; + case 0x80: /* Enable Tuning */ + /* in qemu turning does not take time */ + s->FRO_CONTROL = v32; + break; + case 0x84: + /* RO */ + break; + case 0x8C: + s->FRO_RDTRIM = v32; + break; + case 0x90: + s->FRO_SCTRIM = v32; + break; + case 0x108: + s->FRODIVSEL = v32; + break; + case 0x10C: + /* RO */ + break; + case 0x110: + s->FRODIVOEN = v32; + break; + case 0x130: + s->LOWFREQCLKDIV = v32; + break; + case 0x160: + s->SYSOSCCTL0 = v32; + break; + case 0x168: + s->SYSOSCBYPASS = v32; + break; + case 0x190: + s->LPOSCCTL0 = v32; + break; + case 0x1C0: + s->OSC32KHZCTL0 = v32; + break; + case 0x200: + s->SYSPLL0CLKSEL = v32; + break; + case 0x204: + /* bit1 is reset status */ + s->SYSPLL0CTL0 = v32; + break; + case 0x20C: + s->SYSPLL0LOCKTIMEDIV2 = v32; + break; + case 0x210: + s->SYSPLL0NUM = v32; + break; + case 0x214: + s->SYSPLL0DENOM = v32; + break; + case 0x218: + s->SYSPLL0PFD = v32; + break; + case 0x240: + s->MAINPLLCLKDIV = v32; + break; + case 0x244: + s->DSPPLLCLKDIV = v32; + break; + case 0x248: + s->AUX0PLLCLKDIV = v32; + break; + case 0x24C: + s->AUX1PLLCLKDIV = v32; + break; + case 0x400: + s->SYSCPUAHBCLKDIV = v32; + break; + case 0x430: + s->MAINCLKSELA = v32; + break; + case 0x434: + s->MAINCLKSELB = v32; + break; + case 0x500: + s->PFC0DIV = v32; + break; + case 0x504: + s->PFC1DIV = v32; + break; + case 0x620: + s->FLEXSPI0FCLKSEL = v32; + break; + case 0x624: + s->FLEXSPI0FCLKDIV = v32; + break; + case 0x630: + s->FLEXSPI1FCLKSEL = v32; + break; + case 0x634: + s->FLEXSPI1FCLKDIV = v32; + break; + case 0x640: + s->SCTFCLKSEL = v32; + break; + case 0x644: + s->SCTIN7CLKDIV = v32; + break; + case 0x660: + s->USBHSFCLKSEL = v32; + break; + case 0x664: + s->USBHSFCLKDIV = v32; + break; + case 0x680: + s->SDIO0FCLKSEL = v32; + break; + case 0x684: + s->SDIO0FCLKDIV = v32; + break; + case 0x690: + s->SDIO1FCLKSEL = v32; + break; + case 0x694: + s->SDIO1FCLKDIV = v32; + break; + case 0x6D0: + s->ADC0FCLKSEL0 = v32; + break; + case 0x6D4: + s->ADC0FCLKSEL1 = v32; + break; + case 0x6D8: + s->ADC0FCLKDIV = v32; + break; + case 0x700: + s->UTICKFCLKSEL = v32; + break; + case 0x720: + s->WDT0FCLKSEL = v32; + break; + case 0x730: + s->A32KHZWAKECLKSEL = v32; + break; + case 0x734: + s->A32KHZWAKECLKDIV = v32; + break; + case 0x760: + s->SYSTICKFCLKSEL = v32; + break; + case 0x764: + s->SYSTICKFCLKDIV = v32; + break; + case 0x770: + s->DPHYCLKSEL = v32; + break; + case 0x774: + s->DPHYCLKDIV = v32; + break; + case 0x778: + s->DPHYESCCLKSEL = v32; + break; + case 0x77C: + s->DPHYESCRXCLKDIV = v32; + break; + case 0x780: + s->DPHYESCTXCLKDIV = v32; + break; + case 0x790: + s->GPUCLKSEL = v32; + break; + case 0x794: + s->GPUCLKDIV = v32; + break; + case 0x7A0: + s->DCPIXELCLKSEL = v32; + break; + case 0x7A4: + s->DCPIXELCLKDIV = v32; + break; + default: + break; + } + + return; +} + +static void rt_clkctl0_reset_at_boot(DeviceState *dev) +{ + RTCLKCTL0State *s = RT_CLKCTL0(dev); + + s->PSCCTL0 = 0x5; + s->PSCCTL1 = 0; + s->PSCCTL2 = 0; + s->FRO_CONTROL = 0; + s->FRO_CAPVAL = 0; + s->FRO_RDTRIM = 0x000003BF; + s->FRO_SCTRIM = 0x20; + s->FRODIVSEL = 0; + s->FROCLKSTATUS = 0; + s->FRODIVOEN = 0; + s->LOWFREQCLKDIV = 0; + s->SYSOSCCTL0 = 0; + s->SYSOSCBYPASS = 0; + s->LPOSCCTL0 = 0x807BC4D4; + s->OSC32KHZCTL0 = 0; + s->SYSPLL0CLKSEL = 0x7; + s->SYSPLL0CTL0 = 0x00160002; + s->SYSPLL0LOCKTIMEDIV2 = 0x0000CAFE; + s->SYSPLL0NUM = 0x04DD2F15; + s->SYSPLL0DENOM = 0x1FFFFFDB; + s->SYSPLL0PFD = 0x80808080; + s->MAINPLLCLKDIV = 0; + s->DSPPLLCLKDIV = 0; + s->AUX0PLLCLKDIV = 0; + s->AUX1PLLCLKDIV = 0; + s->SYSCPUAHBCLKDIV = 0; + s->MAINCLKSELA = 0; + s->MAINCLKSELB = 0; + s->PFC0DIV = 0x40000000; + s->PFC1DIV = 0x40000000; + s->FLEXSPI0FCLKSEL = 0x7; + s->FLEXSPI0FCLKDIV = 0x40000000; + s->FLEXSPI1FCLKSEL = 0x7; + s->FLEXSPI1FCLKDIV = 0x40000000; + s->SCTFCLKSEL = 0x7; + s->SCTIN7CLKDIV = 0x40000000; + s->USBHSFCLKSEL = 0x7; + s->USBHSFCLKDIV = 0x40000000; + s->SDIO0FCLKSEL = 0x7; + s->SDIO0FCLKDIV = 0x40000000; + s->SDIO1FCLKSEL = 0x7; + s->SDIO1FCLKDIV = 0x40000000; + s->ADC0FCLKSEL0 = 0x7; + s->ADC0FCLKSEL1 = 0x7; + s->ADC0FCLKDIV = 0x40000000; + s->UTICKFCLKSEL = 0x7; + s->WDT0FCLKSEL = 0; + s->A32KHZWAKECLKSEL = 0x1; + s->A32KHZWAKECLKDIV = 0x1F; + s->SYSTICKFCLKSEL = 0x7; + s->SYSTICKFCLKDIV = 0x40000000; + s->DPHYCLKSEL = 0x7; + s->DPHYCLKDIV = 0x40000000; + s->DPHYESCCLKSEL = 0x7; + s->DPHYESCRXCLKDIV = 0x40000000; + s->DPHYESCTXCLKDIV = 0x40000000; + s->GPUCLKSEL = 0x7; + s->GPUCLKDIV = 0x40000000; + s->DCPIXELCLKSEL = 0x7; + s->DCPIXELCLKDIV = 0x40000000; + +} + +static const MemoryRegionOps rt_clkctl0_ops = { + .read = rt_clkctl0_read, + .write = rt_clkctl0_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_clkctl0_realize(DeviceState *dev, Error **errp) +{ + RTCLKCTL0State *s = RT_CLKCTL0(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_clkctl0_ops, s, + TYPE_RT_CLKCTL0, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_rt_clkctl0 = { + .name = RT_CLKCTL0_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(PSCCTL0, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL1, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL2, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL0_SET, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL1_SET, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL2_SET, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL0_CLR, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL1_CLR, RTCLKCTL0State), + VMSTATE_UINT32(PSCCTL2_CLR, RTCLKCTL0State), + VMSTATE_UINT32(FRO_CONTROL, RTCLKCTL0State), + VMSTATE_UINT32(FRO_CAPVAL, RTCLKCTL0State), + VMSTATE_UINT32(FRO_RDTRIM, RTCLKCTL0State), + VMSTATE_UINT32(FRO_SCTRIM, RTCLKCTL0State), + VMSTATE_UINT32(FRODIVSEL, RTCLKCTL0State), + VMSTATE_UINT32(FROCLKSTATUS, RTCLKCTL0State), + VMSTATE_UINT32(FRODIVOEN, RTCLKCTL0State), + VMSTATE_UINT32(LOWFREQCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(SYSOSCCTL0, RTCLKCTL0State), + VMSTATE_UINT32(SYSOSCBYPASS, RTCLKCTL0State), + VMSTATE_UINT32(LPOSCCTL0, RTCLKCTL0State), + VMSTATE_UINT32(OSC32KHZCTL0, RTCLKCTL0State), + VMSTATE_UINT32(SYSPLL0CLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(SYSPLL0CTL0, RTCLKCTL0State), + VMSTATE_UINT32(SYSPLL0LOCKTIMEDIV2, RTCLKCTL0State), + VMSTATE_UINT32(SYSPLL0NUM, RTCLKCTL0State), + VMSTATE_UINT32(SYSPLL0DENOM, RTCLKCTL0State), + VMSTATE_UINT32(SYSPLL0PFD, RTCLKCTL0State), + VMSTATE_UINT32(MAINPLLCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(DSPPLLCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(AUX0PLLCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(AUX1PLLCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(SYSCPUAHBCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(MAINCLKSELA, RTCLKCTL0State), + VMSTATE_UINT32(MAINCLKSELB, RTCLKCTL0State), + VMSTATE_UINT32(PFC0DIV, RTCLKCTL0State), + VMSTATE_UINT32(PFC1DIV, RTCLKCTL0State), + VMSTATE_UINT32(FLEXSPI0FCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(FLEXSPI0FCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(FLEXSPI1FCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(FLEXSPI1FCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(SCTFCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(SCTIN7CLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(USBHSFCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(USBHSFCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(SDIO0FCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(SDIO0FCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(SDIO1FCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(SDIO1FCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(ADC0FCLKSEL0, RTCLKCTL0State), + VMSTATE_UINT32(ADC0FCLKSEL1, RTCLKCTL0State), + VMSTATE_UINT32(ADC0FCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(UTICKFCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(WDT0FCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(A32KHZWAKECLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(A32KHZWAKECLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(SYSTICKFCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(SYSTICKFCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(DPHYCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(DPHYCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(DPHYESCCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(DPHYESCRXCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(DPHYESCTXCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(GPUCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(GPUCLKDIV, RTCLKCTL0State), + VMSTATE_UINT32(DCPIXELCLKSEL, RTCLKCTL0State), + VMSTATE_UINT32(DCPIXELCLKDIV, RTCLKCTL0State), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_clkctl0_init(Object *obj) +{ + RTCLKCTL0State *s = RT_CLKCTL0(obj); + + memory_region_init_io(&s->iomem, obj, &rt_clkctl0_ops, s, TYPE_RT_CLKCTL0, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_clkctl0_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_clkctl0_realize; + dc->vmsd = &vmstate_rt_clkctl0; + dc->reset = rt_clkctl0_reset_at_boot; +} + +static const TypeInfo rt_clkctl0_info = { + .name = TYPE_RT_CLKCTL0, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTCLKCTL0State), + .instance_init = rt_clkctl0_init, + .class_init = rt_clkctl0_class_init, +}; + +static void rt_clkctl0_register_types(void) +{ + type_register_static(&rt_clkctl0_info); +} + +type_init(rt_clkctl0_register_types) + +static uint64_t rt_clkctl1_read(void *opaque, hwaddr offset, unsigned size) +{ + RTCLKCTL1State *s = RT_CLKCTL1(opaque); + uint32_t value = 0xFEFEFEFE; + + switch(offset) { + case 0x10: + value = s->PSCCTL0; + break; + case 0x14: + value = s->PSCCTL1; + break; + case 0x18: + value = s->PSCCTL2; + break; + case 0x40: /* WO */ + break; + case 0x44: + break; + case 0x48: + break; + case 0x70: + break; + case 0x74: + break; + case 0x78: + break; + case 0x200: /* Enable Tuning */ + /* in qemu turning does not take time */ + value = s->AUDIOPLL0CLKSEL; + break; + case 0x204: + /* apll reset is removed */ + value = s->AUDIOPLL0CTL0 & (~0x2); + break; + case 0x20C: + value = s->AUDIOPLL0LOCKTIMEDIV2; + break; + case 0x210: + value = s->AUDIOPLL0NUM; + break; + case 0x214: + value = s->AUDIOPLL0DENOM; + break; + case 0x218: + /* always locked */ + value = s->AUDIOPLL0PFD | 0x40404040; + break; + case 0x240: + value = s->AUDIOPLLCLKDIV & (~0xE0000000); + break; + case 0x400: + value = s->DSPCPUCLKDIV & (~0xE0000000); + break; + case 0x430: + value = s->DSPCPUCLKSELA; + break; + case 0x434: + value = s->DSPCPUCLKSELB; + break; + case 0x480: + value = s->OSEVENTTFCLKSEL; + break; + case 0x500: + value = s->FRG0CLKSEL; + break; + case 0x504: + value = s->FRG0CTL; + break; + case 0x508: + value = s->FC0FCLKSEL; + break; + case 0x520: + value = s->FRG1CLKSEL; + break; + case 0x524: + value = s->FRG1CTL; + break; + case 0x528: + value = s->FC1FCLKSEL; + break; + case 0x540: + value = s->FRG2CLKSEL; + break; + case 0x544: + value = s->FRG2CTL; + break; + case 0x548: + value = s->FC2FCLKSEL; + break; + case 0x560: + value = s->FRG3CLKSEL; + break; + case 0x564: + value = s->FRG3CTL; + break; + case 0x568: + value = s->FC3FCLKSEL; + break; + case 0x580: + value = s->FRG4CLKSEL; + break; + case 0x584: + value = s->FRG4CTL; + break; + case 0x588: + value = s->FC4FCLKSEL; + break; + case 0x5A0: + value = s->FRG5CLKSEL; + break; + case 0x5A4: + value = s->FRG5CTL; + break; + case 0x5A8: + value = s->FC5FCLKSEL; + break; + case 0x5C0: + value = s->FRG6CLKSEL; + break; + case 0x5C4: + value = s->FRG6CTL; + break; + case 0x5C8: + value = s->FC6FCLKSEL; + break; + case 0x5E0: + value = s->FRG7CLKSEL; + break; + case 0x5E4: + value = s->FRG7CTL; + break; + case 0x5E8: + value = s->FC7FCLKSEL; + break; + case 0x600: + value = s->FRG8CLKSEL; + break; + case 0x604: + value = s->FRG8CTL; + break; + case 0x608: + value = s->FC8FCLKSEL; + break; + case 0x620: + value = s->FRG9CLKSEL; + break; + case 0x624: + value = s->FRG9CTL; + break; + case 0x628: + value = s->FC9FCLKSEL; + break; + case 0x640: + value = s->FRG10CLKSEL; + break; + case 0x644: + value = s->FRG10CTL; + break; + case 0x648: + value = s->FC10FCLKSEL; + break; + case 0x660: + value = s->FRG11CLKSEL; + break; + case 0x664: + value = s->FRG11CTL; + break; + case 0x668: + value = s->FC11FCLKSEL; + break; + case 0x680: + value = s->FRG12CLKSEL; + break; + case 0x684: + value = s->FRG12CTL; + break; + case 0x688: + value = s->FC12FCLKSEL; + break; + case 0x6A0: + value = s->FRG13CLKSEL; + break; + case 0x6A4: + value = s->FRG13CTL; + break; + case 0x6A8: + value = s->FC13FCLKSEL; + break; + case 0x6C0: + value = s->FRG14CLKSEL; + break; + case 0x6C4: + value = s->FRG14CTL; + break; + case 0x6C8: + value = s->FC14FCLKSEL; + break; + case 0x6E0: + value = s->FRG15CLKSEL; + break; + case 0x6E4: + value = s->FRG15CTL; + break; + case 0x6E8: + value = s->FC15FCLKSEL; + break; + case 0x700: + value = s->FRG16CLKSEL; + break; + case 0x704: + value = s->FRG16CTL; + break; + case 0x708: + value = s->FC16FCLKSEL; + break; + case 0x720: + value = s->FRG17CLKSEL; + break; + case 0x724: + value = s->FRG17CTL; + break; + case 0x728: + value = s->FLEXIOCLKSEL; + break; + case 0x740: + value = s->FLEXIOCLKDIV & (~0xE0000000); + break; + case 0x760: + value = s->FRGPLLCLKDIV & (~0xE0000000); + break; + case 0x780: + value = s->DMIC0FCLKSEL; + break; + case 0x784: + value = s->DMIC0FCLKDIV & (~0xE0000000); + break; + case 0x7A0: + value = s->CT32BIT0FCLKSEL; + break; + case 0x7A4: + value = s->CT32BIT1FCLKSEL; + break; + case 0x7A8: + value = s->CT32BIT2FCLKSEL; + break; + case 0x7AC: + value = s->CT32BIT3FCLKSEL; + break; + case 0x7B0: + value = s->CT32BIT4FCLKSEL; + break; + case 0x7C0: + value = s->AUDIOMCLKSEL; + break; + case 0x7C4: + value = s->AUDIOMCLKDIV & (~0xE0000000); + break; + case 0x7E0: + value = s->CLKOUTSEL0; + break; + case 0x7E4: + value = s->CLKOUTSEL1; + break; + case 0x7E8: + value = s->CLKOUTFCLKDIV & (~0xE0000000); + break; + case 0x800: + value = s->I3C01FCLKSEL; + break; + case 0x804: + value = s->I3C01FCLKSTCSEL; + break; + case 0x808: + value = s->I3C01FCLKSTCDIV & (~0xE0000000); + break; + case 0x80C: + value = s->I3C01FCLKSDIV & (~0xE0000000); + break; + case 0x810: + value = s->I3C01FCLKDIV & (~0xE0000000); + break; + case 0x814: + value = s->I3C01FCLKSTSTCLKSEL; + break; + case 0x820: + value = s->WDT1FCLKSEL; + break; + case 0x830: + value = s->ACMP0FCLKSEL; + break; + case 0x834: + value = s->ACMP0FCLKDIV & (~0xE0000000); + break; + default: + break; + } + + return value; +} + +static void rt_clkctl1_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTCLKCTL1State *s = RT_CLKCTL1(opaque); + uint32_t v32 = (uint32_t)value; + + switch(offset) { + case 0x10: + s->PSCCTL0 = v32; + break; + case 0x14: + s->PSCCTL1 = v32; + break; + case 0x18: + s->PSCCTL2 = v32; + break; + case 0x40: /* WO */ + s->PSCCTL0 |= v32; + break; + case 0x44: + s->PSCCTL1 |= v32; + break; + case 0x48: + s->PSCCTL2 |= v32; + break; + case 0x70: + s->PSCCTL0 &= ~v32; + break; + case 0x74: + s->PSCCTL1 &= ~v32; + break; + case 0x78: + s->PSCCTL2 &= ~v32; + break; + case 0x200: /* Enable Tuning */ + /* in qemu turning does not take time */ + s->AUDIOPLL0CLKSEL = v32; + break; + case 0x204: + /* apll reset is removed */ + s->AUDIOPLL0CTL0 = v32; + break; + case 0x20C: + s->AUDIOPLL0LOCKTIMEDIV2 = v32; + break; + case 0x210: + s->AUDIOPLL0NUM = v32; + break; + case 0x214: + s->AUDIOPLL0DENOM = v32; + break; + case 0x218: + /* always locked */ + s->AUDIOPLL0PFD = v32; + break; + case 0x240: + s->AUDIOPLLCLKDIV = v32; + break; + case 0x400: + s->DSPCPUCLKDIV = v32; + break; + case 0x430: + s->DSPCPUCLKSELA = v32; + break; + case 0x434: + s->DSPCPUCLKSELB = v32; + break; + case 0x480: + s->OSEVENTTFCLKSEL = v32; + break; + case 0x500: + s->FRG0CLKSEL = v32; + break; + case 0x504: + s->FRG0CTL = v32; + break; + case 0x508: + s->FC0FCLKSEL = v32; + break; + case 0x520: + s->FRG1CLKSEL = v32; + break; + case 0x524: + s->FRG1CTL = v32; + break; + case 0x528: + s->FC1FCLKSEL = v32; + break; + case 0x540: + s->FRG2CLKSEL = v32; + break; + case 0x544: + s->FRG2CTL = v32; + break; + case 0x548: + s->FC2FCLKSEL = v32; + break; + case 0x560: + s->FRG3CLKSEL = v32; + break; + case 0x564: + s->FRG3CTL = v32; + break; + case 0x568: + s->FC3FCLKSEL = v32; + break; + case 0x580: + s->FRG4CLKSEL = v32; + break; + case 0x584: + s->FRG4CTL = v32; + break; + case 0x588: + s->FC4FCLKSEL = v32; + break; + case 0x5A0: + s->FRG5CLKSEL = v32; + break; + case 0x5A4: + s->FRG5CTL = v32; + break; + case 0x5A8: + s->FC5FCLKSEL = v32; + break; + case 0x5C0: + s->FRG6CLKSEL = v32; + break; + case 0x5C4: + s->FRG6CTL = v32; + break; + case 0x5C8: + s->FC6FCLKSEL = v32; + break; + case 0x5E0: + s->FRG7CLKSEL = v32; + break; + case 0x5E4: + s->FRG7CTL = v32; + break; + case 0x5E8: + s->FC7FCLKSEL = v32; + break; + case 0x600: + s->FRG8CLKSEL = v32; + break; + case 0x604: + s->FRG8CTL = v32; + break; + case 0x608: + s->FC8FCLKSEL = v32; + break; + case 0x620: + s->FRG9CLKSEL = v32; + break; + case 0x624: + s->FRG9CTL = v32; + break; + case 0x628: + s->FC9FCLKSEL = v32; + break; + case 0x640: + s->FRG10CLKSEL = v32; + break; + case 0x644: + s->FRG10CTL = v32; + break; + case 0x648: + s->FC10FCLKSEL = v32; + break; + case 0x660: + s->FRG11CLKSEL = v32; + break; + case 0x664: + s->FRG11CTL = v32; + break; + case 0x668: + s->FC11FCLKSEL = v32; + break; + case 0x680: + s->FRG12CLKSEL = v32; + break; + case 0x684: + s->FRG12CTL = v32; + break; + case 0x688: + s->FC12FCLKSEL = v32; + break; + case 0x6A0: + s->FRG13CLKSEL = v32; + break; + case 0x6A4: + s->FRG13CTL = v32; + break; + case 0x6A8: + s->FC13FCLKSEL = v32; + break; + case 0x6C0: + s->FRG14CLKSEL = v32; + break; + case 0x6C4: + s->FRG14CTL = v32; + break; + case 0x6C8: + s->FC14FCLKSEL = v32; + break; + case 0x6E0: + s->FRG15CLKSEL = v32; + break; + case 0x6E4: + s->FRG15CTL = v32; + break; + case 0x6E8: + s->FC15FCLKSEL = v32; + break; + case 0x700: + s->FRG16CLKSEL = v32; + break; + case 0x704: + s->FRG16CTL = v32; + break; + case 0x708: + s->FC16FCLKSEL = v32; + break; + case 0x720: + s->FRG17CLKSEL = v32; + break; + case 0x724: + s->FRG17CTL = v32; + break; + case 0x728: + s->FLEXIOCLKSEL = v32; + break; + case 0x740: + s->FLEXIOCLKDIV = v32; + break; + case 0x760: + s->FRGPLLCLKDIV = v32; + break; + case 0x780: + s->DMIC0FCLKSEL = v32; + break; + case 0x784: + s->DMIC0FCLKDIV = v32; + break; + case 0x7A0: + s->CT32BIT0FCLKSEL = v32; + break; + case 0x7A4: + s->CT32BIT1FCLKSEL = v32; + break; + case 0x7A8: + s->CT32BIT2FCLKSEL = v32; + break; + case 0x7AC: + s->CT32BIT3FCLKSEL = v32; + break; + case 0x7B0: + s->CT32BIT4FCLKSEL = v32; + break; + case 0x7C0: + s->AUDIOMCLKSEL = v32; + break; + case 0x7C4: + s->AUDIOMCLKDIV = v32; + break; + case 0x7E0: + s->CLKOUTSEL0 = v32; + break; + case 0x7E4: + s->CLKOUTSEL1 = v32; + break; + case 0x7E8: + s->CLKOUTFCLKDIV = v32; + break; + case 0x800: + s->I3C01FCLKSEL = v32; + break; + case 0x804: + s->I3C01FCLKSTCSEL = v32; + break; + case 0x808: + s->I3C01FCLKSTCDIV = v32; + break; + case 0x80C: + s->I3C01FCLKSDIV = v32; + break; + case 0x810: + s->I3C01FCLKDIV = v32; + break; + case 0x814: + s->I3C01FCLKSTSTCLKSEL = v32; + break; + case 0x820: + s->WDT1FCLKSEL = v32; + break; + case 0x830: + s->ACMP0FCLKSEL = v32; + break; + case 0x834: + s->ACMP0FCLKDIV = v32; + break; + default: + break; + } + + return; +} + +static void rt_clkctl1_reset_at_boot(DeviceState *dev) +{ + RTCLKCTL1State *s = RT_CLKCTL1(dev); + + s->PSCCTL0 = 0x0; + s->PSCCTL1 = 0x0; + s->PSCCTL2 = 0x0; + s->AUDIOPLL0CLKSEL = 0x7; + s->AUDIOPLL0CTL0 = 0x160002; + s->AUDIOPLL0LOCKTIMEDIV2 = 0x000CAFE; + s->AUDIOPLL0NUM = 0x04DD2F15; + s->AUDIOPLL0DENOM = 0x1FFFFFDB; + s->AUDIOPLL0PFD = 0x80808080; + s->AUDIOPLLCLKDIV = 0x40000000; + s->DSPCPUCLKDIV = 0x40000000; + s->DSPCPUCLKSELA = 0x0; + s->DSPCPUCLKSELB = 0x0; + s->OSEVENTTFCLKSEL = 0x0; + s->FRG0CLKSEL = 0x7; + s->FRG0CTL = 0xFF; + s->FC0FCLKSEL = 0x7; + s->FRG1CLKSEL = 0x7; + s->FRG1CTL = 0xFF; + s->FC1FCLKSEL = 0x7; + s->FRG2CLKSEL = 0x7; + s->FRG2CTL = 0xFF; + s->FC2FCLKSEL = 0x7; + s->FRG3CLKSEL = 0x7; + s->FRG3CTL = 0xFF; + s->FC3FCLKSEL = 0x7; + s->FRG4CLKSEL = 0x7; + s->FRG4CTL = 0xFF; + s->FC4FCLKSEL = 0x7; + s->FRG5CLKSEL = 0x7; + s->FRG5CTL = 0xFF; + s->FC5FCLKSEL = 0x7; + s->FRG6CLKSEL = 0x7; + s->FRG6CTL = 0xFF; + s->FC6FCLKSEL = 0x7; + s->FRG7CLKSEL = 0x7; + s->FRG7CTL = 0xFF; + s->FC7FCLKSEL = 0x7; + s->FRG8CLKSEL = 0x7; + s->FRG8CTL = 0xFF; + s->FC8FCLKSEL = 0x7; + s->FRG9CLKSEL = 0x7; + s->FRG9CTL = 0xFF; + s->FC9FCLKSEL = 0x7; + s->FRG10CLKSEL = 0x7; + s->FRG10CTL = 0xFF; + s->FC10FCLKSEL = 0x7; + s->FRG11CLKSEL = 0x7; + s->FRG11CTL = 0xFF; + s->FC11FCLKSEL = 0x7; + s->FRG12CLKSEL = 0x7; + s->FRG12CTL = 0xFF; + s->FC12FCLKSEL = 0x7; + s->FRG13CLKSEL = 0x7; + s->FRG13CTL = 0xFF; + s->FC13FCLKSEL = 0x7; + s->FRG14CLKSEL = 0x7; + s->FRG14CTL = 0xFF; + s->FC14FCLKSEL = 0x7; + s->FRG15CLKSEL = 0x7; + s->FRG15CTL = 0xFF; + s->FC15FCLKSEL = 0x7; + s->FRG16CLKSEL = 0x7; + s->FRG16CTL = 0xFF; + s->FC16FCLKSEL = 0x7; + s->FRG17CLKSEL = 0x7; + s->FRG17CTL = 0xFF; + s->FLEXIOCLKSEL = 0x7; + s->FLEXIOCLKDIV = 0x40000000; + s->FRGPLLCLKDIV = 0x40000000; + s->DMIC0FCLKSEL = 0x7; + s->DMIC0FCLKDIV = 0x40000000; + s->CT32BIT0FCLKSEL = 0x7; + s->CT32BIT1FCLKSEL = 0x7; + s->CT32BIT2FCLKSEL = 0x7; + s->CT32BIT3FCLKSEL = 0x7; + s->CT32BIT4FCLKSEL = 0x7; + s->AUDIOMCLKSEL = 0x7; + s->AUDIOMCLKDIV = 0x40000000; + s->CLKOUTSEL0 = 0x7; + s->CLKOUTSEL1 = 0x7; + s->CLKOUTFCLKDIV = 0x40000000; + s->I3C01FCLKSEL = 0x7; + s->I3C01FCLKSTCSEL = 0x7; + s->I3C01FCLKSTCDIV = 0x40000000; + s->I3C01FCLKSDIV = 0x40000000; + s->I3C01FCLKDIV = 0x40000000; + s->I3C01FCLKSTSTCLKSEL = 0x0; + s->WDT1FCLKSEL = 0x0; + s->ACMP0FCLKSEL = 0x7; + s->ACMP0FCLKDIV = 0x40000000; +} + +static const MemoryRegionOps rt_clkctl1_ops = { + .read = rt_clkctl1_read, + .write = rt_clkctl1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_clkctl1_realize(DeviceState *dev, Error **errp) +{ + RTCLKCTL1State *s = RT_CLKCTL1(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_clkctl1_ops, s, + TYPE_RT_CLKCTL1, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_rt_clkctl1 = { + .name = RT_CLKCTL1_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(PSCCTL0, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL1, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL2, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL0_SET, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL1_SET, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL2_SET, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL0_CLR, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL1_CLR, RTCLKCTL1State), + VMSTATE_UINT32(PSCCTL2_CLR, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLL0CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLL0CTL0, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLL0LOCKTIMEDIV2, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLL0NUM, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLL0DENOM, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLL0PFD, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOPLLCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(DSPCPUCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(DSPCPUCLKSELA, RTCLKCTL1State), + VMSTATE_UINT32(DSPCPUCLKSELB, RTCLKCTL1State), + VMSTATE_UINT32(OSEVENTTFCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG0CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG0CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC0FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG1CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG1CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC1FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG2CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG2CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC2FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG3CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG3CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC3FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG4CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG4CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC4FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG5CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG5CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC5FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG6CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG6CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC6FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG7CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG7CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC7FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG8CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG8CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC8FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG9CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG9CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC9FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG10CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG10CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC10FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG11CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG11CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC11FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG12CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG12CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC12FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG13CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG13CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC13FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG14CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG14CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC14FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG15CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG15CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC15FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG16CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG16CTL, RTCLKCTL1State), + VMSTATE_UINT32(FC16FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG17CLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FRG17CTL, RTCLKCTL1State), + VMSTATE_UINT32(FLEXIOCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(FLEXIOCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(FRGPLLCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(DMIC0FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(DMIC0FCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(CT32BIT0FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(CT32BIT1FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(CT32BIT2FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(CT32BIT3FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(CT32BIT4FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOMCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(AUDIOMCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(CLKOUTSEL0, RTCLKCTL1State), + VMSTATE_UINT32(CLKOUTSEL1, RTCLKCTL1State), + VMSTATE_UINT32(CLKOUTFCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(I3C01FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(I3C01FCLKSTCSEL, RTCLKCTL1State), + VMSTATE_UINT32(I3C01FCLKSTCDIV, RTCLKCTL1State), + VMSTATE_UINT32(I3C01FCLKSDIV, RTCLKCTL1State), + VMSTATE_UINT32(I3C01FCLKDIV, RTCLKCTL1State), + VMSTATE_UINT32(I3C01FCLKSTSTCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(WDT1FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(ACMP0FCLKSEL, RTCLKCTL1State), + VMSTATE_UINT32(ACMP0FCLKDIV, RTCLKCTL1State), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_clkctl1_init(Object *obj) +{ + RTCLKCTL1State *s = RT_CLKCTL1(obj); + + memory_region_init_io(&s->iomem, obj, &rt_clkctl1_ops, s, TYPE_RT_CLKCTL1, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_clkctl1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_clkctl1_realize; + dc->vmsd = &vmstate_rt_clkctl1; + dc->reset = rt_clkctl1_reset_at_boot; +} + +static const TypeInfo rt_clkctl1_info = { + .name = TYPE_RT_CLKCTL1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTCLKCTL1State), + .instance_init = rt_clkctl1_init, + .class_init = rt_clkctl1_class_init, +}; + +static void rt_clkctl1_register_types(void) +{ + type_register_static(&rt_clkctl1_info); +} + +type_init(rt_clkctl1_register_types) + diff --git a/hw/misc/rt_pmc.c b/hw/misc/rt_pmc.c new file mode 100644 index 000000000000..9d23c000c559 --- /dev/null +++ b/hw/misc/rt_pmc.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/misc/rt_pmc.h" +#include "migration/vmstate.h" + +#define RT_PMC_NAME "PMC for NXP RTxxx series" + +static uint64_t rt_pmc_read(void *opaque, hwaddr offset, unsigned size) +{ + RTPMCState *s = RT_PMC(opaque); + uint32_t value= 0xFEFEFEFE; + + switch(offset) { + case 0x4: + /* always ok to set*/ + value = 0; + break; + case 0x8: + value = 0; + break; + case 0xC: + value = s->CTRL; + break; + case 0x10: + value = s->RUNCTRL; + break; + case 0x14: + value = s->SLEEPCTRL; + break; + case 0x18: + value = s->LVDCORECTRL; + break; + case 0x24: + value = s->AUTOWKUP; + break; + case 0x28: + value = s->PMICCFG; + break; + case 0x2C: + value = s->PADVRANGE; + break; + case 0x30: + value = s->MEMSEQCTRL; + break; + case 0x60: + value = s->TSENSOR; + break; + default: + break; + } + + return value; +} + +static void rt_pmc_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTPMCState *s = RT_PMC(opaque); + uint32_t v32 = (uint32_t)value; + printf("\r\nrt-pmc write 0x%lx = 0x%lx\r\n", offset, value); + + switch(offset) { + case 0x4: + /* RO */ + break; + case 0x8: + s->FLAGS &= ~v32;//w1c + break; + case 0xC: + s->CTRL = v32; + break; + case 0x10: + s->RUNCTRL = v32; + break; + case 0x14: + s->SLEEPCTRL = v32; + break; + case 0x18: + s->LVDCORECTRL = v32; + break; + case 0x24: + s->AUTOWKUP = v32; + break; + case 0x28: + s->PMICCFG = v32; + break; + case 0x2C: + s->PADVRANGE = v32; + break; + case 0x30: + s->MEMSEQCTRL = v32; + break; + case 0x60: + s->TSENSOR = v32; + break; + default: + break; + } + + return; +} + +static void rt_pmc_reset_at_boot(DeviceState *dev) +{ + RTPMCState *s = RT_PMC(dev); + + s->STATUS = 0x0; + s->FLAGS = 0x00170000; + s->CTRL = 0x00200000; + s->RUNCTRL = 0x00000026; + s->SLEEPCTRL = 0x00000026; + s->LVDCORECTRL = 0x0; + s->AUTOWKUP = 0x0; + s->PMICCFG = 0x00000073; + s->PADVRANGE = 0x0; + s->MEMSEQCTRL = 0x3F; + s->TSENSOR = 0x0; + + s->count = 0; +} + +static const MemoryRegionOps rt_pmc_ops = { + .read = rt_pmc_read, + .write = rt_pmc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_pmc_tick(void *opaque) +{ + RTPMCState *s = RT_PMC(opaque); + + switch(s->state) { + case ePMC_Active: + break; + case ePMC_Sleep: + break; + case ePMC_Deep_Sleep: + break; + case ePMC_Deep_Power_Down: + break; + case ePMC_Full_Deep_Power_Down: + break; + default: + break; + } + + if ((s->CTRL & CTRL_AUTOWKF_MASK) == CTRL_AUTOWKF_MASK && s->AUTOWKUP) + { + s->count++; + if(s->count >= s->AUTOWKUP) + { + s->count = 0; + printf("irq up\r\n"); + qemu_set_irq(s->irq, 1); + s->FLAGS |= FLAG_AUTOWKF_MASK; + } + } + + /* every 62.5 ns */ + if (s->timer){ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + s->timer_interval = 62; + timer_mod(s->timer, now + s->timer_interval); + } +} + +static void rt_pmc_realize(DeviceState *dev, Error **errp) +{ + RTPMCState *s = RT_PMC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_pmc_ops, s, + TYPE_RT_PMC, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + + s->timer_interval = 62; /* every 62.5 ns */ + s->timer = timer_new_ns(QEMU_CLOCK_REALTIME, rt_pmc_tick, s); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + timer_mod(s->timer, now + s->timer_interval); + +} + +static void rt_pmc_unrealize(DeviceState *dev) +{ + RTPMCState *s = RT_PMC(dev); + + if(s->timer){ + timer_del(s->timer); + s->timer = NULL; + } + +} + +static const VMStateDescription vmstate_rt_pmc = { + .name = RT_PMC_NAME, + .version_id = 1, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(STATUS, RTPMCState), + VMSTATE_UINT32(FLAGS, RTPMCState), + VMSTATE_UINT32(CTRL, RTPMCState), + VMSTATE_UINT32(RUNCTRL, RTPMCState), + VMSTATE_UINT32(SLEEPCTRL, RTPMCState), + VMSTATE_UINT32(LVDCORECTRL, RTPMCState), + VMSTATE_UINT32(AUTOWKUP, RTPMCState), + VMSTATE_UINT32(PMICCFG, RTPMCState), + VMSTATE_UINT32(PADVRANGE, RTPMCState), + VMSTATE_UINT32(MEMSEQCTRL, RTPMCState), + VMSTATE_UINT32(TSENSOR, RTPMCState), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_pmc_init(Object *obj) +{ + RTPMCState *s = RT_PMC(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->iomem, obj, &rt_pmc_ops, s, TYPE_RT_PMC, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_pmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_pmc_realize; + dc->unrealize = rt_pmc_unrealize; + dc->vmsd = &vmstate_rt_pmc; + dc->reset = rt_pmc_reset_at_boot; +} + +static const TypeInfo rt_pmc_info = { + .name = TYPE_RT_PMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTPMCState), + .instance_init = rt_pmc_init, + .class_init = rt_pmc_class_init, +}; + +static void rt_pmc_register_types(void) +{ + type_register_static(&rt_pmc_info); +} + +type_init(rt_pmc_register_types) + diff --git a/hw/misc/rt_rstctl.c b/hw/misc/rt_rstctl.c new file mode 100644 index 000000000000..830df7fe45b7 --- /dev/null +++ b/hw/misc/rt_rstctl.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/misc/rt_rstctl.h" +#include "migration/vmstate.h" + + +#define RT_RSTCTL0_NAME "reset controllor0 for NXP RTxxx series" +#define RT_RSTCTL1_NAME "reset controllor1 for NXP RTxxx series" + +static uint64_t rt_rstctl0_read(void *opaque, hwaddr offset, unsigned size) +{ + RTRSTCTL0State *s = RT_RSTCTL0(opaque); + uint32_t value; + + switch(offset) { + case 0x10: /* PRSTCTL0 */ + value = s->PRSTCTL0; + break; + case 0x14: /* PRSTCTL1 */ + value = s->PRSTCTL1; + break; + case 0x18: /* PRSTCTL2 */ + value = s->PRSTCTL2; + break; + default: + break; + } + printf("[RSTCTL0]: read 0x%lx = 0x%x\n", offset, value); + + return value; +} + +static void rt_rstctl0_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTRSTCTL0State *s = RT_RSTCTL0(opaque); + + switch(offset) + { + case 0x0: + s->SYSRSTSTAT &= ~value; + break; + case 0x10: + s->PRSTCTL0 = value; + break; + case 0x14: + s->PRSTCTL1 = value; + break; + case 0x18: + s->PRSTCTL2 = value; + break; + case 0x40: + s->PRSTCTL0 |= value; + break; + case 0x44: + s->PRSTCTL1 |= value; + break; + case 0x48: + s->PRSTCTL2 |= value; + break; + case 0x70: + s->PRSTCTL0 &= ~value; + break; + case 0x74: + s->PRSTCTL1 &= ~value; + break; + case 0x78: + s->PRSTCTL2 &= ~value; + break; + default: + return; + } +} + +static const MemoryRegionOps rt_rstctl0_ops = { + .read = rt_rstctl0_read, + .write = rt_rstctl0_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_rstctl0_realize(DeviceState *dev, Error **errp) +{ + RTRSTCTL0State *s = RT_RSTCTL0(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_rstctl0_ops, s, + TYPE_RT_RSTCTL0, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void rt_rstctl0_reset_at_boot(DeviceState *dev) +{ + RTRSTCTL0State *s = RT_RSTCTL0(dev); + + s->SYSRSTSTAT = 0x1; + s->PRSTCTL0 = 0x7DF51F0A; + s->PRSTCTL1 = 0x0101800C; + s->PRSTCTL2 = 0x1C000001; + s->PRSTCTL0_SET = 0x0; + s->PRSTCTL1_SET = 0x0; + s->PRSTCTL2_SET = 0x0; + s->PRSTCTL0_CLR = 0x0; + s->PRSTCTL1_CLR = 0x0; + s->PRSTCTL2_CLR = 0x0; +} + +static const VMStateDescription vmstate_rt_rstctl0 = { + .name = RT_RSTCTL0_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(SYSRSTSTAT, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL0, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL1, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL2, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL0_SET, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL1_SET, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL2_SET, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL0_CLR, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL1_CLR, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL2_CLR, RTRSTCTL0State), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_rstctl0_init(Object *obj) +{ + RTRSTCTL0State *s = RT_RSTCTL0(obj); + + memory_region_init_io(&s->iomem, obj, &rt_rstctl0_ops, s, TYPE_RT_RSTCTL0, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_rstctl0_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_rstctl0_realize; + dc->vmsd = &vmstate_rt_rstctl0; + dc->reset = rt_rstctl0_reset_at_boot; +} + +static const TypeInfo rt_rstctl0_info = { + .name = TYPE_RT_RSTCTL0, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTRSTCTL0State), + .instance_init = rt_rstctl0_init, + .class_init = rt_rstctl0_class_init, +}; + +static void rt_rstctl0_register_types(void) +{ + type_register_static(&rt_rstctl0_info); +} + +type_init(rt_rstctl0_register_types) + +static uint64_t rt_rstctl1_read(void *opaque, hwaddr offset, unsigned size) +{ + RTRSTCTL1State *s = RT_RSTCTL1(opaque); + uint32_t value; + + switch(offset) { + case 0x10: /* PRSTCTL0 */ + value = s->PRSTCTL0; + break; + case 0x14: /* PRSTCTL1 */ + value = s->PRSTCTL1; + break; + case 0x18: /* PRSTCTL2 */ + value = s->PRSTCTL2; + break; + default: + break; + } + printf("[RSTCTL1]: read 0x%lx = 0x%x\n", offset, value); + + return value; +} + +static void rt_rstctl1_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTRSTCTL1State *s = RT_RSTCTL1(opaque); + + switch(offset) + { + case 0x0: + s->SYSRSTSTAT &= ~value; + break; + case 0x10: + s->PRSTCTL0 = value; + break; + case 0x14: + s->PRSTCTL1 = value; + break; + case 0x18: + s->PRSTCTL2 = value; + break; + case 0x40: + s->PRSTCTL0 |= value; + break; + case 0x44: + s->PRSTCTL1 |= value; + break; + case 0x48: + s->PRSTCTL2 |= value; + break; + case 0x70: + s->PRSTCTL0 &= ~value; + break; + case 0x74: + s->PRSTCTL1 &= ~value; + break; + case 0x78: + s->PRSTCTL2 &= ~value; + break; + default: + return; + } +} + +static const MemoryRegionOps rt_rstctl1_ops = { + .read = rt_rstctl1_read, + .write = rt_rstctl1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_rstctl1_realize(DeviceState *dev, Error **errp) +{ + RTRSTCTL1State *s = RT_RSTCTL1(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_rstctl1_ops, s, + TYPE_RT_RSTCTL1, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_rt_rstctl1 = { + .name = RT_RSTCTL1_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(SYSRSTSTAT, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL0, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL1, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL2, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL0_SET, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL1_SET, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL2_SET, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL0_CLR, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL1_CLR, RTRSTCTL0State), + VMSTATE_UINT32(PRSTCTL2_CLR, RTRSTCTL0State), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_rstctl1_init(Object *obj) +{ + RTRSTCTL1State *s = RT_RSTCTL1(obj); + + memory_region_init_io(&s->iomem, obj, &rt_rstctl1_ops, s, TYPE_RT_RSTCTL1, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_rstctl1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_rstctl1_realize; + dc->vmsd = &vmstate_rt_rstctl1; +} + +static const TypeInfo rt_rstctl1_info = { + .name = TYPE_RT_RSTCTL1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTRSTCTL1State), + .instance_init = rt_rstctl1_init, + .class_init = rt_rstctl1_class_init, +}; + +static void rt_rstctl1_register_types(void) +{ + type_register_static(&rt_rstctl1_info); +} + +type_init(rt_rstctl1_register_types) + diff --git a/hw/misc/rt_sysctl.c b/hw/misc/rt_sysctl.c new file mode 100644 index 000000000000..cb6acb81ad74 --- /dev/null +++ b/hw/misc/rt_sysctl.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/guest-random.h" +#include "hw/irq.h" +#include "hw/misc/rt_sysctl.h" +#include "migration/vmstate.h" + + +#define RT_SYSCTL0_NAME "system controllor0 for NXP RTxxx series" +#define RT_SYSCTL1_NAME "system controllor1 for NXP RTxxx series" + +static uint64_t rt_sysctl0_read(void *opaque, hwaddr offset, unsigned size) +{ + RTSYSCTL0State *s = RT_SYSCTL0(opaque); + + switch(offset) { + default: + break; + } + + return s->reg[offset / 4]; +} + +static void rt_sysctl0_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTSYSCTL0State *s = RT_SYSCTL0(opaque); + + s->reg[offset / 4] = value; +} + +static const MemoryRegionOps rt_sysctl0_ops = { + .read = rt_sysctl0_read, + .write = rt_sysctl0_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_sysctl0_realize(DeviceState *dev, Error **errp) +{ + RTSYSCTL0State *s = RT_SYSCTL0(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_sysctl0_ops, s, + TYPE_RT_SYSCTL0, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_rt_sysctl0 = { + .name = RT_SYSCTL0_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, RTSYSCTL0State, 512), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_sysctl0_init(Object *obj) +{ + RTSYSCTL0State *s = RT_SYSCTL0(obj); + + memory_region_init_io(&s->iomem, obj, &rt_sysctl0_ops, s, TYPE_RT_SYSCTL0, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_sysctl0_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_sysctl0_realize; + dc->vmsd = &vmstate_rt_sysctl0; +} + +static const TypeInfo rt_sysctl0_info = { + .name = TYPE_RT_SYSCTL0, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTSYSCTL0State), + .instance_init = rt_sysctl0_init, + .class_init = rt_sysctl0_class_init, +}; + +static void rt_sysctl0_register_types(void) +{ + type_register_static(&rt_sysctl0_info); +} + +type_init(rt_sysctl0_register_types) + +static uint64_t rt_sysctl1_read(void *opaque, hwaddr offset, unsigned size) +{ + RTSYSCTL1State *s = RT_SYSCTL1(opaque); + + switch(offset) { + default: + break; + } + + return s->reg[offset / 4]; +} + +static void rt_sysctl1_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTSYSCTL1State *s = RT_SYSCTL1(opaque); + + s->reg[offset / 4] = value; +} + +static const MemoryRegionOps rt_sysctl1_ops = { + .read = rt_sysctl1_read, + .write = rt_sysctl1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_sysctl1_realize(DeviceState *dev, Error **errp) +{ + RTSYSCTL1State *s = RT_SYSCTL1(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &rt_sysctl1_ops, s, + TYPE_RT_SYSCTL1, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_rt_sysctl1 = { + .name = RT_SYSCTL1_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, RTSYSCTL1State, 512), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_sysctl1_init(Object *obj) +{ + RTSYSCTL1State *s = RT_SYSCTL1(obj); + + memory_region_init_io(&s->iomem, obj, &rt_sysctl1_ops, s, TYPE_RT_SYSCTL1, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + +} + +static void rt_sysctl1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_sysctl1_realize; + dc->vmsd = &vmstate_rt_sysctl1; +} + +static const TypeInfo rt_sysctl1_info = { + .name = TYPE_RT_SYSCTL1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTSYSCTL1State), + .instance_init = rt_sysctl1_init, + .class_init = rt_sysctl1_class_init, +}; + +static void rt_sysctl1_register_types(void) +{ + type_register_static(&rt_sysctl1_info); +} + +type_init(rt_sysctl1_register_types) + diff --git a/hw/misc/sbsa_ec.c b/hw/misc/sbsa_ec.c index 83020fe9ac9b..86b23a5372f3 100644 --- a/hw/misc/sbsa_ec.c +++ b/hw/misc/sbsa_ec.c @@ -11,18 +11,17 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/log.h" #include "hw/sysbus.h" #include "sysemu/runstate.h" -typedef struct { +typedef struct SECUREECState { SysBusDevice parent_obj; MemoryRegion iomem; } SECUREECState; -#define TYPE_SBSA_EC "sbsa-ec" -#define SECURE_EC(obj) OBJECT_CHECK(SECUREECState, (obj), TYPE_SBSA_EC) +#define TYPE_SBSA_SECURE_EC "sbsa-ec" +OBJECT_DECLARE_SIMPLE_TYPE(SECUREECState, SBSA_SECURE_EC) enum sbsa_ec_powerstates { SBSA_EC_CMD_POWEROFF = 0x01, @@ -37,7 +36,7 @@ static uint64_t sbsa_ec_read(void *opaque, hwaddr offset, unsigned size) } static void sbsa_ec_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) + uint64_t value, unsigned size) { if (offset == 0) { /* PSCI machine power command register */ switch (value) { @@ -66,7 +65,7 @@ static const MemoryRegionOps sbsa_ec_ops = { static void sbsa_ec_init(Object *obj) { - SECUREECState *s = SECURE_EC(obj); + SECUREECState *s = SBSA_SECURE_EC(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); memory_region_init_io(&s->iomem, obj, &sbsa_ec_ops, s, "sbsa-ec", @@ -83,7 +82,7 @@ static void sbsa_ec_class_init(ObjectClass *klass, void *data) } static const TypeInfo sbsa_ec_info = { - .name = TYPE_SBSA_EC, + .name = TYPE_SBSA_SECURE_EC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SECUREECState), .instance_init = sbsa_ec_init, diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index 6d5f84e6c206..6d7fdb040a57 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -64,8 +64,8 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) if (s->blk) { int32_t buf; - if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, - SIFIVE_U_OTP_FUSE_WORD) < 0) { + if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, + SIFIVE_U_OTP_FUSE_WORD, &buf, 0) < 0) { error_report("read error index<%d>", s->pa); return 0xff; } @@ -167,8 +167,8 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr, /* write to backend */ if (s->blk) { if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, - &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, - 0) < 0) { + SIFIVE_U_OTP_FUSE_WORD, &s->fuse[s->pa], 0) + < 0) { error_report("write error index<%d>", s->pa); } } @@ -240,7 +240,7 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp) return; } - if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) { + if (blk_pread(s->blk, 0, filesize, s->fuse, 0) < 0) { error_setg(errp, "failed to read the initial flash content"); return; } @@ -261,14 +261,14 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp) serial_data = s->serial; if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, - &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { + SIFIVE_U_OTP_FUSE_WORD, &serial_data, 0) < 0) { error_setg(errp, "failed to write index<%d>", index); return; } serial_data = ~(s->serial); if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, - &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { + SIFIVE_U_OTP_FUSE_WORD, &serial_data, 0) < 0) { error_setg(errp, "failed to write index<%d>", index + 1); return; } diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 4e0c7973a4d1..c47876a90262 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -23,6 +23,11 @@ allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" avr_power_read(uint8_t value) "power_reduc read value:%u" avr_power_write(uint8_t value) "power_reduc write value:%u" +# axp209.c +axp209_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8 +axp209_select(uint8_t reg) "Accessing reg 0x%" PRIx8 +axp209_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8 + # eccmemctl.c ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x" ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x" @@ -69,6 +74,7 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x" # aspeed_scu.c aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 +aspeed_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 # mps2-scc.c mps2_scc_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" @@ -209,6 +215,11 @@ aspeed_i3c_device_write(uint32_t deviceid, uint64_t offset, uint64_t data) "I3C aspeed_sdmc_write(uint64_t reg, uint64_t data) "reg @0x%" PRIx64 " data: 0x%" PRIx64 aspeed_sdmc_read(uint64_t reg, uint64_t data) "reg @0x%" PRIx64 " data: 0x%" PRIx64 +# aspeed_peci.c +aspeed_peci_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 +aspeed_peci_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 +aspeed_peci_raise_interrupt(uint32_t ctrl, uint32_t status) "ctrl 0x%" PRIx32 " status 0x%" PRIx32 + # bcm2835_property.c bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu" @@ -241,8 +252,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%%" @@ -263,3 +274,8 @@ virt_ctrl_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) virt_ctrl_reset(void *dev) "ctrl: %p" virt_ctrl_realize(void *dev) "ctrl: %p" virt_ctrl_instance_init(void *dev) "ctrl: %p" + +# lasi.c +lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" +lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" +lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c new file mode 100644 index 000000000000..767106b7a307 --- /dev/null +++ b/hw/misc/xlnx-versal-crl.c @@ -0,0 +1,421 @@ +/* + * QEMU model of the Clock-Reset-LPD (CRL). + * + * Copyright (c) 2022 Advanced Micro Devices, Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Written by Edgar E. Iglesias + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/bitops.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/register.h" +#include "hw/resettable.h" + +#include "target/arm/arm-powerctl.h" +#include "hw/misc/xlnx-versal-crl.h" + +#ifndef XLNX_VERSAL_CRL_ERR_DEBUG +#define XLNX_VERSAL_CRL_ERR_DEBUG 0 +#endif + +static void crl_update_irq(XlnxVersalCRL *s) +{ + bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK]; + qemu_set_irq(s->irq, pending); +} + +static void crl_status_postw(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + crl_update_irq(s); +} + +static uint64_t crl_enable_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + uint32_t val = val64; + + s->regs[R_IR_MASK] &= ~val; + crl_update_irq(s); + return 0; +} + +static uint64_t crl_disable_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + uint32_t val = val64; + + s->regs[R_IR_MASK] |= val; + crl_update_irq(s); + return 0; +} + +static void crl_reset_dev(XlnxVersalCRL *s, DeviceState *dev, + bool rst_old, bool rst_new) +{ + device_cold_reset(dev); +} + +static void crl_reset_cpu(XlnxVersalCRL *s, ARMCPU *armcpu, + bool rst_old, bool rst_new) +{ + if (rst_new) { + arm_set_cpu_off(armcpu->mp_affinity); + } else { + arm_set_cpu_on_and_reset(armcpu->mp_affinity); + } +} + +#define REGFIELD_RESET(type, s, reg, f, new_val, dev) { \ + bool old_f = ARRAY_FIELD_EX32((s)->regs, reg, f); \ + bool new_f = FIELD_EX32(new_val, reg, f); \ + \ + /* Detect edges. */ \ + if (dev && old_f != new_f) { \ + crl_reset_ ## type(s, dev, old_f, new_f); \ + } \ +} + +static uint64_t crl_rst_r5_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU0, val64, s->cfg.cpu_r5[0]); + REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU1, val64, s->cfg.cpu_r5[1]); + return val64; +} + +static uint64_t crl_rst_adma_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + int i; + + /* A single register fans out to all ADMA reset inputs. */ + for (i = 0; i < ARRAY_SIZE(s->cfg.adma); i++) { + REGFIELD_RESET(dev, s, RST_ADMA, RESET, val64, s->cfg.adma[i]); + } + return val64; +} + +static uint64_t crl_rst_uart0_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_UART0, RESET, val64, s->cfg.uart[0]); + return val64; +} + +static uint64_t crl_rst_uart1_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_UART1, RESET, val64, s->cfg.uart[1]); + return val64; +} + +static uint64_t crl_rst_gem0_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_GEM0, RESET, val64, s->cfg.gem[0]); + return val64; +} + +static uint64_t crl_rst_gem1_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_GEM1, RESET, val64, s->cfg.gem[1]); + return val64; +} + +static uint64_t crl_rst_usb_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_USB0, RESET, val64, s->cfg.usb); + return val64; +} + +static const RegisterAccessInfo crl_regs_info[] = { + { .name = "ERR_CTRL", .addr = A_ERR_CTRL, + },{ .name = "IR_STATUS", .addr = A_IR_STATUS, + .w1c = 0x1, + .post_write = crl_status_postw, + },{ .name = "IR_MASK", .addr = A_IR_MASK, + .reset = 0x1, + .ro = 0x1, + },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE, + .pre_write = crl_enable_prew, + },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE, + .pre_write = crl_disable_prew, + },{ .name = "WPROT", .addr = A_WPROT, + },{ .name = "PLL_CLK_OTHER_DMN", .addr = A_PLL_CLK_OTHER_DMN, + .reset = 0x1, + .rsvd = 0xe, + },{ .name = "RPLL_CTRL", .addr = A_RPLL_CTRL, + .reset = 0x24809, + .rsvd = 0xf88c00f6, + },{ .name = "RPLL_CFG", .addr = A_RPLL_CFG, + .reset = 0x2000000, + .rsvd = 0x1801210, + },{ .name = "RPLL_FRAC_CFG", .addr = A_RPLL_FRAC_CFG, + .rsvd = 0x7e330000, + },{ .name = "PLL_STATUS", .addr = A_PLL_STATUS, + .reset = R_PLL_STATUS_RPLL_STABLE_MASK | + R_PLL_STATUS_RPLL_LOCK_MASK, + .rsvd = 0xfa, + .ro = 0x5, + },{ .name = "RPLL_TO_XPD_CTRL", .addr = A_RPLL_TO_XPD_CTRL, + .reset = 0x2000100, + .rsvd = 0xfdfc00ff, + },{ .name = "LPD_TOP_SWITCH_CTRL", .addr = A_LPD_TOP_SWITCH_CTRL, + .reset = 0x6000300, + .rsvd = 0xf9fc00f8, + },{ .name = "LPD_LSBUS_CTRL", .addr = A_LPD_LSBUS_CTRL, + .reset = 0x2000800, + .rsvd = 0xfdfc00f8, + },{ .name = "CPU_R5_CTRL", .addr = A_CPU_R5_CTRL, + .reset = 0xe000300, + .rsvd = 0xe1fc00f8, + },{ .name = "IOU_SWITCH_CTRL", .addr = A_IOU_SWITCH_CTRL, + .reset = 0x2000500, + .rsvd = 0xfdfc00f8, + },{ .name = "GEM0_REF_CTRL", .addr = A_GEM0_REF_CTRL, + .reset = 0xe000a00, + .rsvd = 0xf1fc00f8, + },{ .name = "GEM1_REF_CTRL", .addr = A_GEM1_REF_CTRL, + .reset = 0xe000a00, + .rsvd = 0xf1fc00f8, + },{ .name = "GEM_TSU_REF_CTRL", .addr = A_GEM_TSU_REF_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "USB0_BUS_REF_CTRL", .addr = A_USB0_BUS_REF_CTRL, + .reset = 0x2001900, + .rsvd = 0xfdfc00f8, + },{ .name = "UART0_REF_CTRL", .addr = A_UART0_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "UART1_REF_CTRL", .addr = A_UART1_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "SPI0_REF_CTRL", .addr = A_SPI0_REF_CTRL, + .reset = 0x600, + .rsvd = 0xfdfc00f8, + },{ .name = "SPI1_REF_CTRL", .addr = A_SPI1_REF_CTRL, + .reset = 0x600, + .rsvd = 0xfdfc00f8, + },{ .name = "CAN0_REF_CTRL", .addr = A_CAN0_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "CAN1_REF_CTRL", .addr = A_CAN1_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "I2C0_REF_CTRL", .addr = A_I2C0_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "I2C1_REF_CTRL", .addr = A_I2C1_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "DBG_LPD_CTRL", .addr = A_DBG_LPD_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "TIMESTAMP_REF_CTRL", .addr = A_TIMESTAMP_REF_CTRL, + .reset = 0x2000c00, + .rsvd = 0xfdfc00f8, + },{ .name = "CRL_SAFETY_CHK", .addr = A_CRL_SAFETY_CHK, + },{ .name = "PSM_REF_CTRL", .addr = A_PSM_REF_CTRL, + .reset = 0xf04, + .rsvd = 0xfffc00f8, + },{ .name = "DBG_TSTMP_CTRL", .addr = A_DBG_TSTMP_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "CPM_TOPSW_REF_CTRL", .addr = A_CPM_TOPSW_REF_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "USB3_DUAL_REF_CTRL", .addr = A_USB3_DUAL_REF_CTRL, + .reset = 0x3c00, + .rsvd = 0xfdfc00f8, + },{ .name = "RST_CPU_R5", .addr = A_RST_CPU_R5, + .reset = 0x17, + .rsvd = 0x8, + .pre_write = crl_rst_r5_prew, + },{ .name = "RST_ADMA", .addr = A_RST_ADMA, + .reset = 0x1, + .pre_write = crl_rst_adma_prew, + },{ .name = "RST_GEM0", .addr = A_RST_GEM0, + .reset = 0x1, + .pre_write = crl_rst_gem0_prew, + },{ .name = "RST_GEM1", .addr = A_RST_GEM1, + .reset = 0x1, + .pre_write = crl_rst_gem1_prew, + },{ .name = "RST_SPARE", .addr = A_RST_SPARE, + .reset = 0x1, + },{ .name = "RST_USB0", .addr = A_RST_USB0, + .reset = 0x1, + .pre_write = crl_rst_usb_prew, + },{ .name = "RST_UART0", .addr = A_RST_UART0, + .reset = 0x1, + .pre_write = crl_rst_uart0_prew, + },{ .name = "RST_UART1", .addr = A_RST_UART1, + .reset = 0x1, + .pre_write = crl_rst_uart1_prew, + },{ .name = "RST_SPI0", .addr = A_RST_SPI0, + .reset = 0x1, + },{ .name = "RST_SPI1", .addr = A_RST_SPI1, + .reset = 0x1, + },{ .name = "RST_CAN0", .addr = A_RST_CAN0, + .reset = 0x1, + },{ .name = "RST_CAN1", .addr = A_RST_CAN1, + .reset = 0x1, + },{ .name = "RST_I2C0", .addr = A_RST_I2C0, + .reset = 0x1, + },{ .name = "RST_I2C1", .addr = A_RST_I2C1, + .reset = 0x1, + },{ .name = "RST_DBG_LPD", .addr = A_RST_DBG_LPD, + .reset = 0x33, + .rsvd = 0xcc, + },{ .name = "RST_GPIO", .addr = A_RST_GPIO, + .reset = 0x1, + },{ .name = "RST_TTC", .addr = A_RST_TTC, + .reset = 0xf, + },{ .name = "RST_TIMESTAMP", .addr = A_RST_TIMESTAMP, + .reset = 0x1, + },{ .name = "RST_SWDT", .addr = A_RST_SWDT, + .reset = 0x1, + },{ .name = "RST_OCM", .addr = A_RST_OCM, + },{ .name = "RST_IPI", .addr = A_RST_IPI, + },{ .name = "RST_FPD", .addr = A_RST_FPD, + .reset = 0x3, + },{ .name = "PSM_RST_MODE", .addr = A_PSM_RST_MODE, + .reset = 0x1, + .rsvd = 0xf8, + } +}; + +static void crl_reset_enter(Object *obj, ResetType type) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { + register_reset(&s->regs_info[i]); + } +} + +static void crl_reset_hold(Object *obj) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + + crl_update_irq(s); +} + +static const MemoryRegionOps crl_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void crl_init(Object *obj) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + s->reg_array = + register_init_block32(DEVICE(obj), crl_regs_info, + ARRAY_SIZE(crl_regs_info), + s->regs_info, s->regs, + &crl_ops, + XLNX_VERSAL_CRL_ERR_DEBUG, + CRL_R_MAX * 4); + sysbus_init_mmio(sbd, &s->reg_array->mem); + sysbus_init_irq(sbd, &s->irq); + + for (i = 0; i < ARRAY_SIZE(s->cfg.cpu_r5); ++i) { + object_property_add_link(obj, "cpu_r5[*]", TYPE_ARM_CPU, + (Object **)&s->cfg.cpu_r5[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + for (i = 0; i < ARRAY_SIZE(s->cfg.adma); ++i) { + object_property_add_link(obj, "adma[*]", TYPE_DEVICE, + (Object **)&s->cfg.adma[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + for (i = 0; i < ARRAY_SIZE(s->cfg.uart); ++i) { + object_property_add_link(obj, "uart[*]", TYPE_DEVICE, + (Object **)&s->cfg.uart[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + for (i = 0; i < ARRAY_SIZE(s->cfg.gem); ++i) { + object_property_add_link(obj, "gem[*]", TYPE_DEVICE, + (Object **)&s->cfg.gem[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + object_property_add_link(obj, "usb", TYPE_DEVICE, + (Object **)&s->cfg.gem[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); +} + +static void crl_finalize(Object *obj) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + register_finalize_block(s->reg_array); +} + +static const VMStateDescription vmstate_crl = { + .name = TYPE_XLNX_VERSAL_CRL, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, XlnxVersalCRL, CRL_R_MAX), + VMSTATE_END_OF_LIST(), + } +}; + +static void crl_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_crl; + + rc->phases.enter = crl_reset_enter; + rc->phases.hold = crl_reset_hold; +} + +static const TypeInfo crl_info = { + .name = TYPE_XLNX_VERSAL_CRL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XlnxVersalCRL), + .class_init = crl_class_init, + .instance_init = crl_init, + .instance_finalize = crl_finalize, +}; + +static void crl_register_types(void) +{ + type_register_static(&crl_info); +} + +type_init(crl_register_types) diff --git a/hw/net/Kconfig b/hw/net/Kconfig index 6d795ec75256..1cc1c5775eed 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -51,7 +51,7 @@ config RTL8139_PCI config VMXNET3_PCI bool - default y if PCI_DEVICES + default y if PCI_DEVICES && PC_PCI depends on PCI config SMC91C111 diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 24b3a0ff667b..42ea2411a218 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1429,7 +1429,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) { CadenceGEMState *s; uint32_t retval; - s = (CadenceGEMState *)opaque; + s = opaque; offset >>= 2; retval = s->regs[offset]; diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c index 94b3a534f841..2cd90cef1e15 100644 --- a/hw/net/can/can_kvaser_pci.c +++ b/hw/net/can/can_kvaser_pci.c @@ -37,7 +37,7 @@ #include "qapi/error.h" #include "chardev/char.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/can_emu.h" diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c index 29dc696f7c8a..b9918773b3fe 100644 --- a/hw/net/can/can_mioe3680_pci.c +++ b/hw/net/can/can_mioe3680_pci.c @@ -33,7 +33,7 @@ #include "qapi/error.h" #include "chardev/char.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/can_emu.h" diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c index e8e57f4f33e1..8ef3e4659cc0 100644 --- a/hw/net/can/can_pcm3680_pci.c +++ b/hw/net/can/can_pcm3680_pci.c @@ -33,7 +33,7 @@ #include "qapi/error.h" #include "chardev/char.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/can_emu.h" diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index 3ba803e947de..73201f91395a 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -247,21 +247,22 @@ int can_sja_accept_filter(CanSJA1000State *s, static void can_display_msg(const char *prefix, const qemu_can_frame *msg) { int i; - FILE *logfile = qemu_log_lock(); - - qemu_log("%s%03X [%01d] %s %s", - prefix, - msg->can_id & QEMU_CAN_EFF_MASK, - msg->can_dlc, - msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF", - msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT"); - - for (i = 0; i < msg->can_dlc; i++) { - qemu_log(" %02X", msg->data[i]); + FILE *logfile = qemu_log_trylock(); + + if (logfile) { + fprintf(logfile, "%s%03X [%01d] %s %s", + prefix, + msg->can_id & QEMU_CAN_EFF_MASK, + msg->can_dlc, + msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF", + msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT"); + + for (i = 0; i < msg->can_dlc; i++) { + fprintf(logfile, " %02X", msg->data[i]); + } + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); } - qemu_log("\n"); - qemu_log_flush(); - qemu_log_unlock(logfile); } static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame) @@ -430,7 +431,7 @@ void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val, (unsigned long long)val, (unsigned int)addr); if (addr > CAN_SJA_MEM_SIZE) { - return ; + return; } if (s->clock & 0x80) { /* PeliCAN Mode */ diff --git a/hw/net/can/ctu_can_fd_frame.h b/hw/net/can/ctu_can_fd_frame.h index 04d956c84ee7..8c43fd99dd0e 100644 --- a/hw/net/can/ctu_can_fd_frame.h +++ b/hw/net/can/ctu_can_fd_frame.h @@ -29,161 +29,161 @@ /* This file is autogenerated, DO NOT EDIT! */ -#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ -#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ +#ifndef HW_CAN_CTU_CAN_FD_FRAME_H +#define HW_CAN_CTU_CAN_FD_FRAME_H /* CAN_Frame_format memory map */ enum ctu_can_fd_can_frame_format { - CTU_CAN_FD_FRAME_FORM_W = 0x0, - CTU_CAN_FD_IDENTIFIER_W = 0x4, - CTU_CAN_FD_TIMESTAMP_L_W = 0x8, - CTU_CAN_FD_TIMESTAMP_U_W = 0xc, - CTU_CAN_FD_DATA_1_4_W = 0x10, - CTU_CAN_FD_DATA_5_8_W = 0x14, - CTU_CAN_FD_DATA_61_64_W = 0x4c, + CTU_CAN_FD_FRAME_FORM_W = 0x0, + CTU_CAN_FD_IDENTIFIER_W = 0x4, + CTU_CAN_FD_TIMESTAMP_L_W = 0x8, + CTU_CAN_FD_TIMESTAMP_U_W = 0xc, + CTU_CAN_FD_DATA_1_4_W = 0x10, + CTU_CAN_FD_DATA_5_8_W = 0x14, + CTU_CAN_FD_DATA_61_64_W = 0x4c, }; /* Register descriptions: */ union ctu_can_fd_frame_form_w { - uint32_t u32; - struct ctu_can_fd_frame_form_w_s { + uint32_t u32; + struct ctu_can_fd_frame_form_w_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FRAME_FORM_W */ - uint32_t dlc : 4; - uint32_t reserved_4 : 1; - uint32_t rtr : 1; - uint32_t ide : 1; - uint32_t fdf : 1; - uint32_t reserved_8 : 1; - uint32_t brs : 1; - uint32_t esi_rsv : 1; - uint32_t rwcnt : 5; - uint32_t reserved_31_16 : 16; + uint32_t dlc : 4; + uint32_t reserved_4 : 1; + uint32_t rtr : 1; + uint32_t ide : 1; + uint32_t fdf : 1; + uint32_t reserved_8 : 1; + uint32_t brs : 1; + uint32_t esi_rsv : 1; + uint32_t rwcnt : 5; + uint32_t reserved_31_16 : 16; #else - uint32_t reserved_31_16 : 16; - uint32_t rwcnt : 5; - uint32_t esi_rsv : 1; - uint32_t brs : 1; - uint32_t reserved_8 : 1; - uint32_t fdf : 1; - uint32_t ide : 1; - uint32_t rtr : 1; - uint32_t reserved_4 : 1; - uint32_t dlc : 4; + uint32_t reserved_31_16 : 16; + uint32_t rwcnt : 5; + uint32_t esi_rsv : 1; + uint32_t brs : 1; + uint32_t reserved_8 : 1; + uint32_t fdf : 1; + uint32_t ide : 1; + uint32_t rtr : 1; + uint32_t reserved_4 : 1; + uint32_t dlc : 4; #endif - } s; + } s; }; enum ctu_can_fd_frame_form_w_rtr { - NO_RTR_FRAME = 0x0, - RTR_FRAME = 0x1, + NO_RTR_FRAME = 0x0, + RTR_FRAME = 0x1, }; enum ctu_can_fd_frame_form_w_ide { - BASE = 0x0, - EXTENDED = 0x1, + BASE = 0x0, + EXTENDED = 0x1, }; enum ctu_can_fd_frame_form_w_fdf { - NORMAL_CAN = 0x0, - FD_CAN = 0x1, + NORMAL_CAN = 0x0, + FD_CAN = 0x1, }; enum ctu_can_fd_frame_form_w_brs { - BR_NO_SHIFT = 0x0, - BR_SHIFT = 0x1, + BR_NO_SHIFT = 0x0, + BR_SHIFT = 0x1, }; enum ctu_can_fd_frame_form_w_esi_rsv { - ESI_ERR_ACTIVE = 0x0, - ESI_ERR_PASIVE = 0x1, + ESI_ERR_ACTIVE = 0x0, + ESI_ERR_PASIVE = 0x1, }; union ctu_can_fd_identifier_w { - uint32_t u32; - struct ctu_can_fd_identifier_w_s { + uint32_t u32; + struct ctu_can_fd_identifier_w_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* IDENTIFIER_W */ - uint32_t identifier_ext : 18; - uint32_t identifier_base : 11; - uint32_t reserved_31_29 : 3; + uint32_t identifier_ext : 18; + uint32_t identifier_base : 11; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t identifier_base : 11; - uint32_t identifier_ext : 18; + uint32_t reserved_31_29 : 3; + uint32_t identifier_base : 11; + uint32_t identifier_ext : 18; #endif - } s; + } s; }; union ctu_can_fd_timestamp_l_w { - uint32_t u32; - struct ctu_can_fd_timestamp_l_w_s { + uint32_t u32; + struct ctu_can_fd_timestamp_l_w_s { /* TIMESTAMP_L_W */ - uint32_t time_stamp_31_0 : 32; - } s; + uint32_t time_stamp_31_0 : 32; + } s; }; union ctu_can_fd_timestamp_u_w { - uint32_t u32; - struct ctu_can_fd_timestamp_u_w_s { + uint32_t u32; + struct ctu_can_fd_timestamp_u_w_s { /* TIMESTAMP_U_W */ - uint32_t timestamp_l_w : 32; - } s; + uint32_t timestamp_l_w : 32; + } s; }; union ctu_can_fd_data_1_4_w { - uint32_t u32; - struct ctu_can_fd_data_1_4_w_s { + uint32_t u32; + struct ctu_can_fd_data_1_4_w_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* DATA_1_4_W */ - uint32_t data_1 : 8; - uint32_t data_2 : 8; - uint32_t data_3 : 8; - uint32_t data_4 : 8; + uint32_t data_1 : 8; + uint32_t data_2 : 8; + uint32_t data_3 : 8; + uint32_t data_4 : 8; #else - uint32_t data_4 : 8; - uint32_t data_3 : 8; - uint32_t data_2 : 8; - uint32_t data_1 : 8; + uint32_t data_4 : 8; + uint32_t data_3 : 8; + uint32_t data_2 : 8; + uint32_t data_1 : 8; #endif - } s; + } s; }; union ctu_can_fd_data_5_8_w { - uint32_t u32; - struct ctu_can_fd_data_5_8_w_s { + uint32_t u32; + struct ctu_can_fd_data_5_8_w_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* DATA_5_8_W */ - uint32_t data_5 : 8; - uint32_t data_6 : 8; - uint32_t data_7 : 8; - uint32_t data_8 : 8; + uint32_t data_5 : 8; + uint32_t data_6 : 8; + uint32_t data_7 : 8; + uint32_t data_8 : 8; #else - uint32_t data_8 : 8; - uint32_t data_7 : 8; - uint32_t data_6 : 8; - uint32_t data_5 : 8; + uint32_t data_8 : 8; + uint32_t data_7 : 8; + uint32_t data_6 : 8; + uint32_t data_5 : 8; #endif - } s; + } s; }; union ctu_can_fd_data_61_64_w { - uint32_t u32; - struct ctu_can_fd_data_61_64_w_s { + uint32_t u32; + struct ctu_can_fd_data_61_64_w_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* DATA_61_64_W */ - uint32_t data_61 : 8; - uint32_t data_62 : 8; - uint32_t data_63 : 8; - uint32_t data_64 : 8; + uint32_t data_61 : 8; + uint32_t data_62 : 8; + uint32_t data_63 : 8; + uint32_t data_64 : 8; #else - uint32_t data_64 : 8; - uint32_t data_63 : 8; - uint32_t data_62 : 8; - uint32_t data_61 : 8; + uint32_t data_64 : 8; + uint32_t data_63 : 8; + uint32_t data_62 : 8; + uint32_t data_61 : 8; #endif - } s; + } s; }; #endif diff --git a/hw/net/can/ctu_can_fd_regs.h b/hw/net/can/ctu_can_fd_regs.h index 450f4b9fb3c4..d2d88cdd1a4b 100644 --- a/hw/net/can/ctu_can_fd_regs.h +++ b/hw/net/can/ctu_can_fd_regs.h @@ -29,943 +29,943 @@ /* This file is autogenerated, DO NOT EDIT! */ -#ifndef __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ -#define __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ +#ifndef HW_CAN_CTU_CAN_FD_REGS_H +#define HW_CAN_CTU_CAN_FD_REGS_H /* CAN_Registers memory map */ enum ctu_can_fd_can_registers { - CTU_CAN_FD_DEVICE_ID = 0x0, - CTU_CAN_FD_VERSION = 0x2, - CTU_CAN_FD_MODE = 0x4, - CTU_CAN_FD_SETTINGS = 0x6, - CTU_CAN_FD_STATUS = 0x8, - CTU_CAN_FD_COMMAND = 0xc, - CTU_CAN_FD_INT_STAT = 0x10, - CTU_CAN_FD_INT_ENA_SET = 0x14, - CTU_CAN_FD_INT_ENA_CLR = 0x18, - CTU_CAN_FD_INT_MASK_SET = 0x1c, - CTU_CAN_FD_INT_MASK_CLR = 0x20, - CTU_CAN_FD_BTR = 0x24, - CTU_CAN_FD_BTR_FD = 0x28, - CTU_CAN_FD_EWL = 0x2c, - CTU_CAN_FD_ERP = 0x2d, - CTU_CAN_FD_FAULT_STATE = 0x2e, - CTU_CAN_FD_REC = 0x30, - CTU_CAN_FD_TEC = 0x32, - CTU_CAN_FD_ERR_NORM = 0x34, - CTU_CAN_FD_ERR_FD = 0x36, - CTU_CAN_FD_CTR_PRES = 0x38, - CTU_CAN_FD_FILTER_A_MASK = 0x3c, - CTU_CAN_FD_FILTER_A_VAL = 0x40, - CTU_CAN_FD_FILTER_B_MASK = 0x44, - CTU_CAN_FD_FILTER_B_VAL = 0x48, - CTU_CAN_FD_FILTER_C_MASK = 0x4c, - CTU_CAN_FD_FILTER_C_VAL = 0x50, - CTU_CAN_FD_FILTER_RAN_LOW = 0x54, - CTU_CAN_FD_FILTER_RAN_HIGH = 0x58, - CTU_CAN_FD_FILTER_CONTROL = 0x5c, - CTU_CAN_FD_FILTER_STATUS = 0x5e, - CTU_CAN_FD_RX_MEM_INFO = 0x60, - CTU_CAN_FD_RX_POINTERS = 0x64, - CTU_CAN_FD_RX_STATUS = 0x68, - CTU_CAN_FD_RX_SETTINGS = 0x6a, - CTU_CAN_FD_RX_DATA = 0x6c, - CTU_CAN_FD_TX_STATUS = 0x70, - CTU_CAN_FD_TX_COMMAND = 0x74, - CTU_CAN_FD_TX_PRIORITY = 0x78, - CTU_CAN_FD_ERR_CAPT = 0x7c, - CTU_CAN_FD_ALC = 0x7e, - CTU_CAN_FD_TRV_DELAY = 0x80, - CTU_CAN_FD_SSP_CFG = 0x82, - CTU_CAN_FD_RX_FR_CTR = 0x84, - CTU_CAN_FD_TX_FR_CTR = 0x88, - CTU_CAN_FD_DEBUG_REGISTER = 0x8c, - CTU_CAN_FD_YOLO_REG = 0x90, - CTU_CAN_FD_TIMESTAMP_LOW = 0x94, - CTU_CAN_FD_TIMESTAMP_HIGH = 0x98, - CTU_CAN_FD_TXTB1_DATA_1 = 0x100, - CTU_CAN_FD_TXTB1_DATA_2 = 0x104, - CTU_CAN_FD_TXTB1_DATA_20 = 0x14c, - CTU_CAN_FD_TXTB2_DATA_1 = 0x200, - CTU_CAN_FD_TXTB2_DATA_2 = 0x204, - CTU_CAN_FD_TXTB2_DATA_20 = 0x24c, - CTU_CAN_FD_TXTB3_DATA_1 = 0x300, - CTU_CAN_FD_TXTB3_DATA_2 = 0x304, - CTU_CAN_FD_TXTB3_DATA_20 = 0x34c, - CTU_CAN_FD_TXTB4_DATA_1 = 0x400, - CTU_CAN_FD_TXTB4_DATA_2 = 0x404, - CTU_CAN_FD_TXTB4_DATA_20 = 0x44c, + CTU_CAN_FD_DEVICE_ID = 0x0, + CTU_CAN_FD_VERSION = 0x2, + CTU_CAN_FD_MODE = 0x4, + CTU_CAN_FD_SETTINGS = 0x6, + CTU_CAN_FD_STATUS = 0x8, + CTU_CAN_FD_COMMAND = 0xc, + CTU_CAN_FD_INT_STAT = 0x10, + CTU_CAN_FD_INT_ENA_SET = 0x14, + CTU_CAN_FD_INT_ENA_CLR = 0x18, + CTU_CAN_FD_INT_MASK_SET = 0x1c, + CTU_CAN_FD_INT_MASK_CLR = 0x20, + CTU_CAN_FD_BTR = 0x24, + CTU_CAN_FD_BTR_FD = 0x28, + CTU_CAN_FD_EWL = 0x2c, + CTU_CAN_FD_ERP = 0x2d, + CTU_CAN_FD_FAULT_STATE = 0x2e, + CTU_CAN_FD_REC = 0x30, + CTU_CAN_FD_TEC = 0x32, + CTU_CAN_FD_ERR_NORM = 0x34, + CTU_CAN_FD_ERR_FD = 0x36, + CTU_CAN_FD_CTR_PRES = 0x38, + CTU_CAN_FD_FILTER_A_MASK = 0x3c, + CTU_CAN_FD_FILTER_A_VAL = 0x40, + CTU_CAN_FD_FILTER_B_MASK = 0x44, + CTU_CAN_FD_FILTER_B_VAL = 0x48, + CTU_CAN_FD_FILTER_C_MASK = 0x4c, + CTU_CAN_FD_FILTER_C_VAL = 0x50, + CTU_CAN_FD_FILTER_RAN_LOW = 0x54, + CTU_CAN_FD_FILTER_RAN_HIGH = 0x58, + CTU_CAN_FD_FILTER_CONTROL = 0x5c, + CTU_CAN_FD_FILTER_STATUS = 0x5e, + CTU_CAN_FD_RX_MEM_INFO = 0x60, + CTU_CAN_FD_RX_POINTERS = 0x64, + CTU_CAN_FD_RX_STATUS = 0x68, + CTU_CAN_FD_RX_SETTINGS = 0x6a, + CTU_CAN_FD_RX_DATA = 0x6c, + CTU_CAN_FD_TX_STATUS = 0x70, + CTU_CAN_FD_TX_COMMAND = 0x74, + CTU_CAN_FD_TX_PRIORITY = 0x78, + CTU_CAN_FD_ERR_CAPT = 0x7c, + CTU_CAN_FD_ALC = 0x7e, + CTU_CAN_FD_TRV_DELAY = 0x80, + CTU_CAN_FD_SSP_CFG = 0x82, + CTU_CAN_FD_RX_FR_CTR = 0x84, + CTU_CAN_FD_TX_FR_CTR = 0x88, + CTU_CAN_FD_DEBUG_REGISTER = 0x8c, + CTU_CAN_FD_YOLO_REG = 0x90, + CTU_CAN_FD_TIMESTAMP_LOW = 0x94, + CTU_CAN_FD_TIMESTAMP_HIGH = 0x98, + CTU_CAN_FD_TXTB1_DATA_1 = 0x100, + CTU_CAN_FD_TXTB1_DATA_2 = 0x104, + CTU_CAN_FD_TXTB1_DATA_20 = 0x14c, + CTU_CAN_FD_TXTB2_DATA_1 = 0x200, + CTU_CAN_FD_TXTB2_DATA_2 = 0x204, + CTU_CAN_FD_TXTB2_DATA_20 = 0x24c, + CTU_CAN_FD_TXTB3_DATA_1 = 0x300, + CTU_CAN_FD_TXTB3_DATA_2 = 0x304, + CTU_CAN_FD_TXTB3_DATA_20 = 0x34c, + CTU_CAN_FD_TXTB4_DATA_1 = 0x400, + CTU_CAN_FD_TXTB4_DATA_2 = 0x404, + CTU_CAN_FD_TXTB4_DATA_20 = 0x44c, }; /* Register descriptions: */ union ctu_can_fd_device_id_version { - uint32_t u32; - struct ctu_can_fd_device_id_version_s { + uint32_t u32; + struct ctu_can_fd_device_id_version_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* DEVICE_ID */ - uint32_t device_id : 16; + uint32_t device_id : 16; /* VERSION */ - uint32_t ver_minor : 8; - uint32_t ver_major : 8; + uint32_t ver_minor : 8; + uint32_t ver_major : 8; #else - uint32_t ver_major : 8; - uint32_t ver_minor : 8; - uint32_t device_id : 16; + uint32_t ver_major : 8; + uint32_t ver_minor : 8; + uint32_t device_id : 16; #endif - } s; + } s; }; enum ctu_can_fd_device_id_device_id { - CTU_CAN_FD_ID = 0xcafd, + CTU_CAN_FD_ID = 0xcafd, }; union ctu_can_fd_mode_settings { - uint32_t u32; - struct ctu_can_fd_mode_settings_s { + uint32_t u32; + struct ctu_can_fd_mode_settings_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* MODE */ - uint32_t rst : 1; - uint32_t lom : 1; - uint32_t stm : 1; - uint32_t afm : 1; - uint32_t fde : 1; - uint32_t reserved_6_5 : 2; - uint32_t acf : 1; - uint32_t tstm : 1; - uint32_t reserved_15_9 : 7; + uint32_t rst : 1; + uint32_t lom : 1; + uint32_t stm : 1; + uint32_t afm : 1; + uint32_t fde : 1; + uint32_t reserved_6_5 : 2; + uint32_t acf : 1; + uint32_t tstm : 1; + uint32_t reserved_15_9 : 7; /* SETTINGS */ - uint32_t rtrle : 1; - uint32_t rtrth : 4; - uint32_t ilbp : 1; - uint32_t ena : 1; - uint32_t nisofd : 1; - uint32_t pex : 1; - uint32_t reserved_31_25 : 7; -#else - uint32_t reserved_31_25 : 7; - uint32_t pex : 1; - uint32_t nisofd : 1; - uint32_t ena : 1; - uint32_t ilbp : 1; - uint32_t rtrth : 4; - uint32_t rtrle : 1; - uint32_t reserved_15_9 : 7; - uint32_t tstm : 1; - uint32_t acf : 1; - uint32_t reserved_6_5 : 2; - uint32_t fde : 1; - uint32_t afm : 1; - uint32_t stm : 1; - uint32_t lom : 1; - uint32_t rst : 1; -#endif - } s; + uint32_t rtrle : 1; + uint32_t rtrth : 4; + uint32_t ilbp : 1; + uint32_t ena : 1; + uint32_t nisofd : 1; + uint32_t pex : 1; + uint32_t reserved_31_25 : 7; +#else + uint32_t reserved_31_25 : 7; + uint32_t pex : 1; + uint32_t nisofd : 1; + uint32_t ena : 1; + uint32_t ilbp : 1; + uint32_t rtrth : 4; + uint32_t rtrle : 1; + uint32_t reserved_15_9 : 7; + uint32_t tstm : 1; + uint32_t acf : 1; + uint32_t reserved_6_5 : 2; + uint32_t fde : 1; + uint32_t afm : 1; + uint32_t stm : 1; + uint32_t lom : 1; + uint32_t rst : 1; +#endif + } s; }; enum ctu_can_fd_mode_lom { - LOM_DISABLED = 0x0, - LOM_ENABLED = 0x1, + LOM_DISABLED = 0x0, + LOM_ENABLED = 0x1, }; enum ctu_can_fd_mode_stm { - STM_DISABLED = 0x0, - STM_ENABLED = 0x1, + STM_DISABLED = 0x0, + STM_ENABLED = 0x1, }; enum ctu_can_fd_mode_afm { - AFM_DISABLED = 0x0, - AFM_ENABLED = 0x1, + AFM_DISABLED = 0x0, + AFM_ENABLED = 0x1, }; enum ctu_can_fd_mode_fde { - FDE_DISABLE = 0x0, - FDE_ENABLE = 0x1, + FDE_DISABLE = 0x0, + FDE_ENABLE = 0x1, }; enum ctu_can_fd_mode_acf { - ACF_DISABLED = 0x0, - ACF_ENABLED = 0x1, + ACF_DISABLED = 0x0, + ACF_ENABLED = 0x1, }; enum ctu_can_fd_settings_rtrle { - RTRLE_DISABLED = 0x0, - RTRLE_ENABLED = 0x1, + RTRLE_DISABLED = 0x0, + RTRLE_ENABLED = 0x1, }; enum ctu_can_fd_settings_ilbp { - INT_LOOP_DISABLED = 0x0, - INT_LOOP_ENABLED = 0x1, + INT_LOOP_DISABLED = 0x0, + INT_LOOP_ENABLED = 0x1, }; enum ctu_can_fd_settings_ena { - CTU_CAN_DISABLED = 0x0, - CTU_CAN_ENABLED = 0x1, + CTU_CAN_DISABLED = 0x0, + CTU_CAN_ENABLED = 0x1, }; enum ctu_can_fd_settings_nisofd { - ISO_FD = 0x0, - NON_ISO_FD = 0x1, + ISO_FD = 0x0, + NON_ISO_FD = 0x1, }; enum ctu_can_fd_settings_pex { - PROTOCOL_EXCEPTION_DISABLED = 0x0, - PROTOCOL_EXCEPTION_ENABLED = 0x1, + PROTOCOL_EXCEPTION_DISABLED = 0x0, + PROTOCOL_EXCEPTION_ENABLED = 0x1, }; union ctu_can_fd_status { - uint32_t u32; - struct ctu_can_fd_status_s { + uint32_t u32; + struct ctu_can_fd_status_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* STATUS */ - uint32_t rxne : 1; - uint32_t dor : 1; - uint32_t txnf : 1; - uint32_t eft : 1; - uint32_t rxs : 1; - uint32_t txs : 1; - uint32_t ewl : 1; - uint32_t idle : 1; - uint32_t reserved_31_8 : 24; -#else - uint32_t reserved_31_8 : 24; - uint32_t idle : 1; - uint32_t ewl : 1; - uint32_t txs : 1; - uint32_t rxs : 1; - uint32_t eft : 1; - uint32_t txnf : 1; - uint32_t dor : 1; - uint32_t rxne : 1; -#endif - } s; + uint32_t rxne : 1; + uint32_t dor : 1; + uint32_t txnf : 1; + uint32_t eft : 1; + uint32_t rxs : 1; + uint32_t txs : 1; + uint32_t ewl : 1; + uint32_t idle : 1; + uint32_t reserved_31_8 : 24; +#else + uint32_t reserved_31_8 : 24; + uint32_t idle : 1; + uint32_t ewl : 1; + uint32_t txs : 1; + uint32_t rxs : 1; + uint32_t eft : 1; + uint32_t txnf : 1; + uint32_t dor : 1; + uint32_t rxne : 1; +#endif + } s; }; union ctu_can_fd_command { - uint32_t u32; - struct ctu_can_fd_command_s { + uint32_t u32; + struct ctu_can_fd_command_s { #ifdef __LITTLE_ENDIAN_BITFIELD - uint32_t reserved_1_0 : 2; + uint32_t reserved_1_0 : 2; /* COMMAND */ - uint32_t rrb : 1; - uint32_t cdo : 1; - uint32_t ercrst : 1; - uint32_t rxfcrst : 1; - uint32_t txfcrst : 1; - uint32_t reserved_31_7 : 25; + uint32_t rrb : 1; + uint32_t cdo : 1; + uint32_t ercrst : 1; + uint32_t rxfcrst : 1; + uint32_t txfcrst : 1; + uint32_t reserved_31_7 : 25; #else - uint32_t reserved_31_7 : 25; - uint32_t txfcrst : 1; - uint32_t rxfcrst : 1; - uint32_t ercrst : 1; - uint32_t cdo : 1; - uint32_t rrb : 1; - uint32_t reserved_1_0 : 2; + uint32_t reserved_31_7 : 25; + uint32_t txfcrst : 1; + uint32_t rxfcrst : 1; + uint32_t ercrst : 1; + uint32_t cdo : 1; + uint32_t rrb : 1; + uint32_t reserved_1_0 : 2; #endif - } s; + } s; }; union ctu_can_fd_int_stat { - uint32_t u32; - struct ctu_can_fd_int_stat_s { + uint32_t u32; + struct ctu_can_fd_int_stat_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* INT_STAT */ - uint32_t rxi : 1; - uint32_t txi : 1; - uint32_t ewli : 1; - uint32_t doi : 1; - uint32_t fcsi : 1; - uint32_t ali : 1; - uint32_t bei : 1; - uint32_t ofi : 1; - uint32_t rxfi : 1; - uint32_t bsi : 1; - uint32_t rbnei : 1; - uint32_t txbhci : 1; - uint32_t reserved_31_12 : 20; -#else - uint32_t reserved_31_12 : 20; - uint32_t txbhci : 1; - uint32_t rbnei : 1; - uint32_t bsi : 1; - uint32_t rxfi : 1; - uint32_t ofi : 1; - uint32_t bei : 1; - uint32_t ali : 1; - uint32_t fcsi : 1; - uint32_t doi : 1; - uint32_t ewli : 1; - uint32_t txi : 1; - uint32_t rxi : 1; -#endif - } s; + uint32_t rxi : 1; + uint32_t txi : 1; + uint32_t ewli : 1; + uint32_t doi : 1; + uint32_t fcsi : 1; + uint32_t ali : 1; + uint32_t bei : 1; + uint32_t ofi : 1; + uint32_t rxfi : 1; + uint32_t bsi : 1; + uint32_t rbnei : 1; + uint32_t txbhci : 1; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t txbhci : 1; + uint32_t rbnei : 1; + uint32_t bsi : 1; + uint32_t rxfi : 1; + uint32_t ofi : 1; + uint32_t bei : 1; + uint32_t ali : 1; + uint32_t fcsi : 1; + uint32_t doi : 1; + uint32_t ewli : 1; + uint32_t txi : 1; + uint32_t rxi : 1; +#endif + } s; }; union ctu_can_fd_int_ena_set { - uint32_t u32; - struct ctu_can_fd_int_ena_set_s { + uint32_t u32; + struct ctu_can_fd_int_ena_set_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* INT_ENA_SET */ - uint32_t int_ena_set : 12; - uint32_t reserved_31_12 : 20; + uint32_t int_ena_set : 12; + uint32_t reserved_31_12 : 20; #else - uint32_t reserved_31_12 : 20; - uint32_t int_ena_set : 12; + uint32_t reserved_31_12 : 20; + uint32_t int_ena_set : 12; #endif - } s; + } s; }; union ctu_can_fd_int_ena_clr { - uint32_t u32; - struct ctu_can_fd_int_ena_clr_s { + uint32_t u32; + struct ctu_can_fd_int_ena_clr_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* INT_ENA_CLR */ - uint32_t int_ena_clr : 12; - uint32_t reserved_31_12 : 20; + uint32_t int_ena_clr : 12; + uint32_t reserved_31_12 : 20; #else - uint32_t reserved_31_12 : 20; - uint32_t int_ena_clr : 12; + uint32_t reserved_31_12 : 20; + uint32_t int_ena_clr : 12; #endif - } s; + } s; }; union ctu_can_fd_int_mask_set { - uint32_t u32; - struct ctu_can_fd_int_mask_set_s { + uint32_t u32; + struct ctu_can_fd_int_mask_set_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* INT_MASK_SET */ - uint32_t int_mask_set : 12; - uint32_t reserved_31_12 : 20; + uint32_t int_mask_set : 12; + uint32_t reserved_31_12 : 20; #else - uint32_t reserved_31_12 : 20; - uint32_t int_mask_set : 12; + uint32_t reserved_31_12 : 20; + uint32_t int_mask_set : 12; #endif - } s; + } s; }; union ctu_can_fd_int_mask_clr { - uint32_t u32; - struct ctu_can_fd_int_mask_clr_s { + uint32_t u32; + struct ctu_can_fd_int_mask_clr_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* INT_MASK_CLR */ - uint32_t int_mask_clr : 12; - uint32_t reserved_31_12 : 20; + uint32_t int_mask_clr : 12; + uint32_t reserved_31_12 : 20; #else - uint32_t reserved_31_12 : 20; - uint32_t int_mask_clr : 12; + uint32_t reserved_31_12 : 20; + uint32_t int_mask_clr : 12; #endif - } s; + } s; }; union ctu_can_fd_btr { - uint32_t u32; - struct ctu_can_fd_btr_s { + uint32_t u32; + struct ctu_can_fd_btr_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* BTR */ - uint32_t prop : 7; - uint32_t ph1 : 6; - uint32_t ph2 : 6; - uint32_t brp : 8; - uint32_t sjw : 5; + uint32_t prop : 7; + uint32_t ph1 : 6; + uint32_t ph2 : 6; + uint32_t brp : 8; + uint32_t sjw : 5; #else - uint32_t sjw : 5; - uint32_t brp : 8; - uint32_t ph2 : 6; - uint32_t ph1 : 6; - uint32_t prop : 7; + uint32_t sjw : 5; + uint32_t brp : 8; + uint32_t ph2 : 6; + uint32_t ph1 : 6; + uint32_t prop : 7; #endif - } s; + } s; }; union ctu_can_fd_btr_fd { - uint32_t u32; - struct ctu_can_fd_btr_fd_s { + uint32_t u32; + struct ctu_can_fd_btr_fd_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* BTR_FD */ - uint32_t prop_fd : 6; - uint32_t reserved_6 : 1; - uint32_t ph1_fd : 5; - uint32_t reserved_12 : 1; - uint32_t ph2_fd : 5; - uint32_t reserved_18 : 1; - uint32_t brp_fd : 8; - uint32_t sjw_fd : 5; -#else - uint32_t sjw_fd : 5; - uint32_t brp_fd : 8; - uint32_t reserved_18 : 1; - uint32_t ph2_fd : 5; - uint32_t reserved_12 : 1; - uint32_t ph1_fd : 5; - uint32_t reserved_6 : 1; - uint32_t prop_fd : 6; -#endif - } s; + uint32_t prop_fd : 6; + uint32_t reserved_6 : 1; + uint32_t ph1_fd : 5; + uint32_t reserved_12 : 1; + uint32_t ph2_fd : 5; + uint32_t reserved_18 : 1; + uint32_t brp_fd : 8; + uint32_t sjw_fd : 5; +#else + uint32_t sjw_fd : 5; + uint32_t brp_fd : 8; + uint32_t reserved_18 : 1; + uint32_t ph2_fd : 5; + uint32_t reserved_12 : 1; + uint32_t ph1_fd : 5; + uint32_t reserved_6 : 1; + uint32_t prop_fd : 6; +#endif + } s; }; union ctu_can_fd_ewl_erp_fault_state { - uint32_t u32; - struct ctu_can_fd_ewl_erp_fault_state_s { + uint32_t u32; + struct ctu_can_fd_ewl_erp_fault_state_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* EWL */ - uint32_t ew_limit : 8; + uint32_t ew_limit : 8; /* ERP */ - uint32_t erp_limit : 8; + uint32_t erp_limit : 8; /* FAULT_STATE */ - uint32_t era : 1; - uint32_t erp : 1; - uint32_t bof : 1; - uint32_t reserved_31_19 : 13; + uint32_t era : 1; + uint32_t erp : 1; + uint32_t bof : 1; + uint32_t reserved_31_19 : 13; #else - uint32_t reserved_31_19 : 13; - uint32_t bof : 1; - uint32_t erp : 1; - uint32_t era : 1; - uint32_t erp_limit : 8; - uint32_t ew_limit : 8; + uint32_t reserved_31_19 : 13; + uint32_t bof : 1; + uint32_t erp : 1; + uint32_t era : 1; + uint32_t erp_limit : 8; + uint32_t ew_limit : 8; #endif - } s; + } s; }; union ctu_can_fd_rec_tec { - uint32_t u32; - struct ctu_can_fd_rec_tec_s { + uint32_t u32; + struct ctu_can_fd_rec_tec_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* REC */ - uint32_t rec_val : 9; - uint32_t reserved_15_9 : 7; + uint32_t rec_val : 9; + uint32_t reserved_15_9 : 7; /* TEC */ - uint32_t tec_val : 9; - uint32_t reserved_31_25 : 7; + uint32_t tec_val : 9; + uint32_t reserved_31_25 : 7; #else - uint32_t reserved_31_25 : 7; - uint32_t tec_val : 9; - uint32_t reserved_15_9 : 7; - uint32_t rec_val : 9; + uint32_t reserved_31_25 : 7; + uint32_t tec_val : 9; + uint32_t reserved_15_9 : 7; + uint32_t rec_val : 9; #endif - } s; + } s; }; union ctu_can_fd_err_norm_err_fd { - uint32_t u32; - struct ctu_can_fd_err_norm_err_fd_s { + uint32_t u32; + struct ctu_can_fd_err_norm_err_fd_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* ERR_NORM */ - uint32_t err_norm_val : 16; + uint32_t err_norm_val : 16; /* ERR_FD */ - uint32_t err_fd_val : 16; + uint32_t err_fd_val : 16; #else - uint32_t err_fd_val : 16; - uint32_t err_norm_val : 16; + uint32_t err_fd_val : 16; + uint32_t err_norm_val : 16; #endif - } s; + } s; }; union ctu_can_fd_ctr_pres { - uint32_t u32; - struct ctu_can_fd_ctr_pres_s { + uint32_t u32; + struct ctu_can_fd_ctr_pres_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* CTR_PRES */ - uint32_t ctpv : 9; - uint32_t ptx : 1; - uint32_t prx : 1; - uint32_t enorm : 1; - uint32_t efd : 1; - uint32_t reserved_31_13 : 19; + uint32_t ctpv : 9; + uint32_t ptx : 1; + uint32_t prx : 1; + uint32_t enorm : 1; + uint32_t efd : 1; + uint32_t reserved_31_13 : 19; #else - uint32_t reserved_31_13 : 19; - uint32_t efd : 1; - uint32_t enorm : 1; - uint32_t prx : 1; - uint32_t ptx : 1; - uint32_t ctpv : 9; + uint32_t reserved_31_13 : 19; + uint32_t efd : 1; + uint32_t enorm : 1; + uint32_t prx : 1; + uint32_t ptx : 1; + uint32_t ctpv : 9; #endif - } s; + } s; }; union ctu_can_fd_filter_a_mask { - uint32_t u32; - struct ctu_can_fd_filter_a_mask_s { + uint32_t u32; + struct ctu_can_fd_filter_a_mask_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_A_MASK */ - uint32_t bit_mask_a_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_mask_a_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_mask_a_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_mask_a_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_a_val { - uint32_t u32; - struct ctu_can_fd_filter_a_val_s { + uint32_t u32; + struct ctu_can_fd_filter_a_val_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_A_VAL */ - uint32_t bit_val_a_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_val_a_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_val_a_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_val_a_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_b_mask { - uint32_t u32; - struct ctu_can_fd_filter_b_mask_s { + uint32_t u32; + struct ctu_can_fd_filter_b_mask_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_B_MASK */ - uint32_t bit_mask_b_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_mask_b_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_mask_b_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_mask_b_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_b_val { - uint32_t u32; - struct ctu_can_fd_filter_b_val_s { + uint32_t u32; + struct ctu_can_fd_filter_b_val_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_B_VAL */ - uint32_t bit_val_b_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_val_b_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_val_b_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_val_b_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_c_mask { - uint32_t u32; - struct ctu_can_fd_filter_c_mask_s { + uint32_t u32; + struct ctu_can_fd_filter_c_mask_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_C_MASK */ - uint32_t bit_mask_c_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_mask_c_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_mask_c_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_mask_c_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_c_val { - uint32_t u32; - struct ctu_can_fd_filter_c_val_s { + uint32_t u32; + struct ctu_can_fd_filter_c_val_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_C_VAL */ - uint32_t bit_val_c_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_val_c_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_val_c_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_val_c_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_ran_low { - uint32_t u32; - struct ctu_can_fd_filter_ran_low_s { + uint32_t u32; + struct ctu_can_fd_filter_ran_low_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_RAN_LOW */ - uint32_t bit_ran_low_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_ran_low_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_ran_low_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_ran_low_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_ran_high { - uint32_t u32; - struct ctu_can_fd_filter_ran_high_s { + uint32_t u32; + struct ctu_can_fd_filter_ran_high_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_RAN_HIGH */ - uint32_t bit_ran_high_val : 29; - uint32_t reserved_31_29 : 3; + uint32_t bit_ran_high_val : 29; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t bit_ran_high_val : 29; + uint32_t reserved_31_29 : 3; + uint32_t bit_ran_high_val : 29; #endif - } s; + } s; }; union ctu_can_fd_filter_control_filter_status { - uint32_t u32; - struct ctu_can_fd_filter_control_filter_status_s { + uint32_t u32; + struct ctu_can_fd_filter_control_filter_status_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* FILTER_CONTROL */ - uint32_t fanb : 1; - uint32_t fane : 1; - uint32_t fafb : 1; - uint32_t fafe : 1; - uint32_t fbnb : 1; - uint32_t fbne : 1; - uint32_t fbfb : 1; - uint32_t fbfe : 1; - uint32_t fcnb : 1; - uint32_t fcne : 1; - uint32_t fcfb : 1; - uint32_t fcfe : 1; - uint32_t frnb : 1; - uint32_t frne : 1; - uint32_t frfb : 1; - uint32_t frfe : 1; + uint32_t fanb : 1; + uint32_t fane : 1; + uint32_t fafb : 1; + uint32_t fafe : 1; + uint32_t fbnb : 1; + uint32_t fbne : 1; + uint32_t fbfb : 1; + uint32_t fbfe : 1; + uint32_t fcnb : 1; + uint32_t fcne : 1; + uint32_t fcfb : 1; + uint32_t fcfe : 1; + uint32_t frnb : 1; + uint32_t frne : 1; + uint32_t frfb : 1; + uint32_t frfe : 1; /* FILTER_STATUS */ - uint32_t sfa : 1; - uint32_t sfb : 1; - uint32_t sfc : 1; - uint32_t sfr : 1; - uint32_t reserved_31_20 : 12; -#else - uint32_t reserved_31_20 : 12; - uint32_t sfr : 1; - uint32_t sfc : 1; - uint32_t sfb : 1; - uint32_t sfa : 1; - uint32_t frfe : 1; - uint32_t frfb : 1; - uint32_t frne : 1; - uint32_t frnb : 1; - uint32_t fcfe : 1; - uint32_t fcfb : 1; - uint32_t fcne : 1; - uint32_t fcnb : 1; - uint32_t fbfe : 1; - uint32_t fbfb : 1; - uint32_t fbne : 1; - uint32_t fbnb : 1; - uint32_t fafe : 1; - uint32_t fafb : 1; - uint32_t fane : 1; - uint32_t fanb : 1; -#endif - } s; + uint32_t sfa : 1; + uint32_t sfb : 1; + uint32_t sfc : 1; + uint32_t sfr : 1; + uint32_t reserved_31_20 : 12; +#else + uint32_t reserved_31_20 : 12; + uint32_t sfr : 1; + uint32_t sfc : 1; + uint32_t sfb : 1; + uint32_t sfa : 1; + uint32_t frfe : 1; + uint32_t frfb : 1; + uint32_t frne : 1; + uint32_t frnb : 1; + uint32_t fcfe : 1; + uint32_t fcfb : 1; + uint32_t fcne : 1; + uint32_t fcnb : 1; + uint32_t fbfe : 1; + uint32_t fbfb : 1; + uint32_t fbne : 1; + uint32_t fbnb : 1; + uint32_t fafe : 1; + uint32_t fafb : 1; + uint32_t fane : 1; + uint32_t fanb : 1; +#endif + } s; }; union ctu_can_fd_rx_mem_info { - uint32_t u32; - struct ctu_can_fd_rx_mem_info_s { + uint32_t u32; + struct ctu_can_fd_rx_mem_info_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* RX_MEM_INFO */ - uint32_t rx_buff_size : 13; - uint32_t reserved_15_13 : 3; - uint32_t rx_mem_free : 13; - uint32_t reserved_31_29 : 3; + uint32_t rx_buff_size : 13; + uint32_t reserved_15_13 : 3; + uint32_t rx_mem_free : 13; + uint32_t reserved_31_29 : 3; #else - uint32_t reserved_31_29 : 3; - uint32_t rx_mem_free : 13; - uint32_t reserved_15_13 : 3; - uint32_t rx_buff_size : 13; + uint32_t reserved_31_29 : 3; + uint32_t rx_mem_free : 13; + uint32_t reserved_15_13 : 3; + uint32_t rx_buff_size : 13; #endif - } s; + } s; }; union ctu_can_fd_rx_pointers { - uint32_t u32; - struct ctu_can_fd_rx_pointers_s { + uint32_t u32; + struct ctu_can_fd_rx_pointers_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* RX_POINTERS */ - uint32_t rx_wpp : 12; - uint32_t reserved_15_12 : 4; - uint32_t rx_rpp : 12; - uint32_t reserved_31_28 : 4; + uint32_t rx_wpp : 12; + uint32_t reserved_15_12 : 4; + uint32_t rx_rpp : 12; + uint32_t reserved_31_28 : 4; #else - uint32_t reserved_31_28 : 4; - uint32_t rx_rpp : 12; - uint32_t reserved_15_12 : 4; - uint32_t rx_wpp : 12; + uint32_t reserved_31_28 : 4; + uint32_t rx_rpp : 12; + uint32_t reserved_15_12 : 4; + uint32_t rx_wpp : 12; #endif - } s; + } s; }; union ctu_can_fd_rx_status_rx_settings { - uint32_t u32; - struct ctu_can_fd_rx_status_rx_settings_s { + uint32_t u32; + struct ctu_can_fd_rx_status_rx_settings_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* RX_STATUS */ - uint32_t rxe : 1; - uint32_t rxf : 1; - uint32_t reserved_3_2 : 2; - uint32_t rxfrc : 11; - uint32_t reserved_15 : 1; + uint32_t rxe : 1; + uint32_t rxf : 1; + uint32_t reserved_3_2 : 2; + uint32_t rxfrc : 11; + uint32_t reserved_15 : 1; /* RX_SETTINGS */ - uint32_t rtsop : 1; - uint32_t reserved_31_17 : 15; + uint32_t rtsop : 1; + uint32_t reserved_31_17 : 15; #else - uint32_t reserved_31_17 : 15; - uint32_t rtsop : 1; - uint32_t reserved_15 : 1; - uint32_t rxfrc : 11; - uint32_t reserved_3_2 : 2; - uint32_t rxf : 1; - uint32_t rxe : 1; + uint32_t reserved_31_17 : 15; + uint32_t rtsop : 1; + uint32_t reserved_15 : 1; + uint32_t rxfrc : 11; + uint32_t reserved_3_2 : 2; + uint32_t rxf : 1; + uint32_t rxe : 1; #endif - } s; + } s; }; enum ctu_can_fd_rx_settings_rtsop { - RTS_END = 0x0, - RTS_BEG = 0x1, + RTS_END = 0x0, + RTS_BEG = 0x1, }; union ctu_can_fd_rx_data { - uint32_t u32; - struct ctu_can_fd_rx_data_s { + uint32_t u32; + struct ctu_can_fd_rx_data_s { /* RX_DATA */ - uint32_t rx_data : 32; - } s; + uint32_t rx_data : 32; + } s; }; union ctu_can_fd_tx_status { - uint32_t u32; - struct ctu_can_fd_tx_status_s { + uint32_t u32; + struct ctu_can_fd_tx_status_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* TX_STATUS */ - uint32_t tx1s : 4; - uint32_t tx2s : 4; - uint32_t tx3s : 4; - uint32_t tx4s : 4; - uint32_t reserved_31_16 : 16; + uint32_t tx1s : 4; + uint32_t tx2s : 4; + uint32_t tx3s : 4; + uint32_t tx4s : 4; + uint32_t reserved_31_16 : 16; #else - uint32_t reserved_31_16 : 16; - uint32_t tx4s : 4; - uint32_t tx3s : 4; - uint32_t tx2s : 4; - uint32_t tx1s : 4; + uint32_t reserved_31_16 : 16; + uint32_t tx4s : 4; + uint32_t tx3s : 4; + uint32_t tx2s : 4; + uint32_t tx1s : 4; #endif - } s; + } s; }; enum ctu_can_fd_tx_status_tx1s { - TXT_RDY = 0x1, - TXT_TRAN = 0x2, - TXT_ABTP = 0x3, - TXT_TOK = 0x4, - TXT_ERR = 0x6, - TXT_ABT = 0x7, - TXT_ETY = 0x8, + TXT_RDY = 0x1, + TXT_TRAN = 0x2, + TXT_ABTP = 0x3, + TXT_TOK = 0x4, + TXT_ERR = 0x6, + TXT_ABT = 0x7, + TXT_ETY = 0x8, }; union ctu_can_fd_tx_command { - uint32_t u32; - struct ctu_can_fd_tx_command_s { + uint32_t u32; + struct ctu_can_fd_tx_command_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* TX_COMMAND */ - uint32_t txce : 1; - uint32_t txcr : 1; - uint32_t txca : 1; - uint32_t reserved_7_3 : 5; - uint32_t txb1 : 1; - uint32_t txb2 : 1; - uint32_t txb3 : 1; - uint32_t txb4 : 1; - uint32_t reserved_31_12 : 20; -#else - uint32_t reserved_31_12 : 20; - uint32_t txb4 : 1; - uint32_t txb3 : 1; - uint32_t txb2 : 1; - uint32_t txb1 : 1; - uint32_t reserved_7_3 : 5; - uint32_t txca : 1; - uint32_t txcr : 1; - uint32_t txce : 1; -#endif - } s; + uint32_t txce : 1; + uint32_t txcr : 1; + uint32_t txca : 1; + uint32_t reserved_7_3 : 5; + uint32_t txb1 : 1; + uint32_t txb2 : 1; + uint32_t txb3 : 1; + uint32_t txb4 : 1; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t txb4 : 1; + uint32_t txb3 : 1; + uint32_t txb2 : 1; + uint32_t txb1 : 1; + uint32_t reserved_7_3 : 5; + uint32_t txca : 1; + uint32_t txcr : 1; + uint32_t txce : 1; +#endif + } s; }; union ctu_can_fd_tx_priority { - uint32_t u32; - struct ctu_can_fd_tx_priority_s { + uint32_t u32; + struct ctu_can_fd_tx_priority_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* TX_PRIORITY */ - uint32_t txt1p : 3; - uint32_t reserved_3 : 1; - uint32_t txt2p : 3; - uint32_t reserved_7 : 1; - uint32_t txt3p : 3; - uint32_t reserved_11 : 1; - uint32_t txt4p : 3; - uint32_t reserved_31_15 : 17; -#else - uint32_t reserved_31_15 : 17; - uint32_t txt4p : 3; - uint32_t reserved_11 : 1; - uint32_t txt3p : 3; - uint32_t reserved_7 : 1; - uint32_t txt2p : 3; - uint32_t reserved_3 : 1; - uint32_t txt1p : 3; -#endif - } s; + uint32_t txt1p : 3; + uint32_t reserved_3 : 1; + uint32_t txt2p : 3; + uint32_t reserved_7 : 1; + uint32_t txt3p : 3; + uint32_t reserved_11 : 1; + uint32_t txt4p : 3; + uint32_t reserved_31_15 : 17; +#else + uint32_t reserved_31_15 : 17; + uint32_t txt4p : 3; + uint32_t reserved_11 : 1; + uint32_t txt3p : 3; + uint32_t reserved_7 : 1; + uint32_t txt2p : 3; + uint32_t reserved_3 : 1; + uint32_t txt1p : 3; +#endif + } s; }; union ctu_can_fd_err_capt_alc { - uint32_t u32; - struct ctu_can_fd_err_capt_alc_s { + uint32_t u32; + struct ctu_can_fd_err_capt_alc_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* ERR_CAPT */ - uint32_t err_pos : 5; - uint32_t err_type : 3; - uint32_t reserved_15_8 : 8; + uint32_t err_pos : 5; + uint32_t err_type : 3; + uint32_t reserved_15_8 : 8; /* ALC */ - uint32_t alc_bit : 5; - uint32_t alc_id_field : 3; - uint32_t reserved_31_24 : 8; + uint32_t alc_bit : 5; + uint32_t alc_id_field : 3; + uint32_t reserved_31_24 : 8; #else - uint32_t reserved_31_24 : 8; - uint32_t alc_id_field : 3; - uint32_t alc_bit : 5; - uint32_t reserved_15_8 : 8; - uint32_t err_type : 3; - uint32_t err_pos : 5; + uint32_t reserved_31_24 : 8; + uint32_t alc_id_field : 3; + uint32_t alc_bit : 5; + uint32_t reserved_15_8 : 8; + uint32_t err_type : 3; + uint32_t err_pos : 5; #endif - } s; + } s; }; enum ctu_can_fd_err_capt_err_pos { - ERC_POS_SOF = 0x0, - ERC_POS_ARB = 0x1, - ERC_POS_CTRL = 0x2, - ERC_POS_DATA = 0x3, - ERC_POS_CRC = 0x4, - ERC_POS_ACK = 0x5, - ERC_POS_EOF = 0x6, - ERC_POS_ERR = 0x7, - ERC_POS_OVRL = 0x8, - ERC_POS_OTHER = 0x1f, + ERC_POS_SOF = 0x0, + ERC_POS_ARB = 0x1, + ERC_POS_CTRL = 0x2, + ERC_POS_DATA = 0x3, + ERC_POS_CRC = 0x4, + ERC_POS_ACK = 0x5, + ERC_POS_EOF = 0x6, + ERC_POS_ERR = 0x7, + ERC_POS_OVRL = 0x8, + ERC_POS_OTHER = 0x1f, }; enum ctu_can_fd_err_capt_err_type { - ERC_BIT_ERR = 0x0, - ERC_CRC_ERR = 0x1, - ERC_FRM_ERR = 0x2, - ERC_ACK_ERR = 0x3, - ERC_STUF_ERR = 0x4, + ERC_BIT_ERR = 0x0, + ERC_CRC_ERR = 0x1, + ERC_FRM_ERR = 0x2, + ERC_ACK_ERR = 0x3, + ERC_STUF_ERR = 0x4, }; enum ctu_can_fd_alc_alc_id_field { - ALC_RSVD = 0x0, - ALC_BASE_ID = 0x1, - ALC_SRR_RTR = 0x2, - ALC_IDE = 0x3, - ALC_EXTENSION = 0x4, - ALC_RTR = 0x5, + ALC_RSVD = 0x0, + ALC_BASE_ID = 0x1, + ALC_SRR_RTR = 0x2, + ALC_IDE = 0x3, + ALC_EXTENSION = 0x4, + ALC_RTR = 0x5, }; union ctu_can_fd_trv_delay_ssp_cfg { - uint32_t u32; - struct ctu_can_fd_trv_delay_ssp_cfg_s { + uint32_t u32; + struct ctu_can_fd_trv_delay_ssp_cfg_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* TRV_DELAY */ - uint32_t trv_delay_value : 7; - uint32_t reserved_15_7 : 9; + uint32_t trv_delay_value : 7; + uint32_t reserved_15_7 : 9; /* SSP_CFG */ - uint32_t ssp_offset : 8; - uint32_t ssp_src : 2; - uint32_t reserved_31_26 : 6; + uint32_t ssp_offset : 8; + uint32_t ssp_src : 2; + uint32_t reserved_31_26 : 6; #else - uint32_t reserved_31_26 : 6; - uint32_t ssp_src : 2; - uint32_t ssp_offset : 8; - uint32_t reserved_15_7 : 9; - uint32_t trv_delay_value : 7; + uint32_t reserved_31_26 : 6; + uint32_t ssp_src : 2; + uint32_t ssp_offset : 8; + uint32_t reserved_15_7 : 9; + uint32_t trv_delay_value : 7; #endif - } s; + } s; }; enum ctu_can_fd_ssp_cfg_ssp_src { - SSP_SRC_MEAS_N_OFFSET = 0x0, - SSP_SRC_NO_SSP = 0x1, - SSP_SRC_OFFSET = 0x2, + SSP_SRC_MEAS_N_OFFSET = 0x0, + SSP_SRC_NO_SSP = 0x1, + SSP_SRC_OFFSET = 0x2, }; union ctu_can_fd_rx_fr_ctr { - uint32_t u32; - struct ctu_can_fd_rx_fr_ctr_s { + uint32_t u32; + struct ctu_can_fd_rx_fr_ctr_s { /* RX_FR_CTR */ - uint32_t rx_fr_ctr_val : 32; - } s; + uint32_t rx_fr_ctr_val : 32; + } s; }; union ctu_can_fd_tx_fr_ctr { - uint32_t u32; - struct ctu_can_fd_tx_fr_ctr_s { + uint32_t u32; + struct ctu_can_fd_tx_fr_ctr_s { /* TX_FR_CTR */ - uint32_t tx_fr_ctr_val : 32; - } s; + uint32_t tx_fr_ctr_val : 32; + } s; }; union ctu_can_fd_debug_register { - uint32_t u32; - struct ctu_can_fd_debug_register_s { + uint32_t u32; + struct ctu_can_fd_debug_register_s { #ifdef __LITTLE_ENDIAN_BITFIELD /* DEBUG_REGISTER */ - uint32_t stuff_count : 3; - uint32_t destuff_count : 3; - uint32_t pc_arb : 1; - uint32_t pc_con : 1; - uint32_t pc_dat : 1; - uint32_t pc_stc : 1; - uint32_t pc_crc : 1; - uint32_t pc_crcd : 1; - uint32_t pc_ack : 1; - uint32_t pc_ackd : 1; - uint32_t pc_eof : 1; - uint32_t pc_int : 1; - uint32_t pc_susp : 1; - uint32_t pc_ovr : 1; - uint32_t pc_sof : 1; - uint32_t reserved_31_19 : 13; -#else - uint32_t reserved_31_19 : 13; - uint32_t pc_sof : 1; - uint32_t pc_ovr : 1; - uint32_t pc_susp : 1; - uint32_t pc_int : 1; - uint32_t pc_eof : 1; - uint32_t pc_ackd : 1; - uint32_t pc_ack : 1; - uint32_t pc_crcd : 1; - uint32_t pc_crc : 1; - uint32_t pc_stc : 1; - uint32_t pc_dat : 1; - uint32_t pc_con : 1; - uint32_t pc_arb : 1; - uint32_t destuff_count : 3; - uint32_t stuff_count : 3; -#endif - } s; + uint32_t stuff_count : 3; + uint32_t destuff_count : 3; + uint32_t pc_arb : 1; + uint32_t pc_con : 1; + uint32_t pc_dat : 1; + uint32_t pc_stc : 1; + uint32_t pc_crc : 1; + uint32_t pc_crcd : 1; + uint32_t pc_ack : 1; + uint32_t pc_ackd : 1; + uint32_t pc_eof : 1; + uint32_t pc_int : 1; + uint32_t pc_susp : 1; + uint32_t pc_ovr : 1; + uint32_t pc_sof : 1; + uint32_t reserved_31_19 : 13; +#else + uint32_t reserved_31_19 : 13; + uint32_t pc_sof : 1; + uint32_t pc_ovr : 1; + uint32_t pc_susp : 1; + uint32_t pc_int : 1; + uint32_t pc_eof : 1; + uint32_t pc_ackd : 1; + uint32_t pc_ack : 1; + uint32_t pc_crcd : 1; + uint32_t pc_crc : 1; + uint32_t pc_stc : 1; + uint32_t pc_dat : 1; + uint32_t pc_con : 1; + uint32_t pc_arb : 1; + uint32_t destuff_count : 3; + uint32_t stuff_count : 3; +#endif + } s; }; union ctu_can_fd_yolo_reg { - uint32_t u32; - struct ctu_can_fd_yolo_reg_s { + uint32_t u32; + struct ctu_can_fd_yolo_reg_s { /* YOLO_REG */ - uint32_t yolo_val : 32; - } s; + uint32_t yolo_val : 32; + } s; }; union ctu_can_fd_timestamp_low { - uint32_t u32; - struct ctu_can_fd_timestamp_low_s { + uint32_t u32; + struct ctu_can_fd_timestamp_low_s { /* TIMESTAMP_LOW */ - uint32_t timestamp_low : 32; - } s; + uint32_t timestamp_low : 32; + } s; }; union ctu_can_fd_timestamp_high { - uint32_t u32; - struct ctu_can_fd_timestamp_high_s { + uint32_t u32; + struct ctu_can_fd_timestamp_high_s { /* TIMESTAMP_HIGH */ - uint32_t timestamp_high : 32; - } s; + uint32_t timestamp_high : 32; + } s; }; #endif diff --git a/hw/net/can/ctucan_core.h b/hw/net/can/ctucan_core.h index bbc09ae06785..608307a6310c 100644 --- a/hw/net/can/ctucan_core.h +++ b/hw/net/can/ctucan_core.h @@ -31,7 +31,7 @@ #include "exec/hwaddr.h" #include "net/can_emu.h" -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN #define __LITTLE_ENDIAN_BITFIELD 1 #endif diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c index 50f4ea6cd63c..ea079e2af562 100644 --- a/hw/net/can/ctucan_pci.c +++ b/hw/net/can/ctucan_pci.c @@ -34,7 +34,7 @@ #include "qapi/error.h" #include "chardev/char.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/can_emu.h" diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index 22bb8910fa8c..e93e6c5e1946 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); @@ -1079,7 +1079,7 @@ static void xlnx_zynqmp_can_realize(DeviceState *dev, Error **errp) /* Allocate a new timer. */ s->can_timer = ptimer_init(xlnx_zynqmp_can_ptimer_cb, s, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->can_timer); diff --git a/hw/net/e1000.c b/hw/net/e1000.c index f5bc81296d1a..7efb8a4c5225 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/eth.h" @@ -979,7 +979,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH]; pci_dma_read(d, base, &desc, sizeof(desc)); desc.special = vlan_special; - desc.status |= (vlan_status | E1000_RXD_STAT_DD); + desc.status &= ~E1000_RXD_STAT_DD; if (desc.buffer_addr) { if (desc_offset < size) { size_t iov_copy; @@ -1013,6 +1013,9 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) DBGOUT(RX, "Null RX descriptor!!\n"); } pci_dma_write(d, base, &desc, sizeof(desc)); + desc.status |= (vlan_status | E1000_RXD_STAT_DD); + pci_dma_write(d, base + offsetof(struct e1000_rx_desc, status), + &desc.status, sizeof(desc.status)); if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) s->mac_reg[RDH] = 0; diff --git a/hw/net/e1000_regs.h b/hw/net/e1000_regs.h index ae99f58bab28..59e050742b58 100644 --- a/hw/net/e1000_regs.h +++ b/hw/net/e1000_regs.h @@ -552,21 +552,21 @@ #define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ /* PHY Status Register */ -#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ /* PHY Link Partner Ability Register */ #define MII_LPAR_LPACK 0x4000 /* Acked by link partner */ @@ -793,6 +793,7 @@ #define E1000_CTRL_EXT_ASDCHK 0x00001000 /* auto speed detection check */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* EEPROM reset */ #define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_EIAME 0x01000000 #define E1000_CTRL_EXT_IAME 0x08000000 /* Int ACK Auto-mask */ #define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index ac96f7665afc..7523e9f5d223 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -276,25 +276,18 @@ e1000e_unuse_msix_vectors(E1000EState *s, int num_vectors) } } -static bool +static void e1000e_use_msix_vectors(E1000EState *s, int num_vectors) { int i; for (i = 0; i < num_vectors; i++) { - int res = msix_vector_use(PCI_DEVICE(s), i); - if (res < 0) { - trace_e1000e_msix_use_vector_fail(i, res); - e1000e_unuse_msix_vectors(s, i); - return false; - } + msix_vector_use(PCI_DEVICE(s), i); } - return true; } static void e1000e_init_msix(E1000EState *s) { - PCIDevice *d = PCI_DEVICE(s); int res = msix_init(PCI_DEVICE(s), E1000E_MSIX_VEC_NUM, &s->msix, E1000E_MSIX_IDX, E1000E_MSIX_TABLE, @@ -305,9 +298,7 @@ e1000e_init_msix(E1000EState *s) if (res < 0) { trace_e1000e_msix_init_fail(res); } else { - if (!e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM)) { - msix_uninit(d, &s->msix, &s->msix); - } + e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM); } } diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 2c51089a8251..fc9cdb4528d9 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -159,6 +159,8 @@ e1000e_intrmgr_on_throttling_timer(void *opaque) if (msi_enabled(timer->core->owner)) { trace_e1000e_irq_msi_notify_postponed(); + /* Clear msi_causes_pending to fire MSI eventually */ + timer->core->msi_causes_pending = 0; e1000e_set_interrupt_cause(timer->core, 0); } else { trace_e1000e_irq_legacy_notify_postponed(); @@ -1362,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; @@ -1598,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); @@ -1620,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/e1000x_common.c b/hw/net/e1000x_common.c index a8d93870b5a0..2f43e8cd131f 100644 --- a/hw/net/e1000x_common.c +++ b/hw/net/e1000x_common.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "net/net.h" #include "e1000x_common.h" diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 679f52f80f10..dc07984ae9a8 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -42,7 +42,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/net.h" diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index e7fc082518d2..b75d8e3dce9a 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -27,7 +27,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/sysbus.h" #include "hw/irq.h" #include "hw/ptimer.h" @@ -394,7 +393,7 @@ static void etsec_realize(DeviceState *dev, Error **errp) object_get_typename(OBJECT(dev)), dev->id, etsec); qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a); - etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT); + etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(etsec->ptimer); ptimer_set_freq(etsec->ptimer, 100); ptimer_transaction_commit(etsec->ptimer); @@ -444,26 +443,3 @@ static void etsec_register_types(void) } type_init(etsec_register_types) - -DeviceState *etsec_create(hwaddr base, - MemoryRegion * mr, - NICInfo * nd, - qemu_irq tx_irq, - qemu_irq rx_irq, - qemu_irq err_irq) -{ - DeviceState *dev; - - dev = qdev_new("eTSEC"); - qdev_set_nic_properties(dev, nd); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq); - - memory_region_add_subregion(mr, base, - SYS_BUS_DEVICE(dev)->mmio[0].memory); - - return dev; -} diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h index fddf551544aa..3c625c955cf8 100644 --- a/hw/net/fsl_etsec/etsec.h +++ b/hw/net/fsl_etsec/etsec.h @@ -155,13 +155,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(eTSEC, ETSEC_COMMON) #define eTSEC_TRANSMIT 1 #define eTSEC_RECEIVE 2 -DeviceState *etsec_create(hwaddr base, - MemoryRegion *mr, - NICInfo *nd, - qemu_irq tx_irq, - qemu_irq rx_irq, - qemu_irq err_irq); - void etsec_update_irq(eTSEC *etsec); void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr); diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 8f084464155d..a32589e33be4 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "net/checksum.h" #include "qemu/log.h" #include "etsec.h" diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 0db9aaf76a01..c862d9659303 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -438,7 +438,7 @@ static void imx_eth_update(IMXFECState *s) * assignment fail. * * To ensure that all versions of Linux work, generate ENET_INT_MAC - * interrrupts on both interrupt lines. This should be changed if and when + * interrupts on both interrupt lines. This should be changed if and when * qemu supports IOMUX. */ if (s->regs[ENET_EIR] & s->regs[ENET_EIMR] & @@ -1068,9 +1068,9 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, return 0; } - /* 4 bytes for the CRC. */ - size += 4; crc = cpu_to_be32(crc32(~0, buf, size)); + /* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */ + size += 4; crc_ptr = (uint8_t *) &crc; /* Huge frames are truncated. */ @@ -1164,9 +1164,9 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, return 0; } - /* 4 bytes for the CRC. */ - size += 4; crc = cpu_to_be32(crc32(~0, buf, size)); + /* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */ + size += 4; crc_ptr = (uint8_t *) &crc; if (shift16) { diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 6aff424cbe54..f1cba5596724 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. */ @@ -1363,7 +1371,7 @@ static void lan9118_realize(DeviceState *dev, Error **errp) s->pmt_ctrl = 1; s->txp = &s->tx_packet; - s->timer = ptimer_init(lan9118_tick, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(lan9118_tick, s, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->timer); ptimer_set_freq(s->timer, 10000); ptimer_set_limit(s->timer, 0xffff, 1); diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 25e3e453ab12..8aa27bd322d7 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -313,10 +313,10 @@ static void mcf_fec_reset(DeviceState *dev) s->rfsr = 0x500; } -#define MMFR_WRITE_OP (1 << 28) -#define MMFR_READ_OP (2 << 28) -#define MMFR_PHYADDR(v) (((v) >> 23) & 0x1f) -#define MMFR_REGNUM(v) (((v) >> 18) & 0x1f) +#define MMFR_WRITE_OP (1 << 28) +#define MMFR_READ_OP (2 << 28) +#define MMFR_PHYADDR(v) (((v) >> 23) & 0x1f) +#define MMFR_REGNUM(v) (((v) >> 18) & 0x1f) static uint64_t mcf_fec_read_mdio(mcf_fec_state *s) { diff --git a/hw/net/meson.build b/hw/net/meson.build index 685b75badb40..ebac26154261 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -46,8 +46,12 @@ specific_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c' softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('net_rx_pkt.c')) specific_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('virtio-net.c')) -softmmu_ss.add(when: ['CONFIG_VIRTIO_NET', 'CONFIG_VHOST_NET'], if_true: files('vhost_net.c'), if_false: files('vhost_net-stub.c')) -softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost_net-stub.c')) +if have_vhost_net + softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost_net.c'), if_false: files('vhost_net-stub.c')) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost_net-stub.c')) +else + softmmu_ss.add(files('vhost_net-stub.c')) +endif softmmu_ss.add(when: 'CONFIG_ETSEC', if_true: files( 'fsl_etsec/etsec.c', diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c index 9278fdce0b3d..7ccd3e514271 100644 --- a/hw/net/msf2-emac.c +++ b/hw/net/msf2-emac.c @@ -29,7 +29,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/log.h" #include "qapi/error.h" #include "hw/registerfields.h" diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c index 9e5d10859aca..edc6689d33ea 100644 --- a/hw/net/ne2000-pci.c +++ b/hw/net/ne2000-pci.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "ne2000.h" diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 6c17ee1ae211..3f31d04efba0 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -36,89 +36,89 @@ #define MAX_ETH_FRAME_SIZE 1514 -#define E8390_CMD 0x00 /* The command register (for all pages) */ +#define E8390_CMD 0x00 /* The command register (for all pages) */ /* Page 0 register offsets. */ -#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ -#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ -#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ -#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ -#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ -#define EN0_TSR 0x04 /* Transmit status reg RD */ -#define EN0_TPSR 0x04 /* Transmit starting page WR */ -#define EN0_NCR 0x05 /* Number of collision reg RD */ -#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ -#define EN0_FIFO 0x06 /* FIFO RD */ -#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ -#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ -#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ -#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ -#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ -#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ -#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ -#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */ -#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ -#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */ -#define EN0_RSR 0x0c /* rx status reg RD */ -#define EN0_RXCR 0x0c /* RX configuration reg WR */ -#define EN0_TXCR 0x0d /* TX configuration reg WR */ -#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ -#define EN0_DCFG 0x0e /* Data configuration reg WR */ -#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ -#define EN0_IMR 0x0f /* Interrupt mask reg WR */ -#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ +#define EN0_TSR 0x04 /* Transmit status reg RD */ +#define EN0_TPSR 0x04 /* Transmit starting page WR */ +#define EN0_NCR 0x05 /* Number of collision reg RD */ +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ +#define EN0_FIFO 0x06 /* FIFO RD */ +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ +#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */ +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ +#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */ +#define EN0_RSR 0x0c /* rx status reg RD */ +#define EN0_RXCR 0x0c /* RX configuration reg WR */ +#define EN0_TXCR 0x0d /* TX configuration reg WR */ +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ +#define EN0_DCFG 0x0e /* Data configuration reg WR */ +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ +#define EN0_IMR 0x0f /* Interrupt mask reg WR */ +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ #define EN1_PHYS 0x11 #define EN1_CURPAG 0x17 #define EN1_MULT 0x18 -#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */ -#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */ +#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */ +#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */ -#define EN3_CONFIG0 0x33 -#define EN3_CONFIG1 0x34 -#define EN3_CONFIG2 0x35 -#define EN3_CONFIG3 0x36 +#define EN3_CONFIG0 0x33 +#define EN3_CONFIG1 0x34 +#define EN3_CONFIG2 0x35 +#define EN3_CONFIG3 0x36 /* Register accessed at EN_CMD, the 8390 base addr. */ -#define E8390_STOP 0x01 /* Stop and reset the chip */ -#define E8390_START 0x02 /* Start the chip, clear reset */ -#define E8390_TRANS 0x04 /* Transmit a frame */ -#define E8390_RREAD 0x08 /* Remote read */ -#define E8390_RWRITE 0x10 /* Remote write */ -#define E8390_NODMA 0x20 /* Remote DMA */ -#define E8390_PAGE0 0x00 /* Select page chip registers */ -#define E8390_PAGE1 0x40 /* using the two high-order bits */ -#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ +#define E8390_STOP 0x01 /* Stop and reset the chip */ +#define E8390_START 0x02 /* Start the chip, clear reset */ +#define E8390_TRANS 0x04 /* Transmit a frame */ +#define E8390_RREAD 0x08 /* Remote read */ +#define E8390_RWRITE 0x10 /* Remote write */ +#define E8390_NODMA 0x20 /* Remote DMA */ +#define E8390_PAGE0 0x00 /* Select page chip registers */ +#define E8390_PAGE1 0x40 /* using the two high-order bits */ +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ /* Bits in EN0_ISR - Interrupt status register */ -#define ENISR_RX 0x01 /* Receiver, no error */ -#define ENISR_TX 0x02 /* Transmitter, no error */ -#define ENISR_RX_ERR 0x04 /* Receiver, with error */ -#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ -#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ -#define ENISR_COUNTERS 0x20 /* Counters need emptying */ -#define ENISR_RDC 0x40 /* remote dma complete */ -#define ENISR_RESET 0x80 /* Reset completed */ -#define ENISR_ALL 0x3f /* Interrupts we will enable */ +#define ENISR_RX 0x01 /* Receiver, no error */ +#define ENISR_TX 0x02 /* Transmitter, no error */ +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ +#define ENISR_RDC 0x40 /* remote dma complete */ +#define ENISR_RESET 0x80 /* Reset completed */ +#define ENISR_ALL 0x3f /* Interrupts we will enable */ /* Bits in received packet status byte and EN0_RSR*/ -#define ENRSR_RXOK 0x01 /* Received a good packet */ -#define ENRSR_CRC 0x02 /* CRC error */ -#define ENRSR_FAE 0x04 /* frame alignment error */ -#define ENRSR_FO 0x08 /* FIFO overrun */ -#define ENRSR_MPA 0x10 /* missed pkt */ -#define ENRSR_PHY 0x20 /* physical/multicast address */ -#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ -#define ENRSR_DEF 0x80 /* deferring */ +#define ENRSR_RXOK 0x01 /* Received a good packet */ +#define ENRSR_CRC 0x02 /* CRC error */ +#define ENRSR_FAE 0x04 /* frame alignment error */ +#define ENRSR_FO 0x08 /* FIFO overrun */ +#define ENRSR_MPA 0x10 /* missed pkt */ +#define ENRSR_PHY 0x20 /* physical/multicast address */ +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ +#define ENRSR_DEF 0x80 /* deferring */ /* Transmitted packet status, EN0_TSR. */ -#define ENTSR_PTX 0x01 /* Packet transmitted without error */ -#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ -#define ENTSR_COL 0x04 /* The transmit collided at least once. */ +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ #define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ -#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ #define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ -#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ #define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ void ne2000_reset(NE2000State *s) @@ -425,13 +425,13 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) ret = 0x43; break; case EN3_CONFIG0: - ret = 0; /* 10baseT media */ + ret = 0; /* 10baseT media */ break; case EN3_CONFIG2: - ret = 0x40; /* 10baseT active */ + ret = 0x40; /* 10baseT active */ break; case EN3_CONFIG3: - ret = 0x40; /* Full duplex */ + ret = 0x40; /* Full duplex */ break; default: ret = 0x00; diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 1cb1125d9fe1..2533ea27007c 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -21,7 +21,7 @@ #include "net/checksum.h" #include "net/tap.h" #include "net/net.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" enum { NET_TX_PKT_VHDR_FRAG = 0, diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c index 9a2328935c1c..7c86bb52e571 100644 --- a/hw/net/npcm7xx_emc.c +++ b/hw/net/npcm7xx_emc.c @@ -32,7 +32,6 @@ /* For crc32 */ #include -#include "qemu-common.h" #include "hw/irq.h" #include "hw/qdev-clock.h" #include "hw/qdev-properties.h" diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 95d27102aa44..96a302c141ab 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -29,7 +29,7 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "net/net.h" diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index dcd3fc49481b..e63e5249137e 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -370,7 +370,7 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, uint32_t rbadr; int16_t buf_length; int16_t msg_length; - } rda; + } rda; s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff; rmd->buf_length = le16_to_cpu(rda.buf_length); @@ -524,77 +524,77 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, be16_to_cpu(hdr->ether_type)); \ } while (0) -#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) /* generated using the AUTODIN II polynomial - * x^32 + x^26 + x^23 + x^22 + x^16 + - * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 + * x^32 + x^26 + x^23 + x^22 + x^16 + + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 */ static const uint32_t crctab[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h index f49b213c57fc..eb7f46aab353 100644 --- a/hw/net/pcnet.h +++ b/hw/net/pcnet.h @@ -4,8 +4,8 @@ #define PCNET_IOPORT_SIZE 0x20 #define PCNET_PNPMMIO_SIZE 0x20 -#define PCNET_LOOPTEST_CRC 1 -#define PCNET_LOOPTEST_NOCRC 2 +#define PCNET_LOOPTEST_CRC 1 +#define PCNET_LOOPTEST_NOCRC 2 #include "exec/memory.h" #include "hw/irq.h" diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 31f2340fb910..cf54ddf49dc9 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -16,7 +16,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "migration/vmstate.h" @@ -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; @@ -1212,24 +1212,14 @@ static void rocker_msix_vectors_unuse(Rocker *r, } } -static int rocker_msix_vectors_use(Rocker *r, - unsigned int num_vectors) +static void rocker_msix_vectors_use(Rocker *r, unsigned int num_vectors) { PCIDevice *dev = PCI_DEVICE(r); - int err; int i; for (i = 0; i < num_vectors; i++) { - err = msix_vector_use(dev, i); - if (err) { - goto rollback; - } + msix_vector_use(dev, i); } - return 0; - -rollback: - rocker_msix_vectors_unuse(r, i); - return err; } static int rocker_msix_init(Rocker *r, Error **errp) @@ -1247,16 +1237,9 @@ static int rocker_msix_init(Rocker *r, Error **errp) return err; } - err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); - if (err) { - goto err_msix_vectors_use; - } + rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); return 0; - -err_msix_vectors_use: - msix_uninit(dev, &r->msix_bar, &r->msix_bar); - return err; } static void rocker_msix_uninit(Rocker *r) diff --git a/hw/net/rocker/rocker_desc.c b/hw/net/rocker/rocker_desc.c index 01845f115757..f3068c925049 100644 --- a/hw/net/rocker/rocker_desc.c +++ b/hw/net/rocker/rocker_desc.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "net/net.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "rocker.h" #include "rocker_hw.h" diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index b3b8c5bb6d4b..dfe475446942 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -2348,23 +2348,19 @@ static void of_dpa_flow_fill(void *cookie, void *value, void *user_data) if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) || memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) { - nkey->has_eth_src = true; nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a); } - if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { - nmask->has_eth_src = true; + if (nkey->eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a); } if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) || memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) { - nkey->has_eth_dst = true; nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a); } - if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { - nmask->has_eth_dst = true; + if (nkey->eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a); } @@ -2400,7 +2396,6 @@ static void of_dpa_flow_fill(void *cookie, void *value, void *user_data) if (key->ipv4.addr.dst || mask->ipv4.addr.dst) { char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst); int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst); - nkey->has_ip_dst = true; nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len); } break; @@ -2501,12 +2496,10 @@ static void of_dpa_group_fill(void *key, void *value, void *user_data) ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id); } if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_src = true; ngroup->set_eth_src = qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a); } if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_dst = true; ngroup->set_eth_dst = qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a); } @@ -2532,12 +2525,10 @@ static void of_dpa_group_fill(void *key, void *value, void *user_data) ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id); } if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_src = true; ngroup->set_eth_src = qemu_mac_strdup_printf(group->l3_unicast.src_mac.a); } if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_dst = true; ngroup->set_eth_dst = qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a); } diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 6b65823b4bf8..5a5aaf868d22 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -53,7 +53,7 @@ #include "qemu/osdep.h" #include -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "sysemu/dma.h" @@ -77,7 +77,6 @@ ( ( input ) & ( size - 1 ) ) #define ETHER_TYPE_LEN 2 -#define ETH_MTU 1500 #define VLAN_TCI_LEN 2 #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN) @@ -1934,8 +1933,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) #define CP_TX_LS (1<<28) /* large send packet flag */ #define CP_TX_LGSEN (1<<27) -/* large send MSS mask, bits 16...25 */ -#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) +/* large send MSS mask, bits 16...26 */ +#define CP_TC_LGSEN_MSS_SHIFT 16 +#define CP_TC_LGSEN_MSS_MASK ((1 << 11) - 1) /* IP checksum offload flag */ #define CP_TX_IPCS (1<<18) @@ -2027,18 +2027,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) s->currCPlusTxDesc = 0; } + /* Build the Tx Status Descriptor */ + uint32_t tx_status = txdw0; + /* transfer ownership to target */ - txdw0 &= ~CP_TX_OWN; + tx_status &= ~CP_TX_OWN; /* reset error indicator bits */ - txdw0 &= ~CP_TX_STATUS_UNF; - txdw0 &= ~CP_TX_STATUS_TES; - txdw0 &= ~CP_TX_STATUS_OWC; - txdw0 &= ~CP_TX_STATUS_LNKF; - txdw0 &= ~CP_TX_STATUS_EXC; + tx_status &= ~CP_TX_STATUS_UNF; + tx_status &= ~CP_TX_STATUS_TES; + tx_status &= ~CP_TX_STATUS_OWC; + tx_status &= ~CP_TX_STATUS_LNKF; + tx_status &= ~CP_TX_STATUS_EXC; /* update ring data */ - val = cpu_to_le32(txdw0); + val = cpu_to_le32(tx_status); pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4); /* Now decide if descriptor being processed is holding the last segment of packet */ @@ -2132,7 +2135,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) } ip_data_len -= hlen; - if (txdw0 & CP_TX_IPCS) + if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & CP_TX_IPCS)) { DPRINTF("+++ C+ mode need IP checksum\n"); @@ -2149,14 +2152,14 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) goto skip_offload; } - int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) & + CP_TC_LGSEN_MSS_MASK; - DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " - "frame data %d specified MSS=%d\n", ETH_MTU, + DPRINTF("+++ C+ mode offloaded task TSO IP data %d " + "frame data %d specified MSS=%d\n", ip_data_len, saved_size - ETH_HLEN, large_send_mss); int tcp_send_offset = 0; - int send_count = 0; /* maximum IP header length is 60 bytes */ uint8_t saved_ip_header[60]; @@ -2178,25 +2181,22 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) goto skip_offload; } - /* ETH_MTU = ip header len + tcp header len + payload */ int tcp_data_len = ip_data_len - tcp_hlen; - int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " - "data len %d TCP chunk size %d\n", ip_data_len, - tcp_hlen, tcp_data_len, tcp_chunk_size); + "data len %d\n", ip_data_len, tcp_hlen, tcp_data_len); /* note the cycle below overwrites IP header data, but restores it from saved_ip_header before sending packet */ int is_last_frame = 0; - for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += large_send_mss) { - uint16_t chunk_size = tcp_chunk_size; + uint16_t chunk_size = large_send_mss; /* check if this is the last frame */ - if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + if (tcp_send_offset + large_send_mss >= tcp_data_len) { is_last_frame = 1; chunk_size = tcp_data_len - tcp_send_offset; @@ -2245,7 +2245,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); /* increment IP id for subsequent frames */ - ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + ip->ip_id = cpu_to_be16(tcp_send_offset/large_send_mss + be16_to_cpu(ip->ip_id)); ip->ip_sum = 0; ip->ip_sum = ip_checksum(eth_payload_data, hlen); @@ -2261,13 +2261,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* add transferred count to TCP sequence number */ stl_be_p(&p_tcp_hdr->th_seq, chunk_size + ldl_be_p(&p_tcp_hdr->th_seq)); - ++send_count; } /* Stop sending this frame */ saved_size = 0; } - else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + else if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))) { DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); diff --git a/hw/net/sungem.c b/hw/net/sungem.c index 3684a4d733b6..eb0152079044 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/log.h" diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index fc34905f8759..1f3d8011aed2 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/net/mii.h" diff --git a/hw/net/tulip.c b/hw/net/tulip.c index d5b6cc5ee692..915e5fb59541 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "hw/nvram/eeprom93xx.h" #include "migration/vmstate.h" @@ -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); @@ -870,11 +870,10 @@ static const MemoryRegionOps tulip_ops = { static void tulip_idblock_crc(TULIPState *s, uint16_t *srom) { - int word, n; + int word; int bit; unsigned char bitval, crc; const int len = 9; - n = 0; crc = -1; for (word = 0; word < len; word++) { @@ -887,7 +886,6 @@ static void tulip_idblock_crc(TULIPState *s, uint16_t *srom) srom[len - 1] = (srom[len - 1] & 0xff00) | (unsigned short)crc; break; } - n++; bitval = ((srom[word] >> bit) & 1) ^ ((crc >> 7) & 1); crc = crc << 1; if (bitval == 1) { @@ -967,6 +965,8 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) pci_conf = s->dev.config; pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ + qemu_macaddr_default_if_unset(&s->c.macaddr); + s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64); tulip_fill_eeprom(s); @@ -981,8 +981,6 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) s->irq = pci_allocate_irq(&s->dev); - qemu_macaddr_default_if_unset(&s->c.macaddr); - s->nic = qemu_new_nic(&net_tulip_info, &s->c, object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c index 89d71cfb8e13..72df6d757e4d 100644 --- a/hw/net/vhost_net-stub.c +++ b/hw/net/vhost_net-stub.c @@ -82,6 +82,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, { } +bool vhost_net_config_pending(VHostNetState *net) +{ + return false; +} + +void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) +{ +} + int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) { return -1; @@ -101,3 +110,20 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) { return 0; } + +void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc, + int vq_index) +{ + +} + +int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc, + int vq_index) +{ + return 0; +} + +void vhost_net_save_acked_features(NetClientState *nc) +{ + +} diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 30379d2ca410..c4eecc6f3662 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -34,6 +34,7 @@ #include "standard-headers/linux/virtio_ring.h" #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-bus.h" +#include "linux-headers/linux/vhost.h" /* Features supported by host kernel. */ @@ -46,6 +47,7 @@ static const int kernel_feature_bits[] = { VIRTIO_NET_F_MTU, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_RING_PACKED, + VIRTIO_F_RING_RESET, VIRTIO_NET_F_HASH_REPORT, VHOST_INVALID_FEATURE_BIT }; @@ -73,6 +75,7 @@ static const int user_feature_bits[] = { VIRTIO_NET_F_MTU, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_RING_PACKED, + VIRTIO_F_RING_RESET, VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, @@ -141,6 +144,15 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net) return net->dev.acked_features; } +void vhost_net_save_acked_features(NetClientState *nc) +{ +#ifdef CONFIG_VHOST_NET_USER + if (nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { + vhost_user_save_acked_features(nc); + } +#endif +} + static int vhost_net_get_fd(NetClientState *backend) { switch (backend->info->type) { @@ -201,7 +213,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF); } if (~net->dev.features & net->dev.backend_features) { - fprintf(stderr, "vhost lacks feature mask %" PRIu64 + fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 " for backend\n", (uint64_t)(~net->dev.features & net->dev.backend_features)); goto fail; @@ -213,7 +225,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { features = vhost_user_get_acked_features(net->nc); if (~net->dev.features & features) { - fprintf(stderr, "vhost lacks feature mask %" PRIu64 + fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 " for backend\n", (uint64_t)(~net->dev.features & features)); goto fail; @@ -244,12 +256,19 @@ 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; } - r = vhost_dev_start(&net->dev, dev); + r = vhost_dev_start(&net->dev, dev, false); if (r < 0) { goto fail_start; } @@ -274,6 +293,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; @@ -291,7 +317,7 @@ static int vhost_net_start_one(struct vhost_net *net, if (net->nc->info->poll) { net->nc->info->poll(net->nc, true); } - vhost_dev_stop(&net->dev, dev); + vhost_dev_stop(&net->dev, dev, false); fail_start: vhost_dev_disable_notifiers(&net->dev, dev); fail_notifiers: @@ -312,7 +338,10 @@ static void vhost_net_stop_one(struct vhost_net *net, if (net->nc->info->poll) { net->nc->info->poll(net->nc, true); } - vhost_dev_stop(&net->dev, dev); + vhost_dev_stop(&net->dev, dev, false); + if (net->nc->info->stop) { + net->nc->info->stop(net->nc); + } vhost_dev_disable_notifiers(&net->dev, dev); } @@ -370,11 +399,6 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, } else { peer = qemu_get_peer(ncs, n->max_queue_pairs); } - r = vhost_net_start_one(get_vhost_net(peer), dev); - - if (r < 0) { - goto err_start; - } if (peer->vring_enable) { /* restore vring enable state */ @@ -384,13 +408,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, goto err_start; } } + + r = vhost_net_start_one(get_vhost_net(peer), dev); + if (r < 0) { + goto err_start; + } } return 0; err_start: while (--i >= 0) { - peer = qemu_get_peer(ncs , i); + peer = qemu_get_peer(ncs, i < data_queue_pairs ? + i : n->max_queue_pairs); vhost_net_stop_one(get_vhost_net(peer), dev); } e = k->set_guest_notifiers(qbus->parent, total_notifiers, false); @@ -457,6 +487,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, vhost_virtqueue_mask(&net->dev, dev, idx, mask); } +bool vhost_net_config_pending(VHostNetState *net) +{ + return vhost_config_pending(&net->dev); +} + +void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) +{ + vhost_config_mask(&net->dev, dev, mask); +} VHostNetState *get_vhost_net(NetClientState *nc) { VHostNetState *vhost_net = 0; @@ -512,3 +551,80 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); } + +void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc, + int vq_index) +{ + VHostNetState *net = get_vhost_net(nc->peer); + const VhostOps *vhost_ops = net->dev.vhost_ops; + struct vhost_vring_file file = { .fd = -1 }; + int idx; + + /* should only be called after backend is connected */ + assert(vhost_ops); + + idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index); + + if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + file.index = idx; + int r = vhost_net_set_backend(&net->dev, &file); + assert(r >= 0); + } + + vhost_virtqueue_stop(&net->dev, + vdev, + net->dev.vqs + idx, + net->dev.vq_index + idx); +} + +int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc, + int vq_index) +{ + VHostNetState *net = get_vhost_net(nc->peer); + const VhostOps *vhost_ops = net->dev.vhost_ops; + struct vhost_vring_file file = { }; + int idx, r; + + if (!net->dev.started) { + return -EBUSY; + } + + /* should only be called after backend is connected */ + assert(vhost_ops); + + idx = vhost_ops->vhost_get_vq_index(&net->dev, vq_index); + + r = vhost_virtqueue_start(&net->dev, + vdev, + net->dev.vqs + idx, + net->dev.vq_index + idx); + if (r < 0) { + goto err_start; + } + + if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + file.index = idx; + file.fd = net->backend; + r = vhost_net_set_backend(&net->dev, &file); + if (r < 0) { + r = -errno; + goto err_start; + } + } + + return 0; + +err_start: + error_report("Error when restarting the queue."); + + if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + file.fd = VHOST_FILE_UNBIND; + file.index = idx; + int r = vhost_net_set_backend(&net->dev, &file); + assert(r >= 0); + } + + vhost_dev_stop(&net->dev, vdev, false); + + return r; +} diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1067e72b3975..3ae909041aaf 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qemu/atomic.h" #include "qemu/iov.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/virtio/virtio.h" @@ -41,14 +42,13 @@ #include "sysemu/sysemu.h" #include "trace.h" #include "monitor/qdev.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "net_rx_pkt.h" #include "hw/virtio/vhost.h" #include "sysemu/qtest.h" #define VIRTIO_NET_VM_VERSION 11 -#define MAC_TABLE_ENTRIES 64 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ /* previously fixed value */ @@ -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); @@ -118,6 +124,16 @@ static int vq2q(int queue_index) return queue_index / 2; } +static void flush_or_purge_queued_packets(NetClientState *nc) +{ + if (!nc->peer) { + return; + } + + qemu_flush_or_purge_queued_packets(nc->peer, true); + assert(!virtio_net_get_subqueue(nc)->async_tx.elem); +} + /* TODO * - we could suppress RX interrupt if we were so inclined. */ @@ -152,20 +168,24 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, n->config_size); - if (ret != -1) { - /* - * Some NIC/kernel combinations present 0 as the mac address. As - * that is not a legal address, try to proceed with the - * address from the QEMU command line in the hope that the - * address has been configured correctly elsewhere - just not - * reported by the device. - */ - if (memcmp(&netcfg.mac, &zero, sizeof(zero)) == 0) { - info_report("Zero hardware mac address detected. Ignoring."); - memcpy(netcfg.mac, n->mac, ETH_ALEN); - } - memcpy(config, &netcfg, n->config_size); + if (ret == -1) { + return; } + + /* + * Some NIC/kernel combinations present 0 as the mac address. As that + * is not a legal address, try to proceed with the address from the + * QEMU command line in the hope that the address has been configured + * correctly elsewhere - just not reported by the device. + */ + if (memcmp(&netcfg.mac, &zero, sizeof(zero)) == 0) { + info_report("Zero hardware mac address detected. Ignoring."); + memcpy(netcfg.mac, n->mac, ETH_ALEN); + } + + netcfg.status |= virtio_tswap16(vdev, + n->status & VIRTIO_NET_S_ANNOUNCE); + memcpy(config, &netcfg, n->config_size); } } @@ -245,7 +265,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) VirtIODevice *vdev = VIRTIO_DEVICE(n); NetClientState *nc = qemu_get_queue(n->nic); int queue_pairs = n->multiqueue ? n->max_queue_pairs : 1; - int cvq = n->max_ncs - n->max_queue_pairs; + int cvq = virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) ? + n->max_ncs - n->max_queue_pairs : 0; if (!get_vhost_net(nc->peer)) { return; @@ -440,8 +461,7 @@ static void rxfilter_notify(NetClientState *nc) if (nc->rxfilter_notify_enabled) { char *path = object_get_canonical_path(OBJECT(n->qdev)); - qapi_event_send_nic_rx_filter_changed(!!n->netclient_name, - n->netclient_name, path); + qapi_event_send_nic_rx_filter_changed(n->netclient_name, path); g_free(path); /* disable event notification to avoid events flooding */ @@ -529,6 +549,57 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc) return info; } +static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t queue_index) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc; + + /* validate queue_index and skip for cvq */ + if (queue_index >= n->max_queue_pairs * 2) { + return; + } + + nc = qemu_get_subqueue(n->nic, vq2q(queue_index)); + + if (!nc->peer) { + return; + } + + if (get_vhost_net(nc->peer) && + nc->peer->info->type == NET_CLIENT_DRIVER_TAP) { + vhost_net_virtqueue_reset(vdev, nc, queue_index); + } + + flush_or_purge_queued_packets(nc); +} + +static void virtio_net_queue_enable(VirtIODevice *vdev, uint32_t queue_index) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc; + int r; + + /* validate queue_index and skip for cvq */ + if (queue_index >= n->max_queue_pairs * 2) { + return; + } + + nc = qemu_get_subqueue(n->nic, vq2q(queue_index)); + + if (!nc->peer || !vdev->vhost_started) { + return; + } + + if (get_vhost_net(nc->peer) && + nc->peer->info->type == NET_CLIENT_DRIVER_TAP) { + r = vhost_net_virtqueue_restart(vdev, nc, queue_index); + if (r < 0) { + error_report("unable to restart vhost net virtqueue: %d, " + "when resetting the queue", queue_index); + } + } +} + static void virtio_net_reset(VirtIODevice *vdev) { VirtIONet *n = VIRTIO_NET(vdev); @@ -559,12 +630,7 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Flush any async TX */ for (i = 0; i < n->max_queue_pairs; i++) { - NetClientState *nc = qemu_get_subqueue(n->nic, i); - - if (nc->peer) { - qemu_flush_or_purge_queued_packets(nc->peer, true); - assert(!virtio_net_get_subqueue(nc)->async_tx.elem); - } + flush_or_purge_queued_packets(qemu_get_subqueue(n->nic, i)); } } @@ -739,6 +805,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, } if (!get_vhost_net(nc->peer)) { + virtio_add_feature(&features, VIRTIO_F_RING_RESET); return features; } @@ -917,6 +984,12 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) continue; } vhost_net_ack_features(get_vhost_net(nc->peer), features); + + /* + * keep acked_features in NetVhostUserState up-to-date so it + * can't miss any features configured by guest virtio driver. + */ + vhost_net_save_acked_features(nc->peer); } if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { @@ -1379,6 +1452,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, { VirtIODevice *vdev = VIRTIO_DEVICE(n); uint16_t queue_pairs; + NetClientState *nc = qemu_get_queue(n->nic); virtio_net_disable_rss(n); if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) { @@ -1411,6 +1485,13 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, } 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); @@ -1419,56 +1500,71 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_OK; } -static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, + const struct iovec *in_sg, unsigned in_num, + const struct iovec *out_sg, + unsigned out_num) { VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_ctrl_hdr ctrl; virtio_net_ctrl_ack status = VIRTIO_NET_ERR; - VirtQueueElement *elem; size_t s; struct iovec *iov, *iov2; - unsigned int iov_cnt; + + if (iov_size(in_sg, in_num) < sizeof(status) || + iov_size(out_sg, out_num) < sizeof(ctrl)) { + virtio_error(vdev, "virtio-net ctrl missing headers"); + return 0; + } + + iov2 = iov = g_memdup2(out_sg, sizeof(struct iovec) * out_num); + s = iov_to_buf(iov, out_num, 0, &ctrl, sizeof(ctrl)); + iov_discard_front(&iov, &out_num, sizeof(ctrl)); + if (s != sizeof(ctrl)) { + status = VIRTIO_NET_ERR; + } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { + status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, out_num); + } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { + status = virtio_net_handle_mac(n, ctrl.cmd, iov, out_num); + } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { + status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, out_num); + } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { + status = virtio_net_handle_announce(n, ctrl.cmd, iov, out_num); + } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { + status = virtio_net_handle_mq(n, ctrl.cmd, iov, out_num); + } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { + status = virtio_net_handle_offloads(n, ctrl.cmd, iov, out_num); + } + + s = iov_from_buf(in_sg, in_num, 0, &status, sizeof(status)); + assert(s == sizeof(status)); + + g_free(iov2); + return sizeof(status); +} + +static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtQueueElement *elem; for (;;) { + size_t written; elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { break; } - if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || - iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { - virtio_error(vdev, "virtio-net ctrl missing headers"); + + written = virtio_net_handle_ctrl_iov(vdev, elem->in_sg, elem->in_num, + elem->out_sg, elem->out_num); + if (written > 0) { + virtqueue_push(vq, elem, written); + virtio_notify(vdev, vq); + g_free(elem); + } else { virtqueue_detach_element(vq, elem, 0); g_free(elem); break; } - - iov_cnt = elem->out_num; - iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); - s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); - iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); - if (s != sizeof(ctrl)) { - status = VIRTIO_NET_ERR; - } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { - status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); - } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { - status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); - } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { - status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); - } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { - status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt); - } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { - status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt); - } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { - status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); - } - - s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status)); - assert(s == sizeof(status)); - - virtqueue_push(vq, elem, sizeof(status)); - virtio_notify(vdev, vq); - g_free(iov2); - g_free(elem); } } @@ -2385,7 +2481,7 @@ static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc, VirtioNetRscChain *chain; VirtioNetRscUnit unit; - chain = (VirtioNetRscChain *)opq; + chain = opq; hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header) @@ -2496,6 +2592,7 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) VirtIONet *n = qemu_get_nic_opaque(nc); VirtIONetQueue *q = virtio_net_get_subqueue(nc); VirtIODevice *vdev = VIRTIO_DEVICE(n); + int ret; virtqueue_push(q->tx_vq, q->async_tx.elem, 0); virtio_notify(vdev, q->tx_vq); @@ -2504,7 +2601,22 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) q->async_tx.elem = NULL; virtio_queue_set_notification(q->tx_vq, 1); - virtio_net_flush_tx(q); + ret = virtio_net_flush_tx(q); + if (ret >= n->tx_burst) { + /* + * the flush has been stopped by tx_burst + * we will not receive notification for the + * remainining part, so re-schedule + */ + virtio_queue_set_notification(q->tx_vq, 0); + if (q->tx_bh) { + qemu_bh_schedule(q->tx_bh); + } else { + timer_mod(q->tx_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); + } + q->tx_waiting = 1; + } } /* TX */ @@ -2603,6 +2715,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) return num_packets; } +static void virtio_net_tx_timer(void *opaque); + static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = VIRTIO_NET(vdev); @@ -2620,15 +2734,13 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) } if (q->tx_waiting) { - virtio_queue_set_notification(vq, 1); + /* We already have queued packets, immediately flush */ timer_del(q->tx_timer); - q->tx_waiting = 0; - if (virtio_net_flush_tx(q) == -EINVAL) { - return; - } + virtio_net_tx_timer(q); } else { + /* re-arm timer to flush it (and more) on next tick */ timer_mod(q->tx_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); q->tx_waiting = 1; virtio_queue_set_notification(vq, 0); } @@ -2661,6 +2773,8 @@ static void virtio_net_tx_timer(void *opaque) VirtIONetQueue *q = opaque; VirtIONet *n = q->n; VirtIODevice *vdev = VIRTIO_DEVICE(n); + int ret; + /* This happens when device was stopped but BH wasn't. */ if (!vdev->vm_running) { /* Make sure tx waiting is set, so we'll run when restarted. */ @@ -2675,8 +2789,33 @@ static void virtio_net_tx_timer(void *opaque) return; } + ret = virtio_net_flush_tx(q); + if (ret == -EBUSY || ret == -EINVAL) { + return; + } + /* + * If we flush a full burst of packets, assume there are + * more coming and immediately rearm + */ + if (ret >= n->tx_burst) { + q->tx_waiting = 1; + timer_mod(q->tx_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); + return; + } + /* + * If less than a full burst, re-enable notification and flush + * anything that may have come in while we weren't looking. If + * we find something, assume the guest is still active and rearm + */ virtio_queue_set_notification(q->tx_vq, 1); - virtio_net_flush_tx(q); + ret = virtio_net_flush_tx(q); + if (ret > 0) { + virtio_queue_set_notification(q->tx_vq, 0); + q->tx_waiting = 1; + timer_mod(q->tx_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); + } } static void virtio_net_tx_bh(void *opaque) @@ -3170,8 +3309,31 @@ static NetClientInfo net_virtio_info = { static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) { VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + NetClientState *nc; assert(n->vhost_started); + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { + /* Must guard against invalid features and bogus queue index + * from being set by malicious guest, or penetrated through + * buggy migration stream. + */ + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus vq index ignored\n", __func__); + return false; + } + nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return false + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return vhost_net_config_pending(get_vhost_net(nc->peer)); + } return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); } @@ -3179,18 +3341,40 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) { VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + NetClientState *nc; assert(n->vhost_started); - vhost_net_virtqueue_mask(get_vhost_net(nc->peer), - vdev, idx, mask); + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { + /* Must guard against invalid features and bogus queue index + * from being set by malicious guest, or penetrated through + * buggy migration stream. + */ + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus vq index ignored\n", __func__); + return; + } + nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } + /* + *Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + vhost_net_config_mask(get_vhost_net(nc->peer), vdev, mask); + return; + } + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); } 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, @@ -3392,7 +3576,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) } virtio_net_set_config_size(n, n->host_features); - virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); + virtio_init(vdev, VIRTIO_ID_NET, n->config_size); /* * We set a lower limit on RX queue size to what it always was. @@ -3619,6 +3803,14 @@ static bool dev_unplug_pending(void *opaque) return vdc->primary_unplug_pending(dev); } +static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_queue(n->nic); + struct vhost_net *net = get_vhost_net(nc->peer); + return &net->dev; +} + static const VMStateDescription vmstate_virtio_net = { .name = "virtio-net", .minimum_version_id = VIRTIO_NET_VM_VERSION, @@ -3714,6 +3906,8 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->set_features = virtio_net_set_features; vdc->bad_features = virtio_net_bad_features; vdc->reset = virtio_net_reset; + vdc->queue_reset = virtio_net_queue_reset; + vdc->queue_enable = virtio_net_queue_enable; vdc->set_status = virtio_net_set_status; vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; @@ -3721,6 +3915,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->post_load = virtio_net_post_load_virtio; vdc->vmsd = &vmstate_virtio_net_device; vdc->primary_unplug_pending = primary_unplug_pending; + vdc->get_vhost = virtio_net_get_vhost; } static const TypeInfo virtio_net_info = { diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 0b7acf7f895b..d2ab527ef457 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2110,20 +2110,14 @@ vmxnet3_unuse_msix_vectors(VMXNET3State *s, int num_vectors) } } -static bool +static void vmxnet3_use_msix_vectors(VMXNET3State *s, int num_vectors) { PCIDevice *d = PCI_DEVICE(s); int i; for (i = 0; i < num_vectors; i++) { - int res = msix_vector_use(d, i); - if (0 > res) { - VMW_WRPRN("Failed to use MSI-X vector %d, error %d", i, res); - vmxnet3_unuse_msix_vectors(s, i); - return false; - } + msix_vector_use(d, i); } - return true; } static bool @@ -2141,13 +2135,8 @@ vmxnet3_init_msix(VMXNET3State *s) VMW_WRPRN("Failed to initialize MSI-X, error %d", res); s->msix_used = false; } else { - if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) { - VMW_WRPRN("Failed to use MSI-X vectors, error %d", res); - msix_uninit(d, &s->msix_bar, &s->msix_bar); - s->msix_used = false; - } else { - s->msix_used = true; - } + vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS); + s->msix_used = true; } return s->msix_used; } @@ -2412,19 +2401,13 @@ static const VMStateDescription vmstate_vmxnet3_rxq_descr = { static int vmxnet3_post_load(void *opaque, int version_id) { VMXNET3State *s = opaque; - PCIDevice *d = PCI_DEVICE(s); net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags, s->peer_has_vhdr); net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); if (s->msix_used) { - if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) { - VMW_WRPRN("Failed to re-use MSI-X vectors"); - msix_uninit(d, &s->msix_bar, &s->msix_bar); - s->msix_used = false; - return -1; - } + vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS); } if (!vmxnet3_validate_queues(s)) { diff --git a/hw/net/vmxnet3.h b/hw/net/vmxnet3.h index 5b3b76ba7ad1..bf4f6de74a07 100644 --- a/hw/net/vmxnet3.h +++ b/hw/net/vmxnet3.h @@ -35,7 +35,7 @@ #define __le32 uint32_t #define __le64 uint64_t -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define __BIG_ENDIAN_BITFIELD #else #endif @@ -800,7 +800,7 @@ struct Vmxnet3_DriverShared { #undef __le16 #undef __le32 #undef __le64 -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #undef __BIG_ENDIAN_BITFIELD #endif diff --git a/hw/net/vmxnet3_defs.h b/hw/net/vmxnet3_defs.h index 71440509cabf..64034af6d574 100644 --- a/hw/net/vmxnet3_defs.h +++ b/hw/net/vmxnet3_defs.h @@ -19,7 +19,7 @@ #include "net/net.h" #include "hw/net/vmxnet3.h" -#include "qom/object.h" +#include "hw/pci/pci_device.h" #define TYPE_VMXNET3 "vmxnet3" typedef struct VMXNET3State VMXNET3State; diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 5c815b4f0c52..7d92c2d022b0 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -296,9 +296,8 @@ static int net_init(struct XenLegacyDevice *xendev) netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, "xen", NULL, netdev); - snprintf(qemu_get_queue(netdev->nic)->info_str, - sizeof(qemu_get_queue(netdev->nic)->info_str), - "nic: xenbus vif macaddr=%s", netdev->mac); + qemu_set_info_str(qemu_get_queue(netdev->nic), + "nic: xenbus vif macaddr=%s", netdev->mac); /* fill info */ xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1); diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index 3d1205b8bd7a..91383fb09791 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -27,6 +27,7 @@ #include "hw/sysbus.h" #include "hw/char/serial.h" +#include "hw/intc/nios2_vic.h" #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" #include "hw/boards.h" @@ -36,17 +37,28 @@ #include "boot.h" +struct Nios2MachineState { + MachineState parent_obj; + + MemoryRegion phys_tcm; + MemoryRegion phys_tcm_alias; + MemoryRegion phys_ram; + MemoryRegion phys_ram_alias; + + bool vic; +}; + +#define TYPE_NIOS2_MACHINE MACHINE_TYPE_NAME("10m50-ghrd") +OBJECT_DECLARE_TYPE(Nios2MachineState, MachineClass, NIOS2_MACHINE) + #define BINARY_DEVICE_TREE_FILE "10m50-devboard.dtb" static void nios2_10m50_ghrd_init(MachineState *machine) { + Nios2MachineState *nms = NIOS2_MACHINE(machine); Nios2CPU *cpu; DeviceState *dev; MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *phys_tcm = g_new(MemoryRegion, 1); - MemoryRegion *phys_tcm_alias = g_new(MemoryRegion, 1); - MemoryRegion *phys_ram = g_new(MemoryRegion, 1); - MemoryRegion *phys_ram_alias = g_new(MemoryRegion, 1); ram_addr_t tcm_base = 0x0; ram_addr_t tcm_size = 0x1000; /* 1 kiB, but QEMU limit is 4 kiB */ ram_addr_t ram_base = 0x08000000; @@ -55,27 +67,56 @@ static void nios2_10m50_ghrd_init(MachineState *machine) int i; /* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */ - memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size, + memory_region_init_ram(&nms->phys_tcm, NULL, "nios2.tcm", tcm_size, &error_abort); - memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias", - phys_tcm, 0, tcm_size); - memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm); + memory_region_init_alias(&nms->phys_tcm_alias, NULL, "nios2.tcm.alias", + &nms->phys_tcm, 0, tcm_size); + memory_region_add_subregion(address_space_mem, tcm_base, &nms->phys_tcm); memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base, - phys_tcm_alias); + &nms->phys_tcm_alias); /* Physical DRAM with alias at 0xc0000000 */ - memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size, + memory_region_init_ram(&nms->phys_ram, NULL, "nios2.ram", ram_size, &error_abort); - memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias", - phys_ram, 0, ram_size); - memory_region_add_subregion(address_space_mem, ram_base, phys_ram); + memory_region_init_alias(&nms->phys_ram_alias, NULL, "nios2.ram.alias", + &nms->phys_ram, 0, ram_size); + memory_region_add_subregion(address_space_mem, ram_base, &nms->phys_ram); memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base, - phys_ram_alias); + &nms->phys_ram_alias); - /* Create CPU -- FIXME */ - cpu = NIOS2_CPU(cpu_create(TYPE_NIOS2_CPU)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i); + /* Create CPU. We need to set eic_present between init and realize. */ + cpu = NIOS2_CPU(object_new(TYPE_NIOS2_CPU)); + + /* Enable the External Interrupt Controller within the CPU. */ + cpu->eic_present = nms->vic; + + /* Configure new exception vectors. */ + cpu->reset_addr = 0xd4000000; + cpu->exception_addr = 0xc8000120; + cpu->fast_tlb_miss_addr = 0xc0000100; + + qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal); + + if (nms->vic) { + DeviceState *dev = qdev_new(TYPE_NIOS2_VIC); + MemoryRegion *dev_mr; + qemu_irq cpu_irq; + + object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + cpu_irq = qdev_get_gpio_in_named(DEVICE(cpu), "EIC", 0); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq); + for (int i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + + dev_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion(address_space_mem, 0x18002000, dev_mr); + } else { + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i); + } } /* Register: Altera 16550 UART */ @@ -96,20 +137,44 @@ static void nios2_10m50_ghrd_init(MachineState *machine) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]); - /* Configure new exception vectors and reset CPU for it to take effect. */ - cpu->reset_addr = 0xd4000000; - cpu->exception_addr = 0xc8000120; - cpu->fast_tlb_miss_addr = 0xc0000100; - nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename, BINARY_DEVICE_TREE_FILE, NULL); } -static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc) +static bool get_vic(Object *obj, Error **errp) +{ + Nios2MachineState *nms = NIOS2_MACHINE(obj); + return nms->vic; +} + +static void set_vic(Object *obj, bool value, Error **errp) +{ + Nios2MachineState *nms = NIOS2_MACHINE(obj); + nms->vic = value; +} + +static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data) { + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "Altera 10M50 GHRD Nios II design"; mc->init = nios2_10m50_ghrd_init; mc->is_default = true; + + object_class_property_add_bool(oc, "vic", get_vic, set_vic); + object_class_property_set_description(oc, "vic", + "Set on/off to enable/disable the Vectored Interrupt Controller"); } -DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init); +static const TypeInfo nios2_10m50_ghrd_type_info = { + .name = TYPE_NIOS2_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(Nios2MachineState), + .class_init = nios2_10m50_ghrd_class_init, +}; + +static void nios2_10m50_ghrd_type_init(void) +{ + type_register_static(&nios2_10m50_ghrd_type_info); +} +type_init(nios2_10m50_ghrd_type_init); diff --git a/hw/nios2/Kconfig b/hw/nios2/Kconfig index b10ea640dab1..4748ae27b677 100644 --- a/hw/nios2/Kconfig +++ b/hw/nios2/Kconfig @@ -3,6 +3,7 @@ config NIOS2_10M50 select NIOS2 select SERIAL select ALTERA_TIMER + select NIOS2_VIC config NIOS2_GENERIC_NOMMU bool diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c index 5b3e4efed5be..b30a7b1efbcb 100644 --- a/hw/nios2/boot.c +++ b/hw/nios2/boot.c @@ -30,11 +30,11 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu-common.h" #include "qemu/datadir.h" #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" @@ -43,6 +43,8 @@ #include "boot.h" +#include + #define NIOS2_MAGIC 0x534f494e static struct nios2_boot_info { @@ -81,9 +83,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, const char *kernel_cmdline, const char *dtb_filename) { + MachineState *machine = MACHINE(qdev_get_machine()); int fdt_size; void *fdt = NULL; int r; + uint8_t rng_seed[32]; if (dtb_filename) { fdt = load_device_tree(dtb_filename, &fdt_size); @@ -92,6 +96,9 @@ static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, 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); @@ -109,7 +116,10 @@ static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, } cpu_physical_memory_write(bi.fdt, fdt, fdt_size); - g_free(fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + return fdt_size; } @@ -140,7 +150,7 @@ void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base, uint64_t entry, high; int big_endian = 0; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN big_endian = 1; #endif diff --git a/hw/nios2/generic_nommu.c b/hw/nios2/generic_nommu.c index fbc18dbd04c2..48edb3ae373d 100644 --- a/hw/nios2/generic_nommu.c +++ b/hw/nios2/generic_nommu.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "hw/char/serial.h" #include "hw/boards.h" diff --git a/hw/nios2/meson.build b/hw/nios2/meson.build index 6c58e8082b48..22277bd6c56f 100644 --- a/hw/nios2/meson.build +++ b/hw/nios2/meson.build @@ -1,5 +1,5 @@ nios2_ss = ss.source_set() -nios2_ss.add(files('boot.c')) +nios2_ss.add(files('boot.c'), fdt) nios2_ss.add(when: 'CONFIG_NIOS2_10M50', if_true: files('10m50_devboard.c')) nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c')) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 03760ddeae8c..f25cc2c235e9 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -35,6 +35,11 @@ * mdts=,vsl=, \ * zoned.zasl=, \ * zoned.auto_transition=, \ + * sriov_max_vfs= \ + * sriov_vq_flexible= \ + * sriov_vi_flexible= \ + * sriov_max_vi_per_vf= \ + * sriov_max_vq_per_vf= \ * subsys= * -device nvme-ns,drive=,bus=,nsid=,\ * zoned=, \ @@ -71,7 +76,7 @@ * the SUBNQN field in the controller will report the NQN of the subsystem * device. This also enables multi controller capability represented in * Identify Controller data structure in CMIC (Controller Multi-path I/O and - * Namesapce Sharing Capabilities). + * Namespace Sharing Capabilities). * * - `aerl` * The Asynchronous Event Request Limit (AERL). Indicates the maximum number @@ -106,6 +111,35 @@ * transitioned to zone state closed for resource management purposes. * Defaults to 'on'. * + * - `sriov_max_vfs` + * Indicates the maximum number of PCIe virtual functions supported + * by the controller. The default value is 0. Specifying a non-zero value + * enables reporting of both SR-IOV and ARI capabilities by the NVMe device. + * Virtual function controllers will not report SR-IOV capability. + * + * NOTE: Single Root I/O Virtualization support is experimental. + * All the related parameters may be subject to change. + * + * - `sriov_vq_flexible` + * Indicates the total number of flexible queue resources assignable to all + * the secondary controllers. Implicitly sets the number of primary + * controller's private resources to `(max_ioqpairs - sriov_vq_flexible)`. + * + * - `sriov_vi_flexible` + * Indicates the total number of flexible interrupt resources assignable to + * all the secondary controllers. Implicitly sets the number of primary + * controller's private resources to `(msix_qsize - sriov_vi_flexible)`. + * + * - `sriov_max_vi_per_vf` + * Indicates the maximum number of virtual interrupt resources assignable + * to a secondary controller. The default 0 resolves to + * `(sriov_vi_flexible / sriov_max_vfs)`. + * + * - `sriov_max_vq_per_vf` + * Indicates the maximum number of virtual queue resources assignable to + * a secondary controller. The default 0 resolves to + * `(sriov_vq_flexible / sriov_max_vfs)`. + * * nvme namespace device parameters * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - `shared` @@ -154,12 +188,14 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/units.h" +#include "qemu/range.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" #include "sysemu/hostmem.h" #include "hw/pci/msix.h" +#include "hw/pci/pcie_sriov.h" #include "migration/vmstate.h" #include "nvme.h" @@ -176,6 +212,10 @@ #define NVME_TEMPERATURE_CRITICAL 0x175 #define NVME_NUM_FW_SLOTS 1 #define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB) +#define NVME_MAX_VFS 127 +#define NVME_VF_RES_GRANULARITY 1 +#define NVME_VF_OFFSET 0x1 +#define NVME_VF_STRIDE 1 #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ @@ -223,6 +263,8 @@ static const uint32_t nvme_cse_acs[256] = { [NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC, + [NVME_ADM_CMD_VIRT_MNGMT] = NVME_CMD_EFF_CSUPP, + [NVME_ADM_CMD_DBBUF_CONFIG] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, }; @@ -254,6 +296,7 @@ static const uint32_t nvme_cse_iocs_zoned[256] = { }; static void nvme_process_sq(void *opaque); +static void nvme_ctrl_reset(NvmeCtrl *n, NvmeResetType rst); static uint16_t nvme_sqid(NvmeRequest *req) { @@ -406,7 +449,7 @@ static int nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) return 0; } - return pci_dma_read(&n->parent_obj, addr, buf, size); + return pci_dma_read(PCI_DEVICE(n), addr, buf, size); } static int nvme_addr_write(NvmeCtrl *n, hwaddr addr, const void *buf, int size) @@ -426,7 +469,7 @@ static int nvme_addr_write(NvmeCtrl *n, hwaddr addr, const void *buf, int size) return 0; } - return pci_dma_write(&n->parent_obj, addr, buf, size); + return pci_dma_write(PCI_DEVICE(n), addr, buf, size); } static bool nvme_nsid_valid(NvmeCtrl *n, uint32_t nsid) @@ -437,12 +480,12 @@ static bool nvme_nsid_valid(NvmeCtrl *n, uint32_t nsid) static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) { - return sqid < n->params.max_ioqpairs + 1 && n->sq[sqid] != NULL ? 0 : -1; + return sqid < n->conf_ioqpairs + 1 && n->sq[sqid] != NULL ? 0 : -1; } static int nvme_check_cqid(NvmeCtrl *n, uint16_t cqid) { - return cqid < n->params.max_ioqpairs + 1 && n->cq[cqid] != NULL ? 0 : -1; + return cqid < n->conf_ioqpairs + 1 && n->cq[cqid] != NULL ? 0 : -1; } static void nvme_inc_cq_tail(NvmeCQueue *cq) @@ -471,24 +514,27 @@ static uint8_t nvme_sq_empty(NvmeSQueue *sq) static void nvme_irq_check(NvmeCtrl *n) { + PCIDevice *pci = PCI_DEVICE(n); uint32_t intms = ldl_le_p(&n->bar.intms); - if (msix_enabled(&(n->parent_obj))) { + if (msix_enabled(pci)) { return; } if (~intms & n->irq_status) { - pci_irq_assert(&n->parent_obj); + pci_irq_assert(pci); } else { - pci_irq_deassert(&n->parent_obj); + pci_irq_deassert(pci); } } static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) { + PCIDevice *pci = PCI_DEVICE(n); + if (cq->irq_enabled) { - if (msix_enabled(&(n->parent_obj))) { + if (msix_enabled(pci)) { trace_pci_nvme_irq_msix(cq->vector); - msix_notify(&(n->parent_obj), cq->vector); + msix_notify(pci, cq->vector); } else { trace_pci_nvme_irq_pin(); assert(cq->vector < 32); @@ -503,7 +549,7 @@ static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) static void nvme_irq_deassert(NvmeCtrl *n, NvmeCQueue *cq) { if (cq->irq_enabled) { - if (msix_enabled(&(n->parent_obj))) { + if (msix_enabled(PCI_DEVICE(n))) { return; } else { assert(cq->vector < 32); @@ -527,7 +573,7 @@ static void nvme_req_clear(NvmeRequest *req) static inline void nvme_sg_init(NvmeCtrl *n, NvmeSg *sg, bool dma) { if (dma) { - pci_dma_sglist_init(&sg->qsg, &n->parent_obj, 0); + pci_dma_sglist_init(&sg->qsg, PCI_DEVICE(n), 0); sg->flags = NVME_SG_DMA; } else { qemu_iovec_init(&sg->iov, 0); @@ -808,10 +854,6 @@ static uint16_t nvme_map_sgl_data(NvmeCtrl *n, NvmeSg *sg, uint8_t type = NVME_SGL_TYPE(segment[i].type); switch (type) { - case NVME_SGL_DESCR_TYPE_BIT_BUCKET: - if (cmd->opcode == NVME_CMD_WRITE) { - continue; - } case NVME_SGL_DESCR_TYPE_DATA_BLOCK: break; case NVME_SGL_DESCR_TYPE_SEGMENT: @@ -844,10 +886,6 @@ static uint16_t nvme_map_sgl_data(NvmeCtrl *n, NvmeSg *sg, trans_len = MIN(*len, dlen); - if (type == NVME_SGL_DESCR_TYPE_BIT_BUCKET) { - goto next; - } - addr = le64_to_cpu(segment[i].addr); if (UINT64_MAX - addr < dlen) { @@ -859,7 +897,6 @@ static uint16_t nvme_map_sgl_data(NvmeCtrl *n, NvmeSg *sg, return status; } -next: *len -= trans_len; } @@ -917,8 +954,7 @@ static uint16_t nvme_map_sgl(NvmeCtrl *n, NvmeSg *sg, NvmeSglDescriptor sgl, seg_len = le32_to_cpu(sgld->len); /* check the length of the (Last) Segment descriptor */ - if ((!seg_len || seg_len & 0xf) && - (NVME_SGL_TYPE(sgld->type) != NVME_SGL_DESCR_TYPE_BIT_BUCKET)) { + if (!seg_len || seg_len & 0xf) { return NVME_INVALID_SGL_SEG_DESCR | NVME_DNR; } @@ -956,26 +992,20 @@ static uint16_t nvme_map_sgl(NvmeCtrl *n, NvmeSg *sg, NvmeSglDescriptor sgl, last_sgld = &segment[nsgld - 1]; /* - * If the segment ends with a Data Block or Bit Bucket Descriptor Type, - * then we are done. + * If the segment ends with a Data Block, then we are done. */ - switch (NVME_SGL_TYPE(last_sgld->type)) { - case NVME_SGL_DESCR_TYPE_DATA_BLOCK: - case NVME_SGL_DESCR_TYPE_BIT_BUCKET: + if (NVME_SGL_TYPE(last_sgld->type) == NVME_SGL_DESCR_TYPE_DATA_BLOCK) { status = nvme_map_sgl_data(n, sg, segment, nsgld, &len, cmd); if (status) { goto unmap; } goto out; - - default: - break; } /* - * If the last descriptor was not a Data Block or Bit Bucket, then the - * current segment must not be a Last Segment. + * If the last descriptor was not a Data Block, then the current + * segment must not be a Last Segment. */ if (NVME_SGL_TYPE(sgld->type) == NVME_SGL_DESCR_TYPE_LAST_SEGMENT) { status = NVME_INVALID_SGL_SEG_DESCR | NVME_DNR; @@ -1304,6 +1334,26 @@ static inline void nvme_blk_write(BlockBackend *blk, int64_t offset, } } +static void nvme_update_cq_eventidx(const NvmeCQueue *cq) +{ + uint32_t v = cpu_to_le32(cq->head); + + trace_pci_nvme_update_cq_eventidx(cq->cqid, cq->head); + + pci_dma_write(PCI_DEVICE(cq->ctrl), cq->ei_addr, &v, sizeof(v)); +} + +static void nvme_update_cq_head(NvmeCQueue *cq) +{ + uint32_t v; + + pci_dma_read(PCI_DEVICE(cq->ctrl), cq->db_addr, &v, sizeof(v)); + + cq->head = le32_to_cpu(v); + + trace_pci_nvme_update_cq_head(cq->cqid, cq->head); +} + static void nvme_post_cqes(void *opaque) { NvmeCQueue *cq = opaque; @@ -1316,6 +1366,11 @@ static void nvme_post_cqes(void *opaque) NvmeSQueue *sq; hwaddr addr; + if (n->dbbuf_enabled) { + nvme_update_cq_eventidx(cq); + nvme_update_cq_head(cq); + } + if (nvme_cq_full(cq)) { break; } @@ -1325,7 +1380,7 @@ static void nvme_post_cqes(void *opaque) req->cqe.sq_id = cpu_to_le16(sq->sqid); req->cqe.sq_head = cpu_to_le16(sq->head); addr = cq->dma_addr + cq->tail * n->cqe_size; - ret = pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe, + ret = pci_dma_write(PCI_DEVICE(n), addr, (void *)&req->cqe, sizeof(req->cqe)); if (ret) { trace_pci_nvme_err_addr_write(addr); @@ -1362,7 +1417,8 @@ static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req) QTAILQ_REMOVE(&req->sq->out_req_list, req, entry); QTAILQ_INSERT_TAIL(&cq->req_list, req, entry); - timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); + + qemu_bh_schedule(cq->bh); } static void nvme_process_aers(void *opaque) @@ -2290,7 +2346,6 @@ typedef struct NvmeDSMAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; NvmeRequest *req; - QEMUBH *bh; int ret; NvmeDsmRange *range; @@ -2312,7 +2367,7 @@ static void nvme_dsm_cancel(BlockAIOCB *aiocb) } else { /* * We only reach this if nvme_dsm_cancel() has already been called or - * the command ran to completion and nvme_dsm_bh is scheduled to run. + * the command ran to completion. */ assert(iocb->idx == iocb->nr); } @@ -2323,17 +2378,6 @@ static const AIOCBInfo nvme_dsm_aiocb_info = { .cancel_async = nvme_dsm_cancel, }; -static void nvme_dsm_bh(void *opaque) -{ - NvmeDSMAIOCB *iocb = opaque; - - iocb->common.cb(iocb->common.opaque, iocb->ret); - - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; - qemu_aio_unref(iocb); -} - static void nvme_dsm_cb(void *opaque, int ret); static void nvme_dsm_md_cb(void *opaque, int ret) @@ -2345,16 +2389,10 @@ static void nvme_dsm_md_cb(void *opaque, int ret) uint64_t slba; uint32_t nlb; - if (ret < 0) { - iocb->ret = ret; + if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) { goto done; } - if (!ns->lbaf.ms) { - nvme_dsm_cb(iocb, 0); - return; - } - range = &iocb->range[iocb->idx - 1]; slba = le64_to_cpu(range->slba); nlb = le32_to_cpu(range->nlb); @@ -2367,11 +2405,11 @@ static void nvme_dsm_md_cb(void *opaque, int ret) ret = nvme_block_status_all(ns, slba, nlb, BDRV_BLOCK_ZERO); if (ret) { if (ret < 0) { - iocb->ret = ret; goto done; } nvme_dsm_cb(iocb, 0); + return; } iocb->aiocb = blk_aio_pwrite_zeroes(ns->blkconf.blk, nvme_moff(ns, slba), @@ -2380,8 +2418,7 @@ static void nvme_dsm_md_cb(void *opaque, int ret) return; done: - iocb->aiocb = NULL; - qemu_bh_schedule(iocb->bh); + nvme_dsm_cb(iocb, ret); } static void nvme_dsm_cb(void *opaque, int ret) @@ -2394,7 +2431,9 @@ static void nvme_dsm_cb(void *opaque, int ret) uint64_t slba; uint32_t nlb; - if (ret < 0) { + if (iocb->ret < 0) { + goto done; + } else if (ret < 0) { iocb->ret = ret; goto done; } @@ -2428,7 +2467,8 @@ static void nvme_dsm_cb(void *opaque, int ret) done: iocb->aiocb = NULL; - qemu_bh_schedule(iocb->bh); + iocb->common.cb(iocb->common.opaque, iocb->ret); + qemu_aio_unref(iocb); } static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req) @@ -2446,7 +2486,6 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req) nvme_misc_cb, req); iocb->req = req; - iocb->bh = qemu_bh_new(nvme_dsm_bh, iocb); iocb->ret = 0; iocb->range = g_new(NvmeDsmRange, nr); iocb->nr = nr; @@ -2530,7 +2569,6 @@ typedef struct NvmeCopyAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; NvmeRequest *req; - QEMUBH *bh; int ret; void *ranges; @@ -2568,9 +2606,8 @@ static const AIOCBInfo nvme_copy_aiocb_info = { .cancel_async = nvme_copy_cancel, }; -static void nvme_copy_bh(void *opaque) +static void nvme_copy_done(NvmeCopyAIOCB *iocb) { - NvmeCopyAIOCB *iocb = opaque; NvmeRequest *req = iocb->req; NvmeNamespace *ns = req->ns; BlockAcctStats *stats = blk_get_stats(ns->blkconf.blk); @@ -2582,9 +2619,6 @@ static void nvme_copy_bh(void *opaque) qemu_iovec_destroy(&iocb->iov); g_free(iocb->bounce); - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; - if (iocb->ret < 0) { block_acct_failed(stats, &iocb->acct.read); block_acct_failed(stats, &iocb->acct.write); @@ -2597,7 +2631,7 @@ static void nvme_copy_bh(void *opaque) qemu_aio_unref(iocb); } -static void nvme_copy_cb(void *opaque, int ret); +static void nvme_do_copy(NvmeCopyAIOCB *iocb); static void nvme_copy_source_range_parse_format0(void *ranges, int idx, uint64_t *slba, uint32_t *nlb, @@ -2709,7 +2743,7 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret) iocb->idx++; iocb->slba += nlb; out: - nvme_copy_cb(iocb, iocb->ret); + nvme_do_copy(iocb); } static void nvme_copy_out_cb(void *opaque, int ret) @@ -2721,18 +2755,10 @@ static void nvme_copy_out_cb(void *opaque, int ret) size_t mlen; uint8_t *mbounce; - if (ret < 0) { - iocb->ret = ret; - goto out; - } else if (iocb->ret < 0) { + if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) { goto out; } - if (!ns->lbaf.ms) { - nvme_copy_out_completed_cb(iocb, 0); - return; - } - nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL, &nlb, NULL, NULL, NULL); @@ -2749,7 +2775,7 @@ static void nvme_copy_out_cb(void *opaque, int ret) return; out: - nvme_copy_cb(iocb, ret); + nvme_copy_out_completed_cb(iocb, ret); } static void nvme_copy_in_completed_cb(void *opaque, int ret) @@ -2786,6 +2812,10 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret) size_t mlen = nvme_m2b(ns, nlb); uint8_t *mbounce = iocb->bounce + nvme_l2b(ns, nlb); + status = nvme_dif_mangle_mdata(ns, mbounce, mlen, slba); + if (status) { + goto invalid; + } status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen, prinfor, slba, apptag, appmask, &reftag); if (status) { @@ -2839,15 +2869,9 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret) invalid: req->status = status; - iocb->aiocb = NULL; - if (iocb->bh) { - qemu_bh_schedule(iocb->bh); - } - - return; - + iocb->ret = -1; out: - nvme_copy_cb(iocb, ret); + nvme_do_copy(iocb); } static void nvme_copy_in_cb(void *opaque, int ret) @@ -2858,18 +2882,10 @@ static void nvme_copy_in_cb(void *opaque, int ret) uint64_t slba; uint32_t nlb; - if (ret < 0) { - iocb->ret = ret; - goto out; - } else if (iocb->ret < 0) { + if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) { goto out; } - if (!ns->lbaf.ms) { - nvme_copy_in_completed_cb(iocb, 0); - return; - } - nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba, &nlb, NULL, NULL, NULL); @@ -2883,12 +2899,11 @@ static void nvme_copy_in_cb(void *opaque, int ret) return; out: - nvme_copy_cb(iocb, iocb->ret); + nvme_copy_in_completed_cb(iocb, ret); } -static void nvme_copy_cb(void *opaque, int ret) +static void nvme_do_copy(NvmeCopyAIOCB *iocb) { - NvmeCopyAIOCB *iocb = opaque; NvmeRequest *req = iocb->req; NvmeNamespace *ns = req->ns; uint64_t slba; @@ -2896,10 +2911,7 @@ static void nvme_copy_cb(void *opaque, int ret) size_t len; uint16_t status; - if (ret < 0) { - iocb->ret = ret; - goto done; - } else if (iocb->ret < 0) { + if (iocb->ret < 0) { goto done; } @@ -2946,14 +2958,11 @@ static void nvme_copy_cb(void *opaque, int ret) invalid: req->status = status; + iocb->ret = -1; done: - iocb->aiocb = NULL; - if (iocb->bh) { - qemu_bh_schedule(iocb->bh); - } + nvme_copy_done(iocb); } - static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns = req->ns; @@ -2990,7 +2999,8 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) goto invalid; } - if (ns->pif && format != 0x1) { + if ((ns->pif == 0x0 && format != 0x0) || + (ns->pif != 0x0 && format != 0x1)) { status = NVME_INVALID_FORMAT | NVME_DNR; goto invalid; } @@ -3022,7 +3032,6 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) } iocb->req = req; - iocb->bh = qemu_bh_new(nvme_copy_bh, iocb); iocb->ret = 0; iocb->nr = nr; iocb->idx = 0; @@ -3039,7 +3048,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) BLOCK_ACCT_WRITE); req->aiocb = &iocb->common; - nvme_copy_cb(iocb, 0); + nvme_do_copy(iocb); return NVME_NO_COMPLETE; @@ -3115,7 +3124,6 @@ typedef struct NvmeFlushAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; NvmeRequest *req; - QEMUBH *bh; int ret; NvmeNamespace *ns; @@ -3131,6 +3139,7 @@ static void nvme_flush_cancel(BlockAIOCB *acb) if (iocb->aiocb) { blk_aio_cancel_async(iocb->aiocb); + iocb->aiocb = NULL; } } @@ -3140,6 +3149,8 @@ static const AIOCBInfo nvme_flush_aiocb_info = { .get_aio_context = nvme_get_aio_context, }; +static void nvme_do_flush(NvmeFlushAIOCB *iocb); + static void nvme_flush_ns_cb(void *opaque, int ret) { NvmeFlushAIOCB *iocb = opaque; @@ -3161,13 +3172,11 @@ static void nvme_flush_ns_cb(void *opaque, int ret) } out: - iocb->aiocb = NULL; - qemu_bh_schedule(iocb->bh); + nvme_do_flush(iocb); } -static void nvme_flush_bh(void *opaque) +static void nvme_do_flush(NvmeFlushAIOCB *iocb) { - NvmeFlushAIOCB *iocb = opaque; NvmeRequest *req = iocb->req; NvmeCtrl *n = nvme_ctrl(req); int i; @@ -3194,14 +3203,8 @@ static void nvme_flush_bh(void *opaque) return; done: - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; - iocb->common.cb(iocb->common.opaque, iocb->ret); - qemu_aio_unref(iocb); - - return; } static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) @@ -3213,7 +3216,6 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) iocb = qemu_aio_get(&nvme_flush_aiocb_info, NULL, nvme_misc_cb, req); iocb->req = req; - iocb->bh = qemu_bh_new(nvme_flush_bh, iocb); iocb->ret = 0; iocb->ns = NULL; iocb->nsid = 0; @@ -3235,13 +3237,11 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) } req->aiocb = &iocb->common; - qemu_bh_schedule(iocb->bh); + nvme_do_flush(iocb); return NVME_NO_COMPLETE; out: - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; qemu_aio_unref(iocb); return status; @@ -3676,7 +3676,6 @@ typedef struct NvmeZoneResetAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; NvmeRequest *req; - QEMUBH *bh; int ret; bool all; @@ -3705,17 +3704,6 @@ static const AIOCBInfo nvme_zone_reset_aiocb_info = { .cancel_async = nvme_zone_reset_cancel, }; -static void nvme_zone_reset_bh(void *opaque) -{ - NvmeZoneResetAIOCB *iocb = opaque; - - iocb->common.cb(iocb->common.opaque, iocb->ret); - - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; - qemu_aio_unref(iocb); -} - static void nvme_zone_reset_cb(void *opaque, int ret); static void nvme_zone_reset_epilogue_cb(void *opaque, int ret) @@ -3726,14 +3714,8 @@ static void nvme_zone_reset_epilogue_cb(void *opaque, int ret) int64_t moff; int count; - if (ret < 0) { - nvme_zone_reset_cb(iocb, ret); - return; - } - - if (!ns->lbaf.ms) { - nvme_zone_reset_cb(iocb, 0); - return; + if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) { + goto out; } moff = nvme_moff(ns, iocb->zone->d.zslba); @@ -3743,6 +3725,9 @@ static void nvme_zone_reset_epilogue_cb(void *opaque, int ret) BDRV_REQ_MAY_UNMAP, nvme_zone_reset_cb, iocb); return; + +out: + nvme_zone_reset_cb(iocb, ret); } static void nvme_zone_reset_cb(void *opaque, int ret) @@ -3751,7 +3736,9 @@ static void nvme_zone_reset_cb(void *opaque, int ret) NvmeRequest *req = iocb->req; NvmeNamespace *ns = req->ns; - if (ret < 0) { + if (iocb->ret < 0) { + goto done; + } else if (ret < 0) { iocb->ret = ret; goto done; } @@ -3799,9 +3786,9 @@ static void nvme_zone_reset_cb(void *opaque, int ret) done: iocb->aiocb = NULL; - if (iocb->bh) { - qemu_bh_schedule(iocb->bh); - } + + iocb->common.cb(iocb->common.opaque, iocb->ret); + qemu_aio_unref(iocb); } static uint16_t nvme_zone_mgmt_send_zrwa_flush(NvmeCtrl *n, NvmeZone *zone, @@ -3906,7 +3893,6 @@ static uint16_t nvme_zone_mgmt_send(NvmeCtrl *n, NvmeRequest *req) nvme_misc_cb, req); iocb->req = req; - iocb->bh = qemu_bh_new(nvme_zone_reset_bh, iocb); iocb->ret = 0; iocb->all = all; iocb->idx = zone_idx; @@ -4059,14 +4045,14 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) nr_zones++; } } - header = (NvmeZoneReportHeader *)buf; + header = buf; header->nr_zones = cpu_to_le64(nr_zones); buf_p = buf + sizeof(NvmeZoneReportHeader); for (; zone_idx < ns->num_zones && max_zones > 0; zone_idx++) { zone = &ns->zone_array[zone_idx]; if (nvme_zone_matches_filter(zrasf, zone)) { - z = (NvmeZoneDescr *)buf_p; + z = buf_p; buf_p += sizeof(NvmeZoneDescr); z->zt = zone->d.zt; @@ -4183,10 +4169,87 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_OPCODE | NVME_DNR; } +static void nvme_cq_notifier(EventNotifier *e) +{ + NvmeCQueue *cq = container_of(e, NvmeCQueue, notifier); + NvmeCtrl *n = cq->ctrl; + + if (!event_notifier_test_and_clear(e)) { + return; + } + + nvme_update_cq_head(cq); + + if (cq->tail == cq->head) { + if (cq->irq_enabled) { + n->cq_pending--; + } + + nvme_irq_deassert(n, cq); + } + + qemu_bh_schedule(cq->bh); +} + +static int nvme_init_cq_ioeventfd(NvmeCQueue *cq) +{ + NvmeCtrl *n = cq->ctrl; + uint16_t offset = (cq->cqid << 3) + (1 << 2); + int ret; + + ret = event_notifier_init(&cq->notifier, 0); + if (ret < 0) { + return ret; + } + + event_notifier_set_handler(&cq->notifier, nvme_cq_notifier); + memory_region_add_eventfd(&n->iomem, + 0x1000 + offset, 4, false, 0, &cq->notifier); + + return 0; +} + +static void nvme_sq_notifier(EventNotifier *e) +{ + NvmeSQueue *sq = container_of(e, NvmeSQueue, notifier); + + if (!event_notifier_test_and_clear(e)) { + return; + } + + nvme_process_sq(sq); +} + +static int nvme_init_sq_ioeventfd(NvmeSQueue *sq) +{ + NvmeCtrl *n = sq->ctrl; + uint16_t offset = sq->sqid << 3; + int ret; + + ret = event_notifier_init(&sq->notifier, 0); + if (ret < 0) { + return ret; + } + + event_notifier_set_handler(&sq->notifier, nvme_sq_notifier); + memory_region_add_eventfd(&n->iomem, + 0x1000 + offset, 4, false, 0, &sq->notifier); + + return 0; +} + static void nvme_free_sq(NvmeSQueue *sq, NvmeCtrl *n) { + uint16_t offset = sq->sqid << 3; + n->sq[sq->sqid] = NULL; - timer_free(sq->timer); + qemu_bh_delete(sq->bh); + 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); if (sq->sqid) { g_free(sq); @@ -4254,7 +4317,19 @@ static void nvme_init_sq(NvmeSQueue *sq, NvmeCtrl *n, uint64_t dma_addr, sq->io_req[i].sq = sq; QTAILQ_INSERT_TAIL(&(sq->req_list), &sq->io_req[i], entry); } - sq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_process_sq, sq); + + sq->bh = qemu_bh_new(nvme_process_sq, sq); + + if (n->dbbuf_enabled) { + sq->db_addr = n->dbbuf_dbs + (sqid << 3); + sq->ei_addr = n->dbbuf_eis + (sqid << 3); + + if (n->params.ioeventfd && sq->sqid != 0) { + if (!nvme_init_sq_ioeventfd(sq)) { + sq->ioeventfd_enabled = true; + } + } + } assert(n->cq[cqid]); cq = n->cq[cqid]; @@ -4279,8 +4354,7 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_err_invalid_create_sq_cqid(cqid); return NVME_INVALID_CQID | NVME_DNR; } - if (unlikely(!sqid || sqid > n->params.max_ioqpairs || - n->sq[sqid] != NULL)) { + if (unlikely(!sqid || sqid > n->conf_ioqpairs || n->sq[sqid] != NULL)) { trace_pci_nvme_err_invalid_create_sq_sqid(sqid); return NVME_INVALID_QID | NVME_DNR; } @@ -4558,10 +4632,19 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req) static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n) { + PCIDevice *pci = PCI_DEVICE(n); + uint16_t offset = (cq->cqid << 3) + (1 << 2); + n->cq[cq->cqid] = NULL; - timer_free(cq->timer); - if (msix_enabled(&n->parent_obj)) { - msix_vector_unuse(&n->parent_obj, cq->vector); + qemu_bh_delete(cq->bh); + 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(pci)) { + msix_vector_unuse(pci, cq->vector); } if (cq->cqid) { g_free(cq); @@ -4599,11 +4682,10 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t irq_enabled) { - int ret; + PCIDevice *pci = PCI_DEVICE(n); - if (msix_enabled(&n->parent_obj)) { - ret = msix_vector_use(&n->parent_obj, vector); - assert(ret == 0); + if (msix_enabled(pci)) { + msix_vector_use(pci, vector); } cq->ctrl = n; cq->cqid = cqid; @@ -4615,8 +4697,18 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr, cq->head = cq->tail = 0; QTAILQ_INIT(&cq->req_list); QTAILQ_INIT(&cq->sq_list); + if (n->dbbuf_enabled) { + cq->db_addr = n->dbbuf_dbs + (cqid << 3) + (1 << 2); + cq->ei_addr = n->dbbuf_eis + (cqid << 3) + (1 << 2); + + if (n->params.ioeventfd && cqid != 0) { + if (!nvme_init_cq_ioeventfd(cq)) { + cq->ioeventfd_enabled = true; + } + } + } n->cq[cqid] = cq; - cq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_post_cqes, cq); + cq->bh = qemu_bh_new(nvme_post_cqes, cq); } static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeRequest *req) @@ -4632,8 +4724,7 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_create_cq(prp1, cqid, vector, qsize, qflags, NVME_CQ_FLAGS_IEN(qflags) != 0); - if (unlikely(!cqid || cqid > n->params.max_ioqpairs || - n->cq[cqid] != NULL)) { + if (unlikely(!cqid || cqid > n->conf_ioqpairs || n->cq[cqid] != NULL)) { trace_pci_nvme_err_invalid_create_cq_cqid(cqid); return NVME_INVALID_QID | NVME_DNR; } @@ -4645,11 +4736,11 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_err_invalid_create_cq_addr(prp1); return NVME_INVALID_PRP_OFFSET | NVME_DNR; } - if (unlikely(!msix_enabled(&n->parent_obj) && vector)) { + if (unlikely(!msix_enabled(PCI_DEVICE(n)) && vector)) { trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } - if (unlikely(vector >= n->params.msix_qsize)) { + if (unlikely(vector >= n->conf_msix_qsize)) { trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } @@ -4788,6 +4879,37 @@ static uint16_t nvme_identify_ctrl_list(NvmeCtrl *n, NvmeRequest *req, return nvme_c2h(n, (uint8_t *)list, sizeof(list), req); } +static uint16_t nvme_identify_pri_ctrl_cap(NvmeCtrl *n, NvmeRequest *req) +{ + trace_pci_nvme_identify_pri_ctrl_cap(le16_to_cpu(n->pri_ctrl_cap.cntlid)); + + return nvme_c2h(n, (uint8_t *)&n->pri_ctrl_cap, + sizeof(NvmePriCtrlCap), req); +} + +static uint16_t nvme_identify_sec_ctrl_list(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeIdentify *c = (NvmeIdentify *)&req->cmd; + uint16_t pri_ctrl_id = le16_to_cpu(n->pri_ctrl_cap.cntlid); + uint16_t min_id = le16_to_cpu(c->ctrlid); + uint8_t num_sec_ctrl = n->sec_ctrl_list.numcntl; + NvmeSecCtrlList list = {0}; + uint8_t i; + + for (i = 0; i < num_sec_ctrl; i++) { + if (n->sec_ctrl_list.sec[i].scid >= min_id) { + list.numcntl = num_sec_ctrl - i; + memcpy(&list.sec, n->sec_ctrl_list.sec + i, + list.numcntl * sizeof(NvmeSecCtrlEntry)); + break; + } + } + + trace_pci_nvme_identify_sec_ctrl_list(pri_ctrl_id, list.numcntl); + + return nvme_c2h(n, (uint8_t *)&list, sizeof(list), req); +} + static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req, bool active) { @@ -4950,16 +5072,13 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_FIELD | NVME_DNR; } - /* - * If the EUI-64 field is 0 and the NGUID field is 0, the namespace must - * provide a valid Namespace UUID in the Namespace Identification Descriptor - * data structure. QEMU does not yet support setting NGUID. - */ - uuid.hdr.nidt = NVME_NIDT_UUID; - uuid.hdr.nidl = NVME_NIDL_UUID; - memcpy(uuid.v, ns->params.uuid.data, NVME_NIDL_UUID); - memcpy(pos, &uuid, sizeof(uuid)); - pos += sizeof(uuid); + if (!qemu_uuid_is_null(&ns->params.uuid)) { + uuid.hdr.nidt = NVME_NIDT_UUID; + uuid.hdr.nidl = NVME_NIDL_UUID; + memcpy(uuid.v, ns->params.uuid.data, NVME_NIDL_UUID); + memcpy(pos, &uuid, sizeof(uuid)); + pos += sizeof(uuid); + } if (ns->params.eui64) { eui64.hdr.nidt = NVME_NIDT_EUI64; @@ -5007,6 +5126,10 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeRequest *req) return nvme_identify_ctrl_list(n, req, true); case NVME_ID_CNS_CTRL_LIST: return nvme_identify_ctrl_list(n, req, false); + case NVME_ID_CNS_PRIMARY_CTRL_CAP: + return nvme_identify_pri_ctrl_cap(n, req); + case NVME_ID_CNS_SECONDARY_CTRL_LIST: + return nvme_identify_sec_ctrl_list(n, req); case NVME_ID_CNS_CS_NS: return nvme_identify_ns_csi(n, req, true); case NVME_ID_CNS_CS_NS_PRESENT: @@ -5215,13 +5338,12 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) break; case NVME_NUMBER_OF_QUEUES: - result = (n->params.max_ioqpairs - 1) | - ((n->params.max_ioqpairs - 1) << 16); + result = (n->conf_ioqpairs - 1) | ((n->conf_ioqpairs - 1) << 16); trace_pci_nvme_getfeat_numq(result); break; case NVME_INTERRUPT_VECTOR_CONF: iv = dw11 & 0xffff; - if (iv >= n->params.max_ioqpairs + 1) { + if (iv >= n->conf_ioqpairs + 1) { return NVME_INVALID_FIELD | NVME_DNR; } @@ -5320,7 +5442,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) if ((n->temperature >= n->features.temp_thresh_hi) || (n->temperature <= n->features.temp_thresh_low)) { - nvme_smart_event(n, NVME_AER_INFO_SMART_TEMP_THRESH); + nvme_smart_event(n, NVME_SMART_TEMPERATURE); } break; @@ -5377,10 +5499,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_setfeat_numq((dw11 & 0xffff) + 1, ((dw11 >> 16) & 0xffff) + 1, - n->params.max_ioqpairs, - n->params.max_ioqpairs); - req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) | - ((n->params.max_ioqpairs - 1) << 16)); + n->conf_ioqpairs, + n->conf_ioqpairs); + req->cqe.result = cpu_to_le32((n->conf_ioqpairs - 1) | + ((n->conf_ioqpairs - 1) << 16)); break; case NVME_ASYNCHRONOUS_EVENT_CONF: n->features.async_config = dw11; @@ -5563,7 +5685,6 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) typedef struct NvmeFormatAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; - QEMUBH *bh; NvmeRequest *req; int ret; @@ -5578,14 +5699,15 @@ typedef struct NvmeFormatAIOCB { uint8_t pil; } NvmeFormatAIOCB; -static void nvme_format_bh(void *opaque); - static void nvme_format_cancel(BlockAIOCB *aiocb) { NvmeFormatAIOCB *iocb = container_of(aiocb, NvmeFormatAIOCB, common); + iocb->ret = -ECANCELED; + if (iocb->aiocb) { blk_aio_cancel_async(iocb->aiocb); + iocb->aiocb = NULL; } } @@ -5609,13 +5731,17 @@ static void nvme_format_set(NvmeNamespace *ns, uint8_t lbaf, uint8_t mset, nvme_ns_init_format(ns); } +static void nvme_do_format(NvmeFormatAIOCB *iocb); + static void nvme_format_ns_cb(void *opaque, int ret) { NvmeFormatAIOCB *iocb = opaque; NvmeNamespace *ns = iocb->ns; int bytes; - if (ret < 0) { + if (iocb->ret < 0) { + goto done; + } else if (ret < 0) { iocb->ret = ret; goto done; } @@ -5639,8 +5765,7 @@ static void nvme_format_ns_cb(void *opaque, int ret) iocb->offset = 0; done: - iocb->aiocb = NULL; - qemu_bh_schedule(iocb->bh); + nvme_do_format(iocb); } static uint16_t nvme_format_check(NvmeNamespace *ns, uint8_t lbaf, uint8_t pi) @@ -5664,9 +5789,8 @@ static uint16_t nvme_format_check(NvmeNamespace *ns, uint8_t lbaf, uint8_t pi) return NVME_SUCCESS; } -static void nvme_format_bh(void *opaque) +static void nvme_do_format(NvmeFormatAIOCB *iocb) { - NvmeFormatAIOCB *iocb = opaque; NvmeRequest *req = iocb->req; NvmeCtrl *n = nvme_ctrl(req); uint32_t dw10 = le32_to_cpu(req->cmd.cdw10); @@ -5704,11 +5828,7 @@ static void nvme_format_bh(void *opaque) return; done: - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; - iocb->common.cb(iocb->common.opaque, iocb->ret); - qemu_aio_unref(iocb); } @@ -5727,7 +5847,6 @@ static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest *req) iocb = qemu_aio_get(&nvme_format_aiocb_info, NULL, nvme_misc_cb, req); iocb->req = req; - iocb->bh = qemu_bh_new(nvme_format_bh, iocb); iocb->ret = 0; iocb->ns = NULL; iocb->nsid = 0; @@ -5756,17 +5875,235 @@ static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest *req) } req->aiocb = &iocb->common; - qemu_bh_schedule(iocb->bh); + nvme_do_format(iocb); return NVME_NO_COMPLETE; out: - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; qemu_aio_unref(iocb); + return status; } +static void nvme_get_virt_res_num(NvmeCtrl *n, uint8_t rt, int *num_total, + int *num_prim, int *num_sec) +{ + *num_total = le32_to_cpu(rt ? + n->pri_ctrl_cap.vifrt : n->pri_ctrl_cap.vqfrt); + *num_prim = le16_to_cpu(rt ? + n->pri_ctrl_cap.virfap : n->pri_ctrl_cap.vqrfap); + *num_sec = le16_to_cpu(rt ? n->pri_ctrl_cap.virfa : n->pri_ctrl_cap.vqrfa); +} + +static uint16_t nvme_assign_virt_res_to_prim(NvmeCtrl *n, NvmeRequest *req, + uint16_t cntlid, uint8_t rt, + int nr) +{ + int num_total, num_prim, num_sec; + + if (cntlid != n->cntlid) { + return NVME_INVALID_CTRL_ID | NVME_DNR; + } + + nvme_get_virt_res_num(n, rt, &num_total, &num_prim, &num_sec); + + if (nr > num_total) { + return NVME_INVALID_NUM_RESOURCES | NVME_DNR; + } + + if (nr > num_total - num_sec) { + return NVME_INVALID_RESOURCE_ID | NVME_DNR; + } + + if (rt) { + n->next_pri_ctrl_cap.virfap = cpu_to_le16(nr); + } else { + n->next_pri_ctrl_cap.vqrfap = cpu_to_le16(nr); + } + + req->cqe.result = cpu_to_le32(nr); + return req->status; +} + +static void nvme_update_virt_res(NvmeCtrl *n, NvmeSecCtrlEntry *sctrl, + uint8_t rt, int nr) +{ + int prev_nr, prev_total; + + if (rt) { + prev_nr = le16_to_cpu(sctrl->nvi); + prev_total = le32_to_cpu(n->pri_ctrl_cap.virfa); + sctrl->nvi = cpu_to_le16(nr); + n->pri_ctrl_cap.virfa = cpu_to_le32(prev_total + nr - prev_nr); + } else { + prev_nr = le16_to_cpu(sctrl->nvq); + prev_total = le32_to_cpu(n->pri_ctrl_cap.vqrfa); + sctrl->nvq = cpu_to_le16(nr); + n->pri_ctrl_cap.vqrfa = cpu_to_le32(prev_total + nr - prev_nr); + } +} + +static uint16_t nvme_assign_virt_res_to_sec(NvmeCtrl *n, NvmeRequest *req, + uint16_t cntlid, uint8_t rt, int nr) +{ + int num_total, num_prim, num_sec, num_free, diff, limit; + NvmeSecCtrlEntry *sctrl; + + sctrl = nvme_sctrl_for_cntlid(n, cntlid); + if (!sctrl) { + return NVME_INVALID_CTRL_ID | NVME_DNR; + } + + if (sctrl->scs) { + return NVME_INVALID_SEC_CTRL_STATE | NVME_DNR; + } + + limit = le16_to_cpu(rt ? n->pri_ctrl_cap.vifrsm : n->pri_ctrl_cap.vqfrsm); + if (nr > limit) { + return NVME_INVALID_NUM_RESOURCES | NVME_DNR; + } + + nvme_get_virt_res_num(n, rt, &num_total, &num_prim, &num_sec); + num_free = num_total - num_prim - num_sec; + diff = nr - le16_to_cpu(rt ? sctrl->nvi : sctrl->nvq); + + if (diff > num_free) { + return NVME_INVALID_RESOURCE_ID | NVME_DNR; + } + + nvme_update_virt_res(n, sctrl, rt, nr); + req->cqe.result = cpu_to_le32(nr); + + return req->status; +} + +static uint16_t nvme_virt_set_state(NvmeCtrl *n, uint16_t cntlid, bool online) +{ + PCIDevice *pci = PCI_DEVICE(n); + NvmeCtrl *sn = NULL; + NvmeSecCtrlEntry *sctrl; + int vf_index; + + sctrl = nvme_sctrl_for_cntlid(n, cntlid); + if (!sctrl) { + return NVME_INVALID_CTRL_ID | NVME_DNR; + } + + if (!pci_is_vf(pci)) { + vf_index = le16_to_cpu(sctrl->vfn) - 1; + sn = NVME(pcie_sriov_get_vf_at_index(pci, vf_index)); + } + + if (online) { + if (!sctrl->nvi || (le16_to_cpu(sctrl->nvq) < 2) || !sn) { + return NVME_INVALID_SEC_CTRL_STATE | NVME_DNR; + } + + if (!sctrl->scs) { + sctrl->scs = 0x1; + nvme_ctrl_reset(sn, NVME_RESET_FUNCTION); + } + } else { + nvme_update_virt_res(n, sctrl, NVME_VIRT_RES_INTERRUPT, 0); + nvme_update_virt_res(n, sctrl, NVME_VIRT_RES_QUEUE, 0); + + if (sctrl->scs) { + sctrl->scs = 0x0; + if (sn) { + nvme_ctrl_reset(sn, NVME_RESET_FUNCTION); + } + } + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_virt_mngmt(NvmeCtrl *n, NvmeRequest *req) +{ + uint32_t dw10 = le32_to_cpu(req->cmd.cdw10); + uint32_t dw11 = le32_to_cpu(req->cmd.cdw11); + uint8_t act = dw10 & 0xf; + uint8_t rt = (dw10 >> 8) & 0x7; + uint16_t cntlid = (dw10 >> 16) & 0xffff; + int nr = dw11 & 0xffff; + + trace_pci_nvme_virt_mngmt(nvme_cid(req), act, cntlid, rt ? "VI" : "VQ", nr); + + if (rt != NVME_VIRT_RES_QUEUE && rt != NVME_VIRT_RES_INTERRUPT) { + return NVME_INVALID_RESOURCE_ID | NVME_DNR; + } + + switch (act) { + case NVME_VIRT_MNGMT_ACTION_SEC_ASSIGN: + return nvme_assign_virt_res_to_sec(n, req, cntlid, rt, nr); + case NVME_VIRT_MNGMT_ACTION_PRM_ALLOC: + return nvme_assign_virt_res_to_prim(n, req, cntlid, rt, nr); + case NVME_VIRT_MNGMT_ACTION_SEC_ONLINE: + return nvme_virt_set_state(n, cntlid, true); + case NVME_VIRT_MNGMT_ACTION_SEC_OFFLINE: + return nvme_virt_set_state(n, cntlid, false); + default: + return NVME_INVALID_FIELD | NVME_DNR; + } +} + +static uint16_t nvme_dbbuf_config(NvmeCtrl *n, const NvmeRequest *req) +{ + PCIDevice *pci = PCI_DEVICE(n); + uint64_t dbs_addr = le64_to_cpu(req->cmd.dptr.prp1); + uint64_t eis_addr = le64_to_cpu(req->cmd.dptr.prp2); + int i; + + /* Address should be page aligned */ + if (dbs_addr & (n->page_size - 1) || eis_addr & (n->page_size - 1)) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + /* Save shadow buffer base addr for use during queue creation */ + n->dbbuf_dbs = dbs_addr; + n->dbbuf_eis = eis_addr; + n->dbbuf_enabled = true; + + for (i = 0; i < n->params.max_ioqpairs + 1; i++) { + NvmeSQueue *sq = n->sq[i]; + NvmeCQueue *cq = n->cq[i]; + + if (sq) { + /* + * CAP.DSTRD is 0, so offset of ith sq db_addr is (i<<3) + * nvme_process_db() uses this hard-coded way to calculate + * doorbell offsets. Be consistent with that here. + */ + sq->db_addr = dbs_addr + (i << 3); + sq->ei_addr = eis_addr + (i << 3); + pci_dma_write(pci, sq->db_addr, &sq->tail, sizeof(sq->tail)); + + if (n->params.ioeventfd && sq->sqid != 0) { + if (!nvme_init_sq_ioeventfd(sq)) { + sq->ioeventfd_enabled = true; + } + } + } + + if (cq) { + /* CAP.DSTRD is 0, so offset of ith cq db_addr is (i<<3)+(1<<2) */ + cq->db_addr = dbs_addr + (i << 3) + (1 << 2); + cq->ei_addr = eis_addr + (i << 3) + (1 << 2); + pci_dma_write(pci, cq->db_addr, &cq->head, sizeof(cq->head)); + + if (n->params.ioeventfd && cq->cqid != 0) { + if (!nvme_init_cq_ioeventfd(cq)) { + cq->ioeventfd_enabled = true; + } + } + } + } + + trace_pci_nvme_dbbuf_config(dbs_addr, eis_addr); + + return NVME_SUCCESS; +} + static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req) { trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode, @@ -5809,6 +6146,10 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req) return nvme_aer(n, req); case NVME_ADM_CMD_NS_ATTACHMENT: return nvme_ns_attachment(n, req); + case NVME_ADM_CMD_VIRT_MNGMT: + return nvme_virt_mngmt(n, req); + case NVME_ADM_CMD_DBBUF_CONFIG: + return nvme_dbbuf_config(n, req); case NVME_ADM_CMD_FORMAT_NVM: return nvme_format(n, req); default: @@ -5818,6 +6159,26 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_OPCODE | NVME_DNR; } +static void nvme_update_sq_eventidx(const NvmeSQueue *sq) +{ + uint32_t v = cpu_to_le32(sq->tail); + + trace_pci_nvme_update_sq_eventidx(sq->sqid, sq->tail); + + pci_dma_write(PCI_DEVICE(sq->ctrl), sq->ei_addr, &v, sizeof(v)); +} + +static void nvme_update_sq_tail(NvmeSQueue *sq) +{ + uint32_t v; + + pci_dma_read(PCI_DEVICE(sq->ctrl), sq->db_addr, &v, sizeof(v)); + + sq->tail = le32_to_cpu(v); + + trace_pci_nvme_update_sq_tail(sq->sqid, sq->tail); +} + static void nvme_process_sq(void *opaque) { NvmeSQueue *sq = opaque; @@ -5829,6 +6190,10 @@ static void nvme_process_sq(void *opaque) NvmeCmd cmd; NvmeRequest *req; + if (n->dbbuf_enabled) { + nvme_update_sq_tail(sq); + } + while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) { addr = sq->dma_addr + sq->head * n->sqe_size; if (nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd))) { @@ -5852,11 +6217,56 @@ static void nvme_process_sq(void *opaque) req->status = status; nvme_enqueue_req_completion(cq, req); } + + if (n->dbbuf_enabled) { + nvme_update_sq_eventidx(sq); + nvme_update_sq_tail(sq); + } + } +} + +static void nvme_update_msixcap_ts(PCIDevice *pci_dev, uint32_t table_size) +{ + uint8_t *config; + + if (!msix_present(pci_dev)) { + return; + } + + assert(table_size > 0 && table_size <= pci_dev->msix_entries_nr); + + config = pci_dev->config + pci_dev->msix_cap; + pci_set_word_by_mask(config + PCI_MSIX_FLAGS, PCI_MSIX_FLAGS_QSIZE, + table_size - 1); +} + +static void nvme_activate_virt_res(NvmeCtrl *n) +{ + PCIDevice *pci_dev = PCI_DEVICE(n); + NvmePriCtrlCap *cap = &n->pri_ctrl_cap; + NvmeSecCtrlEntry *sctrl; + + /* -1 to account for the admin queue */ + if (pci_is_vf(pci_dev)) { + sctrl = nvme_sctrl(n); + cap->vqprt = sctrl->nvq; + cap->viprt = sctrl->nvi; + n->conf_ioqpairs = sctrl->nvq ? le16_to_cpu(sctrl->nvq) - 1 : 0; + n->conf_msix_qsize = sctrl->nvi ? le16_to_cpu(sctrl->nvi) : 1; + } else { + cap->vqrfap = n->next_pri_ctrl_cap.vqrfap; + cap->virfap = n->next_pri_ctrl_cap.virfap; + n->conf_ioqpairs = le16_to_cpu(cap->vqprt) + + le16_to_cpu(cap->vqrfap) - 1; + n->conf_msix_qsize = le16_to_cpu(cap->viprt) + + le16_to_cpu(cap->virfap); } } -static void nvme_ctrl_reset(NvmeCtrl *n) +static void nvme_ctrl_reset(NvmeCtrl *n, NvmeResetType rst) { + PCIDevice *pci_dev = PCI_DEVICE(n); + NvmeSecCtrlEntry *sctrl; NvmeNamespace *ns; int i; @@ -5886,9 +6296,45 @@ static void nvme_ctrl_reset(NvmeCtrl *n) g_free(event); } + if (n->params.sriov_max_vfs) { + if (!pci_is_vf(pci_dev)) { + for (i = 0; i < n->sec_ctrl_list.numcntl; i++) { + sctrl = &n->sec_ctrl_list.sec[i]; + nvme_virt_set_state(n, le16_to_cpu(sctrl->scid), false); + } + + if (rst != NVME_RESET_CONTROLLER) { + pcie_sriov_pf_disable_vfs(pci_dev); + } + } + + if (rst != NVME_RESET_CONTROLLER) { + nvme_activate_virt_res(n); + } + } + n->aer_queued = 0; + n->aer_mask = 0; n->outstanding_aers = 0; n->qs_created = false; + + nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize); + + if (pci_is_vf(pci_dev)) { + sctrl = nvme_sctrl(n); + + stl_le_p(&n->bar.csts, sctrl->scs ? 0 : NVME_CSTS_FAILED); + } else { + stl_le_p(&n->bar.csts, 0); + } + + stl_le_p(&n->bar.intms, 0); + stl_le_p(&n->bar.intmc, 0); + stl_le_p(&n->bar.cc, 0); + + n->dbbuf_dbs = 0; + n->dbbuf_eis = 0; + n->dbbuf_enabled = false; } static void nvme_ctrl_shutdown(NvmeCtrl *n) @@ -5934,7 +6380,15 @@ static int nvme_start_ctrl(NvmeCtrl *n) uint64_t acq = ldq_le_p(&n->bar.acq); uint32_t page_bits = NVME_CC_MPS(cc) + 12; uint32_t page_size = 1 << page_bits; + NvmeSecCtrlEntry *sctrl = nvme_sctrl(n); + if (pci_is_vf(PCI_DEVICE(n)) && !sctrl->scs) { + trace_pci_nvme_err_startfail_virt_state(le16_to_cpu(sctrl->nvi), + le16_to_cpu(sctrl->nvq), + sctrl->scs ? "ONLINE" : + "OFFLINE"); + return -1; + } if (unlikely(n->cq[0])) { trace_pci_nvme_err_startfail_cq(); return -1; @@ -6015,8 +6469,6 @@ static int nvme_start_ctrl(NvmeCtrl *n) nvme_set_timestamp(n, 0ULL); - QTAILQ_INIT(&n->aer_queue); - nvme_select_iocs(n); return 0; @@ -6045,6 +6497,7 @@ static void nvme_cmb_enable_regs(NvmeCtrl *n) static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, unsigned size) { + PCIDevice *pci = PCI_DEVICE(n); uint64_t cap = ldq_le_p(&n->bar.cap); uint32_t cc = ldl_le_p(&n->bar.cc); uint32_t intms = ldl_le_p(&n->bar.intms); @@ -6068,7 +6521,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, switch (offset) { case NVME_REG_INTMS: - if (unlikely(msix_enabled(&(n->parent_obj)))) { + if (unlikely(msix_enabled(pci))) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_intmask_with_msix, "undefined access to interrupt mask set" " when MSI-X is enabled"); @@ -6081,7 +6534,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, nvme_irq_check(n); break; case NVME_REG_INTMC: - if (unlikely(msix_enabled(&(n->parent_obj)))) { + if (unlikely(msix_enabled(pci))) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_intmask_with_msix, "undefined access to interrupt mask clr" " when MSI-X is enabled"); @@ -6094,20 +6547,21 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, nvme_irq_check(n); break; case NVME_REG_CC: + stl_le_p(&n->bar.cc, data); + trace_pci_nvme_mmio_cfg(data & 0xffffffff); - /* Windows first sends data, then sends enable bit */ - if (!NVME_CC_EN(data) && !NVME_CC_EN(cc) && - !NVME_CC_SHN(data) && !NVME_CC_SHN(cc)) - { - cc = data; + if (NVME_CC_SHN(data) && !(NVME_CC_SHN(cc))) { + trace_pci_nvme_mmio_shutdown_set(); + nvme_ctrl_shutdown(n); + csts &= ~(CSTS_SHST_MASK << CSTS_SHST_SHIFT); + csts |= NVME_CSTS_SHST_COMPLETE; + } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(cc)) { + trace_pci_nvme_mmio_shutdown_cleared(); + csts &= ~(CSTS_SHST_MASK << CSTS_SHST_SHIFT); } if (NVME_CC_EN(data) && !NVME_CC_EN(cc)) { - cc = data; - - /* flush CC since nvme_start_ctrl() needs the value */ - stl_le_p(&n->bar.cc, cc); if (unlikely(nvme_start_ctrl(n))) { trace_pci_nvme_err_startfail(); csts = NVME_CSTS_FAILED; @@ -6117,23 +6571,11 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } } else if (!NVME_CC_EN(data) && NVME_CC_EN(cc)) { trace_pci_nvme_mmio_stopped(); - nvme_ctrl_reset(n); - cc = 0; - csts &= ~NVME_CSTS_READY; - } + nvme_ctrl_reset(n, NVME_RESET_CONTROLLER); - if (NVME_CC_SHN(data) && !(NVME_CC_SHN(cc))) { - trace_pci_nvme_mmio_shutdown_set(); - nvme_ctrl_shutdown(n); - cc = data; - csts |= NVME_CSTS_SHST_COMPLETE; - } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(cc)) { - trace_pci_nvme_mmio_shutdown_cleared(); - csts &= ~NVME_CSTS_SHST_COMPLETE; - cc = data; + break; } - stl_le_p(&n->bar.cc, cc); stl_le_p(&n->bar.csts, csts); break; @@ -6317,6 +6759,12 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) return 0; } + if (pci_is_vf(PCI_DEVICE(n)) && !nvme_sctrl(n)->scs && + addr != NVME_REG_CSTS) { + trace_pci_nvme_err_ignored_mmio_vf_offline(addr, size); + return 0; + } + /* * When PMRWBM bit 1 is set then read from * from PMRSTS should ensure prior writes @@ -6332,6 +6780,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) { + PCIDevice *pci = PCI_DEVICE(n); uint32_t qid; if (unlikely(addr & ((1 << 2) - 1))) { @@ -6398,12 +6847,15 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) start_sqs = nvme_cq_full(cq) ? 1 : 0; cq->head = new_head; + if (!qid && n->dbbuf_enabled) { + pci_dma_write(pci, cq->db_addr, &cq->head, sizeof(cq->head)); + } if (start_sqs) { NvmeSQueue *sq; QTAILQ_FOREACH(sq, &cq->sq_list, entry) { - timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); + qemu_bh_schedule(sq->bh); } - timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); + qemu_bh_schedule(cq->bh); } if (cq->tail == cq->head) { @@ -6455,7 +6907,24 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) trace_pci_nvme_mmio_doorbell_sq(sq->sqid, new_tail); sq->tail = new_tail; - timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); + if (!qid && n->dbbuf_enabled) { + /* + * The spec states "the host shall also update the controller's + * corresponding doorbell property to match the value of that entry + * in the Shadow Doorbell buffer." + * + * Since this context is currently a VM trap, we can safely enforce + * the requirement from the device side in case the host is + * misbehaving. + * + * Note, we shouldn't have to do this, but various drivers + * including ones that run on Linux, are not updating Admin Queues, + * so we can't trust reading it for an appropriate sq tail. + */ + pci_dma_write(pci, sq->db_addr, &sq->tail, sizeof(sq->tail)); + } + + qemu_bh_schedule(sq->bh); } } @@ -6466,6 +6935,12 @@ static void nvme_mmio_write(void *opaque, hwaddr addr, uint64_t data, trace_pci_nvme_mmio_write(addr, data, size); + if (pci_is_vf(PCI_DEVICE(n)) && !nvme_sctrl(n)->scs && + addr != NVME_REG_CSTS) { + trace_pci_nvme_err_ignored_mmio_vf_offline(addr, size); + return; + } + if (addr < sizeof(n->bar)) { nvme_write_bar(n, addr, data, size); } else { @@ -6506,7 +6981,7 @@ static const MemoryRegionOps nvme_cmb_ops = { }, }; -static void nvme_check_constraints(NvmeCtrl *n, Error **errp) +static bool nvme_check_params(NvmeCtrl *n, Error **errp) { NvmeParams *params = &n->params; @@ -6520,38 +6995,38 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) if (n->namespace.blkconf.blk && n->subsys) { error_setg(errp, "subsystem support is unavailable with legacy " "namespace ('drive' property)"); - return; + return false; } if (params->max_ioqpairs < 1 || params->max_ioqpairs > NVME_MAX_IOQPAIRS) { error_setg(errp, "max_ioqpairs must be between 1 and %d", NVME_MAX_IOQPAIRS); - return; + return false; } if (params->msix_qsize < 1 || params->msix_qsize > PCI_MSIX_FLAGS_QSIZE + 1) { error_setg(errp, "msix_qsize must be between 1 and %d", PCI_MSIX_FLAGS_QSIZE + 1); - return; + return false; } if (!params->serial) { error_setg(errp, "serial property not set"); - return; + return false; } if (n->pmr.dev) { if (host_memory_backend_is_mapped(n->pmr.dev)) { error_setg(errp, "can't use already busy memdev: %s", object_get_canonical_path_component(OBJECT(n->pmr.dev))); - return; + return false; } if (!is_power_of_2(n->pmr.dev->size)) { error_setg(errp, "pmr backend size needs to be power of 2 in size"); - return; + return false; } host_memory_backend_set_mapped(n->pmr.dev, true); @@ -6560,26 +7035,150 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) if (n->params.zasl > n->params.mdts) { error_setg(errp, "zoned.zasl (Zone Append Size Limit) must be less " "than or equal to mdts (Maximum Data Transfer Size)"); - return; + return false; } if (!n->params.vsl) { error_setg(errp, "vsl must be non-zero"); - return; + return false; + } + + if (params->sriov_max_vfs) { + if (!n->subsys) { + error_setg(errp, "subsystem is required for the use of SR-IOV"); + return false; + } + + if (params->sriov_max_vfs > NVME_MAX_VFS) { + error_setg(errp, "sriov_max_vfs must be between 0 and %d", + NVME_MAX_VFS); + return false; + } + + if (params->cmb_size_mb) { + error_setg(errp, "CMB is not supported with SR-IOV"); + return false; + } + + if (n->pmr.dev) { + error_setg(errp, "PMR is not supported with SR-IOV"); + return false; + } + + if (!params->sriov_vq_flexible || !params->sriov_vi_flexible) { + error_setg(errp, "both sriov_vq_flexible and sriov_vi_flexible" + " must be set for the use of SR-IOV"); + return false; + } + + if (params->sriov_vq_flexible < params->sriov_max_vfs * 2) { + error_setg(errp, "sriov_vq_flexible must be greater than or equal" + " to %d (sriov_max_vfs * 2)", params->sriov_max_vfs * 2); + return false; + } + + if (params->max_ioqpairs < params->sriov_vq_flexible + 2) { + error_setg(errp, "(max_ioqpairs - sriov_vq_flexible) must be" + " greater than or equal to 2"); + return false; + } + + if (params->sriov_vi_flexible < params->sriov_max_vfs) { + error_setg(errp, "sriov_vi_flexible must be greater than or equal" + " to %d (sriov_max_vfs)", params->sriov_max_vfs); + return false; + } + + if (params->msix_qsize < params->sriov_vi_flexible + 1) { + error_setg(errp, "(msix_qsize - sriov_vi_flexible) must be" + " greater than or equal to 1"); + return false; + } + + if (params->sriov_max_vi_per_vf && + (params->sriov_max_vi_per_vf - 1) % NVME_VF_RES_GRANULARITY) { + error_setg(errp, "sriov_max_vi_per_vf must meet:" + " (sriov_max_vi_per_vf - 1) %% %d == 0 and" + " sriov_max_vi_per_vf >= 1", NVME_VF_RES_GRANULARITY); + return false; + } + + if (params->sriov_max_vq_per_vf && + (params->sriov_max_vq_per_vf < 2 || + (params->sriov_max_vq_per_vf - 1) % NVME_VF_RES_GRANULARITY)) { + error_setg(errp, "sriov_max_vq_per_vf must meet:" + " (sriov_max_vq_per_vf - 1) %% %d == 0 and" + " sriov_max_vq_per_vf >= 2", NVME_VF_RES_GRANULARITY); + return false; + } } + + return true; } static void nvme_init_state(NvmeCtrl *n) { - /* add one to max_ioqpairs to account for the admin queue pair */ - n->reg_size = pow2ceil(sizeof(NvmeBar) + - 2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE); + NvmePriCtrlCap *cap = &n->pri_ctrl_cap; + NvmeSecCtrlList *list = &n->sec_ctrl_list; + NvmeSecCtrlEntry *sctrl; + PCIDevice *pci = PCI_DEVICE(n); + uint8_t max_vfs; + int i; + + if (pci_is_vf(pci)) { + sctrl = nvme_sctrl(n); + max_vfs = 0; + n->conf_ioqpairs = sctrl->nvq ? le16_to_cpu(sctrl->nvq) - 1 : 0; + n->conf_msix_qsize = sctrl->nvi ? le16_to_cpu(sctrl->nvi) : 1; + } else { + max_vfs = n->params.sriov_max_vfs; + n->conf_ioqpairs = n->params.max_ioqpairs; + n->conf_msix_qsize = n->params.msix_qsize; + } + n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1); n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1); n->temperature = NVME_TEMPERATURE; n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING; n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1); + QTAILQ_INIT(&n->aer_queue); + + list->numcntl = cpu_to_le16(max_vfs); + for (i = 0; i < max_vfs; i++) { + sctrl = &list->sec[i]; + sctrl->pcid = cpu_to_le16(n->cntlid); + sctrl->vfn = cpu_to_le16(i + 1); + } + + cap->cntlid = cpu_to_le16(n->cntlid); + cap->crt = NVME_CRT_VQ | NVME_CRT_VI; + + if (pci_is_vf(pci)) { + cap->vqprt = cpu_to_le16(1 + n->conf_ioqpairs); + } else { + cap->vqprt = cpu_to_le16(1 + n->params.max_ioqpairs - + n->params.sriov_vq_flexible); + cap->vqfrt = cpu_to_le32(n->params.sriov_vq_flexible); + cap->vqrfap = cap->vqfrt; + cap->vqgran = cpu_to_le16(NVME_VF_RES_GRANULARITY); + cap->vqfrsm = n->params.sriov_max_vq_per_vf ? + cpu_to_le16(n->params.sriov_max_vq_per_vf) : + cap->vqfrt / MAX(max_vfs, 1); + } + + if (pci_is_vf(pci)) { + cap->viprt = cpu_to_le16(n->conf_msix_qsize); + } else { + cap->viprt = cpu_to_le16(n->params.msix_qsize - + n->params.sriov_vi_flexible); + cap->vifrt = cpu_to_le32(n->params.sriov_vi_flexible); + cap->virfap = cap->vifrt; + cap->vigran = cpu_to_le16(NVME_VF_RES_GRANULARITY); + cap->vifrsm = n->params.sriov_max_vi_per_vf ? + cpu_to_le16(n->params.sriov_max_vi_per_vf) : + cap->vifrt / MAX(max_vfs, 1); + } } static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) @@ -6624,60 +7223,129 @@ static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev) memory_region_set_enabled(&n->pmr.dev->mr, false); } -static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) +static uint64_t nvme_bar_size(unsigned total_queues, unsigned total_irqs, + unsigned *msix_table_offset, + unsigned *msix_pba_offset) { - uint8_t *pci_conf = pci_dev->config; uint64_t bar_size, msix_table_size, msix_pba_size; - unsigned msix_table_offset, msix_pba_offset; - int ret; + bar_size = sizeof(NvmeBar) + 2 * total_queues * NVME_DB_SIZE; + bar_size = QEMU_ALIGN_UP(bar_size, 4 * KiB); + + if (msix_table_offset) { + *msix_table_offset = bar_size; + } + + msix_table_size = PCI_MSIX_ENTRY_SIZE * total_irqs; + bar_size += msix_table_size; + bar_size = QEMU_ALIGN_UP(bar_size, 4 * KiB); + + if (msix_pba_offset) { + *msix_pba_offset = bar_size; + } + + msix_pba_size = QEMU_ALIGN_UP(total_irqs, 64) / 8; + bar_size += msix_pba_size; + + bar_size = pow2ceil(bar_size); + return bar_size; +} + +static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset) +{ + uint16_t vf_dev_id = n->params.use_intel_id ? + PCI_DEVICE_ID_INTEL_NVME : PCI_DEVICE_ID_REDHAT_NVME; + NvmePriCtrlCap *cap = &n->pri_ctrl_cap; + uint64_t bar_size = nvme_bar_size(le16_to_cpu(cap->vqfrsm), + le16_to_cpu(cap->vifrsm), + NULL, NULL); + + pcie_sriov_pf_init(pci_dev, offset, "nvme", vf_dev_id, + n->params.sriov_max_vfs, n->params.sriov_max_vfs, + NVME_VF_OFFSET, NVME_VF_STRIDE); + + pcie_sriov_pf_init_vf_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, bar_size); +} + +static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset) +{ Error *err = NULL; + int ret; + + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, offset, + PCI_PM_SIZEOF, &err); + if (err) { + error_report_err(err); + return ret; + } + + pci_set_word(pci_dev->config + offset + PCI_PM_PMC, + PCI_PM_CAP_VER_1_2); + pci_set_word(pci_dev->config + offset + PCI_PM_CTRL, + PCI_PM_CTRL_NO_SOFT_RESET); + pci_set_word(pci_dev->wmask + offset + PCI_PM_CTRL, + PCI_PM_CTRL_STATE_MASK); + + return 0; +} + +static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) +{ + ERRP_GUARD(); + uint8_t *pci_conf = pci_dev->config; + uint64_t bar_size; + unsigned msix_table_offset, msix_pba_offset; + int ret; pci_conf[PCI_INTERRUPT_PIN] = 1; pci_config_set_prog_interface(pci_conf, 0x2); if (n->params.use_intel_id) { pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); - pci_config_set_device_id(pci_conf, 0x5845); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_NVME); } else { pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT); pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REDHAT_NVME); } pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_EXPRESS); + nvme_add_pm_capability(pci_dev, 0x60); pcie_endpoint_cap_init(pci_dev, 0x80); + pcie_cap_flr_init(pci_dev); + if (n->params.sriov_max_vfs) { + pcie_ari_init(pci_dev, 0x100, 1); + } - bar_size = QEMU_ALIGN_UP(n->reg_size, 4 * KiB); - msix_table_offset = bar_size; - msix_table_size = PCI_MSIX_ENTRY_SIZE * n->params.msix_qsize; - - bar_size += msix_table_size; - bar_size = QEMU_ALIGN_UP(bar_size, 4 * KiB); - msix_pba_offset = bar_size; - msix_pba_size = QEMU_ALIGN_UP(n->params.msix_qsize, 64) / 8; - - bar_size += msix_pba_size; - bar_size = pow2ceil(bar_size); + /* add one to max_ioqpairs to account for the admin queue pair */ + bar_size = nvme_bar_size(n->params.max_ioqpairs + 1, n->params.msix_qsize, + &msix_table_offset, &msix_pba_offset); memory_region_init(&n->bar0, OBJECT(n), "nvme-bar0", bar_size); memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme", - n->reg_size); + msix_table_offset); memory_region_add_subregion(&n->bar0, 0, &n->iomem); - pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | - PCI_BASE_ADDRESS_MEM_TYPE_64, &n->bar0); + if (pci_is_vf(pci_dev)) { + pcie_sriov_vf_register_bar(pci_dev, 0, &n->bar0); + } else { + pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, &n->bar0); + } ret = msix_init(pci_dev, n->params.msix_qsize, &n->bar0, 0, msix_table_offset, - &n->bar0, 0, msix_pba_offset, 0, &err); - if (ret < 0) { - if (ret == -ENOTSUP) { - warn_report_err(err); - } else { - error_propagate(errp, err); - return ret; - } + &n->bar0, 0, msix_pba_offset, 0, errp); + if (ret == -ENOTSUP) { + /* report that msix is not supported, but do not error out */ + warn_report_err(*errp); + *errp = NULL; + } else if (ret < 0) { + /* propagate error to caller */ + return false; } + nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize); + if (n->params.cmb_size_mb) { nvme_init_cmb(n, pci_dev); } @@ -6686,7 +7354,11 @@ static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) nvme_init_pmr(n, pci_dev); } - return 0; + if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) { + nvme_init_sriov(n, pci_dev, 0x120); + } + + return true; } static void nvme_init_subnqn(NvmeCtrl *n) @@ -6707,11 +7379,12 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) NvmeIdCtrl *id = &n->id_ctrl; uint8_t *pci_conf = pci_dev->config; uint64_t cap = ldq_le_p(&n->bar.cap); + NvmeSecCtrlEntry *sctrl = nvme_sctrl(n); id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); - strpadcpy((char *)id->fr, sizeof(id->fr), "1.0", ' '); + strpadcpy((char *)id->fr, sizeof(id->fr), QEMU_VERSION, ' '); strpadcpy((char *)id->sn, sizeof(id->sn), n->params.serial, ' '); id->cntlid = cpu_to_le16(n->cntlid); @@ -6733,7 +7406,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->mdts = n->params.mdts; id->ver = cpu_to_le32(NVME_SPEC_VER); - id->oacs = cpu_to_le16(NVME_OACS_NS_MGMT | NVME_OACS_FORMAT); + id->oacs = + cpu_to_le16(NVME_OACS_NS_MGMT | NVME_OACS_FORMAT | NVME_OACS_DBBUF); id->cntrltype = 0x1; /* @@ -6773,8 +7447,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->vwc = NVME_VWC_NSID_BROADCAST_SUPPORT | NVME_VWC_PRESENT; id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1); - id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN | - NVME_CTRL_SGLS_BITBUCKET); + id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN); nvme_init_subnqn(n); @@ -6799,6 +7472,10 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) stl_le_p(&n->bar.vs, NVME_SPEC_VER); n->bar.intmc = n->bar.intms = 0; + + if (pci_is_vf(pci_dev) && !sctrl->scs) { + stl_le_p(&n->bar.csts, NVME_CSTS_FAILED); + } } static int nvme_init_subsys(NvmeCtrl *n, Error **errp) @@ -6834,25 +7511,30 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns) static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); + DeviceState *dev = DEVICE(pci_dev); NvmeNamespace *ns; - Error *local_err = NULL; + NvmeCtrl *pn = NVME(pcie_sriov_get_pf(pci_dev)); - nvme_check_constraints(n, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (pci_is_vf(pci_dev)) { + /* + * VFs derive settings from the parent. PF's lifespan exceeds + * that of VF's, so it's safe to share params.serial. + */ + memcpy(&n->params, &pn->params, sizeof(NvmeParams)); + n->subsys = pn->subsys; } - qbus_init(&n->bus, sizeof(NvmeBus), TYPE_NVME_BUS, - &pci_dev->qdev, n->parent_obj.qdev.id); - - nvme_init_state(n); - if (nvme_init_pci(n, pci_dev, errp)) { + if (!nvme_check_params(n, errp)) { return; } + qbus_init(&n->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id); + if (nvme_init_subsys(n, errp)) { - error_propagate(errp, local_err); + return; + } + nvme_init_state(n); + if (!nvme_init_pci(n, pci_dev, errp)) { return; } nvme_init_ctrl(n, pci_dev); @@ -6876,7 +7558,7 @@ static void nvme_exit(PCIDevice *pci_dev) NvmeNamespace *ns; int i; - nvme_ctrl_reset(n); + nvme_ctrl_reset(n, NVME_RESET_FUNCTION); if (n->subsys) { for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { @@ -6900,6 +7582,11 @@ static void nvme_exit(PCIDevice *pci_dev) if (n->pmr.dev) { host_memory_backend_set_mapped(n->pmr.dev, false); } + + if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) { + pcie_sriov_pf_exit(pci_dev); + } + msix_uninit(pci_dev, &n->bar0, &n->bar0); memory_region_del_subregion(&n->bar0, &n->iomem); } @@ -6921,9 +7608,19 @@ 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, false), DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0), DEFINE_PROP_BOOL("zoned.auto_transition", NvmeCtrl, params.auto_transition_zones, true), + DEFINE_PROP_UINT8("sriov_max_vfs", NvmeCtrl, params.sriov_max_vfs, 0), + DEFINE_PROP_UINT16("sriov_vq_flexible", NvmeCtrl, + params.sriov_vq_flexible, 0), + DEFINE_PROP_UINT16("sriov_vi_flexible", NvmeCtrl, + params.sriov_vi_flexible, 0), + DEFINE_PROP_UINT8("sriov_max_vi_per_vf", NvmeCtrl, + params.sriov_max_vi_per_vf, 0), + DEFINE_PROP_UINT8("sriov_max_vq_per_vf", NvmeCtrl, + params.sriov_max_vq_per_vf, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -6969,6 +7666,47 @@ static void nvme_set_smart_warning(Object *obj, Visitor *v, const char *name, } } +static void nvme_pci_reset(DeviceState *qdev) +{ + PCIDevice *pci_dev = PCI_DEVICE(qdev); + NvmeCtrl *n = NVME(pci_dev); + + trace_pci_nvme_pci_reset(); + nvme_ctrl_reset(n, NVME_RESET_FUNCTION); +} + +static void nvme_sriov_pre_write_ctrl(PCIDevice *dev, uint32_t address, + uint32_t val, int len) +{ + NvmeCtrl *n = NVME(dev); + NvmeSecCtrlEntry *sctrl; + uint16_t sriov_cap = dev->exp.sriov_cap; + uint32_t off = address - sriov_cap; + int i, num_vfs; + + if (!sriov_cap) { + return; + } + + if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) { + if (!(val & PCI_SRIOV_CTRL_VFE)) { + num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); + for (i = 0; i < num_vfs; i++) { + sctrl = &n->sec_ctrl_list.sec[i]; + nvme_virt_set_state(n, le16_to_cpu(sctrl->scid), false); + } + } + } +} + +static void nvme_pci_write_config(PCIDevice *dev, uint32_t address, + uint32_t val, int len) +{ + nvme_sriov_pre_write_ctrl(dev, address, val, len); + pci_default_write_config(dev, address, val, len); + pcie_cap_flr_write_config(dev, address, val, len); +} + static const VMStateDescription nvme_vmstate = { .name = "nvme", .unmigratable = 1, @@ -6980,6 +7718,7 @@ static void nvme_class_init(ObjectClass *oc, void *data) PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); pc->realize = nvme_realize; + pc->config_write = nvme_pci_write_config; pc->exit = nvme_exit; pc->class_id = PCI_CLASS_STORAGE_EXPRESS; pc->revision = 2; @@ -6988,6 +7727,7 @@ static void nvme_class_init(ObjectClass *oc, void *data) dc->desc = "Non-Volatile Memory Express"; device_class_set_props(dc, nvme_props); dc->vmsd = &nvme_vmstate; + dc->reset = nvme_pci_reset; } static void nvme_instance_init(Object *obj) diff --git a/hw/nvme/dif.c b/hw/nvme/dif.c index 62d885f83ea4..63c44c86ab55 100644 --- a/hw/nvme/dif.c +++ b/hw/nvme/dif.c @@ -26,6 +26,11 @@ uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint8_t prinfo, uint64_t slba, return NVME_INVALID_PROT_INFO | NVME_DNR; } + if ((NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) == NVME_ID_NS_DPS_TYPE_3) && + (prinfo & NVME_PRINFO_PRCHK_REF)) { + return NVME_INVALID_PROT_INFO; + } + return NVME_SUCCESS; } diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 324f53ea0cd1..62a1f97be010 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -29,7 +29,8 @@ void nvme_ns_init_format(NvmeNamespace *ns) { NvmeIdNs *id_ns = &ns->id_ns; BlockDriverInfo bdi; - int npdg, nlbas, ret; + int npdg, ret; + int64_t nlbas; ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; ns->lbasz = 1 << ns->lbaf.ds; @@ -42,7 +43,7 @@ void nvme_ns_init_format(NvmeNamespace *ns) id_ns->ncap = id_ns->nsze; id_ns->nuse = id_ns->ncap; - ns->moff = (int64_t)nlbas << ns->lbaf.ds; + ns->moff = nlbas << ns->lbaf.ds; npdg = ns->blkconf.discard_granularity / ns->lbasz; @@ -545,6 +546,8 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) int i; if (!n->subsys) { + /* If no subsys, the ns cannot be attached to more than one ctrl. */ + ns->params.shared = false; if (ns->params.detached) { error_setg(errp, "detached requires that the nvme device is " "linked to an nvme-subsys device"); @@ -596,7 +599,7 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) { NvmeCtrl *ctrl = subsys->ctrls[i]; - if (ctrl) { + if (ctrl && ctrl != SUBSYS_SLOT_RSVD) { nvme_attach_ns(ctrl, ns); } } @@ -613,7 +616,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false), DEFINE_PROP_BOOL("shared", NvmeNamespace, params.shared, true), DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), - DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid), + DEFINE_PROP_UUID_NODEFAULT("uuid", NvmeNamespace, params.uuid), DEFINE_PROP_UINT64("eui64", NvmeNamespace, params.eui64, 0), DEFINE_PROP_UINT16("ms", NvmeNamespace, params.ms, 0), DEFINE_PROP_UINT8("mset", NvmeNamespace, params.mset, 0), @@ -640,7 +643,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_SIZE("zoned.zrwas", NvmeNamespace, params.zrwas, 0), DEFINE_PROP_SIZE("zoned.zrwafg", NvmeNamespace, params.zrwafg, -1), DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default, - true), + false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 739c8b8f7962..16da27a69bfb 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -15,16 +15,16 @@ * This code is licensed under the GNU GPL v2 or later. */ -#ifndef HW_NVME_INTERNAL_H -#define HW_NVME_INTERNAL_H +#ifndef HW_NVME_NVME_H +#define HW_NVME_NVME_H #include "qemu/uuid.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/block/block.h" #include "block/nvme.h" -#define NVME_MAX_CONTROLLERS 32 +#define NVME_MAX_CONTROLLERS 256 #define NVME_MAX_NAMESPACES 256 #define NVME_EUI64_DEFAULT ((uint64_t)0x5254000000000000) @@ -43,11 +43,13 @@ typedef struct NvmeBus { #define TYPE_NVME_SUBSYS "nvme-subsys" #define NVME_SUBSYS(obj) \ OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS) +#define SUBSYS_SLOT_RSVD (void *)0xFFFF typedef struct NvmeSubsystem { DeviceState parent_obj; NvmeBus bus; uint8_t subnqn[256]; + char *serial; NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS]; NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; @@ -67,6 +69,10 @@ static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys, return NULL; } + if (subsys->ctrls[cntlid] == SUBSYS_SLOT_RSVD) { + return NULL; + } + return subsys->ctrls[cntlid]; } @@ -334,6 +340,8 @@ static inline const char *nvme_adm_opc_str(uint8_t opc) case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES"; case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ"; case NVME_ADM_CMD_NS_ATTACHMENT: return "NVME_ADM_CMD_NS_ATTACHMENT"; + case NVME_ADM_CMD_VIRT_MNGMT: return "NVME_ADM_CMD_VIRT_MNGMT"; + case NVME_ADM_CMD_DBBUF_CONFIG: return "NVME_ADM_CMD_DBBUF_CONFIG"; case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM"; default: return "NVME_ADM_CMD_UNKNOWN"; } @@ -365,7 +373,11 @@ typedef struct NvmeSQueue { uint32_t tail; uint32_t size; uint64_t dma_addr; - QEMUTimer *timer; + uint64_t db_addr; + uint64_t ei_addr; + QEMUBH *bh; + EventNotifier notifier; + bool ioeventfd_enabled; NvmeRequest *io_req; QTAILQ_HEAD(, NvmeRequest) req_list; QTAILQ_HEAD(, NvmeRequest) out_req_list; @@ -382,7 +394,11 @@ typedef struct NvmeCQueue { uint32_t vector; uint32_t size; uint64_t dma_addr; - QEMUTimer *timer; + uint64_t db_addr; + uint64_t ei_addr; + QEMUBH *bh; + EventNotifier notifier; + bool ioeventfd_enabled; QTAILQ_HEAD(, NvmeSQueue) sq_list; QTAILQ_HEAD(, NvmeRequest) req_list; } NvmeCQueue; @@ -405,6 +421,12 @@ typedef struct NvmeParams { uint8_t zasl; bool auto_transition_zones; bool legacy_cmb; + bool ioeventfd; + uint8_t sriov_max_vfs; + uint16_t sriov_vq_flexible; + uint16_t sriov_vi_flexible; + uint8_t sriov_max_vq_per_vf; + uint8_t sriov_max_vi_per_vf; } NvmeParams; typedef struct NvmeCtrl { @@ -422,7 +444,6 @@ typedef struct NvmeCtrl { uint16_t max_prp_ents; uint16_t cqe_size; uint16_t sqe_size; - uint32_t reg_size; uint32_t max_q_ents; uint8_t outstanding_aers; uint32_t irq_status; @@ -432,6 +453,11 @@ typedef struct NvmeCtrl { uint64_t starttime_ms; uint16_t temperature; uint8_t smart_critical_warning; + uint32_t conf_msix_qsize; + uint32_t conf_ioqpairs; + uint64_t dbbuf_dbs; + uint64_t dbbuf_eis; + bool dbbuf_enabled; struct { MemoryRegion mem; @@ -476,8 +502,20 @@ typedef struct NvmeCtrl { uint32_t async_config; NvmeHostBehaviorSupport hbs; } features; + + NvmePriCtrlCap pri_ctrl_cap; + NvmeSecCtrlList sec_ctrl_list; + struct { + uint16_t vqrfap; + uint16_t virfap; + } next_pri_ctrl_cap; /* These override pri_ctrl_cap after reset */ } NvmeCtrl; +typedef enum NvmeResetType { + NVME_RESET_FUNCTION = 0, + NVME_RESET_CONTROLLER = 1, +} NvmeResetType; + static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid) { if (!nsid || nsid > NVME_MAX_NAMESPACES) { @@ -510,6 +548,33 @@ static inline uint16_t nvme_cid(NvmeRequest *req) return le16_to_cpu(req->cqe.cid); } +static inline NvmeSecCtrlEntry *nvme_sctrl(NvmeCtrl *n) +{ + PCIDevice *pci_dev = &n->parent_obj; + NvmeCtrl *pf = NVME(pcie_sriov_get_pf(pci_dev)); + + if (pci_is_vf(pci_dev)) { + return &pf->sec_ctrl_list.sec[pcie_sriov_vf_number(pci_dev)]; + } + + return NULL; +} + +static inline NvmeSecCtrlEntry *nvme_sctrl_for_cntlid(NvmeCtrl *n, + uint16_t cntlid) +{ + NvmeSecCtrlList *list = &n->sec_ctrl_list; + uint8_t i; + + for (i = 0; i < list->numcntl; i++) { + if (le16_to_cpu(list->sec[i].scid) == cntlid) { + return &list->sec[i]; + } + } + + return NULL; +} + void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns); uint16_t nvme_bounce_data(NvmeCtrl *n, void *ptr, uint32_t len, NvmeTxDirection dir, NvmeRequest *req); @@ -519,4 +584,4 @@ void nvme_rw_complete_cb(void *opaque, int ret); uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, NvmeCmd *cmd); -#endif /* HW_NVME_INTERNAL_H */ +#endif /* HW_NVME_NVME_H */ diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index fb58d639504e..9d2643678b53 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -11,19 +11,77 @@ #include "nvme.h" +static int nvme_subsys_reserve_cntlids(NvmeCtrl *n, int start, int num) +{ + NvmeSubsystem *subsys = n->subsys; + NvmeSecCtrlList *list = &n->sec_ctrl_list; + NvmeSecCtrlEntry *sctrl; + int i, cnt = 0; + + for (i = start; i < ARRAY_SIZE(subsys->ctrls) && cnt < num; i++) { + if (!subsys->ctrls[i]) { + sctrl = &list->sec[cnt]; + sctrl->scid = cpu_to_le16(i); + subsys->ctrls[i] = SUBSYS_SLOT_RSVD; + cnt++; + } + } + + return cnt; +} + +static void nvme_subsys_unreserve_cntlids(NvmeCtrl *n) +{ + NvmeSubsystem *subsys = n->subsys; + NvmeSecCtrlList *list = &n->sec_ctrl_list; + NvmeSecCtrlEntry *sctrl; + int i, cntlid; + + for (i = 0; i < n->params.sriov_max_vfs; i++) { + sctrl = &list->sec[i]; + cntlid = le16_to_cpu(sctrl->scid); + + if (cntlid) { + assert(subsys->ctrls[cntlid] == SUBSYS_SLOT_RSVD); + subsys->ctrls[cntlid] = NULL; + sctrl->scid = 0; + } + } +} + int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) { NvmeSubsystem *subsys = n->subsys; - int cntlid, nsid; + NvmeSecCtrlEntry *sctrl = nvme_sctrl(n); + int cntlid, nsid, num_rsvd, num_vfs = n->params.sriov_max_vfs; + + if (pci_is_vf(&n->parent_obj)) { + cntlid = le16_to_cpu(sctrl->scid); + } else { + for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) { + if (!subsys->ctrls[cntlid]) { + break; + } + } - for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) { - if (!subsys->ctrls[cntlid]) { - break; + if (cntlid == ARRAY_SIZE(subsys->ctrls)) { + error_setg(errp, "no more free controller id"); + return -1; + } + + num_rsvd = nvme_subsys_reserve_cntlids(n, cntlid + 1, num_vfs); + if (num_rsvd != num_vfs) { + nvme_subsys_unreserve_cntlids(n); + error_setg(errp, + "no more free controller ids for secondary controllers"); + return -1; } } - if (cntlid == ARRAY_SIZE(subsys->ctrls)) { - error_setg(errp, "no more free controller id"); + if (!subsys->serial) { + subsys->serial = g_strdup(n->params.serial); + } else if (strcmp(subsys->serial, n->params.serial)) { + error_setg(errp, "invalid controller serial"); return -1; } @@ -41,7 +99,13 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n) { - subsys->ctrls[n->cntlid] = NULL; + if (pci_is_vf(&n->parent_obj)) { + subsys->ctrls[n->cntlid] = SUBSYS_SLOT_RSVD; + } else { + subsys->ctrls[n->cntlid] = NULL; + nvme_subsys_unreserve_cntlids(n); + } + n->cntlid = -1; } diff --git a/hw/nvme/trace-events b/hw/nvme/trace-events index ff1b4589692b..b16f2260b4fd 100644 --- a/hw/nvme/trace-events +++ b/hw/nvme/trace-events @@ -3,6 +3,7 @@ pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" pci_nvme_irq_pin(void) "pulsing IRQ pin" pci_nvme_irq_masked(void) "IRQ is masked" pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" +pci_nvme_dbbuf_config(uint64_t dbs_addr, uint64_t eis_addr) "dbs_addr=0x%"PRIx64" eis_addr=0x%"PRIx64"" pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d" @@ -56,6 +57,8 @@ pci_nvme_identify_ctrl(void) "identify controller" pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8"" pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" pci_nvme_identify_ctrl_list(uint8_t cns, uint16_t cntid) "cns 0x%"PRIx8" cntid %"PRIu16"" +pci_nvme_identify_pri_ctrl_cap(uint16_t cntlid) "identify primary controller capabilities cntlid=%"PRIu16"" +pci_nvme_identify_sec_ctrl_list(uint16_t cntlid, uint8_t numcntl) "identify secondary controller list cntlid=%"PRIu16" numcntl=%"PRIu8"" pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8"" pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8"" @@ -81,6 +84,8 @@ pci_nvme_enqueue_event_noqueue(int queued) "queued %d" pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint32_t dw0, uint32_t dw1, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" dw0 0x%"PRIx32" dw1 0x%"PRIx32" status 0x%"PRIx16"" +pci_nvme_update_cq_eventidx(uint16_t cqid, uint16_t new_eventidx) "cqid %"PRIu16" new_eventidx %"PRIu16"" +pci_nvme_update_sq_eventidx(uint16_t sqid, uint16_t new_eventidx) "sqid %"PRIu16" new_eventidx %"PRIu16"" pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d" pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" @@ -97,6 +102,8 @@ pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" pci_nvme_mmio_stopped(void) "cleared controller enable bit" pci_nvme_mmio_shutdown_set(void) "shutdown bit set" pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" +pci_nvme_update_cq_head(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" +pci_nvme_update_sq_tail(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16"" pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" @@ -108,6 +115,8 @@ pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_ pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state" pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state" pci_nvme_zoned_zrwa_implicit_flush(uint64_t zslba, uint32_t nlb) "zslba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_pci_reset(void) "PCI Function Level Reset" +pci_nvme_virt_mngmt(uint16_t cid, uint16_t act, uint16_t cntlid, const char* rt, uint16_t nr) "cid %"PRIu16", act=0x%"PRIx16", ctrlid=%"PRIu16" %s nr=%"PRIu16"" # error conditions pci_nvme_err_mdts(size_t len) "len %zu" @@ -177,7 +186,9 @@ pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32"" pci_nvme_err_startfail(void) "setting controller enable bit failed" +pci_nvme_err_startfail_virt_state(uint16_t vq, uint16_t vi, const char *state) "nvme_start_ctrl failed due to ctrl state: vi=%u vq=%u %s" pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8"" +pci_nvme_err_ignored_mmio_vf_offline(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d" # undefined behavior pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c index a1b9c7884402..1081e2cc0d27 100644 --- a/hw/nvram/eeprom93xx.c +++ b/hw/nvram/eeprom93xx.c @@ -315,7 +315,7 @@ eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords) addrbits = 6; } - eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2); + eeprom = g_malloc0(sizeof(*eeprom) + nwords * 2); eeprom->size = nwords; eeprom->addrbits = addrbits; /* Output DO is tristate, read results in 1. */ diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index 01a3093600fa..2d4d8b952f38 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -64,8 +64,8 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event) case I2C_START_RECV: DPRINTK("clear\n"); if (ee->blk && ee->changed) { - int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0); - if (len != ee->rsize) { + int ret = blk_pwrite(ee->blk, 0, ee->rsize, ee->mem, 0); + if (ret < 0) { ERR(TYPE_AT24C_EE " : failed to write backing file\n"); } @@ -75,6 +75,8 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event) break; case I2C_NACK: break; + default: + return -1; } return 0; } @@ -163,9 +165,9 @@ void at24c_eeprom_reset(DeviceState *state) memset(ee->mem, 0, ee->rsize); if (ee->blk) { - int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize); + int ret = blk_pread(ee->blk, 0, ee->rsize, ee->mem, 0); - if (len != ee->rsize) { + if (ret < 0) { ERR(TYPE_AT24C_EE " : Failed initial sync with backing file\n"); } diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index e5f3c981841d..a00881bc645d 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" @@ -42,6 +41,7 @@ #include "qapi/error.h" #include "hw/acpi/aml-build.h" #include "hw/pci/pci_bus.h" +#include "hw/loader.h" #define FW_CFG_FILE_SLOTS_DFLT 0x20 @@ -179,21 +179,13 @@ static char *read_splashfile(char *filename, gsize *file_sizep, static void fw_cfg_bootsplash(FWCfgState *s) { - const char *boot_splash_filename = NULL; - const char *boot_splash_time = NULL; char *filename, *file_data; gsize file_size; int file_type; - /* get user configuration */ - QemuOptsList *plist = qemu_find_opts("boot-opts"); - QemuOpts *opts = QTAILQ_FIRST(&plist->head); - boot_splash_filename = qemu_opt_get(opts, "splash"); - boot_splash_time = qemu_opt_get(opts, "splash-time"); - /* insert splash time if user configurated */ - if (boot_splash_time) { - int64_t bst_val = qemu_opt_get_number(opts, "splash-time", -1); + if (current_machine->boot_config.has_splash_time) { + int64_t bst_val = current_machine->boot_config.splash_time; uint16_t bst_le16; /* validate the input */ @@ -209,7 +201,8 @@ static void fw_cfg_bootsplash(FWCfgState *s) } /* insert splash file if user configurated */ - if (boot_splash_filename) { + if (current_machine->boot_config.splash) { + const char *boot_splash_filename = current_machine->boot_config.splash; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename); if (filename == NULL) { error_report("failed to find file '%s'", boot_splash_filename); @@ -239,17 +232,11 @@ static void fw_cfg_bootsplash(FWCfgState *s) static void fw_cfg_reboot(FWCfgState *s) { - const char *reboot_timeout = NULL; uint64_t rt_val = -1; uint32_t rt_le32; - /* get user configuration */ - QemuOptsList *plist = qemu_find_opts("boot-opts"); - QemuOpts *opts = QTAILQ_FIRST(&plist->head); - reboot_timeout = qemu_opt_get(opts, "reboot-timeout"); - - if (reboot_timeout) { - rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1); + if (current_machine->boot_config.has_reboot_timeout) { + rt_val = current_machine->boot_config.reboot_timeout; /* validate the input */ if (rt_val > 0xffff && rt_val != (uint64_t)-1) { @@ -622,9 +609,9 @@ static bool fw_cfg_acpi_mr_restore(void *opaque) FWCfgState *s = opaque; bool mr_aligned; - mr_aligned = QEMU_IS_ALIGNED(s->table_mr_size, qemu_real_host_page_size) && - QEMU_IS_ALIGNED(s->linker_mr_size, qemu_real_host_page_size) && - QEMU_IS_ALIGNED(s->rsdp_mr_size, qemu_real_host_page_size); + mr_aligned = QEMU_IS_ALIGNED(s->table_mr_size, qemu_real_host_page_size()) && + QEMU_IS_ALIGNED(s->linker_mr_size, qemu_real_host_page_size()) && + QEMU_IS_ALIGNED(s->rsdp_mr_size, qemu_real_host_page_size()); return s->acpi_mr_restore && !mr_aligned; } @@ -706,12 +693,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); @@ -1134,7 +1121,7 @@ static void fw_cfg_common_realize(DeviceState *dev, Error **errp) fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics); - fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); + fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)(machine->boot_config.has_menu && machine->boot_config.menu)); fw_cfg_bootsplash(s); fw_cfg_reboot(s); @@ -1235,6 +1222,37 @@ FWCfgState *fw_cfg_find(void) return FW_CFG(object_resolve_path_type("", TYPE_FW_CFG, NULL)); } +void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, + uint16_t data_key, const char *image_name, + bool try_decompress) +{ + size_t size = -1; + uint8_t *data; + + if (image_name == NULL) { + return; + } + + if (try_decompress) { + size = load_image_gzipped_buffer(image_name, + LOAD_IMAGE_MAX_GUNZIP_BYTES, &data); + } + + if (size == (size_t)-1) { + gchar *contents; + gsize length; + + if (!g_file_get_contents(image_name, &contents, &length, NULL)) { + error_report("failed to load \"%s\"", image_name); + exit(1); + } + size = length; + data = (uint8_t *)contents; + } + + fw_cfg_add_i32(fw_cfg, size_key, size); + fw_cfg_add_bytes(fw_cfg, data_key, data, size); +} static void fw_cfg_class_init(ObjectClass *klass, void *data) { diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 11f2d31cdb20..3d9ddda21732 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "hw/nvram/chrp_nvram.h" -#include "hw/ppc/mac.h" +#include "hw/nvram/mac_nvram.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/cutils.h" diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 18b43be7f61e..2d72f304422a 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -103,7 +103,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, SpaprMachineState *spapr, { SpaprNvram *nvram = spapr->nvram; hwaddr offset, buffer, len; - int alen; + int ret; void *membuf; if ((nargs != 3) || (nret != 2)) { @@ -128,9 +128,9 @@ static void rtas_nvram_store(PowerPCCPU *cpu, SpaprMachineState *spapr, membuf = cpu_physical_memory_map(buffer, &len, false); - alen = len; + ret = 0; if (nvram->blk) { - alen = blk_pwrite(nvram->blk, offset, membuf, len, 0); + ret = blk_pwrite(nvram->blk, offset, len, membuf, 0); } assert(nvram->buf); @@ -138,8 +138,8 @@ static void rtas_nvram_store(PowerPCCPU *cpu, SpaprMachineState *spapr, cpu_physical_memory_unmap(membuf, len, 0, len); - rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); - rtas_st(rets, 1, (alen < 0) ? 0 : alen); + rtas_st(rets, 0, (ret < 0) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); + rtas_st(rets, 1, (ret < 0) ? 0 : len); } static void spapr_nvram_realize(SpaprVioDevice *dev, Error **errp) @@ -179,9 +179,9 @@ static void spapr_nvram_realize(SpaprVioDevice *dev, Error **errp) } if (nvram->blk) { - int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size); + ret = blk_pread(nvram->blk, 0, nvram->size, nvram->buf, 0); - if (alen != nvram->size) { + if (ret < 0) { error_setg(errp, "can't read spapr-nvram contents"); return; } @@ -224,7 +224,7 @@ static void postload_update_cb(void *opaque, bool running, RunState state) qemu_del_vm_change_state_handler(nvram->vmstate); nvram->vmstate = NULL; - blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size, 0); + blk_pwrite(nvram->blk, 0, nvram->size, nvram->buf, 0); } static int spapr_nvram_post_load(void *opaque, int version_id) diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c index 6ed32adad9fc..c6b484cc85b6 100644 --- a/hw/nvram/xlnx-bbram.c +++ b/hw/nvram/xlnx-bbram.c @@ -124,7 +124,7 @@ static void bbram_bdrv_read(XlnxBBRam *s, Error **errp) blk_name(s->blk)); } - if (blk_pread(s->blk, 0, ram, nr) < 0) { + if (blk_pread(s->blk, 0, nr, ram, 0) < 0) { error_setg(errp, "%s: Failed to read %u bytes from BBRAM backstore.", blk_name(s->blk), nr); @@ -159,7 +159,7 @@ static void bbram_bdrv_sync(XlnxBBRam *s, uint64_t hwaddr) } offset = hwaddr - A_BBRAM_0; - rc = blk_pwrite(s->blk, offset, &le32, 4, 0); + rc = blk_pwrite(s->blk, offset, 4, &le32, 0); if (rc < 0) { bbram_bdrv_error(s, rc, g_strdup_printf("write to offset %u", offset)); } diff --git a/hw/nvram/xlnx-efuse.c b/hw/nvram/xlnx-efuse.c index a0fd77b586dc..fdfffaab99c9 100644 --- a/hw/nvram/xlnx-efuse.c +++ b/hw/nvram/xlnx-efuse.c @@ -77,7 +77,7 @@ static int efuse_bdrv_read(XlnxEFuse *s, Error **errp) blk_name(s->blk)); } - if (blk_pread(s->blk, 0, ram, nr) < 0) { + if (blk_pread(s->blk, 0, nr, ram, 0) < 0) { error_setg(errp, "%s: Failed to read %u bytes from eFUSE backstore.", blk_name(s->blk), nr); return -1; @@ -105,7 +105,7 @@ static void efuse_bdrv_sync(XlnxEFuse *s, unsigned int bit) le32 = cpu_to_le32(xlnx_efuse_get_row(s, bit)); row_offset = (bit / 32) * 4; - if (blk_pwrite(s->blk, row_offset, &le32, 4, 0) < 0) { + if (blk_pwrite(s->blk, row_offset, 4, &le32, 0) < 0) { error_report("%s: Failed to write offset %u of eFUSE backstore.", blk_name(s->blk), row_offset); } diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba04d..97af258b5566 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 000000000000..007e80cd5a0a --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,119 @@ +/* + * 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 "sysemu/reset.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); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, + rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize)); + + return fdt_addr; +} diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d819..10163b391b26 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 ec48172c9db6..2dbc6365bb7c 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 8184caa60b88..35da123aef4c 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" @@ -71,6 +70,10 @@ enum { OR1KSIM_ETHOC_IRQ = 4, }; +enum { + OR1KSIM_UART_COUNT = 4 +}; + static const struct MemmapEntry { hwaddr base; hwaddr size; @@ -78,7 +81,7 @@ static const struct MemmapEntry { [OR1KSIM_DRAM] = { 0x00000000, 0 }, [OR1KSIM_UART] = { 0x90000000, 0x100 }, [OR1KSIM_ETHOC] = { 0x92000000, 0x800 }, - [OR1KSIM_OMPIC] = { 0x98000000, 16 }, + [OR1KSIM_OMPIC] = { 0x98000000, OR1KSIM_CPUS_MAX * 8 }, }; static struct openrisc_boot_info { @@ -239,11 +242,13 @@ static void openrisc_sim_ompic_init(Or1ksimState *state, hwaddr base, static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, hwaddr size, int num_cpus, - OpenRISCCPU *cpus[], int irq_pin) + OpenRISCCPU *cpus[], int irq_pin, + int uart_idx) { void *fdt = state->fdt; char *nodename; qemu_irq serial_irq; + char alias[sizeof("uart0")]; int i; if (num_cpus > 1) { @@ -258,7 +263,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, serial_irq = get_cpu_irq(cpus, 0, irq_pin); } serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, - serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_hd(OR1KSIM_UART_COUNT - uart_idx - 1), + DEVICE_NATIVE_ENDIAN); /* Add device tree node for serial. */ nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base); @@ -271,105 +277,11 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, /* 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); + snprintf(alias, sizeof(alias), "uart%d", uart_idx); + qemu_fdt_setprop_string(fdt, "/aliases", alias, nodename); 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 = ROUND_UP(load_start, 4); - - 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; @@ -410,21 +322,25 @@ static void openrisc_sim_init(MachineState *machine) if (smp_cpus > 1) { openrisc_sim_ompic_init(state, or1ksim_memmap[OR1KSIM_OMPIC].base, - or1ksim_memmap[OR1KSIM_UART].size, + or1ksim_memmap[OR1KSIM_OMPIC].size, smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } - openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base, - or1ksim_memmap[OR1KSIM_UART].size, smp_cpus, cpus, - OR1KSIM_UART_IRQ); + for (n = 0; n < OR1KSIM_UART_COUNT; ++n) + openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base + + or1ksim_memmap[OR1KSIM_UART].size * n, + 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 000000000000..f8a68a6a6b1f --- /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-bridge/Kconfig b/hw/pci-bridge/Kconfig index f8df4315baae..02614f49aa68 100644 --- a/hw/pci-bridge/Kconfig +++ b/hw/pci-bridge/Kconfig @@ -27,3 +27,8 @@ config DEC_PCI config SIMBA bool + +config CXL + bool + default y if PCI_EXPRESS && PXB + depends on PCI_EXPRESS && MSI_NONBROKEN && PXB diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c new file mode 100644 index 000000000000..3d4e6b59cde8 --- /dev/null +++ b/hw/pci-bridge/cxl_downstream.c @@ -0,0 +1,248 @@ +/* + * Emulated CXL Switch Downstream Port + * + * Copyright (c) 2022 Huawei Technologies. + * + * Based on xio3130_downstream.c + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/pci/pcie_port.h" +#include "qapi/error.h" + +typedef struct CXLDownStreamPort { + /*< private >*/ + PCIESlot parent_obj; + + /*< public >*/ + CXLComponentState cxl_cstate; +} CXLDownstreamPort; + +#define TYPE_CXL_DSP "cxl-downstream" +DECLARE_INSTANCE_CHECKER(CXLDownstreamPort, CXL_DSP, TYPE_CXL_DSP) + +#define CXL_DOWNSTREAM_PORT_MSI_OFFSET 0x70 +#define CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR 1 +#define CXL_DOWNSTREAM_PORT_EXP_OFFSET 0x90 +#define CXL_DOWNSTREAM_PORT_AER_OFFSET 0x100 +#define CXL_DOWNSTREAM_PORT_DVSEC_OFFSET \ + (CXL_DOWNSTREAM_PORT_AER_OFFSET + PCI_ERR_SIZEOF) + +static void latch_registers(CXLDownstreamPort *dsp) +{ + uint32_t *reg_state = dsp->cxl_cstate.crb.cache_mem_registers; + uint32_t *write_msk = dsp->cxl_cstate.crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, + CXL2_DOWNSTREAM_PORT); +} + +/* TODO: Look at sharing this code acorss all CXL port types */ +static void cxl_dsp_dvsec_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int len) +{ + CXLDownstreamPort *dsp = CXL_DSP(dev); + CXLComponentState *cxl_cstate = &dsp->cxl_cstate; + + if (range_contains(&cxl_cstate->dvsecs[EXTENSIONS_PORT_DVSEC], addr)) { + uint8_t *reg = &dev->config[addr]; + addr -= cxl_cstate->dvsecs[EXTENSIONS_PORT_DVSEC].lob; + if (addr == PORT_CONTROL_OFFSET) { + if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) { + /* unmask SBR */ + qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n"); + } + if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) { + /* Alt Memory & ID Space Enable */ + qemu_log_mask(LOG_UNIMP, + "Alt Memory & ID space is not supported\n"); + + } + } + } +} + +static void cxl_dsp_config_write(PCIDevice *d, uint32_t address, + uint32_t val, int len) +{ + uint16_t slt_ctl, slt_sta; + + pcie_cap_slot_get(d, &slt_ctl, &slt_sta); + pci_bridge_write_config(d, address, val, len); + pcie_cap_flr_write_config(d, address, val, len); + pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len); + pcie_aer_write_config(d, address, val, len); + + cxl_dsp_dvsec_write_config(d, address, val, len); +} + +static void cxl_dsp_reset(DeviceState *qdev) +{ + PCIDevice *d = PCI_DEVICE(qdev); + CXLDownstreamPort *dsp = CXL_DSP(qdev); + + pcie_cap_deverr_reset(d); + pcie_cap_slot_reset(d); + pcie_cap_arifwd_reset(d); + pci_bridge_reset(qdev); + + latch_registers(dsp); +} + +static void build_dvsecs(CXLComponentState *cxl) +{ + uint8_t *dvsec; + + dvsec = (uint8_t *)&(CXLDVSECPortExtensions){ 0 }; + cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT, + EXTENSIONS_PORT_DVSEC_LENGTH, + EXTENSIONS_PORT_DVSEC, + EXTENSIONS_PORT_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){ + .cap = 0x27, /* Cache, IO, Mem, non-MLD */ + .ctrl = 0x02, /* IO always enabled */ + .status = 0x26, /* same */ + .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */ + }; + cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT, + PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0, + PCIE_FLEXBUS_PORT_DVSEC, + PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortGPF){ + .rsvd = 0, + .phase1_ctrl = 1, /* 1μs timeout */ + .phase2_ctrl = 1, /* 1μs timeout */ + }; + cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT, + GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC, + GPF_PORT_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){ + .rsvd = 0, + .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX, + .reg0_base_hi = 0, + }; + cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT, + REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC, + REG_LOC_DVSEC_REVID, dvsec); +} + +static void cxl_dsp_realize(PCIDevice *d, Error **errp) +{ + PCIEPort *p = PCIE_PORT(d); + PCIESlot *s = PCIE_SLOT(d); + CXLDownstreamPort *dsp = CXL_DSP(d); + CXLComponentState *cxl_cstate = &dsp->cxl_cstate; + ComponentRegisters *cregs = &cxl_cstate->crb; + MemoryRegion *component_bar = &cregs->component_registers; + int rc; + + pci_bridge_initfn(d, TYPE_PCIE_BUS); + pcie_port_init_reg(d); + + rc = msi_init(d, CXL_DOWNSTREAM_PORT_MSI_OFFSET, + CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR, + true, true, errp); + if (rc) { + assert(rc == -ENOTSUP); + goto err_bridge; + } + + rc = pcie_cap_init(d, CXL_DOWNSTREAM_PORT_EXP_OFFSET, + PCI_EXP_TYPE_DOWNSTREAM, p->port, + errp); + if (rc < 0) { + goto err_msi; + } + + pcie_cap_flr_init(d); + pcie_cap_deverr_init(d); + pcie_cap_slot_init(d, s); + pcie_cap_arifwd_init(d); + + pcie_chassis_create(s->chassis); + rc = pcie_chassis_add_slot(s); + if (rc < 0) { + error_setg(errp, "Can't add chassis slot, error %d", rc); + goto err_pcie_cap; + } + + rc = pcie_aer_init(d, PCI_ERR_VER, CXL_DOWNSTREAM_PORT_AER_OFFSET, + PCI_ERR_SIZEOF, errp); + if (rc < 0) { + goto err_chassis; + } + + cxl_cstate->dvsec_offset = CXL_DOWNSTREAM_PORT_DVSEC_OFFSET; + cxl_cstate->pdev = d; + build_dvsecs(cxl_cstate); + cxl_component_register_block_init(OBJECT(d), cxl_cstate, TYPE_CXL_DSP); + pci_register_bar(d, CXL_COMPONENT_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + component_bar); + + return; + + err_chassis: + pcie_chassis_del_slot(s); + err_pcie_cap: + pcie_cap_exit(d); + err_msi: + msi_uninit(d); + err_bridge: + pci_bridge_exitfn(d); +} + +static void cxl_dsp_exitfn(PCIDevice *d) +{ + PCIESlot *s = PCIE_SLOT(d); + + pcie_aer_exit(d); + pcie_chassis_del_slot(s); + pcie_cap_exit(d); + msi_uninit(d); + pci_bridge_exitfn(d); +} + +static void cxl_dsp_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); + + k->config_write = cxl_dsp_config_write; + k->realize = cxl_dsp_realize; + k->exit = cxl_dsp_exitfn; + k->vendor_id = 0x19e5; /* Huawei */ + k->device_id = 0xa129; /* Emulated CXL Switch Downstream Port */ + k->revision = 0; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->desc = "CXL Switch Downstream Port"; + dc->reset = cxl_dsp_reset; +} + +static const TypeInfo cxl_dsp_info = { + .name = TYPE_CXL_DSP, + .instance_size = sizeof(CXLDownstreamPort), + .parent = TYPE_PCIE_SLOT, + .class_init = cxl_dsp_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CXL_DEVICE }, + { } + }, +}; + +static void cxl_dsp_register_type(void) +{ + type_register_static(&cxl_dsp_info); +} + +type_init(cxl_dsp_register_type); diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c new file mode 100644 index 000000000000..6664783974cf --- /dev/null +++ b/hw/pci-bridge/cxl_root_port.c @@ -0,0 +1,240 @@ +/* + * CXL 2.0 Root Port Implementation + * + * Copyright(C) 2020 Intel 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 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 + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/range.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pcie_port.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "qapi/error.h" +#include "hw/cxl/cxl.h" + +#define CXL_ROOT_PORT_DID 0x7075 + +/* Copied from the gen root port which we derive */ +#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 +#define GEN_PCIE_ROOT_PORT_ACS_OFFSET \ + (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF) +#define CXL_ROOT_PORT_DVSEC_OFFSET \ + (GEN_PCIE_ROOT_PORT_ACS_OFFSET + PCI_ACS_SIZEOF) + +typedef struct CXLRootPort { + /*< private >*/ + PCIESlot parent_obj; + + CXLComponentState cxl_cstate; + PCIResReserve res_reserve; +} CXLRootPort; + +#define TYPE_CXL_ROOT_PORT "cxl-rp" +DECLARE_INSTANCE_CHECKER(CXLRootPort, CXL_ROOT_PORT, TYPE_CXL_ROOT_PORT) + +static void latch_registers(CXLRootPort *crp) +{ + uint32_t *reg_state = crp->cxl_cstate.crb.cache_mem_registers; + uint32_t *write_msk = crp->cxl_cstate.crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT); +} + +static void build_dvsecs(CXLComponentState *cxl) +{ + uint8_t *dvsec; + + dvsec = (uint8_t *)&(CXLDVSECPortExtensions){ 0 }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + EXTENSIONS_PORT_DVSEC_LENGTH, + EXTENSIONS_PORT_DVSEC, + EXTENSIONS_PORT_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortGPF){ + .rsvd = 0, + .phase1_ctrl = 1, /* 1μs timeout */ + .phase2_ctrl = 1, /* 1μs timeout */ + }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC, + GPF_PORT_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){ + .cap = 0x26, /* IO, Mem, non-MLD */ + .ctrl = 0x2, + .status = 0x26, /* same */ + .rcvd_mod_ts_data_phase1 = 0xef, + }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0, + PCIE_FLEXBUS_PORT_DVSEC, + PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){ + .rsvd = 0, + .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX, + .reg0_base_hi = 0, + }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC, + REG_LOC_DVSEC_REVID, dvsec); +} + +static void cxl_rp_realize(DeviceState *dev, Error **errp) +{ + PCIDevice *pci_dev = PCI_DEVICE(dev); + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + CXLRootPort *crp = CXL_ROOT_PORT(dev); + CXLComponentState *cxl_cstate = &crp->cxl_cstate; + ComponentRegisters *cregs = &cxl_cstate->crb; + MemoryRegion *component_bar = &cregs->component_registers; + Error *local_err = NULL; + + rpc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + int rc = + pci_bridge_qemu_reserve_cap_init(pci_dev, 0, crp->res_reserve, errp); + if (rc < 0) { + rpc->parent_class.exit(pci_dev); + return; + } + + if (!crp->res_reserve.io || crp->res_reserve.io == -1) { + pci_word_test_and_clear_mask(pci_dev->wmask + PCI_COMMAND, + PCI_COMMAND_IO); + pci_dev->wmask[PCI_IO_BASE] = 0; + pci_dev->wmask[PCI_IO_LIMIT] = 0; + } + + cxl_cstate->dvsec_offset = CXL_ROOT_PORT_DVSEC_OFFSET; + cxl_cstate->pdev = pci_dev; + build_dvsecs(&crp->cxl_cstate); + + cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate, + TYPE_CXL_ROOT_PORT); + + pci_register_bar(pci_dev, CXL_COMPONENT_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + component_bar); +} + +static void cxl_rp_reset_hold(Object *obj) +{ + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj); + CXLRootPort *crp = CXL_ROOT_PORT(obj); + + if (rpc->parent_phases.hold) { + rpc->parent_phases.hold(obj); + } + + latch_registers(crp); +} + +static Property gen_rp_props[] = { + DEFINE_PROP_UINT32("bus-reserve", CXLRootPort, res_reserve.bus, -1), + DEFINE_PROP_SIZE("io-reserve", CXLRootPort, res_reserve.io, -1), + DEFINE_PROP_SIZE("mem-reserve", CXLRootPort, res_reserve.mem_non_pref, -1), + DEFINE_PROP_SIZE("pref32-reserve", CXLRootPort, res_reserve.mem_pref_32, + -1), + DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64, + -1), + DEFINE_PROP_END_OF_LIST() +}; + +static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int len) +{ + CXLRootPort *crp = CXL_ROOT_PORT(dev); + + if (range_contains(&crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC], addr)) { + uint8_t *reg = &dev->config[addr]; + addr -= crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC].lob; + if (addr == PORT_CONTROL_OFFSET) { + if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) { + /* unmask SBR */ + qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n"); + } + if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) { + /* Alt Memory & ID Space Enable */ + qemu_log_mask(LOG_UNIMP, + "Alt Memory & ID space is not supported\n"); + } + } + } +} + +static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val, + int len) +{ + uint16_t slt_ctl, slt_sta; + + pcie_cap_slot_get(d, &slt_ctl, &slt_sta); + pci_bridge_write_config(d, address, val, len); + pcie_cap_flr_write_config(d, address, val, len); + pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len); + pcie_aer_write_config(d, address, val, len); + + cxl_rp_dvsec_write_config(d, address, val, len); +} + +static void cxl_root_port_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(oc); + + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = CXL_ROOT_PORT_DID; + dc->desc = "CXL Root Port"; + k->revision = 0; + device_class_set_props(dc, gen_rp_props); + k->config_write = cxl_rp_write_config; + + device_class_set_parent_realize(dc, cxl_rp_realize, &rpc->parent_realize); + resettable_class_set_parent_phases(rc, NULL, cxl_rp_reset_hold, NULL, + &rpc->parent_phases); + + rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET; + rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET; + + dc->hotpluggable = false; +} + +static const TypeInfo cxl_root_port_info = { + .name = TYPE_CXL_ROOT_PORT, + .parent = TYPE_PCIE_ROOT_PORT, + .instance_size = sizeof(CXLRootPort), + .class_init = cxl_root_port_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CXL_DEVICE }, + { } + }, +}; + +static void cxl_register(void) +{ + type_register_static(&cxl_root_port_info); +} + +type_init(cxl_register); diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c new file mode 100644 index 000000000000..9df436cb73ad --- /dev/null +++ b/hw/pci-bridge/cxl_upstream.c @@ -0,0 +1,408 @@ +/* + * Emulated CXL Switch Upstream Port + * + * Copyright (c) 2022 Huawei Technologies. + * + * Based on xio3130_upstream.c + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/pci/pcie_port.h" + +#define CXL_UPSTREAM_PORT_MSI_NR_VECTOR 2 + +#define CXL_UPSTREAM_PORT_MSI_OFFSET 0x70 +#define CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET 0x90 +#define CXL_UPSTREAM_PORT_AER_OFFSET 0x100 +#define CXL_UPSTREAM_PORT_DVSEC_OFFSET \ + (CXL_UPSTREAM_PORT_AER_OFFSET + PCI_ERR_SIZEOF) + +typedef struct CXLUpstreamPort { + /*< private >*/ + PCIEPort parent_obj; + + /*< public >*/ + CXLComponentState cxl_cstate; + DOECap doe_cdat; +} CXLUpstreamPort; + +CXLComponentState *cxl_usp_to_cstate(CXLUpstreamPort *usp) +{ + return &usp->cxl_cstate; +} + +static void cxl_usp_dvsec_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int len) +{ + CXLUpstreamPort *usp = CXL_USP(dev); + + if (range_contains(&usp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC], addr)) { + uint8_t *reg = &dev->config[addr]; + addr -= usp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC].lob; + if (addr == PORT_CONTROL_OFFSET) { + if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) { + /* unmask SBR */ + qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n"); + } + if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) { + /* Alt Memory & ID Space Enable */ + qemu_log_mask(LOG_UNIMP, + "Alt Memory & ID space is not supported\n"); + } + } + } +} + +static void cxl_usp_write_config(PCIDevice *d, uint32_t address, + uint32_t val, int len) +{ + CXLUpstreamPort *usp = CXL_USP(d); + + pcie_doe_write_config(&usp->doe_cdat, address, val, len); + pci_bridge_write_config(d, address, val, len); + pcie_cap_flr_write_config(d, address, val, len); + pcie_aer_write_config(d, address, val, len); + + cxl_usp_dvsec_write_config(d, address, val, len); +} + +static uint32_t cxl_usp_read_config(PCIDevice *d, uint32_t address, int len) +{ + CXLUpstreamPort *usp = CXL_USP(d); + uint32_t val; + + if (pcie_doe_read_config(&usp->doe_cdat, address, len, &val)) { + return val; + } + + return pci_default_read_config(d, address, len); +} + +static void latch_registers(CXLUpstreamPort *usp) +{ + uint32_t *reg_state = usp->cxl_cstate.crb.cache_mem_registers; + uint32_t *write_msk = usp->cxl_cstate.crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, + CXL2_UPSTREAM_PORT); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8); +} + +static void cxl_usp_reset(DeviceState *qdev) +{ + PCIDevice *d = PCI_DEVICE(qdev); + CXLUpstreamPort *usp = CXL_USP(qdev); + + pci_bridge_reset(qdev); + pcie_cap_deverr_reset(d); + latch_registers(usp); +} + +static void build_dvsecs(CXLComponentState *cxl) +{ + uint8_t *dvsec; + + dvsec = (uint8_t *)&(CXLDVSECPortExtensions){ + .status = 0x1, /* Port Power Management Init Complete */ + }; + cxl_component_create_dvsec(cxl, CXL2_UPSTREAM_PORT, + EXTENSIONS_PORT_DVSEC_LENGTH, + EXTENSIONS_PORT_DVSEC, + EXTENSIONS_PORT_DVSEC_REVID, dvsec); + dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){ + .cap = 0x27, /* Cache, IO, Mem, non-MLD */ + .ctrl = 0x27, /* Cache, IO, Mem */ + .status = 0x26, /* same */ + .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */ + }; + cxl_component_create_dvsec(cxl, CXL2_UPSTREAM_PORT, + PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0, + PCIE_FLEXBUS_PORT_DVSEC, + PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){ + .rsvd = 0, + .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX, + .reg0_base_hi = 0, + }; + cxl_component_create_dvsec(cxl, CXL2_UPSTREAM_PORT, + REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC, + REG_LOC_DVSEC_REVID, dvsec); +} + +static bool cxl_doe_cdat_rsp(DOECap *doe_cap) +{ + CDATObject *cdat = &CXL_USP(doe_cap->pdev)->cxl_cstate.cdat; + uint16_t ent; + void *base; + uint32_t len; + CDATReq *req = pcie_doe_get_write_mbox_ptr(doe_cap); + CDATRsp rsp; + + cxl_doe_cdat_update(&CXL_USP(doe_cap->pdev)->cxl_cstate, &error_fatal); + assert(cdat->entry_len); + + /* Discard if request length mismatched */ + if (pcie_doe_get_obj_len(req) < + DIV_ROUND_UP(sizeof(CDATReq), sizeof(uint32_t))) { + return false; + } + + ent = req->entry_handle; + base = cdat->entry[ent].base; + len = cdat->entry[ent].length; + + rsp = (CDATRsp) { + .header = { + .vendor_id = CXL_VENDOR_ID, + .data_obj_type = CXL_DOE_TABLE_ACCESS, + .reserved = 0x0, + .length = DIV_ROUND_UP((sizeof(rsp) + len), sizeof(uint32_t)), + }, + .rsp_code = CXL_DOE_TAB_RSP, + .table_type = CXL_DOE_TAB_TYPE_CDAT, + .entry_handle = (ent < cdat->entry_len - 1) ? + ent + 1 : CXL_DOE_TAB_ENT_MAX, + }; + + memcpy(doe_cap->read_mbox, &rsp, sizeof(rsp)); + memcpy(doe_cap->read_mbox + DIV_ROUND_UP(sizeof(rsp), sizeof(uint32_t)), + base, len); + + doe_cap->read_mbox_len += rsp.header.length; + + return true; +} + +static DOEProtocol doe_cdat_prot[] = { + { CXL_VENDOR_ID, CXL_DOE_TABLE_ACCESS, cxl_doe_cdat_rsp }, + { } +}; + +enum { + CXL_USP_CDAT_SSLBIS_LAT, + CXL_USP_CDAT_SSLBIS_BW, + CXL_USP_CDAT_NUM_ENTRIES +}; + +static int build_cdat_table(CDATSubHeader ***cdat_table, void *priv) +{ + g_autofree CDATSslbis *sslbis_latency = NULL; + g_autofree CDATSslbis *sslbis_bandwidth = NULL; + CXLUpstreamPort *us = CXL_USP(priv); + PCIBus *bus = &PCI_BRIDGE(us)->sec_bus; + int devfn, sslbis_size, i; + int count = 0; + uint16_t port_ids[256]; + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + PCIDevice *d = bus->devices[devfn]; + PCIEPort *port; + + if (!d || !pci_is_express(d) || !d->exp.exp_cap) { + continue; + } + + /* + * Whilst the PCI express spec doesn't allow anything other than + * downstream ports on this bus, let us be a little paranoid + */ + if (!object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) { + continue; + } + + port = PCIE_PORT(d); + port_ids[count] = port->port; + count++; + } + + /* May not yet have any ports - try again later */ + if (count == 0) { + return 0; + } + + sslbis_size = sizeof(CDATSslbis) + sizeof(*sslbis_latency->sslbe) * count; + sslbis_latency = g_malloc(sslbis_size); + if (!sslbis_latency) { + return -ENOMEM; + } + *sslbis_latency = (CDATSslbis) { + .sslbis_header = { + .header = { + .type = CDAT_TYPE_SSLBIS, + .length = sslbis_size, + }, + .data_type = HMATLB_DATA_TYPE_ACCESS_LATENCY, + .entry_base_unit = 10000, + }, + }; + + for (i = 0; i < count; i++) { + sslbis_latency->sslbe[i] = (CDATSslbe) { + .port_x_id = CDAT_PORT_ID_USP, + .port_y_id = port_ids[i], + .latency_bandwidth = 15, /* 150ns */ + }; + } + + sslbis_bandwidth = g_malloc(sslbis_size); + if (!sslbis_bandwidth) { + return 0; + } + *sslbis_bandwidth = (CDATSslbis) { + .sslbis_header = { + .header = { + .type = CDAT_TYPE_SSLBIS, + .length = sslbis_size, + }, + .data_type = HMATLB_DATA_TYPE_ACCESS_BANDWIDTH, + .entry_base_unit = 1000, + }, + }; + + for (i = 0; i < count; i++) { + sslbis_bandwidth->sslbe[i] = (CDATSslbe) { + .port_x_id = CDAT_PORT_ID_USP, + .port_y_id = port_ids[i], + .latency_bandwidth = 16, /* 16 GB/s */ + }; + } + + *cdat_table = g_malloc0(sizeof(*cdat_table) * CXL_USP_CDAT_NUM_ENTRIES); + if (!*cdat_table) { + return -ENOMEM; + } + + /* Header always at start of structure */ + (*cdat_table)[CXL_USP_CDAT_SSLBIS_LAT] = g_steal_pointer(&sslbis_latency); + (*cdat_table)[CXL_USP_CDAT_SSLBIS_BW] = g_steal_pointer(&sslbis_bandwidth); + + return CXL_USP_CDAT_NUM_ENTRIES; +} + +static void free_default_cdat_table(CDATSubHeader **cdat_table, int num, + void *priv) +{ + int i; + + for (i = 0; i < num; i++) { + g_free(cdat_table[i]); + } + g_free(cdat_table); +} + +static void cxl_usp_realize(PCIDevice *d, Error **errp) +{ + PCIEPort *p = PCIE_PORT(d); + CXLUpstreamPort *usp = CXL_USP(d); + CXLComponentState *cxl_cstate = &usp->cxl_cstate; + ComponentRegisters *cregs = &cxl_cstate->crb; + MemoryRegion *component_bar = &cregs->component_registers; + int rc; + + pci_bridge_initfn(d, TYPE_PCIE_BUS); + pcie_port_init_reg(d); + + rc = msi_init(d, CXL_UPSTREAM_PORT_MSI_OFFSET, + CXL_UPSTREAM_PORT_MSI_NR_VECTOR, true, true, errp); + if (rc) { + assert(rc == -ENOTSUP); + goto err_bridge; + } + + rc = pcie_cap_init(d, CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET, + PCI_EXP_TYPE_UPSTREAM, p->port, errp); + if (rc < 0) { + goto err_msi; + } + + pcie_cap_flr_init(d); + pcie_cap_deverr_init(d); + rc = pcie_aer_init(d, PCI_ERR_VER, CXL_UPSTREAM_PORT_AER_OFFSET, + PCI_ERR_SIZEOF, errp); + if (rc) { + goto err_cap; + } + + cxl_cstate->dvsec_offset = CXL_UPSTREAM_PORT_DVSEC_OFFSET; + cxl_cstate->pdev = d; + build_dvsecs(cxl_cstate); + cxl_component_register_block_init(OBJECT(d), cxl_cstate, TYPE_CXL_USP); + pci_register_bar(d, CXL_COMPONENT_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + component_bar); + + pcie_doe_init(d, &usp->doe_cdat, cxl_cstate->dvsec_offset, doe_cdat_prot, + true, 1); + + cxl_cstate->cdat.build_cdat_table = build_cdat_table; + cxl_cstate->cdat.free_cdat_table = free_default_cdat_table; + cxl_cstate->cdat.private = d; + cxl_doe_cdat_init(cxl_cstate, errp); + + return; + +err_cap: + pcie_cap_exit(d); +err_msi: + msi_uninit(d); +err_bridge: + pci_bridge_exitfn(d); +} + +static void cxl_usp_exitfn(PCIDevice *d) +{ + pcie_aer_exit(d); + pcie_cap_exit(d); + msi_uninit(d); + pci_bridge_exitfn(d); +} + +static Property cxl_upstream_props[] = { + DEFINE_PROP_STRING("cdat", CXLUpstreamPort, cxl_cstate.cdat.filename), + DEFINE_PROP_END_OF_LIST() +}; + +static void cxl_upstream_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); + + k->config_write = cxl_usp_write_config; + k->config_read = cxl_usp_read_config; + k->realize = cxl_usp_realize; + k->exit = cxl_usp_exitfn; + k->vendor_id = 0x19e5; /* Huawei */ + k->device_id = 0xa128; /* Emulated CXL Switch Upstream Port */ + k->revision = 0; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->desc = "CXL Switch Upstream Port"; + dc->reset = cxl_usp_reset; + device_class_set_props(dc, cxl_upstream_props); +} + +static const TypeInfo cxl_usp_info = { + .name = TYPE_CXL_USP, + .parent = TYPE_PCIE_PORT, + .instance_size = sizeof(CXLUpstreamPort), + .class_init = cxl_upstream_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_PCIE_DEVICE }, + { INTERFACE_CXL_DEVICE }, + { } + }, +}; + +static void cxl_usp_register_type(void) +{ + type_register_static(&cxl_usp_info); +} + +type_init(cxl_usp_register_type); diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c deleted file mode 100644 index 4773d07e6d58..000000000000 --- a/hw/pci-bridge/dec.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * QEMU DEC 21154 PCI bridge - * - * Copyright (c) 2006-2007 Fabrice Bellard - * Copyright (c) 2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "dec.h" -#include "hw/sysbus.h" -#include "qapi/error.h" -#include "qemu/module.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_host.h" -#include "hw/pci/pci_bridge.h" -#include "hw/pci/pci_bus.h" -#include "qom/object.h" - -OBJECT_DECLARE_SIMPLE_TYPE(DECState, DEC_21154) - -struct DECState { - PCIHostState parent_obj; -}; - -static int dec_map_irq(PCIDevice *pci_dev, int irq_num) -{ - return irq_num; -} - -static void dec_pci_bridge_realize(PCIDevice *pci_dev, Error **errp) -{ - pci_bridge_initfn(pci_dev, TYPE_PCI_BUS); -} - -static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - k->realize = dec_pci_bridge_realize; - k->exit = pci_bridge_exitfn; - k->vendor_id = PCI_VENDOR_ID_DEC; - k->device_id = PCI_DEVICE_ID_DEC_21154; - k->config_write = pci_bridge_write_config; - k->is_bridge = true; - dc->desc = "DEC 21154 PCI-PCI bridge"; - dc->reset = pci_bridge_reset; - dc->vmsd = &vmstate_pci_device; -} - -static const TypeInfo dec_21154_pci_bridge_info = { - .name = "dec-21154-p2p-bridge", - .parent = TYPE_PCI_BRIDGE, - .instance_size = sizeof(PCIBridge), - .class_init = dec_21154_pci_bridge_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) -{ - PCIDevice *dev; - PCIBridge *br; - - dev = pci_new_multifunction(devfn, false, "dec-21154-p2p-bridge"); - br = PCI_BRIDGE(dev); - pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq); - pci_realize_and_unref(dev, parent_bus, &error_fatal); - return pci_bridge_get_sec_bus(br); -} - -static void pci_dec_21154_device_realize(DeviceState *dev, Error **errp) -{ - PCIHostState *phb; - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - phb = PCI_HOST_BRIDGE(dev); - - memory_region_init_io(&phb->conf_mem, OBJECT(dev), &pci_host_conf_le_ops, - dev, "pci-conf-idx", 0x1000); - memory_region_init_io(&phb->data_mem, OBJECT(dev), &pci_host_data_le_ops, - dev, "pci-data-idx", 0x1000); - sysbus_init_mmio(sbd, &phb->conf_mem); - sysbus_init_mmio(sbd, &phb->data_mem); -} - -static void dec_21154_pci_host_realize(PCIDevice *d, Error **errp) -{ - /* PCI2PCI bridge same values as PearPC - check this */ -} - -static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - k->realize = dec_21154_pci_host_realize; - k->vendor_id = PCI_VENDOR_ID_DEC; - k->device_id = PCI_DEVICE_ID_DEC_21154; - k->revision = 0x02; - k->class_id = PCI_CLASS_BRIDGE_PCI; - k->is_bridge = true; - /* - * PCI-facing part of the host bridge, not usable without the - * host-facing part, which can't be device_add'ed, yet. - */ - dc->user_creatable = false; -} - -static const TypeInfo dec_21154_pci_host_info = { - .name = "dec-21154", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = dec_21154_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = pci_dec_21154_device_realize; -} - -static const TypeInfo pci_dec_21154_device_info = { - .name = TYPE_DEC_21154, - .parent = TYPE_PCI_HOST_BRIDGE, - .instance_size = sizeof(DECState), - .class_init = pci_dec_21154_device_class_init, -}; - -static void dec_register_types(void) -{ - type_register_static(&pci_dec_21154_device_info); - type_register_static(&dec_21154_pci_host_info); - type_register_static(&dec_21154_pci_bridge_info); -} - -type_init(dec_register_types) diff --git a/hw/pci-bridge/dec.h b/hw/pci-bridge/dec.h deleted file mode 100644 index 869e90b13680..000000000000 --- a/hw/pci-bridge/dec.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef HW_PCI_BRIDGE_DEC_H -#define HW_PCI_BRIDGE_DEC_H - - -#define TYPE_DEC_21154 "dec-21154-sysbus" - -PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn); - -#endif diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index f28181e2101c..f3b4a1461101 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -42,7 +42,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" #include "migration/vmstate.h" #include "qemu/module.h" #include "hw/i386/ich9.h" @@ -92,7 +92,6 @@ static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->is_bridge = true; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11; k->revision = ICH9_D2P_A2_REVISION; diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build index daab8acf2aae..fe92d43de69f 100644 --- a/hw/pci-bridge/meson.build +++ b/hw/pci-bridge/meson.build @@ -3,12 +3,14 @@ pci_ss.add(files('pci_bridge_dev.c')) pci_ss.add(when: 'CONFIG_I82801B11', if_true: files('i82801b11.c')) pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c')) pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c', 'pcie_pci_bridge.c')) -pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c')) +pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c'), + if_false: files('pci_expander_bridge_stubs.c')) pci_ss.add(when: 'CONFIG_XIO3130', if_true: files('xio3130_upstream.c', 'xio3130_downstream.c')) +pci_ss.add(when: 'CONFIG_CXL', if_true: files('cxl_root_port.c', 'cxl_upstream.c', 'cxl_downstream.c')) -# NewWorld PowerMac -pci_ss.add(when: 'CONFIG_DEC_PCI', if_true: files('dec.c')) # Sun4u pci_ss.add(when: 'CONFIG_SIMBA', if_true: files('simba.c')) softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss) + +softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('pci_expander_bridge_stubs.c')) diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 657a06ddbe81..3435df8d735f 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -254,7 +254,6 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_REDHAT; k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; k->class_id = PCI_CLASS_BRIDGE_PCI; - k->is_bridge = true; dc->desc = "Standard PCI Bridge"; dc->reset = qdev_pci_bridge_dev_reset; device_class_set_props(dc, pci_bridge_dev_properties); diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index de932286b541..870d9bab1193 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -17,6 +17,8 @@ #include "hw/pci/pci_host.h" #include "hw/qdev-properties.h" #include "hw/pci/pci_bridge.h" +#include "hw/pci-bridge/pci_expander_bridge.h" +#include "hw/cxl/cxl.h" #include "qemu/range.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -24,6 +26,8 @@ #include "hw/boards.h" #include "qom/object.h" +enum BusType { PCI, PCIE, CXL }; + #define TYPE_PXB_BUS "pxb-bus" typedef struct PXBBus PXBBus; DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS, @@ -33,6 +37,10 @@ DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS, DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS, TYPE_PXB_PCIE_BUS) +#define TYPE_PXB_CXL_BUS "pxb-cxl-bus" +DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS, + TYPE_PXB_CXL_BUS) + struct PXBBus { /*< private >*/ PCIBus parent_obj; @@ -42,7 +50,6 @@ struct PXBBus { }; #define TYPE_PXB_DEVICE "pxb" -typedef struct PXBDev PXBDev; DECLARE_INSTANCE_CHECKER(PXBDev, PXB_DEV, TYPE_PXB_DEVICE) @@ -50,18 +57,13 @@ DECLARE_INSTANCE_CHECKER(PXBDev, PXB_DEV, DECLARE_INSTANCE_CHECKER(PXBDev, PXB_PCIE_DEV, TYPE_PXB_PCIE_DEVICE) -struct PXBDev { - /*< private >*/ - PCIDevice parent_obj; - /*< public >*/ - - uint8_t bus_nr; - uint16_t numa_node; - bool bypass_iommu; -}; - static PXBDev *convert_to_pxb(PCIDevice *dev) { + /* A CXL PXB's parent bus is PCIe, so the normal check won't work */ + if (object_dynamic_cast(OBJECT(dev), TYPE_PXB_CXL_DEVICE)) { + return PXB_CXL_DEV(dev); + } + return pci_bus_is_express(pci_get_bus(dev)) ? PXB_PCIE_DEV(dev) : PXB_DEV(dev); } @@ -70,6 +72,13 @@ static GList *pxb_dev_list; #define TYPE_PXB_HOST "pxb-host" +CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb) +{ + CXLHost *host = PXB_CXL_HOST(hb); + + return &host->cxl_cstate; +} + static int pxb_bus_num(PCIBus *bus) { PXBDev *pxb = convert_to_pxb(bus->parent_dev); @@ -106,11 +115,20 @@ static const TypeInfo pxb_pcie_bus_info = { .class_init = pxb_bus_class_init, }; +static const TypeInfo pxb_cxl_bus_info = { + .name = TYPE_PXB_CXL_BUS, + .parent = TYPE_CXL_BUS, + .instance_size = sizeof(PXBBus), + .class_init = pxb_bus_class_init, +}; + static const char *pxb_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { - PXBBus *bus = pci_bus_is_express(rootbus) ? - PXB_PCIE_BUS(rootbus) : PXB_BUS(rootbus); + PXBBus *bus = pci_bus_is_cxl(rootbus) ? + PXB_CXL_BUS(rootbus) : + pci_bus_is_express(rootbus) ? PXB_PCIE_BUS(rootbus) : + PXB_BUS(rootbus); snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus)); return bus->bus_path; @@ -166,6 +184,65 @@ static const TypeInfo pxb_host_info = { .class_init = pxb_host_class_init, }; +static void pxb_cxl_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + CXLHost *cxl = PXB_CXL_HOST(dev); + CXLComponentState *cxl_cstate = &cxl->cxl_cstate; + struct MemoryRegion *mr = &cxl_cstate->crb.component_registers; + + cxl_component_register_block_init(OBJECT(dev), cxl_cstate, + TYPE_PXB_CXL_HOST); + sysbus_init_mmio(sbd, mr); +} + +/* + * Host bridge realization has no means of knowning state associated + * with a particular machine. As such, it is nececssary to delay + * final setup of the host bridge register space until later in the + * machine bring up. + */ +void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp) +{ + PXBDev *pxb = PXB_CXL_DEV(pci_bridge_get_device(bus)); + CXLHost *cxl = pxb->cxl.cxl_host_bridge; + CXLComponentState *cxl_cstate = &cxl->cxl_cstate; + struct MemoryRegion *mr = &cxl_cstate->crb.component_registers; + hwaddr offset; + + offset = memory_region_size(mr) * cxl_state->next_mr_idx; + if (offset > memory_region_size(&cxl_state->host_mr)) { + error_setg(errp, "Insufficient space for pxb cxl host register space"); + return; + } + + memory_region_add_subregion(&cxl_state->host_mr, offset, mr); + cxl_state->next_mr_idx++; +} + +static void pxb_cxl_host_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); + + hc->root_bus_path = pxb_host_root_bus_path; + dc->fw_name = "cxl"; + dc->realize = pxb_cxl_realize; + /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */ + dc->user_creatable = false; +} + +/* + * This is a device to handle the MMIO for a CXL host bridge. It does nothing + * else. + */ +static const TypeInfo cxl_host_info = { + .name = TYPE_PXB_CXL_HOST, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(CXLHost), + .class_init = pxb_cxl_host_class_init, +}; + /* * Registers the PXB bus as a child of pci host root bus. */ @@ -212,6 +289,17 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) return pin - PCI_SLOT(pxb->devfn); } +static void pxb_dev_reset(DeviceState *dev) +{ + CXLHost *cxl = PXB_CXL_DEV(dev)->cxl.cxl_host_bridge; + CXLComponentState *cxl_cstate = &cxl->cxl_cstate; + uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers; + uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8); +} + static gint pxb_compare(gconstpointer a, gconstpointer b) { const PXBDev *pxb_a = a, *pxb_b = b; @@ -221,7 +309,8 @@ static gint pxb_compare(gconstpointer a, gconstpointer b) 0; } -static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) +static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, + Error **errp) { PXBDev *pxb = convert_to_pxb(dev); DeviceState *ds, *bds = NULL; @@ -245,9 +334,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) dev_name = dev->qdev.id; } - ds = qdev_new(TYPE_PXB_HOST); - if (pcie) { + ds = qdev_new(type == CXL ? TYPE_PXB_CXL_HOST : TYPE_PXB_HOST); + if (type == PCIE) { bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); + } else if (type == CXL) { + bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_CXL_BUS); + bus->flags |= PCI_BUS_CXL; + PXB_CXL_DEV(dev)->cxl.cxl_host_bridge = PXB_CXL_HOST(ds); } else { bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); bds = qdev_new("pci-bridge"); @@ -295,7 +388,7 @@ static void pxb_dev_realize(PCIDevice *dev, Error **errp) return; } - pxb_dev_realize_common(dev, false, errp); + pxb_dev_realize_common(dev, PCI, errp); } static void pxb_dev_exitfn(PCIDevice *pci_dev) @@ -348,7 +441,7 @@ static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) return; } - pxb_dev_realize_common(dev, true, errp); + pxb_dev_realize_common(dev, PCIE, errp); } static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) @@ -379,13 +472,61 @@ static const TypeInfo pxb_pcie_dev_info = { }, }; +static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp) +{ + /* A CXL PXB's parent bus is still PCIe */ + if (!pci_bus_is_express(pci_get_bus(dev))) { + error_setg(errp, "pxb-cxl devices cannot reside on a PCI bus"); + return; + } + + pxb_dev_realize_common(dev, CXL, errp); + pxb_dev_reset(DEVICE(dev)); +} + +static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = pxb_cxl_dev_realize; + k->exit = pxb_dev_exitfn; + /* + * XXX: These types of bridges don't actually show up in the hierarchy so + * vendor, device, class, etc. ids are intentionally left out. + */ + + dc->desc = "CXL Host Bridge"; + device_class_set_props(dc, pxb_dev_properties); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + + /* Host bridges aren't hotpluggable. FIXME: spec reference */ + dc->hotpluggable = false; + dc->reset = pxb_dev_reset; +} + +static const TypeInfo pxb_cxl_dev_info = { + .name = TYPE_PXB_CXL_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PXBDev), + .class_init = pxb_cxl_dev_class_init, + .interfaces = + (InterfaceInfo[]){ + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + {}, + }, +}; + static void pxb_register_types(void) { type_register_static(&pxb_bus_info); type_register_static(&pxb_pcie_bus_info); + type_register_static(&pxb_cxl_bus_info); type_register_static(&pxb_host_info); + type_register_static(&cxl_host_info); type_register_static(&pxb_dev_info); type_register_static(&pxb_pcie_dev_info); + type_register_static(&pxb_cxl_dev_info); } type_init(pxb_register_types) diff --git a/hw/pci-bridge/pci_expander_bridge_stubs.c b/hw/pci-bridge/pci_expander_bridge_stubs.c new file mode 100644 index 000000000000..b35180311f68 --- /dev/null +++ b/hw/pci-bridge/pci_expander_bridge_stubs.c @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Stubs for calls made from machines to handle the case where CONFIG_PXB + * is not enabled. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci-bridge/pci_expander_bridge.h" +#include "hw/cxl/cxl.h" + +void pxb_cxl_hook_up_registers(CXLState *state, PCIBus *bus, Error **errp) {}; diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c index 1cd917a45974..2301b2ca0b08 100644 --- a/hw/pci-bridge/pcie_pci_bridge.c +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -145,7 +145,6 @@ static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - k->is_bridge = true; k->vendor_id = PCI_VENDOR_ID_REDHAT; k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE; k->realize = pcie_pci_bridge_realize; diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index f1cfe9d14aaf..efd96bf17419 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -43,9 +43,10 @@ static void rp_write_config(PCIDevice *d, uint32_t address, pcie_aer_root_write_config(d, address, val, len, root_cmd); } -static void rp_reset(DeviceState *qdev) +static void rp_reset_hold(Object *obj) { - PCIDevice *d = PCI_DEVICE(qdev); + PCIDevice *d = PCI_DEVICE(obj); + DeviceState *qdev = DEVICE(obj); rp_aer_vector_update(d); pcie_cap_root_reset(d); @@ -67,7 +68,11 @@ static void rp_realize(PCIDevice *d, Error **errp) int rc; pci_config_set_interrupt_pin(d->config, 1); - pci_bridge_initfn(d, TYPE_PCIE_BUS); + if (d->cap_present & QEMU_PCIE_CAP_CXL) { + pci_bridge_initfn(d, TYPE_CXL_BUS); + } else { + pci_bridge_initfn(d, TYPE_PCIE_BUS); + } pcie_port_init_reg(d); rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, @@ -167,13 +172,13 @@ static void rp_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - k->is_bridge = true; k->config_write = rp_write_config; k->realize = rp_realize; k->exit = rp_exit; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->reset = rp_reset; + rc->phases.hold = rp_reset_hold; device_class_set_props(dc, rp_props); } diff --git a/hw/pci-bridge/simba.c b/hw/pci-bridge/simba.c index ba55ab193939..17aa0d7b2163 100644 --- a/hw/pci-bridge/simba.c +++ b/hw/pci-bridge/simba.c @@ -77,7 +77,6 @@ static void simba_pci_bridge_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_SUN_SIMBA; k->revision = 0x11; k->config_write = pci_bridge_write_config; - k->is_bridge = true; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_bridge_reset; dc->vmsd = &vmstate_pci_device; diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 05e2b06c0cb8..38a2361fa2af 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -159,7 +159,6 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->is_bridge = true; k->config_write = xio3130_downstream_write_config; k->realize = xio3130_downstream_realize; k->exit = xio3130_downstream_exitfn; diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 5ff46ef05047..a48bfe3bc54f 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -128,7 +128,6 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->is_bridge = true; k->config_write = xio3130_upstream_write_config; k->realize = xio3130_upstream_realize; k->exit = xio3130_upstream_exitfn; diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 2b5f7d58cc5d..38fd2ee8f3d7 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -77,3 +77,7 @@ config MV64361 bool select PCI select I8259 + +config DINO + bool + select PCI diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index a57e81e3a97a..f04f3ad668d9 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -42,7 +42,7 @@ #include "qemu/units.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/irq.h" #include "hw/mips/mips.h" #include "hw/pci/pci_host.h" diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index bde3a343a2f5..9e183caa48ea 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -600,7 +600,6 @@ static void designware_pcie_root_class_init(ObjectClass *klass, void *data) k->device_id = 0xABCD; k->revision = 0; k->class_id = PCI_CLASS_BRIDGE_PCI; - k->is_bridge = true; k->exit = pci_bridge_exitfn; k->realize = designware_pcie_root_realize; k->config_read = designware_pcie_root_config_read; diff --git a/hw/pci-host/dino.c b/hw/pci-host/dino.c new file mode 100644 index 000000000000..e8eaebca5451 --- /dev/null +++ b/hw/pci-host/dino.c @@ -0,0 +1,521 @@ +/* + * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines + * + * (C) 2017-2019 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Documentation available at: + * https://parisc.wiki.kernel.org/images-parisc/9/91/Dino_ers.pdf + * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/irq.h" +#include "hw/pci/pci_device.h" +#include "hw/pci/pci_bus.h" +#include "hw/qdev-properties.h" +#include "hw/pci-host/dino.h" +#include "migration/vmstate.h" +#include "trace.h" +#include "qom/object.h" + + +/* + * Dino can forward memory accesses from the CPU in the range between + * 0xf0800000 and 0xff000000 to the PCI bus. + */ +static void gsc_to_pci_forwarding(DinoState *s) +{ + uint32_t io_addr_en, tmp; + int enabled, i; + + tmp = extract32(s->io_control, 7, 2); + enabled = (tmp == 0x01); + io_addr_en = s->io_addr_en; + /* Mask out first (=firmware) and last (=Dino) areas. */ + io_addr_en &= ~(BIT(31) | BIT(0)); + + memory_region_transaction_begin(); + for (i = 1; i < 31; i++) { + MemoryRegion *mem = &s->pci_mem_alias[i]; + if (enabled && (io_addr_en & (1U << i))) { + if (!memory_region_is_mapped(mem)) { + uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; + memory_region_add_subregion(get_system_memory(), addr, mem); + } + } else if (memory_region_is_mapped(mem)) { + memory_region_del_subregion(get_system_memory(), mem); + } + } + memory_region_transaction_commit(); +} + +static bool dino_chip_mem_valid(void *opaque, hwaddr addr, + unsigned size, bool is_write, + MemTxAttrs attrs) +{ + bool ret = false; + + switch (addr) { + case DINO_IAR0: + case DINO_IAR1: + case DINO_IRR0: + case DINO_IRR1: + case DINO_IMR: + case DINO_IPR: + case DINO_ICR: + case DINO_ILR: + case DINO_IO_CONTROL: + case DINO_IO_FBB_EN: + case DINO_IO_ADDR_EN: + case DINO_PCI_IO_DATA: + case DINO_TOC_ADDR: + case DINO_GMASK ... DINO_PCISTS: + case DINO_MLTIM ... DINO_PCIWOR: + case DINO_TLTIM: + ret = true; + break; + case DINO_PCI_IO_DATA + 2: + ret = (size <= 2); + break; + case DINO_PCI_IO_DATA + 1: + case DINO_PCI_IO_DATA + 3: + ret = (size == 1); + } + trace_dino_chip_mem_valid(addr, ret); + return ret; +} + +static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + DinoState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); + MemTxResult ret = MEMTX_OK; + AddressSpace *io; + uint16_t ioaddr; + uint32_t val; + + switch (addr) { + case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3: + /* Read from PCI IO space. */ + io = &address_space_io; + ioaddr = phb->config_reg + (addr & 3); + switch (size) { + case 1: + val = address_space_ldub(io, ioaddr, attrs, &ret); + break; + case 2: + val = address_space_lduw_be(io, ioaddr, attrs, &ret); + break; + case 4: + val = address_space_ldl_be(io, ioaddr, attrs, &ret); + break; + default: + g_assert_not_reached(); + } + break; + + case DINO_IO_FBB_EN: + val = s->io_fbb_en; + break; + case DINO_IO_ADDR_EN: + val = s->io_addr_en; + break; + case DINO_IO_CONTROL: + val = s->io_control; + break; + + case DINO_IAR0: + val = s->iar0; + break; + case DINO_IAR1: + val = s->iar1; + break; + case DINO_IMR: + val = s->imr; + break; + case DINO_ICR: + val = s->icr; + break; + case DINO_IPR: + val = s->ipr; + /* Any read to IPR clears the register. */ + s->ipr = 0; + break; + case DINO_ILR: + val = s->ilr; + break; + case DINO_IRR0: + val = s->ilr & s->imr & ~s->icr; + break; + case DINO_IRR1: + val = s->ilr & s->imr & s->icr; + break; + case DINO_TOC_ADDR: + val = s->toc_addr; + break; + case DINO_GMASK ... DINO_TLTIM: + val = s->reg800[(addr - DINO_GMASK) / 4]; + if (addr == DINO_PAMR) { + val &= ~0x01; /* LSB is hardwired to 0 */ + } + if (addr == DINO_MLTIM) { + val &= ~0x07; /* 3 LSB are hardwired to 0 */ + } + if (addr == DINO_BRDG_FEAT) { + val &= ~(0x10710E0ul | 8); /* bits 5-7, 24 & 15 reserved */ + } + break; + + default: + /* Controlled by dino_chip_mem_valid above. */ + g_assert_not_reached(); + } + + trace_dino_chip_read(addr, val); + *data = val; + return ret; +} + +static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr, + uint64_t val, unsigned size, + MemTxAttrs attrs) +{ + DinoState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); + AddressSpace *io; + MemTxResult ret; + uint16_t ioaddr; + int i; + + trace_dino_chip_write(addr, val); + + switch (addr) { + case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3: + /* Write into PCI IO space. */ + io = &address_space_io; + ioaddr = phb->config_reg + (addr & 3); + switch (size) { + case 1: + address_space_stb(io, ioaddr, val, attrs, &ret); + break; + case 2: + address_space_stw_be(io, ioaddr, val, attrs, &ret); + break; + case 4: + address_space_stl_be(io, ioaddr, val, attrs, &ret); + break; + default: + g_assert_not_reached(); + } + return ret; + + case DINO_IO_FBB_EN: + s->io_fbb_en = val & 0x03; + break; + case DINO_IO_ADDR_EN: + s->io_addr_en = val; + gsc_to_pci_forwarding(s); + break; + case DINO_IO_CONTROL: + s->io_control = val; + gsc_to_pci_forwarding(s); + break; + + case DINO_IAR0: + s->iar0 = val; + break; + case DINO_IAR1: + s->iar1 = val; + break; + case DINO_IMR: + s->imr = val; + break; + case DINO_ICR: + s->icr = val; + break; + case DINO_IPR: + /* Any write to IPR clears the register. */ + s->ipr = 0; + break; + case DINO_TOC_ADDR: + /* IO_COMMAND of CPU with client_id bits */ + s->toc_addr = 0xFFFA0030 | (val & 0x1e000); + break; + + case DINO_ILR: + case DINO_IRR0: + case DINO_IRR1: + /* These registers are read-only. */ + break; + + case DINO_GMASK ... DINO_TLTIM: + i = (addr - DINO_GMASK) / 4; + val &= reg800_keep_bits[i]; + s->reg800[i] = val; + break; + + default: + /* Controlled by dino_chip_mem_valid above. */ + g_assert_not_reached(); + } + return MEMTX_OK; +} + +static const MemoryRegionOps dino_chip_ops = { + .read_with_attrs = dino_chip_read_with_attrs, + .write_with_attrs = dino_chip_write_with_attrs, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .accepts = dino_chip_mem_valid, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +static const VMStateDescription vmstate_dino = { + .name = "Dino", + .version_id = 2, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(iar0, DinoState), + VMSTATE_UINT32(iar1, DinoState), + VMSTATE_UINT32(imr, DinoState), + VMSTATE_UINT32(ipr, DinoState), + VMSTATE_UINT32(icr, DinoState), + VMSTATE_UINT32(ilr, DinoState), + VMSTATE_UINT32(io_fbb_en, DinoState), + VMSTATE_UINT32(io_addr_en, DinoState), + VMSTATE_UINT32(io_control, DinoState), + VMSTATE_UINT32(toc_addr, DinoState), + VMSTATE_END_OF_LIST() + } +}; + +/* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */ + +static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len) +{ + PCIHostState *s = opaque; + return pci_data_read(s->bus, s->config_reg | (addr & 3), len); +} + +static void dino_config_data_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + PCIHostState *s = opaque; + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); +} + +static const MemoryRegionOps dino_config_data_ops = { + .read = dino_config_data_read, + .write = dino_config_data_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len) +{ + DinoState *s = opaque; + return s->config_reg_dino; +} + +static void dino_config_addr_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + PCIHostState *s = opaque; + DinoState *ds = opaque; + ds->config_reg_dino = val; /* keep a copy of original value */ + s->config_reg = val & ~3U; +} + +static const MemoryRegionOps dino_config_addr_ops = { + .read = dino_config_addr_read, + .write = dino_config_addr_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque, + int devfn) +{ + DinoState *s = opaque; + + return &s->bm_as; +} + +/* + * Dino interrupts are connected as shown on Page 78, Table 23 + * (Little-endian bit numbers) + * 0 PCI INTA + * 1 PCI INTB + * 2 PCI INTC + * 3 PCI INTD + * 4 PCI INTE + * 5 PCI INTF + * 6 GSC External Interrupt + * 7 Bus Error for "less than fatal" mode + * 8 PS2 + * 9 Unused + * 10 RS232 + */ + +static void dino_set_irq(void *opaque, int irq, int level) +{ + DinoState *s = opaque; + uint32_t bit = 1u << irq; + uint32_t old_ilr = s->ilr; + + if (level) { + uint32_t ena = bit & ~old_ilr; + s->ipr |= ena; + s->ilr = old_ilr | bit; + if (ena & s->imr) { + uint32_t iar = (ena & s->icr ? s->iar1 : s->iar0); + stl_be_phys(&address_space_memory, iar & -32, iar & 31); + } + } else { + s->ilr = old_ilr & ~bit; + } +} + +static int dino_pci_map_irq(PCIDevice *d, int irq_num) +{ + int slot = PCI_SLOT(d->devfn); + + assert(irq_num >= 0 && irq_num <= 3); + + return slot & 0x03; +} + +static void dino_pcihost_reset(DeviceState *dev) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(dev); + + s->iar0 = s->iar1 = 0xFFFB0000 + 3; /* CPU_HPA + 3 */ + s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ +} + +static void dino_pcihost_realize(DeviceState *dev, Error **errp) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(dev); + + /* Set up PCI view of memory: Bus master address space. */ + memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); + memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), + "bm-system", s->memory_as, 0, + 0xf0000000 + DINO_MEM_CHUNK_SIZE); + memory_region_init_alias(&s->bm_pci_alias, OBJECT(s), + "bm-pci", &s->pci_mem, + 0xf0000000 + DINO_MEM_CHUNK_SIZE, + 30 * DINO_MEM_CHUNK_SIZE); + memory_region_init_alias(&s->bm_cpu_alias, OBJECT(s), + "bm-cpu", s->memory_as, 0xfff00000, + 0xfffff); + memory_region_add_subregion(&s->bm, 0, + &s->bm_ram_alias); + memory_region_add_subregion(&s->bm, + 0xf0000000 + DINO_MEM_CHUNK_SIZE, + &s->bm_pci_alias); + memory_region_add_subregion(&s->bm, 0xfff00000, + &s->bm_cpu_alias); + + address_space_init(&s->bm_as, &s->bm, "pci-bm"); +} + +static void dino_pcihost_unrealize(DeviceState *dev) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(dev); + + address_space_destroy(&s->bm_as); +} + +static void dino_pcihost_init(Object *obj) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(obj); + PCIHostState *phb = PCI_HOST_BRIDGE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + /* Dino PCI access from main memory. */ + memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, + s, "dino", 4096); + + /* Dino PCI config. */ + memory_region_init_io(&phb->conf_mem, OBJECT(phb), + &dino_config_addr_ops, DEVICE(s), + "pci-conf-idx", 4); + memory_region_init_io(&phb->data_mem, OBJECT(phb), + &dino_config_data_ops, DEVICE(s), + "pci-conf-data", 4); + memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR, + &phb->conf_mem); + memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, + &phb->data_mem); + + /* Dino PCI bus memory. */ + memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); + + phb->bus = pci_register_root_bus(DEVICE(s), "pci", + dino_set_irq, dino_pci_map_irq, s, + &s->pci_mem, get_system_io(), + PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); + + /* Set up windows into PCI bus memory. */ + for (i = 1; i < 31; i++) { + uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; + char *name = g_strdup_printf("PCI Outbound Window %d", i); + memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), + name, &s->pci_mem, addr, + DINO_MEM_CHUNK_SIZE); + g_free(name); + } + + pci_setup_iommu(phb->bus, dino_pcihost_set_iommu, s); + + sysbus_init_mmio(sbd, &s->this_mem); + + qdev_init_gpio_in(DEVICE(obj), dino_set_irq, DINO_IRQS); +} + +static Property dino_pcihost_properties[] = { + DEFINE_PROP_LINK("memory-as", DinoState, memory_as, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void dino_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = dino_pcihost_reset; + dc->realize = dino_pcihost_realize; + dc->unrealize = dino_pcihost_unrealize; + device_class_set_props(dc, dino_pcihost_properties); + dc->vmsd = &vmstate_dino; +} + +static const TypeInfo dino_pcihost_info = { + .name = TYPE_DINO_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_init = dino_pcihost_init, + .instance_size = sizeof(DinoState), + .class_init = dino_pcihost_class_init, +}; + +static void dino_register_types(void) +{ + type_register_static(&dino_pcihost_info); +} + +type_init(dino_register_types) diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index e7e162a00ab3..7c7316bc964c 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -5,6 +5,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pcie_host.h" +#include "hw/acpi/cxl.h" static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq) { @@ -139,6 +140,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) QLIST_FOREACH(bus, &bus->child, sibling) { uint8_t bus_num = pci_bus_num(bus); uint8_t numa_node = pci_bus_numa_node(bus); + bool is_cxl = pci_bus_is_cxl(bus); if (!pci_bus_is_root(bus)) { continue; @@ -154,8 +156,16 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) } dev = aml_device("PC%.02X", bus_num); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); + if (is_cxl) { + struct Aml *pkg = aml_package(2); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0016"))); + aml_append(pkg, aml_eisaid("PNP0A08")); + aml_append(pkg, aml_eisaid("PNP0A03")); + aml_append(dev, aml_name_decl("_CID", pkg)); + } else { + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); + aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); + } aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device"))); @@ -175,7 +185,11 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) cfg->pio.base, 0, 0, 0); aml_append(dev, aml_name_decl("_CRS", crs)); - acpi_dsdt_add_pci_osc(dev); + if (is_cxl) { + build_cxl_osc_method(dev); + } else { + acpi_dsdt_add_pci_osc(dev); + } aml_append(scope, dev); } diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index b05facf46353..8cf318cb8002 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -24,27 +24,14 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci_host.h" -#include "hw/ppc/mac.h" #include "hw/qdev-properties.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/irq.h" #include "qapi/error.h" #include "qemu/module.h" #include "trace.h" #include "qom/object.h" - -OBJECT_DECLARE_SIMPLE_TYPE(GrackleState, GRACKLE_PCI_HOST_BRIDGE) - -struct GrackleState { - PCIHostState parent_obj; - - uint32_t ofw_addr; - qemu_irq irqs[4]; - MemoryRegion pci_mmio; - MemoryRegion pci_hole; - MemoryRegion pci_io; -}; +#include "hw/pci-host/grackle.h" /* Don't know if this matches real hardware, but it agrees with OHW. */ static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num) diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index e08716142b6e..d5426ef4a53c 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -237,8 +237,8 @@ static void i440fx_realize(PCIDevice *dev, Error **errp) } } -PCIBus *i440fx_init(const char *host_type, const char *pci_type, - PCII440FXState **pi440fx_state, +PCIBus *i440fx_init(const char *pci_type, + DeviceState *dev, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -247,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; @@ -255,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); @@ -264,8 +262,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); d = pci_create_simple(b, 0, pci_type); - *pi440fx_state = I440FX_PCI_DEVICE(d); - f = *pi440fx_state; + f = I440FX_PCI_DEVICE(d); f->system_memory = address_space_mem; f->pci_address_space = pci_address_space; f->ram_memory = ram_memory; diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 4c4f39c15c69..e832babc9dae 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -25,6 +25,9 @@ pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c')) # ARM devices pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c')) +# HPPA devices +pci_ss.add(when: 'CONFIG_DINO', if_true: files('dino.c')) + softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss) specific_ss.add(when: 'CONFIG_PCI_POWERNV', if_true: files( @@ -32,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/mv64361.c b/hw/pci-host/mv64361.c index 00b3ff7d9098..015b92bd5f74 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -9,12 +9,11 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/units.h" #include "qapi/error.h" #include "hw/hw.h" #include "hw/sysbus.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "hw/irq.h" #include "hw/intc/i8259.h" diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c new file mode 100644 index 000000000000..c62b08538ac0 --- /dev/null +++ b/hw/pci-host/pnv_phb.c @@ -0,0 +1,347 @@ +/* + * 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_hold(Object *obj) +{ + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj); + PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(obj); + PCIDevice *d = PCI_DEVICE(obj); + uint8_t *conf = d->config; + + if (rpc->parent_phases.hold) { + rpc->parent_phases.hold(obj); + } + + 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", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + index = object_property_get_int(OBJECT(bus), "phb-id", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* 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); + ResettableClass *rc = RESETTABLE_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); + resettable_class_set_parent_phases(rc, NULL, pnv_phb_root_port_reset_hold, + NULL, &rpc->parent_phases); + 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 000000000000..58ebd6dd0ff7 --- /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 6e9aa9d6ace2..9054c393a2a3 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -10,8 +10,8 @@ #include "qemu/log.h" #include "qapi/visitor.h" #include "qapi/error.h" -#include "qemu-common.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" @@ -27,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; @@ -591,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) { @@ -987,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; @@ -1035,25 +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_HOST_BRIDGE(phb), TYPE_PNV_PHB3_ROOT_PORT); } void pnv_phb3_update_regions(PnvPHB3 *phb) @@ -1078,123 +1085,97 @@ 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_END_OF_LIST(), + 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_class_init(ObjectClass *klass, void *data) +static void pnv_phb3_root_bus_get_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) { - BusClass *k = BUS_CLASS(klass); + PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj); + uint64_t value = 0; - /* - * PHB3 has only a single root complex. Enforce the limit on the - * parent bus - */ - k->max_dev = 1; + if (strcmp(name, "phb-id") == 0) { + value = bus->phb_id; + } else { + value = bus->chip_id; + } + + visit_type_size(v, name, &value, errp); } -static const TypeInfo pnv_phb3_root_bus_info = { - .name = TYPE_PNV_PHB3_ROOT_BUS, - .parent = TYPE_PCIE_BUS, - .class_init = pnv_phb3_root_bus_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_PCIE_DEVICE }, - { } - }, -}; +static void pnv_phb3_root_bus_set_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) -static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp) { - PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); - PCIDevice *pci = PCI_DEVICE(dev); - PCIBus *bus = pci_get_bus(pci); - PnvPHB3 *phb = NULL; - Error *local_err = NULL; - - phb = (PnvPHB3 *) object_dynamic_cast(OBJECT(bus->qbus.parent), - TYPE_PNV_PHB3); - - if (!phb) { - error_setg(errp, -"pnv_phb3_root_port devices must be connected to pnv-phb3 buses"); + PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj); + uint64_t value; + + if (!visit_type_size(v, name, &value, errp)) { return; } - /* Set unique chassis/slot values for the root port */ - qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id); - qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id); - - rpc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (strcmp(name, "phb-id") == 0) { + bus->phb_id = value; + } else { + bus->chip_id = value; } } -static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data) +static void pnv_phb3_root_bus_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"; + BusClass *k = BUS_CLASS(klass); - device_class_set_parent_realize(dc, pnv_phb3_root_port_realize, - &rpc->parent_realize); - dc->user_creatable = false; + object_class_property_add(klass, "phb-id", "int", + pnv_phb3_root_bus_get_prop, + pnv_phb3_root_bus_set_prop, + NULL, NULL); - k->vendor_id = PCI_VENDOR_ID_IBM; - k->device_id = 0x03dc; - k->revision = 0; + object_class_property_add(klass, "chip-id", "int", + pnv_phb3_root_bus_get_prop, + pnv_phb3_root_bus_set_prop, + NULL, NULL); - rpc->exp_offset = 0x48; - rpc->aer_offset = 0x100; + /* + * PHB3 has only a single root complex. Enforce the limit on the + * parent bus + */ + k->max_dev = 1; } -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 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_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_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c index 8bcbc2cc4f37..41e63b066f95 100644 --- a/hw/pci-host/pnv_phb3_msi.c +++ b/hw/pci-host/pnv_phb3_msi.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qapi/error.h" -#include "qemu-common.h" #include "hw/pci-host/pnv_phb3_regs.h" #include "hw/pci-host/pnv_phb3.h" #include "hw/ppc/pnv.h" @@ -229,22 +228,19 @@ static void phb3_msi_resend(ICSState *ics) } } -static void phb3_msi_reset(DeviceState *dev) +static void phb3_msi_reset_hold(Object *obj) { - Phb3MsiState *msi = PHB3_MSI(dev); - ICSStateClass *icsc = ICS_GET_CLASS(dev); + Phb3MsiState *msi = PHB3_MSI(obj); + ICSStateClass *icsc = ICS_GET_CLASS(obj); - icsc->parent_reset(dev); + if (icsc->parent_phases.hold) { + icsc->parent_phases.hold(obj); + } memset(msi->rba, 0, sizeof(msi->rba)); msi->rba_sum = 0; } -static void phb3_msi_reset_handler(void *dev) -{ - phb3_msi_reset(dev); -} - void pnv_phb3_msi_update_config(Phb3MsiState *msi, uint32_t base, uint32_t count) { @@ -273,8 +269,6 @@ static void phb3_msi_realize(DeviceState *dev, Error **errp) } msi->qirqs = qemu_allocate_irqs(phb3_msi_set_irq, msi, ics->nr_irqs); - - qemu_register_reset(phb3_msi_reset_handler, dev); } static void phb3_msi_instance_init(Object *obj) @@ -295,11 +289,12 @@ static void phb3_msi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ICSStateClass *isc = ICS_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_parent_realize(dc, phb3_msi_realize, &isc->parent_realize); - device_class_set_parent_reset(dc, phb3_msi_reset, - &isc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, phb3_msi_reset_hold, NULL, + &isc->parent_phases); isc->reject = phb3_msi_reject; isc->resend = phb3_msi_resend; diff --git a/hw/pci-host/pnv_phb3_pbcq.c b/hw/pci-host/pnv_phb3_pbcq.c index c7426cd27a20..82f70efa4311 100644 --- a/hw/pci-host/pnv_phb3_pbcq.c +++ b/hw/pci-host/pnv_phb3_pbcq.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/log.h" #include "target/ppc/cpu.h" #include "hw/ppc/fdt.h" diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 11c97e27eb16..ccbde841fc30 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -10,7 +10,6 @@ #include "qemu/log.h" #include "qapi/visitor.h" #include "qapi/error.h" -#include "qemu-common.h" #include "monitor/monitor.h" #include "target/ppc/cpu.h" #include "hw/pci-host/pnv_phb4_regs.h" @@ -32,25 +31,9 @@ qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \ (pec)->chip_id, (pec)->index, ## __VA_ARGS__) -/* - * QEMU version of the GETFIELD/SETFIELD macros - * - * These are common with the PnvXive model. - */ -static inline uint64_t GETFIELD(uint64_t mask, uint64_t word) -{ - return (word & mask) >> ctz64(mask); -} - -static inline uint64_t SETFIELD(uint64_t mask, uint64_t word, - uint64_t value) -{ - return (word & ~mask) | ((value << ctz64(mask)) & mask); -} - 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; @@ -146,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) { @@ -167,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; @@ -1545,29 +1528,16 @@ static void pnv_phb4_instance_init(Object *obj) object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE); } -static void pnv_phb4_realize(DeviceState *dev, Error **errp) +void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb) { - PnvPHB4 *phb = PNV_PHB4(dev); PCIHostState *pci = PCI_HOST_BRIDGE(dev); - XiveSource *xsrc = &phb->xsrc; - int nr_irqs; char name[32]; - /* Set the "big_phb" flag */ - phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3; - - /* Controller Registers */ - snprintf(name, sizeof(name), "phb4-%d.%d-regs", phb->chip_id, - phb->phb_id); - 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); @@ -1577,12 +1547,35 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) memory_region_init(&phb->pci_mmio, OBJECT(phb), name, PCI_MMIO_TOTAL_SIZE); - pci->bus = pci_register_root_bus(dev, dev->id, + 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); + XiveSource *xsrc = &phb->xsrc; + int nr_irqs; + char name[32]; + + /* Set the "big_phb" flag */ + phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3; + + /* Controller Registers */ + snprintf(name, sizeof(name), "phb4-%d.%d-regs", phb->chip_id, + phb->phb_id); + memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb4_reg_ops, phb, + name, 0x2000); /* Setup XIVE Source */ if (phb->big_phb) { @@ -1603,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) * @@ -1693,23 +1676,21 @@ static void pnv_phb4_xive_notify(XiveNotifier *xf, uint32_t srcno, } static Property pnv_phb4_properties[] = { - DEFINE_PROP_UINT32("index", PnvPHB4, phb_id, 0), - DEFINE_PROP_UINT32("chip-id", PnvPHB4, chip_id, 0), - DEFINE_PROP_LINK("pec", PnvPHB4, pec, TYPE_PNV_PHB4_PEC, - PnvPhb4PecState *), - DEFINE_PROP_END_OF_LIST(), + DEFINE_PROP_UINT32("index", PnvPHB4, phb_id, 0), + 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; @@ -1717,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, @@ -1733,129 +1714,72 @@ static const TypeInfo pnv_phb5_type_info = { .instance_size = sizeof(PnvPHB4), }; -static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data) +static void pnv_phb4_root_bus_get_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) { - BusClass *k = BUS_CLASS(klass); - - /* - * PHB4 has only a single root complex. Enforce the limit on the - * parent bus - */ - k->max_dev = 1; -} + PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj); + uint64_t value = 0; -static const TypeInfo pnv_phb4_root_bus_info = { - .name = TYPE_PNV_PHB4_ROOT_BUS, - .parent = TYPE_PCIE_BUS, - .class_init = pnv_phb4_root_bus_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_PCIE_DEVICE }, - { } - }, -}; + if (strcmp(name, "phb-id") == 0) { + value = bus->phb_id; + } else { + value = bus->chip_id; + } -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); + visit_type_size(v, name, &value, errp); } -static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp) -{ - PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); - PCIDevice *pci = PCI_DEVICE(dev); - PCIBus *bus = pci_get_bus(pci); - PnvPHB4 *phb = NULL; - Error *local_err = NULL; +static void pnv_phb4_root_bus_set_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) - phb = (PnvPHB4 *) object_dynamic_cast(OBJECT(bus->qbus.parent), - TYPE_PNV_PHB4); +{ + PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj); + uint64_t value; - if (!phb) { - error_setg(errp, "%s must be connected to pnv-phb4 buses", dev->id); + if (!visit_type_size(v, name, &value, errp)) { return; } - /* Set unique chassis/slot values for the root port */ - qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id); - qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id); - - rpc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (strcmp(name, "phb-id") == 0) { + bus->phb_id = value; + } else { + bus->chip_id = value; } } -static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data) +static void pnv_phb4_root_bus_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, -}; + BusClass *k = BUS_CLASS(klass); -static void pnv_phb5_root_port_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + object_class_property_add(klass, "phb-id", "int", + pnv_phb4_root_bus_get_prop, + pnv_phb4_root_bus_set_prop, + NULL, NULL); - dc->desc = "IBM PHB5 PCIE Root Port"; - dc->user_creatable = false; + object_class_property_add(klass, "chip-id", "int", + pnv_phb4_root_bus_get_prop, + pnv_phb4_root_bus_set_prop, + NULL, NULL); - k->vendor_id = PCI_VENDOR_ID_IBM; - k->device_id = PNV_PHB5_DEVICE_ID; + /* + * PHB4 has only a single root complex. Enforce the limit on the + * parent bus + */ + k->max_dev = 1; } -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 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_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 6f1121a9489a..9871f462cd20 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/log.h" #include "target/ppc/cpu.h" #include "hw/ppc/fdt.h" @@ -116,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)); @@ -131,9 +129,6 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec, if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) { return; } - - /* Add a single Root port if running with defaults */ - pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), pecc->rp_model); } static void pnv_pec_realize(DeviceState *dev, Error **errp) @@ -151,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 */ @@ -216,11 +213,11 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt, } static Property pnv_pec_properties[] = { - DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0), - DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0), - DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP, - PnvChip *), - DEFINE_PROP_END_OF_LIST(), + DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0), + DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0), + DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP, + PnvChip *), + DEFINE_PROP_END_OF_LIST(), }; static uint32_t pnv_pec_xscom_pci_base(PnvPhb4PecState *pec) @@ -265,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 = { @@ -318,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/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 89c1b53dd72b..568849e93000 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -19,7 +19,7 @@ #include "hw/ppc/e500-ccsr.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "qemu/bswap.h" #include "qemu/module.h" diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index ab5a47aff560..20da1213747c 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -379,7 +379,8 @@ static void mch_update_smram(MCHPCIState *mch) memory_region_set_enabled(&mch->high_smram, false); } - if (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) { + if ((pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) && + (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME)) { switch (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) { case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB: diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c index 6e514f75eb8f..2c96ddf8fecd 100644 --- a/hw/pci-host/raven.c +++ b/hw/pci-host/raven.c @@ -24,12 +24,11 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "qemu/log.h" #include "qapi/error.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "hw/qdev-properties.h" diff --git a/hw/pci-host/remote.c b/hw/pci-host/remote.c index eee45444ef73..bfb25ef6af85 100644 --- a/hw/pci-host/remote.c +++ b/hw/pci-host/remote.c @@ -22,7 +22,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 719d6ca2a6de..77e7bbc65fcc 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -26,7 +26,7 @@ #include "hw/sysbus.h" #include "hw/sh4/sh.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "qemu/bswap.h" #include "qemu/module.h" diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 6e5d8d335525..437e66ff5036 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -34,3 +34,8 @@ unin_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 pnv_phb4_xive_notify(uint64_t notif_port, uint64_t data) "notif=@0x%"PRIx64" data=0x%"PRIx64 pnv_phb4_xive_notify_ic(uint64_t addr, uint64_t data) "addr=@0x%"PRIx64" data=0x%"PRIx64 pnv_phb4_xive_notify_abt(uint64_t notif_port, uint64_t data) "notif=@0x%"PRIx64" data=0x%"PRIx64 + +# dino.c +dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" +dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" +dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index d25b62d6a5b2..e3abe3c0f93b 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -24,10 +24,9 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/ppc/mac.h" #include "hw/qdev-properties.h" #include "qemu/module.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "hw/pci-host/uninorth.h" #include "trace.h" @@ -129,11 +128,10 @@ static void pci_unin_main_realize(DeviceState *dev, Error **errp) pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-pci"); - /* DEC 21154 bridge */ -#if 0 - /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */ - pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154"); -#endif + /* + * DEC 21154 bridge was unused for many years, this comment is + * a placeholder for whoever wishes to resurrect it + */ } static void pci_unin_main_init(Object *obj) diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index f66384fa02d8..0d50ea4cc057 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -12,7 +12,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "hw/qdev-properties.h" diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c index 38d5901a454f..c9ab7052f438 100644 --- a/hw/pci-host/xilinx-pcie.c +++ b/hw/pci-host/xilinx-pcie.c @@ -298,7 +298,6 @@ static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data) k->device_id = 0x7021; k->revision = 0; k->class_id = PCI_CLASS_BRIDGE_HOST; - k->is_bridge = true; k->realize = xilinx_pcie_root_realize; k->exit = pci_bridge_exitfn; dc->reset = pci_bridge_reset; diff --git a/hw/pci/meson.build b/hw/pci/meson.build index bcc9c75919f5..4fcd888b2749 100644 --- a/hw/pci/meson.build +++ b/hw/pci/meson.build @@ -5,6 +5,8 @@ pci_ss.add(files( 'pci.c', 'pci_bridge.c', 'pci_host.c', + 'pci-hmp-cmds.c', + 'pci-qmp-cmds.c', 'pcie_sriov.c', 'shpc.c', 'slotid_cap.c' @@ -13,6 +15,7 @@ pci_ss.add(files( # allow plugging PCIe devices into PCI buses, include them even if # CONFIG_PCI_EXPRESS=n. pci_ss.add(files('pcie.c', 'pcie_aer.c')) +pci_ss.add(files('pcie_doe.c')) softmmu_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: files('pcie_port.c', 'pcie_host.c')) softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss) diff --git a/hw/pci/msi.c b/hw/pci/msi.c index 47d2b0f33c66..1cadf150bcbe 100644 --- a/hw/pci/msi.c +++ b/hw/pci/msi.c @@ -134,7 +134,7 @@ void msi_set_message(PCIDevice *dev, MSIMessage msg) pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); } -MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) +static MSIMessage msi_prepare_message(PCIDevice *dev, unsigned int vector) { uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; @@ -159,6 +159,11 @@ MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) return msg; } +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) +{ + return dev->msi_prepare_message(dev, vector); +} + bool msi_enabled(const PCIDevice *dev) { return msi_present(dev) && @@ -241,6 +246,8 @@ int msi_init(struct PCIDevice *dev, uint8_t offset, 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); } + dev->msi_prepare_message = msi_prepare_message; + return 0; } @@ -256,6 +263,7 @@ void msi_uninit(struct PCIDevice *dev) cap_size = msi_cap_sizeof(flags); pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); dev->cap_present &= ~QEMU_PCI_CAP_MSI; + dev->msi_prepare_message = NULL; MSI_DEV_PRINTF(dev, "uninit\n"); } @@ -307,6 +315,38 @@ bool msi_is_masked(const PCIDevice *dev, unsigned int vector) return mask & (1U << vector); } +void msi_set_mask(PCIDevice *dev, int vector, bool mask, Error **errp) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; + uint32_t irq_state, vector_mask, pending; + + if (vector >= PCI_MSI_VECTORS_MAX) { + error_setg(errp, "msi: vector %d not allocated. max vector is %d", + vector, (PCI_MSI_VECTORS_MAX - 1)); + return; + } + + vector_mask = (1U << vector); + + irq_state = pci_get_long(dev->config + msi_mask_off(dev, msi64bit)); + + if (mask) { + irq_state |= vector_mask; + } else { + irq_state &= ~vector_mask; + } + + pci_set_long(dev->config + msi_mask_off(dev, msi64bit), irq_state); + + pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit)); + if (!mask && (pending & vector_mask)) { + pending &= ~vector_mask; + pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending); + msi_notify(dev, vector); + } +} + void msi_notify(PCIDevice *dev, unsigned int vector) { uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); @@ -334,11 +374,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector) void msi_send_message(PCIDevice *dev, MSIMessage msg) { - MemTxAttrs attrs = {}; - - attrs.requester_id = pci_requester_id(dev); - address_space_stl_le(&dev->bus_master_as, msg.address, msg.data, - attrs, NULL); + dev->msi_trigger(dev, msg); } /* Normally called by pci_default_write_config(). */ diff --git a/hw/pci/msix.c b/hw/pci/msix.c index ae9331cd0b45..9e70fcd6fa74 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -31,7 +31,7 @@ #define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) #define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) -MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) +static MSIMessage msix_prepare_message(PCIDevice *dev, unsigned vector) { uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; MSIMessage msg; @@ -41,6 +41,11 @@ MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) return msg; } +MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) +{ + return dev->msix_prepare_message(dev, vector); +} + /* * Special API for POWER to configure the vectors through * a side channel. Should never be used by devices. @@ -131,6 +136,26 @@ static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) } } +void msix_set_mask(PCIDevice *dev, int vector, bool mask) +{ + unsigned offset; + bool was_masked; + + assert(vector < dev->msix_entries_nr); + + offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; + + was_masked = msix_is_masked(dev, vector); + + if (mask) { + dev->msix_table[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; + } else { + dev->msix_table[offset] &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; + } + + msix_handle_mask_update(dev, vector, was_masked); +} + static bool msix_masked(PCIDevice *dev) { return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK; @@ -344,6 +369,8 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, "msix-pba", pba_size); memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); + dev->msix_prepare_message = msix_prepare_message; + return 0; } @@ -429,6 +456,7 @@ void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) g_free(dev->msix_entry_used); dev->msix_entry_used = NULL; dev->cap_present &= ~QEMU_PCI_CAP_MSIX; + dev->msix_prepare_message = NULL; } void msix_uninit_exclusive_bar(PCIDevice *dev) @@ -489,7 +517,9 @@ void msix_notify(PCIDevice *dev, unsigned vector) { MSIMessage msg; - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { + assert(vector < dev->msix_entries_nr); + + if (!dev->msix_entry_used[vector]) { return; } @@ -525,20 +555,17 @@ void msix_reset(PCIDevice *dev) * don't want to follow the spec suggestion can declare all vectors as used. */ /* Mark vector as used. */ -int msix_vector_use(PCIDevice *dev, unsigned vector) +void msix_vector_use(PCIDevice *dev, unsigned vector) { - if (vector >= dev->msix_entries_nr) { - return -EINVAL; - } - + assert(vector < dev->msix_entries_nr); dev->msix_entry_used[vector]++; - return 0; } /* Mark vector as unused. */ void msix_vector_unuse(PCIDevice *dev, unsigned vector) { - if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) { + assert(vector < dev->msix_entries_nr); + if (!dev->msix_entry_used[vector]) { return; } if (--dev->msix_entry_used[vector]) { diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c new file mode 100644 index 000000000000..b09fce937704 --- /dev/null +++ b/hw/pci/pci-hmp-cmds.c @@ -0,0 +1,239 @@ +/* + * HMP commands related to PCI + * + * Copyright IBM, Corp. 2011 + * + * 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. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "pci-internal.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qapi-commands-pci.h" +#include "qemu/cutils.h" + +static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) +{ + PciMemoryRegionList *region; + + monitor_printf(mon, " Bus %2" PRId64 ", ", dev->bus); + monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n", + dev->slot, dev->function); + monitor_printf(mon, " "); + + if (dev->class_info->desc) { + monitor_puts(mon, dev->class_info->desc); + } else { + monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class); + } + + monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n", + dev->id->vendor, dev->id->device); + if (dev->id->has_subsystem_vendor && dev->id->has_subsystem) { + monitor_printf(mon, " PCI subsystem %04" PRIx64 ":%04" PRIx64 "\n", + dev->id->subsystem_vendor, dev->id->subsystem); + } + + if (dev->has_irq) { + monitor_printf(mon, " IRQ %" PRId64 ", pin %c\n", + dev->irq, (char)('A' + dev->irq_pin - 1)); + } + + if (dev->pci_bridge) { + monitor_printf(mon, " BUS %" PRId64 ".\n", + dev->pci_bridge->bus->number); + monitor_printf(mon, " secondary bus %" PRId64 ".\n", + dev->pci_bridge->bus->secondary); + monitor_printf(mon, " subordinate bus %" PRId64 ".\n", + dev->pci_bridge->bus->subordinate); + + monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n", + dev->pci_bridge->bus->io_range->base, + dev->pci_bridge->bus->io_range->limit); + + monitor_printf(mon, + " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n", + dev->pci_bridge->bus->memory_range->base, + dev->pci_bridge->bus->memory_range->limit); + + monitor_printf(mon, " prefetchable memory range " + "[0x%08"PRIx64", 0x%08"PRIx64"]\n", + dev->pci_bridge->bus->prefetchable_range->base, + dev->pci_bridge->bus->prefetchable_range->limit); + } + + for (region = dev->regions; region; region = region->next) { + uint64_t addr, size; + + addr = region->value->address; + size = region->value->size; + + monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar); + + if (!strcmp(region->value->type, "io")) { + monitor_printf(mon, "I/O at 0x%04" PRIx64 + " [0x%04" PRIx64 "].\n", + addr, addr + size - 1); + } else { + monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64 + " [0x%08" PRIx64 "].\n", + region->value->mem_type_64 ? 64 : 32, + region->value->prefetch ? " prefetchable" : "", + addr, addr + size - 1); + } + } + + monitor_printf(mon, " id \"%s\"\n", dev->qdev_id); + + if (dev->pci_bridge) { + if (dev->pci_bridge->has_devices) { + PciDeviceInfoList *cdev; + for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) { + hmp_info_pci_device(mon, cdev->value); + } + } + } +} + +void hmp_info_pci(Monitor *mon, const QDict *qdict) +{ + PciInfoList *info_list, *info; + + info_list = qmp_query_pci(&error_abort); + + for (info = info_list; info; info = info->next) { + PciDeviceInfoList *dev; + + for (dev = info->value->devices; dev; dev = dev->next) { + hmp_info_pci_device(mon, dev->value); + } + } + + qapi_free_PciInfoList(info_list); +} + +void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) +{ + PCIDevice *d = (PCIDevice *)dev; + int class = pci_get_word(d->config + PCI_CLASS_DEVICE); + const pci_class_desc *desc = get_class_desc(class); + char ctxt[64]; + PCIIORegion *r; + int i; + + if (desc->desc) { + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); + } else { + snprintf(ctxt, sizeof(ctxt), "Class %04x", class); + } + + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " + "pci id %04x:%04x (sub %04x:%04x)\n", + indent, "", ctxt, pci_dev_bus_num(d), + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), + pci_get_word(d->config + PCI_VENDOR_ID), + pci_get_word(d->config + PCI_DEVICE_ID), + pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), + pci_get_word(d->config + PCI_SUBSYSTEM_ID)); + for (i = 0; i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + if (!r->size) { + continue; + } + monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS + " [0x%"FMT_PCIBUS"]\n", + indent, "", + i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", + r->addr, r->addr + r->size - 1); + } +} + +void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *id = qdict_get_str(qdict, "id"); + const char *error_name; + uint32_t error_status; + unsigned int num; + bool correctable; + PCIDevice *dev; + PCIEAERErr aer_err; + int ret; + + ret = pci_qdev_find_device(id, &dev); + if (ret == -ENODEV) { + error_setg(&err, "device '%s' not found", id); + goto out; + } + if (ret < 0 || !pci_is_express(dev)) { + error_setg(&err, "device '%s' is not a PCIe device", id); + goto out; + } + + error_name = qdict_get_str(qdict, "error_status"); + if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { + if (qemu_strtoui(error_name, NULL, 0, &num) < 0) { + error_setg(&err, "invalid error status value '%s'", error_name); + goto out; + } + error_status = num; + correctable = qdict_get_try_bool(qdict, "correctable", false); + } else { + if (qdict_haskey(qdict, "correctable")) { + error_setg(&err, "-c is only valid with numeric error status"); + goto out; + } + } + aer_err.status = error_status; + aer_err.source_id = pci_requester_id(dev); + + aer_err.flags = 0; + if (correctable) { + aer_err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; + } + if (qdict_get_try_bool(qdict, "advisory_non_fatal", false)) { + aer_err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; + } + if (qdict_haskey(qdict, "header0")) { + aer_err.flags |= PCIE_AER_ERR_HEADER_VALID; + } + if (qdict_haskey(qdict, "prefix0")) { + aer_err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; + } + + aer_err.header[0] = qdict_get_try_int(qdict, "header0", 0); + aer_err.header[1] = qdict_get_try_int(qdict, "header1", 0); + aer_err.header[2] = qdict_get_try_int(qdict, "header2", 0); + aer_err.header[3] = qdict_get_try_int(qdict, "header3", 0); + + aer_err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); + aer_err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); + aer_err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); + aer_err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); + + ret = pcie_aer_inject_error(dev, &aer_err); + if (ret < 0) { + error_setg_errno(&err, -ret, "failed to inject error"); + goto out; + } + + + monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n", + id, pci_root_bus_path(dev), pci_dev_bus_num(dev), + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + +out: + hmp_handle_error(mon, err); +} diff --git a/hw/pci/pci-internal.h b/hw/pci/pci-internal.h new file mode 100644 index 000000000000..2ea356bdf51d --- /dev/null +++ b/hw/pci/pci-internal.h @@ -0,0 +1,25 @@ +#ifndef HW_PCI_PCI_INTERNAL_H +#define HW_PCI_PCI_INTERNAL_H + +#include "qemu/queue.h" + +typedef struct { + uint16_t class; + const char *desc; + const char *fw_name; + uint16_t fw_ign_bits; +} pci_class_desc; + +typedef QLIST_HEAD(, PCIHostState) PCIHostStateList; + +extern PCIHostStateList pci_host_bridges; + +const pci_class_desc *get_class_desc(int class); +PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); +void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); + +int pcie_aer_parse_error_string(const char *error_name, + uint32_t *status, bool *correctable); +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); + +#endif diff --git a/hw/pci/pci-qmp-cmds.c b/hw/pci/pci-qmp-cmds.c new file mode 100644 index 000000000000..5d9f4817f50c --- /dev/null +++ b/hw/pci/pci-qmp-cmds.c @@ -0,0 +1,199 @@ +/* + * QMP commands related to PCI + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" +#include "pci-internal.h" +#include "qapi/qapi-commands-pci.h" + +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); + +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) +{ + PciMemoryRegionList *head = NULL, **tail = &head; + int i; + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + const PCIIORegion *r = &dev->io_regions[i]; + PciMemoryRegion *region; + + if (!r->size) { + continue; + } + + region = g_malloc0(sizeof(*region)); + + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { + region->type = g_strdup("io"); + } else { + region->type = g_strdup("memory"); + region->has_prefetch = true; + region->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); + region->has_mem_type_64 = true; + region->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); + } + + region->bar = i; + region->address = r->addr; + region->size = r->size; + + QAPI_LIST_APPEND(tail, region); + } + + return head; +} + +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, + int bus_num) +{ + PciBridgeInfo *info; + PciMemoryRange *range; + + info = g_new0(PciBridgeInfo, 1); + + info->bus = g_new0(PciBusInfo, 1); + info->bus->number = dev->config[PCI_PRIMARY_BUS]; + info->bus->secondary = dev->config[PCI_SECONDARY_BUS]; + info->bus->subordinate = dev->config[PCI_SUBORDINATE_BUS]; + + range = info->bus->io_range = g_new0(PciMemoryRange, 1); + range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); + range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); + + range = info->bus->memory_range = g_new0(PciMemoryRange, 1); + range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); + range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); + + range = info->bus->prefetchable_range = g_new0(PciMemoryRange, 1); + range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); + range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); + + if (dev->config[PCI_SECONDARY_BUS] != 0) { + PCIBus *child_bus = pci_find_bus_nr(bus, + dev->config[PCI_SECONDARY_BUS]); + if (child_bus) { + info->has_devices = true; + info->devices = qmp_query_pci_devices(child_bus, + dev->config[PCI_SECONDARY_BUS]); + } + } + + return info; +} + +static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, + int bus_num) +{ + const pci_class_desc *desc; + PciDeviceInfo *info; + uint8_t type; + int class; + + info = g_new0(PciDeviceInfo, 1); + info->bus = bus_num; + info->slot = PCI_SLOT(dev->devfn); + info->function = PCI_FUNC(dev->devfn); + + info->class_info = g_new0(PciDeviceClass, 1); + class = pci_get_word(dev->config + PCI_CLASS_DEVICE); + info->class_info->q_class = class; + desc = get_class_desc(class); + if (desc->desc) { + info->class_info->desc = g_strdup(desc->desc); + } + + info->id = g_new0(PciDeviceId, 1); + info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID); + info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID); + info->regions = qmp_query_pci_regions(dev); + info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); + + info->irq_pin = dev->config[PCI_INTERRUPT_PIN]; + if (dev->config[PCI_INTERRUPT_PIN] != 0) { + info->has_irq = true; + info->irq = dev->config[PCI_INTERRUPT_LINE]; + } + + type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; + if (type == PCI_HEADER_TYPE_BRIDGE) { + info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); + } else if (type == PCI_HEADER_TYPE_NORMAL) { + info->id->has_subsystem = info->id->has_subsystem_vendor = true; + info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID); + info->id->subsystem_vendor = + pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID); + } else if (type == PCI_HEADER_TYPE_CARDBUS) { + info->id->has_subsystem = info->id->has_subsystem_vendor = true; + info->id->subsystem = pci_get_word(dev->config + PCI_CB_SUBSYSTEM_ID); + info->id->subsystem_vendor = + pci_get_word(dev->config + PCI_CB_SUBSYSTEM_VENDOR_ID); + } + + return info; +} + +static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) +{ + PciDeviceInfoList *head = NULL, **tail = &head; + PCIDevice *dev; + int devfn; + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + dev = bus->devices[devfn]; + if (dev) { + QAPI_LIST_APPEND(tail, qmp_query_pci_device(dev, bus, bus_num)); + } + } + + return head; +} + +static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) +{ + PciInfo *info = NULL; + + bus = pci_find_bus_nr(bus, bus_num); + if (bus) { + info = g_malloc0(sizeof(*info)); + info->bus = bus_num; + info->devices = qmp_query_pci_devices(bus, bus_num); + } + + return info; +} + +PciInfoList *qmp_query_pci(Error **errp) +{ + PciInfoList *head = NULL, **tail = &head; + PCIHostState *host_bridge; + + QLIST_FOREACH(host_bridge, &pci_host_bridges, next) { + QAPI_LIST_APPEND(tail, + qmp_query_pci_bus(host_bridge->bus, + pci_bus_num(host_bridge->bus))); + } + + return head; +} diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c index 3a027c42e43b..f0508682d2b8 100644 --- a/hw/pci/pci-stub.c +++ b/hw/pci/pci-stub.c @@ -19,11 +19,9 @@ */ #include "qemu/osdep.h" -#include "sysemu/sysemu.h" #include "monitor/monitor.h" -#include "qapi/error.h" +#include "monitor/hmp.h" #include "qapi/qapi-commands-pci.h" -#include "qapi/qmp/qerror.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" @@ -33,10 +31,13 @@ bool pci_available; PciInfoList *qmp_query_pci(Error **errp) { - error_setg(errp, QERR_UNSUPPORTED); return NULL; } +void hmp_info_pci(Monitor *mon, const QDict *qdict) +{ +} + void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "PCI devices not supported\n"); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index dae9119bfe5f..c2fb88f9a3a9 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "hw/irq.h" @@ -35,7 +34,6 @@ #include "hw/qdev-properties-system.h" #include "migration/qemu-file-types.h" #include "migration/vmstate.h" -#include "monitor/monitor.h" #include "net/net.h" #include "sysemu/numa.h" #include "sysemu/sysemu.h" @@ -48,8 +46,8 @@ #include "hw/hotplug.h" #include "hw/boards.h" #include "qapi/error.h" -#include "qapi/qapi-commands-pci.h" #include "qemu/cutils.h" +#include "pci-internal.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -60,7 +58,6 @@ bool pci_available = true; -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); static void pcibus_reset(BusState *qbus); @@ -201,6 +198,11 @@ static const TypeInfo pci_bus_info = { .class_init = pci_bus_class_init, }; +static const TypeInfo cxl_interface_info = { + .name = INTERFACE_CXL_DEVICE, + .parent = TYPE_INTERFACE, +}; + static const TypeInfo pcie_interface_info = { .name = INTERFACE_PCIE_DEVICE, .parent = TYPE_INTERFACE, @@ -224,7 +226,12 @@ static const TypeInfo pcie_bus_info = { .class_init = pcie_bus_class_init, }; -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); +static const TypeInfo cxl_bus_info = { + .name = TYPE_CXL_BUS, + .parent = TYPE_PCIE_BUS, + .class_init = pcie_bus_class_init, +}; + static void pci_update_mappings(PCIDevice *d); static void pci_irq_handler(void *opaque, int irq_num, int level); static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, Error **); @@ -233,7 +240,7 @@ static void pci_del_option_rom(PCIDevice *pdev); static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; -static QLIST_HEAD(, PCIHostState) pci_host_bridges; +PCIHostStateList pci_host_bridges; int pci_bar(PCIDevice *d, int reg) { @@ -307,6 +314,15 @@ void pci_device_deassert_intx(PCIDevice *dev) } } +static void pci_msi_trigger(PCIDevice *dev, MSIMessage msg) +{ + MemTxAttrs attrs = {}; + + attrs.requester_id = pci_requester_id(dev); + address_space_stl_le(&dev->bus_master_as, msg.address, msg.data, + attrs, NULL); +} + static void pci_reset_regions(PCIDevice *dev) { int r; @@ -359,14 +375,14 @@ static void pci_do_device_reset(PCIDevice *dev) */ void pci_device_reset(PCIDevice *dev) { - qdev_reset_all(&dev->qdev); + device_cold_reset(&dev->qdev); pci_do_device_reset(dev); } /* * Trigger pci bus reset under a given bus. - * Called via qbus_reset_all on RST# assert, after the devices - * have been reset qdev_reset_all-ed already. + * Called via bus_cold_reset on RST# assert, after the devices + * have been reset device_cold_reset-ed already. */ static void pcibus_reset(BusState *qbus) { @@ -557,7 +573,7 @@ void pci_bus_range(PCIBus *bus, int *min_bus, int *max_bus) for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { PCIDevice *dev = bus->devices[i]; - if (dev && PCI_DEVICE_GET_CLASS(dev)->is_bridge) { + if (dev && IS_PCI_BRIDGE(dev)) { *min_bus = MIN(*min_bus, dev->config[PCI_SECONDARY_BUS]); *max_bus = MAX(*max_bus, dev->config[PCI_SUBORDINATE_BUS]); } @@ -573,7 +589,6 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size, const VMStateField *field) { PCIDevice *s = container_of(pv, PCIDevice, config); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(s); uint8_t *config; int i; @@ -595,9 +610,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size, memcpy(s->config, config, size); pci_update_mappings(s); - if (pc->is_bridge) { - PCIBridge *b = PCI_BRIDGE(s); - pci_bridge_update_mappings(b); + if (IS_PCI_BRIDGE(s)) { + pci_bridge_update_mappings(PCI_BRIDGE(s)); } memory_region_set_enabled(&s->bus_master_enable_region, @@ -1071,9 +1085,10 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, Error *local_err = NULL; DeviceState *dev = DEVICE(pci_dev); PCIBus *bus = pci_get_bus(pci_dev); + bool is_bridge = IS_PCI_BRIDGE(pci_dev); /* Only pci bridges can be attached to extra PCI root buses */ - if (pci_bus_is_root(bus) && bus->parent_dev && !pc->is_bridge) { + if (pci_bus_is_root(bus) && bus->parent_dev && !is_bridge) { error_setg(errp, "PCI: Only PCI/PCIe bridges can be plugged into %s", bus->parent_dev->name); @@ -1135,7 +1150,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, pci_config_set_revision(pci_dev->config, pc->revision); pci_config_set_class(pci_dev->config, pc->class_id); - if (!pc->is_bridge) { + if (!is_bridge) { if (pc->subsystem_vendor_id || pc->subsystem_id) { pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, pc->subsystem_vendor_id); @@ -1152,7 +1167,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, pci_init_cmask(pci_dev); pci_init_wmask(pci_dev); pci_init_w1cmask(pci_dev); - if (pc->is_bridge) { + if (is_bridge) { pci_init_mask_bridge(pci_dev); } pci_init_multifunction(bus, pci_dev, &local_err); @@ -1202,6 +1217,8 @@ static void pci_qdev_unrealize(DeviceState *dev) pci_device_deassert_intx(pci_dev); do_pci_unregister_device(pci_dev); + + pci_dev->msi_trigger = NULL; } void pci_register_bar(PCIDevice *pci_dev, int region_num, @@ -1641,13 +1658,6 @@ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) /***********************************************************/ /* monitor info on PCI */ -typedef struct { - uint16_t class; - const char *desc; - const char *fw_name; - uint16_t fw_ign_bits; -} pci_class_desc; - static const pci_class_desc pci_class_descriptions[] = { { 0x0001, "VGA controller", "display"}, @@ -1755,7 +1765,7 @@ void pci_for_each_device(PCIBus *bus, int bus_num, } } -static const pci_class_desc *get_class_desc(int class) +const pci_class_desc *get_class_desc(int class) { const pci_class_desc *desc; @@ -1767,176 +1777,6 @@ static const pci_class_desc *get_class_desc(int class) return desc; } -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); - -static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev) -{ - PciMemoryRegionList *head = NULL, **tail = &head; - int i; - - for (i = 0; i < PCI_NUM_REGIONS; i++) { - const PCIIORegion *r = &dev->io_regions[i]; - PciMemoryRegion *region; - - if (!r->size) { - continue; - } - - region = g_malloc0(sizeof(*region)); - - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - region->type = g_strdup("io"); - } else { - region->type = g_strdup("memory"); - region->has_prefetch = true; - region->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH); - region->has_mem_type_64 = true; - region->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); - } - - region->bar = i; - region->address = r->addr; - region->size = r->size; - - QAPI_LIST_APPEND(tail, region); - } - - return head; -} - -static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, - int bus_num) -{ - PciBridgeInfo *info; - PciMemoryRange *range; - - info = g_new0(PciBridgeInfo, 1); - - info->bus = g_new0(PciBusInfo, 1); - info->bus->number = dev->config[PCI_PRIMARY_BUS]; - info->bus->secondary = dev->config[PCI_SECONDARY_BUS]; - info->bus->subordinate = dev->config[PCI_SUBORDINATE_BUS]; - - range = info->bus->io_range = g_new0(PciMemoryRange, 1); - range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); - range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); - - range = info->bus->memory_range = g_new0(PciMemoryRange, 1); - range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); - range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); - - range = info->bus->prefetchable_range = g_new0(PciMemoryRange, 1); - range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); - range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); - - if (dev->config[PCI_SECONDARY_BUS] != 0) { - PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]); - if (child_bus) { - info->has_devices = true; - info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]); - } - } - - return info; -} - -static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, - int bus_num) -{ - const pci_class_desc *desc; - PciDeviceInfo *info; - uint8_t type; - int class; - - info = g_new0(PciDeviceInfo, 1); - info->bus = bus_num; - info->slot = PCI_SLOT(dev->devfn); - info->function = PCI_FUNC(dev->devfn); - - info->class_info = g_new0(PciDeviceClass, 1); - class = pci_get_word(dev->config + PCI_CLASS_DEVICE); - info->class_info->q_class = class; - desc = get_class_desc(class); - if (desc->desc) { - info->class_info->has_desc = true; - info->class_info->desc = g_strdup(desc->desc); - } - - info->id = g_new0(PciDeviceId, 1); - info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID); - info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID); - info->regions = qmp_query_pci_regions(dev); - info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); - - info->irq_pin = dev->config[PCI_INTERRUPT_PIN]; - if (dev->config[PCI_INTERRUPT_PIN] != 0) { - info->has_irq = true; - info->irq = dev->config[PCI_INTERRUPT_LINE]; - } - - type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; - if (type == PCI_HEADER_TYPE_BRIDGE) { - info->has_pci_bridge = true; - info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); - } else if (type == PCI_HEADER_TYPE_NORMAL) { - info->id->has_subsystem = info->id->has_subsystem_vendor = true; - info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID); - info->id->subsystem_vendor = - pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID); - } else if (type == PCI_HEADER_TYPE_CARDBUS) { - info->id->has_subsystem = info->id->has_subsystem_vendor = true; - info->id->subsystem = pci_get_word(dev->config + PCI_CB_SUBSYSTEM_ID); - info->id->subsystem_vendor = - pci_get_word(dev->config + PCI_CB_SUBSYSTEM_VENDOR_ID); - } - - return info; -} - -static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num) -{ - PciDeviceInfoList *head = NULL, **tail = &head; - PCIDevice *dev; - int devfn; - - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - dev = bus->devices[devfn]; - if (dev) { - QAPI_LIST_APPEND(tail, qmp_query_pci_device(dev, bus, bus_num)); - } - } - - return head; -} - -static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) -{ - PciInfo *info = NULL; - - bus = pci_find_bus_nr(bus, bus_num); - if (bus) { - info = g_malloc0(sizeof(*info)); - info->bus = bus_num; - info->devices = qmp_query_pci_devices(bus, bus_num); - } - - return info; -} - -PciInfoList *qmp_query_pci(Error **errp) -{ - PciInfoList *head = NULL, **tail = &head; - PCIHostState *host_bridge; - - QLIST_FOREACH(host_bridge, &pci_host_bridges, next) { - QAPI_LIST_APPEND(tail, - qmp_query_pci_bus(host_bridge->bus, - pci_bus_num(host_bridge->bus))); - } - - return head; -} - /* Initialize a PCI NIC. */ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, const char *default_model, @@ -2038,6 +1878,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, PCIDevice *pci_vga_init(PCIBus *bus) { + vga_interface_created = true; switch (vga_interface_type) { case VGA_CIRRUS: return pci_create_simple(bus, -1, "cirrus-vga"); @@ -2074,7 +1915,7 @@ static bool pci_root_bus_in_range(PCIBus *bus, int bus_num) for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { PCIDevice *dev = bus->devices[i]; - if (dev && PCI_DEVICE_GET_CLASS(dev)->is_bridge) { + if (dev && IS_PCI_BRIDGE(dev)) { if (pci_secondary_bus_in_range(dev, bus_num)) { return true; } @@ -2084,7 +1925,7 @@ static bool pci_root_bus_in_range(PCIBus *bus, int bus_num) return false; } -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) +PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) { PCIBus *sec; @@ -2182,6 +2023,10 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; } + if (object_class_dynamic_cast(klass, INTERFACE_CXL_DEVICE)) { + pci_dev->cap_present |= QEMU_PCIE_CAP_CXL; + } + pci_dev = do_pci_register_device(pci_dev, object_get_typename(OBJECT(qdev)), pci_dev->devfn, errp); @@ -2236,6 +2081,8 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) } pci_set_power(pci_dev, true); + + pci_dev->msi_trigger = pci_msi_trigger; } PCIDevice *pci_new_multifunction(int devfn, bool multifunction, @@ -2556,44 +2403,6 @@ uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) return pci_find_capability_list(pdev, cap_id, NULL); } -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) -{ - PCIDevice *d = (PCIDevice *)dev; - const pci_class_desc *desc; - char ctxt[64]; - PCIIORegion *r; - int i, class; - - class = pci_get_word(d->config + PCI_CLASS_DEVICE); - desc = pci_class_descriptions; - while (desc->desc && class != desc->class) - desc++; - if (desc->desc) { - snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); - } else { - snprintf(ctxt, sizeof(ctxt), "Class %04x", class); - } - - monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " - "pci id %04x:%04x (sub %04x:%04x)\n", - indent, "", ctxt, pci_dev_bus_num(d), - PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), - pci_get_word(d->config + PCI_VENDOR_ID), - pci_get_word(d->config + PCI_DEVICE_ID), - pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID), - pci_get_word(d->config + PCI_SUBSYSTEM_ID)); - for (i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (!r->size) - continue; - monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS - " [0x%"FMT_PCIBUS"]\n", - indent, "", - i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem", - r->addr, r->addr + r->size - 1); - } -} - static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) { PCIDevice *d = (PCIDevice *)dev; @@ -2625,15 +2434,15 @@ static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) static char *pcibus_get_fw_dev_path(DeviceState *dev) { PCIDevice *d = (PCIDevice *)dev; - char path[50], name[33]; - int off; + char name[33]; + int has_func = !!PCI_FUNC(d->devfn); - off = snprintf(path, sizeof(path), "%s@%x", - pci_dev_fw_name(dev, name, sizeof name), - PCI_SLOT(d->devfn)); - if (PCI_FUNC(d->devfn)) - snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn)); - return g_strdup(path); + return g_strdup_printf("%s@%x%s%.*x", + pci_dev_fw_name(dev, name, sizeof(name)), + PCI_SLOT(d->devfn), + has_func ? "," : "", + has_func, + PCI_FUNC(d->devfn)); } static char *pcibus_get_dev_path(DeviceState *dev) @@ -2747,7 +2556,9 @@ static void pci_device_class_base_init(ObjectClass *klass, void *data) object_class_dynamic_cast(klass, INTERFACE_CONVENTIONAL_PCI_DEVICE); ObjectClass *pcie = object_class_dynamic_cast(klass, INTERFACE_PCIE_DEVICE); - assert(conventional || pcie); + ObjectClass *cxl = + object_class_dynamic_cast(klass, INTERFACE_CXL_DEVICE); + assert(conventional || pcie || cxl); } } @@ -2811,7 +2622,6 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) { Range *range = opaque; - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); uint16_t cmd = pci_get_word(dev->config + PCI_COMMAND); int i; @@ -2819,7 +2629,7 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) return; } - if (pc->is_bridge) { + if (IS_PCI_BRIDGE(dev)) { pcibus_t base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); pcibus_t limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); @@ -2937,7 +2747,9 @@ static void pci_register_types(void) { type_register_static(&pci_bus_info); type_register_static(&pcie_bus_info); + type_register_static(&cxl_bus_info); type_register_static(&conventional_pci_interface_info); + type_register_static(&cxl_interface_info); type_register_static(&pcie_interface_info); type_register_static(&pci_device_type_info); } diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index da34c8ebcd18..b2b180edd61a 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -275,7 +275,7 @@ void pci_bridge_write_config(PCIDevice *d, newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { /* Trigger hot reset on 0->1 transition. */ - qbus_reset_all(BUS(&s->sec_bus)); + bus_cold_reset(BUS(&s->sec_bus)); } } diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 67a5d67372e4..68a62da0b570 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -353,7 +353,7 @@ static void hotplug_event_notify(PCIDevice *dev) msix_notify(dev, pcie_cap_flags_get_vector(dev)); } else if (msi_enabled(dev)) { msi_notify(dev, pcie_cap_flags_get_vector(dev)); - } else { + } else if (pci_intx(dev) != -1) { pci_set_irq(dev, dev->exp.hpev_notified); } } @@ -361,7 +361,8 @@ static void hotplug_event_notify(PCIDevice *dev) static void hotplug_event_clear(PCIDevice *dev) { hotplug_event_update_event_status(dev); - if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) { + if (!msix_enabled(dev) && !msi_enabled(dev) && pci_intx(dev) != -1 && + !dev->exp.hpev_notified) { pci_irq_deassert(dev); } } diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index e1a8a88c8c08..9a19be44ae5a 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -19,17 +19,14 @@ */ #include "qemu/osdep.h" -#include "sysemu/sysemu.h" -#include "qapi/qmp/qdict.h" #include "migration/vmstate.h" -#include "monitor/monitor.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pcie.h" #include "hw/pci/msix.h" #include "hw/pci/msi.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pcie_regs.h" -#include "qapi/error.h" +#include "pci-internal.h" //#define DEBUG_PCIE #ifdef DEBUG_PCIE @@ -44,13 +41,6 @@ #define PCI_ERR_SRC_COR_OFFS 0 #define PCI_ERR_SRC_UNCOR_OFFS 2 -typedef struct PCIEErrorDetails { - const char *id; - const char *root_bus; - int bus; - int devfn; -} PCIEErrorDetails; - /* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ static uint32_t pcie_aer_uncor_default_severity(uint32_t status) { @@ -290,7 +280,7 @@ static void pcie_aer_root_notify(PCIDevice *dev) msix_notify(dev, pcie_aer_root_get_vector(dev)); } else if (msi_enabled(dev)) { msi_notify(dev, pcie_aer_root_get_vector(dev)); - } else { + } else if (pci_intx(dev) != -1) { pci_irq_assert(dev); } } @@ -323,7 +313,7 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) */ } - /* Errro Message Received: Root Error Status register */ + /* Error Message Received: Root Error Status register */ switch (msg->severity) { case PCI_ERR_ROOT_CMD_COR_EN: if (root_status & PCI_ERR_ROOT_COR_RCV) { @@ -631,7 +621,7 @@ static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) * Figure 6-2: Flowchart Showing Sequence of Device Error Signaling and Logging * Operations */ -static int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) { uint8_t *aer_cap = NULL; uint16_t devctl = 0; @@ -933,8 +923,8 @@ static const struct PCIEAERErrorName pcie_aer_error_list[] = { }, }; -static int pcie_aer_parse_error_string(const char *error_name, - uint32_t *status, bool *correctable) +int pcie_aer_parse_error_string(const char *error_name, + uint32_t *status, bool *correctable) { int i; @@ -950,98 +940,3 @@ static int pcie_aer_parse_error_string(const char *error_name, } return -EINVAL; } - -/* - * Inject an error described by @qdict. - * On success, set @details to show where error was sent. - * Return negative errno if injection failed and a message was emitted. - */ -static int do_pcie_aer_inject_error(Monitor *mon, - const QDict *qdict, - PCIEErrorDetails *details) -{ - const char *id = qdict_get_str(qdict, "id"); - const char *error_name; - uint32_t error_status; - bool correctable; - PCIDevice *dev; - PCIEAERErr err; - int ret; - - ret = pci_qdev_find_device(id, &dev); - if (ret < 0) { - monitor_printf(mon, - "id or pci device path is invalid or device not " - "found. %s\n", id); - return ret; - } - if (!pci_is_express(dev)) { - monitor_printf(mon, "the device doesn't support pci express. %s\n", - id); - return -ENOSYS; - } - - error_name = qdict_get_str(qdict, "error_status"); - if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) { - char *e = NULL; - error_status = strtoul(error_name, &e, 0); - correctable = qdict_get_try_bool(qdict, "correctable", false); - if (!e || *e != '\0') { - monitor_printf(mon, "invalid error status value. \"%s\"", - error_name); - return -EINVAL; - } - } - err.status = error_status; - err.source_id = pci_requester_id(dev); - - err.flags = 0; - if (correctable) { - err.flags |= PCIE_AER_ERR_IS_CORRECTABLE; - } - if (qdict_get_try_bool(qdict, "advisory_non_fatal", false)) { - err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY; - } - if (qdict_haskey(qdict, "header0")) { - err.flags |= PCIE_AER_ERR_HEADER_VALID; - } - if (qdict_haskey(qdict, "prefix0")) { - err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT; - } - - err.header[0] = qdict_get_try_int(qdict, "header0", 0); - err.header[1] = qdict_get_try_int(qdict, "header1", 0); - err.header[2] = qdict_get_try_int(qdict, "header2", 0); - err.header[3] = qdict_get_try_int(qdict, "header3", 0); - - err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0); - err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0); - err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0); - err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0); - - ret = pcie_aer_inject_error(dev, &err); - if (ret < 0) { - monitor_printf(mon, "failed to inject error: %s\n", - strerror(-ret)); - return ret; - } - details->id = id; - details->root_bus = pci_root_bus_path(dev); - details->bus = pci_dev_bus_num(dev); - details->devfn = dev->devfn; - - return 0; -} - -void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) -{ - PCIEErrorDetails data; - - if (do_pcie_aer_inject_error(mon, qdict, &data) < 0) { - return; - } - - monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n", - data.id, data.root_bus, data.bus, - PCI_SLOT(data.devfn), PCI_FUNC(data.devfn)); -} diff --git a/hw/pci/pcie_doe.c b/hw/pci/pcie_doe.c new file mode 100644 index 000000000000..2210f8696812 --- /dev/null +++ b/hw/pci/pcie_doe.c @@ -0,0 +1,367 @@ +/* + * PCIe Data Object Exchange + * + * Copyright (C) 2021 Avery Design Systems, 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 "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qemu/range.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie.h" +#include "hw/pci/pcie_doe.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" + +#define DWORD_BYTE 4 + +typedef struct DoeDiscoveryReq { + DOEHeader header; + uint8_t index; + uint8_t reserved[3]; +} QEMU_PACKED DoeDiscoveryReq; + +typedef struct DoeDiscoveryRsp { + DOEHeader header; + uint16_t vendor_id; + uint8_t data_obj_type; + uint8_t next_index; +} QEMU_PACKED DoeDiscoveryRsp; + +static bool pcie_doe_discovery(DOECap *doe_cap) +{ + DoeDiscoveryReq *req = pcie_doe_get_write_mbox_ptr(doe_cap); + DoeDiscoveryRsp rsp; + uint8_t index = req->index; + DOEProtocol *prot; + + /* Discard request if length does not match DoeDiscoveryReq */ + if (pcie_doe_get_obj_len(req) < + DIV_ROUND_UP(sizeof(DoeDiscoveryReq), DWORD_BYTE)) { + return false; + } + + rsp.header = (DOEHeader) { + .vendor_id = PCI_VENDOR_ID_PCI_SIG, + .data_obj_type = PCI_SIG_DOE_DISCOVERY, + .length = DIV_ROUND_UP(sizeof(DoeDiscoveryRsp), DWORD_BYTE), + }; + + /* Point to the requested protocol, index 0 must be Discovery */ + if (index == 0) { + rsp.vendor_id = PCI_VENDOR_ID_PCI_SIG; + rsp.data_obj_type = PCI_SIG_DOE_DISCOVERY; + } else { + if (index < doe_cap->protocol_num) { + prot = &doe_cap->protocols[index - 1]; + rsp.vendor_id = prot->vendor_id; + rsp.data_obj_type = prot->data_obj_type; + } else { + rsp.vendor_id = 0xFFFF; + rsp.data_obj_type = 0xFF; + } + } + + if (index + 1 == doe_cap->protocol_num) { + rsp.next_index = 0; + } else { + rsp.next_index = index + 1; + } + + pcie_doe_set_rsp(doe_cap, &rsp); + + return true; +} + +static void pcie_doe_reset_mbox(DOECap *st) +{ + st->read_mbox_idx = 0; + st->read_mbox_len = 0; + st->write_mbox_len = 0; + + memset(st->read_mbox, 0, PCI_DOE_DW_SIZE_MAX * DWORD_BYTE); + memset(st->write_mbox, 0, PCI_DOE_DW_SIZE_MAX * DWORD_BYTE); +} + +void pcie_doe_init(PCIDevice *dev, DOECap *doe_cap, uint16_t offset, + DOEProtocol *protocols, bool intr, uint16_t vec) +{ + pcie_add_capability(dev, PCI_EXT_CAP_ID_DOE, 0x1, offset, + PCI_DOE_SIZEOF); + + doe_cap->pdev = dev; + doe_cap->offset = offset; + + if (intr && (msi_present(dev) || msix_present(dev))) { + doe_cap->cap.intr = intr; + doe_cap->cap.vec = vec; + } + + doe_cap->write_mbox = g_malloc0(PCI_DOE_DW_SIZE_MAX * DWORD_BYTE); + doe_cap->read_mbox = g_malloc0(PCI_DOE_DW_SIZE_MAX * DWORD_BYTE); + + pcie_doe_reset_mbox(doe_cap); + + doe_cap->protocols = protocols; + for (; protocols->vendor_id; protocols++) { + doe_cap->protocol_num++; + } + assert(doe_cap->protocol_num < PCI_DOE_PROTOCOL_NUM_MAX); + + /* Increment to allow for the discovery protocol */ + doe_cap->protocol_num++; +} + +void pcie_doe_fini(DOECap *doe_cap) +{ + g_free(doe_cap->read_mbox); + g_free(doe_cap->write_mbox); + g_free(doe_cap); +} + +uint32_t pcie_doe_build_protocol(DOEProtocol *p) +{ + return DATA_OBJ_BUILD_HEADER1(p->vendor_id, p->data_obj_type); +} + +void *pcie_doe_get_write_mbox_ptr(DOECap *doe_cap) +{ + return doe_cap->write_mbox; +} + +/* + * Copy the response to read mailbox buffer + * This might be called in self-defined handle_request() if a DOE response is + * required in the corresponding protocol + */ +void pcie_doe_set_rsp(DOECap *doe_cap, void *rsp) +{ + uint32_t len = pcie_doe_get_obj_len(rsp); + + memcpy(doe_cap->read_mbox + doe_cap->read_mbox_len, rsp, len * DWORD_BYTE); + doe_cap->read_mbox_len += len; +} + +uint32_t pcie_doe_get_obj_len(void *obj) +{ + uint32_t len; + + if (!obj) { + return 0; + } + + /* Only lower 18 bits are valid */ + len = DATA_OBJ_LEN_MASK(((DOEHeader *)obj)->length); + + /* PCIe r6.0 Table 6.29: a value of 00000h indicates 2^18 DW */ + return (len) ? len : PCI_DOE_DW_SIZE_MAX; +} + +static void pcie_doe_irq_assert(DOECap *doe_cap) +{ + PCIDevice *dev = doe_cap->pdev; + + if (doe_cap->cap.intr && doe_cap->ctrl.intr) { + if (doe_cap->status.intr) { + return; + } + doe_cap->status.intr = 1; + + if (msix_enabled(dev)) { + msix_notify(dev, doe_cap->cap.vec); + } else if (msi_enabled(dev)) { + msi_notify(dev, doe_cap->cap.vec); + } + } +} + +static void pcie_doe_set_ready(DOECap *doe_cap, bool rdy) +{ + doe_cap->status.ready = rdy; + + if (rdy) { + pcie_doe_irq_assert(doe_cap); + } +} + +static void pcie_doe_set_error(DOECap *doe_cap, bool err) +{ + doe_cap->status.error = err; + + if (err) { + pcie_doe_irq_assert(doe_cap); + } +} + +/* + * Check incoming request in write_mbox for protocol format + */ +static void pcie_doe_prepare_rsp(DOECap *doe_cap) +{ + bool success = false; + int p; + bool (*handle_request)(DOECap *) = NULL; + + if (doe_cap->status.error) { + return; + } + + if (doe_cap->write_mbox[0] == + DATA_OBJ_BUILD_HEADER1(PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_DISCOVERY)) { + handle_request = pcie_doe_discovery; + } else { + for (p = 0; p < doe_cap->protocol_num - 1; p++) { + if (doe_cap->write_mbox[0] == + pcie_doe_build_protocol(&doe_cap->protocols[p])) { + handle_request = doe_cap->protocols[p].handle_request; + break; + } + } + } + + /* + * PCIe r6 DOE 6.30.1: + * If the number of DW transferred does not match the + * indicated Length for a data object, then the + * data object must be silently discarded. + */ + if (handle_request && (doe_cap->write_mbox_len == + pcie_doe_get_obj_len(pcie_doe_get_write_mbox_ptr(doe_cap)))) { + success = handle_request(doe_cap); + } + + if (success) { + pcie_doe_set_ready(doe_cap, 1); + } else { + pcie_doe_reset_mbox(doe_cap); + } +} + +/* + * Read from DOE config space. + * Return false if the address not within DOE_CAP range. + */ +bool pcie_doe_read_config(DOECap *doe_cap, uint32_t addr, int size, + uint32_t *buf) +{ + uint32_t shift; + uint16_t doe_offset = doe_cap->offset; + + if (!range_covers_byte(doe_offset + PCI_EXP_DOE_CAP, + PCI_DOE_SIZEOF - 4, addr)) { + return false; + } + + addr -= doe_offset; + *buf = 0; + + if (range_covers_byte(PCI_EXP_DOE_CAP, DWORD_BYTE, addr)) { + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_REG, INTR_SUPP, + doe_cap->cap.intr); + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_REG, DOE_INTR_MSG_NUM, + doe_cap->cap.vec); + } else if (range_covers_byte(PCI_EXP_DOE_CTRL, DWORD_BYTE, addr)) { + /* Must return ABORT=0 and GO=0 */ + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_CONTROL, DOE_INTR_EN, + doe_cap->ctrl.intr); + } else if (range_covers_byte(PCI_EXP_DOE_STATUS, DWORD_BYTE, addr)) { + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DOE_BUSY, + doe_cap->status.busy); + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DOE_INTR_STATUS, + doe_cap->status.intr); + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DOE_ERROR, + doe_cap->status.error); + *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DATA_OBJ_RDY, + doe_cap->status.ready); + /* Mailbox should be DW accessed */ + } else if (addr == PCI_EXP_DOE_RD_DATA_MBOX && size == DWORD_BYTE) { + if (doe_cap->status.ready && !doe_cap->status.error) { + *buf = doe_cap->read_mbox[doe_cap->read_mbox_idx]; + } + } + + /* Process Alignment */ + shift = addr % DWORD_BYTE; + *buf = extract32(*buf, shift * 8, size * 8); + + return true; +} + +/* + * Write to DOE config space. + * Return if the address not within DOE_CAP range or receives an abort + */ +void pcie_doe_write_config(DOECap *doe_cap, + uint32_t addr, uint32_t val, int size) +{ + uint16_t doe_offset = doe_cap->offset; + uint32_t shift; + + if (!range_covers_byte(doe_offset + PCI_EXP_DOE_CAP, + PCI_DOE_SIZEOF - 4, addr)) { + return; + } + + /* Process Alignment */ + shift = addr % DWORD_BYTE; + addr -= (doe_offset + shift); + val = deposit32(val, shift * 8, size * 8, val); + + switch (addr) { + case PCI_EXP_DOE_CTRL: + if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_ABORT)) { + pcie_doe_set_ready(doe_cap, 0); + pcie_doe_set_error(doe_cap, 0); + pcie_doe_reset_mbox(doe_cap); + return; + } + + if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_GO)) { + pcie_doe_prepare_rsp(doe_cap); + } + + if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_INTR_EN)) { + doe_cap->ctrl.intr = 1; + /* Clear interrupt bit located within the first byte */ + } else if (shift == 0) { + doe_cap->ctrl.intr = 0; + } + break; + case PCI_EXP_DOE_STATUS: + if (FIELD_EX32(val, PCI_DOE_CAP_STATUS, DOE_INTR_STATUS)) { + doe_cap->status.intr = 0; + } + break; + case PCI_EXP_DOE_RD_DATA_MBOX: + /* Mailbox should be DW accessed */ + if (size != DWORD_BYTE) { + return; + } + doe_cap->read_mbox_idx++; + if (doe_cap->read_mbox_idx == doe_cap->read_mbox_len) { + pcie_doe_reset_mbox(doe_cap); + pcie_doe_set_ready(doe_cap, 0); + } else if (doe_cap->read_mbox_idx > doe_cap->read_mbox_len) { + /* Underflow */ + pcie_doe_set_error(doe_cap, 1); + } + break; + case PCI_EXP_DOE_WR_DATA_MBOX: + /* Mailbox should be DW accessed */ + if (size != DWORD_BYTE) { + return; + } + doe_cap->write_mbox[doe_cap->write_mbox_len] = val; + doe_cap->write_mbox_len++; + break; + case PCI_EXP_DOE_CAP: + /* fallthrough */ + default: + break; + } +} diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c index 5abbe8322025..3717e1a08614 100644 --- a/hw/pci/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -20,7 +20,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pcie_host.h" #include "qemu/module.h" diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index e95c1e5519ce..687e4e763a96 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -136,6 +136,31 @@ static void pcie_port_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, pcie_port_props); } +PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn) +{ + int devfn; + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + PCIDevice *d = bus->devices[devfn]; + PCIEPort *port; + + if (!d || !pci_is_express(d) || !d->exp.exp_cap) { + continue; + } + + if (!object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) { + continue; + } + + port = PCIE_PORT(d); + if (port->port == pn) { + return d; + } + } + + return NULL; +} + static const TypeInfo pcie_port_type_info = { .name = TYPE_PCIE_PORT, .parent = TYPE_PCI_BRIDGE, diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 8e3faf1f591a..f0bd72e069e0 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pcie.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 28e62174c425..e71f3a748378 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -456,7 +456,7 @@ static int shpc_cap_add_config(PCIDevice *d, Error **errp) pci_set_byte(config + SHPC_CAP_CxP, 0); pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); d->shpc->cap = config_offset; - /* Make dword select and data writeable. */ + /* Make dword select and data writable. */ pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); return 0; @@ -480,7 +480,8 @@ static const MemoryRegionOps shpc_mmio_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't. - * It's easier to suppport all sizes than worry about it. */ + * It's easier to support all sizes than worry about it. + */ .min_access_size = 1, .max_access_size = 4, }, diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c index 36d021b4a607..8372d05d9ee3 100644 --- a/hw/pci/slotid_cap.c +++ b/hw/pci/slotid_cap.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "hw/pci/slotid_cap.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "qemu/error-report.h" #include "qapi/error.h" diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 400511c6b703..c898021b5fc0 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,14 +71,11 @@ config SAM460EX config PEGASOS2 bool + imply ATI_VGA select MV64361 select VT82C686 - select IDE_VIA select SMBUS_EEPROM select VOF -# This should come with VT82C686 - select ACPI_X86 - imply ATI_VGA config PREP bool @@ -125,13 +121,25 @@ config E500 imply AT24C imply VIRTIO_PCI select ETSEC + select GPIO_MPC8XXX select OPENPIC + select PFLASH_CFI01 select PLATFORM_BUS select PPCE500_PCI + select SDHCI select SERIAL select MPC_I2C select FDT_PPC select DS1338 + select UNIMP + +config E500PLAT + bool + select E500 + +config MPC8544DS + bool + select E500 config VIRTEX bool diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index c7e6767f91a8..9fa1f8e6cf5f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -15,16 +15,18 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "e500.h" #include "e500-ccsr.h" #include "net/net.h" #include "qemu/config-file.h" +#include "hw/block/flash.h" #include "hw/char/serial.h" #include "hw/pci/pci.h" +#include "sysemu/block-backend-io.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" @@ -46,9 +48,10 @@ #include "hw/net/fsl_etsec/etsec.h" #include "hw/i2c/i2c.h" #include "hw/irq.h" +#include "hw/sd/sdhci.h" +#include "hw/misc/unimp.h" #define EPAPR_MAGIC (0x45504150) -#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF #define DTB_MAX_SIZE (8 * MiB) @@ -65,11 +68,14 @@ #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL #define MPC8544_PCI_REGS_OFFSET 0x8000ULL #define MPC8544_PCI_REGS_SIZE 0x1000ULL +#define MPC85XX_ESDHC_REGS_OFFSET 0x2e000ULL +#define MPC85XX_ESDHC_REGS_SIZE 0x1000ULL #define MPC8544_UTIL_OFFSET 0xe0000ULL #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL #define MPC8544_I2C_REGS_OFFSET 0x3000ULL #define MPC8XXX_GPIO_IRQ 47 #define MPC8544_I2C_IRQ 43 +#define MPC85XX_ESDHC_IRQ 72 #define RTC_REGS_OFFSET 0x68 #define PLATFORM_CLK_FREQ_HZ (400 * 1000 * 1000) @@ -202,6 +208,22 @@ static void dt_i2c_create(void *fdt, const char *soc, const char *mpic, g_free(i2c); } +static void dt_sdhc_create(void *fdt, const char *parent, const char *mpic) +{ + hwaddr mmio = MPC85XX_ESDHC_REGS_OFFSET; + hwaddr size = MPC85XX_ESDHC_REGS_SIZE; + int irq = MPC85XX_ESDHC_IRQ; + g_autofree char *name = NULL; + + name = g_strdup_printf("%s/sdhc@%" PRIx64, parent, mmio); + qemu_fdt_add_subnode(fdt, name); + qemu_fdt_setprop(fdt, name, "sdhci,auto-cmd12", NULL, 0); + qemu_fdt_setprop_phandle(fdt, name, "interrupt-parent", mpic); + qemu_fdt_setprop_cells(fdt, name, "bus-width", 4); + qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x2); + qemu_fdt_setprop_cells(fdt, name, "reg", mmio, size); + qemu_fdt_setprop_string(fdt, name, "compatible", "fsl,esdhc"); +} typedef struct PlatformDevtreeData { void *fdt; @@ -268,6 +290,31 @@ static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) } } +static void create_devtree_flash(SysBusDevice *sbdev, + PlatformDevtreeData *data) +{ + g_autofree char *name = NULL; + uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev), + "num-blocks", + &error_fatal); + uint64_t sector_length = object_property_get_uint(OBJECT(sbdev), + "sector-length", + &error_fatal); + uint64_t bank_width = object_property_get_uint(OBJECT(sbdev), + "width", + &error_fatal); + hwaddr flashbase = 0; + hwaddr flashsize = num_blocks * sector_length; + void *fdt = data->fdt; + + name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase); + qemu_fdt_add_subnode(fdt, name); + qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(fdt, name, "reg", + 1, flashbase, 1, flashsize); + qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width); +} + static void platform_bus_create_devtree(PPCE500MachineState *pms, void *fdt, const char *mpic) { @@ -277,6 +324,8 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms, uint64_t addr = pmc->platform_bus_base; uint64_t size = pmc->platform_bus_size; int irq_start = pmc->platform_bus_first_irq; + SysBusDevice *sbdev; + bool ambiguous; /* Create a /platform node that we can put all devices into */ @@ -303,6 +352,13 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms, /* Loop through all dynamic sysbus devices and create nodes for them */ foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); + sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01, + &ambiguous)); + if (sbdev) { + assert(!ambiguous); + create_devtree_flash(sbdev, &data); + } + g_free(node); } @@ -348,6 +404,7 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, }; const char *dtb_file = machine->dtb; const char *toplevel_compat = machine->dt_compatible; + uint8_t rng_seed[32]; if (dtb_file) { char *filename; @@ -405,6 +462,9 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + if (kvm_enabled()) { /* Read out host's frequencies */ clock_freq = kvmppc_get_clockfreq(); @@ -514,6 +574,10 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, dt_rtc_create(fdt, "i2c", "rtc"); + /* sdhc */ + if (pmc->has_esdhc) { + dt_sdhc_create(fdt, soc, mpic); + } gutil = g_strdup_printf("%s/global-utilities@%llx", soc, MPC8544_UTIL_OFFSET); @@ -653,7 +717,6 @@ static int ppce500_prep_device_tree(PPCE500MachineState *machine, kernel_base, kernel_size, true); } -/* Create -kernel TLB entries for BookE. */ hwaddr booke206_page_size_to_tlb(uint64_t size) { return 63 - clz64(size / KiB); @@ -684,6 +747,7 @@ static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) return (1ULL << 10 << tsize); } +/* Create -kernel TLB entries for BookE. */ static void mmubooke_create_initial_mapping(CPUPPCState *env) { ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); @@ -844,7 +908,7 @@ void ppce500_init(MachineState *machine) bool kernel_as_payload; hwaddr bios_entry = 0; target_long payload_size; - struct boot_info *boot_info; + struct boot_info *boot_info = NULL; int dt_size; int i; unsigned int smp_cpus = machine->smp.cpus; @@ -853,6 +917,7 @@ void ppce500_init(MachineState *machine) unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4}; IrqLines *irqs; DeviceState *dev, *mpicdev; + DriveInfo *dinfo; CPUPPCState *firstenv = NULL; MemoryRegion *ccsr_addr_space; SysBusDevice *s; @@ -863,7 +928,6 @@ void ppce500_init(MachineState *machine) for (i = 0; i < smp_cpus; i++) { PowerPCCPU *cpu; CPUState *cs; - qemu_irq *input; cpu = POWERPC_CPU(object_new(machine->cpu_type)); env = &cpu->env; @@ -887,9 +951,10 @@ void ppce500_init(MachineState *machine) firstenv = env; } - input = (qemu_irq *)env->irq_inputs; - irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; - irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; + irqs[i].irq[OPENPIC_OUTPUT_INT] = + qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_INT); + irqs[i].irq[OPENPIC_OUTPUT_CINT] = + qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_CINT); env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0; @@ -898,7 +963,6 @@ void ppce500_init(MachineState *machine) /* Register reset handler */ if (!i) { /* Primary CPU */ - struct boot_info *boot_info; boot_info = g_new0(struct boot_info, 1); qemu_register_reset(ppce500_cpu_reset, cpu); env->load_info = boot_info; @@ -919,8 +983,7 @@ void ppce500_init(MachineState *machine) memory_region_add_subregion(address_space_mem, 0, machine->ram); dev = qdev_new("e500-ccsr"); - object_property_add_child(qdev_get_machine(), "e500-ccsr", - OBJECT(dev)); + object_property_add_child(OBJECT(machine), "e500-ccsr", OBJECT(dev)); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ccsr = CCSR(dev); ccsr_addr_space = &ccsr->ccsr_space; @@ -942,7 +1005,8 @@ void ppce500_init(MachineState *machine) 0, qdev_get_gpio_in(mpicdev, 42), 399193, serial_hd(1), DEVICE_BIG_ENDIAN); } - /* I2C */ + + /* I2C */ dev = qdev_new("mpc-i2c"); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); @@ -952,6 +1016,26 @@ void ppce500_init(MachineState *machine) i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET); + /* eSDHC */ + if (pmc->has_esdhc) { + create_unimplemented_device("esdhc", + pmc->ccsrbar_base + MPC85XX_ESDHC_REGS_OFFSET, + MPC85XX_ESDHC_REGS_SIZE); + + /* + * Compatible with: + * - SD Host Controller Specification Version 2.0 Part A2 + * (See MPC8569E Reference Manual) + */ + dev = qdev_new(TYPE_SYSBUS_SDHCI); + qdev_prop_set_uint8(dev, "sd-spec-version", 2); + qdev_prop_set_uint8(dev, "endianness", DEVICE_BIG_ENDIAN); + s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); + sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC85XX_ESDHC_IRQ)); + memory_region_add_subregion(ccsr_addr_space, MPC85XX_ESDHC_REGS_OFFSET, + sysbus_mmio_get_region(s, 0)); + } /* General Utility device */ dev = qdev_new("mpc8544-guts"); @@ -962,7 +1046,7 @@ void ppce500_init(MachineState *machine) /* PCI */ dev = qdev_new("e500-pcihost"); - object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev)); + object_property_add_child(OBJECT(machine), "pci-host", OBJECT(dev)); qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot); qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); s = SYS_BUS_DEVICE(dev); @@ -1004,23 +1088,63 @@ void ppce500_init(MachineState *machine) } /* Platform Bus Device */ - if (pmc->has_platform_bus) { - dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); - dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); - qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); - qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); + dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); + qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); + qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); + + s = SYS_BUS_DEVICE(pms->pbus_dev); + for (i = 0; i < pmc->platform_bus_num_irqs; i++) { + int irqn = pmc->platform_bus_first_irq + i; + sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); + } - s = SYS_BUS_DEVICE(pms->pbus_dev); - for (i = 0; i < pmc->platform_bus_num_irqs; i++) { - int irqn = pmc->platform_bus_first_irq + i; - sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); + memory_region_add_subregion(address_space_mem, + pmc->platform_bus_base, + &pms->pbus_dev->mmio); + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (dinfo) { + BlockBackend *blk = blk_by_legacy_dinfo(dinfo); + BlockDriverState *bs = blk_bs(blk); + uint64_t mmio_size = memory_region_size(&pms->pbus_dev->mmio); + uint64_t size = bdrv_getlength(bs); + uint32_t sector_len = 64 * KiB; + + if (!is_power_of_2(size)) { + error_report("Size of pflash file must be a power of two."); + exit(1); } - memory_region_add_subregion(address_space_mem, - pmc->platform_bus_base, - sysbus_mmio_get_region(s, 0)); + if (size > mmio_size) { + error_report("Size of pflash file must not be bigger than %" PRIu64 + " bytes.", mmio_size); + exit(1); + } + + if (!QEMU_IS_ALIGNED(size, sector_len)) { + error_report("Size of pflash file must be a multiple of %" PRIu32 + ".", sector_len); + exit(1); + } + + dev = qdev_new(TYPE_PFLASH_CFI01); + qdev_prop_set_drive(dev, "drive", blk); + qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); + qdev_prop_set_uint64(dev, "sector-length", sector_len); + qdev_prop_set_uint8(dev, "width", 2); + qdev_prop_set_bit(dev, "big-endian", true); + qdev_prop_set_uint16(dev, "id0", 0x89); + qdev_prop_set_uint16(dev, "id1", 0x18); + qdev_prop_set_uint16(dev, "id2", 0x0000); + qdev_prop_set_uint16(dev, "id3", 0x0); + qdev_prop_set_string(dev, "name", "e500.flash"); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + memory_region_add_subregion(&pms->pbus_dev->mmio, 0, + pflash_cfi01_get_memory(PFLASH_CFI01(dev))); } /* @@ -1137,7 +1261,6 @@ void ppce500_init(MachineState *machine) } assert(dt_size < DTB_MAX_SIZE); - boot_info = env->load_info; boot_info->entry = bios_entry; boot_info->dt_base = dt_base; boot_info->dt_size = dt_size; diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 1e5853b032b7..8c09ef92e442 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -27,7 +27,7 @@ struct PPCE500MachineClass { int mpic_version; bool has_mpc8xxx_gpio; - bool has_platform_bus; + bool has_esdhc; hwaddr platform_bus_base; hwaddr platform_bus_size; int platform_bus_first_irq; diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index fc911bbb7bd1..44bf874b0fc0 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -86,7 +86,7 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data) pmc->fixup_devtree = e500plat_fixup_devtree; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_42; pmc->has_mpc8xxx_gpio = true; - pmc->has_platform_bus = true; + pmc->has_esdhc = true; pmc->platform_bus_base = 0xf00000000ULL; pmc->platform_bus_size = 128 * MiB; pmc->platform_bus_first_irq = 5; diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h deleted file mode 100644 index a1fa8f8e41a9..000000000000 --- a/hw/ppc/mac.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * QEMU PowerMac emulation shared definitions and prototypes - * - * Copyright (c) 2004-2007 Fabrice Bellard - * Copyright (c) 2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef PPC_MAC_H -#define PPC_MAC_H - -#include "qemu/units.h" -#include "exec/memory.h" -#include "hw/boards.h" -#include "hw/sysbus.h" -#include "hw/input/adb.h" -#include "hw/misc/mos6522.h" -#include "hw/pci/pci_host.h" -#include "hw/pci-host/uninorth.h" -#include "qom/object.h" - -#define NVRAM_SIZE 0x2000 -#define PROM_FILENAME "openbios-ppc" - -#define KERNEL_LOAD_ADDR 0x01000000 -#define KERNEL_GAP 0x00100000 - -#define ESCC_CLOCK 3686400 - -/* Old World IRQs */ -#define OLDWORLD_CUDA_IRQ 0x12 -#define OLDWORLD_ESCCB_IRQ 0x10 -#define OLDWORLD_ESCCA_IRQ 0xf -#define OLDWORLD_IDE0_IRQ 0xd -#define OLDWORLD_IDE0_DMA_IRQ 0x2 -#define OLDWORLD_IDE1_IRQ 0xe -#define OLDWORLD_IDE1_DMA_IRQ 0x3 - -/* New World IRQs */ -#define NEWWORLD_CUDA_IRQ 0x19 -#define NEWWORLD_PMU_IRQ 0x19 -#define NEWWORLD_ESCCB_IRQ 0x24 -#define NEWWORLD_ESCCA_IRQ 0x25 -#define NEWWORLD_IDE0_IRQ 0xd -#define NEWWORLD_IDE0_DMA_IRQ 0x2 -#define NEWWORLD_IDE1_IRQ 0xe -#define NEWWORLD_IDE1_DMA_IRQ 0x3 -#define NEWWORLD_EXTING_GPIO1 0x2f -#define NEWWORLD_EXTING_GPIO9 0x37 - -/* Core99 machine */ -#define TYPE_CORE99_MACHINE MACHINE_TYPE_NAME("mac99") -typedef struct Core99MachineState Core99MachineState; -DECLARE_INSTANCE_CHECKER(Core99MachineState, CORE99_MACHINE, - TYPE_CORE99_MACHINE) - -#define CORE99_VIA_CONFIG_CUDA 0x0 -#define CORE99_VIA_CONFIG_PMU 0x1 -#define CORE99_VIA_CONFIG_PMU_ADB 0x2 - -struct Core99MachineState { - /*< private >*/ - MachineState parent; - - uint8_t via_config; -}; - -/* Grackle PCI */ -#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost" - -/* Mac NVRAM */ -#define TYPE_MACIO_NVRAM "macio-nvram" -OBJECT_DECLARE_SIMPLE_TYPE(MacIONVRAMState, MACIO_NVRAM) - -struct MacIONVRAMState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - uint32_t size; - uint32_t it_shift; - - MemoryRegion mem; - uint8_t *data; -}; - -void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); -#endif /* PPC_MAC_H */ diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 4bddb529c2a6..601ea518f885 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -47,12 +47,14 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" +#include "qemu/units.h" #include "qapi/error.h" #include "hw/ppc/ppc.h" #include "hw/qdev-properties.h" -#include "hw/ppc/mac.h" +#include "hw/nvram/mac_nvram.h" +#include "hw/boards.h" +#include "hw/pci-host/uninorth.h" #include "hw/input/adb.h" #include "hw/ppc/mac_dbdma.h" #include "hw/pci/pci.h" @@ -81,9 +83,31 @@ #define NDRV_VGA_FILENAME "qemu_vga.ndrv" +#define PROM_FILENAME "openbios-ppc" #define PROM_BASE 0xfff00000 #define PROM_SIZE (1 * MiB) +#define KERNEL_LOAD_ADDR 0x01000000 +#define KERNEL_GAP 0x00100000 + +#define TYPE_CORE99_MACHINE MACHINE_TYPE_NAME("mac99") +typedef struct Core99MachineState Core99MachineState; +DECLARE_INSTANCE_CHECKER(Core99MachineState, CORE99_MACHINE, + TYPE_CORE99_MACHINE) + +typedef enum { + CORE99_VIA_CONFIG_CUDA = 0, + CORE99_VIA_CONFIG_PMU, + CORE99_VIA_CONFIG_PMU_ADB +} Core99ViaConfig; + +struct Core99MachineState { + /*< private >*/ + MachineState parent; + + Core99ViaConfig via_config; +}; + static void fw_cfg_boot_set(void *opaque, const char *boot_device, Error **errp) { @@ -107,45 +131,32 @@ static void ppc_core99_reset(void *opaque) /* PowerPC Mac99 hardware initialisation */ static void ppc_core99_init(MachineState *machine) { - ram_addr_t ram_size = machine->ram_size; - const char *bios_name = machine->firmware ?: PROM_FILENAME; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - const char *boot_device = machine->boot_order; Core99MachineState *core99_machine = CORE99_MACHINE(machine); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; IrqLines *openpic_irqs; - int linux_boot, i, j, k; + int i, j, k, ppc_boot_device, machine_arch, bios_size = -1; + const char *bios_name = machine->firmware ?: PROM_FILENAME; MemoryRegion *bios = g_new(MemoryRegion, 1); - hwaddr kernel_base, initrd_base, cmdline_base = 0; - long kernel_size, initrd_size; - UNINHostState *uninorth_pci; + hwaddr kernel_base = 0, initrd_base = 0, cmdline_base = 0; + long kernel_size = 0, initrd_size = 0; PCIBus *pci_bus; - PCIDevice *macio; - ESCCState *escc; bool has_pmu, has_adb; + Object *macio; MACIOIDEState *macio_ide; BusState *adb_bus; MacIONVRAMState *nvr; - int bios_size; - int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; - int machine_arch; SysBusDevice *s; - DeviceState *dev, *pic_dev; + DeviceState *dev, *pic_dev, *uninorth_pci_dev; DeviceState *uninorth_internal_dev = NULL, *uninorth_agp_dev = NULL; hwaddr nvram_addr = 0xFFF04000; - uint64_t tbfreq; - unsigned int smp_cpus = machine->smp.cpus; - - linux_boot = (kernel_filename != NULL); + uint64_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TBFREQ; /* init CPUs */ - for (i = 0; i < smp_cpus; i++) { + for (i = 0; i < machine->smp.cpus; i++) { cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); env = &cpu->env; @@ -177,68 +188,62 @@ static void ppc_core99_init(MachineState *machine) bios_size = load_image_targphys(filename, PROM_BASE, PROM_SIZE); } g_free(filename); - } else { - bios_size = -1; } if (bios_size < 0 || bios_size > PROM_SIZE) { error_report("could not load PowerPC bios '%s'", bios_name); exit(1); } - if (linux_boot) { - int bswap_needed; + if (machine->kernel_filename) { + int bswap_needed = 0; #ifdef BSWAP_NEEDED bswap_needed = 1; -#else - bswap_needed = 0; #endif kernel_base = KERNEL_LOAD_ADDR; - - kernel_size = load_elf(kernel_filename, NULL, + kernel_size = load_elf(machine->kernel_filename, NULL, translate_kernel_address, NULL, NULL, NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0); - if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, kernel_base, - ram_size - kernel_base, bswap_needed, - TARGET_PAGE_SIZE); - if (kernel_size < 0) - kernel_size = load_image_targphys(kernel_filename, + if (kernel_size < 0) { + kernel_size = load_aout(machine->kernel_filename, kernel_base, + machine->ram_size - kernel_base, + bswap_needed, TARGET_PAGE_SIZE); + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(machine->kernel_filename, kernel_base, - ram_size - kernel_base); + machine->ram_size - kernel_base); + } if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); + error_report("could not load kernel '%s'", + machine->kernel_filename); exit(1); } /* load initrd */ - if (initrd_filename) { + if (machine->initrd_filename) { initrd_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP); - initrd_size = load_image_targphys(initrd_filename, initrd_base, - ram_size - initrd_base); + initrd_size = load_image_targphys(machine->initrd_filename, + initrd_base, + machine->ram_size - initrd_base); if (initrd_size < 0) { error_report("could not load initial ram disk '%s'", - initrd_filename); + machine->initrd_filename); exit(1); } cmdline_base = TARGET_PAGE_ALIGN(initrd_base + initrd_size); } else { - initrd_base = 0; - initrd_size = 0; cmdline_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP); } ppc_boot_device = 'm'; } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; ppc_boot_device = '\0'; /* We consider that NewWorld PowerMac never have any floppy drive * For now, OHW cannot boot from the network. */ - for (i = 0; boot_device[i] != '\0'; i++) { - if (boot_device[i] >= 'c' && boot_device[i] <= 'f') { - ppc_boot_device = boot_device[i]; + for (i = 0; machine->boot_config.order[i] != '\0'; i++) { + if (machine->boot_config.order[i] >= 'c' && + machine->boot_config.order[i] <= 'f') { + ppc_boot_device = machine->boot_config.order[i]; break; } } @@ -248,45 +253,39 @@ static void ppc_core99_init(MachineState *machine) } } - /* UniN init */ - dev = qdev_new(TYPE_UNI_NORTH); - s = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(s, &error_fatal); - memory_region_add_subregion(get_system_memory(), 0xf8000000, - sysbus_mmio_get_region(s, 0)); - - openpic_irqs = g_new0(IrqLines, smp_cpus); - for (i = 0; i < smp_cpus; i++) { + openpic_irqs = g_new0(IrqLines, machine->smp.cpus); + dev = DEVICE(cpu); + for (i = 0; i < machine->smp.cpus; i++) { /* Mac99 IRQ connection between OpenPIC outputs pins * and PowerPC input pins */ switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_6xx: openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + qdev_get_gpio_in(dev, PPC6xx_INPUT_INT); openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + qdev_get_gpio_in(dev, PPC6xx_INPUT_INT); openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP]; + qdev_get_gpio_in(dev, PPC6xx_INPUT_MCP); /* Not connected ? */ openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL; /* Check this */ openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; + qdev_get_gpio_in(dev, PPC6xx_INPUT_HRESET); break; #if defined(TARGET_PPC64) case PPC_FLAGS_INPUT_970: openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; + qdev_get_gpio_in(dev, PPC970_INPUT_INT); openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; + qdev_get_gpio_in(dev, PPC970_INPUT_INT); openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP]; + qdev_get_gpio_in(dev, PPC970_INPUT_MCP); /* Not connected ? */ openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL; /* Check this */ openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET]; + qdev_get_gpio_in(dev, PPC970_INPUT_HRESET); break; #endif /* defined(TARGET_PPC64) */ default: @@ -295,24 +294,29 @@ static void ppc_core99_init(MachineState *machine) } } + /* UniN init */ + s = SYS_BUS_DEVICE(qdev_new(TYPE_UNI_NORTH)); + sysbus_realize_and_unref(s, &error_fatal); + memory_region_add_subregion(get_system_memory(), 0xf8000000, + sysbus_mmio_get_region(s, 0)); + if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { + machine_arch = ARCH_MAC99_U3; /* 970 gets a U3 bus */ /* Uninorth AGP bus */ - dev = qdev_new(TYPE_U3_AGP_HOST_BRIDGE); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - uninorth_pci = U3_AGP_HOST_BRIDGE(dev); - s = SYS_BUS_DEVICE(dev); + uninorth_pci_dev = qdev_new(TYPE_U3_AGP_HOST_BRIDGE); + s = SYS_BUS_DEVICE(uninorth_pci_dev); + sysbus_realize_and_unref(s, &error_fatal); + sysbus_mmio_map(s, 0, 0xf0800000); + sysbus_mmio_map(s, 1, 0xf0c00000); /* PCI hole */ - memory_region_add_subregion(get_system_memory(), 0x80000000ULL, + memory_region_add_subregion(get_system_memory(), 0x80000000, sysbus_mmio_get_region(s, 2)); /* Register 8 MB of ISA IO space */ memory_region_add_subregion(get_system_memory(), 0xf2000000, sysbus_mmio_get_region(s, 3)); - sysbus_mmio_map(s, 0, 0xf0800000); - sysbus_mmio_map(s, 1, 0xf0c00000); - - machine_arch = ARCH_MAC99_U3; } else { + machine_arch = ARCH_MAC99; /* Use values found on a real PowerMac */ /* Uninorth AGP bus */ uninorth_agp_dev = qdev_new(TYPE_UNI_NORTH_AGP_HOST_BRIDGE); @@ -329,22 +333,19 @@ static void ppc_core99_init(MachineState *machine) sysbus_mmio_map(s, 0, 0xf4800000); sysbus_mmio_map(s, 1, 0xf4c00000); - /* Uninorth main bus */ - dev = qdev_new(TYPE_UNI_NORTH_PCI_HOST_BRIDGE); - qdev_prop_set_uint32(dev, "ofw-addr", 0xf2000000); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - uninorth_pci = UNI_NORTH_PCI_HOST_BRIDGE(dev); - s = SYS_BUS_DEVICE(dev); + /* Uninorth main bus - this must be last to make it the default */ + uninorth_pci_dev = qdev_new(TYPE_UNI_NORTH_PCI_HOST_BRIDGE); + qdev_prop_set_uint32(uninorth_pci_dev, "ofw-addr", 0xf2000000); + s = SYS_BUS_DEVICE(uninorth_pci_dev); + sysbus_realize_and_unref(s, &error_fatal); + sysbus_mmio_map(s, 0, 0xf2800000); + sysbus_mmio_map(s, 1, 0xf2c00000); /* PCI hole */ - memory_region_add_subregion(get_system_memory(), 0x80000000ULL, + memory_region_add_subregion(get_system_memory(), 0x80000000, sysbus_mmio_get_region(s, 2)); /* Register 8 MB of ISA IO space */ memory_region_add_subregion(get_system_memory(), 0xf2000000, sysbus_mmio_get_region(s, 3)); - sysbus_mmio_map(s, 0, 0xf2800000); - sysbus_mmio_map(s, 1, 0xf2c00000); - - machine_arch = ARCH_MAC99; } machine->usb |= defaults_enabled() && !machine->usb_disabled; @@ -352,32 +353,25 @@ static void ppc_core99_init(MachineState *machine) has_adb = (core99_machine->via_config == CORE99_VIA_CONFIG_CUDA || core99_machine->via_config == CORE99_VIA_CONFIG_PMU_ADB); - /* Timebase Frequency */ - if (kvm_enabled()) { - tbfreq = kvmppc_get_tbfreq(); - } else { - tbfreq = TBFREQ; - } - /* init basic PC hardware */ - pci_bus = PCI_HOST_BRIDGE(uninorth_pci)->bus; + pci_bus = PCI_HOST_BRIDGE(uninorth_pci_dev)->bus; /* MacIO */ - macio = pci_new(-1, TYPE_NEWWORLD_MACIO); + macio = OBJECT(pci_new(-1, TYPE_NEWWORLD_MACIO)); dev = DEVICE(macio); qdev_prop_set_uint64(dev, "frequency", tbfreq); qdev_prop_set_bit(dev, "has-pmu", has_pmu); qdev_prop_set_bit(dev, "has-adb", has_adb); - escc = ESCC(object_resolve_path_component(OBJECT(macio), "escc")); - qdev_prop_set_chr(DEVICE(escc), "chrA", serial_hd(0)); - qdev_prop_set_chr(DEVICE(escc), "chrB", serial_hd(1)); + dev = DEVICE(object_resolve_path_component(macio, "escc")); + qdev_prop_set_chr(dev, "chrA", serial_hd(0)); + qdev_prop_set_chr(dev, "chrB", serial_hd(1)); - pci_realize_and_unref(macio, pci_bus, &error_fatal); + pci_realize_and_unref(PCI_DEVICE(macio), pci_bus, &error_fatal); - pic_dev = DEVICE(object_resolve_path_component(OBJECT(macio), "pic")); + pic_dev = DEVICE(object_resolve_path_component(macio, "pic")); for (i = 0; i < 4; i++) { - qdev_connect_gpio_out(DEVICE(uninorth_pci), i, + qdev_connect_gpio_out(uninorth_pci_dev, i, qdev_get_gpio_in(pic_dev, 0x1b + i)); } @@ -399,7 +393,7 @@ static void ppc_core99_init(MachineState *machine) /* OpenPIC */ s = SYS_BUS_DEVICE(pic_dev); k = 0; - for (i = 0; i < smp_cpus; i++) { + for (i = 0; i < machine->smp.cpus; i++) { for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { sysbus_connect_irq(s, k++, openpic_irqs[i].irq[j]); } @@ -409,19 +403,17 @@ static void ppc_core99_init(MachineState *machine) /* We only emulate 2 out of 3 IDE controllers for now */ ide_drive_get(hd, ARRAY_SIZE(hd)); - macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), - "ide[0]")); + macio_ide = MACIO_IDE(object_resolve_path_component(macio, "ide[0]")); macio_ide_init_drives(macio_ide, hd); - macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), - "ide[1]")); + macio_ide = MACIO_IDE(object_resolve_path_component(macio, "ide[1]")); macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); if (has_adb) { if (has_pmu) { - dev = DEVICE(object_resolve_path_component(OBJECT(macio), "pmu")); + dev = DEVICE(object_resolve_path_component(macio, "pmu")); } else { - dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); + dev = DEVICE(object_resolve_path_component(macio, "cuda")); } adb_bus = qdev_get_child_bus(dev, "adb.0"); @@ -456,18 +448,18 @@ static void ppc_core99_init(MachineState *machine) } /* The NewWorld NVRAM is not located in the MacIO device */ - if (kvm_enabled() && qemu_real_host_page_size > 4096) { + if (kvm_enabled() && qemu_real_host_page_size() > 4096) { /* We can't combine read-write and read-only in a single page, so move the NVRAM out of ROM again for KVM */ nvram_addr = 0xFFE00000; } dev = qdev_new(TYPE_MACIO_NVRAM); - qdev_prop_set_uint32(dev, "size", 0x2000); + qdev_prop_set_uint32(dev, "size", MACIO_NVRAM_SIZE); qdev_prop_set_uint32(dev, "it_shift", 1); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, nvram_addr); nvr = MACIO_NVRAM(dev); - pmac_format_nvram_partition(nvr, 0x2000); + pmac_format_nvram_partition(nvr, MACIO_NVRAM_SIZE); /* No PCI init: the BIOS will do it */ dev = qdev_new(TYPE_FW_CFG_MEM); @@ -481,15 +473,16 @@ static void ppc_core99_init(MachineState *machine) sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); - fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)machine->smp.cpus); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)machine->smp.max_cpus); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (kernel_cmdline) { + if (machine->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base); - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline); + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, + machine->kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 7016979a7cd0..558c6392022d 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -25,19 +25,19 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "qapi/error.h" #include "hw/ppc/ppc.h" #include "hw/qdev-properties.h" -#include "mac.h" +#include "hw/boards.h" #include "hw/input/adb.h" #include "sysemu/sysemu.h" #include "net/net.h" #include "hw/isa/isa.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" +#include "hw/pci-host/grackle.h" #include "hw/nvram/fw_cfg.h" #include "hw/char/escc.h" #include "hw/misc/macio/macio.h" @@ -57,10 +57,15 @@ #define NDRV_VGA_FILENAME "qemu_vga.ndrv" -#define GRACKLE_BASE 0xfec00000 +#define PROM_FILENAME "openbios-ppc" #define PROM_BASE 0xffc00000 #define PROM_SIZE (4 * MiB) +#define KERNEL_LOAD_ADDR 0x01000000 +#define KERNEL_GAP 0x00100000 + +#define GRACKLE_BASE 0xfec00000 + static void fw_cfg_boot_set(void *opaque, const char *boot_device, Error **errp) { @@ -81,33 +86,28 @@ static void ppc_heathrow_reset(void *opaque) static void ppc_heathrow_init(MachineState *machine) { - ram_addr_t ram_size = machine->ram_size; const char *bios_name = machine->firmware ?: PROM_FILENAME; - const char *boot_device = machine->boot_order; PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; - int i; + int i, bios_size = -1; MemoryRegion *bios = g_new(MemoryRegion, 1); - uint32_t kernel_base, initrd_base, cmdline_base = 0; - int32_t kernel_size, initrd_size; + uint64_t bios_addr; + uint32_t kernel_base = 0, initrd_base = 0, cmdline_base = 0; + int32_t kernel_size = 0, initrd_size = 0; PCIBus *pci_bus; - PCIDevice *macio; + Object *macio; MACIOIDEState *macio_ide; - ESCCState *escc; SysBusDevice *s; DeviceState *dev, *pic_dev, *grackle_dev; BusState *adb_bus; - uint64_t bios_addr; - int bios_size; - unsigned int smp_cpus = machine->smp.cpus; uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; - uint64_t tbfreq; + uint64_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TBFREQ; /* init CPUs */ - for (i = 0; i < smp_cpus; i++) { + for (i = 0; i < machine->smp.cpus; i++) { cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); env = &cpu->env; @@ -117,9 +117,9 @@ static void ppc_heathrow_init(MachineState *machine) } /* allocate RAM */ - if (ram_size > 2047 * MiB) { + if (machine->ram_size > 2047 * MiB) { error_report("Too much memory for this machine: %" PRId64 " MB, " - "maximum 2047 MB", ram_size / MiB); + "maximum 2047 MB", machine->ram_size / MiB); exit(1); } @@ -144,8 +144,6 @@ static void ppc_heathrow_init(MachineState *machine) bios_addr = PROM_BASE; } g_free(filename); - } else { - bios_size = -1; } if (bios_size < 0 || bios_addr - PROM_BASE + bios_size > PROM_SIZE) { error_report("could not load PowerPC bios '%s'", bios_name); @@ -153,25 +151,25 @@ static void ppc_heathrow_init(MachineState *machine) } if (machine->kernel_filename) { - int bswap_needed; + int bswap_needed = 0; #ifdef BSWAP_NEEDED bswap_needed = 1; -#else - bswap_needed = 0; #endif kernel_base = KERNEL_LOAD_ADDR; kernel_size = load_elf(machine->kernel_filename, NULL, translate_kernel_address, NULL, NULL, NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0); - if (kernel_size < 0) + if (kernel_size < 0) { kernel_size = load_aout(machine->kernel_filename, kernel_base, - ram_size - kernel_base, bswap_needed, - TARGET_PAGE_SIZE); - if (kernel_size < 0) + machine->ram_size - kernel_base, + bswap_needed, TARGET_PAGE_SIZE); + } + if (kernel_size < 0) { kernel_size = load_image_targphys(machine->kernel_filename, kernel_base, - ram_size - kernel_base); + machine->ram_size - kernel_base); + } if (kernel_size < 0) { error_report("could not load kernel '%s'", machine->kernel_filename); @@ -183,7 +181,7 @@ static void ppc_heathrow_init(MachineState *machine) KERNEL_GAP); initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, - ram_size - initrd_base); + machine->ram_size - initrd_base); if (initrd_size < 0) { error_report("could not load initial ram disk '%s'", machine->initrd_filename); @@ -191,30 +189,27 @@ static void ppc_heathrow_init(MachineState *machine) } cmdline_base = TARGET_PAGE_ALIGN(initrd_base + initrd_size); } else { - initrd_base = 0; - initrd_size = 0; cmdline_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP); } ppc_boot_device = 'm'; } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; ppc_boot_device = '\0'; - for (i = 0; boot_device[i] != '\0'; i++) { - /* TOFIX: for now, the second IDE channel is not properly + for (i = 0; machine->boot_config.order[i] != '\0'; i++) { + /* + * TOFIX: for now, the second IDE channel is not properly * used by OHW. The Mac floppy disk are not emulated. * For now, OHW cannot boot from the network. */ #if 0 - if (boot_device[i] >= 'a' && boot_device[i] <= 'f') { - ppc_boot_device = boot_device[i]; + if (machine->boot_config.order[i] >= 'a' && + machine->boot_config.order[i] <= 'f') { + ppc_boot_device = machine->boot_config.order[i]; break; } #else - if (boot_device[i] >= 'c' && boot_device[i] <= 'd') { - ppc_boot_device = boot_device[i]; + if (machine->boot_config.order[i] >= 'c' && + machine->boot_config.order[i] <= 'd') { + ppc_boot_device = machine->boot_config.order[i]; break; } #endif @@ -225,13 +220,6 @@ static void ppc_heathrow_init(MachineState *machine) } } - /* Timebase Frequency */ - if (kvm_enabled()) { - tbfreq = kvmppc_get_tbfreq(); - } else { - tbfreq = TBFREQ; - } - /* Grackle PCI host bridge */ grackle_dev = qdev_new(TYPE_GRACKLE_PCI_HOST_BRIDGE); qdev_prop_set_uint32(grackle_dev, "ofw-addr", 0x80000000); @@ -250,29 +238,28 @@ static void ppc_heathrow_init(MachineState *machine) pci_bus = PCI_HOST_BRIDGE(grackle_dev)->bus; /* MacIO */ - macio = pci_new(PCI_DEVFN(16, 0), TYPE_OLDWORLD_MACIO); - dev = DEVICE(macio); - qdev_prop_set_uint64(dev, "frequency", tbfreq); + macio = OBJECT(pci_new(PCI_DEVFN(16, 0), TYPE_OLDWORLD_MACIO)); + qdev_prop_set_uint64(DEVICE(macio), "frequency", tbfreq); - escc = ESCC(object_resolve_path_component(OBJECT(macio), "escc")); - qdev_prop_set_chr(DEVICE(escc), "chrA", serial_hd(0)); - qdev_prop_set_chr(DEVICE(escc), "chrB", serial_hd(1)); + dev = DEVICE(object_resolve_path_component(macio, "escc")); + qdev_prop_set_chr(dev, "chrA", serial_hd(0)); + qdev_prop_set_chr(dev, "chrB", serial_hd(1)); - pci_realize_and_unref(macio, pci_bus, &error_fatal); + pci_realize_and_unref(PCI_DEVICE(macio), pci_bus, &error_fatal); - pic_dev = DEVICE(object_resolve_path_component(OBJECT(macio), "pic")); + pic_dev = DEVICE(object_resolve_path_component(macio, "pic")); for (i = 0; i < 4; i++) { qdev_connect_gpio_out(grackle_dev, i, qdev_get_gpio_in(pic_dev, 0x15 + i)); } /* Connect the heathrow PIC outputs to the 6xx bus */ - for (i = 0; i < smp_cpus; i++) { + for (i = 0; i < machine->smp.cpus; i++) { switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_6xx: /* XXX: we register only 1 output pin for heathrow PIC */ qdev_connect_gpio_out(pic_dev, 0, - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]); + qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT)); break; default: error_report("Bus model not supported on OldWorld Mac machine"); @@ -288,16 +275,14 @@ static void ppc_heathrow_init(MachineState *machine) /* MacIO IDE */ ide_drive_get(hd, ARRAY_SIZE(hd)); - macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), - "ide[0]")); + macio_ide = MACIO_IDE(object_resolve_path_component(macio, "ide[0]")); macio_ide_init_drives(macio_ide, hd); - macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), - "ide[1]")); + macio_ide = MACIO_IDE(object_resolve_path_component(macio, "ide[1]")); macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); /* MacIO CUDA/ADB */ - dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); + dev = DEVICE(object_resolve_path_component(macio, "cuda")); adb_bus = qdev_get_child_bus(dev, "adb.0"); dev = qdev_new(TYPE_ADB_KEYBOARD); qdev_realize_and_unref(dev, adb_bus, &error_fatal); @@ -308,8 +293,9 @@ static void ppc_heathrow_init(MachineState *machine) pci_create_simple(pci_bus, -1, "pci-ohci"); } - if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) { graphic_depth = 15; + } /* No PCI init: the BIOS will do it */ @@ -324,9 +310,9 @@ static void ppc_heathrow_init(MachineState *machine) sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); - fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)machine->smp.cpus); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)machine->smp.max_cpus); - fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index aa4c8e6a2eac..c927337da0ed 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', @@ -58,8 +59,9 @@ ppc_ss.add(when: 'CONFIG_PPC440', if_true: files( 'ppc440_bamboo.c', 'ppc440_pcix.c', 'ppc440_uc.c')) ppc_ss.add(when: 'CONFIG_PPC4XX', if_true: files( + 'ppc4xx_devs.c', 'ppc4xx_pci.c', - 'ppc4xx_devs.c')) + 'ppc4xx_sdram.c')) ppc_ss.add(when: 'CONFIG_SAM460EX', if_true: files('sam460ex.c')) # PReP ppc_ss.add(when: 'CONFIG_PREP', if_true: files('prep.c')) @@ -70,12 +72,10 @@ ppc_ss.add(when: 'CONFIG_MAC_OLDWORLD', if_true: files('mac_oldworld.c')) # NewWorld PowerMac ppc_ss.add(when: 'CONFIG_MAC_NEWWORLD', if_true: files('mac_newworld.c')) # e500 +ppc_ss.add(when: 'CONFIG_E500PLAT', if_true: files('e500plat.c')) +ppc_ss.add(when: 'CONFIG_MPC8544DS', if_true: files('mpc8544ds.c')) ppc_ss.add(when: 'CONFIG_E500', if_true: files( 'e500.c', - 'mpc8544ds.c', - 'e500plat.c' -)) -ppc_ss.add(when: 'CONFIG_E500', if_true: files( 'mpc8544_guts.c', 'ppce500_spin.c' )) diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 81177505f029..7dd5219736b2 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -14,6 +14,7 @@ #include "sysemu/device_tree.h" #include "hw/ppc/openpic.h" #include "qemu/error-report.h" +#include "qemu/units.h" #include "cpu.h" static void mpc8544ds_fixup_devtree(void *fdt) @@ -36,7 +37,7 @@ static void mpc8544ds_init(MachineState *machine) ppce500_init(machine); } -static void e500plat_machine_class_init(ObjectClass *oc, void *data) +static void mpc8544ds_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc); @@ -45,6 +46,10 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data) pmc->pci_nr_slots = 2; pmc->fixup_devtree = mpc8544ds_fixup_devtree; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_20; + pmc->platform_bus_base = 0xFF800000ULL; + pmc->platform_bus_size = 8 * MiB; + pmc->platform_bus_first_irq = 5; + pmc->platform_bus_num_irqs = 10; pmc->ccsrbar_base = 0xE0000000ULL; pmc->pci_mmio_base = 0xC0000000ULL; pmc->pci_mmio_bus_base = 0xC0000000ULL; @@ -63,7 +68,7 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data) static const TypeInfo mpc8544ds_info = { .name = TYPE_MPC8544DS_MACHINE, .parent = TYPE_PPCE500_MACHINE, - .class_init = e500plat_machine_class_init, + .class_init = mpc8544ds_machine_class_init, }; static void mpc8544ds_register_types(void) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index d45008ac7131..f46d4bf51d8b 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/units.h" #include "qapi/error.h" #include "hw/hw.h" @@ -103,7 +102,7 @@ static void pegasos2_init(MachineState *machine) CPUPPCState *env; MemoryRegion *rom = g_new(MemoryRegion, 1); PCIBus *pci_bus; - PCIDevice *dev; + PCIDevice *dev, *via; I2CBus *i2c_bus; const char *fwname = machine->firmware ?: PROM_FILENAME; char *filename; @@ -156,34 +155,27 @@ static void pegasos2_init(MachineState *machine) /* Marvell Discovery II system controller */ pm->mv = DEVICE(sysbus_create_simple(TYPE_MV64361, -1, - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT])); + qdev_get_gpio_in(DEVICE(pm->cpu), PPC6xx_INPUT_INT))); pci_bus = mv64361_get_pci_bus(pm->mv, 1); /* VIA VT8231 South Bridge (multifunction PCI device) */ - /* VT8231 function 0: PCI-to-ISA Bridge */ - dev = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), true, + via = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), true, TYPE_VT8231_ISA); - qdev_connect_gpio_out(DEVICE(dev), 0, + object_property_add_alias(OBJECT(machine), "rtc-time", + object_resolve_path_component(OBJECT(via), + "rtc"), + "date"); + qdev_connect_gpio_out(DEVICE(via), 0, qdev_get_gpio_in_named(pm->mv, "gpp", 31)); - /* VT8231 function 1: IDE Controller */ - dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 1), "via-ide"); + dev = PCI_DEVICE(object_resolve_path_component(OBJECT(via), "ide")); pci_ide_create_devs(dev); - /* VT8231 function 2-3: USB Ports */ - pci_create_simple(pci_bus, PCI_DEVFN(12, 2), "vt82c686b-usb-uhci"); - pci_create_simple(pci_bus, PCI_DEVFN(12, 3), "vt82c686b-usb-uhci"); - - /* VT8231 function 4: Power Management Controller */ - dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 4), TYPE_VT8231_PM); + dev = PCI_DEVICE(object_resolve_path_component(OBJECT(via), "pm")); i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c")); spd_data = spd_data_generate(DDR, machine->ram_size); smbus_eeprom_init_one(i2c_bus, 0x57, spd_data); - /* VT8231 function 5-6: AC97 Audio & Modem */ - pci_create_simple(pci_bus, PCI_DEVFN(12, 5), TYPE_VIA_AC97); - pci_create_simple(pci_bus, PCI_DEVFN(12, 6), TYPE_VIA_MC97); - /* other PC hardware */ pci_vga_init(pci_bus); @@ -249,14 +241,14 @@ static void pegasos2_pci_config_write(Pegasos2MachineState *pm, int bus, pegasos2_mv_reg_write(pm, pcicfg + 4, len, val); } -static void pegasos2_machine_reset(MachineState *machine) +static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason) { Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine); void *fdt; uint64_t d[2]; int sz; - qemu_devices_reset(); + qemu_devices_reset(reason); if (!pm->vof) { return; /* Firmware should set up machine so nothing to do */ } @@ -332,6 +324,10 @@ static void pegasos2_machine_reset(MachineState *machine) vof_build_dt(fdt, pm->vof); vof_client_open_store(fdt, pm->vof, "/chosen", "stdout", "/failsafe"); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine); } @@ -462,7 +458,7 @@ static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) /* The TCG path should also be holding the BQL at this point */ g_assert(qemu_mutex_iothread_locked()); - if (msr_pr) { + if (FIELD_EX64(env->msr, MSR, PR)) { qemu_log_mask(LOG_GUEST_ERROR, "Hypercall made with MSR[PR]=1\n"); env->gpr[3] = H_PRIVILEGE; } else if (env->gpr[3] == KVMPPC_H_RTAS) { diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 00f57c9678e6..3d01e26f845b 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "qemu/cutils.h" @@ -44,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" @@ -138,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}; @@ -241,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, @@ -281,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"; @@ -574,13 +643,13 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque) } } -static void pnv_reset(MachineState *machine) +static void pnv_reset(MachineState *machine, ShutdownCause reason) { PnvMachineState *pnv = PNV_MACHINE(machine); IPMIBmc *bmc; void *fdt; - qemu_devices_reset(); + qemu_devices_reset(reason); /* * The machine should provide by default an internal BMC simulator. @@ -609,30 +678,48 @@ static void pnv_reset(MachineState *machine) qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); - g_free(fdt); + /* + * Set machine->fdt for 'dumpdtb' QMP/HMP command. Free + * the existing machine->fdt to avoid leaking it during + * a reset. + */ + g_free(machine->fdt); + machine->fdt = fdt; } static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp) { Pnv8Chip *chip8 = PNV8_CHIP(chip); + qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_EXTERNAL); + + qdev_connect_gpio_out(DEVICE(&chip8->lpc), 0, irq); return pnv_lpc_isa_create(&chip8->lpc, true, errp); } static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp) { Pnv8Chip *chip8 = PNV8_CHIP(chip); + qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_LPC_I2C); + + qdev_connect_gpio_out(DEVICE(&chip8->lpc), 0, irq); return pnv_lpc_isa_create(&chip8->lpc, false, errp); } static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp) { Pnv9Chip *chip9 = PNV9_CHIP(chip); + qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPCHC); + + qdev_connect_gpio_out(DEVICE(&chip9->lpc), 0, irq); return pnv_lpc_isa_create(&chip9->lpc, false, errp); } static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp) { Pnv10Chip *chip10 = PNV10_CHIP(chip); + qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPCHC); + + qdev_connect_gpio_out(DEVICE(&chip10->lpc), 0, irq); return pnv_lpc_isa_create(&chip10->lpc, false, errp); } @@ -641,35 +728,33 @@ static ISABus *pnv_isa_create(PnvChip *chip, Error **errp) return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp); } -static int pnv_chip_power8_pic_print_info_child(Object *child, void *opaque) -{ - Monitor *mon = opaque; - PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3); - - if (phb3) { - pnv_phb3_msi_pic_print_info(&phb3->msis, mon); - ics_pic_print_info(&phb3->lsis, mon); - } - return 0; -} - static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon) { Pnv8Chip *chip8 = PNV8_CHIP(chip); + int i; ics_pic_print_info(&chip8->psi.ics, mon); - object_child_foreach(OBJECT(chip), - pnv_chip_power8_pic_print_info_child, mon); + + for (i = 0; i < chip8->num_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); + } } 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; } @@ -709,7 +794,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) @@ -1141,10 +1226,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; - - for (i = 0; i < chip8->num_phbs; i++) { - object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3); + if (defaults_enabled()) { + chip8->num_phbs = pcc->num_phbs; + + 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); + } } } @@ -1178,14 +1275,6 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) } } -/* Attach a root port device */ -void pnv_phb_attach_root_port(PCIHostState *pci, const char *name) -{ - PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name); - - 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); @@ -1223,8 +1312,6 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) &PNV_PSI(psi8)->xscom_regs); /* Create LPC controller */ - object_property_set_link(OBJECT(&chip8->lpc), "psi", OBJECT(&chip8->psi), - &error_abort); qdev_realize(DEVICE(&chip8->lpc), NULL, &error_fatal); pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs); @@ -1244,12 +1331,12 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) } /* Create the simplified OCC model */ - object_property_set_link(OBJECT(&chip8->occ), "psi", OBJECT(&chip8->psi), - &error_abort); if (!qdev_realize(DEVICE(&chip8->occ), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); + qdev_connect_gpio_out(DEVICE(&chip8->occ), 0, + qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_OCC)); /* OCC SRAM model */ memory_region_add_subregion(get_system_memory(), PNV_OCC_SENSOR_BASE(chip), @@ -1268,9 +1355,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, @@ -1378,6 +1465,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 */ @@ -1508,8 +1597,6 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) &PNV_PSI(psi9)->xscom_regs); /* LPC */ - object_property_set_link(OBJECT(&chip9->lpc), "psi", OBJECT(&chip9->psi), - &error_abort); if (!qdev_realize(DEVICE(&chip9->lpc), NULL, errp)) { return; } @@ -1521,17 +1608,28 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) (uint64_t) PNV9_LPCM_BASE(chip)); /* Create the simplified OCC model */ - object_property_set_link(OBJECT(&chip9->occ), "psi", OBJECT(&chip9->psi), - &error_abort); if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs); + qdev_connect_gpio_out(DEVICE(&chip9->occ), 0, qdev_get_gpio_in( + DEVICE(&chip9->psi), PSIHB9_IRQ_OCC)); /* OCC SRAM model */ 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); @@ -1596,6 +1694,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; @@ -1713,8 +1812,6 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) &PNV_PSI(&chip10->psi)->xscom_regs); /* LPC */ - object_property_set_link(OBJECT(&chip10->lpc), "psi", - OBJECT(&chip10->psi), &error_abort); if (!qdev_realize(DEVICE(&chip10->lpc), NULL, errp)) { return; } @@ -1726,19 +1823,30 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) (uint64_t) PNV10_LPCM_BASE(chip)); /* Create the simplified OCC model */ - object_property_set_link(OBJECT(&chip10->occ), "psi", OBJECT(&chip10->psi), - &error_abort); if (!qdev_realize(DEVICE(&chip10->occ), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV10_XSCOM_OCC_BASE, &chip10->occ.xscom_regs); + qdev_connect_gpio_out(DEVICE(&chip10->occ), 0, qdev_get_gpio_in( + DEVICE(&chip10->psi), PSIHB9_IRQ_OCC)); /* OCC SRAM model */ memory_region_add_subregion(get_system_memory(), 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); @@ -1929,44 +2037,29 @@ PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir) return NULL; } -typedef struct ForeachPhb3Args { - int irq; - ICSState *ics; -} ForeachPhb3Args; - -static int pnv_ics_get_child(Object *child, void *opaque) -{ - ForeachPhb3Args *args = opaque; - PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3); - - if (phb3) { - if (ics_valid_irq(&phb3->lsis, args->irq)) { - args->ics = &phb3->lsis; - } - if (ics_valid_irq(ICS(&phb3->msis), args->irq)) { - args->ics = ICS(&phb3->msis); - } - } - return args->ics ? 1 : 0; -} - static ICSState *pnv_ics_get(XICSFabric *xi, int irq) { PnvMachineState *pnv = PNV_MACHINE(xi); - ForeachPhb3Args args = { irq, NULL }; - int i; + int i, j; for (i = 0; i < pnv->num_chips; i++) { - PnvChip *chip = pnv->chips[i]; Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); if (ics_valid_irq(&chip8->psi.ics, irq)) { return &chip8->psi.ics; } - object_child_foreach(OBJECT(chip), pnv_ics_get_child, &args); - if (args.ics) { - return args.ics; + for (j = 0; j < chip8->num_phbs; j++) { + PnvPHB *phb = chip8->phbs[j]; + PnvPHB3 *phb3 = PNV_PHB3(phb->backend); + + if (ics_valid_irq(&phb3->lsis, irq)) { + return &phb3->lsis; + } + + if (ics_valid_irq(ICS(&phb3->msis), irq)) { + return ICS(&phb3->msis); + } } } return NULL; @@ -1985,28 +2078,23 @@ PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id) return NULL; } -static int pnv_ics_resend_child(Object *child, void *opaque) -{ - PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3); - - if (phb3) { - ics_resend(&phb3->lsis); - ics_resend(ICS(&phb3->msis)); - } - return 0; -} - static void pnv_ics_resend(XICSFabric *xi) { PnvMachineState *pnv = PNV_MACHINE(xi); - int i; + int i, j; for (i = 0; i < pnv->num_chips; i++) { - PnvChip *chip = pnv->chips[i]; Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); ics_resend(&chip8->psi.ics); - object_child_foreach(OBJECT(chip), pnv_ics_resend_child, NULL); + + for (j = 0; j < chip8->num_phbs; j++) { + PnvPHB *phb = chip8->phbs[j]; + PnvPHB3 *phb3 = PNV_PHB3(phb->backend); + + ics_resend(&phb3->lsis); + ics_resend(ICS(&phb3->msis)); + } } } @@ -2102,8 +2190,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; @@ -2111,6 +2205,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) @@ -2120,8 +2216,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"; @@ -2129,6 +2232,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) @@ -2138,14 +2243,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_bmc.c b/hw/ppc/pnv_bmc.c index 75a22ce50b11..99f1e8d7f9f3 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -17,7 +17,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "target/ppc/cpu.h" #include "qemu/log.h" diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 19e8eb885f71..9ee79192ddee 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu) env->msr |= MSR_HVB; /* Hypervisor mode */ env->spr[SPR_HRMOR] = pc->hrmor; hreg_compute_hflags(env); + ppc_maybe_interrupt(env); pcc->intc_reset(pc->chip, cpu); } diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index bcbca3db9743..ee890e7ab419 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -422,7 +422,6 @@ static const MemoryRegionOps pnv_lpc_mmio_ops = { static void pnv_lpc_eval_irqs(PnvLpcController *lpc) { bool lpc_to_opb_irq = false; - PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc); /* Update LPC controller to OPB line */ if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) { @@ -445,7 +444,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc) lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask; /* Reflect the interrupt */ - pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0); + qemu_set_irq(lpc->psi_irq, lpc->opb_irq_stat != 0); } static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size) @@ -637,8 +636,6 @@ static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) xdc->dt_xscom = pnv_lpc_dt_xscom; - plc->psi_irq = PSIHB_IRQ_LPC_I2C; - device_class_set_parent_realize(dc, pnv_lpc_power8_realize, &plc->parent_realize); } @@ -677,8 +674,6 @@ static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data) dc->desc = "PowerNV LPC Controller POWER9"; - plc->psi_irq = PSIHB9_IRQ_LPCHC; - device_class_set_parent_realize(dc, pnv_lpc_power9_realize, &plc->parent_realize); } @@ -706,8 +701,6 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp) { PnvLpcController *lpc = PNV_LPC(dev); - assert(lpc->psi); - /* Reg inits */ lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; @@ -746,12 +739,9 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp) "lpc-hc", LPC_HC_REGS_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR, &lpc->lpc_hc_regs); -} -static Property pnv_lpc_properties[] = { - DEFINE_PROP_LINK("psi", PnvLpcController, psi, TYPE_PNV_PSI, PnvPsi *), - DEFINE_PROP_END_OF_LIST(), -}; + qdev_init_gpio_out(DEVICE(dev), &lpc->psi_irq, 1); +} static void pnv_lpc_class_init(ObjectClass *klass, void *data) { @@ -759,7 +749,6 @@ static void pnv_lpc_class_init(ObjectClass *klass, void *data) dc->realize = pnv_lpc_realize; dc->desc = "PowerNV LPC Controller"; - device_class_set_props(dc, pnv_lpc_properties); dc->user_creatable = false; } @@ -803,7 +792,7 @@ static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) } if (pnv->cpld_irqstate != old_state) { - pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_EXTERNAL, pnv->cpld_irqstate != 0); + qemu_set_irq(lpc->psi_irq, pnv->cpld_irqstate != 0); } } diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c index 4ed66f5e1fcc..9fa6d91d3122 100644 --- a/hw/ppc/pnv_occ.c +++ b/hw/ppc/pnv_occ.c @@ -21,6 +21,7 @@ #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" @@ -51,13 +52,12 @@ static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val) { bool irq_state; - PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ); val &= 0xffff000000000000ull; occ->occmisc = val; irq_state = !!(val >> 63); - pnv_psi_irq_set(occ->psi, poc->psi_irq, irq_state); + qemu_set_irq(occ->psi_irq, irq_state); } static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr, @@ -168,7 +168,6 @@ static void pnv_occ_power8_class_init(ObjectClass *klass, void *data) poc->xscom_size = PNV_XSCOM_OCC_SIZE; poc->xscom_ops = &pnv_occ_power8_xscom_ops; - poc->psi_irq = PSIHB_IRQ_OCC; } static const TypeInfo pnv_occ_power8_type_info = { @@ -241,7 +240,6 @@ static void pnv_occ_power9_class_init(ObjectClass *klass, void *data) dc->desc = "PowerNV OCC Controller (POWER9)"; poc->xscom_size = PNV9_XSCOM_OCC_SIZE; poc->xscom_ops = &pnv_occ_power9_xscom_ops; - poc->psi_irq = PSIHB9_IRQ_OCC; } static const TypeInfo pnv_occ_power9_type_info = { @@ -269,8 +267,6 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp) PnvOCC *occ = PNV_OCC(dev); PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ); - assert(occ->psi); - occ->occmisc = 0; /* XScom region for OCC registers */ @@ -281,12 +277,9 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp) memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops, occ, "occ-common-area", PNV_OCC_SENSOR_DATA_BLOCK_SIZE); -} -static Property pnv_occ_properties[] = { - DEFINE_PROP_LINK("psi", PnvOCC, psi, TYPE_PNV_PSI, PnvPsi *), - DEFINE_PROP_END_OF_LIST(), -}; + qdev_init_gpio_out(DEVICE(dev), &occ->psi_irq, 1); +} static void pnv_occ_class_init(ObjectClass *klass, void *data) { @@ -294,7 +287,6 @@ static void pnv_occ_class_init(ObjectClass *klass, void *data) dc->realize = pnv_occ_realize; dc->desc = "PowerNV OCC Controller"; - device_class_set_props(dc, pnv_occ_properties); dc->user_creatable = false; } diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c index 83ecccca28df..62804082992f 100644 --- a/hw/ppc/pnv_pnor.c +++ b/hw/ppc/pnv_pnor.c @@ -44,8 +44,8 @@ static void pnv_pnor_update(PnvPnor *s, int offset, int size) offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - ret = blk_pwrite(s->blk, offset, s->storage + offset, - offset_end - offset, 0); + ret = blk_pwrite(s->blk, offset, offset_end - offset, s->storage + offset, + 0); if (ret < 0) { error_report("Could not update PNOR offset=0x%" PRIx32" : %s", offset, strerror(-ret)); @@ -99,7 +99,7 @@ static void pnv_pnor_realize(DeviceState *dev, Error **errp) s->storage = blk_blockalign(s->blk, s->size); - if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) { + if (blk_pread(s->blk, 0, s->size, s->storage, 0) < 0) { error_setg(errp, "failed to read the initial flash content"); return; } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 466fb7979887..98045ed3d249 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -184,8 +184,7 @@ static void pnv_psi_set_irsn(PnvPsi *psi, uint64_t val) /* * FSP and PSI interrupts are muxed under the same number. */ -static const uint32_t xivr_regs[] = { - [PSIHB_IRQ_PSI] = PSIHB_XSCOM_XIVR_FSP, +static const uint32_t xivr_regs[PSI_NUM_INTERRUPTS] = { [PSIHB_IRQ_FSP] = PSIHB_XSCOM_XIVR_FSP, [PSIHB_IRQ_OCC] = PSIHB_XSCOM_XIVR_OCC, [PSIHB_IRQ_FSI] = PSIHB_XSCOM_XIVR_FSI, @@ -194,8 +193,7 @@ static const uint32_t xivr_regs[] = { [PSIHB_IRQ_EXTERNAL] = PSIHB_XSCOM_XIVR_EXT, }; -static const uint32_t stat_regs[] = { - [PSIHB_IRQ_PSI] = PSIHB_XSCOM_CR, +static const uint32_t stat_regs[PSI_NUM_INTERRUPTS] = { [PSIHB_IRQ_FSP] = PSIHB_XSCOM_CR, [PSIHB_IRQ_OCC] = PSIHB_XSCOM_IRQ_STAT, [PSIHB_IRQ_FSI] = PSIHB_XSCOM_IRQ_STAT, @@ -204,8 +202,7 @@ static const uint32_t stat_regs[] = { [PSIHB_IRQ_EXTERNAL] = PSIHB_XSCOM_IRQ_STAT, }; -static const uint64_t stat_bits[] = { - [PSIHB_IRQ_PSI] = PSIHB_CR_PSI_IRQ, +static const uint64_t stat_bits[PSI_NUM_INTERRUPTS] = { [PSIHB_IRQ_FSP] = PSIHB_CR_FSP_IRQ, [PSIHB_IRQ_OCC] = PSIHB_IRQ_STAT_OCC, [PSIHB_IRQ_FSI] = PSIHB_IRQ_STAT_FSI, @@ -214,23 +211,14 @@ static const uint64_t stat_bits[] = { [PSIHB_IRQ_EXTERNAL] = PSIHB_IRQ_STAT_EXT, }; -void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state) -{ - PNV_PSI_GET_CLASS(psi)->irq_set(psi, irq, state); -} - -static void pnv_psi_power8_irq_set(PnvPsi *psi, int irq, bool state) +static void pnv_psi_power8_set_irq(void *opaque, int irq, int state) { + PnvPsi *psi = opaque; uint32_t xivr_reg; uint32_t stat_reg; uint32_t src; bool masked; - if (irq > PSIHB_IRQ_EXTERNAL) { - qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq); - return; - } - xivr_reg = xivr_regs[irq]; stat_reg = stat_regs[irq]; @@ -515,6 +503,8 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) ics_set_irq_type(ics, i, true); } + qdev_init_gpio_in(dev, pnv_psi_power8_set_irq, ics->nr_irqs); + psi->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); /* XSCOM region for PSI registers */ @@ -576,7 +566,6 @@ static void pnv_psi_power8_class_init(ObjectClass *klass, void *data) ppc->xscom_pcba = PNV_XSCOM_PSIHB_BASE; ppc->xscom_size = PNV_XSCOM_PSIHB_SIZE; ppc->bar_mask = PSIHB_BAR_MASK; - ppc->irq_set = pnv_psi_power8_irq_set; ppc->compat = compat; ppc->compat_size = sizeof(compat); } @@ -814,15 +803,11 @@ static const MemoryRegionOps pnv_psi_p9_xscom_ops = { } }; -static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state) +static void pnv_psi_power9_set_irq(void *opaque, int irq, int state) { + PnvPsi *psi = opaque; uint64_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)]; - if (irq > PSIHB9_NUM_IRQS) { - qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq); - return; - } - if (irq_method & PSIHB9_IRQ_METHOD) { qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n"); return; @@ -876,6 +861,8 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) psi->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs); + qdev_init_gpio_in(dev, pnv_psi_power9_set_irq, xsrc->nr_irqs); + /* XSCOM region for PSI registers */ pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_p9_xscom_ops, psi, "xscom-psi", PNV9_XSCOM_PSIHB_SIZE); @@ -901,7 +888,6 @@ static void pnv_psi_power9_class_init(ObjectClass *klass, void *data) ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE; ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE; ppc->bar_mask = PSIHB9_BAR_MASK; - ppc->irq_set = pnv_psi_power9_irq_set; ppc->compat = compat; ppc->compat_size = sizeof(compat); diff --git a/hw/ppc/pnv_sbe.c b/hw/ppc/pnv_sbe.c new file mode 100644 index 000000000000..1c7812a13508 --- /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 9ce018dbc279..79f10de57f52 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/ppc.c b/hw/ppc/ppc.c index fea70df45e69..4e816c68c759 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -40,42 +40,29 @@ static void cpu_ppc_tb_stop (CPUPPCState *env); static void cpu_ppc_tb_start (CPUPPCState *env); -void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) +void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) { - CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; unsigned int old_pending; - bool locked = false; /* We may already have the BQL if coming from the reset path */ - if (!qemu_mutex_iothread_locked()) { - locked = true; - qemu_mutex_lock_iothread(); - } + QEMU_IOTHREAD_LOCK_GUARD(); old_pending = env->pending_interrupts; if (level) { - env->pending_interrupts |= 1 << n_IRQ; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + env->pending_interrupts |= irq; } else { - env->pending_interrupts &= ~(1 << n_IRQ); - if (env->pending_interrupts == 0) { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } + env->pending_interrupts &= ~irq; } if (old_pending != env->pending_interrupts) { - kvmppc_set_interrupt(cpu, n_IRQ, level); + ppc_maybe_interrupt(env); + kvmppc_set_interrupt(cpu, irq, level); } - - trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts, + trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, CPU(cpu)->interrupt_request); - - if (locked) { - qemu_mutex_unlock_iothread(); - } } /* PowerPC 6xx / 7xx internal IRQ controller */ @@ -154,10 +141,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) void ppc6xx_irq_init(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, - PPC6xx_INPUT_NB); + qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB); } #if defined(TARGET_PPC64) @@ -234,10 +218,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level) void ppc970_irq_init(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, - PPC970_INPUT_NB); + qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB); } /* POWER7 internal IRQ controller */ @@ -260,10 +241,7 @@ static void power7_set_irq(void *opaque, int pin, int level) void ppcPOWER7_irq_init(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - - env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, - POWER7_INPUT_NB); + qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB); } /* POWER9 internal IRQ controller */ @@ -292,10 +270,7 @@ static void power9_set_irq(void *opaque, int pin, int level) void ppcPOWER9_irq_init(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - - env->irq_inputs = (void **)qemu_allocate_irqs(&power9_set_irq, cpu, - POWER9_INPUT_NB); + qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB); } #endif /* defined(TARGET_PPC64) */ @@ -431,10 +406,7 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) void ppc40x_irq_init(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, - cpu, PPC40x_INPUT_NB); + qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB); } /* PowerPC E500 internal IRQ controller */ @@ -489,10 +461,7 @@ static void ppce500_set_irq(void *opaque, int pin, int level) void ppce500_irq_init(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - - env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, - cpu, PPCE500_INPUT_NB); + qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB); } /* Enable or Disable the E500 EPR capability */ diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index 83f156f585c8..9a4312691e15 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -25,54 +25,162 @@ #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 - -/* 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]; +/* PLB to OPB bridge */ +#define TYPE_PPC405_POB "ppc405-pob" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405PobState, PPC405_POB); +struct Ppc405PobState { + Ppc4xxDcrDeviceState parent_obj; + + uint32_t bear; + uint32_t besr0; + uint32_t besr1; +}; + +/* OPB arbitrer */ +#define TYPE_PPC405_OPBA "ppc405-opba" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OpbaState, PPC405_OPBA); +struct Ppc405OpbaState { + SysBusDevice parent_obj; + + MemoryRegion io; + uint8_t cr; + uint8_t pr; +}; + +/* 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; }; -/* PowerPC 405 core */ -ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size); +#define TYPE_PPC405_SOC "ppc405-soc" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405SoCState, PPC405_SOC); -void ppc4xx_plb_init(CPUPPCState *env); -void ppc405_ebc_init(CPUPPCState *env); +struct Ppc405SoCState { + /* Private */ + DeviceState parent_obj; -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); + /* Public */ + 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; + Ppc4xxSdramDdrState sdram; +}; #endif /* PPC405_H */ diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 7e1a4ac9553b..4092ebc1ab59 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #include "hw/ppc/ppc.h" @@ -49,97 +48,24 @@ #define KERNEL_LOAD_ADDR 0x01000000 #define INITRD_LOAD_ADDR 0x01800000 -#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 PPC405EP_SDRAM_BASE 0x00000000 +#define PPC405EP_SRAM_BASE 0xFFF00000 +#define PPC405EP_SRAM_SIZE (512 * KiB) -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; - } +#define USE_FLASH_BIOS - return ret; -} +#define TYPE_PPC405_MACHINE MACHINE_TYPE_NAME("ppc405") +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405MachineState, PPC405_MACHINE); -static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - ref405ep_fpga_t *fpga; +struct Ppc405MachineState { + /* Private */ + MachineState parent_obj; + /* Public */ - 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, + Ppc405SoCState soc; }; -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; @@ -170,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; @@ -222,53 +268,30 @@ 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) { - MachineClass *mc = MACHINE_GET_CLASS(machine); + Ppc405MachineState *ppc405 = PPC405_MACHINE(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); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - 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_link(OBJECT(&ppc405->soc), "dram", + OBJECT(machine->ram), &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) { MemoryRegion *bios = g_new(MemoryRegion, 1); - g_autofree char *filename; + g_autofree char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, + machine->firmware); long bios_size; memory_region_init_rom(bios, NULL, "ef405ep.bios", BIOS_SIZE, &error_fatal); - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware); if (!filename) { error_report("Could not find firmware '%s'", machine->firmware); exit(1); @@ -286,15 +309,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; @@ -323,63 +337,67 @@ static void ref405ep_init(MachineState *machine) /* Load ELF kernel and rootfs.cpio */ } else if (kernel_filename && !machine->firmware) { - boot_from_kernel(machine, cpu); + ppc4xx_sdram_ddr_enable(&ppc405->soc.sdram); + 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; @@ -389,195 +407,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; - - 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); - } + DeviceClass *dc = DEVICE_CLASS(oc); - 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 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 taihu_class_init(ObjectClass *oc, void *data) +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 36c8ba6f3c14..c973cfb04e4c 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) +{ + Ppc405PobState *pob = PPC405_POB(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + + 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) { - ppc4xx_pob_t *pob; + DeviceClass *dc = DEVICE_CLASS(oc); - 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); + 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,223 +177,35 @@ 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) -{ - ppc4xx_opba_t *opba; - - trace_opba_init(base); - - 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); -} - -/*****************************************************************************/ -/* 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) +static void ppc405_opba_realize(DeviceState *dev, Error **errp) { - ppc4xx_ebc_t *ebc; + Ppc405OpbaState *s = PPC405_OPBA(dev); - 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; - } + memory_region_init_io(&s->io, OBJECT(s), &opba_ops, s, "opba", 2); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io); } -static void ebc_reset (void *opaque) +static void ppc405_opba_class_init(ObjectClass *oc, void *data) { - ppc4xx_ebc_t *ebc; - int i; + DeviceClass *dc = DEVICE_CLASS(oc); - 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; + dc->realize = ppc405_opba_realize; + dc->reset = ppc405_opba_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } -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); -} +/*****************************************************************************/ +/* Code decompression controller */ +/* XXX: TODO */ /*****************************************************************************/ /* DMA controller */ @@ -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; - - 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); + Ppc405DmaState *dma = PPC405_DMA(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + int i; + + 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,286 @@ 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); + + 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); +} - 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 +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) +{ + 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); } -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) +/* PPC405_SOC */ + +static void ppc405_soc_instance_init(Object *obj) { - clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; - qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; - PowerPCCPU *cpu; + 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); + + object_initialize_child(obj, "sdram", &s->sdram, TYPE_PPC4xx_SDRAM_DDR); + object_property_add_alias(obj, "dram", OBJECT(&s->sdram), "dram"); +} + +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); - /* PLB to OPB bridge */ - ppc4xx_pob_init(env); - /* OBP arbitrer */ - ppc4xx_opba_init(0xef600600); - /* Universal interrupt controller */ - uicdev = qdev_new(TYPE_PPC_UIC); - uicsbd = SYS_BUS_DEVICE(uicdev); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->plb), &s->cpu, errp)) { + return; + } - object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu), - &error_fatal); - sysbus_realize_and_unref(uicsbd, &error_fatal); + /* PLB to OPB bridge */ + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->pob), &s->cpu, errp)) { + return; + } - sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]); - sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]); + /* OBP arbitrer */ + sbd = SYS_BUS_DEVICE(&s->opba); + if (!sysbus_realize(sbd, errp)) { + return; + } + sysbus_mmio_map(sbd, 0, 0xef600600); - *uicdevp = uicdev; + /* Universal interrupt controller */ + 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); + /* + * We use the 440 DDR SDRAM controller which has more regs and features + * but it's compatible enough for now + */ + object_property_set_int(OBJECT(&s->sdram), "nbanks", 2, &error_abort); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->sdram), &s->cpu, errp)) { + return; + } + /* XXX 405EP has no ECC interrupt */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdram), 0, + qdev_get_gpio_in(DEVICE(&s->uic), 17)); + /* 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); +} + +static void ppc405_soc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); - return cpu; + dc->realize = ppc405_soc_realize; + /* Reason: only works as part of a ppc405 board/machine */ + dc->user_creatable = false; } + +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.h b/hw/ppc/ppc440.h index 7cef9361255e..7c24db8504e6 100644 --- a/hw/ppc/ppc440.h +++ b/hw/ppc/ppc440.h @@ -16,10 +16,6 @@ void ppc4xx_l2sram_init(CPUPPCState *env); void ppc4xx_cpr_init(CPUPPCState *env); void ppc4xx_sdr_init(CPUPPCState *env); -void ppc440_sdram_init(CPUPPCState *env, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, hwaddr *ram_sizes, - int do_init); void ppc4xx_ahb_init(CPUPPCState *env); void ppc4xx_dma_init(CPUPPCState *env, int dcr_base); void ppc460ex_pcie_init(CPUPPCState *env); diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 7fb620b9a056..81d71adf348b 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -3,9 +3,9 @@ * * Copyright 2007 IBM Corporation. * Authors: - * Jerone Young - * Christian Ehrhardt - * Hollis Blanchard + * Jerone Young + * Christian Ehrhardt + * Hollis Blanchard * * This work is licensed under the GNU GPL license version 2 or later. * @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/error-report.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/error-report.h" #include "net/net.h" @@ -35,6 +34,8 @@ #include "hw/qdev-properties.h" #include "qapi/error.h" +#include + #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" /* from u-boot */ @@ -49,22 +50,15 @@ #define PPC440EP_PCI_IO 0xe8000000 #define PPC440EP_PCI_IOLEN 0x00010000 -#define PPC440EP_SDRAM_NR_BANKS 4 - -static const ram_addr_t ppc440ep_sdram_bank_sizes[] = { - 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0 -}; - static hwaddr entry; -static int bamboo_load_device_tree(hwaddr addr, - uint32_t ramsize, - hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) +static int bamboo_load_device_tree(MachineState *machine, + hwaddr addr, + hwaddr initrd_base, + hwaddr initrd_size) { int ret = -1; - uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) }; char *filename; int fdt_size; void *fdt; @@ -85,27 +79,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) + machine->kernel_cmdline); + 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(); @@ -117,7 +114,10 @@ static int bamboo_load_device_tree(hwaddr addr, tb_freq); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); - g_free(fdt); + + /* Set ms->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + return 0; } @@ -161,14 +161,10 @@ static void main_cpu_reset(void *opaque) static void bamboo_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); - MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS); - hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS]; - hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS]; PCIBus *pcibus; PowerPCCPU *cpu; CPUPPCState *env; @@ -194,27 +190,24 @@ 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, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]); + qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]); + qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); /* SDRAM controller */ - memset(ram_bases, 0, sizeof(ram_bases)); - memset(ram_sizes, 0, sizeof(ram_sizes)); - ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes); + dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR); + object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram), + &error_abort); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ - ppc4xx_sdram_init(env, - qdev_get_gpio_in(uicdev, 14), - PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, 1); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14)); + /* Enable SDRAM memory regions, this should be done by the firmware */ + ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev)); /* PCI */ dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, @@ -250,8 +243,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); } } @@ -288,8 +283,8 @@ static void bamboo_init(MachineState *machine) /* If we're loading a kernel directly, we must load the device tree too. */ if (kernel_filename) { - if (bamboo_load_device_tree(FDT_ADDR, machine->ram_size, RAMDISK_ADDR, - initrd_size, kernel_cmdline) < 0) { + if (bamboo_load_device_tree(machine, FDT_ADDR, + RAMDISK_ADDR, initrd_size) < 0) { error_report("couldn't load device tree"); exit(1); } diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c index 788d25514a44..f10f93c53358 100644 --- a/hw/ppc/ppc440_pcix.c +++ b/hw/ppc/ppc440_pcix.c @@ -26,7 +26,7 @@ #include "hw/irq.h" #include "hw/ppc/ppc.h" #include "hw/ppc/ppc4xx.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 993e3ba955d7..651263926ec5 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -10,19 +10,14 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu/log.h" -#include "qemu/module.h" #include "hw/irq.h" -#include "exec/memory.h" -#include "hw/ppc/ppc.h" +#include "hw/ppc/ppc4xx.h" #include "hw/qdev-properties.h" #include "hw/pci/pci.h" -#include "sysemu/block-backend.h" #include "sysemu/reset.h" #include "ppc440.h" -#include "qom/object.h" /*****************************************************************************/ /* L2 Cache as SRAM */ @@ -378,10 +373,6 @@ enum { PESDR1_RSTSTA = 0x365, }; -#define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29) -#define SDR0_DDR0_DDRM_DDR1 0x20000000 -#define SDR0_DDR0_DDRM_DDR2 0x40000000 - static uint32_t dcr_read_sdr(void *opaque, int dcrn) { ppc4xx_sdr_t *sdr = opaque; @@ -480,262 +471,6 @@ void ppc4xx_sdr_init(CPUPPCState *env) sdr, &dcr_read_sdr, &dcr_write_sdr); } -/*****************************************************************************/ -/* SDRAM controller */ -typedef struct ppc440_sdram_t { - uint32_t addr; - int nbanks; - MemoryRegion containers[4]; /* used for clipping */ - MemoryRegion *ram_memories; - hwaddr ram_bases[4]; - hwaddr ram_sizes[4]; - uint32_t bcr[4]; -} ppc440_sdram_t; - -enum { - SDRAM0_CFGADDR = 0x10, - SDRAM0_CFGDATA, - SDRAM_R0BAS = 0x40, - SDRAM_R1BAS, - SDRAM_R2BAS, - SDRAM_R3BAS, - SDRAM_CONF1HB = 0x45, - SDRAM_PLBADDULL = 0x4a, - SDRAM_CONF1LL = 0x4b, - SDRAM_CONFPATHB = 0x4f, - SDRAM_PLBADDUHB = 0x50, -}; - -static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) -{ - uint32_t bcr; - - switch (ram_size) { - case (8 * MiB): - bcr = 0xffc0; - break; - case (16 * MiB): - bcr = 0xff80; - break; - case (32 * MiB): - bcr = 0xff00; - break; - case (64 * MiB): - bcr = 0xfe00; - break; - case (128 * MiB): - bcr = 0xfc00; - break; - case (256 * MiB): - bcr = 0xf800; - break; - case (512 * MiB): - bcr = 0xf000; - break; - case (1 * GiB): - bcr = 0xe000; - break; - case (2 * GiB): - bcr = 0xc000; - break; - case (4 * GiB): - bcr = 0x8000; - break; - default: - error_report("invalid RAM size " TARGET_FMT_plx, ram_size); - return 0; - } - bcr |= ram_base >> 2 & 0xffe00000; - bcr |= 1; - - return bcr; -} - -static inline hwaddr sdram_base(uint32_t bcr) -{ - return (bcr & 0xffe00000) << 2; -} - -static uint64_t sdram_size(uint32_t bcr) -{ - uint64_t size; - int sh; - - sh = 1024 - ((bcr >> 6) & 0x3ff); - size = 8 * MiB * sh; - - return size; -} - -static void sdram_set_bcr(ppc440_sdram_t *sdram, int i, - uint32_t bcr, int enabled) -{ - if (sdram->bcr[i] & 1) { - /* First unmap RAM if enabled */ - memory_region_del_subregion(get_system_memory(), - &sdram->containers[i]); - memory_region_del_subregion(&sdram->containers[i], - &sdram->ram_memories[i]); - object_unparent(OBJECT(&sdram->containers[i])); - } - sdram->bcr[i] = bcr & 0xffe0ffc1; - if (enabled && (bcr & 1)) { - memory_region_init(&sdram->containers[i], NULL, "sdram-containers", - sdram_size(bcr)); - memory_region_add_subregion(&sdram->containers[i], 0, - &sdram->ram_memories[i]); - memory_region_add_subregion(get_system_memory(), - sdram_base(bcr), - &sdram->containers[i]); - } -} - -static void sdram_map_bcr(ppc440_sdram_t *sdram) -{ - int i; - - for (i = 0; i < sdram->nbanks; i++) { - if (sdram->ram_sizes[i] != 0) { - sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], - sdram->ram_sizes[i]), 1); - } else { - sdram_set_bcr(sdram, i, 0, 0); - } - } -} - -static uint32_t dcr_read_sdram(void *opaque, int dcrn) -{ - ppc440_sdram_t *sdram = opaque; - uint32_t ret = 0; - - switch (dcrn) { - case SDRAM_R0BAS: - case SDRAM_R1BAS: - case SDRAM_R2BAS: - case SDRAM_R3BAS: - if (sdram->ram_sizes[dcrn - SDRAM_R0BAS]) { - ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS], - sdram->ram_sizes[dcrn - SDRAM_R0BAS]); - } - break; - case SDRAM_CONF1HB: - case SDRAM_CONF1LL: - case SDRAM_CONFPATHB: - case SDRAM_PLBADDULL: - case SDRAM_PLBADDUHB: - break; - case SDRAM0_CFGADDR: - ret = sdram->addr; - break; - case SDRAM0_CFGDATA: - switch (sdram->addr) { - case 0x14: /* SDRAM_MCSTAT (405EX) */ - case 0x1F: - ret = 0x80000000; - break; - case 0x21: /* SDRAM_MCOPT2 */ - ret = 0x08000000; - break; - case 0x40: /* SDRAM_MB0CF */ - ret = 0x00008001; - break; - case 0x7A: /* SDRAM_DLCR */ - ret = 0x02000000; - break; - case 0xE1: /* SDR0_DDR0 */ - ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1; - break; - default: - break; - } - break; - default: - break; - } - - return ret; -} - -static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) -{ - ppc440_sdram_t *sdram = opaque; - - switch (dcrn) { - case SDRAM_R0BAS: - case SDRAM_R1BAS: - case SDRAM_R2BAS: - case SDRAM_R3BAS: - case SDRAM_CONF1HB: - case SDRAM_CONF1LL: - case SDRAM_CONFPATHB: - case SDRAM_PLBADDULL: - case SDRAM_PLBADDUHB: - break; - case SDRAM0_CFGADDR: - sdram->addr = val; - break; - case SDRAM0_CFGDATA: - switch (sdram->addr) { - case 0x00: /* B0CR */ - break; - default: - break; - } - break; - default: - break; - } -} - -static void sdram_reset(void *opaque) -{ - ppc440_sdram_t *sdram = opaque; - - sdram->addr = 0; -} - -void ppc440_sdram_init(CPUPPCState *env, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, hwaddr *ram_sizes, - int do_init) -{ - ppc440_sdram_t *sdram; - - sdram = g_malloc0(sizeof(*sdram)); - sdram->nbanks = nbanks; - sdram->ram_memories = ram_memories; - memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr)); - memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr)); - qemu_register_reset(&sdram_reset, sdram); - ppc_dcr_register(env, SDRAM0_CFGADDR, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM0_CFGDATA, - sdram, &dcr_read_sdram, &dcr_write_sdram); - if (do_init) { - sdram_map_bcr(sdram); - } - - ppc_dcr_register(env, SDRAM_R0BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_R1BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_R2BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_R3BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_CONF1HB, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_PLBADDULL, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_CONF1LL, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_CONFPATHB, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_PLBADDUHB, - sdram, &dcr_read_sdram, &dcr_write_sdram); -} - /*****************************************************************************/ /* PLB to AHB bridge */ enum { @@ -904,14 +639,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 +763,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" @@ -1180,6 +919,14 @@ static void dcr_write_pcie(void *opaque, int dcrn, uint32_t val) case PEGPL_CFGMSK: s->cfg_mask = val; size = ~(val & 0xfffffffe) + 1; + /* + * Firmware sets this register to E0000001. Why we are not sure, + * but the current guess is anything above PCIE_MMCFG_SIZE_MAX is + * ignored. + */ + if (size > PCIE_MMCFG_SIZE_MAX) { + size = PCIE_MMCFG_SIZE_MAX; + } pcie_host_mmcfg_update(PCIE_HOST_BRIDGE(s), val & 1, s->cfg_base, size); break; case PEGPL_MSGBAH: diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 737c0896b4f8..c1d111465db6 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -23,452 +23,10 @@ */ #include "qemu/osdep.h" -#include "qemu/units.h" -#include "sysemu/reset.h" #include "cpu.h" -#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" -#include "qemu/error-report.h" #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; -struct ppc4xx_sdram_t { - uint32_t addr; - int nbanks; - MemoryRegion containers[4]; /* used for clipping */ - MemoryRegion *ram_memories; - hwaddr ram_bases[4]; - hwaddr ram_sizes[4]; - uint32_t besr0; - uint32_t besr1; - uint32_t bear; - uint32_t cfg; - uint32_t status; - uint32_t rtr; - uint32_t pmit; - uint32_t bcr[4]; - uint32_t tr; - uint32_t ecccfg; - uint32_t eccesr; - qemu_irq irq; -}; - -enum { - SDRAM0_CFGADDR = 0x010, - SDRAM0_CFGDATA = 0x011, -}; - -/* 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) -{ - uint32_t bcr; - - switch (ram_size) { - case 4 * MiB: - bcr = 0x00000000; - break; - case 8 * MiB: - bcr = 0x00020000; - break; - case 16 * MiB: - bcr = 0x00040000; - break; - case 32 * MiB: - bcr = 0x00060000; - break; - case 64 * MiB: - bcr = 0x00080000; - break; - case 128 * MiB: - bcr = 0x000A0000; - break; - case 256 * MiB: - bcr = 0x000C0000; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__, - ram_size); - return 0x00000000; - } - bcr |= ram_base & 0xFF800000; - bcr |= 1; - - return bcr; -} - -static inline hwaddr sdram_base(uint32_t bcr) -{ - return bcr & 0xFF800000; -} - -static target_ulong sdram_size (uint32_t bcr) -{ - target_ulong size; - int sh; - - sh = (bcr >> 17) & 0x7; - if (sh == 7) - size = -1; - else - size = (4 * MiB) << sh; - - return size; -} - -static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, - uint32_t bcr, int enabled) -{ - if (sdram->bcr[i] & 0x00000001) { - /* Unmap RAM */ - trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), - sdram_size(sdram->bcr[i])); - memory_region_del_subregion(get_system_memory(), - &sdram->containers[i]); - memory_region_del_subregion(&sdram->containers[i], - &sdram->ram_memories[i]); - object_unparent(OBJECT(&sdram->containers[i])); - } - sdram->bcr[i] = bcr & 0xFFDEE001; - if (enabled && (bcr & 0x00000001)) { - trace_ppc4xx_sdram_unmap(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, - &sdram->ram_memories[i]); - memory_region_add_subregion(get_system_memory(), - sdram_base(bcr), - &sdram->containers[i]); - } -} - -static void sdram_map_bcr (ppc4xx_sdram_t *sdram) -{ - int i; - - for (i = 0; i < sdram->nbanks; i++) { - if (sdram->ram_sizes[i] != 0) { - sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], - sdram->ram_sizes[i]), 1); - } else { - sdram_set_bcr(sdram, i, 0x00000000, 0); - } - } -} - -static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) -{ - int i; - - for (i = 0; i < sdram->nbanks; i++) { - trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), - sdram_size(sdram->bcr[i])); - memory_region_del_subregion(get_system_memory(), - &sdram->ram_memories[i]); - } -} - -static uint32_t dcr_read_sdram (void *opaque, int dcrn) -{ - ppc4xx_sdram_t *sdram; - uint32_t ret; - - sdram = opaque; - switch (dcrn) { - case SDRAM0_CFGADDR: - ret = sdram->addr; - break; - case SDRAM0_CFGDATA: - switch (sdram->addr) { - case 0x00: /* SDRAM_BESR0 */ - ret = sdram->besr0; - break; - case 0x08: /* SDRAM_BESR1 */ - ret = sdram->besr1; - break; - case 0x10: /* SDRAM_BEAR */ - ret = sdram->bear; - break; - case 0x20: /* SDRAM_CFG */ - ret = sdram->cfg; - break; - case 0x24: /* SDRAM_STATUS */ - ret = sdram->status; - break; - case 0x30: /* SDRAM_RTR */ - ret = sdram->rtr; - break; - case 0x34: /* SDRAM_PMIT */ - ret = sdram->pmit; - break; - case 0x40: /* SDRAM_B0CR */ - ret = sdram->bcr[0]; - break; - case 0x44: /* SDRAM_B1CR */ - ret = sdram->bcr[1]; - break; - case 0x48: /* SDRAM_B2CR */ - ret = sdram->bcr[2]; - break; - case 0x4C: /* SDRAM_B3CR */ - ret = sdram->bcr[3]; - break; - case 0x80: /* SDRAM_TR */ - ret = -1; /* ? */ - break; - case 0x94: /* SDRAM_ECCCFG */ - ret = sdram->ecccfg; - break; - case 0x98: /* SDRAM_ECCESR */ - ret = sdram->eccesr; - break; - default: /* Error */ - ret = -1; - break; - } - break; - default: - /* Avoid gcc warning */ - ret = 0x00000000; - break; - } - - return ret; -} - -static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_sdram_t *sdram; - - sdram = opaque; - switch (dcrn) { - case SDRAM0_CFGADDR: - sdram->addr = val; - break; - case SDRAM0_CFGDATA: - switch (sdram->addr) { - case 0x00: /* SDRAM_BESR0 */ - sdram->besr0 &= ~val; - break; - case 0x08: /* SDRAM_BESR1 */ - sdram->besr1 &= ~val; - break; - case 0x10: /* SDRAM_BEAR */ - sdram->bear = val; - break; - case 0x20: /* SDRAM_CFG */ - val &= 0xFFE00000; - if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { - trace_ppc4xx_sdram_enable("enable"); - /* validate all RAM mappings */ - sdram_map_bcr(sdram); - sdram->status &= ~0x80000000; - } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { - trace_ppc4xx_sdram_enable("disable"); - /* invalidate all RAM mappings */ - sdram_unmap_bcr(sdram); - sdram->status |= 0x80000000; - } - if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) - sdram->status |= 0x40000000; - else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) - sdram->status &= ~0x40000000; - sdram->cfg = val; - break; - case 0x24: /* SDRAM_STATUS */ - /* Read-only register */ - break; - case 0x30: /* SDRAM_RTR */ - sdram->rtr = val & 0x3FF80000; - break; - case 0x34: /* SDRAM_PMIT */ - sdram->pmit = (val & 0xF8000000) | 0x07C00000; - break; - case 0x40: /* SDRAM_B0CR */ - sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); - break; - case 0x44: /* SDRAM_B1CR */ - sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); - break; - case 0x48: /* SDRAM_B2CR */ - sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); - break; - case 0x4C: /* SDRAM_B3CR */ - sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); - break; - case 0x80: /* SDRAM_TR */ - sdram->tr = val & 0x018FC01F; - break; - case 0x94: /* SDRAM_ECCCFG */ - sdram->ecccfg = val & 0x00F00000; - break; - case 0x98: /* SDRAM_ECCESR */ - val &= 0xFFF0F000; - if (sdram->eccesr == 0 && val != 0) - qemu_irq_raise(sdram->irq); - else if (sdram->eccesr != 0 && val == 0) - qemu_irq_lower(sdram->irq); - sdram->eccesr = val; - break; - default: /* Error */ - break; - } - break; - } -} - -static void sdram_reset (void *opaque) -{ - ppc4xx_sdram_t *sdram; - - sdram = opaque; - sdram->addr = 0x00000000; - sdram->bear = 0x00000000; - sdram->besr0 = 0x00000000; /* No error */ - sdram->besr1 = 0x00000000; /* No error */ - sdram->cfg = 0x00000000; - sdram->ecccfg = 0x00000000; /* No ECC */ - sdram->eccesr = 0x00000000; /* No error */ - sdram->pmit = 0x07C00000; - sdram->rtr = 0x05F00000; - sdram->tr = 0x00854009; - /* We pre-initialize RAM banks */ - sdram->status = 0x00000000; - 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) -{ - ppc4xx_sdram_t *sdram; - - sdram = g_new0(ppc4xx_sdram_t, 1); - sdram->irq = irq; - sdram->nbanks = nbanks; - sdram->ram_memories = ram_memories; - memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); - memcpy(sdram->ram_bases, ram_bases, - nbanks * sizeof(hwaddr)); - memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); - memcpy(sdram->ram_sizes, ram_sizes, - nbanks * sizeof(hwaddr)); - qemu_register_reset(&sdram_reset, sdram); - ppc_dcr_register(env, SDRAM0_CFGADDR, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM0_CFGDATA, - sdram, &dcr_read_sdram, &dcr_write_sdram); - if (do_init) - sdram_map_bcr(sdram); -} - -/* - * Split RAM between SDRAM banks. - * - * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1] - * and must be 0-terminated. - * - * The 4xx SDRAM controller supports a small number of banks, and each bank - * must be one of a small set of sizes. The number of banks and the supported - * sizes varies by SoC. - */ -void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, - MemoryRegion ram_memories[], - hwaddr ram_bases[], hwaddr ram_sizes[], - const ram_addr_t sdram_bank_sizes[]) -{ - ram_addr_t size_left = memory_region_size(ram); - ram_addr_t base = 0; - ram_addr_t bank_size; - int i; - int j; - - for (i = 0; i < nr_banks; i++) { - for (j = 0; sdram_bank_sizes[j] != 0; j++) { - bank_size = sdram_bank_sizes[j]; - if (bank_size <= size_left) { - char name[32]; - - ram_bases[i] = base; - ram_sizes[i] = bank_size; - base += bank_size; - size_left -= bank_size; - snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); - memory_region_init_alias(&ram_memories[i], NULL, name, ram, - ram_bases[i], ram_sizes[i]); - break; - } - } - if (!size_left) { - /* No need to use the remaining banks. */ - break; - } - } - - if (size_left) { - ram_addr_t used_size = memory_region_size(ram) - size_left; - GString *s = g_string_new(NULL); - - for (i = 0; sdram_bank_sizes[i]; i++) { - g_string_append_printf(s, "%" PRIi64 "%s", - sdram_bank_sizes[i] / MiB, - sdram_bank_sizes[i + 1] ? ", " : ""); - } - 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", - used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); - - g_string_free(s, true); - exit(EXIT_FAILURE); - } -} /*****************************************************************************/ /* MAL */ @@ -491,32 +49,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 +66,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 +122,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 +178,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; + } + + 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]); } - 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); + + 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_RXCTP0R + 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 < 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_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 5df97e6d156f..1d4a50fa7c31 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" @@ -27,7 +29,7 @@ #include "migration/vmstate.h" #include "qemu/module.h" #include "sysemu/reset.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "trace.h" #include "qom/object.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/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c new file mode 100644 index 000000000000..a24c80b1d2ac --- /dev/null +++ b/hw/ppc/ppc4xx_sdram.c @@ -0,0 +1,750 @@ +/* + * QEMU PowerPC 4xx embedded processors SDRAM controller emulation + * + * DDR SDRAM controller: + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * DDR2 SDRAM controller: + * Copyright (c) 2012 François Revol + * Copyright (c) 2016-2019 BALATON Zoltan + * + * This work is licensed under the GNU GPL license version 2 or later. + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" /* get_system_memory() */ +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/ppc/ppc4xx.h" +#include "trace.h" + +/*****************************************************************************/ +/* Shared functions */ + +/* + * Split RAM between SDRAM banks. + * + * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1] + * and must be 0-terminated. + * + * The 4xx SDRAM controller supports a small number of banks, and each bank + * must be one of a small set of sizes. The number of banks and the supported + * sizes varies by SoC. + */ +static bool ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, + Ppc4xxSdramBank ram_banks[], + const ram_addr_t sdram_bank_sizes[], + Error **errp) +{ + ERRP_GUARD(); + ram_addr_t size_left = memory_region_size(ram); + ram_addr_t base = 0; + ram_addr_t bank_size; + int i; + int j; + + for (i = 0; i < nr_banks; i++) { + for (j = 0; sdram_bank_sizes[j] != 0; j++) { + bank_size = sdram_bank_sizes[j]; + if (bank_size <= size_left) { + char name[32]; + + ram_banks[i].base = base; + ram_banks[i].size = bank_size; + base += bank_size; + size_left -= bank_size; + snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); + memory_region_init_alias(&ram_banks[i].ram, NULL, name, ram, + ram_banks[i].base, ram_banks[i].size); + break; + } + } + if (!size_left) { + /* No need to use the remaining banks. */ + break; + } + } + + if (size_left) { + ram_addr_t used_size = memory_region_size(ram) - size_left; + GString *s = g_string_new(NULL); + + for (i = 0; sdram_bank_sizes[i]; i++) { + g_string_append_printf(s, "%" PRIi64 "%s", + sdram_bank_sizes[i] / MiB, + sdram_bank_sizes[i + 1] ? ", " : ""); + } + error_setg(errp, "Invalid SDRAM banks"); + error_append_hint(errp, "at most %d bank%s of %s MiB each supported\n", + nr_banks, nr_banks == 1 ? "" : "s", s->str); + error_append_hint(errp, "Possible valid RAM size: %" PRIi64 " MiB\n", + used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); + + g_string_free(s, true); + return false; + } + return true; +} + +static void sdram_bank_map(Ppc4xxSdramBank *bank) +{ + trace_ppc4xx_sdram_map(bank->base, bank->size); + memory_region_init(&bank->container, NULL, "sdram-container", bank->size); + memory_region_add_subregion(&bank->container, 0, &bank->ram); + memory_region_add_subregion(get_system_memory(), bank->base, + &bank->container); +} + +static void sdram_bank_unmap(Ppc4xxSdramBank *bank) +{ + trace_ppc4xx_sdram_unmap(bank->base, bank->size); + memory_region_del_subregion(get_system_memory(), &bank->container); + memory_region_del_subregion(&bank->container, &bank->ram); + object_unparent(OBJECT(&bank->container)); +} + +static void sdram_bank_set_bcr(Ppc4xxSdramBank *bank, uint32_t bcr, + hwaddr base, hwaddr size, int enabled) +{ + if (memory_region_is_mapped(&bank->container)) { + sdram_bank_unmap(bank); + } + bank->bcr = bcr; + bank->base = base; + bank->size = size; + if (enabled && (bcr & 1)) { + sdram_bank_map(bank); + } +} + +enum { + SDRAM0_CFGADDR = 0x010, + SDRAM0_CFGDATA = 0x011, +}; + +/*****************************************************************************/ +/* DDR SDRAM controller */ +#define SDRAM_DDR_BCR_MASK 0xFFDEE001 + +static uint32_t sdram_ddr_bcr(hwaddr ram_base, hwaddr ram_size) +{ + uint32_t bcr; + + switch (ram_size) { + case 4 * MiB: + bcr = 0; + break; + case 8 * MiB: + bcr = 0x20000; + break; + case 16 * MiB: + bcr = 0x40000; + break; + case 32 * MiB: + bcr = 0x60000; + break; + case 64 * MiB: + bcr = 0x80000; + break; + case 128 * MiB: + bcr = 0xA0000; + break; + case 256 * MiB: + bcr = 0xC0000; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__, + ram_size); + return 0; + } + bcr |= ram_base & 0xFF800000; + bcr |= 1; + + return bcr; +} + +static inline hwaddr sdram_ddr_base(uint32_t bcr) +{ + return bcr & 0xFF800000; +} + +static hwaddr sdram_ddr_size(uint32_t bcr) +{ + int sh = (bcr >> 17) & 0x7; + + if (sh == 7) { + return -1; + } + + return (4 * MiB) << sh; +} + +static uint32_t sdram_ddr_dcr_read(void *opaque, int dcrn) +{ + Ppc4xxSdramDdrState *s = opaque; + uint32_t ret; + + switch (dcrn) { + case SDRAM0_CFGADDR: + ret = s->addr; + break; + case SDRAM0_CFGDATA: + switch (s->addr) { + case 0x00: /* SDRAM_BESR0 */ + ret = s->besr0; + break; + case 0x08: /* SDRAM_BESR1 */ + ret = s->besr1; + break; + case 0x10: /* SDRAM_BEAR */ + ret = s->bear; + break; + case 0x20: /* SDRAM_CFG */ + ret = s->cfg; + break; + case 0x24: /* SDRAM_STATUS */ + ret = s->status; + break; + case 0x30: /* SDRAM_RTR */ + ret = s->rtr; + break; + case 0x34: /* SDRAM_PMIT */ + ret = s->pmit; + break; + case 0x40: /* SDRAM_B0CR */ + ret = s->bank[0].bcr; + break; + case 0x44: /* SDRAM_B1CR */ + ret = s->bank[1].bcr; + break; + case 0x48: /* SDRAM_B2CR */ + ret = s->bank[2].bcr; + break; + case 0x4C: /* SDRAM_B3CR */ + ret = s->bank[3].bcr; + break; + case 0x80: /* SDRAM_TR */ + ret = -1; /* ? */ + break; + case 0x94: /* SDRAM_ECCCFG */ + ret = s->ecccfg; + break; + case 0x98: /* SDRAM_ECCESR */ + ret = s->eccesr; + break; + default: /* Error */ + ret = -1; + break; + } + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void sdram_ddr_dcr_write(void *opaque, int dcrn, uint32_t val) +{ + Ppc4xxSdramDdrState *s = opaque; + int i; + + switch (dcrn) { + case SDRAM0_CFGADDR: + s->addr = val; + break; + case SDRAM0_CFGDATA: + switch (s->addr) { + case 0x00: /* SDRAM_BESR0 */ + s->besr0 &= ~val; + break; + case 0x08: /* SDRAM_BESR1 */ + s->besr1 &= ~val; + break; + case 0x10: /* SDRAM_BEAR */ + s->bear = val; + break; + case 0x20: /* SDRAM_CFG */ + val &= 0xFFE00000; + if (!(s->cfg & 0x80000000) && (val & 0x80000000)) { + trace_ppc4xx_sdram_enable("enable"); + /* validate all RAM mappings */ + for (i = 0; i < s->nbanks; i++) { + if (s->bank[i].size) { + sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, + s->bank[i].base, s->bank[i].size, + 1); + } + } + s->status &= ~0x80000000; + } else if ((s->cfg & 0x80000000) && !(val & 0x80000000)) { + trace_ppc4xx_sdram_enable("disable"); + /* invalidate all RAM mappings */ + for (i = 0; i < s->nbanks; i++) { + if (s->bank[i].size) { + sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, + s->bank[i].base, s->bank[i].size, + 0); + } + } + s->status |= 0x80000000; + } + if (!(s->cfg & 0x40000000) && (val & 0x40000000)) { + s->status |= 0x40000000; + } else if ((s->cfg & 0x40000000) && !(val & 0x40000000)) { + s->status &= ~0x40000000; + } + s->cfg = val; + break; + case 0x24: /* SDRAM_STATUS */ + /* Read-only register */ + break; + case 0x30: /* SDRAM_RTR */ + s->rtr = val & 0x3FF80000; + break; + case 0x34: /* SDRAM_PMIT */ + s->pmit = (val & 0xF8000000) | 0x07C00000; + break; + case 0x40: /* SDRAM_B0CR */ + case 0x44: /* SDRAM_B1CR */ + case 0x48: /* SDRAM_B2CR */ + case 0x4C: /* SDRAM_B3CR */ + i = (s->addr - 0x40) / 4; + val &= SDRAM_DDR_BCR_MASK; + if (s->bank[i].size) { + sdram_bank_set_bcr(&s->bank[i], val, + sdram_ddr_base(val), sdram_ddr_size(val), + s->cfg & 0x80000000); + } + break; + case 0x80: /* SDRAM_TR */ + s->tr = val & 0x018FC01F; + break; + case 0x94: /* SDRAM_ECCCFG */ + s->ecccfg = val & 0x00F00000; + break; + case 0x98: /* SDRAM_ECCESR */ + val &= 0xFFF0F000; + if (s->eccesr == 0 && val != 0) { + qemu_irq_raise(s->irq); + } else if (s->eccesr != 0 && val == 0) { + qemu_irq_lower(s->irq); + } + s->eccesr = val; + break; + default: /* Error */ + break; + } + break; + } +} + +static void ppc4xx_sdram_ddr_reset(DeviceState *dev) +{ + Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev); + + s->addr = 0; + s->bear = 0; + s->besr0 = 0; /* No error */ + s->besr1 = 0; /* No error */ + s->cfg = 0; + s->ecccfg = 0; /* No ECC */ + s->eccesr = 0; /* No error */ + s->pmit = 0x07C00000; + s->rtr = 0x05F00000; + s->tr = 0x00854009; + /* We pre-initialize RAM banks */ + s->status = 0; + s->cfg = 0x00800000; +} + +static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp) +{ + Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + const ram_addr_t valid_bank_sizes[] = { + 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 4 * MiB, 0 + }; + int i; + + if (s->nbanks < 1 || s->nbanks > 4) { + error_setg(errp, "Invalid number of RAM banks"); + return; + } + if (!s->dram_mr) { + error_setg(errp, "Missing dram memory region"); + return; + } + if (!ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, + valid_bank_sizes, errp)) { + return; + } + for (i = 0; i < s->nbanks; i++) { + if (s->bank[i].size) { + s->bank[i].bcr = sdram_ddr_bcr(s->bank[i].base, s->bank[i].size); + sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, + s->bank[i].base, s->bank[i].size, 0); + } else { + sdram_bank_set_bcr(&s->bank[i], 0, 0, 0, 0); + } + trace_ppc4xx_sdram_init(sdram_ddr_base(s->bank[i].bcr), + sdram_ddr_size(s->bank[i].bcr), + s->bank[i].bcr); + } + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + + ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR, + s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA, + s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write); +} + +static Property ppc4xx_sdram_ddr_props[] = { + DEFINE_PROP_LINK("dram", Ppc4xxSdramDdrState, dram_mr, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdrState, nbanks, 4), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc4xx_sdram_ddr_realize; + dc->reset = ppc4xx_sdram_ddr_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; + device_class_set_props(dc, ppc4xx_sdram_ddr_props); +} + +void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s) +{ + sdram_ddr_dcr_write(s, SDRAM0_CFGADDR, 0x20); + sdram_ddr_dcr_write(s, SDRAM0_CFGDATA, 0x80000000); +} + +/*****************************************************************************/ +/* DDR2 SDRAM controller */ +#define SDRAM_DDR2_BCR_MASK 0xffe0ffc1 + +enum { + SDRAM_R0BAS = 0x40, + SDRAM_R1BAS, + SDRAM_R2BAS, + SDRAM_R3BAS, + SDRAM_CONF1HB = 0x45, + SDRAM_PLBADDULL = 0x4a, + SDRAM_CONF1LL = 0x4b, + SDRAM_CONFPATHB = 0x4f, + SDRAM_PLBADDUHB = 0x50, +}; + +static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size) +{ + uint32_t bcr; + + switch (ram_size) { + case 8 * MiB: + bcr = 0xffc0; + break; + case 16 * MiB: + bcr = 0xff80; + break; + case 32 * MiB: + bcr = 0xff00; + break; + case 64 * MiB: + bcr = 0xfe00; + break; + case 128 * MiB: + bcr = 0xfc00; + break; + case 256 * MiB: + bcr = 0xf800; + break; + case 512 * MiB: + bcr = 0xf000; + break; + case 1 * GiB: + bcr = 0xe000; + break; + case 2 * GiB: + bcr = 0xc000; + break; + case 4 * GiB: + bcr = 0x8000; + break; + default: + error_report("invalid RAM size " TARGET_FMT_plx, ram_size); + return 0; + } + bcr |= ram_base >> 2 & 0xffe00000; + bcr |= 1; + + return bcr; +} + +static inline hwaddr sdram_ddr2_base(uint32_t bcr) +{ + return (bcr & 0xffe00000) << 2; +} + +static hwaddr sdram_ddr2_size(uint32_t bcr) +{ + int sh; + + sh = 1024 - ((bcr >> 6) & 0x3ff); + return 8 * MiB * sh; +} + +static uint32_t sdram_ddr2_dcr_read(void *opaque, int dcrn) +{ + Ppc4xxSdramDdr2State *s = opaque; + uint32_t ret = 0; + + switch (dcrn) { + case SDRAM_R0BAS: + case SDRAM_R1BAS: + case SDRAM_R2BAS: + case SDRAM_R3BAS: + if (s->bank[dcrn - SDRAM_R0BAS].size) { + ret = sdram_ddr2_bcr(s->bank[dcrn - SDRAM_R0BAS].base, + s->bank[dcrn - SDRAM_R0BAS].size); + } + break; + case SDRAM_CONF1HB: + case SDRAM_CONF1LL: + case SDRAM_CONFPATHB: + case SDRAM_PLBADDULL: + case SDRAM_PLBADDUHB: + break; + case SDRAM0_CFGADDR: + ret = s->addr; + break; + case SDRAM0_CFGDATA: + switch (s->addr) { + case 0x14: /* SDRAM_MCSTAT (405EX) */ + case 0x1F: + ret = 0x80000000; + break; + case 0x21: /* SDRAM_MCOPT2 */ + ret = s->mcopt2; + break; + case 0x40: /* SDRAM_MB0CF */ + ret = 0x00008001; + break; + case 0x7A: /* SDRAM_DLCR */ + ret = 0x02000000; + break; + case 0xE1: /* SDR0_DDR0 */ + ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1; + break; + default: + break; + } + break; + default: + break; + } + + return ret; +} + +#define SDRAM_DDR2_MCOPT2_DCEN BIT(27) + +static void sdram_ddr2_dcr_write(void *opaque, int dcrn, uint32_t val) +{ + Ppc4xxSdramDdr2State *s = opaque; + int i; + + switch (dcrn) { + case SDRAM_R0BAS: + case SDRAM_R1BAS: + case SDRAM_R2BAS: + case SDRAM_R3BAS: + case SDRAM_CONF1HB: + case SDRAM_CONF1LL: + case SDRAM_CONFPATHB: + case SDRAM_PLBADDULL: + case SDRAM_PLBADDUHB: + break; + case SDRAM0_CFGADDR: + s->addr = val; + break; + case SDRAM0_CFGDATA: + switch (s->addr) { + case 0x00: /* B0CR */ + break; + case 0x21: /* SDRAM_MCOPT2 */ + if (!(s->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) && + (val & SDRAM_DDR2_MCOPT2_DCEN)) { + trace_ppc4xx_sdram_enable("enable"); + /* validate all RAM mappings */ + for (i = 0; i < s->nbanks; i++) { + if (s->bank[i].size) { + sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, + s->bank[i].base, s->bank[i].size, + 1); + } + } + s->mcopt2 |= SDRAM_DDR2_MCOPT2_DCEN; + } else if ((s->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) && + !(val & SDRAM_DDR2_MCOPT2_DCEN)) { + trace_ppc4xx_sdram_enable("disable"); + /* invalidate all RAM mappings */ + for (i = 0; i < s->nbanks; i++) { + if (s->bank[i].size) { + sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, + s->bank[i].base, s->bank[i].size, + 0); + } + } + s->mcopt2 &= ~SDRAM_DDR2_MCOPT2_DCEN; + } + break; + default: + break; + } + break; + default: + break; + } +} + +static void ppc4xx_sdram_ddr2_reset(DeviceState *dev) +{ + Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev); + + s->addr = 0; + s->mcopt2 = 0; +} + +static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp) +{ + Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + /* + * SoC also has 4 GiB but that causes problem with 32 bit + * builds (4*GiB overflows the 32 bit ram_addr_t). + */ + const ram_addr_t valid_bank_sizes[] = { + 2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, + 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0 + }; + int i; + + if (s->nbanks < 1 || s->nbanks > 4) { + error_setg(errp, "Invalid number of RAM banks"); + return; + } + if (!s->dram_mr) { + error_setg(errp, "Missing dram memory region"); + return; + } + if (!ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, + valid_bank_sizes, errp)) { + return; + } + for (i = 0; i < s->nbanks; i++) { + if (s->bank[i].size) { + s->bank[i].bcr = sdram_ddr2_bcr(s->bank[i].base, s->bank[i].size); + s->bank[i].bcr &= SDRAM_DDR2_BCR_MASK; + sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, + s->bank[i].base, s->bank[i].size, 0); + } else { + sdram_bank_set_bcr(&s->bank[i], 0, 0, 0, 0); + } + trace_ppc4xx_sdram_init(sdram_ddr2_base(s->bank[i].bcr), + sdram_ddr2_size(s->bank[i].bcr), + s->bank[i].bcr); + } + + ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + + ppc4xx_dcr_register(dcr, SDRAM_R0BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_R1BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_R2BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_R3BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_CONF1HB, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_PLBADDULL, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_CONF1LL, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_CONFPATHB, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_PLBADDUHB, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); +} + +static Property ppc4xx_sdram_ddr2_props[] = { + DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc4xx_sdram_ddr2_realize; + dc->reset = ppc4xx_sdram_ddr2_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; + device_class_set_props(dc, ppc4xx_sdram_ddr2_props); +} + +void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s) +{ + sdram_ddr2_dcr_write(s, SDRAM0_CFGADDR, 0x21); + sdram_ddr2_dcr_write(s, SDRAM0_CFGDATA, 0x08000000); +} + +static const TypeInfo ppc4xx_sdram_types[] = { + { + .name = TYPE_PPC4xx_SDRAM_DDR, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxSdramDdrState), + .class_init = ppc4xx_sdram_ddr_class_init, + }, { + .name = TYPE_PPC4xx_SDRAM_DDR2, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxSdramDdr2State), + .class_init = ppc4xx_sdram_ddr2_class_init, + } +}; + +DEFINE_TYPES(ppc4xx_sdram_types) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index bf622aa38fab..fcbe4c583765 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -50,8 +50,6 @@ /* SMP is not enabled, for now */ #define MAX_CPUS 1 -#define MAX_IDE_BUS 2 - #define CFG_ADDR 0xf0000510 #define KERNEL_LOAD_ADDR 0x01000000 @@ -275,7 +273,7 @@ static void ibm_40p_init(MachineState *machine) /* PCI -> ISA bridge */ i82378_dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(11, 0), "i82378")); qdev_connect_gpio_out(i82378_dev, 0, - cpu->env.irq_inputs[PPC6xx_INPUT_INT]); + qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT)); sysbus_connect_irq(pcihost, 0, qdev_get_gpio_in(i82378_dev, 15)); isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0")); @@ -381,7 +379,7 @@ static void ibm_40p_init(MachineState *machine) } boot_device = 'm'; } else { - boot_device = machine->boot_order[0]; + boot_device = machine->boot_config.order[0]; } fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)machine->smp.max_cpus); diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c index 8c9b8dd67b74..5a56f155f506 100644 --- a/hw/ppc/prep_systemio.c +++ b/hw/ppc/prep_systemio.c @@ -262,7 +262,7 @@ static void prep_systemio_realize(DeviceState *dev, Error **errp) qemu_set_irq(s->non_contiguous_io_map_irq, s->iomap_type & PORT0850_IOMAP_NONCONTIGUOUS); cpu = POWERPC_CPU(first_cpu); - s->softreset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET]; + s->softreset_irq = qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_HRESET); isa_register_portio_list(isa, &s->portio, 0x0, ppc_io800_port_list, s, "systemio800"); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 0737234d66e5..4a22ce3761cf 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/error-report.h" #include "qapi/error.h" @@ -26,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" @@ -75,14 +73,6 @@ #define OPB_FREQ 115000000 #define EBC_FREQ 115000000 #define UART_FREQ 11059200 -#define SDRAM_NR_BANKS 4 - -/* The SoC could also handle 4 GiB but firmware does not work with that. */ -/* Maybe it overflows a signed 32 bit number somewhere? */ -static const ram_addr_t ppc460ex_sdram_bank_sizes[] = { - 2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, 64 * MiB, - 32 * MiB, 0 -}; struct boot_info { uint32_t dt_base; @@ -133,13 +123,12 @@ static int sam460ex_load_uboot(void) return 0; } -static int sam460ex_load_device_tree(hwaddr addr, - uint32_t ramsize, +static int sam460ex_load_device_tree(MachineState *machine, + hwaddr addr, hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) + hwaddr initrd_size) { - uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) }; char *filename; int fdt_size; void *fdt; @@ -173,7 +162,8 @@ static int sam460ex_load_device_tree(hwaddr addr, qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + machine->kernel_cmdline); /* Copy data from the host device tree into the guest. Since the guest can * directly access the timebase without host involvement, we must expose @@ -210,7 +200,9 @@ static int sam460ex_load_device_tree(hwaddr addr, EBC_FREQ); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); - g_free(fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; return fdt_size; } @@ -276,12 +268,8 @@ static void sam460ex_init(MachineState *machine) { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); - MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS); - hwaddr ram_bases[SDRAM_NR_BANKS] = {0}; - 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; @@ -310,11 +298,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 @@ -326,43 +315,56 @@ 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, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]); - sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]); + sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_INT, + qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); + 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)); } } /* SDRAM controller */ - /* put all RAM on first bank because board has one slot - * and firmware only checks that */ - ppc4xx_sdram_banks(machine->ram, 1, ram_memories, ram_bases, ram_sizes, - ppc460ex_sdram_bank_sizes); - + /* The SoC could also handle 4 GiB but firmware does not work with that. */ + if (machine->ram_size > 2 * GiB) { + error_report("Memory over 2 GiB is not supported"); + exit(1); + } + /* Firmware needs at least 64 MiB */ + if (machine->ram_size < 64 * MiB) { + error_report("Memory below 64 MiB is not supported"); + exit(1); + } + dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR2); + object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram), + &error_abort); + /* + * Put all RAM on first bank because board has one slot + * and firmware only checks that + */ + object_property_set_int(OBJECT(dev), "nbanks", 1, &error_abort); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); /* FIXME: does 460EX have ECC interrupts? */ - ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, 1); + /* Enable SDRAM memory regions as we may boot without firmware */ + ppc4xx_sdram_ddr2_enable(PPC4xx_SDRAM_DDR2(dev)); /* IIC controllers and devices */ dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, qdev_get_gpio_in(uic[0], 2)); i2c = PPC4xx_I2C(dev)->bus; /* SPD EEPROM on RAM module */ - spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, - ram_sizes[0]); + spd_data = spd_data_generate(machine->ram_size < 128 * MiB ? DDR : DDR2, + machine->ram_size); spd_data[20] = 4; /* SO-DIMM module */ smbus_eeprom_init_one(i2c, 0x50, spd_data); /* RTC */ @@ -372,7 +374,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); @@ -384,10 +388,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); @@ -493,9 +502,8 @@ static void sam460ex_init(MachineState *machine) if (machine->kernel_filename) { int dt_size; - dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size, - RAMDISK_ADDR, initrd_size, - machine->kernel_cmdline); + dt_size = sam460ex_load_device_tree(machine, FDT_ADDR, + RAMDISK_ADDR, initrd_size); boot_info->dt_base = FDT_ADDR; boot_info->dt_size = dt_size; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a4372ba1891e..4921198b9d6f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -25,9 +25,9 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/memalign.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "qapi/qapi-events-machine.h" #include "qapi/qapi-events-qdev.h" @@ -62,6 +62,7 @@ #include "hw/ppc/fdt.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/vof.h" #include "hw/qdev-properties.h" #include "hw/pci-host/spapr.h" #include "hw/pci/msi.h" @@ -177,8 +178,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 +197,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; } @@ -899,6 +900,8 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) add_str(hypertas, "hcall-hpt-resize"); } + add_str(hypertas, "hcall-watchdog"); + _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions", hypertas->str, hypertas->len)); g_string_free(hypertas, TRUE); @@ -1013,6 +1016,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) { MachineState *machine = MACHINE(spapr); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); + uint8_t rng_seed[32]; int chosen; _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen")); @@ -1045,8 +1049,8 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0)); } } - if (boot_menu) { - _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu))); + if (machine->boot_config.has_menu && machine->boot_config.menu) { + _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true))); } _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width)); _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height)); @@ -1067,7 +1071,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device)); } - if (!spapr->has_graphics && stdout_path) { + if (spapr->want_stdout_path && stdout_path) { /* * "linux,stdout-path" and "stdout" properties are * deprecated by linux kernel. New platforms should only @@ -1090,6 +1094,9 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) spapr_dt_ov5_platform_support(spapr, fdt, chosen); } + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + _FDT(fdt_setprop(fdt, chosen, "rng-seed", rng_seed, sizeof(rng_seed))); + _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5")); } @@ -1270,7 +1277,7 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, g_assert(!vhyp_cpu_in_nested(cpu)); - if (msr_pr) { + if (FIELD_EX64(env->msr, MSR, PR)) { hcall_dprintf("Hypercall made with MSR[PR]=1\n"); env->gpr[3] = H_PRIVILEGE; } else { @@ -1330,6 +1337,11 @@ static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu, patb = spapr->nested_ptcr & PTCR_PATB; pats = spapr->nested_ptcr & PTCR_PATS; + /* Check if partition table is properly aligned */ + if (patb & MAKE_64BIT_MASK(0, pats + 12)) { + return false; + } + /* Calculate number of entries */ pats = 1ull << (pats + 12 - 4); if (pats <= lpid) { @@ -1511,7 +1523,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); @@ -1612,7 +1624,7 @@ void spapr_check_mmu_mode(bool guest_radix) } } -static void spapr_machine_reset(MachineState *machine) +static void spapr_machine_reset(MachineState *machine, ShutdownCause reason) { SpaprMachineState *spapr = SPAPR_MACHINE(machine); PowerPCCPU *first_ppc_cpu; @@ -1638,7 +1650,7 @@ static void spapr_machine_reset(MachineState *machine) spapr_setup_hpt(spapr); } - qemu_devices_reset(); + qemu_devices_reset(reason); spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); @@ -1702,6 +1714,9 @@ static void spapr_machine_reset(MachineState *machine) spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_blob = fdt; + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + /* Set up the entry state */ first_ppc_cpu->env.gpr[5] = 0; @@ -1743,6 +1758,7 @@ static void spapr_rtc_create(SpaprMachineState *spapr) /* Returns whether we want to use VGA or not */ static bool spapr_vga_init(PCIBus *pci_bus, Error **errp) { + vga_interface_created = true; switch (vga_interface_type) { case VGA_NONE: return false; @@ -2712,6 +2728,7 @@ static void spapr_machine_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; PCIHostState *phb; + bool has_vga; int i; MemoryRegion *sysmem = get_system_memory(); long load_limit, fw_size; @@ -2950,9 +2967,12 @@ static void spapr_machine_init(MachineState *machine) } /* Graphics */ - if (spapr_vga_init(phb->bus, &error_fatal)) { - spapr->has_graphics = true; + has_vga = spapr_vga_init(phb->bus, &error_fatal); + if (has_vga) { + spapr->want_stdout_path = !machine->enable_graphics; machine->usb |= defaults_enabled() && !machine->usb_disabled; + } else { + spapr->want_stdout_path = true; } if (machine->usb) { @@ -2962,7 +2982,7 @@ static void spapr_machine_init(MachineState *machine) pci_create_simple(phb->bus, -1, "nec-usb-xhci"); } - if (spapr->has_graphics) { + if (has_vga) { USBBus *usb_bus = usb_bus_find(-1); usb_create_simple(usb_bus, "usb-kbd"); @@ -2971,14 +2991,16 @@ static void spapr_machine_init(MachineState *machine) } if (kernel_filename) { + uint64_t loaded_addr = 0; + spapr->kernel_size = load_elf(kernel_filename, NULL, translate_kernel_address, spapr, - NULL, NULL, NULL, NULL, 1, + NULL, &loaded_addr, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0); if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) { spapr->kernel_size = load_elf(kernel_filename, NULL, translate_kernel_address, spapr, - NULL, NULL, NULL, NULL, 0, + NULL, &loaded_addr, NULL, NULL, 0, PPC_ELF_MACHINE, 0, 0); spapr->kernel_le = spapr->kernel_size > 0; } @@ -2988,6 +3010,13 @@ static void spapr_machine_init(MachineState *machine) exit(1); } + if (spapr->kernel_addr != loaded_addr) { + warn_report("spapr: kernel_addr changed from 0x%"PRIx64 + " to 0x%"PRIx64, + spapr->kernel_addr, loaded_addr); + spapr->kernel_addr = loaded_addr; + } + /* load initrd */ if (initrd_filename) { /* Try to locate the initrd in the gap between the kernel @@ -3038,6 +3067,8 @@ static void spapr_machine_init(MachineState *machine) spapr->vof->fw_size = fw_size; /* for claim() on itself */ spapr_register_hypercall(KVMPPC_H_VOF_CLIENT, spapr_h_vof_client); } + + spapr_watchdog_init(spapr); } #define DEFAULT_KVM_TYPE "auto" @@ -3698,7 +3729,7 @@ void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev) qapi_event_send_mem_unplug_error(dev->id ? : "", qapi_error); - qapi_event_send_device_unplug_guest_error(!!dev->id, dev->id, + qapi_event_send_device_unplug_guest_error(dev->id, dev->canonical_path); } @@ -4703,15 +4734,48 @@ static void spapr_machine_latest_class_options(MachineClass *mc) } \ type_init(spapr_machine_register_##suffix) +/* + * pseries-8.0 + */ +static void spapr_machine_8_0_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(8_0, "8.0", true); + +/* + * pseries-7.2 + */ +static void spapr_machine_7_2_class_options(MachineClass *mc) +{ + spapr_machine_8_0_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len); +} + +DEFINE_SPAPR_MACHINE(7_2, "7.2", false); + +/* + * 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 */ static void spapr_machine_7_0_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + spapr_machine_7_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len); } -DEFINE_SPAPR_MACHINE(7_0, "7.0", true); +DEFINE_SPAPR_MACHINE(7_0, "7.0", false); /* * pseries-6.2 diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 655ab856a01b..b4283055c121 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -553,7 +553,7 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val, * instruction is a harmless no-op. It won't correctly * implement the cache count flush *but* if we have * count-cache-disabled in the host, that flush is - * unnnecessary. So, specifically allow this case. This + * unnecessary. So, specifically allow this case. This * allows us to have better performance on POWER9 DD2.3, * while still working on POWER9 DD2.2 and POWER8 host * cpus. diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 76bc5d42a050..4923435a8b5b 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -175,8 +175,7 @@ static uint32_t drc_unisolate_logical(SpaprDrc *drc) "for device %s", drc->dev->id); } - qapi_event_send_device_unplug_guest_error(!!drc->dev->id, - drc->dev->id, + qapi_event_send_device_unplug_guest_error(drc->dev->id, drc->dev->canonical_path); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 7c8bb76f99bc..925ff523cc9d 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr, env->msr |= (1ULL << MSR_EE); hreg_compute_hflags(env); + ppc_maybe_interrupt(env); if (spapr_cpu->prod) { spapr_cpu->prod = false; @@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr, cs->halted = 1; cs->exception_index = EXCP_HLT; cs->exit_request = 1; + ppc_maybe_interrupt(env); } return H_SUCCESS; @@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu) cs->halted = 1; cs->exception_index = EXCP_HALTED; cs->exit_request = 1; + ppc_maybe_interrupt(&cpu->env); return H_SUCCESS; } @@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr, spapr_cpu = spapr_cpu_state(tcpu); spapr_cpu->prod = true; cs->halted = 0; + ppc_maybe_interrupt(&cpu->env); qemu_cpu_kick(cs); return H_SUCCESS; @@ -920,6 +924,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, target_ulong page_size = args[2]; target_ulong table_size = args[3]; target_ulong update_lpcr = 0; + target_ulong table_byte_size; uint64_t cproc; if (flags & ~FLAGS_MASK) { /* Check no reserved bits are set */ @@ -927,6 +932,14 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, } if (flags & FLAG_MODIFY) { if (flags & FLAG_REGISTER) { + /* Check process table alignment */ + table_byte_size = 1ULL << (table_size + 12); + if (proc_tbl & (table_byte_size - 1)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: process table not properly aligned: proc_tbl 0x" + TARGET_FMT_lx" proc_tbl_size 0x"TARGET_FMT_lx"\n", + __func__, proc_tbl, table_byte_size); + } if (flags & FLAG_RADIX) { /* Register new RADIX process table */ if (proc_tbl & 0xfff || proc_tbl >> 60) { return H_P2; @@ -1247,6 +1260,14 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_blob = fdt; + /* + * Set the machine->fdt pointer again since we just freed + * it above (by freeing spapr->fdt_blob). We set this + * pointer to enable support for the 'dumpdtb' QMP/HMP + * command. + */ + MACHINE(spapr)->fdt = fdt; + return H_SUCCESS; } @@ -1473,32 +1494,7 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, return H_FUNCTION; } -#ifndef CONFIG_TCG -static target_ulong h_softmmu(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - g_assert_not_reached(); -} - -static void hypercall_register_softmmu(void) -{ - /* hcall-pft */ - spapr_register_hypercall(H_ENTER, h_softmmu); - spapr_register_hypercall(H_REMOVE, h_softmmu); - spapr_register_hypercall(H_PROTECT, h_softmmu); - spapr_register_hypercall(H_READ, h_softmmu); - - /* hcall-bulk */ - spapr_register_hypercall(H_BULK_REMOVE, h_softmmu); -} -#else -static void hypercall_register_softmmu(void) -{ - /* DO NOTHING */ -} -#endif - -/* TCG only */ +#ifdef CONFIG_TCG #define PRTS_MASK 0x1f static target_ulong h_set_ptbl(PowerPCCPU *cpu, @@ -1677,6 +1673,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, spapr_cpu->in_nested = true; hreg_compute_hflags(env); + ppc_maybe_interrupt(env); tlb_flush(cs); env->reserve_addr = -1; /* Reset the reservation */ @@ -1818,6 +1815,7 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) spapr_cpu->in_nested = false; hreg_compute_hflags(env); + ppc_maybe_interrupt(env); tlb_flush(cs); env->reserve_addr = -1; /* Reset the reservation */ @@ -1825,6 +1823,48 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) spapr_cpu->nested_host_state = NULL; } +static void hypercall_register_nested(void) +{ + spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); + spapr_register_hypercall(KVMPPC_H_ENTER_NESTED, h_enter_nested); + spapr_register_hypercall(KVMPPC_H_TLB_INVALIDATE, h_tlb_invalidate); + spapr_register_hypercall(KVMPPC_H_COPY_TOFROM_GUEST, h_copy_tofrom_guest); +} + +static void hypercall_register_softmmu(void) +{ + /* DO NOTHING */ +} +#else +void spapr_exit_nested(PowerPCCPU *cpu, int excp) +{ + g_assert_not_reached(); +} + +static target_ulong h_softmmu(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + g_assert_not_reached(); +} + +static void hypercall_register_nested(void) +{ + /* DO NOTHING */ +} + +static void hypercall_register_softmmu(void) +{ + /* hcall-pft */ + spapr_register_hypercall(H_ENTER, h_softmmu); + spapr_register_hypercall(H_REMOVE, h_softmmu); + spapr_register_hypercall(H_PROTECT, h_softmmu); + spapr_register_hypercall(H_READ, h_softmmu); + + /* hcall-bulk */ + spapr_register_hypercall(H_BULK_REMOVE, h_softmmu); +} +#endif + static void hypercall_register_types(void) { hypercall_register_softmmu(); @@ -1881,10 +1921,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt); - spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); - spapr_register_hypercall(KVMPPC_H_ENTER_NESTED, h_enter_nested); - spapr_register_hypercall(KVMPPC_H_TLB_INVALIDATE, h_tlb_invalidate); - spapr_register_hypercall(KVMPPC_H_COPY_TOFROM_GUEST, h_copy_tofrom_guest); + hypercall_register_nested(); } type_init(hypercall_register_types) diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 81e5a1aea3a6..63e34d457a0e 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -279,7 +279,7 @@ static const VMStateDescription vmstate_spapr_tce_table_ex = { static const VMStateDescription vmstate_spapr_tce_table = { .name = "spapr_iommu", - .version_id = 2, + .version_id = 3, .minimum_version_id = 2, .pre_save = spapr_tce_table_pre_save, .post_load = spapr_tce_table_post_load, @@ -292,6 +292,7 @@ static const VMStateDescription vmstate_spapr_tce_table = { VMSTATE_BOOL(bypass, SpaprTceTable), VMSTATE_VARRAY_UINT32_ALLOC(mig_table, SpaprTceTable, mig_nb_table, 0, vmstate_info_uint64, uint64_t), + VMSTATE_BOOL_V(def_win, SpaprTceTable, 3), VMSTATE_END_OF_LIST() }, diff --git a/hw/ppc/spapr_numa.c b/hw/ppc/spapr_numa.c index d7c0e212baf8..a64098c375e0 100644 --- a/hw/ppc/spapr_numa.c +++ b/hw/ppc/spapr_numa.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/ppc/spapr_numa.h" #include "hw/pci-host/spapr.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index c4c97da5de98..04a64cada339 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 5bfd4aa9e5aa..75aacda65a14 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; @@ -1360,7 +1361,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev, { int offset; g_autofree gchar *nodename = spapr_pci_fw_dev_name(dev); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); ResourceProps rp; SpaprDrc *drc = drc_from_dev(sphb, dev); uint32_t vendor_id = pci_default_read_config(dev, PCI_VENDOR_ID, 2); @@ -1445,7 +1445,7 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev, spapr_phb_nvgpu_populate_pcidev_dt(dev, fdt, offset, sphb); - if (!pc->is_bridge) { + if (!IS_PCI_BRIDGE(dev)) { /* Properties only for non-bridges */ uint32_t min_grant = pci_default_read_config(dev, PCI_MIN_GNT, 1); uint32_t max_latency = pci_default_read_config(dev, PCI_MAX_LAT, 1); @@ -1543,7 +1543,6 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler, { SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler)); PCIDevice *pdev = PCI_DEVICE(plugged_dev); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev); SpaprDrc *drc = drc_from_dev(phb, pdev); PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))); uint32_t slotnr = PCI_SLOT(pdev->devfn); @@ -1559,7 +1558,7 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler, } } - if (pc->is_bridge) { + if (IS_PCI_BRIDGE(plugged_dev)) { if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) { return; } @@ -1588,7 +1587,6 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, { SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler)); PCIDevice *pdev = PCI_DEVICE(plugged_dev); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev); SpaprDrc *drc = drc_from_dev(phb, pdev); uint32_t slotnr = PCI_SLOT(pdev->devfn); @@ -1602,7 +1600,7 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, g_assert(drc); - if (pc->is_bridge) { + if (IS_PCI_BRIDGE(plugged_dev)) { spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev)); } @@ -1645,7 +1643,6 @@ static void spapr_pci_bridge_unplug(SpaprPhbState *phb, static void spapr_pci_unplug(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) { - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev); SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler)); /* some version guests do not wait for completion of a device @@ -1660,7 +1657,7 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler, */ pci_device_reset(PCI_DEVICE(plugged_dev)); - if (pc->is_bridge) { + if (IS_PCI_BRIDGE(plugged_dev)) { spapr_pci_bridge_unplug(phb, PCI_BRIDGE(plugged_dev)); return; } @@ -1685,7 +1682,6 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, g_assert(drc->dev == plugged_dev); if (!spapr_drc_unplug_requested(drc)) { - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev); uint32_t slotnr = PCI_SLOT(pdev->devfn); SpaprDrc *func_drc; SpaprDrcClass *func_drck; @@ -1693,7 +1689,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, int i; uint8_t chassis = chassis_from_bus(pci_get_bus(pdev)); - if (pc->is_bridge) { + if (IS_PCI_BRIDGE(plugged_dev)) { error_setg(errp, "PCI: Hot unplug of PCI bridges not supported"); return; } @@ -1978,7 +1974,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) * our memory slot is of page size granularity. */ if (kvm_enabled()) { - msi_window_size = qemu_real_host_page_size; + msi_window_size = qemu_real_host_page_size(); } memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, spapr, @@ -2044,7 +2040,7 @@ static int spapr_phb_children_reset(Object *child, void *opaque) DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE); if (dev) { - device_legacy_reset(dev); + device_cold_reset(dev); } return 0; @@ -2067,6 +2063,7 @@ void spapr_phb_dma_reset(SpaprPhbState *sphb) tcet = spapr_tce_find_by_liobn(sphb->dma_liobn[0]); spapr_tce_table_enable(tcet, SPAPR_TCE_PAGE_SHIFT, sphb->dma_win_addr, sphb->dma_win_size >> SPAPR_TCE_PAGE_SHIFT); + tcet->def_win = true; } static void spapr_phb_reset(DeviceState *qdev) @@ -2359,8 +2356,9 @@ int spapr_dt_phb(SpaprMachineState *spapr, SpaprPhbState *phb, cpu_to_be32(RTAS_IBM_REMOVE_PE_DMA_WINDOW) }; uint32_t ddw_extensions[] = { - cpu_to_be32(1), - cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW) + cpu_to_be32(2), + cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW), + cpu_to_be32(1), /* 1: ibm,query-pe-dma-window 6 outputs, PAPR 2.8 */ }; SpaprTceTable *tcet; SpaprDrc *drc; diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c index 4678c79235f6..2a8a11be1d68 100644 --- a/hw/ppc/spapr_pci_nvlink2.c +++ b/hw/ppc/spapr_pci_nvlink2.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "hw/pci/pci.h" #include "hw/pci-host/spapr.h" #include "hw/ppc/spapr_numa.h" @@ -398,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/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 2a76b4e0b518..d8aeee0b7e56 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -22,6 +22,7 @@ #include "hw/ppc/spapr.h" #include "hw/pci-host/spapr.h" #include "hw/pci/msix.h" +#include "hw/pci/pci_device.h" #include "hw/vfio/vfio.h" #include "qemu/error-report.h" diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index d7c04237feb9..3f664ea02ccf 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr, * guest. * For the same reason, set PSSCR_EC. */ - ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm); env->spr[SPR_PSSCR] |= PSSCR_EC; cs->halted = 1; + ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm); kvmppc_set_reg_ppc_online(cpu, 0); qemu_cpu_kick(cs); } @@ -474,16 +474,16 @@ static void rtas_ibm_nmi_interlock(PowerPCCPU *cpu, if (spapr->fwnmi_machine_check_interlock != cpu->vcpu_id) { /* - * The vCPU that hit the NMI should invoke "ibm,nmi-interlock" + * The vCPU that hit the NMI should invoke "ibm,nmi-interlock" * This should be PARAM_ERROR, but Linux calls "ibm,nmi-interlock" - * for system reset interrupts, despite them not being interlocked. - * PowerVM silently ignores this and returns success here. Returning - * failure causes Linux to print the error "FWNMI: nmi-interlock - * failed: -3", although no other apparent ill effects, this is a - * regression for the user when enabling FWNMI. So for now, match - * PowerVM. When most Linux clients are fixed, this could be - * changed. - */ + * for system reset interrupts, despite them not being interlocked. + * PowerVM silently ignores this and returns success here. Returning + * failure causes Linux to print the error "FWNMI: nmi-interlock + * failed: -3", although no other apparent ill effects, this is a + * regression for the user when enabling FWNMI. So for now, match + * PowerVM. When most Linux clients are fixed, this could be + * changed. + */ rtas_st(rets, 0, RTAS_OUT_SUCCESS); return; } diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c index 3e826e1308c4..7ba11382bc3f 100644 --- a/hw/ppc/spapr_rtas_ddw.c +++ b/hw/ppc/spapr_rtas_ddw.c @@ -72,6 +72,7 @@ static uint32_t spapr_page_mask_to_query_mask(uint64_t page_mask) const struct { int shift; uint32_t mask; } masks[] = { { 12, RTAS_DDW_PGSIZE_4K }, { 16, RTAS_DDW_PGSIZE_64K }, + { 21, RTAS_DDW_PGSIZE_2M }, { 24, RTAS_DDW_PGSIZE_16M }, { 25, RTAS_DDW_PGSIZE_32M }, { 26, RTAS_DDW_PGSIZE_64M }, @@ -99,7 +100,7 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu, uint64_t buid; uint32_t avail, addr, pgmask = 0; - if ((nargs != 3) || (nret != 5)) { + if ((nargs != 3) || ((nret != 5) && (nret != 6))) { goto param_error_exit; } @@ -117,9 +118,20 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu, rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, avail); - rtas_st(rets, 2, 0x80000000); /* The largest window we can possibly have */ - rtas_st(rets, 3, pgmask); - rtas_st(rets, 4, 0); /* DMA migration mask, not supported */ + if (nret == 6) { + /* + * Set the Max TCE number as 1<<(58-21) = 0x20.0000.0000 + * 1<<59 is the huge window start and 21 is 2M page shift. + */ + rtas_st(rets, 2, 0x00000020); + rtas_st(rets, 3, 0x00000000); + rtas_st(rets, 4, pgmask); + rtas_st(rets, 5, 0); /* DMA migration mask, not supported */ + } else { + rtas_st(rets, 2, 0x80000000); + rtas_st(rets, 3, pgmask); + rtas_st(rets, 4, 0); /* DMA migration mask, not supported */ + } trace_spapr_iommu_ddw_query(buid, addr, avail, 0x80000000, pgmask); return; @@ -214,6 +226,7 @@ static void rtas_ibm_remove_pe_dma_window(PowerPCCPU *cpu, SpaprPhbState *sphb; SpaprTceTable *tcet; uint32_t liobn; + bool def_win_removed; if ((nargs != 1) || (nret != 1)) { goto param_error_exit; @@ -230,9 +243,23 @@ static void rtas_ibm_remove_pe_dma_window(PowerPCCPU *cpu, goto param_error_exit; } + def_win_removed = tcet->def_win; spapr_tce_table_disable(tcet); trace_spapr_iommu_ddw_remove(liobn); + /* + * PAPR+/LoPAPR says: + * The platform must restore the default DMA window for the PE on a call + * to the ibm,remove-pe-dma-window RTAS call when all of the following + * are true: + * a. The call removes the last DMA window remaining for the PE. + * b. The DMA window being removed is not the default window + */ + if (spapr_phb_get_active_win_num(sphb) == 0 && !def_win_removed) { + spapr_phb_dma_reset(sphb); + trace_spapr_iommu_ddw_reset(sphb->buid, 0); + } + rtas_st(rets, 0, RTAS_OUT_SUCCESS); return; diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c index 2454086744b1..e10af35a1850 100644 --- a/hw/ppc/spapr_tpm_proxy.c +++ b/hw/ppc/spapr_tpm_proxy.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/reset.h" diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c index a33f940c32bb..09f29be0b9de 100644 --- a/hw/ppc/spapr_vof.c +++ b/hw/ppc/spapr_vof.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 5c0a215cad90..f670e8906cc9 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 @@ -116,7 +127,7 @@ ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32 ppc40x_timers_init(uint32_t value) "frequency %" PRIu32 ppc_irq_set(void *env, uint32_t pin, uint32_t level) "env [%p] pin %d level %d" -ppc_irq_set_exit(void *env, uint32_t n_IRQ, uint32_t level, uint32_t pending, uint32_t request) "env [%p] n_IRQ %d level %d => pending 0x%08" PRIx32 " req 0x%08" PRIx32 +ppc_irq_set_exit(void *env, uint32_t irq, uint32_t level, uint32_t pending, uint32_t request) "env [%p] irq 0x%05" PRIx32 " level %d => pending 0x%08" PRIx32 " req 0x%08" PRIx32 ppc_irq_set_state(const char *name, uint32_t level) "\"%s\" level %d" ppc_irq_reset(const char *name) "%s" ppc_irq_cpu(const char *action) "%s" @@ -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" @@ -171,3 +179,4 @@ ppc405ep_clocks_setup(const char *trace) "%s" ppc4xx_sdram_enable(const char *trace) "%s SDRAM controller" ppc4xx_sdram_unmap(uint64_t addr, uint64_t size) "Unmap RAM area 0x%" PRIx64 " size 0x%" PRIx64 ppc4xx_sdram_map(uint64_t addr, uint64_t size) "Map RAM area 0x%" PRIx64 " size 0x%" PRIx64 +ppc4xx_sdram_init(uint64_t base, uint64_t size, uint32_t bcr) "Init RAM area 0x%" PRIx64 " size 0x%" PRIx64 " bcr 0x%x" diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 9c575403b85c..f2f81bd4259c 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "cpu.h" @@ -46,6 +45,8 @@ #include "hw/qdev-properties.h" #include "ppc405.h" +#include + #define EPAPR_MAGIC (0x45504150) #define FLASH_SIZE (16 * MiB) @@ -105,16 +106,13 @@ 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, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]); + qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, - ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]); + qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); /* This board doesn't wire anything up to the inputs of the UIC. */ return cpu; @@ -148,11 +146,10 @@ static void main_cpu_reset(void *opaque) } #define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" -static int xilinx_load_device_tree(hwaddr addr, - uint32_t ramsize, - hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) +static int xilinx_load_device_tree(MachineState *machine, + hwaddr addr, + hwaddr initrd_base, + hwaddr initrd_size) { char *path; int fdt_size; @@ -160,7 +157,7 @@ static int xilinx_load_device_tree(hwaddr addr, int r; const char *dtb_filename; - dtb_filename = current_machine->dtb; + dtb_filename = machine->dtb; if (dtb_filename) { fdt = load_device_tree(dtb_filename, &fdt_size); if (!fdt) { @@ -194,18 +191,21 @@ static int xilinx_load_device_tree(hwaddr addr, error_report("couldn't set /chosen/linux,initrd-end"); } - r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + machine->kernel_cmdline); if (r < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); cpu_physical_memory_write(addr, fdt, fdt_size); - g_free(fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + return fdt_size; } static void virtex_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; hwaddr initrd_base = 0; int initrd_size = 0; MemoryRegion *address_space_mem = get_system_memory(); @@ -214,7 +214,7 @@ static void virtex_init(MachineState *machine) CPUPPCState *env; hwaddr ram_base = 0; DriveInfo *dinfo; - qemu_irq irq[32], *cpu_irq; + qemu_irq irq[32], cpu_irq; int kernel_size; int i; @@ -237,12 +237,12 @@ static void virtex_init(MachineState *machine) dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1); - cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; + cpu_irq = qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT); dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 0); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); } @@ -298,9 +298,8 @@ static void virtex_init(MachineState *machine) boot_info.fdt = high + (8192 * 2); boot_info.fdt &= ~8191; - xilinx_load_device_tree(boot_info.fdt, machine->ram_size, - initrd_base, initrd_size, - kernel_cmdline); + xilinx_load_device_tree(machine, boot_info.fdt, + initrd_base, initrd_size); } env->load_info = &boot_info; } diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c index 2b63a6287561..18c3f92317a4 100644 --- a/hw/ppc/vof.c +++ b/hw/ppc/vof.c @@ -10,7 +10,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/timer.h" #include "qemu/range.h" #include "qemu/units.h" @@ -294,7 +293,7 @@ static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof, uint32_t nodeph, uint32_t pname, uint32_t valaddr, uint32_t vallen) { - char propname[OF_PROPNAME_LEN_MAX + 1]; + char propname[OF_PROPNAME_LEN_MAX + 1] = ""; uint32_t ret = PROM_ERROR; int offset, rc; char trval[64] = ""; diff --git a/hw/rdma/rdma_utils.c b/hw/rdma/rdma_utils.c index 5a7ef63ad287..c948baf052f9 100644 --- a/hw/rdma/rdma_utils.c +++ b/hw/rdma/rdma_utils.c @@ -14,6 +14,7 @@ */ #include "qemu/osdep.h" +#include "hw/pci/pci_device.h" #include "trace.h" #include "rdma_utils.h" diff --git a/hw/rdma/rdma_utils.h b/hw/rdma/rdma_utils.h index 0c6414e7e0a8..54e4f56eddde 100644 --- a/hw/rdma/rdma_utils.h +++ b/hw/rdma/rdma_utils.h @@ -18,7 +18,6 @@ #define RDMA_UTILS_H #include "qemu/error-report.h" -#include "hw/pci/pci.h" #include "sysemu/dma.h" #define rdma_error_report(fmt, ...) \ diff --git a/hw/rdma/vmw/pvrdma.h b/hw/rdma/vmw/pvrdma.h index d08965d3e2d5..4cbc10c980bf 100644 --- a/hw/rdma/vmw/pvrdma.h +++ b/hw/rdma/vmw/pvrdma.h @@ -18,8 +18,8 @@ #include "qemu/units.h" #include "qemu/notify.h" -#include "hw/pci/pci.h" #include "hw/pci/msix.h" +#include "hw/pci/pci_device.h" #include "chardev/char-fe.h" #include "hw/net/vmxnet3_defs.h" diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c index da7ddfa548ff..1eca6328c924 100644 --- a/hw/rdma/vmw/pvrdma_cmd.c +++ b/hw/rdma/vmw/pvrdma_cmd.c @@ -182,13 +182,10 @@ static int create_pd(PVRDMADev *dev, union pvrdma_cmd_req *req, { struct pvrdma_cmd_create_pd *cmd = &req->create_pd; struct pvrdma_cmd_create_pd_resp *resp = &rsp->create_pd_resp; - int rc; memset(resp, 0, sizeof(*resp)); - rc = rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev, - &resp->pd_handle, cmd->ctx_handle); - - return rc; + return rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev, + &resp->pd_handle, cmd->ctx_handle); } static int destroy_pd(PVRDMADev *dev, union pvrdma_cmd_req *req, @@ -269,8 +266,7 @@ static int create_cq_ring(PCIDevice *pci_dev , PvrdmaRing **ring, r = g_malloc(sizeof(*r)); *ring = r; - r->ring_state = (PvrdmaRingState *) - rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); + r->ring_state = rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); if (!r->ring_state) { rdma_error_report("Failed to map to CQ ring state"); @@ -405,8 +401,7 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma, *rings = sr; /* Create send ring */ - sr->ring_state = (PvrdmaRingState *) - rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); + sr->ring_state = rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); if (!sr->ring_state) { rdma_error_report("Failed to map to QP ring state"); goto out_free_sr_mem; @@ -506,20 +501,17 @@ static int modify_qp(PVRDMADev *dev, union pvrdma_cmd_req *req, union pvrdma_cmd_resp *rsp) { struct pvrdma_cmd_modify_qp *cmd = &req->modify_qp; - int rc; /* No need to verify sgid_index since it is u8 */ - rc = rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev, - cmd->qp_handle, cmd->attr_mask, - cmd->attrs.ah_attr.grh.sgid_index, - (union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid, - cmd->attrs.dest_qp_num, - (enum ibv_qp_state)cmd->attrs.qp_state, - cmd->attrs.qkey, cmd->attrs.rq_psn, - cmd->attrs.sq_psn); - - return rc; + return rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev, + cmd->qp_handle, cmd->attr_mask, + cmd->attrs.ah_attr.grh.sgid_index, + (union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid, + cmd->attrs.dest_qp_num, + (enum ibv_qp_state)cmd->attrs.qp_state, + cmd->attrs.qkey, cmd->attrs.rq_psn, + cmd->attrs.sq_psn); } static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req, @@ -528,15 +520,14 @@ static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req, struct pvrdma_cmd_query_qp *cmd = &req->query_qp; struct pvrdma_cmd_query_qp_resp *resp = &rsp->query_qp_resp; struct ibv_qp_init_attr init_attr; - int rc; memset(resp, 0, sizeof(*resp)); - rc = rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev, cmd->qp_handle, - (struct ibv_qp_attr *)&resp->attrs, cmd->attr_mask, - &init_attr); - - return rc; + return rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev, + cmd->qp_handle, + (struct ibv_qp_attr *)&resp->attrs, + cmd->attr_mask, + &init_attr); } static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req, @@ -562,34 +553,27 @@ static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req, union pvrdma_cmd_resp *rsp) { struct pvrdma_cmd_create_bind *cmd = &req->create_bind; - int rc; union ibv_gid *gid = (union ibv_gid *)&cmd->new_gid; if (cmd->index >= MAX_PORT_GIDS) { return -EINVAL; } - rc = rdma_rm_add_gid(&dev->rdma_dev_res, &dev->backend_dev, - dev->backend_eth_device_name, gid, cmd->index); - - return rc; + return rdma_rm_add_gid(&dev->rdma_dev_res, &dev->backend_dev, + dev->backend_eth_device_name, gid, cmd->index); } static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req, union pvrdma_cmd_resp *rsp) { - int rc; - struct pvrdma_cmd_destroy_bind *cmd = &req->destroy_bind; if (cmd->index >= MAX_PORT_GIDS) { return -EINVAL; } - rc = rdma_rm_del_gid(&dev->rdma_dev_res, &dev->backend_dev, - dev->backend_eth_device_name, cmd->index); - - return rc; + return rdma_rm_del_gid(&dev->rdma_dev_res, &dev->backend_dev, + dev->backend_eth_device_name, cmd->index); } static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req, @@ -597,12 +581,9 @@ static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req, { struct pvrdma_cmd_create_uc *cmd = &req->create_uc; struct pvrdma_cmd_create_uc_resp *resp = &rsp->create_uc_resp; - int rc; memset(resp, 0, sizeof(*resp)); - rc = rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn, &resp->ctx_handle); - - return rc; + return rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn, &resp->ctx_handle); } static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req, @@ -646,8 +627,7 @@ static int create_srq_ring(PCIDevice *pci_dev, PvrdmaRing **ring, r = g_malloc(sizeof(*r)); *ring = r; - r->ring_state = (PvrdmaRingState *) - rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); + r->ring_state = rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); if (!r->ring_state) { rdma_error_report("Failed to map tp SRQ ring state"); goto out_free_ring_mem; diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 91206dbb8eb0..4fc67120256b 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -159,13 +159,13 @@ static void free_dsr(PVRDMADev *dev) free_dev_ring(pci_dev, &dev->dsr_info.cq, dev->dsr_info.cq_ring_state); rdma_pci_dma_unmap(pci_dev, dev->dsr_info.req, - sizeof(union pvrdma_cmd_req)); + sizeof(union pvrdma_cmd_req)); rdma_pci_dma_unmap(pci_dev, dev->dsr_info.rsp, - sizeof(union pvrdma_cmd_resp)); + sizeof(union pvrdma_cmd_resp)); rdma_pci_dma_unmap(pci_dev, dev->dsr_info.dsr, - sizeof(struct pvrdma_device_shared_region)); + sizeof(struct pvrdma_device_shared_region)); dev->dsr_info.dsr = NULL; } @@ -249,7 +249,8 @@ static void init_dsr_dev_caps(PVRDMADev *dev) { struct pvrdma_device_shared_region *dsr; - if (dev->dsr_info.dsr == NULL) { + if (!dev->dsr_info.dsr) { + /* Buggy or malicious guest driver */ rdma_error_report("Can't initialized DSR"); return; } @@ -306,12 +307,7 @@ static int init_msix(PCIDevice *pdev) } for (i = 0; i < RDMA_MAX_INTRS; i++) { - rc = msix_vector_use(PCI_DEVICE(dev), i); - if (rc < 0) { - rdma_error_report("Fail mark MSI-X vector %d", i); - uninit_msix(pdev, i); - return rc; - } + msix_vector_use(PCI_DEVICE(dev), i); } return 0; @@ -608,7 +604,7 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp) rdma_info_report("Initializing device %s %x.%x", pdev->name, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - if (TARGET_PAGE_SIZE != qemu_real_host_page_size) { + if (TARGET_PAGE_SIZE != qemu_real_host_page_size()) { error_setg(errp, "Target page size must be the same as host page size"); return; } diff --git a/hw/rdma/vmw/pvrdma_qp_ops.c b/hw/rdma/vmw/pvrdma_qp_ops.c index bd7cbf2bdfa9..c30c8344f67f 100644 --- a/hw/rdma/vmw/pvrdma_qp_ops.c +++ b/hw/rdma/vmw/pvrdma_qp_ops.c @@ -149,7 +149,7 @@ void pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle) ring = (PvrdmaRing *)qp->opaque; - wqe = (struct PvrdmaSqWqe *)pvrdma_ring_next_elem_read(ring); + wqe = pvrdma_ring_next_elem_read(ring); while (wqe) { CompHandlerCtx *comp_ctx; @@ -212,7 +212,7 @@ void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle) ring = &((PvrdmaRing *)qp->opaque)[1]; - wqe = (struct PvrdmaRqWqe *)pvrdma_ring_next_elem_read(ring); + wqe = pvrdma_ring_next_elem_read(ring); while (wqe) { CompHandlerCtx *comp_ctx; @@ -254,7 +254,7 @@ void pvrdma_srq_recv(PVRDMADev *dev, uint32_t srq_handle) ring = (PvrdmaRing *)srq->opaque; - wqe = (struct PvrdmaRqWqe *)pvrdma_ring_next_elem_read(ring); + wqe = pvrdma_ring_next_elem_read(ring); while (wqe) { CompHandlerCtx *comp_ctx; diff --git a/hw/remote/Kconfig b/hw/remote/Kconfig index 08c16e235f5e..2d6b4f4cf49b 100644 --- a/hw/remote/Kconfig +++ b/hw/remote/Kconfig @@ -2,3 +2,7 @@ config MULTIPROCESS bool depends on PCI && PCI_EXPRESS && KVM select REMOTE_PCIHOST + +config VFIO_USER_SERVER + bool + depends on MULTIPROCESS diff --git a/hw/remote/iohub.c b/hw/remote/iohub.c index 547d597f0feb..40dfee4bad43 100644 --- a/hw/remote/iohub.c +++ b/hw/remote/iohub.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/pci/pci.h" #include "hw/pci/pci_ids.h" diff --git a/hw/remote/iommu.c b/hw/remote/iommu.c new file mode 100644 index 000000000000..1391dd712ced --- /dev/null +++ b/hw/remote/iommu.c @@ -0,0 +1,131 @@ +/** + * IOMMU for remote device + * + * Copyright © 2022 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "hw/remote/iommu.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "trace.h" + +/** + * IOMMU for TYPE_REMOTE_MACHINE - manages DMA address space isolation + * for remote machine. It is used by TYPE_VFIO_USER_SERVER. + * + * - Each TYPE_VFIO_USER_SERVER instance handles one PCIDevice on a PCIBus. + * There is one RemoteIommu per PCIBus, so the RemoteIommu tracks multiple + * PCIDevices by maintaining a ->elem_by_devfn mapping. + * + * - memory_region_init_iommu() is not used because vfio-user MemoryRegions + * will be added to the elem->mr container instead. This is more natural + * than implementing the IOMMUMemoryRegionClass APIs since vfio-user + * provides something that is close to a full-fledged MemoryRegion and + * not like an IOMMU mapping. + * + * - When a device is hot unplugged, the elem->mr reference is dropped so + * all vfio-user MemoryRegions associated with this vfio-user server are + * destroyed. + */ + +static AddressSpace *remote_iommu_find_add_as(PCIBus *pci_bus, + void *opaque, int devfn) +{ + RemoteIommu *iommu = opaque; + RemoteIommuElem *elem = NULL; + + qemu_mutex_lock(&iommu->lock); + + elem = g_hash_table_lookup(iommu->elem_by_devfn, INT2VOIDP(devfn)); + + if (!elem) { + elem = g_new0(RemoteIommuElem, 1); + g_hash_table_insert(iommu->elem_by_devfn, INT2VOIDP(devfn), elem); + } + + if (!elem->mr) { + elem->mr = MEMORY_REGION(object_new(TYPE_MEMORY_REGION)); + memory_region_set_size(elem->mr, UINT64_MAX); + address_space_init(&elem->as, elem->mr, NULL); + } + + qemu_mutex_unlock(&iommu->lock); + + return &elem->as; +} + +void remote_iommu_unplug_dev(PCIDevice *pci_dev) +{ + AddressSpace *as = pci_device_iommu_address_space(pci_dev); + RemoteIommuElem *elem = NULL; + + if (as == &address_space_memory) { + return; + } + + elem = container_of(as, RemoteIommuElem, as); + + address_space_destroy(&elem->as); + + object_unref(elem->mr); + + elem->mr = NULL; +} + +static void remote_iommu_init(Object *obj) +{ + RemoteIommu *iommu = REMOTE_IOMMU(obj); + + iommu->elem_by_devfn = g_hash_table_new_full(NULL, NULL, NULL, g_free); + + qemu_mutex_init(&iommu->lock); +} + +static void remote_iommu_finalize(Object *obj) +{ + RemoteIommu *iommu = REMOTE_IOMMU(obj); + + qemu_mutex_destroy(&iommu->lock); + + g_hash_table_destroy(iommu->elem_by_devfn); + + iommu->elem_by_devfn = NULL; +} + +void remote_iommu_setup(PCIBus *pci_bus) +{ + RemoteIommu *iommu = NULL; + + g_assert(pci_bus); + + iommu = REMOTE_IOMMU(object_new(TYPE_REMOTE_IOMMU)); + + pci_setup_iommu(pci_bus, remote_iommu_find_add_as, iommu); + + object_property_add_child(OBJECT(pci_bus), "remote-iommu", OBJECT(iommu)); + + object_unref(OBJECT(iommu)); +} + +static const TypeInfo remote_iommu_info = { + .name = TYPE_REMOTE_IOMMU, + .parent = TYPE_OBJECT, + .instance_size = sizeof(RemoteIommu), + .instance_init = remote_iommu_init, + .instance_finalize = remote_iommu_finalize, +}; + +static void remote_iommu_register_types(void) +{ + type_register_static(&remote_iommu_info); +} + +type_init(remote_iommu_register_types) diff --git a/hw/remote/machine.c b/hw/remote/machine.c index 952105eab5a2..75d550daae1d 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -14,13 +14,17 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/remote/machine.h" #include "exec/memory.h" #include "qapi/error.h" #include "hw/pci/pci_host.h" #include "hw/remote/iohub.h" +#include "hw/remote/iommu.h" +#include "hw/qdev-core.h" +#include "hw/remote/iommu.h" +#include "hw/remote/vfio-user-obj.h" +#include "hw/pci/msi.h" static void remote_machine_init(MachineState *machine) { @@ -50,25 +54,102 @@ static void remote_machine_init(MachineState *machine) pci_host = PCI_HOST_BRIDGE(rem_host); - remote_iohub_init(&s->iohub); + if (s->vfio_user) { + remote_iommu_setup(pci_host->bus); - pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq, - &s->iohub, REMOTE_IOHUB_NB_PIRQS); + msi_nonbroken = true; + + vfu_object_set_bus_irq(pci_host->bus); + } else { + remote_iohub_init(&s->iohub); + + pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq, + &s->iohub, REMOTE_IOHUB_NB_PIRQS); + } + + qbus_set_hotplug_handler(BUS(pci_host->bus), OBJECT(s)); +} + +static bool remote_machine_get_vfio_user(Object *obj, Error **errp) +{ + RemoteMachineState *s = REMOTE_MACHINE(obj); + + return s->vfio_user; +} + +static void remote_machine_set_vfio_user(Object *obj, bool value, Error **errp) +{ + RemoteMachineState *s = REMOTE_MACHINE(obj); + + if (phase_check(PHASE_MACHINE_CREATED)) { + error_setg(errp, "Error enabling vfio-user - machine already created"); + return; + } + + s->vfio_user = value; +} + +static bool remote_machine_get_auto_shutdown(Object *obj, Error **errp) +{ + RemoteMachineState *s = REMOTE_MACHINE(obj); + + return s->auto_shutdown; +} + +static void remote_machine_set_auto_shutdown(Object *obj, bool value, + Error **errp) +{ + RemoteMachineState *s = REMOTE_MACHINE(obj); + + s->auto_shutdown = value; +} + +static void remote_machine_instance_init(Object *obj) +{ + RemoteMachineState *s = REMOTE_MACHINE(obj); + + s->auto_shutdown = true; +} + +static void remote_machine_dev_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + qdev_unrealize(dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + remote_iommu_unplug_dev(PCI_DEVICE(dev)); + } } static void remote_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); mc->init = remote_machine_init; mc->desc = "Experimental remote machine"; + + hc->unplug = remote_machine_dev_unplug_cb; + + object_class_property_add_bool(oc, "vfio-user", + remote_machine_get_vfio_user, + remote_machine_set_vfio_user); + + object_class_property_add_bool(oc, "auto-shutdown", + remote_machine_get_auto_shutdown, + remote_machine_set_auto_shutdown); } static const TypeInfo remote_machine = { .name = TYPE_REMOTE_MACHINE, .parent = TYPE_MACHINE, .instance_size = sizeof(RemoteMachineState), + .instance_init = remote_machine_instance_init, .class_init = remote_machine_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } }; static void remote_machine_register_types(void) diff --git a/hw/remote/memory.c b/hw/remote/memory.c index 6e21ab1a45c9..6d60da91e01c 100644 --- a/hw/remote/memory.c +++ b/hw/remote/memory.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/remote/memory.h" #include "exec/ram_addr.h" diff --git a/hw/remote/meson.build b/hw/remote/meson.build index e6a5574242fc..ab25c04906c9 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -6,6 +6,10 @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iohub.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iommu.c')) +remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: files('vfio-user-obj.c')) + +remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: libvfio_user_dep) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c')) diff --git a/hw/remote/message.c b/hw/remote/message.c index 11d729845c5a..50f6bf2d495f 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/remote/machine.h" #include "io/channel.h" diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index 7e841820e521..9bd98e82197e 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/module.h" #include "hw/remote/mpqemu-link.h" @@ -69,7 +68,7 @@ bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp) } if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send), - fds, nfds, errp)) { + fds, nfds, 0, errp)) { ret = true; } else { trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds); diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index 0e893f3189e9..eb9918fe72bb 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -7,7 +7,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/compiler.h" #include "qemu/int128.h" diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index bad164299dd4..1c7786b52cf1 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -7,7 +7,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "hw/remote/proxy.h" #include "hw/pci/pci.h" diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c index 4f21254219f8..333e5ac44331 100644 --- a/hw/remote/remote-obj.c +++ b/hw/remote/remote-obj.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/notify.h" diff --git a/hw/remote/trace-events b/hw/remote/trace-events index 0b23974f90c5..c167b3c7a570 100644 --- a/hw/remote/trace-events +++ b/hw/remote/trace-events @@ -2,3 +2,14 @@ mpqemu_send_io_error(int cmd, int size, int nfds) "send command %d size %d, %d file descriptors to remote process" mpqemu_recv_io_error(int cmd, int size, int nfds) "failed to receive %d size %d, %d file descriptors to remote process" + +# vfio-user-obj.c +vfu_prop(const char *prop, const char *val) "vfu: setting %s as %s" +vfu_cfg_read(uint32_t offset, uint32_t val) "vfu: cfg: 0x%u -> 0x%x" +vfu_cfg_write(uint32_t offset, uint32_t val) "vfu: cfg: 0x%u <- 0x%x" +vfu_dma_register(uint64_t gpa, size_t len) "vfu: registering GPA 0x%"PRIx64", %zu bytes" +vfu_dma_unregister(uint64_t gpa) "vfu: unregistering GPA 0x%"PRIx64"" +vfu_bar_register(int i, uint64_t addr, uint64_t size) "vfu: BAR %d: addr 0x%"PRIx64" size 0x%"PRIx64"" +vfu_bar_rw_enter(const char *op, uint64_t addr) "vfu: %s request for BAR address 0x%"PRIx64"" +vfu_bar_rw_exit(const char *op, uint64_t addr) "vfu: Finished %s of BAR address 0x%"PRIx64"" +vfu_interrupt(int pirq) "vfu: sending interrupt to device - PIRQ %d" diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c new file mode 100644 index 000000000000..fe1fdfb5f709 --- /dev/null +++ b/hw/remote/vfio-user-obj.c @@ -0,0 +1,950 @@ +/** + * QEMU vfio-user-server server object + * + * Copyright © 2022 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL-v2, version 2 or later. + * + * See the COPYING file in the top-level directory. + * + */ + +/** + * Usage: add options: + * -machine x-remote,vfio-user=on,auto-shutdown=on + * -device ,id= + * -object x-vfio-user-server,id=,type=unix,path=, + * device= + * + * Note that x-vfio-user-server object must be used with x-remote machine only. + * This server could only support PCI devices for now. + * + * type - SocketAddress type - presently "unix" alone is supported. Required + * option + * + * path - named unix socket, it will be created by the server. It is + * a required option + * + * device - id of a device on the server, a required option. PCI devices + * alone are supported presently. + * + * notes - x-vfio-user-server could block IO and monitor during the + * initialization phase. + */ + +#include "qemu/osdep.h" + +#include "qom/object.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "trace.h" +#include "sysemu/runstate.h" +#include "hw/boards.h" +#include "hw/remote/machine.h" +#include "qapi/error.h" +#include "qapi/qapi-visit-sockets.h" +#include "qapi/qapi-events-misc.h" +#include "qemu/notify.h" +#include "qemu/thread.h" +#include "qemu/main-loop.h" +#include "sysemu/sysemu.h" +#include "libvfio-user.h" +#include "hw/qdev-core.h" +#include "hw/pci/pci.h" +#include "qemu/timer.h" +#include "exec/memory.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/remote/vfio-user-obj.h" + +#define TYPE_VFU_OBJECT "x-vfio-user-server" +OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) + +/** + * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown + * is set, it aborts the machine on error. Otherwise, it logs an + * error message without aborting. + */ +#define VFU_OBJECT_ERROR(o, fmt, ...) \ + { \ + if (vfu_object_auto_shutdown()) { \ + error_setg(&error_abort, (fmt), ## __VA_ARGS__); \ + } else { \ + error_report((fmt), ## __VA_ARGS__); \ + } \ + } \ + +struct VfuObjectClass { + ObjectClass parent_class; + + unsigned int nr_devs; +}; + +struct VfuObject { + /* private */ + Object parent; + + SocketAddress *socket; + + char *device; + + Error *err; + + Notifier machine_done; + + vfu_ctx_t *vfu_ctx; + + PCIDevice *pci_dev; + + Error *unplug_blocker; + + int vfu_poll_fd; + + MSITriggerFunc *default_msi_trigger; + MSIPrepareMessageFunc *default_msi_prepare_message; + MSIxPrepareMessageFunc *default_msix_prepare_message; +}; + +static void vfu_object_init_ctx(VfuObject *o, Error **errp); + +static bool vfu_object_auto_shutdown(void) +{ + bool auto_shutdown = true; + Error *local_err = NULL; + + if (!current_machine) { + return auto_shutdown; + } + + auto_shutdown = object_property_get_bool(OBJECT(current_machine), + "auto-shutdown", + &local_err); + + /* + * local_err would be set if no such property exists - safe to ignore. + * Unlikely scenario as auto-shutdown is always defined for + * TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with + * TYPE_REMOTE_MACHINE + */ + if (local_err) { + auto_shutdown = true; + error_free(local_err); + } + + return auto_shutdown; +} + +static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + VfuObject *o = VFU_OBJECT(obj); + + if (o->vfu_ctx) { + error_setg(errp, "vfu: Unable to set socket property - server busy"); + return; + } + + qapi_free_SocketAddress(o->socket); + + o->socket = NULL; + + visit_type_SocketAddress(v, name, &o->socket, errp); + + if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { + error_setg(errp, "vfu: Unsupported socket type - %s", + SocketAddressType_str(o->socket->type)); + qapi_free_SocketAddress(o->socket); + o->socket = NULL; + return; + } + + trace_vfu_prop("socket", o->socket->u.q_unix.path); + + vfu_object_init_ctx(o, errp); +} + +static void vfu_object_set_device(Object *obj, const char *str, Error **errp) +{ + VfuObject *o = VFU_OBJECT(obj); + + if (o->vfu_ctx) { + error_setg(errp, "vfu: Unable to set device property - server busy"); + return; + } + + g_free(o->device); + + o->device = g_strdup(str); + + trace_vfu_prop("device", str); + + vfu_object_init_ctx(o, errp); +} + +static void vfu_object_ctx_run(void *opaque) +{ + VfuObject *o = opaque; + const char *vfu_id; + char *vfu_path, *pci_dev_path; + int ret = -1; + + while (ret != 0) { + ret = vfu_run_ctx(o->vfu_ctx); + if (ret < 0) { + if (errno == EINTR) { + continue; + } else if (errno == ENOTCONN) { + vfu_id = object_get_canonical_path_component(OBJECT(o)); + vfu_path = object_get_canonical_path(OBJECT(o)); + g_assert(o->pci_dev); + pci_dev_path = object_get_canonical_path(OBJECT(o->pci_dev)); + /* o->device is a required property and is non-NULL here */ + g_assert(o->device); + qapi_event_send_vfu_client_hangup(vfu_id, vfu_path, + o->device, pci_dev_path); + qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); + o->vfu_poll_fd = -1; + object_unparent(OBJECT(o)); + g_free(vfu_path); + g_free(pci_dev_path); + break; + } else { + VFU_OBJECT_ERROR(o, "vfu: Failed to run device %s - %s", + o->device, strerror(errno)); + break; + } + } + } +} + +static void vfu_object_attach_ctx(void *opaque) +{ + VfuObject *o = opaque; + GPollFD pfds[1]; + int ret; + + qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); + + pfds[0].fd = o->vfu_poll_fd; + pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR; + +retry_attach: + ret = vfu_attach_ctx(o->vfu_ctx); + if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + /** + * vfu_object_attach_ctx can block QEMU's main loop + * during attach - the monitor and other IO + * could be unresponsive during this time. + */ + (void)qemu_poll_ns(pfds, 1, 500 * (int64_t)SCALE_MS); + goto retry_attach; + } else if (ret < 0) { + VFU_OBJECT_ERROR(o, "vfu: Failed to attach device %s to context - %s", + o->device, strerror(errno)); + return; + } + + o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); + if (o->vfu_poll_fd < 0) { + VFU_OBJECT_ERROR(o, "vfu: Failed to get poll fd %s", o->device); + return; + } + + qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_ctx_run, NULL, o); +} + +static ssize_t vfu_object_cfg_access(vfu_ctx_t *vfu_ctx, char * const buf, + size_t count, loff_t offset, + const bool is_write) +{ + VfuObject *o = vfu_get_private(vfu_ctx); + uint32_t pci_access_width = sizeof(uint32_t); + size_t bytes = count; + uint32_t val = 0; + char *ptr = buf; + int len; + + /* + * Writes to the BAR registers would trigger an update to the + * global Memory and IO AddressSpaces. But the remote device + * never uses the global AddressSpaces, therefore overlapping + * memory regions are not a problem + */ + while (bytes > 0) { + len = (bytes > pci_access_width) ? pci_access_width : bytes; + if (is_write) { + memcpy(&val, ptr, len); + pci_host_config_write_common(o->pci_dev, offset, + pci_config_size(o->pci_dev), + val, len); + trace_vfu_cfg_write(offset, val); + } else { + val = pci_host_config_read_common(o->pci_dev, offset, + pci_config_size(o->pci_dev), len); + memcpy(ptr, &val, len); + trace_vfu_cfg_read(offset, val); + } + offset += len; + ptr += len; + bytes -= len; + } + + return count; +} + +static void dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) +{ + VfuObject *o = vfu_get_private(vfu_ctx); + AddressSpace *dma_as = NULL; + MemoryRegion *subregion = NULL; + g_autofree char *name = NULL; + struct iovec *iov = &info->iova; + + if (!info->vaddr) { + return; + } + + name = g_strdup_printf("mem-%s-%"PRIx64"", o->device, + (uint64_t)info->vaddr); + + subregion = g_new0(MemoryRegion, 1); + + memory_region_init_ram_ptr(subregion, NULL, name, + iov->iov_len, info->vaddr); + + dma_as = pci_device_iommu_address_space(o->pci_dev); + + memory_region_add_subregion(dma_as->root, (hwaddr)iov->iov_base, subregion); + + trace_vfu_dma_register((uint64_t)iov->iov_base, iov->iov_len); +} + +static void dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) +{ + VfuObject *o = vfu_get_private(vfu_ctx); + AddressSpace *dma_as = NULL; + MemoryRegion *mr = NULL; + ram_addr_t offset; + + mr = memory_region_from_host(info->vaddr, &offset); + if (!mr) { + return; + } + + dma_as = pci_device_iommu_address_space(o->pci_dev); + + memory_region_del_subregion(dma_as->root, mr); + + object_unparent((OBJECT(mr))); + + trace_vfu_dma_unregister((uint64_t)info->iova.iov_base); +} + +static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset, + hwaddr size, const bool is_write) +{ + uint8_t *ptr = buf; + bool release_lock = false; + uint8_t *ram_ptr = NULL; + MemTxResult result; + int access_size; + uint64_t val; + + if (memory_access_is_direct(mr, is_write)) { + /** + * Some devices expose a PCI expansion ROM, which could be buffer + * based as compared to other regions which are primarily based on + * MemoryRegionOps. memory_region_find() would already check + * for buffer overflow, we don't need to repeat it here. + */ + ram_ptr = memory_region_get_ram_ptr(mr); + + if (is_write) { + memcpy((ram_ptr + offset), buf, size); + } else { + memcpy(buf, (ram_ptr + offset), size); + } + + return 0; + } + + while (size) { + /** + * The read/write logic used below is similar to the ones in + * flatview_read/write_continue() + */ + release_lock = prepare_mmio_access(mr); + + access_size = memory_access_size(mr, size, offset); + + if (is_write) { + val = ldn_he_p(ptr, access_size); + + result = memory_region_dispatch_write(mr, offset, val, + size_memop(access_size), + MEMTXATTRS_UNSPECIFIED); + } else { + result = memory_region_dispatch_read(mr, offset, &val, + size_memop(access_size), + MEMTXATTRS_UNSPECIFIED); + + stn_he_p(ptr, access_size, val); + } + + if (release_lock) { + qemu_mutex_unlock_iothread(); + release_lock = false; + } + + if (result != MEMTX_OK) { + return -1; + } + + size -= access_size; + ptr += access_size; + offset += access_size; + } + + return 0; +} + +static size_t vfu_object_bar_rw(PCIDevice *pci_dev, int pci_bar, + hwaddr bar_offset, char * const buf, + hwaddr len, const bool is_write) +{ + MemoryRegionSection section = { 0 }; + uint8_t *ptr = (uint8_t *)buf; + MemoryRegion *section_mr = NULL; + uint64_t section_size; + hwaddr section_offset; + hwaddr size = 0; + + while (len) { + section = memory_region_find(pci_dev->io_regions[pci_bar].memory, + bar_offset, len); + + if (!section.mr) { + warn_report("vfu: invalid address 0x%"PRIx64"", bar_offset); + return size; + } + + section_mr = section.mr; + section_offset = section.offset_within_region; + section_size = int128_get64(section.size); + + if (is_write && section_mr->readonly) { + warn_report("vfu: attempting to write to readonly region in " + "bar %d - [0x%"PRIx64" - 0x%"PRIx64"]", + pci_bar, bar_offset, + (bar_offset + section_size)); + memory_region_unref(section_mr); + return size; + } + + if (vfu_object_mr_rw(section_mr, ptr, section_offset, + section_size, is_write)) { + warn_report("vfu: failed to %s " + "[0x%"PRIx64" - 0x%"PRIx64"] in bar %d", + is_write ? "write to" : "read from", bar_offset, + (bar_offset + section_size), pci_bar); + memory_region_unref(section_mr); + return size; + } + + size += section_size; + bar_offset += section_size; + ptr += section_size; + len -= section_size; + + memory_region_unref(section_mr); + } + + return size; +} + +/** + * VFU_OBJECT_BAR_HANDLER - macro for defining handlers for PCI BARs. + * + * To create handler for BAR number 2, VFU_OBJECT_BAR_HANDLER(2) would + * define vfu_object_bar2_handler + */ +#define VFU_OBJECT_BAR_HANDLER(BAR_NO) \ + static ssize_t vfu_object_bar##BAR_NO##_handler(vfu_ctx_t *vfu_ctx, \ + char * const buf, size_t count, \ + loff_t offset, const bool is_write) \ + { \ + VfuObject *o = vfu_get_private(vfu_ctx); \ + PCIDevice *pci_dev = o->pci_dev; \ + \ + return vfu_object_bar_rw(pci_dev, BAR_NO, offset, \ + buf, count, is_write); \ + } \ + +VFU_OBJECT_BAR_HANDLER(0) +VFU_OBJECT_BAR_HANDLER(1) +VFU_OBJECT_BAR_HANDLER(2) +VFU_OBJECT_BAR_HANDLER(3) +VFU_OBJECT_BAR_HANDLER(4) +VFU_OBJECT_BAR_HANDLER(5) +VFU_OBJECT_BAR_HANDLER(6) + +static vfu_region_access_cb_t *vfu_object_bar_handlers[PCI_NUM_REGIONS] = { + &vfu_object_bar0_handler, + &vfu_object_bar1_handler, + &vfu_object_bar2_handler, + &vfu_object_bar3_handler, + &vfu_object_bar4_handler, + &vfu_object_bar5_handler, + &vfu_object_bar6_handler, +}; + +/** + * vfu_object_register_bars - Identify active BAR regions of pdev and setup + * callbacks to handle read/write accesses + */ +static void vfu_object_register_bars(vfu_ctx_t *vfu_ctx, PCIDevice *pdev) +{ + int flags = VFU_REGION_FLAG_RW; + int i; + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + if (!pdev->io_regions[i].size) { + continue; + } + + if ((i == VFU_PCI_DEV_ROM_REGION_IDX) || + pdev->io_regions[i].memory->readonly) { + flags &= ~VFU_REGION_FLAG_WRITE; + } + + vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR0_REGION_IDX + i, + (size_t)pdev->io_regions[i].size, + vfu_object_bar_handlers[i], + flags, NULL, 0, -1, 0); + + trace_vfu_bar_register(i, pdev->io_regions[i].addr, + pdev->io_regions[i].size); + } +} + +static int vfu_object_map_irq(PCIDevice *pci_dev, int intx) +{ + int pci_bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)), + pci_dev->devfn); + + return pci_bdf; +} + +static void vfu_object_set_irq(void *opaque, int pirq, int level) +{ + PCIBus *pci_bus = opaque; + PCIDevice *pci_dev = NULL; + vfu_ctx_t *vfu_ctx = NULL; + int pci_bus_num, devfn; + + if (level) { + pci_bus_num = PCI_BUS_NUM(pirq); + devfn = PCI_BDF_TO_DEVFN(pirq); + + /* + * pci_find_device() performs at O(1) if the device is attached + * to the root PCI bus. Whereas, if the device is attached to a + * secondary PCI bus (such as when a root port is involved), + * finding the parent PCI bus could take O(n) + */ + pci_dev = pci_find_device(pci_bus, pci_bus_num, devfn); + + vfu_ctx = pci_dev->irq_opaque; + + g_assert(vfu_ctx); + + vfu_irq_trigger(vfu_ctx, 0); + } +} + +static MSIMessage vfu_object_msi_prepare_msg(PCIDevice *pci_dev, + unsigned int vector) +{ + MSIMessage msg; + + msg.address = 0; + msg.data = vector; + + return msg; +} + +static void vfu_object_msi_trigger(PCIDevice *pci_dev, MSIMessage msg) +{ + vfu_ctx_t *vfu_ctx = pci_dev->irq_opaque; + + vfu_irq_trigger(vfu_ctx, msg.data); +} + +static void vfu_object_setup_msi_cbs(VfuObject *o) +{ + o->default_msi_trigger = o->pci_dev->msi_trigger; + o->default_msi_prepare_message = o->pci_dev->msi_prepare_message; + o->default_msix_prepare_message = o->pci_dev->msix_prepare_message; + + o->pci_dev->msi_trigger = vfu_object_msi_trigger; + o->pci_dev->msi_prepare_message = vfu_object_msi_prepare_msg; + o->pci_dev->msix_prepare_message = vfu_object_msi_prepare_msg; +} + +static void vfu_object_restore_msi_cbs(VfuObject *o) +{ + o->pci_dev->msi_trigger = o->default_msi_trigger; + o->pci_dev->msi_prepare_message = o->default_msi_prepare_message; + o->pci_dev->msix_prepare_message = o->default_msix_prepare_message; +} + +static void vfu_msix_irq_state(vfu_ctx_t *vfu_ctx, uint32_t start, + uint32_t count, bool mask) +{ + VfuObject *o = vfu_get_private(vfu_ctx); + uint32_t vector; + + for (vector = start; vector < count; vector++) { + msix_set_mask(o->pci_dev, vector, mask); + } +} + +static void vfu_msi_irq_state(vfu_ctx_t *vfu_ctx, uint32_t start, + uint32_t count, bool mask) +{ + VfuObject *o = vfu_get_private(vfu_ctx); + Error *err = NULL; + uint32_t vector; + + for (vector = start; vector < count; vector++) { + msi_set_mask(o->pci_dev, vector, mask, &err); + if (err) { + VFU_OBJECT_ERROR(o, "vfu: %s: %s", o->device, + error_get_pretty(err)); + error_free(err); + err = NULL; + } + } +} + +static int vfu_object_setup_irqs(VfuObject *o, PCIDevice *pci_dev) +{ + vfu_ctx_t *vfu_ctx = o->vfu_ctx; + int ret; + + ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_INTX_IRQ, 1); + if (ret < 0) { + return ret; + } + + if (msix_nr_vectors_allocated(pci_dev)) { + ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_MSIX_IRQ, + msix_nr_vectors_allocated(pci_dev)); + vfu_setup_irq_state_callback(vfu_ctx, VFU_DEV_MSIX_IRQ, + &vfu_msix_irq_state); + } else if (msi_nr_vectors_allocated(pci_dev)) { + ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_MSI_IRQ, + msi_nr_vectors_allocated(pci_dev)); + vfu_setup_irq_state_callback(vfu_ctx, VFU_DEV_MSI_IRQ, + &vfu_msi_irq_state); + } + + if (ret < 0) { + return ret; + } + + vfu_object_setup_msi_cbs(o); + + pci_dev->irq_opaque = vfu_ctx; + + return 0; +} + +void vfu_object_set_bus_irq(PCIBus *pci_bus) +{ + int bus_num = pci_bus_num(pci_bus); + int max_bdf = PCI_BUILD_BDF(bus_num, PCI_DEVFN_MAX - 1); + + pci_bus_irqs(pci_bus, vfu_object_set_irq, vfu_object_map_irq, pci_bus, + max_bdf); +} + +static int vfu_object_device_reset(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type) +{ + VfuObject *o = vfu_get_private(vfu_ctx); + + /* vfu_object_ctx_run() handles lost connection */ + if (type == VFU_RESET_LOST_CONN) { + return 0; + } + + device_cold_reset(DEVICE(o->pci_dev)); + + return 0; +} + +/* + * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device' + * properties. It also depends on devices instantiated in QEMU. These + * dependencies are not available during the instance_init phase of this + * object's life-cycle. As such, the server is initialized after the + * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT + * when the machine is setup, and the dependencies are available. + */ +static void vfu_object_machine_done(Notifier *notifier, void *data) +{ + VfuObject *o = container_of(notifier, VfuObject, machine_done); + Error *err = NULL; + + vfu_object_init_ctx(o, &err); + + if (err) { + error_propagate(&error_abort, err); + } +} + +/** + * vfu_object_init_ctx: Create and initialize libvfio-user context. Add + * an unplug blocker for the associated PCI device. Setup a FD handler + * to process incoming messages in the context's socket. + * + * The socket and device properties are mandatory, and this function + * will not create the context without them - the setters for these + * properties should call this function when the property is set. The + * machine should also be ready when this function is invoked - it is + * because QEMU objects are initialized before devices, and the + * associated PCI device wouldn't be available at the object + * initialization time. Until these conditions are satisfied, this + * function would return early without performing any task. + */ +static void vfu_object_init_ctx(VfuObject *o, Error **errp) +{ + DeviceState *dev = NULL; + vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL; + int ret; + + if (o->vfu_ctx || !o->socket || !o->device || + !phase_check(PHASE_MACHINE_READY)) { + return; + } + + if (o->err) { + error_propagate(errp, o->err); + o->err = NULL; + return; + } + + o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path, + LIBVFIO_USER_FLAG_ATTACH_NB, + o, VFU_DEV_TYPE_PCI); + if (o->vfu_ctx == NULL) { + error_setg(errp, "vfu: Failed to create context - %s", strerror(errno)); + return; + } + + dev = qdev_find_recursive(sysbus_get_default(), o->device); + if (dev == NULL) { + error_setg(errp, "vfu: Device %s not found", o->device); + goto fail; + } + + if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + error_setg(errp, "vfu: %s not a PCI device", o->device); + goto fail; + } + + o->pci_dev = PCI_DEVICE(dev); + + object_ref(OBJECT(o->pci_dev)); + + if (pci_is_express(o->pci_dev)) { + pci_type = VFU_PCI_TYPE_EXPRESS; + } + + ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0); + if (ret < 0) { + error_setg(errp, + "vfu: Failed to attach PCI device %s to context - %s", + o->device, strerror(errno)); + goto fail; + } + + error_setg(&o->unplug_blocker, + "vfu: %s for %s must be deleted before unplugging", + TYPE_VFU_OBJECT, o->device); + qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); + + ret = vfu_setup_region(o->vfu_ctx, VFU_PCI_DEV_CFG_REGION_IDX, + pci_config_size(o->pci_dev), &vfu_object_cfg_access, + VFU_REGION_FLAG_RW | VFU_REGION_FLAG_ALWAYS_CB, + NULL, 0, -1, 0); + if (ret < 0) { + error_setg(errp, + "vfu: Failed to setup config space handlers for %s- %s", + o->device, strerror(errno)); + goto fail; + } + + ret = vfu_setup_device_dma(o->vfu_ctx, &dma_register, &dma_unregister); + if (ret < 0) { + error_setg(errp, "vfu: Failed to setup DMA handlers for %s", + o->device); + goto fail; + } + + vfu_object_register_bars(o->vfu_ctx, o->pci_dev); + + ret = vfu_object_setup_irqs(o, o->pci_dev); + if (ret < 0) { + error_setg(errp, "vfu: Failed to setup interrupts for %s", + o->device); + goto fail; + } + + ret = vfu_setup_device_reset_cb(o->vfu_ctx, &vfu_object_device_reset); + if (ret < 0) { + error_setg(errp, "vfu: Failed to setup reset callback"); + goto fail; + } + + ret = vfu_realize_ctx(o->vfu_ctx); + if (ret < 0) { + error_setg(errp, "vfu: Failed to realize device %s- %s", + o->device, strerror(errno)); + goto fail; + } + + o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); + if (o->vfu_poll_fd < 0) { + error_setg(errp, "vfu: Failed to get poll fd %s", o->device); + goto fail; + } + + qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_attach_ctx, NULL, o); + + return; + +fail: + vfu_destroy_ctx(o->vfu_ctx); + if (o->unplug_blocker && o->pci_dev) { + qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); + error_free(o->unplug_blocker); + o->unplug_blocker = NULL; + } + if (o->pci_dev) { + vfu_object_restore_msi_cbs(o); + o->pci_dev->irq_opaque = NULL; + object_unref(OBJECT(o->pci_dev)); + o->pci_dev = NULL; + } + o->vfu_ctx = NULL; +} + +static void vfu_object_init(Object *obj) +{ + VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); + VfuObject *o = VFU_OBJECT(obj); + + k->nr_devs++; + + if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { + error_setg(&o->err, "vfu: %s only compatible with %s machine", + TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); + return; + } + + if (!phase_check(PHASE_MACHINE_READY)) { + o->machine_done.notify = vfu_object_machine_done; + qemu_add_machine_init_done_notifier(&o->machine_done); + } + + o->vfu_poll_fd = -1; +} + +static void vfu_object_finalize(Object *obj) +{ + VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); + VfuObject *o = VFU_OBJECT(obj); + + k->nr_devs--; + + qapi_free_SocketAddress(o->socket); + + o->socket = NULL; + + if (o->vfu_poll_fd != -1) { + qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); + o->vfu_poll_fd = -1; + } + + if (o->vfu_ctx) { + vfu_destroy_ctx(o->vfu_ctx); + o->vfu_ctx = NULL; + } + + g_free(o->device); + + o->device = NULL; + + if (o->unplug_blocker && o->pci_dev) { + qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); + error_free(o->unplug_blocker); + o->unplug_blocker = NULL; + } + + if (o->pci_dev) { + vfu_object_restore_msi_cbs(o); + o->pci_dev->irq_opaque = NULL; + object_unref(OBJECT(o->pci_dev)); + o->pci_dev = NULL; + } + + if (!k->nr_devs && vfu_object_auto_shutdown()) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } + + if (o->machine_done.notify) { + qemu_remove_machine_init_done_notifier(&o->machine_done); + o->machine_done.notify = NULL; + } +} + +static void vfu_object_class_init(ObjectClass *klass, void *data) +{ + VfuObjectClass *k = VFU_OBJECT_CLASS(klass); + + k->nr_devs = 0; + + object_class_property_add(klass, "socket", "SocketAddress", NULL, + vfu_object_set_socket, NULL, NULL); + object_class_property_set_description(klass, "socket", + "SocketAddress " + "(ex: type=unix,path=/tmp/sock). " + "Only UNIX is presently supported"); + object_class_property_add_str(klass, "device", NULL, + vfu_object_set_device); + object_class_property_set_description(klass, "device", + "device ID - only PCI devices " + "are presently supported"); +} + +static const TypeInfo vfu_object_info = { + .name = TYPE_VFU_OBJECT, + .parent = TYPE_OBJECT, + .instance_size = sizeof(VfuObject), + .instance_init = vfu_object_init, + .instance_finalize = vfu_object_finalize, + .class_size = sizeof(VfuObjectClass), + .class_init = vfu_object_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void vfu_register_types(void) +{ + type_register_static(&vfu_object_info); +} + +type_init(vfu_register_types); diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 91bb9d21c471..4550b3b938f1 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -4,6 +4,8 @@ config RISCV_NUMA config IBEX bool +# RISC-V machines in alphabetical order + config MICROCHIP_PFSOC bool select CADENCE_SDHCI @@ -11,7 +13,6 @@ config MICROCHIP_PFSOC select MCHP_PFSOC_IOSCB select MCHP_PFSOC_MMUART select MCHP_PFSOC_SYSREG - select MSI_NONBROKEN select RISCV_ACLINT select SIFIVE_PDMA select SIFIVE_PLIC @@ -20,23 +21,17 @@ config MICROCHIP_PFSOC config OPENTITAN bool select IBEX - select UNIMP - -config SHAKTI_C - bool - select UNIMP - select SHAKTI_UART - select RISCV_ACLINT select SIFIVE_PLIC + select UNIMP config RISCV_VIRT bool imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES + imply TPM_TIS_SYSBUS select RISCV_NUMA select GOLDFISH_RTC - select MSI_NONBROKEN select PCI select PCI_EXPRESS_GENERIC_BRIDGE select PFLASH_CFI01 @@ -48,10 +43,17 @@ config RISCV_VIRT select SIFIVE_TEST select VIRTIO_MMIO select FW_CFG_DMA + select PLATFORM_BUS + +config SHAKTI_C + bool + select RISCV_ACLINT + select SHAKTI_UART + select SIFIVE_PLIC + select UNIMP config SIFIVE_E bool - select MSI_NONBROKEN select RISCV_ACLINT select SIFIVE_GPIO select SIFIVE_PLIC @@ -62,7 +64,6 @@ config SIFIVE_E config SIFIVE_U bool select CADENCE - select MSI_NONBROKEN select RISCV_ACLINT select SIFIVE_GPIO select SIFIVE_PDMA @@ -80,6 +81,5 @@ config SPIKE bool select RISCV_NUMA select HTIF - select MSI_NONBROKEN select RISCV_ACLINT select SIFIVE_PLIC diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index cae74fcbcd9a..ebd351c840de 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "qemu/error-report.h" @@ -31,6 +30,7 @@ #include "sysemu/device_tree.h" #include "sysemu/qtest.h" #include "sysemu/kvm.h" +#include "sysemu/reset.h" #include @@ -112,8 +112,8 @@ char *riscv_find_firmware(const char *firmware_filename) if (filename == NULL) { if (!qtest_enabled()) { /* - * We only ship plain binary bios images in the QEMU source. - * With Spike machine that uses ELF images as the default bios, + * We only ship OpenSBI binary bios images in the QEMU source. + * For machines that use images other than the default bios, * running QEMU test will complain hence let's suppress the error * report for QEMU testing. */ @@ -130,7 +130,8 @@ target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb) { - uint64_t firmware_entry, firmware_size, firmware_end; + uint64_t firmware_entry, firmware_end; + ssize_t firmware_size; if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL, &firmware_entry, NULL, &firmware_end, NULL, @@ -186,7 +187,7 @@ target_ulong riscv_load_kernel(const char *kernel_filename, hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start) { - int size; + ssize_t size; /* * We want to put the initrd far enough into RAM that when the @@ -213,9 +214,9 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, return *start + size; } -uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) +uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) { - uint32_t temp, fdt_addr; + uint64_t temp, fdt_addr; hwaddr dram_end = dram_base + mem_size; int ret, fdtsize = fdt_totalsize(fdt); @@ -227,11 +228,11 @@ uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) /* * We should put fdt as far as possible to avoid kernel/initrd overwriting * its content. But it should be addressable by 32 bit system as well. - * Thus, put it at an 16MB aligned address that less than fdt size from the + * Thus, put it at an 2MB aligned address that less than fdt size from the * end of dram or 3GB whichever is lesser. */ - temp = MIN(dram_end, 3072 * MiB); - fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 16 * MiB); + temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; + fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); ret = fdt_pack(fdt); /* Should only fail if we've built a corrupted tree */ @@ -241,6 +242,8 @@ uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, &address_space_memory); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, + rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize)); return fdt_addr; } @@ -286,13 +289,15 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts hwaddr start_addr, hwaddr rom_base, hwaddr rom_size, uint64_t kernel_entry, - uint32_t fdt_load_addr, void *fdt) + uint64_t fdt_load_addr) { int i; uint32_t start_addr_hi32 = 0x00000000; + uint32_t fdt_load_addr_hi32 = 0x00000000; if (!riscv_is_32bit(harts)) { start_addr_hi32 = start_addr >> 32; + fdt_load_addr_hi32 = fdt_load_addr >> 32; } /* reset vector */ uint32_t reset_vec[10] = { @@ -305,7 +310,7 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts start_addr, /* start: .dword */ start_addr_hi32, fdt_load_addr, /* fdt_laddr: .dword */ - 0x00000000, + fdt_load_addr_hi32, /* fw_dyn: */ }; if (riscv_is_32bit(harts)) { @@ -324,8 +329,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) @@ -338,3 +341,32 @@ void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr) riscv_cpu->env.fdt_addr = fdt_addr; } } + +void riscv_setup_firmware_boot(MachineState *machine) +{ + if (machine->kernel_filename) { + FWCfgState *fw_cfg; + fw_cfg = fw_cfg_find(); + + assert(fw_cfg); + /* + * Expose the kernel, the command line, and the initrd in fw_cfg. + * We don't process them here at all, it's all left to the + * firmware. + */ + load_image_to_fw_cfg(fw_cfg, + FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, + machine->kernel_filename, + true); + load_image_to_fw_cfg(fw_cfg, + FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, + machine->initrd_filename, false); + + if (machine->kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, + strlen(machine->kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, + machine->kernel_cmdline); + } + } +} diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index cafd1fc9ae7a..b10321b56409 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -86,46 +86,61 @@ * describes the complete IOSCB modules memory maps */ static const MemMapEntry microchip_pfsoc_memmap[] = { - [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, - [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, - [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, - [MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 }, - [MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 }, - [MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 }, - [MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 }, - [MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 }, - [MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 }, - [MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 }, - [MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 }, - [MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 }, - [MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 }, - [MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 }, - [MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 }, - [MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 }, - [MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 }, - [MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 }, - [MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 }, - [MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 }, - [MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 }, - [MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 }, - [MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 }, - [MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 }, - [MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 }, - [MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 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_ENVM_CFG] = { 0x20200000, 0x1000 }, - [MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 }, - [MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 }, - [MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 }, - [MICROCHIP_PFSOC_EMMC_SD_MUX] = { 0x4f000000, 0x4 }, - [MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 }, - [MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 }, - [MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 }, - [MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 }, + [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, + [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, + [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, + [MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 }, + [MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 }, + [MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 }, + [MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 }, + [MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 }, + [MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 }, + [MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 }, + [MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 }, + [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 }, + [MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 }, + [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_FABRIC_FIC0] = { 0x2000000000, 0x1000000000 }, + [MICROCHIP_PFSOC_FABRIC_FIC1] = { 0x3000000000, 0x1000000000 }, + [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 }, + [MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 }, + }; static void microchip_pfsoc_soc_instance_init(Object *obj) @@ -291,12 +306,25 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp); sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0, memmap[MICROCHIP_PFSOC_SYSREG].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sysreg), 0, + qdev_get_gpio_in(DEVICE(s->plic), + MICROCHIP_PFSOC_MAILBOX_IRQ)); + + /* 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 +364,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 +389,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]; @@ -401,11 +462,22 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->ioscb), 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); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioscb), 0, + qdev_get_gpio_in(DEVICE(s->plic), + MICROCHIP_PFSOC_MAILBOX_IRQ)); + + /* FPGA Fabric */ + create_unimplemented_device("microchip.pfsoc.fabricfic3", + memmap[MICROCHIP_PFSOC_FABRIC_FIC3].base, + memmap[MICROCHIP_PFSOC_FABRIC_FIC3].size); + /* FPGA Fabric */ + create_unimplemented_device("microchip.pfsoc.fabricfic0", + memmap[MICROCHIP_PFSOC_FABRIC_FIC0].base, + memmap[MICROCHIP_PFSOC_FABRIC_FIC0].size); + /* FPGA Fabric */ + create_unimplemented_device("microchip.pfsoc.fabricfic1", + memmap[MICROCHIP_PFSOC_FABRIC_FIC1].base, + memmap[MICROCHIP_PFSOC_FABRIC_FIC1].size); /* QSPI Flash */ memory_region_init_rom(qspi_xip_mem, OBJECT(dev), @@ -571,7 +643,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) "linux,initrd-end", end); } - if (machine->kernel_cmdline) { + if (machine->kernel_cmdline && *machine->kernel_cmdline) { qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs", machine->kernel_cmdline); } @@ -583,7 +655,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 833624d66c42..85ffdac5bef1 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -28,26 +28,36 @@ #include "qemu/units.h" #include "sysemu/sysemu.h" +/* + * This version of the OpenTitan machine currently supports + * OpenTitan RTL version: + * + * + * MMIO mapping as per (specified commit): + * lowRISC/opentitan: hw/top_earlgrey/sw/autogen/top_earlgrey_memory.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 }, [IBEX_DEV_I2C] = { 0x40080000, 0x1000 }, [IBEX_DEV_PATTGEN] = { 0x400e0000, 0x1000 }, [IBEX_DEV_TIMER] = { 0x40100000, 0x1000 }, - [IBEX_DEV_SENSOR_CTRL] = { 0x40110000, 0x1000 }, [IBEX_DEV_OTP_CTRL] = { 0x40130000, 0x4000 }, - [IBEX_DEV_USBDEV] = { 0x40150000, 0x1000 }, + [IBEX_DEV_LC_CTRL] = { 0x40140000, 0x1000 }, + [IBEX_DEV_ALERT_HANDLER] = { 0x40150000, 0x1000 }, [IBEX_DEV_SPI_HOST0] = { 0x40300000, 0x1000 }, [IBEX_DEV_SPI_HOST1] = { 0x40310000, 0x1000 }, + [IBEX_DEV_USBDEV] = { 0x40320000, 0x1000 }, [IBEX_DEV_PWRMGR] = { 0x40400000, 0x1000 }, [IBEX_DEV_RSTMGR] = { 0x40410000, 0x1000 }, [IBEX_DEV_CLKMGR] = { 0x40420000, 0x1000 }, [IBEX_DEV_PINMUX] = { 0x40460000, 0x1000 }, - [IBEX_DEV_PADCTRL] = { 0x40470000, 0x1000 }, + [IBEX_DEV_AON_TIMER] = { 0x40470000, 0x1000 }, + [IBEX_DEV_SENSOR_CTRL] = { 0x40490000, 0x1000 }, [IBEX_DEV_FLASH_CTRL] = { 0x41000000, 0x1000 }, [IBEX_DEV_AES] = { 0x41100000, 0x1000 }, [IBEX_DEV_HMAC] = { 0x41110000, 0x1000 }, @@ -58,10 +68,9 @@ static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_ENTROPY] = { 0x41160000, 0x1000 }, [IBEX_DEV_EDNO] = { 0x41170000, 0x1000 }, [IBEX_DEV_EDN1] = { 0x41180000, 0x1000 }, - [IBEX_DEV_ALERT_HANDLER] = { 0x411b0000, 0x1000 }, [IBEX_DEV_NMI_GEN] = { 0x411c0000, 0x1000 }, [IBEX_DEV_PERI] = { 0x411f0000, 0x10000 }, - [IBEX_DEV_PLIC] = { 0x48000000, 0x4005000 }, + [IBEX_DEV_PLIC] = { 0x48000000, 0x4005000 }, [IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 }, }; @@ -120,11 +129,18 @@ static void lowrisc_ibex_soc_init(Object *obj) object_initialize_child(obj, "uart", &s->uart, TYPE_IBEX_UART); object_initialize_child(obj, "timer", &s->timer, TYPE_IBEX_TIMER); + + for (int i = 0; i < OPENTITAN_NUM_SPI_HOSTS; i++) { + object_initialize_child(obj, "spi_host[*]", &s->spi_host[i], + TYPE_IBEX_SPI_HOST); + } } static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) { const MemMapEntry *memmap = ibex_memmap; + DeviceState *dev; + SysBusDevice *busdev; MachineState *ms = MACHINE(qdev_get_machine()); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); MemoryRegion *sys_mem = get_system_memory(); @@ -134,8 +150,9 @@ 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); - sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &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 */ memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom", @@ -156,10 +173,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) /* PLIC */ qdev_prop_set_string(DEVICE(&s->plic), "hart-config", "M"); - qdev_prop_set_uint32(DEVICE(&s->plic), "hartid-base", 0); qdev_prop_set_uint32(DEVICE(&s->plic), "num-sources", 180); qdev_prop_set_uint32(DEVICE(&s->plic), "num-priorities", 3); - qdev_prop_set_uint32(DEVICE(&s->plic), "priority-base", 0x00); qdev_prop_set_uint32(DEVICE(&s->plic), "pending-base", 0x1000); qdev_prop_set_uint32(DEVICE(&s->plic), "enable-base", 0x2000); qdev_prop_set_uint32(DEVICE(&s->plic), "enable-stride", 32); @@ -209,14 +224,35 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) qdev_get_gpio_in(DEVICE(qemu_get_cpu(0)), IRQ_M_TIMER)); + /* SPI-Hosts */ + for (int i = 0; i < OPENTITAN_NUM_SPI_HOSTS; ++i) { + dev = DEVICE(&(s->spi_host[i])); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi_host[i]), errp)) { + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, memmap[IBEX_DEV_SPI_HOST0 + i].base); + + switch (i) { + case OPENTITAN_SPI_HOST0: + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_SPI_HOST0_ERR_IRQ)); + sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_SPI_HOST0_SPI_EVENT_IRQ)); + break; + case OPENTITAN_SPI_HOST1: + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_SPI_HOST1_ERR_IRQ)); + sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_SPI_HOST1_SPI_EVENT_IRQ)); + break; + } + } + create_unimplemented_device("riscv.lowrisc.ibex.gpio", memmap[IBEX_DEV_GPIO].base, memmap[IBEX_DEV_GPIO].size); create_unimplemented_device("riscv.lowrisc.ibex.spi_device", memmap[IBEX_DEV_SPI_DEVICE].base, memmap[IBEX_DEV_SPI_DEVICE].size); - create_unimplemented_device("riscv.lowrisc.ibex.spi_host0", - memmap[IBEX_DEV_SPI_HOST0].base, memmap[IBEX_DEV_SPI_HOST0].size); - create_unimplemented_device("riscv.lowrisc.ibex.spi_host1", - memmap[IBEX_DEV_SPI_HOST1].base, memmap[IBEX_DEV_SPI_HOST1].size); create_unimplemented_device("riscv.lowrisc.ibex.i2c", memmap[IBEX_DEV_I2C].base, memmap[IBEX_DEV_I2C].size); create_unimplemented_device("riscv.lowrisc.ibex.pattgen", @@ -225,6 +261,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", @@ -233,8 +271,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_DEV_CLKMGR].base, memmap[IBEX_DEV_CLKMGR].size); create_unimplemented_device("riscv.lowrisc.ibex.pinmux", memmap[IBEX_DEV_PINMUX].base, memmap[IBEX_DEV_PINMUX].size); - create_unimplemented_device("riscv.lowrisc.ibex.padctrl", - memmap[IBEX_DEV_PADCTRL].base, memmap[IBEX_DEV_PADCTRL].size); + create_unimplemented_device("riscv.lowrisc.ibex.aon_timer", + memmap[IBEX_DEV_AON_TIMER].base, memmap[IBEX_DEV_AON_TIMER].size); create_unimplemented_device("riscv.lowrisc.ibex.usbdev", memmap[IBEX_DEV_USBDEV].base, memmap[IBEX_DEV_USBDEV].size); create_unimplemented_device("riscv.lowrisc.ibex.flash_ctrl", @@ -265,10 +303,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 90e2cf609f39..e43cc9445cb1 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/sifive_e.c b/hw/riscv/sifive_e.c index dcb87b6cfdf5..d65d2fd869ec 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -195,7 +195,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); /* Mask ROM */ memory_region_init_rom(&s->mask_rom, OBJECT(dev), "riscv.sifive.e.mrom", diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7fbc7dea4212..b40a4767e215 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -287,7 +287,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[SIFIVE_U_DEV_PLIC].base, 0x0, memmap[SIFIVE_U_DEV_PLIC].size); - qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35); + qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", + SIFIVE_U_PLIC_NUM_SOURCES - 1); qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle); plic_phandle = qemu_fdt_get_phandle(fdt, nodename); g_free(cells); @@ -511,7 +512,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, g_free(nodename); update_bootargs: - if (cmdline) { + if (cmdline && *cmdline) { qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } } @@ -634,6 +635,9 @@ static void sifive_u_machine_init(MachineState *machine) start_addr_hi32 = (uint64_t)start_addr >> 32; } + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = s->fdt; + /* reset vector */ uint32_t reset_vec[12] = { s->msel, /* MSEL pin state */ @@ -713,36 +717,20 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error * s->start_in_flash = value; } -static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - visit_type_uint32(v, name, (uint32_t *)opaque, errp); -} - -static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - visit_type_uint32(v, name, (uint32_t *)opaque, errp); -} - static void sifive_u_machine_instance_init(Object *obj) { SiFiveUState *s = RISCV_U_MACHINE(obj); s->start_in_flash = false; s->msel = 0; - object_property_add(obj, "msel", "uint32", - sifive_u_machine_get_uint32_prop, - sifive_u_machine_set_uint32_prop, NULL, &s->msel); + object_property_add_uint32_ptr(obj, "msel", &s->msel, + OBJ_PROP_FLAG_READWRITE); object_property_set_description(obj, "msel", "Mode Select (MSEL[3:0]) pin state"); s->serial = OTP_SERIAL; - object_property_add(obj, "serial", "uint32", - sifive_u_machine_get_uint32_prop, - sifive_u_machine_set_uint32_prop, NULL, &s->serial); + object_property_add_uint32_ptr(obj, "serial", &s->serial, + OBJ_PROP_FLAG_READWRITE); object_property_set_description(obj, "serial", "Board serial number"); } @@ -830,8 +818,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", s->cpu_type); qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004); - sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_fatal); /* * The cluster must be realized after the RISC-V hart array container, * as the container's CPU object is only created on realize, and the diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index d059a67f9b72..13946acf0d18 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -8,7 +8,6 @@ * * 0) HTIF Console and Poweroff * 1) CLINT (Timer and IPI) - * 2) PLIC (Platform Level Interrupt Controller) * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -40,6 +39,8 @@ #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" +#include + static const MemMapEntry spike_memmap[] = { [SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_HTIF] = { 0x1000000, 0x1000 }, @@ -174,10 +175,11 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, riscv_socket_fdt_write_distance_matrix(mc, fdt); - if (cmdline) { - qemu_fdt_add_subnode(fdt, "/chosen"); + qemu_fdt_add_subnode(fdt, "/chosen"); + qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif"); + + if (cmdline && *cmdline) { qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); - qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif"); } } @@ -229,7 +231,7 @@ static void spike_board_init(MachineState *machine) base_hartid, &error_abort); object_property_set_int(OBJECT(&s->soc[i]), "num-harts", hart_count, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal); /* Core Local Interruptor (timer and IPI) for each socket */ riscv_aclint_swi_create( @@ -303,11 +305,15 @@ static void spike_board_init(MachineState *machine) /* Compute the fdt load address in dram */ fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, machine->ram_size, s->fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = s->fdt; + /* load the reset vector */ 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 da50cbed43ec..94ff2a158406 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" @@ -28,6 +29,8 @@ #include "hw/qdev-properties.h" #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" @@ -37,10 +40,12 @@ #include "hw/intc/riscv_imsic.h" #include "hw/intc/sifive_plic.h" #include "hw/misc/sifive_test.h" +#include "hw/platform-bus.h" #include "chardev/char.h" #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "sysemu/tpm.h" #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" #include "hw/display/ramfb.h" @@ -68,25 +73,26 @@ #endif static const MemMapEntry virt_memmap[] = { - [VIRT_DEBUG] = { 0x0, 0x100 }, - [VIRT_MROM] = { 0x1000, 0xf000 }, - [VIRT_TEST] = { 0x100000, 0x1000 }, - [VIRT_RTC] = { 0x101000, 0x1000 }, - [VIRT_CLINT] = { 0x2000000, 0x10000 }, - [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, - [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, - [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, - [VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) }, - [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, - [VIRT_UART0] = { 0x10000000, 0x100 }, - [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, - [VIRT_FW_CFG] = { 0x10100000, 0x18 }, - [VIRT_FLASH] = { 0x20000000, 0x4000000 }, - [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, - [VIRT_IMSIC_S] = { 0x28000000, VIRT_IMSIC_MAX_SIZE }, - [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, - [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, - [VIRT_DRAM] = { 0x80000000, 0x0 }, + [VIRT_DEBUG] = { 0x0, 0x100 }, + [VIRT_MROM] = { 0x1000, 0xf000 }, + [VIRT_TEST] = { 0x100000, 0x1000 }, + [VIRT_RTC] = { 0x101000, 0x1000 }, + [VIRT_CLINT] = { 0x2000000, 0x10000 }, + [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, + [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, + [VIRT_PLATFORM_BUS] = { 0x4000000, 0x2000000 }, + [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, + [VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) }, + [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, + [VIRT_UART0] = { 0x10000000, 0x100 }, + [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, + [VIRT_FW_CFG] = { 0x10100000, 0x18 }, + [VIRT_FLASH] = { 0x20000000, 0x4000000 }, + [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, + [VIRT_IMSIC_S] = { 0x28000000, VIRT_IMSIC_MAX_SIZE }, + [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, + [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, + [VIRT_DRAM] = { 0x80000000, 0x0 }, }; /* PCIe high mmio is fixed for RV32 */ @@ -230,8 +236,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", - (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); + if (riscv_feature(&s->soc[socket].harts[cpu].env, + RISCV_FEATURE_MMU)) { + qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", + (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); + } else { + qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", + "riscv,none"); + } name = riscv_isa_string(&s->soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); @@ -249,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); @@ -455,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)); @@ -463,10 +468,19 @@ static void create_fdt_socket_plic(RISCVVirtState *s, plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg", 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); - qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV); + qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", + VIRT_IRQCHIP_NUM_SOURCES - 1); riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket); qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle", plic_phandles[socket]); + + if (!socket) { + platform_bus_add_all_fdt_nodes(mc->fdt, plic_name, + memmap[VIRT_PLATFORM_BUS].base, + memmap[VIRT_PLATFORM_BUS].size, + VIRT_PLATFORM_BUS_IRQ); + } + g_free(plic_name); g_free(plic_cells); @@ -533,8 +547,6 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, riscv_socket_count(mc) * sizeof(uint32_t) * 4); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids", VIRT_IRQCHIP_NUM_MSIS); - qemu_fdt_setprop_cells(mc->fdt, imsic_name, "riscv,ipi-id", - VIRT_IRQCHIP_IPI_MSI); if (riscv_socket_count(mc) > 1) { qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,hart-index-bits", imsic_num_bits(imsic_max_hart_per_socket)); @@ -544,6 +556,7 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, IMSIC_MMIO_GROUP_MIN_SHIFT); } qemu_fdt_setprop_cell(mc->fdt, imsic_name, "phandle", *msi_m_phandle); + g_free(imsic_name); /* S-level IMSIC node */ @@ -583,8 +596,6 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, riscv_socket_count(mc) * sizeof(uint32_t) * 4); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids", VIRT_IRQCHIP_NUM_MSIS); - qemu_fdt_setprop_cells(mc->fdt, imsic_name, "riscv,ipi-id", - VIRT_IRQCHIP_IPI_MSI); if (imsic_guest_bits) { qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,guest-index-bits", imsic_guest_bits); @@ -681,12 +692,34 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, VIRT_IRQCHIP_NUM_SOURCES); riscv_socket_fdt_write_id(mc, mc->fdt, aplic_name, socket); qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_s_phandle); + + if (!socket) { + platform_bus_add_all_fdt_nodes(mc->fdt, aplic_name, + memmap[VIRT_PLATFORM_BUS].base, + memmap[VIRT_PLATFORM_BUS].size, + VIRT_PLATFORM_BUS_IRQ); + } + g_free(aplic_name); g_free(aplic_cells); 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, @@ -867,7 +900,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); @@ -875,7 +908,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); @@ -890,7 +923,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", @@ -948,12 +981,30 @@ static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) g_free(name); } +static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) +{ + char *nodename; + MachineState *mc = MACHINE(s); + hwaddr base = memmap[VIRT_FW_CFG].base; + hwaddr size = memmap[VIRT_FW_CFG].size; + + nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); + qemu_fdt_add_subnode(mc->fdt, nodename); + qemu_fdt_setprop_string(mc->fdt, nodename, + "compatible", "qemu,fw-cfg-mmio"); + qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg", + 2, base, 2, size); + qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0); + g_free(nodename); +} + static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { 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); @@ -996,11 +1047,17 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_rtc(s, memmap, irq_mmio_phandle); create_fdt_flash(s, memmap); + create_fdt_fw_cfg(s, memmap); + create_fdt_pmu(s); update_bootargs: - if (cmdline) { + 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, @@ -1055,22 +1112,12 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, static FWCfgState *create_fw_cfg(const MachineState *mc) { hwaddr base = virt_memmap[VIRT_FW_CFG].base; - hwaddr size = virt_memmap[VIRT_FW_CFG].size; FWCfgState *fw_cfg; - char *nodename; fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)mc->smp.cpus); - nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - qemu_fdt_add_subnode(mc->fdt, nodename); - qemu_fdt_setprop_string(mc->fdt, nodename, - "compatible", "qemu,fw-cfg-mmio"); - qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg", - 2, base, 2, size); - qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0); - g_free(nodename); return fw_cfg; } @@ -1156,6 +1203,142 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests, return aplic_m; } +static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) +{ + DeviceState *dev; + SysBusDevice *sysbus; + const MemMapEntry *memmap = virt_memmap; + int i; + 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", memmap[VIRT_PLATFORM_BUS].size); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + s->platform_bus_dev = dev; + + sysbus = SYS_BUS_DEVICE(dev); + for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) { + int irq = VIRT_PLATFORM_BUS_IRQ + i; + sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq)); + } + + memory_region_add_subregion(sysmem, + memmap[VIRT_PLATFORM_BUS].base, + sysbus_mmio_get_region(sysbus, 0)); +} + +static void virt_machine_done(Notifier *notifier, void *data) +{ + RISCVVirtState *s = container_of(notifier, RISCVVirtState, + machine_done); + const MemMapEntry *memmap = virt_memmap; + MachineState *machine = MACHINE(s); + target_ulong start_addr = memmap[VIRT_DRAM].base; + target_ulong firmware_end_addr, kernel_start_addr; + uint32_t fdt_load_addr; + uint64_t kernel_entry; + + /* + * Only direct boot kernel is currently supported for KVM VM, + * so the "-bios" parameter is not supported when KVM is enabled. + */ + if (kvm_enabled()) { + if (machine->firmware) { + if (strcmp(machine->firmware, "none")) { + error_report("Machine mode firmware is not supported in " + "combination with KVM."); + exit(1); + } + } else { + machine->firmware = g_strdup("none"); + } + } + + if (riscv_is_32bit(&s->soc[0])) { + firmware_end_addr = riscv_find_and_load_firmware(machine, + RISCV32_BIOS_BIN, start_addr, NULL); + } else { + firmware_end_addr = riscv_find_and_load_firmware(machine, + RISCV64_BIOS_BIN, start_addr, NULL); + } + + /* + * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device + * tree cannot be altered and we get FDT_ERR_NOSPACE. + */ + s->fw_cfg = create_fw_cfg(machine); + rom_set_fw(s->fw_cfg); + + if (drive_get(IF_PFLASH, 0, 1)) { + /* + * S-mode FW like EDK2 will be kept in second plash (unit 1). + * When both kernel, initrd and pflash options are provided in the + * command line, the kernel and initrd will be copied to the fw_cfg + * table and opensbi will jump to the flash address which is the + * entry point of S-mode FW. It is the job of the S-mode FW to load + * the kernel and initrd using fw_cfg table. + * + * If only pflash is given but not -kernel, then it is the job of + * of the S-mode firmware to locate and load the kernel. + * In either case, the next_addr for opensbi will be the flash address. + */ + riscv_setup_firmware_boot(machine); + kernel_entry = virt_memmap[VIRT_FLASH].base + + virt_memmap[VIRT_FLASH].size / 2; + } else if (machine->kernel_filename) { + kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], + firmware_end_addr); + + kernel_entry = riscv_load_kernel(machine->kernel_filename, + kernel_start_addr, NULL); + + if (machine->initrd_filename) { + hwaddr start; + hwaddr end = riscv_load_initrd(machine->initrd_filename, + machine->ram_size, kernel_entry, + &start); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", + "linux,initrd-start", start); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", + end); + } + } else { + /* + * If dynamic firmware is used, it doesn't know where is the next mode + * if kernel argument is not set. + */ + kernel_entry = 0; + } + + if (drive_get(IF_PFLASH, 0, 0)) { + /* + * Pflash was supplied, let's overwrite the address we jump to after + * reset to the base of the flash. + */ + start_addr = virt_memmap[VIRT_FLASH].base; + } + + /* Compute the fdt load address in dram */ + fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base, + machine->ram_size, machine->fdt); + /* load the reset vector */ + 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); + + /* + * Only direct boot kernel is currently supported for KVM VM, + * So here setup kernel start address and fdt address. + * TODO:Support firmware loading and integrate to TCG start + */ + if (kvm_enabled()) { + riscv_setup_direct_kernel(kernel_entry, fdt_load_addr); + } +} + static void virt_machine_init(MachineState *machine) { const MemMapEntry *memmap = virt_memmap; @@ -1163,10 +1346,6 @@ static void virt_machine_init(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); char *soc_name; - target_ulong start_addr = memmap[VIRT_DRAM].base; - target_ulong firmware_end_addr, kernel_start_addr; - uint32_t fdt_load_addr; - uint64_t kernel_entry; DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip; int i, base_hartid, hart_count; @@ -1207,7 +1386,7 @@ static void virt_machine_init(MachineState *machine) base_hartid, &error_abort); object_property_set_int(OBJECT(&s->soc[i]), "num-harts", hart_count, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal); if (!kvm_enabled()) { if (s->have_aclint) { @@ -1296,92 +1475,12 @@ static void virt_machine_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base, machine->ram); - /* create device tree */ - create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, - riscv_is_32bit(&s->soc[0])); - /* boot rom */ memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom", memmap[VIRT_MROM].size, &error_fatal); memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, mask_rom); - /* - * Only direct boot kernel is currently supported for KVM VM, - * so the "-bios" parameter is ignored and treated like "-bios none" - * when KVM is enabled. - */ - if (kvm_enabled()) { - g_free(machine->firmware); - machine->firmware = g_strdup("none"); - } - - if (riscv_is_32bit(&s->soc[0])) { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV32_BIOS_BIN, start_addr, NULL); - } else { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV64_BIOS_BIN, start_addr, NULL); - } - - if (machine->kernel_filename) { - kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], - firmware_end_addr); - - kernel_entry = riscv_load_kernel(machine->kernel_filename, - kernel_start_addr, NULL); - - if (machine->initrd_filename) { - hwaddr start; - hwaddr end = riscv_load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", - end); - } - } else { - /* - * If dynamic firmware is used, it doesn't know where is the next mode - * if kernel argument is not set. - */ - kernel_entry = 0; - } - - if (drive_get(IF_PFLASH, 0, 0)) { - /* - * Pflash was supplied, let's overwrite the address we jump to after - * reset to the base of the flash. - */ - start_addr = virt_memmap[VIRT_FLASH].base; - } - - /* - * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device - * tree cannot be altered and we get FDT_ERR_NOSPACE. - */ - s->fw_cfg = create_fw_cfg(machine); - rom_set_fw(s->fw_cfg); - - /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base, - machine->ram_size, machine->fdt); - /* load the reset vector */ - 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); - - /* - * Only direct boot kernel is currently supported for KVM VM, - * So here setup kernel start address and fdt address. - * TODO:Support firmware loading and integrate to TCG start - */ - if (kvm_enabled()) { - riscv_setup_direct_kernel(kernel_entry, fdt_load_addr); - } - /* SiFive Test MMIO device */ sifive_test_create(memmap[VIRT_TEST].base); @@ -1402,6 +1501,8 @@ static void virt_machine_init(MachineState *machine) memmap[VIRT_PCIE_PIO].base, DEVICE(pcie_irqchip)); + create_platform_bus(s, DEVICE(mmio_irqchip)); + serial_mm_init(system_memory, memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(DEVICE(mmio_irqchip), UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); @@ -1417,6 +1518,13 @@ static void virt_machine_init(MachineState *machine) drive_get(IF_PFLASH, 0, i)); } virt_flash_map(s, system_memory); + + /* create device tree */ + create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, + riscv_is_32bit(&s->soc[0])); + + s->machine_done.notify = virt_machine_done; + qemu_add_machine_init_done_notifier(&s->machine_done); } static void virt_machine_instance_init(Object *obj) @@ -1497,10 +1605,37 @@ static void virt_set_aclint(Object *obj, bool value, Error **errp) s->have_aclint = value; } +static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + DeviceState *dev) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev)) { + return HOTPLUG_HANDLER(machine); + } + return NULL; +} + +static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + RISCVVirtState *s = RISCV_VIRT_MACHINE(hotplug_dev); + + if (s->platform_bus_dev) { + MachineClass *mc = MACHINE_GET_CLASS(s); + + if (device_is_dynamic_sysbus(mc, dev)) { + platform_bus_link_device(PLATFORM_BUS_DEVICE(s->platform_bus_dev), + SYS_BUS_DEVICE(dev)); + } + } +} + static void virt_machine_class_init(ObjectClass *oc, void *data) { char str[128]; MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); mc->desc = "RISC-V VirtIO board"; mc->init = virt_machine_init; @@ -1512,8 +1647,15 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; mc->default_ram_id = "riscv_virt_board.ram"; + assert(!mc->get_hotplug_handler); + mc->get_hotplug_handler = virt_machine_get_hotplug_handler; + + hc->plug = virt_machine_device_plug_cb; machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); +#ifdef CONFIG_TPM + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); +#endif object_class_property_add_bool(oc, "aclint", virt_get_aclint, virt_set_aclint); @@ -1542,6 +1684,10 @@ static const TypeInfo virt_machine_typeinfo = { .class_init = virt_machine_class_init, .instance_init = virt_machine_instance_init, .instance_size = sizeof(RISCVVirtState), + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, }; static void virt_machine_init_register_types(void) diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig index 730c272bc543..d0d8dda0840c 100644 --- a/hw/rtc/Kconfig +++ b/hw/rtc/Kconfig @@ -27,3 +27,6 @@ config SUN4V_RTC config GOLDFISH_RTC bool + +config LS7A_RTC + bool diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c index ae67641de668..d1620c7a2ace 100644 --- a/hw/rtc/exynos4210_rtc.c +++ b/hw/rtc/exynos4210_rtc.c @@ -564,14 +564,14 @@ static void exynos4210_rtc_init(Object *obj) Exynos4210RTCState *s = EXYNOS4210_RTC(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); - s->ptimer = ptimer_init(exynos4210_rtc_tick, s, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(exynos4210_rtc_tick, s, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->ptimer); ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); ptimer_transaction_commit(s->ptimer); s->ptimer_1Hz = ptimer_init(exynos4210_rtc_1Hz_tick, - s, PTIMER_POLICY_DEFAULT); + s, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->ptimer_1Hz); ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); ptimer_transaction_commit(s->ptimer_1Hz); diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be3127..19a56402a0c6 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/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c new file mode 100644 index 000000000000..1f9e38a735bd --- /dev/null +++ b/hw/rtc/ls7a_rtc.c @@ -0,0 +1,488 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Loongarch LS7A Real Time Clock emulation + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "include/hw/register.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "hw/misc/unimp.h" +#include "sysemu/rtc.h" +#include "hw/registerfields.h" + +#define SYS_TOYTRIM 0x20 +#define SYS_TOYWRITE0 0x24 +#define SYS_TOYWRITE1 0x28 +#define SYS_TOYREAD0 0x2C +#define SYS_TOYREAD1 0x30 +#define SYS_TOYMATCH0 0x34 +#define SYS_TOYMATCH1 0x38 +#define SYS_TOYMATCH2 0x3C +#define SYS_RTCCTRL 0x40 +#define SYS_RTCTRIM 0x60 +#define SYS_RTCWRTIE0 0x64 +#define SYS_RTCREAD0 0x68 +#define SYS_RTCMATCH0 0x6C +#define SYS_RTCMATCH1 0x70 +#define SYS_RTCMATCH2 0x74 + +#define LS7A_RTC_FREQ 32768 +#define TIMER_NUMS 3 +/* + * Shift bits and filed mask + */ + +FIELD(TOY, MON, 26, 6) +FIELD(TOY, DAY, 21, 5) +FIELD(TOY, HOUR, 16, 5) +FIELD(TOY, MIN, 10, 6) +FIELD(TOY, SEC, 4, 6) +FIELD(TOY, MSEC, 0, 4) + +FIELD(TOY_MATCH, YEAR, 26, 6) +FIELD(TOY_MATCH, MON, 22, 4) +FIELD(TOY_MATCH, DAY, 17, 5) +FIELD(TOY_MATCH, HOUR, 12, 5) +FIELD(TOY_MATCH, MIN, 6, 6) +FIELD(TOY_MATCH, SEC, 0, 6) + +FIELD(RTC_CTRL, RTCEN, 13, 1) +FIELD(RTC_CTRL, TOYEN, 11, 1) +FIELD(RTC_CTRL, EO, 8, 1) + +#define TYPE_LS7A_RTC "ls7a_rtc" +OBJECT_DECLARE_SIMPLE_TYPE(LS7ARtcState, LS7A_RTC) + +struct LS7ARtcState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + /* + * Needed to preserve the tick_count across migration, even if the + * absolute value of the rtc_clock is different on the source and + * destination. + */ + int64_t offset_toy; + int64_t offset_rtc; + int64_t data; + int tidx; + uint32_t toymatch[3]; + uint32_t toytrim; + uint32_t cntrctl; + uint32_t rtctrim; + uint32_t rtccount; + uint32_t rtcmatch[3]; + QEMUTimer *toy_timer[TIMER_NUMS]; + QEMUTimer *rtc_timer[TIMER_NUMS]; + qemu_irq irq; +}; + +/* switch nanoseconds time to rtc ticks */ +static uint64_t ls7a_rtc_ticks(void) +{ + return qemu_clock_get_ns(rtc_clock) * LS7A_RTC_FREQ / NANOSECONDS_PER_SECOND; +} + +/* switch rtc ticks to nanoseconds */ +static uint64_t ticks_to_ns(uint64_t ticks) +{ + return ticks * NANOSECONDS_PER_SECOND / LS7A_RTC_FREQ; +} + +static bool toy_enabled(LS7ARtcState *s) +{ + return FIELD_EX32(s->cntrctl, RTC_CTRL, TOYEN) && + FIELD_EX32(s->cntrctl, RTC_CTRL, EO); +} + +static bool rtc_enabled(LS7ARtcState *s) +{ + return FIELD_EX32(s->cntrctl, RTC_CTRL, RTCEN) && + FIELD_EX32(s->cntrctl, RTC_CTRL, EO); +} + +/* parse struct tm to toy value */ +static uint64_t toy_time_to_val_mon(const struct tm *tm) +{ + uint64_t val = 0; + + val = FIELD_DP32(val, TOY, MON, tm->tm_mon + 1); + val = FIELD_DP32(val, TOY, DAY, tm->tm_mday); + val = FIELD_DP32(val, TOY, HOUR, tm->tm_hour); + val = FIELD_DP32(val, TOY, MIN, tm->tm_min); + val = FIELD_DP32(val, TOY, SEC, tm->tm_sec); + return val; +} + +static void toymatch_val_to_time(LS7ARtcState *s, uint64_t val, struct tm *tm) +{ + qemu_get_timedate(tm, s->offset_toy); + tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC); + tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN); + tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR); + tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY); + tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1; + tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f)); +} + +static void toymatch_write(LS7ARtcState *s, uint64_t val, int num) +{ + int64_t now, expire_time; + struct tm tm = {}; + + /* it do not support write when toy disabled */ + if (toy_enabled(s)) { + s->toymatch[num] = val; + /* calculate expire time */ + now = qemu_clock_get_ms(rtc_clock); + toymatch_val_to_time(s, val, &tm); + expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; + timer_mod(s->toy_timer[num], expire_time); + } +} + +static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) +{ + uint64_t expire_ns; + + /* it do not support write when toy disabled */ + if (rtc_enabled(s)) { + s->rtcmatch[num] = val; + /* calculate expire time */ + expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc); + timer_mod_ns(s->rtc_timer[num], expire_ns); + } +} + +static void ls7a_toy_stop(LS7ARtcState *s) +{ + int i; + + /* delete timers, and when re-enabled, recalculate expire time */ + for (i = 0; i < TIMER_NUMS; i++) { + timer_del(s->toy_timer[i]); + } +} + +static void ls7a_rtc_stop(LS7ARtcState *s) +{ + int i; + + /* delete timers, and when re-enabled, recalculate expire time */ + for (i = 0; i < TIMER_NUMS; i++) { + timer_del(s->rtc_timer[i]); + } +} + +static void ls7a_toy_start(LS7ARtcState *s) +{ + int i; + uint64_t expire_time, now; + struct tm tm = {}; + + now = qemu_clock_get_ms(rtc_clock); + + /* recalculate expire time and enable timer */ + for (i = 0; i < TIMER_NUMS; i++) { + toymatch_val_to_time(s, s->toymatch[i], &tm); + expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; + timer_mod(s->toy_timer[i], expire_time); + } +} + +static void ls7a_rtc_start(LS7ARtcState *s) +{ + int i; + uint64_t expire_time; + + /* recalculate expire time and enable timer */ + for (i = 0; i < TIMER_NUMS; i++) { + expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc); + timer_mod_ns(s->rtc_timer[i], expire_time); + } +} + +static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) +{ + LS7ARtcState *s = LS7A_RTC(opaque); + struct tm tm; + int val = 0; + + switch (addr) { + case SYS_TOYREAD0: + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + val = toy_time_to_val_mon(&tm); + } else { + /* return 0 when toy disabled */ + val = 0; + } + break; + case SYS_TOYREAD1: + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + val = tm.tm_year; + } else { + /* return 0 when toy disabled */ + val = 0; + } + break; + case SYS_TOYMATCH0: + val = s->toymatch[0]; + break; + case SYS_TOYMATCH1: + val = s->toymatch[1]; + break; + case SYS_TOYMATCH2: + val = s->toymatch[2]; + break; + case SYS_RTCCTRL: + val = s->cntrctl; + break; + case SYS_RTCREAD0: + if (rtc_enabled(s)) { + val = ls7a_rtc_ticks() + s->offset_rtc; + } else { + /* return 0 when rtc disabled */ + val = 0; + } + break; + case SYS_RTCMATCH0: + val = s->rtcmatch[0]; + break; + case SYS_RTCMATCH1: + val = s->rtcmatch[1]; + break; + case SYS_RTCMATCH2: + val = s->rtcmatch[2]; + break; + default: + val = 0; + break; + } + return val; +} + +static void ls7a_rtc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + int old_toyen, old_rtcen, new_toyen, new_rtcen; + LS7ARtcState *s = LS7A_RTC(opaque); + struct tm tm; + + switch (addr) { + case SYS_TOYWRITE0: + /* it do not support write when toy disabled */ + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + tm.tm_sec = FIELD_EX32(val, TOY, SEC); + tm.tm_min = FIELD_EX32(val, TOY, MIN); + tm.tm_hour = FIELD_EX32(val, TOY, HOUR); + tm.tm_mday = FIELD_EX32(val, TOY, DAY); + tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1; + s->offset_toy = qemu_timedate_diff(&tm); + } + break; + case SYS_TOYWRITE1: + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + tm.tm_year = val; + s->offset_toy = qemu_timedate_diff(&tm); + } + break; + case SYS_TOYMATCH0: + toymatch_write(s, val, 0); + break; + case SYS_TOYMATCH1: + toymatch_write(s, val, 1); + break; + case SYS_TOYMATCH2: + toymatch_write(s, val, 2); + break; + case SYS_RTCCTRL: + /* get old ctrl */ + old_toyen = toy_enabled(s); + old_rtcen = rtc_enabled(s); + + s->cntrctl = val; + /* get new ctrl */ + new_toyen = toy_enabled(s); + new_rtcen = rtc_enabled(s); + + /* + * we do not consider if EO changed, as it always set at most time. + * toy or rtc enabled should start timer. otherwise, stop timer + */ + if (old_toyen != new_toyen) { + if (new_toyen) { + ls7a_toy_start(s); + } else { + ls7a_toy_stop(s); + } + } + if (old_rtcen != new_rtcen) { + if (new_rtcen) { + ls7a_rtc_start(s); + } else { + ls7a_rtc_stop(s); + } + } + break; + case SYS_RTCWRTIE0: + if (rtc_enabled(s)) { + s->offset_rtc = val - ls7a_rtc_ticks(); + } + break; + case SYS_RTCMATCH0: + rtcmatch_write(s, val, 0); + break; + case SYS_RTCMATCH1: + rtcmatch_write(s, val, 1); + break; + case SYS_RTCMATCH2: + rtcmatch_write(s, val, 2); + break; + default: + break; + } +} + +static const MemoryRegionOps ls7a_rtc_ops = { + .read = ls7a_rtc_read, + .write = ls7a_rtc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void toy_timer_cb(void *opaque) +{ + LS7ARtcState *s = opaque; + + if (toy_enabled(s)) { + qemu_irq_raise(s->irq); + } +} + +static void rtc_timer_cb(void *opaque) +{ + LS7ARtcState *s = opaque; + + if (rtc_enabled(s)) { + qemu_irq_raise(s->irq); + } +} + +static void ls7a_rtc_realize(DeviceState *dev, Error **errp) +{ + int i; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + LS7ARtcState *d = LS7A_RTC(sbd); + memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, + (void *)d, "ls7a_rtc", 0x100); + + sysbus_init_irq(sbd, &d->irq); + + sysbus_init_mmio(sbd, &d->iomem); + for (i = 0; i < TIMER_NUMS; i++) { + d->toymatch[i] = 0; + d->rtcmatch[i] = 0; + d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d); + d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d); + } + d->offset_toy = 0; + d->offset_rtc = 0; + +} + +/* delete timer and clear reg when reset */ +static void ls7a_rtc_reset(DeviceState *dev) +{ + int i; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + LS7ARtcState *d = LS7A_RTC(sbd); + for (i = 0; i < TIMER_NUMS; i++) { + if (toy_enabled(d)) { + timer_del(d->toy_timer[i]); + } + if (rtc_enabled(d)) { + timer_del(d->rtc_timer[i]); + } + d->toymatch[i] = 0; + d->rtcmatch[i] = 0; + } + d->cntrctl = 0; +} + +static int ls7a_rtc_pre_save(void *opaque) +{ + LS7ARtcState *s = LS7A_RTC(opaque); + + ls7a_toy_stop(s); + ls7a_rtc_stop(s); + + return 0; +} + +static int ls7a_rtc_post_load(void *opaque, int version_id) +{ + LS7ARtcState *s = LS7A_RTC(opaque); + if (toy_enabled(s)) { + ls7a_toy_start(s); + } + + if (rtc_enabled(s)) { + ls7a_rtc_start(s); + } + + return 0; +} + +static const VMStateDescription vmstate_ls7a_rtc = { + .name = "ls7a_rtc", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = ls7a_rtc_pre_save, + .post_load = ls7a_rtc_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT64(offset_toy, LS7ARtcState), + VMSTATE_INT64(offset_rtc, LS7ARtcState), + VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS), + VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS), + VMSTATE_UINT32(cntrctl, LS7ARtcState), + VMSTATE_END_OF_LIST() + } +}; + +static void ls7a_rtc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->vmsd = &vmstate_ls7a_rtc; + dc->realize = ls7a_rtc_realize; + dc->reset = ls7a_rtc_reset; + dc->desc = "ls7a rtc"; +} + +static const TypeInfo ls7a_rtc_info = { + .name = TYPE_LS7A_RTC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LS7ARtcState), + .class_init = ls7a_rtc_class_init, +}; + +static void ls7a_rtc_register_types(void) +{ + type_register_static(&ls7a_rtc_info); +} + +type_init(ls7a_rtc_register_types) diff --git a/hw/rtc/m41t80.c b/hw/rtc/m41t80.c index a00971a67e1c..e045c864bb44 100644 --- a/hw/rtc/m41t80.c +++ b/hw/rtc/m41t80.c @@ -47,7 +47,7 @@ static uint8_t m41t80_recv(I2CSlave *i2c) { M41t80State *s = M41T80(i2c); struct tm now; - qemu_timeval tv; + int64_t rt; if (s->addr < 0) { s->addr = 0; @@ -57,8 +57,8 @@ static uint8_t m41t80_recv(I2CSlave *i2c) } switch (s->addr++) { case 0: - qemu_gettimeofday(&tv); - return to_bcd(tv.tv_usec / 10000); + rt = g_get_real_time(); + return to_bcd((rt % G_USEC_PER_SEC) / 10000); case 1: return to_bcd(now.tm_sec); case 2: diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index f235c2ddbe7b..1ebb412479d9 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -26,7 +26,7 @@ #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/bcd.h" -#include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" @@ -74,6 +74,8 @@ #define RTC_CLOCK_RATE 32768 #define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768) +#define RTC_ISA_BASE 0x70 + static void rtc_set_time(RTCState *s); static void rtc_update_time(RTCState *s); static void rtc_set_cmos(RTCState *s, const struct tm *tm); @@ -941,7 +943,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) qemu_register_suspend_notifier(&s->suspend_notifier); memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2); - isa_register_ioport(isadev, &s->io, RTC_ISA_BASE); + isa_register_ioport(isadev, &s->io, s->io_base); /* register rtc 0x70 port for coalesced_pio */ memory_region_set_flush_coalesced(&s->io); @@ -950,7 +952,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->io, 0, &s->coalesced_io); memory_region_add_coalescing(&s->coalesced_io, 0, 1); - qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3); + qdev_set_legacy_instance_id(dev, s->io_base, 3); object_property_add_tm(OBJECT(s), "date", rtc_get_date); @@ -983,6 +985,7 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) static Property mc146818rtc_properties[] = { DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), + DEFINE_PROP_UINT16("iobase", RTCState, io_base, RTC_ISA_BASE), DEFINE_PROP_UINT8("irq", RTCState, isairq, RTC_ISA_IRQ), DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState, lost_tick_policy, LOST_TICK_POLICY_DISCARD), @@ -1017,9 +1020,9 @@ static void rtc_reset_hold(Object *obj) qemu_irq_lower(s->irq); } -static void rtc_build_aml(ISADevice *isadev, Aml *scope) +static void rtc_build_aml(AcpiDevAmlIf *adev, Aml *scope) { - RTCState *s = MC146818_RTC(isadev); + RTCState *s = MC146818_RTC(adev); Aml *dev; Aml *crs; @@ -1028,7 +1031,7 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope) * does, even though qemu only responds to the first two ports. */ crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE, RTC_ISA_BASE, + aml_append(crs, aml_io(AML_DECODE16, s->io_base, s->io_base, 0x01, 0x08)); aml_append(crs, aml_irq_no_flags(s->isairq)); @@ -1043,13 +1046,13 @@ static void rtc_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); - ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); dc->realize = rtc_realizefn; dc->vmsd = &vmstate_rtc; rc->phases.enter = rtc_reset_enter; rc->phases.hold = rtc_reset_hold; - isa->build_aml = rtc_build_aml; + adevc->build_dev_aml = rtc_build_aml; device_class_set_props(dc, mc146818rtc_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); } @@ -1059,6 +1062,10 @@ static const TypeInfo mc146818rtc_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(RTCState), .class_init = rtc_class_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void mc146818rtc_register_types(void) diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build index 7cecdee5ddb0..dc3397338403 100644 --- a/hw/rtc/meson.build +++ b/hw/rtc/meson.build @@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_rtc.c')) softmmu_ss.add(when: 'CONFIG_SUN4V_RTC', if_true: files('sun4v-rtc.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c')) softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c')) +softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c')) specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c')) diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 75d1fec6ca46..47c17026c738 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -19,12 +19,13 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" -#include "qemu-common.h" #include "hw/loader.h" #include "hw/rx/rx62n.h" #include "sysemu/qtest.h" #include "sysemu/device_tree.h" +#include "sysemu/reset.h" #include "hw/boards.h" #include "qom/object.h" @@ -84,6 +85,7 @@ static void rx_gdbsim_init(MachineState *machine) MemoryRegion *sysmem = get_system_memory(); const char *kernel_filename = machine->kernel_filename; const char *dtb_filename = machine->dtb; + uint8_t rng_seed[32]; if (machine->ram_size < mc->default_ram_size) { char *sz = size_to_str(mc->default_ram_size); @@ -141,10 +143,14 @@ static void rx_gdbsim_init(MachineState *machine) error_report("Couldn't set /chosen/bootargs"); exit(1); } + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(dtb, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); /* DTB is located at the end of SDRAM space. */ - dtb_offset = machine->ram_size - dtb_size; + dtb_offset = ROUND_DOWN(machine->ram_size - dtb_size, 16); rom_add_blob_fixed("dtb", dtb, dtb_size, SDRAM_BASE + dtb_offset); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, + rom_ptr(SDRAM_BASE + dtb_offset, dtb_size)); /* Set dtb address to R1 */ RX_CPU(first_cpu)->env.regs[1] = SDRAM_BASE + dtb_offset; } diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 7d9523f81138..95d1b3a3cee3 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1522,21 +1522,37 @@ IOInstEnding css_do_xsch(SubchDev *sch) IOInstEnding css_do_csch(SubchDev *sch) { SCHIB *schib = &sch->curr_status; + uint16_t old_scsw_ctrl; + IOInstEnding ccode; if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { return IOINST_CC_NOT_OPERATIONAL; } + /* + * Save the current scsw.ctrl in case CSCH fails and we need + * to revert the scsw to the status quo ante. + */ + old_scsw_ctrl = schib->scsw.ctrl; + /* Trigger the clear function. */ schib->scsw.ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); schib->scsw.ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND; - return do_subchannel_work(sch); + ccode = do_subchannel_work(sch); + + if (ccode != IOINST_CC_EXPECTED) { + schib->scsw.ctrl = old_scsw_ctrl; + } + + return ccode; } IOInstEnding css_do_hsch(SubchDev *sch) { SCHIB *schib = &sch->curr_status; + uint16_t old_scsw_ctrl; + IOInstEnding ccode; if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { return IOINST_CC_NOT_OPERATIONAL; @@ -1553,6 +1569,12 @@ IOInstEnding css_do_hsch(SubchDev *sch) return IOINST_CC_BUSY; } + /* + * Save the current scsw.ctrl in case HSCH fails and we need + * to revert the scsw to the status quo ante. + */ + old_scsw_ctrl = schib->scsw.ctrl; + /* Trigger the halt function. */ schib->scsw.ctrl |= SCSW_FCTL_HALT_FUNC; schib->scsw.ctrl &= ~SCSW_FCTL_START_FUNC; @@ -1564,7 +1586,13 @@ IOInstEnding css_do_hsch(SubchDev *sch) } schib->scsw.ctrl |= SCSW_ACTL_HALT_PEND; - return do_subchannel_work(sch); + ccode = do_subchannel_work(sch); + + if (ccode != IOINST_CC_EXPECTED) { + schib->scsw.ctrl = old_scsw_ctrl; + } + + return ccode; } static void css_update_chnmon(SubchDev *sch) @@ -1605,6 +1633,8 @@ static void css_update_chnmon(SubchDev *sch) IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb) { SCHIB *schib = &sch->curr_status; + uint16_t old_scsw_ctrl, old_scsw_flags; + IOInstEnding ccode; if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { return IOINST_CC_NOT_OPERATIONAL; @@ -1626,11 +1656,26 @@ IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb) } sch->orb = *orb; sch->channel_prog = orb->cpa; + + /* + * Save the current scsw.ctrl and scsw.flags in case SSCH fails and we need + * to revert the scsw to the status quo ante. + */ + old_scsw_ctrl = schib->scsw.ctrl; + old_scsw_flags = schib->scsw.flags; + /* Trigger the start function. */ schib->scsw.ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); schib->scsw.flags &= ~SCSW_FLAGS_MASK_PNO; - return do_subchannel_work(sch); + ccode = do_subchannel_work(sch); + + if (ccode != IOINST_CC_EXPECTED) { + schib->scsw.ctrl = old_scsw_ctrl; + schib->scsw.flags = old_scsw_flags; + } + + return ccode; } static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw, diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 6fa47b889ca4..faa51aa4c70d 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -28,7 +28,7 @@ typedef struct SCLPEventsBus { } SCLPEventsBus; /* we need to save 32 bit chunks for compatibility */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define RECV_MASK_LOWER 1 #define RECV_MASK_UPPER 0 #else /* little endian host */ diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index eb7fc4c4ae87..8612684d48e1 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -13,7 +13,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "sysemu/reset.h" @@ -28,11 +27,14 @@ #include "hw/s390x/css.h" #include "hw/s390x/ebcdic.h" #include "hw/s390x/pv.h" +#include "hw/scsi/scsi.h" +#include "hw/virtio/virtio-net.h" #include "ipl.h" #include "qemu/error-report.h" #include "qemu/config-file.h" #include "qemu/cutils.h" #include "qemu/option.h" +#include "standard-headers/linux/virtio_ids.h" #include "exec/exec-all.h" #define KERN_IMAGE_START 0x010000UL @@ -288,13 +290,10 @@ static Property s390_ipl_properties[] = { static void s390_ipl_set_boot_menu(S390IPLState *ipl) { - QemuOptsList *plist = qemu_find_opts("boot-opts"); - QemuOpts *opts = QTAILQ_FIRST(&plist->head); - const char *tmp; unsigned long splash_time = 0; if (!get_boot_device(0)) { - if (boot_menu) { + if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) { error_report("boot menu requires a bootindex to be specified for " "the IPL device"); } @@ -304,7 +303,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl) switch (ipl->iplb.pbt) { case S390_IPL_TYPE_CCW: /* In the absence of -boot menu, use zipl parameters */ - if (!qemu_opt_get(opts, "menu")) { + if (!current_machine->boot_config.has_menu) { ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_ZIPL; return; } @@ -312,26 +311,21 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl) case S390_IPL_TYPE_QEMU_SCSI: break; default: - if (boot_menu) { + if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) { error_report("boot menu is not supported for this device type"); } return; } - if (!boot_menu) { + if (!current_machine->boot_config.has_menu || !current_machine->boot_config.menu) { return; } ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_CMD; - tmp = qemu_opt_get(opts, "splash-time"); - - if (tmp && qemu_strtoul(tmp, NULL, 10, &splash_time)) { - error_report("splash-time is invalid, forcing it to 0"); - ipl->qipl.boot_menu_timeout = 0; - return; + if (current_machine->boot_config.has_splash_time) { + splash_time = current_machine->boot_config.splash_time; } - if (splash_time > 0xffffffff) { error_report("splash-time is too large, forcing it to max value"); ipl->qipl.boot_menu_timeout = 0xffffffff; @@ -376,14 +370,18 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype) object_dynamic_cast(OBJECT(dev_st), TYPE_SCSI_DEVICE); if (sd) { - SCSIBus *bus = scsi_bus_from_device(sd); - VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus); - VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, - vdev); - - ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw), - TYPE_CCW_DEVICE); - tmp_dt = CCW_DEVTYPE_SCSI; + SCSIBus *sbus = scsi_bus_from_device(sd); + VirtIODevice *vdev = (VirtIODevice *) + object_dynamic_cast(OBJECT(sbus->qbus.parent), + TYPE_VIRTIO_DEVICE); + if (vdev) { + ccw_dev = (CcwDevice *) + object_dynamic_cast(OBJECT(qdev_get_parent_bus(DEVICE(vdev))->parent), + TYPE_CCW_DEVICE); + if (ccw_dev) { + tmp_dt = CCW_DEVTYPE_SCSI; + } + } } } } diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index dfc6dfd89c88..7fc86e790547 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -140,7 +140,7 @@ void s390_ipl_clear_reset_request(void); * have an offset of 4 + n * 8 bytes within the struct in order * to keep it double-word aligned. * The total size of the struct must never exceed 28 bytes. - * This definition must be kept in sync with the defininition + * This definition must be kept in sync with the definition * in pc-bios/s390-ccw/iplb.h. */ struct QemuIplParameters { diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build index 28484256ec0b..f291016feeb4 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', @@ -44,6 +45,7 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-ccw-serial.c' if have_virtfs virtio_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-ccw-9p.c')) endif +virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c')) virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c')) s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss) diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index 401b63d6cb65..8dfe92d8dfdd 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -20,6 +20,11 @@ #include "exec/confidential-guest-support.h" #include "hw/s390x/ipl.h" #include "hw/s390x/pv.h" +#include "target/s390x/kvm/kvm_s390x.h" + +static bool info_valid; +static struct kvm_s390_pv_info_vm info_vm; +static struct kvm_s390_pv_info_dump info_dump; static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) { @@ -45,7 +50,7 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) * This macro lets us pass the command as a string to the function so * we can print it on an error. */ -#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data); +#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data) #define s390_pv_cmd_exit(cmd, data) \ { \ int rc; \ @@ -56,6 +61,42 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) } \ } +int s390_pv_query_info(void) +{ + struct kvm_s390_pv_info info = { + .header.id = KVM_PV_INFO_VM, + .header.len_max = sizeof(info.header) + sizeof(info.vm), + }; + int rc; + + /* Info API's first user is dump so they are bundled */ + if (!kvm_s390_get_protected_dump()) { + return 0; + } + + rc = s390_pv_cmd(KVM_PV_INFO, &info); + if (rc) { + error_report("KVM PV INFO cmd %x failed: %s", + info.header.id, strerror(-rc)); + return rc; + } + memcpy(&info_vm, &info.vm, sizeof(info.vm)); + + info.header.id = KVM_PV_INFO_DUMP; + info.header.len_max = sizeof(info.header) + sizeof(info.dump); + rc = s390_pv_cmd(KVM_PV_INFO, &info); + if (rc) { + error_report("KVM PV INFO cmd %x failed: %s", + info.header.id, strerror(-rc)); + return rc; + } + + memcpy(&info_dump, &info.dump, sizeof(info.dump)); + info_valid = true; + + return rc; +} + int s390_pv_vm_enable(void) { return s390_pv_cmd(KVM_PV_ENABLE, NULL); @@ -114,6 +155,77 @@ void s390_pv_inject_reset_error(CPUState *cs) env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; } +uint64_t kvm_s390_pv_dmp_get_size_cpu(void) +{ + return info_dump.dump_cpu_buffer_len; +} + +uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) +{ + return info_dump.dump_config_finalize_len; +} + +uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) +{ + return info_dump.dump_config_mem_buffer_per_1m; +} + +bool kvm_s390_pv_info_basic_valid(void) +{ + return info_valid; +} + +static int s390_pv_dump_cmd(uint64_t subcmd, uint64_t uaddr, uint64_t gaddr, + uint64_t len) +{ + struct kvm_s390_pv_dmp dmp = { + .subcmd = subcmd, + .buff_addr = uaddr, + .buff_len = len, + .gaddr = gaddr, + }; + int ret; + + ret = s390_pv_cmd(KVM_PV_DUMP, (void *)&dmp); + if (ret) { + error_report("KVM DUMP command %ld failed", subcmd); + } + return ret; +} + +int kvm_s390_dump_cpu(S390CPU *cpu, void *buff) +{ + struct kvm_s390_pv_dmp dmp = { + .subcmd = KVM_PV_DUMP_CPU, + .buff_addr = (uint64_t)buff, + .gaddr = 0, + .buff_len = info_dump.dump_cpu_buffer_len, + }; + struct kvm_pv_cmd pv = { + .cmd = KVM_PV_DUMP, + .data = (uint64_t)&dmp, + }; + + return kvm_vcpu_ioctl(CPU(cpu), KVM_S390_PV_CPU_COMMAND, &pv); +} + +int kvm_s390_dump_init(void) +{ + return s390_pv_dump_cmd(KVM_PV_DUMP_INIT, 0, 0, 0); +} + +int kvm_s390_dump_mem_state(uint64_t gaddr, size_t len, void *dest) +{ + return s390_pv_dump_cmd(KVM_PV_DUMP_CONFIG_STOR_STATE, (uint64_t)dest, + gaddr, len); +} + +int kvm_s390_dump_completion_data(void *buff) +{ + return s390_pv_dump_cmd(KVM_PV_DUMP_COMPLETE, (uint64_t)buff, 0, + info_dump.dump_config_finalize_len); +} + #define TYPE_S390_PV_GUEST "s390-pv-guest" OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST) diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 2fc8bb9c2327..e2d86d96e728 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 4b2bdd94b382..02751f35971a 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" @@ -23,6 +24,8 @@ #include "hw/pci/msi.h" #include "qemu/error-report.h" #include "qemu/module.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" #ifndef DEBUG_S390PCI_BUS #define DEBUG_S390PCI_BUS 0 @@ -149,10 +152,30 @@ void s390_pci_sclp_configure(SCCB *sccb) psccb->header.response_code = cpu_to_be16(rc); } +static void s390_pci_shutdown_notifier(Notifier *n, void *opaque) +{ + S390PCIBusDevice *pbdev = container_of(n, S390PCIBusDevice, + shutdown_notifier); + + pci_device_reset(pbdev->pdev); +} + +static void s390_pci_reset_cb(void *opaque) +{ + S390PCIBusDevice *pbdev = opaque; + + pci_device_reset(pbdev->pdev); +} + static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev) { HotplugHandler *hotplug_ctrl; + if (pbdev->pft == ZPCI_PFT_ISM) { + notifier_remove(&pbdev->shutdown_notifier); + qemu_unregister_reset(s390_pci_reset_cb, pbdev); + } + /* Unplug the PCI device */ if (pbdev->pdev) { DeviceState *pdev = DEVICE(pbdev->pdev); @@ -189,7 +212,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 +770,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 +795,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 +861,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 +921,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 +1016,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 +1106,47 @@ 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; + } + /* Register shutdown notifier and reset callback for ISM devices */ + if (pbdev->pft == ZPCI_PFT_ISM) { + pbdev->shutdown_notifier.notify = s390_pci_shutdown_notifier; + qemu_register_shutdown_notifier(&pbdev->shutdown_notifier); + qemu_register_reset(s390_pci_reset_cb, pbdev); + } } 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 +1293,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 +1434,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 +1482,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 6d400d41472e..8f84ac6251c4 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -13,11 +13,14 @@ #include "qemu/osdep.h" #include "exec/memop.h" -#include "exec/memory-internal.h" +#include "exec/memory.h" #include "qemu/error-report.h" #include "sysemu/hw_accel.h" +#include "hw/pci/pci_device.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 +249,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); @@ -256,7 +273,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); goto out; } - device_legacy_reset(DEVICE(pbdev)); + device_cold_reset(DEVICE(pbdev)); pbdev->fh &= ~FH_MASK_ENABLE; pbdev->state = ZPCI_FS_DISABLED; stl_p(&ressetpci->fh, pbdev->fh); @@ -624,6 +641,8 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, } g_hash_table_remove(iommu->iotlb, &entry->iova); inc_dma_avail(iommu); + /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */ + goto out; } else { if (cache) { if (cache->perm == entry->perm && @@ -647,22 +666,52 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, dec_dma_avail(iommu); } + /* + * All associated iotlb entries have already been cleared, trigger the + * unmaps. + */ memory_region_notify_iommu(&iommu->iommu_mr, 0, event); out: return iommu->dma_limit ? iommu->dma_limit->avail : 1; } +static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova, + uint64_t len) +{ + uint64_t remain = len, start = iova, end = start + len - 1, mask, size; + IOMMUTLBEvent event = { + .type = IOMMU_NOTIFIER_UNMAP, + .entry = { + .target_as = &address_space_memory, + .translated_addr = 0, + .perm = IOMMU_NONE, + }, + }; + + while (remain >= TARGET_PAGE_SIZE) { + mask = dma_aligned_pow2_mask(start, end, 64); + size = mask + 1; + event.entry.iova = start; + event.entry.addr_mask = mask; + memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + start += size; + remain -= size; + } +} + int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; + uint64_t iova, coalesce = 0; uint32_t fh; uint16_t error = 0; S390PCIBusDevice *pbdev; S390PCIIOMMU *iommu; S390IOTLBEntry entry; - hwaddr start, end; + hwaddr start, end, sstart; uint32_t dma_avail; + bool again; if (env->psw.mask & PSW_MASK_PSTATE) { s390_program_interrupt(env, PGM_PRIVILEGED, ra); @@ -675,7 +724,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } fh = env->regs[r1] >> 32; - start = env->regs[r2]; + sstart = start = env->regs[r2]; end = start + env->regs[r2 + 1]; pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh); @@ -716,20 +765,54 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) goto err; } + retry: + start = sstart; + again = false; while (start < end) { error = s390_guest_io_table_walk(iommu->g_iota, start, &entry); if (error) { break; } + /* + * If this is an unmap of a PTE, let's try to coalesce multiple unmaps + * into as few notifier events as possible. + */ + if (entry.perm == IOMMU_NONE && entry.len == TARGET_PAGE_SIZE) { + if (coalesce == 0) { + iova = entry.iova; + } + coalesce += entry.len; + } else if (coalesce > 0) { + /* Unleash the coalesced unmap before processing a new map */ + s390_pci_batch_unmap(iommu, iova, coalesce); + coalesce = 0; + } + start += entry.len; - while (entry.iova < start && entry.iova < end && - (dma_avail > 0 || entry.perm == IOMMU_NONE)) { - dma_avail = s390_pci_update_iotlb(iommu, &entry); - entry.iova += TARGET_PAGE_SIZE; - entry.translated_addr += TARGET_PAGE_SIZE; + while (entry.iova < start && entry.iova < end) { + if (dma_avail > 0 || entry.perm == IOMMU_NONE) { + dma_avail = s390_pci_update_iotlb(iommu, &entry); + entry.iova += TARGET_PAGE_SIZE; + entry.translated_addr += TARGET_PAGE_SIZE; + } else { + /* + * We are unable to make a new mapping at this time, continue + * on and hopefully free up more space. Then attempt another + * pass. + */ + again = true; + break; + } } } + if (coalesce) { + /* Unleash the coalesced unmap before finishing rpcit */ + s390_pci_batch_unmap(iommu, iova, coalesce); + coalesce = 0; + } + if (again && dma_avail > 0) + goto retry; err: if (error) { pbdev->state = ZPCI_FS_ERROR; @@ -1050,6 +1133,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 +1213,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 +1227,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 000000000000..9134fe185fea --- /dev/null +++ b/hw/s390x/s390-pci-kvm.c @@ -0,0 +1,52 @@ +/* + * 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(); +} + +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 6f80a47e2990..f51190d4662f 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -84,6 +84,7 @@ S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s, cnt->users = 1; cnt->avail = avail; QTAILQ_INSERT_TAIL(&s->zpci_dma_limit, cnt, link); + pbdev->iommu->max_dma_limit = avail; return cnt; } @@ -103,6 +104,7 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev, struct vfio_info_cap_header *hdr; struct vfio_device_info_cap_zpci_base *cap; VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); + uint64_t vfio_size; hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_BASE); @@ -122,6 +124,38 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev, /* The following values remain 0 until we support other FMB formats */ pbdev->zpci_fn.fmbl = 0; pbdev->zpci_fn.pft = 0; + /* Store function type separately for type-specific behavior */ + pbdev->pft = cap->pft; + + /* + * If appropriate, reduce the size of the supported DMA aperture reported + * to the guest based upon the vfio DMA limit. + */ + vfio_size = pbdev->iommu->max_dma_limit << TARGET_PAGE_BITS; + if (vfio_size < (cap->end_dma - cap->start_dma + 1)) { + pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1; + } +} + +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, @@ -129,13 +163,18 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev, { 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 +183,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 +226,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 +289,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 +310,8 @@ void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) 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 +320,47 @@ void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) 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 capability 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 90480e7cf9bc..f22f61b8b6ac 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -25,6 +25,7 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/qemu-print.h" +#include "qemu/units.h" #include "hw/s390x/s390-pci-bus.h" #include "sysemu/reset.h" #include "hw/s390x/storage-keys.h" @@ -42,6 +43,7 @@ #include "sysemu/sysemu.h" #include "hw/s390x/pv.h" #include "migration/blocker.h" +#include "qapi/visitor.h" static Error *pv_mig_blocker; @@ -83,8 +85,15 @@ static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, static void s390_init_cpus(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); + S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc); int i; + if (machine->smp.threads > s390mc->max_threads) { + error_report("S390 does not support more than %d threads.", + s390mc->max_threads); + exit(1); + } + /* initialize possible_cpus */ mc->possible_cpu_arch_ids(machine); @@ -109,7 +118,7 @@ static void subsystem_reset(void) for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); if (dev) { - qdev_reset_all(dev); + device_cold_reset(dev); } } } @@ -345,7 +354,7 @@ static int s390_machine_protect(S390CcwMachineState *ms) } error_setg(&pv_mig_blocker, - "protected VMs are currently not migrateable."); + "protected VMs are currently not migratable."); rc = migrate_add_blocker(pv_mig_blocker, &local_err); if (rc) { ram_block_discard_disable(false); @@ -365,6 +374,12 @@ static int s390_machine_protect(S390CcwMachineState *ms) ms->pv = true; + /* Will return 0 if API is not available since it's not vital */ + rc = s390_pv_query_info(); + if (rc) { + goto out_err; + } + /* Set SE header and unpack */ rc = s390_ipl_prepare_pv_header(); if (rc) { @@ -404,7 +419,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms) s390_pv_prep_reset(); } -static void s390_machine_reset(MachineState *machine) +static void s390_machine_reset(MachineState *machine, ShutdownCause reason) { S390CcwMachineState *ms = S390_CCW_MACHINE(machine); enum s390_reset reset_type; @@ -426,7 +441,7 @@ static void s390_machine_reset(MachineState *machine) s390_machine_unprotect(ms); } - qemu_devices_reset(); + qemu_devices_reset(reason); s390_crypto_reset(); /* configure and start the ipl CPU only */ @@ -434,7 +449,7 @@ static void s390_machine_reset(MachineState *machine) break; case S390_RESET_MODIFIED_CLEAR: /* - * Susbsystem reset needs to be done before we unshare memory + * Subsystem reset needs to be done before we unshare memory * and lose access to VIRTIO structures in guest memory. */ subsystem_reset(); @@ -447,7 +462,7 @@ static void s390_machine_reset(MachineState *machine) break; case S390_RESET_LOAD_NORMAL: /* - * Susbsystem reset needs to be done before we unshare memory + * Subsystem reset needs to be done before we unshare memory * and lose access to VIRTIO structures in guest memory. */ subsystem_reset(); @@ -582,38 +597,6 @@ static ram_addr_t s390_fixup_ram_size(ram_addr_t sz) return newsz; } -static void ccw_machine_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - NMIClass *nc = NMI_CLASS(oc); - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); - S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc); - - s390mc->ri_allowed = true; - s390mc->cpu_model_allowed = true; - s390mc->css_migration_enabled = true; - s390mc->hpage_1m_allowed = true; - mc->init = ccw_init; - mc->reset = s390_machine_reset; - mc->block_default_type = IF_VIRTIO; - mc->no_cdrom = 1; - mc->no_floppy = 1; - mc->no_parallel = 1; - mc->no_sdcard = 1; - mc->max_cpus = S390_MAX_CPUS; - mc->has_hotpluggable_cpus = true; - assert(!mc->get_hotplug_handler); - mc->get_hotplug_handler = s390_get_hotplug_handler; - mc->cpu_index_to_instance_props = s390_cpu_index_to_props; - mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; - /* it is overridden with 'host' cpu *in kvm_arch_init* */ - mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu"); - hc->plug = s390_machine_device_plug; - hc->unplug_request = s390_machine_device_unplug_request; - nc->nmi_monitor_handler = s390_nmi; - mc->default_ram_id = "s390.ram"; -} - static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) { S390CcwMachineState *ms = S390_CCW_MACHINE(obj); @@ -688,19 +671,29 @@ bool hpage_1m_allowed(void) return get_machine_class()->hpage_1m_allowed; } -static char *machine_get_loadparm(Object *obj, Error **errp) +static void machine_get_loadparm(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + char *str = g_strndup((char *) ms->loadparm, sizeof(ms->loadparm)); - /* make a NUL-terminated string */ - return g_strndup((char *) ms->loadparm, sizeof(ms->loadparm)); + visit_type_str(v, name, &str, errp); + g_free(str); } -static void machine_set_loadparm(Object *obj, const char *val, Error **errp) +static void machine_set_loadparm(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + char *val; int i; + if (!visit_type_str(v, name, &val, errp)) { + return; + } + for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) { uint8_t c = qemu_toupper(val[i]); /* mimic HMC */ @@ -718,29 +711,68 @@ static void machine_set_loadparm(Object *obj, const char *val, Error **errp) ms->loadparm[i] = ' '; /* pad right with spaces */ } } -static inline void s390_machine_initfn(Object *obj) + +static void ccw_machine_class_init(ObjectClass *oc, void *data) { - object_property_add_bool(obj, "aes-key-wrap", - machine_get_aes_key_wrap, - machine_set_aes_key_wrap); - object_property_set_description(obj, "aes-key-wrap", + MachineClass *mc = MACHINE_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc); + + s390mc->ri_allowed = true; + s390mc->cpu_model_allowed = true; + s390mc->css_migration_enabled = true; + s390mc->hpage_1m_allowed = true; + s390mc->max_threads = 1; + mc->init = ccw_init; + mc->reset = s390_machine_reset; + mc->block_default_type = IF_VIRTIO; + mc->no_cdrom = 1; + mc->no_floppy = 1; + mc->no_parallel = 1; + mc->no_sdcard = 1; + mc->max_cpus = S390_MAX_CPUS; + mc->has_hotpluggable_cpus = true; + assert(!mc->get_hotplug_handler); + mc->get_hotplug_handler = s390_get_hotplug_handler; + mc->cpu_index_to_instance_props = s390_cpu_index_to_props; + mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; + /* it is overridden with 'host' cpu *in kvm_arch_init* */ + mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu"); + hc->plug = s390_machine_device_plug; + hc->unplug_request = s390_machine_device_unplug_request; + nc->nmi_monitor_handler = s390_nmi; + mc->default_ram_id = "s390.ram"; + + object_class_property_add_bool(oc, "aes-key-wrap", + machine_get_aes_key_wrap, + machine_set_aes_key_wrap); + object_class_property_set_description(oc, "aes-key-wrap", "enable/disable AES key wrapping using the CPACF wrapping key"); - object_property_set_bool(obj, "aes-key-wrap", true, NULL); - object_property_add_bool(obj, "dea-key-wrap", - machine_get_dea_key_wrap, - machine_set_dea_key_wrap); - object_property_set_description(obj, "dea-key-wrap", + object_class_property_add_bool(oc, "dea-key-wrap", + machine_get_dea_key_wrap, + machine_set_dea_key_wrap); + object_class_property_set_description(oc, "dea-key-wrap", "enable/disable DEA key wrapping using the CPACF wrapping key"); - object_property_set_bool(obj, "dea-key-wrap", true, NULL); - object_property_add_str(obj, "loadparm", - machine_get_loadparm, machine_set_loadparm); - object_property_set_description(obj, "loadparm", + + object_class_property_add(oc, "loadparm", "loadparm", + machine_get_loadparm, machine_set_loadparm, + NULL, NULL); + object_class_property_set_description(oc, "loadparm", "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"); } +static inline void s390_machine_initfn(Object *obj) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + ms->aes_key_wrap = true; + ms->dea_key_wrap = true; +} + static const TypeInfo ccw_machine_info = { .name = TYPE_S390_CCW_MACHINE, .parent = TYPE_MACHINE, @@ -767,7 +799,7 @@ bool css_migration_enabled(void) { \ MachineClass *mc = MACHINE_CLASS(oc); \ ccw_machine_##suffix##_class_options(mc); \ - mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ + mc->desc = "Virtual s390x machine (version " verstr ")"; \ if (latest) { \ mc->alias = "s390-ccw-virtio"; \ mc->is_default = true; \ @@ -791,14 +823,65 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +static void ccw_machine_8_0_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_8_0_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(8_0, "8.0", true); + +static void ccw_machine_7_2_instance_options(MachineState *machine) +{ + ccw_machine_8_0_instance_options(machine); +} + +static void ccw_machine_7_2_class_options(MachineClass *mc) +{ + ccw_machine_8_0_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len); +} +DEFINE_CCW_MACHINE(7_2, "7.2", false); + +static void ccw_machine_7_1_instance_options(MachineState *machine) +{ + static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V7_1 }; + + 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); +} + +static void ccw_machine_7_1_class_options(MachineClass *mc) +{ + S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { TYPE_S390_PCI_DEVICE, "interpret", "off", }, + { TYPE_S390_PCI_DEVICE, "forwarding-assist", "off", }, + }; + + ccw_machine_7_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); + s390mc->max_threads = S390_MAX_CPUS; +} +DEFINE_CCW_MACHINE(7_1, "7.1", false); + static void ccw_machine_7_0_instance_options(MachineState *machine) { + static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V7_0 }; + + ccw_machine_7_1_instance_options(machine); + s390_set_qemu_cpu_model(0x8561, 15, 1, qemu_cpu_feat); } static void ccw_machine_7_0_class_options(MachineClass *mc) { + ccw_machine_7_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len); } -DEFINE_CCW_MACHINE(7_0, "7.0", true); +DEFINE_CCW_MACHINE(7_0, "7.0", false); static void ccw_machine_6_2_instance_options(MachineState *machine) { diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c index 9d0cbfbce2bf..e2202dae2dc2 100644 --- a/hw/s390x/tod-kvm.c +++ b/hw/s390x/tod-kvm.c @@ -13,6 +13,7 @@ #include "qemu/module.h" #include "sysemu/runstate.h" #include "hw/s390x/tod.h" +#include "hw/s390x/pv.h" #include "kvm/kvm_s390x.h" static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp) @@ -84,6 +85,14 @@ static void kvm_s390_tod_vm_state_change(void *opaque, bool running, S390TODState *td = opaque; Error *local_err = NULL; + /* + * Under PV, the clock is under ultravisor control, hence we cannot restore + * it on resume. + */ + if (s390_is_pv()) { + return; + } + if (running && td->stopped) { /* Set the old TOD when running the VM - start the TOD clock. */ kvm_s390_set_tod_raw(&td->base, &local_err); diff --git a/hw/s390x/vhost-scsi-ccw.c b/hw/s390x/vhost-scsi-ccw.c new file mode 100644 index 000000000000..40dc14bbc719 --- /dev/null +++ b/hw/s390x/vhost-scsi-ccw.c @@ -0,0 +1,73 @@ +/* + * vhost ccw scsi implementation + * + * Copyright 2012, 2015 IBM Corp. + * Author(s): Cornelia Huck + * + * 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 "hw/qdev-properties.h" +#include "hw/virtio/virtio.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "virtio-ccw.h" +#include "hw/virtio/vhost-scsi.h" + +#define TYPE_VHOST_SCSI_CCW "vhost-scsi-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VHostSCSICcw, VHOST_SCSI_CCW) + +struct VHostSCSICcw { + VirtioCcwDevice parent_obj; + VHostSCSI vdev; +}; + +static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) +{ + VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); +} + +static void vhost_ccw_scsi_instance_init(Object *obj) +{ + VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); +} + +static Property vhost_ccw_scsi_properties[] = { + DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, + VIRTIO_CCW_MAX_REV), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->realize = vhost_ccw_scsi_realize; + device_class_set_props(dc, vhost_ccw_scsi_properties); + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); +} + +static const TypeInfo vhost_ccw_scsi = { + .name = TYPE_VHOST_SCSI_CCW, + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VHostSCSICcw), + .instance_init = vhost_ccw_scsi_instance_init, + .class_init = vhost_ccw_scsi_class_init, +}; + +static void virtio_ccw_scsi_register(void) +{ + type_register_static(&vhost_ccw_scsi); +} + +type_init(virtio_ccw_scsi_register) diff --git a/hw/s390x/vhost-vsock-ccw.c b/hw/s390x/vhost-vsock-ccw.c index 246416a8f964..07845a9a006f 100644 --- a/hw/s390x/vhost-vsock-ccw.c +++ b/hw/s390x/vhost-vsock-ccw.c @@ -12,6 +12,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/vhost-vsock.h" + +#define TYPE_VHOST_VSOCK_CCW "vhost-vsock-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VHostVSockCCWState, VHOST_VSOCK_CCW) + +struct VHostVSockCCWState { + VirtioCcwDevice parent_obj; + VHostVSock vdev; +}; static Property vhost_vsock_ccw_properties[] = { DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, diff --git a/hw/s390x/virtio-ccw-9p.c b/hw/s390x/virtio-ccw-9p.c index 88c8884fc51d..6f931f5994c2 100644 --- a/hw/s390x/virtio-ccw-9p.c +++ b/hw/s390x/virtio-ccw-9p.c @@ -15,6 +15,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/9pfs/virtio-9p.h" + +#define TYPE_VIRTIO_9P_CCW "virtio-9p-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(V9fsCCWState, VIRTIO_9P_CCW) + +struct V9fsCCWState { + VirtioCcwDevice parent_obj; + V9fsVirtioState vdev; +}; static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-balloon.c b/hw/s390x/virtio-ccw-balloon.c index 4c7631a43350..44287b9bbec4 100644 --- a/hw/s390x/virtio-ccw-balloon.c +++ b/hw/s390x/virtio-ccw-balloon.c @@ -15,6 +15,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-balloon.h" + +#define TYPE_VIRTIO_BALLOON_CCW "virtio-balloon-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBalloonCcw, VIRTIO_BALLOON_CCW) + +struct VirtIOBalloonCcw { + VirtioCcwDevice parent_obj; + VirtIOBalloon vdev; +}; static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c index 2294ce1ce4a0..8e0e58b77d8f 100644 --- a/hw/s390x/virtio-ccw-blk.c +++ b/hw/s390x/virtio-ccw-blk.c @@ -15,6 +15,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-blk.h" + +#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlkCcw, VIRTIO_BLK_CCW) + +struct VirtIOBlkCcw { + VirtioCcwDevice parent_obj; + VirtIOBlock vdev; +}; static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index 358c74fb4bca..0fa2f894439e 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -14,6 +14,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-crypto.h" + +#define TYPE_VIRTIO_CRYPTO_CCW "virtio-crypto-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOCryptoCcw, VIRTIO_CRYPTO_CCW) + +struct VirtIOCryptoCcw { + VirtioCcwDevice parent_obj; + VirtIOCrypto vdev; +}; static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c index 5868a2a07093..0642c5281d92 100644 --- a/hw/s390x/virtio-ccw-gpu.c +++ b/hw/s390x/virtio-ccw-gpu.c @@ -14,6 +14,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-gpu.h" + +#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUCcw, VIRTIO_GPU_CCW) + +struct VirtIOGPUCcw { + VirtioCcwDevice parent_obj; + VirtIOGPU vdev; +}; static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp) { @@ -60,6 +69,7 @@ static const TypeInfo virtio_ccw_gpu = { .class_init = virtio_ccw_gpu_class_init, }; module_obj(TYPE_VIRTIO_GPU_CCW); +module_kconfig(VIRTIO_CCW); static void virtio_ccw_gpu_register(void) { diff --git a/hw/s390x/virtio-ccw-input.c b/hw/s390x/virtio-ccw-input.c index 83136fbba15c..61a07ba38d0f 100644 --- a/hw/s390x/virtio-ccw-input.c +++ b/hw/s390x/virtio-ccw-input.c @@ -14,6 +14,26 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-input.h" + +#define TYPE_VIRTIO_INPUT_CCW "virtio-input-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputCcw, VIRTIO_INPUT_CCW) + +struct VirtIOInputCcw { + VirtioCcwDevice parent_obj; + VirtIOInput vdev; +}; + +#define TYPE_VIRTIO_INPUT_HID_CCW "virtio-input-hid-ccw" +#define TYPE_VIRTIO_KEYBOARD_CCW "virtio-keyboard-ccw" +#define TYPE_VIRTIO_MOUSE_CCW "virtio-mouse-ccw" +#define TYPE_VIRTIO_TABLET_CCW "virtio-tablet-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputHIDCcw, VIRTIO_INPUT_HID_CCW) + +struct VirtIOInputHIDCcw { + VirtioCcwDevice parent_obj; + VirtIOInputHID vdev; +}; static void virtio_ccw_input_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c index 3860d4e6ea93..484e61765997 100644 --- a/hw/s390x/virtio-ccw-net.c +++ b/hw/s390x/virtio-ccw-net.c @@ -15,6 +15,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-net.h" + +#define TYPE_VIRTIO_NET_CCW "virtio-net-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIONetCcw, VIRTIO_NET_CCW) + +struct VirtIONetCcw { + VirtioCcwDevice parent_obj; + VirtIONet vdev; +}; static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index 2e3a9da5e8be..a3fffb513841 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -15,6 +15,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-rng.h" + +#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIORNGCcw, VIRTIO_RNG_CCW) + +struct VirtIORNGCcw { + VirtioCcwDevice parent_obj; + VirtIORNG vdev; +}; static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw-scsi.c b/hw/s390x/virtio-ccw-scsi.c index 6e4beef700bd..d003f89f437f 100644 --- a/hw/s390x/virtio-ccw-scsi.c +++ b/hw/s390x/virtio-ccw-scsi.c @@ -15,6 +15,15 @@ #include "qapi/error.h" #include "qemu/module.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-scsi.h" + +#define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOSCSICcw, VIRTIO_SCSI_CCW) + +struct VirtIOSCSICcw { + VirtioCcwDevice parent_obj; + VirtIOSCSI vdev; +}; static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) { @@ -70,56 +79,9 @@ static const TypeInfo virtio_ccw_scsi = { .class_init = virtio_ccw_scsi_class_init, }; -#ifdef CONFIG_VHOST_SCSI - -static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - qdev_realize(vdev, BUS(&ccw_dev->bus), errp); -} - -static void vhost_ccw_scsi_instance_init(Object *obj) -{ - VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_SCSI); -} - -static Property vhost_ccw_scsi_properties[] = { - DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, - VIRTIO_CCW_MAX_REV), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = vhost_ccw_scsi_realize; - device_class_set_props(dc, vhost_ccw_scsi_properties); - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - -static const TypeInfo vhost_ccw_scsi = { - .name = TYPE_VHOST_SCSI_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VHostSCSICcw), - .instance_init = vhost_ccw_scsi_instance_init, - .class_init = vhost_ccw_scsi_class_init, -}; - -#endif - static void virtio_ccw_scsi_register(void) { type_register_static(&virtio_ccw_scsi); -#ifdef CONFIG_VHOST_SCSI - type_register_static(&vhost_ccw_scsi); -#endif } type_init(virtio_ccw_scsi_register) diff --git a/hw/s390x/virtio-ccw-serial.c b/hw/s390x/virtio-ccw-serial.c index 61958228d169..bf8057880ff6 100644 --- a/hw/s390x/virtio-ccw-serial.c +++ b/hw/s390x/virtio-ccw-serial.c @@ -15,6 +15,15 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-serial.h" #include "virtio-ccw.h" +#include "hw/virtio/virtio-serial.h" + +#define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw" +OBJECT_DECLARE_SIMPLE_TYPE(VirtioSerialCcw, VIRTIO_SERIAL_CCW) + +struct VirtioSerialCcw { + VirtioCcwDevice parent_obj; + VirtIOSerial vdev; +}; static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) { diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index c845a92c3a8b..e33e5207ab8d 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "exec/address-spaces.h" #include "sysemu/kvm.h" #include "net/net.h" #include "hw/virtio/virtio.h" @@ -19,6 +20,7 @@ #include "hw/virtio/virtio-net.h" #include "qemu/bitops.h" #include "qemu/error-report.h" +#include "qemu/log.h" #include "qemu/module.h" #include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-bus.h" @@ -247,12 +249,11 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info, return 0; } -static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) +static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev) { CcwDevice *ccw_dev = CCW_DEVICE(dev); - virtio_ccw_stop_ioeventfd(dev); - virtio_reset(vdev); + virtio_bus_reset(&dev->bus); if (dev->indicators) { release_indicator(&dev->routes.adapter, dev->indicators); dev->indicators = NULL; @@ -357,7 +358,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1); break; case CCW_CMD_VDEV_RESET: - virtio_ccw_reset_virtio(dev, vdev); + virtio_ccw_reset_virtio(dev); ret = 0; break; case CCW_CMD_READ_FEAT: @@ -534,7 +535,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } if (virtio_set_status(vdev, status) == 0) { if (vdev->status == 0) { - virtio_ccw_reset_virtio(dev, vdev); + virtio_ccw_reset_virtio(dev); } if (status & VIRTIO_CONFIG_S_DRIVER_OK) { virtio_ccw_start_ioeventfd(dev); @@ -919,10 +920,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) static void virtio_ccw_reset(DeviceState *d) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - virtio_ccw_reset_virtio(dev, vdev); + virtio_ccw_reset_virtio(dev); if (vdc->parent_reset) { vdc->parent_reset(d); } diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 0168232e3b8d..fac186c8f64d 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -13,24 +13,8 @@ #ifndef HW_S390X_VIRTIO_CCW_H #define HW_S390X_VIRTIO_CCW_H -#include "hw/virtio/virtio-blk.h" -#include "hw/virtio/virtio-net.h" -#include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-scsi.h" #include "qom/object.h" -#ifdef CONFIG_VHOST_SCSI -#include "hw/virtio/vhost-scsi.h" -#endif -#include "hw/virtio/virtio-balloon.h" -#include "hw/virtio/virtio-rng.h" -#include "hw/virtio/virtio-crypto.h" #include "hw/virtio/virtio-bus.h" -#ifdef CONFIG_VHOST_VSOCK -#include "hw/virtio/vhost-vsock.h" -#endif /* CONFIG_VHOST_VSOCK */ -#include "hw/virtio/virtio-gpu.h" -#include "hw/virtio/virtio-input.h" - #include "hw/s390x/s390_flic.h" #include "hw/s390x/css.h" #include "ccw-device.h" @@ -104,139 +88,6 @@ static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev) return dev->max_rev; } -/* virtio-scsi-ccw */ - -#define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOSCSICcw, VIRTIO_SCSI_CCW) - -struct VirtIOSCSICcw { - VirtioCcwDevice parent_obj; - VirtIOSCSI vdev; -}; - -#ifdef CONFIG_VHOST_SCSI -/* vhost-scsi-ccw */ - -#define TYPE_VHOST_SCSI_CCW "vhost-scsi-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VHostSCSICcw, VHOST_SCSI_CCW) - -struct VHostSCSICcw { - VirtioCcwDevice parent_obj; - VHostSCSI vdev; -}; -#endif - -/* virtio-blk-ccw */ - -#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlkCcw, VIRTIO_BLK_CCW) - -struct VirtIOBlkCcw { - VirtioCcwDevice parent_obj; - VirtIOBlock vdev; -}; - -/* virtio-balloon-ccw */ - -#define TYPE_VIRTIO_BALLOON_CCW "virtio-balloon-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBalloonCcw, VIRTIO_BALLOON_CCW) - -struct VirtIOBalloonCcw { - VirtioCcwDevice parent_obj; - VirtIOBalloon vdev; -}; - -/* virtio-serial-ccw */ - -#define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtioSerialCcw, VIRTIO_SERIAL_CCW) - -struct VirtioSerialCcw { - VirtioCcwDevice parent_obj; - VirtIOSerial vdev; -}; - -/* virtio-net-ccw */ - -#define TYPE_VIRTIO_NET_CCW "virtio-net-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIONetCcw, VIRTIO_NET_CCW) - -struct VirtIONetCcw { - VirtioCcwDevice parent_obj; - VirtIONet vdev; -}; - -/* virtio-rng-ccw */ - -#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIORNGCcw, VIRTIO_RNG_CCW) - -struct VirtIORNGCcw { - VirtioCcwDevice parent_obj; - VirtIORNG vdev; -}; - -/* virtio-crypto-ccw */ - -#define TYPE_VIRTIO_CRYPTO_CCW "virtio-crypto-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOCryptoCcw, VIRTIO_CRYPTO_CCW) - -struct VirtIOCryptoCcw { - VirtioCcwDevice parent_obj; - VirtIOCrypto vdev; -}; - VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch); -#ifdef CONFIG_VIRTFS -#include "hw/9pfs/virtio-9p.h" - -#define TYPE_VIRTIO_9P_CCW "virtio-9p-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(V9fsCCWState, VIRTIO_9P_CCW) - -struct V9fsCCWState { - VirtioCcwDevice parent_obj; - V9fsVirtioState vdev; -}; - -#endif /* CONFIG_VIRTFS */ - -#ifdef CONFIG_VHOST_VSOCK -#define TYPE_VHOST_VSOCK_CCW "vhost-vsock-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VHostVSockCCWState, VHOST_VSOCK_CCW) - -struct VHostVSockCCWState { - VirtioCcwDevice parent_obj; - VHostVSock vdev; -}; - -#endif /* CONFIG_VHOST_VSOCK */ - -#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUCcw, VIRTIO_GPU_CCW) - -struct VirtIOGPUCcw { - VirtioCcwDevice parent_obj; - VirtIOGPU vdev; -}; - -#define TYPE_VIRTIO_INPUT_CCW "virtio-input-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputCcw, VIRTIO_INPUT_CCW) - -struct VirtIOInputCcw { - VirtioCcwDevice parent_obj; - VirtIOInput vdev; -}; - -#define TYPE_VIRTIO_INPUT_HID_CCW "virtio-input-hid-ccw" -#define TYPE_VIRTIO_KEYBOARD_CCW "virtio-keyboard-ccw" -#define TYPE_VIRTIO_MOUSE_CCW "virtio-mouse-ccw" -#define TYPE_VIRTIO_TABLET_CCW "virtio-tablet-ccw" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputHIDCcw, VIRTIO_INPUT_HID_CCW) - -struct VirtIOInputHIDCcw { - VirtioCcwDevice parent_obj; - VirtIOInputHID vdev; -}; - #endif diff --git a/hw/scsi/Kconfig b/hw/scsi/Kconfig index 77d397c94905..e7b34dc8e269 100644 --- a/hw/scsi/Kconfig +++ b/hw/scsi/Kconfig @@ -48,6 +48,11 @@ config VIRTIO_SCSI depends on VIRTIO select SCSI +config VHOST_SCSI + bool + default y + depends on VIRTIO && VHOST_KERNEL + config VHOST_USER_SCSI bool # Only PCI devices are provided for now diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 1792f84cea6c..2f7f11e70b08 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -24,7 +24,7 @@ */ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/irq.h" #include "hw/nvram/eeprom93xx.h" #include "hw/scsi/esp.h" diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 2d3c649567af..e52188d0228d 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); @@ -515,7 +515,7 @@ static void do_dma_pdma_cb(ESPState *s) } else { /* * Extra message out bytes received: update cmdfifo_cdb_offset - * and then switch to commmand phase + * and then switch to command phase */ s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; @@ -627,7 +627,7 @@ static void esp_do_dma(ESPState *s) } else { /* * Extra message out bytes received: update cmdfifo_cdb_offset - * and then switch to commmand phase + * and then switch to command phase */ s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; @@ -738,7 +738,7 @@ static void esp_do_nodma(ESPState *s) } else { /* * Extra message out bytes received: update cmdfifo_cdb_offset - * and then switch to commmand phase + * and then switch to command phase */ s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; @@ -939,6 +939,11 @@ static void esp_soft_reset(ESPState *s) esp_hard_reset(s); } +static void esp_bus_reset(ESPState *s) +{ + bus_cold_reset(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 c8773f73f756..af93557a9a30 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "hw/irq.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/scsi/scsi.h" #include "migration/vmstate.h" #include "sysemu/dma.h" @@ -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) { @@ -1028,8 +1028,9 @@ static void lsi_do_msgout(LSIState *s) case 0x0d: /* The ABORT TAG message clears the current I/O process only. */ trace_lsi_do_msgout_abort(current_tag); - if (current_req) { + if (current_req && current_req->req) { scsi_req_cancel(current_req->req); + current_req = NULL; } lsi_disconnect(s); break; @@ -1055,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s) /* clear the current I/O process */ if (s->current) { scsi_req_cancel(s->current->req); + current_req = NULL; } /* As the current implemented devices scsi_disk and scsi_generic @@ -1866,7 +1868,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } if (val & LSI_SCNTL1_RST) { if (!(s->sstat0 & LSI_SSTAT0_RST)) { - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); } @@ -1924,7 +1926,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) lsi_execute_script(s); } if (val & LSI_ISTAT0_SRST) { - qdev_reset_all(DEVICE(s)); + device_cold_reset(DEVICE(s)); } break; case 0x16: /* MBOX0 */ diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index d5dfb412bac4..9cbbb16121d7 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"); @@ -1484,7 +1484,7 @@ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd) MegasasCmd *tmp_cmd = &s->frames[i]; if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) { SCSIDevice *d = tmp_cmd->req->dev; - qdev_reset_all(&d->qdev); + device_cold_reset(&d->qdev); } } return MFI_STAT_OK; @@ -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/mfi.h b/hw/scsi/mfi.h index e67a5c0b477d..0b4ee53dfc0b 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -633,7 +633,7 @@ struct mfi_ctrl_props { * metadata and user data * 1=5%, 2=10%, 3=15% and so on */ - uint8_t viewSpace; /* snapshot writeable VIEWs + uint8_t viewSpace; /* snapshot writable VIEWs * capacity as a % of source LD * capacity. 0=READ only * 1=5%, 2=10%, 3=15% and so on diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 706cf0df3a1f..c485da792c9d 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; @@ -521,7 +522,7 @@ static void mptsas_process_scsi_task_mgmt(MPTSASState *s, MPIMsgSCSITaskMgmt *re reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN; goto out; } - qdev_reset_all(&sdev->qdev); + device_cold_reset(&sdev->qdev); break; case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: @@ -537,13 +538,13 @@ static void mptsas_process_scsi_task_mgmt(MPTSASState *s, MPIMsgSCSITaskMgmt *re QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { sdev = SCSI_DEVICE(kid->child); if (sdev->channel == 0 && sdev->id == req->TargetID) { - qdev_reset_all(kid->child); + device_cold_reset(kid->child); } } break; case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); break; default: @@ -806,7 +807,7 @@ static void mptsas_soft_reset(MPTSASState *s) s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM; mptsas_update_interrupt(s); - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->intr_status = 0; s->intr_mask = save_mask; diff --git a/hw/scsi/mptsas.h b/hw/scsi/mptsas.h index c046497db719..04e97ce3af91 100644 --- a/hw/scsi/mptsas.h +++ b/hw/scsi/mptsas.h @@ -2,7 +2,7 @@ #define MPTSAS_H #include "mpi.h" -#include "qom/object.h" +#include "hw/pci/pci_device.h" #define MPTSAS_NUM_PORTS 8 #define MPTSAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index b2e2bc3c96c5..ceceafb2cdf3 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; } @@ -1609,6 +1616,24 @@ static int scsi_ua_precedence(SCSISense sense) return (sense.asc << 8) | sense.ascq; } +void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense) +{ + int prec1, prec2; + if (sense.key != UNIT_ATTENTION) { + return; + } + + /* + * Override a pre-existing unit attention condition, except for a more + * important reset condition. + */ + prec1 = scsi_ua_precedence(bus->unit_attention); + prec2 = scsi_ua_precedence(sense); + if (prec2 < prec1) { + bus->unit_attention = sense; + } +} + void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense) { int prec1, prec2; @@ -1713,7 +1738,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 072686ed58f9..e493c2881403 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -94,6 +94,7 @@ struct SCSIDiskState { uint16_t port_index; uint64_t max_unmap_size; uint64_t max_io_size; + uint32_t quirks; QEMUBH *bh; char *version; char *serial; @@ -1078,12 +1079,14 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, int page_control) { static const int mode_sense_valid[0x3f] = { + [MODE_PAGE_VENDOR_SPECIFIC] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM), [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM), + [MODE_PAGE_APPLE_VENDOR] = (1 << TYPE_ROM), }; uint8_t *p = *p_outbuf + 2; @@ -1185,6 +1188,10 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, case MODE_PAGE_R_W_ERROR: length = 10; if (page_control == 1) { /* Changeable Values */ + if (s->qdev.type == TYPE_ROM) { + /* Automatic Write Reallocation Enabled */ + p[0] = 0x80; + } break; } p[0] = 0x80; /* Automatic Write Reallocation Enabled */ @@ -1228,6 +1235,36 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, p[19] = (16 * 176) & 0xff; break; + case MODE_PAGE_APPLE_VENDOR: + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR)) { + length = 0x1e; + if (page_control == 1) { /* Changeable Values */ + break; + } + + memset(p, 0, length); + strcpy((char *)p + 8, "APPLE COMPUTER, INC "); + break; + } else { + return -1; + } + + case MODE_PAGE_VENDOR_SPECIFIC: + if (s->qdev.type == TYPE_DISK && (s->quirks & + (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) { + length = 0x2; + if (page_control == 1) { /* Changeable Values */ + p[0] = 0xff; + p[1] = 0xff; + break; + } + p[0] = 0; + p[1] = 0; + break; + } else { + return -1; + } + default: return -1; } @@ -1263,10 +1300,27 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) dev_specific_param |= 0x80; /* Readonly. */ } } else { - /* MMC prescribes that CD/DVD drives have no block descriptors, - * and defines no device-specific parameter. */ - dev_specific_param = 0x00; - dbd = true; + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD)) { + /* Use DBD from the request... */ + dev_specific_param = 0x00; + + /* + * ... unless we receive a request for MODE_PAGE_APPLE_VENDOR + * which should never return a block descriptor even though DBD is + * not set, otherwise CDROM detection fails in MacOS + */ + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR) && + page == MODE_PAGE_APPLE_VENDOR) { + dbd = true; + } + } else { + /* + * MMC prescribes that CD/DVD drives have no block descriptors, + * and defines no device-specific parameter. + */ + dev_specific_param = 0x00; + dbd = true; + } } if (r->req.cmd.buf[0] == MODE_SENSE) { @@ -1502,7 +1556,10 @@ static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) goto invalid_param; } if (page_len > len) { - goto invalid_param_len; + if (!(s->quirks & SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED)) { + goto invalid_param_len; + } + trace_scsi_disk_mode_select_page_truncated(page, page_len, len); } if (!change) { @@ -1534,12 +1591,15 @@ 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; - /* We only support PF=1, SP=0. */ if ((r->req.cmd.buf[1] & 0x11) != 0x10) { - goto invalid_field; + if (!(s->quirks & + (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) { + /* We only support PF=1, SP=0. */ + goto invalid_field; + } } if (len < hdr_len) { @@ -1556,6 +1616,22 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) goto invalid_param; } + /* Allow changing the block size */ + 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; p += bd_len; @@ -1783,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)) { @@ -1825,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); @@ -2127,6 +2204,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) trace_scsi_disk_emulate_command_WRITE_SAME( req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer); break; + case FORMAT_UNIT: + trace_scsi_disk_emulate_command_FORMAT_UNIT(r->req.cmd.xfer); + break; default: trace_scsi_disk_emulate_command_UNKNOWN(buf[0], scsi_command_name(buf[0])); @@ -2419,7 +2499,6 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) } else { blk_set_dev_ops(s->qdev.conf.blk, &scsi_disk_block_ops, s); } - blk_set_guest_block_size(s->qdev.conf.blk, s->qdev.blocksize); blk_iostatus_enable(s->qdev.conf.blk); @@ -2465,6 +2544,7 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); AioContext *ctx; int ret; + uint32_t blocksize = 2048; if (!dev->conf.blk) { /* Anonymous BlockBackend for an empty drive. As we put it into @@ -2474,9 +2554,13 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) assert(ret == 0); } + if (dev->conf.physical_block_size != 0) { + blocksize = dev->conf.physical_block_size; + } + ctx = blk_get_aio_context(dev->conf.blk); aio_context_acquire(ctx); - s->qdev.blocksize = 2048; + s->qdev.blocksize = blocksize; s->qdev.type = TYPE_ROM; s->features |= 1 << SCSI_DISK_F_REMOVABLE; if (!s->product) { @@ -2533,6 +2617,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { [VERIFY_10] = &scsi_disk_emulate_reqops, [VERIFY_12] = &scsi_disk_emulate_reqops, [VERIFY_16] = &scsi_disk_emulate_reqops, + [FORMAT_UNIT] = &scsi_disk_emulate_reqops, [READ_6] = &scsi_disk_dma_reqops, [READ_10] = &scsi_disk_dma_reqops, @@ -2950,14 +3035,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); } } @@ -3037,6 +3123,9 @@ static Property scsi_hd_properties[] = { DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, 5), + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -3085,6 +3174,15 @@ static Property scsi_cd_properties[] = { DEFAULT_MAX_IO_SIZE), DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, 5), + DEFINE_PROP_BIT("quirk_mode_page_apple_vendor", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0), + DEFINE_PROP_BIT("quirk_mode_sense_rom_use_dbd", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD, 0), + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), + DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 0306ccc7b1e4..92cce20a4dbe 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); @@ -321,7 +328,6 @@ static void scsi_read_complete(void * opaque, int ret) s->blocksize = ldl_be_p(&r->buf[8]); s->max_lba = ldq_be_p(&r->buf[0]); } - blk_set_guest_block_size(s->conf.blk, s->blocksize); /* * Patch MODE SENSE device specific parameters if the BDS is opened @@ -785,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 a07a8e1523f6..5bbbef64ef34 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], @@ -864,7 +865,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req) break; } - qdev_reset_all(&d->qdev); + device_cold_reset(&d->qdev); break; case SRP_TSK_ABORT_TASK_SET: @@ -1013,7 +1014,7 @@ static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req) } /* - * Current implementation does not suppport any migration or + * Current implementation does not support any migration or * reservation capabilities. Construct the response telling the * guest not to use them. */ diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 20fb0dc16233..ab238293f0da 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -334,10 +334,13 @@ scsi_disk_emulate_command_UNMAP(size_t xfer) "Unmap (len %zd)" scsi_disk_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)" scsi_disk_emulate_command_WRITE_SAME(int cmd, size_t xfer) "WRITE SAME %d (len %zd)" scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)" +scsi_disk_emulate_command_FORMAT_UNIT(size_t xfer) "Format Unit (len %zu)" scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)" scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)" scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s" scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd=0x%x (sector %" PRId64 ", count %d) timeout=%u" +scsi_disk_mode_select_page_truncated(int page, int len, int page_len) "page %d expected length %d but received length %d" +scsi_disk_mode_select_set_blocksize(int blocksize) "set block size to %d" # scsi-generic.c scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d" diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c index 767f827e55be..a06f01af2624 100644 --- a/hw/scsi/vhost-scsi-common.c +++ b/hw/scsi/vhost-scsi-common.c @@ -68,7 +68,7 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) goto err_guest_notifiers; } - ret = vhost_dev_start(&vsc->dev, vdev); + ret = vhost_dev_start(&vsc->dev, vdev, true); if (ret < 0) { error_report("Error start vhost dev"); goto err_guest_notifiers; @@ -101,7 +101,7 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc) VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); int ret = 0; - vhost_dev_stop(&vsc->dev, vdev); + vhost_dev_stop(&vsc->dev, vdev, true); if (k->set_guest_notifiers) { ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); @@ -113,6 +113,7 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc) if (vsc->inflight) { vhost_dev_free_inflight(vsc->inflight); + g_free(vsc->inflight); vsc->inflight = NULL; } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 778f43e4c190..6a0fd0dfb13d 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -38,6 +38,7 @@ static const int kernel_feature_bits[] = { VIRTIO_RING_F_INDIRECT_DESC, VIRTIO_RING_F_EVENT_IDX, VIRTIO_SCSI_F_HOTPLUG, + VIRTIO_F_RING_RESET, VHOST_INVALID_FEATURE_BIT }; @@ -120,7 +121,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 +148,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; } @@ -273,6 +274,13 @@ static void vhost_scsi_unrealize(DeviceState *dev) virtio_scsi_common_unrealize(dev); } +static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev) +{ + VHostSCSI *s = VHOST_SCSI(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + return &vsc->dev; +} + static Property vhost_scsi_properties[] = { DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd), DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn), @@ -307,6 +315,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) vdc->get_features = vhost_scsi_common_get_features; vdc->set_config = vhost_scsi_common_set_config; vdc->set_status = vhost_scsi_set_status; + vdc->get_vhost = vhost_scsi_get_vhost; fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; } diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 1b2f7eed9889..b7a71a802cdb 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -36,6 +36,7 @@ static const int user_feature_bits[] = { VIRTIO_RING_F_INDIRECT_DESC, VIRTIO_RING_F_EVENT_IDX, VIRTIO_SCSI_F_HOTPLUG, + VIRTIO_F_RING_RESET, VHOST_INVALID_FEATURE_BIT }; @@ -49,7 +50,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 29575cbaf660..20bb91766eed 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -136,16 +136,21 @@ 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(vs->event_vq, s->ctx); + virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx); 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 34a968ecfb5b..2b649ca9762f 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -22,6 +22,7 @@ #include "qemu/iov.h" #include "qemu/module.h" #include "sysemu/block-backend.h" +#include "sysemu/dma.h" #include "hw/qdev-properties.h" #include "hw/scsi/scsi.h" #include "scsi/constants.h" @@ -29,6 +30,43 @@ #include "hw/virtio/virtio-access.h" #include "trace.h" +typedef struct VirtIOSCSIReq { + /* + * Note: + * - fields up to resp_iov are initialized by virtio_scsi_init_req; + * - fields starting at vring are zeroed by virtio_scsi_init_req. + */ + VirtQueueElement elem; + + VirtIOSCSI *dev; + VirtQueue *vq; + QEMUSGList qsgl; + QEMUIOVector resp_iov; + + union { + /* Used for two-stage request submission */ + QTAILQ_ENTRY(VirtIOSCSIReq) next; + + /* Used for cancellation of request during TMFs */ + int remaining; + }; + + SCSIRequest *sreq; + size_t resp_size; + enum SCSIXferMode mode; + union { + VirtIOSCSICmdResp cmd; + VirtIOSCSICtrlTMFResp tmf; + VirtIOSCSICtrlANResp an; + VirtIOSCSIEvent event; + } resp; + union { + VirtIOSCSICmdReq cmd; + VirtIOSCSICtrlTMFReq tmf; + VirtIOSCSICtrlANReq an; + } req; +} VirtIOSCSIReq; + static inline int virtio_scsi_get_lun(uint8_t *lun) { return ((lun[2] << 8) | lun[3]) & 0x3FFF; @@ -45,7 +83,7 @@ static inline SCSIDevice *virtio_scsi_device_get(VirtIOSCSI *s, uint8_t *lun) return scsi_device_get(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); } -void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) +static void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) { VirtIODevice *vdev = VIRTIO_DEVICE(s); const size_t zero_skip = @@ -58,7 +96,7 @@ void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip); } -void virtio_scsi_free_req(VirtIOSCSIReq *req) +static void virtio_scsi_free_req(VirtIOSCSIReq *req) { qemu_iovec_destroy(&req->resp_iov); qemu_sglist_destroy(&req->qsgl); @@ -328,7 +366,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) goto incorrect_lun; } s->resetting++; - qdev_reset_all(&d->qdev); + device_cold_reset(&d->qdev); s->resetting--; break; @@ -380,7 +418,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { SCSIDevice *d1 = SCSI_DEVICE(kid->child); if (d1->channel == 0 && d1->id == target) { - qdev_reset_all(&d1->qdev); + device_cold_reset(&d1->qdev); } } rcu_read_unlock(); @@ -460,28 +498,41 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } } -bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) +static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; - bool progress = false; while ((req = virtio_scsi_pop_req(s, vq))) { - progress = true; virtio_scsi_handle_ctrl_req(s, req); } - return progress; +} + +/* + * If dataplane is configured but not yet started, do so now and return true on + * success. + * + * Dataplane is started by the core virtio code but virtqueue handler functions + * can also be invoked when a guest kicks before DRIVER_OK, so this helper + * function helps us deal with manually starting ioeventfd in that case. + */ +static bool virtio_scsi_defer_to_dataplane(VirtIOSCSI *s) +{ + if (!s->ctx || s->dataplane_started) { + return false; + } + + virtio_device_start_ioeventfd(&s->parent_obj.parent_obj); + return !s->dataplane_fenced; } static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = (VirtIOSCSI *)vdev; - if (s->ctx) { - virtio_device_start_ioeventfd(vdev); - if (!s->dataplane_fenced) { - return; - } + if (virtio_scsi_defer_to_dataplane(s)) { + return; } + virtio_scsi_acquire(s); virtio_scsi_handle_ctrl_vq(s, vq); virtio_scsi_release(s); @@ -572,7 +623,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; @@ -646,7 +698,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 || @@ -672,12 +724,11 @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) scsi_req_unref(sreq); } -bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) +static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req, *next; int ret = 0; bool suppress_notifications = virtio_queue_get_notification(vq); - bool progress = false; QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); @@ -687,7 +738,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) } while ((req = virtio_scsi_pop_req(s, vq))) { - progress = true; ret = virtio_scsi_handle_cmd_req_prepare(s, req); if (!ret) { QTAILQ_INSERT_TAIL(&reqs, req, next); @@ -712,7 +762,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { virtio_scsi_handle_cmd_req_submit(s, req); } - return progress; } static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) @@ -720,12 +769,10 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - if (s->ctx && !s->dataplane_started) { - virtio_device_start_ioeventfd(vdev); - if (!s->dataplane_fenced) { - return; - } + if (virtio_scsi_defer_to_dataplane(s)) { + return; } + virtio_scsi_acquire(s); virtio_scsi_handle_cmd_vq(s, vq); virtio_scsi_release(s); @@ -785,7 +832,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev) assert(!s->dataplane_started); s->resetting++; - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->resetting--; vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; @@ -793,8 +840,8 @@ static void virtio_scsi_reset(VirtIODevice *vdev) s->events_dropped = false; } -void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, - uint32_t event, uint32_t reason) +static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); VirtIOSCSIReq *req; @@ -842,25 +889,21 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, virtio_scsi_complete_req(req); } -bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) +static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) { if (s->events_dropped) { virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); - return true; } - return false; } static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); - if (s->ctx) { - virtio_device_start_ioeventfd(vdev); - if (!s->dataplane_fenced) { - return; - } + if (virtio_scsi_defer_to_dataplane(s)) { + return; } + virtio_scsi_acquire(s); virtio_scsi_handle_event_vq(s, vq); virtio_scsi_release(s); @@ -914,6 +957,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); + scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED)); virtio_scsi_release(s); } } @@ -931,6 +975,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED); + scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED)); virtio_scsi_release(s); } @@ -972,8 +1017,7 @@ void virtio_scsi_common_realize(DeviceState *dev, VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); int i; - virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI, - sizeof(VirtIOSCSIConfig)); + virtio_init(vdev, VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig)); if (s->conf.num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) { s->conf.num_queues = 1; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 4d9969f3b16c..fa766968550d 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -445,7 +445,7 @@ static void pvscsi_reset_adapter(PVSCSIState *s) { s->resetting++; - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->resetting--; pvscsi_process_completion_queue(s); assert(QTAILQ_EMPTY(&s->pending_queue)); @@ -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; @@ -880,7 +880,7 @@ pvscsi_on_cmd_reset_device(PVSCSIState *s) if (sdev != NULL) { s->resetting++; - device_legacy_reset(&sdev->qdev); + device_cold_reset(&sdev->qdev); s->resetting--; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; } @@ -894,7 +894,7 @@ pvscsi_on_cmd_reset_bus(PVSCSIState *s) trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS"); s->resetting++; - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->resetting--; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; } diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index 041e45c68047..51e5e908307c 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -65,7 +65,7 @@ enum { REG_SD_DLBA = 0x84, /* Descriptor List Base Address */ REG_SD_IDST = 0x88, /* Internal DMA Controller Status */ REG_SD_IDIE = 0x8C, /* Internal DMA Controller IRQ Enable */ - REG_SD_THLDC = 0x100, /* Card Threshold Control */ + REG_SD_THLDC = 0x100, /* Card Threshold Control / FIFO (sun4i only)*/ REG_SD_DSBD = 0x10C, /* eMMC DDR Start Bit Detection Control */ REG_SD_RES_CRC = 0x110, /* Response CRC from card/eMMC */ REG_SD_DATA7_CRC = 0x114, /* CRC Data 7 from card/eMMC */ @@ -114,7 +114,9 @@ enum { }; enum { + SD_STAR_FIFO_EMPTY = (1 << 2), SD_STAR_CARD_PRESENT = (1 << 8), + SD_STAR_FIFO_LEVEL_1 = (1 << 17), }; enum { @@ -413,10 +415,29 @@ static void allwinner_sdhost_dma(AwSdHostState *s) } } +static uint32_t allwinner_sdhost_fifo_read(AwSdHostState *s) +{ + uint32_t res = 0; + + if (sdbus_data_ready(&s->sdbus)) { + sdbus_read_data(&s->sdbus, &res, sizeof(uint32_t)); + le32_to_cpus(&res); + allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); + allwinner_sdhost_auto_stop(s); + allwinner_sdhost_update_irq(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n", + __func__); + } + + return res; +} + static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, unsigned size) { AwSdHostState *s = AW_SDHOST(opaque); + AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s); uint32_t res = 0; switch (offset) { @@ -467,6 +488,11 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, break; case REG_SD_STAR: /* Status */ res = s->status; + if (sdbus_data_ready(&s->sdbus)) { + res |= SD_STAR_FIFO_LEVEL_1; + } else { + res |= SD_STAR_FIFO_EMPTY; + } break; case REG_SD_FWLR: /* FIFO Water Level */ res = s->fifo_wlevel; @@ -501,8 +527,12 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, case REG_SD_IDIE: /* Internal DMA Controller Interrupt Enable */ res = s->dmac_irq; break; - case REG_SD_THLDC: /* Card Threshold Control */ - res = s->card_threshold; + case REG_SD_THLDC: /* Card Threshold Control or FIFO register (sun4i) */ + if (sc->is_sun4i) { + res = allwinner_sdhost_fifo_read(s); + } else { + res = s->card_threshold; + } break; case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ res = s->startbit_detect; @@ -524,16 +554,7 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, res = s->status_crc; break; case REG_SD_FIFO: /* Read/Write FIFO */ - if (sdbus_data_ready(&s->sdbus)) { - sdbus_read_data(&s->sdbus, &res, sizeof(uint32_t)); - le32_to_cpus(&res); - allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); - allwinner_sdhost_auto_stop(s); - allwinner_sdhost_update_irq(s); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n", - __func__); - } + res = allwinner_sdhost_fifo_read(s); break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %" @@ -546,11 +567,20 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, return res; } +static void allwinner_sdhost_fifo_write(AwSdHostState *s, uint64_t value) +{ + uint32_t u32 = cpu_to_le32(value); + sdbus_write_data(&s->sdbus, &u32, sizeof(u32)); + allwinner_sdhost_update_transfer_cnt(s, sizeof(u32)); + allwinner_sdhost_auto_stop(s); + allwinner_sdhost_update_irq(s); +} + static void allwinner_sdhost_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { AwSdHostState *s = AW_SDHOST(opaque); - uint32_t u32; + AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s); trace_allwinner_sdhost_write(offset, value, size); @@ -650,18 +680,18 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset, s->dmac_irq = value; allwinner_sdhost_update_irq(s); break; - case REG_SD_THLDC: /* Card Threshold Control */ - s->card_threshold = value; + case REG_SD_THLDC: /* Card Threshold Control or FIFO (sun4i) */ + if (sc->is_sun4i) { + allwinner_sdhost_fifo_write(s, value); + } else { + s->card_threshold = value; + } break; case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ s->startbit_detect = value; break; case REG_SD_FIFO: /* Read/Write FIFO */ - u32 = cpu_to_le32(value); - sdbus_write_data(&s->sdbus, &u32, sizeof(u32)); - allwinner_sdhost_update_transfer_cnt(s, sizeof(u32)); - allwinner_sdhost_auto_stop(s); - allwinner_sdhost_update_irq(s); + allwinner_sdhost_fifo_write(s, value); break; case REG_SD_RES_CRC: /* Response CRC from card/eMMC */ case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */ @@ -827,12 +857,14 @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 8 * KiB; + sc->is_sun4i = true; } static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 64 * KiB; + sc->is_sun4i = false; } static const TypeInfo allwinner_sdhost_info = { diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index b67def638136..edd3cf2a1eb8 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -321,11 +321,10 @@ void omap_mmc_reset(struct omap_mmc_s *host) device_cold_reset(DEVICE(host->card)); } -static uint64_t omap_mmc_read(void *opaque, hwaddr offset, - unsigned size) +static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size) { uint16_t i; - struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; + struct omap_mmc_s *s = opaque; if (size != 2) { return omap_badwidth_read16(opaque, offset); @@ -418,7 +417,7 @@ static void omap_mmc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { int i; - struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; + struct omap_mmc_s *s = opaque; if (size != 2) { omap_badwidth_write16(opaque, offset, value); @@ -576,7 +575,7 @@ static const MemoryRegionOps omap_mmc_ops = { static void omap_mmc_cover_cb(void *opaque, int line, int level) { - struct omap_mmc_s *host = (struct omap_mmc_s *) opaque; + struct omap_mmc_s *host = opaque; if (!host->cdet_state && level) { host->status |= 0x0002; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index cd67a7bac8e2..da5bdd134a97 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -47,7 +47,6 @@ #include "qemu/timer.h" #include "qemu/log.h" #include "qemu/module.h" -#include "qemu-common.h" #include "sdmmc-internal.h" #include "trace.h" @@ -753,7 +752,7 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) { trace_sdcard_read_block(addr, len); - if (!sd->blk || blk_pread(sd->blk, addr, sd->data, len) < 0) { + if (!sd->blk || blk_pread(sd->blk, addr, len, sd->data, 0) < 0) { fprintf(stderr, "sd_blk_read: read error on host side\n"); } } @@ -761,7 +760,7 @@ static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) { trace_sdcard_write_block(addr, len); - if (!sd->blk || blk_pwrite(sd->blk, addr, sd->data, len, 0) < 0) { + if (!sd->blk || blk_pwrite(sd->blk, addr, len, sd->data, 0) < 0) { fprintf(stderr, "sd_blk_write: write error on host side\n"); } } diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index e8c753d6d1ee..5f3765f12d2d 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -288,26 +288,6 @@ enum { extern const VMStateDescription sdhci_vmstate; - -#define ESDHC_MIX_CTRL 0x48 - -#define ESDHC_VENDOR_SPEC 0xc0 -#define ESDHC_IMX_FRC_SDCLK_ON (1 << 8) - -#define ESDHC_DLL_CTRL 0x60 - -#define ESDHC_TUNING_CTRL 0xcc -#define ESDHC_TUNE_CTRL_STATUS 0x68 -#define ESDHC_WTMK_LVL 0x44 - -/* Undocumented register used by guests working around erratum ERR004536 */ -#define ESDHC_UNDOCUMENTED_REG27 0x6c - -#define ESDHC_CTRL_4BITBUS (0x1 << 1) -#define ESDHC_CTRL_8BITBUS (0x2 << 1) - -#define ESDHC_PRNSTS_SDSTB (1 << 3) - /* * Default SD/MMC host controller features information, which will be * presented in CAPABILITIES register of generic SD host controller at reset. @@ -328,6 +308,7 @@ extern const VMStateDescription sdhci_vmstate; #define SDHC_CAPAB_REG_DEFAULT 0x057834b4 #define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ + DEFINE_PROP_UINT8("endianness", _state, endianness, DEVICE_LITTLE_ENDIAN), \ DEFINE_PROP_UINT8("sd-spec-version", _state, sd_spec_version, 2), \ DEFINE_PROP_UINT8("uhs", _state, uhs_mode, UHS_NOT_SUPPORTED), \ DEFINE_PROP_UINT8("vendor", _state, vendor, SDHCI_VENDOR_NONE), \ diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 0e5e988927ec..420b7ba17a24 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -259,6 +259,8 @@ static void sdhci_set_inserted(DeviceState *dev, bool level) if (s->norintstsen & SDHC_NISEN_INSERT) { s->norintsts |= SDHC_NIS_INSERT; } + /*always ensure the clock is ready */ + s->clkcon |= SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE | SDHC_CLOCK_INT_EN; } else { s->prnsts = 0x1fa0000; s->pwrcon &= ~SDHC_POWER_ON; @@ -1200,7 +1202,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) * capabilities register */ if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) { value &= ~SDHC_TRNS_DMA; - } + } MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK); MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16); @@ -1329,7 +1331,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) value >> shift, value >> shift); } -static const MemoryRegionOps sdhci_mmio_ops = { +static const MemoryRegionOps sdhci_mmio_le_ops = { .read = sdhci_read, .write = sdhci_write, .valid = { @@ -1340,6 +1342,21 @@ static const MemoryRegionOps sdhci_mmio_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static const MemoryRegionOps sdhci_mmio_be_ops = { + .read = sdhci_read, + .write = sdhci_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false + }, + .endianness = DEVICE_BIG_ENDIAN, +}; + static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp) { ERRP_GUARD(); @@ -1367,8 +1384,6 @@ void sdhci_initfn(SDHCIState *s) s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); - - s->io_ops = &sdhci_mmio_ops; } void sdhci_uninitfn(SDHCIState *s) @@ -1384,10 +1399,26 @@ void sdhci_common_realize(SDHCIState *s, Error **errp) { ERRP_GUARD(); + if (s->io_ops == NULL) { + printf("init sdhci call back\r\n"); + switch (s->endianness) { + case DEVICE_LITTLE_ENDIAN: + s->io_ops = &sdhci_mmio_le_ops; + break; + case DEVICE_BIG_ENDIAN: + s->io_ops = &sdhci_mmio_be_ops; + break; + default: + error_setg(errp, "Incorrect endianness"); + return; + } + } + sdhci_init_readonly_registers(s, errp); if (*errp) { return; } + s->buf_maxsz = sdhci_get_fifolen(s); s->fifo_buffer = g_malloc0(s->buf_maxsz); @@ -1577,6 +1608,25 @@ static const TypeInfo sdhci_bus_info = { /* --- qdev i.MX eSDHC --- */ +#define USDHC_MIX_CTRL 0x48 + +#define USDHC_VENDOR_SPEC 0xc0 +#define USDHC_IMX_FRC_SDCLK_ON (1 << 8) + +#define USDHC_DLL_CTRL 0x60 + +#define USDHC_TUNING_CTRL 0xcc +#define USDHC_TUNE_CTRL_STATUS 0x68 +#define USDHC_WTMK_LVL 0x44 + +/* Undocumented register used by guests working around erratum ERR004536 */ +#define USDHC_UNDOCUMENTED_REG27 0x6c + +#define USDHC_CTRL_4BITBUS (0x1 << 1) +#define USDHC_CTRL_8BITBUS (0x2 << 1) + +#define USDHC_PRNSTS_SDSTB (1 << 3) + static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) { SDHCIState *s = SYSBUS_SDHCI(opaque); @@ -1596,11 +1646,11 @@ static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) hostctl1 = SDHC_DMA_TYPE(s->hostctl1) << (8 - 3); if (s->hostctl1 & SDHC_CTRL_8BITBUS) { - hostctl1 |= ESDHC_CTRL_8BITBUS; + hostctl1 |= USDHC_CTRL_8BITBUS; } if (s->hostctl1 & SDHC_CTRL_4BITBUS) { - hostctl1 |= ESDHC_CTRL_4BITBUS; + hostctl1 |= USDHC_CTRL_4BITBUS; } ret = hostctl1; @@ -1611,23 +1661,25 @@ static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) case SDHC_PRNSTS: /* Add SDSTB (SD Clock Stable) bit to PRNSTS */ - ret = sdhci_read(opaque, offset, size) & ~ESDHC_PRNSTS_SDSTB; + ret = sdhci_read(opaque, offset, size) & ~USDHC_PRNSTS_SDSTB; if (s->clkcon & SDHC_CLOCK_INT_STABLE) { - ret |= ESDHC_PRNSTS_SDSTB; + ret |= USDHC_PRNSTS_SDSTB; } break; - case ESDHC_VENDOR_SPEC: + case USDHC_VENDOR_SPEC: ret = s->vendor_spec; break; - case ESDHC_DLL_CTRL: - case ESDHC_TUNE_CTRL_STATUS: - case ESDHC_UNDOCUMENTED_REG27: - case ESDHC_TUNING_CTRL: - case ESDHC_MIX_CTRL: - case ESDHC_WTMK_LVL: + case USDHC_DLL_CTRL: + case USDHC_TUNE_CTRL_STATUS: + case USDHC_UNDOCUMENTED_REG27: + case USDHC_TUNING_CTRL: + case USDHC_WTMK_LVL: ret = 0; break; + case USDHC_MIX_CTRL: + ret = s->trnmod; + break; } return ret; @@ -1641,18 +1693,18 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) uint32_t value = (uint32_t)val; switch (offset) { - case ESDHC_DLL_CTRL: - case ESDHC_TUNE_CTRL_STATUS: - case ESDHC_UNDOCUMENTED_REG27: - case ESDHC_TUNING_CTRL: - case ESDHC_WTMK_LVL: + case USDHC_DLL_CTRL: + case USDHC_TUNE_CTRL_STATUS: + case USDHC_UNDOCUMENTED_REG27: + case USDHC_TUNING_CTRL: + case USDHC_WTMK_LVL: break; - case ESDHC_VENDOR_SPEC: + case USDHC_VENDOR_SPEC: s->vendor_spec = value; switch (s->vendor) { case SDHCI_VENDOR_IMX: - if (value & ESDHC_IMX_FRC_SDCLK_ON) { + if (value & USDHC_IMX_FRC_SDCLK_ON) { s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF; } else { s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF; @@ -1721,12 +1773,12 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) * Second, split "Data Transfer Width" from bits 2 and 1 in to * bits 5 and 1 */ - if (value & ESDHC_CTRL_8BITBUS) { + if (value & USDHC_CTRL_8BITBUS) { hostctl1 |= SDHC_CTRL_8BITBUS; } - if (value & ESDHC_CTRL_4BITBUS) { - hostctl1 |= ESDHC_CTRL_4BITBUS; + if (value & USDHC_CTRL_4BITBUS) { + hostctl1 |= USDHC_CTRL_4BITBUS; } /* @@ -1749,7 +1801,7 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) sdhci_write(opaque, offset, value, size); break; - case ESDHC_MIX_CTRL: + case USDHC_MIX_CTRL: /* * So, when SD/MMC stack in Linux tries to write to "Transfer * Mode Register", ESDHC i.MX quirk code will translate it diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig index df392e786904..e03bd09b50e8 100644 --- a/hw/sensor/Kconfig +++ b/hw/sensor/Kconfig @@ -34,3 +34,7 @@ config LSM303DLHC_MAG config ISL_PMBUS_VR bool depends on PMBUS + +config MAX31785 + bool + depends on PMBUS diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c index e11e0288840d..eb344dd5a9d5 100644 --- a/hw/sensor/isl_pmbus_vr.c +++ b/hw/sensor/isl_pmbus_vr.c @@ -15,6 +15,18 @@ static uint8_t isl_pmbus_vr_read_byte(PMBusDevice *pmdev) { + ISLState *s = ISL69260(pmdev); + + switch (pmdev->code) { + case PMBUS_IC_DEVICE_ID: + if (!s->ic_device_id_len) { + break; + } + pmbus_send(pmdev, s->ic_device_id, s->ic_device_id_len); + pmbus_idle(pmdev); + return 0; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: reading from unsupported register: 0x%02x\n", __func__, pmdev->code); @@ -107,6 +119,18 @@ static void raa228000_exit_reset(Object *obj) pmdev->pages[0].read_temperature_3 = 0; } +static void isl69259_exit_reset(Object *obj) +{ + ISLState *s = ISL69260(obj); + static const uint8_t ic_device_id[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c}; + g_assert(sizeof(ic_device_id) <= sizeof(s->ic_device_id)); + + isl_pmbus_vr_exit_reset(obj); + + s->ic_device_id_len = sizeof(ic_device_id); + memcpy(s->ic_device_id, ic_device_id, sizeof(ic_device_id)); +} + static void isl_pmbus_vr_add_props(Object *obj, uint64_t *flags, uint8_t pages) { PMBusDevice *pmdev = PMBUS_DEVICE(obj); @@ -245,6 +269,21 @@ static void raa229004_class_init(ObjectClass *klass, void *data) isl_pmbus_vr_class_init(klass, data, 2); } +static void isl69259_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + dc->desc = "Renesas ISL69259 Digital Multiphase Voltage Regulator"; + rc->phases.exit = isl69259_exit_reset; + isl_pmbus_vr_class_init(klass, data, 2); +} + +static const TypeInfo isl69259_info = { + .name = TYPE_ISL69259, + .parent = TYPE_ISL69260, + .class_init = isl69259_class_init, +}; + static const TypeInfo isl69260_info = { .name = TYPE_ISL69260, .parent = TYPE_PMBUS_DEVICE, @@ -271,6 +310,7 @@ static const TypeInfo raa228000_info = { static void isl_pmbus_vr_register_types(void) { + type_register_static(&isl69259_info); type_register_static(&isl69260_info); type_register_static(&raa228000_info); type_register_static(&raa229004_info); diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c index 4c98ddbf207c..bb8d48b2fdb0 100644 --- a/hw/sensor/lsm303dlhc_mag.c +++ b/hw/sensor/lsm303dlhc_mag.c @@ -427,6 +427,8 @@ static int lsm303dlhc_mag_event(I2CSlave *i2c, enum i2c_event event) break; case I2C_NACK: break; + default: + return -1; } s->len = 0; diff --git a/hw/sensor/max31785.c b/hw/sensor/max31785.c new file mode 100644 index 000000000000..8b95e324814b --- /dev/null +++ b/hw/sensor/max31785.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Maxim MAX31785 PMBus 6-Channel Fan Controller + * + * Datasheet: + * https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf + * + * Copyright(c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "qemu/osdep.h" +#include "hw/i2c/pmbus_device.h" +#include "hw/irq.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "qemu/log.h" +#include "qemu/module.h" + +#define TYPE_MAX31785 "max31785" +#define MAX31785(obj) OBJECT_CHECK(MAX31785State, (obj), TYPE_MAX31785) + +/* MAX31785 mfr specific PMBus commands */ +#define MAX31785_MFR_MODE 0xD1 +#define MAX31785_MFR_PSEN_CONFIG 0xD2 +#define MAX31785_MFR_VOUT_PEAK 0xD4 +#define MAX31785_MFR_TEMPERATURE_PEAK 0xD6 +#define MAX31785_MFR_VOUT_MIN 0xD7 +#define MAX31785_MFR_FAULT_RESPONSE 0xD9 +#define MAX31785_MFR_NV_FAULT_LOG 0xDC +#define MAX31785_MFR_TIME_COUNT 0xDD +#define MAX31785_MFR_TEMP_SENSOR_CONFIG 0xF0 +#define MAX31785_MFR_FAN_CONFIG 0xF1 +#define MAX31785_MFR_FAN_LUT 0xF2 +#define MAX31785_MFR_READ_FAN_PWM 0xF3 +#define MAX31785_MFR_FAN_FAULT_LIMIT 0xF5 +#define MAX31785_MFR_FAN_WARN_LIMIT 0xF6 +#define MAX31785_MFR_FAN_RUN_TIME 0xF7 +#define MAX31785_MFR_FAN_PWM_AVG 0xF8 +#define MAX31785_MFR_FAN_PWM2RPM 0xF9 + +/* defaults as per the data sheet */ +#define MAX31785_DEFAULT_CAPABILITY 0x10 +#define MAX31785_DEFAULT_VOUT_MODE 0x40 +#define MAX31785_DEFAULT_VOUT_SCALE_MONITOR 0x7FFF +#define MAX31785_DEFAULT_FAN_COMMAND_1 0x7FFF +#define MAX31785_DEFAULT_OV_FAULT_LIMIT 0x7FFF +#define MAX31785_DEFAULT_OV_WARN_LIMIT 0x7FFF +#define MAX31785_DEFAULT_OT_FAULT_LIMIT 0x7FFF +#define MAX31785_DEFAULT_OT_WARN_LIMIT 0x7FFF +#define MAX31785_DEFAULT_PMBUS_REVISION 0x11 +#define MAX31785_DEFAULT_MFR_ID 0x4D +#define MAX31785_DEFAULT_MFR_MODEL 0x53 +#define MAX31785_DEFAULT_MFR_REVISION 0x3030 +#define MAX31785A_DEFAULT_MFR_REVISION 0x3040 +#define MAX31785B_DEFAULT_MFR_REVISION 0x3061 +#define MAX31785B_DEFAULT_MFR_TEMPERATURE_PEAK 0x8000 +#define MAX31785B_DEFAULT_MFR_VOUT_MIN 0x7FFF +#define MAX31785_DEFAULT_TEXT 0x3130313031303130 + +/* MAX31785 pages */ +#define MAX31785_TOTAL_NUM_PAGES 23 +#define MAX31785_FAN_PAGES 6 +#define MAX31785_MIN_FAN_PAGE 0 +#define MAX31785_MAX_FAN_PAGE 5 +#define MAX31785_MIN_TEMP_PAGE 6 +#define MAX31785_MAX_TEMP_PAGE 16 +#define MAX31785_MIN_ADC_VOLTAGE_PAGE 17 +#define MAX31785_MAX_ADC_VOLTAGE_PAGE 22 + +/* FAN_CONFIG_1_2 */ +#define MAX31785_MFR_FAN_CONFIG 0xF1 +#define MAX31785_FAN_CONFIG_ENABLE BIT(7) +#define MAX31785_FAN_CONFIG_RPM_PWM BIT(6) +#define MAX31785_FAN_CONFIG_PULSE(pulse) (pulse << 4) +#define MAX31785_DEFAULT_FAN_CONFIG_1_2(pulse) \ + (MAX31785_FAN_CONFIG_ENABLE | MAX31785_FAN_CONFIG_PULSE(pulse)) +#define MAX31785_DEFAULT_MFR_FAN_CONFIG 0x0000 + +/* fan speed in RPM */ +#define MAX31785_DEFAULT_FAN_SPEED 0x7fff +#define MAX31785_DEFAULT_FAN_STATUS 0x00 + +#define MAX31785_DEFAULT_FAN_MAX_PWM 0x2710 + +/* + * MAX31785State: + * @code: The command code received + * @page: Each page corresponds to a device monitored by the Max 31785 + * The page register determines the available commands depending on device + * _____________________________________________________________________________ + * | 0 | Fan Connected to PWM0 | + * |_______|___________________________________________________________________| + * | 1 | Fan Connected to PWM1 | + * |_______|___________________________________________________________________| + * | 2 | Fan Connected to PWM2 | + * |_______|___________________________________________________________________| + * | 3 | Fan Connected to PWM3 | + * |_______|___________________________________________________________________| + * | 4 | Fan Connected to PWM4 | + * |_______|___________________________________________________________________| + * | 5 | Fan Connected to PWM5 | + * |_______|___________________________________________________________________| + * | 6 | Remote Thermal Diode Connected to ADC 0 | + * |_______|___________________________________________________________________| + * | 7 | Remote Thermal Diode Connected to ADC 1 | + * |_______|___________________________________________________________________| + * | 8 | Remote Thermal Diode Connected to ADC 2 | + * |_______|___________________________________________________________________| + * | 9 | Remote Thermal Diode Connected to ADC 3 | + * |_______|___________________________________________________________________| + * | 10 | Remote Thermal Diode Connected to ADC 4 | + * |_______|___________________________________________________________________| + * | 11 | Remote Thermal Diode Connected to ADC 5 | + * |_______|___________________________________________________________________| + * | 12 | Internal Temperature Sensor | + * |_______|___________________________________________________________________| + * | 13 | Remote I2C Temperature Sensor with Address 0 | + * |_______|___________________________________________________________________| + * | 14 | Remote I2C Temperature Sensor with Address 1 | + * |_______|___________________________________________________________________| + * | 15 | Remote I2C Temperature Sensor with Address 2 | + * |_______|___________________________________________________________________| + * | 16 | Remote I2C Temperature Sensor with Address 3 | + * |_______|___________________________________________________________________| + * | 17 | Remote I2C Temperature Sensor with Address 4 | + * |_______|___________________________________________________________________| + * | 17 | Remote Voltage Connected to ADC0 | + * |_______|___________________________________________________________________| + * | 18 | Remote Voltage Connected to ADC1 | + * |_______|___________________________________________________________________| + * | 19 | Remote Voltage Connected to ADC2 | + * |_______|___________________________________________________________________| + * | 20 | Remote Voltage Connected to ADC3 | + * |_______|___________________________________________________________________| + * | 21 | Remote Voltage Connected to ADC4 | + * |_______|___________________________________________________________________| + * | 22 | Remote Voltage Connected to ADC5 | + * |_______|___________________________________________________________________| + * |23-254 | Reserved | + * |_______|___________________________________________________________________| + * | 255 | Applies to all pages | + * |_______|___________________________________________________________________| + */ + +/* Place holder to save the max31785 mfr specific registers */ +typedef struct MAX31785State { + PMBusDevice parent; + uint16_t mfr_mode[MAX31785_TOTAL_NUM_PAGES]; + uint16_t vout_peak[MAX31785_TOTAL_NUM_PAGES]; + uint16_t temperature_peak[MAX31785_TOTAL_NUM_PAGES]; + uint16_t vout_min[MAX31785_TOTAL_NUM_PAGES]; + uint8_t fault_response[MAX31785_TOTAL_NUM_PAGES]; + uint32_t time_count[MAX31785_TOTAL_NUM_PAGES]; + uint16_t temp_sensor_config[MAX31785_TOTAL_NUM_PAGES]; + uint16_t fan_config[MAX31785_TOTAL_NUM_PAGES]; + uint16_t read_fan_pwm[MAX31785_TOTAL_NUM_PAGES]; + uint16_t fan_fault_limit[MAX31785_TOTAL_NUM_PAGES]; + uint16_t fan_warn_limit[MAX31785_TOTAL_NUM_PAGES]; + uint16_t fan_run_time[MAX31785_TOTAL_NUM_PAGES]; + uint16_t fan_pwm_avg[MAX31785_TOTAL_NUM_PAGES]; + uint64_t fan_pwm2rpm[MAX31785_TOTAL_NUM_PAGES]; + uint64_t mfr_location; + uint64_t mfr_date; + uint64_t mfr_serial; + uint16_t mfr_revision; +} MAX31785State; + +static uint8_t max31785_read_byte(PMBusDevice *pmdev) +{ + MAX31785State *s = MAX31785(pmdev); + switch (pmdev->code) { + + case PMBUS_FAN_CONFIG_1_2: + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send8(pmdev, pmdev->pages[pmdev->page].fan_config_1_2); + } + break; + + case PMBUS_FAN_COMMAND_1: + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, pmdev->pages[pmdev->page].fan_command_1); + } + break; + + case PMBUS_READ_FAN_SPEED_1: + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, pmdev->pages[pmdev->page].read_fan_speed_1); + } + break; + + case PMBUS_STATUS_FANS_1_2: + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, pmdev->pages[pmdev->page].status_fans_1_2); + } + break; + + case PMBUS_MFR_REVISION: + pmbus_send16(pmdev, MAX31785_DEFAULT_MFR_REVISION); + break; + + case PMBUS_MFR_ID: + pmbus_send8(pmdev, 0x4d); /* Maxim */ + break; + + case PMBUS_MFR_MODEL: + pmbus_send8(pmdev, 0x53); + break; + + case PMBUS_MFR_LOCATION: + pmbus_send64(pmdev, s->mfr_location); + break; + + case PMBUS_MFR_DATE: + pmbus_send64(pmdev, s->mfr_date); + break; + + case PMBUS_MFR_SERIAL: + pmbus_send64(pmdev, s->mfr_serial); + break; + + case MAX31785_MFR_MODE: + pmbus_send16(pmdev, s->mfr_mode[pmdev->page]); + break; + + case MAX31785_MFR_VOUT_PEAK: + if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && + (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { + pmbus_send16(pmdev, s->vout_peak[pmdev->page]); + } + break; + + case MAX31785_MFR_TEMPERATURE_PEAK: + if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && + (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { + pmbus_send16(pmdev, s->temperature_peak[pmdev->page]); + } + break; + + case MAX31785_MFR_VOUT_MIN: + if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && + (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { + pmbus_send16(pmdev, s->vout_min[pmdev->page]); + } + break; + + case MAX31785_MFR_FAULT_RESPONSE: + pmbus_send8(pmdev, s->fault_response[pmdev->page]); + break; + + case MAX31785_MFR_TIME_COUNT: /* R/W 32 */ + pmbus_send32(pmdev, s->time_count[pmdev->page]); + break; + + case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */ + if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && + (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { + pmbus_send16(pmdev, s->temp_sensor_config[pmdev->page]); + } + break; + + case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, s->fan_config[pmdev->page]); + } + break; + + case MAX31785_MFR_READ_FAN_PWM: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, s->read_fan_pwm[pmdev->page]); + } + break; + + case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, s->fan_fault_limit[pmdev->page]); + } + break; + + case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, s->fan_warn_limit[pmdev->page]); + } + break; + + case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, s->fan_run_time[pmdev->page]); + } + break; + + case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send16(pmdev, s->fan_pwm_avg[pmdev->page]); + } + break; + + case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmbus_send64(pmdev, s->fan_pwm2rpm[pmdev->page]); + } + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: reading from unsupported register: 0x%02x\n", + __func__, pmdev->code); + break; + } + + return 0xFF; +} + +static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf, + uint8_t len) +{ + MAX31785State *s = MAX31785(pmdev); + if (len == 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); + return -1; + } + + pmdev->code = buf[0]; /* PMBus command code */ + + if (len == 1) { + return 0; + } + + /* Exclude command code from buffer */ + buf++; + len--; + + switch (pmdev->code) { + + case PMBUS_FAN_CONFIG_1_2: + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmdev->pages[pmdev->page].fan_config_1_2 = pmbus_receive8(pmdev); + } + break; + + case PMBUS_FAN_COMMAND_1: + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + pmdev->pages[pmdev->page].fan_command_1 = pmbus_receive16(pmdev); + pmdev->pages[pmdev->page].read_fan_speed_1 = + ((MAX31785_DEFAULT_FAN_SPEED / MAX31785_DEFAULT_FAN_MAX_PWM) * + pmdev->pages[pmdev->page].fan_command_1); + } + break; + + case PMBUS_MFR_LOCATION: /* R/W 64 */ + s->mfr_location = pmbus_receive64(pmdev); + break; + + case PMBUS_MFR_DATE: /* R/W 64 */ + s->mfr_date = pmbus_receive64(pmdev); + break; + + case PMBUS_MFR_SERIAL: /* R/W 64 */ + s->mfr_serial = pmbus_receive64(pmdev); + break; + + case MAX31785_MFR_MODE: /* R/W word */ + s->mfr_mode[pmdev->page] = pmbus_receive16(pmdev); + break; + + case MAX31785_MFR_VOUT_PEAK: /* R/W word */ + if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && + (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { + s->vout_peak[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_TEMPERATURE_PEAK: /* R/W word */ + if ((pmdev->page >= 6) && (pmdev->page <= 16)) { + s->temperature_peak[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_VOUT_MIN: /* R/W word */ + if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && + (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { + s->vout_min[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAULT_RESPONSE: /* R/W 8 */ + s->fault_response[pmdev->page] = pmbus_receive8(pmdev); + break; + + case MAX31785_MFR_TIME_COUNT: /* R/W 32 */ + s->time_count[pmdev->page] = pmbus_receive32(pmdev); + break; + + case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */ + if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && + (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { + s->temp_sensor_config[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + s->fan_config[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + s->fan_fault_limit[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + s->fan_warn_limit[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + s->fan_run_time[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + s->fan_pwm_avg[pmdev->page] = pmbus_receive16(pmdev); + } + break; + + case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */ + if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { + s->fan_pwm2rpm[pmdev->page] = pmbus_receive64(pmdev); + } + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: writing to unsupported register: 0x%02x\n", + __func__, pmdev->code); + break; + } + + return 0; +} + +static void max31785_exit_reset(Object *obj) +{ + PMBusDevice *pmdev = PMBUS_DEVICE(obj); + MAX31785State *s = MAX31785(obj); + + pmdev->capability = MAX31785_DEFAULT_CAPABILITY; + + for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) { + pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; + pmdev->pages[i].fan_command_1 = MAX31785_DEFAULT_FAN_COMMAND_1; + pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; + pmdev->pages[i].fan_config_1_2 = MAX31785_DEFAULT_FAN_CONFIG_1_2(0); + pmdev->pages[i].read_fan_speed_1 = MAX31785_DEFAULT_FAN_SPEED; + pmdev->pages[i].status_fans_1_2 = MAX31785_DEFAULT_FAN_STATUS; + } + + for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) { + pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; + pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; + pmdev->pages[i].ot_fault_limit = MAX31785_DEFAULT_OT_FAULT_LIMIT; + pmdev->pages[i].ot_warn_limit = MAX31785_DEFAULT_OT_WARN_LIMIT; + } + + for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE; + i <= MAX31785_MAX_ADC_VOLTAGE_PAGE; + i++) { + pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; + pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; + pmdev->pages[i].vout_scale_monitor = + MAX31785_DEFAULT_VOUT_SCALE_MONITOR; + pmdev->pages[i].vout_ov_fault_limit = MAX31785_DEFAULT_OV_FAULT_LIMIT; + pmdev->pages[i].vout_ov_warn_limit = MAX31785_DEFAULT_OV_WARN_LIMIT; + } + + s->mfr_location = MAX31785_DEFAULT_TEXT; + s->mfr_date = MAX31785_DEFAULT_TEXT; + s->mfr_serial = MAX31785_DEFAULT_TEXT; +} + +static const VMStateDescription vmstate_max31785 = { + .name = TYPE_MAX31785, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]){ + VMSTATE_PMBUS_DEVICE(parent, MAX31785State), + VMSTATE_UINT16_ARRAY(mfr_mode, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(vout_peak, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(temperature_peak, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(vout_min, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT8_ARRAY(fault_response, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT32_ARRAY(time_count, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(fan_config, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(read_fan_pwm, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(fan_fault_limit, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(fan_warn_limit, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(fan_run_time, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT16_ARRAY(fan_pwm_avg, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT64_ARRAY(fan_pwm2rpm, MAX31785State, + MAX31785_TOTAL_NUM_PAGES), + VMSTATE_UINT64(mfr_location, MAX31785State), + VMSTATE_UINT64(mfr_date, MAX31785State), + VMSTATE_UINT64(mfr_serial, MAX31785State), + VMSTATE_END_OF_LIST() + } +}; + +static void max31785_init(Object *obj) +{ + PMBusDevice *pmdev = PMBUS_DEVICE(obj); + + for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) { + pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE); + } + + for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) { + pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_TEMPERATURE); + } + + for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE; + i <= MAX31785_MAX_ADC_VOLTAGE_PAGE; + i++) { + pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_VOUT | + PB_HAS_VOUT_RATING); + } +} + +static void max31785_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass); + dc->desc = "Maxim MAX31785 6-Channel Fan Controller"; + dc->vmsd = &vmstate_max31785; + k->write_data = max31785_write_data; + k->receive_byte = max31785_read_byte; + k->device_num_pages = MAX31785_TOTAL_NUM_PAGES; + rc->phases.exit = max31785_exit_reset; +} + +static const TypeInfo max31785_info = { + .name = TYPE_MAX31785, + .parent = TYPE_PMBUS_DEVICE, + .instance_size = sizeof(MAX31785State), + .instance_init = max31785_init, + .class_init = max31785_class_init, +}; + +static void max31785_register_types(void) +{ + type_register_static(&max31785_info); +} + +type_init(max31785_register_types) diff --git a/hw/sensor/meson.build b/hw/sensor/meson.build index 12b6992bc845..9e9be602c349 100644 --- a/hw/sensor/meson.build +++ b/hw/sensor/meson.build @@ -6,3 +6,4 @@ softmmu_ss.add(when: 'CONFIG_ADM1272', if_true: files('adm1272.c')) softmmu_ss.add(when: 'CONFIG_MAX34451', if_true: files('max34451.c')) softmmu_ss.add(when: 'CONFIG_LSM303DLHC_MAG', if_true: files('lsm303dlhc_mag.c')) softmmu_ss.add(when: 'CONFIG_ISL_PMBUS_VR', if_true: files('isl_pmbus_vr.c')) +softmmu_ss.add(when: 'CONFIG_MAX31785', if_true: files('max31785.c')) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 60349ee40271..4869566cf5df 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -28,6 +28,7 @@ #include "hw/loader.h" #include "hw/boards.h" #include "hw/pci/pci_bus.h" +#include "hw/pci/pci_device.h" #include "smbios_build.h" /* legacy structures and constants for <= 2.0 machines */ @@ -111,6 +112,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 +345,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", @@ -681,8 +712,14 @@ static void smbios_build_type_3_table(void) static void smbios_build_type_4_table(MachineState *ms, unsigned instance) { char sock_str[128]; + size_t tbl_len = SMBIOS_TYPE_4_LEN_V28; + + if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_64) { + tbl_len = SMBIOS_TYPE_4_LEN_V30; + } - SMBIOS_BUILD_TABLE_PRE(4, T4_BASE + instance, true); /* required */ + SMBIOS_BUILD_TABLE_PRE_SIZE(4, T4_BASE + instance, + true, tbl_len); /* required */ snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); @@ -709,8 +746,15 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial); SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset); SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part); - t->core_count = t->core_enabled = ms->smp.cores; - t->thread_count = ms->smp.threads; + + t->core_count = (ms->smp.cores > 255) ? 0xFF : ms->smp.cores; + t->core_enabled = t->core_count; + + t->core_count2 = t->core_enabled2 = cpu_to_le16(ms->smp.cores); + + t->thread_count = (ms->smp.threads > 255) ? 0xFF : ms->smp.threads; + t->thread_count2 = cpu_to_le16(ms->smp.threads); + t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ t->processor_family2 = cpu_to_le16(0x01); /* Other */ @@ -718,6 +762,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 +1094,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 +1270,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 +1413,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/smbios/smbios_build.h b/hw/smbios/smbios_build.h index 56b5a1e3f301..351660024e6e 100644 --- a/hw/smbios/smbios_build.h +++ b/hw/smbios/smbios_build.h @@ -27,6 +27,11 @@ extern unsigned smbios_table_max; extern unsigned smbios_table_cnt; #define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \ + SMBIOS_BUILD_TABLE_PRE_SIZE(tbl_type, tbl_handle, tbl_required, \ + sizeof(struct smbios_type_##tbl_type))\ + +#define SMBIOS_BUILD_TABLE_PRE_SIZE(tbl_type, tbl_handle, \ + tbl_required, tbl_len) \ struct smbios_type_##tbl_type *t; \ size_t t_off; /* table offset into smbios_tables */ \ int str_index = 0; \ @@ -39,12 +44,12 @@ extern unsigned smbios_table_cnt; /* use offset of table t within smbios_tables */ \ /* (pointer must be updated after each realloc) */ \ t_off = smbios_tables_len; \ - smbios_tables_len += sizeof(*t); \ + smbios_tables_len += tbl_len; \ smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \ t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ \ t->header.type = tbl_type; \ - t->header.length = sizeof(*t); \ + t->header.length = tbl_len; \ t->header.handle = cpu_to_le16(tbl_handle); \ } while (0) diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index a9f24968275d..1e39d2e2d0ac 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -26,7 +26,6 @@ #include "qemu/units.h" #include "qemu/error-report.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #include "hw/irq.h" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 7f3a7c002780..d9288326d6ac 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -26,7 +26,6 @@ #include "qemu/units.h" #include "qapi/error.h" #include "qemu/datadir.h" -#include "qemu-common.h" #include "cpu.h" #include "hw/sysbus.h" #include "qemu/error-report.h" @@ -832,8 +831,7 @@ static void sun4m_hw_init(MachineState *machine) SysBusDevice *s; unsigned int smp_cpus = machine->smp.cpus; unsigned int max_cpus = machine->smp.max_cpus; - Object *ram_memdev = object_resolve_path_type(machine->ram_memdev_id, - TYPE_MEMORY_BACKEND, NULL); + HostMemoryBackend *ram_memdev = machine->memdev; NICInfo *nd = &nd_table[0]; if (machine->ram_size > hwdef->max_mem) { @@ -853,7 +851,7 @@ static void sun4m_hw_init(MachineState *machine) /* Create and map RAM frontend */ dev = qdev_new("memory"); - object_property_set_link(OBJECT(dev), "memdev", ram_memdev, &error_fatal); + object_property_set_link(OBJECT(dev), "memdev", OBJECT(ram_memdev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0); @@ -921,6 +919,7 @@ static void sun4m_hw_init(MachineState *machine) /* sbus irq 5 */ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, graphic_width, graphic_height, graphic_depth); + vga_interface_created = true; } else { /* If no display specified, default to TCX */ if (graphic_depth != 8 && graphic_depth != 24) { @@ -936,6 +935,7 @@ static void sun4m_hw_init(MachineState *machine) tcx_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, graphic_width, graphic_height, graphic_depth); + vga_interface_created = true; } } @@ -1049,7 +1049,7 @@ static void sun4m_hw_init(MachineState *machine) machine->ram_size, &initrd_size); nvram_init(nvram, (uint8_t *)&nd->macaddr, machine->kernel_cmdline, - machine->boot_order, machine->ram_size, kernel_size, + machine->boot_config.order, machine->ram_size, kernel_size, graphic_width, graphic_height, graphic_depth, hwdef->nvram_machine_id, "Sun4m"); @@ -1090,7 +1090,7 @@ static void sun4m_hw_init(MachineState *machine) } fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_config.order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index cda7df36e312..387181ff7762 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -26,7 +26,6 @@ #include "qemu/units.h" #include "qemu/error-report.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #include "hw/pci/pci.h" @@ -67,7 +66,6 @@ #define PBM_PCI_IO_BASE (PBM_SPECIAL_BASE + 0x02000000ULL) #define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 -#define MAX_IDE_BUS 2 #define BIOS_CFG_IOPORT 0x510 #define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) @@ -335,7 +333,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) parallel_hds_isa_init(s->isa_bus, MAX_PARALLEL_PORTS); /* Keyboard */ - isa_create_simple(s->isa_bus, "i8042"); + isa_create_simple(s->isa_bus, TYPE_I8042); /* Floppy */ for (i = 0; i < MAX_FD; i++) { @@ -633,6 +631,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, switch (vga_interface_type) { case VGA_STD: pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA"); + vga_interface_created = true; break; case VGA_NONE: break; @@ -695,7 +694,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, &kernel_addr, &kernel_entry); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size, - machine->boot_order, + machine->boot_config.order, kernel_addr, kernel_size, machine->kernel_cmdline, initrd_addr, initrd_size, @@ -727,7 +726,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_config.order[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height); diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index 9178277f8246..1c1dca712e32 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -165,7 +165,7 @@ static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu, } if (tte & IOMMU_TTE_DATA_W) { - /* Writeable */ + /* Writable */ ret.perm = IOMMU_RW; } else { ret.perm = IOMMU_RO; diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 7d90a02181ee..7ed55ea36288 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -20,3 +20,7 @@ config XILINX_SPIPS config STM32F2XX_SPI bool select SSI + +config RT_FLEXSPI + bool + select SSI diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 48305e1574ec..22df4be528a7 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -388,7 +388,7 @@ static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl) static inline int aspeed_smc_flash_addr_width(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; - AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + AspeedSMCClass *asc = fl->asc; if (asc->addr_width) { return asc->addr_width(s); @@ -420,7 +420,7 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl, uint32_t addr) { const AspeedSMCState *s = fl->controller; - AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + AspeedSMCClass *asc = fl->asc; AspeedSegments seg; asc->reg_to_segment(s, s->regs[R_SEG_ADDR0 + fl->cs], &seg); @@ -488,7 +488,7 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) switch (aspeed_smc_flash_mode(fl)) { case CTRL_USERMODE: for (i = 0; i < size; i++) { - ret |= ssi_transfer(s->spi, 0x0) << (8 * i); + ret |= (uint64_t) ssi_transfer(s->spi, 0x0) << (8 * i); } break; case CTRL_READMODE: @@ -497,7 +497,7 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) aspeed_smc_flash_setup(fl, addr); for (i = 0; i < size; i++) { - ret |= ssi_transfer(s->spi, 0x0) << (8 * i); + ret |= (uint64_t) ssi_transfer(s->spi, 0x0) << (8 * i); } aspeed_smc_flash_unselect(fl); @@ -1234,7 +1234,6 @@ static const TypeInfo aspeed_smc_info = { static void aspeed_smc_flash_realize(DeviceState *dev, Error **errp) { AspeedSMCFlash *s = ASPEED_SMC_FLASH(dev); - AspeedSMCClass *asc; g_autofree char *name = g_strdup_printf(TYPE_ASPEED_SMC_FLASH ".%d", s->cs); if (!s->controller) { @@ -1242,14 +1241,14 @@ static void aspeed_smc_flash_realize(DeviceState *dev, Error **errp) return; } - asc = ASPEED_SMC_GET_CLASS(s->controller); + s->asc = ASPEED_SMC_GET_CLASS(s->controller); /* * Use the default segment value to size the memory region. This * can be changed by FW at runtime. */ memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_flash_ops, - s, name, asc->segments[s->cs].size); + s, name, s->asc->segments[s->cs].size); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); } @@ -1696,6 +1695,160 @@ static const TypeInfo aspeed_2600_spi2_info = { .class_init = aspeed_2600_spi2_class_init, }; +/* + * The FMC Segment Registers of the AST1030 have a 512KB unit. + * Only bits [27:19] are used for decoding. + */ +#define AST1030_SEG_ADDR_MASK 0x0ff80000 + +static uint32_t aspeed_1030_smc_segment_to_reg(const AspeedSMCState *s, + const AspeedSegments *seg) +{ + uint32_t reg = 0; + + /* Disabled segments have a nil register */ + if (!seg->size) { + return 0; + } + + reg |= (seg->addr & AST1030_SEG_ADDR_MASK) >> 16; /* start offset */ + reg |= (seg->addr + seg->size - 1) & AST1030_SEG_ADDR_MASK; /* end offset */ + return reg; +} + +static void aspeed_1030_smc_reg_to_segment(const AspeedSMCState *s, + uint32_t reg, AspeedSegments *seg) +{ + uint32_t start_offset = (reg << 16) & AST1030_SEG_ADDR_MASK; + uint32_t end_offset = reg & AST1030_SEG_ADDR_MASK; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + + if (reg) { + seg->addr = asc->flash_window_base + start_offset; + seg->size = end_offset + (512 * KiB) - start_offset; + } else { + seg->addr = asc->flash_window_base; + seg->size = 0; + } +} + +static const uint32_t aspeed_1030_fmc_resets[ASPEED_SMC_R_MAX] = { + [R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 | + CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1), +}; + +static const AspeedSegments aspeed_1030_fmc_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 1030 FMC Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 2; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->cs_num_max = 2; + asc->segments = aspeed_1030_fmc_segments; + asc->segment_addr_mask = 0x0ff80ff8; + asc->resets = aspeed_1030_fmc_resets; + asc->flash_window_base = 0x80000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x000BFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_1030_smc_segment_to_reg; + asc->reg_to_segment = aspeed_1030_smc_reg_to_segment; + asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; +} + +static const TypeInfo aspeed_1030_fmc_info = { + .name = "aspeed.fmc-ast1030", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_1030_fmc_class_init, +}; + +static const AspeedSegments aspeed_1030_spi1_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 1030 SPI1 Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 2; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->cs_num_max = 2; + asc->segments = aspeed_1030_spi1_segments; + asc->segment_addr_mask = 0x0ff00ff0; + asc->flash_window_base = 0x90000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x000BFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; + asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; + asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; +} + +static const TypeInfo aspeed_1030_spi1_info = { + .name = "aspeed.spi1-ast1030", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_1030_spi1_class_init, +}; +static const AspeedSegments aspeed_1030_spi2_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 1030 SPI2 Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 2; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->cs_num_max = 2; + asc->segments = aspeed_1030_spi2_segments; + asc->segment_addr_mask = 0x0ff00ff0; + asc->flash_window_base = 0xb0000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x000BFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; + asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; + asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; +} + +static const TypeInfo aspeed_1030_spi2_info = { + .name = "aspeed.spi2-ast1030", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_1030_spi2_class_init, +}; + static void aspeed_smc_register_types(void) { type_register_static(&aspeed_smc_flash_info); @@ -1709,6 +1862,9 @@ static void aspeed_smc_register_types(void) type_register_static(&aspeed_2600_fmc_info); type_register_static(&aspeed_2600_spi1_info); type_register_static(&aspeed_2600_spi2_info); + type_register_static(&aspeed_1030_fmc_info); + type_register_static(&aspeed_1030_spi1_info); + type_register_static(&aspeed_1030_spi2_info); } type_init(aspeed_smc_register_types) diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c new file mode 100644 index 000000000000..57df462e3ca6 --- /dev/null +++ b/hw/ssi/ibex_spi_host.c @@ -0,0 +1,646 @@ +/* + * QEMU model of the Ibex SPI Controller + * SPEC Reference: https://docs.opentitan.org/hw/ip/spi_host/doc/ + * + * Copyright (C) 2022 Western Digital + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/ssi/ibex_spi_host.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" +#include "trace.h" + +REG32(INTR_STATE, 0x00) + FIELD(INTR_STATE, ERROR, 0, 1) + FIELD(INTR_STATE, SPI_EVENT, 1, 1) +REG32(INTR_ENABLE, 0x04) + FIELD(INTR_ENABLE, ERROR, 0, 1) + FIELD(INTR_ENABLE, SPI_EVENT, 1, 1) +REG32(INTR_TEST, 0x08) + FIELD(INTR_TEST, ERROR, 0, 1) + FIELD(INTR_TEST, SPI_EVENT, 1, 1) +REG32(ALERT_TEST, 0x0c) + FIELD(ALERT_TEST, FETAL_TEST, 0, 1) +REG32(CONTROL, 0x10) + FIELD(CONTROL, RX_WATERMARK, 0, 8) + FIELD(CONTROL, TX_WATERMARK, 1, 8) + FIELD(CONTROL, OUTPUT_EN, 29, 1) + FIELD(CONTROL, SW_RST, 30, 1) + FIELD(CONTROL, SPIEN, 31, 1) +REG32(STATUS, 0x14) + FIELD(STATUS, TXQD, 0, 8) + FIELD(STATUS, RXQD, 18, 8) + FIELD(STATUS, CMDQD, 16, 3) + FIELD(STATUS, RXWM, 20, 1) + FIELD(STATUS, BYTEORDER, 22, 1) + FIELD(STATUS, RXSTALL, 23, 1) + FIELD(STATUS, RXEMPTY, 24, 1) + FIELD(STATUS, RXFULL, 25, 1) + FIELD(STATUS, TXWM, 26, 1) + FIELD(STATUS, TXSTALL, 27, 1) + FIELD(STATUS, TXEMPTY, 28, 1) + FIELD(STATUS, TXFULL, 29, 1) + FIELD(STATUS, ACTIVE, 30, 1) + FIELD(STATUS, READY, 31, 1) +REG32(CONFIGOPTS, 0x18) + FIELD(CONFIGOPTS, CLKDIV_0, 0, 16) + FIELD(CONFIGOPTS, CSNIDLE_0, 16, 4) + FIELD(CONFIGOPTS, CSNTRAIL_0, 20, 4) + FIELD(CONFIGOPTS, CSNLEAD_0, 24, 4) + FIELD(CONFIGOPTS, FULLCYC_0, 29, 1) + FIELD(CONFIGOPTS, CPHA_0, 30, 1) + FIELD(CONFIGOPTS, CPOL_0, 31, 1) +REG32(CSID, 0x1c) + FIELD(CSID, CSID, 0, 32) +REG32(COMMAND, 0x20) + FIELD(COMMAND, LEN, 0, 8) + FIELD(COMMAND, CSAAT, 9, 1) + FIELD(COMMAND, SPEED, 10, 2) + FIELD(COMMAND, DIRECTION, 12, 2) +REG32(ERROR_ENABLE, 0x2c) + FIELD(ERROR_ENABLE, CMDBUSY, 0, 1) + FIELD(ERROR_ENABLE, OVERFLOW, 1, 1) + FIELD(ERROR_ENABLE, UNDERFLOW, 2, 1) + FIELD(ERROR_ENABLE, CMDINVAL, 3, 1) + FIELD(ERROR_ENABLE, CSIDINVAL, 4, 1) +REG32(ERROR_STATUS, 0x30) + FIELD(ERROR_STATUS, CMDBUSY, 0, 1) + FIELD(ERROR_STATUS, OVERFLOW, 1, 1) + FIELD(ERROR_STATUS, UNDERFLOW, 2, 1) + FIELD(ERROR_STATUS, CMDINVAL, 3, 1) + FIELD(ERROR_STATUS, CSIDINVAL, 4, 1) + FIELD(ERROR_STATUS, ACCESSINVAL, 5, 1) +REG32(EVENT_ENABLE, 0x34) + FIELD(EVENT_ENABLE, RXFULL, 0, 1) + FIELD(EVENT_ENABLE, TXEMPTY, 1, 1) + FIELD(EVENT_ENABLE, RXWM, 2, 1) + FIELD(EVENT_ENABLE, TXWM, 3, 1) + FIELD(EVENT_ENABLE, READY, 4, 1) + FIELD(EVENT_ENABLE, IDLE, 5, 1) + +static inline uint8_t div4_round_up(uint8_t dividend) +{ + return (dividend + 3) / 4; +} + +static void ibex_spi_rxfifo_reset(IbexSPIHostState *s) +{ + uint32_t data = s->regs[IBEX_SPI_HOST_STATUS]; + /* Empty the RX FIFO and assert RXEMPTY */ + fifo8_reset(&s->rx_fifo); + data = FIELD_DP32(data, STATUS, RXFULL, 0); + data = FIELD_DP32(data, STATUS, RXEMPTY, 1); + s->regs[IBEX_SPI_HOST_STATUS] = data; +} + +static void ibex_spi_txfifo_reset(IbexSPIHostState *s) +{ + uint32_t data = s->regs[IBEX_SPI_HOST_STATUS]; + /* Empty the TX FIFO and assert TXEMPTY */ + fifo8_reset(&s->tx_fifo); + data = FIELD_DP32(data, STATUS, TXFULL, 0); + data = FIELD_DP32(data, STATUS, TXEMPTY, 1); + s->regs[IBEX_SPI_HOST_STATUS] = data; +} + +static void ibex_spi_host_reset(DeviceState *dev) +{ + IbexSPIHostState *s = IBEX_SPI_HOST(dev); + trace_ibex_spi_host_reset("Resetting Ibex SPI"); + + /* SPI Host Register Reset */ + s->regs[IBEX_SPI_HOST_INTR_STATE] = 0x00; + s->regs[IBEX_SPI_HOST_INTR_ENABLE] = 0x00; + s->regs[IBEX_SPI_HOST_INTR_TEST] = 0x00; + s->regs[IBEX_SPI_HOST_ALERT_TEST] = 0x00; + s->regs[IBEX_SPI_HOST_CONTROL] = 0x7f; + s->regs[IBEX_SPI_HOST_STATUS] = 0x00; + s->regs[IBEX_SPI_HOST_CONFIGOPTS] = 0x00; + s->regs[IBEX_SPI_HOST_CSID] = 0x00; + s->regs[IBEX_SPI_HOST_COMMAND] = 0x00; + /* RX/TX Modelled by FIFO */ + s->regs[IBEX_SPI_HOST_RXDATA] = 0x00; + s->regs[IBEX_SPI_HOST_TXDATA] = 0x00; + + s->regs[IBEX_SPI_HOST_ERROR_ENABLE] = 0x1F; + s->regs[IBEX_SPI_HOST_ERROR_STATUS] = 0x00; + s->regs[IBEX_SPI_HOST_EVENT_ENABLE] = 0x00; + + ibex_spi_rxfifo_reset(s); + ibex_spi_txfifo_reset(s); + + s->init_status = true; + return; +} + +/* + * Check if we need to trigger an interrupt. + * The two interrupts lines (host_err and event) can + * be enabled separately in 'IBEX_SPI_HOST_INTR_ENABLE'. + * + * Interrupts are triggered based on the ones + * enabled in the `IBEX_SPI_HOST_EVENT_ENABLE` and `IBEX_SPI_HOST_ERROR_ENABLE`. + */ +static void ibex_spi_host_irq(IbexSPIHostState *s) +{ + uint32_t intr_test_reg = s->regs[IBEX_SPI_HOST_INTR_TEST]; + uint32_t intr_en_reg = s->regs[IBEX_SPI_HOST_INTR_ENABLE]; + uint32_t intr_state_reg = s->regs[IBEX_SPI_HOST_INTR_STATE]; + + uint32_t err_en_reg = s->regs[IBEX_SPI_HOST_ERROR_ENABLE]; + uint32_t event_en_reg = s->regs[IBEX_SPI_HOST_EVENT_ENABLE]; + uint32_t err_status_reg = s->regs[IBEX_SPI_HOST_ERROR_STATUS]; + uint32_t status_reg = s->regs[IBEX_SPI_HOST_STATUS]; + + + bool error_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, ERROR); + bool event_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, SPI_EVENT); + bool err_pending = FIELD_EX32(intr_state_reg, INTR_STATE, ERROR); + bool status_pending = FIELD_EX32(intr_state_reg, INTR_STATE, SPI_EVENT); + + int err_irq = 0, event_irq = 0; + + /* Error IRQ enabled and Error IRQ Cleared */ + if (error_en && !err_pending) { + /* Event enabled, Interrupt Test Error */ + if (FIELD_EX32(intr_test_reg, INTR_TEST, ERROR)) { + err_irq = 1; + } else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CMDBUSY) && + FIELD_EX32(err_status_reg, ERROR_STATUS, CMDBUSY)) { + /* Wrote to COMMAND when not READY */ + err_irq = 1; + } else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CMDINVAL) && + FIELD_EX32(err_status_reg, ERROR_STATUS, CMDINVAL)) { + /* Invalid command segment */ + err_irq = 1; + } else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CSIDINVAL) && + FIELD_EX32(err_status_reg, ERROR_STATUS, CSIDINVAL)) { + /* Invalid value for CSID */ + err_irq = 1; + } + if (err_irq) { + s->regs[IBEX_SPI_HOST_INTR_STATE] |= R_INTR_STATE_ERROR_MASK; + } + qemu_set_irq(s->host_err, err_irq); + } + + /* Event IRQ Enabled and Event IRQ Cleared */ + if (event_en && !status_pending) { + if (FIELD_EX32(intr_test_reg, INTR_STATE, SPI_EVENT)) { + /* Event enabled, Interrupt Test Event */ + event_irq = 1; + } else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, READY) && + FIELD_EX32(status_reg, STATUS, READY)) { + /* SPI Host ready for next command */ + event_irq = 1; + } else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, TXEMPTY) && + FIELD_EX32(status_reg, STATUS, TXEMPTY)) { + /* SPI TXEMPTY, TXFIFO drained */ + event_irq = 1; + } else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, RXFULL) && + FIELD_EX32(status_reg, STATUS, RXFULL)) { + /* SPI RXFULL, RXFIFO full */ + event_irq = 1; + } + if (event_irq) { + s->regs[IBEX_SPI_HOST_INTR_STATE] |= R_INTR_STATE_SPI_EVENT_MASK; + } + qemu_set_irq(s->event, event_irq); + } +} + +static void ibex_spi_host_transfer(IbexSPIHostState *s) +{ + uint32_t rx, tx, data; + /* Get num of one byte transfers */ + uint8_t segment_len = FIELD_EX32(s->regs[IBEX_SPI_HOST_COMMAND], + COMMAND, LEN); + + while (segment_len > 0) { + if (fifo8_is_empty(&s->tx_fifo)) { + /* Assert Stall */ + s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXSTALL_MASK; + break; + } else if (fifo8_is_full(&s->rx_fifo)) { + /* Assert Stall */ + s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXSTALL_MASK; + break; + } else { + tx = fifo8_pop(&s->tx_fifo); + } + + rx = ssi_transfer(s->ssi, tx); + + trace_ibex_spi_host_transfer(tx, rx); + + if (!fifo8_is_full(&s->rx_fifo)) { + fifo8_push(&s->rx_fifo, rx); + } else { + /* Assert RXFULL */ + s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXFULL_MASK; + } + --segment_len; + } + + data = s->regs[IBEX_SPI_HOST_STATUS]; + /* Assert Ready */ + data = FIELD_DP32(data, STATUS, READY, 1); + /* Set RXQD */ + data = FIELD_DP32(data, STATUS, RXQD, div4_round_up(segment_len)); + /* Set TXQD */ + data = FIELD_DP32(data, STATUS, TXQD, fifo8_num_used(&s->tx_fifo) / 4); + /* Clear TXFULL */ + data = FIELD_DP32(data, STATUS, TXFULL, 0); + /* Reset RXEMPTY */ + data = FIELD_DP32(data, STATUS, RXEMPTY, 0); + /* Update register status */ + s->regs[IBEX_SPI_HOST_STATUS] = data; + /* Drop remaining bytes that exceed segment_len */ + ibex_spi_txfifo_reset(s); + + ibex_spi_host_irq(s); +} + +static uint64_t ibex_spi_host_read(void *opaque, hwaddr addr, + unsigned int size) +{ + IbexSPIHostState *s = opaque; + uint32_t rc = 0; + uint8_t rx_byte = 0; + + trace_ibex_spi_host_read(addr, size); + + /* Match reg index */ + addr = addr >> 2; + switch (addr) { + /* Skipping any W/O registers */ + case IBEX_SPI_HOST_INTR_STATE...IBEX_SPI_HOST_INTR_ENABLE: + case IBEX_SPI_HOST_CONTROL...IBEX_SPI_HOST_STATUS: + rc = s->regs[addr]; + break; + case IBEX_SPI_HOST_CSID: + rc = s->regs[addr]; + break; + case IBEX_SPI_HOST_CONFIGOPTS: + rc = s->config_opts[s->regs[IBEX_SPI_HOST_CSID]]; + break; + case IBEX_SPI_HOST_TXDATA: + rc = s->regs[addr]; + break; + case IBEX_SPI_HOST_RXDATA: + /* Clear RXFULL */ + s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXFULL_MASK; + + for (int i = 0; i < 4; ++i) { + if (fifo8_is_empty(&s->rx_fifo)) { + /* Assert RXEMPTY, no IRQ */ + s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXEMPTY_MASK; + s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= + R_ERROR_STATUS_UNDERFLOW_MASK; + return rc; + } + rx_byte = fifo8_pop(&s->rx_fifo); + rc |= rx_byte << (i * 8); + } + break; + case IBEX_SPI_HOST_ERROR_ENABLE...IBEX_SPI_HOST_EVENT_ENABLE: + rc = s->regs[addr]; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "Bad offset 0x%" HWADDR_PRIx "\n", + addr << 2); + } + return rc; +} + + +static void ibex_spi_host_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + IbexSPIHostState *s = opaque; + uint32_t val32 = val64; + uint32_t shift_mask = 0xff, status = 0, data = 0; + uint8_t txqd_len; + + trace_ibex_spi_host_write(addr, size, val64); + + /* Match reg index */ + addr = addr >> 2; + + switch (addr) { + /* Skipping any R/O registers */ + case IBEX_SPI_HOST_INTR_STATE: + /* rw1c status register */ + if (FIELD_EX32(val32, INTR_STATE, ERROR)) { + data = FIELD_DP32(data, INTR_STATE, ERROR, 0); + } + if (FIELD_EX32(val32, INTR_STATE, SPI_EVENT)) { + data = FIELD_DP32(data, INTR_STATE, SPI_EVENT, 0); + } + s->regs[addr] = data; + break; + case IBEX_SPI_HOST_INTR_ENABLE: + s->regs[addr] = val32; + break; + case IBEX_SPI_HOST_INTR_TEST: + s->regs[addr] = val32; + ibex_spi_host_irq(s); + break; + case IBEX_SPI_HOST_ALERT_TEST: + s->regs[addr] = val32; + qemu_log_mask(LOG_UNIMP, + "%s: SPI_ALERT_TEST is not supported\n", __func__); + break; + case IBEX_SPI_HOST_CONTROL: + s->regs[addr] = val32; + + if (val32 & R_CONTROL_SW_RST_MASK) { + ibex_spi_host_reset((DeviceState *)s); + /* Clear active if any */ + s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_ACTIVE_MASK; + } + + if (val32 & R_CONTROL_OUTPUT_EN_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: CONTROL_OUTPUT_EN is not supported\n", __func__); + } + break; + case IBEX_SPI_HOST_CONFIGOPTS: + /* Update the respective config-opts register based on CSIDth index */ + s->config_opts[s->regs[IBEX_SPI_HOST_CSID]] = val32; + qemu_log_mask(LOG_UNIMP, + "%s: CONFIGOPTS Hardware settings not supported\n", + __func__); + break; + case IBEX_SPI_HOST_CSID: + if (val32 >= s->num_cs) { + /* CSID exceeds max num_cs */ + s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= + R_ERROR_STATUS_CSIDINVAL_MASK; + ibex_spi_host_irq(s); + return; + } + s->regs[addr] = val32; + break; + case IBEX_SPI_HOST_COMMAND: + s->regs[addr] = val32; + + /* STALL, IP not enabled */ + if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_CONTROL], + CONTROL, SPIEN))) { + return; + } + + /* SPI not ready, IRQ Error */ + if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_STATUS], + STATUS, READY))) { + s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= R_ERROR_STATUS_CMDBUSY_MASK; + ibex_spi_host_irq(s); + return; + } + + /* Assert Not Ready */ + s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_READY_MASK; + + if (FIELD_EX32(val32, COMMAND, DIRECTION) != BIDIRECTIONAL_TRANSFER) { + qemu_log_mask(LOG_UNIMP, + "%s: Rx Only/Tx Only are not supported\n", __func__); + } + + if (val32 & R_COMMAND_CSAAT_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: CSAAT is not supported\n", __func__); + } + if (val32 & R_COMMAND_SPEED_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: SPEED is not supported\n", __func__); + } + + /* Set Transfer Callback */ + timer_mod(s->fifo_trigger_handle, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (TX_INTERRUPT_TRIGGER_DELAY_NS)); + + break; + case IBEX_SPI_HOST_TXDATA: + /* + * This is a hardware `feature` where + * the first word written to TXDATA after init is omitted entirely + */ + if (s->init_status) { + s->init_status = false; + return; + } + + for (int i = 0; i < 4; ++i) { + /* Attempting to write when TXFULL */ + if (fifo8_is_full(&s->tx_fifo)) { + /* Assert RXEMPTY, no IRQ */ + s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXFULL_MASK; + s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= + R_ERROR_STATUS_OVERFLOW_MASK; + ibex_spi_host_irq(s); + return; + } + /* Byte ordering is set by the IP */ + status = s->regs[IBEX_SPI_HOST_STATUS]; + if (FIELD_EX32(status, STATUS, BYTEORDER) == 0) { + /* LE: LSB transmitted first (default for ibex processor) */ + shift_mask = 0xff << (i * 8); + } else { + /* BE: MSB transmitted first */ + qemu_log_mask(LOG_UNIMP, + "%s: Big endian is not supported\n", __func__); + } + + fifo8_push(&s->tx_fifo, (val32 & shift_mask) >> (i * 8)); + } + status = s->regs[IBEX_SPI_HOST_STATUS]; + /* Reset TXEMPTY */ + status = FIELD_DP32(status, STATUS, TXEMPTY, 0); + /* Update TXQD */ + txqd_len = FIELD_EX32(status, STATUS, TXQD); + /* Partial bytes (size < 4) are padded, in words. */ + txqd_len += 1; + status = FIELD_DP32(status, STATUS, TXQD, txqd_len); + /* Assert Ready */ + status = FIELD_DP32(status, STATUS, READY, 1); + /* Update register status */ + s->regs[IBEX_SPI_HOST_STATUS] = status; + break; + case IBEX_SPI_HOST_ERROR_ENABLE: + s->regs[addr] = val32; + + if (val32 & R_ERROR_ENABLE_CMDINVAL_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: Segment Length is not supported\n", __func__); + } + break; + case IBEX_SPI_HOST_ERROR_STATUS: + /* + * Indicates any errors that have occurred. + * When an error occurs, the corresponding bit must be cleared + * here before issuing any further commands + */ + status = s->regs[addr]; + /* rw1c status register */ + if (FIELD_EX32(val32, ERROR_STATUS, CMDBUSY)) { + status = FIELD_DP32(status, ERROR_STATUS, CMDBUSY, 0); + } + if (FIELD_EX32(val32, ERROR_STATUS, OVERFLOW)) { + status = FIELD_DP32(status, ERROR_STATUS, OVERFLOW, 0); + } + if (FIELD_EX32(val32, ERROR_STATUS, UNDERFLOW)) { + status = FIELD_DP32(status, ERROR_STATUS, UNDERFLOW, 0); + } + if (FIELD_EX32(val32, ERROR_STATUS, CMDINVAL)) { + status = FIELD_DP32(status, ERROR_STATUS, CMDINVAL, 0); + } + if (FIELD_EX32(val32, ERROR_STATUS, CSIDINVAL)) { + status = FIELD_DP32(status, ERROR_STATUS, CSIDINVAL, 0); + } + if (FIELD_EX32(val32, ERROR_STATUS, ACCESSINVAL)) { + status = FIELD_DP32(status, ERROR_STATUS, ACCESSINVAL, 0); + } + s->regs[addr] = status; + break; + case IBEX_SPI_HOST_EVENT_ENABLE: + /* Controls which classes of SPI events raise an interrupt. */ + s->regs[addr] = val32; + + if (val32 & R_EVENT_ENABLE_RXWM_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: RXWM is not supported\n", __func__); + } + if (val32 & R_EVENT_ENABLE_TXWM_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: TXWM is not supported\n", __func__); + } + + if (val32 & R_EVENT_ENABLE_IDLE_MASK) { + qemu_log_mask(LOG_UNIMP, + "%s: IDLE is not supported\n", __func__); + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "Bad offset 0x%" HWADDR_PRIx "\n", + addr << 2); + } +} + +static const MemoryRegionOps ibex_spi_ops = { + .read = ibex_spi_host_read, + .write = ibex_spi_host_write, + /* Ibex default LE */ + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static Property ibex_spi_properties[] = { + DEFINE_PROP_UINT32("num_cs", IbexSPIHostState, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_ibex = { + .name = TYPE_IBEX_SPI_HOST, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, IbexSPIHostState, IBEX_SPI_HOST_MAX_REGS), + VMSTATE_VARRAY_UINT32(config_opts, IbexSPIHostState, + num_cs, 0, vmstate_info_uint32, uint32_t), + VMSTATE_FIFO8(rx_fifo, IbexSPIHostState), + VMSTATE_FIFO8(tx_fifo, IbexSPIHostState), + VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexSPIHostState), + VMSTATE_BOOL(init_status, IbexSPIHostState), + VMSTATE_END_OF_LIST() + } +}; + +static void fifo_trigger_update(void *opaque) +{ + IbexSPIHostState *s = opaque; + ibex_spi_host_transfer(s); +} + +static void ibex_spi_host_realize(DeviceState *dev, Error **errp) +{ + IbexSPIHostState *s = IBEX_SPI_HOST(dev); + int i; + + s->ssi = ssi_create_bus(dev, "ssi"); + s->cs_lines = g_new0(qemu_irq, s->num_cs); + + for (i = 0; i < s->num_cs; ++i) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]); + } + + /* Setup CONFIGOPTS Multi-register */ + s->config_opts = g_new0(uint32_t, s->num_cs); + + /* Setup FIFO Interrupt Timer */ + s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, + fifo_trigger_update, s); + + /* FIFO sizes as per OT Spec */ + fifo8_create(&s->tx_fifo, IBEX_SPI_HOST_TXFIFO_LEN); + fifo8_create(&s->rx_fifo, IBEX_SPI_HOST_RXFIFO_LEN); +} + +static void ibex_spi_host_init(Object *obj) +{ + IbexSPIHostState *s = IBEX_SPI_HOST(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->host_err); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->event); + + memory_region_init_io(&s->mmio, obj, &ibex_spi_ops, s, + TYPE_IBEX_SPI_HOST, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void ibex_spi_host_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = ibex_spi_host_realize; + dc->reset = ibex_spi_host_reset; + dc->vmsd = &vmstate_ibex; + device_class_set_props(dc, ibex_spi_properties); +} + +static const TypeInfo ibex_spi_host_info = { + .name = TYPE_IBEX_SPI_HOST, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IbexSPIHostState), + .instance_init = ibex_spi_host_init, + .class_init = ibex_spi_host_class_init, +}; + +static void ibex_spi_host_register_types(void) +{ + type_register_static(&ibex_spi_host_info); +} + +type_init(ibex_spi_host_register_types) diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 0ded9cd092d7..1b0d46d44f69 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -10,3 +10,5 @@ softmmu_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c')) softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c')) +softmmu_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) +softmmu_ss.add(when: 'CONFIG_RT_FLEXSPI', if_true: files('rt_flexspi.c')) diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c index 7c7e689707a4..8f85c3e3918d 100644 --- a/hw/ssi/omap_spi.c +++ b/hw/ssi/omap_spi.c @@ -134,10 +134,9 @@ void omap_mcspi_reset(struct omap_mcspi_s *s) omap_mcspi_interrupt_update(s); } -static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, - unsigned size) +static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, unsigned size) { - struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; + struct omap_mcspi_s *s = opaque; int ch = 0; uint32_t ret; @@ -226,7 +225,7 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, static void omap_mcspi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; + struct omap_mcspi_s *s = opaque; int ch = 0; if (size != 4) { diff --git a/hw/ssi/rt_flexspi.c b/hw/ssi/rt_flexspi.c new file mode 100644 index 000000000000..17f4bcc0b2dd --- /dev/null +++ b/hw/ssi/rt_flexspi.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/ssi/rt_flexspi.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" + +#ifndef DEBUG_RT_FLEXSPI +#define DEBUG_RT_FLEXSPI 0 +#endif + +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_RT_FLEXSPI) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_RT_FLEXSPI, \ + __func__, ##args); \ + } \ + } while (0) + +static const VMStateDescription vmstate_rt_flexspi = { + .name = TYPE_RT_FLEXSPI, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_FIFO32(tx_fifo, RTFLEXSPIState), + VMSTATE_FIFO32(rx_fifo, RTFLEXSPIState), + VMSTATE_UINT32_ARRAY(lut, RTFLEXSPIState, 64), + VMSTATE_UINT32(MCR0, RTFLEXSPIState), + VMSTATE_UINT32(MCR1, RTFLEXSPIState), + VMSTATE_UINT32(MCR2, RTFLEXSPIState), + VMSTATE_UINT32(AHBCR, RTFLEXSPIState), + VMSTATE_UINT32(INTEN, RTFLEXSPIState), + VMSTATE_UINT32(INTR, RTFLEXSPIState), + VMSTATE_UINT32(LUTKEY, RTFLEXSPIState), + VMSTATE_UINT32(LUTCR, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF0CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF1CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF2CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF3CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF4CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF5CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF6CR0, RTFLEXSPIState), + VMSTATE_UINT32(AHBRXBUF7CR0, RTFLEXSPIState), + VMSTATE_UINT32(FLSHA1CR0, RTFLEXSPIState), + VMSTATE_UINT32(FLSHA2CR0, RTFLEXSPIState), + VMSTATE_UINT32(FLSHB1CR0, RTFLEXSPIState), + VMSTATE_UINT32(FLSHB2CR0, RTFLEXSPIState), + VMSTATE_UINT32(FLSHA1CR1, RTFLEXSPIState), + VMSTATE_UINT32(FLSHA2CR1, RTFLEXSPIState), + VMSTATE_UINT32(FLSHB1CR1, RTFLEXSPIState), + VMSTATE_UINT32(FLSHB2CR1, RTFLEXSPIState), + VMSTATE_UINT32(FLSHA1CR2, RTFLEXSPIState), + VMSTATE_UINT32(FLSHA2CR2, RTFLEXSPIState), + VMSTATE_UINT32(FLSHB1CR2, RTFLEXSPIState), + VMSTATE_UINT32(FLSHB2CR2, RTFLEXSPIState), + VMSTATE_UINT32(FLSHCR4, RTFLEXSPIState), + VMSTATE_UINT32(IPCR0, RTFLEXSPIState), + VMSTATE_UINT32(IPCR1, RTFLEXSPIState), + VMSTATE_UINT32(IPCMD, RTFLEXSPIState), + VMSTATE_UINT32(DLPR, RTFLEXSPIState), + VMSTATE_UINT32(IPRXFCR, RTFLEXSPIState), + VMSTATE_UINT32(IPTXFCR, RTFLEXSPIState), + VMSTATE_UINT32(DLLACR, RTFLEXSPIState), + VMSTATE_UINT32(DLLBCR, RTFLEXSPIState), + VMSTATE_UINT32(STS0, RTFLEXSPIState), + VMSTATE_UINT32(STS1, RTFLEXSPIState), + VMSTATE_UINT32(STS2, RTFLEXSPIState), + VMSTATE_UINT32(AHBSPNDSTS, RTFLEXSPIState), + VMSTATE_UINT32(IPRXFSTS, RTFLEXSPIState), + VMSTATE_UINT32(IPTXFSTS, RTFLEXSPIState), + VMSTATE_END_OF_LIST() + }, +}; + +static void rt_flexspi_txfifo_reset(RTFLEXSPIState *s) +{ + fifo32_reset(&s->tx_fifo); +} + +static void rt_flexspi_rxfifo_reset(RTFLEXSPIState *s) +{ + fifo32_reset(&s->rx_fifo); +} + +static void rt_flexspi_update_irq(RTFLEXSPIState *s) +{ + int level = 0; /* TODO */ + + qemu_set_irq(s->irq, level); + + DPRINTF("IRQ level is %d\n", level); +} + +static void rt_flexspi_common_reset(RTFLEXSPIState *s) +{ + int i; + + s->MCR0 = 0xFFFF80C2; + s->MCR1 = 0xFFFFFFFF; + s->MCR2 = 0x200081F7; + s->AHBCR = 0x00000018; + s->INTEN = 0x00000000; + s->INTR = 0x00000000; + s->LUTKEY = 0x5AF05AF0; + s->LUTCR = 0x00000002; + s->AHBRXBUF0CR0 = 0x80000010; + s->AHBRXBUF1CR0 = 0x80010010; + s->AHBRXBUF2CR0 = 0x80020010; + s->AHBRXBUF3CR0 = 0x80030010; + s->AHBRXBUF4CR0 = 0x80040010; + s->AHBRXBUF5CR0 = 0x80050010; + s->AHBRXBUF6CR0 = 0x80060010; + s->AHBRXBUF7CR0 = 0x80070010; + s->FLSHA1CR0 = 0x00010000; + s->FLSHA2CR0 = 0x00010000; + s->FLSHB1CR0 = 0x00010000; + s->FLSHB2CR0 = 0x00010000; + s->FLSHA1CR1 = 0x00000063; + s->FLSHA2CR1 = 0x00000063; + s->FLSHB1CR1 = 0x00000063; + s->FLSHB2CR1 = 0x00000063; + s->FLSHA1CR2 = 0x00000000; + s->FLSHA2CR2 = 0x00000000; + s->FLSHB1CR2 = 0x00000000; + s->FLSHB2CR2 = 0x00000000; + s->FLSHCR4 = 0x00000000; + s->IPCR0 = 0x00000000; + s->IPCR1 = 0x00000000; + s->IPCMD = 0x00000000; + s->DLPR = 0x00000000; + s->IPRXFCR = 0x00000000; + s->IPTXFCR = 0x00000000; + s->DLLACR = 0x00000100; + s->DLLBCR = 0x00000100; + s->STS0 = 0x00000002; + s->STS1 = 0x00000000; + s->STS2 = 0x01000100; + s->AHBSPNDSTS = 0x00000000; + s->IPRXFSTS = 0x00000000; + s->IPTXFSTS = 0x00000000; + + rt_flexspi_rxfifo_reset(s); + rt_flexspi_txfifo_reset(s); + + for (i=0; i< LUT_SIZE; i++) + { + s->lut[i] = 0; + } +} + +static void rt_flexspi_reset(DeviceState *dev) +{ + RTFLEXSPIState *s = RT_FLEXSPI(dev); + + rt_flexspi_common_reset(s); + rt_flexspi_update_irq(s); +} + +static uint64_t rt_flexspi_read(void *opaque, hwaddr offset, unsigned size) +{ + uint32_t value = 0; + RTFLEXSPIState *s = opaque; + + switch(offset) + { + case 0x0: + /* clear reset */ + value = s->MCR0 & (~0x1); + break; + case 0x4: + value = s->MCR1; + break; + case 0x8: + value = s->MCR2 & (~0x4000); + break; + case 0xC: + value = s->AHBCR; + break; + case 0x10: + value = s->INTEN; + break; + case 0x14: + value = s->INTR; + break; + case 0x18: + value = s->LUTKEY; + break; + case 0x1C: + value = s->LUTCR; + break; + case 0x20: + value = s->AHBRXBUF0CR0; + break; + case 0x24: + value = s->AHBRXBUF1CR0; + break; + case 0x28: + value = s->AHBRXBUF2CR0; + break; + case 0x2C: + value = s->AHBRXBUF3CR0; + break; + case 0x30: + value = s->AHBRXBUF4CR0; + break; + case 0x34: + value = s->AHBRXBUF5CR0; + break; + case 0x38: + value = s->AHBRXBUF6CR0; + break; + case 0x3C: + value = s->AHBRXBUF7CR0; + break; + case 0x60: + value = s->FLSHA1CR0; + break; + case 0x64: + value = s->FLSHA2CR0; + break; + case 0x68: + value = s->FLSHB1CR0; + break; + case 0x6C: + value = s->FLSHB2CR0; + break; + case 0x70: + value = s->FLSHA1CR1; + break; + case 0x74: + value = s->FLSHA2CR1; + break; + case 0x78: + value = s->FLSHB1CR1; + break; + case 0x7C: + value = s->FLSHB2CR1; + break; + case 0x80: + value = s->FLSHA1CR2; + break; + case 0x84: + value = s->FLSHA2CR2; + break; + case 0x88: + value = s->FLSHB1CR2; + break; + case 0x8C: + value = s->FLSHB2CR2; + break; + case 0x94: + value = s->FLSHCR4; + break; + case 0xA0: + value = s->IPCR0; + break; + case 0xA4: + value = s->IPCR1; + break; + case 0xB0: + value = s->IPCMD; + break; + case 0xB4: + value = s->DLPR; + break; + case 0xB8: + value = s->IPRXFCR; + break; + case 0xBC: + value = s->IPTXFCR; + break; + case 0xC0: + value = s->DLLACR; + break; + case 0xC4: + value = s->DLLBCR; + break; + case 0xE0: + /* ARBIDLE and SEQIDLE */ + value = s->STS0 | (0x3); + break; + case 0xE4: + value = s->STS1; + break; + case 0xE8: + /* AREFLOCK and ASLVLOCK */ + value = s->STS2 | (0x3); + break; + case 0xEC: + value = s->AHBSPNDSTS; + break; + case 0xF0: + value = s->IPRXFSTS; + break; + case 0xF4: + value = s->IPTXFSTS; + break; + default: + break; + } + + return (uint64_t)value; +} + +static void rt_flexspi_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + RTFLEXSPIState *s = opaque; + uint32_t v32 = (uint32_t)value; + + switch(offset) + { + case 0x0: + s->MCR0 = v32; + break; + case 0x4: + s->MCR1 = v32; + break; + case 0x8: + s->MCR2 = v32; + break; + case 0xC: + s->AHBCR = v32; + break; + case 0x10: + s->INTEN = v32; + break; + case 0x14: + s->INTR = s->INTR & (~(v32 & 0x1FFF)); + /* AHBCMDERR is set clear err and error code */ + if (v32 & 0x10 ) { + s->STS1 = s->STS1 & (~0xF0F); + } + break; + case 0x18: + s->LUTKEY = v32; + break; + case 0x1C: + s->LUTCR = v32; + break; + case 0x20: + s->AHBRXBUF0CR0 = v32; + break; + case 0x24: + s->AHBRXBUF1CR0 = v32; + break; + case 0x28: + s->AHBRXBUF2CR0 = v32; + break; + case 0x2C: + s->AHBRXBUF3CR0 = v32; + break; + case 0x30: + s->AHBRXBUF4CR0 = v32; + break; + case 0x34: + s->AHBRXBUF5CR0 = v32; + break; + case 0x38: + s->AHBRXBUF6CR0 = v32; + break; + case 0x3C: + s->AHBRXBUF7CR0 = v32; + break; + case 0x60: + s->FLSHA1CR0 = v32; + break; + case 0x64: + s->FLSHA2CR0 = v32; + break; + case 0x68: + s->FLSHB1CR0 = v32; + break; + case 0x6C: + s->FLSHB2CR0 = v32; + break; + case 0x70: + s->FLSHA1CR1 = v32; + break; + case 0x74: + s->FLSHA2CR1 = v32; + break; + case 0x78: + s->FLSHB1CR1 = v32; + break; + case 0x7C: + s->FLSHB2CR1 = v32; + break; + case 0x80: + s->FLSHA1CR2 = v32; + break; + case 0x84: + s->FLSHA2CR2 = v32; + break; + case 0x88: + s->FLSHB1CR2 = v32; + break; + case 0x8C: + s->FLSHB2CR2 = v32; + break; + case 0x94: + s->FLSHCR4 = v32; + break; + case 0xA0: + s->IPCR0 = v32; + break; + case 0xA4: + s->IPCR1 = v32; + break; + case 0xB0: + s->IPCMD = v32; + break; + case 0xB4: + s->DLPR = v32; + break; + case 0xB8: + s->IPRXFCR = v32; + break; + case 0xBC: + s->IPTXFCR = v32; + break; + case 0xC0: + s->DLLACR = v32; + break; + case 0xC4: + s->DLLBCR = v32; + break; + case 0xE0: + break; + case 0xE4: + break; + case 0xE8: + break; + case 0xEC: + break; + case 0xF0: + break; + case 0xF4: + break; + default: + break; + } +} + +static const struct MemoryRegionOps rt_flexspi_ops = { + .read = rt_flexspi_read, + .write = rt_flexspi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt_flexspi_realize(DeviceState *dev, Error **errp) +{ + RTFLEXSPIState *s = RT_FLEXSPI(dev); + + s->bus = ssi_create_bus(dev, "spi"); + + memory_region_init_io(&s->iomem, OBJECT(dev), &rt_flexspi_ops, s, + TYPE_RT_FLEXSPI, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + + fifo32_create(&s->tx_fifo, FLEXSPI_FIFO_SIZE); + fifo32_create(&s->rx_fifo, FLEXSPI_FIFO_SIZE); +} + +static void rt_flexspi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_flexspi_realize; + dc->vmsd = &vmstate_rt_flexspi; + dc->reset = rt_flexspi_reset; + dc->desc = "NXP RT flexspi Controller"; +} + +static const TypeInfo rt_flexspi_info = { + .name = TYPE_RT_FLEXSPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTFLEXSPIState), + .class_init = rt_flexspi_class_init, +}; + +static void rt_flexspi_register_types(void) +{ + type_register_static(&rt_flexspi_info); +} + +type_init(rt_flexspi_register_types) diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 003931fb509e..d54a109beeb5 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -38,9 +38,8 @@ static void ssi_cs_default(void *opaque, int n, int level) bool cs = !!level; assert(n == 0); if (s->cs != cs) { - SSIPeripheralClass *ssc = SSI_PERIPHERAL_GET_CLASS(s); - if (ssc->set_cs) { - ssc->set_cs(s, cs); + if (s->spc->set_cs) { + s->spc->set_cs(s, cs); } } s->cs = cs; @@ -48,11 +47,11 @@ static void ssi_cs_default(void *opaque, int n, int level) static uint32_t ssi_transfer_raw_default(SSIPeripheral *dev, uint32_t val) { - SSIPeripheralClass *ssc = SSI_PERIPHERAL_GET_CLASS(dev); + SSIPeripheralClass *ssc = dev->spc; if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) || - (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) || - ssc->cs_polarity == SSI_CS_NONE) { + (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) || + ssc->cs_polarity == SSI_CS_NONE) { return ssc->transfer(dev, val); } return 0; @@ -67,6 +66,7 @@ static void ssi_peripheral_realize(DeviceState *dev, Error **errp) ssc->cs_polarity != SSI_CS_NONE) { qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1); } + s->spc = ssc; ssc->realize(s, errp); } @@ -115,13 +115,11 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { BusState *b = BUS(bus); BusChild *kid; - SSIPeripheralClass *ssc; uint32_t r = 0; QTAILQ_FOREACH(kid, &b->children, sibling) { - SSIPeripheral *peripheral = SSI_PERIPHERAL(kid->child); - ssc = SSI_PERIPHERAL_GET_CLASS(peripheral); - r |= ssc->transfer_raw(peripheral, val); + SSIPeripheral *p = SSI_PERIPHERAL(kid->child); + r |= p->spc->transfer_raw(p, val); } return r; diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events index 612d3d6087aa..c707d4aabafe 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -20,3 +20,10 @@ npcm7xx_fiu_ctrl_read(const char *id, uint64_t addr, uint32_t data) "%s offset: npcm7xx_fiu_ctrl_write(const char *id, uint64_t addr, uint32_t data) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32 npcm7xx_fiu_flash_read(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64 npcm7xx_fiu_flash_write(const char *id, unsigned cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64 + +# ibex_spi_host.c + +ibex_spi_host_reset(const char *msg) "%s" +ibex_spi_host_transfer(uint32_t tx_data, uint32_t rx_data) "tx_data: 0x%" PRIx32 " rx_data: @0x%" PRIx32 +ibex_spi_host_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64 +ibex_spi_host_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size %u:" diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 010be7ed1f56..653c82a21be1 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -60,3 +60,6 @@ config STELLARIS_GPTM config AVR_TIMER16 bool + +config RT_OSTIMER + bool diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index c3fc2a4daaf5..971f78462ab4 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -275,7 +275,7 @@ static void a10_pit_init(Object *obj) tc->container = s; tc->index = i; - s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, PTIMER_POLICY_DEFAULT); + s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, PTIMER_POLICY_LEGACY); } } diff --git a/hw/timer/altera_timer.c b/hw/timer/altera_timer.c index c6e02d2b5a7c..0f1f54206a36 100644 --- a/hw/timer/altera_timer.c +++ b/hw/timer/altera_timer.c @@ -185,7 +185,7 @@ static void altera_timer_realize(DeviceState *dev, Error **errp) return; } - t->ptimer = ptimer_init(timer_hit, t, PTIMER_POLICY_DEFAULT); + t->ptimer = ptimer_init(timer_hit, t, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(t->ptimer); ptimer_set_freq(t->ptimer, t->freq_hz); ptimer_transaction_commit(t->ptimer); diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 84cf2726bb39..69c886347222 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -180,7 +180,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->freq = freq; s->control = TIMER_CTRL_IE; - s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_LEGACY); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s); return s; } diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 42c47d2ce64a..9c20b3d6ad8a 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -745,12 +745,29 @@ static const TypeInfo aspeed_2600_timer_info = { .class_init = aspeed_2600_timer_class_init, }; +static void aspeed_1030_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); + + dc->desc = "ASPEED 1030 Timer"; + awc->read = aspeed_2600_timer_read; + awc->write = aspeed_2600_timer_write; +} + +static const TypeInfo aspeed_1030_timer_info = { + .name = TYPE_ASPEED_1030_TIMER, + .parent = TYPE_ASPEED_TIMER, + .class_init = aspeed_1030_timer_class_init, +}; + static void aspeed_timer_register_types(void) { type_register_static(&aspeed_timer_info); type_register_static(&aspeed_2400_timer_info); type_register_static(&aspeed_2500_timer_info); type_register_static(&aspeed_2600_timer_info); + type_register_static(&aspeed_1030_timer_info); } type_init(aspeed_timer_register_types) diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index 64108241ba99..e57a0f5f09f7 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -24,6 +24,8 @@ #include "qemu/timer.h" #include "qom/object.h" +#include "hw/timer/cadence_ttc.h" + #ifdef CADENCE_TTC_ERR_DEBUG #define DB_PRINT(...) do { \ fprintf(stderr, ": %s: ", __func__); \ @@ -49,36 +51,6 @@ #define CLOCK_CTRL_PS_EN 0x00000001 #define CLOCK_CTRL_PS_V 0x0000001e -typedef struct { - QEMUTimer *timer; - int freq; - - uint32_t reg_clock; - uint32_t reg_count; - uint32_t reg_value; - uint16_t reg_interval; - uint16_t reg_match[3]; - uint32_t reg_intr; - uint32_t reg_intr_en; - uint32_t reg_event_ctrl; - uint32_t reg_event; - - uint64_t cpu_time; - unsigned int cpu_time_valid; - - qemu_irq irq; -} CadenceTimerState; - -#define TYPE_CADENCE_TTC "cadence_ttc" -OBJECT_DECLARE_SIMPLE_TYPE(CadenceTTCState, CADENCE_TTC) - -struct CadenceTTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CadenceTimerState timer[3]; -}; - static void cadence_timer_update(CadenceTimerState *s) { qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en)); diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index e3aae4a45a48..d5186f445494 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -139,7 +139,7 @@ static void digic_timer_init(Object *obj) { DigicTimerState *s = DIGIC_TIMER(obj); - s->ptimer = ptimer_init(digic_timer_tick, NULL, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(digic_timer_tick, NULL, PTIMER_POLICY_LEGACY); /* * FIXME: there is no documentation on Digic timer diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 139e5b86a447..ecc2831bafb0 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -370,9 +370,9 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp) ETRAXTimerState *t = ETRAX_TIMER(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_DEFAULT); - t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_DEFAULT); - t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_DEFAULT); + t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_LEGACY); + t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_LEGACY); + t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_LEGACY); sysbus_init_irq(sbd, &t->irq); sysbus_init_irq(sbd, &t->nmi); diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index d0e534399680..e175a9f5b9b3 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1503,17 +1503,17 @@ static void exynos4210_mct_init(Object *obj) /* Global timer */ s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); memset(&s->g_timer.reg, 0, sizeof(struct gregs)); /* Local timers */ for (i = 0; i < 2; i++) { s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(exynos4210_ltick_event, &s->l_timer[i], - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); s->l_timer[i].ptimer_frc = ptimer_init(exynos4210_lfrc_event, &s->l_timer[i], - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); s->l_timer[i].id = i; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 220088120eef..02924a9e5b37 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -400,7 +400,7 @@ static void exynos4210_pwm_init(Object *obj) sysbus_init_irq(dev, &s->timer[i].irq); s->timer[i].ptimer = ptimer_init(exynos4210_pwm_tick, &s->timer[i], - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); s->timer[i].id = i; s->timer[i].parent = s; } diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index d51189010975..5c4923c1e09c 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -383,7 +383,7 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp) timer->unit = unit; timer->ptimer = ptimer_init(grlib_gptimer_hit, timer, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); timer->id = i; /* One IRQ line for each timer */ diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c index 8c2ca364daab..d8b8e4e1f602 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/timer/imx_epit.c b/hw/timer/imx_epit.c index ebd58254d15f..3a869782bcdc 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -6,6 +6,7 @@ * Originally written by Hans Jiang * Updated by Peter Chubb * Updated by Jean-Christophe Dubois + * Updated by Axel Heider * * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. @@ -66,73 +67,54 @@ static const IMXClk imx_epit_clocks[] = { */ static void imx_epit_update_int(IMXEPITState *s) { - if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { + if ((s->sr & SR_OCIF) && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { qemu_irq_raise(s->irq); } else { qemu_irq_lower(s->irq); } } -/* - * Must be called from within a ptimer_transaction_begin/commit block - * for both s->timer_cmp and s->timer_reload. - */ -static void imx_epit_set_freq(IMXEPITState *s) +static uint32_t imx_epit_get_freq(IMXEPITState *s) { - uint32_t clksrc; - uint32_t prescaler; - - clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2); - prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12); - - s->freq = imx_ccm_get_clock_frequency(s->ccm, - imx_epit_clocks[clksrc]) / prescaler; - - DPRINTF("Setting ptimer frequency to %u\n", s->freq); - - if (s->freq) { - ptimer_set_freq(s->timer_reload, s->freq); - ptimer_set_freq(s->timer_cmp, s->freq); - } + uint32_t clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, CR_CLKSRC_BITS); + uint32_t prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, CR_PRESCALE_BITS); + uint32_t f_in = imx_ccm_get_clock_frequency(s->ccm, imx_epit_clocks[clksrc]); + uint32_t freq = f_in / prescaler; + DPRINTF("ptimer frequency is %u\n", freq); + return freq; } -static void imx_epit_reset(DeviceState *dev) +/* + * This is called both on hardware (device) reset and software reset. + */ +static void imx_epit_reset(IMXEPITState *s, bool is_hard_reset) { - IMXEPITState *s = IMX_EPIT(dev); - - /* - * Soft reset doesn't touch some bits; hard reset clears them - */ - s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); + /* Soft reset doesn't touch some bits; hard reset clears them */ + if (is_hard_reset) { + s->cr = 0; + } else { + s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); + } s->sr = 0; s->lr = EPIT_TIMER_MAX; s->cmp = 0; - s->cnt = 0; ptimer_transaction_begin(s->timer_cmp); ptimer_transaction_begin(s->timer_reload); - /* stop both timers */ + + /* + * The reset switches off the input clock, so even if the CR.EN is still + * set, the timers are no longer running. + */ + assert(imx_epit_get_freq(s) == 0); ptimer_stop(s->timer_cmp); ptimer_stop(s->timer_reload); - /* compute new frequency */ - imx_epit_set_freq(s); /* init both timers to EPIT_TIMER_MAX */ ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); - if (s->freq && (s->cr & CR_EN)) { - /* if the timer is still enabled, restart it */ - ptimer_run(s->timer_reload, 0); - } ptimer_transaction_commit(s->timer_cmp); ptimer_transaction_commit(s->timer_reload); } -static uint32_t imx_epit_update_count(IMXEPITState *s) -{ - s->cnt = ptimer_get_count(s->timer_reload); - - return s->cnt; -} - static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) { IMXEPITState *s = IMX_EPIT(opaque); @@ -156,8 +138,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) break; case 4: /* CNT */ - imx_epit_update_count(s); - reg_value = s->cnt; + reg_value = ptimer_get_count(s->timer_reload); break; default: @@ -171,139 +152,219 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) return reg_value; } -/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */ -static void imx_epit_reload_compare_timer(IMXEPITState *s) +/* + * Must be called from a ptimer_transaction_begin/commit block for + * s->timer_cmp, but outside of a transaction block of s->timer_reload, + * so the proper counter value is read. + */ +static void imx_epit_update_compare_timer(IMXEPITState *s) { - if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { - /* if the compare feature is on and timers are running */ - uint32_t tmp = imx_epit_update_count(s); - uint64_t next; - if (tmp > s->cmp) { - /* It'll fire in this round of the timer */ - next = tmp - s->cmp; - } else { /* catch it next time around */ - next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr); + uint64_t counter = 0; + bool is_oneshot = false; + /* + * The compare timer only has to run if the timer peripheral is active + * and there is an input clock, Otherwise it can be switched off. + */ + bool is_active = (s->cr & CR_EN) && imx_epit_get_freq(s); + if (is_active) { + /* + * Calculate next timeout for compare timer. Reading the reload + * counter returns proper results only if pending transactions + * on it are committed here. Otherwise stale values are be read. + */ + counter = ptimer_get_count(s->timer_reload); + uint64_t limit = ptimer_get_limit(s->timer_cmp); + /* + * The compare timer is a periodic timer if the limit is at least + * the compare value. Otherwise it may fire at most once in the + * current round. + */ + bool is_oneshot = (limit >= s->cmp); + if (counter >= s->cmp) { + /* The compare timer fires in the current round. */ + counter -= s->cmp; + } else if (!is_oneshot) { + /* + * The compare timer fires after a reload, as it is below the + * compare value already in this round. Note that the counter + * value calculated below can be above the 32-bit limit, which + * is legal here because the compare timer is an internal + * helper ptimer only. + */ + counter += limit - s->cmp; + } else { + /* + * The compare timer won't fire in this round, and the limit is + * set to a value below the compare value. This practically means + * it will never fire, so it can be switched off. + */ + is_active = false; } - ptimer_set_count(s->timer_cmp, next); } + + /* + * Set the compare timer and let it run, or stop it. This is agnostic + * of CR.OCIEN bit, as this bit affects interrupt generation only. The + * compare timer needs to run even if no interrupts are to be generated, + * because the SR.OCIF bit must be updated also. + * Note that the timer might already be stopped or be running with + * counter values. However, finding out when an update is needed and + * when not is not trivial. It's much easier applying the setting again, + * as this does not harm either and the overhead is negligible. + */ + if (is_active) { + ptimer_set_count(s->timer_cmp, counter); + ptimer_run(s->timer_cmp, is_oneshot ? 1 : 0); + } else { + ptimer_stop(s->timer_cmp); + } + } -static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) +static void imx_epit_write_cr(IMXEPITState *s, uint32_t value) { - IMXEPITState *s = IMX_EPIT(opaque); - uint64_t oldcr; + uint32_t oldcr = s->cr; - DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), - (uint32_t)value); + s->cr = value & 0x03ffffff; - switch (offset >> 2) { - case 0: /* CR */ - - oldcr = s->cr; - s->cr = value & 0x03ffffff; - if (s->cr & CR_SWR) { - /* handle the reset */ - imx_epit_reset(DEVICE(s)); - /* - * TODO: could we 'break' here? following operations appear - * to duplicate the work imx_epit_reset() already did. - */ - } + if (s->cr & CR_SWR) { + /* + * Reset clears CR.SWR again. It does not touch CR.EN, but the timers + * are still stopped because the input clock is disabled. + */ + imx_epit_reset(s, false); + } else { + uint32_t freq; + uint32_t toggled_cr_bits = oldcr ^ s->cr; + /* re-initialize the limits if CR.RLD has changed */ + bool set_limit = toggled_cr_bits & CR_RLD; + /* set the counter if the timer got just enabled and CR.ENMOD is set */ + bool is_switched_on = (toggled_cr_bits & s->cr) & CR_EN; + bool set_counter = is_switched_on && (s->cr & CR_ENMOD); ptimer_transaction_begin(s->timer_cmp); ptimer_transaction_begin(s->timer_reload); - - if (!(s->cr & CR_SWR)) { - imx_epit_set_freq(s); + freq = imx_epit_get_freq(s); + if (freq) { + ptimer_set_freq(s->timer_reload, freq); + ptimer_set_freq(s->timer_cmp, freq); } - if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) { - if (s->cr & CR_ENMOD) { - if (s->cr & CR_RLD) { - ptimer_set_limit(s->timer_reload, s->lr, 1); - ptimer_set_limit(s->timer_cmp, s->lr, 1); - } else { - ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); - ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); - } + if (set_limit || set_counter) { + uint64_t limit = (s->cr & CR_RLD) ? s->lr : EPIT_TIMER_MAX; + ptimer_set_limit(s->timer_reload, limit, set_counter ? 1 : 0); + if (set_limit) { + ptimer_set_limit(s->timer_cmp, limit, 0); } - - imx_epit_reload_compare_timer(s); + } + /* + * If there is an input clock and the peripheral is enabled, then + * ensure the wall clock timer is ticking. Otherwise stop the timers. + * The compare timer will be updated later. + */ + if (freq && (s->cr & CR_EN)) { ptimer_run(s->timer_reload, 0); - if (s->cr & CR_OCIEN) { - ptimer_run(s->timer_cmp, 0); - } else { - ptimer_stop(s->timer_cmp); - } - } else if (!(s->cr & CR_EN)) { - /* stop both timers */ - ptimer_stop(s->timer_reload); - ptimer_stop(s->timer_cmp); - } else if (s->cr & CR_OCIEN) { - if (!(oldcr & CR_OCIEN)) { - imx_epit_reload_compare_timer(s); - ptimer_run(s->timer_cmp, 0); - } } else { - ptimer_stop(s->timer_cmp); + ptimer_stop(s->timer_reload); } - - ptimer_transaction_commit(s->timer_cmp); + /* Commit changes to reload timer, so they can propagate. */ ptimer_transaction_commit(s->timer_reload); - break; + /* Update compare timer based on the committed reload timer value. */ + imx_epit_update_compare_timer(s); + ptimer_transaction_commit(s->timer_cmp); + } - case 1: /* SR - ACK*/ - /* writing 1 to OCIF clear the OCIF bit */ - if (value & 0x01) { - s->sr = 0; - imx_epit_update_int(s); - } - break; + /* + * The interrupt state can change due to: + * - reset clears both SR.OCIF and CR.OCIE + * - write to CR.EN or CR.OCIE + */ + imx_epit_update_int(s); +} - case 2: /* LR - set ticks */ - s->lr = value; +static void imx_epit_write_sr(IMXEPITState *s, uint32_t value) +{ + /* writing 1 to SR.OCIF clears this bit and turns the interrupt off */ + if (value & SR_OCIF) { + s->sr = 0; /* SR.OCIF is the only bit in this register anyway */ + imx_epit_update_int(s); + } +} - ptimer_transaction_begin(s->timer_cmp); - ptimer_transaction_begin(s->timer_reload); - if (s->cr & CR_RLD) { - /* Also set the limit if the LRD bit is set */ - /* If IOVW bit is set then set the timer value */ - ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); - ptimer_set_limit(s->timer_cmp, s->lr, 0); - } else if (s->cr & CR_IOVW) { - /* If IOVW bit is set then set the timer value */ - ptimer_set_count(s->timer_reload, s->lr); - } +static void imx_epit_write_lr(IMXEPITState *s, uint32_t value) +{ + s->lr = value; - imx_epit_reload_compare_timer(s); - ptimer_transaction_commit(s->timer_cmp); - ptimer_transaction_commit(s->timer_reload); + ptimer_transaction_begin(s->timer_cmp); + ptimer_transaction_begin(s->timer_reload); + if (s->cr & CR_RLD) { + /* Also set the limit if the LRD bit is set */ + /* If IOVW bit is set then set the timer value */ + ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); + ptimer_set_limit(s->timer_cmp, s->lr, 0); + } else if (s->cr & CR_IOVW) { + /* If IOVW bit is set then set the timer value */ + ptimer_set_count(s->timer_reload, s->lr); + } + /* Commit the changes to s->timer_reload, so they can propagate. */ + ptimer_transaction_commit(s->timer_reload); + /* Update the compare timer based on the committed reload timer value. */ + imx_epit_update_compare_timer(s); + ptimer_transaction_commit(s->timer_cmp); +} + +static void imx_epit_write_cmp(IMXEPITState *s, uint32_t value) +{ + s->cmp = value; + + /* Update the compare timer based on the committed reload timer value. */ + ptimer_transaction_begin(s->timer_cmp); + imx_epit_update_compare_timer(s); + ptimer_transaction_commit(s->timer_cmp); +} + +static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + IMXEPITState *s = IMX_EPIT(opaque); + + DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), + (uint32_t)value); + + switch (offset >> 2) { + case 0: /* CR */ + imx_epit_write_cr(s, (uint32_t)value); break; - case 3: /* CMP */ - s->cmp = value; + case 1: /* SR */ + imx_epit_write_sr(s, (uint32_t)value); + break; - ptimer_transaction_begin(s->timer_cmp); - imx_epit_reload_compare_timer(s); - ptimer_transaction_commit(s->timer_cmp); + case 2: /* LR */ + imx_epit_write_lr(s, (uint32_t)value); + break; + case 3: /* CMP */ + imx_epit_write_cmp(s, (uint32_t)value); break; default: qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); - break; } } + static void imx_epit_cmp(void *opaque) { IMXEPITState *s = IMX_EPIT(opaque); - DPRINTF("sr was %d\n", s->sr); + /* The cmp ptimer can't be running when the peripheral is disabled */ + assert(s->cr & CR_EN); - s->sr = 1; + DPRINTF("sr was %d\n", s->sr); + /* Set interrupt status bit SR.OCIF and update the interrupt state */ + s->sr |= SR_OCIF; imx_epit_update_int(s); } @@ -320,15 +381,13 @@ static const MemoryRegionOps imx_epit_ops = { static const VMStateDescription vmstate_imx_timer_epit = { .name = TYPE_IMX_EPIT, - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXEPITState), VMSTATE_UINT32(sr, IMXEPITState), VMSTATE_UINT32(lr, IMXEPITState), VMSTATE_UINT32(cmp, IMXEPITState), - VMSTATE_UINT32(cnt, IMXEPITState), - VMSTATE_UINT32(freq, IMXEPITState), VMSTATE_PTIMER(timer_reload, IMXEPITState), VMSTATE_PTIMER(timer_cmp, IMXEPITState), VMSTATE_END_OF_LIST() @@ -347,9 +406,25 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_DEFAULT); + /* + * The reload timer keeps running when the peripheral is enabled. It is a + * kind of wall clock that does not generate any interrupts. The callback + * needs to be provided, but it does nothing as the ptimer already supports + * all necessary reloading functionality. + */ + s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY); + + /* + * The compare timer is running only when the peripheral configuration is + * in a state that will generate compare interrupts. + */ + s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY); +} - s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_DEFAULT); +static void imx_epit_dev_reset(DeviceState *dev) +{ + IMXEPITState *s = IMX_EPIT(dev); + imx_epit_reset(s, true); } static void imx_epit_class_init(ObjectClass *klass, void *data) @@ -357,7 +432,7 @@ static void imx_epit_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = imx_epit_realize; - dc->reset = imx_epit_reset; + dc->reset = imx_epit_dev_reset; dc->vmsd = &vmstate_imx_timer_epit; dc->desc = "i.MX periodic timer"; } diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 5c0d9a269ceb..7222b1b3874a 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -115,6 +115,17 @@ static const IMXClk imx6_gpt_clocks[] = { CLK_HIGH, /* 111 reference clock */ }; +static const IMXClk imx6ul_gpt_clocks[] = { + CLK_NONE, /* 000 No clock source */ + CLK_IPG, /* 001 ipg_clk, 532MHz*/ + CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ + CLK_EXT, /* 011 External clock */ + CLK_32k, /* 100 ipg_clk_32k */ + CLK_NONE, /* 101 not defined */ + CLK_NONE, /* 110 not defined */ + CLK_NONE, /* 111 not defined */ +}; + static const IMXClk imx7_gpt_clocks[] = { CLK_NONE, /* 000 No clock source */ CLK_IPG, /* 001 ipg_clk, 532MHz*/ @@ -505,7 +516,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_LEGACY); } static void imx_gpt_class_init(ObjectClass *klass, void *data) @@ -539,6 +550,13 @@ static void imx6_gpt_init(Object *obj) s->clocks = imx6_gpt_clocks; } +static void imx6ul_gpt_init(Object *obj) +{ + IMXGPTState *s = IMX_GPT(obj); + + s->clocks = imx6ul_gpt_clocks; +} + static void imx7_gpt_init(Object *obj) { IMXGPTState *s = IMX_GPT(obj); @@ -566,6 +584,12 @@ static const TypeInfo imx6_gpt_info = { .instance_init = imx6_gpt_init, }; +static const TypeInfo imx6ul_gpt_info = { + .name = TYPE_IMX6UL_GPT, + .parent = TYPE_IMX25_GPT, + .instance_init = imx6ul_gpt_init, +}; + static const TypeInfo imx7_gpt_info = { .name = TYPE_IMX7_GPT, .parent = TYPE_IMX25_GPT, @@ -577,6 +601,7 @@ static void imx_gpt_register_types(void) type_register_static(&imx25_gpt_info); type_register_static(&imx31_gpt_info); type_register_static(&imx6_gpt_info); + type_register_static(&imx6ul_gpt_info); type_register_static(&imx7_gpt_info); } diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 03092e2cebf4..727c009b2c39 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -36,5 +36,6 @@ softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_timer.c softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c')) specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) +softmmu_ss.add(when: 'CONFIG_RT_OSTIMER', if_true: files('rt_ostimer.c')) specific_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c')) diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c index fe0ca905f3cc..ee7438f1684f 100644 --- a/hw/timer/mss-timer.c +++ b/hw/timer/mss-timer.c @@ -232,7 +232,7 @@ static void mss_timer_init(Object *obj) for (i = 0; i < NUM_TIMERS; i++) { struct Msf2Timer *st = &t->timers[i]; - st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); + st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(st->ptimer); ptimer_set_freq(st->ptimer, t->freq_hz); ptimer_transaction_commit(st->ptimer); diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c index c407190138c7..34e6af7aff55 100644 --- a/hw/timer/omap_gptimer.c +++ b/hw/timer/omap_gptimer.c @@ -159,7 +159,7 @@ static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) static void omap_gp_timer_tick(void *opaque) { - struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *timer = opaque; if (!timer->ar) { timer->st = 0; @@ -179,7 +179,7 @@ static void omap_gp_timer_tick(void *opaque) static void omap_gp_timer_match(void *opaque) { - struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *timer = opaque; if (timer->trigger == gpt_trigger_both) omap_gp_timer_trigger(timer); @@ -189,7 +189,7 @@ static void omap_gp_timer_match(void *opaque) static void omap_gp_timer_input(void *opaque, int line, int on) { - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *s = opaque; int trigger; switch (s->capture) { @@ -219,7 +219,7 @@ static void omap_gp_timer_input(void *opaque, int line, int on) static void omap_gp_timer_clk_update(void *opaque, int line, int on) { - struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *timer = opaque; omap_gp_timer_sync(timer); timer->rate = on ? omap_clk_getrate(timer->clk) : 0; @@ -262,7 +262,7 @@ void omap_gp_timer_reset(struct omap_gp_timer_s *s) static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) { - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *s = opaque; switch (addr) { case 0x00: /* TIDR */ @@ -328,7 +328,7 @@ static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) { - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *s = opaque; uint32_t ret; if (addr & 2) @@ -340,10 +340,9 @@ static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) } } -static void omap_gp_timer_write(void *opaque, hwaddr addr, - uint32_t value) +static void omap_gp_timer_write(void *opaque, hwaddr addr, uint32_t value) { - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *s = opaque; switch (addr) { case 0x00: /* TIDR */ @@ -440,10 +439,9 @@ static void omap_gp_timer_write(void *opaque, hwaddr addr, } } -static void omap_gp_timer_writeh(void *opaque, hwaddr addr, - uint32_t value) +static void omap_gp_timer_writeh(void *opaque, hwaddr addr, uint32_t value) { - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; + struct omap_gp_timer_s *s = opaque; if (addr & 2) omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); diff --git a/hw/timer/omap_synctimer.c b/hw/timer/omap_synctimer.c index 72b997939bda..d93a9344ede9 100644 --- a/hw/timer/omap_synctimer.c +++ b/hw/timer/omap_synctimer.c @@ -39,7 +39,7 @@ void omap_synctimer_reset(struct omap_synctimer_s *s) static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr) { - struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; + struct omap_synctimer_s *s = opaque; switch (addr) { case 0x00: /* 32KSYNCNT_REV */ @@ -55,7 +55,7 @@ static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr) static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr) { - struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; + struct omap_synctimer_s *s = opaque; uint32_t ret; if (addr & 2) diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c index 2e0fd21a36c3..69eabc678a63 100644 --- a/hw/timer/renesas_cmt.c +++ b/hw/timer/renesas_cmt.c @@ -57,7 +57,7 @@ static void update_events(RCMTState *cmt, int ch) if ((cmt->cmstr & (1 << ch)) == 0) { /* count disable, so not happened next event. */ - return ; + return; } next_time = cmt->cmcor[ch] - cmt->cmcnt[ch]; next_time *= NANOSECONDS_PER_SECOND; diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c index d96002e1ee65..c15f65473810 100644 --- a/hw/timer/renesas_tmr.c +++ b/hw/timer/renesas_tmr.c @@ -67,18 +67,18 @@ static void update_events(RTMRState *tmr, int ch) int i, event; if (tmr->tccr[ch] == 0) { - return ; + return; } if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) { /* external clock mode */ /* event not happened */ - return ; + return; } if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CSS_CASCADING) { /* cascading mode */ if (ch == 1) { tmr->next[ch] = none; - return ; + return; } diff[cmia] = concat_reg(tmr->tcora) - concat_reg(tmr->tcnt); diff[cmib] = concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt); @@ -384,7 +384,7 @@ static void timer_events(RTMRState *tmr, int ch) tmr->tcorb[ch]) & 0xff; } else { if (ch == 1) { - return ; + return; } tcnt = issue_event(tmr, ch, 16, concat_reg(tmr->tcnt), diff --git a/hw/timer/rt_ostimer.c b/hw/timer/rt_ostimer.c new file mode 100644 index 000000000000..0e9cc2633384 --- /dev/null +++ b/hw/timer/rt_ostimer.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/timer.h" +#include "hw/irq.h" +#include "hw/ptimer.h" +#include "hw/qdev-properties.h" +#include "qemu/module.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "sysemu/runstate.h" +#include "sysemu/runstate-action.h" +#include "sysemu/sysemu.h" + +#include "hw/timer/rt_ostimer.h" + +/* TODO Capture feature is not implement */ + +static void rt_ostimer_update(RTOSTIMERState *s) +{ + if (s->EVTIMERH == s->MATCH_H && s->EVTIMERL == s->MATCH_L) + { + s->OSEVENT_CTRL |= OSTIMER_INTRFLAG_MASK; + } + /* Update interrupts. */ + if ((s->OSEVENT_CTRL & OSTIMER_INTENA_MASK) == OSTIMER_INTENA_MASK) { + if ((s->OSEVENT_CTRL & OSTIMER_INTRFLAG_MASK) == OSTIMER_INTRFLAG_MASK) { + qemu_irq_raise(s->irq); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); + //qemu_log("ostimer raise irq 0x%x\n", s->OSEVENT_CTRL); + } + } else { + qemu_irq_lower(s->irq); + } +} + +/* Check all active timers, and schedule the next timer interrupt. */ + +static uint64_t rt_ostimer_read(void *opaque, hwaddr offset, unsigned size) +{ + RTOSTIMERState *s = RT_OSTIMER(opaque); + uint32_t v = 0; + + switch (offset) { + case 0x0: + v = s->EVTIMERL; + break; + case 0x4: + v = s->EVTIMERH; + break; + case 0x8: + v = s->CAPTURE_L; + break; + case 0xc: + v = s->CAPTURE_H; + break; + case 0x10: + v = s->MATCH_L; + break; + case 0x14: + v = s->MATCH_H; + break; + case 0x1C: + v = s->OSEVENT_CTRL; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int)offset); + break; + } + + //printf("[RT_OSTIMER]: read 0x%lx = 0x%x\n", offset, v); + return v; +} + + +static void rt_ostimer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + RTOSTIMERState *s = RT_OSTIMER(opaque); + + //printf("[RT_OSTIMER]: write 0x%lx = 0x%lx\n", offset, value); + + switch (offset) { + case 0x0: + /* RO */ + break; + case 0x4: + /* RO */ + break; + case 0x8: + /* RO */ + break; + case 0xc: + /* RO */ + break; + case 0x10: + s->MATCH_L = value; + break; + case 0x14: + s->MATCH_H = value; + break; + case 0x1C: + s->OSEVENT_CTRL = value; + if ((value & OSTIMER_INTRFLAG_MASK) == OSTIMER_INTRFLAG_MASK) + { + s->OSEVENT_CTRL &= (~OSTIMER_INTRFLAG_MASK); + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int)offset); + } +} + + +static const MemoryRegionOps rt_ostimer_ops = { + .read = rt_ostimer_read, + .write = rt_ostimer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_rt_ostimer = { + .name = TYPE_RT_OSTIMER, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(EVTIMERL, RTOSTIMERState), + VMSTATE_UINT32(EVTIMERH, RTOSTIMERState), + VMSTATE_UINT32(CAPTURE_L, RTOSTIMERState), + VMSTATE_UINT32(CAPTURE_H, RTOSTIMERState), + VMSTATE_UINT32(MATCH_L, RTOSTIMERState), + VMSTATE_UINT32(MATCH_H, RTOSTIMERState), + VMSTATE_UINT32(OSEVENT_CTRL, RTOSTIMERState), + VMSTATE_PTIMER(timer, RTOSTIMERState), + VMSTATE_END_OF_LIST() + } +}; + +static void rt_ostimer_tick(void *opaque) +{ + static uint64_t ticks = 0; + uint64_t r = 0; + RTOSTIMERState *s = RT_OSTIMER(opaque); + + ticks += 1; + //printf("[OSTIMER] r = 0x%lx\n", ticks); + /*convert to gray code*/ + r = ticks^(ticks>>1); + + s->EVTIMERH = (uint32_t)(r>>32); + s->EVTIMERL = (uint32_t)(r&0xFFFFFFFF); + //printf("[OSTIMER] s->EVTIMERL = 0x%x\n", s->EVTIMERL); + //printf("[OSTIMER] s->EVTIMERH = 0x%x\n", s->EVTIMERH); + rt_ostimer_update(s); +} + +static void rt_ostimer_realize(DeviceState *dev, Error **errp) +{ + RTOSTIMERState *s = RT_OSTIMER(dev); + + + s->timer = ptimer_init(rt_ostimer_tick, s, PTIMER_POLICY_CONTINUOUS_TRIGGER | PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD); + ptimer_transaction_begin(s->timer); + ptimer_set_freq(s->timer, 1000000); + ptimer_run(s->timer, 0); + ptimer_transaction_commit(s->timer); +} + + +static void rt_ostimer_unrealize(DeviceState *dev) +{ + RTOSTIMERState *s = RT_OSTIMER(dev); + + if(s->timer) { + ptimer_transaction_begin(s->timer); + ptimer_stop(s->timer); + ptimer_transaction_commit(s->timer); + ptimer_free(s->timer); + s->timer = NULL; + } +} + +static void rt_ostimer_init(Object *obj) +{ + RTOSTIMERState *s = RT_OSTIMER(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->iomem, obj, &rt_ostimer_ops, s, + TYPE_RT_OSTIMER, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); +} + +static void rt_ostimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rt_ostimer_realize; + dc->unrealize = rt_ostimer_unrealize; + dc->vmsd = &vmstate_rt_ostimer; +} + +static const TypeInfo rt_ostimer_info = { + .name = TYPE_RT_OSTIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTOSTIMERState), + .instance_init = rt_ostimer_init, + .class_init = rt_ostimer_class_init, +}; + +static void rt_ostimer_register_types(void) +{ + type_register_static(&rt_ostimer_info); +} + +type_init(rt_ostimer_register_types) diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index c72c327bfafa..77889397669a 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -239,7 +239,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) s->enabled = 0; s->irq = irq; - s->timer = ptimer_init(sh_timer_tick, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(sh_timer_tick, s, PTIMER_POLICY_LEGACY); sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index 90fdce4c442b..8c4f6eb06b6c 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -405,7 +405,7 @@ static void slavio_timer_init(Object *obj) tc->timer_index = i; s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->cputimer[i].timer); ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); ptimer_transaction_commit(s->cputimer[i].timer); diff --git a/hw/timer/sse-timer.c b/hw/timer/sse-timer.c index f959cb9d6033..e92e83747d2a 100644 --- a/hw/timer/sse-timer.c +++ b/hw/timer/sse-timer.c @@ -324,7 +324,7 @@ static void sse_timer_write(void *opaque, hwaddr offset, uint64_t value, { uint32_t old_ctl = s->cntp_aival_ctl; - /* EN bit is writeable; CLR bit is write-0-to-clear, write-1-ignored */ + /* EN bit is writable; CLR bit is write-0-to-clear, write-1-ignored */ s->cntp_aival_ctl &= ~R_CNTP_AIVAL_CTL_EN_MASK; s->cntp_aival_ctl |= value & R_CNTP_AIVAL_CTL_EN_MASK; if (!(value & R_CNTP_AIVAL_CTL_CLR_MASK)) { diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 1eb927eb8473..32a9df69e0b3 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -62,10 +62,10 @@ struct xlx_timer }; #define TYPE_XILINX_TIMER "xlnx.xps-timer" -DECLARE_INSTANCE_CHECKER(struct timerblock, XILINX_TIMER, - TYPE_XILINX_TIMER) +typedef struct XpsTimerState XpsTimerState; +DECLARE_INSTANCE_CHECKER(XpsTimerState, XILINX_TIMER, TYPE_XILINX_TIMER) -struct timerblock +struct XpsTimerState { SysBusDevice parent_obj; @@ -76,7 +76,7 @@ struct timerblock struct xlx_timer *timers; }; -static inline unsigned int num_timers(struct timerblock *t) +static inline unsigned int num_timers(XpsTimerState *t) { return 2 - t->one_timer_only; } @@ -87,7 +87,7 @@ static inline unsigned int timer_from_addr(hwaddr addr) return addr >> 2; } -static void timer_update_irq(struct timerblock *t) +static void timer_update_irq(XpsTimerState *t) { unsigned int i, irq = 0; uint32_t csr; @@ -104,7 +104,7 @@ static void timer_update_irq(struct timerblock *t) static uint64_t timer_read(void *opaque, hwaddr addr, unsigned int size) { - struct timerblock *t = opaque; + XpsTimerState *t = opaque; struct xlx_timer *xt; uint32_t r = 0; unsigned int timer; @@ -155,7 +155,7 @@ static void timer_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct timerblock *t = opaque; + XpsTimerState *t = opaque; struct xlx_timer *xt; unsigned int timer; uint32_t value = val64; @@ -202,7 +202,7 @@ static const MemoryRegionOps timer_ops = { static void timer_hit(void *opaque) { struct xlx_timer *xt = opaque; - struct timerblock *t = xt->parent; + XpsTimerState *t = xt->parent; D(fprintf(stderr, "%s %d\n", __func__, xt->nr)); xt->regs[R_TCSR] |= TCSR_TINT; @@ -213,7 +213,7 @@ static void timer_hit(void *opaque) static void xilinx_timer_realize(DeviceState *dev, Error **errp) { - struct timerblock *t = XILINX_TIMER(dev); + XpsTimerState *t = XILINX_TIMER(dev); unsigned int i; /* Init all the ptimers. */ @@ -223,7 +223,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp) xt->parent = t; xt->nr = i; - xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_DEFAULT); + xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(xt->ptimer); ptimer_set_freq(xt->ptimer, t->freq_hz); ptimer_transaction_commit(xt->ptimer); @@ -236,16 +236,15 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp) static void xilinx_timer_init(Object *obj) { - struct timerblock *t = XILINX_TIMER(obj); + XpsTimerState *t = XILINX_TIMER(obj); /* All timers share a single irq line. */ sysbus_init_irq(SYS_BUS_DEVICE(obj), &t->irq); } static Property xilinx_timer_properties[] = { - DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz, - 62 * 1000000), - DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0), + DEFINE_PROP_UINT32("clock-frequency", XpsTimerState, freq_hz, 62 * 1000000), + DEFINE_PROP_UINT8("one-timer-only", XpsTimerState, one_timer_only, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -260,7 +259,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) static const TypeInfo xilinx_timer_info = { .name = TYPE_XILINX_TIMER, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct timerblock), + .instance_size = sizeof(XpsTimerState), .instance_init = xilinx_timer_init, .class_init = xilinx_timer_class_init, }; diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index aa9c00aad3a3..ea930da545af 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" @@ -197,6 +198,7 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret) ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, tpmSts, 1); /* fatal error */ } + memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE); } static enum TPMVersion tpm_crb_get_version(TPMIf *ti) @@ -307,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/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c index c89ac53e65e6..7f74e26ec6c9 100644 --- a/hw/tpm/tpm_ppi.c +++ b/hw/tpm/tpm_ppi.c @@ -47,7 +47,7 @@ void tpm_ppi_reset(TPMPPI *tpmppi) void tpm_ppi_init(TPMPPI *tpmppi, MemoryRegion *m, hwaddr addr, Object *obj) { - tpmppi->buf = qemu_memalign(qemu_real_host_page_size, + tpmppi->buf = qemu_memalign(qemu_real_host_page_size(), HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", TPM_PPI_ADDR_SIZE, tpmppi->buf); diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index e700d821816a..503be2a541d8 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -50,7 +50,12 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, static uint8_t tpm_tis_locality_from_addr(hwaddr addr) { - return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + uint8_t locty; + + locty = (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + assert(TPM_TIS_IS_VALID_LOCTY(locty)); + + return locty; } diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index 3477afd7357e..91e37922484b 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -30,6 +30,7 @@ #include "tpm_prop.h" #include "tpm_tis.h" #include "qom/object.h" +#include "hw/acpi/acpi_aml_interface.h" struct TPMStateISA { /*< private >*/ @@ -138,10 +139,39 @@ static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) } } +static void build_tpm_tis_isa_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + Aml *dev, *crs; + TPMStateISA *isadev = TPM_TIS_ISA(adev); + TPMIf *ti = TPM_IF(isadev); + + dev = aml_device("TPM"); + if (tpm_tis_isa_get_tpm_version(ti) == TPM_VERSION_2_0) { + aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); + aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); + } else { + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); + } + aml_append(dev, aml_name_decl("_UID", aml_int(1))); + aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE, + AML_READ_WRITE)); + /* + * FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs, + * fix default TPM_TIS_IRQ value there to use some unused IRQ + */ + /* aml_append(crs, aml_irq_no_flags(isadev->state.irq_num)); */ + aml_append(dev, aml_name_decl("_CRS", crs)); + tpm_build_ppi_acpi(ti, dev); + aml_append(scope, dev); +} + static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); TPMIfClass *tc = TPM_IF_CLASS(klass); + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); device_class_set_props(dc, tpm_tis_isa_properties); dc->vmsd = &vmstate_tpm_tis_isa; @@ -151,6 +181,7 @@ static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) tc->request_completed = tpm_tis_isa_request_completed; tc->get_version = tpm_tis_isa_get_tpm_version; set_bit(DEVICE_CATEGORY_MISC, dc->categories); + adevc->build_dev_aml = build_tpm_tis_isa_aml; } static const TypeInfo tpm_tis_isa_info = { @@ -161,6 +192,7 @@ static const TypeInfo tpm_tis_isa_info = { .class_init = tpm_tis_isa_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_TPM_IF }, + { TYPE_ACPI_DEV_AML_IF }, { } } }; diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index 6c8c0355e099..ee41a818014b 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -140,7 +140,7 @@ static void emulated_apdu_from_guest(CCIDCardState *base, const uint8_t *apdu, uint32_t len) { EmulatedState *card = EMULATED_CCID_CARD(base); - EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len); + EmulEvent *event = g_malloc(sizeof(EmulEvent) + len); assert(event); event->p.data.type = EMUL_GUEST_APDU; @@ -613,6 +613,7 @@ static const TypeInfo emulated_card_info = { .class_init = emulated_class_initfn, }; module_obj(TYPE_EMULATED_CCID); +module_kconfig(USB); static void ccid_card_emulated_register_types(void) { diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index fa3040fb7154..07ee42f304f9 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/cutils.h" #include "qemu/units.h" #include #include "chardev/char-fe.h" @@ -415,6 +415,7 @@ static const TypeInfo passthru_card_info = { .class_init = passthru_class_initfn, }; module_obj(TYPE_CCID_PASSTHRU); +module_kconfig(USB); static void ccid_card_passthru_register_types(void) { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index e35813d77222..a6b50dbc8df8 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -54,44 +54,44 @@ struct USBHubState { #define TYPE_USB_HUB "usb-hub" OBJECT_DECLARE_SIMPLE_TYPE(USBHubState, USB_HUB) -#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) -#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) -#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) -#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) -#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) -#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) -#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) - -#define PORT_STAT_CONNECTION 0x0001 -#define PORT_STAT_ENABLE 0x0002 -#define PORT_STAT_SUSPEND 0x0004 -#define PORT_STAT_OVERCURRENT 0x0008 -#define PORT_STAT_RESET 0x0010 -#define PORT_STAT_POWER 0x0100 -#define PORT_STAT_LOW_SPEED 0x0200 +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + +#define PORT_STAT_CONNECTION 0x0001 +#define PORT_STAT_ENABLE 0x0002 +#define PORT_STAT_SUSPEND 0x0004 +#define PORT_STAT_OVERCURRENT 0x0008 +#define PORT_STAT_RESET 0x0010 +#define PORT_STAT_POWER 0x0100 +#define PORT_STAT_LOW_SPEED 0x0200 #define PORT_STAT_HIGH_SPEED 0x0400 #define PORT_STAT_TEST 0x0800 #define PORT_STAT_INDICATOR 0x1000 -#define PORT_STAT_C_CONNECTION 0x0001 -#define PORT_STAT_C_ENABLE 0x0002 -#define PORT_STAT_C_SUSPEND 0x0004 -#define PORT_STAT_C_OVERCURRENT 0x0008 -#define PORT_STAT_C_RESET 0x0010 - -#define PORT_CONNECTION 0 -#define PORT_ENABLE 1 -#define PORT_SUSPEND 2 -#define PORT_OVERCURRENT 3 -#define PORT_RESET 4 -#define PORT_POWER 8 -#define PORT_LOWSPEED 9 -#define PORT_HIGHSPEED 10 -#define PORT_C_CONNECTION 16 -#define PORT_C_ENABLE 17 -#define PORT_C_SUSPEND 18 -#define PORT_C_OVERCURRENT 19 -#define PORT_C_RESET 20 +#define PORT_STAT_C_CONNECTION 0x0001 +#define PORT_STAT_C_ENABLE 0x0002 +#define PORT_STAT_C_SUSPEND 0x0004 +#define PORT_STAT_C_OVERCURRENT 0x0008 +#define PORT_STAT_C_RESET 0x0010 + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVERCURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOWSPEED 9 +#define PORT_HIGHSPEED 10 +#define PORT_C_CONNECTION 16 +#define PORT_C_ENABLE 17 +#define PORT_C_SUSPEND 18 +#define PORT_C_OVERCURRENT 19 +#define PORT_C_RESET 20 #define PORT_TEST 21 #define PORT_INDICATOR 22 @@ -155,13 +155,13 @@ static const USBDesc desc_hub = { static const uint8_t qemu_hub_hub_descriptor[] = { - 0x00, /* u8 bLength; patched in later */ - 0x29, /* u8 bDescriptorType; Hub-descriptor */ - 0x00, /* u8 bNbrPorts; (patched later) */ - 0x0a, /* u16 wHubCharacteristics; */ - 0x00, /* (per-port OC, no power switching) */ - 0x01, /* u8 bPwrOn2pwrGood; 2ms */ - 0x00 /* u8 bHubContrCurrent; 0 mA */ + 0x00, /* u8 bLength; patched in later */ + 0x29, /* u8 bDescriptorType; Hub-descriptor */ + 0x00, /* u8 bNbrPorts; (patched later) */ + 0x0a, /* u16 wHubCharacteristics; */ + 0x00, /* (per-port OC, no power switching) */ + 0x01, /* u8 bPwrOn2pwrGood; 2ms */ + 0x00 /* u8 bHubContrCurrent; 0 mA */ /* DeviceRemovable and PortPwrCtrlMask patched in later */ }; diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index e6b77a2a941d..1cac1cd43505 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -10,12 +10,11 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/error-report.h" #include #include - +#include #include @@ -1623,7 +1622,7 @@ static void usb_mtp_write_data(MTPState *s, uint32_t handle) if (s->dataset.filename) { path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename); if (s->dataset.format == FMT_ASSOCIATION) { - ret = mkdir(path, mask); + ret = g_mkdir(path, mask); if (!ret) { usb_mtp_queue_result(s, RES_OK, d->trans, 3, QEMU_STORAGE_ID, diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 6c49c16015e0..5fff487ee5d2 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -52,7 +52,7 @@ #define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ enum usbstring_idx { - STRING_MANUFACTURER = 1, + STRING_MANUFACTURER = 1, STRING_PRODUCT, STRING_ETHADDR, STRING_DATA, @@ -64,37 +64,39 @@ enum usbstring_idx { STRING_SERIALNUMBER, }; -#define DEV_CONFIG_VALUE 1 /* CDC or a subset */ -#define DEV_RNDIS_CONFIG_VALUE 2 /* RNDIS; optional */ +#define DEV_CONFIG_VALUE 1 /* CDC or a subset */ +#define DEV_RNDIS_CONFIG_VALUE 2 /* RNDIS; optional */ -#define USB_CDC_SUBCLASS_ACM 0x02 -#define USB_CDC_SUBCLASS_ETHERNET 0x06 +#define USB_CDC_SUBCLASS_ACM 0x02 +#define USB_CDC_SUBCLASS_ETHERNET 0x06 -#define USB_CDC_PROTO_NONE 0 -#define USB_CDC_ACM_PROTO_VENDOR 0xff +#define USB_CDC_PROTO_NONE 0 +#define USB_CDC_ACM_PROTO_VENDOR 0xff -#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ -#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ -#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ -#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ -#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ +#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ +#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ +#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ +#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ +#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ -#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 -#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 -#define USB_CDC_REQ_SET_LINE_CODING 0x20 -#define USB_CDC_REQ_GET_LINE_CODING 0x21 -#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 -#define USB_CDC_REQ_SEND_BREAK 0x23 -#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 -#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 -#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 -#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 -#define USB_CDC_GET_ETHERNET_STATISTIC 0x44 +#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define USB_CDC_REQ_SET_LINE_CODING 0x20 +#define USB_CDC_REQ_GET_LINE_CODING 0x21 +#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 +#define USB_CDC_REQ_SEND_BREAK 0x23 +#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 +#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 +#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define USB_CDC_GET_ETHERNET_STATISTIC 0x44 -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ -#define STATUS_BYTECOUNT 16 /* 8 byte header + data */ +#define USB_CDC_NETWORK_CONNECTION 0x00 -#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ +#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define STATUS_BYTECOUNT 16 /* 8 byte header + data */ + +#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ static const USBDescStrings usb_net_stringtable = { [STRING_MANUFACTURER] = "QEMU", @@ -304,57 +306,57 @@ static const USBDesc desc_net = { /* * RNDIS Definitions - in theory not specific to USB. */ -#define RNDIS_MAXIMUM_FRAME_SIZE 1518 -#define RNDIS_MAX_TOTAL_SIZE 1558 +#define RNDIS_MAXIMUM_FRAME_SIZE 1518 +#define RNDIS_MAX_TOTAL_SIZE 1558 /* Remote NDIS Versions */ -#define RNDIS_MAJOR_VERSION 1 -#define RNDIS_MINOR_VERSION 0 +#define RNDIS_MAJOR_VERSION 1 +#define RNDIS_MINOR_VERSION 0 /* Status Values */ -#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ -#define RNDIS_STATUS_FAILURE 0xc0000001U /* Unspecified error */ -#define RNDIS_STATUS_INVALID_DATA 0xc0010015U /* Invalid data */ -#define RNDIS_STATUS_NOT_SUPPORTED 0xc00000bbU /* Unsupported request */ -#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000bU /* Device connected */ -#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000cU /* Device disconnected */ +#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ +#define RNDIS_STATUS_FAILURE 0xc0000001U /* Unspecified error */ +#define RNDIS_STATUS_INVALID_DATA 0xc0010015U /* Invalid data */ +#define RNDIS_STATUS_NOT_SUPPORTED 0xc00000bbU /* Unsupported request */ +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000bU /* Device connected */ +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000cU /* Device disconnected */ /* Message Set for Connectionless (802.3) Devices */ enum { - RNDIS_PACKET_MSG = 1, - RNDIS_INITIALIZE_MSG = 2, /* Initialize device */ - RNDIS_HALT_MSG = 3, - RNDIS_QUERY_MSG = 4, - RNDIS_SET_MSG = 5, - RNDIS_RESET_MSG = 6, - RNDIS_INDICATE_STATUS_MSG = 7, - RNDIS_KEEPALIVE_MSG = 8, + RNDIS_PACKET_MSG = 1, + RNDIS_INITIALIZE_MSG = 2, /* Initialize device */ + RNDIS_HALT_MSG = 3, + RNDIS_QUERY_MSG = 4, + RNDIS_SET_MSG = 5, + RNDIS_RESET_MSG = 6, + RNDIS_INDICATE_STATUS_MSG = 7, + RNDIS_KEEPALIVE_MSG = 8, }; /* Message completion */ enum { - RNDIS_INITIALIZE_CMPLT = 0x80000002U, - RNDIS_QUERY_CMPLT = 0x80000004U, - RNDIS_SET_CMPLT = 0x80000005U, - RNDIS_RESET_CMPLT = 0x80000006U, - RNDIS_KEEPALIVE_CMPLT = 0x80000008U, + RNDIS_INITIALIZE_CMPLT = 0x80000002U, + RNDIS_QUERY_CMPLT = 0x80000004U, + RNDIS_SET_CMPLT = 0x80000005U, + RNDIS_RESET_CMPLT = 0x80000006U, + RNDIS_KEEPALIVE_CMPLT = 0x80000008U, }; /* Device Flags */ enum { - RNDIS_DF_CONNECTIONLESS = 1, - RNDIS_DF_CONNECTIONORIENTED = 2, + RNDIS_DF_CONNECTIONLESS = 1, + RNDIS_DF_CONNECTIONORIENTED = 2, }; -#define RNDIS_MEDIUM_802_3 0x00000000U +#define RNDIS_MEDIUM_802_3 0x00000000U /* from drivers/net/sk98lin/h/skgepnmi.h */ -#define OID_PNP_CAPABILITIES 0xfd010100 -#define OID_PNP_SET_POWER 0xfd010101 -#define OID_PNP_QUERY_POWER 0xfd010102 -#define OID_PNP_ADD_WAKE_UP_PATTERN 0xfd010103 -#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xfd010104 -#define OID_PNP_ENABLE_WAKE_UP 0xfd010106 +#define OID_PNP_CAPABILITIES 0xfd010100 +#define OID_PNP_SET_POWER 0xfd010101 +#define OID_PNP_QUERY_POWER 0xfd010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xfd010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xfd010104 +#define OID_PNP_ENABLE_WAKE_UP 0xfd010106 typedef uint32_t le32; @@ -492,88 +494,88 @@ enum rndis_state /* from ndis.h */ enum ndis_oid { /* Required Object IDs (OIDs) */ - OID_GEN_SUPPORTED_LIST = 0x00010101, - OID_GEN_HARDWARE_STATUS = 0x00010102, - OID_GEN_MEDIA_SUPPORTED = 0x00010103, - OID_GEN_MEDIA_IN_USE = 0x00010104, - OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, - OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, - OID_GEN_LINK_SPEED = 0x00010107, - OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, - OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, - OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010a, - OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010b, - OID_GEN_VENDOR_ID = 0x0001010c, - OID_GEN_VENDOR_DESCRIPTION = 0x0001010d, - OID_GEN_CURRENT_PACKET_FILTER = 0x0001010e, - OID_GEN_CURRENT_LOOKAHEAD = 0x0001010f, - OID_GEN_DRIVER_VERSION = 0x00010110, - OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, - OID_GEN_PROTOCOL_OPTIONS = 0x00010112, - OID_GEN_MAC_OPTIONS = 0x00010113, - OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, - OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, - OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, - OID_GEN_SUPPORTED_GUIDS = 0x00010117, - OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, - OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, - OID_GEN_MACHINE_NAME = 0x0001021a, - OID_GEN_RNDIS_CONFIG_PARAMETER = 0x0001021b, - OID_GEN_VLAN_ID = 0x0001021c, + OID_GEN_SUPPORTED_LIST = 0x00010101, + OID_GEN_HARDWARE_STATUS = 0x00010102, + OID_GEN_MEDIA_SUPPORTED = 0x00010103, + OID_GEN_MEDIA_IN_USE = 0x00010104, + OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, + OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, + OID_GEN_LINK_SPEED = 0x00010107, + OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, + OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, + OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010a, + OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010b, + OID_GEN_VENDOR_ID = 0x0001010c, + OID_GEN_VENDOR_DESCRIPTION = 0x0001010d, + OID_GEN_CURRENT_PACKET_FILTER = 0x0001010e, + OID_GEN_CURRENT_LOOKAHEAD = 0x0001010f, + OID_GEN_DRIVER_VERSION = 0x00010110, + OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, + OID_GEN_PROTOCOL_OPTIONS = 0x00010112, + OID_GEN_MAC_OPTIONS = 0x00010113, + OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, + OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, + OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, + OID_GEN_SUPPORTED_GUIDS = 0x00010117, + OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, + OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, + OID_GEN_MACHINE_NAME = 0x0001021a, + OID_GEN_RNDIS_CONFIG_PARAMETER = 0x0001021b, + OID_GEN_VLAN_ID = 0x0001021c, /* Optional OIDs */ - OID_GEN_MEDIA_CAPABILITIES = 0x00010201, - OID_GEN_PHYSICAL_MEDIUM = 0x00010202, + OID_GEN_MEDIA_CAPABILITIES = 0x00010201, + OID_GEN_PHYSICAL_MEDIUM = 0x00010202, /* Required statistics OIDs */ - OID_GEN_XMIT_OK = 0x00020101, - OID_GEN_RCV_OK = 0x00020102, - OID_GEN_XMIT_ERROR = 0x00020103, - OID_GEN_RCV_ERROR = 0x00020104, - OID_GEN_RCV_NO_BUFFER = 0x00020105, + OID_GEN_XMIT_OK = 0x00020101, + OID_GEN_RCV_OK = 0x00020102, + OID_GEN_XMIT_ERROR = 0x00020103, + OID_GEN_RCV_ERROR = 0x00020104, + OID_GEN_RCV_NO_BUFFER = 0x00020105, /* Optional statistics OIDs */ - OID_GEN_DIRECTED_BYTES_XMIT = 0x00020201, - OID_GEN_DIRECTED_FRAMES_XMIT = 0x00020202, - OID_GEN_MULTICAST_BYTES_XMIT = 0x00020203, - OID_GEN_MULTICAST_FRAMES_XMIT = 0x00020204, - OID_GEN_BROADCAST_BYTES_XMIT = 0x00020205, - OID_GEN_BROADCAST_FRAMES_XMIT = 0x00020206, - OID_GEN_DIRECTED_BYTES_RCV = 0x00020207, - OID_GEN_DIRECTED_FRAMES_RCV = 0x00020208, - OID_GEN_MULTICAST_BYTES_RCV = 0x00020209, - OID_GEN_MULTICAST_FRAMES_RCV = 0x0002020a, - OID_GEN_BROADCAST_BYTES_RCV = 0x0002020b, - OID_GEN_BROADCAST_FRAMES_RCV = 0x0002020c, - OID_GEN_RCV_CRC_ERROR = 0x0002020d, - OID_GEN_TRANSMIT_QUEUE_LENGTH = 0x0002020e, - OID_GEN_GET_TIME_CAPS = 0x0002020f, - OID_GEN_GET_NETCARD_TIME = 0x00020210, - OID_GEN_NETCARD_LOAD = 0x00020211, - OID_GEN_DEVICE_PROFILE = 0x00020212, - OID_GEN_INIT_TIME_MS = 0x00020213, - OID_GEN_RESET_COUNTS = 0x00020214, - OID_GEN_MEDIA_SENSE_COUNTS = 0x00020215, - OID_GEN_FRIENDLY_NAME = 0x00020216, - OID_GEN_MINIPORT_INFO = 0x00020217, - OID_GEN_RESET_VERIFY_PARAMETERS = 0x00020218, + OID_GEN_DIRECTED_BYTES_XMIT = 0x00020201, + OID_GEN_DIRECTED_FRAMES_XMIT = 0x00020202, + OID_GEN_MULTICAST_BYTES_XMIT = 0x00020203, + OID_GEN_MULTICAST_FRAMES_XMIT = 0x00020204, + OID_GEN_BROADCAST_BYTES_XMIT = 0x00020205, + OID_GEN_BROADCAST_FRAMES_XMIT = 0x00020206, + OID_GEN_DIRECTED_BYTES_RCV = 0x00020207, + OID_GEN_DIRECTED_FRAMES_RCV = 0x00020208, + OID_GEN_MULTICAST_BYTES_RCV = 0x00020209, + OID_GEN_MULTICAST_FRAMES_RCV = 0x0002020a, + OID_GEN_BROADCAST_BYTES_RCV = 0x0002020b, + OID_GEN_BROADCAST_FRAMES_RCV = 0x0002020c, + OID_GEN_RCV_CRC_ERROR = 0x0002020d, + OID_GEN_TRANSMIT_QUEUE_LENGTH = 0x0002020e, + OID_GEN_GET_TIME_CAPS = 0x0002020f, + OID_GEN_GET_NETCARD_TIME = 0x00020210, + OID_GEN_NETCARD_LOAD = 0x00020211, + OID_GEN_DEVICE_PROFILE = 0x00020212, + OID_GEN_INIT_TIME_MS = 0x00020213, + OID_GEN_RESET_COUNTS = 0x00020214, + OID_GEN_MEDIA_SENSE_COUNTS = 0x00020215, + OID_GEN_FRIENDLY_NAME = 0x00020216, + OID_GEN_MINIPORT_INFO = 0x00020217, + OID_GEN_RESET_VERIFY_PARAMETERS = 0x00020218, /* IEEE 802.3 (Ethernet) OIDs */ - OID_802_3_PERMANENT_ADDRESS = 0x01010101, - OID_802_3_CURRENT_ADDRESS = 0x01010102, - OID_802_3_MULTICAST_LIST = 0x01010103, - OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, - OID_802_3_MAC_OPTIONS = 0x01010105, - OID_802_3_RCV_ERROR_ALIGNMENT = 0x01020101, - OID_802_3_XMIT_ONE_COLLISION = 0x01020102, - OID_802_3_XMIT_MORE_COLLISIONS = 0x01020103, - OID_802_3_XMIT_DEFERRED = 0x01020201, - OID_802_3_XMIT_MAX_COLLISIONS = 0x01020202, - OID_802_3_RCV_OVERRUN = 0x01020203, - OID_802_3_XMIT_UNDERRUN = 0x01020204, - OID_802_3_XMIT_HEARTBEAT_FAILURE = 0x01020205, - OID_802_3_XMIT_TIMES_CRS_LOST = 0x01020206, - OID_802_3_XMIT_LATE_COLLISIONS = 0x01020207, + OID_802_3_PERMANENT_ADDRESS = 0x01010101, + OID_802_3_CURRENT_ADDRESS = 0x01010102, + OID_802_3_MULTICAST_LIST = 0x01010103, + OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, + OID_802_3_MAC_OPTIONS = 0x01010105, + OID_802_3_RCV_ERROR_ALIGNMENT = 0x01020101, + OID_802_3_XMIT_ONE_COLLISION = 0x01020102, + OID_802_3_XMIT_MORE_COLLISIONS = 0x01020103, + OID_802_3_XMIT_DEFERRED = 0x01020201, + OID_802_3_XMIT_MAX_COLLISIONS = 0x01020202, + OID_802_3_RCV_OVERRUN = 0x01020203, + OID_802_3_XMIT_UNDERRUN = 0x01020204, + OID_802_3_XMIT_HEARTBEAT_FAILURE = 0x01020205, + OID_802_3_XMIT_TIMES_CRS_LOST = 0x01020206, + OID_802_3_XMIT_LATE_COLLISIONS = 0x01020207, }; static const uint32_t oid_supported_list[] = @@ -616,13 +618,13 @@ static const uint32_t oid_supported_list[] = OID_802_3_XMIT_MORE_COLLISIONS, }; -#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA (1 << 0) -#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED (1 << 1) -#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND (1 << 2) -#define NDIS_MAC_OPTION_NO_LOOPBACK (1 << 3) -#define NDIS_MAC_OPTION_FULL_DUPLEX (1 << 4) -#define NDIS_MAC_OPTION_EOTX_INDICATION (1 << 5) -#define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6) +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA (1 << 0) +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED (1 << 1) +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND (1 << 2) +#define NDIS_MAC_OPTION_NO_LOOPBACK (1 << 3) +#define NDIS_MAC_OPTION_FULL_DUPLEX (1 << 4) +#define NDIS_MAC_OPTION_EOTX_INDICATION (1 << 5) +#define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6) struct rndis_response { QTAILQ_ENTRY(rndis_response) entries; @@ -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; } @@ -1353,12 +1375,14 @@ static void usb_net_realize(USBDevice *dev, Error **errp) s->rndis_state = RNDIS_UNINITIALIZED; QTAILQ_INIT(&s->rndis_resp); - s->medium = 0; /* NDIS_MEDIUM_802_3 */ + s->medium = 0; /* NDIS_MEDIUM_802_3 */ s->speed = 1000000; /* 100MBps, in 100Bps units */ - s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; + 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-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 91ffd9f8ae8d..28164d89be27 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -37,7 +37,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "qemu-common.h" +#include "qemu/cutils.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "hw/qdev-properties.h" diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index dca62d544fe9..e3bcffb3e0d7 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 c9f295e7e449..88f99c05d53d 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); } @@ -790,7 +791,7 @@ static void usb_uas_task(UASDevice *uas, uas_iu *iu) case UAS_TMF_LOGICAL_UNIT_RESET: trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun); - qdev_reset_all(&dev->qdev); + device_cold_reset(&dev->qdev); usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE); break; diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 8323650c6a4d..7177c17f0312 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -36,8 +36,8 @@ #include "qom/object.h" /* Interface requests */ -#define WACOM_GET_REPORT 0x2101 -#define WACOM_SET_REPORT 0x2109 +#define WACOM_GET_REPORT 0x2101 +#define WACOM_SET_REPORT 0x2109 struct USBWacomState { USBDevice dev; diff --git a/hw/usb/hcd-dwc2.h b/hw/usb/hcd-dwc2.h index 6998b04706da..9c3d88ea14bb 100644 --- a/hw/usb/hcd-dwc2.h +++ b/hw/usb/hcd-dwc2.h @@ -16,8 +16,8 @@ * GNU General Public License for more details. */ -#ifndef HW_USB_DWC2_H -#define HW_USB_DWC2_H +#ifndef HW_USB_HCD_DWC2_H +#define HW_USB_HCD_DWC2_H #include "qemu/timer.h" #include "hw/irq.h" diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 33a8a377bd95..d4da8dcb8d15 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2011,7 +2011,10 @@ static int ehci_state_writeback(EHCIQueue *q) ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd); qtd = (uint32_t *) &q->qh.next_qtd; addr = NLPTR_GET(p->qtdaddr); - put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2); + /* First write back the offset */ + put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qtd + 3, 1); + /* Then write back the token, clearing the 'active' bit */ + put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 1); ehci_free_packet(p); /* diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index a173707d9bf8..2cd821f49e48 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -21,9 +21,8 @@ #include "qemu/timer.h" #include "hw/usb.h" #include "sysemu/dma.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/sysbus.h" -#include "qom/object.h" #ifndef EHCI_DEBUG #define EHCI_DEBUG 0 diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index 85f5ff5bd48d..6dca373cb1fa 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -28,227 +28,227 @@ #include "hw/hw.h" /* Common USB registers */ -#define MUSB_HDRC_FADDR 0x00 /* 8-bit */ -#define MUSB_HDRC_POWER 0x01 /* 8-bit */ - -#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */ -#define MUSB_HDRC_INTRRX 0x04 -#define MUSB_HDRC_INTRTXE 0x06 -#define MUSB_HDRC_INTRRXE 0x08 -#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */ -#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */ -#define MUSB_HDRC_FRAME 0x0c /* 16-bit */ -#define MUSB_HDRC_INDEX 0x0e /* 8 bit */ -#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */ +#define MUSB_HDRC_FADDR 0x00 /* 8-bit */ +#define MUSB_HDRC_POWER 0x01 /* 8-bit */ + +#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */ +#define MUSB_HDRC_INTRRX 0x04 +#define MUSB_HDRC_INTRTXE 0x06 +#define MUSB_HDRC_INTRRXE 0x08 +#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */ +#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */ +#define MUSB_HDRC_FRAME 0x0c /* 16-bit */ +#define MUSB_HDRC_INDEX 0x0e /* 8 bit */ +#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */ /* Per-EP registers in indexed mode */ -#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */ +#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */ /* EP FIFOs */ -#define MUSB_HDRC_FIFO 0x20 +#define MUSB_HDRC_FIFO 0x20 /* Additional Control Registers */ -#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */ +#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */ /* These are indexed */ -#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */ -#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */ -#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */ -#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */ +#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */ +#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */ +#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */ +#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */ /* Some more registers */ -#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */ -#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */ +#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */ +#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */ /* Added in HDRC 1.9(?) & MHDRC 1.4 */ /* ULPI pass-through */ -#define MUSB_HDRC_ULPI_VBUSCTL 0x70 -#define MUSB_HDRC_ULPI_REGDATA 0x74 -#define MUSB_HDRC_ULPI_REGADDR 0x75 -#define MUSB_HDRC_ULPI_REGCTL 0x76 +#define MUSB_HDRC_ULPI_VBUSCTL 0x70 +#define MUSB_HDRC_ULPI_REGDATA 0x74 +#define MUSB_HDRC_ULPI_REGADDR 0x75 +#define MUSB_HDRC_ULPI_REGCTL 0x76 /* Extended config & PHY control */ -#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */ -#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */ -#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */ -#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */ -#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */ -#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */ -#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */ +#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */ +#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */ +#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */ +#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */ +#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */ +#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */ +#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */ /* Per-EP BUSCTL registers */ -#define MUSB_HDRC_BUSCTL 0x80 +#define MUSB_HDRC_BUSCTL 0x80 /* Per-EP registers in flat mode */ -#define MUSB_HDRC_EP 0x100 +#define MUSB_HDRC_EP 0x100 /* offsets to registers in flat model */ -#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */ -#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */ -#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */ -#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */ -#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */ -#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */ -#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */ -#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */ -#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */ -#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */ -#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */ -#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */ -#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */ -#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */ -#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */ +#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */ +#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */ +#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */ +#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */ +#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */ +#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */ +#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */ +#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */ +#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */ +#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */ +#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */ +#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */ +#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */ +#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */ +#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */ /* "Bus control" registers */ -#define MUSB_HDRC_TXFUNCADDR 0x00 -#define MUSB_HDRC_TXHUBADDR 0x02 -#define MUSB_HDRC_TXHUBPORT 0x03 +#define MUSB_HDRC_TXFUNCADDR 0x00 +#define MUSB_HDRC_TXHUBADDR 0x02 +#define MUSB_HDRC_TXHUBPORT 0x03 -#define MUSB_HDRC_RXFUNCADDR 0x04 -#define MUSB_HDRC_RXHUBADDR 0x06 -#define MUSB_HDRC_RXHUBPORT 0x07 +#define MUSB_HDRC_RXFUNCADDR 0x04 +#define MUSB_HDRC_RXHUBADDR 0x06 +#define MUSB_HDRC_RXHUBPORT 0x07 /* * MUSBHDRC Register bit masks */ /* POWER */ -#define MGC_M_POWER_ISOUPDATE 0x80 -#define MGC_M_POWER_SOFTCONN 0x40 -#define MGC_M_POWER_HSENAB 0x20 -#define MGC_M_POWER_HSMODE 0x10 -#define MGC_M_POWER_RESET 0x08 -#define MGC_M_POWER_RESUME 0x04 -#define MGC_M_POWER_SUSPENDM 0x02 -#define MGC_M_POWER_ENSUSPEND 0x01 +#define MGC_M_POWER_ISOUPDATE 0x80 +#define MGC_M_POWER_SOFTCONN 0x40 +#define MGC_M_POWER_HSENAB 0x20 +#define MGC_M_POWER_HSMODE 0x10 +#define MGC_M_POWER_RESET 0x08 +#define MGC_M_POWER_RESUME 0x04 +#define MGC_M_POWER_SUSPENDM 0x02 +#define MGC_M_POWER_ENSUSPEND 0x01 /* INTRUSB */ -#define MGC_M_INTR_SUSPEND 0x01 -#define MGC_M_INTR_RESUME 0x02 -#define MGC_M_INTR_RESET 0x04 -#define MGC_M_INTR_BABBLE 0x04 -#define MGC_M_INTR_SOF 0x08 -#define MGC_M_INTR_CONNECT 0x10 -#define MGC_M_INTR_DISCONNECT 0x20 -#define MGC_M_INTR_SESSREQ 0x40 -#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ -#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ +#define MGC_M_INTR_SUSPEND 0x01 +#define MGC_M_INTR_RESUME 0x02 +#define MGC_M_INTR_RESET 0x04 +#define MGC_M_INTR_BABBLE 0x04 +#define MGC_M_INTR_SOF 0x08 +#define MGC_M_INTR_CONNECT 0x10 +#define MGC_M_INTR_DISCONNECT 0x20 +#define MGC_M_INTR_SESSREQ 0x40 +#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ +#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ /* DEVCTL */ -#define MGC_M_DEVCTL_BDEVICE 0x80 -#define MGC_M_DEVCTL_FSDEV 0x40 -#define MGC_M_DEVCTL_LSDEV 0x20 -#define MGC_M_DEVCTL_VBUS 0x18 -#define MGC_S_DEVCTL_VBUS 3 -#define MGC_M_DEVCTL_HM 0x04 -#define MGC_M_DEVCTL_HR 0x02 -#define MGC_M_DEVCTL_SESSION 0x01 +#define MGC_M_DEVCTL_BDEVICE 0x80 +#define MGC_M_DEVCTL_FSDEV 0x40 +#define MGC_M_DEVCTL_LSDEV 0x20 +#define MGC_M_DEVCTL_VBUS 0x18 +#define MGC_S_DEVCTL_VBUS 3 +#define MGC_M_DEVCTL_HM 0x04 +#define MGC_M_DEVCTL_HR 0x02 +#define MGC_M_DEVCTL_SESSION 0x01 /* TESTMODE */ -#define MGC_M_TEST_FORCE_HOST 0x80 -#define MGC_M_TEST_FIFO_ACCESS 0x40 -#define MGC_M_TEST_FORCE_FS 0x20 -#define MGC_M_TEST_FORCE_HS 0x10 -#define MGC_M_TEST_PACKET 0x08 -#define MGC_M_TEST_K 0x04 -#define MGC_M_TEST_J 0x02 -#define MGC_M_TEST_SE0_NAK 0x01 +#define MGC_M_TEST_FORCE_HOST 0x80 +#define MGC_M_TEST_FIFO_ACCESS 0x40 +#define MGC_M_TEST_FORCE_FS 0x20 +#define MGC_M_TEST_FORCE_HS 0x10 +#define MGC_M_TEST_PACKET 0x08 +#define MGC_M_TEST_K 0x04 +#define MGC_M_TEST_J 0x02 +#define MGC_M_TEST_SE0_NAK 0x01 /* CSR0 */ -#define MGC_M_CSR0_FLUSHFIFO 0x0100 -#define MGC_M_CSR0_TXPKTRDY 0x0002 -#define MGC_M_CSR0_RXPKTRDY 0x0001 +#define MGC_M_CSR0_FLUSHFIFO 0x0100 +#define MGC_M_CSR0_TXPKTRDY 0x0002 +#define MGC_M_CSR0_RXPKTRDY 0x0001 /* CSR0 in Peripheral mode */ -#define MGC_M_CSR0_P_SVDSETUPEND 0x0080 -#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040 -#define MGC_M_CSR0_P_SENDSTALL 0x0020 -#define MGC_M_CSR0_P_SETUPEND 0x0010 -#define MGC_M_CSR0_P_DATAEND 0x0008 -#define MGC_M_CSR0_P_SENTSTALL 0x0004 +#define MGC_M_CSR0_P_SVDSETUPEND 0x0080 +#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040 +#define MGC_M_CSR0_P_SENDSTALL 0x0020 +#define MGC_M_CSR0_P_SETUPEND 0x0010 +#define MGC_M_CSR0_P_DATAEND 0x0008 +#define MGC_M_CSR0_P_SENTSTALL 0x0004 /* CSR0 in Host mode */ -#define MGC_M_CSR0_H_NO_PING 0x0800 -#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ -#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ -#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 -#define MGC_M_CSR0_H_STATUSPKT 0x0040 -#define MGC_M_CSR0_H_REQPKT 0x0020 -#define MGC_M_CSR0_H_ERROR 0x0010 -#define MGC_M_CSR0_H_SETUPPKT 0x0008 -#define MGC_M_CSR0_H_RXSTALL 0x0004 +#define MGC_M_CSR0_H_NO_PING 0x0800 +#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ +#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ +#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 +#define MGC_M_CSR0_H_STATUSPKT 0x0040 +#define MGC_M_CSR0_H_REQPKT 0x0020 +#define MGC_M_CSR0_H_ERROR 0x0010 +#define MGC_M_CSR0_H_SETUPPKT 0x0008 +#define MGC_M_CSR0_H_RXSTALL 0x0004 /* CONFIGDATA */ -#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ -#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ -#define MGC_M_CONFIGDATA_BIGENDIAN 0x20 -#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ -#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ -#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ -#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ -#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */ +#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ +#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ +#define MGC_M_CONFIGDATA_BIGENDIAN 0x20 +#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ +#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ +#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ +#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ +#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */ /* TXCSR in Peripheral and Host mode */ -#define MGC_M_TXCSR_AUTOSET 0x8000 -#define MGC_M_TXCSR_ISO 0x4000 -#define MGC_M_TXCSR_MODE 0x2000 -#define MGC_M_TXCSR_DMAENAB 0x1000 -#define MGC_M_TXCSR_FRCDATATOG 0x0800 -#define MGC_M_TXCSR_DMAMODE 0x0400 -#define MGC_M_TXCSR_CLRDATATOG 0x0040 -#define MGC_M_TXCSR_FLUSHFIFO 0x0008 -#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002 -#define MGC_M_TXCSR_TXPKTRDY 0x0001 +#define MGC_M_TXCSR_AUTOSET 0x8000 +#define MGC_M_TXCSR_ISO 0x4000 +#define MGC_M_TXCSR_MODE 0x2000 +#define MGC_M_TXCSR_DMAENAB 0x1000 +#define MGC_M_TXCSR_FRCDATATOG 0x0800 +#define MGC_M_TXCSR_DMAMODE 0x0400 +#define MGC_M_TXCSR_CLRDATATOG 0x0040 +#define MGC_M_TXCSR_FLUSHFIFO 0x0008 +#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002 +#define MGC_M_TXCSR_TXPKTRDY 0x0001 /* TXCSR in Peripheral mode */ -#define MGC_M_TXCSR_P_INCOMPTX 0x0080 -#define MGC_M_TXCSR_P_SENTSTALL 0x0020 -#define MGC_M_TXCSR_P_SENDSTALL 0x0010 -#define MGC_M_TXCSR_P_UNDERRUN 0x0004 +#define MGC_M_TXCSR_P_INCOMPTX 0x0080 +#define MGC_M_TXCSR_P_SENTSTALL 0x0020 +#define MGC_M_TXCSR_P_SENDSTALL 0x0010 +#define MGC_M_TXCSR_P_UNDERRUN 0x0004 /* TXCSR in Host mode */ -#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200 -#define MGC_M_TXCSR_H_DATATOGGLE 0x0100 -#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080 -#define MGC_M_TXCSR_H_RXSTALL 0x0020 -#define MGC_M_TXCSR_H_ERROR 0x0004 +#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200 +#define MGC_M_TXCSR_H_DATATOGGLE 0x0100 +#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080 +#define MGC_M_TXCSR_H_RXSTALL 0x0020 +#define MGC_M_TXCSR_H_ERROR 0x0004 /* RXCSR in Peripheral and Host mode */ -#define MGC_M_RXCSR_AUTOCLEAR 0x8000 -#define MGC_M_RXCSR_DMAENAB 0x2000 -#define MGC_M_RXCSR_DISNYET 0x1000 -#define MGC_M_RXCSR_DMAMODE 0x0800 -#define MGC_M_RXCSR_INCOMPRX 0x0100 -#define MGC_M_RXCSR_CLRDATATOG 0x0080 -#define MGC_M_RXCSR_FLUSHFIFO 0x0010 -#define MGC_M_RXCSR_DATAERROR 0x0008 -#define MGC_M_RXCSR_FIFOFULL 0x0002 -#define MGC_M_RXCSR_RXPKTRDY 0x0001 +#define MGC_M_RXCSR_AUTOCLEAR 0x8000 +#define MGC_M_RXCSR_DMAENAB 0x2000 +#define MGC_M_RXCSR_DISNYET 0x1000 +#define MGC_M_RXCSR_DMAMODE 0x0800 +#define MGC_M_RXCSR_INCOMPRX 0x0100 +#define MGC_M_RXCSR_CLRDATATOG 0x0080 +#define MGC_M_RXCSR_FLUSHFIFO 0x0010 +#define MGC_M_RXCSR_DATAERROR 0x0008 +#define MGC_M_RXCSR_FIFOFULL 0x0002 +#define MGC_M_RXCSR_RXPKTRDY 0x0001 /* RXCSR in Peripheral mode */ -#define MGC_M_RXCSR_P_ISO 0x4000 -#define MGC_M_RXCSR_P_SENTSTALL 0x0040 -#define MGC_M_RXCSR_P_SENDSTALL 0x0020 -#define MGC_M_RXCSR_P_OVERRUN 0x0004 +#define MGC_M_RXCSR_P_ISO 0x4000 +#define MGC_M_RXCSR_P_SENTSTALL 0x0040 +#define MGC_M_RXCSR_P_SENDSTALL 0x0020 +#define MGC_M_RXCSR_P_OVERRUN 0x0004 /* RXCSR in Host mode */ -#define MGC_M_RXCSR_H_AUTOREQ 0x4000 -#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400 -#define MGC_M_RXCSR_H_DATATOGGLE 0x0200 -#define MGC_M_RXCSR_H_RXSTALL 0x0040 -#define MGC_M_RXCSR_H_REQPKT 0x0020 -#define MGC_M_RXCSR_H_ERROR 0x0004 +#define MGC_M_RXCSR_H_AUTOREQ 0x4000 +#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400 +#define MGC_M_RXCSR_H_DATATOGGLE 0x0200 +#define MGC_M_RXCSR_H_RXSTALL 0x0040 +#define MGC_M_RXCSR_H_REQPKT 0x0020 +#define MGC_M_RXCSR_H_ERROR 0x0004 /* HUBADDR */ -#define MGC_M_HUBADDR_MULTI_TT 0x80 +#define MGC_M_HUBADDR_MULTI_TT 0x80 /* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */ -#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02 -#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01 -#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08 -#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04 -#define MGC_M_ULPI_REGCTL_COMPLETE 0x02 -#define MGC_M_ULPI_REGCTL_REG 0x01 +#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02 +#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01 +#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08 +#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04 +#define MGC_M_ULPI_REGCTL_COMPLETE 0x02 +#define MGC_M_ULPI_REGCTL_REG 0x01 /* #define MUSB_DEBUG */ @@ -296,7 +296,7 @@ struct MUSBEndPoint { uint8_t interval[2]; uint8_t config; uint8_t fifosize; - int timeout[2]; /* Always in microframes */ + int timeout[2]; /* Always in microframes */ uint8_t *buf[2]; int fifolen[2]; @@ -542,7 +542,7 @@ static void musb_cb_tick1(void *opaque) ep->delayed_cb[1](&ep->packey[1].p, opaque); } -#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) +#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) static void musb_schedule_cb(USBPort *port, USBPacket *packey) { @@ -1323,7 +1323,7 @@ static void musb_writeb(void *opaque, hwaddr addr, uint32_t value) /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */ if ((value & MGC_M_POWER_HSENAB) && s->port.dev->speed == USB_SPEED_HIGH) - s->power |= MGC_M_POWER_HSMODE; /* Success */ + s->power |= MGC_M_POWER_HSMODE; /* Success */ /* Restart frame counting. */ } if (value & MGC_M_POWER_SUSPENDM) { diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c index 8e1146b8627f..6b630d35a7fa 100644 --- a/hw/usb/hcd-ohci-pci.c +++ b/hw/usb/hcd-ohci-pci.c @@ -23,7 +23,7 @@ #include "qemu/timer.h" #include "hw/usb.h" #include "migration/vmstate.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/sysbus.h" #include "hw/qdev-dma.h" #include "hw/qdev-properties.h" diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 895b29fb8657..9d68036d233c 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-uhci.h b/hw/usb/hcd-uhci.h index c85ab7868eee..5843af504a27 100644 --- a/hw/usb/hcd-uhci.h +++ b/hw/usb/hcd-uhci.h @@ -30,7 +30,7 @@ #include "exec/memory.h" #include "qemu/timer.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/usb.h" typedef struct UHCIQueue UHCIQueue; diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c index e934b1a5b1fb..643d4643e4d6 100644 --- a/hw/usb/hcd-xhci-pci.c +++ b/hw/usb/hcd-xhci-pci.c @@ -85,7 +85,7 @@ static void xhci_pci_reset(DeviceState *dev) { XHCIPciState *s = XHCI_PCI(dev); - device_legacy_reset(DEVICE(&s->xhci)); + device_cold_reset(DEVICE(&s->xhci)); } static int xhci_pci_vmstate_post_load(void *opaque, int version_id) diff --git a/hw/usb/hcd-xhci-pci.h b/hw/usb/hcd-xhci-pci.h index c193f794439c..08f70ce97cc6 100644 --- a/hw/usb/hcd-xhci-pci.h +++ b/hw/usb/hcd-xhci-pci.h @@ -24,6 +24,7 @@ #ifndef HW_USB_HCD_XHCI_PCI_H #define HW_USB_HCD_XHCI_PCI_H +#include "hw/pci/pci_device.h" #include "hw/usb.h" #include "hcd-xhci.h" diff --git a/hw/usb/hcd-xhci-sysbus.c b/hw/usb/hcd-xhci-sysbus.c index a14e4381960e..faf57b47975d 100644 --- a/hw/usb/hcd-xhci-sysbus.c +++ b/hw/usb/hcd-xhci-sysbus.c @@ -29,7 +29,7 @@ void xhci_sysbus_reset(DeviceState *dev) { XHCISysbusState *s = XHCI_SYSBUS(dev); - device_legacy_reset(DEVICE(&s->xhci)); + device_cold_reset(DEVICE(&s->xhci)); } static void xhci_sysbus_realize(DeviceState *dev, Error **errp) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 0cd0a5e54027..b89b618ec210 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 transfer 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; } @@ -3269,7 +3318,8 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, DPRINTF("%s\n", __func__); slotid = ep->dev->addr; - if (slotid == 0 || !xhci->slots[slotid-1].enabled) { + if (slotid == 0 || slotid > xhci->numslots || + !xhci->slots[slotid - 1].enabled) { DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr); return; } diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 2b35cb6cdd39..176868d34507 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1809,6 +1809,7 @@ static const TypeInfo usb_host_dev_info = { .instance_init = usb_host_instance_init, }; module_obj(TYPE_USB_HOST_DEVICE); +module_kconfig(USB); static void usb_host_register_types(void) { @@ -1836,7 +1837,6 @@ static void usb_host_auto_check(void *unused) struct USBAutoFilter *f; libusb_device **devs = NULL; struct libusb_device_descriptor ddesc; - int unconnected = 0; int i, n; if (usb_host_init() != 0) { @@ -1896,9 +1896,6 @@ static void usb_host_auto_check(void *unused) libusb_free_device_list(devs, 1); QTAILQ_FOREACH(s, &hostdevs, next) { - if (s->dh == NULL) { - unconnected++; - } if (s->seen == 0) { if (s->dh) { usb_host_close(s); @@ -1907,17 +1904,6 @@ static void usb_host_auto_check(void *unused) } s->seen = 0; } - -#if 0 - if (unconnected == 0) { - /* nothing to watch */ - if (usb_auto_timer) { - timer_del(usb_auto_timer); - trace_usb_host_auto_scan_disabled(); - } - return; - } -#endif } if (!usb_vmstate) { diff --git a/hw/usb/meson.build b/hw/usb/meson.build index de853d780dd8..793df42e2127 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -63,6 +63,11 @@ if u2f.found() softmmu_ss.add(when: 'CONFIG_USB_U2F', if_true: [u2f, files('u2f-emulated.c')]) endif +# CanoKey +if canokey.found() + softmmu_ss.add(when: 'CONFIG_USB_CANOKEY', if_true: [canokey, files('canokey.c')]) +endif + # usb redirect if usbredir.found() usbredir_ss = ss.source_set() diff --git a/hw/usb/quirks-pl2303-ids.h b/hw/usb/quirks-pl2303-ids.h index 8dbdb46ffe01..28dd8da61caf 100644 --- a/hw/usb/quirks-pl2303-ids.h +++ b/hw/usb/quirks-pl2303-ids.h @@ -1,150 +1,150 @@ /* * Prolific PL2303 USB to serial adaptor driver header file * - * 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 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. * */ -#define BENQ_VENDOR_ID 0x04a5 -#define BENQ_PRODUCT_ID_S81 0x4027 +#define BENQ_VENDOR_ID 0x04a5 +#define BENQ_PRODUCT_ID_S81 0x4027 -#define PL2303_VENDOR_ID 0x067b -#define PL2303_PRODUCT_ID 0x2303 -#define PL2303_PRODUCT_ID_RSAQ2 0x04bb -#define PL2303_PRODUCT_ID_DCU11 0x1234 -#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 -#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 -#define PL2303_PRODUCT_ID_ALDIGA 0x0611 -#define PL2303_PRODUCT_ID_MMX 0x0612 -#define PL2303_PRODUCT_ID_GPRS 0x0609 -#define PL2303_PRODUCT_ID_HCR331 0x331a -#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 +#define PL2303_VENDOR_ID 0x067b +#define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_DCU11 0x1234 +#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 +#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 +#define PL2303_PRODUCT_ID_ALDIGA 0x0611 +#define PL2303_PRODUCT_ID_MMX 0x0612 +#define PL2303_PRODUCT_ID_GPRS 0x0609 +#define PL2303_PRODUCT_ID_HCR331 0x331a +#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 -#define ATEN_VENDOR_ID 0x0557 -#define ATEN_VENDOR_ID2 0x0547 -#define ATEN_PRODUCT_ID 0x2008 +#define ATEN_VENDOR_ID 0x0557 +#define ATEN_VENDOR_ID2 0x0547 +#define ATEN_PRODUCT_ID 0x2008 -#define IODATA_VENDOR_ID 0x04bb -#define IODATA_PRODUCT_ID 0x0a03 -#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e +#define IODATA_VENDOR_ID 0x04bb +#define IODATA_PRODUCT_ID 0x0a03 +#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e -#define ELCOM_VENDOR_ID 0x056e -#define ELCOM_PRODUCT_ID 0x5003 -#define ELCOM_PRODUCT_ID_UCSGT 0x5004 +#define ELCOM_VENDOR_ID 0x056e +#define ELCOM_PRODUCT_ID 0x5003 +#define ELCOM_PRODUCT_ID_UCSGT 0x5004 -#define ITEGNO_VENDOR_ID 0x0eba -#define ITEGNO_PRODUCT_ID 0x1080 -#define ITEGNO_PRODUCT_ID_2080 0x2080 +#define ITEGNO_VENDOR_ID 0x0eba +#define ITEGNO_PRODUCT_ID 0x1080 +#define ITEGNO_PRODUCT_ID_2080 0x2080 -#define MA620_VENDOR_ID 0x0df7 -#define MA620_PRODUCT_ID 0x0620 +#define MA620_VENDOR_ID 0x0df7 +#define MA620_PRODUCT_ID 0x0620 -#define RATOC_VENDOR_ID 0x0584 -#define RATOC_PRODUCT_ID 0xb000 +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID 0xb000 -#define TRIPP_VENDOR_ID 0x2478 -#define TRIPP_PRODUCT_ID 0x2008 +#define TRIPP_VENDOR_ID 0x2478 +#define TRIPP_PRODUCT_ID 0x2008 -#define RADIOSHACK_VENDOR_ID 0x1453 -#define RADIOSHACK_PRODUCT_ID 0x4026 +#define RADIOSHACK_VENDOR_ID 0x1453 +#define RADIOSHACK_PRODUCT_ID 0x4026 -#define DCU10_VENDOR_ID 0x0731 -#define DCU10_PRODUCT_ID 0x0528 +#define DCU10_VENDOR_ID 0x0731 +#define DCU10_PRODUCT_ID 0x0528 -#define SITECOM_VENDOR_ID 0x6189 -#define SITECOM_PRODUCT_ID 0x2068 +#define SITECOM_VENDOR_ID 0x6189 +#define SITECOM_PRODUCT_ID 0x2068 /* Alcatel OT535/735 USB cable */ -#define ALCATEL_VENDOR_ID 0x11f7 -#define ALCATEL_PRODUCT_ID 0x02df +#define ALCATEL_VENDOR_ID 0x11f7 +#define ALCATEL_PRODUCT_ID 0x02df /* Samsung I330 phone cradle */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_ID 0x8001 +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_ID 0x8001 -#define SIEMENS_VENDOR_ID 0x11f5 -#define SIEMENS_PRODUCT_ID_SX1 0x0001 -#define SIEMENS_PRODUCT_ID_X65 0x0003 -#define SIEMENS_PRODUCT_ID_X75 0x0004 -#define SIEMENS_PRODUCT_ID_EF81 0x0005 +#define SIEMENS_VENDOR_ID 0x11f5 +#define SIEMENS_PRODUCT_ID_SX1 0x0001 +#define SIEMENS_PRODUCT_ID_X65 0x0003 +#define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 -#define SYNTECH_VENDOR_ID 0x0745 -#define SYNTECH_PRODUCT_ID 0x0001 +#define SYNTECH_VENDOR_ID 0x0745 +#define SYNTECH_PRODUCT_ID 0x0001 /* Nokia CA-42 Cable */ -#define NOKIA_CA42_VENDOR_ID 0x078b -#define NOKIA_CA42_PRODUCT_ID 0x1234 +#define NOKIA_CA42_VENDOR_ID 0x078b +#define NOKIA_CA42_PRODUCT_ID 0x1234 /* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ -#define CA_42_CA42_VENDOR_ID 0x10b5 -#define CA_42_CA42_PRODUCT_ID 0xac70 +#define CA_42_CA42_VENDOR_ID 0x10b5 +#define CA_42_CA42_PRODUCT_ID 0xac70 -#define SAGEM_VENDOR_ID 0x079b -#define SAGEM_PRODUCT_ID 0x0027 +#define SAGEM_VENDOR_ID 0x079b +#define SAGEM_PRODUCT_ID 0x0027 /* Leadtek GPS 9531 (ID 0413:2101) */ -#define LEADTEK_VENDOR_ID 0x0413 -#define LEADTEK_9531_PRODUCT_ID 0x2101 +#define LEADTEK_VENDOR_ID 0x0413 +#define LEADTEK_9531_PRODUCT_ID 0x2101 /* USB GSM cable from Speed Dragon Multimedia, Ltd */ -#define SPEEDDRAGON_VENDOR_ID 0x0e55 -#define SPEEDDRAGON_PRODUCT_ID 0x110b +#define SPEEDDRAGON_VENDOR_ID 0x0e55 +#define SPEEDDRAGON_PRODUCT_ID 0x110b /* DATAPILOT Universal-2 Phone Cable */ -#define DATAPILOT_U2_VENDOR_ID 0x0731 -#define DATAPILOT_U2_PRODUCT_ID 0x2003 +#define DATAPILOT_U2_VENDOR_ID 0x0731 +#define DATAPILOT_U2_PRODUCT_ID 0x2003 /* Belkin "F5U257" Serial Adapter */ -#define BELKIN_VENDOR_ID 0x050d -#define BELKIN_PRODUCT_ID 0x0257 +#define BELKIN_VENDOR_ID 0x050d +#define BELKIN_PRODUCT_ID 0x0257 /* Alcor Micro Corp. USB 2.0 TO RS-232 */ -#define ALCOR_VENDOR_ID 0x058F -#define ALCOR_PRODUCT_ID 0x9720 +#define ALCOR_VENDOR_ID 0x058F +#define ALCOR_PRODUCT_ID 0x9720 /* Willcom WS002IN Data Driver (by NetIndex Inc.) */ -#define WS002IN_VENDOR_ID 0x11f6 -#define WS002IN_PRODUCT_ID 0x2001 +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 /* Corega CG-USBRS232R Serial Adapter */ -#define COREGA_VENDOR_ID 0x07aa -#define COREGA_PRODUCT_ID 0x002a +#define COREGA_VENDOR_ID 0x07aa +#define COREGA_PRODUCT_ID 0x002a /* Y.C. Cable U.S.A., Inc - USB to RS-232 */ -#define YCCABLE_VENDOR_ID 0x05ad -#define YCCABLE_PRODUCT_ID 0x0fba +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba /* "Superial" USB - Serial */ -#define SUPERIAL_VENDOR_ID 0x5372 -#define SUPERIAL_PRODUCT_ID 0x2303 +#define SUPERIAL_VENDOR_ID 0x5372 +#define SUPERIAL_PRODUCT_ID 0x2303 /* Hewlett-Packard LD220-HP POS Pole Display */ -#define HP_VENDOR_ID 0x03f0 -#define HP_LD220_PRODUCT_ID 0x3524 +#define HP_VENDOR_ID 0x03f0 +#define HP_LD220_PRODUCT_ID 0x3524 /* Cressi Edy (diving computer) PC interface */ -#define CRESSI_VENDOR_ID 0x04b8 -#define CRESSI_EDY_PRODUCT_ID 0x0521 +#define CRESSI_VENDOR_ID 0x04b8 +#define CRESSI_EDY_PRODUCT_ID 0x0521 /* Zeagle dive computer interface */ -#define ZEAGLE_VENDOR_ID 0x04b8 -#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 +#define ZEAGLE_VENDOR_ID 0x04b8 +#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 /* Sony, USB data cable for CMD-Jxx mobile phones */ -#define SONY_VENDOR_ID 0x054c -#define SONY_QN3USB_PRODUCT_ID 0x0437 +#define SONY_VENDOR_ID 0x054c +#define SONY_QN3USB_PRODUCT_ID 0x0437 /* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ -#define SANWA_VENDOR_ID 0x11ad -#define SANWA_PRODUCT_ID 0x0001 +#define SANWA_VENDOR_ID 0x11ad +#define SANWA_PRODUCT_ID 0x0001 /* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ -#define ADLINK_VENDOR_ID 0x0b63 -#define ADLINK_ND6530_PRODUCT_ID 0x6530 +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 /* SMART USB Serial Adapter */ -#define SMART_VENDOR_ID 0x0b8c -#define SMART_PRODUCT_ID 0x2303 +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 8692ea256109..fd7df599bc0b 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -26,7 +26,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/cutils.h" #include "qemu/units.h" #include "qapi/error.h" #include "qemu/timer.h" @@ -2620,6 +2620,7 @@ static const TypeInfo usbredir_dev_info = { .instance_init = usbredir_instance_init, }; module_obj(TYPE_USB_REDIR); +module_kconfig(USB); static void usbredir_register_types(void) { diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 9773cb53300d..b65269892c5e 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" @@ -345,3 +346,19 @@ usb_serial_set_baud(int bus, int addr, int baud) "dev %d:%u baud rate %d" usb_serial_set_data(int bus, int addr, int parity, int data, int stop) "dev %d:%u parity %c, data bits %d, stop bits %d" usb_serial_set_flow_control(int bus, int addr, int index) "dev %d:%u flow control %d" usb_serial_set_xonxoff(int bus, int addr, uint8_t xon, uint8_t xoff) "dev %d:%u xon 0x%x xoff 0x%x" + +# canokey.c +canokey_emu_stall_ep(uint8_t ep) "ep %d" +canokey_emu_set_address(uint8_t addr) "addr %d" +canokey_emu_prepare_receive(uint8_t ep, uint16_t size) "ep %d size %d" +canokey_emu_transmit(uint8_t ep, uint16_t size) "ep %d size %d" +canokey_thread_start(void) +canokey_thread_stop(void) +canokey_handle_reset(void) +canokey_handle_control_setup(int request, int value, int index, int length) "request 0x%04X value 0x%04X index 0x%04X length 0x%04X" +canokey_handle_control_out(void) +canokey_handle_control_in(int actual_len) "len %d" +canokey_handle_data_out(uint8_t ep_out, uint32_t out_len) "ep %d len %d" +canokey_handle_data_in(uint8_t ep_in, uint32_t in_len) "ep %d len %d" +canokey_realize(void) +canokey_unrealize(void) diff --git a/hw/usb/u2f.h b/hw/usb/u2f.h index db30f3586bf7..a408a8292724 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/usb/vt82c686-uhci-pci.c b/hw/usb/vt82c686-uhci-pci.c index 0bf2b72ff086..46a901f56fd8 100644 --- a/hw/usb/vt82c686-uhci-pci.c +++ b/hw/usb/vt82c686-uhci-pci.c @@ -31,7 +31,7 @@ static void usb_uhci_vt82c686b_realize(PCIDevice *dev, Error **errp) static UHCIInfo uhci_info[] = { { - .name = "vt82c686b-usb-uhci", + .name = TYPE_VT82C686B_USB_UHCI, .vendor_id = PCI_VENDOR_ID_VIA, .device_id = PCI_DEVICE_ID_VIA_UHCI, .revision = 0x01, @@ -45,7 +45,7 @@ static UHCIInfo uhci_info[] = { static const TypeInfo vt82c686b_usb_uhci_type_info = { .parent = TYPE_UHCI, - .name = "vt82c686b-usb-uhci", + .name = TYPE_VT82C686B_USB_UHCI, .class_init = uhci_data_class_init, .class_data = uhci_info, }; diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 080046e3f511..130e5d1dc702 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -40,6 +40,7 @@ #include "trace.h" #include "qapi/error.h" #include "migration/migration.h" +#include "sysemu/tpm.h" VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); @@ -354,7 +355,7 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) } if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) - && (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { + && (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING)) { return false; } } @@ -380,8 +381,8 @@ static bool vfio_devices_all_running_and_saving(VFIOContainer *container) return false; } - if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && - (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { + if ((migration->device_state & VFIO_DEVICE_STATE_V1_SAVING) && + (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING)) { continue; } else { return false; @@ -397,7 +398,7 @@ static int vfio_dma_unmap_bitmap(VFIOContainer *container, { struct vfio_iommu_type1_dma_unmap *unmap; struct vfio_bitmap *bitmap; - uint64_t pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size; + uint64_t pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size(); int ret; unmap = g_malloc0(sizeof(*unmap) + sizeof(*bitmap)); @@ -414,7 +415,7 @@ static int vfio_dma_unmap_bitmap(VFIOContainer *container, * to qemu_real_host_page_size. */ - bitmap->pgsize = qemu_real_host_page_size; + bitmap->pgsize = qemu_real_host_page_size(); bitmap->size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / BITS_PER_BYTE; @@ -577,45 +578,11 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, ram_addr_t *ram_addr, bool *read_only) { - MemoryRegion *mr; - hwaddr xlat; - hwaddr len = iotlb->addr_mask + 1; - bool writable = iotlb->perm & IOMMU_WO; - - /* - * The IOMMU TLB entry we have just covers translation through - * this IOMMU to its immediate target. We need to translate - * it the rest of the way through to memory. - */ - mr = address_space_translate(&address_space_memory, - iotlb->translated_addr, - &xlat, &len, writable, - MEMTXATTRS_UNSPECIFIED); - if (!memory_region_is_ram(mr)) { - error_report("iommu map to non memory area %"HWADDR_PRIx"", - xlat); - return false; - } else if (memory_region_has_ram_discard_manager(mr)) { - RamDiscardManager *rdm = memory_region_get_ram_discard_manager(mr); - MemoryRegionSection tmp = { - .mr = mr, - .offset_within_region = xlat, - .size = int128_make64(len), - }; - - /* - * Malicious VMs can map memory into the IOMMU, which is expected - * to remain discarded. vfio will pin all pages, populating memory. - * Disallow that. vmstate priorities make sure any RamDiscardManager - * were already restored before IOMMUs are restored. - */ - if (!ram_discard_manager_is_populated(rdm, &tmp)) { - error_report("iommu map to discarded memory (e.g., unplugged via" - " virtio-mem): %"HWADDR_PRIx"", - iotlb->translated_addr); - return false; - } + bool ret, mr_has_discard_manager; + ret = memory_get_xlat_addr(iotlb, vaddr, ram_addr, read_only, + &mr_has_discard_manager); + if (ret && mr_has_discard_manager) { /* * Malicious VMs might trigger discarding of IOMMU-mapped memory. The * pages will remain pinned inside vfio until unmapped, resulting in a @@ -634,29 +601,7 @@ static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, " intended via an IOMMU. It's possible to mitigate " " by setting/adjusting RLIMIT_MEMLOCK."); } - - /* - * Translation truncates length to the IOMMU page size, - * check that it did not truncate too much. - */ - if (len & iotlb->addr_mask) { - error_report("iommu has granularity incompatible with target AS"); - return false; - } - - if (vaddr) { - *vaddr = memory_region_get_ram_ptr(mr) + xlat; - } - - if (ram_addr) { - *ram_addr = memory_region_get_ram_addr(mr) + xlat; - } - - if (read_only) { - *read_only = !writable || mr->readonly; - } - - return true; + return ret; } static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) @@ -861,6 +806,22 @@ static void vfio_unregister_ram_discard_listener(VFIOContainer *container, g_free(vrdl); } +static bool vfio_known_safe_misalignment(MemoryRegionSection *section) +{ + MemoryRegion *mr = section->mr; + + if (!TPM_IS_CRB(mr->owner)) { + return false; + } + + /* this is a known safe misaligned region, just trace for debug purpose */ + trace_vfio_known_safe_misalignment(memory_region_name(mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); + return true; +} + static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -882,16 +843,24 @@ static void vfio_listener_region_add(MemoryListener *listener, } if (unlikely((section->offset_within_address_space & - ~qemu_real_host_page_mask) != - (section->offset_within_region & ~qemu_real_host_page_mask))) { - error_report("%s received unaligned region", __func__); + ~qemu_real_host_page_mask()) != + (section->offset_within_region & ~qemu_real_host_page_mask()))) { + if (!vfio_known_safe_misalignment(section)) { + error_report("%s received unaligned region %s iova=0x%"PRIx64 + " offset_within_region=0x%"PRIx64 + " qemu_real_host_page_size=0x%"PRIxPTR, + __func__, memory_region_name(section->mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); + } return; } iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space); llend = int128_make64(section->offset_within_address_space); llend = int128_add(llend, section->size); - llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); + llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask())); if (int128_ge(int128_make64(iova), llend)) { if (memory_region_is_ram_device(section->mr)) { @@ -899,7 +868,7 @@ static void vfio_listener_region_add(MemoryListener *listener, memory_region_name(section->mr), section->offset_within_address_space, int128_getlo(section->size), - qemu_real_host_page_size); + qemu_real_host_page_size()); } return; } @@ -992,7 +961,7 @@ static void vfio_listener_region_add(MemoryListener *listener, * device emulation the VFIO iommu handles to use). */ giommu = g_malloc0(sizeof(*giommu)); - giommu->iommu = iommu_mr; + giommu->iommu_mr = iommu_mr; giommu->iommu_offset = section->offset_within_address_space - section->offset_within_region; giommu->container = container; @@ -1007,7 +976,7 @@ static void vfio_listener_region_add(MemoryListener *listener, int128_get64(llend), iommu_idx); - ret = memory_region_iommu_set_page_size_mask(giommu->iommu, + ret = memory_region_iommu_set_page_size_mask(giommu->iommu_mr, container->pgsizes, &err); if (ret) { @@ -1022,7 +991,7 @@ static void vfio_listener_region_add(MemoryListener *listener, goto fail; } QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); - memory_region_iommu_replay(giommu->iommu, &giommu->n); + memory_region_iommu_replay(giommu->iommu_mr, &giommu->n); return; } @@ -1118,9 +1087,17 @@ static void vfio_listener_region_del(MemoryListener *listener, } if (unlikely((section->offset_within_address_space & - ~qemu_real_host_page_mask) != - (section->offset_within_region & ~qemu_real_host_page_mask))) { - error_report("%s received unaligned region", __func__); + ~qemu_real_host_page_mask()) != + (section->offset_within_region & ~qemu_real_host_page_mask()))) { + if (!vfio_known_safe_misalignment(section)) { + error_report("%s received unaligned region %s iova=0x%"PRIx64 + " offset_within_region=0x%"PRIx64 + " qemu_real_host_page_size=0x%"PRIxPTR, + __func__, memory_region_name(section->mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); + } return; } @@ -1128,7 +1105,7 @@ static void vfio_listener_region_del(MemoryListener *listener, VFIOGuestIOMMU *giommu; QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { - if (MEMORY_REGION(giommu->iommu) == section->mr && + if (MEMORY_REGION(giommu->iommu_mr) == section->mr && giommu->n.start == section->offset_within_region) { memory_region_unregister_iommu_notifier(section->mr, &giommu->n); @@ -1150,7 +1127,7 @@ static void vfio_listener_region_del(MemoryListener *listener, iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space); llend = int128_make64(section->offset_within_address_space); llend = int128_add(llend, section->size); - llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask)); + llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask())); if (int128_ge(int128_make64(iova), llend)) { return; @@ -1272,9 +1249,9 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, * qemu_real_host_page_size to mark those dirty. Hence set bitmap's pgsize * to qemu_real_host_page_size. */ - range->bitmap.pgsize = qemu_real_host_page_size; + range->bitmap.pgsize = qemu_real_host_page_size(); - pages = REAL_HOST_PAGE_ALIGN(range->size) / qemu_real_host_page_size; + pages = REAL_HOST_PAGE_ALIGN(range->size) / qemu_real_host_page_size(); range->bitmap.size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / BITS_PER_BYTE; range->bitmap.data = g_try_malloc0(range->bitmap.size); @@ -1393,11 +1370,11 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, VFIOGuestIOMMU *giommu; QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { - if (MEMORY_REGION(giommu->iommu) == section->mr && + if (MEMORY_REGION(giommu->iommu_mr) == section->mr && giommu->n.start == section->offset_within_region) { Int128 llend; vfio_giommu_dirty_notifier gdn = { .giommu = giommu }; - int idx = memory_region_iommu_attrs_to_index(giommu->iommu, + int idx = memory_region_iommu_attrs_to_index(giommu->iommu_mr, MEMTXATTRS_UNSPECIFIED); llend = int128_add(int128_make64(section->offset_within_region), @@ -1410,7 +1387,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, section->offset_within_region, int128_get64(llend), idx); - memory_region_iommu_replay(giommu->iommu, &gdn.n); + memory_region_iommu_replay(giommu->iommu_mr, &gdn.n); break; } } @@ -1544,11 +1521,10 @@ static int vfio_setup_region_sparse_mmaps(VFIORegion *region, region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); for (i = 0, j = 0; i < sparse->nr_areas; i++) { - trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, - sparse->areas[i].offset + - sparse->areas[i].size); - if (sparse->areas[i].size) { + trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, + sparse->areas[i].offset + + sparse->areas[i].size - 1); region->mmaps[j].offset = sparse->areas[i].offset; region->mmaps[j].size = sparse->areas[i].size; j++; @@ -1970,7 +1946,7 @@ static void vfio_get_iommu_info_migration(VFIOContainer *container, * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of * qemu_real_host_page_size to mark those dirty. */ - if (cap_mig->pgsize_bitmap & qemu_real_host_page_size) { + if (cap_mig->pgsize_bitmap & qemu_real_host_page_size()) { container->dirty_pages_supported = true; container->max_dirty_bitmap_size = cap_mig->max_dirty_bitmap_size; container->dirty_pgsizes = cap_mig->pgsize_bitmap; @@ -2079,29 +2055,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) { + error_setg_errno(errp, -ret, "Failed to get VFIO IOMMU info"); + goto enable_discards_exit; + } - if (ret || !(info->flags & VFIO_IOMMU_INFO_PGSIZES)) { - /* Assume 4k IOVA page size */ - info->iova_pgsizes = 4096; + if (info->flags & VFIO_IOMMU_INFO_PGSIZES) { + container->pgsizes = info->iova_pgsizes; + } else { + container->pgsizes = qemu_real_host_page_size(); } - 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 (!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: @@ -2246,7 +2224,7 @@ static void vfio_disconnect_container(VFIOGroup *group) QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { memory_region_unregister_iommu_notifier( - MEMORY_REGION(giommu->iommu), &giommu->n); + MEMORY_REGION(giommu->iommu_mr), &giommu->n); QLIST_REMOVE(giommu, giommu_next); g_free(giommu); } diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 89bc90508fb8..78f4d82c1c35 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -106,14 +106,14 @@ static void vfio_display_edid_update(VFIOPCIDevice *vdev, bool enabled, return; } -static int vfio_display_edid_ui_info(void *opaque, uint32_t idx, - QemuUIInfo *info) +static void vfio_display_edid_ui_info(void *opaque, uint32_t idx, + QemuUIInfo *info) { VFIOPCIDevice *vdev = opaque; VFIODisplay *dpy = vdev->dpy; if (!dpy->edid_regs) { - return 0; + return; } if (info->width && info->height) { @@ -121,8 +121,6 @@ static int vfio_display_edid_ui_info(void *opaque, uint32_t idx, } else { vfio_display_edid_update(vdev, false, 0, 0); } - - return 0; } static void vfio_display_edid_init(VFIOPCIDevice *vdev) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index ff6b45de6b55..c74453e0b5e0 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -432,7 +432,7 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) } ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_SAVING); + VFIO_DEVICE_STATE_V1_SAVING); if (ret) { error_report("%s: Failed to set state SAVING", vbasedev->name); return ret; @@ -531,8 +531,8 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) uint64_t data_size; int ret; - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_RUNNING, - VFIO_DEVICE_STATE_SAVING); + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_RUNNING, + VFIO_DEVICE_STATE_V1_SAVING); if (ret) { error_report("%s: Failed to set state STOP and SAVING", vbasedev->name); @@ -569,7 +569,7 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) return ret; } - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_SAVING, 0); + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_SAVING, 0); if (ret) { error_report("%s: Failed to set state STOPPED", vbasedev->name); return ret; @@ -609,7 +609,7 @@ static int vfio_load_setup(QEMUFile *f, void *opaque) } ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_RESUMING); + VFIO_DEVICE_STATE_V1_RESUMING); if (ret) { error_report("%s: Failed to set state RESUMING", vbasedev->name); if (migration->region.mmaps) { @@ -717,20 +717,20 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) * In both the above cases, set _RUNNING bit. */ mask = ~VFIO_DEVICE_STATE_MASK; - value = VFIO_DEVICE_STATE_RUNNING; + value = VFIO_DEVICE_STATE_V1_RUNNING; } else { /* * Here device state could be either _RUNNING or _SAVING|_RUNNING. Reset * _RUNNING bit */ - mask = ~VFIO_DEVICE_STATE_RUNNING; + mask = ~VFIO_DEVICE_STATE_V1_RUNNING; /* * When VM state transition to stop for savevm command, device should * start saving data. */ if (state == RUN_STATE_SAVE_VM) { - value = VFIO_DEVICE_STATE_SAVING; + value = VFIO_DEVICE_STATE_V1_SAVING; } else { value = 0; } @@ -768,8 +768,9 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data) case MIGRATION_STATUS_FAILED: bytes_transferred = 0; ret = vfio_migration_set_state(vbasedev, - ~(VFIO_DEVICE_STATE_SAVING | VFIO_DEVICE_STATE_RESUMING), - VFIO_DEVICE_STATE_RUNNING); + ~(VFIO_DEVICE_STATE_V1_SAVING | + VFIO_DEVICE_STATE_V1_RESUMING), + VFIO_DEVICE_STATE_V1_RUNNING); if (ret) { error_report("%s: Failed to set state RUNNING", vbasedev->name); } @@ -805,6 +806,8 @@ static int vfio_migration_init(VFIODevice *vbasedev, } vbasedev->migration = g_new0(VFIOMigration, 1); + vbasedev->migration->device_state = VFIO_DEVICE_STATE_V1_RUNNING; + vbasedev->migration->vm_running = runstate_is_running(); ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, info->index, "migration"); @@ -864,8 +867,10 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) goto add_blocker; } - ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_MIGRATION, - VFIO_REGION_SUBTYPE_MIGRATION, &info); + ret = vfio_get_dev_region_info(vbasedev, + VFIO_REGION_TYPE_MIGRATION_DEPRECATED, + VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, + &info); if (ret) { goto add_blocker; } diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 0cf69a8c6d6f..f0147a050aaa 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1565,22 +1565,6 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) return 0; } -static void vfio_pci_nvlink2_get_tgt(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) -{ - uint64_t tgt = (uintptr_t) opaque; - visit_type_uint64(v, name, &tgt, errp); -} - -static void vfio_pci_nvlink2_get_link_speed(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) -{ - uint32_t link_speed = (uint32_t)(uintptr_t) opaque; - visit_type_uint32(v, name, &link_speed, errp); -} - int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp) { int ret; @@ -1618,9 +1602,9 @@ int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp) nv2reg->size, p); QLIST_INSERT_HEAD(&vdev->bars[0].quirks, quirk, next); - object_property_add(OBJECT(vdev), "nvlink2-tgt", "uint64", - vfio_pci_nvlink2_get_tgt, NULL, NULL, - (void *) (uintptr_t) cap->tgt); + object_property_add_uint64_ptr(OBJECT(vdev), "nvlink2-tgt", + (uint64_t *) &cap->tgt, + OBJ_PROP_FLAG_READ); trace_vfio_pci_nvidia_gpu_setup_quirk(vdev->vbasedev.name, cap->tgt, nv2reg->size); free_exit: @@ -1679,15 +1663,15 @@ int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp) QLIST_INSERT_HEAD(&vdev->bars[0].quirks, quirk, next); } - object_property_add(OBJECT(vdev), "nvlink2-tgt", "uint64", - vfio_pci_nvlink2_get_tgt, NULL, NULL, - (void *) (uintptr_t) captgt->tgt); + object_property_add_uint64_ptr(OBJECT(vdev), "nvlink2-tgt", + (uint64_t *) &captgt->tgt, + OBJ_PROP_FLAG_READ); trace_vfio_pci_nvlink2_setup_quirk_ssatgt(vdev->vbasedev.name, captgt->tgt, atsdreg->size); - object_property_add(OBJECT(vdev), "nvlink2-link-speed", "uint32", - vfio_pci_nvlink2_get_link_speed, NULL, NULL, - (void *) (uintptr_t) capspeed->link_speed); + object_property_add_uint32_ptr(OBJECT(vdev), "nvlink2-link-speed", + &capspeed->link_speed, + OBJ_PROP_FLAG_READ); trace_vfio_pci_nvlink2_setup_quirk_lnkspd(vdev->vbasedev.name, capspeed->link_speed); free_exit: diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 67a183f17bff..939dcc3d4a9e 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -45,8 +45,12 @@ #define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug" +/* Protected by BQL */ +static KVMRouteChange vfio_route_change; + static void vfio_disable_interrupts(VFIOPCIDevice *vdev); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); +static void vfio_msi_disable_common(VFIOPCIDevice *vdev); /* * Disabling BAR mmaping can be slow, but toggling it around INTx can @@ -412,33 +416,36 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, int vector_n, bool msix) { - KVMRouteChange c; - int virq; - if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi)) { return; } - if (event_notifier_init(&vector->kvm_interrupt, 0)) { + vector->virq = kvm_irqchip_add_msi_route(&vfio_route_change, + vector_n, &vdev->pdev); +} + +static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector) +{ + if (vector->virq < 0) { return; } - c = kvm_irqchip_begin_route_changes(kvm_state); - virq = kvm_irqchip_add_msi_route(&c, vector_n, &vdev->pdev); - if (virq < 0) { - event_notifier_cleanup(&vector->kvm_interrupt); - return; + if (event_notifier_init(&vector->kvm_interrupt, 0)) { + goto fail_notifier; } - kvm_irqchip_commit_route_changes(&c); if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt, - NULL, virq) < 0) { - kvm_irqchip_release_virq(kvm_state, virq); - event_notifier_cleanup(&vector->kvm_interrupt); - return; + NULL, vector->virq) < 0) { + goto fail_kvm; } - vector->virq = virq; + return; + +fail_kvm: + event_notifier_cleanup(&vector->kvm_interrupt); +fail_notifier: + kvm_irqchip_release_virq(kvm_state, vector->virq); + vector->virq = -1; } static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector) @@ -493,7 +500,14 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, } } else { if (msg) { - vfio_add_kvm_msi_virq(vdev, vector, nr, true); + if (vdev->defer_kvm_irq_routing) { + vfio_add_kvm_msi_virq(vdev, vector, nr, true); + } else { + vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state); + vfio_add_kvm_msi_virq(vdev, vector, nr, true); + kvm_irqchip_commit_route_changes(&vfio_route_change); + vfio_connect_kvm_msi_virq(vector); + } } } @@ -503,11 +517,13 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, * increase them as needed. */ if (vdev->nr_vectors < nr + 1) { - vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); vdev->nr_vectors = nr + 1; - ret = vfio_enable_vectors(vdev, true); - if (ret) { - error_report("vfio: failed to enable vectors, %d", ret); + if (!vdev->defer_kvm_irq_routing) { + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + ret = vfio_enable_vectors(vdev, true); + if (ret) { + error_report("vfio: failed to enable vectors, %d", ret); + } } } else { Error *err = NULL; @@ -569,11 +585,29 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) } } -static void vfio_msix_enable(VFIOPCIDevice *vdev) +static void vfio_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev) { - PCIDevice *pdev = &vdev->pdev; - unsigned int nr, max_vec = 0; + assert(!vdev->defer_kvm_irq_routing); + vdev->defer_kvm_irq_routing = true; + vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state); +} + +static void vfio_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev) +{ + int i; + + assert(vdev->defer_kvm_irq_routing); + vdev->defer_kvm_irq_routing = false; + + kvm_irqchip_commit_route_changes(&vfio_route_change); + + for (i = 0; i < vdev->nr_vectors; i++) { + vfio_connect_kvm_msi_virq(&vdev->msi_vectors[i]); + } +} +static void vfio_msix_enable(VFIOPCIDevice *vdev) +{ vfio_disable_interrupts(vdev); vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries); @@ -581,37 +615,45 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) vdev->interrupt = VFIO_INT_MSIX; /* - * Some communication channels between VF & PF or PF & fw rely on the - * physical state of the device and expect that enabling MSI-X from the - * guest enables the same on the host. When our guest is Linux, the - * guest driver call to pci_enable_msix() sets the enabling bit in the - * MSI-X capability, but leaves the vector table masked. We therefore - * can't rely on a vector_use callback (from request_irq() in the guest) - * to switch the physical device into MSI-X mode because that may come a - * long time after pci_enable_msix(). This code enables vector 0 with - * triggering to userspace, then immediately release the vector, leaving - * the physical device with no vectors enabled, but MSI-X enabled, just - * like the guest view. - * If there are already unmasked vectors (in migration resume phase and - * some guest startups) which will be enabled soon, we can allocate all - * of them here to avoid inefficiently disabling and enabling vectors - * repeatedly later. + * Setting vector notifiers triggers synchronous vector-use + * callbacks for each active vector. Deferring to commit the KVM + * routes once rather than per vector provides a substantial + * performance improvement. */ - if (!pdev->msix_function_masked) { - for (nr = 0; nr < msix_nr_vectors_allocated(pdev); nr++) { - if (!msix_is_masked(pdev, nr)) { - max_vec = nr; - } - } - } - vfio_msix_vector_do_use(pdev, max_vec, NULL, NULL); - vfio_msix_vector_release(pdev, max_vec); + vfio_prepare_kvm_msi_virq_batch(vdev); - if (msix_set_vector_notifiers(pdev, vfio_msix_vector_use, + if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, vfio_msix_vector_release, NULL)) { error_report("vfio: msix_set_vector_notifiers failed"); } + vfio_commit_kvm_msi_virq_batch(vdev); + + if (vdev->nr_vectors) { + int ret; + + ret = vfio_enable_vectors(vdev, true); + if (ret) { + error_report("vfio: failed to enable vectors, %d", ret); + } + } else { + /* + * Some communication channels between VF & PF or PF & fw rely on the + * physical state of the device and expect that enabling MSI-X from the + * guest enables the same on the host. When our guest is Linux, the + * guest driver call to pci_enable_msix() sets the enabling bit in the + * MSI-X capability, but leaves the vector table masked. We therefore + * can't rely on a vector_use callback (from request_irq() in the guest) + * to switch the physical device into MSI-X mode because that may come a + * long time after pci_enable_msix(). This code enables vector 0 with + * triggering to userspace, then immediately release the vector, leaving + * the physical device with no vectors enabled, but MSI-X enabled, just + * like the guest view. + */ + vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); + vfio_msix_vector_release(&vdev->pdev, 0); + } + trace_vfio_msix_enable(vdev->vbasedev.name); } @@ -621,6 +663,13 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) vfio_disable_interrupts(vdev); + /* + * Setting vector notifiers needs to enable route for each vector. + * Deferring to commit the KVM routes once rather than per vector + * provides a substantial performance improvement. + */ + vfio_prepare_kvm_msi_virq_batch(vdev); + vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev); retry: vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors); @@ -646,6 +695,8 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) vfio_add_kvm_msi_virq(vdev, vector, i, false); } + vfio_commit_kvm_msi_virq_batch(vdev); + /* Set interrupt type prior to possible interrupts */ vdev->interrupt = VFIO_INT_MSI; @@ -653,29 +704,17 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) if (ret) { if (ret < 0) { error_report("vfio: Error: Failed to setup MSI fds: %m"); - } else if (ret != vdev->nr_vectors) { + } else { error_report("vfio: Error: Failed to enable %d " "MSI vectors, retry with %d", vdev->nr_vectors, ret); } - for (i = 0; i < vdev->nr_vectors; i++) { - VFIOMSIVector *vector = &vdev->msi_vectors[i]; - if (vector->virq >= 0) { - vfio_remove_kvm_msi_virq(vector); - } - qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), - NULL, NULL, NULL); - event_notifier_cleanup(&vector->interrupt); - } - - g_free(vdev->msi_vectors); - vdev->msi_vectors = NULL; + vfio_msi_disable_common(vdev); - if (ret > 0 && ret != vdev->nr_vectors) { + if (ret > 0) { vdev->nr_vectors = ret; goto retry; } - vdev->nr_vectors = 0; /* * Failing to setup MSI doesn't really fall within any specification. @@ -683,7 +722,6 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) * out to fall back to INTx for this device. */ error_report("vfio: Error: Failed to enable MSI"); - vdev->interrupt = VFIO_INT_NONE; return; } @@ -693,7 +731,6 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) static void vfio_msi_disable_common(VFIOPCIDevice *vdev) { - Error *err = NULL; int i; for (i = 0; i < vdev->nr_vectors; i++) { @@ -712,15 +749,11 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev) vdev->msi_vectors = NULL; vdev->nr_vectors = 0; vdev->interrupt = VFIO_INT_NONE; - - vfio_intx_enable(vdev, &err); - if (err) { - error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); - } } static void vfio_msix_disable(VFIOPCIDevice *vdev) { + Error *err = NULL; int i; msix_unset_vector_notifiers(&vdev->pdev); @@ -741,6 +774,10 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) } vfio_msi_disable_common(vdev); + vfio_intx_enable(vdev, &err); + if (err) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + } memset(vdev->msix->pending, 0, BITS_TO_LONGS(vdev->msix->entries) * sizeof(unsigned long)); @@ -750,8 +787,14 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) static void vfio_msi_disable(VFIOPCIDevice *vdev) { + Error *err = NULL; + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); vfio_msi_disable_common(vdev); + vfio_intx_enable(vdev, &err); + if (err) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + } trace_vfio_msi_disable(vdev->vbasedev.name); } @@ -1087,8 +1130,8 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar) /* If BAR is mapped and page aligned, update to fill PAGE_SIZE */ if (bar_addr != PCI_BAR_UNMAPPED && - !(bar_addr & ~qemu_real_host_page_mask)) { - size = qemu_real_host_page_size; + !(bar_addr & ~qemu_real_host_page_mask())) { + size = qemu_real_host_page_size(); } memory_region_transaction_begin(); @@ -1204,7 +1247,7 @@ void vfio_pci_write_config(PCIDevice *pdev, for (bar = 0; bar < PCI_ROM_SLOT; bar++) { if (old_addr[bar] != pdev->io_regions[bar].addr && vdev->bars[bar].region.size > 0 && - vdev->bars[bar].region.size < qemu_real_host_page_size) { + vdev->bars[bar].region.size < qemu_real_host_page_size()) { vfio_sub_page_bar_update_mapping(pdev, bar); } } @@ -1292,7 +1335,7 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) } /* MSI-X table start and end aligned to host page size */ - start = vdev->msix->table_offset & qemu_real_host_page_mask; + start = vdev->msix->table_offset & qemu_real_host_page_mask(); end = REAL_HOST_PAGE_ALIGN((uint64_t)vdev->msix->table_offset + (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE)); @@ -2337,7 +2380,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) g_free(reset); trace_vfio_pci_hot_reset_result(vdev->vbasedev.name, - ret ? "%m" : "Success"); + ret ? strerror(errno) : "Success"); out: /* Re-enable INTx on affected devices */ @@ -2478,7 +2521,7 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f) */ if (old_addr[bar] != pdev->io_regions[bar].addr && vdev->bars[bar].region.size > 0 && - vdev->bars[bar].region.size < qemu_real_host_page_size) { + vdev->bars[bar].region.size < qemu_real_host_page_size()) { vfio_sub_page_bar_update_mapping(pdev, bar); } } @@ -2803,6 +2846,7 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) static void vfio_realize(PCIDevice *pdev, Error **errp) { VFIOPCIDevice *vdev = VFIO_PCI(pdev); + VFIODevice *vbasedev = &vdev->vbasedev; VFIODevice *vbasedev_iter; VFIOGroup *group; char *tmp, *subsys, group_path[PATH_MAX], *group_name; @@ -2813,7 +2857,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) int i, ret; bool is_mdev; - if (!vdev->vbasedev.sysfsdev) { + if (!vbasedev->sysfsdev) { if (!(~vdev->host.domain || ~vdev->host.bus || ~vdev->host.slot || ~vdev->host.function)) { error_setg(errp, "No provided host device"); @@ -2821,24 +2865,24 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n"); return; } - vdev->vbasedev.sysfsdev = + vbasedev->sysfsdev = g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x", vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function); } - if (stat(vdev->vbasedev.sysfsdev, &st) < 0) { + if (stat(vbasedev->sysfsdev, &st) < 0) { error_setg_errno(errp, errno, "no such host device"); - error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev); + error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev); return; } - vdev->vbasedev.name = g_path_get_basename(vdev->vbasedev.sysfsdev); - vdev->vbasedev.ops = &vfio_pci_ops; - vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; - vdev->vbasedev.dev = DEVICE(vdev); + vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); + vbasedev->ops = &vfio_pci_ops; + vbasedev->type = VFIO_DEVICE_TYPE_PCI; + vbasedev->dev = DEVICE(vdev); - tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev); + tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); len = readlink(tmp, group_path, sizeof(group_path)); g_free(tmp); @@ -2856,7 +2900,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } - trace_vfio_realize(vdev->vbasedev.name, groupid); + trace_vfio_realize(vbasedev->name, groupid); group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp); if (!group) { @@ -2864,7 +2908,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) { + if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { error_setg(errp, "device is already attached"); vfio_put_group(group); goto error; @@ -2877,22 +2921,22 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) * stays in sync with the active working set of the guest driver. Prevent * the x-balloon-allowed option unless this is minimally an mdev device. */ - tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev); + tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev); subsys = realpath(tmp, NULL); g_free(tmp); is_mdev = subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); free(subsys); - trace_vfio_mdev(vdev->vbasedev.name, is_mdev); + trace_vfio_mdev(vbasedev->name, is_mdev); - if (vdev->vbasedev.ram_block_discard_allowed && !is_mdev) { + if (vbasedev->ram_block_discard_allowed && !is_mdev) { error_setg(errp, "x-balloon-allowed only potentially compatible " "with mdev devices"); vfio_put_group(group); goto error; } - ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp); + ret = vfio_get_device(group, vbasedev->name, vbasedev, errp); if (ret) { vfio_put_group(group); goto error; @@ -2905,7 +2949,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } /* Get a copy of config space */ - ret = pread(vdev->vbasedev.fd, vdev->pdev.config, + ret = pread(vbasedev->fd, vdev->pdev.config, MIN(pci_config_size(&vdev->pdev), vdev->config_size), vdev->config_offset); if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { @@ -2933,7 +2977,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0); - trace_vfio_pci_emulated_vendor_id(vdev->vbasedev.name, vdev->vendor_id); + trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id); } else { vdev->vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); } @@ -2944,7 +2988,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0); - trace_vfio_pci_emulated_device_id(vdev->vbasedev.name, vdev->device_id); + trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id); } else { vdev->device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); } @@ -2956,7 +3000,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID, vdev->sub_vendor_id, ~0); - trace_vfio_pci_emulated_sub_vendor_id(vdev->vbasedev.name, + trace_vfio_pci_emulated_sub_vendor_id(vbasedev->name, vdev->sub_vendor_id); } @@ -2966,7 +3010,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0); - trace_vfio_pci_emulated_sub_device_id(vdev->vbasedev.name, + trace_vfio_pci_emulated_sub_device_id(vbasedev->name, vdev->sub_device_id); } @@ -3025,7 +3069,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto out_teardown; } - ret = vfio_get_dev_region_info(&vdev->vbasedev, + ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion); if (ret) { @@ -3101,9 +3145,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } if (!pdev->failover_pair_id) { - ret = vfio_migration_probe(&vdev->vbasedev, errp); + ret = vfio_migration_probe(vbasedev, errp); if (ret) { - error_report("%s: Migration disabled", vdev->vbasedev.name); + error_report("%s: Migration disabled", vbasedev->name); } } @@ -3120,7 +3164,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_teardown_msi(vdev); vfio_bars_exit(vdev); error: - error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name); + error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name); } static void vfio_instance_finalize(Object *obj) diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 64777516d16d..177abcc8fb67 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -13,12 +13,13 @@ #define HW_VFIO_VFIO_PCI_H #include "exec/memory.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/vfio/vfio-common.h" #include "qemu/event_notifier.h" #include "qemu/queue.h" #include "qemu/timer.h" #include "qom/object.h" +#include "sysemu/kvm.h" #define PCI_ANY_ID (~0) @@ -171,6 +172,7 @@ struct VFIOPCIDevice { bool no_kvm_ioeventfd; bool no_vfio_ioeventfd; bool enable_ramfb; + bool defer_kvm_irq_routing; VFIODisplay *dpy; Notifier irqchip_change_notifier; }; diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 04c6e67f8fba..9ec1e95f6da7 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -44,7 +44,7 @@ static void vfio_prereg_listener_region_add(MemoryListener *listener, const hwaddr gpa = section->offset_within_address_space; hwaddr end; int ret; - hwaddr page_mask = qemu_real_host_page_mask; + hwaddr page_mask = qemu_real_host_page_mask(); struct vfio_iommu_spapr_register_memory reg = { .argsz = sizeof(reg), .flags = 0, @@ -102,7 +102,7 @@ static void vfio_prereg_listener_region_del(MemoryListener *listener, const hwaddr gpa = section->offset_within_address_space; hwaddr end; int ret; - hwaddr page_mask = qemu_real_host_page_mask; + hwaddr page_mask = qemu_real_host_page_mask(); struct vfio_iommu_spapr_register_memory reg = { .argsz = sizeof(reg), .flags = 0, @@ -199,12 +199,12 @@ int vfio_spapr_create_window(VFIOContainer *container, * Below we look at qemu_real_host_page_size as TCEs are allocated from * system pages. */ - bits_per_level = ctz64(qemu_real_host_page_size) + 8; + bits_per_level = ctz64(qemu_real_host_page_size()) + 8; create.levels = bits_total / bits_per_level; if (bits_total % bits_per_level) { ++create.levels; } - max_levels = (64 - create.page_shift) / ctz64(qemu_real_host_page_size); + max_levels = (64 - create.page_shift) / ctz64(qemu_real_host_page_size()); for ( ; create.levels <= max_levels; ++create.levels) { ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); if (!ret) { diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 0ef1b5f4a65f..73dffe9e00d5 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -100,6 +100,7 @@ vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" +vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA" vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index c144d42f9bd0..89e9e426d854 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -1,6 +1,3 @@ -config VHOST - bool - config VIRTIO bool @@ -59,6 +56,16 @@ config VIRTIO_MEM depends on VIRTIO_MEM_SUPPORTED select MEM_DEVICE +config VHOST_VSOCK + bool + default y + depends on VIRTIO && VHOST_KERNEL + +config VHOST_USER_VSOCK + bool + default y + depends on VIRTIO && VHOST_USER + config VHOST_USER_I2C bool default y @@ -68,3 +75,18 @@ config VHOST_USER_RNG bool default y depends on VIRTIO && VHOST_USER + +config VHOST_USER_FS + bool + default y + depends on VIRTIO && VHOST_USER + +config VHOST_USER_GPIO + bool + default y + depends on VIRTIO && VHOST_USER + +config VHOST_VDPA_DEV + bool + default y + depends on VIRTIO && VHOST_VDPA && LINUX diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 67dc77e00fb4..f93be2e1372d 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -2,41 +2,50 @@ softmmu_virtio_ss = ss.source_set() softmmu_virtio_ss.add(files('virtio-bus.c')) softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VHOST', if_false: files('vhost-stub.c')) -softmmu_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss) -softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) +specific_virtio_ss = ss.source_set() +specific_virtio_ss.add(files('virtio.c')) +specific_virtio_ss.add(files('virtio-config-io.c', 'virtio-qmp.c')) -softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) +if have_vhost + specific_virtio_ss.add(files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) + if have_vhost_user + specific_virtio_ss.add(files('vhost-user.c')) + endif + if have_vhost_vdpa + specific_virtio_ss.add(files('vhost-vdpa.c', 'vhost-shadow-virtqueue.c')) + endif +else + softmmu_virtio_ss.add(files('vhost-stub.c')) +endif -virtio_ss = ss.source_set() -virtio_ss.add(files('virtio.c')) -virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) -virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) -virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-shadow-virtqueue.c', 'vhost-vdpa.c')) -virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) -virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) -virtio_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VIRTIO_PCI'], if_true: files('virtio-crypto-pci.c')) -virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) -virtio_ss.add(when: ['CONFIG_VHOST_USER_FS', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-fs-pci.c')) -virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) -virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c', 'vhost-vsock-common.c')) -virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c', 'vhost-vsock-common.c')) -virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) -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_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'], if_true: files('vhost-user-i2c-pci.c')) -virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) -virtio_ss.add(when: ['CONFIG_VHOST_USER_RNG', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-rng-pci.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c', 'vhost-vsock-common.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c', 'vhost-vsock-common.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c')) +specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-pci.c')) + +virtio_pci_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng-pci.c')) @@ -49,7 +58,14 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-serial-pc virtio_pci_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev-pci.c')) -virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) +specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_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')) -specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: virtio_ss) +specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: specific_virtio_ss) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index a5102eac9e57..a87c5f39a2f6 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, bool vrings) "%p:%s vrings:%d" +vhost_dev_stop(void *dev, const char *name, bool vrings) "%p:%s vrings:%d" + # vhost-user.c vhost_user_postcopy_end_entry(void) "" @@ -21,10 +25,15 @@ vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_siz vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" +vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" +vhost_user_create_notifier(int idx, void *n) "idx:%d n:%p" # vhost-vdpa.c -vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 -vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 +vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 +vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 +vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 +vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d" vhost_vdpa_listener_region_del(void *vdpa, uint64_t iova, uint64_t llend) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64 vhost_vdpa_add_status(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8 @@ -53,6 +62,7 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI vhost_vdpa_set_owner(void *dev) "dev: %p" vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 +vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" # virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" @@ -87,7 +97,12 @@ virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 " virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d" virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d" -# virtio-iommu.c +# virtio-pci.c +virtio_pci_notify(uint16_t vector) "virtio_pci_notify vec 0x%x" +virtio_pci_notify_write(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)" +virtio_pci_notify_write_pio(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)" + +# hw/virtio/virtio-iommu.c virtio_iommu_device_reset(void) "reset!" virtio_iommu_system_reset(void) "system reset!" virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64 @@ -114,6 +129,7 @@ virtio_iommu_remap(const char *name, uint64_t virt_start, uint64_t virt_end, uin virtio_iommu_set_page_size_mask(const char *name, uint64_t old, uint64_t new) "mr=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64 virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s" virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s" +virtio_iommu_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)" # virtio-mem.c virtio_mem_send_response(uint16_t type) "type=%" PRIu16 @@ -129,3 +145,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/vdpa-dev-pci.c b/hw/virtio/vdpa-dev-pci.c new file mode 100644 index 000000000000..5446e6b393ef --- /dev/null +++ b/hw/virtio/vdpa-dev-pci.c @@ -0,0 +1,102 @@ +/* + * Vhost Vdpa Device PCI Bindings + * + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved. + * + * Authors: + * Longpeng + * + * Largely based on the "vhost-user-blk-pci.c" and "vhost-user-blk.c" + * implemented by: + * Changpeng Liu + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#include "qemu/osdep.h" +#include +#include +#include "hw/virtio/virtio.h" +#include "hw/virtio/vdpa-dev.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/module.h" +#include "hw/virtio/virtio-pci.h" +#include "qom/object.h" + + +typedef struct VhostVdpaDevicePCI VhostVdpaDevicePCI; + +#define TYPE_VHOST_VDPA_DEVICE_PCI "vhost-vdpa-device-pci-base" +DECLARE_INSTANCE_CHECKER(VhostVdpaDevicePCI, VHOST_VDPA_DEVICE_PCI, + TYPE_VHOST_VDPA_DEVICE_PCI) + +struct VhostVdpaDevicePCI { + VirtIOPCIProxy parent_obj; + VhostVdpaDevice vdev; +}; + +static void vhost_vdpa_device_pci_instance_init(Object *obj) +{ + VhostVdpaDevicePCI *dev = VHOST_VDPA_DEVICE_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_VDPA_DEVICE); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex"); +} + +static Property vhost_vdpa_device_pci_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static int vhost_vdpa_device_pci_post_init(VhostVdpaDevice *v, Error **errp) +{ + VhostVdpaDevicePCI *dev = container_of(v, VhostVdpaDevicePCI, vdev); + VirtIOPCIProxy *vpci_dev = &dev->parent_obj; + + vpci_dev->class_code = virtio_pci_get_class_id(v->vdev_id); + vpci_dev->trans_devid = virtio_pci_get_trans_devid(v->vdev_id); + /* one for config vector */ + vpci_dev->nvectors = v->num_queues + 1; + + return 0; +} + +static void +vhost_vdpa_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VhostVdpaDevicePCI *dev = VHOST_VDPA_DEVICE_PCI(vpci_dev); + + dev->vdev.post_init = vhost_vdpa_device_pci_post_init; + qdev_realize(DEVICE(&dev->vdev), BUS(&vpci_dev->bus), errp); +} + +static void vhost_vdpa_device_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + device_class_set_props(dc, vhost_vdpa_device_pci_properties); + k->realize = vhost_vdpa_device_pci_realize; +} + +static const VirtioPCIDeviceTypeInfo vhost_vdpa_device_pci_info = { + .base_name = TYPE_VHOST_VDPA_DEVICE_PCI, + .generic_name = "vhost-vdpa-device-pci", + .transitional_name = "vhost-vdpa-device-pci-transitional", + .non_transitional_name = "vhost-vdpa-device-pci-non-transitional", + .instance_size = sizeof(VhostVdpaDevicePCI), + .instance_init = vhost_vdpa_device_pci_instance_init, + .class_init = vhost_vdpa_device_pci_class_init, +}; + +static void vhost_vdpa_device_pci_register(void) +{ + virtio_pci_types_register(&vhost_vdpa_device_pci_info); +} + +type_init(vhost_vdpa_device_pci_register); diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c new file mode 100644 index 000000000000..01b41eb0f123 --- /dev/null +++ b/hw/virtio/vdpa-dev.c @@ -0,0 +1,386 @@ +/* + * Vhost Vdpa Device + * + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved. + * + * Authors: + * Longpeng + * + * Largely based on the "vhost-user-blk-pci.c" and "vhost-user-blk.c" + * implemented by: + * Changpeng Liu + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#include "qemu/osdep.h" +#include +#include +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/cutils.h" +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" +#include "hw/virtio/vdpa-dev.h" +#include "sysemu/sysemu.h" +#include "sysemu/runstate.h" + +static void +vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* Nothing to do */ +} + +static uint32_t +vhost_vdpa_device_get_u32(int fd, unsigned long int cmd, Error **errp) +{ + uint32_t val = (uint32_t)-1; + + if (ioctl(fd, cmd, &val) < 0) { + error_setg(errp, "vhost-vdpa-device: cmd 0x%lx failed: %s", + cmd, strerror(errno)); + } + + return val; +} + +static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VhostVdpaDevice *v = VHOST_VDPA_DEVICE(vdev); + struct vhost_vdpa_iova_range iova_range; + uint16_t max_queue_size; + struct vhost_virtqueue *vqs; + int i, ret; + + if (!v->vhostdev) { + error_setg(errp, "vhost-vdpa-device: vhostdev are missing"); + return; + } + + v->vhostfd = qemu_open(v->vhostdev, O_RDWR, errp); + if (*errp) { + return; + } + v->vdpa.device_fd = v->vhostfd; + + v->vdev_id = vhost_vdpa_device_get_u32(v->vhostfd, + VHOST_VDPA_GET_DEVICE_ID, errp); + if (*errp) { + goto out; + } + + max_queue_size = vhost_vdpa_device_get_u32(v->vhostfd, + VHOST_VDPA_GET_VRING_NUM, errp); + if (*errp) { + goto out; + } + + if (v->queue_size > max_queue_size) { + error_setg(errp, "vhost-vdpa-device: invalid queue_size: %u (max:%u)", + v->queue_size, max_queue_size); + goto out; + } else if (!v->queue_size) { + v->queue_size = max_queue_size; + } + + v->num_queues = vhost_vdpa_device_get_u32(v->vhostfd, + VHOST_VDPA_GET_VQS_COUNT, errp); + if (*errp) { + goto out; + } + + if (!v->num_queues || v->num_queues > VIRTIO_QUEUE_MAX) { + error_setg(errp, "invalid number of virtqueues: %u (max:%u)", + v->num_queues, VIRTIO_QUEUE_MAX); + goto out; + } + + v->dev.nvqs = v->num_queues; + vqs = g_new0(struct vhost_virtqueue, v->dev.nvqs); + v->dev.vqs = vqs; + v->dev.vq_index = 0; + v->dev.vq_index_end = v->dev.nvqs; + v->dev.backend_features = 0; + v->started = false; + + ret = vhost_vdpa_get_iova_range(v->vhostfd, &iova_range); + if (ret < 0) { + error_setg(errp, "vhost-vdpa-device: get iova range failed: %s", + strerror(-ret)); + goto free_vqs; + } + v->vdpa.iova_range = iova_range; + + ret = vhost_dev_init(&v->dev, &v->vdpa, VHOST_BACKEND_TYPE_VDPA, 0, NULL); + if (ret < 0) { + error_setg(errp, "vhost-vdpa-device: vhost initialization failed: %s", + strerror(-ret)); + goto free_vqs; + } + + v->config_size = vhost_vdpa_device_get_u32(v->vhostfd, + VHOST_VDPA_GET_CONFIG_SIZE, + errp); + if (*errp) { + goto vhost_cleanup; + } + + /* + * Invoke .post_init() to initialize the transport-specific fields + * before calling virtio_init(). + */ + if (v->post_init && v->post_init(v, errp) < 0) { + goto vhost_cleanup; + } + + v->config = g_malloc0(v->config_size); + + ret = vhost_dev_get_config(&v->dev, v->config, v->config_size, NULL); + if (ret < 0) { + error_setg(errp, "vhost-vdpa-device: get config failed"); + goto free_config; + } + + virtio_init(vdev, v->vdev_id, v->config_size); + + v->virtqs = g_new0(VirtQueue *, v->dev.nvqs); + for (i = 0; i < v->dev.nvqs; i++) { + v->virtqs[i] = virtio_add_queue(vdev, v->queue_size, + vhost_vdpa_device_dummy_handle_output); + } + + return; + +free_config: + g_free(v->config); +vhost_cleanup: + vhost_dev_cleanup(&v->dev); +free_vqs: + g_free(vqs); +out: + qemu_close(v->vhostfd); + v->vhostfd = -1; +} + +static void vhost_vdpa_device_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + int i; + + virtio_set_status(vdev, 0); + + for (i = 0; i < s->num_queues; i++) { + virtio_delete_queue(s->virtqs[i]); + } + g_free(s->virtqs); + virtio_cleanup(vdev); + + g_free(s->config); + g_free(s->dev.vqs); + vhost_dev_cleanup(&s->dev); + qemu_close(s->vhostfd); + s->vhostfd = -1; +} + +static void +vhost_vdpa_device_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + + memcpy(config, s->config, s->config_size); +} + +static void +vhost_vdpa_device_set_config(VirtIODevice *vdev, const uint8_t *config) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + int ret; + + ret = vhost_dev_set_config(&s->dev, s->config, 0, s->config_size, + VHOST_SET_CONFIG_TYPE_MASTER); + if (ret) { + error_report("set device config space failed"); + return; + } +} + +static uint64_t vhost_vdpa_device_get_features(VirtIODevice *vdev, + uint64_t features, + Error **errp) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + uint64_t backend_features = s->dev.features; + + if (!virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM)) { + virtio_clear_feature(&backend_features, VIRTIO_F_IOMMU_PLATFORM); + } + + return backend_features; +} + +static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int i, ret; + + if (!k->set_guest_notifiers) { + error_setg(errp, "binding does not support guest notifiers"); + return -ENOSYS; + } + + ret = vhost_dev_enable_notifiers(&s->dev, vdev); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error enabling host notifiers"); + return ret; + } + + ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error binding guest notifier"); + goto err_host_notifiers; + } + + s->dev.acked_features = vdev->guest_features; + + ret = vhost_dev_start(&s->dev, vdev, false); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; + } + s->started = true; + + /* + * 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 < s->dev.nvqs; i++) { + vhost_virtqueue_mask(&s->dev, vdev, i, false); + } + + return ret; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&s->dev, vdev); + return ret; +} + +static void vhost_vdpa_device_stop(VirtIODevice *vdev) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret; + + if (!s->started) { + return; + } + s->started = false; + + if (!k->set_guest_notifiers) { + return; + } + + vhost_dev_stop(&s->dev, vdev, false); + + ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return; + } + + vhost_dev_disable_notifiers(&s->dev, vdev); +} + +static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + bool should_start = virtio_device_started(vdev, status); + Error *local_err = NULL; + int ret; + + if (!vdev->vm_running) { + should_start = false; + } + + if (s->started == should_start) { + return; + } + + if (should_start) { + ret = vhost_vdpa_device_start(vdev, &local_err); + if (ret < 0) { + error_reportf_err(local_err, "vhost-vdpa-device: start failed: "); + } + } else { + vhost_vdpa_device_stop(vdev); + } +} + +static Property vhost_vdpa_device_properties[] = { + DEFINE_PROP_STRING("vhostdev", VhostVdpaDevice, vhostdev), + DEFINE_PROP_UINT16("queue-size", VhostVdpaDevice, queue_size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_vhost_vdpa_device = { + .name = "vhost-vdpa-device", + .unmigratable = 1, + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; + +static void vhost_vdpa_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + device_class_set_props(dc, vhost_vdpa_device_properties); + dc->desc = "VDPA-based generic device assignment"; + dc->vmsd = &vmstate_vhost_vdpa_device; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + vdc->realize = vhost_vdpa_device_realize; + vdc->unrealize = vhost_vdpa_device_unrealize; + vdc->get_config = vhost_vdpa_device_get_config; + vdc->set_config = vhost_vdpa_device_set_config; + vdc->get_features = vhost_vdpa_device_get_features; + vdc->set_status = vhost_vdpa_device_set_status; +} + +static void vhost_vdpa_device_instance_init(Object *obj) +{ + VhostVdpaDevice *s = VHOST_VDPA_DEVICE(obj); + + device_add_bootindex_property(obj, &s->bootindex, "bootindex", + NULL, DEVICE(obj)); +} + +static const TypeInfo vhost_vdpa_device_info = { + .name = TYPE_VHOST_VDPA_DEVICE, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VhostVdpaDevice), + .class_init = vhost_vdpa_device_class_init, + .instance_init = vhost_vdpa_device_instance_init, +}; + +static void register_vhost_vdpa_device_type(void) +{ + type_register_static(&vhost_vdpa_device_info); +} + +type_init(register_vhost_vdpa_device_type); diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index e409a865aeb3..8e581575c9b3 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -146,6 +146,12 @@ static int vhost_kernel_set_vring_call(struct vhost_dev *dev, return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file); } +static int vhost_kernel_set_vring_err(struct vhost_dev *dev, + struct vhost_vring_file *file) +{ + return vhost_kernel_call(dev, VHOST_SET_VRING_ERR, file); +} + static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev, struct vhost_vring_state *s) { @@ -203,7 +209,6 @@ static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx) return idx - dev->vq_index; } -#ifdef CONFIG_VHOST_VSOCK static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev, uint64_t guest_cid) { @@ -214,7 +219,6 @@ static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start) { return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start); } -#endif /* CONFIG_VHOST_VSOCK */ static void vhost_kernel_iotlb_read(void *opaque) { @@ -311,6 +315,7 @@ const VhostOps kernel_ops = { .vhost_get_vring_base = vhost_kernel_get_vring_base, .vhost_set_vring_kick = vhost_kernel_set_vring_kick, .vhost_set_vring_call = vhost_kernel_set_vring_call, + .vhost_set_vring_err = vhost_kernel_set_vring_err, .vhost_set_vring_busyloop_timeout = vhost_kernel_set_vring_busyloop_timeout, .vhost_set_features = vhost_kernel_set_features, @@ -319,10 +324,8 @@ const VhostOps kernel_ops = { .vhost_set_owner = vhost_kernel_set_owner, .vhost_reset_device = vhost_kernel_reset_device, .vhost_get_vq_index = vhost_kernel_get_vq_index, -#ifdef CONFIG_VHOST_VSOCK .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, .vhost_vsock_set_running = vhost_kernel_vsock_set_running, -#endif /* CONFIG_VHOST_VSOCK */ .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback, .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg, }; diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c index 55fed1fefb43..3d03395a77b5 100644 --- a/hw/virtio/vhost-iova-tree.c +++ b/hw/virtio/vhost-iova-tree.c @@ -11,7 +11,7 @@ #include "qemu/iova-tree.h" #include "vhost-iova-tree.h" -#define iova_min_addr qemu_real_host_page_size +#define iova_min_addr qemu_real_host_page_size() /** * VhostIOVATree, able to: @@ -86,7 +86,7 @@ const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree, int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map) { /* Some vhost devices do not like addr 0. Skip first page */ - hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size; + hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size(); if (map->translated_addr + map->size < map->translated_addr || map->perm == IOMMU_NONE) { @@ -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 6a4f24e0f9c6..4adfd79ff039 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-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c index cb71a294faaf..08980bc23bdb 100644 --- a/hw/virtio/vhost-scsi-pci.c +++ b/hw/virtio/vhost-scsi-pci.c @@ -21,7 +21,7 @@ #include "hw/virtio/vhost-scsi.h" #include "qapi/error.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostSCSIPCI VHostSCSIPCI; diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index b232803d1b19..430729635815 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -33,6 +33,7 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp) ++b) { switch (b) { case VIRTIO_F_ANY_LAYOUT: + case VIRTIO_RING_F_EVENT_IDX: continue; case VIRTIO_F_ACCESS_PLATFORM: @@ -122,22 +123,41 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, return true; } -static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, - const struct iovec *iovec, size_t num, - bool more_descs, bool write) +/** + * Write descriptors to SVQ vring + * + * @svq: The shadow virtqueue + * @sg: Cache for hwaddr + * @iovec: The iovec from the guest + * @num: iovec length + * @more_descs: True if more descriptors come in the chain + * @write: True if they are writeable descriptors + * + * Return true if success, false otherwise and print error. + */ +static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + const struct iovec *iovec, size_t num, + bool more_descs, bool write) { uint16_t i = svq->free_head, last = svq->free_head; unsigned n; uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0; vring_desc_t *descs = svq->vring.desc; + bool ok; if (num == 0) { - return; + return true; + } + + ok = vhost_svq_translate_addr(svq, sg, iovec, num); + if (unlikely(!ok)) { + return false; } for (n = 0; n < num; n++) { if (more_descs || (n + 1 < num)) { descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT); + descs[i].next = cpu_to_le16(svq->desc_next[i]); } else { descs[i].flags = flags; } @@ -145,44 +165,43 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, descs[i].len = cpu_to_le32(iovec[n].iov_len); last = i; - i = cpu_to_le16(descs[i].next); + i = cpu_to_le16(svq->desc_next[i]); } - svq->free_head = le16_to_cpu(descs[last].next); + svq->free_head = le16_to_cpu(svq->desc_next[last]); + return true; } static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, - VirtQueueElement *elem, unsigned *head) + const struct iovec *out_sg, size_t out_num, + const struct iovec *in_sg, size_t in_num, + unsigned *head) { unsigned avail_idx; vring_avail_t *avail = svq->vring.avail; bool ok; - g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num)); + g_autofree hwaddr *sgs = g_new(hwaddr, MAX(out_num, in_num)); *head = svq->free_head; /* We need some descriptors here */ - if (unlikely(!elem->out_num && !elem->in_num)) { + if (unlikely(!out_num && !in_num)) { qemu_log_mask(LOG_GUEST_ERROR, "Guest provided element with no descriptors"); return false; } - ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num); + ok = vhost_svq_vring_write_descs(svq, sgs, out_sg, out_num, in_num > 0, + false); if (unlikely(!ok)) { return false; } - vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, - elem->in_num > 0, false); - - ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num); + ok = vhost_svq_vring_write_descs(svq, sgs, in_sg, in_num, false, true); if (unlikely(!ok)) { return false; } - vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true); - /* * Put the entry in the available array (but don't update avail->idx until * they do sync). @@ -198,32 +217,66 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, return true; } -static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) -{ - unsigned qemu_head; - bool ok = vhost_svq_add_split(svq, elem, &qemu_head); - if (unlikely(!ok)) { - return false; - } - - svq->ring_id_maps[qemu_head] = elem; - return true; -} - static void vhost_svq_kick(VhostShadowVirtqueue *svq) { + bool needs_kick; + /* * We need to expose the available array entries before checking the used * flags */ smp_mb(); - if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { + + if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) { + uint16_t avail_event = *(uint16_t *)(&svq->vring.used->ring[svq->vring.num]); + needs_kick = vring_need_event(avail_event, svq->shadow_avail_idx, svq->shadow_avail_idx - 1); + } else { + needs_kick = !(svq->vring.used->flags & VRING_USED_F_NO_NOTIFY); + } + + if (!needs_kick) { return; } event_notifier_set(&svq->hdev_kick); } +/** + * Add an element to a SVQ. + * + * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + size_t out_num, const struct iovec *in_sg, size_t in_num, + VirtQueueElement *elem) +{ + unsigned qemu_head; + unsigned ndescs = in_num + out_num; + bool ok; + + if (unlikely(ndescs > vhost_svq_available_slots(svq))) { + return -ENOSPC; + } + + ok = vhost_svq_add_split(svq, out_sg, out_num, in_sg, in_num, &qemu_head); + if (unlikely(!ok)) { + return -EINVAL; + } + + svq->desc_state[qemu_head].elem = elem; + svq->desc_state[qemu_head].ndescs = ndescs; + vhost_svq_kick(svq); + return 0; +} + +/* Convenience wrapper to add a guest's element to SVQ */ +static int vhost_svq_add_element(VhostShadowVirtqueue *svq, + VirtQueueElement *elem) +{ + return vhost_svq_add(svq, elem->out_sg, elem->out_num, elem->in_sg, + elem->in_num, elem); +} + /** * Forward available buffers. * @@ -247,8 +300,8 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) virtio_queue_set_notification(svq->vq, false); while (true) { - VirtQueueElement *elem; - bool ok; + g_autofree VirtQueueElement *elem = NULL; + int r; if (svq->next_guest_avail_elem) { elem = g_steal_pointer(&svq->next_guest_avail_elem); @@ -260,28 +313,32 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) break; } - if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) { - /* - * This condition is possible since a contiguous buffer in GPA - * does not imply a contiguous buffer in qemu's VA - * scatter-gather segments. If that happens, the buffer exposed - * to the device needs to be a chain of descriptors at this - * moment. - * - * SVQ cannot hold more available buffers if we are here: - * queue the current guest descriptor and ignore further kicks - * until some elements are used. - */ - svq->next_guest_avail_elem = elem; - return; + if (svq->ops) { + r = svq->ops->avail_handler(svq, elem, svq->ops_opaque); + } else { + r = vhost_svq_add_element(svq, elem); } - - ok = vhost_svq_add(svq, elem); - if (unlikely(!ok)) { - /* VQ is broken, just return and ignore any other kicks */ + if (unlikely(r != 0)) { + if (r == -ENOSPC) { + /* + * This condition is possible since a contiguous buffer in + * GPA does not imply a contiguous buffer in qemu's VA + * scatter-gather segments. If that happens, the buffer + * exposed to the device needs to be a chain of descriptors + * at this moment. + * + * SVQ cannot hold more available buffers if we are here: + * queue the current guest descriptor and ignore kicks + * until some elements are used. + */ + svq->next_guest_avail_elem = g_steal_pointer(&elem); + } + + /* VQ is full or broken, just return and ignore kicks */ return; } - vhost_svq_kick(svq); + /* elem belongs to SVQ or external caller now */ + elem = NULL; } virtio_queue_set_notification(svq->vq, true); @@ -302,11 +359,12 @@ static void vhost_handle_guest_kick_notifier(EventNotifier *n) static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) { + uint16_t *used_idx = &svq->vring.used->idx; if (svq->last_used_idx != svq->shadow_used_idx) { return true; } - svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx); + svq->shadow_used_idx = cpu_to_le16(*(volatile uint16_t *)used_idx); return svq->last_used_idx != svq->shadow_used_idx; } @@ -322,24 +380,45 @@ static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) */ static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq) { - svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); - /* Make sure the flag is written before the read of used_idx */ + if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) { + uint16_t *used_event = (uint16_t *)&svq->vring.avail->ring[svq->vring.num]; + *used_event = svq->shadow_used_idx; + } else { + svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); + } + + /* Make sure the event is enabled before the read of used_idx */ smp_mb(); return !vhost_svq_more_used(svq); } static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) { - svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); + /* + * No need to disable notification in the event idx case, since used event + * index is already an index too far away. + */ + if (!virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) { + svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); + } +} + +static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq, + uint16_t num, uint16_t i) +{ + for (uint16_t j = 0; j < (num - 1); ++j) { + i = le16_to_cpu(svq->desc_next[i]); + } + + return i; } static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, uint32_t *len) { - vring_desc_t *descs = svq->vring.desc; const vring_used_t *used = svq->vring.used; vring_used_elem_t used_elem; - uint16_t last_used; + uint16_t last_used, last_used_chain, num; if (!vhost_svq_more_used(svq)) { return NULL; @@ -358,18 +437,37 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, return NULL; } - if (unlikely(!svq->ring_id_maps[used_elem.id])) { + 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); return NULL; } - descs[used_elem.id].next = svq->free_head; + 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; *len = used_elem.len; - return g_steal_pointer(&svq->ring_id_maps[used_elem.id]); + return g_steal_pointer(&svq->desc_state[used_elem.id].elem); +} + +/** + * Push an element to SVQ, returning it to the guest. + */ +void vhost_svq_push_elem(VhostShadowVirtqueue *svq, + const VirtQueueElement *elem, uint32_t len) +{ + virtqueue_push(svq->vq, elem, len); + if (svq->next_guest_avail_elem) { + /* + * Avail ring was full when vhost_svq_flush was called, so it's a + * good moment to make more descriptors available if possible. + */ + vhost_handle_guest_kick(svq); + } } static void vhost_svq_flush(VhostShadowVirtqueue *svq, @@ -413,6 +511,33 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq, } while (!vhost_svq_enable_notification(svq)); } +/** + * Poll the SVQ for one device used buffer. + * + * This function race with main event loop SVQ polling, so extra + * synchronization is needed. + * + * Return the length written by the device. + */ +size_t vhost_svq_poll(VhostShadowVirtqueue *svq) +{ + int64_t start_us = g_get_monotonic_time(); + uint32_t len; + + do { + if (vhost_svq_more_used(svq)) { + break; + } + + if (unlikely(g_get_monotonic_time() - start_us > 10e6)) { + return 0; + } + } while (true); + + vhost_svq_get_buf(svq, &len); + return len; +} + /** * Forward used buffers. * @@ -468,17 +593,17 @@ void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq) { size_t desc_size = sizeof(vring_desc_t) * svq->vring.num; - size_t avail_size = offsetof(vring_avail_t, ring) + - sizeof(uint16_t) * svq->vring.num; + size_t avail_size = offsetof(vring_avail_t, ring[svq->vring.num]) + + sizeof(uint16_t); - return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size); + return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size()); } size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq) { - size_t used_size = offsetof(vring_used_t, ring) + - sizeof(vring_used_elem_t) * svq->vring.num; - return ROUND_UP(used_size, qemu_real_host_page_size); + size_t used_size = offsetof(vring_used_t, ring[svq->vring.num]) + + sizeof(uint16_t); + return ROUND_UP(used_size, qemu_real_host_page_size()); } /** @@ -499,13 +624,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); } @@ -517,31 +642,35 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) * @svq: Shadow Virtqueue * @vdev: VirtIO device * @vq: Virtqueue to shadow + * @iova_tree: Tree to perform descriptors translations */ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, - VirtQueue *vq) + VirtQueue *vq, VhostIOVATree *iova_tree) { size_t desc_size, driver_size, device_size; + event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); svq->next_guest_avail_elem = NULL; svq->shadow_avail_idx = 0; svq->shadow_used_idx = 0; svq->last_used_idx = 0; svq->vdev = vdev; svq->vq = vq; + svq->iova_tree = iova_tree; svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); driver_size = vhost_svq_driver_area_size(svq); device_size = vhost_svq_device_area_size(svq); - svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size); + svq->vring.desc = qemu_memalign(qemu_real_host_page_size(), driver_size); desc_size = sizeof(vring_desc_t) * svq->vring.num; svq->vring.avail = (void *)((char *)svq->vring.desc + desc_size); memset(svq->vring.desc, 0, driver_size); - svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); + svq->vring.used = qemu_memalign(qemu_real_host_page_size(), device_size); memset(svq->vring.used, 0, device_size); - svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); + svq->desc_state = g_new0(SVQDescState, svq->vring.num); + svq->desc_next = g_new0(uint16_t, svq->vring.num); for (unsigned i = 0; i < svq->vring.num - 1; i++) { - svq->vring.desc[i].next = cpu_to_le16(i + 1); + svq->desc_next[i] = cpu_to_le16(i + 1); } } @@ -551,7 +680,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) { @@ -563,7 +692,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) for (unsigned i = 0; i < svq->vring.num; ++i) { g_autofree VirtQueueElement *elem = NULL; - elem = g_steal_pointer(&svq->ring_id_maps[i]); + elem = g_steal_pointer(&svq->desc_state[i].elem); if (elem) { virtqueue_detach_element(svq->vq, elem, 0); } @@ -574,50 +703,29 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) virtqueue_detach_element(svq->vq, next_avail_elem, 0); } svq->vq = NULL; - g_free(svq->ring_id_maps); + g_free(svq->desc_next); + g_free(svq->desc_state); qemu_vfree(svq->vring.desc); qemu_vfree(svq->vring.used); + event_notifier_set_handler(&svq->hdev_call, NULL); } /** * Creates vhost shadow virtqueue, and instructs the vhost device to use the * shadow methods and file descriptors. * - * @iova_tree: Tree to perform descriptors translations - * - * Returns the new virtqueue or NULL. - * - * In case of error, reason is reported through error_report. + * @ops: SVQ owner callbacks + * @ops_opaque: ops opaque pointer */ -VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) +VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, + void *ops_opaque) { - g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); - int r; - - r = event_notifier_init(&svq->hdev_kick, 0); - if (r != 0) { - error_report("Couldn't create kick event notifier: %s (%d)", - g_strerror(errno), errno); - goto err_init_hdev_kick; - } - - r = event_notifier_init(&svq->hdev_call, 0); - if (r != 0) { - error_report("Couldn't create call event notifier: %s (%d)", - g_strerror(errno), errno); - goto err_init_hdev_call; - } + VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); - event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); - svq->iova_tree = iova_tree; - return g_steal_pointer(&svq); - -err_init_hdev_call: - event_notifier_cleanup(&svq->hdev_kick); - -err_init_hdev_kick: - return NULL; + svq->ops = ops; + svq->ops_opaque = ops_opaque; + return svq; } /** @@ -629,8 +737,5 @@ void vhost_svq_free(gpointer pvq) { VhostShadowVirtqueue *vq = pvq; vhost_svq_stop(vq); - event_notifier_cleanup(&vq->hdev_kick); - event_notifier_set_handler(&vq->hdev_call, NULL); - event_notifier_cleanup(&vq->hdev_call); g_free(vq); } diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h index e5e24c536d03..926a4897b135 100644 --- a/hw/virtio/vhost-shadow-virtqueue.h +++ b/hw/virtio/vhost-shadow-virtqueue.h @@ -15,6 +15,37 @@ #include "standard-headers/linux/vhost_types.h" #include "hw/virtio/vhost-iova-tree.h" +typedef struct SVQDescState { + VirtQueueElement *elem; + + /* + * Number of descriptors exposed to the device. May or may not match + * guest's + */ + unsigned int ndescs; +} SVQDescState; + +typedef struct VhostShadowVirtqueue VhostShadowVirtqueue; + +/** + * Callback to handle an avail buffer. + * + * @svq: Shadow virtqueue + * @elem: Element placed in the queue by the guest + * @vq_callback_opaque: Opaque + * + * Returns 0 if the vq is running as expected. + * + * Note that ownership of elem is transferred to the callback. + */ +typedef int (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq, + VirtQueueElement *elem, + void *vq_callback_opaque); + +typedef struct VhostShadowVirtqueueOps { + VirtQueueAvailCallback avail_handler; +} VhostShadowVirtqueueOps; + /* Shadow virtqueue to relay notifications */ typedef struct VhostShadowVirtqueue { /* Shadow vring */ @@ -47,12 +78,24 @@ typedef struct VhostShadowVirtqueue { /* IOVA mapping */ VhostIOVATree *iova_tree; - /* Map for use the guest's descriptors */ - VirtQueueElement **ring_id_maps; + /* SVQ vring descriptors state */ + SVQDescState *desc_state; /* Next VirtQueue element that guest made available */ VirtQueueElement *next_guest_avail_elem; + /* + * Backup next field for each descriptor so we can recover securely, not + * needing to trust the device access. + */ + uint16_t *desc_next; + + /* Caller callbacks */ + const VhostShadowVirtqueueOps *ops; + + /* Caller callbacks opaque */ + void *ops_opaque; + /* Next head to expose to the device */ uint16_t shadow_avail_idx; @@ -68,6 +111,13 @@ typedef struct VhostShadowVirtqueue { bool vhost_svq_valid_features(uint64_t features, Error **errp); +void vhost_svq_push_elem(VhostShadowVirtqueue *svq, + const VirtQueueElement *elem, uint32_t len); +int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + size_t out_num, const struct iovec *in_sg, size_t in_num, + VirtQueueElement *elem); +size_t vhost_svq_poll(VhostShadowVirtqueue *svq); + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, @@ -76,10 +126,11 @@ size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, - VirtQueue *vq); + VirtQueue *vq, VhostIOVATree *iova_tree); void vhost_svq_stop(VhostShadowVirtqueue *svq); -VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree); +VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, + void *ops_opaque); void vhost_svq_free(gpointer vq); G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c index 33b404d8a225..eef8641a9891 100644 --- a/hw/virtio/vhost-user-blk-pci.c +++ b/hw/virtio/vhost-user-blk-pci.c @@ -26,7 +26,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostUserBlkPCI VHostUserBlkPCI; diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c index 2ed8492b3fa3..6829b8b74353 100644 --- a/hw/virtio/vhost-user-fs-pci.c +++ b/hw/virtio/vhost-user-fs-pci.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-fs.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" struct VHostUserFSPCI { diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index c59595798397..f5049735acf6 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" @@ -31,6 +32,7 @@ static const int user_feature_bits[] = { VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_RING_PACKED, VIRTIO_F_IOMMU_PLATFORM, + VIRTIO_F_RING_RESET, VHOST_INVALID_FEATURE_BIT }; @@ -74,7 +76,7 @@ static void vuf_start(VirtIODevice *vdev) } fs->vhost_dev.acked_features = vdev->guest_features; - ret = vhost_dev_start(&fs->vhost_dev, vdev); + ret = vhost_dev_start(&fs->vhost_dev, vdev, true); if (ret < 0) { error_report("Error starting vhost: %d", -ret); goto err_guest_notifiers; @@ -108,7 +110,7 @@ static void vuf_stop(VirtIODevice *vdev) return; } - vhost_dev_stop(&fs->vhost_dev, vdev); + vhost_dev_stop(&fs->vhost_dev, vdev, true); ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false); if (ret < 0) { @@ -122,13 +124,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_should_start(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; } @@ -161,6 +159,15 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, { VHostUserFS *fs = VHOST_USER_FS(vdev); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return; + } vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); } @@ -168,6 +175,15 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) { VHostUserFS *fs = VHOST_USER_FS(vdev); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return false; + } return vhost_virtqueue_pending(&fs->vhost_dev, idx); } @@ -219,8 +235,7 @@ static void vuf_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "vhost-user-fs", VIRTIO_ID_FS, - sizeof(struct virtio_fs_config)); + virtio_init(vdev, VIRTIO_ID_FS, sizeof(struct virtio_fs_config)); /* Hiprio queue */ fs->hiprio_vq = virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output); @@ -277,6 +292,12 @@ static void vuf_device_unrealize(DeviceState *dev) fs->vhost_dev.vqs = NULL; } +static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev) +{ + VHostUserFS *fs = VHOST_USER_FS(vdev); + return &fs->vhost_dev; +} + static const VMStateDescription vuf_vmstate = { .name = "vhost-user-fs", .unmigratable = 1, @@ -314,6 +335,7 @@ static void vuf_class_init(ObjectClass *klass, void *data) vdc->set_status = vuf_set_status; vdc->guest_notifier_mask = vuf_guest_notifier_mask; vdc->guest_notifier_pending = vuf_guest_notifier_pending; + vdc->get_vhost = vuf_get_vhost; } static const TypeInfo vuf_info = { diff --git a/hw/virtio/vhost-user-gpio-pci.c b/hw/virtio/vhost-user-gpio-pci.c new file mode 100644 index 000000000000..b3028a24a19a --- /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 000000000000..fe3da32c74f2 --- /dev/null +++ b/hw/virtio/vhost-user-gpio.c @@ -0,0 +1,428 @@ +/* + * 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, + VIRTIO_F_RING_RESET, + 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, false); + if (ret < 0) { + error_report("Error starting vhost-user-gpio: %d", ret); + goto err_guest_notifiers; + } + gpio->started_vu = true; + + /* + * 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 (!gpio->started_vu) { + return; + } + gpio->started_vu = false; + + if (!k->set_guest_notifiers) { + return; + } + + vhost_dev_stop(vhost_dev, vdev, false); + + 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_should_start(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); + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return; + } + + 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_event(void *opaque, QEMUChrEvent event); + +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); + + /* Re-instate the event handler for new connections */ + qemu_chr_fe_set_handlers(&gpio->chardev, + NULL, NULL, vu_gpio_event, + NULL, dev, NULL, true); +} + +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: + /* defer close until later to avoid circular close */ + vhost_user_async_close(dev, &gpio->chardev, &gpio->vhost_dev, + vu_gpio_disconnect); + 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-pci.c b/hw/virtio/vhost-user-i2c-pci.c index 70b7b65fd970..00ac10941fa3 100644 --- a/hw/virtio/vhost-user-i2c-pci.c +++ b/hw/virtio/vhost-user-i2c-pci.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-i2c.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" struct VHostUserI2CPCI { VirtIOPCIProxy parent_obj; diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c index 42c7f6d9e5bb..dc5c828ba6dc 100644 --- a/hw/virtio/vhost-user-i2c.c +++ b/hw/virtio/vhost-user-i2c.c @@ -14,13 +14,9 @@ #include "qemu/error-report.h" #include "standard-headers/linux/virtio_ids.h" -/* Remove this once the header is updated in Linux kernel */ -#ifndef VIRTIO_ID_I2C_ADAPTER -#define VIRTIO_ID_I2C_ADAPTER 34 -#endif - static const int feature_bits[] = { VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, + VIRTIO_F_RING_RESET, VHOST_INVALID_FEATURE_BIT }; @@ -50,7 +46,7 @@ static void vu_i2c_start(VirtIODevice *vdev) i2c->vhost_dev.acked_features = vdev->guest_features; - ret = vhost_dev_start(&i2c->vhost_dev, vdev); + ret = vhost_dev_start(&i2c->vhost_dev, vdev, true); if (ret < 0) { error_report("Error starting vhost-user-i2c: %d", -ret); goto err_guest_notifiers; @@ -84,7 +80,7 @@ static void vu_i2c_stop(VirtIODevice *vdev) return; } - vhost_dev_stop(&i2c->vhost_dev, vdev); + vhost_dev_stop(&i2c->vhost_dev, vdev, true); ret = k->set_guest_notifiers(qbus->parent, i2c->vhost_dev.nvqs, false); if (ret < 0) { @@ -98,13 +94,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; - - if (!vdev->vm_running) { - should_start = false; - } + bool should_start = virtio_device_should_start(vdev, status); - if (i2c->vhost_dev.started == should_start) { + if (vhost_dev_is_started(&i2c->vhost_dev) == should_start) { return; } @@ -183,7 +175,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); } } @@ -227,7 +219,7 @@ static void vu_i2c_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "vhost-user-i2c", VIRTIO_ID_I2C_ADAPTER, 0); + virtio_init(vdev, VIRTIO_ID_I2C_ADAPTER, 0); i2c->vhost_dev.nvqs = 1; i2c->vq = virtio_add_queue(vdev, 4, vu_i2c_handle_output); diff --git a/hw/virtio/vhost-user-input-pci.c b/hw/virtio/vhost-user-input-pci.c index c9d3e9113a5e..b858898a3630 100644 --- a/hw/virtio/vhost-user-input-pci.c +++ b/hw/virtio/vhost-user-input-pci.c @@ -9,7 +9,7 @@ #include "hw/virtio/virtio-input.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostUserInputPCI VHostUserInputPCI; diff --git a/hw/virtio/vhost-user-rng-pci.c b/hw/virtio/vhost-user-rng-pci.c index c83dc8681385..f64935453b68 100644 --- a/hw/virtio/vhost-user-rng-pci.c +++ b/hw/virtio/vhost-user-rng-pci.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-rng.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" struct VHostUserRNGPCI { VirtIOPCIProxy parent_obj; diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c index 209ee5bf9acd..201a39e220c5 100644 --- a/hw/virtio/vhost-user-rng.c +++ b/hw/virtio/vhost-user-rng.c @@ -16,6 +16,11 @@ #include "qemu/error-report.h" #include "standard-headers/linux/virtio_ids.h" +static const int feature_bits[] = { + VIRTIO_F_RING_RESET, + VHOST_INVALID_FEATURE_BIT +}; + static void vu_rng_start(VirtIODevice *vdev) { VHostUserRNG *rng = VHOST_USER_RNG(vdev); @@ -42,7 +47,7 @@ static void vu_rng_start(VirtIODevice *vdev) } rng->vhost_dev.acked_features = vdev->guest_features; - ret = vhost_dev_start(&rng->vhost_dev, vdev); + ret = vhost_dev_start(&rng->vhost_dev, vdev, true); if (ret < 0) { error_report("Error starting vhost-user-rng: %d", -ret); goto err_guest_notifiers; @@ -76,7 +81,7 @@ static void vu_rng_stop(VirtIODevice *vdev) return; } - vhost_dev_stop(&rng->vhost_dev, vdev); + vhost_dev_stop(&rng->vhost_dev, vdev, true); ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false); if (ret < 0) { @@ -90,13 +95,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_should_start(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; } @@ -110,8 +111,10 @@ static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status) static uint64_t vu_rng_get_features(VirtIODevice *vdev, uint64_t requested_features, Error **errp) { - /* No feature bits used yet */ - return requested_features; + VHostUserRNG *rng = VHOST_USER_RNG(vdev); + + return vhost_get_features(&rng->vhost_dev, feature_bits, + requested_features); } static void vu_rng_handle_output(VirtIODevice *vdev, VirtQueue *vq) @@ -164,7 +167,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); } } @@ -203,7 +206,7 @@ static void vu_rng_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "vhost-user-rng", VIRTIO_ID_RNG, 0); + virtio_init(vdev, VIRTIO_ID_RNG, 0); rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output); if (!rng->req_vq) { @@ -247,6 +250,12 @@ static void vu_rng_device_unrealize(DeviceState *dev) vhost_user_cleanup(&rng->vhost_user); } +static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) +{ + VHostUserRNG *rng = VHOST_USER_RNG(vdev); + return &rng->vhost_dev; +} + static const VMStateDescription vu_rng_vmstate = { .name = "vhost-user-rng", .unmigratable = 1, @@ -272,6 +281,7 @@ static void vu_rng_class_init(ObjectClass *klass, void *data) vdc->set_status = vu_rng_set_status; vdc->guest_notifier_mask = vu_rng_guest_notifier_mask; vdc->guest_notifier_pending = vu_rng_guest_notifier_pending; + vdc->get_vhost = vu_rng_get_vhost; } static const TypeInfo vu_rng_info = { diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c index d5343412a11c..75882e3cf943 100644 --- a/hw/virtio/vhost-user-scsi-pci.c +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -30,7 +30,7 @@ #include "hw/pci/msix.h" #include "hw/loader.h" #include "sysemu/kvm.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c index 72a96199cd21..e5a86e801362 100644 --- a/hw/virtio/vhost-user-vsock-pci.c +++ b/hw/virtio/vhost-user-vsock-pci.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-vsock.h" #include "qom/object.h" diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c index 52bd682c34d8..9431b9792cd5 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_should_start(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; } @@ -107,7 +103,7 @@ static void vuv_device_realize(DeviceState *dev, Error **errp) return; } - vhost_vsock_common_realize(vdev, "vhost-user-vsock"); + vhost_vsock_common_realize(vdev); vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops); diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 6abbc9da3202..d9ce0501b2c7 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -21,6 +21,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/sockets.h" +#include "sysemu/runstate.h" #include "sysemu/cryptodev.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" @@ -51,7 +52,7 @@ #include "hw/acpi/acpi.h" #define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS -#elif defined(TARGET_PPC) || defined(TARGET_PPC_64) +#elif defined(TARGET_PPC) || defined(TARGET_PPC64) #include "hw/ppc/spapr.h" #define VHOST_USER_MAX_RAM_SLOTS SPAPR_MAX_RAM_SLOTS @@ -81,6 +82,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, /* Feature 14 reserved for VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS. */ VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, + VHOST_USER_PROTOCOL_F_STATUS = 16, VHOST_USER_PROTOCOL_F_MAX }; @@ -126,6 +128,8 @@ typedef enum VhostUserRequest { VHOST_USER_GET_MAX_MEM_SLOTS = 36, VHOST_USER_ADD_MEM_REG = 37, VHOST_USER_REM_MEM_REG = 38, + VHOST_USER_SET_STATUS = 39, + VHOST_USER_GET_STATUS = 40, VHOST_USER_MAX } VhostUserRequest; @@ -200,7 +204,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 +212,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 +252,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 +300,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; } @@ -489,6 +496,8 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, return ret < 0 ? -saved_errno : -EIO; } + trace_vhost_user_write(msg->hdr.request, msg->hdr.flags); + return 0; } @@ -518,6 +527,11 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, .hdr.size = sizeof(msg.payload.log), }; + /* Send only once with first queue pair */ + if (dev->vq_index != 0) { + return 0; + } + if (shmfd && log->fd != -1) { fds[fd_num++] = log->fd; } @@ -751,7 +765,7 @@ static int send_remove_regions(struct vhost_dev *dev, vhost_user_fill_msg_region(®ion_buffer, shadow_reg, 0); msg->payload.mem_reg.region = region_buffer; - ret = vhost_user_write(dev, msg, &fd, 1); + ret = vhost_user_write(dev, msg, NULL, 0); if (ret < 0) { return ret; } @@ -1166,18 +1180,20 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev, static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) { assert(n && n->unmap_addr); - munmap(n->unmap_addr, qemu_real_host_page_size); + munmap(n->unmap_addr, qemu_real_host_page_size()); n->unmap_addr = NULL; } -static void vhost_user_host_notifier_remove(VhostUserState *user, - VirtIODevice *vdev, int queue_idx) +/* + * clean-up function for notifier, will finally free the structure + * under rcu. + */ +static void vhost_user_host_notifier_remove(VhostUserHostNotifier *n, + VirtIODevice *vdev) { - VhostUserHostNotifier *n = &user->notifier[queue_idx]; - if (n->addr) { if (vdev) { - virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); + virtio_queue_set_host_notifier_mr(vdev, n->idx, &n->mr, false); } assert(!n->unmap_addr); n->unmap_addr = n->addr; @@ -1221,6 +1237,15 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) return 0; } +static VhostUserHostNotifier *fetch_notifier(VhostUserState *u, + int idx) +{ + if (idx >= u->notifiers->len) { + return NULL; + } + return g_ptr_array_index(u->notifiers, idx); +} + static int vhost_user_get_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { @@ -1233,7 +1258,10 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, }; struct vhost_user *u = dev->opaque; - vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index); + VhostUserHostNotifier *n = fetch_notifier(u->user, ring->index); + if (n) { + vhost_user_host_notifier_remove(n, dev->vdev); + } ret = vhost_user_write(dev, &msg, NULL, 0); if (ret < 0) { @@ -1295,6 +1323,11 @@ static int vhost_user_set_vring_call(struct vhost_dev *dev, return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file); } +static int vhost_user_set_vring_err(struct vhost_dev *dev, + struct vhost_vring_file *file) +{ + return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_ERR, file); +} static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) { @@ -1428,6 +1461,43 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, return 0; } +static int vhost_user_set_status(struct vhost_dev *dev, uint8_t status) +{ + return vhost_user_set_u64(dev, VHOST_USER_SET_STATUS, status, false); +} + +static int vhost_user_get_status(struct vhost_dev *dev, uint8_t *status) +{ + uint64_t value; + int ret; + + ret = vhost_user_get_u64(dev, VHOST_USER_GET_STATUS, &value); + if (ret < 0) { + return ret; + } + *status = value; + + return 0; +} + +static int vhost_user_add_status(struct vhost_dev *dev, uint8_t status) +{ + uint8_t s; + int ret; + + ret = vhost_user_get_status(dev, &s); + if (ret < 0) { + return ret; + } + + if ((s & status) == status) { + return 0; + } + s |= status; + + return vhost_user_set_status(dev, s); +} + static int vhost_user_set_features(struct vhost_dev *dev, uint64_t features) { @@ -1436,9 +1506,26 @@ static int vhost_user_set_features(struct vhost_dev *dev, * backend is actually logging changes */ bool log_enabled = features & (0x1ULL << VHOST_F_LOG_ALL); + int ret; - 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. + */ + ret = vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, + features | dev->backend_features, log_enabled); + + if (virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_STATUS)) { + if (!ret) { + return vhost_user_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); + } + } + + return ret; } static int vhost_user_set_protocol_features(struct vhost_dev *dev, @@ -1498,12 +1585,40 @@ static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) return dev->config_ops->vhost_dev_config_notifier(dev); } +/* + * Fetch or create the notifier for a given idx. Newly created + * notifiers are added to the pointer array that tracks them. + */ +static VhostUserHostNotifier *fetch_or_create_notifier(VhostUserState *u, + int idx) +{ + VhostUserHostNotifier *n = NULL; + if (idx >= u->notifiers->len) { + g_ptr_array_set_size(u->notifiers, idx + 1); + } + + n = g_ptr_array_index(u->notifiers, idx); + if (!n) { + /* + * In case notification arrive out-of-order, + * make room for current index. + */ + g_ptr_array_remove_index(u->notifiers, idx); + n = g_new0(VhostUserHostNotifier, 1); + n->idx = idx; + g_ptr_array_insert(u->notifiers, idx, n); + trace_vhost_user_create_notifier(idx, n); + } + + return n; +} + static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, VhostUserVringArea *area, int fd) { int queue_idx = area->u64 & VHOST_USER_VRING_IDX_MASK; - size_t page_size = qemu_real_host_page_size; + size_t page_size = qemu_real_host_page_size(); struct vhost_user *u = dev->opaque; VhostUserState *user = u->user; VirtIODevice *vdev = dev->vdev; @@ -1517,9 +1632,12 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, return -EINVAL; } - n = &user->notifier[queue_idx]; - - vhost_user_host_notifier_remove(user, vdev, queue_idx); + /* + * Fetch notifier and invalidate any old data before setting up + * new mapped address. + */ + n = fetch_or_create_notifier(user, queue_idx); + vhost_user_host_notifier_remove(n, vdev); if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { return 0; @@ -1677,7 +1795,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; @@ -1826,7 +1944,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) error_setg(errp, "%s: Failed to get ufd", __func__); return -EIO; } - qemu_set_nonblock(ufd); + qemu_socket_set_nonblock(ufd); /* register ufd with userfault thread */ u->postcopy_fd.fd = ufd; @@ -1945,14 +2063,15 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, Error **errp) { - uint64_t features, protocol_features, ram_slots; + uint64_t features, ram_slots; struct vhost_user *u; + VhostUserState *vus = (VhostUserState *) opaque; int err; assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); u = g_new0(struct vhost_user, 1); - u->user = opaque; + u->user = vus; u->dev = dev; dev->opaque = u; @@ -1963,6 +2082,10 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, } if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) { + bool supports_f_config = vus->supports_config || + (dev->config_ops && dev->config_ops->vhost_dev_config_notifier); + uint64_t protocol_features; + dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES, @@ -1972,19 +2095,32 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, return -EPROTO; } - dev->protocol_features = - protocol_features & VHOST_USER_PROTOCOL_FEATURE_MASK; - - if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) { - /* Don't acknowledge CONFIG feature if device doesn't support it */ - dev->protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); - } else if (!(protocol_features & - (1ULL << VHOST_USER_PROTOCOL_F_CONFIG))) { - error_setg(errp, "Device expects VHOST_USER_PROTOCOL_F_CONFIG " - "but backend does not support it."); - return -EINVAL; + /* + * We will use all the protocol features we support - although + * we suppress F_CONFIG if we know QEMUs internal code can not support + * it. + */ + protocol_features &= VHOST_USER_PROTOCOL_FEATURE_MASK; + + if (supports_f_config) { + if (!virtio_has_feature(protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + error_setg(errp, "vhost-user device expecting " + "VHOST_USER_PROTOCOL_F_CONFIG but the vhost-user backend does " + "not support it."); + return -EPROTO; + } + } else { + if (virtio_has_feature(protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + warn_reportf_err(*errp, "vhost-user backend supports " + "VHOST_USER_PROTOCOL_F_CONFIG but QEMU does not."); + protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); + } } + /* final set of protocol features */ + dev->protocol_features = protocol_features; err = vhost_user_set_protocol_features(dev, dev->protocol_features); if (err < 0) { error_setg_errno(errp, EPROTO, "vhost_backend_init failed"); @@ -2402,11 +2538,7 @@ vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) static bool vhost_user_mem_section_filter(struct vhost_dev *dev, MemoryRegionSection *section) { - bool result; - - result = memory_region_get_fd(section->mr) >= 0; - - return result; + return memory_region_get_fd(section->mr) >= 0; } static int vhost_user_get_inflight_fd(struct vhost_dev *dev, @@ -2502,6 +2634,20 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev, return vhost_user_write(dev, &msg, &inflight->fd, 1); } +static void vhost_user_state_destroy(gpointer data) +{ + VhostUserHostNotifier *n = (VhostUserHostNotifier *) data; + if (n) { + vhost_user_host_notifier_remove(n, NULL); + object_unparent(OBJECT(&n->mr)); + /* + * We can't free until vhost_user_host_notifier_remove has + * done it's thing so schedule the free with RCU. + */ + g_free_rcu(n, rcu); + } +} + bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) { if (user->chr) { @@ -2510,27 +2656,113 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) } user->chr = chr; user->memory_slots = 0; + user->notifiers = g_ptr_array_new_full(VIRTIO_QUEUE_MAX / 4, + &vhost_user_state_destroy); return true; } void vhost_user_cleanup(VhostUserState *user) { - int i; - VhostUserHostNotifier *n; - if (!user->chr) { return; } memory_region_transaction_begin(); - for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - n = &user->notifier[i]; - vhost_user_host_notifier_remove(user, NULL, i); - object_unparent(OBJECT(&n->mr)); - } + user->notifiers = (GPtrArray *) g_ptr_array_free(user->notifiers, true); memory_region_transaction_commit(); user->chr = NULL; } + +typedef struct { + vu_async_close_fn cb; + DeviceState *dev; + CharBackend *cd; + struct vhost_dev *vhost; +} VhostAsyncCallback; + +static void vhost_user_async_close_bh(void *opaque) +{ + VhostAsyncCallback *data = opaque; + struct vhost_dev *vhost = data->vhost; + + /* + * If the vhost_dev has been cleared in the meantime there is + * nothing left to do as some other path has completed the + * cleanup. + */ + if (vhost->vdev) { + data->cb(data->dev); + } + + g_free(data); +} + +/* + * We only schedule the work if the machine is running. If suspended + * we want to keep all the in-flight data as is for migration + * purposes. + */ +void vhost_user_async_close(DeviceState *d, + CharBackend *chardev, struct vhost_dev *vhost, + vu_async_close_fn cb) +{ + if (!runstate_check(RUN_STATE_SHUTDOWN)) { + /* + * A close event may happen during a read/write, but vhost + * code assumes the vhost_dev remains setup, so delay the + * stop & clear. + */ + AioContext *ctx = qemu_get_current_aio_context(); + VhostAsyncCallback *data = g_new0(VhostAsyncCallback, 1); + + /* Save data for the callback */ + data->cb = cb; + data->dev = d; + data->cd = chardev; + data->vhost = vhost; + + /* Disable any further notifications on the chardev */ + qemu_chr_fe_set_handlers(chardev, + NULL, NULL, NULL, NULL, NULL, NULL, + false); + + aio_bh_schedule_oneshot(ctx, vhost_user_async_close_bh, data); + + /* + * Move vhost device to the stopped state. The vhost-user device + * will be clean up and disconnected in BH. This can be useful in + * 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). + * + * Note if the vhost device is fully cleared by the time we + * execute the bottom half we won't continue with the cleanup. + */ + vhost->started = false; + } +} + +static int vhost_user_dev_start(struct vhost_dev *dev, bool started) +{ + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_STATUS)) { + return 0; + } + + /* Set device status only for last queue pair */ + if (dev->vq_index + dev->nvqs != dev->vq_index_end) { + return 0; + } + + if (started) { + return vhost_user_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER | + VIRTIO_CONFIG_S_DRIVER_OK); + } else { + return vhost_user_set_status(dev, 0); + } +} + const VhostOps user_ops = { .backend_type = VHOST_BACKEND_TYPE_USER, .vhost_backend_init = vhost_user_backend_init, @@ -2545,6 +2777,7 @@ const VhostOps user_ops = { .vhost_get_vring_base = vhost_user_get_vring_base, .vhost_set_vring_kick = vhost_user_set_vring_kick, .vhost_set_vring_call = vhost_user_set_vring_call, + .vhost_set_vring_err = vhost_user_set_vring_err, .vhost_set_features = vhost_user_set_features, .vhost_get_features = vhost_user_get_features, .vhost_set_owner = vhost_user_set_owner, @@ -2564,4 +2797,5 @@ const VhostOps user_ops = { .vhost_backend_mem_section_filter = vhost_user_mem_section_filter, .vhost_get_inflight_fd = vhost_user_get_inflight_fd, .vhost_set_inflight_fd = vhost_user_set_inflight_fd, + .vhost_dev_start = vhost_user_dev_start, }; diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 8adf7c0b92d9..542e003101b5 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -20,10 +20,11 @@ #include "hw/virtio/vhost-shadow-virtqueue.h" #include "hw/virtio/vhost-vdpa.h" #include "exec/address-spaces.h" +#include "migration/blocker.h" +#include "qemu/cutils.h" #include "qemu/main-loop.h" #include "cpu.h" #include "trace.h" -#include "qemu-common.h" #include "qapi/error.h" /* @@ -71,22 +72,28 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, return false; } -static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, - void *vaddr, bool readonly) +/* + * The caller must set asid = 0 if the device does not support asid. + * This is not an ABI break since it is set to 0 by the initializer anyway. + */ +int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, + hwaddr size, void *vaddr, bool readonly) { struct vhost_msg_v2 msg = {}; int fd = v->device_fd; int ret = 0; msg.type = v->msg_type; + msg.asid = asid; msg.iotlb.iova = iova; msg.iotlb.size = size; msg.iotlb.uaddr = (uint64_t)(uintptr_t)vaddr; msg.iotlb.perm = readonly ? VHOST_ACCESS_RO : VHOST_ACCESS_RW; msg.iotlb.type = VHOST_IOTLB_UPDATE; - trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.iotlb.iova, msg.iotlb.size, - msg.iotlb.uaddr, msg.iotlb.perm, msg.iotlb.type); + trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.asid, msg.iotlb.iova, + msg.iotlb.size, msg.iotlb.uaddr, msg.iotlb.perm, + msg.iotlb.type); if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { error_report("failed to write, fd=%d, errno=%d (%s)", @@ -97,19 +104,24 @@ static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, return ret; } -static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, - hwaddr size) +/* + * The caller must set asid = 0 if the device does not support asid. + * This is not an ABI break since it is set to 0 by the initializer anyway. + */ +int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, + hwaddr size) { struct vhost_msg_v2 msg = {}; int fd = v->device_fd; int ret = 0; msg.type = v->msg_type; + msg.asid = asid; msg.iotlb.iova = iova; msg.iotlb.size = size; msg.iotlb.type = VHOST_IOTLB_INVALIDATE; - trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.iotlb.iova, + trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.asid, msg.iotlb.iova, msg.iotlb.size, msg.iotlb.type); if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { @@ -129,6 +141,7 @@ static void vhost_vdpa_listener_begin_batch(struct vhost_vdpa *v) .iotlb.type = VHOST_IOTLB_BATCH_BEGIN, }; + trace_vhost_vdpa_listener_begin_batch(v, fd, msg.type, msg.iotlb.type); if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { error_report("failed to write, fd=%d, errno=%d (%s)", fd, errno, strerror(errno)); @@ -163,6 +176,7 @@ static void vhost_vdpa_listener_commit(MemoryListener *listener) msg.type = v->msg_type; msg.iotlb.type = VHOST_IOTLB_BATCH_END; + trace_vhost_vdpa_listener_commit(v, fd, msg.type, msg.iotlb.type); if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { error_report("failed to write, fd=%d, errno=%d (%s)", fd, errno, strerror(errno)); @@ -174,6 +188,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; @@ -209,14 +224,14 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, vaddr, section->readonly); 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), - }; + if (v->shadow_data) { + 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; @@ -226,15 +241,20 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, } vhost_vdpa_iotlb_batch_begin_once(v); - ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), - vaddr, section->readonly); + ret = vhost_vdpa_dma_map(v, VHOST_VDPA_GUEST_PA_ASID, iova, + int128_get64(llsize), vaddr, section->readonly); if (ret) { error_report("vhost vdpa map fail!"); - goto fail; + goto fail_map; } return; +fail_map: + if (v->shadow_data) { + vhost_iova_tree_remove(v->iova_tree, mem_region); + } + fail: /* * On the initfn path, store the first error in the container so we @@ -276,7 +296,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, llsize = int128_sub(llend, int128_make64(iova)); - if (v->shadow_vqs_enabled) { + if (v->shadow_data) { const DMAMap *result; const void *vaddr = memory_region_get_ram_ptr(section->mr) + section->offset_within_region + @@ -287,11 +307,16 @@ 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, &mem_region); + 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)); + ret = vhost_vdpa_dma_unmap(v, VHOST_VDPA_GUEST_PA_ASID, iova, + int128_get64(llsize)); if (ret) { error_report("vhost_vdpa dma unmap error!"); } @@ -353,24 +378,25 @@ static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) return 0; } -static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) +int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range) { - int ret = vhost_vdpa_call(v->dev, VHOST_VDPA_GET_IOVA_RANGE, - &v->iova_range); - if (ret != 0) { - v->iova_range.first = 0; - v->iova_range.last = UINT64_MAX; - } + int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); - trace_vhost_vdpa_get_iova_range(v->dev, v->iova_range.first, - v->iova_range.last); + return ret < 0 ? -errno : 0; } -static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) +/* + * The use of this function is for requests that only need to be + * applied once. Typically such request occurs at the beginning + * of operation, and before setting up queues. It should not be + * used for request that performs operation until all queues are + * set, which would need to check dev->vq_index_end instead. + */ +static bool vhost_vdpa_first_dev(struct vhost_dev *dev) { struct vhost_vdpa *v = dev->opaque; - return v->index != 0; + return v->index == 0; } static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, @@ -383,43 +409,19 @@ static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, return ret; } -static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, - Error **errp) +static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v) { g_autoptr(GPtrArray) shadow_vqs = NULL; - uint64_t dev_features, svq_features; - int r; - bool ok; - - if (!v->shadow_vqs_enabled) { - return 0; - } - - r = vhost_vdpa_get_dev_features(hdev, &dev_features); - if (r != 0) { - error_setg_errno(errp, -r, "Can't get vdpa device features"); - return r; - } - - svq_features = dev_features; - ok = vhost_svq_valid_features(svq_features, errp); - if (unlikely(!ok)) { - return -1; - } shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); for (unsigned n = 0; n < hdev->nvqs; ++n) { - g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree); + VhostShadowVirtqueue *svq; - if (unlikely(!svq)) { - error_setg(errp, "Cannot create svq %u", n); - return -1; - } - g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq)); + svq = vhost_svq_new(v->shadow_vq_ops, v->shadow_vq_ops_opaque); + g_ptr_array_add(shadow_vqs, svq); } v->shadow_vqs = g_steal_pointer(&shadow_vqs); - return 0; } static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) @@ -444,14 +446,9 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) dev->opaque = opaque ; v->listener = vhost_vdpa_memory_listener; v->msg_type = VHOST_IOTLB_MSG_V2; - ret = vhost_vdpa_init_svq(dev, v, errp); - if (ret) { - goto err; - } + vhost_vdpa_init_svq(dev, v); - vhost_vdpa_get_iova_range(v); - - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -459,16 +456,12 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) VIRTIO_CONFIG_S_DRIVER); return 0; - -err: - ram_block_discard_disable(false); - return ret; } static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, int queue_index) { - size_t page_size = qemu_real_host_page_size; + size_t page_size = qemu_real_host_page_size(); struct vhost_vdpa *v = dev->opaque; VirtIODevice *vdev = dev->vdev; VhostVDPAHostNotifier *n; @@ -485,7 +478,7 @@ static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index) { - size_t page_size = qemu_real_host_page_size; + size_t page_size = qemu_real_host_page_size(); struct vhost_vdpa *v = dev->opaque; VirtIODevice *vdev = dev->vdev; VhostVDPAHostNotifier *n; @@ -526,9 +519,18 @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) { int i; + /* + * Pack all the changes to the memory regions in a single + * transaction to avoid a few updating of the address space + * topology. + */ + memory_region_transaction_begin(); + for (i = dev->vq_index; i < dev->vq_index + n; i++) { vhost_vdpa_host_notifier_uninit(dev, i); } + + memory_region_transaction_commit(); } static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) @@ -541,17 +543,21 @@ static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) return; } + /* + * Pack all the changes to the memory regions in a single + * transaction to avoid a few updating of the address space + * topology. + */ + memory_region_transaction_begin(); + for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) { if (vhost_vdpa_host_notifier_init(dev, i)) { - goto err; + vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); + break; } } - return; - -err: - vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); - return; + memory_region_transaction_commit(); } static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) @@ -559,10 +565,6 @@ static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) struct vhost_vdpa *v = dev->opaque; size_t idx; - if (!v->shadow_vqs) { - return; - } - for (idx = 0; idx < v->shadow_vqs->len; ++idx) { vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx)); } @@ -594,7 +596,7 @@ static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, struct vhost_memory *mem) { - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -623,7 +625,7 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, struct vhost_vdpa *v = dev->opaque; int ret; - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -656,7 +658,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) { uint64_t features; uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | - 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH; + 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH | + 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID; int r; if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { @@ -665,7 +668,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) features &= f; - if (vhost_vdpa_one_time_request(dev)) { + if (vhost_vdpa_first_dev(dev)) { r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); if (r) { return -EFAULT; @@ -733,6 +736,13 @@ static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) return 0; } +static int vhost_vdpa_set_config_call(struct vhost_dev *dev, + int fd) +{ + trace_vhost_vdpa_set_config_call(dev, fd); + return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); +} + static void vhost_vdpa_dump_config(struct vhost_dev *dev, const uint8_t *config, uint32_t config_len) { @@ -843,11 +853,23 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, const EventNotifier *event_notifier = &svq->hdev_kick; int r; + r = event_notifier_init(&svq->hdev_kick, 0); + if (r != 0) { + error_setg_errno(errp, -r, "Couldn't create kick event notifier"); + goto err_init_hdev_kick; + } + + r = event_notifier_init(&svq->hdev_call, 0); + if (r != 0) { + error_setg_errno(errp, -r, "Couldn't create call event notifier"); + goto err_init_hdev_call; + } + file.fd = event_notifier_get_fd(event_notifier); r = vhost_vdpa_set_vring_dev_kick(dev, &file); if (unlikely(r != 0)) { error_setg_errno(errp, -r, "Can't set device kick fd"); - return r; + goto err_init_set_dev_fd; } event_notifier = &svq->hdev_call; @@ -855,49 +877,59 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, r = vhost_vdpa_set_vring_dev_call(dev, &file); if (unlikely(r != 0)) { error_setg_errno(errp, -r, "Can't set device call fd"); + goto err_init_set_dev_fd; } + return 0; + +err_init_set_dev_fd: + event_notifier_set_handler(&svq->hdev_call, NULL); + +err_init_hdev_call: + event_notifier_cleanup(&svq->hdev_kick); + +err_init_hdev_kick: return r; } /** * 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; + size = ROUND_UP(result->size, qemu_real_host_page_size()); + r = vhost_vdpa_dma_unmap(v, v->address_space_id, result->iova, size); + 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); } /** @@ -918,12 +950,13 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, return false; } - r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1, + r = vhost_vdpa_dma_map(v, v->address_space_id, needle->iova, + needle->size + 1, (void *)(uintptr_t)needle->translated_addr, 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; @@ -942,6 +975,7 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, struct vhost_vring_addr *addr, Error **errp) { + ERRP_GUARD(); DMAMap device_region, driver_region; struct vhost_vring_addr svq_addr; struct vhost_vdpa *v = dev->opaque; @@ -950,7 +984,6 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, size_t avail_offset; bool ok; - ERRP_GUARD(); vhost_svq_get_vring_addr(svq, &svq_addr); driver_region = (DMAMap) { @@ -975,7 +1008,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; @@ -1008,7 +1041,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) Error *err = NULL; unsigned i; - if (!v->shadow_vqs) { + if (!v->shadow_vqs_enabled) { return true; } @@ -1016,7 +1049,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); struct vhost_vring_addr addr = { - .index = i, + .index = dev->vq_index + i, }; int r; bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); @@ -1024,7 +1057,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) goto err; } - vhost_svq_start(svq, dev->vdev, vq); + vhost_svq_start(svq, dev->vdev, vq, v->iova_tree); ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err); if (unlikely(!ok)) { goto err_map; @@ -1057,23 +1090,21 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) 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; + if (!v->shadow_vqs_enabled) { + 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); - return true; + event_notifier_cleanup(&svq->hdev_kick); + event_notifier_cleanup(&svq->hdev_call); + } } static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) @@ -1090,10 +1121,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); } @@ -1118,7 +1146,7 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, struct vhost_log *log) { struct vhost_vdpa *v = dev->opaque; - if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) { + if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { return 0; } @@ -1154,7 +1182,18 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { struct vhost_vdpa *v = dev->opaque; + VirtQueue *vq = virtio_get_queue(dev->vdev, ring->index); + /* + * vhost-vdpa devices does not support in-flight requests. Set all of them + * as available. + * + * TODO: This is ok for networking, but other kinds of devices might + * have problems with these retransmissions. + */ + while (virtqueue_rewind(vq, 1)) { + continue; + } if (v->shadow_vqs_enabled) { /* * Device vring base was set at device start. SVQ base is handled by @@ -1173,18 +1212,7 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, int ret; if (v->shadow_vqs_enabled) { - VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, - ring->index); - - /* - * Setting base as last used idx, so destination will see as available - * all the entries that the device did not use, including the in-flight - * processing ones. - * - * TODO: This is ok for networking, but other kinds of devices might - * have problems with these retransmissions. - */ - ring->num = svq->last_used_idx; + ring->num = virtio_queue_get_last_avail_idx(dev->vdev, ring->index); return 0; } @@ -1240,7 +1268,7 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev, static int vhost_vdpa_set_owner(struct vhost_dev *dev) { - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -1297,4 +1325,5 @@ const VhostOps vdpa_ops = { .vhost_get_device_id = vhost_vdpa_get_device_id, .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, .vhost_force_iommu = vhost_vdpa_force_iommu, + .vhost_set_config_call = vhost_vdpa_set_config_call, }; diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index ed706681ace8..d2b5519d5a79 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -14,12 +14,14 @@ #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" const int feature_bits[] = { VIRTIO_VSOCK_F_SEQPACKET, + VIRTIO_F_RING_RESET, VHOST_INVALID_FEATURE_BIT }; @@ -68,7 +70,7 @@ int vhost_vsock_common_start(VirtIODevice *vdev) } vvc->vhost_dev.acked_features = vdev->guest_features; - ret = vhost_dev_start(&vvc->vhost_dev, vdev); + ret = vhost_dev_start(&vvc->vhost_dev, vdev, true); if (ret < 0) { error_report("Error starting vhost: %d", -ret); goto err_guest_notifiers; @@ -103,7 +105,7 @@ void vhost_vsock_common_stop(VirtIODevice *vdev) return; } - vhost_dev_stop(&vvc->vhost_dev, vdev); + vhost_dev_stop(&vvc->vhost_dev, vdev, true); ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); if (ret < 0) { @@ -125,6 +127,15 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return; + } vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); } @@ -133,6 +144,15 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return false; + } return vhost_virtqueue_pending(&vvc->vhost_dev, idx); } @@ -199,7 +219,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; } @@ -224,12 +244,11 @@ int vhost_vsock_common_post_load(void *opaque, int version_id) return 0; } -void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name) +void vhost_vsock_common_realize(VirtIODevice *vdev) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); - virtio_init(vdev, name, VIRTIO_ID_VSOCK, - sizeof(struct virtio_vsock_config)); + virtio_init(vdev, VIRTIO_ID_VSOCK, sizeof(struct virtio_vsock_config)); /* Receive and transmit queues belong to vhost */ vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, @@ -259,6 +278,12 @@ void vhost_vsock_common_unrealize(VirtIODevice *vdev) virtio_cleanup(vdev); } +static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + return &vvc->vhost_dev; +} + static Property vhost_vsock_common_properties[] = { DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket, ON_OFF_AUTO_AUTO), @@ -274,6 +299,7 @@ static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; + vdc->get_vhost = vhost_vsock_common_get_vhost; } static const TypeInfo vhost_vsock_common_info = { diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c index 205da8d1f5e2..9f34414d3814 100644 --- a/hw/virtio/vhost-vsock-pci.c +++ b/hw/virtio/vhost-vsock-pci.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-vsock.h" #include "qemu/module.h" diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 433d42d897df..aa16d584eed3 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_should_start(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; } @@ -149,9 +145,8 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) return; } - ret = qemu_try_set_nonblock(vhostfd); - if (ret < 0) { - error_setg_errno(errp, -ret, + if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) { + error_setg_errno(errp, errno, "vhost-vsock: unable to set non-blocking mode"); return; } @@ -163,10 +158,14 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) return; } - qemu_set_nonblock(vhostfd); + if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) { + error_setg_errno(errp, errno, + "Failed to set FD nonblocking"); + return; + } } - vhost_vsock_common_realize(vdev, "vhost-vsock"); + vhost_vsock_common_realize(vdev); ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd, VHOST_BACKEND_TYPE_KERNEL, 0, errp); diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index b643f42ea4ec..eb8c4c378c69 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -20,13 +20,13 @@ #include "qemu/range.h" #include "qemu/error-report.h" #include "qemu/memfd.h" +#include "qemu/log.h" #include "standard-headers/linux/vhost_types.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "migration/qemu-file-types.h" #include "sysemu/dma.h" -#include "sysemu/tcg.h" #include "trace.h" /* enabled until disconnected backend stabilizes */ @@ -107,6 +107,24 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, } } +static bool vhost_dev_has_iommu(struct vhost_dev *dev) +{ + VirtIODevice *vdev = dev->vdev; + + /* + * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support + * incremental memory mapping API via IOTLB API. For platform that + * does not have IOMMU, there's no need to enable this feature + * which may cause unnecessary IOTLB miss/update transactions. + */ + if (vdev) { + return virtio_bus_device_iommu_enabled(vdev) && + virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); + } else { + return false; + } +} + static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, MemoryRegionSection *section, hwaddr first, @@ -138,8 +156,51 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, continue; } - vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys, - range_get_last(vq->used_phys, vq->used_size)); + if (vhost_dev_has_iommu(dev)) { + IOMMUTLBEntry iotlb; + hwaddr used_phys = vq->used_phys, used_size = vq->used_size; + hwaddr phys, s, offset; + + while (used_size) { + rcu_read_lock(); + iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as, + used_phys, + true, + MEMTXATTRS_UNSPECIFIED); + rcu_read_unlock(); + + if (!iotlb.target_as) { + qemu_log_mask(LOG_GUEST_ERROR, "translation " + "failure for used_iova %"PRIx64"\n", + used_phys); + return -EINVAL; + } + + offset = used_phys & iotlb.addr_mask; + phys = iotlb.translated_addr + offset; + + /* + * Distance from start of used ring until last byte of + * IOMMU page. + */ + s = iotlb.addr_mask - offset; + /* + * Size of used ring, or of the part of it until end + * of IOMMU page. To avoid zero result, do the adding + * outside of MIN(). + */ + s = MIN(s, used_size - 1) + 1; + + vhost_dev_sync_region(dev, section, start_addr, end_addr, phys, + range_get_last(phys, s)); + used_size -= s; + used_phys += s; + } + } else { + vhost_dev_sync_region(dev, section, start_addr, + end_addr, vq->used_phys, + range_get_last(vq->used_phys, vq->used_size)); + } } return 0; } @@ -307,20 +368,6 @@ 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) -{ - VirtIODevice *vdev = dev->vdev; - - /* - * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support - * incremental memory mapping API via IOTLB API. For platform that - * 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); -} - static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, hwaddr *plen, bool is_write) { @@ -887,6 +934,10 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) err_vq: for (; i >= 0; --i) { idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i); + addr = virtio_queue_get_desc_addr(dev->vdev, idx); + if (!addr) { + continue; + } vhost_virtqueue_set_addr(dev, dev->vqs + i, idx, dev->log_enabled); } @@ -989,7 +1040,7 @@ static inline bool vhost_needs_vring_endian(VirtIODevice *vdev) if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { return false; } -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_LITTLE; #else return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; @@ -1074,10 +1125,10 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write) return ret; } -static int vhost_virtqueue_start(struct vhost_dev *dev, - struct VirtIODevice *vdev, - struct vhost_virtqueue *vq, - unsigned idx) +int vhost_virtqueue_start(struct vhost_dev *dev, + struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, + unsigned idx) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); VirtioBusState *vbus = VIRTIO_BUS(qbus); @@ -1194,10 +1245,10 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, return r; } -static void vhost_virtqueue_stop(struct vhost_dev *dev, - struct VirtIODevice *vdev, - struct vhost_virtqueue *vq, - unsigned idx) +void vhost_virtqueue_stop(struct vhost_dev *dev, + struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, + unsigned idx) { int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx); struct vhost_vring_state state = { @@ -1275,6 +1326,19 @@ static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, return 0; } +static void vhost_virtqueue_error_notifier(EventNotifier *n) +{ + struct vhost_virtqueue *vq = container_of(n, struct vhost_virtqueue, + error_notifier); + struct vhost_dev *dev = vq->dev; + int index = vq - dev->vqs; + + if (event_notifier_test_and_clear(n) && dev->vdev) { + VHOST_OPS_DEBUG(-EINVAL, "vhost vring error in virtqueue %d", + dev->vq_index + index); + } +} + static int vhost_virtqueue_init(struct vhost_dev *dev, struct vhost_virtqueue *vq, int n) { @@ -1296,7 +1360,27 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, vq->dev = dev; + if (dev->vhost_ops->vhost_set_vring_err) { + r = event_notifier_init(&vq->error_notifier, 0); + if (r < 0) { + goto fail_call; + } + + file.fd = event_notifier_get_fd(&vq->error_notifier); + r = dev->vhost_ops->vhost_set_vring_err(dev, &file); + if (r) { + VHOST_OPS_DEBUG(r, "vhost_set_vring_err failed"); + goto fail_err; + } + + event_notifier_set_handler(&vq->error_notifier, + vhost_virtqueue_error_notifier); + } + return 0; + +fail_err: + event_notifier_cleanup(&vq->error_notifier); fail_call: event_notifier_cleanup(&vq->masked_notifier); return r; @@ -1305,6 +1389,10 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) { event_notifier_cleanup(&vq->masked_notifier); + if (vq->dev->vhost_ops->vhost_set_vring_err) { + event_notifier_set_handler(&vq->error_notifier, NULL); + event_notifier_cleanup(&vq->error_notifier); + } } int vhost_dev_init(struct vhost_dev *hdev, void *opaque, @@ -1433,6 +1521,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); } @@ -1461,7 +1551,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); - int i, r, e; + int i, r; /* We will pass the notifiers to the kernel, make sure that QEMU * doesn't interfere. @@ -1469,32 +1559,29 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) r = virtio_device_grab_ioeventfd(vdev); if (r < 0) { error_report("binding does not support host notifiers"); - goto fail; + return r; } + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + for (i = 0; i < hdev->nvqs; ++i) { r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, true); if (r < 0) { error_report("vhost VQ %d notifier binding failed: %d", i, -r); - goto fail_vq; + memory_region_transaction_commit(); + vhost_dev_disable_notifiers(hdev, vdev); + return r; } } + memory_region_transaction_commit(); + return 0; -fail_vq: - while (--i >= 0) { - e = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, - false); - if (e < 0) { - error_report("vhost VQ %d notifier cleanup error: %d", i, -r); - } - assert (e >= 0); - virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); - } - virtio_device_release_ioeventfd(vdev); -fail: - return r; } /* Stop processing guest IO notifications in vhost. @@ -1507,6 +1594,12 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); int i, r; + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + for (i = 0; i < hdev->nvqs; ++i) { r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, false); @@ -1514,6 +1607,15 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) error_report("vhost VQ %d notifier cleanup failed: %d", i, -r); } assert (r >= 0); + } + + /* + * The transaction expects the ioeventfds to be open when it + * commits. Do it now, before the cleanup loop. + */ + memory_region_transaction_commit(); + + for (i = 0; i < hdev->nvqs; ++i) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); } virtio_device_release_ioeventfd(vdev); @@ -1550,7 +1652,68 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); if (r < 0) { - VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); + error_report("vhost_set_vring_call failed %d", -r); + } +} + +bool vhost_config_pending(struct vhost_dev *hdev) +{ + assert(hdev->vhost_ops); + if ((hdev->started == false) || + (hdev->vhost_ops->vhost_set_config_call == NULL)) { + return false; + } + + EventNotifier *notifier = + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; + return event_notifier_test_and_clear(notifier); +} + +void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) +{ + int fd; + int r; + EventNotifier *notifier = + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; + EventNotifier *config_notifier = &vdev->config_notifier; + assert(hdev->vhost_ops); + + if ((hdev->started == false) || + (hdev->vhost_ops->vhost_set_config_call == NULL)) { + return; + } + if (mask) { + assert(vdev->use_guest_notifier_mask); + fd = event_notifier_get_fd(notifier); + } else { + fd = event_notifier_get_fd(config_notifier); + } + r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); + if (r < 0) { + error_report("vhost_set_config_call failed %d", -r); + } +} + +static void vhost_stop_config_intr(struct vhost_dev *dev) +{ + int fd = -1; + assert(dev->vhost_ops); + if (dev->vhost_ops->vhost_set_config_call) { + dev->vhost_ops->vhost_set_config_call(dev, fd); + } +} + +static void vhost_start_config_intr(struct vhost_dev *dev) +{ + int r; + + assert(dev->vhost_ops); + int fd = event_notifier_get_fd(&dev->vdev->config_notifier); + if (dev->vhost_ops->vhost_set_config_call) { + r = dev->vhost_ops->vhost_set_config_call(dev, fd); + if (!r) { + event_notifier_set(&dev->vdev->config_notifier); + } } } @@ -1731,14 +1894,38 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, return 0; } +static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable) +{ + if (!hdev->vhost_ops->vhost_set_vring_enable) { + return 0; + } + + /* + * For vhost-user devices, if VHOST_USER_F_PROTOCOL_FEATURES has not + * been negotiated, the rings start directly in the enabled state, and + * .vhost_set_vring_enable callback will fail since + * VHOST_USER_SET_VRING_ENABLE is not supported. + */ + if (hdev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER && + !virtio_has_feature(hdev->backend_features, + VHOST_USER_F_PROTOCOL_FEATURES)) { + return 0; + } + + return hdev->vhost_ops->vhost_set_vring_enable(hdev, enable); +} + /* Host notifiers must be enabled at this point. */ -int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) +int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) { int i, r; /* should only be called after backend is connected */ assert(hdev->vhost_ops); + trace_vhost_dev_start(hdev, vdev->name, vrings); + + vdev->vhost_started = true; hdev->started = true; hdev->vdev = vdev; @@ -1766,6 +1953,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } } + r = event_notifier_init( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); + if (r < 0) { + return r; + } + event_notifier_test_and_clear( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); + if (!vdev->use_guest_notifier_mask) { + vhost_config_mask(hdev, vdev, true); + } if (hdev->log_enabled) { uint64_t log_base; @@ -1781,10 +1978,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail_log; } } + if (vrings) { + r = vhost_dev_set_vring_enable(hdev, true); + if (r) { + goto fail_log; + } + } if (hdev->vhost_ops->vhost_dev_start) { r = hdev->vhost_ops->vhost_dev_start(hdev, true); if (r) { - goto fail_log; + goto fail_start; } } if (vhost_dev_has_iommu(hdev) && @@ -1798,7 +2001,12 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) vhost_device_iotlb_miss(hdev, vq->used_phys, true); } } + vhost_start_config_intr(hdev); return 0; +fail_start: + if (vrings) { + vhost_dev_set_vring_enable(hdev, false); + } fail_log: vhost_log_put(hdev, false); fail_vq: @@ -1811,22 +2019,30 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) fail_mem: fail_features: - + vdev->vhost_started = false; hdev->started = false; return r; } /* Host notifiers must be enabled at this point. */ -void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) +void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) { int i; /* should only be called after backend is connected */ assert(hdev->vhost_ops); + event_notifier_test_and_clear( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); + event_notifier_test_and_clear(&vdev->config_notifier); + + trace_vhost_dev_stop(hdev, vdev->name, vrings); if (hdev->vhost_ops->vhost_dev_start) { hdev->vhost_ops->vhost_dev_start(hdev, false); } + if (vrings) { + vhost_dev_set_vring_enable(hdev, false); + } for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_stop(hdev, vdev, @@ -1840,8 +2056,10 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) } memory_listener_unregister(&hdev->iommu_listener); } + vhost_stop_config_intr(hdev); vhost_log_put(hdev, true); hdev->started = false; + vdev->vhost_started = false; hdev->vdev = NULL; } diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c index e07adcd9ea78..94c14f0b98c9 100644 --- a/hw/virtio/virtio-9p-pci.c +++ b/hw/virtio/virtio-9p-pci.c @@ -15,7 +15,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/9pfs/virtio-9p.h" #include "hw/qdev-properties.h" #include "qemu/module.h" diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c index 79a3ba979a8e..ce2645ba7187 100644 --- a/hw/virtio/virtio-balloon-pci.c +++ b/hw/virtio/virtio-balloon-pci.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio-balloon.h" #include "qapi/error.h" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 163d244eb499..746f07c4d26f 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -241,36 +241,34 @@ static void balloon_stats_poll_cb(void *opaque) static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *err = NULL; VirtIOBalloon *s = VIRTIO_BALLOON(obj); + bool ok = false; int i; - if (!visit_start_struct(v, name, NULL, 0, &err)) { - goto out; + if (!visit_start_struct(v, name, NULL, 0, errp)) { + return; } - if (!visit_type_int(v, "last-update", &s->stats_last_update, &err)) { + if (!visit_type_int(v, "last-update", &s->stats_last_update, errp)) { goto out_end; } - if (!visit_start_struct(v, "stats", NULL, 0, &err)) { + if (!visit_start_struct(v, "stats", NULL, 0, errp)) { goto out_end; } for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { - if (!visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], &err)) { + if (!visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], errp)) { goto out_nested; } } - visit_check_struct(v, &err); + ok = visit_check_struct(v, errp); out_nested: visit_end_struct(v, NULL); - if (!err) { - visit_check_struct(v, &err); + if (ok) { + visit_check_struct(v, errp); } out_end: visit_end_struct(v, NULL); -out: - error_propagate(errp, err); } static void balloon_stats_get_poll_interval(Object *obj, Visitor *v, @@ -452,7 +450,6 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) VirtQueueElement *elem; VirtIOBalloonStat stat; size_t offset = 0; - qemu_timeval tv; elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { @@ -484,13 +481,7 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) s->stats[tag] = val; } s->stats_vq_offset = offset; - - if (qemu_gettimeofday(&tv) < 0) { - warn_report("%s: failed to get time of day", __func__); - goto out; - } - - s->stats_last_update = tv.tv_sec; + s->stats_last_update = g_get_real_time() / G_USEC_PER_SEC; out: if (balloon_stats_enabled(s)) { @@ -889,8 +880,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) VirtIOBalloon *s = VIRTIO_BALLOON(dev); int ret; - virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, - virtio_balloon_config_size(s)); + virtio_init(vdev, VIRTIO_ID_BALLOON, virtio_balloon_config_size(s)); ret = qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s); diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c index 9d5795810c36..9743bee965af 100644 --- a/hw/virtio/virtio-blk-pci.c +++ b/hw/virtio/virtio-blk-pci.c @@ -19,7 +19,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-blk.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qapi/error.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 0f69d1c74261..896feb37a1ca 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -78,17 +78,23 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) return; } - vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); - if (klass->get_dma_as != NULL && has_iommu) { + vdev->dma_as = &address_space_memory; + if (has_iommu) { + vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); + /* + * Present IOMMU_PLATFORM to the driver iff iommu_plattform=on and + * device operational. If the driver does not accept IOMMU_PLATFORM + * we fail the device. + */ virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM); - vdev->dma_as = klass->get_dma_as(qbus->parent); - if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) { - error_setg(errp, + if (klass->get_dma_as) { + vdev->dma_as = klass->get_dma_as(qbus->parent); + if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) { + error_setg(errp, "iommu_platform=true is not supported by the device"); - return; + return; + } } - } else { - vdev->dma_as = &address_space_memory; } } @@ -98,6 +104,7 @@ void virtio_bus_reset(VirtioBusState *bus) VirtIODevice *vdev = virtio_bus_get_device(bus); DPRINTF("%s: reset device.\n", BUS(bus)->name); + virtio_bus_stop_ioeventfd(bus); if (vdev != NULL) { virtio_reset(vdev); } diff --git a/hw/virtio/virtio-config-io.c b/hw/virtio/virtio-config-io.c new file mode 100644 index 000000000000..ad78e0b9bc51 --- /dev/null +++ b/hw/virtio/virtio-config-io.c @@ -0,0 +1,204 @@ +/* + * Virtio Support + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/virtio/virtio.h" +#include "cpu.h" + +uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint8_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = ldub_p(vdev->config + addr); + return val; +} + +uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint16_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = lduw_p(vdev->config + addr); + return val; +} + +uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint32_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = ldl_p(vdev->config + addr); + return val; +} + +void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint8_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stb_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint16_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stw_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint32_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stl_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint8_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = ldub_p(vdev->config + addr); + return val; +} + +uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint16_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = lduw_le_p(vdev->config + addr); + return val; +} + +uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint32_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = ldl_le_p(vdev->config + addr); + return val; +} + +void virtio_config_modern_writeb(VirtIODevice *vdev, + uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint8_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stb_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +void virtio_config_modern_writew(VirtIODevice *vdev, + uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint16_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stw_le_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +void virtio_config_modern_writel(VirtIODevice *vdev, + uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint32_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stl_le_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index dcd80b904d61..516425e26a60 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -27,6 +27,39 @@ #define VIRTIO_CRYPTO_VM_VERSION 1 +typedef struct VirtIOCryptoSessionReq { + VirtIODevice *vdev; + VirtQueue *vq; + VirtQueueElement *elem; + CryptoDevBackendSessionInfo info; + CryptoDevCompletionFunc cb; +} VirtIOCryptoSessionReq; + +static void virtio_crypto_free_create_session_req(VirtIOCryptoSessionReq *sreq) +{ + switch (sreq->info.op_code) { + case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + g_free(sreq->info.u.sym_sess_info.cipher_key); + g_free(sreq->info.u.sym_sess_info.auth_key); + break; + + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: + g_free(sreq->info.u.asym_sess_info.key); + break; + + case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: + case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: + case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: + case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: + case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION: + break; + + default: + error_report("Unknown opcode: %u", sreq->info.op_code); + } + g_free(sreq); +} + /* * Transfer virtqueue index to crypto queue index. * The control virtqueue is after the data virtqueues @@ -75,140 +108,232 @@ virtio_crypto_cipher_session_helper(VirtIODevice *vdev, return 0; } -static int64_t +static int virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, struct virtio_crypto_sym_create_session_req *sess_req, uint32_t queue_id, uint32_t opcode, - struct iovec *iov, unsigned int out_num) + struct iovec *iov, unsigned int out_num, + VirtIOCryptoSessionReq *sreq) { VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); - CryptoDevBackendSymSessionInfo info; - int64_t session_id; + CryptoDevBackendSymSessionInfo *sym_info = &sreq->info.u.sym_sess_info; int queue_index; uint32_t op_type; - Error *local_err = NULL; int ret; - memset(&info, 0, sizeof(info)); op_type = ldl_le_p(&sess_req->op_type); - info.op_type = op_type; - info.op_code = opcode; + sreq->info.op_code = opcode; + + sym_info = &sreq->info.u.sym_sess_info; + sym_info->op_type = op_type; if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { - ret = virtio_crypto_cipher_session_helper(vdev, &info, + ret = virtio_crypto_cipher_session_helper(vdev, sym_info, &sess_req->u.cipher.para, &iov, &out_num); if (ret < 0) { - goto err; + return ret; } } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { size_t s; /* cipher part */ - ret = virtio_crypto_cipher_session_helper(vdev, &info, + ret = virtio_crypto_cipher_session_helper(vdev, sym_info, &sess_req->u.chain.para.cipher_param, &iov, &out_num); if (ret < 0) { - goto err; + return ret; } /* hash part */ - info.alg_chain_order = ldl_le_p( + sym_info->alg_chain_order = ldl_le_p( &sess_req->u.chain.para.alg_chain_order); - info.add_len = ldl_le_p(&sess_req->u.chain.para.aad_len); - info.hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode); - if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { - info.hash_alg = ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo); - info.auth_key_len = ldl_le_p( + sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len); + sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode); + if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { + sym_info->hash_alg = + ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo); + sym_info->auth_key_len = ldl_le_p( &sess_req->u.chain.para.u.mac_param.auth_key_len); - info.hash_result_len = ldl_le_p( + sym_info->hash_result_len = ldl_le_p( &sess_req->u.chain.para.u.mac_param.hash_result_len); - if (info.auth_key_len > vcrypto->conf.max_auth_key_len) { + if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) { error_report("virtio-crypto length of auth key is too big: %u", - info.auth_key_len); - ret = -VIRTIO_CRYPTO_ERR; - goto err; + sym_info->auth_key_len); + return -VIRTIO_CRYPTO_ERR; } /* get auth key */ - if (info.auth_key_len > 0) { - DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len); - info.auth_key = g_malloc(info.auth_key_len); - s = iov_to_buf(iov, out_num, 0, info.auth_key, - info.auth_key_len); - if (unlikely(s != info.auth_key_len)) { + if (sym_info->auth_key_len > 0) { + sym_info->auth_key = g_malloc(sym_info->auth_key_len); + s = iov_to_buf(iov, out_num, 0, sym_info->auth_key, + sym_info->auth_key_len); + if (unlikely(s != sym_info->auth_key_len)) { virtio_error(vdev, "virtio-crypto authenticated key incorrect"); - ret = -EFAULT; - goto err; + return -EFAULT; } - iov_discard_front(&iov, &out_num, info.auth_key_len); + iov_discard_front(&iov, &out_num, sym_info->auth_key_len); } - } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { - info.hash_alg = ldl_le_p( + } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { + sym_info->hash_alg = ldl_le_p( &sess_req->u.chain.para.u.hash_param.algo); - info.hash_result_len = ldl_le_p( + sym_info->hash_result_len = ldl_le_p( &sess_req->u.chain.para.u.hash_param.hash_result_len); } else { /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */ error_report("unsupported hash mode"); - ret = -VIRTIO_CRYPTO_NOTSUPP; - goto err; + return -VIRTIO_CRYPTO_NOTSUPP; } } else { /* VIRTIO_CRYPTO_SYM_OP_NONE */ error_report("unsupported cipher op_type: VIRTIO_CRYPTO_SYM_OP_NONE"); - ret = -VIRTIO_CRYPTO_NOTSUPP; - goto err; + return -VIRTIO_CRYPTO_NOTSUPP; } queue_index = virtio_crypto_vq2q(queue_id); - session_id = cryptodev_backend_sym_create_session( - vcrypto->cryptodev, - &info, queue_index, &local_err); - if (session_id >= 0) { - DPRINTF("create session_id=%" PRIu64 " successfully\n", - session_id); - - ret = session_id; - } else { - if (local_err) { - error_report_err(local_err); + return cryptodev_backend_create_session(vcrypto->cryptodev, &sreq->info, + queue_index, sreq->cb, sreq); +} + +static int +virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto, + struct virtio_crypto_akcipher_create_session_req *sess_req, + uint32_t queue_id, uint32_t opcode, + struct iovec *iov, unsigned int out_num, + VirtIOCryptoSessionReq *sreq) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendAsymSessionInfo *asym_info = &sreq->info.u.asym_sess_info; + int queue_index; + uint32_t algo, keytype, keylen; + + algo = ldl_le_p(&sess_req->para.algo); + keytype = ldl_le_p(&sess_req->para.keytype); + keylen = ldl_le_p(&sess_req->para.keylen); + + if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC) + && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) { + error_report("unsupported asym keytype: %d", keytype); + return -VIRTIO_CRYPTO_NOTSUPP; + } + + if (keylen) { + asym_info->key = g_malloc(keylen); + if (iov_to_buf(iov, out_num, 0, asym_info->key, keylen) != keylen) { + virtio_error(vdev, "virtio-crypto asym key incorrect"); + return -EFAULT; } - ret = -VIRTIO_CRYPTO_ERR; + iov_discard_front(&iov, &out_num, keylen); } -err: - g_free(info.cipher_key); - g_free(info.auth_key); - return ret; + sreq->info.op_code = opcode; + asym_info = &sreq->info.u.asym_sess_info; + asym_info->algo = algo; + asym_info->keytype = keytype; + asym_info->keylen = keylen; + switch (asym_info->algo) { + case VIRTIO_CRYPTO_AKCIPHER_RSA: + asym_info->u.rsa.padding_algo = + ldl_le_p(&sess_req->para.u.rsa.padding_algo); + asym_info->u.rsa.hash_algo = + ldl_le_p(&sess_req->para.u.rsa.hash_algo); + break; + + /* TODO DSA&ECDSA handling */ + + default: + return -VIRTIO_CRYPTO_ERR; + } + + queue_index = virtio_crypto_vq2q(queue_id); + return cryptodev_backend_create_session(vcrypto->cryptodev, &sreq->info, + queue_index, sreq->cb, sreq); } -static uint8_t +static int virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto, struct virtio_crypto_destroy_session_req *close_sess_req, - uint32_t queue_id) + uint32_t queue_id, + VirtIOCryptoSessionReq *sreq) { - int ret; uint64_t session_id; - uint32_t status; - Error *local_err = NULL; session_id = ldq_le_p(&close_sess_req->session_id); DPRINTF("close session, id=%" PRIu64 "\n", session_id); - ret = cryptodev_backend_sym_close_session( - vcrypto->cryptodev, session_id, queue_id, &local_err); - if (ret == 0) { - status = VIRTIO_CRYPTO_OK; + return cryptodev_backend_close_session( + vcrypto->cryptodev, session_id, queue_id, sreq->cb, sreq); +} + +static void virtio_crypto_create_session_completion(void *opaque, int ret) +{ + VirtIOCryptoSessionReq *sreq = (VirtIOCryptoSessionReq *)opaque; + VirtQueue *vq = sreq->vq; + VirtQueueElement *elem = sreq->elem; + VirtIODevice *vdev = sreq->vdev; + struct virtio_crypto_session_input input; + struct iovec *in_iov = elem->in_sg; + unsigned in_num = elem->in_num; + size_t s; + + memset(&input, 0, sizeof(input)); + /* Serious errors, need to reset virtio crypto device */ + if (ret == -EFAULT) { + virtqueue_detach_element(vq, elem, 0); + goto out; + } else if (ret == -VIRTIO_CRYPTO_NOTSUPP) { + stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP); + } else if (ret == -VIRTIO_CRYPTO_KEY_REJECTED) { + stl_le_p(&input.status, VIRTIO_CRYPTO_KEY_REJECTED); + } else if (ret != VIRTIO_CRYPTO_OK) { + stl_le_p(&input.status, VIRTIO_CRYPTO_ERR); } else { - if (local_err) { - error_report_err(local_err); - } else { - error_report("destroy session failed"); - } + /* Set the session id */ + stq_le_p(&input.session_id, sreq->info.session_id); + stl_le_p(&input.status, VIRTIO_CRYPTO_OK); + } + + s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input)); + if (unlikely(s != sizeof(input))) { + virtio_error(vdev, "virtio-crypto input incorrect"); + virtqueue_detach_element(vq, elem, 0); + goto out; + } + virtqueue_push(vq, elem, sizeof(input)); + virtio_notify(vdev, vq); + +out: + g_free(elem); + virtio_crypto_free_create_session_req(sreq); +} + +static void virtio_crypto_destroy_session_completion(void *opaque, int ret) +{ + VirtIOCryptoSessionReq *sreq = (VirtIOCryptoSessionReq *)opaque; + VirtQueue *vq = sreq->vq; + VirtQueueElement *elem = sreq->elem; + VirtIODevice *vdev = sreq->vdev; + struct iovec *in_iov = elem->in_sg; + unsigned in_num = elem->in_num; + uint8_t status; + size_t s; + + if (ret < 0) { status = VIRTIO_CRYPTO_ERR; + } else { + status = VIRTIO_CRYPTO_OK; + } + s = iov_from_buf(in_iov, in_num, 0, &status, sizeof(status)); + if (unlikely(s != sizeof(status))) { + virtio_error(vdev, "virtio-crypto status incorrect"); + virtqueue_detach_element(vq, elem, 0); + goto out; } + virtqueue_push(vq, elem, sizeof(status)); + virtio_notify(vdev, vq); - return status; +out: + g_free(elem); + g_free(sreq); } static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) @@ -216,16 +341,16 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); struct virtio_crypto_op_ctrl_req ctrl; VirtQueueElement *elem; - struct iovec *in_iov; - struct iovec *out_iov; - unsigned in_num; + VirtIOCryptoSessionReq *sreq; unsigned out_num; + unsigned in_num; uint32_t queue_id; uint32_t opcode; struct virtio_crypto_session_input input; - int64_t session_id; - uint8_t status; size_t s; + int ret; + struct iovec *out_iov; + struct iovec *in_iov; for (;;) { g_autofree struct iovec *out_iov_copy = NULL; @@ -242,7 +367,7 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } out_num = elem->out_num; - out_iov_copy = g_memdup(elem->out_sg, sizeof(out_iov[0]) * out_num); + out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); out_iov = out_iov_copy; in_num = elem->in_num; @@ -260,72 +385,71 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) opcode = ldl_le_p(&ctrl.header.opcode); queue_id = ldl_le_p(&ctrl.header.queue_id); + sreq = g_new0(VirtIOCryptoSessionReq, 1); + sreq->vdev = vdev; + sreq->vq = vq; + sreq->elem = elem; + switch (opcode) { case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: - memset(&input, 0, sizeof(input)); - session_id = virtio_crypto_create_sym_session(vcrypto, - &ctrl.u.sym_create_session, - queue_id, opcode, - out_iov, out_num); - /* Serious errors, need to reset virtio crypto device */ - if (session_id == -EFAULT) { - virtqueue_detach_element(vq, elem, 0); - break; - } else if (session_id == -VIRTIO_CRYPTO_NOTSUPP) { - stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP); - } else if (session_id == -VIRTIO_CRYPTO_ERR) { - stl_le_p(&input.status, VIRTIO_CRYPTO_ERR); - } else { - /* Set the session id */ - stq_le_p(&input.session_id, session_id); - stl_le_p(&input.status, VIRTIO_CRYPTO_OK); + sreq->cb = virtio_crypto_create_session_completion; + ret = virtio_crypto_create_sym_session(vcrypto, + &ctrl.u.sym_create_session, + queue_id, opcode, + out_iov, out_num, + sreq); + if (ret < 0) { + virtio_crypto_create_session_completion(sreq, ret); } + break; - s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input)); - if (unlikely(s != sizeof(input))) { - virtio_error(vdev, "virtio-crypto input incorrect"); - virtqueue_detach_element(vq, elem, 0); - break; + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: + sreq->cb = virtio_crypto_create_session_completion; + ret = virtio_crypto_create_asym_session(vcrypto, + &ctrl.u.akcipher_create_session, + queue_id, opcode, + out_iov, out_num, + sreq); + if (ret < 0) { + virtio_crypto_create_session_completion(sreq, ret); } - virtqueue_push(vq, elem, sizeof(input)); - virtio_notify(vdev, vq); break; + case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: - status = virtio_crypto_handle_close_session(vcrypto, - &ctrl.u.destroy_session, queue_id); - /* The status only occupy one byte, we can directly use it */ - s = iov_from_buf(in_iov, in_num, 0, &status, sizeof(status)); - if (unlikely(s != sizeof(status))) { - virtio_error(vdev, "virtio-crypto status incorrect"); - virtqueue_detach_element(vq, elem, 0); - break; + case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION: + sreq->cb = virtio_crypto_destroy_session_completion; + ret = virtio_crypto_handle_close_session(vcrypto, + &ctrl.u.destroy_session, queue_id, + sreq); + if (ret < 0) { + virtio_crypto_destroy_session_completion(sreq, ret); } - virtqueue_push(vq, elem, sizeof(status)); - virtio_notify(vdev, vq); break; + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: case VIRTIO_CRYPTO_MAC_CREATE_SESSION: case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: default: - error_report("virtio-crypto unsupported ctrl opcode: %d", opcode); memset(&input, 0, sizeof(input)); + error_report("virtio-crypto unsupported ctrl opcode: %d", opcode); stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP); s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input)); if (unlikely(s != sizeof(input))) { virtio_error(vdev, "virtio-crypto input incorrect"); virtqueue_detach_element(vq, elem, 0); - break; + } else { + virtqueue_push(vq, elem, sizeof(input)); + virtio_notify(vdev, vq); } - virtqueue_push(vq, elem, sizeof(input)); - virtio_notify(vdev, vq); + g_free(sreq); + g_free(elem); break; } /* end switch case */ - g_free(elem); } /* end for loop */ } @@ -339,28 +463,40 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq, req->in_num = 0; req->in_len = 0; req->flags = CRYPTODEV_BACKEND_ALG__MAX; - req->u.sym_op_info = NULL; + memset(&req->op_info, 0x00, sizeof(req->op_info)); } static void virtio_crypto_free_request(VirtIOCryptoReq *req) { - if (req) { - if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { - size_t max_len; - CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info; - - max_len = op_info->iv_len + - op_info->aad_len + - op_info->src_len + - op_info->dst_len + - op_info->digest_result_len; - - /* Zeroize and free request data structure */ - memset(op_info, 0, sizeof(*op_info) + max_len); + if (!req) { + return; + } + + if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { + size_t max_len; + CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info; + + max_len = op_info->iv_len + + op_info->aad_len + + op_info->src_len + + op_info->dst_len + + op_info->digest_result_len; + + /* Zeroize and free request data structure */ + memset(op_info, 0, sizeof(*op_info) + max_len); + g_free(op_info); + } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) { + CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info; + if (op_info) { + g_free(op_info->src); + g_free(op_info->dst); + memset(op_info, 0, sizeof(*op_info)); g_free(op_info); } - g_free(req); } + + g_free(req->in_iov); + g_free(req); } static void @@ -370,6 +506,7 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev, CryptoDevBackendSymOpInfo *sym_op_info) { size_t s, len; + struct iovec *in_iov = req->in_iov; if (status != VIRTIO_CRYPTO_OK) { return; @@ -377,18 +514,18 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev, len = sym_op_info->src_len; /* Save the cipher result */ - s = iov_from_buf(req->in_iov, req->in_num, 0, sym_op_info->dst, len); + s = iov_from_buf(in_iov, req->in_num, 0, sym_op_info->dst, len); if (s != len) { virtio_error(vdev, "virtio-crypto dest data incorrect"); return; } - iov_discard_front(&req->in_iov, &req->in_num, len); + iov_discard_front(&in_iov, &req->in_num, len); if (sym_op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { /* Save the digest result */ - s = iov_from_buf(req->in_iov, req->in_num, 0, + s = iov_from_buf(in_iov, req->in_num, 0, sym_op_info->digest_result, sym_op_info->digest_result_len); if (s != sym_op_info->digest_result_len) { @@ -397,18 +534,53 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev, } } -static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status) +static void +virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev, + VirtIOCryptoReq *req, int32_t status, + CryptoDevBackendAsymOpInfo *asym_op_info) { + size_t s, len; + struct iovec *in_iov = req->in_iov; + + if (status != VIRTIO_CRYPTO_OK) { + return; + } + + len = asym_op_info->dst_len; + if (!len) { + return; + } + + s = iov_from_buf(in_iov, req->in_num, 0, asym_op_info->dst, len); + if (s != len) { + virtio_error(vdev, "virtio-crypto asym dest data incorrect"); + return; + } + + iov_discard_front(&in_iov, &req->in_num, len); + + /* For akcipher, dst_len may be changed after operation */ + req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len; +} + +static void virtio_crypto_req_complete(void *opaque, int ret) +{ + VirtIOCryptoReq *req = (VirtIOCryptoReq *)opaque; VirtIOCrypto *vcrypto = req->vcrypto; VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + uint8_t status = -ret; if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { virtio_crypto_sym_input_data_helper(vdev, req, status, - req->u.sym_op_info); + req->op_info.u.sym_op_info); + } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) { + virtio_crypto_akcipher_input_data_helper(vdev, req, status, + req->op_info.u.asym_op_info); } stb_p(&req->in->status, status); virtqueue_push(req->vq, &req->elem, req->in_len); virtio_notify(vdev, req->vq); + virtio_crypto_free_request(req); } static VirtIOCryptoReq * @@ -543,39 +715,98 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, static int virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto, struct virtio_crypto_sym_data_req *req, - CryptoDevBackendSymOpInfo **sym_op_info, + CryptoDevBackendOpInfo *op_info, struct iovec *iov, unsigned int out_num) { VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendSymOpInfo *sym_op_info; uint32_t op_type; - CryptoDevBackendSymOpInfo *op_info; op_type = ldl_le_p(&req->op_type); - if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { - op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para, + sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para, NULL, iov, out_num); - if (!op_info) { + if (!sym_op_info) { return -EFAULT; } - op_info->op_type = op_type; } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { - op_info = virtio_crypto_sym_op_helper(vdev, NULL, + sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL, &req->u.chain.para, iov, out_num); - if (!op_info) { + if (!sym_op_info) { return -EFAULT; } - op_info->op_type = op_type; } else { /* VIRTIO_CRYPTO_SYM_OP_NONE */ error_report("virtio-crypto unsupported cipher type"); return -VIRTIO_CRYPTO_NOTSUPP; } - *sym_op_info = op_info; + sym_op_info->op_type = op_type; + op_info->u.sym_op_info = sym_op_info; + + return 0; +} + +static int +virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto, + struct virtio_crypto_akcipher_data_req *req, + CryptoDevBackendOpInfo *op_info, + struct iovec *iov, unsigned int out_num) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendAsymOpInfo *asym_op_info; + uint32_t src_len; + uint32_t dst_len; + uint32_t len; + uint8_t *src = NULL; + uint8_t *dst = NULL; + + 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); + + if (src_len > 0) { + src = g_malloc0(src_len); + len = iov_to_buf(iov, out_num, 0, src, src_len); + if (unlikely(len != src_len)) { + virtio_error(vdev, "virtio-crypto asym src data incorrect" + "expected %u, actual %u", src_len, len); + goto err; + } + + iov_discard_front(&iov, &out_num, src_len); + } + + if (dst_len > 0) { + dst = g_malloc0(dst_len); + + if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { + len = iov_to_buf(iov, out_num, 0, dst, dst_len); + if (unlikely(len != dst_len)) { + virtio_error(vdev, "virtio-crypto asym dst data incorrect" + "expected %u, actual %u", dst_len, len); + goto err; + } + + iov_discard_front(&iov, &out_num, dst_len); + } + } + + asym_op_info->src_len = src_len; + asym_op_info->dst_len = dst_len; + asym_op_info->src = src; + asym_op_info->dst = dst; + op_info->u.asym_op_info = asym_op_info; return 0; + + err: + g_free(asym_op_info); + g_free(src); + g_free(dst); + + return -EFAULT; } static int @@ -594,10 +825,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) unsigned in_num; unsigned out_num; uint32_t opcode; - uint8_t status = VIRTIO_CRYPTO_ERR; - uint64_t session_id; - CryptoDevBackendSymOpInfo *sym_op_info = NULL; - Error *local_err = NULL; + CryptoDevBackendOpInfo *op_info = &request->op_info; if (elem->out_num < 1 || elem->in_num < 1) { virtio_error(vdev, "virtio-crypto dataq missing headers"); @@ -605,11 +833,11 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) } out_num = elem->out_num; - out_iov_copy = g_memdup(elem->out_sg, sizeof(out_iov[0]) * out_num); + out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); out_iov = out_iov_copy; in_num = elem->in_num; - in_iov_copy = g_memdup(elem->in_sg, sizeof(in_iov[0]) * in_num); + in_iov_copy = g_memdup2(elem->in_sg, sizeof(in_iov[0]) * in_num); in_iov = in_iov_copy; if (unlikely(iov_to_buf(out_iov, out_num, 0, &req, sizeof(req)) @@ -637,43 +865,48 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) */ request->in_num = in_num; request->in_iov = in_iov; + /* now, we free the in_iov_copy inside virtio_crypto_free_request */ + in_iov_copy = NULL; opcode = ldl_le_p(&req.header.opcode); - session_id = ldq_le_p(&req.header.session_id); + op_info->session_id = ldq_le_p(&req.header.session_id); + op_info->op_code = opcode; switch (opcode) { case VIRTIO_CRYPTO_CIPHER_ENCRYPT: case VIRTIO_CRYPTO_CIPHER_DECRYPT: + op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM; ret = virtio_crypto_handle_sym_req(vcrypto, - &req.u.sym_req, - &sym_op_info, + &req.u.sym_req, op_info, + out_iov, out_num); + goto check_result; + + case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: + case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: + case VIRTIO_CRYPTO_AKCIPHER_SIGN: + case VIRTIO_CRYPTO_AKCIPHER_VERIFY: + op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM; + ret = virtio_crypto_handle_asym_req(vcrypto, + &req.u.akcipher_req, op_info, out_iov, out_num); + +check_result: /* Serious errors, need to reset virtio crypto device */ if (ret == -EFAULT) { return -1; } else if (ret == -VIRTIO_CRYPTO_NOTSUPP) { - virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP); - virtio_crypto_free_request(request); + virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP); } else { - sym_op_info->session_id = session_id; - - /* Set request's parameter */ - request->flags = CRYPTODEV_BACKEND_ALG_SYM; - request->u.sym_op_info = sym_op_info; ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev, - request, queue_index, &local_err); + request, queue_index, + virtio_crypto_req_complete, + request); if (ret < 0) { - status = -ret; - if (local_err) { - error_report_err(local_err); - } - } else { /* ret == VIRTIO_CRYPTO_OK */ - status = ret; + virtio_crypto_req_complete(request, ret); } - virtio_crypto_req_complete(request, status); - virtio_crypto_free_request(request); } break; + case VIRTIO_CRYPTO_HASH: case VIRTIO_CRYPTO_MAC: case VIRTIO_CRYPTO_AEAD_ENCRYPT: @@ -681,8 +914,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) default: error_report("virtio-crypto unsupported dataq opcode: %u", opcode); - virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP); - virtio_crypto_free_request(request); + virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP); } return 0; @@ -779,6 +1011,7 @@ static void virtio_crypto_init_config(VirtIODevice *vdev) vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l; vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h; vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo; + vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo; vcrypto->conf.max_cipher_key_len = vcrypto->conf.cryptodev->conf.max_cipher_key_len; vcrypto->conf.max_auth_key_len = @@ -810,7 +1043,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-crypto", VIRTIO_ID_CRYPTO, vcrypto->config_size); + virtio_init(vdev, VIRTIO_ID_CRYPTO, vcrypto->config_size); vcrypto->curr_queues = 1; vcrypto->vqs = g_new0(VirtIOCryptoQueue, vcrypto->max_queues); for (i = 0; i < vcrypto->max_queues; i++) { @@ -821,7 +1054,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) vcrypto->vqs[i].vcrypto = vcrypto; } - vcrypto->ctrl_vq = virtio_add_queue(vdev, 64, virtio_crypto_handle_ctrl); + vcrypto->ctrl_vq = virtio_add_queue(vdev, 1024, virtio_crypto_handle_ctrl); if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; } else { @@ -891,6 +1124,7 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config) stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len); stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len); stq_le_p(&crypto_cfg.max_size, c->conf.max_size); + stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo); memcpy(config, &crypto_cfg, c->config_size); } @@ -948,6 +1182,15 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, assert(vcrypto->vhost_started); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return; + } cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); } @@ -958,9 +1201,27 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) assert(vcrypto->vhost_started); + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 + * as the Marco of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return false; + } return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); } +static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) +{ + VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); + CryptoDevBackend *b = vcrypto->cryptodev; + CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; + CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); + return &vhost_crypto->dev; +} + static void virtio_crypto_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -977,6 +1238,7 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data) vdc->set_status = virtio_crypto_set_status; vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask; vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending; + vdc->get_vhost = virtio_crypto_get_vhost; } static void virtio_crypto_instance_init(Object *obj) diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c index 0ac360de4f34..cf8a9cf9e8db 100644 --- a/hw/virtio/virtio-input-host-pci.c +++ b/hw/virtio/virtio-input-host-pci.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-input.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c index 48e9ff38e2fb..a9d0992389f2 100644 --- a/hw/virtio/virtio-input-pci.c +++ b/hw/virtio/virtio-input-pci.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio-input.h" #include "qemu/module.h" diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 6a1df7fe5034..7ef2f9dcdbac 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -11,12 +11,13 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-iommu.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "qapi/error.h" #include "hw/boards.h" +#include "hw/pci/pci_bus.h" #include "qom/object.h" typedef struct VirtIOIOMMUPCI VirtIOIOMMUPCI; @@ -44,6 +45,7 @@ static Property virtio_iommu_pci_properties[] = { static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOIOMMUPCI *dev = VIRTIO_IOMMU_PCI(vpci_dev); + PCIBus *pbus = pci_get_bus(&vpci_dev->pci_dev); DeviceState *vdev = DEVICE(&dev->vdev); VirtIOIOMMU *s = VIRTIO_IOMMU(vdev); @@ -57,11 +59,17 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) { error_setg(errp, "reserved region %d has an invalid type", i); error_append_hint(errp, "Valid values are 0 and 1\n"); + return; } } + if (!pci_bus_is_root(pbus)) { + error_setg(errp, "virtio-iommu-pci must be plugged on the root bus"); + return; + } + object_property_set_link(OBJECT(dev), "primary-bus", - OBJECT(pci_get_bus(&vpci_dev->pci_dev)), - &error_abort); + OBJECT(pbus), &error_abort); + virtio_pci_force_virtio_1(vpci_dev); qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } @@ -74,8 +82,6 @@ static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_iommu_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); device_class_set_props(dc, virtio_iommu_pci_properties); - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_IOMMU; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; dc->hotpluggable = false; @@ -90,7 +96,7 @@ static void virtio_iommu_pci_instance_init(Object *obj) } static const VirtioPCIDeviceTypeInfo virtio_iommu_pci_info = { - .generic_name = TYPE_VIRTIO_IOMMU_PCI, + .generic_name = TYPE_VIRTIO_IOMMU_PCI, .instance_size = sizeof(VirtIOIOMMUPCI), .instance_init = virtio_iommu_pci_instance_init, .class_init = virtio_iommu_pci_class_init, diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 6d5ea0bdf1a3..23c470977ed2 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/iov.h" -#include "qemu-common.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio.h" #include "sysemu/kvm.h" @@ -70,6 +69,77 @@ static inline uint16_t virtio_iommu_get_bdf(IOMMUDevice *dev) return PCI_BUILD_BDF(pci_bus_num(dev->bus), dev->devfn); } +static bool virtio_iommu_device_bypassed(IOMMUDevice *sdev) +{ + uint32_t sid; + bool bypassed; + VirtIOIOMMU *s = sdev->viommu; + VirtIOIOMMUEndpoint *ep; + + sid = virtio_iommu_get_bdf(sdev); + + qemu_rec_mutex_lock(&s->mutex); + /* need to check bypass before system reset */ + if (!s->endpoints) { + bypassed = s->config.bypass; + goto unlock; + } + + ep = g_tree_lookup(s->endpoints, GUINT_TO_POINTER(sid)); + if (!ep || !ep->domain) { + bypassed = s->config.bypass; + } else { + bypassed = ep->domain->bypass; + } + +unlock: + qemu_rec_mutex_unlock(&s->mutex); + return bypassed; +} + +/* Return whether the device is using IOMMU translation. */ +static bool virtio_iommu_switch_address_space(IOMMUDevice *sdev) +{ + bool use_remapping; + + assert(sdev); + + use_remapping = !virtio_iommu_device_bypassed(sdev); + + trace_virtio_iommu_switch_address_space(pci_bus_num(sdev->bus), + PCI_SLOT(sdev->devfn), + PCI_FUNC(sdev->devfn), + use_remapping); + + /* Turn off first then on the other */ + if (use_remapping) { + memory_region_set_enabled(&sdev->bypass_mr, false); + memory_region_set_enabled(MEMORY_REGION(&sdev->iommu_mr), true); + } else { + memory_region_set_enabled(MEMORY_REGION(&sdev->iommu_mr), false); + memory_region_set_enabled(&sdev->bypass_mr, true); + } + + return use_remapping; +} + +static void virtio_iommu_switch_address_space_all(VirtIOIOMMU *s) +{ + GHashTableIter iter; + IOMMUPciBus *iommu_pci_bus; + int i; + + g_hash_table_iter_init(&iter, s->as_by_busptr); + while (g_hash_table_iter_next(&iter, NULL, (void **)&iommu_pci_bus)) { + for (i = 0; i < PCI_DEVFN_MAX; i++) { + if (!iommu_pci_bus->pbdev[i]) { + continue; + } + virtio_iommu_switch_address_space(iommu_pci_bus->pbdev[i]); + } + } +} + /** * The bus number is used for lookup when SID based operations occur. * In that case we lazily populate the IOMMUPciBus array from the bus hash @@ -127,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) @@ -145,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; @@ -169,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, @@ -214,6 +293,7 @@ static gboolean virtio_iommu_notify_map_cb(gpointer key, gpointer value, static void virtio_iommu_detach_endpoint_from_domain(VirtIOIOMMUEndpoint *ep) { VirtIOIOMMUDomain *domain = ep->domain; + IOMMUDevice *sdev = container_of(ep->iommu_mr, IOMMUDevice, iommu_mr); if (!ep->domain) { return; @@ -222,6 +302,7 @@ static void virtio_iommu_detach_endpoint_from_domain(VirtIOIOMMUEndpoint *ep) ep->iommu_mr); QLIST_REMOVE(ep, next); ep->domain = NULL; + virtio_iommu_switch_address_space(sdev); } static VirtIOIOMMUEndpoint *virtio_iommu_get_endpoint(VirtIOIOMMU *s, @@ -324,12 +405,39 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque, trace_virtio_iommu_init_iommu_mr(name); + memory_region_init(&sdev->root, OBJECT(s), name, UINT64_MAX); + address_space_init(&sdev->as, &sdev->root, TYPE_VIRTIO_IOMMU); + + /* + * Build the IOMMU disabled container with aliases to the + * shared MRs. Note that aliasing to a shared memory region + * could help the memory API to detect same FlatViews so we + * can have devices to share the same FlatView when in bypass + * mode. (either by not configuring virtio-iommu driver or with + * "iommu=pt"). It will greatly reduce the total number of + * FlatViews of the system hence VM runs faster. + */ + memory_region_init_alias(&sdev->bypass_mr, OBJECT(s), + "system", get_system_memory(), 0, + memory_region_size(get_system_memory())); + memory_region_init_iommu(&sdev->iommu_mr, sizeof(sdev->iommu_mr), TYPE_VIRTIO_IOMMU_MEMORY_REGION, OBJECT(s), name, UINT64_MAX); - address_space_init(&sdev->as, - MEMORY_REGION(&sdev->iommu_mr), TYPE_VIRTIO_IOMMU); + + /* + * Hook both the containers under the root container, we + * switch between iommu & bypass MRs by enable/disable + * corresponding sub-containers + */ + memory_region_add_subregion_overlap(&sdev->root, 0, + MEMORY_REGION(&sdev->iommu_mr), + 0); + memory_region_add_subregion_overlap(&sdev->root, 0, + &sdev->bypass_mr, 0); + + virtio_iommu_switch_address_space(sdev); g_free(name); } return &sdev->as; @@ -343,6 +451,7 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, uint32_t flags = le32_to_cpu(req->flags); VirtIOIOMMUDomain *domain; VirtIOIOMMUEndpoint *ep; + IOMMUDevice *sdev; trace_virtio_iommu_attach(domain_id, ep_id); @@ -376,6 +485,8 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, QLIST_INSERT_HEAD(&domain->endpoint_list, ep, next); ep->domain = domain; + sdev = container_of(ep->iommu_mr, IOMMUDevice, iommu_mr); + virtio_iommu_switch_address_space(sdev); /* Replay domain mappings on the associated memory region */ g_tree_foreach(domain->mappings, virtio_iommu_notify_map_cb, @@ -573,11 +684,10 @@ static int virtio_iommu_probe(VirtIOIOMMU *s, static int virtio_iommu_iov_to_req(struct iovec *iov, unsigned int iov_cnt, - void *req, size_t req_sz) + void *req, size_t payload_sz) { - size_t sz, payload_sz = req_sz - sizeof(struct virtio_iommu_req_tail); + size_t sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz); - sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz); if (unlikely(sz != payload_sz)) { return VIRTIO_IOMMU_S_INVAL; } @@ -590,7 +700,8 @@ static int virtio_iommu_handle_ ## __req(VirtIOIOMMU *s, \ unsigned int iov_cnt) \ { \ struct virtio_iommu_req_ ## __req req; \ - int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req)); \ + int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, \ + sizeof(req) - sizeof(struct virtio_iommu_req_tail));\ \ return ret ? ret : virtio_iommu_ ## __req(s, &req); \ } @@ -643,7 +754,7 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq) tail.status = VIRTIO_IOMMU_S_DEVERR; goto out; } - qemu_mutex_lock(&s->mutex); + qemu_rec_mutex_lock(&s->mutex); switch (head.type) { case VIRTIO_IOMMU_T_ATTACH: tail.status = virtio_iommu_handle_attach(s, iov, iov_cnt); @@ -664,15 +775,14 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq) output_size = s->config.probe_size + sizeof(tail); buf = g_malloc0(output_size); - ptail = (struct virtio_iommu_req_tail *) - (buf + s->config.probe_size); + ptail = buf + s->config.probe_size; ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf); break; } default: tail.status = VIRTIO_IOMMU_S_UNSUPP; } - qemu_mutex_unlock(&s->mutex); + qemu_rec_mutex_unlock(&s->mutex); out: sz = iov_from_buf(elem->in_sg, elem->in_num, 0, @@ -760,9 +870,13 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, sid = virtio_iommu_get_bdf(sdev); trace_virtio_iommu_translate(mr->parent_obj.name, sid, addr, flag); - qemu_mutex_lock(&s->mutex); + qemu_rec_mutex_lock(&s->mutex); ep = g_tree_lookup(s->endpoints, GUINT_TO_POINTER(sid)); + + if (bypass_allowed) + assert(ep && ep->domain && !ep->domain->bypass); + if (!ep) { if (!bypass_allowed) { error_report_once("%s sid=%d is not known!!", __func__, sid); @@ -844,7 +958,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, trace_virtio_iommu_translate_out(addr, entry.translated_addr, sid); unlock: - qemu_mutex_unlock(&s->mutex); + qemu_rec_mutex_unlock(&s->mutex); return entry; } @@ -888,6 +1002,7 @@ static void virtio_iommu_set_config(VirtIODevice *vdev, return; } dev_config->bypass = in_config->bypass; + virtio_iommu_switch_address_space_all(dev); } trace_virtio_iommu_set_config(in_config->bypass); @@ -932,7 +1047,7 @@ static void virtio_iommu_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *n) sid = virtio_iommu_get_bdf(sdev); - qemu_mutex_lock(&s->mutex); + qemu_rec_mutex_lock(&s->mutex); if (!s->endpoints) { goto unlock; @@ -946,7 +1061,7 @@ static void virtio_iommu_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *n) g_tree_foreach(ep->domain->mappings, virtio_iommu_remap, mr); unlock: - qemu_mutex_unlock(&s->mutex); + qemu_rec_mutex_unlock(&s->mutex); } static int virtio_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu_mr, @@ -1027,6 +1142,8 @@ static void virtio_iommu_system_reset(void *opaque) * system reset */ s->config.bypass = s->boot_bypass; + virtio_iommu_switch_address_space_all(s); + } static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) @@ -1034,8 +1151,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOIOMMU *s = VIRTIO_IOMMU(dev); - virtio_init(vdev, "virtio-iommu", VIRTIO_ID_IOMMU, - sizeof(struct virtio_iommu_config)); + virtio_init(vdev, VIRTIO_ID_IOMMU, sizeof(struct virtio_iommu_config)); memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num)); @@ -1043,6 +1159,11 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) virtio_iommu_handle_command); s->event_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, NULL); + /* + * config.bypass is needed to get initial address space early, such as + * in vfio realize + */ + s->config.bypass = s->boot_bypass; s->config.page_size_mask = TARGET_PAGE_MASK; s->config.input_range.end = UINT64_MAX; s->config.domain_range.end = UINT32_MAX; @@ -1058,7 +1179,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) virtio_add_feature(&s->features, VIRTIO_IOMMU_F_PROBE); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS_CONFIG); - qemu_mutex_init(&s->mutex); + qemu_rec_mutex_init(&s->mutex); s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free); @@ -1086,6 +1207,8 @@ static void virtio_iommu_device_unrealize(DeviceState *dev) g_tree_destroy(s->endpoints); } + qemu_rec_mutex_destroy(&s->mutex); + virtio_delete_queue(s->req_vq); virtio_delete_queue(s->event_vq); virtio_cleanup(vdev); @@ -1207,6 +1330,14 @@ static int iommu_post_load(void *opaque, int version_id) VirtIOIOMMU *s = opaque; g_tree_foreach(s->domains, reconstruct_endpoints, s); + + /* + * Memory regions are dynamically turned on/off depending on + * 'config.bypass' and attached domain type if there is. After + * migration, we need to make sure the memory regions are + * still correct. + */ + virtio_iommu_switch_address_space_all(s); return 0; } diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index be2383b0c522..e8c338c5d94d 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -65,7 +65,6 @@ static void virtio_mem_pci_fill_device_info(const MemoryDeviceState *md, DeviceState *dev = DEVICE(md); if (dev->id) { - vi->has_id = true; vi->id = g_strdup(dev->id); } @@ -90,8 +89,7 @@ static void virtio_mem_pci_size_change_notify(Notifier *notifier, void *data) char *qom_path = object_get_canonical_path(OBJECT(dev)); const uint64_t * const size_p = data; - qapi_event_send_memory_device_size_change(!!dev->id, dev->id, *size_p, - qom_path); + qapi_event_send_memory_device_size_change(dev->id, *size_p, qom_path); g_free(qom_path); } @@ -104,8 +102,6 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_mem_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_MEM; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index f55dcf61f203..1ed1f5a4afb8 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/iov.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -53,11 +52,11 @@ static uint32_t virtio_mem_default_thp_size(void) #if defined(__x86_64__) || defined(__arm__) || defined(__powerpc64__) default_thp_size = 2 * MiB; #elif defined(__aarch64__) - if (qemu_real_host_page_size == 4 * KiB) { + if (qemu_real_host_page_size() == 4 * KiB) { default_thp_size = 2 * MiB; - } else if (qemu_real_host_page_size == 16 * KiB) { + } else if (qemu_real_host_page_size() == 16 * KiB) { default_thp_size = 32 * MiB; - } else if (qemu_real_host_page_size == 64 * KiB) { + } else if (qemu_real_host_page_size() == 64 * KiB) { default_thp_size = 512 * MiB; } #endif @@ -120,7 +119,7 @@ static uint64_t virtio_mem_default_block_size(RAMBlock *rb) const uint64_t page_size = qemu_ram_pagesize(rb); /* We can have hugetlbfs with a page size smaller than the THP size. */ - if (page_size == qemu_real_host_page_size) { + if (page_size == qemu_real_host_page_size()) { return MAX(page_size, virtio_mem_thp_size()); } return MAX(page_size, VIRTIO_MEM_MIN_BLOCK_SIZE); @@ -135,7 +134,7 @@ static bool virtio_mem_has_shared_zeropage(RAMBlock *rb) * fresh page, consuming actual memory. */ return !qemu_ram_is_shared(rb) && rb->fd < 0 && - qemu_ram_pagesize(rb) == qemu_real_host_page_size; + qemu_ram_pagesize(rb) == qemu_real_host_page_size(); } #endif /* VIRTIO_MEM_HAS_LEGACY_GUESTS */ @@ -208,7 +207,7 @@ static int virtio_mem_for_each_unplugged_range(const VirtIOMEM *vmem, void *arg, * * Returns false if the intersection is empty, otherwise returns true. */ -static bool virito_mem_intersect_memory_section(MemoryRegionSection *s, +static bool virtio_mem_intersect_memory_section(MemoryRegionSection *s, uint64_t offset, uint64_t size) { uint64_t start = MAX(s->offset_within_region, offset); @@ -236,7 +235,7 @@ static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, uint64_t offset, size; int ret = 0; - first_bit = s->offset_within_region / vmem->bitmap_size; + first_bit = s->offset_within_region / vmem->block_size; first_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, first_bit); while (first_bit < vmem->bitmap_size) { MemoryRegionSection tmp = *s; @@ -246,7 +245,7 @@ static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, first_bit + 1) - 1; size = (last_bit - first_bit + 1) * vmem->block_size; - if (!virito_mem_intersect_memory_section(&tmp, offset, size)) { + if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { break; } ret = cb(&tmp, arg); @@ -268,7 +267,7 @@ static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, uint64_t offset, size; int ret = 0; - first_bit = s->offset_within_region / vmem->bitmap_size; + first_bit = s->offset_within_region / vmem->block_size; first_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, first_bit); while (first_bit < vmem->bitmap_size) { MemoryRegionSection tmp = *s; @@ -278,7 +277,7 @@ static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, first_bit + 1) - 1; size = (last_bit - first_bit + 1) * vmem->block_size; - if (!virito_mem_intersect_memory_section(&tmp, offset, size)) { + if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { break; } ret = cb(&tmp, arg); @@ -314,7 +313,7 @@ static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset, QLIST_FOREACH(rdl, &vmem->rdl_list, next) { MemoryRegionSection tmp = *rdl->section; - if (!virito_mem_intersect_memory_section(&tmp, offset, size)) { + if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { continue; } rdl->notify_discard(rdl, &tmp); @@ -330,7 +329,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, QLIST_FOREACH(rdl, &vmem->rdl_list, next) { MemoryRegionSection tmp = *rdl->section; - if (!virito_mem_intersect_memory_section(&tmp, offset, size)) { + if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { continue; } ret = rdl->notify_populate(rdl, &tmp); @@ -342,12 +341,12 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, if (ret) { /* Notify all already-notified listeners. */ QLIST_FOREACH(rdl2, &vmem->rdl_list, next) { - MemoryRegionSection tmp = *rdl->section; + MemoryRegionSection tmp = *rdl2->section; if (rdl2 == rdl) { break; } - if (!virito_mem_intersect_memory_section(&tmp, offset, size)) { + if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { continue; } rdl2->notify_discard(rdl2, &tmp); @@ -468,7 +467,7 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, int fd = memory_region_get_fd(&vmem->memdev->mr); Error *local_err = NULL; - os_mem_prealloc(fd, area, size, 1, &local_err); + qemu_prealloc_mem(fd, area, size, 1, NULL, &local_err); if (local_err) { static bool warned; @@ -868,8 +867,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) vmem->block_size; vmem->bitmap = bitmap_new(vmem->bitmap_size); - virtio_init(vdev, TYPE_VIRTIO_MEM, VIRTIO_ID_MEM, - sizeof(struct virtio_mem_config)); + virtio_init(vdev, VIRTIO_ID_MEM, sizeof(struct virtio_mem_config)); vmem->vq = virtio_add_queue(vdev, 128, virtio_mem_handle_request); host_memory_backend_set_mapped(vmem->memdev, true); @@ -1096,12 +1094,9 @@ static void virtio_mem_set_requested_size(Object *obj, Visitor *v, Error **errp) { VirtIOMEM *vmem = VIRTIO_MEM(obj); - Error *err = NULL; uint64_t value; - visit_type_size(v, name, &value, &err); - if (err) { - error_propagate(errp, err); + if (!visit_type_size(v, name, &value, errp)) { return; } @@ -1161,7 +1156,6 @@ static void virtio_mem_set_block_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { VirtIOMEM *vmem = VIRTIO_MEM(obj); - Error *err = NULL; uint64_t value; if (DEVICE(obj)->realized) { @@ -1169,9 +1163,7 @@ static void virtio_mem_set_block_size(Object *obj, Visitor *v, const char *name, return; } - visit_type_size(v, name, &value, &err); - if (err) { - error_propagate(errp, err); + if (!visit_type_size(v, name, &value, errp)) { return; } diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 688eccda94d7..103260ec15d4 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -72,12 +72,12 @@ static void virtio_mmio_soft_reset(VirtIOMMIOProxy *proxy) { int i; - if (proxy->legacy) { - return; - } + virtio_bus_reset(&proxy->bus); - for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - proxy->vqs[i].enabled = 0; + if (!proxy->legacy) { + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { + proxy->vqs[i].enabled = 0; + } } } @@ -376,7 +376,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, return; } if (value == 0) { - virtio_reset(vdev); + virtio_mmio_soft_reset(proxy); } else { virtio_queue_set_addr(vdev, vdev->queue_sel, value << proxy->guest_page_shift); @@ -432,7 +432,6 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, } if (vdev->status == 0) { - virtio_reset(vdev); virtio_mmio_soft_reset(proxy); } break; @@ -627,8 +626,8 @@ static void virtio_mmio_reset(DeviceState *d) VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); int i; - virtio_mmio_stop_ioeventfd(proxy); - virtio_bus_reset(&proxy->bus); + virtio_mmio_soft_reset(proxy); + proxy->host_features_sel = 0; proxy->guest_features_sel = 0; proxy->guest_page_shift = 0; @@ -637,7 +636,6 @@ static void virtio_mmio_reset(DeviceState *d) proxy->guest_features[0] = proxy->guest_features[1] = 0; for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - proxy->vqs[i].enabled = 0; proxy->vqs[i].num = 0; proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0; proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0; @@ -672,7 +670,30 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, return 0; } +static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign, + bool with_irqfd) +{ + VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); + int r = 0; + if (assign) { + r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } + virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); + } else { + virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); + event_notifier_cleanup(notifier); + } + if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { + vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); + } + return r; +} static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) { @@ -694,6 +715,10 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, goto assign_error; } } + r = virtio_mmio_set_config_guest_notifier(d, assign, with_irqfd); + if (r < 0) { + goto assign_error; + } return 0; diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c index aa0b3caecbc6..e03543a70a75 100644 --- a/hw/virtio/virtio-net-pci.c +++ b/hw/virtio/virtio-net-pci.c @@ -19,7 +19,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-net.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qapi/error.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 7cf1231c1c55..247325c1933c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -19,6 +19,7 @@ #include "exec/memop.h" #include "standard-headers/linux/virtio_pci.h" +#include "standard-headers/linux/virtio_ids.h" #include "hw/boards.h" #include "hw/virtio/virtio.h" #include "migration/qemu-file-types.h" @@ -33,11 +34,12 @@ #include "hw/pci/msix.h" #include "hw/loader.h" #include "sysemu/kvm.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qemu/range.h" #include "hw/virtio/virtio-bus.h" #include "qapi/visitor.h" #include "sysemu/replay.h" +#include "trace.h" #define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev)) @@ -70,9 +72,11 @@ static void virtio_pci_notify(DeviceState *d, uint16_t vector) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d); - if (msix_enabled(&proxy->pci_dev)) - msix_notify(&proxy->pci_dev, vector); - else { + if (msix_enabled(&proxy->pci_dev)) { + if (vector != VIRTIO_NO_VECTOR) { + msix_notify(&proxy->pci_dev, vector); + } + } else { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); pci_set_irq(&proxy->pci_dev, qatomic_read(&vdev->isr) & 1); } @@ -174,6 +178,7 @@ static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + uint16_t vector; int ret; ret = pci_device_load(&proxy->pci_dev, f); @@ -183,12 +188,17 @@ static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) msix_unuse_all_vectors(&proxy->pci_dev); msix_load(&proxy->pci_dev, f); if (msix_present(&proxy->pci_dev)) { - qemu_get_be16s(f, &vdev->config_vector); + qemu_get_be16s(f, &vector); + + if (vector != VIRTIO_NO_VECTOR && vector >= proxy->nvectors) { + return -EINVAL; + } } else { - vdev->config_vector = VIRTIO_NO_VECTOR; + vector = VIRTIO_NO_VECTOR; } - if (vdev->config_vector != VIRTIO_NO_VECTOR) { - return msix_vector_use(&proxy->pci_dev, vdev->config_vector); + vdev->config_vector = vector; + if (vector != VIRTIO_NO_VECTOR) { + msix_vector_use(&proxy->pci_dev, vector); } return 0; } @@ -201,17 +211,104 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) uint16_t vector; if (msix_present(&proxy->pci_dev)) { qemu_get_be16s(f, &vector); + if (vector != VIRTIO_NO_VECTOR && vector >= proxy->nvectors) { + return -EINVAL; + } } else { vector = VIRTIO_NO_VECTOR; } virtio_queue_set_vector(vdev, n, vector); if (vector != VIRTIO_NO_VECTOR) { - return msix_vector_use(&proxy->pci_dev, vector); + msix_vector_use(&proxy->pci_dev, vector); } return 0; } +typedef struct VirtIOPCIIDInfo { + /* virtio id */ + uint16_t vdev_id; + /* pci device id for the transitional device */ + uint16_t trans_devid; + uint16_t class_id; +} VirtIOPCIIDInfo; + +static const VirtIOPCIIDInfo virtio_pci_id_info[] = { + { + .vdev_id = VIRTIO_ID_CRYPTO, + .class_id = PCI_CLASS_OTHERS, + }, { + .vdev_id = VIRTIO_ID_FS, + .class_id = PCI_CLASS_STORAGE_OTHER, + }, { + .vdev_id = VIRTIO_ID_NET, + .trans_devid = PCI_DEVICE_ID_VIRTIO_NET, + .class_id = PCI_CLASS_NETWORK_ETHERNET, + }, { + .vdev_id = VIRTIO_ID_BLOCK, + .trans_devid = PCI_DEVICE_ID_VIRTIO_BLOCK, + .class_id = PCI_CLASS_STORAGE_SCSI, + }, { + .vdev_id = VIRTIO_ID_CONSOLE, + .trans_devid = PCI_DEVICE_ID_VIRTIO_CONSOLE, + .class_id = PCI_CLASS_COMMUNICATION_OTHER, + }, { + .vdev_id = VIRTIO_ID_SCSI, + .trans_devid = PCI_DEVICE_ID_VIRTIO_SCSI, + .class_id = PCI_CLASS_STORAGE_SCSI + }, { + .vdev_id = VIRTIO_ID_9P, + .trans_devid = PCI_DEVICE_ID_VIRTIO_9P, + .class_id = PCI_BASE_CLASS_NETWORK, + }, { + .vdev_id = VIRTIO_ID_BALLOON, + .trans_devid = PCI_DEVICE_ID_VIRTIO_BALLOON, + .class_id = PCI_CLASS_OTHERS, + }, { + .vdev_id = VIRTIO_ID_RNG, + .trans_devid = PCI_DEVICE_ID_VIRTIO_RNG, + .class_id = PCI_CLASS_OTHERS, + }, +}; + +static const VirtIOPCIIDInfo *virtio_pci_get_id_info(uint16_t vdev_id) +{ + const VirtIOPCIIDInfo *info = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(virtio_pci_id_info); i++) { + if (virtio_pci_id_info[i].vdev_id == vdev_id) { + info = &virtio_pci_id_info[i]; + break; + } + } + + if (!info) { + /* The device id is invalid or not added to the id_info yet. */ + error_report("Invalid virtio device(id %u)", vdev_id); + abort(); + } + + return info; +} + +/* + * Get the Transitional Device ID for the specific device, return + * zero if the device is non-transitional. + */ +uint16_t virtio_pci_get_trans_devid(uint16_t device_id) +{ + return virtio_pci_get_id_info(device_id)->trans_devid; +} + +/* + * Get the Class ID for the specific device. + */ +uint16_t virtio_pci_get_class_id(uint16_t device_id) +{ + return virtio_pci_get_id_info(device_id)->class_id; +} + static bool virtio_pci_ioeventfd_enabled(DeviceState *d) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); @@ -298,6 +395,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) { VirtIOPCIProxy *proxy = opaque; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + uint16_t vector; hwaddr pa; switch (addr) { @@ -351,18 +449,28 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) } break; case VIRTIO_MSI_CONFIG_VECTOR: - msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); + if (vdev->config_vector != VIRTIO_NO_VECTOR) { + msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); + } /* Make it possible for guest to discover an error took place. */ - if (msix_vector_use(&proxy->pci_dev, val) < 0) + if (val < proxy->nvectors) { + msix_vector_use(&proxy->pci_dev, val); + } else { val = VIRTIO_NO_VECTOR; + } vdev->config_vector = val; break; case VIRTIO_MSI_QUEUE_VECTOR: - msix_vector_unuse(&proxy->pci_dev, - virtio_queue_vector(vdev, vdev->queue_sel)); + vector = virtio_queue_vector(vdev, vdev->queue_sel); + if (vector != VIRTIO_NO_VECTOR) { + msix_vector_unuse(&proxy->pci_dev, vector); + } /* Make it possible for guest to discover an error took place. */ - if (msix_vector_use(&proxy->pci_dev, val) < 0) + if (val < proxy->nvectors) { + msix_vector_use(&proxy->pci_dev, val); + } else { val = VIRTIO_NO_VECTOR; + } virtio_queue_set_vector(vdev, vdev->queue_sel, val); break; default: @@ -676,7 +784,6 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, } static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, - unsigned int queue_no, unsigned int vector) { VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; @@ -705,112 +812,160 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, } static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, - unsigned int queue_no, + EventNotifier *n, unsigned int vector) { VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - VirtQueue *vq = virtio_get_queue(vdev, queue_no); - EventNotifier *n = virtio_queue_get_guest_notifier(vq); return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); } static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, - unsigned int queue_no, + EventNotifier *n , unsigned int vector) { - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - VirtQueue *vq = virtio_get_queue(vdev, queue_no); - EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); assert(ret == 0); } +static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + EventNotifier **n, unsigned int *vector) +{ + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq; -static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { + *n = virtio_config_get_guest_notifier(vdev); + *vector = vdev->config_vector; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; + } + *vector = virtio_queue_vector(vdev, queue_no); + vq = virtio_get_queue(vdev, queue_no); + *n = virtio_queue_get_guest_notifier(vq); + } + return 0; +} + +static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) { + unsigned int vector; + int ret; + EventNotifier *n; PCIDevice *dev = &proxy->pci_dev; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - unsigned int vector; - int ret, queue_no; - for (queue_no = 0; queue_no < nvqs; queue_no++) { - if (!virtio_queue_get_num(vdev, queue_no)) { - break; - } - vector = virtio_queue_vector(vdev, queue_no); - if (vector >= msix_nr_vectors_allocated(dev)) { - continue; - } - ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); + ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); + if (ret < 0) { + return ret; + } + if (vector >= msix_nr_vectors_allocated(dev)) { + return 0; + } + ret = kvm_virtio_pci_vq_vector_use(proxy, vector); + if (ret < 0) { + goto undo; + } + /* + * If guest supports masking, set up irqfd now. + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); goto undo; } - /* If guest supports masking, set up irqfd now. - * Otherwise, delay until unmasked in the frontend. - */ - if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { - ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); - if (ret < 0) { - kvm_virtio_pci_vq_vector_release(proxy, vector); - goto undo; - } - } } - return 0; + return 0; undo: - while (--queue_no >= 0) { - vector = virtio_queue_vector(vdev, queue_no); - if (vector >= msix_nr_vectors_allocated(dev)) { - continue; + + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + return ret; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); + if (ret < 0) { + return ret; } - if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { - kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + return ret; +} +static int kvm_virtio_pci_vector_vq_use(VirtIOPCIProxy *proxy, int nvqs) +{ + int queue_no; + int ret = 0; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; } - kvm_virtio_pci_vq_vector_release(proxy, vector); + ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); } return ret; } -static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) +static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) +{ + return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); +} + +static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) { - PCIDevice *dev = &proxy->pci_dev; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); unsigned int vector; - int queue_no; + EventNotifier *n; + int ret; VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + PCIDevice *dev = &proxy->pci_dev; + + ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); + if (ret < 0) { + return; + } + if (vector >= msix_nr_vectors_allocated(dev)) { + return; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); +} + +static void kvm_virtio_pci_vector_vq_release(VirtIOPCIProxy *proxy, int nvqs) +{ + int queue_no; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); for (queue_no = 0; queue_no < nvqs; queue_no++) { if (!virtio_queue_get_num(vdev, queue_no)) { break; } - vector = virtio_queue_vector(vdev, queue_no); - if (vector >= msix_nr_vectors_allocated(dev)) { - continue; - } - /* If guest supports masking, clean up irqfd now. - * Otherwise, it was cleaned when masked in the frontend. - */ - if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { - kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); - } - kvm_virtio_pci_vq_vector_release(proxy, vector); + kvm_virtio_pci_vector_release_one(proxy, queue_no); } } -static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, +static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) +{ + kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); +} + +static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector, - MSIMessage msg) + MSIMessage msg, + EventNotifier *n) { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - VirtQueue *vq = virtio_get_queue(vdev, queue_no); - EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd; int ret = 0; @@ -837,14 +992,15 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, event_notifier_set(n); } } else { - ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); } return ret; } -static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, +static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, unsigned int queue_no, - unsigned int vector) + unsigned int vector, + EventNotifier *n) { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); @@ -855,7 +1011,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { k->guest_notifier_mask(vdev, queue_no, true); } else { - kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + kvm_virtio_pci_irqfd_release(proxy, n, vector); } } @@ -865,6 +1021,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_vector_first_queue(vdev, vector); + EventNotifier *n; int ret, index, unmasked = 0; while (vq) { @@ -873,7 +1030,8 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, break; } if (index < proxy->nvqs_with_notifiers) { - ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); + n = virtio_queue_get_guest_notifier(vq); + ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); if (ret < 0) { goto undo; } @@ -881,15 +1039,26 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, } vq = virtio_vector_next_queue(vq); } - + /* unmask config intr */ + if (vector == vdev->config_vector) { + n = virtio_config_get_guest_notifier(vdev); + ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, + msg, n); + if (ret < 0) { + goto undo_config; + } + } return 0; - +undo_config: + n = virtio_config_get_guest_notifier(vdev); + virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); undo: vq = virtio_vector_first_queue(vdev, vector); while (vq && unmasked >= 0) { index = virtio_get_queue_index(vq); if (index < proxy->nvqs_with_notifiers) { - virtio_pci_vq_vector_mask(proxy, index, vector); + n = virtio_queue_get_guest_notifier(vq); + virtio_pci_one_vector_mask(proxy, index, vector, n); --unmasked; } vq = virtio_vector_next_queue(vq); @@ -902,18 +1071,25 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_vector_first_queue(vdev, vector); + EventNotifier *n; int index; while (vq) { index = virtio_get_queue_index(vq); + n = virtio_queue_get_guest_notifier(vq); if (!virtio_queue_get_num(vdev, index)) { break; } if (index < proxy->nvqs_with_notifiers) { - virtio_pci_vq_vector_mask(proxy, index, vector); + virtio_pci_one_vector_mask(proxy, index, vector, n); } vq = virtio_vector_next_queue(vq); } + + if (vector == vdev->config_vector) { + n = virtio_config_get_guest_notifier(vdev); + virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + } } static void virtio_pci_vector_poll(PCIDevice *dev, @@ -926,19 +1102,17 @@ static void virtio_pci_vector_poll(PCIDevice *dev, int queue_no; unsigned int vector; EventNotifier *notifier; - VirtQueue *vq; + int ret; for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { - if (!virtio_queue_get_num(vdev, queue_no)) { + ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); + if (ret < 0) { break; } - vector = virtio_queue_vector(vdev, queue_no); if (vector < vector_start || vector >= vector_end || !msix_is_masked(dev, vector)) { continue; } - vq = virtio_get_queue(vdev, queue_no); - notifier = virtio_queue_get_guest_notifier(vq); if (k->guest_notifier_pending) { if (k->guest_notifier_pending(vdev, queue_no)) { msix_set_pending(dev, vector); @@ -947,6 +1121,34 @@ static void virtio_pci_vector_poll(PCIDevice *dev, msix_set_pending(dev, vector); } } + /* poll the config intr */ + ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, + &vector); + if (ret < 0) { + return; + } + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + return; + } + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { + msix_set_pending(dev, vector); + } + } else if (event_notifier_test_and_clear(notifier)) { + msix_set_pending(dev, vector); + } +} + +void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, + int n, bool assign, + bool with_irqfd) +{ + if (n == VIRTIO_CONFIG_IRQ_IDX) { + virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); + } else { + virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); + } } static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, @@ -955,17 +1157,25 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); - VirtQueue *vq = virtio_get_queue(vdev, n); - EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + VirtQueue *vq = NULL; + EventNotifier *notifier = NULL; + + if (n == VIRTIO_CONFIG_IRQ_IDX) { + notifier = virtio_config_get_guest_notifier(vdev); + } else { + vq = virtio_get_queue(vdev, n); + notifier = virtio_queue_get_guest_notifier(vq); + } if (assign) { int r = event_notifier_init(notifier, 0); if (r < 0) { return r; } - virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); + virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); } else { - virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); + virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, + with_irqfd); event_notifier_cleanup(notifier); } @@ -995,18 +1205,26 @@ 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; /* Must unset vector notifier while guest notifier is still assigned */ - if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) { + if ((proxy->vector_irqfd || + (vdev->use_guest_notifier_mask && k->guest_notifier_mask)) && + !assign) { msix_unset_vector_notifiers(&proxy->pci_dev); if (proxy->vector_irqfd) { - kvm_virtio_pci_vector_release(proxy, nvqs); + kvm_virtio_pci_vector_vq_release(proxy, nvqs); + kvm_virtio_pci_vector_config_release(proxy); g_free(proxy->vector_irqfd); proxy->vector_irqfd = NULL; } @@ -1022,20 +1240,30 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) goto assign_error; } } - + r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, + with_irqfd); + if (r < 0) { + goto config_assign_error; + } /* Must set vector notifier after guest notifier has been assigned */ - if ((with_irqfd || k->guest_notifier_mask) && assign) { + if ((with_irqfd || + (vdev->use_guest_notifier_mask && k->guest_notifier_mask)) && + assign) { if (with_irqfd) { proxy->vector_irqfd = g_malloc0(sizeof(*proxy->vector_irqfd) * msix_nr_vectors_allocated(&proxy->pci_dev)); - r = kvm_virtio_pci_vector_use(proxy, nvqs); + r = kvm_virtio_pci_vector_vq_use(proxy, nvqs); + if (r < 0) { + goto config_assign_error; + } + r = kvm_virtio_pci_vector_config_use(proxy); if (r < 0) { - goto assign_error; + goto config_error; } } - r = msix_set_vector_notifiers(&proxy->pci_dev, - virtio_pci_vector_unmask, + + r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, virtio_pci_vector_mask, virtio_pci_vector_poll); if (r < 0) { @@ -1048,15 +1276,23 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) notifiers_error: if (with_irqfd) { assert(assign); - kvm_virtio_pci_vector_release(proxy, nvqs); + kvm_virtio_pci_vector_vq_release(proxy, nvqs); } - +config_error: + if (with_irqfd) { + kvm_virtio_pci_vector_config_release(proxy); + } +config_assign_error: + virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, + with_irqfd); assign_error: /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ assert(assign); while (--n >= 0) { virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd); } + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; return r; } @@ -1245,6 +1481,9 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, case VIRTIO_PCI_COMMON_Q_USEDHI: val = proxy->vqs[vdev->queue_sel].used[1]; break; + case VIRTIO_PCI_COMMON_Q_RESET: + val = proxy->vqs[vdev->queue_sel].reset; + break; default: val = 0; } @@ -1257,6 +1496,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, { VirtIOPCIProxy *proxy = opaque; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + uint16_t vector; if (vdev == NULL) { return; @@ -1278,9 +1518,13 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, } break; case VIRTIO_PCI_COMMON_MSIX: - msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); + if (vdev->config_vector != VIRTIO_NO_VECTOR) { + msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); + } /* Make it possible for guest to discover an error took place. */ - if (msix_vector_use(&proxy->pci_dev, val) < 0) { + if (val < proxy->nvectors) { + msix_vector_use(&proxy->pci_dev, val); + } else { val = VIRTIO_NO_VECTOR; } vdev->config_vector = val; @@ -1312,10 +1556,14 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, proxy->vqs[vdev->queue_sel].num); break; case VIRTIO_PCI_COMMON_Q_MSIX: - msix_vector_unuse(&proxy->pci_dev, - virtio_queue_vector(vdev, vdev->queue_sel)); + vector = virtio_queue_vector(vdev, vdev->queue_sel); + if (vector != VIRTIO_NO_VECTOR) { + msix_vector_unuse(&proxy->pci_dev, vector); + } /* Make it possible for guest to discover an error took place. */ - if (msix_vector_use(&proxy->pci_dev, val) < 0) { + if (val < proxy->nvectors) { + msix_vector_use(&proxy->pci_dev, val); + } else { val = VIRTIO_NO_VECTOR; } virtio_queue_set_vector(vdev, vdev->queue_sel, val); @@ -1332,6 +1580,8 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 | proxy->vqs[vdev->queue_sel].used[0]); proxy->vqs[vdev->queue_sel].enabled = 1; + proxy->vqs[vdev->queue_sel].reset = 0; + virtio_queue_enable(vdev, vdev->queue_sel); } else { virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val); } @@ -1354,6 +1604,16 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, case VIRTIO_PCI_COMMON_Q_USEDHI: proxy->vqs[vdev->queue_sel].used[1] = val; break; + case VIRTIO_PCI_COMMON_Q_RESET: + if (val == 1) { + proxy->vqs[vdev->queue_sel].reset = 1; + + virtio_queue_reset(vdev, vdev->queue_sel); + + proxy->vqs[vdev->queue_sel].reset = 0; + proxy->vqs[vdev->queue_sel].enabled = 0; + } + break; default: break; } @@ -1380,6 +1640,7 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) { + trace_virtio_pci_notify_write(addr, val, size); virtio_queue_notify(vdev, queue); } } @@ -1393,6 +1654,7 @@ static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr, unsigned queue = val; if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) { + trace_virtio_pci_notify_write_pio(addr, val, size); virtio_queue_notify(vdev, queue); } } @@ -1667,7 +1929,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by" " neither legacy nor transitional device"); - return ; + return; } /* * Legacy and transitional devices use specific subsystem IDs. @@ -1675,12 +1937,15 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) * is set to PCI_SUBVENDOR_ID_REDHAT_QUMRANET by default. */ pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); + if (proxy->trans_devid) { + pci_config_set_device_id(config, proxy->trans_devid); + } } else { /* pure virtio-1.0 */ pci_set_word(config + PCI_VENDOR_ID, PCI_VENDOR_ID_REDHAT_QUMRANET); pci_set_word(config + PCI_DEVICE_ID, - 0x1040 + virtio_bus_get_vdev_id(bus)); + PCI_DEVICE_ID_VIRTIO_10_BASE + virtio_bus_get_vdev_id(bus)); pci_config_set_revision(config, 1); } config[PCI_INTERRUPT_PIN] = 1; @@ -1939,20 +2204,27 @@ 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_pci_stop_ioeventfd(proxy); virtio_bus_reset(bus); msix_unuse_all_vectors(&proxy->pci_dev); for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { proxy->vqs[i].enabled = 0; + proxy->vqs[i].reset = 0; proxy->vqs[i].num = 0; proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0; 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_hold(Object *obj) +{ + PCIDevice *dev = PCI_DEVICE(obj); + DeviceState *qdev = DEVICE(obj); + + virtio_pci_reset(qdev); if (pci_is_express(dev)) { pcie_cap_deverr_reset(dev); @@ -2011,6 +2283,7 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_props(dc, virtio_pci_properties); k->realize = virtio_pci_realize; @@ -2020,7 +2293,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; + rc->phases.hold = virtio_pci_bus_reset_hold; } static const TypeInfo virtio_pci_info = { diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c index 2b2a0b1eae10..1b89ade9d151 100644 --- a/hw/virtio/virtio-pmem-pci.c +++ b/hw/virtio/virtio-pmem-pci.c @@ -70,7 +70,6 @@ static void virtio_pmem_pci_fill_device_info(const MemoryDeviceState *md, DeviceState *dev = DEVICE(md); if (dev->id) { - vi->has_id = true; vi->id = g_strdup(dev->id); } @@ -90,8 +89,6 @@ static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_pmem_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_PMEM; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index 5419dca75e2c..a1abfe0e1b1c 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "hw/virtio/virtio-pmem.h" @@ -123,8 +122,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp) } host_memory_backend_set_mapped(pmem->memdev, true); - virtio_init(vdev, TYPE_VIRTIO_PMEM, VIRTIO_ID_PMEM, - sizeof(struct virtio_pmem_config)); + virtio_init(vdev, VIRTIO_ID_PMEM, sizeof(struct virtio_pmem_config)); pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush); } diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c new file mode 100644 index 000000000000..e4d4bece2d70 --- /dev/null +++ b/hw/virtio/virtio-qmp.c @@ -0,0 +1,849 @@ +/* + * Virtio QMP helpers + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "virtio-qmp.h" + +#include "qapi/error.h" +#include "qapi/qapi-commands-virtio.h" +#include "qapi/qapi-commands-qom.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qjson.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 + +#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 const 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 const 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 const 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 */ +#ifdef CONFIG_VIRTIO_BLK +static const 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, "" } +}; +#endif + +/* virtio-serial features mapping */ +#ifdef CONFIG_VIRTIO_SERIAL +static const 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, "" } +}; +#endif + +/* virtio-gpu features mapping */ +#ifdef CONFIG_VIRTIO_GPU +static const 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, "" } +}; +#endif + +/* virtio-input features mapping */ +#ifdef CONFIG_VIRTIO_INPUT +static const 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, "" } +}; +#endif + +/* virtio-net features mapping */ +#ifdef CONFIG_VIRTIO_NET +static const 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, "" } +}; +#endif + +/* virtio-scsi features mapping */ +#ifdef CONFIG_VIRTIO_SCSI +static const 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, "" } +}; +#endif + +/* virtio/vhost-user-fs features mapping */ +#ifdef CONFIG_VHOST_USER_FS +static const 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, "" } +}; +#endif + +/* virtio/vhost-user-i2c features mapping */ +#ifdef CONFIG_VIRTIO_I2C_ADAPTER +static const 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, "" } +}; +#endif + +/* virtio/vhost-vsock features mapping */ +#ifdef CONFIG_VHOST_VSOCK +static const 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, "" } +}; +#endif + +/* virtio-balloon features mapping */ +#ifdef CONFIG_VIRTIO_BALLOON +static const 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, "" } +}; +#endif + +/* virtio-crypto features mapping */ +#ifdef CONFIG_VIRTIO_CRYPTO +static const qmp_virtio_feature_map_t virtio_crypto_feature_map[] = { + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + { -1, "" } +}; +#endif + +/* virtio-iommu features mapping */ +#ifdef CONFIG_VIRTIO_IOMMU +static const 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, "" } +}; +#endif + +/* virtio-mem features mapping */ +#ifdef CONFIG_VIRTIO_MEM +static const 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, "" } +}; +#endif + +/* virtio-rng features mapping */ +#ifdef CONFIG_VIRTIO_RNG +static const 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, "" } +}; +#endif + +#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; \ + }) + +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; +} + +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; +} + +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; +} + +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; +} + +VirtIODevice *qmp_find_virtio_device(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; +} + +VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) +{ + VirtIODevice *vdev; + VirtioStatus *status; + + vdev = qmp_find_virtio_device(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; + + 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 = qmp_find_virtio_device(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; +} diff --git a/hw/virtio/virtio-qmp.h b/hw/virtio/virtio-qmp.h new file mode 100644 index 000000000000..8af5f5e65a1a --- /dev/null +++ b/hw/virtio/virtio-qmp.h @@ -0,0 +1,30 @@ +/* + * Virtio QMP helpers + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_VIRTIO_QMP_H +#define HW_VIRTIO_QMP_H + +#include "qapi/qapi-types-virtio.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/vhost.h" + +#include "qemu/queue.h" + +typedef QTAILQ_HEAD(QmpVirtIODeviceList, VirtIODevice) QmpVirtIODeviceList; + +/* QAPI list of realized VirtIODevices */ +extern QmpVirtIODeviceList virtio_list; + +VirtIODevice *qmp_find_virtio_device(const char *path); +VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap); +VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap); +VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap); + +#endif diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index c1f916268be7..6e76f8b57beb 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -11,8 +11,9 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-rng.h" +#include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu/module.h" #include "qom/object.h" @@ -31,11 +32,23 @@ struct VirtIORngPCI { VirtIORNG vdev; }; +static Property virtio_rng_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); DeviceState *vdev = DEVICE(&vrng->vdev); + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = 2; + } + if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; } @@ -54,6 +67,7 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; + device_class_set_props(dc, virtio_rng_properties); } static void virtio_rng_initfn(Object *obj) diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index cc8e9f775d87..7e12fc03bfcc 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -215,7 +215,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0); + virtio_init(vdev, VIRTIO_ID_RNG, 0); vrng->vq = virtio_add_queue(vdev, 8, handle_input); vrng->quota_remaining = vrng->conf.max_bytes; diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c index 97fab742368a..e8e3442f3828 100644 --- a/hw/virtio/virtio-scsi-pci.c +++ b/hw/virtio/virtio-scsi-pci.c @@ -18,7 +18,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-scsi.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c index 35bcd961c988..cea31adcc4c6 100644 --- a/hw/virtio/virtio-serial-pci.c +++ b/hw/virtio/virtio-serial-pci.c @@ -20,7 +20,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-serial.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VirtIOSerialPCI VirtIOSerialPCI; diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c new file mode 100644 index 000000000000..7ddb22cc5e81 --- /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 9d637e043e6b..f35178f5fcde 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -13,13 +13,16 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" +#include "qapi/qapi-commands-virtio.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/core/cpu.h" #include "hw/virtio/virtio.h" +#include "hw/virtio/vhost.h" #include "migration/qemu-file-types.h" #include "qemu/atomic.h" #include "hw/virtio/virtio-bus.h" @@ -27,7 +30,27 @@ #include "hw/virtio/virtio-access.h" #include "sysemu/dma.h" #include "sysemu/runstate.h" +#include "virtio-qmp.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" + +QmpVirtIODeviceList virtio_list; + +/* + * Maximum size of virtio device config space + */ +#define VHOST_USER_MAX_CONFIG_SIZE 256 /* * The alignment to use between consumer and producer parts of vring. @@ -132,6 +155,56 @@ struct VirtQueue QLIST_ENTRY(VirtQueue) node; }; +const char *virtio_device_names[] = { + [VIRTIO_ID_NET] = "virtio-net", + [VIRTIO_ID_BLOCK] = "virtio-blk", + [VIRTIO_ID_CONSOLE] = "virtio-serial", + [VIRTIO_ID_RNG] = "virtio-rng", + [VIRTIO_ID_BALLOON] = "virtio-balloon", + [VIRTIO_ID_IOMEM] = "virtio-iomem", + [VIRTIO_ID_RPMSG] = "virtio-rpmsg", + [VIRTIO_ID_SCSI] = "virtio-scsi", + [VIRTIO_ID_9P] = "virtio-9p", + [VIRTIO_ID_MAC80211_WLAN] = "virtio-mac-wlan", + [VIRTIO_ID_RPROC_SERIAL] = "virtio-rproc-serial", + [VIRTIO_ID_CAIF] = "virtio-caif", + [VIRTIO_ID_MEMORY_BALLOON] = "virtio-mem-balloon", + [VIRTIO_ID_GPU] = "virtio-gpu", + [VIRTIO_ID_CLOCK] = "virtio-clk", + [VIRTIO_ID_INPUT] = "virtio-input", + [VIRTIO_ID_VSOCK] = "vhost-vsock", + [VIRTIO_ID_CRYPTO] = "virtio-crypto", + [VIRTIO_ID_SIGNAL_DIST] = "virtio-signal", + [VIRTIO_ID_PSTORE] = "virtio-pstore", + [VIRTIO_ID_IOMMU] = "virtio-iommu", + [VIRTIO_ID_MEM] = "virtio-mem", + [VIRTIO_ID_SOUND] = "virtio-sound", + [VIRTIO_ID_FS] = "virtio-user-fs", + [VIRTIO_ID_PMEM] = "virtio-pmem", + [VIRTIO_ID_RPMB] = "virtio-rpmb", + [VIRTIO_ID_MAC80211_HWSIM] = "virtio-mac-hwsim", + [VIRTIO_ID_VIDEO_ENCODER] = "virtio-vid-encoder", + [VIRTIO_ID_VIDEO_DECODER] = "virtio-vid-decoder", + [VIRTIO_ID_SCMI] = "virtio-scmi", + [VIRTIO_ID_NITRO_SEC_MOD] = "virtio-nitro-sec-mod", + [VIRTIO_ID_I2C_ADAPTER] = "vhost-user-i2c", + [VIRTIO_ID_WATCHDOG] = "virtio-watchdog", + [VIRTIO_ID_CAN] = "virtio-can", + [VIRTIO_ID_DMABUF] = "virtio-dmabuf", + [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv", + [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol", + [VIRTIO_ID_BT] = "virtio-bluetooth", + [VIRTIO_ID_GPIO] = "virtio-gpio" +}; + +static const char *virtio_id_to_name(uint16_t device_id) +{ + assert(device_id < G_N_ELEMENTS(virtio_device_names)); + const char *name = virtio_device_names[device_id]; + assert(name != NULL); + return name; +} + /* Called within call_rcu(). */ static void virtio_free_region_cache(VRingMemoryRegionCaches *caches) { @@ -341,6 +414,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) { @@ -1969,6 +2055,58 @@ static enum virtio_device_endian virtio_current_cpu_endian(void) } } +static void __virtio_queue_reset(VirtIODevice *vdev, uint32_t i) +{ + vdev->vq[i].vring.desc = 0; + vdev->vq[i].vring.avail = 0; + vdev->vq[i].vring.used = 0; + vdev->vq[i].last_avail_idx = 0; + vdev->vq[i].shadow_avail_idx = 0; + vdev->vq[i].used_idx = 0; + vdev->vq[i].last_avail_wrap_counter = true; + vdev->vq[i].shadow_avail_wrap_counter = true; + vdev->vq[i].used_wrap_counter = true; + virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); + vdev->vq[i].signalled_used = 0; + vdev->vq[i].signalled_used_valid = false; + vdev->vq[i].notification = true; + vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; + vdev->vq[i].inuse = 0; + virtio_virtqueue_reset_region_cache(&vdev->vq[i]); +} + +void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + + if (k->queue_reset) { + k->queue_reset(vdev, queue_index); + } + + __virtio_queue_reset(vdev, queue_index); +} + +void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + + /* + * TODO: Seabios is currently out of spec and triggering this error. + * So this needs to be fixed in Seabios, then this can + * be re-enabled for new machine types only, and also after + * being converted to LOG_GUEST_ERROR. + * + if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { + error_report("queue_enable is only suppported in devices of virtio " + "1.0 or later."); + } + */ + + if (k->queue_enable) { + k->queue_enable(vdev, queue_index); + } +} + void virtio_reset(void *opaque) { VirtIODevice *vdev = opaque; @@ -2000,211 +2138,7 @@ void virtio_reset(void *opaque) virtio_notify_vector(vdev, vdev->config_vector); for(i = 0; i < VIRTIO_QUEUE_MAX; i++) { - vdev->vq[i].vring.desc = 0; - vdev->vq[i].vring.avail = 0; - vdev->vq[i].vring.used = 0; - vdev->vq[i].last_avail_idx = 0; - vdev->vq[i].shadow_avail_idx = 0; - vdev->vq[i].used_idx = 0; - vdev->vq[i].last_avail_wrap_counter = true; - vdev->vq[i].shadow_avail_wrap_counter = true; - vdev->vq[i].used_wrap_counter = true; - virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); - vdev->vq[i].signalled_used = 0; - vdev->vq[i].signalled_used_valid = false; - vdev->vq[i].notification = true; - vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; - vdev->vq[i].inuse = 0; - virtio_virtqueue_reset_region_cache(&vdev->vq[i]); - } -} - -uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint8_t val; - - if (addr + sizeof(val) > vdev->config_len) { - return (uint32_t)-1; - } - - k->get_config(vdev, vdev->config); - - val = ldub_p(vdev->config + addr); - return val; -} - -uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint16_t val; - - if (addr + sizeof(val) > vdev->config_len) { - return (uint32_t)-1; - } - - k->get_config(vdev, vdev->config); - - val = lduw_p(vdev->config + addr); - return val; -} - -uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint32_t val; - - if (addr + sizeof(val) > vdev->config_len) { - return (uint32_t)-1; - } - - k->get_config(vdev, vdev->config); - - val = ldl_p(vdev->config + addr); - return val; -} - -void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint8_t val = data; - - if (addr + sizeof(val) > vdev->config_len) { - return; - } - - stb_p(vdev->config + addr, val); - - if (k->set_config) { - k->set_config(vdev, vdev->config); - } -} - -void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint16_t val = data; - - if (addr + sizeof(val) > vdev->config_len) { - return; - } - - stw_p(vdev->config + addr, val); - - if (k->set_config) { - k->set_config(vdev, vdev->config); - } -} - -void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint32_t val = data; - - if (addr + sizeof(val) > vdev->config_len) { - return; - } - - stl_p(vdev->config + addr, val); - - if (k->set_config) { - k->set_config(vdev, vdev->config); - } -} - -uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint8_t val; - - if (addr + sizeof(val) > vdev->config_len) { - return (uint32_t)-1; - } - - k->get_config(vdev, vdev->config); - - val = ldub_p(vdev->config + addr); - return val; -} - -uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint16_t val; - - if (addr + sizeof(val) > vdev->config_len) { - return (uint32_t)-1; - } - - k->get_config(vdev, vdev->config); - - val = lduw_le_p(vdev->config + addr); - return val; -} - -uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint32_t val; - - if (addr + sizeof(val) > vdev->config_len) { - return (uint32_t)-1; - } - - k->get_config(vdev, vdev->config); - - val = ldl_le_p(vdev->config + addr); - return val; -} - -void virtio_config_modern_writeb(VirtIODevice *vdev, - uint32_t addr, uint32_t data) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint8_t val = data; - - if (addr + sizeof(val) > vdev->config_len) { - return; - } - - stb_p(vdev->config + addr, val); - - if (k->set_config) { - k->set_config(vdev, vdev->config); - } -} - -void virtio_config_modern_writew(VirtIODevice *vdev, - uint32_t addr, uint32_t data) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint16_t val = data; - - if (addr + sizeof(val) > vdev->config_len) { - return; - } - - stw_le_p(vdev->config + addr, val); - - if (k->set_config) { - k->set_config(vdev, vdev->config); - } -} - -void virtio_config_modern_writel(VirtIODevice *vdev, - uint32_t addr, uint32_t data) -{ - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - uint32_t val = data; - - if (addr + sizeof(val) > vdev->config_len) { - return; - } - - stl_le_p(vdev->config + addr, val); - - if (k->set_config) { - k->set_config(vdev, vdev->config); + __virtio_queue_reset(vdev, i); } } @@ -2930,6 +2864,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. */ @@ -2949,11 +2890,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) { @@ -2961,6 +2903,7 @@ size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes, } } + assert(config_size <= params->max_size); return config_size; } @@ -3207,8 +3150,7 @@ void virtio_instance_init_common(Object *proxy_obj, void *data, qdev_alias_all_properties(vdev, proxy_obj); } -void virtio_init(VirtIODevice *vdev, const char *name, - uint16_t device_id, size_t config_size) +void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size) { BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); @@ -3222,6 +3164,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->start_on_kick = false; vdev->started = false; + vdev->vhost_started = false; vdev->device_id = device_id; vdev->status = 0; qatomic_set(&vdev->isr, 0); @@ -3237,7 +3180,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->vq[i].host_notifier_enabled = false; } - vdev->name = name; + vdev->name = virtio_id_to_name(device_id); vdev->config_len = config_size; if (vdev->config_len) { vdev->config = g_malloc0(config_size); @@ -3471,7 +3414,14 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) virtio_irq(vq); } } +static void virtio_config_guest_notifier_read(EventNotifier *n) +{ + VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + if (event_notifier_test_and_clear(n)) { + virtio_notify_config(vdev); + } +} void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, bool with_irqfd) { @@ -3488,6 +3438,23 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, } } +void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, + bool assign, bool with_irqfd) +{ + EventNotifier *n; + n = &vdev->config_notifier; + if (assign && !with_irqfd) { + event_notifier_set_handler(n, virtio_config_guest_notifier_read); + } else { + event_notifier_set_handler(n, NULL); + } + if (!assign) { + /* Test and clear notifier before closing it,*/ + /* in case poll callback didn't have time to run. */ + virtio_config_guest_notifier_read(n); + } +} + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) { return &vq->guest_notifier; @@ -3534,6 +3501,19 @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) virtio_queue_host_notifier_aio_poll_end); } +/* + * Same as virtio_queue_aio_attach_host_notifier() but without polling. Use + * this for rx virtqueues and similar cases where the virtqueue handler + * function does not pop all elements. When the virtqueue is left non-empty + * polling consumes CPU cycles and should not be used. + */ +void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx) +{ + aio_set_event_notifier(ctx, &vq->host_notifier, true, + virtio_queue_host_notifier_read, + NULL, NULL); +} + void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx) { aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL); @@ -3555,6 +3535,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) return &vq->host_notifier; } +EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) +{ + return &vdev->config_notifier; +} + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) { vq->host_notifier_enabled = enabled; @@ -3635,6 +3620,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) @@ -3649,6 +3635,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; } @@ -3822,6 +3809,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) @@ -3832,6 +3821,206 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev) return virtio_bus_ioeventfd_enabled(vbus); } +VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path, + uint16_t queue, + Error **errp) +{ + VirtIODevice *vdev; + VirtQueueStatus *status; + + vdev = qmp_find_virtio_device(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 = qmp_find_virtio_device(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/meson.build b/hw/watchdog/meson.build index 054c403dea7c..8974b5cf4c8a 100644 --- a/hw/watchdog/meson.build +++ b/hw/watchdog/meson.build @@ -6,3 +6,4 @@ softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c')) softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c')) softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c')) +specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c')) diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c index e49cacd0e207..7aa57a8c514f 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/spapr_watchdog.c b/hw/watchdog/spapr_watchdog.c new file mode 100644 index 000000000000..55ff1f03c1da --- /dev/null +++ b/hw/watchdog/spapr_watchdog.c @@ -0,0 +1,274 @@ +/* + * 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 . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "migration/vmstate.h" +#include "trace.h" + +#include "hw/ppc/spapr.h" + +#define FIELD_BE(reg, field, start, len) \ + FIELD(reg, field, 64 - (start + len), len) + +/* + * Bits 47: "leaveOtherWatchdogsRunningOnTimeout", specified on + * the "Start watchdog" operation, + * 0 - stop out-standing watchdogs on timeout, + * 1 - leave outstanding watchdogs running on timeout + */ +FIELD_BE(PSERIES_WDTF, LEAVE_OTHER, 47, 1) + +/* Bits 48-55: "operation" */ +FIELD_BE(PSERIES_WDTF, OP, 48, 8) +#define PSERIES_WDTF_OP_START 0x1 +#define PSERIES_WDTF_OP_STOP 0x2 +#define PSERIES_WDTF_OP_QUERY 0x3 +#define PSERIES_WDTF_OP_QUERY_LPM 0x4 + +/* Bits 56-63: "timeoutAction" */ +FIELD_BE(PSERIES_WDTF, ACTION, 56, 8) +#define PSERIES_WDTF_ACTION_HARD_POWER_OFF 0x1 +#define PSERIES_WDTF_ACTION_HARD_RESTART 0x2 +#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3 + +FIELD_BE(PSERIES_WDTF, RESERVED, 0, 47) + +/* Special watchdogNumber for the "stop all watchdogs" operation */ +#define PSERIES_WDT_STOP_ALL ((uint64_t)~0) + +/* + * For the "Query watchdog capabilities" operation, a uint64 structure + * defined as: + * Bits 0-15: The minimum supported timeout in milliseconds + * Bits 16-31: The number of watchdogs supported + * Bits 32-63: Reserved + */ +FIELD_BE(PSERIES_WDTQ, MIN_TIMEOUT, 0, 16) +FIELD_BE(PSERIES_WDTQ, NUM, 16, 16) + +/* + * For the "Query watchdog LPM requirement" operation: + * 1 = The given "watchdogNumber" must be stopped prior to suspending + * 2 = The given "watchdogNumber" does not have to be stopped prior to + * suspending + */ +#define PSERIES_WDTQL_STOPPED 1 +#define PSERIES_WDTQL_QUERY_NOT_STOPPED 2 + +#define WDT_MIN_TIMEOUT 1 /* 1ms */ + +static target_ulong watchdog_stop(unsigned watchdogNumber, SpaprWatchdog *w) +{ + target_ulong ret = H_NOOP; + + if (timer_pending(&w->timer)) { + timer_del(&w->timer); + ret = H_SUCCESS; + } + trace_spapr_watchdog_stop(watchdogNumber, ret); + + return ret; +} + +static target_ulong watchdog_stop_all(SpaprMachineState *spapr) +{ + target_ulong ret = H_NOOP; + int i; + + for (i = 1; i <= ARRAY_SIZE(spapr->wds); ++i) { + target_ulong r = watchdog_stop(i, &spapr->wds[i - 1]); + + if (r != H_NOOP && r != H_SUCCESS) { + ret = r; + } + } + + return ret; +} + +static void watchdog_expired(void *pw) +{ + SpaprWatchdog *w = pw; + CPUState *cs; + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + unsigned num = w - spapr->wds; + + g_assert(num < ARRAY_SIZE(spapr->wds)); + trace_spapr_watchdog_expired(num, w->action); + switch (w->action) { + case PSERIES_WDTF_ACTION_HARD_POWER_OFF: + qemu_system_vmstop_request(RUN_STATE_SHUTDOWN); + break; + case PSERIES_WDTF_ACTION_HARD_RESTART: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + break; + case PSERIES_WDTF_ACTION_DUMP_RESTART: + CPU_FOREACH(cs) { + async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL); + } + break; + } + if (!w->leave_others) { + watchdog_stop_all(spapr); + } +} + +static target_ulong h_watchdog(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong ret = H_SUCCESS; + target_ulong flags = args[0]; + target_ulong watchdogNumber = args[1]; /* 1-Based per PAPR */ + target_ulong timeoutInMs = args[2]; + unsigned operation = FIELD_EX64(flags, PSERIES_WDTF, OP); + unsigned timeoutAction = FIELD_EX64(flags, PSERIES_WDTF, ACTION); + SpaprWatchdog *w; + + if (FIELD_EX64(flags, PSERIES_WDTF, RESERVED)) { + return H_PARAMETER; + } + + switch (operation) { + case PSERIES_WDTF_OP_START: + if (watchdogNumber > ARRAY_SIZE(spapr->wds)) { + return H_P2; + } + if (timeoutInMs <= WDT_MIN_TIMEOUT) { + return H_P3; + } + + w = &spapr->wds[watchdogNumber - 1]; + switch (timeoutAction) { + case PSERIES_WDTF_ACTION_HARD_POWER_OFF: + case PSERIES_WDTF_ACTION_HARD_RESTART: + case PSERIES_WDTF_ACTION_DUMP_RESTART: + w->action = timeoutAction; + break; + default: + return H_PARAMETER; + } + w->leave_others = FIELD_EX64(flags, PSERIES_WDTF, LEAVE_OTHER); + timer_mod(&w->timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + timeoutInMs); + trace_spapr_watchdog_start(flags, watchdogNumber, timeoutInMs); + break; + case PSERIES_WDTF_OP_STOP: + if (watchdogNumber == PSERIES_WDT_STOP_ALL) { + ret = watchdog_stop_all(spapr); + } else if (watchdogNumber <= ARRAY_SIZE(spapr->wds)) { + ret = watchdog_stop(watchdogNumber, + &spapr->wds[watchdogNumber - 1]); + } else { + return H_P2; + } + break; + case PSERIES_WDTF_OP_QUERY: + args[0] = FIELD_DP64(0, PSERIES_WDTQ, MIN_TIMEOUT, WDT_MIN_TIMEOUT); + args[0] = FIELD_DP64(args[0], PSERIES_WDTQ, NUM, + ARRAY_SIZE(spapr->wds)); + trace_spapr_watchdog_query(args[0]); + break; + case PSERIES_WDTF_OP_QUERY_LPM: + if (watchdogNumber > ARRAY_SIZE(spapr->wds)) { + return H_P2; + } + args[0] = PSERIES_WDTQL_QUERY_NOT_STOPPED; + trace_spapr_watchdog_query_lpm(args[0]); + break; + default: + return H_PARAMETER; + } + + return ret; +} + +void spapr_watchdog_init(SpaprMachineState *spapr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(spapr->wds); ++i) { + char name[16]; + SpaprWatchdog *w = &spapr->wds[i]; + + snprintf(name, sizeof(name) - 1, "wdt%d", i + 1); + object_initialize_child_with_props(OBJECT(spapr), name, w, + sizeof(SpaprWatchdog), + TYPE_SPAPR_WDT, + &error_fatal, NULL); + qdev_realize(DEVICE(w), NULL, &error_fatal); + } +} + +static bool watchdog_needed(void *opaque) +{ + SpaprWatchdog *w = opaque; + + return timer_pending(&w->timer); +} + +static const VMStateDescription vmstate_wdt = { + .name = "spapr_watchdog", + .version_id = 1, + .minimum_version_id = 1, + .needed = watchdog_needed, + .fields = (VMStateField[]) { + VMSTATE_TIMER(timer, SpaprWatchdog), + VMSTATE_UINT8(action, SpaprWatchdog), + VMSTATE_UINT8(leave_others, SpaprWatchdog), + VMSTATE_END_OF_LIST() + } +}; + +static void spapr_wdt_realize(DeviceState *dev, Error **errp) +{ + SpaprWatchdog *w = SPAPR_WDT(dev); + Object *o = OBJECT(dev); + + timer_init_ms(&w->timer, QEMU_CLOCK_VIRTUAL, watchdog_expired, w); + + object_property_add_uint64_ptr(o, "expire", + (uint64_t *)&w->timer.expire_time, + OBJ_PROP_FLAG_READ); + object_property_add_uint8_ptr(o, "action", &w->action, OBJ_PROP_FLAG_READ); + object_property_add_uint8_ptr(o, "leaveOtherWatchdogsRunningOnTimeout", + &w->leave_others, OBJ_PROP_FLAG_READ); +} + +static void spapr_wdt_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = spapr_wdt_realize; + dc->vmsd = &vmstate_wdt; + dc->user_creatable = false; +} + +static const TypeInfo spapr_wdt_info = { + .name = TYPE_SPAPR_WDT, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SpaprWatchdog), + .class_init = spapr_wdt_class_init, +}; + +static void spapr_watchdog_register_types(void) +{ + spapr_register_hypercall(H_WATCHDOG, h_watchdog); + type_register_static(&spapr_wdt_info); +} + +type_init(spapr_watchdog_register_types) diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events index e7523e22aaf2..54371ae07556 100644 --- a/hw/watchdog/trace-events +++ b/hw/watchdog/trace-events @@ -9,3 +9,14 @@ cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32 # wdt-aspeed.c aspeed_wdt_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" aspeed_wdt_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 + +# spapr_watchdog.c +spapr_watchdog_start(uint64_t flags, uint64_t num, uint64_t timeout) "Flags 0x%" PRIx64 " num=%" PRId64 " %" PRIu64 "ms" +spapr_watchdog_stop(uint64_t num, uint64_t ret) "num=%" PRIu64 " ret=%" PRId64 +spapr_watchdog_query(uint64_t caps) "caps=0x%" PRIx64 +spapr_watchdog_query_lpm(uint64_t caps) "caps=0x%" PRIx64 +spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u" + +# watchdog.c +watchdog_perform_action(unsigned int action) "action=%u" +watchdog_set_action(unsigned int action) "action=%u" diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 1437e6c5b629..955046161bf1 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -30,51 +30,9 @@ #include "sysemu/watchdog.h" #include "hw/nmi.h" #include "qemu/help_option.h" +#include "trace.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) { @@ -86,6 +44,8 @@ WatchdogAction get_watchdog_action(void) */ void watchdog_perform_action(void) { + trace_watchdog_perform_action(watchdog_action); + switch (watchdog_action) { case WATCHDOG_ACTION_RESET: /* same as 'system_reset' in monitor */ qapi_event_send_watchdog(WATCHDOG_ACTION_RESET); @@ -132,4 +92,5 @@ void watchdog_perform_action(void) void qmp_watchdog_set_action(WatchdogAction action, Error **errp) { watchdog_action = action; + trace_watchdog_set_action(watchdog_action); } diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 6aa6f90b664a..d753693a2e44 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, @@ -232,8 +227,8 @@ static void aspeed_wdt_reset(DeviceState *dev) AspeedWDTState *s = ASPEED_WDT(dev); AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); - s->regs[WDT_STATUS] = 0x3EF1480; - s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; + s->regs[WDT_STATUS] = awc->default_status; + s->regs[WDT_RELOAD_VALUE] = awc->default_reload_value; s->regs[WDT_RESTART] = 0; s->regs[WDT_CTRL] = awc->sanitize_ctrl(0); s->regs[WDT_RESET_WIDTH] = 0xFF; @@ -319,6 +314,8 @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data) awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->wdt_reload = aspeed_wdt_reload; awc->sanitize_ctrl = aspeed_2400_sanitize_ctrl; + awc->default_status = 0x03EF1480; + awc->default_reload_value = 0x03EF1480; } static const TypeInfo aspeed_2400_wdt_info = { @@ -355,6 +352,8 @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data) awc->reset_pulse = aspeed_2500_wdt_reset_pulse; awc->wdt_reload = aspeed_wdt_reload_1mhz; awc->sanitize_ctrl = aspeed_2500_sanitize_ctrl; + awc->default_status = 0x014FB180; + awc->default_reload_value = 0x014FB180; } static const TypeInfo aspeed_2500_wdt_info = { @@ -376,6 +375,8 @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data) awc->reset_pulse = aspeed_2500_wdt_reset_pulse; awc->wdt_reload = aspeed_wdt_reload_1mhz; awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl; + awc->default_status = 0x014FB180; + awc->default_reload_value = 0x014FB180; } static const TypeInfo aspeed_2600_wdt_info = { @@ -385,13 +386,36 @@ static const TypeInfo aspeed_2600_wdt_info = { .class_init = aspeed_2600_wdt_class_init, }; +static void aspeed_1030_wdt_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); + + dc->desc = "ASPEED 1030 Watchdog Controller"; + awc->offset = 0x80; + awc->ext_pulse_width_mask = 0xfffff; /* TODO */ + awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1; + awc->reset_pulse = aspeed_2500_wdt_reset_pulse; + awc->wdt_reload = aspeed_wdt_reload_1mhz; + awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl; + awc->default_status = 0x014FB180; + awc->default_reload_value = 0x014FB180; +} + +static const TypeInfo aspeed_1030_wdt_info = { + .name = TYPE_ASPEED_1030_WDT, + .parent = TYPE_ASPEED_WDT, + .instance_size = sizeof(AspeedWDTState), + .class_init = aspeed_1030_wdt_class_init, +}; + 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); type_register_static(&aspeed_2600_wdt_info); + type_register_static(&aspeed_1030_wdt_info); } type_init(wdt_aspeed_register_types) diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index 9e8882a11cfc..76d89fbf7852 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 f99a1c9d294f..54c167cd3583 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -24,7 +24,7 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "sysemu/watchdog.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "migration/vmstate.h" #include "qom/object.h" @@ -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 91d1bdc0da13..b116c3a3aa6c 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 c3128370b5bc..e776a2fbd402 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/meson.build b/hw/xen/meson.build index 076954b89ca3..ae0ace3046b8 100644 --- a/hw/xen/meson.build +++ b/hw/xen/meson.build @@ -8,13 +8,17 @@ softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files( )) xen_specific_ss = ss.source_set() -xen_specific_ss.add(when: 'CONFIG_XEN_PCI_PASSTHROUGH', if_true: files( - 'xen-host-pci-device.c', - 'xen_pt.c', - 'xen_pt_config_init.c', - 'xen_pt_graphics.c', - 'xen_pt_load_rom.c', - 'xen_pt_msi.c', -), if_false: files('xen_pt_stub.c')) +if have_xen_pci_passthrough + xen_specific_ss.add(files( + 'xen-host-pci-device.c', + 'xen_pt.c', + 'xen_pt_config_init.c', + 'xen_pt_graphics.c', + 'xen_pt_load_rom.c', + 'xen_pt_msi.c', + )) +else + xen_specific_ss.add(files('xen_pt_stub.c')) +endif specific_ss.add_all(when: ['CONFIG_XEN', xen], if_true: xen_specific_ss) diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 645a29a5a070..df3f6b9ae00f 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -561,6 +561,7 @@ void xen_device_backend_printf(XenDevice *xendev, const char *key, } } +G_GNUC_SCANF(3, 4) static int xen_device_backend_scanf(XenDevice *xendev, const char *key, const char *fmt, ...) { diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 027190fa4470..0ec7e5218333 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -60,7 +60,6 @@ #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/xen/xen.h" -#include "hw/i386/pc.h" #include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" #include "qemu/range.h" @@ -702,17 +701,6 @@ static const MemoryListener xen_pt_io_listener = { .priority = 10, }; -static void -xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, - XenHostPCIDevice *dev) -{ - uint16_t gpu_dev_id; - PCIDevice *d = &s->dev; - - gpu_dev_id = dev->device_id; - igd_passthrough_isa_bridge_create(pci_get_bus(d), gpu_dev_id); -} - /* destroy. */ static void xen_pt_destroy(PCIDevice *d) { diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 6b8e13cdeed5..cf10fc7bbf9e 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -2,7 +2,6 @@ #define XEN_PT_H #include "hw/xen/xen_common.h" -#include "hw/pci/pci.h" #include "xen-host-pci-device.h" #include "qom/object.h" @@ -43,6 +42,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE) uint32_t igd_read_opregion(XenPCIPassthroughState *s); void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val); +void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, + XenHostPCIDevice *dev); /* function type for config reg */ typedef int (*xen_pt_conf_reg_init) diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index c5c4e943a845..cde898b7442b 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, @@ -1965,11 +1965,12 @@ static void xen_pt_config_reg_init(XenPCIPassthroughState *s, if ((data & host_mask) != (val & host_mask)) { uint32_t new_val; - - /* Mask out host (including past size). */ - new_val = val & host_mask; - /* Merge emulated ones (excluding the non-emulated ones). */ - new_val |= data & host_mask; + /* + * Merge the emulated bits (data) with the host bits (val) + * and mask out the bits past size to enable restoration + * of the proper value for logging below. + */ + new_val = XEN_PT_MERGE_VALUE(val, data, host_mask) & size_mask; /* Leave intact host and emulated values past the size - even though * we do not care as we write per reg->size granularity, but for the * logging below lets have the proper value. */ @@ -2031,12 +2032,16 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp) } } - /* - * By default we will trap up to 0x40 in the cfg space. - * If an intel device is pass through we need to trap 0xfc, - * therefore the size should be 0xff. - */ if (xen_pt_emu_reg_grps[i].grp_id == XEN_PCI_INTEL_OPREGION) { + if (!is_igd_vga_passthrough(&s->real_device) || + s->real_device.vendor_id != PCI_VENDOR_ID_INTEL) { + continue; + } + /* + * By default we will trap up to 0x40 in the cfg space. + * If an intel device is pass through we need to trap 0xfc, + * therefore the size should be 0xff. + */ reg_grp_offset = XEN_PCI_INTEL_OPREGION; } diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index a3bc7e39214b..f303f67c9c18 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -289,3 +289,125 @@ void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val) (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT)); } + +typedef struct { + uint16_t gpu_device_id; + uint16_t pch_device_id; + uint8_t pch_revision_id; +} IGDDeviceIDInfo; + +/* + * In real world different GPU should have different PCH. But actually + * the different PCH DIDs likely map to different PCH SKUs. We do the + * same thing for the GPU. For PCH, the different SKUs are going to be + * all the same silicon design and implementation, just different + * features turn on and off with fuses. The SW interfaces should be + * consistent across all SKUs in a given family (eg LPT). But just same + * features may not be supported. + * + * Most of these different PCH features probably don't matter to the + * Gfx driver, but obviously any difference in display port connections + * will so it should be fine with any PCH in case of passthrough. + * + * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) + * scenarios, 0x9cc3 for BDW(Broadwell). + */ +static const IGDDeviceIDInfo igd_combo_id_infos[] = { + /* HSW Classic */ + {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */ + {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */ + {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */ + {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */ + {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */ + /* HSW ULT */ + {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */ + {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */ + {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */ + {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */ + {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */ + {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */ + /* HSW CRW */ + {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */ + {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */ + /* HSW Server */ + {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */ + /* HSW SRVR */ + {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */ + /* BSW */ + {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */ + {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */ + {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */ + {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */ + {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */ + {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */ + {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */ + {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */ + {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */ + {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */ + {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */ +}; + +static void isa_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->desc = "ISA bridge faked to support IGD PT"; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->class_id = PCI_CLASS_BRIDGE_ISA; +}; + +static const TypeInfo isa_bridge_info = { + .name = "igd-passthrough-isa-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = isa_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void pt_graphics_register_types(void) +{ + type_register_static(&isa_bridge_info); +} +type_init(pt_graphics_register_types) + +void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, + XenHostPCIDevice *dev) +{ + PCIBus *bus = pci_get_bus(&s->dev); + struct PCIDevice *bridge_dev; + int i, num; + const uint16_t gpu_dev_id = dev->device_id; + uint16_t pch_dev_id = 0xffff; + uint8_t pch_rev_id = 0; + + num = ARRAY_SIZE(igd_combo_id_infos); + for (i = 0; i < num; i++) { + if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) { + pch_dev_id = igd_combo_id_infos[i].pch_device_id; + pch_rev_id = igd_combo_id_infos[i].pch_revision_id; + } + } + + if (pch_dev_id == 0xffff) { + return; + } + + /* Currently IGD drivers always need to access PCH by 1f.0. */ + bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0), + "igd-passthrough-isa-bridge"); + + /* + * Note that vendor id is always PCI_VENDOR_ID_INTEL. + */ + if (!bridge_dev) { + fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n"); + return; + } + pci_config_set_device_id(bridge_dev->config, pch_dev_id); + pci_config_set_revision(bridge_dev->config, pch_rev_id); +} diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c index 8ab458922adc..1a5177b35468 100644 --- a/hw/xen/xen_pvdev.c +++ b/hw/xen/xen_pvdev.c @@ -196,37 +196,41 @@ const char *xenbus_strstate(enum xenbus_state state) * 2 == noisy debug messages (logfile only). * 3 == will flood your log (logfile only). */ +G_GNUC_PRINTF(3, 0) +static void xen_pv_output_msg(struct XenLegacyDevice *xendev, + FILE *f, const char *fmt, va_list args) +{ + if (xendev) { + fprintf(f, "xen be: %s: ", xendev->name); + } else { + fprintf(f, "xen be core: "); + } + vfprintf(f, fmt, args); +} + void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level, const char *fmt, ...) { + FILE *logfile; va_list args; - if (xendev) { - if (msg_level > xendev->debug) { - return; - } - qemu_log("xen be: %s: ", xendev->name); - if (msg_level == 0) { - fprintf(stderr, "xen be: %s: ", xendev->name); - } - } else { - if (msg_level > debug) { - return; - } - qemu_log("xen be core: "); - if (msg_level == 0) { - fprintf(stderr, "xen be core: "); - } + if (msg_level > (xendev ? xendev->debug : debug)) { + return; } - va_start(args, fmt); - qemu_log_vprintf(fmt, args); - va_end(args); + + logfile = qemu_log_trylock(); + if (logfile) { + va_start(args, fmt); + xen_pv_output_msg(xendev, logfile, fmt, args); + va_end(args); + qemu_log_unlock(logfile); + } + if (msg_level == 0) { va_start(args, fmt); - vfprintf(stderr, fmt, args); + xen_pv_output_msg(xendev, stderr, fmt, args); va_end(args); } - qemu_log_flush(); } void xen_pv_evtchn_event(void *opaque) diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 8df575a457c8..20c9611d7181 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -63,6 +63,7 @@ static void xen_init_pv(MachineState *machine) if (vga_interface_type == VGA_XENFB) { xen_config_dev_vfb(0, "vnc"); xen_config_dev_vkbd(0); + vga_interface_created = true; } /* configure disks */ diff --git a/hw/xtensa/Kconfig b/hw/xtensa/Kconfig index 0740657ea58f..749d976d771b 100644 --- a/hw/xtensa/Kconfig +++ b/hw/xtensa/Kconfig @@ -12,3 +12,7 @@ config XTENSA_XTFPGA select OPENCORES_ETH select PFLASH_CFI01 select SERIAL + +config XTENSA_RT595 + bool + select DBUS_CLIENT diff --git a/hw/xtensa/meson.build b/hw/xtensa/meson.build index 1d5835df4bf4..fec60a0342fd 100644 --- a/hw/xtensa/meson.build +++ b/hw/xtensa/meson.build @@ -7,5 +7,6 @@ xtensa_ss.add(files( xtensa_ss.add(when: 'CONFIG_XTENSA_SIM', if_true: files('sim.c')) xtensa_ss.add(when: 'CONFIG_XTENSA_VIRT', if_true: files('virt.c')) xtensa_ss.add(when: 'CONFIG_XTENSA_XTFPGA', if_true: files('xtfpga.c')) +xtensa_ss.add(when: 'CONFIG_XTENSA_RT595', if_true: files('xt_rt595.c')) hw_arch += {'xtensa': xtensa_ss} diff --git a/hw/xtensa/mx_pic.c b/hw/xtensa/mx_pic.c index d889f953d17e..8211c993eb74 100644 --- a/hw/xtensa/mx_pic.c +++ b/hw/xtensa/mx_pic.c @@ -334,7 +334,7 @@ void xtensa_mx_pic_reset(void *opaque) mx->miasg = 0; mx->mipipart = 0; for (i = 0; i < mx->n_irq; ++i) { - mx->mirout[i] = 1; + mx->mirout[i] = 0; } for (i = 0; i < mx->n_cpu; ++i) { mx->cpu[i].mipicause = 0; diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c index 2028fe793d9b..946c71cb5b5c 100644 --- a/hw/xtensa/sim.c +++ b/hw/xtensa/sim.c @@ -96,7 +96,7 @@ XtensaCPU *xtensa_sim_common_init(MachineState *machine) void xtensa_sim_load_kernel(XtensaCPU *cpu, MachineState *machine) { const char *kernel_filename = machine->kernel_filename; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN int big_endian = true; #else int big_endian = false; diff --git a/hw/xtensa/xt_rt595.c b/hw/xtensa/xt_rt595.c new file mode 100644 index 000000000000..8e7c84bebda6 --- /dev/null +++ b/hw/xtensa/xt_rt595.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2023, NXP Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "cpu.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/qdev-properties.h" +#include "elf.h" +#include "exec/memory.h" +#include "hw/sysbus.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "xtensa_memory.h" +#include "migration/vmstate.h" +#include "hw/misc/dbus_client.h" + +#define RT595_DSP_SRAM_BANKS 32 + +typedef struct mem_region_t { + uint32_t start; + uint32_t size; + uint32_t irq_num; + uint32_t dma_hwtrg_nr; +} mem_region; + +typedef struct rt595_memmap_tag { + mem_region pflash; + mem_region sram_part[RT595_DSP_SRAM_BANKS]; + mem_region mub; + +} rt595_dsp_memmap_t; + +static rt595_dsp_memmap_t _memmap; + +static void rt595_dsp_mmap_init(void) +{ + // Initialize variables + uint32_t base = 0x00800000; + _memmap.pflash.start = 0; + + // Initialize SRAM partitions + for(int i = 0; i < 8; i++) + { + _memmap.sram_part[i].start = base + (0x8000 * i); + _memmap.sram_part[i].size = 0x8000; // 32K + } + + // Add larger SRAM partitions + base = 0x840000; + for(int i = 8; i < 12; i++) + { + _memmap.sram_part[i].start = base + (0x10000 * (i - 8)); + _memmap.sram_part[i].size = 0x10000; // 64K + } + + base = 0x880000; + for(int i = 12; i < 16; i++) + { + _memmap.sram_part[i].start = base + (0x20000 * (i - 12)); + _memmap.sram_part[i].size = 0x20000; // 128K + } + + base = 0x900000; + for(int i = 16; i < RT595_DSP_SRAM_BANKS; i++) + { + _memmap.sram_part[i].start = base + (0x40000 * (i - 16)); + _memmap.sram_part[i].size = 0x40000; // 256K + } + + _memmap.mub.start = 0x40111000; + _memmap.mub.size = 0x1000; + _memmap.mub.irq_num = 15; + +} + +typedef struct XtRT595BoardDesc { + size_t sram_size; + const hwaddr *io; +} XtRT595BoardDesc; + +typedef struct XtRT595State { + MemoryRegion mub; + uint32_t freq; + MemoryRegion pflash; + MemoryRegion rom; + MemoryRegion sram[RT595_DSP_SRAM_BANKS]; + MemoryRegion sram_data_alias_ns[RT595_DSP_SRAM_BANKS]; +} XtRT595State; + +static void xt_rt595_reset(void *opaque) +{ + return; +} + +static qemu_irq rt595_dsp_irq_init(CPUXtensaState *env, int n) +{ + qemu_irq * ext_irqs = xtensa_get_extints(env); + + return ext_irqs[n]; +} + +static void rt595_dsp_resolve_machine_mub(CPUXtensaState *env) +{ + qemu_irq irq = rt595_dsp_irq_init(env, _memmap.mub.irq_num); + + sysbus_create_simple(TYPE_DBUS_CLIENT_MUB, (hwaddr)_memmap.mub.start, irq); +} + +static XtRT595State *xt_rt595_init(CPUXtensaState *env, uint32_t freq) +{ + XtRT595State *s = g_new(XtRT595State, 1); + MemoryRegion *system_memory = get_system_memory(); + + s->freq = freq; + rt595_dsp_mmap_init(); + for (int i=0; i < RT595_DSP_SRAM_BANKS; i++) { + char *sram_name = g_strdup_printf("sram%d", i); + memory_region_init_ram(&s->sram[i], NULL, sram_name, _memmap.sram_part[i].size, &error_fatal); + memory_region_add_subregion(system_memory, _memmap.sram_part[i].start, &s->sram[i]); + g_free(sram_name); + } + + rt595_dsp_resolve_machine_mub(env); + + return s; +} + +static uint64_t translate_phys_addr(void *opaque, uint64_t addr) +{ + XtensaCPU *cpu = opaque; + + return cpu_get_phys_page_debug(CPU(cpu), addr); +} + +static void xt_init(const XtRT595BoardDesc *board, MachineState *machine) +{ + XtensaCPU *cpu = NULL; + CPUXtensaState *env = NULL; + uint32_t freq = 10000000; + const char *kernel_filename = machine->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + + cpu = XTENSA_CPU(cpu_create(machine->cpu_type)); + env = &cpu->env; + env->sregs[PRID] = 0; + //xtensa_select_static_vectors(env, 0); + qemu_register_reset(xt_rt595_reset, cpu); + /* Need MMU initialized prior to ELF loading, + * so that ELF gets loaded into virtual addresses + */ + cpu_reset(CPU(cpu)); + + /* faking core settigs as xtensa need license */ + if (env) { + XtensaMemory sysram = env->config->sysram; + + sysram.location[0].size = ram_size; + xtensa_create_memory_regions(&env->config->instrom, "xtensa.instrom", + get_system_memory()); + xtensa_create_memory_regions(&env->config->instram, "xtensa.instram", + get_system_memory()); + xtensa_create_memory_regions(&env->config->datarom, "xtensa.datarom", + get_system_memory()); + xtensa_create_memory_regions(&env->config->dataram, "xtensa.dataram", + get_system_memory()); + xtensa_create_memory_regions(&env->config->sysrom, "xtensa.sysrom", + get_system_memory()); + xtensa_create_memory_regions(&sysram, "xtensa.sysram", + get_system_memory()); + } + + xt_rt595_init(env, freq); + + /* Use presence of kernel file name as 'boot from SRAM' switch. */ + if (kernel_filename) { + uint64_t elf_entry; + + int success = load_elf(kernel_filename, NULL, translate_phys_addr, cpu, + &elf_entry, NULL, NULL, NULL, false, EM_XTENSA, 0, 0); + if (success > 0) { + cpu->env.pc = elf_entry; + } + } +} + +static void xtensa_rt595_nommu_init(MachineState *machine) +{ + static const XtRT595BoardDesc rt595_board = { + .sram_size = 0x2000000, + }; + xt_init(&rt595_board, machine); +} + +static void xt_rt595_nommu_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "NXP RT595 EVB (" XTENSA_DEFAULT_CPU_NOMMU_MODEL ")"; + mc->init = xtensa_rt595_nommu_init; + mc->max_cpus = 1; + mc->default_cpu_type = XTENSA_DEFAULT_CPU_NOMMU_TYPE; + mc->default_ram_size = 256 * MiB; +} + +static const TypeInfo xt_rt595_type = { + .name = MACHINE_TYPE_NAME("xt-rt595-nommu"), + .parent = TYPE_MACHINE, + .class_init = xt_rt595_nommu_class_init, +}; + +static void xtensa_rt595_machine_init(void) +{ + type_register_static(&xt_rt595_type); +} + +type_init(xtensa_rt595_machine_init) diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index c1e004e8822d..2a5556a35f50 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -219,7 +219,7 @@ static const MemoryRegionOps xtfpga_io_ops = { static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN int be = 1; #else int be = 0; @@ -430,7 +430,7 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine) } if (entry_point != env->pc) { uint8_t boot[] = { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN 0x60, 0x00, 0x08, /* j 1f */ 0x00, /* .literal_position */ 0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */ diff --git a/include/block/accounting.h b/include/block/accounting.h index 878b4c358150..b9caad60d515 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 b39eefb38d16..dd9a7f6461ef 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,12 +78,14 @@ 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); \ /* Increment wait_->num_waiters before evaluating cond. */ \ qatomic_inc(&wait_->num_waiters); \ + /* Paired with smp_mb in aio_wait_kick(). */ \ + smp_mb(); \ if (ctx_ && in_aio_context_home_thread(ctx_)) { \ while ((cond)) { \ aio_poll(ctx_, true); \ @@ -90,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; \ @@ -103,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/aio.h b/include/block/aio.h index 5634173b1233..0f65a3cc9e51 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -22,6 +22,7 @@ #include "qemu/event_notifier.h" #include "qemu/thread.h" #include "qemu/timer.h" +#include "block/graph-lock.h" typedef struct BlockAIOCB BlockAIOCB; typedef void BlockCompletionFunc(void *opaque, int ret); @@ -127,6 +128,14 @@ struct AioContext { /* Used by AioContext users to protect from multi-threaded access. */ QemuRecMutex lock; + /* + * Keep track of readers and writers of the block layer graph. + * This is essential to avoid performing additions and removal + * of nodes and edges from block graph while some + * other thread is traversing it. + */ + BdrvGraphRWlock *bdrv_graph; + /* The list of registered AIO handlers. Protected by ctx->list_lock. */ AioHandlerList aio_handlers; @@ -192,6 +201,8 @@ struct AioContext { QSLIST_HEAD(, Coroutine) scheduled_coroutines; QEMUBH *co_schedule_bh; + int thread_pool_min; + int thread_pool_max; /* Thread pool for performing work and receiving completion callbacks. * Has its own locking. */ @@ -769,4 +780,12 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch, Error **errp); +/** + * aio_context_set_thread_pool_params: + * @ctx: the aio context + * @min: min number of threads to have readily available in the thread pool + * @min: max number of threads the thread pool can contain + */ +void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min, + int64_t max, Error **errp); #endif diff --git a/include/block/block-common.h b/include/block/block-common.h index fdb7306e78a6..4749c46a5e7e 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -29,20 +29,35 @@ #include "qemu/iov.h" #include "qemu/coroutine.h" #include "block/accounting.h" -#include "block/dirty-bitmap.h" -#include "block/blockjob.h" #include "qemu/hbitmap.h" #include "qemu/transactions.h" /* - * generated_co_wrapper + * co_wrapper{*}: Function specifiers used by block-coroutine-wrapper.py * - * Function specifier, which does nothing but mark functions to be + * Function specifiers, which do nothing but mark functions to be * generated by scripts/block-coroutine-wrapper.py * - * Read more in docs/devel/block-coroutine-wrapper.rst + * Usage: read docs/devel/block-coroutine-wrapper.rst + * + * There are 4 kind of specifiers: + * - co_wrapper functions can be called by only non-coroutine context, because + * they always generate a new coroutine. + * - co_wrapper_mixed functions can be called by both coroutine and + * non-coroutine context. + * - co_wrapper_bdrv_rdlock are co_wrapper functions but automatically take and + * release the graph rdlock when creating a new coroutine + * - co_wrapper_mixed_bdrv_rdlock are co_wrapper_mixed functions but + * automatically take and release the graph rdlock when creating a new + * coroutine. */ -#define generated_co_wrapper +#define co_wrapper +#define co_wrapper_mixed +#define co_wrapper_bdrv_rdlock +#define co_wrapper_mixed_bdrv_rdlock + +#include "block/dirty-bitmap.h" +#include "block/blockjob.h" /* block.c */ typedef struct BlockDriver BlockDriver; @@ -80,6 +95,15 @@ typedef enum { */ BDRV_REQ_MAY_UNMAP = 0x4, + /* + * An optimization hint when all QEMUIOVector elements are within + * previously registered bdrv_register_buf() memory ranges. + * + * Code that replaces the user's QEMUIOVector elements with bounce buffers + * must take care to clear this flag. + */ + BDRV_REQ_REGISTERED_BUF = 0x8, + BDRV_REQ_FUA = 0x10, BDRV_REQ_WRITE_COMPRESSED = 0x20, @@ -313,6 +337,45 @@ enum { * * At least one of DATA, METADATA, FILTERED, or COW must be set for * every child. + * + * + * = Connection with bs->children, bs->file and bs->backing fields = + * + * 1. Filters + * + * Filter drivers have drv->is_filter = true. + * + * Filter node has exactly one FILTERED|PRIMARY child, and may have other + * children which must not have these bits (one example is the + * copy-before-write filter, which also has its target DATA child). + * + * Filter nodes never have COW children. + * + * For most filters, the filtered child is linked in bs->file, bs->backing is + * NULL. For some filters (as an exception), it is the other way around; those + * drivers will have drv->filtered_child_is_backing set to true (see that + * field’s documentation for what drivers this concerns) + * + * 2. "raw" driver (block/raw-format.c) + * + * Formally it's not a filter (drv->is_filter = false) + * + * bs->backing is always NULL + * + * Only has one child, linked in bs->file. Its role is either FILTERED|PRIMARY + * (like filter) or DATA|PRIMARY depending on options. + * + * 3. Other drivers + * + * Don't have any FILTERED children. + * + * May have at most one COW child. In this case it's linked in bs->backing. + * Otherwise bs->backing is NULL. COW child is never PRIMARY. + * + * May have at most one PRIMARY child. In this case it's linked in bs->file. + * Otherwise bs->file is NULL. + * + * May also have some other children that don't have the PRIMARY or COW bit set. */ enum BdrvChildRoleBits { /* diff --git a/include/block/block-copy.h b/include/block/block-copy.h index 68bbd344b2c0..8cea4f9b9086 100644 --- a/include/block/block-copy.h +++ b/include/block/block-copy.h @@ -36,11 +36,14 @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm); void block_copy_state_free(BlockCopyState *s); void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes); -int64_t block_copy_reset_unallocated(BlockCopyState *s, - int64_t offset, int64_t *count); +int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s, + int64_t offset, + int64_t *count); int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes, - bool ignore_ratelimit); + bool ignore_ratelimit, uint64_t timeout_ns, + BlockCopyAsyncCallbackFunc cb, + void *cb_opaque); /* * Run block-copy in a coroutine, create corresponding BlockCopyCallState diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 25bb69bbefb9..b0a3cfe6b876 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -55,9 +55,14 @@ BlockDriver *bdrv_find_protocol(const char *filename, bool allow_protocol_prefix, Error **errp); BlockDriver *bdrv_find_format(const char *format_name); -int bdrv_create(BlockDriver *drv, const char* filename, - QemuOpts *opts, Error **errp); -int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); + +int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename, + QemuOpts *opts, Error **errp); +int co_wrapper bdrv_create(BlockDriver *drv, const char *filename, + QemuOpts *opts, Error **errp); + +int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts, + Error **errp); BlockDriverState *bdrv_new(void); int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, @@ -76,9 +81,15 @@ BdrvChild *bdrv_open_child(const char *filename, const BdrvChildClass *child_class, BdrvChildRole child_role, bool allow_none, Error **errp); +int bdrv_open_file_child(const char *filename, + QDict *options, const char *bdref_key, + BlockDriverState *parent, Error **errp); BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, Error **errp); +int bdrv_set_backing_hd_drained(BlockDriverState *bs, + BlockDriverState *backing_hd, + Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, const char *bdref_key, Error **errp); BlockDriverState *bdrv_open(const char *filename, const char *reference, @@ -141,6 +152,7 @@ int bdrv_inactivate_all(void); int bdrv_flush_all(void); void bdrv_close_all(void); void bdrv_drain_all_begin(void); +void bdrv_drain_all_begin_nopoll(void); void bdrv_drain_all_end(void); void bdrv_drain_all(void); @@ -172,7 +184,6 @@ void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque, bool read_only); -int bdrv_get_flags(BlockDriverState *bs); char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); char *bdrv_dirname(BlockDriverState *bs, Error **errp); @@ -218,17 +229,11 @@ void coroutine_fn bdrv_co_lock(BlockDriverState *bs); */ void coroutine_fn bdrv_co_unlock(BlockDriverState *bs); -void bdrv_set_aio_context_ignore(BlockDriverState *bs, - AioContext *new_context, GSList **ignore); -int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, - Error **errp); -int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, - BdrvChild *ignore_child, Error **errp); -bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, - GSList **ignore, Error **errp); -bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, - GSList **ignore, Error **errp); -AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c); +bool bdrv_child_change_aio_context(BdrvChild *c, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp); +int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx, + BdrvChild *ignore_child, Error **errp); int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); @@ -244,9 +249,15 @@ void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); * Register/unregister a buffer for I/O. For example, VFIO drivers are * interested to know the memory areas that would later be used for I/O, so * that they can prepare IOMMU mapping etc., to get better performance. + * + * Buffers must not overlap and they must be unregistered with the same values that they were registered with. + * + * Returns: true on success, false on failure */ -void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size); -void bdrv_unregister_buf(BlockDriverState *bs, void *host); +bool bdrv_register_buf(BlockDriverState *bs, void *host, size_t size, + Error **errp); +void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size); void bdrv_cancel_in_flight(BlockDriverState *bs); diff --git a/include/block/block-hmp-cmds.h b/include/block/block-hmp-cmds.h index 3412e108ca22..ba0593c440e2 100644 --- a/include/block/block-hmp-cmds.h +++ b/include/block/block-hmp-cmds.h @@ -12,8 +12,8 @@ * the COPYING file in the top-level directory. */ -#ifndef BLOCK_HMP_COMMANDS_H -#define BLOCK_HMP_COMMANDS_H +#ifndef BLOCK_BLOCK_HMP_CMDS_H +#define BLOCK_BLOCK_HMP_CMDS_H void hmp_drive_add(Monitor *mon, const QDict *qdict); @@ -38,7 +38,7 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict); void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); -void hmp_block_resize(Monitor *mon, const QDict *qdict); +void coroutine_fn hmp_block_resize(Monitor *mon, const QDict *qdict); void hmp_block_stream(Monitor *mon, const QDict *qdict); void hmp_block_passwd(Monitor *mon, const QDict *qdict); void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict); diff --git a/include/block/block-io.h b/include/block/block-io.h index 5e3f346806b5..2ed6214909d8 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -39,14 +39,27 @@ * to catch when they are accidentally called by the wrong API. */ -int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, - int64_t bytes, BdrvRequestFlags flags); +int co_wrapper_mixed_bdrv_rdlock +bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes, + BdrvRequestFlags flags); + int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags); -int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes); -int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, - int64_t bytes); -int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, - const void *buf, int64_t bytes); + +int co_wrapper_mixed_bdrv_rdlock +bdrv_pread(BdrvChild *child, int64_t offset, int64_t bytes, void *buf, + BdrvRequestFlags flags); + +int co_wrapper_mixed_bdrv_rdlock +bdrv_pwrite(BdrvChild *child, int64_t offset,int64_t bytes, + const void *buf, BdrvRequestFlags flags); + +int co_wrapper_mixed_bdrv_rdlock +bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes, + const void *buf, BdrvRequestFlags flags); + +int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, + int64_t bytes, const void *buf, + BdrvRequestFlags flags); /* * Efficiently zero a region of the disk image. Note that this is a regular * I/O request like read or write and should have a reasonable size. This @@ -75,24 +88,40 @@ void bdrv_aio_cancel(BlockAIOCB *acb); void bdrv_aio_cancel_async(BlockAIOCB *acb); /* sg packet commands */ -int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); +int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); /* Ensure contents are flushed to disk. */ int coroutine_fn bdrv_co_flush(BlockDriverState *bs); -int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); +int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, + int64_t bytes); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); + +int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs, + BlockDriverState *base, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, + BlockDriverState **file); int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); + +int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, + int64_t bytes, int64_t *pnum); int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum); + +int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, + BlockDriverState *base, + bool include_base, int64_t offset, + int64_t bytes, int64_t *pnum); int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, bool include_base, int64_t offset, int64_t bytes, int64_t *pnum); + int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes); @@ -103,6 +132,7 @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, bool bdrv_is_read_only(BlockDriverState *bs); bool bdrv_is_writable(BlockDriverState *bs); bool bdrv_is_sg(BlockDriverState *bs); +int bdrv_get_flags(BlockDriverState *bs); bool bdrv_is_inserted(BlockDriverState *bs); void bdrv_lock_medium(BlockDriverState *bs, bool locked); void bdrv_eject(BlockDriverState *bs, bool eject_flag); @@ -141,7 +171,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); @@ -162,6 +191,8 @@ void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event); */ AioContext *bdrv_get_aio_context(BlockDriverState *bs); +AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c); + /** * Move the current coroutine to the AioContext of @bs and return the old * AioContext of the coroutine. Increase bs->in_flight so that draining @bs @@ -189,8 +220,14 @@ AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); void bdrv_io_plug(BlockDriverState *bs); void bdrv_io_unplug(BlockDriverState *bs); -bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, - uint32_t granularity, Error **errp); +bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, + const char *name, + uint32_t granularity, + Error **errp); +bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, + const char *name, + uint32_t granularity, + Error **errp); /** * @@ -226,21 +263,6 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, int64_t bytes, BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); -/** - * bdrv_drained_end_no_poll: - * - * Same as bdrv_drained_end(), but do not poll for the subgraph to - * actually become unquiesced. Therefore, no graph changes will occur - * with this function. - * - * *drained_end_counter is incremented for every background operation - * that is scheduled, and will be decremented for every operation once - * it settles. The caller must poll until it reaches 0. The counter - * should be accessed using atomic operations only. - */ -void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); - - /* * "I/O or GS" API functions. These functions can run without * the BQL, but only in one specific iothread/main loop. @@ -269,49 +291,55 @@ void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); cond); }) void bdrv_drain(BlockDriverState *bs); -void coroutine_fn bdrv_co_drain(BlockDriverState *bs); -int generated_co_wrapper +int co_wrapper_mixed_bdrv_rdlock bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); -int generated_co_wrapper bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, - BdrvCheckMode fix); +int co_wrapper_mixed_bdrv_rdlock +bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); /* Invalidate any cached metadata used by image formats */ -int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs, - Error **errp); -int generated_co_wrapper bdrv_flush(BlockDriverState *bs); -int generated_co_wrapper bdrv_pdiscard(BdrvChild *child, int64_t offset, - int64_t bytes); -int generated_co_wrapper +int co_wrapper_mixed_bdrv_rdlock +bdrv_invalidate_cache(BlockDriverState *bs, Error **errp); + +int co_wrapper_mixed_bdrv_rdlock bdrv_flush(BlockDriverState *bs); + +int co_wrapper_mixed_bdrv_rdlock +bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); + +int co_wrapper_mixed_bdrv_rdlock bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); -int generated_co_wrapper + +int co_wrapper_mixed_bdrv_rdlock bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); /** * bdrv_parent_drained_begin_single: * - * Begin a quiesced section for the parent of @c. If @poll is true, wait for - * any pending activity to cease. + * Begin a quiesced section for the parent of @c. + */ +void bdrv_parent_drained_begin_single(BdrvChild *c); + +/** + * bdrv_parent_drained_poll_single: + * + * Returns true if there is any pending activity to cease before @c can be + * called quiesced, false otherwise. */ -void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll); +bool bdrv_parent_drained_poll_single(BdrvChild *c); /** * bdrv_parent_drained_end_single: * * End a quiesced section for the parent of @c. - * - * This polls @bs's AioContext until all scheduled sub-drained_ends - * have settled, which may result in graph changes. */ void bdrv_parent_drained_end_single(BdrvChild *c); /** * bdrv_drain_poll: * - * Poll for pending requests in @bs, its parents (except for @ignore_parent), - * and if @recursive is true its children as well (used for subtree drain). + * Poll for pending requests in @bs and its parents (except for @ignore_parent). * * If @ignore_bds_parents is true, parents that are BlockDriverStates must * ignore the drain request because they will be drained separately (used for @@ -319,8 +347,8 @@ void bdrv_parent_drained_end_single(BdrvChild *c); * * This is part of bdrv_drained_begin. */ -bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, - BdrvChild *ignore_parent, bool ignore_bds_parents); +bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent, + bool ignore_bds_parents); /** * bdrv_drained_begin: @@ -338,31 +366,13 @@ void bdrv_drained_begin(BlockDriverState *bs); * Quiesces a BDS like bdrv_drained_begin(), but does not wait for already * running requests to complete. */ -void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, - BdrvChild *parent, bool ignore_bds_parents); - -/** - * Like bdrv_drained_begin, but recursively begins a quiesced section for - * exclusive access to all child nodes as well. - */ -void bdrv_subtree_drained_begin(BlockDriverState *bs); +void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent); /** * bdrv_drained_end: * * End a quiescent section started by bdrv_drained_begin(). - * - * This polls @bs's AioContext until all scheduled sub-drained_ends - * have settled. On one hand, that may result in graph changes. On - * the other, this requires that the caller either runs in the main - * loop; or that all involved nodes (@bs and all of its parents) are - * in the caller's AioContext. */ void bdrv_drained_end(BlockDriverState *bs); -/** - * End a quiescent section started by bdrv_subtree_drained_begin(). - */ -void bdrv_subtree_drained_end(BlockDriverState *bs); - #endif /* BLOCK_IO_H */ diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 8947abab7605..c34c525fa6ba 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -119,6 +119,20 @@ struct BlockDriver { * (And this filtered child must then be bs->file or bs->backing.) */ bool is_filter; + /* + * Only make sense for filter drivers, for others must be false. + * If true, filtered child is bs->backing. Otherwise it's bs->file. + * Two internal filters use bs->backing as filtered child and has this + * field set to true: mirror_top and commit_top. There also two such test + * filters in tests/unit/test-bdrv-graph-mod.c. + * + * Never create any more such filters! + * + * TODO: imagine how to deprecate this behavior and make all filters work + * similarly using bs->file as filtered child. + */ + bool filtered_child_is_backing; + /* * Set to true if the BlockDriver is a format driver. Format nodes * generally do not expect their children to be other format nodes @@ -433,9 +447,12 @@ struct BlockDriver { * that it can do IOMMU mapping with VFIO etc., in order to get better * performance. In the case of VFIO drivers, this callback is used to do * DMA mapping for hot buffers. + * + * Returns: true on success, false on failure */ - void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size); - void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); + bool (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size, + Error **errp); + void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host, size_t size); /* * This field is modified only under the BQL, and is part of @@ -624,8 +641,8 @@ struct BlockDriver { /* * Invalidate any cached meta-data. */ - void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs, - Error **errp); + void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_invalidate_cache)( + BlockDriverState *bs, Error **errp); /* * Flushes all data for all layers by calling bdrv_co_flush for underlying @@ -684,12 +701,11 @@ struct BlockDriver { Error **errp); BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs); - int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs, - QEMUIOVector *qiov, - int64_t pos); - int coroutine_fn (*bdrv_load_vmstate)(BlockDriverState *bs, - QEMUIOVector *qiov, - int64_t pos); + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_save_vmstate)( + BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); + + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_load_vmstate)( + BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); /* removable device specific */ bool (*bdrv_is_inserted)(BlockDriverState *bs); @@ -707,9 +723,8 @@ struct BlockDriver { * Returns 0 for completed check, -errno for internal errors. * The check results are stored in result. */ - int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs, - BdrvCheckResult *result, - BdrvCheckMode fix); + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_check)( + BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix); void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); @@ -718,26 +733,26 @@ struct BlockDriver { void (*bdrv_io_unplug)(BlockDriverState *bs); /** - * bdrv_co_drain_begin is called if implemented in the beginning of a + * bdrv_drain_begin is called if implemented in the beginning of a * drain operation to drain and stop any internal sources of requests in * the driver. - * bdrv_co_drain_end is called if implemented at the end of the drain. + * bdrv_drain_end is called if implemented at the end of the drain. * * They should be used by the driver to e.g. manage scheduled I/O * requests, or toggle an internal state. After the end of the drain new * requests will continue normally. + * + * Implementations of both functions must not call aio_poll(). */ - void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs); - void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); + void (*bdrv_drain_begin)(BlockDriverState *bs); + void (*bdrv_drain_end)(BlockDriverState *bs); bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); - bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, - const char *name, - uint32_t granularity, - Error **errp); - int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs, - const char *name, - Error **errp); + bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)( + BlockDriverState *bs, const char *name, uint32_t granularity, + Error **errp); + int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)( + BlockDriverState *bs, const char *name, Error **errp); }; static inline bool block_driver_can_compress(BlockDriver *drv) @@ -881,8 +896,8 @@ struct BdrvChildClass { void (*activate)(BdrvChild *child, Error **errp); int (*inactivate)(BdrvChild *child); - void (*attach)(BdrvChild *child); - void (*detach)(BdrvChild *child); + void GRAPH_WRLOCK_PTR (*attach)(BdrvChild *child); + void GRAPH_WRLOCK_PTR (*detach)(BdrvChild *child); /* * Notifies the parent that the filename of its child has changed (e.g. @@ -892,11 +907,9 @@ struct BdrvChildClass { int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, const char *filename, Error **errp); - bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, - GSList **ignore, Error **errp); - void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); - - AioContext *(*get_parent_aio_context)(BdrvChild *child); + bool (*change_aio_ctx)(BdrvChild *child, AioContext *ctx, + GHashTable *visited, Transaction *tran, + Error **errp); /* * I/O API functions. These functions are thread-safe. @@ -914,6 +927,8 @@ struct BdrvChildClass { */ const char *(*get_name)(BdrvChild *child); + AioContext *(*get_parent_aio_context)(BdrvChild *child); + /* * If this pair of functions is implemented, the parent doesn't issue new * requests after returning from .drained_begin() until .drained_end() is @@ -922,15 +937,11 @@ struct BdrvChildClass { * These functions must not change the graph (and therefore also must not * call aio_poll(), which could change the graph indirectly). * - * If drained_end() schedules background operations, it must atomically - * increment *drained_end_counter for each such operation and atomically - * decrement it once the operation has settled. - * * Note that this can be nested. If drained_begin() was called twice, new * I/O is allowed only after drained_end() was called twice, too. */ void (*drained_begin)(BdrvChild *child); - void (*drained_end)(BdrvChild *child, int *drained_end_counter); + void (*drained_end)(BdrvChild *child); /* * Returns whether the parent has pending requests for the child. This @@ -967,13 +978,13 @@ struct BdrvChild { bool frozen; /* - * How many times the parent of this child has been drained + * True if the parent of this child has been drained by this BdrvChild * (through klass->drained_*). - * Usually, this is equal to bs->quiesce_counter (potentially - * reduced by bdrv_drain_all_count). It may differ while the + * + * It is generally true if bs->quiesce_counter > 0. It may differ while the * child is entering or leaving a drained section. */ - int parent_quiesce_counter; + bool quiesced_parent; QLIST_ENTRY(BdrvChild) next; QLIST_ENTRY(BdrvChild) next_parent; @@ -1042,16 +1053,13 @@ struct BlockDriverState { QDict *full_open_options; char exact_filename[PATH_MAX]; - BdrvChild *backing; - BdrvChild *file; - /* I/O Limits */ BlockLimits bl; /* * Flags honored during pread */ - unsigned int supported_read_flags; + BdrvRequestFlags supported_read_flags; /* * Flags honored during pwrite (so far: BDRV_REQ_FUA, * BDRV_REQ_WRITE_UNCHANGED). @@ -1069,12 +1077,12 @@ struct BlockDriverState { * flag), or they have to explicitly take the WRITE permission for * their children. */ - unsigned int supported_write_flags; + BdrvRequestFlags supported_write_flags; /* * Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA, * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */ - unsigned int supported_zero_flags; + BdrvRequestFlags supported_zero_flags; /* * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE). * @@ -1082,7 +1090,7 @@ struct BlockDriverState { * that any added space reads as all zeros. If this can't be guaranteed, * the operation must fail. */ - unsigned int supported_truncate_flags; + BdrvRequestFlags supported_truncate_flags; /* the following member gives a name to every node on the bs graph. */ char node_name[32]; @@ -1103,7 +1111,19 @@ struct BlockDriverState { * parent node of this node. */ BlockDriverState *inherits_from; + + /* + * @backing and @file are some of @children or NULL. All these three fields + * (@file, @backing and @children) are modified only in + * bdrv_child_cb_attach() and bdrv_child_cb_detach(). + * + * See also comment in include/block/block.h, to learn how backing and file + * are connected with BdrvChildRole. + */ QLIST_HEAD(, BdrvChild) children; + BdrvChild *backing; + BdrvChild *file; + QLIST_HEAD(, BdrvChild) parents; QDict *options; @@ -1162,7 +1182,6 @@ struct BlockDriverState { /* Accessed with atomic ops. */ int quiesce_counter; - int recursive_quiesce_counter; unsigned int write_gen; /* Current data generation */ @@ -1230,7 +1249,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child) } int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp); -int get_tmp_filename(char *filename, int size); +char *create_tmp_file(Error **errp); void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, QDict *options); diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h index 0f21b0570b1b..2f0993f6e9ca 100644 --- a/include/block/block_int-global-state.h +++ b/include/block/block_int-global-state.h @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #ifndef BLOCK_INT_GLOBAL_STATE_H #define BLOCK_INT_GLOBAL_STATE_H @@ -262,7 +263,7 @@ BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, BlockDriverState **pbs, Error **errp); BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bms, + BlockDirtyBitmapOrStrList *bms, HBitmap **backup, Error **errp); BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, bool release, @@ -309,21 +310,4 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, */ void bdrv_drain_all_end_quiesce(BlockDriverState *bs); -/** - * Make sure that the function is running under both drain and BQL. - * The latter protects from concurrent writings - * from the GS API, while the former prevents concurrent reads - * from I/O. - */ -static inline void assert_bdrv_graph_writable(BlockDriverState *bs) -{ - /* - * TODO: this function is incomplete. Because the users of this - * assert lack the necessary drains, check only for BQL. - * Once the necessary drains are added, - * assert also for qatomic_read(&bs->quiesce_counter) > 0 - */ - assert(qemu_in_main_thread()); -} - -#endif /* BLOCK_INT_GLOBAL_STATE */ +#endif /* BLOCK_INT_GLOBAL_STATE_H */ diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index bb454200e512..8bc061ebb895 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -56,7 +56,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, - int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) + int64_t offset, int64_t bytes, void *buf, BdrvRequestFlags flags) { QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); IO_CODE(); @@ -65,7 +65,7 @@ static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, } static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, - int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags) + int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags) { QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); IO_CODE(); @@ -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); @@ -102,7 +102,7 @@ bool blk_dev_is_tray_open(BlockBackend *blk); void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes); void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out); -bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, +void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, HBitmap **backup, bool lock); @@ -179,16 +179,4 @@ void bdrv_bsc_invalidate_range(BlockDriverState *bs, */ void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes); - -/* - * "I/O or GS" API functions. These functions can run without - * the BQL, but only in one specific iothread/main loop. - * - * See include/block/block-io.h for more information about - * the "I/O or GS" API. - */ - -void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); -void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); - #endif /* BLOCK_INT_IO_H */ diff --git a/include/block/block_int.h b/include/block/block_int.h index 7d50b6bbd13d..b35b0138ed29 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -26,6 +26,7 @@ #include "block_int-global-state.h" #include "block_int-io.h" +#include "block/graph-lock.h" /* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */ diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 6525e16fd53d..03032b2eca76 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/dirty-bitmap.h b/include/block/dirty-bitmap.h index 6528336c4c33..c3700cec762c 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -34,8 +34,14 @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags, Error **errp); void bdrv_release_dirty_bitmap(BdrvDirtyBitmap *bitmap); void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); -int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, - Error **errp); + +int coroutine_fn bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, + const char *name, + Error **errp); +int co_wrapper bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, + const char *name, + Error **errp); + void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap); void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap); diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h new file mode 100644 index 000000000000..4c92cd8edf68 --- /dev/null +++ b/include/block/graph-lock.h @@ -0,0 +1,280 @@ +/* + * Graph lock: rwlock to protect block layer graph manipulations (add/remove + * edges and nodes) + * + * Copyright (c) 2022 Red Hat + * + * 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 GRAPH_LOCK_H +#define GRAPH_LOCK_H + +#include "qemu/osdep.h" +#include "qemu/clang-tsa.h" + +#include "qemu/coroutine.h" + +/** + * Graph Lock API + * This API provides a rwlock used to protect block layer + * graph modifications like edge (BdrvChild) and node (BlockDriverState) + * addition and removal. + * Currently we have 1 writer only, the Main loop, and many + * readers, mostly coroutines running in other AioContext thus other threads. + * + * We distinguish between writer (main loop, under BQL) that modifies the + * graph, and readers (all other coroutines running in various AioContext), + * that go through the graph edges, reading + * BlockDriverState ->parents and->children. + * + * The writer (main loop) has an "exclusive" access, so it first waits for + * current read to finish, and then prevents incoming ones from + * entering while it has the exclusive access. + * + * The readers (coroutines in multiple AioContext) are free to + * access the graph as long the writer is not modifying the graph. + * In case it is, they go in a CoQueue and sleep until the writer + * is done. + * + * If a coroutine changes AioContext, the counter in the original and new + * AioContext are left intact, since the writer does not care where is the + * reader, but only if there is one. + * As a result, some AioContexts might have a negative reader count, to + * balance the positive count of the AioContext that took the lock. + * This also means that when an AioContext is deleted it may have a nonzero + * reader count. In that case we transfer the count to a global shared counter + * so that the writer is always aware of all readers. + */ +typedef struct BdrvGraphRWlock BdrvGraphRWlock; + +/* Dummy lock object to use for Thread Safety Analysis (TSA) */ +typedef struct TSA_CAPABILITY("mutex") BdrvGraphLock { +} BdrvGraphLock; + +extern BdrvGraphLock graph_lock; + +/* + * clang doesn't check consistency in locking annotations between forward + * declarations and the function definition. Having the annotation on the + * definition, but not the declaration in a header file, may give the reader + * a false sense of security because the condition actually remains unchecked + * for callers in other source files. + * + * Therefore, as a convention, for public functions, GRAPH_RDLOCK and + * GRAPH_WRLOCK annotations should be present only in the header file. + */ +#define GRAPH_WRLOCK TSA_REQUIRES(graph_lock) +#define GRAPH_RDLOCK TSA_REQUIRES_SHARED(graph_lock) + +/* + * TSA annotations are not part of function types, so checks are defeated when + * using a function pointer. As a workaround, annotate function pointers with + * this macro that will require that the lock is at least taken while reading + * the pointer. In most cases this is equivalent to actually protecting the + * function call. + */ +#define GRAPH_RDLOCK_PTR TSA_GUARDED_BY(graph_lock) +#define GRAPH_WRLOCK_PTR TSA_GUARDED_BY(graph_lock) + +/* + * register_aiocontext: + * Add AioContext @ctx to the list of AioContext. + * This list is used to obtain the total number of readers + * currently running the graph. + */ +void register_aiocontext(AioContext *ctx); + +/* + * unregister_aiocontext: + * Removes AioContext @ctx to the list of AioContext. + */ +void unregister_aiocontext(AioContext *ctx); + +/* + * bdrv_graph_wrlock: + * Start an exclusive write operation to modify the graph. This means we are + * adding or removing an edge or a node in the block layer graph. Nobody else + * is allowed to access the graph. + * + * Must only be called from outside bdrv_graph_co_rdlock. + * + * The wrlock can only be taken from the main loop, with BQL held, as only the + * main loop is allowed to modify the graph. + * + * This function polls. Callers must not hold the lock of any AioContext other + * than the current one. + */ +void bdrv_graph_wrlock(void) TSA_ACQUIRE(graph_lock) TSA_NO_TSA; + +/* + * bdrv_graph_wrunlock: + * Write finished, reset global has_writer to 0 and restart + * all readers that are waiting. + */ +void bdrv_graph_wrunlock(void) TSA_RELEASE(graph_lock) TSA_NO_TSA; + +/* + * bdrv_graph_co_rdlock: + * Read the bs graph. This usually means traversing all nodes in + * the graph, therefore it can't happen while another thread is + * modifying it. + * Increases the reader counter of the current aiocontext, + * and if has_writer is set, it means that the writer is modifying + * the graph, therefore wait in a coroutine queue. + * The writer will then wake this coroutine once it is done. + * + * This lock should be taken from Iothreads (IO_CODE() class of functions) + * because it signals the writer that there are some + * readers currently running, or waits until the current + * write is finished before continuing. + * Calling this function from the Main Loop with BQL held + * is not necessary, since the Main Loop itself is the only + * writer, thus won't be able to read and write at the same time. + * The only exception to that is when we can't take the lock in the + * function/coroutine itself, and need to delegate the caller (usually main + * loop) to take it and wait that the coroutine ends, so that + * we always signal that a reader is running. + */ +void coroutine_fn TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA +bdrv_graph_co_rdlock(void); + +/* + * bdrv_graph_rdunlock: + * Read terminated, decrease the count of readers in the current aiocontext. + * If the writer is waiting for reads to finish (has_writer == 1), signal + * the writer that we are done via aio_wait_kick() to let it continue. + */ +void coroutine_fn TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA +bdrv_graph_co_rdunlock(void); + +/* + * bdrv_graph_rd{un}lock_main_loop: + * Just a placeholder to mark where the graph rdlock should be taken + * in the main loop. It is just asserting that we are not + * in a coroutine and in GLOBAL_STATE_CODE. + */ +void TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA +bdrv_graph_rdlock_main_loop(void); + +void TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA +bdrv_graph_rdunlock_main_loop(void); + +/* + * assert_bdrv_graph_readable: + * Make sure that the reader is either the main loop, + * or there is at least a reader helding the rdlock. + * In this way an incoming writer is aware of the read and waits. + */ +void GRAPH_RDLOCK assert_bdrv_graph_readable(void); + +/* + * assert_bdrv_graph_writable: + * Make sure that the writer is the main loop and has set @has_writer, + * so that incoming readers will pause. + */ +void GRAPH_WRLOCK assert_bdrv_graph_writable(void); + +/* + * Calling this function tells TSA that we know that the lock is effectively + * taken even though we cannot prove it (yet) with GRAPH_RDLOCK. This can be + * useful in intermediate stages of a conversion to using the GRAPH_RDLOCK + * macro. + */ +static inline void TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA +assume_graph_lock(void) +{ +} + +typedef struct GraphLockable { } GraphLockable; + +/* + * In C, compound literals have the lifetime of an automatic variable. + * In C++ it would be different, but then C++ wouldn't need QemuLockable + * either... + */ +#define GML_OBJ_() (&(GraphLockable) { }) + +/* + * This is not marked as TSA_ACQUIRE() because TSA doesn't understand the + * cleanup attribute and would therefore complain that the graph is never + * unlocked. TSA_ASSERT() makes sure that the following calls know that we + * hold the lock while unlocking is left unchecked. + */ +static inline GraphLockable * TSA_ASSERT(graph_lock) TSA_NO_TSA +graph_lockable_auto_lock(GraphLockable *x) +{ + bdrv_graph_co_rdlock(); + return x; +} + +static inline void TSA_NO_TSA +graph_lockable_auto_unlock(GraphLockable *x) +{ + bdrv_graph_co_rdunlock(); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockable, graph_lockable_auto_unlock) + +#define WITH_GRAPH_RDLOCK_GUARD_(var) \ + for (g_autoptr(GraphLockable) var = graph_lockable_auto_lock(GML_OBJ_()); \ + var; \ + graph_lockable_auto_unlock(var), var = NULL) + +#define WITH_GRAPH_RDLOCK_GUARD() \ + WITH_GRAPH_RDLOCK_GUARD_(glue(graph_lockable_auto, __COUNTER__)) + +#define GRAPH_RDLOCK_GUARD(x) \ + g_autoptr(GraphLockable) \ + glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \ + graph_lockable_auto_lock(GML_OBJ_()) + + +typedef struct GraphLockableMainloop { } GraphLockableMainloop; + +/* + * In C, compound literals have the lifetime of an automatic variable. + * In C++ it would be different, but then C++ wouldn't need QemuLockable + * either... + */ +#define GMLML_OBJ_() (&(GraphLockableMainloop) { }) + +/* + * This is not marked as TSA_ACQUIRE() because TSA doesn't understand the + * cleanup attribute and would therefore complain that the graph is never + * unlocked. TSA_ASSERT() makes sure that the following calls know that we + * hold the lock while unlocking is left unchecked. + */ +static inline GraphLockableMainloop * TSA_ASSERT(graph_lock) TSA_NO_TSA +graph_lockable_auto_lock_mainloop(GraphLockableMainloop *x) +{ + bdrv_graph_rdlock_main_loop(); + return x; +} + +static inline void TSA_NO_TSA +graph_lockable_auto_unlock_mainloop(GraphLockableMainloop *x) +{ + bdrv_graph_rdunlock_main_loop(); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockableMainloop, + graph_lockable_auto_unlock_mainloop) + +#define GRAPH_RDLOCK_GUARD_MAINLOOP(x) \ + g_autoptr(GraphLockableMainloop) \ + glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \ + graph_lockable_auto_lock_mainloop(GMLML_OBJ_()) + +#endif /* GRAPH_LOCK_H */ + diff --git a/include/block/nbd.h b/include/block/nbd.h index a98eb665da04..4ede3b2bd0b2 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2020 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device @@ -344,8 +344,9 @@ void nbd_client_new(QIOChannelSocket *sioc, void nbd_client_get(NBDClient *client); void nbd_client_put(NBDClient *client); -void nbd_server_is_qemu_nbd(bool value); +void nbd_server_is_qemu_nbd(int max_connections); bool nbd_server_is_running(void); +int nbd_server_max_connections(void); void nbd_server_start(SocketAddress *addr, const char *tls_creds, const char *tls_authz, uint32_t max_connections, Error **errp); @@ -423,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/block/nvme.h b/include/block/nvme.h index 3737351cc815..8027b7126bda 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -98,28 +98,28 @@ enum NvmeCapMask { #define NVME_CAP_PMRS(cap) (((cap) >> CAP_PMRS_SHIFT) & CAP_PMRS_MASK) #define NVME_CAP_CMBS(cap) (((cap) >> CAP_CMBS_SHIFT) & CAP_CMBS_MASK) -#define NVME_CAP_SET_MQES(cap, val) (cap |= (uint64_t)(val & CAP_MQES_MASK) \ - << CAP_MQES_SHIFT) -#define NVME_CAP_SET_CQR(cap, val) (cap |= (uint64_t)(val & CAP_CQR_MASK) \ - << CAP_CQR_SHIFT) -#define NVME_CAP_SET_AMS(cap, val) (cap |= (uint64_t)(val & CAP_AMS_MASK) \ - << CAP_AMS_SHIFT) -#define NVME_CAP_SET_TO(cap, val) (cap |= (uint64_t)(val & CAP_TO_MASK) \ - << CAP_TO_SHIFT) -#define NVME_CAP_SET_DSTRD(cap, val) (cap |= (uint64_t)(val & CAP_DSTRD_MASK) \ - << CAP_DSTRD_SHIFT) -#define NVME_CAP_SET_NSSRS(cap, val) (cap |= (uint64_t)(val & CAP_NSSRS_MASK) \ - << CAP_NSSRS_SHIFT) -#define NVME_CAP_SET_CSS(cap, val) (cap |= (uint64_t)(val & CAP_CSS_MASK) \ - << CAP_CSS_SHIFT) -#define NVME_CAP_SET_MPSMIN(cap, val) (cap |= (uint64_t)(val & CAP_MPSMIN_MASK)\ - << CAP_MPSMIN_SHIFT) -#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\ - << CAP_MPSMAX_SHIFT) -#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMRS_MASK) \ - << CAP_PMRS_SHIFT) -#define NVME_CAP_SET_CMBS(cap, val) (cap |= (uint64_t)(val & CAP_CMBS_MASK) \ - << CAP_CMBS_SHIFT) +#define NVME_CAP_SET_MQES(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_MQES_MASK) << CAP_MQES_SHIFT) +#define NVME_CAP_SET_CQR(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_CQR_MASK) << CAP_CQR_SHIFT) +#define NVME_CAP_SET_AMS(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_AMS_MASK) << CAP_AMS_SHIFT) +#define NVME_CAP_SET_TO(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_TO_MASK) << CAP_TO_SHIFT) +#define NVME_CAP_SET_DSTRD(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_DSTRD_MASK) << CAP_DSTRD_SHIFT) +#define NVME_CAP_SET_NSSRS(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_NSSRS_MASK) << CAP_NSSRS_SHIFT) +#define NVME_CAP_SET_CSS(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_CSS_MASK) << CAP_CSS_SHIFT) +#define NVME_CAP_SET_MPSMIN(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_MPSMIN_MASK) << CAP_MPSMIN_SHIFT) +#define NVME_CAP_SET_MPSMAX(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_MPSMAX_MASK) << CAP_MPSMAX_SHIFT) +#define NVME_CAP_SET_PMRS(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_PMRS_MASK) << CAP_PMRS_SHIFT) +#define NVME_CAP_SET_CMBS(cap, val) \ + ((cap) |= (uint64_t)((val) & CAP_CMBS_MASK) << CAP_CMBS_SHIFT) enum NvmeCapCss { NVME_CAP_CSS_NVM = 1 << 0, @@ -595,6 +595,8 @@ enum NvmeAdminCommands { NVME_ADM_CMD_ACTIVATE_FW = 0x10, NVME_ADM_CMD_DOWNLOAD_FW = 0x11, NVME_ADM_CMD_NS_ATTACHMENT = 0x15, + NVME_ADM_CMD_VIRT_MNGMT = 0x1c, + NVME_ADM_CMD_DBBUF_CONFIG = 0x7c, NVME_ADM_CMD_FORMAT_NVM = 0x80, NVME_ADM_CMD_SECURITY_SEND = 0x81, NVME_ADM_CMD_SECURITY_RECV = 0x82, @@ -899,6 +901,10 @@ enum NvmeStatusCodes { NVME_NS_PRIVATE = 0x0119, NVME_NS_NOT_ATTACHED = 0x011a, NVME_NS_CTRL_LIST_INVALID = 0x011c, + NVME_INVALID_CTRL_ID = 0x011f, + NVME_INVALID_SEC_CTRL_STATE = 0x0120, + NVME_INVALID_NUM_RESOURCES = 0x0121, + NVME_INVALID_RESOURCE_ID = 0x0122, NVME_CONFLICTING_ATTRS = 0x0180, NVME_INVALID_PROT_INFO = 0x0181, NVME_WRITE_TO_RO = 0x0182, @@ -1033,6 +1039,8 @@ enum NvmeIdCns { NVME_ID_CNS_NS_PRESENT = 0x11, NVME_ID_CNS_NS_ATTACHED_CTRL_LIST = 0x12, NVME_ID_CNS_CTRL_LIST = 0x13, + NVME_ID_CNS_PRIMARY_CTRL_CAP = 0x14, + NVME_ID_CNS_SECONDARY_CTRL_LIST = 0x15, NVME_ID_CNS_CS_NS_PRESENT_LIST = 0x1a, NVME_ID_CNS_CS_NS_PRESENT = 0x1b, NVME_ID_CNS_IO_COMMAND_SET = 0x1c, @@ -1134,6 +1142,7 @@ enum NvmeIdCtrlOacs { NVME_OACS_FORMAT = 1 << 1, NVME_OACS_FW = 1 << 2, NVME_OACS_NS_MGMT = 1 << 3, + NVME_OACS_DBBUF = 1 << 8, }; enum NvmeIdCtrlOncs { @@ -1553,6 +1562,61 @@ typedef enum NvmeZoneState { NVME_ZONE_STATE_OFFLINE = 0x0f, } NvmeZoneState; +typedef struct QEMU_PACKED NvmePriCtrlCap { + uint16_t cntlid; + uint16_t portid; + uint8_t crt; + uint8_t rsvd5[27]; + uint32_t vqfrt; + uint32_t vqrfa; + uint16_t vqrfap; + uint16_t vqprt; + uint16_t vqfrsm; + uint16_t vqgran; + uint8_t rsvd48[16]; + uint32_t vifrt; + uint32_t virfa; + uint16_t virfap; + uint16_t viprt; + uint16_t vifrsm; + uint16_t vigran; + uint8_t rsvd80[4016]; +} NvmePriCtrlCap; + +typedef enum NvmePriCtrlCapCrt { + NVME_CRT_VQ = 1 << 0, + NVME_CRT_VI = 1 << 1, +} NvmePriCtrlCapCrt; + +typedef struct QEMU_PACKED NvmeSecCtrlEntry { + uint16_t scid; + uint16_t pcid; + uint8_t scs; + uint8_t rsvd5[3]; + uint16_t vfn; + uint16_t nvq; + uint16_t nvi; + uint8_t rsvd14[18]; +} NvmeSecCtrlEntry; + +typedef struct QEMU_PACKED NvmeSecCtrlList { + uint8_t numcntl; + uint8_t rsvd1[31]; + NvmeSecCtrlEntry sec[127]; +} NvmeSecCtrlList; + +typedef enum NvmeVirtMngmtAction { + NVME_VIRT_MNGMT_ACTION_PRM_ALLOC = 0x01, + NVME_VIRT_MNGMT_ACTION_SEC_OFFLINE = 0x07, + NVME_VIRT_MNGMT_ACTION_SEC_ASSIGN = 0x08, + NVME_VIRT_MNGMT_ACTION_SEC_ONLINE = 0x09, +} NvmeVirtMngmtAction; + +typedef enum NvmeVirtualResourceType { + NVME_VIRT_RES_QUEUE = 0x00, + NVME_VIRT_RES_INTERRUPT = 0x01, +} NvmeVirtualResourceType; + static inline void _nvme_check_size(void) { QEMU_BUILD_BUG_ON(sizeof(NvmeBar) != 4096); @@ -1588,5 +1652,8 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4); QEMU_BUILD_BUG_ON(sizeof(NvmeZoneDescr) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeDifTuple) != 16); + QEMU_BUILD_BUG_ON(sizeof(NvmePriCtrlCap) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlEntry) != 32); + QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlList) != 4096); } #endif diff --git a/include/block/qdict.h b/include/block/qdict.h index ced2acfb92a0..b4c28d96a9e5 100644 --- a/include/block/qdict.h +++ b/include/block/qdict.h @@ -12,6 +12,9 @@ #include "qapi/qmp/qdict.h" +QObject *qdict_crumple(const QDict *src, Error **errp); +void qdict_flatten(QDict *qdict); + void qdict_copy_default(QDict *dst, QDict *src, const char *key); void qdict_set_default_str(QDict *dst, const char *key, const char *val); diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h index 7dd7d730a004..2020bcc92df0 100644 --- a/include/block/thread-pool.h +++ b/include/block/thread-pool.h @@ -20,6 +20,8 @@ #include "block/block.h" +#define THREAD_POOL_MAX_THREADS_DEFAULT 64 + typedef int ThreadPoolFunc(void *opaque); typedef struct ThreadPool ThreadPool; @@ -33,5 +35,6 @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func, void *arg); void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg); +void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx); #endif diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h index 6b6e2ceba1d7..0708ca6fa97f 100644 --- a/include/chardev/char-socket.h +++ b/include/chardev/char-socket.h @@ -21,8 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef CHAR_SOCKET_H_ -#define CHAR_SOCKET_H_ + +#ifndef CHAR_SOCKET_H +#define CHAR_SOCKET_H #include "io/channel-socket.h" #include "io/channel-tls.h" @@ -83,4 +84,4 @@ typedef struct SocketChardev SocketChardev; DECLARE_INSTANCE_CHECKER(SocketChardev, SOCKET_CHARDEV, TYPE_CHARDEV_SOCKET) -#endif /* CHAR_SOCKET_H_ */ +#endif /* CHAR_SOCKET_H */ diff --git a/include/chardev/char.h b/include/chardev/char.h index a319b5fdff7f..44cd82e405bf 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/crypto/akcipher.h b/include/crypto/akcipher.h new file mode 100644 index 000000000000..214e58ca47f5 --- /dev/null +++ b/include/crypto/akcipher.h @@ -0,0 +1,179 @@ +/* + * QEMU Crypto asymmetric algorithms + * + * Copyright (c) 2022 Bytedance + * Author: zhenwei pi + * + * 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 QCRYPTO_AKCIPHER_H +#define QCRYPTO_AKCIPHER_H + +#include "qapi/qapi-types-crypto.h" + +typedef struct QCryptoAkCipher QCryptoAkCipher; + +/** + * qcrypto_akcipher_supports: + * @opts: the asymmetric key algorithm and related options + * + * Determine if asymmetric key cipher decribed with @opts is + * supported by the current configured build + * + * Returns: true if it is supported, false otherwise. + */ +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts); + +/** + * qcrypto_akcipher_new: + * @opts: specify the algorithm and the related arguments + * @type: private or public key type + * @key: buffer to store the key + * @key_len: the length of key buffer + * @errp: error pointer + * + * Create akcipher context + * + * Returns: On success, a new QCryptoAkCipher initialized with @opt + * is created and returned, otherwise NULL is returned. + */ + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t key_len, + Error **errp); + +/** + * qcrypto_akcipher_encrypt: + * @akcipher: akcipher context + * @in: plaintext pending to be encrypted + * @in_len: length of plaintext, less or equal to the size reported + * by a call to qcrypto_akcipher_max_plaintext_len() + * @out: buffer to store the ciphertext + * @out_len: length of ciphertext, less or equal to the size reported + * by a call to qcrypto_akcipher_max_ciphertext_len() + * @errp: error pointer + * + * Encrypt @in and write ciphertext into @out + * + * Returns: length of ciphertext if encrypt succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + +/** + * qcrypto_akcipher_decrypt: + * @akcipher: akcipher context + * @in: ciphertext to be decrypted + * @in_len: the length of ciphertext, less or equal to the size reported + * by a call to qcrypto_akcipher_max_ciphertext_len() + * @out: buffer to store the plaintext + * @out_len: length of the plaintext buffer, less or equal to the size + * reported by a call to qcrypto_akcipher_max_plaintext_len() + * @errp: error pointer + * + * Decrypt @in and write plaintext into @out + * + * Returns: length of plaintext if decrypt succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + +/** + * qcrypto_akcipher_sign: + * @akcipher: akcipher context + * @in: data to be signed + * @in_len: the length of data, less or equal to the size reported + * by a call to qcrypto_akcipher_max_dgst_len() + * @out: buffer to store the signature + * @out_len: length of the signature buffer, less or equal to the size + * by a call to qcrypto_akcipher_max_signature_len() + * @errp: error pointer + * + * Generate signature for @in, write into @out + * + * Returns: length of signature if succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + +/** + * qcrypto_akcipher_verify: + * @akcipher: akcipher context + * @in: pointer to the signature + * @in_len: length of signature, ess or equal to the size reported + * by a call to qcrypto_akcipher_max_signature_len() + * @in2: pointer to original data + * @in2_len: the length of original data, less or equal to the size + * by a call to qcrypto_akcipher_max_dgst_len() + * @errp: error pointer + * + * Verify @in and @in2 match or not + * + * Returns: 0 for succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, Error **errp); + +int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher); + +int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher); + +int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher); + +int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher); + +/** + * qcrypto_akcipher_free: + * @akcipher: akcipher context + * + * Free the akcipher context + * + */ +void qcrypto_akcipher_free(QCryptoAkCipher *akcipher); + +/** + * qcrypto_akcipher_export_p8info: + * @opts: the options of the akcipher to be exported. + * @key: the original key of the akcipher to be exported. + * @keylen: length of the 'key' + * @dst: output parameter, if export succeed, *dst is set to the + * PKCS#8 encoded private key, caller MUST free this key with + * g_free after use. + * @dst_len: output parameter, indicates the length of PKCS#8 encoded + * key. + * + * Export the akcipher into DER encoded pkcs#8 private key info, expects + * |key| stores a valid asymmetric PRIVATE key. + * + * Returns: 0 for succeed, otherwise -1 is returned. + */ +int qcrypto_akcipher_export_p8info(const QCryptoAkCipherOptions *opts, + uint8_t *key, size_t keylen, + uint8_t **dst, size_t *dst_len, + Error **errp); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipher, qcrypto_akcipher_free) + +#endif /* QCRYPTO_AKCIPHER_H */ diff --git a/include/crypto/block.h b/include/crypto/block.h index 7a65e8e402a4..4f63a3787277 100644 --- a/include/crypto/block.h +++ b/include/crypto/block.h @@ -29,24 +29,24 @@ typedef struct QCryptoBlock QCryptoBlock; /* See also QCryptoBlockFormat, QCryptoBlockCreateOptions * and QCryptoBlockOpenOptions in qapi/crypto.json */ -typedef ssize_t (*QCryptoBlockReadFunc)(QCryptoBlock *block, - size_t offset, - uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp); +typedef int (*QCryptoBlockReadFunc)(QCryptoBlock *block, + size_t offset, + uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp); -typedef ssize_t (*QCryptoBlockInitFunc)(QCryptoBlock *block, - size_t headerlen, - void *opaque, - Error **errp); +typedef int (*QCryptoBlockInitFunc)(QCryptoBlock *block, + size_t headerlen, + void *opaque, + Error **errp); -typedef ssize_t (*QCryptoBlockWriteFunc)(QCryptoBlock *block, - size_t offset, - const uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp); +typedef int (*QCryptoBlockWriteFunc)(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp); /** * qcrypto_block_has_format: diff --git a/include/crypto/sm4.h b/include/crypto/sm4.h new file mode 100644 index 000000000000..9bd3ebc62e85 --- /dev/null +++ b/include/crypto/sm4.h @@ -0,0 +1,6 @@ +#ifndef QEMU_SM4_H +#define QEMU_SM4_H + +extern const uint8_t sm4_sbox[256]; + +#endif diff --git a/include/crypto/tls-cipher-suites.h b/include/crypto/tls-cipher-suites.h index 7eb1b76122db..3bd2003f32d1 100644 --- a/include/crypto/tls-cipher-suites.h +++ b/include/crypto/tls-cipher-suites.h @@ -8,8 +8,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef QCRYPTO_TLSCIPHERSUITES_H -#define QCRYPTO_TLSCIPHERSUITES_H +#ifndef QCRYPTO_TLS_CIPHER_SUITES_H +#define QCRYPTO_TLS_CIPHER_SUITES_H #include "qom/object.h" #include "crypto/tlscreds.h" @@ -31,4 +31,4 @@ DECLARE_INSTANCE_CHECKER(QCryptoTLSCipherSuites, QCRYPTO_TLS_CIPHER_SUITES, GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, Error **errp); -#endif /* QCRYPTO_TLSCIPHERSUITES_H */ +#endif /* QCRYPTO_TLS_CIPHER_SUITES_H */ diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index fadf6a65ef15..64247ecb11f4 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -253,6 +253,7 @@ enum bfd_architecture #define bfd_mach_rx 0x75 #define bfd_mach_rx_v2 0x76 #define bfd_mach_rx_v3 0x77 + bfd_arch_loongarch, bfd_arch_last }; #define bfd_mach_s390_31 31 @@ -418,7 +419,6 @@ int print_insn_tci(bfd_vma, disassemble_info*); int print_insn_big_mips (bfd_vma, disassemble_info*); int print_insn_little_mips (bfd_vma, disassemble_info*); int print_insn_nanomips (bfd_vma, disassemble_info*); -int print_insn_i386 (bfd_vma, disassemble_info*); int print_insn_m68k (bfd_vma, disassemble_info*); int print_insn_z8001 (bfd_vma, disassemble_info*); int print_insn_z8002 (bfd_vma, disassemble_info*); @@ -429,7 +429,6 @@ int print_insn_h8500 (bfd_vma, disassemble_info*); int print_insn_arm_a64 (bfd_vma, disassemble_info*); int print_insn_alpha (bfd_vma, disassemble_info*); disassembler_ftype arc_get_disassembler (int, int); -int print_insn_arm (bfd_vma, disassemble_info*); int print_insn_sparc (bfd_vma, disassemble_info*); int print_insn_big_a29k (bfd_vma, disassemble_info*); int print_insn_little_a29k (bfd_vma, disassemble_info*); @@ -449,8 +448,6 @@ int print_insn_w65 (bfd_vma, disassemble_info*); int print_insn_d10v (bfd_vma, disassemble_info*); int print_insn_v850 (bfd_vma, disassemble_info*); int print_insn_tic30 (bfd_vma, disassemble_info*); -int print_insn_ppc (bfd_vma, disassemble_info*); -int print_insn_s390 (bfd_vma, disassemble_info*); int print_insn_crisv32 (bfd_vma, disassemble_info*); int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); @@ -462,6 +459,7 @@ int print_insn_riscv64 (bfd_vma, disassemble_info*); int print_insn_riscv128 (bfd_vma, disassemble_info*); int print_insn_rx(bfd_vma, disassemble_info *); int print_insn_hexagon(bfd_vma, disassemble_info *); +int print_insn_loongarch(bfd_vma, disassemble_info *); #ifdef CONFIG_CAPSTONE bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size); diff --git a/include/elf.h b/include/elf.h index 3a4bcb646a18..8bf1e72720d5 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 @@ -1649,6 +1650,8 @@ typedef struct elf64_shdr { #define NT_TASKSTRUCT 4 #define NT_AUXV 6 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_S390_PV_CPU_DATA 0x30e /* s390 protvirt cpu dump data */ +#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */ #define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */ #define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ #define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 (lower half) */ diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index c0f0fab28a1f..2eb11765380c 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -34,13 +34,13 @@ /* some important defines: * - * HOST_WORDS_BIGENDIAN : if defined, the host cpu is big endian and + * HOST_BIG_ENDIAN : whether the host cpu is big endian and * otherwise little endian. * - * TARGET_WORDS_BIGENDIAN : same for target cpu + * TARGET_BIG_ENDIAN : same for the target cpu */ -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN #define BSWAP_NEEDED #endif @@ -120,7 +120,7 @@ static inline void tswap64s(uint64_t *s) /* Target-endianness CPU memory access functions. These fit into the * {ld,st}{type}{sign}{size}{endian}_p naming scheme described in bswap.h. */ -#if defined(TARGET_WORDS_BIGENDIAN) +#if TARGET_BIG_ENDIAN #define lduw_p(p) lduw_be_p(p) #define ldsw_p(p) ldsw_be_p(p) #define ldl_p(p) ldl_be_p(p) @@ -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,31 +277,22 @@ 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); /** - * page_alloc_target_data(address, size) + * page_get_target_data(address) * @address: guest virtual address - * @size: size of data to allocate * - * Allocate @size bytes of out-of-band data to associate with the - * guest page at @address. If the page is not mapped, NULL will - * be returned. If there is existing data associated with @address, - * no new memory will be allocated. + * Return TARGET_PAGE_DATA_SIZE bytes of out-of-band data to associate + * with the guest page at @address, allocating it if necessary. The + * caller should already have verified that the address is valid. * * The memory will be freed when the guest page is deallocated, * e.g. with the munmap system call. */ -void *page_alloc_target_data(target_ulong address, size_t size); - -/** - * page_get_target_data(address) - * @address: guest virtual address - * - * Return any out-of-bound memory assocated with the guest page - * at @address, as per page_alloc_target_data. - */ -void *page_get_target_data(target_ulong address); +void *page_get_target_data(target_ulong address) + __attribute__((returns_nonnull)); #endif CPUArchState *cpu_copy(CPUArchState *env); @@ -419,11 +416,8 @@ static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr) } #ifdef CONFIG_TCG -/* accel/tcg/cpu-exec.c */ -void dump_drift_info(GString *buf); /* accel/tcg/translate-all.c */ void dump_exec_info(GString *buf); -void dump_opcount_info(GString *buf); #endif /* CONFIG_TCG */ #endif /* !CONFIG_USER_ONLY */ diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 50a7d2912e0b..6feaa40ca7b0 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -19,6 +19,9 @@ typedef uint64_t vaddr; #define VADDR_PRIX PRIX64 #define VADDR_MAX UINT64_MAX +void cpu_exec_init_all(void); +void cpu_exec_step_atomic(CPUState *cpu); + /* Using intptr_t ensures that qemu_*_page_mask is sign-extended even * when intptr_t is 32-bit and we are aligning a long long. */ @@ -26,14 +29,16 @@ extern uintptr_t qemu_host_page_size; extern intptr_t qemu_host_page_mask; #define HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_host_page_size) -#define REAL_HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_real_host_page_size) +#define REAL_HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_real_host_page_size()) /* The CPU list lock nests outside page_(un)lock or mmap_(un)lock */ void qemu_init_cpu_list(void); void cpu_list_lock(void); 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); @@ -46,7 +51,7 @@ enum device_endian { DEVICE_LITTLE_ENDIAN, }; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define DEVICE_HOST_ENDIAN DEVICE_BIG_ENDIAN #else #define DEVICE_HOST_ENDIAN DEVICE_LITTLE_ENDIAN @@ -68,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); @@ -86,6 +92,7 @@ void qemu_ram_set_uf_zeroable(RAMBlock *rb); bool qemu_ram_is_migratable(RAMBlock *rb); void qemu_ram_set_migratable(RAMBlock *rb); void qemu_ram_unset_migratable(RAMBlock *rb); +int qemu_ram_get_fd(RAMBlock *rb); size_t qemu_ram_pagesize(RAMBlock *block); size_t qemu_ram_pagesize_largest(void); diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ba3cd32a1ecc..21309cf567a3 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/cpu_ldst.h b/include/exec/cpu_ldst.h index 6adacf89280d..d0c7c0d5fe8e 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -377,7 +377,7 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx, #endif /* defined(CONFIG_USER_ONLY) */ -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN # define cpu_lduw_data cpu_lduw_be_data # define cpu_ldsw_data cpu_ldsw_be_data # define cpu_ldl_data cpu_ldl_be_data diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index d2cb0981f405..25e11b0a8d82 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -24,6 +24,7 @@ #ifdef CONFIG_TCG #include "exec/cpu_ldst.h" #endif +#include "qemu/interval-tree.h" /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -39,29 +40,35 @@ 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); +/** + * cpu_unwind_state_data: + * @cpu: the cpu context + * @host_pc: the host pc within the translation + * @data: output data + * + * Attempt to load the the unwind state for a host pc occurring in + * translated code. If @host_pc is not in translated code, the + * function returns false; otherwise @data is loaded. + * This is the same unwind info as given to restore_state_to_opc. + */ +bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data); /** * cpu_restore_state: - * @cpu: the vCPU state is to be restore to - * @searched_pc: the host PC the fault occurred at - * @will_exit: true if the TB executed will be interrupted after some - cpu adjustments. Required for maintaining the correct - icount valus + * @cpu: the cpu context + * @host_pc: the host pc within the translation * @return: true if state was restored, false otherwise * * Attempt to restore the state for a fault occurring in translated - * code. If the searched_pc is not in translated code no state is + * code. If @host_pc is not in translated code no state is * restored and the function returns false. */ -bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc, bool will_exit); +bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc); -void QEMU_NORETURN cpu_loop_exit_noexc(CPUState *cpu); -void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); -void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); -void QEMU_NORETURN cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); +G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu); +G_NORETURN void cpu_loop_exit(CPUState *cpu); +G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); +G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); /** * cpu_loop_exit_requested: @@ -258,6 +265,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 +464,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 +504,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 */ @@ -492,11 +560,20 @@ struct TranslationBlock { struct tb_tc tc; - /* first and second physical page containing code. The lower bit - of the pointer tells the index in page_next[]. - The list is protected by the TB's page('s) lock(s) */ + /* + * Track tb_page_addr_t intervals that intersect this TB. + * For user-only, the virtual addresses are always contiguous, + * and we use a unified interval tree. For system, we use a + * linked list headed in each PageDesc. Within the list, the lsb + * of the previous pointer tells the index of page_next[], and the + * list is protected by the PageDesc lock(s). + */ +#ifdef CONFIG_USER_ONLY + IntervalTreeNode itree; +#else uintptr_t page_next[2]; tb_page_addr_t page_addr[2]; +#endif /* jmp_lock placed here to fill a 4-byte hole. Its documentation is below */ QemuSpin jmp_lock; @@ -534,27 +611,83 @@ 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) { return qatomic_read(&tb->cflags); } +static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb) +{ +#ifdef CONFIG_USER_ONLY + return tb->itree.start; +#else + return tb->page_addr[0]; +#endif +} + +static inline tb_page_addr_t tb_page_addr1(const TranslationBlock *tb) +{ +#ifdef CONFIG_USER_ONLY + tb_page_addr_t next = tb->itree.last & TARGET_PAGE_MASK; + return next == (tb->itree.start & TARGET_PAGE_MASK) ? -1 : next; +#else + return tb->page_addr[1]; +#endif +} + +static inline void tb_set_page_addr0(TranslationBlock *tb, + tb_page_addr_t addr) +{ +#ifdef CONFIG_USER_ONLY + tb->itree.start = addr; + /* + * To begin, we record an interval of one byte. When the translation + * loop encounters a second page, the interval will be extended to + * include the first byte of the second page, which is sufficient to + * allow tb_page_addr1() above to work properly. The final corrected + * interval will be set by tb_page_add() from tb->size before the + * node is added to the interval tree. + */ + tb->itree.last = addr; +#else + tb->page_addr[0] = addr; +#endif +} + +static inline void tb_set_page_addr1(TranslationBlock *tb, + tb_page_addr_t addr) +{ +#ifdef CONFIG_USER_ONLY + /* Extend the interval to the first byte of the second page. See above. */ + tb->itree.last = addr; +#else + tb->page_addr[1] = addr; +#endif +} + /* current cflags for hashing/comparison */ uint32_t curr_cflags(CPUState *cpu); /* TranslationBlock invalidate API */ #if defined(CONFIG_USER_ONLY) void tb_invalidate_phys_addr(target_ulong addr); -void tb_invalidate_phys_range(target_ulong start, target_ulong end); #else 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_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end); 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. */ @@ -575,14 +708,6 @@ extern __thread uintptr_t tci_tb_ptr; smaller than 4 bytes, so we don't worry about special-casing this. */ #define GETPC_ADJ 2 -#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_DEBUG_TCG) -void assert_no_pages_locked(void); -#else -static inline void assert_no_pages_locked(void) -{ -} -#endif - #if !defined(CONFIG_USER_ONLY) /** @@ -598,44 +723,45 @@ 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. */ -static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, - target_ulong addr) -{ - return addr; -} +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, + void **hostp); /** - * get_page_addr_code_hostp() - user-mode version + * get_page_addr_code() * @env: CPUArchState * @addr: guest virtual address of guest code * - * Returns @addr. + * 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. * - * If @hostp is non-NULL, sets *@hostp to the host address where @addr's content - * is kept. + * Note: this function can trigger an exception. */ -static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, - target_ulong addr, - void **hostp) +static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, + target_ulong addr) { - if (hostp) { - *hostp = g2h_untagged(addr); - } - return addr; + return get_page_addr_code_hostp(env, addr, NULL); } +#if defined(CONFIG_USER_ONLY) +void mmap_lock(void); +void mmap_unlock(void); +bool have_mmap_lock(void); + /** * adjust_signal_pc: * @pc: raw pc from the host signal ucontext_t. @@ -669,9 +795,9 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, * Use the TCGCPUOps hook to record cpu state, do guest operating system * specific things to raise SIGSEGV, and jump to the main cpu loop. */ -void QEMU_NORETURN cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, - MMUAccessType access_type, - bool maperr, uintptr_t ra); +G_NORETURN void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, + MMUAccessType access_type, + bool maperr, uintptr_t ra); /** * cpu_loop_exit_sigbus: @@ -683,44 +809,14 @@ void QEMU_NORETURN cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, * Use the TCGCPUOps hook to record cpu state, do guest operating system * specific things to raise SIGBUS, and jump to the main cpu loop. */ -void QEMU_NORETURN cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, - MMUAccessType access_type, - uintptr_t ra); +G_NORETURN void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, + MMUAccessType access_type, + uintptr_t ra); #else 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/gdbstub.h b/include/exec/gdbstub.h index 89edf94d2860..f667014888ce 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -10,11 +10,71 @@ #define GDB_WATCHPOINT_READ 3 #define GDB_WATCHPOINT_ACCESS 4 +/* For gdb file i/o remote protocol open flags. */ +#define GDB_O_RDONLY 0 +#define GDB_O_WRONLY 1 +#define GDB_O_RDWR 2 +#define GDB_O_APPEND 8 +#define GDB_O_CREAT 0x200 +#define GDB_O_TRUNC 0x400 +#define GDB_O_EXCL 0x800 + +/* For gdb file i/o remote protocol errno values */ +#define GDB_EPERM 1 +#define GDB_ENOENT 2 +#define GDB_EINTR 4 +#define GDB_EBADF 9 +#define GDB_EACCES 13 +#define GDB_EFAULT 14 +#define GDB_EBUSY 16 +#define GDB_EEXIST 17 +#define GDB_ENODEV 19 +#define GDB_ENOTDIR 20 +#define GDB_EISDIR 21 +#define GDB_EINVAL 22 +#define GDB_ENFILE 23 +#define GDB_EMFILE 24 +#define GDB_EFBIG 27 +#define GDB_ENOSPC 28 +#define GDB_ESPIPE 29 +#define GDB_EROFS 30 +#define GDB_ENAMETOOLONG 91 +#define GDB_EUNKNOWN 9999 + +/* For gdb file i/o remote protocol lseek whence. */ +#define GDB_SEEK_SET 0 +#define GDB_SEEK_CUR 1 +#define GDB_SEEK_END 2 + +/* For gdb file i/o stat/fstat. */ +typedef uint32_t gdb_mode_t; +typedef uint32_t gdb_time_t; + +struct gdb_stat { + uint32_t gdb_st_dev; /* device */ + uint32_t gdb_st_ino; /* inode */ + gdb_mode_t gdb_st_mode; /* protection */ + uint32_t gdb_st_nlink; /* number of hard links */ + uint32_t gdb_st_uid; /* user ID of owner */ + uint32_t gdb_st_gid; /* group ID of owner */ + uint32_t gdb_st_rdev; /* device type (if inode device) */ + uint64_t gdb_st_size; /* total size, in bytes */ + uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ + uint64_t gdb_st_blocks; /* number of blocks allocated */ + gdb_time_t gdb_st_atime; /* time of last access */ + gdb_time_t gdb_st_mtime; /* time of last modification */ + gdb_time_t gdb_st_ctime; /* time of last change */ +} QEMU_PACKED; + +struct gdb_timeval { + gdb_time_t tv_sec; /* second */ + uint64_t tv_usec; /* microsecond */ +} QEMU_PACKED; + #ifdef NEED_CPU_H #include "cpu.h" -typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, - target_ulong ret, target_ulong err); +typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err); /** * gdb_do_syscall: @@ -110,7 +170,7 @@ static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi, uint64_t val_lo) { uint64_t to_quad; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN to_quad = tswap64(val_hi); g_byte_array_append(buf, (uint8_t *) &to_quad, 8); to_quad = tswap64(val_lo); diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h index 734af067fee6..bc6698b19f97 100644 --- a/include/exec/helper-head.h +++ b/include/exec/helper-head.h @@ -46,7 +46,7 @@ #define dh_ctype_ptr void * #define dh_ctype_cptr const void * #define dh_ctype_void void -#define dh_ctype_noreturn void QEMU_NORETURN +#define dh_ctype_noreturn G_NORETURN void #define dh_ctype(t) dh_ctype_##t #ifdef NEED_CPU_H @@ -133,6 +133,6 @@ #define DEF_HELPER_7(name, ret, t1, t2, t3, t4, t5, t6, t7) \ DEF_HELPER_FLAGS_7(name, 0, ret, t1, t2, t3, t4, t5, t6, t7) -/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */ +/* MAX_CALL_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */ #endif /* EXEC_HELPER_HEAD_H */ diff --git a/include/exec/log.h b/include/exec/log.h index 3c7fa65ead68..4a7375a45fb5 100644 --- a/include/exec/log.h +++ b/include/exec/log.h @@ -15,15 +15,10 @@ */ static inline void log_cpu_state(CPUState *cpu, int flags) { - QemuLogFile *logfile; - - if (qemu_log_enabled()) { - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - cpu_dump_state(cpu, logfile->fd, flags); - } - rcu_read_unlock(); + FILE *f = qemu_log_trylock(); + if (f) { + cpu_dump_state(cpu, f, flags); + qemu_log_unlock(f); } } @@ -42,43 +37,4 @@ static inline void log_cpu_state_mask(int mask, CPUState *cpu, int flags) } } -#ifdef NEED_CPU_H -/* disas() and target_disas() to qemu_logfile: */ -static inline void log_target_disas(CPUState *cpu, target_ulong start, - target_ulong len) -{ - QemuLogFile *logfile; - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - target_disas(logfile->fd, cpu, start, len); - } - rcu_read_unlock(); -} - -static inline void log_disas(const void *code, unsigned long size) -{ - QemuLogFile *logfile; - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - disas(logfile->fd, code, size); - } - rcu_read_unlock(); -} - -#if defined(CONFIG_USER_ONLY) -/* page_dump() output to the log file: */ -static inline void log_page_dump(const char *operation) -{ - FILE *logfile = qemu_log_lock(); - if (logfile) { - qemu_log("page layout changed following %s\n", operation); - page_dump(logfile); - } - qemu_log_unlock(logfile); -} -#endif -#endif - #endif diff --git a/include/exec/memop.h b/include/exec/memop.h index 2a885f3917b4..25d027434ad5 100644 --- a/include/exec/memop.h +++ b/include/exec/memop.h @@ -28,7 +28,7 @@ typedef enum MemOp { MO_SIGN = 0x08, /* Sign-extended, otherwise zero-extended. */ MO_BSWAP = 0x10, /* Host reverse endian. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN MO_LE = MO_BSWAP, MO_BE = 0, #else @@ -36,7 +36,7 @@ typedef enum MemOp { MO_BE = MO_BSWAP, #endif #ifdef NEED_CPU_H -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN MO_TE = MO_BE, #else MO_TE = MO_LE, diff --git a/include/exec/memopidx.h b/include/exec/memopidx.h index 83bce97874dd..eb7f1591a376 100644 --- a/include/exec/memopidx.h +++ b/include/exec/memopidx.h @@ -9,7 +9,7 @@ */ #ifndef EXEC_MEMOPIDX_H -#define EXEC_MEMOPIDX_H 1 +#define EXEC_MEMOPIDX_H #include "exec/memop.h" diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index 9fcc2af25c88..100c1237ac21 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -38,10 +38,6 @@ void flatview_unref(FlatView *view); extern const MemoryRegionOps unassigned_mem_ops; -bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, - unsigned size, bool is_write, - MemTxAttrs attrs); - void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section); AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv); void address_space_dispatch_compact(AddressSpaceDispatch *d); diff --git a/include/exec/memory.h b/include/exec/memory.h index 4d5997e6bbae..c37ffdbcd1b8 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -69,7 +69,10 @@ static inline void fuzz_dma_read_cb(size_t addr, /* Dirty tracking enabled because measuring dirty rate */ #define GLOBAL_DIRTY_DIRTY_RATE (1U << 1) -#define GLOBAL_DIRTY_MASK (0x3) +/* Dirty tracking enabled because dirty limit */ +#define GLOBAL_DIRTY_LIMIT (1U << 2) + +#define GLOBAL_DIRTY_MASK (0x7) extern unsigned int global_dirty_tracking; @@ -558,7 +561,7 @@ typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); * A #RamDiscardManager coordinates which parts of specific RAM #MemoryRegion * regions are currently populated to be used/accessed by the VM, notifying * after parts were discarded (freeing up memory) and before parts will be - * populated (consuming memory), to be used/acessed by the VM. + * populated (consuming memory), to be used/accessed by the VM. * * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the * #MemoryRegion isn't mapped yet; it cannot change while the #MemoryRegion is @@ -582,7 +585,7 @@ typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); * Listeners are called in multiples of the minimum granularity (unless it * would exceed the registered range) and changes are aligned to the minimum * granularity within the #MemoryRegion. Listeners have to prepare for memory - * becomming discarded in a different granularity than it was populated and the + * becoming discarded in a different granularity than it was populated and the * other way around. */ struct RamDiscardManagerClass { @@ -710,6 +713,10 @@ void ram_discard_manager_register_listener(RamDiscardManager *rdm, void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, RamDiscardListener *rdl); +bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only, + bool *mr_has_discard_manager); + typedef struct CoalescedMemoryRange CoalescedMemoryRange; typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; @@ -1240,7 +1247,7 @@ void memory_region_init_ram_flags_nomigrate(MemoryRegion *mr, Error **errp); /** - * memory_region_init_resizeable_ram: Initialize memory region with resizeable + * memory_region_init_resizeable_ram: Initialize memory region with resizable * RAM. Accesses into the region will * modify memory directly. Only an initial * portion of this RAM is actually used. @@ -1967,7 +1974,7 @@ void memory_region_clear_dirty_bitmap(MemoryRegion *mr, hwaddr start, * querying the same page multiple times, which is especially useful for * display updates where the scanlines often are not page aligned. * - * The dirty bitmap region which gets copyed into the snapshot (and + * The dirty bitmap region which gets copied into the snapshot (and * cleared afterwards) can be larger than requested. The boundaries * are rounded up/down so complete bitmap longs (covering 64 pages on * 64bit hosts) can be copied over into the bitmap snapshot. Which @@ -2435,6 +2442,10 @@ void memory_global_dirty_log_stop(unsigned int flags); void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled); +bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, + unsigned size, bool is_write, + MemTxAttrs attrs); + /** * memory_region_dispatch_read: perform a read directly to the specified * MemoryRegion. @@ -2810,6 +2821,9 @@ MemTxResult address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr, const void *buf, hwaddr len); +int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr); +bool prepare_mmio_access(MemoryRegion *mr); + static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) { if (is_write) { @@ -2931,7 +2945,7 @@ static inline MemOp devend_memop(enum device_endian end) QEMU_BUILD_BUG_ON(DEVICE_HOST_ENDIAN != DEVICE_LITTLE_ENDIAN && DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN /* Swap if non-host endianness or native (target) endianness */ return (end == DEVICE_HOST_ENDIAN) ? 0 : MO_BSWAP; #else diff --git a/include/exec/page-vary.h b/include/exec/page-vary.h index c22a7a742e7c..ebbe9b169b8f 100644 --- a/include/exec/page-vary.h +++ b/include/exec/page-vary.h @@ -31,4 +31,22 @@ extern bool set_preferred_target_page_bits_common(int bits); extern void finalize_target_page_bits_common(int min); #endif +/** + * set_preferred_target_page_bits: + * @bits: number of bits needed to represent an address within the page + * + * Set the preferred target page size (the actual target page + * size may be smaller than any given CPU's preference). + * Returns true on success, false on failure (which can only happen + * if this is called after the system has already finalized its + * choice of page size and the requested page size is smaller than that). + */ +bool set_preferred_target_page_bits(int bits); + +/** + * finalize_target_page_bits: + * Commit the final value set by set_preferred_target_page_bits. + */ +void finalize_target_page_bits(void); + #endif /* EXEC_PAGE_VARY_H */ diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h index f92f16973985..5f5506f1cc2c 100644 --- a/include/exec/plugin-gen.h +++ b/include/exec/plugin-gen.h @@ -12,6 +12,7 @@ #ifndef QEMU_PLUGIN_GEN_H #define QEMU_PLUGIN_GEN_H +#include "exec/cpu_ldst.h" #include "qemu/plugin.h" #include "tcg/tcg.h" @@ -19,7 +20,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 +50,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/poison.h b/include/exec/poison.h index 7c5c02f03f08..f0959bc84ef5 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -14,6 +14,7 @@ #pragma GCC poison TARGET_CRIS #pragma GCC poison TARGET_HEXAGON #pragma GCC poison TARGET_HPPA +#pragma GCC poison TARGET_LOONGARCH64 #pragma GCC poison TARGET_M68K #pragma GCC poison TARGET_MICROBLAZE #pragma GCC poison TARGET_MIPS @@ -38,7 +39,7 @@ #pragma GCC poison TARGET_HAS_BFLT #pragma GCC poison TARGET_NAME #pragma GCC poison TARGET_SUPPORTS_MTTCG -#pragma GCC poison TARGET_WORDS_BIGENDIAN +#pragma GCC poison TARGET_BIG_ENDIAN #pragma GCC poison BSWAP_NEEDED #pragma GCC poison TARGET_LONG_BITS @@ -65,12 +66,11 @@ #pragma GCC poison CPU_INTERRUPT_TGT_INT_2 #pragma GCC poison CONFIG_ALPHA_DIS -#pragma GCC poison CONFIG_ARM_A64_DIS -#pragma GCC poison CONFIG_ARM_DIS #pragma GCC poison CONFIG_CRIS_DIS #pragma GCC poison CONFIG_HPPA_DIS #pragma GCC poison CONFIG_I386_DIS #pragma GCC poison CONFIG_HEXAGON_DIS +#pragma GCC poison CONFIG_LOONGARCH_DIS #pragma GCC poison CONFIG_M68K_DIS #pragma GCC poison CONFIG_MICROBLAZE_DIS #pragma GCC poison CONFIG_MIPS_DIS diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 64fb936c7c74..f4fb6a211175 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -42,7 +42,8 @@ static inline long clear_bmap_size(uint64_t pages, uint8_t shift) } /** - * clear_bmap_set: set clear bitmap for the page range + * clear_bmap_set: set clear bitmap for the page range. Must be with + * bitmap_mutex held. * * @rb: the ramblock to operate on * @start: the start page number @@ -55,12 +56,12 @@ static inline void clear_bmap_set(RAMBlock *rb, uint64_t start, { uint8_t shift = rb->clear_bmap_shift; - bitmap_set_atomic(rb->clear_bmap, start >> shift, - clear_bmap_size(npages, shift)); + bitmap_set(rb->clear_bmap, start >> shift, clear_bmap_size(npages, shift)); } /** - * clear_bmap_test_and_clear: test clear bitmap for the page, clear if set + * clear_bmap_test_and_clear: test clear bitmap for the page, clear if set. + * Must be with bitmap_mutex held. * * @rb: the ramblock to operate on * @page: the page number to check @@ -71,7 +72,7 @@ static inline bool clear_bmap_test_and_clear(RAMBlock *rb, uint64_t page) { uint8_t shift = rb->clear_bmap_shift; - return bitmap_test_and_clear_atomic(rb->clear_bmap, page >> shift, 1); + return bitmap_test_and_clear(rb->clear_bmap, page >> shift, 1); } static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset) @@ -147,8 +148,6 @@ static inline void qemu_ram_block_writeback(RAMBlock *block) #define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1) #define DIRTY_CLIENTS_NOCODE (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE)) -void tb_invalidate_phys_range(ram_addr_t start, ram_addr_t end); - static inline bool cpu_physical_memory_get_dirty(ram_addr_t start, ram_addr_t length, unsigned client) @@ -343,7 +342,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, hwaddr addr; ram_addr_t ram_addr; unsigned long len = (pages + HOST_LONG_BITS - 1) / HOST_LONG_BITS; - unsigned long hpratio = qemu_real_host_page_size / TARGET_PAGE_SIZE; + unsigned long hpratio = qemu_real_host_page_size() / TARGET_PAGE_SIZE; unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); /* start address is aligned at the start of a word? */ diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h index 6cbedf9e0c9a..adc03df59c0f 100644 --- a/include/exec/ramblock.h +++ b/include/exec/ramblock.h @@ -53,6 +53,9 @@ struct RAMBlock { * and split clearing of dirty bitmap on the remote node (e.g., * KVM). The bitmap will be set only when doing global sync. * + * It is only used during src side of ram migration, and it is + * protected by the global ram_state.bitmap_mutex. + * * NOTE: this bitmap is different comparing to the other bitmaps * in that one bit can represent multiple guest pages (which is * decided by the `clear_bmap_shift' variable below). On diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h deleted file mode 100644 index fbcae88f4bab..000000000000 --- a/include/exec/softmmu-semi.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Helper routines to provide target memory access for semihosting - * syscalls in system emulation mode. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ - -#ifndef SOFTMMU_SEMI_H -#define SOFTMMU_SEMI_H - -#include "cpu.h" - -static inline uint64_t softmmu_tget64(CPUArchState *env, target_ulong addr) -{ - uint64_t val; - - cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 8, 0); - return tswap64(val); -} - -static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr) -{ - uint32_t val; - - cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 4, 0); - return tswap32(val); -} - -static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr) -{ - uint8_t val; - - cpu_memory_rw_debug(env_cpu(env), addr, &val, 1, 0); - return val; -} - -#define get_user_u64(arg, p) ({ arg = softmmu_tget64(env, p); 0; }) -#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; }) -#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; }) -#define get_user_ual(arg, p) get_user_u32(arg, p) - -static inline void softmmu_tput64(CPUArchState *env, - target_ulong addr, uint64_t val) -{ - val = tswap64(val); - cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 8, 1); -} - -static inline void softmmu_tput32(CPUArchState *env, - target_ulong addr, uint32_t val) -{ - val = tswap32(val); - cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 4, 1); -} -#define put_user_u64(arg, p) ({ softmmu_tput64(env, p, arg) ; 0; }) -#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; }) -#define put_user_ual(arg, p) put_user_u32(arg, p) - -static void *softmmu_lock_user(CPUArchState *env, - target_ulong addr, target_ulong len, int copy) -{ - uint8_t *p; - /* TODO: Make this something that isn't fixed size. */ - p = malloc(len); - if (p && copy) { - cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0); - } - return p; -} -#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy) -static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr) -{ - char *p; - char *s; - uint8_t c; - /* TODO: Make this something that isn't fixed size. */ - s = p = malloc(1024); - if (!s) { - return NULL; - } - do { - cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0); - addr++; - *(p++) = c; - } while (c); - return s; -} -#define lock_user_string(p) softmmu_lock_user_string(env, p) -static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr, - target_ulong len) -{ - if (len) { - cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1); - } - free(p); -} -#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) - -#endif diff --git a/include/exec/translate-all.h b/include/exec/translate-all.h index 9f646389afea..88602ae8d831 100644 --- a/include/exec/translate-all.h +++ b/include/exec/translate-all.h @@ -23,13 +23,7 @@ /* translate-all.c */ -struct page_collection *page_collection_lock(tb_page_addr_t start, - tb_page_addr_t end); -void page_collection_unlock(struct page_collection *set); -void tb_invalidate_phys_page_fast(struct page_collection *pages, - tb_page_addr_t start, int len, - uintptr_t retaddr); -void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end); +void tb_invalidate_phys_page(tb_page_addr_t addr); void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr); #ifdef CONFIG_USER_ONLY diff --git a/include/exec/translator.h b/include/exec/translator.h index 9bc46eda5950..af2ff95cd527 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; /** @@ -118,16 +121,18 @@ typedef struct TranslatorOps { void (*insn_start)(DisasContextBase *db, CPUState *cpu); void (*translate_insn)(DisasContextBase *db, CPUState *cpu); void (*tb_stop)(DisasContextBase *db, CPUState *cpu); - void (*disas_log)(const DisasContextBase *db, CPUState *cpu); + void (*disas_log)(const DisasContextBase *db, CPUState *cpu, FILE *f); } 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,69 @@ 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; +} + +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; +} + +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; +} -#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) +/** + * translator_fake_ldb - fake instruction load + * @insn8: byte of instruction + * @pc: program counter of instruction + * + * This is a special case helper used where the instruction we are + * about to translate comes from somewhere else (e.g. being + * re-synthesised for s390x "ex"). It ensures we update other areas of + * the translator with details of the executed instruction. + */ -FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD) +static inline void translator_fake_ldb(uint8_t insn8, abi_ptr pc) +{ + plugin_insn_append(pc, &insn8, sizeof(insn8)); +} -#undef GEN_TRANSLATOR_LD -#endif /* EXEC__TRANSLATOR_H */ +/* + * 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-helpers.h b/include/fpu/softfloat-helpers.h index a98d759cd3a5..94cbe073ec5b 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -141,4 +141,4 @@ static inline bool get_default_nan_mode(float_status *status) return status->default_nan_mode; } -#endif /* _SOFTFLOAT_HELPERS_H_ */ +#endif /* SOFTFLOAT_HELPERS_H */ diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 8abd9ab4ec9c..0884ec4ef7a4 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -103,7 +103,7 @@ typedef struct { #define make_floatx80(exp, mant) ((floatx80) { mant, exp }) #define make_floatx80_init(exp, mant) { .low = mant, .high = exp } typedef struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint64_t high, low; #else uint64_t low, high; @@ -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/fpu/softfloat.h b/include/fpu/softfloat.h index d34b2c44d256..3dcf20e3a212 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -95,6 +95,7 @@ typedef enum { #include "fpu/softfloat-types.h" #include "fpu/softfloat-helpers.h" +#include "qemu/int128.h" /*---------------------------------------------------------------------------- | Routine to raise any or all of the software IEC/IEEE floating-point @@ -182,7 +183,9 @@ floatx80 int64_to_floatx80(int64_t, float_status *status); float128 int32_to_float128(int32_t, float_status *status); float128 int64_to_float128(int64_t, float_status *status); +float128 int128_to_float128(Int128, float_status *status); float128 uint64_to_float128(uint64_t, float_status *status); +float128 uint128_to_float128(Int128, float_status *status); /*---------------------------------------------------------------------------- | Software half-precision conversion routines. @@ -1201,9 +1204,13 @@ floatx80 floatx80_default_nan(float_status *status); int32_t float128_to_int32(float128, float_status *status); int32_t float128_to_int32_round_to_zero(float128, float_status *status); int64_t float128_to_int64(float128, float_status *status); +Int128 float128_to_int128(float128, float_status *status); int64_t float128_to_int64_round_to_zero(float128, float_status *status); +Int128 float128_to_int128_round_to_zero(float128, float_status *status); uint64_t float128_to_uint64(float128, float_status *status); +Int128 float128_to_uint128(float128, float_status *status); uint64_t float128_to_uint64_round_to_zero(float128, float_status *status); +Int128 float128_to_uint128_round_to_zero(float128, float_status *status); uint32_t float128_to_uint32(float128, float_status *status); uint32_t float128_to_uint32_round_to_zero(float128, float_status *status); float32 float128_to_float32(float128, float_status *status); diff --git a/include/glib-compat.h b/include/glib-compat.h index 3113a7d2af84..43a562974d80 100644 --- a/include/glib-compat.h +++ b/include/glib-compat.h @@ -147,4 +147,8 @@ qemu_g_test_slow(void) #pragma GCC diagnostic pop +#ifndef G_NORETURN +#define G_NORETURN G_GNUC_NORETURN +#endif + #endif diff --git a/include/hw/acpi/acpi_aml_interface.h b/include/hw/acpi/acpi_aml_interface.h new file mode 100644 index 000000000000..436da069d6b2 --- /dev/null +++ b/include/hw/acpi/acpi_aml_interface.h @@ -0,0 +1,49 @@ +#ifndef ACPI_AML_INTERFACE_H +#define ACPI_AML_INTERFACE_H + +#include "qom/object.h" +#include "hw/acpi/aml-build.h" + +#define TYPE_ACPI_DEV_AML_IF "acpi-dev-aml-interface" +typedef struct AcpiDevAmlIfClass AcpiDevAmlIfClass; +DECLARE_CLASS_CHECKERS(AcpiDevAmlIfClass, ACPI_DEV_AML_IF, TYPE_ACPI_DEV_AML_IF) +#define ACPI_DEV_AML_IF(obj) \ + INTERFACE_CHECK(AcpiDevAmlIf, (obj), TYPE_ACPI_DEV_AML_IF) + +typedef struct AcpiDevAmlIf AcpiDevAmlIf; +typedef void (*dev_aml_fn)(AcpiDevAmlIf *adev, Aml *scope); + +/** + * AcpiDevAmlIfClass: + * + * build_dev_aml: adds device specific AML blob to provided scope + * + * Interface is designed for providing generic callback that builds device + * specific AML blob. + */ +struct AcpiDevAmlIfClass { + /* */ + InterfaceClass parent_class; + + /* */ + dev_aml_fn build_dev_aml; +}; + +static inline dev_aml_fn get_dev_aml_func(DeviceState *dev) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_ACPI_DEV_AML_IF)) { + AcpiDevAmlIfClass *klass = ACPI_DEV_AML_IF_GET_CLASS(dev); + return klass->build_dev_aml; + } + return NULL; +} + +static inline void call_dev_aml_func(DeviceState *dev, Aml *scope) +{ + dev_aml_fn fn = get_dev_aml_func(dev); + if (fn) { + fn(ACPI_DEV_AML_IF(dev), scope); + } +} + +#endif diff --git a/include/hw/acpi/cxl.h b/include/hw/acpi/cxl.h new file mode 100644 index 000000000000..acf441888683 --- /dev/null +++ b/include/hw/acpi/cxl.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * 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 . + */ + +#ifndef HW_ACPI_CXL_H +#define HW_ACPI_CXL_H + +#include "hw/acpi/bios-linker-loader.h" +#include "hw/cxl/cxl.h" + +void cxl_build_cedt(GArray *table_offsets, GArray *table_data, + BIOSLinker *linker, const char *oem_id, + const char *oem_table_id, CXLState *cxl_state); +void build_cxl_osc_method(Aml *dev); + +#endif diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h index b747fe77395f..b2ff663ddcab 100644 --- a/include/hw/acpi/erst.h +++ b/include/hw/acpi/erst.h @@ -11,6 +11,9 @@ #ifndef HW_ACPI_ERST_H #define HW_ACPI_ERST_H +#include "hw/acpi/bios-linker-loader.h" +#include "qom/object.h" + void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, const char *oem_id, const char *oem_table_id); diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index d49217c445fb..d831bbd88969 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -56,8 +56,8 @@ * */ -#ifndef HW_ACPI_GED_H -#define HW_ACPI_GED_H +#ifndef HW_ACPI_GENERIC_EVENT_DEVICE_H +#define HW_ACPI_GENERIC_EVENT_DEVICE_H #include "hw/sysbus.h" #include "hw/acpi/memory_hotplug.h" diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index 7ca92843c6bc..d41866a22993 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -27,7 +27,7 @@ #include "hw/acpi/pcihp.h" #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/acpi_dev_interface.h" -#include "hw/acpi/tco.h" +#include "hw/acpi/ich9_tco.h" #define ACPI_PCIHP_ADDR_ICH9 0x0cc0 diff --git a/include/hw/acpi/ich9_tco.h b/include/hw/acpi/ich9_tco.h new file mode 100644 index 000000000000..c4393caee0fa --- /dev/null +++ b/include/hw/acpi/ich9_tco.h @@ -0,0 +1,82 @@ +/* + * QEMU ICH9 TCO emulation (total cost of ownership) + * + * Copyright (c) 2015 Paulo Alcantara + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_ACPI_TCO_H +#define HW_ACPI_TCO_H + +#include "exec/memory.h" + +/* As per ICH9 spec, the internal timer has an error of ~0.6s on every tick */ +#define TCO_TICK_NSEC 600000000LL + +/* TCO I/O register offsets */ +enum { + TCO_RLD = 0x00, + TCO_DAT_IN = 0x02, + TCO_DAT_OUT = 0x03, + TCO1_STS = 0x04, + TCO2_STS = 0x06, + TCO1_CNT = 0x08, + TCO2_CNT = 0x0a, + TCO_MESSAGE1 = 0x0c, + TCO_MESSAGE2 = 0x0d, + TCO_WDCNT = 0x0e, + SW_IRQ_GEN = 0x10, + TCO_TMR = 0x12, +}; + +/* TCO I/O register control/status bits */ +enum { + SW_TCO_SMI = 1 << 1, + TCO_INT_STS = 1 << 2, + TCO_LOCK = 1 << 12, + TCO_TMR_HLT = 1 << 11, + TCO_TIMEOUT = 1 << 3, + TCO_SECOND_TO_STS = 1 << 1, + TCO_BOOT_STS = 1 << 2, +}; + +/* TCO I/O registers mask bits */ +enum { + TCO_RLD_MASK = 0x3ff, + TCO1_STS_MASK = 0xe870, + TCO2_STS_MASK = 0xfff8, + TCO1_CNT_MASK = 0xfeff, + TCO_TMR_MASK = 0x3ff, +}; + +typedef struct TCOIORegs { + struct { + uint16_t rld; + uint8_t din; + uint8_t dout; + uint16_t sts1; + uint16_t sts2; + uint16_t cnt1; + uint16_t cnt2; + uint8_t msg1; + uint8_t msg2; + uint8_t wdcnt; + uint16_t tmr; + } tco; + uint8_t sw_irq_gen; + + QEMUTimer *tco_timer; + int64_t expire_time; + uint8_t timeouts_no; + + MemoryRegion io; +} TCOIORegs; + +/* tco.c */ +void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent); + +extern const VMStateDescription vmstate_tco_io_sts; + +#endif /* HW_ACPI_TCO_H */ diff --git a/include/hw/acpi/ipmi.h b/include/hw/acpi/ipmi.h index c14ad682ac95..6c8079c97a0f 100644 --- a/include/hw/acpi/ipmi.h +++ b/include/hw/acpi/ipmi.h @@ -9,13 +9,8 @@ #ifndef HW_ACPI_IPMI_H #define HW_ACPI_IPMI_H -#include "hw/acpi/aml-build.h" +#include "hw/acpi/acpi_aml_interface.h" -/* - * Add ACPI IPMI entries for all registered IPMI devices whose parent - * bus matches the given bus. The resource is the ACPI resource that - * contains the IPMI device, this is required for the I2C CRS. - */ -void build_acpi_ipmi_devices(Aml *table, BusState *bus, const char *resource); +void build_ipmi_dev_aml(AcpiDevAmlIf *adev, Aml *scope); #endif /* HW_ACPI_IPMI_H */ diff --git a/include/hw/acpi/piix4.h b/include/hw/acpi/piix4.h new file mode 100644 index 000000000000..be1f8ea80ee8 --- /dev/null +++ b/include/hw/acpi/piix4.h @@ -0,0 +1,75 @@ +/* + * ACPI implementation + * + * Copyright (c) 2006 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * 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 + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef HW_ACPI_PIIX4_H +#define HW_ACPI_PIIX4_H + +#include "hw/pci/pci_device.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/cpu_hotplug.h" +#include "hw/acpi/memory_hotplug.h" +#include "hw/acpi/pcihp.h" +#include "hw/i2c/pm_smbus.h" +#include "hw/isa/apm.h" + +#define TYPE_PIIX4_PM "PIIX4_PM" +OBJECT_DECLARE_SIMPLE_TYPE(PIIX4PMState, PIIX4_PM) + +struct PIIX4PMState { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + + MemoryRegion io; + uint32_t io_base; + + MemoryRegion io_gpe; + ACPIREGS ar; + + APMState apm; + + PMSMBus smb; + uint32_t smb_io_base; + + qemu_irq irq; + qemu_irq smi_irq; + bool smm_enabled; + bool smm_compat; + Notifier machine_ready; + Notifier powerdown_notifier; + + AcpiPciHpState acpi_pci_hotplug; + bool use_acpi_hotplug_bridge; + bool use_acpi_root_pci_hotplug; + bool not_migrate_acpi_index; + + uint8_t disable_s3; + uint8_t disable_s4; + uint8_t s4_val; + + bool cpu_hotplug_legacy; + AcpiCpuHotplug gpe_cpu; + CPUHotplugState cpuhp_state; + + MemHotplugState acpi_memory_hotplug; +}; + +#endif diff --git a/include/hw/acpi/tco.h b/include/hw/acpi/tco.h deleted file mode 100644 index a1e0da82134b..000000000000 --- a/include/hw/acpi/tco.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * QEMU ICH9 TCO emulation - * - * Copyright (c) 2015 Paulo Alcantara - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef HW_ACPI_TCO_H -#define HW_ACPI_TCO_H - -#include "exec/memory.h" - -/* As per ICH9 spec, the internal timer has an error of ~0.6s on every tick */ -#define TCO_TICK_NSEC 600000000LL - -/* TCO I/O register offsets */ -enum { - TCO_RLD = 0x00, - TCO_DAT_IN = 0x02, - TCO_DAT_OUT = 0x03, - TCO1_STS = 0x04, - TCO2_STS = 0x06, - TCO1_CNT = 0x08, - TCO2_CNT = 0x0a, - TCO_MESSAGE1 = 0x0c, - TCO_MESSAGE2 = 0x0d, - TCO_WDCNT = 0x0e, - SW_IRQ_GEN = 0x10, - TCO_TMR = 0x12, -}; - -/* TCO I/O register control/status bits */ -enum { - SW_TCO_SMI = 1 << 1, - TCO_INT_STS = 1 << 2, - TCO_LOCK = 1 << 12, - TCO_TMR_HLT = 1 << 11, - TCO_TIMEOUT = 1 << 3, - TCO_SECOND_TO_STS = 1 << 1, - TCO_BOOT_STS = 1 << 2, -}; - -/* TCO I/O registers mask bits */ -enum { - TCO_RLD_MASK = 0x3ff, - TCO1_STS_MASK = 0xe870, - TCO2_STS_MASK = 0xfff8, - TCO1_CNT_MASK = 0xfeff, - TCO_TMR_MASK = 0x3ff, -}; - -typedef struct TCOIORegs { - struct { - uint16_t rld; - uint8_t din; - uint8_t dout; - uint16_t sts1; - uint16_t sts2; - uint16_t cnt1; - uint16_t cnt2; - uint8_t msg1; - uint8_t msg2; - uint8_t wdcnt; - uint16_t tmr; - } tco; - uint8_t sw_irq_gen; - - QEMUTimer *tco_timer; - int64_t expire_time; - uint8_t timeouts_no; - - MemoryRegion io; -} TCOIORegs; - -/* tco.c */ -void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent); - -extern const VMStateDescription vmstate_tco_io_sts; - -#endif /* HW_ACPI_TCO_H */ diff --git a/include/hw/adc/aspeed_adc.h b/include/hw/adc/aspeed_adc.h index 2f166e8be111..ff1d06ea91de 100644 --- a/include/hw/adc/aspeed_adc.h +++ b/include/hw/adc/aspeed_adc.h @@ -17,6 +17,7 @@ #define TYPE_ASPEED_2400_ADC TYPE_ASPEED_ADC "-ast2400" #define TYPE_ASPEED_2500_ADC TYPE_ASPEED_ADC "-ast2500" #define TYPE_ASPEED_2600_ADC TYPE_ASPEED_ADC "-ast2600" +#define TYPE_ASPEED_1030_ADC TYPE_ASPEED_ADC "-ast1030" OBJECT_DECLARE_TYPE(AspeedADCState, AspeedADCClass, ASPEED_ADC) #define TYPE_ASPEED_ADC_ENGINE "aspeed.adc.engine" diff --git a/include/hw/adc/npcm7xx_adc.h b/include/hw/adc/npcm7xx_adc.h index 7d8442107aed..93330a408d2b 100644 --- a/include/hw/adc/npcm7xx_adc.h +++ b/include/hw/adc/npcm7xx_adc.h @@ -42,7 +42,7 @@ * @iref: The internal reference voltage, initialized at launch time. * @rv: The calibrated output values of 0.5V and 1.5V for the ADC. */ -typedef struct { +struct NPCM7xxADCState { SysBusDevice parent; MemoryRegion iomem; @@ -60,10 +60,9 @@ typedef struct { uint32_t iref; uint16_t calibration_r_values[NPCM7XX_ADC_NUM_CALIB]; -} NPCM7xxADCState; +}; #define TYPE_NPCM7XX_ADC "npcm7xx-adc" -#define NPCM7XX_ADC(obj) \ - OBJECT_CHECK(NPCM7xxADCState, (obj), TYPE_NPCM7XX_ADC) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxADCState, NPCM7XX_ADC) #endif /* NPCM7XX_ADC_H */ diff --git a/include/hw/adc/rt_lpadc.h b/include/hw/adc/rt_lpadc.h new file mode 100644 index 000000000000..c83c9e8e0b84 --- /dev/null +++ b/include/hw/adc/rt_lpadc.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef HW_RT_LPADC_H +#define HW_RT_LPADC_H + +#include "hw/sysbus.h" +#include "qom/object.h" +#include "qemu/fifo32.h" +#include "qemu/timer.h" + +#define TST_REG_NUM 16 +#define ADC_COMMAND_BUF_NUM 15 +#define FIFO_CTL_NUM 2 +#define ADC_CMP_VALUE_NUM 4 + +#define RESFIFO_SIZE 16 + +#define TYPE_RT_LPADC "rt-lpadc" +OBJECT_DECLARE_SIMPLE_TYPE(RTLPADCState, RT_LPADC) + +struct RTLPADCState { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + uint32_t VERID; + uint32_t PARAM; + uint32_t CTRL; + uint32_t STAT; + uint32_t IE; + uint32_t DE; + uint32_t CFG; + uint32_t PAUSE; + uint32_t SWTRIG; + uint32_t TSTAT; + uint32_t TCTRL[TST_REG_NUM]; + uint32_t FCTRL[FIFO_CTL_NUM]; + uint32_t CMDL[ADC_COMMAND_BUF_NUM]; + uint32_t CMDH[ADC_COMMAND_BUF_NUM]; + uint32_t CV[ADC_CMP_VALUE_NUM]; + Fifo32 RESFIFO[FIFO_CTL_NUM]; + + + uint32_t timer_interval; + QEMUTimer *timer; + uint32_t dma_trigger_nr; + uint32_t state; + + qemu_irq irq; +}; + +/* CTL register */ +#define RSTFIFO1_MASK (1U<<9) +#define RSTFIFO0_MASK (1U<<8) +#define DOZEN_MASK (1U<<2) +#define RST_MASK (1U<<1) +#define ADCEN_MASK 1U + +/* STAT register */ +#define CMDACT_OFFSET (24U) +#define CMDACT_MASK (0xF<>(F##_OFFSET)) +#define TO_REG(R, F, V) ((R&(~F##_MASK))|(V<<(F##_OFFSET))) + +typedef enum { + eLPADC_Run = 1000, + eLPADC_Stop = 2000, + eLPADC_Dozen = 3000, +} eLPADCState; + + +#endif /* HW_RT_LPADC_H */ diff --git a/include/hw/adc/zynq-xadc.h b/include/hw/adc/zynq-xadc.h index 2017b7a80377..c10cc4c379c2 100644 --- a/include/hw/adc/zynq-xadc.h +++ b/include/hw/adc/zynq-xadc.h @@ -39,8 +39,7 @@ struct ZynqXADCState { uint16_t xadc_dfifo[ZYNQ_XADC_FIFO_DEPTH]; uint16_t xadc_dfifo_entries; - struct IRQState *qemu_irq; - + qemu_irq irq; }; #endif /* ZYNQ_XADC_H */ diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index a76dc7b84d6e..e0f2f7ab1982 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -4,6 +4,7 @@ #include "qemu/error-report.h" #include "hw/char/serial.h" #include "hw/arm/boot.h" +#include "hw/pci/pci_device.h" #include "hw/timer/allwinner-a10-pit.h" #include "hw/intc/allwinner-a10-pic.h" #include "hw/net/allwinner_emac.h" @@ -12,6 +13,10 @@ #include "hw/usb/hcd-ohci.h" #include "hw/usb/hcd-ehci.h" #include "hw/rtc/allwinner-rtc.h" +#include "hw/misc/allwinner-a10-ccm.h" +#include "hw/misc/allwinner-a10-dramc.h" +#include "hw/i2c/allwinner-i2c.h" +#include "sysemu/block-backend.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -30,15 +35,38 @@ struct AwA10State { /*< public >*/ ARMCPU cpu; + AwA10ClockCtlState ccm; + AwA10DramControllerState dramc; AwA10PITState timer; AwA10PICState intc; AwEmacState emac; AllwinnerAHCIState sata; AwSdHostState mmc0; + AWI2CState i2c0; AwRtcState rtc; MemoryRegion sram_a; EHCISysBusState ehci[AW_A10_NUM_USB]; OHCISysBusState ohci[AW_A10_NUM_USB]; }; +/** + * Emulate Boot ROM firmware setup functionality. + * + * A real Allwinner A10 SoC contains a Boot ROM + * which is the first code that runs right after + * the SoC is powered on. The Boot ROM is responsible + * for loading user code (e.g. a bootloader) from any + * of the supported external devices and writing the + * downloaded code to internal SRAM. After loading the SoC + * begins executing the code written to SRAM. + * + * This function emulates the Boot ROM by copying 32 KiB + * of data at offset 8 KiB from the given block device and writes it to + * the start of the first internal SRAM memory. + * + * @s: Allwinner A10 state object pointer + * @blk: Block backend device object pointer + */ +void allwinner_a10_bootrom_setup(AwA10State *s, BlockBackend *blk); + #endif diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h index 63025fb27c80..1d7ce205890d 100644 --- a/include/hw/arm/allwinner-h3.h +++ b/include/hw/arm/allwinner-h3.h @@ -47,6 +47,7 @@ #include "hw/sd/allwinner-sdhost.h" #include "hw/net/allwinner-sun8i-emac.h" #include "hw/rtc/allwinner-rtc.h" +#include "hw/i2c/allwinner-i2c.h" #include "target/arm/cpu.h" #include "sysemu/block-backend.h" @@ -82,6 +83,7 @@ enum { AW_H3_DEV_UART2, AW_H3_DEV_UART3, AW_H3_DEV_EMAC, + AW_H3_DEV_TWI0, AW_H3_DEV_DRAMCOM, AW_H3_DEV_DRAMCTL, AW_H3_DEV_DRAMPHY, @@ -130,6 +132,7 @@ struct AwH3State { AwH3SysCtrlState sysctrl; AwSidState sid; AwSdHostState mmc0; + AWI2CState i2c0; AwSun8iEmacState emac; AwRtcState rtc; GICState gic; diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h index 9648e7a41933..3d1eaedeb89f 100644 --- a/include/hw/arm/armsse.h +++ b/include/hw/arm/armsse.h @@ -122,6 +122,9 @@ OBJECT_DECLARE_TYPE(ARMSSE, ARMSSEClass, * them via the ARMSSE base class, so they have no IOTKIT() etc macros. */ #define TYPE_IOTKIT "iotkit" +#define TYPE_IMX95 "imx95" +#define TYPE_RW610_M33 "rw610_m33" +#define TYPE_RT500_M33 "rt500_m33" #define TYPE_SSE200 "sse-200" #define TYPE_SSE300 "sse-300" @@ -142,7 +145,7 @@ OBJECT_DECLARE_TYPE(ARMSSE, ARMSSEClass, #define NUM_PPUS 8 /* Number of CPU IRQs used by the SSE itself */ -#define NUM_SSE_IRQS 32 +#define NUM_SSE_IRQS 244 struct ARMSSE { /*< private >*/ diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index da043dcb454d..8389200b2d01 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -13,6 +13,7 @@ #define ASPEED_SOC_H #include "hw/cpu/a15mpcore.h" +#include "hw/arm/armv7m.h" #include "hw/intc/aspeed_vic.h" #include "hw/misc/aspeed_scu.h" #include "hw/adc/aspeed_adc.h" @@ -33,12 +34,16 @@ #include "hw/usb/hcd-ehci.h" #include "qom/object.h" #include "hw/misc/aspeed_lpc.h" +#include "hw/misc/unimp.h" +#include "hw/misc/aspeed_peci.h" +#include "hw/char/serial.h" #define ASPEED_SPIS_NUM 2 #define ASPEED_EHCIS_NUM 2 #define ASPEED_WDTS_NUM 4 #define ASPEED_CPUS_NUM 2 #define ASPEED_MACS_NUM 4 +#define ASPEED_UARTS_NUM 13 struct AspeedSoCState { /*< private >*/ @@ -47,7 +52,10 @@ struct AspeedSoCState { /*< public >*/ ARMCPU cpu[ASPEED_CPUS_NUM]; A15MPPrivState a7mpcore; + ARMv7MState armv7m; + MemoryRegion *memory; MemoryRegion *dram_mr; + MemoryRegion dram_container; MemoryRegion sram; AspeedVICState vic; AspeedRtcState rtc; @@ -62,6 +70,7 @@ struct AspeedSoCState { AspeedSMCState spi[ASPEED_SPIS_NUM]; EHCISysBusState ehci[ASPEED_EHCIS_NUM]; AspeedSBCState sbc; + UnimplementedDeviceState sbc_unimplemented; AspeedSDMCState sdmc; AspeedWDTState wdt[ASPEED_WDTS_NUM]; FTGMAC100State ftgmac100[ASPEED_MACS_NUM]; @@ -71,7 +80,13 @@ struct AspeedSoCState { AspeedSDHCIState sdhci; AspeedSDHCIState emmc; AspeedLPCState lpc; - uint32_t uart_default; + AspeedPECIState peci; + SerialMM uart[ASPEED_UARTS_NUM]; + Clock *sysclk; + UnimplementedDeviceState iomem; + UnimplementedDeviceState video; + UnimplementedDeviceState emmc_boot_controller; + UnimplementedDeviceState dpmcu; }; #define TYPE_ASPEED_SOC "aspeed-soc" @@ -88,9 +103,11 @@ struct AspeedSoCClass { int ehcis_num; int wdts_num; int macs_num; + int uarts_num; const int *irqmap; const hwaddr *memmap; uint32_t num_cpus; + qemu_irq (*get_irq)(AspeedSoCState *s, int dev); }; @@ -101,6 +118,14 @@ enum { ASPEED_DEV_UART3, ASPEED_DEV_UART4, ASPEED_DEV_UART5, + ASPEED_DEV_UART6, + ASPEED_DEV_UART7, + ASPEED_DEV_UART8, + ASPEED_DEV_UART9, + ASPEED_DEV_UART10, + ASPEED_DEV_UART11, + ASPEED_DEV_UART12, + ASPEED_DEV_UART13, ASPEED_DEV_VUART, ASPEED_DEV_FMC, ASPEED_DEV_SPI1, @@ -112,6 +137,7 @@ enum { ASPEED_DEV_SCU, ASPEED_DEV_ADC, ASPEED_DEV_SBC, + ASPEED_DEV_EMMC_BC, ASPEED_DEV_VIDEO, ASPEED_DEV_SRAM, ASPEED_DEV_SDHCI, @@ -131,6 +157,7 @@ enum { ASPEED_DEV_LPC, ASPEED_DEV_IBT, ASPEED_DEV_I2C, + ASPEED_DEV_PECI, ASPEED_DEV_ETH1, ASPEED_DEV_ETH2, ASPEED_DEV_ETH3, @@ -149,4 +176,15 @@ enum { ASPEED_DEV_I3C, }; +qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev); +bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp); +void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr); +bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp); +void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr); +void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev, + const char *name, hwaddr addr, + uint64_t size); +void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, + unsigned int count, int unit0); + #endif /* ASPEED_SOC_H */ diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index d864879421ab..c9d25d493e0b 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -17,6 +17,7 @@ #include "hw/char/bcm2835_aux.h" #include "hw/display/bcm2835_fb.h" #include "hw/dma/bcm2835_dma.h" +#include "hw/or-irq.h" #include "hw/intc/bcm2835_ic.h" #include "hw/misc/bcm2835_property.h" #include "hw/misc/bcm2835_rng.h" @@ -55,6 +56,7 @@ struct BCM2835PeripheralState { BCM2835AuxState aux; BCM2835FBState fb; BCM2835DMAState dma; + qemu_or_irq orgated_dma_irq; BCM2835ICState ic; BCM2835PropertyState property; BCM2835RngState rng; diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index c7ebae156ec5..f18cc3064ffc 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/exynos4210.h b/include/hw/arm/exynos4210.h index 60b9e126f550..97353f1c02f9 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -26,6 +26,10 @@ #include "hw/or-irq.h" #include "hw/sysbus.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/intc/exynos4210_gic.h" +#include "hw/intc/exynos4210_combiner.h" +#include "hw/core/split-irq.h" #include "target/arm/cpu-qom.h" #include "qom/object.h" @@ -65,34 +69,25 @@ #define EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ \ (EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ * 8) -#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp)*8 + (bit)) -#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8) -#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \ - ((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq)) - -/* IRQs number for external and internal GIC */ -#define EXYNOS4210_EXT_GIC_NIRQ (160-32) -#define EXYNOS4210_INT_GIC_NIRQ 64 - #define EXYNOS4210_I2C_NUMBER 9 #define EXYNOS4210_NUM_DMA 3 -typedef struct Exynos4210Irq { - qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; - qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ]; - qemu_irq int_gic_irq[EXYNOS4210_INT_GIC_NIRQ]; - qemu_irq ext_gic_irq[EXYNOS4210_EXT_GIC_NIRQ]; - qemu_irq board_irqs[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; -} Exynos4210Irq; +/* + * We need one splitter for every external combiner input, plus + * one for every non-zero entry in combiner_grp_to_gic_id[], + * minus one for every external combiner ID in second or later + * places in a combinermap[] line. + * We'll assert in exynos4210_init_board_irqs() if this is wrong. + */ +#define EXYNOS4210_NUM_SPLITTERS (EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ + 38) struct Exynos4210State { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ ARMCPU *cpu[EXYNOS4210_NCPUS]; - Exynos4210Irq irqs; - qemu_irq *irq_table; + qemu_irq irq_table[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; MemoryRegion chipid_mem; MemoryRegion iram_mem; @@ -102,6 +97,12 @@ struct Exynos4210State { MemoryRegion bootreg_mem; I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER]; qemu_or_irq pl330_irq_orgate[EXYNOS4210_NUM_DMA]; + qemu_or_irq cpu_irq_orgate[EXYNOS4210_NCPUS]; + A9MPPrivState a9mpcore; + Exynos4210GicState ext_gic; + Exynos4210CombinerState int_combiner; + Exynos4210CombinerState ext_combiner; + SplitIRQ splitter[EXYNOS4210_NUM_SPLITTERS]; }; #define TYPE_EXYNOS4210_SOC "exynos4210" @@ -110,25 +111,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210State, EXYNOS4210_SOC) void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); -/* Initialize exynos4210 IRQ subsystem stub */ -qemu_irq *exynos4210_init_irq(Exynos4210Irq *env); - -/* Initialize board IRQs. - * These IRQs contain splitted Int/External Combiner and External Gic IRQs */ -void exynos4210_init_board_irqs(Exynos4210Irq *s); - /* Get IRQ number from exynos4210 IRQ subsystem stub. * To identify IRQ source use internal combiner group and bit number * grp - group number * bit - bit number inside group */ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit); -/* - * Get Combiner input GPIO into irqs structure - */ -void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, - int ext); - /* * exynos4210 UART */ diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 1c5fa6fd676e..4e5e07186486 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -235,6 +235,26 @@ enum FslIMX7IRQs { FSL_IMX7_USB2_IRQ = 42, FSL_IMX7_USB3_IRQ = 40, + FSL_IMX7_GPT1_IRQ = 55, + FSL_IMX7_GPT2_IRQ = 54, + FSL_IMX7_GPT3_IRQ = 53, + FSL_IMX7_GPT4_IRQ = 52, + + FSL_IMX7_GPIO1_LOW_IRQ = 64, + FSL_IMX7_GPIO1_HIGH_IRQ = 65, + FSL_IMX7_GPIO2_LOW_IRQ = 66, + FSL_IMX7_GPIO2_HIGH_IRQ = 67, + FSL_IMX7_GPIO3_LOW_IRQ = 68, + FSL_IMX7_GPIO3_HIGH_IRQ = 69, + FSL_IMX7_GPIO4_LOW_IRQ = 70, + FSL_IMX7_GPIO4_HIGH_IRQ = 71, + FSL_IMX7_GPIO5_LOW_IRQ = 72, + FSL_IMX7_GPIO5_HIGH_IRQ = 73, + FSL_IMX7_GPIO6_LOW_IRQ = 74, + FSL_IMX7_GPIO6_HIGH_IRQ = 75, + FSL_IMX7_GPIO7_LOW_IRQ = 76, + FSL_IMX7_GPIO7_HIGH_IRQ = 77, + FSL_IMX7_WDOG1_IRQ = 78, FSL_IMX7_WDOG2_IRQ = 79, FSL_IMX7_WDOG3_IRQ = 10, diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index ce593235d946..f1b7e4a48d33 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -52,7 +52,7 @@ #define NPCM7XX_NR_PWM_MODULES 2 -typedef struct NPCM7xxMachine { +struct NPCM7xxMachine { MachineState parent; /* * PWM fan splitter. each splitter connects to one PWM output and @@ -60,11 +60,10 @@ typedef struct NPCM7xxMachine { */ SplitIRQ fan_splitter[NPCM7XX_NR_PWM_MODULES * NPCM7XX_PWM_PER_MODULE]; -} NPCM7xxMachine; +}; #define TYPE_NPCM7XX_MACHINE MACHINE_TYPE_NAME("npcm7xx") -#define NPCM7XX_MACHINE(obj) \ - OBJECT_CHECK(NPCM7xxMachine, (obj), TYPE_NPCM7XX_MACHINE) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxMachine, NPCM7XX_MACHINE) typedef struct NPCM7xxMachineClass { MachineClass parent; @@ -77,7 +76,7 @@ typedef struct NPCM7xxMachineClass { #define NPCM7XX_MACHINE_GET_CLASS(obj) \ OBJECT_GET_CLASS(NPCM7xxMachineClass, (obj), TYPE_NPCM7XX_MACHINE) -typedef struct NPCM7xxState { +struct NPCM7xxState { DeviceState parent; ARMCPU cpu[NPCM7XX_MAX_NUM_CPUS]; @@ -105,10 +104,10 @@ typedef struct NPCM7xxState { NPCM7xxFIUState fiu[2]; NPCM7xxEMCState emc[2]; NPCM7xxSDHCIState mmc; -} NPCM7xxState; +}; #define TYPE_NPCM7XX "npcm7xx" -#define NPCM7XX(obj) OBJECT_CHECK(NPCM7xxState, (obj), TYPE_NPCM7XX) +OBJECT_DECLARE_TYPE(NPCM7xxState, NPCM7xxClass, NPCM7XX) #define TYPE_NPCM730 "npcm730" #define TYPE_NPCM750 "npcm750" @@ -122,11 +121,6 @@ typedef struct NPCM7xxClass { uint32_t num_cpus; } NPCM7xxClass; -#define NPCM7XX_CLASS(klass) \ - OBJECT_CLASS_CHECK(NPCM7xxClass, (klass), TYPE_NPCM7XX) -#define NPCM7XX_GET_CLASS(obj) \ - OBJECT_GET_CLASS(NPCM7xxClass, (obj), TYPE_NPCM7XX) - /** * npcm7xx_load_kernel - Loads memory with everything needed to boot * @machine - The machine containing the SoC to be booted. diff --git a/include/hw/arm/nxp_rt595.h b/include/hw/arm/nxp_rt595.h new file mode 100755 index 000000000000..3c30853c4faa --- /dev/null +++ b/include/hw/arm/nxp_rt595.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef NXP_RT595_H +#define NXP_RT595_H + +#include "hw/arm/armsse.h" +#include "hw/arm/armsse-version.h" +#include "hw/boards.h" +#include "hw/i2c/rt_flexcomm_i2c.h" +#include "hw/sd/sdhci.h" + +/*======================================= + RW610 CM33 CORE module Start + ========================================*/ +#define RT595_M33_NUMIRQ 73 +#define RT595_M33_SRAM_BANKS 32 +#define RT595_M33_FLEXCOMM_PORTS 17 +#define RT595_M33_OS_TIMER_COUNT 2 +#define RT595_M33_USDHC_COUNT 2 + +typedef struct mem_region_t { + uint32_t start; + uint32_t size; + uint32_t irq_num; + uint32_t dma_hwtrg_nr; +} mem_region; + +typedef struct rt595_memmap_tag { + mem_region pflash; + mem_region sram_part[RT595_M33_SRAM_BANKS]; + mem_region flexcomm[RT595_M33_FLEXCOMM_PORTS]; + mem_region rom; + mem_region flexspi0; + mem_region sdma; + mem_region flexspi1; + mem_region CACHE_Control_0; + mem_region CACHE_Control_1; + mem_region CLKCTL0; + mem_region CLKCTL1; + mem_region RSTCTL0; + mem_region RSTCTL1; + mem_region SYSCTL0; + mem_region SYSCTL1; + mem_region PMC; + mem_region IOPCTL; + mem_region PERIPHERAL_MUXES; + mem_region GPIO_INT; + mem_region flexspi; + mem_region flexspi_ctl; + mem_region flexspi1_ctl; + mem_region lpadc; + mem_region ostimer[RT595_M33_OS_TIMER_COUNT]; + mem_region sdio[RT595_M33_USDHC_COUNT]; + mem_region hs_gpio; + mem_region sec_hs_gpio; + mem_region pmc; + mem_region mua; + mem_region pint[8]; + +} rt595_m33_memmap_t; + +typedef struct { + MachineClass parent; + const char *armsse_type; + int uart_overflow_irq; +} RT595_M33_MachineClass; + +typedef struct { + MachineState parent; + + + ARMSSE iotkit; + + MemoryRegion pflash; + MemoryRegion rom; + MemoryRegion sram[RT595_M33_SRAM_BANKS]; + MemoryRegion sram_alias[RT595_M33_SRAM_BANKS]; + MemoryRegion sram_data_alias[RT595_M33_SRAM_BANKS]; + MemoryRegion sram_data_alias_ns[RT595_M33_SRAM_BANKS]; + MemoryRegion CACHE_Control_0; + MemoryRegion CACHE_Control_1; + MemoryRegion CLKCTL0; + MemoryRegion CLKCTL1; + MemoryRegion RSTCTL0; + MemoryRegion RSTCTL1; + MemoryRegion SYSCTL0; + MemoryRegion SYSCTL1; + MemoryRegion PMC; + MemoryRegion IOPCTL; + MemoryRegion PERIPHERAL_MUXES; + MemoryRegion GPIO_INT; + MemoryRegion flexspi_ns; + MemoryRegion flexspi_s; + MemoryRegion flexspi_ctl; + MemoryRegion flexspi1_ctl; + MemoryRegion flexcomm_ns[RT595_M33_FLEXCOMM_PORTS]; + MemoryRegion flexcomm_s[RT595_M33_FLEXCOMM_PORTS]; + MemoryRegion lpadc; + MemoryRegion lprtc; + MemoryRegion pmc; + MemoryRegion pint; + + MemoryRegion CACHE_Control_0_s; + MemoryRegion CACHE_Control_1_s; + MemoryRegion CLKCTL0_s; + MemoryRegion CLKCTL1_s; + MemoryRegion RSTCTL0_s; + MemoryRegion RSTCTL1_s; + MemoryRegion SYSCTL0_s; + MemoryRegion SYSCTL1_s; + MemoryRegion PMC_s; + MemoryRegion IOPCTL_s; + MemoryRegion PERIPHERAL_MUXES_s; + MemoryRegion GPIO_INT_s; + MemoryRegion flexspi_ctl_s; + MemoryRegion flexspi1_ctl_s; + MemoryRegion os_timer[RT595_M33_OS_TIMER_COUNT]; + MemoryRegion os_timer_sec[RT595_M33_OS_TIMER_COUNT]; + MemoryRegion lpadc_s; + MemoryRegion lprtc_s; + MemoryRegion pmc_s; + MemoryRegion sdio_s[RT595_M33_USDHC_COUNT]; + MemoryRegion mua_s; + MemoryRegion pint_s; + + uint32_t boot_base_addr; + + NotifierList dma_hwtrigger_notifiers; + Notifier hwtrigger_notifier; + + RTFLEXCOMMI2CState * flexcomm_i2c_ctl[RT595_M33_FLEXCOMM_PORTS]; + SDHCIState sdio[RT595_M33_USDHC_COUNT]; + + SplitIRQ sec_resp_splitter; + Clock *sysclk; + Clock *s32kclk; +} RT595_M33_MachineState; + +#define TYPE_RT595_CM33_CORE "rt595-cm33-core" + +#define TYPE_RT595_MACHINE "rt595" +#define TYPE_RT595_M33_MACHINE MACHINE_TYPE_NAME("rt595-m33") + +#define RT595_M33_MACHINE(obj) \ + OBJECT_CHECK(RT595_M33_MachineState, obj, TYPE_RT595_MACHINE) +#define RT595_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RT595_M33_MachineClass, obj, TYPE_RT595_MACHINE) +#define RT595_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(RT595_M33_MachineClass, klass, TYPE_RT595_MACHINE) + +/* Main SYSCLK frequency in Hz */ +#define SYSCLK_FRQ 24000000 +#define S32KCLK_FRQ (32 * 1000) + +#endif diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h index ff6a173f8a6b..c275d9b681c8 100644 --- a/include/hw/arm/omap.h +++ b/include/hw/arm/omap.h @@ -70,9 +70,8 @@ void omap_clk_reparent(omap_clk clk, omap_clk parent); /* omap_intc.c */ #define TYPE_OMAP_INTC "common-omap-intc" -typedef struct omap_intr_handler_s omap_intr_handler; -DECLARE_INSTANCE_CHECKER(omap_intr_handler, OMAP_INTC, - TYPE_OMAP_INTC) +typedef struct OMAPIntcState OMAPIntcState; +DECLARE_INSTANCE_CHECKER(OMAPIntcState, OMAP_INTC, TYPE_OMAP_INTC) /* @@ -89,8 +88,8 @@ DECLARE_INSTANCE_CHECKER(omap_intr_handler, OMAP_INTC, * (ie the struct omap_mpu_state_s*) to do the clockname to pointer * translation.) */ -void omap_intc_set_iclk(omap_intr_handler *intc, omap_clk clk); -void omap_intc_set_fclk(omap_intr_handler *intc, omap_clk clk); +void omap_intc_set_iclk(OMAPIntcState *intc, omap_clk clk); +void omap_intc_set_fclk(OMAPIntcState *intc, omap_clk clk); /* omap_i2c.c */ #define TYPE_OMAP_I2C "omap_i2c" @@ -103,21 +102,20 @@ void omap_i2c_set_fclk(OMAPI2CState *i2c, omap_clk clk); /* omap_gpio.c */ #define TYPE_OMAP1_GPIO "omap-gpio" -DECLARE_INSTANCE_CHECKER(struct omap_gpif_s, OMAP1_GPIO, +typedef struct Omap1GpioState Omap1GpioState; +DECLARE_INSTANCE_CHECKER(Omap1GpioState, OMAP1_GPIO, TYPE_OMAP1_GPIO) #define TYPE_OMAP2_GPIO "omap2-gpio" -DECLARE_INSTANCE_CHECKER(struct omap2_gpif_s, OMAP2_GPIO, +typedef struct Omap2GpioState Omap2GpioState; +DECLARE_INSTANCE_CHECKER(Omap2GpioState, OMAP2_GPIO, TYPE_OMAP2_GPIO) -typedef struct omap_gpif_s omap_gpif; -typedef struct omap2_gpif_s omap2_gpif; - /* TODO: clock framework (see above) */ -void omap_gpio_set_clk(omap_gpif *gpio, omap_clk clk); +void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk); -void omap2_gpio_set_iclk(omap2_gpif *gpio, omap_clk clk); -void omap2_gpio_set_fclk(omap2_gpif *gpio, uint8_t i, omap_clk clk); +void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk); +void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk); /* OMAP2 l4 Interconnect */ struct omap_l4_s; diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h index 1095504b86f3..54eb895e42a0 100644 --- a/include/hw/arm/pxa.h +++ b/include/hw/arm/pxa.h @@ -119,14 +119,14 @@ void pxa27x_register_keypad(PXA2xxKeyPadState *kp, const struct keymap *map, int size); /* pxa2xx.c */ -typedef struct PXA2xxI2CState PXA2xxI2CState; +#define TYPE_PXA2XX_I2C "pxa2xx_i2c" +OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CState, PXA2XX_I2C) + PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, qemu_irq irq, uint32_t page_size); I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s); -#define TYPE_PXA2XX_I2C "pxa2xx_i2c" typedef struct PXA2xxI2SState PXA2xxI2SState; -OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CState, PXA2XX_I2C) #define TYPE_PXA2XX_FIR "pxa2xx-fir" OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxFIrState, PXA2XX_FIR) @@ -193,8 +193,7 @@ struct PXA2xxI2SState { # define PA_FMT "0x%08lx" -PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size, - const char *revision); -PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size); +PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision); +PXA2xxState *pxa255_init(unsigned int sdram_size); #endif /* PXA_H */ diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 706be3c6d0a4..c5683af07d67 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -71,6 +71,7 @@ typedef struct SMMUTransCfg { bool disabled; /* smmu is disabled */ bool bypassed; /* translation is bypassed */ bool aborted; /* translation is aborted */ + bool record_faults; /* record fault events */ uint64_t ttb; /* TT base address */ uint8_t oas; /* output address width */ uint8_t tbi; /* Top Byte Ignore */ @@ -172,7 +173,4 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova, /* Unmap the range of all the notifiers registered to any IOMMU mr */ void smmu_inv_notifiers_all(SMMUState *s); -/* Unmap the range of all the notifiers registered to @mr */ -void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr); - #endif /* HW_ARM_SMMU_COMMON_H */ diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h index c641e60735e0..f1921fdf9e72 100644 --- a/include/hw/arm/smmuv3.h +++ b/include/hw/arm/smmuv3.h @@ -77,7 +77,7 @@ struct SMMUv3Class { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; #define TYPE_ARM_SMMUV3 "arm-smmuv3" diff --git a/include/hw/arm/stm32f405_soc.h b/include/hw/arm/stm32f405_soc.h index 5bb0c8d56979..249ab5434ec7 100644 --- a/include/hw/arm/stm32f405_soc.h +++ b/include/hw/arm/stm32f405_soc.h @@ -46,7 +46,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(STM32F405State, STM32F405_SOC) #define FLASH_BASE_ADDRESS 0x08000000 #define FLASH_SIZE (1024 * 1024) #define SRAM_BASE_ADDRESS 0x20000000 -#define SRAM_SIZE (192 * 1024) +#define SRAM_SIZE (128 * 1024) +#define CCM_BASE_ADDRESS 0x10000000 +#define CCM_SIZE (64 * 1024) struct STM32F405State { /*< private >*/ @@ -65,6 +67,7 @@ struct STM32F405State { STM32F2XXADCState adc[STM_NUM_ADCS]; STM32F2XXSPIState spi[STM_NUM_SPIS]; + MemoryRegion ccm; MemoryRegion sram; MemoryRegion flash; MemoryRegion flash_alias; diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 7e76ee26198b..c7dd59d7f1ff 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -113,6 +113,7 @@ typedef enum VirtGICType { VIRT_GIC_VERSION_HOST, VIRT_GIC_VERSION_2, VIRT_GIC_VERSION_3, + VIRT_GIC_VERSION_4, VIRT_GIC_VERSION_NOSEL, } VirtGICType; @@ -124,6 +125,7 @@ struct VirtMachineClass { bool no_pmu; bool claim_edge_triggered_timers; bool smbios_old_sys_ver; + bool no_highmem_compact; bool no_highmem_ecam; bool no_ged; /* Machines < 4.2 have no support for ACPI GED device */ bool kvm_no_adjvtime; @@ -143,6 +145,7 @@ struct VirtMachineState { PFlashCFI01 *flash[2]; bool secure; bool highmem; + bool highmem_compact; bool highmem_ecam; bool highmem_mmio; bool highmem_redists; @@ -151,7 +154,7 @@ struct VirtMachineState { bool virt; bool ras; bool mte; - bool dtb_kaslr_seed; + bool dtb_randomness; OnOffAuto acpi; VirtGICType gic_version; VirtIOMMUType iommu; @@ -185,13 +188,25 @@ OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE) void virt_acpi_setup(VirtMachineState *vms); bool virt_is_acpi_enabled(VirtMachineState *vms); +/* Return number of redistributors that fit in the specified region */ +static uint32_t virt_redist_capacity(VirtMachineState *vms, int region) +{ + uint32_t redist_size; + + if (vms->gic_version == VIRT_GIC_VERSION_3) { + redist_size = GICV3_REDIST_SIZE; + } else { + redist_size = GICV4_REDIST_SIZE; + } + return vms->memmap[region].size / redist_size; +} + /* Return the number of used redistributor regions */ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) { - uint32_t redist0_capacity = - vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; + uint32_t redist0_capacity = virt_redist_capacity(vms, VIRT_GIC_REDIST); - assert(vms->gic_version == VIRT_GIC_VERSION_3); + assert(vms->gic_version != VIRT_GIC_VERSION_2); return (MACHINE(vms)->smp.cpus > redist0_capacity && vms->highmem_redists) ? 2 : 1; diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 0728316ec77f..cbe8a19c10f6 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -14,6 +14,7 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" +#include "hw/cpu/cluster.h" #include "hw/or-irq.h" #include "hw/sd/sdhci.h" #include "hw/intc/arm_gicv3.h" @@ -28,12 +29,14 @@ #include "hw/nvram/xlnx-versal-efuse.h" #include "hw/ssi/xlnx-versal-ospi.h" #include "hw/dma/xlnx_csu_dma.h" +#include "hw/misc/xlnx-versal-crl.h" #include "hw/misc/xlnx-versal-pmc-iou-slcr.h" #define TYPE_XLNX_VERSAL "xlnx-versal" OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL) #define XLNX_VERSAL_NR_ACPUS 2 +#define XLNX_VERSAL_NR_RCPUS 2 #define XLNX_VERSAL_NR_UARTS 2 #define XLNX_VERSAL_NR_GEMS 2 #define XLNX_VERSAL_NR_ADMAS 8 @@ -49,6 +52,7 @@ struct Versal { struct { struct { MemoryRegion mr; + CPUClusterState cluster; ARMCPU cpu[XLNX_VERSAL_NR_ACPUS]; GICv3State gic; } apu; @@ -71,10 +75,21 @@ struct Versal { VersalUsb2 usb; } iou; + /* Real-time Processing Unit. */ + struct { + MemoryRegion mr; + MemoryRegion mr_ps_alias; + + CPUClusterState cluster; + ARMCPU cpu[XLNX_VERSAL_NR_RCPUS]; + } rpu; + struct { qemu_or_irq irq_orgate; XlnxXramCtrl ctrl[XLNX_VERSAL_NR_XRAM]; } xram; + + XlnxVersalCRL crl; } lpd; /* The Platform Management Controller subsystem. */ @@ -115,6 +130,7 @@ struct Versal { #define VERSAL_TIMER_NS_EL1_IRQ 14 #define VERSAL_TIMER_NS_EL2_IRQ 10 +#define VERSAL_CRL_IRQ 10 #define VERSAL_UART0_IRQ_0 18 #define VERSAL_UART1_IRQ_0 19 #define VERSAL_USB0_IRQ_0 22 diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 9d9a9d0bf9d7..20bdf894aa0c 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -41,6 +41,8 @@ #include "hw/or-irq.h" #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) @@ -55,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 @@ -84,6 +87,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP) #define XLNX_ZYNQMP_MAX_RAM_SIZE (XLNX_ZYNQMP_MAX_LOW_RAM_SIZE + \ XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE) +#define XLNX_ZYNQMP_NUM_TTC 4 + /* * Unimplemented mmio regions needed to boot some images. */ @@ -128,6 +133,8 @@ struct XlnxZynqMPState { qemu_or_irq qspi_irq_orgate; 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/audio/soundhw.h b/include/hw/audio/soundhw.h index f09a297854af..270717a06a0a 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -1,15 +1,13 @@ #ifndef HW_SOUNDHW_H #define HW_SOUNDHW_H -void isa_register_soundhw(const char *name, const char *descr, - int (*init_isa)(ISABus *bus)); - void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)); + int (*init_pci)(PCIBus *bus, const char *audiodev)); void deprecated_register_soundhw(const char *name, const char *descr, int isa, const char *typename); void soundhw_init(void); -void select_soundhw(const char *optarg); +void show_valid_soundhw(void); +void select_soundhw(const char *optarg, const char *audiodev); #endif diff --git a/include/hw/block/block.h b/include/hw/block/block.h index 5902c0440a5f..15fff6643502 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/block/fdc.h b/include/hw/block/fdc.h index 1ecca7cac7f0..35248c08379d 100644 --- a/include/hw/block/fdc.h +++ b/include/hw/block/fdc.h @@ -10,8 +10,7 @@ #define TYPE_ISA_FDC "isa-fdc" void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds); -void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, - hwaddr mmio_base, DriveInfo **fds); +void fdctrl_init_sysbus(qemu_irq irq, hwaddr mmio_base, DriveInfo **fds); void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, DriveInfo **fds, qemu_irq *fdc_tc); diff --git a/include/hw/boards.h b/include/hw/boards.h index c92ac8815c85..6fbbfd56c808 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -6,7 +6,6 @@ #include "exec/memory.h" #include "sysemu/hostmem.h" #include "sysemu/blockdev.h" -#include "qemu/accel.h" #include "qapi/qapi-types-machine.h" #include "qemu/module.h" #include "qom/object.h" @@ -25,7 +24,7 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; -void machine_run_board_init(MachineState *machine); +void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -130,11 +129,14 @@ typedef struct { * @prefer_sockets - whether sockets are preferred over cores in smp parsing * @dies_supported - whether dies are supported by the machine * @clusters_supported - whether clusters are supported by the machine + * @has_clusters - whether clusters are explicitly specified in the user + * provided SMP configuration */ typedef struct { bool prefer_sockets; bool dies_supported; bool clusters_supported; + bool has_clusters; } SMPCompatProps; /** @@ -231,7 +233,7 @@ struct MachineClass { const char *deprecation_reason; void (*init)(MachineState *state); - void (*reset)(MachineState *state); + void (*reset)(MachineState *state, ShutdownCause reason); void (*wakeup)(MachineState *state); int (*kvm_type)(MachineState *machine, const char *arg); @@ -339,7 +341,7 @@ struct MachineState { bool suppress_vmdesc; bool enable_graphics; ConfidentialGuestSupport *cgs; - char *ram_memdev_id; + HostMemoryBackend *memdev; /* * convenience alias to ram_memdev_id backend memory region * or to numa container memory region @@ -350,8 +352,7 @@ struct MachineState { ram_addr_t ram_size; ram_addr_t maxram_size; uint64_t ram_slots; - const char *boot_order; - const char *boot_once; + BootConfiguration boot_config; char *kernel_filename; char *kernel_cmdline; char *initrd_filename; @@ -380,6 +381,15 @@ struct MachineState { } \ type_init(machine_initfn##_register_types) +extern GlobalProperty hw_compat_7_2[]; +extern const size_t hw_compat_7_2_len; + +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; + extern GlobalProperty hw_compat_6_2[]; extern const size_t hw_compat_6_2_len; diff --git a/include/hw/char/cmsdk-apb-uart.h b/include/hw/char/cmsdk-apb-uart.h index 9daff0eeee34..64b0a3d5345e 100644 --- a/include/hw/char/cmsdk-apb-uart.h +++ b/include/hw/char/cmsdk-apb-uart.h @@ -15,6 +15,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "chardev/char-fe.h" +#include "qapi/error.h" #include "qom/object.h" #define TYPE_CMSDK_APB_UART "cmsdk-apb-uart" diff --git a/include/hw/char/goldfish_tty.h b/include/hw/char/goldfish_tty.h index 7503d2fa1e15..d59733e5ae41 100644 --- a/include/hw/char/goldfish_tty.h +++ b/include/hw/char/goldfish_tty.h @@ -12,6 +12,7 @@ #include "qemu/fifo8.h" #include "chardev/char-fe.h" +#include "hw/sysbus.h" #define TYPE_GOLDFISH_TTY "goldfish_tty" OBJECT_DECLARE_SIMPLE_TYPE(GoldfishTTYState, GOLDFISH_TTY) diff --git a/include/hw/char/rt_flexcomm.h b/include/hw/char/rt_flexcomm.h new file mode 100644 index 000000000000..5ffe5b5c9b95 --- /dev/null +++ b/include/hw/char/rt_flexcomm.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_FLEXCOMM_H +#define RT_FLEXCOMM_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "qom/object.h" +#include "qemu/bitops.h" +#include "qemu/fifo8.h" + + +#define PERSEL_MASK 0x7 +#define USARTPRESE_MASK 0x10 +#define USARTD_TXDIS_MASK 0x40 +#define USART_STAT_TXNOTFULL_MASK 0x20 +#define USART_STAT_RXNOTEMPTY_MASK 0x40 +#define USART_STAT_RXFULL_MASK 0x80 +#define USART_STAT_TXEMPTY_MASK 0x10 + +#define USART_FIFOINTSTAT_RXLVL 0x80 +#define USART_FIFOINTSTAT_TXLVL 0x40 + +#define USART_FIFOTRIG_RXLVL_MASK 0xF0000 +#define USART_FIFOTRIG_RXLVL_OFFSET (16U) +#define FIFOTRIG_RXLVL(s) ((s->USART_FIFOTRIG&USART_FIFOTRIG_RXLVL_MASK)>>USART_FIFOTRIG_RXLVL_OFFSET) + +#define USART_FIFOTRIG_TXLVL_MASK 0xF00 +#define USART_FIFOTRIG_TXLVL_OFFSET (8U) +#define FIFOTRIG_TXLVL(s) ((s->USART_FIFOTRIG&USART_FIFOTRIG_TXLVL_MASK)>>USART_FIFOTRIG_TXLVL_OFFSET) + +#define TYPE_RT_FLEXCOMM "rt.flexcomm" +OBJECT_DECLARE_SIMPLE_TYPE(RTFLEXCOMMState, RT_FLEXCOMM) + +struct RTFLEXCOMMState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t USART_CFG; + uint32_t USART_CTL; + uint32_t USART_STAT; + uint32_t USART_INTENSET; + uint32_t USART_INTENCLR; + uint32_t USART_BRG; + uint32_t USART_INTSTAT; + uint32_t USART_OSR; + uint32_t USART_ADDR; + uint32_t USART_FIFOCFG; + uint32_t USART_FIFOSTAT; + uint32_t USART_FIFOTRIG; + uint32_t USART_FIFOINTENSET; + uint32_t USART_FIFOINTENCLR; + uint32_t USART_FIFOINTSTAT; + uint32_t USART_FIFOWR; + uint32_t USART_FIFORD; + uint32_t USART_FIFORDNOPOP; + uint32_t USART_FIFOSIZE; + uint32_t PSELID; + uint32_t ID; + uint32_t FIFO_SIZE; + + Fifo8 * RXFIFO; + Fifo8 * TXFIFO; + CharBackend chr; + qemu_irq irq; +}; + +#endif diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h index bb32d0fcb30f..dd09c0680198 100644 --- a/include/hw/char/xilinx_uartlite.h +++ b/include/hw/char/xilinx_uartlite.h @@ -17,6 +17,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" +#include "qapi/error.h" static inline DeviceState *xilinx_uartlite_create(hwaddr addr, qemu_irq irq, diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 136973655c1a..2417597236bc 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); @@ -187,7 +197,7 @@ struct CPUClass { typedef union IcountDecr { uint32_t u32; struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint16_t high; uint16_t low; #else @@ -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; @@ -325,6 +333,7 @@ struct CPUState { struct QemuThread *thread; #ifdef _WIN32 HANDLE hThread; + QemuSemaphore sem; #endif int thread_id; bool running, has_waiter; @@ -361,8 +370,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; @@ -390,6 +398,9 @@ struct CPUState { uint32_t kvm_fetch_index; uint64_t dirty_pages; + /* Use by accel-block: CPU is executing an ioctl() */ + QemuLockCnt in_ioctl_lock; + /* Used for events with 'vcpu' and *without* the 'disabled' properties */ DECLARE_BITMAP(trace_dstate_delayed, CPU_TRACE_DSTATE_MAX_EVENTS); DECLARE_BITMAP(trace_dstate, CPU_TRACE_DSTATE_MAX_EVENTS); @@ -418,6 +429,12 @@ struct CPUState { */ bool throttle_thread_scheduled; + /* + * Sleep throttle_us_per_full microseconds once dirty ring is full + * if dirty page rate limit is enabled. + */ + int64_t throttle_us_per_full; + bool ignore_memory_transaction_failures; /* Used for user-only emulation of prctl(PR_SET_UNALIGN). */ @@ -442,15 +459,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. @@ -1015,7 +1023,7 @@ int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len); */ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx); -void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...) +G_NORETURN void cpu_abort(CPUState *cpu, const char *fmt, ...) G_GNUC_PRINTF(2, 3); /* $(top_srcdir)/cpu.c */ @@ -1028,13 +1036,15 @@ void cpu_exec_unrealizefn(CPUState *cpu); * target_words_bigendian: * Returns true if the (default) endianness of the target is big endian, * false otherwise. Note that in target-specific code, you can use - * TARGET_WORDS_BIGENDIAN directly instead. On the other hand, common + * TARGET_BIG_ENDIAN directly instead. On the other hand, common * code should normally never need to know about the endianness of the * target, so please do *not* use this function unless you know very well * what you are doing! */ bool target_words_bigendian(void); +void page_size_init(void); + #ifdef NEED_CPU_H #ifdef CONFIG_SOFTMMU diff --git a/include/hw/arm/sysbus-fdt.h b/include/hw/core/sysbus-fdt.h similarity index 100% rename from include/hw/arm/sysbus-fdt.h rename to include/hw/core/sysbus-fdt.h diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index a9ba39e5f258..ee169b872ca1 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/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h index e13898553aff..20e3c0ffbb84 100644 --- a/include/hw/core/tcg-cpu-ops.h +++ b/include/hw/core/tcg-cpu-ops.h @@ -31,6 +31,17 @@ struct TCGCPUOps { * function to restore all the state, and register it here. */ void (*synchronize_from_tb)(CPUState *cpu, const TranslationBlock *tb); + /** + * @restore_state_to_opc: Synchronize state from INDEX_op_start_insn + * + * This is called when we unwind state in the middle of a TB, + * usually before raising an exception. Set all part of the CPU + * state which are tracked insn-by-insn in the target-specific + * arguments to start_insn, passed as @data. + */ + void (*restore_state_to_opc)(CPUState *cpu, const TranslationBlock *tb, + const uint64_t *data); + /** @cpu_exec_enter: Callback for cpu_exec preparation */ void (*cpu_exec_enter)(CPUState *cpu); /** @cpu_exec_exit: Callback for cpu_exec cleanup */ @@ -78,9 +89,9 @@ struct TCGCPUOps { * @do_unaligned_access: Callback for unaligned access handling * The callback must exit via raising an exception. */ - void (*do_unaligned_access)(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) QEMU_NORETURN; + G_NORETURN void (*do_unaligned_access)(CPUState *cpu, vaddr addr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); /** * @adjust_watchpoint_address: hack for cpu_check_watchpoint used by ARM @@ -90,6 +101,7 @@ struct TCGCPUOps { /** * @debug_check_watchpoint: return true if the architectural * watchpoint whose address has matched should really fire, used by ARM + * and RISC-V */ bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp); diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h index 8b01ed67d3c1..467b529dc06b 100644 --- a/include/hw/cris/etraxfs.h +++ b/include/hw/cris/etraxfs.h @@ -29,6 +29,7 @@ #include "hw/cris/etraxfs_dma.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" +#include "qapi/error.h" DeviceState *etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr, struct etraxfs_dma_client *dma_out, diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h new file mode 100644 index 000000000000..b161be59b7b1 --- /dev/null +++ b/include/hw/cxl/cxl.h @@ -0,0 +1,62 @@ +/* + * QEMU CXL Support + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_H +#define CXL_H + + +#include "qapi/qapi-types-machine.h" +#include "qapi/qapi-visit-machine.h" +#include "hw/pci/pci_host.h" +#include "cxl_pci.h" +#include "cxl_component.h" +#include "cxl_device.h" + +#define CXL_COMPONENT_REG_BAR_IDX 0 +#define CXL_DEVICE_REG_BAR_IDX 2 + +#define CXL_WINDOW_MAX 10 + +typedef struct PXBDev PXBDev; + +typedef struct CXLFixedWindow { + uint64_t size; + char **targets; + PXBDev *target_hbs[8]; + uint8_t num_targets; + uint8_t enc_int_ways; + uint8_t enc_int_gran; + /* Todo: XOR based interleaving */ + MemoryRegion mr; + hwaddr base; +} CXLFixedWindow; + +typedef struct CXLState { + bool is_enabled; + MemoryRegion host_mr; + unsigned int next_mr_idx; + GList *fixed_windows; + CXLFixedMemoryWindowOptionsList *cfmw_list; +} CXLState; + +struct CXLHost { + PCIHostState parent_obj; + + CXLComponentState cxl_cstate; +}; + +#define TYPE_PXB_CXL_HOST "pxb-cxl-host" +OBJECT_DECLARE_SIMPLE_TYPE(CXLHost, PXB_CXL_HOST) + +#define TYPE_CXL_USP "cxl-upstream" + +typedef struct CXLUpstreamPort CXLUpstreamPort; +DECLARE_INSTANCE_CHECKER(CXLUpstreamPort, CXL_USP, TYPE_CXL_USP) +CXLComponentState *cxl_usp_to_cstate(CXLUpstreamPort *usp); +#endif diff --git a/include/hw/cxl/cxl_cdat.h b/include/hw/cxl/cxl_cdat.h new file mode 100644 index 000000000000..7f6763868597 --- /dev/null +++ b/include/hw/cxl/cxl_cdat.h @@ -0,0 +1,167 @@ +/* + * CXL CDAT Structure + * + * Copyright (C) 2021 Avery Design Systems, 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. + */ + +#ifndef CXL_CDAT_H +#define CXL_CDAT_H + +#include "hw/cxl/cxl_pci.h" +#include "hw/pci/pcie_doe.h" + +/* + * Reference: + * Coherent Device Attribute Table (CDAT) Specification, Rev. 1.03, July. 2022 + * Compute Express Link (CXL) Specification, Rev. 3.0, Aug. 2022 + */ +/* Table Access DOE - CXL r3.0 8.1.11 */ +#define CXL_DOE_TABLE_ACCESS 2 +#define CXL_DOE_PROTOCOL_CDAT ((CXL_DOE_TABLE_ACCESS << 16) | CXL_VENDOR_ID) + +/* Read Entry - CXL r3.0 8.1.11.1 */ +#define CXL_DOE_TAB_TYPE_CDAT 0 +#define CXL_DOE_TAB_ENT_MAX 0xFFFF + +/* Read Entry Request - CXL r3.0 8.1.11.1 Table 8-13 */ +#define CXL_DOE_TAB_REQ 0 +typedef struct CDATReq { + DOEHeader header; + uint8_t req_code; + uint8_t table_type; + uint16_t entry_handle; +} QEMU_PACKED CDATReq; + +/* Read Entry Response - CXL r3.0 8.1.11.1 Table 8-14 */ +#define CXL_DOE_TAB_RSP 0 +typedef struct CDATRsp { + DOEHeader header; + uint8_t rsp_code; + uint8_t table_type; + uint16_t entry_handle; +} QEMU_PACKED CDATRsp; + +/* CDAT Table Format - CDAT Table 1 */ +#define CXL_CDAT_REV 2 +typedef struct CDATTableHeader { + uint32_t length; + uint8_t revision; + uint8_t checksum; + uint8_t reserved[6]; + uint32_t sequence; +} QEMU_PACKED CDATTableHeader; + +/* CDAT Structure Types - CDAT Table 2 */ +typedef enum { + CDAT_TYPE_DSMAS = 0, + CDAT_TYPE_DSLBIS = 1, + CDAT_TYPE_DSMSCIS = 2, + CDAT_TYPE_DSIS = 3, + CDAT_TYPE_DSEMTS = 4, + CDAT_TYPE_SSLBIS = 5, +} CDATType; + +typedef struct CDATSubHeader { + uint8_t type; + uint8_t reserved; + uint16_t length; +} CDATSubHeader; + +/* Device Scoped Memory Affinity Structure - CDAT Table 3 */ +typedef struct CDATDsmas { + CDATSubHeader header; + uint8_t DSMADhandle; + uint8_t flags; +#define CDAT_DSMAS_FLAG_NV (1 << 2) +#define CDAT_DSMAS_FLAG_SHAREABLE (1 << 3) +#define CDAT_DSMAS_FLAG_HW_COHERENT (1 << 4) +#define CDAT_DSMAS_FLAG_DYNAMIC_CAP (1 << 5) + uint16_t reserved; + uint64_t DPA_base; + uint64_t DPA_length; +} QEMU_PACKED CDATDsmas; + +/* Device Scoped Latency and Bandwidth Information Structure - CDAT Table 5 */ +typedef struct CDATDslbis { + CDATSubHeader header; + uint8_t handle; + /* Definitions of these fields refer directly to HMAT fields */ + uint8_t flags; + uint8_t data_type; + uint8_t reserved; + uint64_t entry_base_unit; + uint16_t entry[3]; + uint16_t reserved2; +} QEMU_PACKED CDATDslbis; + +/* Device Scoped Memory Side Cache Information Structure - CDAT Table 6 */ +typedef struct CDATDsmscis { + CDATSubHeader header; + uint8_t DSMAS_handle; + uint8_t reserved[3]; + uint64_t memory_side_cache_size; + uint32_t cache_attributes; +} QEMU_PACKED CDATDsmscis; + +/* Device Scoped Initiator Structure - CDAT Table 7 */ +typedef struct CDATDsis { + CDATSubHeader header; + uint8_t flags; + uint8_t handle; + uint16_t reserved; +} QEMU_PACKED CDATDsis; + +/* Device Scoped EFI Memory Type Structure - CDAT Table 8 */ +typedef struct CDATDsemts { + CDATSubHeader header; + uint8_t DSMAS_handle; + uint8_t EFI_memory_type_attr; + uint16_t reserved; + uint64_t DPA_offset; + uint64_t DPA_length; +} QEMU_PACKED CDATDsemts; + +/* Switch Scoped Latency and Bandwidth Information Structure - CDAT Table 9 */ +typedef struct CDATSslbisHeader { + CDATSubHeader header; + uint8_t data_type; + uint8_t reserved[3]; + uint64_t entry_base_unit; +} QEMU_PACKED CDATSslbisHeader; + +#define CDAT_PORT_ID_USP 0x100 +/* Switch Scoped Latency and Bandwidth Entry - CDAT Table 10 */ +typedef struct CDATSslbe { + uint16_t port_x_id; + uint16_t port_y_id; + uint16_t latency_bandwidth; + uint16_t reserved; +} QEMU_PACKED CDATSslbe; + +typedef struct CDATSslbis { + CDATSslbisHeader sslbis_header; + CDATSslbe sslbe[]; +} QEMU_PACKED CDATSslbis; + +typedef struct CDATEntry { + void *base; + uint32_t length; +} CDATEntry; + +typedef struct CDATObject { + CDATEntry *entry; + int entry_len; + + int (*build_cdat_table)(CDATSubHeader ***cdat_table, void *priv); + void (*free_cdat_table)(CDATSubHeader **cdat_table, int num, void *priv); + bool to_update; + void *private; + char *filename; + uint8_t *buf; + struct CDATSubHeader **built_buf; + int built_buf_len; +} CDATObject; +#endif /* CXL_CDAT_H */ diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h new file mode 100644 index 000000000000..5dca21e95bea --- /dev/null +++ b/include/hw/cxl/cxl_component.h @@ -0,0 +1,231 @@ +/* + * QEMU CXL Component + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_COMPONENT_H +#define CXL_COMPONENT_H + +/* CXL 2.0 - 8.2.4 */ +#define CXL2_COMPONENT_IO_REGION_SIZE 0x1000 +#define CXL2_COMPONENT_CM_REGION_SIZE 0x1000 +#define CXL2_COMPONENT_BLOCK_SIZE 0x10000 + +#include "qemu/compiler.h" +#include "qemu/range.h" +#include "qemu/typedefs.h" +#include "hw/cxl/cxl_cdat.h" +#include "hw/register.h" +#include "qapi/error.h" + +enum reg_type { + CXL2_DEVICE, + CXL2_TYPE3_DEVICE, + CXL2_LOGICAL_DEVICE, + CXL2_ROOT_PORT, + CXL2_UPSTREAM_PORT, + CXL2_DOWNSTREAM_PORT +}; + +/* + * Capability registers are defined at the top of the CXL.cache/mem region and + * are packed. For our purposes we will always define the caps in the same + * order. + * CXL 2.0 - 8.2.5 Table 142 for details. + */ + +/* CXL 2.0 - 8.2.5.1 */ +REG32(CXL_CAPABILITY_HEADER, 0) + FIELD(CXL_CAPABILITY_HEADER, ID, 0, 16) + FIELD(CXL_CAPABILITY_HEADER, VERSION, 16, 4) + FIELD(CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 20, 4) + FIELD(CXL_CAPABILITY_HEADER, ARRAY_SIZE, 24, 8) + +#define CXLx_CAPABILITY_HEADER(type, offset) \ + REG32(CXL_##type##_CAPABILITY_HEADER, offset) \ + FIELD(CXL_##type##_CAPABILITY_HEADER, ID, 0, 16) \ + FIELD(CXL_##type##_CAPABILITY_HEADER, VERSION, 16, 4) \ + FIELD(CXL_##type##_CAPABILITY_HEADER, PTR, 20, 12) +CXLx_CAPABILITY_HEADER(RAS, 0x4) +CXLx_CAPABILITY_HEADER(LINK, 0x8) +CXLx_CAPABILITY_HEADER(HDM, 0xc) +CXLx_CAPABILITY_HEADER(EXTSEC, 0x10) +CXLx_CAPABILITY_HEADER(SNOOP, 0x14) + +/* + * Capability structures contain the actual registers that the CXL component + * implements. Some of these are specific to certain types of components, but + * this implementation leaves enough space regardless. + */ +/* 8.2.5.9 - CXL RAS Capability Structure */ + +/* Give ample space for caps before this */ +#define CXL_RAS_REGISTERS_OFFSET 0x80 +#define CXL_RAS_REGISTERS_SIZE 0x58 +REG32(CXL_RAS_UNC_ERR_STATUS, CXL_RAS_REGISTERS_OFFSET) +REG32(CXL_RAS_UNC_ERR_MASK, CXL_RAS_REGISTERS_OFFSET + 0x4) +REG32(CXL_RAS_UNC_ERR_SEVERITY, CXL_RAS_REGISTERS_OFFSET + 0x8) +REG32(CXL_RAS_COR_ERR_STATUS, CXL_RAS_REGISTERS_OFFSET + 0xc) +REG32(CXL_RAS_COR_ERR_MASK, CXL_RAS_REGISTERS_OFFSET + 0x10) +REG32(CXL_RAS_ERR_CAP_CTRL, CXL_RAS_REGISTERS_OFFSET + 0x14) +/* Offset 0x18 - 0x58 reserved for RAS logs */ + +/* 8.2.5.10 - CXL Security Capability Structure */ +#define CXL_SEC_REGISTERS_OFFSET \ + (CXL_RAS_REGISTERS_OFFSET + CXL_RAS_REGISTERS_SIZE) +#define CXL_SEC_REGISTERS_SIZE 0 /* We don't implement 1.1 downstream ports */ + +/* 8.2.5.11 - CXL Link Capability Structure */ +#define CXL_LINK_REGISTERS_OFFSET \ + (CXL_SEC_REGISTERS_OFFSET + CXL_SEC_REGISTERS_SIZE) +#define CXL_LINK_REGISTERS_SIZE 0x38 + +/* 8.2.5.12 - CXL HDM Decoder Capability Structure */ +#define HDM_DECODE_MAX 10 /* 8.2.5.12.1 */ +#define CXL_HDM_REGISTERS_OFFSET \ + (CXL_LINK_REGISTERS_OFFSET + CXL_LINK_REGISTERS_SIZE) +#define CXL_HDM_REGISTERS_SIZE (0x10 + 0x20 * HDM_DECODE_MAX) +#define HDM_DECODER_INIT(n) \ + REG32(CXL_HDM_DECODER##n##_BASE_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x10) \ + FIELD(CXL_HDM_DECODER##n##_BASE_LO, L, 28, 4) \ + REG32(CXL_HDM_DECODER##n##_BASE_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x14) \ + REG32(CXL_HDM_DECODER##n##_SIZE_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x18) \ + REG32(CXL_HDM_DECODER##n##_SIZE_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x1C) \ + REG32(CXL_HDM_DECODER##n##_CTRL, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x20) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, IG, 0, 4) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, IW, 4, 4) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, LOCK_ON_COMMIT, 8, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, COMMIT, 9, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, COMMITTED, 10, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, ERR, 11, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, TYPE, 12, 1) \ + REG32(CXL_HDM_DECODER##n##_TARGET_LIST_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x24) \ + REG32(CXL_HDM_DECODER##n##_TARGET_LIST_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x28) + +REG32(CXL_HDM_DECODER_CAPABILITY, CXL_HDM_REGISTERS_OFFSET) + FIELD(CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, 0, 4) + FIELD(CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 4, 4) + FIELD(CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 8, 1) + FIELD(CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 9, 1) + FIELD(CXL_HDM_DECODER_CAPABILITY, POISON_ON_ERR_CAP, 10, 1) +REG32(CXL_HDM_DECODER_GLOBAL_CONTROL, CXL_HDM_REGISTERS_OFFSET + 4) + FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, POISON_ON_ERR_EN, 0, 1) + FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, HDM_DECODER_ENABLE, 1, 1) + +HDM_DECODER_INIT(0); + +/* 8.2.5.13 - CXL Extended Security Capability Structure (Root complex only) */ +#define EXTSEC_ENTRY_MAX 256 +#define CXL_EXTSEC_REGISTERS_OFFSET \ + (CXL_HDM_REGISTERS_OFFSET + CXL_HDM_REGISTERS_SIZE) +#define CXL_EXTSEC_REGISTERS_SIZE (8 * EXTSEC_ENTRY_MAX + 4) + +/* 8.2.5.14 - CXL IDE Capability Structure */ +#define CXL_IDE_REGISTERS_OFFSET \ + (CXL_EXTSEC_REGISTERS_OFFSET + CXL_EXTSEC_REGISTERS_SIZE) +#define CXL_IDE_REGISTERS_SIZE 0x20 + +/* 8.2.5.15 - CXL Snoop Filter Capability Structure */ +#define CXL_SNOOP_REGISTERS_OFFSET \ + (CXL_IDE_REGISTERS_OFFSET + CXL_IDE_REGISTERS_SIZE) +#define CXL_SNOOP_REGISTERS_SIZE 0x8 + +QEMU_BUILD_BUG_MSG((CXL_SNOOP_REGISTERS_OFFSET + CXL_SNOOP_REGISTERS_SIZE) >= 0x1000, + "No space for registers"); + +typedef struct component_registers { + /* + * Main memory region to be registered with QEMU core. + */ + MemoryRegion component_registers; + + /* + * 8.2.4 Table 141: + * 0x0000 - 0x0fff CXL.io registers + * 0x1000 - 0x1fff CXL.cache and CXL.mem + * 0x2000 - 0xdfff Implementation specific + * 0xe000 - 0xe3ff CXL ARB/MUX registers + * 0xe400 - 0xffff RSVD + */ + uint32_t io_registers[CXL2_COMPONENT_IO_REGION_SIZE >> 2]; + MemoryRegion io; + + uint32_t cache_mem_registers[CXL2_COMPONENT_CM_REGION_SIZE >> 2]; + uint32_t cache_mem_regs_write_mask[CXL2_COMPONENT_CM_REGION_SIZE >> 2]; + MemoryRegion cache_mem; + + MemoryRegion impl_specific; + MemoryRegion arb_mux; + MemoryRegion rsvd; + + /* special_ops is used for any component that needs any specific handling */ + MemoryRegionOps *special_ops; +} ComponentRegisters; + +/* + * A CXL component represents all entities in a CXL hierarchy. This includes, + * host bridges, root ports, upstream/downstream switch ports, and devices + */ +typedef struct cxl_component { + ComponentRegisters crb; + union { + struct { + Range dvsecs[CXL20_MAX_DVSEC]; + uint16_t dvsec_offset; + struct PCIDevice *pdev; + }; + }; + + CDATObject cdat; +} CXLComponentState; + +void cxl_component_register_block_init(Object *obj, + CXLComponentState *cxl_cstate, + const char *type); +void cxl_component_register_init_common(uint32_t *reg_state, + uint32_t *write_msk, + enum reg_type type); + +void cxl_component_create_dvsec(CXLComponentState *cxl_cstate, + enum reg_type cxl_dev_type, uint16_t length, + uint16_t type, uint8_t rev, uint8_t *body); + +static inline int cxl_decoder_count_enc(int count) +{ + switch (count) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 6: return 3; + case 8: return 4; + case 10: return 5; + } + return 0; +} + +uint8_t cxl_interleave_ways_enc(int iw, Error **errp); +uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp); + +static inline hwaddr cxl_decode_ig(int ig) +{ + return 1ULL << (ig + 8); +} + +CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb); + +void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp); +void cxl_doe_cdat_release(CXLComponentState *cxl_cstate); +void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp); + +#endif diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h new file mode 100644 index 000000000000..250adf18b208 --- /dev/null +++ b/include/hw/cxl/cxl_device.h @@ -0,0 +1,274 @@ +/* + * QEMU CXL Devices + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_DEVICE_H +#define CXL_DEVICE_H + +#include "hw/cxl/cxl_component.h" +#include "hw/pci/pci_device.h" +#include "hw/register.h" + +/* + * The following is how a CXL device's Memory Device registers are laid out. + * The only requirement from the spec is that the capabilities array and the + * capability headers start at offset 0 and are contiguously packed. The headers + * themselves provide offsets to the register fields. For this emulation, the + * actual registers * will start at offset 0x80 (m == 0x80). No secondary + * mailbox is implemented which means that the offset of the start of the + * mailbox payload (n) is given by + * n = m + sizeof(mailbox registers) + sizeof(device registers). + * + * +---------------------------------+ + * | | + * | Memory Device Registers | + * | | + * n + PAYLOAD_SIZE_MAX ----------------------------------- + * ^ | | + * | | | + * | | | + * | | | + * | | | + * | | Mailbox Payload | + * | | | + * | | | + * | | | + * n ----------------------------------- + * ^ | Mailbox Registers | + * | | | + * | ----------------------------------- + * | | | + * | | Device Registers | + * | | | + * m ----------------------------------> + * ^ | Memory Device Capability Header| + * | ----------------------------------- + * | | Mailbox Capability Header | + * | ----------------------------------- + * | | Device Capability Header | + * | ----------------------------------- + * | | Device Cap Array Register | + * 0 +---------------------------------+ + * + */ + +#define CXL_DEVICE_CAP_HDR1_OFFSET 0x10 /* Figure 138 */ +#define CXL_DEVICE_CAP_REG_SIZE 0x10 /* 8.2.8.2 */ +#define CXL_DEVICE_CAPS_MAX 4 /* 8.2.8.2.1 + 8.2.8.5 */ +#define CXL_CAPS_SIZE \ + (CXL_DEVICE_CAP_REG_SIZE * (CXL_DEVICE_CAPS_MAX + 1)) /* +1 for header */ + +#define CXL_DEVICE_STATUS_REGISTERS_OFFSET 0x80 /* Read comment above */ +#define CXL_DEVICE_STATUS_REGISTERS_LENGTH 0x8 /* 8.2.8.3.1 */ + +#define CXL_MAILBOX_REGISTERS_OFFSET \ + (CXL_DEVICE_STATUS_REGISTERS_OFFSET + CXL_DEVICE_STATUS_REGISTERS_LENGTH) +#define CXL_MAILBOX_REGISTERS_SIZE 0x20 /* 8.2.8.4, Figure 139 */ +#define CXL_MAILBOX_PAYLOAD_SHIFT 11 +#define CXL_MAILBOX_MAX_PAYLOAD_SIZE (1 << CXL_MAILBOX_PAYLOAD_SHIFT) +#define CXL_MAILBOX_REGISTERS_LENGTH \ + (CXL_MAILBOX_REGISTERS_SIZE + CXL_MAILBOX_MAX_PAYLOAD_SIZE) + +#define CXL_MEMORY_DEVICE_REGISTERS_OFFSET \ + (CXL_MAILBOX_REGISTERS_OFFSET + CXL_MAILBOX_REGISTERS_LENGTH) +#define CXL_MEMORY_DEVICE_REGISTERS_LENGTH 0x8 + +#define CXL_MMIO_SIZE \ + (CXL_DEVICE_CAP_REG_SIZE + CXL_DEVICE_STATUS_REGISTERS_LENGTH + \ + CXL_MAILBOX_REGISTERS_LENGTH + CXL_MEMORY_DEVICE_REGISTERS_LENGTH) + +typedef struct cxl_device_state { + MemoryRegion device_registers; + + /* mmio for device capabilities array - 8.2.8.2 */ + MemoryRegion device; + MemoryRegion memory_device; + struct { + MemoryRegion caps; + union { + uint32_t caps_reg_state32[CXL_CAPS_SIZE / 4]; + uint64_t caps_reg_state64[CXL_CAPS_SIZE / 8]; + }; + }; + + /* mmio for the mailbox registers 8.2.8.4 */ + struct { + MemoryRegion mailbox; + uint16_t payload_size; + union { + uint8_t mbox_reg_state[CXL_MAILBOX_REGISTERS_LENGTH]; + uint16_t mbox_reg_state16[CXL_MAILBOX_REGISTERS_LENGTH / 2]; + uint32_t mbox_reg_state32[CXL_MAILBOX_REGISTERS_LENGTH / 4]; + uint64_t mbox_reg_state64[CXL_MAILBOX_REGISTERS_LENGTH / 8]; + }; + struct cel_log { + uint16_t opcode; + uint16_t effect; + } cel_log[1 << 16]; + size_t cel_size; + }; + + struct { + bool set; + uint64_t last_set; + uint64_t host_set; + } timestamp; + + /* memory region for persistent memory, HDM */ + uint64_t pmem_size; +} CXLDeviceState; + +/* Initialize the register block for a device */ +void cxl_device_register_block_init(Object *obj, CXLDeviceState *dev); + +/* Set up default values for the register block */ +void cxl_device_register_init_common(CXLDeviceState *dev); + +/* + * CXL 2.0 - 8.2.8.1 including errata F4 + * Documented as a 128 bit register, but 64 bit accesses and the second + * 64 bits are currently reserved. + */ +REG64(CXL_DEV_CAP_ARRAY, 0) /* Documented as 128 bit register but 64 byte accesses */ + FIELD(CXL_DEV_CAP_ARRAY, CAP_ID, 0, 16) + FIELD(CXL_DEV_CAP_ARRAY, CAP_VERSION, 16, 8) + FIELD(CXL_DEV_CAP_ARRAY, CAP_COUNT, 32, 16) + +/* + * Helper macro to initialize capability headers for CXL devices. + * + * In the 8.2.8.2, this is listed as a 128b register, but in 8.2.8, it says: + * > No registers defined in Section 8.2.8 are larger than 64-bits wide so that + * > is the maximum access size allowed for these registers. If this rule is not + * > followed, the behavior is undefined + * + * CXL 2.0 Errata F4 states futher that the layouts in the specification are + * shown as greater than 128 bits, but implementations are expected to + * use any size of access up to 64 bits. + * + * Here we've chosen to make it 4 dwords. The spec allows any pow2 multiple + * access to be used for a register up to 64 bits. + */ +#define CXL_DEVICE_CAPABILITY_HEADER_REGISTER(n, offset) \ + REG32(CXL_DEV_##n##_CAP_HDR0, offset) \ + FIELD(CXL_DEV_##n##_CAP_HDR0, CAP_ID, 0, 16) \ + FIELD(CXL_DEV_##n##_CAP_HDR0, CAP_VERSION, 16, 8) \ + REG32(CXL_DEV_##n##_CAP_HDR1, offset + 4) \ + FIELD(CXL_DEV_##n##_CAP_HDR1, CAP_OFFSET, 0, 32) \ + REG32(CXL_DEV_##n##_CAP_HDR2, offset + 8) \ + FIELD(CXL_DEV_##n##_CAP_HDR2, CAP_LENGTH, 0, 32) + +CXL_DEVICE_CAPABILITY_HEADER_REGISTER(DEVICE_STATUS, CXL_DEVICE_CAP_HDR1_OFFSET) +CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MAILBOX, CXL_DEVICE_CAP_HDR1_OFFSET + \ + CXL_DEVICE_CAP_REG_SIZE) +CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MEMORY_DEVICE, + CXL_DEVICE_CAP_HDR1_OFFSET + + CXL_DEVICE_CAP_REG_SIZE * 2) + +int cxl_initialize_mailbox(CXLDeviceState *cxl_dstate); +void cxl_process_mailbox(CXLDeviceState *cxl_dstate); + +#define cxl_device_cap_init(dstate, reg, cap_id) \ + do { \ + uint32_t *cap_hdrs = dstate->caps_reg_state32; \ + int which = R_CXL_DEV_##reg##_CAP_HDR0; \ + cap_hdrs[which] = \ + FIELD_DP32(cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, \ + CAP_ID, cap_id); \ + cap_hdrs[which] = FIELD_DP32( \ + cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, CAP_VERSION, 1); \ + cap_hdrs[which + 1] = \ + FIELD_DP32(cap_hdrs[which + 1], CXL_DEV_##reg##_CAP_HDR1, \ + CAP_OFFSET, CXL_##reg##_REGISTERS_OFFSET); \ + cap_hdrs[which + 2] = \ + FIELD_DP32(cap_hdrs[which + 2], CXL_DEV_##reg##_CAP_HDR2, \ + CAP_LENGTH, CXL_##reg##_REGISTERS_LENGTH); \ + } while (0) + +/* CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register */ +REG32(CXL_DEV_MAILBOX_CAP, 0) + FIELD(CXL_DEV_MAILBOX_CAP, PAYLOAD_SIZE, 0, 5) + FIELD(CXL_DEV_MAILBOX_CAP, INT_CAP, 5, 1) + FIELD(CXL_DEV_MAILBOX_CAP, BG_INT_CAP, 6, 1) + FIELD(CXL_DEV_MAILBOX_CAP, MSI_N, 7, 4) + +/* CXL 2.0 8.2.8.4.4 Mailbox Control Register */ +REG32(CXL_DEV_MAILBOX_CTRL, 4) + FIELD(CXL_DEV_MAILBOX_CTRL, DOORBELL, 0, 1) + FIELD(CXL_DEV_MAILBOX_CTRL, INT_EN, 1, 1) + FIELD(CXL_DEV_MAILBOX_CTRL, BG_INT_EN, 2, 1) + +/* CXL 2.0 8.2.8.4.5 Command Register */ +REG64(CXL_DEV_MAILBOX_CMD, 8) + FIELD(CXL_DEV_MAILBOX_CMD, COMMAND, 0, 8) + FIELD(CXL_DEV_MAILBOX_CMD, COMMAND_SET, 8, 8) + FIELD(CXL_DEV_MAILBOX_CMD, LENGTH, 16, 20) + +/* CXL 2.0 8.2.8.4.6 Mailbox Status Register */ +REG64(CXL_DEV_MAILBOX_STS, 0x10) + FIELD(CXL_DEV_MAILBOX_STS, BG_OP, 0, 1) + FIELD(CXL_DEV_MAILBOX_STS, ERRNO, 32, 16) + FIELD(CXL_DEV_MAILBOX_STS, VENDOR_ERRNO, 48, 16) + +/* CXL 2.0 8.2.8.4.7 Background Command Status Register */ +REG64(CXL_DEV_BG_CMD_STS, 0x18) + FIELD(CXL_DEV_BG_CMD_STS, OP, 0, 16) + FIELD(CXL_DEV_BG_CMD_STS, PERCENTAGE_COMP, 16, 7) + FIELD(CXL_DEV_BG_CMD_STS, RET_CODE, 32, 16) + FIELD(CXL_DEV_BG_CMD_STS, VENDOR_RET_CODE, 48, 16) + +/* CXL 2.0 8.2.8.4.8 Command Payload Registers */ +REG32(CXL_DEV_CMD_PAYLOAD, 0x20) + +REG64(CXL_MEM_DEV_STS, 0) + FIELD(CXL_MEM_DEV_STS, FATAL, 0, 1) + FIELD(CXL_MEM_DEV_STS, FW_HALT, 1, 1) + FIELD(CXL_MEM_DEV_STS, MEDIA_STATUS, 2, 2) + FIELD(CXL_MEM_DEV_STS, MBOX_READY, 4, 1) + FIELD(CXL_MEM_DEV_STS, RESET_NEEDED, 5, 3) + +struct CXLType3Dev { + /* Private */ + PCIDevice parent_obj; + + /* Properties */ + HostMemoryBackend *hostmem; + HostMemoryBackend *lsa; + uint64_t sn; + + /* State */ + AddressSpace hostmem_as; + CXLComponentState cxl_cstate; + CXLDeviceState cxl_dstate; + + /* DOE */ + DOECap doe_cdat; +}; + +#define TYPE_CXL_TYPE3 "cxl-type3" +OBJECT_DECLARE_TYPE(CXLType3Dev, CXLType3Class, CXL_TYPE3) + +struct CXLType3Class { + /* Private */ + PCIDeviceClass parent_class; + + /* public */ + uint64_t (*get_lsa_size)(CXLType3Dev *ct3d); + + uint64_t (*get_lsa)(CXLType3Dev *ct3d, void *buf, uint64_t size, + uint64_t offset); + void (*set_lsa)(CXLType3Dev *ct3d, const void *buf, uint64_t size, + uint64_t offset); +}; + +MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data, + unsigned size, MemTxAttrs attrs); +MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, + unsigned size, MemTxAttrs attrs); + +#endif diff --git a/include/hw/cxl/cxl_host.h b/include/hw/cxl/cxl_host.h new file mode 100644 index 000000000000..a1b662ce4063 --- /dev/null +++ b/include/hw/cxl/cxl_host.h @@ -0,0 +1,23 @@ +/* + * QEMU CXL Host Setup + * + * Copyright (c) 2022 Huawei + * + * 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 "hw/cxl/cxl.h" +#include "hw/boards.h" + +#ifndef CXL_HOST_H +#define CXL_HOST_H + +void cxl_machine_init(Object *obj, CXLState *state); +void cxl_fmws_link_targets(CXLState *stat, Error **errp); +void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp); + +extern const MemoryRegionOps cfmws_ops; + +#endif diff --git a/include/hw/cxl/cxl_pci.h b/include/hw/cxl/cxl_pci.h new file mode 100644 index 000000000000..01e15ed5b46e --- /dev/null +++ b/include/hw/cxl/cxl_pci.h @@ -0,0 +1,165 @@ +/* + * QEMU CXL PCI interfaces + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_PCI_H +#define CXL_PCI_H + +#include "qemu/compiler.h" + +#define CXL_VENDOR_ID 0x1e98 + +#define PCIE_DVSEC_HEADER1_OFFSET 0x4 /* Offset from start of extend cap */ +#define PCIE_DVSEC_ID_OFFSET 0x8 + +#define PCIE_CXL_DEVICE_DVSEC_LENGTH 0x38 +#define PCIE_CXL1_DEVICE_DVSEC_REVID 0 +#define PCIE_CXL2_DEVICE_DVSEC_REVID 1 + +#define EXTENSIONS_PORT_DVSEC_LENGTH 0x28 +#define EXTENSIONS_PORT_DVSEC_REVID 0 + +#define GPF_PORT_DVSEC_LENGTH 0x10 +#define GPF_PORT_DVSEC_REVID 0 + +#define GPF_DEVICE_DVSEC_LENGTH 0x10 +#define GPF_DEVICE_DVSEC_REVID 0 + +#define PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0 0x14 +#define PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0 1 + +#define REG_LOC_DVSEC_LENGTH 0x24 +#define REG_LOC_DVSEC_REVID 0 + +enum { + PCIE_CXL_DEVICE_DVSEC = 0, + NON_CXL_FUNCTION_MAP_DVSEC = 2, + EXTENSIONS_PORT_DVSEC = 3, + GPF_PORT_DVSEC = 4, + GPF_DEVICE_DVSEC = 5, + PCIE_FLEXBUS_PORT_DVSEC = 7, + REG_LOC_DVSEC = 8, + MLD_DVSEC = 9, + CXL20_MAX_DVSEC +}; + +typedef struct DVSECHeader { + uint32_t cap_hdr; + uint32_t dv_hdr1; + uint16_t dv_hdr2; +} QEMU_PACKED DVSECHeader; +QEMU_BUILD_BUG_ON(sizeof(DVSECHeader) != 10); + +/* + * CXL 2.0 devices must implement certain DVSEC IDs, and can [optionally] + * implement others. + * + * CXL 2.0 Device: 0, [2], 5, 8 + * CXL 2.0 RP: 3, 4, 7, 8 + * CXL 2.0 Upstream Port: [2], 7, 8 + * CXL 2.0 Downstream Port: 3, 4, 7, 8 + */ + +/* CXL 2.0 - 8.1.3 (ID 0001) */ +typedef struct CXLDVSECDevice { + DVSECHeader hdr; + uint16_t cap; + uint16_t ctrl; + uint16_t status; + uint16_t ctrl2; + uint16_t status2; + uint16_t lock; + uint16_t cap2; + uint32_t range1_size_hi; + uint32_t range1_size_lo; + uint32_t range1_base_hi; + uint32_t range1_base_lo; + uint32_t range2_size_hi; + uint32_t range2_size_lo; + uint32_t range2_base_hi; + uint32_t range2_base_lo; +} CXLDVSECDevice; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECDevice) != 0x38); + +/* CXL 2.0 - 8.1.5 (ID 0003) */ +typedef struct CXLDVSECPortExtensions { + DVSECHeader hdr; + uint16_t status; + uint16_t control; + uint8_t alt_bus_base; + uint8_t alt_bus_limit; + uint16_t alt_memory_base; + uint16_t alt_memory_limit; + uint16_t alt_prefetch_base; + uint16_t alt_prefetch_limit; + uint32_t alt_prefetch_base_high; + uint32_t alt_prefetch_limit_high; + uint32_t rcrb_base; + uint32_t rcrb_base_high; +} CXLDVSECPortExtensions; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortExtensions) != 0x28); + +#define PORT_CONTROL_OFFSET 0xc +#define PORT_CONTROL_UNMASK_SBR 1 +#define PORT_CONTROL_ALT_MEMID_EN 4 + +/* CXL 2.0 - 8.1.6 GPF DVSEC (ID 0004) */ +typedef struct CXLDVSECPortGPF { + DVSECHeader hdr; + uint16_t rsvd; + uint16_t phase1_ctrl; + uint16_t phase2_ctrl; +} CXLDVSECPortGPF; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortGPF) != 0x10); + +/* CXL 2.0 - 8.1.7 GPF DVSEC for CXL Device */ +typedef struct CXLDVSECDeviceGPF { + DVSECHeader hdr; + uint16_t phase2_duration; + uint32_t phase2_power; +} CXLDVSECDeviceGPF; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECDeviceGPF) != 0x10); + +/* CXL 2.0 - 8.1.8/8.2.1.3 Flex Bus DVSEC (ID 0007) */ +typedef struct CXLDVSECPortFlexBus { + DVSECHeader hdr; + uint16_t cap; + uint16_t ctrl; + uint16_t status; + uint32_t rcvd_mod_ts_data_phase1; +} CXLDVSECPortFlexBus; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortFlexBus) != 0x14); + +/* CXL 2.0 - 8.1.9 Register Locator DVSEC (ID 0008) */ +typedef struct CXLDVSECRegisterLocator { + DVSECHeader hdr; + uint16_t rsvd; + uint32_t reg0_base_lo; + uint32_t reg0_base_hi; + uint32_t reg1_base_lo; + uint32_t reg1_base_hi; + uint32_t reg2_base_lo; + uint32_t reg2_base_hi; +} CXLDVSECRegisterLocator; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECRegisterLocator) != 0x24); + +/* BAR Equivalence Indicator */ +#define BEI_BAR_10H 0 +#define BEI_BAR_14H 1 +#define BEI_BAR_18H 2 +#define BEI_BAR_1cH 3 +#define BEI_BAR_20H 4 +#define BEI_BAR_24H 5 + +/* Register Block Identifier */ +#define RBI_EMPTY 0 +#define RBI_COMPONENT_REG (1 << 8) +#define RBI_BAR_VIRT_ACL (2 << 8) +#define RBI_CXL_DEVICE_REG (3 << 8) + +#endif diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h index 55a50d3fb042..27cebefc9e71 100644 --- a/include/hw/display/macfb.h +++ b/include/hw/display/macfb.h @@ -15,9 +15,10 @@ #include "exec/memory.h" #include "hw/irq.h" +#include "hw/nubus/nubus.h" +#include "hw/sysbus.h" #include "ui/console.h" #include "qemu/timer.h" -#include "qom/object.h" typedef enum { MACFB_DISPLAY_APPLE_21_COLOR = 0, diff --git a/include/hw/display/xlnx_dp.h b/include/hw/display/xlnx_dp.h index 8ab4733bb854..e86a87f235e1 100644 --- a/include/hw/display/xlnx_dp.h +++ b/include/hw/display/xlnx_dp.h @@ -35,14 +35,20 @@ #include "hw/dma/xlnx_dpdma.h" #include "audio/audio.h" #include "qom/object.h" +#include "hw/ptimer.h" #define AUD_CHBUF_MAX_DEPTH (32 * KiB) #define MAX_QEMU_BUFFER_SIZE (4 * KiB) -#define DP_CORE_REG_ARRAY_SIZE (0x3AF >> 2) +#define DP_CORE_REG_OFFSET (0x0000) +#define DP_CORE_REG_ARRAY_SIZE (0x3B0 >> 2) +#define DP_AVBUF_REG_OFFSET (0xB000) #define DP_AVBUF_REG_ARRAY_SIZE (0x238 >> 2) -#define DP_VBLEND_REG_ARRAY_SIZE (0x1DF >> 2) +#define DP_VBLEND_REG_OFFSET (0xA000) +#define DP_VBLEND_REG_ARRAY_SIZE (0x1E0 >> 2) +#define DP_AUDIO_REG_OFFSET (0xC000) #define DP_AUDIO_REG_ARRAY_SIZE (0x50 >> 2) +#define DP_CONTAINER_SIZE (0xC050) struct PixmanPlane { pixman_format_code_t format; @@ -102,6 +108,8 @@ struct XlnxDPState { */ DPCDState *dpcd; I2CDDCState *edid; + + ptimer_state *vblank; }; #define TYPE_XLNX_DP "xlnx.v-dp" diff --git a/include/hw/dma/sifive_pdma.h b/include/hw/dma/sifive_pdma.h index e319bbd6c40f..8c6cfa7f3250 100644 --- a/include/hw/dma/sifive_pdma.h +++ b/include/hw/dma/sifive_pdma.h @@ -23,6 +23,8 @@ #ifndef SIFIVE_PDMA_H #define SIFIVE_PDMA_H +#include "hw/sysbus.h" + struct sifive_pdma_chan { uint32_t control; uint32_t next_config; diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 7c3b1d0f6cc5..fbe0b1e95619 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -117,7 +117,7 @@ static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, shdr_table = load_at(fd, ehdr->e_shoff, sizeof(struct elf_shdr) * ehdr->e_shnum); if (!shdr_table) { - return ; + return; } if (must_swab) { diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h index 4b7ad77a44f0..7f3259a6300a 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -18,6 +18,8 @@ #define SMBIOS_MAX_TYPE 127 +#define offsetofend(TYPE, MEMBER) \ + (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) /* memory area description, used by type 19 table */ struct smbios_phys_mem_area { @@ -187,6 +189,26 @@ struct smbios_type_4 { uint8_t thread_count; uint16_t processor_characteristics; uint16_t processor_family2; + /* SMBIOS spec 3.0.0, Table 21 */ + uint16_t core_count2; + uint16_t core_enabled2; + uint16_t thread_count2; +} QEMU_PACKED; + +typedef enum smbios_type_4_len_ver { + SMBIOS_TYPE_4_LEN_V28 = offsetofend(struct smbios_type_4, + processor_family2), + SMBIOS_TYPE_4_LEN_V30 = offsetofend(struct smbios_type_4, thread_count2), +} smbios_type_4_len_ver; + +/* 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 */ diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h index 801846befb3b..904eecf62c4c 100644 --- a/include/hw/gpio/aspeed_gpio.h +++ b/include/hw/gpio/aspeed_gpio.h @@ -50,10 +50,24 @@ enum GPIORegType { gpio_reg_input_mask, }; +/* GPIO index mode */ +enum GPIORegIndexType { + gpio_reg_idx_data = 0, + gpio_reg_idx_direction, + gpio_reg_idx_interrupt, + gpio_reg_idx_debounce, + gpio_reg_idx_tolerance, + gpio_reg_idx_cmd_src, + gpio_reg_idx_input_mask, + gpio_reg_idx_reserved, + gpio_reg_idx_new_w_cmd_src, + gpio_reg_idx_new_r_cmd_src, +}; + typedef struct AspeedGPIOReg { uint16_t set_idx; enum GPIORegType type; - } AspeedGPIOReg; +} AspeedGPIOReg; struct AspeedGPIOClass { SysBusDevice parent_obj; @@ -93,4 +107,4 @@ struct AspeedGPIOState { } sets[ASPEED_GPIO_MAX_NR_SETS]; }; -#endif /* _ASPEED_GPIO_H_ */ +#endif /* ASPEED_GPIO_H */ diff --git a/include/hw/gpio/rt_pint.h b/include/hw/gpio/rt_pint.h new file mode 100644 index 000000000000..010997a2aabc --- /dev/null +++ b/include/hw/gpio/rt_pint.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_PINT_H +#define RT_PINT_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_RT_PINT "RT_PINT" +OBJECT_DECLARE_SIMPLE_TYPE(RTPINTState, RT_PINT) + +struct RTPINTState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t ISEL; /* 0x0 */ + uint32_t IENR; /* 0x4 */ + uint32_t SIENR; /* 0x8 */ + uint32_t CIENR; /* 0xc */ + uint32_t IENF; /* 0x10 */ + uint32_t SIENF; /* 0x14 */ + uint32_t CIENF; /* 0x18 */ + uint32_t RISE; /* 0x1c */ + uint32_t FALL; /* 0x20 */ + uint32_t IST; /* 0x24 */ + uint32_t PMCTRL; /* 0x28 */ + uint32_t PMSRC; /* 0x2c */ + uint32_t PMCFG; /* 0x30 */ + + qemu_irq irq[8]; + +}; + +#endif /* RT_PINT_H */ diff --git a/include/hw/hw.h b/include/hw/hw.h index 34377f5309d3..045c1c8b09b3 100644 --- a/include/hw/hw.h +++ b/include/hw/hw.h @@ -5,6 +5,6 @@ #error Cannot include hw/hw.h from user emulation #endif -void QEMU_NORETURN hw_error(const char *fmt, ...) G_GNUC_PRINTF(1, 2); +G_NORETURN void hw_error(const char *fmt, ...) G_GNUC_PRINTF(1, 2); #endif diff --git a/include/hw/hyperv/hyperv-proto.h b/include/hw/hyperv/hyperv-proto.h index 21dc28aee9df..4a2297307b00 100644 --- a/include/hw/hyperv/hyperv-proto.h +++ b/include/hw/hyperv/hyperv-proto.h @@ -24,12 +24,17 @@ #define HV_STATUS_INVALID_PORT_ID 17 #define HV_STATUS_INVALID_CONNECTION_ID 18 #define HV_STATUS_INSUFFICIENT_BUFFERS 19 +#define HV_STATUS_NOT_ACKNOWLEDGED 20 +#define HV_STATUS_NO_DATA 27 /* * Hypercall numbers */ #define HV_POST_MESSAGE 0x005c #define HV_SIGNAL_EVENT 0x005d +#define HV_POST_DEBUG_DATA 0x0069 +#define HV_RETRIEVE_DEBUG_DATA 0x006a +#define HV_RESET_DEBUG_SESSION 0x006b #define HV_HYPERCALL_FAST (1u << 16) /* @@ -127,4 +132,51 @@ struct hyperv_event_flags_page { struct hyperv_event_flags slot[HV_SINT_COUNT]; }; +/* + * Kernel debugger structures + */ + +/* Options flags for hyperv_reset_debug_session */ +#define HV_DEBUG_PURGE_INCOMING_DATA 0x00000001 +#define HV_DEBUG_PURGE_OUTGOING_DATA 0x00000002 +struct hyperv_reset_debug_session_input { + uint32_t options; +} __attribute__ ((__packed__)); + +struct hyperv_reset_debug_session_output { + uint32_t host_ip; + uint32_t target_ip; + uint16_t host_port; + uint16_t target_port; + uint8_t host_mac[6]; + uint8_t target_mac[6]; +} __attribute__ ((__packed__)); + +/* Options for hyperv_post_debug_data */ +#define HV_DEBUG_POST_LOOP 0x00000001 + +struct hyperv_post_debug_data_input { + uint32_t count; + uint32_t options; + /*uint8_t data[HV_HYP_PAGE_SIZE - 2 * sizeof(uint32_t)];*/ +} __attribute__ ((__packed__)); + +struct hyperv_post_debug_data_output { + uint32_t pending_count; +} __attribute__ ((__packed__)); + +/* Options for hyperv_retrieve_debug_data */ +#define HV_DEBUG_RETRIEVE_LOOP 0x00000001 +#define HV_DEBUG_RETRIEVE_TEST_ACTIVITY 0x00000002 + +struct hyperv_retrieve_debug_data_input { + uint32_t count; + uint32_t options; + uint64_t timeout; +} __attribute__ ((__packed__)); + +struct hyperv_retrieve_debug_data_output { + uint32_t retrieved_count; + uint32_t remaining_count; +} __attribute__ ((__packed__)); #endif diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h index a63ee0003c1b..015c3524b1c2 100644 --- a/include/hw/hyperv/hyperv.h +++ b/include/hw/hyperv/hyperv.h @@ -81,4 +81,62 @@ void hyperv_synic_update(CPUState *cs, bool enable, hwaddr msg_page_addr, hwaddr event_page_addr); bool hyperv_is_synic_enabled(void); +/* + * Process HVCALL_RESET_DEBUG_SESSION hypercall. + */ +uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa); +/* + * Process HVCALL_RETREIVE_DEBUG_DATA hypercall. + */ +uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa, + bool fast); +/* + * Process HVCALL_POST_DEBUG_DATA hypercall. + */ +uint16_t hyperv_hcall_post_dbg_data(uint64_t ingpa, uint64_t outgpa, bool fast); + +uint32_t hyperv_syndbg_send(uint64_t ingpa, uint32_t count); +uint32_t hyperv_syndbg_recv(uint64_t ingpa, uint32_t count); +void hyperv_syndbg_set_pending_page(uint64_t ingpa); +uint64_t hyperv_syndbg_query_options(void); + +typedef enum HvSynthDbgMsgType { + HV_SYNDBG_MSG_CONNECTION_INFO, + HV_SYNDBG_MSG_SEND, + HV_SYNDBG_MSG_RECV, + HV_SYNDBG_MSG_SET_PENDING_PAGE, + HV_SYNDBG_MSG_QUERY_OPTIONS +} HvDbgSynthMsgType; + +typedef struct HvSynDbgMsg { + HvDbgSynthMsgType type; + union { + struct { + uint32_t host_ip; + uint16_t host_port; + } connection_info; + struct { + uint64_t buf_gpa; + uint32_t count; + uint32_t pending_count; + bool is_raw; + } send; + struct { + uint64_t buf_gpa; + uint32_t count; + uint32_t options; + uint64_t timeout; + uint32_t retrieved_count; + bool is_raw; + } recv; + struct { + uint64_t buf_gpa; + } pending_page; + struct { + uint64_t options; + } query_options; + } u; +} HvSynDbgMsg; +typedef uint16_t (*HvSynDbgHandler)(void *context, HvSynDbgMsg *msg); +void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context); #endif diff --git a/include/hw/hyperv/vmbus.h b/include/hw/hyperv/vmbus.h index f98bea3888d4..8ea660dd8e6c 100644 --- a/include/hw/hyperv/vmbus.h +++ b/include/hw/hyperv/vmbus.h @@ -223,7 +223,4 @@ int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, void vmbus_unmap_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, unsigned iov_cnt, size_t accessed); -void vmbus_save_req(QEMUFile *f, VMBusChanReq *req); -void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size); - #endif diff --git a/include/hw/i2c/allwinner-i2c.h b/include/hw/i2c/allwinner-i2c.h new file mode 100644 index 000000000000..4f378b86ba19 --- /dev/null +++ b/include/hw/i2c/allwinner-i2c.h @@ -0,0 +1,55 @@ +/* + * Allwinner I2C Bus Serial Interface registers definition + * + * Copyright (C) 2022 Strahinja Jankovic. + * + * This file is derived from IMX I2C controller, + * by Jean-Christophe DUBOIS . + * + * 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 . + * + */ + +#ifndef ALLWINNER_I2C_H +#define ALLWINNER_I2C_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_AW_I2C "allwinner.i2c" +OBJECT_DECLARE_SIMPLE_TYPE(AWI2CState, AW_I2C) + +#define AW_I2C_MEM_SIZE 0x24 + +struct AWI2CState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + I2CBus *bus; + qemu_irq irq; + + uint8_t addr; + uint8_t xaddr; + uint8_t data; + uint8_t cntr; + uint8_t stat; + uint8_t ccr; + uint8_t srst; + uint8_t efr; + uint8_t lcr; +}; + +#endif /* ALLWINNER_I2C_H */ diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h index ad96781e7a84..f54d1e54135c 100644 --- a/include/hw/i2c/arm_sbcon_i2c.h +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -9,8 +9,9 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_I2C_ARM_SBCON_H -#define HW_I2C_ARM_SBCON_H + +#ifndef HW_I2C_ARM_SBCON_I2C_H +#define HW_I2C_ARM_SBCON_I2C_H #include "hw/sysbus.h" #include "hw/i2c/bitbang_i2c.h" @@ -34,4 +35,4 @@ struct ArmSbconI2CState { int in; }; -#endif /* HW_I2C_ARM_SBCON_H */ +#endif /* HW_I2C_ARM_SBCON_I2C_H */ diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h index 4b9be09274c7..adc904d6c1f8 100644 --- a/include/hw/i2c/aspeed_i2c.h +++ b/include/hw/i2c/aspeed_i2c.h @@ -23,16 +23,200 @@ #include "hw/i2c/i2c.h" #include "hw/sysbus.h" +#include "hw/registerfields.h" #include "qom/object.h" #define TYPE_ASPEED_I2C "aspeed.i2c" #define TYPE_ASPEED_2400_I2C TYPE_ASPEED_I2C "-ast2400" #define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500" #define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600" +#define TYPE_ASPEED_1030_I2C TYPE_ASPEED_I2C "-ast1030" OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C) #define ASPEED_I2C_NR_BUSSES 16 #define ASPEED_I2C_MAX_POOL_SIZE 0x800 +#define ASPEED_I2C_OLD_NUM_REG 11 +#define ASPEED_I2C_NEW_NUM_REG 22 + +/* Tx State Machine */ +#define I2CD_TX_STATE_MASK 0xf +#define I2CD_IDLE 0x0 +#define I2CD_MACTIVE 0x8 +#define I2CD_MSTART 0x9 +#define I2CD_MSTARTR 0xa +#define I2CD_MSTOP 0xb +#define I2CD_MTXD 0xc +#define I2CD_MRXACK 0xd +#define I2CD_MRXD 0xe +#define I2CD_MTXACK 0xf +#define I2CD_SWAIT 0x1 +#define I2CD_SRXD 0x4 +#define I2CD_STXACK 0x5 +#define I2CD_STXD 0x6 +#define I2CD_SRXACK 0x7 +#define I2CD_RECOVER 0x3 + +/* I2C Global Register */ +REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */ +REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */ +REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */ + FIELD(I2C_CTRL_GLOBAL, REG_MODE, 2, 1) + FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1) +REG32(I2C_CTRL_NEW_CLK_DIVIDER, 0x10) /* New mode clock divider */ + +/* I2C Old Mode Device (Bus) Register */ +REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control */ + FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */ + SHARED_FIELD(M_SDA_LOCK_EN, 16, 1) + SHARED_FIELD(MULTI_MASTER_DIS, 15, 1) + SHARED_FIELD(M_SCL_DRIVE_EN, 14, 1) + SHARED_FIELD(MSB_STS, 9, 1) + SHARED_FIELD(SDA_DRIVE_IT_EN, 8, 1) + SHARED_FIELD(M_SDA_DRIVE_IT_EN, 7, 1) + SHARED_FIELD(M_HIGH_SPEED_EN, 6, 1) + SHARED_FIELD(DEF_ADDR_EN, 5, 1) + SHARED_FIELD(DEF_ALERT_EN, 4, 1) + SHARED_FIELD(DEF_ARP_EN, 3, 1) + SHARED_FIELD(DEF_GCALL_EN, 2, 1) + SHARED_FIELD(SLAVE_EN, 1, 1) + SHARED_FIELD(MASTER_EN, 0, 1) +REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */ +REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */ +REG32(I2CD_INTR_CTRL, 0x0C) /* I2CD Interrupt Control */ +REG32(I2CD_INTR_STS, 0x10) /* I2CD Interrupt Status */ + SHARED_FIELD(SLAVE_ADDR_MATCH, 31, 1) /* 0: addr1 1: addr2 */ + SHARED_FIELD(SLAVE_ADDR_RX_PENDING, 29, 1) + SHARED_FIELD(SLAVE_INACTIVE_TIMEOUT, 15, 1) + SHARED_FIELD(SDA_DL_TIMEOUT, 14, 1) + SHARED_FIELD(BUS_RECOVER_DONE, 13, 1) + SHARED_FIELD(SMBUS_ALERT, 12, 1) /* Bus [0-3] only */ + FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1) /* Removed */ + FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1) /* Removed */ + FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1) /* Removed */ + FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1) /* Removed */ + FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1) /* use RX_DONE */ + SHARED_FIELD(SCL_TIMEOUT, 6, 1) + SHARED_FIELD(ABNORMAL, 5, 1) + SHARED_FIELD(NORMAL_STOP, 4, 1) + SHARED_FIELD(ARBIT_LOSS, 3, 1) + SHARED_FIELD(RX_DONE, 2, 1) + SHARED_FIELD(TX_NAK, 1, 1) + SHARED_FIELD(TX_ACK, 0, 1) +REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */ + SHARED_FIELD(SDA_OE, 28, 1) + SHARED_FIELD(SDA_O, 27, 1) + SHARED_FIELD(SCL_OE, 26, 1) + SHARED_FIELD(SCL_O, 25, 1) + SHARED_FIELD(TX_TIMING, 23, 2) + SHARED_FIELD(TX_STATE, 19, 4) + SHARED_FIELD(SCL_LINE_STS, 18, 1) + SHARED_FIELD(SDA_LINE_STS, 17, 1) + SHARED_FIELD(BUS_BUSY_STS, 16, 1) + SHARED_FIELD(SDA_OE_OUT_DIR, 15, 1) + SHARED_FIELD(SDA_O_OUT_DIR, 14, 1) + SHARED_FIELD(SCL_OE_OUT_DIR, 13, 1) + SHARED_FIELD(SCL_O_OUT_DIR, 12, 1) + SHARED_FIELD(BUS_RECOVER_CMD_EN, 11, 1) + SHARED_FIELD(S_ALT_EN, 10, 1) + /* Command Bits */ + SHARED_FIELD(RX_DMA_EN, 9, 1) + SHARED_FIELD(TX_DMA_EN, 8, 1) + SHARED_FIELD(RX_BUFF_EN, 7, 1) + SHARED_FIELD(TX_BUFF_EN, 6, 1) + SHARED_FIELD(M_STOP_CMD, 5, 1) + SHARED_FIELD(M_S_RX_CMD_LAST, 4, 1) + SHARED_FIELD(M_RX_CMD, 3, 1) + SHARED_FIELD(S_TX_CMD, 2, 1) + SHARED_FIELD(M_TX_CMD, 1, 1) + SHARED_FIELD(M_START_CMD, 0, 1) +REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */ + SHARED_FIELD(SLAVE_DEV_ADDR1, 0, 7) +REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */ + SHARED_FIELD(RX_COUNT, 24, 5) + SHARED_FIELD(RX_SIZE, 16, 5) + SHARED_FIELD(TX_COUNT, 9, 5) + FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */ +REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */ + SHARED_FIELD(RX_BUF, 8, 8) + SHARED_FIELD(TX_BUF, 0, 8) +REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */ +REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */ + +/* I2C New Mode Device (Bus) Register */ +REG32(I2CC_FUN_CTRL, 0x0) + FIELD(I2CC_FUN_CTRL, RB_EARLY_DONE_EN, 22, 1) + FIELD(I2CC_FUN_CTRL, DMA_DIS_AUTO_RECOVER, 21, 1) + FIELD(I2CC_FUN_CTRL, S_SAVE_ADDR, 20, 1) + FIELD(I2CC_FUN_CTRL, M_PKT_RETRY_CNT, 18, 2) + /* 17:0 shared with I2CD_FUN_CTRL[17:0] */ +REG32(I2CC_AC_TIMING, 0x04) +REG32(I2CC_MS_TXRX_BYTE_BUF, 0x08) + /* 31:16 shared with I2CD_CMD[31:16] */ + /* 15:0 shared with I2CD_BYTE_BUF[15:0] */ +REG32(I2CC_POOL_CTRL, 0x0c) + /* 31:0 shared with I2CD_POOL_CTRL[31:0] */ +REG32(I2CM_INTR_CTRL, 0x10) +REG32(I2CM_INTR_STS, 0x14) + FIELD(I2CM_INTR_STS, PKT_STATE, 28, 4) + FIELD(I2CM_INTR_STS, PKT_CMD_TIMEOUT, 18, 1) + FIELD(I2CM_INTR_STS, PKT_CMD_FAIL, 17, 1) + FIELD(I2CM_INTR_STS, PKT_CMD_DONE, 16, 1) + FIELD(I2CM_INTR_STS, BUS_RECOVER_FAIL, 15, 1) + /* 14:0 shared with I2CD_INTR_STS[14:0] */ +REG32(I2CM_CMD, 0x18) + FIELD(I2CM_CMD, W1_CTRL, 31, 1) + FIELD(I2CM_CMD, PKT_DEV_ADDR, 24, 7) + FIELD(I2CM_CMD, HS_MASTER_MODE_LSB, 17, 3) + FIELD(I2CM_CMD, PKT_OP_EN, 16, 1) + /* 15:0 shared with I2CD_CMD[15:0] */ +REG32(I2CM_DMA_LEN, 0x1c) + FIELD(I2CM_DMA_LEN, RX_BUF_LEN_W1T, 31, 1) + FIELD(I2CM_DMA_LEN, RX_BUF_LEN, 16, 11) + FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1) + FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11) +REG32(I2CS_INTR_CTRL, 0x20) + FIELD(I2CS_INTR_CTRL, PKT_CMD_FAIL, 17, 1) + FIELD(I2CS_INTR_CTRL, PKT_CMD_DONE, 16, 1) +REG32(I2CS_INTR_STS, 0x24) + /* 31:29 shared with I2CD_INTR_STS[31:29] */ + FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2) + FIELD(I2CS_INTR_STS, SLAVE_ADDR3_NAK, 22, 1) + FIELD(I2CS_INTR_STS, SLAVE_ADDR2_NAK, 21, 1) + FIELD(I2CS_INTR_STS, SLAVE_ADDR1_NAK, 20, 1) + FIELD(I2CS_INTR_STS, SLAVE_ADDR_INDICATOR, 18, 2) + FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1) + FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1) + /* 14:0 shared with I2CD_INTR_STS[14:0] */ + FIELD(I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1) +REG32(I2CS_CMD, 0x28) + FIELD(I2CS_CMD, W1_CTRL, 31, 1) + FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2) + FIELD(I2CS_CMD, PKT_MODE_EN, 16, 1) + FIELD(I2CS_CMD, AUTO_NAK_INACTIVE_ADDR, 15, 1) + FIELD(I2CS_CMD, AUTO_NAK_ACTIVE_ADDR, 14, 1) + /* 13:0 shared with I2CD_CMD[13:0] */ +REG32(I2CS_DMA_LEN, 0x2c) + FIELD(I2CS_DMA_LEN, RX_BUF_LEN_W1T, 31, 1) + FIELD(I2CS_DMA_LEN, RX_BUF_LEN, 16, 11) + FIELD(I2CS_DMA_LEN, TX_BUF_LEN_W1T, 15, 1) + FIELD(I2CS_DMA_LEN, TX_BUF_LEN, 0, 11) +REG32(I2CM_DMA_TX_ADDR, 0x30) + FIELD(I2CM_DMA_TX_ADDR, ADDR, 0, 31) +REG32(I2CM_DMA_RX_ADDR, 0x34) + FIELD(I2CM_DMA_RX_ADDR, ADDR, 0, 31) +REG32(I2CS_DMA_TX_ADDR, 0x38) + FIELD(I2CS_DMA_TX_ADDR, ADDR, 0, 31) +REG32(I2CS_DMA_RX_ADDR, 0x3c) + FIELD(I2CS_DMA_RX_ADDR, ADDR, 0, 31) +REG32(I2CS_DEV_ADDR, 0x40) +REG32(I2CM_DMA_LEN_STS, 0x48) + FIELD(I2CM_DMA_LEN_STS, RX_LEN, 16, 13) + FIELD(I2CM_DMA_LEN_STS, TX_LEN, 0, 13) +REG32(I2CS_DMA_LEN_STS, 0x4c) + FIELD(I2CS_DMA_LEN_STS, RX_LEN, 16, 13) + FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13) +REG32(I2CC_DMA_ADDR, 0x50) +REG32(I2CC_DMA_LEN, 0x54) struct AspeedI2CState; @@ -43,21 +227,16 @@ struct AspeedI2CBus { struct AspeedI2CState *controller; + /* slave mode */ + I2CSlave *slave; + MemoryRegion mr; I2CBus *bus; uint8_t id; qemu_irq irq; - uint32_t ctrl; - uint32_t timing[2]; - uint32_t intr_ctrl; - uint32_t intr_status; - uint32_t cmd; - uint32_t buf; - uint32_t pool_ctrl; - uint32_t dma_addr; - uint32_t dma_len; + uint32_t regs[ASPEED_I2C_NEW_NUM_REG]; }; struct AspeedI2CState { @@ -68,6 +247,7 @@ struct AspeedI2CState { uint32_t intr_status; uint32_t ctrl_global; + uint32_t new_clk_divider; MemoryRegion pool_iomem; uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE]; @@ -76,6 +256,11 @@ struct AspeedI2CState { AddressSpace dram_as; }; +#define TYPE_ASPEED_I2C_BUS_SLAVE "aspeed.i2c.slave" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CBusSlave, ASPEED_I2C_BUS_SLAVE) +struct AspeedI2CBusSlave { + I2CSlave i2c; +}; struct AspeedI2CClass { SysBusDeviceClass parent_class; @@ -93,6 +278,104 @@ struct AspeedI2CClass { }; +static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s) +{ + return FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, REG_MODE); +} + +static inline bool aspeed_i2c_bus_pkt_mode_en(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_OP_EN); + } + return false; +} + +static inline uint32_t aspeed_i2c_bus_ctrl_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CC_FUN_CTRL; + } + return R_I2CD_FUN_CTRL; +} + +static inline uint32_t aspeed_i2c_bus_cmd_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CM_CMD; + } + return R_I2CD_CMD; +} + +static inline uint32_t aspeed_i2c_bus_dev_addr_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CS_DEV_ADDR; + } + return R_I2CD_DEV_ADDR; +} + +static inline uint32_t aspeed_i2c_bus_intr_ctrl_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CM_INTR_CTRL; + } + return R_I2CD_INTR_CTRL; +} + +static inline uint32_t aspeed_i2c_bus_intr_sts_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CM_INTR_STS; + } + return R_I2CD_INTR_STS; +} + +static inline uint32_t aspeed_i2c_bus_pool_ctrl_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CC_POOL_CTRL; + } + return R_I2CD_POOL_CTRL; +} + +static inline uint32_t aspeed_i2c_bus_byte_buf_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CC_MS_TXRX_BYTE_BUF; + } + return R_I2CD_BYTE_BUF; +} + +static inline uint32_t aspeed_i2c_bus_dma_len_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CC_DMA_LEN; + } + return R_I2CD_DMA_LEN; +} + +static inline uint32_t aspeed_i2c_bus_dma_addr_offset(AspeedI2CBus *bus) +{ + if (aspeed_i2c_is_new_mode(bus->controller)) { + return R_I2CC_DMA_ADDR; + } + return R_I2CD_DMA_ADDR; +} + +static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus) +{ + return SHARED_ARRAY_FIELD_EX32(bus->regs, aspeed_i2c_bus_ctrl_offset(bus), + MASTER_EN); +} + +static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus) +{ + uint32_t ctrl_reg = aspeed_i2c_bus_ctrl_offset(bus); + return SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, MASTER_EN) || + SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, SLAVE_EN); +} + I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr); #endif /* ASPEED_I2C_H */ diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 5ca3b708c0be..9b9581d23097 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -12,6 +12,7 @@ enum i2c_event { I2C_START_RECV, I2C_START_SEND, + I2C_START_SEND_ASYNC, I2C_FINISH, I2C_NACK /* Masker NACKed a receive byte. */ }; @@ -28,6 +29,9 @@ struct I2CSlaveClass { /* Master to slave. Returns non-zero for a NAK, 0 for success. */ int (*send)(I2CSlave *s, uint8_t data); + /* Master to slave (asynchronous). Receiving slave must call i2c_ack(). */ + void (*send_async)(I2CSlave *s, uint8_t data); + /* * Slave to master. This cannot fail, the device should always * return something here. @@ -69,13 +73,25 @@ struct I2CNode { QLIST_ENTRY(I2CNode) next; }; +typedef struct I2CPendingMaster I2CPendingMaster; + +struct I2CPendingMaster { + QEMUBH *bh; + QSIMPLEQ_ENTRY(I2CPendingMaster) entry; +}; + typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList; +typedef QSIMPLEQ_HEAD(I2CPendingMasters, I2CPendingMaster) I2CPendingMasters; struct I2CBus { BusState qbus; I2CNodeList current_devs; + I2CPendingMasters pending_masters; uint8_t saved_address; bool broadcast; + + /* Set from slave currently mastering the bus. */ + QEMUBH *bh; }; I2CBus *i2c_init_bus(DeviceState *parent, const char *name); @@ -115,9 +131,23 @@ int i2c_start_recv(I2CBus *bus, uint8_t address); */ int i2c_start_send(I2CBus *bus, uint8_t address); +/** + * i2c_start_send_async: start an asynchronous 'send' transfer on an I2C bus. + * + * @bus: #I2CBus to be used + * @address: address of the slave + * + * Return: 0 on success, -1 on error + */ +int i2c_start_send_async(I2CBus *bus, uint8_t address); + void i2c_end_transfer(I2CBus *bus); void i2c_nack(I2CBus *bus); +void i2c_ack(I2CBus *bus); +void i2c_bus_master(I2CBus *bus, QEMUBH *bh); +void i2c_bus_release(I2CBus *bus); int i2c_send(I2CBus *bus, uint8_t data); +int i2c_send_async(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, I2CNodeList *current_devs); diff --git a/include/hw/i2c/i2c_mux_pca954x.h b/include/hw/i2c/i2c_mux_pca954x.h index 8aaf9bbc3942..3dd25ec98309 100644 --- a/include/hw/i2c/i2c_mux_pca954x.h +++ b/include/hw/i2c/i2c_mux_pca954x.h @@ -1,5 +1,5 @@ -#ifndef QEMU_I2C_MUX_PCA954X -#define QEMU_I2C_MUX_PCA954X +#ifndef QEMU_I2C_MUX_PCA954X_H +#define QEMU_I2C_MUX_PCA954X_H #include "hw/i2c/i2c.h" diff --git a/include/hw/i2c/npcm7xx_smbus.h b/include/hw/i2c/npcm7xx_smbus.h index 7d59ee917ebc..3555e6836fb3 100644 --- a/include/hw/i2c/npcm7xx_smbus.h +++ b/include/hw/i2c/npcm7xx_smbus.h @@ -68,7 +68,7 @@ typedef enum NPCM7xxSMBusStatus { * @rx_cur: The current position of rx_fifo. * @status: The current status of the SMBus. */ -typedef struct NPCM7xxSMBusState { +struct NPCM7xxSMBusState { SysBusDevice parent; MemoryRegion iomem; @@ -104,10 +104,9 @@ typedef struct NPCM7xxSMBusState { uint8_t rx_cur; NPCM7xxSMBusStatus status; -} NPCM7xxSMBusState; +}; #define TYPE_NPCM7XX_SMBUS "npcm7xx-smbus" -#define NPCM7XX_SMBUS(obj) OBJECT_CHECK(NPCM7xxSMBusState, (obj), \ - TYPE_NPCM7XX_SMBUS) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxSMBusState, NPCM7XX_SMBUS) #endif /* NPCM7XX_SMBUS_H */ diff --git a/include/hw/i2c/pmbus_device.h b/include/hw/i2c/pmbus_device.h index 0f4d6b3fada0..93f5d57c9dc6 100644 --- a/include/hw/i2c/pmbus_device.h +++ b/include/hw/i2c/pmbus_device.h @@ -155,6 +155,7 @@ enum pmbus_registers { PMBUS_MFR_MAX_TEMP_1 = 0xC0, /* R/W word */ PMBUS_MFR_MAX_TEMP_2 = 0xC1, /* R/W word */ PMBUS_MFR_MAX_TEMP_3 = 0xC2, /* R/W word */ + PMBUS_IDLE_STATE = 0xFF, }; /* STATUS_WORD */ @@ -527,6 +528,12 @@ int pmbus_page_config(PMBusDevice *pmdev, uint8_t page_index, uint64_t flags); */ void pmbus_check_limits(PMBusDevice *pmdev); +/** + * Enter an idle state where only the PMBUS_ERR_BYTE will be returned + * indefinitely until a new command is issued. + */ +void pmbus_idle(PMBusDevice *pmdev); + extern const VMStateDescription vmstate_pmbus_device; #define VMSTATE_PMBUS_DEVICE(_field, _state) { \ diff --git a/include/hw/i2c/rt_flexcomm_i2c.h b/include/hw/i2c/rt_flexcomm_i2c.h new file mode 100644 index 000000000000..c5e670ab9b98 --- /dev/null +++ b/include/hw/i2c/rt_flexcomm_i2c.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_FLEXCOMM_I2C_H +#define RT_FLEXCOMM_I2C_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "qom/object.h" +#include "qemu/bitops.h" +#include "hw/i2c/i2c.h" + +#define TYPE_RT_FLEXCOMMI2C "rt.flexcomm.i2c" +OBJECT_DECLARE_SIMPLE_TYPE(RTFLEXCOMMI2CState, RT_FLEXCOMMI2C) + +enum { + MST_IDLE = 0, + MST_RCV_RD, + MST_TRS_RD, + MST_NAK_ADDR, + MST_NAK_DATA, +}; + +#define PERSEL_MASK 0x7 +#define I2CPRESENT_MASK (1U<<6) + +/* I2C_CFG */ +#define SLVEN_OFFSET 1U +#define SLVEN_LENGTH 1U +#define SLVEN_MASK (((1<*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + uint32_t ID; + + uint32_t I2C_CFG; + uint32_t I2C_STAT; + uint32_t I2C_INTENSET; + uint32_t I2C_INTENCLR; + uint32_t I2C_TIMEOUT; + uint32_t I2C_CLKDIV; + uint32_t I2C_INTSTAT; + uint32_t I2C_MSTCTL; + uint32_t I2C_MSTTIME; + uint32_t I2C_MSTDAT; + uint32_t I2C_SLVCTL; + uint32_t I2C_SLVDAT; + uint32_t I2C_SLVADR0; + uint32_t I2C_SLVADR1; + uint32_t I2C_SLVADR2; + uint32_t I2C_SLVADR3; + uint32_t I2C_SLVQUAL0; + uint32_t I2C_MONRXDAT; + uint32_t PSELID; + + I2CBus *bus; + + qemu_irq irq; +}; + +#endif diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index c175e7e71816..968b6648b3a4 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -226,6 +226,6 @@ static inline int apic_get_bit(uint32_t *tab, int index) return !!(tab[i] & mask); } -APICCommonClass *apic_get_class(void); +APICCommonClass *apic_get_class(Error **errp); #endif /* QEMU_APIC_INTERNAL_H */ diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h index 23ee8e371ba1..222781e8b996 100644 --- a/include/hw/i386/ich9.h +++ b/include/hw/i386/ich9.h @@ -5,12 +5,8 @@ #include "hw/sysbus.h" #include "hw/i386/pc.h" #include "hw/isa/apm.h" -#include "hw/pci/pci.h" -#include "hw/pci/pcie_host.h" -#include "hw/pci/pci_bridge.h" #include "hw/acpi/acpi.h" #include "hw/acpi/ich9.h" -#include "hw/pci/pci_bus.h" #include "qom/object.h" void ich9_lpc_set_irq(void *opaque, int irq_num, int level); diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 3b5ac869db6e..46d973e62975 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -58,7 +58,6 @@ typedef struct VTDContextEntry VTDContextEntry; typedef struct VTDContextCacheEntry VTDContextCacheEntry; typedef struct VTDAddressSpace VTDAddressSpace; typedef struct VTDIOTLBEntry VTDIOTLBEntry; -typedef struct VTDBus VTDBus; typedef union VTD_IR_TableEntry VTD_IR_TableEntry; typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress; typedef struct VTDPASIDDirEntry VTDPASIDDirEntry; @@ -98,11 +97,13 @@ struct VTDPASIDEntry { struct VTDAddressSpace { PCIBus *bus; uint8_t devfn; + uint32_t pasid; AddressSpace as; IOMMUMemoryRegion iommu; MemoryRegion root; /* The root container of the device */ MemoryRegion nodmar; /* The alias of shared nodmar MR */ MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */ + MemoryRegion iommu_ir_fault; /* Interrupt region for catching fault */ IntelIOMMUState *iommu_state; VTDContextCacheEntry context_cache_entry; QLIST_ENTRY(VTDAddressSpace) next; @@ -111,15 +112,10 @@ struct VTDAddressSpace { IOVATree *iova_tree; /* Traces mapped IOVA ranges */ }; -struct VTDBus { - PCIBus* bus; /* A reference to the bus to provide translation for */ - /* A table of VTDAddressSpace objects indexed by devfn */ - VTDAddressSpace *dev_as[]; -}; - struct VTDIOTLBEntry { uint64_t gfn; uint16_t domain_id; + uint32_t pasid; uint64_t slpte; uint64_t mask; uint8_t access_flags; @@ -145,7 +141,7 @@ enum { /* Interrupt Remapping Table Entry Definition */ union VTD_IR_TableEntry { struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint32_t __reserved_1:8; /* Reserved 1 */ uint32_t vector:8; /* Interrupt Vector */ uint32_t irte_mode:1; /* IRTE Mode */ @@ -172,7 +168,7 @@ union VTD_IR_TableEntry { #endif uint32_t dest_id; /* Destination ID */ uint16_t source_id; /* Source-ID */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint64_t __reserved_2:44; /* Reserved 2 */ uint64_t sid_vtype:2; /* Source-ID Validation Type */ uint64_t sid_q:2; /* Source-ID Qualifier */ @@ -191,7 +187,7 @@ union VTD_IR_TableEntry { /* Programming format for MSI/MSI-X addresses */ union VTD_IR_MSIAddress { struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint32_t __head:12; /* Should always be: 0x0fee */ uint32_t index_l:15; /* Interrupt index bit 14-0 */ uint32_t int_mode:1; /* Interrupt format */ @@ -253,8 +249,8 @@ struct IntelIOMMUState { uint32_t context_cache_gen; /* Should be in [1,MAX] */ GHashTable *iotlb; /* IOTLB */ - GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */ - VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */ + GHashTable *vtd_address_spaces; /* VTD address spaces */ + VTDAddressSpace *vtd_as_cache[VTD_PCI_BUS_MAX]; /* VTD address space cache */ /* list of registered notifiers */ QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers; @@ -267,6 +263,8 @@ struct IntelIOMMUState { bool buggy_eim; /* Force buggy EIM unless eim=off */ uint8_t aw_bits; /* Host/IOVA address width (in bits) */ bool dma_drain; /* Whether DMA r/w draining enabled */ + bool dma_translation; /* Whether DMA translation supported */ + bool pasid; /* Whether to support PASID */ /* * Protects IOMMU states in general. Currently it protects the @@ -278,6 +276,7 @@ struct IntelIOMMUState { /* Find the VTD Address space associated with the given bus pointer, * create a new one if none exists */ -VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn); +VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, + int devfn, unsigned int pasid); #endif diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h index 9880443cc7e9..e8ff338d7fad 100644 --- a/include/hw/i386/ioapic_internal.h +++ b/include/hw/i386/ioapic_internal.h @@ -23,6 +23,7 @@ #define QEMU_IOAPIC_INTERNAL_H #include "exec/memory.h" +#include "hw/i386/ioapic.h" #include "hw/sysbus.h" #include "qemu/notify.h" #include "qom/object.h" diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index efcbd926fd43..fad97a891dcb 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -67,8 +67,6 @@ #define PCIE_ECAM_SIZE 0x10000000 /* Machine type options */ -#define MICROVM_MACHINE_PIT "pit" -#define MICROVM_MACHINE_PIC "pic" #define MICROVM_MACHINE_RTC "rtc" #define MICROVM_MACHINE_PCIE "pcie" #define MICROVM_MACHINE_IOAPIC2 "ioapic2" @@ -86,8 +84,6 @@ struct MicrovmMachineState { X86MachineState parent; /* Machine type options */ - OnOffAuto pic; - OnOffAuto pit; OnOffAuto rtc; OnOffAuto pcie; OnOffAuto ioapic2; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 1a27de9c8b35..991f905f5d25 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -14,6 +14,7 @@ #include "qom/object.h" #include "hw/i386/sgx-epc.h" #include "hw/firmware/smbios.h" +#include "hw/cxl/cxl.h" #define HPET_INTCAP "hpet-intcap" @@ -46,7 +47,6 @@ typedef struct PCMachineState { bool acpi_build_enabled; bool smbus_enabled; bool sata_enabled; - bool pit_enabled; bool hpet_enabled; bool i8042_enabled; bool default_bus_bypass_iommu; @@ -56,6 +56,7 @@ typedef struct PCMachineState { hwaddr memhp_io_base; SGXEPCState sgx_epc; + CXLState cxl_devices_state; } PCMachineState; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" @@ -64,7 +65,6 @@ typedef struct PCMachineState { #define PC_MACHINE_VMPORT "vmport" #define PC_MACHINE_SMBUS "smbus" #define PC_MACHINE_SATA "sata" -#define PC_MACHINE_PIT "pit" #define PC_MACHINE_I8042 "i8042" #define PC_MACHINE_MAX_FW_SIZE "max-fw-size" #define PC_MACHINE_SMBIOS_EP "smbios-entry-point-type" @@ -106,7 +106,6 @@ struct PCMachineClass { bool rsdp_in_ram; int legacy_acpi_table_size; unsigned acpi_data_size; - bool do_not_add_smb_acpi; int pci_root_uid; /* SMBIOS compat: */ @@ -119,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; @@ -128,6 +128,9 @@ struct PCMachineClass { /* create kvmclock device even when KVM PV features are not exposed */ bool kvmclock_create_always; + + /* skip passing an rng seed for legacy machines */ + bool legacy_no_rng_seed; }; #define TYPE_PC_MACHINE "generic-pc-machine" @@ -160,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, @@ -168,19 +172,13 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISADevice **rtc_state, bool create_fdctrl, uint32_t hpet_irqs); -void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, BusState *ide0, BusState *ide1, ISADevice *s); void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus); -void pc_pci_device_init(PCIBus *pci_bus); - -typedef void (*cpu_set_smm_t)(int smm, void *arg); void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs); -ISADevice *pc_find_fdc0(void); - /* port92.c */ #define PORT92_A20_LINE "a20" @@ -202,6 +200,15 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, /* sgx.c */ void pc_machine_init_sgx_epc(PCMachineState *pcms); +extern GlobalProperty pc_compat_7_2[]; +extern const size_t pc_compat_7_2_len; + +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; + extern GlobalProperty pc_compat_6_2[]; extern const size_t pc_compat_6_2_len; @@ -286,14 +293,6 @@ extern const size_t pc_compat_1_5_len; extern GlobalProperty pc_compat_1_4[]; extern const size_t pc_compat_1_4_len; -/* Helper for setting model-id for CPU models that changed model-id - * depending on QEMU versions up to QEMU 2.4. - */ -#define PC_CPU_MODEL_IDS(v) \ - { "qemu32-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ - { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ - { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, }, - #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ { \ @@ -312,5 +311,4 @@ extern const size_t pc_compat_1_4_len; } \ type_init(pc_machine_init_##suffix) -extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); #endif diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h index 581fac389a63..3e00efd870c9 100644 --- a/include/hw/i386/sgx-epc.h +++ b/include/hw/i386/sgx-epc.h @@ -12,6 +12,7 @@ #ifndef QEMU_SGX_EPC_H #define QEMU_SGX_EPC_H +#include "hw/qdev-core.h" #include "hw/i386/hostmem-epc.h" #define TYPE_SGX_EPC "sgx-epc" diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h index 5ba0c056d60c..8d8d53b18b62 100644 --- a/include/hw/i386/x86-iommu.h +++ b/include/hw/i386/x86-iommu.h @@ -21,7 +21,6 @@ #define HW_I386_X86_IOMMU_H #include "hw/sysbus.h" -#include "hw/pci/pci.h" #include "hw/pci/msi.h" #include "qom/object.h" @@ -87,7 +86,7 @@ struct X86IOMMUIrq { struct X86IOMMU_MSIMessage { union { struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint32_t __addr_head:12; /* 0xfee */ uint32_t dest:8; uint32_t __reserved:8; @@ -108,7 +107,7 @@ struct X86IOMMU_MSIMessage { }; union { struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint16_t trigger_mode:1; uint16_t level:1; uint16_t __resved:3; diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 916cc325eeb1..62fa5774f849 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; @@ -65,6 +68,8 @@ struct X86MachineState { OnOffAuto smm; OnOffAuto acpi; + OnOffAuto pit; + OnOffAuto pic; char *oem_id; char *oem_table_id; @@ -84,6 +89,8 @@ struct X86MachineState { #define X86_MACHINE_SMM "smm" #define X86_MACHINE_ACPI "acpi" +#define X86_MACHINE_PIT "pit" +#define X86_MACHINE_PIC "pic" #define X86_MACHINE_OEM_ID "x-oem-id" #define X86_MACHINE_OEM_TABLE_ID "x-oem-table-id" #define X86_MACHINE_BUS_LOCK_RATELIMIT "bus-lock-ratelimit" @@ -119,7 +126,8 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware, void x86_load_linux(X86MachineState *x86ms, FWCfgState *fw_cfg, int acpi_data_size, - bool pvh_enabled); + bool pvh_enabled, + bool legacy_no_rng_seed); bool x86_machine_is_smm_enabled(const X86MachineState *x86ms); bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms); @@ -140,4 +148,7 @@ void gsi_handler(void *opaque, int n, int level); void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); DeviceState *ioapic_init_secondary(GSIState *gsi_state); +/* pc_sysfw.c */ +void x86_firmware_configure(void *ptr, int size); + #endif diff --git a/include/hw/ide.h b/include/hw/ide.h index c5ce5da4f478..60f1f4f71494 100644 --- a/include/hw/ide.h +++ b/include/hw/ide.h @@ -8,9 +8,6 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, DriveInfo *hd0, DriveInfo *hd1); -/* ide-pci.c */ -int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux); - /* ide-mmio.c */ void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1); diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 97e7e59dc58c..fc0aa81a88b9 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,9 @@ struct IDEState { uint8_t select; uint8_t status; + bool io8; + bool reset_reverts; + /* set for lba48 access */ uint8_t lba48; BlockBackend *blk; diff --git a/include/hw/ide/pci.h b/include/hw/ide/pci.h index d8384e1c4220..2a6284acac32 100644 --- a/include/hw/ide/pci.h +++ b/include/hw/ide/pci.h @@ -2,7 +2,7 @@ #define HW_IDE_PCI_H #include "hw/ide/internal.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "qom/object.h" #define BM_STATUS_DMAING 0x01 diff --git a/include/hw/ide/piix.h b/include/hw/ide/piix.h new file mode 100644 index 000000000000..ef3ef3d62d75 --- /dev/null +++ b/include/hw/ide/piix.h @@ -0,0 +1,7 @@ +#ifndef HW_IDE_PIIX_H +#define HW_IDE_PIIX_H + +#define TYPE_PIIX3_IDE "piix3-ide" +#define TYPE_PIIX4_IDE "piix4-ide" + +#endif /* HW_IDE_PIIX_H */ diff --git a/include/hw/input/i8042.h b/include/hw/input/i8042.h index e070f546e49d..9fb3f8d78754 100644 --- a/include/hw/input/i8042.h +++ b/include/hw/input/i8042.h @@ -9,17 +9,85 @@ #define HW_INPUT_I8042_H #include "hw/isa/isa.h" +#include "hw/sysbus.h" +#include "hw/input/ps2.h" #include "qom/object.h" +#define I8042_KBD_IRQ 0 +#define I8042_MOUSE_IRQ 1 + +typedef struct KBDState { + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ + uint8_t status; + uint8_t mode; + uint8_t outport; + uint32_t migration_flags; + uint32_t obsrc; + bool outport_present; + bool extended_state; + bool extended_state_loaded; + /* Bitmask of devices with data available. */ + uint8_t pending; + uint8_t obdata; + uint8_t cbdata; + uint8_t pending_tmp; + PS2KbdState ps2kbd; + PS2MouseState ps2mouse; + QEMUTimer *throttle_timer; + + qemu_irq irqs[2]; + qemu_irq a20_out; + hwaddr mask; +} KBDState; + +/* + * QEMU interface: + * + Named GPIO input "ps2-kbd-input-irq": set to 1 if the downstream PS2 + * keyboard device has asserted its irq + * + Named GPIO input "ps2-mouse-input-irq": set to 1 if the downstream PS2 + * mouse device has asserted its irq + * + Named GPIO output "a20": A20 line for x86 PCs + * + Unnamed GPIO output 0-1: i8042 output irqs for keyboard (0) or mouse (1) + */ + #define TYPE_I8042 "i8042" OBJECT_DECLARE_SIMPLE_TYPE(ISAKBDState, I8042) +struct ISAKBDState { + ISADevice parent_obj; + + KBDState kbd; + bool kbd_throttle; + MemoryRegion io[2]; + uint8_t kbd_irq; + uint8_t mouse_irq; +}; + +/* + * QEMU interface: + * + sysbus MMIO region 0: MemoryRegion defining the command/status/data + * registers (access determined by mask property and access type) + * + Named GPIO input "ps2-kbd-input-irq": set to 1 if the downstream PS2 + * keyboard device has asserted its irq + * + Named GPIO input "ps2-mouse-input-irq": set to 1 if the downstream PS2 + * mouse device has asserted its irq + * + Unnamed GPIO output 0-1: i8042 output irqs for keyboard (0) or mouse (1) + */ + +#define TYPE_I8042_MMIO "i8042-mmio" +OBJECT_DECLARE_SIMPLE_TYPE(MMIOKBDState, I8042_MMIO) + +struct MMIOKBDState { + SysBusDevice parent_obj; + + KBDState kbd; + uint32_t size; + MemoryRegion region; +}; + #define I8042_A20_LINE "a20" -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, - MemoryRegion *region, ram_addr_t size, - hwaddr mask); void i8042_isa_mouse_fake_event(ISAKBDState *isa); void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out); diff --git a/include/hw/input/lasips2.h b/include/hw/input/lasips2.h index 0cd7b59064a9..01911c50f9b1 100644 --- a/include/hw/input/lasips2.h +++ b/include/hw/input/lasips2.h @@ -4,13 +4,77 @@ * Copyright (c) 2019 Sven Schnelle * */ + +/* + * QEMU interface: + * + sysbus MMIO region 0: MemoryRegion defining the LASI PS2 keyboard + * registers + * + sysbus MMIO region 1: MemoryRegion defining the LASI PS2 mouse + * registers + * + sysbus IRQ 0: LASI PS2 output irq + * + Named GPIO input "lasips2-port-input-irq[0..1]": set to 1 if the downstream + * LASIPS2Port has asserted its irq + */ + #ifndef HW_INPUT_LASIPS2_H #define HW_INPUT_LASIPS2_H #include "exec/hwaddr.h" +#include "hw/sysbus.h" +#include "hw/input/ps2.h" -#define TYPE_LASIPS2 "lasips2" +#define TYPE_LASIPS2_PORT "lasips2-port" +OBJECT_DECLARE_TYPE(LASIPS2Port, LASIPS2PortDeviceClass, LASIPS2_PORT) + +struct LASIPS2PortDeviceClass { + DeviceClass parent; + + DeviceRealize parent_realize; +}; + +typedef struct LASIPS2State LASIPS2State; + +struct LASIPS2Port { + DeviceState parent_obj; + + LASIPS2State *lasips2; + MemoryRegion reg; + PS2State *ps2dev; + uint8_t id; + uint8_t control; + uint8_t buf; + bool loopback_rbne; + qemu_irq irq; +}; -void lasips2_init(MemoryRegion *address_space, hwaddr base, qemu_irq irq); +#define TYPE_LASIPS2_KBD_PORT "lasips2-kbd-port" +OBJECT_DECLARE_SIMPLE_TYPE(LASIPS2KbdPort, LASIPS2_KBD_PORT) + +struct LASIPS2KbdPort { + LASIPS2Port parent_obj; + + PS2KbdState kbd; +}; + +#define TYPE_LASIPS2_MOUSE_PORT "lasips2-mouse-port" +OBJECT_DECLARE_SIMPLE_TYPE(LASIPS2MousePort, LASIPS2_MOUSE_PORT) + +struct LASIPS2MousePort { + LASIPS2Port parent_obj; + + PS2MouseState mouse; +}; + +struct LASIPS2State { + SysBusDevice parent_obj; + + LASIPS2KbdPort kbd_port; + LASIPS2MousePort mouse_port; + uint8_t int_status; + qemu_irq irq; +}; + +#define TYPE_LASIPS2 "lasips2" +OBJECT_DECLARE_SIMPLE_TYPE(LASIPS2State, LASIPS2) #endif /* HW_INPUT_LASIPS2_H */ diff --git a/include/hw/input/lm832x.h b/include/hw/input/lm832x.h index 2a58ccf89163..e0e5d5ef20e1 100644 --- a/include/hw/input/lm832x.h +++ b/include/hw/input/lm832x.h @@ -18,8 +18,8 @@ * with this program; if not, see . */ -#ifndef HW_INPUT_LM832X -#define HW_INPUT_LM832X +#ifndef HW_INPUT_LM832X_H +#define HW_INPUT_LM832X_H #define TYPE_LM8323 "lm8323" diff --git a/include/hw/input/pl050.h b/include/hw/input/pl050.h new file mode 100644 index 000000000000..89ec4fafc9a0 --- /dev/null +++ b/include/hw/input/pl050.h @@ -0,0 +1,59 @@ +/* + * Arm PrimeCell PL050 Keyboard / Mouse Interface + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#ifndef HW_PL050_H +#define HW_PL050_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "hw/input/ps2.h" +#include "hw/irq.h" + +struct PL050DeviceClass { + SysBusDeviceClass parent_class; + + DeviceRealize parent_realize; +}; + +#define TYPE_PL050 "pl050" +OBJECT_DECLARE_TYPE(PL050State, PL050DeviceClass, PL050) + +struct PL050State { + SysBusDevice parent_obj; + + MemoryRegion iomem; + PS2State *ps2dev; + uint32_t cr; + uint32_t clk; + uint32_t last; + int pending; + qemu_irq irq; + bool is_mouse; +}; + +#define TYPE_PL050_KBD_DEVICE "pl050_keyboard" +OBJECT_DECLARE_SIMPLE_TYPE(PL050KbdState, PL050_KBD_DEVICE) + +struct PL050KbdState { + PL050State parent_obj; + + PS2KbdState kbd; +}; + +#define TYPE_PL050_MOUSE_DEVICE "pl050_mouse" +OBJECT_DECLARE_SIMPLE_TYPE(PL050MouseState, PL050_MOUSE_DEVICE) + +struct PL050MouseState { + PL050State parent_obj; + + PS2MouseState mouse; +}; + +#endif diff --git a/include/hw/input/ps2.h b/include/hw/input/ps2.h index 35d983897a52..cd61a634c395 100644 --- a/include/hw/input/ps2.h +++ b/include/hw/input/ps2.h @@ -25,28 +25,89 @@ #ifndef HW_PS2_H #define HW_PS2_H +#include "hw/sysbus.h" + #define PS2_MOUSE_BUTTON_LEFT 0x01 #define PS2_MOUSE_BUTTON_RIGHT 0x02 #define PS2_MOUSE_BUTTON_MIDDLE 0x04 #define PS2_MOUSE_BUTTON_SIDE 0x08 #define PS2_MOUSE_BUTTON_EXTRA 0x10 -typedef struct PS2State PS2State; +struct PS2DeviceClass { + SysBusDeviceClass parent_class; + + ResettablePhases parent_phases; +}; + +/* + * PS/2 buffer size. Keep 256 bytes for compatibility with + * older QEMU versions. + */ +#define PS2_BUFFER_SIZE 256 + +typedef struct { + uint8_t data[PS2_BUFFER_SIZE]; + int rptr, wptr, cwptr, count; +} PS2Queue; + +/* Output IRQ */ +#define PS2_DEVICE_IRQ 0 + +struct PS2State { + SysBusDevice parent_obj; + + PS2Queue queue; + int32_t write_cmd; + qemu_irq irq; +}; + +#define TYPE_PS2_DEVICE "ps2-device" +OBJECT_DECLARE_TYPE(PS2State, PS2DeviceClass, PS2_DEVICE) + +struct PS2KbdState { + PS2State parent_obj; + + int scan_enabled; + int translate; + int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ + int ledstate; + bool need_high_bit; + unsigned int modifiers; /* bitmask of MOD_* constants above */ +}; + +#define TYPE_PS2_KBD_DEVICE "ps2-kbd" +OBJECT_DECLARE_SIMPLE_TYPE(PS2KbdState, PS2_KBD_DEVICE) + +struct PS2MouseState { + PS2State parent_obj; + + uint8_t mouse_status; + uint8_t mouse_resolution; + uint8_t mouse_sample_rate; + uint8_t mouse_wrap; + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ + uint8_t mouse_detect_state; + int mouse_dx; /* current values, needed for 'poll' mode */ + int mouse_dy; + int mouse_dz; + int mouse_dw; + uint8_t mouse_buttons; +}; + +#define TYPE_PS2_MOUSE_DEVICE "ps2-mouse" +OBJECT_DECLARE_SIMPLE_TYPE(PS2MouseState, PS2_MOUSE_DEVICE) /* ps2.c */ -void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); -void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); -void ps2_write_mouse(void *, int val); -void ps2_write_keyboard(void *, int val); +void ps2_write_mouse(PS2MouseState *s, int val); +void ps2_write_keyboard(PS2KbdState *s, int val); uint32_t ps2_read_data(PS2State *s); void ps2_queue_noirq(PS2State *s, int b); -void ps2_raise_irq(PS2State *s); void ps2_queue(PS2State *s, int b); void ps2_queue_2(PS2State *s, int b1, int b2); void ps2_queue_3(PS2State *s, int b1, int b2, int b3); void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4); -void ps2_keyboard_set_translation(void *opaque, int mode); -void ps2_mouse_fake_event(void *opaque); +void ps2_keyboard_set_translation(PS2KbdState *s, int mode); +void ps2_mouse_fake_event(PS2MouseState *s); int ps2_queue_empty(PS2State *s); #endif /* HW_PS2_H */ diff --git a/include/hw/input/tsc2xxx.h b/include/hw/input/tsc2xxx.h index 5b76ebc17761..00eca17674e3 100644 --- a/include/hw/input/tsc2xxx.h +++ b/include/hw/input/tsc2xxx.h @@ -30,12 +30,12 @@ uWireSlave *tsc2102_init(qemu_irq pint); uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav); I2SCodec *tsc210x_codec(uWireSlave *chip); uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len); -void tsc210x_set_transform(uWireSlave *chip, MouseTransformInfo *info); +void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info); void tsc210x_key_event(uWireSlave *chip, int key, int down); /* tsc2005.c */ void *tsc2005_init(qemu_irq pintdav); uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len); -void tsc2005_set_transform(void *opaque, MouseTransformInfo *info); +void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info); #endif diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index fc38e4b7dca4..ab5182a28a2c 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -38,7 +38,12 @@ #define GICV3_LPI_INTID_START 8192 +/* + * The redistributor in GICv3 has two 64KB frames per CPU; in + * GICv4 it has four 64KB frames per CPU. + */ #define GICV3_REDIST_SIZE 0x20000 +#define GICV4_REDIST_SIZE 0x40000 /* Number of SGI target-list bits */ #define GICV3_TARGETLIST_BITS 16 @@ -46,11 +51,6 @@ /* Maximum number of list registers (architectural limit) */ #define GICV3_LR_MAX 16 -/* Minimum BPR for Secure, or when security not enabled */ -#define GIC_MIN_BPR 0 -/* Minimum BPR for Nonsecure when security is enabled */ -#define GIC_MIN_BPR_NS (GIC_MIN_BPR + 1) - /* For some distributor fields we want to model the array of 32-bit * register values which hold various bitmaps corresponding to enabled, * pending, etc bits. These macros and functions facilitate that; the @@ -174,6 +174,9 @@ struct GICv3CPUState { uint32_t gicr_igrpmodr0; uint32_t gicr_nsacr; uint8_t gicr_ipriorityr[GIC_INTERNAL]; + /* VLPI_base page registers */ + uint64_t gicr_vpropbaser; + uint64_t gicr_vpendbaser; /* CPU interface */ uint64_t icc_sre_el1; @@ -198,6 +201,8 @@ struct GICv3CPUState { int num_list_regs; int vpribits; /* number of virtual priority bits */ int vprebits; /* number of virtual preemption bits */ + int pribits; /* number of physical priority bits */ + int prebits; /* number of physical preemption bits */ /* Current highest priority pending interrupt for this CPU. * This is cached information that can be recalculated from the @@ -211,6 +216,9 @@ struct GICv3CPUState { */ PendingIrq hpplpi; + /* Cached information recalculated from vLPI tables in guest memory */ + PendingIrq hppvlpi; + /* This is temporary working state, to avoid a malloc in gicv3_update() */ bool seenbetter; }; @@ -240,6 +248,7 @@ struct GICv3State { uint32_t revision; bool lpi_enable; bool security_extn; + bool force_8bit_prio; bool irq_reset_nonsecure; bool gicd_no_migration_shift_bug; @@ -272,6 +281,8 @@ struct GICv3State { uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)]; GICv3CPUState *cpu; + /* List of all ITSes connected to this GIC */ + GPtrArray *itslist; }; #define GICV3_BITMAP_ACCESSORS(BMP) \ diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h index 0f130494dd33..a11a0f665457 100644 --- a/include/hw/intc/arm_gicv3_its_common.h +++ b/include/hw/intc/arm_gicv3_its_common.h @@ -78,6 +78,7 @@ struct GICv3ITSState { TableDesc dt; TableDesc ct; + TableDesc vpet; CmdQDesc cq; Error *migration_blocker; @@ -88,6 +89,24 @@ typedef struct GICv3ITSState GICv3ITSState; void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops, const MemoryRegionOps *tops); +/* + * The ITS should call this when it is realized to add itself + * to its GIC's list of connected ITSes. + */ +static inline void gicv3_add_its(GICv3State *s, DeviceState *its) +{ + g_ptr_array_add(s->itslist, its); +} + +/* + * The ITS can use this for operations that must be performed on + * every ITS connected to the same GIC that it is + */ +static inline void gicv3_foreach_its(GICv3State *s, GFunc func, void *opaque) +{ + g_ptr_array_foreach(s->itslist, func, opaque); +} + #define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common" typedef struct GICv3ITSCommonClass GICv3ITSCommonClass; DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSCommonClass, diff --git a/include/hw/intc/exynos4210_combiner.h b/include/hw/intc/exynos4210_combiner.h new file mode 100644 index 000000000000..bd207a7e6e47 --- /dev/null +++ b/include/hw/intc/exynos4210_combiner.h @@ -0,0 +1,57 @@ +/* + * Samsung exynos4210 Interrupt Combiner + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. + * All rights reserved. + * + * Evgeny Voevodin + * + * 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 . + */ + +#ifndef HW_INTC_EXYNOS4210_COMBINER_H +#define HW_INTC_EXYNOS4210_COMBINER_H + +#include "hw/sysbus.h" + +/* + * State for each output signal of internal combiner + */ +typedef struct CombinerGroupState { + uint8_t src_mask; /* 1 - source enabled, 0 - disabled */ + uint8_t src_pending; /* Pending source interrupts before masking */ +} CombinerGroupState; + +#define TYPE_EXYNOS4210_COMBINER "exynos4210.combiner" +OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210CombinerState, EXYNOS4210_COMBINER) + +/* Number of groups and total number of interrupts for the internal combiner */ +#define IIC_NGRP 64 +#define IIC_NIRQ (IIC_NGRP * 8) +#define IIC_REGSET_SIZE 0x41 + +struct Exynos4210CombinerState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + struct CombinerGroupState group[IIC_NGRP]; + uint32_t reg_set[IIC_REGSET_SIZE]; + uint32_t icipsr[2]; + uint32_t external; /* 1 means that this combiner is external */ + + qemu_irq output_irq[IIC_NGRP]; +}; + +#endif diff --git a/include/hw/intc/exynos4210_gic.h b/include/hw/intc/exynos4210_gic.h new file mode 100644 index 000000000000..f64c4069c6dc --- /dev/null +++ b/include/hw/intc/exynos4210_gic.h @@ -0,0 +1,43 @@ +/* + * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. + * All rights reserved. + * + * Evgeny Voevodin + * + * 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 . + */ +#ifndef HW_INTC_EXYNOS4210_GIC_H +#define HW_INTC_EXYNOS4210_GIC_H + +#include "hw/sysbus.h" + +#define TYPE_EXYNOS4210_GIC "exynos4210.gic" +OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210GicState, EXYNOS4210_GIC) + +#define EXYNOS4210_GIC_NCPUS 2 + +struct Exynos4210GicState { + SysBusDevice parent_obj; + + MemoryRegion cpu_container; + MemoryRegion dist_container; + MemoryRegion cpu_alias[EXYNOS4210_GIC_NCPUS]; + MemoryRegion dist_alias[EXYNOS4210_GIC_NCPUS]; + uint32_t num_cpu; + DeviceState *gic; +}; + +#endif diff --git a/include/hw/intc/goldfish_pic.h b/include/hw/intc/goldfish_pic.h index e9d552f79682..3e7958036724 100644 --- a/include/hw/intc/goldfish_pic.h +++ b/include/hw/intc/goldfish_pic.h @@ -10,6 +10,8 @@ #ifndef HW_INTC_GOLDFISH_PIC_H #define HW_INTC_GOLDFISH_PIC_H +#include "hw/sysbus.h" + #define TYPE_GOLDFISH_PIC "goldfish_pic" OBJECT_DECLARE_SIMPLE_TYPE(GoldfishPICState, GOLDFISH_PIC) diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h new file mode 100644 index 000000000000..15b8c999f6a9 --- /dev/null +++ b/include/hw/intc/loongarch_extioi.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch 3A5000 ext interrupt controller definitions + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" + +#ifndef LOONGARCH_EXTIOI_H +#define LOONGARCH_EXTIOI_H + +#define LS3A_INTC_IP 8 +#define EXTIOI_IRQS (256) +#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) +/* map to ipnum per 32 irqs */ +#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) +#define EXTIOI_IRQS_COREMAP_SIZE 256 +#define EXTIOI_IRQS_NODETYPE_COUNT 16 +#define EXTIOI_IRQS_GROUP_COUNT 8 + +#define APIC_OFFSET 0x400 +#define APIC_BASE (0x1000ULL + APIC_OFFSET) + +#define EXTIOI_NODETYPE_START (0x4a0 - APIC_OFFSET) +#define EXTIOI_NODETYPE_END (0x4c0 - APIC_OFFSET) +#define EXTIOI_IPMAP_START (0x4c0 - APIC_OFFSET) +#define EXTIOI_IPMAP_END (0x4c8 - APIC_OFFSET) +#define EXTIOI_ENABLE_START (0x600 - APIC_OFFSET) +#define EXTIOI_ENABLE_END (0x620 - APIC_OFFSET) +#define EXTIOI_BOUNCE_START (0x680 - APIC_OFFSET) +#define EXTIOI_BOUNCE_END (0x6a0 - APIC_OFFSET) +#define EXTIOI_ISR_START (0x700 - APIC_OFFSET) +#define EXTIOI_ISR_END (0x720 - APIC_OFFSET) +#define EXTIOI_COREISR_START (0x800 - APIC_OFFSET) +#define EXTIOI_COREISR_END (0xB20 - APIC_OFFSET) +#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) +#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) + +#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi" +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI) +struct LoongArchExtIOI { + SysBusDevice parent_obj; + /* hardware state */ + uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2]; + uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT]; + uint32_t isr[EXTIOI_IRQS / 32]; + uint32_t coreisr[LOONGARCH_MAX_VCPUS][EXTIOI_IRQS_GROUP_COUNT]; + uint32_t enable[EXTIOI_IRQS / 32]; + uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4]; + uint32_t coremap[EXTIOI_IRQS / 4]; + uint32_t sw_pending[EXTIOI_IRQS / 32]; + DECLARE_BITMAP(sw_isr[LOONGARCH_MAX_VCPUS][LS3A_INTC_IP], EXTIOI_IRQS); + uint8_t sw_ipmap[EXTIOI_IRQS_IPMAP_SIZE]; + uint8_t sw_coremap[EXTIOI_IRQS]; + qemu_irq parent_irq[LOONGARCH_MAX_VCPUS][LS3A_INTC_IP]; + qemu_irq irq[EXTIOI_IRQS]; + MemoryRegion extioi_iocsr_mem[LOONGARCH_MAX_VCPUS]; + MemoryRegion extioi_system_mem; +}; +#endif /* LOONGARCH_EXTIOI_H */ diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h new file mode 100644 index 000000000000..0ee48fca5509 --- /dev/null +++ b/include/hw/intc/loongarch_ipi.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch ipi interrupt header files + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LOONGARCH_IPI_H +#define HW_LOONGARCH_IPI_H + +#include "hw/sysbus.h" + +/* Mainy used by iocsr read and write */ +#define SMP_IPI_MAILBOX 0x1000ULL +#define CORE_STATUS_OFF 0x0 +#define CORE_EN_OFF 0x4 +#define CORE_SET_OFF 0x8 +#define CORE_CLEAR_OFF 0xc +#define CORE_BUF_20 0x20 +#define CORE_BUF_28 0x28 +#define CORE_BUF_30 0x30 +#define CORE_BUF_38 0x38 +#define IOCSR_IPI_SEND 0x40 +#define IOCSR_MAIL_SEND 0x48 +#define IOCSR_ANY_SEND 0x158 + +#define MAIL_SEND_ADDR (SMP_IPI_MAILBOX + IOCSR_MAIL_SEND) +#define MAIL_SEND_OFFSET 0 +#define ANY_SEND_OFFSET (IOCSR_ANY_SEND - IOCSR_MAIL_SEND) + +#define MAX_IPI_CORE_NUM 4 +#define MAX_IPI_MBX_NUM 4 + +#define TYPE_LOONGARCH_IPI "loongarch_ipi" +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI) + +typedef struct IPICore { + uint32_t status; + uint32_t en; + uint32_t set; + uint32_t clear; + /* 64bit buf divide into 2 32bit buf */ + uint32_t buf[MAX_IPI_MBX_NUM * 2]; + qemu_irq irq; +} IPICore; + +struct LoongArchIPI { + SysBusDevice parent_obj; + MemoryRegion ipi_iocsr_mem[MAX_IPI_CORE_NUM]; + MemoryRegion ipi64_iocsr_mem[MAX_IPI_CORE_NUM]; +}; + +#endif diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h new file mode 100644 index 000000000000..b8586fb3b6f6 --- /dev/null +++ b/include/hw/intc/loongarch_pch_msi.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch 7A1000 I/O interrupt controller definitions + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "hw/sysbus.h" + +#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi" +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI) + +/* MSI irq start from 32 to 255 */ +#define PCH_MSI_IRQ_START 32 +#define PCH_MSI_IRQ_END 255 +#define PCH_MSI_IRQ_NUM 224 + +struct LoongArchPCHMSI { + SysBusDevice parent_obj; + qemu_irq *pch_msi_irq; + MemoryRegion msi_mmio; + /* irq base passed to upper extioi intc */ + unsigned int irq_base; + unsigned int irq_num; +}; diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h new file mode 100644 index 000000000000..d5437e88f289 --- /dev/null +++ b/include/hw/intc/loongarch_pch_pic.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch 7A1000 I/O interrupt controller definitions + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "hw/sysbus.h" + +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic" +#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC) + +#define PCH_PIC_INT_ID_VAL 0x7000000UL +#define PCH_PIC_INT_ID_VER 0x1UL + +#define PCH_PIC_INT_ID_LO 0x00 +#define PCH_PIC_INT_ID_HI 0x04 +#define PCH_PIC_INT_MASK_LO 0x20 +#define PCH_PIC_INT_MASK_HI 0x24 +#define PCH_PIC_HTMSI_EN_LO 0x40 +#define PCH_PIC_HTMSI_EN_HI 0x44 +#define PCH_PIC_INT_EDGE_LO 0x60 +#define PCH_PIC_INT_EDGE_HI 0x64 +#define PCH_PIC_INT_CLEAR_LO 0x80 +#define PCH_PIC_INT_CLEAR_HI 0x84 +#define PCH_PIC_AUTO_CTRL0_LO 0xc0 +#define PCH_PIC_AUTO_CTRL0_HI 0xc4 +#define PCH_PIC_AUTO_CTRL1_LO 0xe0 +#define PCH_PIC_AUTO_CTRL1_HI 0xe4 +#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100 +#define PCH_PIC_ROUTE_ENTRY_END 0x13f +#define PCH_PIC_HTMSI_VEC_OFFSET 0x200 +#define PCH_PIC_HTMSI_VEC_END 0x23f +#define PCH_PIC_INT_STATUS_LO 0x3a0 +#define PCH_PIC_INT_STATUS_HI 0x3a4 +#define PCH_PIC_INT_POL_LO 0x3e0 +#define PCH_PIC_INT_POL_HI 0x3e4 + +#define STATUS_LO_START 0 +#define STATUS_HI_START 0x4 +#define POL_LO_START 0x40 +#define POL_HI_START 0x44 +struct LoongArchPCHPIC { + SysBusDevice parent_obj; + qemu_irq parent_irq[64]; + uint64_t int_mask; /*0x020 interrupt mask register*/ + uint64_t htmsi_en; /*0x040 1=msi*/ + uint64_t intedge; /*0x060 edge=1 level =0*/ + uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/ + uint64_t auto_crtl0; /*0x0c0*/ + uint64_t auto_crtl1; /*0x0e0*/ + uint64_t last_intirr; /* edge detection */ + uint64_t intirr; /* 0x380 interrupt request register */ + uint64_t intisr; /* 0x3a0 interrupt service register */ + /* + * 0x3e0 interrupt level polarity selection + * register 0 for high level trigger + */ + uint64_t int_polarity; + + uint8_t route_entry[64]; /*0x100 - 0x138*/ + uint8_t htmsi_vector[64]; /*0x200 - 0x238*/ + + MemoryRegion iomem32_low; + MemoryRegion iomem32_high; + MemoryRegion iomem8; + unsigned int irq_num; +}; diff --git a/include/hw/intc/nios2_vic.h b/include/hw/intc/nios2_vic.h new file mode 100644 index 000000000000..5c975a2ac476 --- /dev/null +++ b/include/hw/intc/nios2_vic.h @@ -0,0 +1,66 @@ +/* + * Vectored Interrupt Controller for nios2 processor + * + * Copyright (c) 2022 Neuroblade + * + * Interface: + * QOM property "cpu": link to the Nios2 CPU (must be set) + * Unnamed GPIO inputs 0..NIOS2_VIC_MAX_IRQ-1: input IRQ lines + * IRQ should be connected to nios2 IRQ0. + * + * Reference: "Embedded Peripherals IP User Guide + * for Intel® Quartus® Prime Design Suite: 21.4" + * Chapter 38 "Vectored Interrupt Controller Core" + * See: https://www.intel.com/content/www/us/en/docs/programmable/683130/21-4/vectored-interrupt-controller-core.html + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_INTC_NIOS2_VIC_H +#define HW_INTC_NIOS2_VIC_H + +#include "hw/sysbus.h" + +#define TYPE_NIOS2_VIC "nios2-vic" +OBJECT_DECLARE_SIMPLE_TYPE(Nios2VIC, NIOS2_VIC) + +#define NIOS2_VIC_MAX_IRQ 32 + +struct Nios2VIC { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + qemu_irq output_int; + + /* properties */ + CPUState *cpu; + MemoryRegion csr; + + uint32_t int_config[NIOS2_VIC_MAX_IRQ]; + uint32_t vic_config; + uint32_t int_raw_status; + uint32_t int_enable; + uint32_t sw_int; + uint32_t vic_status; + uint32_t vec_tbl_base; + uint32_t vec_tbl_addr; +}; + +#endif /* HW_INTC_NIOS2_VIC_H */ diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h index 22dd5e5ac2c9..4d82e9a3c6b1 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 229bd08d2540..693415eb6def 100644 --- a/include/hw/intc/riscv_aclint.h +++ b/include/hw/intc/riscv_aclint.h @@ -31,6 +31,9 @@ typedef struct RISCVAclintMTimerState { /*< private >*/ SysBusDevice parent_obj; + uint64_t time_delta; + uint64_t *timecmp; + QEMUTimer **timers; /*< public >*/ MemoryRegion mmio; diff --git a/include/hw/intc/rx_icu.h b/include/hw/intc/rx_icu.h index 7f5889b36f45..b23504f3dd19 100644 --- a/include/hw/intc/rx_icu.h +++ b/include/hw/intc/rx_icu.h @@ -73,4 +73,4 @@ struct RXICUState { #define TYPE_RX_ICU "rx-icu" OBJECT_DECLARE_SIMPLE_TYPE(RXICUState, RX_ICU) -#endif /* RX_ICU_H */ +#endif /* HW_INTC_RX_ICU_H */ diff --git a/include/hw/intc/sifive_plic.h b/include/hw/intc/sifive_plic.h index 134cf39a96bd..d3f45ec24816 100644 --- a/include/hw/intc/sifive_plic.h +++ b/include/hw/intc/sifive_plic.h @@ -33,7 +33,6 @@ DECLARE_INSTANCE_CHECKER(SiFivePLICState, SIFIVE_PLIC, typedef enum PLICMode { PLICMode_U, PLICMode_S, - PLICMode_H, PLICMode_M } PLICMode; diff --git a/include/hw/irq.h b/include/hw/irq.h index dc7abf199e36..645b73d25123 100644 --- a/include/hw/irq.h +++ b/include/hw/irq.h @@ -46,11 +46,6 @@ void qemu_free_irq(qemu_irq irq); /* Returns a new IRQ with opposite polarity. */ qemu_irq qemu_irq_invert(qemu_irq irq); -/* Returns a new IRQ which feeds into both the passed IRQs. - * It's probably better to use the TYPE_SPLIT_IRQ device instead. - */ -qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2); - /* For internal use in qtest. Similar to qemu_irq_split, but operating on an existing vector of qemu_irq. */ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n); diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 034d706ba167..6c8a8a92cb4c 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -16,20 +16,6 @@ OBJECT_DECLARE_TYPE(ISADevice, ISADeviceClass, ISA_DEVICE) #define TYPE_ISA_BUS "ISA" OBJECT_DECLARE_SIMPLE_TYPE(ISABus, ISA_BUS) -#define TYPE_APPLE_SMC "isa-applesmc" -#define APPLESMC_MAX_DATA_LENGTH 32 -#define APPLESMC_PROP_IO_BASE "iobase" - -static inline uint16_t applesmc_port(void) -{ - Object *obj = object_resolve_path_type("", TYPE_APPLE_SMC, NULL); - - if (obj) { - return object_property_get_uint(obj, APPLESMC_PROP_IO_BASE, NULL); - } - return 0; -} - #define TYPE_ISADMA "isa-dma" typedef struct IsaDmaClass IsaDmaClass; @@ -64,7 +50,6 @@ struct IsaDmaClass { struct ISADeviceClass { DeviceClass parent_class; - void (*build_aml)(ISADevice *dev, Aml *scope); }; struct ISABus { @@ -144,6 +129,4 @@ static inline ISABus *isa_bus_from_device(ISADevice *d) return ISA_BUS(qdev_get_parent_bus(DEVICE(d))); } -#define TYPE_PIIX4_PCI_DEVICE "piix4-isa" - #endif diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index 56ac141be381..e273cd38dcf5 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -1,13 +1,12 @@ #ifndef HW_VT82C686_H #define HW_VT82C686_H -#include "hw/pci/pci.h" #define TYPE_VT82C686B_ISA "vt82c686b-isa" -#define TYPE_VT82C686B_PM "vt82c686b-pm" +#define TYPE_VT82C686B_USB_UHCI "vt82c686b-usb-uhci" #define TYPE_VT8231_ISA "vt8231-isa" -#define TYPE_VT8231_PM "vt8231-pm" #define TYPE_VIA_AC97 "via-ac97" +#define TYPE_VIA_IDE "via-ide" #define TYPE_VIA_MC97 "via-mc97" void via_isa_set_irq(PCIDevice *d, int n, int level); diff --git a/include/hw/loader.h b/include/hw/loader.h index 5572108ba5e5..70248e0da779 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -40,8 +40,8 @@ ssize_t load_image_size(const char *filename, void *addr, size_t size); * * Returns the size of the loaded image on success, -1 otherwise. */ -int load_image_targphys_as(const char *filename, - hwaddr addr, uint64_t max_sz, AddressSpace *as); +ssize_t load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as); /**load_targphys_hex_as: * @filename: Path to the .hex file @@ -53,14 +53,15 @@ int load_image_targphys_as(const char *filename, * * Returns the size of the loaded .hex file on success, -1 otherwise. */ -int load_targphys_hex_as(const char *filename, hwaddr *entry, AddressSpace *as); +ssize_t load_targphys_hex_as(const char *filename, hwaddr *entry, + AddressSpace *as); /** load_image_targphys: * Same as load_image_targphys_as(), but doesn't allow the caller to specify * an AddressSpace. */ -int load_image_targphys(const char *filename, hwaddr, - uint64_t max_sz); +ssize_t load_image_targphys(const char *filename, hwaddr, + uint64_t max_sz); /** * load_image_mr: load an image into a memory region @@ -73,7 +74,7 @@ int load_image_targphys(const char *filename, hwaddr, * If the file is larger than the memory region's size the call will fail. * Returns -1 on failure, or the size of the file. */ -int load_image_mr(const char *filename, MemoryRegion *mr); +ssize_t load_image_mr(const char *filename, MemoryRegion *mr); /* This is the limit on the maximum uncompressed image size that * load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents @@ -81,9 +82,9 @@ int load_image_mr(const char *filename, MemoryRegion *mr); */ #define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20) -int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, - uint8_t **buffer); -int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz); +ssize_t load_image_gzipped_buffer(const char *filename, uint64_t max_sz, + uint8_t **buffer); +ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz); #define ELF_LOAD_FAILED -1 #define ELF_LOAD_NOT_ELF -2 @@ -183,8 +184,8 @@ ssize_t load_elf(const char *filename, */ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp); -int load_aout(const char *filename, hwaddr addr, int max_sz, - int bswap_needed, hwaddr target_page_size); +ssize_t load_aout(const char *filename, hwaddr addr, int max_sz, + int bswap_needed, hwaddr target_page_size); #define LOAD_UIMAGE_LOADADDR_INVALID (-1) @@ -205,19 +206,19 @@ int load_aout(const char *filename, hwaddr addr, int max_sz, * * Returns the size of the loaded image on success, -1 otherwise. */ -int load_uimage_as(const char *filename, hwaddr *ep, - hwaddr *loadaddr, int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque, AddressSpace *as); +ssize_t load_uimage_as(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as); /** load_uimage: * Same as load_uimage_as(), but doesn't allow the caller to specify an * AddressSpace. */ -int load_uimage(const char *filename, hwaddr *ep, - hwaddr *loadaddr, int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque); +ssize_t load_uimage(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque); /** * load_ramdisk_as: @@ -232,15 +233,15 @@ int load_uimage(const char *filename, hwaddr *ep, * * Returns the size of the loaded image on success, -1 otherwise. */ -int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, - AddressSpace *as); +ssize_t load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, + AddressSpace *as); /** * load_ramdisk: * Same as load_ramdisk_as(), but doesn't allow the caller to specify * an AddressSpace. */ -int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz); +ssize_t load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz); ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen); @@ -253,9 +254,9 @@ void pstrcpy_targphys(const char *name, extern bool option_rom_has_mr; extern bool rom_file_has_mr; -int rom_add_file(const char *file, const char *fw_dir, - hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr, AddressSpace *as); +ssize_t rom_add_file(const char *file, const char *fw_dir, + hwaddr addr, int32_t bootindex, + bool option_rom, MemoryRegion *mr, AddressSpace *as); MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, size_t max_len, hwaddr addr, const char *fw_file_name, @@ -336,8 +337,8 @@ void hmp_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_blob_fixed_as(_f, _b, _l, _a, _as) \ rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as, true) -int rom_add_vga(const char *file); -int rom_add_option(const char *file, int32_t bootindex); +ssize_t rom_add_vga(const char *file); +ssize_t rom_add_option(const char *file, int32_t bootindex); /* This is the usual maximum in uboot, so if a uImage overflows this, it would * overflow on real hardware too. */ diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h new file mode 100644 index 000000000000..f5f818894e83 --- /dev/null +++ b/include/hw/loongarch/virt.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Definitions for loongarch board emulation. + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LOONGARCH_H +#define HW_LOONGARCH_H + +#include "target/loongarch/cpu.h" +#include "hw/boards.h" +#include "qemu/queue.h" +#include "hw/intc/loongarch_ipi.h" +#include "hw/block/flash.h" + +#define LOONGARCH_MAX_VCPUS 4 + +#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) +#define VIRT_FLASH_SECTOR_SIZE (128 * KiB) +#define VIRT_FLASH_BASE 0x1d000000UL +#define VIRT_FLASH_SIZE (16 * MiB) + +#define VIRT_LOWMEM_BASE 0 +#define VIRT_LOWMEM_SIZE 0x10000000 +#define VIRT_HIGHMEM_BASE 0x90000000 +#define VIRT_GED_EVT_ADDR 0x100e0000 +#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) + +struct LoongArchMachineState { + /*< private >*/ + MachineState parent_obj; + + IPICore ipi_core[MAX_IPI_CORE_NUM]; + MemoryRegion lowmem; + MemoryRegion highmem; + MemoryRegion isa_io; + MemoryRegion bios; + bool bios_loaded; + /* State for other subsystems/APIs: */ + FWCfgState *fw_cfg; + Notifier machine_done; + OnOffAuto acpi; + char *oem_id; + char *oem_table_id; + DeviceState *acpi_ged; + int fdt_size; + DeviceState *platform_bus_dev; + PCIBus *pci_bus; + PFlashCFI01 *flash; +}; + +#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE) +bool loongarch_is_acpi_enabled(LoongArchMachineState *lams); +void loongarch_acpi_setup(LoongArchMachineState *lams); +#endif diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index cf8f59be44f9..acf887c83d98 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/mips/bios.h b/include/hw/mips/bios.h index c03007999a03..44acb6815bec 100644 --- a/include/hw/mips/bios.h +++ b/include/hw/mips/bios.h @@ -5,7 +5,7 @@ #include "cpu.h" #define BIOS_SIZE (4 * MiB) -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN #define BIOS_FILENAME "mips_bios.bin" #else #define BIOS_FILENAME "mipsel_bios.bin" diff --git a/include/hw/mips/bootloader.h b/include/hw/mips/bootloader.h index b5f48d71bbab..fffb0b7da83d 100644 --- a/include/hw/mips/bootloader.h +++ b/include/hw/mips/bootloader.h @@ -12,8 +12,12 @@ #include "exec/cpu-defs.h" void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr); -void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0, - target_ulong a1, target_ulong a2, target_ulong a3, +void bl_gen_jump_kernel(uint32_t **p, + bool set_sp, target_ulong sp, + bool set_a0, target_ulong a0, + bool set_a1, target_ulong a1, + bool set_a2, target_ulong a2, + bool set_a3, target_ulong a3, target_ulong kernel_addr); void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val); void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val); diff --git a/include/hw/misc/allwinner-a10-ccm.h b/include/hw/misc/allwinner-a10-ccm.h new file mode 100644 index 000000000000..7f22532efaaa --- /dev/null +++ b/include/hw/misc/allwinner-a10-ccm.h @@ -0,0 +1,67 @@ +/* + * Allwinner A10 Clock Control Module emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 CCU, + * by Niek Linnenbank. + * + * 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 . + */ + +#ifndef HW_MISC_ALLWINNER_A10_CCM_H +#define HW_MISC_ALLWINNER_A10_CCM_H + +#include "qom/object.h" +#include "hw/sysbus.h" + +/** + * @name Constants + * @{ + */ + +/** Size of register I/O address space used by CCM device */ +#define AW_A10_CCM_IOSIZE (0x400) + +/** Total number of known registers */ +#define AW_A10_CCM_REGS_NUM (AW_A10_CCM_IOSIZE / sizeof(uint32_t)) + +/** @} */ + +/** + * @name Object model + * @{ + */ + +#define TYPE_AW_A10_CCM "allwinner-a10-ccm" +OBJECT_DECLARE_SIMPLE_TYPE(AwA10ClockCtlState, AW_A10_CCM) + +/** @} */ + +/** + * Allwinner A10 CCM object instance state. + */ +struct AwA10ClockCtlState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + /** Maps I/O registers in physical memory */ + MemoryRegion iomem; + + /** Array of hardware registers */ + uint32_t regs[AW_A10_CCM_REGS_NUM]; +}; + +#endif /* HW_MISC_ALLWINNER_H3_CCU_H */ diff --git a/include/hw/misc/allwinner-a10-dramc.h b/include/hw/misc/allwinner-a10-dramc.h new file mode 100644 index 000000000000..b61fbecbe749 --- /dev/null +++ b/include/hw/misc/allwinner-a10-dramc.h @@ -0,0 +1,68 @@ +/* + * Allwinner A10 DRAM Controller emulation + * + * Copyright (C) 2022 Strahinja Jankovic + * + * This file is derived from Allwinner H3 DRAMC, + * by Niek Linnenbank. + * + * 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 . + */ + +#ifndef HW_MISC_ALLWINNER_A10_DRAMC_H +#define HW_MISC_ALLWINNER_A10_DRAMC_H + +#include "qom/object.h" +#include "hw/sysbus.h" +#include "hw/register.h" + +/** + * @name Constants + * @{ + */ + +/** Size of register I/O address space used by DRAMC device */ +#define AW_A10_DRAMC_IOSIZE (0x1000) + +/** Total number of known registers */ +#define AW_A10_DRAMC_REGS_NUM (AW_A10_DRAMC_IOSIZE / sizeof(uint32_t)) + +/** @} */ + +/** + * @name Object model + * @{ + */ + +#define TYPE_AW_A10_DRAMC "allwinner-a10-dramc" +OBJECT_DECLARE_SIMPLE_TYPE(AwA10DramControllerState, AW_A10_DRAMC) + +/** @} */ + +/** + * Allwinner A10 DRAMC object instance state. + */ +struct AwA10DramControllerState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + /** Maps I/O registers in physical memory */ + MemoryRegion iomem; + + /** Array of hardware registers */ + uint32_t regs[AW_A10_DRAMC_REGS_NUM]; +}; + +#endif /* HW_MISC_ALLWINNER_A10_DRAMC_H */ diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index 94d5ada95fa2..ecb1b67de816 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -15,9 +15,12 @@ #define TYPE_ASPEED_AST2400_HACE TYPE_ASPEED_HACE "-ast2400" #define TYPE_ASPEED_AST2500_HACE TYPE_ASPEED_HACE "-ast2500" #define TYPE_ASPEED_AST2600_HACE TYPE_ASPEED_HACE "-ast2600" +#define TYPE_ASPEED_AST1030_HACE TYPE_ASPEED_HACE "-ast1030" + OBJECT_DECLARE_TYPE(AspeedHACEState, AspeedHACEClass, ASPEED_HACE) #define ASPEED_HACE_NR_REGS (0x64 >> 2) +#define ASPEED_HACE_MAX_SG 256 /* max number of entries */ struct AspeedHACEState { SysBusDevice parent; @@ -25,7 +28,10 @@ struct AspeedHACEState { MemoryRegion iomem; qemu_irq irq; + struct iovec iov_cache[ASPEED_HACE_MAX_SG]; uint32_t regs[ASPEED_HACE_NR_REGS]; + uint32_t total_req_len; + uint32_t iov_count; MemoryRegion *dram_mr; AddressSpace dram_as; @@ -37,7 +43,8 @@ struct AspeedHACEClass { uint32_t src_mask; uint32_t dest_mask; + uint32_t key_mask; uint32_t hash_mask; }; -#endif /* _ASPEED_HACE_H_ */ +#endif /* ASPEED_HACE_H */ diff --git a/include/hw/misc/aspeed_lpc.h b/include/hw/misc/aspeed_lpc.h index df418cfcd36c..fd228731d2ff 100644 --- a/include/hw/misc/aspeed_lpc.h +++ b/include/hw/misc/aspeed_lpc.h @@ -44,4 +44,4 @@ typedef struct AspeedLPCState { uint32_t hicr7; } AspeedLPCState; -#endif /* _ASPEED_LPC_H_ */ +#endif /* ASPEED_LPC_H */ diff --git a/include/hw/misc/aspeed_peci.h b/include/hw/misc/aspeed_peci.h new file mode 100644 index 000000000000..8382707d9fd2 --- /dev/null +++ b/include/hw/misc/aspeed_peci.h @@ -0,0 +1,29 @@ +/* + * Aspeed PECI Controller + * + * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com) + * + * This code is licensed under the GPL version 2 or later. See the COPYING + * file in the top-level directory. + */ + +#ifndef ASPEED_PECI_H +#define ASPEED_PECI_H + +#include "hw/sysbus.h" + +#define ASPEED_PECI_NR_REGS ((0xFC + 4) >> 2) +#define TYPE_ASPEED_PECI "aspeed.peci" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedPECIState, ASPEED_PECI); + +struct AspeedPECIState { + /* */ + SysBusDevice parent; + + MemoryRegion mmio; + qemu_irq irq; + + uint32_t regs[ASPEED_PECI_NR_REGS]; +}; + +#endif diff --git a/include/hw/misc/aspeed_sbc.h b/include/hw/misc/aspeed_sbc.h index 651747e28f3a..405e6782b97a 100644 --- a/include/hw/misc/aspeed_sbc.h +++ b/include/hw/misc/aspeed_sbc.h @@ -17,9 +17,22 @@ OBJECT_DECLARE_TYPE(AspeedSBCState, AspeedSBCClass, ASPEED_SBC) #define ASPEED_SBC_NR_REGS (0x93c >> 2) +#define QSR_AES BIT(27) +#define QSR_RSA1024 (0x0 << 12) +#define QSR_RSA2048 (0x1 << 12) +#define QSR_RSA3072 (0x2 << 12) +#define QSR_RSA4096 (0x3 << 12) +#define QSR_SHA224 (0x0 << 10) +#define QSR_SHA256 (0x1 << 10) +#define QSR_SHA384 (0x2 << 10) +#define QSR_SHA512 (0x3 << 10) + struct AspeedSBCState { SysBusDevice parent; + bool emmc_abr; + uint32_t signing_settings; + MemoryRegion iomem; uint32_t regs[ASPEED_SBC_NR_REGS]; @@ -29,4 +42,4 @@ struct AspeedSBCClass { SysBusDeviceClass parent_class; }; -#endif /* _ASPEED_SBC_H_ */ +#endif /* ASPEED_SBC_H */ diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index c14aff2bcbb5..5c7c04eedfa7 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -19,6 +19,7 @@ OBJECT_DECLARE_TYPE(AspeedSCUState, AspeedSCUClass, ASPEED_SCU) #define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400" #define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500" #define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600" +#define TYPE_ASPEED_1030_SCU TYPE_ASPEED_SCU "-ast1030" #define ASPEED_SCU_NR_REGS (0x1A8 >> 2) #define ASPEED_AST2600_SCU_NR_REGS (0xE20 >> 2) @@ -45,6 +46,8 @@ struct AspeedSCUState { #define AST2600_A1_SILICON_REV 0x05010303U #define AST2600_A2_SILICON_REV 0x05020303U #define AST2600_A3_SILICON_REV 0x05030303U +#define AST1030_A0_SILICON_REV 0x80000000U +#define AST1030_A1_SILICON_REV 0x80010000U #define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04) @@ -56,8 +59,10 @@ struct AspeedSCUClass { const uint32_t *resets; uint32_t (*calc_hpll)(AspeedSCUState *s, uint32_t hpll_reg); + uint32_t (*get_apb)(AspeedSCUState *s); uint32_t apb_divider; uint32_t nr_regs; + bool clkin_25Mhz; const MemoryRegionOps *ops; }; @@ -316,4 +321,44 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s); SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ SCU_AST2500_HW_STRAP_RESERVED1) +/* + * SCU200 H-PLL Parameter Register (for Aspeed AST2600 SOC) + * + * 28:26 H-PLL Parameters + * 25 Enable H-PLL reset + * 24 Enable H-PLL bypass mode + * 23 Turn off H-PLL + * 22:19 H-PLL Post Divider (P) + * 18:13 H-PLL Numerator (M) + * 12:0 H-PLL Denumerator (N) + * + * (Output frequency) = CLKIN(25MHz) * [(M+1) / (N+1)] / (P+1) + * + * The default frequency is 1200Mhz when CLKIN = 25MHz + */ +#define SCU_AST2600_H_PLL_BYPASS_EN (0x1 << 24) +#define SCU_AST2600_H_PLL_OFF (0x1 << 23) + +/* + * SCU310 Clock Selection Register Set 4 (for Aspeed AST1030 SOC) + * + * 31 I3C Clock Source selection + * 30:28 I3C clock divider selection + * 26:24 MAC AHB clock divider selection + * 22:20 RGMII 125MHz clock divider ration + * 19:16 RGMII 50MHz clock divider ration + * 15 LHCLK clock generation/output enable control + * 14:12 LHCLK divider selection + * 11:8 APB Bus PCLK divider selection + * 7 Select PECI clock source + * 6 Select UART debug port clock source + * 5 Select UART6 clock source + * 4 Select UART5 clock source + * 3 Select UART4 clock source + * 2 Select UART3 clock source + * 1 Select UART2 clock source + * 0 Select UART1 clock source + */ +#define SCU_AST1030_CLK_GET_PCLK_DIV(x) (((x) >> 8) & 0xf) + #endif /* ASPEED_SCU_H */ diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index 3df4ceedd2eb..0d380367280d 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_MISC_CPRMAN_H -#define HW_MISC_CPRMAN_H +#ifndef HW_MISC_BCM2835_CPRMAN_H +#define HW_MISC_BCM2835_CPRMAN_H #include "hw/sysbus.h" #include "hw/qdev-clock.h" diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 339759b3071d..7617aff96fde 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_MISC_CPRMAN_INTERNALS_H -#define HW_MISC_CPRMAN_INTERNALS_H +#ifndef HW_MISC_BCM2835_CPRMAN_INTERNALS_H +#define HW_MISC_BCM2835_CPRMAN_INTERNALS_H #include "hw/registerfields.h" #include "hw/misc/bcm2835_cprman.h" diff --git a/include/hw/misc/dbus_client.h b/include/hw/misc/dbus_client.h new file mode 100644 index 000000000000..f3e7d968f80b --- /dev/null +++ b/include/hw/misc/dbus_client.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef DBUS_CLIENT_MU_H +#define DBUS_CLIENT_MU_H + +#include "qemu/dbus.h" +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_DBUS_CLIENT_MUA "dbus_client_mua" +OBJECT_DECLARE_SIMPLE_TYPE(DBUSCLIENTMUAState, DBUS_CLIENT_MUA) + +struct DBUSCLIENT { + QemuThread signal_thr; + GDBusConnection * dbus_conn; + GDBusProxy *proxy; +}; + +struct DBUSCLIENTMUAState { + SysBusDevice parent_obj; + MemoryRegion iomem; + struct DBUSCLIENT dbus; + qemu_irq irq; +}; + +#define TYPE_DBUS_CLIENT_MUB "dbus_client_mub" +OBJECT_DECLARE_SIMPLE_TYPE(DBUSCLIENTMUBState, DBUS_CLIENT_MUB) + +struct DBUSCLIENTMUBState { + SysBusDevice parent_obj; + MemoryRegion iomem; + struct DBUSCLIENT dbus; + qemu_irq irq; +}; + +#endif diff --git a/include/hw/misc/fxos8700.h b/include/hw/misc/fxos8700.h new file mode 100644 index 000000000000..dcff8514ba70 --- /dev/null +++ b/include/hw/misc/fxos8700.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef FXOS8700_H +#define FXOS8700_H + +#include "hw/sysbus.h" +#include "qom/object.h" +#include "hw/i2c/i2c.h" + +#define TYPE_FXOS8700 "FXOS8700" +OBJECT_DECLARE_SIMPLE_TYPE(FXOS8700State, FXOS8700) + +#define FXOS8700_REG_SIZE 128U + +struct FXOS8700State { + I2CSlave parent_obj; + uint32_t reg_idx; + uint8_t reg[FXOS8700_REG_SIZE]; + bool addr_byte; +}; + +#endif /* FXOS8700_H */ diff --git a/include/hw/misc/lasi.h b/include/hw/misc/lasi.h new file mode 100644 index 000000000000..ecc7065ce858 --- /dev/null +++ b/include/hw/misc/lasi.h @@ -0,0 +1,78 @@ +/* + * HP-PARISC Lasi chipset emulation. + * + * (C) 2019 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Documentation available at: + * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf + */ + +#ifndef LASI_H +#define LASI_H + +#include "exec/address-spaces.h" +#include "hw/pci/pci_host.h" +#include "hw/boards.h" + +#define TYPE_LASI_CHIP "lasi-chip" +OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) + +#define LASI_IRR 0x00 /* RO */ +#define LASI_IMR 0x04 +#define LASI_IPR 0x08 +#define LASI_ICR 0x0c +#define LASI_IAR 0x10 + +#define LASI_LPT 0x02000 +#define LASI_UART 0x05000 +#define LASI_LAN 0x07000 +#define LASI_RTC 0x09000 + +#define LASI_PCR 0x0C000 /* LASI Power Control register */ +#define LASI_ERRLOG 0x0C004 /* LASI Error Logging register */ +#define LASI_VER 0x0C008 /* LASI Version Control register */ +#define LASI_IORESET 0x0C00C /* LASI I/O Reset register */ +#define LASI_AMR 0x0C010 /* LASI Arbitration Mask register */ +#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */ +#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */ + +#define LASI_BIT(x) (1ul << (x)) +#define LASI_IRQ_BITS (LASI_BIT(5) | LASI_BIT(7) | LASI_BIT(8) | LASI_BIT(9) \ + | LASI_BIT(13) | LASI_BIT(14) | LASI_BIT(16) | LASI_BIT(17) \ + | LASI_BIT(18) | LASI_BIT(19) | LASI_BIT(20) | LASI_BIT(21) \ + | LASI_BIT(26)) + +#define ICR_BUS_ERROR_BIT LASI_BIT(8) /* bit 8 in ICR */ +#define ICR_TOC_BIT LASI_BIT(1) /* bit 1 in ICR */ + +#define LASI_IRQS 27 + +#define LASI_IRQ_HPA 14 +#define LASI_IRQ_UART_HPA 5 +#define LASI_IRQ_LPT_HPA 7 +#define LASI_IRQ_LAN_HPA 8 +#define LASI_IRQ_SCSI_HPA 9 +#define LASI_IRQ_AUDIO_HPA 13 +#define LASI_IRQ_PS2KBD_HPA 26 +#define LASI_IRQ_PS2MOU_HPA 26 + +struct LasiState { + PCIHostState parent_obj; + + uint32_t irr; + uint32_t imr; + uint32_t ipr; + uint32_t icr; + uint32_t iar; + + uint32_t errlog; + uint32_t amr; + uint32_t rtc; + time_t rtc_ref; + + MemoryRegion this_mem; +}; + +#endif diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h index 6c05f3bfd222..86df2c2b60aa 100644 --- a/include/hw/misc/macio/macio.h +++ b/include/hw/misc/macio/macio.h @@ -27,17 +27,38 @@ #define MACIO_H #include "hw/char/escc.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/ide/internal.h" #include "hw/intc/heathrow_pic.h" #include "hw/misc/macio/cuda.h" #include "hw/misc/macio/gpio.h" #include "hw/misc/macio/pmu.h" -#include "hw/ppc/mac.h" +#include "hw/nvram/mac_nvram.h" #include "hw/ppc/mac_dbdma.h" #include "hw/ppc/openpic.h" #include "qom/object.h" +/* Old World IRQs */ +#define OLDWORLD_CUDA_IRQ 0x12 +#define OLDWORLD_ESCCB_IRQ 0x10 +#define OLDWORLD_ESCCA_IRQ 0xf +#define OLDWORLD_IDE0_IRQ 0xd +#define OLDWORLD_IDE0_DMA_IRQ 0x2 +#define OLDWORLD_IDE1_IRQ 0xe +#define OLDWORLD_IDE1_DMA_IRQ 0x3 + +/* New World IRQs */ +#define NEWWORLD_CUDA_IRQ 0x19 +#define NEWWORLD_PMU_IRQ 0x19 +#define NEWWORLD_ESCCB_IRQ 0x24 +#define NEWWORLD_ESCCA_IRQ 0x25 +#define NEWWORLD_IDE0_IRQ 0xd +#define NEWWORLD_IDE0_DMA_IRQ 0x2 +#define NEWWORLD_IDE1_IRQ 0xe +#define NEWWORLD_IDE1_DMA_IRQ 0x3 +#define NEWWORLD_EXTING_GPIO1 0x2f +#define NEWWORLD_EXTING_GPIO9 0x37 + /* MacIO virtual bus */ #define TYPE_MACIO_BUS "macio-bus" OBJECT_DECLARE_SIMPLE_TYPE(MacIOBusState, MACIO_BUS) diff --git a/include/hw/misc/mchp_pfsoc_dmc.h b/include/hw/misc/mchp_pfsoc_dmc.h index 2baa1413b0c2..3bc1581e0f29 100644 --- a/include/hw/misc/mchp_pfsoc_dmc.h +++ b/include/hw/misc/mchp_pfsoc_dmc.h @@ -23,6 +23,8 @@ #ifndef MCHP_PFSOC_DMC_H #define MCHP_PFSOC_DMC_H +#include "hw/sysbus.h" + /* DDR SGMII PHY module */ #define MCHP_PFSOC_DDR_SGMII_PHY_REG_SIZE 0x1000 diff --git a/include/hw/misc/mchp_pfsoc_ioscb.h b/include/hw/misc/mchp_pfsoc_ioscb.h index 9235523e3340..3fd3e7496652 100644 --- a/include/hw/misc/mchp_pfsoc_ioscb.h +++ b/include/hw/misc/mchp_pfsoc_ioscb.h @@ -23,13 +23,18 @@ #ifndef MCHP_PFSOC_IOSCB_H #define MCHP_PFSOC_IOSCB_H +#include "hw/sysbus.h" + typedef struct MchpPfSoCIoscbState { SysBusDevice parent; MemoryRegion container; MemoryRegion lane01; MemoryRegion lane23; MemoryRegion ctrl; + MemoryRegion qspixip; + MemoryRegion mailbox; MemoryRegion cfg; + MemoryRegion ccc; MemoryRegion pll_mss; MemoryRegion cfm_mss; MemoryRegion pll_ddr; @@ -40,6 +45,7 @@ typedef struct MchpPfSoCIoscbState { MemoryRegion cfm_sgmii; MemoryRegion bc_sgmii; MemoryRegion io_calib_sgmii; + qemu_irq irq; } MchpPfSoCIoscbState; #define TYPE_MCHP_PFSOC_IOSCB "mchp.pfsoc.ioscb" diff --git a/include/hw/misc/mchp_pfsoc_sysreg.h b/include/hw/misc/mchp_pfsoc_sysreg.h index 546ba68f6a18..c2232bd28d03 100644 --- a/include/hw/misc/mchp_pfsoc_sysreg.h +++ b/include/hw/misc/mchp_pfsoc_sysreg.h @@ -23,11 +23,14 @@ #ifndef MCHP_PFSOC_SYSREG_H #define MCHP_PFSOC_SYSREG_H +#include "hw/sysbus.h" + #define MCHP_PFSOC_SYSREG_REG_SIZE 0x2000 typedef struct MchpPfSoCSysregState { SysBusDevice parent; MemoryRegion sysreg; + qemu_irq irq; } MchpPfSoCSysregState; #define TYPE_MCHP_PFSOC_SYSREG "mchp.pfsoc.sysreg" diff --git a/include/hw/misc/mos6522.h b/include/hw/misc/mos6522.h index 0bc22a839576..05872fffc926 100644 --- a/include/hw/misc/mos6522.h +++ b/include/hw/misc/mos6522.h @@ -157,7 +157,7 @@ OBJECT_DECLARE_TYPE(MOS6522State, MOS6522DeviceClass, MOS6522) struct MOS6522DeviceClass { DeviceClass parent_class; - DeviceReset parent_reset; + ResettablePhases parent_phases; void (*portB_write)(MOS6522State *dev); void (*portA_write)(MOS6522State *dev); /* These are used to influence the CUDA MacOS timebase calibration */ diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h index d5c8d16ca42e..5ed4a4672b36 100644 --- a/include/hw/misc/npcm7xx_clk.h +++ b/include/hw/misc/npcm7xx_clk.h @@ -175,6 +175,6 @@ struct NPCM7xxCLKState { }; #define TYPE_NPCM7XX_CLK "npcm7xx-clk" -#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxCLKState, NPCM7XX_CLK) #endif /* NPCM7XX_CLK_H */ diff --git a/include/hw/misc/npcm7xx_gcr.h b/include/hw/misc/npcm7xx_gcr.h index 13109d9d3247..c0bbdda77e59 100644 --- a/include/hw/misc/npcm7xx_gcr.h +++ b/include/hw/misc/npcm7xx_gcr.h @@ -19,13 +19,43 @@ #include "exec/memory.h" #include "hw/sysbus.h" +/* + * NPCM7XX PWRON STRAP bit fields + * 12: SPI0 powered by VSBV3 at 1.8V + * 11: System flash attached to BMC + * 10: BSP alternative pins. + * 9:8: Flash UART command route enabled. + * 7: Security enabled. + * 6: HI-Z state control. + * 5: ECC disabled. + * 4: Reserved + * 3: JTAG2 enabled. + * 2:0: CPU and DRAM clock frequency. + */ +#define NPCM7XX_PWRON_STRAP_SPI0F18 BIT(12) +#define NPCM7XX_PWRON_STRAP_SFAB BIT(11) +#define NPCM7XX_PWRON_STRAP_BSPA BIT(10) +#define NPCM7XX_PWRON_STRAP_FUP(x) ((x) << 8) +#define FUP_NORM_UART2 3 +#define FUP_PROG_UART3 2 +#define FUP_PROG_UART2 1 +#define FUP_NORM_UART3 0 +#define NPCM7XX_PWRON_STRAP_SECEN BIT(7) +#define NPCM7XX_PWRON_STRAP_HIZ BIT(6) +#define NPCM7XX_PWRON_STRAP_ECC BIT(5) +#define NPCM7XX_PWRON_STRAP_RESERVE1 BIT(4) +#define NPCM7XX_PWRON_STRAP_J2EN BIT(3) +#define NPCM7XX_PWRON_STRAP_CKFRQ(x) (x) +#define CKFRQ_SKIPINIT 0x000 +#define CKFRQ_DEFAULT 0x111 + /* * Number of registers in our device state structure. Don't change this without * incrementing the version_id in the vmstate. */ #define NPCM7XX_GCR_NR_REGS (0x148 / sizeof(uint32_t)) -typedef struct NPCM7xxGCRState { +struct NPCM7xxGCRState { SysBusDevice parent; MemoryRegion iomem; @@ -35,9 +65,9 @@ typedef struct NPCM7xxGCRState { uint32_t reset_pwron; uint32_t reset_mdlr; uint32_t reset_intcr3; -} NPCM7xxGCRState; +}; #define TYPE_NPCM7XX_GCR "npcm7xx-gcr" -#define NPCM7XX_GCR(obj) OBJECT_CHECK(NPCM7xxGCRState, (obj), TYPE_NPCM7XX_GCR) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxGCRState, NPCM7XX_GCR) #endif /* NPCM7XX_GCR_H */ diff --git a/include/hw/misc/npcm7xx_mft.h b/include/hw/misc/npcm7xx_mft.h index 36785e3ba814..d6384382ceaf 100644 --- a/include/hw/misc/npcm7xx_mft.h +++ b/include/hw/misc/npcm7xx_mft.h @@ -49,7 +49,7 @@ * @max_rpm: The maximum rpm for fans. Order: A0, B0, A1, B1. * @duty: The duty cycles for fans, relative to NPCM7XX_PWM_MAX_DUTY. */ -typedef struct NPCM7xxMFTState { +struct NPCM7xxMFTState { SysBusDevice parent; MemoryRegion iomem; @@ -61,10 +61,9 @@ typedef struct NPCM7xxMFTState { uint32_t max_rpm[NPCM7XX_MFT_FANIN_COUNT]; uint32_t duty[NPCM7XX_MFT_FANIN_COUNT]; -} NPCM7xxMFTState; +}; #define TYPE_NPCM7XX_MFT "npcm7xx-mft" -#define NPCM7XX_MFT(obj) \ - OBJECT_CHECK(NPCM7xxMFTState, (obj), TYPE_NPCM7XX_MFT) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxMFTState, NPCM7XX_MFT) #endif /* NPCM7XX_MFT_H */ diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h index 7ad632a93a1a..bf953440acc8 100644 --- a/include/hw/misc/npcm7xx_pwm.h +++ b/include/hw/misc/npcm7xx_pwm.h @@ -101,7 +101,6 @@ struct NPCM7xxPWMState { }; #define TYPE_NPCM7XX_PWM "npcm7xx-pwm" -#define NPCM7XX_PWM(obj) \ - OBJECT_CHECK(NPCM7xxPWMState, (obj), TYPE_NPCM7XX_PWM) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxPWMState, NPCM7XX_PWM) #endif /* NPCM7XX_PWM_H */ diff --git a/include/hw/misc/npcm7xx_rng.h b/include/hw/misc/npcm7xx_rng.h index 5e85fd439d8a..650375dc2cd6 100644 --- a/include/hw/misc/npcm7xx_rng.h +++ b/include/hw/misc/npcm7xx_rng.h @@ -18,7 +18,7 @@ #include "hw/sysbus.h" -typedef struct NPCM7xxRNGState { +struct NPCM7xxRNGState { SysBusDevice parent; MemoryRegion iomem; @@ -26,9 +26,9 @@ typedef struct NPCM7xxRNGState { uint8_t rngcs; uint8_t rngd; uint8_t rngmode; -} NPCM7xxRNGState; +}; #define TYPE_NPCM7XX_RNG "npcm7xx-rng" -#define NPCM7XX_RNG(obj) OBJECT_CHECK(NPCM7xxRNGState, (obj), TYPE_NPCM7XX_RNG) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxRNGState, NPCM7XX_RNG) #endif /* NPCM7XX_RNG_H */ diff --git a/include/hw/misc/pca9420.h b/include/hw/misc/pca9420.h new file mode 100644 index 000000000000..106c69e41921 --- /dev/null +++ b/include/hw/misc/pca9420.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PCA9420_H +#define PCA9420_H + +#include "hw/sysbus.h" +#include "qom/object.h" +#include "hw/i2c/i2c.h" + +#define TYPE_PCA9420 "PCA9420" +OBJECT_DECLARE_SIMPLE_TYPE(PCA9420State, PCA9420) + +#define PCA9420_REG_SIZE 0x32U + +struct PCA9420State { + I2CSlave parent_obj; + uint32_t reg_idx; + uint8_t reg[PCA9420_REG_SIZE]; + bool addr_byte; +}; + +#endif /* PCA9420_H */ diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h index 7f16cc9b160b..fab94165d03d 100644 --- a/include/hw/misc/pvpanic.h +++ b/include/hw/misc/pvpanic.h @@ -15,6 +15,7 @@ #ifndef HW_MISC_PVPANIC_H #define HW_MISC_PVPANIC_H +#include "exec/memory.h" #include "qom/object.h" #define TYPE_PVPANIC_ISA_DEVICE "pvpanic" @@ -33,13 +34,4 @@ struct PVPanicState { void pvpanic_setup_io(PVPanicState *s, DeviceState *dev, unsigned size); -static inline uint16_t pvpanic_port(void) -{ - Object *o = object_resolve_path_type("", TYPE_PVPANIC_ISA_DEVICE, NULL); - if (!o) { - return 0; - } - return object_property_get_uint(o, PVPANIC_IOPORT_PROP, NULL); -} - #endif diff --git a/include/hw/misc/rt_clkctl.h b/include/hw/misc/rt_clkctl.h new file mode 100644 index 000000000000..ef79798ef542 --- /dev/null +++ b/include/hw/misc/rt_clkctl.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_CLKCTL_H +#define RT_CLKCTL_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_RT_CLKCTL0 "rt_clkctl0" +OBJECT_DECLARE_SIMPLE_TYPE(RTCLKCTL0State, RT_CLKCTL0) + +struct RTCLKCTL0State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t PSCCTL0; /* 0x10 */ + uint32_t PSCCTL1; /* 0x14 */ + uint32_t PSCCTL2; /* 0x18 */ + uint32_t PSCCTL0_SET; /* 0x40 */ + uint32_t PSCCTL1_SET; /* 0x44 */ + uint32_t PSCCTL2_SET; /* 0x48 */ + uint32_t PSCCTL0_CLR; /* 0x70 */ + uint32_t PSCCTL1_CLR; /* 0x74 */ + uint32_t PSCCTL2_CLR; /* 0x78 */ + uint32_t FRO_CONTROL; /* 0x80 */ + uint32_t FRO_CAPVAL; /* 0x84 */ + uint32_t FRO_RDTRIM; /* 0x8C */ + uint32_t FRO_SCTRIM; /* 0x90 */ + uint32_t FRODIVSEL; /* 0x108 */ + uint32_t FROCLKSTATUS; /* 0x10C */ + uint32_t FRODIVOEN; /* 0x110 */ + uint32_t LOWFREQCLKDIV; /* 0x130 */ + uint32_t SYSOSCCTL0; /* 0x160 */ + uint32_t SYSOSCBYPASS; /* 0x168 */ + uint32_t LPOSCCTL0; /* 0x190 */ + uint32_t OSC32KHZCTL0; /* 0x1C0 */ + uint32_t SYSPLL0CLKSEL; /* 0x200 */ + uint32_t SYSPLL0CTL0; /* 0x204 */ + uint32_t SYSPLL0LOCKTIMEDIV2; /* 0x20C */ + uint32_t SYSPLL0NUM; /* 0x210 */ + uint32_t SYSPLL0DENOM; /* 0x214 */ + uint32_t SYSPLL0PFD; /* 0x218 */ + uint32_t MAINPLLCLKDIV; /* 0x240 */ + uint32_t DSPPLLCLKDIV; /* 0x244 */ + uint32_t AUX0PLLCLKDIV; /* 0x248 */ + uint32_t AUX1PLLCLKDIV; /* 0x24C */ + uint32_t SYSCPUAHBCLKDIV; /* 0x400 */ + uint32_t MAINCLKSELA; /* 0x430 */ + uint32_t MAINCLKSELB; /* 0x434 */ + uint32_t PFC0DIV; /* 0x500 */ + uint32_t PFC1DIV; /* 0x504 */ + uint32_t FLEXSPI0FCLKSEL; /* 0x620 */ + uint32_t FLEXSPI0FCLKDIV; /* 0x624 */ + uint32_t FLEXSPI1FCLKSEL; /* 0x630 */ + uint32_t FLEXSPI1FCLKDIV; /* 0x634 */ + uint32_t SCTFCLKSEL; /* 0x640 */ + uint32_t SCTIN7CLKDIV; /* 0x644 */ + uint32_t USBHSFCLKSEL; /* 0x660 */ + uint32_t USBHSFCLKDIV; /* 0x664 */ + uint32_t SDIO0FCLKSEL; /* 0x680 */ + uint32_t SDIO0FCLKDIV; /* 0x684 */ + uint32_t SDIO1FCLKSEL; /* 0x690 */ + uint32_t SDIO1FCLKDIV; /* 0x694 */ + uint32_t ADC0FCLKSEL0; /* 0x6D0 */ + uint32_t ADC0FCLKSEL1; /* 0x6D4 */ + uint32_t ADC0FCLKDIV; /* 0x6D8 */ + uint32_t UTICKFCLKSEL; /* 0x700 */ + uint32_t WDT0FCLKSEL; /* 0x720 */ + uint32_t A32KHZWAKECLKSEL; /* 0x730 */ + uint32_t A32KHZWAKECLKDIV; /* 0x734 */ + uint32_t SYSTICKFCLKSEL; /* 0x760 */ + uint32_t SYSTICKFCLKDIV; /* 0x764 */ + uint32_t DPHYCLKSEL; /* 0x770 */ + uint32_t DPHYCLKDIV; /* 0x774 */ + uint32_t DPHYESCCLKSEL; /* 0x778 */ + uint32_t DPHYESCRXCLKDIV; /* 0x77C */ + uint32_t DPHYESCTXCLKDIV; /* 0x780 */ + uint32_t GPUCLKSEL; /* 0x790 */ + uint32_t GPUCLKDIV; /* 0x794 */ + uint32_t DCPIXELCLKSEL; /* 0x7A0 */ + uint32_t DCPIXELCLKDIV; /* 0x7A4 */ + +}; + +#define TYPE_RT_CLKCTL1 "rt_clkctl1" +OBJECT_DECLARE_SIMPLE_TYPE(RTCLKCTL1State, RT_CLKCTL1) + +struct RTCLKCTL1State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t PSCCTL0; /* 0x10 */ + uint32_t PSCCTL1; /* 0x14 */ + uint32_t PSCCTL2; /* 0x18 */ + uint32_t PSCCTL0_SET; /* 0x40 */ + uint32_t PSCCTL1_SET; /* 0x44 */ + uint32_t PSCCTL2_SET; /* 0x48 */ + uint32_t PSCCTL0_CLR; /* 0x70 */ + uint32_t PSCCTL1_CLR; /* 0x74 */ + uint32_t PSCCTL2_CLR; /* 0x78 */ + uint32_t AUDIOPLL0CLKSEL; /* 0x200 */ + uint32_t AUDIOPLL0CTL0; /* 0x204 */ + uint32_t AUDIOPLL0LOCKTIMEDIV2; /* 0x20C */ + uint32_t AUDIOPLL0NUM; /* 0x210 */ + uint32_t AUDIOPLL0DENOM; /* 0x214 */ + uint32_t AUDIOPLL0PFD; /* 0x218 */ + uint32_t AUDIOPLLCLKDIV; /* 0x240 */ + uint32_t DSPCPUCLKDIV; /* 0x400 */ + uint32_t DSPCPUCLKSELA; /* 0x430 */ + uint32_t DSPCPUCLKSELB; /* 0x434 */ + uint32_t OSEVENTTFCLKSEL; /* 0x480 */ + uint32_t FRG0CLKSEL; /* 0x500 */ + uint32_t FRG0CTL; /* 0x504 */ + uint32_t FC0FCLKSEL; /* 0x508 */ + uint32_t FRG1CLKSEL; /* 0x520 */ + uint32_t FRG1CTL; /* 0x524 */ + uint32_t FC1FCLKSEL; /* 0x528 */ + uint32_t FRG2CLKSEL; /* 0x540 */ + uint32_t FRG2CTL; /* 0x544 */ + uint32_t FC2FCLKSEL; /* 0x548 */ + uint32_t FRG3CLKSEL; /* 0x560 */ + uint32_t FRG3CTL; /* 0x564 */ + uint32_t FC3FCLKSEL; /* 0x568 */ + uint32_t FRG4CLKSEL; /* 0x580 */ + uint32_t FRG4CTL; /* 0x584 */ + uint32_t FC4FCLKSEL; /* 0x588 */ + uint32_t FRG5CLKSEL; /* 0x5A0 */ + uint32_t FRG5CTL; /* 0x5A4 */ + uint32_t FC5FCLKSEL; /* 0x5A8 */ + uint32_t FRG6CLKSEL; /* 0x5C0 */ + uint32_t FRG6CTL; /* 0x5C4 */ + uint32_t FC6FCLKSEL; /* 0x5C8 */ + uint32_t FRG7CLKSEL; /* 0x5E0 */ + uint32_t FRG7CTL; /* 0x5E4 */ + uint32_t FC7FCLKSEL; /* 0x5E8 */ + uint32_t FRG8CLKSEL; /* 0x600 */ + uint32_t FRG8CTL; /* 0x604 */ + uint32_t FC8FCLKSEL; /* 0x608 */ + uint32_t FRG9CLKSEL; /* 0x620 */ + uint32_t FRG9CTL; /* 0x624 */ + uint32_t FC9FCLKSEL; /* 0x628 */ + uint32_t FRG10CLKSEL; /* 0x640 */ + uint32_t FRG10CTL; /* 0x644 */ + uint32_t FC10FCLKSEL; /* 0x648 */ + uint32_t FRG11CLKSEL; /* 0x660 */ + uint32_t FRG11CTL; /* 0x664 */ + uint32_t FC11FCLKSEL; /* 0x668 */ + uint32_t FRG12CLKSEL; /* 0x680 */ + uint32_t FRG12CTL; /* 0x684 */ + uint32_t FC12FCLKSEL; /* 0x688 */ + uint32_t FRG13CLKSEL; /* 0x6A0 */ + uint32_t FRG13CTL; /* 0x6A4 */ + uint32_t FC13FCLKSEL; /* 0x6A8 */ + uint32_t FRG14CLKSEL; /* 0x6C0 */ + uint32_t FRG14CTL; /* 0x6C4 */ + uint32_t FC14FCLKSEL; /* 0x6C8 */ + uint32_t FRG15CLKSEL; /* 0x6E0 */ + uint32_t FRG15CTL; /* 0x6E4 */ + uint32_t FC15FCLKSEL; /* 0x6E8 */ + uint32_t FRG16CLKSEL; /* 0x700 */ + uint32_t FRG16CTL; /* 0x704 */ + uint32_t FC16FCLKSEL; /* 0x708 */ + uint32_t FRG17CLKSEL; /* 0x720 */ + uint32_t FRG17CTL; /* 0x724 */ + uint32_t FLEXIOCLKSEL; /* 0x728 */ + uint32_t FLEXIOCLKDIV; /* 0x740 */ + uint32_t FRGPLLCLKDIV; /* 0x760 */ + uint32_t DMIC0FCLKSEL; /* 0x780 */ + uint32_t DMIC0FCLKDIV; /* 0x784 */ + uint32_t CT32BIT0FCLKSEL; /* 0x7A0 */ + uint32_t CT32BIT1FCLKSEL; /* 0x7A4 */ + uint32_t CT32BIT2FCLKSEL; /* 0x7A8 */ + uint32_t CT32BIT3FCLKSEL; /* 0x7AC */ + uint32_t CT32BIT4FCLKSEL; /* 0x7B0 */ + uint32_t AUDIOMCLKSEL; /* 0x7C0 */ + uint32_t AUDIOMCLKDIV; /* 0x7C4 */ + uint32_t CLKOUTSEL0; /* 0x7E0 */ + uint32_t CLKOUTSEL1; /* 0x7E4 */ + uint32_t CLKOUTFCLKDIV; /* 0x7E8 */ + uint32_t I3C01FCLKSEL; /* 0x800 */ + uint32_t I3C01FCLKSTCSEL; /* 0x804 */ + uint32_t I3C01FCLKSTCDIV; /* 0x808 */ + uint32_t I3C01FCLKSDIV; /* 0x80C */ + uint32_t I3C01FCLKDIV; /* 0x810 */ + uint32_t I3C01FCLKSTSTCLKSEL; /* 0x814 */ + uint32_t WDT1FCLKSEL; /* 0x820 */ + uint32_t ACMP0FCLKSEL; /* 0x830 */ + uint32_t ACMP0FCLKDIV; /* 0x834 */ + +}; + +#endif /* RT_CLKCTL_H */ diff --git a/include/hw/misc/rt_pmc.h b/include/hw/misc/rt_pmc.h new file mode 100644 index 000000000000..889bd0510884 --- /dev/null +++ b/include/hw/misc/rt_pmc.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_PMC_H +#define RT_PMC_H + +#include "hw/sysbus.h" +#include "qom/object.h" +#include "qemu/timer.h" + +#define TYPE_RT_PMC "rt_pmc" +OBJECT_DECLARE_SIMPLE_TYPE(RTPMCState, RT_PMC) + +#define FLAG_AUTOWKF_MASK (1U<<28) +#define AUTOWKUP_AUTOWKTIME 0xFFFF +#define CTRL_AUTOWKF_MASK (1U<<28) + +struct RTPMCState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t STATUS; + uint32_t FLAGS; + uint32_t CTRL; + uint32_t RUNCTRL; + uint32_t SLEEPCTRL; + uint32_t LVDCORECTRL; + uint32_t AUTOWKUP; + uint32_t PMICCFG; + uint32_t PADVRANGE; + uint32_t MEMSEQCTRL; + uint32_t TSENSOR; + + uint32_t timer_interval; + QEMUTimer *timer; + uint32_t state; + + uint32_t count; + + qemu_irq irq; +}; + +typedef enum { + ePMC_Active = 11000, + ePMC_Sleep = 12000, + ePMC_Deep_Sleep = 13000, + ePMC_Deep_Power_Down = 14000, + ePMC_Full_Deep_Power_Down = 15000, +} ePMState; + +#endif /* RT_PMC_H */ diff --git a/include/hw/misc/rt_rstctl.h b/include/hw/misc/rt_rstctl.h new file mode 100644 index 000000000000..542d5993aab2 --- /dev/null +++ b/include/hw/misc/rt_rstctl.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_RSTCTL_H +#define RT_RSTCTL_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_RT_RSTCTL0 "rt_rstctl0" +OBJECT_DECLARE_SIMPLE_TYPE(RTRSTCTL0State, RT_RSTCTL0) + +struct RTRSTCTL0State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t SYSRSTSTAT; /**< System Reset Status Register, offset: 0x0 */ +// uint8_t RESERVED_0[12]; + uint32_t PRSTCTL0; /**< Peripheral Reset Control Register 0, offset: 0x10 */ + uint32_t PRSTCTL1; /**< Peripheral Reset Control Register 1, offset: 0x14 */ + uint32_t PRSTCTL2; /**< Peripheral Reset Control Register 2, offset: 0x18 */ +// uint8_t RESERVED_1[36]; + uint32_t PRSTCTL0_SET; /**< Peripheral Reset Control Register 0 SET, offset: 0x40 */ + uint32_t PRSTCTL1_SET; /**< Peripheral Reset Control Register 1 SET, offset: 0x44 */ + uint32_t PRSTCTL2_SET; /**< Peripheral Reset Control Register 2 SET, offset: 0x48 */ +// uint8_t RESERVED_2[36]; + uint32_t PRSTCTL0_CLR; /**< Peripheral Reset Control Register 0 CLR, offset: 0x70 */ + uint32_t PRSTCTL1_CLR; /**< Peripheral Reset Control Register 1 CLR, offset: 0x74 */ + uint32_t PRSTCTL2_CLR; /**< Peripheral Reset Control Register 2 CLR, offset: 0x78 */ +}; + +#define TYPE_RT_RSTCTL1 "rt_rstctl1" +OBJECT_DECLARE_SIMPLE_TYPE(RTRSTCTL1State, RT_RSTCTL1) + +struct RTRSTCTL1State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t SYSRSTSTAT; /**< System Reset Status Register, offset: 0x0 */ +// uint8_t RESERVED_0[12]; + uint32_t PRSTCTL0; /**< Peripheral Reset Control Register 0, offset: 0x10 */ + uint32_t PRSTCTL1; /**< Peripheral Reset Control Register 1, offset: 0x14 */ + uint32_t PRSTCTL2; /**< Peripheral Reset Control Register 2, offset: 0x18 */ +// uint8_t RESERVED_1[36]; + uint32_t PRSTCTL0_SET; /**< Peripheral Reset Control Register 0 SET, offset: 0x40 */ + uint32_t PRSTCTL1_SET; /**< Peripheral Reset Control Register 1 SET, offset: 0x44 */ + uint32_t PRSTCTL2_SET; /**< Peripheral Reset Control Register 2 SET, offset: 0x48 */ +// uint8_t RESERVED_2[36]; + uint32_t PRSTCTL0_CLR; /**< Peripheral Reset Control Register 0 CLR, offset: 0x70 */ + uint32_t PRSTCTL1_CLR; /**< Peripheral Reset Control Register 1 CLR, offset: 0x74 */ + uint32_t PRSTCTL2_CLR; /**< Peripheral Reset Control Register 2 CLR, offset: 0x78 */ + +}; + +#endif /* RT_RSTCTL_H */ diff --git a/include/hw/misc/rt_sysctl.h b/include/hw/misc/rt_sysctl.h new file mode 100644 index 000000000000..df26407a75ed --- /dev/null +++ b/include/hw/misc/rt_sysctl.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_SYSCTL_H +#define RT_SYSCTL_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_RT_SYSCTL0 "rt_sysctl0" +OBJECT_DECLARE_SIMPLE_TYPE(RTSYSCTL0State, RT_SYSCTL0) + +struct RTSYSCTL0State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t reg[512]; +}; + +#define TYPE_RT_SYSCTL1 "rt_sysctl1" +OBJECT_DECLARE_SIMPLE_TYPE(RTSYSCTL1State, RT_SYSCTL1) + +struct RTSYSCTL1State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t reg[512]; +}; + +#endif /* RT_SYSCTL_H */ diff --git a/include/hw/misc/sifive_e_prci.h b/include/hw/misc/sifive_e_prci.h index 262ca16181b7..6aa949e910d0 100644 --- a/include/hw/misc/sifive_e_prci.h +++ b/include/hw/misc/sifive_e_prci.h @@ -18,7 +18,8 @@ #ifndef HW_SIFIVE_E_PRCI_H #define HW_SIFIVE_E_PRCI_H -#include "qom/object.h" + +#include "hw/sysbus.h" enum { SIFIVE_E_PRCI_HFROSCCFG = 0x0, diff --git a/include/hw/misc/sifive_u_otp.h b/include/hw/misc/sifive_u_otp.h index 5d0d7df455f4..170d2148f250 100644 --- a/include/hw/misc/sifive_u_otp.h +++ b/include/hw/misc/sifive_u_otp.h @@ -18,7 +18,8 @@ #ifndef HW_SIFIVE_U_OTP_H #define HW_SIFIVE_U_OTP_H -#include "qom/object.h" + +#include "hw/sysbus.h" #define SIFIVE_U_OTP_PA 0x00 #define SIFIVE_U_OTP_PAIO 0x04 diff --git a/include/hw/misc/sifive_u_prci.h b/include/hw/misc/sifive_u_prci.h index d9ebf40b7fa4..4d2491ad46dd 100644 --- a/include/hw/misc/sifive_u_prci.h +++ b/include/hw/misc/sifive_u_prci.h @@ -18,7 +18,8 @@ #ifndef HW_SIFIVE_U_PRCI_H #define HW_SIFIVE_U_PRCI_H -#include "qom/object.h" + +#include "hw/sysbus.h" #define SIFIVE_U_PRCI_HFXOSCCFG 0x00 #define SIFIVE_U_PRCI_COREPLLCFG0 0x04 diff --git a/include/hw/misc/stm32f4xx_exti.h b/include/hw/misc/stm32f4xx_exti.h index ea6b0097b0eb..fc11c595fa46 100644 --- a/include/hw/misc/stm32f4xx_exti.h +++ b/include/hw/misc/stm32f4xx_exti.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef HW_STM_EXTI_H -#define HW_STM_EXTI_H +#ifndef HW_STM32F4XX_EXTI_H +#define HW_STM32F4XX_EXTI_H #include "hw/sysbus.h" #include "qom/object.h" diff --git a/include/hw/misc/stm32f4xx_syscfg.h b/include/hw/misc/stm32f4xx_syscfg.h index 6f8ca49228b6..9fce67f4b481 100644 --- a/include/hw/misc/stm32f4xx_syscfg.h +++ b/include/hw/misc/stm32f4xx_syscfg.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef HW_STM_SYSCFG_H -#define HW_STM_SYSCFG_H +#ifndef HW_STM32F4XX_SYSCFG_H +#define HW_STM32F4XX_SYSCFG_H #include "hw/sysbus.h" #include "qom/object.h" diff --git a/include/hw/misc/virt_ctrl.h b/include/hw/misc/virt_ctrl.h index 25a237e51874..81346cf017ea 100644 --- a/include/hw/misc/virt_ctrl.h +++ b/include/hw/misc/virt_ctrl.h @@ -7,6 +7,8 @@ #ifndef VIRT_CTRL_H #define VIRT_CTRL_H +#include "hw/sysbus.h" + #define TYPE_VIRT_CTRL "virt-ctrl" OBJECT_DECLARE_SIMPLE_TYPE(VirtCtrlState, VIRT_CTRL) diff --git a/include/hw/misc/xlnx-versal-crl.h b/include/hw/misc/xlnx-versal-crl.h new file mode 100644 index 000000000000..2857f4169a53 --- /dev/null +++ b/include/hw/misc/xlnx-versal-crl.h @@ -0,0 +1,235 @@ +/* + * QEMU model of the Clock-Reset-LPD (CRL). + * + * Copyright (c) 2022 Xilinx Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Written by Edgar E. Iglesias + */ +#ifndef HW_MISC_XLNX_VERSAL_CRL_H +#define HW_MISC_XLNX_VERSAL_CRL_H + +#include "hw/sysbus.h" +#include "hw/register.h" +#include "target/arm/cpu.h" + +#define TYPE_XLNX_VERSAL_CRL "xlnx,versal-crl" +OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalCRL, XLNX_VERSAL_CRL) + +REG32(ERR_CTRL, 0x0) + FIELD(ERR_CTRL, SLVERR_ENABLE, 0, 1) +REG32(IR_STATUS, 0x4) + FIELD(IR_STATUS, ADDR_DECODE_ERR, 0, 1) +REG32(IR_MASK, 0x8) + FIELD(IR_MASK, ADDR_DECODE_ERR, 0, 1) +REG32(IR_ENABLE, 0xc) + FIELD(IR_ENABLE, ADDR_DECODE_ERR, 0, 1) +REG32(IR_DISABLE, 0x10) + FIELD(IR_DISABLE, ADDR_DECODE_ERR, 0, 1) +REG32(WPROT, 0x1c) + FIELD(WPROT, ACTIVE, 0, 1) +REG32(PLL_CLK_OTHER_DMN, 0x20) + FIELD(PLL_CLK_OTHER_DMN, APLL_BYPASS, 0, 1) +REG32(RPLL_CTRL, 0x40) + FIELD(RPLL_CTRL, POST_SRC, 24, 3) + FIELD(RPLL_CTRL, PRE_SRC, 20, 3) + FIELD(RPLL_CTRL, CLKOUTDIV, 16, 2) + FIELD(RPLL_CTRL, FBDIV, 8, 8) + FIELD(RPLL_CTRL, BYPASS, 3, 1) + FIELD(RPLL_CTRL, RESET, 0, 1) +REG32(RPLL_CFG, 0x44) + FIELD(RPLL_CFG, LOCK_DLY, 25, 7) + FIELD(RPLL_CFG, LOCK_CNT, 13, 10) + FIELD(RPLL_CFG, LFHF, 10, 2) + FIELD(RPLL_CFG, CP, 5, 4) + FIELD(RPLL_CFG, RES, 0, 4) +REG32(RPLL_FRAC_CFG, 0x48) + FIELD(RPLL_FRAC_CFG, ENABLED, 31, 1) + FIELD(RPLL_FRAC_CFG, SEED, 22, 3) + FIELD(RPLL_FRAC_CFG, ALGRTHM, 19, 1) + FIELD(RPLL_FRAC_CFG, ORDER, 18, 1) + FIELD(RPLL_FRAC_CFG, DATA, 0, 16) +REG32(PLL_STATUS, 0x50) + FIELD(PLL_STATUS, RPLL_STABLE, 2, 1) + FIELD(PLL_STATUS, RPLL_LOCK, 0, 1) +REG32(RPLL_TO_XPD_CTRL, 0x100) + FIELD(RPLL_TO_XPD_CTRL, CLKACT, 25, 1) + FIELD(RPLL_TO_XPD_CTRL, DIVISOR0, 8, 10) +REG32(LPD_TOP_SWITCH_CTRL, 0x104) + FIELD(LPD_TOP_SWITCH_CTRL, CLKACT_ADMA, 26, 1) + FIELD(LPD_TOP_SWITCH_CTRL, CLKACT, 25, 1) + FIELD(LPD_TOP_SWITCH_CTRL, DIVISOR0, 8, 10) + FIELD(LPD_TOP_SWITCH_CTRL, SRCSEL, 0, 3) +REG32(LPD_LSBUS_CTRL, 0x108) + FIELD(LPD_LSBUS_CTRL, CLKACT, 25, 1) + FIELD(LPD_LSBUS_CTRL, DIVISOR0, 8, 10) + FIELD(LPD_LSBUS_CTRL, SRCSEL, 0, 3) +REG32(CPU_R5_CTRL, 0x10c) + FIELD(CPU_R5_CTRL, CLKACT_OCM2, 28, 1) + FIELD(CPU_R5_CTRL, CLKACT_OCM, 27, 1) + FIELD(CPU_R5_CTRL, CLKACT_CORE, 26, 1) + FIELD(CPU_R5_CTRL, CLKACT, 25, 1) + FIELD(CPU_R5_CTRL, DIVISOR0, 8, 10) + FIELD(CPU_R5_CTRL, SRCSEL, 0, 3) +REG32(IOU_SWITCH_CTRL, 0x114) + FIELD(IOU_SWITCH_CTRL, CLKACT, 25, 1) + FIELD(IOU_SWITCH_CTRL, DIVISOR0, 8, 10) + FIELD(IOU_SWITCH_CTRL, SRCSEL, 0, 3) +REG32(GEM0_REF_CTRL, 0x118) + FIELD(GEM0_REF_CTRL, CLKACT_RX, 27, 1) + FIELD(GEM0_REF_CTRL, CLKACT_TX, 26, 1) + FIELD(GEM0_REF_CTRL, CLKACT, 25, 1) + FIELD(GEM0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(GEM0_REF_CTRL, SRCSEL, 0, 3) +REG32(GEM1_REF_CTRL, 0x11c) + FIELD(GEM1_REF_CTRL, CLKACT_RX, 27, 1) + FIELD(GEM1_REF_CTRL, CLKACT_TX, 26, 1) + FIELD(GEM1_REF_CTRL, CLKACT, 25, 1) + FIELD(GEM1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(GEM1_REF_CTRL, SRCSEL, 0, 3) +REG32(GEM_TSU_REF_CTRL, 0x120) + FIELD(GEM_TSU_REF_CTRL, CLKACT, 25, 1) + FIELD(GEM_TSU_REF_CTRL, DIVISOR0, 8, 10) + FIELD(GEM_TSU_REF_CTRL, SRCSEL, 0, 3) +REG32(USB0_BUS_REF_CTRL, 0x124) + FIELD(USB0_BUS_REF_CTRL, CLKACT, 25, 1) + FIELD(USB0_BUS_REF_CTRL, DIVISOR0, 8, 10) + FIELD(USB0_BUS_REF_CTRL, SRCSEL, 0, 3) +REG32(UART0_REF_CTRL, 0x128) + FIELD(UART0_REF_CTRL, CLKACT, 25, 1) + FIELD(UART0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(UART0_REF_CTRL, SRCSEL, 0, 3) +REG32(UART1_REF_CTRL, 0x12c) + FIELD(UART1_REF_CTRL, CLKACT, 25, 1) + FIELD(UART1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(UART1_REF_CTRL, SRCSEL, 0, 3) +REG32(SPI0_REF_CTRL, 0x130) + FIELD(SPI0_REF_CTRL, CLKACT, 25, 1) + FIELD(SPI0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(SPI0_REF_CTRL, SRCSEL, 0, 3) +REG32(SPI1_REF_CTRL, 0x134) + FIELD(SPI1_REF_CTRL, CLKACT, 25, 1) + FIELD(SPI1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(SPI1_REF_CTRL, SRCSEL, 0, 3) +REG32(CAN0_REF_CTRL, 0x138) + FIELD(CAN0_REF_CTRL, CLKACT, 25, 1) + FIELD(CAN0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(CAN0_REF_CTRL, SRCSEL, 0, 3) +REG32(CAN1_REF_CTRL, 0x13c) + FIELD(CAN1_REF_CTRL, CLKACT, 25, 1) + FIELD(CAN1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(CAN1_REF_CTRL, SRCSEL, 0, 3) +REG32(I2C0_REF_CTRL, 0x140) + FIELD(I2C0_REF_CTRL, CLKACT, 25, 1) + FIELD(I2C0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(I2C0_REF_CTRL, SRCSEL, 0, 3) +REG32(I2C1_REF_CTRL, 0x144) + FIELD(I2C1_REF_CTRL, CLKACT, 25, 1) + FIELD(I2C1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(I2C1_REF_CTRL, SRCSEL, 0, 3) +REG32(DBG_LPD_CTRL, 0x148) + FIELD(DBG_LPD_CTRL, CLKACT, 25, 1) + FIELD(DBG_LPD_CTRL, DIVISOR0, 8, 10) + FIELD(DBG_LPD_CTRL, SRCSEL, 0, 3) +REG32(TIMESTAMP_REF_CTRL, 0x14c) + FIELD(TIMESTAMP_REF_CTRL, CLKACT, 25, 1) + FIELD(TIMESTAMP_REF_CTRL, DIVISOR0, 8, 10) + FIELD(TIMESTAMP_REF_CTRL, SRCSEL, 0, 3) +REG32(CRL_SAFETY_CHK, 0x150) +REG32(PSM_REF_CTRL, 0x154) + FIELD(PSM_REF_CTRL, DIVISOR0, 8, 10) + FIELD(PSM_REF_CTRL, SRCSEL, 0, 3) +REG32(DBG_TSTMP_CTRL, 0x158) + FIELD(DBG_TSTMP_CTRL, CLKACT, 25, 1) + FIELD(DBG_TSTMP_CTRL, DIVISOR0, 8, 10) + FIELD(DBG_TSTMP_CTRL, SRCSEL, 0, 3) +REG32(CPM_TOPSW_REF_CTRL, 0x15c) + FIELD(CPM_TOPSW_REF_CTRL, CLKACT, 25, 1) + FIELD(CPM_TOPSW_REF_CTRL, DIVISOR0, 8, 10) + FIELD(CPM_TOPSW_REF_CTRL, SRCSEL, 0, 3) +REG32(USB3_DUAL_REF_CTRL, 0x160) + FIELD(USB3_DUAL_REF_CTRL, CLKACT, 25, 1) + FIELD(USB3_DUAL_REF_CTRL, DIVISOR0, 8, 10) + FIELD(USB3_DUAL_REF_CTRL, SRCSEL, 0, 3) +REG32(RST_CPU_R5, 0x300) + FIELD(RST_CPU_R5, RESET_PGE, 4, 1) + FIELD(RST_CPU_R5, RESET_AMBA, 2, 1) + FIELD(RST_CPU_R5, RESET_CPU1, 1, 1) + FIELD(RST_CPU_R5, RESET_CPU0, 0, 1) +REG32(RST_ADMA, 0x304) + FIELD(RST_ADMA, RESET, 0, 1) +REG32(RST_GEM0, 0x308) + FIELD(RST_GEM0, RESET, 0, 1) +REG32(RST_GEM1, 0x30c) + FIELD(RST_GEM1, RESET, 0, 1) +REG32(RST_SPARE, 0x310) + FIELD(RST_SPARE, RESET, 0, 1) +REG32(RST_USB0, 0x314) + FIELD(RST_USB0, RESET, 0, 1) +REG32(RST_UART0, 0x318) + FIELD(RST_UART0, RESET, 0, 1) +REG32(RST_UART1, 0x31c) + FIELD(RST_UART1, RESET, 0, 1) +REG32(RST_SPI0, 0x320) + FIELD(RST_SPI0, RESET, 0, 1) +REG32(RST_SPI1, 0x324) + FIELD(RST_SPI1, RESET, 0, 1) +REG32(RST_CAN0, 0x328) + FIELD(RST_CAN0, RESET, 0, 1) +REG32(RST_CAN1, 0x32c) + FIELD(RST_CAN1, RESET, 0, 1) +REG32(RST_I2C0, 0x330) + FIELD(RST_I2C0, RESET, 0, 1) +REG32(RST_I2C1, 0x334) + FIELD(RST_I2C1, RESET, 0, 1) +REG32(RST_DBG_LPD, 0x338) + FIELD(RST_DBG_LPD, RPU_DBG1_RESET, 5, 1) + FIELD(RST_DBG_LPD, RPU_DBG0_RESET, 4, 1) + FIELD(RST_DBG_LPD, RESET_HSDP, 1, 1) + FIELD(RST_DBG_LPD, RESET, 0, 1) +REG32(RST_GPIO, 0x33c) + FIELD(RST_GPIO, RESET, 0, 1) +REG32(RST_TTC, 0x344) + FIELD(RST_TTC, TTC3_RESET, 3, 1) + FIELD(RST_TTC, TTC2_RESET, 2, 1) + FIELD(RST_TTC, TTC1_RESET, 1, 1) + FIELD(RST_TTC, TTC0_RESET, 0, 1) +REG32(RST_TIMESTAMP, 0x348) + FIELD(RST_TIMESTAMP, RESET, 0, 1) +REG32(RST_SWDT, 0x34c) + FIELD(RST_SWDT, RESET, 0, 1) +REG32(RST_OCM, 0x350) + FIELD(RST_OCM, RESET, 0, 1) +REG32(RST_IPI, 0x354) + FIELD(RST_IPI, RESET, 0, 1) +REG32(RST_SYSMON, 0x358) + FIELD(RST_SYSMON, SEQ_RST, 1, 1) + FIELD(RST_SYSMON, CFG_RST, 0, 1) +REG32(RST_FPD, 0x360) + FIELD(RST_FPD, SRST, 1, 1) + FIELD(RST_FPD, POR, 0, 1) +REG32(PSM_RST_MODE, 0x370) + FIELD(PSM_RST_MODE, WAKEUP, 2, 1) + FIELD(PSM_RST_MODE, RST_MODE, 0, 2) + +#define CRL_R_MAX (R_PSM_RST_MODE + 1) + +#define RPU_MAX_CPU 2 + +struct XlnxVersalCRL { + SysBusDevice parent_obj; + qemu_irq irq; + + struct { + ARMCPU *cpu_r5[RPU_MAX_CPU]; + DeviceState *adma[8]; + DeviceState *uart[2]; + DeviceState *gem[2]; + DeviceState *usb; + } cfg; + + RegisterInfoArray *reg_array; + uint32_t regs[CRL_R_MAX]; + RegisterInfo regs_info[CRL_R_MAX]; +}; +#endif diff --git a/include/hw/misc/xlnx-versal-pmc-iou-slcr.h b/include/hw/misc/xlnx-versal-pmc-iou-slcr.h index ab4e4b4f185a..f7d24c93c412 100644 --- a/include/hw/misc/xlnx-versal-pmc-iou-slcr.h +++ b/include/hw/misc/xlnx-versal-pmc-iou-slcr.h @@ -51,9 +51,10 @@ * 1: OSPI direct access mode. */ -#ifndef XILINX_VERSAL_PMC_IOU_SLCR_H -#define XILINX_VERSAL_PMC_IOU_SLCR_H +#ifndef XLNX_VERSAL_PMC_IOU_SLCR_H +#define XLNX_VERSAL_PMC_IOU_SLCR_H +#include "hw/sysbus.h" #include "hw/register.h" #define TYPE_XILINX_VERSAL_PMC_IOU_SLCR "xlnx.versal-pmc-iou-slcr" @@ -75,4 +76,4 @@ struct XlnxVersalPmcIouSlcr { RegisterInfo regs_info[XILINX_VERSAL_PMC_IOU_SLCR_R_MAX]; }; -#endif /* XILINX_VERSAL_PMC_IOU_SLCR_H */ +#endif /* XLNX_VERSAL_PMC_IOU_SLCR_H */ diff --git a/include/hw/misc/xlnx-zynqmp-apu-ctrl.h b/include/hw/misc/xlnx-zynqmp-apu-ctrl.h index b8ca9434afbe..c3bf3c1583bb 100644 --- a/include/hw/misc/xlnx-zynqmp-apu-ctrl.h +++ b/include/hw/misc/xlnx-zynqmp-apu-ctrl.h @@ -13,7 +13,7 @@ #include "hw/sysbus.h" #include "hw/register.h" -#include "target/arm/cpu.h" +#include "target/arm/cpu-qom.h" #define TYPE_XLNX_ZYNQMP_APU_CTRL "xlnx.apu-ctrl" OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPAPUCtrl, XLNX_ZYNQMP_APU_CTRL) diff --git a/include/hw/net/allwinner-sun8i-emac.h b/include/hw/net/allwinner-sun8i-emac.h index 460a58f1ca7a..185895f4e131 100644 --- a/include/hw/net/allwinner-sun8i-emac.h +++ b/include/hw/net/allwinner-sun8i-emac.h @@ -101,4 +101,4 @@ struct AwSun8iEmacState { }; -#endif /* HW_NET_ALLWINNER_SUN8I_H */ +#endif /* HW_NET_ALLWINNER_SUN8I_EMAC_H */ diff --git a/include/hw/net/lasi_82596.h b/include/hw/net/lasi_82596.h index 7b62b048336c..3ef2f47ba205 100644 --- a/include/hw/net/lasi_82596.h +++ b/include/hw/net/lasi_82596.h @@ -10,7 +10,7 @@ #include "net/net.h" #include "hw/net/i82596.h" -#include "qom/object.h" +#include "hw/sysbus.h" #define TYPE_LASI_82596 "lasi_82596" typedef struct SysBusI82596State SysBusI82596State; diff --git a/include/hw/net/mv88w8618_eth.h b/include/hw/net/mv88w8618_eth.h index 8f4c746092f0..41074940ec0d 100644 --- a/include/hw/net/mv88w8618_eth.h +++ b/include/hw/net/mv88w8618_eth.h @@ -4,8 +4,9 @@ * * Copyright (c) 2008-2021 QEMU contributors */ -#ifndef HW_NET_MV88W8618_H -#define HW_NET_MV88W8618_H + +#ifndef HW_NET_MV88W8618_ETH_H +#define HW_NET_MV88W8618_ETH_H #define TYPE_MV88W8618_ETH "mv88w8618_eth" diff --git a/include/hw/net/npcm7xx_emc.h b/include/hw/net/npcm7xx_emc.h index eac7f2981678..b789007160ac 100644 --- a/include/hw/net/npcm7xx_emc.h +++ b/include/hw/net/npcm7xx_emc.h @@ -277,10 +277,7 @@ struct NPCM7xxEMCState { bool rx_active; }; -typedef struct NPCM7xxEMCState NPCM7xxEMCState; - #define TYPE_NPCM7XX_EMC "npcm7xx-emc" -#define NPCM7XX_EMC(obj) \ - OBJECT_CHECK(NPCM7xxEMCState, (obj), TYPE_NPCM7XX_EMC) +OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxEMCState, NPCM7XX_EMC) #endif /* NPCM7XX_EMC_H */ diff --git a/include/hw/net/xlnx-zynqmp-can.h b/include/hw/net/xlnx-zynqmp-can.h index eb1558708bbd..fd2aa7776038 100644 --- a/include/hw/net/xlnx-zynqmp-can.h +++ b/include/hw/net/xlnx-zynqmp-can.h @@ -30,6 +30,7 @@ #ifndef XLNX_ZYNQMP_CAN_H #define XLNX_ZYNQMP_CAN_H +#include "hw/sysbus.h" #include "hw/register.h" #include "net/can_emu.h" #include "net/can_host.h" diff --git a/include/hw/nubus/mac-nubus-bridge.h b/include/hw/nubus/mac-nubus-bridge.h index 70ab50ab2d67..be4dd8353051 100644 --- a/include/hw/nubus/mac-nubus-bridge.h +++ b/include/hw/nubus/mac-nubus-bridge.h @@ -6,8 +6,8 @@ * */ -#ifndef HW_NUBUS_MAC_H -#define HW_NUBUS_MAC_H +#ifndef HW_NUBUS_MAC_NUBUS_BRIDGE_H +#define HW_NUBUS_MAC_NUBUS_BRIDGE_H #include "hw/nubus/nubus.h" #include "qom/object.h" diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 0e7a8bc7af20..2e503904dc95 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 @@ -342,4 +364,25 @@ bool fw_cfg_dma_enabled(void *opaque); */ const char *fw_cfg_arch_key_name(uint16_t key); +/** + * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified + * by key. + * @fw_cfg: The firmware config instance to store the data in. + * @size_key: The firmware config key to store the size of the loaded + * data under, with fw_cfg_add_i32(). + * @data_key: The firmware config key to store the loaded data under, + * with fw_cfg_add_bytes(). + * @image_name: The name of the image file to load. If it is NULL, the + * function returns without doing anything. + * @try_decompress: Whether the image should be decompressed (gunzipped) before + * adding it to fw_cfg. If decompression fails, the image is + * loaded as-is. + * + * In case of failure, the function prints an error message to stderr and the + * process exits with status 1. + */ +void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, + uint16_t data_key, const char *image_name, + bool try_decompress); + #endif diff --git a/include/hw/nvram/mac_nvram.h b/include/hw/nvram/mac_nvram.h new file mode 100644 index 000000000000..b780aca470a2 --- /dev/null +++ b/include/hw/nvram/mac_nvram.h @@ -0,0 +1,51 @@ +/* + * PowerMac NVRAM emulation + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MAC_NVRAM_H +#define MAC_NVRAM_H + +#include "exec/memory.h" +#include "hw/sysbus.h" + +#define MACIO_NVRAM_SIZE 0x2000 + +#define TYPE_MACIO_NVRAM "macio-nvram" +OBJECT_DECLARE_SIMPLE_TYPE(MacIONVRAMState, MACIO_NVRAM) + +struct MacIONVRAMState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + uint32_t size; + uint32_t it_shift; + + MemoryRegion mem; + uint8_t *data; +}; + +void pmac_format_nvram_partition(MacIONVRAMState *nvr, int len); + +#endif /* MAC_NVRAM_H */ diff --git a/include/hw/openrisc/boot.h b/include/hw/openrisc/boot.h new file mode 100644 index 000000000000..25a313d63a1c --- /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-bridge/pci_expander_bridge.h b/include/hw/pci-bridge/pci_expander_bridge.h new file mode 100644 index 000000000000..0b3856d615a5 --- /dev/null +++ b/include/hw/pci-bridge/pci_expander_bridge.h @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef PCI_EXPANDER_BRIDGE_H +#define PCI_EXPANDER_BRIDGE_H + +#include "hw/cxl/cxl.h" + +void pxb_cxl_hook_up_registers(CXLState *state, PCIBus *bus, Error **errp); + +#endif /* PCI_EXPANDER_BRIDGE_H */ diff --git a/include/hw/pci-host/designware.h b/include/hw/pci-host/designware.h index 6d9b51ae67cd..908f3d946beb 100644 --- a/include/hw/pci-host/designware.h +++ b/include/hw/pci-host/designware.h @@ -22,9 +22,6 @@ #define DESIGNWARE_H #include "hw/sysbus.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_bus.h" -#include "hw/pci/pcie_host.h" #include "hw/pci/pci_bridge.h" #include "qom/object.h" diff --git a/include/hw/pci-host/dino.h b/include/hw/pci-host/dino.h new file mode 100644 index 000000000000..a1b01849401d --- /dev/null +++ b/include/hw/pci-host/dino.h @@ -0,0 +1,146 @@ +/* + * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines + * + * (C) 2017-2019 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Documentation available at: + * https://parisc.wiki.kernel.org/images-parisc/9/91/Dino_ers.pdf + * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf + */ + +#ifndef DINO_H +#define DINO_H + +#include "hw/pci/pci_host.h" + +#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(DinoState, DINO_PCI_HOST_BRIDGE) + +#define DINO_IAR0 0x004 +#define DINO_IODC 0x008 +#define DINO_IRR0 0x00C /* RO */ +#define DINO_IAR1 0x010 +#define DINO_IRR1 0x014 /* RO */ +#define DINO_IMR 0x018 +#define DINO_IPR 0x01C +#define DINO_TOC_ADDR 0x020 +#define DINO_ICR 0x024 +#define DINO_ILR 0x028 /* RO */ +#define DINO_IO_COMMAND 0x030 /* WO */ +#define DINO_IO_STATUS 0x034 /* RO */ +#define DINO_IO_CONTROL 0x038 +#define DINO_IO_GSC_ERR_RESP 0x040 /* RO */ +#define DINO_IO_ERR_INFO 0x044 /* RO */ +#define DINO_IO_PCI_ERR_RESP 0x048 /* RO */ +#define DINO_IO_FBB_EN 0x05c +#define DINO_IO_ADDR_EN 0x060 +#define DINO_PCI_CONFIG_ADDR 0x064 +#define DINO_PCI_CONFIG_DATA 0x068 +#define DINO_PCI_IO_DATA 0x06c +#define DINO_PCI_MEM_DATA 0x070 /* Dino 3.x only */ +#define DINO_GSC2X_CONFIG 0x7b4 /* RO */ +#define DINO_GMASK 0x800 +#define DINO_PAMR 0x804 +#define DINO_PAPR 0x808 +#define DINO_DAMODE 0x80c +#define DINO_PCICMD 0x810 +#define DINO_PCISTS 0x814 /* R/WC */ +#define DINO_MLTIM 0x81c +#define DINO_BRDG_FEAT 0x820 +#define DINO_PCIROR 0x824 +#define DINO_PCIWOR 0x828 +#define DINO_TLTIM 0x830 + +#define DINO_IRQS 11 /* bits 0-10 are architected */ +#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ +#define DINO_LOCAL_IRQS (DINO_IRQS + 1) +#define DINO_MASK_IRQ(x) (1 << (x)) + +#define DINO_IRQ_PCIINTA 0 +#define DINO_IRQ_PCIINTB 1 +#define DINO_IRQ_PCIINTC 2 +#define DINO_IRQ_PCIINTD 3 +#define DINO_IRQ_PCIINTE 4 +#define DINO_IRQ_PCIINTF 5 +#define DINO_IRQ_GSCEXTINT 6 +#define DINO_IRQ_BUSERRINT 7 +#define DINO_IRQ_PS2INT 8 +#define DINO_IRQ_UNUSED 9 +#define DINO_IRQ_RS232INT 10 + +#define PCIINTA 0x001 +#define PCIINTB 0x002 +#define PCIINTC 0x004 +#define PCIINTD 0x008 +#define PCIINTE 0x010 +#define PCIINTF 0x020 +#define GSCEXTINT 0x040 +/* #define xxx 0x080 - bit 7 is "default" */ +/* #define xxx 0x100 - bit 8 not used */ +/* #define xxx 0x200 - bit 9 not used */ +#define RS232INT 0x400 + +#define DINO_MEM_CHUNK_SIZE (8 * MiB) + +#define DINO800_REGS (1 + (DINO_TLTIM - DINO_GMASK) / 4) +static const uint32_t reg800_keep_bits[DINO800_REGS] = { + MAKE_64BIT_MASK(0, 1), /* GMASK */ + MAKE_64BIT_MASK(0, 7), /* PAMR */ + MAKE_64BIT_MASK(0, 7), /* PAPR */ + MAKE_64BIT_MASK(0, 8), /* DAMODE */ + MAKE_64BIT_MASK(0, 7), /* PCICMD */ + MAKE_64BIT_MASK(0, 9), /* PCISTS */ + MAKE_64BIT_MASK(0, 32), /* Undefined */ + MAKE_64BIT_MASK(0, 8), /* MLTIM */ + MAKE_64BIT_MASK(0, 30), /* BRDG_FEAT */ + MAKE_64BIT_MASK(0, 24), /* PCIROR */ + MAKE_64BIT_MASK(0, 22), /* PCIWOR */ + MAKE_64BIT_MASK(0, 32), /* Undocumented */ + MAKE_64BIT_MASK(0, 9), /* TLTIM */ +}; + +/* offsets to DINO HPA: */ +#define DINO_PCI_ADDR 0x064 +#define DINO_CONFIG_DATA 0x068 +#define DINO_IO_DATA 0x06c + +struct DinoState { + PCIHostState parent_obj; + + /* + * PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, + * so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. + */ + uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ + + uint32_t iar0; + uint32_t iar1; + uint32_t imr; + uint32_t ipr; + uint32_t icr; + uint32_t ilr; + uint32_t io_fbb_en; + uint32_t io_addr_en; + uint32_t io_control; + uint32_t toc_addr; + + uint32_t reg800[DINO800_REGS]; + + MemoryRegion this_mem; + MemoryRegion pci_mem; + MemoryRegion pci_mem_alias[32]; + + MemoryRegion *memory_as; + + AddressSpace bm_as; + MemoryRegion bm; + MemoryRegion bm_ram_alias; + MemoryRegion bm_pci_alias; + MemoryRegion bm_cpu_alias; + + qemu_irq irqs[DINO_IRQS]; +}; + +#endif diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h index fcf8b6382004..b0240bd7681f 100644 --- a/include/hw/pci-host/gpex.h +++ b/include/hw/pci-host/gpex.h @@ -22,7 +22,7 @@ #include "exec/hwaddr.h" #include "hw/sysbus.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pcie_host.h" #include "qom/object.h" diff --git a/include/hw/pci-host/grackle.h b/include/hw/pci-host/grackle.h new file mode 100644 index 000000000000..7ad3a779f036 --- /dev/null +++ b/include/hw/pci-host/grackle.h @@ -0,0 +1,44 @@ +/* + * QEMU Grackle PCI host (heathrow OldWorld PowerMac) + * + * Copyright (c) 2006-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GRACKLE_H +#define GRACKLE_H + +#include "hw/pci/pci_host.h" + +#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(GrackleState, GRACKLE_PCI_HOST_BRIDGE) + +struct GrackleState { + PCIHostState parent_obj; + + uint32_t ofw_addr; + qemu_irq irqs[4]; + MemoryRegion pci_mmio; + MemoryRegion pci_hole; + MemoryRegion pci_io; +}; + +#endif diff --git a/include/hw/pci-host/i440fx.h b/include/hw/pci-host/i440fx.h index f068aaba8fda..bf57216c7839 100644 --- a/include/hw/pci-host/i440fx.h +++ b/include/hw/pci-host/i440fx.h @@ -11,7 +11,7 @@ #ifndef HW_PCI_I440FX_H #define HW_PCI_I440FX_H -#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_device.h" #include "hw/pci-host/pam.h" #include "qom/object.h" @@ -35,8 +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, - PCII440FXState **pi440fx_state, +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 new file mode 100644 index 000000000000..ff4b9799122d --- /dev/null +++ b/include/hw/pci-host/ls7a.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LS7A_H +#define HW_LS7A_H + +#include "hw/pci-host/pam.h" +#include "qemu/units.h" +#include "qemu/range.h" +#include "qom/object.h" + +#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 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 VIRT_PCH_PIC_IRQ_NUM 32 +#define PCH_PIC_IRQ_OFFSET 64 +#define VIRT_DEVICE_IRQS 16 +#define VIRT_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2) +#define VIRT_UART_BASE 0x1fe001e0 +#define VIRT_UART_SIZE 0X100 +#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 af6ec83cf6cc..f791ebda9be4 100644 --- a/include/hw/pci-host/pnv_phb3.h +++ b/include/hw/pci-host/pnv_phb3.h @@ -10,10 +10,9 @@ #ifndef PCI_HOST_PNV_PHB3_H #define PCI_HOST_PNV_PHB3_H -#include "hw/pci/pcie_host.h" -#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 +102,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 +127,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 +166,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_phb3_regs.h b/include/hw/pci-host/pnv_phb3_regs.h index a174ef1f7045..38f8ce9d7406 100644 --- a/include/hw/pci-host/pnv_phb3_regs.h +++ b/include/hw/pci-host/pnv_phb3_regs.h @@ -12,22 +12,6 @@ #include "qemu/host-utils.h" -/* - * QEMU version of the GETFIELD/SETFIELD macros - * - * These are common with the PnvXive model. - */ -static inline uint64_t GETFIELD(uint64_t mask, uint64_t word) -{ - return (word & mask) >> ctz64(mask); -} - -static inline uint64_t SETFIELD(uint64_t mask, uint64_t word, - uint64_t value) -{ - return (word & ~mask) | ((value << ctz64(mask)) & mask); -} - /* * PBCQ XSCOM registers */ diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index 19dcbd6f8727..d9cea3f952f9 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -10,14 +10,14 @@ #ifndef PCI_HOST_PNV_PHB4_H #define PCI_HOST_PNV_PHB4_H -#include "hw/pci/pcie_host.h" -#include "hw/pci/pcie_port.h" +#include "hw/pci/pci_bus.h" #include "hw/ppc/xive.h" #include "qom/object.h" typedef struct PnvPhb4PecState PnvPhb4PecState; typedef struct PnvPhb4PecStack PnvPhb4PecStack; typedef struct PnvPHB4 PnvPHB4; +typedef struct PnvPHB PnvPHB; typedef struct PnvChip PnvChip; /* @@ -45,15 +45,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 +79,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 +158,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 +207,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-host/q35.h b/include/hw/pci-host/q35.h index ab989698ef8f..e89329c51ef2 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -22,7 +22,7 @@ #ifndef HW_Q35_H #define HW_Q35_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pcie_host.h" #include "hw/pci-host/pam.h" #include "qemu/units.h" diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h index 3dcf6aa51d1d..690a01f0fe9e 100644 --- a/include/hw/pci-host/remote.h +++ b/include/hw/pci-host/remote.h @@ -8,8 +8,8 @@ * */ -#ifndef REMOTE_PCIHOST_H -#define REMOTE_PCIHOST_H +#ifndef PCI_HOST_REMOTE_H +#define PCI_HOST_REMOTE_H #include "exec/memory.h" #include "hw/pci/pcie_host.h" diff --git a/include/hw/pci-host/sabre.h b/include/hw/pci-host/sabre.h index 01190241bbde..d12de84ea23a 100644 --- a/include/hw/pci-host/sabre.h +++ b/include/hw/pci-host/sabre.h @@ -1,7 +1,7 @@ #ifndef HW_PCI_HOST_SABRE_H #define HW_PCI_HOST_SABRE_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "hw/sparc/sun4u_iommu.h" #include "qom/object.h" diff --git a/include/hw/pci-host/xilinx-pcie.h b/include/hw/pci-host/xilinx-pcie.h index 89be88d87fdd..e1b3c1c28046 100644 --- a/include/hw/pci-host/xilinx-pcie.h +++ b/include/hw/pci-host/xilinx-pcie.h @@ -21,7 +21,6 @@ #define HW_XILINX_PCIE_H #include "hw/sysbus.h" -#include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pcie_host.h" #include "qom/object.h" diff --git a/include/hw/pci/msi.h b/include/hw/pci/msi.h index 408768848643..ee8ee469a6b5 100644 --- a/include/hw/pci/msi.h +++ b/include/hw/pci/msi.h @@ -21,7 +21,7 @@ #ifndef QEMU_MSI_H #define QEMU_MSI_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" struct MSIMessage { uint64_t address; @@ -43,6 +43,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector); void msi_send_message(PCIDevice *dev, MSIMessage msg); void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); +void msi_set_mask(PCIDevice *dev, int vector, bool mask, Error **errp); static inline bool msi_present(const PCIDevice *dev) { diff --git a/include/hw/pci/msix.h b/include/hw/pci/msix.h index 4c4a60c7399a..0e6f257e4511 100644 --- a/include/hw/pci/msix.h +++ b/include/hw/pci/msix.h @@ -33,9 +33,10 @@ bool msix_is_masked(PCIDevice *dev, unsigned vector); void msix_set_pending(PCIDevice *dev, unsigned vector); void msix_clr_pending(PCIDevice *dev, int vector); -int msix_vector_use(PCIDevice *dev, unsigned vector); +void msix_vector_use(PCIDevice *dev, unsigned vector); void msix_vector_unuse(PCIDevice *dev, unsigned vector); void msix_unuse_all_vectors(PCIDevice *dev); +void msix_set_mask(PCIDevice *dev, int vector, bool mask); void msix_notify(PCIDevice *dev, unsigned vector); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 3a32b8dd40a8..7048a373d127 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -16,6 +16,7 @@ extern bool pci_available; #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) #define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn)) +#define PCI_BDF_TO_DEVFN(x) ((x) & 0xff) #define PCI_BUS_MAX 256 #define PCI_DEVFN_MAX 256 #define PCI_SLOT_MAX 32 @@ -75,6 +76,7 @@ extern bool pci_available; #define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 #define PCI_SUBDEVICE_ID_QEMU 0x1100 +/* legacy virtio-pci devices */ #define PCI_DEVICE_ID_VIRTIO_NET 0x1000 #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 @@ -83,9 +85,15 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 -#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 -#define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014 -#define PCI_DEVICE_ID_VIRTIO_MEM 0x1015 + +/* + * modern virtio-pci devices get their id assigned automatically, + * there is no need to add #defines here. It gets calculated as + * + * PCI_DEVICE_ID = PCI_DEVICE_ID_VIRTIO_10_BASE + + * virtio_bus_get_vdev_id(bus) + */ +#define PCI_DEVICE_ID_VIRTIO_10_BASE 0x1040 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 @@ -127,6 +135,10 @@ typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type); typedef void PCIUnregisterFunc(PCIDevice *pci_dev); +typedef void MSITriggerFunc(PCIDevice *dev, MSIMessage msg); +typedef MSIMessage MSIPrepareMessageFunc(PCIDevice *dev, unsigned vector); +typedef MSIMessage MSIxPrepareMessageFunc(PCIDevice *dev, unsigned vector); + typedef struct PCIIORegion { pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ #define PCI_BAR_UNMAPPED (~(pcibus_t)0) @@ -154,7 +166,6 @@ enum { #define QEMU_PCI_VGA_IO_HI_SIZE 0x20 #include "hw/pci/pci_regs.h" -#include "hw/pci/pcie.h" /* PCI HEADER_TYPE */ #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 @@ -194,19 +205,10 @@ enum { QEMU_PCIE_LNKSTA_DLLLA = (1 << QEMU_PCIE_LNKSTA_DLLLA_BITNR), #define QEMU_PCIE_EXTCAP_INIT_BITNR 9 QEMU_PCIE_EXTCAP_INIT = (1 << QEMU_PCIE_EXTCAP_INIT_BITNR), +#define QEMU_PCIE_CXL_BITNR 10 + QEMU_PCIE_CAP_CXL = (1 << QEMU_PCIE_CXL_BITNR), }; -#define TYPE_PCI_DEVICE "pci-device" -typedef struct PCIDeviceClass PCIDeviceClass; -DECLARE_OBJ_CHECKERS(PCIDevice, PCIDeviceClass, - PCI_DEVICE, TYPE_PCI_DEVICE) - -/* Implemented by devices that can be plugged on PCI Express buses */ -#define INTERFACE_PCIE_DEVICE "pci-express-device" - -/* Implemented by devices that can be plugged on Conventional PCI buses */ -#define INTERFACE_CONVENTIONAL_PCI_DEVICE "conventional-pci-device" - typedef struct PCIINTxRoute { enum { PCI_INTX_ENABLED, @@ -216,32 +218,6 @@ typedef struct PCIINTxRoute { int irq; } PCIINTxRoute; -struct PCIDeviceClass { - DeviceClass parent_class; - - void (*realize)(PCIDevice *dev, Error **errp); - PCIUnregisterFunc *exit; - PCIConfigReadFunc *config_read; - PCIConfigWriteFunc *config_write; - - uint16_t vendor_id; - uint16_t device_id; - uint8_t revision; - uint16_t class_id; - uint16_t subsystem_vendor_id; /* only for header type = 0 */ - uint16_t subsystem_id; /* only for header type = 0 */ - - /* - * pci-to-pci bridge or normal device. - * This doesn't mean pci host switch. - * When card bus bridge is supported, this would be enhanced. - */ - bool is_bridge; - - /* rom bar */ - const char *romfile; -}; - typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, MSIMessage msg); @@ -250,118 +226,6 @@ typedef void (*MSIVectorPollNotifier)(PCIDevice *dev, unsigned int vector_start, unsigned int vector_end); -enum PCIReqIDType { - PCI_REQ_ID_INVALID = 0, - PCI_REQ_ID_BDF, - PCI_REQ_ID_SECONDARY_BUS, - PCI_REQ_ID_MAX, -}; -typedef enum PCIReqIDType PCIReqIDType; - -struct PCIReqIDCache { - PCIDevice *dev; - PCIReqIDType type; -}; -typedef struct PCIReqIDCache PCIReqIDCache; - -struct PCIDevice { - DeviceState qdev; - bool partially_hotplugged; - bool has_power; - - /* PCI config space */ - uint8_t *config; - - /* Used to enable config checks on load. Note that writable bits are - * never checked even if set in cmask. */ - uint8_t *cmask; - - /* Used to implement R/W bytes */ - uint8_t *wmask; - - /* Used to implement RW1C(Write 1 to Clear) bytes */ - uint8_t *w1cmask; - - /* Used to allocate config space for capabilities. */ - uint8_t *used; - - /* the following fields are read only */ - int32_t devfn; - /* Cached device to fetch requester ID from, to avoid the PCI - * tree walking every time we invoke PCI request (e.g., - * MSI). For conventional PCI root complex, this field is - * meaningless. */ - PCIReqIDCache requester_id_cache; - char name[64]; - PCIIORegion io_regions[PCI_NUM_REGIONS]; - AddressSpace bus_master_as; - MemoryRegion bus_master_container_region; - MemoryRegion bus_master_enable_region; - - /* do not access the following fields */ - PCIConfigReadFunc *config_read; - PCIConfigWriteFunc *config_write; - - /* Legacy PCI VGA regions */ - MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS]; - bool has_vga; - - /* Current IRQ levels. Used internally by the generic PCI code. */ - uint8_t irq_state; - - /* Capability bits */ - uint32_t cap_present; - - /* Offset of MSI-X capability in config space */ - uint8_t msix_cap; - - /* MSI-X entries */ - int msix_entries_nr; - - /* Space to store MSIX table & pending bit array */ - uint8_t *msix_table; - uint8_t *msix_pba; - /* MemoryRegion container for msix exclusive BAR setup */ - MemoryRegion msix_exclusive_bar; - /* Memory Regions for MSIX table and pending bit entries. */ - MemoryRegion msix_table_mmio; - MemoryRegion msix_pba_mmio; - /* Reference-count for entries actually in use by driver. */ - unsigned *msix_entry_used; - /* MSIX function mask set or MSIX disabled */ - bool msix_function_masked; - /* Version id needed for VMState */ - int32_t version_id; - - /* Offset of MSI capability in config space */ - uint8_t msi_cap; - - /* PCI Express */ - PCIExpressDevice exp; - - /* SHPC */ - SHPCDevice *shpc; - - /* Location of option rom */ - char *romfile; - uint32_t romsize; - bool has_rom; - MemoryRegion rom; - uint32_t rom_bar; - - /* INTx routing notifier */ - PCIINTxRoutingNotifier intx_routing_notifier; - - /* MSI-X notifiers */ - MSIVectorUseNotifier msix_vector_use_notifier; - MSIVectorReleaseNotifier msix_vector_release_notifier; - MSIVectorPollNotifier msix_vector_poll_notifier; - - /* ID of standby device in net_failover pair */ - char *failover_pair_id; - uint32_t acpi_index; -}; - void pci_register_bar(PCIDevice *pci_dev, int region_num, uint8_t attr, MemoryRegion *memory); void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem, @@ -400,6 +264,7 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); #define TYPE_PCI_BUS "PCI" OBJECT_DECLARE_TYPE(PCIBus, PCIBusClass, PCI_BUS) #define TYPE_PCIE_BUS "PCIE" +#define TYPE_CXL_BUS "CXL" typedef void (*pci_bus_dev_fn)(PCIBus *b, PCIDevice *d, void *opaque); typedef void (*pci_bus_fn)(PCIBus *b, void *opaque); @@ -666,60 +531,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, @@ -737,11 +586,6 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev); qemu_irq pci_allocate_irq(PCIDevice *pci_dev); void pci_set_irq(PCIDevice *pci_dev, int level); -static inline int pci_intx(PCIDevice *pci_dev) -{ - return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; -} - static inline void pci_irq_assert(PCIDevice *pci_dev) { pci_set_irq(pci_dev, 1); @@ -762,184 +606,6 @@ static inline void pci_irq_pulse(PCIDevice *pci_dev) pci_irq_deassert(pci_dev); } -static inline int pci_is_express(const PCIDevice *d) -{ - return d->cap_present & QEMU_PCI_CAP_EXPRESS; -} - -static inline int pci_is_express_downstream_port(const PCIDevice *d) -{ - uint8_t type; - - if (!pci_is_express(d) || !d->exp.exp_cap) { - return 0; - } - - type = pcie_cap_get_type(d); - - return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT; -} - -static inline int pci_is_vf(const PCIDevice *d) -{ - return d->exp.sriov_vf.pf != NULL; -} - -static inline uint32_t pci_config_size(const PCIDevice *d) -{ - return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; -} - -static inline uint16_t pci_get_bdf(PCIDevice *dev) -{ - return PCI_BUILD_BDF(pci_bus_num(pci_get_bus(dev)), dev->devfn); -} - -uint16_t pci_requester_id(PCIDevice *dev); - -/* DMA access functions */ -static inline AddressSpace *pci_get_address_space(PCIDevice *dev) -{ - return &dev->bus_master_as; -} - -/** - * pci_dma_rw: Read from or write to an address space from PCI device. - * - * Return a MemTxResult indicating whether the operation succeeded - * or failed (eg unassigned memory, device rejected the transaction, - * IOMMU fault). - * - * @dev: #PCIDevice doing the memory access - * @addr: address within the #PCIDevice address space - * @buf: buffer with the data transferred - * @len: the number of bytes to read or write - * @dir: indicates the transfer direction - */ -static inline MemTxResult pci_dma_rw(PCIDevice *dev, dma_addr_t addr, - void *buf, dma_addr_t len, - DMADirection dir, MemTxAttrs attrs) -{ - return dma_memory_rw(pci_get_address_space(dev), addr, buf, len, - dir, attrs); -} - -/** - * pci_dma_read: Read from an address space from PCI device. - * - * Return a MemTxResult indicating whether the operation succeeded - * or failed (eg unassigned memory, device rejected the transaction, - * IOMMU fault). Called within RCU critical section. - * - * @dev: #PCIDevice doing the memory access - * @addr: address within the #PCIDevice address space - * @buf: buffer with the data transferred - * @len: length of the data transferred - */ -static inline MemTxResult pci_dma_read(PCIDevice *dev, dma_addr_t addr, - void *buf, dma_addr_t len) -{ - return pci_dma_rw(dev, addr, buf, len, - DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); -} - -/** - * pci_dma_write: Write to address space from PCI device. - * - * Return a MemTxResult indicating whether the operation succeeded - * or failed (eg unassigned memory, device rejected the transaction, - * IOMMU fault). - * - * @dev: #PCIDevice doing the memory access - * @addr: address within the #PCIDevice address space - * @buf: buffer with the data transferred - * @len: the number of bytes to write - */ -static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, - const void *buf, dma_addr_t len) -{ - return pci_dma_rw(dev, addr, (void *) buf, len, - DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); -} - -#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ - static inline MemTxResult ld##_l##_pci_dma(PCIDevice *dev, \ - dma_addr_t addr, \ - uint##_bits##_t *val, \ - MemTxAttrs attrs) \ - { \ - return ld##_l##_dma(pci_get_address_space(dev), addr, val, attrs); \ - } \ - static inline MemTxResult st##_s##_pci_dma(PCIDevice *dev, \ - dma_addr_t addr, \ - uint##_bits##_t val, \ - MemTxAttrs attrs) \ - { \ - return st##_s##_dma(pci_get_address_space(dev), addr, val, attrs); \ - } - -PCI_DMA_DEFINE_LDST(ub, b, 8); -PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) -PCI_DMA_DEFINE_LDST(l_le, l_le, 32); -PCI_DMA_DEFINE_LDST(q_le, q_le, 64); -PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) -PCI_DMA_DEFINE_LDST(l_be, l_be, 32); -PCI_DMA_DEFINE_LDST(q_be, q_be, 64); - -#undef PCI_DMA_DEFINE_LDST - -/** - * pci_dma_map: Map device PCI address space range into host virtual address - * @dev: #PCIDevice to be accessed - * @addr: address within that device's address space - * @plen: pointer to length of buffer; updated on return to indicate - * if only a subset of the requested range has been mapped - * @dir: indicates the transfer direction - * - * Return: A host pointer, or %NULL if the resources needed to - * perform the mapping are exhausted (in that case *@plen - * is set to zero). - */ -static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, - dma_addr_t *plen, DMADirection dir) -{ - void *buf; - - buf = dma_memory_map(pci_get_address_space(dev), addr, plen, dir, - MEMTXATTRS_UNSPECIFIED); - return buf; -} - -static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, - DMADirection dir, dma_addr_t access_len) -{ - dma_memory_unmap(pci_get_address_space(dev), buffer, len, dir, access_len); -} - -static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, - int alloc_hint) -{ - qemu_sglist_init(qsg, DEVICE(dev), alloc_hint, pci_get_address_space(dev)); -} - -extern const VMStateDescription vmstate_pci_device; - -#define VMSTATE_PCI_DEVICE(_field, _state) { \ - .name = (stringify(_field)), \ - .size = sizeof(PCIDevice), \ - .vmsd = &vmstate_pci_device, \ - .flags = VMS_STRUCT, \ - .offset = vmstate_offset_value(_state, _field, PCIDevice), \ -} - -#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ - .name = (stringify(_field)), \ - .size = sizeof(PCIDevice), \ - .vmsd = &vmstate_pci_device, \ - .flags = VMS_STRUCT|VMS_POINTER, \ - .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ -} - MSIMessage pci_get_msi_message(PCIDevice *dev, int vector); void pci_set_power(PCIDevice *pci_dev, bool state); diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index 30691a6e5728..63a752156729 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -26,8 +26,9 @@ #ifndef QEMU_PCI_BRIDGE_H #define QEMU_PCI_BRIDGE_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_bus.h" +#include "hw/cxl/cxl.h" #include "qom/object.h" typedef struct PCIBridgeWindows PCIBridgeWindows; @@ -52,6 +53,7 @@ struct PCIBridgeWindows { #define TYPE_PCI_BRIDGE "base-pci-bridge" OBJECT_DECLARE_SIMPLE_TYPE(PCIBridge, PCI_BRIDGE) +#define IS_PCI_BRIDGE(dev) object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE) struct PCIBridge { /*< private >*/ @@ -80,6 +82,24 @@ struct PCIBridge { #define PCI_BRIDGE_DEV_PROP_CHASSIS_NR "chassis_nr" #define PCI_BRIDGE_DEV_PROP_MSI "msi" #define PCI_BRIDGE_DEV_PROP_SHPC "shpc" +typedef struct CXLHost CXLHost; + +struct PXBDev { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + + uint8_t bus_nr; + uint16_t numa_node; + bool bypass_iommu; + struct cxl_dev { + CXLHost *cxl_host_bridge; /* Pointer to a CXLHost */ + } cxl; +}; + +#define TYPE_PXB_CXL_DEVICE "pxb-cxl" +DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV, + TYPE_PXB_CXL_DEVICE) int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, uint16_t svid, uint16_t ssid, diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 347440d42ca1..56531759578f 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -24,8 +24,12 @@ enum PCIBusFlags { PCI_BUS_IS_ROOT = 0x0001, /* PCIe extended configuration space is accessible on this bus */ PCI_BUS_EXTENDED_CONFIG_SPACE = 0x0002, + /* This is a CXL Type BUS */ + PCI_BUS_CXL = 0x0004, }; +#define PCI_NO_PASID UINT32_MAX + struct PCIBus { BusState qbus; enum PCIBusFlags flags; @@ -53,6 +57,11 @@ struct PCIBus { Notifier machine_done; }; +static inline bool pci_bus_is_cxl(PCIBus *bus) +{ + return !!(bus->flags & PCI_BUS_CXL); +} + static inline bool pci_bus_is_root(PCIBus *bus) { return !!(bus->flags & PCI_BUS_IS_ROOT); diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h new file mode 100644 index 000000000000..d3dd0f64b273 --- /dev/null +++ b/include/hw/pci/pci_device.h @@ -0,0 +1,350 @@ +#ifndef QEMU_PCI_DEVICE_H +#define QEMU_PCI_DEVICE_H + +#include "hw/pci/pci.h" +#include "hw/pci/pcie.h" + +#define TYPE_PCI_DEVICE "pci-device" +typedef struct PCIDeviceClass PCIDeviceClass; +DECLARE_OBJ_CHECKERS(PCIDevice, PCIDeviceClass, + PCI_DEVICE, TYPE_PCI_DEVICE) + +/* + * Implemented by devices that can be plugged on CXL buses. In the spec, this is + * actually a "CXL Component, but we name it device to match the PCI naming. + */ +#define INTERFACE_CXL_DEVICE "cxl-device" + +/* Implemented by devices that can be plugged on PCI Express buses */ +#define INTERFACE_PCIE_DEVICE "pci-express-device" + +/* Implemented by devices that can be plugged on Conventional PCI buses */ +#define INTERFACE_CONVENTIONAL_PCI_DEVICE "conventional-pci-device" + +struct PCIDeviceClass { + DeviceClass parent_class; + + void (*realize)(PCIDevice *dev, Error **errp); + PCIUnregisterFunc *exit; + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision; + uint16_t class_id; + uint16_t subsystem_vendor_id; /* only for header type = 0 */ + uint16_t subsystem_id; /* only for header type = 0 */ + + const char *romfile; /* rom bar */ +}; + +enum PCIReqIDType { + PCI_REQ_ID_INVALID = 0, + PCI_REQ_ID_BDF, + PCI_REQ_ID_SECONDARY_BUS, + PCI_REQ_ID_MAX, +}; +typedef enum PCIReqIDType PCIReqIDType; + +struct PCIReqIDCache { + PCIDevice *dev; + PCIReqIDType type; +}; +typedef struct PCIReqIDCache PCIReqIDCache; + +struct PCIDevice { + DeviceState qdev; + bool partially_hotplugged; + bool has_power; + + /* PCI config space */ + uint8_t *config; + + /* + * Used to enable config checks on load. Note that writable bits are + * never checked even if set in cmask. + */ + uint8_t *cmask; + + /* Used to implement R/W bytes */ + uint8_t *wmask; + + /* Used to implement RW1C(Write 1 to Clear) bytes */ + uint8_t *w1cmask; + + /* Used to allocate config space for capabilities. */ + uint8_t *used; + + /* the following fields are read only */ + int32_t devfn; + /* + * Cached device to fetch requester ID from, to avoid the PCI tree + * walking every time we invoke PCI request (e.g., MSI). For + * conventional PCI root complex, this field is meaningless. + */ + PCIReqIDCache requester_id_cache; + char name[64]; + PCIIORegion io_regions[PCI_NUM_REGIONS]; + AddressSpace bus_master_as; + MemoryRegion bus_master_container_region; + MemoryRegion bus_master_enable_region; + + /* do not access the following fields */ + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + + /* Legacy PCI VGA regions */ + MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS]; + bool has_vga; + + /* Current IRQ levels. Used internally by the generic PCI code. */ + uint8_t irq_state; + + /* Capability bits */ + uint32_t cap_present; + + /* Offset of MSI-X capability in config space */ + uint8_t msix_cap; + + /* MSI-X entries */ + int msix_entries_nr; + + /* Space to store MSIX table & pending bit array */ + uint8_t *msix_table; + uint8_t *msix_pba; + + /* May be used by INTx or MSI during interrupt notification */ + void *irq_opaque; + + MSITriggerFunc *msi_trigger; + MSIPrepareMessageFunc *msi_prepare_message; + MSIxPrepareMessageFunc *msix_prepare_message; + + /* MemoryRegion container for msix exclusive BAR setup */ + MemoryRegion msix_exclusive_bar; + /* Memory Regions for MSIX table and pending bit entries. */ + MemoryRegion msix_table_mmio; + MemoryRegion msix_pba_mmio; + /* Reference-count for entries actually in use by driver. */ + unsigned *msix_entry_used; + /* MSIX function mask set or MSIX disabled */ + bool msix_function_masked; + /* Version id needed for VMState */ + int32_t version_id; + + /* Offset of MSI capability in config space */ + uint8_t msi_cap; + + /* PCI Express */ + PCIExpressDevice exp; + + /* SHPC */ + SHPCDevice *shpc; + + /* Location of option rom */ + char *romfile; + uint32_t romsize; + bool has_rom; + MemoryRegion rom; + uint32_t rom_bar; + + /* INTx routing notifier */ + PCIINTxRoutingNotifier intx_routing_notifier; + + /* MSI-X notifiers */ + MSIVectorUseNotifier msix_vector_use_notifier; + MSIVectorReleaseNotifier msix_vector_release_notifier; + MSIVectorPollNotifier msix_vector_poll_notifier; + + /* ID of standby device in net_failover pair */ + char *failover_pair_id; + uint32_t acpi_index; +}; + +static inline int pci_intx(PCIDevice *pci_dev) +{ + return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; +} + +static inline int pci_is_cxl(const PCIDevice *d) +{ + return d->cap_present & QEMU_PCIE_CAP_CXL; +} + +static inline int pci_is_express(const PCIDevice *d) +{ + return d->cap_present & QEMU_PCI_CAP_EXPRESS; +} + +static inline int pci_is_express_downstream_port(const PCIDevice *d) +{ + uint8_t type; + + if (!pci_is_express(d) || !d->exp.exp_cap) { + return 0; + } + + type = pcie_cap_get_type(d); + + return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT; +} + +static inline int pci_is_vf(const PCIDevice *d) +{ + return d->exp.sriov_vf.pf != NULL; +} + +static inline uint32_t pci_config_size(const PCIDevice *d) +{ + return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; +} + +static inline uint16_t pci_get_bdf(PCIDevice *dev) +{ + return PCI_BUILD_BDF(pci_bus_num(pci_get_bus(dev)), dev->devfn); +} + +uint16_t pci_requester_id(PCIDevice *dev); + +/* DMA access functions */ +static inline AddressSpace *pci_get_address_space(PCIDevice *dev) +{ + return &dev->bus_master_as; +} + +/** + * pci_dma_rw: Read from or write to an address space from PCI device. + * + * Return a MemTxResult indicating whether the operation succeeded + * or failed (eg unassigned memory, device rejected the transaction, + * IOMMU fault). + * + * @dev: #PCIDevice doing the memory access + * @addr: address within the #PCIDevice address space + * @buf: buffer with the data transferred + * @len: the number of bytes to read or write + * @dir: indicates the transfer direction + */ +static inline MemTxResult pci_dma_rw(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len, + DMADirection dir, MemTxAttrs attrs) +{ + return dma_memory_rw(pci_get_address_space(dev), addr, buf, len, + dir, attrs); +} + +/** + * pci_dma_read: Read from an address space from PCI device. + * + * Return a MemTxResult indicating whether the operation succeeded + * or failed (eg unassigned memory, device rejected the transaction, + * IOMMU fault). Called within RCU critical section. + * + * @dev: #PCIDevice doing the memory access + * @addr: address within the #PCIDevice address space + * @buf: buffer with the data transferred + * @len: length of the data transferred + */ +static inline MemTxResult pci_dma_read(PCIDevice *dev, dma_addr_t addr, + void *buf, dma_addr_t len) +{ + return pci_dma_rw(dev, addr, buf, len, + DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); +} + +/** + * pci_dma_write: Write to address space from PCI device. + * + * Return a MemTxResult indicating whether the operation succeeded + * or failed (eg unassigned memory, device rejected the transaction, + * IOMMU fault). + * + * @dev: #PCIDevice doing the memory access + * @addr: address within the #PCIDevice address space + * @buf: buffer with the data transferred + * @len: the number of bytes to write + */ +static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr, + const void *buf, dma_addr_t len) +{ + return pci_dma_rw(dev, addr, (void *) buf, len, + DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED); +} + +#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \ + static inline MemTxResult ld##_l##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, \ + uint##_bits##_t *val, \ + MemTxAttrs attrs) \ + { \ + return ld##_l##_dma(pci_get_address_space(dev), addr, val, attrs); \ + } \ + static inline MemTxResult st##_s##_pci_dma(PCIDevice *dev, \ + dma_addr_t addr, \ + uint##_bits##_t val, \ + MemTxAttrs attrs) \ + { \ + return st##_s##_dma(pci_get_address_space(dev), addr, val, attrs); \ + } + +PCI_DMA_DEFINE_LDST(ub, b, 8); +PCI_DMA_DEFINE_LDST(uw_le, w_le, 16) +PCI_DMA_DEFINE_LDST(l_le, l_le, 32); +PCI_DMA_DEFINE_LDST(q_le, q_le, 64); +PCI_DMA_DEFINE_LDST(uw_be, w_be, 16) +PCI_DMA_DEFINE_LDST(l_be, l_be, 32); +PCI_DMA_DEFINE_LDST(q_be, q_be, 64); + +#undef PCI_DMA_DEFINE_LDST + +/** + * pci_dma_map: Map device PCI address space range into host virtual address + * @dev: #PCIDevice to be accessed + * @addr: address within that device's address space + * @plen: pointer to length of buffer; updated on return to indicate + * if only a subset of the requested range has been mapped + * @dir: indicates the transfer direction + * + * Return: A host pointer, or %NULL if the resources needed to + * perform the mapping are exhausted (in that case *@plen + * is set to zero). + */ +static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, + dma_addr_t *plen, DMADirection dir) +{ + return dma_memory_map(pci_get_address_space(dev), addr, plen, dir, + MEMTXATTRS_UNSPECIFIED); +} + +static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len, + DMADirection dir, dma_addr_t access_len) +{ + dma_memory_unmap(pci_get_address_space(dev), buffer, len, dir, access_len); +} + +static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev, + int alloc_hint) +{ + qemu_sglist_init(qsg, DEVICE(dev), alloc_hint, pci_get_address_space(dev)); +} + +extern const VMStateDescription vmstate_pci_device; + +#define VMSTATE_PCI_DEVICE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_pci_device, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ +} + +#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_pci_device, \ + .flags = VMS_STRUCT | VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ +} + +#endif diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index 11abe22d4604..e4386ebb2038 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -53,6 +53,7 @@ #define PCI_BASE_CLASS_MEMORY 0x05 #define PCI_CLASS_MEMORY_RAM 0x0500 #define PCI_CLASS_MEMORY_FLASH 0x0501 +#define PCI_CLASS_MEMORY_CXL 0x0502 #define PCI_CLASS_MEMORY_OTHER 0x0580 #define PCI_BASE_CLASS_BRIDGE 0x06 @@ -156,6 +157,9 @@ /* Vendors and devices. Sort key: vendor first, device next. */ +/* Ref: PCIe r6.0 Table 6-32 */ +#define PCI_VENDOR_ID_PCI_SIG 0x0001 + #define PCI_VENDOR_ID_LSI_LOGIC 0x1000 #define PCI_DEVICE_ID_LSI_53C810 0x0001 #define PCI_DEVICE_ID_LSI_53C895A 0x0012 @@ -165,7 +169,6 @@ #define PCI_VENDOR_ID_DEC 0x1011 #define PCI_DEVICE_ID_DEC_21143 0x0019 -#define PCI_DEVICE_ID_DEC_21154 0x0026 #define PCI_VENDOR_ID_CIRRUS 0x1013 @@ -237,6 +240,7 @@ #define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e #define PCI_DEVICE_ID_INTEL_82801D 0x24CD #define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab +#define PCI_DEVICE_ID_INTEL_NVME 0x5845 #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 #define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h new file mode 100644 index 000000000000..ba4d8b03bd3b --- /dev/null +++ b/include/hw/pci/pcie_doe.h @@ -0,0 +1,123 @@ +/* + * PCIe Data Object Exchange + * + * Copyright (C) 2021 Avery Design Systems, 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. + */ + +#ifndef PCIE_DOE_H +#define PCIE_DOE_H + +#include "qemu/range.h" +#include "qemu/typedefs.h" +#include "hw/register.h" + +/* + * Reference: + * PCIe r6.0 - 7.9.24 Data Object Exchange Extended Capability + */ +/* Capabilities Register - r6.0 7.9.24.2 */ +#define PCI_EXP_DOE_CAP 0x04 +REG32(PCI_DOE_CAP_REG, 0) + FIELD(PCI_DOE_CAP_REG, INTR_SUPP, 0, 1) + FIELD(PCI_DOE_CAP_REG, DOE_INTR_MSG_NUM, 1, 11) + +/* Control Register - r6.0 7.9.24.3 */ +#define PCI_EXP_DOE_CTRL 0x08 +REG32(PCI_DOE_CAP_CONTROL, 0) + FIELD(PCI_DOE_CAP_CONTROL, DOE_ABORT, 0, 1) + FIELD(PCI_DOE_CAP_CONTROL, DOE_INTR_EN, 1, 1) + FIELD(PCI_DOE_CAP_CONTROL, DOE_GO, 31, 1) + +/* Status Register - r6.0 7.9.24.4 */ +#define PCI_EXP_DOE_STATUS 0x0c +REG32(PCI_DOE_CAP_STATUS, 0) + FIELD(PCI_DOE_CAP_STATUS, DOE_BUSY, 0, 1) + FIELD(PCI_DOE_CAP_STATUS, DOE_INTR_STATUS, 1, 1) + FIELD(PCI_DOE_CAP_STATUS, DOE_ERROR, 2, 1) + FIELD(PCI_DOE_CAP_STATUS, DATA_OBJ_RDY, 31, 1) + +/* Write Data Mailbox Register - r6.0 7.9.24.5 */ +#define PCI_EXP_DOE_WR_DATA_MBOX 0x10 + +/* Read Data Mailbox Register - 7.9.xx.6 */ +#define PCI_EXP_DOE_RD_DATA_MBOX 0x14 + +/* PCI-SIG defined Data Object Types - r6.0 Table 6-32 */ +#define PCI_SIG_DOE_DISCOVERY 0x00 + +#define PCI_DOE_DW_SIZE_MAX (1 << 18) +#define PCI_DOE_PROTOCOL_NUM_MAX 256 + +#define DATA_OBJ_BUILD_HEADER1(v, p) (((p) << 16) | (v)) +#define DATA_OBJ_LEN_MASK(len) ((len) & (PCI_DOE_DW_SIZE_MAX - 1)) + +typedef struct DOEHeader DOEHeader; +typedef struct DOEProtocol DOEProtocol; +typedef struct DOECap DOECap; + +struct DOEHeader { + uint16_t vendor_id; + uint8_t data_obj_type; + uint8_t reserved; + uint32_t length; +} QEMU_PACKED; + +/* Protocol infos and rsp function callback */ +struct DOEProtocol { + uint16_t vendor_id; + uint8_t data_obj_type; + bool (*handle_request)(DOECap *); +}; + +struct DOECap { + /* Owner */ + PCIDevice *pdev; + + uint16_t offset; + + struct { + bool intr; + uint16_t vec; + } cap; + + struct { + bool abort; + bool intr; + bool go; + } ctrl; + + struct { + bool busy; + bool intr; + bool error; + bool ready; + } status; + + uint32_t *write_mbox; + uint32_t *read_mbox; + + /* Mailbox position indicator */ + uint32_t read_mbox_idx; + uint32_t read_mbox_len; + uint32_t write_mbox_len; + + /* Protocols and its callback response */ + DOEProtocol *protocols; + uint16_t protocol_num; +}; + +void pcie_doe_init(PCIDevice *pdev, DOECap *doe_cap, uint16_t offset, + DOEProtocol *protocols, bool intr, uint16_t vec); +void pcie_doe_fini(DOECap *doe_cap); +bool pcie_doe_read_config(DOECap *doe_cap, uint32_t addr, int size, + uint32_t *buf); +void pcie_doe_write_config(DOECap *doe_cap, uint32_t addr, + uint32_t val, int size); +uint32_t pcie_doe_build_protocol(DOEProtocol *p); +void *pcie_doe_get_write_mbox_ptr(DOECap *doe_cap); +void pcie_doe_set_rsp(DOECap *doe_cap, void *rsp); +uint32_t pcie_doe_get_obj_len(void *obj); +#endif /* PCIE_DOE_H */ diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h index 076457b270e2..82d92177da9e 100644 --- a/include/hw/pci/pcie_host.h +++ b/include/hw/pci/pcie_host.h @@ -60,15 +60,15 @@ void pcie_host_mmcfg_update(PCIExpressHost *e, /* * PCI express ECAM (Enhanced Configuration Address Mapping) format. * AKA mmcfg address - * bit 20 - 28: bus number + * bit 20 - 27: bus number * bit 15 - 19: device number * bit 12 - 14: function number * bit 0 - 11: offset in configuration space of a given device */ -#define PCIE_MMCFG_SIZE_MAX (1ULL << 29) +#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) #define PCIE_MMCFG_SIZE_MIN (1ULL << 20) #define PCIE_MMCFG_BUS_BIT 20 -#define PCIE_MMCFG_BUS_MASK 0x1ff +#define PCIE_MMCFG_BUS_MASK 0xff #define PCIE_MMCFG_DEVFN_BIT 12 #define PCIE_MMCFG_DEVFN_MASK 0xff #define PCIE_MMCFG_CONFOFFSET_MASK 0xfff diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index e25b289ce84c..fd484afb3021 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -23,6 +23,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" +#include "hw/pci/pci_device.h" #include "qom/object.h" #define TYPE_PCIE_PORT "pcie-port" @@ -39,6 +40,8 @@ struct PCIEPort { void pcie_port_init_reg(PCIDevice *d); +PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn); + #define TYPE_PCIE_SLOT "pcie-slot" OBJECT_DECLARE_SIMPLE_TYPE(PCIESlot, PCIE_SLOT) @@ -78,7 +81,7 @@ DECLARE_CLASS_CHECKERS(PCIERootPortClass, PCIE_ROOT_PORT, struct PCIERootPortClass { PCIDeviceClass parent_class; DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; uint8_t (*aer_vector)(const PCIDevice *dev); int (*interrupts_init)(PCIDevice *dev, Error **errp); diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h index 1db86b0ec4d3..963dc2e170d1 100644 --- a/include/hw/pci/pcie_regs.h +++ b/include/hw/pci/pcie_regs.h @@ -179,4 +179,8 @@ typedef enum PCIExpLinkWidth { #define PCI_ACS_VER 0x1 #define PCI_ACS_SIZEOF 8 +/* DOE Capability Register Fields */ +#define PCI_DOE_VER 0x1 +#define PCI_DOE_SIZEOF 24 + #endif /* QEMU_PCIE_REGS_H */ diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h index 80f5c84e75cf..96cc7433091b 100644 --- a/include/hw/pci/pcie_sriov.h +++ b/include/hw/pci/pcie_sriov.h @@ -13,6 +13,8 @@ #ifndef QEMU_PCIE_SRIOV_H #define QEMU_PCIE_SRIOV_H +#include "hw/pci/pci.h" + struct PCIESriovPF { uint16_t num_vfs; /* Number of virtual functions created */ uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */ diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h index d5683b739908..89c7a3b7fa9f 100644 --- a/include/hw/pci/shpc.h +++ b/include/hw/pci/shpc.h @@ -3,7 +3,7 @@ #include "exec/memory.h" #include "hw/hotplug.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "migration/vmstate.h" struct SHPCDevice { diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 86cb7d7f971b..9ef7e2d0dc03 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,7 +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); #define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv") typedef struct PnvMachineClass PnvMachineClass; @@ -231,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_lpc.h b/include/hw/ppc/pnv_lpc.h index e893e763dd5f..8a8d1a3d4209 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -1,7 +1,7 @@ /* * QEMU PowerPC PowerNV LPC controller * - * Copyright (c) 2016, IBM Corporation. + * Copyright (c) 2016-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 @@ -20,7 +20,6 @@ #ifndef PPC_PNV_LPC_H #define PPC_PNV_LPC_H -#include "hw/ppc/pnv_psi.h" #include "qom/object.h" #define TYPE_PNV_LPC "pnv-lpc" @@ -84,15 +83,12 @@ struct PnvLpcController { MemoryRegion xscom_regs; /* PSI to generate interrupts */ - PnvPsi *psi; + qemu_irq psi_irq; }; - struct PnvLpcClass { DeviceClass parent_class; - int psi_irq; - DeviceRealize parent_realize; }; diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index f982ba002481..90a81dae2b8d 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -1,7 +1,7 @@ /* * QEMU PowerPC PowerNV Emulation of a few OCC related registers * - * Copyright (c) 2015-2017, IBM Corporation. + * Copyright (c) 2015-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 @@ -20,7 +20,6 @@ #ifndef PPC_PNV_OCC_H #define PPC_PNV_OCC_H -#include "hw/ppc/pnv_psi.h" #include "qom/object.h" #define TYPE_PNV_OCC "pnv-occ" @@ -44,19 +43,17 @@ struct PnvOCC { /* OCC Misc interrupt */ uint64_t occmisc; - PnvPsi *psi; + qemu_irq psi_irq; MemoryRegion xscom_regs; MemoryRegion sram_regs; }; - struct PnvOCCClass { DeviceClass parent_class; int xscom_size; const MemoryRegionOps *xscom_ops; - int psi_irq; }; #define PNV_OCC_SENSOR_DATA_BLOCK_BASE(i) \ diff --git a/include/hw/ppc/pnv_pnor.h b/include/hw/ppc/pnv_pnor.h index 99f9a3adfb54..bab2f798449d 100644 --- a/include/hw/ppc/pnv_pnor.h +++ b/include/hw/ppc/pnv_pnor.h @@ -6,8 +6,10 @@ * This code is licensed under the GPL version 2 or later. See the * COPYING file in the top-level directory. */ -#ifndef _PPC_PNV_PNOR_H -#define _PPC_PNV_PNOR_H + +#ifndef PPC_PNV_PNOR_H +#define PPC_PNV_PNOR_H + #include "qom/object.h" /* @@ -28,4 +30,4 @@ struct PnvPnor { MemoryRegion mmio; }; -#endif /* _PPC_PNV_PNOR_H */ +#endif /* PPC_PNV_PNOR_H */ diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h index eb841b34a1f7..2a6f715350b6 100644 --- a/include/hw/ppc/pnv_psi.h +++ b/include/hw/ppc/pnv_psi.h @@ -1,7 +1,7 @@ /* * QEMU PowerPC PowerNV Processor Service Interface (PSI) model * - * Copyright (c) 2015-2017, IBM Corporation. + * Copyright (c) 2015-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 @@ -23,7 +23,7 @@ #include "hw/sysbus.h" #include "hw/ppc/xics.h" #include "hw/ppc/xive.h" -#include "qom/object.h" +#include "hw/qdev-core.h" #define TYPE_PNV_PSI "pnv-psi" OBJECT_DECLARE_TYPE(PnvPsi, PnvPsiClass, @@ -79,13 +79,10 @@ struct PnvPsiClass { uint64_t bar_mask; const char *compat; int compat_size; - - void (*irq_set)(PnvPsi *psi, int, bool state); }; /* The PSI and FSP interrupts are muxed on the same IRQ number */ typedef enum PnvPsiIrq { - PSIHB_IRQ_PSI, /* internal use only */ PSIHB_IRQ_FSP, /* internal use only */ PSIHB_IRQ_OCC, PSIHB_IRQ_FSI, @@ -96,8 +93,6 @@ typedef enum PnvPsiIrq { #define PSI_NUM_INTERRUPTS 6 -void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state); - /* P9 PSI Interrupts */ #define PSIHB9_IRQ_PSI 0 #define PSIHB9_IRQ_OCC 1 diff --git a/include/hw/ppc/pnv_sbe.h b/include/hw/ppc/pnv_sbe.h new file mode 100644 index 000000000000..f54a3ae9bade --- /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 7c7440de0c40..c6e9ef8dd25a 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/ppc.h b/include/hw/ppc/ppc.h index 364f165b4b56..02af03ada285 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -99,11 +99,11 @@ enum { ARCH_MAC99_U3, }; -#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) -#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) -#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) -#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03) -#define FW_CFG_PPC_CLOCKFREQ (FW_CFG_ARCH_LOCAL + 0x04) +#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) +#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) +#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) +#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03) +#define FW_CFG_PPC_CLOCKFREQ (FW_CFG_ARCH_LOCAL + 0x04) #define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05) #define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06) #define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07) diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index 980f964b5a91..f8c86e09ec0b 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -27,26 +27,129 @@ #include "hw/ppc/ppc.h" #include "exec/memory.h" +#include "hw/sysbus.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); +#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" -void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, - MemoryRegion ram_memories[], - hwaddr ram_bases[], hwaddr ram_sizes[], - const ram_addr_t sdram_bank_sizes[]); +/* + * Generic DCR device + */ +#define TYPE_PPC4xx_DCR_DEVICE "ppc4xx-dcr-device" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxDcrDeviceState, PPC4xx_DCR_DEVICE); +struct Ppc4xxDcrDeviceState { + SysBusDevice parent_obj; -void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, - MemoryRegion ram_memories[], - hwaddr *ram_bases, - hwaddr *ram_sizes, - int do_init); + PowerPCCPU *cpu; +}; -void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, - qemu_irq irqs[4]); +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); -#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" +/* 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; +}; + +/* SDRAM DDR controller */ +typedef struct { + MemoryRegion ram; + MemoryRegion container; /* used for clipping */ + hwaddr base; + hwaddr size; + uint32_t bcr; +} Ppc4xxSdramBank; + +#define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29) +#define SDR0_DDR0_DDRM_DDR1 0x20000000 +#define SDR0_DDR0_DDRM_DDR2 0x40000000 + +#define TYPE_PPC4xx_SDRAM_DDR "ppc4xx-sdram-ddr" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxSdramDdrState, PPC4xx_SDRAM_DDR); +struct Ppc4xxSdramDdrState { + Ppc4xxDcrDeviceState parent_obj; + + MemoryRegion *dram_mr; + uint32_t nbanks; /* Banks to use from 4, e.g. when board has less slots */ + Ppc4xxSdramBank bank[4]; + qemu_irq irq; + + uint32_t addr; + uint32_t besr0; + uint32_t besr1; + uint32_t bear; + uint32_t cfg; + uint32_t status; + uint32_t rtr; + uint32_t pmit; + uint32_t tr; + uint32_t ecccfg; + uint32_t eccesr; +}; + +void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s); + +/* SDRAM DDR2 controller */ +#define TYPE_PPC4xx_SDRAM_DDR2 "ppc4xx-sdram-ddr2" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxSdramDdr2State, PPC4xx_SDRAM_DDR2); +struct Ppc4xxSdramDdr2State { + Ppc4xxDcrDeviceState parent_obj; + + MemoryRegion *dram_mr; + uint32_t nbanks; /* Banks to use from 4, e.g. when board has less slots */ + Ppc4xxSdramBank bank[4]; + + uint32_t addr; + uint32_t mcopt2; +}; + +void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s); #endif /* PPC4XX_H */ diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index f5c33dcc8616..5c8aabd4443d 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -12,7 +12,6 @@ #include "hw/ppc/spapr_xive.h" /* For SpaprXive */ #include "hw/ppc/xics.h" /* For ICSState */ #include "hw/ppc/spapr_tpm_proxy.h" -#include "hw/ppc/vof.h" struct SpaprVioBus; struct SpaprPhbState; @@ -22,6 +21,8 @@ typedef struct SpaprEventLogEntry SpaprEventLogEntry; typedef struct SpaprEventSource SpaprEventSource; typedef struct SpaprPendingHpt SpaprPendingHpt; +typedef struct Vof Vof; + #define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL #define SPAPR_ENTRY_POINT 0x100 @@ -164,6 +165,21 @@ struct SpaprMachineClass { SpaprIrq *irq; }; +#define WDT_MAX_WATCHDOGS 4 /* Maximum number of watchdog devices */ + +#define TYPE_SPAPR_WDT "spapr-wdt" +OBJECT_DECLARE_SIMPLE_TYPE(SpaprWatchdog, SPAPR_WDT) + +typedef struct SpaprWatchdog { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + + QEMUTimer timer; + uint8_t action; /* One of PSERIES_WDTF_ACTION_xxx */ + uint8_t leave_others; /* leaveOtherWatchdogsRunningOnTimeout */ +} SpaprWatchdog; + /** * SpaprMachineState: */ @@ -194,7 +210,7 @@ struct SpaprMachineState { Vof *vof; uint64_t rtc_offset; /* Now used only during incoming migration */ struct PPCTimebase tb; - bool has_graphics; + bool want_stdout_path; uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */ /* Nested HV support (TCG only) */ @@ -264,6 +280,8 @@ struct SpaprMachineState { uint32_t FORM2_assoc_array[NUMA_NODES_MAX_NUM][FORM2_NUMA_ASSOC_SIZE]; Error *fwnmi_migration_blocker; + + SpaprWatchdog wds[WDT_MAX_WATCHDOGS]; }; #define H_SUCCESS 0 @@ -344,6 +362,7 @@ struct SpaprMachineState { #define H_P7 -60 #define H_P8 -61 #define H_P9 -62 +#define H_NOOP -63 #define H_UNSUPPORTED -67 #define H_OVERLAP -68 #define H_UNSUPPORTED_FLAG -256 @@ -564,8 +583,9 @@ struct SpaprMachineState { #define H_SCM_HEALTH 0x400 #define H_RPT_INVALIDATE 0x448 #define H_SCM_FLUSH 0x44C +#define H_WATCHDOG 0x45C -#define MAX_HCALL_OPCODE H_SCM_FLUSH +#define MAX_HCALL_OPCODE H_WATCHDOG /* The hcalls above are standardized in PAPR and implemented by pHyp * as well. @@ -745,6 +765,7 @@ void push_sregs_to_kvm_pr(SpaprMachineState *spapr); #define RTAS_DDW_PGSIZE_128M 0x20 #define RTAS_DDW_PGSIZE_256M 0x40 #define RTAS_DDW_PGSIZE_16G 0x80 +#define RTAS_DDW_PGSIZE_2M 0x100 /* RTAS tokens */ #define RTAS_TOKEN_BASE 0x2000 @@ -828,7 +849,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) @@ -838,7 +860,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, @@ -901,6 +923,7 @@ struct SpaprTceTable { bool bypass; bool need_vfio; bool skipping_replay; + bool def_win; int fd; MemoryRegion root; IOMMUMemoryRegion iommu; @@ -1026,6 +1049,7 @@ extern const VMStateDescription vmstate_spapr_cap_large_decr; extern const VMStateDescription vmstate_spapr_cap_ccf_assist; extern const VMStateDescription vmstate_spapr_cap_fwnmi; extern const VMStateDescription vmstate_spapr_cap_rpt_invalidate; +extern const VMStateDescription vmstate_spapr_wdt; static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap) { @@ -1062,4 +1086,7 @@ target_ulong spapr_vof_client_architecture_support(MachineState *ms, target_ulong ovec_addr); void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt); +/* H_WATCHDOG */ +void spapr_watchdog_init(SpaprMachineState *spapr); + #endif /* HW_SPAPR_H */ diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h index f8c0effcaf88..d3f293da8b76 100644 --- a/include/hw/ppc/vof.h +++ b/include/hw/ppc/vof.h @@ -9,7 +9,7 @@ #include "qom/object.h" #include "exec/address-spaces.h" #include "exec/memory.h" -#include "cpu.h" +#include "exec/cpu-defs.h" typedef struct Vof { uint64_t top_addr; /* copied from rma_size */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 00b80b08c272..95ead0dd7c9f 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -95,7 +95,7 @@ struct ICSStateClass { DeviceClass parent_class; DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; void (*reject)(ICSState *s, uint32_t irq); void (*resend)(ICSState *s); diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 126e4e2c3a17..f7eea4ca8178 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -527,6 +527,7 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp); void xive_tctx_reset(XiveTCTX *tctx); void xive_tctx_destroy(XiveTCTX *tctx); void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb); +void xive_tctx_reset_os_signal(XiveTCTX *tctx); /* * KVM XIVE device helpers diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index c443218475bb..4dc02b0de472 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -33,9 +33,17 @@ * to stderr when the guest attempts to enable the timer. */ -/* The default ptimer policy retains backward compatibility with the legacy - * timers. Custom policies are adjusting the default one. Consider providing - * a correct policy for your timer. +/* + * The 'legacy' ptimer policy retains backward compatibility with the + * traditional ptimer behaviour from before policy flags were introduced. + * It has several weird behaviours which don't match typical hardware + * timer behaviour. For a new device using ptimers, you should not + * use PTIMER_POLICY_LEGACY, but instead check the actual behaviour + * that you need and specify the right set of policy flags to get that. + * + * If you are overhauling an existing device that uses PTIMER_POLICY_LEGACY + * and are in a position to check or test the real hardware behaviour, + * consider updating it to specify the right policy flags. * * The rough edges of the default policy: * - Starting to run with a period = 0 emits error message and stops the @@ -54,7 +62,7 @@ * since the last period, effectively restarting the timer with a * counter = counter value at the moment of change (.i.e. one less). */ -#define PTIMER_POLICY_DEFAULT 0 +#define PTIMER_POLICY_LEGACY 0 /* Periodic timer counter stays with "0" for a one period before wrapping * around. */ diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 92c3d6520866..35fddb19a649 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -193,6 +193,7 @@ struct DeviceState { int instance_id_alias; int alias_required_for_version; ResettableState reset; + GSList *unplug_blockers; }; struct DeviceListener { @@ -385,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. @@ -419,6 +420,34 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, void qdev_machine_creation_done(void); bool qdev_machine_modified(void); +/** + * qdev_add_unplug_blocker: Add an unplug blocker to a device + * + * @dev: Device to be blocked from unplug + * @reason: Reason for blocking + */ +void qdev_add_unplug_blocker(DeviceState *dev, Error *reason); + +/** + * qdev_del_unplug_blocker: Remove an unplug blocker from a device + * + * @dev: Device to be unblocked + * @reason: Pointer to the Error used with qdev_add_unplug_blocker. + * Used as a handle to lookup the blocker for deletion. + */ +void qdev_del_unplug_blocker(DeviceState *dev, Error *reason); + +/** + * qdev_unplug_blocked: Confirm if a device is blocked from unplug + * + * @dev: Device to be tested + * @reason: Returns one of the reasons why the device is blocked, + * if any + * + * Returns: true if device is blocked from unplug, false otherwise + */ +bool qdev_unplug_blocked(DeviceState *dev, Error **errp); + /** * GpioPolarity: Polarity of a GPIO line * @@ -714,32 +743,6 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, void *opaque); -/** - * @qdev_reset_all: - * Reset @dev. See @qbus_reset_all() for more details. - * - * Note: This function is deprecated and will be removed when it becomes unused. - * Please use device_cold_reset() now. - */ -void qdev_reset_all(DeviceState *dev); -void qdev_reset_all_fn(void *opaque); - -/** - * @qbus_reset_all: - * @bus: Bus to be reset. - * - * Reset @bus and perform a bus-level ("hard") reset of all devices connected - * to it, including recursive processing of all buses below @bus itself. A - * hard reset means that qbus_reset_all will reset all state of the device. - * For PCI devices, for example, this will include the base address registers - * or configuration space. - * - * Note: This function is deprecated and will be removed when it becomes unused. - * Please use bus_cold_reset() now. - */ -void qbus_reset_all(BusState *bus); -void qbus_reset_all_fn(void *opaque); - /** * device_cold_reset: * Reset device @dev and perform a recursive processing using the resettable @@ -773,15 +776,6 @@ BusState *sysbus_get_default(void); char *qdev_get_fw_dev_path(DeviceState *dev); char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev); -/** - * device_legacy_reset: - * - * Reset a single device (by calling the reset method). - * Note: This function is deprecated and will be removed when it becomes unused. - * Please use device_cold_reset() now. - */ -void device_legacy_reset(DeviceState *dev); - void device_class_set_props(DeviceClass *dc, Property *props); /** diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index f7925f67d03b..e1df08876c6a 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -17,6 +17,7 @@ struct Property { const PropertyInfo *info; ptrdiff_t offset; uint8_t bitnr; + uint64_t bitmask; bool set_default; union { int64_t i; @@ -54,6 +55,7 @@ extern const PropertyInfo qdev_prop_uint16; extern const PropertyInfo qdev_prop_uint32; extern const PropertyInfo qdev_prop_int32; extern const PropertyInfo qdev_prop_uint64; +extern const PropertyInfo qdev_prop_uint64_checkmask; extern const PropertyInfo qdev_prop_int64; extern const PropertyInfo qdev_prop_size; extern const PropertyInfo qdev_prop_string; @@ -103,6 +105,16 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval) +/** + * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value + * against corresponding bitmask, rejects the value if it violates. + * The default value is set in instance_init(). + */ +#define DEFINE_PROP_UINT64_CHECKMASK(_name, _state, _field, _bitmask) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_uint64_checkmask, uint64_t, \ + .bitmask = (_bitmask), \ + .set_default = false) + #define PROP_ARRAY_LEN_PREFIX "len-" /** diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h index 3a88e135d025..1330ca77de61 100644 --- a/include/hw/registerfields.h +++ b/include/hw/registerfields.h @@ -154,4 +154,74 @@ #define ARRAY_FIELD_DP64(regs, reg, field, val) \ (regs)[R_ ## reg] = FIELD_DP64((regs)[R_ ## reg], reg, field, val); + +/* + * These macros can be used for defining and extracting fields that have the + * same bit position across multiple registers. + */ + +/* Define shared SHIFT, LENGTH, and MASK constants */ +#define SHARED_FIELD(name, shift, length) \ + enum { name ## _ ## SHIFT = (shift)}; \ + enum { name ## _ ## LENGTH = (length)}; \ + enum { name ## _ ## MASK = MAKE_64BIT_MASK(shift, length)}; + +/* Extract a shared field */ +#define SHARED_FIELD_EX8(storage, field) \ + extract8((storage), field ## _SHIFT, field ## _LENGTH) + +#define SHARED_FIELD_EX16(storage, field) \ + extract16((storage), field ## _SHIFT, field ## _LENGTH) + +#define SHARED_FIELD_EX32(storage, field) \ + extract32((storage), field ## _SHIFT, field ## _LENGTH) + +#define SHARED_FIELD_EX64(storage, field) \ + extract64((storage), field ## _SHIFT, field ## _LENGTH) + +/* Extract a shared field from a register array */ +#define SHARED_ARRAY_FIELD_EX32(regs, offset, field) \ + SHARED_FIELD_EX32((regs)[(offset)], field) +#define SHARED_ARRAY_FIELD_EX64(regs, offset, field) \ + SHARED_FIELD_EX64((regs)[(offset)], field) + +/* Deposit a shared field */ +#define SHARED_FIELD_DP8(storage, field, val) ({ \ + struct { \ + unsigned int v:field ## _LENGTH; \ + } _v = { .v = val }; \ + uint8_t _d; \ + _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \ + _d; }) + +#define SHARED_FIELD_DP16(storage, field, val) ({ \ + struct { \ + unsigned int v:field ## _LENGTH; \ + } _v = { .v = val }; \ + uint16_t _d; \ + _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \ + _d; }) + +#define SHARED_FIELD_DP32(storage, field, val) ({ \ + struct { \ + unsigned int v:field ## _LENGTH; \ + } _v = { .v = val }; \ + uint32_t _d; \ + _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \ + _d; }) + +#define SHARED_FIELD_DP64(storage, field, val) ({ \ + struct { \ + uint64_t v:field ## _LENGTH; \ + } _v = { .v = val }; \ + uint64_t _d; \ + _d = deposit64((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \ + _d; }) + +/* Deposit a shared field to a register array */ +#define SHARED_ARRAY_FIELD_DP32(regs, offset, field, val) \ + (regs)[(offset)] = SHARED_FIELD_DP32((regs)[(offset)], field, val); +#define SHARED_ARRAY_FIELD_DP64(regs, offset, field, val) \ + (regs)[(offset)] = SHARED_FIELD_DP64((regs)[(offset)], field, val); + #endif diff --git a/include/hw/remote/iohub.h b/include/hw/remote/iohub.h index 0bf98e0d78c7..6a8444f9a97f 100644 --- a/include/hw/remote/iohub.h +++ b/include/hw/remote/iohub.h @@ -11,7 +11,7 @@ #ifndef REMOTE_IOHUB_H #define REMOTE_IOHUB_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "qemu/event_notifier.h" #include "qemu/thread-posix.h" #include "hw/remote/mpqemu-link.h" diff --git a/include/hw/remote/iommu.h b/include/hw/remote/iommu.h new file mode 100644 index 000000000000..33b68a8f4bf0 --- /dev/null +++ b/include/hw/remote/iommu.h @@ -0,0 +1,40 @@ +/** + * Copyright © 2022 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef REMOTE_IOMMU_H +#define REMOTE_IOMMU_H + +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci.h" + +#ifndef INT2VOIDP +#define INT2VOIDP(i) (void *)(uintptr_t)(i) +#endif + +typedef struct RemoteIommuElem { + MemoryRegion *mr; + + AddressSpace as; +} RemoteIommuElem; + +#define TYPE_REMOTE_IOMMU "x-remote-iommu" +OBJECT_DECLARE_SIMPLE_TYPE(RemoteIommu, REMOTE_IOMMU) + +struct RemoteIommu { + Object parent; + + GHashTable *elem_by_devfn; + + QemuMutex lock; +}; + +void remote_iommu_setup(PCIBus *pci_bus); + +void remote_iommu_unplug_dev(PCIDevice *pci_dev); + +#endif diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h index 2a2a33c4b2c9..ac32fda3875e 100644 --- a/include/hw/remote/machine.h +++ b/include/hw/remote/machine.h @@ -22,6 +22,10 @@ struct RemoteMachineState { RemotePCIHost *host; RemoteIOHubState iohub; + + bool vfio_user; + + bool auto_shutdown; }; /* Used to pass to co-routine device and ioc. */ diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h index 741def71f1a5..0cfd9665bedf 100644 --- a/include/hw/remote/proxy.h +++ b/include/hw/remote/proxy.h @@ -9,7 +9,7 @@ #ifndef PROXY_H #define PROXY_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "io/channel.h" #include "hw/remote/proxy-memory-listener.h" #include "qemu/event_notifier.h" diff --git a/include/hw/remote/vfio-user-obj.h b/include/hw/remote/vfio-user-obj.h new file mode 100644 index 000000000000..87ab78b875ce --- /dev/null +++ b/include/hw/remote/vfio-user-obj.h @@ -0,0 +1,6 @@ +#ifndef VFIO_USER_OBJ_H +#define VFIO_USER_OBJ_H + +void vfu_object_set_bus_irq(PCIBus *pci_bus); + +#endif diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index d937c5c224b9..93e5f8760dfc 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -46,16 +46,17 @@ target_ulong riscv_load_kernel(const char *kernel_filename, symbol_fn_t sym_cb); hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start); -uint32_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); +uint64_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, hwaddr rom_base, hwaddr rom_size, uint64_t kernel_entry, - uint32_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, uint64_t kernel_entry); void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr); +void riscv_setup_firmware_boot(MachineState *machine); #endif /* RISCV_BOOT_H */ diff --git a/include/hw/riscv/boot_opensbi.h b/include/hw/riscv/boot_opensbi.h index 0d5ddd6c3daf..1b749663dcab 100644 --- a/include/hw/riscv/boot_opensbi.h +++ b/include/hw/riscv/boot_opensbi.h @@ -4,8 +4,11 @@ * * Based on include/sbi/{fw_dynamic.h,sbi_scratch.h} from the OpenSBI project. */ -#ifndef OPENSBI_H -#define OPENSBI_H + +#ifndef RISCV_BOOT_OPENSBI_H +#define RISCV_BOOT_OPENSBI_H + +#include "exec/cpu-defs.h" /** Expected value of info magic ('OSBI' ascii string in hex) */ #define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f diff --git a/include/hw/riscv/microchip_pfsoc.h b/include/hw/riscv/microchip_pfsoc.h index a0673f5f59c1..daef086da602 100644 --- a/include/hw/riscv/microchip_pfsoc.h +++ b/include/hw/riscv/microchip_pfsoc.h @@ -22,13 +22,16 @@ #ifndef HW_MICROCHIP_PFSOC_H #define HW_MICROCHIP_PFSOC_H +#include "hw/boards.h" #include "hw/char/mchp_pfsoc_mmuart.h" +#include "hw/cpu/cluster.h" #include "hw/dma/sifive_pdma.h" #include "hw/misc/mchp_pfsoc_dmc.h" #include "hw/misc/mchp_pfsoc_ioscb.h" #include "hw/misc/mchp_pfsoc_sysreg.h" #include "hw/net/cadence_gem.h" #include "hw/sd/cadence_sdhci.h" +#include "hw/riscv/riscv_hart.h" typedef struct MicrochipPFSoCState { /*< private >*/ @@ -88,8 +91,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 +103,30 @@ 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_FIC0, + MICROCHIP_PFSOC_FABRIC_FIC1, + MICROCHIP_PFSOC_FABRIC_FIC3, MICROCHIP_PFSOC_DRAM_LO, MICROCHIP_PFSOC_DRAM_LO_ALIAS, MICROCHIP_PFSOC_DRAM_HI, @@ -133,14 +150,15 @@ enum { MICROCHIP_PFSOC_MMUART2_IRQ = 92, MICROCHIP_PFSOC_MMUART3_IRQ = 93, MICROCHIP_PFSOC_MMUART4_IRQ = 94, + MICROCHIP_PFSOC_MAILBOX_IRQ = 96, }; #define MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT 1 #define MICROCHIP_PFSOC_COMPUTE_CPU_COUNT 4 -#define MICROCHIP_PFSOC_PLIC_NUM_SOURCES 185 +#define MICROCHIP_PFSOC_PLIC_NUM_SOURCES 187 #define MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES 7 -#define MICROCHIP_PFSOC_PLIC_PRIORITY_BASE 0x04 +#define MICROCHIP_PFSOC_PLIC_PRIORITY_BASE 0x00 #define MICROCHIP_PFSOC_PLIC_PENDING_BASE 0x1000 #define MICROCHIP_PFSOC_PLIC_ENABLE_BASE 0x2000 #define MICROCHIP_PFSOC_PLIC_ENABLE_STRIDE 0x80 diff --git a/include/hw/riscv/numa.h b/include/hw/riscv/numa.h index fcce942ceeca..1a9cce334400 100644 --- a/include/hw/riscv/numa.h +++ b/include/hw/riscv/numa.h @@ -19,6 +19,7 @@ #ifndef RISCV_NUMA_H #define RISCV_NUMA_H +#include "hw/boards.h" #include "hw/sysbus.h" #include "sysemu/numa.h" diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 00da9ded4388..7659d1bc5b1f 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -23,11 +23,18 @@ #include "hw/intc/sifive_plic.h" #include "hw/char/ibex_uart.h" #include "hw/timer/ibex_timer.h" +#include "hw/ssi/ibex_spi_host.h" #include "qom/object.h" #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc" OBJECT_DECLARE_SIMPLE_TYPE(LowRISCIbexSoCState, RISCV_IBEX_SOC) +enum { + OPENTITAN_SPI_HOST0, + OPENTITAN_SPI_HOST1, + OPENTITAN_NUM_SPI_HOSTS, +}; + struct LowRISCIbexSoCState { /*< private >*/ SysBusDevice parent_obj; @@ -37,6 +44,9 @@ struct LowRISCIbexSoCState { SiFivePLICState plic; IbexUartState uart; IbexTimerState timer; + IbexSPIHostState spi_host[OPENTITAN_NUM_SPI_HOSTS]; + + uint32_t resetvec; MemoryRegion flash_mem; MemoryRegion rom; @@ -66,11 +76,12 @@ 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, IBEX_DEV_PINMUX, - IBEX_DEV_PADCTRL, + IBEX_DEV_AON_TIMER, IBEX_DEV_USBDEV, IBEX_DEV_FLASH_CTRL, IBEX_DEV_PLIC, @@ -89,15 +100,19 @@ enum { }; enum { - IBEX_TIMER_TIMEREXPIRED0_0 = 126, - IBEX_UART0_RX_PARITY_ERR_IRQ = 8, - IBEX_UART0_RX_TIMEOUT_IRQ = 7, - IBEX_UART0_RX_BREAK_ERR_IRQ = 6, - IBEX_UART0_RX_FRAME_ERR_IRQ = 5, - IBEX_UART0_RX_OVERFLOW_IRQ = 4, - IBEX_UART0_TX_EMPTY_IRQ = 3, - IBEX_UART0_RX_WATERMARK_IRQ = 2, - IBEX_UART0_TX_WATERMARK_IRQ = 1, + IBEX_UART0_TX_WATERMARK_IRQ = 1, + IBEX_UART0_RX_WATERMARK_IRQ = 2, + IBEX_UART0_TX_EMPTY_IRQ = 3, + IBEX_UART0_RX_OVERFLOW_IRQ = 4, + IBEX_UART0_RX_FRAME_ERR_IRQ = 5, + IBEX_UART0_RX_BREAK_ERR_IRQ = 6, + IBEX_UART0_RX_TIMEOUT_IRQ = 7, + IBEX_UART0_RX_PARITY_ERR_IRQ = 8, + IBEX_TIMER_TIMEREXPIRED0_0 = 127, + IBEX_SPI_HOST0_ERR_IRQ = 134, + IBEX_SPI_HOST0_SPI_EVENT_IRQ = 135, + IBEX_SPI_HOST1_ERR_IRQ = 136, + IBEX_SPI_HOST1_SPI_EVENT_IRQ = 137, }; #endif diff --git a/include/hw/riscv/shakti_c.h b/include/hw/riscv/shakti_c.h index 50a2b7908608..539fe1156de1 100644 --- a/include/hw/riscv/shakti_c.h +++ b/include/hw/riscv/shakti_c.h @@ -16,8 +16,8 @@ * this program. If not, see . */ -#ifndef HW_SHAKTI_H -#define HW_SHAKTI_H +#ifndef HW_SHAKTI_C_H +#define HW_SHAKTI_C_H #include "hw/riscv/riscv_hart.h" #include "hw/boards.h" @@ -65,7 +65,7 @@ enum { #define SHAKTI_C_PLIC_NUM_SOURCES 28 /* Excluding Priority 0 */ #define SHAKTI_C_PLIC_NUM_PRIORITIES 2 -#define SHAKTI_C_PLIC_PRIORITY_BASE 0x04 +#define SHAKTI_C_PLIC_PRIORITY_BASE 0x00 #define SHAKTI_C_PLIC_PENDING_BASE 0x1000 #define SHAKTI_C_PLIC_ENABLE_BASE 0x2000 #define SHAKTI_C_PLIC_ENABLE_STRIDE 0x80 diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 83604da805c3..b824a79e2d83 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; @@ -81,9 +82,14 @@ enum { }; #define SIFIVE_E_PLIC_HART_CONFIG "M" -#define SIFIVE_E_PLIC_NUM_SOURCES 127 +/* + * Freedom E310 G002 and G003 supports 52 interrupt sources while + * Freedom E310 G000 supports 51 interrupt sources. We use the value + * of G002 and G003, so it is 53 (including interrupt source 0). + */ +#define SIFIVE_E_PLIC_NUM_SOURCES 53 #define SIFIVE_E_PLIC_NUM_PRIORITIES 7 -#define SIFIVE_E_PLIC_PRIORITY_BASE 0x04 +#define SIFIVE_E_PLIC_PRIORITY_BASE 0x00 #define SIFIVE_E_PLIC_PENDING_BASE 0x1000 #define SIFIVE_E_PLIC_ENABLE_BASE 0x2000 #define SIFIVE_E_PLIC_ENABLE_STRIDE 0x80 diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 8f63a183c474..a67328f7adce 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -19,6 +19,8 @@ #ifndef HW_SIFIVE_U_H #define HW_SIFIVE_U_H +#include "hw/boards.h" +#include "hw/cpu/cluster.h" #include "hw/dma/sifive_pdma.h" #include "hw/net/cadence_gem.h" #include "hw/riscv/riscv_hart.h" @@ -158,7 +160,7 @@ enum { #define SIFIVE_U_PLIC_NUM_SOURCES 54 #define SIFIVE_U_PLIC_NUM_PRIORITIES 7 -#define SIFIVE_U_PLIC_PRIORITY_BASE 0x04 +#define SIFIVE_U_PLIC_PRIORITY_BASE 0x00 #define SIFIVE_U_PLIC_PENDING_BASE 0x1000 #define SIFIVE_U_PLIC_ENABLE_BASE 0x2000 #define SIFIVE_U_PLIC_ENABLE_STRIDE 0x80 diff --git a/include/hw/riscv/spike.h b/include/hw/riscv/spike.h index 73d69234de30..73bf2a9aade6 100644 --- a/include/hw/riscv/spike.h +++ b/include/hw/riscv/spike.h @@ -19,9 +19,9 @@ #ifndef HW_RISCV_SPIKE_H #define HW_RISCV_SPIKE_H +#include "hw/boards.h" #include "hw/riscv/riscv_hart.h" #include "hw/sysbus.h" -#include "qom/object.h" #define SPIKE_CPUS_MAX 8 #define SPIKE_SOCKETS_MAX 8 diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 78b058ec8683..b3d26135c0ac 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -19,10 +19,10 @@ #ifndef HW_RISCV_VIRT_H #define HW_RISCV_VIRT_H +#include "hw/boards.h" #include "hw/riscv/riscv_hart.h" #include "hw/sysbus.h" #include "hw/block/flash.h" -#include "qom/object.h" #define VIRT_CPUS_MAX_BITS 9 #define VIRT_CPUS_MAX (1 << VIRT_CPUS_MAX_BITS) @@ -45,6 +45,8 @@ struct RISCVVirtState { MachineState parent; /*< public >*/ + Notifier machine_done; + DeviceState *platform_bus_dev; RISCVHartArrayState soc[VIRT_SOCKETS_MAX]; DeviceState *irqchip[VIRT_SOCKETS_MAX]; PFlashCFI01 *flash[2]; @@ -75,6 +77,7 @@ enum { VIRT_DRAM, VIRT_PCIE_MMIO, VIRT_PCIE_PIO, + VIRT_PLATFORM_BUS, VIRT_PCIE_ECAM }; @@ -84,17 +87,18 @@ enum { VIRTIO_IRQ = 1, /* 1 to 8 */ VIRTIO_COUNT = 8, PCIE_IRQ = 0x20, /* 32 to 35 */ - VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */ + VIRT_PLATFORM_BUS_IRQ = 64, /* 64 to 95 */ }; -#define VIRT_IRQCHIP_IPI_MSI 1 +#define VIRT_PLATFORM_BUS_NUM_IRQS 32 + #define VIRT_IRQCHIP_NUM_MSIS 255 -#define VIRT_IRQCHIP_NUM_SOURCES VIRTIO_NDEV +#define VIRT_IRQCHIP_NUM_SOURCES 96 #define VIRT_IRQCHIP_NUM_PRIO_BITS 3 #define VIRT_IRQCHIP_MAX_GUESTS_BITS 3 #define VIRT_IRQCHIP_MAX_GUESTS ((1U << VIRT_IRQCHIP_MAX_GUESTS_BITS) - 1U) -#define VIRT_PLIC_PRIORITY_BASE 0x04 +#define VIRT_PLIC_PRIORITY_BASE 0x00 #define VIRT_PLIC_PENDING_BASE 0x1000 #define VIRT_PLIC_ENABLE_BASE 0x2000 #define VIRT_PLIC_ENABLE_STRIDE 0x80 @@ -105,6 +109,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 79ca7daf5dd5..162be3386362 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/rtc/m48t59.h b/include/hw/rtc/m48t59.h index d9b45eb16128..c14937476c1c 100644 --- a/include/hw/rtc/m48t59.h +++ b/include/hw/rtc/m48t59.h @@ -47,4 +47,4 @@ struct NvramClass { void (*toggle_lock)(Nvram *obj, int lock); }; -#endif /* HW_M48T59_H */ +#endif /* HW_RTC_M48T59_H */ diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h index deef93f89a32..1db0fcee926a 100644 --- a/include/hw/rtc/mc146818rtc.h +++ b/include/hw/rtc/mc146818rtc.h @@ -26,6 +26,7 @@ struct RTCState { uint8_t cmos_data[128]; uint8_t cmos_index; uint8_t isairq; + uint16_t io_base; int32_t base_year; uint64_t base_rtc; uint64_t last_update; @@ -49,11 +50,10 @@ struct RTCState { }; #define RTC_ISA_IRQ 8 -#define RTC_ISA_BASE 0x70 ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); int rtc_get_memory(ISADevice *dev, int addr); -#endif /* MC146818RTC_H */ +#endif /* HW_RTC_MC146818RTC_H */ diff --git a/include/hw/rtc/sun4v-rtc.h b/include/hw/rtc/sun4v-rtc.h index fd868f6ed2fa..fc54dfcba473 100644 --- a/include/hw/rtc/sun4v-rtc.h +++ b/include/hw/rtc/sun4v-rtc.h @@ -9,8 +9,8 @@ * version. */ -#ifndef HW_RTC_SUN4V -#define HW_RTC_SUN4V +#ifndef HW_RTC_SUN4V_RTC_H +#define HW_RTC_SUN4V_RTC_H #include "exec/hwaddr.h" diff --git a/include/hw/rtc/xlnx-zynqmp-rtc.h b/include/hw/rtc/xlnx-zynqmp-rtc.h index 5f1ad0a9462f..f0c6a2d78a84 100644 --- a/include/hw/rtc/xlnx-zynqmp-rtc.h +++ b/include/hw/rtc/xlnx-zynqmp-rtc.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef HW_RTC_XLNX_ZYNQMP_H -#define HW_RTC_XLNX_ZYNQMP_H +#ifndef HW_RTC_XLNX_ZYNQMP_RTC_H +#define HW_RTC_XLNX_ZYNQMP_RTC_H #include "hw/register.h" #include "hw/sysbus.h" diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 3ed80dba0dd3..73ceeb58e55a 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -21,8 +21,8 @@ * this program. If not, see . */ -#ifndef HW_RX_RX62N_MCU_H -#define HW_RX_RX62N_MCU_H +#ifndef HW_RX_RX62N_H +#define HW_RX_RX62N_H #include "target/rx/cpu.h" #include "hw/intc/rx_icu.h" diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h index 1f1f545bfc20..9360aa109148 100644 --- a/include/hw/s390x/pv.h +++ b/include/hw/s390x/pv.h @@ -38,6 +38,7 @@ static inline bool s390_is_pv(void) return ccw->pv; } +int s390_pv_query_info(void); int s390_pv_vm_enable(void); void s390_pv_vm_disable(void); int s390_pv_set_sec_parms(uint64_t origin, uint64_t length); @@ -46,8 +47,17 @@ void s390_pv_prep_reset(void); int s390_pv_verify(void); void s390_pv_unshare(void); void s390_pv_inject_reset_error(CPUState *cs); +uint64_t kvm_s390_pv_dmp_get_size_cpu(void); +uint64_t kvm_s390_pv_dmp_get_size_mem_state(void); +uint64_t kvm_s390_pv_dmp_get_size_completion_data(void); +bool kvm_s390_pv_info_basic_valid(void); +int kvm_s390_dump_init(void); +int kvm_s390_dump_cpu(S390CPU *cpu, void *buff); +int kvm_s390_dump_mem_state(uint64_t addr, size_t len, void *dest); +int kvm_s390_dump_completion_data(void *buff); #else /* CONFIG_KVM */ static inline bool s390_is_pv(void) { return false; } +static inline int s390_pv_query_info(void) { return 0; } static inline int s390_pv_vm_enable(void) { return 0; } static inline void s390_pv_vm_disable(void) {} static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; } @@ -56,6 +66,15 @@ static inline void s390_pv_prep_reset(void) {} static inline int s390_pv_verify(void) { return 0; } static inline void s390_pv_unshare(void) {} static inline void s390_pv_inject_reset_error(CPUState *cs) {}; +static inline uint64_t kvm_s390_pv_dmp_get_size_cpu(void) { return 0; } +static inline uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) { return 0; } +static inline uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) { return 0; } +static inline bool kvm_s390_pv_info_basic_valid(void) { return false; } +static inline int kvm_s390_dump_init(void) { return 0; } +static inline int kvm_s390_dump_cpu(S390CPU *cpu, void *buff) { return 0; } +static inline int kvm_s390_dump_mem_state(uint64_t addr, size_t len, + void *dest) { return 0; } +static inline int kvm_s390_dump_completion_data(void *buff) { return 0; } #endif /* CONFIG_KVM */ int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index da3cde2bb425..e0a9f9385be7 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -39,6 +39,9 @@ #define UID_CHECKING_ENABLED 0x01 #define ZPCI_DTSM 0x40 +/* zPCI Function Types */ +#define ZPCI_PFT_ISM 5 + OBJECT_DECLARE_SIMPLE_TYPE(S390pciState, S390_PCI_HOST_BRIDGE) OBJECT_DECLARE_SIMPLE_TYPE(S390PCIBus, S390_PCI_BUS) OBJECT_DECLARE_SIMPLE_TYPE(S390PCIBusDevice, S390_PCI_DEVICE) @@ -278,6 +281,7 @@ struct S390PCIIOMMU { uint64_t g_iota; uint64_t pba; uint64_t pal; + uint64_t max_dma_limit; GHashTable *iotlb; S390PCIDMACount *dma_limit; }; @@ -315,13 +319,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; @@ -340,6 +347,7 @@ struct S390PCIBusDevice { uint16_t noi; uint16_t maxstbl; uint8_t sum; + uint8_t pft; S390PCIGroup *pci_group; ClpRspQueryPci zpci_fn; S390MsixInfo msix; @@ -348,8 +356,11 @@ struct S390PCIBusDevice { MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; + Notifier shutdown_notifier; bool pci_unplug_request_processed; bool unplug_requested; + bool interp; + bool forwarding_assist; QTAILQ_ENTRY(S390PCIBusDevice) link; }; @@ -368,6 +379,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-clp.h b/include/hw/s390x/s390-pci-clp.h index cc8c8662b89b..03b7f9ba5f74 100644 --- a/include/hw/s390x/s390-pci-clp.h +++ b/include/hw/s390x/s390-pci-clp.h @@ -9,8 +9,8 @@ * directory. */ -#ifndef HW_S390_PCI_CLP -#define HW_S390_PCI_CLP +#ifndef HW_S390_PCI_CLP_H +#define HW_S390_PCI_CLP_H /* CLP common request & response block size */ #define CLP_BLK_SIZE 4096 diff --git a/include/hw/s390x/s390-pci-kvm.h b/include/hw/s390x/s390-pci-kvm.h new file mode 100644 index 000000000000..933814a4025b --- /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 ff708aef500f..ae1b126ff70b 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 3331990e02bf..9bba21a9167c 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -39,6 +39,7 @@ struct S390CcwMachineClass { bool cpu_model_allowed; bool css_migration_enabled; bool hpage_1m_allowed; + int max_threads; }; /* runtime-instrumentation allowed by the machine */ diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 1ffb367f94f0..6ea4b64fe796 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); @@ -186,20 +186,21 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, BlockdevOnError rerror, BlockdevOnError werror, const char *serial, Error **errp); +void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense); void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); -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); @@ -226,4 +227,10 @@ SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun); /* scsi-generic.c. */ extern const SCSIReqOps scsi_generic_req_ops; +/* scsi-disk.c */ +#define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0 +#define SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD 1 +#define SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE 2 +#define SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED 3 + #endif diff --git a/include/hw/sd/allwinner-sdhost.h b/include/hw/sd/allwinner-sdhost.h index bfe08ff4ef21..30c1e6040417 100644 --- a/include/hw/sd/allwinner-sdhost.h +++ b/include/hw/sd/allwinner-sdhost.h @@ -130,6 +130,7 @@ struct AwSdHostClass { /** Maximum buffer size in bytes per DMA descriptor */ size_t max_desc_size; + bool is_sun4i; }; diff --git a/include/hw/sd/npcm7xx_sdhci.h b/include/hw/sd/npcm7xx_sdhci.h index d728f0a40de4..ad8002f766dd 100644 --- a/include/hw/sd/npcm7xx_sdhci.h +++ b/include/hw/sd/npcm7xx_sdhci.h @@ -51,7 +51,7 @@ typedef struct NPCM7xxRegs { uint32_t boottoctrl; } NPCM7xxRegisters; -typedef struct NPCM7xxSDHCIState { +struct NPCM7xxSDHCIState { SysBusDevice parent; MemoryRegion container; @@ -60,6 +60,6 @@ typedef struct NPCM7xxSDHCIState { NPCM7xxRegisters regs; SDHCIState sdhci; -} NPCM7xxSDHCIState; +}; #endif /* NPCM7XX_SDHCI_H */ diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 01a64c5442bf..6cd2822f1d13 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -25,7 +25,7 @@ #ifndef SDHCI_H #define SDHCI_H -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/sysbus.h" #include "hw/sd/sd.h" #include "qom/object.h" @@ -96,6 +96,7 @@ struct SDHCIState { /* Configurable properties */ bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */ uint32_t quirks; + uint8_t endianness; uint8_t sd_spec_version; uint8_t uhs_mode; uint8_t vendor; /* For vendor specific functionality */ diff --git a/include/hw/sensor/emc141x_regs.h b/include/hw/sensor/emc141x_regs.h index 0560fb7c5c1e..e509a43d5594 100644 --- a/include/hw/sensor/emc141x_regs.h +++ b/include/hw/sensor/emc141x_regs.h @@ -9,8 +9,8 @@ * later. See the COPYING file in the top-level directory. */ -#ifndef TMP105_REGS_H -#define TMP105_REGS_H +#ifndef EMC141X_REGS_H +#define EMC141X_REGS_H #define EMC1413_DEVICE_ID 0x21 #define EMC1414_DEVICE_ID 0x25 diff --git a/include/hw/sensor/isl_pmbus_vr.h b/include/hw/sensor/isl_pmbus_vr.h index 3e47ff7e48d8..aa2c2767df90 100644 --- a/include/hw/sensor/isl_pmbus_vr.h +++ b/include/hw/sensor/isl_pmbus_vr.h @@ -12,12 +12,17 @@ #include "hw/i2c/pmbus_device.h" #include "qom/object.h" +#define TYPE_ISL69259 "isl69259" #define TYPE_ISL69260 "isl69260" #define TYPE_RAA228000 "raa228000" #define TYPE_RAA229004 "raa229004" +#define ISL_MAX_IC_DEVICE_ID_LEN 16 struct ISLState { PMBusDevice parent; + + uint8_t ic_device_id[ISL_MAX_IC_DEVICE_ID_LEN]; + uint8_t ic_device_id_len; }; OBJECT_DECLARE_SIMPLE_TYPE(ISLState, ISL69260) diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index f63f83e5c611..0bf48e936d44 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -12,14 +12,7 @@ #ifndef HW_SOUTHBRIDGE_PIIX_H #define HW_SOUTHBRIDGE_PIIX_H -#include "hw/pci/pci.h" -#include "qom/object.h" - -#define TYPE_PIIX4_PM "PIIX4_PM" - -I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, - qemu_irq sci_irq, qemu_irq smi_irq, - int smm_enabled, DeviceState **piix4_pm); +#include "hw/pci/pci_device.h" /* PIRQRC[A:D]: PIRQx Route Control Registers */ #define PIIX_PIRQCA 0x60 @@ -70,8 +63,8 @@ typedef struct PIIXState PIIX3State; DECLARE_INSTANCE_CHECKER(PIIX3State, PIIX3_PCI_DEVICE, TYPE_PIIX3_PCI_DEVICE) -PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus); - -DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus); +#define TYPE_PIIX3_DEVICE "PIIX3" +#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen" +#define TYPE_PIIX4_PCI_DEVICE "piix4-isa" #endif diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index 2d5f8f3d8f68..8e1dda556b91 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -30,6 +30,7 @@ #include "qom/object.h" struct AspeedSMCState; +struct AspeedSMCClass; #define TYPE_ASPEED_SMC_FLASH "aspeed.smc.flash" OBJECT_DECLARE_SIMPLE_TYPE(AspeedSMCFlash, ASPEED_SMC_FLASH) @@ -37,6 +38,7 @@ struct AspeedSMCFlash { SysBusDevice parent_obj; struct AspeedSMCState *controller; + struct AspeedSMCClass *asc; uint8_t cs; MemoryRegion mmio; diff --git a/include/hw/ssi/ibex_spi_host.h b/include/hw/ssi/ibex_spi_host.h new file mode 100644 index 000000000000..1f6d07776605 --- /dev/null +++ b/include/hw/ssi/ibex_spi_host.h @@ -0,0 +1,94 @@ + +/* + * QEMU model of the Ibex SPI Controller + * SPEC Reference: https://docs.opentitan.org/hw/ip/spi_host/doc/ + * + * Copyright (C) 2022 Western Digital + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef IBEX_SPI_HOST_H +#define IBEX_SPI_HOST_H + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/ssi/ssi.h" +#include "qemu/fifo8.h" +#include "qom/object.h" +#include "hw/registerfields.h" +#include "qemu/timer.h" + +#define TYPE_IBEX_SPI_HOST "ibex-spi" +#define IBEX_SPI_HOST(obj) \ + OBJECT_CHECK(IbexSPIHostState, (obj), TYPE_IBEX_SPI_HOST) + +/* SPI Registers */ +#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4) /* rw1c */ +#define IBEX_SPI_HOST_INTR_ENABLE (0x04 / 4) /* rw */ +#define IBEX_SPI_HOST_INTR_TEST (0x08 / 4) /* wo */ +#define IBEX_SPI_HOST_ALERT_TEST (0x0c / 4) /* wo */ +#define IBEX_SPI_HOST_CONTROL (0x10 / 4) /* rw */ +#define IBEX_SPI_HOST_STATUS (0x14 / 4) /* ro */ +#define IBEX_SPI_HOST_CONFIGOPTS (0x18 / 4) /* rw */ +#define IBEX_SPI_HOST_CSID (0x1c / 4) /* rw */ +#define IBEX_SPI_HOST_COMMAND (0x20 / 4) /* wo */ +/* RX/TX Modelled by FIFO */ +#define IBEX_SPI_HOST_RXDATA (0x24 / 4) +#define IBEX_SPI_HOST_TXDATA (0x28 / 4) + +#define IBEX_SPI_HOST_ERROR_ENABLE (0x2c / 4) /* rw */ +#define IBEX_SPI_HOST_ERROR_STATUS (0x30 / 4) /* rw1c */ +#define IBEX_SPI_HOST_EVENT_ENABLE (0x34 / 4) /* rw */ + +/* FIFO Len in Bytes */ +#define IBEX_SPI_HOST_TXFIFO_LEN 288 +#define IBEX_SPI_HOST_RXFIFO_LEN 256 + +/* Max Register (Based on addr) */ +#define IBEX_SPI_HOST_MAX_REGS (IBEX_SPI_HOST_EVENT_ENABLE + 1) + +/* MISC */ +#define TX_INTERRUPT_TRIGGER_DELAY_NS 100 +#define BIDIRECTIONAL_TRANSFER 3 + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + uint32_t regs[IBEX_SPI_HOST_MAX_REGS]; + /* Multi-reg that sets config opts per CS */ + uint32_t *config_opts; + Fifo8 rx_fifo; + Fifo8 tx_fifo; + QEMUTimer *fifo_trigger_handle; + + qemu_irq event; + qemu_irq host_err; + uint32_t num_cs; + qemu_irq *cs_lines; + SSIBus *ssi; + + /* Used to track the init status, for replicating TXDATA ghost writes */ + bool init_status; +} IbexSPIHostState; + +#endif diff --git a/include/hw/ssi/rt_flexspi.h b/include/hw/ssi/rt_flexspi.h new file mode 100644 index 000000000000..d22054c4a4c2 --- /dev/null +++ b/include/hw/ssi/rt_flexspi.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_FLEXSPI_H +#define RT_FLEXSPI_H + +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "qemu/bitops.h" +#include "qemu/fifo32.h" +#include "qom/object.h" + + +#define TYPE_RT_FLEXSPI "rt.flexspi" +OBJECT_DECLARE_SIMPLE_TYPE(RTFLEXSPIState, RT_FLEXSPI) + +#define LUT_SIZE 64 +#define FLEXSPI_FIFO_SIZE 32 + +struct RTFLEXSPIState { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion iomem; + + qemu_irq irq; + + SSIBus *bus; + + uint32_t MCR0; + uint32_t MCR1; + uint32_t MCR2; + uint32_t AHBCR; + uint32_t INTEN; + uint32_t INTR; + uint32_t LUTKEY; + uint32_t LUTCR; + uint32_t AHBRXBUF0CR0; + uint32_t AHBRXBUF1CR0; + uint32_t AHBRXBUF2CR0; + uint32_t AHBRXBUF3CR0; + uint32_t AHBRXBUF4CR0; + uint32_t AHBRXBUF5CR0; + uint32_t AHBRXBUF6CR0; + uint32_t AHBRXBUF7CR0; + uint32_t FLSHA1CR0; + uint32_t FLSHA2CR0; + uint32_t FLSHB1CR0; + uint32_t FLSHB2CR0; + uint32_t FLSHA1CR1; + uint32_t FLSHA2CR1; + uint32_t FLSHB1CR1; + uint32_t FLSHB2CR1; + uint32_t FLSHA1CR2; + uint32_t FLSHA2CR2; + uint32_t FLSHB1CR2; + uint32_t FLSHB2CR2; + uint32_t FLSHCR4; + uint32_t IPCR0; + uint32_t IPCR1; + uint32_t IPCMD; + uint32_t DLPR; + uint32_t IPRXFCR; + uint32_t IPTXFCR; + uint32_t DLLACR; + uint32_t DLLBCR; + uint32_t STS0; + uint32_t STS1; + uint32_t STS2; + uint32_t AHBSPNDSTS; + uint32_t IPRXFSTS; + uint32_t IPTXFSTS; + + Fifo32 rx_fifo; + Fifo32 tx_fifo; + uint32_t lut[LUT_SIZE]; +}; + +#endif /* RT_FLEXSPI_H */ diff --git a/include/hw/ssi/sifive_spi.h b/include/hw/ssi/sifive_spi.h index 47d0d6a47cca..d0c40cdb11be 100644 --- a/include/hw/ssi/sifive_spi.h +++ b/include/hw/ssi/sifive_spi.h @@ -22,6 +22,9 @@ #ifndef HW_SIFIVE_SPI_H #define HW_SIFIVE_SPI_H +#include "qemu/fifo8.h" +#include "hw/sysbus.h" + #define SIFIVE_SPI_REG_NUM (0x78 / 4) #define TYPE_SIFIVE_SPI "sifive.spi" diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h index f411858ab083..6950f86810d3 100644 --- a/include/hw/ssi/ssi.h +++ b/include/hw/ssi/ssi.h @@ -59,6 +59,9 @@ struct SSIPeripheralClass { struct SSIPeripheral { DeviceState parent_obj; + /* cache the class */ + SSIPeripheralClass *spc; + /* Chip select state */ bool cs; }; diff --git a/include/hw/ssi/xlnx-versal-ospi.h b/include/hw/ssi/xlnx-versal-ospi.h index 14d12634979b..5d131d351d2f 100644 --- a/include/hw/ssi/xlnx-versal-ospi.h +++ b/include/hw/ssi/xlnx-versal-ospi.h @@ -49,8 +49,8 @@ * + Property "indac-write-disabled": Disable indirect access writes. */ -#ifndef XILINX_VERSAL_OSPI_H -#define XILINX_VERSAL_OSPI_H +#ifndef XLNX_VERSAL_OSPI_H +#define XLNX_VERSAL_OSPI_H #include "hw/register.h" #include "hw/ssi/ssi.h" @@ -108,4 +108,4 @@ struct XlnxVersalOspi { uint8_t stig_membank[512]; }; -#endif /* XILINX_VERSAL_OSPI_H */ +#endif /* XLNX_VERSAL_OSPI_H */ diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_timer.h index d36034a10c20..07dc6b6f2cbd 100644 --- a/include/hw/timer/aspeed_timer.h +++ b/include/hw/timer/aspeed_timer.h @@ -31,6 +31,7 @@ OBJECT_DECLARE_TYPE(AspeedTimerCtrlState, AspeedTimerClass, ASPEED_TIMER) #define TYPE_ASPEED_2400_TIMER TYPE_ASPEED_TIMER "-ast2400" #define TYPE_ASPEED_2500_TIMER TYPE_ASPEED_TIMER "-ast2500" #define TYPE_ASPEED_2600_TIMER TYPE_ASPEED_TIMER "-ast2600" +#define TYPE_ASPEED_1030_TIMER TYPE_ASPEED_TIMER "-ast1030" #define ASPEED_TIMER_NR_TIMERS 8 diff --git a/include/hw/timer/bcm2835_systmr.h b/include/hw/timer/bcm2835_systmr.h index bd3097d746b2..a8f605beeb67 100644 --- a/include/hw/timer/bcm2835_systmr.h +++ b/include/hw/timer/bcm2835_systmr.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef BCM2835_SYSTIMER_H -#define BCM2835_SYSTIMER_H +#ifndef BCM2835_SYSTMR_H +#define BCM2835_SYSTMR_H #include "hw/sysbus.h" #include "hw/irq.h" diff --git a/include/hw/timer/cadence_ttc.h b/include/hw/timer/cadence_ttc.h new file mode 100644 index 000000000000..e1251383f2ac --- /dev/null +++ b/include/hw/timer/cadence_ttc.h @@ -0,0 +1,54 @@ +/* + * Xilinx Zynq cadence TTC model + * + * Copyright (c) 2011 Xilinx Inc. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. + * Written By Haibing Ma + * M. Habib + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef HW_TIMER_CADENCE_TTC_H +#define HW_TIMER_CADENCE_TTC_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" + +typedef struct { + QEMUTimer *timer; + int freq; + + uint32_t reg_clock; + uint32_t reg_count; + uint32_t reg_value; + uint16_t reg_interval; + uint16_t reg_match[3]; + uint32_t reg_intr; + uint32_t reg_intr_en; + uint32_t reg_event_ctrl; + uint32_t reg_event; + + uint64_t cpu_time; + unsigned int cpu_time_valid; + + qemu_irq irq; +} CadenceTimerState; + +#define TYPE_CADENCE_TTC "cadence_ttc" +OBJECT_DECLARE_SIMPLE_TYPE(CadenceTTCState, CADENCE_TTC) + +struct CadenceTTCState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + CadenceTimerState timer[3]; +}; + +#endif diff --git a/include/hw/timer/ibex_timer.h b/include/hw/timer/ibex_timer.h index 1a0a28d5fab5..41f5c82a920b 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/timer/imx_epit.h b/include/hw/timer/imx_epit.h index 2acc41e98220..79aff0cec207 100644 --- a/include/hw/timer/imx_epit.h +++ b/include/hw/timer/imx_epit.h @@ -43,7 +43,7 @@ #define CR_OCIEN (1 << 2) #define CR_RLD (1 << 3) #define CR_PRESCALE_SHIFT (4) -#define CR_PRESCALE_MASK (0xfff) +#define CR_PRESCALE_BITS (12) #define CR_SWR (1 << 16) #define CR_IOVW (1 << 17) #define CR_DBGEN (1 << 18) @@ -51,7 +51,9 @@ #define CR_DOZEN (1 << 20) #define CR_STOPEN (1 << 21) #define CR_CLKSRC_SHIFT (24) -#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) +#define CR_CLKSRC_BITS (2) + +#define SR_OCIF (1 << 0) #define EPIT_TIMER_MAX 0XFFFFFFFFUL @@ -72,9 +74,7 @@ struct IMXEPITState { uint32_t sr; uint32_t lr; uint32_t cmp; - uint32_t cnt; - uint32_t freq; qemu_irq irq; }; diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h index ff5c8a351a05..5a1230da35e5 100644 --- a/include/hw/timer/imx_gpt.h +++ b/include/hw/timer/imx_gpt.h @@ -78,6 +78,7 @@ #define TYPE_IMX25_GPT "imx25.gpt" #define TYPE_IMX31_GPT "imx31.gpt" #define TYPE_IMX6_GPT "imx6.gpt" +#define TYPE_IMX6UL_GPT "imx6ul.gpt" #define TYPE_IMX7_GPT "imx7.gpt" #define TYPE_IMX_GPT TYPE_IMX25_GPT diff --git a/include/hw/timer/rt_ostimer.h b/include/hw/timer/rt_ostimer.h new file mode 100644 index 000000000000..97f171379e3a --- /dev/null +++ b/include/hw/timer/rt_ostimer.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef RT_OSTIMER_H +#define RT_OSTIMER_H + +#include "hw/sysbus.h" +#include "hw/ptimer.h" +#include "hw/misc/imx_ccm.h" +#include "qom/object.h" + +#define TYPE_RT_OSTIMER "rt-ostimer" + + +#define MATCH_WR_RDY_MASK (1U<<2) +#define OSTIMER_INTENA_MASK (1U<<1) +#define OSTIMER_INTRFLAG_MASK (1U) + +typedef struct RTOSTIMERState RTOSTIMERState; +DECLARE_INSTANCE_CHECKER(RTOSTIMERState, RT_OSTIMER, + TYPE_RT_OSTIMER) + +struct RTOSTIMERState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + ptimer_state *timer; + MemoryRegion iomem; + + uint32_t EVTIMERL; + uint32_t EVTIMERH; + uint32_t CAPTURE_L; + uint32_t CAPTURE_H; + uint32_t MATCH_L; + uint32_t MATCH_H; + uint32_t OSEVENT_CTRL; + + uint32_t next_timeout; + uint32_t next_int; + + uint32_t freq; + + qemu_irq irq; +}; + +#endif /* RT_OSTIMER_H */ diff --git a/include/hw/timer/sse-timer.h b/include/hw/timer/sse-timer.h index b4ee8e7f6c40..265ad32400dc 100644 --- a/include/hw/timer/sse-timer.h +++ b/include/hw/timer/sse-timer.h @@ -25,6 +25,7 @@ #define SSE_TIMER_H #include "hw/sysbus.h" +#include "qemu/timer.h" #include "qom/object.h" #include "hw/timer/sse-counter.h" diff --git a/include/hw/tricore/tc27x_soc.h b/include/hw/tricore/tc27x_soc.h index 6a7e5b54f51d..dd3a7485c85a 100644 --- a/include/hw/tricore/tc27x_soc.h +++ b/include/hw/tricore/tc27x_soc.h @@ -18,8 +18,8 @@ * License along with this library; if not, see . */ -#ifndef TC27X_SoC_H -#define TC27X_SoC_H +#ifndef TC27X_SOC_H +#define TC27X_SOC_H #include "hw/sysbus.h" #include "target/tricore/cpu.h" diff --git a/include/hw/tricore/tricore_testdevice.h b/include/hw/tricore/tricore_testdevice.h index 2c56c51bcb8a..1e2b8942ac91 100644 --- a/include/hw/tricore/tricore_testdevice.h +++ b/include/hw/tricore/tricore_testdevice.h @@ -15,9 +15,8 @@ * License along with this library; if not, see . */ - -#ifndef HW_TRICORE_TESTDEV_H -#define HW_TRICORE_TESTDEV_H +#ifndef HW_TRICORE_TESTDEVICE_H +#define HW_TRICORE_TESTDEVICE_H #include "hw/sysbus.h" #include "hw/hw.h" diff --git a/include/hw/usb.h b/include/hw/usb.h index 33668dd0a99a..32c23a5ca2a0 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -66,42 +66,42 @@ //#define USB_STATE_POWERED 2 #define USB_STATE_DEFAULT 3 //#define USB_STATE_ADDRESS 4 -//#define USB_STATE_CONFIGURED 5 +//#define USB_STATE_CONFIGURED 5 #define USB_STATE_SUSPENDED 6 -#define USB_CLASS_AUDIO 1 -#define USB_CLASS_COMM 2 -#define USB_CLASS_HID 3 -#define USB_CLASS_PHYSICAL 5 -#define USB_CLASS_STILL_IMAGE 6 -#define USB_CLASS_PRINTER 7 -#define USB_CLASS_MASS_STORAGE 8 -#define USB_CLASS_HUB 9 -#define USB_CLASS_CDC_DATA 0x0a -#define USB_CLASS_CSCID 0x0b -#define USB_CLASS_CONTENT_SEC 0x0d -#define USB_CLASS_APP_SPEC 0xfe -#define USB_CLASS_VENDOR_SPEC 0xff +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b +#define USB_CLASS_CONTENT_SEC 0x0d +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff #define USB_SUBCLASS_UNDEFINED 0 #define USB_SUBCLASS_AUDIO_CONTROL 1 #define USB_SUBCLASS_AUDIO_STREAMING 2 #define USB_SUBCLASS_AUDIO_MIDISTREAMING 3 -#define USB_DIR_OUT 0 -#define USB_DIR_IN 0x80 +#define USB_DIR_OUT 0 +#define USB_DIR_IN 0x80 -#define USB_TYPE_MASK (0x03 << 5) -#define USB_TYPE_STANDARD (0x00 << 5) -#define USB_TYPE_CLASS (0x01 << 5) -#define USB_TYPE_VENDOR (0x02 << 5) -#define USB_TYPE_RESERVED (0x03 << 5) +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) -#define USB_RECIP_MASK 0x1f -#define USB_RECIP_DEVICE 0x00 -#define USB_RECIP_INTERFACE 0x01 -#define USB_RECIP_ENDPOINT 0x02 -#define USB_RECIP_OTHER 0x03 +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 #define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) #define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) @@ -126,28 +126,28 @@ #define EndpointOutRequest \ ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C #define USB_REQ_SET_SEL 0x30 #define USB_REQ_SET_ISOCH_DELAY 0x31 -#define USB_DEVICE_SELF_POWERED 0 -#define USB_DEVICE_REMOTE_WAKEUP 1 +#define USB_DEVICE_SELF_POWERED 0 +#define USB_DEVICE_REMOTE_WAKEUP 1 -#define USB_DT_DEVICE 0x01 -#define USB_DT_CONFIG 0x02 -#define USB_DT_STRING 0x03 -#define USB_DT_INTERFACE 0x04 -#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 #define USB_DT_DEVICE_QUALIFIER 0x06 #define USB_DT_OTHER_SPEED_CONFIG 0x07 #define USB_DT_DEBUG 0x0A @@ -167,10 +167,10 @@ #define USB_CFG_ATT_WAKEUP (1 << 5) #define USB_CFG_ATT_BATTERY (1 << 4) -#define USB_ENDPOINT_XFER_CONTROL 0 -#define USB_ENDPOINT_XFER_ISOC 1 -#define USB_ENDPOINT_XFER_BULK 2 -#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 #define USB_ENDPOINT_XFER_INVALID 255 #define USB_INTERFACE_INVALID 255 @@ -569,9 +569,9 @@ static inline bool usb_device_is_scsi_storage(USBDevice *dev) /* quirks.c */ /* In bulk endpoints are streaming data sources (iow behave like isoc eps) */ -#define USB_QUIRK_BUFFER_BULK_IN 0x01 +#define USB_QUIRK_BUFFER_BULK_IN 0x01 /* Bulk pkts in FTDI format, need special handling when combining packets */ -#define USB_QUIRK_IS_FTDI 0x02 +#define USB_QUIRK_IS_FTDI 0x02 int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, uint8_t interface_class, uint8_t interface_subclass, diff --git a/include/hw/usb/dwc2-regs.h b/include/hw/usb/dwc2-regs.h index a7eb53148543..0bf3f2aa17ff 100644 --- a/include/hw/usb/dwc2-regs.h +++ b/include/hw/usb/dwc2-regs.h @@ -39,791 +39,791 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DWC2_HW_H -#define DWC2_HW_H - -#define HSOTG_REG(x) (x) - -#define GOTGCTL HSOTG_REG(0x000) -#define GOTGCTL_CHIRPEN BIT(27) -#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) -#define GOTGCTL_MULT_VALID_BC_SHIFT 22 -#define GOTGCTL_OTGVER BIT(20) -#define GOTGCTL_BSESVLD BIT(19) -#define GOTGCTL_ASESVLD BIT(18) -#define GOTGCTL_DBNC_SHORT BIT(17) -#define GOTGCTL_CONID_B BIT(16) -#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15) -#define GOTGCTL_DEVHNPEN BIT(11) -#define GOTGCTL_HSTSETHNPEN BIT(10) -#define GOTGCTL_HNPREQ BIT(9) -#define GOTGCTL_HSTNEGSCS BIT(8) -#define GOTGCTL_SESREQ BIT(1) -#define GOTGCTL_SESREQSCS BIT(0) - -#define GOTGINT HSOTG_REG(0x004) -#define GOTGINT_DBNCE_DONE BIT(19) -#define GOTGINT_A_DEV_TOUT_CHG BIT(18) -#define GOTGINT_HST_NEG_DET BIT(17) -#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9) -#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8) -#define GOTGINT_SES_END_DET BIT(2) - -#define GAHBCFG HSOTG_REG(0x008) -#define GAHBCFG_AHB_SINGLE BIT(23) -#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22) -#define GAHBCFG_REM_MEM_SUPP BIT(21) -#define GAHBCFG_P_TXF_EMP_LVL BIT(8) -#define GAHBCFG_NP_TXF_EMP_LVL BIT(7) -#define GAHBCFG_DMA_EN BIT(5) -#define GAHBCFG_HBSTLEN_MASK (0xf << 1) -#define GAHBCFG_HBSTLEN_SHIFT 1 -#define GAHBCFG_HBSTLEN_SINGLE 0 -#define GAHBCFG_HBSTLEN_INCR 1 -#define GAHBCFG_HBSTLEN_INCR4 3 -#define GAHBCFG_HBSTLEN_INCR8 5 -#define GAHBCFG_HBSTLEN_INCR16 7 -#define GAHBCFG_GLBL_INTR_EN BIT(0) -#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ - GAHBCFG_NP_TXF_EMP_LVL | \ - GAHBCFG_DMA_EN | \ - GAHBCFG_GLBL_INTR_EN) - -#define GUSBCFG HSOTG_REG(0x00C) -#define GUSBCFG_FORCEDEVMODE BIT(30) -#define GUSBCFG_FORCEHOSTMODE BIT(29) -#define GUSBCFG_TXENDDELAY BIT(28) -#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27) -#define GUSBCFG_ICUSBCAP BIT(26) -#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25) -#define GUSBCFG_INDICATORPASSTHROUGH BIT(24) -#define GUSBCFG_INDICATORCOMPLEMENT BIT(23) -#define GUSBCFG_TERMSELDLPULSE BIT(22) -#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21) -#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20) -#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19) -#define GUSBCFG_ULPI_AUTO_RES BIT(18) -#define GUSBCFG_ULPI_FS_LS BIT(17) -#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16) -#define GUSBCFG_PHY_LP_CLK_SEL BIT(15) -#define GUSBCFG_USBTRDTIM_MASK (0xf << 10) -#define GUSBCFG_USBTRDTIM_SHIFT 10 -#define GUSBCFG_HNPCAP BIT(9) -#define GUSBCFG_SRPCAP BIT(8) -#define GUSBCFG_DDRSEL BIT(7) -#define GUSBCFG_PHYSEL BIT(6) -#define GUSBCFG_FSINTF BIT(5) -#define GUSBCFG_ULPI_UTMI_SEL BIT(4) -#define GUSBCFG_PHYIF16 BIT(3) -#define GUSBCFG_PHYIF8 (0 << 3) -#define GUSBCFG_TOUTCAL_MASK (0x7 << 0) -#define GUSBCFG_TOUTCAL_SHIFT 0 -#define GUSBCFG_TOUTCAL_LIMIT 0x7 -#define GUSBCFG_TOUTCAL(_x) ((_x) << 0) - -#define GRSTCTL HSOTG_REG(0x010) -#define GRSTCTL_AHBIDLE BIT(31) -#define GRSTCTL_DMAREQ BIT(30) -#define GRSTCTL_TXFNUM_MASK (0x1f << 6) -#define GRSTCTL_TXFNUM_SHIFT 6 -#define GRSTCTL_TXFNUM_LIMIT 0x1f -#define GRSTCTL_TXFNUM(_x) ((_x) << 6) -#define GRSTCTL_TXFFLSH BIT(5) -#define GRSTCTL_RXFFLSH BIT(4) -#define GRSTCTL_IN_TKNQ_FLSH BIT(3) -#define GRSTCTL_FRMCNTRRST BIT(2) -#define GRSTCTL_HSFTRST BIT(1) -#define GRSTCTL_CSFTRST BIT(0) - -#define GINTSTS HSOTG_REG(0x014) -#define GINTMSK HSOTG_REG(0x018) -#define GINTSTS_WKUPINT BIT(31) -#define GINTSTS_SESSREQINT BIT(30) -#define GINTSTS_DISCONNINT BIT(29) -#define GINTSTS_CONIDSTSCHNG BIT(28) -#define GINTSTS_LPMTRANRCVD BIT(27) -#define GINTSTS_PTXFEMP BIT(26) -#define GINTSTS_HCHINT BIT(25) -#define GINTSTS_PRTINT BIT(24) -#define GINTSTS_RESETDET BIT(23) -#define GINTSTS_FET_SUSP BIT(22) -#define GINTSTS_INCOMPL_IP BIT(21) -#define GINTSTS_INCOMPL_SOOUT BIT(21) -#define GINTSTS_INCOMPL_SOIN BIT(20) -#define GINTSTS_OEPINT BIT(19) -#define GINTSTS_IEPINT BIT(18) -#define GINTSTS_EPMIS BIT(17) -#define GINTSTS_RESTOREDONE BIT(16) -#define GINTSTS_EOPF BIT(15) -#define GINTSTS_ISOUTDROP BIT(14) -#define GINTSTS_ENUMDONE BIT(13) -#define GINTSTS_USBRST BIT(12) -#define GINTSTS_USBSUSP BIT(11) -#define GINTSTS_ERLYSUSP BIT(10) -#define GINTSTS_I2CINT BIT(9) -#define GINTSTS_ULPI_CK_INT BIT(8) -#define GINTSTS_GOUTNAKEFF BIT(7) -#define GINTSTS_GINNAKEFF BIT(6) -#define GINTSTS_NPTXFEMP BIT(5) -#define GINTSTS_RXFLVL BIT(4) -#define GINTSTS_SOF BIT(3) -#define GINTSTS_OTGINT BIT(2) -#define GINTSTS_MODEMIS BIT(1) -#define GINTSTS_CURMODE_HOST BIT(0) - -#define GRXSTSR HSOTG_REG(0x01C) -#define GRXSTSP HSOTG_REG(0x020) -#define GRXSTS_FN_MASK (0x7f << 25) -#define GRXSTS_FN_SHIFT 25 -#define GRXSTS_PKTSTS_MASK (0xf << 17) -#define GRXSTS_PKTSTS_SHIFT 17 -#define GRXSTS_PKTSTS_GLOBALOUTNAK 1 -#define GRXSTS_PKTSTS_OUTRX 2 -#define GRXSTS_PKTSTS_HCHIN 2 -#define GRXSTS_PKTSTS_OUTDONE 3 -#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3 -#define GRXSTS_PKTSTS_SETUPDONE 4 -#define GRXSTS_PKTSTS_DATATOGGLEERR 5 -#define GRXSTS_PKTSTS_SETUPRX 6 -#define GRXSTS_PKTSTS_HCHHALTED 7 -#define GRXSTS_HCHNUM_MASK (0xf << 0) -#define GRXSTS_HCHNUM_SHIFT 0 -#define GRXSTS_DPID_MASK (0x3 << 15) -#define GRXSTS_DPID_SHIFT 15 -#define GRXSTS_BYTECNT_MASK (0x7ff << 4) -#define GRXSTS_BYTECNT_SHIFT 4 -#define GRXSTS_EPNUM_MASK (0xf << 0) -#define GRXSTS_EPNUM_SHIFT 0 - -#define GRXFSIZ HSOTG_REG(0x024) -#define GRXFSIZ_DEPTH_MASK (0xffff << 0) -#define GRXFSIZ_DEPTH_SHIFT 0 - -#define GNPTXFSIZ HSOTG_REG(0x028) +#ifndef DWC2_REGS_H +#define DWC2_REGS_H + +#define HSOTG_REG(x) (x) + +#define GOTGCTL HSOTG_REG(0x000) +#define GOTGCTL_CHIRPEN BIT(27) +#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) +#define GOTGCTL_MULT_VALID_BC_SHIFT 22 +#define GOTGCTL_OTGVER BIT(20) +#define GOTGCTL_BSESVLD BIT(19) +#define GOTGCTL_ASESVLD BIT(18) +#define GOTGCTL_DBNC_SHORT BIT(17) +#define GOTGCTL_CONID_B BIT(16) +#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15) +#define GOTGCTL_DEVHNPEN BIT(11) +#define GOTGCTL_HSTSETHNPEN BIT(10) +#define GOTGCTL_HNPREQ BIT(9) +#define GOTGCTL_HSTNEGSCS BIT(8) +#define GOTGCTL_SESREQ BIT(1) +#define GOTGCTL_SESREQSCS BIT(0) + +#define GOTGINT HSOTG_REG(0x004) +#define GOTGINT_DBNCE_DONE BIT(19) +#define GOTGINT_A_DEV_TOUT_CHG BIT(18) +#define GOTGINT_HST_NEG_DET BIT(17) +#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9) +#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8) +#define GOTGINT_SES_END_DET BIT(2) + +#define GAHBCFG HSOTG_REG(0x008) +#define GAHBCFG_AHB_SINGLE BIT(23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22) +#define GAHBCFG_REM_MEM_SUPP BIT(21) +#define GAHBCFG_P_TXF_EMP_LVL BIT(8) +#define GAHBCFG_NP_TXF_EMP_LVL BIT(7) +#define GAHBCFG_DMA_EN BIT(5) +#define GAHBCFG_HBSTLEN_MASK (0xf << 1) +#define GAHBCFG_HBSTLEN_SHIFT 1 +#define GAHBCFG_HBSTLEN_SINGLE 0 +#define GAHBCFG_HBSTLEN_INCR 1 +#define GAHBCFG_HBSTLEN_INCR4 3 +#define GAHBCFG_HBSTLEN_INCR8 5 +#define GAHBCFG_HBSTLEN_INCR16 7 +#define GAHBCFG_GLBL_INTR_EN BIT(0) +#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ + GAHBCFG_NP_TXF_EMP_LVL | \ + GAHBCFG_DMA_EN | \ + GAHBCFG_GLBL_INTR_EN) + +#define GUSBCFG HSOTG_REG(0x00C) +#define GUSBCFG_FORCEDEVMODE BIT(30) +#define GUSBCFG_FORCEHOSTMODE BIT(29) +#define GUSBCFG_TXENDDELAY BIT(28) +#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27) +#define GUSBCFG_ICUSBCAP BIT(26) +#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25) +#define GUSBCFG_INDICATORPASSTHROUGH BIT(24) +#define GUSBCFG_INDICATORCOMPLEMENT BIT(23) +#define GUSBCFG_TERMSELDLPULSE BIT(22) +#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21) +#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20) +#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19) +#define GUSBCFG_ULPI_AUTO_RES BIT(18) +#define GUSBCFG_ULPI_FS_LS BIT(17) +#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16) +#define GUSBCFG_PHY_LP_CLK_SEL BIT(15) +#define GUSBCFG_USBTRDTIM_MASK (0xf << 10) +#define GUSBCFG_USBTRDTIM_SHIFT 10 +#define GUSBCFG_HNPCAP BIT(9) +#define GUSBCFG_SRPCAP BIT(8) +#define GUSBCFG_DDRSEL BIT(7) +#define GUSBCFG_PHYSEL BIT(6) +#define GUSBCFG_FSINTF BIT(5) +#define GUSBCFG_ULPI_UTMI_SEL BIT(4) +#define GUSBCFG_PHYIF16 BIT(3) +#define GUSBCFG_PHYIF8 (0 << 3) +#define GUSBCFG_TOUTCAL_MASK (0x7 << 0) +#define GUSBCFG_TOUTCAL_SHIFT 0 +#define GUSBCFG_TOUTCAL_LIMIT 0x7 +#define GUSBCFG_TOUTCAL(_x) ((_x) << 0) + +#define GRSTCTL HSOTG_REG(0x010) +#define GRSTCTL_AHBIDLE BIT(31) +#define GRSTCTL_DMAREQ BIT(30) +#define GRSTCTL_TXFNUM_MASK (0x1f << 6) +#define GRSTCTL_TXFNUM_SHIFT 6 +#define GRSTCTL_TXFNUM_LIMIT 0x1f +#define GRSTCTL_TXFNUM(_x) ((_x) << 6) +#define GRSTCTL_TXFFLSH BIT(5) +#define GRSTCTL_RXFFLSH BIT(4) +#define GRSTCTL_IN_TKNQ_FLSH BIT(3) +#define GRSTCTL_FRMCNTRRST BIT(2) +#define GRSTCTL_HSFTRST BIT(1) +#define GRSTCTL_CSFTRST BIT(0) + +#define GINTSTS HSOTG_REG(0x014) +#define GINTMSK HSOTG_REG(0x018) +#define GINTSTS_WKUPINT BIT(31) +#define GINTSTS_SESSREQINT BIT(30) +#define GINTSTS_DISCONNINT BIT(29) +#define GINTSTS_CONIDSTSCHNG BIT(28) +#define GINTSTS_LPMTRANRCVD BIT(27) +#define GINTSTS_PTXFEMP BIT(26) +#define GINTSTS_HCHINT BIT(25) +#define GINTSTS_PRTINT BIT(24) +#define GINTSTS_RESETDET BIT(23) +#define GINTSTS_FET_SUSP BIT(22) +#define GINTSTS_INCOMPL_IP BIT(21) +#define GINTSTS_INCOMPL_SOOUT BIT(21) +#define GINTSTS_INCOMPL_SOIN BIT(20) +#define GINTSTS_OEPINT BIT(19) +#define GINTSTS_IEPINT BIT(18) +#define GINTSTS_EPMIS BIT(17) +#define GINTSTS_RESTOREDONE BIT(16) +#define GINTSTS_EOPF BIT(15) +#define GINTSTS_ISOUTDROP BIT(14) +#define GINTSTS_ENUMDONE BIT(13) +#define GINTSTS_USBRST BIT(12) +#define GINTSTS_USBSUSP BIT(11) +#define GINTSTS_ERLYSUSP BIT(10) +#define GINTSTS_I2CINT BIT(9) +#define GINTSTS_ULPI_CK_INT BIT(8) +#define GINTSTS_GOUTNAKEFF BIT(7) +#define GINTSTS_GINNAKEFF BIT(6) +#define GINTSTS_NPTXFEMP BIT(5) +#define GINTSTS_RXFLVL BIT(4) +#define GINTSTS_SOF BIT(3) +#define GINTSTS_OTGINT BIT(2) +#define GINTSTS_MODEMIS BIT(1) +#define GINTSTS_CURMODE_HOST BIT(0) + +#define GRXSTSR HSOTG_REG(0x01C) +#define GRXSTSP HSOTG_REG(0x020) +#define GRXSTS_FN_MASK (0x7f << 25) +#define GRXSTS_FN_SHIFT 25 +#define GRXSTS_PKTSTS_MASK (0xf << 17) +#define GRXSTS_PKTSTS_SHIFT 17 +#define GRXSTS_PKTSTS_GLOBALOUTNAK 1 +#define GRXSTS_PKTSTS_OUTRX 2 +#define GRXSTS_PKTSTS_HCHIN 2 +#define GRXSTS_PKTSTS_OUTDONE 3 +#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3 +#define GRXSTS_PKTSTS_SETUPDONE 4 +#define GRXSTS_PKTSTS_DATATOGGLEERR 5 +#define GRXSTS_PKTSTS_SETUPRX 6 +#define GRXSTS_PKTSTS_HCHHALTED 7 +#define GRXSTS_HCHNUM_MASK (0xf << 0) +#define GRXSTS_HCHNUM_SHIFT 0 +#define GRXSTS_DPID_MASK (0x3 << 15) +#define GRXSTS_DPID_SHIFT 15 +#define GRXSTS_BYTECNT_MASK (0x7ff << 4) +#define GRXSTS_BYTECNT_SHIFT 4 +#define GRXSTS_EPNUM_MASK (0xf << 0) +#define GRXSTS_EPNUM_SHIFT 0 + +#define GRXFSIZ HSOTG_REG(0x024) +#define GRXFSIZ_DEPTH_MASK (0xffff << 0) +#define GRXFSIZ_DEPTH_SHIFT 0 + +#define GNPTXFSIZ HSOTG_REG(0x028) /* Use FIFOSIZE_* constants to access this register */ -#define GNPTXSTS HSOTG_REG(0x02C) -#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24) -#define GNPTXSTS_NP_TXQ_TOP_SHIFT 24 -#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK (0xff << 16) -#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT 16 -#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v) (((_v) >> 16) & 0xff) -#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK (0xffff << 0) -#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT 0 -#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff) - -#define GI2CCTL HSOTG_REG(0x0030) -#define GI2CCTL_BSYDNE BIT(31) -#define GI2CCTL_RW BIT(30) -#define GI2CCTL_I2CDATSE0 BIT(28) -#define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) -#define GI2CCTL_I2CDEVADDR_SHIFT 26 -#define GI2CCTL_I2CSUSPCTL BIT(25) -#define GI2CCTL_ACK BIT(24) -#define GI2CCTL_I2CEN BIT(23) -#define GI2CCTL_ADDR_MASK (0x7f << 16) -#define GI2CCTL_ADDR_SHIFT 16 -#define GI2CCTL_REGADDR_MASK (0xff << 8) -#define GI2CCTL_REGADDR_SHIFT 8 -#define GI2CCTL_RWDATA_MASK (0xff << 0) -#define GI2CCTL_RWDATA_SHIFT 0 - -#define GPVNDCTL HSOTG_REG(0x0034) -#define GGPIO HSOTG_REG(0x0038) -#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) - -#define GUID HSOTG_REG(0x003c) -#define GSNPSID HSOTG_REG(0x0040) -#define GHWCFG1 HSOTG_REG(0x0044) -#define GSNPSID_ID_MASK GENMASK(31, 16) - -#define GHWCFG2 HSOTG_REG(0x0048) -#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31) -#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26) -#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26 -#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) -#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24 -#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) -#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22 -#define GHWCFG2_MULTI_PROC_INT BIT(20) -#define GHWCFG2_DYNAMIC_FIFO BIT(19) -#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18) -#define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14) -#define GHWCFG2_NUM_HOST_CHAN_SHIFT 14 -#define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10) -#define GHWCFG2_NUM_DEV_EP_SHIFT 10 -#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8) -#define GHWCFG2_FS_PHY_TYPE_SHIFT 8 -#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 -#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1 -#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2 -#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3 -#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6) -#define GHWCFG2_HS_PHY_TYPE_SHIFT 6 -#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 -#define GHWCFG2_HS_PHY_TYPE_UTMI 1 -#define GHWCFG2_HS_PHY_TYPE_ULPI 2 -#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 -#define GHWCFG2_POINT2POINT BIT(5) -#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3) -#define GHWCFG2_ARCHITECTURE_SHIFT 3 -#define GHWCFG2_SLAVE_ONLY_ARCH 0 -#define GHWCFG2_EXT_DMA_ARCH 1 -#define GHWCFG2_INT_DMA_ARCH 2 -#define GHWCFG2_OP_MODE_MASK (0x7 << 0) -#define GHWCFG2_OP_MODE_SHIFT 0 -#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0 -#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1 -#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2 -#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 -#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 -#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 -#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 -#define GHWCFG2_OP_MODE_UNDEFINED 7 - -#define GHWCFG3 HSOTG_REG(0x004c) -#define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16) -#define GHWCFG3_DFIFO_DEPTH_SHIFT 16 -#define GHWCFG3_OTG_LPM_EN BIT(15) -#define GHWCFG3_BC_SUPPORT BIT(14) -#define GHWCFG3_OTG_ENABLE_HSIC BIT(13) -#define GHWCFG3_ADP_SUPP BIT(12) -#define GHWCFG3_SYNCH_RESET_TYPE BIT(11) -#define GHWCFG3_OPTIONAL_FEATURES BIT(10) -#define GHWCFG3_VENDOR_CTRL_IF BIT(9) -#define GHWCFG3_I2C BIT(8) -#define GHWCFG3_OTG_FUNC BIT(7) -#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) -#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4 -#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0) -#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0 - -#define GHWCFG4 HSOTG_REG(0x0050) -#define GHWCFG4_DESC_DMA_DYN BIT(31) -#define GHWCFG4_DESC_DMA BIT(30) -#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) -#define GHWCFG4_NUM_IN_EPS_SHIFT 26 -#define GHWCFG4_DED_FIFO_EN BIT(25) -#define GHWCFG4_DED_FIFO_SHIFT 25 -#define GHWCFG4_SESSION_END_FILT_EN BIT(24) -#define GHWCFG4_B_VALID_FILT_EN BIT(23) -#define GHWCFG4_A_VALID_FILT_EN BIT(22) -#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21) -#define GHWCFG4_IDDIG_FILT_EN BIT(20) -#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16) -#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 -#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) -#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 -#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 -#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 -#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 -#define GHWCFG4_ACG_SUPPORTED BIT(12) -#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) +#define GNPTXSTS HSOTG_REG(0x02C) +#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24) +#define GNPTXSTS_NP_TXQ_TOP_SHIFT 24 +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK (0xff << 16) +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT 16 +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v) (((_v) >> 16) & 0xff) +#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK (0xffff << 0) +#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT 0 +#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff) + +#define GI2CCTL HSOTG_REG(0x0030) +#define GI2CCTL_BSYDNE BIT(31) +#define GI2CCTL_RW BIT(30) +#define GI2CCTL_I2CDATSE0 BIT(28) +#define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) +#define GI2CCTL_I2CDEVADDR_SHIFT 26 +#define GI2CCTL_I2CSUSPCTL BIT(25) +#define GI2CCTL_ACK BIT(24) +#define GI2CCTL_I2CEN BIT(23) +#define GI2CCTL_ADDR_MASK (0x7f << 16) +#define GI2CCTL_ADDR_SHIFT 16 +#define GI2CCTL_REGADDR_MASK (0xff << 8) +#define GI2CCTL_REGADDR_SHIFT 8 +#define GI2CCTL_RWDATA_MASK (0xff << 0) +#define GI2CCTL_RWDATA_SHIFT 0 + +#define GPVNDCTL HSOTG_REG(0x0034) +#define GGPIO HSOTG_REG(0x0038) +#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) + +#define GUID HSOTG_REG(0x003c) +#define GSNPSID HSOTG_REG(0x0040) +#define GHWCFG1 HSOTG_REG(0x0044) +#define GSNPSID_ID_MASK GENMASK(31, 16) + +#define GHWCFG2 HSOTG_REG(0x0048) +#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26 +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24 +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22 +#define GHWCFG2_MULTI_PROC_INT BIT(20) +#define GHWCFG2_DYNAMIC_FIFO BIT(19) +#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18) +#define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14) +#define GHWCFG2_NUM_HOST_CHAN_SHIFT 14 +#define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10) +#define GHWCFG2_NUM_DEV_EP_SHIFT 10 +#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8) +#define GHWCFG2_FS_PHY_TYPE_SHIFT 8 +#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 +#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1 +#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2 +#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3 +#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6) +#define GHWCFG2_HS_PHY_TYPE_SHIFT 6 +#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define GHWCFG2_HS_PHY_TYPE_UTMI 1 +#define GHWCFG2_HS_PHY_TYPE_ULPI 2 +#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 +#define GHWCFG2_POINT2POINT BIT(5) +#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3) +#define GHWCFG2_ARCHITECTURE_SHIFT 3 +#define GHWCFG2_SLAVE_ONLY_ARCH 0 +#define GHWCFG2_EXT_DMA_ARCH 1 +#define GHWCFG2_INT_DMA_ARCH 2 +#define GHWCFG2_OP_MODE_MASK (0x7 << 0) +#define GHWCFG2_OP_MODE_SHIFT 0 +#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0 +#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1 +#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 +#define GHWCFG2_OP_MODE_UNDEFINED 7 + +#define GHWCFG3 HSOTG_REG(0x004c) +#define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16) +#define GHWCFG3_DFIFO_DEPTH_SHIFT 16 +#define GHWCFG3_OTG_LPM_EN BIT(15) +#define GHWCFG3_BC_SUPPORT BIT(14) +#define GHWCFG3_OTG_ENABLE_HSIC BIT(13) +#define GHWCFG3_ADP_SUPP BIT(12) +#define GHWCFG3_SYNCH_RESET_TYPE BIT(11) +#define GHWCFG3_OPTIONAL_FEATURES BIT(10) +#define GHWCFG3_VENDOR_CTRL_IF BIT(9) +#define GHWCFG3_I2C BIT(8) +#define GHWCFG3_OTG_FUNC BIT(7) +#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) +#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4 +#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0) +#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0 + +#define GHWCFG4 HSOTG_REG(0x0050) +#define GHWCFG4_DESC_DMA_DYN BIT(31) +#define GHWCFG4_DESC_DMA BIT(30) +#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) +#define GHWCFG4_NUM_IN_EPS_SHIFT 26 +#define GHWCFG4_DED_FIFO_EN BIT(25) +#define GHWCFG4_DED_FIFO_SHIFT 25 +#define GHWCFG4_SESSION_END_FILT_EN BIT(24) +#define GHWCFG4_B_VALID_FILT_EN BIT(23) +#define GHWCFG4_A_VALID_FILT_EN BIT(22) +#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21) +#define GHWCFG4_IDDIG_FILT_EN BIT(20) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 +#define GHWCFG4_ACG_SUPPORTED BIT(12) +#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) #define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) -#define GHWCFG4_XHIBER BIT(7) -#define GHWCFG4_HIBER BIT(6) -#define GHWCFG4_MIN_AHB_FREQ BIT(5) -#define GHWCFG4_POWER_OPTIMIZ BIT(4) -#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0) -#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0 - -#define GLPMCFG HSOTG_REG(0x0054) -#define GLPMCFG_INVSELHSIC BIT(31) -#define GLPMCFG_HSICCON BIT(30) -#define GLPMCFG_RSTRSLPSTS BIT(29) -#define GLPMCFG_ENBESL BIT(28) -#define GLPMCFG_LPM_RETRYCNT_STS_MASK (0x7 << 25) -#define GLPMCFG_LPM_RETRYCNT_STS_SHIFT 25 -#define GLPMCFG_SNDLPM BIT(24) -#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) -#define GLPMCFG_RETRY_CNT_SHIFT 21 -#define GLPMCFG_LPM_REJECT_CTRL_CONTROL BIT(21) -#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) -#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) -#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 -#define GLPMCFG_L1RESUMEOK BIT(16) -#define GLPMCFG_SLPSTS BIT(15) -#define GLPMCFG_COREL1RES_MASK (0x3 << 13) -#define GLPMCFG_COREL1RES_SHIFT 13 -#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8) -#define GLPMCFG_HIRD_THRES_SHIFT 8 -#define GLPMCFG_HIRD_THRES_EN (0x10 << 8) -#define GLPMCFG_ENBLSLPM BIT(7) -#define GLPMCFG_BREMOTEWAKE BIT(6) -#define GLPMCFG_HIRD_MASK (0xf << 2) -#define GLPMCFG_HIRD_SHIFT 2 -#define GLPMCFG_APPL1RES BIT(1) -#define GLPMCFG_LPMCAP BIT(0) - -#define GPWRDN HSOTG_REG(0x0058) -#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24) -#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24 -#define GPWRDN_ADP_INT BIT(23) -#define GPWRDN_BSESSVLD BIT(22) -#define GPWRDN_IDSTS BIT(21) -#define GPWRDN_LINESTATE_MASK (0x3 << 19) -#define GPWRDN_LINESTATE_SHIFT 19 -#define GPWRDN_STS_CHGINT_MSK BIT(18) -#define GPWRDN_STS_CHGINT BIT(17) -#define GPWRDN_SRP_DET_MSK BIT(16) -#define GPWRDN_SRP_DET BIT(15) -#define GPWRDN_CONNECT_DET_MSK BIT(14) -#define GPWRDN_CONNECT_DET BIT(13) -#define GPWRDN_DISCONN_DET_MSK BIT(12) -#define GPWRDN_DISCONN_DET BIT(11) -#define GPWRDN_RST_DET_MSK BIT(10) -#define GPWRDN_RST_DET BIT(9) -#define GPWRDN_LNSTSCHG_MSK BIT(8) -#define GPWRDN_LNSTSCHG BIT(7) -#define GPWRDN_DIS_VBUS BIT(6) -#define GPWRDN_PWRDNSWTCH BIT(5) -#define GPWRDN_PWRDNRSTN BIT(4) -#define GPWRDN_PWRDNCLMP BIT(3) -#define GPWRDN_RESTORE BIT(2) -#define GPWRDN_PMUACTV BIT(1) -#define GPWRDN_PMUINTSEL BIT(0) - -#define GDFIFOCFG HSOTG_REG(0x005c) -#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16) -#define GDFIFOCFG_EPINFOBASE_SHIFT 16 -#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0) -#define GDFIFOCFG_GDFIFOCFG_SHIFT 0 - -#define ADPCTL HSOTG_REG(0x0060) -#define ADPCTL_AR_MASK (0x3 << 27) -#define ADPCTL_AR_SHIFT 27 -#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26) -#define ADPCTL_ADP_SNS_INT_MSK BIT(25) -#define ADPCTL_ADP_PRB_INT_MSK BIT(24) -#define ADPCTL_ADP_TMOUT_INT BIT(23) -#define ADPCTL_ADP_SNS_INT BIT(22) -#define ADPCTL_ADP_PRB_INT BIT(21) -#define ADPCTL_ADPENA BIT(20) -#define ADPCTL_ADPRES BIT(19) -#define ADPCTL_ENASNS BIT(18) -#define ADPCTL_ENAPRB BIT(17) -#define ADPCTL_RTIM_MASK (0x7ff << 6) -#define ADPCTL_RTIM_SHIFT 6 -#define ADPCTL_PRB_PER_MASK (0x3 << 4) -#define ADPCTL_PRB_PER_SHIFT 4 -#define ADPCTL_PRB_DELTA_MASK (0x3 << 2) -#define ADPCTL_PRB_DELTA_SHIFT 2 -#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) -#define ADPCTL_PRB_DSCHRG_SHIFT 0 - -#define GREFCLK HSOTG_REG(0x0064) -#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15) -#define GREFCLK_REFCLKPER_SHIFT 15 -#define GREFCLK_REF_CLK_MODE BIT(14) -#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff) +#define GHWCFG4_XHIBER BIT(7) +#define GHWCFG4_HIBER BIT(6) +#define GHWCFG4_MIN_AHB_FREQ BIT(5) +#define GHWCFG4_POWER_OPTIMIZ BIT(4) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0 + +#define GLPMCFG HSOTG_REG(0x0054) +#define GLPMCFG_INVSELHSIC BIT(31) +#define GLPMCFG_HSICCON BIT(30) +#define GLPMCFG_RSTRSLPSTS BIT(29) +#define GLPMCFG_ENBESL BIT(28) +#define GLPMCFG_LPM_RETRYCNT_STS_MASK (0x7 << 25) +#define GLPMCFG_LPM_RETRYCNT_STS_SHIFT 25 +#define GLPMCFG_SNDLPM BIT(24) +#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) +#define GLPMCFG_RETRY_CNT_SHIFT 21 +#define GLPMCFG_LPM_REJECT_CTRL_CONTROL BIT(21) +#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) +#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) +#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 +#define GLPMCFG_L1RESUMEOK BIT(16) +#define GLPMCFG_SLPSTS BIT(15) +#define GLPMCFG_COREL1RES_MASK (0x3 << 13) +#define GLPMCFG_COREL1RES_SHIFT 13 +#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8) +#define GLPMCFG_HIRD_THRES_SHIFT 8 +#define GLPMCFG_HIRD_THRES_EN (0x10 << 8) +#define GLPMCFG_ENBLSLPM BIT(7) +#define GLPMCFG_BREMOTEWAKE BIT(6) +#define GLPMCFG_HIRD_MASK (0xf << 2) +#define GLPMCFG_HIRD_SHIFT 2 +#define GLPMCFG_APPL1RES BIT(1) +#define GLPMCFG_LPMCAP BIT(0) + +#define GPWRDN HSOTG_REG(0x0058) +#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24) +#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24 +#define GPWRDN_ADP_INT BIT(23) +#define GPWRDN_BSESSVLD BIT(22) +#define GPWRDN_IDSTS BIT(21) +#define GPWRDN_LINESTATE_MASK (0x3 << 19) +#define GPWRDN_LINESTATE_SHIFT 19 +#define GPWRDN_STS_CHGINT_MSK BIT(18) +#define GPWRDN_STS_CHGINT BIT(17) +#define GPWRDN_SRP_DET_MSK BIT(16) +#define GPWRDN_SRP_DET BIT(15) +#define GPWRDN_CONNECT_DET_MSK BIT(14) +#define GPWRDN_CONNECT_DET BIT(13) +#define GPWRDN_DISCONN_DET_MSK BIT(12) +#define GPWRDN_DISCONN_DET BIT(11) +#define GPWRDN_RST_DET_MSK BIT(10) +#define GPWRDN_RST_DET BIT(9) +#define GPWRDN_LNSTSCHG_MSK BIT(8) +#define GPWRDN_LNSTSCHG BIT(7) +#define GPWRDN_DIS_VBUS BIT(6) +#define GPWRDN_PWRDNSWTCH BIT(5) +#define GPWRDN_PWRDNRSTN BIT(4) +#define GPWRDN_PWRDNCLMP BIT(3) +#define GPWRDN_RESTORE BIT(2) +#define GPWRDN_PMUACTV BIT(1) +#define GPWRDN_PMUINTSEL BIT(0) + +#define GDFIFOCFG HSOTG_REG(0x005c) +#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16) +#define GDFIFOCFG_EPINFOBASE_SHIFT 16 +#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0) +#define GDFIFOCFG_GDFIFOCFG_SHIFT 0 + +#define ADPCTL HSOTG_REG(0x0060) +#define ADPCTL_AR_MASK (0x3 << 27) +#define ADPCTL_AR_SHIFT 27 +#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26) +#define ADPCTL_ADP_SNS_INT_MSK BIT(25) +#define ADPCTL_ADP_PRB_INT_MSK BIT(24) +#define ADPCTL_ADP_TMOUT_INT BIT(23) +#define ADPCTL_ADP_SNS_INT BIT(22) +#define ADPCTL_ADP_PRB_INT BIT(21) +#define ADPCTL_ADPENA BIT(20) +#define ADPCTL_ADPRES BIT(19) +#define ADPCTL_ENASNS BIT(18) +#define ADPCTL_ENAPRB BIT(17) +#define ADPCTL_RTIM_MASK (0x7ff << 6) +#define ADPCTL_RTIM_SHIFT 6 +#define ADPCTL_PRB_PER_MASK (0x3 << 4) +#define ADPCTL_PRB_PER_SHIFT 4 +#define ADPCTL_PRB_DELTA_MASK (0x3 << 2) +#define ADPCTL_PRB_DELTA_SHIFT 2 +#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) +#define ADPCTL_PRB_DSCHRG_SHIFT 0 + +#define GREFCLK HSOTG_REG(0x0064) +#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15) +#define GREFCLK_REFCLKPER_SHIFT 15 +#define GREFCLK_REF_CLK_MODE BIT(14) +#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff) #define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0 -#define GINTMSK2 HSOTG_REG(0x0068) -#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0) +#define GINTMSK2 HSOTG_REG(0x0068) +#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0) -#define GINTSTS2 HSOTG_REG(0x006c) -#define GINTSTS2_WKUP_ALERT_INT BIT(0) +#define GINTSTS2 HSOTG_REG(0x006c) +#define GINTSTS2_WKUP_ALERT_INT BIT(0) -#define HPTXFSIZ HSOTG_REG(0x100) +#define HPTXFSIZ HSOTG_REG(0x100) /* Use FIFOSIZE_* constants to access this register */ -#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) +#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) /* Use FIFOSIZE_* constants to access this register */ /* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */ -#define FIFOSIZE_DEPTH_MASK (0xffff << 16) -#define FIFOSIZE_DEPTH_SHIFT 16 -#define FIFOSIZE_STARTADDR_MASK (0xffff << 0) -#define FIFOSIZE_STARTADDR_SHIFT 0 -#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff) +#define FIFOSIZE_DEPTH_MASK (0xffff << 16) +#define FIFOSIZE_DEPTH_SHIFT 16 +#define FIFOSIZE_STARTADDR_MASK (0xffff << 0) +#define FIFOSIZE_STARTADDR_SHIFT 0 +#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff) /* Device mode registers */ -#define DCFG HSOTG_REG(0x800) -#define DCFG_DESCDMA_EN BIT(23) -#define DCFG_EPMISCNT_MASK (0x1f << 18) -#define DCFG_EPMISCNT_SHIFT 18 -#define DCFG_EPMISCNT_LIMIT 0x1f -#define DCFG_EPMISCNT(_x) ((_x) << 18) -#define DCFG_IPG_ISOC_SUPPORDED BIT(17) -#define DCFG_PERFRINT_MASK (0x3 << 11) -#define DCFG_PERFRINT_SHIFT 11 -#define DCFG_PERFRINT_LIMIT 0x3 -#define DCFG_PERFRINT(_x) ((_x) << 11) -#define DCFG_DEVADDR_MASK (0x7f << 4) -#define DCFG_DEVADDR_SHIFT 4 -#define DCFG_DEVADDR_LIMIT 0x7f -#define DCFG_DEVADDR(_x) ((_x) << 4) -#define DCFG_NZ_STS_OUT_HSHK BIT(2) -#define DCFG_DEVSPD_MASK (0x3 << 0) -#define DCFG_DEVSPD_SHIFT 0 -#define DCFG_DEVSPD_HS 0 -#define DCFG_DEVSPD_FS 1 -#define DCFG_DEVSPD_LS 2 -#define DCFG_DEVSPD_FS48 3 - -#define DCTL HSOTG_REG(0x804) +#define DCFG HSOTG_REG(0x800) +#define DCFG_DESCDMA_EN BIT(23) +#define DCFG_EPMISCNT_MASK (0x1f << 18) +#define DCFG_EPMISCNT_SHIFT 18 +#define DCFG_EPMISCNT_LIMIT 0x1f +#define DCFG_EPMISCNT(_x) ((_x) << 18) +#define DCFG_IPG_ISOC_SUPPORDED BIT(17) +#define DCFG_PERFRINT_MASK (0x3 << 11) +#define DCFG_PERFRINT_SHIFT 11 +#define DCFG_PERFRINT_LIMIT 0x3 +#define DCFG_PERFRINT(_x) ((_x) << 11) +#define DCFG_DEVADDR_MASK (0x7f << 4) +#define DCFG_DEVADDR_SHIFT 4 +#define DCFG_DEVADDR_LIMIT 0x7f +#define DCFG_DEVADDR(_x) ((_x) << 4) +#define DCFG_NZ_STS_OUT_HSHK BIT(2) +#define DCFG_DEVSPD_MASK (0x3 << 0) +#define DCFG_DEVSPD_SHIFT 0 +#define DCFG_DEVSPD_HS 0 +#define DCFG_DEVSPD_FS 1 +#define DCFG_DEVSPD_LS 2 +#define DCFG_DEVSPD_FS48 3 + +#define DCTL HSOTG_REG(0x804) #define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19) -#define DCTL_PWRONPRGDONE BIT(11) -#define DCTL_CGOUTNAK BIT(10) -#define DCTL_SGOUTNAK BIT(9) -#define DCTL_CGNPINNAK BIT(8) -#define DCTL_SGNPINNAK BIT(7) -#define DCTL_TSTCTL_MASK (0x7 << 4) -#define DCTL_TSTCTL_SHIFT 4 -#define DCTL_GOUTNAKSTS BIT(3) -#define DCTL_GNPINNAKSTS BIT(2) -#define DCTL_SFTDISCON BIT(1) -#define DCTL_RMTWKUPSIG BIT(0) - -#define DSTS HSOTG_REG(0x808) -#define DSTS_SOFFN_MASK (0x3fff << 8) -#define DSTS_SOFFN_SHIFT 8 -#define DSTS_SOFFN_LIMIT 0x3fff -#define DSTS_SOFFN(_x) ((_x) << 8) -#define DSTS_ERRATICERR BIT(3) -#define DSTS_ENUMSPD_MASK (0x3 << 1) -#define DSTS_ENUMSPD_SHIFT 1 -#define DSTS_ENUMSPD_HS 0 -#define DSTS_ENUMSPD_FS 1 -#define DSTS_ENUMSPD_LS 2 -#define DSTS_ENUMSPD_FS48 3 -#define DSTS_SUSPSTS BIT(0) - -#define DIEPMSK HSOTG_REG(0x810) -#define DIEPMSK_NAKMSK BIT(13) -#define DIEPMSK_BNAININTRMSK BIT(9) -#define DIEPMSK_TXFIFOUNDRNMSK BIT(8) -#define DIEPMSK_TXFIFOEMPTY BIT(7) -#define DIEPMSK_INEPNAKEFFMSK BIT(6) -#define DIEPMSK_INTKNEPMISMSK BIT(5) -#define DIEPMSK_INTKNTXFEMPMSK BIT(4) -#define DIEPMSK_TIMEOUTMSK BIT(3) -#define DIEPMSK_AHBERRMSK BIT(2) -#define DIEPMSK_EPDISBLDMSK BIT(1) -#define DIEPMSK_XFERCOMPLMSK BIT(0) - -#define DOEPMSK HSOTG_REG(0x814) -#define DOEPMSK_BNAMSK BIT(9) -#define DOEPMSK_BACK2BACKSETUP BIT(6) -#define DOEPMSK_STSPHSERCVDMSK BIT(5) -#define DOEPMSK_OUTTKNEPDISMSK BIT(4) -#define DOEPMSK_SETUPMSK BIT(3) -#define DOEPMSK_AHBERRMSK BIT(2) -#define DOEPMSK_EPDISBLDMSK BIT(1) -#define DOEPMSK_XFERCOMPLMSK BIT(0) - -#define DAINT HSOTG_REG(0x818) -#define DAINTMSK HSOTG_REG(0x81C) -#define DAINT_OUTEP_SHIFT 16 -#define DAINT_OUTEP(_x) (1 << ((_x) + 16)) -#define DAINT_INEP(_x) (1 << (_x)) - -#define DTKNQR1 HSOTG_REG(0x820) -#define DTKNQR2 HSOTG_REG(0x824) -#define DTKNQR3 HSOTG_REG(0x830) -#define DTKNQR4 HSOTG_REG(0x834) -#define DIEPEMPMSK HSOTG_REG(0x834) - -#define DVBUSDIS HSOTG_REG(0x828) -#define DVBUSPULSE HSOTG_REG(0x82C) - -#define DIEPCTL0 HSOTG_REG(0x900) -#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) - -#define DOEPCTL0 HSOTG_REG(0xB00) -#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) +#define DCTL_PWRONPRGDONE BIT(11) +#define DCTL_CGOUTNAK BIT(10) +#define DCTL_SGOUTNAK BIT(9) +#define DCTL_CGNPINNAK BIT(8) +#define DCTL_SGNPINNAK BIT(7) +#define DCTL_TSTCTL_MASK (0x7 << 4) +#define DCTL_TSTCTL_SHIFT 4 +#define DCTL_GOUTNAKSTS BIT(3) +#define DCTL_GNPINNAKSTS BIT(2) +#define DCTL_SFTDISCON BIT(1) +#define DCTL_RMTWKUPSIG BIT(0) + +#define DSTS HSOTG_REG(0x808) +#define DSTS_SOFFN_MASK (0x3fff << 8) +#define DSTS_SOFFN_SHIFT 8 +#define DSTS_SOFFN_LIMIT 0x3fff +#define DSTS_SOFFN(_x) ((_x) << 8) +#define DSTS_ERRATICERR BIT(3) +#define DSTS_ENUMSPD_MASK (0x3 << 1) +#define DSTS_ENUMSPD_SHIFT 1 +#define DSTS_ENUMSPD_HS 0 +#define DSTS_ENUMSPD_FS 1 +#define DSTS_ENUMSPD_LS 2 +#define DSTS_ENUMSPD_FS48 3 +#define DSTS_SUSPSTS BIT(0) + +#define DIEPMSK HSOTG_REG(0x810) +#define DIEPMSK_NAKMSK BIT(13) +#define DIEPMSK_BNAININTRMSK BIT(9) +#define DIEPMSK_TXFIFOUNDRNMSK BIT(8) +#define DIEPMSK_TXFIFOEMPTY BIT(7) +#define DIEPMSK_INEPNAKEFFMSK BIT(6) +#define DIEPMSK_INTKNEPMISMSK BIT(5) +#define DIEPMSK_INTKNTXFEMPMSK BIT(4) +#define DIEPMSK_TIMEOUTMSK BIT(3) +#define DIEPMSK_AHBERRMSK BIT(2) +#define DIEPMSK_EPDISBLDMSK BIT(1) +#define DIEPMSK_XFERCOMPLMSK BIT(0) + +#define DOEPMSK HSOTG_REG(0x814) +#define DOEPMSK_BNAMSK BIT(9) +#define DOEPMSK_BACK2BACKSETUP BIT(6) +#define DOEPMSK_STSPHSERCVDMSK BIT(5) +#define DOEPMSK_OUTTKNEPDISMSK BIT(4) +#define DOEPMSK_SETUPMSK BIT(3) +#define DOEPMSK_AHBERRMSK BIT(2) +#define DOEPMSK_EPDISBLDMSK BIT(1) +#define DOEPMSK_XFERCOMPLMSK BIT(0) + +#define DAINT HSOTG_REG(0x818) +#define DAINTMSK HSOTG_REG(0x81C) +#define DAINT_OUTEP_SHIFT 16 +#define DAINT_OUTEP(_x) (1 << ((_x) + 16)) +#define DAINT_INEP(_x) (1 << (_x)) + +#define DTKNQR1 HSOTG_REG(0x820) +#define DTKNQR2 HSOTG_REG(0x824) +#define DTKNQR3 HSOTG_REG(0x830) +#define DTKNQR4 HSOTG_REG(0x834) +#define DIEPEMPMSK HSOTG_REG(0x834) + +#define DVBUSDIS HSOTG_REG(0x828) +#define DVBUSPULSE HSOTG_REG(0x82C) + +#define DIEPCTL0 HSOTG_REG(0x900) +#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) + +#define DOEPCTL0 HSOTG_REG(0xB00) +#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) /* EP0 specialness: * bits[29..28] - reserved (no SetD0PID, SetD1PID) * bits[25..22] - should always be zero, this isn't a periodic endpoint * bits[10..0] - MPS setting different for EP0 */ -#define D0EPCTL_MPS_MASK (0x3 << 0) -#define D0EPCTL_MPS_SHIFT 0 -#define D0EPCTL_MPS_64 0 -#define D0EPCTL_MPS_32 1 -#define D0EPCTL_MPS_16 2 -#define D0EPCTL_MPS_8 3 - -#define DXEPCTL_EPENA BIT(31) -#define DXEPCTL_EPDIS BIT(30) -#define DXEPCTL_SETD1PID BIT(29) -#define DXEPCTL_SETODDFR BIT(29) -#define DXEPCTL_SETD0PID BIT(28) -#define DXEPCTL_SETEVENFR BIT(28) -#define DXEPCTL_SNAK BIT(27) -#define DXEPCTL_CNAK BIT(26) -#define DXEPCTL_TXFNUM_MASK (0xf << 22) -#define DXEPCTL_TXFNUM_SHIFT 22 -#define DXEPCTL_TXFNUM_LIMIT 0xf -#define DXEPCTL_TXFNUM(_x) ((_x) << 22) -#define DXEPCTL_STALL BIT(21) -#define DXEPCTL_SNP BIT(20) -#define DXEPCTL_EPTYPE_MASK (0x3 << 18) -#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) -#define DXEPCTL_EPTYPE_ISO (0x1 << 18) -#define DXEPCTL_EPTYPE_BULK (0x2 << 18) -#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) - -#define DXEPCTL_NAKSTS BIT(17) -#define DXEPCTL_DPID BIT(16) -#define DXEPCTL_EOFRNUM BIT(16) -#define DXEPCTL_USBACTEP BIT(15) -#define DXEPCTL_NEXTEP_MASK (0xf << 11) -#define DXEPCTL_NEXTEP_SHIFT 11 -#define DXEPCTL_NEXTEP_LIMIT 0xf -#define DXEPCTL_NEXTEP(_x) ((_x) << 11) -#define DXEPCTL_MPS_MASK (0x7ff << 0) -#define DXEPCTL_MPS_SHIFT 0 -#define DXEPCTL_MPS_LIMIT 0x7ff -#define DXEPCTL_MPS(_x) ((_x) << 0) - -#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) -#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) -#define DXEPINT_SETUP_RCVD BIT(15) -#define DXEPINT_NYETINTRPT BIT(14) -#define DXEPINT_NAKINTRPT BIT(13) -#define DXEPINT_BBLEERRINTRPT BIT(12) -#define DXEPINT_PKTDRPSTS BIT(11) -#define DXEPINT_BNAINTR BIT(9) -#define DXEPINT_TXFIFOUNDRN BIT(8) -#define DXEPINT_OUTPKTERR BIT(8) -#define DXEPINT_TXFEMP BIT(7) -#define DXEPINT_INEPNAKEFF BIT(6) -#define DXEPINT_BACK2BACKSETUP BIT(6) -#define DXEPINT_INTKNEPMIS BIT(5) -#define DXEPINT_STSPHSERCVD BIT(5) -#define DXEPINT_INTKNTXFEMP BIT(4) -#define DXEPINT_OUTTKNEPDIS BIT(4) -#define DXEPINT_TIMEOUT BIT(3) -#define DXEPINT_SETUP BIT(3) -#define DXEPINT_AHBERR BIT(2) -#define DXEPINT_EPDISBLD BIT(1) -#define DXEPINT_XFERCOMPL BIT(0) - -#define DIEPTSIZ0 HSOTG_REG(0x910) -#define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19) -#define DIEPTSIZ0_PKTCNT_SHIFT 19 -#define DIEPTSIZ0_PKTCNT_LIMIT 0x3 -#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19) -#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0) -#define DIEPTSIZ0_XFERSIZE_SHIFT 0 -#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f -#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0) - -#define DOEPTSIZ0 HSOTG_REG(0xB10) -#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29) -#define DOEPTSIZ0_SUPCNT_SHIFT 29 -#define DOEPTSIZ0_SUPCNT_LIMIT 0x3 -#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29) -#define DOEPTSIZ0_PKTCNT BIT(19) -#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0) -#define DOEPTSIZ0_XFERSIZE_SHIFT 0 - -#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) -#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) -#define DXEPTSIZ_MC_MASK (0x3 << 29) -#define DXEPTSIZ_MC_SHIFT 29 -#define DXEPTSIZ_MC_LIMIT 0x3 -#define DXEPTSIZ_MC(_x) ((_x) << 29) -#define DXEPTSIZ_PKTCNT_MASK (0x3ff << 19) -#define DXEPTSIZ_PKTCNT_SHIFT 19 -#define DXEPTSIZ_PKTCNT_LIMIT 0x3ff -#define DXEPTSIZ_PKTCNT_GET(_v) (((_v) >> 19) & 0x3ff) -#define DXEPTSIZ_PKTCNT(_x) ((_x) << 19) -#define DXEPTSIZ_XFERSIZE_MASK (0x7ffff << 0) -#define DXEPTSIZ_XFERSIZE_SHIFT 0 -#define DXEPTSIZ_XFERSIZE_LIMIT 0x7ffff -#define DXEPTSIZ_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7ffff) -#define DXEPTSIZ_XFERSIZE(_x) ((_x) << 0) - -#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) -#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) - -#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) - -#define PCGCTL HSOTG_REG(0x0e00) -#define PCGCTL_IF_DEV_MODE BIT(31) -#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29) -#define PCGCTL_P2HD_PRT_SPD_SHIFT 29 -#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27) -#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 -#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20) -#define PCGCTL_MAC_DEV_ADDR_SHIFT 20 -#define PCGCTL_MAX_TERMSEL BIT(19) -#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17) -#define PCGCTL_MAX_XCVRSELECT_SHIFT 17 -#define PCGCTL_PORT_POWER BIT(16) -#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14) -#define PCGCTL_PRT_CLK_SEL_SHIFT 14 -#define PCGCTL_ESS_REG_RESTORED BIT(13) -#define PCGCTL_EXTND_HIBER_SWITCH BIT(12) -#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11) -#define PCGCTL_ENBL_EXTND_HIBER BIT(10) -#define PCGCTL_RESTOREMODE BIT(9) -#define PCGCTL_RESETAFTSUSP BIT(8) -#define PCGCTL_DEEP_SLEEP BIT(7) -#define PCGCTL_PHY_IN_SLEEP BIT(6) -#define PCGCTL_ENBL_SLEEP_GATING BIT(5) -#define PCGCTL_RSTPDWNMODULE BIT(3) -#define PCGCTL_PWRCLMP BIT(2) -#define PCGCTL_GATEHCLK BIT(1) -#define PCGCTL_STOPPCLK BIT(0) +#define D0EPCTL_MPS_MASK (0x3 << 0) +#define D0EPCTL_MPS_SHIFT 0 +#define D0EPCTL_MPS_64 0 +#define D0EPCTL_MPS_32 1 +#define D0EPCTL_MPS_16 2 +#define D0EPCTL_MPS_8 3 + +#define DXEPCTL_EPENA BIT(31) +#define DXEPCTL_EPDIS BIT(30) +#define DXEPCTL_SETD1PID BIT(29) +#define DXEPCTL_SETODDFR BIT(29) +#define DXEPCTL_SETD0PID BIT(28) +#define DXEPCTL_SETEVENFR BIT(28) +#define DXEPCTL_SNAK BIT(27) +#define DXEPCTL_CNAK BIT(26) +#define DXEPCTL_TXFNUM_MASK (0xf << 22) +#define DXEPCTL_TXFNUM_SHIFT 22 +#define DXEPCTL_TXFNUM_LIMIT 0xf +#define DXEPCTL_TXFNUM(_x) ((_x) << 22) +#define DXEPCTL_STALL BIT(21) +#define DXEPCTL_SNP BIT(20) +#define DXEPCTL_EPTYPE_MASK (0x3 << 18) +#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) +#define DXEPCTL_EPTYPE_ISO (0x1 << 18) +#define DXEPCTL_EPTYPE_BULK (0x2 << 18) +#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) + +#define DXEPCTL_NAKSTS BIT(17) +#define DXEPCTL_DPID BIT(16) +#define DXEPCTL_EOFRNUM BIT(16) +#define DXEPCTL_USBACTEP BIT(15) +#define DXEPCTL_NEXTEP_MASK (0xf << 11) +#define DXEPCTL_NEXTEP_SHIFT 11 +#define DXEPCTL_NEXTEP_LIMIT 0xf +#define DXEPCTL_NEXTEP(_x) ((_x) << 11) +#define DXEPCTL_MPS_MASK (0x7ff << 0) +#define DXEPCTL_MPS_SHIFT 0 +#define DXEPCTL_MPS_LIMIT 0x7ff +#define DXEPCTL_MPS(_x) ((_x) << 0) + +#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) +#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) +#define DXEPINT_SETUP_RCVD BIT(15) +#define DXEPINT_NYETINTRPT BIT(14) +#define DXEPINT_NAKINTRPT BIT(13) +#define DXEPINT_BBLEERRINTRPT BIT(12) +#define DXEPINT_PKTDRPSTS BIT(11) +#define DXEPINT_BNAINTR BIT(9) +#define DXEPINT_TXFIFOUNDRN BIT(8) +#define DXEPINT_OUTPKTERR BIT(8) +#define DXEPINT_TXFEMP BIT(7) +#define DXEPINT_INEPNAKEFF BIT(6) +#define DXEPINT_BACK2BACKSETUP BIT(6) +#define DXEPINT_INTKNEPMIS BIT(5) +#define DXEPINT_STSPHSERCVD BIT(5) +#define DXEPINT_INTKNTXFEMP BIT(4) +#define DXEPINT_OUTTKNEPDIS BIT(4) +#define DXEPINT_TIMEOUT BIT(3) +#define DXEPINT_SETUP BIT(3) +#define DXEPINT_AHBERR BIT(2) +#define DXEPINT_EPDISBLD BIT(1) +#define DXEPINT_XFERCOMPL BIT(0) + +#define DIEPTSIZ0 HSOTG_REG(0x910) +#define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19) +#define DIEPTSIZ0_PKTCNT_SHIFT 19 +#define DIEPTSIZ0_PKTCNT_LIMIT 0x3 +#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19) +#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0) +#define DIEPTSIZ0_XFERSIZE_SHIFT 0 +#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f +#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0) + +#define DOEPTSIZ0 HSOTG_REG(0xB10) +#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29) +#define DOEPTSIZ0_SUPCNT_SHIFT 29 +#define DOEPTSIZ0_SUPCNT_LIMIT 0x3 +#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29) +#define DOEPTSIZ0_PKTCNT BIT(19) +#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0) +#define DOEPTSIZ0_XFERSIZE_SHIFT 0 + +#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) +#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) +#define DXEPTSIZ_MC_MASK (0x3 << 29) +#define DXEPTSIZ_MC_SHIFT 29 +#define DXEPTSIZ_MC_LIMIT 0x3 +#define DXEPTSIZ_MC(_x) ((_x) << 29) +#define DXEPTSIZ_PKTCNT_MASK (0x3ff << 19) +#define DXEPTSIZ_PKTCNT_SHIFT 19 +#define DXEPTSIZ_PKTCNT_LIMIT 0x3ff +#define DXEPTSIZ_PKTCNT_GET(_v) (((_v) >> 19) & 0x3ff) +#define DXEPTSIZ_PKTCNT(_x) ((_x) << 19) +#define DXEPTSIZ_XFERSIZE_MASK (0x7ffff << 0) +#define DXEPTSIZ_XFERSIZE_SHIFT 0 +#define DXEPTSIZ_XFERSIZE_LIMIT 0x7ffff +#define DXEPTSIZ_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7ffff) +#define DXEPTSIZ_XFERSIZE(_x) ((_x) << 0) + +#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) +#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) + +#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) + +#define PCGCTL HSOTG_REG(0x0e00) +#define PCGCTL_IF_DEV_MODE BIT(31) +#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29) +#define PCGCTL_P2HD_PRT_SPD_SHIFT 29 +#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27) +#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 +#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20) +#define PCGCTL_MAC_DEV_ADDR_SHIFT 20 +#define PCGCTL_MAX_TERMSEL BIT(19) +#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17) +#define PCGCTL_MAX_XCVRSELECT_SHIFT 17 +#define PCGCTL_PORT_POWER BIT(16) +#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14) +#define PCGCTL_PRT_CLK_SEL_SHIFT 14 +#define PCGCTL_ESS_REG_RESTORED BIT(13) +#define PCGCTL_EXTND_HIBER_SWITCH BIT(12) +#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11) +#define PCGCTL_ENBL_EXTND_HIBER BIT(10) +#define PCGCTL_RESTOREMODE BIT(9) +#define PCGCTL_RESETAFTSUSP BIT(8) +#define PCGCTL_DEEP_SLEEP BIT(7) +#define PCGCTL_PHY_IN_SLEEP BIT(6) +#define PCGCTL_ENBL_SLEEP_GATING BIT(5) +#define PCGCTL_RSTPDWNMODULE BIT(3) +#define PCGCTL_PWRCLMP BIT(2) +#define PCGCTL_GATEHCLK BIT(1) +#define PCGCTL_STOPPCLK BIT(0) #define PCGCCTL1 HSOTG_REG(0xe04) #define PCGCCTL1_TIMER (0x3 << 1) #define PCGCCTL1_GATEEN BIT(0) -#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) +#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) /* Host Mode Registers */ -#define HCFG HSOTG_REG(0x0400) -#define HCFG_MODECHTIMEN BIT(31) -#define HCFG_PERSCHEDENA BIT(26) -#define HCFG_FRLISTEN_MASK (0x3 << 24) -#define HCFG_FRLISTEN_SHIFT 24 -#define HCFG_FRLISTEN_8 (0 << 24) -#define FRLISTEN_8_SIZE 8 -#define HCFG_FRLISTEN_16 BIT(24) -#define FRLISTEN_16_SIZE 16 -#define HCFG_FRLISTEN_32 (2 << 24) -#define FRLISTEN_32_SIZE 32 -#define HCFG_FRLISTEN_64 (3 << 24) -#define FRLISTEN_64_SIZE 64 -#define HCFG_DESCDMA BIT(23) -#define HCFG_RESVALID_MASK (0xff << 8) -#define HCFG_RESVALID_SHIFT 8 -#define HCFG_ENA32KHZ BIT(7) -#define HCFG_FSLSSUPP BIT(2) -#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0) -#define HCFG_FSLSPCLKSEL_SHIFT 0 -#define HCFG_FSLSPCLKSEL_30_60_MHZ 0 -#define HCFG_FSLSPCLKSEL_48_MHZ 1 -#define HCFG_FSLSPCLKSEL_6_MHZ 2 - -#define HFIR HSOTG_REG(0x0404) -#define HFIR_FRINT_MASK (0xffff << 0) -#define HFIR_FRINT_SHIFT 0 -#define HFIR_RLDCTRL BIT(16) - -#define HFNUM HSOTG_REG(0x0408) -#define HFNUM_FRREM_MASK (0xffff << 16) -#define HFNUM_FRREM_SHIFT 16 -#define HFNUM_FRNUM_MASK (0xffff << 0) -#define HFNUM_FRNUM_SHIFT 0 -#define HFNUM_MAX_FRNUM 0x3fff - -#define HPTXSTS HSOTG_REG(0x0410) -#define TXSTS_QTOP_ODD BIT(31) -#define TXSTS_QTOP_CHNEP_MASK (0xf << 27) -#define TXSTS_QTOP_CHNEP_SHIFT 27 -#define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) -#define TXSTS_QTOP_TOKEN_SHIFT 25 -#define TXSTS_QTOP_TERMINATE BIT(24) -#define TXSTS_QSPCAVAIL_MASK (0xff << 16) -#define TXSTS_QSPCAVAIL_SHIFT 16 -#define TXSTS_FSPCAVAIL_MASK (0xffff << 0) -#define TXSTS_FSPCAVAIL_SHIFT 0 - -#define HAINT HSOTG_REG(0x0414) -#define HAINTMSK HSOTG_REG(0x0418) -#define HFLBADDR HSOTG_REG(0x041c) - -#define HPRT0 HSOTG_REG(0x0440) -#define HPRT0_SPD_MASK (0x3 << 17) -#define HPRT0_SPD_SHIFT 17 -#define HPRT0_SPD_HIGH_SPEED 0 -#define HPRT0_SPD_FULL_SPEED 1 -#define HPRT0_SPD_LOW_SPEED 2 -#define HPRT0_TSTCTL_MASK (0xf << 13) -#define HPRT0_TSTCTL_SHIFT 13 -#define HPRT0_PWR BIT(12) -#define HPRT0_LNSTS_MASK (0x3 << 10) -#define HPRT0_LNSTS_SHIFT 10 -#define HPRT0_RST BIT(8) -#define HPRT0_SUSP BIT(7) -#define HPRT0_RES BIT(6) -#define HPRT0_OVRCURRCHG BIT(5) -#define HPRT0_OVRCURRACT BIT(4) -#define HPRT0_ENACHG BIT(3) -#define HPRT0_ENA BIT(2) -#define HPRT0_CONNDET BIT(1) -#define HPRT0_CONNSTS BIT(0) - -#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch)) -#define HCCHAR_CHENA BIT(31) -#define HCCHAR_CHDIS BIT(30) -#define HCCHAR_ODDFRM BIT(29) -#define HCCHAR_DEVADDR_MASK (0x7f << 22) -#define HCCHAR_DEVADDR_SHIFT 22 -#define HCCHAR_MULTICNT_MASK (0x3 << 20) -#define HCCHAR_MULTICNT_SHIFT 20 -#define HCCHAR_EPTYPE_MASK (0x3 << 18) -#define HCCHAR_EPTYPE_SHIFT 18 -#define HCCHAR_LSPDDEV BIT(17) -#define HCCHAR_EPDIR BIT(15) -#define HCCHAR_EPNUM_MASK (0xf << 11) -#define HCCHAR_EPNUM_SHIFT 11 -#define HCCHAR_MPS_MASK (0x7ff << 0) -#define HCCHAR_MPS_SHIFT 0 - -#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch)) -#define HCSPLT_SPLTENA BIT(31) -#define HCSPLT_COMPSPLT BIT(16) -#define HCSPLT_XACTPOS_MASK (0x3 << 14) -#define HCSPLT_XACTPOS_SHIFT 14 -#define HCSPLT_XACTPOS_MID 0 -#define HCSPLT_XACTPOS_END 1 -#define HCSPLT_XACTPOS_BEGIN 2 -#define HCSPLT_XACTPOS_ALL 3 -#define HCSPLT_HUBADDR_MASK (0x7f << 7) -#define HCSPLT_HUBADDR_SHIFT 7 -#define HCSPLT_PRTADDR_MASK (0x7f << 0) -#define HCSPLT_PRTADDR_SHIFT 0 - -#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch)) -#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch)) -#define HCINTMSK_RESERVED14_31 (0x3ffff << 14) -#define HCINTMSK_FRM_LIST_ROLL BIT(13) -#define HCINTMSK_XCS_XACT BIT(12) -#define HCINTMSK_BNA BIT(11) -#define HCINTMSK_DATATGLERR BIT(10) -#define HCINTMSK_FRMOVRUN BIT(9) -#define HCINTMSK_BBLERR BIT(8) -#define HCINTMSK_XACTERR BIT(7) -#define HCINTMSK_NYET BIT(6) -#define HCINTMSK_ACK BIT(5) -#define HCINTMSK_NAK BIT(4) -#define HCINTMSK_STALL BIT(3) -#define HCINTMSK_AHBERR BIT(2) -#define HCINTMSK_CHHLTD BIT(1) -#define HCINTMSK_XFERCOMPL BIT(0) - -#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch)) -#define TSIZ_DOPNG BIT(31) -#define TSIZ_SC_MC_PID_MASK (0x3 << 29) -#define TSIZ_SC_MC_PID_SHIFT 29 -#define TSIZ_SC_MC_PID_DATA0 0 -#define TSIZ_SC_MC_PID_DATA2 1 -#define TSIZ_SC_MC_PID_DATA1 2 -#define TSIZ_SC_MC_PID_MDATA 3 -#define TSIZ_SC_MC_PID_SETUP 3 -#define TSIZ_PKTCNT_MASK (0x3ff << 19) -#define TSIZ_PKTCNT_SHIFT 19 -#define TSIZ_NTD_MASK (0xff << 8) -#define TSIZ_NTD_SHIFT 8 -#define TSIZ_SCHINFO_MASK (0xff << 0) -#define TSIZ_SCHINFO_SHIFT 0 -#define TSIZ_XFERSIZE_MASK (0x7ffff << 0) -#define TSIZ_XFERSIZE_SHIFT 0 - -#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch)) - -#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch)) - -#define HCFIFO(_ch) HSOTG_REG(0x1000 + 0x1000 * (_ch)) +#define HCFG HSOTG_REG(0x0400) +#define HCFG_MODECHTIMEN BIT(31) +#define HCFG_PERSCHEDENA BIT(26) +#define HCFG_FRLISTEN_MASK (0x3 << 24) +#define HCFG_FRLISTEN_SHIFT 24 +#define HCFG_FRLISTEN_8 (0 << 24) +#define FRLISTEN_8_SIZE 8 +#define HCFG_FRLISTEN_16 BIT(24) +#define FRLISTEN_16_SIZE 16 +#define HCFG_FRLISTEN_32 (2 << 24) +#define FRLISTEN_32_SIZE 32 +#define HCFG_FRLISTEN_64 (3 << 24) +#define FRLISTEN_64_SIZE 64 +#define HCFG_DESCDMA BIT(23) +#define HCFG_RESVALID_MASK (0xff << 8) +#define HCFG_RESVALID_SHIFT 8 +#define HCFG_ENA32KHZ BIT(7) +#define HCFG_FSLSSUPP BIT(2) +#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0) +#define HCFG_FSLSPCLKSEL_SHIFT 0 +#define HCFG_FSLSPCLKSEL_30_60_MHZ 0 +#define HCFG_FSLSPCLKSEL_48_MHZ 1 +#define HCFG_FSLSPCLKSEL_6_MHZ 2 + +#define HFIR HSOTG_REG(0x0404) +#define HFIR_FRINT_MASK (0xffff << 0) +#define HFIR_FRINT_SHIFT 0 +#define HFIR_RLDCTRL BIT(16) + +#define HFNUM HSOTG_REG(0x0408) +#define HFNUM_FRREM_MASK (0xffff << 16) +#define HFNUM_FRREM_SHIFT 16 +#define HFNUM_FRNUM_MASK (0xffff << 0) +#define HFNUM_FRNUM_SHIFT 0 +#define HFNUM_MAX_FRNUM 0x3fff + +#define HPTXSTS HSOTG_REG(0x0410) +#define TXSTS_QTOP_ODD BIT(31) +#define TXSTS_QTOP_CHNEP_MASK (0xf << 27) +#define TXSTS_QTOP_CHNEP_SHIFT 27 +#define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) +#define TXSTS_QTOP_TOKEN_SHIFT 25 +#define TXSTS_QTOP_TERMINATE BIT(24) +#define TXSTS_QSPCAVAIL_MASK (0xff << 16) +#define TXSTS_QSPCAVAIL_SHIFT 16 +#define TXSTS_FSPCAVAIL_MASK (0xffff << 0) +#define TXSTS_FSPCAVAIL_SHIFT 0 + +#define HAINT HSOTG_REG(0x0414) +#define HAINTMSK HSOTG_REG(0x0418) +#define HFLBADDR HSOTG_REG(0x041c) + +#define HPRT0 HSOTG_REG(0x0440) +#define HPRT0_SPD_MASK (0x3 << 17) +#define HPRT0_SPD_SHIFT 17 +#define HPRT0_SPD_HIGH_SPEED 0 +#define HPRT0_SPD_FULL_SPEED 1 +#define HPRT0_SPD_LOW_SPEED 2 +#define HPRT0_TSTCTL_MASK (0xf << 13) +#define HPRT0_TSTCTL_SHIFT 13 +#define HPRT0_PWR BIT(12) +#define HPRT0_LNSTS_MASK (0x3 << 10) +#define HPRT0_LNSTS_SHIFT 10 +#define HPRT0_RST BIT(8) +#define HPRT0_SUSP BIT(7) +#define HPRT0_RES BIT(6) +#define HPRT0_OVRCURRCHG BIT(5) +#define HPRT0_OVRCURRACT BIT(4) +#define HPRT0_ENACHG BIT(3) +#define HPRT0_ENA BIT(2) +#define HPRT0_CONNDET BIT(1) +#define HPRT0_CONNSTS BIT(0) + +#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch)) +#define HCCHAR_CHENA BIT(31) +#define HCCHAR_CHDIS BIT(30) +#define HCCHAR_ODDFRM BIT(29) +#define HCCHAR_DEVADDR_MASK (0x7f << 22) +#define HCCHAR_DEVADDR_SHIFT 22 +#define HCCHAR_MULTICNT_MASK (0x3 << 20) +#define HCCHAR_MULTICNT_SHIFT 20 +#define HCCHAR_EPTYPE_MASK (0x3 << 18) +#define HCCHAR_EPTYPE_SHIFT 18 +#define HCCHAR_LSPDDEV BIT(17) +#define HCCHAR_EPDIR BIT(15) +#define HCCHAR_EPNUM_MASK (0xf << 11) +#define HCCHAR_EPNUM_SHIFT 11 +#define HCCHAR_MPS_MASK (0x7ff << 0) +#define HCCHAR_MPS_SHIFT 0 + +#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch)) +#define HCSPLT_SPLTENA BIT(31) +#define HCSPLT_COMPSPLT BIT(16) +#define HCSPLT_XACTPOS_MASK (0x3 << 14) +#define HCSPLT_XACTPOS_SHIFT 14 +#define HCSPLT_XACTPOS_MID 0 +#define HCSPLT_XACTPOS_END 1 +#define HCSPLT_XACTPOS_BEGIN 2 +#define HCSPLT_XACTPOS_ALL 3 +#define HCSPLT_HUBADDR_MASK (0x7f << 7) +#define HCSPLT_HUBADDR_SHIFT 7 +#define HCSPLT_PRTADDR_MASK (0x7f << 0) +#define HCSPLT_PRTADDR_SHIFT 0 + +#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch)) +#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch)) +#define HCINTMSK_RESERVED14_31 (0x3ffff << 14) +#define HCINTMSK_FRM_LIST_ROLL BIT(13) +#define HCINTMSK_XCS_XACT BIT(12) +#define HCINTMSK_BNA BIT(11) +#define HCINTMSK_DATATGLERR BIT(10) +#define HCINTMSK_FRMOVRUN BIT(9) +#define HCINTMSK_BBLERR BIT(8) +#define HCINTMSK_XACTERR BIT(7) +#define HCINTMSK_NYET BIT(6) +#define HCINTMSK_ACK BIT(5) +#define HCINTMSK_NAK BIT(4) +#define HCINTMSK_STALL BIT(3) +#define HCINTMSK_AHBERR BIT(2) +#define HCINTMSK_CHHLTD BIT(1) +#define HCINTMSK_XFERCOMPL BIT(0) + +#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch)) +#define TSIZ_DOPNG BIT(31) +#define TSIZ_SC_MC_PID_MASK (0x3 << 29) +#define TSIZ_SC_MC_PID_SHIFT 29 +#define TSIZ_SC_MC_PID_DATA0 0 +#define TSIZ_SC_MC_PID_DATA2 1 +#define TSIZ_SC_MC_PID_DATA1 2 +#define TSIZ_SC_MC_PID_MDATA 3 +#define TSIZ_SC_MC_PID_SETUP 3 +#define TSIZ_PKTCNT_MASK (0x3ff << 19) +#define TSIZ_PKTCNT_SHIFT 19 +#define TSIZ_NTD_MASK (0xff << 8) +#define TSIZ_NTD_SHIFT 8 +#define TSIZ_SCHINFO_MASK (0xff << 0) +#define TSIZ_SCHINFO_SHIFT 0 +#define TSIZ_XFERSIZE_MASK (0x7ffff << 0) +#define TSIZ_XFERSIZE_SHIFT 0 + +#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch)) + +#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch)) + +#define HCFIFO(_ch) HSOTG_REG(0x1000 + 0x1000 * (_ch)) /** * struct dwc2_dma_desc - DMA descriptor structure, @@ -836,64 +836,64 @@ * Status quadlet and Data buffer pointer. */ struct dwc2_dma_desc { - uint32_t status; - uint32_t buf; + uint32_t status; + uint32_t buf; } __packed; /* Host Mode DMA descriptor status quadlet */ -#define HOST_DMA_A BIT(31) -#define HOST_DMA_STS_MASK (0x3 << 28) -#define HOST_DMA_STS_SHIFT 28 -#define HOST_DMA_STS_PKTERR BIT(28) -#define HOST_DMA_EOL BIT(26) -#define HOST_DMA_IOC BIT(25) -#define HOST_DMA_SUP BIT(24) -#define HOST_DMA_ALT_QTD BIT(23) -#define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17) -#define HOST_DMA_QTD_OFFSET_SHIFT 17 -#define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0) -#define HOST_DMA_ISOC_NBYTES_SHIFT 0 -#define HOST_DMA_NBYTES_MASK (0x1ffff << 0) -#define HOST_DMA_NBYTES_SHIFT 0 -#define HOST_DMA_NBYTES_LIMIT 131071 +#define HOST_DMA_A BIT(31) +#define HOST_DMA_STS_MASK (0x3 << 28) +#define HOST_DMA_STS_SHIFT 28 +#define HOST_DMA_STS_PKTERR BIT(28) +#define HOST_DMA_EOL BIT(26) +#define HOST_DMA_IOC BIT(25) +#define HOST_DMA_SUP BIT(24) +#define HOST_DMA_ALT_QTD BIT(23) +#define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17) +#define HOST_DMA_QTD_OFFSET_SHIFT 17 +#define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0) +#define HOST_DMA_ISOC_NBYTES_SHIFT 0 +#define HOST_DMA_NBYTES_MASK (0x1ffff << 0) +#define HOST_DMA_NBYTES_SHIFT 0 +#define HOST_DMA_NBYTES_LIMIT 131071 /* Device Mode DMA descriptor status quadlet */ -#define DEV_DMA_BUFF_STS_MASK (0x3 << 30) -#define DEV_DMA_BUFF_STS_SHIFT 30 -#define DEV_DMA_BUFF_STS_HREADY 0 -#define DEV_DMA_BUFF_STS_DMABUSY 1 -#define DEV_DMA_BUFF_STS_DMADONE 2 -#define DEV_DMA_BUFF_STS_HBUSY 3 -#define DEV_DMA_STS_MASK (0x3 << 28) -#define DEV_DMA_STS_SHIFT 28 -#define DEV_DMA_STS_SUCC 0 -#define DEV_DMA_STS_BUFF_FLUSH 1 -#define DEV_DMA_STS_BUFF_ERR 3 -#define DEV_DMA_L BIT(27) -#define DEV_DMA_SHORT BIT(26) -#define DEV_DMA_IOC BIT(25) -#define DEV_DMA_SR BIT(24) -#define DEV_DMA_MTRF BIT(23) -#define DEV_DMA_ISOC_PID_MASK (0x3 << 23) -#define DEV_DMA_ISOC_PID_SHIFT 23 -#define DEV_DMA_ISOC_PID_DATA0 0 -#define DEV_DMA_ISOC_PID_DATA2 1 -#define DEV_DMA_ISOC_PID_DATA1 2 -#define DEV_DMA_ISOC_PID_MDATA 3 -#define DEV_DMA_ISOC_FRNUM_MASK (0x7ff << 12) -#define DEV_DMA_ISOC_FRNUM_SHIFT 12 -#define DEV_DMA_ISOC_TX_NBYTES_MASK (0xfff << 0) -#define DEV_DMA_ISOC_TX_NBYTES_LIMIT 0xfff -#define DEV_DMA_ISOC_RX_NBYTES_MASK (0x7ff << 0) -#define DEV_DMA_ISOC_RX_NBYTES_LIMIT 0x7ff -#define DEV_DMA_ISOC_NBYTES_SHIFT 0 -#define DEV_DMA_NBYTES_MASK (0xffff << 0) -#define DEV_DMA_NBYTES_SHIFT 0 -#define DEV_DMA_NBYTES_LIMIT 0xffff - -#define MAX_DMA_DESC_NUM_GENERIC 64 -#define MAX_DMA_DESC_NUM_HS_ISOC 256 - -#endif /* __DWC2_HW_H__ */ +#define DEV_DMA_BUFF_STS_MASK (0x3 << 30) +#define DEV_DMA_BUFF_STS_SHIFT 30 +#define DEV_DMA_BUFF_STS_HREADY 0 +#define DEV_DMA_BUFF_STS_DMABUSY 1 +#define DEV_DMA_BUFF_STS_DMADONE 2 +#define DEV_DMA_BUFF_STS_HBUSY 3 +#define DEV_DMA_STS_MASK (0x3 << 28) +#define DEV_DMA_STS_SHIFT 28 +#define DEV_DMA_STS_SUCC 0 +#define DEV_DMA_STS_BUFF_FLUSH 1 +#define DEV_DMA_STS_BUFF_ERR 3 +#define DEV_DMA_L BIT(27) +#define DEV_DMA_SHORT BIT(26) +#define DEV_DMA_IOC BIT(25) +#define DEV_DMA_SR BIT(24) +#define DEV_DMA_MTRF BIT(23) +#define DEV_DMA_ISOC_PID_MASK (0x3 << 23) +#define DEV_DMA_ISOC_PID_SHIFT 23 +#define DEV_DMA_ISOC_PID_DATA0 0 +#define DEV_DMA_ISOC_PID_DATA2 1 +#define DEV_DMA_ISOC_PID_DATA1 2 +#define DEV_DMA_ISOC_PID_MDATA 3 +#define DEV_DMA_ISOC_FRNUM_MASK (0x7ff << 12) +#define DEV_DMA_ISOC_FRNUM_SHIFT 12 +#define DEV_DMA_ISOC_TX_NBYTES_MASK (0xfff << 0) +#define DEV_DMA_ISOC_TX_NBYTES_LIMIT 0xfff +#define DEV_DMA_ISOC_RX_NBYTES_MASK (0x7ff << 0) +#define DEV_DMA_ISOC_RX_NBYTES_LIMIT 0x7ff +#define DEV_DMA_ISOC_NBYTES_SHIFT 0 +#define DEV_DMA_NBYTES_MASK (0xffff << 0) +#define DEV_DMA_NBYTES_SHIFT 0 +#define DEV_DMA_NBYTES_LIMIT 0xffff + +#define MAX_DMA_DESC_NUM_GENERIC 64 +#define MAX_DMA_DESC_NUM_HS_ISOC 256 + +#endif /* DWC2_REGS_H */ diff --git a/include/hw/usb/hcd-dwc3.h b/include/hw/usb/hcd-dwc3.h index 7c804d536d51..f752a27e9404 100644 --- a/include/hw/usb/hcd-dwc3.h +++ b/include/hw/usb/hcd-dwc3.h @@ -26,6 +26,7 @@ #ifndef HCD_DWC3_H #define HCD_DWC3_H +#include "hw/register.h" #include "hw/usb/hcd-xhci.h" #include "hw/usb/hcd-xhci-sysbus.h" diff --git a/include/hw/usb/hcd-musb.h b/include/hw/usb/hcd-musb.h index c874b9f292f9..4d4b1ec0fc2a 100644 --- a/include/hw/usb/hcd-musb.h +++ b/include/hw/usb/hcd-musb.h @@ -10,8 +10,10 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_USB_MUSB_H -#define HW_USB_MUSB_H +#ifndef HW_USB_HCD_MUSB_H +#define HW_USB_HCD_MUSB_H + +#include "exec/hwaddr.h" enum musb_irq_source_e { musb_irq_suspend = 0, diff --git a/include/hw/usb/msd.h b/include/hw/usb/msd.h index 54e9f38bda46..f9fd862b529a 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/usb/xlnx-usb-subsystem.h b/include/hw/usb/xlnx-usb-subsystem.h index 999e423951ac..40f9e97e093c 100644 --- a/include/hw/usb/xlnx-usb-subsystem.h +++ b/include/hw/usb/xlnx-usb-subsystem.h @@ -22,9 +22,11 @@ * THE SOFTWARE. */ -#ifndef XLNX_VERSAL_USB_SUBSYSTEM_H -#define XLNX_VERSAL_USB_SUBSYSTEM_H +#ifndef XLNX_USB_SUBSYSTEM_H +#define XLNX_USB_SUBSYSTEM_H +#include "hw/register.h" +#include "hw/sysbus.h" #include "hw/usb/xlnx-versal-usb2-ctrl-regs.h" #include "hw/usb/hcd-dwc3.h" diff --git a/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h b/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h index b76dce041957..6a502006b079 100644 --- a/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h +++ b/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h @@ -23,8 +23,11 @@ * THE SOFTWARE. */ -#ifndef XLNX_USB2_REGS_H -#define XLNX_USB2_REGS_H +#ifndef XLNX_VERSAL_USB2_CTRL_REGS_H +#define XLNX_VERSAL_USB2_CTRL_REGS_H + +#include "hw/register.h" +#include "hw/sysbus.h" #define TYPE_XILINX_VERSAL_USB2_CTRL_REGS "xlnx.versal-usb2-ctrl-regs" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 8af11b0a7692..e573f5a9f19f 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -98,7 +98,7 @@ typedef struct VFIOContainer { typedef struct VFIOGuestIOMMU { VFIOContainer *container; - IOMMUMemoryRegion *iommu; + IOMMUMemoryRegion *iommu_mr; hwaddr iommu_offset; IOMMUNotifier n; QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; diff --git a/include/hw/virtio/vdpa-dev.h b/include/hw/virtio/vdpa-dev.h new file mode 100644 index 000000000000..4dbf98195c4c --- /dev/null +++ b/include/hw/virtio/vdpa-dev.h @@ -0,0 +1,43 @@ +/* + * Vhost Vdpa Device + * + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved. + * + * Authors: + * Longpeng + * + * Largely based on the "vhost-user-blk.h" implemented by: + * Changpeng Liu + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef _VHOST_VDPA_DEVICE_H +#define _VHOST_VDPA_DEVICE_H + +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-vdpa.h" +#include "qom/object.h" + + +#define TYPE_VHOST_VDPA_DEVICE "vhost-vdpa-device" +OBJECT_DECLARE_SIMPLE_TYPE(VhostVdpaDevice, VHOST_VDPA_DEVICE) + +struct VhostVdpaDevice { + VirtIODevice parent_obj; + char *vhostdev; + int vhostfd; + int32_t bootindex; + uint32_t vdev_id; + uint32_t num_queues; + struct vhost_dev dev; + struct vhost_vdpa vdpa; + VirtQueue **virtqs; + uint8_t *config; + int config_size; + uint16_t queue_size; + bool started; + int (*post_init)(VhostVdpaDevice *v, Error **errp); +}; + +#endif diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 81bf3109f837..c5ab49051ea6 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -69,6 +69,8 @@ typedef int (*vhost_set_vring_kick_op)(struct vhost_dev *dev, struct vhost_vring_file *file); typedef int (*vhost_set_vring_call_op)(struct vhost_dev *dev, struct vhost_vring_file *file); +typedef int (*vhost_set_vring_err_op)(struct vhost_dev *dev, + struct vhost_vring_file *file); typedef int (*vhost_set_vring_busyloop_timeout_op)(struct vhost_dev *dev, struct vhost_vring_state *r); typedef int (*vhost_set_features_op)(struct vhost_dev *dev, @@ -126,6 +128,8 @@ typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); +typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, + int fd); typedef struct VhostOps { VhostBackendType backend_type; vhost_backend_init vhost_backend_init; @@ -145,6 +149,7 @@ typedef struct VhostOps { vhost_get_vring_base_op vhost_get_vring_base; vhost_set_vring_kick_op vhost_set_vring_kick; vhost_set_vring_call_op vhost_set_vring_call; + vhost_set_vring_err_op vhost_set_vring_err; vhost_set_vring_busyloop_timeout_op vhost_set_vring_busyloop_timeout; vhost_set_features_op vhost_set_features; vhost_get_features_op vhost_get_features; @@ -171,6 +176,7 @@ typedef struct VhostOps { vhost_vq_get_addr_op vhost_vq_get_addr; vhost_get_device_id_op vhost_get_device_id; vhost_force_iommu_op vhost_force_iommu; + vhost_set_config_call_op vhost_set_config_call; } VhostOps; int vhost_backend_update_device_iotlb(struct vhost_dev *dev, diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h index 7c91f15040eb..ea085ee1ed9b 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-fs.h b/include/hw/virtio/vhost-user-fs.h index 0d62834c2510..94c3aaa84edf 100644 --- a/include/hw/virtio/vhost-user-fs.h +++ b/include/hw/virtio/vhost-user-fs.h @@ -11,8 +11,8 @@ * top-level directory. */ -#ifndef _QEMU_VHOST_USER_FS_H -#define _QEMU_VHOST_USER_FS_H +#ifndef QEMU_VHOST_USER_FS_H +#define QEMU_VHOST_USER_FS_H #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" @@ -44,4 +44,4 @@ struct VHostUserFS { /*< public >*/ }; -#endif /* _QEMU_VHOST_USER_FS_H */ +#endif /* QEMU_VHOST_USER_FS_H */ diff --git a/include/hw/virtio/vhost-user-gpio.h b/include/hw/virtio/vhost-user-gpio.h new file mode 100644 index 000000000000..a9305c5e6ccb --- /dev/null +++ b/include/hw/virtio/vhost-user-gpio.h @@ -0,0 +1,45 @@ +/* + * 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; + /** + * There are at least two steps of initialization of the + * vhost-user device. The first is a "connect" step and + * second is a "start" step. Make a separation between + * those initialization phases by using two fields. + * + * @connected: see vu_gpio_connect()/vu_gpio_disconnect() + * @started_vu: see vu_gpio_start()/vu_gpio_stop() + */ + bool connected; + bool started_vu; + /*< public >*/ +}; + +#endif /* _QEMU_VHOST_USER_GPIO_H */ diff --git a/include/hw/virtio/vhost-user-i2c.h b/include/hw/virtio/vhost-user-i2c.h index d8372f3b43ea..0f7acd40e3ad 100644 --- a/include/hw/virtio/vhost-user-i2c.h +++ b/include/hw/virtio/vhost-user-i2c.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _QEMU_VHOST_USER_I2C_H -#define _QEMU_VHOST_USER_I2C_H +#ifndef QEMU_VHOST_USER_I2C_H +#define QEMU_VHOST_USER_I2C_H #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" @@ -28,4 +28,4 @@ struct VHostUserI2C { /* Virtio Feature bits */ #define VIRTIO_I2C_F_ZERO_LENGTH_REQUEST 0 -#endif /* _QEMU_VHOST_USER_I2C_H */ +#endif /* QEMU_VHOST_USER_I2C_H */ diff --git a/include/hw/virtio/vhost-user-rng.h b/include/hw/virtio/vhost-user-rng.h index 071539996d1d..ddd9f01eea61 100644 --- a/include/hw/virtio/vhost-user-rng.h +++ b/include/hw/virtio/vhost-user-rng.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _QEMU_VHOST_USER_RNG_H -#define _QEMU_VHOST_USER_RNG_H +#ifndef QEMU_VHOST_USER_RNG_H +#define QEMU_VHOST_USER_RNG_H #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" @@ -30,4 +30,4 @@ struct VHostUserRNG { /*< public >*/ }; -#endif /* _QEMU_VHOST_USER_RNG_H */ +#endif /* QEMU_VHOST_USER_RNG_H */ diff --git a/include/hw/virtio/vhost-user-vsock.h b/include/hw/virtio/vhost-user-vsock.h index 4cfd55824550..67aa46c95273 100644 --- a/include/hw/virtio/vhost-user-vsock.h +++ b/include/hw/virtio/vhost-user-vsock.h @@ -8,8 +8,8 @@ * top-level directory. */ -#ifndef _QEMU_VHOST_USER_VSOCK_H -#define _QEMU_VHOST_USER_VSOCK_H +#ifndef QEMU_VHOST_USER_VSOCK_H +#define QEMU_VHOST_USER_VSOCK_H #include "hw/virtio/vhost-vsock-common.h" #include "hw/virtio/vhost-user.h" @@ -33,4 +33,4 @@ struct VHostUserVSock { /*< public >*/ }; -#endif /* _QEMU_VHOST_USER_VSOCK_H */ +#endif /* QEMU_VHOST_USER_VSOCK_H */ diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index e44a41bb70d6..191216a74f80 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -11,20 +11,79 @@ #include "chardev/char-fe.h" #include "hw/virtio/virtio.h" +/** + * VhostUserHostNotifier - notifier information for one queue + * @rcu: rcu_head for cleanup + * @mr: memory region of notifier + * @addr: current mapped address + * @unmap_addr: address to be un-mapped + * @idx: virtioqueue index + * + * The VhostUserHostNotifier entries are re-used. When an old mapping + * is to be released it is moved to @unmap_addr and @addr is replaced. + * Once the RCU process has completed the unmap @unmap_addr is + * cleared. + */ typedef struct VhostUserHostNotifier { struct rcu_head rcu; MemoryRegion mr; void *addr; void *unmap_addr; + int idx; } VhostUserHostNotifier; +/** + * VhostUserState - shared state for all vhost-user devices + * @chr: the character backend for the socket + * @notifiers: GPtrArray of @VhostUserHostnotifier + * @memory_slots: + */ typedef struct VhostUserState { CharBackend *chr; - VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; + GPtrArray *notifiers; int memory_slots; + bool supports_config; } VhostUserState; +/** + * vhost_user_init() - initialise shared vhost_user state + * @user: allocated area for storing shared state + * @chr: the chardev for the vhost socket + * @errp: error handle + * + * User can either directly g_new() space for the state or embed + * VhostUserState in their larger device structure and just point to + * it. + * + * Return: true on success, false on error while setting errp. + */ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp); + +/** + * vhost_user_cleanup() - cleanup state + * @user: ptr to use state + * + * Cleans up shared state and notifiers, callee is responsible for + * freeing the @VhostUserState memory itself. + */ void vhost_user_cleanup(VhostUserState *user); +/** + * vhost_user_async_close() - cleanup vhost-user post connection drop + * @d: DeviceState for the associated device (passed to callback) + * @chardev: the CharBackend associated with the connection + * @vhost: the common vhost device + * @cb: the user callback function to complete the clean-up + * + * This function is used to handle the shutdown of a vhost-user + * connection to a backend. We handle this centrally to make sure we + * do all the steps and handle potential races due to VM shutdowns. + * Once the connection is disabled we call a backhalf to ensure + */ +typedef void (*vu_async_close_fn)(DeviceState *cb); + +void vhost_user_async_close(DeviceState *d, + CharBackend *chardev, struct vhost_dev *vhost, + vu_async_close_fn cb); + #endif diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h index a29dbb3f537a..7997f09a8df5 100644 --- a/include/hw/virtio/vhost-vdpa.h +++ b/include/hw/virtio/vhost-vdpa.h @@ -15,9 +15,16 @@ #include #include "hw/virtio/vhost-iova-tree.h" +#include "hw/virtio/vhost-shadow-virtqueue.h" #include "hw/virtio/virtio.h" #include "standard-headers/linux/vhost_types.h" +/* + * ASID dedicated to map guest's addresses. If SVQ is disabled it maps GPA to + * qemu's IOVA. If SVQ is enabled it maps also the SVQ vring here + */ +#define VHOST_VDPA_GUEST_PA_ASID 0 + typedef struct VhostVDPAHostNotifier { MemoryRegion mr; void *addr; @@ -28,15 +35,27 @@ typedef struct vhost_vdpa { int index; uint32_t msg_type; bool iotlb_batch_begin_sent; + uint32_t address_space_id; MemoryListener listener; struct vhost_vdpa_iova_range iova_range; uint64_t acked_features; bool shadow_vqs_enabled; + /* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */ + bool shadow_data; /* IOVA mapping used by the Shadow Virtqueue */ VhostIOVATree *iova_tree; GPtrArray *shadow_vqs; + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; struct vhost_dev *dev; VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; } VhostVDPA; +int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range); + +int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, + hwaddr size, void *vaddr, bool readonly); +int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, + hwaddr size); + #endif diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h index d8b565b4dac8..93c782101dd3 100644 --- a/include/hw/virtio/vhost-vsock-common.h +++ b/include/hw/virtio/vhost-vsock-common.h @@ -8,8 +8,8 @@ * top-level directory. */ -#ifndef _QEMU_VHOST_VSOCK_COMMON_H -#define _QEMU_VHOST_VSOCK_COMMON_H +#ifndef QEMU_VHOST_VSOCK_COMMON_H +#define QEMU_VHOST_VSOCK_COMMON_H #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" @@ -44,9 +44,9 @@ int vhost_vsock_common_start(VirtIODevice *vdev); void vhost_vsock_common_stop(VirtIODevice *vdev); int vhost_vsock_common_pre_save(void *opaque); int vhost_vsock_common_post_load(void *opaque, int version_id); -void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name); +void vhost_vsock_common_realize(VirtIODevice *vdev); void vhost_vsock_common_unrealize(VirtIODevice *vdev); uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features, Error **errp); -#endif /* _QEMU_VHOST_VSOCK_COMMON_H */ +#endif /* QEMU_VHOST_VSOCK_COMMON_H */ diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 58a73e7b7a19..a52f273347c9 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 { @@ -29,6 +32,8 @@ struct vhost_virtqueue { unsigned long long used_phys; unsigned used_size; EventNotifier masked_notifier; + EventNotifier error_notifier; + EventNotifier masked_config_notifier; struct vhost_dev *dev; }; @@ -37,6 +42,7 @@ typedef unsigned long vhost_log_chunk_t; #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) #define VHOST_INVALID_FEATURE_BIT (0xff) +#define VHOST_QUEUE_NUM_CONFIG_INR 0 struct vhost_log { unsigned long long size; @@ -61,6 +67,12 @@ typedef struct VhostDevConfigOps { } VhostDevConfigOps; struct vhost_memory; + +/** + * struct vhost_dev - common vhost_dev structure + * @vhost_ops: backend specific ops + * @config_ops: ops for config changes (see @vhost_dev_set_config_notifier) + */ struct vhost_dev { VirtIODevice *vdev; MemoryListener memory_listener; @@ -78,12 +90,35 @@ struct vhost_dev { int vq_index_end; /* if non-zero, minimum required value for max_queues */ int num_queues; + /** + * vhost feature handling requires matching the feature set + * offered by a backend which may be a subset of the total + * features eventually offered to the guest. + * + * @features: available features provided by the backend + * @acked_features: final negotiated features with front-end driver + * + * @backend_features: this is used in a couple of places to either + * store VHOST_USER_F_PROTOCOL_FEATURES to apply to + * VHOST_USER_SET_FEATURES or VHOST_NET_F_VIRTIO_NET_HDR. Its + * future use should be discouraged and the variable retired as + * its easy to confuse with the VirtIO backend_features. + */ uint64_t features; uint64_t acked_features; uint64_t backend_features; + + /** + * @protocol_features: is the vhost-user only feature set by + * VHOST_USER_SET_PROTOCOL_FEATURES. Protocol features are only + * negotiated if VHOST_USER_F_PROTOCOL_FEATURES has been offered + * by the backend (see @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; @@ -108,14 +143,143 @@ struct vhost_net { NetClientState *nc; }; +/** + * vhost_dev_init() - initialise the vhost interface + * @hdev: the common vhost_dev structure + * @opaque: opaque ptr passed to backend (vhost/vhost-user/vdpa) + * @backend_type: type of backend + * @busyloop_timeout: timeout for polling virtqueue + * @errp: error handle + * + * The initialisation of the vhost device will trigger the + * initialisation of the backend and potentially capability + * negotiation of backend interface. Configuration of the VirtIO + * itself won't happen until the interface is started. + * + * Return: 0 on success, non-zero on error while setting errp. + */ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, VhostBackendType backend_type, uint32_t busyloop_timeout, Error **errp); + +/** + * vhost_dev_cleanup() - tear down and cleanup vhost interface + * @hdev: the common vhost_dev structure + */ void vhost_dev_cleanup(struct vhost_dev *hdev); -int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); -void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + +/** + * vhost_dev_enable_notifiers() - enable event notifiers + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * + * Enable notifications directly to the vhost device rather than being + * triggered by QEMU itself. Notifications should be enabled before + * the vhost device is started via @vhost_dev_start. + * + * Return: 0 on success, < 0 on error. + */ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + +/** + * vhost_dev_disable_notifiers - disable event notifications + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * + * Disable direct notifications to vhost device. + */ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +bool vhost_config_pending(struct vhost_dev *hdev); +void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + +/** + * 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 + * @vdev: the VirtIODevice structure + * @vrings: true to have vrings enabled in this call + * + * Starts the vhost device. From this point VirtIO feature negotiation + * can start and the device can start processing VirtIO transactions. + * + * Return: 0 on success, < 0 on error. + */ +int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); + +/** + * vhost_dev_stop() - stop the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * @vrings: true to have vrings disabled in this call + * + * Stop the vhost device. After the device is stopped the notifiers + * can be disabled (@vhost_dev_disable_notifiers) and the device can + * be torn down (@vhost_dev_cleanup). + */ +void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); + +/** + * DOC: vhost device configuration handling + * + * The VirtIO device configuration space is used for rarely changing + * or initialisation time parameters. The configuration can be updated + * by either the guest driver or the device itself. If the device can + * change the configuration over time the vhost handler should + * register a @VhostDevConfigOps structure with + * @vhost_dev_set_config_notifier so the guest can be notified. Some + * devices register a handler anyway and will signal an error if an + * unexpected config change happens. + */ + +/** + * vhost_dev_get_config() - fetch device configuration + * @hdev: common vhost_dev_structure + * @config: pointer to device appropriate config structure + * @config_len: size of device appropriate config structure + * + * Return: 0 on success, < 0 on error while setting errp + */ +int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, + uint32_t config_len, Error **errp); + +/** + * vhost_dev_set_config() - set device configuration + * @hdev: common vhost_dev_structure + * @data: pointer to data to set + * @offset: offset into configuration space + * @size: length of set + * @flags: @VhostSetConfigType flags + * + * By use of @offset/@size a subset of the configuration space can be + * written to. The @flags are used to indicate if it is a normal + * transaction or related to migration. + * + * Return: 0 on success, non-zero on error + */ +int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags); + +/** + * vhost_dev_set_config_notifier() - register VhostDevConfigOps + * @hdev: common vhost_dev_structure + * @ops: notifier ops + * + * If the device is expected to change configuration a notifier can be + * setup to handle the case. + */ +void vhost_dev_set_config_notifier(struct vhost_dev *dev, + const VhostDevConfigOps *ops); + /* Test and clear masked event pending status. * Should be called after unmask to avoid losing events. @@ -126,8 +290,29 @@ bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n); */ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, bool mask); + +/** + * vhost_get_features() - return a sanitised set of feature bits + * @hdev: common vhost_dev structure + * @feature_bits: pointer to terminated table of feature bits + * @features: original feature set + * + * This returns a set of features bits that is an intersection of what + * is supported by the vhost backend (hdev->features), the supported + * feature_bits and the requested feature set. + */ uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, uint64_t features); + +/** + * vhost_ack_features() - set vhost acked_features + * @hdev: common vhost_dev structure + * @feature_bits: pointer to terminated table of feature bits + * @features: requested feature set + * + * This sets the internal hdev->acked_features to the intersection of + * the backends advertised features and the supported feature_bits. + */ void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, uint64_t features); bool vhost_has_free_slot(void); @@ -136,14 +321,11 @@ int vhost_net_set_backend(struct vhost_dev *hdev, struct vhost_vring_file *file); int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write); -int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, - uint32_t config_len, Error **errp); -int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, - uint32_t offset, uint32_t size, uint32_t flags); -/* notifier callback in case vhost device config space changed - */ -void vhost_dev_set_config_notifier(struct vhost_dev *dev, - const VhostDevConfigOps *ops); + +int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, unsigned idx); +void vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, unsigned idx); void vhost_dev_reset_inflight(struct vhost_inflight *inflight); void vhost_dev_free_inflight(struct vhost_inflight *inflight); diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 6818a23a2d35..07aae69042a9 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -28,7 +28,7 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) { #if defined(LEGACY_VIRTIO_IS_BIENDIAN) return virtio_is_big_endian(vdev); -#elif defined(TARGET_WORDS_BIGENDIAN) +#elif TARGET_BIG_ENDIAN if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { /* Devices conforming to VIRTIO 1.0 or later are always LE. */ return false; @@ -149,7 +149,7 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr) static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN return virtio_access_is_big_endian(vdev) ? s : bswap16(s); #else return virtio_access_is_big_endian(vdev) ? bswap16(s) : s; @@ -215,7 +215,7 @@ static inline void virtio_tswap16s(VirtIODevice *vdev, uint16_t *s) static inline uint32_t virtio_tswap32(VirtIODevice *vdev, uint32_t s) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN return virtio_access_is_big_endian(vdev) ? s : bswap32(s); #else return virtio_access_is_big_endian(vdev) ? bswap32(s) : s; @@ -229,7 +229,7 @@ static inline void virtio_tswap32s(VirtIODevice *vdev, uint32_t *s) static inline uint64_t virtio_tswap64(VirtIODevice *vdev, uint64_t s) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN return virtio_access_is_big_endian(vdev) ? s : bswap64(s); #else return virtio_access_is_big_endian(vdev) ? bswap64(s) : s; diff --git a/include/hw/virtio/virtio-blk-common.h b/include/hw/virtio/virtio-blk-common.h new file mode 100644 index 000000000000..31daada3e3e1 --- /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-blk.h b/include/hw/virtio/virtio-blk.h index d311c57cca4f..7f589b414643 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -19,6 +19,7 @@ #include "hw/block/block.h" #include "sysemu/iothread.h" #include "sysemu/block-backend.h" +#include "sysemu/block-ram-registrar.h" #include "qom/object.h" #define TYPE_VIRTIO_BLK "virtio-blk-device" @@ -64,6 +65,7 @@ struct VirtIOBlock { struct VirtIOBlockDataPlane *dataplane; uint64_t host_features; size_t config_size; + BlockRAMRegistrar blk_ram_registrar; }; typedef struct VirtIOBlockReq { diff --git a/include/hw/virtio/virtio-crypto.h b/include/hw/virtio/virtio-crypto.h index a2228d7b2eb3..348749f5d5cd 100644 --- a/include/hw/virtio/virtio-crypto.h +++ b/include/hw/virtio/virtio-crypto.h @@ -50,6 +50,7 @@ typedef struct VirtIOCryptoConf { uint32_t mac_algo_l; uint32_t mac_algo_h; uint32_t aead_algo; + uint32_t akcipher_algo; /* Maximum length of cipher key */ uint32_t max_cipher_key_len; @@ -71,9 +72,7 @@ typedef struct VirtIOCryptoReq { size_t in_len; VirtQueue *vq; struct VirtIOCrypto *vcrypto; - union { - CryptoDevBackendSymOpInfo *sym_op_info; - } u; + CryptoDevBackendOpInfo op_info; } VirtIOCryptoReq; typedef struct VirtIOCryptoQueue { diff --git a/include/hw/virtio/virtio-gpu-bswap.h b/include/hw/virtio/virtio-gpu-bswap.h index 5faac0d8d5f3..912410848597 100644 --- a/include/hw/virtio/virtio-gpu-bswap.h +++ b/include/hw/virtio/virtio-gpu-bswap.h @@ -29,7 +29,7 @@ virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) static inline void virtio_gpu_bswap_32(void *ptr, size_t size) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN size_t i; struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 2179b757037a..2e28507efe21 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -22,6 +22,7 @@ #include "sysemu/vhost-user-backend.h" #include "standard-headers/linux/virtio_gpu.h" +#include "standard-headers/linux/virtio_ids.h" #include "qom/object.h" #define TYPE_VIRTIO_GPU_BASE "virtio-gpu-base" @@ -37,8 +38,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL) #define TYPE_VHOST_USER_GPU "vhost-user-gpu" OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU) -#define VIRTIO_ID_GPU 16 - struct virtio_gpu_simple_resource { uint32_t resource_id; uint32_t width; @@ -81,6 +80,7 @@ struct virtio_gpu_scanout { struct virtio_gpu_requested_state { uint16_t width_mm, height_mm; uint32_t width, height; + uint32_t refresh_rate; int x, y; }; diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h index 84391f844826..2ad5ee320be9 100644 --- a/include/hw/virtio/virtio-iommu.h +++ b/include/hw/virtio/virtio-iommu.h @@ -37,6 +37,8 @@ typedef struct IOMMUDevice { int devfn; IOMMUMemoryRegion iommu_mr; AddressSpace as; + MemoryRegion root; /* The root container of the device */ + MemoryRegion bypass_mr; /* The alias of shared memory MR */ } IOMMUDevice; typedef struct IOMMUPciBus { @@ -56,7 +58,7 @@ struct VirtIOIOMMU { ReservedRegion *reserved_regions; uint32_t nb_reserved_regions; GTree *domains; - QemuMutex mutex; + QemuRecMutex mutex; GTree *endpoints; bool boot_bypass; }; diff --git a/include/hw/virtio/virtio-mmio.h b/include/hw/virtio/virtio-mmio.h index 090f7730e77a..aa492620228d 100644 --- a/include/hw/virtio/virtio-mmio.h +++ b/include/hw/virtio/virtio-mmio.h @@ -22,8 +22,8 @@ #ifndef HW_VIRTIO_MMIO_H #define HW_VIRTIO_MMIO_H +#include "hw/sysbus.h" #include "hw/virtio/virtio-bus.h" -#include "qom/object.h" /* QOM macros */ /* virtio-mmio-bus */ diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index eb87032627d2..ef234ffe7ef6 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -35,6 +35,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET) * and latency. */ #define TX_BURST 256 +/* Maximum VIRTIO_NET_CTRL_MAC_TABLE_SET unicast + multicast entries. */ +#define MAC_TABLE_ENTRIES 64 + typedef struct virtio_net_conf { uint32_t txtimer; @@ -218,6 +221,10 @@ struct VirtIONet { struct EBPFRSSContext ebpf_rss; }; +size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, + const struct iovec *in_sg, unsigned in_num, + const struct iovec *out_sg, + unsigned out_num); void virtio_net_set_netclient_name(VirtIONet *n, const char *name, const char *type); diff --git a/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h similarity index 93% rename from hw/virtio/virtio-pci.h rename to include/hw/virtio/virtio-pci.h index 2446dcd9aef1..ab2051b64b3b 100644 --- a/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -117,6 +117,11 @@ typedef struct VirtIOPCIRegion { typedef struct VirtIOPCIQueue { uint16_t num; bool enabled; + /* + * No need to migrate the reset status, because it is always 0 + * when the migration starts. + */ + bool reset; uint32_t desc[2]; uint32_t avail[2]; uint32_t used[2]; @@ -146,6 +151,8 @@ struct VirtIOPCIProxy { bool disable_modern; bool ignore_backend_features; OnOffAuto disable_legacy; + /* Transitional device id */ + uint16_t trans_devid; uint32_t class_code; uint32_t nvectors; uint32_t dfselect; @@ -179,6 +186,9 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) proxy->disable_modern = true; } +uint16_t virtio_pci_get_trans_devid(uint16_t device_id); +uint16_t virtio_pci_get_class_id(uint16_t device_id); + /* * virtio-input-pci: This extends VirtioPCIProxy. */ @@ -251,5 +261,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); * @fixed_queues. */ unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); - +void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, + int n, bool assign, + bool with_irqfd); #endif diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 543681bc1838..37b75e15e3e5 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -20,7 +20,6 @@ #define VIRTIO_SCSI_SENSE_SIZE 0 #include "standard-headers/linux/virtio_scsi.h" #include "hw/virtio/virtio.h" -#include "hw/pci/pci.h" #include "hw/scsi/scsi.h" #include "chardev/char-fe.h" #include "sysemu/iothread.h" @@ -55,10 +54,8 @@ struct VirtIOSCSIConf { bool seg_max_adjust; uint32_t max_sectors; uint32_t cmd_per_lun; -#ifdef CONFIG_VHOST_SCSI char *vhostfd; char *wwpn; -#endif CharBackend chardev; uint32_t boot_tpgt; IOThread *iothread; @@ -94,42 +91,6 @@ struct VirtIOSCSI { uint32_t host_features; }; -typedef struct VirtIOSCSIReq { - /* Note: - * - fields up to resp_iov are initialized by virtio_scsi_init_req; - * - fields starting at vring are zeroed by virtio_scsi_init_req. - * */ - VirtQueueElement elem; - - VirtIOSCSI *dev; - VirtQueue *vq; - QEMUSGList qsgl; - QEMUIOVector resp_iov; - - union { - /* Used for two-stage request submission */ - QTAILQ_ENTRY(VirtIOSCSIReq) next; - - /* Used for cancellation of request during TMFs */ - int remaining; - }; - - SCSIRequest *sreq; - size_t resp_size; - enum SCSIXferMode mode; - union { - VirtIOSCSICmdResp cmd; - VirtIOSCSICtrlTMFResp tmf; - VirtIOSCSICtrlANResp an; - VirtIOSCSIEvent event; - } resp; - union { - VirtIOSCSICmdReq cmd; - VirtIOSCSICtrlTMFReq tmf; - VirtIOSCSICtrlANReq an; - } req; -} VirtIOSCSIReq; - static inline void virtio_scsi_acquire(VirtIOSCSI *s) { if (s->ctx) { @@ -151,13 +112,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp); void virtio_scsi_common_unrealize(DeviceState *dev); -bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq); -bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); -bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq); -void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); -void virtio_scsi_free_req(VirtIOSCSIReq *req); -void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, - uint32_t event, uint32_t reason); void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp); int virtio_scsi_dataplane_start(VirtIODevice *s); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b31c4507f5dd..77c6c55929ff 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -23,7 +23,12 @@ #include "standard-headers/linux/virtio_ring.h" #include "qom/object.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) | \ @@ -43,8 +48,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; @@ -67,15 +78,29 @@ typedef struct VirtQueueElement #define VIRTIO_NO_VECTOR 0xffff +/* special index value used internally for config irqs */ +#define VIRTIO_CONFIG_IRQ_IDX -1 + #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, VIRTIO_DEVICE_ENDIAN_BIG, }; +/** + * struct VirtIODevice - common VirtIO structure + * @name: name of the device + * @status: VirtIO Device Status field + * + */ struct VirtIODevice { DeviceState parent_obj; @@ -83,9 +108,20 @@ struct VirtIODevice uint8_t status; uint8_t isr; uint16_t queue_sel; - uint64_t guest_features; + /** + * These fields represent a set of VirtIO features at various + * levels of the stack. @host_features indicates the complete + * feature set the VirtIO device can offer to the driver. + * @guest_features indicates which features the VirtIO driver has + * selected by writing to the feature register. Finally + * @backend_features represents everything supported by the + * backend (e.g. vhost) and could potentially be a subset of the + * total feature set offered by QEMU. + */ uint64_t host_features; + uint64_t guest_features; uint64_t backend_features; + size_t config_len; void *config; uint16_t config_vector; @@ -94,20 +130,31 @@ 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 */ bool disabled; /* device in temporarily disabled state */ + /** + * @use_started: true if the @started flag should be used to check the + * current state of the VirtIO device. Otherwise status bits + * should be checked for a current status of the device. + * @use_started is only set via QMP and defaults to true for all + * modern machines (since 4.1). + */ bool use_started; bool started; bool start_on_kick; /* when virtio 1.0 feature has not been negotiated */ bool disable_legacy_check; + bool vhost_started; VMChangeStateEntry *vmstate; char *bus_name; uint8_t device_endian; bool use_guest_notifier_mask; AddressSpace *dma_as; QLIST_HEAD(, VirtQueue) *vector_queues; + QTAILQ_ENTRY(VirtIODevice) next; + EventNotifier config_notifier; }; struct VirtioDeviceClass { @@ -128,6 +175,10 @@ struct VirtioDeviceClass { void (*set_config)(VirtIODevice *vdev, const uint8_t *config); void (*reset)(VirtIODevice *vdev); void (*set_status)(VirtIODevice *vdev, uint8_t val); + /* Device must validate queue_index. */ + void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index); + /* Device must validate queue_index. */ + void (*queue_enable)(VirtIODevice *vdev, uint32_t queue_index); /* For transitional devices, this is a bitmap of features * that are only exposed on the legacy interface but not * the modern one. @@ -160,13 +211,14 @@ struct VirtioDeviceClass { int (*post_load)(VirtIODevice *vdev); const VMStateDescription *vmsd; bool (*primary_unplug_pending)(void *opaque); + struct vhost_dev *(*get_vhost)(VirtIODevice *vdev); }; void virtio_instance_init_common(Object *proxy_obj, void *data, size_t vdev_size, const char *vdev_name); -void virtio_init(VirtIODevice *vdev, const char *name, - uint16_t device_id, size_t config_size); +void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size); + void virtio_cleanup(VirtIODevice *vdev); void virtio_error(VirtIODevice *vdev, const char *fmt, ...) G_GNUC_PRINTF(2, 3); @@ -265,6 +317,8 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n, MemoryRegion *mr, bool assign); int virtio_set_status(VirtIODevice *vdev, uint8_t val); void virtio_reset(void *opaque); +void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index); +void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index); void virtio_update_irq(VirtIODevice *vdev); int virtio_set_features(VirtIODevice *vdev, uint64_t val); @@ -288,7 +342,9 @@ typedef struct VirtIORNGConf VirtIORNGConf; DEFINE_PROP_BIT64("iommu_platform", _state, _field, \ VIRTIO_F_IOMMU_PLATFORM, false), \ DEFINE_PROP_BIT64("packed", _state, _field, \ - VIRTIO_F_RING_PACKED, false) + VIRTIO_F_RING_PACKED, false), \ + DEFINE_PROP_BIT64("queue_reset", _state, _field, \ + VIRTIO_F_RING_RESET, true) hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n); @@ -317,9 +373,13 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); void virtio_queue_host_notifier_read(EventNotifier *n); void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx); +void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx); void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx); VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); VirtQueue *virtio_vector_next_queue(VirtQueue *vq); +EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); +void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, + bool assign, bool with_irqfd); static inline void virtio_add_feature(uint64_t *features, unsigned int fbit) { @@ -361,6 +421,16 @@ static inline bool virtio_is_big_endian(VirtIODevice *vdev) return false; } +/** + * virtio_device_started() - check if device started + * @vdev - the VirtIO device + * @status - the devices status bits + * + * Check if the device is started. For most modern machines this is + * tracked via the @vdev->started field (to support migration), + * otherwise we check for the final negotiated status bit that + * indicates everything is ready. + */ static inline bool virtio_device_started(VirtIODevice *vdev, uint8_t status) { if (vdev->use_started) { @@ -370,6 +440,24 @@ static inline bool virtio_device_started(VirtIODevice *vdev, uint8_t status) return status & VIRTIO_CONFIG_S_DRIVER_OK; } +/** + * virtio_device_should_start() - check if device startable + * @vdev - the VirtIO device + * @status - the devices status bits + * + * This is similar to virtio_device_started() but also encapsulates a + * check on the VM status which would prevent a device starting + * anyway. + */ +static inline bool virtio_device_should_start(VirtIODevice *vdev, uint8_t status) +{ + if (!vdev->vm_running) { + return false; + } + + return virtio_device_started(vdev, status); +} + static inline void virtio_set_started(VirtIODevice *vdev, bool started) { if (started) { diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index f945cd6c5833..dfa5dfa424a3 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -19,6 +19,7 @@ OBJECT_DECLARE_TYPE(AspeedWDTState, AspeedWDTClass, ASPEED_WDT) #define TYPE_ASPEED_2400_WDT TYPE_ASPEED_WDT "-ast2400" #define TYPE_ASPEED_2500_WDT TYPE_ASPEED_WDT "-ast2500" #define TYPE_ASPEED_2600_WDT TYPE_ASPEED_WDT "-ast2600" +#define TYPE_ASPEED_1030_WDT TYPE_ASPEED_WDT "-ast1030" #define ASPEED_WDT_REGS_MAX (0x20 / 4) @@ -45,6 +46,8 @@ struct AspeedWDTClass { void (*reset_pulse)(AspeedWDTState *s, uint32_t property); void (*wdt_reload)(AspeedWDTState *s); uint64_t (*sanitize_ctrl)(uint64_t data); + uint32_t default_status; + uint32_t default_reload_value; }; #endif /* WDT_ASPEED_H */ diff --git a/include/hw/watchdog/wdt_imx2.h b/include/hw/watchdog/wdt_imx2.h index 023d83f48f6d..600a552d2e22 100644 --- a/include/hw/watchdog/wdt_imx2.h +++ b/include/hw/watchdog/wdt_imx2.h @@ -9,8 +9,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef IMX2_WDT_H -#define IMX2_WDT_H +#ifndef WDT_IMX2_H +#define WDT_IMX2_H #include "qemu/bitops.h" #include "hw/sysbus.h" @@ -88,4 +88,4 @@ struct IMX2WdtState { bool wcr_wdt_locked; /* affects WDT (never cleared) */ }; -#endif /* IMX2_WDT_H */ +#endif /* WDT_IMX2_H */ diff --git a/include/hw/xen/xen-bus-helper.h b/include/hw/xen/xen-bus-helper.h index 629a904d1a86..8782f3055086 100644 --- a/include/hw/xen/xen-bus-helper.h +++ b/include/hw/xen/xen-bus-helper.h @@ -31,10 +31,12 @@ void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid, /* Read from node/key unless node is empty, in which case read from key */ int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid, const char *node, const char *key, Error **errp, - const char *fmt, va_list ap); + const char *fmt, va_list ap) + G_GNUC_SCANF(6, 0); int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid, const char *node, const char *key, Error **errp, - const char *fmt, ...); + const char *fmt, ...) + G_GNUC_SCANF(6, 7); /* Watch node/key unless node is empty, in which case watch key */ void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key, diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 713e763348f4..4d966a2dbbc1 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -94,7 +94,8 @@ void xen_device_frontend_printf(XenDevice *xendev, const char *key, G_GNUC_PRINTF(3, 4); int xen_device_frontend_scanf(XenDevice *xendev, const char *key, - const char *fmt, ...); + const char *fmt, ...) + G_GNUC_SCANF(3, 4); void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, Error **errp); diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 0f9962b1c190..afdf9c436afc 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -21,8 +21,8 @@ extern enum xen_mode xen_mode; extern bool xen_domid_restrict; int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); +int xen_set_pci_link_route(uint8_t link, uint8_t irq); void xen_piix3_set_irq(void *opaque, int irq_num, int level); -void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); void xen_hvm_inject_msi(uint64_t addr, uint32_t data); int xen_is_pirq_msi(uint32_t msi_data); diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 179741ff791c..9a13a756ae3e 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -15,7 +15,7 @@ #include "hw/xen/interface/io/xenbus.h" #include "hw/xen/xen.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/xen/trace.h" extern xc_interface *xen_xc; @@ -316,12 +316,6 @@ static inline int xen_set_pci_intx_level(domid_t domid, uint16_t segment, device, intx, level); } -static inline int xen_set_pci_link_route(domid_t domid, uint8_t link, - uint8_t irq) -{ - return xendevicemodel_set_pci_link_route(xen_dmod, domid, link, irq); -} - static inline int xen_inject_msi(domid_t domid, uint64_t msi_addr, uint32_t msi_data) { diff --git a/include/io/channel-command.h b/include/io/channel-command.h index 27e42bdadc71..98934e6d9eec 100644 --- a/include/io/channel-command.h +++ b/include/io/channel-command.h @@ -41,35 +41,13 @@ struct QIOChannelCommand { QIOChannel parent; int writefd; int readfd; - pid_t pid; + GPid pid; +#ifdef WIN32 + bool blocking; +#endif }; -/** - * qio_channel_command_new_pid: - * @writefd: the FD connected to the command's stdin - * @readfd: the FD connected to the command's stdout - * @pid: the PID of the running child command - * @errp: pointer to a NULL-initialized error object - * - * Create a channel for performing I/O with the - * previously spawned command identified by @pid. - * The two file descriptors provide the connection - * to command's stdio streams, either one or which - * may be -1 to indicate that stream is not open. - * - * The channel will take ownership of the process - * @pid and will kill it when closing the channel. - * Similarly it will take responsibility for - * closing the file descriptors @writefd and @readfd. - * - * Returns: the command channel object, or NULL on error - */ -QIOChannelCommand * -qio_channel_command_new_pid(int writefd, - int readfd, - pid_t pid); - /** * qio_channel_command_new_spawn: * @argv: the NULL terminated list of command arguments diff --git a/include/io/channel-null.h b/include/io/channel-null.h new file mode 100644 index 000000000000..f6d54e63cf93 --- /dev/null +++ b/include/io/channel-null.h @@ -0,0 +1,55 @@ +/* + * QEMU I/O channels null driver + * + * Copyright (c) 2022 Red Hat, Inc. + * + * 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 QIO_CHANNEL_FILE_H +#define QIO_CHANNEL_FILE_H + +#include "io/channel.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_NULL "qio-channel-null" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelNull, QIO_CHANNEL_NULL) + + +/** + * QIOChannelNull: + * + * The QIOChannelNull object provides a channel implementation + * that discards all writes and returns EOF for all reads. + */ + +struct QIOChannelNull { + QIOChannel parent; + bool closed; +}; + + +/** + * qio_channel_null_new: + * + * Create a new IO channel object that discards all writes + * and returns EOF for all reads. + * + * Returns: the new channel object + */ +QIOChannelNull * +qio_channel_null_new(void); + +#endif /* QIO_CHANNEL_NULL_H */ diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h index e747e635147e..513c428fe480 100644 --- a/include/io/channel-socket.h +++ b/include/io/channel-socket.h @@ -47,6 +47,8 @@ struct QIOChannelSocket { socklen_t localAddrLen; struct sockaddr_storage remoteAddr; socklen_t remoteAddrLen; + ssize_t zero_copy_queued; + ssize_t zero_copy_sent; }; diff --git a/include/io/channel.h b/include/io/channel.h index 88988979f88e..f1b7e05f81d6 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -32,12 +32,15 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass, #define QIO_CHANNEL_ERR_BLOCK -2 +#define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1 + typedef enum QIOChannelFeature QIOChannelFeature; enum QIOChannelFeature { QIO_CHANNEL_FEATURE_FD_PASS, QIO_CHANNEL_FEATURE_SHUTDOWN, QIO_CHANNEL_FEATURE_LISTEN, + QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY, }; @@ -104,6 +107,7 @@ struct QIOChannelClass { size_t niov, int *fds, size_t nfds, + int flags, Error **errp); ssize_t (*io_readv)(QIOChannel *ioc, const struct iovec *iov, @@ -136,6 +140,8 @@ struct QIOChannelClass { IOHandler *io_read, IOHandler *io_write, void *opaque); + int (*io_flush)(QIOChannel *ioc, + Error **errp); }; /* General I/O handling functions */ @@ -228,6 +234,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc, * @niov: the length of the @iov array * @fds: an array of file handles to send * @nfds: number of file handles in @fds + * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*) * @errp: pointer to a NULL-initialized error object * * Write data to the IO channel, reading it from the @@ -260,6 +267,7 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp); /** @@ -342,7 +350,7 @@ int qio_channel_readv_all(QIOChannel *ioc, int qio_channel_writev_all(QIOChannel *ioc, const struct iovec *iov, size_t niov, - Error **erp); + Error **errp); /** * qio_channel_readv: @@ -837,6 +845,7 @@ int qio_channel_readv_full_all(QIOChannel *ioc, * @niov: the length of the @iov array * @fds: an array of file handles to send * @nfds: number of file handles in @fds + * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*) * @errp: pointer to a NULL-initialized error object * * @@ -846,6 +855,14 @@ int qio_channel_readv_full_all(QIOChannel *ioc, * to be written, yielding from the current coroutine * if required. * + * If QIO_CHANNEL_WRITE_FLAG_ZERO_COPY is passed in flags, + * instead of waiting for all requested data to be written, + * this function will wait until it's all queued for writing. + * In this case, if the buffer gets changed between queueing and + * sending, the updated buffer will be sent. If this is not a + * desired behavior, it's suggested to call qio_channel_flush() + * before reusing the buffer. + * * Returns: 0 if all bytes were written, or -1 on error */ @@ -853,6 +870,25 @@ int qio_channel_writev_full_all(QIOChannel *ioc, const struct iovec *iov, size_t niov, int *fds, size_t nfds, - Error **errp); + int flags, Error **errp); + +/** + * qio_channel_flush: + * @ioc: the channel object + * @errp: pointer to a NULL-initialized error object + * + * Will block until every packet queued with + * qio_channel_writev_full() + QIO_CHANNEL_WRITE_FLAG_ZERO_COPY + * is sent, or return in case of any error. + * + * If not implemented, acts as a no-op, and returns 0. + * + * Returns -1 if any error is found, + * 1 if every send failed to use zero copy. + * 0 otherwise. + */ + +int qio_channel_flush(QIOChannel *ioc, + Error **errp); #endif /* QIO_CHANNEL_H */ diff --git a/include/libdecnumber/dconfig.h b/include/libdecnumber/dconfig.h index 0f7dccef1f4e..2bc0ba7f1444 100644 --- a/include/libdecnumber/dconfig.h +++ b/include/libdecnumber/dconfig.h @@ -28,7 +28,7 @@ 02110-1301, USA. */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define WORDS_BIGENDIAN 1 #else #define WORDS_BIGENDIAN 0 diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 96d014826ada..27f86399f7b2 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -15,6 +15,7 @@ #define HMP_H #include "qemu/readline.h" +#include "qemu/coroutine.h" #include "qapi/qapi-types-common.h" bool hmp_handle_error(Monitor *mon, Error *err); @@ -81,7 +82,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); void hmp_sendkey(Monitor *mon, const QDict *qdict); -void hmp_screendump(Monitor *mon, const QDict *qdict); +void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict); void hmp_chardev_change(Monitor *mon, const QDict *qdict); void hmp_chardev_remove(Monitor *mon, const QDict *qdict); @@ -95,6 +96,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); @@ -131,7 +137,12 @@ void hmp_replay_delete_break(Monitor *mon, const QDict *qdict); void hmp_replay_seek(Monitor *mon, const QDict *qdict); void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict); void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict); +void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); +void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); +void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); void hmp_human_readable_text_helper(Monitor *mon, HumanReadableText *(*qmp_handler)(Error **)); +void hmp_info_stats(Monitor *mon, const QDict *qdict); +void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict); #endif diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index cc4cc6c6adcf..1e6f4c9bd78f 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); @@ -45,8 +46,7 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque); AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, - bool has_opaque, const char *opaque, - Error **errp); + const char *opaque, Error **errp); int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags); void monitor_fdset_dup_fd_remove(int dup_fd); int64_t monitor_fdset_dup_fd_find(int dup_fd); @@ -56,4 +56,7 @@ void monitor_register_hmp(const char *name, bool info, void monitor_register_hmp_info_hrt(const char *name, HumanReadableText *(*handler)(Error **errp)); +int error_vprintf_unless_qmp(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); +int error_printf_unless_qmp(const char *fmt, ...) G_GNUC_PRINTF(1, 2); + #endif /* MONITOR_H */ diff --git a/include/monitor/stats.h b/include/monitor/stats.h new file mode 100644 index 000000000000..fcf09831542f --- /dev/null +++ b/include/monitor/stats.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef STATS_H +#define STATS_H + +#include "qapi/qapi-types-stats.h" + +typedef void StatRetrieveFunc(StatsResultList **result, StatsTarget target, + strList *names, strList *targets, Error **errp); +typedef void SchemaRetrieveFunc(StatsSchemaList **result, Error **errp); + +/* + * Register callbacks for the QMP query-stats command. + * + * @provider: stats provider checked against QMP command arguments + * @stats_fn: routine to query stats: + * @schema_fn: routine to query stat schemas: + */ +void add_stats_callbacks(StatsProvider provider, + StatRetrieveFunc *stats_fn, + SchemaRetrieveFunc *schemas_fn); + +/* + * Helper routines for adding stats entries to the results lists. + */ +void add_stats_entry(StatsResultList **, StatsProvider, const char *id, + StatsList *stats_list); +void add_stats_schema(StatsSchemaList **, StatsProvider, StatsTarget, + StatsSchemaValueList *); + +/* + * True if a string matches the filter passed to the stats_fn callabck, + * false otherwise. + * + * Note that an empty list means no filtering, i.e. all strings will + * return true. + */ +bool apply_str_list_filter(const char *string, strList *list); + +#endif /* STATS_H */ diff --git a/include/net/eth.h b/include/net/eth.h index 7767ae880ecc..6e699b0d7a4a 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -159,7 +159,7 @@ struct tcp_hdr { u_short th_dport; /* destination port */ uint32_t th_seq; /* sequence number */ uint32_t th_ack; /* acknowledgment number */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN u_char th_off : 4, /* data offset */ th_x2:4; /* (unused) */ #else diff --git a/include/net/net.h b/include/net/net.h index 523136c7acba..dc20b31e9fa4 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; @@ -171,6 +177,8 @@ ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, void qemu_purge_queued_packets(NetClientState *nc); void qemu_flush_queued_packets(NetClientState *nc); void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge); +void qemu_set_info_str(NetClientState *nc, + const char *fmt, ...) G_GNUC_PRINTF(2, 3); void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]); bool qemu_has_ufo(NetClientState *nc); bool qemu_has_vnet_hdr(NetClientState *nc); @@ -214,9 +222,11 @@ extern NICInfo nd_table[MAX_NICS]; extern const char *host_net_devices[]; /* from net.c */ -int net_client_parse(QemuOptsList *opts_list, const char *str); +bool netdev_is_modern(const char *optarg); +void netdev_parse_modern(const char *optarg); +void net_client_parse(QemuOptsList *opts_list, const char *str); void show_netdevs(void); -int net_init_clients(Error **errp); +void net_init_clients(void); void net_check_clients(void); void net_cleanup(void); void hmp_host_net_add(Monitor *mon, const QDict *qdict); diff --git a/include/net/vhost-user.h b/include/net/vhost-user.h index 5bcd8a628598..35bf61970985 100644 --- a/include/net/vhost-user.h +++ b/include/net/vhost-user.h @@ -14,5 +14,6 @@ struct vhost_net; struct vhost_net *vhost_user_get_vhost_net(NetClientState *nc); uint64_t vhost_user_get_acked_features(NetClientState *nc); +void vhost_user_save_acked_features(NetClientState *nc); #endif /* VHOST_USER_H */ diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h index 387e913e4e60..c37aba35e65e 100644 --- a/include/net/vhost_net.h +++ b/include/net/vhost_net.h @@ -39,6 +39,8 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, bool vhost_net_virtqueue_pending(VHostNetState *net, int n); void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, int idx, bool mask); +bool vhost_net_config_pending(VHostNetState *net); +void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); VHostNetState *get_vhost_net(NetClientState *nc); @@ -48,4 +50,10 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net); int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu); +void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc, + int vq_index); +int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc, + int vq_index); + +void vhost_net_save_acked_features(NetClientState *nc); #endif diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h index 2f888d10573f..0d09726939b9 100644 --- a/include/qapi/qmp/qbool.h +++ b/include/qapi/qmp/qbool.h @@ -21,6 +21,10 @@ struct QBool { bool value; }; +void qbool_unref(QBool *q); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QBool, qbool_unref) + QBool *qbool_from_bool(bool value); bool qbool_get_bool(const QBool *qb); diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index d5b5430e21a9..82e90fc07229 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -30,6 +30,10 @@ struct QDict { QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX]; }; +void qdict_unref(QDict *q); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QDict, qdict_unref) + /* Object API */ QDict *qdict_new(void); const char *qdict_entry_key(const QDictEntry *entry); @@ -64,7 +68,4 @@ const char *qdict_get_try_str(const QDict *qdict, const char *key); QDict *qdict_clone_shallow(const QDict *src); -QObject *qdict_crumple(const QDict *src, Error **errp); -void qdict_flatten(QDict *qdict); - #endif /* QDICT_H */ diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h index 596fce0c54e7..87ca83b155af 100644 --- a/include/qapi/qmp/qerror.h +++ b/include/qapi/qmp/qerror.h @@ -50,9 +50,6 @@ #define QERR_MISSING_PARAMETER \ "Parameter '%s' is missing" -#define QERR_PERMISSION_DENIED \ - "Insufficient permission to perform this operation" - #define QERR_PROPERTY_VALUE_BAD \ "Property '%s.%s' doesn't take value '%s'" diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h index 06e98ad5f498..e4e985d4356d 100644 --- a/include/qapi/qmp/qlist.h +++ b/include/qapi/qmp/qlist.h @@ -26,6 +26,10 @@ struct QList { QTAILQ_HEAD(,QListEntry) head; }; +void qlist_unref(QList *q); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QList, qlist_unref) + #define qlist_append(qlist, obj) \ qlist_append_obj(qlist, QOBJECT(obj)) diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h index e84ecceedbcb..7feb7c7d830d 100644 --- a/include/qapi/qmp/qnull.h +++ b/include/qapi/qmp/qnull.h @@ -26,4 +26,8 @@ static inline QNull *qnull(void) return qobject_ref(&qnull_); } +void qnull_unref(QNull *q); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QNull, qnull_unref) + #endif /* QNULL_H */ diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h index 7f84e20bfb2c..e86788dd2e3a 100644 --- a/include/qapi/qmp/qnum.h +++ b/include/qapi/qmp/qnum.h @@ -54,6 +54,10 @@ struct QNum { } u; }; +void qnum_unref(QNum *q); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QNum, qnum_unref) + QNum *qnum_from_int(int64_t value); QNum *qnum_from_uint(uint64_t value); QNum *qnum_from_double(double value); diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 1d8ba469368f..318d815d6a43 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -20,6 +20,10 @@ struct QString { const char *string; }; +void qstring_unref(QString *q); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QString, qstring_unref) + QString *qstring_new(void); QString *qstring_from_str(const char *str); QString *qstring_from_substr(const char *str, size_t start, size_t end); diff --git a/include/qemu-common.h b/include/qemu-common.h deleted file mode 100644 index f0fe07cd74c3..000000000000 --- a/include/qemu-common.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is supposed to be included only by .c files. No header file should - * depend on qemu-common.h, as this would easily lead to circular header - * dependencies. - * - * If a header file uses a definition from qemu-common.h, that definition - * must be moved to a separate header file, and the header that uses it - * must include that header. - */ -#ifndef QEMU_COMMON_H -#define QEMU_COMMON_H - -#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) - -/* Copyright string for -version arguments, About dialogs, etc */ -#define QEMU_COPYRIGHT "Copyright (c) 2003-2022 " \ - "Fabrice Bellard and the QEMU Project developers" - -/* Bug reporting information for --help arguments, About dialogs, etc */ -#define QEMU_HELP_BOTTOM \ - "See for how to report bugs.\n" \ - "More information on the QEMU project at ." - -/* main function, renamed */ -#if defined(CONFIG_COCOA) -int qemu_main(int argc, char **argv, char **envp); -#endif - -ssize_t qemu_write_full(int fd, const void *buf, size_t count) - G_GNUC_WARN_UNUSED_RESULT; - -#ifndef _WIN32 -int qemu_pipe(int pipefd[2]); -/* like openpty() but also makes it raw; return master fd */ -int qemu_openpty_raw(int *aslave, char *pty_name); -#endif - -void cpu_exec_init_all(void); -void cpu_exec_step_atomic(CPUState *cpu); - -/** - * set_preferred_target_page_bits: - * @bits: number of bits needed to represent an address within the page - * - * Set the preferred target page size (the actual target page - * size may be smaller than any given CPU's preference). - * Returns true on success, false on failure (which can only happen - * if this is called after the system has already finalized its - * choice of page size and the requested page size is smaller than that). - */ -bool set_preferred_target_page_bits(int bits); - -/** - * finalize_target_page_bits: - * Commit the final value set by set_preferred_target_page_bits. - */ -void finalize_target_page_bits(void); - -/** - * Sends a (part of) iovec down a socket, yielding when the socket is full, or - * Receives data into a (part of) iovec from a socket, - * yielding when there is no data in the socket. - * The same interface as qemu_sendv_recvv(), with added yielding. - * XXX should mark these as coroutine_fn - */ -ssize_t qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt, - size_t offset, size_t bytes, bool do_send); -#define qemu_co_recvv(sockfd, iov, iov_cnt, offset, bytes) \ - qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, false) -#define qemu_co_sendv(sockfd, iov, iov_cnt, offset, bytes) \ - qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, true) - -/** - * The same as above, but with just a single buffer - */ -ssize_t qemu_co_send_recv(int sockfd, void *buf, size_t bytes, bool do_send); -#define qemu_co_recv(sockfd, buf, bytes) \ - qemu_co_send_recv(sockfd, buf, bytes, false) -#define qemu_co_send(sockfd, buf, bytes) \ - qemu_co_send_recv(sockfd, buf, bytes, true) - -void qemu_progress_init(int enabled, float min_skip); -void qemu_progress_end(void); -void qemu_progress_print(float delta, int max); -const char *qemu_get_vm_name(void); - -/* OS specific functions */ -void os_setup_early_signal_handling(void); -int os_parse_cmd_args(int index, const char *optarg); - -/* - * Hexdump a line of a byte buffer into a hexadecimal/ASCII buffer - */ -#define QEMU_HEXDUMP_LINE_BYTES 16 /* Number of bytes to dump */ -#define QEMU_HEXDUMP_LINE_LEN 75 /* Number of characters in line */ -void qemu_hexdump_line(char *line, unsigned int b, const void *bufptr, - unsigned int len, bool ascii); - -/* - * Hexdump a buffer to a file. An optional string prefix is added to every line - */ - -void qemu_hexdump(FILE *fp, const char *prefix, - const void *bufptr, size_t size); - -/* - * helper to parse debug environment variables - */ -int parse_debug_env(const char *name, int max, int initial); - -void page_size_init(void); - -/* returns non-zero if dump is in progress, otherwise zero is - * returned. */ -bool dump_in_progress(void); - -#endif diff --git a/include/qemu-main.h b/include/qemu-main.h new file mode 100644 index 000000000000..940960a7dbcb --- /dev/null +++ b/include/qemu-main.h @@ -0,0 +1,11 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_MAIN_H +#define QEMU_MAIN_H + +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 4f4c283f6fc4..e84db2e3e504 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -26,10 +26,10 @@ #include "qom/object.h" #include "exec/hwaddr.h" -typedef struct AccelState { +struct AccelState { /*< private >*/ Object parent_obj; -} AccelState; +}; typedef struct AccelClass { /*< private >*/ @@ -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 @@ -68,6 +72,7 @@ typedef struct AccelClass { AccelClass *accel_find(const char *opt_name); AccelState *current_accel(void); +const char *current_accel_name(void); void accel_init_interfaces(AccelClass *ac); @@ -91,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/async-teardown.h b/include/qemu/async-teardown.h new file mode 100644 index 000000000000..092e7a37e7af --- /dev/null +++ b/include/qemu/async-teardown.h @@ -0,0 +1,22 @@ +/* + * Asynchronous teardown + * + * Copyright IBM, Corp. 2022 + * + * Authors: + * Claudio Imbrenda + * + * 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 QEMU_ASYNC_TEARDOWN_H +#define QEMU_ASYNC_TEARDOWN_H + +#include "config-host.h" + +#ifdef CONFIG_LINUX +void init_async_teardown(void); +#endif + +#endif diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 112a29910bea..874134fd19ae 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -15,6 +15,8 @@ #ifndef QEMU_ATOMIC_H #define QEMU_ATOMIC_H +#include "compiler.h" + /* Compiler barrier */ #define barrier() ({ asm volatile("" ::: "memory"); (void)0; }) @@ -81,7 +83,7 @@ * no processors except Alpha need a barrier here. Leave it in if * using Thread Sanitizer to avoid warnings, otherwise optimize it away. */ -#if defined(__SANITIZE_THREAD__) +#ifdef QEMU_SANITIZE_THREAD #define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); }) #elif defined(__alpha__) #define smp_read_barrier_depends() asm volatile("mb":::"memory") @@ -131,7 +133,7 @@ #define qatomic_read(ptr) \ ({ \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ qatomic_read__nocheck(ptr); \ }) @@ -139,14 +141,14 @@ __atomic_store_n(ptr, i, __ATOMIC_RELAXED) #define qatomic_set(ptr, i) do { \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ qatomic_set__nocheck(ptr, i); \ } while(0) /* See above: most compilers currently treat consume and acquire the * same, but this slows down qatomic_rcu_read unnecessarily. */ -#ifdef __SANITIZE_THREAD__ +#ifdef QEMU_SANITIZE_THREAD #define qatomic_rcu_read__nocheck(ptr, valptr) \ __atomic_load(ptr, valptr, __ATOMIC_CONSUME); #else @@ -157,27 +159,27 @@ #define qatomic_rcu_read(ptr) \ ({ \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ typeof_strip_qual(*ptr) _val; \ qatomic_rcu_read__nocheck(ptr, &_val); \ _val; \ }) #define qatomic_rcu_set(ptr, i) do { \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ } while(0) #define qatomic_load_acquire(ptr) \ ({ \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ typeof_strip_qual(*ptr) _val; \ __atomic_load(ptr, &_val, __ATOMIC_ACQUIRE); \ _val; \ }) #define qatomic_store_release(ptr, i) do { \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ } while(0) @@ -189,7 +191,7 @@ }) #define qatomic_xchg(ptr, i) ({ \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ qatomic_xchg__nocheck(ptr, i); \ }) @@ -202,7 +204,7 @@ }) #define qatomic_cmpxchg(ptr, old, new) ({ \ - QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ + qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ qatomic_cmpxchg__nocheck(ptr, old, new); \ }) @@ -254,7 +256,7 @@ #define qatomic_mb_read(ptr) \ qatomic_load_acquire(ptr) -#if !defined(__SANITIZE_THREAD__) && \ +#if !defined(QEMU_SANITIZE_THREAD) && \ (defined(__i386__) || defined(__x86_64__) || defined(__s390x__)) /* This is more efficient than a store plus a fence. */ # define qatomic_mb_set(ptr, i) ((void)qatomic_xchg(ptr, i)) diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 82a1d2f41f66..3ccb00865f2a 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -253,6 +253,7 @@ void bitmap_set(unsigned long *map, long i, long len); void bitmap_set_atomic(unsigned long *map, long i, long len); void bitmap_clear(unsigned long *map, long start, long nr); bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr); +bool bitmap_test_and_clear(unsigned long *map, long start, long nr); void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src, long nr); unsigned long bitmap_find_next_zero_area(unsigned long *map, diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 2d3bb8bbedda..346d05f2aab3 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -19,8 +19,6 @@ extern "C" { #endif -#include "fpu/softfloat-types.h" - #ifdef BSWAP_FROM_BYTESWAP static inline uint16_t bswap16(uint16_t x) { @@ -84,7 +82,7 @@ static inline void bswap64s(uint64_t *s) *s = bswap64(*s); } -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define be_bswap(v, size) (v) #define le_bswap(v, size) glue(bswap, size)(v) #define be_bswaps(v, size) @@ -188,7 +186,7 @@ CPU_CONVERT(le, 64, uint64_t) * a compile-time constant if you pass in a constant. So this can be * used to initialize static variables. */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN # define const_le32(_x) \ ((((_x) & 0x000000ffU) << 24) | \ (((_x) & 0x0000ff00U) << 8) | \ @@ -202,64 +200,6 @@ CPU_CONVERT(le, 64, uint64_t) # define const_le16(_x) (_x) #endif -/* Unions for reinterpreting between floats and integers. */ - -typedef union { - float32 f; - uint32_t l; -} CPU_FloatU; - -typedef union { - float64 d; -#if defined(HOST_WORDS_BIGENDIAN) - struct { - uint32_t upper; - uint32_t lower; - } l; -#else - struct { - uint32_t lower; - uint32_t upper; - } l; -#endif - uint64_t ll; -} CPU_DoubleU; - -typedef union { - floatx80 d; - struct { - uint64_t lower; - uint16_t upper; - } l; -} CPU_LDoubleU; - -typedef union { - float128 q; -#if defined(HOST_WORDS_BIGENDIAN) - struct { - uint32_t upmost; - uint32_t upper; - uint32_t lower; - uint32_t lowest; - } l; - struct { - uint64_t upper; - uint64_t lower; - } ll; -#else - struct { - uint32_t lowest; - uint32_t lower; - uint32_t upper; - uint32_t upmost; - } l; - struct { - uint64_t lower; - uint64_t upper; - } ll; -#endif -} CPU_QuadU; - /* unaligned/endian-independent pointer access */ /* diff --git a/include/qemu/clang-tsa.h b/include/qemu/clang-tsa.h new file mode 100644 index 000000000000..ba06fb8c9249 --- /dev/null +++ b/include/qemu/clang-tsa.h @@ -0,0 +1,114 @@ +#ifndef CLANG_TSA_H +#define CLANG_TSA_H + +/* + * Copyright 2018 Jarkko Hietaniemi + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without + * limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* http://clang.llvm.org/docs/ThreadSafetyAnalysis.html + * + * TSA is available since clang 3.6-ish. + */ +#ifdef __clang__ +# define TSA(x) __attribute__((x)) +#else +# define TSA(x) /* No TSA, make TSA attributes no-ops. */ +#endif + +/* TSA_CAPABILITY() is used to annotate typedefs: + * + * typedef pthread_mutex_t TSA_CAPABILITY("mutex") tsa_mutex; + */ +#define TSA_CAPABILITY(x) TSA(capability(x)) + +/* TSA_GUARDED_BY() is used to annotate global variables, + * the data is guarded: + * + * Foo foo TSA_GUARDED_BY(mutex); + */ +#define TSA_GUARDED_BY(x) TSA(guarded_by(x)) + +/* TSA_PT_GUARDED_BY() is used to annotate global pointers, the data + * behind the pointer is guarded. + * + * Foo* ptr TSA_PT_GUARDED_BY(mutex); + */ +#define TSA_PT_GUARDED_BY(x) TSA(pt_guarded_by(x)) + +/* The TSA_REQUIRES() is used to annotate functions: the caller of the + * function MUST hold the resource, the function will NOT release it. + * + * More than one mutex may be specified, comma-separated. + * + * void Foo(void) TSA_REQUIRES(mutex); + */ +#define TSA_REQUIRES(...) TSA(requires_capability(__VA_ARGS__)) +#define TSA_REQUIRES_SHARED(...) TSA(requires_shared_capability(__VA_ARGS__)) + +/* TSA_EXCLUDES() is used to annotate functions: the caller of the + * function MUST NOT hold resource, the function first acquires the + * resource, and then releases it. + * + * More than one mutex may be specified, comma-separated. + * + * void Foo(void) TSA_EXCLUDES(mutex); + */ +#define TSA_EXCLUDES(...) TSA(locks_excluded(__VA_ARGS__)) + +/* TSA_ACQUIRE() is used to annotate functions: the caller of the + * function MUST NOT hold the resource, the function will acquire the + * resource, but NOT release it. + * + * More than one mutex may be specified, comma-separated. + * + * void Foo(void) TSA_ACQUIRE(mutex); + */ +#define TSA_ACQUIRE(...) TSA(acquire_capability(__VA_ARGS__)) +#define TSA_ACQUIRE_SHARED(...) TSA(acquire_shared_capability(__VA_ARGS__)) + +/* TSA_RELEASE() is used to annotate functions: the caller of the + * function MUST hold the resource, but the function will then release it. + * + * More than one mutex may be specified, comma-separated. + * + * void Foo(void) TSA_RELEASE(mutex); + */ +#define TSA_RELEASE(...) TSA(release_capability(__VA_ARGS__)) +#define TSA_RELEASE_SHARED(...) TSA(release_shared_capability(__VA_ARGS__)) + +/* TSA_NO_TSA is used to annotate functions. Use only when you need to. + * + * void Foo(void) TSA_NO_TSA; + */ +#define TSA_NO_TSA TSA(no_thread_safety_analysis) + +/* + * TSA_ASSERT() is used to annotate functions: This function will assert that + * the lock is held. When it returns, the caller of the function is assumed to + * already hold the resource. + * + * More than one mutex may be specified, comma-separated. + */ +#define TSA_ASSERT(...) TSA(assert_capability(__VA_ARGS__)) +#define TSA_ASSERT_SHARED(...) TSA(assert_shared_capability(__VA_ARGS__)) + +#endif /* #ifndef CLANG_TSA_H */ diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index d9359859d435..f20a76e4a286 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -22,8 +22,6 @@ #define QEMU_EXTERN_C extern #endif -#define QEMU_NORETURN __attribute__ ((__noreturn__)) - #if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) # define QEMU_PACKED __attribute__((gcc_struct, packed)) #else @@ -108,6 +106,14 @@ #define __has_attribute(x) 0 /* compatibility with older GCC */ #endif +#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +# define QEMU_SANITIZE_ADDRESS 1 +#endif + +#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer) +# define QEMU_SANITIZE_THREAD 1 +#endif + /* * GCC doesn't provide __has_attribute() until GCC 5, but we know all the GCC * versions we support have the "flatten" attribute. Clang may not have the @@ -156,22 +162,6 @@ #define QEMU_ALWAYS_INLINE #endif -/** - * qemu_build_not_reached() - * - * The compiler, during optimization, is expected to prove that a call - * to this function cannot be reached and remove it. If the compiler - * supports QEMU_ERROR, this will be reported at compile time; otherwise - * this will be reported at link time due to the missing symbol. - */ -extern void QEMU_NORETURN QEMU_ERROR("code path is reachable") - qemu_build_not_reached_always(void); -#if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) -#define qemu_build_not_reached() qemu_build_not_reached_always() -#else -#define qemu_build_not_reached() g_assert_not_reached() -#endif - /** * In most cases, normal "fallthrough" comments are good enough for * switch-case statements, but sometimes the compiler has problems diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h index f6054233212a..b82a778123f8 100644 --- a/include/qemu/config-file.h +++ b/include/qemu/config-file.h @@ -12,7 +12,6 @@ void qemu_add_opts(QemuOptsList *list); void qemu_add_drive_opts(QemuOptsList *list); int qemu_global_option(const char *str); -void qemu_config_write(FILE *fp); int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp); @@ -23,7 +22,7 @@ int qemu_read_config_file(const char *filename, QEMUConfigCB *f, Error **errp); /* Parse QDict options as a replacement for a config file (allowing multiple enumerated (0..(n-1)) configuration "sections") */ -void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, +bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, Error **errp); #endif /* QEMU_CONFIG_FILE_H */ diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index c828a95ee092..89650a2d7fab 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 @@ -198,27 +198,40 @@ typedef struct CoQueue { */ void qemu_co_queue_init(CoQueue *queue); +typedef enum { + /* + * Enqueue at front instead of back. Use this to re-queue a request when + * its wait condition is not satisfied after being woken up. + */ + CO_QUEUE_WAIT_FRONT = 0x1, +} CoQueueWaitFlags; + /** * Adds the current coroutine to the CoQueue and transfers control to the * caller of the coroutine. The mutex is unlocked during the wait and * locked again afterwards. */ #define qemu_co_queue_wait(queue, lock) \ - qemu_co_queue_wait_impl(queue, QEMU_MAKE_LOCKABLE(lock)) -void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock); + qemu_co_queue_wait_impl(queue, QEMU_MAKE_LOCKABLE(lock), 0) +#define qemu_co_queue_wait_flags(queue, lock, flags) \ + qemu_co_queue_wait_impl(queue, QEMU_MAKE_LOCKABLE(lock), (flags)) +void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock, + CoQueueWaitFlags flags); /** - * Removes the next coroutine from the CoQueue, and wake it up. + * Removes the next coroutine from the CoQueue, and queue it to run after + * the currently-running coroutine yields. * Returns true if a coroutine was removed, false if the queue is empty. - * OK to run from coroutine and non-coroutine context. + * Used from coroutine context, use qemu_co_enter_next outside. */ -bool qemu_co_queue_next(CoQueue *queue); +bool coroutine_fn qemu_co_queue_next(CoQueue *queue); /** - * Empties the CoQueue; all coroutines are woken up. - * OK to run from coroutine and non-coroutine context. + * Empties the CoQueue and queues the coroutine to run after + * the currently-running coroutine yields. + * Used from coroutine context, use qemu_co_enter_all outside. */ -void qemu_co_queue_restart_all(CoQueue *queue); +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue); /** * Removes the next coroutine from the CoQueue, and wake it up. Unlike @@ -233,6 +246,19 @@ void qemu_co_queue_restart_all(CoQueue *queue); qemu_co_enter_next_impl(queue, QEMU_MAKE_LOCKABLE(lock)) bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock); +/** + * Empties the CoQueue, waking the waiting coroutine one at a time. Unlike + * qemu_co_queue_all, this function releases the lock during aio_co_wake + * because it is meant to be used outside coroutine context; in that case, the + * coroutine is entered immediately, before qemu_co_enter_all returns. + * + * If used in coroutine context, qemu_co_enter_all is equivalent to + * qemu_co_queue_all. + */ +#define qemu_co_enter_all(queue, lock) \ + qemu_co_enter_all_impl(queue, QEMU_MAKE_LOCKABLE(lock)) +void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock); + /** * Checks if the CoQueue is empty. */ @@ -261,7 +287,7 @@ void qemu_co_rwlock_init(CoRwlock *lock); * of a parallel writer, control is transferred to the caller of the current * coroutine. */ -void qemu_co_rwlock_rdlock(CoRwlock *lock); +void coroutine_fn qemu_co_rwlock_rdlock(CoRwlock *lock); /** * Write Locks the CoRwlock from a reader. This is a bit more efficient than @@ -270,7 +296,7 @@ void qemu_co_rwlock_rdlock(CoRwlock *lock); * to the caller of the current coroutine; another writer might run while * @qemu_co_rwlock_upgrade blocks. */ -void qemu_co_rwlock_upgrade(CoRwlock *lock); +void coroutine_fn qemu_co_rwlock_upgrade(CoRwlock *lock); /** * Downgrades a write-side critical section to a reader. Downgrading with @@ -278,20 +304,20 @@ void qemu_co_rwlock_upgrade(CoRwlock *lock); * followed by @qemu_co_rwlock_rdlock. This makes it more efficient, but * may also sometimes be necessary for correctness. */ -void qemu_co_rwlock_downgrade(CoRwlock *lock); +void coroutine_fn qemu_co_rwlock_downgrade(CoRwlock *lock); /** * Write Locks the mutex. If the lock cannot be taken immediately because * of a parallel reader, control is transferred to the caller of the current * coroutine. */ -void qemu_co_rwlock_wrlock(CoRwlock *lock); +void coroutine_fn qemu_co_rwlock_wrlock(CoRwlock *lock); /** * Unlocks the read/write lock and schedules the next coroutine that was * waiting for this lock to be run. */ -void qemu_co_rwlock_unlock(CoRwlock *lock); +void coroutine_fn qemu_co_rwlock_unlock(CoRwlock *lock); typedef struct QemuCoSleep { Coroutine *to_wake; @@ -316,6 +342,19 @@ static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns) qemu_co_sleep_ns_wakeable(&w, type, ns); } +typedef void CleanupFunc(void *opaque); +/** + * Run entry in a coroutine and start timer. Wait for entry to finish or for + * timer to elapse, what happen first. If entry finished, return 0, if timer + * elapsed earlier, return -ETIMEDOUT. + * + * Be careful, entry execution is not canceled, user should handle it somehow. + * If @clean is provided, it's called after coroutine finish if timeout + * happened. + */ +int coroutine_fn qemu_co_timeout(CoroutineEntry *entry, void *opaque, + uint64_t timeout_ns, CleanupFunc clean); + /** * Wake a coroutine if it is sleeping in qemu_co_sleep_ns. The timer will be * deleted. @sleep_state must be the variable whose address was given to @@ -334,13 +373,38 @@ void coroutine_fn yield_until_fd_readable(int fd); /** * Increase coroutine pool size */ -void qemu_coroutine_increase_pool_batch_size(unsigned int additional_pool_size); +void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size); /** - * Devcrease coroutine pool size + * Decrease coroutine pool size */ -void qemu_coroutine_decrease_pool_batch_size(unsigned int additional_pool_size); +void qemu_coroutine_dec_pool_size(unsigned int additional_pool_size); #include "qemu/lockable.h" +/** + * Sends a (part of) iovec down a socket, yielding when the socket is full, or + * Receives data into a (part of) iovec from a socket, + * yielding when there is no data in the socket. + * The same interface as qemu_sendv_recvv(), with added yielding. + * XXX should mark these as coroutine_fn + */ +ssize_t coroutine_fn qemu_co_sendv_recvv(int sockfd, struct iovec *iov, + unsigned iov_cnt, size_t offset, + size_t bytes, bool do_send); +#define qemu_co_recvv(sockfd, iov, iov_cnt, offset, bytes) \ + qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, false) +#define qemu_co_sendv(sockfd, iov, iov_cnt, offset, bytes) \ + qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, true) + +/** + * The same as above, but with just a single buffer + */ +ssize_t coroutine_fn qemu_co_send_recv(int sockfd, void *buf, size_t bytes, + bool do_send); +#define qemu_co_recv(sockfd, buf, bytes) \ + qemu_co_send_recv(sockfd, buf, bytes, false) +#define qemu_co_send(sockfd, buf, bytes) \ + qemu_co_send_recv(sockfd, buf, bytes, true) + #endif /* QEMU_COROUTINE_H */ diff --git a/include/qemu/cpu-float.h b/include/qemu/cpu-float.h new file mode 100644 index 000000000000..a26b9faf6850 --- /dev/null +++ b/include/qemu/cpu-float.h @@ -0,0 +1,64 @@ +#ifndef QEMU_CPU_FLOAT_H +#define QEMU_CPU_FLOAT_H + +#include "fpu/softfloat-types.h" + +/* Unions for reinterpreting between floats and integers. */ + +typedef union { + float32 f; + uint32_t l; +} CPU_FloatU; + +typedef union { + float64 d; +#if HOST_BIG_ENDIAN + struct { + uint32_t upper; + uint32_t lower; + } l; +#else + struct { + uint32_t lower; + uint32_t upper; + } l; +#endif + uint64_t ll; +} CPU_DoubleU; + +typedef union { + floatx80 d; + struct { + uint64_t lower; + uint16_t upper; + } l; +} CPU_LDoubleU; + +typedef union { + float128 q; +#if HOST_BIG_ENDIAN + struct { + uint32_t upmost; + uint32_t upper; + uint32_t lower; + uint32_t lowest; + } l; + struct { + uint64_t upper; + uint64_t lower; + } ll; +#else + struct { + uint32_t lowest; + uint32_t lower; + uint32_t upper; + uint32_t upmost; + } l; + struct { + uint64_t lower; + uint64_t upper; + } ll; +#endif +} CPU_QuadU; + +#endif /* QEMU_CPU_FLOAT_H */ diff --git a/include/qemu/crc-ccitt.h b/include/qemu/crc-ccitt.h index 06ee55b159b3..d6eb49146dbc 100644 --- a/include/qemu/crc-ccitt.h +++ b/include/qemu/crc-ccitt.h @@ -11,8 +11,8 @@ * SPDX-License-Identifier: GPL-2.0 */ -#ifndef _CRC_CCITT_H -#define _CRC_CCITT_H +#ifndef CRC_CCITT_H +#define CRC_CCITT_H extern uint16_t const crc_ccitt_table[256]; extern uint16_t const crc_ccitt_false_table[256]; @@ -30,4 +30,4 @@ static inline uint16_t crc_ccitt_false_byte(uint16_t crc, const uint8_t c) return (crc << 8) ^ crc_ccitt_false_table[(crc >> 8) ^ c]; } -#endif /* _CRC_CCITT_H */ +#endif /* CRC_CCITT_H */ diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 320543950c4c..92c436d8c70d 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -1,6 +1,24 @@ #ifndef QEMU_CUTILS_H #define QEMU_CUTILS_H +/* + * si_prefix: + * @exp10: exponent of 10, a multiple of 3 between -18 and 18 inclusive. + * + * Return a SI prefix (n, u, m, K, M, etc.) corresponding + * to the given exponent of 10. + */ +const char *si_prefix(unsigned int exp10); + +/* + * iec_binary_prefix: + * @exp2: exponent of 2, a multiple of 10 between 0 and 60 inclusive. + * + * Return an IEC binary prefix (Ki, Mi, etc.) corresponding + * to the given exponent of 2. + */ +const char *iec_binary_prefix(unsigned int exp2); + /** * pstrcpy: * @buf: buffer to copy string into @@ -129,9 +147,6 @@ static inline const char *qemu_strchrnul(const char *s, int c) const char *qemu_strchrnul(const char *s, int c); #endif time_t mktimegm(struct tm *tm); -int qemu_fdatasync(int fd); -int qemu_msync(void *addr, size_t length, int fd); -int fcntl_setfl(int fd, int flag); int qemu_parse_fd(const char *param); int qemu_strtoi(const char *nptr, const char **endptr, int base, int *result); @@ -196,15 +211,34 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n); */ int qemu_pstrcmp0(const char **str1, const char **str2); +/* Find program directory, and save it for later usage with + * qemu_get_exec_dir(). + * Try OS specific API first, if not working, parse from argv0. */ +void qemu_init_exec_dir(const char *argv0); + +/* Get the saved exec dir. */ +const char *qemu_get_exec_dir(void); /** * get_relocated_path: * @dir: the directory (typically a `CONFIG_*DIR` variable) to be relocated. * * Returns a path for @dir that uses the directory of the running executable - * as the prefix. For example, if `bindir` is `/usr/bin` and @dir is - * `/usr/share/qemu`, the function will append `../share/qemu` to the - * directory that contains the running executable and return the result. + * as the prefix. + * + * When a directory named `qemu-bundle` exists in the directory of the running + * executable, the path to the directory will be prepended to @dir. For + * example, if the directory of the running executable is `/qemu/build` @dir + * is `/usr/share/qemu`, the result will be + * `/qemu/build/qemu-bundle/usr/share/qemu`. The directory is expected to exist + * in the build tree. + * + * Otherwise, the directory of the running executable will be used as the + * prefix and it appends the relative path from `bindir` to @dir. For example, + * if the directory of the running executable is `/opt/qemu/bin`, `bindir` is + * `/usr/bin` and @dir is `/usr/share/qemu`, the result will be + * `/opt/qemu/bin/../share/qemu`. + * * The returned string should be freed by the caller. */ char *get_relocated_path(const char *dir); @@ -214,4 +248,24 @@ static inline const char *yes_no(bool b) return b ? "yes" : "no"; } +/* + * helper to parse debug environment variables + */ +int parse_debug_env(const char *name, int max, int initial); + +/* + * Hexdump a line of a byte buffer into a hexadecimal/ASCII buffer + */ +#define QEMU_HEXDUMP_LINE_BYTES 16 /* Number of bytes to dump */ +#define QEMU_HEXDUMP_LINE_LEN 75 /* Number of characters in line */ +void qemu_hexdump_line(char *line, unsigned int b, const void *bufptr, + unsigned int len, bool ascii); + +/* + * Hexdump a buffer to a file. An optional string prefix is added to every line + */ + +void qemu_hexdump(FILE *fp, const char *prefix, + const void *bufptr, size_t size); + #endif diff --git a/include/qemu/dma_notifier.h b/include/qemu/dma_notifier.h new file mode 100644 index 000000000000..b8d241fd0d72 --- /dev/null +++ b/include/qemu/dma_notifier.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef DMA_NOTIFIER_H +#define DMA_NOTIFIER_H + +#include "qom/object.h" +#include "qemu/notify.h" +#include "qemu/typedefs.h" + +void dma_trigger_init_notifier_list(NotifierList * notifier_list); +void dma_trigger_notifier_connect(Notifier *notifier); +void dma_trigger_notify(void * data); +void dma_trigger_disconnect(Notifier *notifier); + +#endif /* DMA_NOTIFIER_H */ diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h index b6f45e69d79a..3ae2357fda54 100644 --- a/include/qemu/error-report.h +++ b/include/qemu/error-report.h @@ -32,8 +32,6 @@ void loc_set_file(const char *fname, int lno); int error_vprintf(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); int error_printf(const char *fmt, ...) G_GNUC_PRINTF(1, 2); -int error_vprintf_unless_qmp(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); -int error_printf_unless_qmp(const char *fmt, ...) G_GNUC_PRINTF(1, 2); void error_vreport(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); void warn_vreport(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 5bd986aa44a3..af4e4ab7468e 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -76,20 +76,9 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size); * * Store result of merging @a and @b into @result. * @result is allowed to be equal to @a or @b. - * - * Return true if the merge was successful, - * false if it was not attempted. - */ -bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result); - -/** - * hbitmap_can_merge: - * - * hbitmap_can_merge(a, b) && hbitmap_can_merge(a, result) is sufficient and - * necessary for hbitmap_merge will not fail. - * + * All bitmaps must have same size. */ -bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b); +void hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result); /** * hbitmap_empty: diff --git a/include/qemu/help-texts.h b/include/qemu/help-texts.h new file mode 100644 index 000000000000..4f265fed8df1 --- /dev/null +++ b/include/qemu/help-texts.h @@ -0,0 +1,13 @@ +#ifndef QEMU_HELP_TEXTS_H +#define QEMU_HELP_TEXTS_H + +/* Copyright string for -version arguments, About dialogs, etc */ +#define QEMU_COPYRIGHT "Copyright (c) 2003-2022 " \ + "Fabrice Bellard and the QEMU Project developers" + +/* Bug reporting information for --help arguments, About dialogs, etc */ +#define QEMU_HELP_BOTTOM \ + "See for how to report bugs.\n" \ + "More information on the QEMU project at ." + +#endif diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index ca979dc6ccde..88d476161ccb 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -32,6 +32,7 @@ #include "qemu/compiler.h" #include "qemu/bswap.h" +#include "qemu/int128.h" #ifdef CONFIG_INT128 static inline void mulu64(uint64_t *plow, uint64_t *phigh, @@ -88,7 +89,7 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) union { uint64_t ll; struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint32_t high, low; #else uint32_t low, high; @@ -375,12 +376,7 @@ static inline uint64_t uabs64(int64_t v) */ static inline bool sadd32_overflow(int32_t x, int32_t y, int32_t *ret) { -#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 return __builtin_add_overflow(x, y, ret); -#else - *ret = x + y; - return ((*ret ^ x) & ~(x ^ y)) < 0; -#endif } /** @@ -393,12 +389,7 @@ static inline bool sadd32_overflow(int32_t x, int32_t y, int32_t *ret) */ static inline bool sadd64_overflow(int64_t x, int64_t y, int64_t *ret) { -#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 return __builtin_add_overflow(x, y, ret); -#else - *ret = x + y; - return ((*ret ^ x) & ~(x ^ y)) < 0; -#endif } /** @@ -411,12 +402,7 @@ static inline bool sadd64_overflow(int64_t x, int64_t y, int64_t *ret) */ static inline bool uadd32_overflow(uint32_t x, uint32_t y, uint32_t *ret) { -#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 return __builtin_add_overflow(x, y, ret); -#else - *ret = x + y; - return *ret < x; -#endif } /** @@ -429,12 +415,7 @@ static inline bool uadd32_overflow(uint32_t x, uint32_t y, uint32_t *ret) */ static inline bool uadd64_overflow(uint64_t x, uint64_t y, uint64_t *ret) { -#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 return __builtin_add_overflow(x, y, ret); -#else - *ret = x + y; - return *ret < x; -#endif } /** @@ -448,12 +429,7 @@ static inline bool uadd64_overflow(uint64_t x, uint64_t y, uint64_t *ret) */ static inline bool ssub32_overflow(int32_t x, int32_t y, int32_t *ret) { -#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 return __builtin_sub_overflow(x, y, ret); -#else - *ret = x - y; - return ((*ret ^ x) & (x ^ y)) < 0; -#endif } /** @@ -467,12 +443,7 @@ static inline bool ssub32_overflow(int32_t x, int32_t y, int32_t *ret) */ static inline bool ssub64_overflow(int64_t x, int64_t y, int64_t *ret) { -#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 return __builtin_sub_overflow(x, y, ret); -#else - *ret = x - y; - return ((*ret ^ x) & (x ^ y)) < 0; -#endif } /** @@ -486,12 +457,7 @@ static inline bool ssub64_overflow(int64_t x, int64_t y, int64_t *ret) */ static inline bool usub32_overflow(uint32_t x, uint32_t y, uint32_t *ret) { -#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 return __builtin_sub_overflow(x, y, ret); -#else - *ret = x - y; - return x < y; -#endif } /** @@ -505,12 +471,7 @@ static inline bool usub32_overflow(uint32_t x, uint32_t y, uint32_t *ret) */ static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret) { -#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 return __builtin_sub_overflow(x, y, ret); -#else - *ret = x - y; - return x < y; -#endif } /** @@ -523,13 +484,7 @@ static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret) */ static inline bool smul32_overflow(int32_t x, int32_t y, int32_t *ret) { -#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 return __builtin_mul_overflow(x, y, ret); -#else - int64_t z = (int64_t)x * y; - *ret = z; - return *ret != z; -#endif } /** @@ -542,14 +497,7 @@ static inline bool smul32_overflow(int32_t x, int32_t y, int32_t *ret) */ static inline bool smul64_overflow(int64_t x, int64_t y, int64_t *ret) { -#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 return __builtin_mul_overflow(x, y, ret); -#else - uint64_t hi, lo; - muls64(&lo, &hi, x, y); - *ret = lo; - return hi != ((int64_t)lo >> 63); -#endif } /** @@ -562,13 +510,7 @@ static inline bool smul64_overflow(int64_t x, int64_t y, int64_t *ret) */ static inline bool umul32_overflow(uint32_t x, uint32_t y, uint32_t *ret) { -#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 return __builtin_mul_overflow(x, y, ret); -#else - uint64_t z = (uint64_t)x * y; - *ret = z; - return z > UINT32_MAX; -#endif } /** @@ -581,13 +523,7 @@ static inline bool umul32_overflow(uint32_t x, uint32_t y, uint32_t *ret) */ static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret) { -#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 return __builtin_mul_overflow(x, y, ret); -#else - uint64_t hi; - mulu64(ret, &hi, x, y); - return hi != 0; -#endif } /* @@ -597,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; @@ -849,4 +784,6 @@ static inline uint64_t udiv_qrnnd(uint64_t *r, uint64_t n1, #endif } +Int128 divu256(Int128 *plow, Int128 *phigh, Int128 divisor); +Int128 divs256(Int128 *plow, Int128 *phigh, Int128 divisor); #endif diff --git a/include/qemu/int128.h b/include/qemu/int128.h index 2c4064256cdf..d2b76ca6acdc 100644 --- a/include/qemu/int128.h +++ b/include/qemu/int128.h @@ -83,6 +83,11 @@ static inline Int128 int128_rshift(Int128 a, int n) return a >> n; } +static inline Int128 int128_urshift(Int128 a, int n) +{ + return (__uint128_t)a >> n; +} + static inline Int128 int128_lshift(Int128 a, int n) { return a << n; @@ -123,11 +128,21 @@ static inline bool int128_ge(Int128 a, Int128 b) return a >= b; } +static inline bool int128_uge(Int128 a, Int128 b) +{ + return ((__uint128_t)a) >= ((__uint128_t)b); +} + static inline bool int128_lt(Int128 a, Int128 b) { return a < b; } +static inline bool int128_ult(Int128 a, Int128 b) +{ + return (__uint128_t)a < (__uint128_t)b; +} + static inline bool int128_le(Int128 a, Int128 b) { return a <= b; @@ -172,6 +187,15 @@ static inline Int128 bswap128(Int128 a) #endif } +static inline int clz128(Int128 a) +{ + if (a >> 64) { + return __builtin_clzll(a >> 64); + } else { + return (a) ? __builtin_clzll((uint64_t)a) + 64 : 128; + } +} + static inline Int128 int128_divu(Int128 a, Int128 b) { return (__uint128_t)a / (__uint128_t)b; @@ -205,7 +229,7 @@ typedef struct Int128 Int128; * a union with other integer types). */ struct Int128 { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN int64_t hi; uint64_t lo; #else @@ -299,6 +323,20 @@ static inline Int128 int128_rshift(Int128 a, int n) } } +static inline Int128 int128_urshift(Int128 a, int n) +{ + uint64_t h = a.hi; + if (!n) { + return a; + } + h = h >> (n & 63); + if (n >= 64) { + return int128_make64(h); + } else { + return int128_make128((a.lo >> n) | ((uint64_t)a.hi << (64 - n)), h); + } +} + static inline Int128 int128_lshift(Int128 a, int n) { uint64_t l = a.lo << (n & 63); @@ -354,11 +392,21 @@ static inline bool int128_ge(Int128 a, Int128 b) return a.hi > b.hi || (a.hi == b.hi && a.lo >= b.lo); } +static inline bool int128_uge(Int128 a, Int128 b) +{ + return (uint64_t)a.hi > (uint64_t)b.hi || (a.hi == b.hi && a.lo >= b.lo); +} + static inline bool int128_lt(Int128 a, Int128 b) { return !int128_ge(a, b); } +static inline bool int128_ult(Int128 a, Int128 b) +{ + return !int128_uge(a, b); +} + static inline bool int128_le(Int128 a, Int128 b) { return int128_ge(b, a); @@ -399,6 +447,15 @@ static inline Int128 bswap128(Int128 a) return int128_make128(bswap64(a.hi), bswap64(a.lo)); } +static inline int clz128(Int128 a) +{ + if (a.hi) { + return __builtin_clzll(a.hi); + } else { + return (a.lo) ? __builtin_clzll(a.lo) + 64 : 128; + } +} + Int128 int128_divu(Int128, Int128); Int128 int128_remu(Int128, Int128); Int128 int128_divs(Int128, Int128); @@ -412,5 +469,7 @@ static inline void bswap128s(Int128 *s) } #define UINT128_MAX int128_make128(~0LL, ~0LL) +#define INT128_MAX int128_make128(UINT64_MAX, INT64_MAX) +#define INT128_MIN int128_make128(0, INT64_MIN) #endif /* INT128_H */ diff --git a/include/qemu/interval-tree.h b/include/qemu/interval-tree.h new file mode 100644 index 000000000000..25006debe8cf --- /dev/null +++ b/include/qemu/interval-tree.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Interval trees. + * + * Derived from include/linux/interval_tree.h and its dependencies. + */ + +#ifndef QEMU_INTERVAL_TREE_H +#define QEMU_INTERVAL_TREE_H + +/* + * For now, don't expose Linux Red-Black Trees separately, but retain the + * separate type definitions to keep the implementation sane, and allow + * the possibility of disentangling them later. + */ +typedef struct RBNode +{ + /* Encodes parent with color in the lsb. */ + uintptr_t rb_parent_color; + struct RBNode *rb_right; + struct RBNode *rb_left; +} RBNode; + +typedef struct RBRoot +{ + RBNode *rb_node; +} RBRoot; + +typedef struct RBRootLeftCached { + RBRoot rb_root; + RBNode *rb_leftmost; +} RBRootLeftCached; + +typedef struct IntervalTreeNode +{ + RBNode rb; + + uint64_t start; /* Start of interval */ + uint64_t last; /* Last location _in_ interval */ + uint64_t subtree_last; +} IntervalTreeNode; + +typedef RBRootLeftCached IntervalTreeRoot; + +/** + * interval_tree_is_empty + * @root: root of the tree. + * + * Returns true if the tree contains no nodes. + */ +static inline bool interval_tree_is_empty(const IntervalTreeRoot *root) +{ + return root->rb_root.rb_node == NULL; +} + +/** + * interval_tree_insert + * @node: node to insert, + * @root: root of the tree. + * + * Insert @node into @root, and rebalance. + */ +void interval_tree_insert(IntervalTreeNode *node, IntervalTreeRoot *root); + +/** + * interval_tree_remove + * @node: node to remove, + * @root: root of the tree. + * + * Remove @node from @root, and rebalance. + */ +void interval_tree_remove(IntervalTreeNode *node, IntervalTreeRoot *root); + +/** + * interval_tree_iter_first: + * @root: root of the tree, + * @start, @last: the inclusive interval [start, last]. + * + * Locate the "first" of a set of nodes within the tree at @root + * that overlap the interval, where "first" is sorted by start. + * Returns NULL if no overlap found. + */ +IntervalTreeNode *interval_tree_iter_first(IntervalTreeRoot *root, + uint64_t start, uint64_t last); + +/** + * interval_tree_iter_next: + * @node: previous search result + * @start, @last: the inclusive interval [start, last]. + * + * Locate the "next" of a set of nodes within the tree that overlap the + * interval; @next is the result of a previous call to + * interval_tree_iter_{first,next}. Returns NULL if @next was the last + * node in the set. + */ +IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node, + uint64_t start, uint64_t last); + +#endif /* QEMU_INTERVAL_TREE_H */ diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h index c938fb07933a..8528e5c98fbc 100644 --- a/include/qemu/iova-tree.h +++ b/include/qemu/iova-tree.h @@ -72,10 +72,8 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map); * provided. The range does not need to be exactly what has inserted, * all the mappings that are included in the provided range will be * removed from the tree. Here map->translated_addr is meaningless. - * - * Return: 0 if succeeded, or <0 if error. */ -int 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 c105b31076ca..e502787dd87d 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; - /** 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. + * 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; + /** * 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_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. */ -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); +void job_set_aio_context(Job *job, AioContext *ctx); #endif diff --git a/include/qemu/keyval.h b/include/qemu/keyval.h new file mode 100644 index 000000000000..1187b6830343 --- /dev/null +++ b/include/qemu/keyval.h @@ -0,0 +1,15 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef KEYVAL_H +#define KEYVAL_H + +QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key, + bool *p_help, Error **errp); +QDict *keyval_parse(const char *params, const char *implied_key, + bool *help, Error **errp); +void keyval_merge(QDict *old, const QDict *new, Error **errp); + +#endif /* KEYVAL_H */ diff --git a/include/qemu/log-for-trace.h b/include/qemu/log-for-trace.h index 5e415172278a..d47c9cd4462b 100644 --- a/include/qemu/log-for-trace.h +++ b/include/qemu/log-for-trace.h @@ -30,6 +30,6 @@ static inline bool qemu_loglevel_mask(int mask) } /* main logging function */ -int G_GNUC_PRINTF(1, 2) qemu_log(const char *fmt, ...); +void G_GNUC_PRINTF(1, 2) qemu_log(const char *fmt, ...); #endif diff --git a/include/qemu/log.h b/include/qemu/log.h index 5739c7e6d819..c5643d8dd56a 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -3,46 +3,16 @@ /* A small part of this API is split into its own header */ #include "qemu/log-for-trace.h" -#include "qemu/rcu.h" - -typedef struct QemuLogFile { - struct rcu_head rcu; - FILE *fd; -} QemuLogFile; - -/* Private global variable, don't use */ -extern QemuLogFile *qemu_logfile; - /* * The new API: - * */ -/* Log settings checking macros: */ - -/* Returns true if qemu_log() will really write somewhere - */ -static inline bool qemu_log_enabled(void) -{ - return qemu_logfile != NULL; -} +/* Returns true if qemu_log() will really write somewhere. */ +bool qemu_log_enabled(void); -/* Returns true if qemu_log() will write somewhere else than stderr - */ -static inline bool qemu_log_separate(void) -{ - QemuLogFile *logfile; - bool res = false; - - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile && logfile->fd != stderr) { - res = true; - } - rcu_read_unlock(); - return res; -} +/* Returns true if qemu_log() will write somewhere other than stderr. */ +bool qemu_log_separate(void); #define CPU_LOG_TB_OUT_ASM (1 << 0) #define CPU_LOG_TB_IN_ASM (1 << 1) @@ -64,51 +34,15 @@ static inline bool qemu_log_separate(void) #define CPU_LOG_PLUGIN (1 << 18) /* LOG_STRACE is used for user-mode strace logging. */ #define LOG_STRACE (1 << 19) +#define LOG_PER_THREAD (1 << 20) -/* Lock output for a series of related logs. Since this is not needed - * for a single qemu_log / qemu_log_mask / qemu_log_mask_and_addr, we - * assume that qemu_loglevel_mask has already been tested, and that - * qemu_loglevel is never set when qemu_logfile is unset. - */ +/* Lock/unlock output. */ -static inline FILE *qemu_log_lock(void) -{ - QemuLogFile *logfile; - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - qemu_flockfile(logfile->fd); - return logfile->fd; - } else { - return NULL; - } -} - -static inline void qemu_log_unlock(FILE *fd) -{ - if (fd) { - qemu_funlockfile(fd); - } - rcu_read_unlock(); -} +FILE *qemu_log_trylock(void) G_GNUC_WARN_UNUSED_RESULT; +void qemu_log_unlock(FILE *fd); /* Logging functions: */ -/* vfprintf-like logging function - */ -static inline void G_GNUC_PRINTF(1, 0) -qemu_log_vprintf(const char *fmt, va_list va) -{ - QemuLogFile *logfile; - - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - vfprintf(logfile->fd, fmt, va); - } - rcu_read_unlock(); -} - /* log only if a bit is set on the current loglevel mask: * @mask: bit to check in the mask * @fmt: printf-style format string @@ -147,9 +81,9 @@ typedef struct QEMULogItem { extern const QEMULogItem qemu_log_items[]; -void qemu_set_log(int log_flags); -void qemu_log_needs_buffers(void); -void qemu_set_log_filename(const char *filename, Error **errp); +bool qemu_set_log(int log_flags, Error **errp); +bool qemu_set_log_filename(const char *filename, Error **errp); +bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp); void qemu_set_dfilter_ranges(const char *ranges, Error **errp); bool qemu_log_in_addr_range(uint64_t addr); int qemu_str_to_log_mask(const char *str); @@ -159,9 +93,4 @@ int qemu_str_to_log_mask(const char *str); */ void qemu_print_log_usage(FILE *f); -/* fflush() the log file */ -void qemu_log_flush(void); -/* Close the log file */ -void qemu_log_close(void); - #endif diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index d3750c8e7643..c25f39069626 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -26,9 +26,19 @@ #define QEMU_MAIN_LOOP_H #include "block/aio.h" +#include "qom/object.h" +#include "sysemu/event-loop-base.h" #define SIG_IPI SIGUSR1 +#define TYPE_MAIN_LOOP "main-loop" +OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP) + +struct MainLoop { + EventLoopBase parent_obj; +}; +typedef struct MainLoop MainLoop; + /** * qemu_init_main_loop: Set up the process so that it can run the main loop. * @@ -147,6 +157,8 @@ typedef void WaitObjectFunc(void *opaque); * in the main loop's calls to WaitForMultipleObjects. When the handle * is in a signaled state, QEMU will call @func. * + * If the same HANDLE is added twice, this function returns -1. + * * @handle: The Windows handle to be observed. * @func: A function to be called when @handle is in a signaled state. * @opaque: A pointer-size value that is passed to @func. @@ -269,33 +281,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 { \ - /* FIXME: Re-enable after 7.0 release */ \ - /* assert(qemu_in_main_thread()); */ \ + 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 */ \ @@ -333,6 +343,35 @@ void qemu_mutex_lock_iothread_impl(const char *file, int line); */ void qemu_mutex_unlock_iothread(void); +/** + * QEMU_IOTHREAD_LOCK_GUARD + * + * Wrap a block of code in a conditional qemu_mutex_{lock,unlock}_iothread. + */ +typedef struct IOThreadLockAuto IOThreadLockAuto; + +static inline IOThreadLockAuto *qemu_iothread_auto_lock(const char *file, + int line) +{ + if (qemu_mutex_iothread_locked()) { + return NULL; + } + qemu_mutex_lock_iothread_impl(file, line); + /* Anything non-NULL causes the cleanup function to be called */ + return (IOThreadLockAuto *)(uintptr_t)1; +} + +static inline void qemu_iothread_auto_unlock(IOThreadLockAuto *l) +{ + qemu_mutex_unlock_iothread(); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(IOThreadLockAuto, qemu_iothread_auto_unlock) + +#define QEMU_IOTHREAD_LOCK_GUARD() \ + g_autoptr(IOThreadLockAuto) _iothread_lock_auto __attribute__((unused)) \ + = qemu_iothread_auto_lock(__FILE__, __LINE__) + /* * qemu_cond_wait_iothread: Wait on condition for the main loop mutex * diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index 5076695cc811..2825e231a723 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/module.h b/include/qemu/module.h index 5fcc323b2a79..c37ce74b16ff 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -61,16 +61,43 @@ typedef enum { #define fuzz_target_init(function) module_init(function, \ MODULE_INIT_FUZZ_TARGET) #define migration_init(function) module_init(function, MODULE_INIT_MIGRATION) -#define block_module_load_one(lib) module_load_one("block-", lib, false) -#define ui_module_load_one(lib) module_load_one("ui-", lib, false) -#define audio_module_load_one(lib) module_load_one("audio-", lib, false) +#define block_module_load(lib, errp) module_load("block-", lib, errp) +#define ui_module_load(lib, errp) module_load("ui-", lib, errp) +#define audio_module_load(lib, errp) module_load("audio-", lib, errp) void register_module_init(void (*fn)(void), module_init_type type); void register_dso_module_init(void (*fn)(void), module_init_type type); void module_call_init(module_init_type type); -bool module_load_one(const char *prefix, const char *lib_name, bool mayfail); -void module_load_qom_one(const char *type); + +/* + * module_load: attempt to load a module from a set of directories + * + * directories searched are: + * - getenv("QEMU_MODULE_DIR") + * - get_relocated_path(CONFIG_QEMU_MODDIR); + * - /var/run/qemu/${version_dir} + * + * prefix: a subsystem prefix, or the empty string ("audio-", ..., "") + * name: name of the module + * errp: error to set in case the module is found, but load failed. + * + * Return value: -1 on error (errp set if not NULL). + * 0 if module or one of its dependencies are not installed, + * 1 if the module is found and loaded, + * 2 if the module is already loaded, or module is built-in. + */ +int module_load(const char *prefix, const char *name, Error **errp); + +/* + * module_load_qom: attempt to load a module to provide a QOM type + * + * type: the type to be provided + * errp: error to set. + * + * Return value: as per module_load. + */ +int module_load_qom(const char *type, Error **errp); void module_load_qom_all(void); void module_allow_arch(const char *arch); @@ -135,6 +162,16 @@ void module_allow_arch(const char *arch); */ #define module_opts(name) modinfo(opts, name) +/** + * module_kconfig + * + * @name: Kconfig requirement necessary to load the module + * + * This module requires a core module that should be implemented and + * enabled in Kconfig. + */ +#define module_kconfig(name) modinfo(kconfig, name) + /* * module info database * diff --git a/include/qemu/option.h b/include/qemu/option.h index bbd86e1c4eab..b34982878238 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -144,12 +144,6 @@ void qemu_opts_print_help(QemuOptsList *list, bool print_caption); void qemu_opts_free(QemuOptsList *list); QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list); -QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key, - bool *p_help, Error **errp); -QDict *keyval_parse(const char *params, const char *implied_key, - bool *help, Error **errp); -void keyval_merge(QDict *old, const QDict *new, Error **errp); - G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuOpts, qemu_opts_del) #endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 9f06bf536fb1..bd23a08595b1 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -34,6 +34,18 @@ #include "exec/poison.h" #endif +/* + * HOST_WORDS_BIGENDIAN was replaced with HOST_BIG_ENDIAN. Prevent it from + * creeping back in. + */ +#pragma GCC poison HOST_WORDS_BIGENDIAN + +/* + * TARGET_WORDS_BIGENDIAN was replaced with TARGET_BIG_ENDIAN. Prevent it from + * creeping back in. + */ +#pragma GCC poison TARGET_WORDS_BIGENDIAN + #include "qemu/compiler.h" /* Older versions of C++ don't get definitions of various macros from @@ -63,7 +75,7 @@ QEMU_EXTERN_C int daemon(int, int); #ifdef _WIN32 /* as defined in sdkddkver.h */ #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 /* Vista */ +#define _WIN32_WINNT 0x0601 /* Windows 7 API (should be in sync with glib) */ #endif /* reduces the number of implicitly included headers */ #ifndef WIN32_LEAN_AND_MEAN @@ -157,6 +169,31 @@ extern "C" { #define assert(x) g_assert(x) #endif +/** + * qemu_build_not_reached() + * + * The compiler, during optimization, is expected to prove that a call + * to this function cannot be reached and remove it. If the compiler + * supports QEMU_ERROR, this will be reported at compile time; otherwise + * this will be reported at link time due to the missing symbol. + */ +extern G_NORETURN +void QEMU_ERROR("code path is reachable") + qemu_build_not_reached_always(void); +#if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) +#define qemu_build_not_reached() qemu_build_not_reached_always() +#else +#define qemu_build_not_reached() g_assert_not_reached() +#endif + +/** + * qemu_build_assert() + * + * The compiler, during optimization, is expected to prove that the + * assertion is true. + */ +#define qemu_build_assert(test) while (!(test)) qemu_build_not_reached() + /* * According to waitpid man page: * WCOREDUMP @@ -214,6 +251,14 @@ extern "C" { #define ESHUTDOWN 4099 #endif +#define RETRY_ON_EINTR(expr) \ + (__extension__ \ + ({ typeof(expr) __result; \ + do { \ + __result = (expr); \ + } while (__result == -1 && errno == EINTR); \ + __result; })) + /* time_t may be either 32 or 64 bits depending on the host OS, and * can be either signed or unsigned, so we can't just hardcode a * specific maximum value. This is not a C preprocessor constant, @@ -382,11 +427,6 @@ void qemu_anon_ram_free(void *ptr, size_t size); #define HAVE_CHARDEV_SERIAL 1 #endif -#if defined(__linux__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#define HAVE_CHARDEV_PARPORT 1 -#endif - #if defined(__HAIKU__) #define SIGIO SIGPOLL #endif @@ -419,9 +459,9 @@ extern int madvise(char *, size_t, int); /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */ # define QEMU_VMALLOC_ALIGN (256 * 4096) #elif defined(__linux__) && defined(__sparc__) -# define QEMU_VMALLOC_ALIGN MAX(qemu_real_host_page_size, SHMLBA) +# define QEMU_VMALLOC_ALIGN MAX(qemu_real_host_page_size(), SHMLBA) #else -# define QEMU_VMALLOC_ALIGN qemu_real_host_page_size +# define QEMU_VMALLOC_ALIGN qemu_real_host_page_size() #endif #ifdef CONFIG_POSIX @@ -513,29 +553,18 @@ static inline void qemu_timersub(const struct timeval *val1, #define qemu_timersub timersub #endif -void qemu_set_cloexec(int fd); +ssize_t qemu_write_full(int fd, const void *buf, size_t count) + G_GNUC_WARN_UNUSED_RESULT; -void fips_set_state(bool requested); -bool fips_get_state(void); +void qemu_set_cloexec(int fd); -/* Return a dynamically allocated pathname denoting a file or directory that is - * appropriate for storing local state. - * - * @relative_pathname need not start with a directory separator; one will be - * added automatically. +/* Return a dynamically allocated directory path that is appropriate for storing + * local state. * * The caller is responsible for releasing the value returned with g_free() * after use. */ -char *qemu_get_local_state_pathname(const char *relative_pathname); - -/* Find program directory, and save it for later usage with - * qemu_get_exec_dir(). - * Try OS specific API first, if not working, parse from argv0. */ -void qemu_init_exec_dir(const char *argv0); - -/* Get the saved exec dir. */ -const char *qemu_get_exec_dir(void); +char *qemu_get_local_state_dir(void); /** * qemu_getauxval: @@ -548,8 +577,23 @@ unsigned long qemu_getauxval(unsigned long type); void qemu_set_tty_echo(int fd, bool echo); -void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus, - Error **errp); +typedef struct ThreadContext ThreadContext; + +/** + * qemu_prealloc_mem: + * @fd: the fd mapped into the area, -1 for anonymous memory + * @area: start address of the are to preallocate + * @sz: the size of the area to preallocate + * @max_threads: maximum number of threads to use + * @errp: returns an error if this function fails + * + * Preallocate memory (populate/prefault page tables writable) for the virtual + * memory area starting at @area with the size of @sz. After a successful call, + * each page in the area was faulted in writable at least once, for example, + * after allocating file blocks for mapped files. + */ +void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads, + ThreadContext *tc, Error **errp); /** * qemu_get_pid_name: @@ -578,8 +622,15 @@ pid_t qemu_fork(Error **errp); /* Using intptr_t ensures that qemu_*_page_mask is sign-extended even * when intptr_t is 32-bit and we are aligning a long long. */ -extern uintptr_t qemu_real_host_page_size; -extern intptr_t qemu_real_host_page_mask; +static inline uintptr_t qemu_real_host_page_size(void) +{ + return getpagesize(); +} + +static inline intptr_t qemu_real_host_page_mask(void) +{ + return -(intptr_t)qemu_real_host_page_size(); +} /* * After using getopt or getopt_long, if you need to parse another set @@ -596,15 +647,20 @@ static inline void qemu_reset_optind(void) #endif } +int qemu_fdatasync(int fd); + /** - * qemu_get_host_name: - * @errp: Error object - * - * Operating system agnostic way of querying host name. + * Sync changes made to the memory mapped file back to the backing + * storage. For POSIX compliant systems this will fallback + * to regular msync call. Otherwise it will trigger whole file sync + * (including the metadata case there is no support to skip that otherwise) * - * Returns allocated hostname (caller should free), NULL on failure. + * @addr - start of the memory area to be synced + * @length - length of the are to be synced + * @fd - file descriptor for the file to be synced + * (mandatory only for POSIX non-compliant systems) */ -char *qemu_get_host_name(Error **errp); +int qemu_msync(void *addr, size_t length, int fd); /** * qemu_get_host_physmem: diff --git a/include/qemu/plugin-memory.h b/include/qemu/plugin-memory.h index 0f592267279d..6fd539022ac1 100644 --- a/include/qemu/plugin-memory.h +++ b/include/qemu/plugin-memory.h @@ -9,6 +9,9 @@ #ifndef PLUGIN_MEMORY_H #define PLUGIN_MEMORY_H +#include "exec/cpu-defs.h" +#include "exec/hwaddr.h" + struct qemu_plugin_hwaddr { bool is_io; bool is_store; @@ -37,4 +40,4 @@ struct qemu_plugin_hwaddr { bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, bool is_store, struct qemu_plugin_hwaddr *data); -#endif /* _PLUGIN_MEMORY_H_ */ +#endif /* PLUGIN_MEMORY_H */ diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index 145f8a221acb..a772e141939c 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/qemu-plugin.h b/include/qemu/qemu-plugin.h index 535ddbf0ae30..d0e9d03adfe3 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -7,8 +7,9 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef QEMU_PLUGIN_API_H -#define QEMU_PLUGIN_API_H + +#ifndef QEMU_QEMU_PLUGIN_H +#define QEMU_QEMU_PLUGIN_H #include #include @@ -624,4 +625,4 @@ uint64_t qemu_plugin_end_code(void); */ uint64_t qemu_plugin_entry_code(void); -#endif /* QEMU_PLUGIN_API_H */ +#endif /* QEMU_QEMU_PLUGIN_H */ diff --git a/include/qemu/qemu-progress.h b/include/qemu/qemu-progress.h new file mode 100644 index 000000000000..137e1c316fd0 --- /dev/null +++ b/include/qemu/qemu-progress.h @@ -0,0 +1,8 @@ +#ifndef QEMU_PROGRESS_H +#define QEMU_PROGRESS_H + +void qemu_progress_init(int enabled, float min_skip); +void qemu_progress_end(void); +void qemu_progress_print(float delta, int max); + +#endif /* QEMU_PROGRESS_H */ diff --git a/include/qemu/selfmap.h b/include/qemu/selfmap.h index 80cf920fbadb..3479a2a61862 100644 --- a/include/qemu/selfmap.h +++ b/include/qemu/selfmap.h @@ -41,4 +41,4 @@ GSList *read_self_maps(void); */ void free_self_maps(GSList *info); -#endif /* _SELFMAP_H_ */ +#endif /* SELFMAP_H */ diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 0c34bf23987e..2b0698a7c99c 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -14,12 +14,43 @@ 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); +/* + * A variant of send(2) which handles partial send. + * + * Return the number of bytes transferred over the socket. + * Set errno if fewer than `count' bytes are sent. + * + * This function don't work with non-blocking socket's. + * Any of the possibilities with non-blocking socket's is bad: + * - return a short write (then name is wrong) + * - busy wait adding (errno == EAGAIN) to the loop + */ +ssize_t qemu_send_full(int s, const void *buf, size_t count) + G_GNUC_WARN_UNUSED_RESULT; int socket_set_cork(int fd, int v); int socket_set_nodelay(int fd); -void qemu_set_block(int fd); -int qemu_try_set_nonblock(int fd); -void qemu_set_nonblock(int fd); +void qemu_socket_set_block(int fd); +int qemu_socket_try_set_nonblock(int fd); +void qemu_socket_set_nonblock(int fd); int socket_set_fast_reuse(int fd); #ifdef WIN32 @@ -40,6 +71,7 @@ NetworkAddressFamily inet_netfamily(int family); int unix_listen(const char *path, Error **errp); int unix_connect(const char *path, Error **errp); +char *socket_uri(SocketAddress *addr); SocketAddress *socket_parse(const char *str, Error **errp); int socket_connect(SocketAddress *addr, Error **errp); int socket_listen(SocketAddress *addr, int num, Error **errp); @@ -47,6 +79,8 @@ void socket_listen_cleanup(int fd, Error **errp); int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); /* Old, ipv4 only bits. Don't use for new code. */ +int convert_host_port(struct sockaddr_in *saddr, const char *host, + const char *port, Error **errp); int parse_host_port(struct sockaddr_in *saddr, const char *str, Error **errp); int socket_init(void); @@ -121,5 +155,4 @@ SocketAddress *socket_address_flatten(SocketAddressLegacy *addr); * Return 0 on success. */ int socket_address_parse_named_fd(SocketAddress *addr, Error **errp); - #endif /* QEMU_SOCKETS_H */ diff --git a/include/qemu/thread-context.h b/include/qemu/thread-context.h new file mode 100644 index 000000000000..2ebd6b7fe1d4 --- /dev/null +++ b/include/qemu/thread-context.h @@ -0,0 +1,57 @@ +/* + * QEMU Thread Context + * + * Copyright Red Hat Inc., 2022 + * + * Authors: + * David Hildenbrand + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef SYSEMU_THREAD_CONTEXT_H +#define SYSEMU_THREAD_CONTEXT_H + +#include "qapi/qapi-types-machine.h" +#include "qemu/thread.h" +#include "qom/object.h" + +#define TYPE_THREAD_CONTEXT "thread-context" +OBJECT_DECLARE_TYPE(ThreadContext, ThreadContextClass, + THREAD_CONTEXT) + +struct ThreadContextClass { + ObjectClass parent_class; +}; + +struct ThreadContext { + /* private */ + Object parent; + + /* private */ + unsigned int thread_id; + QemuThread thread; + + /* Semaphore to wait for context thread action. */ + QemuSemaphore sem; + /* Semaphore to wait for action in context thread. */ + QemuSemaphore sem_thread; + /* Mutex to synchronize requests. */ + QemuMutex mutex; + + /* Commands for the thread to execute. */ + int thread_cmd; + void *thread_cmd_data; + + /* CPU affinity bitmap used for initialization. */ + unsigned long *init_cpu_bitmap; + int init_cpu_nbits; +}; + +void thread_context_create_thread(ThreadContext *tc, QemuThread *thread, + const char *name, + void *(*start_routine)(void *), void *arg, + int mode); + +#endif /* SYSEMU_THREAD_CONTEXT_H */ diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h index b792e6ef377b..5f2f3d1386bc 100644 --- a/include/qemu/thread-posix.h +++ b/include/qemu/thread-posix.h @@ -27,14 +27,9 @@ struct QemuCond { }; struct QemuSemaphore { -#ifndef CONFIG_SEM_TIMEDWAIT - pthread_mutex_t lock; - pthread_cond_t cond; + QemuMutex mutex; + QemuCond cond; unsigned int count; -#else - sem_t sem; -#endif - bool initialized; }; struct QemuEvent { diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 460568d67d53..7c6703bce362 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -185,10 +185,14 @@ void qemu_event_destroy(QemuEvent *ev); void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode); +int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus, + unsigned long nbits); +int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus, + unsigned long *nbits); void *qemu_thread_join(QemuThread *thread); void qemu_thread_get_self(QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); -void qemu_thread_exit(void *retval) QEMU_NORETURN; +G_NORETURN void qemu_thread_exit(void *retval); void qemu_thread_naming(bool enable); struct Notifier; @@ -227,7 +231,7 @@ struct QemuSpin { static inline void qemu_spin_init(QemuSpin *spin) { - __sync_lock_release(&spin->value); + qatomic_set(&spin->value, 0); #ifdef CONFIG_TSAN __tsan_mutex_create(spin, __tsan_mutex_not_static); #endif @@ -246,7 +250,7 @@ static inline void qemu_spin_lock(QemuSpin *spin) #ifdef CONFIG_TSAN __tsan_mutex_pre_lock(spin, 0); #endif - while (unlikely(__sync_lock_test_and_set(&spin->value, true))) { + while (unlikely(qatomic_xchg(&spin->value, 1))) { while (qatomic_read(&spin->value)) { cpu_relax(); } @@ -261,7 +265,7 @@ static inline bool qemu_spin_trylock(QemuSpin *spin) #ifdef CONFIG_TSAN __tsan_mutex_pre_lock(spin, __tsan_mutex_try_lock); #endif - bool busy = __sync_lock_test_and_set(&spin->value, true); + bool busy = qatomic_xchg(&spin->value, true); #ifdef CONFIG_TSAN unsigned flags = __tsan_mutex_try_lock; flags |= busy ? __tsan_mutex_try_lock_failed : 0; @@ -280,7 +284,7 @@ static inline void qemu_spin_unlock(QemuSpin *spin) #ifdef CONFIG_TSAN __tsan_mutex_pre_unlock(spin, 0); #endif - __sync_lock_release(&spin->value); + qatomic_store_release(&spin->value, 0); #ifdef CONFIG_TSAN __tsan_mutex_post_unlock(spin, 0); #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 42f4ceb701b1..073abab9988a 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -21,6 +21,7 @@ * Incomplete struct types * Please keep this list in case-insensitive alphabetical order. */ +typedef struct AccelState AccelState; typedef struct AdapterInfo AdapterInfo; typedef struct AddressSpace AddressSpace; typedef struct AioContext AioContext; @@ -41,7 +42,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 +132,9 @@ typedef struct VirtIODevice VirtIODevice; typedef struct Visitor Visitor; typedef struct VMChangeStateEntry VMChangeStateEntry; typedef struct VMStateDescription VMStateDescription; +typedef struct DumpState DumpState; +typedef struct GraphicHwOps GraphicHwOps; +typedef struct QEMUCursor QEMUCursor; /* * Pointer types diff --git a/include/qemu/win_dump_defs.h b/include/qemu/win_dump_defs.h index 145096e8ee79..73a44e2408c2 100644 --- a/include/qemu/win_dump_defs.h +++ b/include/qemu/win_dump_defs.h @@ -11,11 +11,22 @@ #ifndef QEMU_WIN_DUMP_DEFS_H #define QEMU_WIN_DUMP_DEFS_H +typedef struct WinDumpPhyMemRun32 { + uint32_t BasePage; + uint32_t PageCount; +} QEMU_PACKED WinDumpPhyMemRun32; + typedef struct WinDumpPhyMemRun64 { uint64_t BasePage; uint64_t PageCount; } QEMU_PACKED WinDumpPhyMemRun64; +typedef struct WinDumpPhyMemDesc32 { + uint32_t NumberOfRuns; + uint32_t NumberOfPages; + WinDumpPhyMemRun32 Run[86]; +} QEMU_PACKED WinDumpPhyMemDesc32; + typedef struct WinDumpPhyMemDesc64 { uint32_t NumberOfRuns; uint32_t unused; @@ -33,6 +44,39 @@ typedef struct WinDumpExceptionRecord { uint64_t ExceptionInformation[15]; } QEMU_PACKED WinDumpExceptionRecord; +typedef struct WinDumpHeader32 { + char Signature[4]; + char ValidDump[4]; + uint32_t MajorVersion; + uint32_t MinorVersion; + uint32_t DirectoryTableBase; + uint32_t PfnDatabase; + uint32_t PsLoadedModuleList; + uint32_t PsActiveProcessHead; + uint32_t MachineImageType; + uint32_t NumberProcessors; + union { + struct { + uint32_t BugcheckCode; + uint32_t BugcheckParameter1; + uint32_t BugcheckParameter2; + uint32_t BugcheckParameter3; + uint32_t BugcheckParameter4; + }; + uint8_t BugcheckData[20]; + }; + uint8_t VersionUser[32]; + uint32_t reserved0; + uint32_t KdDebuggerDataBlock; + union { + WinDumpPhyMemDesc32 PhysicalMemoryBlock; + uint8_t PhysicalMemoryBlockBuffer[700]; + }; + uint8_t reserved1[3200]; + uint32_t RequiredDumpSpace; + uint8_t reserved2[92]; +} QEMU_PACKED WinDumpHeader32; + typedef struct WinDumpHeader64 { char Signature[4]; char ValidDump[4]; @@ -81,24 +125,48 @@ typedef struct WinDumpHeader64 { uint8_t reserved[4018]; } QEMU_PACKED WinDumpHeader64; +typedef union WinDumpHeader { + struct { + char Signature[4]; + char ValidDump[4]; + }; + WinDumpHeader32 x32; + WinDumpHeader64 x64; +} WinDumpHeader; + #define KDBG_OWNER_TAG_OFFSET64 0x10 #define KDBG_MM_PFN_DATABASE_OFFSET64 0xC0 #define KDBG_KI_BUGCHECK_DATA_OFFSET64 0x88 #define KDBG_KI_PROCESSOR_BLOCK_OFFSET64 0x218 #define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64 0x338 +#define KDBG_OWNER_TAG_OFFSET KDBG_OWNER_TAG_OFFSET64 +#define KDBG_MM_PFN_DATABASE_OFFSET KDBG_MM_PFN_DATABASE_OFFSET64 +#define KDBG_KI_BUGCHECK_DATA_OFFSET KDBG_KI_BUGCHECK_DATA_OFFSET64 +#define KDBG_KI_PROCESSOR_BLOCK_OFFSET KDBG_KI_PROCESSOR_BLOCK_OFFSET64 +#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET KDBG_OFFSET_PRCB_CONTEXT_OFFSET64 + #define VMCOREINFO_ELF_NOTE_HDR_SIZE 24 +#define VMCOREINFO_WIN_DUMP_NOTE_SIZE64 (sizeof(WinDumpHeader64) + \ + VMCOREINFO_ELF_NOTE_HDR_SIZE) +#define VMCOREINFO_WIN_DUMP_NOTE_SIZE32 (sizeof(WinDumpHeader32) + \ + VMCOREINFO_ELF_NOTE_HDR_SIZE) #define WIN_CTX_X64 0x00100000L +#define WIN_CTX_X86 0x00010000L #define WIN_CTX_CTL 0x00000001L #define WIN_CTX_INT 0x00000002L #define WIN_CTX_SEG 0x00000004L #define WIN_CTX_FP 0x00000008L #define WIN_CTX_DBG 0x00000010L +#define WIN_CTX_EXT 0x00000020L + +#define WIN_CTX64_FULL (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP) +#define WIN_CTX64_ALL (WIN_CTX64_FULL | WIN_CTX_SEG | WIN_CTX_DBG) -#define WIN_CTX_FULL (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP) -#define WIN_CTX_ALL (WIN_CTX_FULL | WIN_CTX_SEG | WIN_CTX_DBG) +#define WIN_CTX32_FULL (WIN_CTX_X86 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_SEG) +#define WIN_CTX32_ALL (WIN_CTX32_FULL | WIN_CTX_FP | WIN_CTX_DBG | WIN_CTX_EXT) #define LIVE_SYSTEM_DUMP 0x00000161 @@ -107,7 +175,41 @@ typedef struct WinM128A { int64_t high; } QEMU_ALIGNED(16) WinM128A; -typedef struct WinContext { +typedef struct WinContext32 { + uint32_t ContextFlags; + + uint32_t Dr0; + uint32_t Dr1; + uint32_t Dr2; + uint32_t Dr3; + uint32_t Dr6; + uint32_t Dr7; + + uint8_t FloatSave[112]; + + uint32_t SegGs; + uint32_t SegFs; + uint32_t SegEs; + uint32_t SegDs; + + uint32_t Edi; + uint32_t Esi; + uint32_t Ebx; + uint32_t Edx; + uint32_t Ecx; + uint32_t Eax; + + uint32_t Ebp; + uint32_t Eip; + uint32_t SegCs; + uint32_t EFlags; + uint32_t Esp; + uint32_t SegSs; + + uint8_t ExtendedRegisters[512]; +} QEMU_ALIGNED(16) WinContext32; + +typedef struct WinContext64 { uint64_t PHome[6]; uint32_t ContextFlags; @@ -174,6 +276,11 @@ typedef struct WinContext { uint64_t LastBranchFromRip; uint64_t LastExceptionToRip; uint64_t LastExceptionFromRip; -} QEMU_ALIGNED(16) WinContext; +} QEMU_ALIGNED(16) WinContext64; + +typedef union WinContext { + WinContext32 x32; + WinContext64 x64; +} WinContext; #endif /* QEMU_WIN_DUMP_DEFS_H */ diff --git a/include/qemu/xattr.h b/include/qemu/xattr.h index f1d0f7be74bc..b08a934acc2d 100644 --- a/include/qemu/xattr.h +++ b/include/qemu/xattr.h @@ -25,7 +25,9 @@ # if !defined(ENOATTR) # define ENOATTR ENODATA # endif -# include +# ifndef CONFIG_WIN32 +# include +# endif #endif #endif diff --git a/include/qom/object.h b/include/qom/object.h index 5f3d5b5bf532..ef7258a5e149 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -16,7 +16,6 @@ #include "qapi/qapi-builtin-types.h" #include "qemu/module.h" -#include "qom/object.h" struct TypeImpl; typedef struct TypeImpl *Type; diff --git a/include/scsi/constants.h b/include/scsi/constants.h index 2a32c08b5e9c..6a8bad556a4f 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -225,6 +225,7 @@ #define TYPE_NO_LUN 0x7f /* Mode page codes for mode sense/set */ +#define MODE_PAGE_VENDOR_SPECIFIC 0x00 #define MODE_PAGE_R_W_ERROR 0x01 #define MODE_PAGE_HD_GEOMETRY 0x04 #define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05 @@ -234,6 +235,7 @@ #define MODE_PAGE_FAULT_FAIL 0x1c #define MODE_PAGE_TO_PROTECT 0x1d #define MODE_PAGE_CAPABILITIES 0x2a +#define MODE_PAGE_APPLE_VENDOR 0x30 #define MODE_PAGE_ALLS 0x3f /* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor * of MODE_PAGE_SENSE_POWER */ diff --git a/semihosting/common-semi.h b/include/semihosting/common-semi.h similarity index 96% rename from semihosting/common-semi.h rename to include/semihosting/common-semi.h index 0bfab1c669b6..0a91db7c4149 100644 --- a/semihosting/common-semi.h +++ b/include/semihosting/common-semi.h @@ -34,6 +34,6 @@ #ifndef COMMON_SEMI_H #define COMMON_SEMI_H -target_ulong do_common_semihosting(CPUState *cs); +void do_common_semihosting(CPUState *cs); #endif /* COMMON_SEMI_H */ diff --git a/include/semihosting/console.h b/include/semihosting/console.h index 0238f540f4b1..bd78e5f03fce 100644 --- a/include/semihosting/console.h +++ b/include/semihosting/console.h @@ -12,58 +12,48 @@ #include "cpu.h" /** - * qemu_semihosting_console_outs: - * @env: CPUArchState - * @s: host address of null terminated guest string + * qemu_semihosting_console_read: + * @cs: CPUState + * @buf: host buffer + * @len: buffer size * - * Send a null terminated guest string to the debug console. This may - * be the remote gdb session if a softmmu guest is currently being - * debugged. + * Receive at least one character from debug console. As this call may + * block if no data is available we suspend the CPU and will re-execute the + * instruction when data is there. Therefore two conditions must be met: * - * Returns: number of bytes written. + * - CPUState is synchronized before calling this function + * - pc is only updated once the character is successfully returned + * + * Returns: number of characters read, OR cpu_loop_exit! */ -int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s); +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len); /** - * qemu_semihosting_console_outc: - * @env: CPUArchState - * @s: host address of null terminated guest string + * qemu_semihosting_console_write: + * @buf: host buffer + * @len: buffer size * - * Send single character from guest memory to the debug console. This - * may be the remote gdb session if a softmmu guest is currently being - * debugged. + * Write len bytes from buf to the debug console. * - * Returns: nothing + * Returns: number of bytes written -- this should only ever be short + * on some sort of i/o error. */ -void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c); +int qemu_semihosting_console_write(void *buf, int len); -/** - * qemu_semihosting_console_inc: - * @env: CPUArchState - * - * Receive single character from debug console. This may be the remote - * gdb session if a softmmu guest is currently being debugged. As this - * call may block if no data is available we suspend the CPU and will - * re-execute the instruction when data is there. Therefore two - * conditions must be met: - * - CPUState is synchronized before calling this function - * - pc is only updated once the character is successfully returned +/* + * qemu_semihosting_console_block_until_ready: + * @cs: CPUState * - * Returns: character read OR cpu_loop_exit! + * If no data is available we suspend the CPU and will re-execute the + * instruction when data is available. */ -target_ulong qemu_semihosting_console_inc(CPUArchState *env); +void qemu_semihosting_console_block_until_ready(CPUState *cs); /** - * qemu_semihosting_log_out: - * @s: pointer to string - * @len: length of string - * - * Send a string to the debug output. Unlike console_out these strings - * can't be sent to a remote gdb instance as they don't exist in guest - * memory. + * qemu_semihosting_console_ready: * - * Returns: number of bytes written + * Return true if characters are available for read; does not block. */ -int qemu_semihosting_log_out(const char *s, int len); +bool qemu_semihosting_console_ready(void); #endif /* SEMIHOST_CONSOLE_H */ diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h new file mode 100644 index 000000000000..3d426fedab39 --- /dev/null +++ b/include/semihosting/guestfd.h @@ -0,0 +1,91 @@ +/* + * Hosted file support for semihosting syscalls. + * + * Copyright (c) 2005, 2007 CodeSourcery. + * Copyright (c) 2019 Linaro + * Copyright © 2020 by Keith Packard + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef SEMIHOSTING_GUESTFD_H +#define SEMIHOSTING_GUESTFD_H + +typedef enum GuestFDType { + GuestFDUnused = 0, + GuestFDHost, + GuestFDGDB, + GuestFDStatic, + GuestFDConsole, +} GuestFDType; + +/* + * Guest file descriptors are integer indexes into an array of + * these structures (we will dynamically resize as necessary). + */ +typedef struct GuestFD { + GuestFDType type; + union { + int hostfd; + struct { + const uint8_t *data; + size_t len; + size_t off; + } staticfile; + }; +} GuestFD; + +/* + * For ARM semihosting, we have a separate structure for routing + * data for the console which is outside the guest fd address space. + */ +extern GuestFD console_in_gf; +extern GuestFD console_out_gf; + +/** + * alloc_guestfd: + * + * Allocate an unused GuestFD index. The associated guestfd index + * will still be GuestFDUnused until it is initialized. + */ +int alloc_guestfd(void); + +/** + * dealloc_guestfd: + * @guestfd: GuestFD index + * + * Deallocate a GuestFD index. The associated GuestFD structure + * will be recycled for a subsequent allocation. + */ +void dealloc_guestfd(int guestfd); + +/** + * get_guestfd: + * @guestfd: GuestFD index + * + * Return the GuestFD structure associated with an initialized @guestfd, + * or NULL if it has not been allocated, or hasn't been initialized. + */ +GuestFD *get_guestfd(int guestfd); + +/** + * associate_guestfd: + * @guestfd: GuestFD index + * @hostfd: host file descriptor + * + * Initialize the GuestFD for @guestfd to GuestFDHost using @hostfd. + */ +void associate_guestfd(int guestfd, int hostfd); + +/** + * staticfile_guestfd: + * @guestfd: GuestFD index + * @data: data to be read + * @len: length of @data + * + * Initialize the GuestFD for @guestfd to GuestFDStatic. + * The @len bytes at @data will be returned to the guest on reads. + */ +void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len); + +#endif /* SEMIHOSTING_GUESTFD_H */ diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h index 0c55ade3ac1c..efd2efa25ae9 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; } @@ -51,27 +51,25 @@ static inline const char *semihosting_get_cmdline(void) { return NULL; } - -static inline Chardev *semihosting_get_chardev(void) -{ - return NULL; -} -static inline void qemu_semihosting_console_init(void) -{ -} #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); const char *semihosting_get_cmdline(void); void semihosting_arg_fallback(const char *file, const char *cmd); -Chardev *semihosting_get_chardev(void); /* for vl.c hooks */ void qemu_semihosting_enable(void); int qemu_semihosting_config_options(const char *opt); -void qemu_semihosting_connect_chardevs(void); -void qemu_semihosting_console_init(void); +void qemu_semihosting_chardev_init(void); +void qemu_semihosting_console_init(Chardev *); #endif /* CONFIG_USER_ONLY */ +void qemu_semihosting_guestfd_init(void); #endif /* SEMIHOST_H */ diff --git a/include/semihosting/softmmu-uaccess.h b/include/semihosting/softmmu-uaccess.h new file mode 100644 index 000000000000..4f08dfc09865 --- /dev/null +++ b/include/semihosting/softmmu-uaccess.h @@ -0,0 +1,59 @@ +/* + * Helper routines to provide target memory access for semihosting + * syscalls in system emulation mode. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ + +#ifndef SEMIHOSTING_SOFTMMU_UACCESS_H +#define SEMIHOSTING_SOFTMMU_UACCESS_H + +#include "cpu.h" + +#define get_user_u64(val, addr) \ + ({ uint64_t val_ = 0; \ + int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \ + &val_, sizeof(val_), 0); \ + (val) = tswap64(val_); ret_; }) + +#define get_user_u32(val, addr) \ + ({ uint32_t val_ = 0; \ + int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \ + &val_, sizeof(val_), 0); \ + (val) = tswap32(val_); ret_; }) + +#define get_user_u8(val, addr) \ + ({ uint8_t val_ = 0; \ + int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \ + &val_, sizeof(val_), 0); \ + (val) = val_; ret_; }) + +#define get_user_ual(arg, p) get_user_u32(arg, p) + +#define put_user_u64(val, addr) \ + ({ uint64_t val_ = tswap64(val); \ + cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); }) + +#define put_user_u32(val, addr) \ + ({ uint32_t val_ = tswap32(val); \ + cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); }) + +#define put_user_ual(arg, p) put_user_u32(arg, p) + +void *softmmu_lock_user(CPUArchState *env, target_ulong addr, + target_ulong len, bool copy); +#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy) + +char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr); +#define lock_user_string(p) softmmu_lock_user_string(env, p) + +void softmmu_unlock_user(CPUArchState *env, void *p, + target_ulong addr, target_ulong len); +#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) + +ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr); +#define target_strlen(p) softmmu_strlen_user(env, p) + +#endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */ diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h new file mode 100644 index 000000000000..3a5ec229ebfb --- /dev/null +++ b/include/semihosting/syscalls.h @@ -0,0 +1,75 @@ +/* + * Syscall implementations for semihosting. + * + * Copyright (c) 2022 Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef SEMIHOSTING_SYSCALLS_H +#define SEMIHOSTING_SYSCALLS_H + +/* + * Argument loading from the guest is performed by the caller; + * results are returned via the 'complete' callback. + * + * String operands are in address/len pairs. The len argument may be 0 + * (when the semihosting abi does not already provide the length), + * or non-zero (where it should include the terminating zero). + */ + +typedef struct GuestFD GuestFD; + +void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + int gdb_flags, int mode); + +void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, + int fd); + +void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, target_ulong buf, target_ulong len); + +void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len); + +void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, target_ulong buf, target_ulong len); + +void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len); + +void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, int64_t off, int gdb_whence); + +void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, + int fd); + +void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb, + gdb_syscall_complete_cb flen_cb, + int fd, target_ulong fstat_addr); + +void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, target_ulong addr); + +void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + target_ulong addr); + +void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len); + +void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong oname, target_ulong oname_len, + target_ulong nname, target_ulong nname_len); + +void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong cmd, target_ulong cmd_len); + +void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong tv_addr, target_ulong tz_addr); + +void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, GIOCondition cond, int timeout); + +#endif /* SEMIHOSTING_SYSCALLS_H */ diff --git a/include/standard-headers/asm-m68k/bootinfo-virt.h b/include/standard-headers/asm-m68k/bootinfo-virt.h index 81be1e092497..75ac6bbd7d73 100644 --- a/include/standard-headers/asm-m68k/bootinfo-virt.h +++ b/include/standard-headers/asm-m68k/bootinfo-virt.h @@ -13,6 +13,9 @@ #define BI_VIRT_VIRTIO_BASE 0x8004 #define BI_VIRT_CTRL_BASE 0x8005 +/* No longer used -- replaced with BI_RNG_SEED -- but don't reuse this index: + * #define BI_VIRT_RNG_SEED 0x8006 */ + #define VIRT_BOOTI_VERSION MK_BI_VERSION(2, 0) #endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */ diff --git a/include/standard-headers/asm-m68k/bootinfo.h b/include/standard-headers/asm-m68k/bootinfo.h index 7b790e8ec8d6..b7a8dd2514fe 100644 --- a/include/standard-headers/asm-m68k/bootinfo.h +++ b/include/standard-headers/asm-m68k/bootinfo.h @@ -57,7 +57,13 @@ struct mem_info { /* (struct mem_info) */ #define BI_COMMAND_LINE 0x0007 /* kernel command line parameters */ /* (string) */ - +/* + * A random seed used to initialize the RNG. Record format: + * + * - length [ 2 bytes, 16-bit big endian ] + * - seed data [ `length` bytes, padded to preserve 4-byte struct alignment ] + */ +#define BI_RNG_SEED 0x0008 /* * Linux/m68k Architectures (BI_MACHTYPE) diff --git a/include/standard-headers/asm-x86/bootparam.h b/include/standard-headers/asm-x86/bootparam.h index 072e2ed5463c..0b06d2bff1b9 100644 --- a/include/standard-headers/asm-x86/bootparam.h +++ b/include/standard-headers/asm-x86/bootparam.h @@ -10,11 +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 4888f85f6955..48b620cbef69 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 38d5a4cd6ede..4537da20cc0a 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-event-codes.h b/include/standard-headers/linux/input-event-codes.h index b5e86b40abdc..50790aee5ac7 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -278,7 +278,8 @@ #define KEY_PAUSECD 201 #define KEY_PROG3 202 #define KEY_PROG4 203 -#define KEY_DASHBOARD 204 /* AL Dashboard */ +#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */ +#define KEY_DASHBOARD KEY_ALL_APPLICATIONS #define KEY_SUSPEND 205 #define KEY_CLOSE 206 /* AC Close */ #define KEY_PLAY 207 @@ -612,6 +613,7 @@ #define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */ #define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ #define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ +#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ @@ -660,6 +662,27 @@ /* Select an area of screen to be copied */ #define KEY_SELECTIVE_SCREENSHOT 0x27a +/* Move the focus to the next or previous user controllable element within a UI container */ +#define KEY_NEXT_ELEMENT 0x27b +#define KEY_PREVIOUS_ELEMENT 0x27c + +/* Toggle Autopilot engagement */ +#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d + +/* Shortcut Keys */ +#define KEY_MARK_WAYPOINT 0x27e +#define KEY_SOS 0x27f +#define KEY_NAV_CHART 0x280 +#define KEY_FISHING_CHART 0x281 +#define KEY_SINGLE_RANGE_RADAR 0x282 +#define KEY_DUAL_RANGE_RADAR 0x283 +#define KEY_RADAR_OVERLAY 0x284 +#define KEY_TRADITIONAL_SONAR 0x285 +#define KEY_CLEARVU_SONAR 0x286 +#define KEY_SIDEVU_SONAR 0x287 +#define KEY_NAV_INFO 0x288 +#define KEY_BRIGHTNESS_MENU 0x289 + /* * Some keyboards have keys which do not have a defined meaning, these keys * are intended to be programmed / bound to macros by the user. For most diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h index 7822c2417849..942ea6aaa977 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 bee1a9ed6e66..57b8e2ffb1dd 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 0bd2684a2ae4..c41a73fe36ec 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 f5604fc5fb15..da61dee98c5a 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 22e3a85f6760..965ee6ae237e 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 @@ -80,6 +80,12 @@ /* This feature indicates support for the packed virtqueue layout. */ #define VIRTIO_F_RING_PACKED 34 +/* + * Inorder feature indicates that all buffers are used by the device + * in the same order in which they have been made available. + */ +#define VIRTIO_F_IN_ORDER 35 + /* * This feature indicates that memory accesses by the driver and the * device are ordered in a way described by the platform. @@ -90,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_crypto.h b/include/standard-headers/linux/virtio_crypto.h index 5ff0b4ee5921..68066dafb6dd 100644 --- a/include/standard-headers/linux/virtio_crypto.h +++ b/include/standard-headers/linux/virtio_crypto.h @@ -37,6 +37,7 @@ #define VIRTIO_CRYPTO_SERVICE_HASH 1 #define VIRTIO_CRYPTO_SERVICE_MAC 2 #define VIRTIO_CRYPTO_SERVICE_AEAD 3 +#define VIRTIO_CRYPTO_SERVICE_AKCIPHER 4 #define VIRTIO_CRYPTO_OPCODE(service, op) (((service) << 8) | (op)) @@ -57,6 +58,10 @@ struct virtio_crypto_ctrl_header { VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02) #define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03) +#define VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x04) +#define VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x05) uint32_t opcode; uint32_t algo; uint32_t flag; @@ -180,6 +185,58 @@ struct virtio_crypto_aead_create_session_req { uint8_t padding[32]; }; +struct virtio_crypto_rsa_session_para { +#define VIRTIO_CRYPTO_RSA_RAW_PADDING 0 +#define VIRTIO_CRYPTO_RSA_PKCS1_PADDING 1 + uint32_t padding_algo; + +#define VIRTIO_CRYPTO_RSA_NO_HASH 0 +#define VIRTIO_CRYPTO_RSA_MD2 1 +#define VIRTIO_CRYPTO_RSA_MD3 2 +#define VIRTIO_CRYPTO_RSA_MD4 3 +#define VIRTIO_CRYPTO_RSA_MD5 4 +#define VIRTIO_CRYPTO_RSA_SHA1 5 +#define VIRTIO_CRYPTO_RSA_SHA256 6 +#define VIRTIO_CRYPTO_RSA_SHA384 7 +#define VIRTIO_CRYPTO_RSA_SHA512 8 +#define VIRTIO_CRYPTO_RSA_SHA224 9 + uint32_t hash_algo; +}; + +struct virtio_crypto_ecdsa_session_para { +#define VIRTIO_CRYPTO_CURVE_UNKNOWN 0 +#define VIRTIO_CRYPTO_CURVE_NIST_P192 1 +#define VIRTIO_CRYPTO_CURVE_NIST_P224 2 +#define VIRTIO_CRYPTO_CURVE_NIST_P256 3 +#define VIRTIO_CRYPTO_CURVE_NIST_P384 4 +#define VIRTIO_CRYPTO_CURVE_NIST_P521 5 + uint32_t curve_id; + uint32_t padding; +}; + +struct virtio_crypto_akcipher_session_para { +#define VIRTIO_CRYPTO_NO_AKCIPHER 0 +#define VIRTIO_CRYPTO_AKCIPHER_RSA 1 +#define VIRTIO_CRYPTO_AKCIPHER_DSA 2 +#define VIRTIO_CRYPTO_AKCIPHER_ECDSA 3 + uint32_t algo; + +#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC 1 +#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE 2 + uint32_t keytype; + uint32_t keylen; + + union { + struct virtio_crypto_rsa_session_para rsa; + struct virtio_crypto_ecdsa_session_para ecdsa; + } u; +}; + +struct virtio_crypto_akcipher_create_session_req { + struct virtio_crypto_akcipher_session_para para; + uint8_t padding[36]; +}; + struct virtio_crypto_alg_chain_session_para { #define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1 #define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2 @@ -247,6 +304,8 @@ struct virtio_crypto_op_ctrl_req { mac_create_session; struct virtio_crypto_aead_create_session_req aead_create_session; + struct virtio_crypto_akcipher_create_session_req + akcipher_create_session; struct virtio_crypto_destroy_session_req destroy_session; uint8_t padding[56]; @@ -266,6 +325,14 @@ struct virtio_crypto_op_header { VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00) #define VIRTIO_CRYPTO_AEAD_DECRYPT \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01) +#define VIRTIO_CRYPTO_AKCIPHER_ENCRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x00) +#define VIRTIO_CRYPTO_AKCIPHER_DECRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x01) +#define VIRTIO_CRYPTO_AKCIPHER_SIGN \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x02) +#define VIRTIO_CRYPTO_AKCIPHER_VERIFY \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x03) uint32_t opcode; /* algo should be service-specific algorithms */ uint32_t algo; @@ -390,6 +457,16 @@ struct virtio_crypto_aead_data_req { uint8_t padding[32]; }; +struct virtio_crypto_akcipher_para { + uint32_t src_data_len; + uint32_t dst_data_len; +}; + +struct virtio_crypto_akcipher_data_req { + struct virtio_crypto_akcipher_para para; + uint8_t padding[40]; +}; + /* The request of the data virtqueue's packet */ struct virtio_crypto_op_data_req { struct virtio_crypto_op_header header; @@ -399,6 +476,7 @@ struct virtio_crypto_op_data_req { struct virtio_crypto_hash_data_req hash_req; struct virtio_crypto_mac_data_req mac_req; struct virtio_crypto_aead_data_req aead_req; + struct virtio_crypto_akcipher_data_req akcipher_req; uint8_t padding[48]; } u; }; @@ -408,6 +486,8 @@ struct virtio_crypto_op_data_req { #define VIRTIO_CRYPTO_BADMSG 2 #define VIRTIO_CRYPTO_NOTSUPP 3 #define VIRTIO_CRYPTO_INVSESS 4 /* Invalid session id */ +#define VIRTIO_CRYPTO_NOSPC 5 /* no free session ID */ +#define VIRTIO_CRYPTO_KEY_REJECTED 6 /* Signature verification failed */ /* The accelerator hardware is ready */ #define VIRTIO_CRYPTO_S_HW_READY (1 << 0) @@ -438,7 +518,7 @@ struct virtio_crypto_config { uint32_t max_cipher_key_len; /* Maximum length of authenticated key */ uint32_t max_auth_key_len; - uint32_t reserve; + uint32_t akcipher_algo; /* Maximum size of each crypto request's content */ uint64_t max_size; }; diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h index 80d76b75bccd..7aa2eb766205 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 e0a070518f39..42c68caf719d 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 db7a8e2fcbf2..be912cfc957c 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 0fa0e1067ffe..22f6eb8ca710 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-blocker.h b/include/sysemu/accel-blocker.h new file mode 100644 index 000000000000..72020529ef35 --- /dev/null +++ b/include/sysemu/accel-blocker.h @@ -0,0 +1,56 @@ +/* + * Accelerator blocking API, to prevent new ioctls from starting and wait the + * running ones finish. + * This mechanism differs from pause/resume_all_vcpus() in that it does not + * release the BQL. + * + * Copyright (c) 2022 Red Hat Inc. + * + * Author: Emanuele Giuseppe Esposito + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef ACCEL_BLOCKER_H +#define ACCEL_BLOCKER_H + +#include "qemu/osdep.h" +#include "sysemu/cpus.h" + +extern void accel_blocker_init(void); + +/* + * accel_{cpu_}ioctl_begin/end: + * Mark when ioctl is about to run or just finished. + * + * accel_{cpu_}ioctl_begin will block after accel_ioctl_inhibit_begin() is + * called, preventing new ioctls to run. They will continue only after + * accel_ioctl_inibith_end(). + */ +extern void accel_ioctl_begin(void); +extern void accel_ioctl_end(void); +extern void accel_cpu_ioctl_begin(CPUState *cpu); +extern void accel_cpu_ioctl_end(CPUState *cpu); + +/* + * accel_ioctl_inhibit_begin: start critical section + * + * This function makes sure that: + * 1) incoming accel_{cpu_}ioctl_begin() calls block + * 2) wait that all ioctls that were already running reach + * accel_{cpu_}ioctl_end(), kicking vcpus if necessary. + * + * This allows the caller to access shared data or perform operations without + * worrying of concurrent vcpus accesses. + */ +extern void accel_ioctl_inhibit_begin(void); + +/* + * accel_ioctl_inhibit_end: end critical section started by + * accel_ioctl_inhibit_begin() + * + * This function allows blocked accel_{cpu_}ioctl_begin() to continue. + */ +extern void accel_ioctl_inhibit_end(void); + +#endif /* ACCEL_BLOCKER_H */ diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h index 6013c9444cc3..8cc7996deffd 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" @@ -38,11 +39,18 @@ struct AccelOpsClass { void (*synchronize_post_init)(CPUState *cpu); void (*synchronize_state)(CPUState *cpu); void (*synchronize_pre_loadvm)(CPUState *cpu); + void (*synchronize_pre_resume)(bool step_pending); void (*handle_interrupt)(CPUState *cpu, int mask); 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/arch_init.h b/include/sysemu/arch_init.h index 79c2591425f7..8850cb1a14b9 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -24,6 +24,7 @@ enum { QEMU_ARCH_RX = (1 << 20), QEMU_ARCH_AVR = (1 << 21), QEMU_ARCH_HEXAGON = (1 << 22), + QEMU_ARCH_LOONGARCH = (1 << 23), }; extern const uint32_t arch_type; diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h index 2e93a746798e..6858e39cb65f 100644 --- a/include/sysemu/block-backend-global-state.h +++ b/include/sysemu/block-backend-global-state.h @@ -10,8 +10,8 @@ * or later. See the COPYING.LIB file in the top-level directory. */ -#ifndef BLOCK_BACKEND_GS_H -#define BLOCK_BACKEND_GS_H +#ifndef BLOCK_BACKEND_GLOBAL_STATE_H +#define BLOCK_BACKEND_GLOBAL_STATE_H #include "block-backend-common.h" @@ -106,11 +106,11 @@ void blk_io_limits_enable(BlockBackend *blk, const char *group); void blk_io_limits_update_group(BlockBackend *blk, const char *group); void blk_set_force_allow_inactivate(BlockBackend *blk); -void blk_register_buf(BlockBackend *blk, void *host, size_t size); -void blk_unregister_buf(BlockBackend *blk, void *host); +bool blk_register_buf(BlockBackend *blk, void *host, size_t size, Error **errp); +void blk_unregister_buf(BlockBackend *blk, void *host, size_t size); const BdrvChild *blk_root(BlockBackend *blk); int blk_make_empty(BlockBackend *blk, Error **errp); -#endif /* BLOCK_BACKEND_GS_H */ +#endif /* BLOCK_BACKEND_GLOBAL_STATE_H */ diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 6517c3929520..7ec6d978d408 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -72,7 +72,6 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, void blk_iostatus_set_err(BlockBackend *blk, int error); int blk_get_max_iov(BlockBackend *blk); int blk_get_max_hw_iov(BlockBackend *blk); -void blk_set_guest_block_size(BlockBackend *blk, int align); void blk_io_plug(BlockBackend *blk); void blk_io_unplug(BlockBackend *blk); @@ -93,6 +92,15 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, int64_t bytes, BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); +int coroutine_fn blk_co_block_status_above(BlockBackend *blk, + BlockDriverState *base, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, + BlockDriverState **file); +int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk, + BlockDriverState *base, + bool include_base, int64_t offset, + int64_t bytes, int64_t *pnum); /* * "I/O or GS" API functions. These functions can run without @@ -102,60 +110,79 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, * the "I/O or GS" API. */ -int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes); -int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, - BdrvRequestFlags flags); +int co_wrapper_mixed blk_pread(BlockBackend *blk, int64_t offset, + int64_t bytes, void *buf, + BdrvRequestFlags flags); +int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, int64_t bytes, + void *buf, BdrvRequestFlags flags); + +int co_wrapper_mixed blk_preadv(BlockBackend *blk, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags); int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags); -int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, - int64_t bytes, - QEMUIOVector *qiov, size_t qiov_offset, + +int co_wrapper_mixed blk_preadv_part(BlockBackend *blk, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + size_t qiov_offset, BdrvRequestFlags flags); +int coroutine_fn blk_co_preadv_part(BlockBackend *blk, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + size_t qiov_offset, BdrvRequestFlags flags); + +int co_wrapper_mixed blk_pwrite(BlockBackend *blk, int64_t offset, + int64_t bytes, const void *buf, + BdrvRequestFlags flags); +int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, int64_t bytes, + const void *buf, BdrvRequestFlags flags); + +int co_wrapper_mixed blk_pwritev(BlockBackend *blk, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags); int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags); -static inline int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, - int64_t bytes, void *buf, - BdrvRequestFlags flags) -{ - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); - IO_OR_GS_CODE(); - - assert(bytes <= SIZE_MAX); - - return blk_co_preadv(blk, offset, bytes, &qiov, flags); -} - -static inline int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, - int64_t bytes, void *buf, - BdrvRequestFlags flags) -{ - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); - IO_OR_GS_CODE(); +int co_wrapper_mixed blk_pwritev_part(BlockBackend *blk, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + size_t qiov_offset, + BdrvRequestFlags flags); +int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, + int64_t bytes, + QEMUIOVector *qiov, size_t qiov_offset, + BdrvRequestFlags flags); - assert(bytes <= SIZE_MAX); +int co_wrapper_mixed blk_pwrite_compressed(BlockBackend *blk, + int64_t offset, int64_t bytes, + const void *buf); +int coroutine_fn blk_co_pwrite_compressed(BlockBackend *blk, int64_t offset, + int64_t bytes, const void *buf); - return blk_co_pwritev(blk, offset, bytes, &qiov, flags); -} +int co_wrapper_mixed blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, + int64_t bytes, + BdrvRequestFlags flags); +int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, + int64_t bytes, BdrvRequestFlags flags); +int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset, + int64_t bytes); int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); +int co_wrapper_mixed blk_flush(BlockBackend *blk); int coroutine_fn blk_co_flush(BlockBackend *blk); -int blk_flush(BlockBackend *blk); - -int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf); -int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, - int64_t bytes); -int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); -int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, - int64_t bytes, BdrvRequestFlags flags); -int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, - int64_t bytes, BdrvRequestFlags flags); -int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, - PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); +int co_wrapper_mixed blk_ioctl(BlockBackend *blk, unsigned long int req, + void *buf); +int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req, + void *buf); + +int co_wrapper_mixed blk_truncate(BlockBackend *blk, int64_t offset, + bool exact, PreallocMode prealloc, + BdrvRequestFlags flags, Error **errp); +int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact, + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp); #endif /* BLOCK_BACKEND_IO_H */ diff --git a/include/sysemu/block-ram-registrar.h b/include/sysemu/block-ram-registrar.h new file mode 100644 index 000000000000..d8b2f7942ba1 --- /dev/null +++ b/include/sysemu/block-ram-registrar.h @@ -0,0 +1,37 @@ +/* + * BlockBackend RAM Registrar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef BLOCK_RAM_REGISTRAR_H +#define BLOCK_RAM_REGISTRAR_H + +#include "exec/ramlist.h" + +/** + * struct BlockRAMRegistrar: + * + * Keeps RAMBlock memory registered with a BlockBackend using + * blk_register_buf() including hotplugged memory. + * + * Emulated devices or other BlockBackend users initialize a BlockRAMRegistrar + * with blk_ram_registrar_init() before submitting I/O requests with the + * BDRV_REQ_REGISTERED_BUF flag set. + */ +typedef struct { + BlockBackend *blk; + RAMBlockNotifier notifier; + bool ok; +} BlockRAMRegistrar; + +void blk_ram_registrar_init(BlockRAMRegistrar *r, BlockBackend *blk); +void blk_ram_registrar_destroy(BlockRAMRegistrar *r); + +/* Have all RAMBlocks been registered successfully? */ +static inline bool blk_ram_registrar_ok(BlockRAMRegistrar *r) +{ + return r->ok; +} + +#endif /* BLOCK_RAM_REGISTRAR_H */ diff --git a/include/sysemu/cpu-timers.h b/include/sysemu/cpu-timers.h index ed6ee5c46ccd..2e786fe7fb14 100644 --- a/include/sysemu/cpu-timers.h +++ b/include/sysemu/cpu-timers.h @@ -59,6 +59,7 @@ int64_t icount_round(int64_t count); /* if the CPUs are idle, start accounting real time to virtual clock. */ void icount_start_warp_timer(void); void icount_account_warp_timer(void); +void icount_notify_exit(void); /* * CPU Ticks and Clock diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index b5c87d48b34b..1bace3379bbe 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/cryptodev.h b/include/sysemu/cryptodev.h index f4d4057d4da6..cf9b3f07fe84 100644 --- a/include/sysemu/cryptodev.h +++ b/include/sysemu/cryptodev.h @@ -50,13 +50,13 @@ typedef struct CryptoDevBackendClient enum CryptoDevBackendAlgType { CRYPTODEV_BACKEND_ALG_SYM, + CRYPTODEV_BACKEND_ALG_ASYM, CRYPTODEV_BACKEND_ALG__MAX, }; /** * CryptoDevBackendSymSessionInfo: * - * @op_code: operation code (refer to virtio_crypto.h) * @cipher_alg: algorithm type of CIPHER * @key_len: byte length of cipher key * @hash_alg: algorithm type of HASH/MAC @@ -74,7 +74,6 @@ enum CryptoDevBackendAlgType { */ typedef struct CryptoDevBackendSymSessionInfo { /* corresponding with virtio crypto spec */ - uint32_t op_code; uint32_t cipher_alg; uint32_t key_len; uint32_t hash_alg; @@ -89,11 +88,37 @@ typedef struct CryptoDevBackendSymSessionInfo { uint8_t *auth_key; } CryptoDevBackendSymSessionInfo; +/** + * CryptoDevBackendAsymSessionInfo: + */ +typedef struct CryptoDevBackendRsaPara { + uint32_t padding_algo; + uint32_t hash_algo; +} CryptoDevBackendRsaPara; + +typedef struct CryptoDevBackendAsymSessionInfo { + /* corresponding with virtio crypto spec */ + uint32_t algo; + uint32_t keytype; + uint32_t keylen; + uint8_t *key; + union { + CryptoDevBackendRsaPara rsa; + } u; +} CryptoDevBackendAsymSessionInfo; + +typedef struct CryptoDevBackendSessionInfo { + uint32_t op_code; + union { + CryptoDevBackendSymSessionInfo sym_sess_info; + CryptoDevBackendAsymSessionInfo asym_sess_info; + } u; + uint64_t session_id; +} CryptoDevBackendSessionInfo; + /** * CryptoDevBackendSymOpInfo: * - * @session_id: session index which was previously - * created by cryptodev_backend_sym_create_session() * @aad_len: byte length of additional authenticated data * @iv_len: byte length of initialization vector or counter * @src_len: byte length of source data @@ -119,7 +144,6 @@ typedef struct CryptoDevBackendSymSessionInfo { * */ typedef struct CryptoDevBackendSymOpInfo { - uint64_t session_id; uint32_t aad_len; uint32_t iv_len; uint32_t src_len; @@ -138,27 +162,64 @@ typedef struct CryptoDevBackendSymOpInfo { uint8_t data[]; } CryptoDevBackendSymOpInfo; + +/** + * CryptoDevBackendAsymOpInfo: + * + * @src_len: byte length of source data + * @dst_len: byte length of destination data + * @src: point to the source data + * @dst: point to the destination data + * + */ +typedef struct CryptoDevBackendAsymOpInfo { + uint32_t src_len; + uint32_t dst_len; + uint8_t *src; + uint8_t *dst; +} CryptoDevBackendAsymOpInfo; + +typedef struct CryptoDevBackendOpInfo { + enum CryptoDevBackendAlgType algtype; + uint32_t op_code; + uint64_t session_id; + union { + CryptoDevBackendSymOpInfo *sym_op_info; + CryptoDevBackendAsymOpInfo *asym_op_info; + } u; +} CryptoDevBackendOpInfo; + +typedef void (*CryptoDevCompletionFunc) (void *opaque, int ret); struct CryptoDevBackendClass { ObjectClass parent_class; void (*init)(CryptoDevBackend *backend, Error **errp); void (*cleanup)(CryptoDevBackend *backend, Error **errp); - int64_t (*create_session)(CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, - uint32_t queue_index, Error **errp); + int (*create_session)(CryptoDevBackend *backend, + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque); + int (*close_session)(CryptoDevBackend *backend, - uint64_t session_id, - uint32_t queue_index, Error **errp); - int (*do_sym_op)(CryptoDevBackend *backend, - CryptoDevBackendSymOpInfo *op_info, - uint32_t queue_index, Error **errp); + uint64_t session_id, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque); + + int (*do_op)(CryptoDevBackend *backend, + CryptoDevBackendOpInfo *op_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque); }; typedef enum CryptoDevBackendOptionsType { CRYPTODEV_BACKEND_TYPE_NONE = 0, CRYPTODEV_BACKEND_TYPE_BUILTIN = 1, CRYPTODEV_BACKEND_TYPE_VHOST_USER = 2, + CRYPTODEV_BACKEND_TYPE_LKCF = 3, CRYPTODEV_BACKEND_TYPE__MAX, } CryptoDevBackendOptionsType; @@ -190,6 +251,7 @@ struct CryptoDevBackendConf { uint32_t mac_algo_l; uint32_t mac_algo_h; uint32_t aead_algo; + uint32_t akcipher_algo; /* Maximum length of cipher key */ uint32_t max_cipher_key_len; /* Maximum length of authenticated key */ @@ -247,55 +309,69 @@ void cryptodev_backend_cleanup( Error **errp); /** - * cryptodev_backend_sym_create_session: + * cryptodev_backend_create_session: * @backend: the cryptodev backend object * @sess_info: parameters needed by session creating * @queue_index: queue index of cryptodev backend client * @errp: pointer to a NULL-initialized error object + * @cb: callback when session create is compeleted + * @opaque: parameter passed to callback * - * Create a session for symmetric algorithms + * Create a session for symmetric/asymmetric algorithms * - * Returns: session id on success, or -1 on error + * Returns: 0 for success and cb will be called when creation is completed, + * negative value for error, and cb will not be called. */ -int64_t cryptodev_backend_sym_create_session( +int cryptodev_backend_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, - uint32_t queue_index, Error **errp); + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque); /** - * cryptodev_backend_sym_close_session: + * cryptodev_backend_close_session: * @backend: the cryptodev backend object * @session_id: the session id * @queue_index: queue index of cryptodev backend client * @errp: pointer to a NULL-initialized error object + * @cb: callback when session create is compeleted + * @opaque: parameter passed to callback * - * Close a session for symmetric algorithms which was previously - * created by cryptodev_backend_sym_create_session() + * Close a session for which was previously + * created by cryptodev_backend_create_session() * - * Returns: 0 on success, or Negative on error + * Returns: 0 for success and cb will be called when creation is completed, + * negative value for error, and cb will not be called. */ -int cryptodev_backend_sym_close_session( +int cryptodev_backend_close_session( CryptoDevBackend *backend, uint64_t session_id, - uint32_t queue_index, Error **errp); + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque); /** * cryptodev_backend_crypto_operation: * @backend: the cryptodev backend object - * @opaque: pointer to a VirtIOCryptoReq object + * @opaque1: pointer to a VirtIOCryptoReq object * @queue_index: queue index of cryptodev backend client * @errp: pointer to a NULL-initialized error object + * @cb: callbacks when operation is completed + * @opaque2: parameter passed to cb * * Do crypto operation, such as encryption and * decryption * - * Returns: VIRTIO_CRYPTO_OK on success, - * or -VIRTIO_CRYPTO_* on error + * Returns: 0 for success and cb will be called when creation is completed, + * negative value for error, and cb will not be called. */ int cryptodev_backend_crypto_operation( CryptoDevBackend *backend, - void *opaque, - uint32_t queue_index, Error **errp); + void *opaque1, + uint32_t queue_index, + CryptoDevCompletionFunc cb, + void *opaque2); /** * cryptodev_backend_set_used: diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index ef060a97590e..ca5339beae8e 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -136,6 +136,7 @@ int qemu_fdt_add_path(void *fdt, const char *path); } while (0) void qemu_fdt_dumpdtb(void *fdt, int size); +void hmp_dumpdtb(Monitor *mon, const QDict *qdict); /** * qemu_fdt_setprop_sized_cells_from_array: @@ -196,6 +197,15 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt, qdt_tmp); \ }) + +/** + * qemu_fdt_randomize_seeds: + * @fdt: device tree blob + * + * Re-randomize all "rng-seed" properties with new seeds. + */ +void qemu_fdt_randomize_seeds(void *fdt); + #define FDT_PCI_RANGE_RELOCATABLE 0x80000000 #define FDT_PCI_RANGE_PREFETCHABLE 0x40000000 #define FDT_PCI_RANGE_ALIASED 0x20000000 diff --git a/include/sysemu/dirtylimit.h b/include/sysemu/dirtylimit.h new file mode 100644 index 000000000000..8d2c1f3a6b9c --- /dev/null +++ b/include/sysemu/dirtylimit.h @@ -0,0 +1,37 @@ +/* + * Dirty page rate limit common functions + * + * Copyright (c) 2022 CHINA TELECOM CO.,LTD. + * + * Authors: + * Hyman Huang(黄勇) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_DIRTYRLIMIT_H +#define QEMU_DIRTYRLIMIT_H + +#define DIRTYLIMIT_CALC_TIME_MS 1000 /* 1000ms */ + +int64_t vcpu_dirty_rate_get(int cpu_index); +void vcpu_dirty_rate_stat_start(void); +void vcpu_dirty_rate_stat_stop(void); +void vcpu_dirty_rate_stat_initialize(void); +void vcpu_dirty_rate_stat_finalize(void); + +void dirtylimit_state_lock(void); +void dirtylimit_state_unlock(void); +void dirtylimit_state_initialize(void); +void dirtylimit_state_finalize(void); +bool dirtylimit_in_service(void); +bool dirtylimit_vcpu_index_valid(int cpu_index); +void dirtylimit_process(void); +void dirtylimit_change(bool start); +void dirtylimit_set_vcpu(int cpu_index, + uint64_t quota, + bool enable); +void dirtylimit_set_all(uint64_t quota, + bool enable); +void dirtylimit_vcpu_execute(CPUState *cpu); +#endif diff --git a/include/sysemu/dirtyrate.h b/include/sysemu/dirtyrate.h new file mode 100644 index 000000000000..20813f303fc5 --- /dev/null +++ b/include/sysemu/dirtyrate.h @@ -0,0 +1,30 @@ +/* + * dirty page rate helper functions + * + * Copyright (c) 2022 CHINA TELECOM CO.,LTD. + * + * Authors: + * Hyman Huang(黄勇) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_DIRTYRATE_H +#define QEMU_DIRTYRATE_H + +#include "qapi/qapi-types-migration.h" + +typedef struct VcpuStat { + int nvcpu; /* number of vcpu */ + DirtyRateVcpu *rates; /* array of dirty rate for each vcpu */ +} VcpuStat; + +int64_t vcpu_calculate_dirtyrate(int64_t calc_time_ms, + VcpuStat *stat, + unsigned int flag, + bool one_shot); + +void global_dirty_log_change(unsigned int flag, + bool start); +#endif diff --git a/include/sysemu/dump-arch.h b/include/sysemu/dump-arch.h index e25b02e99013..59bbc9be38c9 100644 --- a/include/sysemu/dump-arch.h +++ b/include/sysemu/dump-arch.h @@ -21,6 +21,9 @@ typedef struct ArchDumpInfo { uint32_t page_size; /* The target's page size. If it's variable and * unknown, then this should be the maximum. */ uint64_t phys_base; /* The target's physmem base. */ + void (*arch_sections_add_fn)(DumpState *s); + uint64_t (*arch_sections_write_hdr_fn)(DumpState *s, uint8_t *buff); + int (*arch_sections_write_fn)(DumpState *s, uint8_t *buff); } ArchDumpInfo; struct GuestPhysBlockList; /* memory_mapping.h */ diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 250143cb5a71..7008d43d04ee 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -15,6 +15,7 @@ #define DUMP_H #include "qapi/qapi-types-dump.h" +#include "qemu/thread.h" #define MAKEDUMPFILE_SIGNATURE "makedumpfile" #define MAX_SIZE_MDF_HEADER (4096) /* max size of makedumpfile_header */ @@ -154,20 +155,35 @@ typedef struct DumpState { GuestPhysBlockList guest_phys_blocks; ArchDumpInfo dump_info; MemoryMappingList list; - uint16_t phdr_num; - uint32_t sh_info; - bool have_section; bool resume; bool detached; - ssize_t note_size; 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 */ + + /* Elf dump related data */ + uint32_t phdr_num; + uint32_t shdr_num; + ssize_t note_size; + hwaddr shdr_offset; + hwaddr phdr_offset; + hwaddr section_offset; + hwaddr note_offset; + + void *elf_section_hdrs; /* Pointer to section header buffer */ + void *elf_section_data; /* Pointer to section data buffer */ + uint64_t elf_section_data_size; /* Size of section data */ + GArray *string_table_buf; /* String table data buffer */ uint8_t *note_buf; /* buffer for notes */ size_t note_buf_offset; /* the writing place in note_buf */ @@ -200,4 +216,9 @@ typedef struct DumpState { uint16_t cpu_to_dump16(DumpState *s, uint16_t val); uint32_t cpu_to_dump32(DumpState *s, uint32_t val); uint64_t cpu_to_dump64(DumpState *s, uint64_t val); + +int64_t dump_filtered_memblock_size(GuestPhysBlock *block, int64_t filter_area_start, + int64_t filter_area_length); +int64_t dump_filtered_memblock_start(GuestPhysBlock *block, int64_t filter_area_start, + int64_t filter_area_length); #endif diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h new file mode 100644 index 000000000000..2748bf6ae1f8 --- /dev/null +++ b/include/sysemu/event-loop-base.h @@ -0,0 +1,41 @@ +/* + * QEMU event-loop backend + * + * Copyright (C) 2022 Red Hat Inc + * + * Authors: + * Nicolas Saenz Julienne + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_EVENT_LOOP_BASE_H +#define QEMU_EVENT_LOOP_BASE_H + +#include "qom/object.h" +#include "block/aio.h" +#include "qemu/typedefs.h" + +#define TYPE_EVENT_LOOP_BASE "event-loop-base" +OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass, + EVENT_LOOP_BASE) + +struct EventLoopBaseClass { + ObjectClass parent_class; + + void (*init)(EventLoopBase *base, Error **errp); + void (*update_params)(EventLoopBase *base, Error **errp); + bool (*can_be_deleted)(EventLoopBase *base); +}; + +struct EventLoopBase { + Object parent; + + /* AioContext AIO engine parameters */ + int64_t aio_max_batch; + + /* AioContext thread pool parameters */ + int64_t thread_pool_min; + int64_t thread_pool_max; +}; +#endif diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h index 9ff5c16963f0..39326f1d4f9c 100644 --- a/include/sysemu/hostmem.h +++ b/include/sysemu/hostmem.h @@ -18,6 +18,7 @@ #include "qom/object.h" #include "exec/memory.h" #include "qemu/bitmap.h" +#include "qemu/thread-context.h" #define TYPE_MEMORY_BACKEND "memory-backend" OBJECT_DECLARE_TYPE(HostMemoryBackend, HostMemoryBackendClass, @@ -66,6 +67,7 @@ struct HostMemoryBackend { bool merge, dump, use_canonical_path; bool prealloc, is_mapped, share, reserve; uint32_t prealloc_threads; + ThreadContext *prealloc_context; DECLARE_BITMAP(host_nodes, MAX_NODES + 1); HostMemPolicy policy; diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index 7f714bd1368f..8f8601d6abcb 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -17,11 +17,12 @@ #include "block/aio.h" #include "qemu/thread.h" #include "qom/object.h" +#include "sysemu/event-loop-base.h" #define TYPE_IOTHREAD "iothread" struct IOThread { - Object parent_obj; + EventLoopBase parent_obj; QemuThread thread; AioContext *ctx; @@ -37,9 +38,6 @@ struct IOThread { int64_t poll_max_ns; int64_t poll_grow; int64_t poll_shrink; - - /* AioContext AIO engine parameters */ - int64_t aio_max_batch; }; typedef struct IOThread IOThread; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index a783c7886811..e9a97eda8c00 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 */ @@ -353,6 +349,8 @@ bool kvm_device_supported(int vmfd, uint64_t type); extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; +void kvm_arch_accel_class_init(ObjectClass *oc); + void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run); MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run); @@ -582,4 +580,6 @@ bool kvm_cpu_check_are_resettable(void); bool kvm_arch_cpu_check_are_resettable(void); bool kvm_dirty_ring_enabled(void); + +uint32_t kvm_dirty_ring_size(void); #endif diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 1f5487d9b74d..60b520a13e84 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -10,7 +10,9 @@ #define QEMU_KVM_INT_H #include "exec/memory.h" +#include "qapi/qapi-types-common.h" #include "qemu/accel.h" +#include "qemu/queue.h" #include "sysemu/kvm.h" typedef struct KVMSlot @@ -30,12 +32,94 @@ typedef struct KVMSlot ram_addr_t ram_start_offset; } KVMSlot; +typedef struct KVMMemoryUpdate { + QSIMPLEQ_ENTRY(KVMMemoryUpdate) next; + MemoryRegionSection section; +} KVMMemoryUpdate; + typedef struct KVMMemoryListener { MemoryListener listener; KVMSlot *slots; int as_id; + QSIMPLEQ_HEAD(, KVMMemoryUpdate) transaction_add; + QSIMPLEQ_HEAD(, KVMMemoryUpdate) transaction_del; } KVMMemoryListener; +#define KVM_MSI_HASHTAB_SIZE 256 + +enum KVMDirtyRingReaperState { + KVM_DIRTY_RING_REAPER_NONE = 0, + /* The reaper is sleeping */ + KVM_DIRTY_RING_REAPER_WAIT, + /* The reaper is reaping for dirty pages */ + KVM_DIRTY_RING_REAPER_REAPING, +}; + +/* + * KVM reaper instance, responsible for collecting the KVM dirty bits + * via the dirty ring. + */ +struct KVMDirtyRingReaper { + /* The reaper thread */ + QemuThread reaper_thr; + volatile uint64_t reaper_iteration; /* iteration number of reaper thr */ + volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */ +}; +struct KVMState +{ + AccelState parent_obj; + + int nr_slots; + int fd; + int vmfd; + int coalesced_mmio; + int coalesced_pio; + struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; + bool coalesced_flush_in_progress; + int vcpu_events; + int robust_singlestep; + int debugregs; +#ifdef KVM_CAP_SET_GUEST_DEBUG + QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; +#endif + int max_nested_state_len; + int many_ioeventfds; + int intx_set_mask; + int kvm_shadow_mem; + bool kernel_irqchip_allowed; + bool kernel_irqchip_required; + OnOffAuto kernel_irqchip_split; + bool sync_mmu; + uint64_t manual_dirty_log_protect; + /* The man page (and posix) say ioctl numbers are signed int, but + * they're not. Linux, glibc and *BSD all treat ioctl numbers as + * unsigned, and treating them as signed here can break things */ + unsigned irq_set_ioctl; + unsigned int sigmask_len; + GHashTable *gsimap; +#ifdef KVM_CAP_IRQ_ROUTING + struct kvm_irq_routing *irq_routes; + int nr_allocated_irq_routes; + unsigned long *used_gsi_bitmap; + unsigned int gsi_count; + QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; +#endif + KVMMemoryListener memory_listener; + QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; + + /* For "info mtree -f" to tell if an MR is registered in KVM */ + int nr_as; + struct KVMAs { + KVMMemoryListener *ml; + AddressSpace *as; + } *as; + uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */ + uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */ + struct KVMDirtyRingReaper reaper; + NotifyVmexitOption notify_vmexit; + uint32_t notify_window; +}; + void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, AddressSpace *as, int as_id, const char *name); diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h index dd64fb401dfb..58de7c994d85 100644 --- a/include/sysemu/os-posix.h +++ b/include/sysemu/os-posix.h @@ -42,7 +42,9 @@ extern "C" { #endif +int os_parse_cmd_args(int index, const char *optarg); void os_set_line_buffering(void); +void os_setup_early_signal_handling(void); void os_set_proc_name(const char *s); void os_setup_signal_handling(void); void os_daemonize(void); @@ -52,9 +54,6 @@ int os_mlock(void); #define closesocket(s) close(s) #define ioctlsocket(s, r, v) ioctl(s, r, v) -typedef struct timeval qemu_timeval; -#define qemu_gettimeofday(tp) gettimeofday(tp, NULL) - int os_set_daemonize(bool d); bool is_daemonized(void); diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 770752222ae3..5b38c7bd0451 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 @@ -62,8 +79,10 @@ struct tm *localtime_r(const time_t *timep, struct tm *result); static inline void os_setup_signal_handling(void) {} static inline void os_daemonize(void) {} static inline void os_setup_post(void) {} -void os_set_line_buffering(void); static inline void os_set_proc_name(const char *dummy) {} +static inline int os_parse_cmd_args(int index, const char *optarg) { return -1; } +void os_set_line_buffering(void); +void os_setup_early_signal_handling(void); int getpagesize(void); @@ -71,12 +90,6 @@ int getpagesize(void); # define EPROTONOSUPPORT EINVAL #endif -typedef struct { - long tv_sec; - long tv_usec; -} qemu_timeval; -int qemu_gettimeofday(qemu_timeval *tp); - static inline int os_set_daemonize(bool d) { if (d) { @@ -113,20 +126,22 @@ static inline char *realpath(const char *path, char *resolved_path) return resolved_path; } -/* ??? Mingw appears to export _lock_file and _unlock_file as the functions - * with which to lock a stdio handle. But something is wrong in the markup, - * either in the header or the library, such that we get undefined references - * to "_imp___lock_file" etc when linking. Since we seem to have no other - * alternative, and the usage within the logging functions isn't critical, - * ignore FILE locking. +/* + * Older versions of MinGW do not import _lock_file and _unlock_file properly. + * This was fixed for v6.0.0 with commit b48e3ac8969d. */ - static inline void qemu_flockfile(FILE *f) { +#ifdef HAVE__LOCK_FILE + _lock_file(f); +#endif } static inline void qemu_funlockfile(FILE *f) { +#ifdef HAVE__LOCK_FILE + _unlock_file(f); +#endif } /* We wrap all the sockets functions so that we can diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 0f3b0f7eacf9..7ec0882b50b8 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -160,9 +160,14 @@ void replay_shutdown_request(ShutdownCause cause); Returns 0 in PLAY mode if checkpoint was not found. Returns 1 in all other cases. */ bool replay_checkpoint(ReplayCheckpoint checkpoint); -/*! Used to determine that checkpoint is pending. +/*! Used to determine that checkpoint or async event is pending. Does not proceed to the next event in the log. */ -bool replay_has_checkpoint(void); +bool replay_has_event(void); +/* + * Processes the async events added to the queue (while recording) + * or reads the events from the file (while replaying). + */ +void replay_async_events(void); /* Asynchronous events queue */ @@ -193,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/reset.h b/include/sysemu/reset.h index 0b0d6d7598c9..609e4d50c269 100644 --- a/include/sysemu/reset.h +++ b/include/sysemu/reset.h @@ -1,10 +1,13 @@ #ifndef QEMU_SYSEMU_RESET_H #define QEMU_SYSEMU_RESET_H +#include "qapi/qapi-events-run-state.h" + typedef void QEMUResetHandler(void *opaque); void qemu_register_reset(QEMUResetHandler *func, void *opaque); +void qemu_register_reset_nosnapshotload(QEMUResetHandler *func, void *opaque); void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); -void qemu_devices_reset(void); +void qemu_devices_reset(ShutdownCause reason); #endif diff --git a/include/sysemu/runstate.h b/include/sysemu/runstate.h index a53569157343..f3ed52548ea9 100644 --- a/include/sysemu/runstate.h +++ b/include/sysemu/runstate.h @@ -34,7 +34,13 @@ static inline bool shutdown_caused_by_guest(ShutdownCause cause) } void vm_start(void); -int vm_prepare_start(void); + +/** + * vm_prepare_start: Prepare for starting/resuming the VM + * + * @step_pending: whether any of the CPUs is about to be single-stepped by gdb + */ +int vm_prepare_start(bool step_pending); int vm_stop(RunState state); int vm_stop_force_state(RunState state); int vm_shutdown(void); @@ -69,6 +75,7 @@ void qemu_system_killed(int signal, pid_t pid); void qemu_system_reset(ShutdownCause reason); void qemu_system_guest_panicked(GuestPanicInformation *info); void qemu_system_guest_crashloaded(GuestPanicInformation *info); +bool qemu_system_dump_in_progress(void); #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index b9421e03ffdd..25be2a692e64 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -13,6 +13,8 @@ extern const char *qemu_name; extern QemuUUID qemu_uuid; extern bool qemu_uuid_set; +const char *qemu_get_vm_name(void); + void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); @@ -32,6 +34,7 @@ typedef enum { } VGAInterfaceType; extern int vga_interface_type; +extern bool vga_interface_created; extern int graphic_width; extern int graphic_height; @@ -39,12 +42,8 @@ extern int graphic_depth; extern int display_opengl; extern const char *keyboard_layout; extern int win2k_install_hack; -extern int alt_grab; -extern int ctrl_grab; extern int graphic_rotate; extern int old_param; -extern int boot_menu; -extern bool boot_strict; extern uint8_t *boot_splash_filedata; extern bool enable_mlock; extern bool enable_cpu_pm; @@ -62,9 +61,6 @@ extern int nb_option_roms; extern const char *prom_envs[MAX_PROM_ENVS]; extern unsigned int nb_prom_envs; -/* pcie aer error injection */ -void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict); - /* serial ports */ /* Return the Chardev for serial port i, or NULL if none */ @@ -103,8 +99,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/tpm.h b/include/sysemu/tpm.h index 68b2206463c5..fb40e30ff60e 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -80,6 +80,12 @@ static inline TPMVersion tpm_get_version(TPMIf *ti) #define tpm_init() (0) #define tpm_cleanup() +/* needed for an alignment check in non-tpm code */ +static inline Object *TPM_IS_CRB(Object *obj) +{ + return NULL; +} + #endif /* CONFIG_TPM */ #endif /* QEMU_TPM_H */ diff --git a/include/sysemu/watchdog.h b/include/sysemu/watchdog.h index d2d4901dbbe4..745c89b02bc1 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-ldst.h b/include/tcg/tcg-ldst.h index bf40942de4ab..2ba22bd5fe12 100644 --- a/include/tcg/tcg-ldst.h +++ b/include/tcg/tcg-ldst.h @@ -23,7 +23,7 @@ */ #ifndef TCG_LDST_H -#define TCG_LDST_H 1 +#define TCG_LDST_H #ifdef CONFIG_SOFTMMU @@ -72,8 +72,8 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, #else -void QEMU_NORETURN helper_unaligned_ld(CPUArchState *env, target_ulong addr); -void QEMU_NORETURN helper_unaligned_st(CPUArchState *env, target_ulong addr); +G_NORETURN void helper_unaligned_ld(CPUArchState *env, target_ulong addr); +G_NORETURN void helper_unaligned_st(CPUArchState *env, target_ulong addr); #endif /* CONFIG_SOFTMMU */ #endif /* TCG_LDST_H */ diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index caa0a636125d..79b1cf786fc8 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -332,6 +332,7 @@ void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags); void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg); +void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_smin_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_smax_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_umin_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); @@ -531,6 +532,8 @@ void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags); void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags); void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg); +void tcg_gen_hswap_i64(TCGv_i64 ret, TCGv_i64 arg); +void tcg_gen_wswap_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_smin_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_smax_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_umin_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); @@ -664,35 +667,12 @@ static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2); } #else /* TCG_TARGET_REG_BITS == 32 */ -static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, - tcg_target_long offset) -{ - tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); -} - -static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, - tcg_target_long offset) -{ - tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); -} - -static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, - tcg_target_long offset) -{ - tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); -} - -static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) -{ - tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), - TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); -} +void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset); +void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset); +void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset); -static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) -{ - tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), - TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); -} +void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); +void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_discard_i64(TCGv_i64 arg); void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg); @@ -838,7 +818,7 @@ static inline void tcg_gen_plugin_cb_start(unsigned from, unsigned type, static inline void tcg_gen_plugin_cb_end(void) { - tcg_emit_op(INDEX_op_plugin_cb_end); + tcg_emit_op(INDEX_op_plugin_cb_end, 0); } #if TARGET_LONG_BITS == 32 @@ -1077,6 +1057,8 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t); #define tcg_gen_bswap32_tl tcg_gen_bswap32_i64 #define tcg_gen_bswap64_tl tcg_gen_bswap64_i64 #define tcg_gen_bswap_tl tcg_gen_bswap64_i64 +#define tcg_gen_hswap_tl tcg_gen_hswap_i64 +#define tcg_gen_wswap_tl tcg_gen_wswap_i64 #define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64 #define tcg_gen_extr_i64_tl tcg_gen_extr32_i64 #define tcg_gen_andc_tl tcg_gen_andc_i64 @@ -1192,6 +1174,7 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t); #define tcg_gen_bswap16_tl tcg_gen_bswap16_i32 #define tcg_gen_bswap32_tl(D, S, F) tcg_gen_bswap32_i32(D, S) #define tcg_gen_bswap_tl tcg_gen_bswap32_i32 +#define tcg_gen_hswap_tl tcg_gen_hswap_i32 #define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64 #define tcg_gen_extr_i64_tl tcg_gen_extr_i64_i32 #define tcg_gen_andc_tl tcg_gen_andc_i32 @@ -1282,6 +1265,11 @@ static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b) glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b); } +static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s) +{ + glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s); +} + static inline void tcg_gen_brcondi_ptr(TCGCond cond, TCGv_ptr a, intptr_t b, TCGLabel *label) { diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 73869fd9d04f..b949d75fdd72 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -38,19 +38,7 @@ /* XXX: make safe guess about sizes */ #define MAX_OP_PER_INSTR 266 -#if HOST_LONG_BITS == 32 -#define MAX_OPC_PARAM_PER_ARG 2 -#else -#define MAX_OPC_PARAM_PER_ARG 1 -#endif -#define MAX_OPC_PARAM_IARGS 7 -#define MAX_OPC_PARAM_OARGS 1 -#define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS) - -/* A Call op needs up to 4 + 2N parameters on 32-bit archs, - * and up to 4 + N parameters on 64-bit archs - * (N = number of input arguments + output arguments). */ -#define MAX_OPC_PARAM (4 + (MAX_OPC_PARAM_PER_ARG * MAX_OPC_PARAM_ARGS)) +#define MAX_CALL_IARGS 7 #define CPU_TEMP_BUF_NLONGS 128 #define TCG_STATIC_FRAME_SIZE (CPU_TEMP_BUF_NLONGS * sizeof(long)) @@ -294,7 +282,8 @@ typedef enum TCGType { TCG_TYPE_V128, TCG_TYPE_V256, - TCG_TYPE_COUNT, /* number of different types */ + /* Number of different types (integer not enum) */ +#define TCG_TYPE_COUNT (TCG_TYPE_V256 + 1) /* An alias for the size of the host register. */ #if TCG_TARGET_REG_BITS == 32 @@ -318,6 +307,22 @@ typedef enum TCGType { #endif } TCGType; +/** + * tcg_type_size + * @t: type + * + * Return the size of the type in bytes. + */ +static inline int tcg_type_size(TCGType t) +{ + unsigned i = t; + if (i >= TCG_TYPE_V64) { + tcg_debug_assert(i < TCG_TYPE_COUNT); + i -= TCG_TYPE_V64 - 1; + } + return 4 << i; +} + /** * get_alignment_bits * @memop: MemOp value @@ -398,7 +403,7 @@ typedef TCGv_ptr TCGv_env; #define TCG_CALL_NO_WRITE_GLOBALS 0x0002 /* Helper can be safely suppressed if the return value is not used. */ #define TCG_CALL_NO_SIDE_EFFECTS 0x0004 -/* Helper is QEMU_NORETURN. */ +/* Helper is G_NORETURN. */ #define TCG_CALL_NO_RETURN 0x0008 /* convenience version of most used call flags */ @@ -408,9 +413,6 @@ typedef TCGv_ptr TCGv_env; #define TCG_CALL_NO_RWG_SE (TCG_CALL_NO_RWG | TCG_CALL_NO_SE) #define TCG_CALL_NO_WG_SE (TCG_CALL_NO_WG | TCG_CALL_NO_SE) -/* Used to align parameters. See the comment before tcgv_i32_temp. */ -#define TCG_CALL_DUMMY_ARG ((TCGArg)0) - /* * Flags for the bswap opcodes. * If IZ, the input is zero-extended, otherwise unknown. @@ -433,6 +435,8 @@ typedef enum TCGTempVal { typedef enum TCGTempKind { /* Temp is dead at the end of all basic blocks. */ TEMP_NORMAL, + /* Temp is live across conditional branch, but dead otherwise. */ + TEMP_EBB, /* Temp is saved across basic blocks but dead at the end of TBs. */ TEMP_LOCAL, /* Temp is saved across both basic blocks and translation blocks. */ @@ -454,6 +458,7 @@ typedef struct TCGTemp { unsigned int mem_coherent:1; unsigned int mem_allocated:1; unsigned int temp_allocated:1; + unsigned int temp_subindex:1; int64_t val; struct TCGTemp *mem_base; @@ -473,34 +478,34 @@ typedef struct TCGTempSet { unsigned long l[BITS_TO_LONGS(TCG_MAX_TEMPS)]; } TCGTempSet; -/* While we limit helpers to 6 arguments, for 32-bit hosts, with padding, - this imples a max of 6*2 (64-bit in) + 2 (64-bit out) = 14 operands. - There are never more than 2 outputs, which means that we can store all - dead + sync data within 16 bits. */ -#define DEAD_ARG 4 -#define SYNC_ARG 1 -typedef uint16_t TCGLifeData; +/* + * With 1 128-bit output, a 32-bit host requires 4 output parameters, + * which leaves a maximum of 28 other slots. Which is enough for 7 + * 128-bit operands. + */ +#define DEAD_ARG (1 << 4) +#define SYNC_ARG (1 << 0) +typedef uint32_t TCGLifeData; -/* The layout here is designed to avoid a bitfield crossing of - a 32-bit boundary, which would cause GCC to add extra padding. */ typedef struct TCGOp { - TCGOpcode opc : 8; /* 8 */ + TCGOpcode opc : 8; + unsigned nargs : 8; /* Parameters for this opcode. See below. */ - unsigned param1 : 4; /* 12 */ - unsigned param2 : 4; /* 16 */ + unsigned param1 : 8; + unsigned param2 : 8; /* Lifetime data of the operands. */ - unsigned life : 16; /* 32 */ + TCGLifeData life; /* Next and previous opcodes. */ QTAILQ_ENTRY(TCGOp) link; - /* Arguments for the opcode. */ - TCGArg args[MAX_OPC_PARAM]; - /* Register preferences for the output(s). */ TCGRegSet output_pref[2]; + + /* Arguments for the opcode. */ + TCGArg args[]; } TCGOp; #define TCGOP_CALLI(X) (X)->param1 @@ -512,6 +517,11 @@ typedef struct TCGOp { /* Make sure operands fit in the bitfields above. */ QEMU_BUILD_BUG_ON(NB_OPS > (1 << 8)); +static inline TCGRegSet output_pref(const TCGOp *op, unsigned i) +{ + return i < ARRAY_SIZE(op->output_pref) ? op->output_pref[i] : 0; +} + typedef struct TCGProfile { int64_t cpu_exec_time; int64_t tb_count1; @@ -735,18 +745,6 @@ static inline TCGv_vec temp_tcgv_vec(TCGTemp *t) return (TCGv_vec)temp_tcgv_i32(t); } -#if TCG_TARGET_REG_BITS == 32 -static inline TCGv_i32 TCGV_LOW(TCGv_i64 t) -{ - return temp_tcgv_i32(tcgv_i64_temp(t)); -} - -static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) -{ - return temp_tcgv_i32(tcgv_i64_temp(t) + 1); -} -#endif - static inline TCGArg tcg_get_insn_param(TCGOp *op, int arg) { return op->args[arg]; @@ -838,7 +836,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); @@ -949,6 +947,8 @@ typedef struct TCGArgConstraint { unsigned ct : 16; unsigned alias_index : 4; unsigned sort_index : 4; + unsigned pair_index : 4; + unsigned pair : 2; /* 0: none, 1: first, 2: second, 3: second alias */ bool oalias : 1; bool ialias : 1; bool newreg : 1; @@ -1004,10 +1004,12 @@ bool tcg_op_supported(TCGOpcode op); void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args); -TCGOp *tcg_emit_op(TCGOpcode opc); +TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs); void tcg_op_remove(TCGContext *s, TCGOp *op); -TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, TCGOpcode opc); -TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, TCGOpcode opc); +TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, + TCGOpcode opc, unsigned nargs); +TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, + TCGOpcode opc, unsigned nargs); /** * tcg_remove_ops_after: @@ -1054,9 +1056,11 @@ TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val); #if UINTPTR_MAX == UINT32_MAX # define tcg_const_ptr(x) ((TCGv_ptr)tcg_const_i32((intptr_t)(x))) # define tcg_const_local_ptr(x) ((TCGv_ptr)tcg_const_local_i32((intptr_t)(x))) +# define tcg_constant_ptr(x) ((TCGv_ptr)tcg_constant_i32((intptr_t)(x))) #else # define tcg_const_ptr(x) ((TCGv_ptr)tcg_const_i64((intptr_t)(x))) # define tcg_const_local_ptr(x) ((TCGv_ptr)tcg_const_local_i64((intptr_t)(x))) +# define tcg_constant_ptr(x) ((TCGv_ptr)tcg_constant_i64((intptr_t)(x))) #endif TCGLabel *gen_new_label(void); diff --git a/include/ui/console.h b/include/ui/console.h index 0f84861933e1..e400ee9fa74b 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') @@ -139,6 +140,7 @@ typedef struct QemuUIInfo { int yoff; uint32_t width; uint32_t height; + uint32_t refresh_rate; } QemuUIInfo; /* cursor data format is 32bit RGBA */ @@ -431,8 +433,7 @@ typedef struct GraphicHwOps { void (*gfx_update)(void *opaque); bool gfx_update_async; /* if true, calls graphic_hw_update_done() */ void (*text_update)(void *opaque, console_ch_t *text); - void (*update_interval)(void *opaque, uint64_t interval); - int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info); + void (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info); void (*gl_block)(void *opaque, bool block); } GraphicHwOps; @@ -463,6 +464,7 @@ bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); bool qemu_console_is_gl_blocked(QemuConsole *con); +bool qemu_console_is_multihead(DeviceState *dev); char *qemu_console_get_label(QemuConsole *con); int qemu_console_get_index(QemuConsole *con); uint32_t qemu_console_get_head(QemuConsole *con); @@ -518,6 +520,7 @@ int vnc_display_pw_expire(const char *id, time_t expires); void vnc_parse(const char *str); int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp); bool vnc_display_reload_certs(const char *id, Error **errp); +bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp); /* input.c */ int index_from_key(const char *key, size_t key_length); diff --git a/include/ui/dbus-display.h b/include/ui/dbus-display.h index 88f153c2371d..7c9ec1a069e1 100644 --- a/include/ui/dbus-display.h +++ b/include/ui/dbus-display.h @@ -1,5 +1,5 @@ -#ifndef DBUS_DISPLAY_H_ -#define DBUS_DISPLAY_H_ +#ifndef DBUS_DISPLAY_H +#define DBUS_DISPLAY_H #include "qapi/error.h" #include "ui/dbus-module.h" @@ -14,4 +14,4 @@ static inline bool qemu_using_dbus_display(Error **errp) return true; } -#endif /* DBUS_DISPLAY_H_ */ +#endif /* DBUS_DISPLAY_H */ diff --git a/include/ui/dbus-module.h b/include/ui/dbus-module.h index ace4a17a5c25..5442ee0bb6e0 100644 --- a/include/ui/dbus-module.h +++ b/include/ui/dbus-module.h @@ -1,5 +1,5 @@ -#ifndef DBUS_MODULE_H_ -#define DBUS_MODULE_H_ +#ifndef DBUS_MODULE_H +#define DBUS_MODULE_H struct QemuDBusDisplayOps { bool (*add_client)(int csock, Error **errp); @@ -8,4 +8,4 @@ struct QemuDBusDisplayOps { extern int using_dbus_display; extern struct QemuDBusDisplayOps qemu_dbus_display; -#endif /* DBUS_MODULE_H_*/ +#endif /* DBUS_MODULE_H */ diff --git a/include/ui/gtk.h b/include/ui/gtk.h index 101b147d1b98..ae0f53740d19 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -155,7 +155,7 @@ extern bool gtk_use_gl_area; /* ui/gtk.c */ void gd_update_windowsize(VirtualConsole *vc); -int gd_monitor_update_interval(GtkWidget *widget); +void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget); void gd_hw_gl_flushed(void *vc); /* ui/gtk-egl.c */ diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 806ddcd7cdab..0c775604d173 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -19,7 +19,7 @@ * feeding libjpeg / libpng and writing screenshots. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define PIXMAN_BE_r8g8b8 PIXMAN_r8g8b8 # define PIXMAN_BE_x8r8g8b8 PIXMAN_x8r8g8b8 # define PIXMAN_BE_a8r8g8b8 PIXMAN_a8r8g8b8 diff --git a/include/user/safe-syscall.h b/include/user/safe-syscall.h index 61a04e2b5adf..ddceef12e21a 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/include/user/syscall-trace.h b/include/user/syscall-trace.h index 614cfacfa580..c5a220da34e4 100644 --- a/include/user/syscall-trace.h +++ b/include/user/syscall-trace.h @@ -10,6 +10,7 @@ #ifndef SYSCALL_TRACE_H #define SYSCALL_TRACE_H +#include "exec/user/abitypes.h" #include "trace/trace-root.h" /* @@ -39,4 +40,4 @@ static inline void record_syscall_return(void *cpu, int num, abi_long ret) } -#endif /* _SYSCALL_TRACE_H_ */ +#endif /* SYSCALL_TRACE_H */ diff --git a/io/channel-buffer.c b/io/channel-buffer.c index baa4e2b089f6..bf52011be2d7 100644 --- a/io/channel-buffer.c +++ b/io/channel-buffer.c @@ -81,6 +81,7 @@ static ssize_t qio_channel_buffer_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc); diff --git a/io/channel-command.c b/io/channel-command.c index 338da73ade56..74516252bae5 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -26,11 +26,30 @@ #include "qemu/sockets.h" #include "trace.h" - -QIOChannelCommand * +/** + * qio_channel_command_new_pid: + * @writefd: the FD connected to the command's stdin + * @readfd: the FD connected to the command's stdout + * @pid: the PID/HANDLE of the running child command + * @errp: pointer to a NULL-initialized error object + * + * Create a channel for performing I/O with the + * previously spawned command identified by @pid. + * The two file descriptors provide the connection + * to command's stdio streams, either one or which + * may be -1 to indicate that stream is not open. + * + * The channel will take ownership of the process + * @pid and will kill it when closing the channel. + * Similarly it will take responsibility for + * closing the file descriptors @writefd and @readfd. + * + * Returns: the command channel object, or NULL on error + */ +static QIOChannelCommand * qio_channel_command_new_pid(int writefd, int readfd, - pid_t pid) + GPid pid) { QIOChannelCommand *ioc; @@ -40,118 +59,40 @@ qio_channel_command_new_pid(int writefd, ioc->writefd = writefd; ioc->pid = pid; - trace_qio_channel_command_new_pid(ioc, writefd, readfd, pid); + trace_qio_channel_command_new_pid(ioc, writefd, readfd, +#ifdef WIN32 + GetProcessId(pid) +#else + pid +#endif + ); return ioc; } - -#ifndef WIN32 QIOChannelCommand * qio_channel_command_new_spawn(const char *const argv[], int flags, Error **errp) { - pid_t pid = -1; - int stdinfd[2] = { -1, -1 }; - int stdoutfd[2] = { -1, -1 }; - int devnull = -1; - bool stdinnull = false, stdoutnull = false; - QIOChannelCommand *ioc; + g_autoptr(GError) err = NULL; + GPid pid = 0; + GSpawnFlags gflags = G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD; + int stdinfd = -1, stdoutfd = -1; flags = flags & O_ACCMODE; - - if (flags == O_RDONLY) { - stdinnull = true; - } - if (flags == O_WRONLY) { - stdoutnull = true; - } - - if (stdinnull || stdoutnull) { - devnull = open("/dev/null", O_RDWR); - if (devnull < 0) { - error_setg_errno(errp, errno, - "Unable to open /dev/null"); - goto error; - } - } - - if ((!stdinnull && pipe(stdinfd) < 0) || - (!stdoutnull && pipe(stdoutfd) < 0)) { - error_setg_errno(errp, errno, - "Unable to open pipe"); - goto error; - } - - pid = qemu_fork(errp); - if (pid < 0) { - goto error; - } - - if (pid == 0) { /* child */ - dup2(stdinnull ? devnull : stdinfd[0], STDIN_FILENO); - dup2(stdoutnull ? devnull : stdoutfd[1], STDOUT_FILENO); - /* Leave stderr connected to qemu's stderr */ - - if (!stdinnull) { - close(stdinfd[0]); - close(stdinfd[1]); - } - if (!stdoutnull) { - close(stdoutfd[0]); - close(stdoutfd[1]); - } - if (devnull != -1) { - close(devnull); - } - - execv(argv[0], (char * const *)argv); - _exit(1); - } - - if (!stdinnull) { - close(stdinfd[0]); - } - if (!stdoutnull) { - close(stdoutfd[1]); - } - - ioc = qio_channel_command_new_pid(stdinnull ? devnull : stdinfd[1], - stdoutnull ? devnull : stdoutfd[0], - pid); - trace_qio_channel_command_new_spawn(ioc, argv[0], flags); - return ioc; - - error: - if (devnull != -1) { - close(devnull); - } - if (stdinfd[0] != -1) { - close(stdinfd[0]); + gflags |= flags == O_WRONLY ? G_SPAWN_STDOUT_TO_DEV_NULL : 0; + + if (!g_spawn_async_with_pipes(NULL, (char **)argv, NULL, gflags, NULL, NULL, + &pid, + flags == O_RDONLY ? NULL : &stdinfd, + flags == O_WRONLY ? NULL : &stdoutfd, + NULL, &err)) { + error_setg(errp, "%s", err->message); + return NULL; } - if (stdinfd[1] != -1) { - close(stdinfd[1]); - } - if (stdoutfd[0] != -1) { - close(stdoutfd[0]); - } - if (stdoutfd[1] != -1) { - close(stdoutfd[1]); - } - return NULL; -} -#else /* WIN32 */ -QIOChannelCommand * -qio_channel_command_new_spawn(const char *const argv[], - int flags, - Error **errp) -{ - error_setg_errno(errp, ENOSYS, - "Command spawn not supported on this platform"); - return NULL; + return qio_channel_command_new_pid(stdinfd, stdoutfd, pid); } -#endif /* WIN32 */ #ifndef WIN32 static int qio_channel_command_abort(QIOChannelCommand *ioc, @@ -195,6 +136,23 @@ static int qio_channel_command_abort(QIOChannelCommand *ioc, return 0; } +#else +static int qio_channel_command_abort(QIOChannelCommand *ioc, + Error **errp) +{ + DWORD ret; + + TerminateProcess(ioc->pid, 0); + ret = WaitForSingleObject(ioc->pid, 1000); + if (ret != WAIT_OBJECT_0) { + error_setg(errp, + "Process %llu refused to die", + (unsigned long long)GetProcessId(ioc->pid)); + return -1; + } + + return 0; +} #endif /* ! WIN32 */ @@ -203,7 +161,7 @@ static void qio_channel_command_init(Object *obj) QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj); ioc->readfd = -1; ioc->writefd = -1; - ioc->pid = -1; + ioc->pid = 0; } static void qio_channel_command_finalize(Object *obj) @@ -218,12 +176,27 @@ static void qio_channel_command_finalize(Object *obj) } ioc->writefd = ioc->readfd = -1; if (ioc->pid > 0) { -#ifndef WIN32 qio_channel_command_abort(ioc, NULL); -#endif + g_spawn_close_pid(ioc->pid); } } +#ifdef WIN32 +static bool win32_fd_poll(int fd, gushort events) +{ + GPollFD pfd = { .fd = _get_osfhandle(fd), .events = events }; + int res; + + do { + res = g_poll(&pfd, 1, 0); + } while (res < 0 && errno == EINTR); + if (res == 0) { + return false; + } + + return true; +} +#endif static ssize_t qio_channel_command_readv(QIOChannel *ioc, const struct iovec *iov, @@ -235,6 +208,12 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc, QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); ssize_t ret; +#ifdef WIN32 + if (!cioc->blocking && !win32_fd_poll(cioc->readfd, G_IO_IN)) { + return QIO_CHANNEL_ERR_BLOCK; + } +#endif + retry: ret = readv(cioc->readfd, iov, niov); if (ret < 0) { @@ -258,11 +237,18 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); ssize_t ret; +#ifdef WIN32 + if (!cioc->blocking && !win32_fd_poll(cioc->writefd, G_IO_OUT)) { + return QIO_CHANNEL_ERR_BLOCK; + } +#endif + retry: ret = writev(cioc->writefd, iov, niov); if (ret <= 0) { @@ -285,14 +271,16 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc, { QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); - if (enabled) { - qemu_set_block(cioc->writefd); - qemu_set_block(cioc->readfd); - } else { - qemu_set_nonblock(cioc->writefd); - qemu_set_nonblock(cioc->readfd); - } +#ifdef WIN32 + cioc->blocking = enabled; +#else + if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) || + (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return -1; + } +#endif return 0; } @@ -329,6 +317,8 @@ static int qio_channel_command_close(QIOChannel *ioc, (unsigned long long)cioc->pid); return -1; } +#else + WaitForSingleObject(cioc->pid, INFINITE); #endif if (rv < 0) { diff --git a/io/channel-file.c b/io/channel-file.c index d7cf6d278ff9..b67687c2aa64 100644 --- a/io/channel-file.c +++ b/io/channel-file.c @@ -114,6 +114,7 @@ static ssize_t qio_channel_file_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc); @@ -139,14 +140,19 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc, bool enabled, Error **errp) { +#ifdef WIN32 + /* not implemented */ + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return -1; +#else QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc); - if (enabled) { - qemu_set_block(fioc->fd); - } else { - qemu_set_nonblock(fioc->fd); + if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return -1; } return 0; +#endif } diff --git a/io/channel-null.c b/io/channel-null.c new file mode 100644 index 000000000000..75e378150705 --- /dev/null +++ b/io/channel-null.c @@ -0,0 +1,237 @@ +/* + * QEMU I/O channels null driver + * + * Copyright (c) 2022 Red Hat, Inc. + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "io/channel-null.h" +#include "io/channel-watch.h" +#include "qapi/error.h" +#include "trace.h" +#include "qemu/iov.h" + +typedef struct QIOChannelNullSource QIOChannelNullSource; +struct QIOChannelNullSource { + GSource parent; + QIOChannel *ioc; + GIOCondition condition; +}; + + +QIOChannelNull * +qio_channel_null_new(void) +{ + QIOChannelNull *ioc; + + ioc = QIO_CHANNEL_NULL(object_new(TYPE_QIO_CHANNEL_NULL)); + + trace_qio_channel_null_new(ioc); + + return ioc; +} + + +static void +qio_channel_null_init(Object *obj) +{ + QIOChannelNull *ioc = QIO_CHANNEL_NULL(obj); + ioc->closed = false; +} + + +static ssize_t +qio_channel_null_readv(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds G_GNUC_UNUSED, + size_t *nfds G_GNUC_UNUSED, + Error **errp) +{ + QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); + + if (nioc->closed) { + error_setg_errno(errp, EINVAL, + "Channel is closed"); + return -1; + } + + return 0; +} + + +static ssize_t +qio_channel_null_writev(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds G_GNUC_UNUSED, + size_t nfds G_GNUC_UNUSED, + int flags G_GNUC_UNUSED, + Error **errp) +{ + QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); + + if (nioc->closed) { + error_setg_errno(errp, EINVAL, + "Channel is closed"); + return -1; + } + + return iov_size(iov, niov); +} + + +static int +qio_channel_null_set_blocking(QIOChannel *ioc G_GNUC_UNUSED, + bool enabled G_GNUC_UNUSED, + Error **errp G_GNUC_UNUSED) +{ + return 0; +} + + +static off_t +qio_channel_null_seek(QIOChannel *ioc G_GNUC_UNUSED, + off_t offset G_GNUC_UNUSED, + int whence G_GNUC_UNUSED, + Error **errp G_GNUC_UNUSED) +{ + return 0; +} + + +static int +qio_channel_null_close(QIOChannel *ioc, + Error **errp G_GNUC_UNUSED) +{ + QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); + + nioc->closed = true; + return 0; +} + + +static void +qio_channel_null_set_aio_fd_handler(QIOChannel *ioc G_GNUC_UNUSED, + AioContext *ctx G_GNUC_UNUSED, + IOHandler *io_read G_GNUC_UNUSED, + IOHandler *io_write G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED) +{ +} + + +static gboolean +qio_channel_null_source_prepare(GSource *source G_GNUC_UNUSED, + gint *timeout) +{ + *timeout = -1; + + return TRUE; +} + + +static gboolean +qio_channel_null_source_check(GSource *source G_GNUC_UNUSED) +{ + return TRUE; +} + + +static gboolean +qio_channel_null_source_dispatch(GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + QIOChannelFunc func = (QIOChannelFunc)callback; + QIOChannelNullSource *ssource = (QIOChannelNullSource *)source; + + return (*func)(ssource->ioc, + ssource->condition, + user_data); +} + + +static void +qio_channel_null_source_finalize(GSource *source) +{ + QIOChannelNullSource *ssource = (QIOChannelNullSource *)source; + + object_unref(OBJECT(ssource->ioc)); +} + + +GSourceFuncs qio_channel_null_source_funcs = { + qio_channel_null_source_prepare, + qio_channel_null_source_check, + qio_channel_null_source_dispatch, + qio_channel_null_source_finalize +}; + + +static GSource * +qio_channel_null_create_watch(QIOChannel *ioc, + GIOCondition condition) +{ + GSource *source; + QIOChannelNullSource *ssource; + + source = g_source_new(&qio_channel_null_source_funcs, + sizeof(QIOChannelNullSource)); + ssource = (QIOChannelNullSource *)source; + + ssource->ioc = ioc; + object_ref(OBJECT(ioc)); + + ssource->condition = condition; + + return source; +} + + +static void +qio_channel_null_class_init(ObjectClass *klass, + void *class_data G_GNUC_UNUSED) +{ + QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); + + ioc_klass->io_writev = qio_channel_null_writev; + ioc_klass->io_readv = qio_channel_null_readv; + ioc_klass->io_set_blocking = qio_channel_null_set_blocking; + ioc_klass->io_seek = qio_channel_null_seek; + ioc_klass->io_close = qio_channel_null_close; + ioc_klass->io_create_watch = qio_channel_null_create_watch; + ioc_klass->io_set_aio_fd_handler = qio_channel_null_set_aio_fd_handler; +} + + +static const TypeInfo qio_channel_null_info = { + .parent = TYPE_QIO_CHANNEL, + .name = TYPE_QIO_CHANNEL_NULL, + .instance_size = sizeof(QIOChannelNull), + .instance_init = qio_channel_null_init, + .class_init = qio_channel_null_class_init, +}; + + +static void +qio_channel_null_register_types(void) +{ + type_register_static(&qio_channel_null_info); +} + +type_init(qio_channel_null_register_types); diff --git a/io/channel-socket.c b/io/channel-socket.c index 7a8d9f69c92d..b76dca9cc1bf 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qapi/qapi-visit-sockets.h" #include "qemu/module.h" @@ -26,6 +25,14 @@ #include "io/channel-watch.h" #include "trace.h" #include "qapi/clone-visitor.h" +#ifdef CONFIG_LINUX +#include +#include + +#if (defined(MSG_ZEROCOPY) && defined(SO_ZEROCOPY)) +#define QEMU_MSG_ZEROCOPY +#endif +#endif #define SOCKET_MAX_FDS 16 @@ -55,6 +62,8 @@ qio_channel_socket_new(void) sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET)); sioc->fd = -1; + sioc->zero_copy_queued = 0; + sioc->zero_copy_sent = 0; ioc = QIO_CHANNEL(sioc); qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); @@ -154,6 +163,16 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc, return -1; } +#ifdef QEMU_MSG_ZEROCOPY + int ret, v = 1; + ret = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &v, sizeof(v)); + if (ret == 0) { + /* Zero copy available on host */ + qio_channel_set_feature(QIO_CHANNEL(ioc), + QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY); + } +#endif + return 0; } @@ -461,7 +480,7 @@ static void qio_channel_socket_copy_fds(struct msghdr *msg, } /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */ - qemu_set_block(fd); + qemu_socket_set_block(fd); #ifndef MSG_CMSG_CLOEXEC qemu_set_cloexec(fd); @@ -525,6 +544,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); @@ -533,6 +553,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; size_t fdsize = sizeof(int) * nfds; struct cmsghdr *cmsg; + int sflags = 0; memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); @@ -557,19 +578,44 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, memcpy(CMSG_DATA(cmsg), fds, fdsize); } + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { +#ifdef QEMU_MSG_ZEROCOPY + sflags = MSG_ZEROCOPY; +#else + /* + * We expect QIOChannel class entry point to have + * blocked this code path already + */ + g_assert_not_reached(); +#endif + } + retry: - ret = sendmsg(sioc->fd, &msg, 0); + ret = sendmsg(sioc->fd, &msg, sflags); if (ret <= 0) { - if (errno == EAGAIN) { + switch (errno) { + case EAGAIN: return QIO_CHANNEL_ERR_BLOCK; - } - if (errno == EINTR) { + case EINTR: goto retry; + case ENOBUFS: + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { + error_setg_errno(errp, errno, + "Process can't lock enough memory for using MSG_ZEROCOPY"); + return -1; + } + break; } + error_setg_errno(errp, errno, "Unable to write to socket"); return -1; } + + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { + sioc->zero_copy_queued++; + } + return ret; } #else /* WIN32 */ @@ -620,6 +666,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); @@ -658,6 +705,80 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, } #endif /* WIN32 */ + +#ifdef QEMU_MSG_ZEROCOPY +static int qio_channel_socket_flush(QIOChannel *ioc, + Error **errp) +{ + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); + struct msghdr msg = {}; + struct sock_extended_err *serr; + struct cmsghdr *cm; + char control[CMSG_SPACE(sizeof(*serr))]; + int received; + int ret; + + if (sioc->zero_copy_queued == sioc->zero_copy_sent) { + return 0; + } + + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + memset(control, 0, sizeof(control)); + + ret = 1; + + while (sioc->zero_copy_sent < sioc->zero_copy_queued) { + received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE); + if (received < 0) { + switch (errno) { + case EAGAIN: + /* Nothing on errqueue, wait until something is available */ + qio_channel_wait(ioc, G_IO_ERR); + continue; + case EINTR: + continue; + default: + error_setg_errno(errp, errno, + "Unable to read errqueue"); + return -1; + } + } + + cm = CMSG_FIRSTHDR(&msg); + 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; + } + + serr = (void *) CMSG_DATA(cm); + if (serr->ee_errno != SO_EE_ORIGIN_NONE) { + error_setg_errno(errp, serr->ee_errno, + "Error on socket"); + return -1; + } + if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) { + error_setg_errno(errp, serr->ee_origin, + "Error not from zero copy"); + return -1; + } + + /* No errors, count successfully finished sendmsg()*/ + sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1; + + /* If any sendmsg() succeeded using zero copy, return 0 at the end */ + if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) { + ret = 0; + } + } + + return ret; +} + +#endif /* QEMU_MSG_ZEROCOPY */ + static int qio_channel_socket_set_blocking(QIOChannel *ioc, bool enabled, @@ -666,9 +787,9 @@ qio_channel_socket_set_blocking(QIOChannel *ioc, QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); if (enabled) { - qemu_set_block(sioc->fd); + qemu_socket_set_block(sioc->fd); } else { - qemu_set_nonblock(sioc->fd); + qemu_socket_set_nonblock(sioc->fd); } return 0; } @@ -788,6 +909,9 @@ static void qio_channel_socket_class_init(ObjectClass *klass, ioc_klass->io_set_delay = qio_channel_socket_set_delay; ioc_klass->io_create_watch = qio_channel_socket_create_watch; ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler; +#ifdef QEMU_MSG_ZEROCOPY + ioc_klass->io_flush = qio_channel_socket_flush; +#endif } static const TypeInfo qio_channel_socket_info = { diff --git a/io/channel-tls.c b/io/channel-tls.c index 2ae1b92fc0a8..4ce890a53820 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -301,6 +301,7 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); diff --git a/io/channel-watch.c b/io/channel-watch.c index 0289b3647c27..ad7c568a84d3 100644 --- a/io/channel-watch.c +++ b/io/channel-watch.c @@ -115,28 +115,24 @@ static gboolean qio_channel_socket_source_check(GSource *source) { static struct timeval tv0; - QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; - WSANETWORKEVENTS ev; fd_set rfds, wfds, xfds; if (!ssource->condition) { return 0; } - WSAEnumNetworkEvents(ssource->socket, ssource->ioc->event, &ev); - FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); if (ssource->condition & G_IO_IN) { - FD_SET((SOCKET)ssource->socket, &rfds); + FD_SET(ssource->socket, &rfds); } if (ssource->condition & G_IO_OUT) { - FD_SET((SOCKET)ssource->socket, &wfds); + FD_SET(ssource->socket, &wfds); } if (ssource->condition & G_IO_PRI) { - FD_SET((SOCKET)ssource->socket, &xfds); + FD_SET(ssource->socket, &xfds); } ssource->revents = 0; if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) { @@ -285,11 +281,9 @@ GSource *qio_channel_create_socket_watch(QIOChannel *ioc, GSource *source; QIOChannelSocketSource *ssource; -#ifdef WIN32 WSAEventSelect(socket, ioc->event, FD_READ | FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_WRITE | FD_OOB); -#endif source = g_source_new(&qio_channel_socket_source_funcs, sizeof(QIOChannelSocketSource)); diff --git a/io/channel-websock.c b/io/channel-websock.c index 55145a6a8c5d..fb4932ade70f 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" @@ -1127,6 +1127,7 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); diff --git a/io/channel.c b/io/channel.c index e8b019dc36e2..0640941ac573 100644 --- a/io/channel.c +++ b/io/channel.c @@ -72,18 +72,32 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); - if ((fds || nfds) && - !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { + if (fds || nfds) { + if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { + error_setg_errno(errp, EINVAL, + "Channel does not support file descriptor passing"); + return -1; + } + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { + error_setg_errno(errp, EINVAL, + "Zero Copy does not support file descriptor passing"); + return -1; + } + } + + if ((flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) && + !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { error_setg_errno(errp, EINVAL, - "Channel does not support file descriptor passing"); + "Requested Zero Copy feature is not available"); return -1; } - return klass->io_writev(ioc, iov, niov, fds, nfds, errp); + return klass->io_writev(ioc, iov, niov, fds, nfds, flags, errp); } @@ -217,14 +231,14 @@ int qio_channel_writev_all(QIOChannel *ioc, size_t niov, Error **errp) { - return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, errp); + return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, 0, errp); } int qio_channel_writev_full_all(QIOChannel *ioc, const struct iovec *iov, size_t niov, int *fds, size_t nfds, - Error **errp) + int flags, Error **errp) { int ret = -1; struct iovec *local_iov = g_new(struct iovec, niov); @@ -237,8 +251,10 @@ int qio_channel_writev_full_all(QIOChannel *ioc, while (nlocal_iov > 0) { ssize_t len; - len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, nfds, - errp); + + len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, + nfds, flags, errp); + if (len == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { qio_channel_yield(ioc, G_IO_OUT); @@ -277,7 +293,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc, size_t niov, Error **errp) { - return qio_channel_writev_full(ioc, iov, niov, NULL, 0, errp); + return qio_channel_writev_full(ioc, iov, niov, NULL, 0, 0, errp); } @@ -297,7 +313,7 @@ ssize_t qio_channel_write(QIOChannel *ioc, Error **errp) { struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; - return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, errp); + return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, 0, errp); } @@ -473,6 +489,19 @@ off_t qio_channel_io_seek(QIOChannel *ioc, return klass->io_seek(ioc, offset, whence, errp); } +int qio_channel_flush(QIOChannel *ioc, + Error **errp) +{ + QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); + + if (!klass->io_flush || + !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { + return 0; + } + + return klass->io_flush(ioc, errp); +} + static void qio_channel_restart_read(void *opaque) { diff --git a/io/meson.build b/io/meson.build index bbcd3c53a4a3..283b9b2bdbdf 100644 --- a/io/meson.build +++ b/io/meson.build @@ -3,6 +3,7 @@ io_ss.add(files( 'channel-buffer.c', 'channel-command.c', 'channel-file.c', + 'channel-null.c', 'channel-socket.c', 'channel-tls.c', 'channel-util.c', diff --git a/io/trace-events b/io/trace-events index c5e814eb4466..3cc5cf1efdf3 100644 --- a/io/trace-events +++ b/io/trace-events @@ -10,6 +10,9 @@ qio_task_thread_result(void *task) "Task thread result task=%p" qio_task_thread_source_attach(void *task, void *source) "Task thread source attach task=%p source=%p" qio_task_thread_source_cancel(void *task, void *source) "Task thread source cancel task=%p source=%p" +# channel-null.c +qio_channel_null_new(void *ioc) "Null new ioc=%p" + # channel-socket.c qio_channel_socket_new(void *ioc) "Socket new ioc=%p" qio_channel_socket_new_fd(void *ioc, int fd) "Socket new ioc=%p fd=%d" diff --git a/iothread.c b/iothread.c index 0f98af0f2aa0..3862a6447124 100644 --- a/iothread.c +++ b/iothread.c @@ -17,6 +17,7 @@ #include "qemu/module.h" #include "block/aio.h" #include "block/block.h" +#include "sysemu/event-loop-base.h" #include "sysemu/iothread.h" #include "qapi/error.h" #include "qapi/qapi-commands-misc.h" @@ -152,9 +153,14 @@ static void iothread_init_gcontext(IOThread *iothread) iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE); } -static void iothread_set_aio_context_params(IOThread *iothread, Error **errp) +static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp) { ERRP_GUARD(); + IOThread *iothread = IOTHREAD(base); + + if (!iothread->ctx) { + return; + } aio_context_set_poll_params(iothread->ctx, iothread->poll_max_ns, @@ -166,14 +172,18 @@ static void iothread_set_aio_context_params(IOThread *iothread, Error **errp) } aio_context_set_aio_params(iothread->ctx, - iothread->aio_max_batch, + iothread->parent_obj.aio_max_batch, errp); + + aio_context_set_thread_pool_params(iothread->ctx, base->thread_pool_min, + base->thread_pool_max, errp); } -static void iothread_complete(UserCreatable *obj, Error **errp) + +static void iothread_init(EventLoopBase *base, Error **errp) { Error *local_error = NULL; - IOThread *iothread = IOTHREAD(obj); + IOThread *iothread = IOTHREAD(base); char *thread_name; iothread->stopping = false; @@ -189,7 +199,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) */ iothread_init_gcontext(iothread); - iothread_set_aio_context_params(iothread, &local_error); + iothread_set_aio_context_params(base, &local_error); if (local_error) { error_propagate(errp, local_error); aio_context_unref(iothread->ctx); @@ -201,7 +211,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) * to inherit. */ thread_name = g_strdup_printf("IO %s", - object_get_canonical_path_component(OBJECT(obj))); + object_get_canonical_path_component(OBJECT(base))); qemu_thread_create(&iothread->thread, thread_name, iothread_run, iothread, QEMU_THREAD_JOINABLE); g_free(thread_name); @@ -226,9 +236,6 @@ static IOThreadParamInfo poll_grow_info = { static IOThreadParamInfo poll_shrink_info = { "poll-shrink", offsetof(IOThread, poll_shrink), }; -static IOThreadParamInfo aio_max_batch_info = { - "aio-max-batch", offsetof(IOThread, aio_max_batch), -}; static void iothread_get_param(Object *obj, Visitor *v, const char *name, IOThreadParamInfo *info, Error **errp) @@ -288,35 +295,12 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, } } -static void iothread_get_aio_param(Object *obj, Visitor *v, - const char *name, void *opaque, Error **errp) -{ - IOThreadParamInfo *info = opaque; - - iothread_get_param(obj, v, name, info, errp); -} - -static void iothread_set_aio_param(Object *obj, Visitor *v, - const char *name, void *opaque, Error **errp) -{ - IOThread *iothread = IOTHREAD(obj); - IOThreadParamInfo *info = opaque; - - if (!iothread_set_param(obj, v, name, info, errp)) { - return; - } - - if (iothread->ctx) { - aio_context_set_aio_params(iothread->ctx, - iothread->aio_max_batch, - errp); - } -} - static void iothread_class_init(ObjectClass *klass, void *class_data) { - UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); - ucc->complete = iothread_complete; + EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass); + + bc->init = iothread_init; + bc->update_params = iothread_set_aio_context_params; object_class_property_add(klass, "poll-max-ns", "int", iothread_get_poll_param, @@ -330,23 +314,15 @@ static void iothread_class_init(ObjectClass *klass, void *class_data) iothread_get_poll_param, iothread_set_poll_param, NULL, &poll_shrink_info); - object_class_property_add(klass, "aio-max-batch", "int", - iothread_get_aio_param, - iothread_set_aio_param, - NULL, &aio_max_batch_info); } static const TypeInfo iothread_info = { .name = TYPE_IOTHREAD, - .parent = TYPE_OBJECT, + .parent = TYPE_EVENT_LOOP_BASE, .class_init = iothread_class_init, .instance_size = sizeof(IOThread), .instance_init = iothread_instance_init, .instance_finalize = iothread_instance_finalize, - .interfaces = (InterfaceInfo[]) { - {TYPE_USER_CREATABLE}, - {} - }, }; static void iothread_register_types(void) @@ -383,7 +359,7 @@ static int query_one_iothread(Object *object, void *opaque) info->poll_max_ns = iothread->poll_max_ns; info->poll_grow = iothread->poll_grow; info->poll_shrink = iothread->poll_shrink; - info->aio_max_batch = iothread->aio_max_batch; + info->aio_max_batch = iothread->parent_obj.aio_max_batch; QAPI_LIST_APPEND(*tail, info); return 0; diff --git a/job-qmp.c b/job-qmp.c index 829a28aa70e3..9e26fa899f6b 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'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_ref_locked(job); + job_finalize_locked(job, errp); + + 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; @@ -158,8 +156,7 @@ static JobInfo *job_query_single(Job *job, Error **errp) .status = job->status, .current_progress = progress_current, .total_progress = progress_total, - .has_error = !!job->err, - .error = job->err ? \ + .error = job->err ? g_strdup(error_get_pretty(job->err)) : NULL, }; @@ -171,17 +168,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 075c6f3a202c..72d57f09345b 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,19 +243,32 @@ 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_is_ready(Job *job) +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: @@ -249,7 +290,13 @@ bool job_is_ready(Job *job) return false; } -bool job_is_completed(Job *job) +bool job_is_ready(Job *job) +{ + JOB_LOCK_GUARD(); + return job_is_ready_locked(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(); + + next_aio_context = job->aio_context; + /* + * Coroutine has resumed, but in the meanwhile the job AioContext + * might have changed via bdrv_try_change_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() before re-entering the coroutine. */ + /* 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_completed(job); + job_event_idle_locked(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(Job *job, bool force) +int job_cancel_sync_locked(Job *job, bool force) { if (force) { - return job_finish_sync(job, &job_force_cancel_err, NULL); + return job_finish_sync_locked(job, &job_force_cancel_err_locked, NULL); } else { - return job_finish_sync(job, &job_cancel_err, NULL); + return job_finish_sync_locked(job, &job_cancel_err_locked, NULL); } } +int job_cancel_sync(Job *job, bool force) +{ + 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/libdecnumber/dpd/decimal64.c b/libdecnumber/dpd/decimal64.c index 4816176410f9..290dbe817717 100644 --- a/libdecnumber/dpd/decimal64.c +++ b/libdecnumber/dpd/decimal64.c @@ -617,7 +617,6 @@ static const uInt multies[]={131073, 26215, 5243, 1049, 210}; #endif void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { Int cut; /* work */ - Int n; /* output bunch counter */ Int digits=dn->digits; /* digit countdown */ uInt dpd; /* densely packed decimal value */ uInt bin; /* binary value 0-999 */ @@ -676,7 +675,7 @@ void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { bin=0; /* [keep compiler quiet] */ #endif - for(n=0; digits>0; n++) { /* each output bunch */ + while (digits > 0) { /* each output bunch */ #if DECDPUN==3 /* fast path, 3-at-a-time */ bin=*inu; /* 3 digits ready for convert */ digits-=3; /* [may go negative] */ diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 3d2ce9912dc6..4bf2d7246e5c 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 */ }; @@ -281,6 +285,11 @@ struct kvm_arm_copy_mte_tags { #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 KVM_REG_ARM_FW_REG(3) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL 0 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL 1 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED 2 + /* SVE registers */ #define KVM_REG_ARM64_SVE (0x15 << KVM_REG_ARM_COPROC_SHIFT) @@ -327,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 @@ -362,6 +396,7 @@ struct kvm_arm_copy_mte_tags { #define KVM_ARM_VCPU_PMU_V3_IRQ 0 #define KVM_ARM_VCPU_PMU_V3_INIT 1 #define KVM_ARM_VCPU_PMU_V3_FILTER 2 +#define KVM_ARM_VCPU_PMU_V3_SET_PMU 3 #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 @@ -411,6 +446,16 @@ struct kvm_arm_copy_mte_tags { #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED +/* arm64-specific kvm_run::system_event flags */ +/* + * Reset caused by a PSCI v1.1 SYSTEM_RESET2 call. + * Valid only when the system event has a type of KVM_SYSTEM_EVENT_RESET. + */ +#define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (1ULL << 0) + +/* run->fail_entry.hardware_entry_failure_reason codes. */ +#define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) + #endif #endif /* __ARM_KVM_H__ */ diff --git a/linux-headers/asm-generic/mman-common.h b/linux-headers/asm-generic/mman-common.h index 1567a3294c3d..6c1aa92a92e4 100644 --- a/linux-headers/asm-generic/mman-common.h +++ b/linux-headers/asm-generic/mman-common.h @@ -75,6 +75,8 @@ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ +#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h index 1c48b0ae3ba3..45fa180cc56a 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-mips/mman.h b/linux-headers/asm-mips/mman.h index 40b210c65a5a..1be428663c10 100644 --- a/linux-headers/asm-mips/mman.h +++ b/linux-headers/asm-mips/mman.h @@ -101,6 +101,8 @@ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ +#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h index f808ad1ce500..7351417afd62 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 8062996c2dfd..73d7cdd2ec49 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 f053b8304a85..e2afd95420bb 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 bf6e96011dfe..46de10a809ec 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 d4a8d0424bfb..775dbd3aff73 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 d232feaae972..ebdafa576d6f 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,8 +446,15 @@ 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; - __u64 flags; + __u32 ndata; + union { + __u64 flags; + __u64 data[16]; + }; } system_event; /* KVM_EXIT_S390_STSI */ struct { @@ -487,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]; }; @@ -533,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 \ @@ -562,9 +583,12 @@ struct kvm_s390_mem_op { __u32 op; /* type of operation */ __u64 buf; /* buffer in userspace */ union { - __u8 ar; /* the access register number */ + struct { + __u8 ar; /* the access register number */ + __u8 key; /* access key, ignored if flag unset */ + }; __u32 sida_offset; /* offset into the sida */ - __u8 reserved[32]; /* should be set to 0 */ + __u8 reserved[32]; /* ignored */ }; }; /* types for kvm_s390_mem_op->op */ @@ -572,9 +596,12 @@ struct kvm_s390_mem_op { #define KVM_S390_MEMOP_LOGICAL_WRITE 1 #define KVM_S390_MEMOP_SIDA_READ 2 #define KVM_S390_MEMOP_SIDA_WRITE 3 +#define KVM_S390_MEMOP_ABSOLUTE_READ 4 +#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5 /* flags for kvm_s390_mem_op->flags */ #define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) #define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) +#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2) /* for KVM_INTERRUPT */ struct kvm_interrupt { @@ -606,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 */ @@ -634,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; @@ -1134,6 +1162,19 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_GPA_BITS 207 #define KVM_CAP_XSAVE2 208 #define KVM_CAP_SYS_ATTRIBUTES 209 +#define KVM_CAP_PPC_AIL_MODE_3 210 +#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_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 @@ -1198,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 @@ -1222,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; @@ -1317,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 { @@ -1460,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 */ @@ -1624,9 +1667,6 @@ struct kvm_enc_region { #define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) #define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) -/* Available with KVM_CAP_XSAVE2 */ -#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) - struct kvm_s390_pv_sec_parm { __u64 origin; __u64 length; @@ -1638,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, @@ -1646,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 { @@ -1679,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; }; @@ -1687,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) @@ -1709,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; }; @@ -1719,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 { @@ -1973,6 +2107,8 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_PMU_CAP_DISABLE (1 << 0) + /** * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * @flags: Some extra information for header, always 0 for now. @@ -2016,7 +2152,8 @@ struct kvm_stats_header { #define KVM_STATS_UNIT_BYTES (0x1 << KVM_STATS_UNIT_SHIFT) #define KVM_STATS_UNIT_SECONDS (0x2 << KVM_STATS_UNIT_SHIFT) #define KVM_STATS_UNIT_CYCLES (0x3 << KVM_STATS_UNIT_SHIFT) -#define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_CYCLES +#define KVM_STATS_UNIT_BOOLEAN (0x4 << KVM_STATS_UNIT_SHIFT) +#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) @@ -2051,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/psci.h b/linux-headers/linux/psci.h index a6772d508b25..213b2a0f70b5 100644 --- a/linux-headers/linux/psci.h +++ b/linux-headers/linux/psci.h @@ -82,6 +82,10 @@ #define PSCI_0_2_TOS_UP_NO_MIGRATE 1 #define PSCI_0_2_TOS_MP 2 +/* PSCI v1.1 reset type encoding for SYSTEM_RESET2 */ +#define PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET 0 +#define PSCI_1_1_RESET_TYPE_VENDOR_START 0x80000000U + /* PSCI version decoding (independent of PSCI version) */ #define PSCI_VERSION_MAJOR_SHIFT 16 #define PSCI_VERSION_MINOR_MASK \ diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index 8479af5f4c73..a3a377cd4491 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -32,7 +32,9 @@ UFFD_FEATURE_SIGBUS | \ UFFD_FEATURE_THREAD_ID | \ UFFD_FEATURE_MINOR_HUGETLBFS | \ - UFFD_FEATURE_MINOR_SHMEM) + UFFD_FEATURE_MINOR_SHMEM | \ + UFFD_FEATURE_EXACT_ADDRESS | \ + UFFD_FEATURE_WP_HUGETLBFS_SHMEM) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -46,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 @@ -189,6 +192,13 @@ struct uffdio_api { * * UFFD_FEATURE_MINOR_SHMEM indicates the same support as * UFFD_FEATURE_MINOR_HUGETLBFS, but for shmem-backed pages instead. + * + * 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) @@ -201,6 +211,8 @@ struct uffdio_api { #define UFFD_FEATURE_THREAD_ID (1<<8) #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 new file mode 100644 index 000000000000..6d2ca064b5d6 --- /dev/null +++ b/linux-headers/linux/vduse.h @@ -0,0 +1,353 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _VDUSE_H_ +#define _VDUSE_H_ + +#include + +#define VDUSE_BASE 0x81 + +/* The ioctls for control device (/dev/vduse/control) */ + +#define VDUSE_API_VERSION 0 + +/* + * Get the version of VDUSE API that kernel supported (VDUSE_API_VERSION). + * This is used for future extension. + */ +#define VDUSE_GET_API_VERSION _IOR(VDUSE_BASE, 0x00, __u64) + +/* Set the version of VDUSE API that userspace supported. */ +#define VDUSE_SET_API_VERSION _IOW(VDUSE_BASE, 0x01, __u64) + +/** + * struct vduse_dev_config - basic configuration of a VDUSE device + * @name: VDUSE device name, needs to be NUL terminated + * @vendor_id: virtio vendor id + * @device_id: virtio device id + * @features: virtio features + * @vq_num: the number of virtqueues + * @vq_align: the allocation alignment of virtqueue's metadata + * @reserved: for future use, needs to be initialized to zero + * @config_size: the size of the configuration space + * @config: the buffer of the configuration space + * + * Structure used by VDUSE_CREATE_DEV ioctl to create VDUSE device. + */ +struct vduse_dev_config { +#define VDUSE_NAME_MAX 256 + char name[VDUSE_NAME_MAX]; + __u32 vendor_id; + __u32 device_id; + __u64 features; + __u32 vq_num; + __u32 vq_align; + __u32 reserved[13]; + __u32 config_size; + __u8 config[]; +}; + +/* Create a VDUSE device which is represented by a char device (/dev/vduse/$NAME) */ +#define VDUSE_CREATE_DEV _IOW(VDUSE_BASE, 0x02, struct vduse_dev_config) + +/* + * Destroy a VDUSE device. Make sure there are no more references + * to the char device (/dev/vduse/$NAME). + */ +#define VDUSE_DESTROY_DEV _IOW(VDUSE_BASE, 0x03, char[VDUSE_NAME_MAX]) + +/* The ioctls for VDUSE device (/dev/vduse/$NAME) */ + +/** + * struct vduse_iotlb_entry - entry of IOTLB to describe one IOVA region [start, last] + * @offset: the mmap offset on returned file descriptor + * @start: start of the IOVA region + * @last: last of the IOVA region + * @perm: access permission of the IOVA region + * + * Structure used by VDUSE_IOTLB_GET_FD ioctl to find an overlapped IOVA region. + */ +struct vduse_iotlb_entry { + __u64 offset; + __u64 start; + __u64 last; +#define VDUSE_ACCESS_RO 0x1 +#define VDUSE_ACCESS_WO 0x2 +#define VDUSE_ACCESS_RW 0x3 + __u8 perm; +}; + +/* + * Find the first IOVA region that overlaps with the range [start, last] + * and return the corresponding file descriptor. Return -EINVAL means the + * IOVA region doesn't exist. Caller should set start and last fields. + */ +#define VDUSE_IOTLB_GET_FD _IOWR(VDUSE_BASE, 0x10, struct vduse_iotlb_entry) + +/* + * Get the negotiated virtio features. It's a subset of the features in + * struct vduse_dev_config which can be accepted by virtio driver. It's + * only valid after FEATURES_OK status bit is set. + */ +#define VDUSE_DEV_GET_FEATURES _IOR(VDUSE_BASE, 0x11, __u64) + +/** + * struct vduse_config_data - data used to update configuration space + * @offset: the offset from the beginning of configuration space + * @length: the length to write to configuration space + * @buffer: the buffer used to write from + * + * Structure used by VDUSE_DEV_SET_CONFIG ioctl to update device + * configuration space. + */ +struct vduse_config_data { + __u32 offset; + __u32 length; + __u8 buffer[]; +}; + +/* Set device configuration space */ +#define VDUSE_DEV_SET_CONFIG _IOW(VDUSE_BASE, 0x12, struct vduse_config_data) + +/* + * Inject a config interrupt. It's usually used to notify virtio driver + * that device configuration space has changed. + */ +#define VDUSE_DEV_INJECT_CONFIG_IRQ _IO(VDUSE_BASE, 0x13) + +/** + * struct vduse_vq_config - basic configuration of a virtqueue + * @index: virtqueue index + * @max_size: the max size of virtqueue + * @reserved: for future use, needs to be initialized to zero + * + * Structure used by VDUSE_VQ_SETUP ioctl to setup a virtqueue. + */ +struct vduse_vq_config { + __u32 index; + __u16 max_size; + __u16 reserved[13]; +}; + +/* + * Setup the specified virtqueue. Make sure all virtqueues have been + * configured before the device is attached to vDPA bus. + */ +#define VDUSE_VQ_SETUP _IOW(VDUSE_BASE, 0x14, struct vduse_vq_config) + +/** + * struct vduse_vq_state_split - split virtqueue state + * @avail_index: available index + */ +struct vduse_vq_state_split { + __u16 avail_index; +}; + +/** + * struct vduse_vq_state_packed - packed virtqueue state + * @last_avail_counter: last driver ring wrap counter observed by device + * @last_avail_idx: device available index + * @last_used_counter: device ring wrap counter + * @last_used_idx: used index + */ +struct vduse_vq_state_packed { + __u16 last_avail_counter; + __u16 last_avail_idx; + __u16 last_used_counter; + __u16 last_used_idx; +}; + +/** + * struct vduse_vq_info - information of a virtqueue + * @index: virtqueue index + * @num: the size of virtqueue + * @desc_addr: address of desc area + * @driver_addr: address of driver area + * @device_addr: address of device area + * @split: split virtqueue state + * @packed: packed virtqueue state + * @ready: ready status of virtqueue + * + * Structure used by VDUSE_VQ_GET_INFO ioctl to get virtqueue's information. + */ +struct vduse_vq_info { + __u32 index; + __u32 num; + __u64 desc_addr; + __u64 driver_addr; + __u64 device_addr; + union { + struct vduse_vq_state_split split; + struct vduse_vq_state_packed packed; + }; + __u8 ready; +}; + +/* Get the specified virtqueue's information. Caller should set index field. */ +#define VDUSE_VQ_GET_INFO _IOWR(VDUSE_BASE, 0x15, struct vduse_vq_info) + +/** + * struct vduse_vq_eventfd - eventfd configuration for a virtqueue + * @index: virtqueue index + * @fd: eventfd, -1 means de-assigning the eventfd + * + * Structure used by VDUSE_VQ_SETUP_KICKFD ioctl to setup kick eventfd. + */ +struct vduse_vq_eventfd { + __u32 index; +#define VDUSE_EVENTFD_DEASSIGN -1 + int fd; +}; + +/* + * Setup kick eventfd for specified virtqueue. The kick eventfd is used + * by VDUSE kernel module to notify userspace to consume the avail vring. + */ +#define VDUSE_VQ_SETUP_KICKFD _IOW(VDUSE_BASE, 0x16, struct vduse_vq_eventfd) + +/* + * Inject an interrupt for specific virtqueue. It's used to notify virtio driver + * to consume the used vring. + */ +#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 */ + +/** + * enum vduse_req_type - request type + * @VDUSE_GET_VQ_STATE: get the state for specified virtqueue from userspace + * @VDUSE_SET_STATUS: set the device status + * @VDUSE_UPDATE_IOTLB: Notify userspace to update the memory mapping for + * specified IOVA range via VDUSE_IOTLB_GET_FD ioctl + */ +enum vduse_req_type { + VDUSE_GET_VQ_STATE, + VDUSE_SET_STATUS, + VDUSE_UPDATE_IOTLB, +}; + +/** + * struct vduse_vq_state - virtqueue state + * @index: virtqueue index + * @split: split virtqueue state + * @packed: packed virtqueue state + */ +struct vduse_vq_state { + __u32 index; + union { + struct vduse_vq_state_split split; + struct vduse_vq_state_packed packed; + }; +}; + +/** + * struct vduse_dev_status - device status + * @status: device status + */ +struct vduse_dev_status { + __u8 status; +}; + +/** + * struct vduse_iova_range - IOVA range [start, last] + * @start: start of the IOVA range + * @last: last of the IOVA range + */ +struct vduse_iova_range { + __u64 start; + __u64 last; +}; + +/** + * struct vduse_dev_request - control request + * @type: request type + * @request_id: request id + * @reserved: for future use + * @vq_state: virtqueue state, only index field is available + * @s: device status + * @iova: IOVA range for updating + * @padding: padding + * + * Structure used by read(2) on /dev/vduse/$NAME. + */ +struct vduse_dev_request { + __u32 type; + __u32 request_id; + __u32 reserved[4]; + union { + struct vduse_vq_state vq_state; + struct vduse_dev_status s; + struct vduse_iova_range iova; + __u32 padding[32]; + }; +}; + +/** + * struct vduse_dev_response - response to control request + * @request_id: corresponding request id + * @result: the result of request + * @reserved: for future use, needs to be initialized to zero + * @vq_state: virtqueue state + * @padding: padding + * + * Structure used by write(2) on /dev/vduse/$NAME. + */ +struct vduse_dev_response { + __u32 request_id; +#define VDUSE_REQ_RESULT_OK 0x00 +#define VDUSE_REQ_RESULT_FAILED 0x01 + __u32 result; + __u32 reserved[4]; + union { + struct vduse_vq_state vq_state; + __u32 padding[32]; + }; +}; + +#endif /* _VDUSE_H_ */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index e680594f27b7..ede44b557253 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -323,7 +323,7 @@ struct vfio_region_info_cap_type { #define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff) #define VFIO_REGION_TYPE_GFX (1) #define VFIO_REGION_TYPE_CCW (2) -#define VFIO_REGION_TYPE_MIGRATION (3) +#define VFIO_REGION_TYPE_MIGRATION_DEPRECATED (3) /* sub-types for VFIO_REGION_TYPE_PCI_* */ @@ -405,225 +405,29 @@ struct vfio_region_gfx_edid { #define VFIO_REGION_SUBTYPE_CCW_CRW (3) /* sub-types for VFIO_REGION_TYPE_MIGRATION */ -#define VFIO_REGION_SUBTYPE_MIGRATION (1) - -/* - * The structure vfio_device_migration_info is placed at the 0th offset of - * the VFIO_REGION_SUBTYPE_MIGRATION region to get and set VFIO device related - * migration information. Field accesses from this structure are only supported - * at their native width and alignment. Otherwise, the result is undefined and - * vendor drivers should return an error. - * - * device_state: (read/write) - * - The user application writes to this field to inform the vendor driver - * about the device state to be transitioned to. - * - The vendor driver should take the necessary actions to change the - * device state. After successful transition to a given state, the - * vendor driver should return success on write(device_state, state) - * system call. If the device state transition fails, the vendor driver - * should return an appropriate -errno for the fault condition. - * - On the user application side, if the device state transition fails, - * that is, if write(device_state, state) returns an error, read - * device_state again to determine the current state of the device from - * the vendor driver. - * - The vendor driver should return previous state of the device unless - * the vendor driver has encountered an internal error, in which case - * the vendor driver may report the device_state VFIO_DEVICE_STATE_ERROR. - * - The user application must use the device reset ioctl to recover the - * device from VFIO_DEVICE_STATE_ERROR state. If the device is - * indicated to be in a valid device state by reading device_state, the - * user application may attempt to transition the device to any valid - * state reachable from the current state or terminate itself. - * - * device_state consists of 3 bits: - * - If bit 0 is set, it indicates the _RUNNING state. If bit 0 is clear, - * it indicates the _STOP state. When the device state is changed to - * _STOP, driver should stop the device before write() returns. - * - If bit 1 is set, it indicates the _SAVING state, which means that the - * driver should start gathering device state information that will be - * provided to the VFIO user application to save the device's state. - * - If bit 2 is set, it indicates the _RESUMING state, which means that - * the driver should prepare to resume the device. Data provided through - * the migration region should be used to resume the device. - * Bits 3 - 31 are reserved for future use. To preserve them, the user - * application should perform a read-modify-write operation on this - * field when modifying the specified bits. - * - * +------- _RESUMING - * |+------ _SAVING - * ||+----- _RUNNING - * ||| - * 000b => Device Stopped, not saving or resuming - * 001b => Device running, which is the default state - * 010b => Stop the device & save the device state, stop-and-copy state - * 011b => Device running and save the device state, pre-copy state - * 100b => Device stopped and the device state is resuming - * 101b => Invalid state - * 110b => Error state - * 111b => Invalid state - * - * State transitions: - * - * _RESUMING _RUNNING Pre-copy Stop-and-copy _STOP - * (100b) (001b) (011b) (010b) (000b) - * 0. Running or default state - * | - * - * 1. Normal Shutdown (optional) - * |------------------------------------->| - * - * 2. Save the state or suspend - * |------------------------->|---------->| - * - * 3. Save the state during live migration - * |----------->|------------>|---------->| - * - * 4. Resuming - * |<---------| - * - * 5. Resumed - * |--------->| - * - * 0. Default state of VFIO device is _RUNNING when the user application starts. - * 1. During normal shutdown of the user application, the user application may - * optionally change the VFIO device state from _RUNNING to _STOP. This - * transition is optional. The vendor driver must support this transition but - * must not require it. - * 2. When the user application saves state or suspends the application, the - * device state transitions from _RUNNING to stop-and-copy and then to _STOP. - * On state transition from _RUNNING to stop-and-copy, driver must stop the - * device, save the device state and send it to the application through the - * migration region. The sequence to be followed for such transition is given - * below. - * 3. In live migration of user application, the state transitions from _RUNNING - * to pre-copy, to stop-and-copy, and to _STOP. - * On state transition from _RUNNING to pre-copy, the driver should start - * gathering the device state while the application is still running and send - * the device state data to application through the migration region. - * On state transition from pre-copy to stop-and-copy, the driver must stop - * the device, save the device state and send it to the user application - * through the migration region. - * Vendor drivers must support the pre-copy state even for implementations - * where no data is provided to the user before the stop-and-copy state. The - * user must not be required to consume all migration data before the device - * transitions to a new state, including the stop-and-copy state. - * The sequence to be followed for above two transitions is given below. - * 4. To start the resuming phase, the device state should be transitioned from - * the _RUNNING to the _RESUMING state. - * In the _RESUMING state, the driver should use the device state data - * received through the migration region to resume the device. - * 5. After providing saved device data to the driver, the application should - * change the state from _RESUMING to _RUNNING. - * - * reserved: - * Reads on this field return zero and writes are ignored. - * - * pending_bytes: (read only) - * The number of pending bytes still to be migrated from the vendor driver. - * - * data_offset: (read only) - * The user application should read data_offset field from the migration - * region. The user application should read the device data from this - * offset within the migration region during the _SAVING state or write - * the device data during the _RESUMING state. See below for details of - * sequence to be followed. - * - * data_size: (read/write) - * The user application should read data_size to get the size in bytes of - * the data copied in the migration region during the _SAVING state and - * write the size in bytes of the data copied in the migration region - * during the _RESUMING state. - * - * The format of the migration region is as follows: - * ------------------------------------------------------------------ - * |vfio_device_migration_info| data section | - * | | /////////////////////////////// | - * ------------------------------------------------------------------ - * ^ ^ - * offset 0-trapped part data_offset - * - * The structure vfio_device_migration_info is always followed by the data - * section in the region, so data_offset will always be nonzero. The offset - * from where the data is copied is decided by the kernel driver. The data - * section can be trapped, mmapped, or partitioned, depending on how the kernel - * driver defines the data section. The data section partition can be defined - * as mapped by the sparse mmap capability. If mmapped, data_offset must be - * page aligned, whereas initial section which contains the - * vfio_device_migration_info structure, might not end at the offset, which is - * page aligned. The user is not required to access through mmap regardless - * of the capabilities of the region mmap. - * The vendor driver should determine whether and how to partition the data - * section. The vendor driver should return data_offset accordingly. - * - * The sequence to be followed while in pre-copy state and stop-and-copy state - * is as follows: - * a. Read pending_bytes, indicating the start of a new iteration to get device - * data. Repeated read on pending_bytes at this stage should have no side - * effects. - * If pending_bytes == 0, the user application should not iterate to get data - * for that device. - * If pending_bytes > 0, perform the following steps. - * b. Read data_offset, indicating that the vendor driver should make data - * available through the data section. The vendor driver should return this - * read operation only after data is available from (region + data_offset) - * to (region + data_offset + data_size). - * c. Read data_size, which is the amount of data in bytes available through - * the migration region. - * Read on data_offset and data_size should return the offset and size of - * the current buffer if the user application reads data_offset and - * data_size more than once here. - * d. Read data_size bytes of data from (region + data_offset) from the - * migration region. - * e. Process the data. - * f. Read pending_bytes, which indicates that the data from the previous - * iteration has been read. If pending_bytes > 0, go to step b. - * - * The user application can transition from the _SAVING|_RUNNING - * (pre-copy state) to the _SAVING (stop-and-copy) state regardless of the - * number of pending bytes. The user application should iterate in _SAVING - * (stop-and-copy) until pending_bytes is 0. - * - * The sequence to be followed while _RESUMING device state is as follows: - * While data for this device is available, repeat the following steps: - * a. Read data_offset from where the user application should write data. - * b. Write migration data starting at the migration region + data_offset for - * the length determined by data_size from the migration source. - * c. Write data_size, which indicates to the vendor driver that data is - * written in the migration region. Vendor driver must return this write - * operations on consuming data. Vendor driver should apply the - * user-provided migration region data to the device resume state. - * - * If an error occurs during the above sequences, the vendor driver can return - * an error code for next read() or write() operation, which will terminate the - * loop. The user application should then take the next necessary action, for - * example, failing migration or terminating the user application. - * - * For the user application, data is opaque. The user application should write - * data in the same order as the data is received and the data should be of - * same transaction size at the source. - */ +#define VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED (1) struct vfio_device_migration_info { __u32 device_state; /* VFIO device state */ -#define VFIO_DEVICE_STATE_STOP (0) -#define VFIO_DEVICE_STATE_RUNNING (1 << 0) -#define VFIO_DEVICE_STATE_SAVING (1 << 1) -#define VFIO_DEVICE_STATE_RESUMING (1 << 2) -#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_RUNNING | \ - VFIO_DEVICE_STATE_SAVING | \ - VFIO_DEVICE_STATE_RESUMING) +#define VFIO_DEVICE_STATE_V1_STOP (0) +#define VFIO_DEVICE_STATE_V1_RUNNING (1 << 0) +#define VFIO_DEVICE_STATE_V1_SAVING (1 << 1) +#define VFIO_DEVICE_STATE_V1_RESUMING (1 << 2) +#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_V1_RUNNING | \ + VFIO_DEVICE_STATE_V1_SAVING | \ + VFIO_DEVICE_STATE_V1_RESUMING) #define VFIO_DEVICE_STATE_VALID(state) \ - (state & VFIO_DEVICE_STATE_RESUMING ? \ - (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_RESUMING : 1) + (state & VFIO_DEVICE_STATE_V1_RESUMING ? \ + (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_V1_RESUMING : 1) #define VFIO_DEVICE_STATE_IS_ERROR(state) \ - ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_SAVING | \ - VFIO_DEVICE_STATE_RESUMING)) + ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_V1_SAVING | \ + VFIO_DEVICE_STATE_V1_RESUMING)) #define VFIO_DEVICE_STATE_SET_ERROR(state) \ - ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_SATE_SAVING | \ - VFIO_DEVICE_STATE_RESUMING) + ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_STATE_V1_SAVING | \ + VFIO_DEVICE_STATE_V1_RESUMING) __u32 reserved; __u64 pending_bytes; @@ -839,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: @@ -966,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 @@ -1002,6 +806,186 @@ struct vfio_device_feature { */ #define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) +/* + * Indicates the device can support the migration API through + * VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE. If this GET succeeds, the RUNNING and + * ERROR states are always supported. Support for additional states is + * indicated via the flags field; at least VFIO_MIGRATION_STOP_COPY must be + * set. + * + * VFIO_MIGRATION_STOP_COPY means that STOP, STOP_COPY and + * RESUMING are supported. + * + * VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P means that RUNNING_P2P + * is supported in addition to the STOP_COPY states. + * + * Other combinations of flags have behavior to be defined in the future. + */ +struct vfio_device_feature_migration { + __aligned_u64 flags; +#define VFIO_MIGRATION_STOP_COPY (1 << 0) +#define VFIO_MIGRATION_P2P (1 << 1) +}; +#define VFIO_DEVICE_FEATURE_MIGRATION 1 + +/* + * Upon VFIO_DEVICE_FEATURE_SET, execute a migration state change on the VFIO + * device. The new state is supplied in device_state, see enum + * vfio_device_mig_state for details + * + * The kernel migration driver must fully transition the device to the new state + * value before the operation returns to the user. + * + * The kernel migration driver must not generate asynchronous device state + * transitions outside of manipulation by the user or the VFIO_DEVICE_RESET + * ioctl as described above. + * + * If this function fails then current device_state may be the original + * operating state or some other state along the combination transition path. + * The user can then decide if it should execute a VFIO_DEVICE_RESET, attempt + * to return to the original state, or attempt to return to some other state + * such as RUNNING or STOP. + * + * If the new_state starts a new data transfer session then the FD associated + * with that session is returned in data_fd. The user is responsible to close + * this FD when it is finished. The user must consider the migration data stream + * carried over the FD to be opaque and must preserve the byte order of the + * stream. The user is not required to preserve buffer segmentation when writing + * the data stream during the RESUMING operation. + * + * Upon VFIO_DEVICE_FEATURE_GET, get the current migration state of the VFIO + * device, data_fd will be -1. + */ +struct vfio_device_feature_mig_state { + __u32 device_state; /* From enum vfio_device_mig_state */ + __s32 data_fd; +}; +#define VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE 2 + +/* + * The device migration Finite State Machine is described by the enum + * vfio_device_mig_state. Some of the FSM arcs will create a migration data + * transfer session by returning a FD, in this case the migration data will + * flow over the FD using read() and write() as discussed below. + * + * There are 5 states to support VFIO_MIGRATION_STOP_COPY: + * RUNNING - The device is running normally + * STOP - The device does not change the internal or external state + * STOP_COPY - The device internal state can be read out + * RESUMING - The device is stopped and is loading a new internal state + * ERROR - The device has failed and must be reset + * + * And 1 optional state to support VFIO_MIGRATION_P2P: + * RUNNING_P2P - RUNNING, except the device cannot do peer to peer DMA + * + * The FSM takes actions on the arcs between FSM states. The driver implements + * the following behavior for the FSM arcs: + * + * RUNNING_P2P -> STOP + * STOP_COPY -> STOP + * While in STOP the device must stop the operation of the device. The device + * must not generate interrupts, DMA, or any other change to external state. + * It must not change its internal state. When stopped the device and kernel + * migration driver must accept and respond to interaction to support external + * subsystems in the STOP state, for example PCI MSI-X and PCI config space. + * Failure by the user to restrict device access while in STOP must not result + * in error conditions outside the user context (ex. host system faults). + * + * The STOP_COPY arc will terminate a data transfer session. + * + * RESUMING -> STOP + * Leaving RESUMING terminates a data transfer session and indicates the + * device should complete processing of the data delivered by write(). The + * kernel migration driver should complete the incorporation of data written + * to the data transfer FD into the device internal state and perform + * final validity and consistency checking of the new device state. If the + * user provided data is found to be incomplete, inconsistent, or otherwise + * invalid, the migration driver must fail the SET_STATE ioctl and + * optionally go to the ERROR state as described below. + * + * While in STOP the device has the same behavior as other STOP states + * described above. + * + * To abort a RESUMING session the device must be reset. + * + * RUNNING_P2P -> RUNNING + * While in RUNNING the device is fully operational, the device may generate + * interrupts, DMA, respond to MMIO, all vfio device regions are functional, + * and the device may advance its internal state. + * + * RUNNING -> RUNNING_P2P + * STOP -> RUNNING_P2P + * While in RUNNING_P2P the device is partially running in the P2P quiescent + * state defined below. + * + * STOP -> STOP_COPY + * This arc begin the process of saving the device state and will return a + * new data_fd. + * + * While in the STOP_COPY state the device has the same behavior as STOP + * with the addition that the data transfers session continues to stream the + * migration state. End of stream on the FD indicates the entire device + * state has been transferred. + * + * The user should take steps to restrict access to vfio device regions while + * the device is in STOP_COPY or risk corruption of the device migration data + * stream. + * + * STOP -> RESUMING + * Entering the RESUMING state starts a process of restoring the device state + * and will return a new data_fd. The data stream fed into the data_fd should + * be taken from the data transfer output of a single FD during saving from + * a compatible device. The migration driver may alter/reset the internal + * device state for this arc if required to prepare the device to receive the + * migration data. + * + * any -> ERROR + * ERROR cannot be specified as a device state, however any transition request + * can be failed with an errno return and may then move the device_state into + * ERROR. In this case the device was unable to execute the requested arc and + * was also unable to restore the device to any valid device_state. + * To recover from ERROR VFIO_DEVICE_RESET must be used to return the + * device_state back to RUNNING. + * + * The optional peer to peer (P2P) quiescent state is intended to be a quiescent + * state for the device for the purposes of managing multiple devices within a + * user context where peer-to-peer DMA between devices may be active. The + * RUNNING_P2P states must prevent the device from initiating + * any new P2P DMA transactions. If the device can identify P2P transactions + * then it can stop only P2P DMA, otherwise it must stop all DMA. The migration + * driver must complete any such outstanding operations prior to completing the + * FSM arc into a P2P state. For the purpose of specification the states + * behave as though the device was fully running if not supported. Like while in + * STOP or STOP_COPY the user must not touch the device, otherwise the state + * can be exited. + * + * The remaining possible transitions are interpreted as combinations of the + * above FSM arcs. As there are multiple paths through the FSM arcs the path + * should be selected based on the following rules: + * - Select the shortest path. + * Refer to vfio_mig_get_next_state() for the result of the algorithm. + * + * The automatic transit through the FSM arcs that make up the combination + * transition is invisible to the user. When working with combination arcs the + * user may see any step along the path in the device_state if SET_STATE + * fails. When handling these types of errors users should anticipate future + * revisions of this protocol using new states and those states becoming + * visible in this case. + * + * The optional states cannot be used with SET_STATE if the device does not + * support them. The user can discover if these states are supported by using + * VFIO_DEVICE_FEATURE_MIGRATION. By using combination transitions the user can + * avoid knowing about these optional states if the kernel driver supports them. + */ +enum vfio_device_mig_state { + VFIO_DEVICE_STATE_ERROR = 0, + VFIO_DEVICE_STATE_STOP = 1, + VFIO_DEVICE_STATE_RUNNING = 2, + VFIO_DEVICE_STATE_STOP_COPY = 3, + VFIO_DEVICE_STATE_RESUMING = 4, + VFIO_DEVICE_STATE_RUNNING_P2P = 5, +}; + /* -------- API for Type1 VFIO IOMMU -------- */ /** diff --git a/linux-headers/linux/vfio_zdev.h b/linux-headers/linux/vfio_zdev.h index b4309397b6b2..77f2aff1f27e 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 c998860d7bbc..f9f115a7c75b 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,4 +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/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 1737e2ea655a..9875d609a91b 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" @@ -90,6 +89,15 @@ void cpu_loop(CPUARMState *env) switch (trapnr) { case EXCP_SWI: + /* + * On syscall, PSTATE.ZA is preserved, along with the ZA matrix. + * PSTATE.SM is cleared, per SMSTOP, which does ResetSVEState. + */ + if (FIELD_EX64(env->svcr, SVCR, SM)) { + env->svcr = FIELD_DP64(env->svcr, SVCR, SM, 0); + arm_rebuild_hflags(env); + arm_reset_sve_state(env); + } ret = do_syscall(env, env->xregs[8], env->xregs[0], @@ -155,7 +163,7 @@ void cpu_loop(CPUARMState *env) force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; case EXCP_SEMIHOST: - env->xregs[0] = do_common_semihosting(cs); + do_common_semihosting(cs); env->pc += 4; break; case EXCP_YIELD: @@ -202,7 +210,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) } env->pc = regs->pc; env->xregs[31] = regs->sp; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN env->cp15.sctlr_el[1] |= SCTLR_E0E; for (i = 1; i < 4; ++i) { env->cp15.sctlr_el[i] |= SCTLR_EE; diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index df9e39a4ba04..6a2c6e06d284 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -78,7 +78,8 @@ struct target_extra_context { struct target_sve_context { struct target_aarch64_ctx head; uint16_t vl; - uint16_t reserved[3]; + uint16_t flags; + uint16_t reserved[2]; /* The actual SVE data immediately follows. It is laid out * according to TARGET_SVE_SIG_{Z,P}REG_OFFSET, based off of * the original struct pointer. @@ -101,6 +102,24 @@ struct target_sve_context { #define TARGET_SVE_SIG_CONTEXT_SIZE(VQ) \ (TARGET_SVE_SIG_PREG_OFFSET(VQ, 17)) +#define TARGET_SVE_SIG_FLAG_SM 1 + +#define TARGET_ZA_MAGIC 0x54366345 + +struct target_za_context { + struct target_aarch64_ctx head; + uint16_t vl; + uint16_t reserved[3]; + /* The actual ZA data immediately follows. */ +}; + +#define TARGET_ZA_SIG_REGS_OFFSET \ + QEMU_ALIGN_UP(sizeof(struct target_za_context), TARGET_SVE_VQ_BYTES) +#define TARGET_ZA_SIG_ZAV_OFFSET(VQ, N) \ + (TARGET_ZA_SIG_REGS_OFFSET + (VQ) * TARGET_SVE_VQ_BYTES * (N)) +#define TARGET_ZA_SIG_CONTEXT_SIZE(VQ) \ + TARGET_ZA_SIG_ZAV_OFFSET(VQ, VQ * TARGET_SVE_VQ_BYTES) + struct target_rt_sigframe { struct target_siginfo info; struct target_ucontext uc; @@ -147,7 +166,7 @@ static void target_setup_fpsimd_record(struct target_fpsimd_context *fpsimd, for (i = 0; i < 32; i++) { uint64_t *q = aa64_vfp_qreg(env, i); -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN __put_user(q[0], &fpsimd->vregs[i * 2 + 1]); __put_user(q[1], &fpsimd->vregs[i * 2]); #else @@ -173,13 +192,17 @@ static void target_setup_end_record(struct target_aarch64_ctx *end) } static void target_setup_sve_record(struct target_sve_context *sve, - CPUARMState *env, int vq, int size) + CPUARMState *env, int size) { - int i, j; + int i, j, vq = sve_vq(env); + memset(sve, 0, sizeof(*sve)); __put_user(TARGET_SVE_MAGIC, &sve->head.magic); __put_user(size, &sve->head.size); __put_user(vq * TARGET_SVE_VQ_BYTES, &sve->vl); + if (FIELD_EX64(env->svcr, SVCR, SM)) { + __put_user(TARGET_SVE_SIG_FLAG_SM, &sve->flags); + } /* Note that SVE regs are stored as a byte stream, with each byte element * at a subsequent address. This corresponds to a little-endian store @@ -200,6 +223,35 @@ static void target_setup_sve_record(struct target_sve_context *sve, } } +static void target_setup_za_record(struct target_za_context *za, + CPUARMState *env, int size) +{ + int vq = sme_vq(env); + int vl = vq * TARGET_SVE_VQ_BYTES; + int i, j; + + memset(za, 0, sizeof(*za)); + __put_user(TARGET_ZA_MAGIC, &za->head.magic); + __put_user(size, &za->head.size); + __put_user(vl, &za->vl); + + if (size == TARGET_ZA_SIG_CONTEXT_SIZE(0)) { + return; + } + assert(size == TARGET_ZA_SIG_CONTEXT_SIZE(vq)); + + /* + * Note that ZA vectors are stored as a byte stream, + * with each byte element at a subsequent address. + */ + for (i = 0; i < vl; ++i) { + uint64_t *z = (void *)za + TARGET_ZA_SIG_ZAV_OFFSET(vq, i); + for (j = 0; j < vq * 2; ++j) { + __put_user_e(env->zarray[i].d[j], z + j, le); + } + } +} + static void target_restore_general_frame(CPUARMState *env, struct target_rt_sigframe *sf) { @@ -233,7 +285,7 @@ static void target_restore_fpsimd_record(CPUARMState *env, for (i = 0; i < 32; i++) { uint64_t *q = aa64_vfp_qreg(env, i); -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN __get_user(q[0], &fpsimd->vregs[i * 2 + 1]); __get_user(q[1], &fpsimd->vregs[i * 2]); #else @@ -243,12 +295,50 @@ static void target_restore_fpsimd_record(CPUARMState *env, } } -static void target_restore_sve_record(CPUARMState *env, - struct target_sve_context *sve, int vq) +static bool target_restore_sve_record(CPUARMState *env, + struct target_sve_context *sve, + int size, int *svcr) { - int i, j; + int i, j, vl, vq, flags; + bool sm; - /* Note that SVE regs are stored as a byte stream, with each byte element + __get_user(vl, &sve->vl); + __get_user(flags, &sve->flags); + + sm = flags & TARGET_SVE_SIG_FLAG_SM; + + /* The cpu must support Streaming or Non-streaming SVE. */ + if (sm + ? !cpu_isar_feature(aa64_sme, env_archcpu(env)) + : !cpu_isar_feature(aa64_sve, env_archcpu(env))) { + return false; + } + + /* + * Note that we cannot use sve_vq() because that depends on the + * current setting of PSTATE.SM, not the state to be restored. + */ + vq = sve_vqm1_for_el_sm(env, 0, sm) + 1; + + /* Reject mismatched VL. */ + if (vl != vq * TARGET_SVE_VQ_BYTES) { + return false; + } + + /* Accept empty record -- used to clear PSTATE.SM. */ + if (size <= sizeof(*sve)) { + return true; + } + + /* Reject non-empty but incomplete record. */ + if (size < TARGET_SVE_SIG_CONTEXT_SIZE(vq)) { + return false; + } + + *svcr = FIELD_DP64(*svcr, SVCR, SM, sm); + + /* + * Note that SVE regs are stored as a byte stream, with each byte element * at a subsequent address. This corresponds to a little-endian load * of our 64-bit hunks. */ @@ -270,6 +360,46 @@ static void target_restore_sve_record(CPUARMState *env, } } } + return true; +} + +static bool target_restore_za_record(CPUARMState *env, + struct target_za_context *za, + int size, int *svcr) +{ + int i, j, vl, vq; + + if (!cpu_isar_feature(aa64_sme, env_archcpu(env))) { + return false; + } + + __get_user(vl, &za->vl); + vq = sme_vq(env); + + /* Reject mismatched VL. */ + if (vl != vq * TARGET_SVE_VQ_BYTES) { + return false; + } + + /* Accept empty record -- used to clear PSTATE.ZA. */ + if (size <= TARGET_ZA_SIG_CONTEXT_SIZE(0)) { + return true; + } + + /* Reject non-empty but incomplete record. */ + if (size < TARGET_ZA_SIG_CONTEXT_SIZE(vq)) { + return false; + } + + *svcr = FIELD_DP64(*svcr, SVCR, ZA, 1); + + for (i = 0; i < vl; ++i) { + uint64_t *z = (void *)za + TARGET_ZA_SIG_ZAV_OFFSET(vq, i); + for (j = 0; j < vq * 2; ++j) { + __get_user_e(env->zarray[i].d[j], z + j, le); + } + } + return true; } static int target_restore_sigframe(CPUARMState *env, @@ -278,10 +408,12 @@ static int target_restore_sigframe(CPUARMState *env, struct target_aarch64_ctx *ctx, *extra = NULL; struct target_fpsimd_context *fpsimd = NULL; struct target_sve_context *sve = NULL; + struct target_za_context *za = NULL; uint64_t extra_datap = 0; bool used_extra = false; - bool err = false; - int vq = 0, sve_size = 0; + int sve_size = 0; + int za_size = 0; + int svcr = 0; target_restore_general_frame(env, sf); @@ -294,8 +426,7 @@ static int target_restore_sigframe(CPUARMState *env, switch (magic) { case 0: if (size != 0) { - err = true; - goto exit; + goto err; } if (used_extra) { ctx = NULL; @@ -307,42 +438,46 @@ static int target_restore_sigframe(CPUARMState *env, case TARGET_FPSIMD_MAGIC: if (fpsimd || size != sizeof(struct target_fpsimd_context)) { - err = true; - goto exit; + goto err; } fpsimd = (struct target_fpsimd_context *)ctx; break; case TARGET_SVE_MAGIC: - if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { - vq = (env->vfp.zcr_el[1] & 0xf) + 1; - sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16); - if (!sve && size == sve_size) { - sve = (struct target_sve_context *)ctx; - break; - } + if (sve || size < sizeof(struct target_sve_context)) { + goto err; } - err = true; - goto exit; + sve = (struct target_sve_context *)ctx; + sve_size = size; + break; + + case TARGET_ZA_MAGIC: + if (za || size < sizeof(struct target_za_context)) { + goto err; + } + za = (struct target_za_context *)ctx; + za_size = size; + break; case TARGET_EXTRA_MAGIC: if (extra || size != sizeof(struct target_extra_context)) { - err = true; - goto exit; + goto err; } __get_user(extra_datap, &((struct target_extra_context *)ctx)->datap); __get_user(extra_size, &((struct target_extra_context *)ctx)->size); extra = lock_user(VERIFY_READ, extra_datap, extra_size, 0); + if (!extra) { + return 1; + } break; default: /* Unknown record -- we certainly didn't generate it. * Did we in fact get out of sync? */ - err = true; - goto exit; + goto err; } ctx = (void *)ctx + size; } @@ -351,17 +486,26 @@ static int target_restore_sigframe(CPUARMState *env, if (fpsimd) { target_restore_fpsimd_record(env, fpsimd); } else { - err = true; + goto err; } /* SVE data, if present, overwrites FPSIMD data. */ - if (sve) { - target_restore_sve_record(env, sve, vq); + if (sve && !target_restore_sve_record(env, sve, sve_size, &svcr)) { + goto err; + } + if (za && !target_restore_za_record(env, za, za_size, &svcr)) { + goto err; + } + if (env->svcr != svcr) { + env->svcr = svcr; + arm_rebuild_hflags(env); } + unlock_user(extra, extra_datap, 0); + return 0; - exit: + err: unlock_user(extra, extra_datap, 0); - return err; + return 1; } static abi_ulong get_sigframe(struct target_sigaction *ka, @@ -423,7 +567,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, .total_size = offsetof(struct target_rt_sigframe, uc.tuc_mcontext.__reserved), }; - int fpsimd_ofs, fr_ofs, sve_ofs = 0, vq = 0, sve_size = 0; + int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0; + int sve_size = 0, za_size = 0; struct target_rt_sigframe *frame; struct target_rt_frame_record *fr; abi_ulong frame_addr, return_addr; @@ -433,11 +578,20 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, &layout); /* SVE state needs saving only if it exists. */ - if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { - vq = (env->vfp.zcr_el[1] & 0xf) + 1; - sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16); + if (cpu_isar_feature(aa64_sve, env_archcpu(env)) || + cpu_isar_feature(aa64_sme, env_archcpu(env))) { + sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(sve_vq(env)), 16); sve_ofs = alloc_sigframe_space(sve_size, &layout); } + if (cpu_isar_feature(aa64_sme, env_archcpu(env))) { + /* ZA state needs saving only if it is enabled. */ + if (FIELD_EX64(env->svcr, SVCR, ZA)) { + za_size = TARGET_ZA_SIG_CONTEXT_SIZE(sme_vq(env)); + } else { + za_size = TARGET_ZA_SIG_CONTEXT_SIZE(0); + } + za_ofs = alloc_sigframe_space(za_size, &layout); + } if (layout.extra_ofs) { /* Reserve space for the extra end marker. The standard end marker @@ -484,7 +638,10 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, target_setup_end_record((void *)frame + layout.extra_end_ofs); } if (sve_ofs) { - target_setup_sve_record((void *)frame + sve_ofs, env, vq, sve_size); + target_setup_sve_record((void *)frame + sve_ofs, env, sve_size); + } + if (za_ofs) { + target_setup_za_record((void *)frame + za_ofs, env, za_size); } /* Set up the stack frame for unwinding. */ @@ -508,6 +665,18 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, env->btype = 2; } + /* + * Invoke the signal handler with both SM and ZA disabled. + * When clearing SM, ResetSVEState, per SMSTOP. + */ + if (FIELD_EX64(env->svcr, SVCR, SM)) { + arm_reset_sve_state(env); + } + if (env->svcr) { + env->svcr = 0; + arm_rebuild_hflags(env); + } + if (info) { tswap_siginfo(&frame->info, info); env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info); diff --git a/linux-user/aarch64/target_cpu.h b/linux-user/aarch64/target_cpu.h index 97a477bd3e91..f90359faf20f 100644 --- a/linux-user/aarch64/target_cpu.h +++ b/linux-user/aarch64/target_cpu.h @@ -34,10 +34,13 @@ static inline void cpu_clone_regs_parent(CPUARMState *env, unsigned flags) static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) { - /* Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is + /* + * Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is * different from AArch32 Linux, which uses TPIDRRO. */ env->cp15.tpidr_el[0] = newtls; + /* TPIDR2_EL0 is cleared with CLONE_SETTLS. */ + env->cp15.tpidr2_el0 = 0; } static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) diff --git a/linux-user/aarch64/target_mman.h b/linux-user/aarch64/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/aarch64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/aarch64/target_prctl.h b/linux-user/aarch64/target_prctl.h index 3f5a5d3933a0..907c31414662 100644 --- a/linux-user/aarch64/target_prctl.h +++ b/linux-user/aarch64/target_prctl.h @@ -6,17 +6,18 @@ #ifndef AARCH64_TARGET_PRCTL_H #define AARCH64_TARGET_PRCTL_H -static abi_long do_prctl_get_vl(CPUArchState *env) +static abi_long do_prctl_sve_get_vl(CPUArchState *env) { ARMCPU *cpu = env_archcpu(env); if (cpu_isar_feature(aa64_sve, cpu)) { - return ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16; + /* PSTATE.SM is always unset on syscall entry. */ + return sve_vq(env) * 16; } return -TARGET_EINVAL; } -#define do_prctl_get_vl do_prctl_get_vl +#define do_prctl_sve_get_vl do_prctl_sve_get_vl -static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2) +static abi_long do_prctl_sve_set_vl(CPUArchState *env, abi_long arg2) { /* * We cannot support either PR_SVE_SET_VL_ONEXEC or PR_SVE_VL_INHERIT. @@ -25,23 +26,82 @@ static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2) */ if (cpu_isar_feature(aa64_sve, env_archcpu(env)) && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) { - ARMCPU *cpu = env_archcpu(env); uint32_t vq, old_vq; - old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; + /* PSTATE.SM is always unset on syscall entry. */ + old_vq = sve_vq(env); + + /* + * Bound the value of arg2, so that we know that it fits into + * the 4-bit field in ZCR_EL1. Rely on the hflags rebuild to + * sort out the length supported by the cpu. + */ vq = MAX(arg2 / 16, 1); - vq = MIN(vq, cpu->sve_max_vq); + vq = MIN(vq, ARM_MAX_VQ); + env->vfp.zcr_el[1] = vq - 1; + arm_rebuild_hflags(env); + vq = sve_vq(env); if (vq < old_vq) { aarch64_sve_narrow_vq(env, vq); } - env->vfp.zcr_el[1] = vq - 1; - arm_rebuild_hflags(env); return vq * 16; } return -TARGET_EINVAL; } -#define do_prctl_set_vl do_prctl_set_vl +#define do_prctl_sve_set_vl do_prctl_sve_set_vl + +static abi_long do_prctl_sme_get_vl(CPUArchState *env) +{ + ARMCPU *cpu = env_archcpu(env); + if (cpu_isar_feature(aa64_sme, cpu)) { + return sme_vq(env) * 16; + } + return -TARGET_EINVAL; +} +#define do_prctl_sme_get_vl do_prctl_sme_get_vl + +static abi_long do_prctl_sme_set_vl(CPUArchState *env, abi_long arg2) +{ + /* + * We cannot support either PR_SME_SET_VL_ONEXEC or PR_SME_VL_INHERIT. + * Note the kernel definition of sve_vl_valid allows for VQ=512, + * i.e. VL=8192, even though the architectural maximum is VQ=16. + */ + if (cpu_isar_feature(aa64_sme, env_archcpu(env)) + && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) { + int vq, old_vq; + + old_vq = sme_vq(env); + + /* + * Bound the value of vq, so that we know that it fits into + * the 4-bit field in SMCR_EL1. Because PSTATE.SM is cleared + * on syscall entry, we are not modifying the current SVE + * vector length. + */ + vq = MAX(arg2 / 16, 1); + vq = MIN(vq, 16); + env->vfp.smcr_el[1] = + FIELD_DP64(env->vfp.smcr_el[1], SMCR, LEN, vq - 1); + + /* Delay rebuilding hflags until we know if ZA must change. */ + vq = sve_vqm1_for_el_sm(env, 0, true) + 1; + + if (vq != old_vq) { + /* + * PSTATE.ZA state is cleared on any change to SVL. + * We need not call arm_rebuild_hflags because PSTATE.SM was + * cleared on syscall entry, so this hasn't changed VL. + */ + env->svcr = FIELD_DP64(env->svcr, SVCR, ZA, 0); + arm_rebuild_hflags(env); + } + return vq * 16; + } + return -TARGET_EINVAL; +} +#define do_prctl_sme_set_vl do_prctl_sme_set_vl static abi_long do_prctl_reset_keys(CPUArchState *env, abi_long arg2) { diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h index a98f568ab4d7..c055133725ec 100644 --- a/linux-user/aarch64/target_syscall.h +++ b/linux-user/aarch64/target_syscall.h @@ -8,7 +8,7 @@ struct target_pt_regs { uint64_t pstate; }; -#if defined(TARGET_WORDS_BIGENDIAN) +#if TARGET_BIG_ENDIAN #define UNAME_MACHINE "aarch64_be" #else #define UNAME_MACHINE "aarch64" diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c index de6e0c901cdf..2ea039aa71f7 100644 --- a/linux-user/alpha/cpu_loop.c +++ b/linux-user/alpha/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/alpha/target_mman.h b/linux-user/alpha/target_mman.h new file mode 100644 index 000000000000..cd6e3d70a604 --- /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/cpu_loop.c b/linux-user/arm/cpu_loop.c index aae375d61792..c0790f3246b9 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "elf.h" @@ -231,7 +230,7 @@ do_kernel_trap(CPUARMState *env) /* Jump back to the caller. */ addr = env->regs[14]; if (addr & 1) { - env->thumb = 1; + env->thumb = true; addr &= ~1; } env->regs[15] = addr; @@ -450,7 +449,7 @@ void cpu_loop(CPUARMState *env) } break; case EXCP_SEMIHOST: - env->regs[0] = do_common_semihosting(cs); + do_common_semihosting(cs); env->regs[15] += env->thumb ? 2 : 4; break; case EXCP_INTERRUPT: @@ -519,7 +518,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; } -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN /* Enable BE8. */ if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4 && (info->elf_flags & EF_ARM_BE8)) { diff --git a/linux-user/arm/nwfpe/double_cpdo.c b/linux-user/arm/nwfpe/double_cpdo.c index 1cef380852c9..d45ece2e2fe7 100644 --- a/linux-user/arm/nwfpe/double_cpdo.c +++ b/linux-user/arm/nwfpe/double_cpdo.c @@ -150,7 +150,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case MNF_CODE: { unsigned int *p = (unsigned int*)&rFm; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN p[0] ^= 0x80000000; #else p[1] ^= 0x80000000; @@ -162,7 +162,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case ABS_CODE: { unsigned int *p = (unsigned int*)&rFm; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN p[0] &= 0x7fffffff; #else p[1] &= 0x7fffffff; diff --git a/linux-user/arm/nwfpe/fpa11_cpdt.c b/linux-user/arm/nwfpe/fpa11_cpdt.c index c32b0c2faac0..fee525937c55 100644 --- a/linux-user/arm/nwfpe/fpa11_cpdt.c +++ b/linux-user/arm/nwfpe/fpa11_cpdt.c @@ -44,7 +44,7 @@ void loadDouble(const unsigned int Fn, target_ulong addr) unsigned int *p; p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; fpa11->fType[Fn] = typeDouble; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN /* FIXME - handle failure of get_user() */ get_user_u32(p[0], addr); /* sign & exponent */ get_user_u32(p[1], addr + 4); @@ -147,7 +147,7 @@ void storeDouble(const unsigned int Fn, target_ulong addr) default: val = fpa11->fpreg[Fn].fDouble; } /* FIXME - handle put_user() failures */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN put_user_u32(p[0], addr); /* msw */ put_user_u32(p[1], addr + 4); /* lsw */ #else diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h index 709d19bc9e61..89ba274cfc69 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 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/arm/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h index f04f9c9e3d75..412ad434cfc2 100644 --- a/linux-user/arm/target_syscall.h +++ b/linux-user/arm/target_syscall.h @@ -18,7 +18,7 @@ struct target_pt_regs { #define ARM_NR_set_tls (ARM_NR_BASE + 5) #define ARM_NR_get_tls (ARM_NR_BASE + 6) -#if defined(TARGET_WORDS_BIGENDIAN) +#if TARGET_BIG_ENDIAN #define UNAME_MACHINE "armv5teb" #else #define UNAME_MACHINE "armv5tel" diff --git a/linux-user/cpu_loop-common.h b/linux-user/cpu_loop-common.h index dc0042e4de35..e644d2ef9096 100644 --- a/linux-user/cpu_loop-common.h +++ b/linux-user/cpu_loop-common.h @@ -23,16 +23,9 @@ #include "exec/log.h" #include "special-errno.h" -#define EXCP_DUMP(env, fmt, ...) \ -do { \ - CPUState *cs = env_cpu(env); \ - fprintf(stderr, fmt , ## __VA_ARGS__); \ - cpu_dump_state(cs, stderr, 0); \ - if (qemu_log_separate()) { \ - qemu_log(fmt, ## __VA_ARGS__); \ - log_cpu_state(cs, 0); \ - } \ -} while (0) +void target_exception_dump(CPUArchState *env, const char *fmt, int code); +#define EXCP_DUMP(env, fmt, code) \ + target_exception_dump(env, fmt, code) void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs); #endif diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c index 0f46b3c1a87a..01e6ff16fc92 100644 --- a/linux-user/cris/cpu_loop.c +++ b/linux-user/cris/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/cris/target_mman.h b/linux-user/cris/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /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 c45da4d63375..20894b633f58 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -105,7 +105,7 @@ int info_is_fdpic(struct image_info *info) #define ELIBBAD 80 #endif -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN #define ELF_DATA ELFDATA2MSB #else #define ELF_DATA ELFDATA2LSB @@ -130,19 +130,6 @@ typedef abi_int target_pid_t; #ifdef TARGET_I386 -#define ELF_PLATFORM get_elf_platform() - -static const char *get_elf_platform(void) -{ - static char elf_platform[] = "i386"; - int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL); - if (family > 6) - family = 6; - if (family >= 3) - elf_platform[1] = '0' + family; - return elf_platform; -} - #define ELF_HWCAP get_elf_hwcap() static uint32_t get_elf_hwcap(void) @@ -158,6 +145,8 @@ static uint32_t get_elf_hwcap(void) #define ELF_CLASS ELFCLASS64 #define ELF_ARCH EM_X86_64 +#define ELF_PLATFORM "x86_64" + static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->rax = 0; @@ -206,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 @@ -221,6 +231,22 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #define ELF_CLASS ELFCLASS32 #define ELF_ARCH EM_386 +#define ELF_PLATFORM get_elf_platform() +#define EXSTACK_DEFAULT true + +static const char *get_elf_platform(void) +{ + static char elf_platform[] = "i386"; + int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL); + if (family > 6) { + family = 6; + } + if (family >= 3) { + elf_platform[1] = '0' + family; + } + return elf_platform; +} + static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { @@ -283,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) @@ -394,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); @@ -413,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; } @@ -483,7 +514,7 @@ static const char *get_elf_platform(void) { CPUARMState *env = thread_cpu->env_ptr; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN # define END "b" #else # define END "l" @@ -514,7 +545,7 @@ static const char *get_elf_platform(void) #define ELF_ARCH EM_AARCH64 #define ELF_CLASS ELFCLASS64 -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN # define ELF_PLATFORM "aarch64_be" #else # define ELF_PLATFORM "aarch64" @@ -601,6 +632,18 @@ enum { ARM_HWCAP2_A64_RNG = 1 << 16, ARM_HWCAP2_A64_BTI = 1 << 17, ARM_HWCAP2_A64_MTE = 1 << 18, + ARM_HWCAP2_A64_ECV = 1 << 19, + ARM_HWCAP2_A64_AFP = 1 << 20, + ARM_HWCAP2_A64_RPRES = 1 << 21, + ARM_HWCAP2_A64_MTE3 = 1 << 22, + ARM_HWCAP2_A64_SME = 1 << 23, + ARM_HWCAP2_A64_SME_I16I64 = 1 << 24, + ARM_HWCAP2_A64_SME_F64F64 = 1 << 25, + ARM_HWCAP2_A64_SME_I8I32 = 1 << 26, + ARM_HWCAP2_A64_SME_F16F32 = 1 << 27, + ARM_HWCAP2_A64_SME_B16F32 = 1 << 28, + ARM_HWCAP2_A64_SME_F32F32 = 1 << 29, + ARM_HWCAP2_A64_SME_FA64 = 1 << 30, }; #define ELF_HWCAP get_elf_hwcap() @@ -670,6 +713,14 @@ static uint32_t get_elf_hwcap2(void) GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG); GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI); GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE); + GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME | + ARM_HWCAP2_A64_SME_F32F32 | + ARM_HWCAP2_A64_SME_B16F32 | + ARM_HWCAP2_A64_SME_F16F32 | + ARM_HWCAP2_A64_SME_I8I32)); + GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64); + GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64); + GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64); return hwcaps; } @@ -727,6 +778,7 @@ static inline void init_thread(struct target_pt_regs *regs, #else #define ELF_CLASS ELFCLASS32 +#define EXSTACK_DEFAULT true #endif @@ -779,6 +831,8 @@ enum { QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */ QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */ QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */ + QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */ + QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */ }; #define ELF_HWCAP get_elf_hwcap() @@ -836,6 +890,8 @@ static uint32_t get_elf_hwcap2(void) QEMU_PPC_FEATURE2_VEC_CRYPTO); GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 | QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128); + GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 | + QEMU_PPC_FEATURE2_MMA); #undef GET_FEATURE #undef GET_FEATURE2 @@ -914,6 +970,98 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #endif +#ifdef TARGET_LOONGARCH64 + +#define ELF_START_MMAP 0x80000000 + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_LOONGARCH +#define EXSTACK_DEFAULT true + +#define elf_check_arch(x) ((x) == EM_LOONGARCH) + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + /*Set crmd PG,DA = 1,0 */ + regs->csr.crmd = 2 << 3; + regs->csr.era = infop->entry; + regs->regs[3] = infop->start_stack; +} + +/* See linux kernel: arch/loongarch/include/asm/elf.h */ +#define ELF_NREG 45 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +enum { + TARGET_EF_R0 = 0, + TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33, + TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34, +}; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPULoongArchState *env) +{ + int i; + + (*regs)[TARGET_EF_R0] = 0; + + for (i = 1; i < ARRAY_SIZE(env->gpr); i++) { + (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]); + } + + (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc); + (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_HWCAP get_elf_hwcap() + +/* See arch/loongarch/include/uapi/asm/hwcap.h */ +enum { + HWCAP_LOONGARCH_CPUCFG = (1 << 0), + HWCAP_LOONGARCH_LAM = (1 << 1), + HWCAP_LOONGARCH_UAL = (1 << 2), + HWCAP_LOONGARCH_FPU = (1 << 3), + HWCAP_LOONGARCH_LSX = (1 << 4), + HWCAP_LOONGARCH_LASX = (1 << 5), + HWCAP_LOONGARCH_CRC32 = (1 << 6), + HWCAP_LOONGARCH_COMPLEX = (1 << 7), + HWCAP_LOONGARCH_CRYPTO = (1 << 8), + HWCAP_LOONGARCH_LVZ = (1 << 9), + HWCAP_LOONGARCH_LBT_X86 = (1 << 10), + HWCAP_LOONGARCH_LBT_ARM = (1 << 11), + HWCAP_LOONGARCH_LBT_MIPS = (1 << 12), +}; + +static uint32_t get_elf_hwcap(void) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= HWCAP_LOONGARCH_CRC32; + + if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) { + hwcaps |= HWCAP_LOONGARCH_UAL; + } + + if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) { + hwcaps |= HWCAP_LOONGARCH_FPU; + } + + if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) { + hwcaps |= HWCAP_LOONGARCH_LAM; + } + + return hwcaps; +} + +#define ELF_PLATFORM "loongarch" + +#endif /* TARGET_LOONGARCH64 */ + #ifdef TARGET_MIPS #define ELF_START_MMAP 0x80000000 @@ -924,6 +1072,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #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) @@ -931,6 +1080,37 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #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) { @@ -1096,7 +1276,6 @@ static void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->ea = infop->entry; regs->sp = infop->start_stack; - regs->estatus = 0x3; } #define LO_COMMPAGE TARGET_PAGE_SIZE @@ -1170,7 +1349,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, (*regs)[30] = -1; /* R_SSTATUS */ (*regs)[31] = tswapreg(env->regs[R_RA]); - (*regs)[32] = tswapreg(env->regs[R_PC]); + (*regs)[32] = tswapreg(env->pc); (*regs)[33] = -1; /* R_STATUS */ (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]); @@ -1517,13 +1696,41 @@ static inline void init_thread(struct target_pt_regs *regs, regs->iaoq[0] = infop->entry; regs->iaoq[1] = infop->entry + 4; regs->gr[23] = 0; - regs->gr[24] = infop->arg_start; - regs->gr[25] = (infop->arg_end - infop->arg_start) / sizeof(abi_ulong); + regs->gr[24] = infop->argv; + regs->gr[25] = infop->argc; /* The top-of-stack contains a linkage buffer. */ regs->gr[30] = infop->start_stack + 64; 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 @@ -1600,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 @@ -1635,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". */ @@ -1910,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"); @@ -1933,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; } @@ -2030,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; @@ -2053,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) { @@ -2094,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 @@ -2121,8 +2364,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, u_envp = u_argv + (argc + 1) * n; u_auxv = u_envp + (envc + 1) * n; info->saved_auxv = u_auxv; - info->arg_start = u_argv; - info->arg_end = u_argv + argc * n; + info->argc = argc; + info->envc = envc; + info->argv = u_argv; + info->envp = u_envp; /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off @@ -2169,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); } @@ -2202,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) { @@ -2431,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); } @@ -2746,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) { @@ -2788,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; } } @@ -3972,7 +4225,7 @@ static int fill_note_info(struct elf_note_info *info, if (cpu == thread_cpu) { continue; } - fill_thread_info(info, (CPUArchState *)cpu->env_ptr); + fill_thread_info(info, cpu->env_ptr); } cpu_list_unlock(); diff --git a/linux-user/flatload.c b/linux-user/flatload.c index e4c2f89a2267..e99570ca182b 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 000000000000..1436a3c54308 --- /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/cpu_loop.c b/linux-user/hexagon/cpu_loop.c index 0d73934d31d5..b84e25bf71eb 100644 --- a/linux-user/hexagon/cpu_loop.c +++ b/linux-user/hexagon/cpu_loop.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c index ad4e3822d52c..60fa7e1bcee6 100644 --- a/linux-user/hexagon/signal.c +++ b/linux-user/hexagon/signal.c @@ -39,15 +39,12 @@ struct target_sigcontext { target_ulong m0; target_ulong m1; target_ulong usr; - target_ulong p3_0; target_ulong gp; target_ulong ugp; target_ulong pc; target_ulong cause; target_ulong badva; - target_ulong pad1; - target_ulong pad2; - target_ulong pad3; + target_ulong pred[NUM_PREGS]; }; struct target_ucontext { @@ -118,10 +115,14 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUHexagonState *env) __put_user(env->gpr[HEX_REG_M0], &sc->m0); __put_user(env->gpr[HEX_REG_M1], &sc->m1); __put_user(env->gpr[HEX_REG_USR], &sc->usr); - __put_user(env->gpr[HEX_REG_P3_0], &sc->p3_0); __put_user(env->gpr[HEX_REG_GP], &sc->gp); __put_user(env->gpr[HEX_REG_UGP], &sc->ugp); __put_user(env->gpr[HEX_REG_PC], &sc->pc); + + int i; + for (i = 0; i < NUM_PREGS; i++) { + __put_user(env->pred[i], &(sc->pred[i])); + } } static void setup_ucontext(struct target_ucontext *uc, @@ -230,10 +231,14 @@ static void restore_sigcontext(CPUHexagonState *env, __get_user(env->gpr[HEX_REG_M0], &sc->m0); __get_user(env->gpr[HEX_REG_M1], &sc->m1); __get_user(env->gpr[HEX_REG_USR], &sc->usr); - __get_user(env->gpr[HEX_REG_P3_0], &sc->p3_0); __get_user(env->gpr[HEX_REG_GP], &sc->gp); __get_user(env->gpr[HEX_REG_UGP], &sc->ugp); __get_user(env->gpr[HEX_REG_PC], &sc->pc); + + int i; + for (i = 0; i < NUM_PREGS; i++) { + __get_user(env->pred[i], &(sc->pred[i])); + } } static void restore_ucontext(CPUHexagonState *env, struct target_ucontext *uc) diff --git a/linux-user/hexagon/target_mman.h b/linux-user/hexagon/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/hexagon/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/hexagon/target_signal.h b/linux-user/hexagon/target_signal.h index 193abac340c5..68fb71312ee2 100644 --- a/linux-user/hexagon/target_signal.h +++ b/linux-user/hexagon/target_signal.h @@ -22,4 +22,4 @@ #define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 -#endif /* TARGET_SIGNAL_H */ +#endif /* HEXAGON_TARGET_SIGNAL_H */ diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index a576d1a249fd..8ab133510602 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -143,13 +143,24 @@ void cpu_loop(CPUHPPAState *env) env->iaoq_f = env->gr[31]; env->iaoq_b = env->gr[31] + 4; break; + case EXCP_IMP: + force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f); + break; case EXCP_ILL: - force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->iaoq_f); + EXCP_DUMP(env, "qemu: EXCP_ILL exception %#x\n", trapnr); + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f); break; case EXCP_PRIV_OPR: - force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f); + /* check for glibc ABORT_INSTRUCTION "iitlbp %r0,(%sr0, %r0)" */ + EXCP_DUMP(env, "qemu: EXCP_PRIV_OPR exception %#x\n", trapnr); + if (env->cr[CR_IIR] == 0x04000000) { + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f); + } else { + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f); + } break; case EXCP_PRIV_REG: + EXCP_DUMP(env, "qemu: EXCP_PRIV_REG exception %#x\n", trapnr); force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f); break; case EXCP_OVERFLOW: @@ -161,6 +172,10 @@ void cpu_loop(CPUHPPAState *env) case EXCP_ASSIST: force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f); break; + case EXCP_BREAK: + EXCP_DUMP(env, "qemu: EXCP_BREAK exception %#x\n", trapnr); + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f & ~3); + break; case EXCP_DEBUG: force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f); break; @@ -168,7 +183,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 962f551c0429..f253a1586461 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 000000000000..66dd9f79414e --- /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 af6c2fce589d..190bb3d653b6 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 4b382c1fcf4a..9a8f8ca62817 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 90bffc1956aa..865413c08f07 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "qemu/timer.h" #include "user-internals.h" @@ -138,7 +137,7 @@ static void emulate_vsyscall(CPUX86State *env) } /* - * Validate the the pointer arguments. + * Validate the pointer arguments. */ switch (syscall) { case TARGET_NR_gettimeofday: @@ -202,7 +201,6 @@ void cpu_loop(CPUX86State *env) { CPUState *cs = env_cpu(env); int trapnr; - abi_ulong pc; abi_ulong ret; for(;;) { @@ -308,9 +306,8 @@ void cpu_loop(CPUX86State *env) cpu_exec_step_atomic(cs); break; default: - pc = env->segs[R_CS].base + env->eip; - EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", - (long)pc, trapnr); + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); abort(); } process_pending_signals(env); diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 4372621a4d20..60fa07d6f9cf 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -24,6 +24,10 @@ /* from the Linux kernel - /arch/x86/include/uapi/asm/sigcontext.h */ +#define TARGET_FP_XSTATE_MAGIC1 0x46505853U /* FPXS */ +#define TARGET_FP_XSTATE_MAGIC2 0x46505845U /* FPXE */ +#define TARGET_FP_XSTATE_MAGIC2_SIZE 4 + struct target_fpreg { uint16_t significand[4]; uint16_t exponent; @@ -39,29 +43,16 @@ struct target_xmmreg { uint32_t element[4]; }; -struct target_fpstate_32 { - /* Regular FPU environment */ - uint32_t cw; - uint32_t sw; - uint32_t tag; - uint32_t ipoff; - uint32_t cssel; - uint32_t dataoff; - uint32_t datasel; - struct target_fpreg st[8]; - uint16_t status; - uint16_t magic; /* 0xffff = regular FPU data only */ - - /* FXSR FPU environment */ - uint32_t _fxsr_env[6]; /* FXSR FPU env is ignored */ - uint32_t mxcsr; - uint32_t reserved; - struct target_fpxreg fxsr_st[8]; /* FXSR FPU reg data is ignored */ - struct target_xmmreg xmm[8]; - uint32_t padding[56]; +struct target_fpx_sw_bytes { + uint32_t magic1; + uint32_t extended_size; + uint64_t xfeatures; + uint32_t xstate_size; + uint32_t reserved[7]; }; +QEMU_BUILD_BUG_ON(sizeof(struct target_fpx_sw_bytes) != 12*4); -struct target_fpstate_64 { +struct target_fpstate_fxsave { /* FXSAVE format */ uint16_t cw; uint16_t sw; @@ -73,13 +64,41 @@ struct target_fpstate_64 { uint32_t mxcsr_mask; uint32_t st_space[32]; uint32_t xmm_space[64]; - uint32_t reserved[24]; + uint32_t hw_reserved[12]; + struct target_fpx_sw_bytes sw_reserved; + uint8_t xfeatures[]; }; +#define TARGET_FXSAVE_SIZE sizeof(struct target_fpstate_fxsave) +QEMU_BUILD_BUG_ON(TARGET_FXSAVE_SIZE != 512); +QEMU_BUILD_BUG_ON(offsetof(struct target_fpstate_fxsave, sw_reserved) != 464); + +struct target_fpstate_32 { + /* Regular FPU environment */ + uint32_t cw; + uint32_t sw; + uint32_t tag; + uint32_t ipoff; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + struct target_fpreg st[8]; + uint16_t status; + uint16_t magic; /* 0xffff = regular FPU data only */ + struct target_fpstate_fxsave fxsave; +}; + +/* + * For simplicity, setup_frame aligns struct target_fpstate_32 to + * 16 bytes, so ensure that the FXSAVE area is also aligned. + */ +QEMU_BUILD_BUG_ON(offsetof(struct target_fpstate_32, fxsave) & 15); #ifndef TARGET_X86_64 # define target_fpstate target_fpstate_32 +# define TARGET_FPSTATE_FXSAVE_OFFSET offsetof(struct target_fpstate_32, fxsave) #else -# define target_fpstate target_fpstate_64 +# define target_fpstate target_fpstate_fxsave +# define TARGET_FPSTATE_FXSAVE_OFFSET 0 #endif struct target_sigcontext_32 { @@ -163,10 +182,25 @@ struct sigframe { abi_ulong pretcode; int sig; struct target_sigcontext sc; - struct target_fpstate fpstate; + /* + * The actual fpstate is placed after retcode[] below, to make + * room for the variable-sized xsave data. The older unused fpstate + * has to be kept to avoid changing the offset of extramask[], which + * is part of the ABI. + */ + struct target_fpstate fpstate_unused; abi_ulong extramask[TARGET_NSIG_WORDS-1]; char retcode[8]; + + /* + * This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED + * to it ensures that the base of the frame has an appropriate alignment + * too. + */ + struct target_fpstate fpstate QEMU_ALIGNED(8); }; +#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \ + offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET) struct rt_sigframe { abi_ulong pretcode; @@ -175,26 +209,62 @@ struct rt_sigframe { abi_ulong puc; struct target_siginfo info; struct target_ucontext uc; - struct target_fpstate fpstate; char retcode[8]; + struct target_fpstate fpstate QEMU_ALIGNED(8); }; - +#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \ + offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET) #else struct rt_sigframe { abi_ulong pretcode; struct target_ucontext uc; struct target_siginfo info; - struct target_fpstate fpstate; + struct target_fpstate fpstate QEMU_ALIGNED(16); }; - +#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \ + offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET) #endif /* * Set up a signal frame. */ -/* XXX: save x87 state */ +static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave, + abi_ulong fxsave_addr) +{ + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { + /* fxsave_addr must be 16 byte aligned for fxsave */ + assert(!(fxsave_addr & 0xf)); + + cpu_x86_fxsave(env, fxsave_addr); + __put_user(0, &fxsave->sw_reserved.magic1); + } else { + uint32_t xstate_size = xsave_area_size(env->xcr0, false); + uint32_t xfeatures_size = xstate_size - TARGET_FXSAVE_SIZE; + + /* + * extended_size is the offset from fpstate_addr to right after the end + * of the extended save states. On 32-bit that includes the legacy + * FSAVE area. + */ + uint32_t extended_size = TARGET_FPSTATE_FXSAVE_OFFSET + + xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE; + + /* fxsave_addr must be 64 byte aligned for xsave */ + assert(!(fxsave_addr & 0x3f)); + + /* Zero the header, XSAVE *adds* features to an existing save state. */ + memset(fxsave->xfeatures, 0, 64); + cpu_x86_xsave(env, fxsave_addr); + __put_user(TARGET_FP_XSTATE_MAGIC1, &fxsave->sw_reserved.magic1); + __put_user(extended_size, &fxsave->sw_reserved.extended_size); + __put_user(env->xcr0, &fxsave->sw_reserved.xfeatures); + __put_user(xstate_size, &fxsave->sw_reserved.xstate_size); + __put_user(TARGET_FP_XSTATE_MAGIC2, (uint32_t *) &fxsave->xfeatures[xfeatures_size]); + } +} + static void setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr) @@ -226,13 +296,14 @@ static void setup_sigcontext(struct target_sigcontext *sc, cpu_x86_fsave(env, fpstate_addr, 1); fpstate->status = fpstate->sw; - magic = 0xffff; + if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) { + magic = 0xffff; + } else { + xsave_sigcontext(env, &fpstate->fxsave, + fpstate_addr + TARGET_FPSTATE_FXSAVE_OFFSET); + magic = 0; + } __put_user(magic, &fpstate->magic); - __put_user(fpstate_addr, &sc->fpstate); - - /* non-iBCS2 extensions.. */ - __put_user(mask, &sc->oldmask); - __put_user(env->cr[2], &sc->cr2); #else __put_user(env->regs[R_EDI], &sc->rdi); __put_user(env->regs[R_ESI], &sc->rsi); @@ -262,15 +333,14 @@ static void setup_sigcontext(struct target_sigcontext *sc, __put_user((uint16_t)0, &sc->fs); __put_user(env->segs[R_SS].selector, &sc->ss); - __put_user(mask, &sc->oldmask); - __put_user(env->cr[2], &sc->cr2); - - /* fpstate_addr must be 16 byte aligned for fxsave */ - assert(!(fpstate_addr & 0xf)); + xsave_sigcontext(env, fpstate, fpstate_addr); +#endif - cpu_x86_fxsave(env, fpstate_addr); __put_user(fpstate_addr, &sc->fpstate); -#endif + + /* non-iBCS2 extensions.. */ + __put_user(mask, &sc->oldmask); + __put_user(env->cr[2], &sc->cr2); } /* @@ -278,7 +348,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, */ static inline abi_ulong -get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size) +get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset) { unsigned long esp; @@ -302,11 +372,15 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size) #endif } -#ifndef TARGET_X86_64 - return (esp - frame_size) & -8ul; -#else - return ((esp - frame_size) & (~15ul)) - 8; -#endif + if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) { + return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul; + } else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { + return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset; + } else { + size_t xstate_size = + xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE; + return ((esp - xstate_size) & -64ul) - fxsave_offset; + } } #ifndef TARGET_X86_64 @@ -334,7 +408,7 @@ void setup_frame(int sig, struct target_sigaction *ka, struct sigframe *frame; int i; - frame_addr = get_sigframe(ka, env, sizeof(*frame)); + frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET); trace_user_setup_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) @@ -390,7 +464,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, struct rt_sigframe *frame; int i; - frame_addr = get_sigframe(ka, env, sizeof(*frame)); + frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET); trace_user_setup_rt_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) @@ -409,7 +483,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, } /* Create the ucontext. */ - __put_user(0, &frame->uc.tuc_flags); + if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) { + __put_user(1, &frame->uc.tuc_flags); + } else { + __put_user(0, &frame->uc.tuc_flags); + } __put_user(0, &frame->uc.tuc_link); target_save_altstack(&frame->uc.tuc_stack, env); setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env, @@ -463,10 +541,37 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, force_sigsegv(sig); } +static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave, + abi_ulong fxsave_addr) +{ + if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) { + uint32_t extended_size = tswapl(fxsave->sw_reserved.extended_size); + uint32_t xstate_size = tswapl(fxsave->sw_reserved.xstate_size); + uint32_t xfeatures_size = xstate_size - TARGET_FXSAVE_SIZE; + + /* Linux checks MAGIC2 using xstate_size, not extended_size. */ + if (tswapl(fxsave->sw_reserved.magic1) == TARGET_FP_XSTATE_MAGIC1 && + extended_size >= TARGET_FPSTATE_FXSAVE_OFFSET + xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE) { + if (!access_ok(env_cpu(env), VERIFY_READ, fxsave_addr, + extended_size - TARGET_FPSTATE_FXSAVE_OFFSET)) { + return 1; + } + if (tswapl(*(uint32_t *) &fxsave->xfeatures[xfeatures_size]) == TARGET_FP_XSTATE_MAGIC2) { + cpu_x86_xrstor(env, fxsave_addr); + return 0; + } + } + /* fall through to fxrstor */ + } + + cpu_x86_fxrstor(env, fxsave_addr); + return 0; +} + static int restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) { - unsigned int err = 0; + int err = 1; abi_ulong fpstate_addr; unsigned int tmpflags; @@ -517,20 +622,28 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) fpstate_addr = tswapl(sc->fpstate); if (fpstate_addr != 0) { - if (!access_ok(env_cpu(env), VERIFY_READ, fpstate_addr, - sizeof(struct target_fpstate))) { - goto badframe; + struct target_fpstate *fpstate; + if (!lock_user_struct(VERIFY_READ, fpstate, fpstate_addr, + sizeof(struct target_fpstate))) { + return err; } #ifndef TARGET_X86_64 - cpu_x86_frstor(env, fpstate_addr, 1); + if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) { + cpu_x86_frstor(env, fpstate_addr, 1); + err = 0; + } else { + err = xrstor_sigcontext(env, &fpstate->fxsave, + fpstate_addr + TARGET_FPSTATE_FXSAVE_OFFSET); + } #else - cpu_x86_fxrstor(env, fpstate_addr); + err = xrstor_sigcontext(env, fpstate, fpstate_addr); #endif + unlock_user_struct(fpstate, fpstate_addr, 0); + } else { + err = 0; } return err; -badframe: - return 1; } /* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */ diff --git a/linux-user/i386/target_elf.h b/linux-user/i386/target_elf.h index 1c6142e7da0d..238a9aba738a 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 000000000000..e7ba6070fe7c --- /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 6f191e64d7b5..e6d3ec26dc75 100644 --- a/linux-user/include/host/s390/host-signal.h +++ b/linux-user/include/host/s390/host-signal.h @@ -50,6 +50,7 @@ static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) case 0x50: /* ST */ case 0x42: /* STC */ case 0x40: /* STH */ + case 0x44: /* EX */ case 0xba: /* CS */ case 0xbb: /* CDS */ return true; @@ -61,6 +62,12 @@ static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) return true; } break; + case 0xc6: /* RIL-b format insns */ + switch (pinsn[0] & 0xf) { + case 0x0: /* EXRL */ + return true; + } + break; case 0xc8: /* SSF format insns */ switch (pinsn[0] & 0xf) { case 0x2: /* CSST */ @@ -80,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/ioctls.h b/linux-user/ioctls.h index f182d40190ed..071f7ca25375 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -96,9 +96,7 @@ IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT)) IOCTL(BLKRRPART, 0, TYPE_NULL) IOCTL(BLKGETSIZE, IOC_R, MK_PTR(TYPE_ULONG)) -#ifdef BLKGETSIZE64 IOCTL(BLKGETSIZE64, IOC_R, MK_PTR(TYPE_ULONGLONG)) -#endif IOCTL(BLKFLSBUF, 0, TYPE_NULL) IOCTL(BLKRASET, 0, TYPE_INT) IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG)) @@ -107,33 +105,15 @@ IOCTL_SPECIAL(BLKPG, IOC_W, do_ioctl_blkpg, MK_PTR(MK_STRUCT(STRUCT_blkpg_ioctl_arg))) -#ifdef BLKDISCARD IOCTL(BLKDISCARD, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) -#endif -#ifdef BLKIOMIN IOCTL(BLKIOMIN, IOC_R, MK_PTR(TYPE_INT)) -#endif -#ifdef BLKIOOPT IOCTL(BLKIOOPT, IOC_R, MK_PTR(TYPE_INT)) -#endif -#ifdef BLKALIGNOFF IOCTL(BLKALIGNOFF, IOC_R, MK_PTR(TYPE_INT)) -#endif -#ifdef BLKPBSZGET IOCTL(BLKPBSZGET, IOC_R, MK_PTR(TYPE_INT)) -#endif -#ifdef BLKDISCARDZEROES IOCTL(BLKDISCARDZEROES, IOC_R, MK_PTR(TYPE_INT)) -#endif -#ifdef BLKSECDISCARD IOCTL(BLKSECDISCARD, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) -#endif -#ifdef BLKROTATIONAL IOCTL(BLKROTATIONAL, IOC_R, MK_PTR(TYPE_SHORT)) -#endif -#ifdef BLKZEROOUT IOCTL(BLKZEROOUT, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) -#endif IOCTL(FDMSGON, 0, TYPE_NULL) IOCTL(FDMSGOFF, 0, TYPE_NULL) @@ -149,17 +129,13 @@ IOCTL(FDTWADDLE, 0, TYPE_NULL) IOCTL(FDEJECT, 0, TYPE_NULL) -#ifdef FIBMAP IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) -#endif #ifdef FICLONE IOCTL(FICLONE, IOC_W, TYPE_INT) IOCTL(FICLONERANGE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_file_clone_range))) #endif -#ifdef FIGETBSZ IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) -#endif #ifdef CONFIG_FIEMAP IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap, MK_PTR(MK_STRUCT(STRUCT_fiemap))) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 2ed5fc45ed8c..745cce70abfa 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -92,6 +92,11 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, envp = sp; sp -= (argc + 1) * n; argv = sp; + ts->info->envp = envp; + ts->info->envc = envc; + ts->info->argv = argv; + ts->info->argc = argc; + if (push_ptr) { /* FIXME - handle put_user() failures */ sp -= n; @@ -99,19 +104,22 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, sp -= n; put_user_ual(argv, sp); } + sp -= n; /* FIXME - handle put_user() failures */ put_user_ual(argc, sp); - ts->info->arg_start = stringp; + + ts->info->arg_strings = stringp; while (argc-- > 0) { /* FIXME - handle put_user() failures */ put_user_ual(stringp, argv); argv += n; stringp += target_strlen(stringp) + 1; } - ts->info->arg_end = stringp; /* FIXME - handle put_user() failures */ put_user_ual(0, argv); + + ts->info->env_strings = stringp; while (envc-- > 0) { /* FIXME - handle put_user() failures */ put_user_ual(stringp, envp); diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c new file mode 100644 index 000000000000..894fdd111a8b --- /dev/null +++ b/linux-user/loongarch64/cpu_loop.c @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch user cpu_loop. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "user-internals.h" +#include "cpu_loop-common.h" +#include "signal-common.h" + +void cpu_loop(CPULoongArchState *env) +{ + CPUState *cs = env_cpu(env); + int trapnr, si_code; + abi_long ret; + + for (;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + switch (trapnr) { + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCCODE_SYS: + env->pc += 4; + ret = do_syscall(env, env->gpr[11], + env->gpr[4], env->gpr[5], + env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], + -1, -1); + if (ret == -QEMU_ERESTARTSYS) { + env->pc -= 4; + break; + } + if (ret == -QEMU_ESIGRETURN) { + /* + * Returning from a successful sigreturn syscall. + * Avoid clobbering register state. + */ + break; + } + env->gpr[4] = ret; + break; + case EXCCODE_INE: + force_sig_fault(TARGET_SIGILL, 0, env->pc); + break; + case EXCCODE_FPE: + si_code = TARGET_FPE_FLTUNK; + if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { + si_code = TARGET_FPE_FLTINV; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) { + si_code = TARGET_FPE_FLTDIV; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) { + si_code = TARGET_FPE_FLTOVF; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) { + si_code = TARGET_FPE_FLTUND; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) { + si_code = TARGET_FPE_FLTRES; + } + force_sig_fault(TARGET_SIGFPE, si_code, env->pc); + break; + case EXCP_DEBUG: + case EXCCODE_BRK: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + break; + case EXCCODE_BCE: + force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc); + break; + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + default: + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + exit(EXIT_FAILURE); + } + process_pending_signals(env); + } +} + +void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) +{ + int i; + + for (i = 0; i < 32; i++) { + env->gpr[i] = regs->regs[i]; + } + env->pc = regs->csr.era; + +} diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c new file mode 100644 index 000000000000..7c7afb652e8c --- /dev/null +++ b/linux-user/loongarch64/signal.c @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation of Linux signals + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "user-internals.h" +#include "signal-common.h" +#include "linux-user/trace.h" + +#include "target/loongarch/internals.h" + +/* FP context was used */ +#define SC_USED_FP (1 << 0) + +struct target_sigcontext { + uint64_t sc_pc; + uint64_t sc_regs[32]; + uint32_t sc_flags; + uint64_t sc_extcontext[0] QEMU_ALIGNED(16); +}; + + +#define FPU_CTX_MAGIC 0x46505501 +#define FPU_CTX_ALIGN 8 +struct target_fpu_context { + uint64_t regs[32]; + uint64_t fcc; + uint32_t fcsr; +} QEMU_ALIGNED(FPU_CTX_ALIGN); + +#define CONTEXT_INFO_ALIGN 16 +struct target_sctx_info { + uint32_t magic; + uint32_t size; + uint64_t padding; +} QEMU_ALIGNED(CONTEXT_INFO_ALIGN); + +struct target_ucontext { + abi_ulong tuc_flags; + abi_ptr tuc_link; + target_stack_t tuc_stack; + target_sigset_t tuc_sigmask; + uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)]; + struct target_sigcontext tuc_mcontext; +}; + +struct target_rt_sigframe { + struct target_siginfo rs_info; + struct target_ucontext rs_uc; +}; + +/* + * These two structures are not present in guest memory, are private + * to the signal implementation, but are largely copied from the + * kernel's signal implementation. + */ +struct ctx_layout { + void *haddr; + abi_ptr gaddr; + unsigned int size; +}; + +struct extctx_layout { + unsigned int size; + unsigned int flags; + struct ctx_layout fpu; + struct ctx_layout end; +}; + +static abi_ptr extframe_alloc(struct extctx_layout *extctx, + struct ctx_layout *sctx, unsigned size, + unsigned align, abi_ptr orig_sp) +{ + abi_ptr sp = orig_sp; + + sp -= sizeof(struct target_sctx_info) + size; + align = MAX(align, CONTEXT_INFO_ALIGN); + sp = ROUND_DOWN(sp, align); + sctx->gaddr = sp; + + size = orig_sp - sp; + sctx->size = size; + extctx->size += size; + + return sp; +} + +static abi_ptr setup_extcontext(struct extctx_layout *extctx, abi_ptr sp) +{ + memset(extctx, 0, sizeof(struct extctx_layout)); + + /* Grow down, alloc "end" context info first. */ + sp = extframe_alloc(extctx, &extctx->end, 0, CONTEXT_INFO_ALIGN, sp); + + /* For qemu, there is no lazy fp context switch, so fp always present. */ + extctx->flags = SC_USED_FP; + sp = extframe_alloc(extctx, &extctx->fpu, + sizeof(struct target_rt_sigframe), FPU_CTX_ALIGN, sp); + + return sp; +} + +static void setup_sigframe(CPULoongArchState *env, + struct target_sigcontext *sc, + struct extctx_layout *extctx) +{ + struct target_sctx_info *info; + struct target_fpu_context *fpu_ctx; + int i; + + __put_user(extctx->flags, &sc->sc_flags); + __put_user(env->pc, &sc->sc_pc); + __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; ++i) { + __put_user(env->gpr[i], &sc->sc_regs[i]); + } + + /* + * Set fpu context + */ + info = extctx->fpu.haddr; + __put_user(FPU_CTX_MAGIC, &info->magic); + __put_user(extctx->fpu.size, &info->size); + + fpu_ctx = (struct target_fpu_context *)(info + 1); + for (i = 0; i < 32; ++i) { + __put_user(env->fpr[i], &fpu_ctx->regs[i]); + } + __put_user(read_fcc(env), &fpu_ctx->fcc); + __put_user(env->fcsr0, &fpu_ctx->fcsr); + + /* + * Set end context + */ + info = extctx->end.haddr; + __put_user(0, &info->magic); + __put_user(extctx->end.size, &info->size); +} + +static bool parse_extcontext(struct extctx_layout *extctx, abi_ptr frame) +{ + memset(extctx, 0, sizeof(*extctx)); + + while (1) { + uint32_t magic, size; + + if (get_user_u32(magic, frame) || get_user_u32(size, frame + 4)) { + return false; + } + + switch (magic) { + case 0: /* END */ + extctx->end.gaddr = frame; + extctx->end.size = size; + extctx->size += size; + return true; + + case FPU_CTX_MAGIC: + if (size < (sizeof(struct target_sctx_info) + + sizeof(struct target_fpu_context))) { + return false; + } + extctx->fpu.gaddr = frame; + extctx->fpu.size = size; + extctx->size += size; + break; + default: + return false; + } + + frame += size; + } +} + +static void restore_sigframe(CPULoongArchState *env, + struct target_sigcontext *sc, + struct extctx_layout *extctx) +{ + int i; + + __get_user(env->pc, &sc->sc_pc); + for (i = 1; i < 32; ++i) { + __get_user(env->gpr[i], &sc->sc_regs[i]); + } + + if (extctx->fpu.haddr) { + struct target_fpu_context *fpu_ctx = + extctx->fpu.haddr + sizeof(struct target_sctx_info); + uint64_t fcc; + + for (i = 0; i < 32; ++i) { + __get_user(env->fpr[i], &fpu_ctx->regs[i]); + } + __get_user(fcc, &fpu_ctx->fcc); + write_fcc(env, fcc); + __get_user(env->fcsr0, &fpu_ctx->fcsr); + restore_fp_status(env); + } +} + +/* + * Determine which stack to use. + */ +static abi_ptr get_sigframe(struct target_sigaction *ka, + CPULoongArchState *env, + struct extctx_layout *extctx) +{ + abi_ulong sp; + + sp = target_sigsp(get_sp_from_cpustate(env), ka); + sp = ROUND_DOWN(sp, 16); + sp = setup_extcontext(extctx, sp); + sp -= sizeof(struct target_rt_sigframe); + + assert(QEMU_IS_ALIGNED(sp, 16)); + + return sp; +} + +void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPULoongArchState *env) +{ + struct target_rt_sigframe *frame; + struct extctx_layout extctx; + abi_ptr frame_addr; + int i; + + frame_addr = get_sigframe(ka, env, &extctx); + trace_user_setup_rt_frame(env, frame_addr); + + frame = lock_user(VERIFY_WRITE, frame_addr, + sizeof(*frame) + extctx.size, 0); + if (!frame) { + force_sigsegv(sig); + return; + } + extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr); + extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr); + + tswap_siginfo(&frame->rs_info, info); + + __put_user(0, &frame->rs_uc.tuc_flags); + __put_user(0, &frame->rs_uc.tuc_link); + target_save_altstack(&frame->rs_uc.tuc_stack, env); + + setup_sigframe(env, &frame->rs_uc.tuc_mcontext, &extctx); + + for (i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); + } + + env->gpr[4] = sig; + env->gpr[5] = frame_addr + offsetof(struct target_rt_sigframe, rs_info); + env->gpr[6] = frame_addr + offsetof(struct target_rt_sigframe, rs_uc); + env->gpr[3] = frame_addr; + env->gpr[1] = default_rt_sigreturn; + + env->pc = ka->_sa_handler; + unlock_user(frame, frame_addr, sizeof(*frame) + extctx.size); +} + +long do_rt_sigreturn(CPULoongArchState *env) +{ + struct target_rt_sigframe *frame; + struct extctx_layout extctx; + abi_ulong frame_addr; + sigset_t blocked; + + frame_addr = env->gpr[3]; + trace_user_do_rt_sigreturn(env, frame_addr); + + if (!parse_extcontext(&extctx, frame_addr + sizeof(*frame))) { + goto badframe; + } + + frame = lock_user(VERIFY_READ, frame_addr, + sizeof(*frame) + extctx.size, 1); + if (!frame) { + goto badframe; + } + if (extctx.fpu.gaddr) { + extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr); + } + + target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); + set_sigmask(&blocked); + + restore_sigframe(env, &frame->rs_uc.tuc_mcontext, &extctx); + + target_restore_altstack(&frame->rs_uc.tuc_stack, env); + + unlock_user(frame, frame_addr, 0); + return -QEMU_ESIGRETURN; + + badframe: + force_sig(TARGET_SIGSEGV); + return -QEMU_ESIGRETURN; +} + +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0); + assert(tramp != NULL); + + __put_user(0x03822c0b, tramp + 0); /* ori a7, zero, 0x8b */ + __put_user(0x002b0000, tramp + 1); /* syscall 0 */ + + default_rt_sigreturn = sigtramp_page; + unlock_user(tramp, sigtramp_page, 8); +} diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h new file mode 100644 index 000000000000..1cffcae120e4 --- /dev/null +++ b/linux-user/loongarch64/sockbits.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_SOCKBITS_H +#define LOONGARCH_TARGET_SOCKBITS_H + +#include "../generic/sockbits.h" + +#endif diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h new file mode 100644 index 000000000000..be00915adf22 --- /dev/null +++ b/linux-user/loongarch64/syscall_nr.h @@ -0,0 +1,312 @@ +/* + * This file contains the system call numbers. + * Do not modify. + * This file is generated by scripts/gensyscalls.sh + */ +#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H +#define LINUX_USER_LOONGARCH_SYSCALL_NR_H + +#define TARGET_NR_io_setup 0 +#define TARGET_NR_io_destroy 1 +#define TARGET_NR_io_submit 2 +#define TARGET_NR_io_cancel 3 +#define TARGET_NR_io_getevents 4 +#define TARGET_NR_setxattr 5 +#define TARGET_NR_lsetxattr 6 +#define TARGET_NR_fsetxattr 7 +#define TARGET_NR_getxattr 8 +#define TARGET_NR_lgetxattr 9 +#define TARGET_NR_fgetxattr 10 +#define TARGET_NR_listxattr 11 +#define TARGET_NR_llistxattr 12 +#define TARGET_NR_flistxattr 13 +#define TARGET_NR_removexattr 14 +#define TARGET_NR_lremovexattr 15 +#define TARGET_NR_fremovexattr 16 +#define TARGET_NR_getcwd 17 +#define TARGET_NR_lookup_dcookie 18 +#define TARGET_NR_eventfd2 19 +#define TARGET_NR_epoll_create1 20 +#define TARGET_NR_epoll_ctl 21 +#define TARGET_NR_epoll_pwait 22 +#define TARGET_NR_dup 23 +#define TARGET_NR_dup3 24 +#define TARGET_NR_fcntl 25 +#define TARGET_NR_inotify_init1 26 +#define TARGET_NR_inotify_add_watch 27 +#define TARGET_NR_inotify_rm_watch 28 +#define TARGET_NR_ioctl 29 +#define TARGET_NR_ioprio_set 30 +#define TARGET_NR_ioprio_get 31 +#define TARGET_NR_flock 32 +#define TARGET_NR_mknodat 33 +#define TARGET_NR_mkdirat 34 +#define TARGET_NR_unlinkat 35 +#define TARGET_NR_symlinkat 36 +#define TARGET_NR_linkat 37 +#define TARGET_NR_umount2 39 +#define TARGET_NR_mount 40 +#define TARGET_NR_pivot_root 41 +#define TARGET_NR_nfsservctl 42 +#define TARGET_NR_statfs 43 +#define TARGET_NR_fstatfs 44 +#define TARGET_NR_truncate 45 +#define TARGET_NR_ftruncate 46 +#define TARGET_NR_fallocate 47 +#define TARGET_NR_faccessat 48 +#define TARGET_NR_chdir 49 +#define TARGET_NR_fchdir 50 +#define TARGET_NR_chroot 51 +#define TARGET_NR_fchmod 52 +#define TARGET_NR_fchmodat 53 +#define TARGET_NR_fchownat 54 +#define TARGET_NR_fchown 55 +#define TARGET_NR_openat 56 +#define TARGET_NR_close 57 +#define TARGET_NR_vhangup 58 +#define TARGET_NR_pipe2 59 +#define TARGET_NR_quotactl 60 +#define TARGET_NR_getdents64 61 +#define TARGET_NR_lseek 62 +#define TARGET_NR_read 63 +#define TARGET_NR_write 64 +#define TARGET_NR_readv 65 +#define TARGET_NR_writev 66 +#define TARGET_NR_pread64 67 +#define TARGET_NR_pwrite64 68 +#define TARGET_NR_preadv 69 +#define TARGET_NR_pwritev 70 +#define TARGET_NR_sendfile 71 +#define TARGET_NR_pselect6 72 +#define TARGET_NR_ppoll 73 +#define TARGET_NR_signalfd4 74 +#define TARGET_NR_vmsplice 75 +#define TARGET_NR_splice 76 +#define TARGET_NR_tee 77 +#define TARGET_NR_readlinkat 78 +#define TARGET_NR_sync 81 +#define TARGET_NR_fsync 82 +#define TARGET_NR_fdatasync 83 +#define TARGET_NR_sync_file_range 84 +#define TARGET_NR_timerfd_create 85 +#define TARGET_NR_timerfd_settime 86 +#define TARGET_NR_timerfd_gettime 87 +#define TARGET_NR_utimensat 88 +#define TARGET_NR_acct 89 +#define TARGET_NR_capget 90 +#define TARGET_NR_capset 91 +#define TARGET_NR_personality 92 +#define TARGET_NR_exit 93 +#define TARGET_NR_exit_group 94 +#define TARGET_NR_waitid 95 +#define TARGET_NR_set_tid_address 96 +#define TARGET_NR_unshare 97 +#define TARGET_NR_futex 98 +#define TARGET_NR_set_robust_list 99 +#define TARGET_NR_get_robust_list 100 +#define TARGET_NR_nanosleep 101 +#define TARGET_NR_getitimer 102 +#define TARGET_NR_setitimer 103 +#define TARGET_NR_kexec_load 104 +#define TARGET_NR_init_module 105 +#define TARGET_NR_delete_module 106 +#define TARGET_NR_timer_create 107 +#define TARGET_NR_timer_gettime 108 +#define TARGET_NR_timer_getoverrun 109 +#define TARGET_NR_timer_settime 110 +#define TARGET_NR_timer_delete 111 +#define TARGET_NR_clock_settime 112 +#define TARGET_NR_clock_gettime 113 +#define TARGET_NR_clock_getres 114 +#define TARGET_NR_clock_nanosleep 115 +#define TARGET_NR_syslog 116 +#define TARGET_NR_ptrace 117 +#define TARGET_NR_sched_setparam 118 +#define TARGET_NR_sched_setscheduler 119 +#define TARGET_NR_sched_getscheduler 120 +#define TARGET_NR_sched_getparam 121 +#define TARGET_NR_sched_setaffinity 122 +#define TARGET_NR_sched_getaffinity 123 +#define TARGET_NR_sched_yield 124 +#define TARGET_NR_sched_get_priority_max 125 +#define TARGET_NR_sched_get_priority_min 126 +#define TARGET_NR_sched_rr_get_interval 127 +#define TARGET_NR_restart_syscall 128 +#define TARGET_NR_kill 129 +#define TARGET_NR_tkill 130 +#define TARGET_NR_tgkill 131 +#define TARGET_NR_sigaltstack 132 +#define TARGET_NR_rt_sigsuspend 133 +#define TARGET_NR_rt_sigaction 134 +#define TARGET_NR_rt_sigprocmask 135 +#define TARGET_NR_rt_sigpending 136 +#define TARGET_NR_rt_sigtimedwait 137 +#define TARGET_NR_rt_sigqueueinfo 138 +#define TARGET_NR_rt_sigreturn 139 +#define TARGET_NR_setpriority 140 +#define TARGET_NR_getpriority 141 +#define TARGET_NR_reboot 142 +#define TARGET_NR_setregid 143 +#define TARGET_NR_setgid 144 +#define TARGET_NR_setreuid 145 +#define TARGET_NR_setuid 146 +#define TARGET_NR_setresuid 147 +#define TARGET_NR_getresuid 148 +#define TARGET_NR_setresgid 149 +#define TARGET_NR_getresgid 150 +#define TARGET_NR_setfsuid 151 +#define TARGET_NR_setfsgid 152 +#define TARGET_NR_times 153 +#define TARGET_NR_setpgid 154 +#define TARGET_NR_getpgid 155 +#define TARGET_NR_getsid 156 +#define TARGET_NR_setsid 157 +#define TARGET_NR_getgroups 158 +#define TARGET_NR_setgroups 159 +#define TARGET_NR_uname 160 +#define TARGET_NR_sethostname 161 +#define TARGET_NR_setdomainname 162 +#define TARGET_NR_getrusage 165 +#define TARGET_NR_umask 166 +#define TARGET_NR_prctl 167 +#define TARGET_NR_getcpu 168 +#define TARGET_NR_gettimeofday 169 +#define TARGET_NR_settimeofday 170 +#define TARGET_NR_adjtimex 171 +#define TARGET_NR_getpid 172 +#define TARGET_NR_getppid 173 +#define TARGET_NR_getuid 174 +#define TARGET_NR_geteuid 175 +#define TARGET_NR_getgid 176 +#define TARGET_NR_getegid 177 +#define TARGET_NR_gettid 178 +#define TARGET_NR_sysinfo 179 +#define TARGET_NR_mq_open 180 +#define TARGET_NR_mq_unlink 181 +#define TARGET_NR_mq_timedsend 182 +#define TARGET_NR_mq_timedreceive 183 +#define TARGET_NR_mq_notify 184 +#define TARGET_NR_mq_getsetattr 185 +#define TARGET_NR_msgget 186 +#define TARGET_NR_msgctl 187 +#define TARGET_NR_msgrcv 188 +#define TARGET_NR_msgsnd 189 +#define TARGET_NR_semget 190 +#define TARGET_NR_semctl 191 +#define TARGET_NR_semtimedop 192 +#define TARGET_NR_semop 193 +#define TARGET_NR_shmget 194 +#define TARGET_NR_shmctl 195 +#define TARGET_NR_shmat 196 +#define TARGET_NR_shmdt 197 +#define TARGET_NR_socket 198 +#define TARGET_NR_socketpair 199 +#define TARGET_NR_bind 200 +#define TARGET_NR_listen 201 +#define TARGET_NR_accept 202 +#define TARGET_NR_connect 203 +#define TARGET_NR_getsockname 204 +#define TARGET_NR_getpeername 205 +#define TARGET_NR_sendto 206 +#define TARGET_NR_recvfrom 207 +#define TARGET_NR_setsockopt 208 +#define TARGET_NR_getsockopt 209 +#define TARGET_NR_shutdown 210 +#define TARGET_NR_sendmsg 211 +#define TARGET_NR_recvmsg 212 +#define TARGET_NR_readahead 213 +#define TARGET_NR_brk 214 +#define TARGET_NR_munmap 215 +#define TARGET_NR_mremap 216 +#define TARGET_NR_add_key 217 +#define TARGET_NR_request_key 218 +#define TARGET_NR_keyctl 219 +#define TARGET_NR_clone 220 +#define TARGET_NR_execve 221 +#define TARGET_NR_mmap 222 +#define TARGET_NR_fadvise64 223 +#define TARGET_NR_swapon 224 +#define TARGET_NR_swapoff 225 +#define TARGET_NR_mprotect 226 +#define TARGET_NR_msync 227 +#define TARGET_NR_mlock 228 +#define TARGET_NR_munlock 229 +#define TARGET_NR_mlockall 230 +#define TARGET_NR_munlockall 231 +#define TARGET_NR_mincore 232 +#define TARGET_NR_madvise 233 +#define TARGET_NR_remap_file_pages 234 +#define TARGET_NR_mbind 235 +#define TARGET_NR_get_mempolicy 236 +#define TARGET_NR_set_mempolicy 237 +#define TARGET_NR_migrate_pages 238 +#define TARGET_NR_move_pages 239 +#define TARGET_NR_rt_tgsigqueueinfo 240 +#define TARGET_NR_perf_event_open 241 +#define TARGET_NR_accept4 242 +#define TARGET_NR_recvmmsg 243 +#define TARGET_NR_arch_specific_syscall 244 +#define TARGET_NR_wait4 260 +#define TARGET_NR_prlimit64 261 +#define TARGET_NR_fanotify_init 262 +#define TARGET_NR_fanotify_mark 263 +#define TARGET_NR_name_to_handle_at 264 +#define TARGET_NR_open_by_handle_at 265 +#define TARGET_NR_clock_adjtime 266 +#define TARGET_NR_syncfs 267 +#define TARGET_NR_setns 268 +#define TARGET_NR_sendmmsg 269 +#define TARGET_NR_process_vm_readv 270 +#define TARGET_NR_process_vm_writev 271 +#define TARGET_NR_kcmp 272 +#define TARGET_NR_finit_module 273 +#define TARGET_NR_sched_setattr 274 +#define TARGET_NR_sched_getattr 275 +#define TARGET_NR_renameat2 276 +#define TARGET_NR_seccomp 277 +#define TARGET_NR_getrandom 278 +#define TARGET_NR_memfd_create 279 +#define TARGET_NR_bpf 280 +#define TARGET_NR_execveat 281 +#define TARGET_NR_userfaultfd 282 +#define TARGET_NR_membarrier 283 +#define TARGET_NR_mlock2 284 +#define TARGET_NR_copy_file_range 285 +#define TARGET_NR_preadv2 286 +#define TARGET_NR_pwritev2 287 +#define TARGET_NR_pkey_mprotect 288 +#define TARGET_NR_pkey_alloc 289 +#define TARGET_NR_pkey_free 290 +#define TARGET_NR_statx 291 +#define TARGET_NR_io_pgetevents 292 +#define TARGET_NR_rseq 293 +#define TARGET_NR_kexec_file_load 294 +#define TARGET_NR_pidfd_send_signal 424 +#define TARGET_NR_io_uring_setup 425 +#define TARGET_NR_io_uring_enter 426 +#define TARGET_NR_io_uring_register 427 +#define TARGET_NR_open_tree 428 +#define TARGET_NR_move_mount 429 +#define TARGET_NR_fsopen 430 +#define TARGET_NR_fsconfig 431 +#define TARGET_NR_fsmount 432 +#define TARGET_NR_fspick 433 +#define TARGET_NR_pidfd_open 434 +#define TARGET_NR_clone3 435 +#define TARGET_NR_close_range 436 +#define TARGET_NR_openat2 437 +#define TARGET_NR_pidfd_getfd 438 +#define TARGET_NR_faccessat2 439 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_quotactl_fd 443 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_process_mrelease 448 +#define TARGET_NR_futex_waitv 449 +#define TARGET_NR_set_mempolicy_home_node 450 +#define TARGET_NR_syscalls 451 + +#endif /* LINUX_USER_LOONGARCH_SYSCALL_NR_H */ diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h new file mode 100644 index 000000000000..a29af661566c --- /dev/null +++ b/linux-user/loongarch64/target_cpu.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch specific CPU ABI and functions for linux-user + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_CPU_H +#define LOONGARCH_TARGET_CPU_H + +static inline void cpu_clone_regs_child(CPULoongArchState *env, + target_ulong newsp, unsigned flags) +{ + if (newsp) { + env->gpr[3] = newsp; + } + env->gpr[4] = 0; +} + +static inline void cpu_clone_regs_parent(CPULoongArchState *env, + unsigned flags) +{ +} + +static inline void cpu_set_tls(CPULoongArchState *env, target_ulong newtls) +{ + env->gpr[2] = newtls; +} + +static inline abi_ulong get_sp_from_cpustate(CPULoongArchState *state) +{ + return state->gpr[3]; +} +#endif diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h new file mode 100644 index 000000000000..95c3f05a46d8 --- /dev/null +++ b/linux-user/loongarch64/target_elf.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_ELF_H +#define LOONGARCH_TARGET_ELF_H +static inline const char *cpu_get_model(uint32_t eflags) +{ + return "la464"; +} +#endif diff --git a/linux-user/loongarch64/target_errno_defs.h b/linux-user/loongarch64/target_errno_defs.h new file mode 100644 index 000000000000..c198b8aca9d4 --- /dev/null +++ b/linux-user/loongarch64/target_errno_defs.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_ERRNO_DEFS_H +#define LOONGARCH_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h new file mode 100644 index 000000000000..99bf5868545c --- /dev/null +++ b/linux-user/loongarch64/target_fcntl.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_FCNTL_H +#define LOONGARCH_TARGET_FCNTL_H + +#include "../generic/fcntl.h" + +#endif diff --git a/linux-user/loongarch64/target_mman.h b/linux-user/loongarch64/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/loongarch64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/loongarch64/target_prctl.h b/linux-user/loongarch64/target_prctl.h new file mode 100644 index 000000000000..eb53b31ad554 --- /dev/null +++ b/linux-user/loongarch64/target_prctl.h @@ -0,0 +1 @@ +/* No special prctl support required. */ diff --git a/linux-user/loongarch64/target_resource.h b/linux-user/loongarch64/target_resource.h new file mode 100644 index 000000000000..0f86bf24ee94 --- /dev/null +++ b/linux-user/loongarch64/target_resource.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_RESOURCE_H +#define LOONGARCH_TARGET_RESOURCE_H + +#include "../generic/target_resource.h" + +#endif diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h new file mode 100644 index 000000000000..ad3aaffcb42d --- /dev/null +++ b/linux-user/loongarch64/target_signal.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_SIGNAL_H +#define LOONGARCH_TARGET_SIGNAL_H + +#include "../generic/signal.h" + +#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 + +#endif /* LOONGARCH_TARGET_SIGNAL_H */ diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h new file mode 100644 index 000000000000..6041441e15e9 --- /dev/null +++ b/linux-user/loongarch64/target_structs.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_STRUCTS_H +#define LOONGARCH_TARGET_STRUCTS_H + +#include "../generic/target_structs.h" + +#endif diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h new file mode 100644 index 000000000000..8b5de5212435 --- /dev/null +++ b/linux-user/loongarch64/target_syscall.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_SYSCALL_H +#define LOONGARCH_TARGET_SYSCALL_H + +#include "qemu/units.h" + +/* + * this struct defines the way the registers are stored on the + * stack during a system call. + */ + +struct target_pt_regs { + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + struct { + target_ulong era; + target_ulong badv; + target_ulong crmd; + target_ulong prmd; + target_ulong euen; + target_ulong ecfg; + target_ulong estat; + } csr; + target_ulong orig_a0; + target_ulong __last[0]; +}; + +#define UNAME_MACHINE "loongarch64" +#define UNAME_MINIMUM_RELEASE "5.19.0" + +#define TARGET_MCL_CURRENT 1 +#define TARGET_MCL_FUTURE 2 +#define TARGET_MCL_ONFAULT 4 + +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPULoongArchState *env) +{ + return 64 * KiB; +} + +#endif diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h new file mode 100644 index 000000000000..d425db8748c5 --- /dev/null +++ b/linux-user/loongarch64/termbits.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_TERMBITS_H +#define LOONGARCH_TARGET_TERMBITS_H + +#include "../generic/termbits.h" + +#endif diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index 928a18e3cf05..caead1cb741c 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" @@ -37,27 +36,25 @@ void cpu_loop(CPUM68KState *env) process_queued_cpu_work(cs); switch(trapnr) { - case EXCP_HALT_INSN: - /* Semihosing syscall. */ - env->pc += 4; - do_m68k_semihosting(env, env->dregs[0]); - break; case EXCP_ILLEGAL: case EXCP_LINEA: case EXCP_LINEF: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc); break; case EXCP_CHK: - force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc); + case EXCP_TRAPCC: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->mmu.ar); break; case EXCP_DIV0: - force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->mmu.ar); + break; + case EXCP_TRACE: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_TRACE, env->mmu.ar); break; case EXCP_TRAP0: { abi_long ret; n = env->dregs[0]; - env->pc += 2; ret = do_syscall(env, n, env->dregs[1], @@ -77,7 +74,11 @@ void cpu_loop(CPUM68KState *env) case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; + case EXCP_TRAP0 + 1 ... EXCP_TRAP0 + 14: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, env->pc); + break; case EXCP_DEBUG: + case EXCP_TRAP15: force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; case EXCP_ATOMIC: diff --git a/linux-user/m68k/target_mman.h b/linux-user/m68k/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /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 fbc9bcfd5f5f..a17fed045bfb 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -18,10 +18,9 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qemu/units.h" #include "qemu/accel.h" -#include "sysemu/tcg.h" #include "qemu-version.h" #include #include @@ -55,6 +54,10 @@ #include "loader.h" #include "user-mmap.h" +#ifdef CONFIG_SEMIHOSTING +#include "semihosting/semihost.h" +#endif + #ifndef AT_FLAGS_PRESERVE_ARGV0 #define AT_FLAGS_PRESERVE_ARGV0_BIT 0 #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT) @@ -85,6 +88,7 @@ static bool enable_strace; * Used to support command line arguments overriding environment variables. */ static int last_log_mask; +static const char *last_log_filename; /* * When running 32-on-64 we should make sure we can fit all of the possible @@ -120,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. */ @@ -134,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; @@ -257,7 +267,7 @@ static void handle_arg_dfilter(const char *arg) static void handle_arg_log_filename(const char *arg) { - qemu_set_log_filename(arg, &error_fatal); + last_log_filename = arg; } static void handle_arg_set_env(const char *arg) @@ -643,7 +653,6 @@ int main(int argc, char **argv, char **envp) int i; int ret; int execfd; - int log_mask; unsigned long max_reserved_va; bool preserve_argv0; @@ -665,7 +674,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; } } @@ -677,11 +687,9 @@ int main(int argc, char **argv, char **envp) optind = parse_args(argc, argv); - log_mask = last_log_mask | (enable_strace ? LOG_STRACE : 0); - if (log_mask) { - qemu_log_needs_buffers(); - qemu_set_log(log_mask); - } + qemu_set_log_filename_flags(last_log_filename, + last_log_mask | (enable_strace * LOG_STRACE), + &error_fatal); if (!trace_init_backends()) { exit(1); @@ -858,21 +866,36 @@ int main(int argc, char **argv, char **envp) g_free(target_environ); if (qemu_loglevel_mask(CPU_LOG_PAGE)) { - qemu_log("guest_base %p\n", (void *)guest_base); - log_page_dump("binary load"); - - qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); - qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); - qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n", info->start_code); - qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n", info->start_data); - qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data); - qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", info->start_stack); - qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); - qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); - qemu_log("argv_start 0x" TARGET_ABI_FMT_lx "\n", info->arg_start); - qemu_log("env_start 0x" TARGET_ABI_FMT_lx "\n", - info->arg_end + (abi_ulong)sizeof(abi_ulong)); - qemu_log("auxv_start 0x" TARGET_ABI_FMT_lx "\n", info->saved_auxv); + FILE *f = qemu_log_trylock(); + if (f) { + fprintf(f, "guest_base %p\n", (void *)guest_base); + fprintf(f, "page layout changed following binary load\n"); + page_dump(f); + + fprintf(f, "start_brk 0x" TARGET_ABI_FMT_lx "\n", + info->start_brk); + fprintf(f, "end_code 0x" TARGET_ABI_FMT_lx "\n", + info->end_code); + fprintf(f, "start_code 0x" TARGET_ABI_FMT_lx "\n", + info->start_code); + fprintf(f, "start_data 0x" TARGET_ABI_FMT_lx "\n", + info->start_data); + fprintf(f, "end_data 0x" TARGET_ABI_FMT_lx "\n", + info->end_data); + fprintf(f, "start_stack 0x" TARGET_ABI_FMT_lx "\n", + info->start_stack); + fprintf(f, "brk 0x" TARGET_ABI_FMT_lx "\n", + info->brk); + fprintf(f, "entry 0x" TARGET_ABI_FMT_lx "\n", + info->entry); + fprintf(f, "argv_start 0x" TARGET_ABI_FMT_lx "\n", + info->argv); + fprintf(f, "env_start 0x" TARGET_ABI_FMT_lx "\n", + info->envp); + fprintf(f, "auxv_start 0x" TARGET_ABI_FMT_lx "\n", + info->saved_auxv); + qemu_log_unlock(f); + } } target_set_brk(info->brk); @@ -894,6 +917,11 @@ int main(int argc, char **argv, char **envp) } gdb_handlesig(cpu, 0); } + +#ifdef CONFIG_SEMIHOSTING + qemu_semihosting_guestfd_init(); +#endif + cpu_loop(env); /* never exits */ return 0; diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index 1a2556be2c5f..5ccf9e942eaa 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/microblaze/target_mman.h b/linux-user/microblaze/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/microblaze/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c index 9bb12a07ba08..d5c1c7941d34 100644 --- a/linux-user/mips/cpu_loop.c +++ b/linux-user/mips/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/mips/target_mman.h b/linux-user/mips/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /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 000000000000..e7ba6070fe7c --- /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 c125031b9046..10f5079331c3 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,10 @@ 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; + ret = 0; + error: mmap_unlock(); return ret; @@ -251,8 +255,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 +432,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(); @@ -494,7 +503,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, may need to truncate file maps at EOF and add extra anonymous pages up to the targets page boundary. */ - if ((qemu_real_host_page_size < qemu_host_page_size) && + if ((qemu_real_host_page_size() < qemu_host_page_size) && !(flags & MAP_ANONYMOUS)) { struct stat sb; @@ -537,6 +546,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 +630,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,13 +639,28 @@ 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)) { - log_page_dump(__func__); + FILE *f = qemu_log_trylock(); + if (f) { + fprintf(f, "page layout changed following mmap\n"); + page_dump(f); + qemu_log_unlock(f); + } } - tb_invalidate_phys_range(start, start + len); mmap_unlock(); return start; fail: @@ -736,7 +764,6 @@ int target_munmap(abi_ulong start, abi_ulong len) if (ret == 0) { page_set_flags(start, start + len, 0); - tb_invalidate_phys_range(start, start + len); } mmap_unlock(); return ret; @@ -826,7 +853,74 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID | PAGE_RESET); } - tb_invalidate_phys_range(new_addr, new_addr + new_size); mmap_unlock(); return new_addr; } + +static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end) +{ + ulong addr; + + if ((start | end) & ~qemu_host_page_mask) { + return false; + } + + for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + if (!(page_get_flags(addr) & PAGE_PASSTHROUGH)) { + return false; + } + } + + return true; +} + +abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) +{ + abi_ulong len, end; + int ret = 0; + + if (start & ~TARGET_PAGE_MASK) { + return -TARGET_EINVAL; + } + len = TARGET_PAGE_ALIGN(len_in); + + if (len_in && !len) { + return -TARGET_EINVAL; + } + + end = start + len; + if (end < start) { + return -TARGET_EINVAL; + } + + if (end == start) { + return 0; + } + + if (!guest_range_valid_untagged(start, len)) { + return -TARGET_EINVAL; + } + + /* + * A straight passthrough may not be safe because qemu sometimes turns + * private file-backed mappings into anonymous mappings. + * + * 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: 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 == 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(); + + return ret; +} diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c index 1e93ef34e649..da77ede76bd4 100644 --- a/linux-user/nios2/cpu_loop.c +++ b/linux-user/nios2/cpu_loop.c @@ -26,7 +26,6 @@ void cpu_loop(CPUNios2State *env) { CPUState *cs = env_cpu(env); - target_siginfo_t info; int trapnr, ret; for (;;) { @@ -39,6 +38,30 @@ void cpu_loop(CPUNios2State *env) /* just indicate that signals should be handled asap */ break; + case EXCP_DIV: + /* Match kernel's handle_diverror_c(). */ + env->pc -= 4; + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + break; + + case EXCP_UNALIGN: + case EXCP_UNALIGND: + force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, + env->ctrl[CR_BADADDR]); + break; + + case EXCP_ILLEGAL: + case EXCP_UNIMPL: + /* Match kernel's handle_illegal_c(). */ + env->pc -= 4; + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); + break; + case EXCP_SUPERI: + /* Match kernel's handle_supervisor_instr(). */ + env->pc -= 4; + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; + case EXCP_TRAP: switch (env->error_code) { case 0: @@ -49,32 +72,41 @@ void cpu_loop(CPUNios2State *env) env->regs[7], env->regs[8], env->regs[9], 0, 0); - if (env->regs[2] == 0) { /* FIXME: syscall 0 workaround */ - ret = 0; + if (ret == -QEMU_ESIGRETURN) { + /* rt_sigreturn has set all state. */ + break; } - + if (ret == -QEMU_ERESTARTSYS) { + env->pc -= 4; + break; + } + /* + * See the code after translate_rc_and_ret: all negative + * values are errors (aided by userspace restricted to 2G), + * errno is returned positive in r2, and error indication + * is a boolean in r7. + */ env->regs[2] = abs(ret); - /* Return value is 0..4096 */ - env->regs[7] = ret > 0xfffff000u; - env->regs[R_PC] += 4; + env->regs[7] = ret < 0; break; case 1: qemu_log_mask(CPU_LOG_INT, "\nTrap 1\n"); - force_sig_fault(TARGET_SIGUSR1, 0, env->regs[R_PC]); + force_sig_fault(TARGET_SIGUSR1, 0, env->pc); break; case 2: qemu_log_mask(CPU_LOG_INT, "\nTrap 2\n"); - force_sig_fault(TARGET_SIGUSR2, 0, env->regs[R_PC]); + force_sig_fault(TARGET_SIGUSR2, 0, env->pc); break; case 31: qemu_log_mask(CPU_LOG_INT, "\nTrap 31\n"); - force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[R_PC]); + /* Match kernel's breakpoint_c(). */ + env->pc -= 4; + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; default: qemu_log_mask(CPU_LOG_INT, "\nTrap %d\n", env->error_code); - force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, - env->regs[R_PC]); + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, env->pc); break; case 16: /* QEMU specific, for __kuser_cmpxchg */ @@ -99,27 +131,13 @@ void cpu_loop(CPUNios2State *env) o = env->regs[5]; n = env->regs[6]; env->regs[2] = qatomic_cmpxchg(h, o, n) - o; - env->regs[R_PC] += 4; } break; } break; case EXCP_DEBUG: - info.si_signo = TARGET_SIGTRAP; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - break; - case 0xaa: - { - info.si_signo = TARGET_SIGSEGV; - info.si_errno = 0; - /* TODO: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->regs[R_PC]; - queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - } + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; default: EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n", @@ -133,28 +151,6 @@ void cpu_loop(CPUNios2State *env) void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) { - env->regs[0] = 0; - env->regs[1] = regs->r1; - env->regs[2] = regs->r2; - env->regs[3] = regs->r3; - env->regs[4] = regs->r4; - env->regs[5] = regs->r5; - env->regs[6] = regs->r6; - env->regs[7] = regs->r7; - env->regs[8] = regs->r8; - env->regs[9] = regs->r9; - env->regs[10] = regs->r10; - env->regs[11] = regs->r11; - env->regs[12] = regs->r12; - env->regs[13] = regs->r13; - env->regs[14] = regs->r14; - env->regs[15] = regs->r15; - /* TODO: unsigned long orig_r2; */ - env->regs[R_RA] = regs->ra; - env->regs[R_FP] = regs->fp; env->regs[R_SP] = regs->sp; - env->regs[R_GP] = regs->gp; - env->regs[CR_ESTATUS] = regs->estatus; - env->regs[R_PC] = regs->ea; - /* TODO: unsigned long orig_r7; */ + env->pc = regs->ea; } diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c index 517cd392701c..32b3dc99c6e3 100644 --- a/linux-user/nios2/signal.c +++ b/linux-user/nios2/signal.c @@ -73,12 +73,11 @@ static void rt_setup_ucontext(struct target_ucontext *uc, CPUNios2State *env) __put_user(env->regs[R_RA], &gregs[23]); __put_user(env->regs[R_FP], &gregs[24]); __put_user(env->regs[R_GP], &gregs[25]); - __put_user(env->regs[R_PC], &gregs[27]); + __put_user(env->pc, &gregs[27]); __put_user(env->regs[R_SP], &gregs[28]); } -static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc, - int *pr2) +static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc) { int temp; unsigned long *gregs = uc->tuc_mcontext.gregs; @@ -122,14 +121,12 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc, __get_user(env->regs[R_GP], &gregs[25]); /* Not really necessary no user settable bits */ __get_user(temp, &gregs[26]); - __get_user(env->regs[R_PC], &gregs[27]); + __get_user(env->pc, &gregs[27]); __get_user(env->regs[R_RA], &gregs[23]); __get_user(env->regs[R_SP], &gregs[28]); target_restore_altstack(&uc->tuc_stack, env); - - *pr2 = env->regs[2]; return 0; } @@ -180,25 +177,17 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->regs[4] = sig; env->regs[5] = frame_addr + offsetof(struct target_rt_sigframe, info); env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, uc); - env->regs[R_PC] = ka->_sa_handler; + env->pc = ka->_sa_handler; unlock_user_struct(frame, frame_addr, 1); } -long do_sigreturn(CPUNios2State *env) -{ - trace_user_do_sigreturn(env, 0); - qemu_log_mask(LOG_UNIMP, "do_sigreturn: not implemented\n"); - return -TARGET_ENOSYS; -} - long do_rt_sigreturn(CPUNios2State *env) { /* Verify, can we follow the stack back */ abi_ulong frame_addr = env->regs[R_SP]; struct target_rt_sigframe *frame; sigset_t set; - int rval; if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { goto badframe; @@ -207,15 +196,15 @@ long do_rt_sigreturn(CPUNios2State *env) target_to_host_sigset(&set, &frame->uc.tuc_sigmask); set_sigmask(&set); - if (rt_restore_ucontext(env, &frame->uc, &rval)) { + if (rt_restore_ucontext(env, &frame->uc)) { goto badframe; } unlock_user_struct(frame, frame_addr, 0); - return rval; + return -QEMU_ESIGRETURN; badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -QEMU_ESIGRETURN; } diff --git a/linux-user/nios2/target_cpu.h b/linux-user/nios2/target_cpu.h index 2d2008f0026b..830b4c0741c8 100644 --- a/linux-user/nios2/target_cpu.h +++ b/linux-user/nios2/target_cpu.h @@ -27,6 +27,7 @@ static inline void cpu_clone_regs_child(CPUNios2State *env, target_ulong newsp, env->regs[R_SP] = newsp; } env->regs[R_RET0] = 0; + env->regs[7] = 0; } static inline void cpu_clone_regs_parent(CPUNios2State *env, unsigned flags) diff --git a/linux-user/nios2/target_mman.h b/linux-user/nios2/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/nios2/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c index 7683bea0649e..a7aa586c8f96 100644 --- a/linux-user/openrisc/cpu_loop.c +++ b/linux-user/openrisc/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/openrisc/target_mman.h b/linux-user/openrisc/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/openrisc/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index b468f199e4d2..02204ad8bebb 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "qemu/timer.h" #include "user-internals.h" diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index ce5a4682cdfd..07729c1653b4 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -215,8 +215,7 @@ static target_ulong get_sigframe(struct target_sigaction *ka, return (oldsp - frame_size) & ~0xFUL; } -#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \ - (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN))) +#if TARGET_BIG_ENDIAN == HOST_BIG_ENDIAN #define PPC_VEC_HI 0 #define PPC_VEC_LO 1 #else @@ -543,7 +542,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->nip = (target_ulong) ka->_sa_handler; #endif -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN /* Signal handlers are entered in big-endian mode. */ ppc_store_msr(env, env->msr & ~(1ull << MSR_LE)); #else diff --git a/linux-user/ppc/target_mman.h b/linux-user/ppc/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/ppc/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/ppc/target_syscall.h b/linux-user/ppc/target_syscall.h index 7df911893775..77b36d0b46e6 100644 --- a/linux-user/ppc/target_syscall.h +++ b/linux-user/ppc/target_syscall.h @@ -59,7 +59,7 @@ struct target_revectored_struct { */ #if defined(TARGET_PPC64) -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN #define UNAME_MACHINE "ppc64" #else #define UNAME_MACHINE "ppc64le" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 98dfbf20962b..e2e93fbd1d5d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -40,14 +40,19 @@ struct image_info { abi_ulong data_offset; abi_ulong saved_auxv; abi_ulong auxv_len; - abi_ulong arg_start; - abi_ulong arg_end; - abi_ulong arg_strings; - abi_ulong env_strings; + abi_ulong argc; + abi_ulong argv; + abi_ulong envc; + abi_ulong envp; abi_ulong file_string; 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 */ + abi_ulong env_strings; /* strings for envp; ends arg_strings */ /* The fields below are used in FDPIC mode. */ abi_ulong loadmap_addr; @@ -236,7 +241,7 @@ static inline bool access_ok(CPUState *cpu, int type, } while (0) -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN # define __put_user(x, hptr) __put_user_e(x, hptr, be) # define __get_user(x, hptr) __get_user_e(x, hptr, be) #else diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c index 26d446f32379..bffca7db1275 100644 --- a/linux-user/riscv/cpu_loop.c +++ b/linux-user/riscv/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu.h" #include "user-internals.h" @@ -82,7 +81,7 @@ void cpu_loop(CPURISCVState *env) force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; case RISCV_EXCP_SEMIHOST: - env->gpr[xA0] = do_common_semihosting(cs); + do_common_semihosting(cs); env->pc += 4; break; default: diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 296e39fbf0bb..eaa168199a85 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 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/riscv/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index 7901dfe6f518..285bc60071a8 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index f47713e04a07..f72165576f3b 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -84,6 +84,11 @@ struct target_ucontext { typedef struct { uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; + /* + * This field is no longer initialized by the kernel, but it's still a part + * of the ABI. + */ + uint16_t svc_insn; struct target_siginfo info; struct target_ucontext uc; } rt_sigframe; @@ -141,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]); } @@ -326,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 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/s390x/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/semihost.c b/linux-user/semihost.c index 17f074ac5652..cee62a365c4f 100644 --- a/linux-user/semihost.c +++ b/linux-user/semihost.c @@ -16,39 +16,6 @@ #include "user-internals.h" #include -int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr) -{ - int len = target_strlen(addr); - void *s; - if (len < 0){ - qemu_log_mask(LOG_GUEST_ERROR, - "%s: passed inaccessible address " TARGET_FMT_lx, - __func__, addr); - return 0; - } - s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1); - g_assert(s); /* target_strlen has already verified this will work */ - len = write(STDERR_FILENO, s, len); - unlock_user(s, addr, 0); - return len; -} - -void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr) -{ - char c; - - if (get_user_u8(c, addr)) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: passed inaccessible address " TARGET_FMT_lx, - __func__, addr); - } else { - if (write(STDERR_FILENO, &c, 1) != 1) { - qemu_log_mask(LOG_UNIMP, "%s: unexpected write to stdout failure", - __func__); - } - } -} - /* * For linux-user we can safely block. However as we want to return as * soon as a character is read we need to tweak the termio to disable @@ -56,21 +23,28 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr) * program is expecting more normal behaviour. This is slow but * nothing using semihosting console reading is expecting to be fast. */ -target_ulong qemu_semihosting_console_inc(CPUArchState *env) +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len) { - uint8_t c; + int ret; struct termios old_tio, new_tio; /* Disable line-buffering and echo */ tcgetattr(STDIN_FILENO, &old_tio); new_tio = old_tio; new_tio.c_lflag &= (~ICANON & ~ECHO); + new_tio.c_cc[VMIN] = 1; + new_tio.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSANOW, &new_tio); - c = getchar(); + ret = fread(buf, 1, len, stdin); /* restore config */ tcsetattr(STDIN_FILENO, TCSANOW, &old_tio); - return (target_ulong) c; + return ret; +} + +int qemu_semihosting_console_write(void *buf, int len) +{ + return fwrite(buf, 1, len, stderr); } diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c index 1bd313cb19a2..c805f9db1104 100644 --- a/linux-user/sh4/cpu_loop.c +++ b/linux-user/sh4/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index f6a18bc6b5c0..c4ba962708d6 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 000000000000..e7ba6070fe7c --- /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 6a7e4a93fc13..3e2dc604c2fb 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 092e70b80c6f..61c6fa3fcf12 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 */ }; @@ -725,7 +694,8 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, } /* abort execution with signal */ -static void QEMU_NORETURN dump_core_and_abort(int target_sig) +static G_NORETURN +void dump_core_and_abort(int target_sig) { CPUState *cpu = thread_cpu; CPUArchState *env = cpu->env_ptr; diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index baf3d9ae011f..434c90a55f8f 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/linux-user/sparc/target_mman.h b/linux-user/sparc/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /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 2cdbf030ba44..9ae5a812cd71 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -17,15 +17,17 @@ #include "qemu.h" #include "user-internals.h" #include "strace.h" +#include "signal-common.h" +#include "target_mman.h" struct syscallname { int nr; const char *name; const char *format; - void (*call)(void *, const struct syscallname *, + void (*call)(CPUArchState *, const struct syscallname *, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long); - void (*result)(void *, const struct syscallname *, abi_long, + void (*result)(CPUArchState *, const struct syscallname *, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long); }; @@ -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; @@ -593,7 +587,7 @@ print_fdset(int n, abi_ulong target_fds_addr) /* select */ #ifdef TARGET_NR__newselect static void -print_newselect(void *cpu_env, const struct syscallname *name, +print_newselect(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -611,7 +605,7 @@ print_newselect(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_semctl static void -print_semctl(void *cpu_env, const struct syscallname *name, +print_semctl(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -623,7 +617,7 @@ print_semctl(void *cpu_env, const struct syscallname *name, #endif static void -print_execve(void *cpu_env, const struct syscallname *name, +print_execve(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -656,7 +650,7 @@ print_execve(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ipc static void -print_ipc(void *cpu_env, const struct syscallname *name, +print_ipc(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -689,7 +683,7 @@ print_syscall_err(abi_long ret) const char *errstr; qemu_log(" = "); - if (ret < 0) { + if (is_error(ret)) { errstr = target_strerror(-ret); if (errstr) { qemu_log("-1 errno=%d (%s)", (int)-ret, errstr); @@ -700,7 +694,7 @@ print_syscall_err(abi_long ret) } static void -print_syscall_ret_addr(void *cpu_env, const struct syscallname *name, +print_syscall_ret_addr(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) @@ -721,7 +715,7 @@ print_syscall_ret_raw(struct syscallname *name, abi_long ret) #ifdef TARGET_NR__newselect static void -print_syscall_ret_newselect(void *cpu_env, const struct syscallname *name, +print_syscall_ret_newselect(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) @@ -751,7 +745,7 @@ print_syscall_ret_newselect(void *cpu_env, const struct syscallname *name, #define TARGET_TIME_ERROR 5 /* clock not synchronized */ #ifdef TARGET_NR_adjtimex static void -print_syscall_ret_adjtimex(void *cpu_env, const struct syscallname *name, +print_syscall_ret_adjtimex(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) @@ -786,7 +780,7 @@ print_syscall_ret_adjtimex(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_clock_gettime) || defined(TARGET_NR_clock_getres) static void -print_syscall_ret_clock_gettime(void *cpu_env, const struct syscallname *name, +print_syscall_ret_clock_gettime(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) @@ -803,9 +797,27 @@ print_syscall_ret_clock_gettime(void *cpu_env, const struct syscallname *name, #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(void *cpu_env, const struct syscallname *name, +print_syscall_ret_gettimeofday(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) @@ -824,7 +836,7 @@ print_syscall_ret_gettimeofday(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_getitimer static void -print_syscall_ret_getitimer(void *cpu_env, const struct syscallname *name, +print_syscall_ret_getitimer(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) @@ -843,7 +855,7 @@ print_syscall_ret_getitimer(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_getitimer static void -print_syscall_ret_setitimer(void *cpu_env, const struct syscallname *name, +print_syscall_ret_setitimer(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) @@ -862,7 +874,7 @@ print_syscall_ret_setitimer(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) \ || defined(TARGGET_NR_flistxattr) static void -print_syscall_ret_listxattr(void *cpu_env, const struct syscallname *name, +print_syscall_ret_listxattr(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) @@ -894,7 +906,7 @@ print_syscall_ret_listxattr(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ioctl static void -print_syscall_ret_ioctl(void *cpu_env, const struct syscallname *name, +print_syscall_ret_ioctl(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) @@ -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) { @@ -1760,7 +1798,7 @@ print_termios(void *arg) #ifdef TARGET_NR_accept static void -print_accept(void *cpu_env, const struct syscallname *name, +print_accept(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) { @@ -1774,7 +1812,7 @@ print_accept(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_access static void -print_access(void *cpu_env, const struct syscallname *name, +print_access(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) { @@ -1787,7 +1825,7 @@ print_access(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_acct static void -print_acct(void *cpu_env, const struct syscallname *name, +print_acct(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) { @@ -1799,7 +1837,7 @@ print_acct(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_brk static void -print_brk(void *cpu_env, const struct syscallname *name, +print_brk(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) { @@ -1811,7 +1849,7 @@ print_brk(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_chdir static void -print_chdir(void *cpu_env, const struct syscallname *name, +print_chdir(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) { @@ -1823,7 +1861,7 @@ print_chdir(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_chroot static void -print_chroot(void *cpu_env, const struct syscallname *name, +print_chroot(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) { @@ -1835,7 +1873,7 @@ print_chroot(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_chmod static void -print_chmod(void *cpu_env, const struct syscallname *name, +print_chmod(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) { @@ -1848,7 +1886,7 @@ print_chmod(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_chown) || defined(TARGET_NR_lchown) static void -print_chown(void *cpu_env, const struct syscallname *name, +print_chown(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) { @@ -1863,7 +1901,7 @@ print_chown(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_clock_adjtime static void -print_clock_adjtime(void *cpu_env, const struct syscallname *name, +print_clock_adjtime(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) { @@ -1887,7 +1925,7 @@ static void do_print_clone(unsigned int flags, abi_ulong newsp, } static void -print_clone(void *cpu_env, const struct syscallname *name, +print_clone(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -1907,7 +1945,7 @@ print_clone(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_creat static void -print_creat(void *cpu_env, const struct syscallname *name, +print_creat(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) { @@ -1920,7 +1958,7 @@ print_creat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_execv static void -print_execv(void *cpu_env, const struct syscallname *name, +print_execv(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) { @@ -1931,9 +1969,9 @@ print_execv(void *cpu_env, const struct syscallname *name, } #endif -#ifdef TARGET_NR_faccessat +#if defined(TARGET_NR_faccessat) || defined(TARGET_NR_faccessat2) static void -print_faccessat(void *cpu_env, const struct syscallname *name, +print_faccessat(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) { @@ -1948,7 +1986,7 @@ print_faccessat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fallocate static void -print_fallocate(void *cpu_env, const struct syscallname *name, +print_fallocate(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) { @@ -1968,7 +2006,7 @@ print_fallocate(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fchmodat static void -print_fchmodat(void *cpu_env, const struct syscallname *name, +print_fchmodat(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) { @@ -1983,7 +2021,7 @@ print_fchmodat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fchownat static void -print_fchownat(void *cpu_env, const struct syscallname *name, +print_fchownat(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) { @@ -1999,7 +2037,7 @@ print_fchownat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fcntl) || defined(TARGET_NR_fcntl64) static void -print_fcntl(void *cpu_env, const struct syscallname *name, +print_fcntl(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) { @@ -2135,7 +2173,7 @@ print_fcntl(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fgetxattr static void -print_fgetxattr(void *cpu_env, const struct syscallname *name, +print_fgetxattr(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) { @@ -2150,7 +2188,7 @@ print_fgetxattr(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_flistxattr static void -print_flistxattr(void *cpu_env, const struct syscallname *name, +print_flistxattr(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) { @@ -2164,7 +2202,7 @@ print_flistxattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_getxattr) || defined(TARGET_NR_lgetxattr) static void -print_getxattr(void *cpu_env, const struct syscallname *name, +print_getxattr(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) { @@ -2180,7 +2218,7 @@ print_getxattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) static void -print_listxattr(void *cpu_env, const struct syscallname *name, +print_listxattr(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) { @@ -2195,7 +2233,7 @@ print_listxattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fremovexattr) static void -print_fremovexattr(void *cpu_env, const struct syscallname *name, +print_fremovexattr(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) { @@ -2208,7 +2246,7 @@ print_fremovexattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_removexattr) || defined(TARGET_NR_lremovexattr) static void -print_removexattr(void *cpu_env, const struct syscallname *name, +print_removexattr(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) { @@ -2222,7 +2260,7 @@ print_removexattr(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_futimesat static void -print_futimesat(void *cpu_env, const struct syscallname *name, +print_futimesat(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) { @@ -2237,7 +2275,7 @@ print_futimesat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_gettimeofday static void -print_gettimeofday(void *cpu_env, const struct syscallname *name, +print_gettimeofday(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) { @@ -2250,7 +2288,7 @@ print_gettimeofday(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_settimeofday static void -print_settimeofday(void *cpu_env, const struct syscallname *name, +print_settimeofday(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) { @@ -2263,7 +2301,7 @@ print_settimeofday(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_clock_gettime) || defined(TARGET_NR_clock_getres) static void -print_clock_gettime(void *cpu_env, const struct syscallname *name, +print_clock_gettime(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) { @@ -2275,9 +2313,22 @@ print_clock_gettime(void *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(void *cpu_env, const struct syscallname *name, +print_clock_settime(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) { @@ -2290,7 +2341,7 @@ print_clock_settime(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_getitimer static void -print_getitimer(void *cpu_env, const struct syscallname *name, +print_getitimer(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) { @@ -2303,7 +2354,7 @@ print_getitimer(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_setitimer static void -print_setitimer(void *cpu_env, const struct syscallname *name, +print_setitimer(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) { @@ -2317,7 +2368,7 @@ print_setitimer(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_link static void -print_link(void *cpu_env, const struct syscallname *name, +print_link(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) { @@ -2330,7 +2381,7 @@ print_link(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_linkat static void -print_linkat(void *cpu_env, const struct syscallname *name, +print_linkat(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) { @@ -2346,7 +2397,7 @@ print_linkat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR__llseek) || defined(TARGET_NR_llseek) static void -print__llseek(void *cpu_env, const struct syscallname *name, +print__llseek(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) { @@ -2369,7 +2420,7 @@ print__llseek(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_lseek static void -print_lseek(void *cpu_env, const struct syscallname *name, +print_lseek(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) { @@ -2400,7 +2451,7 @@ print_lseek(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_truncate static void -print_truncate(void *cpu_env, const struct syscallname *name, +print_truncate(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) { @@ -2413,7 +2464,7 @@ print_truncate(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_truncate64 static void -print_truncate64(void *cpu_env, const struct syscallname *name, +print_truncate64(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) { @@ -2430,7 +2481,7 @@ print_truncate64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ftruncate64 static void -print_ftruncate64(void *cpu_env, const struct syscallname *name, +print_ftruncate64(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) { @@ -2447,7 +2498,7 @@ print_ftruncate64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mlockall static void -print_mlockall(void *cpu_env, const struct syscallname *name, +print_mlockall(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) { @@ -2459,7 +2510,7 @@ print_mlockall(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_socket) static void -print_socket(void *cpu_env, const struct syscallname *name, +print_socket(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) { @@ -2920,7 +2971,7 @@ static struct { }; static void -print_socketcall(void *cpu_env, const struct syscallname *name, +print_socketcall(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) { @@ -2941,7 +2992,7 @@ print_socketcall(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_bind) static void -print_bind(void *cpu_env, const struct syscallname *name, +print_bind(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) { @@ -2955,7 +3006,7 @@ print_bind(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \ defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) static void -print_stat(void *cpu_env, const struct syscallname *name, +print_stat(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) { @@ -2969,9 +3020,49 @@ print_stat(void *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(void *cpu_env, const struct syscallname *name, +print_fstat(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) { @@ -2985,7 +3076,7 @@ print_fstat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mkdir static void -print_mkdir(void *cpu_env, const struct syscallname *name, +print_mkdir(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) { @@ -2998,7 +3089,7 @@ print_mkdir(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mkdirat static void -print_mkdirat(void *cpu_env, const struct syscallname *name, +print_mkdirat(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) { @@ -3012,7 +3103,7 @@ print_mkdirat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rmdir static void -print_rmdir(void *cpu_env, const struct syscallname *name, +print_rmdir(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) { @@ -3024,7 +3115,7 @@ print_rmdir(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_sigaction static void -print_rt_sigaction(void *cpu_env, const struct syscallname *name, +print_rt_sigaction(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) { @@ -3038,7 +3129,7 @@ print_rt_sigaction(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_sigprocmask static void -print_rt_sigprocmask(void *cpu_env, const struct syscallname *name, +print_rt_sigprocmask(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) { @@ -3058,7 +3149,7 @@ print_rt_sigprocmask(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_sigqueueinfo static void -print_rt_sigqueueinfo(void *cpu_env, const struct syscallname *name, +print_rt_sigqueueinfo(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) { @@ -3083,7 +3174,7 @@ print_rt_sigqueueinfo(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_tgsigqueueinfo static void -print_rt_tgsigqueueinfo(void *cpu_env, const struct syscallname *name, +print_rt_tgsigqueueinfo(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) { @@ -3167,7 +3258,7 @@ print_syslog_action(abi_ulong arg, int last) } static void -print_syslog(void *cpu_env, const struct syscallname *name, +print_syslog(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) { @@ -3181,7 +3272,7 @@ print_syslog(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mknod static void -print_mknod(void *cpu_env, const struct syscallname *name, +print_mknod(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) { @@ -3200,7 +3291,7 @@ print_mknod(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mknodat static void -print_mknodat(void *cpu_env, const struct syscallname *name, +print_mknodat(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) { @@ -3220,7 +3311,7 @@ print_mknodat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mq_open static void -print_mq_open(void *cpu_env, const struct syscallname *name, +print_mq_open(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) { @@ -3239,7 +3330,7 @@ print_mq_open(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_open static void -print_open(void *cpu_env, const struct syscallname *name, +print_open(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) { @@ -3256,7 +3347,7 @@ print_open(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_openat static void -print_openat(void *cpu_env, const struct syscallname *name, +print_openat(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) { @@ -3272,9 +3363,37 @@ print_openat(void *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, 0); + } + + print_raw_param("%u", arg3, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_mq_unlink static void -print_mq_unlink(void *cpu_env, const struct syscallname *name, +print_mq_unlink(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) { @@ -3286,7 +3405,7 @@ print_mq_unlink(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat) static void -print_fstatat64(void *cpu_env, const struct syscallname *name, +print_fstatat64(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) { @@ -3302,7 +3421,7 @@ print_fstatat64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_readlink static void -print_readlink(void *cpu_env, const struct syscallname *name, +print_readlink(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) { @@ -3316,7 +3435,7 @@ print_readlink(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_readlinkat static void -print_readlinkat(void *cpu_env, const struct syscallname *name, +print_readlinkat(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) { @@ -3331,7 +3450,7 @@ print_readlinkat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rename static void -print_rename(void *cpu_env, const struct syscallname *name, +print_rename(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) { @@ -3344,7 +3463,7 @@ print_rename(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_renameat static void -print_renameat(void *cpu_env, const struct syscallname *name, +print_renameat(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) { @@ -3359,7 +3478,7 @@ print_renameat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_statfs static void -print_statfs(void *cpu_env, const struct syscallname *name, +print_statfs(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) { @@ -3372,7 +3491,7 @@ print_statfs(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_statfs64 static void -print_statfs64(void *cpu_env, const struct syscallname *name, +print_statfs64(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) { @@ -3385,7 +3504,7 @@ print_statfs64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_symlink static void -print_symlink(void *cpu_env, const struct syscallname *name, +print_symlink(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) { @@ -3398,7 +3517,7 @@ print_symlink(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_symlinkat static void -print_symlinkat(void *cpu_env, const struct syscallname *name, +print_symlinkat(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) { @@ -3412,7 +3531,7 @@ print_symlinkat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mount static void -print_mount(void *cpu_env, const struct syscallname *name, +print_mount(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) { @@ -3428,7 +3547,7 @@ print_mount(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_umount static void -print_umount(void *cpu_env, const struct syscallname *name, +print_umount(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) { @@ -3440,7 +3559,7 @@ print_umount(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_umount2 static void -print_umount2(void *cpu_env, const struct syscallname *name, +print_umount2(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) { @@ -3453,7 +3572,7 @@ print_umount2(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_unlink static void -print_unlink(void *cpu_env, const struct syscallname *name, +print_unlink(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) { @@ -3465,7 +3584,7 @@ print_unlink(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_unlinkat static void -print_unlinkat(void *cpu_env, const struct syscallname *name, +print_unlinkat(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) { @@ -3479,7 +3598,7 @@ print_unlinkat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_unshare static void -print_unshare(void *cpu_env, const struct syscallname *name, +print_unshare(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) { @@ -3489,9 +3608,24 @@ print_unshare(void *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(void *cpu_env, const struct syscallname *name, +print_utime(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) { @@ -3504,7 +3638,7 @@ print_utime(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_utimes static void -print_utimes(void *cpu_env, const struct syscallname *name, +print_utimes(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) { @@ -3517,7 +3651,7 @@ print_utimes(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_utimensat static void -print_utimensat(void *cpu_env, const struct syscallname *name, +print_utimensat(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) { @@ -3532,7 +3666,7 @@ print_utimensat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2) static void -print_mmap(void *cpu_env, const struct syscallname *name, +print_mmap(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) { @@ -3550,7 +3684,7 @@ print_mmap(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mprotect static void -print_mprotect(void *cpu_env, const struct syscallname *name, +print_mprotect(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) { @@ -3564,7 +3698,7 @@ print_mprotect(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_munmap static void -print_munmap(void *cpu_env, const struct syscallname *name, +print_munmap(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) { @@ -3576,56 +3710,61 @@ print_munmap(void *cpu_env, const struct syscallname *name, #endif #ifdef TARGET_NR_futex -static void print_futex_op(abi_long tflag, int last) -{ -#define print_op(val) \ -if( cmd == val ) { \ - qemu_log(#val); \ - return; \ -} - - int cmd = (int)tflag; -#ifdef FUTEX_PRIVATE_FLAG - if (cmd & FUTEX_PRIVATE_FLAG) { - qemu_log("FUTEX_PRIVATE_FLAG|"); - cmd &= ~FUTEX_PRIVATE_FLAG; - } -#endif -#ifdef FUTEX_CLOCK_REALTIME - if (cmd & FUTEX_CLOCK_REALTIME) { - qemu_log("FUTEX_CLOCK_REALTIME|"); - cmd &= ~FUTEX_CLOCK_REALTIME; +static void print_futex_op(int cmd, int last) +{ + 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 + }; + + 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 - 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 -print_futex(void *cpu_env, const struct syscallname *name, +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); @@ -3634,7 +3773,7 @@ print_futex(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_kill static void -print_kill(void *cpu_env, const struct syscallname *name, +print_kill(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) { @@ -3647,7 +3786,7 @@ print_kill(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_tkill static void -print_tkill(void *cpu_env, const struct syscallname *name, +print_tkill(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) { @@ -3660,7 +3799,7 @@ print_tkill(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_tgkill static void -print_tgkill(void *cpu_env, const struct syscallname *name, +print_tgkill(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) { @@ -3674,7 +3813,7 @@ print_tgkill(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_statx static void -print_statx(void *cpu_env, const struct syscallname *name, +print_statx(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) { @@ -3690,7 +3829,7 @@ print_statx(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ioctl static void -print_ioctl(void *cpu_env, const struct syscallname *name, +print_ioctl(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) { @@ -3775,55 +3914,74 @@ static int nsyscalls = ARRAY_SIZE(scnames); * The public interface to this module. */ void -print_syscall(void *cpu_env, int num, +print_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, 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) + +#define BLKGETSIZE64 _IOR(0x12,114,size_t) +#define BLKDISCARD _IO(0x12,119) +#define BLKIOMIN _IO(0x12,120) +#define BLKIOOPT _IO(0x12,121) +#define BLKALIGNOFF _IO(0x12,122) +#define BLKPBSZGET _IO(0x12,123) +#define BLKDISCARDZEROES _IO(0x12,124) +#define BLKSECDISCARD _IO(0x12,125) +#define BLKROTATIONAL _IO(0x12,126) +#define BLKZEROOUT _IO(0x12,127) + +#define FIBMAP _IO(0x00,1) +#define FIGETBSZ _IO(0x00,2) + +struct file_clone_range { + __s64 src_fd; + __u64 src_offset; + __u64 src_length; + __u64 dest_offset; +}; + +#define FICLONE _IOW(0x94, 9, int) +#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) + +#else #include +#endif #include #if defined(CONFIG_FIEMAP) #include @@ -140,6 +183,7 @@ #include "qapi/error.h" #include "fd-trans.h" #include "tcg/tcg.h" +#include "cpu_loop-common.h" #ifndef CLONE_IO #define CLONE_IO 0x80000000 /* Clone io context */ @@ -320,8 +364,12 @@ _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif -#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) -_syscall1(int,set_tid_address,int *,tidptr) +#if defined(__NR_close_range) && defined(TARGET_NR_close_range) +#define __NR_sys_close_range __NR_close_range +_syscall3(int,sys_close_range,int,first,int,last,int,flags) +#ifndef CLOSE_RANGE_CLOEXEC +#define CLOSE_RANGE_CLOEXEC (1U << 2) +#endif #endif #if defined(__NR_futex) _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, @@ -331,6 +379,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); @@ -500,20 +558,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) @@ -538,7 +601,7 @@ static inline int target_to_host_errno(int target_errno) } } -static inline abi_long get_errno(abi_long ret) +abi_long get_errno(abi_long ret) { if (ret == -1) return -host_to_target_errno(errno); @@ -1053,8 +1116,10 @@ static inline int target_to_host_resource(int code) return RLIMIT_RSS; case TARGET_RLIMIT_RTPRIO: return RLIMIT_RTPRIO; +#ifdef RLIMIT_RTTIME case TARGET_RLIMIT_RTTIME: return RLIMIT_RTTIME; +#endif case TARGET_RLIMIT_SIGPENDING: return RLIMIT_SIGPENDING; case TARGET_RLIMIT_STACK: @@ -1587,21 +1652,12 @@ static abi_long do_ppoll(abi_long arg1, abi_long arg2, abi_long arg3, } #endif -static abi_long do_pipe2(int host_pipe[], int flags) -{ -#ifdef CONFIG_PIPE2 - return pipe2(host_pipe, flags); -#else - return -ENOSYS; -#endif -} - -static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, +static abi_long do_pipe(CPUArchState *cpu_env, abi_ulong pipedes, int flags, int is_pipe2) { int host_pipe[2]; abi_long ret; - ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe); + ret = pipe2(host_pipe, flags); if (is_error(ret)) return get_errno(ret); @@ -1610,22 +1666,22 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, pipe syscall, but didn't replicate this into the pipe2 syscall. */ if (!is_pipe2) { #if defined(TARGET_ALPHA) - ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1]; + cpu_env->ir[IR_A4] = host_pipe[1]; return host_pipe[0]; #elif defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; + cpu_env->active_tc.gpr[3] = host_pipe[1]; return host_pipe[0]; #elif defined(TARGET_SH4) - ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; + cpu_env->gregs[1] = host_pipe[1]; return host_pipe[0]; #elif defined(TARGET_SPARC) - ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1]; + cpu_env->regwptr[1] = host_pipe[1]; return host_pipe[0]; #endif } if (put_user_s32(host_pipe[0], pipedes) - || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0]))) + || put_user_s32(host_pipe[1], pipedes + sizeof(abi_int))) return -TARGET_EFAULT; return get_errno(ret); } @@ -3297,7 +3353,8 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, if (fd_trans_host_to_target_data(fd)) { ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base, MIN(msg.msg_iov->iov_len, len)); - } else { + } + if (!is_error(ret)) { ret = host_to_target_cmsg(msgp, &msg); } if (!is_error(ret)) { @@ -5414,7 +5471,7 @@ static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp, for (i = 0; i < se->nb_fields; i++) { if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) { assert(*field_types == TYPE_PTRVOID); - target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]); + target_rt_dev_ptr = argptr + src_offsets[i]; host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]); if (*target_rt_dev_ptr != 0) { *host_rt_dev_ptr = (unsigned long)lock_user_string( @@ -6344,6 +6401,12 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) #ifndef PR_SET_SYSCALL_USER_DISPATCH # define PR_SET_SYSCALL_USER_DISPATCH 59 #endif +#ifndef PR_SME_SET_VL +# define PR_SME_SET_VL 63 +# define PR_SME_GET_VL 64 +# define PR_SME_VL_LEN_MASK 0xffff +# define PR_SME_VL_INHERIT (1 << 17) +#endif #include "target_prctl.h" @@ -6363,11 +6426,11 @@ static abi_long do_prctl_inval1(CPUArchState *env, abi_long arg2) #ifndef do_prctl_set_fp_mode #define do_prctl_set_fp_mode do_prctl_inval1 #endif -#ifndef do_prctl_get_vl -#define do_prctl_get_vl do_prctl_inval0 +#ifndef do_prctl_sve_get_vl +#define do_prctl_sve_get_vl do_prctl_inval0 #endif -#ifndef do_prctl_set_vl -#define do_prctl_set_vl do_prctl_inval1 +#ifndef do_prctl_sve_set_vl +#define do_prctl_sve_set_vl do_prctl_inval1 #endif #ifndef do_prctl_reset_keys #define do_prctl_reset_keys do_prctl_inval1 @@ -6384,6 +6447,12 @@ static abi_long do_prctl_inval1(CPUArchState *env, abi_long arg2) #ifndef do_prctl_set_unalign #define do_prctl_set_unalign do_prctl_inval1 #endif +#ifndef do_prctl_sme_get_vl +#define do_prctl_sme_get_vl do_prctl_inval0 +#endif +#ifndef do_prctl_sme_set_vl +#define do_prctl_sme_set_vl do_prctl_inval1 +#endif static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -6432,9 +6501,13 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2, case PR_SET_FP_MODE: return do_prctl_set_fp_mode(env, arg2); case PR_SVE_GET_VL: - return do_prctl_get_vl(env); + return do_prctl_sve_get_vl(env); case PR_SVE_SET_VL: - return do_prctl_set_vl(env, arg2); + return do_prctl_sve_set_vl(env, arg2); + case PR_SME_GET_VL: + return do_prctl_sme_get_vl(env); + case PR_SME_SET_VL: + return do_prctl_sme_set_vl(env, arg2); case PR_PAC_RESET_KEYS: if (arg3 || arg4 || arg5) { return -TARGET_EINVAL; @@ -7250,7 +7323,7 @@ void syscall_init(void) } #ifdef TARGET_NR_truncate64 -static inline abi_long target_truncate64(void *cpu_env, const char *arg1, +static inline abi_long target_truncate64(CPUArchState *cpu_env, const char *arg1, abi_long arg2, abi_long arg3, abi_long arg4) @@ -7264,7 +7337,7 @@ static inline abi_long target_truncate64(void *cpu_env, const char *arg1, #endif #ifdef TARGET_NR_ftruncate64 -static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, +static inline abi_long target_ftruncate64(CPUArchState *cpu_env, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4) @@ -7559,12 +7632,12 @@ static inline int target_to_host_mlockall_arg(int arg) #if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \ defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \ defined(TARGET_NR_newfstatat)) -static inline abi_long host_to_target_stat64(void *cpu_env, +static inline abi_long host_to_target_stat64(CPUArchState *cpu_env, abi_ulong target_addr, struct stat *host_st) { #if defined(TARGET_ARM) && defined(TARGET_ABI32) - if (((CPUARMState *)cpu_env)->eabi) { + if (cpu_env->eabi) { struct target_eabi_stat64 *target_st; if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) @@ -7729,15 +7802,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 @@ -7746,85 +7820,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 @@ -7961,9 +8003,9 @@ int host_to_target_waitstatus(int status) return status; } -static int open_self_cmdline(void *cpu_env, int fd) +static int open_self_cmdline(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm; int i; @@ -7978,9 +8020,9 @@ static int open_self_cmdline(void *cpu_env, int fd) return 0; } -static int open_self_maps(void *cpu_env, int fd) +static int open_self_maps(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); TaskState *ts = cpu->opaque; GSList *map_info = read_self_maps(); GSList *s; @@ -8002,7 +8044,11 @@ static int open_self_maps(void *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; @@ -8040,9 +8086,9 @@ static int open_self_maps(void *cpu_env, int fd) return 0; } -static int open_self_stat(void *cpu_env, int fd) +static int open_self_stat(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); TaskState *ts = cpu->opaque; g_autoptr(GString) buf = g_string_new(NULL); int i; @@ -8078,9 +8124,9 @@ static int open_self_stat(void *cpu_env, int fd) return 0; } -static int open_self_auxv(void *cpu_env, int fd) +static int open_self_auxv(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); TaskState *ts = cpu->opaque; abi_ulong auxv = ts->info->saved_auxv; abi_ulong len = ts->info->auxv_len; @@ -8132,7 +8178,34 @@ static int is_proc_myself(const char *filename, const char *entry) return 0; } -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \ +static void excp_dump_file(FILE *logfile, CPUArchState *env, + const char *fmt, int code) +{ + if (logfile) { + CPUState *cs = env_cpu(env); + + fprintf(logfile, fmt, code); + fprintf(logfile, "Failing executable: %s\n", exec_path); + cpu_dump_state(cs, logfile, 0); + open_self_maps(env, fileno(logfile)); + } +} + +void target_exception_dump(CPUArchState *env, const char *fmt, int code) +{ + /* dump to console */ + excp_dump_file(stderr, env, fmt, code); + + /* dump to log file */ + if (qemu_log_separate()) { + FILE *logfile = qemu_log_trylock(); + + excp_dump_file(logfile, env, fmt, code); + qemu_log_unlock(logfile); + } +} + +#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN || \ defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) static int is_proc(const char *filename, const char *entry) { @@ -8140,8 +8213,8 @@ static int is_proc(const char *filename, const char *entry) } #endif -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) -static int open_net_route(void *cpu_env, int fd) +#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN +static int open_net_route(CPUArchState *cpu_env, int fd) { FILE *fp; char *line = NULL; @@ -8186,7 +8259,7 @@ static int open_net_route(void *cpu_env, int fd) #endif #if defined(TARGET_SPARC) -static int open_cpuinfo(void *cpu_env, int fd) +static int open_cpuinfo(CPUArchState *cpu_env, int fd) { dprintf(fd, "type\t\t: sun4u\n"); return 0; @@ -8194,7 +8267,7 @@ static int open_cpuinfo(void *cpu_env, int fd) #endif #if defined(TARGET_HPPA) -static int open_cpuinfo(void *cpu_env, int fd) +static int open_cpuinfo(CPUArchState *cpu_env, int fd) { dprintf(fd, "cpu family\t: PA-RISC 1.1e\n"); dprintf(fd, "cpu\t\t: PA7300LC (PCX-L2)\n"); @@ -8206,18 +8279,18 @@ static int open_cpuinfo(void *cpu_env, int fd) #endif #if defined(TARGET_M68K) -static int open_hardware(void *cpu_env, int fd) +static int open_hardware(CPUArchState *cpu_env, int fd) { dprintf(fd, "Model:\t\tqemu-m68k\n"); return 0; } #endif -static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) +static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) { struct fake_open { const char *filename; - int (*fill)(void *cpu_env, int fd); + int (*fill)(CPUArchState *cpu_env, int fd); int (*cmp)(const char *s1, const char *s2); }; const struct fake_open *fake_open; @@ -8226,7 +8299,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, { "stat", open_self_stat, is_proc_myself }, { "auxv", open_self_auxv, is_proc_myself }, { "cmdline", open_self_cmdline, is_proc_myself }, -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN { "/proc/net/route", open_net_route, is_proc }, #endif #if defined(TARGET_SPARC) || defined(TARGET_HPPA) @@ -8239,8 +8312,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, }; if (is_proc_myself(pathname, "exe")) { - int execfd = qemu_getauxval(AT_EXECFD); - return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode); + return safe_openat(dirfd, exec_path, flags, mode); } for (fake_open = fakes; fake_open->filename; fake_open++) { @@ -8254,16 +8326,22 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, 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; @@ -8529,7 +8607,7 @@ _syscall2(int, pivot_root, const char *, new_root, const char *, put_old) * of syscall results, can be performed. * All errnos that do_syscall() returns must be -TARGET_. */ -static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, +static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) @@ -8653,10 +8731,51 @@ static abi_long do_syscall1(void *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, *puinfo; + + if (arg3) { + 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); + puinfo = &uinfo; + } else { + puinfo = NULL; + } + ret = get_errno(pidfd_send_signal(arg1, target_to_host_signal(arg2), + puinfo, 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); return get_errno(close(arg1)); +#if defined(__NR_close_range) && defined(TARGET_NR_close_range) + case TARGET_NR_close_range: + ret = get_errno(sys_close_range(arg1, arg2, arg3)); + if (ret == 0 && !(arg3 & CLOSE_RANGE_CLOEXEC)) { + abi_long fd, maxfd; + maxfd = MIN(arg2, target_fd_max); + for (fd = arg1; fd < maxfd; fd++) { + fd_trans_unregister(fd); + } + } + return ret; +#endif case TARGET_NR_brk: return do_brk(arg1); @@ -8813,7 +8932,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, * before the execve completes and makes it the other * program's problem. */ - ret = get_errno(safe_execve(p, argp, envp)); + if (is_proc_myself(p, "exe")) { + ret = get_errno(safe_execve(exec_path, argp, envp)); + } else { + ret = get_errno(safe_execve(p, argp, envp)); + } unlock_user(p, arg1, 0); goto execve_end; @@ -8890,7 +9013,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA) /* Alpha specific */ case TARGET_NR_getxpid: - ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid(); + cpu_env->ir[IR_A4] = getppid(); return get_errno(getpid()); #endif #ifdef TARGET_NR_getpid @@ -9068,6 +9191,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg2, 0); return ret; #endif +#if defined(TARGET_NR_faccessat2) + case TARGET_NR_faccessat2: + if (!(p = lock_user_string(arg2))) { + return -TARGET_EFAULT; + } + ret = get_errno(faccessat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); + return ret; +#endif #ifdef TARGET_NR_nice /* not on alpha */ case TARGET_NR_nice: return get_errno(nice(arg1)); @@ -9413,7 +9545,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { host_to_target_old_sigset(&mask, &oldset); ret = mask; - ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */ + cpu_env->ir[IR_V0] = 0; /* force no error */ } #else sigset_t set, oldset, *set_ptr; @@ -9660,7 +9792,7 @@ static abi_long do_syscall1(void *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: @@ -9673,7 +9805,7 @@ static abi_long do_syscall1(void *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 @@ -9882,11 +10014,22 @@ static abi_long do_syscall1(void *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)); } @@ -10033,7 +10176,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } #ifdef TARGET_ALPHA /* Return value is the unbiased priority. Signal no error. */ - ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; + cpu_env->ir[IR_V0] = 0; #else /* Return value is a biased priority to avoid negative numbers. */ ret = 20 - ret; @@ -11413,7 +11556,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, { uid_t euid; euid=geteuid(); - ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid; + cpu_env->ir[IR_A4]=euid; } return get_errno(getuid()); #endif @@ -11423,7 +11566,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, { uid_t egid; egid=getegid(); - ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid; + cpu_env->ir[IR_A4]=egid; } return get_errno(getgid()); #endif @@ -11435,7 +11578,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, case TARGET_GSI_IEEE_FP_CONTROL: { uint64_t fpcr = cpu_alpha_load_fpcr(cpu_env); - uint64_t swcr = ((CPUAlphaState *)cpu_env)->swcr; + uint64_t swcr = cpu_env->swcr; swcr &= ~SWCR_STATUS_MASK; swcr |= (fpcr >> 35) & SWCR_STATUS_MASK; @@ -11477,8 +11620,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, * could be queried. Therefore, we store the status * bits only in FPCR. */ - ((CPUAlphaState *)cpu_env)->swcr - = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK); + cpu_env->swcr = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK); fpcr = cpu_alpha_load_fpcr(cpu_env); fpcr &= ((uint64_t)FPCR_DYN_MASK << 32); @@ -11502,7 +11644,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, fex = alpha_ieee_fpcr_to_swcr(fpcr); fex = exc & ~fex; fex >>= SWCR_STATUS_TO_EXCSUM_SHIFT; - fex &= ((CPUArchState *)cpu_env)->swcr; + fex &= (cpu_env)->swcr; /* Update the hardware fpcr. */ fpcr |= alpha_ieee_swcr_to_fpcr(exc); @@ -11534,9 +11676,8 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = si_code; - info._sifields._sigfault._addr - = ((CPUArchState *)cpu_env)->pc; - queue_signal((CPUArchState *)cpu_env, info.si_signo, + info._sifields._sigfault._addr = (cpu_env)->pc; + queue_signal(cpu_env, info.si_signo, QEMU_SI_FAULT, &info); } ret = 0; @@ -11742,7 +11883,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return -host_to_target_errno(ret); #endif -#if TARGET_ABI_BITS == 32 +#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32) #ifdef TARGET_NR_fadvise64_64 case TARGET_NR_fadvise64_64: @@ -11807,11 +11948,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_madvise case TARGET_NR_madvise: - /* A straight passthrough may not be safe because qemu sometimes - turns private file-backed mappings into anonymous mappings. - This will break MADV_DONTNEED. - This is a hint, so ignoring and returning success is ok. */ - return 0; + return target_madvise(arg1, arg2, arg3); #endif #ifdef TARGET_NR_fcntl64 case TARGET_NR_fcntl64: @@ -11822,7 +11959,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, to_flock64_fn *copyto = copy_to_user_flock64; #ifdef TARGET_ARM - if (!((CPUARMState *)cpu_env)->eabi) { + if (!cpu_env->eabi) { copyfrom = copy_from_user_oabi_flock64; copyto = copy_to_user_oabi_flock64; } @@ -11873,7 +12010,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return get_errno(sys_gettid()); #ifdef TARGET_NR_readahead case TARGET_NR_readahead: -#if TARGET_ABI_BITS == 32 +#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32) if (regpairs_aligned(cpu_env, num)) { arg2 = arg3; arg3 = arg4; @@ -12050,13 +12187,13 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: #if defined(TARGET_MIPS) - ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1; + cpu_env->active_tc.CP0_UserLocal = arg1; return 0; #elif defined(TARGET_CRIS) if (arg1 & 0xff) ret = -TARGET_EINVAL; else { - ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1; + cpu_env->pregs[PR_PID] = arg1; ret = 0; } return ret; @@ -12200,9 +12337,14 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } #endif -#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) +#if defined(TARGET_NR_set_tid_address) case TARGET_NR_set_tid_address: - return get_errno(set_tid_address((int *)g2h(cpu, arg1))); + { + TaskState *ts = cpu->opaque; + ts->child_tidptr = arg1; + /* do not call host set_tid_address() syscall, instead return tid() */ + return get_errno(sys_gettid()); + } #endif case TARGET_NR_tkill: @@ -12289,11 +12431,11 @@ static abi_long do_syscall1(void *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) @@ -12560,7 +12702,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #endif /* CONFIG_EVENTFD */ #if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate) case TARGET_NR_fallocate: -#if TARGET_ABI_BITS == 32 +#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32) ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4), target_offset64(arg5, arg6))); #else @@ -12571,7 +12713,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #if defined(CONFIG_SYNC_FILE_RANGE) #if defined(TARGET_NR_sync_file_range) case TARGET_NR_sync_file_range: -#if TARGET_ABI_BITS == 32 +#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32) #if defined(TARGET_MIPS) ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), target_offset64(arg5, arg6), arg7)); @@ -12593,7 +12735,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, case TARGET_NR_arm_sync_file_range: #endif /* This is like sync_file_range but the arguments are reordered */ -#if TARGET_ABI_BITS == 32 +#if TARGET_ABI_BITS == 32 && !defined(TARGET_ABI_MIPSN32) ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), target_offset64(arg5, arg6), arg2)); #else @@ -12783,8 +12925,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = arg6; - queue_signal((CPUArchState *)cpu_env, info.si_signo, - QEMU_SI_FAULT, &info); + queue_signal(cpu_env, info.si_signo, QEMU_SI_FAULT, &info); ret = 0xdeadbeef; } @@ -12819,15 +12960,18 @@ static abi_long do_syscall1(void *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; } } @@ -12963,7 +13107,7 @@ static abi_long do_syscall1(void *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; } @@ -13153,7 +13297,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return ret; } -abi_long do_syscall(void *cpu_env, int num, abi_long arg1, +abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 4587b62ac978..77864de57fb6 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -74,7 +74,7 @@ || defined(TARGET_M68K) || defined(TARGET_CRIS) \ || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \ || defined(TARGET_NIOS2) || defined(TARGET_RISCV) \ - || defined(TARGET_XTENSA) + || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -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 @@ -2196,6 +2196,10 @@ struct target_stat64 { uint64_t st_ino; }; +#elif defined(TARGET_LOONGARCH64) + +/* LoongArch no newfstatat/fstat syscall. */ + #else #error unsupported CPU #endif @@ -2258,7 +2262,8 @@ struct target_statfs64 { }; #elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \ - defined(TARGET_RISCV)) && !defined(TARGET_ABI32) + defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64)) && \ + !defined(TARGET_ABI32) struct target_statfs { abi_long f_type; abi_long f_bsize; @@ -2695,6 +2700,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/uname.c b/linux-user/uname.c index 1d82608c100f..32f71f24920d 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -21,7 +21,6 @@ #include "qemu.h" #include "user-internals.h" -//#include "qemu-common.h" #include "uname.h" /* return highest utsname machine name for emulated instruction set @@ -29,7 +28,7 @@ * NB: the default emulated CPU ("any") might not match any existing CPU, e.g. * on ARM it has all features turned on, so there is no perfect arch string to * return here */ -const char *cpu_to_uname_machine(void *cpu_env) +const char *cpu_to_uname_machine(CPUArchState *cpu_env) { #if defined(TARGET_ARM) && !defined(TARGET_AARCH64) @@ -41,7 +40,7 @@ const char *cpu_to_uname_machine(void *cpu_env) /* in theory, endianness is configurable on some ARM CPUs, but this isn't * used in user mode emulation */ -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN #define utsname_suffix "b" #else #define utsname_suffix "l" @@ -55,7 +54,7 @@ const char *cpu_to_uname_machine(void *cpu_env) return "armv5te" utsname_suffix; #elif defined(TARGET_I386) && !defined(TARGET_X86_64) /* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */ - CPUState *cpu = env_cpu((CPUX86State *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); int family = object_property_get_int(OBJECT(cpu), "family", NULL); if (family == 4) { return "i486"; diff --git a/linux-user/uname.h b/linux-user/uname.h index 4503094211f9..4ae563f46c29 100644 --- a/linux-user/uname.h +++ b/linux-user/uname.h @@ -4,7 +4,7 @@ #include #include -const char *cpu_to_uname_machine(void *cpu_env); +const char *cpu_to_uname_machine(CPUArchState *cpu_env); int sys_uname(struct new_utsname *buf); #endif /* UNAME_H */ diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index ee152ccfaa8f..0280e76addda 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -59,12 +59,13 @@ int info_is_fdpic(struct image_info *info); void target_set_brk(abi_ulong new_brk); void syscall_init(void); -abi_long do_syscall(void *cpu_env, int num, abi_long arg1, +abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8); extern __thread CPUState *thread_cpu; -void QEMU_NORETURN cpu_loop(CPUArchState *env); +G_NORETURN void cpu_loop(CPUArchState *env); +abi_long get_errno(abi_long ret); const char *target_strerror(int err); int get_osversion(void); void init_qemu_uname_release(void); @@ -115,7 +116,7 @@ static inline int is_error(abi_long ret) #if (TARGET_ABI_BITS == 32) && !defined(TARGET_ABI_MIPSN32) static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN return ((uint64_t)word0 << 32) | word1; #else return ((uint64_t)word1 << 32) | word0; @@ -132,22 +133,22 @@ void print_termios(void *arg); /* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ #ifdef TARGET_ARM -static inline int regpairs_aligned(void *cpu_env, int num) +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { - return ((((CPUARMState *)cpu_env)->eabi) == 1) ; + return cpu_env->eabi == 1; } #elif defined(TARGET_MIPS) && defined(TARGET_ABI_MIPSO32) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #elif defined(TARGET_PPC) && !defined(TARGET_PPC64) /* * SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs * of registers which translates to the same as ARM/MIPS, because we start with * r3 as arg1 */ -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #elif defined(TARGET_SH4) /* SH4 doesn't align register pairs, except for p{read,write}64 */ -static inline int regpairs_aligned(void *cpu_env, int num) +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { switch (num) { case TARGET_NR_pread64: @@ -159,11 +160,11 @@ static inline int regpairs_aligned(void *cpu_env, int num) } } #elif defined(TARGET_XTENSA) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #elif defined(TARGET_HEXAGON) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #else -static inline int regpairs_aligned(void *cpu_env, int num) { return 0; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 0; } #endif /** diff --git a/linux-user/user-mmap.h b/linux-user/user-mmap.h index d1dec99c0249..480ce1c11487 100644 --- a/linux-user/user-mmap.h +++ b/linux-user/user-mmap.h @@ -25,6 +25,7 @@ int target_munmap(abi_ulong start, abi_ulong len); abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_size, unsigned long flags, abi_ulong new_addr); +abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice); extern unsigned long last_brk; extern abi_ulong mmap_next_start; abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong); diff --git a/linux-user/x86_64/target_elf.h b/linux-user/x86_64/target_elf.h index 7b76a90de880..3f628f8d6619 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 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/x86_64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 06d91a37ecee..f5fb8b5cbebe 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -130,7 +130,7 @@ static int setup_sigcontext(struct target_rt_sigframe *frame, static void install_sigtramp(uint8_t *tramp) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ __put_user(0x22, &tramp[0]); __put_user(0x0a, &tramp[1]); diff --git a/linux-user/xtensa/target_mman.h b/linux-user/xtensa/target_mman.h new file mode 100644 index 000000000000..e7ba6070fe7c --- /dev/null +++ b/linux-user/xtensa/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/xtensa/target_structs.h b/linux-user/xtensa/target_structs.h index 9cde6844b8fc..cb1b3411cf08 100644 --- a/linux-user/xtensa/target_structs.h +++ b/linux-user/xtensa/target_structs.h @@ -15,7 +15,7 @@ struct target_ipc_perm { struct target_semid64_ds { struct target_ipc_perm sem_perm; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN abi_ulong __unused1; abi_ulong sem_otime; abi_ulong __unused2; diff --git a/meson b/meson index 12f9f04ba0de..3a9b285a55b9 160000 --- a/meson +++ b/meson @@ -1 +1 @@ -Subproject commit 12f9f04ba0decfda425dbbf9a501084c153a2d18 +Subproject commit 3a9b285a55b91b53b2acda987192274352ecb5be diff --git a/meson.build b/meson.build index 861de93c4f58..175517eafde8 100644 --- a/meson.build +++ b/meson.build @@ -1,19 +1,21 @@ -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'], + 'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'], version: files('VERSION')) add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true) add_test_setup('slow', exclude_suites: ['thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow']) add_test_setup('thorough', env: ['G_TEST_SLOW=1', 'SPEED=thorough']) +meson.add_postconf_script(find_program('scripts/symlink-install-tree.py')) + not_found = dependency('', required: false) keyval = import('keyval') ss = import('sourceset') fs = import('fs') +targetos = host_machine.system() sh = find_program('sh') -cc = meson.get_compiler('c') config_host = keyval.load(meson.current_build_dir() / 'config-host.mak') enable_modules = 'CONFIG_MODULES' in config_host enable_static = 'CONFIG_STATIC' in config_host @@ -21,6 +23,18 @@ enable_static = 'CONFIG_STATIC' in config_host # Allow both shared and static libraries unless --enable-static static_kwargs = enable_static ? {'static': true} : {} +cc = meson.get_compiler('c') +all_languages = ['c'] +if add_languages('cpp', required: false, native: false) + all_languages += ['cpp'] + cxx = meson.get_compiler('cpp') +endif +if targetos == 'darwin' and \ + add_languages('objc', required: get_option('cocoa'), native: false) + all_languages += ['objc'] + objc = meson.get_compiler('objc') +endif + # Temporary directory used for files created while # configure runs. Since it is in the build directory # we can safely blow away any previous version of it @@ -47,7 +61,7 @@ qapi_trace_events = [] bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin'] supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', - 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc', 'sparc64'] + 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64'] cpu = host_machine.cpu_family() @@ -56,8 +70,6 @@ if cpu in ['riscv32', 'riscv64'] cpu = 'riscv' endif -targetos = host_machine.system() - target_dirs = config_host['TARGET_DIRS'].split() have_linux_user = false have_bsd_user = false @@ -73,7 +85,7 @@ have_tools = get_option('tools') \ .allowed() have_ga = get_option('guest_agent') \ .disable_auto_if(not have_system and not have_tools) \ - .require(targetos in ['sunos', 'linux', 'windows'], + .require(targetos in ['sunos', 'linux', 'windows', 'freebsd', 'netbsd', 'openbsd'], error_message: 'unsupported OS for QEMU guest agent') \ .allowed() have_block = have_system or have_tools @@ -163,22 +175,39 @@ if 'dtrace' in get_option('trace_backends') # semaphores are linked into the main binary and not the module's shared # object. add_global_arguments('-DSTAP_SDT_V2', - native: false, language: ['c', 'cpp', 'objc']) + native: false, language: all_languages) endif endif +if get_option('iasl') == '' + iasl = find_program('iasl', required: false) +else + iasl = find_program(get_option('iasl'), required: true) +endif + ################## # Compiler flags # ################## 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') + qemu_ldflags += cc.get_supported_link_arguments('-Wl,--dynamicbase', '-Wl,--high-entropy-va') +endif + if get_option('gprof') qemu_cflags += ['-p'] - qemu_cxxflags += ['-p'] qemu_objcflags += ['-p'] qemu_ldflags += ['-p'] endif @@ -188,16 +217,21 @@ endif if get_option('fuzzing') add_project_link_arguments(['-Wl,-T,', (meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')], - native: false, language: ['c', 'cpp', 'objc']) + native: false, language: all_languages) # Specify a filter to only instrument code that is directly related to # virtual-devices. configure_file(output: 'instrumentation-filter', input: 'scripts/oss-fuzz/instrumentation-filter-template', copy: true) - add_global_arguments( - cc.get_supported_arguments('-fsanitize-coverage-allowlist=instrumentation-filter'), - native: false, language: ['c', 'cpp', 'objc']) + + if cc.compiles('int main () { return 0; }', + name: '-fsanitize-coverage-allowlist=/dev/null', + args: ['-fsanitize-coverage-allowlist=/dev/null', + '-fsanitize-coverage=trace-pc'] ) + add_global_arguments('-fsanitize-coverage-allowlist=instrumentation-filter', + native: false, language: all_languages) + endif if get_option('fuzzing_engine') == '' # Add CFLAGS to tell clang to add fuzzer-related instrumentation to all the @@ -205,9 +239,9 @@ if get_option('fuzzing') # everything with fsanitize=fuzzer-no-link. Otherwise, the linker will be # unable to bind the fuzzer-related callbacks added by instrumentation. add_global_arguments('-fsanitize=fuzzer-no-link', - native: false, language: ['c', 'cpp', 'objc']) + native: false, language: all_languages) add_global_link_arguments('-fsanitize=fuzzer-no-link', - native: false, language: ['c', 'cpp', 'objc']) + native: false, language: all_languages) # For the actual fuzzer binaries, we need to link against the libfuzzer # library. They need to be configurable, to support OSS-Fuzz fuzz_exe_ldflags = ['-fsanitize=fuzzer'] @@ -218,34 +252,49 @@ if get_option('fuzzing') endif 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']) -add_global_link_arguments(qemu_ldflags, native: false, language: ['c', 'cpp', 'objc']) +# Check that the C++ compiler exists and works with the C compiler. +link_language = 'c' +linker = cc +qemu_cxxflags = [] +if 'cpp' in all_languages + 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 + + 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: all_languages) +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') if targetos == 'linux' add_project_arguments('-isystem', meson.current_source_dir() / 'linux-headers', '-isystem', 'linux-headers', - language: ['c', 'cpp']) + language: all_languages) endif add_project_arguments('-iquote', '.', '-iquote', meson.current_source_dir(), '-iquote', meson.current_source_dir() / 'include', - '-iquote', meson.current_source_dir() / 'disas/libvixl', - 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 + language: all_languages) sparse = find_program('cgcc', required: get_option('sparse')) if sparse.found() @@ -294,10 +343,36 @@ multiprocess_allowed = get_option('multiprocess') \ .require(targetos == 'linux', error_message: 'Multiprocess QEMU is supported only on Linux') \ .allowed() +vfio_user_server_allowed = get_option('vfio_user_server') \ + .require(targetos == 'linux', error_message: 'vfio-user server is supported only on Linux') \ + .allowed() + have_tpm = get_option('tpm') \ .require(targetos != 'windows', error_message: 'TPM emulation only available on POSIX systems') \ .allowed() +# vhost +have_vhost_user = get_option('vhost_user') \ + .disable_auto_if(targetos != 'linux') \ + .require(targetos != 'windows', + error_message: 'vhost-user is not available on Windows').allowed() +have_vhost_vdpa = get_option('vhost_vdpa') \ + .require(targetos == 'linux', + error_message: 'vhost-vdpa is only available on Linux').allowed() +have_vhost_kernel = get_option('vhost_kernel') \ + .require(targetos == 'linux', + error_message: 'vhost-kernel is only available on Linux').allowed() +have_vhost_user_crypto = get_option('vhost_crypto') \ + .require(have_vhost_user, + error_message: 'vhost-crypto requires vhost-user to be enabled').allowed() + +have_vhost = have_vhost_user or have_vhost_vdpa or have_vhost_kernel + +have_vhost_net_user = have_vhost_user and get_option('vhost_net').allowed() +have_vhost_net_vdpa = have_vhost_vdpa and get_option('vhost_net').allowed() +have_vhost_net_kernel = have_vhost_kernel and get_option('vhost_net').allowed() +have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_vdpa + # Target-specific libraries and flags libm = cc.find_library('m', required: false) threads = dependency('threads') @@ -312,10 +387,12 @@ nvmm =not_found hvf = not_found midl = not_found widl = not_found +pathcch = not_found host_dsosuf = '.so' if targetos == 'windows' midl = find_program('midl', required: false) widl = find_program('widl', required: false) + pathcch = cc.find_library('pathcch') socket = cc.find_library('ws2_32') winmm = cc.find_library('winmm') @@ -348,12 +425,6 @@ accelerators = [] if get_option('kvm').allowed() and targetos == 'linux' accelerators += 'CONFIG_KVM' endif -if get_option('xen').allowed() and 'CONFIG_XEN_BACKEND' in config_host - accelerators += 'CONFIG_XEN' - have_xen_pci_passthrough = get_option('xen_pci_passthrough').allowed() and targetos == 'linux' -else - have_xen_pci_passthrough = false -endif if get_option('whpx').allowed() and targetos == 'windows' if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64' error('WHPX requires 64-bit host') @@ -399,15 +470,14 @@ if get_option('tcg').allowed() endif if get_option('tcg_interpreter') tcg_arch = 'tci' - elif host_arch == 'sparc64' - tcg_arch = 'sparc' + config_host += { 'CONFIG_TCG_INTERPRETER': 'y' } elif host_arch == 'x86_64' tcg_arch = 'i386' elif host_arch == 'ppc64' tcg_arch = 'ppc' endif add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, - language: ['c', 'cpp', 'objc']) + language: all_languages) accelerators += 'CONFIG_TCG' config_host += { 'CONFIG_TCG': 'y' } @@ -425,13 +495,6 @@ endif if 'CONFIG_WHPX' not in accelerators and get_option('whpx').enabled() error('WHPX not available on this platform') endif -if not have_xen_pci_passthrough and get_option('xen_pci_passthrough').enabled() - if 'CONFIG_XEN' in accelerators - error('Xen PCI passthrough not available on this platform') - else - error('Xen PCI passthrough requested but Xen not enabled') - endif -endif ################ # Dependencies # @@ -440,19 +503,48 @@ endif # The path to glib.h is added to all compilation commands. This was # grandfathered in from the QEMU Makefiles. add_project_arguments(config_host['GLIB_CFLAGS'].split(), - native: false, language: ['c', 'cpp', 'objc']) + native: false, language: all_languages) glib = declare_dependency(compile_args: config_host['GLIB_CFLAGS'].split(), link_args: config_host['GLIB_LIBS'].split(), - version: config_host['GLIB_VERSION']) + version: config_host['GLIB_VERSION'], + variables: { + 'bindir': config_host['GLIB_BINDIR'], + }) # override glib dep with the configure results (for subprojects) meson.override_dependency('glib-2.0', glib) gio = not_found -if 'CONFIG_GIO' in config_host - gio = declare_dependency(compile_args: config_host['GIO_CFLAGS'].split(), - link_args: config_host['GIO_LIBS'].split(), - version: config_host['GLIB_VERSION']) +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) + if gio.found() and not cc.links(''' + #include + int main(void) + { + g_dbus_proxy_new_sync(0, 0, 0, 0, 0, 0, 0, 0); + return 0; + }''', dependencies: [glib, gio]) + if get_option('gio').enabled() + error('The installed libgio is broken for static linking') + endif + gio = not_found + endif + if gio.found() + gdbus_codegen = find_program(gio.get_variable('gdbus_codegen'), + required: get_option('gio')) + gio_unix = dependency('gio-unix-2.0', required: get_option('gio'), + method: 'pkg-config', kwargs: static_kwargs) + gio = declare_dependency(dependencies: [gio, gio_unix], + 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') lttng = dependency('lttng-ust', required: true, version: '>= 2.1', @@ -471,12 +563,23 @@ if not get_option('linux_aio').auto() or have_block required: get_option('linux_aio'), kwargs: static_kwargs) endif + +linux_io_uring_test = ''' + #include + #include + + int main(void) { return 0; }''' + linux_io_uring = not_found if not get_option('linux_io_uring').auto() or have_block linux_io_uring = dependency('liburing', version: '>=0.3', required: get_option('linux_io_uring'), method: 'pkg-config', kwargs: static_kwargs) + if not cc.links(linux_io_uring_test) + linux_io_uring = not_found + endif endif + libnfs = not_found if not get_option('libnfs').auto() or have_block libnfs = dependency('libnfs', version: '>=1.9.3', @@ -517,19 +620,32 @@ if get_option('attr').allowed() endif endif -cocoa = dependency('appleframeworks', modules: 'Cocoa', 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') +cocoa = dependency('appleframeworks', modules: ['Cocoa', 'CoreVideo'], + required: get_option('cocoa')) + +vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet')) +if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h', + 'VMNET_BRIDGED_MODE', + dependencies: vmnet) + vmnet = not_found + if get_option('vmnet').enabled() + error('vmnet.framework API is outdated') + else + warning('vmnet.framework API is outdated, disabling') + endif endif seccomp = not_found +seccomp_has_sysrawrc = false if not get_option('seccomp').auto() or have_system or have_tools seccomp = dependency('libseccomp', version: '>=2.3.0', required: get_option('seccomp'), method: 'pkg-config', kwargs: static_kwargs) + if seccomp.found() + seccomp_has_sysrawrc = cc.has_header_symbol('seccomp.h', + 'SCMP_FLTATR_API_SYSRAWRC', + dependencies: seccomp) + endif endif libcap_ng = not_found @@ -560,6 +676,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'], @@ -598,6 +734,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 @@ -636,6 +777,13 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu required: get_option('virglrenderer'), kwargs: static_kwargs) endif +blkio = not_found +if not get_option('blkio').auto() or have_block + blkio = dependency('blkio', + method: 'pkg-config', + required: get_option('blkio'), + kwargs: static_kwargs) +endif curl = not_found if not get_option('curl').auto() or have_block curl = dependency('libcurl', version: '>=7.29.0', @@ -742,14 +890,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() @@ -838,7 +982,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 @@ -1000,16 +1144,21 @@ if not get_option('coreaudio').auto() or (targetos == 'darwin' and have_system) endif opengl = not_found -if 'CONFIG_OPENGL' in config_host - opengl = declare_dependency(compile_args: config_host['OPENGL_CFLAGS'].split(), - link_args: config_host['OPENGL_LIBS'].split()) +if not get_option('opengl').auto() or have_system or have_vhost_user_gpu + epoxy = dependency('epoxy', method: 'pkg-config', + required: get_option('opengl'), kwargs: static_kwargs) + if cc.has_header('epoxy/egl.h', dependencies: epoxy) + opengl = epoxy + elif get_option('opengl').enabled() + error('epoxy/egl.h not found') + endif endif gbm = not_found 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 @@ -1049,6 +1198,7 @@ endif # gcrypt over nettle for performance reasons. gcrypt = not_found nettle = not_found +hogweed = not_found xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() @@ -1086,10 +1236,21 @@ if not gnutls_crypto.found() endif endif +gmp = dependency('gmp', required: false, method: 'pkg-config', kwargs: static_kwargs) +if nettle.found() and gmp.found() + hogweed = dependency('hogweed', version: '>=3.4', + method: 'pkg-config', + required: get_option('nettle'), + kwargs: static_kwargs) +endif + + gtk = not_found gtkx11 = not_found vte = not_found -if not get_option('gtk').auto() or (have_system and not cocoa.found()) +have_gtk_clipboard = get_option('gtk_clipboard').enabled() + +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'), @@ -1107,6 +1268,8 @@ if not get_option('gtk').auto() or (have_system and not cocoa.found()) required: get_option('vte'), kwargs: static_kwargs) endif + elif have_gtk_clipboard + error('GTK clipboard requested, but GTK not found') endif endif @@ -1115,14 +1278,16 @@ if gtkx11.found() x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found(), kwargs: static_kwargs) endif -vnc = not_found png = not_found +if get_option('png').allowed() and have_system + png = dependency('libpng', version: '>=1.6.34', required: get_option('png'), + method: 'pkg-config', kwargs: static_kwargs) +endif +vnc = not_found jpeg = not_found sasl = not_found if get_option('vnc').allowed() and have_system vnc = declare_dependency() # dummy dependency - png = dependency('libpng', required: get_option('vnc_png'), - method: 'pkg-config', kwargs: static_kwargs) jpeg = dependency('libjpeg', required: get_option('vnc_jpeg'), method: 'pkg-config', kwargs: static_kwargs) sasl = cc.find_library('sasl2', has_headers: ['sasl/sasl.h'], @@ -1212,14 +1377,103 @@ if numa.found() and not cc.links(''' endif rdma = not_found -if 'CONFIG_RDMA' in config_host - rdma = declare_dependency(link_args: config_host['RDMA_LIBS'].split()) +if not get_option('rdma').auto() or have_system + libumad = cc.find_library('ibumad', required: get_option('rdma')) + rdma_libs = [cc.find_library('rdmacm', has_headers: ['rdma/rdma_cma.h'], + required: get_option('rdma'), + kwargs: static_kwargs), + cc.find_library('ibverbs', required: get_option('rdma'), + kwargs: static_kwargs), + libumad] + rdma = declare_dependency(dependencies: rdma_libs) + foreach lib: rdma_libs + if not lib.found() + rdma = not_found + endif + endforeach endif + xen = not_found -if 'CONFIG_XEN_BACKEND' in config_host - xen = declare_dependency(compile_args: config_host['XEN_CFLAGS'].split(), - link_args: config_host['XEN_LIBS'].split()) +if get_option('xen').enabled() or (get_option('xen').auto() and have_system) + xencontrol = dependency('xencontrol', required: false, + method: 'pkg-config', kwargs: static_kwargs) + if xencontrol.found() + xen_pc = declare_dependency(version: xencontrol.version(), + dependencies: [ + xencontrol, + # disabler: true makes xen_pc.found() return false if any is not found + dependency('xenstore', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xenforeignmemory', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xengnttab', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xenevtchn', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xendevicemodel', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + # optional, no "disabler: true" + dependency('xentoolcore', required: false, + method: 'pkg-config', kwargs: static_kwargs)]) + if xen_pc.found() + xen = xen_pc + endif + endif + if not xen.found() + xen_tests = [ '4.11.0', '4.10.0', '4.9.0', '4.8.0', '4.7.1', '4.6.0', '4.5.0', '4.2.0' ] + xen_libs = { + '4.11.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn', 'xentoolcore' ], + '4.10.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn', 'xentoolcore' ], + '4.9.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ], + '4.8.0': [ 'xenstore', 'xenctrl', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ], + '4.7.1': [ 'xenstore', 'xenctrl', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ], + '4.6.0': [ 'xenstore', 'xenctrl' ], + '4.5.0': [ 'xenstore', 'xenctrl' ], + '4.2.0': [ 'xenstore', 'xenctrl' ], + } + xen_deps = {} + foreach ver: xen_tests + # cache the various library tests to avoid polluting the logs + xen_test_deps = [] + foreach l: xen_libs[ver] + if l not in xen_deps + xen_deps += { l: cc.find_library(l, required: false) } + endif + xen_test_deps += xen_deps[l] + endforeach + + # Use -D to pick just one of the test programs in scripts/xen-detect.c + xen_version = ver.split('.') + xen_ctrl_version = xen_version[0] + \ + ('0' + xen_version[1]).substring(-2) + \ + ('0' + xen_version[2]).substring(-2) + if cc.links(files('scripts/xen-detect.c'), + args: '-DCONFIG_XEN_CTRL_INTERFACE_VERSION=' + xen_ctrl_version, + dependencies: xen_test_deps) + xen = declare_dependency(version: ver, dependencies: xen_test_deps) + break + endif + endforeach + endif + if xen.found() + accelerators += 'CONFIG_XEN' + elif get_option('xen').enabled() + error('could not compile and link Xen test program') + endif endif +have_xen_pci_passthrough = get_option('xen_pci_passthrough') \ + .require(xen.found(), + error_message: 'Xen PCI passthrough requested but Xen not enabled') \ + .require(targetos == 'linux', + error_message: 'Xen PCI passthrough not available on this platform') \ + .allowed() + + cacard = not_found if not get_option('smartcard').auto() or have_system cacard = dependency('libcacard', required: get_option('smartcard'), @@ -1232,6 +1486,12 @@ if have_system method: 'pkg-config', kwargs: static_kwargs) endif +canokey = not_found +if have_system + canokey = dependency('canokey-qemu', required: get_option('canokey'), + method: 'pkg-config', + kwargs: static_kwargs) +endif usbredir = not_found if not get_option('usb_redir').auto() or have_system usbredir = dependency('libusbredirparser-0.5', required: get_option('usb_redir'), @@ -1324,9 +1584,9 @@ has_statx_mnt_id = cc.links(statx_mnt_id_test) have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ .require(targetos == 'linux', error_message: 'vhost_user_blk_server requires linux') \ - .require('CONFIG_VHOST_USER' in config_host, + .require(have_vhost_user, error_message: 'vhost_user_blk_server requires vhost-user support') \ - .disable_auto_if(not have_system) \ + .disable_auto_if(not have_tools and not have_system) \ .allowed() if get_option('fuse').disabled() and get_option('fuse_lseek').enabled() @@ -1351,6 +1611,26 @@ if get_option('fuse_lseek').allowed() endif endif +have_libvduse = (targetos == 'linux') +if get_option('libvduse').enabled() + if targetos != 'linux' + error('libvduse requires linux') + endif +elif get_option('libvduse').disabled() + have_libvduse = false +endif + +have_vduse_blk_export = (have_libvduse and targetos == 'linux') +if get_option('vduse_blk_export').enabled() + if targetos != 'linux' + error('vduse_blk_export requires linux') + elif not have_libvduse + error('vduse_blk_export requires libvduse support') + endif +elif get_option('vduse_blk_export').disabled() + have_vduse_blk_export = false +endif + # libbpf libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config') if libbpf.found() and not cc.links(''' @@ -1382,6 +1662,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) @@ -1389,7 +1670,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 @@ -1447,21 +1728,20 @@ if get_option('cfi') error('-fno-sanitize-trap=cfi-icall is not supported by the compiler') endif endif - add_global_arguments(cfi_flags, native: false, language: ['c', 'cpp', 'objc']) - add_global_link_arguments(cfi_flags, native: false, language: ['c', 'cpp', 'objc']) + add_global_arguments(cfi_flags, native: false, language: all_languages) + add_global_link_arguments(cfi_flags, native: false, language: all_languages) 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(config_host.has_key('GDBUS_CODEGEN'), - error_message: '-display dbus requires gdbus-codegen') \ + .require(gdbus_codegen.found(), + 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') \ @@ -1476,19 +1756,39 @@ have_virtfs = get_option('virtfs') \ have_virtfs_proxy_helper = targetos != 'darwin' and have_virtfs and have_tools +if get_option('block_drv_ro_whitelist') == '' + config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '') +else + config_host_data.set('CONFIG_BDRV_RO_WHITELIST', + '"' + get_option('block_drv_ro_whitelist').replace(',', '", "') + '", ') +endif +if get_option('block_drv_rw_whitelist') == '' + config_host_data.set('CONFIG_BDRV_RW_WHITELIST', '') +else + config_host_data.set('CONFIG_BDRV_RW_WHITELIST', + '"' + get_option('block_drv_rw_whitelist').replace(',', '", "') + '", ') +endif + foreach k : get_option('trace_backends') config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true) endforeach config_host_data.set_quoted('CONFIG_TRACE_FILE', get_option('trace_file')) -if get_option('iasl') != '' - config_host_data.set_quoted('CONFIG_IASL', get_option('iasl')) +config_host_data.set_quoted('CONFIG_TLS_PRIORITY', get_option('tls_priority')) +if iasl.found() + config_host_data.set_quoted('CONFIG_IASL', iasl.full_path()) endif config_host_data.set_quoted('CONFIG_BINDIR', get_option('prefix') / get_option('bindir')) config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix')) config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir) config_host_data.set_quoted('CONFIG_QEMU_DATADIR', get_option('prefix') / qemu_datadir) config_host_data.set_quoted('CONFIG_QEMU_DESKTOPDIR', get_option('prefix') / qemu_desktopdir) -config_host_data.set_quoted('CONFIG_QEMU_FIRMWAREPATH', get_option('qemu_firmwarepath')) + +qemu_firmwarepath = '' +foreach k : get_option('qemu_firmwarepath') + qemu_firmwarepath += '"' + get_option('prefix') / k + '", ' +endforeach +config_host_data.set('CONFIG_QEMU_FIRMWAREPATH', qemu_firmwarepath) + config_host_data.set_quoted('CONFIG_QEMU_HELPERDIR', get_option('prefix') / get_option('libexecdir')) config_host_data.set_quoted('CONFIG_QEMU_ICONDIR', get_option('prefix') / qemu_icondir) config_host_data.set_quoted('CONFIG_QEMU_LOCALEDIR', get_option('prefix') / get_option('localedir')) @@ -1496,6 +1796,14 @@ config_host_data.set_quoted('CONFIG_QEMU_LOCALSTATEDIR', get_option('prefix') / config_host_data.set_quoted('CONFIG_QEMU_MODDIR', get_option('prefix') / qemu_moddir) config_host_data.set_quoted('CONFIG_SYSCONFDIR', get_option('prefix') / get_option('sysconfdir')) +if config_host.has_key('CONFIG_MODULES') + config_host_data.set('CONFIG_STAMP', run_command( + meson.current_source_dir() / 'scripts/qemu-stamp.py', + meson.project_version(), get_option('pkgversion'), '--', + meson.current_source_dir() / 'configure', + capture: true, check: true).stdout().strip()) +endif + have_slirp_smbd = get_option('slirp_smbd') \ .require(targetos != 'windows', error_message: 'Host smbd not supported on this platform.') \ .allowed() @@ -1509,6 +1817,11 @@ endif config_host_data.set('HOST_' + host_arch.to_upper(), 1) +if get_option('module_upgrades') and not enable_modules + error('Cannot enable module-upgrades as modules are not enabled') +endif +config_host_data.set('CONFIG_MODULE_UPGRADES', get_option('module_upgrades')) + config_host_data.set('CONFIG_ATTR', libattr.found()) config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools')) config_host_data.set('CONFIG_BRLAPI', brlapi.found()) @@ -1519,9 +1832,11 @@ config_host_data.set('CONFIG_LIBUDEV', libudev.found()) config_host_data.set('CONFIG_LZO', lzo.found()) config_host_data.set('CONFIG_MPATH', mpathpersist.found()) config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api) +config_host_data.set('CONFIG_BLKIO', blkio.found()) config_host_data.set('CONFIG_CURL', curl.found()) config_host_data.set('CONFIG_CURSES', curses.found()) config_host_data.set('CONFIG_GBM', gbm.found()) +config_host_data.set('CONFIG_GIO', gio.found()) config_host_data.set('CONFIG_GLUSTERFS', glusterfs.found()) if glusterfs.found() config_host_data.set('CONFIG_GLUSTERFS_XLATOR_OPT', glusterfs.version().version_compare('>=4')) @@ -1533,6 +1848,7 @@ if glusterfs.found() endif config_host_data.set('CONFIG_GTK', gtk.found()) config_host_data.set('CONFIG_VTE', vte.found()) +config_host_data.set('CONFIG_GTK_CLIPBOARD', have_gtk_clipboard) config_host_data.set('CONFIG_LIBATTR', have_old_libattr) config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found()) config_host_data.set('CONFIG_EBPF', libbpf.found()) @@ -1544,19 +1860,38 @@ config_host_data.set('CONFIG_LINUX_AIO', libaio.found()) config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found()) config_host_data.set('CONFIG_LIBPMEM', libpmem.found()) config_host_data.set('CONFIG_NUMA', numa.found()) +if numa.found() + config_host_data.set('HAVE_NUMA_HAS_PREFERRED_MANY', + cc.has_function('numa_has_preferred_many', + dependencies: numa)) +endif +config_host_data.set('CONFIG_OPENGL', opengl.found()) config_host_data.set('CONFIG_PROFILER', get_option('profiler')) config_host_data.set('CONFIG_RBD', rbd.found()) +config_host_data.set('CONFIG_RDMA', rdma.found()) config_host_data.set('CONFIG_SDL', sdl.found()) config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) config_host_data.set('CONFIG_SECCOMP', seccomp.found()) +if seccomp.found() + config_host_data.set('CONFIG_SECCOMP_SYSRAWRC', seccomp_has_sysrawrc) +endif config_host_data.set('CONFIG_SNAPPY', snappy.found()) config_host_data.set('CONFIG_TPM', have_tpm) config_host_data.set('CONFIG_USB_LIBUSB', libusb.found()) config_host_data.set('CONFIG_VDE', vde.found()) +config_host_data.set('CONFIG_VHOST_NET', have_vhost_net) +config_host_data.set('CONFIG_VHOST_NET_USER', have_vhost_net_user) +config_host_data.set('CONFIG_VHOST_NET_VDPA', have_vhost_net_vdpa) +config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel) +config_host_data.set('CONFIG_VHOST_USER', have_vhost_user) +config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto) +config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa) +config_host_data.set('CONFIG_VMNET', vmnet.found()) config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server) +config_host_data.set('CONFIG_VDUSE_BLK_EXPORT', have_vduse_blk_export) +config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) -config_host_data.set('CONFIG_VNC_PNG', png.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) @@ -1565,8 +1900,10 @@ config_host_data.set('CONFIG_KEYUTILS', keyutils.found()) config_host_data.set('CONFIG_GETTID', has_gettid) config_host_data.set('CONFIG_GNUTLS', gnutls.found()) config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found()) +config_host_data.set('CONFIG_TASN1', tasn1.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) +config_host_data.set('CONFIG_HOGWEED', hogweed.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) config_host_data.set('CONFIG_STATX', has_statx) @@ -1585,6 +1922,15 @@ config_host_data.set('CONFIG_X11', x11.found()) config_host_data.set('CONFIG_DBUS_DISPLAY', dbus_display) config_host_data.set('CONFIG_CFI', get_option('cfi')) config_host_data.set('CONFIG_SELINUX', selinux.found()) +config_host_data.set('CONFIG_XEN_BACKEND', xen.found()) +if xen.found() + # protect from xen.version() having less than three components + xen_version = xen.version().split('.') + ['0', '0'] + xen_ctrl_version = xen_version[0] + \ + ('0' + xen_version[1]).substring(-2) + \ + ('0' + xen_version[2]).substring(-2) + config_host_data.set('CONFIG_XEN_CTRL_INTERFACE_VERSION', xen_ctrl_version) +endif config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version())) config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0]) config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1]) @@ -1592,7 +1938,6 @@ config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2] config_host_data.set_quoted('CONFIG_HOST_DSOSUF', host_dsosuf) config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device) -config_host_data.set('HOST_WORDS_BIGENDIAN', host_machine.endian() == 'big') have_coroutine_pool = get_option('coroutine_pool') if get_option('debug_stack_usage') and have_coroutine_pool @@ -1605,7 +1950,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')) @@ -1617,8 +1962,12 @@ 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_CLOSE_RANGE', cc.has_function('close_range')) config_host_data.set('CONFIG_ACCEPT4', cc.has_function('accept4')) config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime')) config_host_data.set('CONFIG_DUP3', cc.has_function('dup3')) @@ -1633,20 +1982,26 @@ config_host_data.set('CONFIG_MEMALIGN', cc.has_function('memalign')) config_host_data.set('CONFIG_PPOLL', cc.has_function('ppoll')) config_host_data.set('CONFIG_PREADV', cc.has_function('preadv', prefix: '#include ')) config_host_data.set('CONFIG_PTHREAD_FCHDIR_NP', cc.has_function('pthread_fchdir_np')) -config_host_data.set('CONFIG_SEM_TIMEDWAIT', cc.has_function('sem_timedwait', dependencies: threads)) config_host_data.set('CONFIG_SENDFILE', cc.has_function('sendfile')) config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_function('unshare')) config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs')) config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range')) config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create')) config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range')) +config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs')) config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util)) config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul')) config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include ')) +if rbd.found() + config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS', + cc.has_function('rbd_namespace_exists', + dependencies: rbd, + prefix: '#include ')) +endif if rdma.found() config_host_data.set('HAVE_IBV_ADVISE_MR', cc.has_function('ibv_advise_mr', - args: config_host['RDMA_LIBS'].split(), + dependencies: rdma, prefix: '#include ')) endif @@ -1655,8 +2010,6 @@ config_host_data.set('CONFIG_BYTESWAP_H', cc.has_header_symbol('byteswap.h', 'bswap_32')) config_host_data.set('CONFIG_EPOLL_CREATE1', cc.has_header_symbol('sys/epoll.h', 'epoll_create1')) -config_host_data.set('CONFIG_HAS_ENVIRON', - cc.has_header_symbol('unistd.h', 'environ', prefix: gnu_source_prefix)) config_host_data.set('CONFIG_FALLOCATE_PUNCH_HOLE', cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_PUNCH_HOLE') and cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_KEEP_SIZE')) @@ -1686,6 +2039,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', @@ -1749,15 +2104,6 @@ config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + ''' #else int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); } #endif''')) -config_host_data.set('CONFIG_PIPE2', cc.links(gnu_source_prefix + ''' - #include - #include - - int main(void) - { - int pipefd[2]; - return pipe2(pipefd, O_CLOEXEC); - }''')) config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(gnu_source_prefix + ''' #include #include @@ -1784,7 +2130,34 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_pre pthread_create(&thread, 0, f, 0); return 0; }''', dependencies: threads)) +config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_prefix + ''' + #include + #include + + int main(void) + { + pthread_condattr_t attr + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + return 0; + }''', dependencies: threads)) +config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + ''' + #include + static void *f(void *p) { return NULL; } + int main(void) + { + int setsize = CPU_ALLOC_SIZE(64); + pthread_t thread; + cpu_set_t *cpuset; + pthread_create(&thread, 0, f, 0); + cpuset = CPU_ALLOC(64); + CPU_ZERO_S(setsize, cpuset); + pthread_setaffinity_np(thread, setsize, cpuset); + pthread_getaffinity_np(thread, setsize, cpuset); + CPU_FREE(cpuset); + return 0; + }''', dependencies: threads)) config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + ''' #include #include @@ -1804,7 +2177,7 @@ config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + ''' config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + ''' #include - int main(int argc, char *argv[]) { + int main(void) { return mlockall(MCL_FUTURE); }''')) @@ -1849,7 +2222,7 @@ config_host_data.set('HAVE_FSXATTR', cc.links(''' config_host_data.set('HAVE_BROKEN_SIZE_MAX', not cc.compiles(''' #include #include - int main(int argc, char *argv[]) { + int main(void) { return printf("%zu", SIZE_MAX); }''', args: ['-Werror'])) @@ -1911,6 +2284,32 @@ config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + ''' return getauxval(AT_HWCAP) == 0; }''')) +config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles(''' + #include + + #ifndef USBDEVFS_GET_CAPABILITIES + #error "USBDEVFS_GET_CAPABILITIES undefined" + #endif + + #ifndef USBDEVFS_DISCONNECT_CLAIM + #error "USBDEVFS_DISCONNECT_CLAIM undefined" + #endif + + int main(void) { return 0; }''')) + +have_keyring = get_option('keyring') \ + .require(targetos == 'linux', error_message: 'keyring is only available on Linux') \ + .require(cc.compiles(''' + #include + #include + #include + #include + #include + int main(void) { + return syscall(__NR_keyctl, KEYCTL_READ, 0, NULL, NULL, 0); + }'''), error_message: 'keyctl syscall not available on this system').allowed() +config_host_data.set('CONFIG_SECRET_KEYRING', have_keyring) + have_cpuid_h = cc.links(''' #include int main(void) { @@ -1940,7 +2339,7 @@ config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \ __m256i x = *(__m256i *)a; return _mm256_testz_si256(x, x); } - int main(int argc, char *argv[]) { return bar(argv[0]); } + int main(int argc, char *argv[]) { return bar(argv[argc - 1]); } '''), error_message: 'AVX2 not available').allowed()) config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ @@ -1954,9 +2353,40 @@ config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ __m512i x = *(__m512i *)a; return _mm512_test_epi64_mask(x, x); } - int main(int argc, char *argv[]) { return bar(argv[0]); } + int main(int argc, char *argv[]) { return bar(argv[argc - 1]); } '''), error_message: 'AVX512F not available').allowed()) +have_pvrdma = get_option('pvrdma') \ + .require(rdma.found(), error_message: 'PVRDMA requires OpenFabrics libraries') \ + .require(cc.compiles(gnu_source_prefix + ''' + #include + int main(void) + { + char buf = 0; + void *addr = &buf; + addr = mremap(addr, 0, 1, MREMAP_MAYMOVE | MREMAP_FIXED); + + return 0; + }'''), error_message: 'PVRDMA requires mremap').allowed() + +if have_pvrdma + config_host_data.set('LEGACY_RDMA_REG_MR', not cc.links(''' + #include + int main(void) + { + struct ibv_mr *mr; + struct ibv_pd *pd = NULL; + size_t length = 10; + uint64_t iova = 0; + int access = 0; + void *addr = NULL; + + mr = ibv_reg_mr_iova(pd, addr, length, iova, access); + ibv_dereg_mr(mr); + return 0; + }''')) +endif + if get_option('membarrier').disabled() have_membarrier = false elif targetos == 'windows' @@ -1991,25 +2421,10 @@ have_afalg = get_option('crypto_afalg') \ '''), error_message: 'AF_ALG requested but could not be detected').allowed() config_host_data.set('CONFIG_AF_ALG', have_afalg) -config_host_data.set('CONFIG_AF_VSOCK', cc.compiles(gnu_source_prefix + ''' - #include - #include - #include - #if !defined(AF_VSOCK) - # error missing AF_VSOCK flag - #endif - #include - int main(void) { - int sock, ret; - struct sockaddr_vm svm; - socklen_t len = sizeof(svm); - sock = socket(AF_VSOCK, SOCK_STREAM, 0); - ret = getpeername(sock, (struct sockaddr *)&svm, &len); - if ((ret == -1) && (errno == ENOTCONN)) { - return 0; - } - return -1; - }''')) +config_host_data.set('CONFIG_AF_VSOCK', cc.has_header_symbol( + 'linux/vm_sockets.h', 'AF_VSOCK', + prefix: '#include ', +)) have_vss = false have_vss_sdk = false # old xp/2003 SDK @@ -2022,38 +2437,24 @@ if targetos == 'windows' and link_language == 'cpp' endif config_host_data.set('HAVE_VSS_SDK', have_vss_sdk) -have_ntddscsi = false -if targetos == 'windows' - have_ntddscsi = cc.compiles(''' - #include - #include - int main(void) { - #if !defined(IOCTL_SCSI_GET_ADDRESS) - #error Missing required ioctl definitions - #endif - SCSI_ADDRESS addr = { .Lun = 0, .TargetId = 0, .PathId = 0 }; - return addr.Lun; - } -''') -endif -config_host_data.set('HAVE_NTDDSCSI', have_ntddscsi) - -ignored = ['CONFIG_QEMU_INTERP_PREFIX', # actually per-target - 'HAVE_GDB_BIN'] -arrays = ['CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] foreach k, v: config_host - if ignored.contains(k) - # do nothing - elif arrays.contains(k) - if v != '' - v = '"' + '", "'.join(v.split()) + '", ' - endif - config_host_data.set(k, v) - elif k.startswith('CONFIG_') + if k.startswith('CONFIG_') config_host_data.set(k, v == 'y' ? 1 : v) endif endforeach +# Older versions of MinGW do not import _lock_file and _unlock_file properly. +# This was fixed for v6.0.0 with commit b48e3ac8969d. +if targetos == 'windows' + config_host_data.set('HAVE__LOCK_FILE', cc.links(''' + #include + int main(void) { + _lock_file(NULL); + _unlock_file(NULL); + return 0; + }''', name: '_lock_file and _unlock_file')) +endif + ######################## # Target configuration # ######################## @@ -2069,7 +2470,6 @@ config_target_mak = {} disassemblers = { 'alpha' : ['CONFIG_ALPHA_DIS'], - 'arm' : ['CONFIG_ARM_DIS'], 'avr' : ['CONFIG_AVR_DIS'], 'cris' : ['CONFIG_CRIS_DIS'], 'hexagon' : ['CONFIG_HEXAGON_DIS'], @@ -2088,11 +2488,10 @@ disassemblers = { 'sh4' : ['CONFIG_SH4_DIS'], 'sparc' : ['CONFIG_SPARC_DIS'], 'xtensa' : ['CONFIG_XTENSA_DIS'], + 'loongarch' : ['CONFIG_LOONGARCH_DIS'], } if link_language == 'cpp' disassemblers += { - 'aarch64' : [ 'CONFIG_ARM_A64_DIS'], - 'arm' : [ 'CONFIG_ARM_DIS', 'CONFIG_ARM_A64_DIS'], 'mips' : [ 'CONFIG_MIPS_DIS', 'CONFIG_NANOMIPS_DIS'], } endif @@ -2103,15 +2502,16 @@ host_kconfig = \ (have_tpm ? ['CONFIG_TPM=y'] : []) + \ (spice.found() ? ['CONFIG_SPICE=y'] : []) + \ (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \ - ('CONFIG_OPENGL' in config_host ? ['CONFIG_OPENGL=y'] : []) + \ + (opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \ (x11.found() ? ['CONFIG_X11=y'] : []) + \ - ('CONFIG_VHOST_USER' in config_host ? ['CONFIG_VHOST_USER=y'] : []) + \ - ('CONFIG_VHOST_VDPA' in config_host ? ['CONFIG_VHOST_VDPA=y'] : []) + \ - ('CONFIG_VHOST_KERNEL' in config_host ? ['CONFIG_VHOST_KERNEL=y'] : []) + \ + (have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \ + (have_vhost_vdpa ? ['CONFIG_VHOST_VDPA=y'] : []) + \ + (have_vhost_kernel ? ['CONFIG_VHOST_KERNEL=y'] : []) + \ (have_virtfs ? ['CONFIG_VIRTFS=y'] : []) + \ ('CONFIG_LINUX' in config_host ? ['CONFIG_LINUX=y'] : []) + \ - ('CONFIG_PVRDMA' in config_host ? ['CONFIG_PVRDMA=y'] : []) + \ - (multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + (have_pvrdma ? ['CONFIG_PVRDMA=y'] : []) + \ + (multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \ + (vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ] @@ -2143,7 +2543,7 @@ foreach target : target_dirs config_target += { 'CONFIG_USER_ONLY': 'y', 'CONFIG_QEMU_INTERP_PREFIX': - config_host['CONFIG_QEMU_INTERP_PREFIX'].format(config_target['TARGET_NAME']) + get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']) } endif @@ -2152,11 +2552,6 @@ foreach target : target_dirs if sym == 'CONFIG_TCG' or target in accelerator_targets.get(sym, []) config_target += { sym: 'y' } config_all += { sym: 'y' } - if sym == 'CONFIG_TCG' and tcg_arch == 'tci' - config_target += { 'CONFIG_TCG_INTERPRETER': 'y' } - elif sym == 'CONFIG_XEN' and have_xen_pci_passthrough - config_target += { 'CONFIG_XEN_PCI_PASSTHROUGH': 'y' } - endif if target in modular_tcg config_target += { 'CONFIG_TCG_MODULAR': 'y' } else @@ -2187,6 +2582,9 @@ foreach target : target_dirs if 'TARGET_ABI_DIR' not in config_target config_target += {'TARGET_ABI_DIR': config_target['TARGET_ARCH']} endif + if 'TARGET_BIG_ENDIAN' not in config_target + config_target += {'TARGET_BIG_ENDIAN': 'n'} + endif foreach k, v: disassemblers if host_arch.startswith(k) or config_target['TARGET_BASE_ARCH'].startswith(k) @@ -2211,6 +2609,8 @@ foreach target : target_dirs config_target_data.set_quoted(k, v) elif v == 'y' config_target_data.set(k, 1) + elif v == 'n' + config_target_data.set(k, 0) else config_target_data.set(k, v) endif @@ -2262,7 +2662,7 @@ config_all += config_all_devices config_all += config_host config_all += config_all_disas config_all += { - 'CONFIG_XEN': config_host.has_key('CONFIG_XEN_BACKEND'), + 'CONFIG_XEN': xen.found(), 'CONFIG_SOFTMMU': have_system, 'CONFIG_USER_ONLY': have_user, 'CONFIG_ALL': true, @@ -2285,13 +2685,10 @@ genh += custom_target('config-poison.h', ############## capstone = not_found -capstone_opt = get_option('capstone') -if capstone_opt in ['enabled', 'auto', 'system'] - have_internal = fs.exists(meson.current_source_dir() / 'capstone/Makefile') - capstone = dependency('capstone', version: '>=4.0', +if not get_option('capstone').auto() or have_system or have_user + capstone = dependency('capstone', version: '>=3.0.5', kwargs: static_kwargs, method: 'pkg-config', - required: capstone_opt == 'system' or - capstone_opt == 'enabled' and not have_internal) + required: get_option('capstone')) # Some versions of capstone have broken pkg-config file # that reports a wrong -I path, causing the #include to @@ -2300,204 +2697,25 @@ if capstone_opt in ['enabled', 'auto', 'system'] if capstone.found() and not cc.compiles('#include ', dependencies: [capstone]) capstone = not_found - if capstone_opt == 'system' - error('system capstone requested, it does not appear to work') + if get_option('capstone').enabled() + error('capstone requested, but it does not appear to work') endif endif +endif - if capstone.found() - capstone_opt = 'system' - elif have_internal - capstone_opt = 'internal' - else - capstone_opt = 'disabled' - endif -endif -if capstone_opt == 'internal' - capstone_data = configuration_data() - capstone_data.set('CAPSTONE_USE_SYS_DYN_MEM', '1') - - capstone_files = files( - 'capstone/cs.c', - 'capstone/MCInst.c', - 'capstone/MCInstrDesc.c', - 'capstone/MCRegisterInfo.c', - 'capstone/SStream.c', - 'capstone/utils.c' - ) - - if 'CONFIG_ARM_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_ARM', '1') - capstone_files += files( - 'capstone/arch/ARM/ARMDisassembler.c', - 'capstone/arch/ARM/ARMInstPrinter.c', - 'capstone/arch/ARM/ARMMapping.c', - 'capstone/arch/ARM/ARMModule.c' - ) - endif - - # FIXME: This config entry currently depends on a c++ compiler. - # Which is needed for building libvixl, but not for capstone. - if 'CONFIG_ARM_A64_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_ARM64', '1') - capstone_files += files( - 'capstone/arch/AArch64/AArch64BaseInfo.c', - 'capstone/arch/AArch64/AArch64Disassembler.c', - 'capstone/arch/AArch64/AArch64InstPrinter.c', - 'capstone/arch/AArch64/AArch64Mapping.c', - 'capstone/arch/AArch64/AArch64Module.c' - ) - endif - - if 'CONFIG_PPC_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_POWERPC', '1') - capstone_files += files( - 'capstone/arch/PowerPC/PPCDisassembler.c', - 'capstone/arch/PowerPC/PPCInstPrinter.c', - 'capstone/arch/PowerPC/PPCMapping.c', - 'capstone/arch/PowerPC/PPCModule.c' - ) - endif - - if 'CONFIG_S390_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_SYSZ', '1') - capstone_files += files( - 'capstone/arch/SystemZ/SystemZDisassembler.c', - 'capstone/arch/SystemZ/SystemZInstPrinter.c', - 'capstone/arch/SystemZ/SystemZMapping.c', - 'capstone/arch/SystemZ/SystemZModule.c', - 'capstone/arch/SystemZ/SystemZMCTargetDesc.c' - ) - 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') - if 'CONFIG_I386_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_X86', 1) - capstone_files += files( - 'capstone/arch/X86/X86Disassembler.c', - 'capstone/arch/X86/X86DisassemblerDecoder.c', - 'capstone/arch/X86/X86ATTInstPrinter.c', - 'capstone/arch/X86/X86IntelInstPrinter.c', - 'capstone/arch/X86/X86InstPrinterCommon.c', - 'capstone/arch/X86/X86Mapping.c', - 'capstone/arch/X86/X86Module.c' - ) + if not have_internal + error('libvfio-user source not found - please pull git submodule') endif - configure_file(output: 'capstone-defs.h', configuration: capstone_data) + libvfio_user_proj = subproject('libvfio-user') - capstone_cargs = [ - # FIXME: There does not seem to be a way to completely replace the c_args - # that come from add_project_arguments() -- we can only add to them. - # So: disable all warnings with a big hammer. - '-Wno-error', '-w', - - # Include all configuration defines via a header file, which will wind up - # as a dependency on the object file, and thus changes here will result - # in a rebuild. - '-include', 'capstone-defs.h' - ] - - libcapstone = static_library('capstone', - build_by_default: false, - sources: capstone_files, - c_args: capstone_cargs, - include_directories: 'capstone/include') - capstone = declare_dependency(link_with: libcapstone, - include_directories: 'capstone/include/capstone') -endif + libvfio_user_lib = libvfio_user_proj.get_variable('libvfio_user_dep') -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 = dependency('slirp', kwargs: static_kwargs, - method: 'pkg-config', - required: slirp_opt == 'system' or - slirp_opt == 'enabled' and not have_internal) - 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) - slirp = declare_dependency(link_with: libslirp, - dependencies: slirp_deps, - include_directories: slirp_inc) - endif -endif - -# For CFI, we need to compile slirp as a static library together with qemu. -# This is because we register slirp functions as callbacks for QEMU 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. -# -# Now that slirp_opt has been defined, check if the selected slirp is compatible -# with control-flow integrity. -if get_option('cfi') and slirp_opt == 'system' - error('Control-Flow Integrity is not compatible with system-wide slirp.' \ - + ' Please configure with --enable-slirp=git') + libvfio_user_dep = declare_dependency(dependencies: [libvfio_user_lib]) endif fdt = not_found @@ -2610,7 +2828,7 @@ tracetool_depends = files( qemu_version_cmd = [find_program('scripts/qemu-version.sh'), meson.current_source_dir(), - config_host['PKGVERSION'], meson.project_version()] + get_option('pkgversion'), meson.project_version()] qemu_version = custom_target('qemu-version.h', output: 'qemu-version.h', command: qemu_version_cmd, @@ -2685,6 +2903,7 @@ trace_events_subdirs = [ 'qom', 'monitor', 'util', + 'gdbstub', ] if have_linux_user trace_events_subdirs += [ 'linux-user' ] @@ -2720,7 +2939,6 @@ if have_system 'hw/char', 'hw/display', 'hw/dma', - 'hw/hppa', 'hw/hyperv', 'hw/i2c', 'hw/i386', @@ -2786,11 +3004,17 @@ if have_system or have_user endif vhost_user = not_found -if targetos == 'linux' and 'CONFIG_VHOST_USER' in config_host +if targetos == 'linux' and have_vhost_user libvhost_user = subproject('libvhost-user') vhost_user = libvhost_user.get_variable('vhost_user_dep') endif +libvduse = not_found +if have_libvduse + libvduse_proj = subproject('libvduse') + libvduse = libvduse_proj.get_variable('libvduse_dep') +endif + # NOTE: the trace/ subdirectory needs the qapi_trace_events variable # that is filled in by qapi/. subdir('qapi') @@ -2802,6 +3026,8 @@ subdir('qom') subdir('authz') subdir('crypto') subdir('ui') +subdir('hw') +subdir('gdbstub') if enable_modules @@ -2809,6 +3035,18 @@ if enable_modules modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO') endif +qom_ss = qom_ss.apply(config_host, strict: false) +libqom = static_library('qom', qom_ss.sources() + genh, + dependencies: [qom_ss.dependencies()], + name_suffix: 'fa') +qom = declare_dependency(link_whole: libqom) + +event_loop_base = files('event-loop-base.c') +event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh, + build_by_default: true) +event_loop_base = declare_dependency(link_whole: event_loop_base, + dependencies: [qom]) + stub_ss = stub_ss.apply(config_all, strict: false) util_ss.add_all(trace_ss) @@ -2817,7 +3055,8 @@ libqemuutil = static_library('qemuutil', sources: util_ss.sources() + stub_ss.sources() + genh, dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman]) qemuutil = declare_dependency(link_with: libqemuutil, - sources: genh + version_res) + sources: genh + version_res, + dependencies: [event_loop_base]) if have_system or have_user decodetree = generator(find_program('scripts/decodetree.py'), @@ -2866,7 +3105,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: @@ -2895,7 +3134,6 @@ subdir('monitor') subdir('net') subdir('replay') subdir('semihosting') -subdir('hw') subdir('tcg') subdir('fpu') subdir('accel') @@ -2999,14 +3237,23 @@ foreach d, list : target_modules endforeach if enable_modules - modinfo_src = custom_target('modinfo.c', - output: 'modinfo.c', - input: modinfo_files, - command: [modinfo_generate, '@INPUT@'], - capture: true) - modinfo_lib = static_library('modinfo', modinfo_src) - modinfo_dep = declare_dependency(link_whole: modinfo_lib) - softmmu_ss.add(modinfo_dep) + foreach target : target_dirs + if target.endswith('-softmmu') + config_target = config_target_mak[target] + config_devices_mak = target + '-config-devices.mak' + modinfo_src = custom_target('modinfo-' + target + '.c', + output: 'modinfo-' + target + '.c', + input: modinfo_files, + command: [modinfo_generate, '--devices', config_devices_mak, '@INPUT@'], + capture: true) + + modinfo_lib = static_library('modinfo-' + target + '.c', modinfo_src) + modinfo_dep = declare_dependency(link_with: modinfo_lib) + + arch = config_target['TARGET_NAME'] == 'sparc64' ? 'sparc64' : config_target['TARGET_BASE_ARCH'] + hw_arch[arch].add(modinfo_dep) + endif + endforeach endif nm = find_program('nm') @@ -3020,13 +3267,6 @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms', capture: true, command: [undefsym, nm, '@INPUT@']) -qom_ss = qom_ss.apply(config_host, strict: false) -libqom = static_library('qom', qom_ss.sources() + genh, - dependencies: [qom_ss.dependencies()], - name_suffix: 'fa') - -qom = declare_dependency(link_whole: libqom) - authz_ss = authz_ss.apply(config_host, strict: false) libauthz = static_library('authz', authz_ss.sources() + genh, dependencies: [authz_ss.dependencies()], @@ -3079,7 +3319,7 @@ libblockdev = static_library('blockdev', blockdev_ss.sources() + genh, build_by_default: false) blockdev = declare_dependency(link_whole: [libblockdev], - dependencies: [block]) + dependencies: [block, event_loop_base]) qmp_ss = qmp_ss.apply(config_host, strict: false) libqmp = static_library('qmp', qmp_ss.sources() + genh, @@ -3091,7 +3331,7 @@ qmp = declare_dependency(link_whole: [libqmp]) libchardev = static_library('chardev', chardev_ss.sources() + genh, name_suffix: 'fa', - dependencies: [gnutls], + dependencies: chardev_ss.dependencies(), build_by_default: false) chardev = declare_dependency(link_whole: libchardev) @@ -3116,6 +3356,9 @@ foreach m : block_mods + softmmu_mods install: true, install_dir: qemu_moddir) endforeach +if emulator_modules.length() > 0 + alias_target('modules', emulator_modules) +endif softmmu_ss.add(authz, blockdev, chardev, crypto, io, qmp) common_ss.add(qom, qemuutil) @@ -3156,7 +3399,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() @@ -3173,7 +3415,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() @@ -3367,7 +3608,7 @@ if have_tools dependencies: qemuutil, install: true) - if 'CONFIG_VHOST_USER' in config_host + if have_vhost_user subdir('contrib/vhost-user-blk') subdir('contrib/vhost-user-gpu') subdir('contrib/vhost-user-input') @@ -3407,6 +3648,7 @@ if host_machine.system() == 'windows' '@OUTPUT@', get_option('prefix'), meson.current_source_dir(), + config_host['GLIB_BINDIR'], host_machine.cpu(), '--', '-DDISPLAYVERSION=' + meson.project_version(), @@ -3434,20 +3676,21 @@ endif summary_info = {} summary_info += {'Install prefix': get_option('prefix')} summary_info += {'BIOS directory': qemu_datadir} -summary_info += {'firmware path': get_option('qemu_firmwarepath')} -summary_info += {'binary directory': get_option('bindir')} -summary_info += {'library directory': get_option('libdir')} +pathsep = targetos == 'windows' ? ';' : ':' +summary_info += {'firmware path': pathsep.join(get_option('qemu_firmwarepath'))} +summary_info += {'binary directory': get_option('prefix') / get_option('bindir')} +summary_info += {'library directory': get_option('prefix') / get_option('libdir')} summary_info += {'module directory': qemu_moddir} -summary_info += {'libexec directory': get_option('libexecdir')} -summary_info += {'include directory': get_option('includedir')} -summary_info += {'config directory': get_option('sysconfdir')} +summary_info += {'libexec directory': get_option('prefix') / get_option('libexecdir')} +summary_info += {'include directory': get_option('prefix') / get_option('includedir')} +summary_info += {'config directory': get_option('prefix') / get_option('sysconfdir')} if targetos != 'windows' - summary_info += {'local state directory': get_option('localstatedir')} - summary_info += {'Manual directory': get_option('mandir')} + summary_info += {'local state directory': get_option('prefix') / get_option('localstatedir')} + summary_info += {'Manual directory': get_option('prefix') / get_option('mandir')} else summary_info += {'local state directory': 'queried at runtime'} endif -summary_info += {'Doc directory': get_option('docdir')} +summary_info += {'Doc directory': get_option('prefix') / get_option('docdir')} summary_info += {'Build directory': meson.current_build_dir()} summary_info += {'Source path': meson.current_source_dir()} summary_info += {'GIT submodules': config_host['GIT_SUBMODULES']} @@ -3462,16 +3705,12 @@ summary_info += {'sphinx-build': sphinx_build} if config_host.has_key('HAVE_GDB_BIN') summary_info += {'gdb': config_host['HAVE_GDB_BIN']} endif -if get_option('iasl') != '' - summary_info += {'iasl': get_option('iasl')} -else - summary_info += {'iasl': false} -endif +summary_info += {'iasl': iasl} 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') @@ -3485,7 +3724,7 @@ summary_info += {'block layer': have_block} summary_info += {'Install blobs': get_option('install_blobs')} summary_info += {'module support': config_host.has_key('CONFIG_MODULES')} if config_host.has_key('CONFIG_MODULES') - summary_info += {'alternative module path': config_host.has_key('CONFIG_MODULE_UPGRADES')} + summary_info += {'alternative module path': get_option('module_upgrades')} endif summary_info += {'fuzzing support': get_option('fuzzing')} if have_system @@ -3497,15 +3736,12 @@ if 'simple' in get_option('trace_backends') endif summary_info += {'D-Bus display': dbus_display} summary_info += {'QOM debugging': get_option('qom_cast_debug')} -summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNEL')} -summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} -summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')} -summary_info += {'vhost-scsi support': config_host.has_key('CONFIG_VHOST_SCSI')} -summary_info += {'vhost-vsock support': config_host.has_key('CONFIG_VHOST_VSOCK')} -summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')} +summary_info += {'vhost-kernel support': have_vhost_kernel} +summary_info += {'vhost-net support': have_vhost_net} +summary_info += {'vhost-user support': have_vhost_user} +summary_info += {'vhost-user-crypto support': have_vhost_user_crypto} summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server} -summary_info += {'vhost-user-fs support': config_host.has_key('CONFIG_VHOST_USER_FS')} -summary_info += {'vhost-vdpa support': config_host.has_key('CONFIG_VHOST_VDPA')} +summary_info += {'vhost-vdpa support': have_vhost_vdpa} summary_info += {'build guest agent': have_ga} summary(summary_info, bool_yn: true, section: 'Configurable features') @@ -3523,27 +3759,29 @@ endif if targetos == 'darwin' summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())} endif -summary_info += {'CFLAGS': ' '.join(get_option('c_args') - + ['-O' + get_option('optimization')] - + (get_option('debug') ? ['-g'] : []))} +option_cflags = (get_option('debug') ? ['-g'] : []) +if get_option('optimization') != 'plain' + option_cflags += ['-O' + get_option('optimization')] +endif +summary_info += {'CFLAGS': ' '.join(get_option('c_args') + option_cflags)} if link_language == 'cpp' - summary_info += {'CXXFLAGS': ' '.join(get_option('cpp_args') - + ['-O' + get_option('optimization')] - + (get_option('debug') ? ['-g'] : []))} + summary_info += {'CXXFLAGS': ' '.join(get_option('cpp_args') + option_cflags)} endif if targetos == 'darwin' - summary_info += {'OBJCFLAGS': ' '.join(get_option('objc_args') - + ['-O' + get_option('optimization')] - + (get_option('debug') ? ['-g'] : []))} + summary_info += {'OBJCFLAGS': ' '.join(get_option('objc_args') + option_cflags)} endif link_args = get_option(link_language + '_link_args') if link_args.length() > 0 summary_info += {'LDFLAGS': ' '.join(link_args)} endif -summary_info += {'QEMU_CFLAGS': config_host['QEMU_CFLAGS']} -summary_info += {'QEMU_CXXFLAGS': config_host['QEMU_CXXFLAGS']} -summary_info += {'QEMU_OBJCFLAGS': config_host['QEMU_OBJCFLAGS']} -summary_info += {'QEMU_LDFLAGS': config_host['QEMU_LDFLAGS']} +summary_info += {'QEMU_CFLAGS': ' '.join(qemu_cflags)} +if 'cpp' in all_languages + summary_info += {'QEMU_CXXFLAGS': ' '.join(qemu_cxxflags)} +endif +if 'objc' in all_languages + summary_info += {'QEMU_OBJCFLAGS': ' '.join(qemu_objcflags)} +endif +summary_info += {'QEMU_LDFLAGS': ' '.join(qemu_ldflags)} summary_info += {'profiler': get_option('profiler')} summary_info += {'link-time optimization (LTO)': get_option('b_lto')} summary_info += {'PIE': get_option('b_pie')} @@ -3565,25 +3803,24 @@ endif summary_info += {'strip binaries': get_option('strip')} summary_info += {'sparse': sparse} summary_info += {'mingw32 support': targetos == 'windows'} +summary(summary_info, bool_yn: true, section: 'Compilation') # snarf the cross-compilation information for tests +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) - target = config_cross_tcg['TARGET_NAME'] - compiler = '' - if 'DOCKER_CROSS_CC_GUEST' in config_cross_tcg - summary_info += {target + ' tests': config_cross_tcg['DOCKER_CROSS_CC_GUEST'] + - ' via ' + config_cross_tcg['DOCKER_IMAGE']} - elif 'CROSS_CC_GUEST' in config_cross_tcg - summary_info += {target + ' tests' - : config_cross_tcg['CROSS_CC_GUEST'] } + if 'CC' in config_cross_tcg + summary_info += {config_cross_tcg['TARGET_NAME']: config_cross_tcg['CC']} + have_cross = true endif - endif + endif endforeach - -summary(summary_info, bool_yn: true, section: 'Compilation') +if have_cross + summary(summary_info, bool_yn: true, section: 'Cross compilers') +endif # Targets and accelerators summary_info = {} @@ -3593,9 +3830,9 @@ if have_system summary_info += {'HVF support': config_all.has_key('CONFIG_HVF')} summary_info += {'WHPX support': config_all.has_key('CONFIG_WHPX')} summary_info += {'NVMM support': config_all.has_key('CONFIG_NVMM')} - summary_info += {'Xen support': config_host.has_key('CONFIG_XEN_BACKEND')} - if config_host.has_key('CONFIG_XEN_BACKEND') - summary_info += {'xen ctrl version': config_host['CONFIG_XEN_CTRL_INTERFACE_VERSION']} + summary_info += {'Xen support': xen.found()} + if xen.found() + summary_info += {'xen ctrl version': xen.version()} endif endif summary_info += {'TCG support': config_all.has_key('CONFIG_TCG')} @@ -3612,6 +3849,7 @@ summary_info += {'target list': ' '.join(target_dirs)} if have_system summary_info += {'default devices': get_option('default_devices')} summary_info += {'out of process emulation': multiprocess_allowed} + summary_info += {'vfio-user server': vfio_user_server_allowed} endif summary(summary_info, bool_yn: true, section: 'Targets and accelerators') @@ -3620,8 +3858,8 @@ summary_info = {} summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']} summary_info += {'coroutine pool': have_coroutine_pool} if have_block - summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']} - summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']} + summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')} + summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')} summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')} summary_info += {'VirtFS support': have_virtfs} summary_info += {'build virtiofs daemon': have_virtiofsd} @@ -3636,12 +3874,13 @@ if have_block summary_info += {'qed support': get_option('qed').allowed()} summary_info += {'parallels support': get_option('parallels').allowed()} summary_info += {'FUSE exports': fuse} + summary_info += {'VDUSE block exports': have_vduse_blk_export} endif summary(summary_info, bool_yn: true, section: 'Block layer support') # Crypto summary_info = {} -summary_info += {'TLS priority': config_host['CONFIG_TLS_PRIORITY']} +summary_info += {'TLS priority': get_option('tls_priority')} summary_info += {'GNUTLS support': gnutls} if gnutls.found() summary_info += {' GNUTLS crypto': gnutls_crypto.found()} @@ -3653,35 +3892,38 @@ if nettle.found() endif summary_info += {'AF_ALG support': have_afalg} summary_info += {'rng-none': get_option('rng_none')} -summary_info += {'Linux keyring': config_host.has_key('CONFIG_SECRET_KEYRING')} +summary_info += {'Linux keyring': have_keyring} summary(summary_info, bool_yn: true, section: 'Crypto') # Libraries summary_info = {} if targetos == 'darwin' - summary_info += {'Cocoa support': cocoa} + summary_info += {'Cocoa support': cocoa} + summary_info += {'vmnet.framework support': vmnet} endif summary_info += {'SDL support': sdl} 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} summary_info += {'curses support': curses} summary_info += {'virgl support': virgl} +summary_info += {'blkio support': blkio} summary_info += {'curl support': curl} summary_info += {'Multipath support': mpathpersist} +summary_info += {'PNG support': png} summary_info += {'VNC support': vnc} if vnc.found() summary_info += {'VNC SASL support': sasl} summary_info += {'VNC JPEG support': jpeg} - summary_info += {'VNC PNG support': png} 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' @@ -3699,8 +3941,8 @@ summary_info += {'l2tpv3 support': have_l2tpv3} summary_info += {'Linux AIO support': libaio} summary_info += {'Linux io_uring support': linux_io_uring} summary_info += {'ATTR/XATTR support': libattr} -summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')} -summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')} +summary_info += {'RDMA support': rdma} +summary_info += {'PVRDMA support': have_pvrdma} summary_info += {'fdt support': fdt_opt == 'disabled' ? false : fdt_opt} summary_info += {'libcap-ng support': libcap_ng} summary_info += {'bpf support': libbpf} @@ -3713,14 +3955,13 @@ summary_info += {'smartcard support': cacard} summary_info += {'U2F support': u2f} summary_info += {'libusb': libusb} summary_info += {'usb net redir': usbredir} -summary_info += {'OpenGL support': config_host.has_key('CONFIG_OPENGL')} +summary_info += {'OpenGL support (epoxy)': opengl} summary_info += {'GBM': gbm} summary_info += {'libiscsi support': libiscsi} summary_info += {'libnfs support': libnfs} if targetos == 'windows' if have_ga summary_info += {'QGA VSS support': have_qga_vss} - summary_info += {'QGA w32 disk info': have_ntddscsi} endif endif summary_info += {'seccomp support': seccomp} @@ -3733,7 +3974,7 @@ summary_info += {'bzip2 support': libbzip2} summary_info += {'lzfse support': liblzfse} summary_info += {'zstd support': zstd} summary_info += {'NUMA host support': numa} -summary_info += {'capstone': capstone_opt == 'internal' ? capstone_opt : capstone} +summary_info += {'capstone': capstone} summary_info += {'libpmem support': libpmem} summary_info += {'libdaxctl support': libdaxctl} summary_info += {'libudev': libudev} diff --git a/meson_options.txt b/meson_options.txt index 52b11cead44a..559a571b6b6c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,21 +4,31 @@ option('qemu_suffix', type : 'string', value: 'qemu', description: 'Suffix for QEMU data/modules/config directories (can be empty)') -option('docdir', type : 'string', value : 'doc', +option('docdir', type : 'string', value : 'share/doc', description: 'Base directory for documentation installation (can be empty)') -option('qemu_firmwarepath', type : 'string', value : '', +option('qemu_firmwarepath', type : 'array', value : ['share/qemu-firmware'], description: 'search PATH for firmware files') +option('pkgversion', type : 'string', value : '', + description: 'use specified string as sub-version of the package') option('smbd', type : 'string', value : '', description: 'Path to smbd for slirp networking') option('sphinx_build', type : 'string', value : '', - description: 'Use specified sphinx-build [$sphinx_build] for building document (default to be empty)') + description: 'Use specified sphinx-build for building document') option('iasl', type : 'string', value : '', description: 'Path to ACPI disassembler') +option('tls_priority', type : 'string', value : 'NORMAL', + description: 'Default TLS protocol/cipher priority string') 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)') +option('block_drv_ro_whitelist', type : 'string', value : '', + description: 'set block driver read-only whitelist (by default affects only QEMU, not tools like qemu-img)') +option('interp_prefix', type : 'string', value : '/usr/gnemul/qemu-%M', + description: 'where to find shared libraries etc., use %M for cpu name') option('fuzzing_engine', type : 'string', value : '', description: 'fuzzing engine library for OSS-Fuzz') option('trace_file', type: 'string', value: 'trace', @@ -34,6 +44,8 @@ option('fuzzing', type : 'boolean', value: false, description: 'build fuzzing targets') option('gettext', type : 'feature', value : 'auto', description: 'Localization of the GTK+ user interface') +option('module_upgrades', type : 'boolean', value : false, + description: 'try to load modules from alternate paths for upgrades') option('install_blobs', type : 'boolean', value : true, description: 'install provided firmware blobs') option('sparse', type : 'feature', value : 'auto', @@ -66,16 +78,18 @@ option('xen', type: 'feature', value: 'auto', description: 'Xen backend support') option('xen_pci_passthrough', type: 'feature', value: 'auto', description: 'Xen PCI passthrough support') -option('tcg', type: 'feature', value: 'auto', +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') +option('vfio_user_server', type: 'feature', value: 'disabled', + description: 'vfio-user server support') option('dbus_display', type: 'feature', value: 'auto', description: '-display dbus support') option('tpm', type : 'feature', value : 'auto', @@ -90,6 +104,8 @@ option('avx2', type: 'feature', value: 'auto', description: 'AVX2 optimizations') option('avx512f', type: 'feature', value: 'disabled', description: 'AVX512F optimizations') +option('keyring', type: 'feature', value: 'auto', + description: 'Linux keyring support') option('attr', type : 'feature', value : 'auto', description: 'attr/xattr support') @@ -101,12 +117,16 @@ option('bzip2', type : 'feature', value : 'auto', description: 'bzip2 support for DMG images') option('cap_ng', type : 'feature', value : 'auto', description: 'cap_ng support') +option('blkio', type : 'feature', value : 'auto', + description: 'libblkio block device driver') option('bpf', type : 'feature', value : 'auto', description: 'eBPF support') option('cocoa', type : 'feature', value : 'auto', description: 'Cocoa user interface (macOS only)') option('curl', type : 'feature', value : 'auto', description: 'CURL block device driver') +option('gio', type : 'feature', value : 'auto', + description: 'use libgio for D-Bus support') option('glusterfs', type : 'feature', value : 'auto', description: 'Glusterfs block device driver') option('libiscsi', type : 'feature', value : 'auto', @@ -149,6 +169,12 @@ option('lzo', type : 'feature', value : 'auto', description: 'lzo compression support') option('rbd', type : 'feature', value : 'auto', description: 'Ceph block device driver') +option('opengl', type : 'feature', value : 'auto', + description: 'OpenGL support') +option('rdma', type : 'feature', value : 'auto', + description: 'Enable RDMA-based migration') +option('pvrdma', type : 'feature', value : 'auto', + description: 'Enable PVRDMA support') option('gtk', type : 'feature', value : 'auto', description: 'GTK+ user interface') option('sdl', type : 'feature', value : 'auto', @@ -167,26 +193,39 @@ option('spice_protocol', type : 'feature', value : 'auto', description: 'Spice protocol support') option('u2f', type : 'feature', value : 'auto', description: 'U2F emulation support') +option('canokey', type : 'feature', value : 'auto', + description: 'CanoKey support') option('usb_redir', type : 'feature', value : 'auto', description: 'libusbredir support') 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', + description: 'vmnet.framework network backend support') option('virglrenderer', type : 'feature', value : 'auto', description: 'virgl rendering support') +option('png', type : 'feature', value : 'auto', + description: 'PNG support with libpng') option('vnc', type : 'feature', value : 'auto', description: 'VNC server') option('vnc_jpeg', type : 'feature', value : 'auto', description: 'JPEG lossy compression for VNC server') -option('vnc_png', type : 'feature', value : 'auto', - description: 'PNG compression for VNC server') option('vnc_sasl', type : 'feature', value : 'auto', description: 'SASL authentication for VNC server') option('vte', type : 'feature', value : 'auto', description: 'vte support for the gtk UI') + +# GTK Clipboard implementation is disabled by default, since it may cause hangs +# of the guest VCPUs. See gitlab issue 1150: +# https://gitlab.com/qemu-project/qemu/-/issues/1150 + +option('gtk_clipboard', type: 'feature', value : 'disabled', + description: 'clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)') option('xkbcommon', type : 'feature', value : 'auto', description: 'xkbcommon support') option('zstd', type : 'feature', value : 'auto', @@ -212,20 +251,32 @@ 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') +option('vhost_net', type: 'feature', value: 'auto', + description: 'vhost-net kernel acceleration support') +option('vhost_user', type: 'feature', value: 'auto', + description: 'vhost-user backend support') +option('vhost_crypto', type: 'feature', value: 'auto', + description: 'vhost-user crypto backend support') +option('vhost_vdpa', type: 'feature', value: 'auto', + description: 'vhost-vdpa kernel backend support') option('vhost_user_blk_server', type: 'feature', value: 'auto', description: 'build vhost-user-blk server') option('virtfs', type: 'feature', value: 'auto', description: 'virtio-9p support') option('virtiofsd', type: 'feature', value: 'auto', description: 'build virtiofs daemon (virtiofsd)') +option('libvduse', type: 'feature', value: 'auto', + description: 'build VDUSE Library') +option('vduse_blk_export', type: 'feature', value: 'auto', + description: 'VDUSE block export support') -option('capstone', type: 'combo', value: 'auto', - choices: ['disabled', 'enabled', 'auto', 'system', 'internal'], +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') @@ -270,3 +321,6 @@ option('profiler', type: 'boolean', value: false, description: 'profiler support') option('slirp_smbd', type : 'feature', value : 'auto', description: 'use smbd (at path --smbd=*) in slirp networking') + +option('hexagon_idef_parser', type : 'boolean', value : true, + description: 'use idef-parser to automatically generate TCG code for the Hexagon frontend') diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 9aba7d9c2200..283017d7d3d8 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -551,7 +551,7 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, } bitmap_alias = bmap_inner->alias; - if (bmap_inner->has_transform) { + if (bmap_inner->transform) { bitmap_transform = bmap_inner->transform; } } else { @@ -821,7 +821,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) } if (s->bmap_inner && - s->bmap_inner->has_transform && + s->bmap_inner->transform && s->bmap_inner->transform->has_persistent) { persistent = s->bmap_inner->transform->persistent; } else { diff --git a/migration/block.c b/migration/block.c index 077a41332582..4347da1526a4 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 @@ -568,8 +568,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, bmds_set_aio_inflight(bmds, sector, nr_sectors, 1); blk_mig_unlock(); } else { - ret = blk_pread(bmds->blk, sector * BDRV_SECTOR_SIZE, blk->buf, - nr_sectors * BDRV_SECTOR_SIZE); + ret = blk_pread(bmds->blk, sector * BDRV_SECTOR_SIZE, + nr_sectors * BDRV_SECTOR_SIZE, blk->buf, 0); if (ret < 0) { goto error; } @@ -756,8 +756,8 @@ static int block_save_setup(QEMUFile *f, void *opaque) static int block_save_iterate(QEMUFile *f, void *opaque) { int ret; - int64_t last_ftell = qemu_ftell(f); - int64_t delta_ftell; + int64_t last_bytes = qemu_file_total_transferred(f); + int64_t delta_bytes; trace_migration_block_save("iterate", block_mig_state.submitted, block_mig_state.transferred); @@ -809,10 +809,10 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } qemu_put_be64(f, BLK_MIG_FLAG_EOS); - delta_ftell = qemu_ftell(f) - last_ftell; - if (delta_ftell > 0) { + delta_bytes = qemu_file_total_transferred(f) - last_bytes; + if (delta_bytes > 0) { return 1; - } else if (delta_ftell < 0) { + } else if (delta_bytes < 0) { return -1; } else { return 0; @@ -880,8 +880,8 @@ static void block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, blk_mig_unlock(); /* Report at least one block pending during bulk phase */ - if (pending <= max_size && !block_mig_state.bulk_completed) { - pending = max_size + BLK_MIG_BLOCK_SIZE; + if (!pending && !block_mig_state.bulk_completed) { + pending = BLK_MIG_BLOCK_SIZE; } trace_migration_block_save_pending(pending); @@ -976,8 +976,8 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) cluster_size, BDRV_REQ_MAY_UNMAP); } else { - ret = blk_pwrite(blk, cur_addr, cur_buf, - cluster_size, 0); + ret = blk_pwrite(blk, cur_addr, cluster_size, cur_buf, + 0); } if (ret < 0) { break; diff --git a/migration/channel-block.c b/migration/channel-block.c new file mode 100644 index 000000000000..f4ab53acdb5c --- /dev/null +++ b/migration/channel-block.c @@ -0,0 +1,197 @@ +/* + * QEMU I/O channels block driver + * + * Copyright (c) 2022 Red Hat, Inc. + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "migration/channel-block.h" +#include "qapi/error.h" +#include "block/block.h" +#include "trace.h" + +QIOChannelBlock * +qio_channel_block_new(BlockDriverState *bs) +{ + QIOChannelBlock *ioc; + + ioc = QIO_CHANNEL_BLOCK(object_new(TYPE_QIO_CHANNEL_BLOCK)); + + bdrv_ref(bs); + ioc->bs = bs; + + return ioc; +} + + +static void +qio_channel_block_finalize(Object *obj) +{ + QIOChannelBlock *ioc = QIO_CHANNEL_BLOCK(obj); + + g_clear_pointer(&ioc->bs, bdrv_unref); +} + + +static ssize_t +qio_channel_block_readv(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, + size_t *nfds, + Error **errp) +{ + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); + QEMUIOVector qiov; + int ret; + + qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); + ret = bdrv_readv_vmstate(bioc->bs, &qiov, bioc->offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "bdrv_readv_vmstate failed"); + return -1; + } + + bioc->offset += qiov.size; + return qiov.size; +} + + +static ssize_t +qio_channel_block_writev(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, + size_t nfds, + int flags, + Error **errp) +{ + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); + QEMUIOVector qiov; + int ret; + + qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); + ret = bdrv_writev_vmstate(bioc->bs, &qiov, bioc->offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "bdrv_writev_vmstate failed"); + return -1; + } + + bioc->offset += qiov.size; + return qiov.size; +} + + +static int +qio_channel_block_set_blocking(QIOChannel *ioc, + bool enabled, + Error **errp) +{ + if (!enabled) { + error_setg(errp, "Non-blocking mode not supported for block devices"); + return -1; + } + return 0; +} + + +static off_t +qio_channel_block_seek(QIOChannel *ioc, + off_t offset, + int whence, + Error **errp) +{ + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); + + switch (whence) { + case SEEK_SET: + bioc->offset = offset; + break; + case SEEK_CUR: + bioc->offset += whence; + break; + case SEEK_END: + error_setg(errp, "Size of VMstate region is unknown"); + return (off_t)-1; + default: + g_assert_not_reached(); + } + + return bioc->offset; +} + + +static int +qio_channel_block_close(QIOChannel *ioc, + Error **errp) +{ + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); + int rv = bdrv_flush(bioc->bs); + + if (rv < 0) { + error_setg_errno(errp, -rv, + "Unable to flush VMState"); + return -1; + } + + g_clear_pointer(&bioc->bs, bdrv_unref); + bioc->offset = 0; + + return 0; +} + + +static void +qio_channel_block_set_aio_fd_handler(QIOChannel *ioc, + AioContext *ctx, + IOHandler *io_read, + IOHandler *io_write, + void *opaque) +{ + /* XXX anything we can do here ? */ +} + + +static void +qio_channel_block_class_init(ObjectClass *klass, + void *class_data G_GNUC_UNUSED) +{ + QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); + + ioc_klass->io_writev = qio_channel_block_writev; + ioc_klass->io_readv = qio_channel_block_readv; + ioc_klass->io_set_blocking = qio_channel_block_set_blocking; + ioc_klass->io_seek = qio_channel_block_seek; + ioc_klass->io_close = qio_channel_block_close; + ioc_klass->io_set_aio_fd_handler = qio_channel_block_set_aio_fd_handler; +} + +static const TypeInfo qio_channel_block_info = { + .parent = TYPE_QIO_CHANNEL, + .name = TYPE_QIO_CHANNEL_BLOCK, + .instance_size = sizeof(QIOChannelBlock), + .instance_finalize = qio_channel_block_finalize, + .class_init = qio_channel_block_class_init, +}; + +static void +qio_channel_block_register_types(void) +{ + type_register_static(&qio_channel_block_info); +} + +type_init(qio_channel_block_register_types); diff --git a/migration/channel-block.h b/migration/channel-block.h new file mode 100644 index 000000000000..31673824e697 --- /dev/null +++ b/migration/channel-block.h @@ -0,0 +1,59 @@ +/* + * QEMU I/O channels block driver + * + * Copyright (c) 2022 Red Hat, Inc. + * + * 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 QIO_CHANNEL_BLOCK_H +#define QIO_CHANNEL_BLOCK_H + +#include "io/channel.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_BLOCK "qio-channel-block" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBlock, QIO_CHANNEL_BLOCK) + + +/** + * QIOChannelBlock: + * + * The QIOChannelBlock object provides a channel implementation + * that is able to perform I/O on the BlockDriverState objects + * to the VMState region. + */ + +struct QIOChannelBlock { + QIOChannel parent; + BlockDriverState *bs; + off_t offset; +}; + + +/** + * qio_channel_block_new: + * @bs: the block driver state + * + * Create a new IO channel object that can perform + * I/O on a BlockDriverState object to the VMState + * region + * + * Returns: the new channel object + */ +QIOChannelBlock * +qio_channel_block_new(BlockDriverState *bs); + +#endif /* QIO_CHANNEL_BLOCK_H */ diff --git a/migration/channel.c b/migration/channel.c index c4fc000a1a0a..1b0815039f9d 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -14,7 +14,7 @@ #include "channel.h" #include "tls.h" #include "migration.h" -#include "qemu-file-channel.h" +#include "qemu-file.h" #include "trace.h" #include "qapi/error.h" #include "io/channel-tls.h" @@ -38,10 +38,7 @@ void migration_channel_process_incoming(QIOChannel *ioc) trace_migration_set_incoming_channel( ioc, object_get_typename(OBJECT(ioc))); - if (s->parameters.tls_creds && - *s->parameters.tls_creds && - !object_dynamic_cast(OBJECT(ioc), - TYPE_QIO_CHANNEL_TLS)) { + if (migrate_channel_requires_tls_upgrade(ioc)) { migration_tls_channel_process_incoming(s, ioc, &local_err); } else { migration_ioc_register_yank(ioc); @@ -71,10 +68,7 @@ void migration_channel_connect(MigrationState *s, ioc, object_get_typename(OBJECT(ioc)), hostname, error); if (!error) { - if (s->parameters.tls_creds && - *s->parameters.tls_creds && - !object_dynamic_cast(OBJECT(ioc), - TYPE_QIO_CHANNEL_TLS)) { + if (migrate_channel_requires_tls_upgrade(ioc)) { migration_tls_channel_connect(s, ioc, hostname, &error); if (!error) { @@ -86,7 +80,7 @@ void migration_channel_connect(MigrationState *s, return; } } else { - QEMUFile *f = qemu_fopen_channel_output(ioc); + QEMUFile *f = qemu_file_new_output(ioc); migration_ioc_register_yank(ioc); @@ -96,6 +90,5 @@ void migration_channel_connect(MigrationState *s, } } migrate_fd_connect(s, error); - g_free(s->hostname); error_free(error); } diff --git a/migration/colo.c b/migration/colo.c index 5f7071b3cd6a..232c8d44b1f7 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -14,7 +14,6 @@ #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qapi-commands-migration.h" -#include "qemu-file-channel.h" #include "migration.h" #include "qemu-file.h" #include "savevm.h" @@ -251,7 +250,6 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp) replication_get_error_all(&err); if (err) { s->error = true; - s->has_desc = true; s->desc = g_strdup(error_get_pretty(err)); } else { s->error = false; @@ -559,7 +557,7 @@ static void colo_process_checkpoint(MigrationState *s) goto out; } bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); - fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc)); + fb = qemu_file_new_output(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); @@ -873,7 +871,7 @@ void *colo_process_incoming_thread(void *opaque) colo_incoming_start_dirty_log(); bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); - fb = qemu_fopen_channel_input(QIO_CHANNEL(bioc)); + fb = qemu_file_new_input(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index aace12a78764..4bfb97fc6876 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -46,7 +46,7 @@ static struct DirtyRateStat DirtyStat; static DirtyRateMeasureMode dirtyrate_mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING; -static int64_t set_sample_page_period(int64_t msec, int64_t initial_time) +static int64_t dirty_stat_wait(int64_t msec, int64_t initial_time) { int64_t current_time; @@ -60,6 +60,129 @@ static int64_t set_sample_page_period(int64_t msec, int64_t initial_time) return msec; } +static inline void record_dirtypages(DirtyPageRecord *dirty_pages, + CPUState *cpu, bool start) +{ + if (start) { + dirty_pages[cpu->cpu_index].start_pages = cpu->dirty_pages; + } else { + dirty_pages[cpu->cpu_index].end_pages = cpu->dirty_pages; + } +} + +static int64_t do_calculate_dirtyrate(DirtyPageRecord dirty_pages, + int64_t calc_time_ms) +{ + uint64_t memory_size_MB; + uint64_t increased_dirty_pages = + dirty_pages.end_pages - dirty_pages.start_pages; + + memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20; + + return memory_size_MB * 1000 / calc_time_ms; +} + +void global_dirty_log_change(unsigned int flag, bool start) +{ + qemu_mutex_lock_iothread(); + if (start) { + memory_global_dirty_log_start(flag); + } else { + memory_global_dirty_log_stop(flag); + } + qemu_mutex_unlock_iothread(); +} + +/* + * global_dirty_log_sync + * 1. sync dirty log from kvm + * 2. stop dirty tracking if needed. + */ +static void global_dirty_log_sync(unsigned int flag, bool one_shot) +{ + qemu_mutex_lock_iothread(); + memory_global_dirty_log_sync(); + if (one_shot) { + memory_global_dirty_log_stop(flag); + } + qemu_mutex_unlock_iothread(); +} + +static DirtyPageRecord *vcpu_dirty_stat_alloc(VcpuStat *stat) +{ + CPUState *cpu; + int nvcpu = 0; + + CPU_FOREACH(cpu) { + nvcpu++; + } + + stat->nvcpu = nvcpu; + stat->rates = g_new0(DirtyRateVcpu, nvcpu); + + return g_new0(DirtyPageRecord, nvcpu); +} + +static void vcpu_dirty_stat_collect(VcpuStat *stat, + DirtyPageRecord *records, + bool start) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + record_dirtypages(records, cpu, start); + } +} + +int64_t vcpu_calculate_dirtyrate(int64_t calc_time_ms, + VcpuStat *stat, + unsigned int flag, + bool one_shot) +{ + DirtyPageRecord *records; + int64_t init_time_ms; + int64_t duration; + int64_t dirtyrate; + int i = 0; + unsigned int gen_id; + +retry: + init_time_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + + cpu_list_lock(); + gen_id = cpu_list_generation_id_get(); + records = vcpu_dirty_stat_alloc(stat); + vcpu_dirty_stat_collect(stat, records, true); + cpu_list_unlock(); + + duration = dirty_stat_wait(calc_time_ms, init_time_ms); + + global_dirty_log_sync(flag, one_shot); + + cpu_list_lock(); + if (gen_id != cpu_list_generation_id_get()) { + g_free(records); + g_free(stat->rates); + cpu_list_unlock(); + goto retry; + } + vcpu_dirty_stat_collect(stat, records, false); + cpu_list_unlock(); + + for (i = 0; i < stat->nvcpu; i++) { + dirtyrate = do_calculate_dirtyrate(records[i], duration); + + stat->rates[i].id = i; + stat->rates[i].dirty_rate = dirtyrate; + + trace_dirtyrate_do_calculate_vcpu(i, dirtyrate); + } + + g_free(records); + + return duration; +} + static bool is_sample_period_valid(int64_t sec) { if (sec < MIN_FETCH_DIRTYRATE_TIME_SEC || @@ -347,7 +470,6 @@ find_block_matched(RAMBlock *block, int count, struct RamblockDirtyInfo *infos) { int i; - struct RamblockDirtyInfo *matched; for (i = 0; i < count; i++) { if (!strcmp(infos[i].idstr, qemu_ram_get_idstr(block))) { @@ -366,9 +488,7 @@ find_block_matched(RAMBlock *block, int count, return NULL; } - matched = &infos[i]; - - return matched; + return &infos[i]; } static bool compare_page_hash_info(struct RamblockDirtyInfo *info, @@ -396,44 +516,6 @@ static bool compare_page_hash_info(struct RamblockDirtyInfo *info, return true; } -static inline void record_dirtypages(DirtyPageRecord *dirty_pages, - CPUState *cpu, bool start) -{ - if (start) { - dirty_pages[cpu->cpu_index].start_pages = cpu->dirty_pages; - } else { - dirty_pages[cpu->cpu_index].end_pages = cpu->dirty_pages; - } -} - -static void dirtyrate_global_dirty_log_start(void) -{ - qemu_mutex_lock_iothread(); - memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE); - qemu_mutex_unlock_iothread(); -} - -static void dirtyrate_global_dirty_log_stop(void) -{ - qemu_mutex_lock_iothread(); - memory_global_dirty_log_sync(); - memory_global_dirty_log_stop(GLOBAL_DIRTY_DIRTY_RATE); - qemu_mutex_unlock_iothread(); -} - -static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages) -{ - uint64_t memory_size_MB; - int64_t time_s; - uint64_t increased_dirty_pages = - dirty_pages.end_pages - dirty_pages.start_pages; - - memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20; - time_s = DirtyStat.calc_time; - - return memory_size_MB / time_s; -} - static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages, bool start) { @@ -444,11 +526,6 @@ static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages, } } -static void do_calculate_dirtyrate_bitmap(DirtyPageRecord dirty_pages) -{ - DirtyStat.dirty_rate = do_calculate_dirtyrate_vcpu(dirty_pages); -} - static inline void dirtyrate_manual_reset_protect(void) { RAMBlock *block = NULL; @@ -492,71 +569,49 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config) DirtyStat.start_time = start_time / 1000; msec = config.sample_period_seconds * 1000; - msec = set_sample_page_period(msec, start_time); + msec = dirty_stat_wait(msec, start_time); DirtyStat.calc_time = msec / 1000; /* - * dirtyrate_global_dirty_log_stop do two things. + * do two things. * 1. fetch dirty bitmap from kvm * 2. stop dirty tracking */ - dirtyrate_global_dirty_log_stop(); + global_dirty_log_sync(GLOBAL_DIRTY_DIRTY_RATE, true); record_dirtypages_bitmap(&dirty_pages, false); - do_calculate_dirtyrate_bitmap(dirty_pages); + DirtyStat.dirty_rate = do_calculate_dirtyrate(dirty_pages, msec); } static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config) { - CPUState *cpu; - int64_t msec = 0; - int64_t start_time; + int64_t duration; uint64_t dirtyrate = 0; uint64_t dirtyrate_sum = 0; - DirtyPageRecord *dirty_pages; - int nvcpu = 0; int i = 0; - CPU_FOREACH(cpu) { - nvcpu++; - } - - dirty_pages = malloc(sizeof(*dirty_pages) * nvcpu); - - DirtyStat.dirty_ring.nvcpu = nvcpu; - DirtyStat.dirty_ring.rates = malloc(sizeof(DirtyRateVcpu) * nvcpu); - - dirtyrate_global_dirty_log_start(); - - CPU_FOREACH(cpu) { - record_dirtypages(dirty_pages, cpu, true); - } - - start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - DirtyStat.start_time = start_time / 1000; + /* start log sync */ + global_dirty_log_change(GLOBAL_DIRTY_DIRTY_RATE, true); - msec = config.sample_period_seconds * 1000; - msec = set_sample_page_period(msec, start_time); - DirtyStat.calc_time = msec / 1000; + DirtyStat.start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; - dirtyrate_global_dirty_log_stop(); + /* calculate vcpu dirtyrate */ + duration = vcpu_calculate_dirtyrate(config.sample_period_seconds * 1000, + &DirtyStat.dirty_ring, + GLOBAL_DIRTY_DIRTY_RATE, + true); - CPU_FOREACH(cpu) { - record_dirtypages(dirty_pages, cpu, false); - } + DirtyStat.calc_time = duration / 1000; + /* calculate vm dirtyrate */ for (i = 0; i < DirtyStat.dirty_ring.nvcpu; i++) { - dirtyrate = do_calculate_dirtyrate_vcpu(dirty_pages[i]); - trace_dirtyrate_do_calculate_vcpu(i, dirtyrate); - - DirtyStat.dirty_ring.rates[i].id = i; + dirtyrate = DirtyStat.dirty_ring.rates[i].dirty_rate; DirtyStat.dirty_ring.rates[i].dirty_rate = dirtyrate; dirtyrate_sum += dirtyrate; } DirtyStat.dirty_rate = dirtyrate_sum; - free(dirty_pages); } static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) @@ -574,7 +629,7 @@ static void calculate_dirtyrate_sample_vm(struct DirtyRateConfig config) rcu_read_unlock(); msec = config.sample_period_seconds * 1000; - msec = set_sample_page_period(msec, initial_time); + msec = dirty_stat_wait(msec, initial_time); DirtyStat.start_time = initial_time / 1000; DirtyStat.calc_time = msec / 1000; diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h index 69d4c5b8655f..594a5c0bb64c 100644 --- a/migration/dirtyrate.h +++ b/migration/dirtyrate.h @@ -13,6 +13,8 @@ #ifndef QEMU_MIGRATION_DIRTYRATE_H #define QEMU_MIGRATION_DIRTYRATE_H +#include "sysemu/dirtyrate.h" + /* * Sample 512 pages per GB as default. */ @@ -65,11 +67,6 @@ typedef struct SampleVMStat { uint64_t total_block_mem_MB; /* size of total sampled pages in MB */ } SampleVMStat; -typedef struct VcpuStat { - int nvcpu; /* number of vcpu */ - DirtyRateVcpu *rates; /* array of dirty rate for each vcpu */ -} VcpuStat; - /* * Store calculation statistics for each measure. */ diff --git a/migration/meson.build b/migration/meson.build index 8b5ca5c04760..690487cf1a81 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -4,7 +4,6 @@ migration_files = files( 'xbzrle.c', 'vmstate-types.c', 'vmstate.c', - 'qemu-file-channel.c', 'qemu-file.c', 'yank_functions.c', ) @@ -13,6 +12,7 @@ softmmu_ss.add(migration_files) softmmu_ss.add(files( 'block-dirty-bitmap.c', 'channel.c', + 'channel-block.c', 'colo-failover.c', 'colo.c', 'exec.c', @@ -27,7 +27,7 @@ softmmu_ss.add(files( 'tls.c', ), gnutls) -softmmu_ss.add(when: ['CONFIG_RDMA', rdma], if_true: files('rdma.c')) +softmmu_ss.add(when: rdma, if_true: files('rdma.c')) if get_option('live_block_migration').allowed() softmmu_ss.add(files('block.c')) endif diff --git a/migration/migration.c b/migration/migration.c index 695f0f29000c..52b5d3924431 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -30,7 +30,6 @@ #include "migration/misc.h" #include "migration.h" #include "savevm.h" -#include "qemu-file-channel.h" #include "qemu-file.h" #include "migration/vmstate.h" #include "block/block.h" @@ -49,6 +48,7 @@ #include "trace.h" #include "exec/target_page.h" #include "io/channel-buffer.h" +#include "io/channel-tls.h" #include "migration/colo.h" #include "hw/boards.h" #include "hw/qdev-properties.h" @@ -163,7 +163,8 @@ INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot, MIGRATION_CAPABILITY_COMPRESS, MIGRATION_CAPABILITY_XBZRLE, MIGRATION_CAPABILITY_X_COLO, - MIGRATION_CAPABILITY_VALIDATE_UUID); + MIGRATION_CAPABILITY_VALIDATE_UUID, + MIGRATION_CAPABILITY_ZERO_COPY_SEND); /* When we add fault tolerance, we could have several migrations at once. For now we don't need to add @@ -180,6 +181,18 @@ static int migration_maybe_pause(MigrationState *s, int new_state); static void migrate_fd_cancel(MigrationState *s); +static bool migrate_allow_multi_channels = true; + +void migrate_protocol_allow_multi_channels(bool allow) +{ + migrate_allow_multi_channels = allow; +} + +bool migrate_multi_channels_is_allowed(void) +{ + return migrate_allow_multi_channels; +} + static gint page_request_addr_cmp(gconstpointer ap, gconstpointer bp) { uintptr_t a = (uintptr_t) ap, b = (uintptr_t) bp; @@ -203,9 +216,11 @@ void migration_object_init(void) current_incoming->postcopy_remote_fds = g_array_new(FALSE, TRUE, sizeof(struct PostCopyFD)); qemu_mutex_init(¤t_incoming->rp_mutex); + qemu_mutex_init(¤t_incoming->postcopy_prio_thread_mutex); qemu_event_init(¤t_incoming->main_thread_load_event, false); qemu_sem_init(¤t_incoming->postcopy_pause_sem_dst, 0); qemu_sem_init(¤t_incoming->postcopy_pause_sem_fault, 0); + qemu_sem_init(¤t_incoming->postcopy_pause_sem_fast_load, 0); qemu_mutex_init(¤t_incoming->page_request_mutex); current_incoming->page_requested = g_tree_new(page_request_addr_cmp); @@ -309,6 +324,12 @@ void migration_incoming_state_destroy(void) mis->page_requested = NULL; } + if (mis->postcopy_qemufile_dst) { + migration_ioc_unregister_yank_from_file(mis->postcopy_qemufile_dst); + qemu_fclose(mis->postcopy_qemufile_dst); + mis->postcopy_qemufile_dst = NULL; + } + yank_unregister_instance(MIGRATION_YANK_INSTANCE); } @@ -469,12 +490,12 @@ static void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p = NULL; - migrate_protocol_allow_multifd(false); /* reset it anyway */ + migrate_protocol_allow_multi_channels(false); /* reset it anyway */ qapi_event_send_migration(MIGRATION_STATUS_SETUP); if (strstart(uri, "tcp:", &p) || strstart(uri, "unix:", NULL) || strstart(uri, "vsock:", NULL)) { - migrate_protocol_allow_multifd(true); + migrate_protocol_allow_multi_channels(true); socket_start_incoming_migration(p ? p : uri, errp); #ifdef CONFIG_RDMA } else if (strstart(uri, "rdma:", &p)) { @@ -553,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; @@ -659,28 +681,29 @@ void migration_incoming_process(void) } /* Returns true if recovered from a paused migration, otherwise false */ -static bool postcopy_try_recover(QEMUFile *f) +static bool postcopy_try_recover(void) { MigrationIncomingState *mis = migration_incoming_get_current(); if (mis->state == MIGRATION_STATUS_POSTCOPY_PAUSED) { /* Resumed from a paused postcopy migration */ - mis->from_src_file = f; + /* This should be set already in migration_incoming_setup() */ + assert(mis->from_src_file); /* Postcopy has standalone thread to do vm load */ - qemu_file_set_blocking(f, true); + qemu_file_set_blocking(mis->from_src_file, true); /* Re-configure the return path */ - mis->to_src_file = qemu_file_get_return_path(f); + mis->to_src_file = qemu_file_get_return_path(mis->from_src_file); migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_PAUSED, MIGRATION_STATUS_POSTCOPY_RECOVER); /* * Here, we only wake up the main loading thread (while the - * fault thread will still be waiting), so that we can receive + * rest threads will still be waiting), so that we can receive * commands from source now, and answer it if needed. The - * fault thread will be woken up afterwards until we are sure + * rest threads will be woken up afterwards until we are sure * that source is ready to reply to page requests. */ qemu_sem_post(&mis->postcopy_pause_sem_dst); @@ -692,30 +715,30 @@ static bool postcopy_try_recover(QEMUFile *f) void migration_fd_process_incoming(QEMUFile *f, Error **errp) { - if (postcopy_try_recover(f)) { + if (!migration_incoming_setup(f, errp)) { return; } - - if (!migration_incoming_setup(f, errp)) { + if (postcopy_try_recover()) { return; } migration_incoming_process(); } +static bool migration_needs_multiple_sockets(void) +{ + return migrate_use_multifd() || migrate_postcopy_preempt(); +} + void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); Error *local_err = NULL; bool start_migration; + QEMUFile *f; if (!mis->from_src_file) { /* The first connection (multifd may have multiple) */ - QEMUFile *f = qemu_fopen_channel_input(ioc); - - /* If it's a recovery, we're done */ - if (postcopy_try_recover(f)) { - return; - } + f = qemu_file_new_input(ioc); if (!migration_incoming_setup(f, errp)) { return; @@ -723,13 +746,19 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) /* * Common migration only needs one channel, so we can start - * right now. Multifd needs more than one channel, we wait. + * right now. Some features need more than one channel, we wait. */ - start_migration = !migrate_use_multifd(); + start_migration = !migration_needs_multiple_sockets(); } else { /* Multiple connections */ - assert(migrate_use_multifd()); - start_migration = multifd_recv_new_channel(ioc, &local_err); + assert(migration_needs_multiple_sockets()); + if (migrate_use_multifd()) { + start_migration = multifd_recv_new_channel(ioc, &local_err); + } else { + assert(migrate_postcopy_preempt()); + f = qemu_file_new_input(ioc); + start_migration = postcopy_preempt_new_channel(mis, f); + } if (local_err) { error_propagate(errp, local_err); return; @@ -737,6 +766,10 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) } if (start_migration) { + /* If it's a recovery, we're done */ + if (postcopy_try_recover()) { + return; + } migration_incoming_process(); } } @@ -750,11 +783,20 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) bool migration_has_all_channels(void) { MigrationIncomingState *mis = migration_incoming_get_current(); - bool all_channels; - all_channels = multifd_recv_all_channels_created(); + if (!mis->from_src_file) { + return false; + } + + if (migrate_use_multifd()) { + return multifd_recv_all_channels_created(); + } + + if (migrate_postcopy_preempt()) { + return mis->postcopy_qemufile_dst != NULL; + } - return all_channels && mis->from_src_file != NULL; + return true; } /* @@ -876,11 +918,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->cpu_throttle_increment = s->parameters.cpu_throttle_increment; params->has_cpu_throttle_tailslow = true; params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow; - params->has_tls_creds = true; params->tls_creds = g_strdup(s->parameters.tls_creds); - params->has_tls_hostname = true; params->tls_hostname = g_strdup(s->parameters.tls_hostname); - params->has_tls_authz = true; params->tls_authz = g_strdup(s->parameters.tls_authz ? s->parameters.tls_authz : ""); params->has_max_bandwidth = true; @@ -1005,27 +1044,27 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) { size_t page_size = qemu_target_page_size(); - info->has_ram = true; info->ram = g_malloc0(sizeof(*info->ram)); - info->ram->transferred = ram_counters.transferred; + info->ram->transferred = stat64_get(&ram_atomic_counters.transferred); info->ram->total = ram_bytes_total(); - info->ram->duplicate = ram_counters.duplicate; + info->ram->duplicate = stat64_get(&ram_atomic_counters.duplicate); /* legacy value. It is not used anymore */ info->ram->skipped = 0; - info->ram->normal = ram_counters.normal; - info->ram->normal_bytes = ram_counters.normal * page_size; + info->ram->normal = stat64_get(&ram_atomic_counters.normal); + info->ram->normal_bytes = info->ram->normal * page_size; info->ram->mbps = s->mbps; info->ram->dirty_sync_count = ram_counters.dirty_sync_count; + info->ram->dirty_sync_missed_zero_copy = + ram_counters.dirty_sync_missed_zero_copy; info->ram->postcopy_requests = ram_counters.postcopy_requests; info->ram->page_size = page_size; info->ram->multifd_bytes = ram_counters.multifd_bytes; info->ram->pages_per_second = s->pages_per_second; info->ram->precopy_bytes = ram_counters.precopy_bytes; info->ram->downtime_bytes = ram_counters.downtime_bytes; - info->ram->postcopy_bytes = ram_counters.postcopy_bytes; + info->ram->postcopy_bytes = stat64_get(&ram_atomic_counters.postcopy_bytes); if (migrate_use_xbzrle()) { - info->has_xbzrle_cache = true; info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache)); info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size(); info->xbzrle_cache->bytes = xbzrle_counters.bytes; @@ -1037,7 +1076,6 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) } if (migrate_use_compression()) { - info->has_compression = true; info->compression = g_malloc0(sizeof(*info->compression)); info->compression->pages = compression_counters.pages; info->compression->busy = compression_counters.busy; @@ -1062,7 +1100,6 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) static void populate_disk_info(MigrationInfo *info) { if (blk_mig_active()) { - info->has_disk = true; info->disk = g_malloc0(sizeof(*info->disk)); info->disk->transferred = blk_mig_bytes_transferred(); info->disk->remaining = blk_mig_bytes_remaining(); @@ -1073,6 +1110,7 @@ static void populate_disk_info(MigrationInfo *info) static void fill_source_migration_info(MigrationInfo *info) { MigrationState *s = migrate_get_current(); + int state = qatomic_read(&s->state); GSList *cur_blocker = migration_blockers; info->blocked_reasons = NULL; @@ -1092,7 +1130,7 @@ static void fill_source_migration_info(MigrationInfo *info) } info->has_blocked_reasons = info->blocked_reasons != NULL; - switch (s->state) { + switch (state) { case MIGRATION_STATUS_NONE: /* no migration has happened ever */ /* do not overwrite destination migration status */ @@ -1126,7 +1164,6 @@ static void fill_source_migration_info(MigrationInfo *info) case MIGRATION_STATUS_FAILED: info->has_status = true; if (s->error) { - info->has_error_desc = true; info->error_desc = g_strdup(error_get_pretty(s->error)); } break; @@ -1137,7 +1174,7 @@ static void fill_source_migration_info(MigrationInfo *info) info->has_status = true; break; } - info->status = s->state; + info->status = state; } typedef enum WriteTrackingSupport { @@ -1259,14 +1296,59 @@ static bool migrate_caps_check(bool *cap_list, } } +#ifdef CONFIG_LINUX + if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND] && + (!cap_list[MIGRATION_CAPABILITY_MULTIFD] || + cap_list[MIGRATION_CAPABILITY_COMPRESS] || + cap_list[MIGRATION_CAPABILITY_XBZRLE] || + migrate_multifd_compression() || + migrate_use_tls())) { + error_setg(errp, + "Zero copy only available for non-compressed non-TLS multifd migration"); + return false; + } +#else + if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) { + error_setg(errp, + "Zero copy currently only available on Linux"); + return false; + } +#endif + + /* incoming side only */ if (runstate_check(RUN_STATE_INMIGRATE) && - !migrate_multifd_is_allowed() && + !migrate_multi_channels_is_allowed() && cap_list[MIGRATION_CAPABILITY_MULTIFD]) { error_setg(errp, "multifd is not supported by current protocol"); return false; } + if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) { + if (!cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { + error_setg(errp, "Postcopy preempt requires postcopy-ram"); + return false; + } + + /* + * Preempt mode requires urgent pages to be sent in separate + * channel, OTOH compression logic will disorder all pages into + * different compression channels, which is not compatible with the + * preempt assumptions on channel assignments. + */ + if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) { + error_setg(errp, "Postcopy preempt not compatible with compress"); + return false; + } + } + + if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) { + if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) { + error_setg(errp, "Multifd is not compatible with compress"); + return false; + } + } + return true; } @@ -1482,6 +1564,16 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) return false; } +#ifdef CONFIG_LINUX + if (migrate_use_zero_copy_send() && + ((params->has_multifd_compression && params->multifd_compression) || + (params->tls_creds && *params->tls_creds))) { + error_setg(errp, + "Zero copy only available for non-compressed non-TLS multifd migration"); + return false; + } +#endif + return true; } @@ -1524,12 +1616,12 @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow; } - if (params->has_tls_creds) { + if (params->tls_creds) { assert(params->tls_creds->type == QTYPE_QSTRING); dest->tls_creds = params->tls_creds->u.s; } - if (params->has_tls_hostname) { + if (params->tls_hostname) { assert(params->tls_hostname->type == QTYPE_QSTRING); dest->tls_hostname = params->tls_hostname->u.s; } @@ -1621,19 +1713,19 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow; } - if (params->has_tls_creds) { + if (params->tls_creds) { g_free(s->parameters.tls_creds); assert(params->tls_creds->type == QTYPE_QSTRING); s->parameters.tls_creds = g_strdup(params->tls_creds->u.s); } - if (params->has_tls_hostname) { + if (params->tls_hostname) { g_free(s->parameters.tls_hostname); assert(params->tls_hostname->type == QTYPE_QSTRING); s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s); } - if (params->has_tls_authz) { + if (params->tls_authz) { g_free(s->parameters.tls_authz); assert(params->tls_authz->type == QTYPE_QSTRING); s->parameters.tls_authz = g_strdup(params->tls_authz->u.s); @@ -1710,14 +1802,14 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) MigrationParameters tmp; /* TODO Rewrite "" to null instead */ - if (params->has_tls_creds + if (params->tls_creds && params->tls_creds->type == QTYPE_QNULL) { qobject_unref(params->tls_creds->u.n); params->tls_creds->type = QTYPE_QSTRING; params->tls_creds->u.s = strdup(""); } /* TODO Rewrite "" to null instead */ - if (params->has_tls_hostname + if (params->tls_hostname && params->tls_hostname->type == QTYPE_QNULL) { qobject_unref(params->tls_hostname->u.n); params->tls_hostname->type = QTYPE_QSTRING; @@ -1809,6 +1901,9 @@ static void migrate_fd_cleanup(MigrationState *s) qemu_bh_delete(s->cleanup_bh); s->cleanup_bh = NULL; + g_free(s->hostname); + s->hostname = NULL; + qemu_savevm_state_cleanup(); if (s->to_dst_file) { @@ -1835,6 +1930,12 @@ static void migrate_fd_cleanup(MigrationState *s) qemu_fclose(tmp); } + if (s->postcopy_qemufile_src) { + migration_ioc_unregister_yank_from_file(s->postcopy_qemufile_src); + qemu_fclose(s->postcopy_qemufile_src); + s->postcopy_qemufile_src = NULL; + } + assert(!migration_is_active(s)); if (s->state == MIGRATION_STATUS_CANCELLING) { @@ -2148,11 +2249,8 @@ void qmp_migrate_recover(const char *uri, Error **errp) return; } - if (qatomic_cmpxchg(&mis->postcopy_recover_triggered, - false, true) == true) { - error_setg(errp, "Migrate recovery is triggered already"); - return; - } + /* If there's an existing transport, release it */ + migration_incoming_transport_cleanup(mis); /* * Note that this call will never start a real migration; it will @@ -2160,12 +2258,6 @@ void qmp_migrate_recover(const char *uri, Error **errp) * to continue using that newly established channel. */ qemu_start_incoming_migration(uri, errp); - - /* Safe to dereference with the assert above */ - if (*errp) { - /* Reset the flag so user could still retry */ - qatomic_set(&mis->postcopy_recover_triggered, false); - } } void qmp_migrate_pause(Error **errp) @@ -2319,11 +2411,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, } } - migrate_protocol_allow_multifd(false); + migrate_protocol_allow_multi_channels(false); if (strstart(uri, "tcp:", &p) || strstart(uri, "unix:", NULL) || strstart(uri, "vsock:", NULL)) { - migrate_protocol_allow_multifd(true); + migrate_protocol_allow_multi_channels(true); socket_start_outgoing_migration(s, p ? p : uri, &local_err); #ifdef CONFIG_RDMA } else if (strstart(uri, "rdma:", &p)) { @@ -2536,6 +2628,7 @@ MultiFDCompression migrate_multifd_compression(void) s = migrate_get_current(); + assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX); return s->parameters.multifd_compression; } @@ -2557,6 +2650,26 @@ int migrate_multifd_zstd_level(void) return s->parameters.multifd_zstd_level; } +#ifdef CONFIG_LINUX +bool migrate_use_zero_copy_send(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->enabled_capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND]; +} +#endif + +int migrate_use_tls(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->parameters.tls_creds && *s->parameters.tls_creds; +} + int migrate_use_xbzrle(void) { MigrationState *s; @@ -2620,6 +2733,15 @@ bool migrate_background_snapshot(void) return s->enabled_capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]; } +bool migrate_postcopy_preempt(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]; +} + /* migration thread support */ /* * Something bad happened to the RP stream, mark an error @@ -2652,7 +2774,7 @@ static struct rp_cmd_args { static void migrate_handle_rp_req_pages(MigrationState *ms, const char* rbname, ram_addr_t start, size_t len) { - long our_host_ps = qemu_real_host_page_size; + long our_host_ps = qemu_real_host_page_size(); trace_migrate_handle_rp_req_pages(rbname, start, len); @@ -2718,8 +2840,11 @@ static int migrate_handle_rp_resume_ack(MigrationState *s, uint32_t value) return 0; } -/* Release ms->rp_state.from_dst_file in a safe way */ -static void migration_release_from_dst_file(MigrationState *ms) +/* + * Release ms->rp_state.from_dst_file (and postcopy_qemufile_src if + * existed) in a safe way. + */ +static void migration_release_dst_files(MigrationState *ms) { QEMUFile *file; @@ -2732,6 +2857,18 @@ static void migration_release_from_dst_file(MigrationState *ms) ms->rp_state.from_dst_file = NULL; } + /* + * Do the same to postcopy fast path socket too if there is. No + * locking needed because this qemufile should only be managed by + * return path thread. + */ + if (ms->postcopy_qemufile_src) { + migration_ioc_unregister_yank_from_file(ms->postcopy_qemufile_src); + qemu_file_shutdown(ms->postcopy_qemufile_src); + qemu_fclose(ms->postcopy_qemufile_src); + ms->postcopy_qemufile_src = NULL; + } + qemu_fclose(file); } @@ -2876,7 +3013,7 @@ static void *source_return_path_thread(void *opaque) * Maybe there is something we can do: it looks like a * network down issue, and we pause for a recovery. */ - migration_release_from_dst_file(ms); + migration_release_dst_files(ms); rp = NULL; if (postcopy_pause_return_path_thread(ms)) { /* @@ -2894,7 +3031,7 @@ static void *source_return_path_thread(void *opaque) } trace_source_return_path_thread_end(); - migration_release_from_dst_file(ms); + migration_release_dst_files(ms); rcu_unregister_thread(); return NULL; } @@ -2959,6 +3096,12 @@ static int postcopy_start(MigrationState *ms) int64_t bandwidth = migrate_max_postcopy_bandwidth(); bool restart_block = false; int cur_state = MIGRATION_STATUS_ACTIVE; + + if (postcopy_preempt_wait_channel(ms)) { + migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED); + return -1; + } + if (!migrate_pause_before_switchover()) { migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_POSTCOPY_ACTIVE); @@ -3032,7 +3175,7 @@ static int postcopy_start(MigrationState *ms) */ bioc = qio_channel_buffer_new(4096); qio_channel_set_name(QIO_CHANNEL(bioc), "migration-postcopy-buffer"); - fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc)); + fb = qemu_file_new_output(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); /* @@ -3098,6 +3241,8 @@ static int postcopy_start(MigrationState *ms) MIGRATION_STATUS_FAILED); } + trace_postcopy_preempt_enabled(migrate_postcopy_preempt()); + return ret; fail_closefb: @@ -3210,6 +3355,11 @@ static void migration_completion(MigrationState *s) qemu_savevm_state_complete_postcopy(s->to_dst_file); qemu_mutex_unlock_iothread(); + /* Shutdown the postcopy fast path thread */ + if (migrate_postcopy_preempt()) { + postcopy_preempt_shutdown_file(s); + } + trace_migration_completion_postcopy_end_after_complete(); } else { goto fail; @@ -3421,6 +3571,14 @@ static MigThrError postcopy_pause(MigrationState *s) if (s->state == MIGRATION_STATUS_POSTCOPY_RECOVER) { /* Woken up by a recover procedure. Give it a shot */ + if (postcopy_preempt_wait_channel(s)) { + /* + * Preempt enabled, and new channel create failed; loop + * back to wait for another recovery. + */ + continue; + } + /* * Firstly, let's wake up the return path now, with a new * return path channel. @@ -3459,8 +3617,13 @@ static MigThrError migration_detect_error(MigrationState *s) return MIG_THR_ERR_FATAL; } - /* Try to detect any file errors */ - ret = qemu_file_get_error_obj(s->to_dst_file, &local_error); + /* + * Try to detect any file errors. Note that postcopy_qemufile_src will + * be NULL when postcopy preempt is not enabled. + */ + ret = qemu_file_get_error_obj_any(s->to_dst_file, + s->postcopy_qemufile_src, + &local_error); if (!ret) { /* Everything is fine */ assert(!local_error); @@ -3495,7 +3658,8 @@ static MigThrError migration_detect_error(MigrationState *s) /* How many bytes have we transferred since the beginning of the migration */ static uint64_t migration_total_bytes(MigrationState *s) { - return qemu_ftell(s->to_dst_file) + ram_counters.multifd_bytes; + return qemu_file_total_transferred(s->to_dst_file) + + ram_counters.multifd_bytes; } static void migration_calculate_complete(MigrationState *s) @@ -3921,7 +4085,7 @@ static void *bg_migration_thread(void *opaque) */ s->bioc = qio_channel_buffer_new(512 * 1024); qio_channel_set_name(QIO_CHANNEL(s->bioc), "vmstate-buffer"); - fb = qemu_fopen_channel_output(QIO_CHANNEL(s->bioc)); + fb = qemu_file_new_output(QIO_CHANNEL(s->bioc)); object_unref(OBJECT(s->bioc)); update_iteration_initial_status(s); @@ -4097,6 +4261,15 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) } } + /* This needs to be done before resuming a postcopy */ + if (postcopy_preempt_setup(s, &local_err)) { + error_report_err(local_err); + migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, + MIGRATION_STATUS_FAILED); + migrate_fd_cleanup(s); + return; + } + if (resume) { /* Wakeup the main migration thread to do the recovery */ migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_PAUSED, @@ -4221,6 +4394,9 @@ static Property migration_properties[] = { DEFINE_PROP_SIZE("announce-step", MigrationState, parameters.announce_step, DEFAULT_MIGRATE_ANNOUNCE_STEP), + DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds), + DEFINE_PROP_STRING("tls-hostname", MigrationState, parameters.tls_hostname), + DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz), /* Migration capabilities */ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), @@ -4230,6 +4406,8 @@ static Property migration_properties[] = { DEFINE_PROP_MIG_CAP("x-compress", MIGRATION_CAPABILITY_COMPRESS), DEFINE_PROP_MIG_CAP("x-events", MIGRATION_CAPABILITY_EVENTS), DEFINE_PROP_MIG_CAP("x-postcopy-ram", MIGRATION_CAPABILITY_POSTCOPY_RAM), + DEFINE_PROP_MIG_CAP("x-postcopy-preempt", + MIGRATION_CAPABILITY_POSTCOPY_PREEMPT), DEFINE_PROP_MIG_CAP("x-colo", MIGRATION_CAPABILITY_X_COLO), DEFINE_PROP_MIG_CAP("x-release-ram", MIGRATION_CAPABILITY_RELEASE_RAM), DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK), @@ -4237,6 +4415,10 @@ static Property migration_properties[] = { DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD), DEFINE_PROP_MIG_CAP("x-background-snapshot", MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT), +#ifdef CONFIG_LINUX + DEFINE_PROP_MIG_CAP("x-zero-copy-send", + MIGRATION_CAPABILITY_ZERO_COPY_SEND), +#endif DEFINE_PROP_END_OF_LIST(), }; @@ -4252,18 +4434,16 @@ static void migration_class_init(ObjectClass *klass, void *data) static void migration_instance_finalize(Object *obj) { MigrationState *ms = MIGRATION_OBJ(obj); - MigrationParameters *params = &ms->parameters; qemu_mutex_destroy(&ms->error_mutex); qemu_mutex_destroy(&ms->qemu_file_lock); - g_free(params->tls_hostname); - g_free(params->tls_creds); qemu_sem_destroy(&ms->wait_unplug_sem); qemu_sem_destroy(&ms->rate_limit_sem); qemu_sem_destroy(&ms->pause_sem); qemu_sem_destroy(&ms->postcopy_pause_sem); qemu_sem_destroy(&ms->postcopy_pause_rp_sem); qemu_sem_destroy(&ms->rp_state.rp_sem); + qemu_sem_destroy(&ms->postcopy_qemufile_src_sem); error_free(ms->error); } @@ -4284,6 +4464,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; @@ -4310,6 +4491,7 @@ static void migration_instance_init(Object *obj) qemu_sem_init(&ms->rp_state.rp_sem, 0); qemu_sem_init(&ms->rate_limit_sem, 0); qemu_sem_init(&ms->wait_unplug_sem, 0); + qemu_sem_init(&ms->postcopy_qemufile_src_sem, 0); qemu_mutex_init(&ms->qemu_file_lock); } diff --git a/migration/migration.h b/migration/migration.h index 2de861df010e..ae4ffd34546c 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -23,6 +23,7 @@ #include "io/channel-buffer.h" #include "net/announce.h" #include "qom/object.h" +#include "postcopy-ram.h" struct PostcopyBlocktimeContext; @@ -67,7 +68,7 @@ typedef struct { struct MigrationIncomingState { QEMUFile *from_src_file; /* Previously received RAM's RAMBlock pointer */ - RAMBlock *last_recv_block; + RAMBlock *last_recv_block[RAM_CHANNEL_MAX]; /* A hook to allow cleanup at the end of incoming migration */ void *transport_data; void (*transport_cleanup)(void *data); @@ -112,6 +113,23 @@ struct MigrationIncomingState { * enabled. */ unsigned int postcopy_channels; + /* QEMUFile for postcopy only; it'll be handled by a separate thread */ + QEMUFile *postcopy_qemufile_dst; + /* Postcopy priority thread is used to receive postcopy requested pages */ + QemuThread postcopy_prio_thread; + bool postcopy_prio_thread_created; + /* + * Used to sync between the ram load main thread and the fast ram load + * thread. It protects postcopy_qemufile_dst, which is the postcopy + * fast channel. + * + * The ram fast load thread will take it mostly for the whole lifecycle + * because it needs to continuously read data from the channel, and + * it'll only release this mutex if postcopy is interrupted, so that + * the ram load main thread will take this mutex over and properly + * release the broken channel. + */ + QemuMutex postcopy_prio_thread_mutex; /* * An array of temp host huge pages to be used, one for each postcopy * channel. @@ -139,9 +157,15 @@ struct MigrationIncomingState { struct PostcopyBlocktimeContext *blocktime_ctx; /* notify PAUSED postcopy incoming migrations to try to continue */ - bool postcopy_recover_triggered; QemuSemaphore postcopy_pause_sem_dst; QemuSemaphore postcopy_pause_sem_fault; + /* + * This semaphore is used to allow the ram fast load thread (only when + * postcopy preempt is enabled) fall into sleep when there's network + * interruption detected. When the recovery is done, the main load + * thread will kick the fast ram load thread using this semaphore. + */ + QemuSemaphore postcopy_pause_sem_fast_load; /* List of listening socket addresses */ SocketAddressList *socket_address_list; @@ -193,6 +217,15 @@ struct MigrationState { QEMUBH *cleanup_bh; /* Protected by qemu_file_lock */ QEMUFile *to_dst_file; + /* Postcopy specific transfer channel */ + QEMUFile *postcopy_qemufile_src; + /* + * It is posted when the preempt channel is established. Note: this is + * used for both the start or recover of a postcopy migration. We'll + * post to this sem every time a new preempt channel is created in the + * main thread, and we keep post() and wait() in pair. + */ + QemuSemaphore postcopy_qemufile_src_sem; QIOChannelBuffer *bioc; /* * Protects to_dst_file/from_dst_file pointers. We need to make sure we @@ -376,6 +409,12 @@ MultiFDCompression migrate_multifd_compression(void); int migrate_multifd_zlib_level(void); int migrate_multifd_zstd_level(void); +#ifdef CONFIG_LINUX +bool migrate_use_zero_copy_send(void); +#else +#define migrate_use_zero_copy_send() (false) +#endif +int migrate_use_tls(void); int migrate_use_xbzrle(void); uint64_t migrate_xbzrle_cache_size(void); bool migrate_colo_enabled(void); @@ -395,6 +434,7 @@ int migrate_decompress_threads(void); bool migrate_use_events(void); bool migrate_postcopy_blocktime(void); bool migrate_background_snapshot(void); +bool migrate_postcopy_preempt(void); /* Sending on the return path - generic and then for each message type */ void migrate_send_rp_shut(MigrationIncomingState *mis, @@ -430,4 +470,7 @@ void migration_cancel(const Error *error); void populate_vfio_info(MigrationInfo *info); void postcopy_temp_page_reset(PostcopyTmpPage *tmp_page); +bool migrate_multi_channels_is_allowed(void); +void migrate_protocol_allow_multi_channels(bool allow); + #endif diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c index 3a7ae44485de..37770248e182 100644 --- a/migration/multifd-zlib.c +++ b/migration/multifd-zlib.c @@ -27,6 +27,8 @@ struct zlib_data { uint8_t *zbuff; /* size of compressed buffer */ uint32_t zbuff_len; + /* uncompressed buffer of size qemu_target_page_size() */ + uint8_t *buf; }; /* Multifd zlib compression */ @@ -45,26 +47,38 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp) { struct zlib_data *z = g_new0(struct zlib_data, 1); z_stream *zs = &z->zs; + const char *err_msg; zs->zalloc = Z_NULL; zs->zfree = Z_NULL; zs->opaque = Z_NULL; if (deflateInit(zs, migrate_multifd_zlib_level()) != Z_OK) { - g_free(z); - error_setg(errp, "multifd %u: deflate init failed", p->id); - return -1; + err_msg = "deflate init failed"; + goto err_free_z; } /* This is the maxium size of the compressed buffer */ z->zbuff_len = compressBound(MULTIFD_PACKET_SIZE); z->zbuff = g_try_malloc(z->zbuff_len); if (!z->zbuff) { - deflateEnd(&z->zs); - g_free(z); - error_setg(errp, "multifd %u: out of memory for zbuff", p->id); - return -1; + err_msg = "out of memory for zbuff"; + goto err_deflate_end; + } + z->buf = g_try_malloc(qemu_target_page_size()); + if (!z->buf) { + err_msg = "out of memory for buf"; + goto err_free_zbuff; } p->data = z; return 0; + +err_free_zbuff: + g_free(z->zbuff); +err_deflate_end: + deflateEnd(&z->zs); +err_free_z: + g_free(z); + error_setg(errp, "multifd %u: %s", p->id, err_msg); + return -1; } /** @@ -82,6 +96,8 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp) deflateEnd(&z->zs); g_free(z->zbuff); z->zbuff = NULL; + g_free(z->buf); + z->buf = NULL; g_free(p->data); p->data = NULL; } @@ -100,7 +116,6 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp) static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) { struct zlib_data *z = p->data; - size_t page_size = qemu_target_page_size(); z_stream *zs = &z->zs; uint32_t out_size = 0; int ret; @@ -114,8 +129,14 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) flush = Z_SYNC_FLUSH; } - zs->avail_in = page_size; - zs->next_in = p->pages->block->host + p->normal[i]; + /* + * Since the VM might be running, the page may be changing concurrently + * with compression. zlib does not guarantee that this is safe, + * therefore copy the page before calling deflate(). + */ + memcpy(z->buf, p->pages->block->host + p->normal[i], p->page_size); + zs->avail_in = p->page_size; + zs->next_in = z->buf; zs->avail_out = available; zs->next_out = z->zbuff + out_size; @@ -220,12 +241,11 @@ static void zlib_recv_cleanup(MultiFDRecvParams *p) static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) { struct zlib_data *z = p->data; - size_t page_size = qemu_target_page_size(); z_stream *zs = &z->zs; uint32_t in_size = p->next_packet_size; /* we measure the change of total_out */ uint32_t out_size = zs->total_out; - uint32_t expected_size = p->normal_num * page_size; + uint32_t expected_size = p->normal_num * p->page_size; uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; int ret; int i; @@ -252,7 +272,7 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) flush = Z_SYNC_FLUSH; } - zs->avail_out = page_size; + zs->avail_out = p->page_size; zs->next_out = p->host + p->normal[i]; /* @@ -266,8 +286,8 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) do { ret = inflate(zs, flush); } while (ret == Z_OK && zs->avail_in - && (zs->total_out - start) < page_size); - if (ret == Z_OK && (zs->total_out - start) < page_size) { + && (zs->total_out - start) < p->page_size); + if (ret == Z_OK && (zs->total_out - start) < p->page_size) { error_setg(errp, "multifd %u: inflate generated too few output", p->id); return -1; diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c index d788d309f22e..f4a8e1ed1fa5 100644 --- a/migration/multifd-zstd.c +++ b/migration/multifd-zstd.c @@ -113,7 +113,6 @@ static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp) static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) { struct zstd_data *z = p->data; - size_t page_size = qemu_target_page_size(); int ret; uint32_t i; @@ -128,7 +127,7 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) flush = ZSTD_e_flush; } z->in.src = p->pages->block->host + p->normal[i]; - z->in.size = page_size; + z->in.size = p->page_size; z->in.pos = 0; /* @@ -241,8 +240,7 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) { uint32_t in_size = p->next_packet_size; uint32_t out_size = 0; - size_t page_size = qemu_target_page_size(); - uint32_t expected_size = p->normal_num * page_size; + uint32_t expected_size = p->normal_num * p->page_size; uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; struct zstd_data *z = p->data; int ret; @@ -265,7 +263,7 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) for (i = 0; i < p->normal_num; i++) { z->out.dst = p->host + p->normal[i]; - z->out.size = page_size; + z->out.size = p->page_size; z->out.pos = 0; /* @@ -279,8 +277,8 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) do { ret = ZSTD_decompressStream(z->zds, &z->out, &z->in); } while (ret > 0 && (z->in.size - z->in.pos > 0) - && (z->out.pos < page_size)); - if (ret > 0 && (z->out.pos < page_size)) { + && (z->out.pos < p->page_size)); + if (ret > 0 && (z->out.pos < p->page_size)) { error_setg(errp, "multifd %u: decompressStream buffer too small", p->id); return -1; diff --git a/migration/multifd.c b/migration/multifd.c index 76b57a717787..000ca4d4ec62 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -87,15 +87,14 @@ static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) { MultiFDPages_t *pages = p->pages; - size_t page_size = qemu_target_page_size(); for (int i = 0; i < p->normal_num; i++) { p->iov[p->iovs_num].iov_base = pages->block->host + p->normal[i]; - p->iov[p->iovs_num].iov_len = page_size; + p->iov[p->iovs_num].iov_len = p->page_size; p->iovs_num++; } - p->next_packet_size = p->normal_num * page_size; + p->next_packet_size = p->normal_num * p->page_size; p->flags |= MULTIFD_FLAG_NOCOMP; return 0; } @@ -139,7 +138,6 @@ static void nocomp_recv_cleanup(MultiFDRecvParams *p) static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) { uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; - size_t page_size = qemu_target_page_size(); if (flags != MULTIFD_FLAG_NOCOMP) { error_setg(errp, "multifd %u: flags received %x flags expected %x", @@ -148,7 +146,7 @@ static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) } for (int i = 0; i < p->normal_num; i++) { p->iov[i].iov_base = p->host + p->normal[i]; - p->iov[i].iov_len = page_size; + p->iov[i].iov_len = p->page_size; } return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp); } @@ -281,8 +279,6 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) { MultiFDPacket_t *packet = p->packet; - size_t page_size = qemu_target_page_size(); - uint32_t page_count = MULTIFD_PACKET_SIZE / page_size; RAMBlock *block; int i; @@ -309,10 +305,10 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) * If we received a packet that is 100 times bigger than expected * just stop migration. It is a magic number. */ - if (packet->pages_alloc > page_count) { + if (packet->pages_alloc > p->page_count) { error_setg(errp, "multifd: received packet " "with size %u and expected a size of %u", - packet->pages_alloc, page_count) ; + packet->pages_alloc, p->page_count) ; return -1; } @@ -344,7 +340,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) for (i = 0; i < p->normal_num; i++) { uint64_t offset = be64_to_cpu(packet->offset[i]); - if (offset > (block->used_length - page_size)) { + if (offset > (block->used_length - p->page_size)) { error_setg(errp, "multifd: offset too long %" PRIu64 " (max " RAM_ADDR_FMT ")", offset, block->used_length); @@ -433,11 +429,10 @@ static int multifd_send_pages(QEMUFile *f) p->packet_num = multifd_send_state->packet_num++; multifd_send_state->pages = p->pages; p->pages = pages; - transferred = ((uint64_t) pages->num) * qemu_target_page_size() - + p->packet_len; - qemu_file_update_transfer(f, transferred); + transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len; + qemu_file_acct_rate_limit(f, transferred); ram_counters.multifd_bytes += transferred; - ram_counters.transferred += transferred; + stat64_add(&ram_atomic_counters.transferred, transferred); qemu_mutex_unlock(&p->mutex); qemu_sem_post(&p->sem); @@ -517,7 +512,7 @@ void multifd_save_cleanup(void) { int i; - if (!migrate_use_multifd() || !migrate_multifd_is_allowed()) { + if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { return; } multifd_send_terminate_threads(NULL); @@ -542,8 +537,6 @@ void multifd_save_cleanup(void) qemu_sem_destroy(&p->sem_sync); g_free(p->name); p->name = NULL; - g_free(p->tls_hostname); - p->tls_hostname = NULL; multifd_pages_clear(p->pages); p->pages = NULL; p->packet_len = 0; @@ -568,19 +561,51 @@ void multifd_save_cleanup(void) multifd_send_state = NULL; } -void multifd_send_sync_main(QEMUFile *f) +static int multifd_zero_copy_flush(QIOChannel *c) +{ + int ret; + Error *err = NULL; + + ret = qio_channel_flush(c, &err); + if (ret < 0) { + error_report_err(err); + return -1; + } + if (ret == 1) { + dirty_sync_missed_zero_copy(); + } + + return ret; +} + +int multifd_send_sync_main(QEMUFile *f) { int i; + bool flush_zero_copy; if (!migrate_use_multifd()) { - return; + return 0; } if (multifd_send_state->pages->num) { if (multifd_send_pages(f) < 0) { error_report("%s: multifd_send_pages fail", __func__); - return; + return -1; } } + + /* + * When using zero-copy, it's necessary to flush the pages before any of + * the pages can be sent again, so we'll make sure the new version of the + * pages will always arrive _later_ than the old pages. + * + * Currently we achieve this by flushing the zero-page requested writes + * per ram iteration, but in the future we could potentially optimize it + * to be less frequent, e.g. only after we finished one whole scanning of + * all the dirty bitmaps. + */ + + flush_zero_copy = migrate_use_zero_copy_send(); + for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; @@ -591,17 +616,21 @@ void multifd_send_sync_main(QEMUFile *f) if (p->quit) { error_report("%s: channel %d has already quit", __func__, i); qemu_mutex_unlock(&p->mutex); - return; + return -1; } p->packet_num = multifd_send_state->packet_num++; p->flags |= MULTIFD_FLAG_SYNC; p->pending_job++; - qemu_file_update_transfer(f, p->packet_len); + qemu_file_acct_rate_limit(f, p->packet_len); ram_counters.multifd_bytes += p->packet_len; - ram_counters.transferred += p->packet_len; + stat64_add(&ram_atomic_counters.transferred, p->packet_len); qemu_mutex_unlock(&p->mutex); qemu_sem_post(&p->sem); + + if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) { + return -1; + } } for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; @@ -610,6 +639,8 @@ void multifd_send_sync_main(QEMUFile *f) qemu_sem_wait(&p->sem_sync); } trace_multifd_send_sync_main(multifd_send_state->packet_num); + + return 0; } static void *multifd_send_thread(void *opaque) @@ -617,6 +648,7 @@ static void *multifd_send_thread(void *opaque) MultiFDSendParams *p = opaque; Error *local_err = NULL; int ret = 0; + bool use_zero_copy_send = migrate_use_zero_copy_send(); trace_multifd_send_thread_start(p->id); rcu_register_thread(); @@ -639,9 +671,14 @@ static void *multifd_send_thread(void *opaque) if (p->pending_job) { uint64_t packet_num = p->packet_num; uint32_t flags = p->flags; - p->iovs_num = 1; p->normal_num = 0; + if (use_zero_copy_send) { + p->iovs_num = 0; + } else { + p->iovs_num = 1; + } + for (int i = 0; i < p->pages->num; i++) { p->normal[p->normal_num] = p->pages->offset[i]; p->normal_num++; @@ -665,11 +702,21 @@ static void *multifd_send_thread(void *opaque) trace_multifd_send(p->id, packet_num, p->normal_num, flags, p->next_packet_size); - p->iov[0].iov_len = p->packet_len; - p->iov[0].iov_base = p->packet; + if (use_zero_copy_send) { + /* Send header first, without zerocopy */ + ret = qio_channel_write_all(p->c, (void *)p->packet, + p->packet_len, &local_err); + if (ret != 0) { + break; + } + } else { + /* Send header using the same writev call */ + p->iov[0].iov_len = p->packet_len; + p->iov[0].iov_base = p->packet; + } - ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, - &local_err); + ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num, NULL, + 0, p->write_flags, &local_err); if (ret != 0) { break; } @@ -763,7 +810,7 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p, Error **errp) { MigrationState *s = migrate_get_current(); - const char *hostname = p->tls_hostname; + const char *hostname = s->hostname; QIOChannelTLS *tioc; tioc = migration_tls_client_create(s, ioc, hostname, errp); @@ -784,16 +831,12 @@ static bool multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc, Error *error) { - MigrationState *s = migrate_get_current(); - trace_multifd_set_outgoing_channel( - ioc, object_get_typename(OBJECT(ioc)), p->tls_hostname, error); + ioc, object_get_typename(OBJECT(ioc)), + migrate_get_current()->hostname, error); if (!error) { - if (s->parameters.tls_creds && - *s->parameters.tls_creds && - !object_dynamic_cast(OBJECT(ioc), - TYPE_QIO_CHANNEL_TLS)) { + if (migrate_channel_requires_tls_upgrade(ioc)) { multifd_tls_channel_connect(p, ioc, &error); if (!error) { /* @@ -858,33 +901,20 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) multifd_new_send_channel_cleanup(p, sioc, local_err); } -static bool migrate_allow_multifd = true; -void migrate_protocol_allow_multifd(bool allow) -{ - migrate_allow_multifd = allow; -} - -bool migrate_multifd_is_allowed(void) -{ - return migrate_allow_multifd; -} - int multifd_save_setup(Error **errp) { int thread_count; uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); uint8_t i; - MigrationState *s; if (!migrate_use_multifd()) { return 0; } - if (!migrate_multifd_is_allowed()) { + if (!migrate_multi_channels_is_allowed()) { error_setg(errp, "multifd is not supported by current protocol"); return -1; } - s = migrate_get_current(); thread_count = migrate_multifd_channels(); multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); @@ -909,10 +939,18 @@ int multifd_save_setup(Error **errp) p->packet->magic = cpu_to_be32(MULTIFD_MAGIC); p->packet->version = cpu_to_be32(MULTIFD_VERSION); p->name = g_strdup_printf("multifdsend_%d", i); - p->tls_hostname = g_strdup(s->hostname); /* We need one extra place for the packet header */ p->iov = g_new0(struct iovec, page_count + 1); p->normal = g_new0(ram_addr_t, page_count); + p->page_size = qemu_target_page_size(); + p->page_count = page_count; + + if (migrate_use_zero_copy_send()) { + p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; + } else { + p->write_flags = 0; + } + socket_send_channel_create(multifd_new_send_channel_async, p); } @@ -980,7 +1018,7 @@ int multifd_load_cleanup(Error **errp) { int i; - if (!migrate_use_multifd() || !migrate_multifd_is_allowed()) { + if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { return 0; } multifd_recv_terminate_threads(NULL); @@ -1129,7 +1167,7 @@ int multifd_load_setup(Error **errp) if (!migrate_use_multifd()) { return 0; } - if (!migrate_multifd_is_allowed()) { + if (!migrate_multi_channels_is_allowed()) { error_setg(errp, "multifd is not supported by current protocol"); return -1; } @@ -1153,6 +1191,8 @@ int multifd_load_setup(Error **errp) p->name = g_strdup_printf("multifdrecv_%d", i); p->iov = g_new0(struct iovec, page_count); p->normal = g_new0(ram_addr_t, page_count); + p->page_count = page_count; + p->page_size = qemu_target_page_size(); } for (i = 0; i < thread_count; i++) { diff --git a/migration/multifd.h b/migration/multifd.h index 4dda900a0b4a..e2802a9ce2b7 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -13,8 +13,6 @@ #ifndef QEMU_MIGRATION_MULTIFD_H #define QEMU_MIGRATION_MULTIFD_H -bool migrate_multifd_is_allowed(void); -void migrate_protocol_allow_multifd(bool allow); int multifd_save_setup(Error **errp); void multifd_save_cleanup(void); int multifd_load_setup(Error **errp); @@ -22,7 +20,7 @@ int multifd_load_cleanup(Error **errp); bool multifd_recv_all_channels_created(void); bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp); void multifd_recv_sync_main(void); -void multifd_send_sync_main(QEMUFile *f); +int multifd_send_sync_main(QEMUFile *f); int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset); /* Multifd Compression flags */ @@ -67,48 +65,62 @@ typedef struct { } MultiFDPages_t; typedef struct { - /* this fields are not changed once the thread is created */ + /* Fields are only written at creating/deletion time */ + /* No lock required for them, they are read only */ + /* channel number */ uint8_t id; /* channel thread name */ char *name; - /* tls hostname */ - char *tls_hostname; /* channel thread id */ QemuThread thread; /* communication channel */ QIOChannel *c; + /* is the yank function registered */ + bool registered_yank; + /* packet allocated len */ + uint32_t packet_len; + /* guest page size */ + uint32_t page_size; + /* number of pages in a full packet */ + uint32_t page_count; + /* multifd flags for sending ram */ + int write_flags; + /* sem where to wait for more work */ QemuSemaphore sem; + /* syncs main thread and channels */ + QemuSemaphore sem_sync; + /* this mutex protects the following parameters */ QemuMutex mutex; /* is this channel thread running */ bool running; /* should this thread finish */ bool quit; - /* is the yank function registered */ - bool registered_yank; + /* multifd flags for each packet */ + uint32_t flags; + /* global number of generated multifd packets */ + uint64_t packet_num; /* thread has work to do */ int pending_job; - /* array of pages to sent */ + /* array of pages to sent. + * The owner of 'pages' depends of 'pending_job' value: + * pending_job == 0 -> migration_thread can use it. + * pending_job != 0 -> multifd_channel can use it. + */ MultiFDPages_t *pages; - /* packet allocated len */ - uint32_t packet_len; + + /* thread local variables. No locking required */ + /* pointer to the packet */ MultiFDPacket_t *packet; - /* multifd flags for each packet */ - uint32_t flags; /* size of the next packet that contains pages */ uint32_t next_packet_size; - /* global number of generated multifd packets */ - uint64_t packet_num; - /* thread local variables */ /* packets sent through this channel */ uint64_t num_packets; /* non zero pages sent through this channel */ uint64_t total_normal_pages; - /* syncs main thread and channels */ - QemuSemaphore sem_sync; /* buffers to send */ struct iovec *iov; /* number of iovs used */ @@ -122,7 +134,9 @@ typedef struct { } MultiFDSendParams; typedef struct { - /* this fields are not changed once the thread is created */ + /* Fields are only written at creating/deletion time */ + /* No lock required for them, they are read only */ + /* channel number */ uint8_t id; /* channel thread name */ @@ -131,31 +145,39 @@ typedef struct { QemuThread thread; /* communication channel */ QIOChannel *c; + /* packet allocated len */ + uint32_t packet_len; + /* guest page size */ + uint32_t page_size; + /* number of pages in a full packet */ + uint32_t page_count; + + /* syncs main thread and channels */ + QemuSemaphore sem_sync; + /* this mutex protects the following parameters */ QemuMutex mutex; /* is this channel thread running */ bool running; /* should this thread finish */ bool quit; - /* ramblock host address */ - uint8_t *host; - /* packet allocated len */ - uint32_t packet_len; - /* pointer to the packet */ - MultiFDPacket_t *packet; /* multifd flags for each packet */ uint32_t flags; /* global number of generated multifd packets */ uint64_t packet_num; - /* thread local variables */ + + /* thread local variables. No locking required */ + + /* pointer to the packet */ + MultiFDPacket_t *packet; /* size of the next packet that contains pages */ uint32_t next_packet_size; /* packets sent through this channel */ uint64_t num_packets; + /* ramblock host address */ + uint8_t *host; /* non zero pages recv through this channel */ uint64_t total_normal_pages; - /* syncs main thread and channels */ - QemuSemaphore sem_sync; /* buffers to recv */ struct iovec *iov; /* Pages that are not zero */ diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 32c52f4b1d9e..b9a37ef25581 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -33,6 +33,10 @@ #include "trace.h" #include "hw/boards.h" #include "exec/ramblock.h" +#include "socket.h" +#include "qemu-file.h" +#include "yank_functions.h" +#include "tls.h" /* Arbitrary limit on size of each discard command, * keeps them around ~200 bytes @@ -319,7 +323,7 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis) return false; } - if (qemu_real_host_page_size != ram_pagesize_summary()) { + if (qemu_real_host_page_size() != ram_pagesize_summary()) { bool have_hp = false; /* We've got a huge page */ #ifdef UFFD_FEATURE_MISSING_HUGETLBFS @@ -357,7 +361,7 @@ static int test_ramblock_postcopiable(RAMBlock *rb, void *opaque) */ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) { - long pagesize = qemu_real_host_page_size; + long pagesize = qemu_real_host_page_size(); int ufd = -1; bool ret = false; /* Error unless we change it */ void *testarea = NULL; @@ -567,6 +571,11 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) { trace_postcopy_ram_incoming_cleanup_entry(); + if (mis->postcopy_prio_thread_created) { + qemu_thread_join(&mis->postcopy_prio_thread); + mis->postcopy_prio_thread_created = false; + } + if (mis->have_fault_thread) { Error *local_err = NULL; @@ -1102,8 +1111,13 @@ static int postcopy_temp_pages_setup(MigrationIncomingState *mis) int err, i, channels; void *temp_page; - /* TODO: will be boosted when enable postcopy preemption */ - mis->postcopy_channels = 1; + if (migrate_postcopy_preempt()) { + /* If preemption enabled, need extra channel for urgent requests */ + mis->postcopy_channels = RAM_CHANNEL_MAX; + } else { + /* Both precopy/postcopy on the same channel */ + mis->postcopy_channels = 1; + } channels = mis->postcopy_channels; mis->postcopy_tmp_pages = g_malloc0_n(sizeof(PostcopyTmpPage), channels); @@ -1170,7 +1184,7 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis) return -1; } - postcopy_thread_create(mis, &mis->fault_thread, "postcopy/fault", + postcopy_thread_create(mis, &mis->fault_thread, "fault-default", postcopy_ram_fault_thread, QEMU_THREAD_JOINABLE); mis->have_fault_thread = true; @@ -1185,6 +1199,16 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis) return -1; } + if (migrate_postcopy_preempt()) { + /* + * This thread needs to be created after the temp pages because + * it'll fetch RAM_CHANNEL_POSTCOPY PostcopyTmpPage immediately. + */ + postcopy_thread_create(mis, &mis->postcopy_prio_thread, "fault-fast", + postcopy_preempt_thread, QEMU_THREAD_JOINABLE); + mis->postcopy_prio_thread_created = true; + } + trace_postcopy_ram_enable_notify(); return 0; @@ -1514,3 +1538,159 @@ void postcopy_unregister_shared_ufd(struct PostCopyFD *pcfd) } } } + +bool postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file) +{ + /* + * The new loading channel has its own threads, so it needs to be + * blocked too. It's by default true, just be explicit. + */ + qemu_file_set_blocking(file, true); + mis->postcopy_qemufile_dst = file; + trace_postcopy_preempt_new_channel(); + + /* Start the migration immediately */ + return true; +} + +/* + * Setup the postcopy preempt channel with the IOC. If ERROR is specified, + * setup the error instead. This helper will free the ERROR if specified. + */ +static void +postcopy_preempt_send_channel_done(MigrationState *s, + QIOChannel *ioc, Error *local_err) +{ + if (local_err) { + migrate_set_error(s, local_err); + error_free(local_err); + } else { + migration_ioc_register_yank(ioc); + s->postcopy_qemufile_src = qemu_file_new_output(ioc); + trace_postcopy_preempt_new_channel(); + } + + /* + * Kick the waiter in all cases. The waiter should check upon + * postcopy_qemufile_src to know whether it failed or not. + */ + qemu_sem_post(&s->postcopy_qemufile_src_sem); +} + +static void +postcopy_preempt_tls_handshake(QIOTask *task, gpointer opaque) +{ + g_autoptr(QIOChannel) ioc = QIO_CHANNEL(qio_task_get_source(task)); + MigrationState *s = opaque; + Error *local_err = NULL; + + qio_task_propagate_error(task, &local_err); + postcopy_preempt_send_channel_done(s, ioc, local_err); +} + +static void +postcopy_preempt_send_channel_new(QIOTask *task, gpointer opaque) +{ + g_autoptr(QIOChannel) ioc = QIO_CHANNEL(qio_task_get_source(task)); + MigrationState *s = opaque; + QIOChannelTLS *tioc; + Error *local_err = NULL; + + if (qio_task_propagate_error(task, &local_err)) { + goto out; + } + + if (migrate_channel_requires_tls_upgrade(ioc)) { + tioc = migration_tls_client_create(s, ioc, s->hostname, &local_err); + if (!tioc) { + goto out; + } + trace_postcopy_preempt_tls_handshake(); + qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-preempt"); + qio_channel_tls_handshake(tioc, postcopy_preempt_tls_handshake, + s, NULL, NULL); + /* Setup the channel until TLS handshake finished */ + return; + } + +out: + /* This handles both good and error cases */ + postcopy_preempt_send_channel_done(s, ioc, local_err); +} + +/* Returns 0 if channel established, -1 for error. */ +int postcopy_preempt_wait_channel(MigrationState *s) +{ + /* If preempt not enabled, no need to wait */ + if (!migrate_postcopy_preempt()) { + return 0; + } + + /* + * We need the postcopy preempt channel to be established before + * starting doing anything. + */ + qemu_sem_wait(&s->postcopy_qemufile_src_sem); + + return s->postcopy_qemufile_src ? 0 : -1; +} + +int postcopy_preempt_setup(MigrationState *s, Error **errp) +{ + if (!migrate_postcopy_preempt()) { + return 0; + } + + if (!migrate_multi_channels_is_allowed()) { + error_setg(errp, "Postcopy preempt is not supported as current " + "migration stream does not support multi-channels."); + return -1; + } + + /* Kick an async task to connect */ + socket_send_channel_create(postcopy_preempt_send_channel_new, s); + + return 0; +} + +static void postcopy_pause_ram_fast_load(MigrationIncomingState *mis) +{ + trace_postcopy_pause_fast_load(); + qemu_mutex_unlock(&mis->postcopy_prio_thread_mutex); + qemu_sem_wait(&mis->postcopy_pause_sem_fast_load); + qemu_mutex_lock(&mis->postcopy_prio_thread_mutex); + trace_postcopy_pause_fast_load_continued(); +} + +void *postcopy_preempt_thread(void *opaque) +{ + MigrationIncomingState *mis = opaque; + int ret; + + trace_postcopy_preempt_thread_entry(); + + rcu_register_thread(); + + qemu_sem_post(&mis->thread_sync_sem); + + /* Sending RAM_SAVE_FLAG_EOS to terminate this thread */ + qemu_mutex_lock(&mis->postcopy_prio_thread_mutex); + while (1) { + ret = ram_load_postcopy(mis->postcopy_qemufile_dst, + RAM_CHANNEL_POSTCOPY); + /* If error happened, go into recovery routine */ + if (ret) { + postcopy_pause_ram_fast_load(mis); + } else { + /* We're done */ + break; + } + } + qemu_mutex_unlock(&mis->postcopy_prio_thread_mutex); + + rcu_unregister_thread(); + + trace_postcopy_preempt_thread_exit(); + + return NULL; +} diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h index 07684c0e1dd1..6147bf7d1d0c 100644 --- a/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -183,4 +183,15 @@ int postcopy_wake_shared(struct PostCopyFD *pcfd, uint64_t client_addr, int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb, uint64_t client_addr, uint64_t offset); +/* Hard-code channels for now for postcopy preemption */ +enum PostcopyChannels { + RAM_CHANNEL_PRECOPY = 0, + RAM_CHANNEL_POSTCOPY = 1, + RAM_CHANNEL_MAX, +}; + +bool postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file); +int postcopy_preempt_setup(MigrationState *s, Error **errp); +int postcopy_preempt_wait_channel(MigrationState *s); + #endif diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c deleted file mode 100644 index bb5a5752df2e..000000000000 --- a/migration/qemu-file-channel.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * QEMUFile backend for QIOChannel objects - * - * Copyright (c) 2015-2016 Red Hat, Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qemu-file-channel.h" -#include "qemu-file.h" -#include "io/channel-socket.h" -#include "io/channel-tls.h" -#include "qemu/iov.h" -#include "qemu/yank.h" -#include "yank_functions.h" - - -static ssize_t channel_writev_buffer(void *opaque, - struct iovec *iov, - int iovcnt, - int64_t pos, - Error **errp) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - ssize_t done = 0; - struct iovec *local_iov = g_new(struct iovec, iovcnt); - struct iovec *local_iov_head = local_iov; - unsigned int nlocal_iov = iovcnt; - - nlocal_iov = iov_copy(local_iov, nlocal_iov, - iov, iovcnt, - 0, iov_size(iov, iovcnt)); - - while (nlocal_iov > 0) { - ssize_t len; - len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); - if (len == QIO_CHANNEL_ERR_BLOCK) { - if (qemu_in_coroutine()) { - qio_channel_yield(ioc, G_IO_OUT); - } else { - qio_channel_wait(ioc, G_IO_OUT); - } - continue; - } - if (len < 0) { - done = -EIO; - goto cleanup; - } - - iov_discard_front(&local_iov, &nlocal_iov, len); - done += len; - } - - cleanup: - g_free(local_iov_head); - return done; -} - - -static ssize_t channel_get_buffer(void *opaque, - uint8_t *buf, - int64_t pos, - size_t size, - Error **errp) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - ssize_t ret; - - do { - ret = qio_channel_read(ioc, (char *)buf, size, errp); - if (ret < 0) { - if (ret == QIO_CHANNEL_ERR_BLOCK) { - if (qemu_in_coroutine()) { - qio_channel_yield(ioc, G_IO_IN); - } else { - qio_channel_wait(ioc, G_IO_IN); - } - } else { - return -EIO; - } - } - } while (ret == QIO_CHANNEL_ERR_BLOCK); - - return ret; -} - - -static int channel_close(void *opaque, Error **errp) -{ - int ret; - QIOChannel *ioc = QIO_CHANNEL(opaque); - ret = qio_channel_close(ioc, errp); - object_unref(OBJECT(ioc)); - return ret; -} - - -static int channel_shutdown(void *opaque, - bool rd, - bool wr, - Error **errp) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - - if (qio_channel_has_feature(ioc, - QIO_CHANNEL_FEATURE_SHUTDOWN)) { - QIOChannelShutdown mode; - if (rd && wr) { - mode = QIO_CHANNEL_SHUTDOWN_BOTH; - } else if (rd) { - mode = QIO_CHANNEL_SHUTDOWN_READ; - } else { - mode = QIO_CHANNEL_SHUTDOWN_WRITE; - } - if (qio_channel_shutdown(ioc, mode, errp) < 0) { - return -EIO; - } - } - return 0; -} - - -static int channel_set_blocking(void *opaque, - bool enabled, - Error **errp) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - - if (qio_channel_set_blocking(ioc, enabled, errp) < 0) { - return -1; - } - return 0; -} - -static QEMUFile *channel_get_input_return_path(void *opaque) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - - return qemu_fopen_channel_output(ioc); -} - -static QEMUFile *channel_get_output_return_path(void *opaque) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - - return qemu_fopen_channel_input(ioc); -} - -static const QEMUFileOps channel_input_ops = { - .get_buffer = channel_get_buffer, - .close = channel_close, - .shut_down = channel_shutdown, - .set_blocking = channel_set_blocking, - .get_return_path = channel_get_input_return_path, -}; - - -static const QEMUFileOps channel_output_ops = { - .writev_buffer = channel_writev_buffer, - .close = channel_close, - .shut_down = channel_shutdown, - .set_blocking = channel_set_blocking, - .get_return_path = channel_get_output_return_path, -}; - - -QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc) -{ - object_ref(OBJECT(ioc)); - return qemu_fopen_ops(ioc, &channel_input_ops, true); -} - -QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc) -{ - object_ref(OBJECT(ioc)); - return qemu_fopen_ops(ioc, &channel_output_ops, true); -} diff --git a/migration/qemu-file-channel.h b/migration/qemu-file-channel.h deleted file mode 100644 index 0028a09eb61f..000000000000 --- a/migration/qemu-file-channel.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * QEMUFile backend for QIOChannel objects - * - * Copyright (c) 2015-2016 Red Hat, Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef QEMU_FILE_CHANNEL_H -#define QEMU_FILE_CHANNEL_H - -#include "io/channel.h" - -QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc); -QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc); -#endif diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 1479cddad94a..2d5f74ffc226 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -35,15 +35,24 @@ #define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 64) struct QEMUFile { - const QEMUFileOps *ops; const QEMUFileHooks *hooks; - void *opaque; + QIOChannel *ioc; + bool is_writable; - int64_t bytes_xfer; - int64_t xfer_limit; + /* + * Maximum amount of data in bytes to transfer during one + * rate limiting time window + */ + int64_t rate_limit_max; + /* + * Total amount of data in bytes queued for transfer + * during this rate limiting time window + */ + int64_t rate_limit_used; + + /* The sum of bytes transferred on the wire */ + int64_t total_transferred; - int64_t pos; /* start of buffer when writing, end of buffer - when reading */ int buf_index; int buf_size; /* 0 when writing */ uint8_t buf[IO_BUF_SIZE]; @@ -56,40 +65,54 @@ struct QEMUFile { Error *last_error_obj; /* has the file has been shutdown */ bool shutdown; - /* Whether opaque points to a QIOChannel */ - bool has_ioc; }; /* * Stop a file from being read/written - not all backing files can do this * typically only sockets can. + * + * TODO: convert to propagate Error objects instead of squashing + * to a fixed errno value */ int qemu_file_shutdown(QEMUFile *f) { - int ret; + int ret = 0; f->shutdown = true; - if (!f->ops->shut_down) { - return -ENOSYS; - } - ret = f->ops->shut_down(f->opaque, true, true, NULL); + /* + * We must set qemufile error before the real shutdown(), otherwise + * there can be a race window where we thought IO all went though + * (because last_error==NULL) but actually IO has already stopped. + * + * If without correct ordering, the race can happen like this: + * + * page receiver other thread + * ------------- ------------ + * qemu_get_buffer() + * do shutdown() + * returns 0 (buffer all zero) + * (we didn't check this retcode) + * try to detect IO error + * last_error==NULL, IO okay + * install ALL-ZERO page + * set last_error + * --> guest crash! + */ if (!f->last_error) { qemu_file_set_error(f, -EIO); } - return ret; -} -/* - * Result: QEMUFile* for a 'return path' for comms in the opposite direction - * NULL if not available - */ -QEMUFile *qemu_file_get_return_path(QEMUFile *f) -{ - if (!f->ops->get_return_path) { - return NULL; + if (!qio_channel_has_feature(f->ioc, + QIO_CHANNEL_FEATURE_SHUTDOWN)) { + return -ENOSYS; } - return f->ops->get_return_path(f->opaque); + + if (qio_channel_shutdown(f->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL) < 0) { + ret = -EIO; + } + + return ret; } bool qemu_file_mode_is_not_valid(const char *mode) @@ -104,18 +127,37 @@ bool qemu_file_mode_is_not_valid(const char *mode) return false; } -QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops, bool has_ioc) +static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable) { QEMUFile *f; f = g_new0(QEMUFile, 1); - f->opaque = opaque; - f->ops = ops; - f->has_ioc = has_ioc; + object_ref(ioc); + f->ioc = ioc; + f->is_writable = is_writable; + return f; } +/* + * Result: QEMUFile* for a 'return path' for comms in the opposite direction + * NULL if not available + */ +QEMUFile *qemu_file_get_return_path(QEMUFile *f) +{ + return qemu_file_new_impl(f->ioc, !f->is_writable); +} + +QEMUFile *qemu_file_new_output(QIOChannel *ioc) +{ + return qemu_file_new_impl(ioc, true); +} + +QEMUFile *qemu_file_new_input(QIOChannel *ioc) +{ + return qemu_file_new_impl(ioc, false); +} void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks) { @@ -139,6 +181,33 @@ int qemu_file_get_error_obj(QEMUFile *f, Error **errp) return f->last_error; } +/* + * Get last error for either stream f1 or f2 with optional Error*. + * The error returned (non-zero) can be either from f1 or f2. + * + * If any of the qemufile* is NULL, then skip the check on that file. + * + * When there is no error on both qemufile, zero is returned. + */ +int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp) +{ + int ret = 0; + + if (f1) { + ret = qemu_file_get_error_obj(f1, errp); + /* If there's already error detected, return */ + if (ret) { + return ret; + } + } + + if (f2) { + ret = qemu_file_get_error_obj(f2, errp); + } + + return ret; +} + /* * Set the last error for stream f with optional Error* */ @@ -174,7 +243,7 @@ void qemu_file_set_error(QEMUFile *f, int ret) bool qemu_file_is_writable(QEMUFile *f) { - return f->ops->writev_buffer; + return f->is_writable; } static void qemu_iovec_release_ram(QEMUFile *f) @@ -212,6 +281,7 @@ static void qemu_iovec_release_ram(QEMUFile *f) memset(f->may_free, 0, sizeof(f->may_free)); } + /** * Flushes QEMUFile buffer * @@ -220,10 +290,6 @@ static void qemu_iovec_release_ram(QEMUFile *f) */ void qemu_fflush(QEMUFile *f) { - ssize_t ret = 0; - ssize_t expect = 0; - Error *local_error = NULL; - if (!qemu_file_is_writable(f)) { return; } @@ -232,22 +298,18 @@ void qemu_fflush(QEMUFile *f) return; } if (f->iovcnt > 0) { - expect = iov_size(f->iov, f->iovcnt); - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos, - &local_error); + Error *local_error = NULL; + if (qio_channel_writev_all(f->ioc, + f->iov, f->iovcnt, + &local_error) < 0) { + qemu_file_set_error_obj(f, -EIO, local_error); + } else { + f->total_transferred += iov_size(f->iov, f->iovcnt); + } qemu_iovec_release_ram(f); } - if (ret >= 0) { - f->pos += ret; - } - /* We expect the QEMUFile write impl to send the full - * data set we requested, so sanity check that. - */ - if (ret != expect) { - qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error); - } f->buf_index = 0; f->iovcnt = 0; } @@ -257,7 +319,7 @@ void ram_control_before_iterate(QEMUFile *f, uint64_t flags) int ret = 0; if (f->hooks && f->hooks->before_ram_iterate) { - ret = f->hooks->before_ram_iterate(f, f->opaque, flags, NULL); + ret = f->hooks->before_ram_iterate(f, flags, NULL); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -269,7 +331,7 @@ void ram_control_after_iterate(QEMUFile *f, uint64_t flags) int ret = 0; if (f->hooks && f->hooks->after_ram_iterate) { - ret = f->hooks->after_ram_iterate(f, f->opaque, flags, NULL); + ret = f->hooks->after_ram_iterate(f, flags, NULL); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -281,7 +343,7 @@ void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data) int ret = -EINVAL; if (f->hooks && f->hooks->hook_ram_load) { - ret = f->hooks->hook_ram_load(f, f->opaque, flags, data); + ret = f->hooks->hook_ram_load(f, flags, data); if (ret < 0) { qemu_file_set_error(f, ret); } @@ -301,16 +363,16 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, uint64_t *bytes_sent) { if (f->hooks && f->hooks->save_page) { - int ret = f->hooks->save_page(f, f->opaque, block_offset, + int ret = f->hooks->save_page(f, block_offset, offset, size, bytes_sent); if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { - f->bytes_xfer += size; + f->rate_limit_used += size; } if (ret != RAM_SAVE_CONTROL_DELAYED && ret != RAM_SAVE_CONTROL_NOT_SUPP) { if (bytes_sent && *bytes_sent > 0) { - qemu_update_position(f, *bytes_sent); + qemu_file_credit_transfer(f, *bytes_sent); } else if (ret < 0) { qemu_file_set_error(f, ret); } @@ -349,25 +411,37 @@ static ssize_t qemu_fill_buffer(QEMUFile *f) return 0; } - len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, - IO_BUF_SIZE - pending, &local_error); + do { + len = qio_channel_read(f->ioc, + (char *)f->buf + pending, + IO_BUF_SIZE - pending, + &local_error); + if (len == QIO_CHANNEL_ERR_BLOCK) { + if (qemu_in_coroutine()) { + qio_channel_yield(f->ioc, G_IO_IN); + } else { + qio_channel_wait(f->ioc, G_IO_IN); + } + } else if (len < 0) { + len = -EIO; + } + } while (len == QIO_CHANNEL_ERR_BLOCK); + if (len > 0) { f->buf_size += len; - f->pos += len; + f->total_transferred += len; } else if (len == 0) { qemu_file_set_error_obj(f, -EIO, local_error); - } else if (len != -EAGAIN) { - qemu_file_set_error_obj(f, len, local_error); } else { - error_free(local_error); + qemu_file_set_error_obj(f, len, local_error); } return len; } -void qemu_update_position(QEMUFile *f, size_t size) +void qemu_file_credit_transfer(QEMUFile *f, size_t size) { - f->pos += size; + f->total_transferred += size; } /** Closes the file @@ -380,16 +454,16 @@ void qemu_update_position(QEMUFile *f, size_t size) */ int qemu_fclose(QEMUFile *f) { - int ret; + int ret, ret2; qemu_fflush(f); ret = qemu_file_get_error(f); - if (f->ops->close) { - int ret2 = f->ops->close(f->opaque, NULL); - if (ret >= 0) { - ret = ret2; - } + ret2 = qio_channel_close(f->ioc, NULL); + if (ret >= 0) { + ret = ret2; } + g_clear_pointer(&f->ioc, object_unref); + /* If any error was spotted before closing, we should report it * instead of the close() return value. */ @@ -457,7 +531,7 @@ void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size, return; } - f->bytes_xfer += size; + f->rate_limit_used += size; add_to_iovec(f, buf, size, may_free); } @@ -475,7 +549,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size) l = size; } memcpy(f->buf + f->buf_index, buf, l); - f->bytes_xfer += l; + f->rate_limit_used += l; add_buf_to_iovec(f, l); if (qemu_file_get_error(f)) { break; @@ -492,7 +566,7 @@ void qemu_put_byte(QEMUFile *f, int v) } f->buf[f->buf_index] = v; - f->bytes_xfer++; + f->rate_limit_used++; add_buf_to_iovec(f, 1); } @@ -648,9 +722,9 @@ int qemu_get_byte(QEMUFile *f) return result; } -int64_t qemu_ftell_fast(QEMUFile *f) +int64_t qemu_file_total_transferred_fast(QEMUFile *f) { - int64_t ret = f->pos; + int64_t ret = f->total_transferred; int i; for (i = 0; i < f->iovcnt; i++) { @@ -660,10 +734,10 @@ int64_t qemu_ftell_fast(QEMUFile *f) return ret; } -int64_t qemu_ftell(QEMUFile *f) +int64_t qemu_file_total_transferred(QEMUFile *f) { qemu_fflush(f); - return f->pos; + return f->total_transferred; } int qemu_file_rate_limit(QEMUFile *f) @@ -674,7 +748,7 @@ int qemu_file_rate_limit(QEMUFile *f) if (qemu_file_get_error(f)) { return 1; } - if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) { + if (f->rate_limit_max > 0 && f->rate_limit_used > f->rate_limit_max) { return 1; } return 0; @@ -682,22 +756,22 @@ int qemu_file_rate_limit(QEMUFile *f) int64_t qemu_file_get_rate_limit(QEMUFile *f) { - return f->xfer_limit; + return f->rate_limit_max; } void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit) { - f->xfer_limit = limit; + f->rate_limit_max = limit; } void qemu_file_reset_rate_limit(QEMUFile *f) { - f->bytes_xfer = 0; + f->rate_limit_used = 0; } -void qemu_file_update_transfer(QEMUFile *f, int64_t len) +void qemu_file_acct_rate_limit(QEMUFile *f, int64_t len) { - f->bytes_xfer += len; + f->rate_limit_used += len; } void qemu_put_be16(QEMUFile *f, unsigned int v) @@ -851,19 +925,18 @@ void qemu_put_counted_string(QEMUFile *f, const char *str) */ void qemu_file_set_blocking(QEMUFile *f, bool block) { - if (f->ops->set_blocking) { - f->ops->set_blocking(f->opaque, block, NULL); - } + qio_channel_set_blocking(f->ioc, block, NULL); } /* - * Return the ioc object if it's a migration channel. Note: it can return NULL - * for callers passing in a non-migration qemufile. E.g. see qemu_fopen_bdrv() - * and its usage in e.g. load_snapshot(). So we need to check against NULL - * before using it. If without the check, migration_incoming_state_destroy() - * could fail for load_snapshot(). + * qemu_file_get_ioc: + * + * Get the ioc object for the file, without incrementing + * the reference count. + * + * Returns: the ioc object */ QIOChannel *qemu_file_get_ioc(QEMUFile *file) { - return file->has_ioc ? QIO_CHANNEL(file->opaque) : NULL; + return file->ioc; } diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 3f36d4dc8c4b..fa13d04d787c 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -29,47 +29,12 @@ #include "exec/cpu-common.h" #include "io/channel.h" -/* Read a chunk of data from a file at the given position. The pos argument - * can be ignored if the file is only be used for streaming. The number of - * bytes actually read should be returned. - */ -typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, - int64_t pos, size_t size, - Error **errp); - -/* Close a file - * - * Return negative error number on error, 0 or positive value on success. - * - * The meaning of return value on success depends on the specific back-end being - * used. - */ -typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp); - -/* Called to return the OS file descriptor associated to the QEMUFile. - */ -typedef int (QEMUFileGetFD)(void *opaque); - -/* Called to change the blocking mode of the file - */ -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp); - -/* - * This function writes an iovec to file. The handler must write all - * of the data or return a negative errno value. - */ -typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov, - int iovcnt, int64_t pos, - Error **errp); - /* * This function provides hooks around different * stages of RAM migration. - * 'opaque' is the backend specific data in QEMUFile * 'data' is call specific data associated with the 'flags' value */ -typedef int (QEMURamHookFunc)(QEMUFile *f, void *opaque, uint64_t flags, - void *data); +typedef int (QEMURamHookFunc)(QEMUFile *f, uint64_t flags, void *data); /* * Constants used by ram_control_* hooks @@ -84,34 +49,11 @@ typedef int (QEMURamHookFunc)(QEMUFile *f, void *opaque, uint64_t flags, * This function allows override of where the RAM page * is saved (such as RDMA, for example.) */ -typedef size_t (QEMURamSaveFunc)(QEMUFile *f, void *opaque, - ram_addr_t block_offset, - ram_addr_t offset, - size_t size, - uint64_t *bytes_sent); - -/* - * Return a QEMUFile for comms in the opposite direction - */ -typedef QEMUFile *(QEMURetPathFunc)(void *opaque); - -/* - * Stop any read or write (depending on flags) on the underlying - * transport on the QEMUFile. - * Existing blocking reads/writes must be woken - * Returns 0 on success, -err on error - */ -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr, - Error **errp); - -typedef struct QEMUFileOps { - QEMUFileGetBufferFunc *get_buffer; - QEMUFileCloseFunc *close; - QEMUFileSetBlocking *set_blocking; - QEMUFileWritevBufferFunc *writev_buffer; - QEMURetPathFunc *get_return_path; - QEMUFileShutdownFunc *shut_down; -} QEMUFileOps; +typedef size_t (QEMURamSaveFunc)(QEMUFile *f, + ram_addr_t block_offset, + ram_addr_t offset, + size_t size, + uint64_t *bytes_sent); typedef struct QEMUFileHooks { QEMURamHookFunc *before_ram_iterate; @@ -120,12 +62,41 @@ typedef struct QEMUFileHooks { QEMURamSaveFunc *save_page; } QEMUFileHooks; -QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops, bool has_ioc); +QEMUFile *qemu_file_new_input(QIOChannel *ioc); +QEMUFile *qemu_file_new_output(QIOChannel *ioc); void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks); -int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); -int64_t qemu_ftell(QEMUFile *f); -int64_t qemu_ftell_fast(QEMUFile *f); + +/* + * qemu_file_total_transferred: + * + * Report the total number of bytes transferred with + * this file. + * + * For writable files, any pending buffers will be + * flushed, so the reported value will be equal to + * the number of bytes transferred on the wire. + * + * For readable files, the reported value will be + * equal to the number of bytes transferred on the + * wire. + * + * Returns: the total bytes transferred + */ +int64_t qemu_file_total_transferred(QEMUFile *f); + +/* + * qemu_file_total_transferred_fast: + * + * As qemu_file_total_transferred except for writable + * files, where no flush is performed and the reported + * amount will include the size of any queued buffers, + * on top of the amount actually transferred. + * + * Returns: the total bytes transferred and queued + */ +int64_t qemu_file_total_transferred_fast(QEMUFile *f); + /* * put_buffer without copying the buffer. * The buffer should be available till it is sent asynchronously. @@ -150,12 +121,27 @@ int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src); */ int qemu_peek_byte(QEMUFile *f, int offset); void qemu_file_skip(QEMUFile *f, int size); -void qemu_update_position(QEMUFile *f, size_t size); +/* + * qemu_file_credit_transfer: + * + * Report on a number of bytes that have been transferred + * out of band from the main file object I/O methods. This + * accounting information tracks the total migration traffic. + */ +void qemu_file_credit_transfer(QEMUFile *f, size_t size); void qemu_file_reset_rate_limit(QEMUFile *f); -void qemu_file_update_transfer(QEMUFile *f, int64_t len); +/* + * qemu_file_acct_rate_limit: + * + * Report on a number of bytes the have been transferred + * out of band from the main file object I/O methods, and + * need to be applied to the rate limiting calcuations + */ +void qemu_file_acct_rate_limit(QEMUFile *f, int64_t len); void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error_obj(QEMUFile *f, Error **errp); +int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp); void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); void qemu_file_set_error(QEMUFile *f, int ret); int qemu_file_shutdown(QEMUFile *f); diff --git a/migration/ram.c b/migration/ram.c index 3532f64ecb98..334309f1c6e5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -32,6 +32,7 @@ #include "qemu/bitmap.h" #include "qemu/madvise.h" #include "qemu/main-loop.h" +#include "io/channel-null.h" #include "xbzrle.h" #include "ram.h" #include "migration.h" @@ -84,6 +85,26 @@ XBZRLECacheStats xbzrle_counters; +/* used by the search for pages to send */ +struct PageSearchStatus { + /* The migration channel used for a specific host page */ + QEMUFile *pss_channel; + /* Last block from where we have sent data */ + RAMBlock *last_sent_block; + /* Current block being searched */ + RAMBlock *block; + /* Current page to search from */ + unsigned long page; + /* Set once we wrap around */ + bool complete_round; + /* Whether we're sending a host page */ + bool host_page_sending; + /* The start/end of current host page. Invalid if host_page_sending==false */ + unsigned long host_page_start; + unsigned long host_page_end; +}; +typedef struct PageSearchStatus PageSearchStatus; + /* struct contains XBZRLE cache and a static page used by the compression */ static struct { @@ -161,6 +182,11 @@ int xbzrle_cache_resize(uint64_t new_size, Error **errp) return ret; } +static bool postcopy_preempt_active(void) +{ + return migrate_postcopy_preempt() && migration_in_postcopy(); +} + bool ramblock_is_ignored(RAMBlock *block) { return !qemu_ram_is_migratable(block) || @@ -297,14 +323,15 @@ struct RAMSrcPageRequest { /* State of RAM for migration */ struct RAMState { - /* QEMUFile used for this migration */ - QEMUFile *f; + /* + * PageSearchStatus structures for the channels when send pages. + * Protected by the bitmap_mutex. + */ + PageSearchStatus pss[RAM_CHANNEL_MAX]; /* UFFD file descriptor, used in 'write-tracking' migration */ int uffdio_fd; /* Last block that we have visited searching for dirty pages */ RAMBlock *last_seen_block; - /* Last block from where we have sent data */ - RAMBlock *last_sent_block; /* Last dirty target page we have sent */ ram_addr_t last_page; /* last ram version we have seen */ @@ -342,7 +369,12 @@ struct RAMState { uint64_t target_page_count; /* number of dirty bits in the bitmap */ uint64_t migration_dirty_pages; - /* Protects modification of the bitmap and migration dirty pages */ + /* + * Protects: + * - dirty/clear bitmap + * - migration_dirty_pages + * - pss structures + */ QemuMutex bitmap_mutex; /* The RAMBlock used in the last src_page_requests */ RAMBlock *last_req_rb; @@ -392,30 +424,31 @@ uint64_t ram_bytes_remaining(void) 0; } +/* + * NOTE: not all stats in ram_counters are used in reality. See comments + * for struct MigrationAtomicStats. The ultimate result of ram migration + * counters will be a merged version with both ram_counters and the atomic + * fields in ram_atomic_counters. + */ MigrationStats ram_counters; +MigrationAtomicStats ram_atomic_counters; -static void ram_transferred_add(uint64_t bytes) +void ram_transferred_add(uint64_t bytes) { if (runstate_is_running()) { ram_counters.precopy_bytes += bytes; } else if (migration_in_postcopy()) { - ram_counters.postcopy_bytes += bytes; + stat64_add(&ram_atomic_counters.postcopy_bytes, bytes); } else { ram_counters.downtime_bytes += bytes; } - ram_counters.transferred += bytes; + stat64_add(&ram_atomic_counters.transferred, bytes); } -/* used by the search for pages to send */ -struct PageSearchStatus { - /* Current block being searched */ - RAMBlock *block; - /* Current page to search from */ - unsigned long page; - /* Set once we wrap around */ - bool complete_round; -}; -typedef struct PageSearchStatus PageSearchStatus; +void dirty_sync_missed_zero_copy(void) +{ + ram_counters.dirty_sync_missed_zero_copy++; +} CompressionStats compression_counters; @@ -455,8 +488,6 @@ static QemuThread *compress_threads; */ static QemuMutex comp_done_lock; static QemuCond comp_done_cond; -/* The empty QEMUFileOps will be used by file in CompressParam */ -static const QEMUFileOps empty_ops = { }; static QEMUFile *decomp_file; static DecompressParam *decomp_param; @@ -464,9 +495,29 @@ static QemuThread *decompress_threads; static QemuMutex decomp_done_lock; static QemuCond decomp_done_cond; +static int ram_save_host_page_urgent(PageSearchStatus *pss); + static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, ram_addr_t offset, uint8_t *source_buf); +/* NOTE: page is the PFN not real ram_addr_t. */ +static void pss_init(PageSearchStatus *pss, RAMBlock *rb, ram_addr_t page) +{ + pss->block = rb; + pss->page = page; + pss->complete_round = false; +} + +/* + * Check whether two PSSs are actively sending the same page. Return true + * if it is, false otherwise. + */ +static bool pss_overlap(PageSearchStatus *pss1, PageSearchStatus *pss2) +{ + return pss1->host_page_sending && pss2->host_page_sending && + (pss1->host_page_start == pss2->host_page_start); +} + static void *do_data_compress(void *opaque) { CompressParam *param = opaque; @@ -567,7 +618,8 @@ static int compress_threads_save_setup(void) /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ - comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops, false); + comp_param[i].file = qemu_file_new_output( + QIO_CHANNEL(qio_channel_null_new())); comp_param[i].done = true; comp_param[i].quit = false; qemu_mutex_init(&comp_param[i].mutex); @@ -590,28 +642,30 @@ static int compress_threads_save_setup(void) * * Returns the number of bytes written * - * @f: QEMUFile where to send the data + * @pss: current PSS channel status * @block: block that contains the page we want to send * @offset: offset inside the block for the page * in the lower bits, it contains flags */ -static size_t save_page_header(RAMState *rs, QEMUFile *f, RAMBlock *block, +static size_t save_page_header(PageSearchStatus *pss, RAMBlock *block, ram_addr_t offset) { size_t size, len; + bool same_block = (block == pss->last_sent_block); + QEMUFile *f = pss->pss_channel; - if (block == rs->last_sent_block) { + if (same_block) { offset |= RAM_SAVE_FLAG_CONTINUE; } qemu_put_be64(f, offset); size = 8; - if (!(offset & RAM_SAVE_FLAG_CONTINUE)) { + if (!same_block) { len = strlen(block->idstr); qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)block->idstr, len); size += 1 + len; - rs->last_sent_block = block; + pss->last_sent_block = block; } return size; } @@ -662,7 +716,7 @@ void mig_throttle_counter_reset(void) rs->time_last_bitmap_sync = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); rs->num_dirty_pages_period = 0; - rs->bytes_xfer_prev = ram_counters.transferred; + rs->bytes_xfer_prev = stat64_get(&ram_atomic_counters.transferred); } /** @@ -679,10 +733,6 @@ void mig_throttle_counter_reset(void) */ static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr) { - if (!rs->xbzrle_enabled) { - return; - } - /* We don't care if this fails to allocate a new cache page * as long as it updated an old one */ cache_insert(XBZRLE.cache, current_addr, XBZRLE.zero_target_page, @@ -699,17 +749,19 @@ static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr) * -1 means that xbzrle would be longer than normal * * @rs: current RAM state + * @pss: current PSS channel * @current_data: pointer to the address of the page contents * @current_addr: addr of the page * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, - ram_addr_t current_addr, RAMBlock *block, - ram_addr_t offset) +static int save_xbzrle_page(RAMState *rs, PageSearchStatus *pss, + uint8_t **current_data, ram_addr_t current_addr, + RAMBlock *block, ram_addr_t offset) { int encoded_len = 0, bytes_xbzrle; uint8_t *prev_cached_page; + QEMUFile *file = pss->pss_channel; if (!cache_is_cached(XBZRLE.cache, current_addr, ram_counters.dirty_sync_count)) { @@ -774,11 +826,11 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, } /* Send XBZRLE based compressed page */ - bytes_xbzrle = save_page_header(rs, rs->f, block, + bytes_xbzrle = save_page_header(pss, block, offset | RAM_SAVE_FLAG_XBZRLE); - qemu_put_byte(rs->f, ENCODING_FLAG_XBZRLE); - qemu_put_be16(rs->f, encoded_len); - qemu_put_buffer(rs->f, XBZRLE.encoded_buf, encoded_len); + qemu_put_byte(file, ENCODING_FLAG_XBZRLE); + qemu_put_be16(file, encoded_len); + qemu_put_buffer(file, XBZRLE.encoded_buf, encoded_len); bytes_xbzrle += encoded_len + 1 + 2; /* * Like compressed_size (please see update_compress_thread_counts), @@ -792,26 +844,38 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, } /** - * migration_bitmap_find_dirty: find the next dirty page from start + * pss_find_next_dirty: find the next dirty page of current ramblock * - * Returns the page offset within memory region of the start of a dirty page + * This function updates pss->page to point to the next dirty page index + * within the ramblock to migrate, or the end of ramblock when nothing + * found. Note that when pss->host_page_sending==true it means we're + * during sending a host page, so we won't look for dirty page that is + * outside the host page boundary. * - * @rs: current RAM state - * @rb: RAMBlock where to search for dirty pages - * @start: page where we start the search + * @pss: the current page search status */ -static inline -unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb, - unsigned long start) +static void pss_find_next_dirty(PageSearchStatus *pss) { + RAMBlock *rb = pss->block; unsigned long size = rb->used_length >> TARGET_PAGE_BITS; unsigned long *bitmap = rb->bmap; if (ramblock_is_ignored(rb)) { - return size; + /* Points directly to the end, so we know no dirty page */ + pss->page = size; + return; + } + + /* + * If during sending a host page, only look for dirty pages within the + * current host page being send. + */ + if (pss->host_page_sending) { + assert(pss->host_page_end); + size = MIN(size, pss->host_page_end); } - return find_next_bit(bitmap, size, start); + pss->page = find_next_bit(bitmap, size, pss->page); } static void migration_clear_memory_region_dirty_bitmap(RAMBlock *rb, @@ -1026,8 +1090,9 @@ uint64_t ram_pagesize_summary(void) uint64_t ram_get_total_transferred_pages(void) { - return ram_counters.normal + ram_counters.duplicate + - compression_counters.pages + xbzrle_counters.pages; + return stat64_get(&ram_atomic_counters.normal) + + stat64_get(&ram_atomic_counters.duplicate) + + compression_counters.pages + xbzrle_counters.pages; } static void migration_update_rates(RAMState *rs, int64_t end_time) @@ -1086,8 +1151,8 @@ static void migration_trigger_throttle(RAMState *rs) { MigrationState *s = migrate_get_current(); uint64_t threshold = s->parameters.throttle_trigger_threshold; - - uint64_t bytes_xfer_period = ram_counters.transferred - rs->bytes_xfer_prev; + uint64_t bytes_xfer_period = + stat64_get(&ram_atomic_counters.transferred) - rs->bytes_xfer_prev; uint64_t bytes_dirty_period = rs->num_dirty_pages_period * TARGET_PAGE_SIZE; uint64_t bytes_dirty_threshold = bytes_xfer_period * threshold / 100; @@ -1150,7 +1215,7 @@ static void migration_bitmap_sync(RAMState *rs) /* reset period counters */ rs->time_last_bitmap_sync = end_time; rs->num_dirty_pages_period = 0; - rs->bytes_xfer_prev = ram_counters.transferred; + rs->bytes_xfer_prev = stat64_get(&ram_atomic_counters.transferred); } if (migrate_use_events()) { qapi_event_send_migration_pass(ram_counters.dirty_sync_count); @@ -1177,7 +1242,7 @@ static void migration_bitmap_sync_precopy(RAMState *rs) } } -static void ram_release_page(const char *rbname, uint64_t offset) +void ram_release_page(const char *rbname, uint64_t offset) { if (!migrate_release_ram() || !migration_in_postcopy()) { return; @@ -1192,19 +1257,19 @@ static void ram_release_page(const char *rbname, uint64_t offset) * Returns the size of data written to the file, 0 means the page is not * a zero page * - * @rs: current RAM state - * @file: the file where the data is saved + * @pss: current PSS channel * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_zero_page_to_file(RAMState *rs, QEMUFile *file, +static int save_zero_page_to_file(PageSearchStatus *pss, RAMBlock *block, ram_addr_t offset) { uint8_t *p = block->host + offset; + QEMUFile *file = pss->pss_channel; int len = 0; if (buffer_is_zero(p, TARGET_PAGE_SIZE)) { - len += save_page_header(rs, file, block, offset | RAM_SAVE_FLAG_ZERO); + len += save_page_header(pss, block, offset | RAM_SAVE_FLAG_ZERO); qemu_put_byte(file, 0); len += 1; ram_release_page(block->idstr, offset); @@ -1217,16 +1282,17 @@ static int save_zero_page_to_file(RAMState *rs, QEMUFile *file, * * Returns the number of pages written. * - * @rs: current RAM state + * @pss: current PSS channel * @block: block that contains the page we want to send * @offset: offset inside the block for the page */ -static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) +static int save_zero_page(PageSearchStatus *pss, RAMBlock *block, + ram_addr_t offset) { - int len = save_zero_page_to_file(rs, rs->f, block, offset); + int len = save_zero_page_to_file(pss, block, offset); if (len) { - ram_counters.duplicate++; + stat64_add(&ram_atomic_counters.duplicate, 1); ram_transferred_add(len); return 1; } @@ -1240,15 +1306,15 @@ static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) * * Return true if the pages has been saved, otherwise false is returned. */ -static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, - int *pages) +static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, + ram_addr_t offset, int *pages) { uint64_t bytes_xmit = 0; int ret; *pages = -1; - ret = ram_control_save_page(rs->f, block->offset, offset, TARGET_PAGE_SIZE, - &bytes_xmit); + ret = ram_control_save_page(pss->pss_channel, block->offset, offset, + TARGET_PAGE_SIZE, &bytes_xmit); if (ret == RAM_SAVE_CONTROL_NOT_SUPP) { return false; } @@ -1263,9 +1329,9 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, } if (bytes_xmit > 0) { - ram_counters.normal++; + stat64_add(&ram_atomic_counters.normal, 1); } else if (bytes_xmit == 0) { - ram_counters.duplicate++; + stat64_add(&ram_atomic_counters.duplicate, 1); } return true; @@ -1276,26 +1342,28 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, * * Returns the number of pages written. * - * @rs: current RAM state + * @pss: current PSS channel * @block: block that contains the page we want to send * @offset: offset inside the block for the page * @buf: the page to be sent * @async: send to page asyncly */ -static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, - uint8_t *buf, bool async) +static int save_normal_page(PageSearchStatus *pss, RAMBlock *block, + ram_addr_t offset, uint8_t *buf, bool async) { - ram_transferred_add(save_page_header(rs, rs->f, block, + QEMUFile *file = pss->pss_channel; + + ram_transferred_add(save_page_header(pss, block, offset | RAM_SAVE_FLAG_PAGE)); if (async) { - qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE, - migrate_release_ram() & + qemu_put_buffer_async(file, buf, TARGET_PAGE_SIZE, + migrate_release_ram() && migration_in_postcopy()); } else { - qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE); + qemu_put_buffer(file, buf, TARGET_PAGE_SIZE); } ram_transferred_add(TARGET_PAGE_SIZE); - ram_counters.normal++; + stat64_add(&ram_atomic_counters.normal, 1); return 1; } @@ -1325,8 +1393,8 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss) XBZRLE_cache_lock(); if (rs->xbzrle_enabled && !migration_in_postcopy()) { - pages = save_xbzrle_page(rs, &p, current_addr, block, - offset); + pages = save_xbzrle_page(rs, pss, &p, current_addr, + block, offset); if (!rs->last_stage) { /* Can't send this cached data async, since the cache page * might get updated before it gets to the wire @@ -1337,7 +1405,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss) /* XBZRLE overflow or normal page */ if (pages == -1) { - pages = save_normal_page(rs, block, offset, p, send_async); + pages = save_normal_page(pss, block, offset, p, send_async); } XBZRLE_cache_unlock(); @@ -1345,13 +1413,13 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss) return pages; } -static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, +static int ram_save_multifd_page(QEMUFile *file, RAMBlock *block, ram_addr_t offset) { - if (multifd_queue_page(rs->f, block, offset) < 0) { + if (multifd_queue_page(file, block, offset) < 0) { return -1; } - ram_counters.normal++; + stat64_add(&ram_atomic_counters.normal, 1); return 1; } @@ -1360,14 +1428,15 @@ static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, ram_addr_t offset, uint8_t *source_buf) { RAMState *rs = ram_state; + PageSearchStatus *pss = &rs->pss[RAM_CHANNEL_PRECOPY]; uint8_t *p = block->host + offset; int ret; - if (save_zero_page_to_file(rs, f, block, offset)) { + if (save_zero_page_to_file(pss, block, offset)) { return true; } - save_page_header(rs, f, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE); + save_page_header(pss, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE); /* * copy it to a internal buffer to avoid it being modified by VM @@ -1389,7 +1458,7 @@ update_compress_thread_counts(const CompressParam *param, int bytes_xmit) ram_transferred_add(bytes_xmit); if (param->zero_page) { - ram_counters.duplicate++; + stat64_add(&ram_atomic_counters.duplicate, 1); return; } @@ -1402,6 +1471,7 @@ static bool save_page_use_compression(RAMState *rs); static void flush_compressed_data(RAMState *rs) { + MigrationState *ms = migrate_get_current(); int idx, len, thread_count; if (!save_page_use_compression(rs)) { @@ -1420,7 +1490,7 @@ static void flush_compressed_data(RAMState *rs) for (idx = 0; idx < thread_count; idx++) { qemu_mutex_lock(&comp_param[idx].mutex); if (!comp_param[idx].quit) { - len = qemu_put_qemu_file(rs->f, comp_param[idx].file); + len = qemu_put_qemu_file(ms->to_dst_file, comp_param[idx].file); /* * it's safe to fetch zero_page without holding comp_done_lock * as there is no further request submitted to the thread, @@ -1439,11 +1509,11 @@ static inline void set_compress_params(CompressParam *param, RAMBlock *block, param->offset = offset; } -static int compress_page_with_multi_thread(RAMState *rs, RAMBlock *block, - ram_addr_t offset) +static int compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset) { int idx, thread_count, bytes_xmit = -1, pages = -1; bool wait = migrate_compress_wait_thread(); + MigrationState *ms = migrate_get_current(); thread_count = migrate_compress_threads(); qemu_mutex_lock(&comp_done_lock); @@ -1451,7 +1521,8 @@ static int compress_page_with_multi_thread(RAMState *rs, RAMBlock *block, for (idx = 0; idx < thread_count; idx++) { if (comp_param[idx].done) { comp_param[idx].done = false; - bytes_xmit = qemu_put_qemu_file(rs->f, comp_param[idx].file); + bytes_xmit = qemu_put_qemu_file(ms->to_dst_file, + comp_param[idx].file); qemu_mutex_lock(&comp_param[idx].mutex); set_compress_params(&comp_param[idx], block, offset); qemu_cond_signal(&comp_param[idx].cond); @@ -1487,7 +1558,9 @@ static int compress_page_with_multi_thread(RAMState *rs, RAMBlock *block, */ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again) { - pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page); + /* Update pss->page for the next dirty bit in ramblock */ + pss_find_next_dirty(pss); + if (pss->complete_round && pss->block == rs->last_seen_block && pss->page >= rs->last_page) { /* @@ -1548,7 +1621,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; @@ -1565,13 +1637,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); @@ -1579,9 +1648,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; } @@ -1639,7 +1705,7 @@ static int ram_save_release_protection(RAMState *rs, PageSearchStatus *pss, uint64_t run_length = (pss->page - start_page) << TARGET_PAGE_BITS; /* Flush async buffers before un-protect. */ - qemu_fflush(rs->f); + qemu_fflush(pss->pss_channel); /* Un-protect memory range. */ res = uffd_change_protection(rs->uffdio_fd, page_address, run_length, false, false); @@ -1956,8 +2022,30 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss) { RAMBlock *block; ram_addr_t offset; + bool dirty; + + 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); + } + } - block = unqueue_page(rs, &offset); + } while (block && !dirty); if (!block) { /* @@ -2058,6 +2146,56 @@ int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len) return -1; } + /* + * When with postcopy preempt, we send back the page directly in the + * rp-return thread. + */ + if (postcopy_preempt_active()) { + ram_addr_t page_start = start >> TARGET_PAGE_BITS; + size_t page_size = qemu_ram_pagesize(ramblock); + PageSearchStatus *pss = &ram_state->pss[RAM_CHANNEL_POSTCOPY]; + int ret = 0; + + qemu_mutex_lock(&rs->bitmap_mutex); + + pss_init(pss, ramblock, page_start); + /* + * Always use the preempt channel, and make sure it's there. It's + * safe to access without lock, because when rp-thread is running + * we should be the only one who operates on the qemufile + */ + pss->pss_channel = migrate_get_current()->postcopy_qemufile_src; + assert(pss->pss_channel); + + /* + * It must be either one or multiple of host page size. Just + * assert; if something wrong we're mostly split brain anyway. + */ + assert(len % page_size == 0); + while (len) { + if (ram_save_host_page_urgent(pss)) { + error_report("%s: ram_save_host_page_urgent() failed: " + "ramblock=%s, start_addr=0x"RAM_ADDR_FMT, + __func__, ramblock->idstr, start); + ret = -1; + break; + } + /* + * NOTE: after ram_save_host_page_urgent() succeeded, pss->page + * will automatically be moved and point to the next host page + * we're going to send, so no need to update here. + * + * Normally QEMU never sends >1 host page in requests, so + * logically we don't even need that as the loop should only + * run once, but just to be consistent. + */ + len -= page_size; + }; + qemu_mutex_unlock(&rs->bitmap_mutex); + + return ret; + } + struct RAMSrcPageRequest *new_entry = g_new0(struct RAMSrcPageRequest, 1); new_entry->rb = ramblock; @@ -2096,7 +2234,8 @@ static bool save_page_use_compression(RAMState *rs) * has been properly handled by compression, otherwise needs other * paths to handle it */ -static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) +static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, + RAMBlock *block, ram_addr_t offset) { if (!save_page_use_compression(rs)) { return false; @@ -2112,12 +2251,12 @@ static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) * We post the fist page as normal page as compression will take * much CPU resource. */ - if (block != rs->last_sent_block) { + if (block != pss->last_sent_block) { flush_compressed_data(rs); return false; } - if (compress_page_with_multi_thread(rs, block, offset) > 0) { + if (compress_page_with_multi_thread(block, offset) > 0) { return true; } @@ -2139,20 +2278,20 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; int res; - if (control_save_page(rs, block, offset, &res)) { + if (control_save_page(pss, block, offset, &res)) { return res; } - if (save_compress_page(rs, block, offset)) { + if (save_compress_page(rs, pss, block, offset)) { return 1; } - res = save_zero_page(rs, block, offset); + res = save_zero_page(pss, block, offset); if (res > 0) { /* Must let xbzrle know, otherwise a previous (now 0'd) cached * page would be stale */ - if (!save_page_use_compression(rs)) { + if (rs->xbzrle_enabled) { XBZRLE_cache_lock(); xbzrle_cache_zero_page(rs, block->offset + offset); XBZRLE_cache_unlock(); @@ -2161,19 +2300,105 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) } /* - * Do not use multifd for: - * 1. Compression as the first page in the new block should be posted out - * before sending the compressed page - * 2. In postcopy as one whole host page should be placed + * Do not use multifd in postcopy as one whole host page should be + * placed. Meanwhile postcopy requires atomic update of pages, so even + * if host page size == guest page size the dest guest during run may + * still see partially copied pages which is data corruption. */ - if (!save_page_use_compression(rs) && migrate_use_multifd() - && !migration_in_postcopy()) { - return ram_save_multifd_page(rs, block, offset); + if (migrate_use_multifd() && !migration_in_postcopy()) { + return ram_save_multifd_page(pss->pss_channel, block, offset); } return ram_save_page(rs, pss); } +/* Should be called before sending a host page */ +static void pss_host_page_prepare(PageSearchStatus *pss) +{ + /* How many guest pages are there in one host page? */ + size_t guest_pfns = qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; + + pss->host_page_sending = true; + pss->host_page_start = ROUND_DOWN(pss->page, guest_pfns); + pss->host_page_end = ROUND_UP(pss->page + 1, guest_pfns); +} + +/* + * Whether the page pointed by PSS is within the host page being sent. + * Must be called after a previous pss_host_page_prepare(). + */ +static bool pss_within_range(PageSearchStatus *pss) +{ + ram_addr_t ram_addr; + + assert(pss->host_page_sending); + + /* Over host-page boundary? */ + if (pss->page >= pss->host_page_end) { + return false; + } + + ram_addr = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; + + return offset_in_ramblock(pss->block, ram_addr); +} + +static void pss_host_page_finish(PageSearchStatus *pss) +{ + pss->host_page_sending = false; + /* This is not needed, but just to reset it */ + pss->host_page_start = pss->host_page_end = 0; +} + +/* + * Send an urgent host page specified by `pss'. Need to be called with + * bitmap_mutex held. + * + * Returns 0 if save host page succeeded, false otherwise. + */ +static int ram_save_host_page_urgent(PageSearchStatus *pss) +{ + bool page_dirty, sent = false; + RAMState *rs = ram_state; + int ret = 0; + + trace_postcopy_preempt_send_host_page(pss->block->idstr, pss->page); + pss_host_page_prepare(pss); + + /* + * If precopy is sending the same page, let it be done in precopy, or + * we could send the same page in two channels and none of them will + * receive the whole page. + */ + if (pss_overlap(pss, &ram_state->pss[RAM_CHANNEL_PRECOPY])) { + trace_postcopy_preempt_hit(pss->block->idstr, + pss->page << TARGET_PAGE_BITS); + return 0; + } + + do { + page_dirty = migration_bitmap_clear_dirty(rs, pss->block, pss->page); + + if (page_dirty) { + /* Be strict to return code; it must be 1, or what else? */ + if (ram_save_target_page(rs, pss) != 1) { + error_report_once("%s: ram_save_target_page failed", __func__); + ret = -1; + goto out; + } + sent = true; + } + pss_find_next_dirty(pss); + } while (pss_within_range(pss)); +out: + pss_host_page_finish(pss); + /* For urgent requests, flush immediately if sent */ + if (sent) { + qemu_fflush(pss->pss_channel); + } + return ret; +} + /** * ram_save_host_page: save a whole host page * @@ -2182,9 +2407,14 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) * a host page in which case the remainder of the hostpage is sent. * Only dirty target pages are sent. Note that the host page size may * be a huge page for this block. + * * The saving stops at the boundary of the used_length of the block * if the RAMBlock isn't a multiple of the host page size. * + * The caller must be with ram_state.bitmap_mutex held to call this + * function. Note that this function can temporarily release the lock, but + * when the function is returned it'll make sure the lock is still held. + * * Returns the number of pages written or negative on error * * @rs: current RAM state @@ -2192,11 +2422,10 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) */ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) { + bool page_dirty, preempt_active = postcopy_preempt_active(); int tmppages, pages = 0; size_t pagesize_bits = qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; - unsigned long hostpage_boundary = - QEMU_ALIGN_UP(pss->page + 1, pagesize_bits); unsigned long start_page = pss->page; int res; @@ -2205,29 +2434,49 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) return 0; } + /* Update host page boundary information */ + pss_host_page_prepare(pss); + do { - /* Check the pages is dirty and if it is send it */ - if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { - tmppages = ram_save_target_page(rs, pss); - if (tmppages < 0) { - return tmppages; - } + page_dirty = migration_bitmap_clear_dirty(rs, pss->block, pss->page); - pages += tmppages; + /* Check the pages is dirty and if it is send it */ + if (page_dirty) { /* - * Allow rate limiting to happen in the middle of huge pages if - * something is sent in the current iteration. + * Properly yield the lock only in postcopy preempt mode + * because both migration thread and rp-return thread can + * operate on the bitmaps. */ - if (pagesize_bits > 1 && tmppages > 0) { - migration_rate_limit(); + if (preempt_active) { + qemu_mutex_unlock(&rs->bitmap_mutex); + } + tmppages = ram_save_target_page(rs, pss); + if (tmppages >= 0) { + pages += tmppages; + /* + * Allow rate limiting to happen in the middle of huge pages if + * something is sent in the current iteration. + */ + if (pagesize_bits > 1 && tmppages > 0) { + migration_rate_limit(); + } + } + if (preempt_active) { + qemu_mutex_lock(&rs->bitmap_mutex); } + } else { + tmppages = 0; } - pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page); - } while ((pss->page < hostpage_boundary) && - offset_in_ramblock(pss->block, - ((ram_addr_t)pss->page) << TARGET_PAGE_BITS)); - /* The offset we leave with is the min boundary of host page and block */ - pss->page = MIN(pss->page, hostpage_boundary); + + if (tmppages < 0) { + pss_host_page_finish(pss); + return tmppages; + } + + pss_find_next_dirty(pss); + } while (pss_within_range(pss)); + + pss_host_page_finish(pss); res = ram_save_release_protection(rs, pss, start_page); return (res < 0 ? res : pages); @@ -2248,7 +2497,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) */ static int ram_find_and_save_block(RAMState *rs) { - PageSearchStatus pss; + PageSearchStatus *pss = &rs->pss[RAM_CHANNEL_PRECOPY]; int pages = 0; bool again, found; @@ -2257,30 +2506,36 @@ static int ram_find_and_save_block(RAMState *rs) return pages; } - pss.block = rs->last_seen_block; - pss.page = rs->last_page; - pss.complete_round = false; - - if (!pss.block) { - pss.block = QLIST_FIRST_RCU(&ram_list.blocks); + /* + * Always keep last_seen_block/last_page valid during this procedure, + * because find_dirty_block() relies on these values (e.g., we compare + * last_seen_block with pss.block to see whether we searched all the + * ramblocks) to detect the completion of migration. Having NULL value + * of last_seen_block can conditionally cause below loop to run forever. + */ + if (!rs->last_seen_block) { + rs->last_seen_block = QLIST_FIRST_RCU(&ram_list.blocks); + rs->last_page = 0; } + pss_init(pss, rs->last_seen_block, rs->last_page); + do { again = true; - found = get_queued_page(rs, &pss); + found = get_queued_page(rs, pss); if (!found) { /* priority queue empty, so just search for something dirty */ - found = find_dirty_block(rs, &pss, &again); + found = find_dirty_block(rs, pss, &again); } if (found) { - pages = ram_save_host_page(rs, &pss); + pages = ram_save_host_page(rs, pss); } } while (!pages && again); - rs->last_seen_block = pss.block; - rs->last_page = pss.page; + rs->last_seen_block = pss->block; + rs->last_page = pss->page; return pages; } @@ -2290,11 +2545,11 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero) uint64_t pages = size / TARGET_PAGE_SIZE; if (zero) { - ram_counters.duplicate += pages; + stat64_add(&ram_atomic_counters.duplicate, pages); } else { - ram_counters.normal += pages; + stat64_add(&ram_atomic_counters.normal, pages); ram_transferred_add(size); - qemu_update_position(f, size); + qemu_file_credit_transfer(f, size); } } @@ -2394,8 +2649,13 @@ static void ram_save_cleanup(void *opaque) static void ram_state_reset(RAMState *rs) { + int i; + + for (i = 0; i < RAM_CHANNEL_MAX; i++) { + rs->pss[i].last_sent_block = NULL; + } + rs->last_seen_block = NULL; - rs->last_sent_block = NULL; rs->last_page = 0; rs->last_version = ram_list.version; rs->xbzrle_enabled = false; @@ -2587,8 +2847,8 @@ void ram_postcopy_send_discard_bitmap(MigrationState *ms) migration_bitmap_sync(rs); /* Easiest way to make sure we don't resume in the middle of a host-page */ + rs->pss[RAM_CHANNEL_PRECOPY].last_sent_block = NULL; rs->last_seen_block = NULL; - rs->last_sent_block = NULL; rs->last_page = 0; postcopy_each_ram_send_discard(ms); @@ -2825,7 +3085,7 @@ static void ram_state_resume_prepare(RAMState *rs, QEMUFile *out) ram_state_reset(rs); /* Update RAMState cache of output QEMUFile */ - rs->f = out; + rs->pss[RAM_CHANNEL_PRECOPY].pss_channel = out; trace_ram_state_resume_prepare(pages); } @@ -2903,6 +3163,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) { RAMState **rsp = opaque; RAMBlock *block; + int ret; if (compress_threads_save_setup()) { return -1; @@ -2915,7 +3176,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) return -1; } } - (*rsp)->f = f; + (*rsp)->pss[RAM_CHANNEL_PRECOPY].pss_channel = f; WITH_RCU_READ_LOCK_GUARD() { qemu_put_be64(f, ram_bytes_total_common(true) | RAM_SAVE_FLAG_MEM_SIZE); @@ -2937,7 +3198,11 @@ static int ram_save_setup(QEMUFile *f, void *opaque) ram_control_before_iterate(f, RAM_CONTROL_SETUP); ram_control_after_iterate(f, RAM_CONTROL_SETUP); - multifd_send_sync_main(f); + ret = multifd_send_sync_main(f); + if (ret < 0) { + return ret; + } + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); @@ -3046,7 +3311,11 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) out: if (ret >= 0 && migration_is_setup_or_active(migrate_get_current()->state)) { - multifd_send_sync_main(rs->f); + ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel); + if (ret < 0) { + return ret; + } + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); ram_transferred_add(8); @@ -3088,6 +3357,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) /* try transferring iterative blocks of memory */ /* flush all remaining blocks regardless of rate limiting */ + qemu_mutex_lock(&rs->bitmap_mutex); while (true) { int pages; @@ -3101,18 +3371,25 @@ static int ram_save_complete(QEMUFile *f, void *opaque) break; } } + qemu_mutex_unlock(&rs->bitmap_mutex); flush_compressed_data(rs); ram_control_after_iterate(f, RAM_CONTROL_FINISH); } - if (ret >= 0) { - multifd_send_sync_main(rs->f); - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - qemu_fflush(f); + if (ret < 0) { + return ret; } - return ret; + ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel); + if (ret < 0) { + return ret; + } + + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + + return 0; } static void ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, @@ -3188,11 +3465,13 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host) * @mis: the migration incoming state pointer * @f: QEMUFile where to read the data from * @flags: Page flags (mostly to see if it's a continuation of previous block) + * @channel: the channel we're using */ static inline RAMBlock *ram_block_from_stream(MigrationIncomingState *mis, - QEMUFile *f, int flags) + QEMUFile *f, int flags, + int channel) { - RAMBlock *block = mis->last_recv_block; + RAMBlock *block = mis->last_recv_block[channel]; char id[256]; uint8_t len; @@ -3219,7 +3498,7 @@ static inline RAMBlock *ram_block_from_stream(MigrationIncomingState *mis, return NULL; } - mis->last_recv_block = block; + mis->last_recv_block[channel] = block; return block; } @@ -3638,15 +3917,15 @@ int ram_postcopy_incoming_init(MigrationIncomingState *mis) * rcu_read_lock is taken prior to this being called. * * @f: QEMUFile where to send the data + * @channel: the channel to use for loading */ -static int ram_load_postcopy(QEMUFile *f) +int ram_load_postcopy(QEMUFile *f, int channel) { int flags = 0, ret = 0; bool place_needed = false; bool matches_target_page_size = false; MigrationIncomingState *mis = migration_incoming_get_current(); - /* Currently we only use channel 0. TODO: use all the channels */ - PostcopyTmpPage *tmp_page = &mis->postcopy_tmp_pages[0]; + PostcopyTmpPage *tmp_page = &mis->postcopy_tmp_pages[channel]; while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) { ram_addr_t addr; @@ -3670,10 +3949,10 @@ static int ram_load_postcopy(QEMUFile *f) flags = addr & ~TARGET_PAGE_MASK; addr &= TARGET_PAGE_MASK; - trace_ram_load_postcopy_loop((uint64_t)addr, flags); + trace_ram_load_postcopy_loop(channel, (uint64_t)addr, flags); if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | RAM_SAVE_FLAG_COMPRESS_PAGE)) { - block = ram_block_from_stream(mis, f, flags); + block = ram_block_from_stream(mis, f, flags, channel); if (!block) { ret = -EINVAL; break; @@ -3711,10 +3990,10 @@ static int ram_load_postcopy(QEMUFile *f) } else if (tmp_page->host_addr != host_page_from_ram_block_offset(block, addr)) { /* not the 1st TP within the HP */ - error_report("Non-same host page detected. " + error_report("Non-same host page detected on channel %d: " "Target host page %p, received host page %p " "(rb %s offset 0x"RAM_ADDR_FMT" target_pages %d)", - tmp_page->host_addr, + channel, tmp_page->host_addr, host_page_from_ram_block_offset(block, addr), block->idstr, addr, tmp_page->target_pages); ret = -EINVAL; @@ -3924,7 +4203,8 @@ static int ram_load_precopy(QEMUFile *f) if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) { - RAMBlock *block = ram_block_from_stream(mis, f, flags); + RAMBlock *block = ram_block_from_stream(mis, f, flags, + RAM_CHANNEL_PRECOPY); host = host_from_ram_block_offset(block, addr); /* @@ -4101,7 +4381,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) */ WITH_RCU_READ_LOCK_GUARD() { if (postcopy_running) { - ret = ram_load_postcopy(f); + /* + * Note! Here RAM_CHANNEL_PRECOPY is the precopy channel of + * postcopy migration, we have another RAM_CHANNEL_POSTCOPY to + * service fast page faults. + */ + ret = ram_load_postcopy(f, RAM_CHANNEL_PRECOPY); } else { ret = ram_load_precopy(f); } @@ -4263,6 +4548,12 @@ static int ram_resume_prepare(MigrationState *s, void *opaque) return 0; } +void postcopy_preempt_shutdown_file(MigrationState *s) +{ + qemu_put_be64(s->postcopy_qemufile_src, RAM_SAVE_FLAG_EOS); + qemu_fflush(s->postcopy_qemufile_src); +} + static SaveVMHandlers savevm_ram_handlers = { .save_setup = ram_save_setup, .save_live_iterate = ram_save_iterate, diff --git a/migration/ram.h b/migration/ram.h index 2c6dc3675d5a..81cbb0947c61 100644 --- a/migration/ram.h +++ b/migration/ram.h @@ -32,7 +32,27 @@ #include "qapi/qapi-types-migration.h" #include "exec/cpu-common.h" #include "io/channel.h" +#include "qemu/stats64.h" +/* + * These are the migration statistic counters that need to be updated using + * atomic ops (can be accessed by more than one thread). Here since we + * cannot modify MigrationStats directly to use Stat64 as it was defined in + * the QAPI scheme, we define an internal structure to hold them, and we + * propagate the real values when QMP queries happen. + * + * IOW, the corresponding fields within ram_counters on these specific + * fields will be always zero and not being used at all; they're just + * placeholders to make it QAPI-compatible. + */ +typedef struct { + Stat64 transferred; + Stat64 duplicate; + Stat64 normal; + Stat64 postcopy_bytes; +} MigrationAtomicStats; + +extern MigrationAtomicStats ram_atomic_counters; extern MigrationStats ram_counters; extern XBZRLECacheStats xbzrle_counters; extern CompressionStats compression_counters; @@ -61,9 +81,13 @@ void ram_postcopy_send_discard_bitmap(MigrationState *ms); /* For incoming postcopy discard */ int ram_discard_range(const char *block_name, uint64_t start, size_t length); int ram_postcopy_incoming_init(MigrationIncomingState *mis); +int ram_load_postcopy(QEMUFile *f, int channel); void ram_handle_compressed(void *host, uint8_t ch, uint64_t size); +void ram_transferred_add(uint64_t bytes); +void ram_release_page(const char *rbname, uint64_t offset); + int ramblock_recv_bitmap_test(RAMBlock *rb, void *host_addr); bool ramblock_recv_bitmap_test_byte_offset(RAMBlock *rb, uint64_t byte_offset); void ramblock_recv_bitmap_set(RAMBlock *rb, void *host_addr); @@ -72,6 +96,8 @@ int64_t ramblock_recv_bitmap_send(QEMUFile *file, const char *block_name); int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb); bool ramblock_page_is_discarded(RAMBlock *rb, ram_addr_t start); +void postcopy_preempt_shutdown_file(MigrationState *s); +void *postcopy_preempt_thread(void *opaque); /* ram cache */ int colo_init_ram_cache(void); @@ -86,4 +112,6 @@ void ram_write_tracking_prepare(void); int ram_write_tracking_start(void); void ram_write_tracking_stop(void); +void dirty_sync_missed_zero_copy(void); + #endif diff --git a/migration/rdma.c b/migration/rdma.c index ef1e65ec366d..94a55dd95b5d 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -21,7 +21,6 @@ #include "migration.h" #include "qemu-file.h" #include "ram.h" -#include "qemu-file-channel.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/module.h" @@ -1370,30 +1369,6 @@ const char *print_wrid(int wrid) return wrid_desc[wrid]; } -/* - * RDMA requires memory registration (mlock/pinning), but this is not good for - * overcommitment. - * - * In preparation for the future where LRU information or workload-specific - * writable writable working set memory access behavior is available to QEMU - * it would be nice to have in place the ability to UN-register/UN-pin - * particular memory regions from the RDMA hardware when it is determine that - * those regions of memory will likely not be accessed again in the near future. - * - * While we do not yet have such information right now, the following - * compile-time option allows us to perform a non-optimized version of this - * behavior. - * - * By uncommenting this option, you will cause *all* RDMA transfers to be - * unregistered immediately after the transfer completes on both sides of the - * connection. This has no effect in 'rdma-pin-all' mode, only regular mode. - * - * This will have a terrible impact on migration performance, so until future - * workload information or LRU information is available, do not attempt to use - * this feature except for basic testing. - */ -/* #define RDMA_UNREGISTRATION_EXAMPLE */ - /* * Perform a non-optimized memory unregistration after every transfer * for demonstration purposes, only if pin-all is not requested. @@ -1486,34 +1461,6 @@ static uint64_t qemu_rdma_make_wrid(uint64_t wr_id, uint64_t index, return result; } -/* - * Set bit for unregistration in the next iteration. - * We cannot transmit right here, but will unpin later. - */ -static void qemu_rdma_signal_unregister(RDMAContext *rdma, uint64_t index, - uint64_t chunk, uint64_t wr_id) -{ - if (rdma->unregistrations[rdma->unregister_next] != 0) { - error_report("rdma migration: queue is full"); - } else { - RDMALocalBlock *block = &(rdma->local_ram_blocks.block[index]); - - if (!test_and_set_bit(chunk, block->unregister_bitmap)) { - trace_qemu_rdma_signal_unregister_append(chunk, - rdma->unregister_next); - - rdma->unregistrations[rdma->unregister_next++] = - qemu_rdma_make_wrid(wr_id, index, chunk); - - if (rdma->unregister_next == RDMA_SIGNALED_SEND_MAX) { - rdma->unregister_next = 0; - } - } else { - trace_qemu_rdma_signal_unregister_already(chunk); - } - } -} - /* * Consult the connection manager to see a work request * (of any kind) has completed. @@ -1571,18 +1518,6 @@ static uint64_t qemu_rdma_poll(RDMAContext *rdma, struct ibv_cq *cq, if (rdma->nb_sent > 0) { rdma->nb_sent--; } - - if (!rdma->pin_all) { - /* - * FYI: If one wanted to signal a specific chunk to be unregistered - * using LRU or workload-specific information, this is the function - * you would call to do so. That chunk would then get asynchronously - * unregistered later. - */ -#ifdef RDMA_UNREGISTRATION_EXAMPLE - qemu_rdma_signal_unregister(rdma, index, chunk, wc.wr_id); -#endif - } } else { trace_qemu_rdma_poll_other(print_wrid(wr_id), wr_id, rdma->nb_sent); } @@ -2137,11 +2072,6 @@ static int qemu_rdma_write_one(QEMUFile *f, RDMAContext *rdma, chunk_end = ram_chunk_end(block, chunk + chunks); - if (!rdma->pin_all) { -#ifdef RDMA_UNREGISTRATION_EXAMPLE - qemu_rdma_unregister_waiting(rdma); -#endif - } while (test_bit(chunk, block->transit_bitmap)) { (void)count; @@ -2840,6 +2770,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); @@ -3277,33 +3208,17 @@ qio_channel_rdma_shutdown(QIOChannel *ioc, * Offset is an offset to be added to block_offset and used * to also lookup the corresponding RAMBlock. * - * @size > 0 : - * Initiate an transfer this size. - * - * @size == 0 : - * A 'hint' or 'advice' that means that we wish to speculatively - * and asynchronously unregister this memory. In this case, there is no - * guarantee that the unregister will actually happen, for example, - * if the memory is being actively transmitted. Additionally, the memory - * may be re-registered at any future time if a write within the same - * chunk was requested again, even if you attempted to unregister it - * here. - * - * @size < 0 : TODO, not yet supported - * Unregister the memory NOW. This means that the caller does not - * expect there to be any future RDMA transfers and we just want to clean - * things up. This is used in case the upper layer owns the memory and - * cannot wait for qemu_fclose() to occur. + * @size : Number of bytes to transfer * * @bytes_sent : User-specificed pointer to indicate how many bytes were * sent. Usually, this will not be more than a few bytes of * the protocol because most transfers are sent asynchronously. */ -static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, +static size_t qemu_rdma_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size, uint64_t *bytes_sent) { - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque); + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; int ret; @@ -3322,61 +3237,27 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, qemu_fflush(f); - if (size > 0) { - /* - * Add this page to the current 'chunk'. If the chunk - * is full, or the page doesn't belong to the current chunk, - * an actual RDMA write will occur and a new chunk will be formed. - */ - ret = qemu_rdma_write(f, rdma, block_offset, offset, size); - if (ret < 0) { - error_report("rdma migration: write error! %d", ret); - goto err; - } - - /* - * We always return 1 bytes because the RDMA - * protocol is completely asynchronous. We do not yet know - * whether an identified chunk is zero or not because we're - * waiting for other pages to potentially be merged with - * the current chunk. So, we have to call qemu_update_position() - * later on when the actual write occurs. - */ - if (bytes_sent) { - *bytes_sent = 1; - } - } else { - uint64_t index, chunk; - - /* TODO: Change QEMUFileOps prototype to be signed: size_t => long - if (size < 0) { - ret = qemu_rdma_drain_cq(f, rdma); - if (ret < 0) { - fprintf(stderr, "rdma: failed to synchronously drain" - " completion queue before unregistration.\n"); - goto err; - } - } - */ - - ret = qemu_rdma_search_ram_block(rdma, block_offset, - offset, size, &index, &chunk); - - if (ret) { - error_report("ram block search failed"); - goto err; - } - - qemu_rdma_signal_unregister(rdma, index, chunk, 0); + /* + * Add this page to the current 'chunk'. If the chunk + * is full, or the page doesn't belong to the current chunk, + * an actual RDMA write will occur and a new chunk will be formed. + */ + ret = qemu_rdma_write(f, rdma, block_offset, offset, size); + if (ret < 0) { + error_report("rdma migration: write error! %d", ret); + goto err; + } - /* - * TODO: Synchronous, guaranteed unregistration (should not occur during - * fast-path). Otherwise, unregisters will process on the next call to - * qemu_rdma_drain_cq() - if (size < 0) { - qemu_rdma_unregister_waiting(rdma); - } - */ + /* + * We always return 1 bytes because the RDMA + * protocol is completely asynchronous. We do not yet know + * whether an identified chunk is zero or not because we're + * waiting for other pages to potentially be merged with + * the current chunk. So, we have to call qemu_update_position() + * later on when the actual write occurs. + */ + if (bytes_sent) { + *bytes_sent = 1; } /* @@ -3949,14 +3830,15 @@ rdma_block_notification_handle(QIOChannelRDMA *rioc, const char *name) return 0; } -static int rdma_load_hook(QEMUFile *f, void *opaque, uint64_t flags, void *data) +static int rdma_load_hook(QEMUFile *f, uint64_t flags, void *data) { + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); switch (flags) { case RAM_CONTROL_BLOCK_REG: - return rdma_block_notification_handle(opaque, data); + return rdma_block_notification_handle(rioc, data); case RAM_CONTROL_HOOK: - return qemu_rdma_registration_handle(f, opaque); + return qemu_rdma_registration_handle(f, rioc); default: /* Shouldn't be called with any other values */ @@ -3964,10 +3846,10 @@ static int rdma_load_hook(QEMUFile *f, void *opaque, uint64_t flags, void *data) } } -static int qemu_rdma_registration_start(QEMUFile *f, void *opaque, +static int qemu_rdma_registration_start(QEMUFile *f, uint64_t flags, void *data) { - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque); + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; RCU_READ_LOCK_GUARD(); @@ -3993,10 +3875,10 @@ static int qemu_rdma_registration_start(QEMUFile *f, void *opaque, * Inform dest that dynamic registrations are done for now. * First, flush writes, if any. */ -static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, +static int qemu_rdma_registration_stop(QEMUFile *f, uint64_t flags, void *data) { - QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque); + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qemu_file_get_ioc(f)); RDMAContext *rdma; RDMAControlHeader head = { .len = 0, .repeat = 1 }; int ret = 0; @@ -4169,12 +4051,12 @@ static QEMUFile *qemu_fopen_rdma(RDMAContext *rdma, const char *mode) rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA)); if (mode[0] == 'w') { - rioc->file = qemu_fopen_channel_output(QIO_CHANNEL(rioc)); + rioc->file = qemu_file_new_output(QIO_CHANNEL(rioc)); rioc->rdmaout = rdma; rioc->rdmain = rdma->return_path; qemu_file_set_hooks(rioc->file, &rdma_write_hooks); } else { - rioc->file = qemu_fopen_channel_input(QIO_CHANNEL(rioc)); + rioc->file = qemu_file_new_input(QIO_CHANNEL(rioc)); rioc->rdmain = rdma; rioc->rdmaout = rdma->return_path; qemu_file_set_hooks(rioc->file, &rdma_read_hooks); diff --git a/migration/savevm.c b/migration/savevm.c index 02ed94c18066..a0cdb714f74c 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -35,8 +35,8 @@ #include "migration/misc.h" #include "migration/register.h" #include "migration/global_state.h" +#include "migration/channel-block.h" #include "ram.h" -#include "qemu-file-channel.h" #include "qemu-file.h" #include "savevm.h" #include "postcopy-ram.h" @@ -130,48 +130,13 @@ static struct mig_cmd_args { /***********************************************************/ /* savevm/loadvm support */ -static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, - int64_t pos, Error **errp) -{ - int ret; - QEMUIOVector qiov; - - qemu_iovec_init_external(&qiov, iov, iovcnt); - ret = bdrv_writev_vmstate(opaque, &qiov, pos); - if (ret < 0) { - return ret; - } - - return qiov.size; -} - -static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, - size_t size, Error **errp) -{ - return bdrv_load_vmstate(opaque, buf, pos, size); -} - -static int bdrv_fclose(void *opaque, Error **errp) -{ - return bdrv_flush(opaque); -} - -static const QEMUFileOps bdrv_read_ops = { - .get_buffer = block_get_buffer, - .close = bdrv_fclose -}; - -static const QEMUFileOps bdrv_write_ops = { - .writev_buffer = block_writev_buffer, - .close = bdrv_fclose -}; - static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) { if (is_writable) { - return qemu_fopen_ops(bs, &bdrv_write_ops, false); + return qemu_file_new_output(QIO_CHANNEL(qio_channel_block_new(bs))); + } else { + return qemu_file_new_input(QIO_CHANNEL(qio_channel_block_new(bs))); } - return qemu_fopen_ops(bs, &bdrv_read_ops, false); } @@ -916,9 +881,9 @@ static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se, { int64_t old_offset, size; - old_offset = qemu_ftell_fast(f); + old_offset = qemu_file_total_transferred_fast(f); se->ops->save_state(f, se->opaque); - size = qemu_ftell_fast(f) - old_offset; + size = qemu_file_total_transferred_fast(f) - old_offset; if (vmdesc) { json_writer_int64(vmdesc, "size", size); @@ -2152,6 +2117,13 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis) */ qemu_sem_post(&mis->postcopy_pause_sem_fault); + if (migrate_postcopy_preempt()) { + /* The channel should already be setup again; make sure of it */ + assert(mis->postcopy_qemufile_dst); + /* Kick the fast ram load thread too */ + qemu_sem_post(&mis->postcopy_pause_sem_fast_load); + } + return 0; } @@ -2193,7 +2165,7 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) bioc->usage += length; trace_loadvm_handle_cmd_packaged_received(ret); - QEMUFile *packf = qemu_fopen_channel_input(QIO_CHANNEL(bioc)); + QEMUFile *packf = qemu_file_new_input(QIO_CHANNEL(bioc)); ret = qemu_loadvm_state_main(packf, mis); trace_loadvm_handle_cmd_packaged_main(ret); @@ -2575,23 +2547,10 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis) { int i; - /* - * If network is interrupted, any temp page we received will be useless - * because we didn't mark them as "received" in receivedmap. After a - * proper recovery later (which will sync src dirty bitmap with receivedmap - * on dest) these cached small pages will be resent again. - */ - for (i = 0; i < mis->postcopy_channels; i++) { - postcopy_temp_page_reset(&mis->postcopy_tmp_pages[i]); - } - trace_postcopy_pause_incoming(); assert(migrate_postcopy_ram()); - /* Clear the triggered bit to allow one recovery */ - mis->postcopy_recover_triggered = false; - /* * Unregister yank with either from/to src would work, since ioc behind it * is the same @@ -2610,12 +2569,37 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis) mis->to_src_file = NULL; qemu_mutex_unlock(&mis->rp_mutex); + /* + * NOTE: this must happen before reset the PostcopyTmpPages below, + * otherwise it's racy to reset those fields when the fast load thread + * can be accessing it in parallel. + */ + if (mis->postcopy_qemufile_dst) { + qemu_file_shutdown(mis->postcopy_qemufile_dst); + /* Take the mutex to make sure the fast ram load thread halted */ + qemu_mutex_lock(&mis->postcopy_prio_thread_mutex); + migration_ioc_unregister_yank_from_file(mis->postcopy_qemufile_dst); + qemu_fclose(mis->postcopy_qemufile_dst); + mis->postcopy_qemufile_dst = NULL; + qemu_mutex_unlock(&mis->postcopy_prio_thread_mutex); + } + migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, MIGRATION_STATUS_POSTCOPY_PAUSED); /* Notify the fault thread for the invalidated file handle */ postcopy_fault_thread_notify(mis); + /* + * If network is interrupted, any temp page we received will be useless + * because we didn't mark them as "received" in receivedmap. After a + * proper recovery later (which will sync src dirty bitmap with receivedmap + * on dest) these cached small pages will be resent again. + */ + for (i = 0; i < mis->postcopy_channels; i++) { + postcopy_temp_page_reset(&mis->postcopy_tmp_pages[i]); + } + error_report("Detected IO failure for postcopy. " "Migration paused."); @@ -2637,8 +2621,8 @@ int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis) while (true) { section_type = qemu_get_byte(f); - if (qemu_file_get_error(f)) { - ret = qemu_file_get_error(f); + ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, NULL); + if (ret) { break; } @@ -2890,7 +2874,7 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate, goto the_end; } ret = qemu_savevm_state(f, errp); - vm_state_size = qemu_ftell(f); + vm_state_size = qemu_file_total_transferred(f); ret2 = qemu_fclose(f); if (ret < 0) { goto the_end; @@ -2954,7 +2938,7 @@ void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live, goto the_end; } qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-save-state"); - f = qemu_fopen_channel_output(QIO_CHANNEL(ioc)); + f = qemu_file_new_output(QIO_CHANNEL(ioc)); object_unref(OBJECT(ioc)); ret = qemu_save_device_state(f); if (ret < 0 || qemu_fclose(f) < 0) { @@ -3001,7 +2985,7 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp) return; } qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state"); - f = qemu_fopen_channel_input(QIO_CHANNEL(ioc)); + f = qemu_file_new_input(QIO_CHANNEL(ioc)); object_unref(OBJECT(ioc)); ret = qemu_loadvm_state(f); @@ -3074,7 +3058,7 @@ bool load_snapshot(const char *name, const char *vmstate, goto err_drain; } - qemu_system_reset(SHUTDOWN_CAUSE_NONE); + qemu_system_reset(SHUTDOWN_CAUSE_SNAPSHOT_LOAD); mis->from_src_file = f; if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) { diff --git a/migration/socket.c b/migration/socket.c index 05705a32d8f6..e6fdf3c5e1ac 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -26,7 +26,7 @@ #include "io/channel-socket.h" #include "io/net-listener.h" #include "trace.h" - +#include "postcopy-ram.h" struct SocketOutgoingArgs { SocketAddress *saddr; @@ -39,6 +39,24 @@ void socket_send_channel_create(QIOTaskFunc f, void *data) f, data, NULL, NULL); } +QIOChannel *socket_send_channel_create_sync(Error **errp) +{ + QIOChannelSocket *sioc = qio_channel_socket_new(); + + if (!outgoing_args.saddr) { + object_unref(OBJECT(sioc)); + error_setg(errp, "Initial sock address not set!"); + return NULL; + } + + if (qio_channel_socket_connect_sync(sioc, outgoing_args.saddr, errp) < 0) { + object_unref(OBJECT(sioc)); + return NULL; + } + + return QIO_CHANNEL(sioc); +} + int socket_send_channel_destroy(QIOChannel *send) { /* Remove channel */ @@ -74,9 +92,17 @@ static void socket_outgoing_migration(QIOTask *task, if (qio_task_propagate_error(task, &err)) { trace_migration_socket_outgoing_error(error_get_pretty(err)); - } else { - trace_migration_socket_outgoing_connected(data->hostname); + goto out; } + + trace_migration_socket_outgoing_connected(data->hostname); + + if (migrate_use_zero_copy_send() && + !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { + error_setg(&err, "Zero copy send feature not detected in host kernel"); + } + +out: migration_channel_connect(data->s, sioc, data->hostname, err); object_unref(OBJECT(sioc)); } @@ -158,6 +184,8 @@ socket_start_incoming_migration_internal(SocketAddress *saddr, if (migrate_use_multifd()) { num = migrate_multifd_channels(); + } else if (migrate_postcopy_preempt()) { + num = RAM_CHANNEL_MAX; } if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) { diff --git a/migration/socket.h b/migration/socket.h index 891dbcccebbb..dc54df4e6cc0 100644 --- a/migration/socket.h +++ b/migration/socket.h @@ -21,6 +21,7 @@ #include "io/task.h" void socket_send_channel_create(QIOTaskFunc f, void *data); +QIOChannel *socket_send_channel_create_sync(Error **errp); int socket_send_channel_destroy(QIOChannel *send); void socket_start_incoming_migration(const char *str, Error **errp); diff --git a/migration/tls.c b/migration/tls.c index ca1ea3bbdd45..4d2166a2095a 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -126,7 +126,6 @@ QIOChannelTLS *migration_tls_client_create(MigrationState *s, Error **errp) { QCryptoTLSCreds *creds; - QIOChannelTLS *tioc; creds = migration_tls_get_creds( s, QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, errp); @@ -137,15 +136,8 @@ QIOChannelTLS *migration_tls_client_create(MigrationState *s, if (s->parameters.tls_hostname && *s->parameters.tls_hostname) { hostname = s->parameters.tls_hostname; } - if (!hostname) { - error_setg(errp, "No hostname available for TLS"); - return NULL; - } - tioc = qio_channel_tls_new_client( - ioc, creds, hostname, errp); - - return tioc; + return qio_channel_tls_new_client(ioc, creds, hostname, errp); } void migration_tls_channel_connect(MigrationState *s, @@ -170,3 +162,12 @@ void migration_tls_channel_connect(MigrationState *s, NULL, NULL); } + +bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc) +{ + if (!migrate_use_tls()) { + return false; + } + + return !object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS); +} diff --git a/migration/tls.h b/migration/tls.h index de4fe2cafd71..98e23c9b0e48 100644 --- a/migration/tls.h +++ b/migration/tls.h @@ -37,4 +37,8 @@ void migration_tls_channel_connect(MigrationState *s, QIOChannel *ioc, const char *hostname, Error **errp); + +/* Whether the QIO channel requires further TLS handshake? */ +bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc); + #endif diff --git a/migration/trace-events b/migration/trace-events index 1aec580e92a6..57003edcbda7 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -85,13 +85,15 @@ 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" migration_throttle(void) "" ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx" ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: 0x%" PRIx64 " flags: 0x%x host: %p" -ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x" +ram_load_postcopy_loop(int channel, uint64_t addr, int flags) "chan=%d addr=0x%" PRIx64 " flags=0x%x" ram_postcopy_send_discard_bitmap(void) "" ram_save_page(const char *rbname, uint64_t offset, void *host) "%s: offset: 0x%" PRIx64 " host: %p" ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: 0x%zx len: 0x%zx" @@ -110,7 +112,12 @@ 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 +postcopy_preempt_send_host_page(char *str, uint64_t offset) "ramblock %s offset 0x%"PRIx64 +postcopy_preempt_switch_channel(int channel) "%d" +postcopy_preempt_reset_channel(void) "" # multifd.c multifd_new_send_channel_async(uint8_t id) "channel %u" @@ -176,6 +183,7 @@ migration_thread_low_pending(uint64_t pending) "%" PRIu64 migrate_transferred(uint64_t tranferred, uint64_t time_spent, uint64_t bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %" PRIu64 " max_size %" PRId64 process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d" process_incoming_migration_co_postcopy_end_main(void) "" +postcopy_preempt_enabled(bool value) "%d" # channel.c migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s" @@ -263,6 +271,8 @@ mark_postcopy_blocktime_begin(uint64_t addr, void *dd, uint32_t time, int cpu, i mark_postcopy_blocktime_end(uint64_t addr, void *dd, uint32_t time, int affected_cpu) "addr: 0x%" PRIx64 ", dd: %p, time: %u, affected_cpu: %d" postcopy_pause_fault_thread(void) "" postcopy_pause_fault_thread_continued(void) "" +postcopy_pause_fast_load(void) "" +postcopy_pause_fast_load_continued(void) "" postcopy_ram_fault_thread_entry(void) "" postcopy_ram_fault_thread_exit(void) "" postcopy_ram_fault_thread_fds_core(int baseufd, int quitfd) "ufd: %d quitfd: %d" @@ -278,6 +288,10 @@ postcopy_request_shared_page(const char *sharer, const char *rb, uint64_t rb_off postcopy_request_shared_page_present(const char *sharer, const char *rb, uint64_t rb_offset) "%s already %s offset 0x%"PRIx64 postcopy_wake_shared(uint64_t client_addr, const char *rb) "at 0x%"PRIx64" in %s" postcopy_page_req_del(void *addr, int count) "resolved page req %p total %d" +postcopy_preempt_tls_handshake(void) "" +postcopy_preempt_new_channel(void) "" +postcopy_preempt_thread_entry(void) "" +postcopy_preempt_thread_exit(void) "" get_mem_fault_cpu_index(int cpu, uint32_t pid) "cpu: %d, pid: %u" diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c index bf4d440308ea..e83bfccb9ecf 100644 --- a/migration/vmstate-types.c +++ b/migration/vmstate-types.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cpu-float.h" #include "qemu-file.h" #include "migration.h" #include "migration/vmstate.h" diff --git a/migration/vmstate.c b/migration/vmstate.c index 36ae8b9e1918..924494bda3cd 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -360,7 +360,7 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, void *curr_elem = first_elem + size * i; vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems); - old_offset = qemu_ftell_fast(f); + old_offset = qemu_file_total_transferred_fast(f); if (field->flags & VMS_ARRAY_OF_POINTER) { assert(curr_elem); curr_elem = *(void **)curr_elem; @@ -390,7 +390,8 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, return ret; } - written_bytes = qemu_ftell_fast(f) - old_offset; + written_bytes = qemu_file_total_transferred_fast(f) - + old_offset; vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); /* Compressed arrays only care about the first element */ diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 634968498b58..ed78a87ddd80 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -37,11 +37,13 @@ #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-net.h" -#include "qapi/qapi-commands-pci.h" #include "qapi/qapi-commands-rocker.h" #include "qapi/qapi-commands-run-state.h" +#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" @@ -52,6 +54,7 @@ #include "ui/console.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "hw/core/cpu.h" #include "hw/intc/intc.h" #include "migration/snapshot.h" #include "migration/misc.h" @@ -100,7 +103,7 @@ void hmp_info_name(Monitor *mon, const QDict *qdict) NameInfo *info; info = qmp_query_name(NULL); - if (info->has_name) { + if (info->name) { monitor_printf(mon, "%s\n", info->name); } qapi_free_NameInfo(info); @@ -195,27 +198,6 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict) qapi_free_MouseInfoList(mice_list); } -static char *SocketAddress_to_str(SocketAddress *addr) -{ - switch (addr->type) { - case SOCKET_ADDRESS_TYPE_INET: - return g_strdup_printf("tcp:%s:%s", - addr->u.inet.host, - addr->u.inet.port); - case SOCKET_ADDRESS_TYPE_UNIX: - return g_strdup_printf("unix:%s", - addr->u.q_unix.path); - case SOCKET_ADDRESS_TYPE_FD: - return g_strdup_printf("fd:%s", addr->u.fd.str); - case SOCKET_ADDRESS_TYPE_VSOCK: - return g_strdup_printf("tcp:%s:%s", - addr->u.vsock.cid, - addr->u.vsock.port); - default: - return g_strdup("unknown address type"); - } -} - void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; @@ -236,8 +218,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) if (info->has_status) { monitor_printf(mon, "Migration status: %s", MigrationStatus_str(info->status)); - if (info->status == MIGRATION_STATUS_FAILED && - info->has_error_desc) { + if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) { monitor_printf(mon, " (%s)\n", info->error_desc); } else { monitor_printf(mon, "\n"); @@ -259,7 +240,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) } } - if (info->has_ram) { + if (info->ram) { monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", info->ram->transferred >> 10); monitor_printf(mon, "throughput: %0.2f mbps\n", @@ -305,9 +286,14 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n", info->ram->postcopy_bytes >> 10); } + if (info->ram->dirty_sync_missed_zero_copy) { + monitor_printf(mon, + "Zero-copy-send fallbacks happened: %" PRIu64 " times\n", + info->ram->dirty_sync_missed_zero_copy); + } } - if (info->has_disk) { + if (info->disk) { monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n", info->disk->transferred >> 10); monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n", @@ -316,7 +302,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->disk->total >> 10); } - if (info->has_xbzrle_cache) { + if (info->xbzrle_cache) { monitor_printf(mon, "cache size: %" PRIu64 " bytes\n", info->xbzrle_cache->cache_size); monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n", @@ -333,7 +319,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->xbzrle_cache->overflow); } - if (info->has_compression) { + if (info->compression) { monitor_printf(mon, "compression pages: %" PRIu64 " pages\n", info->compression->pages); monitor_printf(mon, "compression busy: %" PRIu64 "\n", @@ -373,14 +359,14 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) monitor_printf(mon, "socket address: [\n"); for (addr = info->socket_address; addr; addr = addr->next) { - char *s = SocketAddress_to_str(addr->value); + char *s = socket_uri(addr->value); monitor_printf(mon, "\t%s\n", s); g_free(s); } monitor_printf(mon, "]\n"); } - if (info->has_vfio) { + if (info->vfio) { monitor_printf(mon, "vfio device transferred: %" PRIu64 " kbytes\n", info->vfio->transferred >> 10); } @@ -460,11 +446,11 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %u\n", MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE), params->max_cpu_throttle); - assert(params->has_tls_creds); + assert(params->tls_creds); monitor_printf(mon, "%s: '%s'\n", MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS), params->tls_creds); - assert(params->has_tls_hostname); + assert(params->tls_hostname); monitor_printf(mon, "%s: '%s'\n", MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME), params->tls_hostname); @@ -561,11 +547,9 @@ static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client) hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client"); monitor_printf(mon, " x509_dname: %s\n", - cinfo->has_x509_dname ? - cinfo->x509_dname : "none"); + cinfo->x509_dname ?: "none"); monitor_printf(mon, " sasl_username: %s\n", - cinfo->has_sasl_username ? - cinfo->sasl_username : "none"); + cinfo->sasl_username ?: "none"); client = client->next; } @@ -610,7 +594,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict) hmp_info_vnc_authcrypt(mon, " ", info->auth, info->has_vencrypt ? &info->vencrypt : NULL); } - if (info->has_display) { + if (info->display) { monitor_printf(mon, " Display: %s\n", info->display); } info2l = info2l->next; @@ -713,89 +697,6 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict) qapi_free_BalloonInfo(info); } -static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) -{ - PciMemoryRegionList *region; - - monitor_printf(mon, " Bus %2" PRId64 ", ", dev->bus); - monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n", - dev->slot, dev->function); - monitor_printf(mon, " "); - - if (dev->class_info->has_desc) { - monitor_printf(mon, "%s", dev->class_info->desc); - } else { - monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class); - } - - monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n", - dev->id->vendor, dev->id->device); - if (dev->id->has_subsystem_vendor && dev->id->has_subsystem) { - monitor_printf(mon, " PCI subsystem %04" PRIx64 ":%04" PRIx64 "\n", - dev->id->subsystem_vendor, dev->id->subsystem); - } - - if (dev->has_irq) { - monitor_printf(mon, " IRQ %" PRId64 ", pin %c\n", - dev->irq, (char)('A' + dev->irq_pin - 1)); - } - - if (dev->has_pci_bridge) { - monitor_printf(mon, " BUS %" PRId64 ".\n", - dev->pci_bridge->bus->number); - monitor_printf(mon, " secondary bus %" PRId64 ".\n", - dev->pci_bridge->bus->secondary); - monitor_printf(mon, " subordinate bus %" PRId64 ".\n", - dev->pci_bridge->bus->subordinate); - - monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n", - dev->pci_bridge->bus->io_range->base, - dev->pci_bridge->bus->io_range->limit); - - monitor_printf(mon, - " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n", - dev->pci_bridge->bus->memory_range->base, - dev->pci_bridge->bus->memory_range->limit); - - monitor_printf(mon, " prefetchable memory range " - "[0x%08"PRIx64", 0x%08"PRIx64"]\n", - dev->pci_bridge->bus->prefetchable_range->base, - dev->pci_bridge->bus->prefetchable_range->limit); - } - - for (region = dev->regions; region; region = region->next) { - uint64_t addr, size; - - addr = region->value->address; - size = region->value->size; - - monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar); - - if (!strcmp(region->value->type, "io")) { - monitor_printf(mon, "I/O at 0x%04" PRIx64 - " [0x%04" PRIx64 "].\n", - addr, addr + size - 1); - } else { - monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64 - " [0x%08" PRIx64 "].\n", - region->value->mem_type_64 ? 64 : 32, - region->value->prefetch ? " prefetchable" : "", - addr, addr + size - 1); - } - } - - monitor_printf(mon, " id \"%s\"\n", dev->qdev_id); - - if (dev->has_pci_bridge) { - if (dev->pci_bridge->has_devices) { - PciDeviceInfoList *cdev; - for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) { - hmp_info_pci_device(mon, cdev->value); - } - } - } -} - static int hmp_info_pic_foreach(Object *obj, void *opaque) { InterruptStatsProvider *intc; @@ -822,29 +723,6 @@ void hmp_info_pic(Monitor *mon, const QDict *qdict) hmp_info_pic_foreach, mon); } -void hmp_info_pci(Monitor *mon, const QDict *qdict) -{ - PciInfoList *info_list, *info; - Error *err = NULL; - - info_list = qmp_query_pci(&err); - if (err) { - monitor_printf(mon, "PCI devices not supported\n"); - error_free(err); - return; - } - - for (info = info_list; info; info = info->next) { - PciDeviceInfoList *dev; - - for (dev = info->value->devices; dev; dev = dev->next) { - hmp_info_pci_device(mon, dev->value); - } - } - - qapi_free_PciInfoList(info_list); -} - void hmp_info_tpm(Monitor *mon, const QDict *qdict) { #ifdef CONFIG_TPM @@ -877,10 +755,10 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) case TPM_TYPE_PASSTHROUGH: tpo = ti->options->u.passthrough.data; monitor_printf(mon, "%s%s%s%s", - tpo->has_path ? ",path=" : "", - tpo->has_path ? tpo->path : "", - tpo->has_cancel_path ? ",cancel-path=" : "", - tpo->has_cancel_path ? tpo->cancel_path : ""); + tpo->path ? ",path=" : "", + tpo->path ?: "", + tpo->cancel_path ? ",cancel-path=" : "", + tpo->cancel_path ?: ""); break; case TPM_TYPE_EMULATOR: teo = ti->options->u.emulator.data; @@ -1117,7 +995,6 @@ void hmp_announce_self(Monitor *mon, const QDict *qdict) params->interfaces = strList_from_comma_list(interfaces_str); params->has_interfaces = params->interfaces != NULL; params->id = g_strdup(id); - params->has_id = !!params->id; qmp_announce_self(params, NULL); qapi_free_AnnounceParameters(params); } @@ -1249,19 +1126,16 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) visit_type_uint8(v, param, &p->max_cpu_throttle, &err); break; case MIGRATION_PARAMETER_TLS_CREDS: - p->has_tls_creds = true; p->tls_creds = g_new0(StrOrNull, 1); p->tls_creds->type = QTYPE_QSTRING; visit_type_str(v, param, &p->tls_creds->u.s, &err); break; case MIGRATION_PARAMETER_TLS_HOSTNAME: - p->has_tls_hostname = true; p->tls_hostname = g_new0(StrOrNull, 1); p->tls_hostname->type = QTYPE_QSTRING; visit_type_str(v, param, &p->tls_hostname->u.s, &err); break; case MIGRATION_PARAMETER_TLS_AUTHZ: - p->has_tls_authz = true; p->tls_authz = g_new0(StrOrNull, 1); p->tls_authz->type = QTYPE_QSTRING; visit_type_str(v, param, &p->tls_authz->u.s, &err); @@ -1373,7 +1247,7 @@ void hmp_client_migrate_info(Monitor *mon, const QDict *qdict) qmp_client_migrate_info(protocol, hostname, has_port, port, has_tls_port, tls_port, - !!cert_subject, cert_subject, &err); + cert_subject, &err); hmp_handle_error(mon, err); } @@ -1418,7 +1292,6 @@ void hmp_set_password(Monitor *mon, const QDict *qdict) } if (opts.protocol == DISPLAY_PROTOCOL_VNC) { - opts.u.vnc.has_display = !!display; opts.u.vnc.display = (char *)display; } @@ -1446,7 +1319,6 @@ void hmp_expire_password(Monitor *mon, const QDict *qdict) } if (opts.protocol == DISPLAY_PROTOCOL_VNC) { - opts.u.vnc.has_display = !!display; opts.u.vnc.display = (char *)display; } @@ -1472,6 +1344,7 @@ void hmp_change(Monitor *mon, const QDict *qdict) const char *target = qdict_get_str(qdict, "target"); const char *arg = qdict_get_try_str(qdict, "arg"); const char *read_only = qdict_get_try_str(qdict, "read-only-mode"); + bool force = qdict_get_try_bool(qdict, "force", false); BlockdevChangeReadOnlyMode read_only_mode = 0; Error *err = NULL; @@ -1507,8 +1380,8 @@ void hmp_change(Monitor *mon, const QDict *qdict) } } - qmp_blockdev_change_medium(true, device, false, NULL, target, - !!arg, arg, !!read_only, read_only_mode, + qmp_blockdev_change_medium(device, NULL, target, arg, true, force, + !!read_only, read_only_mode, &err); } @@ -1530,7 +1403,7 @@ static void hmp_migrate_status_cb(void *opaque) info = qmp_query_migrate(NULL); if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE || info->status == MIGRATION_STATUS_SETUP) { - if (info->has_disk) { + if (info->disk) { int progress; if (info->disk->remaining) { @@ -1548,7 +1421,7 @@ static void hmp_migrate_status_cb(void *opaque) if (status->is_block_migration) { monitor_printf(status->mon, "\n"); } - if (info->has_error_desc) { + if (info->error_desc) { error_report("%s", info->error_desc); } monitor_resume(status->mon); @@ -1720,9 +1593,19 @@ hmp_screendump(Monitor *mon, const QDict *qdict) const char *filename = qdict_get_str(qdict, "filename"); const char *id = qdict_get_try_str(qdict, "device"); int64_t head = qdict_get_try_int(qdict, "head", 0); + const char *input_format = qdict_get_try_str(qdict, "format"); Error *err = NULL; + ImageFormat format; + + format = qapi_enum_parse(&ImageFormat_lookup, input_format, + IMAGE_FORMAT_PPM, &err); + if (err) { + goto end; + } - qmp_screendump(filename, id != NULL, id, id != NULL, head, &err); + qmp_screendump(filename, id, id != NULL, head, + input_format != NULL, format, &err); +end: hmp_handle_error(mon, err); } @@ -2016,35 +1899,35 @@ void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) } } - if (key->has_eth_src) { + if (key->eth_src) { if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) && - (mask->has_eth_src) && + mask->eth_src && (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { monitor_printf(mon, " src "); } else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) && - (mask->has_eth_src) && + mask->eth_src && (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { monitor_printf(mon, " src "); } else { monitor_printf(mon, " src %s", key->eth_src); - if (mask->has_eth_src) { + if (mask->eth_src) { monitor_printf(mon, "(%s)", mask->eth_src); } } } - if (key->has_eth_dst) { + if (key->eth_dst) { if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) && - (mask->has_eth_dst) && + mask->eth_dst && (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { monitor_printf(mon, " dst "); } else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) && - (mask->has_eth_dst) && + mask->eth_dst && (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { monitor_printf(mon, " dst "); } else { monitor_printf(mon, " dst %s", key->eth_dst); - if (mask->has_eth_dst) { + if (mask->eth_dst) { monitor_printf(mon, "(%s)", mask->eth_dst); } } @@ -2064,7 +1947,7 @@ void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) } } - if (key->has_ip_dst) { + if (key->ip_dst) { monitor_printf(mon, " dst %s", key->ip_dst); } @@ -2143,7 +2026,7 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) group->set_vlan_id & VLAN_VID_MASK); } - if (group->has_set_eth_src) { + if (group->set_eth_src) { if (!set) { set = true; monitor_printf(mon, " set"); @@ -2151,7 +2034,7 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) monitor_printf(mon, " src %s", group->set_eth_src); } - if (group->has_set_eth_dst) { + if (group->set_eth_dst) { if (!set) { monitor_printf(mon, " set"); } @@ -2221,3 +2104,543 @@ void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict) } hmp_handle_error(mon, err); } + +static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) +{ + const char *unit = NULL; + monitor_printf(mon, " %s (%s%s", value->name, StatsType_str(value->type), + value->has_unit || value->exponent ? ", " : ""); + + if (value->has_unit) { + if (value->unit == STATS_UNIT_SECONDS) { + unit = "s"; + } else if (value->unit == STATS_UNIT_BYTES) { + unit = "B"; + } + } + + if (unit && value->base == 10 && + value->exponent >= -18 && value->exponent <= 18 && + value->exponent % 3 == 0) { + monitor_puts(mon, si_prefix(value->exponent)); + } else if (unit && value->base == 2 && + value->exponent >= 0 && value->exponent <= 60 && + value->exponent % 10 == 0) { + + 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", + value->base, value->exponent, + value->has_unit ? " " : ""); + unit = NULL; + } + + if (value->has_unit) { + monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit)); + } + + /* Print bucket size for linear histograms */ + if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) { + monitor_printf(mon, ", bucket size=%d", value->bucket_size); + } + monitor_printf(mon, ")"); +} + +static StatsSchemaValueList *find_schema_value_list( + StatsSchemaList *list, StatsProvider provider, + StatsTarget target) +{ + StatsSchemaList *node; + + for (node = list; node; node = node->next) { + if (node->value->provider == provider && + node->value->target == target) { + return node->value->stats; + } + } + return NULL; +} + +static void print_stats_results(Monitor *mon, StatsTarget target, + bool show_provider, + StatsResult *result, + StatsSchemaList *schema) +{ + /* Find provider schema */ + StatsSchemaValueList *schema_value_list = + find_schema_value_list(schema, result->provider, target); + StatsList *stats_list; + + if (!schema_value_list) { + monitor_printf(mon, "failed to find schema list for %s\n", + StatsProvider_str(result->provider)); + return; + } + + if (show_provider) { + monitor_printf(mon, "provider: %s\n", + StatsProvider_str(result->provider)); + } + + for (stats_list = result->stats; stats_list; + stats_list = stats_list->next, + schema_value_list = schema_value_list->next) { + + Stats *stats = stats_list->value; + StatsValue *stats_value = stats->value; + StatsSchemaValue *schema_value = schema_value_list->value; + + /* Find schema entry */ + while (!g_str_equal(stats->name, schema_value->name)) { + if (!schema_value_list->next) { + monitor_printf(mon, "failed to find schema entry for %s\n", + stats->name); + return; + } + schema_value_list = schema_value_list->next; + schema_value = schema_value_list->value; + } + + print_stats_schema_value(mon, schema_value); + + if (stats_value->type == QTYPE_QNUM) { + monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar); + } else if (stats_value->type == QTYPE_QBOOL) { + monitor_printf(mon, ": %s\n", stats_value->u.boolean ? "yes" : "no"); + } else if (stats_value->type == QTYPE_QLIST) { + uint64List *list; + int i; + + monitor_printf(mon, ": "); + for (list = stats_value->u.list, i = 1; + list; + list = list->next, i++) { + monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value); + } + monitor_printf(mon, "\n"); + } + } +} + +/* Create the StatsFilter that is needed for an "info stats" invocation. */ +static StatsFilter *stats_filter(StatsTarget target, const char *names, + int cpu_index, StatsProvider provider) +{ + StatsFilter *filter = g_malloc0(sizeof(*filter)); + StatsProvider provider_idx; + StatsRequestList *request_list = NULL; + + filter->target = target; + switch (target) { + case STATS_TARGET_VM: + break; + case STATS_TARGET_VCPU: + { + strList *vcpu_list = NULL; + CPUState *cpu = qemu_get_cpu(cpu_index); + char *canonical_path = object_get_canonical_path(OBJECT(cpu)); + + QAPI_LIST_PREPEND(vcpu_list, canonical_path); + filter->u.vcpu.has_vcpus = true; + filter->u.vcpu.vcpus = vcpu_list; + break; + } + default: + break; + } + + if (!names && provider == STATS_PROVIDER__MAX) { + return filter; + } + + /* + * "info stats" can only query either one or all the providers. Querying + * by name, but not by provider, requires the creation of one filter per + * provider. + */ + for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) { + if (provider == STATS_PROVIDER__MAX || provider == provider_idx) { + StatsRequest *request = g_new0(StatsRequest, 1); + request->provider = provider_idx; + if (names && !g_str_equal(names, "*")) { + request->has_names = true; + request->names = strList_from_comma_list(names); + } + QAPI_LIST_PREPEND(request_list, request); + } + } + + filter->has_providers = true; + filter->providers = request_list; + return filter; +} + +void hmp_info_stats(Monitor *mon, const QDict *qdict) +{ + const char *target_str = qdict_get_str(qdict, "target"); + const char *provider_str = qdict_get_try_str(qdict, "provider"); + const char *names = qdict_get_try_str(qdict, "names"); + + StatsProvider provider = STATS_PROVIDER__MAX; + StatsTarget target; + Error *err = NULL; + g_autoptr(StatsSchemaList) schema = NULL; + g_autoptr(StatsResultList) stats = NULL; + g_autoptr(StatsFilter) filter = NULL; + StatsResultList *entry; + + target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err); + if (err) { + monitor_printf(mon, "invalid stats target %s\n", target_str); + goto exit_no_print; + } + if (provider_str) { + provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err); + if (err) { + monitor_printf(mon, "invalid stats provider %s\n", provider_str); + goto exit_no_print; + } + } + + schema = qmp_query_stats_schemas(provider_str ? true : false, + provider, &err); + if (err) { + goto exit; + } + + switch (target) { + case STATS_TARGET_VM: + filter = stats_filter(target, names, -1, provider); + break; + case STATS_TARGET_VCPU: {} + int cpu_index = monitor_get_cpu_index(mon); + filter = stats_filter(target, names, cpu_index, provider); + break; + default: + abort(); + } + + stats = qmp_query_stats(filter, &err); + if (err) { + goto exit; + } + for (entry = stats; entry; entry = entry->next) { + print_stats_results(mon, target, provider_str == NULL, entry->value, schema); + } + +exit: + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + } +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->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->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 24fd2e5f34bf..43fd69f98461 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; } @@ -308,8 +313,8 @@ void help_cmd(Monitor *mon, const char *name) static const char *pch; static sigjmp_buf expr_env; -static void G_GNUC_PRINTF(2, 3) QEMU_NORETURN -expr_error(Monitor *mon, const char *fmt, ...) +static G_NORETURN G_GNUC_PRINTF(2, 3) +void expr_error(Monitor *mon, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -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 a756dbd6db0c..bf3f1c67ca4c 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -25,10 +25,8 @@ #include "qemu/osdep.h" #include "monitor-internal.h" #include "monitor/qdev.h" -#include "hw/usb.h" #include "hw/pci/pci.h" #include "sysemu/watchdog.h" -#include "hw/loader.h" #include "exec/gdbstub.h" #include "net/net.h" #include "net/slirp.h" @@ -39,17 +37,14 @@ #include "ui/input.h" #include "audio/audio.h" #include "disas/disas.h" -#include "sysemu/balloon.h" #include "qemu/timer.h" #include "qemu/log.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" #include "authz/list.h" #include "qapi/util.h" -#include "sysemu/blockdev.h" #include "sysemu/sysemu.h" -#include "sysemu/tcg.h" -#include "sysemu/tpm.h" +#include "sysemu/device_tree.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qstring.h" @@ -77,7 +72,6 @@ #include "qapi/qapi-init-commands.h" #include "qapi/error.h" #include "qapi/qmp-event.h" -#include "sysemu/cpus.h" #include "qemu/cutils.h" #if defined(TARGET_S390X) @@ -85,6 +79,9 @@ #include "hw/s390x/storage-attributes.h" #endif +/* Make devices configuration available for use in hmp-commands*.hx templates */ +#include CONFIG_DEVICES + /* file descriptors passed via SCM_RIGHTS */ typedef struct mon_fd_t mon_fd_t; struct mon_fd_t { @@ -305,6 +302,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) { @@ -313,13 +311,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); } } @@ -389,7 +392,7 @@ static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) void qmp_client_migrate_info(const char *protocol, const char *hostname, bool has_port, int64_t port, bool has_tls_port, int64_t tls_port, - bool has_cert_subject, const char *cert_subject, + const char *cert_subject, Error **errp) { if (strcmp(protocol, "spice") == 0) { @@ -419,8 +422,7 @@ static void hmp_logfile(Monitor *mon, const QDict *qdict) { Error *err = NULL; - qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err); - if (err) { + if (!qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err)) { error_report_err(err); } } @@ -429,6 +431,7 @@ static void hmp_log(Monitor *mon, const QDict *qdict) { int mask; const char *items = qdict_get_str(qdict, "items"); + Error *err = NULL; if (!strcmp(items, "none")) { mask = 0; @@ -439,7 +442,10 @@ static void hmp_log(Monitor *mon, const QDict *qdict) return; } } - qemu_set_log(mask); + + if (!qemu_set_log(mask, &err)) { + error_report_err(err); + } } static void hmp_singlestep(Monitor *mon, const QDict *qdict) @@ -720,7 +726,7 @@ static uint64_t vtop(void *ptr, Error **errp) uint64_t pinfo; uint64_t ret = -1; uintptr_t addr = (uintptr_t) ptr; - uintptr_t pagesize = qemu_real_host_page_size; + uintptr_t pagesize = qemu_real_host_page_size(); off_t offset = addr / pagesize * sizeof(pinfo); int fd; @@ -1074,6 +1080,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) } fd = monfd->fd; + assert(fd >= 0); /* caller takes ownership of fd */ QLIST_REMOVE(monfd, next); @@ -1120,7 +1127,7 @@ void monitor_fdsets_cleanup(void) } } -AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque, +AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, const char *opaque, Error **errp) { int fd; @@ -1133,8 +1140,7 @@ AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque, goto error; } - fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, - has_opaque, opaque, errp); + fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp); if (fdinfo) { return fdinfo; } @@ -1202,12 +1208,7 @@ FdsetInfoList *qmp_query_fdsets(Error **errp) fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); fdsetfd_info->fd = mon_fdset_fd->fd; - if (mon_fdset_fd->opaque) { - fdsetfd_info->has_opaque = true; - fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); - } else { - fdsetfd_info->has_opaque = false; - } + fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info); } @@ -1219,8 +1220,7 @@ FdsetInfoList *qmp_query_fdsets(Error **errp) } AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, - bool has_opaque, const char *opaque, - Error **errp) + const char *opaque, Error **errp) { MonFdset *mon_fdset = NULL; MonFdsetFd *mon_fdset_fd; @@ -1288,9 +1288,7 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); mon_fdset_fd->fd = fd; mon_fdset_fd->removed = false; - if (has_opaque) { - mon_fdset_fd->opaque = g_strdup(opaque); - } + mon_fdset_fd->opaque = g_strdup(opaque); QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); fdinfo = g_malloc0(sizeof(*fdinfo)); @@ -1391,23 +1389,16 @@ void monitor_fdset_dup_fd_remove(int dup_fd) int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) { int fd; - Error *local_err = NULL; if (!qemu_isdigit(fdname[0]) && mon) { - fd = monitor_get_fd(mon, fdname, &local_err); + fd = monitor_get_fd(mon, fdname, errp); } else { fd = qemu_parse_fd(fdname); - if (fd == -1) { - error_setg(&local_err, "Invalid file descriptor number '%s'", + if (fd < 0) { + error_setg(errp, "Invalid file descriptor number '%s'", fdname); } } - if (local_err) { - error_propagate(errp, local_err); - assert(fd == -1); - } else { - assert(fd != -1); - } return fd; } diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index caa2e90ef22a..a2cdbbf64643 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/monitor.c b/monitor/monitor.c index 21c7a68758f5..7ed7bd53421f 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -286,6 +286,16 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap) return -1; } +int error_printf_unless_qmp(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = error_vprintf_unless_qmp(fmt, ap); + va_end(ap); + return ret; +} static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { /* Limit guest-triggerable events to 1 per second */ @@ -701,8 +711,8 @@ void monitor_init_globals_core(void) int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) { + ERRP_GUARD(); Chardev *chr; - Error *local_err = NULL; chr = qemu_chr_find(opts->chardev); if (chr == NULL) { @@ -716,7 +726,7 @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) switch (opts->mode) { case MONITOR_MODE_CONTROL: - monitor_init_qmp(chr, opts->pretty, &local_err); + monitor_init_qmp(chr, opts->pretty, errp); break; case MONITOR_MODE_READLINE: if (!allow_hmp) { @@ -727,17 +737,13 @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) error_setg(errp, "'pretty' is not compatible with HMP monitors"); return -1; } - monitor_init_hmp(chr, true, &local_err); + monitor_init_hmp(chr, true, errp); break; default: g_assert_not_reached(); } - if (local_err) { - error_propagate(errp, local_err); - return -1; - } - return 0; + return *errp ? -1 : 0; } int monitor_init_opts(QemuOpts *opts, Error **errp) diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 0b04855ce899..2932b3f3a5b2 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -14,7 +14,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/option.h" #include "monitor/monitor.h" @@ -36,6 +35,7 @@ #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" +#include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-ui.h" #include "qapi/type-helpers.h" #include "qapi/qmp/qerror.h" @@ -44,16 +44,13 @@ #include "hw/acpi/acpi_dev_interface.h" #include "hw/intc/intc.h" #include "hw/rdma/rdma.h" +#include "monitor/stats.h" NameInfo *qmp_query_name(Error **errp) { NameInfo *info = g_malloc0(sizeof(*info)); - if (qemu_name) { - info->has_name = true; - info->name = g_strdup(qemu_name); - } - + info->name = g_strdup(qemu_name); return info; } @@ -85,7 +82,7 @@ void qmp_stop(Error **errp) { /* if there is a dump in background, we should wait until the dump * finished */ - if (dump_in_progress()) { + if (qemu_system_dump_in_progress()) { error_setg(errp, "There is a dump in process, please wait."); return; } @@ -115,7 +112,7 @@ void qmp_cont(Error **errp) /* if there is a dump in background, we should wait until the dump * finished */ - if (dump_in_progress()) { + if (qemu_system_dump_in_progress()) { error_setg(errp, "There is a dump in process, please wait."); return; } @@ -134,8 +131,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 @@ -347,6 +347,21 @@ void qmp_display_reload(DisplayReloadOptions *arg, Error **errp) } } +void qmp_display_update(DisplayUpdateOptions *arg, Error **errp) +{ + switch (arg->type) { + case DISPLAY_UPDATE_TYPE_VNC: +#ifdef CONFIG_VNC + vnc_display_update(&arg->u.vnc, errp); +#else + error_setg(errp, "vnc is invalid, missing 'CONFIG_VNC'"); +#endif + break; + default: + abort(); + } +} + static int qmp_x_query_rdma_foreach(Object *obj, void *opaque) { RdmaProvider *rdma; @@ -427,3 +442,153 @@ HumanReadableText *qmp_x_query_irq(Error **errp) return human_readable_text_from_str(buf); } + +typedef struct StatsCallbacks { + StatsProvider provider; + StatRetrieveFunc *stats_cb; + SchemaRetrieveFunc *schemas_cb; + QTAILQ_ENTRY(StatsCallbacks) next; +} StatsCallbacks; + +static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = + QTAILQ_HEAD_INITIALIZER(stats_callbacks); + +void add_stats_callbacks(StatsProvider provider, + StatRetrieveFunc *stats_fn, + SchemaRetrieveFunc *schemas_fn) +{ + StatsCallbacks *entry = g_new(StatsCallbacks, 1); + entry->provider = provider; + entry->stats_cb = stats_fn; + entry->schemas_cb = schemas_fn; + + QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); +} + +static bool invoke_stats_cb(StatsCallbacks *entry, + StatsResultList **stats_results, + StatsFilter *filter, StatsRequest *request, + Error **errp) +{ + ERRP_GUARD(); + strList *targets = NULL; + strList *names = NULL; + + if (request) { + if (request->provider != entry->provider) { + return true; + } + if (request->has_names && !request->names) { + return true; + } + names = request->has_names ? request->names : NULL; + } + + switch (filter->target) { + case STATS_TARGET_VM: + break; + case STATS_TARGET_VCPU: + if (filter->u.vcpu.has_vcpus) { + if (!filter->u.vcpu.vcpus) { + /* No targets allowed? Return no statistics. */ + return true; + } + targets = filter->u.vcpu.vcpus; + } + break; + default: + abort(); + } + + entry->stats_cb(stats_results, filter->target, names, targets, errp); + if (*errp) { + qapi_free_StatsResultList(*stats_results); + *stats_results = NULL; + return false; + } + return true; +} + +StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) +{ + StatsResultList *stats_results = NULL; + StatsCallbacks *entry; + StatsRequestList *request; + + QTAILQ_FOREACH(entry, &stats_callbacks, next) { + if (filter->has_providers) { + for (request = filter->providers; request; request = request->next) { + if (!invoke_stats_cb(entry, &stats_results, filter, + request->value, errp)) { + break; + } + } + } else { + if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { + break; + } + } + } + + return stats_results; +} + +StatsSchemaList *qmp_query_stats_schemas(bool has_provider, + StatsProvider provider, + Error **errp) +{ + ERRP_GUARD(); + StatsSchemaList *stats_results = NULL; + StatsCallbacks *entry; + + QTAILQ_FOREACH(entry, &stats_callbacks, next) { + if (!has_provider || provider == entry->provider) { + entry->schemas_cb(&stats_results, errp); + if (*errp) { + qapi_free_StatsSchemaList(stats_results); + return NULL; + } + } + } + + return stats_results; +} + +void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, + const char *qom_path, StatsList *stats_list) +{ + StatsResult *entry = g_new0(StatsResult, 1); + + entry->provider = provider; + entry->qom_path = g_strdup(qom_path); + entry->stats = stats_list; + + QAPI_LIST_PREPEND(*stats_results, entry); +} + +void add_stats_schema(StatsSchemaList **schema_results, + StatsProvider provider, StatsTarget target, + StatsSchemaValueList *stats_list) +{ + StatsSchema *entry = g_new0(StatsSchema, 1); + + entry->provider = provider; + entry->target = target; + entry->stats = stats_list; + QAPI_LIST_PREPEND(*schema_results, entry); +} + +bool apply_str_list_filter(const char *string, strList *list) +{ + strList *str_list = NULL; + + if (!list) { + return true; + } + for (str_list = list; str_list; str_list = str_list->next) { + if (g_str_equal(string, str_list->value)) { + return true; + } + } + return false; +} diff --git a/nbd/client-connection.c b/nbd/client-connection.c index 2a632931c393..0c5f917efac0 100644 --- a/nbd/client-connection.c +++ b/nbd/client-connection.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "trace.h" #include "block/nbd.h" @@ -210,6 +211,7 @@ static void *connect_thread_func(void *opaque) object_unref(OBJECT(conn->sioc)); conn->sioc = NULL; if (conn->do_retry && !conn->detached) { + trace_nbd_connect_thread_sleep(timeout); qemu_mutex_unlock(&conn->mutex); sleep(timeout); diff --git a/nbd/server.c b/nbd/server.c index c5644fd3f6ad..67ed33357847 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2021 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device Server Side @@ -1638,12 +1638,12 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, { NBDExport *exp = container_of(blk_exp, NBDExport, common); BlockExportOptionsNbd *arg = &exp_args->u.nbd; + const char *name = arg->name ?: exp_args->node_name; BlockBackend *blk = blk_exp->blk; int64_t size; uint64_t perm, shared_perm; bool readonly = !exp_args->writable; - bool shared = !exp_args->writable; - strList *bitmaps; + BlockDirtyBitmapOrStrList *bitmaps; size_t i; int ret; @@ -1654,12 +1654,8 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, return -EINVAL; } - if (!arg->has_name) { - arg->name = exp_args->node_name; - } - - if (strlen(arg->name) > NBD_MAX_STRING_SIZE) { - error_setg(errp, "export name '%s' too long", arg->name); + if (strlen(name) > NBD_MAX_STRING_SIZE) { + error_setg(errp, "export name '%s' too long", name); return -EINVAL; } @@ -1668,8 +1664,8 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, return -EINVAL; } - if (nbd_export_find(arg->name)) { - error_setg(errp, "NBD server already has export named '%s'", arg->name); + if (nbd_export_find(name)) { + error_setg(errp, "NBD server already has export named '%s'", name); return -EEXIST; } @@ -1689,15 +1685,16 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, } QTAILQ_INIT(&exp->clients); - exp->name = g_strdup(arg->name); + exp->name = g_strdup(name); exp->description = g_strdup(arg->description); exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE); + + if (nbd_server_max_connections() != 1) { + exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; + } if (readonly) { exp->nbdflags |= NBD_FLAG_READ_ONLY; - if (shared) { - exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; - } } else { exp->nbdflags |= (NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_FAST_ZERO); @@ -1709,37 +1706,56 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, } exp->export_bitmaps = g_new0(BdrvDirtyBitmap *, exp->nr_export_bitmaps); for (i = 0, bitmaps = arg->bitmaps; bitmaps; - i++, bitmaps = bitmaps->next) { - const char *bitmap = bitmaps->value; + i++, bitmaps = bitmaps->next) + { + const char *bitmap; BlockDriverState *bs = blk_bs(blk); BdrvDirtyBitmap *bm = NULL; - while (bs) { - bm = bdrv_find_dirty_bitmap(bs, bitmap); - if (bm != NULL) { - break; + switch (bitmaps->value->type) { + case QTYPE_QSTRING: + bitmap = bitmaps->value->u.local; + while (bs) { + bm = bdrv_find_dirty_bitmap(bs, bitmap); + if (bm != NULL) { + break; + } + + bs = bdrv_filter_or_cow_bs(bs); } - bs = bdrv_filter_or_cow_bs(bs); - } + if (bm == NULL) { + ret = -ENOENT; + error_setg(errp, "Bitmap '%s' is not found", + bitmaps->value->u.local); + goto fail; + } - if (bm == NULL) { - ret = -ENOENT; - error_setg(errp, "Bitmap '%s' is not found", bitmap); - goto fail; + if (readonly && bdrv_is_writable(bs) && + bdrv_dirty_bitmap_enabled(bm)) { + ret = -EINVAL; + error_setg(errp, "Enabled bitmap '%s' incompatible with " + "readonly export", bitmap); + goto fail; + } + break; + case QTYPE_QDICT: + bitmap = bitmaps->value->u.external.name; + bm = block_dirty_bitmap_lookup(bitmaps->value->u.external.node, + bitmap, NULL, errp); + if (!bm) { + ret = -ENOENT; + goto fail; + } + break; + default: + abort(); } - if (bdrv_dirty_bitmap_check(bm, BDRV_BITMAP_ALLOW_RO, errp)) { - ret = -EINVAL; - goto fail; - } + assert(bm); - if (readonly && bdrv_is_writable(bs) && - bdrv_dirty_bitmap_enabled(bm)) { + if (bdrv_dirty_bitmap_check(bm, BDRV_BITMAP_ALLOW_RO, errp)) { ret = -EINVAL; - error_setg(errp, - "Enabled bitmap '%s' incompatible with readonly export", - bitmap); goto fail; } @@ -1972,7 +1988,7 @@ static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, } /* Do a sparse read and send the structured reply to the client. - * Returns -errno if sending fails. bdrv_block_status_above() failure is + * Returns -errno if sending fails. blk_co_block_status_above() failure is * reported to the client, at which point this function succeeds. */ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, @@ -1988,10 +2004,10 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, while (progress < size) { int64_t pnum; - int status = bdrv_block_status_above(blk_bs(exp->common.blk), NULL, - offset + progress, - size - progress, &pnum, NULL, - NULL); + int status = blk_co_block_status_above(exp->common.blk, NULL, + offset + progress, + size - progress, &pnum, NULL, + NULL); bool final; if (status < 0) { @@ -2020,8 +2036,8 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, stl_be_p(&chunk.length, pnum); ret = nbd_co_send_iov(client, iov, 1, errp); } else { - ret = blk_pread(exp->common.blk, offset + progress, - data + progress, pnum); + ret = blk_pread(exp->common.blk, offset + progress, pnum, + data + progress, 0); if (ret < 0) { error_setg_errno(errp, -ret, "reading from file failed"); break; @@ -2122,14 +2138,15 @@ static int nbd_extent_array_add(NBDExtentArray *ea, return 0; } -static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, - uint64_t bytes, NBDExtentArray *ea) +static int coroutine_fn blockstatus_to_extents(BlockBackend *blk, + uint64_t offset, uint64_t bytes, + NBDExtentArray *ea) { while (bytes) { uint32_t flags; int64_t num; - int ret = bdrv_block_status_above(bs, NULL, offset, bytes, &num, - NULL, NULL); + int ret = blk_co_block_status_above(blk, NULL, offset, bytes, &num, + NULL, NULL); if (ret < 0) { return ret; @@ -2149,13 +2166,14 @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, return 0; } -static int blockalloc_to_extents(BlockDriverState *bs, uint64_t offset, - uint64_t bytes, NBDExtentArray *ea) +static int coroutine_fn blockalloc_to_extents(BlockBackend *blk, + uint64_t offset, uint64_t bytes, + NBDExtentArray *ea) { while (bytes) { int64_t num; - int ret = bdrv_is_allocated_above(bs, NULL, false, offset, bytes, - &num); + int ret = blk_co_is_allocated_above(blk, NULL, false, offset, bytes, + &num); if (ret < 0) { return ret; @@ -2201,20 +2219,21 @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, } /* Get block status from the exported device and send it to the client */ -static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, - BlockDriverState *bs, uint64_t offset, - uint32_t length, bool dont_fragment, - bool last, uint32_t context_id, - Error **errp) +static int +coroutine_fn nbd_co_send_block_status(NBDClient *client, uint64_t handle, + BlockBackend *blk, uint64_t offset, + uint32_t length, bool dont_fragment, + bool last, uint32_t context_id, + Error **errp) { int ret; unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS; g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents); if (context_id == NBD_META_ID_BASE_ALLOCATION) { - ret = blockstatus_to_extents(bs, offset, length, ea); + ret = blockstatus_to_extents(blk, offset, length, ea); } else { - ret = blockalloc_to_extents(bs, offset, length, ea); + ret = blockalloc_to_extents(blk, offset, length, ea); } if (ret < 0) { return nbd_co_send_structured_error( @@ -2425,7 +2444,7 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request, data, request->len, errp); } - ret = blk_pread(exp->common.blk, request->from, data, request->len); + ret = blk_pread(exp->common.blk, request->from, request->len, data, 0); if (ret < 0) { return nbd_send_generic_reply(client, request->handle, ret, "reading from file failed", errp); @@ -2492,7 +2511,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, if (request->flags & NBD_CMD_FLAG_FUA) { flags |= BDRV_REQ_FUA; } - ret = blk_pwrite(exp->common.blk, request->from, data, request->len, + ret = blk_pwrite(exp->common.blk, request->from, request->len, data, flags); return nbd_send_generic_reply(client, request->handle, ret, "writing to file failed", errp); @@ -2541,7 +2560,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, if (client->export_meta.base_allocation) { ret = nbd_co_send_block_status(client, request->handle, - blk_bs(exp->common.blk), + exp->common.blk, request->from, request->len, dont_fragment, !--contexts_remaining, @@ -2554,7 +2573,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, if (client->export_meta.allocation_depth) { ret = nbd_co_send_block_status(client, request->handle, - blk_bs(exp->common.blk), + exp->common.blk, request->from, request->len, dont_fragment, !--contexts_remaining, diff --git a/nbd/trace-events b/nbd/trace-events index c4919a2dd581..b7032ca2778a 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -73,3 +73,6 @@ nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *n nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32 nbd_co_receive_align_compliance(const char *op, uint64_t from, uint32_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx32 ", align=0x%" PRIx32 nbd_trip(void) "Reading request" + +# client-connection.c +nbd_connect_thread_sleep(uint64_t timeout) "timeout %" PRIu64 diff --git a/net/announce.c b/net/announce.c index 3b9e2f1f14e8..9e9904442238 100644 --- a/net/announce.c +++ b/net/announce.c @@ -7,7 +7,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/cutils.h" #include "net/announce.h" #include "net/net.h" #include "qapi/clone-visitor.h" @@ -46,7 +46,7 @@ void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named) } qapi_free_strList(timer->params.interfaces); timer->params.interfaces = NULL; - if (free_named && timer->params.has_id) { + if (free_named && timer->params.id) { AnnounceTimer *list_timer; /* * Sanity check: There should only be one timer on the list with @@ -157,7 +157,7 @@ static void qemu_announce_self_iter(NICState *nic, void *opaque) skip = false; } - trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_", + trace_qemu_announce_self_iter(timer->params.id ?: "_", nic->ncs->name, qemu_ether_ntoa(&nic->conf->macaddr), skip); @@ -199,9 +199,9 @@ void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params) void qmp_announce_self(AnnounceParameters *params, Error **errp) { AnnounceTimer *named_timer; - if (!params->has_id) { + + if (!params->id) { params->id = g_strdup(""); - params->has_id = true; } named_timer = g_datalist_get_data(&named_timers, params->id); diff --git a/net/can/can_socketcan.c b/net/can/can_socketcan.c index 4b68f60c6b66..c1a1ad05636b 100644 --- a/net/can/can_socketcan.c +++ b/net/can/can_socketcan.c @@ -76,19 +76,21 @@ QEMU_BUILD_BUG_ON(offsetof(qemu_can_frame, data) static void can_host_socketcan_display_msg(struct qemu_can_frame *msg) { int i; - FILE *logfile = qemu_log_lock(); - qemu_log("[cansocketcan]: %03X [%01d] %s %s", - msg->can_id & QEMU_CAN_EFF_MASK, - msg->can_dlc, - msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF", - msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT"); - - for (i = 0; i < msg->can_dlc; i++) { - qemu_log(" %02X", msg->data[i]); + FILE *logfile = qemu_log_trylock(); + + if (logfile) { + fprintf(logfile, "[cansocketcan]: %03X [%01d] %s %s", + msg->can_id & QEMU_CAN_EFF_MASK, + msg->can_dlc, + msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF", + msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT"); + + for (i = 0; i < msg->can_dlc; i++) { + fprintf(logfile, " %02X", msg->data[i]); + } + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); } - qemu_log("\n"); - qemu_log_flush(); - qemu_log_unlock(logfile); } static void can_host_socketcan_read(void *opaque) diff --git a/net/clients.h b/net/clients.h index 92f9b59aedce..ed8bdfff1e7c 100644 --- a/net/clients.h +++ b/net/clients.h @@ -40,6 +40,12 @@ int net_init_hubport(const Netdev *netdev, const char *name, int net_init_socket(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); +int net_init_stream(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + +int net_init_dgram(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + int net_init_tap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); @@ -63,4 +69,15 @@ int net_init_vhost_user(const Netdev *netdev, const char *name, int net_init_vhost_vdpa(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); +#ifdef CONFIG_VMNET +int net_init_vmnet_host(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + +int net_init_vmnet_shared(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + +int net_init_vmnet_bridged(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); +#endif /* CONFIG_VMNET */ + #endif /* QEMU_NET_CLIENTS_H */ diff --git a/net/colo-compare.c b/net/colo-compare.c index 62554b5b3c8f..7f9e6f89ce05 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -13,7 +13,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "trace.h" #include "qapi/error.h" @@ -1136,22 +1135,17 @@ static void set_max_queue_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *local_err = NULL; uint64_t value; - visit_type_uint64(v, name, &value, &local_err); - if (local_err) { - goto out; + if (!visit_type_uint64(v, name, &value, errp)) { + return; } if (!value) { - error_setg(&local_err, "Property '%s.%s' requires a positive value", + error_setg(errp, "Property '%s.%s' requires a positive value", object_get_typename(obj), name); - goto out; + return; } max_queue_size = value; - -out: - error_propagate(errp, local_err); } static void compare_pri_rs_finalize(SocketReadState *pri_rs) @@ -1324,7 +1318,7 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) s->connection_track_table = g_hash_table_new_full(connection_key_hash, connection_key_equal, g_free, - connection_destroy); + NULL); colo_compare_iothread(s); diff --git a/net/colo.c b/net/colo.c index 1f8162f59f77..fb2c36a026f8 100644 --- a/net/colo.c +++ b/net/colo.c @@ -44,14 +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 = eth_get_l2_hdr_length(data); - - if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) { - trace_colo_proxy_main("pkt->size < ETH_HLEN"); + ssize_t l2hdr_len; + + assert(data); + + /* 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. @@ -218,7 +232,7 @@ Connection *connection_get(GHashTable *connection_track_table, /* * clear the conn_list */ - while (!g_queue_is_empty(conn_list)) { + while (conn_list && !g_queue_is_empty(conn_list)) { connection_destroy(g_queue_pop_head(conn_list)); } } diff --git a/net/colo.h b/net/colo.h index 8b3e8d5a8366..22fc3031f722 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/dgram.c b/net/dgram.c new file mode 100644 index 000000000000..9f7bf3837653 --- /dev/null +++ b/net/dgram.c @@ -0,0 +1,623 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2022 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#include "net/net.h" +#include "clients.h" +#include "monitor/monitor.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "qemu/sockets.h" +#include "qemu/iov.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" + +typedef struct NetDgramState { + NetClientState nc; + int fd; + SocketReadState rs; + bool read_poll; /* waiting to receive data? */ + bool write_poll; /* waiting to transmit data? */ + /* contains destination iff connectionless */ + struct sockaddr *dest_addr; + socklen_t dest_len; +} NetDgramState; + +static void net_dgram_send(void *opaque); +static void net_dgram_writable(void *opaque); + +static void net_dgram_update_fd_handler(NetDgramState *s) +{ + qemu_set_fd_handler(s->fd, + s->read_poll ? net_dgram_send : NULL, + s->write_poll ? net_dgram_writable : NULL, + s); +} + +static void net_dgram_read_poll(NetDgramState *s, bool enable) +{ + s->read_poll = enable; + net_dgram_update_fd_handler(s); +} + +static void net_dgram_write_poll(NetDgramState *s, bool enable) +{ + s->write_poll = enable; + net_dgram_update_fd_handler(s); +} + +static void net_dgram_writable(void *opaque) +{ + NetDgramState *s = opaque; + + net_dgram_write_poll(s, false); + + qemu_flush_queued_packets(&s->nc); +} + +static ssize_t net_dgram_receive(NetClientState *nc, + const uint8_t *buf, size_t size) +{ + NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc); + ssize_t ret; + + do { + if (s->dest_addr) { + ret = sendto(s->fd, buf, size, 0, s->dest_addr, s->dest_len); + } else { + ret = send(s->fd, buf, size, 0); + } + } while (ret == -1 && errno == EINTR); + + if (ret == -1 && errno == EAGAIN) { + net_dgram_write_poll(s, true); + return 0; + } + return ret; +} + +static void net_dgram_send_completed(NetClientState *nc, ssize_t len) +{ + NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc); + + if (!s->read_poll) { + net_dgram_read_poll(s, true); + } +} + +static void net_dgram_rs_finalize(SocketReadState *rs) +{ + NetDgramState *s = container_of(rs, NetDgramState, rs); + + if (qemu_send_packet_async(&s->nc, rs->buf, + rs->packet_len, + net_dgram_send_completed) == 0) { + net_dgram_read_poll(s, false); + } +} + +static void net_dgram_send(void *opaque) +{ + NetDgramState *s = opaque; + int size; + + size = recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0); + if (size < 0) { + return; + } + if (size == 0) { + /* end of connection */ + net_dgram_read_poll(s, false); + net_dgram_write_poll(s, false); + return; + } + if (qemu_send_packet_async(&s->nc, s->rs.buf, size, + net_dgram_send_completed) == 0) { + net_dgram_read_poll(s, false); + } +} + +static int net_dgram_mcast_create(struct sockaddr_in *mcastaddr, + struct in_addr *localaddr, + Error **errp) +{ + struct ip_mreq imr; + int fd; + int val, ret; +#ifdef __OpenBSD__ + unsigned char loop; +#else + int loop; +#endif + + if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { + error_setg(errp, "specified mcastaddr %s (0x%08x) " + "does not contain a multicast address", + inet_ntoa(mcastaddr->sin_addr), + (int)ntohl(mcastaddr->sin_addr.s_addr)); + return -1; + } + + fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create datagram socket"); + return -1; + } + + /* + * Allow multiple sockets to bind the same multicast ip and port by setting + * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set + * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR + * only on posix systems. + */ + val = 1; + ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't set socket option SO_REUSEADDR"); + goto fail; + } + + ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind ip=%s to socket", + inet_ntoa(mcastaddr->sin_addr)); + goto fail; + } + + /* Add host to multicast group */ + imr.imr_multiaddr = mcastaddr->sin_addr; + if (localaddr) { + imr.imr_interface = *localaddr; + } else { + imr.imr_interface.s_addr = htonl(INADDR_ANY); + } + + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &imr, sizeof(struct ip_mreq)); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't add socket to multicast group %s", + inet_ntoa(imr.imr_multiaddr)); + goto fail; + } + + /* Force mcast msgs to loopback (eg. several QEMUs in same host */ + loop = 1; + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop, sizeof(loop)); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't force multicast message to loopback"); + goto fail; + } + + /* If a bind address is given, only send packets from that address */ + if (localaddr != NULL) { + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, + localaddr, sizeof(*localaddr)); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't set the default network send interface"); + goto fail; + } + } + + qemu_socket_set_nonblock(fd); + return fd; +fail: + if (fd >= 0) { + closesocket(fd); + } + return -1; +} + +static void net_dgram_cleanup(NetClientState *nc) +{ + NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc); + if (s->fd != -1) { + net_dgram_read_poll(s, false); + net_dgram_write_poll(s, false); + close(s->fd); + s->fd = -1; + } + g_free(s->dest_addr); + s->dest_addr = NULL; + s->dest_len = 0; +} + +static NetClientInfo net_dgram_socket_info = { + .type = NET_CLIENT_DRIVER_DGRAM, + .size = sizeof(NetDgramState), + .receive = net_dgram_receive, + .cleanup = net_dgram_cleanup, +}; + +static NetDgramState *net_dgram_fd_init(NetClientState *peer, + const char *model, + const char *name, + int fd, + Error **errp) +{ + NetClientState *nc; + NetDgramState *s; + + nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); + + s = DO_UPCAST(NetDgramState, nc, nc); + + s->fd = fd; + net_socket_rs_init(&s->rs, net_dgram_rs_finalize, false); + net_dgram_read_poll(s, true); + + return s; +} + +static int net_dgram_mcast_init(NetClientState *peer, + const char *model, + const char *name, + SocketAddress *remote, + SocketAddress *local, + Error **errp) +{ + NetDgramState *s; + int fd, ret; + struct sockaddr_in *saddr; + + if (remote->type != SOCKET_ADDRESS_TYPE_INET) { + error_setg(errp, "multicast only support inet type"); + return -1; + } + + saddr = g_new(struct sockaddr_in, 1); + if (convert_host_port(saddr, remote->u.inet.host, remote->u.inet.port, + errp) < 0) { + g_free(saddr); + return -1; + } + + if (!local) { + fd = net_dgram_mcast_create(saddr, NULL, errp); + if (fd < 0) { + g_free(saddr); + return -1; + } + } else { + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: { + struct in_addr localaddr; + + if (inet_aton(local->u.inet.host, &localaddr) == 0) { + g_free(saddr); + error_setg(errp, "localaddr '%s' is not a valid IPv4 address", + local->u.inet.host); + return -1; + } + + fd = net_dgram_mcast_create(saddr, &localaddr, errp); + if (fd < 0) { + g_free(saddr); + return -1; + } + break; + } + case SOCKET_ADDRESS_TYPE_FD: { + int newfd; + + fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); + if (fd == -1) { + g_free(saddr); + return -1; + } + ret = qemu_socket_try_set_nonblock(fd); + if (ret < 0) { + g_free(saddr); + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } + + /* + * fd passed: multicast: "learn" dest_addr address from bound + * address and save it. Because this may be "shared" socket from a + * "master" process, datagrams would be recv() by ONLY ONE process: + * we must "clone" this dgram socket --jjo + */ + + saddr = g_new(struct sockaddr_in, 1); + + if (convert_host_port(saddr, local->u.inet.host, local->u.inet.port, + errp) < 0) { + g_free(saddr); + closesocket(fd); + return -1; + } + + /* must be bound */ + if (saddr->sin_addr.s_addr == 0) { + error_setg(errp, "can't setup multicast destination address"); + g_free(saddr); + closesocket(fd); + return -1; + } + /* clone dgram socket */ + newfd = net_dgram_mcast_create(saddr, NULL, errp); + if (newfd < 0) { + g_free(saddr); + closesocket(fd); + return -1; + } + /* clone newfd to fd, close newfd */ + dup2(newfd, fd); + close(newfd); + break; + } + default: + g_free(saddr); + error_setg(errp, "only support inet or fd type for local"); + return -1; + } + } + + s = net_dgram_fd_init(peer, model, name, fd, errp); + if (!s) { + g_free(saddr); + return -1; + } + + g_assert(s->dest_addr == NULL); + s->dest_addr = (struct sockaddr *)saddr; + s->dest_len = sizeof(*saddr); + + if (!local) { + qemu_set_info_str(&s->nc, "mcast=%s:%d", + inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); + } else { + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: + qemu_set_info_str(&s->nc, "mcast=%s:%d", + inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); + break; + case SOCKET_ADDRESS_TYPE_FD: + qemu_set_info_str(&s->nc, "fd=%d (cloned mcast=%s:%d)", + fd, inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); + break; + default: + g_assert_not_reached(); + } + } + + return 0; + +} + + +int net_init_dgram(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + NetDgramState *s; + int fd, ret; + SocketAddress *remote, *local; + struct sockaddr *dest_addr; + struct sockaddr_in laddr_in, raddr_in; + struct sockaddr_un laddr_un, raddr_un; + socklen_t dest_len; + + assert(netdev->type == NET_CLIENT_DRIVER_DGRAM); + + remote = netdev->u.dgram.remote; + local = netdev->u.dgram.local; + + /* detect multicast address */ + if (remote && remote->type == SOCKET_ADDRESS_TYPE_INET) { + struct sockaddr_in mcastaddr; + + if (convert_host_port(&mcastaddr, remote->u.inet.host, + remote->u.inet.port, errp) < 0) { + return -1; + } + + if (IN_MULTICAST(ntohl(mcastaddr.sin_addr.s_addr))) { + return net_dgram_mcast_init(peer, "dram", name, remote, local, + errp); + } + } + + /* unicast address */ + if (!local) { + error_setg(errp, "dgram requires local= parameter"); + return -1; + } + + if (remote) { + if (local->type == SOCKET_ADDRESS_TYPE_FD) { + error_setg(errp, "don't set remote with local.fd"); + return -1; + } + if (remote->type != local->type) { + error_setg(errp, "remote and local types must be the same"); + return -1; + } + } else { + if (local->type != SOCKET_ADDRESS_TYPE_FD) { + error_setg(errp, + "type=inet or type=unix requires remote parameter"); + return -1; + } + } + + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: + if (convert_host_port(&laddr_in, local->u.inet.host, local->u.inet.port, + errp) < 0) { + return -1; + } + + if (convert_host_port(&raddr_in, remote->u.inet.host, + remote->u.inet.port, errp) < 0) { + return -1; + } + + fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create datagram socket"); + return -1; + } + + ret = socket_set_fast_reuse(fd); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't set socket option SO_REUSEADDR"); + closesocket(fd); + return -1; + } + ret = bind(fd, (struct sockaddr *)&laddr_in, sizeof(laddr_in)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind ip=%s to socket", + inet_ntoa(laddr_in.sin_addr)); + closesocket(fd); + return -1; + } + qemu_socket_set_nonblock(fd); + + dest_len = sizeof(raddr_in); + dest_addr = g_malloc(dest_len); + memcpy(dest_addr, &raddr_in, dest_len); + break; + case SOCKET_ADDRESS_TYPE_UNIX: + ret = unlink(local->u.q_unix.path); + if (ret < 0 && errno != ENOENT) { + error_setg_errno(errp, errno, "failed to unlink socket %s", + local->u.q_unix.path); + return -1; + } + + laddr_un.sun_family = PF_UNIX; + ret = snprintf(laddr_un.sun_path, sizeof(laddr_un.sun_path), "%s", + local->u.q_unix.path); + if (ret < 0 || ret >= sizeof(laddr_un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", + local->u.q_unix.path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(laddr_un.sun_path)); + } + + raddr_un.sun_family = PF_UNIX; + ret = snprintf(raddr_un.sun_path, sizeof(raddr_un.sun_path), "%s", + remote->u.q_unix.path); + if (ret < 0 || ret >= sizeof(raddr_un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", + remote->u.q_unix.path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(raddr_un.sun_path)); + } + + fd = qemu_socket(PF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create datagram socket"); + return -1; + } + + ret = bind(fd, (struct sockaddr *)&laddr_un, sizeof(laddr_un)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind unix=%s to socket", + laddr_un.sun_path); + closesocket(fd); + return -1; + } + qemu_socket_set_nonblock(fd); + + dest_len = sizeof(raddr_un); + dest_addr = g_malloc(dest_len); + memcpy(dest_addr, &raddr_un, dest_len); + break; + case SOCKET_ADDRESS_TYPE_FD: + fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); + if (fd == -1) { + return -1; + } + ret = qemu_socket_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } + dest_addr = NULL; + dest_len = 0; + break; + default: + error_setg(errp, "only support inet or fd type for local"); + return -1; + } + + s = net_dgram_fd_init(peer, "dgram", name, fd, errp); + if (!s) { + return -1; + } + + if (remote) { + g_assert(s->dest_addr == NULL); + s->dest_addr = dest_addr; + s->dest_len = dest_len; + } + + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: + qemu_set_info_str(&s->nc, "udp=%s:%d/%s:%d", + inet_ntoa(laddr_in.sin_addr), + ntohs(laddr_in.sin_port), + inet_ntoa(raddr_in.sin_addr), + ntohs(raddr_in.sin_port)); + break; + case SOCKET_ADDRESS_TYPE_UNIX: + qemu_set_info_str(&s->nc, "udp=%s:%s", + laddr_un.sun_path, raddr_un.sun_path); + break; + case SOCKET_ADDRESS_TYPE_FD: { + SocketAddress *sa; + SocketAddressType sa_type; + + sa = socket_local_address(fd, errp); + if (sa) { + sa_type = sa->type; + qapi_free_SocketAddress(sa); + + qemu_set_info_str(&s->nc, "fd=%d %s", fd, + SocketAddressType_str(sa_type)); + } else { + qemu_set_info_str(&s->nc, "fd=%d", fd); + } + break; + } + default: + g_assert_not_reached(); + } + + return 0; +} diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c index bf05023dc3c6..c18c4c201901 100644 --- a/net/filter-rewriter.c +++ b/net/filter-rewriter.c @@ -383,7 +383,7 @@ static void colo_rewriter_setup(NetFilterState *nf, Error **errp) s->connection_track_table = g_hash_table_new_full(connection_key_hash, connection_key_equal, g_free, - connection_destroy); + NULL); s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf); } diff --git a/net/hub.c b/net/hub.c index 1375738bf121..4c8a469a50aa 100644 --- a/net/hub.c +++ b/net/hub.c @@ -274,7 +274,7 @@ int net_init_hubport(const Netdev *netdev, const char *name, assert(!peer); hubport = &netdev->u.hubport; - if (hubport->has_netdev) { + if (hubport->netdev) { hubpeer = qemu_find_netdev(hubport->netdev); if (!hubpeer) { error_setg(errp, "netdev '%s' not found", hubport->netdev); @@ -313,6 +313,8 @@ void net_hub_check_clients(void) case NET_CLIENT_DRIVER_USER: case NET_CLIENT_DRIVER_TAP: case NET_CLIENT_DRIVER_SOCKET: + case NET_CLIENT_DRIVER_STREAM: + case NET_CLIENT_DRIVER_DGRAM: case NET_CLIENT_DRIVER_VDE: case NET_CLIENT_DRIVER_VHOST_USER: has_host_dev = 1; diff --git a/net/l2tpv3.c b/net/l2tpv3.c index b8faa8796c8f..53b2d32573b4 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -240,9 +240,7 @@ static ssize_t net_l2tpv3_receive_dgram_iov(NetClientState *nc, message.msg_control = NULL; message.msg_controllen = 0; message.msg_flags = 0; - do { - ret = sendmsg(s->fd, &message, 0); - } while ((ret == -1) && (errno == EINTR)); + ret = RETRY_ON_EINTR(sendmsg(s->fd, &message, 0)); if (ret > 0) { ret -= s->offset; } else if (ret == 0) { @@ -285,9 +283,7 @@ static ssize_t net_l2tpv3_receive_dgram(NetClientState *nc, message.msg_control = NULL; message.msg_controllen = 0; message.msg_flags = 0; - do { - ret = sendmsg(s->fd, &message, 0); - } while ((ret == -1) && (errno == EINTR)); + ret = RETRY_ON_EINTR(sendmsg(s->fd, &message, 0)); if (ret > 0) { ret -= s->offset; } else if (ret == 0) { @@ -434,12 +430,9 @@ static void net_l2tpv3_send(void *opaque) msgvec = s->msgvec + s->queue_head; if (target_count > 0) { - do { - count = recvmmsg( - s->fd, - msgvec, - target_count, MSG_DONTWAIT, NULL); - } while ((count == -1) && (errno == EINTR)); + count = RETRY_ON_EINTR( + recvmmsg(s->fd, msgvec, target_count, MSG_DONTWAIT, NULL) + ); if (count < 0) { /* Recv error - we still need to flush packets here, * (re)set queue head to current position @@ -578,7 +571,7 @@ int net_init_l2tpv3(const Netdev *netdev, if (l2tpv3->has_udp && l2tpv3->udp) { s->udp = true; - if (!(l2tpv3->has_srcport && l2tpv3->has_dstport)) { + if (!(l2tpv3->srcport && l2tpv3->dstport)) { error_setg(errp, "need both src and dst port for udp"); goto outerr; } else { @@ -716,15 +709,14 @@ int net_init_l2tpv3(const Netdev *netdev, s->vec = g_new(struct iovec, MAX_L2TPV3_IOVCNT); s->header_buf = g_malloc(s->header_size); - qemu_set_nonblock(fd); + qemu_socket_set_nonblock(fd); s->fd = fd; s->counter = 0; l2tpv3_read_poll(s, true); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "l2tpv3: connected"); + qemu_set_info_str(&s->nc, "l2tpv3: connected"); return 0; outerr: qemu_del_net_client(nc); diff --git a/net/meson.build b/net/meson.build index 847bc2ac85be..6cd1e3dab3a6 100644 --- a/net/meson.build +++ b/net/meson.build @@ -13,6 +13,8 @@ softmmu_ss.add(files( 'net.c', 'queue.c', 'socket.c', + 'stream.c', + 'dgram.c', 'util.c', )) @@ -26,10 +28,10 @@ softmmu_ss.add(when: vde, if_true: files('vde.c')) if have_netmap softmmu_ss.add(files('netmap.c')) endif -vhost_user_ss = ss.source_set() -vhost_user_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c')) -softmmu_ss.add_all(when: 'CONFIG_VHOST_NET_USER', if_true: vhost_user_ss) -softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-user-stub.c')) +if have_vhost_net_user + softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c')) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-user-stub.c')) +endif softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('tap-linux.c')) softmmu_ss.add(when: 'CONFIG_BSD', if_true: files('tap-bsd.c')) @@ -40,6 +42,16 @@ if not config_host.has_key('CONFIG_LINUX') and not config_host.has_key('CONFIG_B endif softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files(tap_posix)) softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c')) -softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c')) +if have_vhost_net_vdpa + softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-vdpa.c'), if_false: files('vhost-vdpa-stub.c')) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-vdpa-stub.c')) +endif +vmnet_files = files( + 'vmnet-common.m', + 'vmnet-bridged.m', + 'vmnet-host.c', + 'vmnet-shared.c' +) +softmmu_ss.add(when: vmnet, if_true: vmnet_files) subdir('can') diff --git a/net/net.c b/net/net.c index f0d14dbfc1f0..2d014729989f 100644 --- a/net/net.c +++ b/net/net.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "net/net.h" #include "clients.h" @@ -49,12 +48,14 @@ #include "qemu/qemu-print.h" #include "qemu/main-loop.h" #include "qemu/option.h" +#include "qemu/keyval.h" #include "qapi/error.h" #include "qapi/opts-visitor.h" #include "sysemu/runstate.h" #include "net/colo-compare.h" #include "net/filter.h" #include "qapi/string-output-visitor.h" +#include "qapi/qobject-input-visitor.h" /* Net bridge is currently not supported for W32. */ #if !defined(_WIN32) @@ -64,58 +65,70 @@ static VMChangeStateEntry *net_change_state_entry; static QTAILQ_HEAD(, NetClientState) net_clients; +typedef struct NetdevQueueEntry { + Netdev *nd; + Location loc; + QSIMPLEQ_ENTRY(NetdevQueueEntry) entry; +} NetdevQueueEntry; + +typedef QSIMPLEQ_HEAD(, NetdevQueueEntry) NetdevQueue; + +static NetdevQueue nd_queue = QSIMPLEQ_HEAD_INITIALIZER(nd_queue); + /***********************************************************/ /* network device redirectors */ -int parse_host_port(struct sockaddr_in *saddr, const char *str, - Error **errp) +int convert_host_port(struct sockaddr_in *saddr, const char *host, + const char *port, Error **errp) { - gchar **substrings; struct hostent *he; - const char *addr, *p, *r; - int port, ret = 0; + const char *r; + long p; memset(saddr, 0, sizeof(*saddr)); - substrings = g_strsplit(str, ":", 2); - if (!substrings || !substrings[0] || !substrings[1]) { - error_setg(errp, "host address '%s' doesn't contain ':' " - "separating host from port", str); - ret = -1; - goto out; - } - - addr = substrings[0]; - p = substrings[1]; - saddr->sin_family = AF_INET; - if (addr[0] == '\0') { + if (host[0] == '\0') { saddr->sin_addr.s_addr = 0; } else { - if (qemu_isdigit(addr[0])) { - if (!inet_aton(addr, &saddr->sin_addr)) { + if (qemu_isdigit(host[0])) { + if (!inet_aton(host, &saddr->sin_addr)) { error_setg(errp, "host address '%s' is not a valid " - "IPv4 address", addr); - ret = -1; - goto out; + "IPv4 address", host); + return -1; } } else { - he = gethostbyname(addr); + he = gethostbyname(host); if (he == NULL) { - error_setg(errp, "can't resolve host address '%s'", addr); - ret = -1; - goto out; + error_setg(errp, "can't resolve host address '%s'", host); + return -1; } saddr->sin_addr = *(struct in_addr *)he->h_addr; } } - port = strtol(p, (char **)&r, 0); - if (r == p) { - error_setg(errp, "port number '%s' is invalid", p); + if (qemu_strtol(port, &r, 0, &p) != 0) { + error_setg(errp, "port number '%s' is invalid", port); + return -1; + } + saddr->sin_port = htons(p); + return 0; +} + +int parse_host_port(struct sockaddr_in *saddr, const char *str, + Error **errp) +{ + gchar **substrings; + int ret; + + substrings = g_strsplit(str, ":", 2); + if (!substrings || !substrings[0] || !substrings[1]) { + error_setg(errp, "host address '%s' doesn't contain ':' " + "separating host from port", str); ret = -1; goto out; } - saddr->sin_port = htons(port); + + ret = convert_host_port(saddr, substrings[0], substrings[1], errp); out: g_strfreev(substrings); @@ -129,13 +142,20 @@ char *qemu_mac_strdup_printf(const uint8_t *macaddr) macaddr[3], macaddr[4], macaddr[5]); } +void qemu_set_info_str(NetClientState *nc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(nc->info_str, sizeof(nc->info_str), fmt, ap); + va_end(ap); +} + void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) { - snprintf(nc->info_str, sizeof(nc->info_str), - "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - nc->model, - macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); + qemu_set_info_str(nc, "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + nc->model, macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); } static int mac_table[256] = {0}; @@ -524,7 +544,7 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len) int qemu_set_vnet_le(NetClientState *nc, bool is_le) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN if (!nc || !nc->info->set_vnet_le) { return -ENOSYS; } @@ -537,7 +557,7 @@ int qemu_set_vnet_le(NetClientState *nc, bool is_le) int qemu_set_vnet_be(NetClientState *nc, bool is_be) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN return 0; #else if (!nc || !nc->info->set_vnet_be) { @@ -944,7 +964,7 @@ static int net_init_nic(const Netdev *netdev, const char *name, memset(nd, 0, sizeof(*nd)); - if (nic->has_netdev) { + if (nic->netdev) { nd->netdev = qemu_find_netdev(nic->netdev); if (!nd->netdev) { error_setg(errp, "netdev '%s' not found", nic->netdev); @@ -955,19 +975,19 @@ static int net_init_nic(const Netdev *netdev, const char *name, nd->netdev = peer; } nd->name = g_strdup(name); - if (nic->has_model) { + if (nic->model) { nd->model = g_strdup(nic->model); } - if (nic->has_addr) { + if (nic->addr) { nd->devaddr = g_strdup(nic->addr); } - if (nic->has_macaddr && + if (nic->macaddr && net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { error_setg(errp, "invalid syntax for ethernet address"); return -1; } - if (nic->has_macaddr && + if (nic->macaddr && is_multicast_ether_addr(nd->macaddr.a)) { error_setg(errp, "NIC cannot have multicast MAC address (odd 1st byte)"); @@ -1002,6 +1022,8 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( #endif [NET_CLIENT_DRIVER_TAP] = net_init_tap, [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, + [NET_CLIENT_DRIVER_STREAM] = net_init_stream, + [NET_CLIENT_DRIVER_DGRAM] = net_init_dgram, #ifdef CONFIG_VDE [NET_CLIENT_DRIVER_VDE] = net_init_vde, #endif @@ -1021,6 +1043,11 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( #ifdef CONFIG_L2TPV3 [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, #endif +#ifdef CONFIG_VMNET + [NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host, + [NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared, + [NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged, +#endif /* CONFIG_VMNET */ }; @@ -1032,25 +1059,29 @@ static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp) if (is_netdev) { if (netdev->type == NET_CLIENT_DRIVER_NIC || !net_client_init_fun[netdev->type]) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a netdev backend type"); + error_setg(errp, "network backend '%s' is not compiled into this binary", + NetClientDriver_str(netdev->type)); return -1; } } else { if (netdev->type == NET_CLIENT_DRIVER_NONE) { return 0; /* nothing to do */ } - if (netdev->type == NET_CLIENT_DRIVER_HUBPORT || - !net_client_init_fun[netdev->type]) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a net backend type (maybe it is not compiled " - "into this binary)"); + if (netdev->type == NET_CLIENT_DRIVER_HUBPORT) { + error_setg(errp, "network backend '%s' is only supported with -netdev/-nic", + NetClientDriver_str(netdev->type)); + return -1; + } + + if (!net_client_init_fun[netdev->type]) { + error_setg(errp, "network backend '%s' is not compiled into this binary", + NetClientDriver_str(netdev->type)); return -1; } /* Do not add to a hub if it's a nic with a netdev= parameter. */ if (netdev->type != NET_CLIENT_DRIVER_NIC || - !netdev->u.nic.has_netdev) { + !netdev->u.nic.netdev) { peer = net_hub_add_port(0, NULL, NULL); } } @@ -1084,6 +1115,8 @@ void show_netdevs(void) int idx; const char *available_netdevs[] = { "socket", + "stream", + "dgram", "hubport", "tap", #ifdef CONFIG_SLIRP @@ -1106,6 +1139,11 @@ void show_netdevs(void) #endif #ifdef CONFIG_VHOST_VDPA "vhost-vdpa", +#endif +#ifdef CONFIG_VMNET + "vmnet-host", + "vmnet-shared", + "vmnet-bridged", #endif }; @@ -1257,8 +1295,7 @@ void print_net_client(Monitor *mon, NetClientState *nc) } } -RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, - Error **errp) +RxFilterInfoList *qmp_query_rx_filter(const char *name, Error **errp) { NetClientState *nc; RxFilterInfoList *filter_list = NULL, **tail = &filter_list; @@ -1266,13 +1303,13 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, QTAILQ_FOREACH(nc, &net_clients, next) { RxFilterInfo *info; - if (has_name && strcmp(nc->name, name) != 0) { + if (name && strcmp(nc->name, name) != 0) { continue; } /* only query rx-filter information of NIC */ if (nc->info->type != NET_CLIENT_DRIVER_NIC) { - if (has_name) { + if (name) { error_setg(errp, "net client(%s) isn't a NIC", name); assert(!filter_list); return NULL; @@ -1289,19 +1326,19 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, if (nc->info->query_rx_filter) { info = nc->info->query_rx_filter(nc); QAPI_LIST_APPEND(tail, info); - } else if (has_name) { + } else if (name) { error_setg(errp, "net client(%s) doesn't support" " rx-filter querying", name); assert(!filter_list); return NULL; } - if (has_name) { + if (name) { break; } } - if (filter_list == NULL && has_name) { + if (filter_list == NULL && name) { error_setg(errp, "invalid net client name: %s", name); } @@ -1551,36 +1588,97 @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) return ret; } -int net_init_clients(Error **errp) +static void netdev_init_modern(void) +{ + while (!QSIMPLEQ_EMPTY(&nd_queue)) { + NetdevQueueEntry *nd = QSIMPLEQ_FIRST(&nd_queue); + + QSIMPLEQ_REMOVE_HEAD(&nd_queue, entry); + loc_push_restore(&nd->loc); + net_client_init1(nd->nd, true, &error_fatal); + loc_pop(&nd->loc); + qapi_free_Netdev(nd->nd); + g_free(nd); + } +} + +void net_init_clients(void) { net_change_state_entry = qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); QTAILQ_INIT(&net_clients); - if (qemu_opts_foreach(qemu_find_opts("netdev"), - net_init_netdev, NULL, errp)) { - return -1; - } + netdev_init_modern(); - if (qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, errp)) { - return -1; - } + qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, + &error_fatal); - if (qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, errp)) { - return -1; + qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, + &error_fatal); + + qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, + &error_fatal); +} + +/* + * Does this -netdev argument use modern rather than traditional syntax? + * Modern syntax is to be parsed with netdev_parse_modern(). + * Traditional syntax is to be parsed with net_client_parse(). + */ +bool netdev_is_modern(const char *optarg) +{ + QemuOpts *opts; + bool is_modern; + const char *type; + static QemuOptsList dummy_opts = { + .name = "netdev", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head), + .desc = { { } }, + }; + + if (optarg[0] == '{') { + /* This is JSON, which means it's modern syntax */ + return true; } - return 0; + opts = qemu_opts_create(&dummy_opts, NULL, false, &error_abort); + qemu_opts_do_parse(opts, optarg, dummy_opts.implied_opt_name, + &error_abort); + type = qemu_opt_get(opts, "type"); + is_modern = !g_strcmp0(type, "stream") || !g_strcmp0(type, "dgram"); + + qemu_opts_reset(&dummy_opts); + + return is_modern; +} + +/* + * netdev_parse_modern() uses modern, more expressive syntax than + * net_client_parse(), but supports only the -netdev option. + * netdev_parse_modern() appends to @nd_queue, whereas net_client_parse() + * appends to @qemu_netdev_opts. + */ +void netdev_parse_modern(const char *optarg) +{ + Visitor *v; + NetdevQueueEntry *nd; + + v = qobject_input_visitor_new_str(optarg, "type", &error_fatal); + nd = g_new(NetdevQueueEntry, 1); + visit_type_Netdev(v, NULL, &nd->nd, &error_fatal); + visit_free(v); + loc_save(&nd->loc); + + QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry); } -int net_client_parse(QemuOptsList *opts_list, const char *optarg) +void net_client_parse(QemuOptsList *opts_list, const char *optarg) { if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { - return -1; + exit(1); } - - return 0; } /* From FreeBSD */ diff --git a/net/slirp.c b/net/slirp.c index bc5e9e4f77a3..2ee3f1a0d7ca 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -184,23 +184,66 @@ static int64_t net_slirp_clock_get_ns(void *opaque) return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } +typedef struct SlirpTimer SlirpTimer; +struct SlirpTimer { + QEMUTimer timer; +#if SLIRP_CHECK_VERSION(4,7,0) + Slirp *slirp; + SlirpTimerId id; + void *cb_opaque; +#endif +}; + +#if SLIRP_CHECK_VERSION(4,7,0) +static void net_slirp_init_completed(Slirp *slirp, void *opaque) +{ + SlirpState *s = opaque; + s->slirp = slirp; +} + +static void net_slirp_timer_cb(void *opaque) +{ + SlirpTimer *t = opaque; + slirp_handle_timer(t->slirp, t->id, t->cb_opaque); +} + +static void *net_slirp_timer_new_opaque(SlirpTimerId id, + void *cb_opaque, void *opaque) +{ + SlirpState *s = opaque; + SlirpTimer *t = g_new(SlirpTimer, 1); + t->slirp = s->slirp; + t->id = id; + t->cb_opaque = cb_opaque; + timer_init_full(&t->timer, NULL, QEMU_CLOCK_VIRTUAL, + SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, + net_slirp_timer_cb, t); + return t; +} +#else static void *net_slirp_timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque) { - return timer_new_full(NULL, QEMU_CLOCK_VIRTUAL, - SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, - cb, cb_opaque); + SlirpTimer *t = g_new(SlirpTimer, 1); + timer_init_full(&t->timer, NULL, QEMU_CLOCK_VIRTUAL, + SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, + cb, cb_opaque); + return t; } +#endif static void net_slirp_timer_free(void *timer, void *opaque) { - timer_free(timer); + SlirpTimer *t = timer; + timer_del(&t->timer); + g_free(t); } static void net_slirp_timer_mod(void *timer, int64_t expire_timer, void *opaque) { - timer_mod(timer, expire_timer); + SlirpTimer *t = timer; + timer_mod(&t->timer, expire_timer); } static void net_slirp_register_poll_fd(int fd, void *opaque) @@ -222,7 +265,12 @@ static const SlirpCb slirp_cb = { .send_packet = net_slirp_send_packet, .guest_error = net_slirp_guest_error, .clock_get_ns = net_slirp_clock_get_ns, +#if SLIRP_CHECK_VERSION(4,7,0) + .init_completed = net_slirp_init_completed, + .timer_new_opaque = net_slirp_timer_new_opaque, +#else .timer_new = net_slirp_timer_new, +#endif .timer_free = net_slirp_timer_free, .timer_mod = net_slirp_timer_mod, .register_poll_fd = net_slirp_register_poll_fd, @@ -380,6 +428,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, #if defined(CONFIG_SMBD_COMMAND) struct in_addr smbsrv = { .s_addr = 0 }; #endif + SlirpConfig cfg = { 0 }; NetClientState *nc; SlirpState *s; char buf[20]; @@ -562,18 +611,31 @@ static int net_slirp_init(NetClientState *peer, const char *model, nc = qemu_new_net_client(&net_slirp_info, peer, model, name); - snprintf(nc->info_str, sizeof(nc->info_str), - "net=%s,restrict=%s", inet_ntoa(net), - restricted ? "on" : "off"); + qemu_set_info_str(nc, "net=%s,restrict=%s", inet_ntoa(net), + restricted ? "on" : "off"); s = DO_UPCAST(SlirpState, nc, nc); - s->slirp = slirp_init(restricted, ipv4, net, mask, host, - ipv6, ip6_prefix, vprefix6_len, ip6_host, - vhostname, tftp_server_name, - tftp_export, bootfile, dhcp, - dns, ip6_dns, dnssearch, vdomainname, - &slirp_cb, s); + cfg.version = SLIRP_CHECK_VERSION(4,7,0) ? 4 : 1; + cfg.restricted = restricted; + cfg.in_enabled = ipv4; + cfg.vnetwork = net; + cfg.vnetmask = mask; + cfg.vhost = host; + cfg.in6_enabled = ipv6; + cfg.vprefix_addr6 = ip6_prefix; + cfg.vprefix_len = vprefix6_len; + cfg.vhost6 = ip6_host; + cfg.vhostname = vhostname; + cfg.tftp_server_name = tftp_server_name; + cfg.tftp_path = tftp_export; + cfg.bootfile = bootfile; + cfg.vdhcp_start = dhcp; + cfg.vnameserver = dns; + cfg.vnameserver6 = ip6_dns; + cfg.vdnssearch = dnssearch; + cfg.vdomainname = vdomainname; + s->slirp = slirp_new(&cfg, &slirp_cb, s); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); /* @@ -1091,8 +1153,8 @@ int net_init_slirp(const Netdev *netdev, const char *name, ipv6 = 0; } - vnet = user->has_net ? g_strdup(user->net) : - user->has_ip ? g_strdup_printf("%s/24", user->ip) : + vnet = user->net ? g_strdup(user->net) : + user->ip ? g_strdup_printf("%s/24", user->ip) : NULL; dnssearch = slirp_dnssearch(user->dnssearch); diff --git a/net/socket.c b/net/socket.c index c4b80e9228d7..2fc5696755e0 100644 --- a/net/socket.c +++ b/net/socket.c @@ -27,7 +27,6 @@ #include "clients.h" #include "monitor/monitor.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/sockets.h" @@ -118,15 +117,13 @@ static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); ssize_t ret; - do { - if (s->dgram_dst.sin_family != AF_UNIX) { - ret = sendto(s->fd, buf, size, 0, - (struct sockaddr *)&s->dgram_dst, - sizeof(s->dgram_dst)); - } else { - ret = send(s->fd, buf, size, 0); - } - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR( + s->dgram_dst.sin_family != AF_UNIX ? + sendto(s->fd, buf, size, 0, + (struct sockaddr *)&s->dgram_dst, + sizeof(s->dgram_dst)) : + send(s->fd, buf, size, 0) + ); if (ret == -1 && errno == EAGAIN) { net_socket_write_poll(s, true); @@ -180,7 +177,7 @@ static void net_socket_send(void *opaque) s->fd = -1; net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); s->nc.link_down = true; - memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); + qemu_set_info_str(&s->nc, "%s", ""); return; } @@ -298,7 +295,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, } } - qemu_set_nonblock(fd); + qemu_socket_set_nonblock(fd); return fd; fail: if (fd >= 0) @@ -388,16 +385,15 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, /* mcast: save bound address as dst */ if (is_connected && mcast != NULL) { s->dgram_dst = saddr; - snprintf(nc->info_str, sizeof(nc->info_str), - "socket: fd=%d (cloned mcast=%s:%d)", - fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(nc, "socket: fd=%d (cloned mcast=%s:%d)", fd, + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } else { if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { s->dgram_dst.sin_family = AF_UNIX; } - snprintf(nc->info_str, sizeof(nc->info_str), - "socket: fd=%d %s", fd, SocketAddressType_str(sa_type)); + qemu_set_info_str(nc, "socket: fd=%d %s", fd, + SocketAddressType_str(sa_type)); } return s; @@ -431,7 +427,7 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, nc = qemu_new_net_client(&net_socket_info, peer, model, name); - snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); + qemu_set_info_str(nc, "socket: fd=%d", fd); s = DO_UPCAST(NetSocketState, nc, nc); @@ -498,9 +494,8 @@ static void net_socket_accept(void *opaque) s->fd = fd; s->nc.link_down = false; net_socket_connect(s); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connection from %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: connection from %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } static int net_socket_listen_init(NetClientState *peer, @@ -523,7 +518,7 @@ static int net_socket_listen_init(NetClientState *peer, error_setg_errno(errp, errno, "can't create stream socket"); return -1; } - qemu_set_nonblock(fd); + qemu_socket_set_nonblock(fd); socket_set_fast_reuse(fd); @@ -571,7 +566,7 @@ static int net_socket_connect_init(NetClientState *peer, error_setg_errno(errp, errno, "can't create stream socket"); return -1; } - qemu_set_nonblock(fd); + qemu_socket_set_nonblock(fd); connected = 0; for(;;) { @@ -580,8 +575,7 @@ static int net_socket_connect_init(NetClientState *peer, if (errno == EINTR || errno == EWOULDBLOCK) { /* continue */ } else if (errno == EINPROGRESS || - errno == EALREADY || - errno == EINVAL) { + errno == EALREADY) { break; } else { error_setg_errno(errp, errno, "can't connect socket"); @@ -598,9 +592,8 @@ static int net_socket_connect_init(NetClientState *peer, return -1; } - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: connect to %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } @@ -643,9 +636,8 @@ static int net_socket_mcast_init(NetClientState *peer, s->dgram_dst = saddr; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: mcast=%s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: mcast=%s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } @@ -689,7 +681,7 @@ static int net_socket_udp_init(NetClientState *peer, closesocket(fd); return -1; } - qemu_set_nonblock(fd); + qemu_socket_set_nonblock(fd); s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp); if (!s) { @@ -698,9 +690,8 @@ static int net_socket_udp_init(NetClientState *peer, s->dgram_dst = raddr; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: udp=%s:%d", - inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: udp=%s:%d", inet_ntoa(raddr.sin_addr), + ntohs(raddr.sin_port)); return 0; } @@ -712,26 +703,26 @@ int net_init_socket(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_SOCKET); sock = &netdev->u.socket; - if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + - sock->has_udp != 1) { + if (!!sock->fd + !!sock->listen + !!sock->connect + !!sock->mcast + + !!sock->udp != 1) { error_setg(errp, "exactly one of listen=, connect=, mcast= or udp=" " is required"); return -1; } - if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) { + if (sock->localaddr && !sock->mcast && !sock->udp) { error_setg(errp, "localaddr= is only valid with mcast= or udp="); return -1; } - if (sock->has_fd) { + if (sock->fd) { int fd, ret; fd = monitor_fd_param(monitor_cur(), sock->fd, errp); if (fd == -1) { return -1; } - ret = qemu_try_set_nonblock(fd); + ret = qemu_socket_try_set_nonblock(fd); if (ret < 0) { error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", name, fd); @@ -744,7 +735,7 @@ int net_init_socket(const Netdev *netdev, const char *name, return 0; } - if (sock->has_listen) { + if (sock->listen) { if (net_socket_listen_init(peer, "socket", name, sock->listen, errp) < 0) { return -1; @@ -752,7 +743,7 @@ int net_init_socket(const Netdev *netdev, const char *name, return 0; } - if (sock->has_connect) { + if (sock->connect) { if (net_socket_connect_init(peer, "socket", name, sock->connect, errp) < 0) { return -1; @@ -760,7 +751,7 @@ int net_init_socket(const Netdev *netdev, const char *name, return 0; } - if (sock->has_mcast) { + if (sock->mcast) { /* if sock->localaddr is missing, it has been initialized to "all bits * zero" */ if (net_socket_mcast_init(peer, "socket", name, sock->mcast, @@ -770,8 +761,8 @@ int net_init_socket(const Netdev *netdev, const char *name, return 0; } - assert(sock->has_udp); - if (!sock->has_localaddr) { + assert(sock->udp); + if (!sock->localaddr) { error_setg(errp, "localaddr= is mandatory with udp="); return -1; } diff --git a/net/stream.c b/net/stream.c new file mode 100644 index 000000000000..37ff727e0c42 --- /dev/null +++ b/net/stream.c @@ -0,0 +1,386 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2022 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#include "net/net.h" +#include "clients.h" +#include "monitor/monitor.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "qemu/sockets.h" +#include "qemu/iov.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include "io/channel.h" +#include "io/channel-socket.h" +#include "io/net-listener.h" +#include "qapi/qapi-events-net.h" + +typedef struct NetStreamState { + NetClientState nc; + QIOChannel *listen_ioc; + QIONetListener *listener; + QIOChannel *ioc; + guint ioc_read_tag; + guint ioc_write_tag; + SocketReadState rs; + unsigned int send_index; /* number of bytes sent*/ +} NetStreamState; + +static void net_stream_listen(QIONetListener *listener, + QIOChannelSocket *cioc, + void *opaque); + +static gboolean net_stream_writable(QIOChannel *ioc, + GIOCondition condition, + gpointer data) +{ + NetStreamState *s = data; + + s->ioc_write_tag = 0; + + qemu_flush_queued_packets(&s->nc); + + return G_SOURCE_REMOVE; +} + +static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + uint32_t len = htonl(size); + struct iovec iov[] = { + { + .iov_base = &len, + .iov_len = sizeof(len), + }, { + .iov_base = (void *)buf, + .iov_len = size, + }, + }; + struct iovec local_iov[2]; + unsigned int nlocal_iov; + size_t remaining; + ssize_t ret; + + remaining = iov_size(iov, 2) - s->send_index; + nlocal_iov = iov_copy(local_iov, 2, iov, 2, s->send_index, remaining); + ret = qio_channel_writev(s->ioc, local_iov, nlocal_iov, NULL); + if (ret == QIO_CHANNEL_ERR_BLOCK) { + ret = 0; /* handled further down */ + } + if (ret == -1) { + s->send_index = 0; + return -errno; + } + if (ret < (ssize_t)remaining) { + s->send_index += ret; + s->ioc_write_tag = qio_channel_add_watch(s->ioc, G_IO_OUT, + net_stream_writable, s, NULL); + return 0; + } + s->send_index = 0; + return size; +} + +static gboolean net_stream_send(QIOChannel *ioc, + GIOCondition condition, + gpointer data); + +static void net_stream_send_completed(NetClientState *nc, ssize_t len) +{ + NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + + if (!s->ioc_read_tag) { + s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, + net_stream_send, s, NULL); + } +} + +static void net_stream_rs_finalize(SocketReadState *rs) +{ + NetStreamState *s = container_of(rs, NetStreamState, rs); + + if (qemu_send_packet_async(&s->nc, rs->buf, + rs->packet_len, + net_stream_send_completed) == 0) { + if (s->ioc_read_tag) { + g_source_remove(s->ioc_read_tag); + s->ioc_read_tag = 0; + } + } +} + +static gboolean net_stream_send(QIOChannel *ioc, + GIOCondition condition, + gpointer data) +{ + NetStreamState *s = data; + int size; + int ret; + char buf1[NET_BUFSIZE]; + const char *buf; + + size = qio_channel_read(s->ioc, buf1, sizeof(buf1), NULL); + if (size < 0) { + if (errno != EWOULDBLOCK) { + goto eoc; + } + } else if (size == 0) { + /* end of connection */ + eoc: + s->ioc_read_tag = 0; + if (s->ioc_write_tag) { + g_source_remove(s->ioc_write_tag); + s->ioc_write_tag = 0; + } + if (s->listener) { + qio_net_listener_set_client_func(s->listener, net_stream_listen, + s, NULL); + } + object_unref(OBJECT(s->ioc)); + s->ioc = NULL; + + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + s->nc.link_down = true; + qemu_set_info_str(&s->nc, "%s", ""); + + qapi_event_send_netdev_stream_disconnected(s->nc.name); + + return G_SOURCE_REMOVE; + } + buf = buf1; + + ret = net_fill_rstate(&s->rs, (const uint8_t *)buf, size); + + if (ret == -1) { + goto eoc; + } + + return G_SOURCE_CONTINUE; +} + +static void net_stream_cleanup(NetClientState *nc) +{ + NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + if (s->ioc) { + if (QIO_CHANNEL_SOCKET(s->ioc)->fd != -1) { + if (s->ioc_read_tag) { + g_source_remove(s->ioc_read_tag); + s->ioc_read_tag = 0; + } + if (s->ioc_write_tag) { + g_source_remove(s->ioc_write_tag); + s->ioc_write_tag = 0; + } + } + object_unref(OBJECT(s->ioc)); + s->ioc = NULL; + } + if (s->listen_ioc) { + if (s->listener) { + qio_net_listener_disconnect(s->listener); + object_unref(OBJECT(s->listener)); + s->listener = NULL; + } + object_unref(OBJECT(s->listen_ioc)); + s->listen_ioc = NULL; + } +} + +static NetClientInfo net_stream_info = { + .type = NET_CLIENT_DRIVER_STREAM, + .size = sizeof(NetStreamState), + .receive = net_stream_receive, + .cleanup = net_stream_cleanup, +}; + +static void net_stream_listen(QIONetListener *listener, + QIOChannelSocket *cioc, + void *opaque) +{ + NetStreamState *s = opaque; + SocketAddress *addr; + char *uri; + + object_ref(OBJECT(cioc)); + + qio_net_listener_set_client_func(s->listener, NULL, s, NULL); + + s->ioc = QIO_CHANNEL(cioc); + qio_channel_set_name(s->ioc, "stream-server"); + s->nc.link_down = false; + + s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send, + s, NULL); + + if (cioc->localAddr.ss_family == AF_UNIX) { + addr = qio_channel_socket_get_local_address(cioc, NULL); + } else { + addr = qio_channel_socket_get_remote_address(cioc, NULL); + } + g_assert(addr != NULL); + uri = socket_uri(addr); + qemu_set_info_str(&s->nc, "%s", uri); + g_free(uri); + qapi_event_send_netdev_stream_connected(s->nc.name, addr); + qapi_free_SocketAddress(addr); +} + +static void net_stream_server_listening(QIOTask *task, gpointer opaque) +{ + NetStreamState *s = opaque; + QIOChannelSocket *listen_sioc = QIO_CHANNEL_SOCKET(s->listen_ioc); + SocketAddress *addr; + int ret; + + if (listen_sioc->fd < 0) { + qemu_set_info_str(&s->nc, "connection error"); + return; + } + + addr = qio_channel_socket_get_local_address(listen_sioc, NULL); + g_assert(addr != NULL); + ret = qemu_socket_try_set_nonblock(listen_sioc->fd); + if (addr->type == SOCKET_ADDRESS_TYPE_FD && ret < 0) { + qemu_set_info_str(&s->nc, "can't use file descriptor %s (errno %d)", + addr->u.fd.str, -ret); + return; + } + g_assert(ret == 0); + qapi_free_SocketAddress(addr); + + s->nc.link_down = true; + s->listener = qio_net_listener_new(); + + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + qio_net_listener_set_client_func(s->listener, net_stream_listen, s, NULL); + qio_net_listener_add(s->listener, listen_sioc); +} + +static int net_stream_server_init(NetClientState *peer, + const char *model, + const char *name, + SocketAddress *addr, + Error **errp) +{ + NetClientState *nc; + NetStreamState *s; + QIOChannelSocket *listen_sioc = qio_channel_socket_new(); + + nc = qemu_new_net_client(&net_stream_info, peer, model, name); + s = DO_UPCAST(NetStreamState, nc, nc); + + s->listen_ioc = QIO_CHANNEL(listen_sioc); + qio_channel_socket_listen_async(listen_sioc, addr, 0, + net_stream_server_listening, s, + NULL, NULL); + + return 0; +} + +static void net_stream_client_connected(QIOTask *task, gpointer opaque) +{ + NetStreamState *s = opaque; + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(s->ioc); + SocketAddress *addr; + gchar *uri; + int ret; + + if (sioc->fd < 0) { + qemu_set_info_str(&s->nc, "connection error"); + goto error; + } + + addr = qio_channel_socket_get_remote_address(sioc, NULL); + g_assert(addr != NULL); + uri = socket_uri(addr); + qemu_set_info_str(&s->nc, "%s", uri); + g_free(uri); + + ret = qemu_socket_try_set_nonblock(sioc->fd); + if (addr->type == SOCKET_ADDRESS_TYPE_FD && ret < 0) { + qemu_set_info_str(&s->nc, "can't use file descriptor %s (errno %d)", + addr->u.fd.str, -ret); + qapi_free_SocketAddress(addr); + goto error; + } + g_assert(ret == 0); + + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + + /* Disable Nagle algorithm on TCP sockets to reduce latency */ + qio_channel_set_delay(s->ioc, false); + + s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send, + s, NULL); + s->nc.link_down = false; + qapi_event_send_netdev_stream_connected(s->nc.name, addr); + qapi_free_SocketAddress(addr); + + return; +error: + object_unref(OBJECT(s->ioc)); + s->ioc = NULL; +} + +static int net_stream_client_init(NetClientState *peer, + const char *model, + const char *name, + SocketAddress *addr, + Error **errp) +{ + NetStreamState *s; + NetClientState *nc; + QIOChannelSocket *sioc = qio_channel_socket_new(); + + nc = qemu_new_net_client(&net_stream_info, peer, model, name); + s = DO_UPCAST(NetStreamState, nc, nc); + + s->ioc = QIO_CHANNEL(sioc); + s->nc.link_down = true; + + qio_channel_socket_connect_async(sioc, addr, + net_stream_client_connected, s, + NULL, NULL); + + return 0; +} + +int net_init_stream(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + const NetdevStreamOptions *sock; + + assert(netdev->type == NET_CLIENT_DRIVER_STREAM); + sock = &netdev->u.stream; + + if (!sock->has_server || !sock->server) { + return net_stream_client_init(peer, "stream", name, sock->addr, errp); + } + return net_stream_server_init(peer, "stream", name, sock->addr, errp); +} diff --git a/net/tap-bsd.c b/net/tap-bsd.c index e45a6d124eb6..4c98fdd337e5 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "tap_int.h" #include "qemu/cutils.h" @@ -57,7 +56,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, } else { snprintf(dname, sizeof dname, "/dev/tap%d", i); } - TFR(fd = open(dname, O_RDWR)); + fd = RETRY_ON_EINTR(open(dname, O_RDWR)); if (fd >= 0) { break; } @@ -99,7 +98,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, return -1; } } - fcntl(fd, F_SETFL, O_NONBLOCK); + g_unix_set_fd_nonblocking(fd, true, NULL); return fd; } @@ -112,7 +111,7 @@ static int tap_open_clone(char *ifname, int ifname_size, Error **errp) int fd, s, ret; struct ifreq ifr; - TFR(fd = open(PATH_NET_TAP, O_RDWR)); + fd = RETRY_ON_EINTR(open(PATH_NET_TAP, O_RDWR)); if (fd < 0) { error_setg_errno(errp, errno, "could not open %s", PATH_NET_TAP); return -1; @@ -160,7 +159,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, if (ifname[0] != '\0') { char dname[100]; snprintf(dname, sizeof dname, "/dev/%s", ifname); - TFR(fd = open(dname, O_RDWR)); + fd = RETRY_ON_EINTR(open(dname, O_RDWR)); if (fd < 0 && errno != ENOENT) { error_setg_errno(errp, errno, "could not open %s", dname); return -1; @@ -190,7 +189,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, goto error; } - fcntl(fd, F_SETFL, O_NONBLOCK); + g_unix_set_fd_nonblocking(fd, true, NULL); return fd; error: diff --git a/net/tap-linux.c b/net/tap-linux.c index 5e70b9303710..f54f308d359c 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "tap_int.h" #include "tap-linux.h" #include "net/tap.h" @@ -46,7 +45,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int len = sizeof(struct virtio_net_hdr); unsigned int features; - TFR(fd = open(PATH_NET_TUN, O_RDWR)); + fd = RETRY_ON_EINTR(open(PATH_NET_TUN, O_RDWR)); if (fd < 0) { error_setg_errno(errp, errno, "could not open %s", PATH_NET_TUN); return -1; @@ -114,7 +113,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, return -1; } pstrcpy(ifname, ifname_size, ifr.ifr_name); - fcntl(fd, F_SETFL, O_NONBLOCK); + g_unix_set_fd_nonblocking(fd, true, NULL); return fd; } diff --git a/net/tap-linux.h b/net/tap-linux.h index 1d06fe0de63b..bbbb62c2a75c 100644 --- a/net/tap-linux.h +++ b/net/tap-linux.h @@ -45,10 +45,10 @@ #define IFF_DETACH_QUEUE 0x0400 /* Features for GSO (TUNSETOFFLOAD). */ -#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ -#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ -#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ -#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ -#define TUN_F_UFO 0x10 /* I can handle UFO packets */ +#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ +#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ +#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ +#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ +#define TUN_F_UFO 0x10 /* I can handle UFO packets */ #endif /* QEMU_TAP_LINUX_H */ diff --git a/net/tap-solaris.c b/net/tap-solaris.c index d85224242b30..38e15028bf3d 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -27,7 +27,6 @@ #include "tap_int.h" #include "qemu/ctype.h" #include "qemu/cutils.h" -#include "qemu-common.h" #include #include @@ -85,13 +84,13 @@ static int tap_alloc(char *dev, size_t dev_size, Error **errp) if( ip_fd ) close(ip_fd); - TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); + ip_fd = RETRY_ON_EINTR(open("/dev/udp", O_RDWR, 0)); if (ip_fd < 0) { error_setg(errp, "Can't open /dev/ip (actually /dev/udp)"); return -1; } - TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); + tap_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0)); if (tap_fd < 0) { error_setg(errp, "Can't open /dev/tap"); return -1; @@ -105,7 +104,7 @@ static int tap_alloc(char *dev, size_t dev_size, Error **errp) if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) error_report("Can't assign new interface"); - TFR(if_fd = open("/dev/tap", O_RDWR, 0)); + if_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0)); if (if_fd < 0) { error_setg(errp, "Can't open /dev/tap (2)"); return -1; @@ -138,7 +137,7 @@ static int tap_alloc(char *dev, size_t dev_size, Error **errp) if (ioctl (ip_fd, I_PUSH, "arp") < 0) error_report("Can't push ARP module (3)"); /* Open arp_fd */ - TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); + arp_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0)); if (arp_fd < 0) error_report("Can't open %s", "/dev/tap"); @@ -199,7 +198,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, return -1; } } - fcntl(fd, F_SETFL, O_NONBLOCK); + g_unix_set_fd_nonblocking(fd, true, NULL); return fd; } diff --git a/net/tap-win32.c b/net/tap-win32.c index 6096972f5d47..f327d62ab07a 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -29,7 +29,6 @@ #include "qemu/osdep.h" #include "tap_int.h" -#include "qemu-common.h" #include "clients.h" /* net_init_tap */ #include "net/eth.h" #include "net/net.h" @@ -790,8 +789,7 @@ static int tap_win32_init(NetClientState *peer, const char *model, s = DO_UPCAST(TAPState, nc, nc); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "tap: ifname=%s", ifname); + qemu_set_info_str(&s->nc, "tap: ifname=%s", ifname); s->handle = handle; @@ -809,7 +807,7 @@ int net_init_tap(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_TAP); tap = &netdev->u.tap; - if (!tap->has_ifname) { + if (!tap->ifname) { error_report("tap: no interface name"); return -1; } diff --git a/net/tap.c b/net/tap.c index c5cbeaa7a2be..7d7bc1dc5f70 100644 --- a/net/tap.c +++ b/net/tap.c @@ -38,7 +38,6 @@ #include "monitor/monitor.h" #include "sysemu/sysemu.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" @@ -103,9 +102,7 @@ static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt { ssize_t len; - do { - len = writev(s->fd, iov, iovcnt); - } while (len == -1 && errno == EINTR); + len = RETRY_ON_EINTR(writev(s->fd, iov, iovcnt)); if (len == -1 && errno == EAGAIN) { tap_write_poll(s, true); @@ -578,9 +575,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge, close(sv[1]); - do { - fd = recv_fd(sv[0]); - } while (fd == -1 && errno == EINTR); + fd = RETRY_ON_EINTR(recv_fd(sv[0])); saved_errno = errno; close(sv[0]); @@ -612,15 +607,18 @@ int net_init_bridge(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE); bridge = &netdev->u.bridge; - helper = bridge->has_helper ? bridge->helper : NULL; - br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE; + helper = bridge->helper; + br = bridge->br ?: DEFAULT_BRIDGE_INTERFACE; fd = net_bridge_run_helper(helper, br, errp); if (fd == -1) { return -1; } - qemu_set_nonblock(fd); + if (!g_unix_set_fd_nonblocking(fd, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return -1; + } vnet_hdr = tap_probe_vnet_hdr(fd, errp); if (vnet_hdr < 0) { close(fd); @@ -628,8 +626,7 @@ int net_init_bridge(const Netdev *netdev, const char *name, } s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, - br); + qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br); return 0; } @@ -649,7 +646,7 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, vnet_hdr_required = 0; } - TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required, + fd = RETRY_ON_EINTR(tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required, mq_required, errp)); if (fd < 0) { return -1; @@ -684,18 +681,16 @@ 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) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); - } else if (tap->has_helper) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", - tap->helper); + if (tap->fd || tap->fds) { + qemu_set_info_str(&s->nc, "fd=%d", fd); + } else if (tap->helper) { + qemu_set_info_str(&s->nc, "helper=%s", tap->helper); } else { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "ifname=%s,script=%s,downscript=%s", ifname, script, - downscript); + qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname, + script, downscript); if (strcmp(downscript, "no") != 0) { snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); @@ -717,8 +712,6 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } if (vhostfdname) { - int ret; - vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, &err); if (vhostfd == -1) { if (tap->has_vhostforce && tap->vhostforce) { @@ -726,13 +719,12 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } else { warn_report_err(err); } - return; + goto failed; } - ret = qemu_try_set_nonblock(vhostfd); - if (ret < 0) { - error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + 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); @@ -744,9 +736,12 @@ 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"); + goto failed; } - qemu_set_nonblock(vhostfd); } options.opaque = (void *)(uintptr_t)vhostfd; options.nvqs = 2; @@ -758,11 +753,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) @@ -807,21 +808,21 @@ int net_init_tap(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_TAP); tap = &netdev->u.tap; queues = tap->has_queues ? tap->queues : 1; - vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; - script = tap->has_script ? tap->script : NULL; - downscript = tap->has_downscript ? tap->downscript : NULL; + vhostfdname = tap->vhostfd; + script = tap->script; + downscript = tap->downscript; /* QEMU hubs do not support multiqueue tap, in this case peer is set. * For -netdev, peer is always NULL. */ - if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) { + if (peer && (tap->has_queues || tap->fds || tap->vhostfds)) { error_setg(errp, "Multiqueue tap cannot be used with hubs"); return -1; } - if (tap->has_fd) { - if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_helper || tap->has_queues || - tap->has_fds || tap->has_vhostfds) { + if (tap->fd) { + if (tap->ifname || tap->script || tap->downscript || + tap->has_vnet_hdr || tap->helper || tap->has_queues || + tap->fds || tap->vhostfds) { error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, " "helper=, queues=, fds=, and vhostfds= " "are invalid with fd="); @@ -833,9 +834,8 @@ int net_init_tap(const Netdev *netdev, const char *name, return -1; } - ret = qemu_try_set_nonblock(fd); - if (ret < 0) { - error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + if (!g_unix_set_fd_nonblocking(fd, true, NULL)) { + error_setg_errno(errp, errno, "%s: Can't use file descriptor %d", name, fd); close(fd); return -1; @@ -855,14 +855,14 @@ int net_init_tap(const Netdev *netdev, const char *name, close(fd); return -1; } - } else if (tap->has_fds) { + } else if (tap->fds) { char **fds; char **vhost_fds; int nfds = 0, nvhosts = 0; - if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_helper || tap->has_queues || - tap->has_vhostfd) { + if (tap->ifname || tap->script || tap->downscript || + tap->has_vnet_hdr || tap->helper || tap->has_queues || + tap->vhostfd) { error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, " "helper=, queues=, and vhostfd= " "are invalid with fds="); @@ -873,7 +873,7 @@ int net_init_tap(const Netdev *netdev, const char *name, vhost_fds = g_new0(char *, MAX_TAP_QUEUES); nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES); - if (tap->has_vhostfds) { + if (tap->vhostfds) { nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES); if (nfds != nvhosts) { error_setg(errp, "The number of fds passed does not match " @@ -890,9 +890,9 @@ int net_init_tap(const Netdev *netdev, const char *name, goto free_fail; } - ret = qemu_try_set_nonblock(fd); - if (ret < 0) { - error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + ret = g_unix_set_fd_nonblocking(fd, true, NULL); + if (!ret) { + error_setg_errno(errp, errno, "%s: Can't use file descriptor %d", name, fd); goto free_fail; } @@ -912,7 +912,7 @@ int net_init_tap(const Netdev *netdev, const char *name, net_init_tap_one(tap, peer, "tap", name, ifname, script, downscript, - tap->has_vhostfds ? vhost_fds[i] : NULL, + tap->vhostfds ? vhost_fds[i] : NULL, vnet_hdr, fd, &err); if (err) { error_propagate(errp, err); @@ -931,23 +931,25 @@ int net_init_tap(const Netdev *netdev, const char *name, g_free(fds); g_free(vhost_fds); return ret; - } else if (tap->has_helper) { - if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) { + } else if (tap->helper) { + if (tap->ifname || tap->script || tap->downscript || + tap->has_vnet_hdr || tap->has_queues || tap->vhostfds) { error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, " "queues=, and vhostfds= are invalid with helper="); return -1; } fd = net_bridge_run_helper(tap->helper, - tap->has_br ? - tap->br : DEFAULT_BRIDGE_INTERFACE, + tap->br ?: DEFAULT_BRIDGE_INTERFACE, errp); if (fd == -1) { return -1; } - qemu_set_nonblock(fd); + if (!g_unix_set_fd_nonblocking(fd, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return -1; + } vnet_hdr = tap_probe_vnet_hdr(fd, errp); if (vnet_hdr < 0) { close(fd); @@ -965,7 +967,7 @@ int net_init_tap(const Netdev *netdev, const char *name, } else { g_autofree char *default_script = NULL; g_autofree char *default_downscript = NULL; - if (tap->has_vhostfds) { + if (tap->vhostfds) { error_setg(errp, "vhostfds= is invalid if fds= wasn't specified"); return -1; } @@ -978,7 +980,7 @@ int net_init_tap(const Netdev *netdev, const char *name, get_relocated_path(DEFAULT_NETWORK_DOWN_SCRIPT); } - if (tap->has_ifname) { + if (tap->ifname) { pstrcpy(ifname, sizeof ifname, tap->ifname); } else { ifname[0] = '\0'; @@ -991,7 +993,7 @@ int net_init_tap(const Netdev *netdev, const char *name, return -1; } - if (queues > 1 && i == 0 && !tap->has_ifname) { + if (queues > 1 && i == 0 && !tap->ifname) { if (tap_fd_get_ifname(fd, ifname)) { error_setg(errp, "Fail to get ifname"); close(fd); diff --git a/net/trace-events b/net/trace-events index d7a17256cca6..823a071bdce8 100644 --- a/net/trace-events +++ b/net/trace-events @@ -9,6 +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, 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/util.h b/net/util.h index 358185fd5034..288312979f09 100644 --- a/net/util.h +++ b/net/util.h @@ -30,7 +30,7 @@ * Structure of an internet header, naked of options. */ struct ip { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint8_t ip_v:4, /* version */ ip_hl:4; /* header length */ #else diff --git a/net/vde.c b/net/vde.c index 99189cccb694..c0a08662cc30 100644 --- a/net/vde.c +++ b/net/vde.c @@ -27,7 +27,6 @@ #include "net/net.h" #include "clients.h" -#include "qemu-common.h" #include "qemu/option.h" #include "qemu/main-loop.h" #include "qapi/error.h" @@ -99,8 +98,7 @@ static int net_vde_init(NetClientState *peer, const char *model, nc = qemu_new_net_client(&net_vde_info, peer, model, name); - snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d", - sock, vde_datafd(vde)); + qemu_set_info_str(nc, "sock=%s,fd=%d", sock, vde_datafd(vde)); s = DO_UPCAST(VDEState, nc, nc); diff --git a/net/vhost-user.c b/net/vhost-user.c index b1a0247b5981..5993e4afcaac 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -45,10 +45,23 @@ uint64_t vhost_user_get_acked_features(NetClientState *nc) return s->acked_features; } -static void vhost_user_stop(int queues, NetClientState *ncs[]) +void vhost_user_save_acked_features(NetClientState *nc) { NetVhostUserState *s; + + s = DO_UPCAST(NetVhostUserState, nc, nc); + if (s->vhost_net) { + uint64_t features = vhost_net_get_acked_features(s->vhost_net); + if (features) { + s->acked_features = features; + } + } +} + +static void vhost_user_stop(int queues, NetClientState *ncs[]) +{ int i; + NetVhostUserState *s; for (i = 0; i < queues; i++) { assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); @@ -56,11 +69,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); if (s->vhost_net) { - /* save acked features */ - uint64_t features = vhost_net_get_acked_features(s->vhost_net); - if (features) { - s->acked_features = features; - } + vhost_user_save_acked_features(ncs[i]); vhost_net_cleanup(s->vhost_net); } } @@ -251,11 +260,7 @@ static void chr_closed_bh(void *opaque) s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); for (i = queues -1; i >= 0; i--) { - s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); - - if (s->vhost_net) { - s->acked_features = vhost_net_get_acked_features(s->vhost_net); - } + vhost_user_save_acked_features(ncs[i]); } qmp_set_link(name, false, &err); @@ -341,8 +346,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, user = g_new0(struct VhostUserState, 1); for (i = 0; i < queues; i++) { nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); - snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", - i, chr->label); + qemu_set_info_str(nc, "vhost-user%d to %s", i, chr->label); nc->queue_index = i; if (!nc0) { nc0 = nc; diff --git a/net/vhost-vdpa-stub.c b/net/vhost-vdpa-stub.c new file mode 100644 index 000000000000..1732ed2443fa --- /dev/null +++ b/net/vhost-vdpa-stub.c @@ -0,0 +1,21 @@ +/* + * vhost-vdpa-stub.c + * + * 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 "clients.h" +#include "net/vhost-vdpa.h" +#include "qapi/error.h" + +int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*"); + return -1; +} diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 1e9fe47c033d..1a13a34d35c0 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -11,11 +11,14 @@ #include "qemu/osdep.h" #include "clients.h" +#include "hw/virtio/virtio-net.h" #include "net/vhost_net.h" #include "net/vhost-vdpa.h" #include "hw/virtio/vhost-vdpa.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/memalign.h" #include "qemu/option.h" #include "qapi/error.h" #include @@ -30,6 +33,13 @@ typedef struct VhostVDPAState { NetClientState nc; struct vhost_vdpa vhost_vdpa; VHostNetState *vhost_net; + + /* Control commands shadow buffers */ + void *cvq_cmd_out_buffer; + virtio_net_ctrl_ack *status; + + /* The device always have SVQ enabled */ + bool always_svq; bool started; } VhostVDPAState; @@ -55,20 +65,44 @@ const int vdpa_feature_bits[] = { VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_RX_EXTRA, VIRTIO_NET_F_CTRL_VLAN, - VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_CTRL_MAC_ADDR, VIRTIO_NET_F_RSS, VIRTIO_NET_F_MQ, VIRTIO_NET_F_CTRL_VQ, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_RING_PACKED, + VIRTIO_F_RING_RESET, VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, - VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_STATUS, VHOST_INVALID_FEATURE_BIT }; +/** Supported device specific feature bits with SVQ */ +static const uint64_t vdpa_svq_device_features = + BIT_ULL(VIRTIO_NET_F_CSUM) | + BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | + BIT_ULL(VIRTIO_NET_F_MTU) | + BIT_ULL(VIRTIO_NET_F_MAC) | + BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | + BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) | + BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | + BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | + BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | + BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | + BIT_ULL(VIRTIO_NET_F_HOST_ECN) | + BIT_ULL(VIRTIO_NET_F_HOST_UFO) | + 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) | + BIT_ULL(VIRTIO_NET_F_STANDBY); + +#define VHOST_VDPA_NET_CVQ_ASID 1 + VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); @@ -76,6 +110,23 @@ VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) return s->vhost_net; } +static bool vhost_vdpa_net_valid_svq_features(uint64_t features, Error **errp) +{ + uint64_t invalid_dev_features = + features & ~vdpa_svq_device_features & + /* Transport are all accepted at this point */ + ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, + VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); + + if (invalid_dev_features) { + error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, + invalid_dev_features); + return false; + } + + return vhost_svq_valid_features(features, errp); +} + static int vhost_vdpa_net_check_device_id(struct vhost_net *net) { uint32_t device_id; @@ -127,7 +178,13 @@ static int vhost_vdpa_add(NetClientState *ncs, void *be, static void vhost_vdpa_cleanup(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + struct vhost_dev *dev = &s->vhost_net->dev; + qemu_vfree(s->cvq_cmd_out_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); + } if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); g_free(s->vhost_net); @@ -174,7 +231,7 @@ static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc, static ssize_t vhost_vdpa_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - return 0; + return size; } static NetClientInfo net_vhost_vdpa_info = { @@ -187,13 +244,431 @@ static NetClientInfo net_vhost_vdpa_info = { .check_peer_type = vhost_vdpa_check_peer_type, }; +static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) +{ + struct vhost_vring_state state = { + .index = vq_index, + }; + int r = ioctl(device_fd, VHOST_VDPA_GET_VRING_GROUP, &state); + + if (unlikely(r < 0)) { + error_report("Cannot get VQ %u group: %s", vq_index, + g_strerror(errno)); + return r; + } + + return state.num; +} + +static int vhost_vdpa_set_address_space_id(struct vhost_vdpa *v, + unsigned vq_group, + unsigned asid_num) +{ + struct vhost_vring_state asid = { + .index = vq_group, + .num = asid_num, + }; + int r; + + r = ioctl(v->device_fd, VHOST_VDPA_SET_GROUP_ASID, &asid); + if (unlikely(r < 0)) { + error_report("Can't set vq group %u asid %u, errno=%d (%s)", + asid.index, asid.num, errno, g_strerror(errno)); + } + return r; +} + +static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) +{ + VhostIOVATree *tree = v->iova_tree; + DMAMap needle = { + /* + * No need to specify size or to look for more translations since + * this contiguous chunk was allocated by us. + */ + .translated_addr = (hwaddr)(uintptr_t)addr, + }; + const DMAMap *map = vhost_iova_tree_find_iova(tree, &needle); + int r; + + if (unlikely(!map)) { + error_report("Cannot locate expected map"); + return; + } + + r = vhost_vdpa_dma_unmap(v, v->address_space_id, map->iova, map->size + 1); + if (unlikely(r != 0)) { + error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); + } + + vhost_iova_tree_remove(tree, *map); +} + +static size_t vhost_vdpa_net_cvq_cmd_len(void) +{ + /* + * MAC_TABLE_SET is the ctrl command that produces the longer out buffer. + * In buffer is always 1 byte, so it should fit here + */ + return sizeof(struct virtio_net_ctrl_hdr) + + 2 * sizeof(struct virtio_net_ctrl_mac) + + MAC_TABLE_ENTRIES * ETH_ALEN; +} + +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()); +} + +/** 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; + + map.translated_addr = (hwaddr)(uintptr_t)buf; + 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 r; + } + + r = vhost_vdpa_dma_map(v, v->address_space_id, map.iova, + vhost_vdpa_net_cvq_cmd_page_len(), buf, !write); + if (unlikely(r < 0)) { + goto dma_map_err; + } + + return 0; + +dma_map_err: + vhost_iova_tree_remove(v->iova_tree, map); + return r; +} + +static int vhost_vdpa_net_cvq_start(NetClientState *nc) +{ + VhostVDPAState *s; + struct vhost_vdpa *v; + uint64_t backend_features; + int64_t cvq_group; + int cvq_index, r; + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + s = DO_UPCAST(VhostVDPAState, nc, nc); + v = &s->vhost_vdpa; + + v->shadow_data = s->always_svq; + v->shadow_vqs_enabled = s->always_svq; + s->vhost_vdpa.address_space_id = VHOST_VDPA_GUEST_PA_ASID; + + if (s->always_svq) { + /* SVQ is already configured for all virtqueues */ + goto out; + } + + /* + * If we early return in these cases SVQ will not be enabled. The migration + * will be blocked as long as vhost-vdpa backends will not offer _F_LOG. + * + * Calling VHOST_GET_BACKEND_FEATURES as they are not available in v->dev + * yet. + */ + r = ioctl(v->device_fd, VHOST_GET_BACKEND_FEATURES, &backend_features); + if (unlikely(r < 0)) { + error_report("Cannot get vdpa backend_features: %s(%d)", + g_strerror(errno), errno); + return -1; + } + if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) || + !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { + return 0; + } + + /* + * Check if all the virtqueues of the virtio device are in a different vq + * than the last vq. VQ group of last group passed in cvq_group. + */ + cvq_index = v->dev->vq_index_end - 1; + cvq_group = vhost_vdpa_get_vring_group(v->device_fd, cvq_index); + if (unlikely(cvq_group < 0)) { + return cvq_group; + } + for (int i = 0; i < cvq_index; ++i) { + int64_t group = vhost_vdpa_get_vring_group(v->device_fd, i); + + if (unlikely(group < 0)) { + return group; + } + + if (group == cvq_group) { + return 0; + } + } + + r = vhost_vdpa_set_address_space_id(v, cvq_group, VHOST_VDPA_NET_CVQ_ASID); + if (unlikely(r < 0)) { + return r; + } + + v->iova_tree = vhost_iova_tree_new(v->iova_range.first, + v->iova_range.last); + v->shadow_vqs_enabled = true; + s->vhost_vdpa.address_space_id = VHOST_VDPA_NET_CVQ_ASID; + +out: + if (!s->vhost_vdpa.shadow_vqs_enabled) { + return 0; + } + + 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 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); + if (!s->always_svq) { + /* + * If only the CVQ is shadowed we can delete this safely. + * If all the VQs are shadows this will be needed by the time the + * device is started again to register SVQ vrings and similar. + */ + g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); + } + } +} + +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, +}; + +/** + * Validate and copy control virtqueue commands. + * + * Following QEMU guidelines, we offer a copy of the buffers to the device to + * prevent TOCTOU bugs. + */ +static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + VirtQueueElement *elem, + void *opaque) +{ + VhostVDPAState *s = opaque; + size_t in_len; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; + /* 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), + }; + ssize_t dev_written = -EINVAL; + + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, + s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_len()); + if (*(uint8_t *)s->cvq_cmd_out_buffer == VIRTIO_NET_CTRL_ANNOUNCE) { + /* + * Guest announce capability is emulated by qemu, so don't forward to + * the device. + */ + dev_written = sizeof(status); + *s->status = VIRTIO_NET_OK; + } else { + dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); + if (unlikely(dev_written < 0)) { + goto out; + } + } + + if (unlikely(dev_written < sizeof(status))) { + error_report("Insufficient written data (%zu)", dev_written); + 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, &out, 1); + if (status != VIRTIO_NET_OK) { + error_report("Bad CVQ processing in model"); + } + +out: + in_len = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, + sizeof(status)); + if (unlikely(in_len < sizeof(status))) { + error_report("Bad device CVQ written length"); + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); + return dev_written < 0 ? dev_written : 0; +} + +static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { + .avail_handler = vhost_vdpa_net_handle_ctrl_avail, +}; + static NetClientState *net_vhost_vdpa_init(NetClientState *peer, - const char *device, - const char *name, - int vdpa_device_fd, - int queue_pair_index, - int nvqs, - bool is_datapath) + const char *device, + const char *name, + int vdpa_device_fd, + int queue_pair_index, + int nvqs, + bool is_datapath, + bool svq, + struct vhost_vdpa_iova_range iova_range, + VhostIOVATree *iova_tree) { NetClientState *nc = NULL; VhostVDPAState *s; @@ -203,14 +678,30 @@ 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); + qemu_set_info_str(nc, TYPE_VHOST_VDPA); s = DO_UPCAST(VhostVDPAState, nc, nc); s->vhost_vdpa.device_fd = vdpa_device_fd; s->vhost_vdpa.index = queue_pair_index; + s->always_svq = svq; + s->vhost_vdpa.shadow_vqs_enabled = svq; + s->vhost_vdpa.iova_range = iova_range; + s->vhost_vdpa.shadow_data = svq; + s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + 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->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; + } ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); if (ret) { qemu_del_net_client(nc); @@ -219,20 +710,24 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, return nc; } -static int vhost_vdpa_get_max_queue_pairs(int fd, int *has_cvq, Error **errp) +static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) +{ + int ret = ioctl(fd, VHOST_GET_FEATURES, features); + if (unlikely(ret < 0)) { + error_setg_errno(errp, errno, + "Fail to query features from vhost-vDPA device"); + } + return ret; +} + +static int vhost_vdpa_get_max_queue_pairs(int fd, uint64_t features, + int *has_cvq, Error **errp) { unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); g_autofree struct vhost_vdpa_config *config = NULL; __virtio16 *max_queue_pairs; - uint64_t features; int ret; - ret = ioctl(fd, VHOST_GET_FEATURES, &features); - if (ret) { - error_setg(errp, "Fail to query features from vhost-vDPA device"); - return ret; - } - if (features & (1 << VIRTIO_NET_F_CTRL_VQ)) { *has_cvq = 1; } else { @@ -262,52 +757,99 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { const NetdevVhostVDPAOptions *opts; + uint64_t features; int vdpa_device_fd; g_autofree NetClientState **ncs = NULL; + g_autoptr(VhostIOVATree) iova_tree = NULL; + struct vhost_vdpa_iova_range iova_range; NetClientState *nc; - int queue_pairs, 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; - if (!opts->vhostdev) { - error_setg(errp, "vdpa character device not specified with vhostdev"); + if (!opts->vhostdev && !opts->vhostfd) { + error_setg(errp, + "vhost-vdpa: neither vhostdev= nor vhostfd= was specified"); return -1; } - vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp); - if (vdpa_device_fd == -1) { - return -errno; + if (opts->vhostdev && opts->vhostfd) { + error_setg(errp, + "vhost-vdpa: vhostdev= and vhostfd= are mutually exclusive"); + return -1; + } + + if (opts->vhostdev) { + vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp); + if (vdpa_device_fd == -1) { + return -errno; + } + } else { + /* has_vhostfd */ + vdpa_device_fd = monitor_fd_param(monitor_cur(), opts->vhostfd, errp); + if (vdpa_device_fd == -1) { + error_prepend(errp, "vhost-vdpa: unable to parse vhostfd: "); + return -1; + } } - queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); + if (unlikely(r < 0)) { + goto err; + } + + queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features, &has_cvq, errp); if (queue_pairs < 0) { qemu_close(vdpa_device_fd); return queue_pairs; } + r = vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); + if (unlikely(r < 0)) { + error_setg(errp, "vhost-vdpa: get iova range failed: %s", + strerror(-r)); + goto err; + } + + if (opts->x_svq) { + if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; + } + + iova_tree = vhost_iova_tree_new(iova_range.first, iova_range.last); + } + ncs = g_malloc0(sizeof(*ncs) * queue_pairs); for (i = 0; i < queue_pairs; i++) { ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, - vdpa_device_fd, i, 2, true); + vdpa_device_fd, i, 2, true, opts->x_svq, + iova_range, iova_tree); if (!ncs[i]) goto err; } if (has_cvq) { nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, - vdpa_device_fd, i, 1, false); + vdpa_device_fd, i, 1, false, + opts->x_svq, iova_range, iova_tree); if (!nc) goto err; } + /* iova_tree ownership belongs to last NetClientState */ + g_steal_pointer(&iova_tree); return 0; err: if (i) { - qemu_del_net_client(ncs[0]); + for (i--; i >= 0; i--) { + qemu_del_net_client(ncs[i]); + } } + +err_svq: qemu_close(vdpa_device_fd); return -1; diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m new file mode 100644 index 000000000000..46d22828632b --- /dev/null +++ b/net/vmnet-bridged.m @@ -0,0 +1,152 @@ +/* + * vmnet-bridged.m + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * 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 "qapi/qapi-types-net.h" +#include "qapi/error.h" +#include "clients.h" +#include "vmnet_int.h" + +#include + + +static bool validate_ifname(const char *ifname) +{ + xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); + bool match = false; + if (!xpc_array_get_count(shared_if_list)) { + goto done; + } + + match = !xpc_array_apply( + shared_if_list, + ^bool(size_t index, xpc_object_t value) { + return strcmp(xpc_string_get_string_ptr(value), ifname) != 0; + }); + +done: + xpc_release(shared_if_list); + return match; +} + + +static char* get_valid_ifnames() +{ + xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); + __block char *if_list = NULL; + __block char *if_list_prev = NULL; + + if (!xpc_array_get_count(shared_if_list)) { + goto done; + } + + xpc_array_apply( + shared_if_list, + ^bool(size_t index, xpc_object_t value) { + /* build list of strings like "en0 en1 en2 " */ + if_list = g_strconcat(xpc_string_get_string_ptr(value), + " ", + if_list_prev, + NULL); + g_free(if_list_prev); + if_list_prev = if_list; + return true; + }); + +done: + xpc_release(shared_if_list); + return if_list; +} + + +static bool validate_options(const Netdev *netdev, Error **errp) +{ + const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); + char* if_list; + + if (!validate_ifname(options->ifname)) { + if_list = get_valid_ifnames(); + if (if_list) { + error_setg(errp, + "unsupported ifname '%s', expected one of [ %s]", + options->ifname, + if_list); + g_free(if_list); + } else { + error_setg(errp, + "unsupported ifname '%s', no supported " + "interfaces available", + options->ifname); + } + return false; + } + +#if !defined(MAC_OS_VERSION_11_0) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0 + if (options->has_isolated) { + error_setg(errp, + "vmnet-bridged.isolated feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } +#endif + return true; +} + + +static xpc_object_t build_if_desc(const Netdev *netdev) +{ + const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); + + xpc_dictionary_set_uint64(if_desc, + vmnet_operation_mode_key, + VMNET_BRIDGED_MODE + ); + + xpc_dictionary_set_string(if_desc, + vmnet_shared_interface_name_key, + options->ifname); + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + xpc_dictionary_set_bool(if_desc, + vmnet_enable_isolation_key, + options->isolated); +#endif + return if_desc; +} + + +static NetClientInfo net_vmnet_bridged_info = { + .type = NET_CLIENT_DRIVER_VMNET_BRIDGED, + .size = sizeof(VmnetState), + .receive = vmnet_receive_common, + .cleanup = vmnet_cleanup_common, +}; + + +int net_init_vmnet_bridged(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + NetClientState *nc = qemu_new_net_client(&net_vmnet_bridged_info, + peer, "vmnet-bridged", name); + xpc_object_t if_desc; + int result = -1; + + if (!validate_options(netdev, errp)) { + return result; + } + + if_desc = build_if_desc(netdev); + result = vmnet_if_create(nc, if_desc, errp); + xpc_release(if_desc); + return result; +} diff --git a/net/vmnet-common.m b/net/vmnet-common.m new file mode 100644 index 000000000000..2cb60b9ddde7 --- /dev/null +++ b/net/vmnet-common.m @@ -0,0 +1,378 @@ +/* + * vmnet-common.m - network client wrapper for Apple vmnet.framework + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * Copyright(c) 2021 Phillip Tennen + * + * 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 "qemu/main-loop.h" +#include "qemu/log.h" +#include "qapi/qapi-types-net.h" +#include "vmnet_int.h" +#include "clients.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include +#include + + +static void vmnet_send_completed(NetClientState *nc, ssize_t len); + + +const char *vmnet_status_map_str(vmnet_return_t status) +{ + switch (status) { + case VMNET_SUCCESS: + return "success"; + case VMNET_FAILURE: + return "general failure (possibly not enough privileges)"; + case VMNET_MEM_FAILURE: + return "memory allocation failure"; + case VMNET_INVALID_ARGUMENT: + return "invalid argument specified"; + case VMNET_SETUP_INCOMPLETE: + return "interface setup is not complete"; + case VMNET_INVALID_ACCESS: + return "invalid access, permission denied"; + case VMNET_PACKET_TOO_BIG: + return "packet size is larger than MTU"; + case VMNET_BUFFER_EXHAUSTED: + return "buffers exhausted in kernel"; + case VMNET_TOO_MANY_PACKETS: + return "packet count exceeds limit"; +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + case VMNET_SHARING_SERVICE_BUSY: + return "conflict, sharing service is in use"; +#endif + default: + return "unknown vmnet error"; + } +} + + +/** + * Write packets from QEMU to vmnet interface. + * + * vmnet.framework supports iov, but writing more than + * one iov into vmnet interface fails with + * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into + * one and passing it to vmnet works fine. That's the + * reason why receive_iov() left unimplemented. But it still + * works with good performance having .receive() only. + */ +ssize_t vmnet_receive_common(NetClientState *nc, + const uint8_t *buf, + size_t size) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + struct vmpktdesc packet; + struct iovec iov; + int pkt_cnt; + vmnet_return_t if_status; + + if (size > s->max_packet_size) { + warn_report("vmnet: packet is too big, %zu > %" PRIu64, + packet.vm_pkt_size, + s->max_packet_size); + return -1; + } + + iov.iov_base = (char *) buf; + iov.iov_len = size; + + packet.vm_pkt_iovcnt = 1; + packet.vm_flags = 0; + packet.vm_pkt_size = size; + packet.vm_pkt_iov = &iov; + pkt_cnt = 1; + + if_status = vmnet_write(s->vmnet_if, &packet, &pkt_cnt); + if (if_status != VMNET_SUCCESS) { + error_report("vmnet: write error: %s\n", + vmnet_status_map_str(if_status)); + return -1; + } + + if (pkt_cnt) { + return size; + } + return 0; +} + + +/** + * Read packets from vmnet interface and write them + * to temporary buffers in VmnetState. + * + * Returns read packets number (may be 0) on success, + * -1 on error + */ +static int vmnet_read_packets(VmnetState *s) +{ + assert(s->packets_send_current_pos == s->packets_send_end_pos); + + struct vmpktdesc *packets = s->packets_buf; + vmnet_return_t status; + int i; + + /* Read as many packets as present */ + s->packets_send_current_pos = 0; + s->packets_send_end_pos = VMNET_PACKETS_LIMIT; + for (i = 0; i < s->packets_send_end_pos; ++i) { + packets[i].vm_pkt_size = s->max_packet_size; + packets[i].vm_pkt_iovcnt = 1; + packets[i].vm_flags = 0; + } + + status = vmnet_read(s->vmnet_if, packets, &s->packets_send_end_pos); + if (status != VMNET_SUCCESS) { + error_printf("vmnet: read failed: %s\n", + vmnet_status_map_str(status)); + s->packets_send_current_pos = 0; + s->packets_send_end_pos = 0; + return -1; + } + return s->packets_send_end_pos; +} + + +/** + * Write packets from temporary buffers in VmnetState + * to QEMU. + */ +static void vmnet_write_packets_to_qemu(VmnetState *s) +{ + while (s->packets_send_current_pos < s->packets_send_end_pos) { + ssize_t size = qemu_send_packet_async(&s->nc, + s->iov_buf[s->packets_send_current_pos].iov_base, + s->packets_buf[s->packets_send_current_pos].vm_pkt_size, + vmnet_send_completed); + + if (size == 0) { + /* QEMU is not ready to consume more packets - + * stop and wait for completion callback call */ + return; + } + ++s->packets_send_current_pos; + } +} + + +/** + * Bottom half callback that transfers packets from vmnet interface + * to QEMU. + * + * The process of transferring packets is three-staged: + * 1. Handle vmnet event; + * 2. Read packets from vmnet interface into temporary buffer; + * 3. Write packets from temporary buffer to QEMU. + * + * QEMU may suspend this process on the last stage, returning 0 from + * qemu_send_packet_async function. If this happens, we should + * respectfully wait until it is ready to consume more packets, + * write left ones in temporary buffer and only after this + * continue reading more packets from vmnet interface. + * + * Packets to be transferred are stored into packets_buf, + * in the window [packets_send_current_pos..packets_send_end_pos) + * including current_pos, excluding end_pos. + * + * Thus, if QEMU is not ready, buffer is not read and + * packets_send_current_pos < packets_send_end_pos. + */ +static void vmnet_send_bh(void *opaque) +{ + NetClientState *nc = (NetClientState *) opaque; + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + + /* + * Do nothing if QEMU is not ready - wait + * for completion callback invocation + */ + if (s->packets_send_current_pos < s->packets_send_end_pos) { + return; + } + + /* Read packets from vmnet interface */ + if (vmnet_read_packets(s) > 0) { + /* Send them to QEMU */ + vmnet_write_packets_to_qemu(s); + } +} + + +/** + * Completion callback to be invoked by QEMU when it becomes + * ready to consume more packets. + */ +static void vmnet_send_completed(NetClientState *nc, ssize_t len) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + + /* Callback is invoked eq queued packet is sent */ + ++s->packets_send_current_pos; + + /* Complete sending packets left in VmnetState buffers */ + vmnet_write_packets_to_qemu(s); + + /* And read new ones from vmnet if VmnetState buffer is ready */ + if (s->packets_send_current_pos < s->packets_send_end_pos) { + qemu_bh_schedule(s->send_bh); + } +} + + +static void vmnet_bufs_init(VmnetState *s) +{ + struct vmpktdesc *packets = s->packets_buf; + struct iovec *iov = s->iov_buf; + int i; + + for (i = 0; i < VMNET_PACKETS_LIMIT; ++i) { + iov[i].iov_len = s->max_packet_size; + iov[i].iov_base = g_malloc0(iov[i].iov_len); + packets[i].vm_pkt_iov = iov + i; + } +} + + +int vmnet_if_create(NetClientState *nc, + xpc_object_t if_desc, + Error **errp) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + dispatch_semaphore_t if_created_sem = dispatch_semaphore_create(0); + __block vmnet_return_t if_status; + + s->if_queue = dispatch_queue_create( + "org.qemu.vmnet.if_queue", + DISPATCH_QUEUE_SERIAL + ); + + xpc_dictionary_set_bool( + if_desc, + vmnet_allocate_mac_address_key, + false + ); + +#ifdef DEBUG + qemu_log("vmnet.start.interface_desc:\n"); + xpc_dictionary_apply(if_desc, + ^bool(const char *k, xpc_object_t v) { + char *desc = xpc_copy_description(v); + qemu_log(" %s=%s\n", k, desc); + free(desc); + return true; + }); +#endif /* DEBUG */ + + s->vmnet_if = vmnet_start_interface( + if_desc, + s->if_queue, + ^(vmnet_return_t status, xpc_object_t interface_param) { + if_status = status; + if (status != VMNET_SUCCESS || !interface_param) { + dispatch_semaphore_signal(if_created_sem); + return; + } + +#ifdef DEBUG + qemu_log("vmnet.start.interface_param:\n"); + xpc_dictionary_apply(interface_param, + ^bool(const char *k, xpc_object_t v) { + char *desc = xpc_copy_description(v); + qemu_log(" %s=%s\n", k, desc); + free(desc); + return true; + }); +#endif /* DEBUG */ + + s->mtu = xpc_dictionary_get_uint64( + interface_param, + vmnet_mtu_key); + s->max_packet_size = xpc_dictionary_get_uint64( + interface_param, + vmnet_max_packet_size_key); + + dispatch_semaphore_signal(if_created_sem); + }); + + if (s->vmnet_if == NULL) { + dispatch_release(s->if_queue); + dispatch_release(if_created_sem); + error_setg(errp, + "unable to create interface with requested params"); + return -1; + } + + dispatch_semaphore_wait(if_created_sem, DISPATCH_TIME_FOREVER); + dispatch_release(if_created_sem); + + if (if_status != VMNET_SUCCESS) { + dispatch_release(s->if_queue); + error_setg(errp, + "cannot create vmnet interface: %s", + vmnet_status_map_str(if_status)); + return -1; + } + + s->send_bh = aio_bh_new(qemu_get_aio_context(), vmnet_send_bh, nc); + vmnet_bufs_init(s); + + s->packets_send_current_pos = 0; + s->packets_send_end_pos = 0; + + vmnet_interface_set_event_callback( + s->vmnet_if, + VMNET_INTERFACE_PACKETS_AVAILABLE, + s->if_queue, + ^(interface_event_t event_id, xpc_object_t event) { + assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE); + /* + * This function is being called from a non qemu thread, so + * we only schedule a BH, and do the rest of the io completion + * handling from vmnet_send_bh() which runs in a qemu context. + */ + qemu_bh_schedule(s->send_bh); + }); + + return 0; +} + + +void vmnet_cleanup_common(NetClientState *nc) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + dispatch_semaphore_t if_stopped_sem; + + if (s->vmnet_if == NULL) { + return; + } + + if_stopped_sem = dispatch_semaphore_create(0); + vmnet_stop_interface( + s->vmnet_if, + s->if_queue, + ^(vmnet_return_t status) { + assert(status == VMNET_SUCCESS); + dispatch_semaphore_signal(if_stopped_sem); + }); + dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER); + + qemu_purge_queued_packets(nc); + + qemu_bh_delete(s->send_bh); + dispatch_release(if_stopped_sem); + dispatch_release(s->if_queue); + + for (int i = 0; i < VMNET_PACKETS_LIMIT; ++i) { + g_free(s->iov_buf[i].iov_base); + } +} diff --git a/net/vmnet-host.c b/net/vmnet-host.c new file mode 100644 index 000000000000..1f95f7343a12 --- /dev/null +++ b/net/vmnet-host.c @@ -0,0 +1,128 @@ +/* + * vmnet-host.c + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * 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 "qemu/uuid.h" +#include "qapi/qapi-types-net.h" +#include "qapi/error.h" +#include "clients.h" +#include "vmnet_int.h" + +#include + + +static bool validate_options(const Netdev *netdev, Error **errp) +{ + const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host); + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + + QemuUUID net_uuid; + if (options->net_uuid && + qemu_uuid_parse(options->net_uuid, &net_uuid) < 0) { + error_setg(errp, "Invalid UUID provided in 'net-uuid'"); + return false; + } +#else + if (options->has_isolated) { + error_setg(errp, + "vmnet-host.isolated feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } + + if (options->net_uuid) { + error_setg(errp, + "vmnet-host.net-uuid feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } +#endif + + if ((options->start_address || + options->end_address || + options->subnet_mask) && + !(options->start_address && + options->end_address && + options->subnet_mask)) { + error_setg(errp, + "'start-address', 'end-address', 'subnet-mask' " + "should be provided together"); + return false; + } + + return true; +} + +static xpc_object_t build_if_desc(const Netdev *netdev) +{ + const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host); + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); + + xpc_dictionary_set_uint64(if_desc, + vmnet_operation_mode_key, + VMNET_HOST_MODE); + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + + xpc_dictionary_set_bool(if_desc, + vmnet_enable_isolation_key, + options->isolated); + + QemuUUID net_uuid; + if (options->net_uuid) { + qemu_uuid_parse(options->net_uuid, &net_uuid); + xpc_dictionary_set_uuid(if_desc, + vmnet_network_identifier_key, + net_uuid.data); + } +#endif + + if (options->start_address) { + xpc_dictionary_set_string(if_desc, + vmnet_start_address_key, + options->start_address); + xpc_dictionary_set_string(if_desc, + vmnet_end_address_key, + options->end_address); + xpc_dictionary_set_string(if_desc, + vmnet_subnet_mask_key, + options->subnet_mask); + } + + return if_desc; +} + +static NetClientInfo net_vmnet_host_info = { + .type = NET_CLIENT_DRIVER_VMNET_HOST, + .size = sizeof(VmnetState), + .receive = vmnet_receive_common, + .cleanup = vmnet_cleanup_common, +}; + +int net_init_vmnet_host(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + NetClientState *nc = qemu_new_net_client(&net_vmnet_host_info, + peer, "vmnet-host", name); + xpc_object_t if_desc; + int result = -1; + + if (!validate_options(netdev, errp)) { + return result; + } + + if_desc = build_if_desc(netdev); + result = vmnet_if_create(nc, if_desc, errp); + xpc_release(if_desc); + return result; +} diff --git a/net/vmnet-shared.c b/net/vmnet-shared.c new file mode 100644 index 000000000000..40c7306a758a --- /dev/null +++ b/net/vmnet-shared.c @@ -0,0 +1,114 @@ +/* + * vmnet-shared.c + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * 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 "qapi/qapi-types-net.h" +#include "qapi/error.h" +#include "vmnet_int.h" +#include "clients.h" + +#include + + +static bool validate_options(const Netdev *netdev, Error **errp) +{ + const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared); + +#if !defined(MAC_OS_VERSION_11_0) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0 + if (options->has_isolated) { + error_setg(errp, + "vmnet-shared.isolated feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } +#endif + + if ((options->start_address || + options->end_address || + options->subnet_mask) && + !(options->start_address && + options->end_address && + options->subnet_mask)) { + error_setg(errp, + "'start-address', 'end-address', 'subnet-mask' " + "should be provided together" + ); + return false; + } + + return true; +} + +static xpc_object_t build_if_desc(const Netdev *netdev) +{ + const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared); + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); + + xpc_dictionary_set_uint64( + if_desc, + vmnet_operation_mode_key, + VMNET_SHARED_MODE + ); + + if (options->nat66_prefix) { + xpc_dictionary_set_string(if_desc, + vmnet_nat66_prefix_key, + options->nat66_prefix); + } + + if (options->start_address) { + xpc_dictionary_set_string(if_desc, + vmnet_start_address_key, + options->start_address); + xpc_dictionary_set_string(if_desc, + vmnet_end_address_key, + options->end_address); + xpc_dictionary_set_string(if_desc, + vmnet_subnet_mask_key, + options->subnet_mask); + } + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + xpc_dictionary_set_bool( + if_desc, + vmnet_enable_isolation_key, + options->isolated + ); +#endif + + return if_desc; +} + +static NetClientInfo net_vmnet_shared_info = { + .type = NET_CLIENT_DRIVER_VMNET_SHARED, + .size = sizeof(VmnetState), + .receive = vmnet_receive_common, + .cleanup = vmnet_cleanup_common, +}; + +int net_init_vmnet_shared(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + NetClientState *nc = qemu_new_net_client(&net_vmnet_shared_info, + peer, "vmnet-shared", name); + xpc_object_t if_desc; + int result = -1; + + if (!validate_options(netdev, errp)) { + return result; + } + + if_desc = build_if_desc(netdev); + result = vmnet_if_create(nc, if_desc, errp); + xpc_release(if_desc); + return result; +} diff --git a/net/vmnet_int.h b/net/vmnet_int.h new file mode 100644 index 000000000000..adf6e8c20d5d --- /dev/null +++ b/net/vmnet_int.h @@ -0,0 +1,63 @@ +/* + * vmnet_int.h + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#ifndef VMNET_INT_H +#define VMNET_INT_H + +#include "qemu/osdep.h" +#include "vmnet_int.h" +#include "clients.h" + +#include +#include + +/** + * From vmnet.framework documentation + * + * Each read/write call allows up to 200 packets to be + * read or written for a maximum of 256KB. + * + * Each packet written should be a complete + * ethernet frame. + * + * https://developer.apple.com/documentation/vmnet + */ +#define VMNET_PACKETS_LIMIT 200 + +typedef struct VmnetState { + NetClientState nc; + interface_ref vmnet_if; + + uint64_t mtu; + uint64_t max_packet_size; + + dispatch_queue_t if_queue; + + QEMUBH *send_bh; + + struct vmpktdesc packets_buf[VMNET_PACKETS_LIMIT]; + int packets_send_current_pos; + int packets_send_end_pos; + + struct iovec iov_buf[VMNET_PACKETS_LIMIT]; +} VmnetState; + +const char *vmnet_status_map_str(vmnet_return_t status); + +int vmnet_if_create(NetClientState *nc, + xpc_object_t if_desc, + Error **errp); + +ssize_t vmnet_receive_common(NetClientState *nc, + const uint8_t *buf, + size_t size); + +void vmnet_cleanup_common(NetClientState *nc); + +#endif /* VMNET_INT_H */ diff --git a/os-posix.c b/os-posix.c index 24692c8593f3..5adc69f560ef 100644 --- a/os-posix.c +++ b/os-posix.c @@ -29,7 +29,6 @@ #include #include -#include "qemu-common.h" /* Needed early for CONFIG_BSD etc. */ #include "net/slirp.h" #include "qemu/qemu-options.h" @@ -40,6 +39,7 @@ #ifdef CONFIG_LINUX #include +#include "qemu/async-teardown.h" #endif /* @@ -152,11 +152,8 @@ int os_parse_cmd_args(int index, const char *optarg) daemonize = 1; break; #if defined(CONFIG_LINUX) - case QEMU_OPTION_enablefips: - warn_report("-enable-fips is deprecated, please build QEMU with " - "the `libgcrypt` library as the cryptography provider " - "to enable FIPS compliance"); - fips_set_state(true); + case QEMU_OPTION_asyncteardown: + init_async_teardown(); break; #endif default: @@ -224,7 +221,7 @@ void os_daemonize(void) pid_t pid; int fds[2]; - if (pipe(fds) == -1) { + if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) { exit(1); } @@ -249,7 +246,6 @@ void os_daemonize(void) close(fds[0]); daemon_pipe = fds[1]; - qemu_set_cloexec(daemon_pipe); setsid(); @@ -276,7 +272,7 @@ void os_setup_post(void) error_report("not able to chdir to /: %s", strerror(errno)); exit(1); } - TFR(fd = qemu_open_old("/dev/null", O_RDWR)); + fd = RETRY_ON_EINTR(qemu_open_old("/dev/null", O_RDWR)); if (fd == -1) { exit(1); } @@ -292,7 +288,7 @@ void os_setup_post(void) dup2(fd, 0); dup2(fd, 1); /* In case -D is given do not redirect stderr to /dev/null */ - if (!qemu_logfile) { + if (!qemu_log_enabled()) { dup2(fd, 2); } diff --git a/os-win32.c b/os-win32.c index e31c921983b4..725ad652e8bb 100644 --- a/os-win32.c +++ b/os-win32.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include #include -#include "qemu-common.h" #include "sysemu/runstate.h" static BOOL WINAPI qemu_ctrl_handler(DWORD type) @@ -61,12 +60,3 @@ void os_set_line_buffering(void) setbuf(stdout, NULL); setbuf(stderr, NULL); } - -/* - * Parse OS specific command line options. - * return 0 if option handled, -1 otherwise - */ -int os_parse_cmd_args(int index, const char *optarg) -{ - return -1; -} diff --git a/page-vary-common.c b/page-vary-common.c index 91755564985c..ab77672dd412 100644 --- a/page-vary-common.c +++ b/page-vary-common.c @@ -20,7 +20,6 @@ #define IN_PAGE_VARY 1 #include "qemu/osdep.h" -#include "qemu-common.h" #include "exec/page-vary.h" /* WARNING: This file must *not* be complied with -flto. */ diff --git a/page-vary.c b/page-vary.c index 057c7f181521..343b4adb95a5 100644 --- a/page-vary.c +++ b/page-vary.c @@ -20,7 +20,7 @@ #define IN_PAGE_VARY 1 #include "qemu/osdep.h" -#include "qemu-common.h" +#include "exec/page-vary.h" #include "exec/exec-all.h" bool set_preferred_target_page_bits(int bits) diff --git a/pc-bios/README b/pc-bios/README index ba6c15e76957..b94f3fb0811b 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/bios-256k.bin b/pc-bios/bios-256k.bin index 6163fb8149dc..211b2a4da224 100644 Binary files a/pc-bios/bios-256k.bin and b/pc-bios/bios-256k.bin differ diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin index 97fbd3192a6f..6204a714cd83 100644 Binary files a/pc-bios/bios-microvm.bin and b/pc-bios/bios-microvm.bin differ diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 68f65ff2fde1..12d6a037be66 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img index 0ec2d96b8f48..b2cbb71ee0f9 100644 Binary files a/pc-bios/hppa-firmware.img and b/pc-bios/hppa-firmware.img differ diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index 44247a12b54a..06c75e646b9f 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -38,11 +38,10 @@ if meson.is_cross_build() or 'CONFIG_XKBCOMMON' not in config_host else native_qemu_keymap = qemu_keymap endif -cp = find_program('cp') -t = [] -foreach km, args: keymaps - if native_qemu_keymap.found() +if native_qemu_keymap.found() + t = [] + foreach km, args: keymaps # generate with qemu-kvm t += custom_target(km, build_by_default: true, @@ -50,20 +49,11 @@ foreach km, args: keymaps command: [native_qemu_keymap, '-f', '@OUTPUT@', args.split()], install: true, install_dir: qemu_datadir / 'keymaps') - else - # copy from source tree - t += custom_target(km, - build_by_default: true, - input: km, - output: km, - command: [cp, '@INPUT@', '@OUTPUT@'], - install: true, - install_dir: qemu_datadir / 'keymaps') - endif -endforeach + endforeach -if native_qemu_keymap.found() alias_target('update-keymaps', t) +else + install_data(keymaps.keys(), install_dir: qemu_datadir / 'keymaps') endif install_data(['sl', 'sv'], install_dir: qemu_datadir / 'keymaps') diff --git a/pc-bios/meson.build b/pc-bios/meson.build index c86dedf7dff9..388e0db6e403 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -23,7 +23,7 @@ if unpack_edk2_blobs endforeach endif -blobs = files( +blobs = [ 'bios.bin', 'bios-256k.bin', 'bios-microvm.bin', @@ -83,7 +83,7 @@ blobs = files( 'npcm7xx_bootrom.bin', 'vof.bin', 'vof-nvram.bin', -) +] if get_option('install_blobs') install_data(blobs, install_dir: qemu_datadir) diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin index dba8e8655fbf..81bab1adc97b 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 f223e56991f5..5eb0a743260b 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 f1ef89807355..b1fff0ba6c84 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -6,68 +6,64 @@ all: multiboot.bin multiboot_dma.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bi # Dummy command so that make thinks it has done something @true -include ../../config-host.mak 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 - -# 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 += $(CFLAGS_NOPIE) -ffreestanding -I$(TOPSRC_DIR)/include -override CFLAGS += $(call cc-option, -fno-stack-protector) -override CFLAGS += $(call cc-option, -m16) - -ifeq ($(filter -m16, $(CFLAGS)),) -# Attempt to work around compilers that lack -m16 (GCC <= 4.8, clang <= ??) -# On GCC we add -fno-toplevel-reorder to keep the order of asm blocks with -# respect to the rest of the code. clang does not have -fno-toplevel-reorder, -# but it places all asm blocks at the beginning and we're relying on it for -# the option ROM header. So just force clang not to use the integrated -# assembler, which doesn't support .code16gcc. -override CFLAGS += $(call cc-option, -fno-toplevel-reorder) -override CFLAGS += $(call cc-option, -no-integrated-as) -override CFLAGS += -m32 -include $(SRC_DIR)/code16gcc.h -endif - -Wa = -Wa, -override ASFLAGS += -32 -override CFLAGS += $(call cc-option, $(Wa)-32) - -LD_I386_EMULATION ?= elf_i386 -override LDFLAGS = -m $(LD_I386_EMULATION) -T $(SRC_DIR)/flat.lds +override CFLAGS += -march=i486 -Wall $(EXTRA_CFLAGS) -m16 +override CFLAGS += -ffreestanding -I$(TOPSRC_DIR)/include + +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 + +# 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,$(CPP) $(CPPFLAGS) -c -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/optionrom/code16gcc.h b/pc-bios/optionrom/code16gcc.h deleted file mode 100644 index 9c8d25d508ac..000000000000 --- a/pc-bios/optionrom/code16gcc.h +++ /dev/null @@ -1,3 +0,0 @@ -asm( -".code16gcc\n" -); diff --git a/pc-bios/qboot.rom b/pc-bios/qboot.rom old mode 100644 new mode 100755 index 7634106a0766..684000f57aad 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 a560c1272f6c..554fcbd1b7af 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 0eb68efc7b75..10e8f5cb633d 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -2,55 +2,71 @@ all: build-all # Dummy command so that make thinks it has done something @true -include ../../config-host.mak +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))) -$(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) +$(call set-vpath, $(SRC_PATH)) # Flags for dependency generation QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d %.o: %.c - $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \ - -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(EXTRA_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \ + -c -o $@ $<,Compiling) %.o: %.S - $(call quiet-command,$(CCAS) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \ - -c -o $@ $<,"CCAS","$(TARGET_DIR)$@") + $(call quiet-command,$(CCAS) $(EXTRA_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \ + -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 -QEMU_CFLAGS := -Wall $(filter -W%, $(QEMU_CFLAGS)) -QEMU_CFLAGS += $(call cc-option,-Werror $(QEMU_CFLAGS),-Wno-stringop-overflow) -QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE -QEMU_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables -QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector) -QEMU_CFLAGS += -msoft-float -QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS),-march=z900,-march=z10) -QEMU_CFLAGS += -std=gnu99 +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 += -msoft-float +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 -ifneq ($(wildcard $(SRC_PATH)/roms/SLOF/lib/libnet),) -include $(SRC_PATH)/pc-bios/s390-ccw/netboot.mak +ifneq ($(wildcard $(SRC_PATH)/../../roms/SLOF/lib/libnet),) +include $(SRC_PATH)/netboot.mak else s390-netboot.img: @echo "s390-netboot.img not built since roms/SLOF/ is not available." @@ -61,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/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 56411ab3b67e..994e59c0b022 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -780,18 +780,37 @@ static void ipl_iso_el_torito(void) } } +/** + * Detect whether we're trying to boot from an .ISO image. + * These always have a signature string "CD001" at offset 0x8001. + */ +static bool has_iso_signature(void) +{ + int blksize = virtio_get_block_size(); + + if (!blksize || virtio_read(0x8000 / blksize, sec)) { + return false; + } + + return !memcmp("CD001", &sec[1], 5); +} + /*********************************************************************** * Bus specific IPL sequences */ static void zipl_load_vblk(void) { - if (virtio_guessed_disk_nature()) { - virtio_assume_iso9660(); + int blksize = virtio_get_block_size(); + + if (blksize == VIRTIO_ISO_BLOCK_SIZE || has_iso_signature()) { + if (blksize != VIRTIO_ISO_BLOCK_SIZE) { + virtio_assume_iso9660(); + } + ipl_iso_el_torito(); } - ipl_iso_el_torito(); - if (virtio_guessed_disk_nature()) { + if (blksize != VIRTIO_DASD_DEFAULT_BLOCK_SIZE) { sclp_print("Using guessed DASD geometry.\n"); virtio_assume_eckd(); } diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h index 1e5d4e92e12c..88a88adfd2fd 100644 --- a/pc-bios/s390-ccw/cio.h +++ b/pc-bios/s390-ccw/cio.h @@ -20,7 +20,7 @@ struct pmcw { __u32 intparm; /* interruption parameter */ __u32 qf:1; /* qdio facility */ __u32 w:1; - __u32 isc:3; /* interruption sublass */ + __u32 isc:3; /* interruption subclass */ __u32 res5:3; /* reserved zeros */ __u32 ena:1; /* enabled */ __u32 lm:2; /* limit mode */ diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h index 772d5c57c94e..cb6ac8a880a0 100644 --- a/pc-bios/s390-ccw/iplb.h +++ b/pc-bios/s390-ccw/iplb.h @@ -81,7 +81,7 @@ extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); #define QIPL_FLAG_BM_OPTS_ZIPL 0x40 /* - * This definition must be kept in sync with the defininition + * This definition must be kept in sync with the definition * in hw/s390x/ipl.h */ struct QemuIplParameters { diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 5d2b7ba94de4..a2def83e8236 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -14,6 +14,7 @@ #include "s390-ccw.h" #include "cio.h" #include "virtio.h" +#include "virtio-scsi.h" #include "dasd-ipl.h" char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); @@ -218,6 +219,7 @@ static int virtio_setup(void) { VDev *vdev = virtio_get_device(); QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS; + int ret; memcpy(&qipl, early_qipl, sizeof(QemuIplParameters)); @@ -225,18 +227,26 @@ static int virtio_setup(void) menu_setup(); } - if (virtio_get_device_type() == VIRTIO_ID_NET) { + switch (vdev->senseid.cu_model) { + case VIRTIO_ID_NET: sclp_print("Network boot device detected\n"); vdev->netboot_start_addr = qipl.netboot_start_addr; - } else { - int ret = virtio_blk_setup_device(blk_schid); - if (ret) { - return ret; - } + return 0; + case VIRTIO_ID_BLOCK: + ret = virtio_blk_setup_device(blk_schid); + break; + case VIRTIO_ID_SCSI: + ret = virtio_scsi_setup_device(blk_schid); + break; + default: + panic("\n! No IPL device available !\n"); + } + + if (!ret) { IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected"); } - return 0; + return ret; } static void ipl_boot_device(void) @@ -281,7 +291,7 @@ static void probe_boot_device(void) sclp_print("Could not find a suitable boot device (none specified)\n"); } -int main(void) +void main(void) { sclp_setup(); css_setup(); @@ -294,5 +304,4 @@ int main(void) } panic("Failed to load OS from hard disk\n"); - return 0; /* make compiler happy */ } diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index 68b4d7edcb2c..046aa35587ac 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -1,5 +1,5 @@ -SLOF_DIR := $(SRC_PATH)/roms/SLOF +SLOF_DIR := $(SRC_PATH)/../../roms/SLOF NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o @@ -8,55 +8,55 @@ LIBNET_INC := -I$(SLOF_DIR)/lib/libnet NETLDFLAGS := $(LDFLAGS) -Wl,-Ttext=0x7800000 -$(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC) +$(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)$@") + $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into) # libc files: -LIBC_CFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(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 = $(QEMU_CFLAGS) $(CFLAGS) $(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/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 79db69ff542e..b88e0550ab9f 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -57,6 +57,7 @@ void write_subsystem_identification(void); void write_iplb_location(void); extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); unsigned int get_loadparm_index(void); +void main(void); /* sclp.c */ void sclp_print(const char *string); diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S index 4d5ad21653d0..6072906df48c 100644 --- a/pc-bios/s390-ccw/start.S +++ b/pc-bios/s390-ccw/start.S @@ -19,7 +19,7 @@ _start: larl %r2, __bss_start larl %r3, _end slgr %r3, %r2 /* get sizeof bss */ - ltgr %r3,%r3 /* bss emtpy? */ + ltgr %r3,%r3 /* bss empty? */ jz done aghi %r3,-1 srlg %r4,%r3,8 /* how many 256 byte chunks? */ diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c index 7d35050292de..794f99b42c22 100644 --- a/pc-bios/s390-ccw/virtio-blkdev.c +++ b/pc-bios/s390-ccw/virtio-blkdev.c @@ -13,6 +13,9 @@ #include "virtio.h" #include "virtio-scsi.h" +#define VIRTIO_BLK_F_GEOMETRY (1 << 4) +#define VIRTIO_BLK_F_BLK_SIZE (1 << 6) + static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr, int sec_num) { @@ -112,23 +115,6 @@ VirtioGDN virtio_guessed_disk_nature(void) return virtio_get_device()->guessed_disk_nature; } -void virtio_assume_scsi(void) -{ - VDev *vdev = virtio_get_device(); - - switch (vdev->senseid.cu_model) { - case VIRTIO_ID_BLOCK: - vdev->guessed_disk_nature = VIRTIO_GDN_SCSI; - vdev->config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE; - vdev->config.blk.physical_block_exp = 0; - vdev->blk_factor = 1; - break; - case VIRTIO_ID_SCSI: - vdev->scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE; - break; - } -} - void virtio_assume_iso9660(void) { VDev *vdev = virtio_get_device(); @@ -155,7 +141,7 @@ void virtio_assume_eckd(void) vdev->config.blk.physical_block_exp = 0; switch (vdev->senseid.cu_model) { case VIRTIO_ID_BLOCK: - vdev->config.blk.blk_size = 4096; + vdev->config.blk.blk_size = VIRTIO_DASD_DEFAULT_BLOCK_SIZE; break; case VIRTIO_ID_SCSI: vdev->config.blk.blk_size = vdev->scsi_block_size; @@ -166,46 +152,19 @@ void virtio_assume_eckd(void) virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size); } -bool virtio_disk_is_scsi(void) -{ - VDev *vdev = virtio_get_device(); - - if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI) { - return true; - } - switch (vdev->senseid.cu_model) { - case VIRTIO_ID_BLOCK: - return (vdev->config.blk.geometry.heads == 255) - && (vdev->config.blk.geometry.sectors == 63) - && (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE); - case VIRTIO_ID_SCSI: - return true; - } - return false; -} - -bool virtio_disk_is_eckd(void) +bool virtio_ipl_disk_is_valid(void) { + int blksize = virtio_get_block_size(); VDev *vdev = virtio_get_device(); - const int block_size = virtio_get_block_size(); - if (vdev->guessed_disk_nature == VIRTIO_GDN_DASD) { + if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI || + vdev->guessed_disk_nature == VIRTIO_GDN_DASD) { return true; } - switch (vdev->senseid.cu_model) { - case VIRTIO_ID_BLOCK: - return (vdev->config.blk.geometry.heads == 15) - && (vdev->config.blk.geometry.sectors == - virtio_eckd_sectors_for_block_size(block_size)); - case VIRTIO_ID_SCSI: - return false; - } - return false; -} -bool virtio_ipl_disk_is_valid(void) -{ - return virtio_disk_is_scsi() || virtio_disk_is_eckd(); + return (vdev->senseid.cu_model == VIRTIO_ID_BLOCK || + vdev->senseid.cu_model == VIRTIO_ID_SCSI) && + blksize >= 512 && blksize <= 4096; } int virtio_get_block_size(void) @@ -214,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; } @@ -266,34 +225,12 @@ uint64_t virtio_get_blocks(void) int virtio_blk_setup_device(SubChannelId schid) { VDev *vdev = virtio_get_device(); - int ret = 0; + vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE; vdev->schid = schid; virtio_setup_ccw(vdev); - switch (vdev->senseid.cu_model) { - case VIRTIO_ID_BLOCK: - sclp_print("Using virtio-blk.\n"); - if (!virtio_ipl_disk_is_valid()) { - /* make sure all getters but blocksize return 0 for - * invalid IPL disk - */ - memset(&vdev->config.blk, 0, sizeof(vdev->config.blk)); - virtio_assume_scsi(); - } - break; - case VIRTIO_ID_SCSI: - IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE, - "Config: sense size mismatch"); - IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE, - "Config: CDB size mismatch"); - - sclp_print("Using virtio-scsi.\n"); - ret = virtio_scsi_setup(vdev); - break; - default: - panic("\n! No IPL device available !\n"); - } + sclp_print("Using virtio-blk.\n"); - return ret; + return 0; } diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c index 2c8d0f30970a..dcce696a3375 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 */ @@ -329,7 +329,7 @@ static void scsi_parse_capacity_report(void *data, } } -int virtio_scsi_setup(VDev *vdev) +static int virtio_scsi_setup(VDev *vdev) { int retry_test_unit_ready = 3; uint8_t data[256]; @@ -430,3 +430,20 @@ int virtio_scsi_setup(VDev *vdev) return 0; } + +int virtio_scsi_setup_device(SubChannelId schid) +{ + VDev *vdev = virtio_get_device(); + + vdev->schid = schid; + virtio_setup_ccw(vdev); + + IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE, + "Config: sense size mismatch"); + IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE, + "Config: CDB size mismatch"); + + sclp_print("Using virtio-scsi.\n"); + + return virtio_scsi_setup(vdev); +} diff --git a/pc-bios/s390-ccw/virtio-scsi.h b/pc-bios/s390-ccw/virtio-scsi.h index 4b14c2c2f909..e6b6cd4815b0 100644 --- a/pc-bios/s390-ccw/virtio-scsi.h +++ b/pc-bios/s390-ccw/virtio-scsi.h @@ -67,8 +67,8 @@ static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r) return r->response == VIRTIO_SCSI_S_OK && r->status == CDB_STATUS_GOOD; } -int virtio_scsi_setup(VDev *vdev); int virtio_scsi_read_many(VDev *vdev, ulong sector, void *load_addr, int sec_num); +int virtio_scsi_setup_device(SubChannelId schid); #endif /* VIRTIO_SCSI_H */ diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 5d2c6e338169..f37510f3124e 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -220,7 +220,7 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd) void virtio_setup_ccw(VDev *vdev) { int i, rc, cfg_size = 0; - unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK; + uint8_t status; struct VirtioFeatureDesc { uint32_t features; uint8_t index; @@ -234,6 +234,10 @@ void virtio_setup_ccw(VDev *vdev) run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false); + status = VIRTIO_CONFIG_S_ACKNOWLEDGE; + rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false); + IPL_assert(rc == 0, "Could not write ACKNOWLEDGE status to host"); + switch (vdev->senseid.cu_model) { case VIRTIO_ID_NET: vdev->nr_vqs = 2; @@ -253,9 +257,10 @@ void virtio_setup_ccw(VDev *vdev) default: panic("Unsupported virtio device\n"); } - IPL_assert( - run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false) == 0, - "Could not get block device configuration"); + + status |= VIRTIO_CONFIG_S_DRIVER; + rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false); + IPL_assert(rc == 0, "Could not write DRIVER status to host"); /* Feature negotiation */ for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) { @@ -269,6 +274,9 @@ void virtio_setup_ccw(VDev *vdev) IPL_assert(rc == 0, "Could not set features bits"); } + rc = run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false); + IPL_assert(rc == 0, "Could not get virtio device configuration"); + for (i = 0; i < vdev->nr_vqs; i++) { VqInfo info = { .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE), @@ -281,9 +289,8 @@ void virtio_setup_ccw(VDev *vdev) .num = 0, }; - IPL_assert( - run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false) == 0, - "Could not get block device VQ configuration"); + rc = run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false); + IPL_assert(rc == 0, "Could not get virtio device VQ configuration"); info.num = config.num; vring_init(&vdev->vrings[i], &info); vdev->vrings[i].schid = vdev->schid; @@ -291,9 +298,10 @@ void virtio_setup_ccw(VDev *vdev) run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0, "Cannot set VQ info"); } - IPL_assert( - run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false) == 0, - "Could not write status to host"); + + status |= VIRTIO_CONFIG_S_DRIVER_OK; + rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false); + IPL_assert(rc == 0, "Could not write DRIVER_OK status to host"); } bool virtio_is_supported(SubChannelId schid) diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index 19fceb6495f3..e657d381ecad 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -182,22 +182,20 @@ enum guessed_disk_nature_type { typedef enum guessed_disk_nature_type VirtioGDN; VirtioGDN virtio_guessed_disk_nature(void); -void virtio_assume_scsi(void); void virtio_assume_eckd(void); void virtio_assume_iso9660(void); -extern bool virtio_disk_is_scsi(void); -extern bool virtio_disk_is_eckd(void); -extern bool virtio_ipl_disk_is_valid(void); -extern int virtio_get_block_size(void); -extern uint8_t virtio_get_heads(void); -extern uint8_t virtio_get_sectors(void); -extern uint64_t virtio_get_blocks(void); -extern int virtio_read_many(ulong sector, void *load_addr, int sec_num); +bool virtio_ipl_disk_is_valid(void); +int virtio_get_block_size(void); +uint8_t virtio_get_heads(void); +uint8_t virtio_get_sectors(void); +uint64_t virtio_get_blocks(void); +int virtio_read_many(ulong sector, void *load_addr, int sec_num); #define VIRTIO_SECTOR_SIZE 512 #define VIRTIO_ISO_BLOCK_SIZE 2048 #define VIRTIO_SCSI_BLOCK_SIZE 512 +#define VIRTIO_DASD_DEFAULT_BLOCK_SIZE 4096 static inline ulong virtio_sector_adjust(ulong sector) { diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img index bc34af8a287e..682da24a05d3 100644 Binary files a/pc-bios/s390-netboot.img and b/pc-bios/s390-netboot.img differ diff --git a/pc-bios/skiboot.lid b/pc-bios/skiboot.lid index 8a3c278512a4..58ec5ec38edb 100644 Binary files a/pc-bios/skiboot.lid and b/pc-bios/skiboot.lid differ diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index cbbe23e91075..ef9b81d6282b 100644 Binary files a/pc-bios/slof.bin and b/pc-bios/slof.bin differ diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin index 4533d0d063c2..39b240514819 100644 Binary files a/pc-bios/vgabios-ati.bin and b/pc-bios/vgabios-ati.bin differ diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin index 3ecf92de0114..b20d67ccf540 100644 Binary files a/pc-bios/vgabios-bochs-display.bin and b/pc-bios/vgabios-bochs-display.bin differ diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 9b4ffdf45f5f..ebe53366e45c 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin index 8a27dac55729..4b5573a85781 100644 Binary files a/pc-bios/vgabios-qxl.bin and b/pc-bios/vgabios-qxl.bin differ diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin index ec9541cfb48f..d458ec743642 100644 Binary files a/pc-bios/vgabios-ramfb.bin and b/pc-bios/vgabios-ramfb.bin differ diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin index 55390c45c925..797e1036c985 100644 Binary files a/pc-bios/vgabios-stdvga.bin and b/pc-bios/vgabios-stdvga.bin differ diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin index 2334733a7550..3f8fe9de13bb 100644 Binary files a/pc-bios/vgabios-virtio.bin and b/pc-bios/vgabios-virtio.bin differ diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin index b668ac04a67c..d5f263a9f74a 100644 Binary files a/pc-bios/vgabios-vmware.bin and b/pc-bios/vgabios-vmware.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index a924891ea58e..d26af416ced0 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ diff --git a/pc-bios/vof/Makefile b/pc-bios/vof/Makefile index aa1678c4d889..d1eb6ced7ec9 100644 --- a/pc-bios/vof/Makefile +++ b/pc-bios/vof/Makefile @@ -1,23 +1,31 @@ -all: build-all +include config.mak +VPATH=$(SRC_DIR) +all: vof.bin -build-all: vof.bin +NULL := +SPACE := $(NULL) # +TARGET_PREFIX := $(patsubst %/,%:$(SPACE),$(TARGET_DIR)) -CROSS ?= -CC = $(CROSS)gcc -LD = $(CROSS)ld -OBJCOPY = $(CROSS)objcopy +quiet-@ = $(if $(V),,@$(if $1,,printf "%s\n" "$(TARGET_PREFIX)$1" && )) +quiet-command = $(call quiet-@,$2 $@)$1 + +EXTRA_CFLAGS += -mcpu=power4 %.o: %.S - $(CC) -m32 -mbig-endian -mcpu=power4 -c -o $@ $< + $(call quiet-command, $(CC) $(EXTRA_CFLAGS) -c -o $@ $<,Assembling) %.o: %.c - $(CC) -m32 -mbig-endian -mcpu=power4 -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 -Tvof.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 *~ + +distclean: clean + +.PHONY: all clean distclean diff --git a/plugins/api.c b/plugins/api.c index 7bf71b189dd0..2078b16edb02 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 792262da0839..ccb770a48501 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 fa1204732718..752377c66d32 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/plugins/plugin.h b/plugins/plugin.h index b13677d0dc24..5eb2fdbc85eb 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -9,8 +9,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef PLUGIN_INTERNAL_H -#define PLUGIN_INTERNAL_H +#ifndef PLUGIN_H +#define PLUGIN_H #include #include "qemu/qht.h" @@ -97,4 +97,4 @@ void plugin_register_vcpu_mem_cb(GArray **arr, void exec_inline_op(struct qemu_plugin_dyn_cb *cb); -#endif /* _PLUGIN_INTERNAL_H_ */ +#endif /* PLUGIN_H */ diff --git a/po/LINGUAS b/po/LINGUAS index cc4b5c3b36c5..9b33a3659fcd 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -5,4 +5,5 @@ hu it sv tr +uk zh_CN diff --git a/po/uk.po b/po/uk.po new file mode 100644 index 000000000000..ff037808bf18 --- /dev/null +++ b/po/uk.po @@ -0,0 +1,75 @@ +# Ukrainian translation for QEMU. +# This file is put in the public domain. +# Andrij Mizyk , 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: QEMU 1.4.50\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2018-07-18 07:56+0200\n" +"PO-Revision-Date: 2022-06-13 01:33+0300\n" +"Last-Translator: Andrij Mizyk \n" +"Language-Team: Ukrainian\n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Gtranslator 2.91.6\n" + +msgid " - Press Ctrl+Alt+G to release grab" +msgstr " - Натисніть Ctrl+Alt+G, щоб відпустити захоплення" + +msgid " [Paused]" +msgstr " [Призупинено]" + +msgid "_Pause" +msgstr "_Призупинити" + +msgid "_Reset" +msgstr "_Скинути" + +msgid "Power _Down" +msgstr "Вимкнути _живлення" + +msgid "_Quit" +msgstr "_Вийти" + +msgid "_Fullscreen" +msgstr "Повний _екран" + +msgid "_Copy" +msgstr "_Копіювати" + +msgid "Zoom _In" +msgstr "_Збільшити" + +msgid "Zoom _Out" +msgstr "З_меншити" + +msgid "Best _Fit" +msgstr "Найкращий _розмір" + +msgid "Zoom To _Fit" +msgstr "Збільшити до _розміру" + +msgid "Grab On _Hover" +msgstr "Захопити при _наведенні" + +msgid "_Grab Input" +msgstr "Захопити _введення" + +msgid "Show _Tabs" +msgstr "Показувати _вкладки" + +msgid "Detach Tab" +msgstr "Відʼєднати вкладку" + +msgid "Show Menubar" +msgstr "Показувати рядок меню" + +msgid "_Machine" +msgstr "_Машина" + +msgid "_View" +msgstr "_Вигляд" diff --git a/python/Makefile b/python/Makefile index 333431136257..b170708398ab 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/README.rst b/python/README.rst index fcf74f69eae0..9c1fceaee73b 100644 --- a/python/README.rst +++ b/python/README.rst @@ -59,7 +59,7 @@ Package installation also normally provides executable console scripts, so that tools like ``qmp-shell`` are always available via $PATH. To invoke them without installation, you can invoke e.g.: -``> PYTHONPATH=~/src/qemu/python python3 -m qemu.aqmp.qmp_shell`` +``> PYTHONPATH=~/src/qemu/python python3 -m qemu.qmp.qmp_shell`` The mappings between console script name and python module path can be found in ``setup.cfg``. diff --git a/python/qemu/aqmp/__init__.py b/python/qemu/aqmp/__init__.py deleted file mode 100644 index 4c22c380790f..000000000000 --- a/python/qemu/aqmp/__init__.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -QEMU Monitor Protocol (QMP) development library & tooling. - -This package provides a fairly low-level class for communicating -asynchronously with QMP protocol servers, as implemented by QEMU, the -QEMU Guest Agent, and the QEMU Storage Daemon. - -`QMPClient` provides the main functionality of this package. All errors -raised by this library derive from `QMPError`, see `aqmp.error` for -additional detail. See `aqmp.events` for an in-depth tutorial on -managing QMP events. -""" - -# Copyright (C) 2020, 2021 John Snow for Red Hat, Inc. -# -# Authors: -# John Snow -# -# Based on earlier work by Luiz Capitulino . -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -import logging - -from .error import QMPError -from .events import EventListener -from .message import Message -from .protocol import ( - ConnectError, - Runstate, - SocketAddrT, - StateError, -) -from .qmp_client import ExecInterruptedError, ExecuteError, QMPClient - - -# Suppress logging unless an application engages it. -logging.getLogger('qemu.aqmp').addHandler(logging.NullHandler()) - - -# The order of these fields impact the Sphinx documentation order. -__all__ = ( - # Classes, most to least important - 'QMPClient', - 'Message', - 'EventListener', - 'Runstate', - - # Exceptions, most generic to most explicit - 'QMPError', - 'StateError', - 'ConnectError', - 'ExecuteError', - 'ExecInterruptedError', - - # Type aliases - 'SocketAddrT', -) diff --git a/python/qemu/aqmp/aqmp_tui.py b/python/qemu/aqmp/aqmp_tui.py deleted file mode 100644 index f1e926dd7565..000000000000 --- a/python/qemu/aqmp/aqmp_tui.py +++ /dev/null @@ -1,653 +0,0 @@ -# Copyright (c) 2021 -# -# Authors: -# Niteesh Babu G S -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. -""" -AQMP TUI - -AQMP TUI is an asynchronous interface built on top the of the AQMP library. -It is the successor of QMP-shell and is bought-in as a replacement for it. - -Example Usage: aqmp-tui -Full Usage: aqmp-tui --help -""" - -import argparse -import asyncio -import json -import logging -from logging import Handler, LogRecord -import signal -from typing import ( - List, - Optional, - Tuple, - Type, - Union, - cast, -) - -from pygments import lexers -from pygments import token as Token -import urwid -import urwid_readline - -from qemu.qmp import QEMUMonitorProtocol, QMPBadPortError - -from .error import ProtocolError -from .message import DeserializationError, Message, UnexpectedTypeError -from .protocol import ConnectError, Runstate -from .qmp_client import ExecInterruptedError, QMPClient -from .util import create_task, pretty_traceback - - -# The name of the signal that is used to update the history list -UPDATE_MSG: str = 'UPDATE_MSG' - - -palette = [ - (Token.Punctuation, '', '', '', 'h15,bold', 'g7'), - (Token.Text, '', '', '', '', 'g7'), - (Token.Name.Tag, '', '', '', 'bold,#f88', 'g7'), - (Token.Literal.Number.Integer, '', '', '', '#fa0', 'g7'), - (Token.Literal.String.Double, '', '', '', '#6f6', 'g7'), - (Token.Keyword.Constant, '', '', '', '#6af', 'g7'), - ('DEBUG', '', '', '', '#ddf', 'g7'), - ('INFO', '', '', '', 'g100', 'g7'), - ('WARNING', '', '', '', '#ff6', 'g7'), - ('ERROR', '', '', '', '#a00', 'g7'), - ('CRITICAL', '', '', '', '#a00', 'g7'), - ('background', '', 'black', '', '', 'g7'), -] - - -def format_json(msg: str) -> str: - """ - Formats valid/invalid multi-line JSON message into a single-line message. - - Formatting is first tried using the standard json module. If that fails - due to an decoding error then a simple string manipulation is done to - achieve a single line JSON string. - - Converting into single line is more asthetically pleasing when looking - along with error messages. - - Eg: - Input: - [ 1, - true, - 3 ] - The above input is not a valid QMP message and produces the following error - "QMP message is not a JSON object." - When displaying this in TUI in multiline mode we get - - [ 1, - true, - 3 ]: QMP message is not a JSON object. - - whereas in singleline mode we get the following - - [1, true, 3]: QMP message is not a JSON object. - - The single line mode is more asthetically pleasing. - - :param msg: - The message to formatted into single line. - - :return: Formatted singleline message. - """ - try: - msg = json.loads(msg) - return str(json.dumps(msg)) - except json.decoder.JSONDecodeError: - msg = msg.replace('\n', '') - words = msg.split(' ') - words = list(filter(None, words)) - return ' '.join(words) - - -def has_handler_type(logger: logging.Logger, - handler_type: Type[Handler]) -> bool: - """ - The Logger class has no interface to check if a certain type of handler is - installed or not. So we provide an interface to do so. - - :param logger: - Logger object - :param handler_type: - The type of the handler to be checked. - - :return: returns True if handler of type `handler_type`. - """ - for handler in logger.handlers: - if isinstance(handler, handler_type): - return True - return False - - -class App(QMPClient): - """ - Implements the AQMP TUI. - - Initializes the widgets and starts the urwid event loop. - - :param address: - Address of the server to connect to. - :param num_retries: - The number of times to retry before stopping to reconnect. - :param retry_delay: - The delay(sec) before each retry - """ - def __init__(self, address: Union[str, Tuple[str, int]], num_retries: int, - retry_delay: Optional[int]) -> None: - urwid.register_signal(type(self), UPDATE_MSG) - self.window = Window(self) - self.address = address - self.aloop: Optional[asyncio.AbstractEventLoop] = None - self.num_retries = num_retries - self.retry_delay = retry_delay if retry_delay else 2 - self.retry: bool = False - self.exiting: bool = False - super().__init__() - - def add_to_history(self, msg: str, level: Optional[str] = None) -> None: - """ - Appends the msg to the history list. - - :param msg: - The raw message to be appended in string type. - """ - urwid.emit_signal(self, UPDATE_MSG, msg, level) - - def _cb_outbound(self, msg: Message) -> Message: - """ - Callback: outbound message hook. - - Appends the outgoing messages to the history box. - - :param msg: raw outbound message. - :return: final outbound message. - """ - str_msg = str(msg) - - if not has_handler_type(logging.getLogger(), TUILogHandler): - logging.debug('Request: %s', str_msg) - self.add_to_history('<-- ' + str_msg) - return msg - - def _cb_inbound(self, msg: Message) -> Message: - """ - Callback: outbound message hook. - - Appends the incoming messages to the history box. - - :param msg: raw inbound message. - :return: final inbound message. - """ - str_msg = str(msg) - - if not has_handler_type(logging.getLogger(), TUILogHandler): - logging.debug('Request: %s', str_msg) - self.add_to_history('--> ' + str_msg) - return msg - - async def _send_to_server(self, msg: Message) -> None: - """ - This coroutine sends the message to the server. - The message has to be pre-validated. - - :param msg: - Pre-validated message to be to sent to the server. - - :raise Exception: When an unhandled exception is caught. - """ - try: - await self._raw(msg, assign_id='id' not in msg) - except ExecInterruptedError as err: - logging.info('Error server disconnected before reply %s', str(err)) - self.add_to_history('Server disconnected before reply', 'ERROR') - except Exception as err: - logging.error('Exception from _send_to_server: %s', str(err)) - raise err - - def cb_send_to_server(self, raw_msg: str) -> None: - """ - Validates and sends the message to the server. - The raw string message is first converted into a Message object - and is then sent to the server. - - :param raw_msg: - The raw string message to be sent to the server. - - :raise Exception: When an unhandled exception is caught. - """ - try: - msg = Message(bytes(raw_msg, encoding='utf-8')) - create_task(self._send_to_server(msg)) - except (DeserializationError, UnexpectedTypeError) as err: - raw_msg = format_json(raw_msg) - logging.info('Invalid message: %s', err.error_message) - self.add_to_history(f'{raw_msg}: {err.error_message}', 'ERROR') - - def unhandled_input(self, key: str) -> None: - """ - Handle's keys which haven't been handled by the child widgets. - - :param key: - Unhandled key - """ - if key == 'esc': - self.kill_app() - - def kill_app(self) -> None: - """ - Initiates killing of app. A bridge between asynchronous and synchronous - code. - """ - create_task(self._kill_app()) - - async def _kill_app(self) -> None: - """ - This coroutine initiates the actual disconnect process and calls - urwid.ExitMainLoop() to kill the TUI. - - :raise Exception: When an unhandled exception is caught. - """ - self.exiting = True - await self.disconnect() - logging.debug('Disconnect finished. Exiting app') - raise urwid.ExitMainLoop() - - async def disconnect(self) -> None: - """ - Overrides the disconnect method to handle the errors locally. - """ - try: - await super().disconnect() - except (OSError, EOFError) as err: - logging.info('disconnect: %s', str(err)) - self.retry = True - except ProtocolError as err: - logging.info('disconnect: %s', str(err)) - except Exception as err: - logging.error('disconnect: Unhandled exception %s', str(err)) - raise err - - def _set_status(self, msg: str) -> None: - """ - Sets the message as the status. - - :param msg: - The message to be displayed in the status bar. - """ - self.window.footer.set_text(msg) - - def _get_formatted_address(self) -> str: - """ - Returns a formatted version of the server's address. - - :return: formatted address - """ - if isinstance(self.address, tuple): - host, port = self.address - addr = f'{host}:{port}' - else: - addr = f'{self.address}' - return addr - - async def _initiate_connection(self) -> Optional[ConnectError]: - """ - Tries connecting to a server a number of times with a delay between - each try. If all retries failed then return the error faced during - the last retry. - - :return: Error faced during last retry. - """ - current_retries = 0 - err = None - - # initial try - await self.connect_server() - while self.retry and current_retries < self.num_retries: - logging.info('Connection Failed, retrying in %d', self.retry_delay) - status = f'[Retry #{current_retries} ({self.retry_delay}s)]' - self._set_status(status) - - await asyncio.sleep(self.retry_delay) - - err = await self.connect_server() - current_retries += 1 - # If all retries failed report the last error - if err: - logging.info('All retries failed: %s', err) - return err - return None - - async def manage_connection(self) -> None: - """ - Manage the connection based on the current run state. - - A reconnect is issued when the current state is IDLE and the number - of retries is not exhausted. - A disconnect is issued when the current state is DISCONNECTING. - """ - while not self.exiting: - if self.runstate == Runstate.IDLE: - err = await self._initiate_connection() - # If retry is still true then, we have exhausted all our tries. - if err: - self._set_status(f'[Error: {err.error_message}]') - else: - addr = self._get_formatted_address() - self._set_status(f'[Connected {addr}]') - elif self.runstate == Runstate.DISCONNECTING: - self._set_status('[Disconnected]') - await self.disconnect() - # check if a retry is needed - if self.runstate == Runstate.IDLE: - continue - await self.runstate_changed() - - async def connect_server(self) -> Optional[ConnectError]: - """ - Initiates a connection to the server at address `self.address` - and in case of a failure, sets the status to the respective error. - """ - try: - await self.connect(self.address) - self.retry = False - except ConnectError as err: - logging.info('connect_server: ConnectError %s', str(err)) - self.retry = True - return err - return None - - def run(self, debug: bool = False) -> None: - """ - Starts the long running co-routines and the urwid event loop. - - :param debug: - Enables/Disables asyncio event loop debugging - """ - screen = urwid.raw_display.Screen() - screen.set_terminal_properties(256) - - self.aloop = asyncio.get_event_loop() - self.aloop.set_debug(debug) - - # Gracefully handle SIGTERM and SIGINT signals - cancel_signals = [signal.SIGTERM, signal.SIGINT] - for sig in cancel_signals: - self.aloop.add_signal_handler(sig, self.kill_app) - - event_loop = urwid.AsyncioEventLoop(loop=self.aloop) - main_loop = urwid.MainLoop(urwid.AttrMap(self.window, 'background'), - unhandled_input=self.unhandled_input, - screen=screen, - palette=palette, - handle_mouse=True, - event_loop=event_loop) - - create_task(self.manage_connection(), self.aloop) - try: - main_loop.run() - except Exception as err: - logging.error('%s\n%s\n', str(err), pretty_traceback()) - raise err - - -class StatusBar(urwid.Text): - """ - A simple statusbar modelled using the Text widget. The status can be - set using the set_text function. All text set is aligned to right. - - :param text: Initial text to be displayed. Default is empty str. - """ - def __init__(self, text: str = ''): - super().__init__(text, align='right') - - -class Editor(urwid_readline.ReadlineEdit): - """ - A simple editor modelled using the urwid_readline.ReadlineEdit widget. - Mimcs GNU readline shortcuts and provides history support. - - The readline shortcuts can be found below: - https://github.com/rr-/urwid_readline#features - - Along with the readline features, this editor also has support for - history. Pressing the 'up'/'down' switches between the prev/next messages - available in the history. - - Currently there is no support to save the history to a file. The history of - previous commands is lost on exit. - - :param parent: Reference to the TUI object. - """ - def __init__(self, parent: App) -> None: - super().__init__(caption='> ', multiline=True) - self.parent = parent - self.history: List[str] = [] - self.last_index: int = -1 - self.show_history: bool = False - - def keypress(self, size: Tuple[int, int], key: str) -> Optional[str]: - """ - Handles the keypress on this widget. - - :param size: - The current size of the widget. - :param key: - The key to be handled. - - :return: Unhandled key if any. - """ - msg = self.get_edit_text() - if key == 'up' and not msg: - # Show the history when 'up arrow' is pressed with no input text. - # NOTE: The show_history logic is necessary because in 'multiline' - # mode (which we use) 'up arrow' is used to move between lines. - if not self.history: - return None - self.show_history = True - last_msg = self.history[self.last_index] - self.set_edit_text(last_msg) - self.edit_pos = len(last_msg) - elif key == 'up' and self.show_history: - self.last_index = max(self.last_index - 1, -len(self.history)) - self.set_edit_text(self.history[self.last_index]) - self.edit_pos = len(self.history[self.last_index]) - elif key == 'down' and self.show_history: - if self.last_index == -1: - self.set_edit_text('') - self.show_history = False - else: - self.last_index += 1 - self.set_edit_text(self.history[self.last_index]) - self.edit_pos = len(self.history[self.last_index]) - elif key == 'meta enter': - # When using multiline, enter inserts a new line into the editor - # send the input to the server on alt + enter - self.parent.cb_send_to_server(msg) - self.history.append(msg) - self.set_edit_text('') - self.last_index = -1 - self.show_history = False - else: - self.show_history = False - self.last_index = -1 - return cast(Optional[str], super().keypress(size, key)) - return None - - -class EditorWidget(urwid.Filler): - """ - Wrapper around the editor widget. - - The Editor is a flow widget and has to wrapped inside a box widget. - This class wraps the Editor inside filler widget. - - :param parent: Reference to the TUI object. - """ - def __init__(self, parent: App) -> None: - super().__init__(Editor(parent), valign='top') - - -class HistoryBox(urwid.ListBox): - """ - This widget is modelled using the ListBox widget, contains the list of - all messages both QMP messages and log messsages to be shown in the TUI. - - The messages are urwid.Text widgets. On every append of a message, the - focus is shifted to the last appended message. - - :param parent: Reference to the TUI object. - """ - def __init__(self, parent: App) -> None: - self.parent = parent - self.history = urwid.SimpleFocusListWalker([]) - super().__init__(self.history) - - def add_to_history(self, - history: Union[str, List[Tuple[str, str]]]) -> None: - """ - Appends a message to the list and set the focus to the last appended - message. - - :param history: - The history item(message/event) to be appended to the list. - """ - self.history.append(urwid.Text(history)) - self.history.set_focus(len(self.history) - 1) - - def mouse_event(self, size: Tuple[int, int], _event: str, button: float, - _x: int, _y: int, focus: bool) -> None: - # Unfortunately there are no urwid constants that represent the mouse - # events. - if button == 4: # Scroll up event - super().keypress(size, 'up') - elif button == 5: # Scroll down event - super().keypress(size, 'down') - - -class HistoryWindow(urwid.Frame): - """ - This window composes the HistoryBox and EditorWidget in a horizontal split. - By default the first focus is given to the history box. - - :param parent: Reference to the TUI object. - """ - def __init__(self, parent: App) -> None: - self.parent = parent - self.editor_widget = EditorWidget(parent) - self.editor = urwid.LineBox(self.editor_widget) - self.history = HistoryBox(parent) - self.body = urwid.Pile([('weight', 80, self.history), - ('weight', 20, self.editor)]) - super().__init__(self.body) - urwid.connect_signal(self.parent, UPDATE_MSG, self.cb_add_to_history) - - def cb_add_to_history(self, msg: str, level: Optional[str] = None) -> None: - """ - Appends a message to the history box - - :param msg: - The message to be appended to the history box. - :param level: - The log level of the message, if it is a log message. - """ - formatted = [] - if level: - msg = f'[{level}]: {msg}' - formatted.append((level, msg)) - else: - lexer = lexers.JsonLexer() # pylint: disable=no-member - for token in lexer.get_tokens(msg): - formatted.append(token) - self.history.add_to_history(formatted) - - -class Window(urwid.Frame): - """ - This window is the top most widget of the TUI and will contain other - windows. Each child of this widget is responsible for displaying a specific - functionality. - - :param parent: Reference to the TUI object. - """ - def __init__(self, parent: App) -> None: - self.parent = parent - footer = StatusBar() - body = HistoryWindow(parent) - super().__init__(body, footer=footer) - - -class TUILogHandler(Handler): - """ - This handler routes all the log messages to the TUI screen. - It is installed to the root logger to so that the log message from all - libraries begin used is routed to the screen. - - :param tui: Reference to the TUI object. - """ - def __init__(self, tui: App) -> None: - super().__init__() - self.tui = tui - - def emit(self, record: LogRecord) -> None: - """ - Emits a record to the TUI screen. - - Appends the log message to the TUI screen - """ - level = record.levelname - msg = record.getMessage() - self.tui.add_to_history(msg, level) - - -def main() -> None: - """ - Driver of the whole script, parses arguments, initialize the TUI and - the logger. - """ - parser = argparse.ArgumentParser(description='AQMP TUI') - parser.add_argument('qmp_server', help='Address of the QMP server. ' - 'Format ') - parser.add_argument('--num-retries', type=int, default=10, - help='Number of times to reconnect before giving up.') - parser.add_argument('--retry-delay', type=int, - help='Time(s) to wait before next retry. ' - 'Default action is to wait 2s between each retry.') - parser.add_argument('--log-file', help='The Log file name') - parser.add_argument('--log-level', default='WARNING', - help='Log level ') - parser.add_argument('--asyncio-debug', action='store_true', - help='Enable debug mode for asyncio loop. ' - 'Generates lot of output, makes TUI unusable when ' - 'logs are logged in the TUI. ' - 'Use only when logging to a file.') - args = parser.parse_args() - - try: - address = QEMUMonitorProtocol.parse_address(args.qmp_server) - except QMPBadPortError as err: - parser.error(str(err)) - - app = App(address, args.num_retries, args.retry_delay) - - root_logger = logging.getLogger() - root_logger.setLevel(logging.getLevelName(args.log_level)) - - if args.log_file: - root_logger.addHandler(logging.FileHandler(args.log_file)) - else: - root_logger.addHandler(TUILogHandler(app)) - - app.run(args.asyncio_debug) - - -if __name__ == '__main__': - main() diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py deleted file mode 100644 index 46026e9fdc6c..000000000000 --- a/python/qemu/aqmp/legacy.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -Sync QMP Wrapper - -This class pretends to be qemu.qmp.QEMUMonitorProtocol. -""" - -import asyncio -from typing import ( - Any, - Awaitable, - Dict, - List, - Optional, - TypeVar, - Union, -) - -import qemu.qmp - -from .error import QMPError -from .protocol import Runstate, SocketAddrT -from .qmp_client import QMPClient - - -# (Temporarily) Re-export QMPBadPortError -QMPBadPortError = qemu.qmp.QMPBadPortError - -#: QMPMessage is an entire QMP message of any kind. -QMPMessage = Dict[str, Any] - -#: QMPReturnValue is the 'return' value of a command. -QMPReturnValue = object - -#: QMPObject is any object in a QMP message. -QMPObject = Dict[str, object] - -# QMPMessage can be outgoing commands or incoming events/returns. -# QMPReturnValue is usually a dict/json object, but due to QAPI's -# 'returns-whitelist', it can actually be anything. -# -# {'return': {}} is a QMPMessage, -# {} is the QMPReturnValue. - - -# pylint: disable=missing-docstring - - -class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol): - def __init__(self, address: SocketAddrT, - server: bool = False, - nickname: Optional[str] = None): - - # pylint: disable=super-init-not-called - self._aqmp = QMPClient(nickname) - self._aloop = asyncio.get_event_loop() - self._address = address - self._timeout: Optional[float] = None - - if server: - self._sync(self._aqmp.start_server(self._address)) - - _T = TypeVar('_T') - - def _sync( - self, future: Awaitable[_T], timeout: Optional[float] = None - ) -> _T: - return self._aloop.run_until_complete( - asyncio.wait_for(future, timeout=timeout) - ) - - def _get_greeting(self) -> Optional[QMPMessage]: - if self._aqmp.greeting is not None: - # pylint: disable=protected-access - return self._aqmp.greeting._asdict() - return None - - # __enter__ and __exit__ need no changes - # parse_address needs no changes - - def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: - self._aqmp.await_greeting = negotiate - self._aqmp.negotiate = negotiate - - self._sync( - self._aqmp.connect(self._address) - ) - return self._get_greeting() - - def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage: - self._aqmp.await_greeting = True - self._aqmp.negotiate = True - - self._sync(self._aqmp.accept(), timeout) - - ret = self._get_greeting() - assert ret is not None - return ret - - def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage: - return dict( - self._sync( - # pylint: disable=protected-access - - # _raw() isn't a public API, because turning off - # automatic ID assignment is discouraged. For - # compatibility with iotests *only*, do it anyway. - self._aqmp._raw(qmp_cmd, assign_id=False), - self._timeout - ) - ) - - # Default impl of cmd() delegates to cmd_obj - - def command(self, cmd: str, **kwds: object) -> QMPReturnValue: - return self._sync( - self._aqmp.execute(cmd, kwds), - self._timeout - ) - - def pull_event(self, - wait: Union[bool, float] = False) -> Optional[QMPMessage]: - if not wait: - # wait is False/0: "do not wait, do not except." - if self._aqmp.events.empty(): - return None - - # If wait is 'True', wait forever. If wait is False/0, the events - # queue must not be empty; but it still needs some real amount - # of time to complete. - timeout = None - if wait and isinstance(wait, float): - timeout = wait - - return dict( - self._sync( - self._aqmp.events.get(), - timeout - ) - ) - - def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]: - events = [dict(x) for x in self._aqmp.events.clear()] - if events: - return events - - event = self.pull_event(wait) - return [event] if event is not None else [] - - def clear_events(self) -> None: - self._aqmp.events.clear() - - def close(self) -> None: - self._sync( - self._aqmp.disconnect() - ) - - def settimeout(self, timeout: Optional[float]) -> None: - self._timeout = timeout - - def send_fd_scm(self, fd: int) -> None: - self._aqmp.send_fd_scm(fd) - - def __del__(self) -> None: - if self._aqmp.runstate == Runstate.IDLE: - return - - if not self._aloop.is_running(): - self.close() - else: - # Garbage collection ran while the event loop was running. - # Nothing we can do about it now, but if we don't raise our - # own error, the user will be treated to a lot of traceback - # they might not understand. - raise QMPError( - "QEMUMonitorProtocol.close()" - " was not called before object was garbage collected" - ) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index a5972fab4d2b..748a0d807c9d 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -40,21 +40,16 @@ TypeVar, ) -from qemu.qmp import ( # pylint: disable=import-error +from qemu.qmp import SocketAddrT +from qemu.qmp.legacy import ( + QEMUMonitorProtocol, QMPMessage, QMPReturnValue, - SocketAddrT, ) from . import console_socket -if os.environ.get('QEMU_PYTHON_LEGACY_QMP'): - from qemu.qmp import QEMUMonitorProtocol -else: - from qemu.aqmp.legacy import QEMUMonitorProtocol - - LOG = logging.getLogger(__name__) @@ -378,6 +373,7 @@ def _post_shutdown(self) -> None: Called to cleanup the VM instance after the process has exited. May also be called after a failed launch. """ + LOG.debug("Cleaning up after VM process") try: self._close_qmp_connection() except Exception as err: # pylint: disable=broad-except @@ -500,8 +496,9 @@ def _early_cleanup(self) -> None: """ # If we keep the console socket open, we may deadlock waiting # for QEMU to exit, while QEMU is waiting for the socket to - # become writeable. + # become writable. if self._console_socket is not None: + LOG.debug("Closing console socket") self._console_socket.close() self._console_socket = None @@ -512,6 +509,7 @@ def _hard_shutdown(self) -> None: :raise subprocess.Timeout: When timeout is exceeds 60 seconds waiting for the QEMU process to terminate. """ + LOG.debug("Performing hard shutdown") self._early_cleanup() self._subp.kill() self._subp.wait(timeout=60) @@ -528,8 +526,18 @@ def _soft_shutdown(self, timeout: Optional[int]) -> None: :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for the QEMU process to terminate. """ + LOG.debug("Attempting graceful termination") + self._early_cleanup() + if self._quit_issued: + LOG.debug( + "Anticipating QEMU termination due to prior 'quit' command, " + "or explicit call to wait()" + ) + else: + LOG.debug("Politely asking QEMU to terminate") + if self._qmp_connection: try: if not self._quit_issued: @@ -539,8 +547,18 @@ def _soft_shutdown(self, timeout: Optional[int]) -> None: finally: # Regardless, we want to quiesce the connection. self._close_qmp_connection() + elif not self._quit_issued: + LOG.debug( + "Not anticipating QEMU quit and no QMP connection present, " + "issuing SIGTERM" + ) + self._subp.terminate() # May raise subprocess.TimeoutExpired + LOG.debug( + "Waiting (timeout=%s) for QEMU process (pid=%s) to terminate", + timeout, self._subp.pid + ) self._subp.wait(timeout=timeout) def _do_shutdown(self, timeout: Optional[int]) -> None: @@ -558,6 +576,10 @@ def _do_shutdown(self, timeout: Optional[int]) -> None: try: self._soft_shutdown(timeout) except Exception as exc: + if isinstance(exc, subprocess.TimeoutExpired): + LOG.debug("Timed out waiting for QEMU process to exit") + LOG.debug("Graceful shutdown failed", exc_info=True) + LOG.debug("Falling back to hard shutdown") self._hard_shutdown() raise AbnormalShutdown("Could not perform graceful shutdown") \ from exc @@ -580,6 +602,10 @@ def shutdown(self, if not self._launched: return + LOG.debug("Shutting down VM appliance; timeout=%s", timeout) + if hard: + LOG.debug("Caller requests immediate termination of QEMU process.") + try: if hard: self._user_killed = True @@ -743,8 +769,9 @@ def events_wait(self, :param timeout: Optional timeout, in seconds. See QEMUMonitorProtocol.pull_event. - :raise QMPTimeoutError: If timeout was non-zero and no matching events - were found. + :raise asyncio.TimeoutError: + If timeout was non-zero and no matching events were found. + :return: A QMP event matching the filter criteria. If timeout was 0 and no event matched, None. """ @@ -767,7 +794,7 @@ def _match(event: QMPMessage) -> bool: event = self._qmp.pull_event(wait=timeout) if event is None: # NB: None is only returned when timeout is false-ish. - # Timeouts raise QMPTimeoutError instead! + # Timeouts raise asyncio.TimeoutError instead! break if _match(event): return event diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py index f2f9aaa5e500..1a1fc6c9b08e 100644 --- a/python/qemu/machine/qtest.py +++ b/python/qemu/machine/qtest.py @@ -26,7 +26,7 @@ TextIO, ) -from qemu.qmp import SocketAddrT # pylint: disable=import-error +from qemu.qmp import SocketAddrT from .machine import QEMUMachine diff --git a/python/qemu/qmp/README.rst b/python/qemu/qmp/README.rst deleted file mode 100644 index 5bfb82535f8e..000000000000 --- a/python/qemu/qmp/README.rst +++ /dev/null @@ -1,9 +0,0 @@ -qemu.qmp package -================ - -This package provides a library used for connecting to and communicating -with QMP servers. It is used extensively by iotests, vm tests, -avocado tests, and other utilities in the ./scripts directory. It is -not a fully-fledged SDK and is subject to change at any time. - -See the documentation in ``__init__.py`` for more information. diff --git a/python/qemu/qmp/__init__.py b/python/qemu/qmp/__init__.py index 358c0971d06a..69190d057a5b 100644 --- a/python/qemu/qmp/__init__.py +++ b/python/qemu/qmp/__init__.py @@ -1,422 +1,59 @@ """ QEMU Monitor Protocol (QMP) development library & tooling. -This package provides a fairly low-level class for communicating to QMP -protocol servers, as implemented by QEMU, the QEMU Guest Agent, and the -QEMU Storage Daemon. This library is not intended for production use. - -`QEMUMonitorProtocol` is the primary class of interest, and all errors -raised derive from `QMPError`. +This package provides a fairly low-level class for communicating +asynchronously with QMP protocol servers, as implemented by QEMU, the +QEMU Guest Agent, and the QEMU Storage Daemon. + +`QMPClient` provides the main functionality of this package. All errors +raised by this library derive from `QMPError`, see `qmp.error` for +additional detail. See `qmp.events` for an in-depth tutorial on +managing QMP events. """ -# Copyright (C) 2009, 2010 Red Hat Inc. +# Copyright (C) 2020-2022 John Snow for Red Hat, Inc. # # Authors: -# Luiz Capitulino +# John Snow # -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -import errno -import json -import logging -import socket -import struct -from types import TracebackType -from typing import ( - Any, - Dict, - List, - Optional, - TextIO, - Tuple, - Type, - TypeVar, - Union, - cast, -) - - -#: QMPMessage is an entire QMP message of any kind. -QMPMessage = Dict[str, Any] - -#: QMPReturnValue is the 'return' value of a command. -QMPReturnValue = object - -#: QMPObject is any object in a QMP message. -QMPObject = Dict[str, object] - -# QMPMessage can be outgoing commands or incoming events/returns. -# QMPReturnValue is usually a dict/json object, but due to QAPI's -# 'returns-whitelist', it can actually be anything. +# Based on earlier work by Luiz Capitulino . # -# {'return': {}} is a QMPMessage, -# {} is the QMPReturnValue. - - -InternetAddrT = Tuple[str, int] -UnixAddrT = str -SocketAddrT = Union[InternetAddrT, UnixAddrT] - - -class QMPError(Exception): - """ - QMP base exception - """ - - -class QMPConnectError(QMPError): - """ - QMP connection exception - """ - - -class QMPCapabilitiesError(QMPError): - """ - QMP negotiate capabilities exception - """ - - -class QMPTimeoutError(QMPError): - """ - QMP timeout exception - """ - - -class QMPProtocolError(QMPError): - """ - QMP protocol error; unexpected response - """ - - -class QMPResponseError(QMPError): - """ - Represents erroneous QMP monitor reply - """ - def __init__(self, reply: QMPMessage): - try: - desc = reply['error']['desc'] - except KeyError: - desc = reply - super().__init__(desc) - self.reply = reply - - -class QMPBadPortError(QMPError): - """ - Unable to parse socket address: Port was non-numerical. - """ - - -class QEMUMonitorProtocol: - """ - Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) and then - allow to handle commands and events. - """ - - #: Logger object for debugging messages - logger = logging.getLogger('QMP') - - def __init__(self, address: SocketAddrT, - server: bool = False, - nickname: Optional[str] = None): - """ - Create a QEMUMonitorProtocol class. - - @param address: QEMU address, can be either a unix socket path (string) - or a tuple in the form ( address, port ) for a TCP - connection - @param server: server mode listens on the socket (bool) - @raise OSError on socket connection errors - @note No connection is established, this is done by the connect() or - accept() methods - """ - self.__events: List[QMPMessage] = [] - self.__address = address - self.__sock = self.__get_sock() - self.__sockfile: Optional[TextIO] = None - self._nickname = nickname - if self._nickname: - self.logger = logging.getLogger('QMP').getChild(self._nickname) - if server: - self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.__sock.bind(self.__address) - self.__sock.listen(1) - - def __get_sock(self) -> socket.socket: - if isinstance(self.__address, tuple): - family = socket.AF_INET - else: - family = socket.AF_UNIX - return socket.socket(family, socket.SOCK_STREAM) - - def __negotiate_capabilities(self) -> QMPMessage: - greeting = self.__json_read() - if greeting is None or "QMP" not in greeting: - raise QMPConnectError - # Greeting seems ok, negotiate capabilities - resp = self.cmd('qmp_capabilities') - if resp and "return" in resp: - return greeting - raise QMPCapabilitiesError - - def __json_read(self, only_event: bool = False) -> Optional[QMPMessage]: - assert self.__sockfile is not None - while True: - data = self.__sockfile.readline() - if not data: - return None - # By definition, any JSON received from QMP is a QMPMessage, - # and we are asserting only at static analysis time that it - # has a particular shape. - resp: QMPMessage = json.loads(data) - if 'event' in resp: - self.logger.debug("<<< %s", resp) - self.__events.append(resp) - if not only_event: - continue - return resp - - def __get_events(self, wait: Union[bool, float] = False) -> None: - """ - Check for new events in the stream and cache them in __events. +# This work is licensed under the terms of the GNU LGPL, version 2 or +# later. See the COPYING file in the top-level directory. - @param wait (bool): block until an event is available. - @param wait (float): If wait is a float, treat it as a timeout value. - - @raise QMPTimeoutError: If a timeout float is provided and the timeout - period elapses. - @raise QMPConnectError: If wait is True but no events could be - retrieved or if some other error occurred. - """ - - # Current timeout and blocking status - current_timeout = self.__sock.gettimeout() - - # Check for new events regardless and pull them into the cache: - self.__sock.settimeout(0) # i.e. setblocking(False) - try: - self.__json_read() - except OSError as err: - # EAGAIN: No data available; not critical - if err.errno != errno.EAGAIN: - raise - finally: - self.__sock.settimeout(current_timeout) - - # Wait for new events, if needed. - # if wait is 0.0, this means "no wait" and is also implicitly false. - if not self.__events and wait: - if isinstance(wait, float): - self.__sock.settimeout(wait) - try: - ret = self.__json_read(only_event=True) - except socket.timeout as err: - raise QMPTimeoutError("Timeout waiting for event") from err - except Exception as err: - msg = "Error while reading from socket" - raise QMPConnectError(msg) from err - finally: - self.__sock.settimeout(current_timeout) - - if ret is None: - raise QMPConnectError("Error while reading from socket") - - T = TypeVar('T') - - def __enter__(self: T) -> T: - # Implement context manager enter function. - return self - - def __exit__(self, - # pylint: disable=duplicate-code - # see https://github.com/PyCQA/pylint/issues/3619 - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType]) -> None: - # Implement context manager exit function. - self.close() - - @classmethod - def parse_address(cls, address: str) -> SocketAddrT: - """ - Parse a string into a QMP address. - - Figure out if the argument is in the port:host form. - If it's not, it's probably a file path. - """ - components = address.split(':') - if len(components) == 2: - try: - port = int(components[1]) - except ValueError: - msg = f"Bad port: '{components[1]}' in '{address}'." - raise QMPBadPortError(msg) from None - return (components[0], port) - - # Treat as filepath. - return address - - def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: - """ - Connect to the QMP Monitor and perform capabilities negotiation. - - @return QMP greeting dict, or None if negotiate is false - @raise OSError on socket connection errors - @raise QMPConnectError if the greeting is not received - @raise QMPCapabilitiesError if fails to negotiate capabilities - """ - self.__sock.connect(self.__address) - self.__sockfile = self.__sock.makefile(mode='r') - if negotiate: - return self.__negotiate_capabilities() - return None - - def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage: - """ - Await connection from QMP Monitor and perform capabilities negotiation. - - @param timeout: timeout in seconds (nonnegative float number, or - None). The value passed will set the behavior of the - underneath QMP socket as described in [1]. - Default value is set to 15.0. - - @return QMP greeting dict - @raise OSError on socket connection errors - @raise QMPConnectError if the greeting is not received - @raise QMPCapabilitiesError if fails to negotiate capabilities - - [1] - https://docs.python.org/3/library/socket.html#socket.socket.settimeout - """ - self.__sock.settimeout(timeout) - self.__sock, _ = self.__sock.accept() - self.__sockfile = self.__sock.makefile(mode='r') - return self.__negotiate_capabilities() - - def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage: - """ - Send a QMP command to the QMP Monitor. - - @param qmp_cmd: QMP command to be sent as a Python dict - @return QMP response as a Python dict - """ - self.logger.debug(">>> %s", qmp_cmd) - self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8')) - resp = self.__json_read() - if resp is None: - raise QMPConnectError("Unexpected empty reply from server") - self.logger.debug("<<< %s", resp) - return resp - - def cmd(self, name: str, - args: Optional[Dict[str, object]] = None, - cmd_id: Optional[object] = None) -> QMPMessage: - """ - Build a QMP command and send it to the QMP Monitor. - - @param name: command name (string) - @param args: command arguments (dict) - @param cmd_id: command id (dict, list, string or int) - """ - qmp_cmd: QMPMessage = {'execute': name} - if args: - qmp_cmd['arguments'] = args - if cmd_id: - qmp_cmd['id'] = cmd_id - return self.cmd_obj(qmp_cmd) - - def command(self, cmd: str, **kwds: object) -> QMPReturnValue: - """ - Build and send a QMP command to the monitor, report errors if any - """ - ret = self.cmd(cmd, kwds) - if 'error' in ret: - raise QMPResponseError(ret) - if 'return' not in ret: - raise QMPProtocolError( - "'return' key not found in QMP response '{}'".format(str(ret)) - ) - return cast(QMPReturnValue, ret['return']) - - def pull_event(self, - wait: Union[bool, float] = False) -> Optional[QMPMessage]: - """ - Pulls a single event. - - @param wait (bool): block until an event is available. - @param wait (float): If wait is a float, treat it as a timeout value. - - @raise QMPTimeoutError: If a timeout float is provided and the timeout - period elapses. - @raise QMPConnectError: If wait is True but no events could be - retrieved or if some other error occurred. - - @return The first available QMP event, or None. - """ - self.__get_events(wait) - - if self.__events: - return self.__events.pop(0) - return None - - def get_events(self, wait: bool = False) -> List[QMPMessage]: - """ - Get a list of available QMP events and clear all pending events. - - @param wait (bool): block until an event is available. - @param wait (float): If wait is a float, treat it as a timeout value. - - @raise QMPTimeoutError: If a timeout float is provided and the timeout - period elapses. - @raise QMPConnectError: If wait is True but no events could be - retrieved or if some other error occurred. - - @return The list of available QMP events. - """ - self.__get_events(wait) - events = self.__events - self.__events = [] - return events +import logging - def clear_events(self) -> None: - """ - Clear current list of pending events. - """ - self.__events = [] +from .error import QMPError +from .events import EventListener +from .message import Message +from .protocol import ( + ConnectError, + Runstate, + SocketAddrT, + StateError, +) +from .qmp_client import ExecInterruptedError, ExecuteError, QMPClient - def close(self) -> None: - """ - Close the socket and socket file. - """ - if self.__sock: - self.__sock.close() - if self.__sockfile: - self.__sockfile.close() - def settimeout(self, timeout: Optional[float]) -> None: - """ - Set the socket timeout. +# Suppress logging unless an application engages it. +logging.getLogger('qemu.qmp').addHandler(logging.NullHandler()) - @param timeout (float): timeout in seconds (non-zero), or None. - @note This is a wrap around socket.settimeout - @raise ValueError: if timeout was set to 0. - """ - if timeout == 0: - msg = "timeout cannot be 0; this engages non-blocking mode." - msg += " Use 'None' instead to disable timeouts." - raise ValueError(msg) - self.__sock.settimeout(timeout) +# The order of these fields impact the Sphinx documentation order. +__all__ = ( + # Classes, most to least important + 'QMPClient', + 'Message', + 'EventListener', + 'Runstate', - def send_fd_scm(self, fd: int) -> None: - """ - Send a file descriptor to the remote via SCM_RIGHTS. - """ - if self.__sock.family != socket.AF_UNIX: - raise RuntimeError("Can't use SCM_RIGHTS on non-AF_UNIX socket.") + # Exceptions, most generic to most explicit + 'QMPError', + 'StateError', + 'ConnectError', + 'ExecuteError', + 'ExecInterruptedError', - self.__sock.sendmsg( - [b' '], - [(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack('@i', fd))] - ) + # Type aliases + 'SocketAddrT', +) diff --git a/python/qemu/aqmp/error.py b/python/qemu/qmp/error.py similarity index 100% rename from python/qemu/aqmp/error.py rename to python/qemu/qmp/error.py diff --git a/python/qemu/aqmp/events.py b/python/qemu/qmp/events.py similarity index 99% rename from python/qemu/aqmp/events.py rename to python/qemu/qmp/events.py index f3d4e2b5e853..6199776cc664 100644 --- a/python/qemu/aqmp/events.py +++ b/python/qemu/qmp/events.py @@ -1,5 +1,5 @@ """ -AQMP Events and EventListeners +QMP Events and EventListeners Asynchronous QMP uses `EventListener` objects to listen for events. An `EventListener` is a FIFO event queue that can be pre-filtered to listen diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py new file mode 100644 index 000000000000..1951754455a9 --- /dev/null +++ b/python/qemu/qmp/legacy.py @@ -0,0 +1,315 @@ +""" +(Legacy) Sync QMP Wrapper + +This module provides the `QEMUMonitorProtocol` class, which is a +synchronous wrapper around `QMPClient`. + +Its design closely resembles that of the original QEMUMonitorProtocol +class, originally written by Luiz Capitulino. It is provided here for +compatibility with scripts inside the QEMU source tree that expect the +old interface. +""" + +# +# Copyright (C) 2009-2022 Red Hat Inc. +# +# Authors: +# Luiz Capitulino +# John Snow +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +import asyncio +from types import TracebackType +from typing import ( + Any, + Awaitable, + Dict, + List, + Optional, + Type, + TypeVar, + Union, +) + +from .error import QMPError +from .protocol import Runstate, SocketAddrT +from .qmp_client import QMPClient + + +#: QMPMessage is an entire QMP message of any kind. +QMPMessage = Dict[str, Any] + +#: QMPReturnValue is the 'return' value of a command. +QMPReturnValue = object + +#: QMPObject is any object in a QMP message. +QMPObject = Dict[str, object] + +# QMPMessage can be outgoing commands or incoming events/returns. +# QMPReturnValue is usually a dict/json object, but due to QAPI's +# 'command-returns-exceptions', it can actually be anything. +# +# {'return': {}} is a QMPMessage, +# {} is the QMPReturnValue. + + +class QMPBadPortError(QMPError): + """ + Unable to parse socket address: Port was non-numerical. + """ + + +class QEMUMonitorProtocol: + """ + Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) + and then allow to handle commands and events. + + :param address: QEMU address, can be either a unix socket path (string) + or a tuple in the form ( address, port ) for a TCP + connection + :param server: Act as the socket server. (See 'accept') + :param nickname: Optional nickname used for logging. + """ + + def __init__(self, address: SocketAddrT, + server: bool = False, + nickname: Optional[str] = None): + + self._qmp = QMPClient(nickname) + self._aloop = asyncio.get_event_loop() + self._address = address + self._timeout: Optional[float] = None + + if server: + self._sync(self._qmp.start_server(self._address)) + + _T = TypeVar('_T') + + def _sync( + self, future: Awaitable[_T], timeout: Optional[float] = None + ) -> _T: + return self._aloop.run_until_complete( + asyncio.wait_for(future, timeout=timeout) + ) + + def _get_greeting(self) -> Optional[QMPMessage]: + if self._qmp.greeting is not None: + # pylint: disable=protected-access + return self._qmp.greeting._asdict() + return None + + def __enter__(self: _T) -> _T: + # Implement context manager enter function. + return self + + def __exit__(self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> None: + # Implement context manager exit function. + self.close() + + @classmethod + def parse_address(cls, address: str) -> SocketAddrT: + """ + Parse a string into a QMP address. + + Figure out if the argument is in the port:host form. + If it's not, it's probably a file path. + """ + components = address.split(':') + if len(components) == 2: + try: + port = int(components[1]) + except ValueError: + msg = f"Bad port: '{components[1]}' in '{address}'." + raise QMPBadPortError(msg) from None + return (components[0], port) + + # Treat as filepath. + return address + + def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: + """ + Connect to the QMP Monitor and perform capabilities negotiation. + + :return: QMP greeting dict, or None if negotiate is false + :raise ConnectError: on connection errors + """ + self._qmp.await_greeting = negotiate + self._qmp.negotiate = negotiate + + self._sync( + self._qmp.connect(self._address) + ) + return self._get_greeting() + + def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage: + """ + Await connection from QMP Monitor and perform capabilities negotiation. + + :param timeout: + timeout in seconds (nonnegative float number, or None). + If None, there is no timeout, and this may block forever. + + :return: QMP greeting dict + :raise ConnectError: on connection errors + """ + self._qmp.await_greeting = True + self._qmp.negotiate = True + + self._sync(self._qmp.accept(), timeout) + + ret = self._get_greeting() + assert ret is not None + return ret + + def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage: + """ + Send a QMP command to the QMP Monitor. + + :param qmp_cmd: QMP command to be sent as a Python dict + :return: QMP response as a Python dict + """ + return dict( + self._sync( + # pylint: disable=protected-access + + # _raw() isn't a public API, because turning off + # automatic ID assignment is discouraged. For + # compatibility with iotests *only*, do it anyway. + self._qmp._raw(qmp_cmd, assign_id=False), + self._timeout + ) + ) + + def cmd(self, name: str, + args: Optional[Dict[str, object]] = None, + cmd_id: Optional[object] = None) -> QMPMessage: + """ + Build a QMP command and send it to the QMP Monitor. + + :param name: command name (string) + :param args: command arguments (dict) + :param cmd_id: command id (dict, list, string or int) + """ + qmp_cmd: QMPMessage = {'execute': name} + if args: + qmp_cmd['arguments'] = args + if cmd_id: + qmp_cmd['id'] = cmd_id + return self.cmd_obj(qmp_cmd) + + def command(self, cmd: str, **kwds: object) -> QMPReturnValue: + """ + Build and send a QMP command to the monitor, report errors if any + """ + return self._sync( + self._qmp.execute(cmd, kwds), + self._timeout + ) + + def pull_event(self, + wait: Union[bool, float] = False) -> Optional[QMPMessage]: + """ + Pulls a single event. + + :param wait: + If False or 0, do not wait. Return None if no events ready. + If True, wait forever until the next event. + Otherwise, wait for the specified number of seconds. + + :raise asyncio.TimeoutError: + When a timeout is requested and the timeout period elapses. + + :return: The first available QMP event, or None. + """ + if not wait: + # wait is False/0: "do not wait, do not except." + if self._qmp.events.empty(): + return None + + # If wait is 'True', wait forever. If wait is False/0, the events + # queue must not be empty; but it still needs some real amount + # of time to complete. + timeout = None + if wait and isinstance(wait, float): + timeout = wait + + return dict( + self._sync( + self._qmp.events.get(), + timeout + ) + ) + + def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]: + """ + Get a list of QMP events and clear all pending events. + + :param wait: + If False or 0, do not wait. Return None if no events ready. + If True, wait until we have at least one event. + Otherwise, wait for up to the specified number of seconds for at + least one event. + + :raise asyncio.TimeoutError: + When a timeout is requested and the timeout period elapses. + + :return: A list of QMP events. + """ + events = [dict(x) for x in self._qmp.events.clear()] + if events: + return events + + event = self.pull_event(wait) + return [event] if event is not None else [] + + def clear_events(self) -> None: + """Clear current list of pending events.""" + self._qmp.events.clear() + + def close(self) -> None: + """Close the connection.""" + self._sync( + self._qmp.disconnect() + ) + + def settimeout(self, timeout: Optional[float]) -> None: + """ + Set the timeout for QMP RPC execution. + + This timeout affects the `cmd`, `cmd_obj`, and `command` methods. + The `accept`, `pull_event` and `get_event` methods have their + own configurable timeouts. + + :param timeout: + timeout in seconds, or None. + None will wait indefinitely. + """ + self._timeout = timeout + + def send_fd_scm(self, fd: int) -> None: + """ + Send a file descriptor to the remote via SCM_RIGHTS. + """ + self._qmp.send_fd_scm(fd) + + def __del__(self) -> None: + if self._qmp.runstate == Runstate.IDLE: + return + + if not self._aloop.is_running(): + self.close() + else: + # Garbage collection ran while the event loop was running. + # Nothing we can do about it now, but if we don't raise our + # own error, the user will be treated to a lot of traceback + # they might not understand. + raise QMPError( + "QEMUMonitorProtocol.close()" + " was not called before object was garbage collected" + ) diff --git a/python/qemu/aqmp/message.py b/python/qemu/qmp/message.py similarity index 100% rename from python/qemu/aqmp/message.py rename to python/qemu/qmp/message.py diff --git a/python/qemu/aqmp/models.py b/python/qemu/qmp/models.py similarity index 100% rename from python/qemu/aqmp/models.py rename to python/qemu/qmp/models.py diff --git a/python/qemu/aqmp/protocol.py b/python/qemu/qmp/protocol.py similarity index 99% rename from python/qemu/aqmp/protocol.py rename to python/qemu/qmp/protocol.py index 36fae57f2778..6ea86650ad24 100644 --- a/python/qemu/aqmp/protocol.py +++ b/python/qemu/qmp/protocol.py @@ -196,9 +196,9 @@ class AsyncProtocol(Generic[T]): :param name: Name used for logging messages, if any. By default, messages - will log to 'qemu.aqmp.protocol', but each individual connection + will log to 'qemu.qmp.protocol', but each individual connection can be given its own logger by giving it a name; messages will - then log to 'qemu.aqmp.protocol.${name}'. + then log to 'qemu.qmp.protocol.${name}'. """ # pylint: disable=too-many-instance-attributes diff --git a/python/qemu/aqmp/qmp_client.py b/python/qemu/qmp/qmp_client.py similarity index 97% rename from python/qemu/aqmp/qmp_client.py rename to python/qemu/qmp/qmp_client.py index 90a8737f03a9..5dcda04a7562 100644 --- a/python/qemu/aqmp/qmp_client.py +++ b/python/qemu/qmp/qmp_client.py @@ -192,7 +192,7 @@ async def run(self, address='/tmp/qemu.socket'): await self.qmp.runstate_changed.wait() await self.disconnect() - See `aqmp.events` for more detail on event handling patterns. + See `qmp.events` for more detail on event handling patterns. """ #: Logger object used for debugging messages. logger = logging.getLogger(__name__) @@ -416,7 +416,7 @@ def _do_send(self, msg: Message) -> None: @upper_half def _get_exec_id(self) -> str: - exec_id = f"__aqmp#{self._execute_id:05d}" + exec_id = f"__qmp#{self._execute_id:05d}" self._execute_id += 1 return exec_id @@ -476,7 +476,7 @@ async def _execute(self, msg: Message, assign_id: bool = True) -> Message: An execution ID will be assigned if assign_id is `True`. It can be disabled, but this requires that an ID is manually assigned instead. For manually assigned IDs, you must not use the string - '__aqmp#' anywhere in the ID. + '__qmp#' anywhere in the ID. :param msg: The QMP `Message` to execute. :param assign_id: If True, assign a new execution ID. @@ -490,7 +490,7 @@ async def _execute(self, msg: Message, assign_id: bool = True) -> Message: msg['id'] = self._get_exec_id() elif 'id' in msg: assert isinstance(msg['id'], str) - assert '__aqmp#' not in msg['id'] + assert '__qmp#' not in msg['id'] exec_id = await self._issue(msg) return await self._reply(exec_id) @@ -512,7 +512,7 @@ async def _raw( Assign an arbitrary execution ID to this message. If `False`, the existing id must either be absent (and no other such pending execution may omit an ID) or a string. If it is - a string, it must not start with '__aqmp#' and no other such + a string, it must not start with '__qmp#' and no other such pending execution may currently be using that ID. :return: Execution reply from the server. @@ -524,7 +524,7 @@ async def _raw( When assign_id is `False`, an ID is given, and it is not a string. :raise ValueError: When assign_id is `False`, but the ID is not usable; - Either because it starts with '__aqmp#' or it is already in-use. + Either because it starts with '__qmp#' or it is already in-use. """ # 1. convert generic Mapping or bytes to a QMP Message # 2. copy Message objects so that we assign an ID only to the copy. @@ -534,9 +534,9 @@ async def _raw( if not assign_id and 'id' in msg: if not isinstance(exec_id, str): raise TypeError(f"ID ('{exec_id}') must be a string.") - if exec_id.startswith('__aqmp#'): + if exec_id.startswith('__qmp#'): raise ValueError( - f"ID ('{exec_id}') must not start with '__aqmp#'." + f"ID ('{exec_id}') must not start with '__qmp#'." ) if not assign_id and exec_id in self._pending: diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/qmp/qmp_shell.py similarity index 98% rename from python/qemu/aqmp/qmp_shell.py rename to python/qemu/qmp/qmp_shell.py index 35691494d0a8..619ab42cedd5 100644 --- a/python/qemu/aqmp/qmp_shell.py +++ b/python/qemu/qmp/qmp_shell.py @@ -1,11 +1,12 @@ # -# Copyright (C) 2009, 2010 Red Hat Inc. +# Copyright (C) 2009-2022 Red Hat Inc. # # Authors: # Luiz Capitulino +# John Snow # -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. +# This work is licensed under the terms of the GNU LGPL, version 2 or +# later. See the COPYING file in the top-level directory. # """ @@ -97,8 +98,8 @@ Sequence, ) -from qemu.aqmp import ConnectError, QMPError, SocketAddrT -from qemu.aqmp.legacy import ( +from qemu.qmp import ConnectError, QMPError, SocketAddrT +from qemu.qmp.legacy import ( QEMUMonitorProtocol, QMPBadPortError, QMPMessage, diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py new file mode 100644 index 000000000000..ce239d8979b5 --- /dev/null +++ b/python/qemu/qmp/qmp_tui.py @@ -0,0 +1,652 @@ +# Copyright (c) 2021 +# +# Authors: +# Niteesh Babu G S +# +# This work is licensed under the terms of the GNU LGPL, version 2 or +# later. See the COPYING file in the top-level directory. +""" +QMP TUI + +QMP TUI is an asynchronous interface built on top the of the QMP library. +It is the successor of QMP-shell and is bought-in as a replacement for it. + +Example Usage: qmp-tui +Full Usage: qmp-tui --help +""" + +import argparse +import asyncio +import json +import logging +from logging import Handler, LogRecord +import signal +from typing import ( + List, + Optional, + Tuple, + Type, + Union, + cast, +) + +from pygments import lexers +from pygments import token as Token +import urwid +import urwid_readline + +from .error import ProtocolError +from .legacy import QEMUMonitorProtocol, QMPBadPortError +from .message import DeserializationError, Message, UnexpectedTypeError +from .protocol import ConnectError, Runstate +from .qmp_client import ExecInterruptedError, QMPClient +from .util import create_task, pretty_traceback + + +# The name of the signal that is used to update the history list +UPDATE_MSG: str = 'UPDATE_MSG' + + +palette = [ + (Token.Punctuation, '', '', '', 'h15,bold', 'g7'), + (Token.Text, '', '', '', '', 'g7'), + (Token.Name.Tag, '', '', '', 'bold,#f88', 'g7'), + (Token.Literal.Number.Integer, '', '', '', '#fa0', 'g7'), + (Token.Literal.String.Double, '', '', '', '#6f6', 'g7'), + (Token.Keyword.Constant, '', '', '', '#6af', 'g7'), + ('DEBUG', '', '', '', '#ddf', 'g7'), + ('INFO', '', '', '', 'g100', 'g7'), + ('WARNING', '', '', '', '#ff6', 'g7'), + ('ERROR', '', '', '', '#a00', 'g7'), + ('CRITICAL', '', '', '', '#a00', 'g7'), + ('background', '', 'black', '', '', 'g7'), +] + + +def format_json(msg: str) -> str: + """ + Formats valid/invalid multi-line JSON message into a single-line message. + + Formatting is first tried using the standard json module. If that fails + due to an decoding error then a simple string manipulation is done to + achieve a single line JSON string. + + Converting into single line is more asthetically pleasing when looking + along with error messages. + + Eg: + Input: + [ 1, + true, + 3 ] + The above input is not a valid QMP message and produces the following error + "QMP message is not a JSON object." + When displaying this in TUI in multiline mode we get + + [ 1, + true, + 3 ]: QMP message is not a JSON object. + + whereas in singleline mode we get the following + + [1, true, 3]: QMP message is not a JSON object. + + The single line mode is more asthetically pleasing. + + :param msg: + The message to formatted into single line. + + :return: Formatted singleline message. + """ + try: + msg = json.loads(msg) + return str(json.dumps(msg)) + except json.decoder.JSONDecodeError: + msg = msg.replace('\n', '') + words = msg.split(' ') + words = list(filter(None, words)) + return ' '.join(words) + + +def has_handler_type(logger: logging.Logger, + handler_type: Type[Handler]) -> bool: + """ + The Logger class has no interface to check if a certain type of handler is + installed or not. So we provide an interface to do so. + + :param logger: + Logger object + :param handler_type: + The type of the handler to be checked. + + :return: returns True if handler of type `handler_type`. + """ + for handler in logger.handlers: + if isinstance(handler, handler_type): + return True + return False + + +class App(QMPClient): + """ + Implements the QMP TUI. + + Initializes the widgets and starts the urwid event loop. + + :param address: + Address of the server to connect to. + :param num_retries: + The number of times to retry before stopping to reconnect. + :param retry_delay: + The delay(sec) before each retry + """ + def __init__(self, address: Union[str, Tuple[str, int]], num_retries: int, + retry_delay: Optional[int]) -> None: + urwid.register_signal(type(self), UPDATE_MSG) + self.window = Window(self) + self.address = address + self.aloop: Optional[asyncio.AbstractEventLoop] = None + self.num_retries = num_retries + self.retry_delay = retry_delay if retry_delay else 2 + self.retry: bool = False + self.exiting: bool = False + super().__init__() + + def add_to_history(self, msg: str, level: Optional[str] = None) -> None: + """ + Appends the msg to the history list. + + :param msg: + The raw message to be appended in string type. + """ + urwid.emit_signal(self, UPDATE_MSG, msg, level) + + def _cb_outbound(self, msg: Message) -> Message: + """ + Callback: outbound message hook. + + Appends the outgoing messages to the history box. + + :param msg: raw outbound message. + :return: final outbound message. + """ + str_msg = str(msg) + + if not has_handler_type(logging.getLogger(), TUILogHandler): + logging.debug('Request: %s', str_msg) + self.add_to_history('<-- ' + str_msg) + return msg + + def _cb_inbound(self, msg: Message) -> Message: + """ + Callback: outbound message hook. + + Appends the incoming messages to the history box. + + :param msg: raw inbound message. + :return: final inbound message. + """ + str_msg = str(msg) + + if not has_handler_type(logging.getLogger(), TUILogHandler): + logging.debug('Request: %s', str_msg) + self.add_to_history('--> ' + str_msg) + return msg + + async def _send_to_server(self, msg: Message) -> None: + """ + This coroutine sends the message to the server. + The message has to be pre-validated. + + :param msg: + Pre-validated message to be to sent to the server. + + :raise Exception: When an unhandled exception is caught. + """ + try: + await self._raw(msg, assign_id='id' not in msg) + except ExecInterruptedError as err: + logging.info('Error server disconnected before reply %s', str(err)) + self.add_to_history('Server disconnected before reply', 'ERROR') + except Exception as err: + logging.error('Exception from _send_to_server: %s', str(err)) + raise err + + def cb_send_to_server(self, raw_msg: str) -> None: + """ + Validates and sends the message to the server. + The raw string message is first converted into a Message object + and is then sent to the server. + + :param raw_msg: + The raw string message to be sent to the server. + + :raise Exception: When an unhandled exception is caught. + """ + try: + msg = Message(bytes(raw_msg, encoding='utf-8')) + create_task(self._send_to_server(msg)) + except (DeserializationError, UnexpectedTypeError) as err: + raw_msg = format_json(raw_msg) + logging.info('Invalid message: %s', err.error_message) + self.add_to_history(f'{raw_msg}: {err.error_message}', 'ERROR') + + def unhandled_input(self, key: str) -> None: + """ + Handle's keys which haven't been handled by the child widgets. + + :param key: + Unhandled key + """ + if key == 'esc': + self.kill_app() + + def kill_app(self) -> None: + """ + Initiates killing of app. A bridge between asynchronous and synchronous + code. + """ + create_task(self._kill_app()) + + async def _kill_app(self) -> None: + """ + This coroutine initiates the actual disconnect process and calls + urwid.ExitMainLoop() to kill the TUI. + + :raise Exception: When an unhandled exception is caught. + """ + self.exiting = True + await self.disconnect() + logging.debug('Disconnect finished. Exiting app') + raise urwid.ExitMainLoop() + + async def disconnect(self) -> None: + """ + Overrides the disconnect method to handle the errors locally. + """ + try: + await super().disconnect() + except (OSError, EOFError) as err: + logging.info('disconnect: %s', str(err)) + self.retry = True + except ProtocolError as err: + logging.info('disconnect: %s', str(err)) + except Exception as err: + logging.error('disconnect: Unhandled exception %s', str(err)) + raise err + + def _set_status(self, msg: str) -> None: + """ + Sets the message as the status. + + :param msg: + The message to be displayed in the status bar. + """ + self.window.footer.set_text(msg) + + def _get_formatted_address(self) -> str: + """ + Returns a formatted version of the server's address. + + :return: formatted address + """ + if isinstance(self.address, tuple): + host, port = self.address + addr = f'{host}:{port}' + else: + addr = f'{self.address}' + return addr + + async def _initiate_connection(self) -> Optional[ConnectError]: + """ + Tries connecting to a server a number of times with a delay between + each try. If all retries failed then return the error faced during + the last retry. + + :return: Error faced during last retry. + """ + current_retries = 0 + err = None + + # initial try + await self.connect_server() + while self.retry and current_retries < self.num_retries: + logging.info('Connection Failed, retrying in %d', self.retry_delay) + status = f'[Retry #{current_retries} ({self.retry_delay}s)]' + self._set_status(status) + + await asyncio.sleep(self.retry_delay) + + err = await self.connect_server() + current_retries += 1 + # If all retries failed report the last error + if err: + logging.info('All retries failed: %s', err) + return err + return None + + async def manage_connection(self) -> None: + """ + Manage the connection based on the current run state. + + A reconnect is issued when the current state is IDLE and the number + of retries is not exhausted. + A disconnect is issued when the current state is DISCONNECTING. + """ + while not self.exiting: + if self.runstate == Runstate.IDLE: + err = await self._initiate_connection() + # If retry is still true then, we have exhausted all our tries. + if err: + self._set_status(f'[Error: {err.error_message}]') + else: + addr = self._get_formatted_address() + self._set_status(f'[Connected {addr}]') + elif self.runstate == Runstate.DISCONNECTING: + self._set_status('[Disconnected]') + await self.disconnect() + # check if a retry is needed + if self.runstate == Runstate.IDLE: + continue + await self.runstate_changed() + + async def connect_server(self) -> Optional[ConnectError]: + """ + Initiates a connection to the server at address `self.address` + and in case of a failure, sets the status to the respective error. + """ + try: + await self.connect(self.address) + self.retry = False + except ConnectError as err: + logging.info('connect_server: ConnectError %s', str(err)) + self.retry = True + return err + return None + + def run(self, debug: bool = False) -> None: + """ + Starts the long running co-routines and the urwid event loop. + + :param debug: + Enables/Disables asyncio event loop debugging + """ + screen = urwid.raw_display.Screen() + screen.set_terminal_properties(256) + + self.aloop = asyncio.get_event_loop() + self.aloop.set_debug(debug) + + # Gracefully handle SIGTERM and SIGINT signals + cancel_signals = [signal.SIGTERM, signal.SIGINT] + for sig in cancel_signals: + self.aloop.add_signal_handler(sig, self.kill_app) + + event_loop = urwid.AsyncioEventLoop(loop=self.aloop) + main_loop = urwid.MainLoop(urwid.AttrMap(self.window, 'background'), + unhandled_input=self.unhandled_input, + screen=screen, + palette=palette, + handle_mouse=True, + event_loop=event_loop) + + create_task(self.manage_connection(), self.aloop) + try: + main_loop.run() + except Exception as err: + logging.error('%s\n%s\n', str(err), pretty_traceback()) + raise err + + +class StatusBar(urwid.Text): + """ + A simple statusbar modelled using the Text widget. The status can be + set using the set_text function. All text set is aligned to right. + + :param text: Initial text to be displayed. Default is empty str. + """ + def __init__(self, text: str = ''): + super().__init__(text, align='right') + + +class Editor(urwid_readline.ReadlineEdit): + """ + A simple editor modelled using the urwid_readline.ReadlineEdit widget. + Mimcs GNU readline shortcuts and provides history support. + + The readline shortcuts can be found below: + https://github.com/rr-/urwid_readline#features + + Along with the readline features, this editor also has support for + history. Pressing the 'up'/'down' switches between the prev/next messages + available in the history. + + Currently there is no support to save the history to a file. The history of + previous commands is lost on exit. + + :param parent: Reference to the TUI object. + """ + def __init__(self, parent: App) -> None: + super().__init__(caption='> ', multiline=True) + self.parent = parent + self.history: List[str] = [] + self.last_index: int = -1 + self.show_history: bool = False + + def keypress(self, size: Tuple[int, int], key: str) -> Optional[str]: + """ + Handles the keypress on this widget. + + :param size: + The current size of the widget. + :param key: + The key to be handled. + + :return: Unhandled key if any. + """ + msg = self.get_edit_text() + if key == 'up' and not msg: + # Show the history when 'up arrow' is pressed with no input text. + # NOTE: The show_history logic is necessary because in 'multiline' + # mode (which we use) 'up arrow' is used to move between lines. + if not self.history: + return None + self.show_history = True + last_msg = self.history[self.last_index] + self.set_edit_text(last_msg) + self.edit_pos = len(last_msg) + elif key == 'up' and self.show_history: + self.last_index = max(self.last_index - 1, -len(self.history)) + self.set_edit_text(self.history[self.last_index]) + self.edit_pos = len(self.history[self.last_index]) + elif key == 'down' and self.show_history: + if self.last_index == -1: + self.set_edit_text('') + self.show_history = False + else: + self.last_index += 1 + self.set_edit_text(self.history[self.last_index]) + self.edit_pos = len(self.history[self.last_index]) + elif key == 'meta enter': + # When using multiline, enter inserts a new line into the editor + # send the input to the server on alt + enter + self.parent.cb_send_to_server(msg) + self.history.append(msg) + self.set_edit_text('') + self.last_index = -1 + self.show_history = False + else: + self.show_history = False + self.last_index = -1 + return cast(Optional[str], super().keypress(size, key)) + return None + + +class EditorWidget(urwid.Filler): + """ + Wrapper around the editor widget. + + The Editor is a flow widget and has to wrapped inside a box widget. + This class wraps the Editor inside filler widget. + + :param parent: Reference to the TUI object. + """ + def __init__(self, parent: App) -> None: + super().__init__(Editor(parent), valign='top') + + +class HistoryBox(urwid.ListBox): + """ + This widget is modelled using the ListBox widget, contains the list of + all messages both QMP messages and log messsages to be shown in the TUI. + + The messages are urwid.Text widgets. On every append of a message, the + focus is shifted to the last appended message. + + :param parent: Reference to the TUI object. + """ + def __init__(self, parent: App) -> None: + self.parent = parent + self.history = urwid.SimpleFocusListWalker([]) + super().__init__(self.history) + + def add_to_history(self, + history: Union[str, List[Tuple[str, str]]]) -> None: + """ + Appends a message to the list and set the focus to the last appended + message. + + :param history: + The history item(message/event) to be appended to the list. + """ + self.history.append(urwid.Text(history)) + self.history.set_focus(len(self.history) - 1) + + def mouse_event(self, size: Tuple[int, int], _event: str, button: float, + _x: int, _y: int, focus: bool) -> None: + # Unfortunately there are no urwid constants that represent the mouse + # events. + if button == 4: # Scroll up event + super().keypress(size, 'up') + elif button == 5: # Scroll down event + super().keypress(size, 'down') + + +class HistoryWindow(urwid.Frame): + """ + This window composes the HistoryBox and EditorWidget in a horizontal split. + By default the first focus is given to the history box. + + :param parent: Reference to the TUI object. + """ + def __init__(self, parent: App) -> None: + self.parent = parent + self.editor_widget = EditorWidget(parent) + self.editor = urwid.LineBox(self.editor_widget) + self.history = HistoryBox(parent) + self.body = urwid.Pile([('weight', 80, self.history), + ('weight', 20, self.editor)]) + super().__init__(self.body) + urwid.connect_signal(self.parent, UPDATE_MSG, self.cb_add_to_history) + + def cb_add_to_history(self, msg: str, level: Optional[str] = None) -> None: + """ + Appends a message to the history box + + :param msg: + The message to be appended to the history box. + :param level: + The log level of the message, if it is a log message. + """ + formatted = [] + if level: + msg = f'[{level}]: {msg}' + formatted.append((level, msg)) + else: + lexer = lexers.JsonLexer() # pylint: disable=no-member + for token in lexer.get_tokens(msg): + formatted.append(token) + self.history.add_to_history(formatted) + + +class Window(urwid.Frame): + """ + This window is the top most widget of the TUI and will contain other + windows. Each child of this widget is responsible for displaying a specific + functionality. + + :param parent: Reference to the TUI object. + """ + def __init__(self, parent: App) -> None: + self.parent = parent + footer = StatusBar() + body = HistoryWindow(parent) + super().__init__(body, footer=footer) + + +class TUILogHandler(Handler): + """ + This handler routes all the log messages to the TUI screen. + It is installed to the root logger to so that the log message from all + libraries begin used is routed to the screen. + + :param tui: Reference to the TUI object. + """ + def __init__(self, tui: App) -> None: + super().__init__() + self.tui = tui + + def emit(self, record: LogRecord) -> None: + """ + Emits a record to the TUI screen. + + Appends the log message to the TUI screen + """ + level = record.levelname + msg = record.getMessage() + self.tui.add_to_history(msg, level) + + +def main() -> None: + """ + Driver of the whole script, parses arguments, initialize the TUI and + the logger. + """ + parser = argparse.ArgumentParser(description='QMP TUI') + parser.add_argument('qmp_server', help='Address of the QMP server. ' + 'Format ') + parser.add_argument('--num-retries', type=int, default=10, + help='Number of times to reconnect before giving up.') + parser.add_argument('--retry-delay', type=int, + help='Time(s) to wait before next retry. ' + 'Default action is to wait 2s between each retry.') + parser.add_argument('--log-file', help='The Log file name') + parser.add_argument('--log-level', default='WARNING', + help='Log level ') + parser.add_argument('--asyncio-debug', action='store_true', + help='Enable debug mode for asyncio loop. ' + 'Generates lot of output, makes TUI unusable when ' + 'logs are logged in the TUI. ' + 'Use only when logging to a file.') + args = parser.parse_args() + + try: + address = QEMUMonitorProtocol.parse_address(args.qmp_server) + except QMPBadPortError as err: + parser.error(str(err)) + + app = App(address, args.num_retries, args.retry_delay) + + root_logger = logging.getLogger() + root_logger.setLevel(logging.getLevelName(args.log_level)) + + if args.log_file: + root_logger.addHandler(logging.FileHandler(args.log_file)) + else: + root_logger.addHandler(TUILogHandler(app)) + + app.run(args.asyncio_debug) + + +if __name__ == '__main__': + main() diff --git a/python/qemu/aqmp/util.py b/python/qemu/qmp/util.py similarity index 98% rename from python/qemu/aqmp/util.py rename to python/qemu/qmp/util.py index eaa5fc7d5f9c..ca6225e9cda0 100644 --- a/python/qemu/aqmp/util.py +++ b/python/qemu/qmp/util.py @@ -40,7 +40,9 @@ async def flush(writer: asyncio.StreamWriter) -> None: drain. The flow control limits are restored after the call is completed. """ - transport = cast(asyncio.WriteTransport, writer.transport) + transport = cast( # type: ignore[redundant-cast] + asyncio.WriteTransport, writer.transport + ) # https://github.com/python/typeshed/issues/5779 low, high = transport.get_write_buffer_limits() # type: ignore diff --git a/python/qemu/utils/__init__.py b/python/qemu/utils/__init__.py index 9fb273b13d15..017cfdcda75b 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/python/qemu/utils/qemu_ga_client.py b/python/qemu/utils/qemu_ga_client.py index 15ed430c6182..8c38a7ac9c0e 100644 --- a/python/qemu/utils/qemu_ga_client.py +++ b/python/qemu/utils/qemu_ga_client.py @@ -50,8 +50,8 @@ Sequence, ) -from qemu.aqmp import ConnectError, SocketAddrT -from qemu.aqmp.legacy import QEMUMonitorProtocol +from qemu.qmp import ConnectError, SocketAddrT +from qemu.qmp.legacy import QEMUMonitorProtocol # This script has not seen many patches or careful attention in quite diff --git a/python/qemu/utils/qom.py b/python/qemu/utils/qom.py index bb5d1a78f597..bcf192f47744 100644 --- a/python/qemu/utils/qom.py +++ b/python/qemu/utils/qom.py @@ -32,7 +32,7 @@ import argparse -from qemu.aqmp import ExecuteError +from qemu.qmp import ExecuteError from .qom_common import QOMCommand diff --git a/python/qemu/utils/qom_common.py b/python/qemu/utils/qom_common.py index e034a6f2476b..80da1b23041a 100644 --- a/python/qemu/utils/qom_common.py +++ b/python/qemu/utils/qom_common.py @@ -27,8 +27,8 @@ TypeVar, ) -from qemu.aqmp import QMPError -from qemu.aqmp.legacy import QEMUMonitorProtocol +from qemu.qmp import QMPError +from qemu.qmp.legacy import QEMUMonitorProtocol class ObjectPropertyInfo: diff --git a/python/qemu/utils/qom_fuse.py b/python/qemu/utils/qom_fuse.py index 653a76b93b9a..8dcd59fcde61 100644 --- a/python/qemu/utils/qom_fuse.py +++ b/python/qemu/utils/qom_fuse.py @@ -48,7 +48,7 @@ import fuse from fuse import FUSE, FuseOSError, Operations -from qemu.aqmp import ExecuteError +from qemu.qmp import ExecuteError from .qom_common import QOMCommand diff --git a/python/setup.cfg b/python/setup.cfg index 241f243e8b94..564181570654 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -19,6 +19,7 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Typing :: Typed [options] @@ -27,7 +28,6 @@ packages = qemu.qmp qemu.machine qemu.utils - qemu.aqmp [options.package_data] * = py.typed @@ -52,7 +52,7 @@ devel = fuse = fusepy >= 2.0.4 -# AQMP TUI dependencies +# QMP TUI dependencies tui = urwid >= 2.1.2 urwid-readline >= 0.13 @@ -67,12 +67,13 @@ console_scripts = qom-tree = qemu.utils.qom:QOMTree.entry_point qom-fuse = qemu.utils.qom_fuse:QOMFuse.entry_point [fuse] qemu-ga-client = qemu.utils.qemu_ga_client:main - qmp-shell = qemu.aqmp.qmp_shell:main - qmp-shell-wrap = qemu.aqmp.qmp_shell:main_wrap - aqmp-tui = qemu.aqmp.aqmp_tui:main [tui] + qmp-shell = qemu.qmp.qmp_shell:main + qmp-shell-wrap = qemu.qmp.qmp_shell:main_wrap + qmp-tui = qemu.qmp.qmp_tui:main [tui] [flake8] -extend-ignore = E722 # Prefer pylint's bare-except checks to flake8's +# Prefer pylint's bare-except checks to flake8's +extend-ignore = E722 exclude = __pycache__, [mypy] @@ -80,12 +81,13 @@ strict = True python_version = 3.6 warn_unused_configs = True namespace_packages = True +warn_unused_ignores = False [mypy-qemu.utils.qom_fuse] # fusepy has no type stubs: allow_subclassing_any = True -[mypy-qemu.aqmp.aqmp_tui] +[mypy-qemu.qmp.qmp_tui] # urwid and urwid_readline have no type stubs: allow_subclassing_any = True @@ -158,7 +160,7 @@ multi_line_output=3 # of python available on your system to run this test. [tox:tox] -envlist = py36, py37, py38, py39, py310 +envlist = py36, py37, py38, py39, py310, py311 skip_missing_interpreters = true [testenv] diff --git a/python/tests/protocol.py b/python/tests/protocol.py index d6849ad30620..56c4d441f9c4 100644 --- a/python/tests/protocol.py +++ b/python/tests/protocol.py @@ -6,9 +6,9 @@ import avocado -from qemu.aqmp import ConnectError, Runstate -from qemu.aqmp.protocol import AsyncProtocol, StateError -from qemu.aqmp.util import asyncio_run, create_task +from qemu.qmp import ConnectError, Runstate +from qemu.qmp.protocol import AsyncProtocol, StateError +from qemu.qmp.util import asyncio_run, create_task class NullProtocol(AsyncProtocol[None]): @@ -183,7 +183,7 @@ def testDefaultName(self): def testLogger(self): self.assertEqual( self.proto.logger.name, - 'qemu.aqmp.protocol' + 'qemu.qmp.protocol' ) def testName(self): @@ -196,7 +196,7 @@ def testName(self): self.assertEqual( self.proto.logger.name, - 'qemu.aqmp.protocol.Steve' + 'qemu.qmp.protocol.Steve' ) self.assertEqual( @@ -431,7 +431,7 @@ async def _bad_connection(self, family: str): await self.proto.start_server_and_accept('/dev/null') async def _hanging_connection(self): - with TemporaryDirectory(suffix='.aqmp') as tmpdir: + with TemporaryDirectory(suffix='.qmp') as tmpdir: sock = os.path.join(tmpdir, type(self.proto).__name__ + ".sock") await self.proto.start_server_and_accept(sock) @@ -587,7 +587,7 @@ async def _asyncTearDown(self): @TestBase.async_test async def testSmoke(self): - with TemporaryDirectory(suffix='.aqmp') as tmpdir: + with TemporaryDirectory(suffix='.qmp') as tmpdir: sock = os.path.join(tmpdir, type(self.proto).__name__ + ".sock") server_task = create_task(self.server.start_server_and_accept(sock)) diff --git a/qapi/audio.json b/qapi/audio.json index 0785e70a5030..1e0a24bdfc40 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: # @@ -352,7 +374,6 @@ '*out': 'AudiodevPerDirectionOptions', '*path': 'str' } } - ## # @AudioFormat: # @@ -388,7 +409,7 @@ ## { 'enum': 'AudiodevDriver', 'data': [ 'none', 'alsa', 'coreaudio', 'dbus', 'dsound', 'jack', 'oss', 'pa', - 'sdl', 'spice', 'wav' ] } + 'sdl', 'sndio', 'spice', 'wav' ] } ## # @Audiodev: @@ -419,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 beeb91952af3..95ac4fa63422 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -237,7 +237,6 @@ # information (since 1.7) # # Since: 1.3 -# ## { 'struct': 'ImageInfo', 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', @@ -288,7 +287,6 @@ # supports it # # Since: 1.4 -# ## { 'struct': 'ImageCheck', 'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int', @@ -328,7 +326,6 @@ # @filename: filename that is referred to by @offset # # Since: 2.6 -# ## { 'struct': 'MapEntry', 'data': {'start': 'int', 'length': 'int', 'data': 'bool', @@ -340,9 +337,9 @@ # # Cache mode information for a block device # -# @writeback: true if writeback mode is enabled -# @direct: true if the host page cache is bypassed (O_DIRECT) -# @no-flush: true if flush requests are ignored for the device +# @writeback: true if writeback mode is enabled +# @direct: true if the host page cache is bypassed (O_DIRECT) +# @no-flush: true if flush requests are ignored for the device # # Since: 2.3 ## @@ -445,7 +442,6 @@ # has one or more dirty bitmaps) (Since 4.2) # # Since: 0.14 -# ## { 'struct': 'BlockDeviceInfo', 'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str', @@ -608,7 +604,7 @@ # @inserted: @BlockDeviceInfo describing the device if media is # present # -# Since: 0.14 +# Since: 0.14 ## { 'struct': 'BlockInfo', 'data': {'device': 'str', '*qdev': 'str', 'type': 'str', 'removable': 'bool', @@ -741,8 +737,8 @@ # } # ## -{ 'command': 'query-block', 'returns': ['BlockInfo'] } - +{ 'command': 'query-block', 'returns': ['BlockInfo'], + 'allow-preconfig': true } ## # @BlockDeviceTimedStats: @@ -800,9 +796,9 @@ # # Statistics of a virtual block device or a block backing device. # -# @rd_bytes: The number of bytes read by the device. +# @rd_bytes: The number of bytes read by the device. # -# @wr_bytes: The number of bytes written by the device. +# @wr_bytes: The number of bytes written by the device. # # @unmap_bytes: The number of bytes unmapped by the device (Since 4.2) # @@ -975,7 +971,7 @@ # @qdev: The qdev ID, or if no ID is assigned, the QOM path of the block # device. (since 3.0) # -# @stats: A @BlockDeviceStats for the device. +# @stats: A @BlockDeviceStats for the device. # # @driver-specific: Optional driver-specific stats. (Since 4.2) # @@ -1118,7 +1114,8 @@ ## { 'command': 'query-blockstats', 'data': { '*query-nodes': 'bool' }, - 'returns': ['BlockStats'] } + 'returns': ['BlockStats'], + 'allow-preconfig': true } ## # @BlockdevOnError: @@ -1267,7 +1264,8 @@ # # Since: 1.1 ## -{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] } +{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'], + 'allow-preconfig': true } ## # @block_resize: @@ -1280,7 +1278,7 @@ # # @node-name: graph node name to get the image resized (Since 2.0) # -# @size: new image size in bytes +# @size: new image size in bytes # # Returns: - nothing on success # - If @device is not a valid block device, DeviceNotFound @@ -1298,7 +1296,8 @@ 'data': { '*device': 'str', '*node-name': 'str', 'size': 'int' }, - 'coroutine': true } + 'coroutine': true, + 'allow-preconfig': true } ## # @NewImageMode: @@ -1514,8 +1513,8 @@ # ## { 'command': 'blockdev-snapshot-sync', - 'data': 'BlockdevSnapshotSync' } - + 'data': 'BlockdevSnapshotSync', + 'allow-preconfig': true } ## # @blockdev-snapshot: @@ -1556,7 +1555,8 @@ ## { 'command': 'blockdev-snapshot', 'data': 'BlockdevSnapshot', - 'features': [ 'allow-write-only-overlay' ] } + 'features': [ 'allow-write-only-overlay' ], + 'allow-preconfig': true } ## # @change-backing-file: @@ -1588,7 +1588,8 @@ ## { 'command': 'change-backing-file', 'data': { 'device': 'str', 'image-node-name': 'str', - 'backing-file': 'str' } } + 'backing-file': 'str' }, + 'allow-preconfig': true } ## # @block-commit: @@ -1698,7 +1699,8 @@ '*backing-file': 'str', '*speed': 'int', '*on-error': 'BlockdevOnError', '*filter-node-name': 'str', - '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + '*auto-finalize': 'bool', '*auto-dismiss': 'bool' }, + 'allow-preconfig': true } ## # @drive-backup: @@ -1727,7 +1729,8 @@ # ## { 'command': 'drive-backup', 'boxed': true, - 'data': 'DriveBackup', 'features': ['deprecated'] } + 'data': 'DriveBackup', 'features': ['deprecated'], + 'allow-preconfig': true } ## # @blockdev-backup: @@ -1744,6 +1747,7 @@ # Since: 2.3 # # Example: +# # -> { "execute": "blockdev-backup", # "arguments": { "device": "src-id", # "sync": "full", @@ -1752,8 +1756,8 @@ # ## { 'command': 'blockdev-backup', 'boxed': true, - 'data': 'BlockdevBackup' } - + 'data': 'BlockdevBackup', + 'allow-preconfig': true } ## # @query-named-block-nodes: @@ -1819,7 +1823,8 @@ ## { 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ], - 'data': { '*flat': 'bool' } } + 'data': { '*flat': 'bool' }, + 'allow-preconfig': true } ## # @XDbgBlockGraphNodeType: @@ -1928,7 +1933,8 @@ # Since: 4.0 ## { 'command': 'x-debug-query-block-graph', 'returns': 'XDbgBlockGraph', - 'features': [ 'unstable' ] } + 'features': [ 'unstable' ], + 'allow-preconfig': true } ## # @drive-mirror: @@ -1956,7 +1962,8 @@ # ## { 'command': 'drive-mirror', 'boxed': true, - 'data': 'DriveMirror' } + 'data': 'DriveMirror', + 'allow-preconfig': true } ## # @DriveMirror: @@ -1966,8 +1973,8 @@ # @job-id: identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the device name or node-name of a root node whose writes should be -# mirrored. +# @device: the device name or node-name of a root node whose writes should be +# mirrored. # # @target: the target of the new image. If the file exists, or if it # is a device, the existing file/device will be used as the new @@ -1987,7 +1994,7 @@ # @mode: whether and how QEMU should create a new image, default is # 'absolute-paths'. # -# @speed: the maximum speed, in bytes per second +# @speed: the maximum speed, in bytes per second # # @sync: what parts of the disk image should be copied to the destination # (all the disk, only the sectors allocated in the topmost image, or @@ -2008,6 +2015,7 @@ # @on-target-error: the action to take on an error on the target, # default 'report' (no limitations, since this applies to # a different block device than @device). +# # @unmap: Whether to try to unmap target sectors where source has # only zero. If true, and target unallocated sectors will read as zero, # target image sectors will be unmapped; otherwise, zeroes will be @@ -2029,6 +2037,7 @@ # When true, this job will automatically disappear from the query # list without user intervention. # Defaults to true. (Since 3.1) +# # Since: 1.3 ## { 'struct': 'DriveMirror', @@ -2079,7 +2088,7 @@ '*persistent': 'bool', '*disabled': 'bool' } } ## -# @BlockDirtyBitmapMergeSource: +# @BlockDirtyBitmapOrStr: # # @local: name of the bitmap, attached to the same node as target bitmap. # @@ -2087,7 +2096,7 @@ # # Since: 4.1 ## -{ 'alternate': 'BlockDirtyBitmapMergeSource', +{ 'alternate': 'BlockDirtyBitmapOrStr', 'data': { 'local': 'str', 'external': 'BlockDirtyBitmap' } } @@ -2106,7 +2115,7 @@ ## { 'struct': 'BlockDirtyBitmapMerge', 'data': { 'node': 'str', 'target': 'str', - 'bitmaps': ['BlockDirtyBitmapMergeSource'] } } + 'bitmaps': ['BlockDirtyBitmapOrStr'] } } ## # @block-dirty-bitmap-add: @@ -2127,7 +2136,8 @@ # ## { 'command': 'block-dirty-bitmap-add', - 'data': 'BlockDirtyBitmapAdd' } + 'data': 'BlockDirtyBitmapAdd', + 'allow-preconfig': true } ## # @block-dirty-bitmap-remove: @@ -2151,7 +2161,8 @@ # ## { 'command': 'block-dirty-bitmap-remove', - 'data': 'BlockDirtyBitmap' } + 'data': 'BlockDirtyBitmap', + 'allow-preconfig': true } ## # @block-dirty-bitmap-clear: @@ -2174,7 +2185,8 @@ # ## { 'command': 'block-dirty-bitmap-clear', - 'data': 'BlockDirtyBitmap' } + 'data': 'BlockDirtyBitmap', + 'allow-preconfig': true } ## # @block-dirty-bitmap-enable: @@ -2195,7 +2207,8 @@ # ## { 'command': 'block-dirty-bitmap-enable', - 'data': 'BlockDirtyBitmap' } + 'data': 'BlockDirtyBitmap', + 'allow-preconfig': true } ## # @block-dirty-bitmap-disable: @@ -2216,7 +2229,8 @@ # ## { 'command': 'block-dirty-bitmap-disable', - 'data': 'BlockDirtyBitmap' } + 'data': 'BlockDirtyBitmap', + 'allow-preconfig': true } ## # @block-dirty-bitmap-merge: @@ -2248,7 +2262,8 @@ # ## { 'command': 'block-dirty-bitmap-merge', - 'data': 'BlockDirtyBitmapMerge' } + 'data': 'BlockDirtyBitmapMerge', + 'allow-preconfig': true } ## # @BlockDirtyBitmapSha256: @@ -2279,7 +2294,8 @@ ## { 'command': 'x-debug-block-dirty-bitmap-sha256', 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256', - 'features': [ 'unstable' ] } + 'features': [ 'unstable' ], + 'allow-preconfig': true } ## # @blockdev-mirror: @@ -2300,7 +2316,7 @@ # broken Quorum files. By default, @device is replaced, although # implicitly created filters on it are kept. # -# @speed: the maximum speed, in bytes per second +# @speed: the maximum speed, in bytes per second # # @sync: what parts of the disk image should be copied to the destination # (all the disk, only the sectors allocated in the topmost image, or @@ -2342,6 +2358,7 @@ # When true, this job will automatically disappear from the query # list without user intervention. # Defaults to true. (Since 3.1) +# # Returns: nothing on success. # # Since: 2.6 @@ -2364,7 +2381,8 @@ '*on-target-error': 'BlockdevOnError', '*filter-node-name': 'str', '*copy-mode': 'MirrorCopyMode', - '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + '*auto-finalize': 'bool', '*auto-dismiss': 'bool' }, + 'allow-preconfig': true } ## # @BlockIOThrottle: @@ -2666,7 +2684,8 @@ '*base-node': 'str', '*backing-file': 'str', '*bottom': 'str', '*speed': 'int', '*on-error': 'BlockdevOnError', '*filter-node-name': 'str', - '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + '*auto-finalize': 'bool', '*auto-dismiss': 'bool' }, + 'allow-preconfig': true } ## # @block-job-set-speed: @@ -2690,7 +2709,8 @@ # Since: 1.1 ## { 'command': 'block-job-set-speed', - 'data': { 'device': 'str', 'speed': 'int' } } + 'data': { 'device': 'str', 'speed': 'int' }, + 'allow-preconfig': true } ## # @block-job-cancel: @@ -2729,7 +2749,8 @@ # # Since: 1.1 ## -{ 'command': 'block-job-cancel', 'data': { 'device': 'str', '*force': 'bool' } } +{ 'command': 'block-job-cancel', 'data': { 'device': 'str', '*force': 'bool' }, + 'allow-preconfig': true } ## # @block-job-pause: @@ -2753,7 +2774,8 @@ # # Since: 1.3 ## -{ 'command': 'block-job-pause', 'data': { 'device': 'str' } } +{ 'command': 'block-job-pause', 'data': { 'device': 'str' }, + 'allow-preconfig': true } ## # @block-job-resume: @@ -2775,7 +2797,8 @@ # # Since: 1.3 ## -{ 'command': 'block-job-resume', 'data': { 'device': 'str' } } +{ 'command': 'block-job-resume', 'data': { 'device': 'str' }, + 'allow-preconfig': true } ## # @block-job-complete: @@ -2803,7 +2826,8 @@ # # Since: 1.3 ## -{ 'command': 'block-job-complete', 'data': { 'device': 'str' } } +{ 'command': 'block-job-complete', 'data': { 'device': 'str' }, + 'allow-preconfig': true } ## # @block-job-dismiss: @@ -2823,7 +2847,8 @@ # # Since: 2.12 ## -{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } } +{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' }, + 'allow-preconfig': true } ## # @block-job-finalize: @@ -2841,7 +2866,8 @@ # # Since: 2.12 ## -{ 'command': 'block-job-finalize', 'data': { 'id': 'str' } } +{ 'command': 'block-job-finalize', 'data': { 'id': 'str' }, + 'allow-preconfig': true } ## # @BlockdevDiscardOptions: @@ -2925,11 +2951,19 @@ 'file', 'snapshot-access', 'ftp', 'ftps', 'gluster', {'name': 'host_cdrom', 'if': 'HAVE_HOST_BLOCK_DEVICE' }, {'name': 'host_device', 'if': 'HAVE_HOST_BLOCK_DEVICE' }, - 'http', 'https', 'iscsi', - 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', - 'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd', + 'http', 'https', + { 'name': 'io_uring', 'if': 'CONFIG_BLKIO' }, + 'iscsi', + 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', + { 'name': 'nvme-io_uring', 'if': 'CONFIG_BLKIO' }, + 'parallels', 'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', + 'raw', 'rbd', { 'name': 'replication', 'if': 'CONFIG_REPLICATION' }, - 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] } + 'ssh', 'throttle', 'vdi', 'vhdx', + { 'name': 'virtio-blk-vfio-pci', 'if': 'CONFIG_BLKIO' }, + { 'name': 'virtio-blk-vhost-user', 'if': 'CONFIG_BLKIO' }, + { 'name': 'virtio-blk-vhost-vdpa', 'if': 'CONFIG_BLKIO' }, + 'vmdk', 'vpc', 'vvfat' ] } ## # @BlockdevOptionsFile: @@ -3067,7 +3101,6 @@ 'base': 'BlockdevOptionsGenericFormat', 'data': { '*key-secret': 'str' } } - ## # @BlockdevOptionsGenericCOWFormat: # @@ -3182,8 +3215,6 @@ 'base': 'BlockdevOptionsGenericCOWFormat', 'data': { '*encrypt': 'BlockdevQcowEncryption' } } - - ## # @BlockdevQcow2EncryptionFormat: # @@ -3339,15 +3370,14 @@ ## # @BlockdevOptionsSsh: # -# @server: host address +# @server: host address # -# @path: path to the image on the host +# @path: path to the image on the host # -# @user: user as which to connect, defaults to current -# local user name +# @user: user as which to connect, defaults to current local user name # -# @host-key-check: Defines how and what to check the host key against -# (default: known_hosts) +# @host-key-check: Defines how and what to check the host key against +# (default: known_hosts) # # Since: 2.9 ## @@ -3357,7 +3387,6 @@ '*user': 'str', '*host-key-check': 'SshHostKeyCheck' } } - ## # @BlkdebugEvent: # @@ -3657,6 +3686,72 @@ '*debug': 'int', '*logfile': 'str' } } +## +# @BlockdevOptionsIoUring: +# +# Driver specific block device options for the io_uring backend. +# +# @filename: path to the image file +# +# Since: 7.2 +## +{ 'struct': 'BlockdevOptionsIoUring', + 'data': { 'filename': 'str' }, + 'if': 'CONFIG_BLKIO' } + +## +# @BlockdevOptionsNvmeIoUring: +# +# Driver specific block device options for the nvme-io_uring backend. +# +# @path: path to the NVMe namespace's character device (e.g. /dev/ng0n1). +# +# Since: 7.2 +## +{ 'struct': 'BlockdevOptionsNvmeIoUring', + 'data': { 'path': 'str' }, + 'if': 'CONFIG_BLKIO' } + +## +# @BlockdevOptionsVirtioBlkVfioPci: +# +# Driver specific block device options for the virtio-blk-vfio-pci backend. +# +# @path: path to the PCI device's sysfs directory (e.g. +# /sys/bus/pci/devices/0000:00:01.0). +# +# Since: 7.2 +## +{ 'struct': 'BlockdevOptionsVirtioBlkVfioPci', + 'data': { 'path': 'str' }, + 'if': 'CONFIG_BLKIO' } + +## +# @BlockdevOptionsVirtioBlkVhostUser: +# +# Driver specific block device options for the virtio-blk-vhost-user backend. +# +# @path: path to the vhost-user UNIX domain socket. +# +# Since: 7.2 +## +{ 'struct': 'BlockdevOptionsVirtioBlkVhostUser', + 'data': { 'path': 'str' }, + 'if': 'CONFIG_BLKIO' } + +## +# @BlockdevOptionsVirtioBlkVhostVdpa: +# +# Driver specific block device options for the virtio-blk-vhost-vdpa backend. +# +# @path: path to the vhost-vdpa character device. +# +# Since: 7.2 +## +{ 'struct': 'BlockdevOptionsVirtioBlkVhostVdpa', + 'data': { 'path': 'str' }, + 'if': 'CONFIG_BLKIO' } + ## # @IscsiTransport: # @@ -3721,7 +3816,6 @@ '*header-digest': 'IscsiHeaderDigest', '*timeout': 'int' } } - ## # @RbdAuthMode: # @@ -4139,6 +4233,7 @@ # @throttle-group: the name of the throttle-group object to use. It # must already exist. # @file: reference to or definition of the data source block device +# # Since: 2.11 ## { 'struct': 'BlockdevOptionsThrottle', @@ -4163,6 +4258,25 @@ 'base': 'BlockdevOptionsGenericFormat', 'data': { '*bottom': 'str' } } +## +# @OnCbwError: +# +# An enumeration of possible behaviors for copy-before-write operation +# failures. +# +# @break-guest-write: report the error to the guest. This way, the guest +# will not be able to overwrite areas that cannot be +# backed up, so the backup process remains valid. +# +# @break-snapshot: continue guest write. Doing so will make the provided +# snapshot state invalid and any backup or export +# process based on it will finally fail. +# +# Since: 7.1 +## +{ 'enum': 'OnCbwError', + 'data': [ 'break-guest-write', 'break-snapshot' ] } + ## # @BlockdevOptionsCbw: # @@ -4184,11 +4298,21 @@ # modifications (or removing) of specified bitmap doesn't # influence the filter. (Since 7.0) # +# @on-cbw-error: Behavior on failure of copy-before-write operation. +# Default is @break-guest-write. (Since 7.1) +# +# @cbw-timeout: Zero means no limit. Non-zero sets the timeout in seconds +# for copy-before-write operation. When a timeout occurs, +# the respective copy-before-write operation will fail, and +# the @on-cbw-error parameter will decide how this failure +# is handled. Default 0. (Since 7.1) +# # Since: 6.2 ## { 'struct': 'BlockdevOptionsCbw', 'base': 'BlockdevOptionsGenericFormat', - 'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap' } } + 'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap', + '*on-cbw-error': 'OnCbwError', '*cbw-timeout': 'uint32' } } ## # @BlockdevOptions: @@ -4255,6 +4379,8 @@ 'if': 'HAVE_HOST_BLOCK_DEVICE' }, 'http': 'BlockdevOptionsCurlHttp', 'https': 'BlockdevOptionsCurlHttps', + 'io_uring': { 'type': 'BlockdevOptionsIoUring', + 'if': 'CONFIG_BLKIO' }, 'iscsi': 'BlockdevOptionsIscsi', 'luks': 'BlockdevOptionsLUKS', 'nbd': 'BlockdevOptionsNbd', @@ -4262,6 +4388,8 @@ 'null-aio': 'BlockdevOptionsNull', 'null-co': 'BlockdevOptionsNull', 'nvme': 'BlockdevOptionsNVMe', + 'nvme-io_uring': { 'type': 'BlockdevOptionsNvmeIoUring', + 'if': 'CONFIG_BLKIO' }, 'parallels': 'BlockdevOptionsGenericFormat', 'preallocate':'BlockdevOptionsPreallocate', 'qcow2': 'BlockdevOptionsQcow2', @@ -4277,6 +4405,15 @@ 'throttle': 'BlockdevOptionsThrottle', 'vdi': 'BlockdevOptionsGenericFormat', 'vhdx': 'BlockdevOptionsGenericFormat', + 'virtio-blk-vfio-pci': + { 'type': 'BlockdevOptionsVirtioBlkVfioPci', + 'if': 'CONFIG_BLKIO' }, + 'virtio-blk-vhost-user': + { 'type': 'BlockdevOptionsVirtioBlkVhostUser', + 'if': 'CONFIG_BLKIO' }, + 'virtio-blk-vhost-vdpa': + { 'type': 'BlockdevOptionsVirtioBlkVhostVdpa', + 'if': 'CONFIG_BLKIO' }, 'vmdk': 'BlockdevOptionsGenericCOWFormat', 'vpc': 'BlockdevOptionsGenericFormat', 'vvfat': 'BlockdevOptionsVVFAT' @@ -4362,7 +4499,8 @@ # <- { "return": {} } # ## -{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true } +{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true, + 'allow-preconfig': true } ## # @blockdev-reopen: @@ -4406,7 +4544,8 @@ # Since: 6.1 ## { 'command': 'blockdev-reopen', - 'data': { 'options': ['BlockdevOptions'] } } + 'data': { 'options': ['BlockdevOptions'] }, + 'allow-preconfig': true } ## # @blockdev-del: @@ -4439,7 +4578,8 @@ # <- { "return": {} } # ## -{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } } +{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' }, + 'allow-preconfig': true } ## # @BlockdevCreateOptionsFile: @@ -4555,15 +4695,14 @@ ## # @BlockdevQcow2Version: # -# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2) -# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3) +# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2) +# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3) # # Since: 2.12 ## { 'enum': 'BlockdevQcow2Version', 'data': [ 'v2', 'v3' ] } - ## # @Qcow2CompressionType: # @@ -4670,18 +4809,18 @@ # # Subformat options for VMDK images # -# @monolithicSparse: Single file image with sparse cluster allocation +# @monolithicSparse: Single file image with sparse cluster allocation # -# @monolithicFlat: Single flat data image and a descriptor file +# @monolithicFlat: Single flat data image and a descriptor file # # @twoGbMaxExtentSparse: Data is split into 2GB (per virtual LBA) sparse extent # files, in addition to a descriptor file # -# @twoGbMaxExtentFlat: Data is split into 2GB (per virtual LBA) flat extent -# files, in addition to a descriptor file +# @twoGbMaxExtentFlat: Data is split into 2GB (per virtual LBA) flat extent +# files, in addition to a descriptor file # -# @streamOptimized: Single file image sparse cluster allocation, optimized -# for streaming over network. +# @streamOptimized: Single file image sparse cluster allocation, optimized +# for streaming over network. # # Since: 4.0 ## @@ -4737,7 +4876,6 @@ '*toolsversion': 'str', '*zeroed-grain': 'bool' } } - ## # @BlockdevCreateOptionsSsh: # @@ -4773,7 +4911,7 @@ # @BlockdevVhdxSubformat: # # @dynamic: Growing image file -# @fixed: Preallocated fixed-size image file +# @fixed: Preallocated fixed-size image file # # Since: 2.12 ## @@ -4811,7 +4949,7 @@ # @BlockdevVpcSubformat: # # @dynamic: Growing image file -# @fixed: Preallocated fixed-size image file +# @fixed: Preallocated fixed-size image file # # Since: 2.12 ## @@ -4874,15 +5012,16 @@ # Starts a job to create an image format on a given node. The job is # automatically finalized, but a manual job-dismiss is required. # -# @job-id: Identifier for the newly created job. +# @job-id: Identifier for the newly created job. # -# @options: Options for the image creation. +# @options: Options for the image creation. # # Since: 3.0 ## { 'command': 'blockdev-create', 'data': { 'job-id': 'str', - 'options': 'BlockdevCreateOptions' } } + 'options': 'BlockdevCreateOptions' }, + 'allow-preconfig': true } ## # @BlockdevAmendOptionsLUKS: @@ -4914,7 +5053,7 @@ # # Options for amending an image format # -# @driver: Block driver of the node to amend. +# @driver: Block driver of the node to amend. # # Since: 5.1 ## @@ -4932,17 +5071,17 @@ # Starts a job to amend format specific options of an existing open block device # The job is automatically finalized, but a manual job-dismiss is required. # -# @job-id: Identifier for the newly created job. +# @job-id: Identifier for the newly created job. # -# @node-name: Name of the block node to work on +# @node-name: Name of the block node to work on # -# @options: Options (driver specific) +# @options: Options (driver specific) # -# @force: Allow unsafe operations, format specific -# For luks that allows erase of the last active keyslot -# (permanent loss of data), -# and replacement of an active keyslot -# (possible loss of data if IO error happens) +# @force: Allow unsafe operations, format specific +# For luks that allows erase of the last active keyslot +# (permanent loss of data), +# and replacement of an active keyslot +# (possible loss of data if IO error happens) # # Features: # @unstable: This command is experimental. @@ -4954,7 +5093,8 @@ 'node-name': 'str', 'options': 'BlockdevAmendOptions', '*force': 'bool' }, - 'features': [ 'unstable' ] } + 'features': [ 'unstable' ], + 'allow-preconfig': true } ## # @BlockErrorAction: @@ -4972,7 +5112,6 @@ { 'enum': 'BlockErrorAction', 'data': [ 'ignore', 'report', 'stop' ] } - ## # @BLOCK_IMAGE_CORRUPTED: # @@ -5200,7 +5339,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 } } # ## @@ -5305,7 +5444,8 @@ # ## { 'command': 'block-set-write-threshold', - 'data': { 'node-name': 'str', 'write-threshold': 'uint64' } } + 'data': { 'node-name': 'str', 'write-threshold': 'uint64' }, + 'allow-preconfig': true } ## # @x-blockdev-change: @@ -5366,7 +5506,8 @@ 'data' : { 'parent': 'str', '*child': 'str', '*node': 'str' }, - 'features': [ 'unstable' ] } + 'features': [ 'unstable' ], + 'allow-preconfig': true } ## # @x-blockdev-set-iothread: @@ -5408,7 +5549,8 @@ 'data' : { 'node-name': 'str', 'iothread': 'StrOrNull', '*force': 'bool' }, - 'features': [ 'unstable' ] } + 'features': [ 'unstable' ], + 'allow-preconfig': true } ## # @QuorumOpType: @@ -5540,7 +5682,8 @@ # ## { 'command': 'blockdev-snapshot-internal-sync', - 'data': 'BlockdevSnapshotInternal' } + 'data': 'BlockdevSnapshotInternal', + 'allow-preconfig': true } ## # @blockdev-snapshot-delete-internal-sync: @@ -5587,4 +5730,5 @@ ## { 'command': 'blockdev-snapshot-delete-internal-sync', 'data': { 'device': 'str', '*id': 'str', '*name': 'str'}, - 'returns': 'SnapshotInfo' } + 'returns': 'SnapshotInfo', + 'allow-preconfig': true } diff --git a/qapi/block-export.json b/qapi/block-export.json index 1e34927f85e2..4627bbc4e603 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -6,6 +6,7 @@ ## { 'include': 'sockets.json' } +{ 'include': 'block-core.json' } ## # @NbdServerOptions: @@ -21,7 +22,9 @@ # recreated on the fly while the NBD server is active. # If missing, it will default to denying access (since 4.0). # @max-connections: The maximum number of connections to allow at the same -# time, 0 for unlimited. (since 5.2; default: 0) +# time, 0 for unlimited. Setting this to 1 also stops +# the server from advertising multiple client support +# (since 5.2; default: 0) # # Since: 4.2 ## @@ -50,7 +53,9 @@ # recreated on the fly while the NBD server is active. # If missing, it will default to denying access (since 4.0). # @max-connections: The maximum number of connections to allow at the same -# time, 0 for unlimited. (since 5.2; default: 0) +# time, 0 for unlimited. Setting this to 1 also stops +# the server from advertising multiple client support +# (since 5.2; default: 0). # # Returns: error if the server is already running. # @@ -60,7 +65,8 @@ 'data': { 'addr': 'SocketAddressLegacy', '*tls-creds': 'str', '*tls-authz': 'str', - '*max-connections': 'uint32' } } + '*max-connections': 'uint32' }, + 'allow-preconfig': true } ## # @BlockExportOptionsNbdBase: @@ -89,6 +95,7 @@ # @device, so the NBD client can use NBD_OPT_SET_META_CONTEXT with # the metadata context name "qemu:dirty-bitmap:BITMAP" to inspect # each bitmap. +# Since 7.1 bitmap may be specified by node/name pair. # # @allocation-depth: Also export the allocation depth map for @device, so # the NBD client can use NBD_OPT_SET_META_CONTEXT with @@ -99,7 +106,8 @@ ## { 'struct': 'BlockExportOptionsNbd', 'base': 'BlockExportOptionsNbdBase', - 'data': { '*bitmaps': ['str'], '*allocation-depth': 'bool' } } + 'data': { '*bitmaps': ['BlockDirtyBitmapOrStr'], + '*allocation-depth': 'bool' } } ## # @BlockExportOptionsVhostUserBlk: @@ -170,6 +178,27 @@ '*allow-other': 'FuseExportAllowOther' }, 'if': 'CONFIG_FUSE' } +## +# @BlockExportOptionsVduseBlk: +# +# A vduse-blk block export. +# +# @name: the name of VDUSE device (must be unique across the host). +# @num-queues: the number of virtqueues. Defaults to 1. +# @queue-size: the size of virtqueue. Defaults to 256. +# @logical-block-size: Logical block size in bytes. Range [512, PAGE_SIZE] +# and must be power of 2. Defaults to 512 bytes. +# @serial: the serial number of virtio block device. Defaults to empty string. +# +# Since: 7.1 +## +{ 'struct': 'BlockExportOptionsVduseBlk', + 'data': { 'name': 'str', + '*num-queues': 'uint16', + '*queue-size': 'uint16', + '*logical-block-size': 'size', + '*serial': 'str' } } + ## # @NbdServerAddOptions: # @@ -208,7 +237,8 @@ # Since: 1.3 ## { 'command': 'nbd-server-add', - 'data': 'NbdServerAddOptions', 'boxed': true, 'features': ['deprecated'] } + 'data': 'NbdServerAddOptions', 'boxed': true, 'features': ['deprecated'], + 'allow-preconfig': true } ## # @BlockExportRemoveMode: @@ -253,7 +283,8 @@ ## { 'command': 'nbd-server-remove', 'data': {'name': 'str', '*mode': 'BlockExportRemoveMode'}, - 'features': ['deprecated'] } + 'features': ['deprecated'], + 'allow-preconfig': true } ## # @nbd-server-stop: @@ -263,7 +294,8 @@ # # Since: 1.3 ## -{ 'command': 'nbd-server-stop' } +{ 'command': 'nbd-server-stop', + 'allow-preconfig': true } ## # @BlockExportType: @@ -273,6 +305,7 @@ # @nbd: NBD export # @vhost-user-blk: vhost-user-blk export (since 5.2) # @fuse: FUSE export (since: 6.0) +# @vduse-blk: vduse-blk export (since 7.1) # # Since: 4.2 ## @@ -280,7 +313,8 @@ 'data': [ 'nbd', { 'name': 'vhost-user-blk', 'if': 'CONFIG_VHOST_USER_BLK_SERVER' }, - { 'name': 'fuse', 'if': 'CONFIG_FUSE' } ] } + { 'name': 'fuse', 'if': 'CONFIG_FUSE' }, + { 'name': 'vduse-blk', 'if': 'CONFIG_VDUSE_BLK_EXPORT' } ] } ## # @BlockExportOptions: @@ -324,7 +358,9 @@ 'vhost-user-blk': { 'type': 'BlockExportOptionsVhostUserBlk', 'if': 'CONFIG_VHOST_USER_BLK_SERVER' }, 'fuse': { 'type': 'BlockExportOptionsFuse', - 'if': 'CONFIG_FUSE' } + 'if': 'CONFIG_FUSE' }, + 'vduse-blk': { 'type': 'BlockExportOptionsVduseBlk', + 'if': 'CONFIG_VDUSE_BLK_EXPORT' } } } ## @@ -335,7 +371,8 @@ # Since: 5.2 ## { 'command': 'block-export-add', - 'data': 'BlockExportOptions', 'boxed': true } + 'data': 'BlockExportOptions', 'boxed': true, + 'allow-preconfig': true } ## # @block-export-del: @@ -355,7 +392,8 @@ # Since: 5.2 ## { 'command': 'block-export-del', - 'data': { 'id': 'str', '*mode': 'BlockExportRemoveMode' } } + 'data': { 'id': 'str', '*mode': 'BlockExportRemoveMode' }, + 'allow-preconfig': true } ## # @BLOCK_EXPORT_DELETED: @@ -384,7 +422,7 @@ # block-export-del command, but before the shutdown has # completed) # -# Since: 5.2 +# Since: 5.2 ## { 'struct': 'BlockExportInfo', 'data': { 'id': 'str', @@ -399,4 +437,5 @@ # # Since: 5.2 ## -{ 'command': 'query-block-exports', 'returns': ['BlockExportInfo'] } +{ 'command': 'query-block-exports', 'returns': ['BlockExportInfo'], + 'allow-preconfig': true } diff --git a/qapi/block.json b/qapi/block.json index 82fcf2c914c8..5fe068f903a7 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -50,9 +50,9 @@ # # Type of Floppy drive to be emulated by the Floppy Disk Controller. # -# @144: 1.44MB 3.5" drive -# @288: 2.88MB 3.5" drive -# @120: 1.2MB 5.25" drive +# @144: 1.44MB 3.5" drive +# @288: 2.88MB 3.5" drive +# @120: 1.2MB 5.25" drive # @none: No drive connected # @auto: Automatically determined by inserted media at boot # @@ -105,7 +105,8 @@ # # Returns: - Nothing on success # - If @device is not a valid block device, DeviceNotFound -# Notes: Ejecting a device with no media results in success +# +# Notes: Ejecting a device with no media results in success # # Since: 0.14 # @@ -285,7 +286,6 @@ 'data': { 'id': 'str', 'node-name': 'str'} } - ## # @BlockdevChangeReadOnlyMode: # @@ -299,12 +299,10 @@ # @read-write: Makes the device writable # # Since: 2.3 -# ## { 'enum': 'BlockdevChangeReadOnlyMode', 'data': ['retain', 'read-only', 'read-write'] } - ## # @blockdev-change-medium: # @@ -326,6 +324,11 @@ # @read-only-mode: change the read-only mode of the device; defaults # to 'retain' # +# @force: if false (the default), an eject request through blockdev-open-tray +# will be sent to the guest if it has locked the tray (and the tray +# will not be opened immediately); if true, the tray will be opened +# regardless of whether it is locked. (since 7.1) +# # Features: # @deprecated: Member @device is deprecated. Use @id instead. # @@ -367,9 +370,9 @@ '*id': 'str', 'filename': 'str', '*format': 'str', + '*force': 'bool', '*read-only-mode': 'BlockdevChangeReadOnlyMode' } } - ## # @DEVICE_TRAY_MOVED: # @@ -493,7 +496,8 @@ # <- { "return": {} } ## { 'command': 'block_set_io_throttle', 'boxed': true, - 'data': 'BlockIOThrottle' } + 'data': 'BlockIOThrottle', + 'allow-preconfig': true } ## # @block-latency-histogram-set: @@ -569,4 +573,5 @@ '*boundaries': ['uint64'], '*boundaries-read': ['uint64'], '*boundaries-write': ['uint64'], - '*boundaries-flush': ['uint64'] } } + '*boundaries-flush': ['uint64'] }, + 'allow-preconfig': true } diff --git a/qapi/char.json b/qapi/char.json index 7b421515751b..923dc5056d78 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -216,7 +216,7 @@ # # Configuration info for file chardevs. # -# @in: The name of the input file +# @in: The name of the input file # @out: The name of the output file # @append: Open the file in append mode (default false to # truncate) (Since 2.6) @@ -329,7 +329,6 @@ 'data': { '*signal': 'bool' }, 'base': 'ChardevCommon' } - ## # @ChardevSpiceChannel: # @@ -377,10 +376,10 @@ # # Configuration info for virtual console chardevs. # -# @width: console width, in pixels +# @width: console width, in pixels # @height: console height, in pixels -# @cols: console width, in chars -# @rows: console height, in chars +# @cols: console width, in chars +# @rows: console height, in chars # # Since: 1.5 ## @@ -413,7 +412,6 @@ # @clipboard: enable/disable clipboard, default is disabled. # # Since: 6.1 -# ## { 'struct': 'ChardevQemuVDAgent', 'data': { '*mouse': 'bool', diff --git a/qapi/common.json b/qapi/common.json index 412cc4f5aed0..356db3f67051 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -192,7 +192,6 @@ # Keys to toggle input-linux between host and guest. # # Since: 4.0 -# ## { 'enum': 'GrabToggleKeys', 'data': [ 'ctrl-ctrl', 'alt-alt', 'shift-shift','meta-meta', 'scrolllock', @@ -204,7 +203,6 @@ # @human-readable-text: Formatted output intended for humans. # # Since: 6.2 -# ## { 'struct': 'HumanReadableText', 'data': { 'human-readable-text': 'str' } } diff --git a/qapi/control.json b/qapi/control.json index 71a838d49ec5..afca2043af2f 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -33,7 +33,6 @@ # all the QMP capabilities will be turned off by default. # # Since: 0.13 -# ## { 'command': 'qmp_capabilities', 'data': { '*enable': [ 'QMPCapability' ] }, @@ -49,7 +48,6 @@ # (Please refer to qmp-spec.txt for more information on OOB) # # Since: 2.12 -# ## { 'enum': 'QMPCapability', 'data': [ 'oob' ] } @@ -70,7 +68,6 @@ { 'struct': 'VersionTriple', 'data': {'major': 'int', 'minor': 'int', 'micro': 'int'} } - ## # @VersionInfo: # @@ -195,14 +192,14 @@ # # Options to be used for adding a new monitor. # -# @id: Name of the monitor +# @id: Name of the monitor # -# @mode: Selects the monitor mode (default: readline in the system -# emulator, control in qemu-storage-daemon) +# @mode: Selects the monitor mode (default: readline in the system +# emulator, control in qemu-storage-daemon) # -# @pretty: Enables pretty printing (QMP only) +# @pretty: Enables pretty printing (QMP only) # -# @chardev: Name of a character device to expose the monitor on +# @chardev: Name of a character device to expose the monitor on # # Since: 5.0 ## diff --git a/qapi/crypto.json b/qapi/crypto.json index 1ec54c15ca5f..653e6e3f3de2 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -24,7 +24,6 @@ 'prefix': 'QCRYPTO_TLS_CREDS_ENDPOINT', 'data': ['client', 'server']} - ## # @QCryptoSecretFormat: # @@ -32,13 +31,13 @@ # # @raw: raw bytes. When encoded in JSON only valid UTF-8 sequences can be used # @base64: arbitrary base64 encoded binary data +# # Since: 2.6 ## { 'enum': 'QCryptoSecretFormat', 'prefix': 'QCRYPTO_SECRET_FORMAT', 'data': ['raw', 'base64']} - ## # @QCryptoHashAlgorithm: # @@ -51,13 +50,13 @@ # @sha384: SHA-384. (since 2.7) # @sha512: SHA-512. (since 2.7) # @ripemd160: RIPEMD-160. (since 2.7) +# # Since: 2.6 ## { 'enum': 'QCryptoHashAlgorithm', 'prefix': 'QCRYPTO_HASH_ALG', 'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160']} - ## # @QCryptoCipherAlgorithm: # @@ -75,6 +74,7 @@ # @twofish-128: Twofish with 128 bit / 16 byte keys # @twofish-192: Twofish with 192 bit / 24 byte keys # @twofish-256: Twofish with 256 bit / 32 byte keys +# # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm', @@ -85,7 +85,6 @@ 'serpent-128', 'serpent-192', 'serpent-256', 'twofish-128', 'twofish-192', 'twofish-256']} - ## # @QCryptoCipherMode: # @@ -95,13 +94,13 @@ # @cbc: Cipher Block Chaining # @xts: XEX with tweaked code book and ciphertext stealing # @ctr: Counter (Since 2.8) +# # Since: 2.6 ## { 'enum': 'QCryptoCipherMode', 'prefix': 'QCRYPTO_CIPHER_MODE', 'data': ['ecb', 'cbc', 'xts', 'ctr']} - ## # @QCryptoIVGenAlgorithm: # @@ -114,6 +113,7 @@ # @plain: 64-bit sector number truncated to 32-bits # @plain64: 64-bit sector number # @essiv: 64-bit sector number encrypted with a hash of the encryption key +# # Since: 2.6 ## { 'enum': 'QCryptoIVGenAlgorithm', @@ -170,12 +170,12 @@ # @key-secret: the ID of a QCryptoSecret object providing the # decryption key. Mandatory except when probing image for # metadata only. +# # Since: 2.6 ## { 'struct': 'QCryptoBlockOptionsLUKS', 'data': { '*key-secret': 'str' }} - ## # @QCryptoBlockCreateOptionsLUKS: # @@ -194,6 +194,7 @@ # @iter-time: number of milliseconds to spend in # PBKDF passphrase processing. Currently defaults # to 2000. (since 2.8) +# # Since: 2.6 ## { 'struct': 'QCryptoBlockCreateOptionsLUKS', @@ -205,7 +206,6 @@ '*hash-alg': 'QCryptoHashAlgorithm', '*iter-time': 'int'}} - ## # @QCryptoBlockOpenOptions: # @@ -220,7 +220,6 @@ 'data': { 'qcow': 'QCryptoBlockOptionsQCow', 'luks': 'QCryptoBlockOptionsLUKS' } } - ## # @QCryptoBlockCreateOptions: # @@ -235,7 +234,6 @@ 'data': { 'qcow': 'QCryptoBlockOptionsQCow', 'luks': 'QCryptoBlockCreateOptionsLUKS' } } - ## # @QCryptoBlockInfoBase: # @@ -249,7 +247,6 @@ { 'struct': 'QCryptoBlockInfoBase', 'data': { 'format': 'QCryptoBlockFormat' }} - ## # @QCryptoBlockInfoLUKSSlot: # @@ -269,7 +266,6 @@ '*stripes': 'int', 'key-offset': 'int' } } - ## # @QCryptoBlockInfoLUKS: # @@ -315,15 +311,14 @@ # # Defines state of keyslots that are affected by the update # -# @active: The slots contain the given password and marked as active -# @inactive: The slots are erased (contain garbage) and marked as inactive +# @active: The slots contain the given password and marked as active +# @inactive: The slots are erased (contain garbage) and marked as inactive # # Since: 5.1 ## { 'enum': 'QCryptoBlockLUKSKeyslotState', 'data': [ 'active', 'inactive' ] } - ## # @QCryptoBlockAmendOptionsLUKS: # @@ -332,33 +327,32 @@ # # @state: the desired state of the keyslots # -# @new-secret: The ID of a QCryptoSecret object providing the password to be -# written into added active keyslots -# -# @old-secret: Optional (for deactivation only) -# If given will deactivate all keyslots that -# match password located in QCryptoSecret with this ID +# @new-secret: The ID of a QCryptoSecret object providing the password to be +# written into added active keyslots # -# @iter-time: Optional (for activation only) -# Number of milliseconds to spend in -# PBKDF passphrase processing for the newly activated keyslot. -# Currently defaults to 2000. +# @old-secret: Optional (for deactivation only) +# If given will deactivate all keyslots that +# match password located in QCryptoSecret with this ID # -# @keyslot: Optional. ID of the keyslot to activate/deactivate. -# For keyslot activation, keyslot should not be active already -# (this is unsafe to update an active keyslot), -# but possible if 'force' parameter is given. -# If keyslot is not given, first free keyslot will be written. +# @iter-time: Optional (for activation only) +# Number of milliseconds to spend in +# PBKDF passphrase processing for the newly activated keyslot. +# Currently defaults to 2000. # -# For keyslot deactivation, this parameter specifies the exact -# keyslot to deactivate +# @keyslot: Optional. ID of the keyslot to activate/deactivate. +# For keyslot activation, keyslot should not be active already +# (this is unsafe to update an active keyslot), +# but possible if 'force' parameter is given. +# If keyslot is not given, first free keyslot will be written. # -# @secret: Optional. The ID of a QCryptoSecret object providing the -# password to use to retrieve current master key. -# Defaults to the same secret that was used to open the image +# For keyslot deactivation, this parameter specifies the exact +# keyslot to deactivate # +# @secret: Optional. The ID of a QCryptoSecret object providing the +# password to use to retrieve current master key. +# Defaults to the same secret that was used to open the image # -# Since 5.1 +# Since: 5.1 ## { 'struct': 'QCryptoBlockAmendOptionsLUKS', 'data': { 'state': 'QCryptoBlockLUKSKeyslotState', @@ -540,3 +534,67 @@ 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] }, '*sanity-check': 'bool', '*passwordid': 'str' } } +## +# @QCryptoAkCipherAlgorithm: +# +# The supported algorithms for asymmetric encryption ciphers +# +# @rsa: RSA algorithm +# +# Since: 7.1 +## +{ 'enum': 'QCryptoAkCipherAlgorithm', + 'prefix': 'QCRYPTO_AKCIPHER_ALG', + 'data': ['rsa']} + +## +# @QCryptoAkCipherKeyType: +# +# The type of asymmetric keys. +# +# Since: 7.1 +## +{ 'enum': 'QCryptoAkCipherKeyType', + 'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE', + 'data': ['public', 'private']} + +## +# @QCryptoRSAPaddingAlgorithm: +# +# The padding algorithm for RSA. +# +# @raw: no padding used +# @pkcs1: pkcs1#v1.5 +# +# Since: 7.1 +## +{ 'enum': 'QCryptoRSAPaddingAlgorithm', + 'prefix': 'QCRYPTO_RSA_PADDING_ALG', + 'data': ['raw', 'pkcs1']} + +## +# @QCryptoAkCipherOptionsRSA: +# +# Specific parameters for RSA algorithm. +# +# @hash-alg: QCryptoHashAlgorithm +# @padding-alg: QCryptoRSAPaddingAlgorithm +# +# Since: 7.1 +## +{ 'struct': 'QCryptoAkCipherOptionsRSA', + 'data': { 'hash-alg':'QCryptoHashAlgorithm', + 'padding-alg': 'QCryptoRSAPaddingAlgorithm'}} + +## +# @QCryptoAkCipherOptions: +# +# The options that are available for all asymmetric key algorithms +# when creating a new QCryptoAkCipher. +# +# Since: 7.1 +## +{ 'union': 'QCryptoAkCipherOptions', + 'base': { 'alg': 'QCryptoAkCipherAlgorithm' }, + 'discriminator': 'alg', + 'data': { 'rsa': 'QCryptoAkCipherOptionsRSA' }} diff --git a/qapi/dump.json b/qapi/dump.json index 29441af9d868..6fc215dd47b2 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -186,8 +186,8 @@ # # Returns the available formats for dump-guest-memory # -# Returns: A @DumpGuestMemoryCapability object listing available formats for -# dump-guest-memory +# Returns: A @DumpGuestMemoryCapability object listing available formats for +# dump-guest-memory # # Since: 2.0 # @@ -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/job.json b/qapi/job.json index 1a6ef0345154..d5f84e9615ba 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -173,7 +173,6 @@ ## { 'command': 'job-cancel', 'data': { 'id': 'str' } } - ## # @job-complete: # diff --git a/qapi/machine-target.json b/qapi/machine-target.json index f5ec4bc172b0..2e267fa45803 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -54,7 +54,6 @@ { 'enum': 'CpuModelExpansionType', 'data': [ 'static', 'full' ] } - ## # @CpuModelCompareResult: # @@ -324,7 +323,8 @@ 'TARGET_ARM', 'TARGET_I386', 'TARGET_S390X', - 'TARGET_MIPS' ] } } + 'TARGET_MIPS', + 'TARGET_LOONGARCH64' ] } } ## # @query-cpu-definitions: @@ -340,4 +340,5 @@ 'TARGET_ARM', 'TARGET_I386', 'TARGET_S390X', - 'TARGET_MIPS' ] } } + 'TARGET_MIPS', + 'TARGET_LOONGARCH64' ] } } diff --git a/qapi/machine.json b/qapi/machine.json index d25a481ce40f..b9228a5e4616 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -30,7 +30,7 @@ ## { 'enum' : 'SysEmuTarget', 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', - 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', + 'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', 'sh4eb', 'sparc', 'sparc64', 'tricore', @@ -77,7 +77,6 @@ # additional fields will be listed (since 3.0) # # Since: 2.12 -# ## { 'union' : 'CpuInfoFast', 'base' : { 'cpu-index' : 'int', @@ -299,6 +298,7 @@ # returning does not indicate that a guest has accepted the request or # that it has shut down. Many guests will respond to this command by # prompting the user in some way. +# # Example: # # -> { "execute": "system_powerdown" } @@ -315,9 +315,9 @@ # query-current-machine), wake-up guest from suspend if the guest is # in SUSPENDED state. Return an error otherwise. # -# Since: 1.1 +# Since: 1.1 # -# Returns: nothing. +# Returns: nothing. # # Note: prior to 4.0, this command does nothing in case the guest # isn't suspended. @@ -368,9 +368,9 @@ # Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or all CPUs (ppc64). # The command fails when the guest doesn't support injecting. # -# Returns: If successful, nothing +# Returns: If successful, nothing # -# Since: 0.14 +# Since: 0.14 # # Note: prior to 2.1, this command was only supported for x86 and s390 VMs # @@ -502,6 +502,40 @@ 'dst': 'uint16', 'val': 'uint8' }} +## +# @CXLFixedMemoryWindowOptions: +# +# Create a CXL Fixed Memory Window +# +# @size: Size of the Fixed Memory Window in bytes. Must be a multiple +# of 256MiB. +# @interleave-granularity: Number of contiguous bytes for which +# accesses will go to a given interleave target. +# Accepted values [256, 512, 1k, 2k, 4k, 8k, 16k] +# @targets: Target root bridge IDs from -device ...,id= for each root +# bridge. +# +# Since 7.1 +## +{ 'struct': 'CXLFixedMemoryWindowOptions', + 'data': { + 'size': 'size', + '*interleave-granularity': 'size', + 'targets': ['str'] }} + +## +# @CXLFMWProperties: +# +# List of CXL Fixed Memory Windows. +# +# @cxl-fmw: List of CXLFixedMemoryWindowOptions +# +# Since 7.1 +## +{ 'struct' : 'CXLFMWProperties', + 'data': { 'cxl-fmw': ['CXLFixedMemoryWindowOptions'] } +} + ## # @X86CPURegister32: # @@ -868,10 +902,11 @@ # @node-id: NUMA node ID the CPU belongs to # @socket-id: socket number within node/board the CPU belongs to # @die-id: die number within socket the CPU belongs to (since 4.1) -# @core-id: core number within die the CPU belongs to +# @cluster-id: cluster number within die the CPU belongs to (since 7.1) +# @core-id: core number within cluster the CPU belongs to # @thread-id: thread number within core the CPU belongs to # -# Note: currently there are 5 properties that could be present +# Note: currently there are 6 properties that could be present # but management should be prepared to pass through other # properties with device_add command to allow for future # interface extension. This also requires the filed names to be kept in @@ -883,6 +918,7 @@ 'data': { '*node-id': 'int', '*socket-id': 'int', '*die-id': 'int', + '*cluster-id': 'int', '*core-id': 'int', '*thread-id': 'int' } @@ -922,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]"} # ]}' # @@ -970,7 +1006,7 @@ # preconfigure stage to configure numa mapping before initializing # machine. # -# Since 3.0 +# Since: 3.0 ## { 'command': 'set-numa-node', 'boxed': true, 'data': 'NumaOptions', @@ -1019,7 +1055,6 @@ # Formula used: logical_vm_size = vm_ram_size - balloon_size # # Since: 0.14 -# ## { 'struct': 'BalloonInfo', 'data': {'actual': 'int' } } @@ -1039,7 +1074,7 @@ # # -> { "execute": "query-balloon" } # <- { "return": { -# "actual": 1073741824, +# "actual": 1073741824 # } # } # @@ -1364,7 +1399,6 @@ { 'event': 'MEMORY_DEVICE_SIZE_CHANGE', 'data': { '*id': 'str', 'size': 'size', 'qom-path' : 'str'} } - ## # @MEM_UNPLUG_ERROR: # @@ -1382,7 +1416,7 @@ # # Example: # -# <- { "event": "MEM_UNPLUG_ERROR" +# <- { "event": "MEM_UNPLUG_ERROR", # "data": { "device": "dimm1", # "msg": "acpi: device unplug for unsupported device" # }, @@ -1393,6 +1427,36 @@ 'data': { 'device': 'str', 'msg': 'str' }, 'features': ['deprecated'] } +## +# @BootConfiguration: +# +# Schema for virtual machine boot configuration. +# +# @order: Boot order (a=floppy, c=hard disk, d=CD-ROM, n=network) +# +# @once: Boot order to apply on first boot +# +# @menu: Whether to show a boot menu +# +# @splash: The name of the file to be passed to the firmware as logo picture, if @menu is true. +# +# @splash-time: How long to show the logo picture, in milliseconds +# +# @reboot-timeout: Timeout before guest reboots after boot fails +# +# @strict: Whether to attempt booting from devices not included in the boot order +# +# Since: 7.1 +## +{ 'struct': 'BootConfiguration', 'data': { + '*order': 'str', + '*once': 'str', + '*menu': 'bool', + '*splash': 'str', + '*splash-time': 'int', + '*reboot-timeout': 'int', + '*strict': 'bool' } } + ## # @SMPConfiguration: # @@ -1582,3 +1646,39 @@ ## { 'enum': 'SmbiosEntryPointType', 'data': [ '32', '64' ] } + +## +# @MemorySizeConfiguration: +# +# Schema for memory size configuration. +# +# @size: memory size in bytes +# +# @max-size: maximum hotpluggable memory size in bytes +# +# @slots: number of available memory slots for hotplug +# +# Since: 7.1 +## +{ 'struct': 'MemorySizeConfiguration', 'data': { + '*size': 'size', + '*max-size': 'size', + '*slots': 'uint64' } } + +## +# @dumpdtb: +# +# Save the FDT in dtb format. +# +# @filename: name of the dtb file to be created +# +# Since: 7.2 +# +# Example: +# {"execute": "dumpdtb"} +# "arguments": { "filename": "fdt.dtb" } } +# +## +{ 'command': 'dumpdtb', + 'data': { 'filename': 'str' }, + 'if': 'CONFIG_FDT' } diff --git a/qapi/meson.build b/qapi/meson.build index 656ef0e039ff..fbdb442fdf46 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -13,7 +13,7 @@ util_ss.add(files( if have_system util_ss.add(files('qapi-type-helpers.c')) endif -if have_system or have_tools +if have_system or have_tools or have_ga util_ss.add(files( 'qmp-dispatch.c', 'qmp-event.c', @@ -46,8 +46,10 @@ qapi_all_modules = [ 'replay', 'run-state', 'sockets', + 'stats', 'trace', 'transaction', + 'virtio', 'yank', ] if have_system @@ -67,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 27d7b281581d..88ecf86ac876 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -55,6 +55,10 @@ # @postcopy-bytes: The number of bytes sent during the post-copy phase # (since 7.0). # +# @dirty-sync-missed-zero-copy: Number of times dirty RAM synchronization could +# not avoid copying dirty pages. This is between +# 0 and @dirty-sync-count * @multifd-channels. +# (since 7.1) # Since: 0.14 ## { 'struct': 'MigrationStats', @@ -65,7 +69,8 @@ 'postcopy-requests' : 'int', 'page-size' : 'int', 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64', 'precopy-bytes' : 'uint64', 'downtime-bytes' : 'uint64', - 'postcopy-bytes' : 'uint64' } } + 'postcopy-bytes' : 'uint64', + 'dirty-sync-missed-zero-copy' : 'uint64' } } ## # @XBZRLECacheStats: @@ -151,7 +156,6 @@ # (since 4.2) # # Since: 2.3 -# ## { 'enum': 'MigrationStatus', 'data': [ 'none', 'setup', 'cancelling', 'cancelled', @@ -166,7 +170,6 @@ # @transferred: amount of bytes transferred to the target VM by VFIO devices # # Since: 5.2 -# ## { 'struct': 'VfioStats', 'data': {'transferred': 'int' } } @@ -463,6 +466,18 @@ # procedure starts. The VM RAM is saved with running VM. # (since 6.0) # +# @zero-copy-send: Controls behavior on sending memory pages on migration. +# When true, enables a zero-copy mechanism for sending +# memory pages, if host supports it. +# Requires that QEMU be permitted to use locked memory +# for guest RAM pages. +# (since 7.1) +# @postcopy-preempt: If enabled, the migration process will allow postcopy +# requests to preempt precopy stream, so postcopy requests +# will be handled faster. This is a performance feature and +# should not affect the correctness of postcopy migration. +# (since 7.1) +# # Features: # @unstable: Members @x-colo and @x-ignore-shared are experimental. # @@ -476,7 +491,8 @@ 'block', 'return-path', 'pause-before-switchover', 'multifd', 'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate', { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] }, - 'validate-uuid', 'background-snapshot'] } + 'validate-uuid', 'background-snapshot', + 'zero-copy-send', 'postcopy-preempt'] } ## # @MigrationCapabilityStatus: @@ -546,7 +562,6 @@ # @zstd: use zstd compression method. # # Since: 5.0 -# ## { 'enum': 'MultiFDCompression', 'data': [ 'none', 'zlib', @@ -741,6 +756,7 @@ # will consume more CPU. # Defaults to 1. (Since 5.0) # +# # @block-bitmap-mapping: Maps block nodes and bitmaps on them to # aliases for the purpose of dirty bitmap migration. Such # aliases may for example be the corresponding names on the @@ -1194,10 +1210,10 @@ # ask the client to automatically reconnect using the new parameters # once migration finished successfully. Only implemented for SPICE. # -# @protocol: must be "spice" -# @hostname: migration target hostname -# @port: spice tcp port for plaintext channels -# @tls-port: spice tcp port for tls-secured channels +# @protocol: must be "spice" +# @hostname: migration target hostname +# @port: spice tcp port for plaintext channels +# @tls-port: spice tcp port for tls-secured channels # @cert-subject: server certificate subject # # Since: 0.14 @@ -1422,7 +1438,9 @@ # @state: The state the migration is currently expected to be in # # Returns: nothing on success +# # Since: 2.11 +# # Example: # # -> { "execute": "migrate-continue" , "arguments": @@ -1619,7 +1637,7 @@ # # Query replication status while the vm is running. # -# Returns: A @ReplicationResult object showing the status. +# Returns: A @ReplicationStatus object showing the status. # # Example: # @@ -1736,6 +1754,7 @@ # Since: 4.2 # # Example: +# # <- { "event": "UNPLUG_PRIMARY", # "data": { "device-id": "hostdev0" }, # "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } @@ -1754,7 +1773,6 @@ # @dirty-rate: dirty rate. # # Since: 6.2 -# ## { 'struct': 'DirtyRateVcpu', 'data': { 'id': 'int', 'dirty-rate': 'int64' } } @@ -1771,7 +1789,6 @@ # @measured: the dirtyrate thread has measured and results are available. # # Since: 5.2 -# ## { 'enum': 'DirtyRateStatus', 'data': [ 'unstarted', 'measuring', 'measured'] } @@ -1788,7 +1805,6 @@ # @dirty-bitmap: calculate dirtyrate by dirty bitmap. # # Since: 6.2 -# ## { 'enum': 'DirtyRateMeasureMode', 'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] } @@ -1818,7 +1834,6 @@ # mode specified (Since 6.2) # # Since: 5.2 -# ## { 'struct': 'DirtyRateInfo', 'data': {'*dirty-rate': 'int64', @@ -1845,6 +1860,7 @@ # Since: 5.2 # # Example: +# # {"execute": "calc-dirty-rate", "arguments": {"calc-time": 1, # 'sample-pages': 512} } # @@ -1862,6 +1878,86 @@ ## { 'command': 'query-dirty-rate', 'returns': 'DirtyRateInfo' } +## +# @DirtyLimitInfo: +# +# Dirty page rate limit information of a virtual CPU. +# +# @cpu-index: index of a virtual CPU. +# +# @limit-rate: upper limit of dirty page rate (MB/s) for a virtual +# CPU, 0 means unlimited. +# +# @current-rate: current dirty page rate (MB/s) for a virtual CPU. +# +# Since: 7.1 +# +## +{ 'struct': 'DirtyLimitInfo', + 'data': { 'cpu-index': 'int', + 'limit-rate': 'uint64', + 'current-rate': 'uint64' } } + +## +# @set-vcpu-dirty-limit: +# +# Set the upper limit of dirty page rate for virtual CPUs. +# +# Requires KVM with accelerator property "dirty-ring-size" set. +# A virtual CPU's dirty page rate is a measure of its memory load. +# To observe dirty page rates, use @calc-dirty-rate. +# +# @cpu-index: index of a virtual CPU, default is all. +# +# @dirty-rate: upper limit of dirty page rate (MB/s) for virtual CPUs. +# +# Since: 7.1 +# +# Example: +# {"execute": "set-vcpu-dirty-limit"} +# "arguments": { "dirty-rate": 200, +# "cpu-index": 1 } } +# +## +{ 'command': 'set-vcpu-dirty-limit', + 'data': { '*cpu-index': 'int', + 'dirty-rate': 'uint64' } } + +## +# @cancel-vcpu-dirty-limit: +# +# Cancel the upper limit of dirty page rate for virtual CPUs. +# +# Cancel the dirty page limit for the vCPU which has been set with +# set-vcpu-dirty-limit command. Note that this command requires +# support from dirty ring, same as the "set-vcpu-dirty-limit". +# +# @cpu-index: index of a virtual CPU, default is all. +# +# Since: 7.1 +# +# Example: +# {"execute": "cancel-vcpu-dirty-limit"} +# "arguments": { "cpu-index": 1 } } +# +## +{ 'command': 'cancel-vcpu-dirty-limit', + 'data': { '*cpu-index': 'int'} } + +## +# @query-vcpu-dirty-limit: +# +# Returns information about virtual CPU dirty page rate limits, if any. +# +# Since: 7.1 +# +# Example: +# {"execute": "query-vcpu-dirty-limit"} +# +## +{ 'command': 'query-vcpu-dirty-limit', + 'returns': [ 'DirtyLimitInfo' ] } + ## # @snapshot-save: # @@ -1899,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, @@ -1960,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, @@ -2012,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/misc-target.json b/qapi/misc-target.json index 036c5e4a9141..5b6a8e91850a 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -21,7 +21,6 @@ { 'command': 'rtc-reset-reinjection', 'if': 'TARGET_I386' } - ## # @SevState: # @@ -101,7 +100,6 @@ { 'command': 'query-sev', 'returns': 'SevInfo', 'if': 'TARGET_I386' } - ## # @SevLaunchMeasureInfo: # @@ -110,7 +108,6 @@ # @data: the measurement value encoded in base64 # # Since: 2.12 -# ## { 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'}, 'if': 'TARGET_I386' } @@ -133,16 +130,17 @@ { 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo', 'if': 'TARGET_I386' } - ## # @SevCapability: # # The struct describes capability for a Secure Encrypted Virtualization # feature. # -# @pdh: Platform Diffie-Hellman key (base64 encoded) +# @pdh: Platform Diffie-Hellman key (base64 encoded) +# +# @cert-chain: PDH certificate chain (base64 encoded) # -# @cert-chain: PDH certificate chain (base64 encoded) +# @cpu0-id: Unique ID of CPU0 (base64 encoded) (since 7.1) # # @cbitpos: C-bit location in page table entry # @@ -154,6 +152,7 @@ { 'struct': 'SevCapability', 'data': { 'pdh': 'str', 'cert-chain': 'str', + 'cpu0-id': 'str', 'cbitpos': 'int', 'reduced-phys-bits': 'int'}, 'if': 'TARGET_I386' } @@ -172,6 +171,7 @@ # # -> { "execute": "query-sev-capabilities" } # <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE", +# "cpu0-id": "2lvmGwo+...61iEinw==", # "cbitpos": 47, "reduced-phys-bits": 5}} # ## @@ -190,7 +190,6 @@ # @gpa: the guest physical address where secret will be injected. # # Since: 6.0 -# ## { 'command': 'sev-inject-launch-secret', 'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' }, @@ -202,8 +201,7 @@ # The struct describes attestation report for a Secure Encrypted # Virtualization feature. # -# @data: guest attestation report (base64 encoded) -# +# @data: guest attestation report (base64 encoded) # # Since: 6.1 ## @@ -303,7 +301,6 @@ { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'], 'if': 'TARGET_ARM' } - ## # @SGXEPCSection: # @@ -332,14 +329,8 @@ # # @flc: true if FLC is supported # -# @section-size: The EPC section size for guest -# Redundant with @sections. Just for backward compatibility. -# # @sections: The EPC sections info for guest (Since: 7.0) # -# Features: -# @deprecated: Member @section-size is deprecated. Use @sections instead. -# # Since: 6.2 ## { 'struct': 'SGXInfo', @@ -347,8 +338,6 @@ 'sgx1': 'bool', 'sgx2': 'bool', 'flc': 'bool', - 'section-size': { 'type': 'uint64', - 'features': [ 'deprecated' ] }, 'sections': ['SGXEPCSection']}, 'if': 'TARGET_I386' } @@ -365,7 +354,7 @@ # # -> { "execute": "query-sgx" } # <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, -# "flc": true, "section-size" : 96468992, +# "flc": true, # "sections": [{"node": 0, "size": 67108864}, # {"node": 1, "size": 29360128}]} } # @@ -385,7 +374,7 @@ # # -> { "execute": "query-sgx-capabilities" } # <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, -# "flc": true, "section-size" : 96468992, +# "flc": true, # "section" : [{"node": 0, "size": 67108864}, # {"node": 1, "size": 29360128}]} } # diff --git a/qapi/misc.json b/qapi/misc.json index b83cc3902988..27ef5a2b2029 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -136,7 +136,7 @@ # # Stop all guest VCPU execution. # -# Since: 0.14 +# Since: 0.14 # # Notes: This function will succeed even if the guest is already in the stopped # state. In "inmigrate" state, it will ensure that the guest @@ -156,9 +156,9 @@ # # Resume guest VCPU execution. # -# Since: 0.14 +# Since: 0.14 # -# Returns: If successful, nothing +# Returns: If successful, nothing # # Notes: This command will succeed if the guest is currently running. It # will also succeed if the guest is in the "inmigrate" state; in @@ -188,7 +188,7 @@ # Features: # @unstable: This command is experimental. # -# Since 3.0 +# Since: 3.0 # # Returns: nothing # @@ -553,3 +553,34 @@ ## { 'event': 'RTC_CHANGE', 'data': { 'offset': 'int', 'qom-path': 'str' } } + +## +# @VFU_CLIENT_HANGUP: +# +# Emitted when the client of a TYPE_VFIO_USER_SERVER closes the +# communication channel +# +# @vfu-id: ID of the TYPE_VFIO_USER_SERVER object. It is the last component +# of @vfu-qom-path referenced below +# +# @vfu-qom-path: path to the TYPE_VFIO_USER_SERVER object in the QOM tree +# +# @dev-id: ID of attached PCI device +# +# @dev-qom-path: path to attached PCI device in the QOM tree +# +# Since: 7.1 +# +# Example: +# +# <- { "event": "VFU_CLIENT_HANGUP", +# "data": { "vfu-id": "vfu1", +# "vfu-qom-path": "/objects/vfu1", +# "dev-id": "sas1", +# "dev-qom-path": "/machine/peripheral/sas1" }, +# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } +# +## +{ 'event': 'VFU_CLIENT_HANGUP', + 'data': { 'vfu-id': 'str', 'vfu-qom-path': 'str', + 'dev-id': 'str', 'dev-qom-path': 'str' } } diff --git a/qapi/net.json b/qapi/net.json index b92f3f5fb444..522ac582edeb 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -7,6 +7,7 @@ ## { 'include': 'common.json' } +{ 'include': 'sockets.json' } ## # @set_link: @@ -298,7 +299,7 @@ # # @udp: use the udp version of l2tpv3 encapsulation # -# @cookie64: use 64 bit coookies +# @cookie64: use 64 bit cookies # # @counter: have sequence counter # @@ -442,15 +443,193 @@ # @vhostdev: path of vhost-vdpa device # (default:'/dev/vhost-vdpa-0') # +# @vhostfd: file descriptor of an already opened vhost vdpa device +# # @queues: number of queues to be created for multiqueue vhost-vdpa # (default: 1) # +# @x-svq: Start device with (experimental) shadow virtqueue. (Since 7.1) +# (default: false) +# +# Features: +# @unstable: Member @x-svq is experimental. +# # Since: 5.1 ## { 'struct': 'NetdevVhostVDPAOptions', 'data': { '*vhostdev': 'str', - '*queues': 'int' } } + '*vhostfd': 'str', + '*queues': 'int', + '*x-svq': {'type': 'bool', 'features' : [ 'unstable'] } } } + +## +# @NetdevVmnetHostOptions: +# +# vmnet (host mode) network backend. +# +# Allows the vmnet interface to communicate with other vmnet +# interfaces that are in host mode and also with the host. +# +# @start-address: The starting IPv4 address to use for the interface. +# Must be in the private IP range (RFC 1918). Must be +# specified along with @end-address and @subnet-mask. +# This address is used as the gateway address. The +# subsequent address up to and including end-address are +# placed in the DHCP pool. +# +# @end-address: The DHCP IPv4 range end address to use for the +# interface. Must be in the private IP range (RFC 1918). +# Must be specified along with @start-address and +# @subnet-mask. +# +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must +# be specified along with @start-address and @subnet-mask. +# +# @isolated: Enable isolation for this interface. Interface isolation +# ensures that vmnet interface is not able to communicate +# with any other vmnet interfaces. Only communication with +# host is allowed. Requires at least macOS Big Sur 11.0. +# +# @net-uuid: The identifier (UUID) to uniquely identify the isolated +# network vmnet interface should be added to. If +# set, no DHCP service is provided for this interface and +# network communication is allowed only with other interfaces +# added to this network identified by the UUID. Requires +# at least macOS Big Sur 11.0. +# +# Since: 7.1 +## +{ 'struct': 'NetdevVmnetHostOptions', + 'data': { + '*start-address': 'str', + '*end-address': 'str', + '*subnet-mask': 'str', + '*isolated': 'bool', + '*net-uuid': 'str' }, + 'if': 'CONFIG_VMNET' } + +## +# @NetdevVmnetSharedOptions: +# +# vmnet (shared mode) network backend. +# +# Allows traffic originating from the vmnet interface to reach the +# Internet through a network address translator (NAT). +# The vmnet interface can communicate with the host and with +# other shared mode interfaces on the same subnet. If no DHCP +# settings, subnet mask and IPv6 prefix specified, the interface can +# communicate with any of other interfaces in shared mode. +# +# @start-address: The starting IPv4 address to use for the interface. +# Must be in the private IP range (RFC 1918). Must be +# specified along with @end-address and @subnet-mask. +# This address is used as the gateway address. The +# subsequent address up to and including end-address are +# placed in the DHCP pool. +# +# @end-address: The DHCP IPv4 range end address to use for the +# interface. Must be in the private IP range (RFC 1918). +# Must be specified along with @start-address and @subnet-mask. +# +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must +# be specified along with @start-address and @subnet-mask. +# +# @isolated: Enable isolation for this interface. Interface isolation +# ensures that vmnet interface is not able to communicate +# with any other vmnet interfaces. Only communication with +# host is allowed. Requires at least macOS Big Sur 11.0. +# +# @nat66-prefix: The IPv6 prefix to use into guest network. Must be a +# unique local address i.e. start with fd00::/8 and have +# length of 64. +# +# Since: 7.1 +## +{ 'struct': 'NetdevVmnetSharedOptions', + 'data': { + '*start-address': 'str', + '*end-address': 'str', + '*subnet-mask': 'str', + '*isolated': 'bool', + '*nat66-prefix': 'str' }, + 'if': 'CONFIG_VMNET' } + +## +# @NetdevVmnetBridgedOptions: +# +# vmnet (bridged mode) network backend. +# +# Bridges the vmnet interface with a physical network interface. +# +# @ifname: The name of the physical interface to be bridged. +# +# @isolated: Enable isolation for this interface. Interface isolation +# ensures that vmnet interface is not able to communicate +# with any other vmnet interfaces. Only communication with +# host is allowed. Requires at least macOS Big Sur 11.0. +# +# Since: 7.1 +## +{ 'struct': 'NetdevVmnetBridgedOptions', + 'data': { + 'ifname': 'str', + '*isolated': 'bool' }, + 'if': 'CONFIG_VMNET' } + +## +# @NetdevStreamOptions: +# +# Configuration info for stream socket netdev +# +# @addr: socket address to listen on (server=true) +# or connect to (server=false) +# @server: create server socket (default: false) +# +# Only SocketAddress types 'unix', 'inet' and 'fd' are supported. +# +# Since: 7.2 +## +{ 'struct': 'NetdevStreamOptions', + 'data': { + 'addr': 'SocketAddress', + '*server': 'bool' } } + +## +# @NetdevDgramOptions: +# +# Configuration info for datagram socket netdev. +# +# @remote: remote address +# @local: local address +# +# Only SocketAddress types 'unix', 'inet' and 'fd' are supported. +# +# If remote address is present and it's a multicast address, local address +# is optional. Otherwise local address is required and remote address is +# optional. +# +# .. table:: Valid parameters combination table +# :widths: auto +# +# ============= ======== ===== +# remote local okay? +# ============= ======== ===== +# absent absent no +# absent not fd no +# absent fd yes +# multicast absent yes +# multicast present yes +# not multicast absent no +# not multicast present yes +# ============= ======== ===== +# +# Since: 7.2 +## +{ 'struct': 'NetdevDgramOptions', + 'data': { + '*local': 'SocketAddress', + '*remote': 'SocketAddress' } } ## # @NetClientDriver: @@ -460,10 +639,19 @@ # Since: 2.7 # # @vhost-vdpa since 5.1 +# @vmnet-host since 7.1 +# @vmnet-shared since 7.1 +# @vmnet-bridged since 7.1 +# @stream since 7.2 +# @dgram since 7.2 ## { 'enum': 'NetClientDriver', - 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', - 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa' ] } + 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'stream', + 'dgram', 'vde', 'bridge', 'hubport', 'netmap', 'vhost-user', + 'vhost-vdpa', + { 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' }, + { 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' }, + { 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] } ## # @Netdev: @@ -477,6 +665,11 @@ # Since: 1.2 # # 'l2tpv3' - since 2.1 +# 'vmnet-host' - since 7.1 +# 'vmnet-shared' - since 7.1 +# 'vmnet-bridged' - since 7.1 +# 'stream' since 7.2 +# 'dgram' since 7.2 ## { 'union': 'Netdev', 'base': { 'id': 'str', 'type': 'NetClientDriver' }, @@ -487,12 +680,20 @@ 'tap': 'NetdevTapOptions', 'l2tpv3': 'NetdevL2TPv3Options', 'socket': 'NetdevSocketOptions', + 'stream': 'NetdevStreamOptions', + 'dgram': 'NetdevDgramOptions', 'vde': 'NetdevVdeOptions', 'bridge': 'NetdevBridgeOptions', 'hubport': 'NetdevHubPortOptions', 'netmap': 'NetdevNetmapOptions', 'vhost-user': 'NetdevVhostUserOptions', - 'vhost-vdpa': 'NetdevVhostVDPAOptions' } } + 'vhost-vdpa': 'NetdevVhostVDPAOptions', + 'vmnet-host': { 'type': 'NetdevVmnetHostOptions', + 'if': 'CONFIG_VMNET' }, + 'vmnet-shared': { 'type': 'NetdevVmnetSharedOptions', + 'if': 'CONFIG_VMNET' }, + 'vmnet-bridged': { 'type': 'NetdevVmnetBridgedOptions', + 'if': 'CONFIG_VMNET' } } } ## # @RxState: @@ -621,7 +822,6 @@ # "data": { "name": "vnet0", # "path": "/machine/peripheral/vnet0/virtio-backend" }, # "timestamp": { "seconds": 1368697518, "microseconds": 326866 } } -# } # ## { 'event': 'NIC_RX_FILTER_CHANGED', @@ -698,3 +898,52 @@ ## { 'event': 'FAILOVER_NEGOTIATED', 'data': {'device-id': 'str'} } + +## +# @NETDEV_STREAM_CONNECTED: +# +# Emitted when the netdev stream backend is connected +# +# @netdev-id: QEMU netdev id that is connected +# @addr: The destination address +# +# Since: 7.2 +# +# Example: +# +# <- { "event": "NETDEV_STREAM_CONNECTED", +# "data": { "netdev-id": "netdev0", +# "addr": { "port": "47666", "ipv6": true, +# "host": "::1", "type": "inet" } }, +# "timestamp": { "seconds": 1666269863, "microseconds": 311222 } } +# +# or +# +# <- { "event": "NETDEV_STREAM_CONNECTED", +# "data": { "netdev-id": "netdev0", +# "addr": { "path": "/tmp/qemu0", "type": "unix" } }, +# "timestamp": { "seconds": 1666269706, "microseconds": 413651 } } +# +## +{ 'event': 'NETDEV_STREAM_CONNECTED', + 'data': { 'netdev-id': 'str', + 'addr': 'SocketAddress' } } + +## +# @NETDEV_STREAM_DISCONNECTED: +# +# Emitted when the netdev stream backend is disconnected +# +# @netdev-id: QEMU netdev id that is disconnected +# +# Since: 7.2 +# +# Example: +# +# <- { 'event': 'NETDEV_STREAM_DISCONNECTED', +# 'data': {'netdev-id': 'netdev0'}, +# 'timestamp': {'seconds': 1663330937, 'microseconds': 526695} } +# +## +{ 'event': 'NETDEV_STREAM_DISCONNECTED', + 'data': { 'netdev-id': 'str' } } diff --git a/qapi/pragma.json b/qapi/pragma.json index e6a021c19cf9..7f810b0e977b 100644 --- a/qapi/pragma.json +++ b/qapi/pragma.json @@ -6,7 +6,7 @@ # Whitelists to permit QAPI rule violations; think twice before you # add to them! { 'pragma': { - # Commands allowed to return a non-dictionary: + # Command names containing '_' 'command-name-exceptions': [ 'add_client', 'block_resize', @@ -24,6 +24,7 @@ 'system_powerdown', 'system_reset', 'system_wakeup' ], + # Commands allowed to return a non-dictionary 'command-returns-exceptions': [ 'human-monitor-command', 'qom-get', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 4912b9744e69..f000b90744fa 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -93,3 +93,5 @@ { 'include': 'audio.json' } { 'include': 'acpi.json' } { 'include': 'pci.json' } +{ 'include': 'stats.json' } +{ 'include': 'virtio.json' } diff --git a/qapi/qdev.json b/qapi/qdev.json index 26cd10106b27..2708fb4e9930 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/qmp-event.c b/qapi/qmp-event.c index 19d3cd003833..0fe0d0a5a6e5 100644 --- a/qapi/qmp-event.c +++ b/qapi/qmp-event.c @@ -20,15 +20,12 @@ static void timestamp_put(QDict *qdict) { - int err; QDict *ts; - qemu_timeval tv; + int64_t rt = g_get_real_time(); - err = qemu_gettimeofday(&tv); - /* Put -1 to indicate failure of getting host time */ ts = qdict_from_jsonf_nofail("{ 'seconds': %lld, 'microseconds': %lld }", - err < 0 ? -1LL : (long long)tv.tv_sec, - err < 0 ? -1LL : (long long)tv.tv_usec); + (long long)rt / G_USEC_PER_SEC, + (long long)rt % G_USEC_PER_SEC); qdict_put(qdict, "timestamp", ts); } diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index f0b4c7ca9d39..3e8aca6b1594 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -28,7 +28,7 @@ #include "qapi/qmp/qnum.h" #include "qapi/qmp/qstring.h" #include "qemu/cutils.h" -#include "qemu/option.h" +#include "qemu/keyval.h" typedef struct StackObject { const char *name; /* Name of @obj in its parent, if any */ diff --git a/qapi/qom.json b/qapi/qom.json index eeb5395ff3b7..30e76653ad28 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -499,6 +499,28 @@ '*repeat': 'bool', '*grab-toggle': 'GrabToggleKeys' } } +## +# @EventLoopBaseProperties: +# +# Common properties for event loops +# +# @aio-max-batch: maximum number of requests in a batch for the AIO engine, +# 0 means that the engine will use its default. +# (default: 0) +# +# @thread-pool-min: minimum number of threads reserved in the thread pool +# (default:0) +# +# @thread-pool-max: maximum number of threads the thread pool can contain +# (default:64) +# +# Since: 7.1 +## +{ 'struct': 'EventLoopBaseProperties', + 'data': { '*aio-max-batch': 'int', + '*thread-pool-min': 'int', + '*thread-pool-max': 'int' } } + ## # @IothreadProperties: # @@ -516,17 +538,26 @@ # algorithm detects it is spending too long polling without # encountering events. 0 selects a default behaviour (default: 0) # -# @aio-max-batch: maximum number of requests in a batch for the AIO engine, -# 0 means that the engine will use its default -# (default:0, since 6.1) +# The @aio-max-batch option is available since 6.1. # # Since: 2.0 ## { 'struct': 'IothreadProperties', + 'base': 'EventLoopBaseProperties', 'data': { '*poll-max-ns': 'int', '*poll-grow': 'int', - '*poll-shrink': 'int', - '*aio-max-batch': 'int' } } + '*poll-shrink': 'int' } } + +## +# @MainLoopProperties: +# +# Properties for the main-loop object. +# +# Since: 7.1 +## +{ 'struct': 'MainLoopProperties', + 'base': 'EventLoopBaseProperties', + 'data': {} } ## # @MemoryBackendProperties: @@ -547,6 +578,9 @@ # # @prealloc-threads: number of CPU threads to use for prealloc (default: 1) # +# @prealloc-context: thread context to use for creation of preallocation threads +# (default: none) (since 7.2) +# # @share: if false, the memory is private to QEMU; if true, it is shared # (default: false) # @@ -555,7 +589,7 @@ # # @size: size of the memory region in bytes # -# @x-use-canonical-path-for-ramblock-id: if true, the canoncial path is used +# @x-use-canonical-path-for-ramblock-id: if true, the canonical path is used # for ramblock-id. Disable this for 4.0 # machine types or older to allow # migration with newer QEMU versions. @@ -577,6 +611,7 @@ '*policy': 'HostMemPolicy', '*prealloc': 'bool', '*prealloc-threads': 'uint32', + '*prealloc-context': 'str', '*share': 'bool', '*reserve': 'bool', 'size': 'size', @@ -703,6 +738,20 @@ { 'struct': 'RemoteObjectProperties', 'data': { 'fd': 'str', 'devid': 'str' } } +## +# @VfioUserServerProperties: +# +# Properties for x-vfio-user-server objects. +# +# @socket: socket to be used by the libvfio-user library +# +# @device: the ID of the device to be emulated at the server +# +# Since: 7.1 +## +{ 'struct': 'VfioUserServerProperties', + 'data': { 'socket': 'SocketAddress', 'device': 'str' } } + ## # @RngProperties: # @@ -785,6 +834,28 @@ 'reduced-phys-bits': 'uint32', '*kernel-hashes': 'bool' } } +## +# @ThreadContextProperties: +# +# Properties for thread context objects. +# +# @cpu-affinity: the list of host CPU numbers used as CPU affinity for all +# threads created in the thread context (default: QEMU main +# thread CPU affinity) +# +# @node-affinity: the list of host node numbers that will be resolved to a +# list of host CPU numbers used as CPU affinity. This is a +# shortcut for specifying the list of host CPU numbers +# belonging to the host nodes manually by setting +# @cpu-affinity. (default: QEMU main thread affinity) +# +# Since: 7.2 +## +{ 'struct': 'ThreadContextProperties', + 'data': { '*cpu-affinity': ['uint16'], + '*node-affinity': ['uint16'] } } + + ## # @ObjectType: # @@ -805,6 +876,7 @@ 'colo-compare', 'cryptodev-backend', 'cryptodev-backend-builtin', + 'cryptodev-backend-lkcf', { 'name': 'cryptodev-vhost-user', 'if': 'CONFIG_VHOST_CRYPTO' }, 'dbus-vmstate', @@ -818,6 +890,7 @@ { 'name': 'input-linux', 'if': 'CONFIG_LINUX' }, 'iothread', + 'main-loop', { 'name': 'memory-backend-epc', 'if': 'CONFIG_LINUX' }, 'memory-backend-file', @@ -836,13 +909,15 @@ { 'name': 'secret_keyring', 'if': 'CONFIG_SECRET_KEYRING' }, 'sev-guest', + 'thread-context', 's390-pv-guest', 'throttle-group', 'tls-creds-anon', 'tls-creds-psk', 'tls-creds-x509', 'tls-cipher-suites', - { 'name': 'x-remote-object', 'features': [ 'unstable' ] } + { 'name': 'x-remote-object', 'features': [ 'unstable' ] }, + { 'name': 'x-vfio-user-server', 'features': [ 'unstable' ] } ] } ## @@ -870,6 +945,7 @@ 'colo-compare': 'ColoCompareProperties', 'cryptodev-backend': 'CryptodevBackendProperties', 'cryptodev-backend-builtin': 'CryptodevBackendProperties', + 'cryptodev-backend-lkcf': 'CryptodevBackendProperties', 'cryptodev-vhost-user': { 'type': 'CryptodevVhostUserProperties', 'if': 'CONFIG_VHOST_CRYPTO' }, 'dbus-vmstate': 'DBusVMStateProperties', @@ -883,6 +959,7 @@ 'input-linux': { 'type': 'InputLinuxProperties', 'if': 'CONFIG_LINUX' }, 'iothread': 'IothreadProperties', + 'main-loop': 'MainLoopProperties', 'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties', 'if': 'CONFIG_LINUX' }, 'memory-backend-file': 'MemoryBackendFileProperties', @@ -900,12 +977,14 @@ 'secret_keyring': { 'type': 'SecretKeyringProperties', 'if': 'CONFIG_SECRET_KEYRING' }, 'sev-guest': 'SevGuestProperties', + 'thread-context': 'ThreadContextProperties', 'throttle-group': 'ThrottleGroupProperties', 'tls-creds-anon': 'TlsCredsAnonProperties', 'tls-creds-psk': 'TlsCredsPskProperties', 'tls-creds-x509': 'TlsCredsX509Properties', 'tls-cipher-suites': 'TlsCredsProperties', - 'x-remote-object': 'RemoteObjectProperties' + 'x-remote-object': 'RemoteObjectProperties', + 'x-vfio-user-server': 'VfioUserServerProperties' } } ## diff --git a/qapi/replay.json b/qapi/replay.json index 351898f60df5..729470300d69 100644 --- a/qapi/replay.json +++ b/qapi/replay.json @@ -40,7 +40,6 @@ # @icount: current number of executed instructions. # # Since: 5.2 -# ## { 'struct': 'ReplayInfo', 'data': { 'mode': 'ReplayMode', '*filename': 'str', 'icount': 'int' } } diff --git a/qapi/run-state.json b/qapi/run-state.json index 8124220bd979..419c188dd1ad 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -86,12 +86,16 @@ # ignores --no-reboot. This is useful for sanitizing # hypercalls on s390 that are used during kexec/kdump/boot # +# @snapshot-load: A snapshot is being loaded by the record & replay +# subsystem. This value is used only within QEMU. It +# doesn't occur in QMP. (since 7.2) +# ## { 'enum': 'ShutdownCause', # Beware, shutdown_caused_by_guest() depends on enumeration order 'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset', 'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset', - 'guest-panic', 'subsystem-reset'] } + 'guest-panic', 'subsystem-reset', 'snapshot-load'] } ## # @StatusInfo: @@ -104,7 +108,7 @@ # # @status: the virtual machine @RunState # -# Since: 0.14 +# Since: 0.14 # # Notes: @singlestep is enabled through the GDB stub ## @@ -118,7 +122,7 @@ # # Returns: @StatusInfo reflecting all VCPUs # -# Since: 0.14 +# Since: 0.14 # # Example: # @@ -348,7 +352,7 @@ # # @poweroff: Shutdown the VM and exit # -# @pause: pause the VM# +# @pause: pause the VM # # Since: 6.0 ## @@ -364,10 +368,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: @@ -592,13 +599,11 @@ # @guest: memory failure at guest memory, # # Since: 5.2 -# ## { 'enum': 'MemoryFailureRecipient', 'data': [ 'hypervisor', 'guest' ] } - ## # @MemoryFailureAction: # @@ -619,7 +624,6 @@ # to handle memory failures. # # Since: 5.2 -# ## { 'enum': 'MemoryFailureAction', 'data': [ 'ignore', @@ -639,8 +643,24 @@ # failure was still in progress. # # Since: 5.2 -# ## { 'struct': 'MemoryFailureFlags', 'data': { 'action-required': 'bool', 'recursive': 'bool'} } + +## +# @NotifyVmexitOption: +# +# An enumeration of the options specified when enabling notify VM exit +# +# @run: enable the feature, do nothing and continue if the notify VM exit happens. +# +# @internal-error: enable the feature, raise a internal error if the notify +# VM exit happens. +# +# @disable: disable the feature. +# +# Since: 7.2 +## +{ 'enum': 'NotifyVmexitOption', + 'data': [ 'run', 'internal-error', 'disable' ] } \ No newline at end of file diff --git a/qapi/sockets.json b/qapi/sockets.json index 5773d9fcc424..bad74e34d38c 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -149,7 +149,7 @@ # # Note: This type is deprecated in favor of SocketAddress. The # difference between SocketAddressLegacy and SocketAddress is that the -# latter is has fewer {} on the wire. +# latter has fewer {} on the wire. # # Since: 1.3 ## @@ -167,9 +167,9 @@ # # Available SocketAddress types # -# @inet: Internet address +# @inet: Internet address # -# @unix: Unix domain socket +# @unix: Unix domain socket # # @vsock: VMCI address # @@ -189,7 +189,7 @@ # Captures the address of a socket, which could also be a named file # descriptor # -# @type: Transport type +# @type: Transport type # # Since: 2.9 ## diff --git a/qapi/stats.json b/qapi/stats.json new file mode 100644 index 000000000000..57db5b1c741c --- /dev/null +++ b/qapi/stats.json @@ -0,0 +1,251 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +## +# = Statistics +## + +## +# @StatsType: +# +# Enumeration of statistics types +# +# @cumulative: stat is cumulative; value can only increase. +# @instant: stat is instantaneous; value can increase or decrease. +# @peak: stat is the peak value; value can only increase. +# @linear-histogram: stat is a linear histogram. +# @log2-histogram: stat is a logarithmic histogram, with one bucket +# for each power of two. +# +# Since: 7.1 +## +{ 'enum' : 'StatsType', + 'data' : [ 'cumulative', 'instant', 'peak', 'linear-histogram', + 'log2-histogram' ] } + +## +# @StatsUnit: +# +# Enumeration of unit of measurement for statistics +# +# @bytes: stat reported in bytes. +# @seconds: stat reported in seconds. +# @cycles: stat reported in clock cycles. +# @boolean: stat is a boolean value. +# +# Since: 7.1 +## +{ 'enum' : 'StatsUnit', + 'data' : [ 'bytes', 'seconds', 'cycles', 'boolean' ] } + +## +# @StatsProvider: +# +# Enumeration of statistics providers. +# +# Since: 7.1 +## +{ 'enum': 'StatsProvider', + 'data': [ 'kvm' ] } + +## +# @StatsTarget: +# +# The kinds of objects on which one can request statistics. +# +# @vm: statistics that apply to the entire virtual machine or +# the entire QEMU process. +# +# @vcpu: statistics that apply to a single virtual CPU. +# +# Since: 7.1 +## +{ 'enum': 'StatsTarget', + 'data': [ 'vm', 'vcpu' ] } + +## +# @StatsRequest: +# +# Indicates a set of statistics that should be returned by query-stats. +# +# @provider: provider for which to return statistics. + +# @names: statistics to be returned (all if omitted). +# +# Since: 7.1 +## +{ 'struct': 'StatsRequest', + 'data': { 'provider': 'StatsProvider', + '*names': [ 'str' ] } } + +## +# @StatsVCPUFilter: +# +# @vcpus: list of QOM paths for the desired vCPU objects. +# +# Since: 7.1 +## +{ 'struct': 'StatsVCPUFilter', + 'data': { '*vcpus': [ 'str' ] } } + +## +# @StatsFilter: +# +# The arguments to the query-stats command; specifies a target for which to +# request statistics and optionally the required subset of information for +# that target: +# - which vCPUs to request statistics for +# - which providers to request statistics from +# - which named values to return within each provider +# +# Since: 7.1 +## +{ 'union': 'StatsFilter', + 'base': { + 'target': 'StatsTarget', + '*providers': [ 'StatsRequest' ] }, + 'discriminator': 'target', + 'data': { 'vcpu': 'StatsVCPUFilter' } } + +## +# @StatsValue: +# +# @scalar: single unsigned 64-bit integers. +# @list: list of unsigned 64-bit integers (used for histograms). +# +# Since: 7.1 +## +{ 'alternate': 'StatsValue', + 'data': { 'scalar': 'uint64', + 'boolean': 'bool', + 'list': [ 'uint64' ] } } + +## +# @Stats: +# +# @name: name of stat. +# @value: stat value. +# +# Since: 7.1 +## +{ 'struct': 'Stats', + 'data': { 'name': 'str', + 'value' : 'StatsValue' } } + +## +# @StatsResult: +# +# @provider: provider for this set of statistics. +# +# @qom-path: Path to the object for which the statistics are returned, +# if the object is exposed in the QOM tree +# +# @stats: list of statistics. +# +# Since: 7.1 +## +{ 'struct': 'StatsResult', + 'data': { 'provider': 'StatsProvider', + '*qom-path': 'str', + 'stats': [ 'Stats' ] } } + +## +# @query-stats: +# +# Return runtime-collected statistics for objects such as the +# VM or its vCPUs. +# +# The arguments are a StatsFilter and specify the provider and objects +# to return statistics about. +# +# Returns: a list of StatsResult, one for each provider and object +# (e.g., for each vCPU). +# +# Since: 7.1 +## +{ 'command': 'query-stats', + 'data': 'StatsFilter', + 'boxed': true, + 'returns': [ 'StatsResult' ] } + +## +# @StatsSchemaValue: +# +# Schema for a single statistic. +# +# @name: name of the statistic; each element of the schema is uniquely +# identified by a target, a provider (both available in @StatsSchema) +# and the name. +# +# @type: kind of statistic. +# +# @unit: basic unit of measure for the statistic; if missing, the statistic +# is a simple number or counter. +# +# @base: base for the multiple of @unit in which the statistic is measured. +# Only present if @exponent is non-zero; @base and @exponent together +# form a SI prefix (e.g., _nano-_ for ``base=10`` and ``exponent=-9``) +# or IEC binary prefix (e.g. _kibi-_ for ``base=2`` and ``exponent=10``) +# +# @exponent: exponent for the multiple of @unit in which the statistic is +# expressed, or 0 for the basic unit +# +# @bucket-size: Present when @type is "linear-histogram", contains the width +# of each bucket of the histogram. +# +# Since: 7.1 +## +{ 'struct': 'StatsSchemaValue', + 'data': { 'name': 'str', + 'type': 'StatsType', + '*unit': 'StatsUnit', + '*base': 'int8', + 'exponent': 'int16', + '*bucket-size': 'uint32' } } + +## +# @StatsSchema: +# +# Schema for all available statistics for a provider and target. +# +# @provider: provider for this set of statistics. +# +# @target: the kind of object that can be queried through the provider. +# +# @stats: list of statistics. +# +# Since: 7.1 +## +{ 'struct': 'StatsSchema', + 'data': { 'provider': 'StatsProvider', + 'target': 'StatsTarget', + 'stats': [ 'StatsSchemaValue' ] } } + +## +# @query-stats-schemas: +# +# Return the schema for all available runtime-collected statistics. +# +# Note: runtime-collected statistics and their names fall outside QEMU's usual +# deprecation policies. QEMU will try to keep the set of available data +# stable, together with their names, but will not guarantee stability +# at all costs; the same is true of providers that source statistics +# externally, e.g. from Linux. For example, if the same value is being +# tracked with different names on different architectures or by different +# providers, one of them might be renamed. A statistic might go away if +# an algorithm is changed or some code is removed; changing a default +# might cause previously useful statistics to always report 0. Such +# changes, however, are expected to be rare. +# +# Since: 7.1 +## +{ 'command': 'query-stats-schemas', + 'data': { '*provider': 'StatsProvider' }, + 'returns': [ 'StatsSchema' ] } diff --git a/qapi/ui.json b/qapi/ui.json index 13a8bb82aa05..0abba3e930a4 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -15,7 +15,6 @@ # Display protocols which support changing password options. # # Since: 7.0 -# ## { 'enum': 'DisplayProtocol', 'data': [ 'vnc', 'spice' ] } @@ -32,7 +31,6 @@ # @disconnect: disconnect existing clients # # Since: 7.0 -# ## { 'enum': 'SetPasswordAction', 'data': [ 'keep', 'fail', 'disconnect' ] } @@ -52,7 +50,6 @@ # For VNC, only 'keep' is currently implemented. # # Since: 7.0 -# ## { 'union': 'SetPasswordOptions', 'base': { 'protocol': 'DisplayProtocol', @@ -70,7 +67,6 @@ # Defaults to the first. # # Since: 7.0 -# ## { 'struct': 'SetPasswordOptionsVnc', 'data': { '*display': 'str' } } @@ -115,7 +111,6 @@ # sure you are on the same machine as the QEMU instance. # # Since: 7.0 -# ## { 'union': 'ExpirePasswordOptions', 'base': { 'protocol': 'DisplayProtocol', @@ -132,9 +127,7 @@ # Defaults to the first. # # Since: 7.0 -# ## - { 'struct': 'ExpirePasswordOptionsVnc', 'data': { '*display': 'str' } } @@ -157,12 +150,26 @@ ## { 'command': 'expire_password', 'boxed': true, 'data': 'ExpirePasswordOptions' } +## +# @ImageFormat: +# +# Supported image format types. +# +# @png: PNG format +# +# @ppm: PPM format +# +# Since: 7.1 +## +{ 'enum': 'ImageFormat', + 'data': ['ppm', 'png'] } + ## # @screendump: # -# Write a PPM of the VGA screen to a file. +# Capture the contents of a screen and write it to a file. # -# @filename: the path of a new PPM file to store the image +# @filename: the path of a new file to store the image # # @device: ID of the display device that should be dumped. If this parameter # is missing, the primary display will be used. (Since 2.12) @@ -171,6 +178,8 @@ # parameter is missing, head #0 will be used. Also note that the head # can only be specified in conjunction with the device ID. (Since 2.12) # +# @format: image format for screendump. (default: ppm) (Since 7.1) +# # Returns: Nothing on success # # Since: 0.14 @@ -183,7 +192,8 @@ # ## { 'command': 'screendump', - 'data': {'filename': 'str', '*device': 'str', '*head': 'int'}, + 'data': {'filename': 'str', '*device': 'str', '*head': 'int', + '*format': 'ImageFormat'}, 'coroutine': true } ## @@ -657,8 +667,8 @@ # { # "host":"127.0.0.1", # "service":"50401", -# "family":"ipv4" -# "websocket":false, +# "family":"ipv4", +# "websocket":false # } # ] # } @@ -884,7 +894,6 @@ # are effectively synonyms. # # Since: 1.3 -# ## { 'enum': 'QKeyCode', 'data': [ 'unmapped', @@ -1009,8 +1018,8 @@ # # Keyboard input event. # -# @key: Which key this event is for. -# @down: True for key-down and false for key-up events. +# @key: Which key this event is for. +# @down: True for key-down and false for key-up events. # # Since: 2.0 ## @@ -1024,7 +1033,7 @@ # Pointer button input event. # # @button: Which button this event is for. -# @down: True for key-down and false for key-up events. +# @down: True for key-down and false for key-up events. # # Since: 2.0 ## @@ -1186,13 +1195,20 @@ # assuming the guest will resize the display to match # the window size then. Otherwise it defaults to "off". # Since 3.1 +# @show-tabs: Display the tab bar for switching between the various graphical +# interfaces (e.g. VGA and virtual console character devices) +# by default. +# Since 7.1 +# @show-menubar: Display the main window menubar. Defaults to "on". +# Since 8.0 # # Since: 2.12 -# ## { 'struct' : 'DisplayGTK', 'data' : { '*grab-on-hover' : 'bool', - '*zoom-to-fit' : 'bool' } } + '*zoom-to-fit' : 'bool', + '*show-tabs' : 'bool', + '*show-menubar' : 'bool' } } ## # @DisplayEGLHeadless: @@ -1203,7 +1219,6 @@ # available node on the host. # # Since: 3.1 -# ## { 'struct' : 'DisplayEGLHeadless', 'data' : { '*rendernode' : 'str' } } @@ -1224,7 +1239,6 @@ # @audiodev: Use the specified DBus audiodev to export audio. # # Since: 7.0 -# ## { 'struct' : 'DisplayDBus', 'data' : { '*rendernode' : 'str', @@ -1232,21 +1246,20 @@ '*p2p': 'bool', '*audiodev': 'str' } } - ## - # @DisplayGLMode: - # - # Display OpenGL mode. - # - # @off: Disable OpenGL (default). - # @on: Use OpenGL, pick context type automatically. - # Would better be named 'auto' but is called 'on' for backward - # compatibility with bool type. - # @core: Use OpenGL with Core (desktop) Context. - # @es: Use OpenGL with ES (embedded systems) Context. - # - # Since: 3.0 - # - ## +## +# @DisplayGLMode: +# +# Display OpenGL mode. +# +# @off: Disable OpenGL (default). +# @on: Use OpenGL, pick context type automatically. +# Would better be named 'auto' but is called 'on' for backward +# compatibility with bool type. +# @core: Use OpenGL with Core (desktop) Context. +# @es: Use OpenGL with ES (embedded systems) Context. +# +# Since: 3.0 +## { 'enum' : 'DisplayGLMode', 'data' : [ 'off', 'on', 'core', 'es' ] } @@ -1255,10 +1268,9 @@ # # Curses display options. # -# @charset: Font charset used by guest (default: CP437). +# @charset: Font charset used by guest (default: CP437). # # Since: 4.0 -# ## { 'struct' : 'DisplayCurses', 'data' : { '*charset' : 'str' } } @@ -1291,6 +1303,29 @@ '*swap-opt-cmd': 'bool' } } +## +# @HotKeyMod: +# +# Set of modifier keys that need to be held for shortcut key actions. +# +# Since: 7.1 +## +{ 'enum' : 'HotKeyMod', + 'data' : [ 'lctrl-lalt', 'lshift-lctrl-lalt', 'rctrl' ] } + +## +# @DisplaySDL: +# +# SDL2 display options. +# +# @grab-mod: Modifier keys that should be pressed together with the +# "G" key to release the mouse grab. +# +# Since: 7.1 +## +{ 'struct' : 'DisplaySDL', + 'data' : { '*grab-mod' : 'HotKeyMod' } } + ## # @DisplayType: # @@ -1328,7 +1363,6 @@ # @dbus: Start a D-Bus service for the display. (Since 7.0) # # Since: 2.12 -# ## { 'enum' : 'DisplayType', 'data' : [ @@ -1350,15 +1384,13 @@ # # Display (user interface) options. # -# @type: Which DisplayType qemu should use. -# @full-screen: Start user interface in fullscreen mode (default: off). -# @window-close: Allow to quit qemu with window close button (default: on). -# @show-cursor: Force showing the mouse cursor (default: off). -# (since: 5.0) -# @gl: Enable OpenGL support (default: off). +# @type: Which DisplayType qemu should use. +# @full-screen: Start user interface in fullscreen mode (default: off). +# @window-close: Allow to quit qemu with window close button (default: on). +# @show-cursor: Force showing the mouse cursor (default: off). (since: 5.0) +# @gl: Enable OpenGL support (default: off). # # Since: 2.12 -# ## { 'union' : 'DisplayOptions', 'base' : { 'type' : 'DisplayType', @@ -1373,7 +1405,8 @@ 'curses': { 'type': 'DisplayCurses', 'if': 'CONFIG_CURSES' }, 'egl-headless': { 'type': 'DisplayEGLHeadless', 'if': { 'all': ['CONFIG_OPENGL', 'CONFIG_GBM'] } }, - 'dbus': { 'type': 'DisplayDBus', 'if': 'CONFIG_DBUS_DISPLAY' } + 'dbus': { 'type': 'DisplayDBus', 'if': 'CONFIG_DBUS_DISPLAY' }, + 'sdl': { 'type': 'DisplaySDL', 'if': 'CONFIG_SDL' } } } @@ -1385,7 +1418,6 @@ # Returns: @DisplayOptions # # Since: 3.1 -# ## { 'command': 'query-display-options', 'returns': 'DisplayOptions' } @@ -1398,7 +1430,6 @@ # @vnc: VNC display # # Since: 6.0 -# ## { 'enum': 'DisplayReloadType', 'data': ['vnc'] } @@ -1411,7 +1442,6 @@ # @tls-certs: reload tls certs or not. # # Since: 6.0 -# ## { 'struct': 'DisplayReloadOptionsVNC', 'data': { '*tls-certs': 'bool' } } @@ -1424,7 +1454,6 @@ # @type: Specify the display type. # # Since: 6.0 -# ## { 'union': 'DisplayReloadOptions', 'base': {'type': 'DisplayReloadType'}, @@ -1450,3 +1479,65 @@ { 'command': 'display-reload', 'data': 'DisplayReloadOptions', 'boxed' : true } + +## +# @DisplayUpdateType: +# +# Available DisplayUpdate types. +# +# @vnc: VNC display +# +# Since: 7.1 +## +{ 'enum': 'DisplayUpdateType', + 'data': ['vnc'] } + +## +# @DisplayUpdateOptionsVNC: +# +# Specify the VNC reload options. +# +# @addresses: If specified, change set of addresses +# to listen for connections. Addresses configured +# for websockets are not touched. +# +# Since: 7.1 +## +{ 'struct': 'DisplayUpdateOptionsVNC', + 'data': { '*addresses': ['SocketAddress'] } } + +## +# @DisplayUpdateOptions: +# +# Options of the display configuration reload. +# +# @type: Specify the display type. +# +# Since: 7.1 +## +{ 'union': 'DisplayUpdateOptions', + 'base': {'type': 'DisplayUpdateType'}, + 'discriminator': 'type', + 'data': { 'vnc': 'DisplayUpdateOptionsVNC' } } + +## +# @display-update: +# +# Update display configuration. +# +# Returns: Nothing on success. +# +# Since: 7.1 +# +# Example: +# +# -> { "execute": "display-update", +# "arguments": { "type": "vnc", "addresses": +# [ { "type": "inet", "host": "0.0.0.0", +# "port": "5901" } ] } } +# <- { "return": {} } +# +## +{ 'command': 'display-update', + 'data': 'DisplayUpdateOptions', + 'boxed' : true } diff --git a/qapi/virtio.json b/qapi/virtio.json new file mode 100644 index 000000000000..019d2d1987c1 --- /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.2 +# +## +{ '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.2 +# +# 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.2 +# +## + +{ '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.2 +# +## + +{ '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.2 +# +# 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 negotiation 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 negotiation 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.2 +## + +{ '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.2 +## + +{ '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.2 +## + +{ '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.2 +# +## + +{ '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.2 +# +# 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.2 +# +## + +{ '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.2 +# +# 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.2 +# +## + +{ '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.2 +# +## + +{ '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.2 +# +## + +{ '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.2 +# +## + +{ '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.2 +# +# 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-edid.c b/qemu-edid.c index 20c958d9c7eb..92e1a660a76b 100644 --- a/qemu-edid.c +++ b/qemu-edid.c @@ -92,6 +92,10 @@ int main(int argc, char *argv[]) fprintf(stderr, "not a number: %s\n", optarg); exit(1); } + if (dpi == 0) { + fprintf(stderr, "cannot be zero: %s\n", optarg); + exit(1); + } break; case 'v': info.vendor = optarg; diff --git a/qemu-img.c b/qemu-img.c index 1caddfb23a71..439d8de1e3b7 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -25,7 +25,8 @@ #include "qemu/osdep.h" #include -#include "qemu-common.h" +#include "qemu/help-texts.h" +#include "qemu/qemu-progress.h" #include "qemu-version.h" #include "qapi/error.h" #include "qapi/qapi-commands-block-core.h" @@ -99,7 +100,8 @@ static void format_print(void *opaque, const char *name) printf(" %s", name); } -static void QEMU_NORETURN G_GNUC_PRINTF(1, 2) error_exit(const char *fmt, ...) +static G_NORETURN G_GNUC_PRINTF(1, 2) +void error_exit(const char *fmt, ...) { va_list ap; @@ -111,18 +113,21 @@ static void QEMU_NORETURN G_GNUC_PRINTF(1, 2) error_exit(const char *fmt, ...) exit(EXIT_FAILURE); } -static void QEMU_NORETURN missing_argument(const char *option) +static G_NORETURN +void missing_argument(const char *option) { error_exit("missing argument for option '%s'", option); } -static void QEMU_NORETURN unrecognized_option(const char *option) +static G_NORETURN +void unrecognized_option(const char *option) { error_exit("unrecognized option '%s'", option); } /* Please keep in synch with docs/tools/qemu-img.rst */ -static void QEMU_NORETURN help(void) +static G_NORETURN +void help(void) { const char *help_msg = QEMU_IMG_VERSION @@ -159,8 +164,8 @@ static void QEMU_NORETURN 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" @@ -906,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, @@ -918,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) { @@ -1304,7 +1312,7 @@ static int check_empty_sectors(BlockBackend *blk, int64_t offset, int ret = 0; int64_t idx; - ret = blk_pread(blk, offset, buffer, bytes); + ret = blk_pread(blk, offset, bytes, buffer, 0); if (ret < 0) { error_report("Error while reading offset %" PRId64 " of %s: %s", offset, filename, strerror(-ret)); @@ -1521,7 +1529,7 @@ static int img_compare(int argc, char **argv) int64_t pnum; chunk = MIN(chunk, IO_BUF_SIZE); - ret = blk_pread(blk1, offset, buf1, chunk); + ret = blk_pread(blk1, offset, chunk, buf1, 0); if (ret < 0) { error_report("Error while reading offset %" PRId64 " of %s: %s", @@ -1529,7 +1537,7 @@ static int img_compare(int argc, char **argv) ret = 4; goto out; } - ret = blk_pread(blk2, offset, buf2, chunk); + ret = blk_pread(blk2, offset, chunk, buf2, 0); if (ret < 0) { error_report("Error while reading offset %" PRId64 " of %s: %s", @@ -1618,16 +1626,16 @@ static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name, const char *src_node, const char *src_name, Error **errp) { - BlockDirtyBitmapMergeSource *merge_src; - BlockDirtyBitmapMergeSourceList *list = NULL; + BlockDirtyBitmapOrStr *merge_src; + BlockDirtyBitmapOrStrList *list = NULL; - merge_src = g_new0(BlockDirtyBitmapMergeSource, 1); + merge_src = g_new0(BlockDirtyBitmapOrStr, 1); merge_src->type = QTYPE_QDICT; merge_src->u.external.node = g_strdup(src_node); merge_src->u.external.name = g_strdup(src_name); QAPI_LIST_PREPEND(list, merge_src); qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp); - qapi_free_BlockDirtyBitmapMergeSourceList(list); + qapi_free_BlockDirtyBitmapOrStrList(list); } enum ImgConvertBlockStatus { @@ -2109,7 +2117,7 @@ static int convert_do_copy(ImgConvertState *s) if (s->compressed && !s->ret) { /* signal EOF to align */ - ret = blk_pwrite_compressed(s->target, 0, NULL, 0); + ret = blk_pwrite_compressed(s->target, 0, 0, NULL); if (ret < 0) { return ret; } @@ -2907,15 +2915,15 @@ static ImageInfoList *collect_image_info_list(bool image_opts, image_opts = false; if (chain) { - if (info->has_full_backing_filename) { + if (info->full_backing_filename) { filename = info->full_backing_filename; - } else if (info->has_backing_filename) { + } else if (info->backing_filename) { error_report("Could not determine absolute backing filename," " but backing filename '%s' present", info->backing_filename); goto err; } - if (info->has_backing_filename_format) { + if (info->backing_filename_format) { fmt = info->backing_filename_format; } } @@ -3038,7 +3046,7 @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n", e->start, e->length, e->has_offset ? e->offset : 0, - e->has_filename ? e->filename : ""); + e->filename ?: ""); } /* This format ignores the distinction between 0, ZERO and ZERO|DATA. * Modify the flags here to allow more coalescing. @@ -3119,7 +3127,6 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, .has_offset = has_offset, .depth = depth, .present = !!(ret & BDRV_BLOCK_ALLOCATED), - .has_filename = filename, .filename = filename, }; @@ -3135,11 +3142,11 @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next) curr->data != next->data || curr->depth != next->depth || curr->present != next->present || - curr->has_filename != next->has_filename || + !curr->filename != !next->filename || curr->has_offset != next->has_offset) { return false; } - if (curr->has_filename && strcmp(curr->filename, next->filename)) { + if (curr->filename && strcmp(curr->filename, next->filename)) { return false; } if (curr->has_offset && curr->offset + curr->length != next->offset) { @@ -3305,11 +3312,11 @@ static int img_snapshot(int argc, char **argv) char *filename, *snapshot_name = NULL; int c, ret = 0, bdrv_oflags; int action = 0; - qemu_timeval tv; bool quiet = false; Error *err = NULL; bool image_opts = false; bool force_share = false; + int64_t rt; bdrv_oflags = BDRV_O_RDWR; /* Parse commandline parameters */ @@ -3406,9 +3413,9 @@ static int img_snapshot(int argc, char **argv) memset(&sn, 0, sizeof(sn)); pstrcpy(sn.name, sizeof(sn.name), snapshot_name); - qemu_gettimeofday(&tv); - sn.date_sec = tv.tv_sec; - sn.date_nsec = tv.tv_usec * 1000; + rt = g_get_real_time(); + sn.date_sec = rt / G_USEC_PER_SEC; + sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000; ret = bdrv_snapshot_create(bs, &sn); if (ret) { @@ -3774,7 +3781,7 @@ static int img_rebase(int argc, char **argv) n = old_backing_size - offset; } - ret = blk_pread(blk_old_backing, offset, buf_old, n); + ret = blk_pread(blk_old_backing, offset, n, buf_old, 0); if (ret < 0) { error_report("error while reading from old backing file"); goto out; @@ -3788,7 +3795,7 @@ static int img_rebase(int argc, char **argv) n = new_backing_size - offset; } - ret = blk_pread(blk_new_backing, offset, buf_new, n); + ret = blk_pread(blk_new_backing, offset, n, buf_new, 0); if (ret < 0) { error_report("error while reading from new backing file"); goto out; @@ -3807,8 +3814,8 @@ static int img_rebase(int argc, char **argv) if (buf_old_is_zero) { ret = blk_pwrite_zeroes(blk, offset + written, pnum, 0); } else { - ret = blk_pwrite(blk, offset + written, - buf_old + written, pnum, 0); + ret = blk_pwrite(blk, offset + written, pnum, + buf_old + written, 0); } if (ret < 0) { error_report("Error while writing to COW image: %s", @@ -4363,7 +4370,7 @@ static int img_bench(int argc, char **argv) struct timeval t1, t2; int i; bool force_share = false; - size_t buf_size; + size_t buf_size = 0; for (;;) { static const struct option long_options[] = { @@ -4562,7 +4569,7 @@ static int img_bench(int argc, char **argv) data.buf = blk_blockalign(blk, buf_size); memset(data.buf, pattern, data.nrreq * data.bufsize); - blk_register_buf(blk, data.buf, buf_size); + blk_register_buf(blk, data.buf, buf_size, &error_fatal); data.qiov = g_new(QEMUIOVector, data.nrreq); for (i = 0; i < data.nrreq; i++) { @@ -4585,7 +4592,7 @@ static int img_bench(int argc, char **argv) out: if (data.buf) { - blk_unregister_buf(blk, data.buf); + blk_unregister_buf(blk, data.buf, buf_size); } qemu_vfree(data.buf); blk_unref(blk); @@ -4914,7 +4921,7 @@ static int img_dd(int argc, char **argv) const char *out_fmt = "raw"; const char *fmt = NULL; int64_t size = 0; - int64_t block_count = 0, out_pos, in_pos; + int64_t out_pos, in_pos; bool force_share = false; struct DdInfo dd = { .flags = 0, @@ -5114,31 +5121,24 @@ static int img_dd(int argc, char **argv) in.buf = g_new(uint8_t, in.bsz); - for (out_pos = 0; in_pos < size; block_count++) { - int in_ret, out_ret; + for (out_pos = 0; in_pos < size; ) { + int bytes = (in_pos + in.bsz > size) ? size - in_pos : in.bsz; - if (in_pos + in.bsz > size) { - in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos); - } else { - in_ret = blk_pread(blk1, in_pos, in.buf, in.bsz); - } - if (in_ret < 0) { + ret = blk_pread(blk1, in_pos, bytes, in.buf, 0); + if (ret < 0) { error_report("error while reading from input image file: %s", - strerror(-in_ret)); - ret = -1; + strerror(-ret)); goto out; } - in_pos += in_ret; - - out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0); + in_pos += bytes; - if (out_ret < 0) { + ret = blk_pwrite(blk2, out_pos, bytes, in.buf, 0); + if (ret < 0) { error_report("error while writing to output image file: %s", - strerror(-out_ret)); - ret = -1; + strerror(-ret)); goto out; } - out_pos += out_ret; + out_pos += bytes; } out: @@ -5442,7 +5442,7 @@ int main(int argc, char **argv) exit(1); } trace_init_file(); - qemu_set_log(LOG_TRACE); + qemu_set_log(LOG_TRACE, &error_fatal); /* find the command */ for (cmd = img_cmds; cmd->name != NULL; cmd++) { diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 2f0d8ac25a46..952dc940f1df 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -541,28 +541,34 @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, static int do_pread(BlockBackend *blk, char *buf, int64_t offset, int64_t bytes, int64_t *total) { + int ret; + if (bytes > INT_MAX) { return -ERANGE; } - *total = blk_pread(blk, offset, (uint8_t *)buf, bytes); - if (*total < 0) { - return *total; + ret = blk_pread(blk, offset, bytes, (uint8_t *)buf, 0); + if (ret < 0) { + return ret; } + *total = bytes; return 1; } static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, int64_t bytes, int flags, int64_t *total) { + int ret; + if (bytes > INT_MAX) { return -ERANGE; } - *total = blk_pwrite(blk, offset, (uint8_t *)buf, bytes, flags); - if (*total < 0) { - return *total; + ret = blk_pwrite(blk, offset, bytes, (uint8_t *)buf, flags); + if (ret < 0) { + return ret; } + *total = bytes; return 1; } @@ -625,7 +631,7 @@ static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, return -ERANGE; } - ret = blk_pwrite_compressed(blk, offset, buf, bytes); + ret = blk_pwrite_compressed(blk, offset, bytes, buf); if (ret < 0) { return ret; } diff --git a/qemu-io.c b/qemu-io.c index eb8afc8b413b..2bd7bfb65073 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -15,7 +15,8 @@ #include #endif -#include "qemu-common.h" +#include "qemu/help-texts.h" +#include "qemu/cutils.h" #include "qapi/error.h" #include "qemu-io.h" #include "qemu/error-report.h" @@ -634,7 +635,7 @@ int main(int argc, char **argv) exit(1); } trace_init_file(); - qemu_set_log(LOG_TRACE); + qemu_set_log(LOG_TRACE, &error_fatal); /* initialize commands */ qemuio_add_command(&quit_cmd); diff --git a/qemu-nbd.c b/qemu-nbd.c index 713e7557a9eb..6ff45308a9ce 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -21,7 +21,7 @@ #include #include -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qapi/error.h" #include "qemu/cutils.h" #include "sysemu/block-backend.h" @@ -567,7 +567,7 @@ int main(int argc, char **argv) QDict *options = NULL; const char *export_name = NULL; /* defaults to "" later for server mode */ const char *export_description = NULL; - strList *bitmaps = NULL; + BlockDirtyBitmapOrStrList *bitmaps = NULL; bool alloc_depth = false; const char *tlscredsid = NULL; const char *tlshostname = NULL; @@ -687,7 +687,14 @@ int main(int argc, char **argv) alloc_depth = true; break; case 'B': - QAPI_LIST_PREPEND(bitmaps, g_strdup(optarg)); + { + BlockDirtyBitmapOrStr *el = g_new(BlockDirtyBitmapOrStr, 1); + *el = (BlockDirtyBitmapOrStr) { + .type = QTYPE_QSTRING, + .u.local = g_strdup(optarg), + }; + QAPI_LIST_PREPEND(bitmaps, el); + } break; case 'k': sockpath = optarg; @@ -804,7 +811,7 @@ int main(int argc, char **argv) exit(1); } trace_init_file(); - qemu_set_log(LOG_TRACE); + qemu_set_log(LOG_TRACE, &error_fatal); socket_activation = check_socket_activation(); if (socket_activation == 0) { @@ -902,13 +909,14 @@ int main(int argc, char **argv) if ((device && !verbose) || fork_process) { #ifndef WIN32 + g_autoptr(GError) err = NULL; int stderr_fd[2]; pid_t pid; int ret; - if (qemu_pipe(stderr_fd) < 0) { + if (!g_unix_open_pipe(stderr_fd, FD_CLOEXEC, &err)) { error_report("Error setting up communication pipe: %s", - strerror(errno)); + err->message); exit(EXIT_FAILURE); } @@ -1087,7 +1095,7 @@ int main(int argc, char **argv) bs->detect_zeroes = detect_zeroes; - nbd_server_is_qemu_nbd(true); + nbd_server_is_qemu_nbd(shared); export_opts = g_new(BlockExportOptions, 1); *export_opts = (BlockExportOptions) { @@ -1099,9 +1107,7 @@ int main(int argc, char **argv) .has_writable = true, .writable = !readonly, .u.nbd = { - .has_name = true, .name = g_strdup(export_name), - .has_description = !!export_description, .description = g_strdup(export_description), .has_bitmaps = !!bitmaps, .bitmaps = bitmaps, diff --git a/qemu-options.hx b/qemu-options.hx index 34e9b32a5c00..3aa3a2f5a351 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -36,7 +36,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ " nvdimm=on|off controls NVDIMM support (default=off)\n" " memory-encryption=@var{} memory encryption object to use (default=none)\n" " hmat=on|off controls ACPI HMAT support (default=off)\n" - " memory-backend='backend-id' specifies explicitly provided backend for main RAM (default=none)\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", QEMU_ARCH_ALL) SRST ``-machine [type=]name[,prop=value[,...]]`` @@ -124,6 +125,38 @@ SRST -object memory-backend-ram,id=pc.ram,size=512M,x-use-canonical-path-for-ramblock-id=off -machine memory-backend=pc.ram -m 512M + + ``cxl-fmw.0.targets.0=firsttarget,cxl-fmw.0.targets.1=secondtarget,cxl-fmw.0.size=size[,cxl-fmw.0.interleave-granularity=granularity]`` + Define a CXL Fixed Memory Window (CFMW). + + Described in the CXL 2.0 ECN: CEDT CFMWS & QTG _DSM. + + They are regions of Host Physical Addresses (HPA) on a system which + may be interleaved across one or more CXL host bridges. The system + software will assign particular devices into these windows and + configure the downstream Host-managed Device Memory (HDM) decoders + in root ports, switch ports and devices appropriately to meet the + interleave requirements before enabling the memory devices. + + ``targets.X=target`` provides the mapping to CXL host bridges + which may be identified by the id provided in the -device entry. + Multiple entries are needed to specify all the targets when + the fixed memory window represents interleaved memory. X is the + target index from 0. + + ``size=size`` sets the size of the CFMW. This must be a multiple of + 256MiB. The region will be aligned to 256MiB but the location is + platform and configuration dependent. + + ``interleave-granularity=granularity`` sets the granularity of + interleave. Default 256KiB. Only 256KiB, 512KiB, 1024KiB, 2048KiB + 4096KiB, 8192KiB and 16384KiB granularities supported. + + Example: + + :: + + -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 ERST DEF("M", HAS_ARG, QEMU_OPTION_M, @@ -152,6 +185,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel, " split-wx=on|off (enable TCG split w^x mapping)\n" " tb-size=n (TCG translation block cache size)\n" " dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n" + " notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n" " thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL) SRST ``-accel name[,prop=value[,...]]`` @@ -203,6 +237,16 @@ SRST is disabled (dirty-ring-size=0). When enabled, KVM will instead record dirty pages in a bitmap. + ``notify-vmexit=run|internal-error|disable,notify-window=n`` + Enables or disables notify VM exit support on x86 host and specify + the corresponding notify window to trigger the VM exit if enabled. + ``run`` option enables the feature. It does nothing and continue + if the exit happens. ``internal-error`` option enables the feature. + It raises a internal error. ``disable`` option doesn't enable the feature. + This feature can mitigate the CPU stuck issue due to event windows don't + open up for a specified of time (i.e. notify-window). + Default: notify-vmexit=run,notify-window=0. + ERST DEF("smp", HAS_ARG, QEMU_OPTION_smp, @@ -299,6 +343,9 @@ SRST :: -smp 2 + + Note: The cluster topology will only be generated in ACPI and exposed + to guest if it's explicitly specified in -smp. ERST DEF("numa", HAS_ARG, QEMU_OPTION_numa, @@ -318,7 +365,7 @@ SRST \ ``-numa cpu,node-id=node[,socket-id=x][,core-id=y][,thread-id=z]`` \ -``-numa hmat-lb,initiator=node,target=node,hierarchy=hierarchy,data-type=tpye[,latency=lat][,bandwidth=bw]`` +``-numa hmat-lb,initiator=node,target=node,hierarchy=hierarchy,data-type=type[,latency=lat][,bandwidth=bw]`` \ ``-numa hmat-cache,node-id=node,size=size,level=level[,associativity=str][,policy=str][,line=size]`` Define a NUMA node and assign RAM and VCPUs to it. Set the NUMA @@ -661,9 +708,35 @@ SRST (deprecated) environment variables. ERST +DEF("audio", HAS_ARG, QEMU_OPTION_audio, + "-audio [driver=]driver,model=value[,prop[=value][,...]]\n" + " specifies the audio backend and device to use;\n" + " apart from 'model', options are the same as for -audiodev.\n" + " use '-audio model=help' to show possible devices.\n", + QEMU_ARCH_ALL) +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 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: + + .. parsed-literal:: + + |qemu_system| -audiodev pa,id=pa -device sb16,audiodev=pa + |qemu_system| -audio pa,model=sb16 +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" @@ -710,6 +783,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 @@ -876,6 +952,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 @@ -892,33 +981,6 @@ SRST ``qemu.wav``. ERST -DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, - "-soundhw c1,... enable audio support\n" - " and only specified sound cards (comma separated list)\n" - " use '-soundhw help' to get the list of supported cards\n" - " use '-soundhw all' to enable all of them\n", QEMU_ARCH_ALL) -SRST -``-soundhw card1[,card2,...] or -soundhw all`` - Enable audio and selected sound hardware. Use 'help' to print all - available sound hardware. For example: - - .. parsed-literal:: - - |qemu_system_x86| -soundhw sb16,adlib disk.img - |qemu_system_x86| -soundhw es1370 disk.img - |qemu_system_x86| -soundhw ac97 disk.img - |qemu_system_x86| -soundhw hda disk.img - |qemu_system_x86| -soundhw all disk.img - |qemu_system_x86| -soundhw help - - Note that Linux's i810\_audio OSS kernel (for AC97) module might - require manually specifying clocking. - - :: - - modprobe i810_audio clocking=48000 -ERST - DEF("device", HAS_ARG, QEMU_OPTION_device, "-device driver[,prop[=value][,...]]\n" " add device (based on driver)\n" @@ -986,7 +1048,7 @@ SRST details on the external interface. ``-device isa-ipmi-kcs,bmc=id[,ioport=val][,irq=val]`` - Add a KCS IPMI interafce on the ISA bus. This also adds a + Add a KCS IPMI interface on the ISA bus. This also adds a corresponding ACPI and SMBIOS entries, if appropriate. ``bmc=id`` @@ -1006,7 +1068,7 @@ SRST is 0xe4 and the default interrupt is 5. ``-device pci-ipmi-kcs,bmc=id`` - Add a KCS IPMI interafce on the PCI bus. + Add a KCS IPMI interface on the PCI bus. ``bmc=id`` The BMC to connect to, one of ipmi-bmc-sim or ipmi-bmc-extern above. @@ -1075,6 +1137,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) @@ -1555,13 +1630,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) @@ -1720,7 +1788,7 @@ SRST directory on host is made directly accessible by guest as a pass-through file system by using the 9P network protocol for communication between host and guests, if desired even accessible, shared by several guests - simultaniously. + simultaneously. Note that ``-virtfs`` is actually just a convenience shortcut for its generalized form ``-fsdev -device virtio-9p-pci``. @@ -1903,12 +1971,13 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, "-display spice-app[,gl=on|off]\n" #endif #if defined(CONFIG_SDL) - "-display sdl[,alt_grab=on|off][,ctrl_grab=on|off][,gl=on|core|es|off]\n" - " [,grab-mod=][,show-cursor=on|off][,window-close=on|off]\n" + "-display sdl[,gl=on|core|es|off][,grab-mod=][,show-cursor=on|off]\n" + " [,window-close=on|off]\n" #endif #if defined(CONFIG_GTK) "-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n" - " [,show-cursor=on|off][,window-close=on|off]\n" + " [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n" + " [,show-menubar=on|off]\n" #endif #if defined(CONFIG_VNC) "-display vnc=[,]\n" @@ -1946,9 +2015,8 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, , QEMU_ARCH_ALL) SRST ``-display type`` - Select type of display to use. This option is a replacement for the - old style -sdl/-curses/... options. Use ``-display help`` to list - the available display types. Valid values for type are + Select type of display to use. Use ``-display help`` to list the available + display types. Valid values for type are ``spice-app[,gl=on|off]`` Start QEMU as a Spice server and launch the default Spice client @@ -1977,12 +2045,6 @@ SRST the mouse grabbing in conjunction with the "g" key. ```` can be either ``lshift-lctrl-lalt`` or ``rctrl``. - ``alt_grab=on|off`` : Use Control+Alt+Shift-g to toggle mouse grabbing. - This parameter is deprecated - use ``grab-mod`` instead. - - ``ctrl_grab=on|off`` : Use Right-Control-g to toggle mouse grabbing. - This parameter is deprecated - use ``grab-mod`` instead. - ``gl=on|off|core|es`` : Use OpenGL for displaying ``show-cursor=on|off`` : Force showing the mouse cursor @@ -2000,10 +2062,16 @@ SRST ``grab-on-hover=on|off`` : Grab keyboard input on mouse hover + ``show-tabs=on|off`` : Display the tab bar for switching between the + various graphical interfaces (e.g. VGA and + virtual console character devices) by default. + ``show-cursor=on|off`` : Force showing the mouse cursor ``window-close=on|off`` : Allow to quit qemu with window close button + ``show-menubar=on|off`` : Display the main window menubar, defaults to "on" + ``curses[,charset=]`` Display video output via curses. For graphics device models which support a text mode, QEMU can display this output using a @@ -2056,47 +2124,6 @@ SRST Use C-a h for help on switching between the console and monitor. ERST -DEF("curses", 0, QEMU_OPTION_curses, - "-curses shorthand for -display curses\n", - QEMU_ARCH_ALL) -SRST -``-curses`` - Normally, if QEMU is compiled with graphical window support, it - displays output such as guest graphics, guest console, and the QEMU - monitor in a window. With this option, QEMU can display the VGA - output when in text mode using a curses/ncurses interface. Nothing - is displayed in graphical mode. -ERST - -DEF("alt-grab", 0, QEMU_OPTION_alt_grab, - "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n", - QEMU_ARCH_ALL) -SRST -``-alt-grab`` - Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt). Note that - this also affects the special keys (for fullscreen, monitor-mode - switching, etc). This option is deprecated - please use - ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. -ERST - -DEF("ctrl-grab", 0, QEMU_OPTION_ctrl_grab, - "-ctrl-grab use Right-Ctrl to grab mouse (instead of Ctrl-Alt)\n", - QEMU_ARCH_ALL) -SRST -``-ctrl-grab`` - Use Right-Ctrl to grab mouse (instead of Ctrl-Alt). Note that this - also affects the special keys (for fullscreen, monitor-mode - switching, etc). This option is deprecated - please use - ``-display sdl,grab-mod=rctrl`` instead. -ERST - -DEF("sdl", 0, QEMU_OPTION_sdl, - "-sdl shorthand for -display sdl\n", QEMU_ARCH_ALL) -SRST -``-sdl`` - Enable SDL. -ERST - #ifdef CONFIG_SPICE DEF("spice", HAS_ARG, QEMU_OPTION_spice, "-spice [port=port][,tls-port=secured-port][,x509-dir=]\n" @@ -2518,7 +2545,7 @@ DEF("no-hpet", 0, QEMU_OPTION_no_hpet, "-no-hpet disable HPET\n", QEMU_ARCH_I386) SRST ``-no-hpet`` - Disable HPET support. + Disable HPET support. Deprecated, use '-machine hpet=off' instead. ERST DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable, @@ -2556,6 +2583,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" @@ -2740,6 +2769,20 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n" " configure a network backend to connect to another network\n" " using an UDP tunnel\n" + "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off]\n" + "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off]\n" + "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n" + " configure a network backend to connect to another network\n" + " using a socket connection in stream mode.\n" + "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n" + "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=fd,local.str=file-descriptor]\n" + " configure a network backend to connect to a multicast maddr and port\n" + " use ``local.host=addr`` to specify the host address to send packets from\n" + "-netdev dgram,id=str,local.type=inet,local.host=addr,local.port=port[,remote.type=inet,remote.host=addr,remote.port=port]\n" + "-netdev dgram,id=str,local.type=unix,local.path=path[,remote.type=unix,remote.path=path]\n" + "-netdev dgram,id=str,local.type=fd,local.str=file-descriptor\n" + " configure a network backend to connect to another network\n" + " using an UDP tunnel\n" #ifdef CONFIG_VDE "-netdev vde,id=str[,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n" " configure a network backend to connect to port 'n' of a vde switch\n" @@ -2758,8 +2801,29 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, " configure a vhost-user network, backed by a chardev 'dev'\n" #endif #ifdef __linux__ - "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n" + "-netdev vhost-vdpa,id=str[,vhostdev=/path/to/dev][,vhostfd=h]\n" " configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n" + " use 'vhostdev=/path/to/dev' to open a vhost vdpa device\n" + " use 'vhostfd=h' to connect to an already opened vhost vdpa device\n" +#endif +#ifdef CONFIG_VMNET + "-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n" + " [,start-address=addr,end-address=addr,subnet-mask=mask]\n" + " configure a vmnet network backend in host mode with ID 'str',\n" + " isolate this interface from others with 'isolated',\n" + " configure the address range and choose a subnet mask,\n" + " specify network UUID 'uuid' to disable DHCP and interact with\n" + " vmnet-host interfaces within this isolated network\n" + "-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n" + " [,start-address=addr,end-address=addr,subnet-mask=mask]\n" + " configure a vmnet network backend in shared mode with ID 'str',\n" + " configure the address range and choose a subnet mask,\n" + " set IPv6 ULA prefix (of length 64) to use for internal network,\n" + " isolate this interface from others with 'isolated'\n" + "-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n" + " configure a vmnet network backend in bridged mode with ID 'str',\n" + " use 'ifname=name' to select a physical network interface to be bridged,\n" + " isolate this interface from others with 'isolated'\n" #endif "-netdev hubport,id=str,hubid=n[,netdev=nd]\n" " configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL) @@ -2779,6 +2843,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic, #endif #ifdef CONFIG_POSIX "vhost-user|" +#endif +#ifdef CONFIG_VMNET + "vmnet-host|vmnet-shared|vmnet-bridged|" #endif "socket][,option][,...][mac=macaddr]\n" " initialize an on-board / default host NIC (using MAC address\n" @@ -2801,6 +2868,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, #endif #ifdef CONFIG_NETMAP "netmap|" +#endif +#ifdef CONFIG_VMNET + "vmnet-host|vmnet-shared|vmnet-bridged|" #endif "socket][,option][,option][,...]\n" " old way to initialize a host network interface\n" @@ -3239,7 +3309,7 @@ SRST -netdev type=vhost-user,id=net0,chardev=chr0 \ -device virtio-net-pci,netdev=net0 -``-netdev vhost-vdpa,vhostdev=/path/to/dev`` +``-netdev vhost-vdpa[,vhostdev=/path/to/dev][,vhostfd=h]`` Establish a vhost-vdpa netdev. vDPA device is a device that uses a datapath which complies with @@ -3312,11 +3382,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) "-chardev serial,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" - "-chardev tty,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) "-chardev parallel,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" - "-chardev parport,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" #endif #if defined(CONFIG_SPICE) "-chardev spicevmc,id=id,name=name[,debug=debug][,logfile=PATH][,logappend=on|off]\n" @@ -3331,7 +3399,7 @@ The general form of a character device option is: ``-chardev backend,id=id[,mux=on|off][,options]`` Backend is one of: ``null``, ``socket``, ``udp``, ``msmouse``, ``vc``, ``ringbuf``, ``file``, ``pipe``, ``console``, ``serial``, - ``pty``, ``stdio``, ``braille``, ``tty``, ``parallel``, ``parport``, + ``pty``, ``stdio``, ``braille``, ``parallel``, ``spicevmc``, ``spiceport``. The specific backend will determine the applicable options. @@ -3555,15 +3623,8 @@ The available backends are: Connect to a local BrlAPI server. ``braille`` does not take any options. -``-chardev tty,id=id,path=path`` - ``tty`` is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD - and DragonFlyBSD hosts. It is an alias for ``serial``. - - ``path`` specifies the path to the tty. ``path`` is required. - ``-chardev parallel,id=id,path=path`` \ -``-chardev parport,id=id,path=path`` ``parallel`` is only available on Linux, FreeBSD and DragonFlyBSD hosts. @@ -3673,12 +3734,67 @@ DEFHEADING() #endif -DEFHEADING(Linux/Multiboot boot specific:) +DEFHEADING(Boot Image or Kernel specific:) +SRST +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 -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. +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 @@ -3718,6 +3834,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:) @@ -4168,15 +4303,10 @@ 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_ALL) + "-enable-kvm enable KVM full virtualization support\n", + QEMU_ARCH_ARM | QEMU_ARCH_I386 | QEMU_ARCH_MIPS | QEMU_ARCH_PPC | + QEMU_ARCH_RISCV | QEMU_ARCH_S390X) SRST ``-enable-kvm`` Enable KVM full virtualization support. This option is only @@ -4184,16 +4314,17 @@ SRST ERST DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid, - "-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL) + "-xen-domid id specify xen guest domain id\n", + QEMU_ARCH_ARM | QEMU_ARCH_I386) DEF("xen-attach", 0, QEMU_OPTION_xen_attach, "-xen-attach attach to existing xen domain\n" " libxl will use this when starting QEMU\n", - QEMU_ARCH_ALL) + QEMU_ARCH_ARM | QEMU_ARCH_I386) DEF("xen-domid-restrict", 0, QEMU_OPTION_xen_domid_restrict, "-xen-domid-restrict restrict set of available xen operations\n" " to specified domain id. (Does not affect\n" " xenpv machine type).\n", - QEMU_ARCH_ALL) + QEMU_ARCH_ARM | QEMU_ARCH_I386) SRST ``-xen-domid id`` Specify xen guest domain id (XEN only). @@ -4225,7 +4356,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", @@ -4241,7 +4372,7 @@ SRST ``-action panic=none`` ``-action reboot=shutdown,shutdown=pause`` - ``-watchdog i6300esb -action watchdog=pause`` + ``-device i6300esb -action watchdog=pause`` ERST @@ -4359,35 +4490,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", @@ -4409,7 +4511,7 @@ SRST Examples: - ``-watchdog i6300esb -watchdog-action pause``; \ ``-watchdog ib700`` + ``-device i6300esb -watchdog-action pause`` ERST @@ -4540,12 +4642,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). @@ -4572,6 +4674,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 @@ -4622,18 +4731,14 @@ SRST ERST DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig, - "-readconfig \n", QEMU_ARCH_ALL) + "-readconfig \n" + " read config file\n", QEMU_ARCH_ALL) SRST ``-readconfig file`` Read device configuration from file. This approach is useful when you want to spawn QEMU process with many command line options but you don't want to exceed the command line character limit. ERST -DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig, - "-writeconfig \n" - " read/write config file (deprecated)\n", QEMU_ARCH_ALL) -SRST -ERST DEF("no-user-config", 0, QEMU_OPTION_nouserconfig, "-no-user-config\n" @@ -4674,13 +4779,22 @@ DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL) DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL) #ifdef __linux__ -DEF("enable-fips", 0, QEMU_OPTION_enablefips, - "-enable-fips enable FIPS 140-2 compliance\n", +DEF("async-teardown", 0, QEMU_OPTION_asyncteardown, + "-async-teardown enable asynchronous teardown\n", QEMU_ARCH_ALL) #endif SRST -``-enable-fips`` - Enable FIPS 140-2 compliance mode. +``-async-teardown`` + Enable asynchronous teardown. A new process called "cleanup/" + will be created at startup sharing the address space with the main qemu + process, using clone. It will wait for the main qemu process to + terminate completely, and then exit. + This allows qemu to terminate very quickly even if the guest was + huge, leaving the teardown of the address space to the cleanup + process. Since the cleanup process shares the same cgroups as the + main qemu process, accounting is performed correctly. This only + works if the cleanup process is not forcefully killed with SIGKILL + before the main qemu process has terminated completely. ERST DEF("msg", HAS_ARG, QEMU_OPTION_msg, @@ -5157,8 +5271,8 @@ SRST read the colo-compare git log. ``-object cryptodev-backend-builtin,id=id[,queues=queues]`` - Creates a cryptodev backend which executes crypto opreation from - the QEMU cipher APIS. The id parameter is a unique ID that will + Creates a cryptodev backend which executes crypto operations from + the QEMU cipher APIs. The id parameter is a unique ID that will be used to reference this cryptodev backend from the ``virtio-crypto`` device. The queues parameter is optional, which specify the queue number of cryptodev backend, the default @@ -5425,7 +5539,7 @@ SRST file=/etc/qemu/vnc.allow Finally the ``/etc/qemu/vnc.allow`` file would contain the list - of x509 distingished names that are permitted access + of x509 distinguished names that are permitted access :: diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 03739753607d..0c5175d95719 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -1,8 +1,10 @@ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include #include "qapi/error.h" #include "qemu/sockets.h" #include "channel.h" +#include "cutils.h" #ifdef CONFIG_SOLARIS #include @@ -34,7 +36,7 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel, g_warning("error converting fd to gsocket: %s", strerror(errno)); goto out; } - qemu_set_nonblock(client_fd); + qemu_socket_set_nonblock(client_fd); ret = ga_channel_client_add(c, client_fd); if (ret) { g_warning("error setting up connection"); @@ -119,7 +121,7 @@ static int ga_channel_client_add(GAChannel *c, int fd) } static gboolean ga_channel_open(GAChannel *c, const gchar *path, - GAChannelMethod method, int fd) + GAChannelMethod method, int fd, Error **errp) { int ret; c->method = method; @@ -127,27 +129,48 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, switch (c->method) { case GA_CHANNEL_VIRTIO_SERIAL: { assert(fd < 0); - fd = qemu_open_old(path, O_RDWR | O_NONBLOCK + fd = qga_open_cloexec( + path, #ifndef CONFIG_SOLARIS - | O_ASYNC + O_ASYNC | #endif - ); + O_RDWR | O_NONBLOCK, + 0 + ); if (fd == -1) { - g_critical("error opening channel: %s", strerror(errno)); + error_setg_errno(errp, errno, "error opening channel '%s'", path); return false; } #ifdef CONFIG_SOLARIS ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI); if (ret == -1) { - g_critical("error setting event mask for channel: %s", - strerror(errno)); + error_setg_errno(errp, errno, "error setting event mask for channel"); close(fd); return false; } #endif +#ifdef __FreeBSD__ + /* + * In the default state channel sends echo of every command to a + * client. The client programm doesn't expect this and raises an + * error. Suppress echo by resetting ECHO terminal flag. + */ + struct termios tio; + if (tcgetattr(fd, &tio) < 0) { + error_setg_errno(errp, errno, "error getting channel termios attrs"); + close(fd); + return false; + } + tio.c_lflag &= ~ECHO; + if (tcsetattr(fd, TCSAFLUSH, &tio) < 0) { + error_setg_errno(errp, errno, "error setting channel termios attrs"); + close(fd); + return false; + } +#endif /* __FreeBSD__ */ ret = ga_channel_client_add(c, fd); if (ret) { - g_critical("error adding channel to main loop"); + error_setg(errp, "error adding channel to main loop"); close(fd); return false; } @@ -157,9 +180,9 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, struct termios tio; assert(fd < 0); - fd = qemu_open_old(path, O_RDWR | O_NOCTTY | O_NONBLOCK); + fd = qga_open_cloexec(path, O_RDWR | O_NOCTTY | O_NONBLOCK, 0); if (fd == -1) { - g_critical("error opening channel: %s", strerror(errno)); + error_setg_errno(errp, errno, "error opening channel '%s'", path); return false; } tcgetattr(fd, &tio); @@ -180,7 +203,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, tcsetattr(fd, TCSANOW, &tio); ret = ga_channel_client_add(c, fd); if (ret) { - g_critical("error adding channel to main loop"); + error_setg(errp, "error adding channel to main loop"); close(fd); return false; } @@ -188,12 +211,8 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, } case GA_CHANNEL_UNIX_LISTEN: { if (fd < 0) { - Error *local_err = NULL; - - fd = unix_listen(path, &local_err); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); + fd = unix_listen(path, errp); + if (fd < 0) { return false; } } @@ -202,24 +221,19 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, } case GA_CHANNEL_VSOCK_LISTEN: { if (fd < 0) { - Error *local_err = NULL; SocketAddress *addr; char *addr_str; addr_str = g_strdup_printf("vsock:%s", path); - addr = socket_parse(addr_str, &local_err); + addr = socket_parse(addr_str, errp); g_free(addr_str); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); + if (!addr) { return false; } - fd = socket_listen(addr, 1, &local_err); + fd = socket_listen(addr, 1, errp); qapi_free_SocketAddress(addr); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); + if (fd < 0) { return false; } } @@ -227,7 +241,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, break; } default: - g_critical("error binding/listening to specified socket"); + error_setg(errp, "error binding/listening to specified socket"); return false; } @@ -272,12 +286,14 @@ GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count) GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, int listen_fd, GAChannelCallback cb, gpointer opaque) { + Error *err = NULL; GAChannel *c = g_new0(GAChannel, 1); c->event_cb = cb; c->user_data = opaque; - if (!ga_channel_open(c, path, method, listen_fd)) { - g_critical("error opening channel"); + if (!ga_channel_open(c, path, method, listen_fd, &err)) { + g_critical("%s", error_get_pretty(err)); + error_free(err); ga_channel_free(c); return NULL; } diff --git a/qga/commands-bsd.c b/qga/commands-bsd.c new file mode 100644 index 000000000000..17bddda1cfb6 --- /dev/null +++ b/qga/commands-bsd.c @@ -0,0 +1,205 @@ +/* + * QEMU Guest Agent BSD-specific command implementations + * + * Copyright (c) Virtuozzo International GmbH. + * + * Authors: + * Alexander Ivanov + * + * 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 "qga-qapi-commands.h" +#include "qapi/qmp/qerror.h" +#include "qapi/error.h" +#include "qemu/queue.h" +#include "commands-common.h" +#include +#include +#include +#include +#include +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include +#include +#else +#include +#endif +#include + +#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) +bool build_fs_mount_list(FsMountList *mounts, Error **errp) +{ + FsMount *mount; + struct statfs *mntbuf, *mntp; + struct stat statbuf; + int i, count, ret; + + count = getmntinfo(&mntbuf, MNT_NOWAIT); + if (count == 0) { + error_setg_errno(errp, errno, "getmntinfo failed"); + return false; + } + + for (i = 0; i < count; i++) { + mntp = &mntbuf[i]; + ret = stat(mntp->f_mntonname, &statbuf); + if (ret != 0) { + error_setg_errno(errp, errno, "stat failed on %s", + mntp->f_mntonname); + return false; + } + + mount = g_new0(FsMount, 1); + + mount->dirname = g_strdup(mntp->f_mntonname); + mount->devtype = g_strdup(mntp->f_fstypename); + mount->devmajor = major(mount->dev); + mount->devminor = minor(mount->dev); + mount->fsid = mntp->f_fsid; + mount->dev = statbuf.st_dev; + + QTAILQ_INSERT_TAIL(mounts, mount, next); + } + return true; +} +#endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */ + +#if defined(CONFIG_FSFREEZE) +static int ufssuspend_fd = -1; +static int ufssuspend_cnt; + +int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints, + strList *mountpoints, + FsMountList mounts, + Error **errp) +{ + int ret; + strList *list; + struct FsMount *mount; + + if (ufssuspend_fd != -1) { + error_setg(errp, "filesystems have already frozen"); + return -1; + } + + ufssuspend_cnt = 0; + ufssuspend_fd = qemu_open(_PATH_UFSSUSPEND, O_RDWR, errp); + if (ufssuspend_fd == -1) { + return -1; + } + + QTAILQ_FOREACH_REVERSE(mount, &mounts, next) { + /* + * To issue fsfreeze in the reverse order of mounts, check if the + * mount is listed in the list here + */ + if (has_mountpoints) { + for (list = mountpoints; list; list = list->next) { + if (g_str_equal(list->value, mount->dirname)) { + break; + } + } + if (!list) { + continue; + } + } + + /* Only UFS supports suspend */ + if (!g_str_equal(mount->devtype, "ufs")) { + continue; + } + + ret = ioctl(ufssuspend_fd, UFSSUSPEND, &mount->fsid); + if (ret == -1) { + /* + * ioctl returns EBUSY for all the FS except the first one + * that was suspended + */ + if (errno == EBUSY) { + continue; + } + error_setg_errno(errp, errno, "failed to freeze %s", + mount->dirname); + goto error; + } + ufssuspend_cnt++; + } + return ufssuspend_cnt; +error: + close(ufssuspend_fd); + ufssuspend_fd = -1; + return -1; + +} + +/* + * We don't need to call UFSRESUME ioctl because all the frozen FS + * are thawed on /dev/ufssuspend closing. + */ +int qmp_guest_fsfreeze_do_thaw(Error **errp) +{ + int ret = ufssuspend_cnt; + ufssuspend_cnt = 0; + if (ufssuspend_fd != -1) { + close(ufssuspend_fd); + ufssuspend_fd = -1; + } + return ret; +} + +GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +GuestDiskInfoList *qmp_guest_get_disks(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} +#endif /* CONFIG_FSFREEZE */ + +#ifdef HAVE_GETIFADDRS +/* + * Fill "buf" with MAC address by ifaddrs. Pointer buf must point to a + * buffer with ETHER_ADDR_LEN length at least. + * + * Returns false in case of an error, otherwise true. "obtained" arguument + * is true if a MAC address was obtained successful, otherwise false. + */ +bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned char *buf, + bool *obtained, Error **errp) +{ + struct sockaddr_dl *sdp; + + *obtained = false; + + if (ifa->ifa_addr->sa_family != AF_LINK) { + /* We can get HW address only for AF_LINK family. */ + g_debug("failed to get MAC address of %s", ifa->ifa_name); + return true; + } + + sdp = (struct sockaddr_dl *)ifa->ifa_addr; + memcpy(buf, sdp->sdl_data + sdp->sdl_nlen, ETHER_ADDR_LEN); + *obtained = true; + + return true; +} +#endif /* HAVE_GETIFADDRS */ diff --git a/qga/commands-common.h b/qga/commands-common.h index 90785ed4bb7b..8c1c56aac970 100644 --- a/qga/commands-common.h +++ b/qga/commands-common.h @@ -10,6 +10,57 @@ #define QGA_COMMANDS_COMMON_H #include "qga-qapi-types.h" +#include "guest-agent-core.h" +#include "qemu/queue.h" + +#if defined(__linux__) +#include +#ifdef FIFREEZE +#define CONFIG_FSFREEZE +#endif +#ifdef FITRIM +#define CONFIG_FSTRIM +#endif +#endif /* __linux__ */ + +#ifdef __FreeBSD__ +#include +#ifdef UFSSUSPEND +#define CONFIG_FSFREEZE +#endif +#endif /* __FreeBSD__ */ + +#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) +typedef struct FsMount { + char *dirname; + char *devtype; + unsigned int devmajor, devminor; +#if defined(__FreeBSD__) + dev_t dev; + fsid_t fsid; +#endif + QTAILQ_ENTRY(FsMount) next; +} FsMount; + +typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList; + +bool build_fs_mount_list(FsMountList *mounts, Error **errp); +void free_fs_mount_list(FsMountList *mounts); +#endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */ + +#if defined(CONFIG_FSFREEZE) +int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints, + strList *mountpoints, + FsMountList mounts, + Error **errp); +int qmp_guest_fsfreeze_do_thaw(Error **errp); +#endif /* CONFIG_FSFREEZE */ + +#ifdef HAVE_GETIFADDRS +#include +bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned char *buf, + bool *obtained, Error **errp); +#endif typedef struct GuestFileHandle GuestFileHandle; @@ -18,4 +69,15 @@ GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp); GuestFileRead *guest_file_read_unsafe(GuestFileHandle *gfh, int64_t count, Error **errp); +/** + * qga_get_host_name: + * @errp: Error object + * + * Operating system agnostic way of querying host name. + * Compared to g_get_host_name(), it doesn't cache the result. + * + * Returns allocated hostname (caller should free), NULL on failure. + */ +char *qga_get_host_name(Error **errp); + #endif diff --git a/qga/commands-linux.c b/qga/commands-linux.c new file mode 100644 index 000000000000..214e408fcdd1 --- /dev/null +++ b/qga/commands-linux.c @@ -0,0 +1,286 @@ +/* + * QEMU Guest Agent Linux-specific command implementations + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Michael Roth + * Michal Privoznik + * + * 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 "qapi/error.h" +#include "commands-common.h" +#include "cutils.h" +#include +#include + +#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) +static int dev_major_minor(const char *devpath, + unsigned int *devmajor, unsigned int *devminor) +{ + struct stat st; + + *devmajor = 0; + *devminor = 0; + + if (stat(devpath, &st) < 0) { + slog("failed to stat device file '%s': %s", devpath, strerror(errno)); + return -1; + } + if (S_ISDIR(st.st_mode)) { + /* It is bind mount */ + return -2; + } + if (S_ISBLK(st.st_mode)) { + *devmajor = major(st.st_rdev); + *devminor = minor(st.st_rdev); + return 0; + } + return -1; +} + +static bool build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) +{ + struct mntent *ment; + FsMount *mount; + char const *mtab = "/proc/self/mounts"; + FILE *fp; + unsigned int devmajor, devminor; + + fp = setmntent(mtab, "r"); + if (!fp) { + error_setg(errp, "failed to open mtab file: '%s'", mtab); + return false; + } + + while ((ment = getmntent(fp))) { + /* + * An entry which device name doesn't start with a '/' is + * either a dummy file system or a network file system. + * Add special handling for smbfs and cifs as is done by + * coreutils as well. + */ + if ((ment->mnt_fsname[0] != '/') || + (strcmp(ment->mnt_type, "smbfs") == 0) || + (strcmp(ment->mnt_type, "cifs") == 0)) { + continue; + } + if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) { + /* Skip bind mounts */ + continue; + } + + mount = g_new0(FsMount, 1); + mount->dirname = g_strdup(ment->mnt_dir); + mount->devtype = g_strdup(ment->mnt_type); + mount->devmajor = devmajor; + mount->devminor = devminor; + + QTAILQ_INSERT_TAIL(mounts, mount, next); + } + + endmntent(fp); + return true; +} + +static void decode_mntname(char *name, int len) +{ + int i, j = 0; + for (i = 0; i <= len; i++) { + if (name[i] != '\\') { + name[j++] = name[i]; + } else if (name[i + 1] == '\\') { + name[j++] = '\\'; + i++; + } else if (name[i + 1] >= '0' && name[i + 1] <= '3' && + name[i + 2] >= '0' && name[i + 2] <= '7' && + name[i + 3] >= '0' && name[i + 3] <= '7') { + name[j++] = (name[i + 1] - '0') * 64 + + (name[i + 2] - '0') * 8 + + (name[i + 3] - '0'); + i += 3; + } else { + name[j++] = name[i]; + } + } +} + +/* + * Walk the mount table and build a list of local file systems + */ +bool build_fs_mount_list(FsMountList *mounts, Error **errp) +{ + FsMount *mount; + char const *mountinfo = "/proc/self/mountinfo"; + FILE *fp; + char *line = NULL, *dash; + size_t n; + char check; + unsigned int devmajor, devminor; + int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e; + + fp = fopen(mountinfo, "r"); + if (!fp) { + return build_fs_mount_list_from_mtab(mounts, errp); + } + + while (getline(&line, &n, fp) != -1) { + ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c", + &devmajor, &devminor, &dir_s, &dir_e, &check); + if (ret < 3) { + continue; + } + dash = strstr(line + dir_e, " - "); + if (!dash) { + continue; + } + ret = sscanf(dash, " - %n%*s%n %n%*s%n%c", + &type_s, &type_e, &dev_s, &dev_e, &check); + if (ret < 1) { + continue; + } + line[dir_e] = 0; + dash[type_e] = 0; + dash[dev_e] = 0; + decode_mntname(line + dir_s, dir_e - dir_s); + decode_mntname(dash + dev_s, dev_e - dev_s); + if (devmajor == 0) { + /* btrfs reports major number = 0 */ + if (strcmp("btrfs", dash + type_s) != 0 || + dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) { + continue; + } + } + + mount = g_new0(FsMount, 1); + mount->dirname = g_strdup(line + dir_s); + mount->devtype = g_strdup(dash + type_s); + mount->devmajor = devmajor; + mount->devminor = devminor; + + QTAILQ_INSERT_TAIL(mounts, mount, next); + } + free(line); + + fclose(fp); + return true; +} +#endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */ + +#ifdef CONFIG_FSFREEZE +/* + * Walk list of mounted file systems in the guest, and freeze the ones which + * are real local file systems. + */ +int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints, + strList *mountpoints, + FsMountList mounts, + Error **errp) +{ + struct FsMount *mount; + strList *list; + int fd, ret, i = 0; + + QTAILQ_FOREACH_REVERSE(mount, &mounts, next) { + /* To issue fsfreeze in the reverse order of mounts, check if the + * mount is listed in the list here */ + if (has_mountpoints) { + for (list = mountpoints; list; list = list->next) { + if (strcmp(list->value, mount->dirname) == 0) { + break; + } + } + if (!list) { + continue; + } + } + + fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); + if (fd == -1) { + error_setg_errno(errp, errno, "failed to open %s", mount->dirname); + return -1; + } + + /* we try to cull filesystems we know won't work in advance, but other + * filesystems may not implement fsfreeze for less obvious reasons. + * these will report EOPNOTSUPP. we simply ignore these when tallying + * the number of frozen filesystems. + * if a filesystem is mounted more than once (aka bind mount) a + * consecutive attempt to freeze an already frozen filesystem will + * return EBUSY. + * + * any other error means a failure to freeze a filesystem we + * expect to be freezable, so return an error in those cases + * and return system to thawed state. + */ + ret = ioctl(fd, FIFREEZE); + if (ret == -1) { + if (errno != EOPNOTSUPP && errno != EBUSY) { + error_setg_errno(errp, errno, "failed to freeze %s", + mount->dirname); + close(fd); + return -1; + } + } else { + i++; + } + close(fd); + } + return i; +} + +int qmp_guest_fsfreeze_do_thaw(Error **errp) +{ + int ret; + FsMountList mounts; + FsMount *mount; + int fd, i = 0, logged; + Error *local_err = NULL; + + QTAILQ_INIT(&mounts); + if (!build_fs_mount_list(&mounts, &local_err)) { + error_propagate(errp, local_err); + return -1; + } + + QTAILQ_FOREACH(mount, &mounts, next) { + logged = false; + fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); + if (fd == -1) { + continue; + } + /* we have no way of knowing whether a filesystem was actually unfrozen + * as a result of a successful call to FITHAW, only that if an error + * was returned the filesystem was *not* unfrozen by that particular + * call. + * + * since multiple preceding FIFREEZEs require multiple calls to FITHAW + * to unfreeze, continuing issuing FITHAW until an error is returned, + * in which case either the filesystem is in an unfreezable state, or, + * more likely, it was thawed previously (and remains so afterward). + * + * also, since the most recent successful call is the one that did + * the actual unfreeze, we can use this to provide an accurate count + * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which + * may * be useful for determining whether a filesystem was unfrozen + * during the freeze/thaw phase by a process other than qemu-ga. + */ + do { + ret = ioctl(fd, FITHAW); + if (ret == 0 && !logged) { + i++; + logged = true; + } + } while (ret == 0); + close(fd); + } + + free_fs_mount_list(&mounts); + + return i; +} +#endif /* CONFIG_FSFREEZE */ diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 75dbaab68ea9..ebd33a643cf9 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -16,49 +16,44 @@ #include #include #include -#include "qemu-common.h" -#include "guest-agent-core.h" #include "qga-qapi-commands.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" -#include "qemu/queue.h" #include "qemu/host-utils.h" #include "qemu/sockets.h" #include "qemu/base64.h" #include "qemu/cutils.h" #include "commands-common.h" +#include "block/nvme.h" +#include "cutils.h" #ifdef HAVE_UTMPX #include #endif -#ifndef CONFIG_HAS_ENVIRON -#ifdef __APPLE__ -#include -#define environ (*_NSGetEnviron()) -#else -extern char **environ; -#endif -#endif - #if defined(__linux__) #include -#include -#include -#include -#include -#include #include +#include #ifdef CONFIG_LIBUDEV #include #endif +#endif -#ifdef FIFREEZE -#define CONFIG_FSFREEZE +#ifdef HAVE_GETIFADDRS +#include +#include +#include +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include +#include +#else +#include #endif -#ifdef FITRIM -#define CONFIG_FSTRIM +#include +#ifdef CONFIG_SOLARIS +#include #endif #endif @@ -68,9 +63,7 @@ static void ga_wait_child(pid_t pid, int *status, Error **errp) *status = 0; - do { - rpid = waitpid(pid, status, 0); - } while (rpid == -1 && errno == EINTR); + rpid = RETRY_ON_EINTR(waitpid(pid, status, 0)); if (rpid == -1) { error_setg_errno(errp, errno, "failed to wait for child (pid: %d)", @@ -81,20 +74,34 @@ static void ga_wait_child(pid_t pid, int *status, Error **errp) g_assert(rpid == pid); } -void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) +void qmp_guest_shutdown(const char *mode, Error **errp) { const char *shutdown_flag; Error *local_err = NULL; pid_t pid; int status; +#ifdef CONFIG_SOLARIS + const char *powerdown_flag = "-i5"; + const char *halt_flag = "-i0"; + const char *reboot_flag = "-i6"; +#elif defined(CONFIG_BSD) + const char *powerdown_flag = "-p"; + const char *halt_flag = "-h"; + const char *reboot_flag = "-r"; +#else + const char *powerdown_flag = "-P"; + const char *halt_flag = "-H"; + const char *reboot_flag = "-r"; +#endif + slog("guest-shutdown called, mode: %s", mode); - if (!has_mode || strcmp(mode, "powerdown") == 0) { - shutdown_flag = "-P"; + if (!mode || strcmp(mode, "powerdown") == 0) { + shutdown_flag = powerdown_flag; } else if (strcmp(mode, "halt") == 0) { - shutdown_flag = "-H"; + shutdown_flag = halt_flag; } else if (strcmp(mode, "reboot") == 0) { - shutdown_flag = "-r"; + shutdown_flag = reboot_flag; } else { error_setg(errp, "mode is invalid (valid values are: halt|powerdown|reboot"); @@ -109,8 +116,16 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) reopen_fd_to_null(1); reopen_fd_to_null(2); - execle("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0", - "hypervisor initiated shutdown", (char *)NULL, environ); +#ifdef CONFIG_SOLARIS + execl("/sbin/shutdown", "shutdown", shutdown_flag, "-g0", "-y", + "hypervisor initiated shutdown", (char *)NULL); +#elif defined(CONFIG_BSD) + execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0", + "hypervisor initiated shutdown", (char *)NULL); +#else + execl("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0", + "hypervisor initiated shutdown", (char *)NULL); +#endif _exit(EXIT_FAILURE); } else if (pid < 0) { error_setg_errno(errp, errno, "failed to create child process"); @@ -136,20 +151,6 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) /* succeeded */ } -int64_t qmp_guest_get_time(Error **errp) -{ - int ret; - qemu_timeval tq; - - ret = qemu_gettimeofday(&tq); - if (ret < 0) { - error_setg_errno(errp, errno, "Failed to get time"); - return -1; - } - - return tq.tv_sec * 1000000000LL + tq.tv_usec * 1000; -} - void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) { int ret; @@ -207,8 +208,7 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) /* Use '/sbin/hwclock -w' to set RTC from the system time, * or '/sbin/hwclock -s' to set the system time from RTC. */ - execle(hwclock_path, "hwclock", has_time ? "-w" : "-s", - NULL, environ); + execl(hwclock_path, "hwclock", has_time ? "-w" : "-s", NULL); _exit(EXIT_FAILURE); } else if (pid < 0) { error_setg_errno(errp, errno, "failed to create child process"); @@ -340,83 +340,81 @@ find_open_flag(const char *mode_str, Error **errp) static FILE * safe_open_or_create(const char *path, const char *mode, Error **errp) { - Error *local_err = NULL; int oflag; + int fd = -1; + FILE *f = NULL; + + oflag = find_open_flag(mode, errp); + if (oflag < 0) { + goto end; + } + + /* If the caller wants / allows creation of a new file, we implement it + * with a two step process: open() + (open() / fchmod()). + * + * First we insist on creating the file exclusively as a new file. If + * that succeeds, we're free to set any file-mode bits on it. (The + * motivation is that we want to set those file-mode bits independently + * of the current umask.) + * + * If the exclusive creation fails because the file already exists + * (EEXIST is not possible for any other reason), we just attempt to + * open the file, but in this case we won't be allowed to change the + * file-mode bits on the preexistent file. + * + * The pathname should never disappear between the two open()s in + * practice. If it happens, then someone very likely tried to race us. + * In this case just go ahead and report the ENOENT from the second + * open() to the caller. + * + * If the caller wants to open a preexistent file, then the first + * open() is decisive and its third argument is ignored, and the second + * open() and the fchmod() are never called. + */ + fd = qga_open_cloexec(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0); + if (fd == -1 && errno == EEXIST) { + oflag &= ~(unsigned)O_CREAT; + fd = qga_open_cloexec(path, oflag, 0); + } + if (fd == -1) { + error_setg_errno(errp, errno, + "failed to open file '%s' (mode: '%s')", + path, mode); + goto end; + } - oflag = find_open_flag(mode, &local_err); - if (local_err == NULL) { - int fd; - - /* If the caller wants / allows creation of a new file, we implement it - * with a two step process: open() + (open() / fchmod()). - * - * First we insist on creating the file exclusively as a new file. If - * that succeeds, we're free to set any file-mode bits on it. (The - * motivation is that we want to set those file-mode bits independently - * of the current umask.) - * - * If the exclusive creation fails because the file already exists - * (EEXIST is not possible for any other reason), we just attempt to - * open the file, but in this case we won't be allowed to change the - * file-mode bits on the preexistent file. - * - * The pathname should never disappear between the two open()s in - * practice. If it happens, then someone very likely tried to race us. - * In this case just go ahead and report the ENOENT from the second - * open() to the caller. - * - * If the caller wants to open a preexistent file, then the first - * open() is decisive and its third argument is ignored, and the second - * open() and the fchmod() are never called. - */ - fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0); - if (fd == -1 && errno == EEXIST) { - oflag &= ~(unsigned)O_CREAT; - fd = open(path, oflag); - } - - if (fd == -1) { - error_setg_errno(&local_err, errno, "failed to open file '%s' " - "(mode: '%s')", path, mode); - } else { - qemu_set_cloexec(fd); + if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) { + error_setg_errno(errp, errno, "failed to set permission " + "0%03o on new file '%s' (mode: '%s')", + (unsigned)DEFAULT_NEW_FILE_MODE, path, mode); + goto end; + } - if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) { - error_setg_errno(&local_err, errno, "failed to set permission " - "0%03o on new file '%s' (mode: '%s')", - (unsigned)DEFAULT_NEW_FILE_MODE, path, mode); - } else { - FILE *f; - - f = fdopen(fd, mode); - if (f == NULL) { - error_setg_errno(&local_err, errno, "failed to associate " - "stdio stream with file descriptor %d, " - "file '%s' (mode: '%s')", fd, path, mode); - } else { - return f; - } - } + f = fdopen(fd, mode); + if (f == NULL) { + error_setg_errno(errp, errno, "failed to associate stdio stream with " + "file descriptor %d, file '%s' (mode: '%s')", + fd, path, mode); + } - close(fd); - if (oflag & O_CREAT) { - unlink(path); - } +end: + if (f == NULL && fd != -1) { + close(fd); + if (oflag & O_CREAT) { + unlink(path); } } - - error_propagate(errp, local_err); - return NULL; + return f; } -int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, +int64_t qmp_guest_file_open(const char *path, const char *mode, Error **errp) { FILE *fh; Error *local_err = NULL; int64_t handle; - if (!has_mode) { + if (!mode) { mode = "r"; } slog("guest-file-open called, filepath: %s, mode: %s", path, mode); @@ -429,7 +427,11 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, /* set fd non-blocking to avoid common use cases (like reading from a * named pipe) from hanging the agent */ - qemu_set_nonblock(fileno(fh)); + if (!g_unix_set_fd_nonblocking(fileno(fh), true, NULL)) { + fclose(fh); + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return -1; + } handle = guest_file_handle_add(fh, errp); if (handle < 0) { @@ -615,20 +617,8 @@ void qmp_guest_file_flush(int64_t handle, Error **errp) } } -/* linux-specific implementations. avoid this if at all possible. */ -#if defined(__linux__) - #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) -typedef struct FsMount { - char *dirname; - char *devtype; - unsigned int devmajor, devminor; - QTAILQ_ENTRY(FsMount) next; -} FsMount; - -typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList; - -static void free_fs_mount_list(FsMountList *mounts) +void free_fs_mount_list(FsMountList *mounts) { FsMount *mount, *temp; @@ -643,158 +633,158 @@ static void free_fs_mount_list(FsMountList *mounts) g_free(mount); } } +#endif + +#if defined(CONFIG_FSFREEZE) +typedef enum { + FSFREEZE_HOOK_THAW = 0, + FSFREEZE_HOOK_FREEZE, +} FsfreezeHookArg; + +static const char *fsfreeze_hook_arg_string[] = { + "thaw", + "freeze", +}; -static int dev_major_minor(const char *devpath, - unsigned int *devmajor, unsigned int *devminor) +static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp) { - struct stat st; + int status; + pid_t pid; + const char *hook; + const char *arg_str = fsfreeze_hook_arg_string[arg]; + Error *local_err = NULL; - *devmajor = 0; - *devminor = 0; + hook = ga_fsfreeze_hook(ga_state); + if (!hook) { + return; + } + if (access(hook, X_OK) != 0) { + error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook); + return; + } - if (stat(devpath, &st) < 0) { - slog("failed to stat device file '%s': %s", devpath, strerror(errno)); - return -1; + slog("executing fsfreeze hook with arg '%s'", arg_str); + pid = fork(); + if (pid == 0) { + setsid(); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execl(hook, hook, arg_str, NULL); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + error_setg_errno(errp, errno, "failed to create child process"); + return; + } + + ga_wait_child(pid, &status, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } - if (S_ISDIR(st.st_mode)) { - /* It is bind mount */ - return -2; + + if (!WIFEXITED(status)) { + error_setg(errp, "fsfreeze hook has terminated abnormally"); + return; } - if (S_ISBLK(st.st_mode)) { - *devmajor = major(st.st_rdev); - *devminor = minor(st.st_rdev); - return 0; + + status = WEXITSTATUS(status); + if (status) { + error_setg(errp, "fsfreeze hook has failed with status %d", status); + return; } - return -1; } /* - * Walk the mount table and build a list of local file systems + * Return status of freeze/thaw */ -static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) +GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp) { - struct mntent *ment; - FsMount *mount; - char const *mtab = "/proc/self/mounts"; - FILE *fp; - unsigned int devmajor, devminor; - - fp = setmntent(mtab, "r"); - if (!fp) { - error_setg(errp, "failed to open mtab file: '%s'", mtab); - return; + if (ga_is_frozen(ga_state)) { + return GUEST_FSFREEZE_STATUS_FROZEN; } - while ((ment = getmntent(fp))) { - /* - * An entry which device name doesn't start with a '/' is - * either a dummy file system or a network file system. - * Add special handling for smbfs and cifs as is done by - * coreutils as well. - */ - if ((ment->mnt_fsname[0] != '/') || - (strcmp(ment->mnt_type, "smbfs") == 0) || - (strcmp(ment->mnt_type, "cifs") == 0)) { - continue; - } - if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) { - /* Skip bind mounts */ - continue; - } + return GUEST_FSFREEZE_STATUS_THAWED; +} + +int64_t qmp_guest_fsfreeze_freeze(Error **errp) +{ + return qmp_guest_fsfreeze_freeze_list(false, NULL, errp); +} + +int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, + strList *mountpoints, + Error **errp) +{ + int ret; + FsMountList mounts; + Error *local_err = NULL; - mount = g_new0(FsMount, 1); - mount->dirname = g_strdup(ment->mnt_dir); - mount->devtype = g_strdup(ment->mnt_type); - mount->devmajor = devmajor; - mount->devminor = devminor; + slog("guest-fsfreeze called"); - QTAILQ_INSERT_TAIL(mounts, mount, next); + execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; } - endmntent(fp); -} + QTAILQ_INIT(&mounts); + if (!build_fs_mount_list(&mounts, &local_err)) { + error_propagate(errp, local_err); + return -1; + } -static void decode_mntname(char *name, int len) -{ - int i, j = 0; - for (i = 0; i <= len; i++) { - if (name[i] != '\\') { - name[j++] = name[i]; - } else if (name[i + 1] == '\\') { - name[j++] = '\\'; - i++; - } else if (name[i + 1] >= '0' && name[i + 1] <= '3' && - name[i + 2] >= '0' && name[i + 2] <= '7' && - name[i + 3] >= '0' && name[i + 3] <= '7') { - name[j++] = (name[i + 1] - '0') * 64 + - (name[i + 2] - '0') * 8 + - (name[i + 3] - '0'); - i += 3; - } else { - name[j++] = name[i]; - } + /* cannot risk guest agent blocking itself on a write in this state */ + ga_set_frozen(ga_state); + + ret = qmp_guest_fsfreeze_do_freeze_list(has_mountpoints, mountpoints, + mounts, errp); + + free_fs_mount_list(&mounts); + /* We may not issue any FIFREEZE here. + * Just unset ga_state here and ready for the next call. + */ + if (ret == 0) { + ga_unset_frozen(ga_state); + } else if (ret < 0) { + qmp_guest_fsfreeze_thaw(NULL); } + return ret; } -static void build_fs_mount_list(FsMountList *mounts, Error **errp) +int64_t qmp_guest_fsfreeze_thaw(Error **errp) { - FsMount *mount; - char const *mountinfo = "/proc/self/mountinfo"; - FILE *fp; - char *line = NULL, *dash; - size_t n; - char check; - unsigned int devmajor, devminor; - int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e; + int ret; - fp = fopen(mountinfo, "r"); - if (!fp) { - build_fs_mount_list_from_mtab(mounts, errp); - return; + ret = qmp_guest_fsfreeze_do_thaw(errp); + if (ret >= 0) { + ga_unset_frozen(ga_state); + execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp); + } else { + ret = 0; } - while (getline(&line, &n, fp) != -1) { - ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c", - &devmajor, &devminor, &dir_s, &dir_e, &check); - if (ret < 3) { - continue; - } - dash = strstr(line + dir_e, " - "); - if (!dash) { - continue; - } - ret = sscanf(dash, " - %n%*s%n %n%*s%n%c", - &type_s, &type_e, &dev_s, &dev_e, &check); - if (ret < 1) { - continue; - } - line[dir_e] = 0; - dash[type_e] = 0; - dash[dev_e] = 0; - decode_mntname(line + dir_s, dir_e - dir_s); - decode_mntname(dash + dev_s, dev_e - dev_s); - if (devmajor == 0) { - /* btrfs reports major number = 0 */ - if (strcmp("btrfs", dash + type_s) != 0 || - dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) { - continue; - } - } + return ret; +} - mount = g_new0(FsMount, 1); - mount->dirname = g_strdup(line + dir_s); - mount->devtype = g_strdup(dash + type_s); - mount->devmajor = devmajor; - mount->devminor = devminor; +static void guest_fsfreeze_cleanup(void) +{ + Error *err = NULL; - QTAILQ_INSERT_TAIL(mounts, mount, next); + if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { + qmp_guest_fsfreeze_thaw(&err); + if (err) { + slog("failed to clean up frozen filesystems: %s", + error_get_pretty(err)); + error_free(err); + } } - free(line); - - fclose(fp); } #endif +/* linux-specific implementations. avoid this if at all possible. */ +#if defined(__linux__) #if defined(CONFIG_FSFREEZE) static char *get_pci_driver(char const *syspath, int pathlen, Error **errp) @@ -889,7 +879,8 @@ static bool build_guest_fsinfo_for_pci_dev(char const *syspath, if (driver && (g_str_equal(driver, "ata_piix") || g_str_equal(driver, "sym53c8xx") || g_str_equal(driver, "virtio-pci") || - g_str_equal(driver, "ahci"))) { + g_str_equal(driver, "ahci") || + g_str_equal(driver, "nvme"))) { break; } @@ -984,6 +975,8 @@ static bool build_guest_fsinfo_for_pci_dev(char const *syspath, g_debug("no host for '%s' (driver '%s')", syspath, driver); goto cleanup; } + } else if (strcmp(driver, "nvme") == 0) { + disk->bus_type = GUEST_DISK_BUS_TYPE_NVME; } else { g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath); goto cleanup; @@ -1047,7 +1040,6 @@ static bool build_guest_fsinfo_for_ccw_dev(char const *syspath, return false; } - disk->has_ccw_address = true; disk->ccw_address = g_new0(GuestCCWAddress, 1); disk->ccw_address->cssid = cssid; disk->ccw_address->ssid = ssid; @@ -1094,12 +1086,10 @@ static void build_guest_fsinfo_for_real_device(char const *syspath, devnode = udev_device_get_devnode(udevice); if (devnode != NULL) { disk->dev = g_strdup(devnode); - disk->has_dev = true; } serial = udev_device_get_property_value(udevice, "ID_SERIAL"); if (serial != NULL && *serial != 0) { disk->serial = g_strdup(serial); - disk->has_serial = true; } } @@ -1118,7 +1108,7 @@ static void build_guest_fsinfo_for_real_device(char const *syspath, has_hwinf = false; } - if (has_hwinf || disk->has_dev || disk->has_serial) { + if (has_hwinf || disk->dev || disk->serial) { QAPI_LIST_PREPEND(fs->disk, disk); } else { qapi_free_GuestDiskAddress(disk); @@ -1201,7 +1191,15 @@ static void build_guest_fsinfo_for_device(char const *devpath, syspath = realpath(devpath, NULL); if (!syspath) { - error_setg_errno(errp, errno, "realpath(\"%s\")", devpath); + if (errno != ENOENT) { + error_setg_errno(errp, errno, "realpath(\"%s\")", devpath); + return; + } + + /* ENOENT: This devpath may not exist because of container config */ + if (!fs->name) { + fs->name = g_path_get_basename(devpath); + } return; } @@ -1387,6 +1385,75 @@ static GuestDiskInfoList *get_disk_partitions( return ret; } +static void get_nvme_smart(GuestDiskInfo *disk) +{ + int fd; + GuestNVMeSmart *smart; + NvmeSmartLog log = {0}; + struct nvme_admin_cmd cmd = { + .opcode = NVME_ADM_CMD_GET_LOG_PAGE, + .nsid = NVME_NSID_BROADCAST, + .addr = (uintptr_t)&log, + .data_len = sizeof(log), + .cdw10 = NVME_LOG_SMART_INFO | (1 << 15) /* RAE bit */ + | (((sizeof(log) >> 2) - 1) << 16) + }; + + fd = qga_open_cloexec(disk->name, O_RDONLY, 0); + if (fd == -1) { + g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno)); + return; + } + + if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd)) { + g_debug("Failed to get smart: %s: %s", disk->name, g_strerror(errno)); + close(fd); + return; + } + + disk->smart = g_new0(GuestDiskSmart, 1); + disk->smart->type = GUEST_DISK_BUS_TYPE_NVME; + + smart = &disk->smart->u.nvme; + smart->critical_warning = log.critical_warning; + smart->temperature = lduw_le_p(&log.temperature); /* unaligned field */ + smart->available_spare = log.available_spare; + smart->available_spare_threshold = log.available_spare_threshold; + smart->percentage_used = log.percentage_used; + smart->data_units_read_lo = le64_to_cpu(log.data_units_read[0]); + smart->data_units_read_hi = le64_to_cpu(log.data_units_read[1]); + smart->data_units_written_lo = le64_to_cpu(log.data_units_written[0]); + smart->data_units_written_hi = le64_to_cpu(log.data_units_written[1]); + smart->host_read_commands_lo = le64_to_cpu(log.host_read_commands[0]); + smart->host_read_commands_hi = le64_to_cpu(log.host_read_commands[1]); + smart->host_write_commands_lo = le64_to_cpu(log.host_write_commands[0]); + smart->host_write_commands_hi = le64_to_cpu(log.host_write_commands[1]); + smart->controller_busy_time_lo = le64_to_cpu(log.controller_busy_time[0]); + smart->controller_busy_time_hi = le64_to_cpu(log.controller_busy_time[1]); + smart->power_cycles_lo = le64_to_cpu(log.power_cycles[0]); + smart->power_cycles_hi = le64_to_cpu(log.power_cycles[1]); + smart->power_on_hours_lo = le64_to_cpu(log.power_on_hours[0]); + smart->power_on_hours_hi = le64_to_cpu(log.power_on_hours[1]); + smart->unsafe_shutdowns_lo = le64_to_cpu(log.unsafe_shutdowns[0]); + smart->unsafe_shutdowns_hi = le64_to_cpu(log.unsafe_shutdowns[1]); + smart->media_errors_lo = le64_to_cpu(log.media_errors[0]); + smart->media_errors_hi = le64_to_cpu(log.media_errors[1]); + smart->number_of_error_log_entries_lo = + le64_to_cpu(log.number_of_error_log_entries[0]); + smart->number_of_error_log_entries_hi = + le64_to_cpu(log.number_of_error_log_entries[1]); + + close(fd); +} + +static void get_disk_smart(GuestDiskInfo *disk) +{ + if (disk->address + && (disk->address->bus_type == GUEST_DISK_BUS_TYPE_NVME)) { + get_nvme_smart(disk); + } +} + GuestDiskInfoList *qmp_guest_get_disks(Error **errp) { GuestDiskInfoList *ret = NULL; @@ -1434,7 +1501,6 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) disk->name = dev_name; disk->partition = false; disk->alias = get_alias_for_syspath(disk_dir); - disk->has_alias = (disk->alias != NULL); QAPI_LIST_PREPEND(ret, disk); /* Get address for non-virtual devices */ @@ -1454,12 +1520,11 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) error_get_pretty(local_err)); error_free(local_err); local_err = NULL; - } else if (disk->address != NULL) { - disk->has_address = true; } } get_disk_deps(disk_dir, disk); + get_disk_smart(disk); ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name); } @@ -1516,8 +1581,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) Error *local_err = NULL; QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { + if (!build_fs_mount_list(&mounts, &local_err)) { error_propagate(errp, local_err); return NULL; } @@ -1537,278 +1601,31 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) free_fs_mount_list(&mounts); return ret; } +#endif /* CONFIG_FSFREEZE */ +#if defined(CONFIG_FSTRIM) +/* + * Walk list of mounted file systems in the guest, and trim them. + */ +GuestFilesystemTrimResponse * +qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) +{ + GuestFilesystemTrimResponse *response; + GuestFilesystemTrimResult *result; + int ret = 0; + FsMountList mounts; + struct FsMount *mount; + int fd; + struct fstrim_range r; -typedef enum { - FSFREEZE_HOOK_THAW = 0, - FSFREEZE_HOOK_FREEZE, -} FsfreezeHookArg; + slog("guest-fstrim called"); -static const char *fsfreeze_hook_arg_string[] = { - "thaw", - "freeze", -}; + QTAILQ_INIT(&mounts); + if (!build_fs_mount_list(&mounts, errp)) { + return NULL; + } -static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp) -{ - int status; - pid_t pid; - const char *hook; - const char *arg_str = fsfreeze_hook_arg_string[arg]; - Error *local_err = NULL; - - hook = ga_fsfreeze_hook(ga_state); - if (!hook) { - return; - } - if (access(hook, X_OK) != 0) { - error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook); - return; - } - - slog("executing fsfreeze hook with arg '%s'", arg_str); - pid = fork(); - if (pid == 0) { - setsid(); - reopen_fd_to_null(0); - reopen_fd_to_null(1); - reopen_fd_to_null(2); - - execle(hook, hook, arg_str, NULL, environ); - _exit(EXIT_FAILURE); - } else if (pid < 0) { - error_setg_errno(errp, errno, "failed to create child process"); - return; - } - - ga_wait_child(pid, &status, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - if (!WIFEXITED(status)) { - error_setg(errp, "fsfreeze hook has terminated abnormally"); - return; - } - - status = WEXITSTATUS(status); - if (status) { - error_setg(errp, "fsfreeze hook has failed with status %d", status); - return; - } -} - -/* - * Return status of freeze/thaw - */ -GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp) -{ - if (ga_is_frozen(ga_state)) { - return GUEST_FSFREEZE_STATUS_FROZEN; - } - - return GUEST_FSFREEZE_STATUS_THAWED; -} - -int64_t qmp_guest_fsfreeze_freeze(Error **errp) -{ - return qmp_guest_fsfreeze_freeze_list(false, NULL, errp); -} - -/* - * Walk list of mounted file systems in the guest, and freeze the ones which - * are real local file systems. - */ -int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, - strList *mountpoints, - Error **errp) -{ - int ret = 0, i = 0; - strList *list; - FsMountList mounts; - struct FsMount *mount; - Error *local_err = NULL; - int fd; - - slog("guest-fsfreeze called"); - - execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return -1; - } - - QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return -1; - } - - /* cannot risk guest agent blocking itself on a write in this state */ - ga_set_frozen(ga_state); - - QTAILQ_FOREACH_REVERSE(mount, &mounts, next) { - /* To issue fsfreeze in the reverse order of mounts, check if the - * mount is listed in the list here */ - if (has_mountpoints) { - for (list = mountpoints; list; list = list->next) { - if (strcmp(list->value, mount->dirname) == 0) { - break; - } - } - if (!list) { - continue; - } - } - - fd = qemu_open_old(mount->dirname, O_RDONLY); - if (fd == -1) { - error_setg_errno(errp, errno, "failed to open %s", mount->dirname); - goto error; - } - - /* we try to cull filesystems we know won't work in advance, but other - * filesystems may not implement fsfreeze for less obvious reasons. - * these will report EOPNOTSUPP. we simply ignore these when tallying - * the number of frozen filesystems. - * if a filesystem is mounted more than once (aka bind mount) a - * consecutive attempt to freeze an already frozen filesystem will - * return EBUSY. - * - * any other error means a failure to freeze a filesystem we - * expect to be freezable, so return an error in those cases - * and return system to thawed state. - */ - ret = ioctl(fd, FIFREEZE); - if (ret == -1) { - if (errno != EOPNOTSUPP && errno != EBUSY) { - error_setg_errno(errp, errno, "failed to freeze %s", - mount->dirname); - close(fd); - goto error; - } - } else { - i++; - } - close(fd); - } - - free_fs_mount_list(&mounts); - /* We may not issue any FIFREEZE here. - * Just unset ga_state here and ready for the next call. - */ - if (i == 0) { - ga_unset_frozen(ga_state); - } - return i; - -error: - free_fs_mount_list(&mounts); - qmp_guest_fsfreeze_thaw(NULL); - return 0; -} - -/* - * Walk list of frozen file systems in the guest, and thaw them. - */ -int64_t qmp_guest_fsfreeze_thaw(Error **errp) -{ - int ret; - FsMountList mounts; - FsMount *mount; - int fd, i = 0, logged; - Error *local_err = NULL; - - QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return 0; - } - - QTAILQ_FOREACH(mount, &mounts, next) { - logged = false; - fd = qemu_open_old(mount->dirname, O_RDONLY); - if (fd == -1) { - continue; - } - /* we have no way of knowing whether a filesystem was actually unfrozen - * as a result of a successful call to FITHAW, only that if an error - * was returned the filesystem was *not* unfrozen by that particular - * call. - * - * since multiple preceding FIFREEZEs require multiple calls to FITHAW - * to unfreeze, continuing issuing FITHAW until an error is returned, - * in which case either the filesystem is in an unfreezable state, or, - * more likely, it was thawed previously (and remains so afterward). - * - * also, since the most recent successful call is the one that did - * the actual unfreeze, we can use this to provide an accurate count - * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which - * may * be useful for determining whether a filesystem was unfrozen - * during the freeze/thaw phase by a process other than qemu-ga. - */ - do { - ret = ioctl(fd, FITHAW); - if (ret == 0 && !logged) { - i++; - logged = true; - } - } while (ret == 0); - close(fd); - } - - ga_unset_frozen(ga_state); - free_fs_mount_list(&mounts); - - execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp); - - return i; -} - -static void guest_fsfreeze_cleanup(void) -{ - Error *err = NULL; - - if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { - qmp_guest_fsfreeze_thaw(&err); - if (err) { - slog("failed to clean up frozen filesystems: %s", - error_get_pretty(err)); - error_free(err); - } - } -} -#endif /* CONFIG_FSFREEZE */ - -#if defined(CONFIG_FSTRIM) -/* - * Walk list of mounted file systems in the guest, and trim them. - */ -GuestFilesystemTrimResponse * -qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) -{ - GuestFilesystemTrimResponse *response; - GuestFilesystemTrimResult *result; - int ret = 0; - FsMountList mounts; - struct FsMount *mount; - int fd; - Error *local_err = NULL; - struct fstrim_range r; - - slog("guest-fstrim called"); - - QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return NULL; - } - - response = g_malloc0(sizeof(*response)); + response = g_malloc0(sizeof(*response)); QTAILQ_FOREACH(mount, &mounts, next) { result = g_malloc0(sizeof(*result)); @@ -1816,11 +1633,10 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) QAPI_LIST_PREPEND(response->paths, result); - fd = qemu_open_old(mount->dirname, O_RDONLY); + fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); if (fd == -1) { result->error = g_strdup_printf("failed to open: %s", strerror(errno)); - result->has_error = true; continue; } @@ -1835,7 +1651,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) r.minlen = has_minimum ? minimum : 0; ret = ioctl(fd, FITRIM, &r); if (ret == -1) { - result->has_error = true; if (errno == ENOTTY || errno == EOPNOTSUPP) { result->error = g_strdup("trim not supported"); } else { @@ -1888,7 +1703,7 @@ static int run_process_child(const char *command[], Error **errp) spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; - success = g_spawn_sync(NULL, (char **)command, environ, spawn_flag, + success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag, NULL, NULL, NULL, NULL, &exit_status, &g_err); @@ -2154,223 +1969,6 @@ void qmp_guest_suspend_hybrid(Error **errp) guest_suspend(SUSPEND_MODE_HYBRID, errp); } -static GuestNetworkInterface * -guest_find_interface(GuestNetworkInterfaceList *head, - const char *name) -{ - for (; head; head = head->next) { - if (strcmp(head->value->name, name) == 0) { - return head->value; - } - } - - return NULL; -} - -static int guest_get_network_stats(const char *name, - GuestNetworkInterfaceStat *stats) -{ - int name_len; - char const *devinfo = "/proc/net/dev"; - FILE *fp; - char *line = NULL, *colon; - size_t n = 0; - fp = fopen(devinfo, "r"); - if (!fp) { - return -1; - } - name_len = strlen(name); - while (getline(&line, &n, fp) != -1) { - long long dummy; - long long rx_bytes; - long long rx_packets; - long long rx_errs; - long long rx_dropped; - long long tx_bytes; - long long tx_packets; - long long tx_errs; - long long tx_dropped; - char *trim_line; - trim_line = g_strchug(line); - if (trim_line[0] == '\0') { - continue; - } - colon = strchr(trim_line, ':'); - if (!colon) { - continue; - } - if (colon - name_len == trim_line && - strncmp(trim_line, name, name_len) == 0) { - if (sscanf(colon + 1, - "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld", - &rx_bytes, &rx_packets, &rx_errs, &rx_dropped, - &dummy, &dummy, &dummy, &dummy, - &tx_bytes, &tx_packets, &tx_errs, &tx_dropped, - &dummy, &dummy, &dummy, &dummy) != 16) { - continue; - } - stats->rx_bytes = rx_bytes; - stats->rx_packets = rx_packets; - stats->rx_errs = rx_errs; - stats->rx_dropped = rx_dropped; - stats->tx_bytes = tx_bytes; - stats->tx_packets = tx_packets; - stats->tx_errs = tx_errs; - stats->tx_dropped = tx_dropped; - fclose(fp); - g_free(line); - return 0; - } - } - fclose(fp); - g_free(line); - g_debug("/proc/net/dev: Interface '%s' not found", name); - return -1; -} - -/* - * Build information about guest interfaces - */ -GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) -{ - GuestNetworkInterfaceList *head = NULL, **tail = &head; - struct ifaddrs *ifap, *ifa; - - if (getifaddrs(&ifap) < 0) { - error_setg_errno(errp, errno, "getifaddrs failed"); - goto error; - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - GuestNetworkInterface *info; - GuestIpAddressList **address_tail; - GuestIpAddress *address_item = NULL; - GuestNetworkInterfaceStat *interface_stat = NULL; - char addr4[INET_ADDRSTRLEN]; - char addr6[INET6_ADDRSTRLEN]; - int sock; - struct ifreq ifr; - unsigned char *mac_addr; - void *p; - - g_debug("Processing %s interface", ifa->ifa_name); - - info = guest_find_interface(head, ifa->ifa_name); - - if (!info) { - info = g_malloc0(sizeof(*info)); - info->name = g_strdup(ifa->ifa_name); - - QAPI_LIST_APPEND(tail, info); - } - - if (!info->has_hardware_address && ifa->ifa_flags & SIOCGIFHWADDR) { - /* we haven't obtained HW address yet */ - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock == -1) { - error_setg_errno(errp, errno, "failed to create socket"); - goto error; - } - - memset(&ifr, 0, sizeof(ifr)); - pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->name); - if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { - error_setg_errno(errp, errno, - "failed to get MAC address of %s", - ifa->ifa_name); - close(sock); - goto error; - } - - close(sock); - mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; - - info->hardware_address = - g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", - (int) mac_addr[0], (int) mac_addr[1], - (int) mac_addr[2], (int) mac_addr[3], - (int) mac_addr[4], (int) mac_addr[5]); - - info->has_hardware_address = true; - } - - if (ifa->ifa_addr && - ifa->ifa_addr->sa_family == AF_INET) { - /* interface with IPv4 address */ - p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { - error_setg_errno(errp, errno, "inet_ntop failed"); - goto error; - } - - address_item = g_malloc0(sizeof(*address_item)); - address_item->ip_address = g_strdup(addr4); - address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; - - if (ifa->ifa_netmask) { - /* Count the number of set bits in netmask. - * This is safe as '1' and '0' cannot be shuffled in netmask. */ - p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; - address_item->prefix = ctpop32(((uint32_t *) p)[0]); - } - } else if (ifa->ifa_addr && - ifa->ifa_addr->sa_family == AF_INET6) { - /* interface with IPv6 address */ - p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; - if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { - error_setg_errno(errp, errno, "inet_ntop failed"); - goto error; - } - - address_item = g_malloc0(sizeof(*address_item)); - address_item->ip_address = g_strdup(addr6); - address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; - - if (ifa->ifa_netmask) { - /* Count the number of set bits in netmask. - * This is safe as '1' and '0' cannot be shuffled in netmask. */ - p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; - address_item->prefix = - ctpop32(((uint32_t *) p)[0]) + - ctpop32(((uint32_t *) p)[1]) + - ctpop32(((uint32_t *) p)[2]) + - ctpop32(((uint32_t *) p)[3]); - } - } - - if (!address_item) { - continue; - } - - address_tail = &info->ip_addresses; - while (*address_tail) { - address_tail = &(*address_tail)->next; - } - QAPI_LIST_APPEND(address_tail, address_item); - - info->has_ip_addresses = true; - - if (!info->has_statistics) { - interface_stat = g_malloc0(sizeof(*interface_stat)); - if (guest_get_network_stats(info->name, interface_stat) == -1) { - info->has_statistics = false; - g_free(interface_stat); - } else { - info->statistics = interface_stat; - info->has_statistics = true; - } - } - } - - freeifaddrs(ifap); - return head; - -error: - freeifaddrs(ifap); - qapi_free_GuestNetworkInterfaceList(head); - return NULL; -} - /* Transfer online/offline status between @vcpu and the guest system. * * On input either @errp or *@errp must be NULL. @@ -2510,7 +2108,9 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) return processed; } +#endif /* __linux__ */ +#if defined(__linux__) || defined(__FreeBSD__) void qmp_guest_set_user_password(const char *username, const char *password, bool crypted, @@ -2544,17 +2144,22 @@ void qmp_guest_set_user_password(const char *username, goto out; } +#ifdef __FreeBSD__ + chpasswddata = g_strdup(rawpasswddata); + passwd_path = g_find_program_in_path("pw"); +#else chpasswddata = g_strdup_printf("%s:%s\n", username, rawpasswddata); - chpasswdlen = strlen(chpasswddata); - passwd_path = g_find_program_in_path("chpasswd"); +#endif + + chpasswdlen = strlen(chpasswddata); if (!passwd_path) { error_setg(errp, "cannot find 'passwd' program in PATH"); goto out; } - if (pipe(datafd) < 0) { + if (!g_unix_open_pipe(datafd, FD_CLOEXEC, NULL)) { error_setg(errp, "cannot create pipe FDs"); goto out; } @@ -2568,11 +2173,17 @@ void qmp_guest_set_user_password(const char *username, reopen_fd_to_null(1); reopen_fd_to_null(2); +#ifdef __FreeBSD__ + const char *h_arg; + h_arg = (crypted) ? "-H" : "-h"; + execl(passwd_path, "pw", "usermod", "-n", username, h_arg, "0", NULL); +#else if (crypted) { - execle(passwd_path, "chpasswd", "-e", NULL, environ); + execl(passwd_path, "chpasswd", "-e", NULL); } else { - execle(passwd_path, "chpasswd", NULL, environ); + execl(passwd_path, "chpasswd", NULL); } +#endif _exit(EXIT_FAILURE); } else if (pid < 0) { error_setg_errno(errp, errno, "failed to create child process"); @@ -2615,7 +2226,17 @@ void qmp_guest_set_user_password(const char *username, close(datafd[1]); } } +#else /* __linux__ || __FreeBSD__ */ +void qmp_guest_set_user_password(const char *username, + const char *password, + bool crypted, + Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); +} +#endif /* __linux__ || __FreeBSD__ */ +#ifdef __linux__ static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf, int size, Error **errp) { @@ -2923,6 +2544,206 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp) return info; } +#define MAX_NAME_LEN 128 +static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp) +{ +#ifdef CONFIG_LINUX + GuestDiskStatsInfoList *head = NULL, **tail = &head; + const char *diskstats = "/proc/diskstats"; + FILE *fp; + size_t n; + char *line = NULL; + + fp = fopen(diskstats, "r"); + if (fp == NULL) { + error_setg_errno(errp, errno, "open(\"%s\")", diskstats); + return NULL; + } + + while (getline(&line, &n, fp) != -1) { + g_autofree GuestDiskStatsInfo *diskstatinfo = NULL; + g_autofree GuestDiskStats *diskstat = NULL; + char dev_name[MAX_NAME_LEN]; + unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks; + unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios; + unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec; + unsigned long dc_ios, dc_merges, dc_sec, fl_ios; + unsigned int major, minor; + int i; + + i = sscanf(line, "%u %u %s %lu %lu %lu" + "%lu %lu %lu %lu %u %u %u %u" + "%lu %lu %lu %u %lu %u", + &major, &minor, dev_name, + &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, + &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec, + &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks, + &dc_ios, &dc_merges, &dc_sec, &dc_ticks, + &fl_ios, &fl_ticks); + + if (i < 7) { + continue; + } + + diskstatinfo = g_new0(GuestDiskStatsInfo, 1); + diskstatinfo->name = g_strdup(dev_name); + diskstatinfo->major = major; + diskstatinfo->minor = minor; + + diskstat = g_new0(GuestDiskStats, 1); + if (i == 7) { + diskstat->has_read_ios = true; + diskstat->read_ios = rd_ios; + diskstat->has_read_sectors = true; + diskstat->read_sectors = rd_merges_or_rd_sec; + diskstat->has_write_ios = true; + diskstat->write_ios = rd_sec_or_wr_ios; + diskstat->has_write_sectors = true; + diskstat->write_sectors = rd_ticks_or_wr_sec; + } + if (i >= 14) { + diskstat->has_read_ios = true; + diskstat->read_ios = rd_ios; + diskstat->has_read_sectors = true; + diskstat->read_sectors = rd_sec_or_wr_ios; + diskstat->has_read_merges = true; + diskstat->read_merges = rd_merges_or_rd_sec; + diskstat->has_read_ticks = true; + diskstat->read_ticks = rd_ticks_or_wr_sec; + diskstat->has_write_ios = true; + diskstat->write_ios = wr_ios; + diskstat->has_write_sectors = true; + diskstat->write_sectors = wr_sec; + diskstat->has_write_merges = true; + diskstat->write_merges = wr_merges; + diskstat->has_write_ticks = true; + diskstat->write_ticks = wr_ticks; + diskstat->has_ios_pgr = true; + diskstat->ios_pgr = ios_pgr; + diskstat->has_total_ticks = true; + diskstat->total_ticks = tot_ticks; + diskstat->has_weight_ticks = true; + diskstat->weight_ticks = rq_ticks; + } + if (i >= 18) { + diskstat->has_discard_ios = true; + diskstat->discard_ios = dc_ios; + diskstat->has_discard_merges = true; + diskstat->discard_merges = dc_merges; + diskstat->has_discard_sectors = true; + diskstat->discard_sectors = dc_sec; + diskstat->has_discard_ticks = true; + diskstat->discard_ticks = dc_ticks; + } + if (i >= 20) { + diskstat->has_flush_ios = true; + diskstat->flush_ios = fl_ios; + diskstat->has_flush_ticks = true; + diskstat->flush_ticks = fl_ticks; + } + + diskstatinfo->stats = g_steal_pointer(&diskstat); + QAPI_LIST_APPEND(tail, diskstatinfo); + diskstatinfo = NULL; + } + free(line); + fclose(fp); + return head; +#else + g_debug("disk stats reporting available only for Linux"); + return NULL; +#endif +} + +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + return guest_get_diskstats(errp); +} + +GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp) +{ + GuestCpuStatsList *head = NULL, **tail = &head; + const char *cpustats = "/proc/stat"; + int clk_tck = sysconf(_SC_CLK_TCK); + FILE *fp; + size_t n; + char *line = NULL; + + fp = fopen(cpustats, "r"); + if (fp == NULL) { + error_setg_errno(errp, errno, "open(\"%s\")", cpustats); + return NULL; + } + + while (getline(&line, &n, fp) != -1) { + GuestCpuStats *cpustat = NULL; + GuestLinuxCpuStats *linuxcpustat; + int i; + unsigned long user, system, idle, iowait, irq, softirq, steal, guest; + unsigned long nice, guest_nice; + char name[64]; + + i = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + name, &user, &nice, &system, &idle, &iowait, &irq, &softirq, + &steal, &guest, &guest_nice); + + /* drop "cpu 1 2 3 ...", get "cpuX 1 2 3 ..." only */ + if ((i == EOF) || strncmp(name, "cpu", 3) || (name[3] == '\0')) { + continue; + } + + if (i < 5) { + slog("Parsing cpu stat from %s failed, see \"man proc\"", cpustats); + break; + } + + cpustat = g_new0(GuestCpuStats, 1); + cpustat->type = GUEST_CPU_STATS_TYPE_LINUX; + + linuxcpustat = &cpustat->u.q_linux; + linuxcpustat->cpu = atoi(&name[3]); + linuxcpustat->user = user * 1000 / clk_tck; + linuxcpustat->nice = nice * 1000 / clk_tck; + linuxcpustat->system = system * 1000 / clk_tck; + linuxcpustat->idle = idle * 1000 / clk_tck; + + if (i > 5) { + linuxcpustat->has_iowait = true; + linuxcpustat->iowait = iowait * 1000 / clk_tck; + } + + if (i > 6) { + linuxcpustat->has_irq = true; + linuxcpustat->irq = irq * 1000 / clk_tck; + linuxcpustat->has_softirq = true; + linuxcpustat->softirq = softirq * 1000 / clk_tck; + } + + if (i > 8) { + linuxcpustat->has_steal = true; + linuxcpustat->steal = steal * 1000 / clk_tck; + } + + if (i > 9) { + linuxcpustat->has_guest = true; + linuxcpustat->guest = guest * 1000 / clk_tck; + } + + if (i > 10) { + linuxcpustat->has_guest = true; + linuxcpustat->guest = guest * 1000 / clk_tck; + linuxcpustat->has_guestnice = true; + linuxcpustat->guestnice = guest_nice * 1000 / clk_tck; + } + + QAPI_LIST_APPEND(tail, cpustat); + } + + free(line); + fclose(fp); + return head; +} + #else /* defined(__linux__) */ void qmp_guest_suspend_disk(Error **errp) @@ -2940,12 +2761,6 @@ void qmp_guest_suspend_hybrid(Error **errp) error_setg(errp, QERR_UNSUPPORTED); } -GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) -{ - error_setg(errp, QERR_UNSUPPORTED); - return NULL; -} - GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) { error_setg(errp, QERR_UNSUPPORTED); @@ -2958,14 +2773,6 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) return -1; } -void qmp_guest_set_user_password(const char *username, - const char *password, - bool crypted, - Error **errp) -{ - error_setg(errp, QERR_UNSUPPORTED); -} - GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp) { error_setg(errp, QERR_UNSUPPORTED); @@ -2987,6 +2794,271 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp) #endif +#ifdef HAVE_GETIFADDRS +static GuestNetworkInterface * +guest_find_interface(GuestNetworkInterfaceList *head, + const char *name) +{ + for (; head; head = head->next) { + if (strcmp(head->value->name, name) == 0) { + return head->value; + } + } + + return NULL; +} + +static int guest_get_network_stats(const char *name, + GuestNetworkInterfaceStat *stats) +{ +#ifdef CONFIG_LINUX + int name_len; + char const *devinfo = "/proc/net/dev"; + FILE *fp; + char *line = NULL, *colon; + size_t n = 0; + fp = fopen(devinfo, "r"); + if (!fp) { + g_debug("failed to open network stats %s: %s", devinfo, + g_strerror(errno)); + return -1; + } + name_len = strlen(name); + while (getline(&line, &n, fp) != -1) { + long long dummy; + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_dropped; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_dropped; + char *trim_line; + trim_line = g_strchug(line); + if (trim_line[0] == '\0') { + continue; + } + colon = strchr(trim_line, ':'); + if (!colon) { + continue; + } + if (colon - name_len == trim_line && + strncmp(trim_line, name, name_len) == 0) { + if (sscanf(colon + 1, + "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld", + &rx_bytes, &rx_packets, &rx_errs, &rx_dropped, + &dummy, &dummy, &dummy, &dummy, + &tx_bytes, &tx_packets, &tx_errs, &tx_dropped, + &dummy, &dummy, &dummy, &dummy) != 16) { + continue; + } + stats->rx_bytes = rx_bytes; + stats->rx_packets = rx_packets; + stats->rx_errs = rx_errs; + stats->rx_dropped = rx_dropped; + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + stats->tx_errs = tx_errs; + stats->tx_dropped = tx_dropped; + fclose(fp); + g_free(line); + return 0; + } + } + fclose(fp); + g_free(line); + g_debug("/proc/net/dev: Interface '%s' not found", name); +#else /* !CONFIG_LINUX */ + g_debug("Network stats reporting available only for Linux"); +#endif /* !CONFIG_LINUX */ + return -1; +} + +#ifndef CONFIG_BSD +/* + * Fill "buf" with MAC address by ifaddrs. Pointer buf must point to a + * buffer with ETHER_ADDR_LEN length at least. + * + * Returns false in case of an error, otherwise true. "obtained" argument + * is true if a MAC address was obtained successful, otherwise false. + */ +bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned char *buf, + bool *obtained, Error **errp) +{ + struct ifreq ifr; + int sock; + + *obtained = false; + + /* we haven't obtained HW address yet */ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock == -1) { + error_setg_errno(errp, errno, "failed to create socket"); + return false; + } + + memset(&ifr, 0, sizeof(ifr)); + pstrcpy(ifr.ifr_name, IF_NAMESIZE, ifa->ifa_name); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { + /* + * We can't get the hw addr of this interface, but that's not a + * fatal error. + */ + if (errno == EADDRNOTAVAIL) { + /* The interface doesn't have a hw addr (e.g. loopback). */ + g_debug("failed to get MAC address of %s: %s", + ifa->ifa_name, strerror(errno)); + } else{ + g_warning("failed to get MAC address of %s: %s", + ifa->ifa_name, strerror(errno)); + } + } else { +#ifdef CONFIG_SOLARIS + memcpy(buf, &ifr.ifr_addr.sa_data, ETHER_ADDR_LEN); +#else + memcpy(buf, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); +#endif + *obtained = true; + } + close(sock); + return true; +} +#endif /* CONFIG_BSD */ + +/* + * Build information about guest interfaces + */ +GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) +{ + GuestNetworkInterfaceList *head = NULL, **tail = &head; + struct ifaddrs *ifap, *ifa; + + if (getifaddrs(&ifap) < 0) { + error_setg_errno(errp, errno, "getifaddrs failed"); + goto error; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + GuestNetworkInterface *info; + GuestIpAddressList **address_tail; + GuestIpAddress *address_item = NULL; + GuestNetworkInterfaceStat *interface_stat = NULL; + char addr4[INET_ADDRSTRLEN]; + char addr6[INET6_ADDRSTRLEN]; + unsigned char mac_addr[ETHER_ADDR_LEN]; + bool obtained; + void *p; + + g_debug("Processing %s interface", ifa->ifa_name); + + info = guest_find_interface(head, ifa->ifa_name); + + if (!info) { + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(ifa->ifa_name); + + QAPI_LIST_APPEND(tail, info); + } + + if (!info->hardware_address) { + if (!guest_get_hw_addr(ifa, mac_addr, &obtained, errp)) { + goto error; + } + if (obtained) { + info->hardware_address = + g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", + (int) mac_addr[0], (int) mac_addr[1], + (int) mac_addr[2], (int) mac_addr[3], + (int) mac_addr[4], (int) mac_addr[5]); + } + } + + if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_INET) { + /* interface with IPv4 address */ + p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { + error_setg_errno(errp, errno, "inet_ntop failed"); + goto error; + } + + address_item = g_malloc0(sizeof(*address_item)); + address_item->ip_address = g_strdup(addr4); + address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; + + if (ifa->ifa_netmask) { + /* Count the number of set bits in netmask. + * This is safe as '1' and '0' cannot be shuffled in netmask. */ + p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; + address_item->prefix = ctpop32(((uint32_t *) p)[0]); + } + } else if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_INET6) { + /* interface with IPv6 address */ + p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { + error_setg_errno(errp, errno, "inet_ntop failed"); + goto error; + } + + address_item = g_malloc0(sizeof(*address_item)); + address_item->ip_address = g_strdup(addr6); + address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; + + if (ifa->ifa_netmask) { + /* Count the number of set bits in netmask. + * This is safe as '1' and '0' cannot be shuffled in netmask. */ + p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; + address_item->prefix = + ctpop32(((uint32_t *) p)[0]) + + ctpop32(((uint32_t *) p)[1]) + + ctpop32(((uint32_t *) p)[2]) + + ctpop32(((uint32_t *) p)[3]); + } + } + + if (!address_item) { + continue; + } + + address_tail = &info->ip_addresses; + while (*address_tail) { + address_tail = &(*address_tail)->next; + } + QAPI_LIST_APPEND(address_tail, address_item); + + info->has_ip_addresses = true; + + if (!info->statistics) { + interface_stat = g_malloc0(sizeof(*interface_stat)); + if (guest_get_network_stats(info->name, interface_stat) == -1) { + g_free(interface_stat); + } else { + info->statistics = interface_stat; + } + } + } + + freeifaddrs(ifap); + return head; + +error: + freeifaddrs(ifap); + qapi_free_GuestNetworkInterfaceList(head); + return NULL; +} + +#else + +GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +#endif /* HAVE_GETIFADDRS */ + #if !defined(CONFIG_FSFREEZE) GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) @@ -3031,6 +3103,18 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) return NULL; } +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + #endif /* CONFIG_FSFREEZE */ #if !defined(CONFIG_FSTRIM) @@ -3042,26 +3126,30 @@ 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__) { const char *list[] = { "guest-suspend-disk", "guest-suspend-ram", - "guest-suspend-hybrid", "guest-network-get-interfaces", - "guest-get-vcpus", "guest-set-vcpus", + "guest-suspend-hybrid", "guest-get-vcpus", "guest-set-vcpus", "guest-get-memory-blocks", "guest-set-memory-blocks", "guest-get-memory-block-size", "guest-get-memory-block-info", NULL}; 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) + blockedrpcs = g_list_append(blockedrpcs, + g_strdup("guest-network-get-interfaces")); +#endif + #if !defined(CONFIG_FSFREEZE) { const char *list[] = { @@ -3072,18 +3160,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 */ @@ -3254,11 +3342,8 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp) if (uname(&kinfo) != 0) { error_setg_errno(errp, errno, "uname failed"); } else { - info->has_kernel_version = true; info->kernel_version = g_strdup(kinfo.version); - info->has_kernel_release = true; info->kernel_release = g_strdup(kinfo.release); - info->has_machine = true; info->machine = g_strdup(kinfo.machine); } @@ -3278,7 +3363,6 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp) value = g_key_file_get_value(osrelease, "os-release", osfield, NULL); \ if (value != NULL) { \ ga_osrelease_replace_special(value); \ - info->has_ ## field = true; \ info->field = value; \ } \ } while (0) @@ -3303,3 +3387,38 @@ GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) return NULL; } + +#ifndef HOST_NAME_MAX +# ifdef _POSIX_HOST_NAME_MAX +# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +# else +# define HOST_NAME_MAX 255 +# endif +#endif + +char *qga_get_host_name(Error **errp) +{ + long len = -1; + g_autofree char *hostname = NULL; + +#ifdef _SC_HOST_NAME_MAX + len = sysconf(_SC_HOST_NAME_MAX); +#endif /* _SC_HOST_NAME_MAX */ + + if (len < 0) { + len = HOST_NAME_MAX; + } + + /* Unfortunately, gethostname() below does not guarantee a + * NULL terminated string. Therefore, allocate one byte more + * to be sure. */ + hostname = g_new0(char, len + 1); + + if (gethostname(hostname, len) < 0) { + error_setg_errno(errp, errno, + "cannot get hostname"); + return NULL; + } + + return g_steal_pointer(&hostname); +} diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 3c428213db0a..b5fee6a2cd6c 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -18,10 +18,8 @@ #include #include #include -#ifdef HAVE_NTDDSCSI #include #include -#endif #include #include #include @@ -195,8 +193,7 @@ static void handle_set_nonblocking(HANDLE fh) SetNamedPipeHandleState(fh, &pipe_state, NULL, NULL); } -int64_t qmp_guest_file_open(const char *path, bool has_mode, - const char *mode, Error **errp) +int64_t qmp_guest_file_open(const char *path, const char *mode, Error **errp) { int64_t fd = -1; HANDLE fh; @@ -208,7 +205,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, GError *gerr = NULL; wchar_t *w_path = NULL; - if (!has_mode) { + if (!mode) { mode = "r"; } slog("guest-file-open called, filepath: %s, mode: %s", path, mode); @@ -277,13 +274,12 @@ static void acquire_privilege(const char *name, Error **errp) { HANDLE token = NULL; TOKEN_PRIVILEGES priv; - Error *local_err = NULL; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "no luid for requested privilege"); goto out; } @@ -292,13 +288,13 @@ static void acquire_privilege(const char *name, Error **errp) priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "unable to acquire requested privilege"); goto out; } } else { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "failed to open privilege token"); } @@ -306,7 +302,6 @@ static void acquire_privilege(const char *name, Error **errp) if (token) { CloseHandle(token); } - error_propagate(errp, local_err); } static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, @@ -319,14 +314,14 @@ static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, } } -void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) +void qmp_guest_shutdown(const char *mode, Error **errp) { Error *local_err = NULL; UINT shutdown_flag = EWX_FORCE; slog("guest-shutdown called, mode: %s", mode); - if (!has_mode || strcmp(mode, "powerdown") == 0) { + if (!mode || strcmp(mode, "powerdown") == 0) { shutdown_flag |= EWX_POWEROFF; } else if (strcmp(mode, "halt") == 0) { shutdown_flag |= EWX_SHUTDOWN; @@ -474,8 +469,6 @@ void qmp_guest_file_flush(int64_t handle, Error **errp) } } -#ifdef HAVE_NTDDSCSI - static GuestDiskBusType win2qemu[] = { [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN, [BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI, @@ -494,6 +487,11 @@ static GuestDiskBusType win2qemu[] = { #if (_WIN32_WINNT >= 0x0601) [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL, [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL, + /* + * BusTypeSpaces currently is not suported + */ + [BusTypeSpaces] = GUEST_DISK_BUS_TYPE_UNKNOWN, + [BusTypeNvme] = GUEST_DISK_BUS_TYPE_NVME, #endif }; @@ -598,6 +596,18 @@ static void get_pci_address_for_device(GuestPCIAddress *pci, } } +static GuestPCIAddress *get_empty_pci_address(void) +{ + GuestPCIAddress *pci = NULL; + + pci = g_malloc0(sizeof(*pci)); + pci->domain = -1; + pci->slot = -1; + pci->function = -1; + pci->bus = -1; + return pci; +} + static GuestPCIAddress *get_pci_info(int number, Error **errp) { HDEVINFO dev_info = INVALID_HANDLE_VALUE; @@ -607,13 +617,7 @@ static GuestPCIAddress *get_pci_info(int number, Error **errp) SP_DEVICE_INTERFACE_DATA dev_iface_data; HANDLE dev_file; int i; - GuestPCIAddress *pci = NULL; - - pci = g_malloc0(sizeof(*pci)); - pci->domain = -1; - pci->slot = -1; - pci->function = -1; - pci->bus = -1; + GuestPCIAddress *pci = get_empty_pci_address(); dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); @@ -832,7 +836,6 @@ static void get_disk_properties(HANDLE vol_h, GuestDiskAddress *disk, g_debug("serial number \"%s\"", serial); if (*serial != 0) { disk->serial = g_strndup(serial, len); - disk->has_serial = true; } } out_free: @@ -871,10 +874,14 @@ static void get_single_disk_info(int disk_number, * if that doesn't hold since that suggests some other unexpected * breakage */ - disk->pci_controller = get_pci_info(disk_number, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto err_close; + if (disk->bus_type == GUEST_DISK_BUS_TYPE_USB) { + disk->pci_controller = get_empty_pci_address(); + } else { + disk->pci_controller = get_pci_info(disk_number, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto err_close; + } } if (disk->bus_type == GUEST_DISK_BUS_TYPE_SCSI || disk->bus_type == GUEST_DISK_BUS_TYPE_IDE @@ -950,7 +957,6 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp) /* Possibly CD-ROM or a shared drive. Try to pass the volume */ g_debug("volume not on disk"); disk = g_new0(GuestDiskAddress, 1); - disk->has_dev = true; disk->dev = g_strdup(name); get_single_disk_info(0xffffffff, disk, &local_err); if (local_err) { @@ -982,7 +988,6 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp) * See also Naming Files, Paths and Namespaces: * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces */ - disk->has_dev = true; disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu", extents->Extents[i].DiskNumber); @@ -1077,7 +1082,6 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) g_debug(" number: %lu", sdn.DeviceNumber); address = g_new0(GuestDiskAddress, 1); - address->has_dev = true; address->dev = g_strdup(disk->name); get_single_disk_info(sdn.DeviceNumber, address, &local_err); if (local_err) { @@ -1088,7 +1092,6 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) address = NULL; } else { disk->address = address; - disk->has_address = true; } QAPI_LIST_PREPEND(ret, disk); @@ -1098,21 +1101,6 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) return ret; } -#else - -static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp) -{ - return NULL; -} - -GuestDiskInfoList *qmp_guest_get_disks(Error **errp) -{ - error_setg(errp, QERR_UNSUPPORTED); - return NULL; -} - -#endif /* HAVE_NTDDSCSI */ - static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) { DWORD info_size; @@ -1383,7 +1371,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) g_free(uc_path); if (!path) { - res->has_error = true; res->error = g_strdup(gerr->message); g_error_free(gerr); break; @@ -1401,7 +1388,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &out /* stdout */, NULL /* stdin */, NULL, &gerr)) { - res->has_error = true; res->error = g_strdup(gerr->message); g_error_free(gerr); } else { @@ -1417,7 +1403,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) if (g_strstr_len(lines[i], -1, "(0x") == NULL) { continue; } - res->has_error = true; res->error = g_strdup(lines[i]); break; } @@ -1697,8 +1682,6 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) (int) mac_addr[0], (int) mac_addr[1], (int) mac_addr[2], (int) mac_addr[3], (int) mac_addr[4], (int) mac_addr[5]); - - info->has_hardware_address = true; } head_addr = NULL; @@ -1727,15 +1710,13 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) info->has_ip_addresses = true; info->ip_addresses = head_addr; } - if (!info->has_statistics) { + if (!info->statistics) { interface_stat = g_malloc0(sizeof(*interface_stat)); - if (guest_get_network_stats(addr->AdapterName, - interface_stat) == -1) { - info->has_statistics = false; + if (guest_get_network_stats(addr->AdapterName, interface_stat) + == -1) { g_free(interface_stat); } else { info->statistics = interface_stat; - info->has_statistics = true; } } } @@ -1751,25 +1732,6 @@ static int64_t filetime_to_ns(const FILETIME *tf) - W32_FT_OFFSET) * 100; } -int64_t qmp_guest_get_time(Error **errp) -{ - SYSTEMTIME ts = {0}; - FILETIME tf; - - GetSystemTime(&ts); - if (ts.wYear < 1601 || ts.wYear > 30827) { - error_setg(errp, "Failed to get time"); - return -1; - } - - if (!SystemTimeToFileTime(&ts, &tf)) { - error_setg(errp, "Failed to convert system time: %d", (int)GetLastError()); - return -1; - } - - return filetime_to_ns(&tf); -} - void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) { Error *local_err = NULL; @@ -2038,8 +2000,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", @@ -2050,7 +2012,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)) { @@ -2061,11 +2023,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 */ @@ -2146,7 +2108,6 @@ GuestUserList *qmp_guest_get_users(Error **errp) user->user = g_strdup(info->UserName); user->domain = g_strdup(info->Domain); - user->has_domain = true; user->login_time = login_time; @@ -2365,29 +2326,19 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp) info = g_new0(GuestOSInfo, 1); - info->has_kernel_version = true; info->kernel_version = g_strdup_printf("%lu.%lu", os_version.dwMajorVersion, os_version.dwMinorVersion); - info->has_kernel_release = true; info->kernel_release = g_strdup_printf("%lu", os_version.dwBuildNumber); - info->has_machine = true; info->machine = ga_get_current_arch(); - info->has_id = true; info->id = g_strdup("mswindows"); - info->has_name = true; info->name = g_strdup("Microsoft Windows"); - info->has_pretty_name = true; info->pretty_name = product_name; - info->has_version = true; info->version = ga_get_win_name(&os_version, false); - info->has_version_id = true; info->version_id = ga_get_win_name(&os_version, true); - info->has_variant = true; info->variant = g_strdup(server ? "server" : "client"); - info->has_variant_id = true; info->variant_id = g_strdup(server ? "server" : "client"); return info; @@ -2511,7 +2462,6 @@ GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) device_id = g_match_info_fetch(match_info, 2); device->id = g_new0(GuestDeviceId, 1); - device->has_id = true; device->id->type = GUEST_DEVICE_TYPE_PCI; id = &device->id->u.pci; id->vendor_id = g_ascii_strtoull(vendor_id, NULL, 16); @@ -2535,7 +2485,6 @@ GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) error_setg(errp, "conversion to utf8 failed (driver version)"); return NULL; } - device->has_driver_version = true; date = (LPFILETIME)cm_get_property(dev_info_data.DevInst, &qga_DEVPKEY_Device_DriverDate, &cm_type); @@ -2557,3 +2506,28 @@ GuestDeviceInfoList *qmp_guest_get_devices(Error **errp) } return head; } + +char *qga_get_host_name(Error **errp) +{ + wchar_t tmp[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD size = G_N_ELEMENTS(tmp); + + if (GetComputerNameW(tmp, &size) == 0) { + error_setg_win32(errp, GetLastError(), "failed close handle"); + return NULL; + } + + return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL); +} + +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + +GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} diff --git a/qga/commands.c b/qga/commands.c index 72e602220771..360077364e39 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -18,7 +18,6 @@ #include "qapi/qmp/qerror.h" #include "qemu/base64.h" #include "qemu/cutils.h" -#include "qemu/atomic.h" #include "commands-common.h" /* Maximum captured guest-exec out_data/err_data - 16MB */ @@ -162,13 +161,12 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp) ges = g_new0(GuestExecStatus, 1); - bool finished = qatomic_mb_read(&gei->finished); + bool finished = gei->finished; /* need to wait till output channels are closed * to be sure we captured all output at this point */ if (gei->has_output) { - finished = finished && qatomic_mb_read(&gei->out.closed); - finished = finished && qatomic_mb_read(&gei->err.closed); + finished &= gei->out.closed && gei->err.closed; } ges->exited = finished; @@ -208,14 +206,12 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp) } #endif if (gei->out.length > 0) { - ges->has_out_data = true; ges->out_data = g_base64_encode(gei->out.data, gei->out.length); g_free(gei->out.data); ges->has_out_truncated = gei->out.truncated; } if (gei->err.length > 0) { - ges->has_err_data = true; ges->err_data = g_base64_encode(gei->err.data, gei->err.length); g_free(gei->err.data); ges->has_err_truncated = gei->err.truncated; @@ -270,7 +266,7 @@ static void guest_exec_child_watch(GPid pid, gint status, gpointer data) (int32_t)gpid_to_int64(pid), (uint32_t)status); gei->status = status; - qatomic_mb_set(&gei->finished, true); + gei->finished = true; g_spawn_close_pid(pid); } @@ -326,7 +322,7 @@ static gboolean guest_exec_input_watch(GIOChannel *ch, done: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - qatomic_mb_set(&p->closed, true); + p->closed = true; g_free(p->data); return false; @@ -380,14 +376,14 @@ static gboolean guest_exec_output_watch(GIOChannel *ch, close: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - qatomic_mb_set(&p->closed, true); + p->closed = true; return false; } GuestExec *qmp_guest_exec(const char *path, bool has_arg, strList *arg, bool has_env, strList *env, - bool has_input_data, const char *input_data, + const char *input_data, bool has_capture_output, bool capture_output, Error **errp) { @@ -408,7 +404,7 @@ GuestExec *qmp_guest_exec(const char *path, arglist.value = (char *)path; arglist.next = has_arg ? arg : NULL; - if (has_input_data) { + if (input_data) { input = qbase64_decode(input_data, -1, &ninput, errp); if (!input) { return NULL; @@ -425,7 +421,7 @@ GuestExec *qmp_guest_exec(const char *path, } ret = g_spawn_async_with_pipes(NULL, argv, envp, flags, - guest_exec_task_setup, NULL, &pid, has_input_data ? &in_fd : NULL, + guest_exec_task_setup, NULL, &pid, input_data ? &in_fd : NULL, has_output ? &out_fd : NULL, has_output ? &err_fd : NULL, &gerr); if (!ret) { error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message); @@ -440,7 +436,7 @@ GuestExec *qmp_guest_exec(const char *path, gei->has_output = has_output; g_child_watch_add(pid, guest_exec_child_watch, gei); - if (has_input_data) { + if (input_data) { gei->in.data = g_steal_pointer(&input); gei->in.size = ninput; #ifdef G_OS_WIN32 @@ -511,7 +507,7 @@ int ga_parse_whence(GuestFileWhence *whence, Error **errp) GuestHostName *qmp_guest_get_host_name(Error **errp) { GuestHostName *result = NULL; - g_autofree char *hostname = qemu_get_host_name(errp); + g_autofree char *hostname = qga_get_host_name(errp); /* * We want to avoid using g_get_host_name() because that @@ -549,7 +545,6 @@ GuestTimezone *qmp_guest_get_timezone(Error **errp) info->offset = g_time_zone_get_offset(tz, intv); name = g_time_zone_get_abbreviation(tz, intv); if (name != NULL) { - info->has_zone = true; info->zone = g_strdup(name); } g_time_zone_unref(tz); @@ -585,3 +580,8 @@ GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, return read_data; } + +int64_t qmp_guest_get_time(Error **errp) +{ + return g_get_real_time() * 1000; +} diff --git a/qga/cutils.c b/qga/cutils.c new file mode 100644 index 000000000000..b8e142ef649d --- /dev/null +++ b/qga/cutils.c @@ -0,0 +1,33 @@ +/* + * 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 "cutils.h" + +#include "qapi/error.h" + +/** + * qga_open_cloexec: + * @name: the pathname to open + * @flags: as in open() + * @mode: as in open() + * + * A wrapper for open() function which sets O_CLOEXEC. + * + * On error, -1 is returned. + */ +int qga_open_cloexec(const char *name, int flags, mode_t mode) +{ + int ret; + +#ifdef O_CLOEXEC + ret = open(name, flags | O_CLOEXEC, mode); +#else + ret = open(name, flags, mode); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + + return ret; +} diff --git a/qga/cutils.h b/qga/cutils.h new file mode 100644 index 000000000000..f0f30a7d28aa --- /dev/null +++ b/qga/cutils.h @@ -0,0 +1,8 @@ +#ifndef CUTILS_H_ +#define CUTILS_H_ + +#include "qemu/osdep.h" + +int qga_open_cloexec(const char *name, int flags, mode_t mode); + +#endif /* CUTILS_H_ */ diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index 29cd50402fdb..b4e7c52c611f 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/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index 0950e8c6becc..51340f7eccb5 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -1,62 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + NOT VersionNT64 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - + + + + + + + + + + + + Key="Software\$(var.QEMU_GA_MANUFACTURER)\$(var.QEMU_GA_DISTRO)\Tools\QemuGA"> - + + + + + diff --git a/qga/main.c b/qga/main.c index b9dd19918e47..85b7d6ced504 100644 --- a/qga/main.c +++ b/qga/main.c @@ -18,7 +18,7 @@ #include #include #endif -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qapi/qmp/json-parser.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" @@ -37,17 +37,16 @@ #include "qga/service-win32.h" #include "qga/vss-win32.h" #endif -#ifdef __linux__ -#include -#ifdef FIFREEZE -#define CONFIG_FSFREEZE -#endif -#endif +#include "commands-common.h" #ifndef _WIN32 +#ifdef CONFIG_BSD +#define QGA_VIRTIO_PATH_DEFAULT "/dev/vtcon/org.qemu.guest_agent.0" +#else /* CONFIG_BSD */ #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" -#define QGA_STATE_RELATIVE_DIR "run" +#endif /* CONFIG_BSD */ #define QGA_SERIAL_PATH_DEFAULT "/dev/ttyS0" +#define QGA_STATE_RELATIVE_DIR "run" #else #define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0" #define QGA_STATE_RELATIVE_DIR "qemu-ga" @@ -84,10 +83,11 @@ struct GAState { #ifdef _WIN32 GAService service; HANDLE wakeup_event; + HANDLE event_log; #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", @@ -129,12 +129,12 @@ static void stop_agent(GAState *s, bool requested); static void init_dfl_pathnames(void) { + g_autofree char *state = qemu_get_local_state_dir(); + g_assert(dfl_pathnames.state_dir == NULL); g_assert(dfl_pathnames.pidfile == NULL); - dfl_pathnames.state_dir = qemu_get_local_state_pathname( - QGA_STATE_RELATIVE_DIR); - dfl_pathnames.pidfile = qemu_get_local_state_pathname( - QGA_STATE_RELATIVE_DIR G_DIR_SEPARATOR_S "qemu-ga.pid"); + dfl_pathnames.state_dir = g_build_filename(state, QGA_STATE_RELATIVE_DIR, NULL); + dfl_pathnames.pidfile = g_build_filename(state, QGA_STATE_RELATIVE_DIR, "qemu-ga.pid", NULL); } static void quit_handler(int sig) @@ -223,6 +223,10 @@ void reopen_fd_to_null(int fd) static void usage(const char *cmd) { +#ifdef CONFIG_FSFREEZE + g_autofree char *fsfreeze_hook = get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT); +#endif + printf( "Usage: %s [-m -p ] []\n" "QEMU Guest Agent " QEMU_FULL_VERSION "\n" @@ -256,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" @@ -270,7 +274,7 @@ QEMU_HELP_BOTTOM "\n" , cmd, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT, dfl_pathnames.pidfile, #ifdef CONFIG_FSFREEZE - QGA_FSFREEZE_HOOK_DEFAULT, + fsfreeze_hook, #endif dfl_pathnames.state_dir); } @@ -310,11 +314,42 @@ void ga_enable_logging(GAState *s) s->logging_enabled = true; } +static int glib_log_level_to_system(int level) +{ + switch (level) { +#ifndef _WIN32 + case G_LOG_LEVEL_ERROR: + return LOG_ERR; + case G_LOG_LEVEL_CRITICAL: + return LOG_CRIT; + case G_LOG_LEVEL_WARNING: + return LOG_WARNING; + case G_LOG_LEVEL_MESSAGE: + return LOG_NOTICE; + case G_LOG_LEVEL_DEBUG: + return LOG_DEBUG; + case G_LOG_LEVEL_INFO: + default: + return LOG_INFO; +#else + case G_LOG_LEVEL_ERROR: + case G_LOG_LEVEL_CRITICAL: + return EVENTLOG_ERROR_TYPE; + case G_LOG_LEVEL_WARNING: + return EVENTLOG_WARNING_TYPE; + case G_LOG_LEVEL_MESSAGE: + case G_LOG_LEVEL_INFO: + case G_LOG_LEVEL_DEBUG: + default: + return EVENTLOG_INFORMATION_TYPE; +#endif + } +} + static void ga_log(const gchar *domain, GLogLevelFlags level, const gchar *msg, gpointer opaque) { GAState *s = opaque; - GTimeVal time; const char *level_str = ga_log_level_str(level); if (!ga_logging_enabled(s)) { @@ -322,16 +357,17 @@ static void ga_log(const gchar *domain, GLogLevelFlags level, } level &= G_LOG_LEVEL_MASK; -#ifndef _WIN32 if (g_strcmp0(domain, "syslog") == 0) { - syslog(LOG_INFO, "%s: %s", level_str, msg); - } else if (level & s->log_level) { +#ifndef _WIN32 + syslog(glib_log_level_to_system(level), "%s: %s", level_str, msg); #else - if (level & s->log_level) { + ReportEvent(s->event_log, glib_log_level_to_system(level), + 0, 1, NULL, 1, 0, &msg, NULL); #endif - g_get_current_time(&time); - fprintf(s->log_file, - "%lu.%lu: %s: %s\n", time.tv_sec, time.tv_usec, level_str, msg); + } else if (level & s->log_level) { + g_autoptr(GDateTime) now = g_date_time_new_now_utc(); + g_autofree char *nowstr = g_date_time_format(now, "%s.%f"); + fprintf(s->log_file, "%s: %s: %s\n", nowstr, level_str, msg); fflush(s->log_file); } } @@ -360,31 +396,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); @@ -423,8 +459,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; @@ -462,8 +498,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", @@ -609,7 +645,7 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data) * host-side chardev. sleep a bit to mitigate this */ if (s->virtio) { - usleep(100 * 1000); + g_usleep(G_USEC_PER_SEC / 10); } return true; default: @@ -893,7 +929,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 */ @@ -947,8 +984,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; @@ -960,6 +997,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(); @@ -1006,10 +1044,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, ",")); } @@ -1069,8 +1113,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); @@ -1102,7 +1146,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 @@ -1160,8 +1205,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 @@ -1215,7 +1260,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); } @@ -1272,7 +1317,16 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR); ga_enable_logging(s); + g_debug("Guest agent version %s started", QEMU_FULL_VERSION); + #ifdef _WIN32 + s->event_log = RegisterEventSource(NULL, "qemu-ga"); + if (!s->event_log) { + g_autofree gchar *errmsg = g_win32_error_message(GetLastError()); + g_critical("unable to register event source: %s", errmsg); + return NULL; + } + /* On win32 the state directory is application specific (be it the default * or a user override). We got past the command line parsing; let's create * the directory (with any intermediate directories). If we run into an @@ -1297,7 +1351,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); @@ -1321,10 +1375,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); @@ -1364,6 +1418,7 @@ static void cleanup_agent(GAState *s) { #ifdef _WIN32 CloseHandle(s->wakeup_event); + CloseHandle(s->event_log); #endif if (s->command_state) { ga_command_state_cleanup_all(s->command_state); diff --git a/qga/meson.build b/qga/meson.build index 62472747f1bb..ad17dc7dca13 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -65,12 +65,19 @@ qga_ss.add(files( 'commands.c', 'guest-agent-command-state.c', 'main.c', + 'cutils.c', )) qga_ss.add(when: 'CONFIG_POSIX', if_true: files( 'channel-posix.c', 'commands-posix.c', 'commands-posix-ssh.c', )) +qga_ss.add(when: 'CONFIG_LINUX', if_true: files( + 'commands-linux.c', +)) +qga_ss.add(when: 'CONFIG_BSD', if_true: files( + 'commands-bsd.c', +)) qga_ss.add(when: 'CONFIG_WIN32', if_true: files( 'channel-win32.c', 'commands-win32.c', @@ -83,17 +90,32 @@ qga_ss = qga_ss.apply(config_host, strict: false) gen_tlb = [] qga_libs = [] if targetos == 'windows' - qga_libs += ['-lws2_32', '-lwinmm', '-lpowrprof', '-lwtsapi32', '-lwininet', '-liphlpapi', '-lnetapi32'] + qga_libs += ['-lws2_32', '-lwinmm', '-lpowrprof', '-lwtsapi32', '-lwininet', '-liphlpapi', '-lnetapi32', + '-lsetupapi', '-lcfgmgr32'] if have_qga_vss qga_libs += ['-lole32', '-loleaut32', '-lshlwapi', '-lstdc++', '-Wl,--enable-stdcall-fixup'] subdir('vss-win32') endif - if have_ntddscsi - qga_libs += ['-lsetupapi', '-lcfgmgr32'] - endif endif -qga = executable('qemu-ga', qga_ss.sources(), +qga_objs = [] +if targetos == 'windows' + windmc = find_program('windmc', required: true) + windres = find_program('windres', required: true) + + msgrc = custom_target('messages-win32.rc', + input: 'messages-win32.mc', + output: ['messages-win32.rc', 'MSG00409.bin', 'messages-win32.h'], + command: [windmc, '-h', '@OUTDIR@', '-r', '@OUTDIR@', '@INPUT@']) + msgobj = custom_target('messages-win32.o', + input: msgrc[0], + output: 'messages-win32.o', + command: [windres, '-I', '@OUTDIR@', '-o', '@OUTPUT@', '@INPUT@']) + + qga_objs = [msgobj] +endif + +qga = executable('qemu-ga', qga_ss.sources() + qga_objs, link_args: qga_libs, dependencies: [qemuutil, libudev], install: true) @@ -118,20 +140,25 @@ if targetos == 'windows' qemu_ga_msi_vss = ['-D', 'InstallVss'] deps += qga_vss endif + if glib.version() < '2.73.2' + libpcre = 'libpcre1' + else + libpcre = 'libpcre2' + endif qga_msi = custom_target('QGA MSI', input: files('installer/qemu-ga.wxs'), output: 'qemu-ga-@0@.msi'.format(host_arch), depends: deps, command: [ - find_program('env'), - 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], - 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], - 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'], - 'BUILD_DIR=' + meson.build_root(), wixl, '-o', '@OUTPUT0@', '@INPUT0@', qemu_ga_msi_arch[cpu], qemu_ga_msi_vss, - '-D', 'Mingw_dlls=' + config_host['QEMU_GA_MSI_MINGW_DLL_PATH'], + '-D', 'BUILD_DIR=' + meson.project_build_root(), + '-D', 'BIN_DIR=' + glib.get_variable('bindir'), + '-D', 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], + '-D', 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], + '-D', 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'], + '-D', 'LIBPCRE=' + libpcre, ]) all_qga += [qga_msi] alias_target('msi', qga_msi) @@ -140,7 +167,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/messages-win32.mc b/qga/messages-win32.mc new file mode 100644 index 000000000000..e21019cebe44 --- /dev/null +++ b/qga/messages-win32.mc @@ -0,0 +1,9 @@ +LanguageNames=( + English=0x409:MSG00409 +) + +MessageId=1 +SymbolicName=QEMU_GA_EVENTLOG_GENERAL +Language=English +%1 +. diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 94e4aacdcc65..796434ed346f 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': [ @@ -392,7 +392,7 @@ ## # @guest-file-flush: # -# Write file changes bufferred in userspace to disk/kernel buffers +# Write file changes buffered in userspace to disk/kernel buffers # # @handle: filehandle returned by guest-file-open # @@ -827,13 +827,14 @@ # @mmc: Win multimedia card (MMC) bus type # @virtual: Win virtual bus type # @file-backed-virtual: Win file-backed bus type +# @nvme: NVMe disks (since 7.1) # # Since: 2.2; 'Unknown' and all entries below since 2.4 ## { 'enum': 'GuestDiskBusType', 'data': [ 'ide', 'fdc', 'scsi', 'virtio', 'xen', 'usb', 'uml', 'sata', 'sd', 'unknown', 'ieee1394', 'ssa', 'fibre', 'raid', 'iscsi', - 'sas', 'mmc', 'virtual', 'file-backed-virtual' ] } + 'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ] } ## @@ -887,6 +888,55 @@ '*serial': 'str', '*dev': 'str', '*ccw-address': 'GuestCCWAddress'} } +## +# @GuestNVMeSmart: +# +# NVMe smart informations, based on NVMe specification, +# section +# +# Since: 7.1 +## +{ 'struct': 'GuestNVMeSmart', + 'data': {'critical-warning': 'int', + 'temperature': 'int', + 'available-spare': 'int', + 'available-spare-threshold': 'int', + 'percentage-used': 'int', + 'data-units-read-lo': 'uint64', + 'data-units-read-hi': 'uint64', + 'data-units-written-lo': 'uint64', + 'data-units-written-hi': 'uint64', + 'host-read-commands-lo': 'uint64', + 'host-read-commands-hi': 'uint64', + 'host-write-commands-lo': 'uint64', + 'host-write-commands-hi': 'uint64', + 'controller-busy-time-lo': 'uint64', + 'controller-busy-time-hi': 'uint64', + 'power-cycles-lo': 'uint64', + 'power-cycles-hi': 'uint64', + 'power-on-hours-lo': 'uint64', + 'power-on-hours-hi': 'uint64', + 'unsafe-shutdowns-lo': 'uint64', + 'unsafe-shutdowns-hi': 'uint64', + 'media-errors-lo': 'uint64', + 'media-errors-hi': 'uint64', + 'number-of-error-log-entries-lo': 'uint64', + 'number-of-error-log-entries-hi': 'uint64' } } + +## +# @GuestDiskSmart: +# +# Disk type related smart information. +# +# - @nvme: NVMe disk smart +# +# Since: 7.1 +## +{ 'union': 'GuestDiskSmart', + 'base': { 'type': 'GuestDiskBusType' }, + 'discriminator': 'type', + 'data': { 'nvme': 'GuestNVMeSmart' } } + ## # @GuestDiskInfo: # @@ -898,12 +948,14 @@ # @address: disk address information (only for non-virtual devices) # @alias: optional alias assigned to the disk, on Linux this is a name assigned # by device mapper +# @smart: disk smart information (Since 7.1) # -# Since 5.2 +# Since: 5.2 ## { 'struct': 'GuestDiskInfo', 'data': {'name': 'str', 'partition': 'bool', '*dependencies': ['str'], - '*address': 'GuestDiskAddress', '*alias': 'str'} } + '*address': 'GuestDiskAddress', '*alias': 'str', + '*smart': 'GuestDiskSmart'} } ## # @guest-get-disks: @@ -1438,3 +1490,170 @@ { 'command': 'guest-ssh-remove-authorized-keys', 'data': { 'username': 'str', 'keys': ['str'] }, 'if': 'CONFIG_POSIX' } + +## +# @GuestDiskStats: +# +# @read-sectors: sectors read +# +# @read-ios: reads completed successfully +# +# @read-merges: read requests merged +# +# @write-sectors: sectors written +# +# @write-ios: writes completed +# +# @write-merges: write requests merged +# +# @discard-sectors: sectors discarded +# +# @discard-ios: discards completed successfully +# +# @discard-merges: discard requests merged +# +# @flush-ios: flush requests completed successfully +# +# @read-ticks: time spent reading(ms) +# +# @write-ticks: time spent writing(ms) +# +# @discard-ticks: time spent discarding(ms) +# +# @flush-ticks: time spent flushing(ms) +# +# @ios-pgr: number of I/Os currently in flight +# +# @total-ticks: time spent doing I/Os (ms) +# +# @weight-ticks: weighted time spent doing I/Os since the last update of this field(ms) +# +# Since: 7.1 +## +{ 'struct': 'GuestDiskStats', + 'data': {'*read-sectors': 'uint64', + '*read-ios': 'uint64', + '*read-merges': 'uint64', + '*write-sectors': 'uint64', + '*write-ios': 'uint64', + '*write-merges': 'uint64', + '*discard-sectors': 'uint64', + '*discard-ios': 'uint64', + '*discard-merges': 'uint64', + '*flush-ios': 'uint64', + '*read-ticks': 'uint64', + '*write-ticks': 'uint64', + '*discard-ticks': 'uint64', + '*flush-ticks': 'uint64', + '*ios-pgr': 'uint64', + '*total-ticks': 'uint64', + '*weight-ticks': 'uint64' + } } + +## +# @GuestDiskStatsInfo: +# +# @name disk name +# +# @major major device number of disk +# +# @minor minor device number of disk +## +{ 'struct': 'GuestDiskStatsInfo', + 'data': {'name': 'str', + 'major': 'uint64', + 'minor': 'uint64', + 'stats': 'GuestDiskStats' } } + +## +# @guest-get-diskstats: +# +# Retrieve information about disk stats. +# Returns: List of disk stats of guest. +# +# Since: 7.1 +## +{ 'command': 'guest-get-diskstats', + 'returns': ['GuestDiskStatsInfo'] +} + +## +# @GuestCpuStatsType: +# +# An enumeration of OS type +# +# Since: 7.1 +## +{ 'enum': 'GuestCpuStatsType', + 'data': [ 'linux' ] } + + +## +# @GuestLinuxCpuStats: +# +# CPU statistics of Linux +# +# @cpu: CPU index in guest OS +# +# @user: Time spent in user mode +# +# @nice: Time spent in user mode with low priority (nice) +# +# @system: Time spent in system mode +# +# @idle: Time spent in the idle task +# +# @iowait: Time waiting for I/O to complete (since Linux 2.5.41) +# +# @irq: Time servicing interrupts (since Linux 2.6.0-test4) +# +# @softirq: Time servicing softirqs (since Linux 2.6.0-test4) +# +# @steal: Stolen time by host (since Linux 2.6.11) +# +# @guest: ime spent running a virtual CPU for guest operating systems under +# the control of the Linux kernel (since Linux 2.6.24) +# +# @guestnice: Time spent running a niced guest (since Linux 2.6.33) +# +# Since: 7.1 +## +{ 'struct': 'GuestLinuxCpuStats', + 'data': {'cpu': 'int', + 'user': 'uint64', + 'nice': 'uint64', + 'system': 'uint64', + 'idle': 'uint64', + '*iowait': 'uint64', + '*irq': 'uint64', + '*softirq': 'uint64', + '*steal': 'uint64', + '*guest': 'uint64', + '*guestnice': 'uint64' + } } + +## +# @GuestCpuStats: +# +# Get statistics of each CPU in millisecond. +# +# - @linux: Linux style CPU statistics +# +# Since: 7.1 +## +{ 'union': 'GuestCpuStats', + 'base': { 'type': 'GuestCpuStatsType' }, + 'discriminator': 'type', + 'data': { 'linux': 'GuestLinuxCpuStats' } } + +## +# @guest-get-cpustats: +# +# Retrieve information about CPU stats. +# Returns: List of CPU stats of guest. +# +# Since: 7.1 +## +{ 'command': 'guest-get-cpustats', + 'returns': ['GuestCpuStats'] +} diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build index 71c50d0866c4..9483ccd3b880 100644 --- a/qga/vss-win32/meson.build +++ b/qga/vss-win32/meson.build @@ -7,7 +7,7 @@ link_args = cc.get_supported_link_arguments([ qga_vss = shared_module( 'qga-vss', - ['requester.cpp', 'provider.cpp', 'install.cpp'], + ['requester.cpp', 'provider.cpp', 'install.cpp', genh], name_prefix: '', cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'], link_args: link_args, @@ -23,8 +23,6 @@ qga_vss = shared_module( ] ) -all_qga += qga_vss - if midl.found() gen_tlb = custom_target('gen-tlb', input: 'qga-vss.idl', @@ -36,3 +34,5 @@ else output: 'qga-vss.tlb', command: [widl, '-t', '@INPUT@', '-o', '@OUTPUT@']) endif + +all_qga += [ qga_vss, gen_tlb ] diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 4513324dd2a0..b371affeab17 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -354,12 +354,12 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) if (FAILED(hr)) { err_set(errset, hr, "failed to add %S to snapshot set", volume_name_wchar); - delete volume_name_wchar; + delete[] volume_name_wchar; goto out; } num_mount_points++; - delete volume_name_wchar; + delete[] volume_name_wchar; } if (num_mount_points == 0) { diff --git a/qobject/qbool.c b/qobject/qbool.c index 16a600abb93f..c7049c0c501b 100644 --- a/qobject/qbool.c +++ b/qobject/qbool.c @@ -56,3 +56,8 @@ void qbool_destroy_obj(QObject *obj) assert(obj != NULL); g_free(qobject_to(QBool, obj)); } + +void qbool_unref(QBool *q) +{ + qobject_unref(q); +} diff --git a/qobject/qdict.c b/qobject/qdict.c index 0216ca7ac168..8faff230d391 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -442,3 +442,8 @@ void qdict_destroy_obj(QObject *obj) g_free(qdict); } + +void qdict_unref(QDict *q) +{ + qobject_unref(q); +} diff --git a/qobject/qlist.c b/qobject/qlist.c index 60562a1f5269..356ad946b00c 100644 --- a/qobject/qlist.c +++ b/qobject/qlist.c @@ -182,3 +182,8 @@ void qlist_destroy_obj(QObject *obj) g_free(qlist); } + +void qlist_unref(QList *q) +{ + qobject_unref(q); +} diff --git a/qobject/qnull.c b/qobject/qnull.c index b26b36821905..445a5db7f36f 100644 --- a/qobject/qnull.c +++ b/qobject/qnull.c @@ -29,3 +29,8 @@ bool qnull_is_equal(const QObject *x, const QObject *y) { return true; } + +void qnull_unref(QNull *q) +{ + qobject_unref(q); +} diff --git a/qobject/qnum.c b/qobject/qnum.c index 5dd66938dd84..2bbeaedc7b44 100644 --- a/qobject/qnum.c +++ b/qobject/qnum.c @@ -239,3 +239,8 @@ void qnum_destroy_obj(QObject *obj) assert(obj != NULL); g_free(qobject_to(QNum, obj)); } + +void qnum_unref(QNum *q) +{ + qobject_unref(q); +} diff --git a/qobject/qstring.c b/qobject/qstring.c index b4613899b979..794f8c93578a 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -100,3 +100,8 @@ void qstring_destroy_obj(QObject *obj) g_free((char *)qs->string); g_free(qs); } + +void qstring_unref(QString *q) +{ + qobject_unref(q); +} diff --git a/qom/object.c b/qom/object.c index d34608558e9e..e25f1e96db1e 100644 --- a/qom/object.c +++ b/qom/object.c @@ -526,8 +526,13 @@ void object_initialize(void *data, size_t size, const char *typename) #ifdef CONFIG_MODULES if (!type) { - module_load_qom_one(typename); - type = type_get_by_name(typename); + int rv = module_load_qom(typename, &error_fatal); + if (rv > 0) { + type = type_get_by_name(typename); + } else { + error_report("missing object type '%s'", typename); + exit(1); + } } #endif if (!type) { @@ -1033,8 +1038,13 @@ ObjectClass *module_object_class_by_name(const char *typename) oc = object_class_by_name(typename); #ifdef CONFIG_MODULES if (!oc) { - module_load_qom_one(typename); - oc = object_class_by_name(typename); + Error *local_err = NULL; + int rv = module_load_qom(typename, &local_err); + if (rv > 0) { + oc = object_class_by_name(typename); + } else if (rv < 0) { + error_report_err(local_err); + } } #endif return oc; @@ -1383,7 +1393,8 @@ bool object_property_get(Object *obj, const char *name, Visitor *v, } if (!prop->get) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property '%s.%s' is not readable", + object_get_typename(obj), name); return false; } prop->get(obj, v, name, prop->opaque, &err); @@ -1402,7 +1413,8 @@ bool object_property_set(Object *obj, const char *name, Visitor *v, } if (!prop->set) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property '%s.%s' is not writable", + object_get_typename(obj), name); return false; } prop->set(obj, v, name, prop->opaque, errp); diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 3b61c195c53d..f94b6c319312 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -17,6 +17,7 @@ #include "qemu/qemu-print.h" #include "qapi/opts-visitor.h" #include "qemu/config-file.h" +#include "qemu/keyval.h" bool user_creatable_complete(UserCreatable *uc, Error **errp) { diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index 2e63a4c1840b..7c087299de9e 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -99,15 +99,13 @@ static void qom_list_types_tramp(ObjectClass *klass, void *data) info->name = g_strdup(object_class_get_name(klass)); info->has_abstract = info->abstract = object_class_is_abstract(klass); if (parent) { - info->has_parent = true; info->parent = g_strdup(object_class_get_name(parent)); } QAPI_LIST_PREPEND(*pret, info); } -ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, - const char *implements, +ObjectTypeInfoList *qmp_qom_list_types(const char *implements, bool has_abstract, bool abstract, Error **errp) @@ -168,10 +166,8 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename, info = g_new0(ObjectPropertyInfo, 1); info->name = g_strdup(prop->name); info->type = g_strdup(prop->type); - info->has_description = !!prop->description; info->description = g_strdup(prop->description); info->default_value = qobject_ref(prop->defval); - info->has_default_value = !!info->default_value; QAPI_LIST_PREPEND(prop_list, info); } @@ -215,7 +211,6 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename, info = g_malloc0(sizeof(*info)); info->name = g_strdup(prop->name); info->type = g_strdup(prop->type); - info->has_description = !!prop->description; info->description = g_strdup(prop->description); QAPI_LIST_PREPEND(prop_list, info); diff --git a/release_note.txt b/release_note.txt new file mode 100644 index 000000000000..c6db185b9e3f --- /dev/null +++ b/release_note.txt @@ -0,0 +1,3 @@ +This is a NXP customized qemu release to enable imimxrt595_evk platfrom +the release tag is defined as +qemu_7.2.50_rt595_cus_t: qemu 7.2.50 rt595 customized tag diff --git a/replay/replay-char.c b/replay/replay-char.c index d2025948cfff..a31aded032e7 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-debugging.c b/replay/replay-debugging.c index 1cde50e9f37f..3e60549a4aeb 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -50,7 +50,6 @@ ReplayInfo *qmp_query_replay(Error **errp) retval->mode = replay_mode; if (replay_get_filename()) { retval->filename = g_strdup(replay_get_filename()); - retval->has_filename = true; } retval->icount = replay_get_current_icount(); return retval; diff --git a/replay/replay-events.c b/replay/replay-events.c index ac47c898340f..af0721cc1a16 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -170,13 +170,12 @@ void replay_block_event(QEMUBH *bh, uint64_t id) } } -static void replay_save_event(Event *event, int checkpoint) +static void replay_save_event(Event *event) { if (replay_mode != REPLAY_MODE_PLAY) { /* put the event into the file */ - replay_put_event(EVENT_ASYNC); - replay_put_byte(checkpoint); - replay_put_byte(event->event_kind); + g_assert(event->event_kind < REPLAY_ASYNC_COUNT); + replay_put_event(EVENT_ASYNC + event->event_kind); /* save event-specific data */ switch (event->event_kind) { @@ -206,36 +205,25 @@ static void replay_save_event(Event *event, int checkpoint) } /* Called with replay mutex locked */ -void replay_save_events(int checkpoint) +void replay_save_events(void) { g_assert(replay_mutex_locked()); - g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); - g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL); while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); - replay_save_event(event, checkpoint); + replay_save_event(event); replay_run_event(event); QTAILQ_REMOVE(&events_list, event, events); g_free(event); } } -static Event *replay_read_event(int checkpoint) +static Event *replay_read_event(void) { Event *event; - if (replay_state.read_event_kind == -1) { - replay_state.read_event_checkpoint = replay_get_byte(); - replay_state.read_event_kind = replay_get_byte(); - replay_state.read_event_id = -1; - replay_check_error(); - } - - if (checkpoint != replay_state.read_event_checkpoint) { - return NULL; - } + ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC; /* Events that has not to be in the queue */ - switch (replay_state.read_event_kind) { + switch (event_kind) { case REPLAY_ASYNC_EVENT_BH: case REPLAY_ASYNC_EVENT_BH_ONESHOT: if (replay_state.read_event_id == -1) { @@ -244,17 +232,17 @@ static Event *replay_read_event(int checkpoint) break; case REPLAY_ASYNC_EVENT_INPUT: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = replay_read_input_event(); return event; case REPLAY_ASYNC_EVENT_INPUT_SYNC: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = 0; return event; case REPLAY_ASYNC_EVENT_CHAR_READ: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = replay_event_char_read_load(); return event; case REPLAY_ASYNC_EVENT_BLOCK: @@ -264,18 +252,17 @@ static Event *replay_read_event(int checkpoint) break; case REPLAY_ASYNC_EVENT_NET: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = replay_event_net_load(); return event; default: - error_report("Unknown ID %d of replay event", - replay_state.read_event_kind); + error_report("Unknown ID %d of replay event", event_kind); exit(1); break; } QTAILQ_FOREACH(event, &events_list, events) { - if (event->event_kind == replay_state.read_event_kind + if (event->event_kind == event_kind && (replay_state.read_event_id == -1 || replay_state.read_event_id == event->id)) { break; @@ -284,26 +271,23 @@ static Event *replay_read_event(int checkpoint) if (event) { QTAILQ_REMOVE(&events_list, event, events); - } else { - return NULL; } - /* Read event-specific data */ - return event; } /* Called with replay mutex locked */ -void replay_read_events(int checkpoint) +void replay_read_events(void) { g_assert(replay_mutex_locked()); - while (replay_state.data_kind == EVENT_ASYNC) { - Event *event = replay_read_event(checkpoint); + while (replay_state.data_kind >= EVENT_ASYNC + && replay_state.data_kind <= EVENT_ASYNC_LAST) { + Event *event = replay_read_event(); if (!event) { break; } replay_finish_event(); - replay_state.read_event_kind = -1; + replay_state.read_event_id = -1; replay_run_event(event); g_free(event); @@ -312,7 +296,7 @@ void replay_read_events(int checkpoint) void replay_init_events(void) { - replay_state.read_event_kind = -1; + replay_state.read_event_id = -1; } void replay_finish_events(void) diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 97649ed8d77b..b6836354ac53 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -12,6 +12,19 @@ * */ +/* Asynchronous events IDs */ + +typedef enum ReplayAsyncEventKind { + REPLAY_ASYNC_EVENT_BH, + REPLAY_ASYNC_EVENT_BH_ONESHOT, + REPLAY_ASYNC_EVENT_INPUT, + REPLAY_ASYNC_EVENT_INPUT_SYNC, + REPLAY_ASYNC_EVENT_CHAR_READ, + REPLAY_ASYNC_EVENT_BLOCK, + REPLAY_ASYNC_EVENT_NET, + REPLAY_ASYNC_COUNT +} ReplayAsyncEventKind; + /* Any changes to order/number of events will need to bump REPLAY_VERSION */ enum ReplayEvents { /* for instruction event */ @@ -22,6 +35,7 @@ enum ReplayEvents { EVENT_EXCEPTION, /* for async events */ EVENT_ASYNC, + EVENT_ASYNC_LAST = EVENT_ASYNC + REPLAY_ASYNC_COUNT - 1, /* for shutdown requests, range allows recovery of ShutdownCause */ EVENT_SHUTDOWN, EVENT_SHUTDOWN_LAST = EVENT_SHUTDOWN + SHUTDOWN_CAUSE__MAX, @@ -49,21 +63,6 @@ enum ReplayEvents { EVENT_COUNT }; -/* Asynchronous events IDs */ - -enum ReplayAsyncEventKind { - REPLAY_ASYNC_EVENT_BH, - REPLAY_ASYNC_EVENT_BH_ONESHOT, - REPLAY_ASYNC_EVENT_INPUT, - REPLAY_ASYNC_EVENT_INPUT_SYNC, - REPLAY_ASYNC_EVENT_CHAR_READ, - REPLAY_ASYNC_EVENT_BLOCK, - REPLAY_ASYNC_EVENT_NET, - REPLAY_ASYNC_COUNT -}; - -typedef enum ReplayAsyncEventKind ReplayAsyncEventKind; - typedef struct ReplayState { /*! Cached clock values. */ int64_t cached_clock[REPLAY_CLOCK_COUNT]; @@ -83,12 +82,8 @@ typedef struct ReplayState { uint64_t block_request_id; /*! Prior value of the host clock */ uint64_t host_clock_last; - /*! Asynchronous event type read from the log */ - int32_t read_event_kind; /*! Asynchronous event id read from the log */ uint64_t read_event_id; - /*! Asynchronous event checkpoint id read from the log */ - int32_t read_event_checkpoint; } ReplayState; extern ReplayState replay_state; @@ -141,7 +136,7 @@ bool replay_next_event_is(int event); /*! Reads next clock value from the file. If clock kind read from the file is different from the parameter, the value is not used. */ -void replay_read_next_clock(unsigned int kind); +void replay_read_next_clock(ReplayClockKind kind); /* Asynchronous events queue */ @@ -152,9 +147,9 @@ void replay_finish_events(void); /*! Returns true if there are any unsaved events in the queue */ bool replay_has_events(void); /*! Saves events from queue into the file */ -void replay_save_events(int checkpoint); +void replay_save_events(void); /*! Read events from the file into the input queue */ -void replay_read_events(int checkpoint); +void replay_read_events(void); /*! Adds specified async event to the queue */ void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque, void *opaque2, uint64_t id); diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index e8767a1937c8..10a7cf79927e 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -59,9 +59,7 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT32(has_unread_data, ReplayState), VMSTATE_UINT64(file_offset, ReplayState), VMSTATE_UINT64(block_request_id, ReplayState), - VMSTATE_INT32(read_event_kind, ReplayState), VMSTATE_UINT64(read_event_id, ReplayState), - VMSTATE_INT32(read_event_checkpoint, ReplayState), VMSTATE_END_OF_LIST() }, }; diff --git a/replay/replay-time.c b/replay/replay-time.c index 00ebcb7a493d..ee0ebfcf09f8 100644 --- a/replay/replay-time.c +++ b/replay/replay-time.c @@ -48,7 +48,6 @@ void replay_read_next_clock(ReplayClockKind kind) /*! Reads next clock event from the input. */ int64_t replay_read_clock(ReplayClockKind kind, int64_t raw_icount) { - int64_t ret; g_assert(replay_file && replay_mutex_locked()); replay_advance_current_icount(raw_icount); @@ -56,7 +55,5 @@ int64_t replay_read_clock(ReplayClockKind kind, int64_t raw_icount) if (replay_next_event_is(EVENT_CLOCK + kind)) { replay_read_next_clock(kind); } - ret = replay_state.cached_clock[kind]; - - return ret; + return replay_state.cached_clock[kind]; } diff --git a/replay/replay.c b/replay/replay.c index 6df2abc18c7f..9a0dc1cf4447 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe0200a +#define REPLAY_VERSION 0xe0200c /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) @@ -171,64 +171,49 @@ void replay_shutdown_request(ShutdownCause cause) bool replay_checkpoint(ReplayCheckpoint checkpoint) { - bool res = false; - static bool in_checkpoint; assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); - if (!replay_file) { - return true; - } - - if (in_checkpoint) { - /* - Recursion occurs when HW event modifies timers. - Prevent performing icount warp in this case and - wait for another invocation of the checkpoint. - */ - g_assert(replay_mode == REPLAY_MODE_PLAY); - return false; - } - in_checkpoint = true; - replay_save_instructions(); if (replay_mode == REPLAY_MODE_PLAY) { g_assert(replay_mutex_locked()); if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { replay_finish_event(); - } else if (replay_state.data_kind != EVENT_ASYNC) { - res = false; - goto out; + } else { + return false; } - replay_read_events(checkpoint); - /* replay_read_events may leave some unread events. - Return false if not all of the events associated with - checkpoint were processed */ - res = replay_state.data_kind != EVENT_ASYNC; } else if (replay_mode == REPLAY_MODE_RECORD) { g_assert(replay_mutex_locked()); replay_put_event(EVENT_CHECKPOINT + checkpoint); - /* This checkpoint belongs to several threads. - Processing events from different threads is - non-deterministic */ - if (checkpoint != CHECKPOINT_CLOCK_WARP_START - /* FIXME: this is temporary fix, other checkpoints - may also be invoked from the different threads someday. - Asynchronous event processing should be refactored - to create additional replay event kind which is - nailed to the one of the threads and which processes - the event queue. */ - && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) { - replay_save_events(checkpoint); - } - res = true; } -out: - in_checkpoint = false; - return res; + return true; } -bool replay_has_checkpoint(void) +void replay_async_events(void) +{ + static bool processing = false; + /* + * If we are already processing the events, recursion may occur + * in case of incorrect implementation when HW event modifies timers. + * Timer modification may invoke the icount warp, event processing, + * and cause the recursion. + */ + g_assert(!processing); + processing = true; + + replay_save_instructions(); + + if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); + replay_read_events(); + } else if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); + replay_save_events(); + } + processing = false; +} + +bool replay_has_event(void) { bool res = false; if (replay_mode == REPLAY_MODE_PLAY) { @@ -236,6 +221,8 @@ bool replay_has_checkpoint(void) replay_account_executed_instructions(); res = EVENT_CHECKPOINT <= replay_state.data_kind && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; + res = res || (EVENT_ASYNC <= replay_state.data_kind + && replay_state.data_kind <= EVENT_ASYNC_LAST); } return res; } @@ -379,17 +366,14 @@ 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; - replay_mode = REPLAY_MODE_NONE; - replay_finish_events(); + replay_mode = REPLAY_MODE_NONE; } void replay_add_blocker(Error *reason) diff --git a/roms/SLOF b/roms/SLOF index 5b4c5acdcd55..6b6c16b4b407 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit 5b4c5acdcd552a4e1796aeca6bb700f6cbb0282d +Subproject commit 6b6c16b4b40763507cf1f518096f3c3883c5cf2d diff --git a/roms/opensbi b/roms/opensbi index 48f91ee9c960..4489876e933d 160000 --- a/roms/opensbi +++ b/roms/opensbi @@ -1 +1 @@ -Subproject commit 48f91ee9c960f048c4a7d1da4447d31e04931e38 +Subproject commit 4489876e933d8ba0d8bc6c64bae71e295d45faac diff --git a/roms/qboot b/roms/qboot index a5300c4949b8..8ca302e86d68 160000 --- a/roms/qboot +++ b/roms/qboot @@ -1 +1 @@ -Subproject commit a5300c4949b8d4de2d34bedfaed66793f48ec948 +Subproject commit 8ca302e86d685fa05b16e2b208888243da319941 diff --git a/roms/seabios b/roms/seabios index d239552ce722..3208b098f51a 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit d239552ce7220e448ae81f41515138f7b9e3c4db +Subproject commit 3208b098f51a9ef96d0dfa71d5ec3a3eaec88f0a diff --git a/roms/seabios-hppa b/roms/seabios-hppa index bf3404006fd2..458626c4c644 160000 --- a/roms/seabios-hppa +++ b/roms/seabios-hppa @@ -1 +1 @@ -Subproject commit bf3404006fd2c832857eb57e6f853862f97dacea +Subproject commit 458626c4c6441045c0612f24313c7cf1f95e71c6 diff --git a/roms/skiboot b/roms/skiboot index 820d43c0a775..24a7eb35966d 160000 --- a/roms/skiboot +++ b/roms/skiboot @@ -1 +1 @@ -Subproject commit 820d43c0a7751e75a8830561f35535dfffd522bd +Subproject commit 24a7eb35966d93455520bc2debdd7954314b638b diff --git a/scripts/analyze-inclusions b/scripts/analyze-inclusions index 14806e18c6e1..45c821de32b3 100644 --- a/scripts/analyze-inclusions +++ b/scripts/analyze-inclusions @@ -46,7 +46,6 @@ grep_include() { } echo Found $(find . -name "*.d" | wc -l) object files -echo $(grep_include -F 'include/qemu-common.h') files include qemu-common.h echo $(grep_include -F 'hw/hw.h') files include hw/hw.h echo $(grep_include 'target/[a-z0-9]*/cpu\.h') files include cpu.h echo $(grep_include -F 'qapi-types.h') files include qapi-types.h @@ -86,9 +85,6 @@ analyze() { echo osdep.h: analyze ../include/qemu/osdep.h -echo qemu-common.h: -analyze -include ../include/qemu/osdep.h ../include/qemu-common.h - echo hw/hw.h: analyze -include ../include/qemu/osdep.h ../include/hw/hw.h diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index c6169db69f51..23e042dacdb3 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/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index 08be813407b6..6e087fa0b7f0 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -2,7 +2,7 @@ """Generate coroutine wrappers for block subsystem. The program parses one or several concatenated c files from stdin, -searches for functions with the 'generated_co_wrapper' specifier +searches for functions with the 'co_wrapper' specifier and generates corresponding wrappers on stdout. Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]... @@ -62,10 +62,28 @@ def __init__(self, param_decl: str) -> None: class FuncDecl: - def __init__(self, return_type: str, name: str, args: str) -> None: + def __init__(self, return_type: str, name: str, args: str, + variant: str) -> None: self.return_type = return_type.strip() self.name = name.strip() + self.struct_name = snake_to_camel(self.name) self.args = [ParamDecl(arg.strip()) for arg in args.split(',')] + self.create_only_co = 'mixed' not in variant + self.graph_rdlock = 'bdrv_rdlock' in variant + + subsystem, subname = self.name.split('_', 1) + self.co_name = f'{subsystem}_co_{subname}' + + t = self.args[0].type + if t == 'BlockDriverState *': + ctx = 'bdrv_get_aio_context(bs)' + elif t == 'BdrvChild *': + ctx = 'bdrv_get_aio_context(child->bs)' + elif t == 'BlockBackend *': + ctx = 'blk_get_aio_context(blk)' + else: + ctx = 'qemu_get_aio_context()' + self.ctx = ctx def gen_list(self, format: str) -> str: return ', '.join(format.format_map(arg.__dict__) for arg in self.args) @@ -74,17 +92,20 @@ def gen_block(self, format: str) -> str: return '\n'.join(format.format_map(arg.__dict__) for arg in self.args) -# Match wrappers declared with a generated_co_wrapper mark -func_decl_re = re.compile(r'^int\s*generated_co_wrapper\s*' +# Match wrappers declared with a co_wrapper mark +func_decl_re = re.compile(r'^(?P[a-zA-Z][a-zA-Z0-9_]* [\*]?)' + r'\s*co_wrapper' + r'(?P(_[a-z][a-z0-9_]*)?)\s*' r'(?P[a-z][a-z0-9_]*)' r'\((?P[^)]*)\);$', re.MULTILINE) def func_decl_iter(text: str) -> Iterator: for m in func_decl_re.finditer(text): - yield FuncDecl(return_type='int', + yield FuncDecl(return_type=m.group('return_type'), name=m.group('wrapper_name'), - args=m.group('args')) + args=m.group('args'), + variant=m.group('variant')) def snake_to_camel(func_name: str) -> str: @@ -97,24 +118,75 @@ def snake_to_camel(func_name: str) -> str: return ''.join(words) +def create_mixed_wrapper(func: FuncDecl) -> str: + """ + Checks if we are already in coroutine + """ + name = func.co_name + struct_name = func.struct_name + graph_assume_lock = 'assume_graph_lock();' if func.graph_rdlock else '' + + return f"""\ +{func.return_type} {func.name}({ func.gen_list('{decl}') }) +{{ + if (qemu_in_coroutine()) {{ + {graph_assume_lock} + return {name}({ func.gen_list('{name}') }); + }} else {{ + {struct_name} s = {{ + .poll_state.ctx = {func.ctx}, + .poll_state.in_progress = true, + +{ func.gen_block(' .{name} = {name},') } + }}; + + s.poll_state.co = qemu_coroutine_create({name}_entry, &s); + + bdrv_poll_co(&s.poll_state); + return s.ret; + }} +}}""" + + +def create_co_wrapper(func: FuncDecl) -> str: + """ + Assumes we are not in coroutine, and creates one + """ + name = func.co_name + struct_name = func.struct_name + return f"""\ +{func.return_type} {func.name}({ func.gen_list('{decl}') }) +{{ + {struct_name} s = {{ + .poll_state.ctx = {func.ctx}, + .poll_state.in_progress = true, + +{ func.gen_block(' .{name} = {name},') } + }}; + assert(!qemu_in_coroutine()); + + s.poll_state.co = qemu_coroutine_create({name}_entry, &s); + + bdrv_poll_co(&s.poll_state); + return s.ret; +}}""" + + def gen_wrapper(func: FuncDecl) -> str: assert not '_co_' in func.name - assert func.return_type == 'int' - assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *', - 'BlockBackend *'] - subsystem, subname = func.name.split('_', 1) + name = func.co_name + struct_name = func.struct_name - name = f'{subsystem}_co_{subname}' + graph_lock='' + graph_unlock='' + if func.graph_rdlock: + graph_lock=' bdrv_graph_co_rdlock();' + graph_unlock=' bdrv_graph_co_rdunlock();' - t = func.args[0].type - if t == 'BlockDriverState *': - bs = 'bs' - elif t == 'BdrvChild *': - bs = 'child->bs' - else: - bs = 'blk_bs(blk)' - struct_name = snake_to_camel(name) + creation_function = create_mixed_wrapper + if func.create_only_co: + creation_function = create_co_wrapper return f"""\ /* @@ -123,6 +195,7 @@ def gen_wrapper(func: FuncDecl) -> str: typedef struct {struct_name} {{ BdrvPollCo poll_state; + {func.return_type} ret; { func.gen_block(' {decl};') } }} {struct_name}; @@ -130,29 +203,15 @@ def gen_wrapper(func: FuncDecl) -> str: {{ {struct_name} *s = opaque; - s->poll_state.ret = {name}({ func.gen_list('s->{name}') }); +{graph_lock} + s->ret = {name}({ func.gen_list('s->{name}') }); +{graph_unlock} s->poll_state.in_progress = false; aio_wait_kick(); }} -int {func.name}({ func.gen_list('{decl}') }) -{{ - if (qemu_in_coroutine()) {{ - return {name}({ func.gen_list('{name}') }); - }} else {{ - {struct_name} s = {{ - .poll_state.bs = {bs}, - .poll_state.in_progress = true, - -{ func.gen_block(' .{name} = {name},') } - }}; - - s.poll_state.co = qemu_coroutine_create({name}_entry, &s); - - return bdrv_poll_co(&s.poll_state); - }} -}}""" +{creation_function(func)}""" def gen_wrappers(input_code: str) -> str: diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ddc6003de280..6ecabfb2b520 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -223,7 +223,7 @@ sub help { our $Attribute = qr{ const| volatile| - QEMU_NORETURN| + G_NORETURN| G_GNUC_WARN_UNUSED_RESULT| G_GNUC_NULL_TERMINATED| QEMU_PACKED| @@ -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"; @@ -1680,8 +1681,10 @@ sub process { # Block comment styles # Block comments use /* on a line of its own - if ($rawline !~ m@^\+.*/\*.*\*/[ \t)}]*$@ && #inline /*...*/ - $rawline =~ m@^\+.*/\*\*?+[ \t]*[^ \t]@) { # /* or /** non-blank + my $commentline = $rawline; + while ($commentline =~ s@^(\+.*)/\*.*\*/@$1@o) { # remove inline /*...*/ + } + if ($commentline =~ m@^\+.*/\*\*?+[ \t]*[^ \t]@) { # /* or /** non-blank WARN("Block comments use a leading /* on a separate line\n" . $herecurr); } @@ -2831,8 +2834,8 @@ sub process { } # check for pointless casting of g_malloc return - if ($line =~ /\*\s*\)\s*g_(try)?(m|re)alloc(0?)(_n)?\b/) { - if ($2 == 'm') { + if ($line =~ /\*\s*\)\s*g_(try|)(m|re)alloc(0?)(_n)?\b/) { + if ($2 eq 'm') { ERROR("unnecessary cast may hide bugs, use g_$1new$3 instead\n" . $herecurr); } else { ERROR("unnecessary cast may hide bugs, use g_$1renew$3 instead\n" . $herecurr); @@ -2974,10 +2977,10 @@ sub process { ERROR("use memset() instead of bzero()\n" . $herecurr); } if ($line =~ /\bgetpagesize\(\)/) { - ERROR("use qemu_real_host_page_size instead of getpagesize()\n" . $herecurr); + ERROR("use qemu_real_host_page_size() instead of getpagesize()\n" . $herecurr); } if ($line =~ /\bsysconf\(_SC_PAGESIZE\)/) { - ERROR("use qemu_real_host_page_size instead of sysconf(_SC_PAGESIZE)\n" . $herecurr); + ERROR("use qemu_real_host_page_size() instead of sysconf(_SC_PAGESIZE)\n" . $herecurr); } my $non_exit_glib_asserts = qr{g_assert_cmpstr| g_assert_cmpint| diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure index 9850dd44444a..75882faa9ca5 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/configure +++ b/scripts/ci/org.centos/stream/8/x86_64/configure @@ -132,17 +132,15 @@ --disable-vhost-crypto \ --disable-vhost-kernel \ --disable-vhost-net \ ---disable-vhost-scsi \ --disable-vhost-user \ --disable-vhost-user-blk-server \ --disable-vhost-vdpa \ ---disable-vhost-vsock \ --disable-virglrenderer \ --disable-virtfs \ --disable-virtiofsd \ --disable-vnc \ --disable-vnc-jpeg \ ---disable-vnc-png \ +--disable-png \ --disable-vnc-sasl \ --disable-vte \ --disable-vvfat \ @@ -190,7 +188,7 @@ --enable-tcg \ --enable-tools \ --enable-tpm \ ---enable-trace-backend=dtrace \ +--enable-trace-backends=dtrace \ --enable-usb-redir \ --enable-virtiofsd \ --enable-vhost-kernel \ @@ -198,9 +196,8 @@ --enable-vhost-user \ --enable-vhost-user-blk-server \ --enable-vhost-vdpa \ ---enable-vhost-vsock \ --enable-vnc \ ---enable-vnc-png \ +--enable-png \ --enable-vnc-sasl \ --enable-werror \ --enable-xkbcommon diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index 9182e0c253fd..b04c2b7ceee9 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -33,10 +33,9 @@ when: - ansible_facts['distribution'] == 'Ubuntu' - - name: Install basic packages to build QEMU on Ubuntu 18.04/20.04 + - name: Install basic packages to build QEMU on Ubuntu 20.04 package: name: - # Originally from tests/docker/dockerfiles/ubuntu1804.docker - ccache - gcc - gettext @@ -90,7 +89,7 @@ when: - ansible_facts['distribution'] == 'Ubuntu' - - name: Install packages to build QEMU on Ubuntu 18.04/20.04 on non-s390x + - name: Install packages to build QEMU on Ubuntu 20.04 on non-s390x package: name: - libspice-server-dev @@ -98,16 +97,7 @@ state: present when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] != 's390x' - - - name: Install basic packages to build QEMU on Ubuntu 18.04 - package: - name: - # Originally from tests/docker/dockerfiles/ubuntu1804.docker - - clang - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_version'] == '18.04' + - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64' - name: Install basic packages to build QEMU on Ubuntu 20.04 package: @@ -163,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 @@ -177,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/clean-header-guards.pl b/scripts/clean-header-guards.pl index a6680253b1fa..a7fd8dc99f4a 100755 --- a/scripts/clean-header-guards.pl +++ b/scripts/clean-header-guards.pl @@ -32,8 +32,8 @@ use Getopt::Std; # Stuff we don't want to clean because we import it into our tree: -my $exclude = qr,^(disas/libvixl/|include/standard-headers/ - |linux-headers/|pc-bios/|tests/tcg/|tests/multiboot/),x; +my $exclude = qr,^(include/standard-headers/|linux-headers/ + |pc-bios/|tests/tcg/|tests/multiboot/),x; # Stuff that is expected to fail the preprocessing test: my $exclude_cpp = qr,^include/libdecnumber/decNumberLocal.h,; diff --git a/scripts/clean-includes b/scripts/clean-includes index aaa7d4ceb389..d37bd4f69284 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -51,7 +51,7 @@ GIT=no DUPHEAD=no # Extended regular expression defining files to ignore when using --all -XDIRREGEX='^(tests/tcg|tests/multiboot|pc-bios|disas/libvixl)' +XDIRREGEX='^(tests/tcg|tests/multiboot|pc-bios)' while true do diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h index 3d1e9b50919a..d247a5086e91 100644 --- a/scripts/cocci-macro-file.h +++ b/scripts/cocci-macro-file.h @@ -19,7 +19,7 @@ */ /* From qemu/compiler.h */ -#define QEMU_NORETURN __attribute__ ((__noreturn__)) +#define G_NORETURN __attribute__ ((__noreturn__)) #define G_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #define G_GNUC_NULL_TERMINATED __attribute__((sentinel)) diff --git a/scripts/coccinelle/return_directly.cocci b/scripts/coccinelle/return_directly.cocci index 4cf50e75ea03..6cb1b3c99a77 100644 --- a/scripts/coccinelle/return_directly.cocci +++ b/scripts/coccinelle/return_directly.cocci @@ -11,9 +11,8 @@ identifier F; - T VAR; ... when != VAR -- VAR = -+ return - E; +- VAR = (E); - return VAR; ++ return E; ... when != VAR } diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md index 183f26a32c98..0e6ab4936e5d 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/.*) @@ -87,9 +87,6 @@ io ipmi ~ (/qemu)?((/include)?/hw/ipmi/.*) -libvixl - ~ (/qemu)?(/disas/libvixl/.*) - migration ~ (/qemu)?((/include)?/migration/.*) @@ -111,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.*) @@ -146,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/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index 181bdcb26382..129672c86fa1 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -394,7 +394,7 @@ echo "Configuring..." --enable-opengl --enable-vte --enable-gnutls \ --enable-nettle --enable-curses --enable-curl \ --audio-drv-list=oss,alsa,sdl,pa --enable-virtfs \ - --enable-vnc --enable-vnc-sasl --enable-vnc-jpeg --enable-vnc-png \ + --enable-vnc --enable-vnc-sasl --enable-vnc-jpeg --enable-png \ --enable-xen --enable-brlapi \ --enable-linux-aio --enable-attr \ --enable-cap-ng --enable-trace-backends=log --enable-spice --enable-rbd \ diff --git a/scripts/cpu-x86-uarch-abi.py b/scripts/cpu-x86-uarch-abi.py index c262d2f02778..82ff07582f8a 100644 --- a/scripts/cpu-x86-uarch-abi.py +++ b/scripts/cpu-x86-uarch-abi.py @@ -6,7 +6,7 @@ # compatibility levels for each CPU model. # -from qemu.aqmp.legacy import QEMUMonitorProtocol +from qemu.qmp.legacy import QEMUMonitorProtocol import sys if len(sys.argv) != 2: diff --git a/scripts/dbus_mu_client.py b/scripts/dbus_mu_client.py new file mode 100644 index 000000000000..93488816dc9d --- /dev/null +++ b/scripts/dbus_mu_client.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 + +from __future__ import print_function + +usage = """Usage: +python3 imx-s400-mu-service.py & +python3 imx-s400-mu-client.py +python3 imx-s400-mu-client.py --exit-service +""" + +# Copyright (C) 2004-2006 Red Hat Inc. +# Copyright (C) 2005-2007 Collabora Ltd. +# +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +import sys +from traceback import print_exc +from gi.repository import GLib + +import dbus +import dbus.mainloop.glib + +loop = None + +def catchall_mu_signals_handler(hello_string): + global loop + print("Received a hello signal and it says ", hello_string) + GLib.timeout_add(500, loop.quit) + +def hello_signal_handler(hello_string): + print ("Received signal (by connecting using remote object) and it says: " + + hello_string) + +def main(): + global loop + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + bus = dbus.SessionBus() + + try: + remote_object = bus.get_object("org.qemu.client", + "/org/qemu/client") + + # you can either specify the dbus_interface in each call... + hello_reply_list = remote_object.HelloWorld("Hello from dbus_mu_client.py!", + dbus_interface = "org.qemu.client") + remote_object.connect_to_signal("MUSignal", hello_signal_handler, dbus_interface="org.qemu.client.mua", arg0="Hello") + except dbus.DBusException: + print_exc() + print(usage) + sys.exit(1) + + bus.add_signal_receiver(catchall_mu_signals_handler, dbus_interface = "org.qemu.client.mua", signal_name = "MUSignal") + + print("client:", hello_reply_list) + + if sys.argv[1:] == ['--exit-service']: + iface = dbus.Interface(remote_object, "org.qemu.client") + iface.Exit() + return + + # ... or create an Interface wrapper for the remote object + iface = dbus.Interface(remote_object, "org.qemu.client.mua") + + read_reply = iface.MUARead(0x0) + + print("client:", read_reply) + + write_reply = iface.MUAWrite(0x40, 1) + + print("client:", write_reply) + + signal_reply = iface.emitMUASignal() + + print("signal:", signal_reply) + + # D-Bus exceptions are mapped to Python exceptions + try: + iface.RaiseException() + except dbus.DBusException as e: + print("client:", str(e)) + + # introspection is automatically supported + print("client:", remote_object.Introspect(dbus_interface="org.freedesktop.DBus.Introspectable")) + + + + loop = GLib.MainLoop() + loop.run() + +if __name__ == '__main__': + main() diff --git a/scripts/dbus_mu_service.py b/scripts/dbus_mu_service.py new file mode 100644 index 000000000000..a9eeaa0a6d58 --- /dev/null +++ b/scripts/dbus_mu_service.py @@ -0,0 +1,381 @@ +#!/usr/bin/env python3 + +from __future__ import print_function +import logging + +from gi.repository import GLib + +from enum import IntEnum + +import dbus +import dbus.service +import dbus.mainloop.glib + +usage = """Usage: +python3 dbus_mu_service.py & +python3 dbus_mu_client.py +python3 dbus_mu_client.py --exit-service +""" + +# Copyright (C) 2004-2006 Red Hat Inc. +# Copyright (C) 2005-2007 Collabora Ltd. +# Copyright (C) 2022-2023 NXP +# +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + +# pylint: disable=R0201,C0103,R1725,W1203 + +logging.basicConfig(level = logging.DEBUG) +logger = logging.getLogger() + +class DemoException(dbus.DBusException): + ''' + DemoException + ''' + _dbus_error_name = 'org.qemu.client.mu.Exception' + + +class DBusMu(dbus.service.Object): + ''' + DdbusMu class + ''' + VER = 0x0 + PAR = 0x4 + SR = 0x60 + CR = 0x64 + TRN = [0x20, 0x24, 0x28, 0x2C] + RRN = [0x40, 0x44, 0x48, 0x4C] + GIRN_OFFSET = 16 + GIRN_MASK = 0xF<>self.GIRN_OFFSET + self.mub_data[hex(self.CR)] |= _v<>self.GIPN_OFFSET + _v = ~_v + if _v: + self.mub_data[hex(self.CR)] &= ~(_v<>self.GIRN_OFFSET + self.mua_data[hex(self.CR)] |= _v<>self.GIPN_OFFSET + _v = ~_v + if _v: + self.mua_data[hex(self.CR)] &= ~(_v< $builddir/tests/venv/bin/python3 "{path}"') + sys.exit(1) logger = logging.getLogger('device-crash-test') dbg = logger.debug @@ -93,6 +101,7 @@ ERROR_RULE_LIST = [ {'device':'pci-bridge', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. {'device':'pci-bridge-seat', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. {'device':'pxb', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. + {'device':'pxb-cxl', 'expected':True}, # pxb-cxl devices cannot reside on a PCI bus. {'device':'scsi-block', 'expected':True}, # drive property not set {'device':'scsi-generic', 'expected':True}, # drive property not set {'device':'scsi-hd', 'expected':True}, # drive property not set @@ -517,7 +526,7 @@ def main(): # Async QMP, when in use, is chatty about connection failures. # This script knowingly generates a ton of connection errors. # Silence this logger. - logging.getLogger('qemu.aqmp.qmp_client').setLevel(logging.CRITICAL) + logging.getLogger('qemu.qmp.qmp_client').setLevel(logging.CRITICAL) fatal_failures = [] wl_stats = {} diff --git a/scripts/feature_to_c.sh b/scripts/feature_to_c.sh index b1169899c19d..c1f67c8f6a57 100644 --- a/scripts/feature_to_c.sh +++ b/scripts/feature_to_c.sh @@ -56,6 +56,7 @@ for input; do done echo +echo '#include "exec/gdbstub.h"' echo "const char *const xml_builtin[][2] = {" for input; do diff --git a/scripts/gensyscalls.sh b/scripts/gensyscalls.sh index 8fb450e3c960..a2f7664b7bb4 100755 --- a/scripts/gensyscalls.sh +++ b/scripts/gensyscalls.sh @@ -44,6 +44,7 @@ read_includes() cpp -P -nostdinc -fdirectives-only \ -D_UAPI_ASM_$(upper ${arch})_BITSPERLONG_H \ + -D__ASM_$(upper ${arch})_BITSPERLONG_H \ -D__BITS_PER_LONG=${bits} \ -I${linux}/arch/${arch}/include/uapi/ \ -I${linux}/include/uapi \ @@ -99,4 +100,5 @@ generate_syscall_nr openrisc 32 "$output/linux-user/openrisc/syscall_nr.h" generate_syscall_nr riscv 32 "$output/linux-user/riscv/syscall32_nr.h" generate_syscall_nr riscv 64 "$output/linux-user/riscv/syscall64_nr.h" generate_syscall_nr hexagon 32 "$output/linux-user/hexagon/syscall_nr.h" +generate_syscall_nr loongarch 64 "$output/linux-user/loongarch64/syscall_nr.h" rm -fr "$TMP" diff --git a/scripts/git-submodule.sh b/scripts/git-submodule.sh index e225d3a96344..7be41f594832 100755 --- a/scripts/git-submodule.sh +++ b/scripts/git-submodule.sh @@ -51,6 +51,12 @@ validate_error() { exit 1 } +if test -n "$maybe_modules" && ! test -e ".git" +then + echo "$0: unexpectedly called with submodules but no git checkout exists" + exit 1 +fi + modules="" for m in $maybe_modules do @@ -63,12 +69,6 @@ do fi done -if test -n "$maybe_modules" && ! test -e ".git" -then - echo "$0: unexpectedly called with submodules but no git checkout exists" - exit 1 -fi - case "$command" in status|validate) if test -z "$maybe_modules" diff --git a/scripts/hxtool-conv.pl b/scripts/hxtool-conv.pl deleted file mode 100755 index eede40b34622..000000000000 --- a/scripts/hxtool-conv.pl +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/perl -w -# -# Script to convert .hx file STEXI/ETEXI blocks to SRST/ERST -# -# Copyright (C) 2020 Linaro -# -# 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. - -# This script was only ever intended as a one-off conversion operation. -# Please excuse the places where it is a bit hacky. -# Some manual intervention after the conversion is expected, as are -# some warnings from makeinfo. -# Warning: this script is not idempotent: don't try to run it on -# a .hx file that already has SRST/ERST sections. - -# Expected usage: -# scripts/hxtool-conv.pl file.hx > file.hx.new - -use utf8; - -my $reading_texi = 0; -my $texiblock = ''; -my @tables = (); - -sub update_tables($) { - my ($texi) = @_; - # Update our list of open table directives: every @table - # line in the texi fragment is added to the list, and every - # @end table line means we remove an entry from the list. - # If this fragment had a completely self contained table with - # both the @table and @end table lines, this will be a no-op. - foreach (split(/\n/, $texi)) { - push @tables, $_ if /^\@table/; - pop @tables if /^\@end table/; - } -} - -sub only_table_directives($) { - # Return true if every line in the fragment is a start or end table directive - my ($texi) = @_; - foreach (split(/\n/, $texi)) { - return 0 unless /^\@table/ or /^\@end table/; - } - return 1; -} - -sub output_rstblock($) { - # Write the output to /tmp/frag.texi, wrapped in whatever current @table - # lines we need. - my ($texi) = @_; - - # As a special case, if this fragment is only table directives and - # nothing else, update our set of open table directives but otherwise - # ignore it. This avoids emitting an empty SRST/ERST block. - if (only_table_directives($texi)) { - update_tables($texi); - return; - } - - open(my $fragfh, '>', '/tmp/frag.texi'); - # First output the currently active set of open table directives - print $fragfh join("\n", @tables); - # Next, update our list of open table directives. - # We need to do this before we emit the closing table directives - # so that we emit the right number if this fragment had an - # unbalanced set of directives. - update_tables($texi); - # Then emit the texi fragment itself. - print $fragfh "\n$texi\n"; - # Finally, add the necessary closing table directives. - print $fragfh "\@end table\n" x scalar @tables; - close $fragfh; - - # Now invoke makeinfo/pandoc on it and slurp the results into a string - open(my $fh, '-|', "makeinfo --force -o - --docbook " - . "-D 'qemu_system_x86 QEMU_SYSTEM_X86_MACRO' " - . "-D 'qemu_system QEMU_SYSTEM_MACRO' /tmp/frag.texi " - . " | pandoc -f docbook -t rst") - or die "can't start makeinfo/pandoc: $!"; - - binmode $fh, ':encoding(utf8)'; - - print "SRST\n"; - - # Slurp the whole thing into a string so we can do multiline - # string matches on it. - my $rst = do { - local $/ = undef; - <$fh>; - }; - $rst =~ s/^- − /- /gm; - $rst =~ s/“/"/gm; - $rst =~ s/”/"/gm; - $rst =~ s/‘/'/gm; - $rst =~ s/’/'/gm; - $rst =~ s/QEMU_SYSTEM_MACRO/|qemu_system|/g; - $rst =~ s/QEMU_SYSTEM_X86_MACRO/|qemu_system_x86|/g; - $rst =~ s/(?=::\n\n +\|qemu)/.. parsed-literal/g; - $rst =~ s/:\n\n::$/::/gm; - - # Fix up the invalid reference format makeinfo/pandoc emit: - # `Some string here <#anchorname>`__ - # should be: - # :ref:`anchorname` - $rst =~ s/\`[^<`]+\<\#([^>]+)\>\`__/:ref:`$1`/gm; - print $rst; - - close $fh or die "error on close: $!"; - print "ERST\n"; -} - -# Read the whole .hx input file. -while (<>) { - # Always print the current line - print; - if (/STEXI/) { - $reading_texi = 1; - $texiblock = ''; - next; - } - if (/ETEXI/) { - $reading_texi = 0; - # dump RST version of block - output_rstblock($texiblock); - next; - } - if ($reading_texi) { - # Accumulate the texi into a string - # but drop findex entries as they will confuse makeinfo - next if /^\@findex/; - $texiblock .= $_; - } -} - -die "Unexpectedly still in texi block at EOF" if $reading_texi; diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index f140040104bf..ce27f5e635af 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -23,6 +23,7 @@ MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490 MSR_IA32_VMX_VMFUNC = 0x491 +MSR_IA32_VMX_PROCBASED_CTLS3 = 0x492 class msr(object): def __init__(self): @@ -71,6 +72,13 @@ class Control(object): s = 'yes' print(' %-40s %s' % (self.bits[bit], s)) +# All 64 bits in the tertiary controls MSR are allowed-1 +class Allowed1Control(Control): + def read2(self, nr): + m = msr() + val = m.read(nr, 0) + return (0, val) + class Misc(object): def __init__(self, name, bits, msr): self.name = name @@ -135,6 +143,7 @@ controls = [ 12: 'RDTSC exiting', 15: 'CR3-load exiting', 16: 'CR3-store exiting', + 17: 'Activate tertiary controls', 19: 'CR8-load exiting', 20: 'CR8-store exiting', 21: 'Use TPR shadow', @@ -186,6 +195,14 @@ controls = [ cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, ), + Allowed1Control( + name = 'tertiary processor-based controls', + bits = { + 4: 'Enable IPI virtualization' + }, + cap_msr = MSR_IA32_VMX_PROCBASED_CTLS3, + ), + Control( name = 'VM-Exit controls', bits = { diff --git a/scripts/main.c b/scripts/main.c new file mode 100644 index 000000000000..b552c8e4ed7d --- /dev/null +++ b/scripts/main.c @@ -0,0 +1 @@ +int main(void) {} diff --git a/scripts/make-release b/scripts/make-release index 05b14ecc95eb..44a9d86a04a7 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -10,14 +10,22 @@ # This work is licensed under the terms of the GNU GPLv2 or later. # See the COPYING file in the top-level directory. +if [ $# -ne 2 ]; then + echo "Usage:" + echo " $0 gitrepo version" + exit 0 +fi + src="$1" version="$2" destination=qemu-${version} -git clone "${src}" ${destination} +git clone --single-branch -b "v${version}" -c advice.detachedHead=false \ + "${src}" ${destination} + pushd ${destination} -git checkout "v${version}" -git submodule update --init + +git submodule update --init --single-branch (cd roms/seabios && git describe --tags --long --dirty > .version) (cd roms/skiboot && ./make_version.sh > .version) # Fetch edk2 submodule's submodules, since it won't have access to them via @@ -28,7 +36,7 @@ git submodule update --init # submodule dependencies, so we continue to handle these on a case-by-case # basis for now. (cd roms/edk2 && \ - git submodule update --init -- \ + git submodule update --init --depth 1 -- \ ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 \ BaseTools/Source/C/BrotliCompress/brotli \ CryptoPkg/Library/OpensslLib/openssl \ diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 693be7b96601..3e2b4785388f 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -26,20 +26,34 @@ import sys SKIP_OPTIONS = { - "audio_drv_list", "default_devices", - "docdir", "fuzzing_engine", - "iasl", - "qemu_firmwarepath", "qemu_suffix", "smbd", - "sphinx_build", - "trace_file", +} + +OPTION_NAMES = { + "b_coverage": "gcov", + "b_lto": "lto", + "malloc": "enable-malloc", + "pkgversion": "with-pkgversion", + "qemu_firmwarepath": "firmwarepath", + "trace_backends": "enable-trace-backends", + "trace_file": "with-trace-file", } BUILTIN_OPTIONS = { + "b_coverage", + "b_lto", + "datadir", + "includedir", + "libdir", + "libexecdir", + "localedir", + "localstatedir", + "mandir", "strip", + "sysconfdir", } LINE_WIDTH = 76 @@ -75,7 +89,7 @@ def help_line(left, opt, indent, long): right = f'{opt["description"]}' if long: value = value_to_help(opt["value"]) - if value != "auto": + if value != "auto" and value != "": right += f" [{value}]" if "choices" in opt and long: choices = "/".join(sorted(opt["choices"])) @@ -96,6 +110,18 @@ def allow_arg(opt): return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"}) +# Return whether the option (a dictionary) can be used without +# arguments. Booleans can only be used without arguments; +# combos require an argument if they accept neither "enabled" +# nor "disabled" +def require_arg(opt): + if opt["type"] == "boolean": + return False + if opt["type"] != "combo": + return True + return not ({"enabled", "disabled"}.intersection(opt["choices"])) + + def filter_options(json): if ":" in json["name"]: return False @@ -110,20 +136,48 @@ def load_options(json): return sorted(json, key=lambda x: x["name"]) +def cli_option(opt): + name = opt["name"] + if name in OPTION_NAMES: + return OPTION_NAMES[name] + return name.replace("_", "-") + + +def cli_help_key(opt): + key = cli_option(opt) + if require_arg(opt): + return key + if opt["type"] == "boolean" and opt["value"]: + return f"disable-{key}" + return f"enable-{key}" + + +def cli_metavar(opt): + if opt["type"] == "string": + return "VALUE" + if opt["type"] == "array": + return "CHOICES" if "choices" in opt else "VALUES" + return "CHOICE" + + def print_help(options): print("meson_options_help() {") - for opt in options: - key = opt["name"].replace("_", "-") + for opt in sorted(options, key=cli_help_key): + key = cli_help_key(opt) # The first section includes options that have an arguments, # and booleans (i.e., only one of enable/disable makes sense) - if opt["type"] == "boolean": - left = f"--disable-{key}" if opt["value"] else f"--enable-{key}" + if require_arg(opt): + metavar = cli_metavar(opt) + left = f"--{key}={metavar}" + help_line(left, opt, 27, True) + elif opt["type"] == "boolean": + left = f"--{key}" help_line(left, opt, 27, False) elif allow_arg(opt): if opt["type"] == "combo" and "enabled" in opt["choices"]: - left = f"--enable-{key}[=CHOICE]" + left = f"--{key}[=CHOICE]" else: - left = f"--enable-{key}=CHOICE" + left = f"--{key}=CHOICE" help_line(left, opt, 27, True) sh_print() @@ -142,9 +196,14 @@ def print_parse(options): print("_meson_option_parse() {") print(" case $1 in") for opt in options: - key = opt["name"].replace("_", "-") + key = cli_option(opt) name = opt["name"] - if opt["type"] == "boolean": + if require_arg(opt): + if opt["type"] == "array" and not "choices" in opt: + print(f' --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;') + else: + print(f' --{key}=*) quote_sh "-D{name}=$2" ;;') + elif opt["type"] == "boolean": print(f' --enable-{key}) printf "%s" -D{name}=true ;;') print(f' --disable-{key}) printf "%s" -D{name}=false ;;') else: diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 1e26f4571ef4..0f71e92dcba6 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -1,35 +1,66 @@ # 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: 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)' + printf "%s\n" ' --block-drv-rw-whitelist=VALUE' + printf "%s\n" ' set block driver read-write whitelist (by default' + printf "%s\n" ' affects only QEMU, not tools like qemu-img)' + printf "%s\n" ' --datadir=VALUE Data file directory [share]' + printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' + printf "%s\n" ' --disable-hexagon-idef-parser' + printf "%s\n" ' use idef-parser to automatically generate TCG' + printf "%s\n" ' code for the Hexagon frontend' + printf "%s\n" ' --disable-install-blobs install provided firmware blobs' + printf "%s\n" ' --docdir=VALUE Base directory for documentation installation' + printf "%s\n" ' (can be empty) [share/doc]' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' printf "%s\n" ' use block whitelist also in tools instead of only' printf "%s\n" ' QEMU' - printf "%s\n" ' --enable-capstone[=CHOICE]' - printf "%s\n" ' Whether and how to find the capstone library' - printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-cfi Control-Flow Integrity (CFI)' printf "%s\n" ' --enable-cfi-debug Verbose errors in case of CFI violation' - printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' printf "%s\n" ' --enable-debug-mutex mutex debugging support' printf "%s\n" ' --enable-debug-stack-usage' printf "%s\n" ' measure coroutine stack usage' printf "%s\n" ' --enable-fdt[=CHOICE] Whether and how to find the libfdt library' printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-fuzzing build fuzzing targets' + printf "%s\n" ' --enable-gcov Enable coverage tracking.' printf "%s\n" ' --enable-gprof QEMU profiling with gprof' - printf "%s\n" ' --disable-install-blobs install provided firmware blobs' + printf "%s\n" ' --enable-lto Use link time optimization' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' + printf "%s\n" ' --enable-module-upgrades try to load modules from alternate paths for' + printf "%s\n" ' upgrades' printf "%s\n" ' --enable-profiler profiler support' 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=CHOICE' + printf "%s\n" ' --enable-trace-backends=CHOICES' printf "%s\n" ' Set available tracing backends [log] (choices:' printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' + printf "%s\n" ' --firmwarepath=VALUES search PATH for firmware files [share/qemu-' + printf "%s\n" ' firmware]' + printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' + printf "%s\n" ' --includedir=VALUE Header file directory [include]' + printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for' + printf "%s\n" ' cpu name [/usr/gnemul/qemu-%M]' + printf "%s\n" ' --libdir=VALUE Library directory [lib64]' + printf "%s\n" ' --libexecdir=VALUE Library executable directory [libexec]' + printf "%s\n" ' --localedir=VALUE Locale data directory [share/locale]' + printf "%s\n" ' --localstatedir=VALUE Localstate data directory [/var/local]' + printf "%s\n" ' --mandir=VALUE Manual page directory [share/man]' + printf "%s\n" ' --sphinx-build=VALUE Use specified sphinx-build for building document' + printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]' + printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' + printf "%s\n" ' [NORMAL]' + printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the' + printf "%s\n" ' package' + printf "%s\n" ' --with-trace-file=VALUE Trace file prefix for simple backend [trace]' printf "%s\n" '' printf "%s\n" 'Optional features, enabled with --enable-FEATURE and' printf "%s\n" 'disabled with --disable-FEATURE, default is enabled if available' @@ -40,11 +71,14 @@ meson_options_help() { printf "%s\n" ' auth-pam PAM access control' printf "%s\n" ' avx2 AVX2 optimizations' printf "%s\n" ' avx512f AVX512F optimizations' + printf "%s\n" ' blkio libblkio block device driver' printf "%s\n" ' bochs bochs image format support' printf "%s\n" ' bpf eBPF support' printf "%s\n" ' brlapi brlapi character device driver' printf "%s\n" ' bzip2 bzip2 support for DMG images' + printf "%s\n" ' canokey CanoKey support' printf "%s\n" ' cap-ng cap_ng support' + printf "%s\n" ' capstone Whether and how to find the capstone library' printf "%s\n" ' cloop cloop image format support' printf "%s\n" ' cocoa Cocoa user interface (macOS only)' printf "%s\n" ' coreaudio CoreAudio sound support' @@ -59,15 +93,18 @@ meson_options_help() { printf "%s\n" ' fuse-lseek SEEK_HOLE/SEEK_DATA support for FUSE exports' printf "%s\n" ' gcrypt libgcrypt cryptography support' printf "%s\n" ' gettext Localization of the GTK+ user interface' + printf "%s\n" ' gio use libgio for D-Bus support' printf "%s\n" ' glusterfs Glusterfs block device driver' printf "%s\n" ' gnutls GNUTLS cryptography support' printf "%s\n" ' gtk GTK+ user interface' + printf "%s\n" ' gtk-clipboard clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)' printf "%s\n" ' guest-agent Build QEMU Guest Agent' printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Agent' printf "%s\n" ' hax HAX acceleration support' printf "%s\n" ' hvf HVF acceleration support' printf "%s\n" ' iconv Font glyph conversion support' printf "%s\n" ' jack JACK sound support' + printf "%s\n" ' keyring Linux keyring support' printf "%s\n" ' kvm KVM acceleration support' printf "%s\n" ' l2tpv3 l2tpv3 network backend support' printf "%s\n" ' libdaxctl libdaxctl support' @@ -77,6 +114,7 @@ meson_options_help() { printf "%s\n" ' libssh ssh block device support' printf "%s\n" ' libudev Use libudev to enumerate host devices' printf "%s\n" ' libusb libusb support for USB passthrough' + printf "%s\n" ' libvduse build VDUSE Library' printf "%s\n" ' linux-aio Linux AIO support' printf "%s\n" ' linux-io-uring Linux io_uring support' printf "%s\n" ' live-block-migration' @@ -91,21 +129,27 @@ meson_options_help() { printf "%s\n" ' nettle nettle cryptography support' printf "%s\n" ' numa libnuma support' printf "%s\n" ' nvmm NVMM acceleration support' + printf "%s\n" ' opengl OpenGL support' printf "%s\n" ' oss OSS sound support' printf "%s\n" ' pa PulseAudio sound support' printf "%s\n" ' parallels parallels image format support' + printf "%s\n" ' png PNG support with libpng' + printf "%s\n" ' pvrdma Enable PVRDMA support' printf "%s\n" ' qcow1 qcow1 image format support' printf "%s\n" ' qed qed image format support' printf "%s\n" ' qga-vss build QGA VSS support (broken with MinGW)' printf "%s\n" ' rbd Ceph block device driver' + printf "%s\n" ' rdma Enable RDMA-based migration' printf "%s\n" ' replication replication support' printf "%s\n" ' sdl SDL user interface' 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' @@ -116,14 +160,23 @@ meson_options_help() { printf "%s\n" ' usb-redir libusbredir support' printf "%s\n" ' vde vde network backend support' printf "%s\n" ' vdi vdi image format support' + printf "%s\n" ' vduse-blk-export' + printf "%s\n" ' VDUSE block export support' + printf "%s\n" ' vfio-user-server' + printf "%s\n" ' vfio-user server support' + printf "%s\n" ' vhost-crypto vhost-user crypto backend support' + printf "%s\n" ' vhost-kernel vhost kernel backend support' + printf "%s\n" ' vhost-net vhost-net kernel acceleration support' + printf "%s\n" ' vhost-user vhost-user backend support' printf "%s\n" ' vhost-user-blk-server' printf "%s\n" ' build vhost-user-blk server' + printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support' printf "%s\n" ' virglrenderer virgl rendering support' printf "%s\n" ' virtfs virtio-9p support' printf "%s\n" ' virtiofsd build virtiofs daemon (virtiofsd)' + printf "%s\n" ' vmnet vmnet.framework network backend support' printf "%s\n" ' vnc VNC server' printf "%s\n" ' vnc-jpeg JPEG lossy compression for VNC server' - printf "%s\n" ' vnc-png PNG compression for VNC server' printf "%s\n" ' vnc-sasl SASL authentication for VNC server' printf "%s\n" ' vte vte support for the gtk UI' printf "%s\n" ' vvfat vvfat image format support' @@ -140,12 +193,21 @@ _meson_option_parse() { --disable-alsa) printf "%s" -Dalsa=disabled ;; --enable-attr) printf "%s" -Dattr=enabled ;; --disable-attr) printf "%s" -Dattr=disabled ;; + --audio-drv-list=*) quote_sh "-Daudio_drv_list=$2" ;; --enable-auth-pam) printf "%s" -Dauth_pam=enabled ;; --disable-auth-pam) printf "%s" -Dauth_pam=disabled ;; --enable-avx2) printf "%s" -Davx2=enabled ;; --disable-avx2) printf "%s" -Davx2=disabled ;; --enable-avx512f) printf "%s" -Davx512f=enabled ;; --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --enable-gcov) printf "%s" -Db_coverage=true ;; + --disable-gcov) printf "%s" -Db_coverage=false ;; + --enable-lto) printf "%s" -Db_lto=true ;; + --disable-lto) printf "%s" -Db_lto=false ;; + --enable-blkio) printf "%s" -Dblkio=enabled ;; + --disable-blkio) printf "%s" -Dblkio=disabled ;; + --block-drv-ro-whitelist=*) quote_sh "-Dblock_drv_ro_whitelist=$2" ;; + --block-drv-rw-whitelist=*) quote_sh "-Dblock_drv_rw_whitelist=$2" ;; --enable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=true ;; --disable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=false ;; --enable-bochs) printf "%s" -Dbochs=enabled ;; @@ -156,11 +218,12 @@ _meson_option_parse() { --disable-brlapi) printf "%s" -Dbrlapi=disabled ;; --enable-bzip2) printf "%s" -Dbzip2=enabled ;; --disable-bzip2) printf "%s" -Dbzip2=disabled ;; + --enable-canokey) printf "%s" -Dcanokey=enabled ;; + --disable-canokey) printf "%s" -Dcanokey=disabled ;; --enable-cap-ng) printf "%s" -Dcap_ng=enabled ;; --disable-cap-ng) printf "%s" -Dcap_ng=disabled ;; --enable-capstone) printf "%s" -Dcapstone=enabled ;; --disable-capstone) printf "%s" -Dcapstone=disabled ;; - --enable-capstone=*) quote_sh "-Dcapstone=$2" ;; --enable-cfi) printf "%s" -Dcfi=true ;; --disable-cfi) printf "%s" -Dcfi=false ;; --enable-cfi-debug) printf "%s" -Dcfi_debug=true ;; @@ -179,6 +242,7 @@ _meson_option_parse() { --disable-curl) printf "%s" -Dcurl=disabled ;; --enable-curses) printf "%s" -Dcurses=enabled ;; --disable-curses) printf "%s" -Dcurses=disabled ;; + --datadir=*) quote_sh "-Ddatadir=$2" ;; --enable-dbus-display) printf "%s" -Ddbus_display=enabled ;; --disable-dbus-display) printf "%s" -Ddbus_display=disabled ;; --enable-debug-mutex) printf "%s" -Ddebug_mutex=true ;; @@ -187,6 +251,7 @@ _meson_option_parse() { --disable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=false ;; --enable-dmg) printf "%s" -Ddmg=enabled ;; --disable-dmg) printf "%s" -Ddmg=disabled ;; + --docdir=*) quote_sh "-Ddocdir=$2" ;; --enable-docs) printf "%s" -Ddocs=enabled ;; --disable-docs) printf "%s" -Ddocs=disabled ;; --enable-dsound) printf "%s" -Ddsound=enabled ;; @@ -204,6 +269,8 @@ _meson_option_parse() { --disable-gcrypt) printf "%s" -Dgcrypt=disabled ;; --enable-gettext) printf "%s" -Dgettext=enabled ;; --disable-gettext) printf "%s" -Dgettext=disabled ;; + --enable-gio) printf "%s" -Dgio=enabled ;; + --disable-gio) printf "%s" -Dgio=disabled ;; --enable-glusterfs) printf "%s" -Dglusterfs=enabled ;; --disable-glusterfs) printf "%s" -Dglusterfs=disabled ;; --enable-gnutls) printf "%s" -Dgnutls=enabled ;; @@ -212,26 +279,37 @@ _meson_option_parse() { --disable-gprof) printf "%s" -Dgprof=false ;; --enable-gtk) printf "%s" -Dgtk=enabled ;; --disable-gtk) printf "%s" -Dgtk=disabled ;; + --enable-gtk-clipboard) printf "%s" -Dgtk_clipboard=enabled ;; + --disable-gtk-clipboard) printf "%s" -Dgtk_clipboard=disabled ;; --enable-guest-agent) printf "%s" -Dguest_agent=enabled ;; --disable-guest-agent) printf "%s" -Dguest_agent=disabled ;; --enable-guest-agent-msi) printf "%s" -Dguest_agent_msi=enabled ;; --disable-guest-agent-msi) printf "%s" -Dguest_agent_msi=disabled ;; --enable-hax) printf "%s" -Dhax=enabled ;; --disable-hax) printf "%s" -Dhax=disabled ;; + --enable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=true ;; + --disable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=false ;; --enable-hvf) printf "%s" -Dhvf=enabled ;; --disable-hvf) printf "%s" -Dhvf=disabled ;; + --iasl=*) quote_sh "-Diasl=$2" ;; --enable-iconv) printf "%s" -Diconv=enabled ;; --disable-iconv) printf "%s" -Diconv=disabled ;; + --includedir=*) quote_sh "-Dincludedir=$2" ;; --enable-install-blobs) printf "%s" -Dinstall_blobs=true ;; --disable-install-blobs) printf "%s" -Dinstall_blobs=false ;; + --interp-prefix=*) quote_sh "-Dinterp_prefix=$2" ;; --enable-jack) printf "%s" -Djack=enabled ;; --disable-jack) printf "%s" -Djack=disabled ;; + --enable-keyring) printf "%s" -Dkeyring=enabled ;; + --disable-keyring) printf "%s" -Dkeyring=disabled ;; --enable-kvm) printf "%s" -Dkvm=enabled ;; --disable-kvm) printf "%s" -Dkvm=disabled ;; --enable-l2tpv3) printf "%s" -Dl2tpv3=enabled ;; --disable-l2tpv3) printf "%s" -Dl2tpv3=disabled ;; --enable-libdaxctl) printf "%s" -Dlibdaxctl=enabled ;; --disable-libdaxctl) printf "%s" -Dlibdaxctl=disabled ;; + --libdir=*) quote_sh "-Dlibdir=$2" ;; + --libexecdir=*) quote_sh "-Dlibexecdir=$2" ;; --enable-libiscsi) printf "%s" -Dlibiscsi=enabled ;; --disable-libiscsi) printf "%s" -Dlibiscsi=disabled ;; --enable-libnfs) printf "%s" -Dlibnfs=enabled ;; @@ -244,12 +322,16 @@ _meson_option_parse() { --disable-libudev) printf "%s" -Dlibudev=disabled ;; --enable-libusb) printf "%s" -Dlibusb=enabled ;; --disable-libusb) printf "%s" -Dlibusb=disabled ;; + --enable-libvduse) printf "%s" -Dlibvduse=enabled ;; + --disable-libvduse) printf "%s" -Dlibvduse=disabled ;; --enable-linux-aio) printf "%s" -Dlinux_aio=enabled ;; --disable-linux-aio) printf "%s" -Dlinux_aio=disabled ;; --enable-linux-io-uring) printf "%s" -Dlinux_io_uring=enabled ;; --disable-linux-io-uring) printf "%s" -Dlinux_io_uring=disabled ;; --enable-live-block-migration) printf "%s" -Dlive_block_migration=enabled ;; --disable-live-block-migration) printf "%s" -Dlive_block_migration=disabled ;; + --localedir=*) quote_sh "-Dlocaledir=$2" ;; + --localstatedir=*) quote_sh "-Dlocalstatedir=$2" ;; --enable-lzfse) printf "%s" -Dlzfse=enabled ;; --disable-lzfse) printf "%s" -Dlzfse=disabled ;; --enable-lzo) printf "%s" -Dlzo=enabled ;; @@ -257,8 +339,11 @@ _meson_option_parse() { --enable-malloc=*) quote_sh "-Dmalloc=$2" ;; --enable-malloc-trim) printf "%s" -Dmalloc_trim=enabled ;; --disable-malloc-trim) printf "%s" -Dmalloc_trim=disabled ;; + --mandir=*) quote_sh "-Dmandir=$2" ;; --enable-membarrier) printf "%s" -Dmembarrier=enabled ;; --disable-membarrier) printf "%s" -Dmembarrier=disabled ;; + --enable-module-upgrades) printf "%s" -Dmodule_upgrades=true ;; + --disable-module-upgrades) printf "%s" -Dmodule_upgrades=false ;; --enable-mpath) printf "%s" -Dmpath=enabled ;; --disable-mpath) printf "%s" -Dmpath=disabled ;; --enable-multiprocess) printf "%s" -Dmultiprocess=enabled ;; @@ -271,24 +356,34 @@ _meson_option_parse() { --disable-numa) printf "%s" -Dnuma=disabled ;; --enable-nvmm) printf "%s" -Dnvmm=enabled ;; --disable-nvmm) printf "%s" -Dnvmm=disabled ;; + --enable-opengl) printf "%s" -Dopengl=enabled ;; + --disable-opengl) printf "%s" -Dopengl=disabled ;; --enable-oss) printf "%s" -Doss=enabled ;; --disable-oss) printf "%s" -Doss=disabled ;; --enable-pa) printf "%s" -Dpa=enabled ;; --disable-pa) printf "%s" -Dpa=disabled ;; --enable-parallels) printf "%s" -Dparallels=enabled ;; --disable-parallels) printf "%s" -Dparallels=disabled ;; + --with-pkgversion=*) quote_sh "-Dpkgversion=$2" ;; + --enable-png) printf "%s" -Dpng=enabled ;; + --disable-png) printf "%s" -Dpng=disabled ;; --enable-profiler) printf "%s" -Dprofiler=true ;; --disable-profiler) printf "%s" -Dprofiler=false ;; + --enable-pvrdma) printf "%s" -Dpvrdma=enabled ;; + --disable-pvrdma) printf "%s" -Dpvrdma=disabled ;; --enable-qcow1) printf "%s" -Dqcow1=enabled ;; --disable-qcow1) printf "%s" -Dqcow1=disabled ;; --enable-qed) printf "%s" -Dqed=enabled ;; --disable-qed) printf "%s" -Dqed=disabled ;; + --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$(meson_option_build_array $2)" ;; --enable-qga-vss) printf "%s" -Dqga_vss=enabled ;; --disable-qga-vss) printf "%s" -Dqga_vss=disabled ;; --enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;; --disable-qom-cast-debug) printf "%s" -Dqom_cast_debug=false ;; --enable-rbd) printf "%s" -Drbd=enabled ;; --disable-rbd) printf "%s" -Drbd=disabled ;; + --enable-rdma) printf "%s" -Drdma=enabled ;; + --disable-rdma) printf "%s" -Drdma=disabled ;; --enable-replication) printf "%s" -Dreplication=enabled ;; --disable-replication) printf "%s" -Dreplication=disabled ;; --enable-rng-none) printf "%s" -Drng_none=true ;; @@ -303,30 +398,35 @@ _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" ;; --enable-spice) printf "%s" -Dspice=enabled ;; --disable-spice) printf "%s" -Dspice=disabled ;; --enable-spice-protocol) printf "%s" -Dspice_protocol=enabled ;; --disable-spice-protocol) printf "%s" -Dspice_protocol=disabled ;; --enable-strip) printf "%s" -Dstrip=true ;; --disable-strip) printf "%s" -Dstrip=false ;; + --sysconfdir=*) quote_sh "-Dsysconfdir=$2" ;; --enable-tcg) printf "%s" -Dtcg=enabled ;; --disable-tcg) printf "%s" -Dtcg=disabled ;; --enable-tcg-interpreter) printf "%s" -Dtcg_interpreter=true ;; --disable-tcg-interpreter) printf "%s" -Dtcg_interpreter=false ;; + --tls-priority=*) quote_sh "-Dtls_priority=$2" ;; --enable-tools) printf "%s" -Dtools=enabled ;; --disable-tools) printf "%s" -Dtools=disabled ;; --enable-tpm) printf "%s" -Dtpm=enabled ;; --disable-tpm) printf "%s" -Dtpm=disabled ;; --enable-trace-backends=*) quote_sh "-Dtrace_backends=$2" ;; + --with-trace-file=*) quote_sh "-Dtrace_file=$2" ;; --enable-u2f) printf "%s" -Du2f=enabled ;; --disable-u2f) printf "%s" -Du2f=disabled ;; --enable-usb-redir) printf "%s" -Dusb_redir=enabled ;; @@ -335,20 +435,34 @@ _meson_option_parse() { --disable-vde) printf "%s" -Dvde=disabled ;; --enable-vdi) printf "%s" -Dvdi=enabled ;; --disable-vdi) printf "%s" -Dvdi=disabled ;; + --enable-vduse-blk-export) printf "%s" -Dvduse_blk_export=enabled ;; + --disable-vduse-blk-export) printf "%s" -Dvduse_blk_export=disabled ;; + --enable-vfio-user-server) printf "%s" -Dvfio_user_server=enabled ;; + --disable-vfio-user-server) printf "%s" -Dvfio_user_server=disabled ;; + --enable-vhost-crypto) printf "%s" -Dvhost_crypto=enabled ;; + --disable-vhost-crypto) printf "%s" -Dvhost_crypto=disabled ;; + --enable-vhost-kernel) printf "%s" -Dvhost_kernel=enabled ;; + --disable-vhost-kernel) printf "%s" -Dvhost_kernel=disabled ;; + --enable-vhost-net) printf "%s" -Dvhost_net=enabled ;; + --disable-vhost-net) printf "%s" -Dvhost_net=disabled ;; + --enable-vhost-user) printf "%s" -Dvhost_user=enabled ;; + --disable-vhost-user) printf "%s" -Dvhost_user=disabled ;; --enable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=enabled ;; --disable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=disabled ;; + --enable-vhost-vdpa) printf "%s" -Dvhost_vdpa=enabled ;; + --disable-vhost-vdpa) printf "%s" -Dvhost_vdpa=disabled ;; --enable-virglrenderer) printf "%s" -Dvirglrenderer=enabled ;; --disable-virglrenderer) printf "%s" -Dvirglrenderer=disabled ;; --enable-virtfs) printf "%s" -Dvirtfs=enabled ;; --disable-virtfs) printf "%s" -Dvirtfs=disabled ;; --enable-virtiofsd) printf "%s" -Dvirtiofsd=enabled ;; --disable-virtiofsd) printf "%s" -Dvirtiofsd=disabled ;; + --enable-vmnet) printf "%s" -Dvmnet=enabled ;; + --disable-vmnet) printf "%s" -Dvmnet=disabled ;; --enable-vnc) printf "%s" -Dvnc=enabled ;; --disable-vnc) printf "%s" -Dvnc=disabled ;; --enable-vnc-jpeg) printf "%s" -Dvnc_jpeg=enabled ;; --disable-vnc-jpeg) printf "%s" -Dvnc_jpeg=disabled ;; - --enable-vnc-png) printf "%s" -Dvnc_png=enabled ;; - --disable-vnc-png) printf "%s" -Dvnc_png=disabled ;; --enable-vnc-sasl) printf "%s" -Dvnc_sasl=enabled ;; --disable-vnc-sasl) printf "%s" -Dvnc_sasl=disabled ;; --enable-vte) printf "%s" -Dvte=enabled ;; diff --git a/scripts/modinfo-generate.py b/scripts/modinfo-generate.py index f559eed0077a..b1538fcced77 100755 --- a/scripts/modinfo-generate.py +++ b/scripts/modinfo-generate.py @@ -32,7 +32,7 @@ def parse_line(line): continue return (kind, data) -def generate(name, lines): +def generate(name, lines, enabled): arch = "" objs = [] deps = [] @@ -48,6 +48,14 @@ def generate(name, lines): opts.append(data) elif kind == 'arch': arch = data; + elif kind == 'kconfig': + # don't add a module which dependency is not enabled + # in kconfig + if data.strip() not in enabled: + print(" /* module {} isn't enabled in Kconfig. */" + .format(data.strip())) + print("/* },{ */") + return None else: print("unknown:", kind) exit(1) @@ -58,8 +66,8 @@ def generate(name, lines): print_array("objs", objs) print_array("deps", deps) print_array("opts", opts) - print("},{"); - return deps + print("},{") + return {dep.strip('" ') for dep in deps} def print_pre(): print("/* generated by scripts/modinfo-generate.py */") @@ -72,23 +80,38 @@ def print_post(): print("}};") def main(args): - deps = {} + if len(args) < 3 or args[0] != '--devices': + print('Expected: modinfo-generate.py --devices ' + 'config-device.mak [modinfo files]', file=sys.stderr) + exit(1) + + # get all devices enabled in kconfig, from *-config-device.mak + enabled = set() + with open(args[1]) as file: + for line in file.readlines(): + config = line.split('=') + if config[1].rstrip() == 'y': + enabled.add(config[0][7:]) # remove CONFIG_ + + deps = set() + modules = set() print_pre() - for modinfo in args: + for modinfo in args[2:]: with open(modinfo) as f: lines = f.readlines() print(" /* %s */" % modinfo) - (basename, ext) = os.path.splitext(modinfo) - deps[basename] = generate(basename, lines) + (basename, _) = os.path.splitext(modinfo) + moddeps = generate(basename, lines, enabled) + if moddeps is not None: + modules.add(basename) + deps.update(moddeps) print_post() - flattened_deps = {flat.strip('" ') for dep in deps.values() for flat in dep} error = False - for dep in flattened_deps: - if dep not in deps.keys(): - print("Dependency {} cannot be satisfied".format(dep), - file=sys.stderr) - error = True + for dep in deps.difference(modules): + print("Dependency {} cannot be satisfied".format(dep), + file=sys.stderr) + error = True if error: exit(1) diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index 304634b71ec0..0fe81efbbcec 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -81,12 +81,12 @@ def emit_prolog(suites, prefix): def emit_suite_deps(name, suite, prefix): deps = ' '.join(suite.deps) - targets = f'{prefix}-{name} {prefix}-report-{name}.junit.xml {prefix} {prefix}-report.junit.xml' + targets = [f'{prefix}-{name}', f'{prefix}-report-{name}.junit.xml', f'{prefix}', f'{prefix}-report.junit.xml', + f'{prefix}-build'] print() print(f'.{prefix}-{name}.deps = {deps}') - print(f'ifneq ($(filter {prefix}-build {targets}, $(MAKECMDGOALS)),)') - print(f'.{prefix}.build-suites += {name}') - print(f'endif') + for t in targets: + print(f'.ninja-goals.{t} += $(.{prefix}-{name}.deps)') def emit_suite(name, suite, prefix): emit_suite_deps(name, suite, prefix) diff --git a/scripts/nsis.py b/scripts/nsis.py index 462d6cac3b62..03ed7608a2ca 100644 --- a/scripts/nsis.py +++ b/scripts/nsis.py @@ -18,26 +18,52 @@ def signcode(path): return subprocess.run([cmd, path]) +def find_deps(exe_or_dll, search_path, analyzed_deps): + deps = [exe_or_dll] + output = subprocess.check_output(["objdump", "-p", exe_or_dll], text=True) + output = output.split("\n") + for line in output: + if not line.startswith("\tDLL Name: "): + continue + + dep = line.split("DLL Name: ")[1].strip() + if dep in analyzed_deps: + continue + + dll = os.path.join(search_path, dep) + if not os.path.exists(dll): + # assume it's a Windows provided dll, skip it + continue + + analyzed_deps.add(dep) + # locate the dll dependencies recursively + rdeps = find_deps(dll, search_path, analyzed_deps) + deps.extend(rdeps) + + return deps def main(): parser = argparse.ArgumentParser(description="QEMU NSIS build helper.") parser.add_argument("outfile") parser.add_argument("prefix") parser.add_argument("srcdir") + parser.add_argument("dlldir") parser.add_argument("cpu") parser.add_argument("nsisargs", nargs="*") args = parser.parse_args() + # canonicalize the Windows native prefix path + prefix = os.path.splitdrive(args.prefix)[1] destdir = tempfile.mkdtemp() try: - subprocess.run(["make", "install", "DESTDIR=" + destdir + os.path.sep]) + subprocess.run(["make", "install", "DESTDIR=" + destdir]) with open( - os.path.join(destdir + args.prefix, "system-emulations.nsh"), "w" + os.path.join(destdir + prefix, "system-emulations.nsh"), "w" ) as nsh, open( - os.path.join(destdir + args.prefix, "system-mui-text.nsh"), "w" + os.path.join(destdir + prefix, "system-mui-text.nsh"), "w" ) as muinsh: for exe in sorted(glob.glob( - os.path.join(destdir + args.prefix, "qemu-system-*.exe") + os.path.join(destdir + prefix, "qemu-system-*.exe") )): exe = os.path.basename(exe) arch = exe[12:-4] @@ -61,22 +87,36 @@ def main(): !insertmacro MUI_DESCRIPTION_TEXT ${{Section_{0}}} "{1}" """.format(arch, desc)) - for exe in glob.glob(os.path.join(destdir + args.prefix, "*.exe")): + search_path = args.dlldir + print("Searching '%s' for the dependent dlls ..." % search_path) + dlldir = os.path.join(destdir + prefix, "dll") + os.mkdir(dlldir) + + for exe in glob.glob(os.path.join(destdir + prefix, "*.exe")): signcode(exe) + # find all dll dependencies + deps = set(find_deps(exe, search_path, set())) + deps.remove(exe) + + # copy all dlls to the DLLDIR + for dep in deps: + dllfile = os.path.join(dlldir, os.path.basename(dep)) + if (os.path.exists(dllfile)): + continue + print("Copying '%s' to '%s'" % (dep, dllfile)) + shutil.copy(dep, dllfile) + makensis = [ "makensis", "-V2", "-NOCD", "-DSRCDIR=" + args.srcdir, - "-DBINDIR=" + destdir + args.prefix, + "-DBINDIR=" + destdir + prefix, ] - dlldir = "w32" if args.cpu == "x86_64": - dlldir = "w64" makensis += ["-DW64"] - if os.path.exists(os.path.join(args.srcdir, "dll")): - makensis += ["-DDLLDIR={0}/dll/{1}".format(args.srcdir, dlldir)] + makensis += ["-DDLLDIR=" + dlldir] makensis += ["-DOUTFILE=" + args.outfile] + args.nsisargs subprocess.run(makensis) diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh index 98b56e05210c..3bda0d72c72c 100755 --- a/scripts/oss-fuzz/build.sh +++ b/scripts/oss-fuzz/build.sh @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e # # OSS-Fuzz build script. See: # https://google.github.io/oss-fuzz/getting-started/new-project-guide/#buildsh @@ -64,7 +64,7 @@ mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here # Build once to get the list of dynamic lib paths, and copy them over ../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \ - --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \ + --prefix="/opt/qemu-oss-fuzz" \ --extra-cflags="$EXTRA_CFLAGS" --target-list="i386-softmmu" if ! make "-j$(nproc)" qemu-fuzz-i386; then @@ -81,16 +81,18 @@ if [ "$GITLAB_CI" != "true" ]; then # Build a second time to build the final binary with correct rpath ../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \ - --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \ + --prefix="/opt/qemu-oss-fuzz" \ --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="-Wl,-rpath,\$ORIGIN/lib" \ --target-list="i386-softmmu" make "-j$(nproc)" qemu-fuzz-i386 V=1 fi -# Copy over the datadir -cp -r ../pc-bios/ "$DEST_DIR/pc-bios" +# Place data files in the preinstall tree +make install DESTDIR=$DEST_DIR/qemu-bundle +rm -rf $DEST_DIR/qemu-bundle/opt/qemu-oss-fuzz/bin +rm -rf $DEST_DIR/qemu-bundle/opt/qemu-oss-fuzz/libexec -targets=$(./qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}') +targets=$(./qemu-fuzz-i386 | grep generic-fuzz | awk '$1 ~ /\*/ {print $2}') base_copy="$DEST_DIR/qemu-fuzz-i386-target-$(echo "$targets" | head -n 1)" cp "./qemu-fuzz-i386" "$base_copy" @@ -105,7 +107,7 @@ do # to be configured. We have some generic-fuzz-{pc-q35, floppy, ...} targets # that are thin wrappers around this target that set the required # environment variables according to predefined configs. - if [ "$target" != "generic-fuzz" ]; then + if [[ $target == "generic-fuzz-"* ]]; then ln $base_copy \ "$DEST_DIR/qemu-fuzz-i386-target-$target" fi diff --git a/scripts/oss-fuzz/output_reproducer.py b/scripts/oss-fuzz/output_reproducer.py index 3608b0600e00..e8ef76b34138 100755 --- a/scripts/oss-fuzz/output_reproducer.py +++ b/scripts/oss-fuzz/output_reproducer.py @@ -36,7 +36,7 @@ def c_header(owner): #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" """.format(date=date.today().year, owner=owner) diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 38ca38a7b9dd..79c5e5c3a989 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -64,7 +64,7 @@ def gen_call(name: str, elif arg_type: assert not arg_type.variants for memb in arg_type.members: - if memb.optional: + if memb.need_has(): argstr += 'arg.has_%s, ' % c_name(memb.name) argstr += 'arg.%s, ' % c_name(memb.name) @@ -83,7 +83,7 @@ def gen_call(name: str, trace_qmp_enter_%(name)s(req_json->str); } - ''', +''', upper=upper, name=name) ret += mcgen(''' @@ -124,13 +124,13 @@ def gen_call(name: str, trace_qmp_exit_%(name)s(ret_json->str, true); } - ''', +''', upper=upper, name=name) else: ret += mcgen(''' trace_qmp_exit_%(name)s("{}", true); - ''', +''', name=name) return ret @@ -316,7 +316,6 @@ def _begin_user_module(self, name: str) -> None: #include "qapi/error.h" #include "%(visit)s.h" #include "%(commands)s.h" - ''', commands=commands, visit=visit)) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 489273574aee..737b059e6291 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -114,7 +114,7 @@ def c_name(name: str, protect: bool = True) -> str: 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq']) # namespace pollution: - polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386']) + polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386', 'linux']) name = re.sub(r'[^A-Za-z0-9_]', '_', name) if protect and (name in (c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words) diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 27b44c49f5e9..3cf01e96b689 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -60,7 +60,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str: for memb in typ.members: ret += sep sep = ', ' - if memb.optional: + if memb.need_has(): ret += 'has_' + c_name(memb.name) + sep if memb.type.name == 'str': # Cast away const added in build_params() @@ -196,7 +196,6 @@ def _begin_user_module(self, name: str) -> None: #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp-event.h" - ''', events=events, visit=visit, prefix=self._prefix)) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 3cb389e875c5..5a1782b57eae 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -443,7 +443,7 @@ def check_features(features: Optional[object], check_keys(feat, info, source, ['name'], ['if']) check_name_is_str(feat['name'], info, source) source = "%s '%s'" % (source, feat['name']) - check_name_str(feat['name'], info, source) + check_name_lower(feat['name'], info, source) check_if(feat, info, source) @@ -554,7 +554,7 @@ def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None: check_name_lower(key, info, source) check_keys(value, info, source, ['type'], ['if']) check_if(value, info, source) - check_type(value['type'], info, source) + check_type(value['type'], info, source, allow_array=True) def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None: diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index 113b49134de4..b5a8d03e8ebd 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -121,7 +121,7 @@ def build_params(arg_type: Optional[QAPISchemaObjectType], for memb in arg_type.members: ret += sep sep = ', ' - if memb.optional: + if memb.need_has(): ret += 'bool has_%s, ' % c_name(memb.name) ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name)) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index b7b3fc0ce400..cd8661125cd2 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -243,6 +243,7 @@ def alternate_qtype(self): 'number': 'QTYPE_QNUM', 'int': 'QTYPE_QNUM', 'boolean': 'QTYPE_QBOOL', + 'array': 'QTYPE_QLIST', 'object': 'QTYPE_QDICT' } return json2qtype.get(self.json_type()) @@ -252,6 +253,11 @@ def doc_type(self): return None return self.name + def need_has_if_optional(self): + # When FOO is a pointer, has_FOO == !!FOO, i.e. has_FOO is redundant. + # Except for arrays; see QAPISchemaArrayType.need_has_if_optional(). + return not self.c_type().endswith(POINTER_SUFFIX) + def check(self, schema): QAPISchemaEntity.check(self, schema) for feat in self.features: @@ -351,6 +357,11 @@ def __init__(self, name, info, element_type): self._element_type_name = element_type self.element_type = None + def need_has_if_optional(self): + # When FOO is an array, we still need has_FOO to distinguish + # absent (!has_FOO) from present and empty (has_FOO && !FOO). + return True + def check(self, schema): super().check(schema) self.element_type = schema.resolve_type( @@ -744,6 +755,10 @@ def __init__(self, name, info, typ, optional, ifcond=None, features=None): self.optional = optional self.features = features or [] + def need_has(self): + assert self.type + return self.optional and self.type.need_has_if_optional() + def check(self, schema): assert self.defined_in self.type = schema.resolve_type(self._type_name, self.info, @@ -1069,6 +1084,9 @@ def _def_struct_type(self, expr, info, doc): None)) def _make_variant(self, case, typ, ifcond, info): + if isinstance(typ, list): + assert len(typ) == 1 + typ = self._make_array_type(typ[0], info) return QAPISchemaVariant(case, info, typ, ifcond) def _def_union_type(self, expr, info, doc): diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 477d02700137..c39d054d2cda 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -142,7 +142,7 @@ def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str: ret = '' for memb in members: ret += memb.ifcond.gen_if() - if memb.optional: + if memb.need_has(): ret += mcgen(''' bool has_%(c_name)s; ''', diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 380fa197f589..26a584ee4c22 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -71,6 +71,16 @@ def gen_visit_object_members(name: str, ''', c_name=c_name(name)) + sep = '' + for memb in members: + if memb.optional and not memb.need_has(): + ret += mcgen(''' + bool has_%(c_name)s = !!obj->%(c_name)s; +''', + c_name=c_name(memb.name)) + sep = '\n' + ret += sep + if base: ret += mcgen(''' if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) { @@ -82,10 +92,13 @@ def gen_visit_object_members(name: str, for memb in members: ret += memb.ifcond.gen_if() if memb.optional: + has = 'has_' + c_name(memb.name) + if memb.need_has(): + has = 'obj->' + has ret += mcgen(''' - if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) { + if (visit_optional(v, "%(name)s", &%(has)s)) { ''', - name=memb.name, c_name=c_name(memb.name)) + name=memb.name, has=has) indent.increase() special_features = gen_special_features(memb.features) if special_features != '0': diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 9cb723f44355..6ef9f118d9ff 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -4,7 +4,7 @@ qemu_target_list="i386 i486 alpha arm armeb sparc sparc32plus sparc64 \ ppc ppc64 ppc64le m68k mips mipsel mipsn32 mipsn32el mips64 mips64el \ sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \ -microblaze microblazeel or1k x86_64 hexagon" +microblaze microblazeel or1k x86_64 hexagon loongarch64" i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00' i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' @@ -140,6 +140,10 @@ hexagon_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x hexagon_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' hexagon_family=hexagon +loongarch64_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02\x01' +loongarch64_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' +loongarch64_family=loongarch + qemu_get_family() { cpu=${HOST_ARCH:-$(uname -m)} case "$cpu" in @@ -167,6 +171,9 @@ qemu_get_family() { riscv*) echo "riscv" ;; + loongarch*) + echo "loongarch" + ;; *) echo "$cpu" ;; diff --git a/scripts/qemu-stamp.py b/scripts/qemu-stamp.py new file mode 100644 index 000000000000..7beeeb07eddf --- /dev/null +++ b/scripts/qemu-stamp.py @@ -0,0 +1,24 @@ +#! /usr/bin/env python3 + +# Usage: scripts/qemu-stamp.py STRING1 STRING2... -- FILE1 FILE2... +import hashlib +import os +import sys + +sha = hashlib.sha1() +is_file = False +for arg in sys.argv[1:]: + if arg == '--': + is_file = True + continue + if is_file: + with open(arg, 'rb') as f: + for chunk in iter(lambda: f.read(65536), b''): + sha.update(chunk) + else: + sha.update(os.fsencode(arg)) + sha.update(b'\n') + +# The hash can start with a digit, which the compiler doesn't +# like as an symbol. So prefix it with an underscore +print("_" + sha.hexdigest()) diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 31b19d73e22a..4a20f97db708 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -4,7 +4,7 @@ import os import sys sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) -from qemu.aqmp import qmp_shell +from qemu.qmp import qmp_shell if __name__ == '__main__': diff --git a/scripts/qmp/qmp-shell-wrap b/scripts/qmp/qmp-shell-wrap index 66846e36d1fd..9e94da114f5f 100755 --- a/scripts/qmp/qmp-shell-wrap +++ b/scripts/qmp/qmp-shell-wrap @@ -4,7 +4,7 @@ import os import sys sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) -from qemu.aqmp import qmp_shell +from qemu.qmp import qmp_shell if __name__ == '__main__': diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py index b33fb70d5ee9..8f731a5cfe17 100755 --- a/scripts/render_block_graph.py +++ b/scripts/render_block_graph.py @@ -25,8 +25,8 @@ from graphviz import Digraph sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python')) -from qemu.aqmp import QMPError -from qemu.aqmp.legacy import QEMUMonitorProtocol +from qemu.qmp import QMPError +from qemu.qmp.legacy import QEMUMonitorProtocol def perm(arr): diff --git a/scripts/simplebench/bench_block_job.py b/scripts/simplebench/bench_block_job.py index a403c35b08f6..56191db44b21 100755 --- a/scripts/simplebench/bench_block_job.py +++ b/scripts/simplebench/bench_block_job.py @@ -27,8 +27,7 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine -from qemu.qmp import QMPConnectError -from qemu.aqmp import ConnectError +from qemu.qmp import ConnectError def bench_block_job(cmd, cmd_args, qemu_args): @@ -50,7 +49,7 @@ def bench_block_job(cmd, cmd_args, qemu_args): vm.launch() except OSError as e: return {'error': 'popen failed: ' + str(e)} - except (QMPConnectError, ConnectError, socket.timeout): + except (ConnectError, socket.timeout): return {'error': 'qemu failed: ' + str(vm.get_log())} try: diff --git a/scripts/symlink-install-tree.py b/scripts/symlink-install-tree.py new file mode 100644 index 000000000000..67cb86dd523a --- /dev/null +++ b/scripts/symlink-install-tree.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +from pathlib import PurePath +import errno +import json +import os +import subprocess +import sys + +def destdir_join(d1: str, d2: str) -> str: + if not d1: + return d2 + # c:\destdir + c:\prefix must produce c:\destdir\prefix + return str(PurePath(d1, *PurePath(d2).parts[1:])) + +introspect = os.environ.get('MESONINTROSPECT') +out = subprocess.run([*introspect.split(' '), '--installed'], + stdout=subprocess.PIPE, check=True).stdout +for source, dest in json.loads(out).items(): + bundle_dest = destdir_join('qemu-bundle', dest) + path = os.path.dirname(bundle_dest) + try: + os.makedirs(path, exist_ok=True) + except BaseException as e: + print(f'error making directory {path}', file=sys.stderr) + raise e + try: + os.symlink(source, bundle_dest) + except BaseException as e: + if not isinstance(e, OSError) or e.errno != errno.EEXIST: + print(f'error making symbolic link {dest}', file=sys.stderr) + raise e diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 839a5ec6149b..b1ad99cba824 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -161,7 +161,7 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \ - psci.h psp-sev.h userfaultfd.h mman.h; do + psci.h psp-sev.h userfaultfd.h mman.h vduse.h; do cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" done diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py index 539ead62b498..dfeee8231a8a 100755 --- a/scripts/vmstate-static-checker.py +++ b/scripts/vmstate-static-checker.py @@ -40,7 +40,7 @@ def check_fields_match(name, s_field, d_field): return True # Some fields changed names between qemu versions. This list - # is used to whitelist such changes in each section / description. + # is used to allow such changes in each section / description. changed_names = { 'apic': ['timer', 'timer_expiry'], 'e1000': ['dev', 'parent_obj'], @@ -367,7 +367,6 @@ def check_machine_type(s, d): if s["Name"] != d["Name"]: print("Warning: checking incompatible machine types:", end=' ') print("\"" + s["Name"] + "\", \"" + d["Name"] + "\"") - return def main(): diff --git a/scripts/xen-detect.c b/scripts/xen-detect.c new file mode 100644 index 000000000000..85e8206490e7 --- /dev/null +++ b/scripts/xen-detect.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Test programs for various Xen versions that QEMU supports. */ +#if CONFIG_XEN_CTRL_INTERFACE_VERSION == 41100 + #undef XC_WANT_COMPAT_DEVICEMODEL_API + #define __XEN_TOOLS__ + #include + #include + int main(void) { + xendevicemodel_handle *xd; + xenforeignmemory_handle *xfmem; + + xd = xendevicemodel_open(0, 0); + xendevicemodel_pin_memory_cacheattr(xd, 0, 0, 0, 0); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map_resource(xfmem, 0, 0, 0, 0, 0, NULL, 0, 0); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 41000 + #undef XC_WANT_COMPAT_MAP_FOREIGN_API + #include + #include + int main(void) { + xenforeignmemory_handle *xfmem; + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map2(xfmem, 0, 0, 0, 0, 0, 0, 0); + xentoolcore_restrict_all(0); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40900 + #undef XC_WANT_COMPAT_DEVICEMODEL_API + #define __XEN_TOOLS__ + #include + int main(void) { + xendevicemodel_handle *xd; + + xd = xendevicemodel_open(0, 0); + xendevicemodel_close(xd); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40800 + /* + * If we have stable libs the we don't want the libxc compat + * layers, regardless of what CFLAGS we may have been given. + * + * Also, check if xengnttab_grant_copy_segment_t is defined and + * grant copy operation is implemented. + */ + #undef XC_WANT_COMPAT_EVTCHN_API + #undef XC_WANT_COMPAT_GNTTAB_API + #undef XC_WANT_COMPAT_MAP_FOREIGN_API + #include + #include + #include + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc = NULL; + xenforeignmemory_handle *xfmem; + xenevtchn_handle *xe; + xengnttab_handle *xg; + xengnttab_grant_copy_segment_t* seg = NULL; + + xs_daemon_open(); + + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); + + xe = xenevtchn_open(0, 0); + xenevtchn_fd(xe); + + xg = xengnttab_open(0, 0); + xengnttab_grant_copy(xg, 0, seg); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40701 + /* + * If we have stable libs the we don't want the libxc compat + * layers, regardless of what CFLAGS we may have been given. + */ + #undef XC_WANT_COMPAT_EVTCHN_API + #undef XC_WANT_COMPAT_GNTTAB_API + #undef XC_WANT_COMPAT_MAP_FOREIGN_API + #include + #include + #include + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc = NULL; + xenforeignmemory_handle *xfmem; + xenevtchn_handle *xe; + xengnttab_handle *xg; + + xs_daemon_open(); + + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); + + xe = xenevtchn_open(0, 0); + xenevtchn_fd(xe); + + xg = xengnttab_open(0, 0); + xengnttab_map_grant_ref(xg, 0, 0, 0); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40600 + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + xc_reserved_device_memory_map(xc, 0, 0, 0, 0, NULL, 0); + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40500 + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, 0, NULL); + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40200 + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + return 0; + } + +#else +#error invalid CONFIG_XEN_CTRL_INTERFACE_VERSION +#endif diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c index 451c7631b76f..3be52a98d580 100644 --- a/scsi/pr-manager-helper.c +++ b/scsi/pr-manager-helper.c @@ -77,7 +77,7 @@ static int pr_manager_helper_write(PRManagerHelper *pr_mgr, iov.iov_base = (void *)buf; iov.iov_len = sz; n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1, - nfds ? &fd : NULL, nfds, errp); + nfds ? &fd : NULL, nfds, 0, errp); if (n_written <= 0) { assert(n_written != QIO_CHANNEL_ERR_BLOCK); diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index f281daeced8d..196b78c00df5 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -36,7 +36,7 @@ #include #endif -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/main-loop.h" @@ -77,8 +77,10 @@ static int gid = -1; static void compute_default_paths(void) { - socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); - pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid"); + g_autofree char *state = qemu_get_local_state_dir(); + + socket_path = g_build_filename(state, "run", "qemu-pr-helper.sock", NULL); + pidfile = g_build_filename(state, "run", "qemu-pr-helper.pid", NULL); } static void usage(const char *name) @@ -1001,7 +1003,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } trace_init_file(); - qemu_set_log(LOG_TRACE); + qemu_set_log(LOG_TRACE, &error_fatal); #ifdef CONFIG_MPATH dm_init(); diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 7a51fd0737d1..62d8bae97f0e 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 @@ -32,12 +32,14 @@ */ #include "qemu/osdep.h" - +#include "qemu/timer.h" +#include "exec/gdbstub.h" #include "semihosting/semihost.h" #include "semihosting/console.h" #include "semihosting/common-semi.h" -#include "qemu/timer.h" -#include "exec/gdbstub.h" +#include "semihosting/guestfd.h" +#include "semihosting/syscalls.h" + #ifdef CONFIG_USER_ONLY #include "qemu.h" @@ -45,9 +47,6 @@ #else #include "qemu/cutils.h" #include "hw/loader.h" -#ifdef TARGET_ARM -#include "hw/arm/boot.h" -#endif #include "hw/boards.h" #endif @@ -85,65 +84,21 @@ #define O_BINARY 0 #endif -#define GDB_O_RDONLY 0x000 -#define GDB_O_WRONLY 0x001 -#define GDB_O_RDWR 0x002 -#define GDB_O_APPEND 0x008 -#define GDB_O_CREAT 0x200 -#define GDB_O_TRUNC 0x400 -#define GDB_O_BINARY 0 - static int gdb_open_modeflags[12] = { GDB_O_RDONLY, - GDB_O_RDONLY | GDB_O_BINARY, + GDB_O_RDONLY, GDB_O_RDWR, - GDB_O_RDWR | GDB_O_BINARY, + GDB_O_RDWR, + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, - GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY, GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, - GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY, + GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, - GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY, GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, - GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY -}; - -static int open_modeflags[12] = { - O_RDONLY, - O_RDONLY | O_BINARY, - O_RDWR, - O_RDWR | O_BINARY, - O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, - O_WRONLY | O_CREAT | O_APPEND, - O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY + GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, }; -typedef enum GuestFDType { - GuestFDUnused = 0, - GuestFDHost = 1, - GuestFDGDB = 2, - GuestFDFeatureFile = 3, -} GuestFDType; - -/* - * Guest file descriptors are integer indexes into an array of - * these structures (we will dynamically resize as necessary). - */ -typedef struct GuestFD { - GuestFDType type; - union { - int hostfd; - target_ulong featurefile_offset; - }; -} GuestFD; - -static GArray *guestfd_array; - #ifndef CONFIG_USER_ONLY /** @@ -210,155 +165,37 @@ static LayoutInfo common_semi_find_bases(CPUState *cs) #endif -#ifdef TARGET_ARM -static inline target_ulong -common_semi_arg(CPUState *cs, int argno) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - if (is_a64(env)) { - return env->xregs[argno]; - } else { - return env->regs[argno]; - } -} - -static inline void -common_semi_set_ret(CPUState *cs, target_ulong ret) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - if (is_a64(env)) { - env->xregs[0] = ret; - } else { - env->regs[0] = ret; - } -} - -static inline bool -common_semi_sys_exit_extended(CPUState *cs, int nr) -{ - return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr)); -} - -#endif /* TARGET_ARM */ - -#ifdef TARGET_RISCV -static inline target_ulong -common_semi_arg(CPUState *cs, int argno) -{ - RISCVCPU *cpu = RISCV_CPU(cs); - CPURISCVState *env = &cpu->env; - return env->gpr[xA0 + argno]; -} - -static inline void -common_semi_set_ret(CPUState *cs, target_ulong ret) -{ - RISCVCPU *cpu = RISCV_CPU(cs); - CPURISCVState *env = &cpu->env; - env->gpr[xA0] = ret; -} - -static inline bool -common_semi_sys_exit_extended(CPUState *cs, int nr) -{ - return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8); -} - -#endif - -/* - * Allocate a new guest file descriptor and return it; if we - * couldn't allocate a new fd then return -1. - * This is a fairly simplistic implementation because we don't - * expect that most semihosting guest programs will make very - * heavy use of opening and closing fds. - */ -static int alloc_guestfd(void) -{ - guint i; - - if (!guestfd_array) { - /* New entries zero-initialized, i.e. type GuestFDUnused */ - guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD)); - } - - /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */ - for (i = 1; i < guestfd_array->len; i++) { - GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i); - - if (gf->type == GuestFDUnused) { - return i; - } - } - - /* All elements already in use: expand the array */ - g_array_set_size(guestfd_array, i + 1); - return i; -} - -/* - * Look up the guestfd in the data structure; return NULL - * for out of bounds, but don't check whether the slot is unused. - * This is used internally by the other guestfd functions. - */ -static GuestFD *do_get_guestfd(int guestfd) -{ - if (!guestfd_array) { - return NULL; - } - - if (guestfd <= 0 || guestfd >= guestfd_array->len) { - return NULL; - } - - return &g_array_index(guestfd_array, GuestFD, guestfd); -} - -/* - * Associate the specified guest fd (which must have been - * allocated via alloc_fd() and not previously used) with - * the specified host/gdb fd. - */ -static void associate_guestfd(int guestfd, int hostfd) -{ - GuestFD *gf = do_get_guestfd(guestfd); - - assert(gf); - gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost; - gf->hostfd = hostfd; -} +#include "common-semi-target.h" /* - * Deallocate the specified guest file descriptor. This doesn't - * close the host fd, it merely undoes the work of alloc_fd(). + * 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. */ -static void dealloc_guestfd(int guestfd) -{ - GuestFD *gf = do_get_guestfd(guestfd); - assert(gf); - gf->type = GuestFDUnused; -} +#define GET_ARG(n) do { \ + if (is_64bit_semihosting(env)) { \ + if (get_user_u64(arg ## n, args + (n) * 8)) { \ + goto do_fault; \ + } \ + } else { \ + if (get_user_u32(arg ## n, args + (n) * 4)) { \ + goto do_fault; \ + } \ + } \ +} while (0) -/* - * Given a guest file descriptor, get the associated struct. - * If the fd is not valid, return NULL. This is the function - * used by the various semihosting calls to validate a handle - * from the guest. - * Note: calling alloc_guestfd() or dealloc_guestfd() will - * invalidate any GuestFD* obtained by calling this function. - */ -static GuestFD *get_guestfd(int guestfd) -{ - GuestFD *gf = do_get_guestfd(guestfd); +#define SET_ARG(n, val) \ + (is_64bit_semihosting(env) ? \ + put_user_u64(val, args + (n) * 8) : \ + put_user_u32(val, args + (n) * 4)) - if (!gf || gf->type == GuestFDUnused) { - return NULL; - } - return gf; -} /* * The semihosting API has no concept of its errno being thread-safe, @@ -370,22 +207,8 @@ static GuestFD *get_guestfd(int guestfd) #ifndef CONFIG_USER_ONLY static target_ulong syscall_err; -#include "exec/softmmu-semi.h" -#endif - -static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code) -{ - if (code == (uint32_t)-1) { -#ifdef CONFIG_USER_ONLY - TaskState *ts = cs->opaque; - - ts->swi_errno = errno; -#else - syscall_err = errno; +#include "semihosting/softmmu-uaccess.h" #endif - } - return code; -} static inline uint32_t get_swi_errno(CPUState *cs) { @@ -398,254 +221,116 @@ static inline uint32_t get_swi_errno(CPUState *cs) #endif } -static target_ulong common_semi_syscall_len; - -static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err) -{ - target_ulong reg0 = common_semi_arg(cs, 0); - - if (ret == (target_ulong)-1) { - errno = err; - set_swi_errno(cs, -1); - reg0 = ret; - } else { - /* Fixup syscalls that use nonstardard return conventions. */ - switch (reg0) { - case TARGET_SYS_WRITE: - case TARGET_SYS_READ: - reg0 = common_semi_syscall_len - ret; - break; - case TARGET_SYS_SEEK: - reg0 = 0; - break; - default: - reg0 = ret; - break; - } - } - common_semi_set_ret(cs, reg0); -} - -static target_ulong common_semi_flen_buf(CPUState *cs) +static void common_semi_cb(CPUState *cs, uint64_t ret, int err) { - target_ulong sp; -#ifdef TARGET_ARM - /* Return an address in target memory of 64 bytes where the remote - * gdb should write its stat struct. (The format of this structure - * is defined by GDB's remote protocol and is not target-specific.) - * We put this on the guest's stack just below SP. - */ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - - if (is_a64(env)) { - sp = env->xregs[31]; - } else { - sp = env->regs[13]; - } -#endif -#ifdef TARGET_RISCV - RISCVCPU *cpu = RISCV_CPU(cs); - CPURISCVState *env = &cpu->env; - - sp = env->gpr[xSP]; + if (err) { +#ifdef CONFIG_USER_ONLY + TaskState *ts = cs->opaque; + ts->swi_errno = err; +#else + syscall_err = err; #endif - - return sp - 64; -} - -static void -common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err) -{ - /* The size is always stored in big-endian order, extract - the value. We assume the size always fit in 32 bits. */ - uint32_t size; - cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32, - (uint8_t *)&size, 4, 0); - size = be32_to_cpu(size); - common_semi_set_ret(cs, size); - errno = err; - set_swi_errno(cs, -1); -} - -static int common_semi_open_guestfd; - -static void -common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err) -{ - if (ret == (target_ulong)-1) { - errno = err; - set_swi_errno(cs, -1); - dealloc_guestfd(common_semi_open_guestfd); - } else { - associate_guestfd(common_semi_open_guestfd, ret); - ret = common_semi_open_guestfd; } common_semi_set_ret(cs, ret); } -static target_ulong -common_semi_gdb_syscall(CPUState *cs, gdb_syscall_complete_cb cb, - const char *fmt, ...) +/* + * Use 0xdeadbeef as the return value when there isn't a defined + * return value for the call. + */ +static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err) { - va_list va; - - va_start(va, fmt); - gdb_do_syscallv(cb, fmt, va); - va_end(va); - - /* - * FIXME: in softmmu mode, the gdbstub will schedule our callback - * to occur, but will not actually call it to complete the syscall - * until after this function has returned and we are back in the - * CPU main loop. Therefore callers to this function must not - * do anything with its return value, because it is not necessarily - * the result of the syscall, but could just be the old value of X0. - * The only thing safe to do with this is that the callers of - * do_common_semihosting() will write it straight back into X0. - * (In linux-user mode, the callback will have happened before - * gdb_do_syscallv() returns.) - * - * We should tidy this up so neither this function nor - * do_common_semihosting() return a value, so the mistake of - * doing something with the return value is not possible to make. - */ - - return common_semi_arg(cs, 0); + common_semi_set_ret(cs, 0xdeadbeef); } /* - * Types for functions implementing various semihosting calls - * for specific types of guest file descriptor. These must all - * do the work and return the required return value for the guest, - * setting the guest errno if appropriate. + * SYS_READ and SYS_WRITE always return the number of bytes not read/written. + * There is no error condition, other than returning the original length. */ -typedef uint32_t sys_closefn(CPUState *cs, GuestFD *gf); -typedef uint32_t sys_writefn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len); -typedef uint32_t sys_readfn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len); -typedef uint32_t sys_isattyfn(CPUState *cs, GuestFD *gf); -typedef uint32_t sys_seekfn(CPUState *cs, GuestFD *gf, - target_ulong offset); -typedef uint32_t sys_flenfn(CPUState *cs, GuestFD *gf); - -static uint32_t host_closefn(CPUState *cs, GuestFD *gf) +static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err) { - /* - * Only close the underlying host fd if it's one we opened on behalf - * of the guest in SYS_OPEN. - */ - if (gf->hostfd == STDIN_FILENO || - gf->hostfd == STDOUT_FILENO || - gf->hostfd == STDERR_FILENO) { - return 0; + /* Recover the original length from the third argument. */ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + target_ulong args = common_semi_arg(cs, 1); + target_ulong arg2; + GET_ARG(2); + + if (err) { + do_fault: + ret = 0; /* error: no bytes transmitted */ } - return set_swi_errno(cs, close(gf->hostfd)); + common_semi_set_ret(cs, arg2 - ret); } -static uint32_t host_writefn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len) +/* + * Convert from Posix ret+errno to Arm SYS_ISTTY return values. + * With gdbstub, err is only ever set for protocol errors to EIO. + */ +static void common_semi_istty_cb(CPUState *cs, uint64_t ret, int err) { - CPUArchState *env = cs->env_ptr; - uint32_t ret; - char *s = lock_user(VERIFY_READ, buf, len, 1); - (void) env; /* Used in arm softmmu lock_user implicitly */ - if (!s) { - /* Return bytes not written on error */ - return len; + if (err) { + ret = (err == ENOTTY ? 0 : -1); } - ret = set_swi_errno(cs, write(gf->hostfd, s, len)); - unlock_user(s, buf, 0); - if (ret == (uint32_t)-1) { - ret = 0; - } - /* Return bytes not written */ - return len - ret; + common_semi_cb(cs, ret, err); } -static uint32_t host_readfn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len) +/* + * SYS_SEEK returns 0 on success, not the resulting offset. + */ +static void common_semi_seek_cb(CPUState *cs, uint64_t ret, int err) { - CPUArchState *env = cs->env_ptr; - uint32_t ret; - char *s = lock_user(VERIFY_WRITE, buf, len, 0); - (void) env; /* Used in arm softmmu lock_user implicitly */ - if (!s) { - /* return bytes not read */ - return len; - } - do { - ret = set_swi_errno(cs, read(gf->hostfd, s, len)); - } while (ret == -1 && errno == EINTR); - unlock_user(s, buf, len); - if (ret == (uint32_t)-1) { + if (!err) { ret = 0; } - /* Return bytes not read */ - return len - ret; -} - -static uint32_t host_isattyfn(CPUState *cs, GuestFD *gf) -{ - return isatty(gf->hostfd); + common_semi_cb(cs, ret, err); } -static uint32_t host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset) +/* + * Return an address in target memory of 64 bytes where the remote + * gdb should write its stat struct. (The format of this structure + * is defined by GDB's remote protocol and is not target-specific.) + * We put this on the guest's stack just below SP. + */ +static target_ulong common_semi_flen_buf(CPUState *cs) { - uint32_t ret = set_swi_errno(cs, lseek(gf->hostfd, offset, SEEK_SET)); - if (ret == (uint32_t)-1) { - return -1; - } - return 0; + target_ulong sp = common_semi_stack_bottom(cs); + return sp - 64; } -static uint32_t host_flenfn(CPUState *cs, GuestFD *gf) -{ - struct stat buf; - uint32_t ret = set_swi_errno(cs, fstat(gf->hostfd, &buf)); - if (ret == (uint32_t)-1) { - return -1; +static void +common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err) +{ + if (!err) { + /* The size is always stored in big-endian order, extract the value. */ + uint64_t size; + if (cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + + offsetof(struct gdb_stat, gdb_st_size), + &size, 8, 0)) { + ret = -1, err = EFAULT; + } else { + size = be64_to_cpu(size); + if (ret != size) { + ret = -1, err = EOVERFLOW; + } + } } - return buf.st_size; -} - -static uint32_t gdb_closefn(CPUState *cs, GuestFD *gf) -{ - return common_semi_gdb_syscall(cs, common_semi_cb, "close,%x", gf->hostfd); -} - -static uint32_t gdb_writefn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len) -{ - common_semi_syscall_len = len; - return common_semi_gdb_syscall(cs, common_semi_cb, "write,%x,%x,%x", - gf->hostfd, buf, len); + common_semi_cb(cs, ret, err); } -static uint32_t gdb_readfn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len) -{ - common_semi_syscall_len = len; - return common_semi_gdb_syscall(cs, common_semi_cb, "read,%x,%x,%x", - gf->hostfd, buf, len); -} - -static uint32_t gdb_isattyfn(CPUState *cs, GuestFD *gf) -{ - return common_semi_gdb_syscall(cs, common_semi_cb, "isatty,%x", gf->hostfd); -} - -static uint32_t gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset) +static void +common_semi_readc_cb(CPUState *cs, uint64_t ret, int err) { - return common_semi_gdb_syscall(cs, common_semi_cb, "lseek,%x,%x,0", - gf->hostfd, offset); -} + if (!err) { + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + uint8_t ch; -static uint32_t gdb_flenfn(CPUState *cs, GuestFD *gf) -{ - return common_semi_gdb_syscall(cs, common_semi_flen_cb, "fstat,%x,%x", - gf->hostfd, common_semi_flen_buf(cs)); + if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) { + ret = -1, err = EFAULT; + } else { + ret = ch; + } + } + common_semi_cb(cs, ret, err); } #define SHFB_MAGIC_0 0x53 @@ -665,157 +350,15 @@ static const uint8_t featurefile_data[] = { SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */ }; -static void init_featurefile_guestfd(int guestfd) -{ - GuestFD *gf = do_get_guestfd(guestfd); - - assert(gf); - gf->type = GuestFDFeatureFile; - gf->featurefile_offset = 0; -} - -static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf) -{ - /* Nothing to do */ - return 0; -} - -static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len) -{ - /* This fd can never be open for writing */ - - errno = EBADF; - return set_swi_errno(cs, -1); -} - -static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf, - target_ulong buf, uint32_t len) -{ - CPUArchState *env = cs->env_ptr; - uint32_t i; - char *s; - - (void) env; /* Used in arm softmmu lock_user implicitly */ - s = lock_user(VERIFY_WRITE, buf, len, 0); - if (!s) { - return len; - } - - for (i = 0; i < len; i++) { - if (gf->featurefile_offset >= sizeof(featurefile_data)) { - break; - } - s[i] = featurefile_data[gf->featurefile_offset]; - gf->featurefile_offset++; - } - - unlock_user(s, buf, len); - - /* Return number of bytes not read */ - return len - i; -} - -static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf) -{ - return 0; -} - -static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf, - target_ulong offset) -{ - gf->featurefile_offset = offset; - return 0; -} - -static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf) -{ - return sizeof(featurefile_data); -} - -typedef struct GuestFDFunctions { - sys_closefn *closefn; - sys_writefn *writefn; - sys_readfn *readfn; - sys_isattyfn *isattyfn; - sys_seekfn *seekfn; - sys_flenfn *flenfn; -} GuestFDFunctions; - -static const GuestFDFunctions guestfd_fns[] = { - [GuestFDHost] = { - .closefn = host_closefn, - .writefn = host_writefn, - .readfn = host_readfn, - .isattyfn = host_isattyfn, - .seekfn = host_seekfn, - .flenfn = host_flenfn, - }, - [GuestFDGDB] = { - .closefn = gdb_closefn, - .writefn = gdb_writefn, - .readfn = gdb_readfn, - .isattyfn = gdb_isattyfn, - .seekfn = gdb_seekfn, - .flenfn = gdb_flenfn, - }, - [GuestFDFeatureFile] = { - .closefn = featurefile_closefn, - .writefn = featurefile_writefn, - .readfn = featurefile_readfn, - .isattyfn = featurefile_isattyfn, - .seekfn = featurefile_seekfn, - .flenfn = featurefile_flenfn, - }, -}; - -/* - * 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. - */ -static inline bool is_64bit_semihosting(CPUArchState *env) -{ -#if defined(TARGET_ARM) - return is_a64(env); -#elif defined(TARGET_RISCV) - return riscv_cpu_mxl(env) != MXL_RV32; -#else -#error un-handled architecture -#endif -} - - -#define GET_ARG(n) do { \ - if (is_64bit_semihosting(env)) { \ - if (get_user_u64(arg ## n, args + (n) * 8)) { \ - errno = EFAULT; \ - return set_swi_errno(cs, -1); \ - } \ - } else { \ - if (get_user_u32(arg ## n, args + (n) * 4)) { \ - errno = EFAULT; \ - return set_swi_errno(cs, -1); \ - } \ - } \ -} while (0) - -#define SET_ARG(n, val) \ - (is_64bit_semihosting(env) ? \ - put_user_u64(val, args + (n) * 8) : \ - put_user_u32(val, args + (n) * 4)) - - /* * Do a semihosting call. * * The specification always says that the "return register" either * returns a specific value or is corrupted, so we don't need to * report to our caller whether we are returning a value or trying to - * leave the register unchanged. We use 0xdeadbeef as the return value - * when there isn't a defined return value for the call. + * leave the register unchanged. */ -target_ulong do_common_semihosting(CPUState *cs) +void do_common_semihosting(CPUState *cs) { CPUArchState *env = cs->env_ptr; target_ulong args; @@ -824,43 +367,31 @@ target_ulong do_common_semihosting(CPUState *cs) char * s; int nr; uint32_t ret; - uint32_t len; - GuestFD *gf; int64_t elapsed; - (void) env; /* Used implicitly by arm lock_user macro */ nr = common_semi_arg(cs, 0) & 0xffffffffU; args = common_semi_arg(cs, 1); switch (nr) { case TARGET_SYS_OPEN: { - int guestfd; + int ret, err = 0; + int hostfd; GET_ARG(0); GET_ARG(1); GET_ARG(2); s = lock_user_string(arg0); if (!s) { - errno = EFAULT; - return set_swi_errno(cs, -1); + goto do_fault; } if (arg1 >= 12) { unlock_user(s, arg0, 0); - errno = EINVAL; - return set_swi_errno(cs, -1); - } - - guestfd = alloc_guestfd(); - if (guestfd < 0) { - unlock_user(s, arg0, 0); - errno = EMFILE; - return set_swi_errno(cs, -1); + common_semi_cb(cs, -1, EINVAL); + break; } if (strcmp(s, ":tt") == 0) { - int result_fileno; - /* * We implement SH_EXT_STDOUT_STDERR, so: * open for read == stdin @@ -868,206 +399,170 @@ target_ulong do_common_semihosting(CPUState *cs) * open for append == stderr */ if (arg1 < 4) { - result_fileno = STDIN_FILENO; + hostfd = STDIN_FILENO; } else if (arg1 < 8) { - result_fileno = STDOUT_FILENO; + hostfd = STDOUT_FILENO; } else { - result_fileno = STDERR_FILENO; + hostfd = STDERR_FILENO; } - associate_guestfd(guestfd, result_fileno); - unlock_user(s, arg0, 0); - return guestfd; - } - if (strcmp(s, ":semihosting-features") == 0) { - unlock_user(s, arg0, 0); + ret = alloc_guestfd(); + associate_guestfd(ret, hostfd); + } else if (strcmp(s, ":semihosting-features") == 0) { /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ if (arg1 != 0 && arg1 != 1) { - dealloc_guestfd(guestfd); - errno = EACCES; - return set_swi_errno(cs, -1); - } - init_featurefile_guestfd(guestfd); - return guestfd; - } - - if (use_gdb_syscalls()) { - common_semi_open_guestfd = guestfd; - ret = common_semi_gdb_syscall(cs, common_semi_open_cb, - "open,%s,%x,1a4", arg0, (int)arg2 + 1, - gdb_open_modeflags[arg1]); - } else { - ret = set_swi_errno(cs, open(s, open_modeflags[arg1], 0644)); - if (ret == (uint32_t)-1) { - dealloc_guestfd(guestfd); + ret = -1; + err = EACCES; } else { - associate_guestfd(guestfd, ret); - ret = guestfd; + ret = alloc_guestfd(); + staticfile_guestfd(ret, featurefile_data, + sizeof(featurefile_data)); } + } else { + unlock_user(s, arg0, 0); + semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1, + gdb_open_modeflags[arg1], 0644); + break; } unlock_user(s, arg0, 0); - return ret; + common_semi_cb(cs, ret, err); + break; } + case TARGET_SYS_CLOSE: GET_ARG(0); + semihost_sys_close(cs, common_semi_cb, arg0); + break; - gf = get_guestfd(arg0); - if (!gf) { - errno = EBADF; - return set_swi_errno(cs, -1); - } - - ret = guestfd_fns[gf->type].closefn(cs, gf); - dealloc_guestfd(arg0); - return ret; case TARGET_SYS_WRITEC: - qemu_semihosting_console_outc(cs->env_ptr, args); - return 0xdeadbeef; + /* + * FIXME: the byte to be written is in a target_ulong slot, + * which means this is wrong for a big-endian guest. + */ + semihost_sys_write_gf(cs, common_semi_dead_cb, + &console_out_gf, args, 1); + break; + case TARGET_SYS_WRITE0: - return qemu_semihosting_console_outs(cs->env_ptr, args); + { + ssize_t len = target_strlen(args); + if (len < 0) { + common_semi_dead_cb(cs, -1, EFAULT); + } else { + semihost_sys_write_gf(cs, common_semi_dead_cb, + &console_out_gf, args, len); + } + } + break; + case TARGET_SYS_WRITE: GET_ARG(0); GET_ARG(1); GET_ARG(2); - len = arg2; + semihost_sys_write(cs, common_semi_rw_cb, arg0, arg1, arg2); + break; - gf = get_guestfd(arg0); - if (!gf) { - errno = EBADF; - return set_swi_errno(cs, -1); - } - - return guestfd_fns[gf->type].writefn(cs, gf, arg1, len); case TARGET_SYS_READ: GET_ARG(0); GET_ARG(1); GET_ARG(2); - len = arg2; + semihost_sys_read(cs, common_semi_rw_cb, arg0, arg1, arg2); + break; - gf = get_guestfd(arg0); - if (!gf) { - errno = EBADF; - return set_swi_errno(cs, -1); - } - - return guestfd_fns[gf->type].readfn(cs, gf, arg1, len); case TARGET_SYS_READC: - return qemu_semihosting_console_inc(cs->env_ptr); + semihost_sys_read_gf(cs, common_semi_readc_cb, &console_in_gf, + common_semi_stack_bottom(cs) - 1, 1); + break; + case TARGET_SYS_ISERROR: GET_ARG(0); - return (target_long) arg0 < 0 ? 1 : 0; + common_semi_set_ret(cs, (target_long)arg0 < 0); + break; + case TARGET_SYS_ISTTY: GET_ARG(0); + semihost_sys_isatty(cs, common_semi_istty_cb, arg0); + break; - gf = get_guestfd(arg0); - if (!gf) { - errno = EBADF; - return set_swi_errno(cs, -1); - } - - return guestfd_fns[gf->type].isattyfn(cs, gf); case TARGET_SYS_SEEK: GET_ARG(0); GET_ARG(1); + semihost_sys_lseek(cs, common_semi_seek_cb, arg0, arg1, GDB_SEEK_SET); + break; - gf = get_guestfd(arg0); - if (!gf) { - errno = EBADF; - return set_swi_errno(cs, -1); - } - - return guestfd_fns[gf->type].seekfn(cs, gf, arg1); case TARGET_SYS_FLEN: GET_ARG(0); + semihost_sys_flen(cs, common_semi_flen_fstat_cb, common_semi_cb, + arg0, common_semi_flen_buf(cs)); + break; - gf = get_guestfd(arg0); - if (!gf) { - errno = EBADF; - return set_swi_errno(cs, -1); - } - - return guestfd_fns[gf->type].flenfn(cs, gf); case TARGET_SYS_TMPNAM: + { + int len; + char *p; + GET_ARG(0); GET_ARG(1); GET_ARG(2); - if (asprintf(&s, "/tmp/qemu-%x%02x", getpid(), - (int) (arg1 & 0xff)) < 0) { - return -1; + len = asprintf(&s, "%s/qemu-%x%02x", g_get_tmp_dir(), + getpid(), (int)arg1 & 0xff); + if (len < 0) { + common_semi_set_ret(cs, -1); + break; } - ul_ret = (target_ulong) -1; + /* Allow for trailing NUL */ + len++; /* Make sure there's enough space in the buffer */ - if (strlen(s) < arg2) { - char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0); - strcpy(output, s); - unlock_user(output, arg0, arg2); - ul_ret = 0; + 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); + unlock_user(p, arg0, len); free(s); - return ul_ret; + common_semi_set_ret(cs, 0); + break; + } + case TARGET_SYS_REMOVE: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - ret = common_semi_gdb_syscall(cs, common_semi_cb, "unlink,%s", - arg0, (int)arg1 + 1); - } else { - s = lock_user_string(arg0); - if (!s) { - errno = EFAULT; - return set_swi_errno(cs, -1); - } - ret = set_swi_errno(cs, remove(s)); - unlock_user(s, arg0, 0); - } - return ret; + semihost_sys_remove(cs, common_semi_cb, arg0, arg1 + 1); + break; + case TARGET_SYS_RENAME: GET_ARG(0); GET_ARG(1); GET_ARG(2); GET_ARG(3); - if (use_gdb_syscalls()) { - return common_semi_gdb_syscall(cs, common_semi_cb, "rename,%s,%s", - arg0, (int)arg1 + 1, arg2, - (int)arg3 + 1); - } else { - char *s2; - s = lock_user_string(arg0); - s2 = lock_user_string(arg2); - if (!s || !s2) { - errno = EFAULT; - ret = set_swi_errno(cs, -1); - } else { - ret = set_swi_errno(cs, rename(s, s2)); - } - if (s2) - unlock_user(s2, arg2, 0); - if (s) - unlock_user(s, arg0, 0); - return ret; - } + semihost_sys_rename(cs, common_semi_cb, arg0, arg1 + 1, arg2, arg3 + 1); + break; + case TARGET_SYS_CLOCK: - return clock() / (CLOCKS_PER_SEC / 100); + common_semi_set_ret(cs, clock() / (CLOCKS_PER_SEC / 100)); + break; + case TARGET_SYS_TIME: - return set_swi_errno(cs, time(NULL)); + ul_ret = time(NULL); + common_semi_cb(cs, ul_ret, ul_ret == -1 ? errno : 0); + break; + case TARGET_SYS_SYSTEM: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - return common_semi_gdb_syscall(cs, common_semi_cb, "system,%s", - arg0, (int)arg1 + 1); - } else { - s = lock_user_string(arg0); - if (!s) { - errno = EFAULT; - return set_swi_errno(cs, -1); - } - ret = set_swi_errno(cs, system(s)); - unlock_user(s, arg0, 0); - return ret; - } + semihost_sys_system(cs, common_semi_cb, arg0, arg1 + 1); + break; + case TARGET_SYS_ERRNO: - return get_swi_errno(cs); + common_semi_set_ret(cs, get_swi_errno(cs)); + break; + case TARGET_SYS_GET_CMDLINE: { /* Build a command-line from the original argv. @@ -1106,7 +601,7 @@ target_ulong do_common_semihosting(CPUState *cs) #else unsigned int i; - output_size = ts->info->arg_end - ts->info->arg_start; + output_size = ts->info->env_strings - ts->info->arg_strings; if (!output_size) { /* * We special-case the "empty command line" case (argc==0). @@ -1118,22 +613,20 @@ target_ulong do_common_semihosting(CPUState *cs) if (output_size > input_size) { /* Not enough space to store command-line arguments. */ - errno = E2BIG; - return set_swi_errno(cs, -1); + common_semi_cb(cs, -1, E2BIG); + break; } /* Adjust the command-line length. */ if (SET_ARG(1, output_size - 1)) { /* Couldn't write back to argument block */ - errno = EFAULT; - return set_swi_errno(cs, -1); + goto do_fault; } /* Lock the buffer on the ARM side. */ output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0); if (!output_buffer) { - errno = EFAULT; - return set_swi_errno(cs, -1); + goto do_fault; } /* Copy the command-line arguments. */ @@ -1146,11 +639,10 @@ target_ulong do_common_semihosting(CPUState *cs) goto out; } - if (copy_from_user(output_buffer, ts->info->arg_start, + if (copy_from_user(output_buffer, ts->info->arg_strings, output_size)) { - errno = EFAULT; - status = set_swi_errno(cs, -1); - goto out; + unlock_user(output_buffer, arg0, 0); + goto do_fault; } /* Separate arguments by white spaces. */ @@ -1163,9 +655,10 @@ target_ulong do_common_semihosting(CPUState *cs) #endif /* Unlock the buffer on the ARM side. */ unlock_user(output_buffer, arg0, output_size); - - return status; + common_semi_cb(cs, status, 0); } + break; + case TARGET_SYS_HEAPINFO: { target_ulong retvals[4]; @@ -1222,12 +715,13 @@ target_ulong do_common_semihosting(CPUState *cs) if (fail) { /* Couldn't write back to argument block */ - errno = EFAULT; - return set_swi_errno(cs, -1); + goto do_fault; } } - return 0; + common_semi_set_ret(cs, 0); } + break; + case TARGET_SYS_EXIT: case TARGET_SYS_EXIT_EXTENDED: if (common_semi_sys_exit_extended(cs, nr)) { @@ -1257,36 +751,45 @@ target_ulong do_common_semihosting(CPUState *cs) } gdb_exit(ret); exit(ret); + 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; + } } - return 0; + common_semi_set_ret(cs, 0); + break; + case TARGET_SYS_TICKFREQ: /* qemu always uses nsec */ - return 1000000000; + common_semi_set_ret(cs, 1000000000); + break; + case TARGET_SYS_SYNCCACHE: /* * Clean the D-cache and invalidate the I-cache for the specified * virtual address range. This is a nop for us since we don't * implement caches. This is only present on A64. */ -#ifdef TARGET_ARM - if (is_a64(cs->env_ptr)) { - return 0; + if (common_semi_has_synccache(env)) { + common_semi_set_ret(cs, 0); + break; } -#endif -#ifdef TARGET_RISCV - return 0; -#endif - /* fall through -- invalid for A32/T32 */ + /* fall through */ default: fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); cpu_dump_state(cs, stderr, 0); abort(); + + do_fault: + common_semi_cb(cs, -1, EFAULT); + break; } } diff --git a/semihosting/config.c b/semihosting/config.c index 50d82108e6ef..89a175968790 100644 --- a/semihosting/config.c +++ b/semihosting/config.c @@ -27,12 +27,16 @@ QemuOptsList qemu_semihosting_config_opts = { .name = "semihosting-config", + .merge_lists = true, .implied_opt_name = "enable", .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head), .desc = { { .name = "enable", .type = QEMU_OPT_BOOL, + }, { + .name = "userspace", + .type = QEMU_OPT_BOOL, }, { .name = "target", .type = QEMU_OPT_STRING, @@ -49,8 +53,8 @@ QemuOptsList qemu_semihosting_config_opts = { typedef struct SemihostingConfig { bool enabled; + bool userspace_enabled; SemihostingTarget target; - Chardev *chardev; char **argv; int argc; const char *cmdline; /* concatenated argv */ @@ -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) @@ -121,11 +125,6 @@ void semihosting_arg_fallback(const char *file, const char *cmd) } } -Chardev *semihosting_get_chardev(void) -{ - return semihosting.chardev; -} - void qemu_semihosting_enable(void) { semihosting.enabled = true; @@ -142,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"); @@ -171,16 +172,19 @@ int qemu_semihosting_config_options(const char *optarg) return 0; } -void qemu_semihosting_connect_chardevs(void) +/* We had to defer this until chardevs were created */ +void qemu_semihosting_chardev_init(void) { - /* We had to defer this until chardevs were created */ + Chardev *chr = NULL; + if (semihost_chardev) { - Chardev *chr = qemu_chr_find(semihost_chardev); + chr = qemu_chr_find(semihost_chardev); if (chr == NULL) { error_report("semihosting chardev '%s' not found", semihost_chardev); exit(1); } - semihosting.chardev = chr; } + + qemu_semihosting_console_init(chr); } diff --git a/semihosting/console.c b/semihosting/console.c index ef6958d8445a..5d61e8207e26 100644 --- a/semihosting/console.c +++ b/semihosting/console.c @@ -27,89 +27,10 @@ #include "qapi/error.h" #include "qemu/fifo8.h" -int qemu_semihosting_log_out(const char *s, int len) -{ - Chardev *chardev = semihosting_get_chardev(); - if (chardev) { - return qemu_chr_write_all(chardev, (uint8_t *) s, len); - } else { - return write(STDERR_FILENO, s, len); - } -} - -/* - * A re-implementation of lock_user_string that we can use locally - * instead of relying on softmmu-semi. Hopefully we can deprecate that - * in time. Copy string until we find a 0 or address error. - */ -static GString *copy_user_string(CPUArchState *env, target_ulong addr) -{ - CPUState *cpu = env_cpu(env); - GString *s = g_string_sized_new(128); - uint8_t c; - - do { - if (cpu_memory_rw_debug(cpu, addr++, &c, 1, 0) == 0) { - if (c) { - s = g_string_append_c(s, c); - } - } else { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: passed inaccessible address " TARGET_FMT_lx, - __func__, addr); - break; - } - } while (c!=0); - - return s; -} - -static void semihosting_cb(CPUState *cs, target_ulong ret, target_ulong err) -{ - if (ret == (target_ulong) -1) { - qemu_log("%s: gdb console output failed ("TARGET_FMT_ld")", - __func__, err); - } -} - -int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr) -{ - GString *s = copy_user_string(env, addr); - int out = s->len; - - if (use_gdb_syscalls()) { - gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, s->len); - } else { - out = qemu_semihosting_log_out(s->str, s->len); - } - - g_string_free(s, true); - return out; -} - -void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr) -{ - CPUState *cpu = env_cpu(env); - uint8_t c; - - if (cpu_memory_rw_debug(cpu, addr, &c, 1, 0) == 0) { - if (use_gdb_syscalls()) { - gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, 1); - } else { - qemu_semihosting_log_out((const char *) &c, 1); - } - } else { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: passed inaccessible address " TARGET_FMT_lx, - __func__, addr); - } -} - -#define FIFO_SIZE 1024 - /* Access to this structure is protected by the BQL */ typedef struct SemihostingConsole { CharBackend backend; + Chardev *chr; GSList *sleeping_cpus; bool got; Fifo8 fifo; @@ -117,13 +38,13 @@ typedef struct SemihostingConsole { static SemihostingConsole console; +#define FIFO_SIZE 1024 + static int console_can_read(void *opaque) { SemihostingConsole *c = opaque; - int ret; g_assert(qemu_mutex_iothread_locked()); - ret = (int) fifo8_num_free(&c->fifo); - return ret; + return (int)fifo8_num_free(&c->fifo); } static void console_wake_up(gpointer data, gpointer user_data) @@ -145,27 +66,59 @@ static void console_read(void *opaque, const uint8_t *buf, int size) c->sleeping_cpus = NULL; } -target_ulong qemu_semihosting_console_inc(CPUArchState *env) +bool qemu_semihosting_console_ready(void) +{ + SemihostingConsole *c = &console; + + g_assert(qemu_mutex_iothread_locked()); + return !fifo8_is_empty(&c->fifo); +} + +void qemu_semihosting_console_block_until_ready(CPUState *cs) { - uint8_t ch; SemihostingConsole *c = &console; + g_assert(qemu_mutex_iothread_locked()); - g_assert(current_cpu); + + /* Block if the fifo is completely empty. */ if (fifo8_is_empty(&c->fifo)) { - c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, current_cpu); - current_cpu->halted = 1; - current_cpu->exception_index = EXCP_HALTED; - cpu_loop_exit(current_cpu); + c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs); + cs->halted = 1; + cs->exception_index = EXCP_HALTED; + cpu_loop_exit(cs); /* never returns */ } - ch = fifo8_pop(&c->fifo); - return (target_ulong) ch; } -void qemu_semihosting_console_init(void) +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len) { - Chardev *chr = semihosting_get_chardev(); + SemihostingConsole *c = &console; + int ret = 0; + qemu_semihosting_console_block_until_ready(cs); + + /* Read until buffer full or fifo exhausted. */ + do { + *(char *)(buf + ret) = fifo8_pop(&c->fifo); + ret++; + } while (ret < len && !fifo8_is_empty(&c->fifo)); + + return ret; +} + +int qemu_semihosting_console_write(void *buf, int len) +{ + if (console.chr) { + int r = qemu_chr_write_all(console.chr, (uint8_t *)buf, len); + return r < 0 ? 0 : r; + } else { + return fwrite(buf, 1, len, stderr); + } +} + +void qemu_semihosting_console_init(Chardev *chr) +{ + console.chr = chr; if (chr) { fifo8_create(&console.fifo, FIFO_SIZE); qemu_chr_fe_init(&console.backend, chr, &error_abort); @@ -175,4 +128,6 @@ void qemu_semihosting_console_init(void) NULL, NULL, &console, NULL, true); } + + qemu_semihosting_guestfd_init(); } diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c new file mode 100644 index 000000000000..b05c52f26ff5 --- /dev/null +++ b/semihosting/guestfd.c @@ -0,0 +1,160 @@ +/* + * Hosted file support for semihosting syscalls. + * + * Copyright (c) 2005, 2007 CodeSourcery. + * Copyright (c) 2019 Linaro + * Copyright © 2020 by Keith Packard + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" +#include "semihosting/semihost.h" +#include "semihosting/guestfd.h" +#ifdef CONFIG_USER_ONLY +#include "qemu.h" +#else +#include "semihosting/softmmu-uaccess.h" +#include CONFIG_DEVICES +#endif + +static GArray *guestfd_array; + +#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING +GuestFD console_in_gf; +GuestFD console_out_gf; +#endif + +void qemu_semihosting_guestfd_init(void) +{ + /* New entries zero-initialized, i.e. type GuestFDUnused */ + guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD)); + +#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING + /* For ARM-compat, the console is in a separate namespace. */ + if (use_gdb_syscalls()) { + console_in_gf.type = GuestFDGDB; + console_in_gf.hostfd = 0; + console_out_gf.type = GuestFDGDB; + console_out_gf.hostfd = 2; + } else { + console_in_gf.type = GuestFDConsole; + console_out_gf.type = GuestFDConsole; + } +#else + /* Otherwise, the stdio file descriptors apply. */ + guestfd_array = g_array_set_size(guestfd_array, 3); +#ifndef CONFIG_USER_ONLY + if (!use_gdb_syscalls()) { + GuestFD *gf = &g_array_index(guestfd_array, GuestFD, 0); + gf[0].type = GuestFDConsole; + gf[1].type = GuestFDConsole; + gf[2].type = GuestFDConsole; + return; + } +#endif + associate_guestfd(0, 0); + associate_guestfd(1, 1); + associate_guestfd(2, 2); +#endif +} + +/* + * Allocate a new guest file descriptor and return it; if we + * couldn't allocate a new fd then return -1. + * This is a fairly simplistic implementation because we don't + * expect that most semihosting guest programs will make very + * heavy use of opening and closing fds. + */ +int alloc_guestfd(void) +{ + guint i; + + /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */ + for (i = 1; i < guestfd_array->len; i++) { + GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i); + + if (gf->type == GuestFDUnused) { + return i; + } + } + + /* All elements already in use: expand the array */ + g_array_set_size(guestfd_array, i + 1); + return i; +} + +static void do_dealloc_guestfd(GuestFD *gf) +{ + gf->type = GuestFDUnused; +} + +/* + * Look up the guestfd in the data structure; return NULL + * for out of bounds, but don't check whether the slot is unused. + * This is used internally by the other guestfd functions. + */ +static GuestFD *do_get_guestfd(int guestfd) +{ + if (guestfd < 0 || guestfd >= guestfd_array->len) { + return NULL; + } + + return &g_array_index(guestfd_array, GuestFD, guestfd); +} + +/* + * Given a guest file descriptor, get the associated struct. + * If the fd is not valid, return NULL. This is the function + * used by the various semihosting calls to validate a handle + * from the guest. + * Note: calling alloc_guestfd() or dealloc_guestfd() will + * invalidate any GuestFD* obtained by calling this function. + */ +GuestFD *get_guestfd(int guestfd) +{ + GuestFD *gf = do_get_guestfd(guestfd); + + if (!gf || gf->type == GuestFDUnused) { + return NULL; + } + return gf; +} + +/* + * Associate the specified guest fd (which must have been + * allocated via alloc_fd() and not previously used) with + * the specified host/gdb fd. + */ +void associate_guestfd(int guestfd, int hostfd) +{ + GuestFD *gf = do_get_guestfd(guestfd); + + assert(gf); + gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost; + gf->hostfd = hostfd; +} + +void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len) +{ + GuestFD *gf = do_get_guestfd(guestfd); + + assert(gf); + gf->type = GuestFDStatic; + gf->staticfile.data = data; + gf->staticfile.len = len; + gf->staticfile.off = 0; +} + +/* + * Deallocate the specified guest file descriptor. This doesn't + * close the host fd, it merely undoes the work of alloc_fd(). + */ +void dealloc_guestfd(int guestfd) +{ + GuestFD *gf = do_get_guestfd(guestfd); + + assert(gf); + do_dealloc_guestfd(gf); +} diff --git a/semihosting/meson.build b/semihosting/meson.build index ea8090abe34c..8057db5494a8 100644 --- a/semihosting/meson.build +++ b/semihosting/meson.build @@ -1,6 +1,12 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files( + 'guestfd.c', + 'syscalls.c', +)) + +specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SOFTMMU'], if_true: files( 'config.c', 'console.c', + 'uaccess.c', )) specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'], diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c new file mode 100644 index 000000000000..5893c760c5f6 --- /dev/null +++ b/semihosting/syscalls.c @@ -0,0 +1,976 @@ +/* + * Syscall implementations for semihosting. + * + * Copyright (c) 2022 Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" +#include "semihosting/guestfd.h" +#include "semihosting/syscalls.h" +#include "semihosting/console.h" +#ifdef CONFIG_USER_ONLY +#include "qemu.h" +#else +#include "semihosting/softmmu-uaccess.h" +#endif + + +/* + * Validate or compute the length of the string (including terminator). + */ +static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char c; + + if (tlen == 0) { + ssize_t slen = target_strlen(str); + + if (slen < 0) { + return -EFAULT; + } + if (slen >= INT32_MAX) { + return -ENAMETOOLONG; + } + return slen + 1; + } + if (tlen > INT32_MAX) { + return -ENAMETOOLONG; + } + if (get_user_u8(c, str + tlen - 1)) { + return -EFAULT; + } + if (c != 0) { + return -EINVAL; + } + return tlen; +} + +static int validate_lock_user_string(char **pstr, CPUState *cs, + target_ulong tstr, target_ulong tlen) +{ + int ret = validate_strlen(cs, tstr, tlen); + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *str = NULL; + + if (ret > 0) { + str = lock_user(VERIFY_READ, tstr, ret, true); + ret = str ? 0 : -EFAULT; + } + *pstr = str; + return ret; +} + +/* + * TODO: Note that gdb always stores the stat structure big-endian. + * So far, that's ok, as the only two targets using this are also + * big-endian. Until we do something with gdb, also produce the + * same big-endian result from the host. + */ +static int copy_stat_to_user(CPUState *cs, target_ulong addr, + const struct stat *s) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + struct gdb_stat *p; + + if (s->st_dev != (uint32_t)s->st_dev || + s->st_ino != (uint32_t)s->st_ino) { + return -EOVERFLOW; + } + + p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0); + if (!p) { + return -EFAULT; + } + + 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 0; +} + +/* + * GDB semihosting syscall implementations. + */ + +static gdb_syscall_complete_cb gdb_open_complete; + +static void gdb_open_cb(CPUState *cs, uint64_t ret, int err) +{ + if (!err) { + int guestfd = alloc_guestfd(); + associate_guestfd(guestfd, ret); + ret = guestfd; + } + gdb_open_complete(cs, ret, err); +} + +static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + int gdb_flags, int mode) +{ + int len = validate_strlen(cs, fname, fname_len); + if (len < 0) { + complete(cs, -1, -len); + return; + } + + gdb_open_complete = complete; + gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x", + fname, len, (target_ulong)gdb_flags, (target_ulong)mode); +} + +static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf) +{ + gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd); +} + +static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + gdb_do_syscall(complete, "read,%x,%x,%x", + (target_ulong)gf->hostfd, buf, len); +} + +static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + gdb_do_syscall(complete, "write,%x,%x,%x", + (target_ulong)gf->hostfd, buf, len); +} + +static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, int64_t off, int gdb_whence) +{ + gdb_do_syscall(complete, "lseek,%x,%lx,%x", + (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence); +} + +static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf) +{ + gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd); +} + +static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong addr) +{ + gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr); +} + +static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + target_ulong addr) +{ + int len = validate_strlen(cs, fname, fname_len); + if (len < 0) { + complete(cs, -1, -len); + return; + } + + gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr); +} + +static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len) +{ + int len = validate_strlen(cs, fname, fname_len); + if (len < 0) { + complete(cs, -1, -len); + return; + } + + gdb_do_syscall(complete, "unlink,%s", fname, len); +} + +static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong oname, target_ulong oname_len, + target_ulong nname, target_ulong nname_len) +{ + int olen, nlen; + + olen = validate_strlen(cs, oname, oname_len); + if (olen < 0) { + complete(cs, -1, -olen); + return; + } + nlen = validate_strlen(cs, nname, nname_len); + if (nlen < 0) { + complete(cs, -1, -nlen); + return; + } + + gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen); +} + +static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong cmd, target_ulong cmd_len) +{ + int len = validate_strlen(cs, cmd, cmd_len); + if (len < 0) { + complete(cs, -1, -len); + return; + } + + gdb_do_syscall(complete, "system,%s", cmd, len); +} + +static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong tv_addr, target_ulong tz_addr) +{ + gdb_do_syscall(complete, "gettimeofday,%x,%x", tv_addr, tz_addr); +} + +/* + * Host semihosting syscall implementations. + */ + +static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + int gdb_flags, int mode) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *p; + int ret, host_flags; + + ret = validate_lock_user_string(&p, cs, fname, fname_len); + if (ret < 0) { + complete(cs, -1, -ret); + return; + } + + if (gdb_flags & GDB_O_WRONLY) { + host_flags = O_WRONLY; + } else if (gdb_flags & GDB_O_RDWR) { + host_flags = O_RDWR; + } else { + host_flags = O_RDONLY; + } + if (gdb_flags & GDB_O_CREAT) { + host_flags |= O_CREAT; + } + if (gdb_flags & GDB_O_TRUNC) { + host_flags |= O_TRUNC; + } + if (gdb_flags & GDB_O_EXCL) { + host_flags |= O_EXCL; + } + + ret = open(p, host_flags, mode); + if (ret < 0) { + complete(cs, -1, errno); + } else { + int guestfd = alloc_guestfd(); + associate_guestfd(guestfd, ret); + complete(cs, guestfd, 0); + } + unlock_user(p, fname, 0); +} + +static void host_close(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf) +{ + /* + * Only close the underlying host fd if it's one we opened on behalf + * of the guest in SYS_OPEN. + */ + if (gf->hostfd != STDIN_FILENO && + gf->hostfd != STDOUT_FILENO && + gf->hostfd != STDERR_FILENO && + close(gf->hostfd) < 0) { + complete(cs, -1, errno); + } else { + complete(cs, 0, 0); + } +} + +static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + void *ptr = lock_user(VERIFY_WRITE, buf, len, 0); + ssize_t ret; + + if (!ptr) { + complete(cs, -1, EFAULT); + return; + } + ret = RETRY_ON_EINTR(read(gf->hostfd, ptr, len)); + if (ret == -1) { + complete(cs, -1, errno); + unlock_user(ptr, buf, 0); + } else { + complete(cs, ret, 0); + unlock_user(ptr, buf, ret); + } +} + +static void host_write(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + void *ptr = lock_user(VERIFY_READ, buf, len, 1); + ssize_t ret; + + if (!ptr) { + complete(cs, -1, EFAULT); + return; + } + ret = write(gf->hostfd, ptr, len); + complete(cs, ret, ret == -1 ? errno : 0); + unlock_user(ptr, buf, 0); +} + +static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, int64_t off, int whence) +{ + /* So far, all hosts use the same values. */ + QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET); + QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR); + QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END); + + off_t ret = off; + int err = 0; + + if (ret == off) { + ret = lseek(gf->hostfd, ret, whence); + if (ret == -1) { + err = errno; + } + } else { + ret = -1; + err = EINVAL; + } + complete(cs, ret, err); +} + +static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf) +{ + int ret = isatty(gf->hostfd); + complete(cs, ret, ret ? 0 : errno); +} + +static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf) +{ + struct stat buf; + + if (fstat(gf->hostfd, &buf) < 0) { + complete(cs, -1, errno); + } else { + complete(cs, buf.st_size, 0); + } +} + +static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong addr) +{ + struct stat buf; + int ret; + + ret = fstat(gf->hostfd, &buf); + if (ret) { + complete(cs, -1, errno); + return; + } + ret = copy_stat_to_user(cs, addr, &buf); + complete(cs, ret ? -1 : 0, ret ? -ret : 0); +} + +static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + target_ulong addr) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + struct stat buf; + char *name; + int ret, err; + + ret = validate_lock_user_string(&name, cs, fname, fname_len); + if (ret < 0) { + complete(cs, -1, -ret); + return; + } + + ret = stat(name, &buf); + if (ret) { + err = errno; + } else { + ret = copy_stat_to_user(cs, addr, &buf); + err = 0; + if (ret < 0) { + err = -ret; + ret = -1; + } + } + complete(cs, ret, err); + unlock_user(name, fname, 0); +} + +static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *p; + int ret; + + ret = validate_lock_user_string(&p, cs, fname, fname_len); + if (ret < 0) { + complete(cs, -1, -ret); + return; + } + + ret = remove(p); + complete(cs, ret, ret ? errno : 0); + unlock_user(p, fname, 0); +} + +static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong oname, target_ulong oname_len, + target_ulong nname, target_ulong nname_len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *ostr, *nstr; + int ret; + + ret = validate_lock_user_string(&ostr, cs, oname, oname_len); + if (ret < 0) { + complete(cs, -1, -ret); + return; + } + ret = validate_lock_user_string(&nstr, cs, nname, nname_len); + if (ret < 0) { + unlock_user(ostr, oname, 0); + complete(cs, -1, -ret); + return; + } + + ret = rename(ostr, nstr); + complete(cs, ret, ret ? errno : 0); + unlock_user(ostr, oname, 0); + unlock_user(nstr, nname, 0); +} + +static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong cmd, target_ulong cmd_len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *p; + int ret; + + ret = validate_lock_user_string(&p, cs, cmd, cmd_len); + if (ret < 0) { + complete(cs, -1, -ret); + return; + } + + ret = system(p); + complete(cs, ret, ret == -1 ? errno : 0); + unlock_user(p, cmd, 0); +} + +static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong tv_addr, target_ulong tz_addr) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + struct gdb_timeval *p; + int64_t rt; + + /* GDB fails on non-null TZ, so be consistent. */ + if (tz_addr != 0) { + complete(cs, -1, EINVAL); + return; + } + + p = lock_user(VERIFY_WRITE, tv_addr, sizeof(struct gdb_timeval), 0); + if (!p) { + complete(cs, -1, EFAULT); + return; + } + + /* TODO: Like stat, gdb always produces big-endian results; match it. */ + rt = g_get_real_time(); + 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, tv_addr, sizeof(struct gdb_timeval)); +} + +#ifndef CONFIG_USER_ONLY +static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, GIOCondition cond, int timeout) +{ + /* + * Since this is only used by xtensa in system mode, and stdio is + * handled through GuestFDConsole, and there are no semihosting + * system calls for sockets and the like, that means this descriptor + * must be a normal file. Normal files never block and are thus + * always ready. + */ + complete(cs, cond & (G_IO_IN | G_IO_OUT), 0); +} +#endif + +/* + * Static file semihosting syscall implementations. + */ + +static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + target_ulong rest = gf->staticfile.len - gf->staticfile.off; + void *ptr; + + if (len > rest) { + len = rest; + } + ptr = lock_user(VERIFY_WRITE, buf, len, 0); + if (!ptr) { + complete(cs, -1, EFAULT); + return; + } + memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len); + gf->staticfile.off += len; + complete(cs, len, 0); + unlock_user(ptr, buf, len); +} + +static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, int64_t off, int gdb_whence) +{ + int64_t ret; + + switch (gdb_whence) { + case GDB_SEEK_SET: + ret = off; + break; + case GDB_SEEK_CUR: + ret = gf->staticfile.off + off; + break; + case GDB_SEEK_END: + ret = gf->staticfile.len + off; + break; + default: + ret = -1; + break; + } + if (ret >= 0 && ret <= gf->staticfile.len) { + gf->staticfile.off = ret; + complete(cs, ret, 0); + } else { + complete(cs, -1, EINVAL); + } +} + +static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf) +{ + complete(cs, gf->staticfile.len, 0); +} + +/* + * Console semihosting syscall implementations. + */ + +static void console_read(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *ptr; + int ret; + + ptr = lock_user(VERIFY_WRITE, buf, len, 0); + if (!ptr) { + complete(cs, -1, EFAULT); + return; + } + ret = qemu_semihosting_console_read(cs, ptr, len); + complete(cs, ret, 0); + unlock_user(ptr, buf, ret); +} + +static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; + char *ptr = lock_user(VERIFY_READ, buf, len, 1); + int ret; + + if (!ptr) { + complete(cs, -1, EFAULT); + return; + } + ret = qemu_semihosting_console_write(ptr, len); + complete(cs, ret ? ret : -1, ret ? 0 : EIO); + unlock_user(ptr, buf, 0); +} + +static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong addr) +{ + static const struct stat tty_buf = { + .st_mode = 020666, /* S_IFCHR, ugo+rw */ + .st_rdev = 5, /* makedev(5, 0) -- linux /dev/tty */ + }; + int ret; + + ret = copy_stat_to_user(cs, addr, &tty_buf); + complete(cs, ret ? -1 : 0, ret ? -ret : 0); +} + +#ifndef CONFIG_USER_ONLY +static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, GIOCondition cond, int timeout) +{ + /* The semihosting console does not support urgent data or errors. */ + cond &= G_IO_IN | G_IO_OUT; + + /* + * Since qemu_semihosting_console_write never blocks, we can + * consider output always ready -- leave G_IO_OUT alone. + * All that remains is to conditionally signal input ready. + * Since output ready causes an immediate return, only block + * for G_IO_IN alone. + * + * TODO: Implement proper timeout. For now, only support + * indefinite wait or immediate poll. + */ + if (cond == G_IO_IN && timeout < 0) { + qemu_semihosting_console_block_until_ready(cs); + /* We returned -- input must be ready. */ + } else if ((cond & G_IO_IN) && !qemu_semihosting_console_ready()) { + cond &= ~G_IO_IN; + } + + complete(cs, cond, 0); +} +#endif + +/* + * Syscall entry points. + */ + +void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + int gdb_flags, int mode) +{ + if (use_gdb_syscalls()) { + gdb_open(cs, complete, fname, fname_len, gdb_flags, mode); + } else { + host_open(cs, complete, fname, fname_len, gdb_flags, mode); + } +} + +void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd) +{ + GuestFD *gf = get_guestfd(fd); + + if (!gf) { + complete(cs, -1, EBADF); + return; + } + switch (gf->type) { + case GuestFDGDB: + gdb_close(cs, complete, gf); + break; + case GuestFDHost: + host_close(cs, complete, gf); + break; + case GuestFDStatic: + case GuestFDConsole: + complete(cs, 0, 0); + break; + default: + g_assert_not_reached(); + } + dealloc_guestfd(fd); +} + +void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + /* + * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. + * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad + * idea to do this unconditionally. + */ + if (len > INT32_MAX) { + len = INT32_MAX; + } + switch (gf->type) { + case GuestFDGDB: + gdb_read(cs, complete, gf, buf, len); + break; + case GuestFDHost: + host_read(cs, complete, gf, buf, len); + break; + case GuestFDStatic: + staticfile_read(cs, complete, gf, buf, len); + break; + case GuestFDConsole: + console_read(cs, complete, gf, buf, len); + break; + default: + g_assert_not_reached(); + } +} + +void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, target_ulong buf, target_ulong len) +{ + GuestFD *gf = get_guestfd(fd); + + if (gf) { + semihost_sys_read_gf(cs, complete, gf, buf, len); + } else { + complete(cs, -1, EBADF); + } +} + +void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete, + GuestFD *gf, target_ulong buf, target_ulong len) +{ + /* + * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. + * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad + * idea to do this unconditionally. + */ + if (len > INT32_MAX) { + len = INT32_MAX; + } + switch (gf->type) { + case GuestFDGDB: + gdb_write(cs, complete, gf, buf, len); + break; + case GuestFDHost: + host_write(cs, complete, gf, buf, len); + break; + case GuestFDConsole: + console_write(cs, complete, gf, buf, len); + break; + case GuestFDStatic: + /* Static files are never open for writing: EBADF. */ + complete(cs, -1, EBADF); + break; + default: + g_assert_not_reached(); + } +} + +void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, target_ulong buf, target_ulong len) +{ + GuestFD *gf = get_guestfd(fd); + + if (gf) { + semihost_sys_write_gf(cs, complete, gf, buf, len); + } else { + complete(cs, -1, EBADF); + } +} + +void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, int64_t off, int gdb_whence) +{ + GuestFD *gf = get_guestfd(fd); + + if (!gf) { + complete(cs, -1, EBADF); + return; + } + switch (gf->type) { + case GuestFDGDB: + gdb_lseek(cs, complete, gf, off, gdb_whence); + return; + case GuestFDHost: + host_lseek(cs, complete, gf, off, gdb_whence); + break; + case GuestFDStatic: + staticfile_lseek(cs, complete, gf, off, gdb_whence); + break; + case GuestFDConsole: + complete(cs, -1, ESPIPE); + break; + default: + g_assert_not_reached(); + } +} + +void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd) +{ + GuestFD *gf = get_guestfd(fd); + + if (!gf) { + complete(cs, 0, EBADF); + return; + } + switch (gf->type) { + case GuestFDGDB: + gdb_isatty(cs, complete, gf); + break; + case GuestFDHost: + host_isatty(cs, complete, gf); + break; + case GuestFDStatic: + complete(cs, 0, ENOTTY); + break; + case GuestFDConsole: + complete(cs, 1, 0); + break; + default: + g_assert_not_reached(); + } +} + +void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb, + gdb_syscall_complete_cb flen_cb, int fd, + target_ulong fstat_addr) +{ + GuestFD *gf = get_guestfd(fd); + + if (!gf) { + flen_cb(cs, -1, EBADF); + return; + } + switch (gf->type) { + case GuestFDGDB: + gdb_fstat(cs, fstat_cb, gf, fstat_addr); + break; + case GuestFDHost: + host_flen(cs, flen_cb, gf); + break; + case GuestFDStatic: + staticfile_flen(cs, flen_cb, gf); + break; + case GuestFDConsole: + default: + g_assert_not_reached(); + } +} + +void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, target_ulong addr) +{ + GuestFD *gf = get_guestfd(fd); + + if (!gf) { + complete(cs, -1, EBADF); + return; + } + switch (gf->type) { + case GuestFDGDB: + gdb_fstat(cs, complete, gf, addr); + break; + case GuestFDHost: + host_fstat(cs, complete, gf, addr); + break; + case GuestFDConsole: + console_fstat(cs, complete, gf, addr); + break; + case GuestFDStatic: + default: + g_assert_not_reached(); + } +} + +void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len, + target_ulong addr) +{ + if (use_gdb_syscalls()) { + gdb_stat(cs, complete, fname, fname_len, addr); + } else { + host_stat(cs, complete, fname, fname_len, addr); + } +} + +void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong fname, target_ulong fname_len) +{ + if (use_gdb_syscalls()) { + gdb_remove(cs, complete, fname, fname_len); + } else { + host_remove(cs, complete, fname, fname_len); + } +} + +void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong oname, target_ulong oname_len, + target_ulong nname, target_ulong nname_len) +{ + if (use_gdb_syscalls()) { + gdb_rename(cs, complete, oname, oname_len, nname, nname_len); + } else { + host_rename(cs, complete, oname, oname_len, nname, nname_len); + } +} + +void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong cmd, target_ulong cmd_len) +{ + if (use_gdb_syscalls()) { + gdb_system(cs, complete, cmd, cmd_len); + } else { + host_system(cs, complete, cmd, cmd_len); + } +} + +void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, + target_ulong tv_addr, target_ulong tz_addr) +{ + if (use_gdb_syscalls()) { + gdb_gettimeofday(cs, complete, tv_addr, tz_addr); + } else { + host_gettimeofday(cs, complete, tv_addr, tz_addr); + } +} + +#ifndef CONFIG_USER_ONLY +void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, + int fd, GIOCondition cond, int timeout) +{ + GuestFD *gf = get_guestfd(fd); + + if (!gf) { + complete(cs, G_IO_NVAL, 1); + return; + } + switch (gf->type) { + case GuestFDGDB: + complete(cs, G_IO_NVAL, 1); + break; + case GuestFDHost: + host_poll_one(cs, complete, gf, cond, timeout); + break; + case GuestFDConsole: + console_poll_one(cs, complete, gf, cond, timeout); + break; + case GuestFDStatic: + default: + g_assert_not_reached(); + } +} +#endif diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c new file mode 100644 index 000000000000..801882806976 --- /dev/null +++ b/semihosting/uaccess.c @@ -0,0 +1,91 @@ +/* + * Helper routines to provide target memory access for semihosting + * syscalls in system emulation mode. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ + +#include "qemu/osdep.h" +#include "exec/exec-all.h" +#include "semihosting/softmmu-uaccess.h" + +void *softmmu_lock_user(CPUArchState *env, target_ulong addr, + target_ulong len, bool copy) +{ + void *p = malloc(len); + if (p && copy) { + if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) { + free(p); + p = NULL; + } + } + return p; +} + +ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr) +{ + int mmu_idx = cpu_mmu_index(env, false); + size_t len = 0; + + while (1) { + size_t left_in_page; + int flags; + void *h; + + /* Find the number of bytes remaining in the page. */ + left_in_page = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); + + flags = probe_access_flags(env, addr, MMU_DATA_LOAD, + mmu_idx, true, &h, 0); + if (flags & TLB_INVALID_MASK) { + return -1; + } + if (flags & TLB_MMIO) { + do { + uint8_t c; + if (cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0)) { + return -1; + } + if (c == 0) { + return len; + } + addr++; + len++; + if (len > INT32_MAX) { + return -1; + } + } while (--left_in_page != 0); + } else { + char *p = memchr(h, 0, left_in_page); + if (p) { + len += p - (char *)h; + return len <= INT32_MAX ? (ssize_t)len : -1; + } + addr += left_in_page; + len += left_in_page; + if (len > INT32_MAX) { + return -1; + } + } + } +} + +char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr) +{ + ssize_t len = softmmu_strlen_user(env, addr); + if (len < 0) { + return NULL; + } + return softmmu_lock_user(env, addr, len + 1, true); +} + +void softmmu_unlock_user(CPUArchState *env, void *p, + target_ulong addr, target_ulong len) +{ + if (len) { + cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1); + } + free(p); +} diff --git a/slirp b/slirp deleted file mode 160000 index a88d9ace234a..000000000000 --- a/slirp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a88d9ace234a24ce1c17189642ef9104799425e0 diff --git a/softmmu/bootdevice.c b/softmmu/bootdevice.c index c0713bfa9fa3..2106f1026ff3 100644 --- a/softmmu/bootdevice.c +++ b/softmmu/bootdevice.c @@ -268,7 +268,8 @@ char *get_boot_devices_list(size_t *size) *size = total; - if (boot_strict && *size > 0) { + if (current_machine->boot_config.has_strict && + current_machine->boot_config.strict && *size > 0) { list[total-1] = '\n'; list = g_realloc(list, total + 5); memcpy(&list[total], "HALT", 5); diff --git a/softmmu/cpu-throttle.c b/softmmu/cpu-throttle.c index 8c2144ab95cc..d9bb30a223d8 100644 --- a/softmmu/cpu-throttle.c +++ b/softmmu/cpu-throttle.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/thread.h" #include "hw/core/cpu.h" #include "qemu/main-loop.h" diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c index 204d946a1729..117408cb83af 100644 --- a/softmmu/cpu-timers.c +++ b/softmmu/cpu-timers.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "migration/vmstate.h" #include "qapi/error.h" diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 7b75bb66d5e6..5a584a8d57d7 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "monitor/monitor.h" #include "qemu/coroutine-tls.h" #include "qapi/error.h" @@ -355,7 +354,7 @@ static void qemu_init_sigbus(void) /* * ALERT: when modifying this, take care that SIGBUS forwarding in - * os_mem_prealloc() will continue working as expected. + * qemu_prealloc_mem() will continue working as expected. */ memset(&action, 0, sizeof(action)); action.sa_flags = SA_SIGINFO; @@ -438,18 +437,19 @@ void qemu_wait_io_event(CPUState *cpu) void cpus_kick_thread(CPUState *cpu) { -#ifndef _WIN32 - int err; - if (cpu->thread_kicked) { return; } cpu->thread_kicked = true; - err = pthread_kill(cpu->thread->thread, SIG_IPI); + +#ifndef _WIN32 + int err = pthread_kill(cpu->thread->thread, SIG_IPI); if (err && err != ESRCH) { fprintf(stderr, "qemu:%s: %s", __func__, strerror(err)); exit(1); } +#else + qemu_sem_post(&cpu->sem); #endif } @@ -618,6 +618,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()); @@ -673,7 +680,7 @@ int vm_stop(RunState state) * Returns -1 if the vCPUs are not to be restarted (e.g. if they are already * running or in case of an error condition), 0 otherwise. */ -int vm_prepare_start(void) +int vm_prepare_start(bool step_pending) { RunState requested; @@ -693,6 +700,14 @@ int vm_prepare_start(void) return -1; } + /* + * WHPX accelerator needs to know whether we are going to step + * any CPUs, before starting the first one. + */ + if (cpus_accel->synchronize_pre_resume) { + cpus_accel->synchronize_pre_resume(step_pending); + } + /* We are sending this now, but the CPUs will be resumed shortly later */ qapi_event_send_resume(); @@ -704,7 +719,7 @@ int vm_prepare_start(void) void vm_start(void) { - if (!vm_prepare_start()) { + if (!vm_prepare_start(false)) { resume_all_vcpus(); } } diff --git a/softmmu/datadir.c b/softmmu/datadir.c index 504c4665bed7..c9237cb5d4a6 100644 --- a/softmmu/datadir.c +++ b/softmmu/datadir.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/cutils.h" #include "trace.h" @@ -84,40 +83,22 @@ void qemu_add_data_dir(char *path) data_dir[data_dir_idx++] = path; } -/* - * Find a likely location for support files using the location of the binary. - * When running from the build tree this will be "$bindir/pc-bios". - * Otherwise, this is CONFIG_QEMU_DATADIR (possibly relocated). - * - * The caller must use g_free() to free the returned data when it is - * no longer required. - */ -static char *find_datadir(void) -{ - g_autofree char *dir = NULL; - - dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL); - if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { - return g_steal_pointer(&dir); - } - - return get_relocated_path(CONFIG_QEMU_DATADIR); -} - void qemu_add_default_firmwarepath(void) { - char **dirs; + static const char * const dirs[] = { + CONFIG_QEMU_FIRMWAREPATH + NULL + }; + size_t i; /* add configured firmware directories */ - dirs = g_strsplit(CONFIG_QEMU_FIRMWAREPATH, G_SEARCHPATH_SEPARATOR_S, 0); for (i = 0; dirs[i] != NULL; i++) { qemu_add_data_dir(get_relocated_path(dirs[i])); } - g_strfreev(dirs); /* try to find datadir relative to the executable path */ - qemu_add_data_dir(find_datadir()); + qemu_add_data_dir(get_relocated_path(CONFIG_QEMU_DATADIR)); } void qemu_list_data_dirs(void) diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c index 6ca3fad28556..30aa3aea9fad 100644 --- a/softmmu/device_tree.c +++ b/softmmu/device_tree.c @@ -22,10 +22,14 @@ #include "qemu/option.h" #include "qemu/bswap.h" #include "qemu/cutils.h" +#include "qemu/guest-random.h" #include "sysemu/device_tree.h" #include "hw/loader.h" #include "hw/boards.h" #include "qemu/config-file.h" +#include "qapi/qapi-commands-machine.h" +#include "qapi/qmp/qdict.h" +#include "monitor/hmp.h" #include @@ -643,3 +647,57 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt, g_free(propcells); return ret; } + +void qmp_dumpdtb(const char *filename, Error **errp) +{ + g_autoptr(GError) err = NULL; + uint32_t size; + + if (!current_machine->fdt) { + error_setg(errp, "This machine doesn't have a FDT"); + return; + } + + size = fdt_totalsize(current_machine->fdt); + + g_assert(size > 0); + + if (!g_file_set_contents(filename, current_machine->fdt, size, &err)) { + error_setg(errp, "Error saving FDT to file %s: %s", + filename, err->message); + } +} + +void hmp_dumpdtb(Monitor *mon, const QDict *qdict) +{ + const char *filename = qdict_get_str(qdict, "filename"); + Error *local_err = NULL; + + qmp_dumpdtb(filename, &local_err); + + if (hmp_handle_error(mon, local_err)) { + return; + } + + info_report("dtb dumped to %s", filename); +} + +void qemu_fdt_randomize_seeds(void *fdt) +{ + int noffset, poffset, len; + const char *name; + uint8_t *data; + + for (noffset = fdt_next_node(fdt, 0, NULL); + noffset >= 0; + noffset = fdt_next_node(fdt, noffset, NULL)) { + for (poffset = fdt_first_property_offset(fdt, noffset); + poffset >= 0; + poffset = fdt_next_property_offset(fdt, poffset)) { + data = (uint8_t *)fdt_getprop_by_offset(fdt, poffset, &name, &len); + if (!data || strcmp(name, "rng-seed")) + continue; + qemu_guest_getrandom_nofail(data, len); + } + } +} diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c new file mode 100644 index 000000000000..12668555f2c1 --- /dev/null +++ b/softmmu/dirtylimit.c @@ -0,0 +1,601 @@ +/* + * Dirty page rate limit implementation code + * + * Copyright (c) 2022 CHINA TELECOM CO.,LTD. + * + * Authors: + * Hyman Huang(黄勇) + * + * 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 "qapi/error.h" +#include "qemu/main-loop.h" +#include "qapi/qapi-commands-migration.h" +#include "qapi/qmp/qdict.h" +#include "qapi/error.h" +#include "sysemu/dirtyrate.h" +#include "sysemu/dirtylimit.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "exec/memory.h" +#include "hw/boards.h" +#include "sysemu/kvm.h" +#include "trace.h" + +/* + * Dirtylimit stop working if dirty page rate error + * value less than DIRTYLIMIT_TOLERANCE_RANGE + */ +#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ +/* + * Plus or minus vcpu sleep time linearly if dirty + * page rate error value percentage over + * DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT. + * Otherwise, plus or minus a fixed vcpu sleep time. + */ +#define DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT 50 +/* + * Max vcpu sleep time percentage during a cycle + * composed of dirty ring full and sleep time. + */ +#define DIRTYLIMIT_THROTTLE_PCT_MAX 99 + +struct { + VcpuStat stat; + bool running; + QemuThread thread; +} *vcpu_dirty_rate_stat; + +typedef struct VcpuDirtyLimitState { + int cpu_index; + bool enabled; + /* + * Quota dirty page rate, unit is MB/s + * zero if not enabled. + */ + uint64_t quota; +} VcpuDirtyLimitState; + +struct { + VcpuDirtyLimitState *states; + /* Max cpus number configured by user */ + int max_cpus; + /* Number of vcpu under dirtylimit */ + int limited_nvcpu; +} *dirtylimit_state; + +/* protect dirtylimit_state */ +static QemuMutex dirtylimit_mutex; + +/* dirtylimit thread quit if dirtylimit_quit is true */ +static bool dirtylimit_quit; + +static void vcpu_dirty_rate_stat_collect(void) +{ + VcpuStat stat; + int i = 0; + + /* calculate vcpu dirtyrate */ + vcpu_calculate_dirtyrate(DIRTYLIMIT_CALC_TIME_MS, + &stat, + GLOBAL_DIRTY_LIMIT, + false); + + for (i = 0; i < stat.nvcpu; i++) { + vcpu_dirty_rate_stat->stat.rates[i].id = i; + vcpu_dirty_rate_stat->stat.rates[i].dirty_rate = + stat.rates[i].dirty_rate; + } + + free(stat.rates); +} + +static void *vcpu_dirty_rate_stat_thread(void *opaque) +{ + rcu_register_thread(); + + /* start log sync */ + global_dirty_log_change(GLOBAL_DIRTY_LIMIT, true); + + while (qatomic_read(&vcpu_dirty_rate_stat->running)) { + vcpu_dirty_rate_stat_collect(); + if (dirtylimit_in_service()) { + dirtylimit_process(); + } + } + + /* stop log sync */ + global_dirty_log_change(GLOBAL_DIRTY_LIMIT, false); + + rcu_unregister_thread(); + return NULL; +} + +int64_t vcpu_dirty_rate_get(int cpu_index) +{ + DirtyRateVcpu *rates = vcpu_dirty_rate_stat->stat.rates; + return qatomic_read_i64(&rates[cpu_index].dirty_rate); +} + +void vcpu_dirty_rate_stat_start(void) +{ + if (qatomic_read(&vcpu_dirty_rate_stat->running)) { + return; + } + + qatomic_set(&vcpu_dirty_rate_stat->running, 1); + qemu_thread_create(&vcpu_dirty_rate_stat->thread, + "dirtyrate-stat", + vcpu_dirty_rate_stat_thread, + NULL, + QEMU_THREAD_JOINABLE); +} + +void vcpu_dirty_rate_stat_stop(void) +{ + qatomic_set(&vcpu_dirty_rate_stat->running, 0); + dirtylimit_state_unlock(); + qemu_mutex_unlock_iothread(); + qemu_thread_join(&vcpu_dirty_rate_stat->thread); + qemu_mutex_lock_iothread(); + dirtylimit_state_lock(); +} + +void vcpu_dirty_rate_stat_initialize(void) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + int max_cpus = ms->smp.max_cpus; + + vcpu_dirty_rate_stat = + g_malloc0(sizeof(*vcpu_dirty_rate_stat)); + + vcpu_dirty_rate_stat->stat.nvcpu = max_cpus; + vcpu_dirty_rate_stat->stat.rates = + g_new0(DirtyRateVcpu, max_cpus); + + vcpu_dirty_rate_stat->running = false; +} + +void vcpu_dirty_rate_stat_finalize(void) +{ + free(vcpu_dirty_rate_stat->stat.rates); + vcpu_dirty_rate_stat->stat.rates = NULL; + + free(vcpu_dirty_rate_stat); + vcpu_dirty_rate_stat = NULL; +} + +void dirtylimit_state_lock(void) +{ + qemu_mutex_lock(&dirtylimit_mutex); +} + +void dirtylimit_state_unlock(void) +{ + qemu_mutex_unlock(&dirtylimit_mutex); +} + +static void +__attribute__((__constructor__)) dirtylimit_mutex_init(void) +{ + qemu_mutex_init(&dirtylimit_mutex); +} + +static inline VcpuDirtyLimitState *dirtylimit_vcpu_get_state(int cpu_index) +{ + return &dirtylimit_state->states[cpu_index]; +} + +void dirtylimit_state_initialize(void) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + int max_cpus = ms->smp.max_cpus; + int i; + + dirtylimit_state = g_malloc0(sizeof(*dirtylimit_state)); + + dirtylimit_state->states = + g_new0(VcpuDirtyLimitState, max_cpus); + + for (i = 0; i < max_cpus; i++) { + dirtylimit_state->states[i].cpu_index = i; + } + + dirtylimit_state->max_cpus = max_cpus; + trace_dirtylimit_state_initialize(max_cpus); +} + +void dirtylimit_state_finalize(void) +{ + free(dirtylimit_state->states); + dirtylimit_state->states = NULL; + + free(dirtylimit_state); + dirtylimit_state = NULL; + + trace_dirtylimit_state_finalize(); +} + +bool dirtylimit_in_service(void) +{ + return !!dirtylimit_state; +} + +bool dirtylimit_vcpu_index_valid(int cpu_index) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + + return !(cpu_index < 0 || + cpu_index >= ms->smp.max_cpus); +} + +static inline int64_t dirtylimit_dirty_ring_full_time(uint64_t dirtyrate) +{ + static uint64_t max_dirtyrate; + uint32_t dirty_ring_size = kvm_dirty_ring_size(); + uint64_t dirty_ring_size_meory_MB = + dirty_ring_size * TARGET_PAGE_SIZE >> 20; + + if (max_dirtyrate < dirtyrate) { + max_dirtyrate = dirtyrate; + } + + return dirty_ring_size_meory_MB * 1000000 / max_dirtyrate; +} + +static inline bool dirtylimit_done(uint64_t quota, + uint64_t current) +{ + uint64_t min, max; + + min = MIN(quota, current); + max = MAX(quota, current); + + return ((max - min) <= DIRTYLIMIT_TOLERANCE_RANGE) ? true : false; +} + +static inline bool +dirtylimit_need_linear_adjustment(uint64_t quota, + uint64_t current) +{ + uint64_t min, max; + + min = MIN(quota, current); + max = MAX(quota, current); + + return ((max - min) * 100 / max) > DIRTYLIMIT_LINEAR_ADJUSTMENT_PCT; +} + +static void dirtylimit_set_throttle(CPUState *cpu, + uint64_t quota, + uint64_t current) +{ + int64_t ring_full_time_us = 0; + uint64_t sleep_pct = 0; + uint64_t throttle_us = 0; + + if (current == 0) { + cpu->throttle_us_per_full = 0; + return; + } + + ring_full_time_us = dirtylimit_dirty_ring_full_time(current); + + if (dirtylimit_need_linear_adjustment(quota, current)) { + if (quota < current) { + sleep_pct = (current - quota) * 100 / current; + throttle_us = + ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); + cpu->throttle_us_per_full += throttle_us; + } else { + sleep_pct = (quota - current) * 100 / quota; + throttle_us = + ring_full_time_us * sleep_pct / (double)(100 - sleep_pct); + cpu->throttle_us_per_full -= throttle_us; + } + + trace_dirtylimit_throttle_pct(cpu->cpu_index, + sleep_pct, + throttle_us); + } else { + if (quota < current) { + cpu->throttle_us_per_full += ring_full_time_us / 10; + } else { + cpu->throttle_us_per_full -= ring_full_time_us / 10; + } + } + + /* + * TODO: in the big kvm_dirty_ring_size case (eg: 65536, or other scenario), + * current dirty page rate may never reach the quota, we should stop + * increasing sleep time? + */ + cpu->throttle_us_per_full = MIN(cpu->throttle_us_per_full, + ring_full_time_us * DIRTYLIMIT_THROTTLE_PCT_MAX); + + cpu->throttle_us_per_full = MAX(cpu->throttle_us_per_full, 0); +} + +static void dirtylimit_adjust_throttle(CPUState *cpu) +{ + uint64_t quota = 0; + uint64_t current = 0; + int cpu_index = cpu->cpu_index; + + quota = dirtylimit_vcpu_get_state(cpu_index)->quota; + current = vcpu_dirty_rate_get(cpu_index); + + if (!dirtylimit_done(quota, current)) { + dirtylimit_set_throttle(cpu, quota, current); + } + + return; +} + +void dirtylimit_process(void) +{ + CPUState *cpu; + + if (!qatomic_read(&dirtylimit_quit)) { + dirtylimit_state_lock(); + + if (!dirtylimit_in_service()) { + dirtylimit_state_unlock(); + return; + } + + CPU_FOREACH(cpu) { + if (!dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled) { + continue; + } + dirtylimit_adjust_throttle(cpu); + } + dirtylimit_state_unlock(); + } +} + +void dirtylimit_change(bool start) +{ + if (start) { + qatomic_set(&dirtylimit_quit, 0); + } else { + qatomic_set(&dirtylimit_quit, 1); + } +} + +void dirtylimit_set_vcpu(int cpu_index, + uint64_t quota, + bool enable) +{ + trace_dirtylimit_set_vcpu(cpu_index, quota); + + if (enable) { + dirtylimit_state->states[cpu_index].quota = quota; + if (!dirtylimit_vcpu_get_state(cpu_index)->enabled) { + dirtylimit_state->limited_nvcpu++; + } + } else { + dirtylimit_state->states[cpu_index].quota = 0; + if (dirtylimit_state->states[cpu_index].enabled) { + dirtylimit_state->limited_nvcpu--; + } + } + + dirtylimit_state->states[cpu_index].enabled = enable; +} + +void dirtylimit_set_all(uint64_t quota, + bool enable) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + int max_cpus = ms->smp.max_cpus; + int i; + + for (i = 0; i < max_cpus; i++) { + dirtylimit_set_vcpu(i, quota, enable); + } +} + +void dirtylimit_vcpu_execute(CPUState *cpu) +{ + if (dirtylimit_in_service() && + dirtylimit_vcpu_get_state(cpu->cpu_index)->enabled && + cpu->throttle_us_per_full) { + trace_dirtylimit_vcpu_execute(cpu->cpu_index, + cpu->throttle_us_per_full); + usleep(cpu->throttle_us_per_full); + } +} + +static void dirtylimit_init(void) +{ + dirtylimit_state_initialize(); + dirtylimit_change(true); + vcpu_dirty_rate_stat_initialize(); + vcpu_dirty_rate_stat_start(); +} + +static void dirtylimit_cleanup(void) +{ + vcpu_dirty_rate_stat_stop(); + vcpu_dirty_rate_stat_finalize(); + dirtylimit_change(false); + dirtylimit_state_finalize(); +} + +void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, + int64_t cpu_index, + Error **errp) +{ + if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { + return; + } + + if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { + error_setg(errp, "incorrect cpu index specified"); + return; + } + + if (!dirtylimit_in_service()) { + return; + } + + dirtylimit_state_lock(); + + if (has_cpu_index) { + dirtylimit_set_vcpu(cpu_index, 0, false); + } else { + dirtylimit_set_all(0, false); + } + + if (!dirtylimit_state->limited_nvcpu) { + dirtylimit_cleanup(); + } + + dirtylimit_state_unlock(); +} + +void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) +{ + int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); + Error *err = NULL; + + qmp_cancel_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, &err); + if (err) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " + "dirty limit for virtual CPU]\n"); +} + +void qmp_set_vcpu_dirty_limit(bool has_cpu_index, + int64_t cpu_index, + uint64_t dirty_rate, + Error **errp) +{ + if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { + error_setg(errp, "dirty page limit feature requires KVM with" + " accelerator property 'dirty-ring-size' set'"); + return; + } + + if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) { + error_setg(errp, "incorrect cpu index specified"); + return; + } + + if (!dirty_rate) { + qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp); + return; + } + + dirtylimit_state_lock(); + + if (!dirtylimit_in_service()) { + dirtylimit_init(); + } + + if (has_cpu_index) { + dirtylimit_set_vcpu(cpu_index, dirty_rate, true); + } else { + dirtylimit_set_all(dirty_rate, true); + } + + dirtylimit_state_unlock(); +} + +void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) +{ + int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); + int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); + Error *err = NULL; + + qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); + if (err) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " + "dirty limit for virtual CPU]\n"); +} + +static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) +{ + DirtyLimitInfo *info = NULL; + + info = g_malloc0(sizeof(*info)); + info->cpu_index = cpu_index; + info->limit_rate = dirtylimit_vcpu_get_state(cpu_index)->quota; + info->current_rate = vcpu_dirty_rate_get(cpu_index); + + return info; +} + +static struct DirtyLimitInfoList *dirtylimit_query_all(void) +{ + int i, index; + DirtyLimitInfo *info = NULL; + DirtyLimitInfoList *head = NULL, **tail = &head; + + dirtylimit_state_lock(); + + if (!dirtylimit_in_service()) { + dirtylimit_state_unlock(); + return NULL; + } + + for (i = 0; i < dirtylimit_state->max_cpus; i++) { + index = dirtylimit_state->states[i].cpu_index; + if (dirtylimit_vcpu_get_state(index)->enabled) { + info = dirtylimit_query_vcpu(index); + QAPI_LIST_APPEND(tail, info); + } + } + + dirtylimit_state_unlock(); + + return head; +} + +struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) +{ + if (!dirtylimit_in_service()) { + return NULL; + } + + return dirtylimit_query_all(); +} + +void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) +{ + DirtyLimitInfoList *limit, *head, *info = NULL; + Error *err = NULL; + + if (!dirtylimit_in_service()) { + monitor_printf(mon, "Dirty page limit not enabled!\n"); + return; + } + + info = qmp_query_vcpu_dirty_limit(&err); + if (err) { + hmp_handle_error(mon, err); + return; + } + + head = info; + for (limit = head; limit != NULL; limit = limit->next) { + monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," + " current rate %"PRIi64 " (MB/s)\n", + limit->value->cpu_index, + limit->value->limit_rate, + limit->value->current_rate); + } + + g_free(info); +} diff --git a/softmmu/globals.c b/softmmu/globals.c index 3ebd718e35da..527edbefdd07 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -40,6 +40,7 @@ int nb_nics; NICInfo nd_table[MAX_NICS]; int autostart = 1; int vga_interface_type = VGA_NONE; +bool vga_interface_created; Chardev *parallel_hds[MAX_PARALLEL_PORTS]; int win2k_install_hack; int singlestep; @@ -49,12 +50,8 @@ QEMUOptionRom option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int old_param; const char *qemu_name; -int alt_grab; -int ctrl_grab; unsigned int nb_prom_envs; const char *prom_envs[MAX_PROM_ENVS]; -int boot_menu; -bool boot_strict; uint8_t *boot_splash_filedata; int only_migratable; /* turn it off unless user states otherwise */ int icount_align_option; diff --git a/softmmu/icount.c b/softmmu/icount.c index 21341a4ce49e..4504433e1687 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "migration/vmstate.h" #include "qapi/error.h" @@ -323,7 +322,7 @@ void icount_start_warp_timer(void) * to vCPU was processed in advance and vCPU went to sleep. * Therefore we have to wake it up for doing someting. */ - if (replay_has_checkpoint()) { + if (replay_has_event()) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } return; @@ -405,6 +404,8 @@ void icount_account_warp_timer(void) return; } + replay_async_events(); + /* warp clock deterministically in record/replay mode */ if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_ACCOUNT)) { return; @@ -487,3 +488,11 @@ void icount_configure(QemuOpts *opts, Error **errp) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); } + +void icount_notify_exit(void) +{ + if (icount_enabled() && current_cpu) { + qemu_cpu_kick(current_cpu); + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } +} diff --git a/softmmu/main.c b/softmmu/main.c index 639c67ff4893..694388bd7f7f 100644 --- a/softmmu/main.c +++ b/softmmu/main.c @@ -23,32 +23,27 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu-main.h" #include "sysemu/sysemu.h" #ifdef CONFIG_SDL -#if defined(__APPLE__) || defined(main) #include -static int qemu_main(int argc, char **argv, char **envp); -int main(int argc, char **argv) -{ - return qemu_main(argc, argv, NULL); -} -#undef main -#define main qemu_main #endif -#endif /* CONFIG_SDL */ -#ifdef CONFIG_COCOA -#undef main -#define main qemu_main -#endif /* CONFIG_COCOA */ - -int 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; + +int main(int argc, char **argv) +{ + qemu_init(argc, argv); + return qemu_main(); } diff --git a/softmmu/memory.c b/softmmu/memory.c index bfa5d5178c5b..e05332d07fe5 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -33,6 +33,7 @@ #include "qemu/accel.h" #include "hw/boards.h" #include "migration/vmstate.h" +#include "exec/address-spaces.h" //#define DEBUG_UNASSIGNED @@ -350,7 +351,7 @@ static void flatview_simplify(FlatView *view) static bool memory_region_big_endian(MemoryRegion *mr) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN return mr->ops->endianness != DEVICE_LITTLE_ENDIAN; #else return mr->ops->endianness == DEVICE_BIG_ENDIAN; @@ -2121,6 +2122,77 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, rdmc->unregister_listener(rdm, rdl); } +/* Called with rcu_read_lock held. */ +bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only, + bool *mr_has_discard_manager) +{ + MemoryRegion *mr; + hwaddr xlat; + hwaddr len = iotlb->addr_mask + 1; + bool writable = iotlb->perm & IOMMU_WO; + + if (mr_has_discard_manager) { + *mr_has_discard_manager = false; + } + /* + * The IOMMU TLB entry we have just covers translation through + * this IOMMU to its immediate target. We need to translate + * it the rest of the way through to memory. + */ + mr = address_space_translate(&address_space_memory, iotlb->translated_addr, + &xlat, &len, writable, MEMTXATTRS_UNSPECIFIED); + if (!memory_region_is_ram(mr)) { + error_report("iommu map to non memory area %" HWADDR_PRIx "", xlat); + return false; + } else if (memory_region_has_ram_discard_manager(mr)) { + RamDiscardManager *rdm = memory_region_get_ram_discard_manager(mr); + MemoryRegionSection tmp = { + .mr = mr, + .offset_within_region = xlat, + .size = int128_make64(len), + }; + if (mr_has_discard_manager) { + *mr_has_discard_manager = true; + } + /* + * Malicious VMs can map memory into the IOMMU, which is expected + * to remain discarded. vfio will pin all pages, populating memory. + * Disallow that. vmstate priorities make sure any RamDiscardManager + * were already restored before IOMMUs are restored. + */ + if (!ram_discard_manager_is_populated(rdm, &tmp)) { + error_report("iommu map to discarded memory (e.g., unplugged via" + " virtio-mem): %" HWADDR_PRIx "", + iotlb->translated_addr); + return false; + } + } + + /* + * Translation truncates length to the IOMMU page size, + * check that it did not truncate too much. + */ + if (len & iotlb->addr_mask) { + error_report("iommu has granularity incompatible with target AS"); + return false; + } + + if (vaddr) { + *vaddr = memory_region_get_ram_ptr(mr) + xlat; + } + + if (ram_addr) { + *ram_addr = memory_region_get_ram_addr(mr) + xlat; + } + + if (read_only) { + *read_only = !writable || mr->readonly; + } + + return true; +} + void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) { uint8_t mask = 1 << client; @@ -2300,20 +2372,15 @@ void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr, int memory_region_get_fd(MemoryRegion *mr) { - int fd; - RCU_READ_LOCK_GUARD(); while (mr->alias) { mr = mr->alias; } - fd = mr->ram_block->fd; - - return fd; + return mr->ram_block->fd; } void *memory_region_get_ram_ptr(MemoryRegion *mr) { - void *ptr; uint64_t offset = 0; RCU_READ_LOCK_GUARD(); @@ -2322,9 +2389,7 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) mr = mr->alias; } assert(mr->ram_block); - ptr = qemu_map_ram_ptr(mr->ram_block, offset); - - return ptr; + return qemu_map_ram_ptr(mr->ram_block, offset); } MemoryRegion *memory_region_from_host(void *ptr, ram_addr_t *offset) diff --git a/softmmu/meson.build b/softmmu/meson.build index 8138248661a2..3272af1f3120 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -4,6 +4,7 @@ specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( 'memory.c', 'physmem.c', 'qtest.c', + 'dirtylimit.c', )]) specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: [files( diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 4e1b27a20ecc..edec095c7a5f 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "exec/page-vary.h" #include "qapi/error.h" #include "qemu/cutils.h" @@ -669,7 +669,7 @@ void tcg_iommu_init_notifier_list(CPUState *cpu) /* Called from RCU critical section */ MemoryRegionSection * -address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, +address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr orig_addr, hwaddr *xlat, hwaddr *plen, MemTxAttrs attrs, int *prot) { @@ -678,6 +678,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, IOMMUMemoryRegionClass *imrc; IOMMUTLBEntry iotlb; int iommu_idx; + hwaddr addr = orig_addr; AddressSpaceDispatch *d = qatomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); @@ -722,6 +723,16 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, return section; translate_fail: + /* + * We should be given a page-aligned address -- certainly + * tlb_set_page_with_attrs() does so. The page offset of xlat + * is used to index sections[], and PHYS_SECTION_UNASSIGNED = 0. + * The page portion of xlat will be logged by memory_region_access_valid() + * when this memory access is rejected, so use the original untranslated + * physical address. + */ + assert((orig_addr & ~TARGET_PAGE_MASK) == 0); + *xlat = orig_addr; return &d->map.sections[PHYS_SECTION_UNASSIGNED]; } @@ -1320,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; @@ -1380,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) @@ -1754,6 +1748,11 @@ void qemu_ram_unset_migratable(RAMBlock *rb) rb->flags &= ~RAM_MIGRATABLE; } +int qemu_ram_get_fd(RAMBlock *rb) +{ + return rb->fd; +} + /* Called with iothread lock held. */ void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev) { @@ -2163,7 +2162,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size, new_block->max_length = max_size; assert(max_size >= size); new_block->fd = -1; - new_block->page_size = qemu_real_host_page_size; + new_block->page_size = qemu_real_host_page_size(); new_block->host = host; new_block->flags = ram_flags; ram_block_add(new_block, &local_err); @@ -2449,6 +2448,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, @@ -2719,7 +2730,7 @@ void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size) invalidate_and_set_dirty(mr, addr, size); } -static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) +int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) { unsigned access_size_max = mr->ops->valid.max_access_size; @@ -2746,7 +2757,7 @@ static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) return l; } -static bool prepare_mmio_access(MemoryRegion *mr) +bool prepare_mmio_access(MemoryRegion *mr) { bool release_lock = false; @@ -3225,7 +3236,6 @@ void *address_space_map(AddressSpace *as, hwaddr len = *plen; hwaddr l, xlat; MemoryRegion *mr; - void *ptr; FlatView *fv; if (len == 0) { @@ -3264,9 +3274,7 @@ void *address_space_map(AddressSpace *as, *plen = flatview_extend_translation(fv, addr, len, mr, xlat, l, is_write, attrs); fuzz_dma_read_cb(addr, *plen, mr); - ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true); - - return ptr; + return qemu_ram_ptr_length(mr->ram_block, xlat, plen, true); } /* Unmaps a memory region previously mapped by address_space_map(). @@ -3534,15 +3542,13 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr) { MemoryRegion*mr; hwaddr l = 1; - bool res; RCU_READ_LOCK_GUARD(); mr = address_space_translate(&address_space_memory, phys_addr, &phys_addr, &l, false, MEMTXATTRS_UNSPECIFIED); - res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr)); - return res; + return !(memory_region_is_ram(mr) || memory_region_is_romd(mr)); } int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque) @@ -3701,7 +3707,7 @@ void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root) " %s%s%s%s%s", i, s->offset_within_address_space, - s->offset_within_address_space + MR_SIZE(s->mr->size), + s->offset_within_address_space + MR_SIZE(s->size), s->mr->name ? s->mr->name : "(noname)", i < ARRAY_SIZE(names) ? names[i] : "", s->mr == root ? " [ROOT]" : "", diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index 12fe60c4670d..4b0ef6578090 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -60,7 +60,8 @@ typedef struct QDevAlias QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ - QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) + QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ + QEMU_ARCH_LOONGARCH) #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) @@ -898,6 +899,10 @@ void qdev_unplug(DeviceState *dev, Error **errp) HotplugHandlerClass *hdc; Error *local_err = NULL; + if (qdev_unplug_blocked(dev, errp)) { + return; + } + if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) { error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); return; diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c index deaf8a4ef5aa..d66a2a12262c 100644 --- a/softmmu/qemu-seccomp.c +++ b/softmmu/qemu-seccomp.c @@ -312,6 +312,19 @@ static int seccomp_start(uint32_t seccomp_opts, Error **errp) goto seccomp_return; } +#if defined(CONFIG_SECCOMP_SYSRAWRC) + /* + * This must be the first seccomp_attr_set() call to have full + * error propagation from subsequent seccomp APIs. + */ + rc = seccomp_attr_set(ctx, SCMP_FLTATR_API_SYSRAWRC, 1); + if (rc != 0) { + error_setg_errno(errp, -rc, + "failed to set seccomp rawrc attribute"); + goto seccomp_return; + } +#endif + rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_TSYNC, 1); if (rc != 0) { error_setg_errno(errp, -rc, diff --git a/softmmu/qtest.c b/softmmu/qtest.c index cc586233a974..d3e0ab4eda26 100644 --- a/softmmu/qtest.c +++ b/softmmu/qtest.c @@ -58,12 +58,12 @@ static FILE *qtest_log_fp; static QTest *qtest; static GString *inbuf; static int irq_levels[MAX_IRQ]; -static qemu_timeval start_time; +static GTimer *timer; static bool qtest_opened; static void (*qtest_server_send)(void*, const char*); static void *qtest_server_send_opaque; -#define FMT_timeval "%ld.%06ld" +#define FMT_timeval "%.06f" /** * DOC: QTest Protocol @@ -264,28 +264,13 @@ static int hex2nib(char ch) } } -static void qtest_get_time(qemu_timeval *tv) -{ - qemu_gettimeofday(tv); - tv->tv_sec -= start_time.tv_sec; - tv->tv_usec -= start_time.tv_usec; - if (tv->tv_usec < 0) { - tv->tv_usec += 1000000; - tv->tv_sec -= 1; - } -} - static void qtest_send_prefix(CharBackend *chr) { - qemu_timeval tv; - if (!qtest_log_fp || !qtest_opened) { return; } - qtest_get_time(&tv); - fprintf(qtest_log_fp, "[S +" FMT_timeval "] ", - (long) tv.tv_sec, (long) tv.tv_usec); + fprintf(qtest_log_fp, "[S +" FMT_timeval "] ", g_timer_elapsed(timer, NULL)); } static void G_GNUC_PRINTF(1, 2) qtest_log_send(const char *fmt, ...) @@ -386,12 +371,9 @@ static void qtest_process_command(CharBackend *chr, gchar **words) command = words[0]; if (qtest_log_fp) { - qemu_timeval tv; int i; - qtest_get_time(&tv); - fprintf(qtest_log_fp, "[R +" FMT_timeval "]", - (long) tv.tv_sec, (long) tv.tv_usec); + fprintf(qtest_log_fp, "[R +" FMT_timeval "]", g_timer_elapsed(timer, NULL)); for (i = 0; words[i]; i++) { fprintf(qtest_log_fp, " %s", words[i]); } @@ -732,7 +714,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) qtest_send(chr, "OK\n"); } else if (strcmp(words[0], "endianness") == 0) { qtest_send_prefix(chr); -#if defined(TARGET_WORDS_BIGENDIAN) +#if TARGET_BIG_ENDIAN qtest_sendf(chr, "OK big\n"); #else qtest_sendf(chr, "OK little\n"); @@ -771,12 +753,18 @@ static void qtest_process_command(CharBackend *chr, gchar **words) qtest_sendf(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } else if (strcmp(words[0], "module_load") == 0) { + Error *local_err = NULL; + int rv; g_assert(words[1] && words[2]); qtest_send_prefix(chr); - if (module_load_one(words[1], words[2], false)) { + rv = module_load(words[1], words[2], &local_err); + if (rv > 0) { qtest_sendf(chr, "OK\n"); } else { + if (rv < 0) { + error_report_err(local_err); + } qtest_sendf(chr, "FAIL\n"); } } else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) { @@ -846,21 +834,20 @@ static void qtest_event(void *opaque, QEMUChrEvent event) for (i = 0; i < ARRAY_SIZE(irq_levels); i++) { irq_levels[i] = 0; } - qemu_gettimeofday(&start_time); + + g_clear_pointer(&timer, g_timer_destroy); + timer = g_timer_new(); qtest_opened = true; if (qtest_log_fp) { - fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n", - (long) start_time.tv_sec, (long) start_time.tv_usec); + fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n", g_timer_elapsed(timer, NULL)); } break; case CHR_EVENT_CLOSED: qtest_opened = false; if (qtest_log_fp) { - qemu_timeval tv; - qtest_get_time(&tv); - fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n", - (long) tv.tv_sec, (long) tv.tv_usec); + fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n", g_timer_elapsed(timer, NULL)); } + g_clear_pointer(&timer, g_timer_destroy); break; default: break; @@ -996,7 +983,7 @@ static void qtest_set_log(Object *obj, const char *value, Error **errp) QTest *q = QTEST(obj); if (qtest == q) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property 'log' can not be set now"); } else { g_free(q->log); q->log = g_strdup(value); @@ -1016,7 +1003,7 @@ static void qtest_set_chardev(Object *obj, const char *value, Error **errp) Chardev *chr; if (qtest == q) { - error_setg(errp, QERR_PERMISSION_DENIED); + error_setg(errp, "Property 'chardev' can not be set now"); return; } diff --git a/softmmu/runstate.c b/softmmu/runstate.c index e0d869b21aa4..cab9f6fc075b 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -40,7 +40,6 @@ #include "qapi/error.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-events-run-state.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/job.h" @@ -127,6 +126,7 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH }, { RUN_STATE_COLO, RUN_STATE_RUNNING }, + { RUN_STATE_COLO, RUN_STATE_PRELAUNCH }, { RUN_STATE_COLO, RUN_STATE_SHUTDOWN}, { RUN_STATE_RUNNING, RUN_STATE_DEBUG }, @@ -441,11 +441,16 @@ void qemu_system_reset(ShutdownCause reason) cpu_synchronize_all_states(); if (mc && mc->reset) { - mc->reset(current_machine); + mc->reset(current_machine, reason); } else { - qemu_devices_reset(); + qemu_devices_reset(reason); } - if (reason && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { + switch (reason) { + case SHUTDOWN_CAUSE_NONE: + case SHUTDOWN_CAUSE_SUBSYSTEM_RESET: + case SHUTDOWN_CAUSE_SNAPSHOT_LOAD: + break; + default: qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); } cpu_synchronize_all_post_reset(); @@ -479,17 +484,15 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) */ if (panic_action == PANIC_ACTION_PAUSE || (panic_action == PANIC_ACTION_SHUTDOWN && shutdown_action == SHUTDOWN_ACTION_PAUSE)) { - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, - !!info, info); + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, info); vm_stop(RUN_STATE_GUEST_PANICKED); - } else if (panic_action == PANIC_ACTION_SHUTDOWN) { - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_POWEROFF, - !!info, info); + } else if (panic_action == PANIC_ACTION_SHUTDOWN || + panic_action == PANIC_ACTION_EXIT_FAILURE) { + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_POWEROFF, info); vm_stop(RUN_STATE_GUEST_PANICKED); qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC); } else { - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_RUN, - !!info, info); + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_RUN, info); } if (info) { @@ -516,13 +519,8 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) void qemu_system_guest_crashloaded(GuestPanicInformation *info) { qemu_log_mask(LOG_GUEST_ERROR, "Guest crash loaded"); - - qapi_event_send_guest_crashloaded(GUEST_PANIC_ACTION_RUN, - !!info, info); - - if (info) { - qapi_free_GuestPanicInformation(info); - } + qapi_event_send_guest_crashloaded(GUEST_PANIC_ACTION_RUN, info); + qapi_free_GuestPanicInformation(info); } void qemu_system_reset_request(ShutdownCause reason) @@ -662,7 +660,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 +678,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 +717,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 +733,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/trace-events b/softmmu/trace-events index 9c88887b3c64..22606dc27b31 100644 --- a/softmmu/trace-events +++ b/softmmu/trace-events @@ -31,3 +31,10 @@ runstate_set(int current_state, const char *current_state_str, int new_state, co system_wakeup_request(int reason) "reason=%d" qemu_system_shutdown_request(int reason) "reason=%d" qemu_system_powerdown_request(void) "" + +#dirtylimit.c +dirtylimit_state_initialize(int max_cpus) "dirtylimit state initialize: max cpus %d" +dirtylimit_state_finalize(void) +dirtylimit_throttle_pct(int cpu_index, uint64_t pct, int64_t time_us) "CPU[%d] throttle percent: %" PRIu64 ", throttle adjust time %"PRIi64 " us" +dirtylimit_set_vcpu(int cpu_index, uint64_t quota) "CPU[%d] set dirty page rate limit %"PRIu64 +dirtylimit_vcpu_execute(int cpu_index, int64_t sleep_time_us) "CPU[%d] sleep %"PRIi64 " us" diff --git a/softmmu/vl.c b/softmmu/vl.c index 6f646531a0ae..9bd0e52d016a 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -23,10 +23,11 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "exec/cpu-common.h" +#include "exec/page-vary.h" #include "hw/qdev-properties.h" #include "qapi/compat-policy.h" #include "qapi/error.h" @@ -52,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" @@ -115,8 +115,11 @@ #include "crypto/init.h" #include "sysemu/replay.h" #include "qapi/qapi-events-run-state.h" +#include "qapi/qapi-types-audio.h" +#include "qapi/qapi-visit-audio.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qapi-visit-compat.h" +#include "qapi/qapi-visit-machine.h" #include "qapi/qapi-visit-ui.h" #include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-commands-migration.h" @@ -124,9 +127,11 @@ #include "qapi/qapi-visit-qom.h" #include "qapi/qapi-commands-ui.h" #include "qapi/qmp/qdict.h" +#include "block/qdict.h" #include "qapi/qmp/qerror.h" #include "sysemu/iothread.h" #include "qemu/guest-random.h" +#include "qemu/keyval.h" #include "config-host.h" @@ -156,11 +161,11 @@ static const char *mem_path; static const char *incoming; static const char *loadvm; static const char *accelerators; +static bool have_custom_ram_size; +static const char *ram_memdev_id; static QDict *machine_opts_dict; static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts); static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts); -static ram_addr_t maxram_size; -static uint64_t ram_slots; static int display_remote; static int snapshot; static bool preconfig_requested; @@ -168,7 +173,6 @@ static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); static bool nographic = false; static int mem_prealloc; /* force preallocation of physical target memory */ -static ram_addr_t ram_size; static const char *vga_model = NULL; static DisplayOptions dpy; static int num_serial_hds; @@ -176,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; @@ -608,7 +611,7 @@ static int parse_add_fd(void *opaque, QemuOpts *opts, Error **errp) } /* add the duplicate fd, and optionally the opaque string, to the fd set */ - fdinfo = monitor_fdset_add_fd(dupfd, true, fdset_id, !!fd_opaque, fd_opaque, + fdinfo = monitor_fdset_add_fd(dupfd, true, fdset_id, fd_opaque, &error_abort); g_free(fdinfo); @@ -931,10 +934,12 @@ static const VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = { .name = "CG3 framebuffer", .class_names = { "cgthree" }, }, +#ifdef CONFIG_XEN_BACKEND [VGA_XENFB] = { .opt_name = "xenfb", .name = "Xen paravirtualized framebuffer", }, +#endif }; static bool vga_interface_available(VGAInterfaceType t) @@ -974,7 +979,8 @@ static void select_vgahw(const MachineClass *machine_class, const char *p) if (vga_interface_available(t) && ti->opt_name) { printf("%-20s %s%s\n", ti->opt_name, ti->name ?: "", - g_str_equal(ti->opt_name, def) ? " (default)" : ""); + (def && g_str_equal(ti->opt_name, def)) ? + " (default)" : ""); } } exit(0); @@ -1040,100 +1046,7 @@ static void parse_display(const char *p) exit(0); } - if (strstart(p, "sdl", &opts)) { - /* - * sdl DisplayType needs hand-crafted parser instead of - * parse_display_qapi() due to some options not in - * DisplayOptions, specifically: - * - ctrl_grab + alt_grab - * They can't be moved into the QAPI since they use underscores, - * thus they will get replaced by "grab-mod" in the long term - */ -#if defined(CONFIG_SDL) - dpy.type = DISPLAY_TYPE_SDL; - while (*opts) { - const char *nextopt; - - if (strstart(opts, ",grab-mod=", &nextopt)) { - opts = nextopt; - if (strstart(opts, "lshift-lctrl-lalt", &nextopt)) { - alt_grab = 1; - } else if (strstart(opts, "rctrl", &nextopt)) { - ctrl_grab = 1; - } else { - goto invalid_sdl_args; - } - } else if (strstart(opts, ",alt_grab=", &nextopt)) { - opts = nextopt; - if (strstart(opts, "on", &nextopt)) { - alt_grab = 1; - } else if (strstart(opts, "off", &nextopt)) { - alt_grab = 0; - } else { - goto invalid_sdl_args; - } - warn_report("alt_grab is deprecated, use grab-mod instead."); - } else if (strstart(opts, ",ctrl_grab=", &nextopt)) { - opts = nextopt; - if (strstart(opts, "on", &nextopt)) { - ctrl_grab = 1; - } else if (strstart(opts, "off", &nextopt)) { - ctrl_grab = 0; - } else { - goto invalid_sdl_args; - } - warn_report("ctrl_grab is deprecated, use grab-mod instead."); - } else if (strstart(opts, ",window_close=", &nextopt) || - strstart(opts, ",window-close=", &nextopt)) { - if (strstart(opts, ",window_close=", NULL)) { - warn_report("window_close with an underscore is deprecated," - " please use window-close instead."); - } - opts = nextopt; - dpy.has_window_close = true; - if (strstart(opts, "on", &nextopt)) { - dpy.window_close = true; - } else if (strstart(opts, "off", &nextopt)) { - dpy.window_close = false; - } else { - goto invalid_sdl_args; - } - } else if (strstart(opts, ",show-cursor=", &nextopt)) { - opts = nextopt; - dpy.has_show_cursor = true; - if (strstart(opts, "on", &nextopt)) { - dpy.show_cursor = true; - } else if (strstart(opts, "off", &nextopt)) { - dpy.show_cursor = false; - } else { - goto invalid_sdl_args; - } - } else if (strstart(opts, ",gl=", &nextopt)) { - opts = nextopt; - dpy.has_gl = true; - if (strstart(opts, "on", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_ON; - } else if (strstart(opts, "core", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_CORE; - } else if (strstart(opts, "es", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_ES; - } else if (strstart(opts, "off", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_OFF; - } else { - goto invalid_sdl_args; - } - } else { - invalid_sdl_args: - error_report("invalid SDL option string"); - exit(1); - } - opts = nextopt; - } -#else - error_report("SDL display supported is not available in this binary"); - exit(1); -#endif - } else if (strstart(p, "vnc", &opts)) { + if (strstart(p, "vnc", &opts)) { /* * vnc isn't a (local) DisplayType but a protocol for remote * display access. @@ -1348,6 +1261,7 @@ static void qemu_disable_default_devices(void) if (!vga_model && !default_vga) { vga_interface_type = VGA_DEVICE; + vga_interface_created = true; } if (!has_defaults || machine_class->no_serial) { default_serial = 0; @@ -1606,13 +1520,18 @@ machine_parse_property_opt(QemuOptsList *opts_list, const char *propname, } static const char *pid_file; -static Notifier qemu_unlink_pidfile_notifier; +struct UnlinkPidfileNotifier { + Notifier notifier; + char *pid_file_realpath; +}; +static struct UnlinkPidfileNotifier qemu_unlink_pidfile_notifier; static void qemu_unlink_pidfile(Notifier *n, void *data) { - if (pid_file) { - unlink(pid_file); - } + struct UnlinkPidfileNotifier *upn; + + upn = DO_UPCAST(struct UnlinkPidfileNotifier, notifier, n); + unlink(upn->pid_file_realpath); } static const QEMUOption *lookup_opt(int argc, char **argv, @@ -1730,6 +1649,7 @@ static void keyval_dashify(QDict *qdict, Error **errp) static void qemu_apply_legacy_machine_options(QDict *qdict) { const char *value; + QObject *prop; keyval_dashify(qdict, &error_fatal); @@ -1762,6 +1682,26 @@ static void qemu_apply_legacy_machine_options(QDict *qdict) false); qdict_del(qdict, "kernel-irqchip"); } + + value = qdict_get_try_str(qdict, "memory-backend"); + if (value) { + if (mem_path) { + error_report("'-mem-path' can't be used together with" + "'-machine memory-backend'"); + exit(EXIT_FAILURE); + } + + /* Resolved later. */ + ram_memdev_id = g_strdup(value); + qdict_del(qdict, "memory-backend"); + } + + prop = qdict_get(qdict, "memory"); + if (prop) { + have_custom_ram_size = + qobject_type(prop) == QTYPE_QDICT && + qdict_haskey(qobject_to(QDict, prop), "size"); + } } static void object_option_foreach_add(bool (*type_opt_predicate)(const char *)) @@ -1819,6 +1759,27 @@ static void object_option_parse(const char *optarg) visit_free(v); } +/* + * Very early object creation, before the sandbox options have been activated. + */ +static bool object_create_pre_sandbox(const char *type) +{ + /* + * Objects should in general not get initialized "too early" without + * a reason. If you add one, state the reason in a comment! + */ + + /* + * Reason: -sandbox on,resourcecontrol=deny disallows setting CPU + * affinity of threads. + */ + if (g_str_equal(type, "thread-context")) { + return true; + } + + return false; +} + /* * Initial object creation happens before all other * QEMU data types are created. The majority of objects @@ -1833,6 +1794,11 @@ static bool object_create_early(const char *type) * add one, state the reason in a comment! */ + /* Reason: already created. */ + if (object_create_pre_sandbox(type)) { + return false; + } + /* Reason: property "chardev" */ if (g_str_equal(type, "rng-egd") || g_str_equal(type, "qtest")) { @@ -1878,40 +1844,9 @@ static bool object_create_early(const char *type) static void qemu_apply_machine_options(QDict *qdict) { - MachineClass *machine_class = MACHINE_GET_CLASS(current_machine); - const char *boot_order = NULL; - const char *boot_once = NULL; - QemuOpts *opts; - object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); - current_machine->ram_size = ram_size; - current_machine->maxram_size = maxram_size; - current_machine->ram_slots = ram_slots; - - opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); - if (opts) { - boot_order = qemu_opt_get(opts, "order"); - if (boot_order) { - validate_bootdevices(boot_order, &error_fatal); - } - boot_once = qemu_opt_get(opts, "once"); - if (boot_once) { - validate_bootdevices(boot_once, &error_fatal); - } - - boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu); - boot_strict = qemu_opt_get_bool(opts, "strict", false); - } - - if (!boot_order) { - boot_order = machine_class->default_boot_order; - } - - current_machine->boot_order = boot_order; - current_machine->boot_once = boot_once; - - 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); } @@ -1937,10 +1872,6 @@ static void qemu_create_early_backends(void) const bool use_gtk = false; #endif - if ((alt_grab || ctrl_grab) && !use_sdl) { - error_report("-alt-grab and -ctrl-grab are only valid " - "for SDL, ignoring option"); - } if (dpy.has_window_close && !use_gtk && !use_sdl) { error_report("window-close is only valid for GTK and SDL, " "ignoring option"); @@ -1978,7 +1909,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); + } } @@ -1988,7 +1921,7 @@ static void qemu_create_early_backends(void) */ static bool object_create_late(const char *type) { - return !object_create_early(type); + return !object_create_early(type) && !object_create_pre_sandbox(type); } static void qemu_create_late_backends(void) @@ -1997,7 +1930,7 @@ static void qemu_create_late_backends(void) qtest_server_init(qtest_chrdev, qtest_log, &error_fatal); } - net_init_clients(&error_fatal); + net_init_clients(); object_option_foreach_add(object_create_late); @@ -2016,128 +1949,64 @@ static void qemu_create_late_backends(void) exit(1); /* now chardevs have been created we may have semihosting to connect */ - qemu_semihosting_connect_chardevs(); - qemu_semihosting_console_init(); -} - -static bool have_custom_ram_size(void) -{ - QemuOpts *opts = qemu_find_opts_singleton("memory"); - return !!qemu_opt_get_size(opts, "size", 0); + qemu_semihosting_chardev_init(); } static void qemu_resolve_machine_memdev(void) { - if (current_machine->ram_memdev_id) { + if (ram_memdev_id) { Object *backend; ram_addr_t backend_size; - backend = object_resolve_path_type(current_machine->ram_memdev_id, + backend = object_resolve_path_type(ram_memdev_id, TYPE_MEMORY_BACKEND, NULL); if (!backend) { - error_report("Memory backend '%s' not found", - current_machine->ram_memdev_id); + error_report("Memory backend '%s' not found", ram_memdev_id); exit(EXIT_FAILURE); } - backend_size = object_property_get_uint(backend, "size", &error_abort); - if (have_custom_ram_size() && backend_size != ram_size) { - error_report("Size specified by -m option must match size of " - "explicitly specified 'memory-backend' property"); - exit(EXIT_FAILURE); - } - if (mem_path) { - error_report("'-mem-path' can't be used together with" - "'-machine memory-backend'"); - exit(EXIT_FAILURE); - } - ram_size = backend_size; - } - - if (!xen_enabled()) { - /* On 32-bit hosts, QEMU is limited by virtual address space */ - if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { - error_report("at most 2047 MB RAM can be simulated"); - exit(1); + if (!have_custom_ram_size) { + backend_size = object_property_get_uint(backend, "size", &error_abort); + current_machine->ram_size = backend_size; } + object_property_set_link(OBJECT(current_machine), + "memory-backend", backend, &error_fatal); } } -static void set_memory_options(MachineClass *mc) +static void parse_memory_options(void) { - uint64_t sz; - const char *mem_str; - const ram_addr_t default_ram_size = mc->default_ram_size; QemuOpts *opts = qemu_find_opts_singleton("memory"); + QDict *dict, *prop; + const char *mem_str; Location loc; loc_push_none(&loc); qemu_opts_loc_restore(opts); - sz = 0; - mem_str = qemu_opt_get(opts, "size"); - if (mem_str) { - if (!*mem_str) { - error_report("missing 'size' option value"); - exit(EXIT_FAILURE); - } - - sz = qemu_opt_get_size(opts, "size", ram_size); + prop = qdict_new(); + if (qemu_opt_get_size(opts, "size", 0) != 0) { /* Fix up legacy suffix-less format */ + mem_str = qemu_opt_get(opts, "size"); if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) { - uint64_t overflow_check = sz; - - sz *= MiB; - if (sz / MiB != overflow_check) { - error_report("too large 'size' option value"); - exit(EXIT_FAILURE); - } + g_autofree char *mib_str = g_strdup_printf("%sM", mem_str); + qdict_put_str(prop, "size", mib_str); + } else { + qdict_put_str(prop, "size", mem_str); } } - /* backward compatibility behaviour for case "-m 0" */ - if (sz == 0) { - sz = default_ram_size; - } - - sz = QEMU_ALIGN_UP(sz, 8192); - if (mc->fixup_ram_size) { - sz = mc->fixup_ram_size(sz); - } - ram_size = sz; - if (ram_size != sz) { - error_report("ram size too large"); - exit(EXIT_FAILURE); - } - - maxram_size = ram_size; - if (qemu_opt_get(opts, "maxmem")) { - uint64_t slots; - - sz = qemu_opt_get_size(opts, "maxmem", 0); - slots = qemu_opt_get_number(opts, "slots", 0); - if (sz < ram_size) { - error_report("invalid value of -m option maxmem: " - "maximum memory size (0x%" PRIx64 ") must be at least " - "the initial memory size (0x" RAM_ADDR_FMT ")", - sz, ram_size); - exit(EXIT_FAILURE); - } else if (slots && sz == ram_size) { - error_report("invalid value of -m option maxmem: " - "memory slots were specified but maximum memory size " - "(0x%" PRIx64 ") is equal to the initial memory size " - "(0x" RAM_ADDR_FMT ")", sz, ram_size); - exit(EXIT_FAILURE); - } - - maxram_size = sz; - ram_slots = slots; - } else if (qemu_opt_get(opts, "slots")) { - error_report("invalid -m option value: missing 'maxmem' option"); - exit(EXIT_FAILURE); + qdict_put_str(prop, "max-size", qemu_opt_get(opts, "maxmem")); + } + if (qemu_opt_get(opts, "slots")) { + qdict_put_str(prop, "slots", qemu_opt_get(opts, "slots")); } + dict = qdict_new(); + qdict_put(dict, "memory", prop); + keyval_merge(machine_opts_dict, dict, &error_fatal); + qobject_unref(dict); loc_pop(&loc); } @@ -2146,8 +2015,6 @@ static void qemu_create_machine(QDict *qdict) MachineClass *machine_class = select_machine(qdict, &error_fatal); object_set_machine_compat_props(machine_class->compat_props); - set_memory_options(machine_class); - current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class))); object_property_add_child(object_get_root(), "machine", OBJECT(current_machine)); @@ -2206,7 +2073,8 @@ 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, "smp-opts") || + g_str_equal(group, "boot-opts")) { return false; } return true; @@ -2228,6 +2096,8 @@ static void qemu_record_config_group(const char *group, QDict *dict, keyval_merge(machine_opts_dict, dict, errp); } else if (g_str_equal(group, "smp-opts")) { machine_merge_property("smp", dict, &error_fatal); + } else if (g_str_equal(group, "boot-opts")) { + machine_merge_property("boot", dict, &error_fatal); } else { abort(); } @@ -2424,8 +2294,7 @@ static void configure_accelerators(const char *progname) } if (init_failed && !qtest_chrdev) { - AccelClass *ac = ACCEL_GET_CLASS(current_accel()); - error_report("falling back to %s", ac->name); + error_report("falling back to %s", current_accel_name()); } if (icount_enabled() && !tcg_enabled()) { @@ -2434,27 +2303,6 @@ static void configure_accelerators(const char *progname) } } -static void create_default_memdev(MachineState *ms, const char *path) -{ - Object *obj; - MachineClass *mc = MACHINE_GET_CLASS(ms); - - obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); - if (path) { - object_property_set_str(obj, "mem-path", path, &error_fatal); - } - object_property_set_int(obj, "size", ms->ram_size, &error_fatal); - object_property_add_child(object_get_objects_root(), mc->default_ram_id, - obj); - /* Ensure backend's memory region name is equal to mc->default_ram_id */ - object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", - false, &error_fatal); - user_creatable_complete(USER_CREATABLE(obj), &error_fatal); - object_unref(obj); - object_property_set_str(OBJECT(ms), "memory-backend", mc->default_ram_id, - &error_fatal); -} - static void qemu_validate_options(const QDict *machine_opts) { const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel"); @@ -2505,12 +2353,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 */ @@ -2535,6 +2377,11 @@ static int process_runstate_actions(void *opaque, QemuOpts *opts, Error **errp) static void qemu_process_early_options(void) { + qemu_opts_foreach(qemu_find_opts("name"), + parse_name, NULL, &error_fatal); + + object_option_foreach_add(object_create_pre_sandbox); + #ifdef CONFIG_SECCOMP QemuOptsList *olist = qemu_find_opts_err("sandbox", NULL); if (olist) { @@ -2542,9 +2389,6 @@ static void qemu_process_early_options(void) } #endif - qemu_opts_foreach(qemu_find_opts("name"), - parse_name, NULL, &error_fatal); - if (qemu_opts_foreach(qemu_find_opts("action"), process_runstate_actions, NULL, &error_fatal)) { exit(1); @@ -2559,19 +2403,16 @@ static void qemu_process_early_options(void) #endif /* Open the logfile at this point and set the log mask if necessary. */ - if (log_file) { - qemu_set_log_filename(log_file, &error_fatal); - } - if (log_mask) { - int mask; - mask = qemu_str_to_log_mask(log_mask); - if (!mask) { - qemu_print_log_usage(stdout); - exit(1); + { + int mask = 0; + if (log_mask) { + mask = qemu_str_to_log_mask(log_mask); + if (!mask) { + qemu_print_log_usage(stdout); + exit(1); + } } - qemu_set_log(mask); - } else { - qemu_set_log(0); + qemu_set_log_filename_flags(log_file, mask, &error_fatal); } qemu_add_default_firmwarepath(); @@ -2609,13 +2450,30 @@ static void qemu_maybe_daemonize(const char *pid_file) os_daemonize(); rcu_disable_atfork(); - if (pid_file && !qemu_write_pidfile(pid_file, &err)) { - error_reportf_err(err, "cannot create PID file: "); - exit(1); - } + if (pid_file) { + char *pid_file_realpath = NULL; + + if (!qemu_write_pidfile(pid_file, &err)) { + error_reportf_err(err, "cannot create PID file: "); + exit(1); + } + + pid_file_realpath = g_malloc0(PATH_MAX); + if (!realpath(pid_file, pid_file_realpath)) { + error_report("cannot resolve PID file path: %s: %s", + pid_file, strerror(errno)); + unlink(pid_file); + exit(1); + } - qemu_unlink_pidfile_notifier.notify = qemu_unlink_pidfile; - qemu_add_exit_notifier(&qemu_unlink_pidfile_notifier); + qemu_unlink_pidfile_notifier = (struct UnlinkPidfileNotifier) { + .notifier = { + .notify = qemu_unlink_pidfile, + }, + .pid_file_realpath = pid_file_realpath, + }; + qemu_add_exit_notifier(&qemu_unlink_pidfile_notifier.notifier); + } } static void qemu_init_displays(void) @@ -2642,18 +2500,11 @@ static void qemu_init_displays(void) static void qemu_init_board(void) { - MachineClass *machine_class = MACHINE_GET_CLASS(current_machine); - - if (machine_class->default_ram_id && current_machine->ram_size && - numa_uses_legacy_mem() && !current_machine->ram_memdev_id) { - create_default_memdev(current_machine, mem_path); - } - /* process plugin before CPUs are created, but once -smp has been parsed */ qemu_plugin_load_list(&plugin_list, &error_fatal); /* From here on we enter MACHINE_PHASE_INITIALIZED. */ - machine_run_board_init(current_machine); + machine_run_board_init(current_machine, mem_path, &error_fatal); drive_check_orphaned(); @@ -2734,6 +2585,12 @@ static void qemu_machine_creation_done(void) if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { exit(1); } + if (!vga_interface_created && !default_vga && + vga_interface_type != VGA_NONE) { + warn_report("A -vga option was passed but this machine " + "type does not use that option; " + "No VGA device has been created"); + } } void qmp_x_exit_preconfig(Error **errp) @@ -2768,7 +2625,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; @@ -2933,16 +2790,6 @@ void qemu_init(int argc, char **argv, char **envp) nographic = true; dpy.type = DISPLAY_TYPE_NONE; break; - case QEMU_OPTION_curses: - warn_report("-curses is deprecated, " - "use -display curses instead."); -#ifdef CONFIG_CURSES - dpy.type = DISPLAY_TYPE_CURSES; -#else - error_report("curses or iconv support is disabled"); - exit(1); -#endif - break; case QEMU_OPTION_portrait: graphic_rotate = 90; break; @@ -2970,11 +2817,7 @@ void qemu_init(int argc, char **argv, char **envp) drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); break; case QEMU_OPTION_boot: - opts = qemu_opts_parse_noisily(qemu_find_opts("boot-opts"), - optarg, true); - if (!opts) { - exit(1); - } + machine_parse_property_opt(qemu_find_opts("boot-opts"), "boot", optarg); break; case QEMU_OPTION_fda: case QEMU_OPTION_fdb: @@ -2986,21 +2829,19 @@ void qemu_init(int argc, char **argv, char **envp) break; case QEMU_OPTION_netdev: default_net = 0; - if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) { - exit(1); + if (netdev_is_modern(optarg)) { + netdev_parse_modern(optarg); + } else { + net_client_parse(qemu_find_opts("netdev"), optarg); } break; case QEMU_OPTION_nic: default_net = 0; - if (net_client_parse(qemu_find_opts("nic"), optarg) == -1) { - exit(1); - } + net_client_parse(qemu_find_opts("nic"), optarg); break; case QEMU_OPTION_net: default_net = 0; - if (net_client_parse(qemu_find_opts("net"), optarg) == -1) { - exit(1); - } + net_client_parse(qemu_find_opts("net"), optarg); break; #ifdef CONFIG_LIBISCSI case QEMU_OPTION_iscsi: @@ -3018,9 +2859,38 @@ void qemu_init(int argc, char **argv, char **envp) case QEMU_OPTION_audiodev: audio_parse_option(optarg); break; - case QEMU_OPTION_soundhw: - select_soundhw (optarg); + case QEMU_OPTION_audio: { + 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"); + } + if (!qdict_haskey(dict, "model")) { + error_setg(&error_fatal, "Parameter 'model' is missing"); + } + model = g_strdup(qdict_get_str(dict, "model")); + qdict_del(dict, "model"); + if (is_help_option(model)) { + show_valid_soundhw(); + exit(0); + } + v = qobject_input_visitor_new_keyval(QOBJECT(dict)); + qobject_unref(dict); + visit_type_Audiodev(v, NULL, &dev, &error_fatal); + visit_free(v); + audio_define(dev); + select_soundhw(model, dev->id); + g_free(model); break; + } case QEMU_OPTION_h: help(0); break; @@ -3029,10 +2899,9 @@ void qemu_init(int argc, char **argv, char **envp) exit(0); break; case QEMU_OPTION_m: - opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), - optarg, true); - if (!opts) { - exit(EXIT_FAILURE); + opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), optarg, true); + if (opts == NULL) { + exit(1); } break; #ifdef CONFIG_TPM @@ -3256,14 +3125,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)) { @@ -3293,25 +3154,6 @@ void qemu_init(int argc, char **argv, char **envp) dpy.has_full_screen = true; dpy.full_screen = true; break; - case QEMU_OPTION_alt_grab: - alt_grab = 1; - warn_report("-alt-grab is deprecated, please use " - "-display sdl,grab-mod=lshift-lctrl-lalt instead."); - break; - case QEMU_OPTION_ctrl_grab: - ctrl_grab = 1; - warn_report("-ctrl-grab is deprecated, please use " - "-display sdl,grab-mod=rctrl instead."); - break; - case QEMU_OPTION_sdl: - warn_report("-sdl is deprecated, use -display sdl instead."); -#ifdef CONFIG_SDL - dpy.type = DISPLAY_TYPE_SDL; - break; -#else - error_report("SDL support is disabled"); - exit(1); -#endif case QEMU_OPTION_pidfile: pid_file = optarg; break; @@ -3417,6 +3259,7 @@ void qemu_init(int argc, char **argv, char **envp) qdict_put_str(machine_opts_dict, "acpi", "off"); break; case QEMU_OPTION_no_hpet: + warn_report("-no-hpet is deprecated, use '-machine hpet=off' instead"); qdict_put_str(machine_opts_dict, "hpet", "off"); break; case QEMU_OPTION_no_reboot: @@ -3551,26 +3394,6 @@ void qemu_init(int argc, char **argv, char **envp) display_remote++; break; #endif - case QEMU_OPTION_writeconfig: - { - FILE *fp; - warn_report("-writeconfig is deprecated and will go away without a replacement"); - if (strcmp(optarg, "-") == 0) { - fp = stdout; - } else { - fp = fopen(optarg, "w"); - if (fp == NULL) { - error_report("open %s: %s", optarg, - strerror(errno)); - exit(1); - } - } - qemu_config_write(fp); - if (fp != stdout) { - fclose(fp); - } - break; - } case QEMU_OPTION_qtest: qtest_chrdev = optarg; break; @@ -3705,6 +3528,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(); @@ -3743,7 +3569,7 @@ void qemu_init(int argc, char **argv, char **envp) machine_class = MACHINE_GET_CLASS(current_machine); if (!qtest_enabled() && machine_class->deprecation_reason) { - error_report("Machine type '%s' is deprecated: %s", + warn_report("Machine type '%s' is deprecated: %s", machine_class->name, machine_class->deprecation_reason); } diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c index eb724072579a..7718f6dcda30 100644 --- a/storage-daemon/qemu-storage-daemon.c +++ b/storage-daemon/qemu-storage-daemon.c @@ -42,8 +42,9 @@ #include "qapi/qmp/qstring.h" #include "qapi/qobject-input-visitor.h" -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "qemu-version.h" +#include "qemu/cutils.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/help_option.h" @@ -60,6 +61,7 @@ #include "trace/control.h" static const char *pid_file; +static char *pid_file_realpath; static volatile bool exit_requested = false; void qemu_system_killed(int signal, pid_t pid) @@ -120,6 +122,16 @@ static void help(void) " vhost-user-blk device over file descriptor\n" "\n" #endif /* CONFIG_VHOST_USER_BLK_SERVER */ +#ifdef CONFIG_VDUSE_BLK_EXPORT +" --export [type=]vduse-blk,id=,node-name=\n" +" ,name=[,writable=on|off]\n" +" [,num-queues=][,queue-size=]\n" +" [,logical-block-size=]\n" +" [,serial=]\n" +" export the specified block node as a\n" +" vduse-blk device\n" +"\n" +#endif /* CONFIG_VDUSE_BLK_EXPORT */ " --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n" " configure a QMP monitor\n" "\n" @@ -285,7 +297,11 @@ static void process_options(int argc, char *argv[], bool pre_init_pass) } case OPTION_DAEMONIZE: if (os_set_daemonize(true) < 0) { - error_report("--daemonize not supported in this build"); + /* + * --daemonize is parsed before monitor_init_globals_core(), so + * error_report() does not work yet + */ + fprintf(stderr, "--daemonize not supported in this build\n"); exit(EXIT_FAILURE); } break; @@ -348,7 +364,7 @@ static void process_options(int argc, char *argv[], bool pre_init_pass) static void pid_file_cleanup(void) { - unlink(pid_file); + unlink(pid_file_realpath); } static void pid_file_init(void) @@ -364,6 +380,14 @@ static void pid_file_init(void) exit(EXIT_FAILURE); } + pid_file_realpath = g_malloc(PATH_MAX); + if (!realpath(pid_file, pid_file_realpath)) { + error_report("cannot resolve PID file path: %s: %s", + pid_file, strerror(errno)); + unlink(pid_file); + exit(EXIT_FAILURE); + } + atexit(pid_file_cleanup); } @@ -392,7 +416,7 @@ int main(int argc, char *argv[]) if (!trace_init_backends()) { return EXIT_FAILURE; } - qemu_set_log(LOG_TRACE); + qemu_set_log(LOG_TRACE, &error_fatal); qemu_init_main_loop(&error_fatal); process_options(argc, argv, false); diff --git a/stubs/error-printf.c b/stubs/error-printf.c index a2f61521a16f..0e326d801059 100644 --- a/stubs/error-printf.c +++ b/stubs/error-printf.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "monitor/monitor.h" int error_vprintf(const char *fmt, va_list ap) { diff --git a/stubs/get-vm-name.c b/stubs/get-vm-name.c index fa990136b068..0906303f7306 100644 --- a/stubs/get-vm-name.c +++ b/stubs/get-vm-name.c @@ -1,5 +1,5 @@ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "sysemu/sysemu.h" const char *qemu_get_vm_name(void) { diff --git a/stubs/graph-lock.c b/stubs/graph-lock.c new file mode 100644 index 000000000000..177aa0a8ba5a --- /dev/null +++ b/stubs/graph-lock.c @@ -0,0 +1,10 @@ +#include "qemu/osdep.h" +#include "block/graph-lock.h" + +void register_aiocontext(AioContext *ctx) +{ +} + +void unregister_aiocontext(AioContext *ctx) +{ +} diff --git a/stubs/icount.c b/stubs/icount.c index f13c43568bce..6df8c2bf7d44 100644 --- a/stubs/icount.c +++ b/stubs/icount.c @@ -43,3 +43,7 @@ void icount_account_warp_timer(void) { abort(); } + +void icount_notify_exit(void) +{ +} diff --git a/stubs/meson.build b/stubs/meson.build index 6f80fec76174..981585cbdf0e 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -13,6 +13,7 @@ stub_ss.add(files('error-printf.c')) stub_ss.add(files('fdset.c')) stub_ss.add(files('gdbstub.c')) stub_ss.add(files('get-vm-name.c')) +stub_ss.add(files('graph-lock.c')) if linux_io_uring.found() stub_ss.add(files('io_uring.c')) endif @@ -29,6 +30,7 @@ stub_ss.add(files('migr-blocker.c')) stub_ss.add(files('module-opts.c')) stub_ss.add(files('monitor.c')) stub_ss.add(files('monitor-core.c')) +stub_ss.add(files('physmem.c')) stub_ss.add(files('qemu-timer-notify-cb.c')) stub_ss.add(files('qmp_memory_device.c')) stub_ss.add(files('qmp-command-available.c')) @@ -48,7 +50,7 @@ stub_ss.add(files('vmstate.c')) stub_ss.add(files('vm-stop.c')) stub_ss.add(files('win32-kbd-hook.c')) stub_ss.add(files('cpu-synchronize-state.c')) -if have_block +if have_block or have_ga stub_ss.add(files('replay-tools.c')) endif if have_system @@ -60,3 +62,4 @@ if have_system else stub_ss.add(files('qdev.c')) endif +stub_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_false: files('vfio-user-obj.c')) diff --git a/stubs/monitor-core.c b/stubs/monitor-core.c index d058a2a00d85..afa477aae656 100644 --- a/stubs/monitor-core.c +++ b/stubs/monitor-core.c @@ -1,6 +1,5 @@ #include "qemu/osdep.h" #include "monitor/monitor.h" -#include "qemu-common.h" #include "qapi/qapi-emit-events.h" Monitor *monitor_cur(void) diff --git a/stubs/physmem.c b/stubs/physmem.c new file mode 100644 index 000000000000..1fc5f2df29fa --- /dev/null +++ b/stubs/physmem.c @@ -0,0 +1,13 @@ +#include "qemu/osdep.h" +#include "exec/cpu-common.h" + +RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset, + ram_addr_t *offset) +{ + return NULL; +} + +int qemu_ram_get_fd(RAMBlock *rb) +{ + return -1; +} diff --git a/stubs/qdev.c b/stubs/qdev.c index 187659f7071a..6869f6f90a29 100644 --- a/stubs/qdev.c +++ b/stubs/qdev.c @@ -15,15 +15,13 @@ #include "qemu/osdep.h" #include "qapi/qapi-events-qdev.h" -void qapi_event_send_device_deleted(bool has_device, - const char *device, +void qapi_event_send_device_deleted(const char *device, const char *path) { /* Nothing to do. */ } -void qapi_event_send_device_unplug_guest_error(bool has_device, - const char *device, +void qapi_event_send_device_unplug_guest_error(const char *device, const char *path) { /* Nothing to do. */ diff --git a/stubs/replay-tools.c b/stubs/replay-tools.c index 43296b3d4eb7..3e8ca3212d97 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 4bf2cf71b9b4..d65c9fd5dcf4 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; } @@ -65,10 +65,6 @@ void semihosting_arg_fallback(const char *file, const char *cmd) { } -void qemu_semihosting_connect_chardevs(void) -{ -} - -void qemu_semihosting_console_init(void) +void qemu_semihosting_chardev_init(void) { } diff --git a/stubs/vfio-user-obj.c b/stubs/vfio-user-obj.c new file mode 100644 index 000000000000..79100d768e2a --- /dev/null +++ b/stubs/vfio-user-obj.c @@ -0,0 +1,6 @@ +#include "qemu/osdep.h" +#include "hw/remote/vfio-user-obj.h" + +void vfu_object_set_bus_irq(PCIBus *pci_bus) +{ +} diff --git a/stubs/xen-hw-stub.c b/stubs/xen-hw-stub.c index 15f3921a76b0..34a22f2ad72e 100644 --- a/stubs/xen-hw-stub.c +++ b/stubs/xen-hw-stub.c @@ -19,8 +19,9 @@ void xen_piix3_set_irq(void *opaque, int irq_num, int level) { } -void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) +int xen_set_pci_link_route(uint8_t link, uint8_t irq) { + return -1; } void xen_hvm_inject_msi(uint64_t addr, uint32_t data) diff --git a/subprojects/libvduse/include/atomic.h b/subprojects/libvduse/include/atomic.h new file mode 120000 index 000000000000..8c2be64f7b17 --- /dev/null +++ b/subprojects/libvduse/include/atomic.h @@ -0,0 +1 @@ +../../../include/qemu/atomic.h \ No newline at end of file diff --git a/subprojects/libvduse/include/compiler.h b/subprojects/libvduse/include/compiler.h new file mode 120000 index 000000000000..de7b70697cd2 --- /dev/null +++ b/subprojects/libvduse/include/compiler.h @@ -0,0 +1 @@ +../../../include/qemu/compiler.h \ No newline at end of file diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c new file mode 100644 index 000000000000..377959a0b4fb --- /dev/null +++ b/subprojects/libvduse/libvduse.c @@ -0,0 +1,1381 @@ +/* + * VDUSE (vDPA Device in Userspace) library + * + * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved. + * Portions of codes and concepts borrowed from libvhost-user.c, so: + * Copyright IBM, Corp. 2007 + * Copyright (c) 2016 Red Hat, Inc. + * + * Author: + * Xie Yongji + * Anthony Liguori + * Marc-André Lureau + * Victor Kaplansky + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "include/atomic.h" +#include "linux-headers/linux/virtio_ring.h" +#include "linux-headers/linux/virtio_config.h" +#include "linux-headers/linux/vduse.h" +#include "libvduse.h" + +#define VDUSE_VQ_ALIGN 4096 +#define MAX_IOVA_REGIONS 256 + +#define LOG_ALIGNMENT 64 + +/* Round number down to multiple */ +#define ALIGN_DOWN(n, m) ((n) / (m) * (m)) + +/* Round number up to multiple */ +#define ALIGN_UP(n, m) ALIGN_DOWN((n) + (m) - 1, (m)) + +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +typedef struct VduseDescStateSplit { + uint8_t inflight; + uint8_t padding[5]; + uint16_t next; + uint64_t counter; +} VduseDescStateSplit; + +typedef struct VduseVirtqLogInflight { + uint64_t features; + uint16_t version; + uint16_t desc_num; + uint16_t last_batch_head; + uint16_t used_idx; + VduseDescStateSplit desc[]; +} VduseVirtqLogInflight; + +typedef struct VduseVirtqLog { + VduseVirtqLogInflight inflight; +} VduseVirtqLog; + +typedef struct VduseVirtqInflightDesc { + uint16_t index; + uint64_t counter; +} VduseVirtqInflightDesc; + +typedef struct VduseRing { + unsigned int num; + uint64_t desc_addr; + uint64_t avail_addr; + uint64_t used_addr; + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; +} VduseRing; + +struct VduseVirtq { + VduseRing vring; + uint16_t last_avail_idx; + uint16_t shadow_avail_idx; + uint16_t used_idx; + uint16_t signalled_used; + bool signalled_used_valid; + int index; + unsigned int inuse; + bool ready; + int fd; + VduseDev *dev; + VduseVirtqInflightDesc *resubmit_list; + uint16_t resubmit_num; + uint64_t counter; + VduseVirtqLog *log; +}; + +typedef struct VduseIovaRegion { + uint64_t iova; + uint64_t size; + uint64_t mmap_offset; + uint64_t mmap_addr; +} VduseIovaRegion; + +struct VduseDev { + VduseVirtq *vqs; + VduseIovaRegion regions[MAX_IOVA_REGIONS]; + int num_regions; + char *name; + uint32_t device_id; + uint32_t vendor_id; + uint16_t num_queues; + uint16_t queue_size; + uint64_t features; + const VduseOps *ops; + int fd; + int ctrl_fd; + void *priv; + void *log; +}; + +static inline size_t vduse_vq_log_size(uint16_t queue_size) +{ + return ALIGN_UP(sizeof(VduseDescStateSplit) * queue_size + + sizeof(VduseVirtqLogInflight), LOG_ALIGNMENT); +} + +static void *vduse_log_get(const char *filename, size_t size) +{ + void *ptr = MAP_FAILED; + int fd; + + fd = open(filename, O_RDWR | O_CREAT, 0600); + if (fd == -1) { + return MAP_FAILED; + } + + if (ftruncate(fd, size) == -1) { + goto out; + } + + ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + +out: + close(fd); + return ptr; +} + +static inline bool has_feature(uint64_t features, unsigned int fbit) +{ + assert(fbit < 64); + return !!(features & (1ULL << fbit)); +} + +static inline bool vduse_dev_has_feature(VduseDev *dev, unsigned int fbit) +{ + return has_feature(dev->features, fbit); +} + +uint64_t vduse_get_virtio_features(void) +{ + return (1ULL << VIRTIO_F_IOMMU_PLATFORM) | + (1ULL << VIRTIO_F_VERSION_1) | + (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | + (1ULL << VIRTIO_RING_F_EVENT_IDX) | + (1ULL << VIRTIO_RING_F_INDIRECT_DESC); +} + +VduseDev *vduse_queue_get_dev(VduseVirtq *vq) +{ + return vq->dev; +} + +int vduse_queue_get_fd(VduseVirtq *vq) +{ + return vq->fd; +} + +void *vduse_dev_get_priv(VduseDev *dev) +{ + return dev->priv; +} + +VduseVirtq *vduse_dev_get_queue(VduseDev *dev, int index) +{ + return &dev->vqs[index]; +} + +int vduse_dev_get_fd(VduseDev *dev) +{ + return dev->fd; +} + +static int vduse_inject_irq(VduseDev *dev, int index) +{ + return ioctl(dev->fd, VDUSE_VQ_INJECT_IRQ, &index); +} + +static int inflight_desc_compare(const void *a, const void *b) +{ + VduseVirtqInflightDesc *desc0 = (VduseVirtqInflightDesc *)a, + *desc1 = (VduseVirtqInflightDesc *)b; + + if (desc1->counter > desc0->counter && + (desc1->counter - desc0->counter) < VIRTQUEUE_MAX_SIZE * 2) { + return 1; + } + + return -1; +} + +static int vduse_queue_check_inflights(VduseVirtq *vq) +{ + int i = 0; + VduseDev *dev = vq->dev; + + vq->used_idx = le16toh(vq->vring.used->idx); + vq->resubmit_num = 0; + vq->resubmit_list = NULL; + vq->counter = 0; + + if (unlikely(vq->log->inflight.used_idx != vq->used_idx)) { + if (vq->log->inflight.last_batch_head > VIRTQUEUE_MAX_SIZE) { + return -1; + } + + vq->log->inflight.desc[vq->log->inflight.last_batch_head].inflight = 0; + + barrier(); + + vq->log->inflight.used_idx = vq->used_idx; + } + + for (i = 0; i < vq->log->inflight.desc_num; i++) { + if (vq->log->inflight.desc[i].inflight == 1) { + vq->inuse++; + } + } + + vq->shadow_avail_idx = vq->last_avail_idx = vq->inuse + vq->used_idx; + + if (vq->inuse) { + vq->resubmit_list = calloc(vq->inuse, sizeof(VduseVirtqInflightDesc)); + if (!vq->resubmit_list) { + return -1; + } + + for (i = 0; i < vq->log->inflight.desc_num; i++) { + if (vq->log->inflight.desc[i].inflight) { + vq->resubmit_list[vq->resubmit_num].index = i; + vq->resubmit_list[vq->resubmit_num].counter = + vq->log->inflight.desc[i].counter; + vq->resubmit_num++; + } + } + + if (vq->resubmit_num > 1) { + qsort(vq->resubmit_list, vq->resubmit_num, + sizeof(VduseVirtqInflightDesc), inflight_desc_compare); + } + vq->counter = vq->resubmit_list[0].counter + 1; + } + + vduse_inject_irq(dev, vq->index); + + return 0; +} + +static int vduse_queue_inflight_get(VduseVirtq *vq, int desc_idx) +{ + vq->log->inflight.desc[desc_idx].counter = vq->counter++; + + barrier(); + + vq->log->inflight.desc[desc_idx].inflight = 1; + + return 0; +} + +static int vduse_queue_inflight_pre_put(VduseVirtq *vq, int desc_idx) +{ + vq->log->inflight.last_batch_head = desc_idx; + + return 0; +} + +static int vduse_queue_inflight_post_put(VduseVirtq *vq, int desc_idx) +{ + vq->log->inflight.desc[desc_idx].inflight = 0; + + barrier(); + + vq->log->inflight.used_idx = vq->used_idx; + + return 0; +} + +static void vduse_iova_remove_region(VduseDev *dev, uint64_t start, + uint64_t last) +{ + int i; + + if (last == start) { + return; + } + + for (i = 0; i < MAX_IOVA_REGIONS; i++) { + if (!dev->regions[i].mmap_addr) { + continue; + } + + if (start <= dev->regions[i].iova && + last >= (dev->regions[i].iova + dev->regions[i].size - 1)) { + munmap((void *)(uintptr_t)dev->regions[i].mmap_addr, + dev->regions[i].mmap_offset + dev->regions[i].size); + dev->regions[i].mmap_addr = 0; + dev->num_regions--; + } + } +} + +static int vduse_iova_add_region(VduseDev *dev, int fd, + uint64_t offset, uint64_t start, + uint64_t last, int prot) +{ + int i; + uint64_t size = last - start + 1; + void *mmap_addr = mmap(0, size + offset, prot, MAP_SHARED, fd, 0); + + if (mmap_addr == MAP_FAILED) { + close(fd); + return -EINVAL; + } + + for (i = 0; i < MAX_IOVA_REGIONS; i++) { + if (!dev->regions[i].mmap_addr) { + dev->regions[i].mmap_addr = (uint64_t)(uintptr_t)mmap_addr; + dev->regions[i].mmap_offset = offset; + dev->regions[i].iova = start; + dev->regions[i].size = size; + dev->num_regions++; + break; + } + } + assert(i < MAX_IOVA_REGIONS); + close(fd); + + return 0; +} + +static int perm_to_prot(uint8_t perm) +{ + int prot = 0; + + switch (perm) { + case VDUSE_ACCESS_WO: + prot |= PROT_WRITE; + break; + case VDUSE_ACCESS_RO: + prot |= PROT_READ; + break; + case VDUSE_ACCESS_RW: + prot |= PROT_READ | PROT_WRITE; + break; + default: + break; + } + + return prot; +} + +static inline void *iova_to_va(VduseDev *dev, uint64_t *plen, uint64_t iova) +{ + int i, ret; + struct vduse_iotlb_entry entry; + + for (i = 0; i < MAX_IOVA_REGIONS; i++) { + VduseIovaRegion *r = &dev->regions[i]; + + if (!r->mmap_addr) { + continue; + } + + if ((iova >= r->iova) && (iova < (r->iova + r->size))) { + if ((iova + *plen) > (r->iova + r->size)) { + *plen = r->iova + r->size - iova; + } + return (void *)(uintptr_t)(iova - r->iova + + r->mmap_addr + r->mmap_offset); + } + } + + entry.start = iova; + entry.last = iova + 1; + ret = ioctl(dev->fd, VDUSE_IOTLB_GET_FD, &entry); + if (ret < 0) { + return NULL; + } + + if (!vduse_iova_add_region(dev, ret, entry.offset, entry.start, + entry.last, perm_to_prot(entry.perm))) { + return iova_to_va(dev, plen, iova); + } + + return NULL; +} + +static inline uint16_t vring_avail_flags(VduseVirtq *vq) +{ + return le16toh(vq->vring.avail->flags); +} + +static inline uint16_t vring_avail_idx(VduseVirtq *vq) +{ + vq->shadow_avail_idx = le16toh(vq->vring.avail->idx); + + return vq->shadow_avail_idx; +} + +static inline uint16_t vring_avail_ring(VduseVirtq *vq, int i) +{ + return le16toh(vq->vring.avail->ring[i]); +} + +static inline uint16_t vring_get_used_event(VduseVirtq *vq) +{ + return vring_avail_ring(vq, vq->vring.num); +} + +static bool vduse_queue_get_head(VduseVirtq *vq, unsigned int idx, + unsigned int *head) +{ + /* + * Grab the next descriptor number they're advertising, and increment + * the index we've seen. + */ + *head = vring_avail_ring(vq, idx % vq->vring.num); + + /* If their number is silly, that's a fatal mistake. */ + if (*head >= vq->vring.num) { + fprintf(stderr, "Guest says index %u is available\n", *head); + return false; + } + + return true; +} + +static int +vduse_queue_read_indirect_desc(VduseDev *dev, struct vring_desc *desc, + uint64_t addr, size_t len) +{ + struct vring_desc *ori_desc; + uint64_t read_len; + + if (len > (VIRTQUEUE_MAX_SIZE * sizeof(struct vring_desc))) { + return -1; + } + + if (len == 0) { + return -1; + } + + while (len) { + read_len = len; + ori_desc = iova_to_va(dev, &read_len, addr); + if (!ori_desc) { + return -1; + } + + memcpy(desc, ori_desc, read_len); + len -= read_len; + addr += read_len; + desc += read_len; + } + + return 0; +} + +enum { + VIRTQUEUE_READ_DESC_ERROR = -1, + VIRTQUEUE_READ_DESC_DONE = 0, /* end of chain */ + VIRTQUEUE_READ_DESC_MORE = 1, /* more buffers in chain */ +}; + +static int vduse_queue_read_next_desc(struct vring_desc *desc, int i, + unsigned int max, unsigned int *next) +{ + /* If this descriptor says it doesn't chain, we're done. */ + if (!(le16toh(desc[i].flags) & VRING_DESC_F_NEXT)) { + return VIRTQUEUE_READ_DESC_DONE; + } + + /* Check they're not leading us off end of descriptors. */ + *next = desc[i].next; + /* Make sure compiler knows to grab that: we don't want it changing! */ + smp_wmb(); + + if (*next >= max) { + fprintf(stderr, "Desc next is %u\n", *next); + return VIRTQUEUE_READ_DESC_ERROR; + } + + return VIRTQUEUE_READ_DESC_MORE; +} + +/* + * Fetch avail_idx from VQ memory only when we really need to know if + * guest has added some buffers. + */ +static bool vduse_queue_empty(VduseVirtq *vq) +{ + if (unlikely(!vq->vring.avail)) { + return true; + } + + if (vq->shadow_avail_idx != vq->last_avail_idx) { + return false; + } + + return vring_avail_idx(vq) == vq->last_avail_idx; +} + +static bool vduse_queue_should_notify(VduseVirtq *vq) +{ + VduseDev *dev = vq->dev; + uint16_t old, new; + bool v; + + /* We need to expose used array entries before checking used event. */ + smp_mb(); + + /* Always notify when queue is empty (when feature acknowledge) */ + if (vduse_dev_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY) && + !vq->inuse && vduse_queue_empty(vq)) { + return true; + } + + if (!vduse_dev_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) { + return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT); + } + + v = vq->signalled_used_valid; + vq->signalled_used_valid = true; + old = vq->signalled_used; + new = vq->signalled_used = vq->used_idx; + return !v || vring_need_event(vring_get_used_event(vq), new, old); +} + +void vduse_queue_notify(VduseVirtq *vq) +{ + VduseDev *dev = vq->dev; + + if (unlikely(!vq->vring.avail)) { + return; + } + + if (!vduse_queue_should_notify(vq)) { + return; + } + + if (vduse_inject_irq(dev, vq->index) < 0) { + fprintf(stderr, "Error inject irq for vq %d: %s\n", + vq->index, strerror(errno)); + } +} + +static inline void vring_set_avail_event(VduseVirtq *vq, uint16_t val) +{ + uint16_t val_le = htole16(val); + memcpy(&vq->vring.used->ring[vq->vring.num], &val_le, sizeof(uint16_t)); +} + +static bool vduse_queue_map_single_desc(VduseVirtq *vq, unsigned int *p_num_sg, + struct iovec *iov, unsigned int max_num_sg, + bool is_write, uint64_t pa, size_t sz) +{ + unsigned num_sg = *p_num_sg; + VduseDev *dev = vq->dev; + + assert(num_sg <= max_num_sg); + + if (!sz) { + fprintf(stderr, "virtio: zero sized buffers are not allowed\n"); + return false; + } + + while (sz) { + uint64_t len = sz; + + if (num_sg == max_num_sg) { + fprintf(stderr, + "virtio: too many descriptors in indirect table\n"); + return false; + } + + iov[num_sg].iov_base = iova_to_va(dev, &len, pa); + if (iov[num_sg].iov_base == NULL) { + fprintf(stderr, "virtio: invalid address for buffers\n"); + return false; + } + iov[num_sg++].iov_len = len; + sz -= len; + pa += len; + } + + *p_num_sg = num_sg; + return true; +} + +static void *vduse_queue_alloc_element(size_t sz, unsigned out_num, + unsigned in_num) +{ + VduseVirtqElement *elem; + size_t in_sg_ofs = ALIGN_UP(sz, __alignof__(elem->in_sg[0])); + size_t out_sg_ofs = in_sg_ofs + in_num * sizeof(elem->in_sg[0]); + size_t out_sg_end = out_sg_ofs + out_num * sizeof(elem->out_sg[0]); + + assert(sz >= sizeof(VduseVirtqElement)); + elem = malloc(out_sg_end); + if (!elem) { + return NULL; + } + elem->out_num = out_num; + elem->in_num = in_num; + elem->in_sg = (void *)elem + in_sg_ofs; + elem->out_sg = (void *)elem + out_sg_ofs; + return elem; +} + +static void *vduse_queue_map_desc(VduseVirtq *vq, unsigned int idx, size_t sz) +{ + struct vring_desc *desc = vq->vring.desc; + VduseDev *dev = vq->dev; + uint64_t desc_addr, read_len; + unsigned int desc_len; + unsigned int max = vq->vring.num; + unsigned int i = idx; + VduseVirtqElement *elem; + struct iovec iov[VIRTQUEUE_MAX_SIZE]; + struct vring_desc desc_buf[VIRTQUEUE_MAX_SIZE]; + unsigned int out_num = 0, in_num = 0; + int rc; + + if (le16toh(desc[i].flags) & VRING_DESC_F_INDIRECT) { + if (le32toh(desc[i].len) % sizeof(struct vring_desc)) { + fprintf(stderr, "Invalid size for indirect buffer table\n"); + return NULL; + } + + /* loop over the indirect descriptor table */ + desc_addr = le64toh(desc[i].addr); + desc_len = le32toh(desc[i].len); + max = desc_len / sizeof(struct vring_desc); + read_len = desc_len; + desc = iova_to_va(dev, &read_len, desc_addr); + if (unlikely(desc && read_len != desc_len)) { + /* Failed to use zero copy */ + desc = NULL; + if (!vduse_queue_read_indirect_desc(dev, desc_buf, + desc_addr, + desc_len)) { + desc = desc_buf; + } + } + if (!desc) { + fprintf(stderr, "Invalid indirect buffer table\n"); + return NULL; + } + i = 0; + } + + /* Collect all the descriptors */ + do { + if (le16toh(desc[i].flags) & VRING_DESC_F_WRITE) { + if (!vduse_queue_map_single_desc(vq, &in_num, iov + out_num, + VIRTQUEUE_MAX_SIZE - out_num, + true, le64toh(desc[i].addr), + le32toh(desc[i].len))) { + return NULL; + } + } else { + if (in_num) { + fprintf(stderr, "Incorrect order for descriptors\n"); + return NULL; + } + if (!vduse_queue_map_single_desc(vq, &out_num, iov, + VIRTQUEUE_MAX_SIZE, false, + le64toh(desc[i].addr), + le32toh(desc[i].len))) { + return NULL; + } + } + + /* If we've got too many, that implies a descriptor loop. */ + if ((in_num + out_num) > max) { + fprintf(stderr, "Looped descriptor\n"); + return NULL; + } + rc = vduse_queue_read_next_desc(desc, i, max, &i); + } while (rc == VIRTQUEUE_READ_DESC_MORE); + + if (rc == VIRTQUEUE_READ_DESC_ERROR) { + fprintf(stderr, "read descriptor error\n"); + return NULL; + } + + /* Now copy what we have collected and mapped */ + elem = vduse_queue_alloc_element(sz, out_num, in_num); + if (!elem) { + fprintf(stderr, "read descriptor error\n"); + return NULL; + } + elem->index = idx; + for (i = 0; i < out_num; i++) { + elem->out_sg[i] = iov[i]; + } + for (i = 0; i < in_num; i++) { + elem->in_sg[i] = iov[out_num + i]; + } + + return elem; +} + +void *vduse_queue_pop(VduseVirtq *vq, size_t sz) +{ + unsigned int head; + VduseVirtqElement *elem; + VduseDev *dev = vq->dev; + int i; + + if (unlikely(!vq->vring.avail)) { + return NULL; + } + + if (unlikely(vq->resubmit_list && vq->resubmit_num > 0)) { + i = (--vq->resubmit_num); + elem = vduse_queue_map_desc(vq, vq->resubmit_list[i].index, sz); + + if (!vq->resubmit_num) { + free(vq->resubmit_list); + vq->resubmit_list = NULL; + } + + return elem; + } + + if (vduse_queue_empty(vq)) { + return NULL; + } + /* Needed after virtio_queue_empty() */ + smp_rmb(); + + if (vq->inuse >= vq->vring.num) { + fprintf(stderr, "Virtqueue size exceeded: %d\n", vq->inuse); + return NULL; + } + + if (!vduse_queue_get_head(vq, vq->last_avail_idx++, &head)) { + return NULL; + } + + if (vduse_dev_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) { + vring_set_avail_event(vq, vq->last_avail_idx); + } + + elem = vduse_queue_map_desc(vq, head, sz); + + if (!elem) { + return NULL; + } + + vq->inuse++; + + vduse_queue_inflight_get(vq, head); + + return elem; +} + +static inline void vring_used_write(VduseVirtq *vq, + struct vring_used_elem *uelem, int i) +{ + struct vring_used *used = vq->vring.used; + + used->ring[i] = *uelem; +} + +static void vduse_queue_fill(VduseVirtq *vq, const VduseVirtqElement *elem, + unsigned int len, unsigned int idx) +{ + struct vring_used_elem uelem; + + if (unlikely(!vq->vring.used)) { + return; + } + + idx = (idx + vq->used_idx) % vq->vring.num; + + uelem.id = htole32(elem->index); + uelem.len = htole32(len); + vring_used_write(vq, &uelem, idx); +} + +static inline void vring_used_idx_set(VduseVirtq *vq, uint16_t val) +{ + vq->vring.used->idx = htole16(val); + vq->used_idx = val; +} + +static void vduse_queue_flush(VduseVirtq *vq, unsigned int count) +{ + uint16_t old, new; + + if (unlikely(!vq->vring.used)) { + return; + } + + /* Make sure buffer is written before we update index. */ + smp_wmb(); + + old = vq->used_idx; + new = old + count; + vring_used_idx_set(vq, new); + vq->inuse -= count; + if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old))) { + vq->signalled_used_valid = false; + } +} + +void vduse_queue_push(VduseVirtq *vq, const VduseVirtqElement *elem, + unsigned int len) +{ + vduse_queue_fill(vq, elem, len, 0); + vduse_queue_inflight_pre_put(vq, elem->index); + vduse_queue_flush(vq, 1); + vduse_queue_inflight_post_put(vq, elem->index); +} + +static int vduse_queue_update_vring(VduseVirtq *vq, uint64_t desc_addr, + uint64_t avail_addr, uint64_t used_addr) +{ + struct VduseDev *dev = vq->dev; + uint64_t len; + + len = sizeof(struct vring_desc); + vq->vring.desc = iova_to_va(dev, &len, desc_addr); + if (len != sizeof(struct vring_desc)) { + return -EINVAL; + } + + len = sizeof(struct vring_avail); + vq->vring.avail = iova_to_va(dev, &len, avail_addr); + if (len != sizeof(struct vring_avail)) { + return -EINVAL; + } + + len = sizeof(struct vring_used); + vq->vring.used = iova_to_va(dev, &len, used_addr); + if (len != sizeof(struct vring_used)) { + return -EINVAL; + } + + if (!vq->vring.desc || !vq->vring.avail || !vq->vring.used) { + fprintf(stderr, "Failed to get vq[%d] iova mapping\n", vq->index); + return -EINVAL; + } + + return 0; +} + +static void vduse_queue_enable(VduseVirtq *vq) +{ + struct VduseDev *dev = vq->dev; + struct vduse_vq_info vq_info; + struct vduse_vq_eventfd vq_eventfd; + int fd; + + vq_info.index = vq->index; + if (ioctl(dev->fd, VDUSE_VQ_GET_INFO, &vq_info)) { + fprintf(stderr, "Failed to get vq[%d] info: %s\n", + vq->index, strerror(errno)); + return; + } + + if (!vq_info.ready) { + return; + } + + vq->vring.num = vq_info.num; + vq->vring.desc_addr = vq_info.desc_addr; + vq->vring.avail_addr = vq_info.driver_addr; + vq->vring.used_addr = vq_info.device_addr; + + if (vduse_queue_update_vring(vq, vq_info.desc_addr, + vq_info.driver_addr, vq_info.device_addr)) { + fprintf(stderr, "Failed to update vring for vq[%d]\n", vq->index); + return; + } + + fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "Failed to init eventfd for vq[%d]\n", vq->index); + return; + } + + vq_eventfd.index = vq->index; + vq_eventfd.fd = fd; + if (ioctl(dev->fd, VDUSE_VQ_SETUP_KICKFD, &vq_eventfd)) { + fprintf(stderr, "Failed to setup kick fd for vq[%d]\n", vq->index); + close(fd); + return; + } + + vq->fd = fd; + vq->signalled_used_valid = false; + vq->ready = true; + + if (vduse_queue_check_inflights(vq)) { + fprintf(stderr, "Failed to check inflights for vq[%d]\n", vq->index); + close(fd); + return; + } + + dev->ops->enable_queue(dev, vq); +} + +static void vduse_queue_disable(VduseVirtq *vq) +{ + struct VduseDev *dev = vq->dev; + struct vduse_vq_eventfd eventfd; + + if (!vq->ready) { + return; + } + + dev->ops->disable_queue(dev, vq); + + eventfd.index = vq->index; + eventfd.fd = VDUSE_EVENTFD_DEASSIGN; + ioctl(dev->fd, VDUSE_VQ_SETUP_KICKFD, &eventfd); + close(vq->fd); + + assert(vq->inuse == 0); + + vq->vring.num = 0; + vq->vring.desc_addr = 0; + vq->vring.avail_addr = 0; + vq->vring.used_addr = 0; + vq->vring.desc = 0; + vq->vring.avail = 0; + vq->vring.used = 0; + vq->ready = false; + vq->fd = -1; +} + +static void vduse_dev_start_dataplane(VduseDev *dev) +{ + int i; + + if (ioctl(dev->fd, VDUSE_DEV_GET_FEATURES, &dev->features)) { + fprintf(stderr, "Failed to get features: %s\n", strerror(errno)); + return; + } + assert(vduse_dev_has_feature(dev, VIRTIO_F_VERSION_1)); + + for (i = 0; i < dev->num_queues; i++) { + vduse_queue_enable(&dev->vqs[i]); + } +} + +static void vduse_dev_stop_dataplane(VduseDev *dev) +{ + size_t log_size = dev->num_queues * vduse_vq_log_size(VIRTQUEUE_MAX_SIZE); + int i; + + for (i = 0; i < dev->num_queues; i++) { + vduse_queue_disable(&dev->vqs[i]); + } + if (dev->log) { + memset(dev->log, 0, log_size); + } + dev->features = 0; + vduse_iova_remove_region(dev, 0, ULONG_MAX); +} + +int vduse_dev_handler(VduseDev *dev) +{ + struct vduse_dev_request req; + struct vduse_dev_response resp = { 0 }; + VduseVirtq *vq; + int i, ret; + + ret = read(dev->fd, &req, sizeof(req)); + if (ret != sizeof(req)) { + fprintf(stderr, "Read request error [%d]: %s\n", + ret, strerror(errno)); + return -errno; + } + resp.request_id = req.request_id; + + switch (req.type) { + case VDUSE_GET_VQ_STATE: + vq = &dev->vqs[req.vq_state.index]; + resp.vq_state.split.avail_index = vq->last_avail_idx; + resp.result = VDUSE_REQ_RESULT_OK; + break; + case VDUSE_SET_STATUS: + if (req.s.status & VIRTIO_CONFIG_S_DRIVER_OK) { + vduse_dev_start_dataplane(dev); + } else if (req.s.status == 0) { + vduse_dev_stop_dataplane(dev); + } + resp.result = VDUSE_REQ_RESULT_OK; + break; + case VDUSE_UPDATE_IOTLB: + /* The iova will be updated by iova_to_va() later, so just remove it */ + vduse_iova_remove_region(dev, req.iova.start, req.iova.last); + for (i = 0; i < dev->num_queues; i++) { + VduseVirtq *vq = &dev->vqs[i]; + if (vq->ready) { + if (vduse_queue_update_vring(vq, vq->vring.desc_addr, + vq->vring.avail_addr, + vq->vring.used_addr)) { + fprintf(stderr, "Failed to update vring for vq[%d]\n", + vq->index); + } + } + } + resp.result = VDUSE_REQ_RESULT_OK; + break; + default: + resp.result = VDUSE_REQ_RESULT_FAILED; + break; + } + + ret = write(dev->fd, &resp, sizeof(resp)); + if (ret != sizeof(resp)) { + fprintf(stderr, "Write request %d error [%d]: %s\n", + req.type, ret, strerror(errno)); + return -errno; + } + return 0; +} + +int vduse_dev_update_config(VduseDev *dev, uint32_t size, + uint32_t offset, char *buffer) +{ + int ret; + struct vduse_config_data *data; + + data = malloc(offsetof(struct vduse_config_data, buffer) + size); + if (!data) { + return -ENOMEM; + } + + data->offset = offset; + data->length = size; + memcpy(data->buffer, buffer, size); + + ret = ioctl(dev->fd, VDUSE_DEV_SET_CONFIG, data); + free(data); + + if (ret) { + return -errno; + } + + if (ioctl(dev->fd, VDUSE_DEV_INJECT_CONFIG_IRQ)) { + return -errno; + } + + return 0; +} + +int vduse_dev_setup_queue(VduseDev *dev, int index, int max_size) +{ + VduseVirtq *vq = &dev->vqs[index]; + struct vduse_vq_config vq_config = { 0 }; + + if (max_size > VIRTQUEUE_MAX_SIZE) { + return -EINVAL; + } + + vq_config.index = vq->index; + vq_config.max_size = max_size; + + if (ioctl(dev->fd, VDUSE_VQ_SETUP, &vq_config)) { + return -errno; + } + + vduse_queue_enable(vq); + + return 0; +} + +int vduse_set_reconnect_log_file(VduseDev *dev, const char *filename) +{ + + size_t log_size = dev->num_queues * vduse_vq_log_size(VIRTQUEUE_MAX_SIZE); + void *log; + int i; + + dev->log = log = vduse_log_get(filename, log_size); + if (log == MAP_FAILED) { + fprintf(stderr, "Failed to get vduse log\n"); + return -EINVAL; + } + + for (i = 0; i < dev->num_queues; i++) { + dev->vqs[i].log = log; + dev->vqs[i].log->inflight.desc_num = VIRTQUEUE_MAX_SIZE; + log = (void *)((char *)log + vduse_vq_log_size(VIRTQUEUE_MAX_SIZE)); + } + + return 0; +} + +static int vduse_dev_init_vqs(VduseDev *dev, uint16_t num_queues) +{ + VduseVirtq *vqs; + int i; + + vqs = calloc(sizeof(VduseVirtq), num_queues); + if (!vqs) { + return -ENOMEM; + } + + for (i = 0; i < num_queues; i++) { + vqs[i].index = i; + vqs[i].dev = dev; + vqs[i].fd = -1; + } + dev->vqs = vqs; + + return 0; +} + +static int vduse_dev_init(VduseDev *dev, const char *name, + uint16_t num_queues, const VduseOps *ops, + void *priv) +{ + char *dev_path, *dev_name; + int ret, fd; + + dev_path = malloc(strlen(name) + strlen("/dev/vduse/") + 1); + if (!dev_path) { + return -ENOMEM; + } + sprintf(dev_path, "/dev/vduse/%s", name); + + fd = open(dev_path, O_RDWR); + free(dev_path); + if (fd < 0) { + fprintf(stderr, "Failed to open vduse dev %s: %s\n", + name, strerror(errno)); + return -errno; + } + + if (ioctl(fd, VDUSE_DEV_GET_FEATURES, &dev->features)) { + fprintf(stderr, "Failed to get features: %s\n", strerror(errno)); + close(fd); + return -errno; + } + + dev_name = strdup(name); + if (!dev_name) { + close(fd); + return -ENOMEM; + } + + ret = vduse_dev_init_vqs(dev, num_queues); + if (ret) { + free(dev_name); + close(fd); + return ret; + } + + dev->name = dev_name; + dev->num_queues = num_queues; + dev->fd = fd; + dev->ops = ops; + dev->priv = priv; + + return 0; +} + +static inline bool vduse_name_is_invalid(const char *name) +{ + return strlen(name) >= VDUSE_NAME_MAX || strstr(name, ".."); +} + +VduseDev *vduse_dev_create_by_fd(int fd, uint16_t num_queues, + const VduseOps *ops, void *priv) +{ + VduseDev *dev; + int ret; + + if (!ops || !ops->enable_queue || !ops->disable_queue) { + fprintf(stderr, "Invalid parameter for vduse\n"); + return NULL; + } + + dev = calloc(sizeof(VduseDev), 1); + if (!dev) { + fprintf(stderr, "Failed to allocate vduse device\n"); + return NULL; + } + + if (ioctl(fd, VDUSE_DEV_GET_FEATURES, &dev->features)) { + fprintf(stderr, "Failed to get features: %s\n", strerror(errno)); + free(dev); + return NULL; + } + + ret = vduse_dev_init_vqs(dev, num_queues); + if (ret) { + fprintf(stderr, "Failed to init vqs\n"); + free(dev); + return NULL; + } + + dev->num_queues = num_queues; + dev->fd = fd; + dev->ops = ops; + dev->priv = priv; + + return dev; +} + +VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues, + const VduseOps *ops, void *priv) +{ + VduseDev *dev; + int ret; + + if (!name || vduse_name_is_invalid(name) || !ops || + !ops->enable_queue || !ops->disable_queue) { + fprintf(stderr, "Invalid parameter for vduse\n"); + return NULL; + } + + dev = calloc(sizeof(VduseDev), 1); + if (!dev) { + fprintf(stderr, "Failed to allocate vduse device\n"); + return NULL; + } + + 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)); + free(dev); + return NULL; + } + + return dev; +} + +VduseDev *vduse_dev_create(const char *name, uint32_t device_id, + uint32_t vendor_id, uint64_t features, + uint16_t num_queues, uint32_t config_size, + char *config, const VduseOps *ops, void *priv) +{ + VduseDev *dev; + int ret, ctrl_fd; + uint64_t version; + struct vduse_dev_config *dev_config; + size_t size = offsetof(struct vduse_dev_config, config); + + 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"); + return NULL; + } + + dev = calloc(sizeof(VduseDev), 1); + if (!dev) { + fprintf(stderr, "Failed to allocate vduse device\n"); + return NULL; + } + + ctrl_fd = open("/dev/vduse/control", O_RDWR); + if (ctrl_fd < 0) { + fprintf(stderr, "Failed to open /dev/vduse/control: %s\n", + strerror(errno)); + goto err_ctrl; + } + + version = VDUSE_API_VERSION; + if (ioctl(ctrl_fd, VDUSE_SET_API_VERSION, &version)) { + fprintf(stderr, "Failed to set api version %" PRIu64 ": %s\n", + version, strerror(errno)); + goto err_dev; + } + + dev_config = calloc(size + config_size, 1); + if (!dev_config) { + fprintf(stderr, "Failed to allocate config space\n"); + goto err_dev; + } + + assert(!vduse_name_is_invalid(name)); + strcpy(dev_config->name, name); + dev_config->device_id = device_id; + dev_config->vendor_id = vendor_id; + dev_config->features = features; + dev_config->vq_num = num_queues; + dev_config->vq_align = VDUSE_VQ_ALIGN; + dev_config->config_size = config_size; + memcpy(dev_config->config, config, config_size); + + ret = ioctl(ctrl_fd, VDUSE_CREATE_DEV, dev_config); + free(dev_config); + if (ret && errno != EEXIST) { + fprintf(stderr, "Failed to create vduse device %s: %s\n", + name, strerror(errno)); + goto err_dev; + } + dev->ctrl_fd = ctrl_fd; + + 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)); + goto err; + } + + return dev; +err: + ioctl(ctrl_fd, VDUSE_DESTROY_DEV, name); +err_dev: + close(ctrl_fd); +err_ctrl: + free(dev); + + return NULL; +} + +int vduse_dev_destroy(VduseDev *dev) +{ + size_t log_size = dev->num_queues * vduse_vq_log_size(VIRTQUEUE_MAX_SIZE); + int i, ret = 0; + + if (dev->log) { + munmap(dev->log, log_size); + } + for (i = 0; i < dev->num_queues; i++) { + free(dev->vqs[i].resubmit_list); + } + free(dev->vqs); + if (dev->fd >= 0) { + close(dev->fd); + dev->fd = -1; + } + if (dev->ctrl_fd >= 0) { + if (ioctl(dev->ctrl_fd, VDUSE_DESTROY_DEV, dev->name)) { + ret = -errno; + } + close(dev->ctrl_fd); + dev->ctrl_fd = -1; + } + free(dev->name); + free(dev); + + return ret; +} diff --git a/subprojects/libvduse/libvduse.h b/subprojects/libvduse/libvduse.h new file mode 100644 index 000000000000..32f19e7b486a --- /dev/null +++ b/subprojects/libvduse/libvduse.h @@ -0,0 +1,247 @@ +/* + * VDUSE (vDPA Device in Userspace) library + * + * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved. + * + * Author: + * Xie Yongji + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef LIBVDUSE_H +#define LIBVDUSE_H + +#include +#include + +#define VIRTQUEUE_MAX_SIZE 1024 + +/* VDUSE device structure */ +typedef struct VduseDev VduseDev; + +/* Virtqueue structure */ +typedef struct VduseVirtq VduseVirtq; + +/* Some operation of VDUSE backend */ +typedef struct VduseOps { + /* Called when virtqueue can be processed */ + void (*enable_queue)(VduseDev *dev, VduseVirtq *vq); + /* Called when virtqueue processing should be stopped */ + void (*disable_queue)(VduseDev *dev, VduseVirtq *vq); +} VduseOps; + +/* Describing elements of the I/O buffer */ +typedef struct VduseVirtqElement { + /* Descriptor table index */ + unsigned int index; + /* Number of physically-contiguous device-readable descriptors */ + unsigned int out_num; + /* Number of physically-contiguous device-writable descriptors */ + unsigned int in_num; + /* Array to store physically-contiguous device-writable descriptors */ + struct iovec *in_sg; + /* Array to store physically-contiguous device-readable descriptors */ + struct iovec *out_sg; +} VduseVirtqElement; + + +/** + * vduse_get_virtio_features: + * + * Get supported virtio features + * + * Returns: supported feature bits + */ +uint64_t vduse_get_virtio_features(void); + +/** + * vduse_queue_get_dev: + * @vq: specified virtqueue + * + * Get corresponding VDUSE device from the virtqueue. + * + * Returns: a pointer to VDUSE device on success, NULL on failure. + */ +VduseDev *vduse_queue_get_dev(VduseVirtq *vq); + +/** + * vduse_queue_get_fd: + * @vq: specified virtqueue + * + * Get the kick fd for the virtqueue. + * + * Returns: file descriptor on success, -1 on failure. + */ +int vduse_queue_get_fd(VduseVirtq *vq); + +/** + * vduse_queue_pop: + * @vq: specified virtqueue + * @sz: the size of struct to return (must be >= VduseVirtqElement) + * + * Pop an element from virtqueue available ring. + * + * Returns: a pointer to a structure containing VduseVirtqElement on success, + * NULL on failure. + */ +void *vduse_queue_pop(VduseVirtq *vq, size_t sz); + +/** + * vduse_queue_push: + * @vq: specified virtqueue + * @elem: pointer to VduseVirtqElement returned by vduse_queue_pop() + * @len: length in bytes to write + * + * Push an element to virtqueue used ring. + */ +void vduse_queue_push(VduseVirtq *vq, const VduseVirtqElement *elem, + unsigned int len); +/** + * vduse_queue_notify: + * @vq: specified virtqueue + * + * Request to notify the queue. + */ +void vduse_queue_notify(VduseVirtq *vq); + +/** + * vduse_dev_get_priv: + * @dev: VDUSE device + * + * Get the private pointer passed to vduse_dev_create(). + * + * Returns: private pointer on success, NULL on failure. + */ +void *vduse_dev_get_priv(VduseDev *dev); + +/** + * vduse_dev_get_queue: + * @dev: VDUSE device + * @index: virtqueue index + * + * Get the specified virtqueue. + * + * Returns: a pointer to the virtqueue on success, NULL on failure. + */ +VduseVirtq *vduse_dev_get_queue(VduseDev *dev, int index); + +/** + * vduse_dev_get_fd: + * @dev: VDUSE device + * + * Get the control message fd for the VDUSE device. + * + * Returns: file descriptor on success, -1 on failure. + */ +int vduse_dev_get_fd(VduseDev *dev); + +/** + * vduse_dev_handler: + * @dev: VDUSE device + * + * Used to process the control message. + * + * Returns: file descriptor on success, -errno on failure. + */ +int vduse_dev_handler(VduseDev *dev); + +/** + * vduse_dev_update_config: + * @dev: VDUSE device + * @size: the size to write to configuration space + * @offset: the offset from the beginning of configuration space + * @buffer: the buffer used to write from + * + * Update device configuration space and inject a config interrupt. + * + * Returns: 0 on success, -errno on failure. + */ +int vduse_dev_update_config(VduseDev *dev, uint32_t size, + uint32_t offset, char *buffer); + +/** + * vduse_dev_setup_queue: + * @dev: VDUSE device + * @index: virtqueue index + * @max_size: the max size of virtqueue + * + * Setup the specified virtqueue. + * + * Returns: 0 on success, -errno on failure. + */ +int vduse_dev_setup_queue(VduseDev *dev, int index, int max_size); + +/** + * vduse_set_reconnect_log_file: + * @dev: VDUSE device + * @file: filename of reconnect log + * + * Specify the file to store log for reconnecting. It should + * be called before vduse_dev_setup_queue(). + * + * Returns: 0 on success, -errno on failure. + */ +int vduse_set_reconnect_log_file(VduseDev *dev, const char *filename); + +/** + * vduse_dev_create_by_fd: + * @fd: passed file descriptor + * @num_queues: the number of virtqueues + * @ops: the operation of VDUSE backend + * @priv: private pointer + * + * Create VDUSE device from a passed file descriptor. + * + * Returns: pointer to VDUSE device on success, NULL on failure. + */ +VduseDev *vduse_dev_create_by_fd(int fd, uint16_t num_queues, + const VduseOps *ops, void *priv); + +/** + * vduse_dev_create_by_name: + * @name: VDUSE device name + * @num_queues: the number of virtqueues + * @ops: the operation of VDUSE backend + * @priv: private pointer + * + * Create VDUSE device on /dev/vduse/$NAME. + * + * Returns: pointer to VDUSE device on success, NULL on failure. + */ +VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues, + const VduseOps *ops, void *priv); + +/** + * vduse_dev_create: + * @name: VDUSE device name + * @device_id: virtio device id + * @vendor_id: virtio vendor id + * @features: virtio features + * @num_queues: the number of virtqueues + * @config_size: the size of the configuration space + * @config: the buffer of the configuration space + * @ops: the operation of VDUSE backend + * @priv: private pointer + * + * Create VDUSE device. + * + * Returns: pointer to VDUSE device on success, NULL on failure. + */ +VduseDev *vduse_dev_create(const char *name, uint32_t device_id, + uint32_t vendor_id, uint64_t features, + uint16_t num_queues, uint32_t config_size, + char *config, const VduseOps *ops, void *priv); + +/** + * vduse_dev_destroy: + * @dev: VDUSE device + * + * Destroy the VDUSE device. + * + * Returns: 0 on success, -errno on failure. + */ +int vduse_dev_destroy(VduseDev *dev); + +#endif diff --git a/subprojects/libvduse/linux-headers/linux b/subprojects/libvduse/linux-headers/linux new file mode 120000 index 000000000000..04f3304f79c6 --- /dev/null +++ b/subprojects/libvduse/linux-headers/linux @@ -0,0 +1 @@ +../../../linux-headers/linux/ \ No newline at end of file diff --git a/subprojects/libvduse/meson.build b/subprojects/libvduse/meson.build new file mode 100644 index 000000000000..3e3b53da33ae --- /dev/null +++ b/subprojects/libvduse/meson.build @@ -0,0 +1,16 @@ +project('libvduse', 'c', + license: 'GPL-2.0-or-later', + default_options: ['warning_level=1', 'c_std=gnu99']) + +cc = meson.get_compiler('c') +add_project_arguments(cc.get_supported_arguments('-Wsign-compare', + '-Wdeclaration-after-statement', + '-Wstrict-aliasing'), + native: false, language: 'c') + +libvduse = static_library('vduse', + files('libvduse.c'), + c_args: '-D_GNU_SOURCE') + +libvduse_dep = declare_dependency(link_with: libvduse, + include_directories: include_directories('.')) diff --git a/subprojects/libvduse/standard-headers/linux b/subprojects/libvduse/standard-headers/linux new file mode 120000 index 000000000000..c416f068ac77 --- /dev/null +++ b/subprojects/libvduse/standard-headers/linux @@ -0,0 +1 @@ +../../../include/standard-headers/linux/ \ No newline at end of file diff --git a/subprojects/libvfio-user b/subprojects/libvfio-user new file mode 160000 index 000000000000..0b28d205572c --- /dev/null +++ b/subprojects/libvfio-user @@ -0,0 +1 @@ +Subproject commit 0b28d205572c80b568a1003db2c8f37ca333e4d7 diff --git a/subprojects/libvhost-user/include/compiler.h b/subprojects/libvhost-user/include/compiler.h new file mode 120000 index 000000000000..de7b70697cd2 --- /dev/null +++ b/subprojects/libvhost-user/include/compiler.h @@ -0,0 +1 @@ +../../../include/qemu/compiler.h \ No newline at end of file diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 47d2efc60fb3..fc69783d2bf6 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -13,6 +13,10 @@ * later. See the COPYING file in the top-level directory. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + /* this code avoids GLib dependency */ #include #include @@ -45,10 +49,21 @@ #include "libvhost-user.h" /* usually provided by GLib */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#if !defined(__clang__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 4) +#define G_GNUC_PRINTF(format_idx, arg_idx) \ + __attribute__((__format__(gnu_printf, format_idx, arg_idx))) +#else +#define G_GNUC_PRINTF(format_idx, arg_idx) \ + __attribute__((__format__(__printf__, format_idx, arg_idx))) +#endif +#else /* !__GNUC__ */ +#define G_GNUC_PRINTF(format_idx, arg_idx) +#endif /* !__GNUC__ */ #ifndef MIN #define MIN(x, y) ({ \ - typeof(x) _min1 = (x); \ - typeof(y) _min2 = (y); \ + __typeof__(x) _min1 = (x); \ + __typeof__(y) _min2 = (y); \ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) #endif @@ -99,7 +114,7 @@ static inline bool vu_has_protocol_feature(VuDev *dev, unsigned int fbit) return has_feature(dev->protocol_features, fbit); } -static const char * +const char * vu_request_to_string(unsigned int req) { #define REQ(req) [req] = #req @@ -151,7 +166,7 @@ vu_request_to_string(unsigned int req) } } -static void +static void G_GNUC_PRINTF(2, 3) vu_panic(VuDev *dev, const char *msg, ...) { char *buf = NULL; @@ -177,7 +192,7 @@ vu_panic(VuDev *dev, const char *msg, ...) void * vu_gpa_to_va(VuDev *dev, uint64_t *plen, uint64_t guest_addr) { - int i; + unsigned int i; if (*plen == 0) { return NULL; @@ -203,7 +218,7 @@ vu_gpa_to_va(VuDev *dev, uint64_t *plen, uint64_t guest_addr) static void * qva_to_va(VuDev *dev, uint64_t qemu_addr) { - int i; + unsigned int i; /* Find matching memory region. */ for (i = 0; i < dev->nregions; i++) { @@ -324,7 +339,7 @@ vu_message_read_default(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) goto fail; } - assert(rc == vmsg->size); + assert((uint32_t)rc == vmsg->size); } return true; @@ -606,11 +621,13 @@ map_ring(VuDev *dev, VuVirtq *vq) static bool generate_faults(VuDev *dev) { - int i; + unsigned int i; for (i = 0; i < dev->nregions; i++) { VuDevRegion *dev_region = &dev->regions[i]; int ret; #ifdef UFFDIO_REGISTER + struct uffdio_register reg_struct; + /* * We should already have an open ufd. Mark each memory * range as ufd. @@ -644,14 +661,15 @@ generate_faults(VuDev *dev) { "%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n", __func__, i, strerror(errno)); } - struct uffdio_register reg_struct; + reg_struct.range.start = (uintptr_t)dev_region->mmap_addr; reg_struct.range.len = dev_region->size + dev_region->mmap_offset; reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING; if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, ®_struct)) { vu_panic(dev, "%s: Failed to userfault region %d " - "@%p + size:%zx offset: %zx: (ufd=%d)%s\n", + "@%" PRIx64 " + size:%" PRIx64 " offset: %" PRIx64 + ": (ufd=%d)%s\n", __func__, i, dev_region->mmap_addr, dev_region->size, dev_region->mmap_offset, @@ -700,7 +718,7 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { if (vmsg->size < VHOST_USER_MEM_REG_SIZE) { close(vmsg->fds[0]); vu_panic(dev, "VHOST_USER_ADD_MEM_REG requires a message size of at " - "least %d bytes and only %d bytes were received", + "least %zu bytes and only %d bytes were received", VHOST_USER_MEM_REG_SIZE, vmsg->size); return false; } @@ -779,15 +797,9 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { /* Send the message back to qemu with the addresses filled in. */ vmsg->fd_num = 0; - if (!vu_send_reply(dev, dev->sock, vmsg)) { - vu_panic(dev, "failed to respond to add-mem-region for postcopy"); - return false; - } - DPRINT("Successfully added new region in postcopy\n"); dev->nregions++; - return false; - + return true; } else { for (i = 0; i < dev->max_queues; i++) { if (dev->vq[i].vring.desc) { @@ -800,8 +812,7 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { DPRINT("Successfully added new region\n"); dev->nregions++; - vmsg_set_reply_u64(vmsg, 0); - return true; + return false; } } @@ -820,20 +831,20 @@ static inline bool reg_equal(VuDevRegion *vudev_reg, static bool vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m; - int i; + unsigned int i; bool found = false; - if (vmsg->fd_num != 1) { + if (vmsg->fd_num > 1) { vmsg_close_fds(vmsg); - vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - only 1 fd " + vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - at most 1 fd " "should be sent for this message type", vmsg->fd_num); return false; } if (vmsg->size < VHOST_USER_MEM_REG_SIZE) { - close(vmsg->fds[0]); + vmsg_close_fds(vmsg); vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at " - "least %d bytes and only %d bytes were received", + "least %zu bytes and only %d bytes were received", VHOST_USER_MEM_REG_SIZE, vmsg->size); return false; } @@ -874,21 +885,19 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { } } - if (found) { - vmsg_set_reply_u64(vmsg, 0); - } else { + if (!found) { vu_panic(dev, "Specified region not found\n"); } - close(vmsg->fds[0]); + vmsg_close_fds(vmsg); - return true; + return false; } static bool vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) { - int i; + unsigned int i; VhostUserMemory m = vmsg->payload.memory, *memory = &m; dev->nregions = memory->nregions; @@ -965,7 +974,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) static bool vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) { - int i; + unsigned int i; VhostUserMemory m = vmsg->payload.memory, *memory = &m; for (i = 0; i < dev->nregions; i++) { @@ -1590,12 +1599,13 @@ vu_set_config(VuDev *dev, VhostUserMsg *vmsg) static bool vu_set_postcopy_advise(VuDev *dev, VhostUserMsg *vmsg) { - dev->postcopy_ufd = -1; #ifdef UFFDIO_API struct uffdio_api api_struct; dev->postcopy_ufd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); vmsg->size = 0; +#else + dev->postcopy_ufd = -1; #endif if (dev->postcopy_ufd == -1) { @@ -1830,18 +1840,11 @@ vu_handle_vring_kick(VuDev *dev, VhostUserMsg *vmsg) static bool vu_handle_get_max_memslots(VuDev *dev, VhostUserMsg *vmsg) { - vmsg->flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION; - vmsg->size = sizeof(vmsg->payload.u64); - vmsg->payload.u64 = VHOST_USER_MAX_RAM_SLOTS; - vmsg->fd_num = 0; - - if (!vu_message_write(dev, dev->sock, vmsg)) { - vu_panic(dev, "Failed to send max ram slots: %s\n", strerror(errno)); - } + vmsg_set_reply_u64(vmsg, VHOST_USER_MAX_RAM_SLOTS); DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_USER_MAX_RAM_SLOTS); - return false; + return true; } static bool @@ -1980,7 +1983,7 @@ vu_dispatch(VuDev *dev) void vu_deinit(VuDev *dev) { - int i; + unsigned int i; for (i = 0; i < dev->nregions; i++) { VuDevRegion *r = &dev->regions[i]; @@ -2475,14 +2478,13 @@ vring_used_flags_unset_bit(VuVirtq *vq, int mask) static inline void vring_set_avail_event(VuVirtq *vq, uint16_t val) { - uint16_t *avail; + uint16_t val_le = htole16(val); if (!vq->notification) { return; } - avail = (uint16_t *)&vq->vring.used->ring[vq->vring.num]; - *avail = htole16(val); + memcpy(&vq->vring.used->ring[vq->vring.num], &val_le, sizeof(uint16_t)); } void diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h index cde9f07bb3c4..8cda9b8f577a 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -343,7 +343,7 @@ typedef struct VuVirtq { /* Notification enabled? */ bool notification; - int inuse; + unsigned int inuse; vu_queue_handler_cb handler; @@ -473,6 +473,15 @@ bool vu_init(VuDev *dev, */ void vu_deinit(VuDev *dev); + +/** + * vu_request_to_string: return string for vhost message request + * @req: VhostUserMsg request + * + * Returns a const string, do not free. + */ +const char *vu_request_to_string(unsigned int req); + /** * vu_dispatch: * @dev: a VuDev context diff --git a/subprojects/libvhost-user/meson.build b/subprojects/libvhost-user/meson.build index 39825d9404ae..a18014e7f26f 100644 --- a/subprojects/libvhost-user/meson.build +++ b/subprojects/libvhost-user/meson.build @@ -1,6 +1,12 @@ project('libvhost-user', 'c', license: 'GPL-2.0-or-later', - default_options: ['c_std=gnu99']) + default_options: ['warning_level=1', 'c_std=gnu99']) + +cc = meson.get_compiler('c') +add_project_arguments(cc.get_supported_arguments('-Wsign-compare', + '-Wdeclaration-after-statement', + '-Wstrict-aliasing'), + native: false, language: 'c') threads = dependency('threads') glib = dependency('glib-2.0') diff --git a/target/Kconfig b/target/Kconfig index ae7f24fc66b0..83da0bd2938b 100644 --- a/target/Kconfig +++ b/target/Kconfig @@ -4,6 +4,7 @@ source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig +source loongarch/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h index 1153992e42ad..17cd14e59042 100644 --- a/target/alpha/cpu-param.h +++ b/target/alpha/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef ALPHA_CPU_PARAM_H -#define ALPHA_CPU_PARAM_H 1 +#define ALPHA_CPU_PARAM_H #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 13 diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index a8990d401bc3..270ae787b18b 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -33,6 +33,22 @@ 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 void alpha_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + AlphaCPU *cpu = ALPHA_CPU(cs); + + cpu->env.pc = data[0]; +} + static bool alpha_cpu_has_work(CPUState *cs) { /* Here we are checking to see if the CPU should wake up from HALT. @@ -218,6 +234,7 @@ static const struct SysemuCPUOps alpha_sysemu_ops = { static const struct TCGCPUOps alpha_tcg_ops = { .initialize = alpha_translate_init, + .restore_state_to_opc = alpha_restore_state_to_opc, #ifdef CONFIG_USER_ONLY .record_sigsegv = alpha_cpu_record_sigsegv, @@ -244,6 +261,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/cpu.h b/target/alpha/cpu.h index 58f00b7814fd..d0abc949a8d0 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" /* Alpha processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) @@ -433,8 +434,8 @@ void alpha_translate_init(void); #define CPU_RESOLVING_TYPE TYPE_ALPHA_CPU void alpha_cpu_list(void); -void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int); -void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t); +G_NORETURN void dynamic_excp(CPUAlphaState *, uintptr_t, int, int); +G_NORETURN void arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t); uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env); void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val); @@ -451,9 +452,9 @@ void alpha_cpu_record_sigbus(CPUState *cs, vaddr address, bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); -void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, MMUAccessType access_type, diff --git a/target/alpha/helper.c b/target/alpha/helper.c index dcaa2d03adb3..970c86977154 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -514,7 +514,7 @@ void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags) /* This should only be called from translate, via gen_excp. We expect that ENV->PC has already been updated. */ -void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error) +G_NORETURN void helper_excp(CPUAlphaState *env, int excp, int error) { CPUState *cs = env_cpu(env); @@ -524,23 +524,23 @@ void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error) } /* This may be called from any of the helpers to set up EXCEPTION_INDEX. */ -void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr, - int excp, int error) +G_NORETURN void dynamic_excp(CPUAlphaState *env, uintptr_t retaddr, + int excp, int error) { CPUState *cs = env_cpu(env); cs->exception_index = excp; env->error_code = error; if (retaddr) { - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); /* Floating-point exceptions (our only users) point to the next PC. */ env->pc += 4; } cpu_loop_exit(cs); } -void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr, - int exc, uint64_t mask) +G_NORETURN void arith_excp(CPUAlphaState *env, uintptr_t retaddr, + int exc, uint64_t mask) { env->trap_arg0 = exc; env->trap_arg1 = mask; diff --git a/target/alpha/mem_helper.c b/target/alpha/mem_helper.c index 47283a06123b..a39b52c5dd62 100644 --- a/target/alpha/mem_helper.c +++ b/target/alpha/mem_helper.c @@ -28,7 +28,7 @@ static void do_unaligned_access(CPUAlphaState *env, vaddr addr, uintptr_t retadd uint64_t pc; uint32_t insn; - cpu_restore_state(env_cpu(env), retaddr, true); + cpu_restore_state(env_cpu(env), retaddr); pc = env->pc; insn = cpu_ldl_code(env, pc); diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 66768ab47ad5..f9bcdeb7179c 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -235,7 +235,7 @@ static TCGv dest_fpr(DisasContext *ctx, unsigned reg) static int get_flag_ofs(unsigned shift) { int ofs = offsetof(CPUAlphaState, flags); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN ofs += 3 - (shift / 8); #else ofs += shift / 8; @@ -3027,10 +3027,11 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void alpha_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void alpha_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps alpha_tr_ops = { @@ -3042,14 +3043,9 @@ 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); -} - -void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; + translator_loop(cpu, tb, max_insns, pc, host_pc, &alpha_tr_ops, &dc.base); } diff --git a/target/arm/a32.decode b/target/arm/a32.decode index fcd8cd4f7d92..f2ca48094955 100644 --- a/target/arm/a32.decode +++ b/target/arm/a32.decode @@ -187,13 +187,17 @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn { { - YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 - WFE ---- 0011 0010 0000 1111 ---- 0000 0010 - WFI ---- 0011 0010 0000 1111 ---- 0000 0011 + [ + YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 + WFE ---- 0011 0010 0000 1111 ---- 0000 0010 + WFI ---- 0011 0010 0000 1111 ---- 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 - # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 + # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + + ESB ---- 0011 0010 0000 1111 ---- 0001 0000 + ] # The canonical nop ends in 00000000, but the whole of the # rest of the space executes as nop if otherwise unsupported. diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c index 018484531091..2d8e41ab8a3b 100644 --- a/target/arm/arch_dump.c +++ b/target/arm/arch_dump.c @@ -166,7 +166,7 @@ static off_t sve_fpcr_offset(uint32_t vq) static uint32_t sve_current_vq(CPUARMState *env) { - return sve_zcr_len_for_el(env, arm_current_el(env)) + 1; + return sve_vqm1_for_el(env, arm_current_el(env)) + 1; } static size_t sve_size_vq(uint32_t vq) @@ -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/common-semi-target.h b/target/arm/common-semi-target.h new file mode 100644 index 000000000000..629d75ca5a75 --- /dev/null +++ b/target/arm/common-semi-target.h @@ -0,0 +1,62 @@ +/* + * Target-specific parts of semihosting/arm-compat-semi.c. + * + * Copyright (c) 2005, 2007 CodeSourcery. + * Copyright (c) 2019, 2022 Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_ARM_COMMON_SEMI_TARGET_H +#define TARGET_ARM_COMMON_SEMI_TARGET_H + +#ifndef CONFIG_USER_ONLY +#include "hw/arm/boot.h" +#endif + +static inline target_ulong common_semi_arg(CPUState *cs, int argno) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + if (is_a64(env)) { + return env->xregs[argno]; + } else { + return env->regs[argno]; + } +} + +static inline void common_semi_set_ret(CPUState *cs, target_ulong ret) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + if (is_a64(env)) { + env->xregs[0] = ret; + } else { + env->regs[0] = ret; + } +} + +static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr) +{ + return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr)); +} + +static inline bool is_64bit_semihosting(CPUArchState *env) +{ + return is_a64(env); +} + +static inline target_ulong common_semi_stack_bottom(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + return is_a64(env) ? env->xregs[31] : env->regs[13]; +} + +static inline bool common_semi_has_synccache(CPUArchState *env) +{ + /* Ok for A64, invalid for A32/T32 */ + return is_a64(env); +} + +#endif diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h new file mode 100644 index 000000000000..7e78c2c05c61 --- /dev/null +++ b/target/arm/cpregs.h @@ -0,0 +1,496 @@ +/* + * QEMU ARM CP Register access and descriptions + * + * Copyright (c) 2022 Linaro Ltd + * + * 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 + * + */ + +#ifndef TARGET_ARM_CPREGS_H +#define TARGET_ARM_CPREGS_H + +/* + * ARMCPRegInfo type field bits: + */ +enum { + /* + * Register must be handled specially during translation. + * The method is one of the values below: + */ + ARM_CP_SPECIAL_MASK = 0x000f, + /* Special: no change to PE state: writes ignored, reads ignored. */ + ARM_CP_NOP = 0x0001, + /* Special: sysreg is WFI, for v5 and v6. */ + ARM_CP_WFI = 0x0002, + /* Special: sysreg is NZCV. */ + ARM_CP_NZCV = 0x0003, + /* Special: sysreg is CURRENTEL. */ + ARM_CP_CURRENTEL = 0x0004, + /* Special: sysreg is DC ZVA or similar. */ + ARM_CP_DC_ZVA = 0x0005, + ARM_CP_DC_GVA = 0x0006, + ARM_CP_DC_GZVA = 0x0007, + + /* Flag: reads produce resetvalue; writes ignored. */ + ARM_CP_CONST = 1 << 4, + /* Flag: For ARM_CP_STATE_AA32, sysreg is 64-bit. */ + ARM_CP_64BIT = 1 << 5, + /* + * Flag: TB should not be ended after a write to this register + * (the default is that the TB ends after cp writes). + */ + ARM_CP_SUPPRESS_TB_END = 1 << 6, + /* + * Flag: Permit a register definition to override a previous definition + * for the same (cp, is64, crn, crm, opc1, opc2) tuple: either the new + * or the old must have the ARM_CP_OVERRIDE bit set. + */ + ARM_CP_OVERRIDE = 1 << 7, + /* + * Flag: Register is an alias view of some underlying state which is also + * visible via another register, and that the other register is handling + * migration and reset; registers marked ARM_CP_ALIAS will not be migrated + * but may have their state set by syncing of register state from KVM. + */ + ARM_CP_ALIAS = 1 << 8, + /* + * Flag: Register does I/O and therefore its accesses need to be marked + * with gen_io_start() and also end the TB. In particular, registers which + * implement clocks or timers require this. + */ + ARM_CP_IO = 1 << 9, + /* + * Flag: Register has no underlying state and does not support raw access + * for state saving/loading; it will not be used for either migration or + * KVM state synchronization. Typically this is for "registers" which are + * actually used as instructions for cache maintenance and so on. + */ + ARM_CP_NO_RAW = 1 << 10, + /* + * Flag: The read or write hook might raise an exception; the generated + * code will synchronize the CPU state before calling the hook so that it + * is safe for the hook to call raise_exception(). + */ + ARM_CP_RAISES_EXC = 1 << 11, + /* + * Flag: Writes to the sysreg might change the exception level - typically + * on older ARM chips. For those cases we need to re-read the new el when + * recomputing the translation flags. + */ + ARM_CP_NEWEL = 1 << 12, + /* + * Flag: Access check for this sysreg is identical to accessing FPU state + * from an instruction: use translation fp_access_check(). + */ + ARM_CP_FPU = 1 << 13, + /* + * Flag: Access check for this sysreg is identical to accessing SVE state + * from an instruction: use translation sve_access_check(). + */ + ARM_CP_SVE = 1 << 14, + /* Flag: Do not expose in gdb sysreg xml. */ + ARM_CP_NO_GDB = 1 << 15, + /* + * Flags: If EL3 but not EL2... + * - UNDEF: discard the cpreg, + * - KEEP: retain the cpreg as is, + * - C_NZ: set const on the cpreg, but retain resetvalue, + * - else: set const on the cpreg, zero resetvalue, aka RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + ARM_CP_EL3_NO_EL2_UNDEF = 1 << 16, + ARM_CP_EL3_NO_EL2_KEEP = 1 << 17, + ARM_CP_EL3_NO_EL2_C_NZ = 1 << 18, + /* + * Flag: Access check for this sysreg is constrained by the + * ARM pseudocode function CheckSMEAccess(). + */ + ARM_CP_SME = 1 << 19, +}; + +/* + * Valid values for ARMCPRegInfo state field, indicating which of + * the AArch32 and AArch64 execution states this register is visible in. + * If the reginfo doesn't explicitly specify then it is AArch32 only. + * If the reginfo is declared to be visible in both states then a second + * reginfo is synthesised for the AArch32 view of the AArch64 register, + * such that the AArch32 view is the lower 32 bits of the AArch64 one. + * Note that we rely on the values of these enums as we iterate through + * the various states in some places. + */ +typedef enum { + ARM_CP_STATE_AA32 = 0, + ARM_CP_STATE_AA64 = 1, + ARM_CP_STATE_BOTH = 2, +} CPState; + +/* + * ARM CP register secure state flags. These flags identify security state + * attributes for a given CP register entry. + * The existence of both or neither secure and non-secure flags indicates that + * the register has both a secure and non-secure hash entry. A single one of + * these flags causes the register to only be hashed for the specified + * security state. + * Although definitions may have any combination of the S/NS bits, each + * registered entry will only have one to identify whether the entry is secure + * or non-secure. + */ +typedef enum { + ARM_CP_SECSTATE_BOTH = 0, /* define one cpreg for each secstate */ + ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ + ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ +} CPSecureState; + +/* + * Access rights: + * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM + * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and + * PL2 (hyp). The other level which has Read and Write bits is Secure PL1 + * (ie any of the privileged modes in Secure state, or Monitor mode). + * If a register is accessible in one privilege level it's always accessible + * in higher privilege levels too. Since "Secure PL1" also follows this rule + * (ie anything visible in PL2 is visible in S-PL1, some things are only + * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the + * terminology a little and call this PL3. + * In AArch64 things are somewhat simpler as the PLx bits line up exactly + * with the ELx exception levels. + * + * If access permissions for a register are more complex than can be + * described with these bits, then use a laxer set of restrictions, and + * do the more restrictive/complex check inside a helper function. + */ +typedef enum { + PL3_R = 0x80, + PL3_W = 0x40, + PL2_R = 0x20 | PL3_R, + PL2_W = 0x10 | PL3_W, + PL1_R = 0x08 | PL2_R, + PL1_W = 0x04 | PL2_W, + PL0_R = 0x02 | PL1_R, + PL0_W = 0x01 | PL1_W, + + /* + * For user-mode some registers are accessible to EL0 via a kernel + * trap-and-emulate ABI. In this case we define the read permissions + * as actually being PL0_R. However some bits of any given register + * may still be masked. + */ +#ifdef CONFIG_USER_ONLY + PL0U_R = PL0_R, +#else + PL0U_R = PL1_R, +#endif + + PL3_RW = PL3_R | PL3_W, + PL2_RW = PL2_R | PL2_W, + PL1_RW = PL1_R | PL1_W, + PL0_RW = PL0_R | PL0_W, +} CPAccessRights; + +typedef enum CPAccessResult { + /* Access is permitted */ + CP_ACCESS_OK = 0, + + /* + * Combined with one of the following, the low 2 bits indicate the + * target exception level. If 0, the exception is taken to the usual + * target EL (EL1 or PL1 if in EL0, otherwise to the current EL). + */ + CP_ACCESS_EL_MASK = 3, + + /* + * Access fails due to a configurable trap or enable which would + * result in a categorized exception syndrome giving information about + * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6, + * 0xc or 0x18). + */ + CP_ACCESS_TRAP = (1 << 2), + CP_ACCESS_TRAP_EL2 = CP_ACCESS_TRAP | 2, + CP_ACCESS_TRAP_EL3 = CP_ACCESS_TRAP | 3, + + /* + * Access fails and results in an exception syndrome 0x0 ("uncategorized"). + * Note that this is not a catch-all case -- the set of cases which may + * result in this failure is specifically defined by the architecture. + */ + CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2), + CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2, + CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 3, +} CPAccessResult; + +typedef struct ARMCPRegInfo ARMCPRegInfo; + +/* + * Access functions for coprocessor registers. These cannot fail and + * may not raise exceptions. + */ +typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque); +typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque, + uint64_t value); +/* Access permission check functions for coprocessor registers. */ +typedef CPAccessResult CPAccessFn(CPUARMState *env, + const ARMCPRegInfo *opaque, + bool isread); +/* Hook function for register reset */ +typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); + +#define CP_ANY 0xff + +/* Definition of an ARM coprocessor register */ +struct ARMCPRegInfo { + /* Name of register (useful mainly for debugging, need not be unique) */ + const char *name; + /* + * Location of register: coprocessor number and (crn,crm,opc1,opc2) + * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a + * 'wildcard' field -- any value of that field in the MRC/MCR insn + * will be decoded to this register. The register read and write + * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2 + * used by the program, so it is possible to register a wildcard and + * then behave differently on read/write if necessary. + * For 64 bit registers, only crm and opc1 are relevant; crn and opc2 + * must both be zero. + * For AArch64-visible registers, opc0 is also used. + * Since there are no "coprocessors" in AArch64, cp is purely used as a + * way to distinguish (for KVM's benefit) guest-visible system registers + * from demuxed ones provided to preserve the "no side effects on + * KVM register read/write from QEMU" semantics. cp==0x13 is guest + * visible (to match KVM's encoding); cp==0 will be converted to + * cp==0x13 when the ARMCPRegInfo is registered, for convenience. + */ + uint8_t cp; + uint8_t crn; + uint8_t crm; + uint8_t opc0; + uint8_t opc1; + uint8_t opc2; + /* Execution state in which this register is visible: ARM_CP_STATE_* */ + CPState state; + /* Register type: ARM_CP_* bits/values */ + int type; + /* Access rights: PL*_[RW] */ + CPAccessRights access; + /* Security state: ARM_CP_SECSTATE_* bits/values */ + CPSecureState secure; + /* + * The opaque pointer passed to define_arm_cp_regs_with_opaque() when + * this register was defined: can be used to hand data through to the + * register read/write functions, since they are passed the ARMCPRegInfo*. + */ + void *opaque; + /* + * Value of this register, if it is ARM_CP_CONST. Otherwise, if + * fieldoffset is non-zero, the reset value of the register. + */ + uint64_t resetvalue; + /* + * Offset of the field in CPUARMState for this register. + * This is not needed if either: + * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs + * 2. both readfn and writefn are specified + */ + ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ + + /* + * Offsets of the secure and non-secure fields in CPUARMState for the + * register if it is banked. These fields are only used during the static + * registration of a register. During hashing the bank associated + * with a given security state is copied to fieldoffset which is used from + * there on out. + * + * It is expected that register definitions use either fieldoffset or + * bank_fieldoffsets in the definition but not both. It is also expected + * that both bank offsets are set when defining a banked register. This + * use indicates that a register is banked. + */ + ptrdiff_t bank_fieldoffsets[2]; + + /* + * Function for making any access checks for this register in addition to + * those specified by the 'access' permissions bits. If NULL, no extra + * checks required. The access check is performed at runtime, not at + * translate time. + */ + CPAccessFn *accessfn; + /* + * Function for handling reads of this register. If NULL, then reads + * will be done by loading from the offset into CPUARMState specified + * by fieldoffset. + */ + CPReadFn *readfn; + /* + * Function for handling writes of this register. If NULL, then writes + * will be done by writing to the offset into CPUARMState specified + * by fieldoffset. + */ + CPWriteFn *writefn; + /* + * Function for doing a "raw" read; used when we need to copy + * coprocessor state to the kernel for KVM or out for + * migration. This only needs to be provided if there is also a + * readfn and it has side effects (for instance clear-on-read bits). + */ + CPReadFn *raw_readfn; + /* + * Function for doing a "raw" write; used when we need to copy KVM + * kernel coprocessor state into userspace, or for inbound + * migration. This only needs to be provided if there is also a + * writefn and it masks out "unwritable" bits or has write-one-to-clear + * or similar behaviour. + */ + CPWriteFn *raw_writefn; + /* + * Function for resetting the register. If NULL, then reset will be done + * by writing resetvalue to the field specified in fieldoffset. If + * fieldoffset is 0 then no reset will be done. + */ + CPResetFn *resetfn; + + /* + * "Original" writefn and readfn. + * For ARMv8.1-VHE register aliases, we overwrite the read/write + * accessor functions of various EL1/EL0 to perform the runtime + * check for which sysreg should actually be modified, and then + * forwards the operation. Before overwriting the accessors, + * the original function is copied here, so that accesses that + * really do go to the EL1/EL0 version proceed normally. + * (The corresponding EL2 register is linked via opaque.) + */ + CPReadFn *orig_readfn; + CPWriteFn *orig_writefn; +}; + +/* + * Macros which are lvalues for the field in CPUARMState for the + * ARMCPRegInfo *ri. + */ +#define CPREG_FIELD32(env, ri) \ + (*(uint32_t *)((char *)(env) + (ri)->fieldoffset)) +#define CPREG_FIELD64(env, ri) \ + (*(uint64_t *)((char *)(env) + (ri)->fieldoffset)) + +void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg, + void *opaque); + +static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs) +{ + define_one_arm_cp_reg_with_opaque(cpu, regs, NULL); +} + +void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs, + void *opaque, size_t len); + +#define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE) \ + do { \ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \ + define_arm_cp_regs_with_opaque_len(CPU, REGS, OPAQUE, \ + ARRAY_SIZE(REGS)); \ + } while (0) + +#define define_arm_cp_regs(CPU, REGS) \ + define_arm_cp_regs_with_opaque(CPU, REGS, NULL) + +const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp); + +/* + * Definition of an ARM co-processor register as viewed from + * userspace. This is used for presenting sanitised versions of + * registers to userspace when emulating the Linux AArch64 CPU + * ID/feature ABI (advertised as HWCAP_CPUID). + */ +typedef struct ARMCPRegUserSpaceInfo { + /* Name of register */ + const char *name; + + /* Is the name actually a glob pattern */ + bool is_glob; + + /* Only some bits are exported to user space */ + uint64_t exported_bits; + + /* Fixed bits are applied after the mask */ + uint64_t fixed_bits; +} ARMCPRegUserSpaceInfo; + +void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len, + const ARMCPRegUserSpaceInfo *mods, + size_t mods_len); + +#define modify_arm_cp_regs(REGS, MODS) \ + do { \ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(MODS) == 0); \ + modify_arm_cp_regs_with_len(REGS, ARRAY_SIZE(REGS), \ + MODS, ARRAY_SIZE(MODS)); \ + } while (0) + +/* CPWriteFn that can be used to implement writes-ignored behaviour */ +void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value); +/* CPReadFn that can be used for read-as-zero behaviour */ +uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri); + +/* CPWriteFn that just writes the value to ri->fieldoffset */ +void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value); + +/* + * CPResetFn that does nothing, for use if no reset is required even + * if fieldoffset is non zero. + */ +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque); + +/* + * Return true if this reginfo struct's field in the cpu state struct + * is 64 bits wide. + */ +static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri) +{ + return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT); +} + +static inline bool cp_access_ok(int current_el, + const ARMCPRegInfo *ri, int isread) +{ + return (ri->access >> ((current_el * 2) + isread)) & 1; +} + +/* Raw read of a coprocessor register (as needed for migration, etc) */ +uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); + +/* + * Return true if the cp register encoding is in the "feature ID space" as + * defined by FEAT_IDST (and thus should be reported with ER_ELx.EC + * as EC_SYSTEMREGISTERTRAP rather than EC_UNCATEGORIZED). + */ +static inline bool arm_cpreg_encoding_in_idspace(uint8_t opc0, uint8_t opc1, + uint8_t opc2, + uint8_t crn, uint8_t crm) +{ + return opc0 == 3 && (opc1 == 0 || opc1 == 1 || opc1 == 3) && + crn == 0 && crm < 8; +} + +/* + * As arm_cpreg_encoding_in_idspace(), but take the encoding from an + * ARMCPRegInfo. + */ +static inline bool arm_cpreg_in_idspace(const ARMCPRegInfo *ri) +{ + return ri->state == ARM_CP_STATE_AA64 && + arm_cpreg_encoding_in_idspace(ri->opc0, ri->opc1, ri->opc2, + ri->crn, ri->crm); +} + +#endif /* TARGET_ARM_CPREGS_H */ diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index b59d505761cb..53cac9c89bf9 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef ARM_CPU_PARAM_H -#define ARM_CPU_PARAM_H 1 +#define ARM_CPU_PARAM_H #ifdef TARGET_AARCH64 # define TARGET_LONG_BITS 64 @@ -30,8 +30,23 @@ */ # define TARGET_PAGE_BITS_VARY # define TARGET_PAGE_BITS_MIN 10 + +# define TARGET_TB_PCREL 1 + +/* + * Cache the attrs and shareability fields from the page table entry. + * + * For ARMMMUIdx_Stage2*, pte_attrs is the S2 descriptor bits [5:2]. + * Otherwise, pte_attrs is the same as the MAIR_EL1 8-bit format. + * For shareability and guarded, as in the SH and GP fields respectively + * of the VMSAv8-64 PTEs. + */ +# define TARGET_PAGE_ENTRY_EXTRA \ + uint8_t pte_attrs; \ + uint8_t shareability; \ + bool guarded; #endif -#define NB_MMU_MODES 15 +#define NB_MMU_MODES 12 #endif diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h index 64c44cef2ddf..514c22ced9b8 100644 --- a/target/arm/cpu-qom.h +++ b/target/arm/cpu-qom.h @@ -43,7 +43,7 @@ void aarch64_cpu_register(const ARMCPUInfo *info); /** * ARMCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * An ARM CPU model. */ @@ -54,7 +54,7 @@ struct ARMCPUClass { const ARMCPUInfo *info; DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5d4ca7a22700..5f63316dbf22 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -22,11 +22,10 @@ #include "qemu/qemu-print.h" #include "qemu/timer.h" #include "qemu/log.h" -#include "qemu-common.h" +#include "exec/page-vary.h" #include "target/arm/idau.h" #include "qemu/module.h" #include "qapi/error.h" -#include "qapi/visitor.h" #include "cpu.h" #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" @@ -39,10 +38,12 @@ #include "hw/boards.h" #endif #include "sysemu/tcg.h" +#include "sysemu/qtest.h" #include "sysemu/hw_accel.h" #include "kvm_arm.h" #include "disas/capstone.h" #include "fpu/softfloat.h" +#include "cpregs.h" static void arm_cpu_set_pc(CPUState *cs, vaddr value) { @@ -51,28 +52,66 @@ static void arm_cpu_set_pc(CPUState *cs, vaddr value) if (is_a64(env)) { env->pc = value; - env->thumb = 0; + env->thumb = false; } else { env->regs[15] = value & ~1; env->thumb = value & 1; } } +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) { - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; + /* The program counter is always up to date with TARGET_TB_PCREL. */ + if (!TARGET_TB_PCREL) { + CPUARMState *env = cs->env_ptr; + /* + * It's OK to look at env for the current mode here, because it's + * never possible for an AArch64 TB to chain to an AArch32 TB. + */ + if (is_a64(env)) { + env->pc = tb_pc(tb); + } else { + env->regs[15] = tb_pc(tb); + } + } +} + +void arm_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + CPUARMState *env = cs->env_ptr; - /* - * It's OK to look at env for the current mode here, because it's - * never possible for an AArch64 TB to chain to an AArch32 TB. - */ if (is_a64(env)) { - env->pc = tb->pc; + if (TARGET_TB_PCREL) { + env->pc = (env->pc & TARGET_PAGE_MASK) | data[0]; + } else { + env->pc = data[0]; + } + env->condexec_bits = 0; + env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; } else { - env->regs[15] = tb->pc; + if (TARGET_TB_PCREL) { + env->regs[15] = (env->regs[15] & TARGET_PAGE_MASK) | data[0]; + } else { + env->regs[15] = data[0]; + } + env->condexec_bits = data[1]; + env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; } } #endif /* CONFIG_TCG */ @@ -84,7 +123,7 @@ static bool arm_cpu_has_work(CPUState *cs) return (cpu->power_state != PSCI_OFF) && cs->interrupt_request & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD - | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ + | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR | CPU_INTERRUPT_EXITTB); } @@ -116,7 +155,7 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) ARMCPRegInfo *ri = value; ARMCPU *cpu = opaque; - if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS)) { + if (ri->type & (ARM_CP_SPECIAL_MASK | ARM_CP_ALIAS)) { return; } @@ -152,7 +191,7 @@ static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) ARMCPU *cpu = opaque; uint64_t oldvalue, newvalue; - if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) { + if (ri->type & (ARM_CP_SPECIAL_MASK | ARM_CP_ALIAS | ARM_CP_NO_RAW)) { return; } @@ -162,14 +201,16 @@ static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) assert(oldvalue == newvalue); } -static void arm_cpu_reset(DeviceState *dev) +static void arm_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); ARMCPU *cpu = ARM_CPU(s); ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu); CPUARMState *env = &cpu->env; - acc->parent_reset(dev); + if (acc->parent_phases.hold) { + acc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUARMState, end_reset_fields)); @@ -189,7 +230,7 @@ static void arm_cpu_reset(DeviceState *dev) if (arm_feature(env, ARM_FEATURE_AARCH64)) { /* 64 bit CPUs always start in 64 bit mode */ - env->aarch64 = 1; + env->aarch64 = true; #if defined(CONFIG_USER_ONLY) env->pstate = PSTATE_MODE_EL0t; /* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */ @@ -197,21 +238,34 @@ static void arm_cpu_reset(DeviceState *dev) /* Enable all PAC keys. */ env->cp15.sctlr_el[1] |= (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB); + /* Trap on btype=3 for PACIxSP. */ + env->cp15.sctlr_el[1] |= SCTLR_BT0; /* and to the FP/Neon instructions */ - env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3); - /* and to the SVE instructions */ - env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3); - /* with reasonable vector length */ + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR_EL1, FPEN, 3); + /* and to the SVE instructions, with default vector length */ if (cpu_isar_feature(aa64_sve, cpu)) { - env->vfp.zcr_el[1] = - aarch64_sve_zcr_get_valid_len(cpu, cpu->sve_default_vq - 1); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR_EL1, ZEN, 3); + env->vfp.zcr_el[1] = cpu->sve_default_vq - 1; + } + /* and for SME instructions, with default vector length, and TPIDR2 */ + if (cpu_isar_feature(aa64_sme, cpu)) { + env->cp15.sctlr_el[1] |= SCTLR_EnTP2; + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR_EL1, SMEN, 3); + env->vfp.smcr_el[1] = cpu->sme_default_vq - 1; + if (cpu_isar_feature(aa64_sme_fa64, cpu)) { + env->vfp.smcr_el[1] = FIELD_DP64(env->vfp.smcr_el[1], + SMCR, FA64, 1); + } } /* * Enable 48-bit address space (TODO: take reserved_va into account). * Enable TBI0 but not TBI1. * Note that this must match useronly_clean_ptr. */ - env->cp15.tcr_el[1].raw_tcr = 5 | (1ULL << 37); + env->cp15.tcr_el[1] = 5 | (1ULL << 37); /* Enable MTE */ if (cpu_isar_feature(aa64_mte, cpu)) { @@ -227,6 +281,11 @@ static void arm_cpu_reset(DeviceState *dev) */ env->cp15.gcr_el1 = 0x1ffff; } + /* + * Disable access to SCXTNUM_EL0 from CSV2_1p2. + * This is not yet exposed from the Linux kernel in any way. + */ + env->cp15.sctlr_el[1] |= SCTLR_TSCXT; #else /* Reset into the highest available EL */ if (arm_feature(env, ARM_FEATURE_EL3)) { @@ -244,8 +303,15 @@ static void arm_cpu_reset(DeviceState *dev) } else { #if defined(CONFIG_USER_ONLY) /* Userspace expects access to cp10 and cp11 for FP/Neon */ - env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 4, 0xf); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR, CP10, 3); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR, CP11, 3); #endif + if (arm_feature(env, ARM_FEATURE_V8)) { + env->cp15.rvbar = cpu->rvbar_prop; + env->regs[15] = cpu->rvbar_prop; + } } #if defined(CONFIG_USER_ONLY) @@ -424,6 +490,14 @@ static void arm_cpu_reset(DeviceState *dev) sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion); } } + + if (cpu->pmsav8r_hdregion > 0) { + memset(env->pmsav8.hprbar, 0, + sizeof(*env->pmsav8.hprbar) * cpu->pmsav8r_hdregion); + memset(env->pmsav8.hprlar, 0, + sizeof(*env->pmsav8.hprlar) * cpu->pmsav8r_hdregion); + } + env->pmsav7.rnr[M_REG_NS] = 0; env->pmsav7.rnr[M_REG_S] = 0; env->pmsav8.mair0[M_REG_NS] = 0; @@ -467,7 +541,7 @@ static void arm_cpu_reset(DeviceState *dev) arm_rebuild_hflags(env); } -#ifndef CONFIG_USER_ONLY +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, unsigned int target_el, @@ -508,6 +582,12 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, return false; } return !(env->daif & PSTATE_I); + case EXCP_VSERR: + if (!(hcr_el2 & HCR_AMO) || (hcr_el2 & HCR_TGE)) { + /* VIRQs are only taken when hypervized. */ + return false; + } + return !(env->daif & PSTATE_A); default: g_assert_not_reached(); } @@ -520,14 +600,24 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, if ((target_el > cur_el) && (target_el != 1)) { /* Exceptions targeting a higher EL may not be maskable */ if (arm_feature(env, ARM_FEATURE_AARCH64)) { - /* - * 64-bit masking rules are simple: exceptions to EL3 - * can't be masked, and exceptions to EL2 can only be - * masked from Secure state. The HCR and SCR settings - * don't affect the masking logic, only the interrupt routing. - */ - if (target_el == 3 || !secure || (env->cp15.scr_el3 & SCR_EEL2)) { + switch (target_el) { + case 2: + /* + * According to ARM DDI 0487H.a, an interrupt can be masked + * when HCR_E2H and HCR_TGE are both set regardless of the + * current Security state. Note that we need to revisit this + * part again once we need to support NMI. + */ + if ((hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { + unmasked = true; + } + break; + case 3: + /* Interrupt cannot be masked when the target EL is 3 */ unmasked = true; + break; + default: + g_assert_not_reached(); } } else { /* @@ -629,6 +719,17 @@ static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) goto found; } } + if (interrupt_request & CPU_INTERRUPT_VSERR) { + excp_idx = EXCP_VSERR; + target_el = 1; + if (arm_excp_unmasked(cs, excp_idx, target_el, + cur_el, secure, hcr_el2)) { + /* Taking a virtual abort clears HCR_EL2.VSE */ + env->cp15.hcr_el2 &= ~HCR_VSE; + cpu_reset_interrupt(cs, CPU_INTERRUPT_VSERR); + goto found; + } + } return false; found: @@ -637,7 +738,8 @@ static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) cc->tcg_ops->do_interrupt(cs); return true; } -#endif /* !CONFIG_USER_ONLY */ + +#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ void arm_cpu_update_virq(ARMCPU *cpu) { @@ -681,6 +783,25 @@ void arm_cpu_update_vfiq(ARMCPU *cpu) } } +void arm_cpu_update_vserr(ARMCPU *cpu) +{ + /* + * Update the interrupt level for VSERR, which is the HCR_EL2.VSE bit. + */ + CPUARMState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + bool new_state = env->cp15.hcr_el2 & HCR_VSE; + + if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VSERR) != 0)) { + if (new_state) { + cpu_interrupt(cs, CPU_INTERRUPT_VSERR); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VSERR); + } + } +} + #ifndef CONFIG_USER_ONLY static void arm_cpu_set_irq(void *opaque, int irq, int level) { @@ -694,6 +815,16 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level) [ARM_CPU_VFIQ] = CPU_INTERRUPT_VFIQ }; + if (!arm_feature(env, ARM_FEATURE_EL2) && + (irq == ARM_CPU_VIRQ || irq == ARM_CPU_VFIQ)) { + /* + * The GIC might tell us about VIRQ and VFIQ state, but if we don't + * have EL2 support we don't care. (Unless the guest is doing something + * silly this will only be calls saying "level is still 0".) + */ + return; + } + if (level) { env->irq_line_state |= mask[irq]; } else { @@ -702,11 +833,9 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level) switch (irq) { case ARM_CPU_VIRQ: - assert(arm_feature(env, ARM_FEATURE_EL2)); arm_cpu_update_virq(cpu); break; case ARM_CPU_VFIQ: - assert(arm_feature(env, ARM_FEATURE_EL2)); arm_cpu_update_vfiq(cpu); break; case ARM_CPU_IRQ: @@ -764,12 +893,6 @@ static bool arm_cpu_virtio_is_big_endian(CPUState *cs) #endif -static int -print_insn_thumb1(bfd_vma pc, disassemble_info *info) -{ - return print_insn_arm(pc | 1, info); -} - static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) { ARMCPU *ac = ARM_CPU(cpu); @@ -777,25 +900,16 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) bool sctlr_b; if (is_a64(env)) { - /* We might not be compiled with the A64 disassembler - * because it needs a C++ compiler. Leave print_insn - * unset in this case to use the caller default behaviour. - */ -#if defined(CONFIG_ARM_A64_DIS) - info->print_insn = print_insn_arm_a64; -#endif info->cap_arch = CS_ARCH_ARM64; info->cap_insn_unit = 4; info->cap_insn_split = 4; } else { int cap_mode; if (env->thumb) { - info->print_insn = print_insn_thumb1; info->cap_insn_unit = 2; info->cap_insn_split = 4; cap_mode = CS_MODE_THUMB; } else { - info->print_insn = print_insn_arm; info->cap_insn_unit = 4; info->cap_insn_split = 4; cap_mode = CS_MODE_ARM; @@ -812,7 +926,7 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) sctlr_b = arm_sctlr_b(env); if (bswap_code(sctlr_b)) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN info->endian = BFD_ENDIAN_LITTLE; #else info->endian = BFD_ENDIAN_BIG; @@ -836,6 +950,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) int i; int el = arm_current_el(env); const char *ns_status; + bool sve; qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); for (i = 0; i < 32; i++) { @@ -862,6 +977,12 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) el, psr & PSTATE_SP ? 'h' : 't'); + if (cpu_isar_feature(aa64_sme, cpu)) { + qemu_fprintf(f, " SVCR=%08" PRIx64 " %c%c", + env->svcr, + (FIELD_EX64(env->svcr, SVCR, ZA) ? 'Z' : '-'), + (FIELD_EX64(env->svcr, SVCR, SM) ? 'S' : '-')); + } if (cpu_isar_feature(aa64_bti, cpu)) { qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); } @@ -876,8 +997,16 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n", vfp_get_fpcr(env), vfp_get_fpsr(env)); - if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { - int j, zcr_len = sve_zcr_len_for_el(env, el); + if (cpu_isar_feature(aa64_sme, cpu) && FIELD_EX64(env->svcr, SVCR, SM)) { + sve = sme_exception_el(env, el) == 0; + } else if (cpu_isar_feature(aa64_sve, cpu)) { + sve = sve_exception_el(env, el) == 0; + } else { + sve = false; + } + + if (sve) { + int j, zcr_len = sve_vqm1_for_el(env, el); for (i = 0; i <= FFR_PRED_NUM; i++) { bool eol; @@ -1060,27 +1189,13 @@ uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz) return (Aff1 << ARM_AFF1_SHIFT) | Aff0; } -static void cpreg_hashtable_data_destroy(gpointer data) -{ - /* - * Destroy function for cpu->cp_regs hashtable data entries. - * We must free the name string because it was g_strdup()ed in - * add_cpreg_to_hashtable(). It's OK to cast away the 'const' - * from r->name because we know we definitely allocated it. - */ - ARMCPRegInfo *r = data; - - g_free((void *)r->name); - g_free(r); -} - static void arm_cpu_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); cpu_set_cpustate_pointers(cpu); - cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, - g_free, cpreg_hashtable_data_destroy); + cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, g_free); QLIST_INIT(&cpu->pre_el_change_hooks); QLIST_INIT(&cpu->el_change_hooks); @@ -1088,11 +1203,13 @@ static void arm_cpu_initfn(Object *obj) #ifdef CONFIG_USER_ONLY # ifdef TARGET_AARCH64 /* - * The linux kernel defaults to 512-bit vectors, when sve is supported. - * See documentation for /proc/sys/abi/sve_default_vector_length, and - * our corresponding sve-default-vector-length cpu property. + * The linux kernel defaults to 512-bit for SVE, and 256-bit for SME. + * These values were chosen to fit within the default signal frame. + * See documentation for /proc/sys/abi/{sve,sme}_default_vector_length, + * and our corresponding cpu property. */ cpu->sve_default_vq = 4; + cpu->sme_default_vq = 2; # endif #else /* Our inbound IRQ and FIQ lines */ @@ -1239,7 +1356,7 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property); } - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + if (arm_feature(&cpu->env, ARM_FEATURE_V8)) { object_property_add_uint64_ptr(obj, "rvbar", &cpu->rvbar_prop, OBJ_PROP_FLAG_READWRITE); @@ -1387,6 +1504,7 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) { Error *local_err = NULL; +#ifdef TARGET_AARCH64 if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { arm_cpu_sve_finalize(cpu, &local_err); if (local_err != NULL) { @@ -1394,6 +1512,12 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) return; } + arm_cpu_sme_finalize(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + arm_cpu_pauth_finalize(cpu, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); @@ -1406,6 +1530,7 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) return; } } +#endif if (kvm_enabled()) { kvm_arm_steal_time_finalize(cpu, &local_err); @@ -1456,25 +1581,32 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } - if (kvm_enabled()) { + if (!tcg_enabled() && !qtest_enabled()) { /* + * We assume that no accelerator except TCG (and the "not really an + * accelerator" qtest) can handle these features, because Arm hardware + * virtualization can't virtualize them. + * * Catch all the cases which might cause us to create more than one * address space for the CPU (otherwise we will assert() later in * cpu_address_space_init()). */ if (arm_feature(env, ARM_FEATURE_M)) { error_setg(errp, - "Cannot enable KVM when using an M-profile guest CPU"); + "Cannot enable %s when using an M-profile guest CPU", + current_accel_name()); return; } if (cpu->has_el3) { error_setg(errp, - "Cannot enable KVM when guest CPU has EL3 enabled"); + "Cannot enable %s when guest CPU has EL3 enabled", + current_accel_name()); return; } if (cpu->tag_memory) { error_setg(errp, - "Cannot enable KVM when guest CPUs has MTE enabled"); + "Cannot enable %s when guest CPUs has MTE enabled", + current_accel_name()); return; } } @@ -1579,6 +1711,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) unset_feature(env, ARM_FEATURE_NEON); t = cpu->isar.id_aa64isar0; + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 0); t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0); cpu->isar.id_aa64isar0 = t; @@ -1593,6 +1731,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->isar.id_aa64pfr0 = t; u = cpu->isar.id_isar5; + u = FIELD_DP32(u, ID_ISAR5, AES, 0); + u = FIELD_DP32(u, ID_ISAR5, SHA1, 0); + u = FIELD_DP32(u, ID_ISAR5, SHA2, 0); u = FIELD_DP32(u, ID_ISAR5, RDM, 0); u = FIELD_DP32(u, ID_ISAR5, VCMA, 0); cpu->isar.id_isar5 = u; @@ -1795,11 +1936,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) */ unset_feature(env, ARM_FEATURE_EL3); - /* Disable the security extension feature bits in the processor feature - * registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12]. + /* + * Disable the security extension feature bits in the processor + * feature registers as well. */ - cpu->isar.id_pfr1 &= ~0xf0; - cpu->isar.id_aa64pfr0 &= ~0xf000; + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, EL3, 0); } if (!cpu->has_el2) { @@ -1830,12 +1974,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } if (!arm_feature(env, ARM_FEATURE_EL2)) { - /* Disable the hypervisor feature bits in the processor feature - * registers if we don't have EL2. These are id_pfr1[15:12] and - * id_aa64pfr0_el1[11:8]. + /* + * Disable the hypervisor feature bits in the processor feature + * registers if we don't have EL2. */ - cpu->isar.id_aa64pfr0 &= ~0xf00; - cpu->isar.id_pfr1 &= ~0xf000; + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, EL2, 0); + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, + ID_PFR1, VIRTUALIZATION, 0); } #ifndef CONFIG_USER_ONLY @@ -1849,14 +1995,24 @@ 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. */ - if (!cpu->has_mpu) { - cpu->pmsav7_dregion = 0; - } - if (cpu->pmsav7_dregion == 0) { + if (!cpu->has_mpu || cpu->pmsav7_dregion == 0) { cpu->has_mpu = false; + cpu->pmsav7_dregion = 0; + cpu->pmsav8r_hdregion = 0; } if (arm_feature(env, ARM_FEATURE_PMSA) && @@ -1883,6 +2039,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) env->pmsav7.dracr = g_new0(uint32_t, nr); } } + + if (cpu->pmsav8r_hdregion > 0xff) { + error_setg(errp, "PMSAv8 MPU EL2 #regions invalid %" PRIu32, + cpu->pmsav8r_hdregion); + return; + } + + if (cpu->pmsav8r_hdregion) { + env->pmsav8.hprbar = g_new0(uint32_t, + cpu->pmsav8r_hdregion); + env->pmsav8.hprlar = g_new0(uint32_t, + cpu->pmsav8r_hdregion); + } } if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { @@ -2044,6 +2213,7 @@ static const struct TCGCPUOps arm_tcg_ops = { .initialize = arm_translate_init, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, + .restore_state_to_opc = arm_restore_state_to_opc, #ifdef CONFIG_USER_ONLY .record_sigsegv = arm_cpu_record_sigsegv, @@ -2066,17 +2236,21 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) ARMCPUClass *acc = ARM_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(acc); DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, arm_cpu_realizefn, &acc->parent_realize); device_class_set_props(dc, arm_cpu_properties); - device_class_set_parent_reset(dc, arm_cpu_reset, &acc->parent_reset); + + resettable_class_set_parent_phases(rc, NULL, arm_cpu_reset_hold, NULL, + &acc->parent_phases); cc->class_by_name = arm_cpu_class_by_name; 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 23879de5fa7f..bf2bce046d56 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -21,6 +21,7 @@ #define ARM_CPU_H #include "kvm-consts.h" +#include "qemu/cpu-float.h" #include "hw/registerfields.h" #include "cpu-qom.h" #include "exec/cpu-defs.h" @@ -55,6 +56,7 @@ #define EXCP_LSERR 21 /* v8M LSERR SecureFault */ #define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */ #define EXCP_DIVBYZERO 23 /* v7M DIVBYZERO UsageFault */ +#define EXCP_VSERR 24 /* NB: add new EXCP_ defines to the array in arm_log_exception() too */ #define ARMV7M_EXCP_RESET 1 @@ -88,6 +90,7 @@ enum { #define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1 #define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2 #define CPU_INTERRUPT_VFIQ CPU_INTERRUPT_TGT_EXT_3 +#define CPU_INTERRUPT_VSERR CPU_INTERRUPT_TGT_INT_0 /* The usual mapping for an AArch64 system register to its AArch32 * counterpart is for the 32 bit world to have access to the lower @@ -95,7 +98,7 @@ enum { * therefore useful to be able to pass TCG the offset of the least * significant half of a uint64_t struct member. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define offsetoflow32(S, M) (offsetof(S, M) + sizeof(uint32_t)) #define offsetofhigh32(S, M) offsetof(S, M) #else @@ -163,12 +166,6 @@ typedef struct ARMGenericTimer { #define GTIMER_HYPVIRT 4 #define NUM_GTIMERS 5 -typedef struct { - uint64_t raw_tcr; - uint32_t mask; - uint32_t base_mask; -} TCR; - #define VTCR_NSW (1u << 29) #define VTCR_NSA (1u << 30) #define VSTCR_SW VTCR_NSW @@ -202,14 +199,8 @@ typedef struct { #ifdef TARGET_AARCH64 # define ARM_MAX_VQ 16 -void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp); -void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp); -void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp); #else # define ARM_MAX_VQ 1 -static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { } -static inline void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) { } -static inline void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) { } #endif typedef struct ARMVectorReg { @@ -234,6 +225,8 @@ typedef struct CPUARMTBFlags { target_ulong flags2; } CPUARMTBFlags; +typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; + typedef struct CPUArchState { /* Regs for current mode. */ uint32_t regs[16]; @@ -255,10 +248,12 @@ typedef struct CPUArchState { * nRW (also known as M[4]) is kept, inverted, in env->aarch64 * DAIF (exception masks) are kept in env->daif * BTYPE is kept in env->btype + * SM and ZA are kept in env->svcr * all other bits are stored in their correct places in env->pstate */ uint32_t pstate; - uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */ + bool aarch64; /* True if CPU is in aarch64 state; inverse of PSTATE.nRW */ + bool thumb; /* True if CPU is in thumb mode; cpsr[5] */ /* Cached TBFLAGS state. See below for which bits are included. */ CPUARMTBFlags hflags; @@ -285,10 +280,10 @@ typedef struct CPUArchState { uint32_t ZF; /* Z set if zero. */ uint32_t QF; /* 0 or 1 */ uint32_t GE; /* cpsr[19:16] */ - uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */ uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */ uint32_t btype; /* BTI branch type. spsr[11:10]. */ uint64_t daif; /* exception masks, in the bits they are in PSTATE */ + uint64_t svcr; /* PSTATE.{SM,ZA} in the bits they are in SVCR */ uint64_t elr_el[4]; /* AArch64 exception link regs */ uint64_t sp_el[4]; /* AArch64 banked stack pointers */ @@ -314,6 +309,7 @@ typedef struct CPUArchState { }; uint64_t sctlr_el[4]; }; + uint64_t vsctlr; /* Virtualization System control register. */ uint64_t cpacr_el1; /* Architectural feature access control register */ uint64_t cptr_el[4]; /* ARMv8 feature trap registers */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ @@ -340,9 +336,9 @@ typedef struct CPUArchState { uint64_t vttbr_el2; /* Virtualization Translation Table Base. */ uint64_t vsttbr_el2; /* Secure Virtualization Translation Table. */ /* MMU translation table base control. */ - TCR tcr_el[4]; - TCR vtcr_el2; /* Virtualization Translation Control. */ - TCR vstcr_el2; /* Secure Virtualization Translation Control. */ + uint64_t tcr_el[4]; + uint64_t vtcr_el2; /* Virtualization Translation Control. */ + uint64_t vstcr_el2; /* Secure Virtualization Translation Control. */ uint32_t c2_data; /* MPU data cacheable bits. */ uint32_t c2_insn; /* MPU instruction cacheable bits. */ union { /* MMU domain access control register @@ -359,6 +355,7 @@ typedef struct CPUArchState { uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */ uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */ uint64_t hcr_el2; /* Hypervisor configuration register */ + uint64_t hcrx_el2; /* Extended Hypervisor configuration register */ uint64_t scr_el3; /* Secure configuration register. */ union { /* Fault status registers. */ struct { @@ -382,7 +379,7 @@ typedef struct CPUArchState { union { /* Fault address registers. */ struct { uint64_t _unused_far0; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint32_t ifar_ns; uint32_t dfar_ns; uint32_t ifar_s; @@ -419,7 +416,7 @@ typedef struct CPUArchState { uint64_t c9_pminten; /* perf monitor interrupt enables */ union { /* Memory attribute redirection */ struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint64_t _unused_mair_0; uint32_t mair1_ns; uint32_t mair0_ns; @@ -470,6 +467,7 @@ typedef struct CPUArchState { }; uint64_t tpidr_el[4]; }; + uint64_t tpidr2_el0; /* The secure banks of these registers don't map anywhere */ uint64_t tpidrurw_s; uint64_t tpidrprw_s; @@ -499,6 +497,7 @@ typedef struct CPUArchState { uint64_t dbgwcr[16]; /* watchpoint control registers */ uint64_t mdscr_el1; uint64_t oslsr_el1; /* OS Lock Status */ + uint64_t osdlr_el1; /* OS DoubleLock status */ uint64_t mdcr_el2; uint64_t mdcr_el3; /* Stores the architectural value of the counter *the last time it was @@ -524,6 +523,11 @@ typedef struct CPUArchState { uint64_t tfsr_el[4]; /* tfsre0_el1 is index 0. */ uint64_t gcr_el1; uint64_t rgsr_el1; + + /* Minimal RAS registers */ + uint64_t disr_el1; + uint64_t vdisr_el2; + uint64_t vsesr_el2; } cp15; struct { @@ -657,8 +661,8 @@ typedef struct CPUArchState { float_status standard_fp_status; float_status standard_fp_status_f16; - /* ZCR_EL[1-3] */ - uint64_t zcr_el[4]; + uint64_t zcr_el[4]; /* ZCR_EL[1-3] */ + uint64_t smcr_el[4]; /* SMCR_EL[1-3] */ } vfp; uint64_t exclusive_addr; uint64_t exclusive_val; @@ -680,6 +684,30 @@ typedef struct CPUArchState { ARMPACKey apdb; ARMPACKey apga; } keys; + + uint64_t scxtnum_el[4]; + + /* + * SME ZA storage -- 256 x 256 byte array, with bytes in host word order, + * as we do with vfp.zregs[]. This corresponds to the architectural ZA + * array, where ZA[N] is in the least-significant bytes of env->zarray[N]. + * When SVL is less than the architectural maximum, the accessible + * storage is restricted, such that if the SVL is X bytes the guest can + * see only the bottom X elements of zarray[], and only the least + * significant X bytes of each element of the array. (In other words, + * the observable part is always square.) + * + * The ZA storage can also be considered as a set of square tiles of + * elements of different sizes. The mapping from tiles to the ZA array + * is architecturally defined, such that for tiles of elements of esz + * bytes, the Nth row (or "horizontal slice") of tile T is in + * ZA[T + N * esz]. Note that this means that each tile is not contiguous + * in the ZA storage, because its rows are striped through the ZA array. + * + * Because this is so large, keep this toward the end of the reset area, + * to keep the offsets into the rest of the structure smaller. + */ + ARMVectorReg zarray[ARM_MAX_VQ * 16]; #endif #if defined(CONFIG_USER_ONLY) @@ -690,6 +718,9 @@ typedef struct CPUArchState { struct CPUBreakpoint *cpu_breakpoint[16]; struct CPUWatchpoint *cpu_watchpoint[16]; + /* Optional fault info across tlb lookup. */ + ARMMMUFaultInfo *tlb_fi; + /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; @@ -715,8 +746,11 @@ typedef struct CPUArchState { */ uint32_t *rbar[M_REG_NUM_BANKS]; uint32_t *rlar[M_REG_NUM_BANKS]; + uint32_t *hprbar; + uint32_t *hprlar; uint32_t mair0[M_REG_NUM_BANKS]; uint32_t mair1[M_REG_NUM_BANKS]; + uint32_t hprselr; } pmsav8; /* v8M SAU */ @@ -771,6 +805,19 @@ typedef enum ARMPSCIState { typedef struct ARMISARegisters ARMISARegisters; +/* + * In map, each set bit is a supported vector length of (bit-number + 1) * 16 + * bytes, i.e. each bit number + 1 is the vector length in quadwords. + * + * While processing properties during initialization, corresponding init bits + * are set for bits in sve_vq_map that have been set by properties. + * + * Bits set in supported represent valid vector lengths for the CPU type. + */ +typedef struct { + uint32_t map, init, supported; +} ARMVQMap; + /** * ARMCPU: * @env: #CPUARMState @@ -863,6 +910,8 @@ struct ArchCPU { bool has_mpu; /* PMSAv7 MPU number of supported regions */ uint32_t pmsav7_dregion; + /* PMSAv8 MPU number of supported hyp regions */ + uint32_t pmsav8r_hdregion; /* v8M SAU number of supported regions */ uint32_t sau_sregion; @@ -937,6 +986,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; @@ -944,7 +994,10 @@ 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; uint64_t id_aa64isar0; uint64_t id_aa64isar1; uint64_t id_aa64pfr0; @@ -955,6 +1008,8 @@ struct ArchCPU { uint64_t id_aa64dfr0; uint64_t id_aa64dfr1; uint64_t id_aa64zfr0; + uint64_t id_aa64smfr0; + uint64_t reset_pmcr_el0; } isar; uint64_t midr; uint32_t revidr; @@ -992,6 +1047,7 @@ struct ArchCPU { int gic_num_lrs; /* number of list registers */ int gic_vpribits; /* number of virtual priority bits */ int gic_vprebits; /* number of virtual preemption bits */ + int gic_pribits; /* number of physical priority bits */ /* Whether the cfgend input is high (i.e. this CPU should reset into * big-endian mode). This setting isn't used directly: instead it modifies @@ -1014,23 +1070,11 @@ struct ArchCPU { #ifdef CONFIG_USER_ONLY /* Used to set the default vector length at process start. */ uint32_t sve_default_vq; + uint32_t sme_default_vq; #endif - /* - * In sve_vq_map each set bit is a supported vector length of - * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector - * length in quadwords. - * - * While processing properties during initialization, corresponding - * sve_vq_init bits are set for bits in sve_vq_map that have been - * set by properties. - * - * Bits set in sve_vq_supported represent valid vector lengths for - * the CPU type. - */ - DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); - DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); - DECLARE_BITMAP(sve_vq_supported, ARM_MAX_VQ); + ARMVQMap sve_vq; + ARMVQMap sme_vq; /* Generic timer counter frequency, in Hz */ uint64_t gt_cntfrq_hz; @@ -1069,9 +1113,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); @@ -1079,8 +1123,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el, bool el0_a64); -void aarch64_add_sve_properties(Object *obj); -void aarch64_add_pauth_properties(Object *obj); +void arm_reset_sve_state(CPUARMState *env); /* * SVE registers are encoded in KVM's memory in an endianness-invariant format. @@ -1093,7 +1136,7 @@ void aarch64_add_pauth_properties(Object *obj); */ static inline uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN int i; for (i = 0; i < nr; ++i) { @@ -1111,7 +1154,6 @@ static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { } static inline void aarch64_sve_change_el(CPUARMState *env, int o, int n, bool a) { } -static inline void aarch64_add_sve_properties(Object *obj) { } #endif void aarch64_sync_32_to_64(CPUARMState *env); @@ -1119,7 +1161,22 @@ void aarch64_sync_64_to_32(CPUARMState *env); int fp_exception_el(CPUARMState *env, int cur_el); int sve_exception_el(CPUARMState *env, int cur_el); -uint32_t sve_zcr_len_for_el(CPUARMState *env, int el); +int sme_exception_el(CPUARMState *env, int cur_el); + +/** + * sve_vqm1_for_el_sm: + * @env: CPUARMState + * @el: exception level + * @sm: streaming mode + * + * Compute the current vector length for @el & @sm, in units of + * Quadwords Minus 1 -- the same scale used for ZCR_ELx.LEN. + * If @sm, compute for SVL, otherwise NVL. + */ +uint32_t sve_vqm1_for_el_sm(CPUARMState *env, int el, bool sm); + +/* Likewise, but using @sm = PSTATE.SM. */ +uint32_t sve_vqm1_for_el(CPUARMState *env, int el); static inline bool is_a64(CPUARMState *env) { @@ -1203,6 +1260,7 @@ void pmu_init(ARMCPU *cpu); #define SCTLR_WXN (1U << 19) #define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */ #define SCTLR_UWXN (1U << 20) /* v7 onward, AArch32 only */ +#define SCTLR_TSCXT (1U << 20) /* FEAT_CSV2_1p2, AArch64 only */ #define SCTLR_FI (1U << 21) /* up to v7, v8 RES0 */ #define SCTLR_IESB (1U << 21) /* v8.2-IESB, AArch64 only */ #define SCTLR_U (1U << 22) /* up to v6, RAO in v7 */ @@ -1232,15 +1290,70 @@ void pmu_init(ARMCPU *cpu); #define SCTLR_ATA0 (1ULL << 42) /* v8.5-MemTag */ #define SCTLR_ATA (1ULL << 43) /* v8.5-MemTag */ #define SCTLR_DSSBS_64 (1ULL << 44) /* v8.5, AArch64 only */ - -#define CPTR_TCPAC (1U << 31) -#define CPTR_TTA (1U << 20) -#define CPTR_TFP (1U << 10) -#define CPTR_TZ (1U << 8) /* CPTR_EL2 */ -#define CPTR_EZ (1U << 8) /* CPTR_EL3 */ - +#define SCTLR_TWEDEn (1ULL << 45) /* FEAT_TWED */ +#define SCTLR_TWEDEL MAKE_64_MASK(46, 4) /* FEAT_TWED */ +#define SCTLR_TMT0 (1ULL << 50) /* FEAT_TME */ +#define SCTLR_TMT (1ULL << 51) /* FEAT_TME */ +#define SCTLR_TME0 (1ULL << 52) /* FEAT_TME */ +#define SCTLR_TME (1ULL << 53) /* FEAT_TME */ +#define SCTLR_EnASR (1ULL << 54) /* FEAT_LS64_V */ +#define SCTLR_EnAS0 (1ULL << 55) /* FEAT_LS64_ACCDATA */ +#define SCTLR_EnALS (1ULL << 56) /* FEAT_LS64 */ +#define SCTLR_EPAN (1ULL << 57) /* FEAT_PAN3 */ +#define SCTLR_EnTP2 (1ULL << 60) /* FEAT_SME */ +#define SCTLR_NMI (1ULL << 61) /* FEAT_NMI */ +#define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */ +#define SCTLR_TIDCP (1ULL << 63) /* FEAT_TIDCP1 */ + +/* Bit definitions for CPACR (AArch32 only) */ +FIELD(CPACR, CP10, 20, 2) +FIELD(CPACR, CP11, 22, 2) +FIELD(CPACR, TRCDIS, 28, 1) /* matches CPACR_EL1.TTA */ +FIELD(CPACR, D32DIS, 30, 1) /* up to v7; RAZ in v8 */ +FIELD(CPACR, ASEDIS, 31, 1) + +/* Bit definitions for CPACR_EL1 (AArch64 only) */ +FIELD(CPACR_EL1, ZEN, 16, 2) +FIELD(CPACR_EL1, FPEN, 20, 2) +FIELD(CPACR_EL1, SMEN, 24, 2) +FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */ + +/* Bit definitions for HCPTR (AArch32 only) */ +FIELD(HCPTR, TCP10, 10, 1) +FIELD(HCPTR, TCP11, 11, 1) +FIELD(HCPTR, TASE, 15, 1) +FIELD(HCPTR, TTA, 20, 1) +FIELD(HCPTR, TAM, 30, 1) /* matches CPTR_EL2.TAM */ +FIELD(HCPTR, TCPAC, 31, 1) /* matches CPTR_EL2.TCPAC */ + +/* Bit definitions for CPTR_EL2 (AArch64 only) */ +FIELD(CPTR_EL2, TZ, 8, 1) /* !E2H */ +FIELD(CPTR_EL2, TFP, 10, 1) /* !E2H, matches HCPTR.TCP10 */ +FIELD(CPTR_EL2, TSM, 12, 1) /* !E2H */ +FIELD(CPTR_EL2, ZEN, 16, 2) /* E2H */ +FIELD(CPTR_EL2, FPEN, 20, 2) /* E2H */ +FIELD(CPTR_EL2, SMEN, 24, 2) /* E2H */ +FIELD(CPTR_EL2, TTA, 28, 1) +FIELD(CPTR_EL2, TAM, 30, 1) /* matches HCPTR.TAM */ +FIELD(CPTR_EL2, TCPAC, 31, 1) /* matches HCPTR.TCPAC */ + +/* Bit definitions for CPTR_EL3 (AArch64 only) */ +FIELD(CPTR_EL3, EZ, 8, 1) +FIELD(CPTR_EL3, TFP, 10, 1) +FIELD(CPTR_EL3, ESM, 12, 1) +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) @@ -1255,7 +1368,9 @@ void pmu_init(ARMCPU *cpu); #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) @@ -1319,6 +1434,25 @@ void pmu_init(ARMCPU *cpu); #define TTBCR_SH1 (1U << 28) #define TTBCR_EAE (1U << 31) +FIELD(VTCR, T0SZ, 0, 6) +FIELD(VTCR, SL0, 6, 2) +FIELD(VTCR, IRGN0, 8, 2) +FIELD(VTCR, ORGN0, 10, 2) +FIELD(VTCR, SH0, 12, 2) +FIELD(VTCR, TG0, 14, 2) +FIELD(VTCR, PS, 16, 3) +FIELD(VTCR, VS, 19, 1) +FIELD(VTCR, HA, 21, 1) +FIELD(VTCR, HD, 22, 1) +FIELD(VTCR, HWU59, 25, 1) +FIELD(VTCR, HWU60, 26, 1) +FIELD(VTCR, HWU61, 27, 1) +FIELD(VTCR, HWU62, 28, 1) +FIELD(VTCR, NSW, 29, 1) +FIELD(VTCR, NSA, 30, 1) +FIELD(VTCR, DS, 32, 1) +FIELD(VTCR, SL2, 33, 1) + /* Bit definitions for ARMv8 SPSR (PSTATE) format. * Only these are valid when in AArch64 mode; in * AArch32 mode SPSRs are basically CPSR-format. @@ -1354,6 +1488,14 @@ void pmu_init(ARMCPU *cpu); #define PSTATE_MODE_EL1t 4 #define PSTATE_MODE_EL0t 0 +/* PSTATE bits that are accessed via SVCR and not stored in SPSR_ELx. */ +FIELD(SVCR, SM, 0, 1) +FIELD(SVCR, ZA, 1, 1) + +/* Fields for SMCR_ELx. */ +FIELD(SMCR, LEN, 0, 4) +FIELD(SMCR, FA64, 31, 1) + /* Write a new value to v7m.exception, thus transitioning into or out * of Handler mode; this may result in a change of active stack pointer. */ @@ -1518,32 +1660,57 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HCR_TWEDEN (1ULL << 59) #define HCR_TWEDEL MAKE_64BIT_MASK(60, 4) +#define HCRX_ENAS0 (1ULL << 0) +#define HCRX_ENALS (1ULL << 1) +#define HCRX_ENASR (1ULL << 2) +#define HCRX_FNXS (1ULL << 3) +#define HCRX_FGTNXS (1ULL << 4) +#define HCRX_SMPME (1ULL << 5) +#define HCRX_TALLINT (1ULL << 6) +#define HCRX_VINMI (1ULL << 7) +#define HCRX_VFNMI (1ULL << 8) +#define HCRX_CMOW (1ULL << 9) +#define HCRX_MCE2 (1ULL << 10) +#define HCRX_MSCEN (1ULL << 11) + #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_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) +#define SCR_ENAS0 (1ULL << 36) +#define SCR_ADEN (1ULL << 37) +#define SCR_HXEN (1ULL << 38) +#define SCR_TRNDR (1ULL << 40) +#define SCR_ENTP2 (1ULL << 41) +#define SCR_GPF (1ULL << 48) #define HSTR_TTEE (1 << 16) #define HSTR_TJDBX (1 << 17) @@ -1933,6 +2100,7 @@ FIELD(ID_MMFR4, CCIDX, 24, 4) FIELD(ID_MMFR4, EVT, 28, 4) FIELD(ID_MMFR5, ETS, 0, 4) +FIELD(ID_MMFR5, NTLBPA, 4, 4) FIELD(ID_PFR0, STATE0, 0, 4) FIELD(ID_PFR0, STATE1, 4, 4) @@ -1985,6 +2153,16 @@ FIELD(ID_AA64ISAR1, SPECRES, 40, 4) FIELD(ID_AA64ISAR1, BF16, 44, 4) FIELD(ID_AA64ISAR1, DGH, 48, 4) FIELD(ID_AA64ISAR1, I8MM, 52, 4) +FIELD(ID_AA64ISAR1, XS, 56, 4) +FIELD(ID_AA64ISAR1, LS64, 60, 4) + +FIELD(ID_AA64ISAR2, WFXT, 0, 4) +FIELD(ID_AA64ISAR2, RPRES, 4, 4) +FIELD(ID_AA64ISAR2, GPA3, 8, 4) +FIELD(ID_AA64ISAR2, APA3, 12, 4) +FIELD(ID_AA64ISAR2, MOPS, 16, 4) +FIELD(ID_AA64ISAR2, BC, 20, 4) +FIELD(ID_AA64ISAR2, PAC_FRAC, 24, 4) FIELD(ID_AA64PFR0, EL0, 0, 4) FIELD(ID_AA64PFR0, EL1, 4, 4) @@ -2007,6 +2185,10 @@ FIELD(ID_AA64PFR1, SSBS, 4, 4) FIELD(ID_AA64PFR1, MTE, 8, 4) FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4) FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4) +FIELD(ID_AA64PFR1, SME, 24, 4) +FIELD(ID_AA64PFR1, RNDR_TRAP, 28, 4) +FIELD(ID_AA64PFR1, CSV2_FRAC, 32, 4) +FIELD(ID_AA64PFR1, NMI, 36, 4) FIELD(ID_AA64MMFR0, PARANGE, 0, 4) FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4) @@ -2033,6 +2215,11 @@ FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) FIELD(ID_AA64MMFR1, XNX, 28, 4) FIELD(ID_AA64MMFR1, TWED, 32, 4) FIELD(ID_AA64MMFR1, ETS, 36, 4) +FIELD(ID_AA64MMFR1, HCX, 40, 4) +FIELD(ID_AA64MMFR1, AFP, 44, 4) +FIELD(ID_AA64MMFR1, NTLBPA, 48, 4) +FIELD(ID_AA64MMFR1, TIDCP1, 52, 4) +FIELD(ID_AA64MMFR1, CMOW, 56, 4) FIELD(ID_AA64MMFR2, CNP, 0, 4) FIELD(ID_AA64MMFR2, UAO, 4, 4) @@ -2059,7 +2246,10 @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) FIELD(ID_AA64DFR0, PMSVER, 32, 4) FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) +FIELD(ID_AA64DFR0, TRACEBUFFER, 44, 4) FIELD(ID_AA64DFR0, MTPMU, 48, 4) +FIELD(ID_AA64DFR0, BRBE, 52, 4) +FIELD(ID_AA64DFR0, HPMN0, 60, 4) FIELD(ID_AA64ZFR0, SVEVER, 0, 4) FIELD(ID_AA64ZFR0, AES, 4, 4) @@ -2071,6 +2261,15 @@ FIELD(ID_AA64ZFR0, I8MM, 44, 4) FIELD(ID_AA64ZFR0, F32MM, 52, 4) FIELD(ID_AA64ZFR0, F64MM, 56, 4) +FIELD(ID_AA64SMFR0, F32F32, 32, 1) +FIELD(ID_AA64SMFR0, B16F32, 34, 1) +FIELD(ID_AA64SMFR0, F16F32, 35, 1) +FIELD(ID_AA64SMFR0, I8I32, 36, 4) +FIELD(ID_AA64SMFR0, F64F64, 48, 1) +FIELD(ID_AA64SMFR0, I16I64, 52, 4) +FIELD(ID_AA64SMFR0, SMEVER, 56, 4) +FIELD(ID_AA64SMFR0, FA64, 63, 1) + FIELD(ID_DFR0, COPDBG, 0, 4) FIELD(ID_DFR0, COPSDBG, 4, 4) FIELD(ID_DFR0, MMAPDBG, 8, 4) @@ -2081,6 +2280,7 @@ FIELD(ID_DFR0, PERFMON, 24, 4) FIELD(ID_DFR0, TRACEFILT, 28, 4) FIELD(ID_DFR1, MTPMU, 0, 4) +FIELD(ID_DFR1, HPMN0, 4, 4) FIELD(DBGDIDR, SE_IMP, 12, 1) FIELD(DBGDIDR, NSUHD_IMP, 14, 1) @@ -2089,6 +2289,15 @@ FIELD(DBGDIDR, CTX_CMPS, 20, 4) FIELD(DBGDIDR, BRPS, 24, 4) FIELD(DBGDIDR, WRPS, 28, 4) +FIELD(DBGDEVID, PCSAMPLE, 0, 4) +FIELD(DBGDEVID, WPADDRMASK, 4, 4) +FIELD(DBGDEVID, BPADDRMASK, 8, 4) +FIELD(DBGDEVID, VECTORCATCH, 12, 4) +FIELD(DBGDEVID, VIRTEXTNS, 16, 4) +FIELD(DBGDEVID, DOUBLELOCK, 20, 4) +FIELD(DBGDEVID, AUXREGS, 24, 4) +FIELD(DBGDEVID, CIDMASK, 28, 4) + FIELD(MVFR0, SIMDREG, 0, 4) FIELD(MVFR0, FPSP, 4, 4) FIELD(MVFR0, FPDP, 8, 4) @@ -2214,15 +2423,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 @@ -2236,6 +2445,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; @@ -2248,7 +2462,9 @@ 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); /* Return true if the specified exception level is running in AArch64 state. */ static inline bool arm_el_is_aa64(CPUARMState *env, int el) @@ -2544,144 +2760,6 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) return kvmid; } -/* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a - * special-behaviour cp reg and bits [11..8] indicate what behaviour - * it has. Otherwise it is a simple cp reg, where CONST indicates that - * TCG can assume the value to be constant (ie load at translate time) - * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END - * indicates that the TB should not be ended after a write to this register - * (the default is that the TB ends after cp writes). OVERRIDE permits - * a register definition to override a previous definition for the - * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the - * old must have the OVERRIDE bit set. - * ALIAS indicates that this register is an alias view of some underlying - * state which is also visible via another register, and that the other - * register is handling migration and reset; registers marked ALIAS will not be - * migrated but may have their state set by syncing of register state from KVM. - * NO_RAW indicates that this register has no underlying state and does not - * support raw access for state saving/loading; it will not be used for either - * migration or KVM state synchronization. (Typically this is for "registers" - * which are actually used as instructions for cache maintenance and so on.) - * IO indicates that this register does I/O and therefore its accesses - * need to be marked with gen_io_start() and also end the TB. In particular, - * registers which implement clocks or timers require this. - * RAISES_EXC is for when the read or write hook might raise an exception; - * the generated code will synchronize the CPU state before calling the hook - * so that it is safe for the hook to call raise_exception(). - * NEWEL is for writes to registers that might change the exception - * level - typically on older ARM chips. For those cases we need to - * re-read the new el when recomputing the translation flags. - */ -#define ARM_CP_SPECIAL 0x0001 -#define ARM_CP_CONST 0x0002 -#define ARM_CP_64BIT 0x0004 -#define ARM_CP_SUPPRESS_TB_END 0x0008 -#define ARM_CP_OVERRIDE 0x0010 -#define ARM_CP_ALIAS 0x0020 -#define ARM_CP_IO 0x0040 -#define ARM_CP_NO_RAW 0x0080 -#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100) -#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200) -#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300) -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400) -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500) -#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600) -#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700) -#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA -#define ARM_CP_FPU 0x1000 -#define ARM_CP_SVE 0x2000 -#define ARM_CP_NO_GDB 0x4000 -#define ARM_CP_RAISES_EXC 0x8000 -#define ARM_CP_NEWEL 0x10000 -/* Used only as a terminator for ARMCPRegInfo lists */ -#define ARM_CP_SENTINEL 0xfffff -/* Mask of only the flag bits in a type field */ -#define ARM_CP_FLAG_MASK 0x1f0ff - -/* Valid values for ARMCPRegInfo state field, indicating which of - * the AArch32 and AArch64 execution states this register is visible in. - * If the reginfo doesn't explicitly specify then it is AArch32 only. - * If the reginfo is declared to be visible in both states then a second - * reginfo is synthesised for the AArch32 view of the AArch64 register, - * such that the AArch32 view is the lower 32 bits of the AArch64 one. - * Note that we rely on the values of these enums as we iterate through - * the various states in some places. - */ -enum { - ARM_CP_STATE_AA32 = 0, - ARM_CP_STATE_AA64 = 1, - ARM_CP_STATE_BOTH = 2, -}; - -/* ARM CP register secure state flags. These flags identify security state - * attributes for a given CP register entry. - * The existence of both or neither secure and non-secure flags indicates that - * the register has both a secure and non-secure hash entry. A single one of - * these flags causes the register to only be hashed for the specified - * security state. - * Although definitions may have any combination of the S/NS bits, each - * registered entry will only have one to identify whether the entry is secure - * or non-secure. - */ -enum { - ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ - ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ -}; - -/* Return true if cptype is a valid type field. This is used to try to - * catch errors where the sentinel has been accidentally left off the end - * of a list of registers. - */ -static inline bool cptype_valid(int cptype) -{ - return ((cptype & ~ARM_CP_FLAG_MASK) == 0) - || ((cptype & ARM_CP_SPECIAL) && - ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL)); -} - -/* Access rights: - * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM - * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and - * PL2 (hyp). The other level which has Read and Write bits is Secure PL1 - * (ie any of the privileged modes in Secure state, or Monitor mode). - * If a register is accessible in one privilege level it's always accessible - * in higher privilege levels too. Since "Secure PL1" also follows this rule - * (ie anything visible in PL2 is visible in S-PL1, some things are only - * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the - * terminology a little and call this PL3. - * In AArch64 things are somewhat simpler as the PLx bits line up exactly - * with the ELx exception levels. - * - * If access permissions for a register are more complex than can be - * described with these bits, then use a laxer set of restrictions, and - * do the more restrictive/complex check inside a helper function. - */ -#define PL3_R 0x80 -#define PL3_W 0x40 -#define PL2_R (0x20 | PL3_R) -#define PL2_W (0x10 | PL3_W) -#define PL1_R (0x08 | PL2_R) -#define PL1_W (0x04 | PL2_W) -#define PL0_R (0x02 | PL1_R) -#define PL0_W (0x01 | PL1_W) - -/* - * For user-mode some registers are accessible to EL0 via a kernel - * trap-and-emulate ABI. In this case we define the read permissions - * as actually being PL0_R. However some bits of any given register - * may still be masked. - */ -#ifdef CONFIG_USER_ONLY -#define PL0U_R PL0_R -#else -#define PL0U_R PL1_R -#endif - -#define PL3_RW (PL3_R | PL3_W) -#define PL2_RW (PL2_R | PL2_W) -#define PL1_RW (PL1_R | PL1_W) -#define PL0_RW (PL0_R | PL0_W) - /* Return the highest implemented Exception Level */ static inline int arm_highest_el(CPUARMState *env) { @@ -2733,241 +2811,6 @@ static inline int arm_current_el(CPUARMState *env) } } -typedef struct ARMCPRegInfo ARMCPRegInfo; - -typedef enum CPAccessResult { - /* Access is permitted */ - CP_ACCESS_OK = 0, - /* Access fails due to a configurable trap or enable which would - * result in a categorized exception syndrome giving information about - * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6, - * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or - * PL1 if in EL0, otherwise to the current EL). - */ - CP_ACCESS_TRAP = 1, - /* Access fails and results in an exception syndrome 0x0 ("uncategorized"). - * Note that this is not a catch-all case -- the set of cases which may - * result in this failure is specifically defined by the architecture. - */ - CP_ACCESS_TRAP_UNCATEGORIZED = 2, - /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */ - CP_ACCESS_TRAP_EL2 = 3, - CP_ACCESS_TRAP_EL3 = 4, - /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */ - CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5, - CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6, - /* Access fails and results in an exception syndrome for an FP access, - * trapped directly to EL2 or EL3 - */ - CP_ACCESS_TRAP_FP_EL2 = 7, - CP_ACCESS_TRAP_FP_EL3 = 8, -} CPAccessResult; - -/* Access functions for coprocessor registers. These cannot fail and - * may not raise exceptions. - */ -typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque); -typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque, - uint64_t value); -/* Access permission check functions for coprocessor registers. */ -typedef CPAccessResult CPAccessFn(CPUARMState *env, - const ARMCPRegInfo *opaque, - bool isread); -/* Hook function for register reset */ -typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); - -#define CP_ANY 0xff - -/* Definition of an ARM coprocessor register */ -struct ARMCPRegInfo { - /* Name of register (useful mainly for debugging, need not be unique) */ - const char *name; - /* Location of register: coprocessor number and (crn,crm,opc1,opc2) - * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a - * 'wildcard' field -- any value of that field in the MRC/MCR insn - * will be decoded to this register. The register read and write - * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2 - * used by the program, so it is possible to register a wildcard and - * then behave differently on read/write if necessary. - * For 64 bit registers, only crm and opc1 are relevant; crn and opc2 - * must both be zero. - * For AArch64-visible registers, opc0 is also used. - * Since there are no "coprocessors" in AArch64, cp is purely used as a - * way to distinguish (for KVM's benefit) guest-visible system registers - * from demuxed ones provided to preserve the "no side effects on - * KVM register read/write from QEMU" semantics. cp==0x13 is guest - * visible (to match KVM's encoding); cp==0 will be converted to - * cp==0x13 when the ARMCPRegInfo is registered, for convenience. - */ - uint8_t cp; - uint8_t crn; - uint8_t crm; - uint8_t opc0; - uint8_t opc1; - uint8_t opc2; - /* Execution state in which this register is visible: ARM_CP_STATE_* */ - int state; - /* Register type: ARM_CP_* bits/values */ - int type; - /* Access rights: PL*_[RW] */ - int access; - /* Security state: ARM_CP_SECSTATE_* bits/values */ - int secure; - /* The opaque pointer passed to define_arm_cp_regs_with_opaque() when - * this register was defined: can be used to hand data through to the - * register read/write functions, since they are passed the ARMCPRegInfo*. - */ - void *opaque; - /* Value of this register, if it is ARM_CP_CONST. Otherwise, if - * fieldoffset is non-zero, the reset value of the register. - */ - uint64_t resetvalue; - /* Offset of the field in CPUARMState for this register. - * - * This is not needed if either: - * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs - * 2. both readfn and writefn are specified - */ - ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ - - /* Offsets of the secure and non-secure fields in CPUARMState for the - * register if it is banked. These fields are only used during the static - * registration of a register. During hashing the bank associated - * with a given security state is copied to fieldoffset which is used from - * there on out. - * - * It is expected that register definitions use either fieldoffset or - * bank_fieldoffsets in the definition but not both. It is also expected - * that both bank offsets are set when defining a banked register. This - * use indicates that a register is banked. - */ - ptrdiff_t bank_fieldoffsets[2]; - - /* Function for making any access checks for this register in addition to - * those specified by the 'access' permissions bits. If NULL, no extra - * checks required. The access check is performed at runtime, not at - * translate time. - */ - CPAccessFn *accessfn; - /* Function for handling reads of this register. If NULL, then reads - * will be done by loading from the offset into CPUARMState specified - * by fieldoffset. - */ - CPReadFn *readfn; - /* Function for handling writes of this register. If NULL, then writes - * will be done by writing to the offset into CPUARMState specified - * by fieldoffset. - */ - CPWriteFn *writefn; - /* Function for doing a "raw" read; used when we need to copy - * coprocessor state to the kernel for KVM or out for - * migration. This only needs to be provided if there is also a - * readfn and it has side effects (for instance clear-on-read bits). - */ - CPReadFn *raw_readfn; - /* Function for doing a "raw" write; used when we need to copy KVM - * kernel coprocessor state into userspace, or for inbound - * migration. This only needs to be provided if there is also a - * writefn and it masks out "unwritable" bits or has write-one-to-clear - * or similar behaviour. - */ - CPWriteFn *raw_writefn; - /* Function for resetting the register. If NULL, then reset will be done - * by writing resetvalue to the field specified in fieldoffset. If - * fieldoffset is 0 then no reset will be done. - */ - CPResetFn *resetfn; - - /* - * "Original" writefn and readfn. - * For ARMv8.1-VHE register aliases, we overwrite the read/write - * accessor functions of various EL1/EL0 to perform the runtime - * check for which sysreg should actually be modified, and then - * forwards the operation. Before overwriting the accessors, - * the original function is copied here, so that accesses that - * really do go to the EL1/EL0 version proceed normally. - * (The corresponding EL2 register is linked via opaque.) - */ - CPReadFn *orig_readfn; - CPWriteFn *orig_writefn; -}; - -/* Macros which are lvalues for the field in CPUARMState for the - * ARMCPRegInfo *ri. - */ -#define CPREG_FIELD32(env, ri) \ - (*(uint32_t *)((char *)(env) + (ri)->fieldoffset)) -#define CPREG_FIELD64(env, ri) \ - (*(uint64_t *)((char *)(env) + (ri)->fieldoffset)) - -#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL } - -void define_arm_cp_regs_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque); -void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque); -static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs) -{ - define_arm_cp_regs_with_opaque(cpu, regs, 0); -} -static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs) -{ - define_one_arm_cp_reg_with_opaque(cpu, regs, 0); -} -const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp); - -/* - * Definition of an ARM co-processor register as viewed from - * userspace. This is used for presenting sanitised versions of - * registers to userspace when emulating the Linux AArch64 CPU - * ID/feature ABI (advertised as HWCAP_CPUID). - */ -typedef struct ARMCPRegUserSpaceInfo { - /* Name of register */ - const char *name; - - /* Is the name actually a glob pattern */ - bool is_glob; - - /* Only some bits are exported to user space */ - uint64_t exported_bits; - - /* Fixed bits are applied after the mask */ - uint64_t fixed_bits; -} ARMCPRegUserSpaceInfo; - -#define REGUSERINFO_SENTINEL { .name = NULL } - -void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods); - -/* CPWriteFn that can be used to implement writes-ignored behaviour */ -void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value); -/* CPReadFn that can be used for read-as-zero behaviour */ -uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri); - -/* CPResetFn that does nothing, for use if no reset is required even - * if fieldoffset is non zero. - */ -void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque); - -/* Return true if this reginfo struct's field in the cpu state struct - * is 64 bits wide. - */ -static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri) -{ - return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT); -} - -static inline bool cp_access_ok(int current_el, - const ARMCPRegInfo *ri, int isread) -{ - return (ri->access >> ((current_el * 2) + isread)) & 1; -} - -/* Raw read of a coprocessor register (as needed for migration, etc) */ -uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); - /** * write_list_to_cpustate * @cpu: ARMCPU @@ -3058,26 +2901,29 @@ 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) + * Physical (NS & S) + * Stage2 (NS & S) * - * for a total of 11 different mmu_idx. + * for a total of 12 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: @@ -3116,9 +2962,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 @@ -3132,22 +2975,27 @@ 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, + + /* TLBs with 1-1 mapping to the physical address spaces. */ + ARMMMUIdx_Phys_NS = 8 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_S = 9 | ARM_MMU_IDX_A, + + /* + * Used for second stage of an S12 page table walk, or for descriptor + * loads during first stage of an S1 page table walk. Note that both + * are in use simultaneously for SecureEL2: the security state for + * the S2 ptw is selected by the NS bit from the S1 ptw. + */ + ARMMMUIdx_Stage2 = 10 | ARM_MMU_IDX_A, + ARMMMUIdx_Stage2_S = 11 | ARM_MMU_IDX_A, /* * These are not allocated TLBs and are used only for AT system @@ -3156,18 +3004,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 - * page table walk. Note that if we ever want to have a TLB for this - * 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, /* * M-profile. @@ -3197,14 +3033,9 @@ 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(Stage2), + TO_CORE_BIT(Stage2_S), TO_CORE_BIT(MUser), TO_CORE_BIT(MPriv), @@ -3228,27 +3059,6 @@ typedef enum ARMASIdx { ARMASIdx_TagS = 3, } ARMASIdx; -/* Return the Exception Level targeted by debug exceptions. */ -static inline int arm_debug_target_el(CPUARMState *env) -{ - bool secure = arm_is_secure(env); - bool route_to_el2 = false; - - if (arm_is_el2_enabled(env)) { - route_to_el2 = env->cp15.hcr_el2 & HCR_TGE || - env->cp15.mdcr_el2 & MDCR_TDE; - } - - if (route_to_el2) { - return 2; - } else if (arm_feature(env, ARM_FEATURE_EL3) && - !arm_el_is_aa64(env, 3) && secure) { - return 3; - } else { - return 1; - } -} - static inline bool arm_v7m_csselr_razwi(ARMCPU *cpu) { /* If all the CLIDR.Ctypem bits are 0 there are no caches, and @@ -3257,107 +3067,6 @@ static inline bool arm_v7m_csselr_razwi(ARMCPU *cpu) return (cpu->clidr & R_V7M_CLIDR_CTYPE_ALL_MASK) != 0; } -/* See AArch64.GenerateDebugExceptionsFrom() in ARM ARM pseudocode */ -static inline bool aa64_generate_debug_exceptions(CPUARMState *env) -{ - int cur_el = arm_current_el(env); - int debug_el; - - if (cur_el == 3) { - return false; - } - - /* MDCR_EL3.SDD disables debug events from Secure state */ - if (arm_is_secure_below_el3(env) - && extract32(env->cp15.mdcr_el3, 16, 1)) { - return false; - } - - /* - * Same EL to same EL debug exceptions need MDSCR_KDE enabled - * while not masking the (D)ebug bit in DAIF. - */ - debug_el = arm_debug_target_el(env); - - if (cur_el == debug_el) { - return extract32(env->cp15.mdscr_el1, 13, 1) - && !(env->daif & PSTATE_D); - } - - /* Otherwise the debug target needs to be a higher EL */ - return debug_el > cur_el; -} - -static inline bool aa32_generate_debug_exceptions(CPUARMState *env) -{ - int el = arm_current_el(env); - - if (el == 0 && arm_el_is_aa64(env, 1)) { - return aa64_generate_debug_exceptions(env); - } - - if (arm_is_secure(env)) { - int spd; - - if (el == 0 && (env->cp15.sder & 1)) { - /* SDER.SUIDEN means debug exceptions from Secure EL0 - * are always enabled. Otherwise they are controlled by - * SDCR.SPD like those from other Secure ELs. - */ - return true; - } - - spd = extract32(env->cp15.mdcr_el3, 14, 2); - switch (spd) { - case 1: - /* SPD == 0b01 is reserved, but behaves as 0b00. */ - case 0: - /* For 0b00 we return true if external secure invasive debug - * is enabled. On real hardware this is controlled by external - * signals to the core. QEMU always permits debug, and behaves - * as if DBGEN, SPIDEN, NIDEN and SPNIDEN are all tied high. - */ - return true; - case 2: - return false; - case 3: - return true; - } - } - - return el != 2; -} - -/* Return true if debugging exceptions are currently enabled. - * This corresponds to what in ARM ARM pseudocode would be - * if UsingAArch32() then - * return AArch32.GenerateDebugExceptions() - * else - * return AArch64.GenerateDebugExceptions() - * We choose to push the if() down into this function for clarity, - * since the pseudocode has it at all callsites except for the one in - * CheckSoftwareStep(), where it is elided because both branches would - * always return the same value. - */ -static inline bool arm_generate_debug_exceptions(CPUARMState *env) -{ - if (env->aarch64) { - return aa64_generate_debug_exceptions(env); - } else { - return aa32_generate_debug_exceptions(env); - } -} - -/* Is single-stepping active? (Note that the "is EL_D AArch64?" check - * implicitly means this always returns false in pre-v8 CPUs.) - */ -static inline bool arm_singlestep_active(CPUARMState *env) -{ - return extract32(env->cp15.mdscr_el1, 0, 1) - && arm_el_is_aa64(env, arm_debug_target_el(env)) - && arm_generate_debug_exceptions(env); -} - static inline bool arm_sctlr_b(CPUARMState *env) { return @@ -3447,11 +3156,9 @@ FIELD(TBFLAG_ANY, BE_DATA, 3, 1) FIELD(TBFLAG_ANY, MMUIDX, 4, 4) /* Target EL if we take a floating-point-disabled exception */ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2) -/* For A-profile only, target EL for debug exceptions. */ -FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 10, 2) /* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */ -FIELD(TBFLAG_ANY, ALIGN_MEM, 12, 1) -FIELD(TBFLAG_ANY, PSTATE__IL, 13, 1) +FIELD(TBFLAG_ANY, ALIGN_MEM, 10, 1) +FIELD(TBFLAG_ANY, PSTATE__IL, 11, 1) /* * Bit usage when in AArch32 state, both A- and M-profile. @@ -3480,6 +3187,11 @@ FIELD(TBFLAG_A32, HSTR_ACTIVE, 9, 1) * the same thing as the current security state of the processor! */ FIELD(TBFLAG_A32, NS, 10, 1) +/* + * Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. + * This requires an SME trap from AArch32 mode when using NEON. + */ +FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1) /* * Bit usage when in AArch32 state, for M-profile only. @@ -3496,13 +3208,16 @@ 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 */ FIELD(TBFLAG_A64, TBII, 0, 2) FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2) -FIELD(TBFLAG_A64, ZCR_LEN, 4, 4) +/* The current vector length, either NVL or SVL. */ +FIELD(TBFLAG_A64, VL, 4, 4) FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1) FIELD(TBFLAG_A64, BT, 9, 1) FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */ @@ -3512,6 +3227,12 @@ FIELD(TBFLAG_A64, ATA, 15, 1) FIELD(TBFLAG_A64, TCMA, 16, 2) FIELD(TBFLAG_A64, MTE_ACTIVE, 18, 1) FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1) +FIELD(TBFLAG_A64, SMEEXC_EL, 20, 2) +FIELD(TBFLAG_A64, PSTATE_SM, 22, 1) +FIELD(TBFLAG_A64, PSTATE_ZA, 23, 1) +FIELD(TBFLAG_A64, SVL, 24, 4) +/* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */ +FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1) /* * Helpers for using the above. @@ -3546,15 +3267,37 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) return EX_TBFLAG_ANY(env->hflags, MMUIDX); } +/** + * sve_vq + * @env: the cpu context + * + * Return the VL cached within env->hflags, in units of quadwords. + */ +static inline int sve_vq(CPUARMState *env) +{ + return EX_TBFLAG_A64(env->hflags, VL) + 1; +} + +/** + * sme_vq + * @env: the cpu context + * + * Return the SVL cached within env->hflags, in units of quadwords. + */ +static inline int sme_vq(CPUARMState *env) +{ + return EX_TBFLAG_A64(env->hflags, SVL) + 1; +} + static inline bool bswap_code(bool sctlr_b) { #ifdef CONFIG_USER_ONLY - /* BE8 (SCTLR.B = 0, TARGET_WORDS_BIGENDIAN = 1) is mixed endian. - * The invalid combination SCTLR.B=1/CPSR.E=1/TARGET_WORDS_BIGENDIAN=0 + /* BE8 (SCTLR.B = 0, TARGET_BIG_ENDIAN = 1) is mixed endian. + * The invalid combination SCTLR.B=1/CPSR.E=1/TARGET_BIG_ENDIAN=0 * would also end up as a mixed-endian mode with BE code, LE data. */ return -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN 1 ^ #endif sctlr_b; @@ -3570,7 +3313,7 @@ static inline bool bswap_code(bool sctlr_b) static inline bool arm_cpu_bswap_data(CPUARMState *env) { return -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN 1 ^ #endif arm_cpu_data_is_big_endian(env); @@ -3662,27 +3405,24 @@ 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]; - -/* Helper for the macros below, validating the argument type. */ -static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x) -{ - return x; -} - -/* - * Lvalue macros for ARM TLB bits that we must cache in the TCG TLB. - * Using these should be a bit more self-documenting than using the - * generic target bits directly. - */ -#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0) -#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1) +extern const uint64_t pred_esz_masks[5]; /* * AArch64 usage of the PAGE_TARGET_* bits for linux-user. + * Note that with the Linux kernel, PROT_MTE may not be cleared by mprotect + * mprotect but PROT_BTI may be cleared. C.f. the kernel's VM_ARCH_CLEAR. */ -#define PAGE_BTI PAGE_TARGET_1 -#define PAGE_MTE PAGE_TARGET_2 +#define PAGE_BTI PAGE_TARGET_1 +#define PAGE_MTE PAGE_TARGET_2 +#define PAGE_TARGET_STICKY PAGE_MTE + +/* We associate one allocation tag per 16 bytes, the minimum. */ +#define LOG2_TAG_GRANULE 4 +#define TAG_GRANULE (1 << LOG2_TAG_GRANULE) + +#ifdef CONFIG_USER_ONLY +#define TARGET_PAGE_DATA_SIZE (TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1)) +#endif #ifdef TARGET_TAGGED_ADDRESSES /** @@ -3982,20 +3722,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; @@ -4016,6 +3763,16 @@ static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id) return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0; } +static inline bool isar_feature_aa32_half_evt(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 1; +} + +static inline bool isar_feature_aa32_evt(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 2; +} + static inline bool isar_feature_aa32_dit(const ARMISARegisters *id) { return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0; @@ -4026,6 +3783,21 @@ static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0; } +static inline bool isar_feature_aa32_debugv7p1(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 5; +} + +static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8; +} + +static inline bool isar_feature_aa32_doublelock(const ARMISARegisters *id) +{ + return FIELD_EX32(id->dbgdevid, DBGDEVID, DOUBLELOCK) > 0; +} + /* * 64-bit feature tests via id registers. */ @@ -4203,6 +3975,21 @@ static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2; } +static inline bool isar_feature_aa64_aa32_el2(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL2) >= 2; +} + +static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0; +} + +static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2; +} + static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; @@ -4233,6 +4020,11 @@ static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; } +static inline bool isar_feature_aa64_hcx(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HCX) != 0; +} + static inline bool isar_feature_aa64_uao(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0; @@ -4243,6 +4035,26 @@ static inline bool isar_feature_aa64_st(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0; } +static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0; +} + +static inline bool isar_feature_aa64_ids(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, IDS) != 0; +} + +static inline bool isar_feature_aa64_half_evt(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 1; +} + +static inline bool isar_feature_aa64_evt(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 2; +} + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; @@ -4258,18 +4070,29 @@ static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; } -static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) +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_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; @@ -4307,6 +4130,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; @@ -4317,6 +4173,21 @@ static inline bool isar_feature_aa64_lva(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, VARANGE) != 0; } +static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0; +} + +static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0; +} + +static inline bool isar_feature_aa64_hdbs(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) >= 2; +} + static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0; @@ -4327,11 +4198,29 @@ static inline bool isar_feature_aa64_dit(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0; } +static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id) +{ + int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2); + if (key >= 2) { + return true; /* FEAT_CSV2_2 */ + } + if (key == 1) { + key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC); + return key >= 2; /* FEAT_CSV2_1p2 */ + } + return false; +} + static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; } +static inline bool isar_feature_aa64_debugv8p2(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, DEBUGVER) >= 8; +} + static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0; @@ -4382,6 +4271,26 @@ static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0; } +static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, F64F64); +} + +static inline bool isar_feature_aa64_sme_i16i64(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, I16I64) == 0xf; +} + +static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64); +} + +static inline bool isar_feature_aa64_doublelock(const ARMISARegisters *id) +{ + return FIELD_SEX64(id->id_aa64dfr0, ID_AA64DFR0, DOUBLELOCK) >= 0; +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ @@ -4395,14 +4304,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) @@ -4415,6 +4329,26 @@ static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id) return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id); } +static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id) +{ + return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id); +} + +static inline bool isar_feature_any_ras(const ARMISARegisters *id) +{ + return isar_feature_aa64_ras(id) || isar_feature_aa32_ras(id); +} + +static inline bool isar_feature_any_half_evt(const ARMISARegisters *id) +{ + return isar_feature_aa64_half_evt(id) || isar_feature_aa32_half_evt(id); +} + +static inline bool isar_feature_any_evt(const ARMISARegisters *id) +{ + return isar_feature_aa64_evt(id) || isar_feature_aa32_evt(id); +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index eb44c05822cf..0e021960fb5b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -21,83 +21,20 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" -#ifdef CONFIG_TCG -#include "hw/core/tcg-cpu-ops.h" -#endif /* CONFIG_TCG */ #include "qemu/module.h" -#if !defined(CONFIG_USER_ONLY) -#include "hw/loader.h" -#endif #include "sysemu/kvm.h" #include "sysemu/hvf.h" #include "kvm_arm.h" #include "hvf_arm.h" #include "qapi/visitor.h" #include "hw/qdev-properties.h" +#include "internals.h" - -#ifndef CONFIG_USER_ONLY -static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - ARMCPU *cpu = env_archcpu(env); - - /* Number of cores is in [25:24]; otherwise we RAZ */ - return (cpu->core_count - 1) << 24; -} -#endif - -static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { -#ifndef CONFIG_USER_ONLY - { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, - .writefn = arm_cp_write_ignore }, - { .name = "L2CTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, - .writefn = arm_cp_write_ignore }, -#endif - { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ECTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR", - .cp = 15, .opc1 = 0, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUECTLR", - .cp = 15, .opc1 = 1, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUMERRSR", - .cp = 15, .opc1 = 2, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2MERRSR", - .cp = 15, .opc1 = 3, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - REGINFO_SENTINEL -}; - -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); @@ -106,20 +43,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; @@ -129,125 +62,52 @@ 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.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; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); -} - -static void aarch64_a53_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); + cpu->dcz_blocksize = 4; - 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->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; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); -} + cpu->gic_pribits = 5; -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->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; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + + /* These values are the same with A53/A57/A72. */ + define_cortex_a72_a57_a53_cp_reginfo(cpu); } void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) @@ -267,8 +127,11 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * any of the above. Finally, if SVE is not disabled, then at least one * vector length must be enabled. */ - DECLARE_BITMAP(tmp, ARM_MAX_VQ); - uint32_t vq, max_vq = 0; + uint32_t vq_map = cpu->sve_vq.map; + uint32_t vq_init = cpu->sve_vq.init; + uint32_t vq_supported; + uint32_t vq_mask = 0; + uint32_t tmp, vq, max_vq = 0; /* * CPU models specify a set of supported vector lengths which are @@ -276,10 +139,16 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * in the supported bitmap results in an error. When KVM is enabled we * fetch the supported bitmap from the host. */ - if (kvm_enabled() && kvm_arm_sve_supported()) { - kvm_arm_sve_get_vls(CPU(cpu), cpu->sve_vq_supported); - } else if (kvm_enabled()) { - assert(!cpu_isar_feature(aa64_sve, cpu)); + if (kvm_enabled()) { + if (kvm_arm_sve_supported()) { + cpu->sve_vq.supported = kvm_arm_sve_get_vls(CPU(cpu)); + vq_supported = cpu->sve_vq.supported; + } else { + assert(!cpu_isar_feature(aa64_sve, cpu)); + vq_supported = 0; + } + } else { + vq_supported = cpu->sve_vq.supported; } /* @@ -287,8 +156,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * From the properties, sve_vq_map implies sve_vq_init. * Check first for any sve enabled. */ - if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) { - max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1; + if (vq_map != 0) { + max_vq = 32 - clz32(vq_map); + vq_mask = MAKE_64BIT_MASK(0, max_vq); if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) { error_setg(errp, "cannot enable sve%d", max_vq * 128); @@ -304,15 +174,10 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * For KVM we have to automatically enable all supported unitialized * lengths, even when the smaller lengths are not all powers-of-two. */ - bitmap_andnot(tmp, cpu->sve_vq_supported, cpu->sve_vq_init, max_vq); - bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq); + vq_map |= vq_supported & ~vq_init & vq_mask; } else { /* Propagate enabled bits down through required powers-of-two. */ - for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { - if (!test_bit(vq - 1, cpu->sve_vq_init)) { - set_bit(vq - 1, cpu->sve_vq_map); - } - } + vq_map |= SVE_VQ_POW2_MAP & ~vq_init & vq_mask; } } else if (cpu->sve_max_vq == 0) { /* @@ -325,25 +190,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) if (kvm_enabled()) { /* Disabling a supported length disables all larger lengths. */ - for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { - if (test_bit(vq - 1, cpu->sve_vq_init) && - test_bit(vq - 1, cpu->sve_vq_supported)) { - break; - } - } + tmp = vq_init & vq_supported; } else { /* Disabling a power-of-two disables all larger lengths. */ - for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) { - if (test_bit(vq - 1, cpu->sve_vq_init)) { - break; - } - } + tmp = vq_init & SVE_VQ_POW2_MAP; } + vq = ctz32(tmp) + 1; max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ; - bitmap_andnot(cpu->sve_vq_map, cpu->sve_vq_supported, - cpu->sve_vq_init, max_vq); - if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) { + vq_mask = MAKE_64BIT_MASK(0, max_vq); + vq_map = vq_supported & ~vq_init & vq_mask; + + if (max_vq == 0 || vq_map == 0) { error_setg(errp, "cannot disable sve%d", vq * 128); error_append_hint(errp, "Disabling sve%d results in all " "vector lengths being disabled.\n", @@ -353,7 +211,8 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) return; } - max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1; + max_vq = 32 - clz32(vq_map); + vq_mask = MAKE_64BIT_MASK(0, max_vq); } /* @@ -363,9 +222,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) */ if (cpu->sve_max_vq != 0) { max_vq = cpu->sve_max_vq; + vq_mask = MAKE_64BIT_MASK(0, max_vq); - if (!test_bit(max_vq - 1, cpu->sve_vq_map) && - test_bit(max_vq - 1, cpu->sve_vq_init)) { + if (vq_init & ~vq_map & (1 << (max_vq - 1))) { error_setg(errp, "cannot disable sve%d", max_vq * 128); error_append_hint(errp, "The maximum vector length must be " "enabled, sve-max-vq=%d (%d bits)\n", @@ -374,8 +233,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) } /* Set all bits not explicitly set within sve-max-vq. */ - bitmap_complement(tmp, cpu->sve_vq_init, max_vq); - bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq); + vq_map |= ~vq_init & vq_mask; } /* @@ -384,13 +242,14 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * are clear, just in case anybody looks. */ assert(max_vq != 0); - bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq); + assert(vq_mask != 0); + vq_map &= vq_mask; /* Ensure the set of lengths matches what is supported. */ - bitmap_xor(tmp, cpu->sve_vq_map, cpu->sve_vq_supported, max_vq); - if (!bitmap_empty(tmp, max_vq)) { - vq = find_last_bit(tmp, max_vq) + 1; - if (test_bit(vq - 1, cpu->sve_vq_map)) { + tmp = vq_map ^ (vq_supported & vq_mask); + if (tmp) { + vq = 32 - clz32(tmp); + if (vq_map & (1 << (vq - 1))) { if (cpu->sve_max_vq) { error_setg(errp, "cannot set sve-max-vq=%d", cpu->sve_max_vq); error_append_hint(errp, "This CPU does not support " @@ -400,8 +259,13 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) "using only sve properties.\n"); } else { error_setg(errp, "cannot enable sve%d", vq * 128); - error_append_hint(errp, "This CPU does not support " - "the vector length %d-bits.\n", vq * 128); + if (vq_supported) { + error_append_hint(errp, "This CPU does not support " + "the vector length %d-bits.\n", vq * 128); + } else { + error_append_hint(errp, "SVE not supported by KVM " + "on this host\n"); + } } return; } else { @@ -414,15 +278,15 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) return; } else { /* Ensure all required powers-of-two are enabled. */ - for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { - if (!test_bit(vq - 1, cpu->sve_vq_map)) { - error_setg(errp, "cannot disable sve%d", vq * 128); - error_append_hint(errp, "sve%d is required as it " - "is a power-of-two length smaller " - "than the maximum, sve%d\n", - vq * 128, max_vq * 128); - return; - } + tmp = SVE_VQ_POW2_MAP & vq_mask & ~vq_map; + if (tmp) { + vq = 32 - clz32(tmp); + error_setg(errp, "cannot disable sve%d", vq * 128); + error_append_hint(errp, "sve%d is required as it " + "is a power-of-two length smaller " + "than the maximum, sve%d\n", + vq * 128, max_vq * 128); + return; } } } @@ -442,6 +306,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) /* From now on sve_max_vq is the actual maximum supported length. */ cpu->sve_max_vq = max_vq; + cpu->sve_vq.map = vq_map; } static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name, @@ -486,31 +351,34 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, } /* - * Note that cpu_arm_get/set_sve_vq cannot use the simpler - * object_property_add_bool interface because they make use - * of the contents of "name" to determine which bit on which - * to operate. + * Note that cpu_arm_{get,set}_vq cannot use the simpler + * object_property_add_bool interface because they make use of the + * contents of "name" to determine which bit on which to operate. */ -static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) +static void cpu_arm_get_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) { ARMCPU *cpu = ARM_CPU(obj); + ARMVQMap *vq_map = opaque; uint32_t vq = atoi(&name[3]) / 128; + bool sve = vq_map == &cpu->sve_vq; bool value; - /* All vector lengths are disabled when SVE is off. */ - if (!cpu_isar_feature(aa64_sve, cpu)) { + /* All vector lengths are disabled when feature is off. */ + if (sve + ? !cpu_isar_feature(aa64_sve, cpu) + : !cpu_isar_feature(aa64_sme, cpu)) { value = false; } else { - value = test_bit(vq - 1, cpu->sve_vq_map); + value = extract32(vq_map->map, vq - 1, 1); } visit_type_bool(v, name, &value, errp); } -static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) +static void cpu_arm_set_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) { - ARMCPU *cpu = ARM_CPU(obj); + ARMVQMap *vq_map = opaque; uint32_t vq = atoi(&name[3]) / 128; bool value; @@ -518,18 +386,8 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, return; } - if (value && kvm_enabled() && !kvm_arm_sve_supported()) { - error_setg(errp, "cannot enable %s", name); - error_append_hint(errp, "SVE not supported by KVM on this host\n"); - return; - } - - if (value) { - set_bit(vq - 1, cpu->sve_vq_map); - } else { - clear_bit(vq - 1, cpu->sve_vq_map); - } - set_bit(vq - 1, cpu->sve_vq_init); + vq_map->map = deposit32(vq_map->map, vq - 1, 1, value); + vq_map->init |= 1 << (vq - 1); } static bool cpu_arm_get_sve(Object *obj, Error **errp) @@ -553,13 +411,85 @@ static void cpu_arm_set_sve(Object *obj, bool value, Error **errp) cpu->isar.id_aa64pfr0 = t; } -#ifdef CONFIG_USER_ONLY -/* Mirror linux /proc/sys/abi/sve_default_vector_length. */ -static void cpu_arm_set_sve_default_vec_len(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) +void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp) +{ + uint32_t vq_map = cpu->sme_vq.map; + uint32_t vq_init = cpu->sme_vq.init; + uint32_t vq_supported = cpu->sme_vq.supported; + uint32_t vq; + + if (vq_map == 0) { + if (!cpu_isar_feature(aa64_sme, cpu)) { + cpu->isar.id_aa64smfr0 = 0; + return; + } + + /* TODO: KVM will require limitations via SMCR_EL2. */ + vq_map = vq_supported & ~vq_init; + + if (vq_map == 0) { + vq = ctz32(vq_supported) + 1; + error_setg(errp, "cannot disable sme%d", vq * 128); + error_append_hint(errp, "All SME vector lengths are disabled.\n"); + error_append_hint(errp, "With SME enabled, at least one " + "vector length must be enabled.\n"); + return; + } + } else { + if (!cpu_isar_feature(aa64_sme, cpu)) { + vq = 32 - clz32(vq_map); + error_setg(errp, "cannot enable sme%d", vq * 128); + error_append_hint(errp, "SME must be enabled to enable " + "vector lengths.\n"); + error_append_hint(errp, "Add sme=on to the CPU property list.\n"); + return; + } + /* TODO: KVM will require limitations via SMCR_EL2. */ + } + + cpu->sme_vq.map = vq_map; +} + +static bool cpu_arm_get_sme(Object *obj, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + return cpu_isar_feature(aa64_sme, cpu); +} + +static void cpu_arm_set_sme(Object *obj, bool value, Error **errp) { ARMCPU *cpu = ARM_CPU(obj); + uint64_t t; + + t = cpu->isar.id_aa64pfr1; + t = FIELD_DP64(t, ID_AA64PFR1, SME, value); + cpu->isar.id_aa64pfr1 = t; +} + +static bool cpu_arm_get_sme_fa64(Object *obj, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + return cpu_isar_feature(aa64_sme, cpu) && + cpu_isar_feature(aa64_sme_fa64, cpu); +} + +static void cpu_arm_set_sme_fa64(Object *obj, bool value, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint64_t t; + + t = cpu->isar.id_aa64smfr0; + t = FIELD_DP64(t, ID_AA64SMFR0, FA64, value); + cpu->isar.id_aa64smfr0 = t; +} + +#ifdef CONFIG_USER_ONLY +/* Mirror linux /proc/sys/abi/{sve,sme}_default_vector_length. */ +static void cpu_arm_set_default_vec_len(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + uint32_t *ptr_default_vq = opaque; int32_t default_len, default_vq, remainder; if (!visit_type_int32(v, name, &default_len, errp)) { @@ -568,7 +498,7 @@ static void cpu_arm_set_sve_default_vec_len(Object *obj, Visitor *v, /* Undocumented, but the kernel allows -1 to indicate "maximum". */ if (default_len == -1) { - cpu->sve_default_vq = ARM_MAX_VQ; + *ptr_default_vq = ARM_MAX_VQ; return; } @@ -580,7 +510,11 @@ static void cpu_arm_set_sve_default_vec_len(Object *obj, Visitor *v, * and is the maximum architectural width of ZCR_ELx.LEN. */ if (remainder || default_vq < 1 || default_vq > 512) { - error_setg(errp, "cannot set sve-default-vector-length"); + ARMCPU *cpu = ARM_CPU(obj); + const char *which = + (ptr_default_vq == &cpu->sve_default_vq ? "sve" : "sme"); + + error_setg(errp, "cannot set %s-default-vector-length", which); if (remainder) { error_append_hint(errp, "Vector length not a multiple of 16\n"); } else if (default_vq < 1) { @@ -592,22 +526,23 @@ static void cpu_arm_set_sve_default_vec_len(Object *obj, Visitor *v, return; } - cpu->sve_default_vq = default_vq; + *ptr_default_vq = default_vq; } -static void cpu_arm_get_sve_default_vec_len(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) +static void cpu_arm_get_default_vec_len(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { - ARMCPU *cpu = ARM_CPU(obj); - int32_t value = cpu->sve_default_vq * 16; + uint32_t *ptr_default_vq = opaque; + int32_t value = *ptr_default_vq * 16; visit_type_int32(v, name, &value, errp); } #endif -void aarch64_add_sve_properties(Object *obj) +static void aarch64_add_sve_properties(Object *obj) { + ARMCPU *cpu = ARM_CPU(obj); uint32_t vq; object_property_add_bool(obj, "sve", cpu_arm_get_sve, cpu_arm_set_sve); @@ -615,15 +550,41 @@ void aarch64_add_sve_properties(Object *obj) for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { char name[8]; sprintf(name, "sve%d", vq * 128); - object_property_add(obj, name, "bool", cpu_arm_get_sve_vq, - cpu_arm_set_sve_vq, NULL, NULL); + object_property_add(obj, name, "bool", cpu_arm_get_vq, + cpu_arm_set_vq, NULL, &cpu->sve_vq); } #ifdef CONFIG_USER_ONLY /* Mirror linux /proc/sys/abi/sve_default_vector_length. */ object_property_add(obj, "sve-default-vector-length", "int32", - cpu_arm_get_sve_default_vec_len, - cpu_arm_set_sve_default_vec_len, NULL, NULL); + cpu_arm_get_default_vec_len, + cpu_arm_set_default_vec_len, NULL, + &cpu->sve_default_vq); +#endif +} + +static void aarch64_add_sme_properties(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint32_t vq; + + object_property_add_bool(obj, "sme", cpu_arm_get_sme, cpu_arm_set_sme); + object_property_add_bool(obj, "sme_fa64", cpu_arm_get_sme_fa64, + cpu_arm_set_sme_fa64); + + for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) { + char name[8]; + sprintf(name, "sme%d", vq * 128); + object_property_add(obj, name, "bool", cpu_arm_get_vq, + cpu_arm_set_vq, NULL, &cpu->sme_vq); + } + +#ifdef CONFIG_USER_ONLY + /* Mirror linux /proc/sys/abi/sme_default_vector_length. */ + object_property_add(obj, "sme-default-vector-length", "int32", + cpu_arm_get_default_vec_len, + cpu_arm_set_default_vec_len, NULL, + &cpu->sme_default_vq); #endif } @@ -667,7 +628,7 @@ static Property arm_cpu_pauth_property = static Property arm_cpu_pauth_impdef_property = DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false); -void aarch64_add_pauth_properties(Object *obj) +static void aarch64_add_pauth_properties(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -711,55 +672,479 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) cpu->isar.id_aa64mmfr0 = t; } -static void aarch64_host_initfn(Object *obj) -{ -#if defined(CONFIG_KVM) - ARMCPU *cpu = ARM_CPU(obj); - kvm_arm_set_cpu_features_from_host(cpu); - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - aarch64_add_sve_properties(obj); - aarch64_add_pauth_properties(obj); - } -#elif defined(CONFIG_HVF) - ARMCPU *cpu = ARM_CPU(obj); - hvf_arm_set_cpu_features_from_host(cpu); - aarch64_add_pauth_properties(obj); -#else - g_assert_not_reached(); -#endif -} - -/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); - * otherwise, a CPU with as many features enabled as our emulation supports. - * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; - * this only needs to handle 64 bits. - */ -static void aarch64_max_initfn(Object *obj) +static void aarch64_a57_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - uint64_t t; - uint32_t u; - - if (kvm_enabled() || hvf_enabled()) { - /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ - aarch64_host_initfn(obj); - return; - } - - /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ - aarch64_a57_initfn(obj); - - /* - * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real - * one and try to apply errata workarounds or use impdef features we - * don't provide. - * An IMPLEMENTER field of 0 means "reserved for software use"; - * ARCHITECTURE must be 0xf indicating "v7 or later, check ID registers - * to see which features are present"; - * the VARIANT, PARTNUM and REVISION fields are all implementation - * defined and we choose to define PARTNUM just in case guest - * code needs to distinguish this QEMU CPU from other software + 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_a55_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a55"; + 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 = 0x84448004; /* L1Ip = VIPT */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + 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 = 0x0000000010112222ull; + 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 = 0x00011142; + 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 = 0x00011011; + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x412FD050; /* r2p0 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */ + cpu->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */ + + /* From B2.96 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.45 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.4 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410b3000; +} + +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) + ARMCPU *cpu = ARM_CPU(obj); + kvm_arm_set_cpu_features_from_host(cpu); + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + aarch64_add_sve_properties(obj); + aarch64_add_pauth_properties(obj); + } +#elif defined(CONFIG_HVF) + ARMCPU *cpu = ARM_CPU(obj); + hvf_arm_set_cpu_features_from_host(cpu); + aarch64_add_pauth_properties(obj); +#else + g_assert_not_reached(); +#endif +} + +/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); + * otherwise, a CPU with as many features enabled as our emulation supports. + * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; + * this only needs to handle 64 bits. + */ +static void aarch64_max_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint64_t t; + uint32_t u; + + if (kvm_enabled() || hvf_enabled()) { + /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ + aarch64_host_initfn(obj); + return; + } + + /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ + + aarch64_a57_initfn(obj); + + /* + * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real + * one and try to apply errata workarounds or use impdef features we + * don't provide. + * An IMPLEMENTER field of 0 means "reserved for software use"; + * ARCHITECTURE must be 0xf indicating "v7 or later, check ID registers + * to see which features are present"; + * the VARIANT, PARTNUM and REVISION fields are all implementation + * defined and we choose to define PARTNUM just in case guest + * code needs to distinguish this QEMU CPU from other software * implementations, though this shouldn't be needed. */ t = FIELD_DP64(0, MIDR_EL1, IMPLEMENTER, 0); @@ -769,52 +1154,68 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); cpu->midr = t; + /* + * We're going to set FEAT_S2FWB, which mandates that CLIDR_EL1.{LoUU,LoUIS} + * are zero. + */ + u = cpu->clidr; + u = FIELD_DP32(u, CLIDR_EL1, LOUIS, 0); + u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0); + cpu->clidr = u; + t = cpu->isar.id_aa64isar0; - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); - t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ - t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* FEAT_SM4 */ + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* FEAT_DotProd */ + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* FEAT_FlagM2 */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ cpu->isar.id_aa64isar0 = t; t = cpu->isar.id_aa64isar1; - t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ - t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* FEAT_FCMA */ + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* FEAT_LRCPC2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */ + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ cpu->isar.id_aa64isar1 = t; t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */ t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); - t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); - t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ cpu->isar.id_aa64pfr0 = t; t = cpu->isar.id_aa64pfr1; - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); - t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* FEAT_BTI */ + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* FEAT_SSBS2 */ /* * Begin with full support for MTE. This will be downgraded to MTE=0 * during realize if the board provides no tag memory, much like * we do for EL2 with the virtualization=on property. */ - t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ + t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ + t = FIELD_DP64(t, ID_AA64PFR1, SME, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ cpu->isar.id_aa64pfr1 = t; t = cpu->isar.id_aa64mmfr0; @@ -826,84 +1227,60 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_aa64mmfr0 = t; t = cpu->isar.id_aa64mmfr1; - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ - t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ - t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ + t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2); /* FEAT_HAFDBS */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* FEAT_HPDS */ + 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; t = cpu->isar.id_aa64mmfr2; - t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); - t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ - t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */ - t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ + t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ + t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ + t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ + t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ + t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2); /* FEAT_EVT */ + t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */ cpu->isar.id_aa64mmfr2 = t; t = cpu->isar.id_aa64zfr0; t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* PMULL */ - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ + t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */ + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* FEAT_F32MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ cpu->isar.id_aa64zfr0 = t; - /* Replicate the same data to the 32-bit id registers. */ - u = cpu->isar.id_isar5; - u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ - u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); - u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); - u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); - u = FIELD_DP32(u, ID_ISAR5, RDM, 1); - u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = u; - - u = cpu->isar.id_isar6; - u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); - u = FIELD_DP32(u, ID_ISAR6, DP, 1); - u = FIELD_DP32(u, ID_ISAR6, FHM, 1); - u = FIELD_DP32(u, ID_ISAR6, SB, 1); - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); - u = FIELD_DP32(u, ID_ISAR6, BF16, 1); - u = FIELD_DP32(u, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = u; - - u = cpu->isar.id_pfr0; - u = FIELD_DP32(u, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = u; - - u = cpu->isar.id_pfr2; - u = FIELD_DP32(u, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = u; - - u = cpu->isar.id_mmfr3; - u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = u; - - u = cpu->isar.id_mmfr4; - u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ - u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ - u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = u; - t = cpu->isar.id_aa64dfr0; - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ cpu->isar.id_aa64dfr0 = t; - u = cpu->isar.id_dfr0; - u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ - cpu->isar.id_dfr0 = u; + t = cpu->isar.id_aa64smfr0; + t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, I8I32, 0xf); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1); /* FEAT_SME_F64F64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* FEAT_SME_I16I64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* FEAT_SME_FA64 */ + cpu->isar.id_aa64smfr0 = t; - u = cpu->isar.mvfr1; - u = FIELD_DP32(u, MVFR1, FPHP, 3); /* v8.2-FP16 */ - u = FIELD_DP32(u, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = u; + /* Replicate the same data to the 32-bit id registers. */ + aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* @@ -914,67 +1291,26 @@ static void aarch64_max_initfn(Object *obj) cpu->dcz_blocksize = 7; /* 512 bytes */ #endif - bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ); + cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ); + cpu->sme_vq.supported = SVE_VQ_POW2_MAP; aarch64_add_pauth_properties(obj); aarch64_add_sve_properties(obj); + aarch64_add_sme_properties(obj); object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, cpu_max_set_sve_max_vq, NULL, NULL); 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; - - /* Suppport of A64FX's vector length are 128,256 and 512bit only */ - aarch64_add_sve_properties(obj); - bitmap_zero(cpu->sve_vq_supported, ARM_MAX_VQ); - set_bit(0, cpu->sve_vq_supported); /* 128bit */ - set_bit(1, cpu->sve_vq_supported); /* 256bit */ - set_bit(3, cpu->sve_vq_supported); /* 512bit */ - - /* 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-a55", .initfn = aarch64_a55_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, + { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, + { .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, #if defined(CONFIG_KVM) || defined(CONFIG_HVF) { .name = "host", .initfn = aarch64_host_initfn }, diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 13d0e9b1954a..54db93e8adbb 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -18,6 +18,136 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/boards.h" #endif +#include "cpregs.h" + + +/* Share AArch32 -cpu max features with AArch64. */ +void aa32_max_features(ARMCPU *cpu) +{ + uint32_t t; + + /* Add additional features supported by QEMU */ + t = cpu->isar.id_isar5; + t = FIELD_DP32(t, ID_ISAR5, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); /* FEAT_SHA256 */ + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); /* FEAT_FCMA */ + cpu->isar.id_isar5 = t; + + t = cpu->isar.id_isar6; + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP32(t, ID_ISAR6, DP, 1); /* Feat_DotProd */ + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP32(t, ID_ISAR6, SB, 1); /* FEAT_SB */ + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP32(t, ID_ISAR6, BF16, 1); /* FEAT_AA32BF16 */ + t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); /* FEAT_AA32I8MM */ + cpu->isar.id_isar6 = t; + + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* FEAT_FP16 */ + cpu->isar.mvfr1 = t; + + t = cpu->isar.mvfr2; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + + t = cpu->isar.id_mmfr3; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ + cpu->isar.id_mmfr3 = t; + + t = cpu->isar.id_mmfr4; + 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, EVT, 2); /* FEAT_EVT */ + 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 */ + t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ + cpu->isar.id_pfr0 = t; + + t = cpu->isar.id_pfr2; + t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */ + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ + cpu->isar.id_pfr2 = t; + + 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, 6); /* FEAT_PMUv3p5 */ + cpu->isar.id_dfr0 = t; +} + +#ifndef CONFIG_USER_ONLY +static uint64_t l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = env_archcpu(env); + + /* Number of cores is in [25:24]; otherwise we RAZ */ + return (cpu->core_count - 1) << 24; +} + +static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { + { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2CTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ECTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR", + .cp = 15, .opc1 = 0, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUECTLR", + .cp = 15, .opc1 = 1, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUMERRSR", + .cp = 15, .opc1 = 2, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2MERRSR", + .cp = 15, .opc1 = 3, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, +}; + +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) +{ + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); +} +#endif /* !CONFIG_USER_ONLY */ /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) @@ -263,7 +393,6 @@ static const ARMCPRegInfo cortexa8_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void cortex_a8_initfn(Object *obj) @@ -301,6 +430,7 @@ static void cortex_a8_initfn(Object *obj) cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ cpu->reset_auxcr = 2; + cpu->isar.reset_pmcr_el0 = 0x41002000; define_arm_cp_regs(cpu, cortexa8_cp_reginfo); } @@ -331,7 +461,6 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = { .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, - REGINFO_SENTINEL }; static void cortex_a9_initfn(Object *obj) @@ -373,6 +502,7 @@ static void cortex_a9_initfn(Object *obj) cpu->clidr = (1 << 27) | (1 << 24) | 3; cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ + cpu->isar.reset_pmcr_el0 = 0x41093000; define_arm_cp_regs(cpu, cortexa9_cp_reginfo); } @@ -397,7 +527,6 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = { #endif { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void cortex_a7_initfn(Object *obj) @@ -439,10 +568,13 @@ static void cortex_a7_initfn(Object *obj) cpu->isar.id_isar3 = 0x11112131; cpu->isar.id_isar4 = 0x10011142; cpu->isar.dbgdidr = 0x3515f005; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x1; cpu->clidr = 0x0a200023; cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + cpu->isar.reset_pmcr_el0 = 0x41072000; define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ } @@ -461,7 +593,9 @@ static void cortex_a15_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_EL3); set_feature(&cpu->env, ARM_FEATURE_PMU); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; - cpu->midr = 0x412fc0f1; + /* r4p0 cpu, not requiring expensive tlb flush errata */ + cpu->midr = 0x414fc0f0; + cpu->revidr = 0x0; cpu->reset_fpsid = 0x410430f0; cpu->isar.mvfr0 = 0x10110222; cpu->isar.mvfr1 = 0x11111111; @@ -481,10 +615,13 @@ static void cortex_a15_initfn(Object *obj) cpu->isar.id_isar3 = 0x11112131; cpu->isar.id_isar4 = 0x10011142; cpu->isar.dbgdidr = 0x3515f021; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x0; cpu->clidr = 0x0a200023; cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + cpu->isar.reset_pmcr_el0 = 0x410F3000; define_arm_cp_regs(cpu, cortexa15_cp_reginfo); } @@ -616,7 +753,7 @@ static void cortex_m33_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); cpu->midr = 0x410fd213; /* r0p3 */ - cpu->pmsav7_dregion = 16; + cpu->pmsav7_dregion = 8; /* default is 8 not 16*/ cpu->sau_sregion = 8; cpu->isar.mvfr0 = 0x10110021; cpu->isar.mvfr1 = 0x11000011; @@ -685,7 +822,6 @@ static const ARMCPRegInfo cortexr5_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST }, { .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static void cortex_r5_initfn(Object *obj) @@ -714,9 +850,51 @@ static void cortex_r5_initfn(Object *obj) cpu->isar.id_isar6 = 0x0; cpu->mp_is_up = true; cpu->pmsav7_dregion = 16; + cpu->isar.reset_pmcr_el0 = 0x41151800; define_arm_cp_regs(cpu, cortexr5_cp_reginfo); } +static void cortex_r52_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_PMSA); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + cpu->midr = 0x411fd133; /* r1p3 */ + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034023; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8144c004; + cpu->reset_sctlr = 0x30c50838; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x10111001; + cpu->isar.id_dfr0 = 0x03010006; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00211040; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01200000; + cpu->isar.id_mmfr3 = 0xf0102211; + cpu->isar.id_mmfr4 = 0x00000010; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232142; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x00010001; + cpu->isar.dbgdidr = 0x77168000; + cpu->clidr = (1 << 27) | (1 << 24) | 0x3; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ + + cpu->pmsav7_dregion = 16; + cpu->pmsav8r_hdregion = 16; +} + static void cortex_r5f_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -899,6 +1077,7 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = { .initialize = arm_translate_init, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, + .restore_state_to_opc = arm_restore_state_to_opc, #ifdef CONFIG_USER_ONLY .record_sigsegv = arm_cpu_record_sigsegv, @@ -939,70 +1118,58 @@ static void arm_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - cortex_a15_initfn(obj); + /* aarch64_a57_initfn, advertising none of the aarch64 features */ + 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_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 = 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.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x00110f13; + 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 */ + define_cortex_a72_a57_a53_cp_reginfo(cpu); - /* old-style VFP short-vector support */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* - * We don't set these in system emulation mode for the moment, - * since we don't correctly set (all of) the ID registers to - * advertise them. + * Break with true ARMv8 and add back old-style VFP short-vector support. + * Only do this for user-mode, where -cpu max is the default, so that + * older v6 and v7 programs are more likely to work without adjustment. */ - set_feature(&cpu->env, ARM_FEATURE_V8); - { - uint32_t t; - - t = cpu->isar.id_isar5; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = t; - - t = cpu->isar.id_isar6; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); - t = FIELD_DP32(t, ID_ISAR6, BF16, 1); - t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = t; - - t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = t; - - t = cpu->isar.mvfr2; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - - t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = t; - - t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = t; - - t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = t; - - t = cpu->isar.id_pfr2; - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = t; - } -#endif /* CONFIG_USER_ONLY */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +#endif } #endif /* !TARGET_AARCH64 */ @@ -1037,6 +1204,7 @@ static const ARMCPUInfo arm_tcg_cpus[] = { .class_init = arm_v7m_class_init }, { .name = "cortex-r5", .initfn = cortex_r5_initfn }, { .name = "cortex-r5f", .initfn = cortex_r5f_initfn }, + { .name = "cortex-r52", .initfn = cortex_r52_initfn }, { .name = "ti925t", .initfn = ti925t_initfn }, { .name = "sa1100", .initfn = sa1100_initfn }, { .name = "sa1110", .initfn = sa1110_initfn }, diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index 28a84c2dbdb6..d28690321f0b 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -15,6 +15,7 @@ #include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "crypto/aes.h" +#include "crypto/sm4.h" #include "vec_internal.h" union CRYPTO_STATE { @@ -23,7 +24,7 @@ union CRYPTO_STATE { uint64_t l[2]; }; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define CR_ST_BYTE(state, i) ((state).bytes[(15 - (i)) ^ 8]) #define CR_ST_WORD(state, i) ((state).words[(3 - (i)) ^ 2]) #else @@ -694,41 +695,6 @@ DO_SM3TT(crypto_sm3tt2b, 3) #undef DO_SM3TT -static uint8_t const sm4_sbox[] = { - 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, - 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, - 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, - 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, - 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, - 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, - 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, - 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, - 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, - 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, - 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, - 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, - 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, - 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, - 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, - 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, - 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, - 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, - 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, - 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, - 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, - 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, - 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, - 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, - 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, - 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, - 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, - 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, - 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, - 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, - 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, - 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, -}; - static void do_crypto_sm4e(uint64_t *rd, uint64_t *rn, uint64_t *rm) { union CRYPTO_STATE d = { .l = { rn[0], rn[1] } }; diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 32f3caec2389..2f6ddc0da57b 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -6,11 +6,163 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "internals.h" +#include "cpregs.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" + +/* Return the Exception Level targeted by debug exceptions. */ +static int arm_debug_target_el(CPUARMState *env) +{ + bool secure = arm_is_secure(env); + bool route_to_el2 = false; + + if (arm_is_el2_enabled(env)) { + route_to_el2 = env->cp15.hcr_el2 & HCR_TGE || + env->cp15.mdcr_el2 & MDCR_TDE; + } + + if (route_to_el2) { + return 2; + } else if (arm_feature(env, ARM_FEATURE_EL3) && + !arm_el_is_aa64(env, 3) && secure) { + return 3; + } else { + return 1; + } +} + +/* + * Raise an exception to the debug target el. + * Modify syndrome to indicate when origin and target EL are the same. + */ +G_NORETURN static void +raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome) +{ + int debug_el = arm_debug_target_el(env); + int cur_el = arm_current_el(env); + + /* + * If singlestep is targeting a lower EL than the current one, then + * DisasContext.ss_active must be false and we can never get here. + * Similarly for watchpoint and breakpoint matches. + */ + assert(debug_el >= cur_el); + syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT; + raise_exception(env, excp, syndrome, debug_el); +} + +/* See AArch64.GenerateDebugExceptionsFrom() in ARM ARM pseudocode */ +static bool aa64_generate_debug_exceptions(CPUARMState *env) +{ + int cur_el = arm_current_el(env); + int debug_el; + + if (cur_el == 3) { + return false; + } + + /* MDCR_EL3.SDD disables debug events from Secure state */ + if (arm_is_secure_below_el3(env) + && extract32(env->cp15.mdcr_el3, 16, 1)) { + return false; + } + + /* + * Same EL to same EL debug exceptions need MDSCR_KDE enabled + * while not masking the (D)ebug bit in DAIF. + */ + debug_el = arm_debug_target_el(env); + + if (cur_el == debug_el) { + return extract32(env->cp15.mdscr_el1, 13, 1) + && !(env->daif & PSTATE_D); + } + + /* Otherwise the debug target needs to be a higher EL */ + return debug_el > cur_el; +} + +static bool aa32_generate_debug_exceptions(CPUARMState *env) +{ + int el = arm_current_el(env); + + if (el == 0 && arm_el_is_aa64(env, 1)) { + return aa64_generate_debug_exceptions(env); + } + + if (arm_is_secure(env)) { + int spd; + + if (el == 0 && (env->cp15.sder & 1)) { + /* + * SDER.SUIDEN means debug exceptions from Secure EL0 + * are always enabled. Otherwise they are controlled by + * SDCR.SPD like those from other Secure ELs. + */ + return true; + } + + spd = extract32(env->cp15.mdcr_el3, 14, 2); + switch (spd) { + case 1: + /* SPD == 0b01 is reserved, but behaves as 0b00. */ + case 0: + /* + * For 0b00 we return true if external secure invasive debug + * is enabled. On real hardware this is controlled by external + * signals to the core. QEMU always permits debug, and behaves + * as if DBGEN, SPIDEN, NIDEN and SPNIDEN are all tied high. + */ + return true; + case 2: + return false; + case 3: + return true; + } + } + + return el != 2; +} + +/* + * Return true if debugging exceptions are currently enabled. + * This corresponds to what in ARM ARM pseudocode would be + * if UsingAArch32() then + * return AArch32.GenerateDebugExceptions() + * else + * return AArch64.GenerateDebugExceptions() + * We choose to push the if() down into this function for clarity, + * since the pseudocode has it at all callsites except for the one in + * CheckSoftwareStep(), where it is elided because both branches would + * always return the same value. + */ +bool arm_generate_debug_exceptions(CPUARMState *env) +{ + if ((env->cp15.oslsr_el1 & 1) || (env->cp15.osdlr_el1 & 1)) { + return false; + } + if (is_a64(env)) { + return aa64_generate_debug_exceptions(env); + } else { + return aa32_generate_debug_exceptions(env); + } +} + +/* + * Is single-stepping active? (Note that the "is EL_D AArch64?" check + * implicitly means this always returns false in pre-v8 CPUs.) + */ +bool arm_singlestep_active(CPUARMState *env) +{ + return extract32(env->cp15.mdscr_el1, 0, 1) + && arm_el_is_aa64(env, arm_debug_target_el(env)) + && arm_generate_debug_exceptions(env); +} + /* Return true if the linked breakpoint entry lbn passes its checks */ static bool linked_bp_matches(ARMCPU *cpu, int lbn) { @@ -143,9 +295,9 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp) * Non-Secure to simplify the code slightly compared to the full * table in the ARM ARM. */ - pac = extract64(cr, 1, 2); - hmc = extract64(cr, 13, 1); - ssc = extract64(cr, 14, 2); + pac = FIELD_EX64(cr, DBGWCR, PAC); + hmc = FIELD_EX64(cr, DBGWCR, HMC); + ssc = FIELD_EX64(cr, DBGWCR, SSC); switch (ssc) { case 0: @@ -184,8 +336,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp) g_assert_not_reached(); } - wt = extract64(cr, 20, 1); - lbn = extract64(cr, 16, 4); + wt = FIELD_EX64(cr, DBGWCR, WT); + lbn = FIELD_EX64(cr, DBGWCR, LBN); if (wt && !linked_bp_matches(cpu, lbn)) { return false; @@ -273,6 +425,35 @@ bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) return check_watchpoints(cpu); } +/* + * Return the FSR value for a debug exception (watchpoint, hardware + * breakpoint or BKPT insn) targeting the specified exception level. + */ +static uint32_t arm_debug_exception_fsr(CPUARMState *env) +{ + ARMMMUFaultInfo fi = { .type = ARMFault_Debug }; + int target_el = arm_debug_target_el(env); + bool using_lpae = false; + + if (target_el == 2 || arm_el_is_aa64(env, target_el)) { + using_lpae = true; + } else if (arm_feature(env, ARM_FEATURE_PMSA) && + arm_feature(env, ARM_FEATURE_V8)) { + using_lpae = true; + } else { + if (arm_feature(env, ARM_FEATURE_LPAE) && + (env->cp15.tcr_el[target_el] & TTBCR_EAE)) { + using_lpae = true; + } + } + + if (using_lpae) { + return arm_fi_to_lfsc(&fi); + } else { + return arm_fi_to_sfsc(&fi); + } +} + void arm_debug_excp_handler(CPUState *cs) { /* @@ -286,19 +467,16 @@ void arm_debug_excp_handler(CPUState *cs) if (wp_hit) { if (wp_hit->flags & BP_CPU) { bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0; - bool same_el = arm_debug_target_el(env) == arm_current_el(env); cs->watchpoint_hit = NULL; env->exception.fsr = arm_debug_exception_fsr(env); env->exception.vaddress = wp_hit->hitaddr; - raise_exception(env, EXCP_DATA_ABORT, - syn_watchpoint(same_el, 0, wnr), - arm_debug_target_el(env)); + raise_exception_debug(env, EXCP_DATA_ABORT, + syn_watchpoint(0, 0, wnr)); } } else { uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; - bool same_el = (arm_debug_target_el(env) == arm_current_el(env)); /* * (1) GDB breakpoints should be handled first. @@ -318,9 +496,618 @@ void arm_debug_excp_handler(CPUState *cs) * exception/security level. */ env->exception.vaddress = 0; - raise_exception(env, EXCP_PREFETCH_ABORT, - syn_breakpoint(same_el), - arm_debug_target_el(env)); + raise_exception_debug(env, EXCP_PREFETCH_ABORT, syn_breakpoint(0)); + } +} + +/* + * Raise an EXCP_BKPT with the specified syndrome register value, + * targeting the correct exception level for debug exceptions. + */ +void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome) +{ + int debug_el = arm_debug_target_el(env); + int cur_el = arm_current_el(env); + + /* FSR will only be used if the debug target EL is AArch32. */ + env->exception.fsr = arm_debug_exception_fsr(env); + /* + * FAR is UNKNOWN: clear vaddress to avoid potentially exposing + * values to the guest that it shouldn't be able to see at its + * exception/security level. + */ + env->exception.vaddress = 0; + /* + * Other kinds of architectural debug exception are ignored if + * they target an exception level below the current one (in QEMU + * this is checked by arm_generate_debug_exceptions()). Breakpoint + * instructions are special because they always generate an exception + * to somewhere: if they can't go to the configured debug exception + * level they are taken to the current exception level. + */ + if (debug_el < cur_el) { + debug_el = cur_el; + } + raise_exception(env, EXCP_BKPT, syndrome, debug_el); +} + +void HELPER(exception_swstep)(CPUARMState *env, uint32_t syndrome) +{ + raise_exception_debug(env, EXCP_UDEF, syndrome); +} + +/* + * Check for traps to "powerdown debug" registers, which are controlled + * by MDCR.TDOSA + */ +static CPAccessResult access_tdosa(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); + bool mdcr_el2_tdosa = (mdcr_el2 & MDCR_TDOSA) || (mdcr_el2 & MDCR_TDE) || + (arm_hcr_el2_eff(env) & HCR_TGE); + + if (el < 2 && mdcr_el2_tdosa) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDOSA)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +/* + * Check for traps to "debug ROM" registers, which are controlled + * by MDCR_EL2.TDRA for EL2 but by the more general MDCR_EL3.TDA for EL3. + */ +static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); + bool mdcr_el2_tdra = (mdcr_el2 & MDCR_TDRA) || (mdcr_el2 & MDCR_TDE) || + (arm_hcr_el2_eff(env) & HCR_TGE); + + if (el < 2 && mdcr_el2_tdra) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +/* + * Check for traps to general debug registers, which are controlled + * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3. + */ +static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); + bool mdcr_el2_tda = (mdcr_el2 & MDCR_TDA) || (mdcr_el2 & MDCR_TDE) || + (arm_hcr_el2_eff(env) & HCR_TGE); + + if (el < 2 && mdcr_el2_tda) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* + * Writes to OSLAR_EL1 may update the OS lock status, which can be + * read via a bit in OSLSR_EL1. + */ + int oslock; + + if (ri->state == ARM_CP_STATE_AA32) { + oslock = (value == 0xC5ACCE55); + } else { + oslock = value & 1; + } + + env->cp15.oslsr_el1 = deposit32(env->cp15.oslsr_el1, 1, 1, oslock); +} + +static void osdlr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + /* + * Only defined bit is bit 0 (DLK); if Feat_DoubleLock is not + * implemented this is RAZ/WI. + */ + if(arm_feature(env, ARM_FEATURE_AARCH64) + ? cpu_isar_feature(aa64_doublelock, cpu) + : cpu_isar_feature(aa32_doublelock, cpu)) { + env->cp15.osdlr_el1 = value & 1; + } +} + +static const ARMCPRegInfo debug_cp_reginfo[] = { + /* + * DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped + * debug components. The AArch64 version of DBGDRAR is named MDRAR_EL1; + * unlike DBGDRAR it is never accessible from EL0. + * DBGDSAR is deprecated and must RAZ from v8 anyway, so it has no AArch64 + * accessor. + */ + { .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .accessfn = access_tdra, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, + .access = PL1_R, .accessfn = access_tdra, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .accessfn = access_tdra, + .type = ARM_CP_CONST, .resetvalue = 0 }, + /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */ + { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, + .access = PL1_RW, .accessfn = access_tda, + .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), + .resetvalue = 0 }, + /* + * MDCCSR_EL0[30:29] map to EDSCR[30:29]. Simply RAZ as the external + * Debug Communication Channel is not implemented. + */ + { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0, + .access = PL0_R, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = 0 }, + /* + * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as + * it is unlikely a guest will care. + * We don't implement the configurable EL0 access. + */ + { .name = "DBGDSCRint", .state = ARM_CP_STATE_AA32, + .cp = 14, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0, + .type = ARM_CP_ALIAS, + .access = PL1_R, .accessfn = access_tda, + .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), }, + { .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4, + .access = PL1_W, .type = ARM_CP_NO_RAW, + .accessfn = access_tdosa, + .writefn = oslar_write }, + { .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4, + .access = PL1_R, .resetvalue = 10, + .accessfn = access_tdosa, + .fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) }, + /* Dummy OSDLR_EL1: 32-bit Linux will read this */ + { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4, + .access = PL1_RW, .accessfn = access_tdosa, + .writefn = osdlr_write, + .fieldoffset = offsetof(CPUARMState, cp15.osdlr_el1) }, + /* + * Dummy DBGVCR: Linux wants to clear this on startup, but we don't + * implement vector catch debug events yet. + */ + { .name = "DBGVCR", + .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_NOP }, + /* + * Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor + * to save and restore a 32-bit guest's DBGVCR) + */ + { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0, + .access = PL2_RW, .accessfn = access_tda, + .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP }, + /* + * Dummy MDCCINT_EL1, since we don't implement the Debug Communications + * Channel but Linux may try to access this register. The 32-bit + * alias is DBGDCCINT. + */ + { .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_NOP }, +}; + +static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { + /* 64 bit access versions of the (dummy) debug registers */ + { .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0, + .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0, + .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, +}; + +void hw_watchpoint_update(ARMCPU *cpu, int n) +{ + CPUARMState *env = &cpu->env; + vaddr len = 0; + vaddr wvr = env->cp15.dbgwvr[n]; + uint64_t wcr = env->cp15.dbgwcr[n]; + int mask; + int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; + + if (env->cpu_watchpoint[n]) { + cpu_watchpoint_remove_by_ref(CPU(cpu), env->cpu_watchpoint[n]); + env->cpu_watchpoint[n] = NULL; + } + + if (!FIELD_EX64(wcr, DBGWCR, E)) { + /* E bit clear : watchpoint disabled */ + return; + } + + switch (FIELD_EX64(wcr, DBGWCR, LSC)) { + case 0: + /* LSC 00 is reserved and must behave as if the wp is disabled */ + return; + case 1: + flags |= BP_MEM_READ; + break; + case 2: + flags |= BP_MEM_WRITE; + break; + case 3: + flags |= BP_MEM_ACCESS; + break; + } + + /* + * Attempts to use both MASK and BAS fields simultaneously are + * CONSTRAINED UNPREDICTABLE; we opt to ignore BAS in this case, + * thus generating a watchpoint for every byte in the masked region. + */ + mask = FIELD_EX64(wcr, DBGWCR, MASK); + if (mask == 1 || mask == 2) { + /* + * Reserved values of MASK; we must act as if the mask value was + * some non-reserved value, or as if the watchpoint were disabled. + * We choose the latter. + */ + return; + } else if (mask) { + /* Watchpoint covers an aligned area up to 2GB in size */ + len = 1ULL << mask; + /* + * If masked bits in WVR are not zero it's CONSTRAINED UNPREDICTABLE + * whether the watchpoint fires when the unmasked bits match; we opt + * to generate the exceptions. + */ + wvr &= ~(len - 1); + } else { + /* Watchpoint covers bytes defined by the byte address select bits */ + int bas = FIELD_EX64(wcr, DBGWCR, BAS); + int basstart; + + if (extract64(wvr, 2, 1)) { + /* + * Deprecated case of an only 4-aligned address. BAS[7:4] are + * ignored, and BAS[3:0] define which bytes to watch. + */ + bas &= 0xf; + } + + if (bas == 0) { + /* This must act as if the watchpoint is disabled */ + return; + } + + /* + * The BAS bits are supposed to be programmed to indicate a contiguous + * range of bytes. Otherwise it is CONSTRAINED UNPREDICTABLE whether + * we fire for each byte in the word/doubleword addressed by the WVR. + * We choose to ignore any non-zero bits after the first range of 1s. + */ + basstart = ctz32(bas); + len = cto32(bas >> basstart); + wvr += basstart; + } + + cpu_watchpoint_insert(CPU(cpu), wvr, len, flags, + &env->cpu_watchpoint[n]); +} + +void hw_watchpoint_update_all(ARMCPU *cpu) +{ + int i; + CPUARMState *env = &cpu->env; + + /* + * Completely clear out existing QEMU watchpoints and our array, to + * avoid possible stale entries following migration load. + */ + cpu_watchpoint_remove_all(CPU(cpu), BP_CPU); + memset(env->cpu_watchpoint, 0, sizeof(env->cpu_watchpoint)); + + for (i = 0; i < ARRAY_SIZE(cpu->env.cpu_watchpoint); i++) { + hw_watchpoint_update(cpu, i); + } +} + +static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + int i = ri->crm; + + /* + * Bits [1:0] are RES0. + * + * It is IMPLEMENTATION DEFINED whether [63:49] ([63:53] with FEAT_LVA) + * are hardwired to the value of bit [48] ([52] with FEAT_LVA), or if + * they contain the value written. It is CONSTRAINED UNPREDICTABLE + * whether the RESS bits are ignored when comparing an address. + * + * Therefore we are allowed to compare the entire register, which lets + * us avoid considering whether or not FEAT_LVA is actually enabled. + */ + value &= ~3ULL; + + raw_write(env, ri, value); + hw_watchpoint_update(cpu, i); +} + +static void dbgwcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + int i = ri->crm; + + raw_write(env, ri, value); + hw_watchpoint_update(cpu, i); +} + +void hw_breakpoint_update(ARMCPU *cpu, int n) +{ + CPUARMState *env = &cpu->env; + uint64_t bvr = env->cp15.dbgbvr[n]; + uint64_t bcr = env->cp15.dbgbcr[n]; + vaddr addr; + int bt; + int flags = BP_CPU; + + if (env->cpu_breakpoint[n]) { + cpu_breakpoint_remove_by_ref(CPU(cpu), env->cpu_breakpoint[n]); + env->cpu_breakpoint[n] = NULL; + } + + if (!extract64(bcr, 0, 1)) { + /* E bit clear : watchpoint disabled */ + return; + } + + bt = extract64(bcr, 20, 4); + + switch (bt) { + case 4: /* unlinked address mismatch (reserved if AArch64) */ + case 5: /* linked address mismatch (reserved if AArch64) */ + qemu_log_mask(LOG_UNIMP, + "arm: address mismatch breakpoint types not implemented\n"); + return; + case 0: /* unlinked address match */ + case 1: /* linked address match */ + { + /* + * Bits [1:0] are RES0. + * + * It is IMPLEMENTATION DEFINED whether bits [63:49] + * ([63:53] for FEAT_LVA) are hardwired to a copy of the sign bit + * of the VA field ([48] or [52] for FEAT_LVA), or whether the + * value is read as written. It is CONSTRAINED UNPREDICTABLE + * whether the RESS bits are ignored when comparing an address. + * Therefore we are allowed to compare the entire register, which + * lets us avoid considering whether FEAT_LVA is actually enabled. + * + * The BAS field is used to allow setting breakpoints on 16-bit + * wide instructions; it is CONSTRAINED UNPREDICTABLE whether + * a bp will fire if the addresses covered by the bp and the addresses + * covered by the insn overlap but the insn doesn't start at the + * start of the bp address range. We choose to require the insn and + * the bp to have the same address. The constraints on writing to + * BAS enforced in dbgbcr_write mean we have only four cases: + * 0b0000 => no breakpoint + * 0b0011 => breakpoint on addr + * 0b1100 => breakpoint on addr + 2 + * 0b1111 => breakpoint on addr + * See also figure D2-3 in the v8 ARM ARM (DDI0487A.c). + */ + int bas = extract64(bcr, 5, 4); + addr = bvr & ~3ULL; + if (bas == 0) { + return; + } + if (bas == 0xc) { + addr += 2; + } + break; + } + case 2: /* unlinked context ID match */ + case 8: /* unlinked VMID match (reserved if no EL2) */ + case 10: /* unlinked context ID and VMID match (reserved if no EL2) */ + qemu_log_mask(LOG_UNIMP, + "arm: unlinked context breakpoint types not implemented\n"); + return; + case 9: /* linked VMID match (reserved if no EL2) */ + case 11: /* linked context ID and VMID match (reserved if no EL2) */ + case 3: /* linked context ID match */ + default: + /* + * We must generate no events for Linked context matches (unless + * they are linked to by some other bp/wp, which is handled in + * updates for the linking bp/wp). We choose to also generate no events + * for reserved values. + */ + return; + } + + cpu_breakpoint_insert(CPU(cpu), addr, flags, &env->cpu_breakpoint[n]); +} + +void hw_breakpoint_update_all(ARMCPU *cpu) +{ + int i; + CPUARMState *env = &cpu->env; + + /* + * Completely clear out existing QEMU breakpoints and our array, to + * avoid possible stale entries following migration load. + */ + cpu_breakpoint_remove_all(CPU(cpu), BP_CPU); + memset(env->cpu_breakpoint, 0, sizeof(env->cpu_breakpoint)); + + for (i = 0; i < ARRAY_SIZE(cpu->env.cpu_breakpoint); i++) { + hw_breakpoint_update(cpu, i); + } +} + +static void dbgbvr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + int i = ri->crm; + + raw_write(env, ri, value); + hw_breakpoint_update(cpu, i); +} + +static void dbgbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + int i = ri->crm; + + /* + * BAS[3] is a read-only copy of BAS[2], and BAS[1] a read-only + * copy of BAS[0]. + */ + value = deposit64(value, 6, 1, extract64(value, 5, 1)); + value = deposit64(value, 8, 1, extract64(value, 7, 1)); + + raw_write(env, ri, value); + hw_breakpoint_update(cpu, i); +} + +void define_debug_regs(ARMCPU *cpu) +{ + /* + * Define v7 and v8 architectural debug registers. + * These are just dummy implementations for now. + */ + int i; + int wrps, brps, ctx_cmps; + + /* + * The Arm ARM says DBGDIDR is optional and deprecated if EL1 cannot + * use AArch32. Given that bit 15 is RES1, if the value is 0 then + * the register must not exist for this cpu. + */ + if (cpu->isar.dbgdidr != 0) { + ARMCPRegInfo dbgdidr = { + .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, + .opc1 = 0, .opc2 = 0, + .access = PL0_R, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, + }; + define_one_arm_cp_reg(cpu, &dbgdidr); + } + + /* + * DBGDEVID is present in the v7 debug architecture if + * DBGDIDR.DEVID_imp is 1 (bit 15); from v7.1 and on it is + * mandatory (and bit 15 is RES1). DBGDEVID1 and DBGDEVID2 exist + * from v7.1 of the debug architecture. Because no fields have yet + * been defined in DBGDEVID2 (and quite possibly none will ever + * be) we don't define an ARMISARegisters field for it. + * These registers exist only if EL1 can use AArch32, but that + * happens naturally because they are only PL1 accessible anyway. + */ + if (extract32(cpu->isar.dbgdidr, 15, 1)) { + ARMCPRegInfo dbgdevid = { + .name = "DBGDEVID", + .cp = 14, .opc1 = 0, .crn = 7, .opc2 = 2, .crn = 7, + .access = PL1_R, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdevid, + }; + define_one_arm_cp_reg(cpu, &dbgdevid); + } + if (cpu_isar_feature(aa32_debugv7p1, cpu)) { + ARMCPRegInfo dbgdevid12[] = { + { + .name = "DBGDEVID1", + .cp = 14, .opc1 = 0, .crn = 7, .opc2 = 1, .crn = 7, + .access = PL1_R, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdevid1, + }, { + .name = "DBGDEVID2", + .cp = 14, .opc1 = 0, .crn = 7, .opc2 = 0, .crn = 7, + .access = PL1_R, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = 0, + }, + }; + define_arm_cp_regs(cpu, dbgdevid12); + } + + brps = arm_num_brps(cpu); + wrps = arm_num_wrps(cpu); + ctx_cmps = arm_num_ctx_cmps(cpu); + + assert(ctx_cmps <= brps); + + define_arm_cp_regs(cpu, debug_cp_reginfo); + + if (arm_feature(&cpu->env, ARM_FEATURE_LPAE)) { + define_arm_cp_regs(cpu, debug_lpae_cp_reginfo); + } + + for (i = 0; i < brps; i++) { + char *dbgbvr_el1_name = g_strdup_printf("DBGBVR%d_EL1", i); + char *dbgbcr_el1_name = g_strdup_printf("DBGBCR%d_EL1", i); + ARMCPRegInfo dbgregs[] = { + { .name = dbgbvr_el1_name, .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, + .access = PL1_RW, .accessfn = access_tda, + .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]), + .writefn = dbgbvr_write, .raw_writefn = raw_write + }, + { .name = dbgbcr_el1_name, .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5, + .access = PL1_RW, .accessfn = access_tda, + .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), + .writefn = dbgbcr_write, .raw_writefn = raw_write + }, + }; + define_arm_cp_regs(cpu, dbgregs); + g_free(dbgbvr_el1_name); + g_free(dbgbcr_el1_name); + } + + for (i = 0; i < wrps; i++) { + char *dbgwvr_el1_name = g_strdup_printf("DBGWVR%d_EL1", i); + char *dbgwcr_el1_name = g_strdup_printf("DBGWCR%d_EL1", i); + ARMCPRegInfo dbgregs[] = { + { .name = dbgwvr_el1_name, .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, + .access = PL1_RW, .accessfn = access_tda, + .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]), + .writefn = dbgwvr_write, .raw_writefn = raw_write + }, + { .name = dbgwcr_el1_name, .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7, + .access = PL1_RW, .accessfn = access_tda, + .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), + .writefn = dbgwcr_write, .raw_writefn = raw_write + }, + }; + define_arm_cp_regs(cpu, dbgregs); + g_free(dbgwvr_el1_name); + g_free(dbgwcr_el1_name); } } diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index ca1de4751160..2f806512d0ad 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -19,8 +19,9 @@ */ #include "qemu/osdep.h" #include "cpu.h" -#include "internals.h" #include "exec/gdbstub.h" +#include "internals.h" +#include "cpregs.h" typedef struct RegisterSysregXmlParam { CPUState *cs; @@ -117,7 +118,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) /* * Don't allow writing to XPSR.Exception as it can cause * a transition into or out of handler mode (it's not - * writeable via the MSR insn so this is a reasonable + * writable via the MSR insn so this is a reasonable * restriction). Other fields are safe to update. */ xpsr_write(env, tmp, ~XPSR_EXCP); @@ -272,7 +273,7 @@ static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, static void arm_register_sysreg_for_xml(gpointer key, gpointer value, gpointer p) { - uint32_t ri_key = *(uint32_t *)key; + uint32_t ri_key = (uintptr_t)key; ARMCPRegInfo *ri = value; RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; GString *s = param->s; diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 596878666d73..07a6746944d2 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -152,7 +152,7 @@ int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg) * We report in Vector Granules (VG) which is 64bit in a Z reg * while the ZCR works in Vector Quads (VQ) which is 128bit chunks. */ - int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1; + int vq = sve_vqm1_for_el(env, arm_current_el(env)) + 1; return gdb_get_reg64(buf, vq * 2); } default: diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 7cf953b1e64e..77a8502b6b6a 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -952,7 +952,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) qemu_mutex_unlock_iothread(); if (!return_to_aa64) { - env->aarch64 = 0; + env->aarch64 = false; /* We do a raw CPSR write because aarch64_sync_64_to_32() * will sort the register banks out for us, and we've already * caught all the bad-mode cases in el_from_spsr(). @@ -975,7 +975,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) } else { int tbii; - env->aarch64 = 1; + env->aarch64 = true; spsr &= aarch64_pstate_valid_mask(&env_archcpu(env)->isar); pstate_write(env, spsr); if (!arm_singlestep_active(env)) { diff --git a/target/arm/helper-sme.h b/target/arm/helper-sme.h new file mode 100644 index 000000000000..d2d544a6961b --- /dev/null +++ b/target/arm/helper-sme.h @@ -0,0 +1,147 @@ +/* + * AArch64 SME specific helper definitions + * + * Copyright (c) 2022 Linaro, Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.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 . + */ + +DEF_HELPER_FLAGS_2(set_pstate_sm, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_2(set_pstate_za, TCG_CALL_NO_RWG, void, env, i32) + +DEF_HELPER_FLAGS_3(sme_zero, TCG_CALL_NO_RWG, void, env, i32, i32) + +/* Move to/from vertical array slices, i.e. columns, so 'c'. */ +DEF_HELPER_FLAGS_4(sme_mova_cz_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_zc_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_cz_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_zc_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_cz_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_zc_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_cz_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_zc_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_cz_q, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_mova_zc_q, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(sme_ld1b_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1b_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1b_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1b_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_ld1h_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1h_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_ld1s_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1s_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_ld1d_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1d_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_ld1q_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_ld1q_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_st1b_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1b_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1b_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1b_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_st1h_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1h_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_st1s_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1s_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_st1d_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1d_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_st1q_be_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_le_h, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_be_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_le_v, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_be_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_le_h_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_be_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_5(sme_st1q_le_v_mte, TCG_CALL_NO_WG, void, env, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_5(sme_addha_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_addva_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_addha_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_addva_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_7(sme_fmopa_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sme_fmopa_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sme_fmopa_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_bfmopa, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_smopa_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_umopa_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_sumopa_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_usmopa_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_smopa_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_umopa_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_sumopa_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_6(sme_usmopa_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, i32) diff --git a/target/arm/helper-sve.h b/target/arm/helper-sve.h index dc629f851a3d..cc4e1d894813 100644 --- a/target/arm/helper-sve.h +++ b/target/arm/helper-sve.h @@ -325,6 +325,8 @@ DEF_HELPER_FLAGS_5(sve_sel_zpzz_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(sve_sel_zpzz_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve_sel_zpzz_q, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(sve2_addp_zpzz_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) @@ -717,6 +719,8 @@ DEF_HELPER_FLAGS_4(sve_revh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sve_revw_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_revd_q, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + DEF_HELPER_FLAGS_4(sve_rbit_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sve_rbit_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sve_rbit_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/helper.c b/target/arm/helper.c index 7d14650615c3..22ea8fbe3685 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7,14 +7,11 @@ */ #include "qemu/osdep.h" -#include "qemu/units.h" #include "qemu/log.h" -#include "target/arm/idau.h" #include "trace.h" #include "cpu.h" #include "internals.h" #include "exec/helper-proto.h" -#include "qemu/host-utils.h" #include "qemu/main-loop.h" #include "qemu/timer.h" #include "qemu/bitops.h" @@ -23,37 +20,19 @@ #include "exec/exec-all.h" #include /* For crc32 */ #include "hw/irq.h" -#include "semihosting/semihost.h" -#include "sysemu/cpus.h" #include "sysemu/cpu-timers.h" #include "sysemu/kvm.h" -#include "sysemu/tcg.h" -#include "qemu/range.h" #include "qapi/qapi-commands-machine-target.h" #include "qapi/error.h" #include "qemu/guest-random.h" #ifdef CONFIG_TCG -#include "arm_ldst.h" -#include "exec/cpu_ldst.h" #include "semihosting/common-semi.h" #endif +#include "cpregs.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ -#define PMCR_NUM_COUNTERS 4 /* QEMU IMPDEF choice */ - -#ifndef CONFIG_USER_ONLY - -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) - __attribute__((nonnull)); -#endif static void switch_mode(CPUARMState *env, int mode); -static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx); static uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri) { @@ -65,8 +44,7 @@ static uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri) } } -static void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) +void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { assert(ri->fieldoffset); if (cpreg_field_is_64bit(ri)) { @@ -98,7 +76,8 @@ uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri) static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t v) { - /* Raw write of a coprocessor register (as needed for migration, etc). + /* + * Raw write of a coprocessor register (as needed for migration, etc). * Note that constant registers are treated as write-ignored; the * caller should check for success by whether a readback gives the * value written. @@ -116,7 +95,8 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri, static bool raw_accessors_invalid(const ARMCPRegInfo *ri) { - /* Return true if the regdef would cause an assertion if you called + /* + * Return true if the regdef would cause an assertion if you called * read_raw_cp_reg() or write_raw_cp_reg() on it (ie if it is a * program bug for it not to have the NO_RAW flag). * NB that returning false here doesn't necessarily mean that calling @@ -199,7 +179,8 @@ bool write_list_to_cpustate(ARMCPU *cpu) if (ri->type & ARM_CP_NO_RAW) { continue; } - /* Write value and confirm it reads back as written + /* + * Write value and confirm it reads back as written * (to catch read-only registers and partially read-only * registers where the incoming migration value doesn't match) */ @@ -214,13 +195,10 @@ bool write_list_to_cpustate(ARMCPU *cpu) static void add_cpreg_to_list(gpointer key, gpointer opaque) { ARMCPU *cpu = opaque; - uint64_t regidx; - const ARMCPRegInfo *ri; + uint32_t regidx = (uintptr_t)key; + const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); - regidx = *(uint32_t *)key; - ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); - - if (!(ri->type & (ARM_CP_NO_RAW|ARM_CP_ALIAS))) { + if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) { cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx); /* The value array need not be initialized at this point */ cpu->cpreg_array_len++; @@ -230,21 +208,19 @@ static void add_cpreg_to_list(gpointer key, gpointer opaque) static void count_cpreg(gpointer key, gpointer opaque) { ARMCPU *cpu = opaque; - uint64_t regidx; const ARMCPRegInfo *ri; - regidx = *(uint32_t *)key; - ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); + ri = g_hash_table_lookup(cpu->cp_regs, key); - if (!(ri->type & (ARM_CP_NO_RAW|ARM_CP_ALIAS))) { + if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) { cpu->cpreg_array_len++; } } static gint cpreg_key_compare(gconstpointer a, gconstpointer b) { - uint64_t aidx = cpreg_to_kvm_id(*(uint32_t *)a); - uint64_t bidx = cpreg_to_kvm_id(*(uint32_t *)b); + uint64_t aidx = cpreg_to_kvm_id((uintptr_t)a); + uint64_t bidx = cpreg_to_kvm_id((uintptr_t)b); if (aidx > bidx) { return 1; @@ -257,7 +233,8 @@ static gint cpreg_key_compare(gconstpointer a, gconstpointer b) void init_cpreg_list(ARMCPU *cpu) { - /* Initialise the cpreg_tuples[] array based on the cp_regs hash. + /* + * Initialise the cpreg_tuples[] array based on the cp_regs hash. * Note that we require cpreg_tuples[] to be sorted by key ID. */ GList *keys; @@ -299,7 +276,8 @@ static CPAccessResult access_el3_aa32ns(CPUARMState *env, return CP_ACCESS_OK; } -/* Some secure-only AArch32 registers trap to EL3 if used from +/* + * Some secure-only AArch32 registers trap to EL3 if used from * Secure EL1 (but are just ordinary UNDEF in other non-EL3 contexts). * Note that an access from Secure EL1 can only happen if EL3 is AArch64. * We assume that the .access field is set to PL1_RW. @@ -321,72 +299,8 @@ static CPAccessResult access_trap_aa32s_el1(CPUARMState *env, return CP_ACCESS_TRAP_UNCATEGORIZED; } -static uint64_t arm_mdcr_el2_eff(CPUARMState *env) -{ - return arm_is_el2_enabled(env) ? env->cp15.mdcr_el2 : 0; -} - -/* Check for traps to "powerdown debug" registers, which are controlled - * by MDCR.TDOSA - */ -static CPAccessResult access_tdosa(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - int el = arm_current_el(env); - uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); - bool mdcr_el2_tdosa = (mdcr_el2 & MDCR_TDOSA) || (mdcr_el2 & MDCR_TDE) || - (arm_hcr_el2_eff(env) & HCR_TGE); - - if (el < 2 && mdcr_el2_tdosa) { - return CP_ACCESS_TRAP_EL2; - } - if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDOSA)) { - return CP_ACCESS_TRAP_EL3; - } - return CP_ACCESS_OK; -} - -/* Check for traps to "debug ROM" registers, which are controlled - * by MDCR_EL2.TDRA for EL2 but by the more general MDCR_EL3.TDA for EL3. - */ -static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - int el = arm_current_el(env); - uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); - bool mdcr_el2_tdra = (mdcr_el2 & MDCR_TDRA) || (mdcr_el2 & MDCR_TDE) || - (arm_hcr_el2_eff(env) & HCR_TGE); - - if (el < 2 && mdcr_el2_tdra) { - return CP_ACCESS_TRAP_EL2; - } - if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) { - return CP_ACCESS_TRAP_EL3; - } - return CP_ACCESS_OK; -} - -/* Check for traps to general debug registers, which are controlled - * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3. - */ -static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - int el = arm_current_el(env); - uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); - bool mdcr_el2_tda = (mdcr_el2 & MDCR_TDA) || (mdcr_el2 & MDCR_TDE) || - (arm_hcr_el2_eff(env) & HCR_TGE); - - if (el < 2 && mdcr_el2_tda) { - return CP_ACCESS_TRAP_EL2; - } - if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) { - return CP_ACCESS_TRAP_EL3; - } - return CP_ACCESS_OK; -} - -/* Check for traps to performance monitor registers, which are controlled +/* + * Check for traps to performance monitor registers, which are controlled * by MDCR_EL2.TPM for EL2 and MDCR_EL3.TPM for EL3. */ static CPAccessResult access_tpm(CPUARMState *env, const ARMCPRegInfo *ri, @@ -447,6 +361,30 @@ static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBIS. */ +static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && + (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBIS))) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} + +#ifdef TARGET_AARCH64 +/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBOS. */ +static CPAccessResult access_ttlbos(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && + (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBOS))) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} +#endif + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -460,7 +398,8 @@ static void fcse_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) ARMCPU *cpu = env_archcpu(env); if (raw_read(env, ri) != value) { - /* Unlike real hardware the qemu TLB uses virtual addresses, + /* + * Unlike real hardware the qemu TLB uses virtual addresses, * not modified virtual addresses, so this causes a TLB flush. */ tlb_flush(CPU(cpu)); @@ -475,7 +414,8 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri, if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_PMSA) && !extended_addresses_enabled(env)) { - /* For VMSA (when not using the LPAE long descriptor page table + /* + * For VMSA (when not using the LPAE long descriptor page table * format) this register includes the ASID, so do a TLB flush. * For PMSA it is purely a process ID and no action is needed. */ @@ -484,6 +424,21 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri, raw_write(env, ri, value); } +static int alle1_tlbmask(CPUARMState *env) +{ + /* + * Note that the 'ALL' scope must invalidate both stage 1 and + * stage 2 translations, whereas most other scopes only invalidate + * stage 1 translations. + */ + return (ARMMMUIdxBit_E10_1 | + ARMMMUIdxBit_E10_1_PAN | + ARMMMUIdxBit_E10_0 | + ARMMMUIdxBit_Stage2 | + ARMMMUIdxBit_Stage2_S); +} + + /* IS variants of TLB operations must affect all cores */ static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) @@ -586,10 +541,7 @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = env_cpu(env); - tlb_flush_by_mmuidx(cs, - ARMMMUIdxBit_E10_1 | - ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0); + tlb_flush_by_mmuidx(cs, alle1_tlbmask(env)); } static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -597,10 +549,7 @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = env_cpu(env); - tlb_flush_by_mmuidx_all_cpus_synced(cs, - ARMMMUIdxBit_E10_1 | - ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0); + tlb_flush_by_mmuidx_all_cpus_synced(cs, alle1_tlbmask(env)); } @@ -639,8 +588,27 @@ static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMMMUIdxBit_E2); } +static void tlbiipas2_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + CPUState *cs = env_cpu(env); + uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12; + + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2); +} + +static void tlbiipas2is_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + CPUState *cs = env_cpu(env); + uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12; + + tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, ARMMMUIdxBit_Stage2); +} + static const ARMCPRegInfo cp_reginfo[] = { - /* Define the secure and non-secure FCSE identifier CP registers + /* + * Define the secure and non-secure FCSE identifier CP registers * separately because there is no secure bank in V8 (no _EL3). This allows * the secure register to be properly reset and migrated. There is also no * v8 EL1 version of the register so the non-secure instance stands alone. @@ -655,7 +623,8 @@ static const ARMCPRegInfo cp_reginfo[] = { .access = PL1_RW, .secure = ARM_CP_SECSTATE_S, .fieldoffset = offsetof(CPUARMState, cp15.fcseidr_s), .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, }, - /* Define the secure and non-secure context identifier CP registers + /* + * Define the secure and non-secure context identifier CP registers * separately because there is no secure bank in V8 (no _EL3). This allows * the secure register to be properly reset and migrated. In the * non-secure case, the 32-bit register will have reset and migration @@ -673,11 +642,11 @@ static const ARMCPRegInfo cp_reginfo[] = { .secure = ARM_CP_SECSTATE_S, .fieldoffset = offsetof(CPUARMState, cp15.contextidr_s), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo not_v8_cp_reginfo[] = { - /* NB: Some of these registers exist in v8 but with more precise + /* + * NB: Some of these registers exist in v8 but with more precise * definitions that don't use CP_ANY wildcards (mostly in v8_cp_reginfo[]). */ /* MMU Domain access control / MPU write buffer control */ @@ -687,7 +656,8 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = { .writefn = dacr_write, .raw_writefn = raw_write, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), offsetoflow32(CPUARMState, cp15.dacr_ns) } }, - /* ARMv7 allocates a range of implementation defined TLB LOCKDOWN regs. + /* + * ARMv7 allocates a range of implementation defined TLB LOCKDOWN regs. * For v6 and v5, these mappings are overly broad. */ { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 0, @@ -702,25 +672,26 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = { { .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_OVERRIDE }, - REGINFO_SENTINEL }; static const ARMCPRegInfo not_v6_cp_reginfo[] = { - /* Not all pre-v6 cores implemented this WFI, so this is slightly + /* + * Not all pre-v6 cores implemented this WFI, so this is slightly * over-broad. */ { .name = "WFI_v5", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = 2, .access = PL1_W, .type = ARM_CP_WFI }, - REGINFO_SENTINEL }; static const ARMCPRegInfo not_v7_cp_reginfo[] = { - /* Standard v6 WFI (also used in some pre-v6 cores); not in v7 (which + /* + * Standard v6 WFI (also used in some pre-v6 cores); not in v7 (which * is UNPREDICTABLE; we choose to NOP as most implementations do). */ { .name = "WFI_v6", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, .access = PL1_W, .type = ARM_CP_WFI }, - /* L1 cache lockdown. Not architectural in v6 and earlier but in practice + /* + * L1 cache lockdown. Not architectural in v6 and earlier but in practice * implemented in 926, 946, 1026, 1136, 1176 and 11MPCore. StrongARM and * OMAPCP will override this space. */ @@ -734,14 +705,16 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = { { .name = "DUMMY", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = CP_ANY, .access = PL1_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW, .resetvalue = 0 }, - /* We don't implement pre-v7 debug but most CPUs had at least a DBGDIDR; + /* + * We don't implement pre-v7 debug but most CPUs had at least a DBGDIDR; * implementing it as RAZ means the "debug architecture version" bits * will read as a reserved value, which should cause Linux to not try * to use the debug hardware. */ { .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* MMU TLB control. Note that the wildcarding means we cover not just + /* + * MMU TLB control. Note that the wildcarding means we cover not just * the unified TLB ops but also the dside/iside/inner-shareable variants. */ { .name = "TLBIALL", .cp = 15, .crn = 8, .crm = CP_ANY, @@ -760,7 +733,6 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = { .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP }, { .name = "NMRR", .cp = 15, .crn = 10, .crm = 2, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -770,25 +742,30 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, /* In ARMv8 most bits of CPACR_EL1 are RES0. */ if (!arm_feature(env, ARM_FEATURE_V8)) { - /* ARMv7 defines bits for unimplemented coprocessors as RAZ/WI. + /* + * ARMv7 defines bits for unimplemented coprocessors as RAZ/WI. * ASEDIS [31] and D32DIS [30] are both UNK/SBZP without VFP. * TRCDIS [28] is RAZ/WI since we do not implement a trace macrocell. */ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { /* VFP coprocessor: cp10 & cp11 [23:20] */ - mask |= (1 << 31) | (1 << 30) | (0xf << 20); + mask |= R_CPACR_ASEDIS_MASK | + R_CPACR_D32DIS_MASK | + R_CPACR_CP11_MASK | + R_CPACR_CP10_MASK; if (!arm_feature(env, ARM_FEATURE_NEON)) { /* ASEDIS [31] bit is RAO/WI */ - value |= (1 << 31); + value |= R_CPACR_ASEDIS_MASK; } - /* VFPv3 and upwards with NEON implement 32 double precision + /* + * VFPv3 and upwards with NEON implement 32 double precision * registers (D0-D31). */ if (!cpu_isar_feature(aa32_simd_r32, env_archcpu(env))) { /* D32DIS [30] is RAO/WI if D16-31 are not implemented. */ - value |= (1 << 30); + value |= R_CPACR_D32DIS_MASK; } } value &= mask; @@ -800,8 +777,8 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value &= ~(0xf << 20); - value |= env->cp15.cpacr_el1 & (0xf << 20); + mask = R_CPACR_CP11_MASK | R_CPACR_CP10_MASK; + value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); } env->cp15.cpacr_el1 = value; @@ -817,7 +794,7 @@ static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri) if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value &= ~(0xf << 20); + value = ~(R_CPACR_CP11_MASK | R_CPACR_CP10_MASK); } return value; } @@ -825,7 +802,8 @@ static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri) static void cpacr_reset(CPUARMState *env, const ARMCPRegInfo *ri) { - /* Call cpacr_write() so that we reset with the correct RAO bits set + /* + * Call cpacr_write() so that we reset with the correct RAO bits set * for our CPU features. */ cpacr_write(env, ri, 0); @@ -837,11 +815,11 @@ static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri, if (arm_feature(env, ARM_FEATURE_V8)) { /* Check if CPACR accesses are to be trapped to EL2 */ if (arm_current_el(env) == 1 && arm_is_el2_enabled(env) && - (env->cp15.cptr_el[2] & CPTR_TCPAC)) { + FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TCPAC)) { return CP_ACCESS_TRAP_EL2; /* Check if CPACR accesses are to be trapped to EL3 */ } else if (arm_current_el(env) < 3 && - (env->cp15.cptr_el[3] & CPTR_TCPAC)) { + FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, TCPAC)) { return CP_ACCESS_TRAP_EL3; } } @@ -853,7 +831,8 @@ static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { /* Check if CPTR accesses are set to trap to EL3 */ - if (arm_current_el(env) == 2 && (env->cp15.cptr_el[3] & CPTR_TCPAC)) { + if (arm_current_el(env) == 2 && + FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, TCPAC)) { return CP_ACCESS_TRAP_EL3; } @@ -865,7 +844,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { { .name = "MVA_prefetch", .cp = 15, .crn = 7, .crm = 13, .opc1 = 0, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NOP }, - /* We need to break the TB after ISB to execute self-modifying code + /* + * We need to break the TB after ISB to execute self-modifying code * correctly and also to take any pending interrupts immediately. * So use arm_cp_write_ignore() function instead of ARM_CP_NOP flag. */ @@ -880,7 +860,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ifar_s), offsetof(CPUARMState, cp15.ifar_ns) }, .resetvalue = 0, }, - /* Watchpoint Fault Address Register : should actually only be present + /* + * Watchpoint Fault Address Register : should actually only be present * for 1136, 1176, 11MPCore. */ { .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, @@ -889,7 +870,6 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1), .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read }, - REGINFO_SENTINEL }; typedef struct pm_event { @@ -965,16 +945,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) @@ -1008,17 +988,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, }, @@ -1086,7 +1066,8 @@ static bool event_supported(uint16_t number) static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { - /* Performance monitor registers user accessibility is controlled + /* + * Performance monitor registers user accessibility is controlled * by PMUSERENR. MDCR_EL2.TPM and MDCR_EL3.TPM allow configurable * trapping to EL2 or EL3 for other accesses. */ @@ -1165,14 +1146,24 @@ static CPAccessResult pmreg_access_ccntr(CPUARMState *env, return pmreg_access(env, ri, isread); } -/* Returns true if the counter (pass 31 for PMCCNTR) should count events using +/* + * 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. */ 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); @@ -1190,19 +1181,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) { @@ -1250,6 +1251,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, @@ -1262,8 +1300,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; } @@ -1272,7 +1309,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); } @@ -1298,16 +1335,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; @@ -1325,9 +1364,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); } @@ -1342,15 +1383,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 @@ -1418,8 +1466,8 @@ static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } - env->cp15.c9_pmcr &= ~PMCR_WRITEABLE_MASK; - env->cp15.c9_pmcr |= (value & PMCR_WRITEABLE_MASK); + env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK; + env->cp15.c9_pmcr |= (value & PMCR_WRITABLE_MASK); pmu_op_finish(env); } @@ -1428,6 +1476,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 */ @@ -1441,9 +1491,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; + + overflow_mask = pmevcntr_is_64_bit(env, i) ? + 1ULL << 63 : 1ULL << 31; - if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & INT32_MIN) { + if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & overflow_mask) { env->cp15.c9_pmovsr |= (1 << i); pmu_update_irq(env); } @@ -1467,7 +1520,8 @@ static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri) static void pmselr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - /* The value of PMSELR.SEL affects the behavior of PMXEVTYPER and + /* + * The value of PMSELR.SEL affects the behavior of PMXEVTYPER and * PMXEVCNTR. We allow [0..31] to be written to PMSELR here; in the * meanwhile, we check PMSELR.SEL when PMXEVTYPER and PMXEVCNTR are * accessed. @@ -1518,15 +1572,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, @@ -1574,7 +1632,8 @@ static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, env->cp15.c14_pmevtyper[counter] = value & PMXEVTYPER_MASK; pmevcntr_op_finish(env, counter); } - /* Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when + /* + * Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when * PMSELR value is equal to or greater than the number of implemented * counters, but not equal to 0x1f. We opt to behave as a RAZ/WI. */ @@ -1646,6 +1705,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; @@ -1665,10 +1728,16 @@ 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 - * are CONSTRAINED UNPREDICTABLE. */ + /* + * We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR + * are CONSTRAINED UNPREDICTABLE. + */ return 0; } } @@ -1743,7 +1812,8 @@ static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - /* Note that even though the AArch64 view of this register has bits + /* + * Note that even though the AArch64 view of this register has bits * [10:0] all RES0 we can only mask the bottom 5, to comply with the * architectural requirements for bits which are RES0 only in some * contexts. (ARMv8 would permit us to do no masking at all, but ARMv7 @@ -1755,16 +1825,26 @@ 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; - if (ri->state == ARM_CP_STATE_AA64) { - if (arm_feature(env, ARM_FEATURE_AARCH64) && - !cpu_isar_feature(aa64_aa32_el1, cpu)) { - value |= SCR_FW | SCR_AW; /* these two bits are RES1. */ - } - valid_mask &= ~SCR_NET; + /* + * Because SCR_EL3 is the "real" cpreg and SCR is the alias, reset always + * passes the reginfo for SCR_EL3, which has type ARM_CP_STATE_AA64. + * Instead, choose the format based on the mode of EL3. + */ + if (arm_el_is_aa64(env, 3)) { + value |= SCR_FW | SCR_AW; /* RES1 */ + valid_mask &= ~SCR_NET; /* RES0 */ + if (!cpu_isar_feature(aa64_aa32_el1, cpu) && + !cpu_isar_feature(aa64_aa32_el2, cpu)) { + value |= SCR_RW; /* RAO/WI */ + } + if (cpu_isar_feature(aa64_ras, cpu)) { + valid_mask |= SCR_TERR; + } if (cpu_isar_feature(aa64_lor, cpu)) { valid_mask |= SCR_TLOR; } @@ -1777,14 +1857,30 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= SCR_ATA; } + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + valid_mask |= SCR_ENSCXT; + } + if (cpu_isar_feature(aa64_doublefault, cpu)) { + valid_mask |= SCR_EASE | SCR_NMEA; + } + if (cpu_isar_feature(aa64_sme, cpu)) { + valid_mask |= SCR_ENTP2; + } + if (cpu_isar_feature(aa64_hcx, cpu)) { + valid_mask |= SCR_HXEN; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); + if (cpu_isar_feature(aa32_ras, cpu)) { + valid_mask |= SCR_TERR; + } } if (!arm_feature(env, ARM_FEATURE_EL2)) { valid_mask &= ~SCR_HCE; - /* On ARMv7, SMD (or SCD as it is called in v7) is only + /* + * On ARMv7, SMD (or SCD as it is called in v7) is only * supported if EL2 exists. The bit is UNK/SBZP when * EL2 is unavailable. In QEMU ARMv7, we force it to always zero * when EL2 is unavailable. @@ -1798,7 +1894,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) @@ -1810,11 +1921,12 @@ static void scr_reset(CPUARMState *env, const ARMCPRegInfo *ri) scr_write(env, ri, 0); } -static CPAccessResult access_aa64_tid2(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult access_tid4(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) { - if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TID2)) { + if (arm_current_el(env) == 1 && + (arm_hcr_el2_eff(env) & (HCR_TID2 | HCR_TID4))) { return CP_ACCESS_TRAP_EL2; } @@ -1825,7 +1937,8 @@ static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = env_archcpu(env); - /* Acquire the CSSELR index from the bank corresponding to the CCSIDR + /* + * Acquire the CSSELR index from the bank corresponding to the CCSIDR * bank */ uint32_t index = A32_BANKED_REG_GET(env, csselr, @@ -1867,7 +1980,12 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri) } } - /* External aborts are not possible in QEMU so A bit is always clear */ + if (hcr_el2 & HCR_AMO) { + if (cs->interrupt_request & CPU_INTERRUPT_VSERR) { + ret |= CPSR_A; + } + } + return ret; } @@ -1895,7 +2013,8 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */ { .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, .access = PL1_W, .type = ARM_CP_NOP }, - /* Performance monitors are implementation defined in v7, + /* + * Performance monitors are implementation defined in v7, * but with an ARM recommended set of registers, which we * follow. * @@ -1907,12 +2026,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, @@ -1922,11 +2041,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, @@ -2040,16 +2159,17 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .readfn = ccsidr_read, .type = ARM_CP_NO_RAW }, { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, .access = PL1_RW, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .writefn = csselr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.csselr_s), offsetof(CPUARMState, cp15.csselr_ns) } }, - /* Auxiliary ID register: this actually has an IMPDEF value but for now + /* + * Auxiliary ID register: this actually has an IMPDEF value but for now * just RAZ for all cores: */ { .name = "AIDR", .state = ARM_CP_STATE_BOTH, @@ -2057,7 +2177,8 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid1, .resetvalue = 0 }, - /* Auxiliary fault status registers: these also are IMPDEF, and we + /* + * Auxiliary fault status registers: these also are IMPDEF, and we * choose to RAZ/WI for all cores. */ { .name = "AFSR0_EL1", .state = ARM_CP_STATE_BOTH, @@ -2068,7 +2189,8 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1, .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* MAIR can just read-as-written because we don't implement caches + /* + * MAIR can just read-as-written because we don't implement caches * and so don't need to care about memory attributes. */ { .name = "MAIR_EL1", .state = ARM_CP_STATE_AA64, @@ -2080,10 +2202,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .opc0 = 3, .opc1 = 6, .crn = 10, .crm = 2, .opc2 = 0, .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[3]), .resetvalue = 0 }, - /* For non-long-descriptor page tables these are PRRR and NMRR; + /* + * For non-long-descriptor page tables these are PRRR and NMRR; * regardless they still act as reads-as-written for QEMU. */ - /* MAIR0/1 are defined separately from their 64-bit counterpart which + /* + * MAIR0/1 are defined separately from their 64-bit counterpart which * allows them to assign the correct fieldoffset based on the endianness * handled in the field definitions. */ @@ -2135,24 +2259,22 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3, .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, .writefn = tlbimvaa_write }, - REGINFO_SENTINEL }; static const ARMCPRegInfo v7mp_cp_reginfo[] = { /* 32 bit TLB invalidates, Inner Shareable */ { .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbiall_is_write }, { .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimva_is_write }, { .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbiasid_is_write }, { .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimvaa_is_write }, - REGINFO_SENTINEL }; static const ARMCPRegInfo pmovsset_cp_reginfo[] = { @@ -2170,7 +2292,6 @@ static const ARMCPRegInfo pmovsset_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr), .writefn = pmovsset_write, .raw_writefn = raw_write }, - REGINFO_SENTINEL }; static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -2211,7 +2332,6 @@ static const ARMCPRegInfo t2ee_cp_reginfo[] = { { .name = "TEEHBR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0, .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, teehbr), .accessfn = teehbr_access, .resetvalue = 0 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo v6k_cp_reginfo[] = { @@ -2226,11 +2346,11 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { .resetfn = arm_cp_reset_ignore }, { .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 3, .crn = 13, .crm = 0, - .access = PL0_R|PL1_W, + .access = PL0_R | PL1_W, .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el[0]), .resetvalue = 0}, { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3, - .access = PL0_R|PL1_W, + .access = PL0_R | PL1_W, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidruro_s), offsetoflow32(CPUARMState, cp15.tpidruro_ns) }, .resetfn = arm_cp_reset_ignore }, @@ -2243,7 +2363,6 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrprw_s), offsetoflow32(CPUARMState, cp15.tpidrprw_ns) }, .resetvalue = 0 }, - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -2251,7 +2370,8 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { - /* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero. + /* + * CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero. * Writable only at the highest implemented exception level. */ int el = arm_current_el(env); @@ -2410,7 +2530,8 @@ static CPAccessResult gt_stimer_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { - /* The AArch64 register view of the secure physical timer is + /* + * The AArch64 register view of the secure physical timer is * always accessible from EL3, and configurably accessible from * Secure EL1. */ @@ -2445,7 +2566,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx]; if (gt->ctl & 1) { - /* Timer enabled: calculate and set current ISTATUS, irq, and + /* + * Timer enabled: calculate and set current ISTATUS, irq, and * reset timer to when ISTATUS next has to change */ uint64_t offset = timeridx == GTIMER_VIRT ? @@ -2468,7 +2590,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) /* Next transition is when we hit cval */ nexttick = gt->cval + offset; } - /* Note that the desired next expiry time might be beyond the + /* + * Note that the desired next expiry time might be beyond the * signed-64-bit range of a QEMUTimer -- in this case we just * set the timer for as far in the future as possible. When the * timer expires we will reset the timer for any remaining period. @@ -2585,7 +2708,8 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, /* Enable toggled */ gt_recalc_timer(cpu, timeridx); } else if ((oldval ^ value) & 2) { - /* IMASK toggled: don't need to recalculate, + /* + * IMASK toggled: don't need to recalculate, * just set the interrupt line based on ISTATUS */ int irqstate = (oldval & 4) && !(value & 2); @@ -2629,9 +2753,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; @@ -2644,9 +2765,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; @@ -2902,7 +3020,8 @@ static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque) } static const ARMCPRegInfo generic_timer_cp_reginfo[] = { - /* Note that CNTFRQ is purely reads-as-written for the benefit + /* + * Note that CNTFRQ is purely reads-as-written for the benefit * of software; writing it doesn't actually change the timer frequency. * Our reset value matches the fixed frequency we implement the timer at. */ @@ -3065,7 +3184,8 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .readfn = gt_virt_redir_cval_read, .raw_readfn = raw_read, .writefn = gt_virt_redir_cval_write, .raw_writefn = raw_write, }, - /* Secure timer -- this is actually restricted to only EL3 + /* + * Secure timer -- this is actually restricted to only EL3 * and configurably Secure-EL1 via the accessfn. */ { .name = "CNTPS_TVAL_EL1", .state = ARM_CP_STATE_AA64, @@ -3091,7 +3211,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval), .writefn = gt_sec_cval_write, .raw_writefn = raw_write, }, - REGINFO_SENTINEL }; static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3105,7 +3224,8 @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri, #else -/* In user-mode most of the generic timer registers are inaccessible +/* + * In user-mode most of the generic timer registers are inaccessible * however modern kernels (4.12+) allow access to cntvct_el0 */ @@ -3113,7 +3233,8 @@ static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = env_archcpu(env); - /* Currently we have no support for QEMUTimer in linux-user so we + /* + * Currently we have no support for QEMUTimer in linux-user so we * can't call gt_get_countervalue(env), instead we directly * call the lower level functions. */ @@ -3132,7 +3253,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO, .readfn = gt_virt_cnt_read, }, - REGINFO_SENTINEL }; #endif @@ -3155,7 +3275,8 @@ static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { if (ri->opc2 & 4) { - /* The ATS12NSO* operations must trap to EL3 or EL2 if executed in + /* + * The ATS12NSO* operations must trap to EL3 or EL2 if executed in * Secure EL1 (which can only happen if EL3 is AArch64). * They are simply UNDEF if executed from NS EL1. * They function normally from EL2 or EL3. @@ -3175,20 +3296,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(!res.cacheattrs.is_s2_format); if (ret) { /* @@ -3294,12 +3418,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); @@ -3313,19 +3437,20 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, } } } else { - /* fsr is a DFSR/IFSR value for the short descriptor + /* + * fsr is a DFSR/IFSR value for the short descriptor * translation table format (with WnR always clear). * Convert it to a 32-bit PAR. */ 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 { @@ -3353,17 +3478,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: @@ -3374,14 +3499,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(); @@ -3390,16 +3516,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 @@ -3415,7 +3543,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 @@ -3441,42 +3570,46 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD; ARMMMUIdx mmu_idx; int secure = arm_is_secure_below_el3(env); + uint64_t hcr_el2 = arm_hcr_el2_eff(env); + bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE); switch (ri->opc2 & 6) { case 0: 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 = regime_e20 ? + ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN; } else { - mmu_idx = secure ? ARMMMUIdx_Stage1_SE1 : ARMMMUIdx_Stage1_E1; + mmu_idx = regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_Stage1_E1; } break; case 4: /* AT S1E2R, AT S1E2W */ - mmu_idx = secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2; + mmu_idx = hcr_el2 & HCR_E2H ? ARMMMUIdx_E20_2 : 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 = regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_Stage1_E0; break; case 4: /* AT S12E1R, AT S12E1W */ - mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_E10_1; + mmu_idx = regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E10_1; break; case 6: /* AT S12E0R, AT S12E0W */ - mmu_idx = secure ? ARMMMUIdx_SE10_0 : ARMMMUIdx_E10_0; + mmu_idx = regime_e20 ? ARMMMUIdx_E20_0 : 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(); @@ -3496,7 +3629,6 @@ static const ARMCPRegInfo vapa_cp_reginfo[] = { .access = PL1_W, .accessfn = ats_access, .writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC }, #endif - REGINFO_SENTINEL }; /* Return basic MPU access permission bits. */ @@ -3594,48 +3726,264 @@ static void pmsav7_rgnr_write(CPUARMState *env, const ARMCPRegInfo *ri, raw_write(env, ri, value); } -static const ARMCPRegInfo pmsav7_cp_reginfo[] = { - /* Reset for all these registers is handled in arm_cpu_reset(), - * because the PMSAv7 is also used by M-profile CPUs, which do - * not register cpregs but still need the state to be reset. - */ - { .name = "DRBAR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_NO_RAW, - .fieldoffset = offsetof(CPUARMState, pmsav7.drbar), - .readfn = pmsav7_read, .writefn = pmsav7_write, - .resetfn = arm_cp_reset_ignore }, - { .name = "DRSR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_NO_RAW, - .fieldoffset = offsetof(CPUARMState, pmsav7.drsr), - .readfn = pmsav7_read, .writefn = pmsav7_write, - .resetfn = arm_cp_reset_ignore }, - { .name = "DRACR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 4, - .access = PL1_RW, .type = ARM_CP_NO_RAW, - .fieldoffset = offsetof(CPUARMState, pmsav7.dracr), - .readfn = pmsav7_read, .writefn = pmsav7_write, - .resetfn = arm_cp_reset_ignore }, - { .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]), - .writefn = pmsav7_rgnr_write, - .resetfn = arm_cp_reset_ignore }, - REGINFO_SENTINEL -}; +static void prbar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); -static const ARMCPRegInfo pmsav5_cp_reginfo[] = { - { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_ALIAS, - .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap), - .readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, }, - { .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_ALIAS, - .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap), - .readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, }, - { .name = "DATA_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 2, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap), - .resetvalue = 0, }, - { .name = "INSN_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 3, + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ + env->pmsav8.rbar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]] = value; +} + +static uint64_t prbar_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return env->pmsav8.rbar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]]; +} + +static void prlar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ + env->pmsav8.rlar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]] = value; +} + +static uint64_t prlar_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return env->pmsav8.rlar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]]; +} + +static void prselr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + + /* + * Ignore writes that would select not implemented region. + * This is architecturally UNPREDICTABLE. + */ + if (value >= cpu->pmsav7_dregion) { + return; + } + + env->pmsav7.rnr[M_REG_NS] = value; +} + +static void hprbar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ + env->pmsav8.hprbar[env->pmsav8.hprselr] = value; +} + +static uint64_t hprbar_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return env->pmsav8.hprbar[env->pmsav8.hprselr]; +} + +static void hprlar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ + env->pmsav8.hprlar[env->pmsav8.hprselr] = value; +} + +static uint64_t hprlar_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return env->pmsav8.hprlar[env->pmsav8.hprselr]; +} + +static void hprenr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint32_t n; + uint32_t bit; + ARMCPU *cpu = env_archcpu(env); + + /* Ignore writes to unimplemented regions */ + int rmax = MIN(cpu->pmsav8r_hdregion, 32); + value &= MAKE_64BIT_MASK(0, rmax); + + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ + + /* Register alias is only valid for first 32 indexes */ + for (n = 0; n < rmax; ++n) { + bit = extract32(value, n, 1); + env->pmsav8.hprlar[n] = deposit32( + env->pmsav8.hprlar[n], 0, 1, bit); + } +} + +static uint64_t hprenr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint32_t n; + uint32_t result = 0x0; + ARMCPU *cpu = env_archcpu(env); + + /* Register alias is only valid for first 32 indexes */ + for (n = 0; n < MIN(cpu->pmsav8r_hdregion, 32); ++n) { + if (env->pmsav8.hprlar[n] & 0x1) { + result |= (0x1 << n); + } + } + return result; +} + +static void hprselr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + + /* + * Ignore writes that would select not implemented region. + * This is architecturally UNPREDICTABLE. + */ + if (value >= cpu->pmsav8r_hdregion) { + return; + } + + env->pmsav8.hprselr = value; +} + +static void pmsav8r_regn_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = env_archcpu(env); + uint8_t index = (extract32(ri->opc0, 0, 1) << 4) | + (extract32(ri->crm, 0, 3) << 1) | extract32(ri->opc2, 2, 1); + + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ + + if (ri->opc1 & 4) { + if (index >= cpu->pmsav8r_hdregion) { + return; + } + if (ri->opc2 & 0x1) { + env->pmsav8.hprlar[index] = value; + } else { + env->pmsav8.hprbar[index] = value; + } + } else { + if (index >= cpu->pmsav7_dregion) { + return; + } + if (ri->opc2 & 0x1) { + env->pmsav8.rlar[M_REG_NS][index] = value; + } else { + env->pmsav8.rbar[M_REG_NS][index] = value; + } + } +} + +static uint64_t pmsav8r_regn_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = env_archcpu(env); + uint8_t index = (extract32(ri->opc0, 0, 1) << 4) | + (extract32(ri->crm, 0, 3) << 1) | extract32(ri->opc2, 2, 1); + + if (ri->opc1 & 4) { + if (index >= cpu->pmsav8r_hdregion) { + return 0x0; + } + if (ri->opc2 & 0x1) { + return env->pmsav8.hprlar[index]; + } else { + return env->pmsav8.hprbar[index]; + } + } else { + if (index >= cpu->pmsav7_dregion) { + return 0x0; + } + if (ri->opc2 & 0x1) { + return env->pmsav8.rlar[M_REG_NS][index]; + } else { + return env->pmsav8.rbar[M_REG_NS][index]; + } + } +} + +static const ARMCPRegInfo pmsav8r_cp_reginfo[] = { + { .name = "PRBAR", + .cp = 15, .opc1 = 0, .crn = 6, .crm = 3, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .accessfn = access_tvm_trvm, + .readfn = prbar_read, .writefn = prbar_write }, + { .name = "PRLAR", + .cp = 15, .opc1 = 0, .crn = 6, .crm = 3, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .accessfn = access_tvm_trvm, + .readfn = prlar_read, .writefn = prlar_write }, + { .name = "PRSELR", .resetvalue = 0, + .cp = 15, .opc1 = 0, .crn = 6, .crm = 2, .opc2 = 1, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .writefn = prselr_write, + .fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]) }, + { .name = "HPRBAR", .resetvalue = 0, + .cp = 15, .opc1 = 4, .crn = 6, .crm = 3, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .readfn = hprbar_read, .writefn = hprbar_write }, + { .name = "HPRLAR", + .cp = 15, .opc1 = 4, .crn = 6, .crm = 3, .opc2 = 1, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .readfn = hprlar_read, .writefn = hprlar_write }, + { .name = "HPRSELR", .resetvalue = 0, + .cp = 15, .opc1 = 4, .crn = 6, .crm = 2, .opc2 = 1, + .access = PL2_RW, + .writefn = hprselr_write, + .fieldoffset = offsetof(CPUARMState, pmsav8.hprselr) }, + { .name = "HPRENR", + .cp = 15, .opc1 = 4, .crn = 6, .crm = 1, .opc2 = 1, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .readfn = hprenr_read, .writefn = hprenr_write }, +}; + +static const ARMCPRegInfo pmsav7_cp_reginfo[] = { + /* + * Reset for all these registers is handled in arm_cpu_reset(), + * because the PMSAv7 is also used by M-profile CPUs, which do + * not register cpregs but still need the state to be reset. + */ + { .name = "DRBAR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .fieldoffset = offsetof(CPUARMState, pmsav7.drbar), + .readfn = pmsav7_read, .writefn = pmsav7_write, + .resetfn = arm_cp_reset_ignore }, + { .name = "DRSR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .fieldoffset = offsetof(CPUARMState, pmsav7.drsr), + .readfn = pmsav7_read, .writefn = pmsav7_write, + .resetfn = arm_cp_reset_ignore }, + { .name = "DRACR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 4, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .fieldoffset = offsetof(CPUARMState, pmsav7.dracr), + .readfn = pmsav7_read, .writefn = pmsav7_write, + .resetfn = arm_cp_reset_ignore }, + { .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]), + .writefn = pmsav7_rgnr_write, + .resetfn = arm_cp_reset_ignore }, +}; + +static const ARMCPRegInfo pmsav5_cp_reginfo[] = { + { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_ALIAS, + .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap), + .readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, }, + { .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_ALIAS, + .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap), + .readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, }, + { .name = "DATA_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap), + .resetvalue = 0, }, + { .name = "INSN_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 3, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap), .resetvalue = 0, }, @@ -3670,22 +4018,23 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { { .name = "946_PRBS7", .cp = 15, .crn = 6, .crm = 7, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.c6_region[7]) }, - REGINFO_SENTINEL }; -static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) +static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - TCR *tcr = raw_ptr(env, ri); - int maskshift = extract32(value, 0, 3); + ARMCPU *cpu = env_archcpu(env); if (!arm_feature(env, ARM_FEATURE_V8)) { if (arm_feature(env, ARM_FEATURE_LPAE) && (value & TTBCR_EAE)) { - /* Pre ARMv8 bits [21:19], [15:14] and [6:3] are UNK/SBZP when - * using Long-desciptor translation table format */ + /* + * Pre ARMv8 bits [21:19], [15:14] and [6:3] are UNK/SBZP when + * using Long-descriptor translation table format + */ value &= ~((7 << 19) | (3 << 14) | (0xf << 3)); } else if (arm_feature(env, ARM_FEATURE_EL3)) { - /* In an implementation that includes the Security Extensions + /* + * In an implementation that includes the Security Extensions * TTBCR has additional fields PD0 [4] and PD1 [5] for * Short-descriptor translation table format. */ @@ -3695,55 +4044,24 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } - /* Update the masks corresponding to the TCR bank being written - * Note that we always calculate mask and base_mask, but - * they are only used for short-descriptor tables (ie if EAE is 0); - * for long-descriptor tables the TCR fields are used differently - * and the mask and base_mask values are meaningless. - */ - tcr->raw_tcr = value; - tcr->mask = ~(((uint32_t)0xffffffffu) >> maskshift); - tcr->base_mask = ~((uint32_t)0x3fffu >> maskshift); -} - -static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - ARMCPU *cpu = env_archcpu(env); - TCR *tcr = raw_ptr(env, ri); - if (arm_feature(env, ARM_FEATURE_LPAE)) { - /* With LPAE the TTBCR could result in a change of ASID + /* + * With LPAE the TTBCR could result in a change of ASID * via the TTBCR.A1 bit, so do a TLB flush. */ tlb_flush(CPU(cpu)); } - /* Preserve the high half of TCR_EL1, set via TTBCR2. */ - value = deposit64(tcr->raw_tcr, 0, 32, value); - vmsa_ttbcr_raw_write(env, ri, value); -} - -static void vmsa_ttbcr_reset(CPUARMState *env, const ARMCPRegInfo *ri) -{ - TCR *tcr = raw_ptr(env, ri); - - /* Reset both the TCR as well as the masks corresponding to the bank of - * the TCR being reset. - */ - tcr->raw_tcr = 0; - tcr->mask = 0; - tcr->base_mask = 0xffffc000u; + raw_write(env, ri, value); } static void vmsa_tcr_el12_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); - TCR *tcr = raw_ptr(env, ri); /* For AArch64 the A1 bit could result in a change of ASID, so TLB flush. */ tlb_flush(CPU(cpu)); - tcr->raw_tcr = value; + raw_write(env, ri, value); } static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3772,11 +4090,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); @@ -3790,20 +4103,12 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, /* * A change in VMID to the stage2 page table (Stage2) invalidates - * the combined stage 1&2 tlbs (EL10_1 and EL10_0). + * the stage2 and combined stage 1&2 tlbs (EL10_1 and EL10_0). */ - if (raw_read(env, ri) != value) { - 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); + if (extract64(raw_read(env, ri) ^ value, 48, 16) != 0) { + tlb_flush_by_mmuidx(cs, alle1_tlbmask(env)); } + raw_write(env, ri, value); } static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { @@ -3824,7 +4129,6 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo vmsa_cp_reginfo[] = { @@ -3848,19 +4152,19 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .accessfn = access_tvm_trvm, .writefn = vmsa_tcr_el12_write, - .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write, + .raw_writefn = raw_write, + .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[1]) }, { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_ALIAS, .writefn = vmsa_ttbcr_write, - .raw_writefn = vmsa_ttbcr_raw_write, - /* No offsetoflow32 -- pass the entire TCR to writefn/raw_writefn. */ - .bank_fieldoffsets = { offsetof(CPUARMState, cp15.tcr_el[3]), - offsetof(CPUARMState, cp15.tcr_el[1])} }, - REGINFO_SENTINEL + .raw_writefn = raw_write, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), + offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, }; -/* Note that unlike TTBCR, writing to TTBCR2 does not require flushing +/* + * Note that unlike TTBCR, writing to TTBCR2 does not require flushing * qemu tlbs nor adjusting cached masks. */ static const ARMCPRegInfo ttbcr2_reginfo = { @@ -3868,8 +4172,8 @@ static const ARMCPRegInfo ttbcr2_reginfo = { .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_ALIAS, .bank_fieldoffsets = { - offsetofhigh32(CPUARMState, cp15.tcr_el[3].raw_tcr), - offsetofhigh32(CPUARMState, cp15.tcr_el[1].raw_tcr), + offsetofhigh32(CPUARMState, cp15.tcr_el[3]), + offsetofhigh32(CPUARMState, cp15.tcr_el[1]), }, }; @@ -3898,7 +4202,8 @@ static void omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri, static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - /* On OMAP there are registers indicating the max/min index of dcache lines + /* + * On OMAP there are registers indicating the max/min index of dcache lines * containing a dirty line; cache flush operations have to reset these. */ env->cp15.c15_i_max = 0x000; @@ -3930,7 +4235,8 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { .crm = 8, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NO_RAW, .readfn = arm_cp_read_zero, .writefn = omap_wfi_write, }, - /* TODO: Peripheral port remap register: + /* + * TODO: Peripheral port remap register: * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt controller * base address at $rn & ~0xfff and map size of 0x200 << ($rn & 0xfff), * when MMU is off. @@ -3942,7 +4248,6 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { { .name = "C9", .cp = 15, .crn = 9, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void xscale_cpar_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3960,7 +4265,8 @@ static const ARMCPRegInfo xscale_cp_reginfo[] = { .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_xscaleauxcr), .resetvalue = 0, }, - /* XScale specific cache-lockdown: since we have no cache we NOP these + /* + * XScale specific cache-lockdown: since we have no cache we NOP these * and hope the guest does not really rely on cache behaviour. */ { .name = "XSCALE_LOCK_ICACHE_LINE", @@ -3975,11 +4281,11 @@ static const ARMCPRegInfo xscale_cp_reginfo[] = { { .name = "XSCALE_UNLOCK_DCACHE", .cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { - /* RAZ/WI the whole crn=15 space, when we don't have a more specific + /* + * RAZ/WI the whole crn=15 space, when we don't have a more specific * implementation of this implementation-defined space. * Ideally this should eventually disappear in favour of actually * implementing the correct behaviour for all cores. @@ -3989,7 +4295,6 @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_RAW | ARM_CP_OVERRIDE, .resetvalue = 0 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { @@ -3997,32 +4302,31 @@ static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { { .name = "CDSR", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW, .resetvalue = 0 }, - REGINFO_SENTINEL }; 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 }, /* The cache ops themselves: these all NOP for QEMU */ { .name = "IICR", .cp = 15, .crm = 5, .opc1 = 0, - .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_64BIT }, { .name = "IDCR", .cp = 15, .crm = 6, .opc1 = 0, - .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_64BIT }, { .name = "CDCR", .cp = 15, .crm = 12, .opc1 = 0, - .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + .access = PL0_W, .type = ARM_CP_NOP | ARM_CP_64BIT }, { .name = "PIR", .cp = 15, .crm = 12, .opc1 = 1, - .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + .access = PL0_W, .type = ARM_CP_NOP | ARM_CP_64BIT }, { .name = "PDR", .cp = 15, .crm = 12, .opc1 = 2, - .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, + .access = PL0_W, .type = ARM_CP_NOP | ARM_CP_64BIT }, { .name = "CIDCR", .cp = 15, .crm = 14, .opc1 = 0, - .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, - REGINFO_SENTINEL + .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_64BIT }, }; static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { - /* The cache test-and-clean instructions always return (1 << 30) + /* + * The cache test-and-clean instructions always return (1 << 30) * to indicate that there are no dirty cache lines. */ { .name = "TC_DCACHE", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 3, @@ -4031,7 +4335,6 @@ static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { { .name = "TCI_DCACHE", .cp = 15, .crn = 7, .crm = 14, .opc1 = 0, .opc2 = 3, .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW, .resetvalue = (1 << 30) }, - REGINFO_SENTINEL }; static const ARMCPRegInfo strongarm_cp_reginfo[] = { @@ -4040,7 +4343,6 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST | ARM_CP_OVERRIDE | ARM_CP_NO_RAW }, - REGINFO_SENTINEL }; static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -4060,7 +4362,8 @@ static uint64_t mpidr_read_val(CPUARMState *env) if (arm_feature(env, ARM_FEATURE_V7MP)) { mpidr |= (1U << 31); - /* Cores which are uniprocessor (non-coherent) + /* + * Cores which are uniprocessor (non-coherent) * but still implement the MP extensions set * bit 30. (For instance, Cortex-R5). */ @@ -4107,7 +4410,6 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) }, .writefn = vmsa_ttbr_write, }, - REGINFO_SENTINEL }; static uint64_t aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -4241,9 +4543,7 @@ static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env, return CP_ACCESS_OK; } -static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult do_cacheop_pou_access(CPUARMState *env, uint64_t hcrflags) { /* Cache invalidate/clean to Point of Unification... */ switch (arm_current_el(env)) { @@ -4254,8 +4554,8 @@ static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, } /* fall through */ case 1: - /* ... EL1 must trap to EL2 if HCR_EL2.TPU is set. */ - if (arm_hcr_el2_eff(env) & HCR_TPU) { + /* ... EL1 must trap to EL2 if relevant HCR_EL2 flags are set. */ + if (arm_hcr_el2_eff(env) & hcrflags) { return CP_ACCESS_TRAP_EL2; } break; @@ -4263,7 +4563,20 @@ static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, return CP_ACCESS_OK; } -/* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions +static CPAccessResult access_ticab(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + return do_cacheop_pou_access(env, HCR_TICAB | HCR_TPU); +} + +static CPAccessResult access_tocu(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + return do_cacheop_pou_access(env, HCR_TOCU | HCR_TPU); +} + +/* + * See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions * Page D4-1736 (DDI0487A.b) */ @@ -4281,11 +4594,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; } @@ -4293,7 +4601,7 @@ static int vae1_tlbmask(CPUARMState *env) static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx, uint64_t addr) { - uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; + uint64_t tcr = regime_tcr(env, mmu_idx); int tbi = aa64_va_parameter_tbi(tcr, mmu_idx); int select = extract64(addr, 55, 1); @@ -4312,10 +4620,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); } @@ -4341,37 +4645,12 @@ static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri, } } -static int alle1_tlbmask(CPUARMState *env) -{ - /* - * Note that the 'ALL' scope must invalidate both stage 1 and - * 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; - } -} - 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, @@ -4398,7 +4677,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, @@ -4424,13 +4703,14 @@ 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, uint64_t value) { - /* Invalidate by VA, EL2 + /* + * Invalidate by VA, EL2 * Currently handles both VAE2 and VALE2, since we don't support * flush-last-level-only. */ @@ -4444,7 +4724,8 @@ static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri, static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - /* Invalidate by VA, EL3 + /* + * Invalidate by VA, EL3 * Currently handles both VAE3 and VALE3, since we don't support * flush-last-level-only. */ @@ -4452,7 +4733,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, @@ -4469,7 +4750,8 @@ static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri, static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - /* Invalidate by VA, EL1&0 (AArch64 version). + /* + * Invalidate by VA, EL1&0 (AArch64 version). * Currently handles all of VAE1, VAAE1, VAALE1 and VALE1, * since we don't support flush-for-specific-ASID-only or * flush-last-level-only. @@ -4491,12 +4773,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, @@ -4504,37 +4784,94 @@ 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 -typedef struct { - uint64_t base; - uint64_t length; -} TLBIRange; +static int ipas2e1_tlbmask(CPUARMState *env, int64_t value) +{ + /* + * The MSB of value is the NS field, which only applies if SEL2 + * is implemented and SCR_EL3.NS is not set (i.e. in secure mode). + */ + return (value >= 0 + && cpu_isar_feature(aa64_sel2, env_archcpu(env)) + && arm_is_secure_below_el3(env) + ? ARMMMUIdxBit_Stage2_S + : ARMMMUIdxBit_Stage2); +} -static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx, - uint64_t value) +static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - unsigned int page_size_granule, page_shift, num, scale, exponent; - /* Extract one bit to represent the va selector in use. */ - uint64_t select = sextract64(value, 36, 1); - ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true); - TLBIRange ret = { }; + CPUState *cs = env_cpu(env); + int mask = ipas2e1_tlbmask(env, value); + uint64_t pageaddr = sextract64(value << 12, 0, 56); - page_size_granule = extract64(value, 46, 2); + if (tlb_force_broadcast(env)) { + tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask); + } else { + tlb_flush_page_by_mmuidx(cs, pageaddr, mask); + } +} + +static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + CPUState *cs = env_cpu(env); + int mask = ipas2e1_tlbmask(env, value); + uint64_t pageaddr = sextract64(value << 12, 0, 56); + + tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask); +} + +#ifdef TARGET_AARCH64 +typedef struct { + uint64_t base; + 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) +{ + unsigned int page_size_granule, page_shift, num, scale, exponent; + /* Extract one bit to represent the va selector in use. */ + 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; @@ -4613,8 +4950,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, @@ -4660,8 +4996,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, @@ -4675,7 +5010,21 @@ 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); +} + +static void tlbi_aa64_ripas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + do_rvae_write(env, value, ipas2e1_tlbmask(env, value), + tlb_force_broadcast(env)); +} + +static void tlbi_aa64_ripas2e1is_write(CPUARMState *env, + const ARMCPRegInfo *ri, + uint64_t value) +{ + do_rvae_write(env, value, ipas2e1_tlbmask(env, value), true); } #endif @@ -4723,7 +5072,8 @@ static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { if (!(env->pstate & PSTATE_SP)) { - /* Access to SP_EL0 is undefined if it's being used as + /* + * Access to SP_EL0 is undefined if it's being used as * the stack pointer. */ return CP_ACCESS_TRAP_UNCATEGORIZED; @@ -4763,7 +5113,8 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, } if (raw_read(env, ri) == value) { - /* Skip the TLB flush if nothing actually changed; Linux likes + /* + * Skip the TLB flush if nothing actually changed; Linux likes * to do a lot of pointless SCTLR writes. */ return; @@ -4785,26 +5136,54 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } -static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) +static void mdcr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) { - return CP_ACCESS_TRAP_FP_EL2; + /* + * 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); } - if (env->cp15.cptr_el[3] & CPTR_TFP) { - return CP_ACCESS_TRAP_FP_EL3; + env->cp15.mdcr_el3 = value; + if (pmu_op) { + pmu_op_finish(env); } - return CP_ACCESS_OK; } 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[] = { - /* Minimal set of EL0-visible registers. This will need to be expanded + /* + * Minimal set of EL0-visible registers. This will need to be expanded * significantly for system emulation of AArch64 CPUs. */ { .name = "NZCV", .state = ARM_CP_STATE_AA64, @@ -4843,15 +5222,15 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "IC_IALLUIS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_ticab }, { .name = "IC_IALLU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_tocu }, { .name = "IC_IVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 5, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_tocu }, { .name = "DC_IVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, .access = PL1_W, .accessfn = aa64_cacheop_poc_access, @@ -4869,7 +5248,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DC_CVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 11, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_tocu }, { .name = "DC_CIVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, @@ -4880,27 +5259,27 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { /* TLBI operations */ { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0, @@ -4928,10 +5307,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ipas2e1is_write }, { .name = "TLBI_IPAS2LE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ipas2e1is_write }, { .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4, .access = PL2_W, .type = ARM_CP_NO_RAW, @@ -4942,10 +5323,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbi_aa64_alle1is_write }, { .name = "TLBI_IPAS2E1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ipas2e1_write }, { .name = "TLBI_IPAS2LE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ipas2e1_write }, { .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4, .access = PL2_W, .type = ARM_CP_NO_RAW, @@ -5006,10 +5389,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { #endif /* TLB invalidate last level of translation table walk */ { .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimva_is_write }, { .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimvaa_is_write }, { .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5, .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, @@ -5026,25 +5409,29 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbimva_hyp_is_write }, { .name = "TLBIIPAS2", .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL2_W }, + .type = ARM_CP_NO_RAW, .access = PL2_W, + .writefn = tlbiipas2_hyp_write }, { .name = "TLBIIPAS2IS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL2_W }, + .type = ARM_CP_NO_RAW, .access = PL2_W, + .writefn = tlbiipas2is_hyp_write }, { .name = "TLBIIPAS2L", .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5, - .type = ARM_CP_NOP, .access = PL2_W }, + .type = ARM_CP_NO_RAW, .access = PL2_W, + .writefn = tlbiipas2_hyp_write }, { .name = "TLBIIPAS2LIS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5, - .type = ARM_CP_NOP, .access = PL2_W }, + .type = ARM_CP_NO_RAW, .access = PL2_W, + .writefn = tlbiipas2is_hyp_write }, /* 32 bit cache operations */ { .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_ticab }, { .name = "BPIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "ICIALLU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tocu }, { .name = "ICIMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tocu }, { .name = "BPIALL", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "BPIMVA", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 7, @@ -5058,7 +5445,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCCSW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 11, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tocu }, { .name = "DCCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_poc_access }, { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, @@ -5079,7 +5466,8 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) }, - /* We rely on the access checks not allowing the guest to write to the + /* + * We rely on the access checks not allowing the guest to write to the * state field when SPSel indicates that it's being used as the stack * pointer. */ @@ -5090,7 +5478,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, @@ -5098,17 +5486,17 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write }, { .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0, - .type = ARM_CP_ALIAS, - .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]), - .access = PL2_RW, .accessfn = fpexc32_access }, + .access = PL2_RW, + .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP, + .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) }, { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0, - .access = PL2_RW, .resetvalue = 0, + .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP, .writefn = dacr_write, .raw_writefn = raw_write, .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) }, { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1, - .access = PL2_RW, .resetvalue = 0, + .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP, .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) }, { .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, @@ -5131,135 +5519,17 @@ 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, .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) }, - REGINFO_SENTINEL -}; - -/* Used to describe the behaviour of EL2 regs when EL2 does not exist. */ -static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { - { .name = "VBAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0, - .access = PL2_RW, - .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore }, - { .name = "HCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HACR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 7, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPTR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "HMAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "AMAIR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 3, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "HAMAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 10, .crm = 3, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "AFSR0_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "AFSR1_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 1, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "VTCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "VTTBR", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 6, .crm = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, - .access = PL2_RW, .accessfn = access_tda, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "FAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HIFAR", .state = ARM_CP_STATE_AA32, - .type = ARM_CP_CONST, - .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 2, - .access = PL2_RW, .resetvalue = 0 }, - REGINFO_SENTINEL -}; - -/* Ditto, but for registers which exist in ARMv8 but not v7 */ -static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = { - { .name = "HCR2", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) @@ -5275,7 +5545,8 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (arm_feature(env, ARM_FEATURE_EL3)) { valid_mask &= ~HCR_HCD; } else if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) { - /* Architecturally HCR.TSC is RES0 if EL3 is not implemented. + /* + * Architecturally HCR.TSC is RES0 if EL3 is not implemented. * However, if we're using the SMC PSCI conduit then QEMU is * effectively acting like EL3 firmware and so the guest at * EL2 should retain the ability to prevent EL1 from being @@ -5289,6 +5560,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_vh, cpu)) { valid_mask |= HCR_E2H; } + if (cpu_isar_feature(aa64_ras, cpu)) { + valid_mask |= HCR_TERR | HCR_TEA; + } if (cpu_isar_feature(aa64_lor, cpu)) { valid_mask |= HCR_TLOR; } @@ -5298,6 +5572,18 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= HCR_ATA | HCR_DCT | HCR_TID5; } + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + valid_mask |= HCR_ENSCXT; + } + if (cpu_isar_feature(aa64_fwb, cpu)) { + valid_mask |= HCR_FWB; + } + } + + if (cpu_isar_feature(any_evt, cpu)) { + valid_mask |= HCR_TTLBIS | HCR_TTLBOS | HCR_TICAB | HCR_TOCU | HCR_TID4; + } else if (cpu_isar_feature(any_half_evt, cpu)) { + valid_mask |= HCR_TICAB | HCR_TOCU | HCR_TID4; } /* Clear RES0 bits. */ @@ -5309,8 +5595,10 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) * HCR_PTW forbids certain page-table setups * HCR_DC disables stage1 and enables stage2 translation * HCR_DCT enables tagging on (disabled) stage1 translation + * HCR_FWB changes the interpretation of stage2 descriptor bits */ - if ((env->cp15.hcr_el2 ^ value) & (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT)) { + if ((env->cp15.hcr_el2 ^ value) & + (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB)) { tlb_flush(CPU(cpu)); } env->cp15.hcr_el2 = value; @@ -5329,6 +5617,7 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) g_assert(qemu_mutex_iothread_locked()); arm_cpu_update_virq(cpu); arm_cpu_update_vfiq(cpu); + arm_cpu_update_vserr(cpu); } static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) @@ -5353,15 +5642,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 @@ -5420,6 +5709,85 @@ 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(). + */ +bool el_is_in_host(CPUARMState *env, int el) +{ + uint64_t mask; + + /* + * Since we only care about E2H and TGE, we can skip arm_hcr_el2_eff(). + * Perform the simplest bit tests first, and validate EL2 afterward. + */ + if (el & 1) { + return false; /* EL1 or EL3 */ + } + + /* + * Note that hcr_write() checks isar_feature_aa64_vh(), + * aka HaveVirtHostExt(), in allowing HCR_E2H to be set. + */ + mask = el ? HCR_E2H : HCR_E2H | HCR_TGE; + if ((env->cp15.hcr_el2 & mask) != mask) { + return false; + } + + /* TGE and/or E2H set: double check those bits are currently legal. */ + return arm_is_el2_enabled(env) && arm_el_is_aa64(env, 2); +} + +static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint64_t valid_mask = 0; + + /* No features adding bits to HCRX are implemented. */ + + /* Clear RES0 bits. */ + env->cp15.hcrx_el2 = value & valid_mask; +} + +static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_HXEN)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo hcrx_el2_reginfo = { + .name = "HCRX_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 2, + .access = PL2_RW, .writefn = hcrx_write, .accessfn = access_hxen, + .fieldoffset = offsetof(CPUARMState, cp15.hcrx_el2), +}; + +/* Return the effective value of HCRX_EL2. */ +uint64_t arm_hcrx_el2_eff(CPUARMState *env) +{ + /* + * The bits in this register behave as 0 for all purposes other than + * direct reads of the register if: + * - EL2 is not enabled in the current security state, + * - SCR_EL3.HXEn is 0. + */ + if (!arm_is_el2_enabled(env) + || (arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_HXEN))) { + return 0; + } + return env->cp15.hcrx_el2; +} + static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -5429,8 +5797,8 @@ static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value &= ~(0x3 << 10); - value |= env->cp15.cptr_el[2] & (0x3 << 10); + uint64_t mask = R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; + value = (value & ~mask) | (env->cp15.cptr_el[2] & mask); } env->cp15.cptr_el[2] = value; } @@ -5445,7 +5813,7 @@ static uint64_t cptr_el2_read(CPUARMState *env, const ARMCPRegInfo *ri) if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value |= 0x3 << 10; + value |= R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; } return value; } @@ -5527,19 +5895,16 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { { .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2, .access = PL2_RW, .writefn = vmsa_tcr_el12_write, - /* no .raw_writefn or .resetfn needed as we never use mask/base_mask */ .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[2]) }, { .name = "VTCR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, .type = ARM_CP_ALIAS, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) }, + .fieldoffset = offsetoflow32(CPUARMState, cp15.vtcr_el2) }, { .name = "VTCR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, .access = PL2_RW, - /* no .writefn needed as this can't cause an ASID change; - * no .raw_writefn or .resetfn needed as we never use mask/base_mask - */ + /* no .writefn needed as this can't cause an ASID change */ .fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) }, { .name = "VTTBR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 6, .crm = 2, @@ -5588,42 +5953,46 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .writefn = tlbimva_hyp_is_write }, { .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2_write }, { .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2_write }, { .name = "TLBI_VALE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2_write }, { .name = "TLBI_ALLE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2is_write }, { .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_VALE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, #ifndef CONFIG_USER_ONLY - /* Unlike the other EL2-related AT operations, these must + /* + * Unlike the other EL2-related AT operations, these must * UNDEF from EL3 if EL2 is not implemented, which is why we * define them here rather than with the rest of the AT ops. */ { .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF, + .writefn = ats_write64 }, { .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, - /* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF, + .writefn = ats_write64 }, + /* + * The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE * if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3 * with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose * to behave as if SCR.NS was 1. @@ -5636,7 +6005,8 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC }, { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, - /* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the + /* + * ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the * reset values as IMPDEF. We choose to reset to 3 to comply with * both ARMv7 and ARMv8. */ @@ -5673,13 +6043,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .resetvalue = 0, .writefn = gt_hyp_ctl_write, .raw_writefn = raw_write }, #endif - /* The only field of MDCR_EL2 that has a defined architectural reset value - * is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N. - */ - { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, - .access = PL2_RW, .resetvalue = PMCR_NUM_COUNTERS, - .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), }, { .name = "HPFAR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, .access = PL2_RW, .accessfn = access_el3_aa32ns, @@ -5692,7 +6055,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) }, - REGINFO_SENTINEL }; static const ARMCPRegInfo el2_v8_cp_reginfo[] = { @@ -5702,7 +6064,6 @@ static const ARMCPRegInfo el2_v8_cp_reginfo[] = { .access = PL2_RW, .fieldoffset = offsetofhigh32(CPUARMState, cp15.hcr_el2), .writefn = hcr_writehigh }, - REGINFO_SENTINEL }; static CPAccessResult sel2_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -5723,13 +6084,13 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2, .access = PL2_RW, .accessfn = sel2_access, .fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) }, - REGINFO_SENTINEL }; static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { - /* The NSACR is RW at EL3, and RO for NS EL1 and NS EL2. + /* + * The NSACR is RW at EL3, and RO for NS EL1 and NS EL2. * At Secure EL1 it traps to EL3 or EL2. */ if (arm_current_el(env) == 3) { @@ -5777,12 +6138,8 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { { .name = "TCR_EL3", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2, .access = PL3_RW, - /* no .writefn needed as this can't cause an ASID change; - * we must provide a .raw_writefn and .resetfn because we handle - * reset and migration for the AArch32 TTBCR(S), which might be - * using mask and base_mask. - */ - .resetfn = vmsa_ttbcr_reset, .raw_writefn = vmsa_ttbcr_raw_write, + /* no .writefn needed as this can't cause an ASID change */ + .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[3]) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, @@ -5849,7 +6206,6 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 5, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae3_write }, - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -5946,10 +6302,16 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) */ { K(3, 0, 1, 2, 0), K(3, 4, 1, 2, 0), K(3, 5, 1, 2, 0), "ZCR_EL1", "ZCR_EL2", "ZCR_EL12", isar_feature_aa64_sve }, + { K(3, 0, 1, 2, 6), K(3, 4, 1, 2, 6), K(3, 5, 1, 2, 6), + "SMCR_EL1", "SMCR_EL2", "SMCR_EL12", isar_feature_aa64_sme }, { K(3, 0, 5, 6, 0), K(3, 4, 5, 6, 0), K(3, 5, 5, 6, 0), "TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte }, + { K(3, 0, 13, 0, 7), K(3, 4, 13, 0, 7), K(3, 5, 13, 0, 7), + "SCXTNUM_EL1", "SCXTNUM_EL2", "SCXTNUM_EL12", + isar_feature_aa64_scxtnum }, + /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */ /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */ }; @@ -5959,14 +6321,17 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) for (i = 0; i < ARRAY_SIZE(aliases); i++) { const struct E2HAlias *a = &aliases[i]; - ARMCPRegInfo *src_reg, *dst_reg; + ARMCPRegInfo *src_reg, *dst_reg, *new_reg; + bool ok; if (a->feature && !a->feature(&cpu->isar)) { continue; } - src_reg = g_hash_table_lookup(cpu->cp_regs, &a->src_key); - dst_reg = g_hash_table_lookup(cpu->cp_regs, &a->dst_key); + src_reg = g_hash_table_lookup(cpu->cp_regs, + (gpointer)(uintptr_t)a->src_key); + dst_reg = g_hash_table_lookup(cpu->cp_regs, + (gpointer)(uintptr_t)a->dst_key); g_assert(src_reg != NULL); g_assert(dst_reg != NULL); @@ -5978,19 +6343,16 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) g_assert(src_reg->opaque == NULL); /* Create alias before redirection so we dup the right data. */ - if (a->new_key) { - ARMCPRegInfo *new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo)); - uint32_t *new_key = g_memdup(&a->new_key, sizeof(uint32_t)); - bool ok; + new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo)); - new_reg->name = a->new_name; - new_reg->type |= ARM_CP_ALIAS; - /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ - new_reg->access &= PL2_RW | PL3_RW; + new_reg->name = a->new_name; + new_reg->type |= ARM_CP_ALIAS; + /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ + new_reg->access &= PL2_RW | PL3_RW; - ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg); - g_assert(ok); - } + ok = g_hash_table_insert(cpu->cp_regs, + (gpointer)(uintptr_t)a->new_key, new_reg); + g_assert(ok); src_reg->opaque = dst_reg; src_reg->orig_readfn = src_reg->readfn ?: raw_read; @@ -6040,127 +6402,102 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } -static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) +/* + * Check for traps to RAS registers, which are controlled + * by HCR_EL2.TERR and SCR_EL3.TERR. + */ +static CPAccessResult access_terr(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { - /* Writes to OSLAR_EL1 may update the OS lock status, which can be - * read via a bit in OSLSR_EL1. - */ - int oslock; + int el = arm_current_el(env); - if (ri->state == ARM_CP_STATE_AA32) { - oslock = (value == 0xC5ACCE55); - } else { - oslock = value & 1; + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_TERR)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_TERR)) { + return CP_ACCESS_TRAP_EL3; } + return CP_ACCESS_OK; +} + +static uint64_t disr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + int el = arm_current_el(env); - env->cp15.oslsr_el1 = deposit32(env->cp15.oslsr_el1, 1, 1, oslock); + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_AMO)) { + return env->cp15.vdisr_el2; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_EA)) { + return 0; /* RAZ/WI */ + } + return env->cp15.disr_el1; } -static const ARMCPRegInfo debug_cp_reginfo[] = { - /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped - * debug components. The AArch64 version of DBGDRAR is named MDRAR_EL1; - * unlike DBGDRAR it is never accessible from EL0. - * DBGDSAR is deprecated and must RAZ from v8 anyway, so it has no AArch64 - * accessor. - */ - { .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL0_R, .accessfn = access_tdra, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, - .access = PL1_R, .accessfn = access_tdra, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL0_R, .accessfn = access_tdra, - .type = ARM_CP_CONST, .resetvalue = 0 }, - /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */ - { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, - .access = PL1_RW, .accessfn = access_tda, - .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), - .resetvalue = 0 }, - /* - * MDCCSR_EL0[30:29] map to EDSCR[30:29]. Simply RAZ as the external - * Debug Communication Channel is not implemented. - */ - { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64, - .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0, - .access = PL0_R, .accessfn = access_tda, - .type = ARM_CP_CONST, .resetvalue = 0 }, - /* - * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as - * it is unlikely a guest will care. - * We don't implement the configurable EL0 access. - */ - { .name = "DBGDSCRint", .state = ARM_CP_STATE_AA32, - .cp = 14, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0, - .type = ARM_CP_ALIAS, - .access = PL1_R, .accessfn = access_tda, - .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), }, - { .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4, - .access = PL1_W, .type = ARM_CP_NO_RAW, - .accessfn = access_tdosa, - .writefn = oslar_write }, - { .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4, - .access = PL1_R, .resetvalue = 10, - .accessfn = access_tdosa, - .fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) }, - /* Dummy OSDLR_EL1: 32-bit Linux will read this */ - { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4, - .access = PL1_RW, .accessfn = access_tdosa, - .type = ARM_CP_NOP }, - /* Dummy DBGVCR: Linux wants to clear this on startup, but we don't - * implement vector catch debug events yet. - */ - { .name = "DBGVCR", - .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, - .access = PL1_RW, .accessfn = access_tda, - .type = ARM_CP_NOP }, - /* Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor - * to save and restore a 32-bit guest's DBGVCR) - */ - { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0, - .access = PL2_RW, .accessfn = access_tda, - .type = ARM_CP_NOP }, - /* Dummy MDCCINT_EL1, since we don't implement the Debug Communications - * Channel but Linux may try to access this register. The 32-bit - * alias is DBGDCCINT. - */ - { .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, - .access = PL1_RW, .accessfn = access_tda, - .type = ARM_CP_NOP }, - REGINFO_SENTINEL -}; +static void disr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_AMO)) { + env->cp15.vdisr_el2 = val; + return; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_EA)) { + return; /* RAZ/WI */ + } + env->cp15.disr_el1 = val; +} -static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { - /* 64 bit access versions of the (dummy) debug registers */ - { .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0, - .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0, - .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 }, - REGINFO_SENTINEL +/* + * Minimal RAS implementation with no Error Records. + * Which means that all of the Error Record registers: + * ERXADDR_EL1 + * ERXCTLR_EL1 + * ERXFR_EL1 + * ERXMISC0_EL1 + * ERXMISC1_EL1 + * ERXMISC2_EL1 + * ERXMISC3_EL1 + * ERXPFGCDN_EL1 (RASv1p1) + * ERXPFGCTL_EL1 (RASv1p1) + * ERXPFGF_EL1 (RASv1p1) + * ERXSTATUS_EL1 + * and + * ERRSELR_EL1 + * may generate UNDEFINED, which is the effect we get by not + * listing them at all. + */ +static const ARMCPRegInfo minimal_ras_reginfo[] = { + { .name = "DISR_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 1, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.disr_el1), + .readfn = disr_read, .writefn = disr_write, .raw_writefn = raw_write }, + { .name = "ERRIDR_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 3, .opc2 = 0, + .access = PL1_R, .accessfn = access_terr, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vdisr_el2) }, + { .name = "VSESR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) }, }; -/* Return the exception level to which exceptions should be taken - * via SVEAccessTrap. If an exception should be routed through - * AArch64.AdvSIMDFPAccessTrap, return 0; fp_exception_el should - * take care of raising that exception. - * C.f. the ARM pseudocode function CheckSVEEnabled. +/* + * Return the exception level to which exceptions should be taken + * via SVEAccessTrap. This excludes the check for whether the exception + * should be routed through AArch64.AdvSIMDFPAccessTrap. That can easily + * be found by testing 0 < fp_exception_el < sve_exception_el. + * + * C.f. the ARM pseudocode function CheckSVEEnabled. Note that the + * pseudocode does *not* separate out the FP trap checks, but has them + * all in one function. */ int sve_exception_el(CPUARMState *env, int el) { #ifndef CONFIG_USER_ONLY - uint64_t hcr_el2 = arm_hcr_el2_eff(env); - - if (el <= 1 && (hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - /* Check CPACR.ZEN. */ - switch (extract32(env->cp15.cpacr_el1, 16, 2)) { + if (el <= 1 && !el_is_in_host(env, el)) { + switch (FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, ZEN)) { case 1: if (el != 0) { break; @@ -6168,12 +6505,48 @@ int sve_exception_el(CPUARMState *env, int el) /* fall through */ case 0: case 2: - /* route_to_el2 */ - return hcr_el2 & HCR_TGE ? 2 : 1; + return 1; + } + } + + if (el <= 2 && arm_is_el2_enabled(env)) { + /* CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). */ + if (env->cp15.hcr_el2 & HCR_E2H) { + switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, ZEN)) { + case 1: + if (el != 0 || !(env->cp15.hcr_el2 & HCR_TGE)) { + break; + } + /* fall through */ + case 0: + case 2: + return 2; + } + } else { + if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TZ)) { + return 2; + } } + } + + /* CPTR_EL3. Since EZ is negative we must check for EL3. */ + if (arm_feature(env, ARM_FEATURE_EL3) + && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, EZ)) { + return 3; + } +#endif + return 0; +} - /* Check CPACR.FPEN. */ - switch (extract32(env->cp15.cpacr_el1, 20, 2)) { +/* + * Return the exception level to which exceptions should be taken for SME. + * C.f. the ARM pseudocode function CheckSMEAccess. + */ +int sme_exception_el(CPUARMState *env, int el) +{ +#ifndef CONFIG_USER_ONLY + if (el <= 1 && !el_is_in_host(env, el)) { + switch (FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, SMEN)) { case 1: if (el != 0) { break; @@ -6181,19 +6554,16 @@ int sve_exception_el(CPUARMState *env, int el) /* fall through */ case 0: case 2: - return 0; + return 1; } } - /* - * CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). - */ - if (el <= 2) { - if (hcr_el2 & HCR_E2H) { - /* Check CPTR_EL2.ZEN. */ - switch (extract32(env->cp15.cptr_el[2], 16, 2)) { + if (el <= 2 && arm_is_el2_enabled(env)) { + /* CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). */ + if (env->cp15.hcr_el2 & HCR_E2H) { + switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, SMEN)) { case 1: - if (el != 0 || !(hcr_el2 & HCR_TGE)) { + if (el != 0 || !(env->cp15.hcr_el2 & HCR_TGE)) { break; } /* fall through */ @@ -6201,78 +6571,93 @@ int sve_exception_el(CPUARMState *env, int el) case 2: return 2; } - - /* Check CPTR_EL2.FPEN. */ - switch (extract32(env->cp15.cptr_el[2], 20, 2)) { - case 1: - if (el == 2 || !(hcr_el2 & HCR_TGE)) { - break; - } - /* fall through */ - case 0: - case 2: - return 0; - } - } else if (arm_is_el2_enabled(env)) { - if (env->cp15.cptr_el[2] & CPTR_TZ) { + } else { + if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TSM)) { return 2; } - if (env->cp15.cptr_el[2] & CPTR_TFP) { - return 0; - } } } - /* CPTR_EL3. Since EZ is negative we must check for EL3. */ + /* CPTR_EL3. Since ESM is negative we must check for EL3. */ if (arm_feature(env, ARM_FEATURE_EL3) - && !(env->cp15.cptr_el[3] & CPTR_EZ)) { + && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) { return 3; } #endif return 0; } -uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len) +/* This corresponds to the ARM pseudocode function IsFullA64Enabled(). */ +static bool sme_fa64(CPUARMState *env, int el) { - uint32_t end_len; - - start_len = MIN(start_len, ARM_MAX_VQ - 1); - end_len = start_len; + if (!cpu_isar_feature(aa64_sme_fa64, env_archcpu(env))) { + return false; + } - if (!test_bit(start_len, cpu->sve_vq_map)) { - end_len = find_last_bit(cpu->sve_vq_map, start_len); - assert(end_len < start_len); + if (el <= 1 && !el_is_in_host(env, el)) { + if (!FIELD_EX64(env->vfp.smcr_el[1], SMCR, FA64)) { + return false; + } + } + if (el <= 2 && arm_is_el2_enabled(env)) { + if (!FIELD_EX64(env->vfp.smcr_el[2], SMCR, FA64)) { + return false; + } + } + if (arm_feature(env, ARM_FEATURE_EL3)) { + if (!FIELD_EX64(env->vfp.smcr_el[3], SMCR, FA64)) { + return false; + } } - return end_len; + + return true; } /* * Given that SVE is enabled, return the vector length for EL. */ -uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) +uint32_t sve_vqm1_for_el_sm(CPUARMState *env, int el, bool sm) { ARMCPU *cpu = env_archcpu(env); - uint32_t zcr_len = cpu->sve_max_vq - 1; + uint64_t *cr = env->vfp.zcr_el; + uint32_t map = cpu->sve_vq.map; + uint32_t len = ARM_MAX_VQ - 1; - if (el <= 1 && - (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); + if (sm) { + cr = env->vfp.smcr_el; + map = cpu->sme_vq.map; + } + + if (el <= 1 && !el_is_in_host(env, el)) { + len = MIN(len, 0xf & (uint32_t)cr[1]); } if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]); + len = MIN(len, 0xf & (uint32_t)cr[2]); } if (arm_feature(env, ARM_FEATURE_EL3)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]); + len = MIN(len, 0xf & (uint32_t)cr[3]); + } + + map &= MAKE_64BIT_MASK(0, len + 1); + if (map != 0) { + return 31 - clz32(map); } - return aarch64_sve_zcr_get_valid_len(cpu, zcr_len); + /* Bit 0 is always set for Normal SVE -- not so for Streaming SVE. */ + assert(sm); + return ctz32(cpu->sme_vq.map); +} + +uint32_t sve_vqm1_for_el(CPUARMState *env, int el) +{ + return sve_vqm1_for_el_sm(env, el, FIELD_EX64(env->svcr, SVCR, SM)); } static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { int cur_el = arm_current_el(env); - int old_len = sve_zcr_len_for_el(env, cur_el); + int old_len = sve_vqm1_for_el(env, cur_el); int new_len; /* Bits other than [3:0] are RAZ/WI. */ @@ -6283,386 +6668,152 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, * Because we arrived here, we know both FP and SVE are enabled; * otherwise we would have trapped access to the ZCR_ELn register. */ - new_len = sve_zcr_len_for_el(env, cur_el); + new_len = sve_vqm1_for_el(env, cur_el); if (new_len < old_len) { aarch64_sve_narrow_vq(env, new_len + 1); } } -static const ARMCPRegInfo zcr_el1_reginfo = { - .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), - .writefn = zcr_write, .raw_writefn = raw_write -}; - -static const ARMCPRegInfo zcr_el2_reginfo = { - .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[2]), - .writefn = zcr_write, .raw_writefn = raw_write -}; - -static const ARMCPRegInfo zcr_no_el2_reginfo = { - .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_SVE, - .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore -}; - -static const ARMCPRegInfo zcr_el3_reginfo = { - .name = "ZCR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL3_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[3]), - .writefn = zcr_write, .raw_writefn = raw_write +static const ARMCPRegInfo zcr_reginfo[] = { + { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), + .writefn = zcr_write, .raw_writefn = raw_write }, + { .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[2]), + .writefn = zcr_write, .raw_writefn = raw_write }, + { .name = "ZCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL3_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[3]), + .writefn = zcr_write, .raw_writefn = raw_write }, }; -void hw_watchpoint_update(ARMCPU *cpu, int n) +#ifdef TARGET_AARCH64 +static CPAccessResult access_tpidr2(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { - CPUARMState *env = &cpu->env; - vaddr len = 0; - vaddr wvr = env->cp15.dbgwvr[n]; - uint64_t wcr = env->cp15.dbgwcr[n]; - int mask; - int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; - - if (env->cpu_watchpoint[n]) { - cpu_watchpoint_remove_by_ref(CPU(cpu), env->cpu_watchpoint[n]); - env->cpu_watchpoint[n] = NULL; - } - - if (!extract64(wcr, 0, 1)) { - /* E bit clear : watchpoint disabled */ - return; - } - - switch (extract64(wcr, 3, 2)) { - case 0: - /* LSC 00 is reserved and must behave as if the wp is disabled */ - return; - case 1: - flags |= BP_MEM_READ; - break; - case 2: - flags |= BP_MEM_WRITE; - break; - case 3: - flags |= BP_MEM_ACCESS; - break; - } - - /* Attempts to use both MASK and BAS fields simultaneously are - * CONSTRAINED UNPREDICTABLE; we opt to ignore BAS in this case, - * thus generating a watchpoint for every byte in the masked region. - */ - mask = extract64(wcr, 24, 4); - if (mask == 1 || mask == 2) { - /* Reserved values of MASK; we must act as if the mask value was - * some non-reserved value, or as if the watchpoint were disabled. - * We choose the latter. - */ - return; - } else if (mask) { - /* Watchpoint covers an aligned area up to 2GB in size */ - len = 1ULL << mask; - /* If masked bits in WVR are not zero it's CONSTRAINED UNPREDICTABLE - * whether the watchpoint fires when the unmasked bits match; we opt - * to generate the exceptions. - */ - wvr &= ~(len - 1); - } else { - /* Watchpoint covers bytes defined by the byte address select bits */ - int bas = extract64(wcr, 5, 8); - int basstart; - - if (extract64(wvr, 2, 1)) { - /* Deprecated case of an only 4-aligned address. BAS[7:4] are - * ignored, and BAS[3:0] define which bytes to watch. - */ - bas &= 0xf; - } + int el = arm_current_el(env); - if (bas == 0) { - /* This must act as if the watchpoint is disabled */ - return; + if (el == 0) { + uint64_t sctlr = arm_sctlr(env, el); + if (!(sctlr & SCTLR_EnTP2)) { + return CP_ACCESS_TRAP; } - - /* The BAS bits are supposed to be programmed to indicate a contiguous - * range of bytes. Otherwise it is CONSTRAINED UNPREDICTABLE whether - * we fire for each byte in the word/doubleword addressed by the WVR. - * We choose to ignore any non-zero bits after the first range of 1s. - */ - basstart = ctz32(bas); - len = cto32(bas >> basstart); - wvr += basstart; } - - cpu_watchpoint_insert(CPU(cpu), wvr, len, flags, - &env->cpu_watchpoint[n]); + /* TODO: FEAT_FGT */ + if (el < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_ENTP2)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; } -void hw_watchpoint_update_all(ARMCPU *cpu) +static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { - int i; - CPUARMState *env = &cpu->env; - - /* Completely clear out existing QEMU watchpoints and our array, to - * avoid possible stale entries following migration load. - */ - cpu_watchpoint_remove_all(CPU(cpu), BP_CPU); - memset(env->cpu_watchpoint, 0, sizeof(env->cpu_watchpoint)); - - for (i = 0; i < ARRAY_SIZE(cpu->env.cpu_watchpoint); i++) { - hw_watchpoint_update(cpu, i); + /* TODO: FEAT_FGT for SMPRI_EL1 but not SMPRIMAP_EL2 */ + if (arm_current_el(env) < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) { + return CP_ACCESS_TRAP_EL3; } + return CP_ACCESS_OK; } -static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) +static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - ARMCPU *cpu = env_archcpu(env); - int i = ri->crm; - - /* - * Bits [1:0] are RES0. - * - * It is IMPLEMENTATION DEFINED whether [63:49] ([63:53] with FEAT_LVA) - * are hardwired to the value of bit [48] ([52] with FEAT_LVA), or if - * they contain the value written. It is CONSTRAINED UNPREDICTABLE - * whether the RESS bits are ignored when comparing an address. - * - * Therefore we are allowed to compare the entire register, which lets - * us avoid considering whether or not FEAT_LVA is actually enabled. - */ - value &= ~3ULL; - - raw_write(env, ri, value); - hw_watchpoint_update(cpu, i); + helper_set_pstate_sm(env, FIELD_EX64(value, SVCR, SM)); + helper_set_pstate_za(env, FIELD_EX64(value, SVCR, ZA)); + arm_rebuild_hflags(env); } -static void dbgwcr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) +static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) { - ARMCPU *cpu = env_archcpu(env); - int i = ri->crm; + int cur_el = arm_current_el(env); + int old_len = sve_vqm1_for_el(env, cur_el); + int new_len; + QEMU_BUILD_BUG_ON(ARM_MAX_VQ > R_SMCR_LEN_MASK + 1); + value &= R_SMCR_LEN_MASK | R_SMCR_FA64_MASK; raw_write(env, ri, value); - hw_watchpoint_update(cpu, i); -} -void hw_breakpoint_update(ARMCPU *cpu, int n) -{ - CPUARMState *env = &cpu->env; - uint64_t bvr = env->cp15.dbgbvr[n]; - uint64_t bcr = env->cp15.dbgbcr[n]; - vaddr addr; - int bt; - int flags = BP_CPU; - - if (env->cpu_breakpoint[n]) { - cpu_breakpoint_remove_by_ref(CPU(cpu), env->cpu_breakpoint[n]); - env->cpu_breakpoint[n] = NULL; - } - - if (!extract64(bcr, 0, 1)) { - /* E bit clear : watchpoint disabled */ - return; - } - - bt = extract64(bcr, 20, 4); - - switch (bt) { - case 4: /* unlinked address mismatch (reserved if AArch64) */ - case 5: /* linked address mismatch (reserved if AArch64) */ - qemu_log_mask(LOG_UNIMP, - "arm: address mismatch breakpoint types not implemented\n"); - return; - case 0: /* unlinked address match */ - case 1: /* linked address match */ - { - /* - * Bits [1:0] are RES0. - * - * It is IMPLEMENTATION DEFINED whether bits [63:49] - * ([63:53] for FEAT_LVA) are hardwired to a copy of the sign bit - * of the VA field ([48] or [52] for FEAT_LVA), or whether the - * value is read as written. It is CONSTRAINED UNPREDICTABLE - * whether the RESS bits are ignored when comparing an address. - * Therefore we are allowed to compare the entire register, which - * lets us avoid considering whether FEAT_LVA is actually enabled. - * - * The BAS field is used to allow setting breakpoints on 16-bit - * wide instructions; it is CONSTRAINED UNPREDICTABLE whether - * a bp will fire if the addresses covered by the bp and the addresses - * covered by the insn overlap but the insn doesn't start at the - * start of the bp address range. We choose to require the insn and - * the bp to have the same address. The constraints on writing to - * BAS enforced in dbgbcr_write mean we have only four cases: - * 0b0000 => no breakpoint - * 0b0011 => breakpoint on addr - * 0b1100 => breakpoint on addr + 2 - * 0b1111 => breakpoint on addr - * See also figure D2-3 in the v8 ARM ARM (DDI0487A.c). - */ - int bas = extract64(bcr, 5, 4); - addr = bvr & ~3ULL; - if (bas == 0) { - return; - } - if (bas == 0xc) { - addr += 2; - } - break; - } - case 2: /* unlinked context ID match */ - case 8: /* unlinked VMID match (reserved if no EL2) */ - case 10: /* unlinked context ID and VMID match (reserved if no EL2) */ - qemu_log_mask(LOG_UNIMP, - "arm: unlinked context breakpoint types not implemented\n"); - return; - case 9: /* linked VMID match (reserved if no EL2) */ - case 11: /* linked context ID and VMID match (reserved if no EL2) */ - case 3: /* linked context ID match */ - default: - /* We must generate no events for Linked context matches (unless - * they are linked to by some other bp/wp, which is handled in - * updates for the linking bp/wp). We choose to also generate no events - * for reserved values. - */ - return; - } - - cpu_breakpoint_insert(CPU(cpu), addr, flags, &env->cpu_breakpoint[n]); -} - -void hw_breakpoint_update_all(ARMCPU *cpu) -{ - int i; - CPUARMState *env = &cpu->env; - - /* Completely clear out existing QEMU breakpoints and our array, to - * avoid possible stale entries following migration load. + /* + * Note that it is CONSTRAINED UNPREDICTABLE what happens to ZA storage + * when SVL is widened (old values kept, or zeros). Choose to keep the + * current values for simplicity. But for QEMU internals, we must still + * apply the narrower SVL to the Zregs and Pregs -- see the comment + * above aarch64_sve_narrow_vq. */ - cpu_breakpoint_remove_all(CPU(cpu), BP_CPU); - memset(env->cpu_breakpoint, 0, sizeof(env->cpu_breakpoint)); - - for (i = 0; i < ARRAY_SIZE(cpu->env.cpu_breakpoint); i++) { - hw_breakpoint_update(cpu, i); + new_len = sve_vqm1_for_el(env, cur_el); + if (new_len < old_len) { + aarch64_sve_narrow_vq(env, new_len + 1); } } -static void dbgbvr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - ARMCPU *cpu = env_archcpu(env); - int i = ri->crm; - - raw_write(env, ri, value); - hw_breakpoint_update(cpu, i); -} - -static void dbgbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - ARMCPU *cpu = env_archcpu(env); - int i = ri->crm; - - /* BAS[3] is a read-only copy of BAS[2], and BAS[1] a read-only - * copy of BAS[0]. +static const ARMCPRegInfo sme_reginfo[] = { + { .name = "TPIDR2_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 5, + .access = PL0_RW, .accessfn = access_tpidr2, + .fieldoffset = offsetof(CPUARMState, cp15.tpidr2_el0) }, + { .name = "SVCR", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 2, + .access = PL0_RW, .type = ARM_CP_SME, + .fieldoffset = offsetof(CPUARMState, svcr), + .writefn = svcr_write, .raw_writefn = raw_write }, + { .name = "SMCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 6, + .access = PL1_RW, .type = ARM_CP_SME, + .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[1]), + .writefn = smcr_write, .raw_writefn = raw_write }, + { .name = "SMCR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 6, + .access = PL2_RW, .type = ARM_CP_SME, + .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[2]), + .writefn = smcr_write, .raw_writefn = raw_write }, + { .name = "SMCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 6, + .access = PL3_RW, .type = ARM_CP_SME, + .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[3]), + .writefn = smcr_write, .raw_writefn = raw_write }, + { .name = "SMIDR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 6, + .access = PL1_R, .accessfn = access_aa64_tid1, + /* + * IMPLEMENTOR = 0 (software) + * REVISION = 0 (implementation defined) + * SMPS = 0 (no streaming execution priority in QEMU) + * AFFINITY = 0 (streaming sve mode not shared with other PEs) + */ + .type = ARM_CP_CONST, .resetvalue = 0, }, + /* + * Because SMIDR_EL1.SMPS is 0, SMPRI_EL1 and SMPRIMAP_EL2 are RES 0. */ - value = deposit64(value, 6, 1, extract64(value, 5, 1)); - value = deposit64(value, 8, 1, extract64(value, 7, 1)); - - raw_write(env, ri, value); - hw_breakpoint_update(cpu, i); -} + { .name = "SMPRI_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 4, + .access = PL1_RW, .accessfn = access_esm, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5, + .access = PL2_RW, .accessfn = access_esm, + .type = ARM_CP_CONST, .resetvalue = 0 }, +}; +#endif /* TARGET_AARCH64 */ -static void define_debug_regs(ARMCPU *cpu) +static void define_pmu_regs(ARMCPU *cpu) { - /* Define v7 and v8 architectural debug registers. - * These are just dummy implementations for now. - */ - int i; - int wrps, brps, ctx_cmps; - /* - * The Arm ARM says DBGDIDR is optional and deprecated if EL1 cannot - * use AArch32. Given that bit 15 is RES1, if the value is 0 then - * the register must not exist for this cpu. + * v7 performance monitor control register: same implementor + * field as main ID register, and we implement four counters in + * addition to the cycle count register. */ - if (cpu->isar.dbgdidr != 0) { - ARMCPRegInfo dbgdidr = { - .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, - .opc1 = 0, .opc2 = 0, - .access = PL0_R, .accessfn = access_tda, - .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, - }; - define_one_arm_cp_reg(cpu, &dbgdidr); - } - - /* Note that all these register fields hold "number of Xs minus 1". */ - brps = arm_num_brps(cpu); - wrps = arm_num_wrps(cpu); - ctx_cmps = arm_num_ctx_cmps(cpu); - - assert(ctx_cmps <= brps); - - define_arm_cp_regs(cpu, debug_cp_reginfo); - - if (arm_feature(&cpu->env, ARM_FEATURE_LPAE)) { - define_arm_cp_regs(cpu, debug_lpae_cp_reginfo); - } - - for (i = 0; i < brps; i++) { - ARMCPRegInfo dbgregs[] = { - { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, - .access = PL1_RW, .accessfn = access_tda, - .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]), - .writefn = dbgbvr_write, .raw_writefn = raw_write - }, - { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5, - .access = PL1_RW, .accessfn = access_tda, - .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), - .writefn = dbgbcr_write, .raw_writefn = raw_write - }, - REGINFO_SENTINEL - }; - define_arm_cp_regs(cpu, dbgregs); - } - - for (i = 0; i < wrps; i++) { - ARMCPRegInfo dbgregs[] = { - { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, - .access = PL1_RW, .accessfn = access_tda, - .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]), - .writefn = dbgwvr_write, .raw_writefn = raw_write - }, - { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH, - .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7, - .access = PL1_RW, .accessfn = access_tda, - .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), - .writefn = dbgwcr_write, .raw_writefn = raw_write - }, - REGINFO_SENTINEL - }; - define_arm_cp_regs(cpu, dbgregs); - } -} - -static void define_pmu_regs(ARMCPU *cpu) -{ - /* - * v7 performance monitor control register: same implementor - * field as main ID register, and we implement four counters in - * addition to the cycle count register. - */ - unsigned int i, pmcrn = PMCR_NUM_COUNTERS; + unsigned int i, pmcrn = pmu_num_counters(&cpu->env); ARMCPRegInfo pmcr = { .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0, .access = PL0_RW, @@ -6677,10 +6828,10 @@ static void define_pmu_regs(ARMCPU *cpu) .access = PL0_RW, .accessfn = pmreg_access, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr), - .resetvalue = (cpu->midr & 0xff000000) | (pmcrn << PMCRN_SHIFT) | - PMCRLC, + .resetvalue = cpu->isar.reset_pmcr_el0, .writefn = pmcr_write, .raw_writefn = raw_write, }; + define_one_arm_cp_reg(cpu, &pmcr); define_one_arm_cp_reg(cpu, &pmcr64); for (i = 0; i < pmcrn; i++) { @@ -6693,10 +6844,10 @@ static void define_pmu_regs(ARMCPU *cpu) .crm = 8 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7, .access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS, .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn, - .accessfn = pmreg_access }, + .accessfn = pmreg_access_xevcntr }, { .name = pmevcntr_el0_name, .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 8 | (3 & (i >> 3)), - .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access, + .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access_xevcntr, .type = ARM_CP_IO, .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn, .raw_readfn = pmevcntr_rawread, @@ -6712,7 +6863,6 @@ static void define_pmu_regs(ARMCPU *cpu) .type = ARM_CP_IO, .readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn, .raw_writefn = pmevtyper_rawwrite }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, pmev_regs); g_free(pmevcntr_name); @@ -6720,7 +6870,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, @@ -6730,11 +6880,10 @@ static void define_pmu_regs(ARMCPU *cpu) .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 5, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, .resetvalue = extract64(cpu->pmceid1, 32, 32) }, - REGINFO_SENTINEL }; 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, @@ -6745,7 +6894,8 @@ static void define_pmu_regs(ARMCPU *cpu) } } -/* We don't know until after realize whether there's a GICv3 +/* + * We don't know until after realize whether there's a GICv3 * attached, and that is what registers the gicv3 sysregs. * So we have to fill in the GIC fields in ID_PFR/ID_PFR1_EL1/ID_AA64PFR0_EL1 * at runtime. @@ -6774,7 +6924,8 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) } #endif -/* Shared logic between LORID and the rest of the LOR* registers. +/* + * Shared logic between LORID and the rest of the LOR* registers. * Secure state exclusion has already been dealt with. */ static CPAccessResult access_lor_ns(CPUARMState *env, @@ -6827,7 +6978,6 @@ static const ARMCPRegInfo lor_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7, .access = PL1_R, .accessfn = access_lor_ns, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; #ifdef TARGET_AARCH64 @@ -6837,7 +6987,7 @@ static CPAccessResult access_pauth(CPUARMState *env, const ARMCPRegInfo *ri, int el = arm_current_el(env); if (el < 2 && - arm_feature(env, ARM_FEATURE_EL2) && + arm_is_el2_enabled(env) && !(arm_hcr_el2_eff(env) & HCR_APK)) { return CP_ACCESS_TRAP_EL2; } @@ -6890,93 +7040,96 @@ static const ARMCPRegInfo pauth_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 3, .access = PL1_RW, .accessfn = access_pauth, .fieldoffset = offsetof(CPUARMState, keys.apib.hi) }, - REGINFO_SENTINEL }; static const ARMCPRegInfo tlbirange_reginfo[] = { { .name = "TLBI_RVAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 5, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 7, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 5, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 7, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RVAAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RVALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 5, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RVAALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 7, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RIPAS2E1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 2, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ripas2e1is_write }, { .name = "TLBI_RIPAS2LE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 6, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ripas2e1is_write }, { .name = "TLBI_RVAE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVALE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RIPAS2E1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 2, - .access = PL2_W, .type = ARM_CP_NOP }, - { .name = "TLBI_RIPAS2LE1", .state = ARM_CP_STATE_AA64, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ripas2e1_write }, + { .name = "TLBI_RIPAS2LE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 6, - .access = PL2_W, .type = ARM_CP_NOP }, + .access = PL2_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_ripas2e1_write }, { .name = "TLBI_RVAE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVALE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVAE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2_write }, { .name = "TLBI_RVALE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2_write }, { .name = "TLBI_RVAE3IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 1, @@ -7002,41 +7155,40 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 5, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae3_write }, - REGINFO_SENTINEL }; static const ARMCPRegInfo tlbios_reginfo[] = { { .name = "TLBI_VMALLE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 0, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 5, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 7, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2is_write }, { .name = "TLBI_VAE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_ALLE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 4, @@ -7044,7 +7196,7 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .writefn = tlbi_aa64_alle1is_write }, { .name = "TLBI_VALE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_VMALLS12E1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 6, @@ -7074,7 +7226,6 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 5, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae3is_write }, - REGINFO_SENTINEL }; static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri) @@ -7113,7 +7264,6 @@ static const ARMCPRegInfo rndr_reginfo[] = { .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO, .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1, .access = PL0_R, .readfn = rndr_readfn }, - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -7149,7 +7299,6 @@ static const ARMCPRegInfo dcpop_reg[] = { .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, - REGINFO_SENTINEL }; static const ARMCPRegInfo dcpodp_reg[] = { @@ -7157,7 +7306,6 @@ static const ARMCPRegInfo dcpodp_reg[] = { .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, - REGINFO_SENTINEL }; #endif /*CONFIG_USER_ONLY*/ @@ -7259,14 +7407,12 @@ static const ARMCPRegInfo mte_reginfo[] = { { .name = "DC_CIGDSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, - REGINFO_SENTINEL }; static const ARMCPRegInfo mte_tco_ro_reginfo[] = { { .name = "TCO", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, .type = ARM_CP_CONST, .access = PL0_RW, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { @@ -7318,10 +7464,54 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { .accessfn = aa64_zva_access, #endif }, - REGINFO_SENTINEL }; -#endif +static CPAccessResult access_scxtnum(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + uint64_t hcr = arm_hcr_el2_eff(env); + int el = arm_current_el(env); + + if (el == 0 && !((hcr & HCR_E2H) && (hcr & HCR_TGE))) { + if (env->cp15.sctlr_el[1] & SCTLR_TSCXT) { + if (hcr & HCR_TGE) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_TRAP; + } + } else if (el < 2 && (env->cp15.sctlr_el[2] & SCTLR_TSCXT)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 2 && arm_is_el2_enabled(env) && !(hcr & HCR_ENSCXT)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_ENSCXT)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo scxtnum_reginfo[] = { + { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL0_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) }, + { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL1_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, + { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL2_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[2]) }, + { .name = "SCXTNUM_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL3_RW, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[3]) }, +}; +#endif /* TARGET_AARCH64 */ static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) @@ -7364,7 +7554,6 @@ static const ARMCPRegInfo predinv_reginfo[] = { { .name = "CPPRCTX", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 7, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, - REGINFO_SENTINEL }; static uint64_t ccsidr2_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -7377,9 +7566,8 @@ static const ARMCPRegInfo ccsidr2_reginfo[] = { { .name = "CCSIDR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 2, .access = PL1_R, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .readfn = ccsidr2_read, .type = ARM_CP_NO_RAW }, - REGINFO_SENTINEL }; static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri, @@ -7440,14 +7628,16 @@ static const ARMCPRegInfo jazelle_regs[] = { .cp = 14, .crn = 2, .crm = 0, .opc1 = 7, .opc2 = 0, .accessfn = access_joscr_jmcr, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL +}; + +static const ARMCPRegInfo contextidr_el2 = { + .name = "CONTEXTIDR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 1, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[2]) }; static const ARMCPRegInfo vhe_reginfo[] = { - { .name = "CONTEXTIDR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL2_RW, - .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[2]) }, { .name = "TTBR1_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 1, .access = PL2_RW, .writefn = vmsa_tcr_ttbr_el2_write, @@ -7505,7 +7695,6 @@ static const ARMCPRegInfo vhe_reginfo[] = { .access = PL2_RW, .accessfn = e2h_access, .writefn = gt_virt_cval_write, .raw_writefn = raw_write }, #endif - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -7518,7 +7707,6 @@ static const ARMCPRegInfo ats1e1_reginfo[] = { .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo ats1cp_reginfo[] = { @@ -7530,7 +7718,6 @@ static const ARMCPRegInfo ats1cp_reginfo[] = { .cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write }, - REGINFO_SENTINEL }; #endif @@ -7552,7 +7739,6 @@ static const ARMCPRegInfo actlr2_hactlr2_reginfo[] = { .cp = 15, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 3, .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; void register_cp_regs_for_features(ARMCPU *cpu) @@ -7566,7 +7752,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, cp_reginfo); if (!arm_feature(env, ARM_FEATURE_V8)) { - /* Must go early as it is full of wildcards that may be + /* + * Must go early as it is full of wildcards that may be * overridden by later definitions. */ define_arm_cp_regs(cpu, not_v8_cp_reginfo); @@ -7580,7 +7767,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa32_tid3, .resetvalue = cpu->isar.id_pfr0 }, - /* ID_PFR1 is not a plain ARM_CP_CONST because we don't know + /* + * ID_PFR1 is not a plain ARM_CP_CONST because we don't know * the value of the GIC field until after we define these regs. */ { .name = "ID_PFR1", .state = ARM_CP_STATE_BOTH, @@ -7659,7 +7847,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa32_tid3, .resetvalue = cpu->isar.id_isar6 }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, v6_idregs); define_arm_cp_regs(cpu, v6_cp_reginfo); @@ -7681,7 +7868,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .name = "CLIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .resetvalue = cpu->clidr }; define_one_arm_cp_reg(cpu, &clidr); @@ -7692,11 +7879,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 @@ -7736,11 +7928,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, .resetvalue = cpu->isar.id_aa64zfr0 }, - { .name = "ID_AA64PFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + { .name = "ID_AA64SMFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, - .resetvalue = 0 }, + .resetvalue = cpu->isar.id_aa64smfr0 }, { .name = "ID_AA64PFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, @@ -7886,7 +8078,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, @@ -7896,17 +8115,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, @@ -7927,37 +8146,93 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, .resetvalue = cpu->pmceid1 }, - REGINFO_SENTINEL }; #ifdef CONFIG_USER_ONLY - ARMCPRegUserSpaceInfo v8_user_idregs[] = { + static const ARMCPRegUserSpaceInfo v8_user_idregs[] = { { .name = "ID_AA64PFR0_EL1", - .exported_bits = 0x000f000f00ff0000, - .fixed_bits = 0x0000000000000011 }, + .exported_bits = R_ID_AA64PFR0_FP_MASK | + R_ID_AA64PFR0_ADVSIMD_MASK | + R_ID_AA64PFR0_SVE_MASK | + R_ID_AA64PFR0_DIT_MASK, + .fixed_bits = (0x1u << R_ID_AA64PFR0_EL0_SHIFT) | + (0x1u << R_ID_AA64PFR0_EL1_SHIFT) }, { .name = "ID_AA64PFR1_EL1", - .exported_bits = 0x00000000000000f0 }, + .exported_bits = R_ID_AA64PFR1_BT_MASK | + R_ID_AA64PFR1_SSBS_MASK | + R_ID_AA64PFR1_MTE_MASK | + R_ID_AA64PFR1_SME_MASK }, { .name = "ID_AA64PFR*_EL1_RESERVED", - .is_glob = true }, - { .name = "ID_AA64ZFR0_EL1" }, + .is_glob = true }, + { .name = "ID_AA64ZFR0_EL1", + .exported_bits = R_ID_AA64ZFR0_SVEVER_MASK | + R_ID_AA64ZFR0_AES_MASK | + R_ID_AA64ZFR0_BITPERM_MASK | + R_ID_AA64ZFR0_BFLOAT16_MASK | + R_ID_AA64ZFR0_SHA3_MASK | + R_ID_AA64ZFR0_SM4_MASK | + R_ID_AA64ZFR0_I8MM_MASK | + R_ID_AA64ZFR0_F32MM_MASK | + R_ID_AA64ZFR0_F64MM_MASK }, + { .name = "ID_AA64SMFR0_EL1", + .exported_bits = R_ID_AA64SMFR0_F32F32_MASK | + R_ID_AA64SMFR0_B16F32_MASK | + R_ID_AA64SMFR0_F16F32_MASK | + R_ID_AA64SMFR0_I8I32_MASK | + R_ID_AA64SMFR0_F64F64_MASK | + R_ID_AA64SMFR0_I16I64_MASK | + R_ID_AA64SMFR0_FA64_MASK }, { .name = "ID_AA64MMFR0_EL1", - .fixed_bits = 0x00000000ff000000 }, - { .name = "ID_AA64MMFR1_EL1" }, + .exported_bits = R_ID_AA64MMFR0_ECV_MASK, + .fixed_bits = (0xfu << R_ID_AA64MMFR0_TGRAN64_SHIFT) | + (0xfu << R_ID_AA64MMFR0_TGRAN4_SHIFT) }, + { .name = "ID_AA64MMFR1_EL1", + .exported_bits = R_ID_AA64MMFR1_AFP_MASK }, + { .name = "ID_AA64MMFR2_EL1", + .exported_bits = R_ID_AA64MMFR2_AT_MASK }, { .name = "ID_AA64MMFR*_EL1_RESERVED", - .is_glob = true }, + .is_glob = true }, { .name = "ID_AA64DFR0_EL1", - .fixed_bits = 0x0000000000000006 }, - { .name = "ID_AA64DFR1_EL1" }, + .fixed_bits = (0x6u << R_ID_AA64DFR0_DEBUGVER_SHIFT) }, + { .name = "ID_AA64DFR1_EL1" }, { .name = "ID_AA64DFR*_EL1_RESERVED", - .is_glob = true }, + .is_glob = true }, { .name = "ID_AA64AFR*", - .is_glob = true }, + .is_glob = true }, { .name = "ID_AA64ISAR0_EL1", - .exported_bits = 0x00fffffff0fffff0 }, + .exported_bits = R_ID_AA64ISAR0_AES_MASK | + R_ID_AA64ISAR0_SHA1_MASK | + R_ID_AA64ISAR0_SHA2_MASK | + R_ID_AA64ISAR0_CRC32_MASK | + R_ID_AA64ISAR0_ATOMIC_MASK | + R_ID_AA64ISAR0_RDM_MASK | + R_ID_AA64ISAR0_SHA3_MASK | + R_ID_AA64ISAR0_SM3_MASK | + R_ID_AA64ISAR0_SM4_MASK | + R_ID_AA64ISAR0_DP_MASK | + R_ID_AA64ISAR0_FHM_MASK | + R_ID_AA64ISAR0_TS_MASK | + R_ID_AA64ISAR0_RNDR_MASK }, { .name = "ID_AA64ISAR1_EL1", - .exported_bits = 0x000000f0ffffffff }, + .exported_bits = R_ID_AA64ISAR1_DPB_MASK | + R_ID_AA64ISAR1_APA_MASK | + R_ID_AA64ISAR1_API_MASK | + R_ID_AA64ISAR1_JSCVT_MASK | + R_ID_AA64ISAR1_FCMA_MASK | + R_ID_AA64ISAR1_LRCPC_MASK | + R_ID_AA64ISAR1_GPA_MASK | + R_ID_AA64ISAR1_GPI_MASK | + R_ID_AA64ISAR1_FRINTTS_MASK | + R_ID_AA64ISAR1_SB_MASK | + R_ID_AA64ISAR1_BF16_MASK | + R_ID_AA64ISAR1_DGH_MASK | + R_ID_AA64ISAR1_I8MM_MASK }, + { .name = "ID_AA64ISAR2_EL1", + .exported_bits = R_ID_AA64ISAR2_WFXT_MASK | + R_ID_AA64ISAR2_RPRES_MASK | + R_ID_AA64ISAR2_GPA3_MASK | + R_ID_AA64ISAR2_APA3_MASK }, { .name = "ID_AA64ISAR*_EL1_RESERVED", - .is_glob = true }, - REGUSERINFO_SENTINEL + .is_glob = true }, }; modify_arm_cp_regs(v8_idregs, v8_user_idregs); #endif @@ -7965,7 +8240,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (!arm_feature(env, ARM_FEATURE_EL3) && !arm_feature(env, ARM_FEATURE_EL2)) { ARMCPRegInfo rvbar = { - .name = "RVBAR_EL1", .state = ARM_CP_STATE_AA64, + .name = "RVBAR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1, .access = PL1_R, .fieldoffset = offsetof(CPUARMState, cp15.rvbar), @@ -7974,31 +8249,78 @@ 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); + } } - if (arm_feature(env, ARM_FEATURE_EL2)) { + + /* + * Register the base EL2 cpregs. + * Pre v8, these registers are implemented only as part of the + * Virtualization Extensions (EL2 present). Beginning with v8, + * if EL2 is missing but EL3 is enabled, mostly these become + * RES0 from EL3, with some specific exceptions. + */ + if (arm_feature(env, ARM_FEATURE_EL2) + || (arm_feature(env, ARM_FEATURE_EL3) + && arm_feature(env, ARM_FEATURE_V8))) { uint64_t vmpidr_def = mpidr_read_val(env); ARMCPRegInfo vpidr_regs[] = { { .name = "VPIDR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .resetvalue = cpu->midr, .type = ARM_CP_ALIAS, + .resetvalue = cpu->midr, + .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetoflow32(CPUARMState, cp15.vpidr_el2) }, { .name = "VPIDR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, .access = PL2_RW, .resetvalue = cpu->midr, + .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, { .name = "VMPIDR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .resetvalue = vmpidr_def, .type = ARM_CP_ALIAS, + .resetvalue = vmpidr_def, + .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetoflow32(CPUARMState, cp15.vmpidr_el2) }, { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, - .resetvalue = vmpidr_def, + .access = PL2_RW, .resetvalue = vmpidr_def, + .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) }, - REGINFO_SENTINEL }; + /* + * The only field of MDCR_EL2 that has a defined architectural reset + * 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, .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), + }; + define_one_arm_cp_reg(cpu, &mdcr_el2); define_arm_cp_regs(cpu, vpidr_regs); define_arm_cp_regs(cpu, el2_cp_reginfo); if (arm_feature(env, ARM_FEATURE_V8)) { @@ -8009,42 +8331,24 @@ void register_cp_regs_for_features(ARMCPU *cpu) } /* RVBAR_EL2 is only implemented if EL2 is the highest EL */ if (!arm_feature(env, ARM_FEATURE_EL3)) { - ARMCPRegInfo rvbar = { - .name = "RVBAR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 1, - .access = PL2_R, - .fieldoffset = offsetof(CPUARMState, cp15.rvbar), - }; - define_one_arm_cp_reg(cpu, &rvbar); - } - } else { - /* If EL2 is missing but higher ELs are enabled, we need to - * register the no_el2 reginfos. - */ - if (arm_feature(env, ARM_FEATURE_EL3)) { - /* When EL3 exists but not EL2, VPIDR and VMPIDR take the value - * of MIDR_EL1 and MPIDR_EL1. - */ - ARMCPRegInfo vpidr_regs[] = { - { .name = "VPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = cpu->midr, - .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, - { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_NO_RAW, - .writefn = arm_cp_write_ignore, .readfn = mpidr_read }, - REGINFO_SENTINEL + ARMCPRegInfo rvbar[] = { + { + .name = "RVBAR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 1, + .access = PL2_R, + .fieldoffset = offsetof(CPUARMState, cp15.rvbar), + }, + { .name = "RVBAR", .type = ARM_CP_ALIAS, + .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1, + .access = PL2_R, + .fieldoffset = offsetof(CPUARMState, cp15.rvbar), + }, }; - define_arm_cp_regs(cpu, vpidr_regs); - define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo); - if (arm_feature(env, ARM_FEATURE_V8)) { - define_arm_cp_regs(cpu, el3_no_el2_v8_cp_reginfo); - } + define_arm_cp_regs(cpu, rvbar); } } + + /* Register the base EL3 cpregs. */ if (arm_feature(env, ARM_FEATURE_EL3)) { define_arm_cp_regs(cpu, el3_cp_reginfo); ARMCPRegInfo el3_regs[] = { @@ -8059,12 +8363,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) .raw_writefn = raw_write, .writefn = sctlr_write, .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]), .resetvalue = cpu->reset_sctlr }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, el3_regs); } - /* The behaviour of NSACR is sufficiently various that we don't + /* + * The behaviour of NSACR is sufficiently various that we don't * try to describe it in a single reginfo: * if EL3 is 64 bit, then trap to EL3 from S EL1, * reads as constant 0xc00 from NS EL1 and NS EL2 @@ -8074,7 +8378,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) */ if (arm_feature(env, ARM_FEATURE_EL3)) { if (arm_feature(env, ARM_FEATURE_AARCH64)) { - ARMCPRegInfo nsacr = { + static const ARMCPRegInfo nsacr = { .name = "NSACR", .type = ARM_CP_CONST, .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL1_RW, .accessfn = nsacr_access, @@ -8082,7 +8386,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; define_one_arm_cp_reg(cpu, &nsacr); } else { - ARMCPRegInfo nsacr = { + static const ARMCPRegInfo nsacr = { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL3_RW | PL1_R, @@ -8093,7 +8397,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } else { if (arm_feature(env, ARM_FEATURE_V8)) { - ARMCPRegInfo nsacr = { + static const ARMCPRegInfo nsacr = { .name = "NSACR", .type = ARM_CP_CONST, .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL1_R, @@ -8156,13 +8460,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa32_jazelle, cpu)) { define_arm_cp_regs(cpu, jazelle_regs); } - /* Slightly awkwardly, the OMAP and StrongARM cores need all of + /* + * Slightly awkwardly, the OMAP and StrongARM cores need all of * cp15 crn=0 to be writes-ignored, whereas for other cores they should * be read-only (ie write causes UNDEF exception). */ { ARMCPRegInfo id_pre_v8_midr_cp_reginfo[] = { - /* Pre-v8 MIDR space. + /* + * Pre-v8 MIDR space. * Note that the MIDR isn't a simple constant register because * of the TI925 behaviour where writes to another register can * cause the MIDR value to change. @@ -8194,7 +8500,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "DUMMY", .cp = 15, .crn = 0, .crm = 7, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; ARMCPRegInfo id_v8_midr_cp_reginfo[] = { { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH, @@ -8202,10 +8507,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_NO_RAW, .resetvalue = cpu->midr, .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid), .readfn = midr_read }, - /* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */ - { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST, - .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4, - .access = PL1_R, .resetvalue = cpu->midr }, + /* crn = 0 op1 = 0 crm = 0 op2 = 7 : AArch32 aliases of MIDR */ { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST, .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 7, .access = PL1_R, .resetvalue = cpu->midr }, @@ -8214,7 +8516,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .accessfn = access_aa64_tid1, .type = ARM_CP_CONST, .resetvalue = cpu->revidr }, - REGINFO_SENTINEL + }; + ARMCPRegInfo id_v8_midr_alias_cp_reginfo = { + .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST, + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4, + .access = PL1_R, .resetvalue = cpu->midr }; ARMCPRegInfo id_cp_reginfo[] = { /* These are common to v8 and pre-v8 */ @@ -8232,7 +8538,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .accessfn = access_aa32_tid1, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; /* TLBTR is specific to VMSA */ ARMCPRegInfo id_tlbtr_reginfo = { @@ -8249,47 +8554,128 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->pmsav7_dregion << 8 }; - ARMCPRegInfo crn0_wi_reginfo = { + /* HMPUIR is specific to PMSA V8 */ + ARMCPRegInfo id_hmpuir_reginfo = { + .name = "HMPUIR", + .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 4, + .access = PL2_R, .type = ARM_CP_CONST, + .resetvalue = cpu->pmsav8r_hdregion + }; + static const ARMCPRegInfo crn0_wi_reginfo = { .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_OVERRIDE }; #ifdef CONFIG_USER_ONLY - ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = { + static const ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = { { .name = "MIDR_EL1", - .exported_bits = 0x00000000ffffffff }, - { .name = "REVIDR_EL1" }, - REGUSERINFO_SENTINEL + .exported_bits = R_MIDR_EL1_REVISION_MASK | + R_MIDR_EL1_PARTNUM_MASK | + R_MIDR_EL1_ARCHITECTURE_MASK | + R_MIDR_EL1_VARIANT_MASK | + R_MIDR_EL1_IMPLEMENTER_MASK }, + { .name = "REVIDR_EL1" }, }; modify_arm_cp_regs(id_v8_midr_cp_reginfo, id_v8_user_midr_cp_reginfo); #endif if (arm_feature(env, ARM_FEATURE_OMAPCP) || arm_feature(env, ARM_FEATURE_STRONGARM)) { - ARMCPRegInfo *r; - /* Register the blanket "writes ignored" value first to cover the + size_t i; + /* + * Register the blanket "writes ignored" value first to cover the * whole space. Then update the specific ID registers to allow write * access, so that they ignore writes rather than causing them to * UNDEF. */ define_one_arm_cp_reg(cpu, &crn0_wi_reginfo); - for (r = id_pre_v8_midr_cp_reginfo; - r->type != ARM_CP_SENTINEL; r++) { - r->access = PL1_RW; + for (i = 0; i < ARRAY_SIZE(id_pre_v8_midr_cp_reginfo); ++i) { + id_pre_v8_midr_cp_reginfo[i].access = PL1_RW; } - for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) { - r->access = PL1_RW; + for (i = 0; i < ARRAY_SIZE(id_cp_reginfo); ++i) { + id_cp_reginfo[i].access = PL1_RW; } id_mpuir_reginfo.access = PL1_RW; id_tlbtr_reginfo.access = PL1_RW; } if (arm_feature(env, ARM_FEATURE_V8)) { define_arm_cp_regs(cpu, id_v8_midr_cp_reginfo); + if (!arm_feature(env, ARM_FEATURE_PMSA)) { + define_one_arm_cp_reg(cpu, &id_v8_midr_alias_cp_reginfo); + } } else { define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo); } define_arm_cp_regs(cpu, id_cp_reginfo); if (!arm_feature(env, ARM_FEATURE_PMSA)) { define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo); + } else if (arm_feature(env, ARM_FEATURE_PMSA) && + arm_feature(env, ARM_FEATURE_V8)) { + uint32_t i = 0; + char *tmp_string; + + define_one_arm_cp_reg(cpu, &id_mpuir_reginfo); + define_one_arm_cp_reg(cpu, &id_hmpuir_reginfo); + define_arm_cp_regs(cpu, pmsav8r_cp_reginfo); + + /* Register alias is only valid for first 32 indexes */ + for (i = 0; i < MIN(cpu->pmsav7_dregion, 32); ++i) { + uint8_t crm = 0b1000 | extract32(i, 1, 3); + uint8_t opc1 = extract32(i, 4, 1); + uint8_t opc2 = extract32(i, 0, 1) << 2; + + tmp_string = g_strdup_printf("PRBAR%u", i); + ARMCPRegInfo tmp_prbarn_reginfo = { + .name = tmp_string, .type = ARM_CP_ALIAS | ARM_CP_NO_RAW, + .cp = 15, .opc1 = opc1, .crn = 6, .crm = crm, .opc2 = opc2, + .access = PL1_RW, .resetvalue = 0, + .accessfn = access_tvm_trvm, + .writefn = pmsav8r_regn_write, .readfn = pmsav8r_regn_read + }; + define_one_arm_cp_reg(cpu, &tmp_prbarn_reginfo); + g_free(tmp_string); + + opc2 = extract32(i, 0, 1) << 2 | 0x1; + tmp_string = g_strdup_printf("PRLAR%u", i); + ARMCPRegInfo tmp_prlarn_reginfo = { + .name = tmp_string, .type = ARM_CP_ALIAS | ARM_CP_NO_RAW, + .cp = 15, .opc1 = opc1, .crn = 6, .crm = crm, .opc2 = opc2, + .access = PL1_RW, .resetvalue = 0, + .accessfn = access_tvm_trvm, + .writefn = pmsav8r_regn_write, .readfn = pmsav8r_regn_read + }; + define_one_arm_cp_reg(cpu, &tmp_prlarn_reginfo); + g_free(tmp_string); + } + + /* Register alias is only valid for first 32 indexes */ + for (i = 0; i < MIN(cpu->pmsav8r_hdregion, 32); ++i) { + uint8_t crm = 0b1000 | extract32(i, 1, 3); + uint8_t opc1 = 0b100 | extract32(i, 4, 1); + uint8_t opc2 = extract32(i, 0, 1) << 2; + + tmp_string = g_strdup_printf("HPRBAR%u", i); + ARMCPRegInfo tmp_hprbarn_reginfo = { + .name = tmp_string, + .type = ARM_CP_NO_RAW, + .cp = 15, .opc1 = opc1, .crn = 6, .crm = crm, .opc2 = opc2, + .access = PL2_RW, .resetvalue = 0, + .writefn = pmsav8r_regn_write, .readfn = pmsav8r_regn_read + }; + define_one_arm_cp_reg(cpu, &tmp_hprbarn_reginfo); + g_free(tmp_string); + + opc2 = extract32(i, 0, 1) << 2 | 0x1; + tmp_string = g_strdup_printf("HPRLAR%u", i); + ARMCPRegInfo tmp_hprlarn_reginfo = { + .name = tmp_string, + .type = ARM_CP_NO_RAW, + .cp = 15, .opc1 = opc1, .crn = 6, .crm = crm, .opc2 = opc2, + .access = PL2_RW, .resetvalue = 0, + .writefn = pmsav8r_regn_write, .readfn = pmsav8r_regn_read + }; + define_one_arm_cp_reg(cpu, &tmp_hprlarn_reginfo); + g_free(tmp_string); + } } else if (arm_feature(env, ARM_FEATURE_V7)) { define_one_arm_cp_reg(cpu, &id_mpuir_reginfo); } @@ -8300,13 +8686,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "MPIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5, .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW }, - REGINFO_SENTINEL }; #ifdef CONFIG_USER_ONLY - ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = { + static const ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = { { .name = "MPIDR_EL1", .fixed_bits = 0x0000000080000000 }, - REGUSERINFO_SENTINEL }; modify_arm_cp_regs(mpidr_cp_reginfo, mpidr_user_cp_reginfo); #endif @@ -8327,7 +8711,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 1, .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, auxcr_reginfo); if (cpu_isar_feature(aa32_ac2, cpu)) { @@ -8362,7 +8745,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .type = ARM_CP_CONST, .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0, .access = PL1_R, .resetvalue = cpu->reset_cbar }, - REGINFO_SENTINEL }; /* We don't implement a r/w 64 bit CBAR currently */ assert(arm_feature(env, ARM_FEATURE_CBAR_RO)); @@ -8371,7 +8753,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo cbar = { .name = "CBAR", .cp = 15, .crn = 15, .crm = 0, .opc1 = 4, .opc2 = 0, - .access = PL1_R|PL3_W, .resetvalue = cpu->reset_cbar, + .access = PL1_R | PL3_W, .resetvalue = cpu->reset_cbar, .fieldoffset = offsetof(CPUARMState, cp15.c15_config_base_address) }; @@ -8385,14 +8767,13 @@ void register_cp_regs_for_features(ARMCPU *cpu) } if (arm_feature(env, ARM_FEATURE_VBAR)) { - ARMCPRegInfo vbar_cp_reginfo[] = { + static const ARMCPRegInfo vbar_cp_reginfo[] = { { .name = "VBAR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .writefn = vbar_write, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), offsetof(CPUARMState, cp15.vbar_ns) }, .resetvalue = 0 }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, vbar_cp_reginfo); } @@ -8409,13 +8790,25 @@ void register_cp_regs_for_features(ARMCPU *cpu) .raw_writefn = raw_write, }; if (arm_feature(env, ARM_FEATURE_XSCALE)) { - /* Normally we would always end the TB on an SCTLR write, but Linux + /* + * Normally we would always end the TB on an SCTLR write, but Linux * arch/arm/mach-pxa/sleep.S expects two instructions following * an MMU enable to execute from cache. Imitate this behaviour. */ sctlr.type |= ARM_CP_SUPPRESS_TB_END; } define_one_arm_cp_reg(cpu, &sctlr); + + if (arm_feature(env, ARM_FEATURE_PMSA) && + arm_feature(env, ARM_FEATURE_V8)) { + ARMCPRegInfo vsctlr = { + .name = "VSCTLR", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0, + .access = PL2_RW, .resetvalue = 0x0, + .fieldoffset = offsetoflow32(CPUARMState, cp15.vsctlr), + }; + define_one_arm_cp_reg(cpu, &vsctlr); + } } if (cpu_isar_feature(aa64_lor, cpu)) { @@ -8442,24 +8835,30 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_ssbs, cpu)) { define_one_arm_cp_reg(cpu, &ssbs_reginfo); } + if (cpu_isar_feature(any_ras, cpu)) { + define_arm_cp_regs(cpu, minimal_ras_reginfo); + } + if (cpu_isar_feature(aa64_vh, cpu) || + cpu_isar_feature(aa64_debugv8p2, cpu)) { + define_one_arm_cp_reg(cpu, &contextidr_el2); + } if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) { define_arm_cp_regs(cpu, vhe_reginfo); } if (cpu_isar_feature(aa64_sve, cpu)) { - define_one_arm_cp_reg(cpu, &zcr_el1_reginfo); - if (arm_feature(env, ARM_FEATURE_EL2)) { - define_one_arm_cp_reg(cpu, &zcr_el2_reginfo); - } else { - define_one_arm_cp_reg(cpu, &zcr_no_el2_reginfo); - } - if (arm_feature(env, ARM_FEATURE_EL3)) { - define_one_arm_cp_reg(cpu, &zcr_el3_reginfo); - } + define_arm_cp_regs(cpu, zcr_reginfo); + } + + if (cpu_isar_feature(aa64_hcx, cpu)) { + define_one_arm_cp_reg(cpu, &hcrx_el2_reginfo); } #ifdef TARGET_AARCH64 + if (cpu_isar_feature(aa64_sme, cpu)) { + define_arm_cp_regs(cpu, sme_reginfo); + } if (cpu_isar_feature(aa64_pauth, cpu)) { define_arm_cp_regs(cpu, pauth_reginfo); } @@ -8495,6 +8894,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, mte_tco_ro_reginfo); define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo); } + + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + define_arm_cp_regs(cpu, scxtnum_reginfo); + } #endif if (cpu_isar_feature(any_predinv, cpu)) { @@ -8537,12 +8940,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); } @@ -8585,106 +8993,186 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) return cpu_list; } +/* + * Private utility function for define_one_arm_cp_reg_with_opaque(): + * add a single reginfo struct to the hash table. + */ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, - void *opaque, int state, int secstate, + void *opaque, CPState state, + CPSecureState secstate, int crm, int opc1, int opc2, const char *name) { - /* Private utility function for define_one_arm_cp_reg_with_opaque(): - * add a single reginfo struct to the hash table. + CPUARMState *env = &cpu->env; + uint32_t key; + ARMCPRegInfo *r2; + bool is64 = r->type & ARM_CP_64BIT; + bool ns = secstate & ARM_CP_SECSTATE_NS; + int cp = r->cp; + size_t name_len; + bool make_const; + + switch (state) { + case ARM_CP_STATE_AA32: + /* We assume it is a cp15 register if the .cp field is left unset. */ + if (cp == 0 && r->state == ARM_CP_STATE_BOTH) { + cp = 15; + } + key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2); + break; + case ARM_CP_STATE_AA64: + /* + * To allow abbreviation of ARMCPRegInfo definitions, we treat + * cp == 0 as equivalent to the value for "standard guest-visible + * sysreg". STATE_BOTH definitions are also always "standard sysreg" + * in their AArch64 view (the .cp value may be non-zero for the + * benefit of the AArch32 view). + */ + if (cp == 0 || r->state == ARM_CP_STATE_BOTH) { + cp = CP_REG_ARM64_SYSREG_CP; + } + key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2); + break; + default: + g_assert_not_reached(); + } + + /* Overriding of an existing definition must be explicitly requested. */ + if (!(r->type & ARM_CP_OVERRIDE)) { + const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key); + if (oldreg) { + assert(oldreg->type & ARM_CP_OVERRIDE); + } + } + + /* + * Eliminate registers that are not present because the EL is missing. + * Doing this here makes it easier to put all registers for a given + * feature into the same ARMCPRegInfo array and define them all at once. */ - uint32_t *key = g_new(uint32_t, 1); - ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); - int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; - int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; + make_const = false; + if (arm_feature(env, ARM_FEATURE_EL3)) { + /* + * An EL2 register without EL2 but with EL3 is (usually) RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + int min_el = ctz32(r->access) / 2; + if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) { + if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) { + return; + } + make_const = !(r->type & ARM_CP_EL3_NO_EL2_KEEP); + } + } else { + CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2) + ? PL2_RW : PL1_RW); + if ((r->access & max_el) == 0) { + return; + } + } + + /* Combine cpreg and name into one allocation. */ + name_len = strlen(name) + 1; + r2 = g_malloc(sizeof(*r2) + name_len); + *r2 = *r; + r2->name = memcpy(r2 + 1, name, name_len); - r2->name = g_strdup(name); - /* Reset the secure state to the specific incoming state. This is - * necessary as the register may have been defined with both states. + /* + * Update fields to match the instantiation, overwiting wildcards + * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH. */ + r2->cp = cp; + r2->crm = crm; + r2->opc1 = opc1; + r2->opc2 = opc2; + r2->state = state; r2->secure = secstate; - - if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { - /* Register is banked (using both entries in array). - * Overwriting fieldoffset as the array is only used to define - * banked registers but later only fieldoffset is used. - */ - r2->fieldoffset = r->bank_fieldoffsets[ns]; + if (opaque) { + r2->opaque = opaque; } - if (state == ARM_CP_STATE_AA32) { - if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { - /* If the register is banked then we don't need to migrate or - * reset the 32-bit instance in certain cases: - * - * 1) If the register has both 32-bit and 64-bit instances then we - * can count on the 64-bit instance taking care of the - * non-secure bank. - * 2) If ARMv8 is enabled then we can count on a 64-bit version - * taking care of the secure bank. This requires that separate - * 32 and 64-bit definitions are provided. - */ - if ((r->state == ARM_CP_STATE_BOTH && ns) || - (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) { - r2->type |= ARM_CP_ALIAS; - } - } else if ((secstate != r->secure) && !ns) { - /* The register is not banked so we only want to allow migration of - * the non-secure instance. - */ - r2->type |= ARM_CP_ALIAS; + if (make_const) { + /* This should not have been a very special register to begin. */ + int old_special = r2->type & ARM_CP_SPECIAL_MASK; + assert(old_special == 0 || old_special == ARM_CP_NOP); + /* + * Set the special function to CONST, retaining the other flags. + * This is important for e.g. ARM_CP_SVE so that we still + * take the SVE trap if CPTR_EL3.EZ == 0. + */ + r2->type = (r2->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST; + /* + * Usually, these registers become RES0, but there are a few + * special cases like VPIDR_EL2 which have a constant non-zero + * value with writes ignored. + */ + if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) { + r2->resetvalue = 0; } + /* + * ARM_CP_CONST has precedence, so removing the callbacks and + * offsets are not strictly necessary, but it is potentially + * less confusing to debug later. + */ + r2->readfn = NULL; + r2->writefn = NULL; + r2->raw_readfn = NULL; + r2->raw_writefn = NULL; + r2->resetfn = NULL; + r2->fieldoffset = 0; + r2->bank_fieldoffsets[0] = 0; + r2->bank_fieldoffsets[1] = 0; + } else { + bool isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; - if (r->state == ARM_CP_STATE_BOTH) { - /* We assume it is a cp15 register if the .cp field is left unset. + if (isbanked) { + /* + * Register is banked (using both entries in array). + * Overwriting fieldoffset as the array is only used to define + * banked registers but later only fieldoffset is used. */ - if (r2->cp == 0) { - r2->cp = 15; + r2->fieldoffset = r->bank_fieldoffsets[ns]; + } + if (state == ARM_CP_STATE_AA32) { + if (isbanked) { + /* + * If the register is banked then we don't need to migrate or + * reset the 32-bit instance in certain cases: + * + * 1) If the register has both 32-bit and 64-bit instances + * then we can count on the 64-bit instance taking care + * of the non-secure bank. + * 2) If ARMv8 is enabled then we can count on a 64-bit + * version taking care of the secure bank. This requires + * that separate 32 and 64-bit definitions are provided. + */ + if ((r->state == ARM_CP_STATE_BOTH && ns) || + (arm_feature(env, ARM_FEATURE_V8) && !ns)) { + r2->type |= ARM_CP_ALIAS; + } + } else if ((secstate != r->secure) && !ns) { + /* + * The register is not banked so we only want to allow + * migration of the non-secure instance. + */ + r2->type |= ARM_CP_ALIAS; } -#ifdef HOST_WORDS_BIGENDIAN - if (r2->fieldoffset) { + if (HOST_BIG_ENDIAN && + r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { r2->fieldoffset += sizeof(uint32_t); } -#endif } } - if (state == ARM_CP_STATE_AA64) { - /* To allow abbreviation of ARMCPRegInfo - * definitions, we treat cp == 0 as equivalent to - * the value for "standard guest-visible sysreg". - * STATE_BOTH definitions are also always "standard - * sysreg" in their AArch64 view (the .cp value may - * be non-zero for the benefit of the AArch32 view). - */ - if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) { - r2->cp = CP_REG_ARM64_SYSREG_CP; - } - *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm, - r2->opc0, opc1, opc2); - } else { - *key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2); - } - if (opaque) { - r2->opaque = opaque; - } - /* reginfo passed to helpers is correct for the actual access, - * and is never ARM_CP_STATE_BOTH: - */ - r2->state = state; - /* Make sure reginfo passed to helpers for wildcarded regs - * has the correct crm/opc1/opc2 for this reg, not CP_ANY: - */ - r2->crm = crm; - r2->opc1 = opc1; - r2->opc2 = opc2; - /* By convention, for wildcarded registers only the first + + /* + * By convention, for wildcarded registers only the first * entry is used for migration; the others are marked as * ALIAS so we don't try to transfer the register * multiple times. Special registers (ie NOP/WFI) are * never migratable and not even raw-accessible. */ - if ((r->type & ARM_CP_SPECIAL)) { + if (r2->type & ARM_CP_SPECIAL_MASK) { r2->type |= ARM_CP_NO_RAW; } if (((r->crm == CP_ANY) && crm != 0) || @@ -8693,7 +9181,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB; } - /* Check that raw accesses are either forbidden or handled. Note that + /* + * Check that raw accesses are either forbidden or handled. Note that * we can't assert this earlier because the setup of fieldoffset for * banked registers has to be done first. */ @@ -8701,29 +9190,15 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, assert(!raw_accessors_invalid(r2)); } - /* Overriding of an existing definition must be explicitly - * requested. - */ - if (!(r->type & ARM_CP_OVERRIDE)) { - ARMCPRegInfo *oldreg; - oldreg = g_hash_table_lookup(cpu->cp_regs, key); - if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) { - fprintf(stderr, "Register redefined: cp=%d %d bit " - "crn=%d crm=%d opc1=%d opc2=%d, " - "was %s, now %s\n", r2->cp, 32 + 32 * is64, - r2->crn, r2->crm, r2->opc1, r2->opc2, - oldreg->name, r2->name); - g_assert_not_reached(); - } - } - g_hash_table_insert(cpu->cp_regs, key, r2); + g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2); } void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *r, void *opaque) { - /* Define implementations of coprocessor registers. + /* + * Define implementations of coprocessor registers. * We store these in a hashtable because typically * there are less than 150 registers in a space which * is 16*16*16*8*8 = 262144 in size. @@ -8746,13 +9221,15 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of * the register, if any. */ - int crm, opc1, opc2, state; + int crm, opc1, opc2; int crmmin = (r->crm == CP_ANY) ? 0 : r->crm; int crmmax = (r->crm == CP_ANY) ? 15 : r->crm; int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1; int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1; int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2; int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2; + CPState state; + /* 64 bit registers have only CRm and Opc1 fields */ assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn))); /* op0 only exists in the AArch64 encodings */ @@ -8788,14 +9265,15 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, default: g_assert_not_reached(); } - /* The AArch64 pseudocode CheckSystemAccess() specifies that op1 + /* + * The AArch64 pseudocode CheckSystemAccess() specifies that op1 * encodes a minimum access level for the register. We roll this * runtime check into our general permission check code, so check * here that the reginfo's specified permissions are strict enough * to encompass the generic architectural permission check. */ if (r->state != ARM_CP_STATE_AA32) { - int mask = 0; + CPAccessRights mask; switch (r->opc1) { case 0: /* min_EL EL1, but some accessible to EL0 via kernel ABI */ @@ -8824,17 +9302,17 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, break; default: /* broken reginfo with out-of-range opc1 */ - assert(false); - break; + g_assert_not_reached(); } /* assert our permissions are not too lax (stricter is fine) */ assert((r->access & ~mask) == 0); } - /* Check that the register definition has enough info to handle + /* + * Check that the register definition has enough info to handle * reads and writes if they are permitted. */ - if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) { + if (!(r->type & (ARM_CP_SPECIAL_MASK | ARM_CP_CONST))) { if (r->access & PL3_R) { assert((r->fieldoffset || (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) || @@ -8846,8 +9324,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, r->writefn); } } - /* Bad type field probably means missing sentinel at end of reg list */ - assert(cptype_valid(r->type)); + for (crm = crmmin; crm <= crmmax; crm++) { for (opc1 = opc1min; opc1 <= opc1max; opc1++) { for (opc2 = opc2min; opc2 <= opc2max; opc2++) { @@ -8857,7 +9334,8 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, continue; } if (state == ARM_CP_STATE_AA32) { - /* Under AArch32 CP registers can be common + /* + * Under AArch32 CP registers can be common * (same for secure and non-secure world) or banked. */ char *name; @@ -8869,7 +9347,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, r->secure, crm, opc1, opc2, r->name); break; - default: + case ARM_CP_SECSTATE_BOTH: name = g_strdup_printf("%s_S", r->name); add_cpreg_to_hashtable(cpu, r, opaque, state, ARM_CP_SECSTATE_S, @@ -8879,10 +9357,14 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, ARM_CP_SECSTATE_NS, crm, opc1, opc2, r->name); break; + default: + g_assert_not_reached(); } } else { - /* AArch64 registers get mapped to non-secure instance - * of AArch32 */ + /* + * AArch64 registers get mapped to non-secure instance + * of AArch32 + */ add_cpreg_to_hashtable(cpu, r, opaque, state, ARM_CP_SECSTATE_NS, crm, opc1, opc2, r->name); @@ -8893,13 +9375,13 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, } } -void define_arm_cp_regs_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque) +/* Define a whole list of registers */ +void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs, + void *opaque, size_t len) { - /* Define a whole list of registers */ - const ARMCPRegInfo *r; - for (r = regs; r->type != ARM_CP_SENTINEL; r++) { - define_one_arm_cp_reg_with_opaque(cpu, r, opaque); + size_t i; + for (i = 0; i < len; ++i) { + define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque); } } @@ -8911,17 +9393,20 @@ void define_arm_cp_regs_with_opaque(ARMCPU *cpu, * user-space cannot alter any values and dynamic values pertaining to * execution state are hidden from user space view anyway. */ -void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods) +void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len, + const ARMCPRegUserSpaceInfo *mods, + size_t mods_len) { - const ARMCPRegUserSpaceInfo *m; - ARMCPRegInfo *r; - - for (m = mods; m->name; m++) { + for (size_t mi = 0; mi < mods_len; ++mi) { + const ARMCPRegUserSpaceInfo *m = mods + mi; GPatternSpec *pat = NULL; + if (m->is_glob) { pat = g_pattern_spec_new(m->name); } - for (r = regs; r->type != ARM_CP_SENTINEL; r++) { + for (size_t ri = 0; ri < regs_len; ++ri) { + ARMCPRegInfo *r = regs + ri; + if (pat && g_pattern_match_string(pat, r->name)) { r->type = ARM_CP_CONST; r->access = PL0U_R; @@ -8943,7 +9428,7 @@ void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods) const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp) { - return g_hash_table_lookup(cpregs, &encoded_cp); + return g_hash_table_lookup(cpregs, (gpointer)(uintptr_t)encoded_cp); } void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, @@ -8965,7 +9450,8 @@ void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque) static int bad_mode_switch(CPUARMState *env, int mode, CPSRWriteType write_type) { - /* Return true if it is not valid for us to switch to + /* + * Return true if it is not valid for us to switch to * this CPU mode (ie all the UNPREDICTABLE cases in * the ARM ARM CPSRWriteByInstr pseudocode). */ @@ -8986,10 +9472,12 @@ static int bad_mode_switch(CPUARMState *env, int mode, CPSRWriteType write_type) case ARM_CPU_MODE_UND: case ARM_CPU_MODE_IRQ: case ARM_CPU_MODE_FIQ: - /* Note that we don't implement the IMPDEF NSACR.RFR which in v7 + /* + * Note that we don't implement the IMPDEF NSACR.RFR which in v7 * allows FIQ mode to be Secure-only. (In v8 this doesn't exist.) */ - /* If HCR.TGE is set then changes from Monitor to NS PL1 via MSR + /* + * If HCR.TGE is set then changes from Monitor to NS PL1 via MSR * and CPS are treated as illegal mode changes. */ if (write_type == CPSRWriteByInstr && @@ -9031,10 +9519,12 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, env->CF = (val >> 29) & 1; env->VF = (val << 3) & 0x80000000; } - if (mask & CPSR_Q) + if (mask & CPSR_Q) { env->QF = ((val & CPSR_Q) != 0); - if (mask & CPSR_T) + } + if (mask & CPSR_T) { env->thumb = ((val & CPSR_T) != 0); + } if (mask & CPSR_IT_0_1) { env->condexec_bits &= ~3; env->condexec_bits |= (val >> 25) & 3; @@ -9047,7 +9537,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, env->GE = (val >> 16) & 0xf; } - /* In a V7 implementation that includes the security extensions but does + /* + * In a V7 implementation that includes the security extensions but does * not include Virtualization Extensions the SCR.FW and SCR.AW bits control * whether non-secure software is allowed to change the CPSR_F and CPSR_A * bits respectively. @@ -9063,7 +9554,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, changed_daif = (env->daif ^ val) & mask; if (changed_daif & CPSR_A) { - /* Check to see if we are allowed to change the masking of async + /* + * Check to see if we are allowed to change the masking of async * abort exceptions from a non-secure state. */ if (!(env->cp15.scr_el3 & SCR_AW)) { @@ -9075,7 +9567,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, } if (changed_daif & CPSR_F) { - /* Check to see if we are allowed to change the masking of FIQ + /* + * Check to see if we are allowed to change the masking of FIQ * exceptions from a non-secure state. */ if (!(env->cp15.scr_el3 & SCR_FW)) { @@ -9085,7 +9578,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, mask &= ~CPSR_F; } - /* Check whether non-maskable FIQ (NMFI) support is enabled. + /* + * Check whether non-maskable FIQ (NMFI) support is enabled. * If this bit is set software is not allowed to mask * FIQs, but is allowed to set CPSR_F to 0. */ @@ -9105,7 +9599,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, if (write_type != CPSRWriteRaw && ((env->uncached_cpsr ^ val) & mask & CPSR_M)) { if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) { - /* Note that we can only get here in USR mode if this is a + /* + * Note that we can only get here in USR mode if this is a * gdb stub write; for this case we follow the architectural * behaviour for guest writes in USR mode of ignoring an attempt * to switch mode. (Those are caught by translate.c for writes @@ -9113,7 +9608,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, */ mask &= ~CPSR_M; } else if (bad_mode_switch(env, val & CPSR_M, write_type)) { - /* Attempt to switch to an invalid mode: this is UNPREDICTABLE in + /* + * Attempt to switch to an invalid mode: this is UNPREDICTABLE in * v7, and has defined behaviour in v8: * + leave CPSR.M untouched * + allow changes to the other CPSR fields @@ -9233,15 +9729,16 @@ static void switch_mode(CPUARMState *env, int mode) int i; old_mode = env->uncached_cpsr & CPSR_M; - if (mode == old_mode) + if (mode == old_mode) { return; + } if (old_mode == ARM_CPU_MODE_FIQ) { - memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); - memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); + memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); } else if (mode == ARM_CPU_MODE_FIQ) { - memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); - memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); + memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); } i = bank_number(old_mode); @@ -9256,7 +9753,8 @@ static void switch_mode(CPUARMState *env, int mode) env->regs[14] = env->banked_r14[r14_bank_number(mode)]; } -/* Physical Interrupt Target EL Lookup Table +/* + * Physical Interrupt Target EL Lookup Table * * [ From ARM ARM section G1.13.4 (Table G1-15) ] * @@ -9330,7 +9828,8 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, if (arm_feature(env, ARM_FEATURE_EL3)) { rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); } else { - /* Either EL2 is the highest EL (and so the EL2 register width + /* + * Either EL2 is the highest EL (and so the EL2 register width * is given by is64); or there is no EL2 or EL3, in which case * the value of 'rw' does not affect the table lookup anyway. */ @@ -9396,6 +9895,7 @@ void arm_log_exception(CPUState *cs) [EXCP_LSERR] = "v8M LSERR UsageFault", [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault", [EXCP_DIVBYZERO] = "v7M DIVBYZERO UsageFault", + [EXCP_VSERR] = "Virtual SERR", }; if (idx >= 0 && idx < ARRAY_SIZE(excnames)) { @@ -9604,7 +10104,8 @@ void aarch64_sync_64_to_32(CPUARMState *env) env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23]; } - /* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ + /* + * Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ * mode, then we can copy to r8-r14. Otherwise, we copy to the * FIQ bank for r8-r14. */ @@ -9836,10 +10337,11 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) new_mode = ARM_CPU_MODE_UND; addr = 0x04; mask = CPSR_I; - if (env->thumb) + if (env->thumb) { offset = 2; - else + } else { offset = 4; + } break; case EXCP_SWI: new_mode = ARM_CPU_MODE_SVC; @@ -9908,6 +10410,31 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) mask = CPSR_A | CPSR_I | CPSR_F; offset = 4; break; + case EXCP_VSERR: + { + /* + * Note that this is reported as a data abort, but the DFAR + * has an UNKNOWN value. Construct the SError syndrome from + * AET and ExT fields. + */ + ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal, }; + + if (extended_addresses_enabled(env)) { + env->exception.fsr = arm_fi_to_lfsc(&fi); + } else { + env->exception.fsr = arm_fi_to_sfsc(&fi); + } + env->exception.fsr |= env->cp15.vsesr_el2 & 0xd000; + A32_BANKED_CURRENT_REG_SET(env, dfsr, env->exception.fsr); + qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x\n", + env->exception.fsr); + + new_mode = ARM_CPU_MODE_ABT; + addr = 0x10; + mask = CPSR_A | CPSR_I; + offset = 8; + } + break; case EXCP_SMC: new_mode = ARM_CPU_MODE_MON; addr = 0x08; @@ -9925,7 +10452,8 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) /* High vectors. When enabled, base address cannot be remapped. */ addr += 0xffff0000; } else { - /* ARM v7 architectures provide a vector base address register to remap + /* + * ARM v7 architectures provide a vector base address register to remap * the interrupt vector table. * This register is only followed in non-monitor mode, and is banked. * Note: only bits 31:5 are valid. @@ -10015,6 +10543,31 @@ static uint32_t cpsr_read_for_spsr_elx(CPUARMState *env) return ret; } +static bool syndrome_is_sync_extabt(uint32_t syndrome) +{ + /* Return true if this syndrome value is a synchronous external abort */ + switch (syn_get_ec(syndrome)) { + case EC_INSNABORT: + case EC_INSNABORT_SAME_EL: + case EC_DATAABORT: + case EC_DATAABORT_SAME_EL: + /* Look at fault status code for all the synchronous ext abort cases */ + switch (syndrome & 0x3f) { + case 0x10: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return true; + default: + return false; + } + default: + return false; + } +} + /* Handle exception entry to a target EL which is using AArch64 */ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) { @@ -10034,7 +10587,8 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) aarch64_sve_change_el(env, cur_el, new_el, is_a64(env)); if (cur_el < new_el) { - /* Entry vector offset depends on whether the implemented EL + /* + * Entry vector offset depends on whether the implemented EL * immediately lower than the target level is using AArch32 or AArch64 */ bool is_aa64; @@ -10070,6 +10624,14 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) switch (cs->exception_index) { case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: + /* + * FEAT_DoubleFault allows synchronous external aborts taken to EL3 + * to be taken to the SError vector entrypoint. + */ + if (new_el == 3 && (env->cp15.scr_el3 & SCR_EASE) && + syndrome_is_sync_extabt(env->exception.syndrome)) { + addr += 0x180; + } env->cp15.far_el[new_el] = env->exception.vaddress; qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n", env->cp15.far_el[new_el]); @@ -10128,6 +10690,12 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) case EXCP_VFIQ: addr += 0x100; break; + case EXCP_VSERR: + addr += 0x180; + /* Construct the SError syndrome from IDS and ISS fields. */ + env->exception.syndrome = syn_serror(env->cp15.vsesr_el2 & 0x1ffffff); + env->cp15.esr_el[new_el] = env->exception.syndrome; + break; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } @@ -10182,7 +10750,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) } pstate_write(env, PSTATE_DAIF | new_mode); - env->aarch64 = 1; + env->aarch64 = true; aarch64_restore_sp(env, new_el); helper_rebuild_hflags_a64(env, new_el); @@ -10209,19 +10777,20 @@ static void handle_semihosting(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "...handling as semihosting call 0x%" PRIx64 "\n", env->xregs[0]); - env->xregs[0] = do_common_semihosting(cs); + do_common_semihosting(cs); env->pc += 4; } else { qemu_log_mask(CPU_LOG_INT, "...handling as semihosting call 0x%x\n", env->regs[0]); - env->regs[0] = do_common_semihosting(cs); + do_common_semihosting(cs); env->regs[15] += env->thumb ? 2 : 4; } } #endif -/* Handle a CPU exception for A and R profile CPUs. +/* + * Handle a CPU exception for A and R profile CPUs. * Do any appropriate logging, handle PSCI calls, and then hand off * to the AArch64-entry or AArch32-entry function depending on the * target exception level's register width. @@ -10266,7 +10835,8 @@ void arm_cpu_do_interrupt(CPUState *cs) } #endif - /* Hooks may change global state so BQL should be held, also the + /* + * Hooks may change global state so BQL should be held, also the * BQL needs to be held for any modification of * cs->interrupt_request. */ @@ -10294,2591 +10864,264 @@ 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]; } -/* Return the SCTLR value which controls this address translation regime */ -static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - return env->cp15.sctlr_el[regime_el(env, mmu_idx)]; -} - -#ifndef CONFIG_USER_ONLY - -/* Return true if the specified stage of address translation is disabled */ -static inline bool regime_translation_disabled(CPUARMState *env, - ARMMMUIdx mmu_idx) -{ - uint64_t hcr_el2; - - if (arm_feature(env, ARM_FEATURE_M)) { - switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] & - (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 */ - return mmu_idx & ARM_MMU_IDX_M_NEGPRI; - case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: - /* Enabled for all cases */ - return false; - case 0: - default: - /* HFNMIENA set and ENABLE clear is UNPREDICTABLE, but - * we warned about that in armv7m_nvic.c when the guest set it. - */ - return true; - } - } - - hcr_el2 = arm_hcr_el2_eff(env); - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == 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) { - return true; - } - } - - if ((hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) { - /* HCR.DC means SCTLR_EL1.M behaves as 0 */ - return true; - } - - return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; -} - -static inline bool regime_translation_big_endian(CPUARMState *env, - ARMMMUIdx mmu_idx) +int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) { - return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; -} - -/* Return the TTBR associated with this translation regime */ -static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, - int ttbrn) -{ - if (mmu_idx == ARMMMUIdx_Stage2) { - return env->cp15.vttbr_el2; - } - if (mmu_idx == ARMMMUIdx_Stage2_S) { - return env->cp15.vsttbr_el2; - } - if (ttbrn == 0) { - return env->cp15.ttbr0_el[regime_el(env, mmu_idx)]; + if (regime_has_2_ranges(mmu_idx)) { + return extract64(tcr, 37, 2); + } else if (regime_is_stage2(mmu_idx)) { + return 0; /* VTCR_EL2 */ } else { - return env->cp15.ttbr1_el[regime_el(env, mmu_idx)]; - } -} - -#endif /* !CONFIG_USER_ONLY */ - -/* Convert a possible stage1+2 MMU index into the appropriate - * stage 1 MMU index - */ -static inline 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: - return ARMMMUIdx_Stage1_E1; - case ARMMMUIdx_E10_1_PAN: - return ARMMMUIdx_Stage1_E1_PAN; - default: - return mmu_idx; - } -} - -/* Return true if the translation regime is using LPAE format page tables */ -static inline bool regime_using_lpae_format(CPUARMState *env, - ARMMMUIdx mmu_idx) -{ - int el = regime_el(env, mmu_idx); - if (el == 2 || arm_el_is_aa64(env, el)) { - return true; - } - if (arm_feature(env, ARM_FEATURE_LPAE) - && (regime_tcr(env, mmu_idx)->raw_tcr & TTBCR_EAE)) { - return true; + /* Replicate the single TBI bit so we always have 2 bits. */ + return extract32(tcr, 20, 1) * 3; } - return false; -} - -/* Returns true if the stage 1 translation regime is using LPAE format page - * tables. Used when raising alignment exceptions, whose FSR changes depending - * on whether the long or short descriptor format is in use. */ -bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - mmu_idx = stage_1_mmu_idx(mmu_idx); - - return regime_using_lpae_format(env, mmu_idx); } -#ifndef CONFIG_USER_ONLY -static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) +int aa64_va_parameter_tbid(uint64_t tcr, 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: - case ARMMMUIdx_MSUserNegPri: - return true; - default: - return false; - case ARMMMUIdx_E10_0: - case ARMMMUIdx_E10_1: - case ARMMMUIdx_E10_1_PAN: - g_assert_not_reached(); + if (regime_has_2_ranges(mmu_idx)) { + return extract64(tcr, 51, 2); + } else if (regime_is_stage2(mmu_idx)) { + return 0; /* VTCR_EL2 */ + } else { + /* Replicate the single TBID bit so we always have 2 bits. */ + return extract32(tcr, 29, 1) * 3; } } -/* Translate section/page access permissions to page - * R/W protection flags - * - * @env: CPUARMState - * @mmu_idx: MMU index indicating required translation regime - * @ap: The 3-bit access permissions (AP[2:0]) - * @domain_prot: The 2-bit domain access permissions - */ -static inline int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, - int ap, int domain_prot) +static int aa64_va_parameter_tcma(uint64_t tcr, ARMMMUIdx mmu_idx) { - bool is_user = regime_is_user(env, mmu_idx); - - if (domain_prot == 3) { - return PAGE_READ | PAGE_WRITE; - } - - switch (ap) { - case 0: - if (arm_feature(env, ARM_FEATURE_V7)) { - return 0; - } - switch (regime_sctlr(env, mmu_idx) & (SCTLR_S | SCTLR_R)) { - case SCTLR_S: - return is_user ? 0 : PAGE_READ; - case SCTLR_R: - return PAGE_READ; - default: - return 0; - } - case 1: - return is_user ? 0 : PAGE_READ | PAGE_WRITE; - case 2: - if (is_user) { - return PAGE_READ; - } else { - return PAGE_READ | PAGE_WRITE; - } - case 3: - return PAGE_READ | PAGE_WRITE; - case 4: /* Reserved. */ - return 0; - case 5: - return is_user ? 0 : PAGE_READ; - case 6: - return PAGE_READ; - case 7: - if (!arm_feature(env, ARM_FEATURE_V6K)) { - return 0; - } - return PAGE_READ; - default: - g_assert_not_reached(); + if (regime_has_2_ranges(mmu_idx)) { + return extract64(tcr, 57, 2); + } else { + /* Replicate the single TCMA bit so we always have 2 bits. */ + return extract32(tcr, 30, 1) * 3; } } -/* Translate section/page access permissions to page - * R/W protection flags. - * - * @ap: The 2-bit simple AP (AP[2:1]) - * @is_user: TRUE if accessing from PL0 - */ -static inline int simple_ap_to_rw_prot_is_user(int ap, bool is_user) +static ARMGranuleSize tg0_to_gran_size(int tg) { - switch (ap) { + switch (tg) { case 0: - return is_user ? 0 : PAGE_READ | PAGE_WRITE; + return Gran4K; case 1: - return PAGE_READ | PAGE_WRITE; + return Gran64K; case 2: - return is_user ? 0 : PAGE_READ; - case 3: - return PAGE_READ; + return Gran16K; default: - g_assert_not_reached(); - } -} - -static inline int -simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) -{ - return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); -} - -/* Translate S2 section/page access permissions to protection flags - * - * @env: CPUARMState - * @s2ap: The 2-bit stage2 access permissions (S2AP) - * @xn: XN (execute-never) bits - * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 - */ -static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) -{ - int prot = 0; - - if (s2ap & 1) { - prot |= PAGE_READ; - } - if (s2ap & 2) { - prot |= PAGE_WRITE; - } - - if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) { - switch (xn) { - case 0: - prot |= PAGE_EXEC; - break; - case 1: - if (s1_is_el0) { - prot |= PAGE_EXEC; - } - break; - case 2: - break; - case 3: - if (!s1_is_el0) { - prot |= PAGE_EXEC; - } - break; - default: - g_assert_not_reached(); - } - } else { - if (!extract32(xn, 1, 1)) { - if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) { - prot |= PAGE_EXEC; - } - } - } - return prot; -} - -/* Translate section/page access permissions to protection flags - * - * @env: CPUARMState - * @mmu_idx: MMU index indicating required translation regime - * @is_aa64: TRUE if AArch64 - * @ap: The 2-bit simple AP (AP[2:1]) - * @ns: NS (non-secure) bit - * @xn: XN (execute-never) bit - * @pxn: PXN (privileged execute-never) bit - */ -static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int ns, int xn, int pxn) -{ - bool is_user = regime_is_user(env, mmu_idx); - int prot_rw, user_rw; - bool have_wxn; - int wxn = 0; - - assert(mmu_idx != ARMMMUIdx_Stage2); - assert(mmu_idx != ARMMMUIdx_Stage2_S); - - user_rw = simple_ap_to_rw_prot_is_user(ap, true); - if (is_user) { - prot_rw = user_rw; - } else { - if (user_rw && regime_is_pan(env, mmu_idx)) { - /* PAN forbids data accesses but doesn't affect insn fetch */ - prot_rw = 0; - } else { - prot_rw = simple_ap_to_rw_prot_is_user(ap, false); - } - } - - if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { - return prot_rw; - } - - /* TODO have_wxn should be replaced with - * ARM_FEATURE_V8 || (ARM_FEATURE_V7 && ARM_FEATURE_EL2) - * when ARM_FEATURE_EL2 starts getting set. For now we assume all LPAE - * compatible processors have EL2, which is required for [U]WXN. - */ - have_wxn = arm_feature(env, ARM_FEATURE_LPAE); - - if (have_wxn) { - wxn = regime_sctlr(env, mmu_idx) & SCTLR_WXN; - } - - if (is_aa64) { - if (regime_has_2_ranges(mmu_idx) && !is_user) { - xn = pxn || (user_rw & PAGE_WRITE); - } - } else if (arm_feature(env, ARM_FEATURE_V7)) { - switch (regime_el(env, mmu_idx)) { - case 1: - case 3: - if (is_user) { - xn = xn || !(user_rw & PAGE_READ); - } else { - int uwxn = 0; - if (have_wxn) { - uwxn = regime_sctlr(env, mmu_idx) & SCTLR_UWXN; - } - xn = xn || !(prot_rw & PAGE_READ) || pxn || - (uwxn && (user_rw & PAGE_WRITE)); - } - break; - case 2: - break; - } - } else { - xn = wxn = 0; - } - - if (xn || (wxn && (prot_rw & PAGE_WRITE))) { - return prot_rw; - } - return prot_rw | PAGE_EXEC; -} - -static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, - uint32_t *table, uint32_t address) -{ - /* Note that we can only get here for an AArch32 PL0/PL1 lookup */ - TCR *tcr = regime_tcr(env, mmu_idx); - - if (address & tcr->mask) { - if (tcr->raw_tcr & TTBCR_PD1) { - /* Translation table walk disabled for TTBR1 */ - return false; - } - *table = regime_ttbr(env, mmu_idx, 1) & 0xffffc000; - } else { - if (tcr->raw_tcr & TTBCR_PD0) { - /* Translation table walk disabled for TTBR0 */ - return false; - } - *table = regime_ttbr(env, mmu_idx, 0) & tcr->base_mask; - } - *table |= (address >> 18) & 0x3ffc; - return true; -} - -/* Translate a S1 pagetable walk through S2 if needed. */ -static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, - hwaddr addr, bool *is_secure, - 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 = {}; - - ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, false, - &s2pa, &txattrs, &s2prot, &s2size, fi, - &cacheattrs); - if (ret) { - assert(fi->type != ARMFault_None); - fi->s2addr = addr; - fi->stage2 = true; - fi->s1ptw = true; - fi->s1ns = !*is_secure; - return ~0; - } - if ((arm_hcr_el2_eff(env) & HCR_PTW) && - (cacheattrs.attrs & 0xf0) == 0) { - /* - * PTW set and S1 walk touched S2 Device memory: - * generate Permission fault. - */ - fi->type = ARMFault_Permission; - fi->s2addr = addr; - fi->stage2 = true; - fi->s1ptw = true; - 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.raw_tcr & VSTCR_SW); - } else { - *is_secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW); - } - } else { - assert(!*is_secure); - } - - addr = s2pa; - } - return addr; -} - -/* All loads done in the course of a page table walk go through here. */ -static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; - MemTxResult result = MEMTX_OK; - AddressSpace *as; - uint32_t data; - - addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); - attrs.secure = is_secure; - as = arm_addressspace(cs, attrs); - if (fi->s1ptw) { - return 0; - } - if (regime_translation_big_endian(env, mmu_idx)) { - data = address_space_ldl_be(as, addr, attrs, &result); - } else { - data = address_space_ldl_le(as, addr, attrs, &result); - } - if (result == MEMTX_OK) { - return data; - } - fi->type = ARMFault_SyncExternalOnWalk; - fi->ea = arm_extabort_type(result); - return 0; -} - -static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; - MemTxResult result = MEMTX_OK; - AddressSpace *as; - uint64_t data; - - addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); - attrs.secure = is_secure; - as = arm_addressspace(cs, attrs); - if (fi->s1ptw) { - return 0; - } - if (regime_translation_big_endian(env, mmu_idx)) { - data = address_space_ldq_be(as, addr, attrs, &result); - } else { - data = address_space_ldq_le(as, addr, attrs, &result); - } - if (result == MEMTX_OK) { - return data; + return GranInvalid; } - fi->type = ARMFault_SyncExternalOnWalk; - fi->ea = arm_extabort_type(result); - return 0; -} - -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, - ARMMMUFaultInfo *fi) -{ - CPUState *cs = env_cpu(env); - int level = 1; - uint32_t table; - uint32_t desc; - int type; - int ap; - int domain = 0; - int domain_prot; - hwaddr phys_addr; - uint32_t dacr; - - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - if (!get_level1_table_address(env, mmu_idx, &table, address)) { - /* Section translation fault if page walk is disabled by PD0 or PD1 */ - fi->type = ARMFault_Translation; - goto do_fault; - } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - type = (desc & 3); - domain = (desc >> 5) & 0x0f; - if (regime_el(env, mmu_idx) == 1) { - dacr = env->cp15.dacr_ns; - } else { - dacr = env->cp15.dacr_s; - } - domain_prot = (dacr >> (domain * 2)) & 3; - if (type == 0) { - /* Section translation fault. */ - fi->type = ARMFault_Translation; - goto do_fault; - } - if (type != 2) { - level = 2; - } - if (domain_prot == 0 || domain_prot == 2) { - fi->type = ARMFault_Domain; - goto do_fault; - } - if (type == 2) { - /* 1Mb section. */ - phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - ap = (desc >> 10) & 3; - *page_size = 1024 * 1024; - } else { - /* Lookup l2 entry. */ - if (type == 1) { - /* Coarse pagetable. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - } else { - /* Fine pagetable. */ - table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); - } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - switch (desc & 3) { - case 0: /* Page translation fault. */ - fi->type = ARMFault_Translation; - goto do_fault; - case 1: /* 64k page. */ - phys_addr = (desc & 0xffff0000) | (address & 0xffff); - ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - *page_size = 0x10000; - break; - case 2: /* 4k page. */ - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - ap = (desc >> (4 + ((address >> 9) & 6))) & 3; - *page_size = 0x1000; - break; - case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */ - if (type == 1) { - /* ARMv6/XScale extended small page format */ - if (arm_feature(env, ARM_FEATURE_XSCALE) - || arm_feature(env, ARM_FEATURE_V6)) { - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - *page_size = 0x1000; - } else { - /* UNPREDICTABLE in ARMv5; we choose to take a - * page translation fault. - */ - fi->type = ARMFault_Translation; - goto do_fault; - } - } else { - phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - *page_size = 0x400; - } - ap = (desc >> 4) & 3; - break; - default: - /* Never happens, but compiler isn't smart enough to tell. */ - abort(); - } - } - *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); - *prot |= *prot ? PAGE_EXEC : 0; - if (!(*prot & (1 << access_type))) { - /* Access permission fault. */ - fi->type = ARMFault_Permission; - goto do_fault; - } - *phys_ptr = phys_addr; - return false; -do_fault: - fi->domain = domain; - fi->level = level; - return true; -} - -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) -{ - CPUState *cs = env_cpu(env); - ARMCPU *cpu = env_archcpu(env); - int level = 1; - uint32_t table; - uint32_t desc; - uint32_t xn; - uint32_t pxn = 0; - int type; - int ap; - int domain = 0; - int domain_prot; - hwaddr phys_addr; - uint32_t dacr; - bool ns; - - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - if (!get_level1_table_address(env, mmu_idx, &table, address)) { - /* Section translation fault if page walk is disabled by PD0 or PD1 */ - fi->type = ARMFault_Translation; - goto do_fault; - } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - type = (desc & 3); - if (type == 0 || (type == 3 && !cpu_isar_feature(aa32_pxn, cpu))) { - /* Section translation fault, or attempt to use the encoding - * which is Reserved on implementations without PXN. - */ - fi->type = ARMFault_Translation; - goto do_fault; - } - if ((type == 1) || !(desc & (1 << 18))) { - /* Page or Section. */ - domain = (desc >> 5) & 0x0f; - } - if (regime_el(env, mmu_idx) == 1) { - dacr = env->cp15.dacr_ns; - } else { - dacr = env->cp15.dacr_s; - } - if (type == 1) { - level = 2; - } - domain_prot = (dacr >> (domain * 2)) & 3; - if (domain_prot == 0 || domain_prot == 2) { - /* Section or Page domain fault */ - fi->type = ARMFault_Domain; - goto do_fault; - } - if (type != 1) { - if (desc & (1 << 18)) { - /* Supersection. */ - 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; - } else { - /* Section. */ - phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - *page_size = 0x100000; - } - ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); - xn = desc & (1 << 4); - pxn = desc & 1; - ns = extract32(desc, 19, 1); - } else { - if (cpu_isar_feature(aa32_pxn, cpu)) { - pxn = (desc >> 2) & 1; - } - ns = extract32(desc, 3, 1); - /* Lookup l2 entry. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); - switch (desc & 3) { - case 0: /* Page translation fault. */ - fi->type = ARMFault_Translation; - goto do_fault; - case 1: /* 64k page. */ - phys_addr = (desc & 0xffff0000) | (address & 0xffff); - xn = desc & (1 << 15); - *page_size = 0x10000; - break; - case 2: case 3: /* 4k page. */ - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - xn = desc & 1; - *page_size = 0x1000; - break; - default: - /* Never happens, but compiler isn't smart enough to tell. */ - abort(); - } - } - if (domain_prot == 3) { - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - } else { - if (pxn && !regime_is_user(env, mmu_idx)) { - xn = 1; - } - if (xn && access_type == MMU_INST_FETCH) { - fi->type = ARMFault_Permission; - goto do_fault; - } - - if (arm_feature(env, ARM_FEATURE_V6K) && - (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { - /* The simplified model uses AP[0] as an access control bit. */ - if ((ap & 1) == 0) { - /* Access flag fault. */ - fi->type = ARMFault_AccessFlag; - goto do_fault; - } - *prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); - } else { - *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); - } - if (*prot && !xn) { - *prot |= PAGE_EXEC; - } - if (!(*prot & (1 << access_type))) { - /* Access permission fault. */ - fi->type = ARMFault_Permission; - goto do_fault; - } - } - if (ns) { - /* The NS bit will (as required by the architecture) have no effect if - * 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; - } - *phys_ptr = phys_addr; - return false; -do_fault: - fi->domain = domain; - fi->level = level; - return true; -} - -/* - * check_s2_mmu_setup - * @cpu: ARMCPU - * @is_aa64: True if the translation regime is in AArch64 state - * @startlevel: Suggested starting level - * @inputsize: Bitsize of IPAs - * @stride: Page-table stride (See the ARM ARM) - * - * Returns true if the suggested S2 translation parameters are OK and - * false otherwise. - */ -static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, - int inputsize, int stride, int outputsize) -{ - const int grainsize = stride + 3; - int startsizecheck; - - /* - * Negative levels are usually not allowed... - * Except for FEAT_LPA2, 4k page table, 52-bit address space, which - * begins with level -1. Note that previous feature tests will have - * eliminated this combination if it is not enabled. - */ - if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) { - return false; - } - - startsizecheck = inputsize - ((3 - level) * stride + grainsize); - if (startsizecheck < 1 || startsizecheck > stride + 4) { - return false; - } - - if (is_aa64) { - switch (stride) { - case 13: /* 64KB Pages. */ - if (level == 0 || (level == 1 && outputsize <= 42)) { - return false; - } - break; - case 11: /* 16KB Pages. */ - if (level == 0 || (level == 1 && outputsize <= 40)) { - return false; - } - break; - case 9: /* 4KB Pages. */ - if (level == 0 && outputsize <= 42) { - return false; - } - break; - default: - g_assert_not_reached(); - } - - /* Inputsize checks. */ - if (inputsize > outputsize && - (arm_el_is_aa64(&cpu->env, 1) || inputsize > 40)) { - /* This is CONSTRAINED UNPREDICTABLE and we choose to fault. */ - return false; - } - } else { - /* AArch32 only supports 4KB pages. Assert on that. */ - assert(stride == 9); - - if (level == 0) { - return false; - } - } - return true; -} - -/* Translate from the 4-bit stage 2 representation of - * memory attributes (without cache-allocation hints) to - * the 8-bit representation of the stage 1 MAIR registers - * (which includes allocation hints). - * - * ref: shared/translation/attrs/S2AttrDecode() - * .../S2ConvertAttrsHints() - */ -static uint8_t convert_stage2_attrs(CPUARMState *env, 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 */ - hiattr = loattr = 1; /* non-cacheable */ - } else { - if (hiattr != 1) { /* Write-through or write-back */ - hihint = 3; /* RW allocate */ - } - if (loattr != 1) { /* Write-through or write-back */ - lohint = 3; /* RW allocate */ - } - } - } - - return (hiattr << 6) | (hihint << 4) | (loattr << 2) | lohint; -} -#endif /* !CONFIG_USER_ONLY */ - -/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ -static const uint8_t pamax_map[] = { - [0] = 32, - [1] = 36, - [2] = 40, - [3] = 42, - [4] = 44, - [5] = 48, - [6] = 52, -}; - -/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */ -unsigned int arm_pamax(ARMCPU *cpu) -{ - unsigned int parange = - FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); - - /* - * id_aa64mmfr0 is a read-only register so values outside of the - * supported mappings can be considered an implementation error. - */ - assert(parange < ARRAY_SIZE(pamax_map)); - return pamax_map[parange]; -} - -static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) -{ - if (regime_has_2_ranges(mmu_idx)) { - return extract64(tcr, 37, 2); - } else if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - return 0; /* VTCR_EL2 */ - } else { - /* Replicate the single TBI bit so we always have 2 bits. */ - return extract32(tcr, 20, 1) * 3; - } -} - -static int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx) -{ - if (regime_has_2_ranges(mmu_idx)) { - return extract64(tcr, 51, 2); - } else if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - return 0; /* VTCR_EL2 */ - } else { - /* Replicate the single TBID bit so we always have 2 bits. */ - return extract32(tcr, 29, 1) * 3; - } -} - -static int aa64_va_parameter_tcma(uint64_t tcr, ARMMMUIdx mmu_idx) -{ - if (regime_has_2_ranges(mmu_idx)) { - return extract64(tcr, 57, 2); - } else { - /* Replicate the single TCMA bit so we always have 2 bits. */ - return extract32(tcr, 30, 1) * 3; - } -} - -ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, - ARMMMUIdx mmu_idx, bool data) -{ - uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; - bool epd, hpd, using16k, using64k, tsz_oob, ds; - int select, tsz, tbi, max_tsz, min_tsz, ps, sh; - ARMCPU *cpu = env_archcpu(env); - - 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) { - /* VTCR_EL2 */ - hpd = false; - } else { - hpd = extract32(tcr, 24, 1); - } - epd = false; - sh = extract32(tcr, 12, 2); - ps = extract32(tcr, 16, 3); - ds = extract64(tcr, 32, 1); - } else { - /* - * Bit 55 is always between the two regions, and is canonical for - * determining if address tagging is enabled. - */ - select = extract64(va, 55, 1); - if (!select) { - tsz = extract32(tcr, 0, 6); - 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); - epd = extract32(tcr, 23, 1); - sh = extract32(tcr, 28, 2); - hpd = extract64(tcr, 42, 1); - } - ps = extract64(tcr, 32, 3); - ds = extract64(tcr, 59, 1); - } - - if (cpu_isar_feature(aa64_st, cpu)) { - max_tsz = 48 - using64k; - } else { - max_tsz = 39; - } - - /* - * DS is RES0 unless FEAT_LPA2 is supported for the given page size; - * adjust the effective value of DS, as documented. - */ - min_tsz = 16; - if (using64k) { - if (cpu_isar_feature(aa64_lva, cpu)) { - min_tsz = 12; - } - ds = false; - } else if (ds) { - switch (mmu_idx) { - case ARMMMUIdx_Stage2: - case ARMMMUIdx_Stage2_S: - if (using16k) { - ds = cpu_isar_feature(aa64_tgran16_2_lpa2, cpu); - } else { - ds = cpu_isar_feature(aa64_tgran4_2_lpa2, cpu); - } - break; - default: - if (using16k) { - ds = cpu_isar_feature(aa64_tgran16_lpa2, cpu); - } else { - ds = cpu_isar_feature(aa64_tgran4_lpa2, cpu); - } - break; - } - if (ds) { - min_tsz = 12; - } - } - - if (tsz > max_tsz) { - tsz = max_tsz; - tsz_oob = true; - } else if (tsz < min_tsz) { - tsz = min_tsz; - tsz_oob = true; - } else { - tsz_oob = false; - } - - /* Present TBI as a composite with TBID. */ - tbi = aa64_va_parameter_tbi(tcr, mmu_idx); - if (!data) { - tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); - } - tbi = (tbi >> select) & 1; - - return (ARMVAParameters) { - .tsz = tsz, - .ps = ps, - .sh = sh, - .select = select, - .tbi = tbi, - .epd = epd, - .hpd = hpd, - .using16k = using16k, - .using64k = using64k, - .tsz_oob = tsz_oob, - .ds = ds, - }; -} - -#ifndef CONFIG_USER_ONLY -static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, - ARMMMUIdx mmu_idx) -{ - uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; - uint32_t el = regime_el(env, mmu_idx); - int select, tsz; - bool epd, hpd; - - assert(mmu_idx != ARMMMUIdx_Stage2_S); - - if (mmu_idx == ARMMMUIdx_Stage2) { - /* VTCR */ - bool sext = extract32(tcr, 4, 1); - bool sign = extract32(tcr, 3, 1); - - /* - * If the sign-extend bit is not the same as t0sz[3], the result - * is unpredictable. Flag this as a guest error. - */ - if (sign != sext) { - qemu_log_mask(LOG_GUEST_ERROR, - "AArch32: VTCR.S / VTCR.T0SZ[3] mismatch\n"); - } - tsz = sextract32(tcr, 0, 4) + 8; - select = 0; - hpd = false; - epd = false; - } else if (el == 2) { - /* HTCR */ - tsz = extract32(tcr, 0, 3); - select = 0; - hpd = extract64(tcr, 24, 1); - epd = false; - } else { - int t0sz = extract32(tcr, 0, 3); - int t1sz = extract32(tcr, 16, 3); - - if (t1sz == 0) { - select = va > (0xffffffffu >> t0sz); - } else { - /* Note that we will detect errors later. */ - select = va >= ~(0xffffffffu >> t1sz); - } - if (!select) { - tsz = t0sz; - epd = extract32(tcr, 7, 1); - hpd = extract64(tcr, 41, 1); - } else { - tsz = t1sz; - epd = extract32(tcr, 23, 1); - hpd = extract64(tcr, 42, 1); - } - /* For aarch32, hpd0 is not enabled without t2e as well. */ - hpd &= extract32(tcr, 6, 1); - } - - return (ARMVAParameters) { - .tsz = tsz, - .select = select, - .epd = epd, - .hpd = hpd, - }; -} - -/** - * get_phys_addr_lpae: perform one stage of page table walk, LPAE format - * - * 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 long-format - * DFSR/IFSR fault register, with the following caveats: - * * the WnR bit is never set (the caller must do this). - * - * @env: CPUARMState - * @address: virtual address to get physical address for - * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH - * @mmu_idx: MMU index indicating required translation regime - * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page 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 - * @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) -{ - ARMCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); - /* Read an LPAE long-descriptor translation table. */ - ARMFaultType fault_type = ARMFault_Translation; - uint32_t level; - ARMVAParameters param; - uint64_t ttbr; - hwaddr descaddr, indexmask, indexmask_grainsize; - uint32_t tableattrs; - target_ulong page_size; - uint32_t attrs; - int32_t stride; - int addrsize, inputsize, outputsize; - TCR *tcr = regime_tcr(env, mmu_idx); - int ap, ns, xn, pxn; - uint32_t el = regime_el(env, mmu_idx); - uint64_t descaddrmask; - bool aarch64 = arm_el_is_aa64(env, el); - bool guarded = false; - - /* TODO: This code does not support shareability levels. */ - if (aarch64) { - int ps; - - param = aa64_va_parameters(env, address, mmu_idx, - access_type != MMU_INST_FETCH); - level = 0; - - /* - * If TxSZ is programmed to a value larger than the maximum, - * or smaller than the effective minimum, it is IMPLEMENTATION - * DEFINED whether we behave as if the field were programmed - * within bounds, or if a level 0 Translation fault is generated. - * - * With FEAT_LVA, fault on less than minimum becomes required, - * so our choice is to always raise the fault. - */ - if (param.tsz_oob) { - fault_type = ARMFault_Translation; - goto do_fault; - } - - addrsize = 64 - 8 * param.tbi; - inputsize = 64 - param.tsz; - - /* - * Bound PS by PARANGE to find the effective output address size. - * ID_AA64MMFR0 is a read-only register so values outside of the - * supported mappings can be considered an implementation error. - */ - ps = FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); - ps = MIN(ps, param.ps); - assert(ps < ARRAY_SIZE(pamax_map)); - outputsize = pamax_map[ps]; - } else { - param = aa32_va_parameters(env, address, mmu_idx); - level = 1; - addrsize = (mmu_idx == ARMMMUIdx_Stage2 ? 40 : 32); - inputsize = addrsize - param.tsz; - outputsize = 40; - } - - /* - * We determined the region when collecting the parameters, but we - * have not yet validated that the address is valid for the region. - * Extract the top bits and verify that they all match select. - * - * For aa32, if inputsize == addrsize, then we have selected the - * region by exclusion in aa32_va_parameters and there is no more - * validation to do here. - */ - if (inputsize < addrsize) { - target_ulong top_bits = sextract64(address, inputsize, - addrsize - inputsize); - if (-top_bits != param.select) { - /* The gap between the two regions is a Translation fault */ - fault_type = ARMFault_Translation; - goto do_fault; - } - } - - if (param.using64k) { - stride = 13; - } else if (param.using16k) { - stride = 11; - } else { - stride = 9; - } - - /* Note that QEMU ignores shareability and cacheability attributes, - * so we don't need to do anything with the SH, ORGN, IRGN fields - * in the TTBCR. Similarly, TTBCR:A1 selects whether we get the - * ASID from TTBR0 or TTBR1, but QEMU's TLB doesn't currently - * implement any ASID-like capability so we can ignore it (instead - * we will always flush the TLB any time the ASID is changed). - */ - ttbr = regime_ttbr(env, mmu_idx, param.select); - - /* Here we should have set up all the parameters for the translation: - * inputsize, ttbr, epd, stride, tbi - */ - - if (param.epd) { - /* Translation table walk disabled => Translation fault on TLB miss - * Note: This is always 0 on 64-bit EL2 and EL3. - */ - goto do_fault; - } - - if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { - /* The starting level depends on the virtual address size (which can - * be up to 48 bits) and the translation granule size. It indicates - * the number of strides (stride bits at a time) needed to - * consume the bits of the input address. In the pseudocode this is: - * level = 4 - RoundUp((inputsize - grainsize) / stride) - * where their 'inputsize' is our 'inputsize', 'grainsize' is - * our 'stride + 3' and 'stride' is our 'stride'. - * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: - * = 4 - (inputsize - stride - 3 + stride - 1) / stride - * = 4 - (inputsize - 4) / stride; - */ - level = 4 - (inputsize - 4) / stride; - } else { - /* For stage 2 translations the starting level is specified by the - * VTCR_EL2.SL0 field (whose interpretation depends on the page size) - */ - uint32_t sl0 = extract32(tcr->raw_tcr, 6, 2); - uint32_t sl2 = extract64(tcr->raw_tcr, 33, 1); - uint32_t startlevel; - bool ok; - - /* SL2 is RES0 unless DS=1 & 4kb granule. */ - if (param.ds && stride == 9 && sl2) { - if (sl0 != 0) { - level = 0; - fault_type = ARMFault_Translation; - goto do_fault; - } - startlevel = -1; - } else if (!aarch64 || stride == 9) { - /* AArch32 or 4KB pages */ - startlevel = 2 - sl0; - - if (cpu_isar_feature(aa64_st, cpu)) { - startlevel &= 3; - } - } else { - /* 16KB or 64KB pages */ - startlevel = 3 - sl0; - } - - /* Check that the starting level is valid. */ - ok = check_s2_mmu_setup(cpu, aarch64, startlevel, - inputsize, stride, outputsize); - if (!ok) { - fault_type = ARMFault_Translation; - goto do_fault; - } - level = startlevel; - } - - indexmask_grainsize = MAKE_64BIT_MASK(0, stride + 3); - indexmask = MAKE_64BIT_MASK(0, inputsize - (stride * (4 - level))); - - /* Now we can extract the actual base address from the TTBR */ - descaddr = extract64(ttbr, 0, 48); - - /* - * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [5:2] of TTBR. - * - * Otherwise, if the base address is out of range, raise AddressSizeFault. - * In the pseudocode, this is !IsZero(baseregister<47:outputsize>), - * but we've just cleared the bits above 47, so simplify the test. - */ - if (outputsize > 48) { - descaddr |= extract64(ttbr, 2, 4) << 48; - } else if (descaddr >> outputsize) { - level = 0; - fault_type = ARMFault_AddressSize; - goto do_fault; - } - - /* - * We rely on this masking to clear the RES0 bits at the bottom of the TTBR - * and also to mask out CnP (bit 0) which could validly be non-zero. - */ - descaddr &= ~indexmask; - - /* - * For AArch32, the address field in the descriptor goes up to bit 39 - * for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0 - * or an AddressSize fault is raised. So for v8 we extract those SBZ - * bits as part of the address, which will be checked via outputsize. - * For AArch64, the address field goes up to bit 47, or 49 with FEAT_LPA2; - * the highest bits of a 52-bit output are placed elsewhere. - */ - if (param.ds) { - descaddrmask = MAKE_64BIT_MASK(0, 50); - } else if (arm_feature(env, ARM_FEATURE_V8)) { - descaddrmask = MAKE_64BIT_MASK(0, 48); - } else { - descaddrmask = MAKE_64BIT_MASK(0, 40); - } - descaddrmask &= ~indexmask_grainsize; - - /* Secure accesses start with the page table in secure memory and - * can be downgraded to non-secure at any step. Non-secure accesses - * 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); - for (;;) { - uint64_t descriptor; - bool nstable; - - descaddr |= (address >> (stride * (4 - level))) & indexmask; - descaddr &= ~7ULL; - nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - - if (!(descriptor & 1) || - (!(descriptor & 2) && (level == 3))) { - /* Invalid, or the Reserved level 3 encoding */ - goto do_fault; - } - - descaddr = descriptor & descaddrmask; - - /* - * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12] - * of descriptor. For FEAT_LPA2 and effective DS, bits [51:50] of - * descaddr are in [9:8]. Otherwise, if descaddr is out of range, - * raise AddressSizeFault. - */ - if (outputsize > 48) { - if (param.ds) { - descaddr |= extract64(descriptor, 8, 2) << 50; - } else { - descaddr |= extract64(descriptor, 12, 4) << 48; - } - } else if (descaddr >> outputsize) { - fault_type = ARMFault_AddressSize; - goto do_fault; - } - - if ((descriptor & 2) && (level < 3)) { - /* Table entry. The top five bits are attributes which may - * propagate down through lower levels of the table (and - * which are all arranged so that 0 means "no effect", so - * we can gather them up by ORing in the bits at each level). - */ - tableattrs |= extract64(descriptor, 59, 5); - level++; - indexmask = indexmask_grainsize; - continue; - } - /* - * Block entry at level 1 or 2, or page entry at level 3. - * These are basically the same thing, although the number - * of bits we pull in from the vaddr varies. Note that although - * descaddrmask masks enough of the low bits of the descriptor - * to give a correct page or table address, the address field - * in a block descriptor is smaller; so we need to explicitly - * clear the lower bits here before ORing in the low vaddr bits. - */ - page_size = (1ULL << ((stride * (4 - level)) + 3)); - descaddr &= ~(page_size - 1); - descaddr |= (address & (page_size - 1)); - /* Extract attributes from the descriptor */ - attrs = extract64(descriptor, 2, 10) - | (extract64(descriptor, 52, 12) << 10); - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - /* Stage 2 table descriptors do not include any attribute fields */ - break; - } - /* Merge in attributes from table descriptors */ - attrs |= nstable << 3; /* NS */ - guarded = extract64(descriptor, 50, 1); /* GP */ - if (param.hpd) { - /* HPD disables all the table attributes except NSTable. */ - break; - } - attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */ - /* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1 - * means "force PL1 access only", which means forcing AP[1] to 0. - */ - attrs &= ~(extract32(tableattrs, 2, 1) << 4); /* !APT[0] => AP[1] */ - attrs |= extract32(tableattrs, 3, 1) << 5; /* APT[1] => AP[2] */ - break; - } - /* Here descaddr is the final physical address, and attributes - * are all in attrs. - */ - fault_type = ARMFault_AccessFlag; - if ((attrs & (1 << 8)) == 0) { - /* Access flag */ - goto do_fault; - } - - ap = extract32(attrs, 4, 2); - - 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); - } 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); - } - - fault_type = ARMFault_Permission; - if (!(*prot & (1 << access_type))) { - goto do_fault; - } - - if (ns) { - /* The NS bit will (as required by the architecture) have no effect if - * 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; - } - /* 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; - } - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - cacheattrs->attrs = convert_stage2_attrs(env, 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->attrs = extract64(mair, attrindx * 8, 8); - } - - /* - * For FEAT_LPA2 and effective DS, the SH field in the attributes - * was re-purposed for output address bits. The SH attribute in - * that case comes from TCR_ELx, which we extracted earlier. - */ - if (param.ds) { - cacheattrs->shareability = param.sh; - } else { - cacheattrs->shareability = extract32(attrs, 6, 2); - } - - *phys_ptr = descaddr; - *page_size_ptr = page_size; - return false; - -do_fault: - fi->type = fault_type; - fi->level = level; - /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ - fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_Stage2 || - mmu_idx == ARMMMUIdx_Stage2_S); - fi->s1ns = mmu_idx == ARMMMUIdx_Stage2; - return true; -} - -static inline void get_phys_addr_pmsav7_default(CPUARMState *env, - ARMMMUIdx mmu_idx, - int32_t address, int *prot) -{ - if (!arm_feature(env, ARM_FEATURE_M)) { - *prot = PAGE_READ | PAGE_WRITE; - switch (address) { - case 0xF0000000 ... 0xFFFFFFFF: - if (regime_sctlr(env, mmu_idx) & SCTLR_V) { - /* hivecs execing is ok */ - *prot |= PAGE_EXEC; - } - break; - case 0x00000000 ... 0x7FFFFFFF: - *prot |= PAGE_EXEC; - break; - } - } else { - /* Default system address map for M profile cores. - * The architecture specifies which regions are execute-never; - * at the MPU level no other checks are defined. - */ - switch (address) { - case 0x00000000 ... 0x1fffffff: /* ROM */ - case 0x20000000 ... 0x3fffffff: /* SRAM */ - case 0x60000000 ... 0x7fffffff: /* RAM */ - case 0x80000000 ... 0x9fffffff: /* RAM */ - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - break; - case 0x40000000 ... 0x5fffffff: /* Peripheral */ - case 0xa0000000 ... 0xbfffffff: /* Device */ - case 0xc0000000 ... 0xdfffffff: /* Device */ - case 0xe0000000 ... 0xffffffff: /* System */ - *prot = PAGE_READ | PAGE_WRITE; - break; - default: - g_assert_not_reached(); - } - } -} - -static bool pmsav7_use_background_region(ARMCPU *cpu, - ARMMMUIdx mmu_idx, bool is_user) -{ - /* Return true if we should use the default memory map as a - * "background" region if there are no hits against any MPU regions. - */ - CPUARMState *env = &cpu->env; - - if (is_user) { - return false; - } - - if (arm_feature(env, ARM_FEATURE_M)) { - return env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] - & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; - } else { - return regime_sctlr(env, mmu_idx) & SCTLR_BR; - } -} - -static inline bool m_is_ppb_region(CPUARMState *env, uint32_t address) -{ - /* True if address is in the M profile PPB region 0xe0000000 - 0xe00fffff */ - return arm_feature(env, ARM_FEATURE_M) && - extract32(address, 20, 12) == 0xe00; -} - -static inline bool m_is_system_region(CPUARMState *env, uint32_t address) -{ - /* True if address is in the M profile system region - * 0xe0000000 - 0xffffffff - */ - return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; -} - -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, - 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; - - if (regime_translation_disabled(env, mmu_idx) || - m_is_ppb_region(env, address)) { - /* MPU disabled or M profile PPB access: use default memory map. - * The other case which uses the default memory map in the - * v7M ARM ARM pseudocode is exception vector reads from the vector - * table. In QEMU those accesses are done in arm_v7m_load_vector(), - * 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); - } else { /* MPU enabled */ - for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { - /* region search */ - uint32_t base = env->pmsav7.drbar[n]; - uint32_t rsize = extract32(env->pmsav7.drsr[n], 1, 5); - uint32_t rmask; - bool srdis = false; - - if (!(env->pmsav7.drsr[n] & 0x1)) { - continue; - } - - if (!rsize) { - qemu_log_mask(LOG_GUEST_ERROR, - "DRSR[%d]: Rsize field cannot be 0\n", n); - continue; - } - rsize++; - rmask = (1ull << rsize) - 1; - - if (base & rmask) { - qemu_log_mask(LOG_GUEST_ERROR, - "DRBAR[%d]: 0x%" PRIx32 " misaligned " - "to DRSR region size, mask = 0x%" PRIx32 "\n", - n, base, rmask); - continue; - } - - if (address < base || address > base + rmask) { - /* - * Address not in this region. We must check whether the - * region covers addresses in the same page as our address. - * In that case we must not report a size that covers the - * whole page for a subsequent hit against a different MPU - * region or the background region, because it would result in - * incorrect TLB hits for subsequent accesses to addresses that - * are in this MPU region. - */ - if (ranges_overlap(base, rmask, - address & TARGET_PAGE_MASK, - TARGET_PAGE_SIZE)) { - *page_size = 1; - } - continue; - } - - /* Region matched */ - - if (rsize >= 8) { /* no subregions for regions < 256 bytes */ - int i, snd; - uint32_t srdis_mask; - - rsize -= 3; /* sub region size (power of 2) */ - snd = ((address - base) >> rsize) & 0x7; - srdis = extract32(env->pmsav7.drsr[n], snd + 8, 1); - - srdis_mask = srdis ? 0x3 : 0x0; - for (i = 2; i <= 8 && rsize < TARGET_PAGE_BITS; i *= 2) { - /* This will check in groups of 2, 4 and then 8, whether - * the subregion bits are consistent. rsize is incremented - * back up to give the region size, considering consistent - * adjacent subregions as one region. Stop testing if rsize - * is already big enough for an entire QEMU page. - */ - int snd_rounded = snd & ~(i - 1); - uint32_t srdis_multi = extract32(env->pmsav7.drsr[n], - snd_rounded + 8, i); - if (srdis_mask ^ srdis_multi) { - break; - } - srdis_mask = (srdis_mask << i) | srdis_mask; - rsize++; - } - } - if (srdis) { - continue; - } - if (rsize < TARGET_PAGE_BITS) { - *page_size = 1 << rsize; - } - break; - } - - if (n == -1) { /* no hits */ - if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { - /* background fault */ - fi->type = ARMFault_Background; - return true; - } - get_phys_addr_pmsav7_default(env, mmu_idx, address, 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); - - if (m_is_system_region(env, address)) { - /* System space is always execute never */ - xn = 1; - } - - if (is_user) { /* User mode AP bit decoding */ - switch (ap) { - case 0: - case 1: - case 5: - break; /* no access */ - case 3: - *prot |= PAGE_WRITE; - /* fall through */ - case 2: - case 6: - *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; - break; - } - /* fall through */ - default: - qemu_log_mask(LOG_GUEST_ERROR, - "DRACR[%d]: Bad value for AP bits: 0x%" - PRIx32 "\n", n, ap); - } - } else { /* Priv. mode AP bits decoding */ - switch (ap) { - case 0: - break; /* no access */ - case 1: - case 2: - case 3: - *prot |= PAGE_WRITE; - /* fall through */ - case 5: - case 6: - *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; - break; - } - /* fall through */ - default: - qemu_log_mask(LOG_GUEST_ERROR, - "DRACR[%d]: Bad value for AP bits: 0x%" - PRIx32 "\n", n, ap); - } - } - - /* execute never */ - if (xn) { - *prot &= ~PAGE_EXEC; - } - } - } - - fi->type = ARMFault_Permission; - fi->level = 1; - return !(*prot & (1 << access_type)); -} - -static bool v8m_is_sau_exempt(CPUARMState *env, - uint32_t address, MMUAccessType access_type) -{ - /* The architecture specifies that certain address ranges are - * exempt from v8M SAU/IDAU checks. - */ - return - (access_type == MMU_INST_FETCH && m_is_system_region(env, address)) || - (address >= 0xe0000000 && address <= 0xe0002fff) || - (address >= 0xe000e000 && address <= 0xe000efff) || - (address >= 0xe002e000 && address <= 0xe002efff) || - (address >= 0xe0040000 && address <= 0xe0041fff) || - (address >= 0xe00ff000 && address <= 0xe00fffff); -} - -void v8m_security_lookup(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - V8M_SAttributes *sattrs) -{ - /* Look up the security attributes for this address. Compare the - * pseudocode SecurityCheck() function. - * We assume the caller has zero-initialized *sattrs. - */ - ARMCPU *cpu = env_archcpu(env); - int r; - bool idau_exempt = false, idau_ns = true, idau_nsc = true; - int idau_region = IREGION_NOTVALID; - uint32_t addr_page_base = address & TARGET_PAGE_MASK; - uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); - - if (cpu->idau) { - IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(cpu->idau); - IDAUInterface *ii = IDAU_INTERFACE(cpu->idau); - - iic->check(ii, address, &idau_region, &idau_exempt, &idau_ns, - &idau_nsc); - } - - if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) { - /* 0xf0000000..0xffffffff is always S for insn fetches */ - return; - } - - if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) { - sattrs->ns = !regime_is_secure(env, mmu_idx); - return; - } - - if (idau_region != IREGION_NOTVALID) { - sattrs->irvalid = true; - sattrs->iregion = idau_region; - } - - switch (env->sau.ctrl & 3) { - case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */ - break; - case 2: /* SAU.ENABLE == 0, SAU.ALLNS == 1 */ - sattrs->ns = true; - break; - default: /* SAU.ENABLE == 1 */ - for (r = 0; r < cpu->sau_sregion; r++) { - if (env->sau.rlar[r] & 1) { - uint32_t base = env->sau.rbar[r] & ~0x1f; - uint32_t limit = env->sau.rlar[r] | 0x1f; - - if (base <= address && limit >= address) { - if (base > addr_page_base || limit < addr_page_limit) { - sattrs->subpage = true; - } - if (sattrs->srvalid) { - /* If we hit in more than one region then we must report - * as Secure, not NS-Callable, with no valid region - * number info. - */ - sattrs->ns = false; - sattrs->nsc = false; - sattrs->sregion = 0; - sattrs->srvalid = false; - break; - } else { - if (env->sau.rlar[r] & 2) { - sattrs->nsc = true; - } else { - sattrs->ns = true; - } - sattrs->srvalid = true; - sattrs->sregion = r; - } - } else { - /* - * Address not in this region. We must check whether the - * region covers addresses in the same page as our address. - * In that case we must not report a size that covers the - * whole page for a subsequent hit against a different MPU - * region or the background region, because it would result - * in incorrect TLB hits for subsequent accesses to - * addresses that are in this MPU region. - */ - if (limit >= base && - ranges_overlap(base, limit - base + 1, - addr_page_base, - TARGET_PAGE_SIZE)) { - sattrs->subpage = true; - } - } - } - } - break; - } - - /* - * The IDAU will override the SAU lookup results if it specifies - * higher security than the SAU does. - */ - if (!idau_ns) { - if (sattrs->ns || (!idau_nsc && sattrs->nsc)) { - sattrs->ns = false; - sattrs->nsc = idau_nsc; - } - } -} - -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) -{ - /* Perform a PMSAv8 MPU lookup (without also doing the SAU check - * that a full phys-to-virt translation does). - * 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. - */ - 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; - if (mregion) { - *mregion = -1; - } - - /* Unlike the ARM ARM pseudocode, we don't need to check whether this - * was an exception vector read from the vector table (which is always - * done using the default system address map), because those accesses - * 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 */ - hit = true; - } else if (m_is_ppb_region(env, address)) { - hit = true; - } else { - if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) { - hit = true; - } - - for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { - /* region search */ - /* Note that the base address is bits [31:5] from the register - * with bits [4:0] all zeroes, but the limit address is bits - * [31:5] from the register with bits [4:0] all ones. - */ - uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f; - uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f; - - if (!(env->pmsav8.rlar[secure][n] & 0x1)) { - /* Region disabled */ - continue; - } - - if (address < base || address > limit) { - /* - * Address not in this region. We must check whether the - * region covers addresses in the same page as our address. - * In that case we must not report a size that covers the - * whole page for a subsequent hit against a different MPU - * region or the background region, because it would result in - * incorrect TLB hits for subsequent accesses to addresses that - * are in this MPU region. - */ - if (limit >= base && - ranges_overlap(base, limit - base + 1, - addr_page_base, - TARGET_PAGE_SIZE)) { - *is_subpage = true; - } - continue; - } - - if (base > addr_page_base || limit < addr_page_limit) { - *is_subpage = true; - } - - if (matchregion != -1) { - /* Multiple regions match -- always a failure (unlike - * PMSAv7 where highest-numbered-region wins) - */ - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - - matchregion = n; - hit = true; - } - } - - if (!hit) { - /* background fault */ - fi->type = ARMFault_Background; - return true; - } - - if (matchregion == -1) { - /* hit using the background region */ - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); - } else { - uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2); - uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1); - bool pxn = false; - - if (arm_feature(env, ARM_FEATURE_V8_1M)) { - pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1); - } - - if (m_is_system_region(env, address)) { - /* System space is always execute never */ - xn = 1; - } - - *prot = simple_ap_to_rw_prot(env, mmu_idx, ap); - if (*prot && !xn && !(pxn && !is_user)) { - *prot |= PAGE_EXEC; - } - /* We don't need to look the attribute up in the MAIR0/MAIR1 - * registers because that only tells us about cacheability. - */ - if (mregion) { - *mregion = matchregion; - } - } - - fi->type = ARMFault_Permission; - fi->level = 1; - return !(*prot & (1 << access_type)); -} - - -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, - 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); - if (access_type == MMU_INST_FETCH) { - /* Instruction fetches always use the MMU bank and the - * transaction attribute determined by the fetch address, - * regardless of CPU state. This is painful for QEMU - * to handle, because it would mean we need to encode - * into the mmu_idx not just the (user, negpri) information - * for the current security state but also that for the - * other security state, which would balloon the number - * of mmu_idx values needed alarmingly. - * Fortunately we can avoid this because it's not actually - * possible to arbitrarily execute code from memory with - * the wrong security attribute: it will always generate - * an exception of some kind or another, apart from the - * special case of an NS CPU executing an SG instruction - * in S&NSC memory. So we always just fail the translation - * here and sort things out in the exception handler - * (including possibly emulating an SG instruction). - */ - if (sattrs.ns != !secure) { - if (sattrs.nsc) { - fi->type = ARMFault_QEMU_NSCExec; - } else { - fi->type = ARMFault_QEMU_SFault; - } - *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; - *phys_ptr = address; - *prot = 0; - return true; - } - } else { - /* For data accesses we always use the MMU bank indicated - * by the current CPU state, but the security attributes - * might downgrade a secure access to nonsecure. - */ - if (sattrs.ns) { - txattrs->secure = false; - } else if (!secure) { - /* NS access to S memory must fault. - * Architecturally we should first check whether the - * MPU information for this address indicates that we - * are doing an unaligned access to Device memory, which - * should generate a UsageFault instead. QEMU does not - * currently check for that kind of unaligned access though. - * If we added it we would need to do so as a special case - * 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; - 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; - return ret; -} - -static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - ARMMMUFaultInfo *fi) -{ - int n; - uint32_t mask; - uint32_t base; - bool is_user = regime_is_user(env, mmu_idx); - - if (regime_translation_disabled(env, mmu_idx)) { - /* MPU disabled. */ - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return false; - } - - *phys_ptr = address; - for (n = 7; n >= 0; n--) { - base = env->cp15.c6_region[n]; - if ((base & 1) == 0) { - continue; - } - mask = 1 << ((base >> 1) & 0x1f); - /* Keep this shift separate from the above to avoid an - (undefined) << 32. */ - mask = (mask << 1) - 1; - if (((base ^ address) & ~mask) == 0) { - break; - } - } - if (n < 0) { - fi->type = ARMFault_Background; - return true; - } - - if (access_type == MMU_INST_FETCH) { - mask = env->cp15.pmsav5_insn_ap; - } else { - mask = env->cp15.pmsav5_data_ap; - } - mask = (mask >> (n * 4)) & 0xf; - switch (mask) { - case 0: - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - case 1: - if (is_user) { - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - *prot = PAGE_READ | PAGE_WRITE; - break; - case 2: - *prot = PAGE_READ; - if (!is_user) { - *prot |= PAGE_WRITE; - } - break; - case 3: - *prot = PAGE_READ | PAGE_WRITE; - break; - case 5: - if (is_user) { - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - *prot = PAGE_READ; - break; - case 6: - *prot = PAGE_READ; - break; - default: - /* Bad permission. */ - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - *prot |= PAGE_EXEC; - return false; -} - -/* Combine either inner or outer cacheability attributes for normal - * memory, according to table D4-42 and pseudocode procedure - * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). - * - * NB: only stage 1 includes allocation hints (RW bits), leading to - * some asymmetry. - */ -static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) -{ - if (s1 == 4 || s2 == 4) { - /* non-cacheable has precedence */ - return 4; - } else if (extract32(s1, 2, 2) == 0 || extract32(s1, 2, 2) == 2) { - /* stage 1 write-through takes precedence */ - return s1; - } else if (extract32(s2, 2, 2) == 2) { - /* stage 2 write-through takes precedence, but the allocation hint - * is still taken from stage 1 - */ - return (2 << 2) | extract32(s1, 0, 2); - } else { /* write-back */ - return s1; - } -} - -/* Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 - * and CombineS1S2Desc() - * - * @s1: Attributes from stage 1 walk - * @s2: Attributes from stage 2 walk - */ -static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) -{ - uint8_t s1lo, s2lo, s1hi, s2hi; - ARMCacheAttrs ret; - bool tagged = false; - - if (s1.attrs == 0xf0) { - tagged = true; - s1.attrs = 0xff; - } - - s1lo = extract32(s1.attrs, 0, 4); - s2lo = extract32(s2.attrs, 0, 4); - s1hi = extract32(s1.attrs, 4, 4); - s2hi = extract32(s2.attrs, 4, 4); - - /* Combine shareability attributes (table D4-43) */ - if (s1.shareability == 2 || s2.shareability == 2) { - /* if either are outer-shareable, the result is outer-shareable */ - ret.shareability = 2; - } else if (s1.shareability == 3 || s2.shareability == 3) { - /* if either are inner-shareable, the result is inner-shareable */ - ret.shareability = 3; - } else { - /* both non-shareable */ - ret.shareability = 0; - } - - /* Combine memory type and cacheability attributes */ - if (s1hi == 0 || s2hi == 0) { - /* Device has precedence over normal */ - if (s1lo == 0 || s2lo == 0) { - /* nGnRnE has precedence over anything */ - ret.attrs = 0; - } else if (s1lo == 4 || s2lo == 4) { - /* non-Reordering has precedence over Reordering */ - ret.attrs = 4; /* nGnRE */ - } else if (s1lo == 8 || s2lo == 8) { - /* non-Gathering has precedence over Gathering */ - ret.attrs = 8; /* nGRE */ - } else { - ret.attrs = 0xc; /* GRE */ - } - - /* Any location for which the resultant memory type is any - * type of Device memory is always treated as Outer Shareable. - */ - ret.shareability = 2; - } else { /* Normal memory */ - /* Outer/inner cacheability combine independently */ - ret.attrs = combine_cacheattr_nibble(s1hi, s2hi) << 4 - | combine_cacheattr_nibble(s1lo, s2lo); - - if (ret.attrs == 0x44) { - /* Any location for which the resultant memory type is Normal - * Inner Non-cacheable, Outer Non-cacheable is always treated - * as Outer Shareable. - */ - ret.shareability = 2; - } - } - - /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ - if (tagged && ret.attrs == 0xff) { - ret.attrs = 0xf0; - } - - 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 - */ -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 ARMGranuleSize tg1_to_gran_size(int tg) { - ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx); - - if (mmu_idx != s1_mmu_idx) { - /* Call ourselves recursively to do the stage 1 and then stage 2 - * translations if mmu_idx is a two-stage regime. - */ - if (arm_feature(env, ARM_FEATURE_EL2)) { - hwaddr ipa; - int s2_prot; - int ret; - bool ipa_secure; - ARMCacheAttrs cacheattrs2 = {}; - ARMMMUIdx s2_mmu_idx; - bool is_el0; - - ret = get_phys_addr(env, address, access_type, s1_mmu_idx, &ipa, - attrs, prot, page_size, fi, cacheattrs); - - /* If S1 fails or S2 is disabled, return early. */ - if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2)) { - *phys_ptr = ipa; - return ret; - } - - ipa_secure = attrs->secure; - if (arm_is_secure_below_el3(env)) { - if (ipa_secure) { - attrs->secure = !(env->cp15.vstcr_el2.raw_tcr & VSTCR_SW); - } else { - attrs->secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW); - } - } else { - assert(!ipa_secure); - } - - s2_mmu_idx = attrs->secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; - is_el0 = mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_SE10_0; + switch (tg) { + case 1: + return Gran16K; + case 2: + return Gran4K; + case 3: + return Gran64K; + default: + return GranInvalid; + } +} - /* 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); - fi->s2addr = ipa; - /* Combine the S1 and S2 perms. */ - *prot &= s2_prot; +static inline bool have4k(ARMCPU *cpu, bool stage2) +{ + return stage2 ? cpu_isar_feature(aa64_tgran4_2, cpu) + : cpu_isar_feature(aa64_tgran4, cpu); +} - /* If S2 fails, return early. */ - if (ret) { - return ret; - } +static inline bool have16k(ARMCPU *cpu, bool stage2) +{ + return stage2 ? cpu_isar_feature(aa64_tgran16_2, cpu) + : cpu_isar_feature(aa64_tgran16, cpu); +} - /* Combine the S1 and S2 cache attributes. */ - if (arm_hcr_el2_eff(env) & HCR_DC) { - /* - * HCR.DC forces the first stage attributes to - * Normal Non-Shareable, - * Inner Write-Back Read-Allocate Write-Allocate, - * Outer Write-Back Read-Allocate Write-Allocate. - * Do not overwrite Tagged within attrs. - */ - if (cacheattrs->attrs != 0xf0) { - cacheattrs->attrs = 0xff; - } - cacheattrs->shareability = 0; - } - *cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2); +static inline bool have64k(ARMCPU *cpu, bool stage2) +{ + return stage2 ? cpu_isar_feature(aa64_tgran64_2, cpu) + : cpu_isar_feature(aa64_tgran64, cpu); +} - /* 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.raw_tcr & (VSTCR_SA | VSTCR_SW)); - } else { - attrs->secure = - !((env->cp15.vtcr_el2.raw_tcr & (VTCR_NSA | VTCR_NSW)) - || (env->cp15.vstcr_el2.raw_tcr & (VSTCR_SA | VSTCR_SW))); - } - } - return 0; - } else { - /* - * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. - */ - mmu_idx = stage_1_mmu_idx(mmu_idx); +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; } - - /* The page table entries may downgrade secure to non-secure, but - * cannot upgrade an non-secure translation regime's attributes - * to secure. + /* + * 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. */ - attrs->secure = regime_is_secure(env, mmu_idx); - attrs->user = regime_is_user(env, mmu_idx); + if (have4k(cpu, stage2)) { + return Gran4K; + } + if (have16k(cpu, stage2)) { + return Gran16K; + } + assert(have64k(cpu, stage2)); + return Gran64K; +} - /* Fast Context Switch Extension. This doesn't exist at all in v8. - * In v7 and earlier it affects all stage 1 translations. - */ - if (address < 0x02000000 && mmu_idx != ARMMMUIdx_Stage2 - && !arm_feature(env, ARM_FEATURE_V8)) { - if (regime_el(env, mmu_idx) == 3) { - address += env->cp15.fcseidr_s; +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, tsz_oob, ds, ha, hd; + int select, tsz, tbi, max_tsz, min_tsz, ps, sh; + ARMGranuleSize gran; + ARMCPU *cpu = env_archcpu(env); + bool stage2 = regime_is_stage2(mmu_idx); + + if (!regime_has_2_ranges(mmu_idx)) { + select = 0; + tsz = extract32(tcr, 0, 6); + gran = tg0_to_gran_size(extract32(tcr, 14, 2)); + if (stage2) { + /* VTCR_EL2 */ + hpd = false; } else { - address += env->cp15.fcseidr_ns; + hpd = extract32(tcr, 24, 1); } - } - - if (arm_feature(env, ARM_FEATURE_PMSA)) { - bool ret; - *page_size = TARGET_PAGE_SIZE; + epd = false; + sh = extract32(tcr, 12, 2); + ps = extract32(tcr, 16, 3); + ha = extract32(tcr, 21, 1) && cpu_isar_feature(aa64_hafs, cpu); + hd = extract32(tcr, 22, 1) && cpu_isar_feature(aa64_hdbs, cpu); + ds = extract64(tcr, 32, 1); + } else { + bool e0pd; - 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); - } 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); + /* + * Bit 55 is always between the two regions, and is canonical for + * determining if address tagging is enabled. + */ + 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); + hpd = extract64(tcr, 41, 1); + e0pd = extract64(tcr, 55, 1); } else { - /* Pre-v7 MPU */ - ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, - phys_ptr, prot, 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", - access_type == MMU_DATA_LOAD ? "reading" : - (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' : '-'); + 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); + e0pd = extract64(tcr, 56, 1); + } + ps = extract64(tcr, 32, 3); + ha = extract64(tcr, 39, 1) && cpu_isar_feature(aa64_hafs, cpu); + hd = extract64(tcr, 40, 1) && cpu_isar_feature(aa64_hdbs, cpu); + ds = extract64(tcr, 59, 1); - return ret; + if (e0pd && cpu_isar_feature(aa64_e0pd, cpu) && + regime_is_user(env, mmu_idx)) { + epd = true; + } } - /* Definitely a real MMU, not an MPU */ - - if (regime_translation_disabled(env, mmu_idx)) { - uint64_t hcr; - uint8_t memattr; + gran = sanitize_gran_size(cpu, gran, stage2); - /* - * 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].raw_tcr; - 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; - } + if (cpu_isar_feature(aa64_st, cpu)) { + max_tsz = 48 - (gran == Gran64K); + } else { + max_tsz = 39; + } - /* - * 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); - } + /* + * DS is RES0 unless FEAT_LPA2 is supported for the given page size; + * adjust the effective value of DS, as documented. + */ + min_tsz = 16; + if (gran == Gran64K) { + if (cpu_isar_feature(aa64_lva, cpu)) { + min_tsz = 12; } - *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; - if (hcr & HCR_DC) { - if (hcr & HCR_DCT) { - memattr = 0xf0; /* Tagged, Normal, WB, RWA */ + ds = false; + } else if (ds) { + if (regime_is_stage2(mmu_idx)) { + if (gran == Gran16K) { + ds = cpu_isar_feature(aa64_tgran16_2_lpa2, cpu); } else { - memattr = 0xff; /* Normal, WB, RWA */ + ds = cpu_isar_feature(aa64_tgran4_2_lpa2, cpu); } - } else if (access_type == MMU_INST_FETCH) { - if (regime_sctlr(env, mmu_idx) & SCTLR_I) { - memattr = 0xee; /* Normal, WT, RA, NT */ + } else { + if (gran == Gran16K) { + ds = cpu_isar_feature(aa64_tgran16_lpa2, cpu); } else { - memattr = 0x44; /* Normal, NC, No */ + ds = cpu_isar_feature(aa64_tgran4_lpa2, cpu); } - cacheattrs->shareability = 2; /* outer sharable */ - } else { - memattr = 0x00; /* Device, nGnRnE */ } - cacheattrs->attrs = memattr; - return 0; + if (ds) { + min_tsz = 12; + } } - 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); - } 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); + if (tsz > max_tsz) { + tsz = max_tsz; + tsz_oob = true; + } else if (tsz < min_tsz) { + tsz = min_tsz; + tsz_oob = true; } else { - return get_phys_addr_v5(env, address, access_type, mmu_idx, - phys_ptr, prot, page_size, fi); + tsz_oob = false; } -} - -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; - ARMMMUFaultInfo fi = {}; - ARMMMUIdx mmu_idx = arm_mmu_idx(env); - ARMCacheAttrs cacheattrs = {}; - - *attrs = (MemTxAttrs) {}; - ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fi, &cacheattrs); - - if (ret) { - return -1; + /* Present TBI as a composite with TBID. */ + tbi = aa64_va_parameter_tbi(tcr, mmu_idx); + if (!data) { + tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); } - return phys_addr; -} + tbi = (tbi >> select) & 1; -#endif + return (ARMVAParameters) { + .tsz = tsz, + .ps = ps, + .sh = sh, + .select = select, + .tbi = tbi, + .epd = epd, + .hpd = hpd, + .tsz_oob = tsz_oob, + .ds = ds, + .ha = ha, + .hd = ha && hd, + .gran = gran, + }; +} -/* Note that signed overflow is undefined in C. The following routines are - careful to use unsigned types where modulo arithmetic is required. - Failure to do so _will_ break on newer gcc. */ +/* + * Note that signed overflow is undefined in C. The following routines are + * careful to use unsigned types where modulo arithmetic is required. + * Failure to do so _will_ break on newer gcc. + */ /* Signed saturating arithmetic. */ @@ -12889,10 +11132,11 @@ static inline uint16_t add16_sat(uint16_t a, uint16_t b) res = a + b; if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { - if (a & 0x8000) + if (a & 0x8000) { res = 0x8000; - else + } else { res = 0x7fff; + } } return res; } @@ -12904,10 +11148,11 @@ static inline uint8_t add8_sat(uint8_t a, uint8_t b) res = a + b; if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { - if (a & 0x80) + if (a & 0x80) { res = 0x80; - else + } else { res = 0x7f; + } } return res; } @@ -12919,10 +11164,11 @@ static inline uint16_t sub16_sat(uint16_t a, uint16_t b) res = a - b; if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { - if (a & 0x8000) + if (a & 0x8000) { res = 0x8000; - else + } else { res = 0x7fff; + } } return res; } @@ -12934,10 +11180,11 @@ static inline uint8_t sub8_sat(uint8_t a, uint8_t b) res = a - b; if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { - if (a & 0x80) + if (a & 0x80) { res = 0x80; - else + } else { res = 0x7f; + } } return res; } @@ -12955,34 +11202,38 @@ static inline uint16_t add16_usat(uint16_t a, uint16_t b) { uint16_t res; res = a + b; - if (res < a) + if (res < a) { res = 0xffff; + } return res; } static inline uint16_t sub16_usat(uint16_t a, uint16_t b) { - if (a > b) + if (a > b) { return a - b; - else + } else { return 0; + } } static inline uint8_t add8_usat(uint8_t a, uint8_t b) { uint8_t res; res = a + b; - if (res < a) + if (res < a) { res = 0xff; + } return res; } static inline uint8_t sub8_usat(uint8_t a, uint8_t b) { - if (a > b) + if (a > b) { return a - b; - else + } else { return 0; + } } #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); @@ -13000,7 +11251,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) RESULT(sum, n, 16); \ if (sum >= 0) \ ge |= 3 << (n * 2); \ - } while(0) + } while (0) #define SARITH8(a, b, n, op) do { \ int32_t sum; \ @@ -13008,7 +11259,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) RESULT(sum, n, 8); \ if (sum >= 0) \ ge |= 1 << n; \ - } while(0) + } while (0) #define ADD16(a, b, n) SARITH16(a, b, n, +) @@ -13027,7 +11278,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) RESULT(sum, n, 16); \ if ((sum >> 16) == 1) \ ge |= 3 << (n * 2); \ - } while(0) + } while (0) #define ADD8(a, b, n) do { \ uint32_t sum; \ @@ -13035,7 +11286,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) RESULT(sum, n, 8); \ if ((sum >> 8) == 1) \ ge |= 1 << n; \ - } while(0) + } while (0) #define SUB16(a, b, n) do { \ uint32_t sum; \ @@ -13043,7 +11294,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) RESULT(sum, n, 16); \ if ((sum >> 16) == 0) \ ge |= 3 << (n * 2); \ - } while(0) + } while (0) #define SUB8(a, b, n) do { \ uint32_t sum; \ @@ -13051,7 +11302,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) RESULT(sum, n, 8); \ if ((sum >> 8) == 0) \ ge |= 1 << n; \ - } while(0) + } while (0) #define PFX u #define ARITH_GE @@ -13086,10 +11337,11 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) static inline uint8_t do_usad(uint8_t a, uint8_t b) { - if (a > b) + if (a > b) { return a - b; - else + } else { return b - a; + } } /* Unsigned sum of absolute byte differences. */ @@ -13109,18 +11361,23 @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) uint32_t mask; mask = 0; - if (flags & 1) + if (flags & 1) { mask |= 0xff; - if (flags & 2) + } + if (flags & 2) { mask |= 0xff00; - if (flags & 4) + } + if (flags & 4) { mask |= 0xff0000; - if (flags & 8) + } + if (flags & 8) { mask |= 0xff000000; + } return (a & mask) | (b & ~mask); } -/* CRC helpers. +/* + * CRC helpers. * The upper bytes of val (above the number specified by 'bytes') must have * been zeroed out by the caller. */ @@ -13144,7 +11401,8 @@ uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes) return crc32c(acc, buf, bytes) ^ 0xffffffff; } -/* Return the exception level to which FP-disabled exceptions should +/* + * Return the exception level to which FP-disabled exceptions should * be taken, or 0 if FP is enabled. */ int fp_exception_el(CPUARMState *env, int cur_el) @@ -13152,7 +11410,8 @@ int fp_exception_el(CPUARMState *env, int cur_el) #ifndef CONFIG_USER_ONLY uint64_t hcr_el2; - /* CPACR and the CPTR registers don't exist before v6, so FP is + /* + * CPACR and the CPTR registers don't exist before v6, so FP is * always accessible */ if (!arm_feature(env, ARM_FEATURE_V6)) { @@ -13177,37 +11436,33 @@ int fp_exception_el(CPUARMState *env, int cur_el) hcr_el2 = arm_hcr_el2_eff(env); - /* The CPACR controls traps to EL1, or PL1 if we're 32 bit: + /* + * The CPACR controls traps to EL1, or PL1 if we're 32 bit: * 0, 2 : trap EL0 and EL1/PL1 accesses * 1 : trap only EL0 accesses * 3 : trap no accesses * This register is ignored if E2H+TGE are both set. */ if ((hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - int fpen = extract32(env->cp15.cpacr_el1, 20, 2); + int fpen = FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, FPEN); switch (fpen) { + case 1: + if (cur_el != 0) { + break; + } + /* fall through */ case 0: case 2: - if (cur_el == 0 || cur_el == 1) { - /* Trap to PL1, which might be EL1 or EL3 */ - if (arm_is_secure(env) && !arm_el_is_aa64(env, 3)) { - return 3; - } - return 1; - } - if (cur_el == 3 && !is_a64(env)) { - /* Secure PL1 running at EL3 */ + /* Trap from Secure PL0 or PL1 to Secure PL1. */ + if (!arm_el_is_aa64(env, 3) + && (cur_el == 3 || arm_is_secure_below_el3(env))) { return 3; } - break; - case 1: - if (cur_el == 0) { + if (cur_el <= 1) { return 1; } break; - case 3: - break; } } @@ -13230,8 +11485,7 @@ int fp_exception_el(CPUARMState *env, int cur_el) */ if (cur_el <= 2) { if (hcr_el2 & HCR_E2H) { - /* Check CPTR_EL2.FPEN. */ - switch (extract32(env->cp15.cptr_el[2], 20, 2)) { + switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, FPEN)) { case 1: if (cur_el != 0 || !(hcr_el2 & HCR_TGE)) { break; @@ -13242,14 +11496,14 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 2; } } else if (arm_is_el2_enabled(env)) { - if (env->cp15.cptr_el[2] & CPTR_TFP) { + if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TFP)) { return 2; } } } /* CPTR_EL3 : present in v8 */ - if (env->cp15.cptr_el[3] & CPTR_TFP) { + if (FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, TFP)) { /* Trap all FP ops to EL3 */ return 3; } @@ -13267,22 +11521,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(); @@ -13296,6 +11543,15 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) } #endif +static bool arm_pan_enabled(CPUARMState *env) +{ + if (is_a64(env)) { + return env->pstate & PSTATE_PAN; + } else { + return env->uncached_cpsr & CPSR_PAN; + } +} + ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) { ARMMMUIdx idx; @@ -13316,7 +11572,7 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) } break; case 1: - if (env->pstate & PSTATE_PAN) { + if (arm_pan_enabled(env)) { idx = ARMMMUIdx_E10_1_PAN; } else { idx = ARMMMUIdx_E10_1; @@ -13325,7 +11581,7 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) case 2: /* Note that TGE does not apply at EL2. */ if (arm_hcr_el2_eff(env) & HCR_E2H) { - if (env->pstate & PSTATE_PAN) { + if (arm_pan_enabled(env)) { idx = ARMMMUIdx_E20_2_PAN; } else { idx = ARMMMUIdx_E20_2; @@ -13335,15 +11591,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; } @@ -13352,13 +11604,6 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } -#ifndef CONFIG_USER_ONLY -ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) -{ - return stage_1_mmu_idx(arm_mmu_idx(env)); -} -#endif - static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx, CPUARMTBFlags flags) @@ -13415,21 +11660,17 @@ static CPUARMTBFlags rebuild_hflags_m32(CPUARMState *env, int fp_el, DP_TBFLAG_M32(flags, STACKCHECK, 1); } - return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); -} - -static CPUARMTBFlags rebuild_hflags_aprofile(CPUARMState *env) -{ - CPUARMTBFlags flags = {}; + if (arm_feature(env, ARM_FEATURE_M_SECURITY) && env->v7m.secure) { + DP_TBFLAG_M32(flags, SECURE, 1); + } - DP_TBFLAG_ANY(flags, DEBUG_TARGET_EL, arm_debug_target_el(env)); - return flags; + return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx) { - CPUARMTBFlags flags = rebuild_hflags_aprofile(env); + CPUARMTBFlags flags = {}; int el = arm_current_el(env); if (arm_sctlr(env, el) & SCTLR_A) { @@ -13449,15 +11690,29 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, DP_TBFLAG_ANY(flags, PSTATE__IL, 1); } + /* + * The SME exception we are testing for is raised via + * AArch64.CheckFPAdvSIMDEnabled(), as called from + * AArch32.CheckAdvSIMDOrFPEnabled(). + */ + if (el == 0 + && FIELD_EX64(env->svcr, SVCR, SM) + && (!arm_is_el2_enabled(env) + || (arm_el_is_aa64(env, 2) && !(env->cp15.hcr_el2 & HCR_TGE))) + && arm_el_is_aa64(env, 1) + && !sme_fa64(env, el)) { + DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1); + } + return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, ARMMMUIdx mmu_idx) { - CPUARMTBFlags flags = rebuild_hflags_aprofile(env); + CPUARMTBFlags flags = {}; ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx); - uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; + uint64_t tcr = regime_tcr(env, mmu_idx); uint64_t sctlr; int tbii, tbid; @@ -13472,19 +11727,41 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { int sve_el = sve_exception_el(env, el); - uint32_t zcr_len; /* - * If SVE is disabled, but FP is enabled, - * then the effective len is 0. + * If either FP or SVE are disabled, translator does not need len. + * If SVE EL > FP EL, FP exception has precedence, and translator + * does not need SVE EL. Save potential re-translations by forcing + * the unneeded data to zero. */ - if (sve_el != 0 && fp_el == 0) { - zcr_len = 0; - } else { - zcr_len = sve_zcr_len_for_el(env, el); + if (fp_el != 0) { + if (sve_el > fp_el) { + sve_el = 0; + } + } else if (sve_el == 0) { + DP_TBFLAG_A64(flags, VL, sve_vqm1_for_el(env, el)); } DP_TBFLAG_A64(flags, SVEEXC_EL, sve_el); - DP_TBFLAG_A64(flags, ZCR_LEN, zcr_len); + } + if (cpu_isar_feature(aa64_sme, env_archcpu(env))) { + int sme_el = sme_exception_el(env, el); + bool sm = FIELD_EX64(env->svcr, SVCR, SM); + + DP_TBFLAG_A64(flags, SMEEXC_EL, sme_el); + if (sme_el == 0) { + /* Similarly, do not compute SVL if SME is disabled. */ + int svl = sve_vqm1_for_el_sm(env, el, true); + DP_TBFLAG_A64(flags, SVL, svl); + if (sm) { + /* If SVE is disabled, we will not have set VL above. */ + DP_TBFLAG_A64(flags, VL, svl); + } + } + if (sm) { + DP_TBFLAG_A64(flags, PSTATE_SM, 1); + DP_TBFLAG_A64(flags, SME_TRAP_NONSTREAMING, !sme_fa64(env, el)); + } + DP_TBFLAG_A64(flags, PSTATE_ZA, FIELD_EX64(env->svcr, SVCR, ZA)); } sctlr = regime_sctlr(env, stage1); @@ -13521,15 +11798,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. @@ -13814,6 +12087,21 @@ void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) } } +static uint32_t sve_vqm1_for_el_sm_ena(CPUARMState *env, int el, bool sm) +{ + int exc_el; + + if (sm) { + exc_el = sme_exception_el(env, el); + } else { + exc_el = sve_exception_el(env, el); + } + if (exc_el) { + return 0; /* disabled */ + } + return sve_vqm1_for_el_sm(env, el, sm); +} + /* * Notice a change in SVE vector size when changing EL. */ @@ -13822,7 +12110,7 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, { ARMCPU *cpu = env_archcpu(env); int old_len, new_len; - bool old_a64, new_a64; + bool old_a64, new_a64, sm; /* Nothing to do if no SVE. */ if (!cpu_isar_feature(aa64_sve, cpu)) { @@ -13834,6 +12122,20 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, return; } + old_a64 = old_el ? arm_el_is_aa64(env, old_el) : el0_a64; + new_a64 = new_el ? arm_el_is_aa64(env, new_el) : el0_a64; + + /* + * Both AArch64.TakeException and AArch64.ExceptionReturn + * invoke ResetSVEState when taking an exception from, or + * returning to, AArch32 state when PSTATE.SM is enabled. + */ + sm = FIELD_EX64(env->svcr, SVCR, SM); + if (old_a64 != new_a64 && sm) { + arm_reset_sve_state(env); + return; + } + /* * DDI0584A.d sec 3.2: "If SVE instructions are disabled or trapped * at ELx, or not available because the EL is in AArch32 state, then @@ -13846,12 +12148,13 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, * we already have the correct register contents when encountering the * vq0->vq0 transition between EL0->EL1. */ - old_a64 = old_el ? arm_el_is_aa64(env, old_el) : el0_a64; - old_len = (old_a64 && !sve_exception_el(env, old_el) - ? sve_zcr_len_for_el(env, old_el) : 0); - new_a64 = new_el ? arm_el_is_aa64(env, new_el) : el0_a64; - new_len = (new_a64 && !sve_exception_el(env, new_el) - ? sve_zcr_len_for_el(env, new_el) : 0); + old_len = new_len = 0; + if (old_a64) { + old_len = sve_vqm1_for_el_sm_ena(env, old_el, sm); + } + if (new_a64) { + new_len = sve_vqm1_for_el_sm_ena(env, new_el, sm); + } /* When changing vector length, clear inaccessible state. */ if (new_len < old_len) { diff --git a/target/arm/helper.h b/target/arm/helper.h index b463d9343bce..92f36d9dbb7b 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -44,9 +44,11 @@ DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_2(exception_internal, void, env, i32) -DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32) -DEF_HELPER_2(exception_bkpt_insn, void, env, i32) +DEF_HELPER_2(exception_internal, noreturn, env, i32) +DEF_HELPER_3(exception_with_syndrome, noreturn, env, i32, i32) +DEF_HELPER_4(exception_with_syndrome_el, noreturn, env, i32, i32, i32) +DEF_HELPER_2(exception_bkpt_insn, noreturn, env, i32) +DEF_HELPER_2(exception_swstep, noreturn, env, i32) DEF_HELPER_2(exception_pc_alignment, noreturn, env, tl) DEF_HELPER_1(setend, void, env) DEF_HELPER_2(wfi, void, env, i32) @@ -54,6 +56,7 @@ DEF_HELPER_1(wfe, void, env) DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) +DEF_HELPER_1(vesb, void, env) DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_2(cpsr_write_eret, void, env, i32) @@ -1016,9 +1019,28 @@ DEF_HELPER_FLAGS_6(gvec_bfmlal, TCG_CALL_NO_RWG, DEF_HELPER_FLAGS_6(gvec_bfmlal_idx, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_uclamp_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uclamp_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uclamp_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uclamp_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" +#include "helper-sme.h" #endif #include "helper-mve.h" diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 8c34f86792ed..060aa0ccf4b0 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -10,7 +10,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "sysemu/runstate.h" @@ -18,6 +17,7 @@ #include "sysemu/hvf_int.h" #include "sysemu/hw_accel.h" #include "hvf_arm.h" +#include "cpregs.h" #include @@ -565,7 +565,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) hv_return_t ret; int i; - env->aarch64 = 1; + env->aarch64 = true; asm volatile("mrs %0, cntfrq_el0" : "=r"(arm_cpu->gt_cntfrq_hz)); /* Allocate enough space for our sysreg sync */ @@ -978,8 +978,8 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) } } - env->cp15.c9_pmcr &= ~PMCR_WRITEABLE_MASK; - env->cp15.c9_pmcr |= (val & PMCR_WRITEABLE_MASK); + env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK; + env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK); pmu_op_finish(env); break; @@ -1201,7 +1201,7 @@ int hvf_vcpu_exec(CPUState *cpu) /* we got kicked, no exit to process */ return 0; default: - assert(0); + g_assert_not_reached(); } hvf_sync_vtimer(cpu); diff --git a/target/arm/internals.h b/target/arm/internals.h index 7f696cd36a8c..d9555309df0f 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -81,6 +81,18 @@ FIELD(V7M_EXCRET, RES1, 7, 25) /* including the must-be-1 prefix */ */ #define FNC_RETURN_MIN_MAGIC 0xfefffffe +/* Bit definitions for DBGWCRn and DBGWCRn_EL1 */ +FIELD(DBGWCR, E, 0, 1) +FIELD(DBGWCR, PAC, 1, 2) +FIELD(DBGWCR, LSC, 3, 2) +FIELD(DBGWCR, BAS, 5, 8) +FIELD(DBGWCR, HMC, 13, 1) +FIELD(DBGWCR, SSC, 14, 2) +FIELD(DBGWCR, LBN, 16, 4) +FIELD(DBGWCR, WT, 20, 1) +FIELD(DBGWCR, MASK, 24, 5) +FIELD(DBGWCR, SSCE, 29, 1) + /* We use a few fake FSR values for internal purposes in M profile. * M profile cores don't have A/R format FSRs, but currently our * get_phys_addr() code assumes A/R profile and reports failures via @@ -102,13 +114,13 @@ FIELD(V7M_EXCRET, RES1, 7, 25) /* including the must-be-1 prefix */ * and target exception level. This should be called from helper functions, * and never returns because we will longjump back up to the CPU main loop. */ -void QEMU_NORETURN raise_exception(CPUARMState *env, uint32_t excp, - uint32_t syndrome, uint32_t target_el); +G_NORETURN void raise_exception(CPUARMState *env, uint32_t excp, + uint32_t syndrome, uint32_t target_el); /* * Similarly, but also use unwinding to restore cpu state. */ -void QEMU_NORETURN raise_exception_ra(CPUARMState *env, uint32_t excp, +G_NORETURN void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome, uint32_t target_el, uintptr_t ra); @@ -173,21 +185,14 @@ static inline int r14_bank_number(int mode) void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); void arm_translate_init(void); +void arm_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data); + #ifdef CONFIG_TCG void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); #endif /* CONFIG_TCG */ -/** - * aarch64_sve_zcr_get_valid_len: - * @cpu: cpu context - * @start_len: maximum len to consider - * - * Return the maximum supported sve vector length <= @start_len. - * Note that both @start_len and the return value are in units - * of ZCR_ELx.LEN, so the vector bit length is (x + 1) * 128. - */ -uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len); - enum arm_fprounding { FPROUNDING_TIEEVEN, FPROUNDING_POSINF, @@ -251,9 +256,13 @@ unsigned int arm_pamax(ARMCPU *cpu); */ static inline bool extended_addresses_enabled(CPUARMState *env) { - TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + uint64_t tcr = env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + if (arm_feature(env, ARM_FEATURE_PMSA) && + arm_feature(env, ARM_FEATURE_V8)) { + return true; + } return arm_el_is_aa64(env, 1) || - (arm_feature(env, ARM_FEATURE_LPAE) && (tcr->raw_tcr & TTBCR_EAE)); + (arm_feature(env, ARM_FEATURE_LPAE) && (tcr & TTBCR_EAE)); } /* Update a QEMU watchpoint based on the information the guest has set in the @@ -337,6 +346,7 @@ typedef enum ARMFaultType { ARMFault_AsyncExternal, ARMFault_Debug, ARMFault_TLBConflict, + ARMFault_UnsuppAtomicUpdate, ARMFault_Lockdown, ARMFault_Exclusive, ARMFault_ICacheMaint, @@ -523,6 +533,9 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) case ARMFault_TLBConflict: fsc = 0x30; break; + case ARMFault_UnsuppAtomicUpdate: + fsc = 0x31; + break; case ARMFault_Lockdown: fsc = 0x34; break; @@ -601,14 +614,19 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, /* Return the MMU index for a v7M CPU in the specified security state */ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate); -/* Return true if the stage 1 translation regime is using LPAE format page - * tables */ +/* Return true if the translation regime is using LPAE format page tables */ +bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx); + +/* + * Return true if the stage 1 translation regime is using LPAE + * format page tables + */ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx); /* Raise a data fault alignment exception for the specified virtual address */ -void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); /* arm_cpu_do_transaction_failed: handle a memory system error response * (eg "no device/memory present at address") by raising an external abort @@ -643,112 +661,53 @@ 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; } } +static inline bool regime_is_stage2(ARMMMUIdx mmu_idx) +{ + return mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S; +} + /* Return the exception level which controls this address translation regime */ 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: @@ -765,45 +724,61 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) } } -/* Return the TCR controlling this translation regime */ -static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) +static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) { - if (mmu_idx == ARMMMUIdx_Stage2) { - return &env->cp15.vtcr_el2; - } - if (mmu_idx == ARMMMUIdx_Stage2_S) { - /* - * Note: Secure stage 2 nominally shares fields from VTCR_EL2, but - * those are not currently used by QEMU, so just return VSTCR_EL2. - */ - return &env->cp15.vstcr_el2; + switch (mmu_idx) { + case ARMMMUIdx_E20_0: + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_MUser: + case ARMMMUIdx_MSUser: + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MSUserNegPri: + return true; + default: + return false; + case ARMMMUIdx_E10_0: + case ARMMMUIdx_E10_1: + case ARMMMUIdx_E10_1_PAN: + g_assert_not_reached(); } - return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; } -/* Return the FSR value for a debug exception (watchpoint, hardware - * breakpoint or BKPT insn) targeting the specified exception level. - */ -static inline uint32_t arm_debug_exception_fsr(CPUARMState *env) +/* Return the SCTLR value which controls this address translation regime */ +static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx) { - ARMMMUFaultInfo fi = { .type = ARMFault_Debug }; - int target_el = arm_debug_target_el(env); - bool using_lpae = false; + return env->cp15.sctlr_el[regime_el(env, mmu_idx)]; +} - if (target_el == 2 || arm_el_is_aa64(env, target_el)) { - using_lpae = true; - } else { - if (arm_feature(env, ARM_FEATURE_LPAE) && - (env->cp15.tcr_el[target_el].raw_tcr & TTBCR_EAE)) { - using_lpae = true; - } - } +/* + * These are the fields in VTCR_EL2 which affect both the Secure stage 2 + * and the Non-Secure stage 2 translation regimes (and hence which are + * not present in VSTCR_EL2). + */ +#define VTCR_SHARED_FIELD_MASK \ + (R_VTCR_IRGN0_MASK | R_VTCR_ORGN0_MASK | R_VTCR_SH0_MASK | \ + R_VTCR_PS_MASK | R_VTCR_VS_MASK | R_VTCR_HA_MASK | R_VTCR_HD_MASK | \ + R_VTCR_DS_MASK) - if (using_lpae) { - return arm_fi_to_lfsc(&fi); - } else { - return arm_fi_to_sfsc(&fi); +/* Return the value of the TCR controlling this translation regime */ +static inline uint64_t regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + if (mmu_idx == ARMMMUIdx_Stage2) { + return env->cp15.vtcr_el2; } + if (mmu_idx == ARMMMUIdx_Stage2_S) { + /* + * Secure stage 2 shares fields from VTCR_EL2. We merge those + * in with the VSTCR_EL2 value to synthesize a single VTCR_EL2 format + * value so the callers don't need to special case this. + * + * If a future architecture change defines bits in VSTCR_EL2 that + * overlap with these VTCR_EL2 fields we may need to revisit this. + */ + uint64_t v = env->cp15.vstcr_el2 & ~VTCR_SHARED_FIELD_MASK; + v |= env->cp15.vtcr_el2 & VTCR_SHARED_FIELD_MASK; + return v; + } + return env->cp15.tcr_el[regime_el(env, mmu_idx)]; } /** @@ -935,6 +910,14 @@ void arm_cpu_update_virq(ARMCPU *cpu); */ void arm_cpu_update_vfiq(ARMCPU *cpu); +/** + * arm_cpu_update_vserr: Update CPU_INTERRUPT_VSERR bit + * + * Update the CPU_INTERRUPT_VSERR bit in cs->interrupt_request, + * following a change to the HCR_EL2.VSE bit. + */ +void arm_cpu_update_vserr(ARMCPU *cpu); + /** * arm_mmu_idx_el: * @env: The cpu environment @@ -959,11 +942,16 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env); * Return the ARMMMUIdx for the stage1 traversal for the current regime. */ #ifdef CONFIG_USER_ONLY +static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) +{ + return ARMMMUIdx_Stage1_E0; +} static inline ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) { return ARMMMUIdx_Stage1_E0; } #else +ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx); ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env); #endif @@ -980,9 +968,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; @@ -1049,6 +1034,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. @@ -1061,29 +1075,18 @@ 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; + bool ha : 1; + bool hd : 1; + ARMGranuleSize gran : 2; } ARMVAParameters; ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMMMUIdx mmu_idx, bool data); -static inline int exception_target_el(CPUARMState *env) -{ - int target_el = MAX(1, arm_current_el(env)); - - /* - * No such thing as secure EL1 if EL3 is aarch32, - * so update the target EL to EL3 in this case. - */ - if (arm_is_secure(env) && !arm_el_is_aa64(env, 3) && target_el == 1) { - target_el = 3; - } - - return target_el; -} +int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx); +int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx); /* Determine if allocation tags are available. */ static inline bool allocation_tag_access_enabled(CPUARMState *env, int el, @@ -1119,27 +1122,76 @@ 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 { - unsigned int attrs:8; /* as in the MAIR register encoding */ + /* + * If is_s2_format is true, attrs is the S2 descriptor bits [5:2] + * Otherwise, attrs is the same as the MAIR_EL1 8-bit format + */ + unsigned int attrs:8; unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */ + bool is_s2_format:1; + bool guarded:1; /* guarded bit of the v8-64 PTE */ } 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 */ @@ -1150,10 +1202,6 @@ void arm_log_exception(CPUState *cs); */ #define GMID_EL1_BS 6 -/* We associate one allocation tag per 16 bytes, the minimum. */ -#define LOG2_TAG_GRANULE 4 -#define TAG_GRANULE (1 << LOG2_TAG_GRANULE) - /* * SVE predicates are 1/8 the size of SVE vectors, and cannot use * the same simd_desc() encoding due to restrictions on size. @@ -1247,6 +1295,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 @@ -1255,10 +1304,10 @@ enum MVEECIState { #define PMCRP 0x2 #define PMCRE 0x1 /* - * Mask of PMCR bits writeable by guest (not including WO bits like C, P, + * 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_WRITEABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) +#define PMCR_WRITABLE_MASK (PMCRLP | PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) #define PMXEVTYPER_P 0x80000000 #define PMXEVTYPER_U 0x40000000 @@ -1279,13 +1328,15 @@ enum MVEECIState { static inline uint32_t pmu_num_counters(CPUARMState *env) { - return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT; + ARMCPU *cpu = env_archcpu(env); + + return (cpu->isar.reset_pmcr_el0 & PMCRN_MASK) >> PMCRN_SHIFT; } /* 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 @@ -1293,6 +1344,37 @@ int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg); int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg); int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg); int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg); +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp); +void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp); +void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp); +void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp); #endif +#ifdef CONFIG_USER_ONLY +static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } +#else +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); +#endif + +bool el_is_in_host(CPUARMState *env, int el); + +void aa32_max_features(ARMCPU *cpu); +int exception_target_el(CPUARMState *env); +bool arm_singlestep_active(CPUARMState *env); +bool arm_generate_debug_exceptions(CPUARMState *env); + +/* Add the cpreg definitions for debug related system registers */ +void define_debug_regs(ARMCPU *cpu); + +/* Effective value of MDCR_EL2 */ +static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env) +{ + return arm_is_el2_enabled(env) ? env->cp15.mdcr_el2 : 0; +} + +/* Powers of 2 for sve_vq_map et al. */ +#define SVE_VQ_POW2_MAP \ + ((1 << (1 - 1)) | (1 << (2 - 1)) | \ + (1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1))) + #endif diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h index faacf96fdc71..09967ec5e641 100644 --- a/target/arm/kvm-consts.h +++ b/target/arm/kvm-consts.h @@ -14,16 +14,16 @@ #ifndef ARM_KVM_CONSTS_H #define ARM_KVM_CONSTS_H +#ifdef NEED_CPU_H #ifdef CONFIG_KVM #include #include - #define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(X != Y) +#endif +#endif -#else - +#ifndef MISMATCH_CHECK #define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(0) - #endif #define CP_REG_SIZE_SHIFT 52 diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index 56a7099e6b98..965a486b3202 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -15,10 +15,10 @@ bool write_kvmstate_to_list(ARMCPU *cpu) { - abort(); + g_assert_not_reached(); } bool write_list_to_kvmstate(ARMCPU *cpu, int level) { - abort(); + g_assert_not_reached(); } diff --git a/target/arm/kvm.c b/target/arm/kvm.c index bbf1ce7ba3bc..f022c644d2ff 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -13,7 +13,6 @@ #include -#include "qemu-common.h" #include "qemu/timer.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" @@ -80,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; } @@ -541,7 +542,7 @@ bool write_kvmstate_to_list(ARMCPU *cpu) ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); break; default: - abort(); + g_assert_not_reached(); } if (ret) { ok = false; @@ -576,7 +577,7 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) r.addr = (uintptr_t)(cpu->cpreg_values + i); break; default: - abort(); + g_assert_not_reached(); } ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); if (ret) { @@ -960,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); } @@ -1057,3 +1058,7 @@ bool kvm_arch_cpu_check_are_resettable(void) { return true; } + +void kvm_arch_accel_class_init(ObjectClass *oc) +{ +} diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index ccadfbbe72be..1197253d12f7 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -16,7 +16,6 @@ #include #include -#include "qemu-common.h" #include "qapi/error.h" #include "cpu.h" #include "qemu/timer.h" @@ -209,7 +208,7 @@ static int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type) { HWWatchpoint wp = { - .wcr = 1, /* E=1, enable */ + .wcr = R_DBGWCR_E_MASK, /* E=1, enable */ .wvr = addr & (~0x7ULL), .details = { .vaddr = addr, .len = len } }; @@ -222,19 +221,19 @@ static int insert_hw_watchpoint(target_ulong addr, * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state, * valid whether EL3 is implemented or not */ - wp.wcr = deposit32(wp.wcr, 1, 2, 3); + wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3); switch (type) { case GDB_WATCHPOINT_READ: - wp.wcr = deposit32(wp.wcr, 3, 2, 1); + wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1); wp.details.flags = BP_MEM_READ; break; case GDB_WATCHPOINT_WRITE: - wp.wcr = deposit32(wp.wcr, 3, 2, 2); + wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2); wp.details.flags = BP_MEM_WRITE; break; case GDB_WATCHPOINT_ACCESS: - wp.wcr = deposit32(wp.wcr, 3, 2, 3); + wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3); wp.details.flags = BP_MEM_ACCESS; break; default: @@ -253,8 +252,8 @@ static int insert_hw_watchpoint(target_ulong addr, int bits = ctz64(len); wp.wvr &= ~((1 << bits) - 1); - wp.wcr = deposit32(wp.wcr, 24, 4, bits); - wp.wcr = deposit32(wp.wcr, 5, 8, 0xff); + wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits); + wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff); } else { return -ENOBUFS; } @@ -506,8 +505,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) */ int fdarray[3]; 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,16 +527,28 @@ 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 | 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC); } + if (kvm_arm_pmu_supported()) { + init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3; + pmu_supported = true; + } + if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) { return false; } @@ -569,6 +580,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) } else { err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, ARM64_SYS_REG(3, 0, 0, 4, 1)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0, + ARM64_SYS_REG(3, 0, 0, 4, 5)); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, ARM64_SYS_REG(3, 0, 0, 5, 0)); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, @@ -595,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, @@ -630,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 @@ -660,24 +677,24 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) dbgdidr |= (1 << 15); /* RES1 bit */ ahcf->isar.dbgdidr = dbgdidr; } - } - 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; + if (pmu_supported) { + /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */ + err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0, + ARM64_SYS_REG(3, 3, 9, 12, 0)); + } - /* - * Before v5.1, KVM did not support SVE and did not expose - * ID_AA64ZFR0_EL1 even as RAZ. After v5.1, KVM still does - * not expose the register to "user" requests like this - * unless the host supports SVE. - */ - 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); @@ -749,15 +766,13 @@ bool kvm_arm_steal_time_supported(void) QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1); -void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) +uint32_t kvm_arm_sve_get_vls(CPUState *cs) { /* Only call this function if kvm_arm_sve_supported() returns true. */ static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS]; static bool probed; uint32_t vq = 0; - int i, j; - - bitmap_zero(map, ARM_MAX_VQ); + int i; /* * KVM ensures all host CPUs support the same set of vector lengths. @@ -798,46 +813,24 @@ void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) if (vq > ARM_MAX_VQ) { warn_report("KVM supports vector lengths larger than " "QEMU can enable"); + vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ); } } - for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) { - if (!vls[i]) { - continue; - } - for (j = 1; j <= 64; ++j) { - vq = j + i * 64; - if (vq > ARM_MAX_VQ) { - return; - } - if (vls[i] & (1UL << (j - 1))) { - set_bit(vq - 1, map); - } - } - } + return vls[0]; } static int kvm_arm_sve_set_vls(CPUState *cs) { - uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0}; + ARMCPU *cpu = ARM_CPU(cs); + uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = { cpu->sve_vq.map }; struct kvm_one_reg reg = { .id = KVM_REG_ARM64_SVE_VLS, .addr = (uint64_t)&vls[0], }; - ARMCPU *cpu = ARM_CPU(cs); - uint32_t vq; - int i, j; assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX); - for (vq = 1; vq <= cpu->sve_max_vq; ++vq) { - if (test_bit(vq - 1, cpu->sve_vq_map)) { - i = (vq - 1) / 64; - j = (vq - 1) % 64; - vls[i] |= 1UL << j; - } - } - return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } @@ -1023,7 +1016,7 @@ static int kvm_arch_put_fpsimd(CPUState *cs) for (i = 0; i < 32; i++) { uint64_t *q = aa64_vfp_qreg(env, i); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint64_t fp_val[2] = { q[1], q[0] }; reg.addr = (uintptr_t)fp_val; #else @@ -1242,7 +1235,7 @@ static int kvm_arch_get_fpsimd(CPUState *cs) if (ret) { return ret; } else { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint64_t t; t = q[0], q[0] = q[1], q[1] = t; #endif diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index b7f78b521545..99017b635ce4 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -239,13 +239,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); /** * kvm_arm_sve_get_vls: * @cs: CPUState - * @map: bitmap to fill in * * Get all the SVE vector lengths supported by the KVM host, setting * the bits corresponding to their length in quadwords minus one - * (vq - 1) in @map up to ARM_MAX_VQ. + * (vq - 1) up to ARM_MAX_VQ. Return the resulting map. */ -void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map); +uint32_t kvm_arm_sve_get_vls(CPUState *cs); /** * kvm_arm_set_cpu_features_from_host: @@ -439,7 +438,7 @@ static inline void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp) g_assert_not_reached(); } -static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) +static inline uint32_t kvm_arm_sve_get_vls(CPUState *cs) { g_assert_not_reached(); } diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index b7a0fe011412..033a4d92614a 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -7,30 +7,14 @@ */ #include "qemu/osdep.h" -#include "qemu/units.h" -#include "target/arm/idau.h" -#include "trace.h" #include "cpu.h" #include "internals.h" -#include "exec/gdbstub.h" #include "exec/helper-proto.h" -#include "qemu/host-utils.h" #include "qemu/main-loop.h" #include "qemu/bitops.h" -#include "qemu/crc32c.h" -#include "qemu/qemu-print.h" #include "qemu/log.h" #include "exec/exec-all.h" -#include /* For crc32 */ -#include "semihosting/semihost.h" -#include "sysemu/cpus.h" -#include "sysemu/kvm.h" -#include "qemu/range.h" -#include "qapi/qapi-commands-machine-target.h" -#include "qapi/error.h" -#include "qemu/guest-random.h" #ifdef CONFIG_TCG -#include "arm_ldst.h" #include "exec/cpu_ldst.h" #include "semihosting/common-semi.h" #endif @@ -183,19 +167,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 +207,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 +255,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 +282,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"); @@ -564,7 +538,7 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK; } switch_v7m_security_state(env, dest & 1); - env->thumb = 1; + env->thumb = true; env->regs[15] = dest & ~1; arm_rebuild_hflags(env); } @@ -590,7 +564,7 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) * except that the low bit doesn't indicate Thumb/not. */ env->regs[14] = nextinst; - env->thumb = 1; + env->thumb = true; env->regs[15] = dest & ~1; return; } @@ -626,7 +600,7 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) } env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK; switch_v7m_security_state(env, 0); - env->thumb = 1; + env->thumb = true; env->regs[15] = dest; arm_rebuild_hflags(env); } @@ -699,7 +673,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 +1965,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 +1983,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 +1999,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 +2030,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 +2053,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 +2092,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 +2108,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; } @@ -2373,7 +2338,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) "...handling as semihosting call 0x%x\n", env->regs[0]); #ifdef CONFIG_TCG - env->regs[0] = do_common_semihosting(cs); + do_common_semihosting(cs); #else g_assert_not_reached(); #endif @@ -2790,15 +2755,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 +2789,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 +2811,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/machine.c b/target/arm/machine.c index 135d2420b5c9..5f2615265256 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -167,6 +167,39 @@ static const VMStateDescription vmstate_sve = { VMSTATE_END_OF_LIST() } }; + +static const VMStateDescription vmstate_vreg = { + .name = "vreg", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64_ARRAY(d, ARMVectorReg, ARM_MAX_VQ * 2), + VMSTATE_END_OF_LIST() + } +}; + +static bool za_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + + /* + * When ZA storage is disabled, its contents are discarded. + * It will be zeroed when ZA storage is re-enabled. + */ + return FIELD_EX64(cpu->env.svcr, SVCR, ZA); +} + +static const VMStateDescription vmstate_za = { + .name = "cpu/sme", + .version_id = 1, + .minimum_version_id = 1, + .needed = za_needed, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(env.zarray, ARMCPU, ARM_MAX_VQ * 16, 0, + vmstate_vreg, ARMVectorReg), + VMSTATE_END_OF_LIST() + } +}; #endif /* AARCH64 */ static bool serror_needed(void *opaque) @@ -454,6 +487,30 @@ static bool pmsav8_needed(void *opaque) arm_feature(env, ARM_FEATURE_V8); } +static bool pmsav8r_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + return arm_feature(env, ARM_FEATURE_PMSA) && + arm_feature(env, ARM_FEATURE_V8) && + !arm_feature(env, ARM_FEATURE_M); +} + +static const VMStateDescription vmstate_pmsav8r = { + .name = "cpu/pmsav8/pmsav8r", + .version_id = 1, + .minimum_version_id = 1, + .needed = pmsav8r_needed, + .fields = (VMStateField[]) { + VMSTATE_VARRAY_UINT32(env.pmsav8.hprbar, ARMCPU, + pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t), + VMSTATE_VARRAY_UINT32(env.pmsav8.hprlar, ARMCPU, + pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_pmsav8 = { .name = "cpu/pmsav8", .version_id = 1, @@ -467,6 +524,10 @@ static const VMStateDescription vmstate_pmsav8 = { VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU), VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_pmsav8r, + NULL } }; @@ -661,7 +722,7 @@ static int cpu_pre_save(void *opaque) if (kvm_enabled()) { if (!write_kvmstate_to_list(cpu)) { /* This should never fail */ - abort(); + g_assert_not_reached(); } /* @@ -672,7 +733,7 @@ static int cpu_pre_save(void *opaque) } else { if (!write_cpustate_to_list(cpu, false)) { /* This should never fail. */ - abort(); + g_assert_not_reached(); } } @@ -884,6 +945,7 @@ const VMStateDescription vmstate_arm_cpu = { &vmstate_m_security, #ifdef TARGET_AARCH64 &vmstate_sve, + &vmstate_za, #endif &vmstate_serror, &vmstate_irq_line_state, diff --git a/target/arm/meson.build b/target/arm/meson.build index 50f152214afe..87e911b27fb0 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -1,5 +1,7 @@ gen = [ decodetree.process('sve.decode', extra_args: '--decode=disas_sve'), + decodetree.process('sme.decode', extra_args: '--decode=disas_sme'), + decodetree.process('sme-fa64.decode', extra_args: '--static-decode=disas_sme_fa64'), decodetree.process('neon-shared.decode', extra_args: '--decode=disas_neon_shared'), decodetree.process('neon-dp.decode', extra_args: '--decode=disas_neon_dp'), decodetree.process('neon-ls.decode', extra_args: '--decode=disas_neon_ls'), @@ -47,8 +49,10 @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'mte_helper.c', 'pauth_helper.c', 'sve_helper.c', + 'sme_helper.c', 'translate-a64.c', 'translate-sve.c', + 'translate-sme.c', )) arm_softmmu_ss = ss.source_set() @@ -58,6 +62,7 @@ arm_softmmu_ss.add(files( 'machine.c', 'monitor.c', 'psci.c', + 'ptw.c', )) subdir('hvf') diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 80c64fa3556d..ecdd5ee81742 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -221,7 +221,6 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, qobject_unref(qdict_out); } else { expansion_info->model->props = QOBJECT(qdict_out); - expansion_info->model->has_props = true; } object_unref(obj); diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index d11a8c70d041..86b37548386f 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -95,20 +95,14 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, } tags = page_get_target_data(clean_ptr); - if (tags == NULL) { - size_t alloc_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1); - tags = page_alloc_target_data(clean_ptr, alloc_size); - assert(tags != NULL); - } index = extract32(ptr, LOG2_TAG_GRANULE + 1, TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1); return tags + index; #else - uintptr_t index; - CPUIOTLBEntry *iotlbentry; + CPUTLBEntryFull *full; + MemTxAttrs attrs; int in_page, flags; - ram_addr_t ptr_ra; hwaddr ptr_paddr, tag_paddr, xlat; MemoryRegion *mr; ARMASIdx tag_asi; @@ -124,30 +118,12 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, * valid. Indicate to probe_access_flags no-fault, then assert that * we received a valid page. */ - flags = probe_access_flags(env, ptr, ptr_access, ptr_mmu_idx, - ra == 0, &host, ra); + flags = probe_access_full(env, ptr, ptr_access, ptr_mmu_idx, + ra == 0, &host, &full, ra); assert(!(flags & TLB_INVALID_MASK)); - /* - * Find the iotlbentry 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. - */ - index = tlb_index(env, ptr_mmu_idx, ptr); -# ifdef CONFIG_DEBUG_TCG - { - CPUTLBEntry *entry = tlb_entry(env, ptr_mmu_idx, ptr); - target_ulong comparator = (ptr_access == MMU_DATA_LOAD - ? entry->addr_read - : tlb_addr_write(entry)); - g_assert(tlb_hit(comparator, ptr)); - } -# endif - iotlbentry = &env_tlb(env)->d[ptr_mmu_idx].iotlb[index]; - /* If the virtual page MemAttr != Tagged, access unchecked. */ - if (!arm_tlb_mte_tagged(&iotlbentry->attrs)) { + if (full->pte_attrs != 0xf0) { return NULL; } @@ -162,6 +138,14 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, return NULL; } + /* + * Remember these values across the second lookup below, + * which may invalidate this pointer via tlb resize. + */ + ptr_paddr = full->phys_addr; + attrs = full->attrs; + full = NULL; + /* * The Normal memory access can extend to the next page. E.g. a single * 8-byte access to the last byte of a page will check only the last @@ -170,9 +154,8 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, */ in_page = -(ptr | TARGET_PAGE_MASK); if (unlikely(ptr_size > in_page)) { - void *ignore; - flags |= probe_access_flags(env, ptr + in_page, ptr_access, - ptr_mmu_idx, ra == 0, &ignore, ra); + flags |= probe_access_full(env, ptr + in_page, ptr_access, + ptr_mmu_idx, ra == 0, &host, &full, ra); assert(!(flags & TLB_INVALID_MASK)); } @@ -180,33 +163,17 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, if (unlikely(flags & TLB_WATCHPOINT)) { 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); + cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, attrs, wp, ra); } - /* - * Find the physical address within the normal mem space. - * The memory region lookup must succeed because TLB_MMIO was - * not set in the cputlb lookup above. - */ - mr = memory_region_from_host(host, &ptr_ra); - tcg_debug_assert(mr != NULL); - tcg_debug_assert(memory_region_is_ram(mr)); - ptr_paddr = ptr_ra; - do { - ptr_paddr += mr->addr; - mr = mr->container; - } while (mr); - /* Convert to the physical address in tag space. */ 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 = 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); + tag_access == MMU_DATA_STORE, attrs); /* * Note that @mr will never be NULL. If there is nothing in the address diff --git a/target/arm/mve_helper.c b/target/arm/mve_helper.c index 846962bf4c5a..403b345ea3b9 100644 --- a/target/arm/mve_helper.c +++ b/target/arm/mve_helper.c @@ -726,7 +726,7 @@ static void mergemask_sb(int8_t *d, int8_t r, uint16_t mask) static void mergemask_uh(uint16_t *d, uint16_t r, uint16_t mask) { - uint16_t bmask = expand_pred_b_data[mask & 3]; + uint16_t bmask = expand_pred_b(mask); *d = (*d & ~bmask) | (r & bmask); } @@ -737,7 +737,7 @@ static void mergemask_sh(int16_t *d, int16_t r, uint16_t mask) static void mergemask_uw(uint32_t *d, uint32_t r, uint16_t mask) { - uint32_t bmask = expand_pred_b_data[mask & 0xf]; + uint32_t bmask = expand_pred_b(mask); *d = (*d & ~bmask) | (r & bmask); } @@ -748,7 +748,7 @@ static void mergemask_sw(int32_t *d, int32_t r, uint16_t mask) static void mergemask_uq(uint64_t *d, uint64_t r, uint16_t mask) { - uint64_t bmask = expand_pred_b_data[mask & 0xff]; + uint64_t bmask = expand_pred_b(mask); *d = (*d & ~bmask) | (r & bmask); } diff --git a/target/arm/neon_helper.c b/target/arm/neon_helper.c index 338b9189d5b2..bc6c4a54e9d9 100644 --- a/target/arm/neon_helper.c +++ b/target/arm/neon_helper.c @@ -23,7 +23,7 @@ typedef struct \ { \ type v1; \ } neon_##name; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define NEON_TYPE2(name, type) \ typedef struct \ { \ diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 70b42b55fd0c..70672bcd9fc2 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -23,10 +23,26 @@ #include "internals.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "cpregs.h" #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) +int exception_target_el(CPUARMState *env) +{ + int target_el = MAX(1, arm_current_el(env)); + + /* + * No such thing as secure EL1 if EL3 is aarch32, + * so update the target EL to EL3 in this case. + */ + if (arm_is_secure(env) && !arm_el_is_aa64(env, 3) && target_el == 1) { + target_el = 3; + } + + return target_el; +} + void raise_exception(CPUARMState *env, uint32_t excp, uint32_t syndrome, uint32_t target_el) { @@ -62,7 +78,7 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome, * we must restore CPU state here before setting the syndrome * the caller passed us, and cannot use cpu_loop_exit_restore(). */ - cpu_restore_state(cs, ra, true); + cpu_restore_state(cs, ra); raise_exception(env, excp, syndrome, target_el); } @@ -365,7 +381,7 @@ void HELPER(yield)(CPUARMState *env) * those EXCP values which are special cases for QEMU to interrupt * execution and not to be used for exceptions which are passed to * the guest (those must all have syndrome information and thus should - * use exception_with_syndrome). + * use exception_with_syndrome*). */ void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) { @@ -377,39 +393,20 @@ void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) } /* Raise an exception with the specified syndrome register value */ -void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, - uint32_t syndrome, uint32_t target_el) +void HELPER(exception_with_syndrome_el)(CPUARMState *env, uint32_t excp, + uint32_t syndrome, uint32_t target_el) { raise_exception(env, excp, syndrome, target_el); } -/* Raise an EXCP_BKPT with the specified syndrome register value, - * targeting the correct exception level for debug exceptions. +/* + * Raise an exception with the specified syndrome register value + * to the default target el. */ -void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome) +void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, + uint32_t syndrome) { - int debug_el = arm_debug_target_el(env); - int cur_el = arm_current_el(env); - - /* FSR will only be used if the debug target EL is AArch32. */ - env->exception.fsr = arm_debug_exception_fsr(env); - /* FAR is UNKNOWN: clear vaddress to avoid potentially exposing - * values to the guest that it shouldn't be able to see at its - * exception/security level. - */ - env->exception.vaddress = 0; - /* - * Other kinds of architectural debug exception are ignored if - * they target an exception level below the current one (in QEMU - * this is checked by arm_generate_debug_exceptions()). Breakpoint - * instructions are special because they always generate an exception - * to somewhere: if they can't go to the configured debug exception - * level they are taken to the current exception level. - */ - if (debug_el < cur_el) { - debug_el = cur_el; - } - raise_exception(env, EXCP_BKPT, syndrome, debug_el); + raise_exception(env, excp, syndrome, exception_target_el(env)); } uint32_t HELPER(cpsr_read)(CPUARMState *env) @@ -630,12 +627,15 @@ uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno) void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, uint32_t isread) { + ARMCPU *cpu = env_archcpu(env); const ARMCPRegInfo *ri = rip; + CPAccessResult res = CP_ACCESS_OK; int target_el; if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 && extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { - raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env)); + res = CP_ACCESS_TRAP; + goto fail; } /* @@ -654,61 +654,54 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, mask &= ~((1 << 4) | (1 << 14)); if (env->cp15.hstr_el2 & mask) { - target_el = 2; - goto exept; + res = CP_ACCESS_TRAP_EL2; + goto fail; } } - if (!ri->accessfn) { + if (ri->accessfn) { + res = ri->accessfn(env, ri, isread); + } + if (likely(res == CP_ACCESS_OK)) { return; } - switch (ri->accessfn(env, ri, isread)) { - case CP_ACCESS_OK: - return; + fail: + switch (res & ~CP_ACCESS_EL_MASK) { case CP_ACCESS_TRAP: - target_el = exception_target_el(env); - break; - case CP_ACCESS_TRAP_EL2: - /* Requesting a trap to EL2 when we're in EL3 is - * a bug in the access function. - */ - assert(arm_current_el(env) != 3); - target_el = 2; - break; - case CP_ACCESS_TRAP_EL3: - target_el = 3; break; case CP_ACCESS_TRAP_UNCATEGORIZED: - target_el = exception_target_el(env); - syndrome = syn_uncategorized(); - break; - case CP_ACCESS_TRAP_UNCATEGORIZED_EL2: - target_el = 2; + if (cpu_isar_feature(aa64_ids, cpu) && isread && + arm_cpreg_in_idspace(ri)) { + /* + * FEAT_IDST says this should be reported as EC_SYSTEMREGISTERTRAP, + * not EC_UNCATEGORIZED + */ + break; + } syndrome = syn_uncategorized(); break; - case CP_ACCESS_TRAP_UNCATEGORIZED_EL3: - target_el = 3; - syndrome = syn_uncategorized(); + default: + g_assert_not_reached(); + } + + target_el = res & CP_ACCESS_EL_MASK; + switch (target_el) { + case 0: + target_el = exception_target_el(env); break; - case CP_ACCESS_TRAP_FP_EL2: - target_el = 2; - /* Since we are an implementation that takes exceptions on a trapped - * conditional insn only if the insn has passed its condition code - * check, we take the IMPDEF choice to always report CV=1 COND=0xe - * (which is also the required value for AArch64 traps). - */ - syndrome = syn_fp_access_trap(1, 0xe, false); + case 2: + assert(arm_current_el(env) != 3); + assert(arm_is_el2_enabled(env)); break; - case CP_ACCESS_TRAP_FP_EL3: - target_el = 3; - syndrome = syn_fp_access_trap(1, 0xe, false); + case 3: + assert(arm_feature(env, ARM_FEATURE_EL3)); break; default: + /* No "direct" traps to EL1 */ g_assert_not_reached(); } -exept: raise_exception(env, EXCP_UDEF, syndrome, target_el); } @@ -972,3 +965,46 @@ void HELPER(probe_access)(CPUARMState *env, target_ulong ptr, access_type, mmu_idx, ra); } } + +/* + * This function corresponds to AArch64.vESBOperation(). + * Note that the AArch32 version is not functionally different. + */ +void HELPER(vesb)(CPUARMState *env) +{ + /* + * The EL2Enabled() check is done inside arm_hcr_el2_eff, + * and will return HCR_EL2.VSE == 0, so nothing happens. + */ + uint64_t hcr = arm_hcr_el2_eff(env); + bool enabled = !(hcr & HCR_TGE) && (hcr & HCR_AMO); + bool pending = enabled && (hcr & HCR_VSE); + bool masked = (env->daif & PSTATE_A); + + /* If VSE pending and masked, defer the exception. */ + if (pending && masked) { + uint32_t syndrome; + + if (arm_el_is_aa64(env, 1)) { + /* Copy across IDS and ISS from VSESR. */ + syndrome = env->cp15.vsesr_el2 & 0x1ffffff; + } else { + ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal }; + + if (extended_addresses_enabled(env)) { + syndrome = arm_fi_to_lfsc(&fi); + } else { + syndrome = arm_fi_to_sfsc(&fi); + } + /* Copy across AET and ExT from VSESR. */ + syndrome |= env->cp15.vsesr_el2 & 0xd000; + } + + /* Set VDISR_EL2.A along with the syndrome. */ + env->cp15.vdisr_el2 = syndrome | (1u << 31); + + /* Clear pending virtual SError */ + env->cp15.hcr_el2 &= ~HCR_VSE; + cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_VSERR); + } +} diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c index 739aa520dddd..d0483bf051ec 100644 --- a/target/arm/pauth_helper.c +++ b/target/arm/pauth_helper.c @@ -382,8 +382,8 @@ static uint64_t pauth_strip(CPUARMState *env, uint64_t ptr, bool data) return pauth_original_ptr(ptr, param); } -static void QEMU_NORETURN pauth_trap(CPUARMState *env, int target_el, - uintptr_t ra) +static G_NORETURN +void pauth_trap(CPUARMState *env, int target_el, uintptr_t ra) { raise_exception_ra(env, EXCP_UDEF, syn_pactrap(), target_el, ra); } diff --git a/target/arm/ptw.c b/target/arm/ptw.c new file mode 100644 index 000000000000..4bda0590c7ca --- /dev/null +++ b/target/arm/ptw.c @@ -0,0 +1,2993 @@ +/* + * ARM page table walking. + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/range.h" +#include "qemu/main-loop.h" +#include "exec/exec-all.h" +#include "cpu.h" +#include "internals.h" +#include "idau.h" + + +typedef struct S1Translate { + ARMMMUIdx in_mmu_idx; + ARMMMUIdx in_ptw_idx; + bool in_secure; + bool in_debug; + bool out_secure; + bool out_rw; + bool out_be; + hwaddr out_virt; + hwaddr out_phys; + void *out_host; +} S1Translate; + +static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, + uint64_t address, + MMUAccessType access_type, bool s1_is_el0, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) + __attribute__((nonnull)); + +static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) + __attribute__((nonnull)); + +/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ +static const uint8_t pamax_map[] = { + [0] = 32, + [1] = 36, + [2] = 40, + [3] = 42, + [4] = 44, + [5] = 48, + [6] = 52, +}; + +/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */ +unsigned int arm_pamax(ARMCPU *cpu) +{ + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + unsigned int parange = + FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); + + /* + * id_aa64mmfr0 is a read-only register so values outside of the + * supported mappings can be considered an implementation error. + */ + assert(parange < ARRAY_SIZE(pamax_map)); + return pamax_map[parange]; + } + + /* + * In machvirt_init, we call arm_pamax on a cpu that is not fully + * initialized, so we can't rely on the propagation done in realize. + */ + if (arm_feature(&cpu->env, ARM_FEATURE_LPAE) || + arm_feature(&cpu->env, ARM_FEATURE_V7VE)) { + /* v7 with LPAE */ + return 40; + } + /* Anything else */ + return 32; +} + +/* + * Convert a possible stage1+2 MMU index into the appropriate stage 1 MMU index + */ +ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) +{ + switch (mmu_idx) { + case ARMMMUIdx_E10_0: + return ARMMMUIdx_Stage1_E0; + case ARMMMUIdx_E10_1: + return ARMMMUIdx_Stage1_E1; + case ARMMMUIdx_E10_1_PAN: + return ARMMMUIdx_Stage1_E1_PAN; + default: + return mmu_idx; + } +} + +ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) +{ + return stage_1_mmu_idx(arm_mmu_idx(env)); +} + +static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; +} + +/* Return the TTBR associated with this translation regime */ +static uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) +{ + if (mmu_idx == ARMMMUIdx_Stage2) { + return env->cp15.vttbr_el2; + } + if (mmu_idx == ARMMMUIdx_Stage2_S) { + return env->cp15.vsttbr_el2; + } + if (ttbrn == 0) { + return env->cp15.ttbr0_el[regime_el(env, mmu_idx)]; + } else { + return env->cp15.ttbr1_el[regime_el(env, mmu_idx)]; + } +} + +/* Return true if the specified stage of address translation is disabled */ +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[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 */ + return mmu_idx & ARM_MMU_IDX_M_NEGPRI; + case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: + /* Enabled for all cases */ + return false; + case 0: + default: + /* + * HFNMIENA set and ENABLE clear is UNPREDICTABLE, but + * we warned about that in armv7m_nvic.c when the guest set it. + */ + return true; + } + } + + hcr_el2 = arm_hcr_el2_eff_secstate(env, is_secure); + + 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; + + 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; + + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_E1: + case ARMMMUIdx_Stage1_E1_PAN: + /* HCR.DC means SCTLR_EL1.M behaves as 0 */ + 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; + + case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_S: + /* No translation for physical address spaces. */ + return true; + + default: + g_assert_not_reached(); + } + + return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; +} + +static bool S2_attrs_are_device(uint64_t hcr, uint8_t attrs) +{ + /* + * For an S1 page table walk, the stage 1 attributes are always + * some form of "this is Normal memory". The combined S1+S2 + * attributes are therefore only Device if stage 2 specifies Device. + * With HCR_EL2.FWB == 0 this is when descriptor bits [5:4] are 0b00, + * ie when cacheattrs.attrs bits [3:2] are 0b00. + * With HCR_EL2.FWB == 1 this is when descriptor bit [4] is 0, ie + * when cacheattrs.attrs bit [2] is 0. + */ + if (hcr & HCR_FWB) { + return (attrs & 0x4) == 0; + } else { + return (attrs & 0xc) == 0; + } +} + +/* Translate a S1 pagetable walk through S2 if needed. */ +static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, + hwaddr addr, ARMMMUFaultInfo *fi) +{ + bool is_secure = ptw->in_secure; + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; + ARMMMUIdx s2_mmu_idx = ptw->in_ptw_idx; + uint8_t pte_attrs; + bool pte_secure; + + ptw->out_virt = addr; + + if (unlikely(ptw->in_debug)) { + /* + * From gdbstub, do not use softmmu so that we don't modify the + * state of the cpu at all, including softmmu tlb contents. + */ + if (regime_is_stage2(s2_mmu_idx)) { + S1Translate s2ptw = { + .in_mmu_idx = s2_mmu_idx, + .in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS, + .in_secure = is_secure, + .in_debug = true, + }; + GetPhysAddrResult s2 = { }; + + if (!get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, + false, &s2, fi)) { + goto fail; + } + ptw->out_phys = s2.f.phys_addr; + pte_attrs = s2.cacheattrs.attrs; + pte_secure = s2.f.attrs.secure; + } else { + /* Regime is physical. */ + ptw->out_phys = addr; + pte_attrs = 0; + pte_secure = is_secure; + } + ptw->out_host = NULL; + ptw->out_rw = false; + } else { + CPUTLBEntryFull *full; + int flags; + + env->tlb_fi = fi; + flags = probe_access_full(env, addr, MMU_DATA_LOAD, + arm_to_core_mmu_idx(s2_mmu_idx), + true, &ptw->out_host, &full, 0); + env->tlb_fi = NULL; + + if (unlikely(flags & TLB_INVALID_MASK)) { + goto fail; + } + ptw->out_phys = full->phys_addr; + ptw->out_rw = full->prot & PAGE_WRITE; + pte_attrs = full->pte_attrs; + pte_secure = full->attrs.secure; + } + + if (regime_is_stage2(s2_mmu_idx)) { + uint64_t hcr = arm_hcr_el2_eff_secstate(env, is_secure); + + if ((hcr & HCR_PTW) && S2_attrs_are_device(hcr, pte_attrs)) { + /* + * PTW set and S1 walk touched S2 Device memory: + * generate Permission fault. + */ + fi->type = ARMFault_Permission; + fi->s2addr = addr; + fi->stage2 = true; + fi->s1ptw = true; + fi->s1ns = !is_secure; + return false; + } + } + + /* Check if page table walk is to secure or non-secure PA space. */ + ptw->out_secure = (is_secure + && !(pte_secure + ? env->cp15.vstcr_el2 & VSTCR_SW + : env->cp15.vtcr_el2 & VTCR_NSW)); + ptw->out_be = regime_translation_big_endian(env, mmu_idx); + return true; + + fail: + assert(fi->type != ARMFault_None); + fi->s2addr = addr; + fi->stage2 = true; + fi->s1ptw = true; + fi->s1ns = !is_secure; + return false; +} + +/* All loads done in the course of a page table walk go through here. */ +static uint32_t arm_ldl_ptw(CPUARMState *env, S1Translate *ptw, + ARMMMUFaultInfo *fi) +{ + CPUState *cs = env_cpu(env); + void *host = ptw->out_host; + uint32_t data; + + if (likely(host)) { + /* Page tables are in RAM, and we have the host address. */ + data = qatomic_read((uint32_t *)host); + if (ptw->out_be) { + data = be32_to_cpu(data); + } else { + data = le32_to_cpu(data); + } + } else { + /* Page tables are in MMIO. */ + MemTxAttrs attrs = { .secure = ptw->out_secure }; + AddressSpace *as = arm_addressspace(cs, attrs); + MemTxResult result = MEMTX_OK; + + if (ptw->out_be) { + data = address_space_ldl_be(as, ptw->out_phys, attrs, &result); + } else { + data = address_space_ldl_le(as, ptw->out_phys, attrs, &result); + } + if (unlikely(result != MEMTX_OK)) { + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; + } + } + return data; +} + +static uint64_t arm_ldq_ptw(CPUARMState *env, S1Translate *ptw, + ARMMMUFaultInfo *fi) +{ + CPUState *cs = env_cpu(env); + void *host = ptw->out_host; + uint64_t data; + + if (likely(host)) { + /* Page tables are in RAM, and we have the host address. */ +#ifdef CONFIG_ATOMIC64 + data = qatomic_read__nocheck((uint64_t *)host); + if (ptw->out_be) { + data = be64_to_cpu(data); + } else { + data = le64_to_cpu(data); + } +#else + if (ptw->out_be) { + data = ldq_be_p(host); + } else { + data = ldq_le_p(host); + } +#endif + } else { + /* Page tables are in MMIO. */ + MemTxAttrs attrs = { .secure = ptw->out_secure }; + AddressSpace *as = arm_addressspace(cs, attrs); + MemTxResult result = MEMTX_OK; + + if (ptw->out_be) { + data = address_space_ldq_be(as, ptw->out_phys, attrs, &result); + } else { + data = address_space_ldq_le(as, ptw->out_phys, attrs, &result); + } + if (unlikely(result != MEMTX_OK)) { + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; + } + } + return data; +} + +static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val, + uint64_t new_val, S1Translate *ptw, + ARMMMUFaultInfo *fi) +{ + uint64_t cur_val; + void *host = ptw->out_host; + + if (unlikely(!host)) { + fi->type = ARMFault_UnsuppAtomicUpdate; + fi->s1ptw = true; + return 0; + } + + /* + * Raising a stage2 Protection fault for an atomic update to a read-only + * page is delayed until it is certain that there is a change to make. + */ + if (unlikely(!ptw->out_rw)) { + int flags; + void *discard; + + env->tlb_fi = fi; + flags = probe_access_flags(env, ptw->out_virt, MMU_DATA_STORE, + arm_to_core_mmu_idx(ptw->in_ptw_idx), + true, &discard, 0); + env->tlb_fi = NULL; + + if (unlikely(flags & TLB_INVALID_MASK)) { + assert(fi->type != ARMFault_None); + fi->s2addr = ptw->out_virt; + fi->stage2 = true; + fi->s1ptw = true; + fi->s1ns = !ptw->in_secure; + return 0; + } + + /* In case CAS mismatches and we loop, remember writability. */ + ptw->out_rw = true; + } + +#ifdef CONFIG_ATOMIC64 + if (ptw->out_be) { + old_val = cpu_to_be64(old_val); + new_val = cpu_to_be64(new_val); + cur_val = qatomic_cmpxchg__nocheck((uint64_t *)host, old_val, new_val); + cur_val = be64_to_cpu(cur_val); + } else { + old_val = cpu_to_le64(old_val); + new_val = cpu_to_le64(new_val); + cur_val = qatomic_cmpxchg__nocheck((uint64_t *)host, old_val, new_val); + cur_val = le64_to_cpu(cur_val); + } +#else + /* + * We can't support the full 64-bit atomic cmpxchg on the host. + * Because this is only used for FEAT_HAFDBS, which is only for AA64, + * we know that TCG_OVERSIZED_GUEST is set, which means that we are + * running in round-robin mode and could only race with dma i/o. + */ +#ifndef TCG_OVERSIZED_GUEST +# error "Unexpected configuration" +#endif + bool locked = qemu_mutex_iothread_locked(); + if (!locked) { + qemu_mutex_lock_iothread(); + } + if (ptw->out_be) { + cur_val = ldq_be_p(host); + if (cur_val == old_val) { + stq_be_p(host, new_val); + } + } else { + cur_val = ldq_le_p(host); + if (cur_val == old_val) { + stq_le_p(host, new_val); + } + } + if (!locked) { + qemu_mutex_unlock_iothread(); + } +#endif + + return cur_val; +} + +static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, + uint32_t *table, uint32_t address) +{ + /* Note that we can only get here for an AArch32 PL0/PL1 lookup */ + uint64_t tcr = regime_tcr(env, mmu_idx); + int maskshift = extract32(tcr, 0, 3); + uint32_t mask = ~(((uint32_t)0xffffffffu) >> maskshift); + uint32_t base_mask; + + if (address & mask) { + if (tcr & TTBCR_PD1) { + /* Translation table walk disabled for TTBR1 */ + return false; + } + *table = regime_ttbr(env, mmu_idx, 1) & 0xffffc000; + } else { + if (tcr & TTBCR_PD0) { + /* Translation table walk disabled for TTBR0 */ + return false; + } + base_mask = ~((uint32_t)0x3fffu >> maskshift); + *table = regime_ttbr(env, mmu_idx, 0) & base_mask; + } + *table |= (address >> 18) & 0x3ffc; + return true; +} + +/* + * Translate section/page access permissions to page R/W protection flags + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * @ap: The 3-bit access permissions (AP[2:0]) + * @domain_prot: The 2-bit domain access permissions + * @is_user: TRUE if accessing from PL0 + */ +static int ap_to_rw_prot_is_user(CPUARMState *env, ARMMMUIdx mmu_idx, + int ap, int domain_prot, bool is_user) +{ + if (domain_prot == 3) { + return PAGE_READ | PAGE_WRITE; + } + + switch (ap) { + case 0: + if (arm_feature(env, ARM_FEATURE_V7)) { + return 0; + } + switch (regime_sctlr(env, mmu_idx) & (SCTLR_S | SCTLR_R)) { + case SCTLR_S: + return is_user ? 0 : PAGE_READ; + case SCTLR_R: + return PAGE_READ; + default: + return 0; + } + case 1: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 2: + if (is_user) { + return PAGE_READ; + } else { + return PAGE_READ | PAGE_WRITE; + } + case 3: + return PAGE_READ | PAGE_WRITE; + case 4: /* Reserved. */ + return 0; + case 5: + return is_user ? 0 : PAGE_READ; + case 6: + return PAGE_READ; + case 7: + if (!arm_feature(env, ARM_FEATURE_V6K)) { + return 0; + } + return PAGE_READ; + default: + g_assert_not_reached(); + } +} + +/* + * Translate section/page access permissions to page R/W protection flags + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * @ap: The 3-bit access permissions (AP[2:0]) + * @domain_prot: The 2-bit domain access permissions + */ +static int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, + int ap, int domain_prot) +{ + return ap_to_rw_prot_is_user(env, mmu_idx, ap, domain_prot, + regime_is_user(env, mmu_idx)); +} + +/* + * Translate section/page access permissions to page R/W protection flags. + * @ap: The 2-bit simple AP (AP[2:1]) + * @is_user: TRUE if accessing from PL0 + */ +static int simple_ap_to_rw_prot_is_user(int ap, bool is_user) +{ + switch (ap) { + case 0: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 1: + return PAGE_READ | PAGE_WRITE; + case 2: + return is_user ? 0 : PAGE_READ; + case 3: + return PAGE_READ; + default: + g_assert_not_reached(); + } +} + +static int simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) +{ + return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); +} + +static bool get_phys_addr_v5(CPUARMState *env, S1Translate *ptw, + uint32_t address, MMUAccessType access_type, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) +{ + int level = 1; + uint32_t table; + uint32_t desc; + int type; + int ap; + int domain = 0; + int domain_prot; + hwaddr phys_addr; + uint32_t dacr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + if (!get_level1_table_address(env, ptw->in_mmu_idx, &table, address)) { + /* Section translation fault if page walk is disabled by PD0 or PD1 */ + fi->type = ARMFault_Translation; + goto do_fault; + } + if (!S1_ptw_translate(env, ptw, table, fi)) { + goto do_fault; + } + desc = arm_ldl_ptw(env, ptw, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + type = (desc & 3); + domain = (desc >> 5) & 0x0f; + if (regime_el(env, ptw->in_mmu_idx) == 1) { + dacr = env->cp15.dacr_ns; + } else { + dacr = env->cp15.dacr_s; + } + domain_prot = (dacr >> (domain * 2)) & 3; + if (type == 0) { + /* Section translation fault. */ + fi->type = ARMFault_Translation; + goto do_fault; + } + if (type != 2) { + level = 2; + } + if (domain_prot == 0 || domain_prot == 2) { + fi->type = ARMFault_Domain; + goto do_fault; + } + if (type == 2) { + /* 1Mb section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + ap = (desc >> 10) & 3; + result->f.lg_page_size = 20; /* 1MB */ + } else { + /* Lookup l2 entry. */ + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } + if (!S1_ptw_translate(env, ptw, table, fi)) { + goto do_fault; + } + desc = arm_ldl_ptw(env, ptw, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + switch (desc & 3) { + case 0: /* Page translation fault. */ + fi->type = ARMFault_Translation; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + result->f.lg_page_size = 16; + break; + case 2: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + ap = (desc >> (4 + ((address >> 9) & 6))) & 3; + result->f.lg_page_size = 12; + break; + case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */ + if (type == 1) { + /* ARMv6/XScale extended small page format */ + if (arm_feature(env, ARM_FEATURE_XSCALE) + || arm_feature(env, ARM_FEATURE_V6)) { + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + result->f.lg_page_size = 12; + } else { + /* + * UNPREDICTABLE in ARMv5; we choose to take a + * page translation fault. + */ + fi->type = ARMFault_Translation; + goto do_fault; + } + } else { + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + result->f.lg_page_size = 10; + } + ap = (desc >> 4) & 3; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + g_assert_not_reached(); + } + } + result->f.prot = ap_to_rw_prot(env, ptw->in_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; + } + result->f.phys_addr = phys_addr; + return false; +do_fault: + fi->domain = domain; + fi->level = level; + return true; +} + +static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw, + uint32_t address, MMUAccessType access_type, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) +{ + ARMCPU *cpu = env_archcpu(env); + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; + int level = 1; + uint32_t table; + uint32_t desc; + uint32_t xn; + uint32_t pxn = 0; + int type; + int ap; + int domain = 0; + int domain_prot; + hwaddr phys_addr; + uint32_t dacr; + bool ns; + int user_prot; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + if (!get_level1_table_address(env, mmu_idx, &table, address)) { + /* Section translation fault if page walk is disabled by PD0 or PD1 */ + fi->type = ARMFault_Translation; + goto do_fault; + } + if (!S1_ptw_translate(env, ptw, table, fi)) { + goto do_fault; + } + desc = arm_ldl_ptw(env, ptw, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + type = (desc & 3); + if (type == 0 || (type == 3 && !cpu_isar_feature(aa32_pxn, cpu))) { + /* Section translation fault, or attempt to use the encoding + * which is Reserved on implementations without PXN. + */ + fi->type = ARMFault_Translation; + goto do_fault; + } + if ((type == 1) || !(desc & (1 << 18))) { + /* Page or Section. */ + domain = (desc >> 5) & 0x0f; + } + if (regime_el(env, mmu_idx) == 1) { + dacr = env->cp15.dacr_ns; + } else { + dacr = env->cp15.dacr_s; + } + if (type == 1) { + level = 2; + } + domain_prot = (dacr >> (domain * 2)) & 3; + if (domain_prot == 0 || domain_prot == 2) { + /* Section or Page domain fault */ + fi->type = ARMFault_Domain; + goto do_fault; + } + if (type != 1) { + if (desc & (1 << 18)) { + /* Supersection. */ + phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); + phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32; + phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36; + result->f.lg_page_size = 24; /* 16MB */ + } else { + /* Section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + result->f.lg_page_size = 20; /* 1MB */ + } + ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); + xn = desc & (1 << 4); + pxn = desc & 1; + ns = extract32(desc, 19, 1); + } else { + if (cpu_isar_feature(aa32_pxn, cpu)) { + pxn = (desc >> 2) & 1; + } + ns = extract32(desc, 3, 1); + /* Lookup l2 entry. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + if (!S1_ptw_translate(env, ptw, table, fi)) { + goto do_fault; + } + desc = arm_ldl_ptw(env, ptw, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); + switch (desc & 3) { + case 0: /* Page translation fault. */ + fi->type = ARMFault_Translation; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + xn = desc & (1 << 15); + result->f.lg_page_size = 16; + break; + case 2: case 3: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + xn = desc & 1; + result->f.lg_page_size = 12; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + g_assert_not_reached(); + } + } + if (domain_prot == 3) { + result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + } else { + if (pxn && !regime_is_user(env, mmu_idx)) { + xn = 1; + } + if (xn && access_type == MMU_INST_FETCH) { + fi->type = ARMFault_Permission; + goto do_fault; + } + + if (arm_feature(env, ARM_FEATURE_V6K) && + (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { + /* The simplified model uses AP[0] as an access control bit. */ + if ((ap & 1) == 0) { + /* Access flag fault. */ + fi->type = ARMFault_AccessFlag; + goto do_fault; + } + result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); + user_prot = simple_ap_to_rw_prot_is_user(ap >> 1, 1); + } else { + result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + user_prot = ap_to_rw_prot_is_user(env, mmu_idx, ap, domain_prot, 1); + } + if (result->f.prot && !xn) { + result->f.prot |= PAGE_EXEC; + } + if (!(result->f.prot & (1 << access_type))) { + /* Access permission fault. */ + fi->type = ARMFault_Permission; + goto do_fault; + } + if (regime_is_pan(env, mmu_idx) && + !regime_is_user(env, mmu_idx) && + user_prot && + access_type != MMU_INST_FETCH) { + /* Privileged Access Never fault */ + fi->type = ARMFault_Permission; + goto do_fault; + } + } + if (ns) { + /* The NS bit will (as required by the architecture) have no effect if + * the CPU doesn't support TZ or this is a non-secure translation + * regime, because the attribute will already be non-secure. + */ + result->f.attrs.secure = false; + } + result->f.phys_addr = phys_addr; + return false; +do_fault: + fi->domain = domain; + fi->level = level; + return true; +} + +/* + * Translate S2 section/page access permissions to protection flags + * @env: CPUARMState + * @s2ap: The 2-bit stage2 access permissions (S2AP) + * @xn: XN (execute-never) bits + * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 + */ +static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) +{ + int prot = 0; + + if (s2ap & 1) { + prot |= PAGE_READ; + } + if (s2ap & 2) { + prot |= PAGE_WRITE; + } + + if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) { + switch (xn) { + case 0: + prot |= PAGE_EXEC; + break; + case 1: + if (s1_is_el0) { + prot |= PAGE_EXEC; + } + break; + case 2: + break; + case 3: + if (!s1_is_el0) { + prot |= PAGE_EXEC; + } + break; + default: + g_assert_not_reached(); + } + } else { + if (!extract32(xn, 1, 1)) { + if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) { + prot |= PAGE_EXEC; + } + } + } + return prot; +} + +/* + * Translate section/page access permissions to protection flags + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * @is_aa64: TRUE if AArch64 + * @ap: The 2-bit simple AP (AP[2:1]) + * @ns: NS (non-secure) bit + * @xn: XN (execute-never) bit + * @pxn: PXN (privileged execute-never) bit + */ +static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, + int ap, int ns, int xn, int pxn) +{ + bool is_user = regime_is_user(env, mmu_idx); + int prot_rw, user_rw; + bool have_wxn; + int wxn = 0; + + assert(!regime_is_stage2(mmu_idx)); + + user_rw = simple_ap_to_rw_prot_is_user(ap, true); + if (is_user) { + prot_rw = user_rw; + } else { + if (user_rw && regime_is_pan(env, mmu_idx)) { + /* PAN forbids data accesses but doesn't affect insn fetch */ + prot_rw = 0; + } else { + prot_rw = simple_ap_to_rw_prot_is_user(ap, false); + } + } + + if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { + return prot_rw; + } + + /* TODO have_wxn should be replaced with + * ARM_FEATURE_V8 || (ARM_FEATURE_V7 && ARM_FEATURE_EL2) + * when ARM_FEATURE_EL2 starts getting set. For now we assume all LPAE + * compatible processors have EL2, which is required for [U]WXN. + */ + have_wxn = arm_feature(env, ARM_FEATURE_LPAE); + + if (have_wxn) { + wxn = regime_sctlr(env, mmu_idx) & SCTLR_WXN; + } + + if (is_aa64) { + if (regime_has_2_ranges(mmu_idx) && !is_user) { + xn = pxn || (user_rw & PAGE_WRITE); + } + } else if (arm_feature(env, ARM_FEATURE_V7)) { + switch (regime_el(env, mmu_idx)) { + case 1: + case 3: + if (is_user) { + xn = xn || !(user_rw & PAGE_READ); + } else { + int uwxn = 0; + if (have_wxn) { + uwxn = regime_sctlr(env, mmu_idx) & SCTLR_UWXN; + } + xn = xn || !(prot_rw & PAGE_READ) || pxn || + (uwxn && (user_rw & PAGE_WRITE)); + } + break; + case 2: + break; + } + } else { + xn = wxn = 0; + } + + if (xn || (wxn && (prot_rw & PAGE_WRITE))) { + return prot_rw; + } + return prot_rw | PAGE_EXEC; +} + +static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, + ARMMMUIdx mmu_idx) +{ + uint64_t tcr = regime_tcr(env, mmu_idx); + uint32_t el = regime_el(env, mmu_idx); + int select, tsz; + bool epd, hpd; + + assert(mmu_idx != ARMMMUIdx_Stage2_S); + + if (mmu_idx == ARMMMUIdx_Stage2) { + /* VTCR */ + bool sext = extract32(tcr, 4, 1); + bool sign = extract32(tcr, 3, 1); + + /* + * If the sign-extend bit is not the same as t0sz[3], the result + * is unpredictable. Flag this as a guest error. + */ + if (sign != sext) { + qemu_log_mask(LOG_GUEST_ERROR, + "AArch32: VTCR.S / VTCR.T0SZ[3] mismatch\n"); + } + tsz = sextract32(tcr, 0, 4) + 8; + select = 0; + hpd = false; + epd = false; + } else if (el == 2) { + /* HTCR */ + tsz = extract32(tcr, 0, 3); + select = 0; + hpd = extract64(tcr, 24, 1); + epd = false; + } else { + int t0sz = extract32(tcr, 0, 3); + int t1sz = extract32(tcr, 16, 3); + + if (t1sz == 0) { + select = va > (0xffffffffu >> t0sz); + } else { + /* Note that we will detect errors later. */ + select = va >= ~(0xffffffffu >> t1sz); + } + if (!select) { + tsz = t0sz; + epd = extract32(tcr, 7, 1); + hpd = extract64(tcr, 41, 1); + } else { + tsz = t1sz; + epd = extract32(tcr, 23, 1); + hpd = extract64(tcr, 42, 1); + } + /* For aarch32, hpd0 is not enabled without t2e as well. */ + hpd &= extract32(tcr, 6, 1); + } + + return (ARMVAParameters) { + .tsz = tsz, + .select = select, + .epd = epd, + .hpd = hpd, + }; +} + +/* + * check_s2_mmu_setup + * @cpu: ARMCPU + * @is_aa64: True if the translation regime is in AArch64 state + * @startlevel: Suggested starting level + * @inputsize: Bitsize of IPAs + * @stride: Page-table stride (See the ARM ARM) + * + * Returns true if the suggested S2 translation parameters are OK and + * false otherwise. + */ +static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, + int inputsize, int stride, int outputsize) +{ + const int grainsize = stride + 3; + int startsizecheck; + + /* + * Negative levels are usually not allowed... + * Except for FEAT_LPA2, 4k page table, 52-bit address space, which + * begins with level -1. Note that previous feature tests will have + * eliminated this combination if it is not enabled. + */ + if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) { + return false; + } + + startsizecheck = inputsize - ((3 - level) * stride + grainsize); + if (startsizecheck < 1 || startsizecheck > stride + 4) { + return false; + } + + if (is_aa64) { + switch (stride) { + case 13: /* 64KB Pages. */ + if (level == 0 || (level == 1 && outputsize <= 42)) { + return false; + } + break; + case 11: /* 16KB Pages. */ + if (level == 0 || (level == 1 && outputsize <= 40)) { + return false; + } + break; + case 9: /* 4KB Pages. */ + if (level == 0 && outputsize <= 42) { + return false; + } + break; + default: + g_assert_not_reached(); + } + + /* Inputsize checks. */ + if (inputsize > outputsize && + (arm_el_is_aa64(&cpu->env, 1) || inputsize > 40)) { + /* This is CONSTRAINED UNPREDICTABLE and we choose to fault. */ + return false; + } + } else { + /* AArch32 only supports 4KB pages. Assert on that. */ + assert(stride == 9); + + if (level == 0) { + return false; + } + } + return true; +} + +/** + * get_phys_addr_lpae: perform one stage of page table walk, LPAE format + * + * 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 long-format DFSR/IFSR fault register, with the following caveat: + * the WnR bit is never set (the caller must do this). + * + * @env: CPUARMState + * @ptw: Current and next stage parameters for the walk. + * @address: virtual address to get physical address for + * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH + * @s1_is_el0: if @ptw->in_mmu_idx is ARMMMUIdx_Stage2 + * (so this is a stage 2 page 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. + * @result: set on translation success, + * @fi: set to fault info if the translation fails + */ +static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, + uint64_t address, + MMUAccessType access_type, bool s1_is_el0, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) +{ + ARMCPU *cpu = env_archcpu(env); + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; + bool is_secure = ptw->in_secure; + int32_t level; + ARMVAParameters param; + uint64_t ttbr; + hwaddr descaddr, indexmask, indexmask_grainsize; + uint32_t tableattrs; + target_ulong page_size; + uint64_t attrs; + int32_t stride; + int addrsize, inputsize, outputsize; + uint64_t tcr = regime_tcr(env, mmu_idx); + int ap, ns, xn, pxn; + uint32_t el = regime_el(env, mmu_idx); + uint64_t descaddrmask; + bool aarch64 = arm_el_is_aa64(env, el); + uint64_t descriptor, new_descriptor; + bool nstable; + + /* TODO: This code does not support shareability levels. */ + if (aarch64) { + int ps; + + param = aa64_va_parameters(env, address, mmu_idx, + access_type != MMU_INST_FETCH); + level = 0; + + /* + * If TxSZ is programmed to a value larger than the maximum, + * or smaller than the effective minimum, it is IMPLEMENTATION + * DEFINED whether we behave as if the field were programmed + * within bounds, or if a level 0 Translation fault is generated. + * + * With FEAT_LVA, fault on less than minimum becomes required, + * so our choice is to always raise the fault. + */ + if (param.tsz_oob) { + goto do_translation_fault; + } + + addrsize = 64 - 8 * param.tbi; + inputsize = 64 - param.tsz; + + /* + * Bound PS by PARANGE to find the effective output address size. + * ID_AA64MMFR0 is a read-only register so values outside of the + * supported mappings can be considered an implementation error. + */ + ps = FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); + ps = MIN(ps, param.ps); + assert(ps < ARRAY_SIZE(pamax_map)); + outputsize = pamax_map[ps]; + + /* + * With LPA2, the effective output address (OA) size is at most 48 bits + * unless TCR.DS == 1 + */ + if (!param.ds && param.gran != Gran64K) { + outputsize = MIN(outputsize, 48); + } + } else { + param = aa32_va_parameters(env, address, mmu_idx); + level = 1; + addrsize = (mmu_idx == ARMMMUIdx_Stage2 ? 40 : 32); + inputsize = addrsize - param.tsz; + outputsize = 40; + } + + /* + * We determined the region when collecting the parameters, but we + * have not yet validated that the address is valid for the region. + * Extract the top bits and verify that they all match select. + * + * For aa32, if inputsize == addrsize, then we have selected the + * region by exclusion in aa32_va_parameters and there is no more + * validation to do here. + */ + if (inputsize < addrsize) { + target_ulong top_bits = sextract64(address, inputsize, + addrsize - inputsize); + if (-top_bits != param.select) { + /* The gap between the two regions is a Translation fault */ + goto do_translation_fault; + } + } + + stride = arm_granule_bits(param.gran) - 3; + + /* + * Note that QEMU ignores shareability and cacheability attributes, + * so we don't need to do anything with the SH, ORGN, IRGN fields + * in the TTBCR. Similarly, TTBCR:A1 selects whether we get the + * ASID from TTBR0 or TTBR1, but QEMU's TLB doesn't currently + * implement any ASID-like capability so we can ignore it (instead + * we will always flush the TLB any time the ASID is changed). + */ + ttbr = regime_ttbr(env, mmu_idx, param.select); + + /* + * Here we should have set up all the parameters for the translation: + * inputsize, ttbr, epd, stride, tbi + */ + + if (param.epd) { + /* + * Translation table walk disabled => Translation fault on TLB miss + * Note: This is always 0 on 64-bit EL2 and EL3. + */ + goto do_translation_fault; + } + + if (!regime_is_stage2(mmu_idx)) { + /* + * The starting level depends on the virtual address size (which can + * be up to 48 bits) and the translation granule size. It indicates + * the number of strides (stride bits at a time) needed to + * consume the bits of the input address. In the pseudocode this is: + * level = 4 - RoundUp((inputsize - grainsize) / stride) + * where their 'inputsize' is our 'inputsize', 'grainsize' is + * our 'stride + 3' and 'stride' is our 'stride'. + * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: + * = 4 - (inputsize - stride - 3 + stride - 1) / stride + * = 4 - (inputsize - 4) / stride; + */ + level = 4 - (inputsize - 4) / stride; + } else { + /* + * For stage 2 translations the starting level is specified by the + * VTCR_EL2.SL0 field (whose interpretation depends on the page size) + */ + uint32_t sl0 = extract32(tcr, 6, 2); + uint32_t sl2 = extract64(tcr, 33, 1); + int32_t startlevel; + bool ok; + + /* SL2 is RES0 unless DS=1 & 4kb granule. */ + if (param.ds && stride == 9 && sl2) { + if (sl0 != 0) { + level = 0; + goto do_translation_fault; + } + startlevel = -1; + } else if (!aarch64 || stride == 9) { + /* AArch32 or 4KB pages */ + startlevel = 2 - sl0; + + if (cpu_isar_feature(aa64_st, cpu)) { + startlevel &= 3; + } + } else { + /* 16KB or 64KB pages */ + startlevel = 3 - sl0; + } + + /* Check that the starting level is valid. */ + ok = check_s2_mmu_setup(cpu, aarch64, startlevel, + inputsize, stride, outputsize); + if (!ok) { + goto do_translation_fault; + } + level = startlevel; + } + + indexmask_grainsize = MAKE_64BIT_MASK(0, stride + 3); + indexmask = MAKE_64BIT_MASK(0, inputsize - (stride * (4 - level))); + + /* Now we can extract the actual base address from the TTBR */ + descaddr = extract64(ttbr, 0, 48); + + /* + * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [5:2] of TTBR. + * + * Otherwise, if the base address is out of range, raise AddressSizeFault. + * In the pseudocode, this is !IsZero(baseregister<47:outputsize>), + * but we've just cleared the bits above 47, so simplify the test. + */ + if (outputsize > 48) { + descaddr |= extract64(ttbr, 2, 4) << 48; + } else if (descaddr >> outputsize) { + level = 0; + fi->type = ARMFault_AddressSize; + goto do_fault; + } + + /* + * We rely on this masking to clear the RES0 bits at the bottom of the TTBR + * and also to mask out CnP (bit 0) which could validly be non-zero. + */ + descaddr &= ~indexmask; + + /* + * For AArch32, the address field in the descriptor goes up to bit 39 + * for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0 + * or an AddressSize fault is raised. So for v8 we extract those SBZ + * bits as part of the address, which will be checked via outputsize. + * For AArch64, the address field goes up to bit 47, or 49 with FEAT_LPA2; + * the highest bits of a 52-bit output are placed elsewhere. + */ + if (param.ds) { + descaddrmask = MAKE_64BIT_MASK(0, 50); + } else if (arm_feature(env, ARM_FEATURE_V8)) { + descaddrmask = MAKE_64BIT_MASK(0, 48); + } else { + descaddrmask = MAKE_64BIT_MASK(0, 40); + } + descaddrmask &= ~indexmask_grainsize; + + /* + * Secure accesses start with the page table in secure memory and + * can be downgraded to non-secure at any step. Non-secure accesses + * remain non-secure. We implement this by just ORing in the NSTable/NS + * bits at each step. + */ + tableattrs = is_secure ? 0 : (1 << 4); + + next_level: + descaddr |= (address >> (stride * (4 - level))) & indexmask; + descaddr &= ~7ULL; + nstable = extract32(tableattrs, 4, 1); + if (nstable) { + /* + * Stage2_S -> Stage2 or Phys_S -> Phys_NS + * Assert that the non-secure idx are even, and relative order. + */ + QEMU_BUILD_BUG_ON((ARMMMUIdx_Phys_NS & 1) != 0); + QEMU_BUILD_BUG_ON((ARMMMUIdx_Stage2 & 1) != 0); + QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_NS + 1 != ARMMMUIdx_Phys_S); + QEMU_BUILD_BUG_ON(ARMMMUIdx_Stage2 + 1 != ARMMMUIdx_Stage2_S); + ptw->in_ptw_idx &= ~1; + ptw->in_secure = false; + } + if (!S1_ptw_translate(env, ptw, descaddr, fi)) { + goto do_fault; + } + descriptor = arm_ldq_ptw(env, ptw, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + new_descriptor = descriptor; + + restart_atomic_update: + if (!(descriptor & 1) || (!(descriptor & 2) && (level == 3))) { + /* Invalid, or the Reserved level 3 encoding */ + goto do_translation_fault; + } + + descaddr = descriptor & descaddrmask; + + /* + * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12] + * of descriptor. For FEAT_LPA2 and effective DS, bits [51:50] of + * descaddr are in [9:8]. Otherwise, if descaddr is out of range, + * raise AddressSizeFault. + */ + if (outputsize > 48) { + if (param.ds) { + descaddr |= extract64(descriptor, 8, 2) << 50; + } else { + descaddr |= extract64(descriptor, 12, 4) << 48; + } + } else if (descaddr >> outputsize) { + fi->type = ARMFault_AddressSize; + goto do_fault; + } + + if ((descriptor & 2) && (level < 3)) { + /* + * Table entry. The top five bits are attributes which may + * propagate down through lower levels of the table (and + * which are all arranged so that 0 means "no effect", so + * we can gather them up by ORing in the bits at each level). + */ + tableattrs |= extract64(descriptor, 59, 5); + level++; + indexmask = indexmask_grainsize; + goto next_level; + } + + /* + * Block entry at level 1 or 2, or page entry at level 3. + * These are basically the same thing, although the number + * of bits we pull in from the vaddr varies. Note that although + * descaddrmask masks enough of the low bits of the descriptor + * to give a correct page or table address, the address field + * in a block descriptor is smaller; so we need to explicitly + * clear the lower bits here before ORing in the low vaddr bits. + * + * Afterward, descaddr is the final physical address. + */ + page_size = (1ULL << ((stride * (4 - level)) + 3)); + descaddr &= ~(hwaddr)(page_size - 1); + descaddr |= (address & (page_size - 1)); + + if (likely(!ptw->in_debug)) { + /* + * Access flag. + * If HA is enabled, prepare to update the descriptor below. + * Otherwise, pass the access fault on to software. + */ + if (!(descriptor & (1 << 10))) { + if (param.ha) { + new_descriptor |= 1 << 10; /* AF */ + } else { + fi->type = ARMFault_AccessFlag; + goto do_fault; + } + } + + /* + * Dirty Bit. + * If HD is enabled, pre-emptively set/clear the appropriate AP/S2AP + * bit for writeback. The actual write protection test may still be + * overridden by tableattrs, to be merged below. + */ + if (param.hd + && extract64(descriptor, 51, 1) /* DBM */ + && access_type == MMU_DATA_STORE) { + if (regime_is_stage2(mmu_idx)) { + new_descriptor |= 1ull << 7; /* set S2AP[1] */ + } else { + new_descriptor &= ~(1ull << 7); /* clear AP[2] */ + } + } + } + + /* + * Extract attributes from the (modified) descriptor, and apply + * table descriptors. Stage 2 table descriptors do not include + * any attribute fields. HPD disables all the table attributes + * except NSTable. + */ + attrs = new_descriptor & (MAKE_64BIT_MASK(2, 10) | MAKE_64BIT_MASK(50, 14)); + if (!regime_is_stage2(mmu_idx)) { + attrs |= nstable << 5; /* NS */ + if (!param.hpd) { + attrs |= extract64(tableattrs, 0, 2) << 53; /* XN, PXN */ + /* + * The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1 + * means "force PL1 access only", which means forcing AP[1] to 0. + */ + attrs &= ~(extract64(tableattrs, 2, 1) << 6); /* !APT[0] => AP[1] */ + attrs |= extract32(tableattrs, 3, 1) << 7; /* APT[1] => AP[2] */ + } + } + + ap = extract32(attrs, 6, 2); + if (regime_is_stage2(mmu_idx)) { + ns = mmu_idx == ARMMMUIdx_Stage2; + xn = extract64(attrs, 53, 2); + result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); + } else { + ns = extract32(attrs, 5, 1); + xn = extract64(attrs, 54, 1); + pxn = extract64(attrs, 53, 1); + result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); + } + + if (!(result->f.prot & (1 << access_type))) { + fi->type = ARMFault_Permission; + goto do_fault; + } + + /* If FEAT_HAFDBS has made changes, update the PTE. */ + if (new_descriptor != descriptor) { + new_descriptor = arm_casq_ptw(env, descriptor, new_descriptor, ptw, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + /* + * I_YZSVV says that if the in-memory descriptor has changed, + * then we must use the information in that new value + * (which might include a different output address, different + * attributes, or generate a fault). + * Restart the handling of the descriptor value from scratch. + */ + if (new_descriptor != descriptor) { + descriptor = new_descriptor; + goto restart_atomic_update; + } + } + + if (ns) { + /* + * The NS bit will (as required by the architecture) have no effect if + * the CPU doesn't support TZ or this is a non-secure translation + * regime, because the attribute will already be non-secure. + */ + result->f.attrs.secure = false; + } + + /* When in aarch64 mode, and BTI is enabled, remember GP in the TLB. */ + if (aarch64 && cpu_isar_feature(aa64_bti, cpu)) { + result->f.guarded = extract64(attrs, 50, 1); /* GP */ + } + + if (regime_is_stage2(mmu_idx)) { + result->cacheattrs.is_s2_format = true; + result->cacheattrs.attrs = extract32(attrs, 2, 4); + } else { + /* Index into MAIR registers for cache attributes */ + uint8_t attrindx = extract32(attrs, 2, 3); + uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; + assert(attrindx <= 7); + result->cacheattrs.is_s2_format = false; + result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8); + } + + /* + * For FEAT_LPA2 and effective DS, the SH field in the attributes + * was re-purposed for output address bits. The SH attribute in + * that case comes from TCR_ELx, which we extracted earlier. + */ + if (param.ds) { + result->cacheattrs.shareability = param.sh; + } else { + result->cacheattrs.shareability = extract32(attrs, 8, 2); + } + + result->f.phys_addr = descaddr; + result->f.lg_page_size = ctz64(page_size); + return false; + + do_translation_fault: + fi->type = ARMFault_Translation; + do_fault: + fi->level = level; + /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ + fi->stage2 = fi->s1ptw || regime_is_stage2(mmu_idx); + fi->s1ns = mmu_idx == ARMMMUIdx_Stage2; + return true; +} + +static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + int n; + uint32_t mask; + uint32_t base; + bool is_user = regime_is_user(env, mmu_idx); + + if (regime_translation_disabled(env, mmu_idx, is_secure)) { + /* MPU disabled. */ + result->f.phys_addr = address; + result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return false; + } + + result->f.phys_addr = address; + for (n = 7; n >= 0; n--) { + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) { + continue; + } + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) { + break; + } + } + if (n < 0) { + fi->type = ARMFault_Background; + return true; + } + + if (access_type == MMU_INST_FETCH) { + mask = env->cp15.pmsav5_insn_ap; + } else { + mask = env->cp15.pmsav5_data_ap; + } + mask = (mask >> (n * 4)) & 0xf; + switch (mask) { + case 0: + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + case 1: + if (is_user) { + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + result->f.prot = PAGE_READ | PAGE_WRITE; + break; + case 2: + result->f.prot = PAGE_READ; + if (!is_user) { + result->f.prot |= PAGE_WRITE; + } + break; + case 3: + result->f.prot = PAGE_READ | PAGE_WRITE; + break; + case 5: + if (is_user) { + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + result->f.prot = PAGE_READ; + break; + case 6: + result->f.prot = PAGE_READ; + break; + default: + /* Bad permission. */ + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + result->f.prot |= PAGE_EXEC; + return false; +} + +static void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, + int32_t address, uint8_t *prot) +{ + if (!arm_feature(env, ARM_FEATURE_M)) { + *prot = PAGE_READ | PAGE_WRITE; + switch (address) { + case 0xF0000000 ... 0xFFFFFFFF: + if (regime_sctlr(env, mmu_idx) & SCTLR_V) { + /* hivecs execing is ok */ + *prot |= PAGE_EXEC; + } + break; + case 0x00000000 ... 0x7FFFFFFF: + *prot |= PAGE_EXEC; + break; + } + } else { + /* Default system address map for M profile cores. + * The architecture specifies which regions are execute-never; + * at the MPU level no other checks are defined. + */ + switch (address) { + case 0x00000000 ... 0x1fffffff: /* ROM */ + case 0x20000000 ... 0x3fffffff: /* SRAM */ + case 0x60000000 ... 0x7fffffff: /* RAM */ + case 0x80000000 ... 0x9fffffff: /* RAM */ + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + break; + case 0x40000000 ... 0x5fffffff: /* Peripheral */ + case 0xa0000000 ... 0xbfffffff: /* Device */ + case 0xc0000000 ... 0xdfffffff: /* Device */ + case 0xe0000000 ... 0xffffffff: /* System */ + *prot = PAGE_READ | PAGE_WRITE; + break; + default: + g_assert_not_reached(); + } + } +} + +static bool m_is_ppb_region(CPUARMState *env, uint32_t address) +{ + /* True if address is in the M profile PPB region 0xe0000000 - 0xe00fffff */ + return arm_feature(env, ARM_FEATURE_M) && + extract32(address, 20, 12) == 0xe00; +} + +static bool m_is_system_region(CPUARMState *env, uint32_t address) +{ + /* + * True if address is in the M profile system region + * 0xe0000000 - 0xffffffff + */ + return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; +} + +static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, + bool is_secure, bool is_user) +{ + /* + * Return true if we should use the default memory map as a + * "background" region if there are no hits against any MPU regions. + */ + CPUARMState *env = &cpu->env; + + if (is_user) { + return false; + } + + if (arm_feature(env, ARM_FEATURE_M)) { + return env->v7m.mpu_ctrl[is_secure] & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; + } + + if (mmu_idx == ARMMMUIdx_Stage2) { + return false; + } + + return regime_sctlr(env, mmu_idx) & SCTLR_BR; +} + +static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + ARMCPU *cpu = env_archcpu(env); + int n; + bool is_user = regime_is_user(env, mmu_idx); + + result->f.phys_addr = address; + result->f.lg_page_size = TARGET_PAGE_BITS; + result->f.prot = 0; + + 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. + * The other case which uses the default memory map in the + * v7M ARM ARM pseudocode is exception vector reads from the vector + * table. In QEMU those accesses are done in arm_v7m_load_vector(), + * 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, &result->f.prot); + } else { /* MPU enabled */ + for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { + /* region search */ + uint32_t base = env->pmsav7.drbar[n]; + uint32_t rsize = extract32(env->pmsav7.drsr[n], 1, 5); + uint32_t rmask; + bool srdis = false; + + if (!(env->pmsav7.drsr[n] & 0x1)) { + continue; + } + + if (!rsize) { + qemu_log_mask(LOG_GUEST_ERROR, + "DRSR[%d]: Rsize field cannot be 0\n", n); + continue; + } + rsize++; + rmask = (1ull << rsize) - 1; + + if (base & rmask) { + qemu_log_mask(LOG_GUEST_ERROR, + "DRBAR[%d]: 0x%" PRIx32 " misaligned " + "to DRSR region size, mask = 0x%" PRIx32 "\n", + n, base, rmask); + continue; + } + + if (address < base || address > base + rmask) { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result in + * incorrect TLB hits for subsequent accesses to addresses that + * are in this MPU region. + */ + if (ranges_overlap(base, rmask, + address & TARGET_PAGE_MASK, + TARGET_PAGE_SIZE)) { + result->f.lg_page_size = 0; + } + continue; + } + + /* Region matched */ + + if (rsize >= 8) { /* no subregions for regions < 256 bytes */ + int i, snd; + uint32_t srdis_mask; + + rsize -= 3; /* sub region size (power of 2) */ + snd = ((address - base) >> rsize) & 0x7; + srdis = extract32(env->pmsav7.drsr[n], snd + 8, 1); + + srdis_mask = srdis ? 0x3 : 0x0; + for (i = 2; i <= 8 && rsize < TARGET_PAGE_BITS; i *= 2) { + /* + * This will check in groups of 2, 4 and then 8, whether + * the subregion bits are consistent. rsize is incremented + * back up to give the region size, considering consistent + * adjacent subregions as one region. Stop testing if rsize + * is already big enough for an entire QEMU page. + */ + int snd_rounded = snd & ~(i - 1); + uint32_t srdis_multi = extract32(env->pmsav7.drsr[n], + snd_rounded + 8, i); + if (srdis_mask ^ srdis_multi) { + break; + } + srdis_mask = (srdis_mask << i) | srdis_mask; + rsize++; + } + } + if (srdis) { + continue; + } + if (rsize < TARGET_PAGE_BITS) { + result->f.lg_page_size = rsize; + } + break; + } + + if (n == -1) { /* no hits */ + 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, + &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); + + if (m_is_system_region(env, address)) { + /* System space is always execute never */ + xn = 1; + } + + if (is_user) { /* User mode AP bit decoding */ + switch (ap) { + case 0: + case 1: + case 5: + break; /* no access */ + case 3: + result->f.prot |= PAGE_WRITE; + /* fall through */ + case 2: + case 6: + 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)) { + result->f.prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "DRACR[%d]: Bad value for AP bits: 0x%" + PRIx32 "\n", n, ap); + } + } else { /* Priv. mode AP bits decoding */ + switch (ap) { + case 0: + break; /* no access */ + case 1: + case 2: + case 3: + result->f.prot |= PAGE_WRITE; + /* fall through */ + case 5: + case 6: + 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)) { + result->f.prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "DRACR[%d]: Bad value for AP bits: 0x%" + PRIx32 "\n", n, ap); + } + } + + /* execute never */ + if (xn) { + result->f.prot &= ~PAGE_EXEC; + } + } + } + + fi->type = ARMFault_Permission; + fi->level = 1; + return !(result->f.prot & (1 << access_type)); +} + +static uint32_t *regime_rbar(CPUARMState *env, ARMMMUIdx mmu_idx, + uint32_t secure) +{ + if (regime_el(env, mmu_idx) == 2) { + return env->pmsav8.hprbar; + } else { + return env->pmsav8.rbar[secure]; + } +} + +static uint32_t *regime_rlar(CPUARMState *env, ARMMMUIdx mmu_idx, + uint32_t secure) +{ + if (regime_el(env, mmu_idx) == 2) { + return env->pmsav8.hprlar; + } else { + return env->pmsav8.rlar[secure]; + } +} + +bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi, uint32_t *mregion) +{ + /* + * Perform a PMSAv8 MPU lookup (without also doing the SAU check + * that a full phys-to-virt translation does). + * 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). + * 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); + 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); + int region_counter; + + if (regime_el(env, mmu_idx) == 2) { + region_counter = cpu->pmsav8r_hdregion; + } else { + region_counter = cpu->pmsav7_dregion; + } + + result->f.lg_page_size = TARGET_PAGE_BITS; + result->f.phys_addr = address; + result->f.prot = 0; + if (mregion) { + *mregion = -1; + } + + if (mmu_idx == ARMMMUIdx_Stage2) { + fi->stage2 = true; + } + + /* + * Unlike the ARM ARM pseudocode, we don't need to check whether this + * was an exception vector read from the vector table (which is always + * done using the default system address map), because those accesses + * 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, secure)) { /* MPU disabled */ + hit = true; + } else if (m_is_ppb_region(env, address)) { + hit = true; + } else { + if (pmsav7_use_background_region(cpu, mmu_idx, secure, is_user)) { + hit = true; + } + + uint32_t bitmask; + if (arm_feature(env, ARM_FEATURE_M)) { + bitmask = 0x1f; + } else { + bitmask = 0x3f; + fi->level = 0; + } + + for (n = region_counter - 1; n >= 0; n--) { + /* region search */ + /* + * Note that the base address is bits [31:x] from the register + * with bits [x-1:0] all zeroes, but the limit address is bits + * [31:x] from the register with bits [x:0] all ones. Where x is + * 5 for Cortex-M and 6 for Cortex-R + */ + uint32_t base = regime_rbar(env, mmu_idx, secure)[n] & ~bitmask; + uint32_t limit = regime_rlar(env, mmu_idx, secure)[n] | bitmask; + + if (!(regime_rlar(env, mmu_idx, secure)[n] & 0x1)) { + /* Region disabled */ + continue; + } + + if (address < base || address > limit) { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result in + * incorrect TLB hits for subsequent accesses to addresses that + * are in this MPU region. + */ + if (limit >= base && + ranges_overlap(base, limit - base + 1, + addr_page_base, + TARGET_PAGE_SIZE)) { + result->f.lg_page_size = 0; + } + continue; + } + + if (base > addr_page_base || limit < addr_page_limit) { + result->f.lg_page_size = 0; + } + + if (matchregion != -1) { + /* + * Multiple regions match -- always a failure (unlike + * PMSAv7 where highest-numbered-region wins) + */ + fi->type = ARMFault_Permission; + if (arm_feature(env, ARM_FEATURE_M)) { + fi->level = 1; + } + return true; + } + + matchregion = n; + hit = true; + } + } + + if (!hit) { + if (arm_feature(env, ARM_FEATURE_M)) { + fi->type = ARMFault_Background; + } else { + fi->type = ARMFault_Permission; + } + return true; + } + + if (matchregion == -1) { + /* hit using the background region */ + get_phys_addr_pmsav7_default(env, mmu_idx, address, &result->f.prot); + } else { + uint32_t matched_rbar = regime_rbar(env, mmu_idx, secure)[matchregion]; + uint32_t matched_rlar = regime_rlar(env, mmu_idx, secure)[matchregion]; + uint32_t ap = extract32(matched_rbar, 1, 2); + uint32_t xn = extract32(matched_rbar, 0, 1); + bool pxn = false; + + if (arm_feature(env, ARM_FEATURE_V8_1M)) { + pxn = extract32(matched_rlar, 4, 1); + } + + if (m_is_system_region(env, address)) { + /* System space is always execute never */ + xn = 1; + } + + if (regime_el(env, mmu_idx) == 2) { + result->f.prot = simple_ap_to_rw_prot_is_user(ap, + mmu_idx != ARMMMUIdx_E2); + } else { + result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap); + } + + if (!arm_feature(env, ARM_FEATURE_M)) { + uint8_t attrindx = extract32(matched_rlar, 1, 3); + uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; + uint8_t sh = extract32(matched_rlar, 3, 2); + + if (regime_sctlr(env, mmu_idx) & SCTLR_WXN && + result->f.prot & PAGE_WRITE && mmu_idx != ARMMMUIdx_Stage2) { + xn = 0x1; + } + + if ((regime_el(env, mmu_idx) == 1) && + regime_sctlr(env, mmu_idx) & SCTLR_UWXN && ap == 0x1) { + pxn = 0x1; + } + + result->cacheattrs.is_s2_format = false; + result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8); + result->cacheattrs.shareability = sh; + } + + if (result->f.prot && !xn && !(pxn && !is_user)) { + result->f.prot |= PAGE_EXEC; + } + + if (mregion) { + *mregion = matchregion; + } + } + + fi->type = ARMFault_Permission; + if (arm_feature(env, ARM_FEATURE_M)) { + fi->level = 1; + } + return !(result->f.prot & (1 << access_type)); +} + +static bool v8m_is_sau_exempt(CPUARMState *env, + uint32_t address, MMUAccessType access_type) +{ + /* + * The architecture specifies that certain address ranges are + * exempt from v8M SAU/IDAU checks. + */ + return + (access_type == MMU_INST_FETCH && m_is_system_region(env, address)) || + (address >= 0xe0000000 && address <= 0xe0002fff) || + (address >= 0xe000e000 && address <= 0xe000efff) || + (address >= 0xe002e000 && address <= 0xe002efff) || + (address >= 0xe0040000 && address <= 0xe0041fff) || + (address >= 0xe00ff000 && address <= 0xe00fffff); +} + +void v8m_security_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, V8M_SAttributes *sattrs) +{ + /* + * Look up the security attributes for this address. Compare the + * pseudocode SecurityCheck() function. + * We assume the caller has zero-initialized *sattrs. + */ + ARMCPU *cpu = env_archcpu(env); + int r; + bool idau_exempt = false, idau_ns = true, idau_nsc = true; + int idau_region = IREGION_NOTVALID; + uint32_t addr_page_base = address & TARGET_PAGE_MASK; + uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); + + if (cpu->idau) { + IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(cpu->idau); + IDAUInterface *ii = IDAU_INTERFACE(cpu->idau); + + iic->check(ii, address, &idau_region, &idau_exempt, &idau_ns, + &idau_nsc); + } + + if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) { + /* 0xf0000000..0xffffffff is always S for insn fetches */ + return; + } + + if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) { + sattrs->ns = !is_secure; + return; + } + + if (idau_region != IREGION_NOTVALID) { + sattrs->irvalid = true; + sattrs->iregion = idau_region; + } + + switch (env->sau.ctrl & 3) { + case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */ + break; + case 2: /* SAU.ENABLE == 0, SAU.ALLNS == 1 */ + sattrs->ns = true; + break; + default: /* SAU.ENABLE == 1 */ + for (r = 0; r < cpu->sau_sregion; r++) { + if (env->sau.rlar[r] & 1) { + uint32_t base = env->sau.rbar[r] & ~0x1f; + uint32_t limit = env->sau.rlar[r] | 0x1f; + + if (base <= address && limit >= address) { + if (base > addr_page_base || limit < addr_page_limit) { + sattrs->subpage = true; + } + if (sattrs->srvalid) { + /* + * If we hit in more than one region then we must report + * as Secure, not NS-Callable, with no valid region + * number info. + */ + sattrs->ns = false; + sattrs->nsc = false; + sattrs->sregion = 0; + sattrs->srvalid = false; + break; + } else { + if (env->sau.rlar[r] & 2) { + sattrs->nsc = true; + } else { + sattrs->ns = true; + } + sattrs->srvalid = true; + sattrs->sregion = r; + } + } else { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result + * in incorrect TLB hits for subsequent accesses to + * addresses that are in this MPU region. + */ + if (limit >= base && + ranges_overlap(base, limit - base + 1, + addr_page_base, + TARGET_PAGE_SIZE)) { + sattrs->subpage = true; + } + } + } + } + break; + } + + /* + * The IDAU will override the SAU lookup results if it specifies + * higher security than the SAU does. + */ + if (!idau_ns) { + if (sattrs->ns || (!idau_nsc && sattrs->nsc)) { + sattrs->ns = false; + sattrs->nsc = idau_nsc; + } + } +} + +static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + V8M_SAttributes sattrs = {}; + bool ret; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + 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 + * transaction attribute determined by the fetch address, + * regardless of CPU state. This is painful for QEMU + * to handle, because it would mean we need to encode + * into the mmu_idx not just the (user, negpri) information + * for the current security state but also that for the + * other security state, which would balloon the number + * of mmu_idx values needed alarmingly. + * Fortunately we can avoid this because it's not actually + * possible to arbitrarily execute code from memory with + * the wrong security attribute: it will always generate + * an exception of some kind or another, apart from the + * special case of an NS CPU executing an SG instruction + * in S&NSC memory. So we always just fail the translation + * here and sort things out in the exception handler + * (including possibly emulating an SG instruction). + */ + if (sattrs.ns != !secure) { + if (sattrs.nsc) { + fi->type = ARMFault_QEMU_NSCExec; + } else { + fi->type = ARMFault_QEMU_SFault; + } + result->f.lg_page_size = sattrs.subpage ? 0 : TARGET_PAGE_BITS; + result->f.phys_addr = address; + result->f.prot = 0; + return true; + } + } else { + /* + * For data accesses we always use the MMU bank indicated + * by the current CPU state, but the security attributes + * might downgrade a secure access to nonsecure. + */ + if (sattrs.ns) { + result->f.attrs.secure = false; + } else if (!secure) { + /* + * NS access to S memory must fault. + * Architecturally we should first check whether the + * MPU information for this address indicates that we + * are doing an unaligned access to Device memory, which + * should generate a UsageFault instead. QEMU does not + * currently check for that kind of unaligned access though. + * If we added it we would need to do so as a special case + * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). + */ + fi->type = ARMFault_QEMU_SFault; + 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, secure, + result, fi, NULL); + if (sattrs.subpage) { + result->f.lg_page_size = 0; + } + return ret; +} + +/* + * Translate from the 4-bit stage 2 representation of + * memory attributes (without cache-allocation hints) to + * the 8-bit representation of the stage 1 MAIR registers + * (which includes allocation hints). + * + * ref: shared/translation/attrs/S2AttrDecode() + * .../S2ConvertAttrsHints() + */ +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 (hcr & HCR_CD) { /* cache disabled */ + hiattr = loattr = 1; /* non-cacheable */ + } else { + if (hiattr != 1) { /* Write-through or write-back */ + hihint = 3; /* RW allocate */ + } + if (loattr != 1) { /* Write-through or write-back */ + lohint = 3; /* RW allocate */ + } + } + } + + return (hiattr << 6) | (hihint << 4) | (loattr << 2) | lohint; +} + +/* + * Combine either inner or outer cacheability attributes for normal + * memory, according to table D4-42 and pseudocode procedure + * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). + * + * NB: only stage 1 includes allocation hints (RW bits), leading to + * some asymmetry. + */ +static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) +{ + if (s1 == 4 || s2 == 4) { + /* non-cacheable has precedence */ + return 4; + } else if (extract32(s1, 2, 2) == 0 || extract32(s1, 2, 2) == 2) { + /* stage 1 write-through takes precedence */ + return s1; + } else if (extract32(s2, 2, 2) == 2) { + /* stage 2 write-through takes precedence, but the allocation hint + * is still taken from stage 1 + */ + return (2 << 2) | extract32(s1, 0, 2); + } else { /* write-back */ + return s1; + } +} + +/* + * Combine the memory type and cacheability attributes of + * s1 and s2 for the HCR_EL2.FWB == 0 case, returning the + * combined attributes in MAIR_EL1 format. + */ +static uint8_t combined_attrs_nofwb(uint64_t hcr, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs; + + if (s2.is_s2_format) { + s2_mair_attrs = convert_stage2_attrs(hcr, s2.attrs); + } else { + s2_mair_attrs = s2.attrs; + } + + s1lo = extract32(s1.attrs, 0, 4); + s2lo = extract32(s2_mair_attrs, 0, 4); + s1hi = extract32(s1.attrs, 4, 4); + s2hi = extract32(s2_mair_attrs, 4, 4); + + /* Combine memory type and cacheability attributes */ + if (s1hi == 0 || s2hi == 0) { + /* Device has precedence over normal */ + if (s1lo == 0 || s2lo == 0) { + /* nGnRnE has precedence over anything */ + ret_attrs = 0; + } else if (s1lo == 4 || s2lo == 4) { + /* non-Reordering has precedence over Reordering */ + ret_attrs = 4; /* nGnRE */ + } else if (s1lo == 8 || s2lo == 8) { + /* non-Gathering has precedence over Gathering */ + ret_attrs = 8; /* nGRE */ + } else { + ret_attrs = 0xc; /* GRE */ + } + } else { /* Normal memory */ + /* Outer/inner cacheability combine independently */ + ret_attrs = combine_cacheattr_nibble(s1hi, s2hi) << 4 + | combine_cacheattr_nibble(s1lo, s2lo); + } + return ret_attrs; +} + +static uint8_t force_cacheattr_nibble_wb(uint8_t attr) +{ + /* + * Given the 4 bits specifying the outer or inner cacheability + * in MAIR format, return a value specifying Normal Write-Back, + * with the allocation and transient hints taken from the input + * if the input specified some kind of cacheable attribute. + */ + if (attr == 0 || attr == 4) { + /* + * 0 == an UNPREDICTABLE encoding + * 4 == Non-cacheable + * Either way, force Write-Back RW allocate non-transient + */ + return 0xf; + } + /* Change WriteThrough to WriteBack, keep allocation and transient hints */ + return attr | 4; +} + +/* + * Combine the memory type and cacheability attributes of + * s1 and s2 for the HCR_EL2.FWB == 1 case, returning the + * combined attributes in MAIR_EL1 format. + */ +static uint8_t combined_attrs_fwb(ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + assert(s2.is_s2_format && !s1.is_s2_format); + + switch (s2.attrs) { + case 7: + /* Use stage 1 attributes */ + return s1.attrs; + case 6: + /* + * Force Normal Write-Back. Note that if S1 is Normal cacheable + * then we take the allocation hints from it; otherwise it is + * RW allocate, non-transient. + */ + if ((s1.attrs & 0xf0) == 0) { + /* S1 is Device */ + return 0xff; + } + /* Need to check the Inner and Outer nibbles separately */ + return force_cacheattr_nibble_wb(s1.attrs & 0xf) | + force_cacheattr_nibble_wb(s1.attrs >> 4) << 4; + case 5: + /* If S1 attrs are Device, use them; otherwise Normal Non-cacheable */ + if ((s1.attrs & 0xf0) == 0) { + return s1.attrs; + } + return 0x44; + case 0 ... 3: + /* Force Device, of subtype specified by S2 */ + return s2.attrs << 2; + default: + /* + * RESERVED values (including RES0 descriptor bit [5] being nonzero); + * arbitrarily force Device. + */ + return 0; + } +} + +/* + * Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 + * and CombineS1S2Desc() + * + * @env: CPUARMState + * @s1: Attributes from stage 1 walk + * @s2: Attributes from stage 2 walk + */ +static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + ARMCacheAttrs ret; + bool tagged = false; + + assert(!s1.is_s2_format); + ret.is_s2_format = false; + + if (s1.attrs == 0xf0) { + tagged = true; + s1.attrs = 0xff; + } + + /* Combine shareability attributes (table D4-43) */ + if (s1.shareability == 2 || s2.shareability == 2) { + /* if either are outer-shareable, the result is outer-shareable */ + ret.shareability = 2; + } else if (s1.shareability == 3 || s2.shareability == 3) { + /* if either are inner-shareable, the result is inner-shareable */ + ret.shareability = 3; + } else { + /* both non-shareable */ + ret.shareability = 0; + } + + /* Combine memory type and cacheability attributes */ + if (hcr & HCR_FWB) { + ret.attrs = combined_attrs_fwb(s1, s2); + } else { + ret.attrs = combined_attrs_nofwb(hcr, s1, s2); + } + + /* + * Any location for which the resultant memory type is any + * type of Device memory is always treated as Outer Shareable. + * Any location for which the resultant memory type is Normal + * Inner Non-cacheable, Outer Non-cacheable is always treated + * as Outer Shareable. + * TODO: FEAT_XS adds another value (0x40) also meaning iNCoNC + */ + if ((ret.attrs & 0xf0) == 0 || ret.attrs == 0x44) { + ret.shareability = 2; + } + + /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ + if (tagged && ret.attrs == 0xff) { + ret.attrs = 0xf0; + } + + return ret; +} + +/* + * MMU disabled. S1 addresses within aa64 translation regimes are + * still checked for bounds -- see AArch64.S1DisabledOutput(). + */ +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 */ + int r_el; + + switch (mmu_idx) { + case ARMMMUIdx_Stage2: + case ARMMMUIdx_Stage2_S: + case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_S: + break; + + default: + 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; + break; + } + + 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 false; +} + +static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + hwaddr ipa; + int s1_prot, s1_lgpgsz; + bool is_secure = ptw->in_secure; + bool ret, ipa_secure, s2walk_secure; + ARMCacheAttrs cacheattrs1; + bool is_el0; + uint64_t hcr; + + ret = get_phys_addr_with_struct(env, ptw, address, access_type, result, fi); + + /* If S1 fails, return early. */ + if (ret) { + return ret; + } + + 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; + } + + is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0; + ptw->in_mmu_idx = s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; + ptw->in_ptw_idx = s2walk_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS; + ptw->in_secure = s2walk_secure; + + /* + * 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; + s1_lgpgsz = result->f.lg_page_size; + cacheattrs1 = result->cacheattrs; + memset(result, 0, sizeof(*result)); + + if (arm_feature(env, ARM_FEATURE_PMSA)) { + ret = get_phys_addr_pmsav8(env, ipa, access_type, + ptw->in_mmu_idx, is_secure, result, fi); + } else { + ret = get_phys_addr_lpae(env, ptw, ipa, access_type, + is_el0, result, fi); + } + fi->s2addr = ipa; + + /* Combine the S1 and S2 perms. */ + result->f.prot &= s1_prot; + + /* If S2 fails, return early. */ + if (ret) { + return ret; + } + + /* + * If either S1 or S2 returned a result smaller than TARGET_PAGE_SIZE, + * this means "don't put this in the TLB"; in this case, return a + * result with lg_page_size == 0 to achieve that. Otherwise, + * use the maximum of the S1 & S2 page size, so that invalidation + * of pages > TARGET_PAGE_SIZE works correctly. (This works even though + * we know the combined result permissions etc only cover the minimum + * of the S1 and S2 page size, because we know that the common TLB code + * never actually creates TLB entries bigger than TARGET_PAGE_SIZE, + * and passing a larger page size value only affects invalidations.) + */ + if (result->f.lg_page_size < TARGET_PAGE_BITS || + s1_lgpgsz < TARGET_PAGE_BITS) { + result->f.lg_page_size = 0; + } else if (result->f.lg_page_size < s1_lgpgsz) { + result->f.lg_page_size = s1_lgpgsz; + } + + /* Combine the S1 and S2 cache attributes. */ + hcr = arm_hcr_el2_eff_secstate(env, is_secure); + if (hcr & HCR_DC) { + /* + * HCR.DC forces the first stage attributes to + * Normal Non-Shareable, + * Inner Write-Back Read-Allocate Write-Allocate, + * Outer Write-Back Read-Allocate Write-Allocate. + * Do not overwrite Tagged within attrs. + */ + if (cacheattrs1.attrs != 0xf0) { + cacheattrs1.attrs = 0xff; + } + cacheattrs1.shareability = 0; + } + 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)))); + + return false; +} + +static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + ARMMMUIdx mmu_idx = ptw->in_mmu_idx; + bool is_secure = ptw->in_secure; + ARMMMUIdx s1_mmu_idx; + + /* + * The page table entries may downgrade secure to non-secure, but + * cannot upgrade an non-secure translation regime's attributes + * to secure. + */ + result->f.attrs.secure = is_secure; + + switch (mmu_idx) { + case ARMMMUIdx_Phys_S: + case ARMMMUIdx_Phys_NS: + /* Checking Phys early avoids special casing later vs regime_el. */ + return get_phys_addr_disabled(env, address, access_type, mmu_idx, + is_secure, result, fi); + + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_E1: + case ARMMMUIdx_Stage1_E1_PAN: + /* First stage lookup uses second stage for ptw. */ + ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; + break; + + case ARMMMUIdx_E10_0: + s1_mmu_idx = ARMMMUIdx_Stage1_E0; + goto do_twostage; + case ARMMMUIdx_E10_1: + s1_mmu_idx = ARMMMUIdx_Stage1_E1; + goto do_twostage; + case ARMMMUIdx_E10_1_PAN: + s1_mmu_idx = ARMMMUIdx_Stage1_E1_PAN; + do_twostage: + /* + * Call ourselves recursively to do the stage 1 and then stage 2 + * translations if mmu_idx is a two-stage regime, and EL2 present. + * Otherwise, a stage1+stage2 translation is just stage 1. + */ + ptw->in_mmu_idx = mmu_idx = s1_mmu_idx; + if (arm_feature(env, ARM_FEATURE_EL2) && + !regime_translation_disabled(env, ARMMMUIdx_Stage2, is_secure)) { + return get_phys_addr_twostage(env, ptw, address, access_type, + result, fi); + } + /* fall through */ + + default: + /* Single stage and second stage uses physical for ptw. */ + ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS; + break; + } + + result->f.attrs.user = regime_is_user(env, mmu_idx); + + /* + * Fast Context Switch Extension. This doesn't exist at all in v8. + * In v7 and earlier it affects all stage 1 translations. + */ + if (address < 0x02000000 && mmu_idx != ARMMMUIdx_Stage2 + && !arm_feature(env, ARM_FEATURE_V8)) { + if (regime_el(env, mmu_idx) == 3) { + address += env->cp15.fcseidr_s; + } else { + address += env->cp15.fcseidr_ns; + } + } + + if (arm_feature(env, ARM_FEATURE_PMSA)) { + bool ret; + 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, + is_secure, result, fi); + } else if (arm_feature(env, ARM_FEATURE_V7)) { + /* PMSAv7 */ + ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, + is_secure, result, fi); + } else { + /* Pre-v7 MPU */ + ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, + 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", + access_type == MMU_DATA_LOAD ? "reading" : + (access_type == MMU_DATA_STORE ? "writing" : "execute"), + (uint32_t)address, mmu_idx, + ret ? "Miss" : "Hit", + 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, 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, ptw, address, access_type, false, + result, fi); + } else if (arm_feature(env, ARM_FEATURE_V7) || + regime_sctlr(env, mmu_idx) & SCTLR_XP) { + return get_phys_addr_v6(env, ptw, address, access_type, result, fi); + } else { + return get_phys_addr_v5(env, ptw, address, access_type, result, fi); + } +} + +bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + S1Translate ptw = { + .in_mmu_idx = mmu_idx, + .in_secure = is_secure, + }; + return get_phys_addr_with_struct(env, &ptw, address, access_type, + 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_Phys_NS: + 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_Phys_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; + S1Translate ptw = { + .in_mmu_idx = arm_mmu_idx(env), + .in_secure = arm_is_secure(env), + .in_debug = true, + }; + GetPhysAddrResult res = {}; + ARMMMUFaultInfo fi = {}; + bool ret; + + ret = get_phys_addr_with_struct(env, &ptw, addr, MMU_DATA_LOAD, &res, &fi); + *attrs = res.f.attrs; + + if (ret) { + return -1; + } + return res.f.phys_addr; +} diff --git a/target/arm/sme-fa64.decode b/target/arm/sme-fa64.decode new file mode 100644 index 000000000000..47708ccc8dae --- /dev/null +++ b/target/arm/sme-fa64.decode @@ -0,0 +1,60 @@ +# AArch64 SME allowed instruction decoding +# +# Copyright (c) 2022 Linaro, Ltd +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.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 . + +# +# This file is processed by scripts/decodetree.py +# + +# These patterns are taken from Appendix E1.1 of DDI0616 A.a, +# Arm Architecture Reference Manual Supplement, +# The Scalable Matrix Extension (SME), for Armv9-A + +{ + [ + OK 0-00 1110 0000 0001 0010 11-- ---- ---- # SMOV W|Xd,Vn.B[0] + OK 0-00 1110 0000 0010 0010 11-- ---- ---- # SMOV W|Xd,Vn.H[0] + OK 0100 1110 0000 0100 0010 11-- ---- ---- # SMOV Xd,Vn.S[0] + OK 0000 1110 0000 0001 0011 11-- ---- ---- # UMOV Wd,Vn.B[0] + OK 0000 1110 0000 0010 0011 11-- ---- ---- # UMOV Wd,Vn.H[0] + OK 0000 1110 0000 0100 0011 11-- ---- ---- # UMOV Wd,Vn.S[0] + OK 0100 1110 0000 1000 0011 11-- ---- ---- # UMOV Xd,Vn.D[0] + ] + FAIL 0--0 111- ---- ---- ---- ---- ---- ---- # Advanced SIMD vector operations +} + +{ + [ + OK 0101 1110 --1- ---- 11-1 11-- ---- ---- # FMULX/FRECPS/FRSQRTS (scalar) + OK 0101 1110 -10- ---- 00-1 11-- ---- ---- # FMULX/FRECPS/FRSQRTS (scalar, FP16) + OK 01-1 1110 1-10 0001 11-1 10-- ---- ---- # FRECPE/FRSQRTE/FRECPX (scalar) + OK 01-1 1110 1111 1001 11-1 10-- ---- ---- # FRECPE/FRSQRTE/FRECPX (scalar, FP16) + ] + FAIL 01-1 111- ---- ---- ---- ---- ---- ---- # Advanced SIMD single-element operations +} + +FAIL 0-00 110- ---- ---- ---- ---- ---- ---- # Advanced SIMD structure load/store +FAIL 1100 1110 ---- ---- ---- ---- ---- ---- # Advanced SIMD cryptography extensions +FAIL 0001 1110 0111 1110 0000 00-- ---- ---- # FJCVTZS + +# These are the "avoidance of doubt" final table of Illegal Advanced SIMD instructions +# We don't actually need to include these, as the default is OK. +# -001 111- ---- ---- ---- ---- ---- ---- # Scalar floating-point operations +# --10 110- ---- ---- ---- ---- ---- ---- # Load/store pair of FP registers +# --01 1100 ---- ---- ---- ---- ---- ---- # Load FP register (PC-relative literal) +# --11 1100 --0- ---- ---- ---- ---- ---- # Load/store FP register (unscaled imm) +# --11 1100 --1- ---- ---- ---- ---- --10 # Load/store FP register (register offset) +# --11 1101 ---- ---- ---- ---- ---- ---- # Load/store FP register (scaled imm) diff --git a/target/arm/sme.decode b/target/arm/sme.decode new file mode 100644 index 000000000000..628804e37a82 --- /dev/null +++ b/target/arm/sme.decode @@ -0,0 +1,88 @@ +# AArch64 SME instruction descriptions +# +# Copyright (c) 2022 Linaro, Ltd +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.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 . + +# +# This file is processed by scripts/decodetree.py +# + +### SME Misc + +ZERO 11000000 00 001 00000000000 imm:8 + +### SME Move into/from Array + +%mova_rs 13:2 !function=plus_12 +&mova esz rs pg zr za_imm v:bool to_vec:bool + +MOVA 11000000 esz:2 00000 0 v:1 .. pg:3 zr:5 0 za_imm:4 \ + &mova to_vec=0 rs=%mova_rs +MOVA 11000000 11 00000 1 v:1 .. pg:3 zr:5 0 za_imm:4 \ + &mova to_vec=0 rs=%mova_rs esz=4 + +MOVA 11000000 esz:2 00001 0 v:1 .. pg:3 0 za_imm:4 zr:5 \ + &mova to_vec=1 rs=%mova_rs +MOVA 11000000 11 00001 1 v:1 .. pg:3 0 za_imm:4 zr:5 \ + &mova to_vec=1 rs=%mova_rs esz=4 + +### SME Memory + +&ldst esz rs pg rn rm za_imm v:bool st:bool + +LDST1 1110000 0 esz:2 st:1 rm:5 v:1 .. pg:3 rn:5 0 za_imm:4 \ + &ldst rs=%mova_rs +LDST1 1110000 111 st:1 rm:5 v:1 .. pg:3 rn:5 0 za_imm:4 \ + &ldst esz=4 rs=%mova_rs + +&ldstr rv rn imm +@ldstr ....... ... . ...... .. ... rn:5 . imm:4 \ + &ldstr rv=%mova_rs + +LDR 1110000 100 0 000000 .. 000 ..... 0 .... @ldstr +STR 1110000 100 1 000000 .. 000 ..... 0 .... @ldstr + +### SME Add Vector to Array + +&adda zad zn pm pn +@adda_32 ........ .. ..... . pm:3 pn:3 zn:5 ... zad:2 &adda +@adda_64 ........ .. ..... . pm:3 pn:3 zn:5 .. zad:3 &adda + +ADDHA_s 11000000 10 01000 0 ... ... ..... 000 .. @adda_32 +ADDVA_s 11000000 10 01000 1 ... ... ..... 000 .. @adda_32 +ADDHA_d 11000000 11 01000 0 ... ... ..... 00 ... @adda_64 +ADDVA_d 11000000 11 01000 1 ... ... ..... 00 ... @adda_64 + +### SME Outer Product + +&op zad zn zm pm pn sub:bool +@op_32 ........ ... zm:5 pm:3 pn:3 zn:5 sub:1 .. zad:2 &op +@op_64 ........ ... zm:5 pm:3 pn:3 zn:5 sub:1 . zad:3 &op + +FMOPA_s 10000000 100 ..... ... ... ..... . 00 .. @op_32 +FMOPA_d 10000000 110 ..... ... ... ..... . 0 ... @op_64 + +BFMOPA 10000001 100 ..... ... ... ..... . 00 .. @op_32 +FMOPA_h 10000001 101 ..... ... ... ..... . 00 .. @op_32 + +SMOPA_s 1010000 0 10 0 ..... ... ... ..... . 00 .. @op_32 +SUMOPA_s 1010000 0 10 1 ..... ... ... ..... . 00 .. @op_32 +USMOPA_s 1010000 1 10 0 ..... ... ... ..... . 00 .. @op_32 +UMOPA_s 1010000 1 10 1 ..... ... ... ..... . 00 .. @op_32 + +SMOPA_d 1010000 0 11 0 ..... ... ... ..... . 0 ... @op_64 +SUMOPA_d 1010000 0 11 1 ..... ... ... ..... . 0 ... @op_64 +USMOPA_d 1010000 1 11 0 ..... ... ... ..... . 0 ... @op_64 +UMOPA_d 1010000 1 11 1 ..... ... ... ..... . 0 ... @op_64 diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c new file mode 100644 index 000000000000..f891306bb981 --- /dev/null +++ b/target/arm/sme_helper.c @@ -0,0 +1,1201 @@ +/* + * ARM SME Operations + * + * Copyright (c) 2022 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "tcg/tcg-gvec-desc.h" +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#include "exec/exec-all.h" +#include "qemu/int128.h" +#include "fpu/softfloat.h" +#include "vec_internal.h" +#include "sve_ldst_internal.h" + +/* ResetSVEState */ +void arm_reset_sve_state(CPUARMState *env) +{ + memset(env->vfp.zregs, 0, sizeof(env->vfp.zregs)); + /* Recall that FFR is stored as pregs[16]. */ + memset(env->vfp.pregs, 0, sizeof(env->vfp.pregs)); + vfp_set_fpcr(env, 0x0800009f); +} + +void helper_set_pstate_sm(CPUARMState *env, uint32_t i) +{ + if (i == FIELD_EX64(env->svcr, SVCR, SM)) { + return; + } + env->svcr ^= R_SVCR_SM_MASK; + arm_reset_sve_state(env); +} + +void helper_set_pstate_za(CPUARMState *env, uint32_t i) +{ + if (i == FIELD_EX64(env->svcr, SVCR, ZA)) { + return; + } + env->svcr ^= R_SVCR_ZA_MASK; + + /* + * ResetSMEState. + * + * SetPSTATE_ZA zeros on enable and disable. We can zero this only + * on enable: while disabled, the storage is inaccessible and the + * value does not matter. We're not saving the storage in vmstate + * when disabled either. + */ + if (i) { + memset(env->zarray, 0, sizeof(env->zarray)); + } +} + +void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl) +{ + uint32_t i; + + /* + * Special case clearing the entire ZA space. + * This falls into the CONSTRAINED UNPREDICTABLE zeroing of any + * parts of the ZA storage outside of SVL. + */ + if (imm == 0xff) { + memset(env->zarray, 0, sizeof(env->zarray)); + return; + } + + /* + * Recall that ZAnH.D[m] is spread across ZA[n+8*m], + * so each row is discontiguous within ZA[]. + */ + for (i = 0; i < svl; i++) { + if (imm & (1 << (i % 8))) { + memset(&env->zarray[i], 0, svl); + } + } +} + + +/* + * When considering the ZA storage as an array of elements of + * type T, the index within that array of the Nth element of + * a vertical slice of a tile can be calculated like this, + * regardless of the size of type T. This is because the tiles + * are interleaved, so if type T is size N bytes then row 1 of + * the tile is N rows away from row 0. The division by N to + * convert a byte offset into an array index and the multiplication + * by N to convert from vslice-index-within-the-tile to + * the index within the ZA storage cancel out. + */ +#define tile_vslice_index(i) ((i) * sizeof(ARMVectorReg)) + +/* + * When doing byte arithmetic on the ZA storage, the element + * byteoff bytes away in a tile vertical slice is always this + * many bytes away in the ZA storage, regardless of the + * size of the tile element, assuming that byteoff is a multiple + * of the element size. Again this is because of the interleaving + * of the tiles. For instance if we have 1 byte per element then + * each row of the ZA storage has one byte of the vslice data, + * and (counting from 0) byte 8 goes in row 8 of the storage + * at offset (8 * row-size-in-bytes). + * If we have 8 bytes per element then each row of the ZA storage + * has 8 bytes of the data, but there are 8 interleaved tiles and + * so byte 8 of the data goes into row 1 of the tile, + * which is again row 8 of the storage, so the offset is still + * (8 * row-size-in-bytes). Similarly for other element sizes. + */ +#define tile_vslice_offset(byteoff) ((byteoff) * sizeof(ARMVectorReg)) + + +/* + * Move Zreg vector to ZArray column. + */ +#define DO_MOVA_C(NAME, TYPE, H) \ +void HELPER(NAME)(void *za, void *vn, void *vg, uint32_t desc) \ +{ \ + int i, oprsz = simd_oprsz(desc); \ + for (i = 0; i < oprsz; ) { \ + uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \ + do { \ + if (pg & 1) { \ + *(TYPE *)(za + tile_vslice_offset(i)) = *(TYPE *)(vn + H(i)); \ + } \ + i += sizeof(TYPE); \ + pg >>= sizeof(TYPE); \ + } while (i & 15); \ + } \ +} + +DO_MOVA_C(sme_mova_cz_b, uint8_t, H1) +DO_MOVA_C(sme_mova_cz_h, uint16_t, H1_2) +DO_MOVA_C(sme_mova_cz_s, uint32_t, H1_4) + +void HELPER(sme_mova_cz_d)(void *za, void *vn, void *vg, uint32_t desc) +{ + int i, oprsz = simd_oprsz(desc) / 8; + uint8_t *pg = vg; + uint64_t *n = vn; + uint64_t *a = za; + + for (i = 0; i < oprsz; i++) { + if (pg[H1(i)] & 1) { + a[tile_vslice_index(i)] = n[i]; + } + } +} + +void HELPER(sme_mova_cz_q)(void *za, void *vn, void *vg, uint32_t desc) +{ + int i, oprsz = simd_oprsz(desc) / 16; + uint16_t *pg = vg; + Int128 *n = vn; + Int128 *a = za; + + /* + * Int128 is used here simply to copy 16 bytes, and to simplify + * the address arithmetic. + */ + for (i = 0; i < oprsz; i++) { + if (pg[H2(i)] & 1) { + a[tile_vslice_index(i)] = n[i]; + } + } +} + +#undef DO_MOVA_C + +/* + * Move ZArray column to Zreg vector. + */ +#define DO_MOVA_Z(NAME, TYPE, H) \ +void HELPER(NAME)(void *vd, void *za, void *vg, uint32_t desc) \ +{ \ + int i, oprsz = simd_oprsz(desc); \ + for (i = 0; i < oprsz; ) { \ + uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \ + do { \ + if (pg & 1) { \ + *(TYPE *)(vd + H(i)) = *(TYPE *)(za + tile_vslice_offset(i)); \ + } \ + i += sizeof(TYPE); \ + pg >>= sizeof(TYPE); \ + } while (i & 15); \ + } \ +} + +DO_MOVA_Z(sme_mova_zc_b, uint8_t, H1) +DO_MOVA_Z(sme_mova_zc_h, uint16_t, H1_2) +DO_MOVA_Z(sme_mova_zc_s, uint32_t, H1_4) + +void HELPER(sme_mova_zc_d)(void *vd, void *za, void *vg, uint32_t desc) +{ + int i, oprsz = simd_oprsz(desc) / 8; + uint8_t *pg = vg; + uint64_t *d = vd; + uint64_t *a = za; + + for (i = 0; i < oprsz; i++) { + if (pg[H1(i)] & 1) { + d[i] = a[tile_vslice_index(i)]; + } + } +} + +void HELPER(sme_mova_zc_q)(void *vd, void *za, void *vg, uint32_t desc) +{ + int i, oprsz = simd_oprsz(desc) / 16; + uint16_t *pg = vg; + Int128 *d = vd; + Int128 *a = za; + + /* + * Int128 is used here simply to copy 16 bytes, and to simplify + * the address arithmetic. + */ + for (i = 0; i < oprsz; i++, za += sizeof(ARMVectorReg)) { + if (pg[H2(i)] & 1) { + d[i] = a[tile_vslice_index(i)]; + } + } +} + +#undef DO_MOVA_Z + +/* + * Clear elements in a tile slice comprising len bytes. + */ + +typedef void ClearFn(void *ptr, size_t off, size_t len); + +static void clear_horizontal(void *ptr, size_t off, size_t len) +{ + memset(ptr + off, 0, len); +} + +static void clear_vertical_b(void *vptr, size_t off, size_t len) +{ + for (size_t i = 0; i < len; ++i) { + *(uint8_t *)(vptr + tile_vslice_offset(i + off)) = 0; + } +} + +static void clear_vertical_h(void *vptr, size_t off, size_t len) +{ + for (size_t i = 0; i < len; i += 2) { + *(uint16_t *)(vptr + tile_vslice_offset(i + off)) = 0; + } +} + +static void clear_vertical_s(void *vptr, size_t off, size_t len) +{ + for (size_t i = 0; i < len; i += 4) { + *(uint32_t *)(vptr + tile_vslice_offset(i + off)) = 0; + } +} + +static void clear_vertical_d(void *vptr, size_t off, size_t len) +{ + for (size_t i = 0; i < len; i += 8) { + *(uint64_t *)(vptr + tile_vslice_offset(i + off)) = 0; + } +} + +static void clear_vertical_q(void *vptr, size_t off, size_t len) +{ + for (size_t i = 0; i < len; i += 16) { + memset(vptr + tile_vslice_offset(i + off), 0, 16); + } +} + +/* + * Copy elements from an array into a tile slice comprising len bytes. + */ + +typedef void CopyFn(void *dst, const void *src, size_t len); + +static void copy_horizontal(void *dst, const void *src, size_t len) +{ + memcpy(dst, src, len); +} + +static void copy_vertical_b(void *vdst, const void *vsrc, size_t len) +{ + const uint8_t *src = vsrc; + uint8_t *dst = vdst; + size_t i; + + for (i = 0; i < len; ++i) { + dst[tile_vslice_index(i)] = src[i]; + } +} + +static void copy_vertical_h(void *vdst, const void *vsrc, size_t len) +{ + const uint16_t *src = vsrc; + uint16_t *dst = vdst; + size_t i; + + for (i = 0; i < len / 2; ++i) { + dst[tile_vslice_index(i)] = src[i]; + } +} + +static void copy_vertical_s(void *vdst, const void *vsrc, size_t len) +{ + const uint32_t *src = vsrc; + uint32_t *dst = vdst; + size_t i; + + for (i = 0; i < len / 4; ++i) { + dst[tile_vslice_index(i)] = src[i]; + } +} + +static void copy_vertical_d(void *vdst, const void *vsrc, size_t len) +{ + const uint64_t *src = vsrc; + uint64_t *dst = vdst; + size_t i; + + for (i = 0; i < len / 8; ++i) { + dst[tile_vslice_index(i)] = src[i]; + } +} + +static void copy_vertical_q(void *vdst, const void *vsrc, size_t len) +{ + for (size_t i = 0; i < len; i += 16) { + memcpy(vdst + tile_vslice_offset(i), vsrc + i, 16); + } +} + +/* + * Host and TLB primitives for vertical tile slice addressing. + */ + +#define DO_LD(NAME, TYPE, HOST, TLB) \ +static inline void sme_##NAME##_v_host(void *za, intptr_t off, void *host) \ +{ \ + TYPE val = HOST(host); \ + *(TYPE *)(za + tile_vslice_offset(off)) = val; \ +} \ +static inline void sme_##NAME##_v_tlb(CPUARMState *env, void *za, \ + intptr_t off, target_ulong addr, uintptr_t ra) \ +{ \ + TYPE val = TLB(env, useronly_clean_ptr(addr), ra); \ + *(TYPE *)(za + tile_vslice_offset(off)) = val; \ +} + +#define DO_ST(NAME, TYPE, HOST, TLB) \ +static inline void sme_##NAME##_v_host(void *za, intptr_t off, void *host) \ +{ \ + TYPE val = *(TYPE *)(za + tile_vslice_offset(off)); \ + HOST(host, val); \ +} \ +static inline void sme_##NAME##_v_tlb(CPUARMState *env, void *za, \ + intptr_t off, target_ulong addr, uintptr_t ra) \ +{ \ + TYPE val = *(TYPE *)(za + tile_vslice_offset(off)); \ + TLB(env, useronly_clean_ptr(addr), val, ra); \ +} + +/* + * The ARMVectorReg elements are stored in host-endian 64-bit units. + * For 128-bit quantities, the sequence defined by the Elem[] pseudocode + * corresponds to storing the two 64-bit pieces in little-endian order. + */ +#define DO_LDQ(HNAME, VNAME, BE, HOST, TLB) \ +static inline void HNAME##_host(void *za, intptr_t off, void *host) \ +{ \ + uint64_t val0 = HOST(host), val1 = HOST(host + 8); \ + uint64_t *ptr = za + off; \ + ptr[0] = BE ? val1 : val0, ptr[1] = BE ? val0 : val1; \ +} \ +static inline void VNAME##_v_host(void *za, intptr_t off, void *host) \ +{ \ + HNAME##_host(za, tile_vslice_offset(off), host); \ +} \ +static inline void HNAME##_tlb(CPUARMState *env, void *za, intptr_t off, \ + target_ulong addr, uintptr_t ra) \ +{ \ + uint64_t val0 = TLB(env, useronly_clean_ptr(addr), ra); \ + uint64_t val1 = TLB(env, useronly_clean_ptr(addr + 8), ra); \ + uint64_t *ptr = za + off; \ + ptr[0] = BE ? val1 : val0, ptr[1] = BE ? val0 : val1; \ +} \ +static inline void VNAME##_v_tlb(CPUARMState *env, void *za, intptr_t off, \ + target_ulong addr, uintptr_t ra) \ +{ \ + HNAME##_tlb(env, za, tile_vslice_offset(off), addr, ra); \ +} + +#define DO_STQ(HNAME, VNAME, BE, HOST, TLB) \ +static inline void HNAME##_host(void *za, intptr_t off, void *host) \ +{ \ + uint64_t *ptr = za + off; \ + HOST(host, ptr[BE]); \ + HOST(host + 1, ptr[!BE]); \ +} \ +static inline void VNAME##_v_host(void *za, intptr_t off, void *host) \ +{ \ + HNAME##_host(za, tile_vslice_offset(off), host); \ +} \ +static inline void HNAME##_tlb(CPUARMState *env, void *za, intptr_t off, \ + target_ulong addr, uintptr_t ra) \ +{ \ + uint64_t *ptr = za + off; \ + TLB(env, useronly_clean_ptr(addr), ptr[BE], ra); \ + TLB(env, useronly_clean_ptr(addr + 8), ptr[!BE], ra); \ +} \ +static inline void VNAME##_v_tlb(CPUARMState *env, void *za, intptr_t off, \ + target_ulong addr, uintptr_t ra) \ +{ \ + HNAME##_tlb(env, za, tile_vslice_offset(off), addr, ra); \ +} + +DO_LD(ld1b, uint8_t, ldub_p, cpu_ldub_data_ra) +DO_LD(ld1h_be, uint16_t, lduw_be_p, cpu_lduw_be_data_ra) +DO_LD(ld1h_le, uint16_t, lduw_le_p, cpu_lduw_le_data_ra) +DO_LD(ld1s_be, uint32_t, ldl_be_p, cpu_ldl_be_data_ra) +DO_LD(ld1s_le, uint32_t, ldl_le_p, cpu_ldl_le_data_ra) +DO_LD(ld1d_be, uint64_t, ldq_be_p, cpu_ldq_be_data_ra) +DO_LD(ld1d_le, uint64_t, ldq_le_p, cpu_ldq_le_data_ra) + +DO_LDQ(sve_ld1qq_be, sme_ld1q_be, 1, ldq_be_p, cpu_ldq_be_data_ra) +DO_LDQ(sve_ld1qq_le, sme_ld1q_le, 0, ldq_le_p, cpu_ldq_le_data_ra) + +DO_ST(st1b, uint8_t, stb_p, cpu_stb_data_ra) +DO_ST(st1h_be, uint16_t, stw_be_p, cpu_stw_be_data_ra) +DO_ST(st1h_le, uint16_t, stw_le_p, cpu_stw_le_data_ra) +DO_ST(st1s_be, uint32_t, stl_be_p, cpu_stl_be_data_ra) +DO_ST(st1s_le, uint32_t, stl_le_p, cpu_stl_le_data_ra) +DO_ST(st1d_be, uint64_t, stq_be_p, cpu_stq_be_data_ra) +DO_ST(st1d_le, uint64_t, stq_le_p, cpu_stq_le_data_ra) + +DO_STQ(sve_st1qq_be, sme_st1q_be, 1, stq_be_p, cpu_stq_be_data_ra) +DO_STQ(sve_st1qq_le, sme_st1q_le, 0, stq_le_p, cpu_stq_le_data_ra) + +#undef DO_LD +#undef DO_ST +#undef DO_LDQ +#undef DO_STQ + +/* + * Common helper for all contiguous predicated loads. + */ + +static inline QEMU_ALWAYS_INLINE +void sme_ld1(CPUARMState *env, void *za, uint64_t *vg, + const target_ulong addr, uint32_t desc, const uintptr_t ra, + const int esz, uint32_t mtedesc, bool vertical, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn, + ClearFn *clr_fn, + CopyFn *cpy_fn) +{ + const intptr_t reg_max = simd_oprsz(desc); + const intptr_t esize = 1 << esz; + intptr_t reg_off, reg_last; + SVEContLdSt info; + void *host; + int flags; + + /* Find the active elements. */ + if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, esize)) { + /* The entire predicate was false; no load occurs. */ + clr_fn(za, 0, reg_max); + return; + } + + /* Probe the page(s). Exit with exception for any invalid page. */ + sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_LOAD, ra); + + /* Handle watchpoints for all active elements. */ + sve_cont_ldst_watchpoints(&info, env, vg, addr, esize, esize, + BP_MEM_READ, ra); + + /* + * Handle mte checks for all active elements. + * Since TBI must be set for MTE, !mtedesc => !mte_active. + */ + if (mtedesc) { + sve_cont_ldst_mte_check(&info, env, vg, addr, esize, esize, + mtedesc, ra); + } + + flags = info.page[0].flags | info.page[1].flags; + if (unlikely(flags != 0)) { +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + /* + * At least one page includes MMIO. + * Any bus operation can fail with cpu_transaction_failed, + * which for ARM will raise SyncExternal. Perform the load + * into scratch memory to preserve register state until the end. + */ + ARMVectorReg scratch = { }; + + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[1]; + if (reg_last < 0) { + reg_last = info.reg_off_split; + if (reg_last < 0) { + reg_last = info.reg_off_last[0]; + } + } + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + tlb_fn(env, &scratch, reg_off, addr + reg_off, ra); + } + reg_off += esize; + } while (reg_off & 63); + } while (reg_off <= reg_last); + + cpy_fn(za, &scratch, reg_max); + return; +#endif + } + + /* The entire operation is in RAM, on valid pages. */ + + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[0]; + host = info.page[0].host; + + if (!vertical) { + memset(za, 0, reg_max); + } else if (reg_off) { + clr_fn(za, 0, reg_off); + } + + while (reg_off <= reg_last) { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + host_fn(za, reg_off, host + reg_off); + } else if (vertical) { + clr_fn(za, reg_off, esize); + } + reg_off += esize; + } while (reg_off <= reg_last && (reg_off & 63)); + } + + /* + * Use the slow path to manage the cross-page misalignment. + * But we know this is RAM and cannot trap. + */ + reg_off = info.reg_off_split; + if (unlikely(reg_off >= 0)) { + tlb_fn(env, za, reg_off, addr + reg_off, ra); + } + + reg_off = info.reg_off_first[1]; + if (unlikely(reg_off >= 0)) { + reg_last = info.reg_off_last[1]; + host = info.page[1].host; + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + host_fn(za, reg_off, host + reg_off); + } else if (vertical) { + clr_fn(za, reg_off, esize); + } + reg_off += esize; + } while (reg_off & 63); + } while (reg_off <= reg_last); + } +} + +static inline QEMU_ALWAYS_INLINE +void sme_ld1_mte(CPUARMState *env, void *za, uint64_t *vg, + target_ulong addr, uint32_t desc, uintptr_t ra, + const int esz, bool vertical, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn, + ClearFn *clr_fn, + CopyFn *cpy_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + int bit55 = extract64(addr, 55, 1); + + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ + if (!tbi_check(desc, bit55) || + tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + + sme_ld1(env, za, vg, addr, desc, ra, esz, mtedesc, vertical, + host_fn, tlb_fn, clr_fn, cpy_fn); +} + +#define DO_LD(L, END, ESZ) \ +void HELPER(sme_ld1##L##END##_h)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_ld1(env, za, vg, addr, desc, GETPC(), ESZ, 0, false, \ + sve_ld1##L##L##END##_host, sve_ld1##L##L##END##_tlb, \ + clear_horizontal, copy_horizontal); \ +} \ +void HELPER(sme_ld1##L##END##_v)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_ld1(env, za, vg, addr, desc, GETPC(), ESZ, 0, true, \ + sme_ld1##L##END##_v_host, sme_ld1##L##END##_v_tlb, \ + clear_vertical_##L, copy_vertical_##L); \ +} \ +void HELPER(sme_ld1##L##END##_h_mte)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_ld1_mte(env, za, vg, addr, desc, GETPC(), ESZ, false, \ + sve_ld1##L##L##END##_host, sve_ld1##L##L##END##_tlb, \ + clear_horizontal, copy_horizontal); \ +} \ +void HELPER(sme_ld1##L##END##_v_mte)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_ld1_mte(env, za, vg, addr, desc, GETPC(), ESZ, true, \ + sme_ld1##L##END##_v_host, sme_ld1##L##END##_v_tlb, \ + clear_vertical_##L, copy_vertical_##L); \ +} + +DO_LD(b, , MO_8) +DO_LD(h, _be, MO_16) +DO_LD(h, _le, MO_16) +DO_LD(s, _be, MO_32) +DO_LD(s, _le, MO_32) +DO_LD(d, _be, MO_64) +DO_LD(d, _le, MO_64) +DO_LD(q, _be, MO_128) +DO_LD(q, _le, MO_128) + +#undef DO_LD + +/* + * Common helper for all contiguous predicated stores. + */ + +static inline QEMU_ALWAYS_INLINE +void sme_st1(CPUARMState *env, void *za, uint64_t *vg, + const target_ulong addr, uint32_t desc, const uintptr_t ra, + const int esz, uint32_t mtedesc, bool vertical, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + const intptr_t reg_max = simd_oprsz(desc); + const intptr_t esize = 1 << esz; + intptr_t reg_off, reg_last; + SVEContLdSt info; + void *host; + int flags; + + /* Find the active elements. */ + if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, esize)) { + /* The entire predicate was false; no store occurs. */ + return; + } + + /* Probe the page(s). Exit with exception for any invalid page. */ + sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_STORE, ra); + + /* Handle watchpoints for all active elements. */ + sve_cont_ldst_watchpoints(&info, env, vg, addr, esize, esize, + BP_MEM_WRITE, ra); + + /* + * Handle mte checks for all active elements. + * Since TBI must be set for MTE, !mtedesc => !mte_active. + */ + if (mtedesc) { + sve_cont_ldst_mte_check(&info, env, vg, addr, esize, esize, + mtedesc, ra); + } + + flags = info.page[0].flags | info.page[1].flags; + if (unlikely(flags != 0)) { +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + /* + * At least one page includes MMIO. + * Any bus operation can fail with cpu_transaction_failed, + * which for ARM will raise SyncExternal. We cannot avoid + * this fault and will leave with the store incomplete. + */ + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[1]; + if (reg_last < 0) { + reg_last = info.reg_off_split; + if (reg_last < 0) { + reg_last = info.reg_off_last[0]; + } + } + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + tlb_fn(env, za, reg_off, addr + reg_off, ra); + } + reg_off += esize; + } while (reg_off & 63); + } while (reg_off <= reg_last); + return; +#endif + } + + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[0]; + host = info.page[0].host; + + while (reg_off <= reg_last) { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + host_fn(za, reg_off, host + reg_off); + } + reg_off += 1 << esz; + } while (reg_off <= reg_last && (reg_off & 63)); + } + + /* + * Use the slow path to manage the cross-page misalignment. + * But we know this is RAM and cannot trap. + */ + reg_off = info.reg_off_split; + if (unlikely(reg_off >= 0)) { + tlb_fn(env, za, reg_off, addr + reg_off, ra); + } + + reg_off = info.reg_off_first[1]; + if (unlikely(reg_off >= 0)) { + reg_last = info.reg_off_last[1]; + host = info.page[1].host; + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + host_fn(za, reg_off, host + reg_off); + } + reg_off += 1 << esz; + } while (reg_off & 63); + } while (reg_off <= reg_last); + } +} + +static inline QEMU_ALWAYS_INLINE +void sme_st1_mte(CPUARMState *env, void *za, uint64_t *vg, target_ulong addr, + uint32_t desc, uintptr_t ra, int esz, bool vertical, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + int bit55 = extract64(addr, 55, 1); + + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ + if (!tbi_check(desc, bit55) || + tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + + sme_st1(env, za, vg, addr, desc, ra, esz, mtedesc, + vertical, host_fn, tlb_fn); +} + +#define DO_ST(L, END, ESZ) \ +void HELPER(sme_st1##L##END##_h)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_st1(env, za, vg, addr, desc, GETPC(), ESZ, 0, false, \ + sve_st1##L##L##END##_host, sve_st1##L##L##END##_tlb); \ +} \ +void HELPER(sme_st1##L##END##_v)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_st1(env, za, vg, addr, desc, GETPC(), ESZ, 0, true, \ + sme_st1##L##END##_v_host, sme_st1##L##END##_v_tlb); \ +} \ +void HELPER(sme_st1##L##END##_h_mte)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_st1_mte(env, za, vg, addr, desc, GETPC(), ESZ, false, \ + sve_st1##L##L##END##_host, sve_st1##L##L##END##_tlb); \ +} \ +void HELPER(sme_st1##L##END##_v_mte)(CPUARMState *env, void *za, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sme_st1_mte(env, za, vg, addr, desc, GETPC(), ESZ, true, \ + sme_st1##L##END##_v_host, sme_st1##L##END##_v_tlb); \ +} + +DO_ST(b, , MO_8) +DO_ST(h, _be, MO_16) +DO_ST(h, _le, MO_16) +DO_ST(s, _be, MO_32) +DO_ST(s, _le, MO_32) +DO_ST(d, _be, MO_64) +DO_ST(d, _le, MO_64) +DO_ST(q, _be, MO_128) +DO_ST(q, _le, MO_128) + +#undef DO_ST + +void HELPER(sme_addha_s)(void *vzda, void *vzn, void *vpn, + void *vpm, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_oprsz(desc) / 4; + uint64_t *pn = vpn, *pm = vpm; + uint32_t *zda = vzda, *zn = vzn; + + for (row = 0; row < oprsz; ) { + uint64_t pa = pn[row >> 4]; + do { + if (pa & 1) { + for (col = 0; col < oprsz; ) { + uint64_t pb = pm[col >> 4]; + do { + if (pb & 1) { + zda[tile_vslice_index(row) + H4(col)] += zn[H4(col)]; + } + pb >>= 4; + } while (++col & 15); + } + } + pa >>= 4; + } while (++row & 15); + } +} + +void HELPER(sme_addha_d)(void *vzda, void *vzn, void *vpn, + void *vpm, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_oprsz(desc) / 8; + uint8_t *pn = vpn, *pm = vpm; + uint64_t *zda = vzda, *zn = vzn; + + for (row = 0; row < oprsz; ++row) { + if (pn[H1(row)] & 1) { + for (col = 0; col < oprsz; ++col) { + if (pm[H1(col)] & 1) { + zda[tile_vslice_index(row) + col] += zn[col]; + } + } + } + } +} + +void HELPER(sme_addva_s)(void *vzda, void *vzn, void *vpn, + void *vpm, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_oprsz(desc) / 4; + uint64_t *pn = vpn, *pm = vpm; + uint32_t *zda = vzda, *zn = vzn; + + for (row = 0; row < oprsz; ) { + uint64_t pa = pn[row >> 4]; + do { + if (pa & 1) { + uint32_t zn_row = zn[H4(row)]; + for (col = 0; col < oprsz; ) { + uint64_t pb = pm[col >> 4]; + do { + if (pb & 1) { + zda[tile_vslice_index(row) + H4(col)] += zn_row; + } + pb >>= 4; + } while (++col & 15); + } + } + pa >>= 4; + } while (++row & 15); + } +} + +void HELPER(sme_addva_d)(void *vzda, void *vzn, void *vpn, + void *vpm, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_oprsz(desc) / 8; + uint8_t *pn = vpn, *pm = vpm; + uint64_t *zda = vzda, *zn = vzn; + + for (row = 0; row < oprsz; ++row) { + if (pn[H1(row)] & 1) { + uint64_t zn_row = zn[row]; + for (col = 0; col < oprsz; ++col) { + if (pm[H1(col)] & 1) { + zda[tile_vslice_index(row) + col] += zn_row; + } + } + } + } +} + +void HELPER(sme_fmopa_s)(void *vza, void *vzn, void *vzm, void *vpn, + void *vpm, void *vst, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_maxsz(desc); + uint32_t neg = simd_data(desc) << 31; + uint16_t *pn = vpn, *pm = vpm; + float_status fpst; + + /* + * Make a copy of float_status because this operation does not + * update the cumulative fp exception status. It also produces + * default nans. + */ + fpst = *(float_status *)vst; + set_default_nan_mode(true, &fpst); + + for (row = 0; row < oprsz; ) { + uint16_t pa = pn[H2(row >> 4)]; + do { + if (pa & 1) { + void *vza_row = vza + tile_vslice_offset(row); + uint32_t n = *(uint32_t *)(vzn + H1_4(row)) ^ neg; + + for (col = 0; col < oprsz; ) { + uint16_t pb = pm[H2(col >> 4)]; + do { + if (pb & 1) { + uint32_t *a = vza_row + H1_4(col); + uint32_t *m = vzm + H1_4(col); + *a = float32_muladd(n, *m, *a, 0, vst); + } + col += 4; + pb >>= 4; + } while (col & 15); + } + } + row += 4; + pa >>= 4; + } while (row & 15); + } +} + +void HELPER(sme_fmopa_d)(void *vza, void *vzn, void *vzm, void *vpn, + void *vpm, void *vst, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_oprsz(desc) / 8; + uint64_t neg = (uint64_t)simd_data(desc) << 63; + uint64_t *za = vza, *zn = vzn, *zm = vzm; + uint8_t *pn = vpn, *pm = vpm; + float_status fpst = *(float_status *)vst; + + set_default_nan_mode(true, &fpst); + + for (row = 0; row < oprsz; ++row) { + if (pn[H1(row)] & 1) { + uint64_t *za_row = &za[tile_vslice_index(row)]; + uint64_t n = zn[row] ^ neg; + + for (col = 0; col < oprsz; ++col) { + if (pm[H1(col)] & 1) { + uint64_t *a = &za_row[col]; + *a = float64_muladd(n, zm[col], *a, 0, &fpst); + } + } + } + } +} + +/* + * Alter PAIR as needed for controlling predicates being false, + * and for NEG on an enabled row element. + */ +static inline uint32_t f16mop_adj_pair(uint32_t pair, uint32_t pg, uint32_t neg) +{ + /* + * The pseudocode uses a conditional negate after the conditional zero. + * It is simpler here to unconditionally negate before conditional zero. + */ + pair ^= neg; + if (!(pg & 1)) { + pair &= 0xffff0000u; + } + if (!(pg & 4)) { + pair &= 0x0000ffffu; + } + return pair; +} + +static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, + float_status *s_std, float_status *s_odd) +{ + float64 e1r = float16_to_float64(e1 & 0xffff, true, s_std); + float64 e1c = float16_to_float64(e1 >> 16, true, s_std); + float64 e2r = float16_to_float64(e2 & 0xffff, true, s_std); + float64 e2c = float16_to_float64(e2 >> 16, true, s_std); + float64 t64; + float32 t32; + + /* + * The ARM pseudocode function FPDot performs both multiplies + * and the add with a single rounding operation. Emulate this + * by performing the first multiply in round-to-odd, then doing + * the second multiply as fused multiply-add, and rounding to + * float32 all in one step. + */ + t64 = float64_mul(e1r, e2r, s_odd); + t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std); + + /* This conversion is exact, because we've already rounded. */ + t32 = float64_to_float32(t64, s_std); + + /* The final accumulation step is not fused. */ + return float32_add(sum, t32, s_std); +} + +void HELPER(sme_fmopa_h)(void *vza, void *vzn, void *vzm, void *vpn, + void *vpm, void *vst, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_maxsz(desc); + uint32_t neg = simd_data(desc) * 0x80008000u; + uint16_t *pn = vpn, *pm = vpm; + float_status fpst_odd, fpst_std; + + /* + * Make a copy of float_status because this operation does not + * update the cumulative fp exception status. It also produces + * default nans. Make a second copy with round-to-odd -- see above. + */ + fpst_std = *(float_status *)vst; + set_default_nan_mode(true, &fpst_std); + fpst_odd = fpst_std; + set_float_rounding_mode(float_round_to_odd, &fpst_odd); + + for (row = 0; row < oprsz; ) { + uint16_t prow = pn[H2(row >> 4)]; + do { + void *vza_row = vza + tile_vslice_offset(row); + uint32_t n = *(uint32_t *)(vzn + H1_4(row)); + + n = f16mop_adj_pair(n, prow, neg); + + for (col = 0; col < oprsz; ) { + uint16_t pcol = pm[H2(col >> 4)]; + do { + if (prow & pcol & 0b0101) { + uint32_t *a = vza_row + H1_4(col); + uint32_t m = *(uint32_t *)(vzm + H1_4(col)); + + m = f16mop_adj_pair(m, pcol, 0); + *a = f16_dotadd(*a, n, m, &fpst_std, &fpst_odd); + + col += 4; + pcol >>= 4; + } + } while (col & 15); + } + row += 4; + prow >>= 4; + } while (row & 15); + } +} + +void HELPER(sme_bfmopa)(void *vza, void *vzn, void *vzm, void *vpn, + void *vpm, uint32_t desc) +{ + intptr_t row, col, oprsz = simd_maxsz(desc); + uint32_t neg = simd_data(desc) * 0x80008000u; + uint16_t *pn = vpn, *pm = vpm; + + for (row = 0; row < oprsz; ) { + uint16_t prow = pn[H2(row >> 4)]; + do { + void *vza_row = vza + tile_vslice_offset(row); + uint32_t n = *(uint32_t *)(vzn + H1_4(row)); + + n = f16mop_adj_pair(n, prow, neg); + + for (col = 0; col < oprsz; ) { + uint16_t pcol = pm[H2(col >> 4)]; + do { + if (prow & pcol & 0b0101) { + uint32_t *a = vza_row + H1_4(col); + uint32_t m = *(uint32_t *)(vzm + H1_4(col)); + + m = f16mop_adj_pair(m, pcol, 0); + *a = bfdotadd(*a, n, m); + + col += 4; + pcol >>= 4; + } + } while (col & 15); + } + row += 4; + prow >>= 4; + } while (row & 15); + } +} + +typedef uint64_t IMOPFn(uint64_t, uint64_t, uint64_t, uint8_t, bool); + +static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm, + uint8_t *pn, uint8_t *pm, + uint32_t desc, IMOPFn *fn) +{ + intptr_t row, col, oprsz = simd_oprsz(desc) / 8; + bool neg = simd_data(desc); + + for (row = 0; row < oprsz; ++row) { + uint8_t pa = pn[H1(row)]; + uint64_t *za_row = &za[tile_vslice_index(row)]; + uint64_t n = zn[row]; + + for (col = 0; col < oprsz; ++col) { + uint8_t pb = pm[H1(col)]; + uint64_t *a = &za_row[col]; + + *a = fn(n, zm[col], *a, pa & pb, neg); + } + } +} + +#define DEF_IMOP_32(NAME, NTYPE, MTYPE) \ +static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \ +{ \ + uint32_t sum0 = 0, sum1 = 0; \ + /* Apply P to N as a mask, making the inactive elements 0. */ \ + n &= expand_pred_b(p); \ + sum0 += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \ + sum0 += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \ + sum0 += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \ + sum0 += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \ + sum1 += (NTYPE)(n >> 32) * (MTYPE)(m >> 32); \ + sum1 += (NTYPE)(n >> 40) * (MTYPE)(m >> 40); \ + sum1 += (NTYPE)(n >> 48) * (MTYPE)(m >> 48); \ + sum1 += (NTYPE)(n >> 56) * (MTYPE)(m >> 56); \ + if (neg) { \ + sum0 = (uint32_t)a - sum0, sum1 = (uint32_t)(a >> 32) - sum1; \ + } else { \ + sum0 = (uint32_t)a + sum0, sum1 = (uint32_t)(a >> 32) + sum1; \ + } \ + return ((uint64_t)sum1 << 32) | sum0; \ +} + +#define DEF_IMOP_64(NAME, NTYPE, MTYPE) \ +static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \ +{ \ + uint64_t sum = 0; \ + /* Apply P to N as a mask, making the inactive elements 0. */ \ + n &= expand_pred_h(p); \ + sum += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \ + sum += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \ + sum += (NTYPE)(n >> 32) * (MTYPE)(m >> 32); \ + sum += (NTYPE)(n >> 48) * (MTYPE)(m >> 48); \ + return neg ? a - sum : a + sum; \ +} + +DEF_IMOP_32(smopa_s, int8_t, int8_t) +DEF_IMOP_32(umopa_s, uint8_t, uint8_t) +DEF_IMOP_32(sumopa_s, int8_t, uint8_t) +DEF_IMOP_32(usmopa_s, uint8_t, int8_t) + +DEF_IMOP_64(smopa_d, int16_t, int16_t) +DEF_IMOP_64(umopa_d, uint16_t, uint16_t) +DEF_IMOP_64(sumopa_d, int16_t, uint16_t) +DEF_IMOP_64(usmopa_d, uint16_t, int16_t) + +#define DEF_IMOPH(NAME) \ + void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, void *vpn, \ + void *vpm, uint32_t desc) \ + { do_imopa(vza, vzn, vzm, vpn, vpm, desc, NAME); } + +DEF_IMOPH(smopa_s) +DEF_IMOPH(umopa_s) +DEF_IMOPH(sumopa_s) +DEF_IMOPH(usmopa_s) +DEF_IMOPH(smopa_d) +DEF_IMOPH(umopa_d) +DEF_IMOPH(sumopa_d) +DEF_IMOPH(usmopa_d) diff --git a/target/arm/sve.decode b/target/arm/sve.decode index 0388cce3bd9a..14b3a69c364f 100644 --- a/target/arm/sve.decode +++ b/target/arm/sve.decode @@ -449,14 +449,17 @@ INDEX_ri 00000100 esz:2 1 imm:s5 010001 rn:5 rd:5 # SVE index generation (register start, register increment) INDEX_rr 00000100 .. 1 ..... 010011 ..... ..... @rd_rn_rm -### SVE Stack Allocation Group +### SVE / Streaming SVE Stack Allocation Group # SVE stack frame adjustment ADDVL 00000100 001 ..... 01010 ...... ..... @rd_rn_i6 +ADDSVL 00000100 001 ..... 01011 ...... ..... @rd_rn_i6 ADDPL 00000100 011 ..... 01010 ...... ..... @rd_rn_i6 +ADDSPL 00000100 011 ..... 01011 ...... ..... @rd_rn_i6 # SVE stack frame size RDVL 00000100 101 11111 01010 imm:s6 rd:5 +RDSVL 00000100 101 11111 01011 imm:s6 rd:5 ### SVE Bitwise Shift - Unpredicated Group @@ -528,8 +531,14 @@ DUPM 00000101 11 0000 dbm:13 rd:5 FCPY 00000101 .. 01 .... 110 imm:8 ..... @rdn_pg4 # SVE copy integer immediate (predicated) -CPY_m_i 00000101 .. 01 .... 01 . ........ ..... @rdn_pg4 imm=%sh8_i8s -CPY_z_i 00000101 .. 01 .... 00 . ........ ..... @rdn_pg4 imm=%sh8_i8s +{ + INVALID 00000101 00 01 ---- 01 1 -------- ----- + CPY_m_i 00000101 .. 01 .... 01 . ........ ..... @rdn_pg4 imm=%sh8_i8s +} +{ + INVALID 00000101 00 01 ---- 00 1 -------- ----- + CPY_z_i 00000101 .. 01 .... 00 . ........ ..... @rdn_pg4 imm=%sh8_i8s +} ### SVE Permute - Extract Group @@ -643,6 +652,7 @@ REVB 00000101 .. 1001 00 100 ... ..... ..... @rd_pg_rn REVH 00000101 .. 1001 01 100 ... ..... ..... @rd_pg_rn REVW 00000101 .. 1001 10 100 ... ..... ..... @rd_pg_rn RBIT 00000101 .. 1001 11 100 ... ..... ..... @rd_pg_rn +REVD 00000101 00 1011 10 100 ... ..... ..... @rd_pg_rn_e0 # SVE vector splice (predicated, destructive) SPLICE 00000101 .. 101 100 100 ... ..... ..... @rdn_pg_rm @@ -787,16 +797,40 @@ WHILE_ptr 00100101 esz:2 1 rm:5 001 100 rn:5 rw:1 rd:4 FDUP 00100101 esz:2 111 00 1110 imm:8 rd:5 # SVE broadcast integer immediate (unpredicated) -DUP_i 00100101 esz:2 111 00 011 . ........ rd:5 imm=%sh8_i8s +{ + INVALID 00100101 00 111 00 011 1 -------- ----- + DUP_i 00100101 esz:2 111 00 011 . ........ rd:5 imm=%sh8_i8s +} # SVE integer add/subtract immediate (unpredicated) -ADD_zzi 00100101 .. 100 000 11 . ........ ..... @rdn_sh_i8u -SUB_zzi 00100101 .. 100 001 11 . ........ ..... @rdn_sh_i8u -SUBR_zzi 00100101 .. 100 011 11 . ........ ..... @rdn_sh_i8u -SQADD_zzi 00100101 .. 100 100 11 . ........ ..... @rdn_sh_i8u -UQADD_zzi 00100101 .. 100 101 11 . ........ ..... @rdn_sh_i8u -SQSUB_zzi 00100101 .. 100 110 11 . ........ ..... @rdn_sh_i8u -UQSUB_zzi 00100101 .. 100 111 11 . ........ ..... @rdn_sh_i8u +{ + INVALID 00100101 00 100 000 11 1 -------- ----- + ADD_zzi 00100101 .. 100 000 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 001 11 1 -------- ----- + SUB_zzi 00100101 .. 100 001 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 011 11 1 -------- ----- + SUBR_zzi 00100101 .. 100 011 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 100 11 1 -------- ----- + SQADD_zzi 00100101 .. 100 100 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 101 11 1 -------- ----- + UQADD_zzi 00100101 .. 100 101 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 110 11 1 -------- ----- + SQSUB_zzi 00100101 .. 100 110 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 111 11 1 -------- ----- + UQSUB_zzi 00100101 .. 100 111 11 . ........ ..... @rdn_sh_i8u +} # SVE integer min/max immediate (unpredicated) SMAX_zzi 00100101 .. 101 000 110 ........ ..... @rdn_i8s @@ -1153,10 +1187,10 @@ LD1RO_zpri 1010010 .. 01 0.... 001 ... ..... ..... \ @rpri_load_msz nreg=0 # SVE 32-bit gather prefetch (scalar plus 32-bit scaled offsets) -PRF 1000010 00 -1 ----- 0-- --- ----- 0 ---- +PRF_ns 1000010 00 -1 ----- 0-- --- ----- 0 ---- # SVE 32-bit gather prefetch (vector plus immediate) -PRF 1000010 -- 00 ----- 111 --- ----- 0 ---- +PRF_ns 1000010 -- 00 ----- 111 --- ----- 0 ---- # SVE contiguous prefetch (scalar plus immediate) PRF 1000010 11 1- ----- 0-- --- ----- 0 ---- @@ -1193,13 +1227,13 @@ LD1_zpiz 1100010 .. 01 ..... 1.. ... ..... ..... \ @rpri_g_load esz=3 # SVE 64-bit gather prefetch (scalar plus 64-bit scaled offsets) -PRF 1100010 00 11 ----- 1-- --- ----- 0 ---- +PRF_ns 1100010 00 11 ----- 1-- --- ----- 0 ---- # SVE 64-bit gather prefetch (scalar plus unpacked 32-bit scaled offsets) -PRF 1100010 00 -1 ----- 0-- --- ----- 0 ---- +PRF_ns 1100010 00 -1 ----- 0-- --- ----- 0 ---- # SVE 64-bit gather prefetch (vector plus immediate) -PRF 1100010 -- 00 ----- 111 --- ----- 0 ---- +PRF_ns 1100010 -- 00 ----- 111 --- ----- 0 ---- ### SVE Memory Store Group @@ -1568,10 +1602,9 @@ SQRDCMLAH_zzzz 01000100 esz:2 0 rm:5 0011 rot:2 rn:5 rd:5 ra=%reg_movprfx USDOT_zzzz 01000100 .. 0 ..... 011 110 ..... ..... @rda_rn_rm ### SVE2 floating point matrix multiply accumulate -{ - BFMMLA 01100100 01 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 - FMMLA 01100100 .. 1 ..... 111 001 ..... ..... @rda_rn_rm -} +BFMMLA 01100100 01 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 +FMMLA_s 01100100 10 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 +FMMLA_d 01100100 11 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 ### SVE2 Memory Gather Load Group @@ -1642,3 +1675,28 @@ BFMLALT_zzxw 01100100 11 1 ..... 0100.1 ..... ..... @rrxr_3a esz=2 ### SVE2 floating-point bfloat16 dot-product (indexed) BFDOT_zzxz 01100100 01 1 ..... 010000 ..... ..... @rrxr_2 esz=2 + +### SVE broadcast predicate element + +&psel esz pd pn pm rv imm +%psel_rv 16:2 !function=plus_12 +%psel_imm_b 22:2 19:2 +%psel_imm_h 22:2 20:1 +%psel_imm_s 22:2 +%psel_imm_d 23:1 +@psel ........ .. . ... .. .. pn:4 . pm:4 . pd:4 \ + &psel rv=%psel_rv + +PSEL 00100101 .. 1 ..1 .. 01 .... 0 .... 0 .... \ + @psel esz=0 imm=%psel_imm_b +PSEL 00100101 .. 1 .10 .. 01 .... 0 .... 0 .... \ + @psel esz=1 imm=%psel_imm_h +PSEL 00100101 .. 1 100 .. 01 .... 0 .... 0 .... \ + @psel esz=2 imm=%psel_imm_s +PSEL 00100101 .1 1 000 .. 01 .... 0 .... 0 .... \ + @psel esz=3 imm=%psel_imm_d + +### SVE clamp + +SCLAMP 01000100 .. 0 ..... 110000 ..... ..... @rda_rn_rm +UCLAMP 01000100 .. 0 ..... 110001 ..... ..... @rda_rn_rm diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index d45d0886159f..521fc9b96976 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -21,12 +21,12 @@ #include "cpu.h" #include "internals.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" #include "tcg/tcg.h" #include "vec_internal.h" +#include "sve_ldst_internal.h" /* Return a value for NZCV as per the ARM PredTest pseudofunction. @@ -103,44 +103,6 @@ uint32_t HELPER(sve_predtest)(void *vd, void *vg, uint32_t words) return flags; } -/* - * Expand active predicate bits to bytes, for byte elements. - * (The data table itself is in vec_helper.c as MVE also needs it.) - */ -static inline uint64_t expand_pred_b(uint8_t byte) -{ - return expand_pred_b_data[byte]; -} - -/* Similarly for half-word elements. - * for (i = 0; i < 256; ++i) { - * unsigned long m = 0; - * if (i & 0xaa) { - * continue; - * } - * for (j = 0; j < 8; j += 2) { - * if ((i >> j) & 1) { - * m |= 0xfffful << (j << 3); - * } - * } - * printf("[0x%x] = 0x%016lx,\n", i, m); - * } - */ -static inline uint64_t expand_pred_h(uint8_t byte) -{ - static const uint64_t word[] = { - [0x01] = 0x000000000000ffff, [0x04] = 0x00000000ffff0000, - [0x05] = 0x00000000ffffffff, [0x10] = 0x0000ffff00000000, - [0x11] = 0x0000ffff0000ffff, [0x14] = 0x0000ffffffff0000, - [0x15] = 0x0000ffffffffffff, [0x40] = 0xffff000000000000, - [0x41] = 0xffff00000000ffff, [0x44] = 0xffff0000ffff0000, - [0x45] = 0xffff0000ffffffff, [0x50] = 0xffffffff00000000, - [0x51] = 0xffffffff0000ffff, [0x54] = 0xffffffffffff0000, - [0x55] = 0xffffffffffffffff, - }; - return word[byte & 0x55]; -} - /* Similarly for single word elements. */ static inline uint64_t expand_pred_s(uint8_t byte) { @@ -969,6 +931,22 @@ DO_ZPZ_D(sve_revh_d, uint64_t, hswap64) DO_ZPZ_D(sve_revw_d, uint64_t, wswap64) +void HELPER(sme_revd_q)(void *vd, void *vn, void *vg, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc) / 8; + uint64_t *d = vd, *n = vn; + uint8_t *pg = vg; + + for (i = 0; i < opr_sz; i += 2) { + if (pg[H1(i)] & 1) { + uint64_t n0 = n[i + 0]; + uint64_t n1 = n[i + 1]; + d[i + 0] = n1; + d[i + 1] = n0; + } + } +} + DO_ZPZ(sve_rbit_b, uint8_t, H1, revbit8) DO_ZPZ(sve_rbit_h, uint16_t, H1_2, revbit16) DO_ZPZ(sve_rbit_s, uint32_t, H1_4, revbit32) @@ -2802,7 +2780,7 @@ static void swap_memmove(void *vd, void *vs, size_t n) uintptr_t o = (d | s | n) & 7; size_t i; -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN o = 0; #endif switch (o) { @@ -2864,7 +2842,7 @@ static void swap_memzero(void *vd, size_t n) return; } -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN o = 0; #endif switch (o) { @@ -3382,19 +3360,21 @@ void HELPER(sve_punpk_p)(void *vd, void *vn, uint32_t pred_desc) void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ { \ intptr_t oprsz = simd_oprsz(desc); \ + intptr_t odd_ofs = simd_data(desc); \ intptr_t i, oprsz_2 = oprsz / 2; \ ARMVectorReg tmp_n, tmp_m; \ /* We produce output faster than we consume input. \ Therefore we must be mindful of possible overlap. */ \ if (unlikely((vn - vd) < (uintptr_t)oprsz)) { \ - vn = memcpy(&tmp_n, vn, oprsz_2); \ + vn = memcpy(&tmp_n, vn, oprsz); \ } \ if (unlikely((vm - vd) < (uintptr_t)oprsz)) { \ - vm = memcpy(&tmp_m, vm, oprsz_2); \ + vm = memcpy(&tmp_m, vm, oprsz); \ } \ for (i = 0; i < oprsz_2; i += sizeof(TYPE)) { \ - *(TYPE *)(vd + H(2 * i + 0)) = *(TYPE *)(vn + H(i)); \ - *(TYPE *)(vd + H(2 * i + sizeof(TYPE))) = *(TYPE *)(vm + H(i)); \ + *(TYPE *)(vd + H(2 * i + 0)) = *(TYPE *)(vn + odd_ofs + H(i)); \ + *(TYPE *)(vd + H(2 * i + sizeof(TYPE))) = \ + *(TYPE *)(vm + odd_ofs + H(i)); \ } \ if (sizeof(TYPE) == 16 && unlikely(oprsz & 16)) { \ memset(vd + oprsz - 16, 0, 16); \ @@ -3601,6 +3581,18 @@ void HELPER(sve_sel_zpzz_d)(void *vd, void *vn, void *vm, } } +void HELPER(sve_sel_zpzz_q)(void *vd, void *vn, void *vm, + void *vg, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc) / 16; + Int128 *d = vd, *n = vn, *m = vm; + uint16_t *pg = vg; + + for (i = 0; i < opr_sz; i += 1) { + d[i] = (pg[H2(i)] & 1 ? n : m)[i]; + } +} + /* Two operand comparison controlled by a predicate. * ??? It is very tempting to want to be able to expand this inline * with x86 instructions, e.g. @@ -5299,111 +5291,6 @@ void HELPER(sve_fcmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va, * Load contiguous data, protected by a governing predicate. */ -/* - * Load one element into @vd + @reg_off from @host. - * The controlling predicate is known to be true. - */ -typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host); - -/* - * Load one element into @vd + @reg_off from (@env, @vaddr, @ra). - * The controlling predicate is known to be true. - */ -typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, - target_ulong vaddr, uintptr_t retaddr); - -/* - * Generate the above primitives. - */ - -#define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \ -static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ -{ \ - TYPEM val = HOST(host); \ - *(TYPEE *)(vd + H(reg_off)) = val; \ -} - -#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \ -static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ -{ HOST(host, (TYPEM)*(TYPEE *)(vd + H(reg_off))); } - -#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ -static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, uintptr_t ra) \ -{ \ - *(TYPEE *)(vd + H(reg_off)) = \ - (TYPEM)TLB(env, useronly_clean_ptr(addr), ra); \ -} - -#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \ -static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, uintptr_t ra) \ -{ \ - TLB(env, useronly_clean_ptr(addr), \ - (TYPEM)*(TYPEE *)(vd + H(reg_off)), ra); \ -} - -#define DO_LD_PRIM_1(NAME, H, TE, TM) \ - DO_LD_HOST(NAME, H, TE, TM, ldub_p) \ - DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra) - -DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t) -DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t) -DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t, int8_t) -DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t) -DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t) -DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t) -DO_LD_PRIM_1(ld1bds, H1_8, uint64_t, int8_t) - -#define DO_ST_PRIM_1(NAME, H, TE, TM) \ - DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \ - DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra) - -DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t) -DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t) -DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t) -DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t) - -#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \ - DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \ - DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \ - DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \ - DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra) - -#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \ - DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \ - DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \ - DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \ - DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra) - -DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw) -DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw) -DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw) -DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw) -DO_LD_PRIM_2(hds, H1_8, uint64_t, int16_t, lduw) - -DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw) -DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw) -DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw) - -DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl) -DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl) -DO_LD_PRIM_2(sds, H1_8, uint64_t, int32_t, ldl) - -DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl) -DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl) - -DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq) -DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq) - -#undef DO_LD_TLB -#undef DO_ST_TLB -#undef DO_LD_HOST -#undef DO_LD_PRIM_1 -#undef DO_ST_PRIM_1 -#undef DO_LD_PRIM_2 -#undef DO_ST_PRIM_2 - /* * Skip through a sequence of inactive elements in the guarding predicate @vg, * beginning at @reg_off bounded by @reg_max. Return the offset of the active @@ -5444,16 +5331,9 @@ static intptr_t find_next_active(uint64_t *vg, intptr_t reg_off, * exit via page fault exception. */ -typedef struct { - void *host; - int flags; - MemTxAttrs attrs; -} SVEHostPage; - -static bool sve_probe_page(SVEHostPage *info, bool nofault, - CPUARMState *env, target_ulong addr, - int mem_off, MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) +bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env, + target_ulong addr, int mem_off, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) { int flags; @@ -5471,8 +5351,14 @@ static bool sve_probe_page(SVEHostPage *info, bool nofault, */ addr = useronly_clean_ptr(addr); +#ifdef CONFIG_USER_ONLY flags = probe_access_flags(env, addr, access_type, mmu_idx, nofault, &info->host, retaddr); +#else + CPUTLBEntryFull *full; + flags = probe_access_full(env, addr, access_type, mmu_idx, nofault, + &info->host, &full, retaddr); +#endif info->flags = flags; if (flags & TLB_INVALID_MASK) { @@ -5480,88 +5366,27 @@ static bool sve_probe_page(SVEHostPage *info, bool nofault, return false; } - /* Ensure that info->host[] is relative to addr, not addr + mem_off. */ - info->host -= mem_off; - #ifdef CONFIG_USER_ONLY memset(&info->attrs, 0, sizeof(info->attrs)); + /* Require both ANON and MTE; see allocation_tag_mem(). */ + info->tagged = (flags & PAGE_ANON) && (flags & PAGE_MTE); #else - /* - * Find the iotlbentry for addr and return the transaction attributes. - * This *must* be present in the TLB because we just found the mapping. - */ - { - uintptr_t index = tlb_index(env, mmu_idx, addr); - -# ifdef CONFIG_DEBUG_TCG - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong comparator = (access_type == MMU_DATA_LOAD - ? entry->addr_read - : tlb_addr_write(entry)); - g_assert(tlb_hit(comparator, addr)); -# endif - - CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; - info->attrs = iotlbentry->attrs; - } + info->attrs = full->attrs; + info->tagged = full->pte_attrs == 0xf0; #endif + /* Ensure that info->host[] is relative to addr, not addr + mem_off. */ + info->host -= mem_off; return true; } - -/* - * Analyse contiguous data, protected by a governing predicate. - */ - -typedef enum { - FAULT_NO, - FAULT_FIRST, - FAULT_ALL, -} SVEContFault; - -typedef struct { - /* - * First and last element wholly contained within the two pages. - * mem_off_first[0] and reg_off_first[0] are always set >= 0. - * reg_off_last[0] may be < 0 if the first element crosses pages. - * All of mem_off_first[1], reg_off_first[1] and reg_off_last[1] - * are set >= 0 only if there are complete elements on a second page. - * - * The reg_off_* offsets are relative to the internal vector register. - * The mem_off_first offset is relative to the memory address; the - * two offsets are different when a load operation extends, a store - * operation truncates, or for multi-register operations. - */ - int16_t mem_off_first[2]; - int16_t reg_off_first[2]; - int16_t reg_off_last[2]; - - /* - * One element that is misaligned and spans both pages, - * or -1 if there is no such active element. - */ - int16_t mem_off_split; - int16_t reg_off_split; - - /* - * The byte offset at which the entire operation crosses a page boundary. - * Set >= 0 if and only if the entire operation spans two pages. - */ - int16_t page_split; - - /* TLB data for the two pages. */ - SVEHostPage page[2]; -} SVEContLdSt; - /* * Find first active element on each page, and a loose bound for the * final element on each page. Identify any single element that spans * the page boundary. Return true if there are any active elements. */ -static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, - uint64_t *vg, intptr_t reg_max, - int esz, int msize) +bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, + intptr_t reg_max, int esz, int msize) { const int esize = 1 << esz; const uint64_t pg_mask = pred_esz_masks[esz]; @@ -5651,9 +5476,9 @@ static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, * Control the generation of page faults with @fault. Return false if * there is no work to do, which can only happen with @fault == FAULT_NO. */ -static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, - CPUARMState *env, target_ulong addr, - MMUAccessType access_type, uintptr_t retaddr) +bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, + CPUARMState *env, target_ulong addr, + MMUAccessType access_type, uintptr_t retaddr) { int mmu_idx = cpu_mmu_index(env, false); int mem_off = info->mem_off_first[0]; @@ -5709,12 +5534,12 @@ static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, return have_work; } -static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, - int esize, int msize, int wp_access, - uintptr_t retaddr) -{ #ifndef CONFIG_USER_ONLY +void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, int wp_access, + uintptr_t retaddr) +{ intptr_t mem_off, reg_off, reg_last; int flags0 = info->page[0].flags; int flags1 = info->page[1].flags; @@ -5770,17 +5595,17 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, } while (reg_off & 63); } while (reg_off <= reg_last); } -#endif } +#endif -static void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, int esize, - int msize, uint32_t mtedesc, uintptr_t ra) +void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, int esize, + int msize, uint32_t mtedesc, uintptr_t ra) { intptr_t mem_off, reg_off, reg_last; /* Process the page only if MemAttr == Tagged. */ - if (arm_tlb_mte_tagged(&info->page[0].attrs)) { + if (info->page[0].tagged) { mem_off = info->mem_off_first[0]; reg_off = info->reg_off_first[0]; reg_last = info->reg_off_split; @@ -5801,7 +5626,7 @@ static void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, } mem_off = info->mem_off_first[1]; - if (mem_off >= 0 && arm_tlb_mte_tagged(&info->page[1].attrs)) { + if (mem_off >= 0 && info->page[1].tagged) { reg_off = info->reg_off_first[1]; reg_last = info->reg_off_last[1]; @@ -6180,7 +6005,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, * Disable MTE checking if the Tagged bit is not set. Since TBI must * be set within MTEDESC for MTE, !mtedesc => !mte_active. */ - if (arm_tlb_mte_tagged(&info.page[0].attrs)) { + if (!info.page[0].tagged) { mtedesc = 0; } @@ -6731,7 +6556,7 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, cpu_check_watchpoint(env_cpu(env), addr, msize, info.attrs, BP_MEM_READ, retaddr); } - if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { + if (mtedesc && info.tagged) { mte_check(env, mtedesc, addr, retaddr); } if (unlikely(info.flags & TLB_MMIO)) { @@ -6748,7 +6573,7 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, msize, info.attrs, BP_MEM_READ, retaddr); } - if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { + if (mtedesc && info.tagged) { mte_check(env, mtedesc, addr, retaddr); } tlb_fn(env, &scratch, reg_off, addr, retaddr); @@ -6949,9 +6774,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, (env_cpu(env), addr, msize) & BP_MEM_READ)) { goto fault; } - if (mtedesc && - arm_tlb_mte_tagged(&info.attrs) && - !mte_probe(env, mtedesc, addr)) { + if (mtedesc && info.tagged && !mte_probe(env, mtedesc, addr)) { goto fault; } @@ -7137,7 +6960,7 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, info.attrs, BP_MEM_WRITE, retaddr); } - if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { + if (mtedesc && info.tagged) { mte_check(env, mtedesc, addr, retaddr); } } diff --git a/target/arm/sve_ldst_internal.h b/target/arm/sve_ldst_internal.h new file mode 100644 index 000000000000..4f159ec4adfc --- /dev/null +++ b/target/arm/sve_ldst_internal.h @@ -0,0 +1,222 @@ +/* + * ARM SVE Load/Store Helpers + * + * Copyright (c) 2018-2022 Linaro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.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 TARGET_ARM_SVE_LDST_INTERNAL_H +#define TARGET_ARM_SVE_LDST_INTERNAL_H + +#include "exec/cpu_ldst.h" + +/* + * Load one element into @vd + @reg_off from @host. + * The controlling predicate is known to be true. + */ +typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host); + +/* + * Load one element into @vd + @reg_off from (@env, @vaddr, @ra). + * The controlling predicate is known to be true. + */ +typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, + target_ulong vaddr, uintptr_t retaddr); + +/* + * Generate the above primitives. + */ + +#define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \ +static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ +{ TYPEM val = HOST(host); *(TYPEE *)(vd + H(reg_off)) = val; } + +#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \ +static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ +{ TYPEM val = *(TYPEE *)(vd + H(reg_off)); HOST(host, val); } + +#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ +static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd, \ + intptr_t reg_off, target_ulong addr, uintptr_t ra) \ +{ \ + TYPEM val = TLB(env, useronly_clean_ptr(addr), ra); \ + *(TYPEE *)(vd + H(reg_off)) = val; \ +} + +#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \ +static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd, \ + intptr_t reg_off, target_ulong addr, uintptr_t ra) \ +{ \ + TYPEM val = *(TYPEE *)(vd + H(reg_off)); \ + TLB(env, useronly_clean_ptr(addr), val, ra); \ +} + +#define DO_LD_PRIM_1(NAME, H, TE, TM) \ + DO_LD_HOST(NAME, H, TE, TM, ldub_p) \ + DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra) + +DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t) +DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t) +DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t, int8_t) +DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t) +DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t) +DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t) +DO_LD_PRIM_1(ld1bds, H1_8, uint64_t, int8_t) + +#define DO_ST_PRIM_1(NAME, H, TE, TM) \ + DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \ + DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra) + +DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t) +DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t) +DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t) +DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t) + +#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \ + DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \ + DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \ + DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \ + DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra) + +#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \ + DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \ + DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \ + DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \ + DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra) + +DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw) +DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw) +DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw) +DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw) +DO_LD_PRIM_2(hds, H1_8, uint64_t, int16_t, lduw) + +DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw) +DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw) +DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw) + +DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl) +DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl) +DO_LD_PRIM_2(sds, H1_8, uint64_t, int32_t, ldl) + +DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl) +DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl) + +DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq) +DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq) + +#undef DO_LD_TLB +#undef DO_ST_TLB +#undef DO_LD_HOST +#undef DO_LD_PRIM_1 +#undef DO_ST_PRIM_1 +#undef DO_LD_PRIM_2 +#undef DO_ST_PRIM_2 + +/* + * Resolve the guest virtual address to info->host and info->flags. + * If @nofault, return false if the page is invalid, otherwise + * exit via page fault exception. + */ + +typedef struct { + void *host; + int flags; + MemTxAttrs attrs; + bool tagged; +} SVEHostPage; + +bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env, + target_ulong addr, int mem_off, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); + +/* + * Analyse contiguous data, protected by a governing predicate. + */ + +typedef enum { + FAULT_NO, + FAULT_FIRST, + FAULT_ALL, +} SVEContFault; + +typedef struct { + /* + * First and last element wholly contained within the two pages. + * mem_off_first[0] and reg_off_first[0] are always set >= 0. + * reg_off_last[0] may be < 0 if the first element crosses pages. + * All of mem_off_first[1], reg_off_first[1] and reg_off_last[1] + * are set >= 0 only if there are complete elements on a second page. + * + * The reg_off_* offsets are relative to the internal vector register. + * The mem_off_first offset is relative to the memory address; the + * two offsets are different when a load operation extends, a store + * operation truncates, or for multi-register operations. + */ + int16_t mem_off_first[2]; + int16_t reg_off_first[2]; + int16_t reg_off_last[2]; + + /* + * One element that is misaligned and spans both pages, + * or -1 if there is no such active element. + */ + int16_t mem_off_split; + int16_t reg_off_split; + + /* + * The byte offset at which the entire operation crosses a page boundary. + * Set >= 0 if and only if the entire operation spans two pages. + */ + int16_t page_split; + + /* TLB data for the two pages. */ + SVEHostPage page[2]; +} SVEContLdSt; + +/* + * Find first active element on each page, and a loose bound for the + * final element on each page. Identify any single element that spans + * the page boundary. Return true if there are any active elements. + */ +bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, + intptr_t reg_max, int esz, int msize); + +/* + * Resolve the guest virtual addresses to info->page[]. + * Control the generation of page faults with @fault. Return false if + * there is no work to do, which can only happen with @fault == FAULT_NO. + */ +bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, + CPUARMState *env, target_ulong addr, + MMUAccessType access_type, uintptr_t retaddr); + +#ifdef CONFIG_USER_ONLY +static inline void +sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, uint64_t *vg, + target_ulong addr, int esize, int msize, + int wp_access, uintptr_t retaddr) +{ } +#else +void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, int wp_access, + uintptr_t retaddr); +#endif + +void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, uint64_t *vg, + target_ulong addr, int esize, int msize, + uint32_t mtedesc, uintptr_t ra); + +#endif /* TARGET_ARM_SVE_LDST_INTERNAL_H */ diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index 8cde8e7243ae..73df5e379386 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -48,6 +48,7 @@ enum arm_exception_class { EC_AA64_SMC = 0x17, EC_SYSTEMREGISTERTRAP = 0x18, EC_SVEACCESSTRAP = 0x19, + EC_SMETRAP = 0x1d, EC_INSNABORT = 0x20, EC_INSNABORT_SAME_EL = 0x21, EC_PCALIGNMENT = 0x22, @@ -68,6 +69,13 @@ enum arm_exception_class { EC_AA64_BKPT = 0x3c, }; +typedef enum { + SME_ET_AccessTrap, + SME_ET_Streaming, + SME_ET_NotStreaming, + SME_ET_InactiveZA, +} SMEExceptionType; + #define ARM_EL_EC_SHIFT 26 #define ARM_EL_IL_SHIFT 25 #define ARM_EL_ISV_SHIFT 24 @@ -185,12 +193,13 @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm, | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; } -static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit) +static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit, + int coproc) { - /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 coproc == 0xa */ + /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */ return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT) | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | 0xa; + | (cv << 24) | (cond << 20) | coproc; } static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit) @@ -206,6 +215,12 @@ static inline uint32_t syn_sve_access_trap(void) return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT; } +static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) +{ + return (EC_SMETRAP << ARM_EL_EC_SHIFT) + | (is_16bit ? 0 : ARM_EL_IL) | etype; +} + static inline uint32_t syn_pactrap(void) { return EC_PACTRAP << ARM_EL_EC_SHIFT; @@ -287,4 +302,9 @@ static inline uint32_t syn_pcalignment(void) return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; } +static inline uint32_t syn_serror(uint32_t extra) +{ + return (EC_SERROR << ARM_EL_EC_SHIFT) | ARM_EL_IL | extra; +} + #endif /* TARGET_ARM_SYNDROME_H */ diff --git a/target/arm/t32.decode b/target/arm/t32.decode index 78fadef9d621..f21ad0167ab9 100644 --- a/target/arm/t32.decode +++ b/target/arm/t32.decode @@ -364,17 +364,17 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm [ # Hints, and CPS { - YIELD 1111 0011 1010 1111 1000 0000 0000 0001 - WFE 1111 0011 1010 1111 1000 0000 0000 0010 - WFI 1111 0011 1010 1111 1000 0000 0000 0011 + [ + YIELD 1111 0011 1010 1111 1000 0000 0000 0001 + WFE 1111 0011 1010 1111 1000 0000 0000 0010 + WFI 1111 0011 1010 1111 1000 0000 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV 1111 0011 1010 1111 1000 0000 0000 0100 - # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV 1111 0011 1010 1111 1000 0000 0000 0100 + # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 - # For M-profile minimal-RAS ESB can be a NOP, which is the - # default behaviour since it is in the hint space. - # ESB 1111 0011 1010 1111 1000 0000 0001 0000 + ESB 1111 0011 1010 1111 1000 0000 0001 0000 + ] # The canonical nop ends in 0000 0000, but the whole rest # of the space is "reserved hint, behaves as nop". diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index b79004e0cca6..60abcbebe648 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -11,6 +11,36 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" + +/* Return true if the translation regime is using LPAE format page tables */ +bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + int el = regime_el(env, mmu_idx); + if (el == 2 || arm_el_is_aa64(env, el)) { + return true; + } + if (arm_feature(env, ARM_FEATURE_PMSA) && + arm_feature(env, ARM_FEATURE_V8)) { + return true; + } + if (arm_feature(env, ARM_FEATURE_LPAE) + && (regime_tcr(env, mmu_idx) & TTBCR_EAE)) { + return true; + } + return false; +} + +/* + * Returns true if the stage 1 translation regime is using LPAE format page + * tables. Used when raising alignment exceptions, whose FSR changes depending + * on whether the long or short descriptor format is in use. + */ +bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + mmu_idx = stage_1_mmu_idx(mmu_idx); + return regime_using_lpae_format(env, mmu_idx); +} + static inline uint32_t merge_syn_data_abort(uint32_t template_syn, unsigned int target_el, bool same_el, bool ea, @@ -79,9 +109,10 @@ static uint32_t compute_fsr_fsc(CPUARMState *env, ARMMMUFaultInfo *fi, return fsr; } -static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, ARMMMUFaultInfo *fi) +static G_NORETURN +void arm_deliver_fault(ARMCPU *cpu, vaddr addr, + MMUAccessType access_type, + int mmu_idx, ARMMMUFaultInfo *fi) { CPUARMState *env = &cpu->env; int target_el; @@ -129,7 +160,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, ARMMMUFaultInfo fi = {}; /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); fi.type = ARMFault_Alignment; arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); @@ -169,7 +200,7 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, ARMMMUFaultInfo fi = {}; /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); fi.ea = arm_extabort_type(response); fi.type = ARMFault_SyncExternal; @@ -181,12 +212,20 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, bool probe, uintptr_t retaddr) { ARMCPU *cpu = ARM_CPU(cs); - ARMMMUFaultInfo fi = {}; - hwaddr phys_addr; - target_ulong page_size; - int prot, ret; - MemTxAttrs attrs = {}; - ARMCacheAttrs cacheattrs = {}; + GetPhysAddrResult res = {}; + ARMMMUFaultInfo local_fi, *fi; + int ret; + + /* + * Allow S1_ptw_translate to see any fault generated here. + * Since this may recurse, read and clear. + */ + fi = cpu->env.tlb_fi; + if (fi) { + cpu->env.tlb_fi = NULL; + } else { + fi = memset(&local_fi, 0, sizeof(local_fi)); + } /* * Walk the page table and (if the mapping exists) add the page @@ -196,32 +235,29 @@ 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; - } - tlb_set_page_with_attrs(cs, address, phys_addr, attrs, - prot, mmu_idx, page_size); + res.f.pte_attrs = res.cacheattrs.attrs; + res.f.shareability = res.cacheattrs.shareability; + + tlb_set_page_full(cs, mmu_idx, address, &res.f); return true; } else if (probe) { return false; } else { /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr, true); - arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi); + cpu_restore_state(cs, retaddr); + arm_deliver_fault(cpu, address, access_type, mmu_idx, fi); } } #else @@ -239,7 +275,7 @@ void arm_cpu_record_sigsegv(CPUState *cs, vaddr addr, * We report both ESR and FAR to signal handlers. * For now, it's easiest to deliver the fault normally. */ - cpu_restore_state(cs, ra, true); + cpu_restore_state(cs, ra); arm_deliver_fault(cpu, addr, access_type, MMU_USER_IDX, &fi); } diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 5be4b9b8346b..5339c22f1e03 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -17,8 +17,8 @@ * License along with this library; if not, see . */ -#ifndef TARGET_ARM_TRANSLATE_A64_H -#define TARGET_ARM_TRANSLATE_A64_H +#ifndef TARGET_ARM_TRANSLATE_A32_H +#define TARGET_ARM_TRANSLATE_A32_H /* Prototypes for autogenerated disassembler functions */ bool disas_m_nocp(DisasContext *dc, uint32_t insn); @@ -40,7 +40,7 @@ void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop); TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs); void gen_set_cpsr(TCGv_i32 var, uint32_t mask); void gen_set_condexec(DisasContext *s); -void gen_set_pc_im(DisasContext *s, target_ulong val); +void gen_update_pc(DisasContext *s, target_long diff); void gen_lookup_tb(DisasContext *s); long vfp_reg_offset(bool dp, unsigned reg); long neon_full_reg_offset(unsigned reg); @@ -61,17 +61,14 @@ static inline TCGv_i32 load_cpu_offset(int offset) #define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) -static inline void store_cpu_offset(TCGv_i32 var, int offset) -{ - tcg_gen_st_i32(var, cpu_env, offset); - tcg_temp_free_i32(var); -} +void store_cpu_offset(TCGv_i32 var, int offset, int size); -#define store_cpu_field(var, name) \ - store_cpu_offset(var, offsetof(CPUARMState, name)) +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUARMState, name), \ + sizeof_field(CPUARMState, name)) #define store_cpu_field_constant(val, name) \ - tcg_gen_st_i32(tcg_constant_i32(val), cpu_env, offsetof(CPUARMState, name)) + store_cpu_field(tcg_constant_i32(val), name) /* Create a new temporary and set it to the value of a CPU register. */ static inline TCGv_i32 load_reg(DisasContext *s, int reg) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 9333d7be41aa..2ee171f249ca 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -27,14 +27,12 @@ #include "translate.h" #include "internals.h" #include "qemu/host-utils.h" - #include "semihosting/semihost.h" #include "exec/gen-icount.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "exec/log.h" - +#include "cpregs.h" #include "translate-a64.h" #include "qemu/atomic128.h" @@ -113,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(); } @@ -128,32 +118,42 @@ static int get_a64_user_mem_index(DisasContext *s) return arm_to_core_mmu_idx(useridx); } -static void reset_btype(DisasContext *s) +static void set_btype_raw(int val) { - if (s->btype != 0) { - TCGv_i32 zero = tcg_const_i32(0); - tcg_gen_st_i32(zero, cpu_env, offsetof(CPUARMState, btype)); - tcg_temp_free_i32(zero); - s->btype = 0; - } + tcg_gen_st_i32(tcg_constant_i32(val), cpu_env, + offsetof(CPUARMState, btype)); } static void set_btype(DisasContext *s, int val) { - TCGv_i32 tcg_val; - /* BTYPE is a 2-bit field, and 0 should be done with reset_btype. */ tcg_debug_assert(val >= 1 && val <= 3); - - tcg_val = tcg_const_i32(val); - tcg_gen_st_i32(tcg_val, cpu_env, offsetof(CPUARMState, btype)); - tcg_temp_free_i32(tcg_val); + set_btype_raw(val); s->btype = -1; } -void gen_a64_set_pc_im(uint64_t val) +static void reset_btype(DisasContext *s) +{ + if (s->btype != 0) { + set_btype_raw(0); + s->btype = 0; + } +} + +static void gen_pc_plus_diff(DisasContext *s, TCGv_i64 dest, target_long diff) { - tcg_gen_movi_i64(cpu_pc, val); + assert(s->pc_save != -1); + if (TARGET_TB_PCREL) { + tcg_gen_addi_i64(dest, cpu_pc, (s->pc_curr - s->pc_save) + diff); + } else { + tcg_gen_movi_i64(dest, s->pc_curr + diff); + } +} + +void gen_a64_update_pc(DisasContext *s, target_long diff) +{ + gen_pc_plus_diff(s, cpu_pc, diff); + s->pc_save = s->pc_curr + diff; } /* @@ -207,6 +207,7 @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src) * then loading an address into the PC will clear out any tag. */ gen_top_byte_ignore(s, cpu_pc, src, s->tbii); + s->pc_save = -1; } /* @@ -241,14 +242,10 @@ static void gen_address_with_allocation_tag0(TCGv_i64 dst, TCGv_i64 src) static void gen_probe_access(DisasContext *s, TCGv_i64 ptr, MMUAccessType acc, int log2_size) { - TCGv_i32 t_acc = tcg_const_i32(acc); - TCGv_i32 t_idx = tcg_const_i32(get_mem_index(s)); - TCGv_i32 t_size = tcg_const_i32(1 << log2_size); - - gen_helper_probe_access(cpu_env, ptr, t_acc, t_idx, t_size); - tcg_temp_free_i32(t_acc); - tcg_temp_free_i32(t_idx); - tcg_temp_free_i32(t_size); + gen_helper_probe_access(cpu_env, ptr, + tcg_constant_i32(acc), + tcg_constant_i32(get_mem_index(s)), + tcg_constant_i32(1 << log2_size)); } /* @@ -263,7 +260,6 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, int core_idx) { if (tag_checked && s->mte_active[is_unpriv]) { - TCGv_i32 tcg_desc; TCGv_i64 ret; int desc = 0; @@ -272,11 +268,9 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << log2_size) - 1); - tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); - gen_helper_mte_check(ret, cpu_env, tcg_desc, addr); - tcg_temp_free_i32(tcg_desc); + gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr); return ret; } @@ -297,7 +291,6 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, bool tag_checked, int size) { if (tag_checked && s->mte_active[0]) { - TCGv_i32 tcg_desc; TCGv_i64 ret; int desc = 0; @@ -306,11 +299,9 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); desc = FIELD_DP32(desc, MTEDESC, SIZEM1, size - 1); - tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); - gen_helper_mte_check(ret, cpu_env, tcg_desc, addr); - tcg_temp_free_i32(tcg_desc); + gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr); return ret; } @@ -342,30 +333,28 @@ static void a64_free_cc(DisasCompare64 *c64) tcg_temp_free_i64(c64->value); } -static void gen_exception_internal(int excp) +static void gen_rebuild_hflags(DisasContext *s) { - TCGv_i32 tcg_excp = tcg_const_i32(excp); + gen_helper_rebuild_hflags_a64(cpu_env, tcg_constant_i32(s->current_el)); +} +static void gen_exception_internal(int excp) +{ assert(excp_is_internal(excp)); - gen_helper_exception_internal(cpu_env, tcg_excp); - tcg_temp_free_i32(tcg_excp); + gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp)); } -static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp) +static void gen_exception_internal_insn(DisasContext *s, int excp) { - gen_a64_set_pc_im(pc); + gen_a64_update_pc(s, 0); gen_exception_internal(excp); s->base.is_jmp = DISAS_NORETURN; } static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome) { - TCGv_i32 tcg_syn; - - gen_a64_set_pc_im(s->pc_curr); - tcg_syn = tcg_const_i32(syndrome); - gen_helper_exception_bkpt_insn(cpu_env, tcg_syn); - tcg_temp_free_i32(tcg_syn); + gen_a64_update_pc(s, 0); + gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syndrome)); s->base.is_jmp = DISAS_NORETURN; } @@ -393,15 +382,28 @@ static inline bool use_goto_tb(DisasContext *s, uint64_t dest) return translator_use_goto_tb(&s->base, dest); } -static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) +static void gen_goto_tb(DisasContext *s, int n, int64_t diff) { - if (use_goto_tb(s, dest)) { - tcg_gen_goto_tb(n); - gen_a64_set_pc_im(dest); + if (use_goto_tb(s, s->pc_curr + diff)) { + /* + * For pcrel, the pc must always be up-to-date on entry to + * the linked TB, so that it can use simple additions for all + * further adjustments. For !pcrel, the linked TB is compiled + * to know its full virtual address, so we can delay the + * update to pc to the unlinked path. A long chain of links + * can thus avoid many updates to the PC. + */ + if (TARGET_TB_PCREL) { + gen_a64_update_pc(s, diff); + tcg_gen_goto_tb(n); + } else { + tcg_gen_goto_tb(n); + gen_a64_update_pc(s, diff); + } tcg_gen_exit_tb(s->base.tb, n); s->base.is_jmp = DISAS_NORETURN; } else { - gen_a64_set_pc_im(dest); + gen_a64_update_pc(s, diff); if (s->ss_active) { gen_step_complete_exception(s); } else { @@ -827,15 +829,15 @@ static void gen_adc(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) { if (sf) { - TCGv_i64 result, cf_64, vf_64, tmp; - result = tcg_temp_new_i64(); - cf_64 = tcg_temp_new_i64(); - vf_64 = tcg_temp_new_i64(); - tmp = tcg_const_i64(0); + TCGv_i64 result = tcg_temp_new_i64(); + TCGv_i64 cf_64 = tcg_temp_new_i64(); + TCGv_i64 vf_64 = tcg_temp_new_i64(); + TCGv_i64 tmp = tcg_temp_new_i64(); + TCGv_i64 zero = tcg_constant_i64(0); tcg_gen_extu_i32_i64(cf_64, cpu_CF); - tcg_gen_add2_i64(result, cf_64, t0, tmp, cf_64, tmp); - tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, tmp); + tcg_gen_add2_i64(result, cf_64, t0, zero, cf_64, zero); + tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, zero); tcg_gen_extrl_i64_i32(cpu_CF, cf_64); gen_set_NZ64(result); @@ -851,15 +853,15 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) tcg_temp_free_i64(cf_64); tcg_temp_free_i64(result); } else { - TCGv_i32 t0_32, t1_32, tmp; - t0_32 = tcg_temp_new_i32(); - t1_32 = tcg_temp_new_i32(); - tmp = tcg_const_i32(0); + TCGv_i32 t0_32 = tcg_temp_new_i32(); + TCGv_i32 t1_32 = tcg_temp_new_i32(); + TCGv_i32 tmp = tcg_temp_new_i32(); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_extrl_i64_i32(t0_32, t0); tcg_gen_extrl_i64_i32(t1_32, t1); - tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, cpu_CF, tmp); - tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, tmp); + tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, zero, cpu_CF, zero); + tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, zero); tcg_gen_mov_i32(cpu_ZF, cpu_NF); tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32); @@ -1170,35 +1172,109 @@ static void do_vec_ld(DisasContext *s, int destidx, int element, * unallocated-encoding checks (otherwise the syndrome information * for the resulting exception will be incorrect). */ -static bool fp_access_check(DisasContext *s) +static bool fp_access_check_only(DisasContext *s) { if (s->fp_excp_el) { assert(!s->fp_access_checked); s->fp_access_checked = true; - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, false), s->fp_excp_el); + gen_exception_insn_el(s, 0, EXCP_UDEF, + syn_fp_access_trap(1, 0xe, false, 0), + s->fp_excp_el); return false; } s->fp_access_checked = true; return true; } -/* Check that SVE access is enabled. If it is, return true. +static bool fp_access_check(DisasContext *s) +{ + if (!fp_access_check_only(s)) { + return false; + } + if (s->sme_trap_nonstreaming && s->is_nonstreaming) { + gen_exception_insn(s, 0, EXCP_UDEF, + syn_smetrap(SME_ET_Streaming, false)); + return false; + } + return true; +} + +/* + * Check that SVE access is enabled. If it is, return true. * If not, emit code to generate an appropriate exception and return false. + * This function corresponds to CheckSVEEnabled(). */ bool sve_access_check(DisasContext *s) { - if (s->sve_excp_el) { - assert(!s->sve_access_checked); - s->sve_access_checked = true; - - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_sve_access_trap(), s->sve_excp_el); - return false; + if (s->pstate_sm || !dc_isar_feature(aa64_sve, s)) { + assert(dc_isar_feature(aa64_sme, s)); + if (!sme_sm_enabled_check(s)) { + goto fail_exit; + } + } else if (s->sve_excp_el) { + gen_exception_insn_el(s, 0, EXCP_UDEF, + syn_sve_access_trap(), s->sve_excp_el); + goto fail_exit; } s->sve_access_checked = true; return fp_access_check(s); + + fail_exit: + /* Assert that we only raise one exception per instruction. */ + assert(!s->sve_access_checked); + s->sve_access_checked = true; + return false; +} + +/* + * Check that SME access is enabled, raise an exception if not. + * Note that this function corresponds to CheckSMEAccess and is + * only used directly for cpregs. + */ +static bool sme_access_check(DisasContext *s) +{ + if (s->sme_excp_el) { + gen_exception_insn_el(s, 0, EXCP_UDEF, + syn_smetrap(SME_ET_AccessTrap, false), + s->sme_excp_el); + return false; + } + return true; +} + +/* This function corresponds to CheckSMEEnabled. */ +bool sme_enabled_check(DisasContext *s) +{ + /* + * Note that unlike sve_excp_el, we have not constrained sme_excp_el + * to be zero when fp_excp_el has priority. This is because we need + * sme_excp_el by itself for cpregs access checks. + */ + if (!s->fp_excp_el || s->sme_excp_el < s->fp_excp_el) { + s->fp_access_checked = true; + return sme_access_check(s); + } + return fp_access_check_only(s); +} + +/* Common subroutine for CheckSMEAnd*Enabled. */ +bool sme_enabled_check_with_svcr(DisasContext *s, unsigned req) +{ + if (!sme_enabled_check(s)) { + return false; + } + if (FIELD_EX64(req, SVCR, SM) && !s->pstate_sm) { + gen_exception_insn(s, 0, EXCP_UDEF, + syn_smetrap(SME_ET_NotStreaming, false)); + return false; + } + if (FIELD_EX64(req, SVCR, ZA) && !s->pstate_za) { + gen_exception_insn(s, 0, EXCP_UDEF, + syn_smetrap(SME_ET_InactiveZA, false)); + return false; + } + return true; } /* @@ -1303,16 +1379,16 @@ static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table, */ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn) { - uint64_t addr = s->pc_curr + sextract32(insn, 0, 26) * 4; + int64_t diff = sextract32(insn, 0, 26) * 4; if (insn & (1U << 31)) { /* BL Branch with link */ - tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next); + gen_pc_plus_diff(s, cpu_reg(s, 30), curr_insn_len(s)); } /* B Branch / BL Branch with link */ reset_btype(s); - gen_goto_tb(s, 0, addr); + gen_goto_tb(s, 0, diff); } /* Compare and branch (immediate) @@ -1324,25 +1400,24 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn) static void disas_comp_b_imm(DisasContext *s, uint32_t insn) { unsigned int sf, op, rt; - uint64_t addr; - TCGLabel *label_match; + int64_t diff; + DisasLabel match; TCGv_i64 tcg_cmp; sf = extract32(insn, 31, 1); op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */ rt = extract32(insn, 0, 5); - addr = s->pc_curr + sextract32(insn, 5, 19) * 4; + diff = sextract32(insn, 5, 19) * 4; tcg_cmp = read_cpu_reg(s, rt, sf); - label_match = gen_new_label(); - reset_btype(s); - tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ, - tcg_cmp, 0, label_match); - gen_goto_tb(s, 0, s->base.pc_next); - gen_set_label(label_match); - gen_goto_tb(s, 1, addr); + match = gen_disas_label(s); + tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ, + tcg_cmp, 0, match.label); + gen_goto_tb(s, 0, 4); + set_disas_label(s, match); + gen_goto_tb(s, 1, diff); } /* Test and branch (immediate) @@ -1354,26 +1429,27 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn) static void disas_test_b_imm(DisasContext *s, uint32_t insn) { unsigned int bit_pos, op, rt; - uint64_t addr; - TCGLabel *label_match; + int64_t diff; + DisasLabel match; TCGv_i64 tcg_cmp; bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5); op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */ - addr = s->pc_curr + sextract32(insn, 5, 14) * 4; + diff = sextract32(insn, 5, 14) * 4; rt = extract32(insn, 0, 5); tcg_cmp = tcg_temp_new_i64(); tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos)); - label_match = gen_new_label(); reset_btype(s); + + match = gen_disas_label(s); tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ, - tcg_cmp, 0, label_match); + tcg_cmp, 0, match.label); tcg_temp_free_i64(tcg_cmp); - gen_goto_tb(s, 0, s->base.pc_next); - gen_set_label(label_match); - gen_goto_tb(s, 1, addr); + gen_goto_tb(s, 0, 4); + set_disas_label(s, match); + gen_goto_tb(s, 1, diff); } /* Conditional branch (immediate) @@ -1385,26 +1461,26 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn) static void disas_cond_b_imm(DisasContext *s, uint32_t insn) { unsigned int cond; - uint64_t addr; + int64_t diff; if ((insn & (1 << 4)) || (insn & (1 << 24))) { unallocated_encoding(s); return; } - addr = s->pc_curr + sextract32(insn, 5, 19) * 4; + diff = sextract32(insn, 5, 19) * 4; cond = extract32(insn, 0, 4); reset_btype(s); if (cond < 0x0e) { /* genuinely conditional branches */ - TCGLabel *label_match = gen_new_label(); - arm_gen_test_cc(cond, label_match); - gen_goto_tb(s, 0, s->base.pc_next); - gen_set_label(label_match); - gen_goto_tb(s, 1, addr); + DisasLabel match = gen_disas_label(s); + arm_gen_test_cc(cond, match.label); + gen_goto_tb(s, 0, 4); + set_disas_label(s, match); + gen_goto_tb(s, 1, diff); } else { /* 0xe and 0xf are both "always" conditions */ - gen_goto_tb(s, 0, addr); + gen_goto_tb(s, 0, diff); } } @@ -1442,6 +1518,7 @@ static void handle_hint(DisasContext *s, uint32_t insn, break; case 0b00100: /* SEV */ case 0b00101: /* SEVL */ + case 0b00110: /* DGH */ /* we treat all as NOP at least for now */ break; case 0b00111: /* XPACLRI */ @@ -1469,6 +1546,23 @@ static void handle_hint(DisasContext *s, uint32_t insn, gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); } break; + case 0b10000: /* ESB */ + /* Without RAS, we must implement this as NOP. */ + if (dc_isar_feature(aa64_ras, s)) { + /* + * QEMU does not have a source of physical SErrors, + * so we are only concerned with virtual SErrors. + * The pseudocode in the ARM for this case is + * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then + * AArch64.vESBOperation(); + * Most of the condition can be evaluated at translation time. + * Test for EL2 present, and defer test for SEL2 to runtime. + */ + if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { + gen_helper_vesb(cpu_env); + } + } + break; case 0b11000: /* PACIAZ */ if (s->pauth_active) { gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], @@ -1560,7 +1654,7 @@ static void handle_sync(DisasContext *s, uint32_t insn, * any pending interrupts immediately. */ reset_btype(s); - gen_goto_tb(s, 0, s->base.pc_next); + gen_goto_tb(s, 0, 4); return; case 7: /* SB */ @@ -1572,7 +1666,7 @@ static void handle_sync(DisasContext *s, uint32_t insn, * MB and end the TB instead. */ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - gen_goto_tb(s, 0, s->base.pc_next); + gen_goto_tb(s, 0, 4); return; default: @@ -1628,7 +1722,6 @@ static void gen_axflag(void) static void handle_msr_i(DisasContext *s, uint32_t insn, unsigned int op1, unsigned int op2, unsigned int crm) { - TCGv_i32 t1; int op = op1 << 3 | op2; /* End the TB by default, chaining is ok. */ @@ -1668,9 +1761,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, } else { clear_pstate_bits(PSTATE_UAO); } - t1 = tcg_const_i32(s->current_el); - gen_helper_rebuild_hflags_a64(cpu_env, t1); - tcg_temp_free_i32(t1); + gen_rebuild_hflags(s); break; case 0x04: /* PAN */ @@ -1682,18 +1773,14 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, } else { clear_pstate_bits(PSTATE_PAN); } - t1 = tcg_const_i32(s->current_el); - gen_helper_rebuild_hflags_a64(cpu_env, t1); - tcg_temp_free_i32(t1); + gen_rebuild_hflags(s); break; case 0x05: /* SPSel */ if (s->current_el == 0) { goto do_unallocated; } - t1 = tcg_const_i32(crm & PSTATE_SP); - gen_helper_msr_i_spsel(cpu_env, t1); - tcg_temp_free_i32(t1); + gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(crm & PSTATE_SP)); break; case 0x19: /* SSBS */ @@ -1721,15 +1808,11 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, break; case 0x1e: /* DAIFSet */ - t1 = tcg_const_i32(crm); - gen_helper_msr_i_daifset(cpu_env, t1); - tcg_temp_free_i32(t1); + gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(crm)); break; case 0x1f: /* DAIFClear */ - t1 = tcg_const_i32(crm); - gen_helper_msr_i_daifclear(cpu_env, t1); - tcg_temp_free_i32(t1); + gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(crm)); /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */ s->base.is_jmp = DISAS_UPDATE_EXIT; break; @@ -1742,9 +1825,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, } else { clear_pstate_bits(PSTATE_TCO); } - t1 = tcg_const_i32(s->current_el); - gen_helper_rebuild_hflags_a64(cpu_env, t1); - tcg_temp_free_i32(t1); + gen_rebuild_hflags(s); /* Many factors, including TCO, go into MTE_ACTIVE. */ s->base.is_jmp = DISAS_UPDATE_NOCHAIN; } else if (dc_isar_feature(aa64_mte_insn_reg, s)) { @@ -1755,6 +1836,30 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, } break; + case 0x1b: /* SVCR* */ + if (!dc_isar_feature(aa64_sme, s) || crm < 2 || crm > 7) { + goto do_unallocated; + } + if (sme_access_check(s)) { + bool i = crm & 1; + bool changed = false; + + if ((crm & 2) && i != s->pstate_sm) { + gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i)); + changed = true; + } + if ((crm & 4) && i != s->pstate_za) { + gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i)); + changed = true; + } + if (changed) { + gen_rebuild_hflags(s); + } else { + s->base.is_jmp = DISAS_NEXT; + } + } + break; + default: do_unallocated: unallocated_encoding(s); @@ -1805,6 +1910,29 @@ static void gen_set_nzcv(TCGv_i64 tcg_rt) tcg_temp_free_i32(nzcv); } +static void gen_sysreg_undef(DisasContext *s, bool isread, + uint8_t op0, uint8_t op1, uint8_t op2, + uint8_t crn, uint8_t crm, uint8_t rt) +{ + /* + * Generate code to emit an UNDEF with correct syndrome + * information for a failed system register access. + * This is EC_UNCATEGORIZED (ie a standard UNDEF) in most cases, + * but if FEAT_IDST is implemented then read accesses to registers + * in the feature ID space are reported with the EC_SYSTEMREGISTERTRAP + * syndrome. + */ + uint32_t syndrome; + + if (isread && dc_isar_feature(aa64_ids, s) && + arm_cpreg_encoding_in_idspace(op0, op1, op2, crn, crm)) { + syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); + } else { + syndrome = syn_uncategorized(); + } + gen_exception_insn(s, 0, EXCP_UDEF, syndrome); +} + /* MRS - move from system register * MSR (register) - move to system register * SYS @@ -1830,13 +1958,13 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 " "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n", isread ? "read" : "write", op0, op1, crn, crm, op2); - unallocated_encoding(s); + gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); return; } /* Check access permissions */ if (!cp_access_ok(s->current_el, ri, isread)) { - unallocated_encoding(s); + gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); return; } @@ -1844,29 +1972,26 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, /* Emit code to perform further access permissions checks at * runtime; this may result in an exception. */ - TCGv_ptr tmpptr; - TCGv_i32 tcg_syn, tcg_isread; uint32_t syndrome; - gen_a64_set_pc_im(s->pc_curr); - tmpptr = tcg_const_ptr(ri); syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); - tcg_syn = tcg_const_i32(syndrome); - tcg_isread = tcg_const_i32(isread); - gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn, tcg_isread); - tcg_temp_free_ptr(tmpptr); - tcg_temp_free_i32(tcg_syn); - tcg_temp_free_i32(tcg_isread); + gen_a64_update_pc(s, 0); + gen_helper_access_check_cp_reg(cpu_env, + tcg_constant_ptr(ri), + tcg_constant_i32(syndrome), + tcg_constant_i32(isread)); } else if (ri->type & ARM_CP_RAISES_EXC) { /* * The readfn or writefn might raise an exception; * synchronize the CPU state in case it does. */ - gen_a64_set_pc_im(s->pc_curr); + gen_a64_update_pc(s, 0); } /* Handle special cases first */ - switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) { + switch (ri->type & ARM_CP_SPECIAL_MASK) { + case 0: + break; case ARM_CP_NOP: return; case ARM_CP_NZCV: @@ -1887,17 +2012,15 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, case ARM_CP_DC_ZVA: /* Writes clear the aligned block of memory which rt points into. */ if (s->mte_active[0]) { - TCGv_i32 t_desc; int desc = 0; desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); - t_desc = tcg_const_i32(desc); tcg_rt = new_tmp_a64(s); - gen_helper_mte_check_zva(tcg_rt, cpu_env, t_desc, cpu_reg(s, rt)); - tcg_temp_free_i32(t_desc); + gen_helper_mte_check_zva(tcg_rt, cpu_env, + tcg_constant_i32(desc), cpu_reg(s, rt)); } else { tcg_rt = clean_data_tbi(s, cpu_reg(s, rt)); } @@ -1943,12 +2066,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } return; default: - break; + g_assert_not_reached(); } - if ((ri->type & ARM_CP_FPU) && !fp_access_check(s)) { + if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) { return; } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { return; + } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { + return; } if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { @@ -1961,10 +2086,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, if (ri->type & ARM_CP_CONST) { tcg_gen_movi_i64(tcg_rt, ri->resetvalue); } else if (ri->readfn) { - TCGv_ptr tmpptr; - tmpptr = tcg_const_ptr(ri); - gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr); - tcg_temp_free_ptr(tmpptr); + gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_constant_ptr(ri)); } else { tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset); } @@ -1973,10 +2095,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, /* If not forbidden by access permissions, treat as WI */ return; } else if (ri->writefn) { - TCGv_ptr tmpptr; - tmpptr = tcg_const_ptr(ri); - gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt); - tcg_temp_free_ptr(tmpptr); + gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tcg_rt); } else { tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset); } @@ -1991,9 +2110,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, * A write to any coprocessor regiser that ends a TB * must rebuild the hflags for the next TB. */ - TCGv_i32 tcg_el = tcg_const_i32(s->current_el); - gen_helper_rebuild_hflags_a64(cpu_env, tcg_el); - tcg_temp_free_i32(tcg_el); + gen_rebuild_hflags(s); /* * We default to ending the TB on a coprocessor register write, * but allow this to be suppressed by the register definition @@ -2056,7 +2173,6 @@ static void disas_exc(DisasContext *s, uint32_t insn) int opc = extract32(insn, 21, 3); int op2_ll = extract32(insn, 0, 5); int imm16 = extract32(insn, 5, 16); - TCGv_i32 tmp; switch (opc) { case 0: @@ -2068,8 +2184,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) switch (op2_ll) { case 1: /* SVC */ gen_ss_advance(s); - gen_exception_insn(s, s->base.pc_next, EXCP_SWI, - syn_aa64_svc(imm16), default_exception_el(s)); + gen_exception_insn(s, 4, EXCP_SWI, syn_aa64_svc(imm16)); break; case 2: /* HVC */ if (s->current_el == 0) { @@ -2079,24 +2194,20 @@ static void disas_exc(DisasContext *s, uint32_t insn) /* The pre HVC helper handles cases when HVC gets trapped * as an undefined insn by runtime configuration. */ - gen_a64_set_pc_im(s->pc_curr); + gen_a64_update_pc(s, 0); gen_helper_pre_hvc(cpu_env); gen_ss_advance(s); - gen_exception_insn(s, s->base.pc_next, EXCP_HVC, - syn_aa64_hvc(imm16), 2); + gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(imm16), 2); break; case 3: /* SMC */ if (s->current_el == 0) { unallocated_encoding(s); break; } - gen_a64_set_pc_im(s->pc_curr); - tmp = tcg_const_i32(syn_aa64_smc(imm16)); - gen_helper_pre_smc(cpu_env, tmp); - tcg_temp_free_i32(tmp); + gen_a64_update_pc(s, 0); + gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(imm16))); gen_ss_advance(s); - gen_exception_insn(s, s->base.pc_next, EXCP_SMC, - syn_aa64_smc(imm16), 3); + gen_exception_insn_el(s, 4, EXCP_SMC, syn_aa64_smc(imm16), 3); break; default: unallocated_encoding(s); @@ -2122,20 +2233,10 @@ 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) { - unsupported_encoding(s, insn); - break; - } -#endif - gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST); + if (semihosting_enabled(s->current_el == 0) && imm16 == 0xf000) { + gen_exception_internal_insn(s, EXCP_SEMIHOST); } else { - unsupported_encoding(s, insn); + unallocated_encoding(s); } break; case 5: @@ -2144,7 +2245,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) break; } /* DCPS1, DCPS2, DCPS3 */ - unsupported_encoding(s, insn); + unallocated_encoding(s); break; default: unallocated_encoding(s); @@ -2223,11 +2324,17 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) default: goto do_unallocated; } - gen_a64_set_pc(s, dst); /* BLR also needs to load return address */ if (opc == 1) { - tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next); + TCGv_i64 lr = cpu_reg(s, 30); + if (dst == lr) { + TCGv_i64 tmp = new_tmp_a64(s); + tcg_gen_mov_i64(tmp, dst); + dst = tmp; + } + gen_pc_plus_diff(s, lr, curr_insn_len(s)); } + gen_a64_set_pc(s, dst); break; case 8: /* BRAA */ @@ -2250,11 +2357,17 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) } else { dst = cpu_reg(s, rn); } - gen_a64_set_pc(s, dst); /* BLRAA also needs to load return address */ if (opc == 9) { - tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next); + TCGv_i64 lr = cpu_reg(s, 30); + if (dst == lr) { + TCGv_i64 tmp = new_tmp_a64(s); + tcg_gen_mov_i64(tmp, dst); + dst = tmp; + } + gen_pc_plus_diff(s, lr, curr_insn_len(s)); } + gen_a64_set_pc(s, dst); break; case 4: /* ERET */ @@ -2309,7 +2422,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) if (op3 != 0 || op4 != 0 || rn != 0x1f) { goto do_unallocated; } else { - unsupported_encoding(s, insn); + unallocated_encoding(s); } return; @@ -2567,7 +2680,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, tcg_temp_free_i64(cmp); } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { if (HAVE_CMPXCHG128) { - TCGv_i32 tcg_rs = tcg_const_i32(rs); + TCGv_i32 tcg_rs = tcg_constant_i32(rs); if (s->be_data == MO_LE) { gen_helper_casp_le_parallel(cpu_env, tcg_rs, clean_addr, t1, t2); @@ -2575,7 +2688,6 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, gen_helper_casp_be_parallel(cpu_env, tcg_rs, clean_addr, t1, t2); } - tcg_temp_free_i32(tcg_rs); } else { gen_helper_exit_atomic(cpu_env); s->base.is_jmp = DISAS_NORETURN; @@ -2586,7 +2698,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, TCGv_i64 a2 = tcg_temp_new_i64(); TCGv_i64 c1 = tcg_temp_new_i64(); TCGv_i64 c2 = tcg_temp_new_i64(); - TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 zero = tcg_constant_i64(0); /* Load the two words, in memory order. */ tcg_gen_qemu_ld_i64(d1, clean_addr, memidx, @@ -2607,7 +2719,6 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, tcg_temp_free_i64(a2); tcg_temp_free_i64(c1); tcg_temp_free_i64(c2); - tcg_temp_free_i64(zero); /* Write back the data from memory to Rs. */ tcg_gen_mov_i64(s1, d1); @@ -2824,7 +2935,8 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) tcg_rt = cpu_reg(s, rt); - clean_addr = tcg_const_i64(s->pc_curr + imm); + clean_addr = new_tmp_a64(s); + gen_pc_plus_diff(s, clean_addr, imm); if (is_vector) { do_fp_ld(s, rt, clean_addr, size); } else { @@ -2834,7 +2946,6 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN, false, true, rt, iss_sf, false); } - tcg_temp_free_i64(clean_addr); } /* @@ -3044,7 +3155,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, bool is_store = false; bool is_extended = false; bool is_unpriv = (idx == 2); - bool iss_valid = !is_vector; + bool iss_valid; bool post_index; bool writeback; int memidx; @@ -3097,6 +3208,8 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, g_assert_not_reached(); } + iss_valid = !is_vector && !writeback; + if (rn == 31) { gen_check_sp_alignment(s); } @@ -3740,7 +3853,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) mop = endian | size | align; elements = (is_q ? 16 : 8) >> size; - tcg_ebytes = tcg_const_i64(1 << size); + tcg_ebytes = tcg_constant_i64(1 << size); for (r = 0; r < rpt; r++) { int e; for (e = 0; e < elements; e++) { @@ -3756,7 +3869,6 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) } } } - tcg_temp_free_i64(tcg_ebytes); if (!is_store) { /* For non-quad operations, setting a slice of the low @@ -3886,7 +3998,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) total); mop = finalize_memop(s, scale); - tcg_ebytes = tcg_const_i64(1 << scale); + tcg_ebytes = tcg_constant_i64(1 << scale); for (xs = 0; xs < selem; xs++) { if (replicate) { /* Load and replicate to all elements */ @@ -3908,7 +4020,6 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes); rt = (rt + 1) % 32; } - tcg_temp_free_i64(tcg_ebytes); if (is_postidx) { if (rm == 31) { @@ -4099,7 +4210,7 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) if (is_zero) { TCGv_i64 clean_addr = clean_data_tbi(s, addr); - TCGv_i64 tcg_zero = tcg_const_i64(0); + TCGv_i64 tcg_zero = tcg_constant_i64(0); int mem_index = get_mem_index(s); int i, n = (1 + is_pair) << LOG2_TAG_GRANULE; @@ -4109,7 +4220,6 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) tcg_gen_addi_i64(clean_addr, clean_addr, 8); tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index, MO_UQ); } - tcg_temp_free_i64(tcg_zero); } if (index != 0) { @@ -4170,23 +4280,22 @@ static void disas_ldst(DisasContext *s, uint32_t insn) static void disas_pc_rel_adr(DisasContext *s, uint32_t insn) { unsigned int page, rd; - uint64_t base; - uint64_t offset; + int64_t offset; page = extract32(insn, 31, 1); /* SignExtend(immhi:immlo) -> offset */ offset = sextract64(insn, 5, 19); offset = offset << 2 | extract32(insn, 29, 2); rd = extract32(insn, 0, 5); - base = s->pc_curr; if (page) { /* ADRP (page based) */ - base &= ~0xfff; offset <<= 12; + /* The page offset is ok for TARGET_TB_PCREL. */ + offset -= s->pc_curr & 0xfff; } - tcg_gen_movi_i64(cpu_reg(s, rd), base + offset); + gen_pc_plus_diff(s, cpu_reg(s, rd), offset); } /* @@ -4228,13 +4337,12 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) tcg_gen_addi_i64(tcg_result, tcg_rn, imm); } } else { - TCGv_i64 tcg_imm = tcg_const_i64(imm); + TCGv_i64 tcg_imm = tcg_constant_i64(imm); if (sub_op) { gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm); } else { gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm); } - tcg_temp_free_i64(tcg_imm); } if (is_64bit) { @@ -4282,12 +4390,9 @@ static void disas_add_sub_imm_with_tags(DisasContext *s, uint32_t insn) tcg_rd = cpu_reg_sp(s, rd); if (s->ata) { - TCGv_i32 offset = tcg_const_i32(imm); - TCGv_i32 tag_offset = tcg_const_i32(uimm4); - - gen_helper_addsubg(tcg_rd, cpu_env, tcg_rn, offset, tag_offset); - tcg_temp_free_i32(tag_offset); - tcg_temp_free_i32(offset); + gen_helper_addsubg(tcg_rd, cpu_env, tcg_rn, + tcg_constant_i32(imm), + tcg_constant_i32(uimm4)); } else { tcg_gen_addi_i64(tcg_rd, tcg_rn, imm); gen_address_with_allocation_tag0(tcg_rd, tcg_rd); @@ -4473,7 +4578,6 @@ static void disas_movw_imm(DisasContext *s, uint32_t insn) int opc = extract32(insn, 29, 2); int pos = extract32(insn, 21, 2) << 4; TCGv_i64 tcg_rd = cpu_reg(s, rd); - TCGv_i64 tcg_imm; if (!sf && (pos >= 32)) { unallocated_encoding(s); @@ -4493,9 +4597,7 @@ static void disas_movw_imm(DisasContext *s, uint32_t insn) tcg_gen_movi_i64(tcg_rd, imm); break; case 3: /* MOVK */ - tcg_imm = tcg_const_i64(imm); - tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_imm, pos, 16); - tcg_temp_free_i64(tcg_imm); + tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_constant_i64(imm), pos, 16); if (!sf) { tcg_gen_ext32u_i64(tcg_rd, tcg_rd); } @@ -4735,11 +4837,7 @@ static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf, if (shift_i == 0) { tcg_gen_mov_i64(dst, src); } else { - TCGv_i64 shift_const; - - shift_const = tcg_const_i64(shift_i); - shift_reg(dst, src, sf, shift_type, shift_const); - tcg_temp_free_i64(shift_const); + shift_reg(dst, src, sf, shift_type, tcg_constant_i64(shift_i)); } } @@ -5316,7 +5414,7 @@ static void disas_cond_select(DisasContext *s, uint32_t insn) tcg_rd = cpu_reg(s, rd); a64_test_cc(&c, cond); - zero = tcg_const_i64(0); + zero = tcg_constant_i64(0); if (rn == 31 && rm == 31 && (else_inc ^ else_inv)) { /* CSET & CSETM. */ @@ -5337,7 +5435,6 @@ static void disas_cond_select(DisasContext *s, uint32_t insn) tcg_gen_movcond_i64(c.cond, tcg_rd, c.value, zero, t_true, t_false); } - tcg_temp_free_i64(zero); a64_free_cc(&c); if (!sf) { @@ -5434,7 +5531,7 @@ static void handle_rev16(DisasContext *s, unsigned int sf, TCGv_i64 tcg_rd = cpu_reg(s, rd); TCGv_i64 tcg_tmp = tcg_temp_new_i64(); TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf); - TCGv_i64 mask = tcg_const_i64(sf ? 0x00ff00ff00ff00ffull : 0x00ff00ff); + TCGv_i64 mask = tcg_constant_i64(sf ? 0x00ff00ff00ff00ffull : 0x00ff00ff); tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8); tcg_gen_and_i64(tcg_rd, tcg_rn, mask); @@ -5442,7 +5539,6 @@ static void handle_rev16(DisasContext *s, unsigned int sf, tcg_gen_shli_i64(tcg_rd, tcg_rd, 8); tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp); - tcg_temp_free_i64(mask); tcg_temp_free_i64(tcg_tmp); } @@ -5725,15 +5821,13 @@ static void handle_crc32(DisasContext *s, } tcg_acc = cpu_reg(s, rn); - tcg_bytes = tcg_const_i32(1 << sz); + tcg_bytes = tcg_constant_i32(1 << sz); if (crc32c) { gen_helper_crc32c_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes); } else { gen_helper_crc32_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes); } - - tcg_temp_free_i32(tcg_bytes); } /* Data-processing (2 source) @@ -5799,15 +5893,13 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { goto do_unallocated; } else { - TCGv_i64 t1 = tcg_const_i64(1); - TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t = tcg_temp_new_i64(); - tcg_gen_extract_i64(t2, cpu_reg_sp(s, rn), 56, 4); - tcg_gen_shl_i64(t1, t1, t2); - tcg_gen_or_i64(cpu_reg(s, rd), cpu_reg(s, rm), t1); + tcg_gen_extract_i64(t, cpu_reg_sp(s, rn), 56, 4); + tcg_gen_shl_i64(t, tcg_constant_i64(1), t); + tcg_gen_or_i64(cpu_reg(s, rd), cpu_reg(s, rm), t); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); + tcg_temp_free_i64(t); } break; case 8: /* LSLV */ @@ -5942,7 +6034,7 @@ static void handle_fp_compare(DisasContext *s, int size, tcg_vn = read_fp_dreg(s, rn); if (cmp_with_zero) { - tcg_vm = tcg_const_i64(0); + tcg_vm = tcg_constant_i64(0); } else { tcg_vm = read_fp_dreg(s, rm); } @@ -6052,7 +6144,6 @@ static void disas_fp_compare(DisasContext *s, uint32_t insn) static void disas_fp_ccomp(DisasContext *s, uint32_t insn) { unsigned int mos, type, rm, cond, rn, op, nzcv; - TCGv_i64 tcg_flags; TCGLabel *label_continue = NULL; int size; @@ -6096,9 +6187,7 @@ static void disas_fp_ccomp(DisasContext *s, uint32_t insn) label_continue = gen_new_label(); arm_gen_test_cc(cond, label_match); /* nomatch: */ - tcg_flags = tcg_const_i64(nzcv << 28); - gen_set_nzcv(tcg_flags); - tcg_temp_free_i64(tcg_flags); + gen_set_nzcv(tcg_constant_i64(nzcv << 28)); tcg_gen_br(label_continue); gen_set_label(label_match); } @@ -6119,7 +6208,7 @@ static void disas_fp_ccomp(DisasContext *s, uint32_t insn) static void disas_fp_csel(DisasContext *s, uint32_t insn) { unsigned int mos, type, rm, cond, rn, rd; - TCGv_i64 t_true, t_false, t_zero; + TCGv_i64 t_true, t_false; DisasCompare64 c; MemOp sz; @@ -6164,9 +6253,8 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn) read_vec_element(s, t_false, rm, 0, sz); a64_test_cc(&c, cond); - t_zero = tcg_const_i64(0); - tcg_gen_movcond_i64(c.cond, t_true, c.value, t_zero, t_true, t_false); - tcg_temp_free_i64(t_zero); + tcg_gen_movcond_i64(c.cond, t_true, c.value, tcg_constant_i64(0), + t_true, t_false); tcg_temp_free_i64(t_false); a64_free_cc(&c); @@ -6222,7 +6310,7 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn) gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst); break; default: - abort(); + g_assert_not_reached(); } write_fp_sreg(s, rd, tcg_res); @@ -6463,7 +6551,7 @@ static void handle_fp_fcvt(DisasContext *s, int opcode, break; } default: - abort(); + g_assert_not_reached(); } } @@ -6948,7 +7036,6 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn) int type = extract32(insn, 22, 2); int mos = extract32(insn, 29, 3); uint64_t imm; - TCGv_i64 tcg_res; MemOp sz; if (mos || imm5) { @@ -6979,10 +7066,7 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn) } imm = vfp_expand_imm(sz, imm8); - - tcg_res = tcg_const_i64(imm); - write_fp_dreg(s, rd, tcg_res); - tcg_temp_free_i64(tcg_res); + write_fp_dreg(s, rd, tcg_constant_i64(imm)); } /* Handle floating point <=> fixed point conversions. Note that we can @@ -7000,7 +7084,7 @@ static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode, tcg_fpstatus = fpstatus_ptr(type == 3 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_shift = tcg_const_i32(64 - scale); + tcg_shift = tcg_constant_i32(64 - scale); if (itof) { TCGv_i64 tcg_int = cpu_reg(s, rn); @@ -7159,7 +7243,6 @@ static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode, } tcg_temp_free_ptr(tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); } /* Floating point <-> fixed point conversions @@ -8430,7 +8513,7 @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, /* Deal with the rounding step */ if (round) { if (extended_result) { - TCGv_i64 tcg_zero = tcg_const_i64(0); + TCGv_i64 tcg_zero = tcg_constant_i64(0); if (!is_u) { /* take care of sign extending tcg_res */ tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63); @@ -8442,7 +8525,6 @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, tcg_src, tcg_zero, tcg_rnd, tcg_zero); } - tcg_temp_free_i64(tcg_zero); } else { tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd); } @@ -8528,8 +8610,7 @@ static void handle_scalar_simd_shri(DisasContext *s, } if (round) { - uint64_t round_const = 1ULL << (shift - 1); - tcg_round = tcg_const_i64(round_const); + tcg_round = tcg_constant_i64(1ULL << (shift - 1)); } else { tcg_round = NULL; } @@ -8555,9 +8636,6 @@ static void handle_scalar_simd_shri(DisasContext *s, tcg_temp_free_i64(tcg_rn); tcg_temp_free_i64(tcg_rd); - if (round) { - tcg_temp_free_i64(tcg_round); - } } /* SHL/SLI - Scalar shift left */ @@ -8655,8 +8733,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, tcg_final = tcg_const_i64(0); if (round) { - uint64_t round_const = 1ULL << (shift - 1); - tcg_round = tcg_const_i64(round_const); + tcg_round = tcg_constant_i64(1ULL << (shift - 1)); } else { tcg_round = NULL; } @@ -8676,9 +8753,6 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, write_vec_element(s, tcg_final, rd, 1, MO_64); } - if (round) { - tcg_temp_free_i64(tcg_round); - } tcg_temp_free_i64(tcg_rn); tcg_temp_free_i64(tcg_rd); tcg_temp_free_i32(tcg_rd_narrowed); @@ -8730,7 +8804,7 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, } if (size == 3) { - TCGv_i64 tcg_shift = tcg_const_i64(shift); + TCGv_i64 tcg_shift = tcg_constant_i64(shift); static NeonGenTwo64OpEnvFn * const fns[2][2] = { { gen_helper_neon_qshl_s64, gen_helper_neon_qshlu_s64 }, { NULL, gen_helper_neon_qshl_u64 }, @@ -8747,10 +8821,9 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, tcg_temp_free_i64(tcg_op); } - tcg_temp_free_i64(tcg_shift); clear_vec_high(s, is_q, rd); } else { - TCGv_i32 tcg_shift = tcg_const_i32(shift); + TCGv_i32 tcg_shift = tcg_constant_i32(shift); static NeonGenTwoOpEnvFn * const fns[2][2][3] = { { { gen_helper_neon_qshl_s8, @@ -8795,7 +8868,6 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, tcg_temp_free_i32(tcg_op); } - tcg_temp_free_i32(tcg_shift); if (!scalar) { clear_vec_high(s, is_q, rd); @@ -8815,7 +8887,7 @@ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int pass; if (fracbits || size == MO_64) { - tcg_shift = tcg_const_i32(fracbits); + tcg_shift = tcg_constant_i32(fracbits); } if (size == MO_64) { @@ -8900,9 +8972,6 @@ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, } tcg_temp_free_ptr(tcg_fpst); - if (tcg_shift) { - tcg_temp_free_i32(tcg_shift); - } clear_vec_high(s, elements << size == 16, rd); } @@ -8992,7 +9061,7 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar, tcg_fpstatus = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus); fracbits = (16 << size) - immhb; - tcg_shift = tcg_const_i32(fracbits); + tcg_shift = tcg_constant_i32(fracbits); if (size == MO_64) { int maxpass = is_scalar ? 1 : 2; @@ -9050,7 +9119,6 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar, } } - tcg_temp_free_i32(tcg_shift); gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus); tcg_temp_free_ptr(tcg_fpstatus); tcg_temp_free_i32(tcg_rmode); @@ -9922,23 +9990,15 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, case 0x1c: /* FCVTAS */ case 0x3a: /* FCVTPS */ case 0x3b: /* FCVTZS */ - { - TCGv_i32 tcg_shift = tcg_const_i32(0); - gen_helper_vfp_tosqd(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); + gen_helper_vfp_tosqd(tcg_rd, tcg_rn, tcg_constant_i32(0), tcg_fpstatus); break; - } case 0x5a: /* FCVTNU */ case 0x5b: /* FCVTMU */ case 0x5c: /* FCVTAU */ case 0x7a: /* FCVTPU */ case 0x7b: /* FCVTZU */ - { - TCGv_i32 tcg_shift = tcg_const_i32(0); - gen_helper_vfp_touqd(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); + gen_helper_vfp_touqd(tcg_rd, tcg_rn, tcg_constant_i32(0), tcg_fpstatus); break; - } case 0x18: /* FRINTN */ case 0x19: /* FRINTM */ case 0x38: /* FRINTP */ @@ -9978,7 +10038,7 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, if (is_double) { TCGv_i64 tcg_op = tcg_temp_new_i64(); - TCGv_i64 tcg_zero = tcg_const_i64(0); + TCGv_i64 tcg_zero = tcg_constant_i64(0); TCGv_i64 tcg_res = tcg_temp_new_i64(); NeonGenTwoDoubleOpFn *genfn; bool swap = false; @@ -10014,13 +10074,12 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, write_vec_element(s, tcg_res, rd, pass, MO_64); } tcg_temp_free_i64(tcg_res); - tcg_temp_free_i64(tcg_zero); tcg_temp_free_i64(tcg_op); clear_vec_high(s, !is_scalar, rd); } else { TCGv_i32 tcg_op = tcg_temp_new_i32(); - TCGv_i32 tcg_zero = tcg_const_i32(0); + TCGv_i32 tcg_zero = tcg_constant_i32(0); TCGv_i32 tcg_res = tcg_temp_new_i32(); NeonGenTwoSingleOpFn *genfn; bool swap = false; @@ -10089,7 +10148,6 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, } } tcg_temp_free_i32(tcg_res); - tcg_temp_free_i32(tcg_zero); tcg_temp_free_i32(tcg_op); if (!is_scalar) { clear_vec_high(s, is_q, rd); @@ -10190,7 +10248,7 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar, int passes = scalar ? 1 : 2; if (scalar) { - tcg_res[1] = tcg_const_i32(0); + tcg_res[1] = tcg_constant_i32(0); } for (pass = 0; pass < passes; pass++) { @@ -10368,9 +10426,7 @@ static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u, } if (is_scalar) { - TCGv_i64 tcg_zero = tcg_const_i64(0); - write_vec_element(s, tcg_zero, rd, 0, MO_64); - tcg_temp_free_i64(tcg_zero); + write_vec_element(s, tcg_constant_i64(0), rd, 0, MO_64); } write_vec_element_i32(s, tcg_rd, rd, pass, MO_32); } @@ -10553,23 +10609,17 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) case 0x1c: /* FCVTAS */ case 0x3a: /* FCVTPS */ case 0x3b: /* FCVTZS */ - { - TCGv_i32 tcg_shift = tcg_const_i32(0); - gen_helper_vfp_tosls(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); + gen_helper_vfp_tosls(tcg_rd, tcg_rn, tcg_constant_i32(0), + tcg_fpstatus); break; - } case 0x5a: /* FCVTNU */ case 0x5b: /* FCVTMU */ case 0x5c: /* FCVTAU */ case 0x7a: /* FCVTPU */ case 0x7b: /* FCVTZU */ - { - TCGv_i32 tcg_shift = tcg_const_i32(0); - gen_helper_vfp_touls(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); + gen_helper_vfp_touls(tcg_rd, tcg_rn, tcg_constant_i32(0), + tcg_fpstatus); break; - } default: g_assert_not_reached(); } @@ -10741,8 +10791,7 @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, read_vec_element(s, tcg_final, rd, is_q ? 1 : 0, MO_64); if (round) { - uint64_t round_const = 1ULL << (shift - 1); - tcg_round = tcg_const_i64(round_const); + tcg_round = tcg_constant_i64(1ULL << (shift - 1)); } else { tcg_round = NULL; } @@ -10760,9 +10809,6 @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, } else { write_vec_element(s, tcg_final, rd, 1, MO_64); } - if (round) { - tcg_temp_free_i64(tcg_round); - } tcg_temp_free_i64(tcg_rn); tcg_temp_free_i64(tcg_rd); tcg_temp_free_i64(tcg_final); @@ -12466,7 +12512,7 @@ static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u, } } if (!is_q) { - tcg_res[1] = tcg_const_i64(0); + tcg_res[1] = tcg_constant_i64(0); } for (pass = 0; pass < 2; pass++) { write_vec_element(s, tcg_res[pass], rd, pass, MO_64); @@ -12899,25 +12945,17 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x1c: /* FCVTAS */ case 0x3a: /* FCVTPS */ case 0x3b: /* FCVTZS */ - { - TCGv_i32 tcg_shift = tcg_const_i32(0); gen_helper_vfp_tosls(tcg_res, tcg_op, - tcg_shift, tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); + tcg_constant_i32(0), tcg_fpstatus); break; - } case 0x5a: /* FCVTNU */ case 0x5b: /* FCVTMU */ case 0x5c: /* FCVTAU */ case 0x7a: /* FCVTPU */ case 0x7b: /* FCVTZU */ - { - TCGv_i32 tcg_shift = tcg_const_i32(0); gen_helper_vfp_touls(tcg_res, tcg_op, - tcg_shift, tcg_fpstatus); - tcg_temp_free_i32(tcg_shift); + tcg_constant_i32(0), tcg_fpstatus); break; - } case 0x18: /* FRINTN */ case 0x19: /* FRINTM */ case 0x38: /* FRINTP */ @@ -14015,7 +14053,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } if (is_scalar) { - tcg_res[1] = tcg_const_i64(0); + tcg_res[1] = tcg_constant_i64(0); } for (pass = 0; pass < 2; pass++) { @@ -14419,7 +14457,7 @@ static void disas_crypto_four_reg(DisasContext *s, uint32_t insn) tcg_op2 = tcg_temp_new_i32(); tcg_op3 = tcg_temp_new_i32(); tcg_res = tcg_temp_new_i32(); - tcg_zero = tcg_const_i32(0); + tcg_zero = tcg_constant_i32(0); read_vec_element_i32(s, tcg_op1, rn, 3, MO_32); read_vec_element_i32(s, tcg_op2, rm, 3, MO_32); @@ -14439,7 +14477,6 @@ static void disas_crypto_four_reg(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_op2); tcg_temp_free_i32(tcg_op3); tcg_temp_free_i32(tcg_res); - tcg_temp_free_i32(tcg_zero); } } @@ -14568,6 +14605,23 @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn) } } +/* + * Include the generated SME FA64 decoder. + */ + +#include "decode-sme-fa64.c.inc" + +static bool trans_OK(DisasContext *s, arg_OK *a) +{ + return true; +} + +static bool trans_FAIL(DisasContext *s, arg_OK *a) +{ + s->is_nonstreaming = true; + return true; +} + /** * is_guarded_page: * @env: The cpu environment @@ -14581,22 +14635,21 @@ static bool is_guarded_page(CPUARMState *env, DisasContext *s) #ifdef CONFIG_USER_ONLY return page_get_flags(addr) & PAGE_BTI; #else + CPUTLBEntryFull *full; + void *host; int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx); - unsigned int index = tlb_index(env, mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); + int flags; /* * We test this immediately after reading an insn, which means - * that any normal page must be in the TLB. The only exception - * would be for executing from flash or device memory, which - * does not retain the TLB entry. - * - * FIXME: Assume false for those, for now. We could use - * arm_cpu_get_phys_page_attrs_debug to re-read the page - * table entry even for that case. + * that the TLB entry must be present and valid, and thus this + * access will never raise an exception. */ - return (tlb_hit(entry->addr_code, addr) && - arm_tlb_bti_gp(&env_tlb(env)->d[mmu_idx].iotlb[index].attrs)); + flags = probe_access_full(env, addr, MMU_INST_FETCH, mmu_idx, + false, &host, &full, 0); + assert(!(flags & TLB_INVALID_MASK)); + + return full->guarded; #endif } @@ -14663,14 +14716,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->isar = &arm_cpu->isar; dc->condjmp = 0; - - dc->aarch64 = 1; - /* If we are coming from secure EL0 in a system with a 32-bit EL3, then - * there is no secure EL1, so we route exceptions to EL3. - */ - dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) && - !arm_el_is_aa64(env, 3); - dc->thumb = 0; + dc->pc_save = dc->base.pc_first; + dc->aarch64 = true; + dc->thumb = false; dc->sctlr_b = 0; dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE; dc->condexec_mask = 0; @@ -14688,7 +14736,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); - dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16; + dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); + dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; + dc->svl = (EX_TBFLAG_A64(tb_flags, SVL) + 1) * 16; dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE); dc->bt = EX_TBFLAG_A64(tb_flags, BT); dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE); @@ -14696,6 +14746,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->ata = EX_TBFLAG_A64(tb_flags, ATA); dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE); dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE); + dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM); + dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA); + dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING); dc->vec_len = 0; dc->vec_stride = 0; dc->cp_regs = arm_cpu->cp_regs; @@ -14725,7 +14778,6 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE); dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS); dc->is_ldex = false; - dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL); /* Bound the number of insns to execute to those left on the page. */ bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; @@ -14746,8 +14798,12 @@ static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu) static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); + target_ulong pc_arg = dc->base.pc_next; - tcg_gen_insn_start(dc->base.pc_next, 0, 0); + if (TARGET_TB_PCREL) { + pc_arg &= ~TARGET_PAGE_MASK; + } + tcg_gen_insn_start(pc_arg, 0, 0); dc->insn_start = tcg_last_op(); } @@ -14804,8 +14860,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * Illegal execution state. This has priority over BTI * exceptions, but comes after instruction abort exceptions. */ - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_illegalstate(), default_exception_el(s)); + gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate()); return; } @@ -14836,9 +14891,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) if (s->btype != 0 && s->guarded_page && !btype_destination_ok(insn, s->bt, s->btype)) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_btitrap(s->btype), - default_exception_el(s)); + gen_exception_insn(s, 0, EXCP_UDEF, syn_btitrap(s->btype)); return; } } else { @@ -14847,12 +14900,22 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) } } + s->is_nonstreaming = false; + if (s->sme_trap_nonstreaming) { + disas_sme_fa64(s, insn); + } + switch (extract32(insn, 25, 4)) { - case 0x0: case 0x1: case 0x3: /* UNALLOCATED */ + case 0x0: + if (!extract32(insn, 31, 1) || !disas_sme(s, insn)) { + unallocated_encoding(s); + } + break; + case 0x1: case 0x3: /* UNALLOCATED */ unallocated_encoding(s); break; case 0x2: - if (!dc_isar_feature(aa64_sve, s) || !disas_sve(s, insn)) { + if (!disas_sve(s, insn)) { unallocated_encoding(s); } break; @@ -14907,7 +14970,7 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) */ switch (dc->base.is_jmp) { default: - gen_a64_set_pc_im(dc->base.pc_next); + gen_a64_update_pc(dc, 4); /* fall through */ case DISAS_EXIT: case DISAS_JUMP: @@ -14920,17 +14983,17 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) switch (dc->base.is_jmp) { case DISAS_NEXT: case DISAS_TOO_MANY: - gen_goto_tb(dc, 1, dc->base.pc_next); + gen_goto_tb(dc, 1, 4); break; default: case DISAS_UPDATE_EXIT: - gen_a64_set_pc_im(dc->base.pc_next); + gen_a64_update_pc(dc, 4); /* fall through */ case DISAS_EXIT: tcg_gen_exit_tb(NULL, 0); break; case DISAS_UPDATE_NOCHAIN: - gen_a64_set_pc_im(dc->base.pc_next); + gen_a64_update_pc(dc, 4); /* fall through */ case DISAS_JUMP: tcg_gen_lookup_and_goto_ptr(); @@ -14939,40 +15002,37 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_SWI: break; case DISAS_WFE: - gen_a64_set_pc_im(dc->base.pc_next); + gen_a64_update_pc(dc, 4); gen_helper_wfe(cpu_env); break; case DISAS_YIELD: - gen_a64_set_pc_im(dc->base.pc_next); + gen_a64_update_pc(dc, 4); gen_helper_yield(cpu_env); break; case DISAS_WFI: - { - /* This is a special case because we don't want to just halt the CPU - * if trying to debug across a WFI. + /* + * This is a special case because we don't want to just halt + * the CPU if trying to debug across a WFI. */ - TCGv_i32 tmp = tcg_const_i32(4); - - gen_a64_set_pc_im(dc->base.pc_next); - gen_helper_wfi(cpu_env, tmp); - tcg_temp_free_i32(tmp); - /* The helper doesn't necessarily throw an exception, but we + gen_a64_update_pc(dc, 4); + gen_helper_wfi(cpu_env, tcg_constant_i32(4)); + /* + * The helper doesn't necessarily throw an exception, but we * must go back to the main loop to check for interrupts anyway. */ tcg_gen_exit_tb(NULL, 0); break; } - } } } static void aarch64_tr_disas_log(const DisasContextBase *dcbase, - CPUState *cpu) + CPUState *cpu, FILE *logfile) { DisasContext *dc = container_of(dcbase, DisasContext, base); - qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first)); - log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first)); + target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size); } const TranslatorOps aarch64_translator_ops = { diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 58f50abca469..ad3762d1acfe 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -18,15 +18,6 @@ #ifndef TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H -#define unsupported_encoding(s, insn) \ - do { \ - qemu_log_mask(LOG_UNIMP, \ - "%s:%d: unsupported instruction encoding 0x%08x " \ - "at pc=%016" PRIx64 "\n", \ - __FILE__, __LINE__, insn, s->pc_curr); \ - unallocated_encoding(s); \ - } while (0) - TCGv_i64 new_tmp_a64(DisasContext *s); TCGv_i64 new_tmp_a64_local(DisasContext *s); TCGv_i64 new_tmp_a64_zero(DisasContext *s); @@ -38,6 +29,27 @@ void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v); bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, unsigned int imms, unsigned int immr); bool sve_access_check(DisasContext *s); +bool sme_enabled_check(DisasContext *s); +bool sme_enabled_check_with_svcr(DisasContext *s, unsigned); + +/* This function corresponds to CheckStreamingSVEEnabled. */ +static inline bool sme_sm_enabled_check(DisasContext *s) +{ + return sme_enabled_check_with_svcr(s, R_SVCR_SM_MASK); +} + +/* This function corresponds to CheckSMEAndZAEnabled. */ +static inline bool sme_za_enabled_check(DisasContext *s) +{ + return sme_enabled_check_with_svcr(s, R_SVCR_ZA_MASK); +} + +/* Note that this function corresponds to CheckStreamingSVEAndZAEnabled. */ +static inline bool sme_smza_enabled_check(DisasContext *s) +{ + return sme_enabled_check_with_svcr(s, R_SVCR_SM_MASK | R_SVCR_ZA_MASK); +} + TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr); TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, bool tag_checked, int log2_size); @@ -71,7 +83,7 @@ static inline int vec_reg_offset(DisasContext *s, int regno, { int element_size = 1 << size; int offs = element * element_size; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN /* This is complicated slightly because vfp.zregs[n].d[0] is * still the lowest and vfp.zregs[n].d[15] the highest of the * 256 byte vector, even on big endian systems. @@ -113,10 +125,69 @@ static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno) /* Return the byte size of the "whole" vector register, VL / 8. */ static inline int vec_full_reg_size(DisasContext *s) { - return s->sve_len; + return s->vl; +} + +/* Return the byte size of the vector register, SVL / 8. */ +static inline int streaming_vec_reg_size(DisasContext *s) +{ + return s->svl; +} + +/* + * Return the offset info CPUARMState of the predicate vector register Pn. + * Note for this purpose, FFR is P16. + */ +static inline int pred_full_reg_offset(DisasContext *s, int regno) +{ + return offsetof(CPUARMState, vfp.pregs[regno]); +} + +/* Return the byte size of the whole predicate register, VL / 64. */ +static inline int pred_full_reg_size(DisasContext *s) +{ + return s->vl >> 3; +} + +/* Return the byte size of the predicate register, SVL / 64. */ +static inline int streaming_pred_reg_size(DisasContext *s) +{ + return s->svl >> 3; +} + +/* + * Round up the size of a register to a size allowed by + * the tcg vector infrastructure. Any operation which uses this + * size may assume that the bits above pred_full_reg_size are zero, + * and must leave them the same way. + * + * Note that this is not needed for the vector registers as they + * are always properly sized for tcg vectors. + */ +static inline int size_for_gvec(int size) +{ + if (size <= 8) { + return 8; + } else { + return QEMU_ALIGN_UP(size, 16); + } +} + +static inline int pred_gvec_reg_size(DisasContext *s) +{ + return size_for_gvec(pred_full_reg_size(s)); +} + +/* Return a newly allocated pointer to the predicate register. */ +static inline TCGv_ptr pred_full_reg_ptr(DisasContext *s, int regno) +{ + TCGv_ptr ret = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(ret, cpu_env, pred_full_reg_offset(s, regno)); + return ret; } bool disas_sve(DisasContext *, uint32_t); +bool disas_sme(DisasContext *, uint32_t); void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); @@ -124,4 +195,7 @@ void gen_gvec_xar(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_sve_ldr(DisasContext *s, TCGv_ptr, int vofs, int len, int rn, int imm); +void gen_sve_str(DisasContext *s, TCGv_ptr, int vofs, int len, int rn, int imm); + #endif /* TARGET_ARM_TRANSLATE_A64_H */ diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c index d9e144e8eb37..5df7d4612098 100644 --- a/target/arm/translate-m-nocp.c +++ b/target/arm/translate-m-nocp.c @@ -140,11 +140,11 @@ static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); tcg_gen_or_i32(sfpa, sfpa, aspen); arm_gen_condlabel(s); - tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel); + tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel.label); if (s->fp_excp_el != 0) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); + gen_exception_insn_el(s, 0, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); return true; } @@ -173,7 +173,7 @@ static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) } /* Zero the Sregs from btmreg to topreg inclusive. */ - zero = tcg_const_i64(0); + zero = tcg_constant_i64(0); if (btmreg & 1) { write_neon_element64(zero, btmreg >> 1, 1, MO_32); btmreg++; @@ -187,8 +187,7 @@ static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) } assert(btmreg == topreg + 1); if (dc_isar_feature(aa32_mve, s)) { - TCGv_i32 z32 = tcg_const_i32(0); - store_cpu_field(z32, v7m.vpr); + store_cpu_field(tcg_constant_i32(0), v7m.vpr); } clear_eci_state(s); @@ -377,7 +376,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno, if (!vfp_access_check_m(s, true)) { /* * This was only a conditional exception, so override - * gen_exception_insn()'s default to DISAS_NORETURN + * gen_exception_insn_el()'s default to DISAS_NORETURN */ s->base.is_jmp = DISAS_NEXT; break; @@ -512,7 +511,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, } case ARM_VFP_FPCXT_NS: { - TCGv_i32 control, sfpa, fpscr, fpdscr, zero; + TCGv_i32 control, sfpa, fpscr, fpdscr; TCGLabel *lab_active = gen_new_label(); lookup_tb = true; @@ -533,7 +532,7 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, if (!vfp_access_check_m(s, true)) { /* * This was only a conditional exception, so override - * gen_exception_insn()'s default to DISAS_NORETURN + * gen_exception_insn_el()'s default to DISAS_NORETURN */ s->base.is_jmp = DISAS_NEXT; break; @@ -552,10 +551,9 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, storefn(s, opaque, tmp, true); /* If SFPA is zero then set FPSCR from FPDSCR_NS */ fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); - zero = tcg_const_i32(0); - tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, zero, fpdscr, fpscr); + tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, tcg_constant_i32(0), + fpdscr, fpscr); gen_helper_vfp_set_fpscr(cpu_env, fpscr); - tcg_temp_free_i32(zero); tcg_temp_free_i32(sfpa); tcg_temp_free_i32(fpdscr); tcg_temp_free_i32(fpscr); @@ -767,14 +765,13 @@ static bool trans_NOCP(DisasContext *s, arg_nocp *a) } if (a->cp != 10) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), default_exception_el(s)); + gen_exception_insn(s, 0, EXCP_NOCP, syn_uncategorized()); return true; } if (s->fp_excp_el != 0) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); + gen_exception_insn_el(s, 0, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); return true; } diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c index 4267d43cc7c4..db7ea3f6038e 100644 --- a/target/arm/translate-mve.c +++ b/target/arm/translate-mve.c @@ -100,8 +100,7 @@ bool mve_eci_check(DisasContext *s) return true; default: /* Reserved value: INVSTATE UsageFault */ - gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), - default_exception_el(s)); + gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized()); return false; } } diff --git a/target/arm/translate-neon.c b/target/arm/translate-neon.c index 384604c0095a..4016339d46f8 100644 --- a/target/arm/translate-neon.c +++ b/target/arm/translate-neon.c @@ -447,7 +447,7 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) int mmu_idx = get_mem_index(s); int size = a->size; TCGv_i64 tmp64; - TCGv_i32 addr, tmp; + TCGv_i32 addr; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return false; @@ -513,7 +513,6 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) tmp64 = tcg_temp_new_i64(); addr = tcg_temp_new_i32(); - tmp = tcg_const_i32(1 << size); load_reg_var(s, addr, a->rn); mop = endian | size | align; @@ -530,7 +529,7 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) neon_load_element64(tmp64, tt, n, size); gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop); } - tcg_gen_add_i32(addr, addr, tmp); + tcg_gen_addi_i32(addr, addr, 1 << size); /* Subsequent memory operations inherit alignment */ mop &= ~MO_AMASK; @@ -538,7 +537,6 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) } } tcg_temp_free_i32(addr); - tcg_temp_free_i32(tmp); tcg_temp_free_i64(tmp64); gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); @@ -586,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(); @@ -681,7 +683,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) } break; default: - abort(); + g_assert_not_reached(); } if ((vd + a->stride * (nregs - 1)) > 31) { /* @@ -1348,7 +1350,7 @@ static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, * To avoid excessive duplication of ops we implement shift * by immediate using the variable shift operations. */ - constimm = tcg_const_i64(dup_const(a->size, a->shift)); + constimm = tcg_constant_i64(dup_const(a->size, a->shift)); for (pass = 0; pass < a->q + 1; pass++) { TCGv_i64 tmp = tcg_temp_new_i64(); @@ -1358,7 +1360,6 @@ static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, write_neon_element64(tmp, a->vd, pass, MO_64); tcg_temp_free_i64(tmp); } - tcg_temp_free_i64(constimm); return true; } @@ -1394,7 +1395,7 @@ static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, * To avoid excessive duplication of ops we implement shift * by immediate using the variable shift operations. */ - constimm = tcg_const_i32(dup_const(a->size, a->shift)); + constimm = tcg_constant_i32(dup_const(a->size, a->shift)); tmp = tcg_temp_new_i32(); for (pass = 0; pass < (a->q ? 4 : 2); pass++) { @@ -1403,7 +1404,6 @@ static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, write_neon_element32(tmp, a->vd, pass, MO_32); } tcg_temp_free_i32(tmp); - tcg_temp_free_i32(constimm); return true; } @@ -1457,7 +1457,7 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, * This is always a right shift, and the shiftfn is always a * left-shift helper, which thus needs the negated shift count. */ - constimm = tcg_const_i64(-a->shift); + constimm = tcg_constant_i64(-a->shift); rm1 = tcg_temp_new_i64(); rm2 = tcg_temp_new_i64(); rd = tcg_temp_new_i32(); @@ -1477,7 +1477,6 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, tcg_temp_free_i32(rd); tcg_temp_free_i64(rm1); tcg_temp_free_i64(rm2); - tcg_temp_free_i64(constimm); return true; } @@ -1521,7 +1520,7 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, /* size == 2 */ imm = -a->shift; } - constimm = tcg_const_i32(imm); + constimm = tcg_constant_i32(imm); /* Load all inputs first to avoid potential overwrite */ rm1 = tcg_temp_new_i32(); @@ -1546,7 +1545,6 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, shiftfn(rm3, rm3, constimm); shiftfn(rm4, rm4, constimm); - tcg_temp_free_i32(constimm); tcg_gen_concat_i32_i64(rtmp, rm3, rm4); tcg_temp_free_i32(rm4); @@ -2911,7 +2909,7 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a) return true; } - desc = tcg_const_i32((a->vn << 2) | a->len); + desc = tcg_constant_i32((a->vn << 2) | a->len); def = tcg_temp_new_i64(); if (a->op) { read_neon_element64(def, a->vd, 0, MO_64); @@ -2926,7 +2924,6 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a) tcg_temp_free_i64(def); tcg_temp_free_i64(val); - tcg_temp_free_i32(desc); return true; } diff --git a/target/arm/translate-sme.c b/target/arm/translate-sme.c new file mode 100644 index 000000000000..7b87a9df63c1 --- /dev/null +++ b/target/arm/translate-sme.c @@ -0,0 +1,373 @@ +/* + * AArch64 SME translation + * + * Copyright (c) 2022 Linaro, Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg-gvec-desc.h" +#include "translate.h" +#include "exec/helper-gen.h" +#include "translate-a64.h" +#include "fpu/softfloat.h" + + +/* + * Include the generated decoder. + */ + +#include "decode-sme.c.inc" + + +/* + * Resolve tile.size[index] to a host pointer, where tile and index + * are always decoded together, dependent on the element size. + */ +static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs, + int tile_index, bool vertical) +{ + int tile = tile_index >> (4 - esz); + int index = esz == MO_128 ? 0 : extract32(tile_index, 0, 4 - esz); + int pos, len, offset; + TCGv_i32 tmp; + TCGv_ptr addr; + + /* Compute the final index, which is Rs+imm. */ + tmp = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(tmp, cpu_reg(s, rs)); + tcg_gen_addi_i32(tmp, tmp, index); + + /* Prepare a power-of-two modulo via extraction of @len bits. */ + len = ctz32(streaming_vec_reg_size(s)) - esz; + + if (vertical) { + /* + * Compute the byte offset of the index within the tile: + * (index % (svl / size)) * size + * = (index % (svl >> esz)) << esz + * Perform the power-of-two modulo via extraction of the low @len bits. + * Perform the multiply by shifting left by @pos bits. + * Perform these operations simultaneously via deposit into zero. + */ + pos = esz; + tcg_gen_deposit_z_i32(tmp, tmp, pos, len); + + /* + * For big-endian, adjust the indexed column byte offset within + * the uint64_t host words that make up env->zarray[]. + */ + if (HOST_BIG_ENDIAN && esz < MO_64) { + tcg_gen_xori_i32(tmp, tmp, 8 - (1 << esz)); + } + } else { + /* + * Compute the byte offset of the index within the tile: + * (index % (svl / size)) * (size * sizeof(row)) + * = (index % (svl >> esz)) << (esz + log2(sizeof(row))) + */ + pos = esz + ctz32(sizeof(ARMVectorReg)); + tcg_gen_deposit_z_i32(tmp, tmp, pos, len); + + /* Row slices are always aligned and need no endian adjustment. */ + } + + /* The tile byte offset within env->zarray is the row. */ + offset = tile * sizeof(ARMVectorReg); + + /* Include the byte offset of zarray to make this relative to env. */ + offset += offsetof(CPUARMState, zarray); + tcg_gen_addi_i32(tmp, tmp, offset); + + /* Add the byte offset to env to produce the final pointer. */ + addr = tcg_temp_new_ptr(); + tcg_gen_ext_i32_ptr(addr, tmp); + tcg_temp_free_i32(tmp); + tcg_gen_add_ptr(addr, addr, cpu_env); + + return addr; +} + +static bool trans_ZERO(DisasContext *s, arg_ZERO *a) +{ + if (!dc_isar_feature(aa64_sme, s)) { + return false; + } + if (sme_za_enabled_check(s)) { + gen_helper_sme_zero(cpu_env, tcg_constant_i32(a->imm), + tcg_constant_i32(streaming_vec_reg_size(s))); + } + return true; +} + +static bool trans_MOVA(DisasContext *s, arg_MOVA *a) +{ + static gen_helper_gvec_4 * const h_fns[5] = { + gen_helper_sve_sel_zpzz_b, gen_helper_sve_sel_zpzz_h, + gen_helper_sve_sel_zpzz_s, gen_helper_sve_sel_zpzz_d, + gen_helper_sve_sel_zpzz_q + }; + static gen_helper_gvec_3 * const cz_fns[5] = { + gen_helper_sme_mova_cz_b, gen_helper_sme_mova_cz_h, + gen_helper_sme_mova_cz_s, gen_helper_sme_mova_cz_d, + gen_helper_sme_mova_cz_q, + }; + static gen_helper_gvec_3 * const zc_fns[5] = { + gen_helper_sme_mova_zc_b, gen_helper_sme_mova_zc_h, + gen_helper_sme_mova_zc_s, gen_helper_sme_mova_zc_d, + gen_helper_sme_mova_zc_q, + }; + + TCGv_ptr t_za, t_zr, t_pg; + TCGv_i32 t_desc; + int svl; + + if (!dc_isar_feature(aa64_sme, s)) { + return false; + } + if (!sme_smza_enabled_check(s)) { + return true; + } + + t_za = get_tile_rowcol(s, a->esz, a->rs, a->za_imm, a->v); + t_zr = vec_full_reg_ptr(s, a->zr); + t_pg = pred_full_reg_ptr(s, a->pg); + + svl = streaming_vec_reg_size(s); + t_desc = tcg_constant_i32(simd_desc(svl, svl, 0)); + + if (a->v) { + /* Vertical slice -- use sme mova helpers. */ + if (a->to_vec) { + zc_fns[a->esz](t_zr, t_za, t_pg, t_desc); + } else { + cz_fns[a->esz](t_za, t_zr, t_pg, t_desc); + } + } else { + /* Horizontal slice -- reuse sve sel helpers. */ + if (a->to_vec) { + h_fns[a->esz](t_zr, t_za, t_zr, t_pg, t_desc); + } else { + h_fns[a->esz](t_za, t_zr, t_za, t_pg, t_desc); + } + } + + tcg_temp_free_ptr(t_za); + tcg_temp_free_ptr(t_zr); + tcg_temp_free_ptr(t_pg); + + return true; +} + +static bool trans_LDST1(DisasContext *s, arg_LDST1 *a) +{ + typedef void GenLdSt1(TCGv_env, TCGv_ptr, TCGv_ptr, TCGv, TCGv_i32); + + /* + * Indexed by [esz][be][v][mte][st], which is (except for load/store) + * also the order in which the elements appear in the function names, + * and so how we must concatenate the pieces. + */ + +#define FN_LS(F) { gen_helper_sme_ld1##F, gen_helper_sme_st1##F } +#define FN_MTE(F) { FN_LS(F), FN_LS(F##_mte) } +#define FN_HV(F) { FN_MTE(F##_h), FN_MTE(F##_v) } +#define FN_END(L, B) { FN_HV(L), FN_HV(B) } + + static GenLdSt1 * const fns[5][2][2][2][2] = { + FN_END(b, b), + FN_END(h_le, h_be), + FN_END(s_le, s_be), + FN_END(d_le, d_be), + FN_END(q_le, q_be), + }; + +#undef FN_LS +#undef FN_MTE +#undef FN_HV +#undef FN_END + + TCGv_ptr t_za, t_pg; + TCGv_i64 addr; + int svl, desc = 0; + bool be = s->be_data == MO_BE; + bool mte = s->mte_active[0]; + + if (!dc_isar_feature(aa64_sme, s)) { + return false; + } + if (!sme_smza_enabled_check(s)) { + return true; + } + + t_za = get_tile_rowcol(s, a->esz, a->rs, a->za_imm, a->v); + t_pg = pred_full_reg_ptr(s, a->pg); + addr = tcg_temp_new_i64(); + + tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), a->esz); + tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, a->rn)); + + if (mte) { + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, a->st); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << a->esz) - 1); + desc <<= SVE_MTEDESC_SHIFT; + } else { + addr = clean_data_tbi(s, addr); + } + svl = streaming_vec_reg_size(s); + desc = simd_desc(svl, svl, desc); + + fns[a->esz][be][a->v][mte][a->st](cpu_env, t_za, t_pg, addr, + tcg_constant_i32(desc)); + + tcg_temp_free_ptr(t_za); + tcg_temp_free_ptr(t_pg); + tcg_temp_free_i64(addr); + return true; +} + +typedef void GenLdStR(DisasContext *, TCGv_ptr, int, int, int, int); + +static bool do_ldst_r(DisasContext *s, arg_ldstr *a, GenLdStR *fn) +{ + int svl = streaming_vec_reg_size(s); + int imm = a->imm; + TCGv_ptr base; + + if (!sme_za_enabled_check(s)) { + return true; + } + + /* ZA[n] equates to ZA0H.B[n]. */ + base = get_tile_rowcol(s, MO_8, a->rv, imm, false); + + fn(s, base, 0, svl, a->rn, imm * svl); + + tcg_temp_free_ptr(base); + return true; +} + +TRANS_FEAT(LDR, aa64_sme, do_ldst_r, a, gen_sve_ldr) +TRANS_FEAT(STR, aa64_sme, do_ldst_r, a, gen_sve_str) + +static bool do_adda(DisasContext *s, arg_adda *a, MemOp esz, + gen_helper_gvec_4 *fn) +{ + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, 0); + TCGv_ptr za, zn, pn, pm; + + if (!sme_smza_enabled_check(s)) { + return true; + } + + /* Sum XZR+zad to find ZAd. */ + za = get_tile_rowcol(s, esz, 31, a->zad, false); + zn = vec_full_reg_ptr(s, a->zn); + pn = pred_full_reg_ptr(s, a->pn); + pm = pred_full_reg_ptr(s, a->pm); + + fn(za, zn, pn, pm, tcg_constant_i32(desc)); + + tcg_temp_free_ptr(za); + tcg_temp_free_ptr(zn); + tcg_temp_free_ptr(pn); + tcg_temp_free_ptr(pm); + return true; +} + +TRANS_FEAT(ADDHA_s, aa64_sme, do_adda, a, MO_32, gen_helper_sme_addha_s) +TRANS_FEAT(ADDVA_s, aa64_sme, do_adda, a, MO_32, gen_helper_sme_addva_s) +TRANS_FEAT(ADDHA_d, aa64_sme_i16i64, do_adda, a, MO_64, gen_helper_sme_addha_d) +TRANS_FEAT(ADDVA_d, aa64_sme_i16i64, do_adda, a, MO_64, gen_helper_sme_addva_d) + +static bool do_outprod(DisasContext *s, arg_op *a, MemOp esz, + gen_helper_gvec_5 *fn) +{ + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, a->sub); + TCGv_ptr za, zn, zm, pn, pm; + + if (!sme_smza_enabled_check(s)) { + return true; + } + + /* Sum XZR+zad to find ZAd. */ + za = get_tile_rowcol(s, esz, 31, a->zad, false); + zn = vec_full_reg_ptr(s, a->zn); + zm = vec_full_reg_ptr(s, a->zm); + pn = pred_full_reg_ptr(s, a->pn); + pm = pred_full_reg_ptr(s, a->pm); + + fn(za, zn, zm, pn, pm, tcg_constant_i32(desc)); + + tcg_temp_free_ptr(za); + tcg_temp_free_ptr(zn); + tcg_temp_free_ptr(pn); + tcg_temp_free_ptr(pm); + return true; +} + +static bool do_outprod_fpst(DisasContext *s, arg_op *a, MemOp esz, + gen_helper_gvec_5_ptr *fn) +{ + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, a->sub); + TCGv_ptr za, zn, zm, pn, pm, fpst; + + if (!sme_smza_enabled_check(s)) { + return true; + } + + /* Sum XZR+zad to find ZAd. */ + za = get_tile_rowcol(s, esz, 31, a->zad, false); + zn = vec_full_reg_ptr(s, a->zn); + zm = vec_full_reg_ptr(s, a->zm); + pn = pred_full_reg_ptr(s, a->pn); + pm = pred_full_reg_ptr(s, a->pm); + fpst = fpstatus_ptr(FPST_FPCR); + + fn(za, zn, zm, pn, pm, fpst, tcg_constant_i32(desc)); + + tcg_temp_free_ptr(za); + tcg_temp_free_ptr(zn); + tcg_temp_free_ptr(pn); + tcg_temp_free_ptr(pm); + tcg_temp_free_ptr(fpst); + return true; +} + +TRANS_FEAT(FMOPA_h, aa64_sme, do_outprod_fpst, a, MO_32, gen_helper_sme_fmopa_h) +TRANS_FEAT(FMOPA_s, aa64_sme, do_outprod_fpst, a, MO_32, gen_helper_sme_fmopa_s) +TRANS_FEAT(FMOPA_d, aa64_sme_f64f64, do_outprod_fpst, a, MO_64, gen_helper_sme_fmopa_d) + +/* TODO: FEAT_EBF16 */ +TRANS_FEAT(BFMOPA, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_bfmopa) + +TRANS_FEAT(SMOPA_s, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_smopa_s) +TRANS_FEAT(UMOPA_s, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_umopa_s) +TRANS_FEAT(SUMOPA_s, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_sumopa_s) +TRANS_FEAT(USMOPA_s, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_usmopa_s) + +TRANS_FEAT(SMOPA_d, aa64_sme_i16i64, do_outprod, a, MO_64, gen_helper_sme_smopa_d) +TRANS_FEAT(UMOPA_d, aa64_sme_i16i64, do_outprod, a, MO_64, gen_helper_sme_umopa_d) +TRANS_FEAT(SUMOPA_d, aa64_sme_i16i64, do_outprod, a, MO_64, gen_helper_sme_sumopa_d) +TRANS_FEAT(USMOPA_d, aa64_sme_i16i64, do_outprod, a, MO_64, gen_helper_sme_usmopa_d) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2c23459e7684..621a2abb22f2 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -100,133 +100,363 @@ static inline int msz_dtype(DisasContext *s, int msz) * Implement all of the translator functions referenced by the decoder. */ -/* Return the offset info CPUARMState of the predicate vector register Pn. - * Note for this purpose, FFR is P16. - */ -static inline int pred_full_reg_offset(DisasContext *s, int regno) +/* Invoke an out-of-line helper on 2 Zregs. */ +static bool gen_gvec_ool_zz(DisasContext *s, gen_helper_gvec_2 *fn, + int rd, int rn, int data) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vsz, vsz, data, fn); + } + return true; +} + +static bool gen_gvec_fpst_zz(DisasContext *s, gen_helper_gvec_2_ptr *fn, + int rd, int rn, int data, + ARMFPStatusFlavour flavour) { - return offsetof(CPUARMState, vfp.pregs[regno]); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + status, vsz, vsz, data, fn); + tcg_temp_free_ptr(status); + } + return true; } -/* Return the byte size of the whole predicate register, VL / 64. */ -static inline int pred_full_reg_size(DisasContext *s) +static bool gen_gvec_fpst_arg_zz(DisasContext *s, gen_helper_gvec_2_ptr *fn, + arg_rr_esz *a, int data) { - return s->sve_len >> 3; + return gen_gvec_fpst_zz(s, fn, a->rd, a->rn, data, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } -/* Round up the size of a register to a size allowed by - * the tcg vector infrastructure. Any operation which uses this - * size may assume that the bits above pred_full_reg_size are zero, - * and must leave them the same way. - * - * Note that this is not needed for the vector registers as they - * are always properly sized for tcg vectors. - */ -static int size_for_gvec(int size) +/* Invoke an out-of-line helper on 3 Zregs. */ +static bool gen_gvec_ool_zzz(DisasContext *s, gen_helper_gvec_3 *fn, + int rd, int rn, int rm, int data) { - if (size <= 8) { - return 8; - } else { - return QEMU_ALIGN_UP(size, 16); + if (fn == NULL) { + return false; } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vsz, vsz, data, fn); + } + return true; } -static int pred_gvec_reg_size(DisasContext *s) +static bool gen_gvec_ool_arg_zzz(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rrr_esz *a, int data) { - return size_for_gvec(pred_full_reg_size(s)); + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); } -/* Invoke an out-of-line helper on 2 Zregs. */ -static void gen_gvec_ool_zz(DisasContext *s, gen_helper_gvec_2 *fn, - int rd, int rn, int data) +/* Invoke an out-of-line helper on 3 Zregs, plus float_status. */ +static bool gen_gvec_fpst_zzz(DisasContext *s, gen_helper_gvec_3_ptr *fn, + int rd, int rn, int rm, + int data, ARMFPStatusFlavour flavour) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + status, vsz, vsz, data, fn); + + tcg_temp_free_ptr(status); + } + return true; } -/* Invoke an out-of-line helper on 3 Zregs. */ -static void gen_gvec_ool_zzz(DisasContext *s, gen_helper_gvec_3 *fn, - int rd, int rn, int rm, int data) +static bool gen_gvec_fpst_arg_zzz(DisasContext *s, gen_helper_gvec_3_ptr *fn, + arg_rrr_esz *a, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vsz, vsz, data, fn); + return gen_gvec_fpst_zzz(s, fn, a->rd, a->rn, a->rm, data, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } /* Invoke an out-of-line helper on 4 Zregs. */ -static void gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, +static bool gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int ra, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vec_full_reg_offset(s, ra), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vec_full_reg_offset(s, ra), + vsz, vsz, data, fn); + } + return true; +} + +static bool gen_gvec_ool_arg_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, + arg_rrrr_esz *a, int data) +{ + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); +} + +static bool gen_gvec_ool_arg_zzxz(DisasContext *s, gen_helper_gvec_4 *fn, + arg_rrxr_esz *a) +{ + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); +} + +/* Invoke an out-of-line helper on 4 Zregs, plus a pointer. */ +static bool gen_gvec_ptr_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, + int rd, int rn, int rm, int ra, + int data, TCGv_ptr ptr) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vec_full_reg_offset(s, ra), + ptr, vsz, vsz, data, fn); + } + return true; +} + +static bool gen_gvec_fpst_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, + int rd, int rn, int rm, int ra, + int data, ARMFPStatusFlavour flavour) +{ + TCGv_ptr status = fpstatus_ptr(flavour); + bool ret = gen_gvec_ptr_zzzz(s, fn, rd, rn, rm, ra, data, status); + tcg_temp_free_ptr(status); + return ret; +} + +/* Invoke an out-of-line helper on 4 Zregs, 1 Preg, plus fpst. */ +static bool gen_gvec_fpst_zzzzp(DisasContext *s, gen_helper_gvec_5_ptr *fn, + int rd, int rn, int rm, int ra, int pg, + int data, ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vec_full_reg_offset(s, ra), + pred_full_reg_offset(s, pg), + status, vsz, vsz, data, fn); + + tcg_temp_free_ptr(status); + } + return true; } /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ -static void gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, +static bool gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int pg, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - pred_full_reg_offset(s, pg), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + pred_full_reg_offset(s, pg), + vsz, vsz, data, fn); + } + return true; +} + +static bool gen_gvec_ool_arg_zpz(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rpr_esz *a, int data) +{ + return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, data); +} + +static bool gen_gvec_ool_arg_zpzi(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rpri_esz *a) +{ + return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); +} + +static bool gen_gvec_fpst_zzp(DisasContext *s, gen_helper_gvec_3_ptr *fn, + int rd, int rn, int pg, int data, + ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + pred_full_reg_offset(s, pg), + status, vsz, vsz, data, fn); + tcg_temp_free_ptr(status); + } + return true; +} + +static bool gen_gvec_fpst_arg_zpz(DisasContext *s, gen_helper_gvec_3_ptr *fn, + arg_rpr_esz *a, int data, + ARMFPStatusFlavour flavour) +{ + return gen_gvec_fpst_zzp(s, fn, a->rd, a->rn, a->pg, data, flavour); } /* Invoke an out-of-line helper on 3 Zregs and a predicate. */ -static void gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, +static bool gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int pg, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - pred_full_reg_offset(s, pg), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + pred_full_reg_offset(s, pg), + vsz, vsz, data, fn); + } + return true; } -/* Invoke a vector expander on two Zregs. */ -static void gen_gvec_fn_zz(DisasContext *s, GVecGen2Fn *gvec_fn, - int esz, int rd, int rn) +static bool gen_gvec_ool_arg_zpzz(DisasContext *s, gen_helper_gvec_4 *fn, + arg_rprr_esz *a, int data) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(esz, vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), vsz, vsz); + return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, data); +} + +/* Invoke an out-of-line helper on 3 Zregs and a predicate. */ +static bool gen_gvec_fpst_zzzp(DisasContext *s, gen_helper_gvec_4_ptr *fn, + int rd, int rn, int rm, int pg, int data, + ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + pred_full_reg_offset(s, pg), + status, vsz, vsz, data, fn); + tcg_temp_free_ptr(status); + } + return true; +} + +static bool gen_gvec_fpst_arg_zpzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, + arg_rprr_esz *a) +{ + return gen_gvec_fpst_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, 0, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +} + +/* Invoke a vector expander on two Zregs and an immediate. */ +static bool gen_gvec_fn_zzi(DisasContext *s, GVecGen2iFn *gvec_fn, + int esz, int rd, int rn, uint64_t imm) +{ + if (gvec_fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + gvec_fn(esz, vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), imm, vsz, vsz); + } + return true; +} + +static bool gen_gvec_fn_arg_zzi(DisasContext *s, GVecGen2iFn *gvec_fn, + arg_rri_esz *a) +{ + if (a->esz < 0) { + /* Invalid tsz encoding -- see tszimm_esz. */ + return false; + } + return gen_gvec_fn_zzi(s, gvec_fn, a->esz, a->rd, a->rn, a->imm); } /* Invoke a vector expander on three Zregs. */ -static void gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, +static bool gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, int esz, int rd, int rn, int rm) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(esz, vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), vsz, vsz); + if (gvec_fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + gvec_fn(esz, vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), vsz, vsz); + } + return true; +} + +static bool gen_gvec_fn_arg_zzz(DisasContext *s, GVecGen3Fn *fn, + arg_rrr_esz *a) +{ + return gen_gvec_fn_zzz(s, fn, a->esz, a->rd, a->rn, a->rm); } /* Invoke a vector expander on four Zregs. */ -static void gen_gvec_fn_zzzz(DisasContext *s, GVecGen4Fn *gvec_fn, - int esz, int rd, int rn, int rm, int ra) +static bool gen_gvec_fn_arg_zzzz(DisasContext *s, GVecGen4Fn *gvec_fn, + arg_rrrr_esz *a) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(esz, vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vec_full_reg_offset(s, ra), vsz, vsz); + if (gvec_fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + gvec_fn(a->esz, vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vec_full_reg_offset(s, a->ra), vsz, vsz); + } + return true; } /* Invoke a vector move on two Zregs. */ static bool do_mov_z(DisasContext *s, int rd, int rn) { if (sve_access_check(s)) { - gen_gvec_fn_zz(s, tcg_gen_gvec_mov, MO_8, rd, rn); + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_mov(MO_8, vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), vsz, vsz); } return true; } @@ -239,13 +469,16 @@ static void do_dupi_z(DisasContext *s, int rd, uint64_t word) } /* Invoke a vector expander on three Pregs. */ -static void gen_gvec_fn_ppp(DisasContext *s, GVecGen3Fn *gvec_fn, +static bool gen_gvec_fn_ppp(DisasContext *s, GVecGen3Fn *gvec_fn, int rd, int rn, int rm) { - unsigned psz = pred_gvec_reg_size(s); - gvec_fn(MO_64, pred_full_reg_offset(s, rd), - pred_full_reg_offset(s, rn), - pred_full_reg_offset(s, rm), psz, psz); + if (sve_access_check(s)) { + unsigned psz = pred_gvec_reg_size(s); + gvec_fn(MO_64, pred_full_reg_offset(s, rd), + pred_full_reg_offset(s, rn), + pred_full_reg_offset(s, rm), psz, psz); + } + return true; } /* Invoke a vector move on two Pregs. */ @@ -282,13 +515,12 @@ static void do_predtest(DisasContext *s, int dofs, int gofs, int words) { TCGv_ptr dptr = tcg_temp_new_ptr(); TCGv_ptr gptr = tcg_temp_new_ptr(); - TCGv_i32 t; + TCGv_i32 t = tcg_temp_new_i32(); tcg_gen_addi_ptr(dptr, cpu_env, dofs); tcg_gen_addi_ptr(gptr, cpu_env, gofs); - t = tcg_const_i32(words); - gen_helper_sve_predtest(t, dptr, gptr, t); + gen_helper_sve_predtest(t, dptr, gptr, tcg_constant_i32(words)); tcg_temp_free_ptr(dptr); tcg_temp_free_ptr(gptr); @@ -297,42 +529,26 @@ 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, }; -/* - *** SVE Logical - Unpredicated Group - */ - -static bool do_zzz_fn(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *gvec_fn) +static bool trans_INVALID(DisasContext *s, arg_INVALID *a) { - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, gvec_fn, a->esz, a->rd, a->rn, a->rm); - } + unallocated_encoding(s); return true; } -static bool trans_AND_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_and); -} - -static bool trans_ORR_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_or); -} - -static bool trans_EOR_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_xor); -} +/* + *** SVE Logical - Unpredicated Group + */ -static bool trans_BIC_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_andc); -} +TRANS_FEAT(AND_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_and, a) +TRANS_FEAT(ORR_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_or, a) +TRANS_FEAT(EOR_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_xor, a) +TRANS_FEAT(BIC_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_andc, a) static void gen_xar8_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, int64_t sh) { @@ -438,17 +654,6 @@ static bool trans_XAR(DisasContext *s, arg_rrri_esz *a) return true; } -static bool do_sve2_zzzz_fn(DisasContext *s, arg_rrrr_esz *a, GVecGen4Fn *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_fn_zzzz(s, fn, a->esz, a->rd, a->rn, a->rm, a->ra); - } - return true; -} - static void gen_eor3_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { tcg_gen_xor_i64(d, n, m); @@ -475,10 +680,7 @@ static void gen_eor3(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_EOR3(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_eor3); -} +TRANS_FEAT(EOR3, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_eor3, a) static void gen_bcax_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -506,10 +708,7 @@ static void gen_bcax(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_BCAX(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bcax); -} +TRANS_FEAT(BCAX, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bcax, a) static void gen_bsl(unsigned vece, uint32_t d, uint32_t n, uint32_t m, uint32_t a, uint32_t oprsz, uint32_t maxsz) @@ -518,10 +717,7 @@ static void gen_bsl(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_bitsel(vece, d, a, n, m, oprsz, maxsz); } -static bool trans_BSL(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bsl); -} +TRANS_FEAT(BSL, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bsl, a) static void gen_bsl1n_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -556,10 +752,7 @@ static void gen_bsl1n(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_BSL1N(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bsl1n); -} +TRANS_FEAT(BSL1N, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bsl1n, a) static void gen_bsl2n_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -603,10 +796,7 @@ static void gen_bsl2n(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_BSL2N(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bsl2n); -} +TRANS_FEAT(BSL2N, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bsl2n, a) static void gen_nbsl_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -635,239 +825,136 @@ static void gen_nbsl(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_NBSL(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_nbsl); -} +TRANS_FEAT(NBSL, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_nbsl, a) /* *** SVE Integer Arithmetic - Unpredicated Group */ -static bool trans_ADD_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_add); -} - -static bool trans_SUB_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_sub); -} - -static bool trans_SQADD_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_ssadd); -} - -static bool trans_SQSUB_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_sssub); -} - -static bool trans_UQADD_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_usadd); -} - -static bool trans_UQSUB_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_fn(s, a, tcg_gen_gvec_ussub); -} +TRANS_FEAT(ADD_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_add, a) +TRANS_FEAT(SUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_sub, a) +TRANS_FEAT(SQADD_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_ssadd, a) +TRANS_FEAT(SQSUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_sssub, a) +TRANS_FEAT(UQADD_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_usadd, a) +TRANS_FEAT(UQSUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_ussub, a) /* *** SVE Integer Arithmetic - Binary Predicated Group */ -static bool do_zpzz_ool(DisasContext *s, arg_rprr_esz *a, gen_helper_gvec_4 *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, 0); - } - return true; -} - /* Select active elememnts from Zn and inactive elements from Zm, * storing the result in Zd. */ -static void do_sel_z(DisasContext *s, int rd, int rn, int rm, int pg, int esz) +static bool do_sel_z(DisasContext *s, int rd, int rn, int rm, int pg, int esz) { static gen_helper_gvec_4 * const fns[4] = { gen_helper_sve_sel_zpzz_b, gen_helper_sve_sel_zpzz_h, gen_helper_sve_sel_zpzz_s, gen_helper_sve_sel_zpzz_d }; - gen_gvec_ool_zzzp(s, fns[esz], rd, rn, rm, pg, 0); + return gen_gvec_ool_zzzp(s, fns[esz], rd, rn, rm, pg, 0); } -#define DO_ZPZZ(NAME, name) \ -static bool trans_##NAME##_zpzz(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4 * const fns[4] = { \ - gen_helper_sve_##name##_zpzz_b, gen_helper_sve_##name##_zpzz_h, \ - gen_helper_sve_##name##_zpzz_s, gen_helper_sve_##name##_zpzz_d, \ +#define DO_ZPZZ(NAME, FEAT, name) \ + static gen_helper_gvec_4 * const name##_zpzz_fns[4] = { \ + gen_helper_##name##_zpzz_b, gen_helper_##name##_zpzz_h, \ + gen_helper_##name##_zpzz_s, gen_helper_##name##_zpzz_d, \ }; \ - return do_zpzz_ool(s, a, fns[a->esz]); \ -} - -DO_ZPZZ(AND, and) -DO_ZPZZ(EOR, eor) -DO_ZPZZ(ORR, orr) -DO_ZPZZ(BIC, bic) - -DO_ZPZZ(ADD, add) -DO_ZPZZ(SUB, sub) - -DO_ZPZZ(SMAX, smax) -DO_ZPZZ(UMAX, umax) -DO_ZPZZ(SMIN, smin) -DO_ZPZZ(UMIN, umin) -DO_ZPZZ(SABD, sabd) -DO_ZPZZ(UABD, uabd) - -DO_ZPZZ(MUL, mul) -DO_ZPZZ(SMULH, smulh) -DO_ZPZZ(UMULH, umulh) - -DO_ZPZZ(ASR, asr) -DO_ZPZZ(LSR, lsr) -DO_ZPZZ(LSL, lsl) - -static bool trans_SDIV_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[4] = { - NULL, NULL, gen_helper_sve_sdiv_zpzz_s, gen_helper_sve_sdiv_zpzz_d - }; - return do_zpzz_ool(s, a, fns[a->esz]); -} - -static bool trans_UDIV_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[4] = { - NULL, NULL, gen_helper_sve_udiv_zpzz_s, gen_helper_sve_udiv_zpzz_d - }; - return do_zpzz_ool(s, a, fns[a->esz]); -} + TRANS_FEAT(NAME, FEAT, gen_gvec_ool_arg_zpzz, \ + name##_zpzz_fns[a->esz], a, 0) + +DO_ZPZZ(AND_zpzz, aa64_sve, sve_and) +DO_ZPZZ(EOR_zpzz, aa64_sve, sve_eor) +DO_ZPZZ(ORR_zpzz, aa64_sve, sve_orr) +DO_ZPZZ(BIC_zpzz, aa64_sve, sve_bic) + +DO_ZPZZ(ADD_zpzz, aa64_sve, sve_add) +DO_ZPZZ(SUB_zpzz, aa64_sve, sve_sub) + +DO_ZPZZ(SMAX_zpzz, aa64_sve, sve_smax) +DO_ZPZZ(UMAX_zpzz, aa64_sve, sve_umax) +DO_ZPZZ(SMIN_zpzz, aa64_sve, sve_smin) +DO_ZPZZ(UMIN_zpzz, aa64_sve, sve_umin) +DO_ZPZZ(SABD_zpzz, aa64_sve, sve_sabd) +DO_ZPZZ(UABD_zpzz, aa64_sve, sve_uabd) + +DO_ZPZZ(MUL_zpzz, aa64_sve, sve_mul) +DO_ZPZZ(SMULH_zpzz, aa64_sve, sve_smulh) +DO_ZPZZ(UMULH_zpzz, aa64_sve, sve_umulh) + +DO_ZPZZ(ASR_zpzz, aa64_sve, sve_asr) +DO_ZPZZ(LSR_zpzz, aa64_sve, sve_lsr) +DO_ZPZZ(LSL_zpzz, aa64_sve, sve_lsl) + +static gen_helper_gvec_4 * const sdiv_fns[4] = { + NULL, NULL, gen_helper_sve_sdiv_zpzz_s, gen_helper_sve_sdiv_zpzz_d +}; +TRANS_FEAT(SDIV_zpzz, aa64_sve, gen_gvec_ool_arg_zpzz, sdiv_fns[a->esz], a, 0) -static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - if (sve_access_check(s)) { - do_sel_z(s, a->rd, a->rn, a->rm, a->pg, a->esz); - } - return true; -} +static gen_helper_gvec_4 * const udiv_fns[4] = { + NULL, NULL, gen_helper_sve_udiv_zpzz_s, gen_helper_sve_udiv_zpzz_d +}; +TRANS_FEAT(UDIV_zpzz, aa64_sve, gen_gvec_ool_arg_zpzz, udiv_fns[a->esz], a, 0) -#undef DO_ZPZZ +TRANS_FEAT(SEL_zpzz, aa64_sve, do_sel_z, a->rd, a->rn, a->rm, a->pg, a->esz) /* *** SVE Integer Arithmetic - Unary Predicated Group */ -static bool do_zpz_ool(DisasContext *s, arg_rpr_esz *a, gen_helper_gvec_3 *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, 0); - } - return true; -} - -#define DO_ZPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ - gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ +#define DO_ZPZ(NAME, FEAT, name) \ + static gen_helper_gvec_3 * const name##_fns[4] = { \ + gen_helper_##name##_b, gen_helper_##name##_h, \ + gen_helper_##name##_s, gen_helper_##name##_d, \ }; \ - return do_zpz_ool(s, a, fns[a->esz]); \ -} - -DO_ZPZ(CLS, cls) -DO_ZPZ(CLZ, clz) -DO_ZPZ(CNT_zpz, cnt_zpz) -DO_ZPZ(CNOT, cnot) -DO_ZPZ(NOT_zpz, not_zpz) -DO_ZPZ(ABS, abs) -DO_ZPZ(NEG, neg) - -static bool trans_FABS(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_fabs_h, - gen_helper_sve_fabs_s, - gen_helper_sve_fabs_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} - -static bool trans_FNEG(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_fneg_h, - gen_helper_sve_fneg_s, - gen_helper_sve_fneg_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} - -static bool trans_SXTB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_sxtb_h, - gen_helper_sve_sxtb_s, - gen_helper_sve_sxtb_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} + TRANS_FEAT(NAME, FEAT, gen_gvec_ool_arg_zpz, name##_fns[a->esz], a, 0) + +DO_ZPZ(CLS, aa64_sve, sve_cls) +DO_ZPZ(CLZ, aa64_sve, sve_clz) +DO_ZPZ(CNT_zpz, aa64_sve, sve_cnt_zpz) +DO_ZPZ(CNOT, aa64_sve, sve_cnot) +DO_ZPZ(NOT_zpz, aa64_sve, sve_not_zpz) +DO_ZPZ(ABS, aa64_sve, sve_abs) +DO_ZPZ(NEG, aa64_sve, sve_neg) +DO_ZPZ(RBIT, aa64_sve, sve_rbit) + +static gen_helper_gvec_3 * const fabs_fns[4] = { + NULL, gen_helper_sve_fabs_h, + gen_helper_sve_fabs_s, gen_helper_sve_fabs_d, +}; +TRANS_FEAT(FABS, aa64_sve, gen_gvec_ool_arg_zpz, fabs_fns[a->esz], a, 0) -static bool trans_UXTB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_uxtb_h, - gen_helper_sve_uxtb_s, - gen_helper_sve_uxtb_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const fneg_fns[4] = { + NULL, gen_helper_sve_fneg_h, + gen_helper_sve_fneg_s, gen_helper_sve_fneg_d, +}; +TRANS_FEAT(FNEG, aa64_sve, gen_gvec_ool_arg_zpz, fneg_fns[a->esz], a, 0) -static bool trans_SXTH(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, NULL, - gen_helper_sve_sxth_s, - gen_helper_sve_sxth_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sxtb_fns[4] = { + NULL, gen_helper_sve_sxtb_h, + gen_helper_sve_sxtb_s, gen_helper_sve_sxtb_d, +}; +TRANS_FEAT(SXTB, aa64_sve, gen_gvec_ool_arg_zpz, sxtb_fns[a->esz], a, 0) -static bool trans_UXTH(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, NULL, - gen_helper_sve_uxth_s, - gen_helper_sve_uxth_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const uxtb_fns[4] = { + NULL, gen_helper_sve_uxtb_h, + gen_helper_sve_uxtb_s, gen_helper_sve_uxtb_d, +}; +TRANS_FEAT(UXTB, aa64_sve, gen_gvec_ool_arg_zpz, uxtb_fns[a->esz], a, 0) -static bool trans_SXTW(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ool(s, a, a->esz == 3 ? gen_helper_sve_sxtw_d : NULL); -} +static gen_helper_gvec_3 * const sxth_fns[4] = { + NULL, NULL, gen_helper_sve_sxth_s, gen_helper_sve_sxth_d +}; +TRANS_FEAT(SXTH, aa64_sve, gen_gvec_ool_arg_zpz, sxth_fns[a->esz], a, 0) -static bool trans_UXTW(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ool(s, a, a->esz == 3 ? gen_helper_sve_uxtw_d : NULL); -} +static gen_helper_gvec_3 * const uxth_fns[4] = { + NULL, NULL, gen_helper_sve_uxth_s, gen_helper_sve_uxth_d +}; +TRANS_FEAT(UXTH, aa64_sve, gen_gvec_ool_arg_zpz, uxth_fns[a->esz], a, 0) -#undef DO_ZPZ +TRANS_FEAT(SXTW, aa64_sve, gen_gvec_ool_arg_zpz, + a->esz == 3 ? gen_helper_sve_sxtw_d : NULL, a, 0) +TRANS_FEAT(UXTW, aa64_sve, gen_gvec_ool_arg_zpz, + a->esz == 3 ? gen_helper_sve_uxtw_d : NULL, a, 0) /* *** SVE Integer Reduction Group @@ -889,7 +976,7 @@ static bool do_vpz_ool(DisasContext *s, arg_rpr_esz *a, return true; } - desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); + desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); temp = tcg_temp_new_i64(); t_zn = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); @@ -899,7 +986,6 @@ static bool do_vpz_ool(DisasContext *s, arg_rpr_esz *a, fn(temp, t_zn, t_pg, desc); tcg_temp_free_ptr(t_zn); tcg_temp_free_ptr(t_pg); - tcg_temp_free_i32(desc); write_fp_dreg(s, a->rd, temp); tcg_temp_free_i64(temp); @@ -907,14 +993,11 @@ static bool do_vpz_ool(DisasContext *s, arg_rpr_esz *a, } #define DO_VPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_gvec_reduc * const fns[4] = { \ + static gen_helper_gvec_reduc * const name##_fns[4] = { \ gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - return do_vpz_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve, do_vpz_ool, a, name##_fns[a->esz]) DO_VPZ(ORV, orv) DO_VPZ(ANDV, andv) @@ -926,14 +1009,11 @@ DO_VPZ(UMAXV, umaxv) DO_VPZ(SMINV, sminv) DO_VPZ(UMINV, uminv) -static bool trans_SADDV(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_reduc * const fns[4] = { - gen_helper_sve_saddv_b, gen_helper_sve_saddv_h, - gen_helper_sve_saddv_s, NULL - }; - return do_vpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_reduc * const saddv_fns[4] = { + gen_helper_sve_saddv_b, gen_helper_sve_saddv_h, + gen_helper_sve_saddv_s, NULL +}; +TRANS_FEAT(SADDV, aa64_sve, do_vpz_ool, a, saddv_fns[a->esz]) #undef DO_VPZ @@ -952,168 +1032,105 @@ static bool do_movz_zpz(DisasContext *s, int rd, int rn, int pg, gen_helper_sve_movz_b, gen_helper_sve_movz_h, gen_helper_sve_movz_s, gen_helper_sve_movz_d, }; - - if (sve_access_check(s)) { - gen_gvec_ool_zzp(s, fns[esz], rd, rn, pg, invert); - } - return true; + return gen_gvec_ool_zzp(s, fns[esz], rd, rn, pg, invert); } -static bool do_zpzi_ool(DisasContext *s, arg_rpri_esz *a, - gen_helper_gvec_3 *fn) +static bool do_shift_zpzi(DisasContext *s, arg_rpri_esz *a, bool asr, + gen_helper_gvec_3 * const fns[4]) { - if (sve_access_check(s)) { - gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); - } - return true; -} + int max; -static bool trans_ASR_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_asr_zpzi_b, gen_helper_sve_asr_zpzi_h, - gen_helper_sve_asr_zpzi_s, gen_helper_sve_asr_zpzi_d, - }; if (a->esz < 0) { /* Invalid tsz encoding -- see tszimm_esz. */ return false; } - /* Shift by element size is architecturally valid. For - arithmetic right-shift, it's the same as by one less. */ - a->imm = MIN(a->imm, (8 << a->esz) - 1); - return do_zpzi_ool(s, a, fns[a->esz]); -} -static bool trans_LSR_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_lsr_zpzi_b, gen_helper_sve_lsr_zpzi_h, - gen_helper_sve_lsr_zpzi_s, gen_helper_sve_lsr_zpzi_d, - }; - if (a->esz < 0) { - return false; - } - /* Shift by element size is architecturally valid. - For logical shifts, it is a zeroing operation. */ - if (a->imm >= (8 << a->esz)) { - return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); - } else { - return do_zpzi_ool(s, a, fns[a->esz]); + /* + * Shift by element size is architecturally valid. + * For arithmetic right-shift, it's the same as by one less. + * For logical shifts and ASRD, it is a zeroing operation. + */ + max = 8 << a->esz; + if (a->imm >= max) { + if (asr) { + a->imm = max - 1; + } else { + return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); + } } + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } -static bool trans_LSL_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_lsl_zpzi_b, gen_helper_sve_lsl_zpzi_h, - gen_helper_sve_lsl_zpzi_s, gen_helper_sve_lsl_zpzi_d, - }; - if (a->esz < 0) { - return false; - } - /* Shift by element size is architecturally valid. - For logical shifts, it is a zeroing operation. */ - if (a->imm >= (8 << a->esz)) { - return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); - } else { - return do_zpzi_ool(s, a, fns[a->esz]); - } -} +static gen_helper_gvec_3 * const asr_zpzi_fns[4] = { + gen_helper_sve_asr_zpzi_b, gen_helper_sve_asr_zpzi_h, + gen_helper_sve_asr_zpzi_s, gen_helper_sve_asr_zpzi_d, +}; +TRANS_FEAT(ASR_zpzi, aa64_sve, do_shift_zpzi, a, true, asr_zpzi_fns) -static bool trans_ASRD(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_asrd_b, gen_helper_sve_asrd_h, - gen_helper_sve_asrd_s, gen_helper_sve_asrd_d, - }; - if (a->esz < 0) { - return false; - } - /* Shift by element size is architecturally valid. For arithmetic - right shift for division, it is a zeroing operation. */ - if (a->imm >= (8 << a->esz)) { - return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); - } else { - return do_zpzi_ool(s, a, fns[a->esz]); - } -} +static gen_helper_gvec_3 * const lsr_zpzi_fns[4] = { + gen_helper_sve_lsr_zpzi_b, gen_helper_sve_lsr_zpzi_h, + gen_helper_sve_lsr_zpzi_s, gen_helper_sve_lsr_zpzi_d, +}; +TRANS_FEAT(LSR_zpzi, aa64_sve, do_shift_zpzi, a, false, lsr_zpzi_fns) -static bool trans_SQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqshl_zpzi_b, gen_helper_sve2_sqshl_zpzi_h, - gen_helper_sve2_sqshl_zpzi_s, gen_helper_sve2_sqshl_zpzi_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzi_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const lsl_zpzi_fns[4] = { + gen_helper_sve_lsl_zpzi_b, gen_helper_sve_lsl_zpzi_h, + gen_helper_sve_lsl_zpzi_s, gen_helper_sve_lsl_zpzi_d, +}; +TRANS_FEAT(LSL_zpzi, aa64_sve, do_shift_zpzi, a, false, lsl_zpzi_fns) -static bool trans_UQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_uqshl_zpzi_b, gen_helper_sve2_uqshl_zpzi_h, - gen_helper_sve2_uqshl_zpzi_s, gen_helper_sve2_uqshl_zpzi_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzi_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const asrd_fns[4] = { + gen_helper_sve_asrd_b, gen_helper_sve_asrd_h, + gen_helper_sve_asrd_s, gen_helper_sve_asrd_d, +}; +TRANS_FEAT(ASRD, aa64_sve, do_shift_zpzi, a, false, asrd_fns) -static bool trans_SRSHR(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_srshr_b, gen_helper_sve2_srshr_h, - gen_helper_sve2_srshr_s, gen_helper_sve2_srshr_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzi_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sqshl_zpzi_fns[4] = { + gen_helper_sve2_sqshl_zpzi_b, gen_helper_sve2_sqshl_zpzi_h, + gen_helper_sve2_sqshl_zpzi_s, gen_helper_sve2_sqshl_zpzi_d, +}; +TRANS_FEAT(SQSHL_zpzi, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : sqshl_zpzi_fns[a->esz], a) -static bool trans_URSHR(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_urshr_b, gen_helper_sve2_urshr_h, - gen_helper_sve2_urshr_s, gen_helper_sve2_urshr_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzi_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const uqshl_zpzi_fns[4] = { + gen_helper_sve2_uqshl_zpzi_b, gen_helper_sve2_uqshl_zpzi_h, + gen_helper_sve2_uqshl_zpzi_s, gen_helper_sve2_uqshl_zpzi_d, +}; +TRANS_FEAT(UQSHL_zpzi, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : uqshl_zpzi_fns[a->esz], a) -static bool trans_SQSHLU(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqshlu_b, gen_helper_sve2_sqshlu_h, - gen_helper_sve2_sqshlu_s, gen_helper_sve2_sqshlu_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzi_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const srshr_fns[4] = { + gen_helper_sve2_srshr_b, gen_helper_sve2_srshr_h, + gen_helper_sve2_srshr_s, gen_helper_sve2_srshr_d, +}; +TRANS_FEAT(SRSHR, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : srshr_fns[a->esz], a) + +static gen_helper_gvec_3 * const urshr_fns[4] = { + gen_helper_sve2_urshr_b, gen_helper_sve2_urshr_h, + gen_helper_sve2_urshr_s, gen_helper_sve2_urshr_d, +}; +TRANS_FEAT(URSHR, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : urshr_fns[a->esz], a) + +static gen_helper_gvec_3 * const sqshlu_fns[4] = { + gen_helper_sve2_sqshlu_b, gen_helper_sve2_sqshlu_h, + gen_helper_sve2_sqshlu_s, gen_helper_sve2_sqshlu_d, +}; +TRANS_FEAT(SQSHLU, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : sqshlu_fns[a->esz], a) /* *** SVE Bitwise Shift - Predicated Group */ #define DO_ZPZW(NAME, name) \ -static bool trans_##NAME##_zpzw(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4 * const fns[3] = { \ + static gen_helper_gvec_4 * const name##_zpzw_fns[4] = { \ gen_helper_sve_##name##_zpzw_b, gen_helper_sve_##name##_zpzw_h, \ - gen_helper_sve_##name##_zpzw_s, \ + gen_helper_sve_##name##_zpzw_s, NULL \ }; \ - if (a->esz < 0 || a->esz >= 3) { \ - return false; \ - } \ - return do_zpzz_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_zpzw, aa64_sve, gen_gvec_ool_arg_zpzz, \ + a->esz < 0 ? NULL : name##_zpzw_fns[a->esz], a, 0) DO_ZPZW(ASR, asr) DO_ZPZW(LSR, lsr) @@ -1152,45 +1169,21 @@ static bool do_shift_imm(DisasContext *s, arg_rri_esz *a, bool asr, return true; } -static bool trans_ASR_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_shift_imm(s, a, true, tcg_gen_gvec_sari); -} - -static bool trans_LSR_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_shift_imm(s, a, false, tcg_gen_gvec_shri); -} - -static bool trans_LSL_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_shift_imm(s, a, false, tcg_gen_gvec_shli); -} - -static bool do_zzw_ool(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); - } - return true; -} +TRANS_FEAT(ASR_zzi, aa64_sve, do_shift_imm, a, true, tcg_gen_gvec_sari) +TRANS_FEAT(LSR_zzi, aa64_sve, do_shift_imm, a, false, tcg_gen_gvec_shri) +TRANS_FEAT(LSL_zzi, aa64_sve, do_shift_imm, a, false, tcg_gen_gvec_shli) #define DO_ZZW(NAME, name) \ -static bool trans_##NAME##_zzw(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ + static gen_helper_gvec_3 * const name##_zzw_fns[4] = { \ gen_helper_sve_##name##_zzw_b, gen_helper_sve_##name##_zzw_h, \ gen_helper_sve_##name##_zzw_s, NULL \ }; \ - return do_zzw_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve, gen_gvec_ool_arg_zzz, \ + name##_zzw_fns[a->esz], a, 0) -DO_ZZW(ASR, asr) -DO_ZZW(LSR, lsr) -DO_ZZW(LSL, lsl) +DO_ZZW(ASR_zzw, asr) +DO_ZZW(LSR_zzw, lsr) +DO_ZZW(LSL_zzw, lsl) #undef DO_ZZW @@ -1213,31 +1206,36 @@ static bool do_zpzzz_ool(DisasContext *s, arg_rprrr_esz *a, return true; } -#define DO_ZPZZZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprrr_esz *a) \ -{ \ - static gen_helper_gvec_5 * const fns[4] = { \ - gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ - }; \ - return do_zpzzz_ool(s, a, fns[a->esz]); \ -} - -DO_ZPZZZ(MLA, mla) -DO_ZPZZZ(MLS, mls) +static gen_helper_gvec_5 * const mla_fns[4] = { + gen_helper_sve_mla_b, gen_helper_sve_mla_h, + gen_helper_sve_mla_s, gen_helper_sve_mla_d, +}; +TRANS_FEAT(MLA, aa64_sve, do_zpzzz_ool, a, mla_fns[a->esz]) -#undef DO_ZPZZZ +static gen_helper_gvec_5 * const mls_fns[4] = { + gen_helper_sve_mls_b, gen_helper_sve_mls_h, + gen_helper_sve_mls_s, gen_helper_sve_mls_d, +}; +TRANS_FEAT(MLS, aa64_sve, do_zpzzz_ool, a, mls_fns[a->esz]) /* *** SVE Index Generation Group */ -static void do_index(DisasContext *s, int esz, int rd, +static bool do_index(DisasContext *s, int esz, int rd, TCGv_i64 start, TCGv_i64 incr) { - unsigned vsz = vec_full_reg_size(s); - TCGv_i32 desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); - TCGv_ptr t_zd = tcg_temp_new_ptr(); + unsigned vsz; + TCGv_i32 desc; + TCGv_ptr t_zd; + + if (!sve_access_check(s)) { + return true; + } + + vsz = vec_full_reg_size(s); + desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); + t_zd = tcg_temp_new_ptr(); tcg_gen_addi_ptr(t_zd, cpu_env, vec_full_reg_offset(s, rd)); if (esz == 3) { @@ -1260,79 +1258,79 @@ static void do_index(DisasContext *s, int esz, int rd, tcg_temp_free_i32(i32); } tcg_temp_free_ptr(t_zd); - tcg_temp_free_i32(desc); + return true; } -static bool trans_INDEX_ii(DisasContext *s, arg_INDEX_ii *a) +TRANS_FEAT(INDEX_ii, aa64_sve, do_index, a->esz, a->rd, + tcg_constant_i64(a->imm1), tcg_constant_i64(a->imm2)) +TRANS_FEAT(INDEX_ir, aa64_sve, do_index, a->esz, a->rd, + tcg_constant_i64(a->imm), cpu_reg(s, a->rm)) +TRANS_FEAT(INDEX_ri, aa64_sve, do_index, a->esz, a->rd, + cpu_reg(s, a->rn), tcg_constant_i64(a->imm)) +TRANS_FEAT(INDEX_rr, aa64_sve, do_index, a->esz, a->rd, + cpu_reg(s, a->rn), cpu_reg(s, a->rm)) + +/* + *** SVE Stack Allocation Group + */ + +static bool trans_ADDVL(DisasContext *s, arg_ADDVL *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { - TCGv_i64 start = tcg_const_i64(a->imm1); - TCGv_i64 incr = tcg_const_i64(a->imm2); - do_index(s, a->esz, a->rd, start, incr); - tcg_temp_free_i64(start); - tcg_temp_free_i64(incr); + TCGv_i64 rd = cpu_reg_sp(s, a->rd); + TCGv_i64 rn = cpu_reg_sp(s, a->rn); + tcg_gen_addi_i64(rd, rn, a->imm * vec_full_reg_size(s)); } return true; } -static bool trans_INDEX_ir(DisasContext *s, arg_INDEX_ir *a) +static bool trans_ADDSVL(DisasContext *s, arg_ADDSVL *a) { - if (sve_access_check(s)) { - TCGv_i64 start = tcg_const_i64(a->imm); - TCGv_i64 incr = cpu_reg(s, a->rm); - do_index(s, a->esz, a->rd, start, incr); - tcg_temp_free_i64(start); + if (!dc_isar_feature(aa64_sme, s)) { + return false; + } + if (sme_enabled_check(s)) { + TCGv_i64 rd = cpu_reg_sp(s, a->rd); + TCGv_i64 rn = cpu_reg_sp(s, a->rn); + tcg_gen_addi_i64(rd, rn, a->imm * streaming_vec_reg_size(s)); } return true; } -static bool trans_INDEX_ri(DisasContext *s, arg_INDEX_ri *a) +static bool trans_ADDPL(DisasContext *s, arg_ADDPL *a) { - if (sve_access_check(s)) { - TCGv_i64 start = cpu_reg(s, a->rn); - TCGv_i64 incr = tcg_const_i64(a->imm); - do_index(s, a->esz, a->rd, start, incr); - tcg_temp_free_i64(incr); + if (!dc_isar_feature(aa64_sve, s)) { + return false; } - return true; -} - -static bool trans_INDEX_rr(DisasContext *s, arg_INDEX_rr *a) -{ - if (sve_access_check(s)) { - TCGv_i64 start = cpu_reg(s, a->rn); - TCGv_i64 incr = cpu_reg(s, a->rm); - do_index(s, a->esz, a->rd, start, incr); - } - return true; -} - -/* - *** SVE Stack Allocation Group - */ - -static bool trans_ADDVL(DisasContext *s, arg_ADDVL *a) -{ if (sve_access_check(s)) { TCGv_i64 rd = cpu_reg_sp(s, a->rd); TCGv_i64 rn = cpu_reg_sp(s, a->rn); - tcg_gen_addi_i64(rd, rn, a->imm * vec_full_reg_size(s)); + tcg_gen_addi_i64(rd, rn, a->imm * pred_full_reg_size(s)); } return true; } -static bool trans_ADDPL(DisasContext *s, arg_ADDPL *a) +static bool trans_ADDSPL(DisasContext *s, arg_ADDSPL *a) { - if (sve_access_check(s)) { + if (!dc_isar_feature(aa64_sme, s)) { + return false; + } + if (sme_enabled_check(s)) { TCGv_i64 rd = cpu_reg_sp(s, a->rd); TCGv_i64 rn = cpu_reg_sp(s, a->rn); - tcg_gen_addi_i64(rd, rn, a->imm * pred_full_reg_size(s)); + tcg_gen_addi_i64(rd, rn, a->imm * streaming_pred_reg_size(s)); } return true; } static bool trans_RDVL(DisasContext *s, arg_RDVL *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); tcg_gen_movi_i64(reg, a->imm * vec_full_reg_size(s)); @@ -1340,75 +1338,49 @@ static bool trans_RDVL(DisasContext *s, arg_RDVL *a) return true; } -/* - *** SVE Compute Vector Address Group - */ - -static bool do_adr(DisasContext *s, arg_rrri *a, gen_helper_gvec_3 *fn) +static bool trans_RDSVL(DisasContext *s, arg_RDSVL *a) { - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, a->imm); + if (!dc_isar_feature(aa64_sme, s)) { + return false; + } + if (sme_enabled_check(s)) { + TCGv_i64 reg = cpu_reg(s, a->rd); + tcg_gen_movi_i64(reg, a->imm * streaming_vec_reg_size(s)); } return true; } -static bool trans_ADR_p32(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_p32); -} - -static bool trans_ADR_p64(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_p64); -} +/* + *** SVE Compute Vector Address Group + */ -static bool trans_ADR_s32(DisasContext *s, arg_rrri *a) +static bool do_adr(DisasContext *s, arg_rrri *a, gen_helper_gvec_3 *fn) { - return do_adr(s, a, gen_helper_sve_adr_s32); + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, a->imm); } -static bool trans_ADR_u32(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_u32); -} +TRANS_FEAT_NONSTREAMING(ADR_p32, aa64_sve, do_adr, a, gen_helper_sve_adr_p32) +TRANS_FEAT_NONSTREAMING(ADR_p64, aa64_sve, do_adr, a, gen_helper_sve_adr_p64) +TRANS_FEAT_NONSTREAMING(ADR_s32, aa64_sve, do_adr, a, gen_helper_sve_adr_s32) +TRANS_FEAT_NONSTREAMING(ADR_u32, aa64_sve, do_adr, a, gen_helper_sve_adr_u32) /* *** SVE Integer Misc - Unpredicated Group */ -static bool trans_FEXPA(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2 * const fns[4] = { - NULL, - gen_helper_sve_fexpa_h, - gen_helper_sve_fexpa_s, - gen_helper_sve_fexpa_d, - }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); - } - return true; -} +static gen_helper_gvec_2 * const fexpa_fns[4] = { + NULL, gen_helper_sve_fexpa_h, + gen_helper_sve_fexpa_s, gen_helper_sve_fexpa_d, +}; +TRANS_FEAT_NONSTREAMING(FEXPA, aa64_sve, gen_gvec_ool_zz, + fexpa_fns[a->esz], a->rd, a->rn, 0) -static bool trans_FTSSEL(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_ftssel_h, - gen_helper_sve_ftssel_s, - gen_helper_sve_ftssel_d, - }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); - } - return true; -} +static gen_helper_gvec_3 * const ftssel_fns[4] = { + NULL, gen_helper_sve_ftssel_h, + gen_helper_sve_ftssel_s, gen_helper_sve_ftssel_d, +}; +TRANS_FEAT_NONSTREAMING(FTSSEL, aa64_sve, gen_gvec_ool_arg_zzz, + ftssel_fns[a->esz], a, 0) /* *** SVE Predicate Logical Operations Group @@ -1492,20 +1464,17 @@ static bool trans_AND_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!a->s) { - if (!sve_access_check(s)) { - return true; - } if (a->rn == a->rm) { if (a->pg == a->rn) { - do_mov_p(s, a->rd, a->rn); - } else { - gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->pg); + return do_mov_p(s, a->rd, a->rn); } - return true; + return gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->pg); } else if (a->pg == a->rn || a->pg == a->rm) { - gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->rm); - return true; + return gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->rm); } } return do_pppp_flags(s, a, &op); @@ -1533,11 +1502,11 @@ static bool trans_BIC_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!a->s && a->pg == a->rn) { - if (sve_access_check(s)) { - gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->rn, a->rm); - } - return true; + return gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->rn, a->rm); } return do_pppp_flags(s, a, &op); } @@ -1563,12 +1532,20 @@ static bool trans_EOR_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_eor_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + /* Alias NOT (predicate) is EOR Pd.B, Pg/Z, Pn.B, Pg.B */ + if (!a->s && a->pg == a->rm) { + return gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->pg, a->rn); + } return do_pppp_flags(s, a, &op); } static bool trans_SEL_pppp(DisasContext *s, arg_rprr_s *a) { - if (a->s) { + if (a->s || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -1603,6 +1580,9 @@ static bool trans_ORR_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!a->s && a->pg == a->rn && a->rn == a->rm) { return do_mov_p(s, a->rd, a->rn); } @@ -1630,6 +1610,10 @@ static bool trans_ORN_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_orn_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } return do_pppp_flags(s, a, &op); } @@ -1654,6 +1638,10 @@ static bool trans_NOR_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_nor_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } return do_pppp_flags(s, a, &op); } @@ -1678,6 +1666,10 @@ static bool trans_NAND_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_nand_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } return do_pppp_flags(s, a, &op); } @@ -1687,6 +1679,9 @@ static bool trans_NAND_pppp(DisasContext *s, arg_rprr_s *a) static bool trans_PTEST(DisasContext *s, arg_PTEST *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int nofs = pred_full_reg_offset(s, a->rn); int gofs = pred_full_reg_offset(s, a->pg); @@ -1827,22 +1822,14 @@ static bool do_predset(DisasContext *s, int esz, int rd, int pat, bool setflag) return true; } -static bool trans_PTRUE(DisasContext *s, arg_PTRUE *a) -{ - return do_predset(s, a->esz, a->rd, a->pat, a->s); -} +TRANS_FEAT(PTRUE, aa64_sve, do_predset, a->esz, a->rd, a->pat, a->s) -static bool trans_SETFFR(DisasContext *s, arg_SETFFR *a) -{ - /* Note pat == 31 is #all, to set all elements. */ - return do_predset(s, 0, FFR_PRED_NUM, 31, false); -} +/* Note pat == 31 is #all, to set all elements. */ +TRANS_FEAT_NONSTREAMING(SETFFR, aa64_sve, + do_predset, 0, FFR_PRED_NUM, 31, false) -static bool trans_PFALSE(DisasContext *s, arg_PFALSE *a) -{ - /* Note pat == 32 is #unimp, to set no elements. */ - return do_predset(s, 0, a->rd, 32, false); -} +/* Note pat == 32 is #unimp, to set no elements. */ +TRANS_FEAT(PFALSE, aa64_sve, do_predset, 0, a->rd, 32, false) static bool trans_RDFFR_p(DisasContext *s, arg_RDFFR_p *a) { @@ -1853,18 +1840,13 @@ static bool trans_RDFFR_p(DisasContext *s, arg_RDFFR_p *a) .rd = a->rd, .pg = a->pg, .s = a->s, .rn = FFR_PRED_NUM, .rm = FFR_PRED_NUM, }; - return trans_AND_pppp(s, &alt_a); -} -static bool trans_RDFFR(DisasContext *s, arg_RDFFR *a) -{ - return do_mov_p(s, a->rd, FFR_PRED_NUM); + s->is_nonstreaming = true; + return trans_AND_pppp(s, &alt_a); } -static bool trans_WRFFR(DisasContext *s, arg_WRFFR *a) -{ - return do_mov_p(s, FFR_PRED_NUM, a->rn); -} +TRANS_FEAT_NONSTREAMING(RDFFR, aa64_sve, do_mov_p, a->rd, FFR_PRED_NUM) +TRANS_FEAT_NONSTREAMING(WRFFR, aa64_sve, do_mov_p, FFR_PRED_NUM, a->rn) static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a, void (*gen_fn)(TCGv_i32, TCGv_ptr, @@ -1884,9 +1866,9 @@ static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a, tcg_gen_addi_ptr(t_pd, cpu_env, pred_full_reg_offset(s, a->rd)); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->rn)); - t = tcg_const_i32(desc); + t = tcg_temp_new_i32(); - gen_fn(t, t_pd, t_pg, t); + gen_fn(t, t_pd, t_pg, tcg_constant_i32(desc)); tcg_temp_free_ptr(t_pd); tcg_temp_free_ptr(t_pg); @@ -1895,15 +1877,8 @@ static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a, return true; } -static bool trans_PFIRST(DisasContext *s, arg_rr_esz *a) -{ - return do_pfirst_pnext(s, a, gen_helper_sve_pfirst); -} - -static bool trans_PNEXT(DisasContext *s, arg_rr_esz *a) -{ - return do_pfirst_pnext(s, a, gen_helper_sve_pnext); -} +TRANS_FEAT(PFIRST, aa64_sve, do_pfirst_pnext, a, gen_helper_sve_pfirst) +TRANS_FEAT(PNEXT, aa64_sve, do_pfirst_pnext, a, gen_helper_sve_pnext) /* *** SVE Element Count Group @@ -1916,8 +1891,6 @@ static bool trans_PNEXT(DisasContext *s, arg_rr_esz *a) static void do_sat_addsub_32(TCGv_i64 reg, TCGv_i64 val, bool u, bool d) { int64_t ibound; - TCGv_i64 bound; - TCGCond cond; /* Use normal 64-bit arithmetic to detect 32-bit overflow. */ if (u) { @@ -1928,15 +1901,12 @@ static void do_sat_addsub_32(TCGv_i64 reg, TCGv_i64 val, bool u, bool d) if (d) { tcg_gen_sub_i64(reg, reg, val); ibound = (u ? 0 : INT32_MIN); - cond = TCG_COND_LT; + tcg_gen_smax_i64(reg, reg, tcg_constant_i64(ibound)); } else { tcg_gen_add_i64(reg, reg, val); ibound = (u ? UINT32_MAX : INT32_MAX); - cond = TCG_COND_GT; + tcg_gen_smin_i64(reg, reg, tcg_constant_i64(ibound)); } - bound = tcg_const_i64(ibound); - tcg_gen_movcond_i64(cond, reg, reg, bound, bound, reg); - tcg_temp_free_i64(bound); } /* Similarly with 64-bit values. */ @@ -1998,7 +1968,7 @@ static void do_sat_addsub_vec(DisasContext *s, int esz, int rd, int rn, nptr = tcg_temp_new_ptr(); tcg_gen_addi_ptr(dptr, cpu_env, vec_full_reg_offset(s, rd)); tcg_gen_addi_ptr(nptr, cpu_env, vec_full_reg_offset(s, rn)); - desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); + desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); switch (esz) { case MO_8: @@ -2067,11 +2037,13 @@ static void do_sat_addsub_vec(DisasContext *s, int esz, int rd, int rn, tcg_temp_free_ptr(dptr); tcg_temp_free_ptr(nptr); - tcg_temp_free_i32(desc); } static bool trans_CNT_r(DisasContext *s, arg_CNT_r *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned fullsz = vec_full_reg_size(s); unsigned numelem = decode_pred_count(fullsz, a->pat, a->esz); @@ -2082,6 +2054,9 @@ static bool trans_CNT_r(DisasContext *s, arg_CNT_r *a) static bool trans_INCDEC_r(DisasContext *s, arg_incdec_cnt *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned fullsz = vec_full_reg_size(s); unsigned numelem = decode_pred_count(fullsz, a->pat, a->esz); @@ -2095,6 +2070,9 @@ static bool trans_INCDEC_r(DisasContext *s, arg_incdec_cnt *a) static bool trans_SINCDEC_r_32(DisasContext *s, arg_incdec_cnt *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -2112,15 +2090,16 @@ static bool trans_SINCDEC_r_32(DisasContext *s, arg_incdec_cnt *a) tcg_gen_ext32s_i64(reg, reg); } } else { - TCGv_i64 t = tcg_const_i64(inc); - do_sat_addsub_32(reg, t, a->u, a->d); - tcg_temp_free_i64(t); + do_sat_addsub_32(reg, tcg_constant_i64(inc), a->u, a->d); } return true; } static bool trans_SINCDEC_r_64(DisasContext *s, arg_incdec_cnt *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -2131,16 +2110,14 @@ static bool trans_SINCDEC_r_64(DisasContext *s, arg_incdec_cnt *a) TCGv_i64 reg = cpu_reg(s, a->rd); if (inc != 0) { - TCGv_i64 t = tcg_const_i64(inc); - do_sat_addsub_64(reg, t, a->u, a->d); - tcg_temp_free_i64(t); + do_sat_addsub_64(reg, tcg_constant_i64(inc), a->u, a->d); } return true; } static bool trans_INCDEC_v(DisasContext *s, arg_incdec2_cnt *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } @@ -2150,11 +2127,10 @@ static bool trans_INCDEC_v(DisasContext *s, arg_incdec2_cnt *a) if (inc != 0) { if (sve_access_check(s)) { - TCGv_i64 t = tcg_const_i64(a->d ? -inc : inc); tcg_gen_gvec_adds(a->esz, vec_full_reg_offset(s, a->rd), vec_full_reg_offset(s, a->rn), - t, fullsz, fullsz); - tcg_temp_free_i64(t); + tcg_constant_i64(a->d ? -inc : inc), + fullsz, fullsz); } } else { do_mov_z(s, a->rd, a->rn); @@ -2164,7 +2140,7 @@ static bool trans_INCDEC_v(DisasContext *s, arg_incdec2_cnt *a) static bool trans_SINCDEC_v(DisasContext *s, arg_incdec2_cnt *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } @@ -2174,9 +2150,8 @@ static bool trans_SINCDEC_v(DisasContext *s, arg_incdec2_cnt *a) if (inc != 0) { if (sve_access_check(s)) { - TCGv_i64 t = tcg_const_i64(inc); - do_sat_addsub_vec(s, a->esz, a->rd, a->rn, t, a->u, a->d); - tcg_temp_free_i64(t); + do_sat_addsub_vec(s, a->esz, a->rd, a->rn, + tcg_constant_i64(inc), a->u, a->d); } } else { do_mov_z(s, a->rd, a->rn); @@ -2196,32 +2171,20 @@ static bool do_zz_dbm(DisasContext *s, arg_rr_dbm *a, GVecGen2iFn *gvec_fn) extract32(a->dbm, 6, 6))) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(MO_64, vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), imm, vsz, vsz); - } - return true; -} - -static bool trans_AND_zzi(DisasContext *s, arg_rr_dbm *a) -{ - return do_zz_dbm(s, a, tcg_gen_gvec_andi); -} - -static bool trans_ORR_zzi(DisasContext *s, arg_rr_dbm *a) -{ - return do_zz_dbm(s, a, tcg_gen_gvec_ori); + return gen_gvec_fn_zzi(s, gvec_fn, MO_64, a->rd, a->rn, imm); } -static bool trans_EOR_zzi(DisasContext *s, arg_rr_dbm *a) -{ - return do_zz_dbm(s, a, tcg_gen_gvec_xori); -} +TRANS_FEAT(AND_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_andi) +TRANS_FEAT(ORR_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_ori) +TRANS_FEAT(EOR_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_xori) static bool trans_DUPM(DisasContext *s, arg_DUPM *a) { uint64_t imm; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!logic_imm_decode_wmask(&imm, extract32(a->dbm, 12, 1), extract32(a->dbm, 0, 6), extract32(a->dbm, 6, 6))) { @@ -2249,7 +2212,7 @@ static void do_cpy_m(DisasContext *s, int esz, int rd, int rn, int pg, gen_helper_sve_cpy_m_s, gen_helper_sve_cpy_m_d, }; unsigned vsz = vec_full_reg_size(s); - TCGv_i32 desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); + TCGv_i32 desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); TCGv_ptr t_zd = tcg_temp_new_ptr(); TCGv_ptr t_zn = tcg_temp_new_ptr(); TCGv_ptr t_pg = tcg_temp_new_ptr(); @@ -2263,33 +2226,28 @@ static void do_cpy_m(DisasContext *s, int esz, int rd, int rn, int pg, tcg_temp_free_ptr(t_zd); tcg_temp_free_ptr(t_zn); tcg_temp_free_ptr(t_pg); - tcg_temp_free_i32(desc); } static bool trans_FCPY(DisasContext *s, arg_FCPY *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { /* Decode the VFP immediate. */ uint64_t imm = vfp_expand_imm(a->esz, a->imm); - TCGv_i64 t_imm = tcg_const_i64(imm); - do_cpy_m(s, a->esz, a->rd, a->rn, a->pg, t_imm); - tcg_temp_free_i64(t_imm); + do_cpy_m(s, a->esz, a->rd, a->rn, a->pg, tcg_constant_i64(imm)); } return true; } static bool trans_CPY_m_i(DisasContext *s, arg_rpri_esz *a) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { + if (!dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { - TCGv_i64 t_imm = tcg_const_i64(a->imm); - do_cpy_m(s, a->esz, a->rd, a->rn, a->pg, t_imm); - tcg_temp_free_i64(t_imm); + do_cpy_m(s, a->esz, a->rd, a->rn, a->pg, tcg_constant_i64(a->imm)); } return true; } @@ -2301,16 +2259,15 @@ static bool trans_CPY_z_i(DisasContext *s, arg_CPY_z_i *a) gen_helper_sve_cpy_z_s, gen_helper_sve_cpy_z_d, }; - if (a->esz == 0 && extract32(s->insn, 13, 1)) { + if (!dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); - TCGv_i64 t_imm = tcg_const_i64(a->imm); tcg_gen_gvec_2i_ool(vec_full_reg_offset(s, a->rd), pred_full_reg_offset(s, a->pg), - t_imm, vsz, vsz, 0, fns[a->esz]); - tcg_temp_free_i64(t_imm); + tcg_constant_i64(a->imm), + vsz, vsz, 0, fns[a->esz]); } return true; } @@ -2349,18 +2306,8 @@ static bool do_EXT(DisasContext *s, int rd, int rn, int rm, int imm) return true; } -static bool trans_EXT(DisasContext *s, arg_EXT *a) -{ - return do_EXT(s, a->rd, a->rn, a->rm, a->imm); -} - -static bool trans_EXT_sve2(DisasContext *s, arg_rri *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_EXT(s, a->rd, a->rn, (a->rn + 1) % 32, a->imm); -} +TRANS_FEAT(EXT, aa64_sve, do_EXT, a->rd, a->rn, a->rm, a->imm) +TRANS_FEAT(EXT_sve2, aa64_sve2, do_EXT, a->rd, a->rn, (a->rn + 1) % 32, a->imm) /* *** SVE Permute - Unpredicated Group @@ -2368,6 +2315,9 @@ static bool trans_EXT_sve2(DisasContext *s, arg_rri *a) static bool trans_DUP_s(DisasContext *s, arg_DUP_s *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); tcg_gen_gvec_dup_i64(a->esz, vec_full_reg_offset(s, a->rd), @@ -2378,6 +2328,9 @@ static bool trans_DUP_s(DisasContext *s, arg_DUP_s *a) static bool trans_DUP_x(DisasContext *s, arg_DUP_x *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if ((a->imm & 0x1f) == 0) { return false; } @@ -2411,7 +2364,7 @@ static void do_insr_i64(DisasContext *s, arg_rrr_esz *a, TCGv_i64 val) gen_helper_sve_insr_s, gen_helper_sve_insr_d, }; unsigned vsz = vec_full_reg_size(s); - TCGv_i32 desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); + TCGv_i32 desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); TCGv_ptr t_zd = tcg_temp_new_ptr(); TCGv_ptr t_zn = tcg_temp_new_ptr(); @@ -2422,11 +2375,13 @@ static void do_insr_i64(DisasContext *s, arg_rrr_esz *a, TCGv_i64 val) tcg_temp_free_ptr(t_zd); tcg_temp_free_ptr(t_zn); - tcg_temp_free_i32(desc); } static bool trans_INSR_f(DisasContext *s, arg_rrr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 t = tcg_temp_new_i64(); tcg_gen_ld_i64(t, cpu_env, vec_reg_offset(s, a->rm, 0, MO_64)); @@ -2438,70 +2393,39 @@ static bool trans_INSR_f(DisasContext *s, arg_rrr_esz *a) static bool trans_INSR_r(DisasContext *s, arg_rrr_esz *a) { - if (sve_access_check(s)) { - do_insr_i64(s, a, cpu_reg(s, a->rm)); - } - return true; -} - -static bool trans_REV_v(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2 * const fns[4] = { - gen_helper_sve_rev_b, gen_helper_sve_rev_h, - gen_helper_sve_rev_s, gen_helper_sve_rev_d - }; - - if (sve_access_check(s)) { - gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); + if (!dc_isar_feature(aa64_sve, s)) { + return false; } - return true; -} - -static bool trans_TBL(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_tbl_b, gen_helper_sve_tbl_h, - gen_helper_sve_tbl_s, gen_helper_sve_tbl_d - }; - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); + do_insr_i64(s, a, cpu_reg(s, a->rm)); } return true; } -static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_4 * const fns[4] = { - gen_helper_sve2_tbl_b, gen_helper_sve2_tbl_h, - gen_helper_sve2_tbl_s, gen_helper_sve2_tbl_d - }; +static gen_helper_gvec_2 * const rev_fns[4] = { + gen_helper_sve_rev_b, gen_helper_sve_rev_h, + gen_helper_sve_rev_s, gen_helper_sve_rev_d +}; +TRANS_FEAT(REV_v, aa64_sve, gen_gvec_ool_zz, rev_fns[a->esz], a->rd, a->rn, 0) - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, - (a->rn + 1) % 32, a->rm, 0); - } - return true; -} +static gen_helper_gvec_3 * const sve_tbl_fns[4] = { + gen_helper_sve_tbl_b, gen_helper_sve_tbl_h, + gen_helper_sve_tbl_s, gen_helper_sve_tbl_d +}; +TRANS_FEAT(TBL, aa64_sve, gen_gvec_ool_arg_zzz, sve_tbl_fns[a->esz], a, 0) -static bool trans_TBX(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_tbx_b, gen_helper_sve2_tbx_h, - gen_helper_sve2_tbx_s, gen_helper_sve2_tbx_d - }; +static gen_helper_gvec_4 * const sve2_tbl_fns[4] = { + gen_helper_sve2_tbl_b, gen_helper_sve2_tbl_h, + gen_helper_sve2_tbl_s, gen_helper_sve2_tbl_d +}; +TRANS_FEAT(TBL_sve2, aa64_sve2, gen_gvec_ool_zzzz, sve2_tbl_fns[a->esz], + a->rd, a->rn, (a->rn + 1) % 32, a->rm, 0) - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); - } - return true; -} +static gen_helper_gvec_3 * const tbx_fns[4] = { + gen_helper_sve2_tbx_b, gen_helper_sve2_tbx_h, + gen_helper_sve2_tbx_s, gen_helper_sve2_tbx_d +}; +TRANS_FEAT(TBX, aa64_sve2, gen_gvec_ool_arg_zzz, tbx_fns[a->esz], a, 0) static bool trans_UNPK(DisasContext *s, arg_UNPK *a) { @@ -2512,7 +2436,7 @@ static bool trans_UNPK(DisasContext *s, arg_UNPK *a) { gen_helper_sve_sunpk_d, gen_helper_sve_uunpk_d }, }; - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -2541,7 +2465,6 @@ static bool do_perm_pred3(DisasContext *s, arg_rrr_esz *a, bool high_odd, TCGv_ptr t_d = tcg_temp_new_ptr(); TCGv_ptr t_n = tcg_temp_new_ptr(); TCGv_ptr t_m = tcg_temp_new_ptr(); - TCGv_i32 t_desc; uint32_t desc = 0; desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz); @@ -2551,14 +2474,12 @@ static bool do_perm_pred3(DisasContext *s, arg_rrr_esz *a, bool high_odd, tcg_gen_addi_ptr(t_d, cpu_env, pred_full_reg_offset(s, a->rd)); tcg_gen_addi_ptr(t_n, cpu_env, pred_full_reg_offset(s, a->rn)); tcg_gen_addi_ptr(t_m, cpu_env, pred_full_reg_offset(s, a->rm)); - t_desc = tcg_const_i32(desc); - fn(t_d, t_n, t_m, t_desc); + fn(t_d, t_n, t_m, tcg_constant_i32(desc)); tcg_temp_free_ptr(t_d); tcg_temp_free_ptr(t_n); tcg_temp_free_ptr(t_m); - tcg_temp_free_i32(t_desc); return true; } @@ -2572,7 +2493,6 @@ static bool do_perm_pred2(DisasContext *s, arg_rr_esz *a, bool high_odd, unsigned vsz = pred_full_reg_size(s); TCGv_ptr t_d = tcg_temp_new_ptr(); TCGv_ptr t_n = tcg_temp_new_ptr(); - TCGv_i32 t_desc; uint32_t desc = 0; tcg_gen_addi_ptr(t_d, cpu_env, pred_full_reg_offset(s, a->rd)); @@ -2581,224 +2501,103 @@ static bool do_perm_pred2(DisasContext *s, arg_rr_esz *a, bool high_odd, desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz); desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); desc = FIELD_DP32(desc, PREDDESC, DATA, high_odd); - t_desc = tcg_const_i32(desc); - fn(t_d, t_n, t_desc); + fn(t_d, t_n, tcg_constant_i32(desc)); - tcg_temp_free_i32(t_desc); tcg_temp_free_ptr(t_d); tcg_temp_free_ptr(t_n); return true; } -static bool trans_ZIP1_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 0, gen_helper_sve_zip_p); -} +TRANS_FEAT(ZIP1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_zip_p) +TRANS_FEAT(ZIP2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_zip_p) +TRANS_FEAT(UZP1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_uzp_p) +TRANS_FEAT(UZP2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_uzp_p) +TRANS_FEAT(TRN1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_trn_p) +TRANS_FEAT(TRN2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_trn_p) -static bool trans_ZIP2_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 1, gen_helper_sve_zip_p); -} +TRANS_FEAT(REV_p, aa64_sve, do_perm_pred2, a, 0, gen_helper_sve_rev_p) +TRANS_FEAT(PUNPKLO, aa64_sve, do_perm_pred2, a, 0, gen_helper_sve_punpk_p) +TRANS_FEAT(PUNPKHI, aa64_sve, do_perm_pred2, a, 1, gen_helper_sve_punpk_p) -static bool trans_UZP1_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 0, gen_helper_sve_uzp_p); -} +/* + *** SVE Permute - Interleaving Group + */ -static bool trans_UZP2_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 1, gen_helper_sve_uzp_p); -} +static gen_helper_gvec_3 * const zip_fns[4] = { + gen_helper_sve_zip_b, gen_helper_sve_zip_h, + gen_helper_sve_zip_s, gen_helper_sve_zip_d, +}; +TRANS_FEAT(ZIP1_z, aa64_sve, gen_gvec_ool_arg_zzz, + zip_fns[a->esz], a, 0) +TRANS_FEAT(ZIP2_z, aa64_sve, gen_gvec_ool_arg_zzz, + zip_fns[a->esz], a, vec_full_reg_size(s) / 2) -static bool trans_TRN1_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 0, gen_helper_sve_trn_p); -} +TRANS_FEAT(ZIP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_zip_q, a, 0) +TRANS_FEAT(ZIP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_zip_q, a, + QEMU_ALIGN_DOWN(vec_full_reg_size(s), 32) / 2) -static bool trans_TRN2_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 1, gen_helper_sve_trn_p); -} +static gen_helper_gvec_3 * const uzp_fns[4] = { + gen_helper_sve_uzp_b, gen_helper_sve_uzp_h, + gen_helper_sve_uzp_s, gen_helper_sve_uzp_d, +}; -static bool trans_REV_p(DisasContext *s, arg_rr_esz *a) -{ - return do_perm_pred2(s, a, 0, gen_helper_sve_rev_p); -} +TRANS_FEAT(UZP1_z, aa64_sve, gen_gvec_ool_arg_zzz, + uzp_fns[a->esz], a, 0) +TRANS_FEAT(UZP2_z, aa64_sve, gen_gvec_ool_arg_zzz, + uzp_fns[a->esz], a, 1 << a->esz) -static bool trans_PUNPKLO(DisasContext *s, arg_PUNPKLO *a) -{ - return do_perm_pred2(s, a, 0, gen_helper_sve_punpk_p); -} +TRANS_FEAT(UZP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_uzp_q, a, 0) +TRANS_FEAT(UZP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_uzp_q, a, 16) -static bool trans_PUNPKHI(DisasContext *s, arg_PUNPKHI *a) -{ - return do_perm_pred2(s, a, 1, gen_helper_sve_punpk_p); -} +static gen_helper_gvec_3 * const trn_fns[4] = { + gen_helper_sve_trn_b, gen_helper_sve_trn_h, + gen_helper_sve_trn_s, gen_helper_sve_trn_d, +}; + +TRANS_FEAT(TRN1_z, aa64_sve, gen_gvec_ool_arg_zzz, + trn_fns[a->esz], a, 0) +TRANS_FEAT(TRN2_z, aa64_sve, gen_gvec_ool_arg_zzz, + trn_fns[a->esz], a, 1 << a->esz) + +TRANS_FEAT(TRN1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_trn_q, a, 0) +TRANS_FEAT(TRN2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_trn_q, a, 16) /* - *** SVE Permute - Interleaving Group + *** SVE Permute Vector - Predicated Group */ -static bool do_zip(DisasContext *s, arg_rrr_esz *a, bool high) +static gen_helper_gvec_3 * const compact_fns[4] = { + NULL, NULL, gen_helper_sve_compact_s, gen_helper_sve_compact_d +}; +TRANS_FEAT_NONSTREAMING(COMPACT, aa64_sve, gen_gvec_ool_arg_zpz, + compact_fns[a->esz], a, 0) + +/* Call the helper that computes the ARM LastActiveElement pseudocode + * function, scaled by the element size. This includes the not found + * indication; e.g. not found for esz=3 is -8. + */ +static void find_last_active(DisasContext *s, TCGv_i32 ret, int esz, int pg) { - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_zip_b, gen_helper_sve_zip_h, - gen_helper_sve_zip_s, gen_helper_sve_zip_d, - }; + /* Predicate sizes may be smaller and cannot use simd_desc. We cannot + * round up, as we do elsewhere, because we need the exact size. + */ + TCGv_ptr t_p = tcg_temp_new_ptr(); + unsigned desc = 0; - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - unsigned high_ofs = high ? vsz / 2 : 0; - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn) + high_ofs, - vec_full_reg_offset(s, a->rm) + high_ofs, - vsz, vsz, 0, fns[a->esz]); - } - return true; -} - -static bool do_zzz_data_ool(DisasContext *s, arg_rrr_esz *a, int data, - gen_helper_gvec_3 *fn) -{ - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); - } - return true; -} - -static bool trans_ZIP1_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip(s, a, false); -} - -static bool trans_ZIP2_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip(s, a, true); -} - -static bool do_zip_q(DisasContext *s, arg_rrr_esz *a, bool high) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - unsigned high_ofs = high ? QEMU_ALIGN_DOWN(vsz, 32) / 2 : 0; - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn) + high_ofs, - vec_full_reg_offset(s, a->rm) + high_ofs, - vsz, vsz, 0, gen_helper_sve2_zip_q); - } - return true; -} - -static bool trans_ZIP1_q(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip_q(s, a, false); -} - -static bool trans_ZIP2_q(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip_q(s, a, true); -} - -static gen_helper_gvec_3 * const uzp_fns[4] = { - gen_helper_sve_uzp_b, gen_helper_sve_uzp_h, - gen_helper_sve_uzp_s, gen_helper_sve_uzp_d, -}; - -static bool trans_UZP1_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_data_ool(s, a, 0, uzp_fns[a->esz]); -} - -static bool trans_UZP2_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_data_ool(s, a, 1 << a->esz, uzp_fns[a->esz]); -} - -static bool trans_UZP1_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return do_zzz_data_ool(s, a, 0, gen_helper_sve2_uzp_q); -} - -static bool trans_UZP2_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return do_zzz_data_ool(s, a, 16, gen_helper_sve2_uzp_q); -} - -static gen_helper_gvec_3 * const trn_fns[4] = { - gen_helper_sve_trn_b, gen_helper_sve_trn_h, - gen_helper_sve_trn_s, gen_helper_sve_trn_d, -}; - -static bool trans_TRN1_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_data_ool(s, a, 0, trn_fns[a->esz]); -} - -static bool trans_TRN2_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zzz_data_ool(s, a, 1 << a->esz, trn_fns[a->esz]); -} - -static bool trans_TRN1_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return do_zzz_data_ool(s, a, 0, gen_helper_sve2_trn_q); -} - -static bool trans_TRN2_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return do_zzz_data_ool(s, a, 16, gen_helper_sve2_trn_q); -} - -/* - *** SVE Permute Vector - Predicated Group - */ - -static bool trans_COMPACT(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, NULL, gen_helper_sve_compact_s, gen_helper_sve_compact_d - }; - return do_zpz_ool(s, a, fns[a->esz]); -} - -/* Call the helper that computes the ARM LastActiveElement pseudocode - * function, scaled by the element size. This includes the not found - * indication; e.g. not found for esz=3 is -8. - */ -static void find_last_active(DisasContext *s, TCGv_i32 ret, int esz, int pg) -{ - /* Predicate sizes may be smaller and cannot use simd_desc. We cannot - * round up, as we do elsewhere, because we need the exact size. - */ - TCGv_ptr t_p = tcg_temp_new_ptr(); - TCGv_i32 t_desc; - unsigned desc = 0; - - desc = FIELD_DP32(desc, PREDDESC, OPRSZ, pred_full_reg_size(s)); - desc = FIELD_DP32(desc, PREDDESC, ESZ, esz); + desc = FIELD_DP32(desc, PREDDESC, OPRSZ, pred_full_reg_size(s)); + desc = FIELD_DP32(desc, PREDDESC, ESZ, esz); tcg_gen_addi_ptr(t_p, cpu_env, pred_full_reg_offset(s, pg)); - t_desc = tcg_const_i32(desc); - gen_helper_sve_last_active_element(ret, t_p, t_desc); + gen_helper_sve_last_active_element(ret, t_p, tcg_constant_i32(desc)); - tcg_temp_free_i32(t_desc); tcg_temp_free_ptr(t_p); } @@ -2813,11 +2612,9 @@ static void incr_last_active(DisasContext *s, TCGv_i32 last, int esz) if (is_power_of_2(vsz)) { tcg_gen_andi_i32(last, last, vsz - 1); } else { - TCGv_i32 max = tcg_const_i32(vsz); - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 max = tcg_constant_i32(vsz); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_movcond_i32(TCG_COND_GEU, last, last, max, zero, last); - tcg_temp_free_i32(max); - tcg_temp_free_i32(zero); } } @@ -2829,11 +2626,9 @@ static void wrap_last_active(DisasContext *s, TCGv_i32 last, int esz) if (is_power_of_2(vsz)) { tcg_gen_andi_i32(last, last, vsz - 1); } else { - TCGv_i32 max = tcg_const_i32(vsz - (1 << esz)); - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 max = tcg_constant_i32(vsz - (1 << esz)); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_movcond_i32(TCG_COND_LT, last, last, zero, max, last); - tcg_temp_free_i32(max); - tcg_temp_free_i32(zero); } } @@ -2872,7 +2667,7 @@ static TCGv_i64 load_last_active(DisasContext *s, TCGv_i32 last, * The final adjustment for the vector register base * is added via constant offset to the load. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN /* Adjust for element ordering. See vec_reg_offset. */ if (esz < 3) { tcg_gen_xori_i32(last, last, 8 - (1 << esz)); @@ -2935,22 +2730,15 @@ static bool do_clast_vector(DisasContext *s, arg_rprr_esz *a, bool before) return true; } -static bool trans_CLASTA_z(DisasContext *s, arg_rprr_esz *a) -{ - return do_clast_vector(s, a, false); -} - -static bool trans_CLASTB_z(DisasContext *s, arg_rprr_esz *a) -{ - return do_clast_vector(s, a, true); -} +TRANS_FEAT(CLASTA_z, aa64_sve, do_clast_vector, a, false) +TRANS_FEAT(CLASTB_z, aa64_sve, do_clast_vector, a, true) /* Compute CLAST for a scalar. */ static void do_clast_scalar(DisasContext *s, int esz, int pg, int rm, bool before, TCGv_i64 reg_val) { TCGv_i32 last = tcg_temp_new_i32(); - TCGv_i64 ele, cmp, zero; + TCGv_i64 ele, cmp; find_last_active(s, last, esz, pg); @@ -2970,10 +2758,9 @@ static void do_clast_scalar(DisasContext *s, int esz, int pg, int rm, ele = load_last_active(s, last, rm, esz); tcg_temp_free_i32(last); - zero = tcg_const_i64(0); - tcg_gen_movcond_i64(TCG_COND_GE, reg_val, cmp, zero, ele, reg_val); + tcg_gen_movcond_i64(TCG_COND_GE, reg_val, cmp, tcg_constant_i64(0), + ele, reg_val); - tcg_temp_free_i64(zero); tcg_temp_free_i64(cmp); tcg_temp_free_i64(ele); } @@ -2993,15 +2780,8 @@ static bool do_clast_fp(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_CLASTA_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_fp(s, a, false); -} - -static bool trans_CLASTB_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_fp(s, a, true); -} +TRANS_FEAT(CLASTA_v, aa64_sve, do_clast_fp, a, false) +TRANS_FEAT(CLASTB_v, aa64_sve, do_clast_fp, a, true) /* Compute CLAST for a Xreg. */ static bool do_clast_general(DisasContext *s, arg_rpr_esz *a, bool before) @@ -3033,15 +2813,8 @@ static bool do_clast_general(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_CLASTA_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_general(s, a, false); -} - -static bool trans_CLASTB_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_general(s, a, true); -} +TRANS_FEAT(CLASTA_r, aa64_sve, do_clast_general, a, false) +TRANS_FEAT(CLASTB_r, aa64_sve, do_clast_general, a, true) /* Compute LAST for a scalar. */ static TCGv_i64 do_last_scalar(DisasContext *s, int esz, @@ -3073,15 +2846,8 @@ static bool do_last_fp(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_LASTA_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_fp(s, a, false); -} - -static bool trans_LASTB_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_fp(s, a, true); -} +TRANS_FEAT(LASTA_v, aa64_sve, do_last_fp, a, false) +TRANS_FEAT(LASTB_v, aa64_sve, do_last_fp, a, true) /* Compute LAST for a Xreg. */ static bool do_last_general(DisasContext *s, arg_rpr_esz *a, bool before) @@ -3094,18 +2860,14 @@ static bool do_last_general(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_LASTA_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_general(s, a, false); -} - -static bool trans_LASTB_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_general(s, a, true); -} +TRANS_FEAT(LASTA_r, aa64_sve, do_last_general, a, false) +TRANS_FEAT(LASTB_r, aa64_sve, do_last_general, a, true) static bool trans_CPY_m_r(DisasContext *s, arg_rpr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { do_cpy_m(s, a->esz, a->rd, a->rd, a->pg, cpu_reg_sp(s, a->rn)); } @@ -3114,6 +2876,9 @@ static bool trans_CPY_m_r(DisasContext *s, arg_rpr_esz *a) static bool trans_CPY_m_v(DisasContext *s, arg_rpr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int ofs = vec_reg_offset(s, a->rn, 0, a->esz); TCGv_i64 t = load_esz(cpu_env, ofs, a->esz); @@ -3123,64 +2888,27 @@ static bool trans_CPY_m_v(DisasContext *s, arg_rpr_esz *a) return true; } -static bool trans_REVB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_revb_h, - gen_helper_sve_revb_s, - gen_helper_sve_revb_d, - }; - return do_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const revb_fns[4] = { + NULL, gen_helper_sve_revb_h, + gen_helper_sve_revb_s, gen_helper_sve_revb_d, +}; +TRANS_FEAT(REVB, aa64_sve, gen_gvec_ool_arg_zpz, revb_fns[a->esz], a, 0) -static bool trans_REVH(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - NULL, - gen_helper_sve_revh_s, - gen_helper_sve_revh_d, - }; - return do_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const revh_fns[4] = { + NULL, NULL, gen_helper_sve_revh_s, gen_helper_sve_revh_d, +}; +TRANS_FEAT(REVH, aa64_sve, gen_gvec_ool_arg_zpz, revh_fns[a->esz], a, 0) -static bool trans_REVW(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ool(s, a, a->esz == 3 ? gen_helper_sve_revw_d : NULL); -} +TRANS_FEAT(REVW, aa64_sve, gen_gvec_ool_arg_zpz, + a->esz == 3 ? gen_helper_sve_revw_d : NULL, a, 0) -static bool trans_RBIT(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_rbit_b, - gen_helper_sve_rbit_h, - gen_helper_sve_rbit_s, - gen_helper_sve_rbit_d, - }; - return do_zpz_ool(s, a, fns[a->esz]); -} +TRANS_FEAT(REVD, aa64_sme, gen_gvec_ool_arg_zpz, gen_helper_sme_revd_q, a, 0) -static bool trans_SPLICE(DisasContext *s, arg_rprr_esz *a) -{ - if (sve_access_check(s)) { - gen_gvec_ool_zzzp(s, gen_helper_sve_splice, - a->rd, a->rn, a->rm, a->pg, a->esz); - } - return true; -} +TRANS_FEAT(SPLICE, aa64_sve, gen_gvec_ool_arg_zpzz, + gen_helper_sve_splice, a, a->esz) -static bool trans_SPLICE_sve2(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzp(s, gen_helper_sve_splice, - a->rd, a->rn, (a->rn + 1) % 32, a->pg, a->esz); - } - return true; -} +TRANS_FEAT(SPLICE_sve2, aa64_sve2, gen_gvec_ool_zzzp, gen_helper_sve_splice, + a->rd, a->rn, (a->rn + 1) % 32, a->pg, a->esz) /* *** SVE Integer Compare - Vectors Group @@ -3201,7 +2929,7 @@ static bool do_ppzz_flags(DisasContext *s, arg_rprr_esz *a, } vsz = vec_full_reg_size(s); - t = tcg_const_i32(simd_desc(vsz, vsz, 0)); + t = tcg_temp_new_i32(); pd = tcg_temp_new_ptr(); zn = tcg_temp_new_ptr(); zm = tcg_temp_new_ptr(); @@ -3212,7 +2940,7 @@ static bool do_ppzz_flags(DisasContext *s, arg_rprr_esz *a, tcg_gen_addi_ptr(zm, cpu_env, vec_full_reg_offset(s, a->rm)); tcg_gen_addi_ptr(pg, cpu_env, pred_full_reg_offset(s, a->pg)); - gen_fn(t, pd, zn, zm, pg, t); + gen_fn(t, pd, zn, zm, pg, tcg_constant_i32(simd_desc(vsz, vsz, 0))); tcg_temp_free_ptr(pd); tcg_temp_free_ptr(zn); @@ -3226,14 +2954,12 @@ static bool do_ppzz_flags(DisasContext *s, arg_rprr_esz *a, } #define DO_PPZZ(NAME, name) \ -static bool trans_##NAME##_ppzz(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_flags_4 * const fns[4] = { \ - gen_helper_sve_##name##_ppzz_b, gen_helper_sve_##name##_ppzz_h, \ - gen_helper_sve_##name##_ppzz_s, gen_helper_sve_##name##_ppzz_d, \ - }; \ - return do_ppzz_flags(s, a, fns[a->esz]); \ -} + static gen_helper_gvec_flags_4 * const name##_ppzz_fns[4] = { \ + gen_helper_sve_##name##_ppzz_b, gen_helper_sve_##name##_ppzz_h, \ + gen_helper_sve_##name##_ppzz_s, gen_helper_sve_##name##_ppzz_d, \ + }; \ + TRANS_FEAT(NAME##_ppzz, aa64_sve, do_ppzz_flags, \ + a, name##_ppzz_fns[a->esz]) DO_PPZZ(CMPEQ, cmpeq) DO_PPZZ(CMPNE, cmpne) @@ -3245,14 +2971,12 @@ DO_PPZZ(CMPHS, cmphs) #undef DO_PPZZ #define DO_PPZW(NAME, name) \ -static bool trans_##NAME##_ppzw(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_flags_4 * const fns[4] = { \ - gen_helper_sve_##name##_ppzw_b, gen_helper_sve_##name##_ppzw_h, \ - gen_helper_sve_##name##_ppzw_s, NULL \ - }; \ - return do_ppzz_flags(s, a, fns[a->esz]); \ -} + static gen_helper_gvec_flags_4 * const name##_ppzw_fns[4] = { \ + gen_helper_sve_##name##_ppzw_b, gen_helper_sve_##name##_ppzw_h, \ + gen_helper_sve_##name##_ppzw_s, NULL \ + }; \ + TRANS_FEAT(NAME##_ppzw, aa64_sve, do_ppzz_flags, \ + a, name##_ppzw_fns[a->esz]) DO_PPZW(CMPEQ, cmpeq) DO_PPZW(CMPNE, cmpne) @@ -3286,7 +3010,7 @@ static bool do_ppzi_flags(DisasContext *s, arg_rpri_esz *a, } vsz = vec_full_reg_size(s); - t = tcg_const_i32(simd_desc(vsz, vsz, a->imm)); + t = tcg_temp_new_i32(); pd = tcg_temp_new_ptr(); zn = tcg_temp_new_ptr(); pg = tcg_temp_new_ptr(); @@ -3295,7 +3019,7 @@ static bool do_ppzi_flags(DisasContext *s, arg_rpri_esz *a, tcg_gen_addi_ptr(zn, cpu_env, vec_full_reg_offset(s, a->rn)); tcg_gen_addi_ptr(pg, cpu_env, pred_full_reg_offset(s, a->pg)); - gen_fn(t, pd, zn, pg, t); + gen_fn(t, pd, zn, pg, tcg_constant_i32(simd_desc(vsz, vsz, a->imm))); tcg_temp_free_ptr(pd); tcg_temp_free_ptr(zn); @@ -3308,14 +3032,12 @@ static bool do_ppzi_flags(DisasContext *s, arg_rpri_esz *a, } #define DO_PPZI(NAME, name) \ -static bool trans_##NAME##_ppzi(DisasContext *s, arg_rpri_esz *a) \ -{ \ - static gen_helper_gvec_flags_3 * const fns[4] = { \ + static gen_helper_gvec_flags_3 * const name##_ppzi_fns[4] = { \ gen_helper_sve_##name##_ppzi_b, gen_helper_sve_##name##_ppzi_h, \ gen_helper_sve_##name##_ppzi_s, gen_helper_sve_##name##_ppzi_d, \ }; \ - return do_ppzi_flags(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_ppzi, aa64_sve, do_ppzi_flags, a, \ + name##_ppzi_fns[a->esz]) DO_PPZI(CMPEQ, cmpeq) DO_PPZI(CMPNE, cmpne) @@ -3348,7 +3070,7 @@ static bool do_brk3(DisasContext *s, arg_rprr_s *a, TCGv_ptr n = tcg_temp_new_ptr(); TCGv_ptr m = tcg_temp_new_ptr(); TCGv_ptr g = tcg_temp_new_ptr(); - TCGv_i32 t = tcg_const_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz)); + TCGv_i32 desc = tcg_constant_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz)); tcg_gen_addi_ptr(d, cpu_env, pred_full_reg_offset(s, a->rd)); tcg_gen_addi_ptr(n, cpu_env, pred_full_reg_offset(s, a->rn)); @@ -3356,16 +3078,17 @@ static bool do_brk3(DisasContext *s, arg_rprr_s *a, tcg_gen_addi_ptr(g, cpu_env, pred_full_reg_offset(s, a->pg)); if (a->s) { - fn_s(t, d, n, m, g, t); + TCGv_i32 t = tcg_temp_new_i32(); + fn_s(t, d, n, m, g, desc); do_pred_flags(t); + tcg_temp_free_i32(t); } else { - fn(d, n, m, g, t); + fn(d, n, m, g, desc); } tcg_temp_free_ptr(d); tcg_temp_free_ptr(n); tcg_temp_free_ptr(m); tcg_temp_free_ptr(g); - tcg_temp_free_i32(t); return true; } @@ -3382,59 +3105,43 @@ static bool do_brk2(DisasContext *s, arg_rpr_s *a, TCGv_ptr d = tcg_temp_new_ptr(); TCGv_ptr n = tcg_temp_new_ptr(); TCGv_ptr g = tcg_temp_new_ptr(); - TCGv_i32 t = tcg_const_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz)); + TCGv_i32 desc = tcg_constant_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz)); tcg_gen_addi_ptr(d, cpu_env, pred_full_reg_offset(s, a->rd)); tcg_gen_addi_ptr(n, cpu_env, pred_full_reg_offset(s, a->rn)); tcg_gen_addi_ptr(g, cpu_env, pred_full_reg_offset(s, a->pg)); if (a->s) { - fn_s(t, d, n, g, t); + TCGv_i32 t = tcg_temp_new_i32(); + fn_s(t, d, n, g, desc); do_pred_flags(t); + tcg_temp_free_i32(t); } else { - fn(d, n, g, t); + fn(d, n, g, desc); } tcg_temp_free_ptr(d); tcg_temp_free_ptr(n); tcg_temp_free_ptr(g); - tcg_temp_free_i32(t); return true; } -static bool trans_BRKPA(DisasContext *s, arg_rprr_s *a) -{ - return do_brk3(s, a, gen_helper_sve_brkpa, gen_helper_sve_brkpas); -} - -static bool trans_BRKPB(DisasContext *s, arg_rprr_s *a) -{ - return do_brk3(s, a, gen_helper_sve_brkpb, gen_helper_sve_brkpbs); -} - -static bool trans_BRKA_m(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brka_m, gen_helper_sve_brkas_m); -} - -static bool trans_BRKB_m(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brkb_m, gen_helper_sve_brkbs_m); -} +TRANS_FEAT(BRKPA, aa64_sve, do_brk3, a, + gen_helper_sve_brkpa, gen_helper_sve_brkpas) +TRANS_FEAT(BRKPB, aa64_sve, do_brk3, a, + gen_helper_sve_brkpb, gen_helper_sve_brkpbs) -static bool trans_BRKA_z(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brka_z, gen_helper_sve_brkas_z); -} +TRANS_FEAT(BRKA_m, aa64_sve, do_brk2, a, + gen_helper_sve_brka_m, gen_helper_sve_brkas_m) +TRANS_FEAT(BRKB_m, aa64_sve, do_brk2, a, + gen_helper_sve_brkb_m, gen_helper_sve_brkbs_m) -static bool trans_BRKB_z(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brkb_z, gen_helper_sve_brkbs_z); -} +TRANS_FEAT(BRKA_z, aa64_sve, do_brk2, a, + gen_helper_sve_brka_z, gen_helper_sve_brkas_z) +TRANS_FEAT(BRKB_z, aa64_sve, do_brk2, a, + gen_helper_sve_brkb_z, gen_helper_sve_brkbs_z) -static bool trans_BRKN(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brkn, gen_helper_sve_brkns); -} +TRANS_FEAT(BRKN, aa64_sve, do_brk2, a, + gen_helper_sve_brkn, gen_helper_sve_brkns) /* *** SVE Predicate Count Group @@ -3466,24 +3173,24 @@ static void do_cntp(DisasContext *s, TCGv_i64 val, int esz, int pn, int pg) TCGv_ptr t_pn = tcg_temp_new_ptr(); TCGv_ptr t_pg = tcg_temp_new_ptr(); unsigned desc = 0; - TCGv_i32 t_desc; desc = FIELD_DP32(desc, PREDDESC, OPRSZ, psz); desc = FIELD_DP32(desc, PREDDESC, ESZ, esz); tcg_gen_addi_ptr(t_pn, cpu_env, pred_full_reg_offset(s, pn)); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); - t_desc = tcg_const_i32(desc); - gen_helper_sve_cntp(val, t_pn, t_pg, t_desc); + gen_helper_sve_cntp(val, t_pn, t_pg, tcg_constant_i32(desc)); tcg_temp_free_ptr(t_pn); tcg_temp_free_ptr(t_pg); - tcg_temp_free_i32(t_desc); } } static bool trans_CNTP(DisasContext *s, arg_CNTP *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { do_cntp(s, cpu_reg(s, a->rd), a->esz, a->rn, a->pg); } @@ -3492,6 +3199,9 @@ static bool trans_CNTP(DisasContext *s, arg_CNTP *a) static bool trans_INCDECP_r(DisasContext *s, arg_incdec_pred *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); TCGv_i64 val = tcg_temp_new_i64(); @@ -3509,7 +3219,7 @@ static bool trans_INCDECP_r(DisasContext *s, arg_incdec_pred *a) static bool trans_INCDECP_z(DisasContext *s, arg_incdec2_pred *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -3526,6 +3236,9 @@ static bool trans_INCDECP_z(DisasContext *s, arg_incdec2_pred *a) static bool trans_SINCDECP_r_32(DisasContext *s, arg_incdec_pred *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); TCGv_i64 val = tcg_temp_new_i64(); @@ -3538,6 +3251,9 @@ static bool trans_SINCDECP_r_32(DisasContext *s, arg_incdec_pred *a) static bool trans_SINCDECP_r_64(DisasContext *s, arg_incdec_pred *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); TCGv_i64 val = tcg_temp_new_i64(); @@ -3550,7 +3266,7 @@ static bool trans_SINCDECP_r_64(DisasContext *s, arg_incdec_pred *a) static bool trans_SINCDECP_z(DisasContext *s, arg_incdec2_pred *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -3567,6 +3283,9 @@ static bool trans_SINCDECP_z(DisasContext *s, arg_incdec2_pred *a) static bool trans_CTERM(DisasContext *s, arg_CTERM *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -3593,7 +3312,7 @@ static bool trans_CTERM(DisasContext *s, arg_CTERM *a) static bool trans_WHILE(DisasContext *s, arg_WHILE *a) { TCGv_i64 op0, op1, t0, t1, tmax; - TCGv_i32 t2, t3; + TCGv_i32 t2; TCGv_ptr ptr; unsigned vsz = vec_full_reg_size(s); unsigned desc = 0; @@ -3603,7 +3322,9 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a) bool eq = a->eq == a->lt; /* The greater-than conditions are all SVE2. */ - if (!a->lt && !dc_isar_feature(aa64_sve2, s)) { + if (a->lt + ? !dc_isar_feature(aa64_sve, s) + : !dc_isar_feature(aa64_sve2, s)) { return false; } if (!sve_access_check(s)) { @@ -3649,7 +3370,7 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a) } } - tmax = tcg_const_i64(vsz >> a->esz); + tmax = tcg_constant_i64(vsz >> a->esz); if (eq) { /* Equality means one more iteration. */ tcg_gen_addi_i64(t0, t0, 1); @@ -3669,7 +3390,6 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a) /* Bound to the maximum. */ tcg_gen_umin_i64(t0, t0, tmax); - tcg_temp_free_i64(tmax); /* Set the count to zero if the condition is false. */ tcg_gen_movi_i64(t1, 0); @@ -3686,28 +3406,26 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a) desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz / 8); desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); - t3 = tcg_const_i32(desc); ptr = tcg_temp_new_ptr(); tcg_gen_addi_ptr(ptr, cpu_env, pred_full_reg_offset(s, a->rd)); if (a->lt) { - gen_helper_sve_whilel(t2, ptr, t2, t3); + gen_helper_sve_whilel(t2, ptr, t2, tcg_constant_i32(desc)); } else { - gen_helper_sve_whileg(t2, ptr, t2, t3); + gen_helper_sve_whileg(t2, ptr, t2, tcg_constant_i32(desc)); } do_pred_flags(t2); tcg_temp_free_ptr(ptr); tcg_temp_free_i32(t2); - tcg_temp_free_i32(t3); return true; } static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) { TCGv_i64 op0, op1, diff, t1, tmax; - TCGv_i32 t2, t3; + TCGv_i32 t2; TCGv_ptr ptr; unsigned vsz = vec_full_reg_size(s); unsigned desc = 0; @@ -3722,7 +3440,7 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) op0 = read_cpu_reg(s, a->rn, 1); op1 = read_cpu_reg(s, a->rm, 1); - tmax = tcg_const_i64(vsz); + tmax = tcg_constant_i64(vsz); diff = tcg_temp_new_i64(); if (a->rw) { @@ -3748,7 +3466,6 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) /* Bound to the maximum. */ tcg_gen_umin_i64(diff, diff, tmax); - tcg_temp_free_i64(tmax); /* Since we're bounded, pass as a 32-bit type. */ t2 = tcg_temp_new_i32(); @@ -3757,17 +3474,15 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz / 8); desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); - t3 = tcg_const_i32(desc); ptr = tcg_temp_new_ptr(); tcg_gen_addi_ptr(ptr, cpu_env, pred_full_reg_offset(s, a->rd)); - gen_helper_sve_whilel(t2, ptr, t2, t3); + gen_helper_sve_whilel(t2, ptr, t2, tcg_constant_i32(desc)); do_pred_flags(t2); tcg_temp_free_ptr(ptr); tcg_temp_free_i32(t2); - tcg_temp_free_i32(t3); return true; } @@ -3777,7 +3492,7 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) static bool trans_FDUP(DisasContext *s, arg_FDUP *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -3794,30 +3509,18 @@ static bool trans_FDUP(DisasContext *s, arg_FDUP *a) static bool trans_DUP_i(DisasContext *s, arg_DUP_i *a) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { + if (!dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); int dofs = vec_full_reg_offset(s, a->rd); - tcg_gen_gvec_dup_imm(a->esz, dofs, vsz, vsz, a->imm); } return true; } -static bool trans_ADD_zzi(DisasContext *s, arg_rri_esz *a) -{ - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_addi(a->esz, vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), a->imm, vsz, vsz); - } - return true; -} +TRANS_FEAT(ADD_zzi, aa64_sve, gen_gvec_fn_arg_zzi, tcg_gen_gvec_addi, a) static bool trans_SUB_zzi(DisasContext *s, arg_rri_esz *a) { @@ -3856,86 +3559,51 @@ static bool trans_SUBR_zzi(DisasContext *s, arg_rri_esz *a) .scalar_first = true } }; - if (a->esz == 0 && extract32(s->insn, 13, 1)) { + if (!dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); - TCGv_i64 c = tcg_const_i64(a->imm); tcg_gen_gvec_2s(vec_full_reg_offset(s, a->rd), vec_full_reg_offset(s, a->rn), - vsz, vsz, c, &op[a->esz]); - tcg_temp_free_i64(c); + vsz, vsz, tcg_constant_i64(a->imm), &op[a->esz]); } return true; } -static bool trans_MUL_zzi(DisasContext *s, arg_rri_esz *a) -{ - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_muli(a->esz, vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), a->imm, vsz, vsz); - } - return true; -} +TRANS_FEAT(MUL_zzi, aa64_sve, gen_gvec_fn_arg_zzi, tcg_gen_gvec_muli, a) static bool do_zzi_sat(DisasContext *s, arg_rri_esz *a, bool u, bool d) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } if (sve_access_check(s)) { - TCGv_i64 val = tcg_const_i64(a->imm); - do_sat_addsub_vec(s, a->esz, a->rd, a->rn, val, u, d); - tcg_temp_free_i64(val); + do_sat_addsub_vec(s, a->esz, a->rd, a->rn, + tcg_constant_i64(a->imm), u, d); } return true; } -static bool trans_SQADD_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, false, false); -} - -static bool trans_UQADD_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, true, false); -} - -static bool trans_SQSUB_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, false, true); -} - -static bool trans_UQSUB_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, true, true); -} +TRANS_FEAT(SQADD_zzi, aa64_sve, do_zzi_sat, a, false, false) +TRANS_FEAT(UQADD_zzi, aa64_sve, do_zzi_sat, a, true, false) +TRANS_FEAT(SQSUB_zzi, aa64_sve, do_zzi_sat, a, false, true) +TRANS_FEAT(UQSUB_zzi, aa64_sve, do_zzi_sat, a, true, true) static bool do_zzi_ool(DisasContext *s, arg_rri_esz *a, gen_helper_gvec_2i *fn) { if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); - TCGv_i64 c = tcg_const_i64(a->imm); - tcg_gen_gvec_2i_ool(vec_full_reg_offset(s, a->rd), vec_full_reg_offset(s, a->rn), - c, vsz, vsz, 0, fn); - tcg_temp_free_i64(c); + tcg_constant_i64(a->imm), vsz, vsz, 0, fn); } return true; } #define DO_ZZI(NAME, name) \ -static bool trans_##NAME##_zzi(DisasContext *s, arg_rri_esz *a) \ -{ \ - static gen_helper_gvec_2i * const fns[4] = { \ + static gen_helper_gvec_2i * const name##i_fns[4] = { \ gen_helper_sve_##name##i_b, gen_helper_sve_##name##i_h, \ gen_helper_sve_##name##i_s, gen_helper_sve_##name##i_d, \ }; \ - return do_zzi_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_zzi, aa64_sve, do_zzi_ool, a, name##i_fns[a->esz]) DO_ZZI(SMAX, smax) DO_ZZI(UMAX, umax) @@ -3944,204 +3612,130 @@ DO_ZZI(UMIN, umin) #undef DO_ZZI -static bool trans_DOT_zzzz(DisasContext *s, arg_DOT_zzzz *a) -{ - static gen_helper_gvec_4 * const fns[2][2] = { - { gen_helper_gvec_sdot_b, gen_helper_gvec_sdot_h }, - { gen_helper_gvec_udot_b, gen_helper_gvec_udot_h } - }; - - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->u][a->sz], a->rd, a->rn, a->rm, a->ra, 0); - } - return true; -} +static gen_helper_gvec_4 * const dot_fns[2][2] = { + { gen_helper_gvec_sdot_b, gen_helper_gvec_sdot_h }, + { gen_helper_gvec_udot_b, gen_helper_gvec_udot_h } +}; +TRANS_FEAT(DOT_zzzz, aa64_sve, gen_gvec_ool_zzzz, + dot_fns[a->u][a->sz], a->rd, a->rn, a->rm, a->ra, 0) /* * SVE Multiply - Indexed */ -static bool do_zzxz_ool(DisasContext *s, arg_rrxr_esz *a, - gen_helper_gvec_4 *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); - } - return true; -} +TRANS_FEAT(SDOT_zzxw_s, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_sdot_idx_b, a) +TRANS_FEAT(SDOT_zzxw_d, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_sdot_idx_h, a) +TRANS_FEAT(UDOT_zzxw_s, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_udot_idx_b, a) +TRANS_FEAT(UDOT_zzxw_d, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_udot_idx_h, a) -#define DO_RRXR(NAME, FUNC) \ - static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { return do_zzxz_ool(s, a, FUNC); } +TRANS_FEAT(SUDOT_zzxw_s, aa64_sve_i8mm, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_sudot_idx_b, a) +TRANS_FEAT(USDOT_zzxw_s, aa64_sve_i8mm, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_usdot_idx_b, a) -DO_RRXR(trans_SDOT_zzxw_s, gen_helper_gvec_sdot_idx_b) -DO_RRXR(trans_SDOT_zzxw_d, gen_helper_gvec_sdot_idx_h) -DO_RRXR(trans_UDOT_zzxw_s, gen_helper_gvec_udot_idx_b) -DO_RRXR(trans_UDOT_zzxw_d, gen_helper_gvec_udot_idx_h) +#define DO_SVE2_RRX(NAME, FUNC) \ + TRANS_FEAT(NAME, aa64_sve, gen_gvec_ool_zzz, FUNC, \ + a->rd, a->rn, a->rm, a->index) -static bool trans_SUDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - return do_zzxz_ool(s, a, gen_helper_gvec_sudot_idx_b); -} +DO_SVE2_RRX(MUL_zzx_h, gen_helper_gvec_mul_idx_h) +DO_SVE2_RRX(MUL_zzx_s, gen_helper_gvec_mul_idx_s) +DO_SVE2_RRX(MUL_zzx_d, gen_helper_gvec_mul_idx_d) -static bool trans_USDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - return do_zzxz_ool(s, a, gen_helper_gvec_usdot_idx_b); -} +DO_SVE2_RRX(SQDMULH_zzx_h, gen_helper_sve2_sqdmulh_idx_h) +DO_SVE2_RRX(SQDMULH_zzx_s, gen_helper_sve2_sqdmulh_idx_s) +DO_SVE2_RRX(SQDMULH_zzx_d, gen_helper_sve2_sqdmulh_idx_d) -#undef DO_RRXR - -static bool do_sve2_zzz_data(DisasContext *s, int rd, int rn, int rm, int data, - gen_helper_gvec_3 *fn) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vsz, vsz, data, fn); - } - return true; -} - -#define DO_SVE2_RRX(NAME, FUNC) \ - static bool NAME(DisasContext *s, arg_rrx_esz *a) \ - { return do_sve2_zzz_data(s, a->rd, a->rn, a->rm, a->index, FUNC); } - -DO_SVE2_RRX(trans_MUL_zzx_h, gen_helper_gvec_mul_idx_h) -DO_SVE2_RRX(trans_MUL_zzx_s, gen_helper_gvec_mul_idx_s) -DO_SVE2_RRX(trans_MUL_zzx_d, gen_helper_gvec_mul_idx_d) - -DO_SVE2_RRX(trans_SQDMULH_zzx_h, gen_helper_sve2_sqdmulh_idx_h) -DO_SVE2_RRX(trans_SQDMULH_zzx_s, gen_helper_sve2_sqdmulh_idx_s) -DO_SVE2_RRX(trans_SQDMULH_zzx_d, gen_helper_sve2_sqdmulh_idx_d) - -DO_SVE2_RRX(trans_SQRDMULH_zzx_h, gen_helper_sve2_sqrdmulh_idx_h) -DO_SVE2_RRX(trans_SQRDMULH_zzx_s, gen_helper_sve2_sqrdmulh_idx_s) -DO_SVE2_RRX(trans_SQRDMULH_zzx_d, gen_helper_sve2_sqrdmulh_idx_d) +DO_SVE2_RRX(SQRDMULH_zzx_h, gen_helper_sve2_sqrdmulh_idx_h) +DO_SVE2_RRX(SQRDMULH_zzx_s, gen_helper_sve2_sqrdmulh_idx_s) +DO_SVE2_RRX(SQRDMULH_zzx_d, gen_helper_sve2_sqrdmulh_idx_d) #undef DO_SVE2_RRX #define DO_SVE2_RRX_TB(NAME, FUNC, TOP) \ - static bool NAME(DisasContext *s, arg_rrx_esz *a) \ - { \ - return do_sve2_zzz_data(s, a->rd, a->rn, a->rm, \ - (a->index << 1) | TOP, FUNC); \ - } + TRANS_FEAT(NAME, aa64_sve, gen_gvec_ool_zzz, FUNC, \ + a->rd, a->rn, a->rm, (a->index << 1) | TOP) -DO_SVE2_RRX_TB(trans_SQDMULLB_zzx_s, gen_helper_sve2_sqdmull_idx_s, false) -DO_SVE2_RRX_TB(trans_SQDMULLB_zzx_d, gen_helper_sve2_sqdmull_idx_d, false) -DO_SVE2_RRX_TB(trans_SQDMULLT_zzx_s, gen_helper_sve2_sqdmull_idx_s, true) -DO_SVE2_RRX_TB(trans_SQDMULLT_zzx_d, gen_helper_sve2_sqdmull_idx_d, true) +DO_SVE2_RRX_TB(SQDMULLB_zzx_s, gen_helper_sve2_sqdmull_idx_s, false) +DO_SVE2_RRX_TB(SQDMULLB_zzx_d, gen_helper_sve2_sqdmull_idx_d, false) +DO_SVE2_RRX_TB(SQDMULLT_zzx_s, gen_helper_sve2_sqdmull_idx_s, true) +DO_SVE2_RRX_TB(SQDMULLT_zzx_d, gen_helper_sve2_sqdmull_idx_d, true) -DO_SVE2_RRX_TB(trans_SMULLB_zzx_s, gen_helper_sve2_smull_idx_s, false) -DO_SVE2_RRX_TB(trans_SMULLB_zzx_d, gen_helper_sve2_smull_idx_d, false) -DO_SVE2_RRX_TB(trans_SMULLT_zzx_s, gen_helper_sve2_smull_idx_s, true) -DO_SVE2_RRX_TB(trans_SMULLT_zzx_d, gen_helper_sve2_smull_idx_d, true) +DO_SVE2_RRX_TB(SMULLB_zzx_s, gen_helper_sve2_smull_idx_s, false) +DO_SVE2_RRX_TB(SMULLB_zzx_d, gen_helper_sve2_smull_idx_d, false) +DO_SVE2_RRX_TB(SMULLT_zzx_s, gen_helper_sve2_smull_idx_s, true) +DO_SVE2_RRX_TB(SMULLT_zzx_d, gen_helper_sve2_smull_idx_d, true) -DO_SVE2_RRX_TB(trans_UMULLB_zzx_s, gen_helper_sve2_umull_idx_s, false) -DO_SVE2_RRX_TB(trans_UMULLB_zzx_d, gen_helper_sve2_umull_idx_d, false) -DO_SVE2_RRX_TB(trans_UMULLT_zzx_s, gen_helper_sve2_umull_idx_s, true) -DO_SVE2_RRX_TB(trans_UMULLT_zzx_d, gen_helper_sve2_umull_idx_d, true) +DO_SVE2_RRX_TB(UMULLB_zzx_s, gen_helper_sve2_umull_idx_s, false) +DO_SVE2_RRX_TB(UMULLB_zzx_d, gen_helper_sve2_umull_idx_d, false) +DO_SVE2_RRX_TB(UMULLT_zzx_s, gen_helper_sve2_umull_idx_s, true) +DO_SVE2_RRX_TB(UMULLT_zzx_d, gen_helper_sve2_umull_idx_d, true) #undef DO_SVE2_RRX_TB -static bool do_sve2_zzzz_data(DisasContext *s, int rd, int rn, int rm, int ra, - int data, gen_helper_gvec_4 *fn) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vec_full_reg_offset(s, ra), - vsz, vsz, data, fn); - } - return true; -} - #define DO_SVE2_RRXR(NAME, FUNC) \ - static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { return do_sve2_zzzz_data(s, a->rd, a->rn, a->rm, a->ra, a->index, FUNC); } + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_arg_zzxz, FUNC, a) -DO_SVE2_RRXR(trans_MLA_zzxz_h, gen_helper_gvec_mla_idx_h) -DO_SVE2_RRXR(trans_MLA_zzxz_s, gen_helper_gvec_mla_idx_s) -DO_SVE2_RRXR(trans_MLA_zzxz_d, gen_helper_gvec_mla_idx_d) +DO_SVE2_RRXR(MLA_zzxz_h, gen_helper_gvec_mla_idx_h) +DO_SVE2_RRXR(MLA_zzxz_s, gen_helper_gvec_mla_idx_s) +DO_SVE2_RRXR(MLA_zzxz_d, gen_helper_gvec_mla_idx_d) -DO_SVE2_RRXR(trans_MLS_zzxz_h, gen_helper_gvec_mls_idx_h) -DO_SVE2_RRXR(trans_MLS_zzxz_s, gen_helper_gvec_mls_idx_s) -DO_SVE2_RRXR(trans_MLS_zzxz_d, gen_helper_gvec_mls_idx_d) +DO_SVE2_RRXR(MLS_zzxz_h, gen_helper_gvec_mls_idx_h) +DO_SVE2_RRXR(MLS_zzxz_s, gen_helper_gvec_mls_idx_s) +DO_SVE2_RRXR(MLS_zzxz_d, gen_helper_gvec_mls_idx_d) -DO_SVE2_RRXR(trans_SQRDMLAH_zzxz_h, gen_helper_sve2_sqrdmlah_idx_h) -DO_SVE2_RRXR(trans_SQRDMLAH_zzxz_s, gen_helper_sve2_sqrdmlah_idx_s) -DO_SVE2_RRXR(trans_SQRDMLAH_zzxz_d, gen_helper_sve2_sqrdmlah_idx_d) +DO_SVE2_RRXR(SQRDMLAH_zzxz_h, gen_helper_sve2_sqrdmlah_idx_h) +DO_SVE2_RRXR(SQRDMLAH_zzxz_s, gen_helper_sve2_sqrdmlah_idx_s) +DO_SVE2_RRXR(SQRDMLAH_zzxz_d, gen_helper_sve2_sqrdmlah_idx_d) -DO_SVE2_RRXR(trans_SQRDMLSH_zzxz_h, gen_helper_sve2_sqrdmlsh_idx_h) -DO_SVE2_RRXR(trans_SQRDMLSH_zzxz_s, gen_helper_sve2_sqrdmlsh_idx_s) -DO_SVE2_RRXR(trans_SQRDMLSH_zzxz_d, gen_helper_sve2_sqrdmlsh_idx_d) +DO_SVE2_RRXR(SQRDMLSH_zzxz_h, gen_helper_sve2_sqrdmlsh_idx_h) +DO_SVE2_RRXR(SQRDMLSH_zzxz_s, gen_helper_sve2_sqrdmlsh_idx_s) +DO_SVE2_RRXR(SQRDMLSH_zzxz_d, gen_helper_sve2_sqrdmlsh_idx_d) #undef DO_SVE2_RRXR #define DO_SVE2_RRXR_TB(NAME, FUNC, TOP) \ - static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { \ - return do_sve2_zzzz_data(s, a->rd, a->rn, a->rm, a->rd, \ - (a->index << 1) | TOP, FUNC); \ - } - -DO_SVE2_RRXR_TB(trans_SQDMLALB_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, false) -DO_SVE2_RRXR_TB(trans_SQDMLALB_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, false) -DO_SVE2_RRXR_TB(trans_SQDMLALT_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, true) -DO_SVE2_RRXR_TB(trans_SQDMLALT_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, true) - -DO_SVE2_RRXR_TB(trans_SQDMLSLB_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, false) -DO_SVE2_RRXR_TB(trans_SQDMLSLB_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, false) -DO_SVE2_RRXR_TB(trans_SQDMLSLT_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, true) -DO_SVE2_RRXR_TB(trans_SQDMLSLT_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, true) - -DO_SVE2_RRXR_TB(trans_SMLALB_zzxw_s, gen_helper_sve2_smlal_idx_s, false) -DO_SVE2_RRXR_TB(trans_SMLALB_zzxw_d, gen_helper_sve2_smlal_idx_d, false) -DO_SVE2_RRXR_TB(trans_SMLALT_zzxw_s, gen_helper_sve2_smlal_idx_s, true) -DO_SVE2_RRXR_TB(trans_SMLALT_zzxw_d, gen_helper_sve2_smlal_idx_d, true) - -DO_SVE2_RRXR_TB(trans_UMLALB_zzxw_s, gen_helper_sve2_umlal_idx_s, false) -DO_SVE2_RRXR_TB(trans_UMLALB_zzxw_d, gen_helper_sve2_umlal_idx_d, false) -DO_SVE2_RRXR_TB(trans_UMLALT_zzxw_s, gen_helper_sve2_umlal_idx_s, true) -DO_SVE2_RRXR_TB(trans_UMLALT_zzxw_d, gen_helper_sve2_umlal_idx_d, true) - -DO_SVE2_RRXR_TB(trans_SMLSLB_zzxw_s, gen_helper_sve2_smlsl_idx_s, false) -DO_SVE2_RRXR_TB(trans_SMLSLB_zzxw_d, gen_helper_sve2_smlsl_idx_d, false) -DO_SVE2_RRXR_TB(trans_SMLSLT_zzxw_s, gen_helper_sve2_smlsl_idx_s, true) -DO_SVE2_RRXR_TB(trans_SMLSLT_zzxw_d, gen_helper_sve2_smlsl_idx_d, true) - -DO_SVE2_RRXR_TB(trans_UMLSLB_zzxw_s, gen_helper_sve2_umlsl_idx_s, false) -DO_SVE2_RRXR_TB(trans_UMLSLB_zzxw_d, gen_helper_sve2_umlsl_idx_d, false) -DO_SVE2_RRXR_TB(trans_UMLSLT_zzxw_s, gen_helper_sve2_umlsl_idx_s, true) -DO_SVE2_RRXR_TB(trans_UMLSLT_zzxw_d, gen_helper_sve2_umlsl_idx_d, true) + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_zzzz, FUNC, \ + a->rd, a->rn, a->rm, a->ra, (a->index << 1) | TOP) + +DO_SVE2_RRXR_TB(SQDMLALB_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, false) +DO_SVE2_RRXR_TB(SQDMLALB_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, false) +DO_SVE2_RRXR_TB(SQDMLALT_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, true) +DO_SVE2_RRXR_TB(SQDMLALT_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, true) + +DO_SVE2_RRXR_TB(SQDMLSLB_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, false) +DO_SVE2_RRXR_TB(SQDMLSLB_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, false) +DO_SVE2_RRXR_TB(SQDMLSLT_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, true) +DO_SVE2_RRXR_TB(SQDMLSLT_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, true) + +DO_SVE2_RRXR_TB(SMLALB_zzxw_s, gen_helper_sve2_smlal_idx_s, false) +DO_SVE2_RRXR_TB(SMLALB_zzxw_d, gen_helper_sve2_smlal_idx_d, false) +DO_SVE2_RRXR_TB(SMLALT_zzxw_s, gen_helper_sve2_smlal_idx_s, true) +DO_SVE2_RRXR_TB(SMLALT_zzxw_d, gen_helper_sve2_smlal_idx_d, true) + +DO_SVE2_RRXR_TB(UMLALB_zzxw_s, gen_helper_sve2_umlal_idx_s, false) +DO_SVE2_RRXR_TB(UMLALB_zzxw_d, gen_helper_sve2_umlal_idx_d, false) +DO_SVE2_RRXR_TB(UMLALT_zzxw_s, gen_helper_sve2_umlal_idx_s, true) +DO_SVE2_RRXR_TB(UMLALT_zzxw_d, gen_helper_sve2_umlal_idx_d, true) + +DO_SVE2_RRXR_TB(SMLSLB_zzxw_s, gen_helper_sve2_smlsl_idx_s, false) +DO_SVE2_RRXR_TB(SMLSLB_zzxw_d, gen_helper_sve2_smlsl_idx_d, false) +DO_SVE2_RRXR_TB(SMLSLT_zzxw_s, gen_helper_sve2_smlsl_idx_s, true) +DO_SVE2_RRXR_TB(SMLSLT_zzxw_d, gen_helper_sve2_smlsl_idx_d, true) + +DO_SVE2_RRXR_TB(UMLSLB_zzxw_s, gen_helper_sve2_umlsl_idx_s, false) +DO_SVE2_RRXR_TB(UMLSLB_zzxw_d, gen_helper_sve2_umlsl_idx_d, false) +DO_SVE2_RRXR_TB(UMLSLT_zzxw_s, gen_helper_sve2_umlsl_idx_s, true) +DO_SVE2_RRXR_TB(UMLSLT_zzxw_d, gen_helper_sve2_umlsl_idx_d, true) #undef DO_SVE2_RRXR_TB #define DO_SVE2_RRXR_ROT(NAME, FUNC) \ - static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ - { \ - return do_sve2_zzzz_data(s, a->rd, a->rn, a->rm, a->ra, \ - (a->index << 2) | a->rot, FUNC); \ - } + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_zzzz, FUNC, \ + a->rd, a->rn, a->rm, a->ra, (a->index << 2) | a->rot) DO_SVE2_RRXR_ROT(CMLA_zzxz_h, gen_helper_sve2_cmla_idx_h) DO_SVE2_RRXR_ROT(CMLA_zzxz_s, gen_helper_sve2_cmla_idx_s) @@ -4160,59 +3754,31 @@ DO_SVE2_RRXR_ROT(CDOT_zzxw_d, gen_helper_sve2_cdot_idx_d) static bool do_FMLA_zzxz(DisasContext *s, arg_rrxr_esz *a, bool sub) { - static gen_helper_gvec_4_ptr * const fns[3] = { + static gen_helper_gvec_4_ptr * const fns[4] = { + NULL, gen_helper_gvec_fmla_idx_h, gen_helper_gvec_fmla_idx_s, gen_helper_gvec_fmla_idx_d, }; - - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, (a->index << 1) | sub, - fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} - -static bool trans_FMLA_zzxz(DisasContext *s, arg_FMLA_zzxz *a) -{ - return do_FMLA_zzxz(s, a, false); + return gen_gvec_fpst_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, + (a->index << 1) | sub, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } -static bool trans_FMLS_zzxz(DisasContext *s, arg_FMLA_zzxz *a) -{ - return do_FMLA_zzxz(s, a, true); -} +TRANS_FEAT(FMLA_zzxz, aa64_sve, do_FMLA_zzxz, a, false) +TRANS_FEAT(FMLS_zzxz, aa64_sve, do_FMLA_zzxz, a, true) /* *** SVE Floating Point Multiply Indexed Group */ -static bool trans_FMUL_zzx(DisasContext *s, arg_FMUL_zzx *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_gvec_fmul_idx_h, - gen_helper_gvec_fmul_idx_s, - gen_helper_gvec_fmul_idx_d, - }; - - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - status, vsz, vsz, a->index, fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_3_ptr * const fmul_idx_fns[4] = { + NULL, gen_helper_gvec_fmul_idx_h, + gen_helper_gvec_fmul_idx_s, gen_helper_gvec_fmul_idx_d, +}; +TRANS_FEAT(FMUL_zzx, aa64_sve, gen_gvec_fpst_zzz, + fmul_idx_fns[a->esz], a->rd, a->rn, a->rm, a->index, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) /* *** SVE Floating Point Fast Reduction Group @@ -4221,15 +3787,24 @@ static bool trans_FMUL_zzx(DisasContext *s, arg_FMUL_zzx *a) typedef void gen_helper_fp_reduce(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32); -static void do_reduce(DisasContext *s, arg_rpr_esz *a, +static bool do_reduce(DisasContext *s, arg_rpr_esz *a, gen_helper_fp_reduce *fn) { - unsigned vsz = vec_full_reg_size(s); - unsigned p2vsz = pow2ceil(vsz); - TCGv_i32 t_desc = tcg_const_i32(simd_desc(vsz, vsz, p2vsz)); + unsigned vsz, p2vsz; + TCGv_i32 t_desc; TCGv_ptr t_zn, t_pg, status; TCGv_i64 temp; + if (fn == NULL) { + return false; + } + if (!sve_access_check(s)) { + return true; + } + + vsz = vec_full_reg_size(s); + p2vsz = pow2ceil(vsz); + t_desc = tcg_constant_i32(simd_desc(vsz, vsz, p2vsz)); temp = tcg_temp_new_i64(); t_zn = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); @@ -4242,28 +3817,18 @@ static void do_reduce(DisasContext *s, arg_rpr_esz *a, tcg_temp_free_ptr(t_zn); tcg_temp_free_ptr(t_pg); tcg_temp_free_ptr(status); - tcg_temp_free_i32(t_desc); write_fp_dreg(s, a->rd, temp); tcg_temp_free_i64(temp); + return true; } #define DO_VPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_fp_reduce * const fns[3] = { \ - gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, \ - gen_helper_sve_##name##_d, \ + static gen_helper_fp_reduce * const name##_fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - if (a->esz == 0) { \ - return false; \ - } \ - if (sve_access_check(s)) { \ - do_reduce(s, a, fns[a->esz - 1]); \ - } \ - return true; \ -} + TRANS_FEAT(NAME, aa64_sve, do_reduce, a, name##_fns[a->esz]) DO_VPZ(FADDV, faddv) DO_VPZ(FMINNMV, fminnmv) @@ -4271,86 +3836,54 @@ DO_VPZ(FMAXNMV, fmaxnmv) DO_VPZ(FMINV, fminv) DO_VPZ(FMAXV, fmaxv) +#undef DO_VPZ + /* *** SVE Floating Point Unary Operations - Unpredicated Group */ -static void do_zz_fp(DisasContext *s, arg_rr_esz *a, gen_helper_gvec_2_ptr *fn) -{ - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - - tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); -} - -static bool trans_FRECPE(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2_ptr * const fns[3] = { - gen_helper_gvec_frecpe_h, - gen_helper_gvec_frecpe_s, - gen_helper_gvec_frecpe_d, - }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - do_zz_fp(s, a, fns[a->esz - 1]); - } - return true; -} +static gen_helper_gvec_2_ptr * const frecpe_fns[] = { + NULL, gen_helper_gvec_frecpe_h, + gen_helper_gvec_frecpe_s, gen_helper_gvec_frecpe_d, +}; +TRANS_FEAT(FRECPE, aa64_sve, gen_gvec_fpst_arg_zz, frecpe_fns[a->esz], a, 0) -static bool trans_FRSQRTE(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2_ptr * const fns[3] = { - gen_helper_gvec_frsqrte_h, - gen_helper_gvec_frsqrte_s, - gen_helper_gvec_frsqrte_d, - }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - do_zz_fp(s, a, fns[a->esz - 1]); - } - return true; -} +static gen_helper_gvec_2_ptr * const frsqrte_fns[] = { + NULL, gen_helper_gvec_frsqrte_h, + gen_helper_gvec_frsqrte_s, gen_helper_gvec_frsqrte_d, +}; +TRANS_FEAT(FRSQRTE, aa64_sve, gen_gvec_fpst_arg_zz, frsqrte_fns[a->esz], a, 0) /* *** SVE Floating Point Compare with Zero Group */ -static void do_ppz_fp(DisasContext *s, arg_rpr_esz *a, +static bool do_ppz_fp(DisasContext *s, arg_rpr_esz *a, gen_helper_gvec_3_ptr *fn) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = + fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(pred_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); + tcg_gen_gvec_3_ptr(pred_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + pred_full_reg_offset(s, a->pg), + status, vsz, vsz, 0, fn); + tcg_temp_free_ptr(status); + } + return true; } #define DO_PPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_gvec_3_ptr * const fns[3] = { \ - gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, \ - gen_helper_sve_##name##_d, \ + static gen_helper_gvec_3_ptr * const name##_fns[] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - if (a->esz == 0) { \ - return false; \ - } \ - if (sve_access_check(s)) { \ - do_ppz_fp(s, a, fns[a->esz - 1]); \ - } \ - return true; \ -} + TRANS_FEAT(NAME, aa64_sve, do_ppz_fp, a, name##_fns[a->esz]) DO_PPZ(FCMGE_ppz0, fcmge0) DO_PPZ(FCMGT_ppz0, fcmgt0) @@ -4365,28 +3898,13 @@ DO_PPZ(FCMNE_ppz0, fcmne0) *** SVE floating-point trig multiply-add coefficient */ -static bool trans_FTMAD(DisasContext *s, arg_FTMAD *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_ftmad_h, - gen_helper_sve_ftmad_s, - gen_helper_sve_ftmad_d, - }; - - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - status, vsz, vsz, a->imm, fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_3_ptr * const ftmad_fns[4] = { + NULL, gen_helper_sve_ftmad_h, + gen_helper_sve_ftmad_s, gen_helper_sve_ftmad_d, +}; +TRANS_FEAT_NONSTREAMING(FTMAD, aa64_sve, gen_gvec_fpst_zzz, + ftmad_fns[a->esz], a->rd, a->rn, a->rm, a->imm, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) /* *** SVE Floating Point Accumulating Reduction Group @@ -4406,9 +3924,10 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) TCGv_i64 t_val; TCGv_i32 t_desc; - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } + s->is_nonstreaming = true; if (!sve_access_check(s)) { return true; } @@ -4419,11 +3938,10 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) tcg_gen_addi_ptr(t_rm, cpu_env, vec_full_reg_offset(s, a->rm)); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->pg)); t_fpst = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - t_desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); + t_desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); fns[a->esz - 1](t_val, t_val, t_rm, t_pg, t_fpst, t_desc); - tcg_temp_free_i32(t_desc); tcg_temp_free_ptr(t_fpst); tcg_temp_free_ptr(t_pg); tcg_temp_free_ptr(t_rm); @@ -4437,90 +3955,50 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) *** SVE Floating Point Arithmetic - Unpredicated Group */ -static bool do_zzz_fp(DisasContext *s, arg_rrr_esz *a, - gen_helper_gvec_3_ptr *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} - - #define DO_FP3(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3_ptr * const fns[4] = { \ + static gen_helper_gvec_3_ptr * const name##_fns[4] = { \ NULL, gen_helper_gvec_##name##_h, \ gen_helper_gvec_##name##_s, gen_helper_gvec_##name##_d \ }; \ - return do_zzz_fp(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve, gen_gvec_fpst_arg_zzz, name##_fns[a->esz], a, 0) DO_FP3(FADD_zzz, fadd) DO_FP3(FSUB_zzz, fsub) DO_FP3(FMUL_zzz, fmul) -DO_FP3(FTSMUL, ftsmul) DO_FP3(FRECPS, recps) DO_FP3(FRSQRTS, rsqrts) #undef DO_FP3 +static gen_helper_gvec_3_ptr * const ftsmul_fns[4] = { + NULL, gen_helper_gvec_ftsmul_h, + gen_helper_gvec_ftsmul_s, gen_helper_gvec_ftsmul_d +}; +TRANS_FEAT_NONSTREAMING(FTSMUL, aa64_sve, gen_gvec_fpst_arg_zzz, + ftsmul_fns[a->esz], a, 0) + /* *** SVE Floating Point Arithmetic - Predicated Group */ -static bool do_zpzz_fp(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_4_ptr *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} - -#define DO_FP3(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4_ptr * const fns[4] = { \ - NULL, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ - }; \ - return do_zpzz_fp(s, a, fns[a->esz]); \ -} - -DO_FP3(FADD_zpzz, fadd) -DO_FP3(FSUB_zpzz, fsub) -DO_FP3(FMUL_zpzz, fmul) -DO_FP3(FMIN_zpzz, fmin) -DO_FP3(FMAX_zpzz, fmax) -DO_FP3(FMINNM_zpzz, fminnum) -DO_FP3(FMAXNM_zpzz, fmaxnum) -DO_FP3(FABD, fabd) -DO_FP3(FSCALE, fscalbn) -DO_FP3(FDIV, fdiv) -DO_FP3(FMULX, fmulx) - -#undef DO_FP3 +#define DO_ZPZZ_FP(NAME, FEAT, name) \ + static gen_helper_gvec_4_ptr * const name##_zpzz_fns[4] = { \ + NULL, gen_helper_##name##_h, \ + gen_helper_##name##_s, gen_helper_##name##_d \ + }; \ + TRANS_FEAT(NAME, FEAT, gen_gvec_fpst_arg_zpzz, name##_zpzz_fns[a->esz], a) + +DO_ZPZZ_FP(FADD_zpzz, aa64_sve, sve_fadd) +DO_ZPZZ_FP(FSUB_zpzz, aa64_sve, sve_fsub) +DO_ZPZZ_FP(FMUL_zpzz, aa64_sve, sve_fmul) +DO_ZPZZ_FP(FMIN_zpzz, aa64_sve, sve_fmin) +DO_ZPZZ_FP(FMAX_zpzz, aa64_sve, sve_fmax) +DO_ZPZZ_FP(FMINNM_zpzz, aa64_sve, sve_fminnum) +DO_ZPZZ_FP(FMAXNM_zpzz, aa64_sve, sve_fmaxnum) +DO_ZPZZ_FP(FABD, aa64_sve, sve_fabd) +DO_ZPZZ_FP(FSCALE, aa64_sve, sve_fscalbn) +DO_ZPZZ_FP(FDIV, aa64_sve, sve_fdiv) +DO_ZPZZ_FP(FMULX, aa64_sve, sve_fmulx) typedef void gen_helper_sve_fp2scalar(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, TCGv_i32); @@ -4540,45 +4018,42 @@ static void do_fp_scalar(DisasContext *s, int zd, int zn, int pg, bool is_fp16, tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); status = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR); - desc = tcg_const_i32(simd_desc(vsz, vsz, 0)); + desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); fn(t_zd, t_zn, t_pg, scalar, status, desc); - tcg_temp_free_i32(desc); tcg_temp_free_ptr(status); tcg_temp_free_ptr(t_pg); tcg_temp_free_ptr(t_zn); tcg_temp_free_ptr(t_zd); } -static void do_fp_imm(DisasContext *s, arg_rpri_esz *a, uint64_t imm, +static bool do_fp_imm(DisasContext *s, arg_rpri_esz *a, uint64_t imm, gen_helper_sve_fp2scalar *fn) { - TCGv_i64 temp = tcg_const_i64(imm); - do_fp_scalar(s, a->rd, a->rn, a->pg, a->esz == MO_16, temp, fn); - tcg_temp_free_i64(temp); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + do_fp_scalar(s, a->rd, a->rn, a->pg, a->esz == MO_16, + tcg_constant_i64(imm), fn); + } + return true; } -#define DO_FP_IMM(NAME, name, const0, const1) \ -static bool trans_##NAME##_zpzi(DisasContext *s, arg_rpri_esz *a) \ -{ \ - static gen_helper_sve_fp2scalar * const fns[3] = { \ - gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, \ - gen_helper_sve_##name##_d \ - }; \ - static uint64_t const val[3][2] = { \ - { float16_##const0, float16_##const1 }, \ - { float32_##const0, float32_##const1 }, \ - { float64_##const0, float64_##const1 }, \ - }; \ - if (a->esz == 0) { \ - return false; \ - } \ - if (sve_access_check(s)) { \ - do_fp_imm(s, a, val[a->esz - 1][a->imm], fns[a->esz - 1]); \ - } \ - return true; \ -} +#define DO_FP_IMM(NAME, name, const0, const1) \ + static gen_helper_sve_fp2scalar * const name##_fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, \ + gen_helper_sve_##name##_d \ + }; \ + static uint64_t const name##_const[4][2] = { \ + { -1, -1 }, \ + { float16_##const0, float16_##const1 }, \ + { float32_##const0, float32_##const1 }, \ + { float64_##const0, float64_##const1 }, \ + }; \ + TRANS_FEAT(NAME##_zpzi, aa64_sve, do_fp_imm, a, \ + name##_const[a->esz][a->imm], name##_fns[a->esz]) DO_FP_IMM(FADD, fadds, half, one) DO_FP_IMM(FSUB, fsubs, half, one) @@ -4611,14 +4086,11 @@ static bool do_fp_cmp(DisasContext *s, arg_rprr_esz *a, } #define DO_FPCMP(NAME, name) \ -static bool trans_##NAME##_ppzz(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4_ptr * const fns[4] = { \ + static gen_helper_gvec_4_ptr * const name##_fns[4] = { \ NULL, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ }; \ - return do_fp_cmp(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_ppzz, aa64_sve, do_fp_cmp, a, name##_fns[a->esz]) DO_FPCMP(FCMGE, fcmge) DO_FPCMP(FCMGT, fcmgt) @@ -4630,59 +4102,22 @@ DO_FPCMP(FACGT, facgt) #undef DO_FPCMP -static bool trans_FCADD(DisasContext *s, arg_FCADD *a) -{ - static gen_helper_gvec_4_ptr * const fns[3] = { - gen_helper_sve_fcadd_h, - gen_helper_sve_fcadd_s, - gen_helper_sve_fcadd_d - }; - - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, a->rot, fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} - -static bool do_fmla(DisasContext *s, arg_rprrr_esz *a, - gen_helper_gvec_5_ptr *fn) -{ - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_4_ptr * const fcadd_fns[] = { + NULL, gen_helper_sve_fcadd_h, + gen_helper_sve_fcadd_s, gen_helper_sve_fcadd_d, +}; +TRANS_FEAT(FCADD, aa64_sve, gen_gvec_fpst_zzzp, fcadd_fns[a->esz], + a->rd, a->rn, a->rm, a->pg, a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) #define DO_FMLA(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprrr_esz *a) \ -{ \ - static gen_helper_gvec_5_ptr * const fns[4] = { \ - NULL, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ - }; \ - return do_fmla(s, a, fns[a->esz]); \ -} + static gen_helper_gvec_5_ptr * const name##_fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ + }; \ + TRANS_FEAT(NAME, aa64_sve, gen_gvec_fpst_zzzzp, name##_fns[a->esz], \ + a->rd, a->rn, a->rm, a->ra, a->pg, 0, \ + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) DO_FMLA(FMLA_zpzzz, fmla_zpzzz) DO_FMLA(FMLS_zpzzz, fmls_zpzzz) @@ -4691,368 +4126,180 @@ DO_FMLA(FNMLS_zpzzz, fnmls_zpzzz) #undef DO_FMLA -static bool trans_FCMLA_zpzzz(DisasContext *s, arg_FCMLA_zpzzz *a) +static gen_helper_gvec_5_ptr * const fcmla_fns[4] = { + NULL, gen_helper_sve_fcmla_zpzzz_h, + gen_helper_sve_fcmla_zpzzz_s, gen_helper_sve_fcmla_zpzzz_d, +}; +TRANS_FEAT(FCMLA_zpzzz, aa64_sve, gen_gvec_fpst_zzzzp, fcmla_fns[a->esz], + a->rd, a->rn, a->rm, a->ra, a->pg, a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) + +static gen_helper_gvec_4_ptr * const fcmla_idx_fns[4] = { + NULL, gen_helper_gvec_fcmlah_idx, gen_helper_gvec_fcmlas_idx, NULL +}; +TRANS_FEAT(FCMLA_zzxz, aa64_sve, gen_gvec_fpst_zzzz, fcmla_idx_fns[a->esz], + a->rd, a->rn, a->rm, a->ra, a->index * 4 + a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) + +/* + *** SVE Floating Point Unary Operations Predicated Group + */ + +TRANS_FEAT(FCVT_sh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_sh, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_hs, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_hs, a, 0, FPST_FPCR) + +TRANS_FEAT(BFCVT, aa64_sve_bf16, gen_gvec_fpst_arg_zpz, + gen_helper_sve_bfcvt, a, 0, FPST_FPCR) + +TRANS_FEAT(FCVT_dh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_dh, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_hd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_hd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_ds, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_sd, a, 0, FPST_FPCR) + +TRANS_FEAT(FCVTZS_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZU_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZS_hs, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_hs, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZU_hs, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_hs, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZS_hd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_hd, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZU_hd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_hd, a, 0, FPST_FPCR_F16) + +TRANS_FEAT(FCVTZS_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_ss, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_ss, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZS_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_sd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_sd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZS_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_ds, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_ds, a, 0, FPST_FPCR) + +TRANS_FEAT(FCVTZS_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_dd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_dd, a, 0, FPST_FPCR) + +static gen_helper_gvec_3_ptr * const frint_fns[] = { + NULL, + gen_helper_sve_frint_h, + gen_helper_sve_frint_s, + gen_helper_sve_frint_d +}; +TRANS_FEAT(FRINTI, aa64_sve, gen_gvec_fpst_arg_zpz, frint_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) + +static gen_helper_gvec_3_ptr * const frintx_fns[] = { + NULL, + gen_helper_sve_frintx_h, + gen_helper_sve_frintx_s, + gen_helper_sve_frintx_d +}; +TRANS_FEAT(FRINTX, aa64_sve, gen_gvec_fpst_arg_zpz, frintx_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + +static bool do_frint_mode(DisasContext *s, arg_rpr_esz *a, + int mode, gen_helper_gvec_3_ptr *fn) { - static gen_helper_gvec_5_ptr * const fns[4] = { - NULL, - gen_helper_sve_fcmla_zpzzz_h, - gen_helper_sve_fcmla_zpzzz_s, - gen_helper_sve_fcmla_zpzzz_d, - }; + unsigned vsz; + TCGv_i32 tmode; + TCGv_ptr status; - if (a->esz == 0) { + if (fn == NULL) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, a->rot, fns[a->esz]); - tcg_temp_free_ptr(status); + if (!sve_access_check(s)) { + return true; } - return true; -} -static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) -{ - static gen_helper_gvec_4_ptr * const fns[2] = { - gen_helper_gvec_fcmlah_idx, - gen_helper_gvec_fcmlas_idx, - }; + vsz = vec_full_reg_size(s); + tmode = tcg_const_i32(mode); + status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_debug_assert(a->esz == 1 || a->esz == 2); - tcg_debug_assert(a->rd == a->ra); - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, - a->index * 4 + a->rot, - fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} + gen_helper_set_rmode(tmode, tmode, status); -/* - *** SVE Floating Point Unary Operations Predicated Group - */ + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + pred_full_reg_offset(s, a->pg), + status, vsz, vsz, 0, fn); -static bool do_zpz_ptr(DisasContext *s, int rd, int rn, int pg, - bool is_fp16, gen_helper_gvec_3_ptr *fn) -{ - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - pred_full_reg_offset(s, pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } + gen_helper_set_rmode(tmode, tmode, status); + tcg_temp_free_i32(tmode); + tcg_temp_free_ptr(status); return true; } -static bool trans_FCVT_sh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_sh); -} - -static bool trans_FCVT_hs(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_hs); -} - -static bool trans_BFCVT(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_bfcvt); -} - -static bool trans_FCVT_dh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_dh); -} - -static bool trans_FCVT_hd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_hd); -} - -static bool trans_FCVT_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_ds); -} - -static bool trans_FCVT_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_sd); -} - -static bool trans_FCVTZS_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzs_hh); -} - -static bool trans_FCVTZU_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzu_hh); -} - -static bool trans_FCVTZS_hs(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzs_hs); -} - -static bool trans_FCVTZU_hs(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzu_hs); -} - -static bool trans_FCVTZS_hd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzs_hd); -} - -static bool trans_FCVTZU_hd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzu_hd); -} - -static bool trans_FCVTZS_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_ss); -} - -static bool trans_FCVTZU_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_ss); -} - -static bool trans_FCVTZS_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_sd); -} - -static bool trans_FCVTZU_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_sd); -} - -static bool trans_FCVTZS_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_ds); -} - -static bool trans_FCVTZU_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_ds); -} +TRANS_FEAT(FRINTN, aa64_sve, do_frint_mode, a, + float_round_nearest_even, frint_fns[a->esz]) +TRANS_FEAT(FRINTP, aa64_sve, do_frint_mode, a, + float_round_up, frint_fns[a->esz]) +TRANS_FEAT(FRINTM, aa64_sve, do_frint_mode, a, + float_round_down, frint_fns[a->esz]) +TRANS_FEAT(FRINTZ, aa64_sve, do_frint_mode, a, + float_round_to_zero, frint_fns[a->esz]) +TRANS_FEAT(FRINTA, aa64_sve, do_frint_mode, a, + float_round_ties_away, frint_fns[a->esz]) -static bool trans_FCVTZS_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_dd); -} - -static bool trans_FCVTZU_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_dd); -} - -static gen_helper_gvec_3_ptr * const frint_fns[3] = { - gen_helper_sve_frint_h, - gen_helper_sve_frint_s, - gen_helper_sve_frint_d +static gen_helper_gvec_3_ptr * const frecpx_fns[] = { + NULL, gen_helper_sve_frecpx_h, + gen_helper_sve_frecpx_s, gen_helper_sve_frecpx_d, }; +TRANS_FEAT(FRECPX, aa64_sve, gen_gvec_fpst_arg_zpz, frecpx_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool trans_FRINTI(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, - frint_fns[a->esz - 1]); -} - -static bool trans_FRINTX(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_frintx_h, - gen_helper_sve_frintx_s, - gen_helper_sve_frintx_d - }; - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, fns[a->esz - 1]); -} - -static bool do_frint_mode(DisasContext *s, arg_rpr_esz *a, - int mode, gen_helper_gvec_3_ptr *fn) -{ - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_i32 tmode = tcg_const_i32(mode); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - - gen_helper_set_rmode(tmode, tmode, status); - - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - - gen_helper_set_rmode(tmode, tmode, status); - tcg_temp_free_i32(tmode); - tcg_temp_free_ptr(status); - } - return true; -} - -static bool trans_FRINTN(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_frint_mode(s, a, float_round_nearest_even, frint_fns[a->esz - 1]); -} - -static bool trans_FRINTP(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_frint_mode(s, a, float_round_up, frint_fns[a->esz - 1]); -} - -static bool trans_FRINTM(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_frint_mode(s, a, float_round_down, frint_fns[a->esz - 1]); -} - -static bool trans_FRINTZ(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_frint_mode(s, a, float_round_to_zero, frint_fns[a->esz - 1]); -} - -static bool trans_FRINTA(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_frint_mode(s, a, float_round_ties_away, frint_fns[a->esz - 1]); -} - -static bool trans_FRECPX(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_frecpx_h, - gen_helper_sve_frecpx_s, - gen_helper_sve_frecpx_d - }; - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, fns[a->esz - 1]); -} - -static bool trans_FSQRT(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_fsqrt_h, - gen_helper_sve_fsqrt_s, - gen_helper_sve_fsqrt_d - }; - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, fns[a->esz - 1]); -} - -static bool trans_SCVTF_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_scvt_hh); -} - -static bool trans_SCVTF_sh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_scvt_sh); -} - -static bool trans_SCVTF_dh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_scvt_dh); -} - -static bool trans_SCVTF_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_ss); -} - -static bool trans_SCVTF_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_ds); -} - -static bool trans_SCVTF_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_sd); -} - -static bool trans_SCVTF_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_dd); -} - -static bool trans_UCVTF_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_ucvt_hh); -} - -static bool trans_UCVTF_sh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_ucvt_sh); -} - -static bool trans_UCVTF_dh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_ucvt_dh); -} - -static bool trans_UCVTF_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_ss); -} - -static bool trans_UCVTF_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_ds); -} - -static bool trans_UCVTF_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_sd); -} - -static bool trans_UCVTF_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_dd); -} +static gen_helper_gvec_3_ptr * const fsqrt_fns[] = { + NULL, gen_helper_sve_fsqrt_h, + gen_helper_sve_fsqrt_s, gen_helper_sve_fsqrt_d, +}; +TRANS_FEAT(FSQRT, aa64_sve, gen_gvec_fpst_arg_zpz, fsqrt_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) + +TRANS_FEAT(SCVTF_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(SCVTF_sh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_sh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(SCVTF_dh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_dh, a, 0, FPST_FPCR_F16) + +TRANS_FEAT(SCVTF_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_ss, a, 0, FPST_FPCR) +TRANS_FEAT(SCVTF_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_ds, a, 0, FPST_FPCR) + +TRANS_FEAT(SCVTF_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_sd, a, 0, FPST_FPCR) +TRANS_FEAT(SCVTF_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_dd, a, 0, FPST_FPCR) + +TRANS_FEAT(UCVTF_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(UCVTF_sh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_sh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(UCVTF_dh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_dh, a, 0, FPST_FPCR_F16) + +TRANS_FEAT(UCVTF_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_ss, a, 0, FPST_FPCR) +TRANS_FEAT(UCVTF_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_ds, a, 0, FPST_FPCR) +TRANS_FEAT(UCVTF_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_sd, a, 0, FPST_FPCR) + +TRANS_FEAT(UCVTF_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_dd, a, 0, FPST_FPCR) /* *** SVE Memory - 32-bit Gather and Unsized Contiguous Group @@ -5062,7 +4309,8 @@ static bool trans_UCVTF_dd(DisasContext *s, arg_rpr_esz *a) * The load should begin at the address Rn + IMM. */ -static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) +void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs, + int len, int rn, int imm) { int len_align = QEMU_ALIGN_DOWN(len, 8); int len_remain = len % 8; @@ -5088,7 +4336,7 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) t0 = tcg_temp_new_i64(); for (i = 0; i < len_align; i += 8) { tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ); - tcg_gen_st_i64(t0, cpu_env, vofs + i); + tcg_gen_st_i64(t0, base, vofs + i); tcg_gen_addi_i64(clean_addr, clean_addr, 8); } tcg_temp_free_i64(t0); @@ -5101,6 +4349,12 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) clean_addr = new_tmp_a64_local(s); tcg_gen_mov_i64(clean_addr, t0); + if (base != cpu_env) { + TCGv_ptr b = tcg_temp_local_new_ptr(); + tcg_gen_mov_ptr(b, base); + base = b; + } + gen_set_label(loop); t0 = tcg_temp_new_i64(); @@ -5108,7 +4362,7 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) tcg_gen_addi_i64(clean_addr, clean_addr, 8); tp = tcg_temp_new_ptr(); - tcg_gen_add_ptr(tp, cpu_env, i); + tcg_gen_add_ptr(tp, base, i); tcg_gen_addi_ptr(i, i, 8); tcg_gen_st_i64(t0, tp, vofs); tcg_temp_free_ptr(tp); @@ -5116,6 +4370,11 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop); tcg_temp_free_ptr(i); + + if (base != cpu_env) { + tcg_temp_free_ptr(base); + assert(len_remain == 0); + } } /* @@ -5144,13 +4403,14 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) default: g_assert_not_reached(); } - tcg_gen_st_i64(t0, cpu_env, vofs + len_align); + tcg_gen_st_i64(t0, base, vofs + len_align); tcg_temp_free_i64(t0); } } /* Similarly for stores. */ -static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) +void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs, + int len, int rn, int imm) { int len_align = QEMU_ALIGN_DOWN(len, 8); int len_remain = len % 8; @@ -5176,7 +4436,7 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) t0 = tcg_temp_new_i64(); for (i = 0; i < len_align; i += 8) { - tcg_gen_ld_i64(t0, cpu_env, vofs + i); + tcg_gen_ld_i64(t0, base, vofs + i); tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ); tcg_gen_addi_i64(clean_addr, clean_addr, 8); } @@ -5190,11 +4450,17 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) clean_addr = new_tmp_a64_local(s); tcg_gen_mov_i64(clean_addr, t0); + if (base != cpu_env) { + TCGv_ptr b = tcg_temp_local_new_ptr(); + tcg_gen_mov_ptr(b, base); + base = b; + } + gen_set_label(loop); t0 = tcg_temp_new_i64(); tp = tcg_temp_new_ptr(); - tcg_gen_add_ptr(tp, cpu_env, i); + tcg_gen_add_ptr(tp, base, i); tcg_gen_ld_i64(t0, tp, vofs); tcg_gen_addi_ptr(i, i, 8); tcg_temp_free_ptr(tp); @@ -5205,12 +4471,17 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop); tcg_temp_free_ptr(i); + + if (base != cpu_env) { + tcg_temp_free_ptr(base); + assert(len_remain == 0); + } } /* Predicate register stores can be any multiple of 2. */ if (len_remain) { t0 = tcg_temp_new_i64(); - tcg_gen_ld_i64(t0, cpu_env, vofs + len_align); + tcg_gen_ld_i64(t0, base, vofs + len_align); switch (len_remain) { case 2: @@ -5236,40 +4507,52 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) static bool trans_LDR_zri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = vec_full_reg_size(s); int off = vec_full_reg_offset(s, a->rd); - do_ldr(s, off, size, a->rn, a->imm * size); + gen_sve_ldr(s, cpu_env, off, size, a->rn, a->imm * size); } return true; } static bool trans_LDR_pri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = pred_full_reg_size(s); int off = pred_full_reg_offset(s, a->rd); - do_ldr(s, off, size, a->rn, a->imm * size); + gen_sve_ldr(s, cpu_env, off, size, a->rn, a->imm * size); } return true; } static bool trans_STR_zri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = vec_full_reg_size(s); int off = vec_full_reg_offset(s, a->rd); - do_str(s, off, size, a->rn, a->imm * size); + gen_sve_str(s, cpu_env, off, size, a->rn, a->imm * size); } return true; } static bool trans_STR_pri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = pred_full_reg_size(s); int off = pred_full_reg_offset(s, a->rd); - do_str(s, off, size, a->rn, a->imm * size); + gen_sve_str(s, cpu_env, off, size, a->rn, a->imm * size); } return true; } @@ -5302,7 +4585,6 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, { unsigned vsz = vec_full_reg_size(s); TCGv_ptr t_pg; - TCGv_i32 t_desc; int desc = 0; /* @@ -5324,14 +4606,12 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, } desc = simd_desc(vsz, vsz, zt | desc); - t_desc = tcg_const_i32(desc); t_pg = tcg_temp_new_ptr(); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); - fn(cpu_env, t_pg, addr, t_desc); + fn(cpu_env, t_pg, addr, tcg_constant_i32(desc)); tcg_temp_free_ptr(t_pg); - tcg_temp_free_i32(t_desc); } /* Indexed by [mte][be][dtype][nreg] */ @@ -5469,7 +4749,7 @@ static void do_ld_zpa(DisasContext *s, int zt, int pg, static bool trans_LD_zprr(DisasContext *s, arg_rprr_load *a) { - if (a->rm == 31) { + if (a->rm == 31 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -5483,6 +4763,9 @@ static bool trans_LD_zprr(DisasContext *s, arg_rprr_load *a) static bool trans_LD_zpri(DisasContext *s, arg_rpri_load *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int vsz = vec_full_reg_size(s); int elements = vsz >> dtype_esz[a->dtype]; @@ -5584,6 +4867,10 @@ static bool trans_LDFF1_zprr(DisasContext *s, arg_rprr_load *a) gen_helper_sve_ldff1dd_be_r_mte } }, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), dtype_msz(a->dtype)); @@ -5682,6 +4969,10 @@ static bool trans_LDNF1_zpri(DisasContext *s, arg_rpri_load *a) gen_helper_sve_ldnf1dd_be_r_mte } }, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; if (sve_access_check(s)) { int vsz = vec_full_reg_size(s); int elements = vsz >> dtype_esz[a->dtype]; @@ -5711,7 +5002,7 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) * for this load operation. */ TCGv_i64 tmp = tcg_temp_new_i64(); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN poff += 6; #endif tcg_gen_ld16u_i64(tmp, cpu_env, poff); @@ -5739,7 +5030,7 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) static bool trans_LD1RQ_zprr(DisasContext *s, arg_rprr_load *a) { - if (a->rm == 31) { + if (a->rm == 31 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -5754,6 +5045,9 @@ static bool trans_LD1RQ_zprr(DisasContext *s, arg_rprr_load *a) static bool trans_LD1RQ_zpri(DisasContext *s, arg_rpri_load *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_addi_i64(addr, cpu_reg_sp(s, a->rn), a->imm * 16); @@ -5790,7 +5084,7 @@ static void do_ldro(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) * for this load operation. */ TCGv_i64 tmp = tcg_temp_new_i64(); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN poff += 4; #endif tcg_gen_ld32u_i64(tmp, cpu_env, poff); @@ -5833,6 +5127,7 @@ static bool trans_LD1RO_zprr(DisasContext *s, arg_rprr_load *a) if (a->rm == 31) { return false; } + s->is_nonstreaming = true; if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), dtype_msz(a->dtype)); @@ -5847,6 +5142,7 @@ static bool trans_LD1RO_zpri(DisasContext *s, arg_rpri_load *a) if (!dc_isar_feature(aa64_sve_f64mm, s)) { return false; } + s->is_nonstreaming = true; if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_addi_i64(addr, cpu_reg_sp(s, a->rn), a->imm * 32); @@ -5865,6 +5161,9 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) TCGLabel *over; TCGv_i64 temp, clean_addr; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -6033,6 +5332,9 @@ static void do_st_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (a->rm == 31 || a->msz > a->esz) { return false; } @@ -6047,6 +5349,9 @@ static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) static bool trans_ST_zpri(DisasContext *s, arg_rpri_store *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (a->msz > a->esz) { return false; } @@ -6074,7 +5379,6 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, TCGv_ptr t_zm = tcg_temp_new_ptr(); TCGv_ptr t_pg = tcg_temp_new_ptr(); TCGv_ptr t_zt = tcg_temp_new_ptr(); - TCGv_i32 t_desc; int desc = 0; if (s->mte_active[0]) { @@ -6086,17 +5390,15 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, desc <<= SVE_MTEDESC_SHIFT; } desc = simd_desc(vsz, vsz, desc | scale); - t_desc = tcg_const_i32(desc); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); tcg_gen_addi_ptr(t_zm, cpu_env, vec_full_reg_offset(s, zm)); tcg_gen_addi_ptr(t_zt, cpu_env, vec_full_reg_offset(s, zt)); - fn(cpu_env, t_zt, t_pg, t_zm, scalar, t_desc); + fn(cpu_env, t_zt, t_pg, t_zm, scalar, tcg_constant_i32(desc)); tcg_temp_free_ptr(t_zt); tcg_temp_free_ptr(t_zm); tcg_temp_free_ptr(t_pg); - tcg_temp_free_i32(t_desc); } /* Indexed by [mte][be][ff][xs][u][msz]. */ @@ -6433,7 +5735,11 @@ static bool trans_LD1_zprz(DisasContext *s, arg_LD1_zprz *a) bool be = s->be_data == MO_BE; bool mte = s->mte_active[0]; - if (!sve_access_check(s)) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; + if (!sve_access_check(s)) { return true; } @@ -6457,11 +5763,14 @@ static bool trans_LD1_zpiz(DisasContext *s, arg_LD1_zpiz *a) gen_helper_gvec_mem_scatter *fn = NULL; bool be = s->be_data == MO_BE; bool mte = s->mte_active[0]; - TCGv_i64 imm; if (a->esz < a->msz || (a->esz == a->msz && !a->u)) { return false; } + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; if (!sve_access_check(s)) { return true; } @@ -6479,9 +5788,8 @@ static bool trans_LD1_zpiz(DisasContext *s, arg_LD1_zpiz *a) /* Treat LD1_zpiz (zn[x] + imm) the same way as LD1_zprz (rn + zm[x]) * by loading the immediate into the scalar parameter. */ - imm = tcg_const_i64(a->imm << a->msz); - do_mem_zpz(s, a->rd, a->pg, a->rn, 0, imm, a->msz, false, fn); - tcg_temp_free_i64(imm); + do_mem_zpz(s, a->rd, a->pg, a->rn, 0, + tcg_constant_i64(a->imm << a->msz), a->msz, false, fn); return true; } @@ -6497,6 +5805,7 @@ static bool trans_LDNT1_zprz(DisasContext *s, arg_LD1_zprz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } + s->is_nonstreaming = true; if (!sve_access_check(s)) { return true; } @@ -6617,6 +5926,10 @@ static bool trans_ST1_zprz(DisasContext *s, arg_ST1_zprz *a) if (a->esz < a->msz || (a->msz == 0 && a->scale)) { return false; } + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; if (!sve_access_check(s)) { return true; } @@ -6640,11 +5953,14 @@ static bool trans_ST1_zpiz(DisasContext *s, arg_ST1_zpiz *a) gen_helper_gvec_mem_scatter *fn = NULL; bool be = s->be_data == MO_BE; bool mte = s->mte_active[0]; - TCGv_i64 imm; if (a->esz < a->msz) { return false; } + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; if (!sve_access_check(s)) { return true; } @@ -6662,9 +5978,8 @@ static bool trans_ST1_zpiz(DisasContext *s, arg_ST1_zpiz *a) /* Treat ST1_zpiz (zn[x] + imm) the same way as ST1_zprz (rn + zm[x]) * by loading the immediate into the scalar parameter. */ - imm = tcg_const_i64(a->imm << a->msz); - do_mem_zpz(s, a->rd, a->pg, a->rn, 0, imm, a->msz, true, fn); - tcg_temp_free_i64(imm); + do_mem_zpz(s, a->rd, a->pg, a->rn, 0, + tcg_constant_i64(a->imm << a->msz), a->msz, true, fn); return true; } @@ -6680,6 +5995,7 @@ static bool trans_STNT1_zprz(DisasContext *s, arg_ST1_zprz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } + s->is_nonstreaming = true; if (!sve_access_check(s)) { return true; } @@ -6706,6 +6022,9 @@ static bool trans_STNT1_zprz(DisasContext *s, arg_ST1_zprz *a) static bool trans_PRF(DisasContext *s, arg_PRF *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } /* Prefetch is a nop within QEMU. */ (void)sve_access_check(s); return true; @@ -6713,10 +6032,21 @@ static bool trans_PRF(DisasContext *s, arg_PRF *a) static bool trans_PRF_rr(DisasContext *s, arg_PRF_rr *a) { - if (a->rm == 31) { + if (a->rm == 31 || !dc_isar_feature(aa64_sve, s)) { + return false; + } + /* Prefetch is a nop within QEMU. */ + (void)sve_access_check(s); + return true; +} + +static bool trans_PRF_ns(DisasContext *s, arg_PRF_ns *a) +{ + if (!dc_isar_feature(aa64_sve, s)) { return false; } /* Prefetch is a nop within QEMU. */ + s->is_nonstreaming = true; (void)sve_access_check(s); return true; } @@ -6735,294 +6065,213 @@ static bool trans_PRF_rr(DisasContext *s, arg_PRF_rr *a) * In the meantime, just emit the moves. */ -static bool trans_MOVPRFX(DisasContext *s, arg_MOVPRFX *a) -{ - return do_mov_z(s, a->rd, a->rn); -} - -static bool trans_MOVPRFX_m(DisasContext *s, arg_rpr_esz *a) -{ - if (sve_access_check(s)) { - do_sel_z(s, a->rd, a->rn, a->rd, a->pg, a->esz); - } - return true; -} - -static bool trans_MOVPRFX_z(DisasContext *s, arg_rpr_esz *a) -{ - return do_movz_zpz(s, a->rd, a->rn, a->pg, a->esz, false); -} +TRANS_FEAT(MOVPRFX, aa64_sve, do_mov_z, a->rd, a->rn) +TRANS_FEAT(MOVPRFX_m, aa64_sve, do_sel_z, a->rd, a->rn, a->rd, a->pg, a->esz) +TRANS_FEAT(MOVPRFX_z, aa64_sve, do_movz_zpz, a->rd, a->rn, a->pg, a->esz, false) /* * SVE2 Integer Multiply - Unpredicated */ -static bool trans_MUL_zzz(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, tcg_gen_gvec_mul, a->esz, a->rd, a->rn, a->rm); - } - return true; -} - -static bool do_sve2_zzz_ool(DisasContext *s, arg_rrr_esz *a, - gen_helper_gvec_3 *fn) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); - } - return true; -} +TRANS_FEAT(MUL_zzz, aa64_sve2, gen_gvec_fn_arg_zzz, tcg_gen_gvec_mul, a) -static bool trans_SMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_gvec_smulh_b, gen_helper_gvec_smulh_h, - gen_helper_gvec_smulh_s, gen_helper_gvec_smulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const smulh_zzz_fns[4] = { + gen_helper_gvec_smulh_b, gen_helper_gvec_smulh_h, + gen_helper_gvec_smulh_s, gen_helper_gvec_smulh_d, +}; +TRANS_FEAT(SMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + smulh_zzz_fns[a->esz], a, 0) -static bool trans_UMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_gvec_umulh_b, gen_helper_gvec_umulh_h, - gen_helper_gvec_umulh_s, gen_helper_gvec_umulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const umulh_zzz_fns[4] = { + gen_helper_gvec_umulh_b, gen_helper_gvec_umulh_h, + gen_helper_gvec_umulh_s, gen_helper_gvec_umulh_d, +}; +TRANS_FEAT(UMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + umulh_zzz_fns[a->esz], a, 0) -static bool trans_PMUL_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_sve2_zzz_ool(s, a, gen_helper_gvec_pmul_b); -} +TRANS_FEAT(PMUL_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + gen_helper_gvec_pmul_b, a, 0) -static bool trans_SQDMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqdmulh_b, gen_helper_sve2_sqdmulh_h, - gen_helper_sve2_sqdmulh_s, gen_helper_sve2_sqdmulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sqdmulh_zzz_fns[4] = { + gen_helper_sve2_sqdmulh_b, gen_helper_sve2_sqdmulh_h, + gen_helper_sve2_sqdmulh_s, gen_helper_sve2_sqdmulh_d, +}; +TRANS_FEAT(SQDMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqdmulh_zzz_fns[a->esz], a, 0) -static bool trans_SQRDMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqrdmulh_b, gen_helper_sve2_sqrdmulh_h, - gen_helper_sve2_sqrdmulh_s, gen_helper_sve2_sqrdmulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sqrdmulh_zzz_fns[4] = { + gen_helper_sve2_sqrdmulh_b, gen_helper_sve2_sqrdmulh_h, + gen_helper_sve2_sqrdmulh_s, gen_helper_sve2_sqrdmulh_d, +}; +TRANS_FEAT(SQRDMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqrdmulh_zzz_fns[a->esz], a, 0) /* * SVE2 Integer - Predicated */ -static bool do_sve2_zpzz_ool(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_4 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzz_ool(s, a, fn); -} - -static bool trans_SADALP_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[3] = { - gen_helper_sve2_sadalp_zpzz_h, - gen_helper_sve2_sadalp_zpzz_s, - gen_helper_sve2_sadalp_zpzz_d, - }; - if (a->esz == 0) { - return false; - } - return do_sve2_zpzz_ool(s, a, fns[a->esz - 1]); -} +static gen_helper_gvec_4 * const sadlp_fns[4] = { + NULL, gen_helper_sve2_sadalp_zpzz_h, + gen_helper_sve2_sadalp_zpzz_s, gen_helper_sve2_sadalp_zpzz_d, +}; +TRANS_FEAT(SADALP_zpzz, aa64_sve2, gen_gvec_ool_arg_zpzz, + sadlp_fns[a->esz], a, 0) -static bool trans_UADALP_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[3] = { - gen_helper_sve2_uadalp_zpzz_h, - gen_helper_sve2_uadalp_zpzz_s, - gen_helper_sve2_uadalp_zpzz_d, - }; - if (a->esz == 0) { - return false; - } - return do_sve2_zpzz_ool(s, a, fns[a->esz - 1]); -} +static gen_helper_gvec_4 * const uadlp_fns[4] = { + NULL, gen_helper_sve2_uadalp_zpzz_h, + gen_helper_sve2_uadalp_zpzz_s, gen_helper_sve2_uadalp_zpzz_d, +}; +TRANS_FEAT(UADALP_zpzz, aa64_sve2, gen_gvec_ool_arg_zpzz, + uadlp_fns[a->esz], a, 0) /* * SVE2 integer unary operations (predicated) */ -static bool do_sve2_zpz_ool(DisasContext *s, arg_rpr_esz *a, - gen_helper_gvec_3 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ool(s, a, fn); -} - -static bool trans_URECPE(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz != 2) { - return false; - } - return do_sve2_zpz_ool(s, a, gen_helper_sve2_urecpe_s); -} - -static bool trans_URSQRTE(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz != 2) { - return false; - } - return do_sve2_zpz_ool(s, a, gen_helper_sve2_ursqrte_s); -} +TRANS_FEAT(URECPE, aa64_sve2, gen_gvec_ool_arg_zpz, + a->esz == 2 ? gen_helper_sve2_urecpe_s : NULL, a, 0) -static bool trans_SQABS(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqabs_b, gen_helper_sve2_sqabs_h, - gen_helper_sve2_sqabs_s, gen_helper_sve2_sqabs_d, - }; - return do_sve2_zpz_ool(s, a, fns[a->esz]); -} +TRANS_FEAT(URSQRTE, aa64_sve2, gen_gvec_ool_arg_zpz, + a->esz == 2 ? gen_helper_sve2_ursqrte_s : NULL, a, 0) -static bool trans_SQNEG(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqneg_b, gen_helper_sve2_sqneg_h, - gen_helper_sve2_sqneg_s, gen_helper_sve2_sqneg_d, - }; - return do_sve2_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sqabs_fns[4] = { + gen_helper_sve2_sqabs_b, gen_helper_sve2_sqabs_h, + gen_helper_sve2_sqabs_s, gen_helper_sve2_sqabs_d, +}; +TRANS_FEAT(SQABS, aa64_sve2, gen_gvec_ool_arg_zpz, sqabs_fns[a->esz], a, 0) -#define DO_SVE2_ZPZZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4 * const fns[4] = { \ - gen_helper_sve2_##name##_zpzz_b, gen_helper_sve2_##name##_zpzz_h, \ - gen_helper_sve2_##name##_zpzz_s, gen_helper_sve2_##name##_zpzz_d, \ - }; \ - return do_sve2_zpzz_ool(s, a, fns[a->esz]); \ -} +static gen_helper_gvec_3 * const sqneg_fns[4] = { + gen_helper_sve2_sqneg_b, gen_helper_sve2_sqneg_h, + gen_helper_sve2_sqneg_s, gen_helper_sve2_sqneg_d, +}; +TRANS_FEAT(SQNEG, aa64_sve2, gen_gvec_ool_arg_zpz, sqneg_fns[a->esz], a, 0) -DO_SVE2_ZPZZ(SQSHL, sqshl) -DO_SVE2_ZPZZ(SQRSHL, sqrshl) -DO_SVE2_ZPZZ(SRSHL, srshl) +DO_ZPZZ(SQSHL, aa64_sve2, sve2_sqshl) +DO_ZPZZ(SQRSHL, aa64_sve2, sve2_sqrshl) +DO_ZPZZ(SRSHL, aa64_sve2, sve2_srshl) -DO_SVE2_ZPZZ(UQSHL, uqshl) -DO_SVE2_ZPZZ(UQRSHL, uqrshl) -DO_SVE2_ZPZZ(URSHL, urshl) +DO_ZPZZ(UQSHL, aa64_sve2, sve2_uqshl) +DO_ZPZZ(UQRSHL, aa64_sve2, sve2_uqrshl) +DO_ZPZZ(URSHL, aa64_sve2, sve2_urshl) -DO_SVE2_ZPZZ(SHADD, shadd) -DO_SVE2_ZPZZ(SRHADD, srhadd) -DO_SVE2_ZPZZ(SHSUB, shsub) +DO_ZPZZ(SHADD, aa64_sve2, sve2_shadd) +DO_ZPZZ(SRHADD, aa64_sve2, sve2_srhadd) +DO_ZPZZ(SHSUB, aa64_sve2, sve2_shsub) -DO_SVE2_ZPZZ(UHADD, uhadd) -DO_SVE2_ZPZZ(URHADD, urhadd) -DO_SVE2_ZPZZ(UHSUB, uhsub) +DO_ZPZZ(UHADD, aa64_sve2, sve2_uhadd) +DO_ZPZZ(URHADD, aa64_sve2, sve2_urhadd) +DO_ZPZZ(UHSUB, aa64_sve2, sve2_uhsub) -DO_SVE2_ZPZZ(ADDP, addp) -DO_SVE2_ZPZZ(SMAXP, smaxp) -DO_SVE2_ZPZZ(UMAXP, umaxp) -DO_SVE2_ZPZZ(SMINP, sminp) -DO_SVE2_ZPZZ(UMINP, uminp) +DO_ZPZZ(ADDP, aa64_sve2, sve2_addp) +DO_ZPZZ(SMAXP, aa64_sve2, sve2_smaxp) +DO_ZPZZ(UMAXP, aa64_sve2, sve2_umaxp) +DO_ZPZZ(SMINP, aa64_sve2, sve2_sminp) +DO_ZPZZ(UMINP, aa64_sve2, sve2_uminp) -DO_SVE2_ZPZZ(SQADD_zpzz, sqadd) -DO_SVE2_ZPZZ(UQADD_zpzz, uqadd) -DO_SVE2_ZPZZ(SQSUB_zpzz, sqsub) -DO_SVE2_ZPZZ(UQSUB_zpzz, uqsub) -DO_SVE2_ZPZZ(SUQADD, suqadd) -DO_SVE2_ZPZZ(USQADD, usqadd) +DO_ZPZZ(SQADD_zpzz, aa64_sve2, sve2_sqadd) +DO_ZPZZ(UQADD_zpzz, aa64_sve2, sve2_uqadd) +DO_ZPZZ(SQSUB_zpzz, aa64_sve2, sve2_sqsub) +DO_ZPZZ(UQSUB_zpzz, aa64_sve2, sve2_uqsub) +DO_ZPZZ(SUQADD, aa64_sve2, sve2_suqadd) +DO_ZPZZ(USQADD, aa64_sve2, sve2_usqadd) /* * SVE2 Widening Integer Arithmetic */ -static bool do_sve2_zzw_ool(DisasContext *s, arg_rrr_esz *a, - gen_helper_gvec_3 *fn, int data) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vsz, vsz, data, fn); - } - return true; -} - -#define DO_SVE2_ZZZ_TB(NAME, name, SEL1, SEL2) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ - NULL, gen_helper_sve2_##name##_h, \ - gen_helper_sve2_##name##_s, gen_helper_sve2_##name##_d, \ - }; \ - return do_sve2_zzw_ool(s, a, fns[a->esz], (SEL2 << 1) | SEL1); \ -} - -DO_SVE2_ZZZ_TB(SADDLB, saddl, false, false) -DO_SVE2_ZZZ_TB(SSUBLB, ssubl, false, false) -DO_SVE2_ZZZ_TB(SABDLB, sabdl, false, false) - -DO_SVE2_ZZZ_TB(UADDLB, uaddl, false, false) -DO_SVE2_ZZZ_TB(USUBLB, usubl, false, false) -DO_SVE2_ZZZ_TB(UABDLB, uabdl, false, false) - -DO_SVE2_ZZZ_TB(SADDLT, saddl, true, true) -DO_SVE2_ZZZ_TB(SSUBLT, ssubl, true, true) -DO_SVE2_ZZZ_TB(SABDLT, sabdl, true, true) - -DO_SVE2_ZZZ_TB(UADDLT, uaddl, true, true) -DO_SVE2_ZZZ_TB(USUBLT, usubl, true, true) -DO_SVE2_ZZZ_TB(UABDLT, uabdl, true, true) - -DO_SVE2_ZZZ_TB(SADDLBT, saddl, false, true) -DO_SVE2_ZZZ_TB(SSUBLBT, ssubl, false, true) -DO_SVE2_ZZZ_TB(SSUBLTB, ssubl, true, false) - -DO_SVE2_ZZZ_TB(SQDMULLB_zzz, sqdmull_zzz, false, false) -DO_SVE2_ZZZ_TB(SQDMULLT_zzz, sqdmull_zzz, true, true) - -DO_SVE2_ZZZ_TB(SMULLB_zzz, smull_zzz, false, false) -DO_SVE2_ZZZ_TB(SMULLT_zzz, smull_zzz, true, true) - -DO_SVE2_ZZZ_TB(UMULLB_zzz, umull_zzz, false, false) -DO_SVE2_ZZZ_TB(UMULLT_zzz, umull_zzz, true, true) - -static bool do_eor_tb(DisasContext *s, arg_rrr_esz *a, bool sel1) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_eoril_b, gen_helper_sve2_eoril_h, - gen_helper_sve2_eoril_s, gen_helper_sve2_eoril_d, - }; - return do_sve2_zzw_ool(s, a, fns[a->esz], (!sel1 << 1) | sel1); -} - -static bool trans_EORBT(DisasContext *s, arg_rrr_esz *a) -{ - return do_eor_tb(s, a, false); -} - -static bool trans_EORTB(DisasContext *s, arg_rrr_esz *a) -{ - return do_eor_tb(s, a, true); -} +static gen_helper_gvec_3 * const saddl_fns[4] = { + NULL, gen_helper_sve2_saddl_h, + gen_helper_sve2_saddl_s, gen_helper_sve2_saddl_d, +}; +TRANS_FEAT(SADDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + saddl_fns[a->esz], a, 0) +TRANS_FEAT(SADDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + saddl_fns[a->esz], a, 3) +TRANS_FEAT(SADDLBT, aa64_sve2, gen_gvec_ool_arg_zzz, + saddl_fns[a->esz], a, 2) + +static gen_helper_gvec_3 * const ssubl_fns[4] = { + NULL, gen_helper_sve2_ssubl_h, + gen_helper_sve2_ssubl_s, gen_helper_sve2_ssubl_d, +}; +TRANS_FEAT(SSUBLB, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 0) +TRANS_FEAT(SSUBLT, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 3) +TRANS_FEAT(SSUBLBT, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 2) +TRANS_FEAT(SSUBLTB, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 1) + +static gen_helper_gvec_3 * const sabdl_fns[4] = { + NULL, gen_helper_sve2_sabdl_h, + gen_helper_sve2_sabdl_s, gen_helper_sve2_sabdl_d, +}; +TRANS_FEAT(SABDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + sabdl_fns[a->esz], a, 0) +TRANS_FEAT(SABDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + sabdl_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const uaddl_fns[4] = { + NULL, gen_helper_sve2_uaddl_h, + gen_helper_sve2_uaddl_s, gen_helper_sve2_uaddl_d, +}; +TRANS_FEAT(UADDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + uaddl_fns[a->esz], a, 0) +TRANS_FEAT(UADDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + uaddl_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const usubl_fns[4] = { + NULL, gen_helper_sve2_usubl_h, + gen_helper_sve2_usubl_s, gen_helper_sve2_usubl_d, +}; +TRANS_FEAT(USUBLB, aa64_sve2, gen_gvec_ool_arg_zzz, + usubl_fns[a->esz], a, 0) +TRANS_FEAT(USUBLT, aa64_sve2, gen_gvec_ool_arg_zzz, + usubl_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const uabdl_fns[4] = { + NULL, gen_helper_sve2_uabdl_h, + gen_helper_sve2_uabdl_s, gen_helper_sve2_uabdl_d, +}; +TRANS_FEAT(UABDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + uabdl_fns[a->esz], a, 0) +TRANS_FEAT(UABDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + uabdl_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const sqdmull_fns[4] = { + NULL, gen_helper_sve2_sqdmull_zzz_h, + gen_helper_sve2_sqdmull_zzz_s, gen_helper_sve2_sqdmull_zzz_d, +}; +TRANS_FEAT(SQDMULLB_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqdmull_fns[a->esz], a, 0) +TRANS_FEAT(SQDMULLT_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqdmull_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const smull_fns[4] = { + NULL, gen_helper_sve2_smull_zzz_h, + gen_helper_sve2_smull_zzz_s, gen_helper_sve2_smull_zzz_d, +}; +TRANS_FEAT(SMULLB_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + smull_fns[a->esz], a, 0) +TRANS_FEAT(SMULLT_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + smull_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const umull_fns[4] = { + NULL, gen_helper_sve2_umull_zzz_h, + gen_helper_sve2_umull_zzz_s, gen_helper_sve2_umull_zzz_d, +}; +TRANS_FEAT(UMULLB_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + umull_fns[a->esz], a, 0) +TRANS_FEAT(UMULLT_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + umull_fns[a->esz], a, 3) + +static gen_helper_gvec_3 * const eoril_fns[4] = { + gen_helper_sve2_eoril_b, gen_helper_sve2_eoril_h, + gen_helper_sve2_eoril_s, gen_helper_sve2_eoril_d, +}; +TRANS_FEAT(EORBT, aa64_sve2, gen_gvec_ool_arg_zzz, eoril_fns[a->esz], a, 2) +TRANS_FEAT(EORTB, aa64_sve2, gen_gvec_ool_arg_zzz, eoril_fns[a->esz], a, 1) static bool do_trans_pmull(DisasContext *s, arg_rrr_esz *a, bool sel) { @@ -7030,41 +6279,48 @@ static bool do_trans_pmull(DisasContext *s, arg_rrr_esz *a, bool sel) gen_helper_gvec_pmull_q, gen_helper_sve2_pmull_h, NULL, gen_helper_sve2_pmull_d, }; - if (a->esz == 0 && !dc_isar_feature(aa64_sve2_pmull128, s)) { + + if (a->esz == 0) { + if (!dc_isar_feature(aa64_sve2_pmull128, s)) { + return false; + } + s->is_nonstreaming = true; + } else if (!dc_isar_feature(aa64_sve, s)) { return false; } - return do_sve2_zzw_ool(s, a, fns[a->esz], sel); + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, sel); } -static bool trans_PMULLB(DisasContext *s, arg_rrr_esz *a) -{ - return do_trans_pmull(s, a, false); -} +TRANS_FEAT(PMULLB, aa64_sve2, do_trans_pmull, a, false) +TRANS_FEAT(PMULLT, aa64_sve2, do_trans_pmull, a, true) -static bool trans_PMULLT(DisasContext *s, arg_rrr_esz *a) -{ - return do_trans_pmull(s, a, true); -} +static gen_helper_gvec_3 * const saddw_fns[4] = { + NULL, gen_helper_sve2_saddw_h, + gen_helper_sve2_saddw_s, gen_helper_sve2_saddw_d, +}; +TRANS_FEAT(SADDWB, aa64_sve2, gen_gvec_ool_arg_zzz, saddw_fns[a->esz], a, 0) +TRANS_FEAT(SADDWT, aa64_sve2, gen_gvec_ool_arg_zzz, saddw_fns[a->esz], a, 1) -#define DO_SVE2_ZZZ_WTB(NAME, name, SEL2) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ - NULL, gen_helper_sve2_##name##_h, \ - gen_helper_sve2_##name##_s, gen_helper_sve2_##name##_d, \ - }; \ - return do_sve2_zzw_ool(s, a, fns[a->esz], SEL2); \ -} +static gen_helper_gvec_3 * const ssubw_fns[4] = { + NULL, gen_helper_sve2_ssubw_h, + gen_helper_sve2_ssubw_s, gen_helper_sve2_ssubw_d, +}; +TRANS_FEAT(SSUBWB, aa64_sve2, gen_gvec_ool_arg_zzz, ssubw_fns[a->esz], a, 0) +TRANS_FEAT(SSUBWT, aa64_sve2, gen_gvec_ool_arg_zzz, ssubw_fns[a->esz], a, 1) -DO_SVE2_ZZZ_WTB(SADDWB, saddw, false) -DO_SVE2_ZZZ_WTB(SADDWT, saddw, true) -DO_SVE2_ZZZ_WTB(SSUBWB, ssubw, false) -DO_SVE2_ZZZ_WTB(SSUBWT, ssubw, true) +static gen_helper_gvec_3 * const uaddw_fns[4] = { + NULL, gen_helper_sve2_uaddw_h, + gen_helper_sve2_uaddw_s, gen_helper_sve2_uaddw_d, +}; +TRANS_FEAT(UADDWB, aa64_sve2, gen_gvec_ool_arg_zzz, uaddw_fns[a->esz], a, 0) +TRANS_FEAT(UADDWT, aa64_sve2, gen_gvec_ool_arg_zzz, uaddw_fns[a->esz], a, 1) -DO_SVE2_ZZZ_WTB(UADDWB, uaddw, false) -DO_SVE2_ZZZ_WTB(UADDWT, uaddw, true) -DO_SVE2_ZZZ_WTB(USUBWB, usubw, false) -DO_SVE2_ZZZ_WTB(USUBWT, usubw, true) +static gen_helper_gvec_3 * const usubw_fns[4] = { + NULL, gen_helper_sve2_usubw_h, + gen_helper_sve2_usubw_s, gen_helper_sve2_usubw_d, +}; +TRANS_FEAT(USUBWB, aa64_sve2, gen_gvec_ool_arg_zzz, usubw_fns[a->esz], a, 0) +TRANS_FEAT(USUBWT, aa64_sve2, gen_gvec_ool_arg_zzz, usubw_fns[a->esz], a, 1) static void gen_sshll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm) { @@ -7153,46 +6409,11 @@ static void gen_ushll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm) } } -static bool do_sve2_shll_tb(DisasContext *s, arg_rri_esz *a, - bool sel, bool uns) +static bool do_shll_tb(DisasContext *s, arg_rri_esz *a, + const GVecGen2i ops[3], bool sel) { - static const TCGOpcode sshll_list[] = { - INDEX_op_shli_vec, INDEX_op_sari_vec, 0 - }; - static const TCGOpcode ushll_list[] = { - INDEX_op_shli_vec, INDEX_op_shri_vec, 0 - }; - static const GVecGen2i ops[2][3] = { - { { .fniv = gen_sshll_vec, - .opt_opc = sshll_list, - .fno = gen_helper_sve2_sshll_h, - .vece = MO_16 }, - { .fniv = gen_sshll_vec, - .opt_opc = sshll_list, - .fno = gen_helper_sve2_sshll_s, - .vece = MO_32 }, - { .fniv = gen_sshll_vec, - .opt_opc = sshll_list, - .fno = gen_helper_sve2_sshll_d, - .vece = MO_64 } }, - { { .fni8 = gen_ushll16_i64, - .fniv = gen_ushll_vec, - .opt_opc = ushll_list, - .fno = gen_helper_sve2_ushll_h, - .vece = MO_16 }, - { .fni8 = gen_ushll32_i64, - .fniv = gen_ushll_vec, - .opt_opc = ushll_list, - .fno = gen_helper_sve2_ushll_s, - .vece = MO_32 }, - { .fni8 = gen_ushll64_i64, - .fniv = gen_ushll_vec, - .opt_opc = ushll_list, - .fno = gen_helper_sve2_ushll_d, - .vece = MO_64 } }, - }; - if (a->esz < 0 || a->esz > 2 || !dc_isar_feature(aa64_sve2, s)) { + if (a->esz < 0 || a->esz > 2) { return false; } if (sve_access_check(s)) { @@ -7200,284 +6421,184 @@ static bool do_sve2_shll_tb(DisasContext *s, arg_rri_esz *a, tcg_gen_gvec_2i(vec_full_reg_offset(s, a->rd), vec_full_reg_offset(s, a->rn), vsz, vsz, (a->imm << 1) | sel, - &ops[uns][a->esz]); + &ops[a->esz]); } return true; } -static bool trans_SSHLLB(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, false, false); -} +static const TCGOpcode sshll_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, 0 +}; +static const GVecGen2i sshll_ops[3] = { + { .fniv = gen_sshll_vec, + .opt_opc = sshll_list, + .fno = gen_helper_sve2_sshll_h, + .vece = MO_16 }, + { .fniv = gen_sshll_vec, + .opt_opc = sshll_list, + .fno = gen_helper_sve2_sshll_s, + .vece = MO_32 }, + { .fniv = gen_sshll_vec, + .opt_opc = sshll_list, + .fno = gen_helper_sve2_sshll_d, + .vece = MO_64 } +}; +TRANS_FEAT(SSHLLB, aa64_sve2, do_shll_tb, a, sshll_ops, false) +TRANS_FEAT(SSHLLT, aa64_sve2, do_shll_tb, a, sshll_ops, true) -static bool trans_SSHLLT(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, true, false); -} +static const TCGOpcode ushll_list[] = { + INDEX_op_shli_vec, INDEX_op_shri_vec, 0 +}; +static const GVecGen2i ushll_ops[3] = { + { .fni8 = gen_ushll16_i64, + .fniv = gen_ushll_vec, + .opt_opc = ushll_list, + .fno = gen_helper_sve2_ushll_h, + .vece = MO_16 }, + { .fni8 = gen_ushll32_i64, + .fniv = gen_ushll_vec, + .opt_opc = ushll_list, + .fno = gen_helper_sve2_ushll_s, + .vece = MO_32 }, + { .fni8 = gen_ushll64_i64, + .fniv = gen_ushll_vec, + .opt_opc = ushll_list, + .fno = gen_helper_sve2_ushll_d, + .vece = MO_64 }, +}; +TRANS_FEAT(USHLLB, aa64_sve2, do_shll_tb, a, ushll_ops, false) +TRANS_FEAT(USHLLT, aa64_sve2, do_shll_tb, a, ushll_ops, true) -static bool trans_USHLLB(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, false, true); -} +static gen_helper_gvec_3 * const bext_fns[4] = { + gen_helper_sve2_bext_b, gen_helper_sve2_bext_h, + gen_helper_sve2_bext_s, gen_helper_sve2_bext_d, +}; +TRANS_FEAT_NONSTREAMING(BEXT, aa64_sve2_bitperm, gen_gvec_ool_arg_zzz, + bext_fns[a->esz], a, 0) -static bool trans_USHLLT(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, true, true); -} +static gen_helper_gvec_3 * const bdep_fns[4] = { + gen_helper_sve2_bdep_b, gen_helper_sve2_bdep_h, + gen_helper_sve2_bdep_s, gen_helper_sve2_bdep_d, +}; +TRANS_FEAT_NONSTREAMING(BDEP, aa64_sve2_bitperm, gen_gvec_ool_arg_zzz, + bdep_fns[a->esz], a, 0) -static bool trans_BEXT(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_bext_b, gen_helper_sve2_bext_h, - gen_helper_sve2_bext_s, gen_helper_sve2_bext_d, - }; - if (!dc_isar_feature(aa64_sve2_bitperm, s)) { - return false; - } - return do_sve2_zzw_ool(s, a, fns[a->esz], 0); -} +static gen_helper_gvec_3 * const bgrp_fns[4] = { + gen_helper_sve2_bgrp_b, gen_helper_sve2_bgrp_h, + gen_helper_sve2_bgrp_s, gen_helper_sve2_bgrp_d, +}; +TRANS_FEAT_NONSTREAMING(BGRP, aa64_sve2_bitperm, gen_gvec_ool_arg_zzz, + bgrp_fns[a->esz], a, 0) -static bool trans_BDEP(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_bdep_b, gen_helper_sve2_bdep_h, - gen_helper_sve2_bdep_s, gen_helper_sve2_bdep_d, - }; - if (!dc_isar_feature(aa64_sve2_bitperm, s)) { - return false; - } - return do_sve2_zzw_ool(s, a, fns[a->esz], 0); -} +static gen_helper_gvec_3 * const cadd_fns[4] = { + gen_helper_sve2_cadd_b, gen_helper_sve2_cadd_h, + gen_helper_sve2_cadd_s, gen_helper_sve2_cadd_d, +}; +TRANS_FEAT(CADD_rot90, aa64_sve2, gen_gvec_ool_arg_zzz, + cadd_fns[a->esz], a, 0) +TRANS_FEAT(CADD_rot270, aa64_sve2, gen_gvec_ool_arg_zzz, + cadd_fns[a->esz], a, 1) + +static gen_helper_gvec_3 * const sqcadd_fns[4] = { + gen_helper_sve2_sqcadd_b, gen_helper_sve2_sqcadd_h, + gen_helper_sve2_sqcadd_s, gen_helper_sve2_sqcadd_d, +}; +TRANS_FEAT(SQCADD_rot90, aa64_sve2, gen_gvec_ool_arg_zzz, + sqcadd_fns[a->esz], a, 0) +TRANS_FEAT(SQCADD_rot270, aa64_sve2, gen_gvec_ool_arg_zzz, + sqcadd_fns[a->esz], a, 1) + +static gen_helper_gvec_4 * const sabal_fns[4] = { + NULL, gen_helper_sve2_sabal_h, + gen_helper_sve2_sabal_s, gen_helper_sve2_sabal_d, +}; +TRANS_FEAT(SABALB, aa64_sve2, gen_gvec_ool_arg_zzzz, sabal_fns[a->esz], a, 0) +TRANS_FEAT(SABALT, aa64_sve2, gen_gvec_ool_arg_zzzz, sabal_fns[a->esz], a, 1) -static bool trans_BGRP(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_bgrp_b, gen_helper_sve2_bgrp_h, - gen_helper_sve2_bgrp_s, gen_helper_sve2_bgrp_d, - }; - if (!dc_isar_feature(aa64_sve2_bitperm, s)) { - return false; - } - return do_sve2_zzw_ool(s, a, fns[a->esz], 0); -} +static gen_helper_gvec_4 * const uabal_fns[4] = { + NULL, gen_helper_sve2_uabal_h, + gen_helper_sve2_uabal_s, gen_helper_sve2_uabal_d, +}; +TRANS_FEAT(UABALB, aa64_sve2, gen_gvec_ool_arg_zzzz, uabal_fns[a->esz], a, 0) +TRANS_FEAT(UABALT, aa64_sve2, gen_gvec_ool_arg_zzzz, uabal_fns[a->esz], a, 1) -static bool do_cadd(DisasContext *s, arg_rrr_esz *a, bool sq, bool rot) +static bool do_adcl(DisasContext *s, arg_rrrr_esz *a, bool sel) { - static gen_helper_gvec_3 * const fns[2][4] = { - { gen_helper_sve2_cadd_b, gen_helper_sve2_cadd_h, - gen_helper_sve2_cadd_s, gen_helper_sve2_cadd_d }, - { gen_helper_sve2_sqcadd_b, gen_helper_sve2_sqcadd_h, - gen_helper_sve2_sqcadd_s, gen_helper_sve2_sqcadd_d }, + static gen_helper_gvec_4 * const fns[2] = { + gen_helper_sve2_adcl_s, + gen_helper_sve2_adcl_d, }; - return do_sve2_zzw_ool(s, a, fns[sq][a->esz], rot); -} - -static bool trans_CADD_rot90(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, false, false); + /* + * Note that in this case the ESZ field encodes both size and sign. + * Split out 'subtract' into bit 1 of the data field for the helper. + */ + return gen_gvec_ool_arg_zzzz(s, fns[a->esz & 1], a, (a->esz & 2) | sel); } -static bool trans_CADD_rot270(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, false, true); -} +TRANS_FEAT(ADCLB, aa64_sve2, do_adcl, a, false) +TRANS_FEAT(ADCLT, aa64_sve2, do_adcl, a, true) -static bool trans_SQCADD_rot90(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, true, false); -} +TRANS_FEAT(SSRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_ssra, a) +TRANS_FEAT(USRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_usra, a) +TRANS_FEAT(SRSRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_srsra, a) +TRANS_FEAT(URSRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_ursra, a) +TRANS_FEAT(SRI, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_sri, a) +TRANS_FEAT(SLI, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_sli, a) -static bool trans_SQCADD_rot270(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, true, true); -} +TRANS_FEAT(SABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_saba, a) +TRANS_FEAT(UABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_uaba, a) -static bool do_sve2_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, - gen_helper_gvec_4 *fn, int data) +static bool do_narrow_extract(DisasContext *s, arg_rri_esz *a, + const GVecGen2 ops[3]) { - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { + if (a->esz < 0 || a->esz > MO_32 || a->imm != 0) { return false; } if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_2(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vsz, vsz, &ops[a->esz]); } return true; } -static bool do_abal(DisasContext *s, arg_rrrr_esz *a, bool uns, bool sel) -{ - static gen_helper_gvec_4 * const fns[2][4] = { - { NULL, gen_helper_sve2_sabal_h, - gen_helper_sve2_sabal_s, gen_helper_sve2_sabal_d }, - { NULL, gen_helper_sve2_uabal_h, - gen_helper_sve2_uabal_s, gen_helper_sve2_uabal_d }, - }; - return do_sve2_zzzz_ool(s, a, fns[uns][a->esz], sel); -} +static const TCGOpcode sqxtn_list[] = { + INDEX_op_shli_vec, INDEX_op_smin_vec, INDEX_op_smax_vec, 0 +}; -static bool trans_SABALB(DisasContext *s, arg_rrrr_esz *a) +static void gen_sqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { - return do_abal(s, a, false, false); + TCGv_vec t = tcg_temp_new_vec_matching(d); + int halfbits = 4 << vece; + int64_t mask = (1ull << halfbits) - 1; + int64_t min = -1ull << (halfbits - 1); + int64_t max = -min - 1; + + tcg_gen_dupi_vec(vece, t, min); + tcg_gen_smax_vec(vece, d, n, t); + tcg_gen_dupi_vec(vece, t, max); + tcg_gen_smin_vec(vece, d, d, t); + tcg_gen_dupi_vec(vece, t, mask); + tcg_gen_and_vec(vece, d, d, t); + tcg_temp_free_vec(t); } -static bool trans_SABALT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, false, true); -} - -static bool trans_UABALB(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, true, false); -} - -static bool trans_UABALT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, true, true); -} - -static bool do_adcl(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[2] = { - gen_helper_sve2_adcl_s, - gen_helper_sve2_adcl_d, - }; - /* - * Note that in this case the ESZ field encodes both size and sign. - * Split out 'subtract' into bit 1 of the data field for the helper. - */ - return do_sve2_zzzz_ool(s, a, fns[a->esz & 1], (a->esz & 2) | sel); -} - -static bool trans_ADCLB(DisasContext *s, arg_rrrr_esz *a) -{ - return do_adcl(s, a, false); -} - -static bool trans_ADCLT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_adcl(s, a, true); -} - -static bool do_sve2_fn2i(DisasContext *s, arg_rri_esz *a, GVecGen2iFn *fn) -{ - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - unsigned rd_ofs = vec_full_reg_offset(s, a->rd); - unsigned rn_ofs = vec_full_reg_offset(s, a->rn); - fn(a->esz, rd_ofs, rn_ofs, a->imm, vsz, vsz); - } - return true; -} - -static bool trans_SSRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_ssra); -} - -static bool trans_USRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_usra); -} - -static bool trans_SRSRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_srsra); -} - -static bool trans_URSRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_ursra); -} - -static bool trans_SRI(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_sri); -} - -static bool trans_SLI(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_sli); -} - -static bool do_sve2_fn_zzz(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, fn, a->esz, a->rd, a->rn, a->rm); - } - return true; -} - -static bool trans_SABA(DisasContext *s, arg_rrr_esz *a) -{ - return do_sve2_fn_zzz(s, a, gen_gvec_saba); -} - -static bool trans_UABA(DisasContext *s, arg_rrr_esz *a) -{ - return do_sve2_fn_zzz(s, a, gen_gvec_uaba); -} - -static bool do_sve2_narrow_extract(DisasContext *s, arg_rri_esz *a, - const GVecGen2 ops[3]) -{ - if (a->esz < 0 || a->esz > MO_32 || a->imm != 0 || - !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_2(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vsz, vsz, &ops[a->esz]); - } - return true; -} - -static const TCGOpcode sqxtn_list[] = { - INDEX_op_shli_vec, INDEX_op_smin_vec, INDEX_op_smax_vec, 0 +static const GVecGen2 sqxtnb_ops[3] = { + { .fniv = gen_sqxtnb_vec, + .opt_opc = sqxtn_list, + .fno = gen_helper_sve2_sqxtnb_h, + .vece = MO_16 }, + { .fniv = gen_sqxtnb_vec, + .opt_opc = sqxtn_list, + .fno = gen_helper_sve2_sqxtnb_s, + .vece = MO_32 }, + { .fniv = gen_sqxtnb_vec, + .opt_opc = sqxtn_list, + .fno = gen_helper_sve2_sqxtnb_d, + .vece = MO_64 }, }; - -static void gen_sqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) -{ - TCGv_vec t = tcg_temp_new_vec_matching(d); - int halfbits = 4 << vece; - int64_t mask = (1ull << halfbits) - 1; - int64_t min = -1ull << (halfbits - 1); - int64_t max = -min - 1; - - tcg_gen_dupi_vec(vece, t, min); - tcg_gen_smax_vec(vece, d, n, t); - tcg_gen_dupi_vec(vece, t, max); - tcg_gen_smin_vec(vece, d, d, t); - tcg_gen_dupi_vec(vece, t, mask); - tcg_gen_and_vec(vece, d, d, t); - tcg_temp_free_vec(t); -} - -static bool trans_SQXTNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtnb_vec, - .opt_opc = sqxtn_list, - .fno = gen_helper_sve2_sqxtnb_h, - .vece = MO_16 }, - { .fniv = gen_sqxtnb_vec, - .opt_opc = sqxtn_list, - .fno = gen_helper_sve2_sqxtnb_s, - .vece = MO_32 }, - { .fniv = gen_sqxtnb_vec, - .opt_opc = sqxtn_list, - .fno = gen_helper_sve2_sqxtnb_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +TRANS_FEAT(SQXTNB, aa64_sve2, do_narrow_extract, a, sqxtnb_ops) static void gen_sqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { @@ -7497,27 +6618,24 @@ static void gen_sqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtnt_vec, - .opt_opc = sqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtnt_h, - .vece = MO_16 }, - { .fniv = gen_sqxtnt_vec, - .opt_opc = sqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtnt_s, - .vece = MO_32 }, - { .fniv = gen_sqxtnt_vec, - .opt_opc = sqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtnt_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtnt_ops[3] = { + { .fniv = gen_sqxtnt_vec, + .opt_opc = sqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtnt_h, + .vece = MO_16 }, + { .fniv = gen_sqxtnt_vec, + .opt_opc = sqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtnt_s, + .vece = MO_32 }, + { .fniv = gen_sqxtnt_vec, + .opt_opc = sqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTNT, aa64_sve2, do_narrow_extract, a, sqxtnt_ops) static const TCGOpcode uqxtn_list[] = { INDEX_op_shli_vec, INDEX_op_umin_vec, 0 @@ -7534,24 +6652,21 @@ static void gen_uqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_UQXTNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_uqxtnb_vec, - .opt_opc = uqxtn_list, - .fno = gen_helper_sve2_uqxtnb_h, - .vece = MO_16 }, - { .fniv = gen_uqxtnb_vec, - .opt_opc = uqxtn_list, - .fno = gen_helper_sve2_uqxtnb_s, - .vece = MO_32 }, - { .fniv = gen_uqxtnb_vec, - .opt_opc = uqxtn_list, - .fno = gen_helper_sve2_uqxtnb_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 uqxtnb_ops[3] = { + { .fniv = gen_uqxtnb_vec, + .opt_opc = uqxtn_list, + .fno = gen_helper_sve2_uqxtnb_h, + .vece = MO_16 }, + { .fniv = gen_uqxtnb_vec, + .opt_opc = uqxtn_list, + .fno = gen_helper_sve2_uqxtnb_s, + .vece = MO_32 }, + { .fniv = gen_uqxtnb_vec, + .opt_opc = uqxtn_list, + .fno = gen_helper_sve2_uqxtnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQXTNB, aa64_sve2, do_narrow_extract, a, uqxtnb_ops) static void gen_uqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { @@ -7566,27 +6681,24 @@ static void gen_uqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_UQXTNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_uqxtnt_vec, - .opt_opc = uqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_uqxtnt_h, - .vece = MO_16 }, - { .fniv = gen_uqxtnt_vec, - .opt_opc = uqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_uqxtnt_s, - .vece = MO_32 }, - { .fniv = gen_uqxtnt_vec, - .opt_opc = uqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_uqxtnt_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 uqxtnt_ops[3] = { + { .fniv = gen_uqxtnt_vec, + .opt_opc = uqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_uqxtnt_h, + .vece = MO_16 }, + { .fniv = gen_uqxtnt_vec, + .opt_opc = uqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_uqxtnt_s, + .vece = MO_32 }, + { .fniv = gen_uqxtnt_vec, + .opt_opc = uqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_uqxtnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQXTNT, aa64_sve2, do_narrow_extract, a, uqxtnt_ops) static const TCGOpcode sqxtun_list[] = { INDEX_op_shli_vec, INDEX_op_umin_vec, INDEX_op_smax_vec, 0 @@ -7605,24 +6717,21 @@ static void gen_sqxtunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTUNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtunb_vec, - .opt_opc = sqxtun_list, - .fno = gen_helper_sve2_sqxtunb_h, - .vece = MO_16 }, - { .fniv = gen_sqxtunb_vec, - .opt_opc = sqxtun_list, - .fno = gen_helper_sve2_sqxtunb_s, - .vece = MO_32 }, - { .fniv = gen_sqxtunb_vec, - .opt_opc = sqxtun_list, - .fno = gen_helper_sve2_sqxtunb_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtunb_ops[3] = { + { .fniv = gen_sqxtunb_vec, + .opt_opc = sqxtun_list, + .fno = gen_helper_sve2_sqxtunb_h, + .vece = MO_16 }, + { .fniv = gen_sqxtunb_vec, + .opt_opc = sqxtun_list, + .fno = gen_helper_sve2_sqxtunb_s, + .vece = MO_32 }, + { .fniv = gen_sqxtunb_vec, + .opt_opc = sqxtun_list, + .fno = gen_helper_sve2_sqxtunb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTUNB, aa64_sve2, do_narrow_extract, a, sqxtunb_ops) static void gen_sqxtunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { @@ -7639,32 +6748,29 @@ static void gen_sqxtunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTUNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtunt_vec, - .opt_opc = sqxtun_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtunt_h, - .vece = MO_16 }, - { .fniv = gen_sqxtunt_vec, - .opt_opc = sqxtun_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtunt_s, - .vece = MO_32 }, - { .fniv = gen_sqxtunt_vec, - .opt_opc = sqxtun_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtunt_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtunt_ops[3] = { + { .fniv = gen_sqxtunt_vec, + .opt_opc = sqxtun_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtunt_h, + .vece = MO_16 }, + { .fniv = gen_sqxtunt_vec, + .opt_opc = sqxtun_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtunt_s, + .vece = MO_32 }, + { .fniv = gen_sqxtunt_vec, + .opt_opc = sqxtun_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtunt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTUNT, aa64_sve2, do_narrow_extract, a, sqxtunt_ops) -static bool do_sve2_shr_narrow(DisasContext *s, arg_rri_esz *a, - const GVecGen2i ops[3]) +static bool do_shr_narrow(DisasContext *s, arg_rri_esz *a, + const GVecGen2i ops[3]) { - if (a->esz < 0 || a->esz > MO_32 || !dc_isar_feature(aa64_sve2, s)) { + if (a->esz < 0 || a->esz > MO_32) { return false; } assert(a->imm > 0 && a->imm <= (8 << a->esz)); @@ -7713,28 +6819,25 @@ static void gen_shrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) tcg_temp_free_vec(t); } -static bool trans_SHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { INDEX_op_shri_vec, 0 }; - static const GVecGen2i ops[3] = { - { .fni8 = gen_shrnb16_i64, - .fniv = gen_shrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_shrnb_h, - .vece = MO_16 }, - { .fni8 = gen_shrnb32_i64, - .fniv = gen_shrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_shrnb_s, - .vece = MO_32 }, - { .fni8 = gen_shrnb64_i64, - .fniv = gen_shrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_shrnb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode shrnb_vec_list[] = { INDEX_op_shri_vec, 0 }; +static const GVecGen2i shrnb_ops[3] = { + { .fni8 = gen_shrnb16_i64, + .fniv = gen_shrnb_vec, + .opt_opc = shrnb_vec_list, + .fno = gen_helper_sve2_shrnb_h, + .vece = MO_16 }, + { .fni8 = gen_shrnb32_i64, + .fniv = gen_shrnb_vec, + .opt_opc = shrnb_vec_list, + .fno = gen_helper_sve2_shrnb_s, + .vece = MO_32 }, + { .fni8 = gen_shrnb64_i64, + .fniv = gen_shrnb_vec, + .opt_opc = shrnb_vec_list, + .fno = gen_helper_sve2_shrnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SHRNB, aa64_sve2, do_shr_narrow, a, shrnb_ops) static void gen_shrnt_i64(unsigned vece, TCGv_i64 d, TCGv_i64 n, int shr) { @@ -7775,51 +6878,42 @@ static void gen_shrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) tcg_temp_free_vec(t); } -static bool trans_SHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { INDEX_op_shli_vec, 0 }; - static const GVecGen2i ops[3] = { - { .fni8 = gen_shrnt16_i64, - .fniv = gen_shrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_shrnt_h, - .vece = MO_16 }, - { .fni8 = gen_shrnt32_i64, - .fniv = gen_shrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_shrnt_s, - .vece = MO_32 }, - { .fni8 = gen_shrnt64_i64, - .fniv = gen_shrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_shrnt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode shrnt_vec_list[] = { INDEX_op_shli_vec, 0 }; +static const GVecGen2i shrnt_ops[3] = { + { .fni8 = gen_shrnt16_i64, + .fniv = gen_shrnt_vec, + .opt_opc = shrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_shrnt_h, + .vece = MO_16 }, + { .fni8 = gen_shrnt32_i64, + .fniv = gen_shrnt_vec, + .opt_opc = shrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_shrnt_s, + .vece = MO_32 }, + { .fni8 = gen_shrnt64_i64, + .fniv = gen_shrnt_vec, + .opt_opc = shrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_shrnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SHRNT, aa64_sve2, do_shr_narrow, a, shrnt_ops) -static bool trans_RSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_rshrnb_h }, - { .fno = gen_helper_sve2_rshrnb_s }, - { .fno = gen_helper_sve2_rshrnb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i rshrnb_ops[3] = { + { .fno = gen_helper_sve2_rshrnb_h }, + { .fno = gen_helper_sve2_rshrnb_s }, + { .fno = gen_helper_sve2_rshrnb_d }, +}; +TRANS_FEAT(RSHRNB, aa64_sve2, do_shr_narrow, a, rshrnb_ops) -static bool trans_RSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_rshrnt_h }, - { .fno = gen_helper_sve2_rshrnt_s }, - { .fno = gen_helper_sve2_rshrnt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i rshrnt_ops[3] = { + { .fno = gen_helper_sve2_rshrnt_h }, + { .fno = gen_helper_sve2_rshrnt_s }, + { .fno = gen_helper_sve2_rshrnt_d }, +}; +TRANS_FEAT(RSHRNT, aa64_sve2, do_shr_narrow, a, rshrnt_ops) static void gen_sqshrunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -7835,27 +6929,24 @@ static void gen_sqshrunb_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRUNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrunb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrunb_h, - .vece = MO_16 }, - { .fniv = gen_sqshrunb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrunb_s, - .vece = MO_32 }, - { .fniv = gen_sqshrunb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrunb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrunb_vec_list[] = { + INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i sqshrunb_ops[3] = { + { .fniv = gen_sqshrunb_vec, + .opt_opc = sqshrunb_vec_list, + .fno = gen_helper_sve2_sqshrunb_h, + .vece = MO_16 }, + { .fniv = gen_sqshrunb_vec, + .opt_opc = sqshrunb_vec_list, + .fno = gen_helper_sve2_sqshrunb_s, + .vece = MO_32 }, + { .fniv = gen_sqshrunb_vec, + .opt_opc = sqshrunb_vec_list, + .fno = gen_helper_sve2_sqshrunb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRUNB, aa64_sve2, do_shr_narrow, a, sqshrunb_ops) static void gen_sqshrunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -7873,51 +6964,42 @@ static void gen_sqshrunt_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRUNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shli_vec, INDEX_op_sari_vec, - INDEX_op_smax_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrunt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrunt_h, - .vece = MO_16 }, - { .fniv = gen_sqshrunt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrunt_s, - .vece = MO_32 }, - { .fniv = gen_sqshrunt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrunt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrunt_vec_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, + INDEX_op_smax_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i sqshrunt_ops[3] = { + { .fniv = gen_sqshrunt_vec, + .opt_opc = sqshrunt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrunt_h, + .vece = MO_16 }, + { .fniv = gen_sqshrunt_vec, + .opt_opc = sqshrunt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrunt_s, + .vece = MO_32 }, + { .fniv = gen_sqshrunt_vec, + .opt_opc = sqshrunt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrunt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRUNT, aa64_sve2, do_shr_narrow, a, sqshrunt_ops) -static bool trans_SQRSHRUNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrunb_h }, - { .fno = gen_helper_sve2_sqrshrunb_s }, - { .fno = gen_helper_sve2_sqrshrunb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrunb_ops[3] = { + { .fno = gen_helper_sve2_sqrshrunb_h }, + { .fno = gen_helper_sve2_sqrshrunb_s }, + { .fno = gen_helper_sve2_sqrshrunb_d }, +}; +TRANS_FEAT(SQRSHRUNB, aa64_sve2, do_shr_narrow, a, sqrshrunb_ops) -static bool trans_SQRSHRUNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrunt_h }, - { .fno = gen_helper_sve2_sqrshrunt_s }, - { .fno = gen_helper_sve2_sqrshrunt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrunt_ops[3] = { + { .fno = gen_helper_sve2_sqrshrunt_h }, + { .fno = gen_helper_sve2_sqrshrunt_s }, + { .fno = gen_helper_sve2_sqrshrunt_d }, +}; +TRANS_FEAT(SQRSHRUNT, aa64_sve2, do_shr_narrow, a, sqrshrunt_ops) static void gen_sqshrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -7937,27 +7019,24 @@ static void gen_sqshrnb_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_smin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrnb_h, - .vece = MO_16 }, - { .fniv = gen_sqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrnb_s, - .vece = MO_32 }, - { .fniv = gen_sqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrnb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrnb_vec_list[] = { + INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_smin_vec, 0 +}; +static const GVecGen2i sqshrnb_ops[3] = { + { .fniv = gen_sqshrnb_vec, + .opt_opc = sqshrnb_vec_list, + .fno = gen_helper_sve2_sqshrnb_h, + .vece = MO_16 }, + { .fniv = gen_sqshrnb_vec, + .opt_opc = sqshrnb_vec_list, + .fno = gen_helper_sve2_sqshrnb_s, + .vece = MO_32 }, + { .fniv = gen_sqshrnb_vec, + .opt_opc = sqshrnb_vec_list, + .fno = gen_helper_sve2_sqshrnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRNB, aa64_sve2, do_shr_narrow, a, sqshrnb_ops) static void gen_sqshrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -7978,51 +7057,42 @@ static void gen_sqshrnt_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shli_vec, INDEX_op_sari_vec, - INDEX_op_smax_vec, INDEX_op_smin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrnt_h, - .vece = MO_16 }, - { .fniv = gen_sqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrnt_s, - .vece = MO_32 }, - { .fniv = gen_sqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrnt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrnt_vec_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, + INDEX_op_smax_vec, INDEX_op_smin_vec, 0 +}; +static const GVecGen2i sqshrnt_ops[3] = { + { .fniv = gen_sqshrnt_vec, + .opt_opc = sqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrnt_h, + .vece = MO_16 }, + { .fniv = gen_sqshrnt_vec, + .opt_opc = sqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrnt_s, + .vece = MO_32 }, + { .fniv = gen_sqshrnt_vec, + .opt_opc = sqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRNT, aa64_sve2, do_shr_narrow, a, sqshrnt_ops) -static bool trans_SQRSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrnb_h }, - { .fno = gen_helper_sve2_sqrshrnb_s }, - { .fno = gen_helper_sve2_sqrshrnb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrnb_ops[3] = { + { .fno = gen_helper_sve2_sqrshrnb_h }, + { .fno = gen_helper_sve2_sqrshrnb_s }, + { .fno = gen_helper_sve2_sqrshrnb_d }, +}; +TRANS_FEAT(SQRSHRNB, aa64_sve2, do_shr_narrow, a, sqrshrnb_ops) -static bool trans_SQRSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrnt_h }, - { .fno = gen_helper_sve2_sqrshrnt_s }, - { .fno = gen_helper_sve2_sqrshrnt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrnt_ops[3] = { + { .fno = gen_helper_sve2_sqrshrnt_h }, + { .fno = gen_helper_sve2_sqrshrnt_s }, + { .fno = gen_helper_sve2_sqrshrnt_d }, +}; +TRANS_FEAT(SQRSHRNT, aa64_sve2, do_shr_narrow, a, sqrshrnt_ops) static void gen_uqshrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -8036,27 +7106,24 @@ static void gen_uqshrnb_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_UQSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shri_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_uqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_uqshrnb_h, - .vece = MO_16 }, - { .fniv = gen_uqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_uqshrnb_s, - .vece = MO_32 }, - { .fniv = gen_uqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_uqshrnb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode uqshrnb_vec_list[] = { + INDEX_op_shri_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i uqshrnb_ops[3] = { + { .fniv = gen_uqshrnb_vec, + .opt_opc = uqshrnb_vec_list, + .fno = gen_helper_sve2_uqshrnb_h, + .vece = MO_16 }, + { .fniv = gen_uqshrnb_vec, + .opt_opc = uqshrnb_vec_list, + .fno = gen_helper_sve2_uqshrnb_s, + .vece = MO_32 }, + { .fniv = gen_uqshrnb_vec, + .opt_opc = uqshrnb_vec_list, + .fno = gen_helper_sve2_uqshrnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQSHRNB, aa64_sve2, do_shr_narrow, a, uqshrnb_ops) static void gen_uqshrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -8072,60 +7139,49 @@ static void gen_uqshrnt_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_UQSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_uqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_uqshrnt_h, - .vece = MO_16 }, - { .fniv = gen_uqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_uqshrnt_s, - .vece = MO_32 }, - { .fniv = gen_uqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_uqshrnt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode uqshrnt_vec_list[] = { + INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i uqshrnt_ops[3] = { + { .fniv = gen_uqshrnt_vec, + .opt_opc = uqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_uqshrnt_h, + .vece = MO_16 }, + { .fniv = gen_uqshrnt_vec, + .opt_opc = uqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_uqshrnt_s, + .vece = MO_32 }, + { .fniv = gen_uqshrnt_vec, + .opt_opc = uqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_uqshrnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQSHRNT, aa64_sve2, do_shr_narrow, a, uqshrnt_ops) -static bool trans_UQRSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_uqrshrnb_h }, - { .fno = gen_helper_sve2_uqrshrnb_s }, - { .fno = gen_helper_sve2_uqrshrnb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i uqrshrnb_ops[3] = { + { .fno = gen_helper_sve2_uqrshrnb_h }, + { .fno = gen_helper_sve2_uqrshrnb_s }, + { .fno = gen_helper_sve2_uqrshrnb_d }, +}; +TRANS_FEAT(UQRSHRNB, aa64_sve2, do_shr_narrow, a, uqrshrnb_ops) -static bool trans_UQRSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_uqrshrnt_h }, - { .fno = gen_helper_sve2_uqrshrnt_s }, - { .fno = gen_helper_sve2_uqrshrnt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i uqrshrnt_ops[3] = { + { .fno = gen_helper_sve2_uqrshrnt_h }, + { .fno = gen_helper_sve2_uqrshrnt_s }, + { .fno = gen_helper_sve2_uqrshrnt_d }, +}; +TRANS_FEAT(UQRSHRNT, aa64_sve2, do_shr_narrow, a, uqrshrnt_ops) #define DO_SVE2_ZZZ_NARROW(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ + static gen_helper_gvec_3 * const name##_fns[4] = { \ NULL, gen_helper_sve2_##name##_h, \ gen_helper_sve2_##name##_s, gen_helper_sve2_##name##_d, \ }; \ - return do_sve2_zzz_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_arg_zzz, \ + name##_fns[a->esz], a, 0) DO_SVE2_ZZZ_NARROW(ADDHNB, addhnb) DO_SVE2_ZZZ_NARROW(ADDHNT, addhnt) @@ -8137,655 +7193,391 @@ DO_SVE2_ZZZ_NARROW(SUBHNT, subhnt) DO_SVE2_ZZZ_NARROW(RSUBHNB, rsubhnb) DO_SVE2_ZZZ_NARROW(RSUBHNT, rsubhnt) -static bool do_sve2_ppzz_flags(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_flags_4 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_ppzz_flags(s, a, fn); -} - -#define DO_SVE2_PPZZ_MATCH(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_flags_4 * const fns[4] = { \ - gen_helper_sve2_##name##_ppzz_b, gen_helper_sve2_##name##_ppzz_h, \ - NULL, NULL \ - }; \ - return do_sve2_ppzz_flags(s, a, fns[a->esz]); \ -} +static gen_helper_gvec_flags_4 * const match_fns[4] = { + gen_helper_sve2_match_ppzz_b, gen_helper_sve2_match_ppzz_h, NULL, NULL +}; +TRANS_FEAT_NONSTREAMING(MATCH, aa64_sve2, do_ppzz_flags, a, match_fns[a->esz]) -DO_SVE2_PPZZ_MATCH(MATCH, match) -DO_SVE2_PPZZ_MATCH(NMATCH, nmatch) +static gen_helper_gvec_flags_4 * const nmatch_fns[4] = { + gen_helper_sve2_nmatch_ppzz_b, gen_helper_sve2_nmatch_ppzz_h, NULL, NULL +}; +TRANS_FEAT_NONSTREAMING(NMATCH, aa64_sve2, do_ppzz_flags, a, nmatch_fns[a->esz]) -static bool trans_HISTCNT(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[2] = { - gen_helper_sve2_histcnt_s, gen_helper_sve2_histcnt_d - }; - if (a->esz < 2) { - return false; - } - return do_sve2_zpzz_ool(s, a, fns[a->esz - 2]); -} +static gen_helper_gvec_4 * const histcnt_fns[4] = { + NULL, NULL, gen_helper_sve2_histcnt_s, gen_helper_sve2_histcnt_d +}; +TRANS_FEAT_NONSTREAMING(HISTCNT, aa64_sve2, gen_gvec_ool_arg_zpzz, + histcnt_fns[a->esz], a, 0) -static bool trans_HISTSEG(DisasContext *s, arg_rrr_esz *a) -{ - if (a->esz != 0) { - return false; - } - return do_sve2_zzz_ool(s, a, gen_helper_sve2_histseg); -} +TRANS_FEAT_NONSTREAMING(HISTSEG, aa64_sve2, gen_gvec_ool_arg_zzz, + a->esz == 0 ? gen_helper_sve2_histseg : NULL, a, 0) -static bool do_sve2_zpzz_fp(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_4_ptr *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpzz_fp(s, a, fn); -} - -#define DO_SVE2_ZPZZ_FP(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4_ptr * const fns[4] = { \ - NULL, gen_helper_sve2_##name##_zpzz_h, \ - gen_helper_sve2_##name##_zpzz_s, gen_helper_sve2_##name##_zpzz_d \ - }; \ - return do_sve2_zpzz_fp(s, a, fns[a->esz]); \ -} - -DO_SVE2_ZPZZ_FP(FADDP, faddp) -DO_SVE2_ZPZZ_FP(FMAXNMP, fmaxnmp) -DO_SVE2_ZPZZ_FP(FMINNMP, fminnmp) -DO_SVE2_ZPZZ_FP(FMAXP, fmaxp) -DO_SVE2_ZPZZ_FP(FMINP, fminp) +DO_ZPZZ_FP(FADDP, aa64_sve2, sve2_faddp_zpzz) +DO_ZPZZ_FP(FMAXNMP, aa64_sve2, sve2_fmaxnmp_zpzz) +DO_ZPZZ_FP(FMINNMP, aa64_sve2, sve2_fminnmp_zpzz) +DO_ZPZZ_FP(FMAXP, aa64_sve2, sve2_fmaxp_zpzz) +DO_ZPZZ_FP(FMINP, aa64_sve2, sve2_fminp_zpzz) /* * SVE Integer Multiply-Add (unpredicated) */ -static bool trans_FMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - gen_helper_gvec_4_ptr *fn; +TRANS_FEAT_NONSTREAMING(FMMLA_s, aa64_sve_f32mm, gen_gvec_fpst_zzzz, + gen_helper_fmmla_s, a->rd, a->rn, a->rm, a->ra, + 0, FPST_FPCR) +TRANS_FEAT_NONSTREAMING(FMMLA_d, aa64_sve_f64mm, gen_gvec_fpst_zzzz, + gen_helper_fmmla_d, a->rd, a->rn, a->rm, a->ra, + 0, FPST_FPCR) - switch (a->esz) { - case MO_32: - if (!dc_isar_feature(aa64_sve_f32mm, s)) { - return false; - } - fn = gen_helper_fmmla_s; - break; - case MO_64: - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - fn = gen_helper_fmmla_d; - break; - default: - return false; - } +static gen_helper_gvec_4 * const sqdmlal_zzzw_fns[] = { + NULL, gen_helper_sve2_sqdmlal_zzzw_h, + gen_helper_sve2_sqdmlal_zzzw_s, gen_helper_sve2_sqdmlal_zzzw_d, +}; +TRANS_FEAT(SQDMLALB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlal_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SQDMLALT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlal_zzzw_fns[a->esz], a, 3) +TRANS_FEAT(SQDMLALBT, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlal_zzzw_fns[a->esz], a, 2) + +static gen_helper_gvec_4 * const sqdmlsl_zzzw_fns[] = { + NULL, gen_helper_sve2_sqdmlsl_zzzw_h, + gen_helper_sve2_sqdmlsl_zzzw_s, gen_helper_sve2_sqdmlsl_zzzw_d, +}; +TRANS_FEAT(SQDMLSLB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlsl_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SQDMLSLT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlsl_zzzw_fns[a->esz], a, 3) +TRANS_FEAT(SQDMLSLBT, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlsl_zzzw_fns[a->esz], a, 2) + +static gen_helper_gvec_4 * const sqrdmlah_fns[] = { + gen_helper_sve2_sqrdmlah_b, gen_helper_sve2_sqrdmlah_h, + gen_helper_sve2_sqrdmlah_s, gen_helper_sve2_sqrdmlah_d, +}; +TRANS_FEAT(SQRDMLAH_zzzz, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqrdmlah_fns[a->esz], a, 0) - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_4 * const sqrdmlsh_fns[] = { + gen_helper_sve2_sqrdmlsh_b, gen_helper_sve2_sqrdmlsh_h, + gen_helper_sve2_sqrdmlsh_s, gen_helper_sve2_sqrdmlsh_d, +}; +TRANS_FEAT(SQRDMLSH_zzzz, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqrdmlsh_fns[a->esz], a, 0) -static bool do_sqdmlal_zzzw(DisasContext *s, arg_rrrr_esz *a, - bool sel1, bool sel2) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_sqdmlal_zzzw_h, - gen_helper_sve2_sqdmlal_zzzw_s, gen_helper_sve2_sqdmlal_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], (sel2 << 1) | sel1); -} +static gen_helper_gvec_4 * const smlal_zzzw_fns[] = { + NULL, gen_helper_sve2_smlal_zzzw_h, + gen_helper_sve2_smlal_zzzw_s, gen_helper_sve2_smlal_zzzw_d, +}; +TRANS_FEAT(SMLALB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlal_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SMLALT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlal_zzzw_fns[a->esz], a, 1) + +static gen_helper_gvec_4 * const umlal_zzzw_fns[] = { + NULL, gen_helper_sve2_umlal_zzzw_h, + gen_helper_sve2_umlal_zzzw_s, gen_helper_sve2_umlal_zzzw_d, +}; +TRANS_FEAT(UMLALB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlal_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(UMLALT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlal_zzzw_fns[a->esz], a, 1) + +static gen_helper_gvec_4 * const smlsl_zzzw_fns[] = { + NULL, gen_helper_sve2_smlsl_zzzw_h, + gen_helper_sve2_smlsl_zzzw_s, gen_helper_sve2_smlsl_zzzw_d, +}; +TRANS_FEAT(SMLSLB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlsl_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SMLSLT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlsl_zzzw_fns[a->esz], a, 1) + +static gen_helper_gvec_4 * const umlsl_zzzw_fns[] = { + NULL, gen_helper_sve2_umlsl_zzzw_h, + gen_helper_sve2_umlsl_zzzw_s, gen_helper_sve2_umlsl_zzzw_d, +}; +TRANS_FEAT(UMLSLB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlsl_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(UMLSLT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlsl_zzzw_fns[a->esz], a, 1) + +static gen_helper_gvec_4 * const cmla_fns[] = { + gen_helper_sve2_cmla_zzzz_b, gen_helper_sve2_cmla_zzzz_h, + gen_helper_sve2_cmla_zzzz_s, gen_helper_sve2_cmla_zzzz_d, +}; +TRANS_FEAT(CMLA_zzzz, aa64_sve2, gen_gvec_ool_zzzz, + cmla_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) -static bool do_sqdmlsl_zzzw(DisasContext *s, arg_rrrr_esz *a, - bool sel1, bool sel2) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_sqdmlsl_zzzw_h, - gen_helper_sve2_sqdmlsl_zzzw_s, gen_helper_sve2_sqdmlsl_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], (sel2 << 1) | sel1); -} +static gen_helper_gvec_4 * const cdot_fns[] = { + NULL, NULL, gen_helper_sve2_cdot_zzzz_s, gen_helper_sve2_cdot_zzzz_d +}; +TRANS_FEAT(CDOT_zzzz, aa64_sve2, gen_gvec_ool_zzzz, + cdot_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) -static bool trans_SQDMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlal_zzzw(s, a, false, false); -} +static gen_helper_gvec_4 * const sqrdcmlah_fns[] = { + gen_helper_sve2_sqrdcmlah_zzzz_b, gen_helper_sve2_sqrdcmlah_zzzz_h, + gen_helper_sve2_sqrdcmlah_zzzz_s, gen_helper_sve2_sqrdcmlah_zzzz_d, +}; +TRANS_FEAT(SQRDCMLAH_zzzz, aa64_sve2, gen_gvec_ool_zzzz, + sqrdcmlah_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) -static bool trans_SQDMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlal_zzzw(s, a, true, true); -} +TRANS_FEAT(USDOT_zzzz, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + a->esz == 2 ? gen_helper_gvec_usdot_b : NULL, a, 0) -static bool trans_SQDMLALBT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlal_zzzw(s, a, false, true); -} +TRANS_FEAT_NONSTREAMING(AESMC, aa64_sve2_aes, gen_gvec_ool_zz, + gen_helper_crypto_aesmc, a->rd, a->rd, a->decrypt) -static bool trans_SQDMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlsl_zzzw(s, a, false, false); -} +TRANS_FEAT_NONSTREAMING(AESE, aa64_sve2_aes, gen_gvec_ool_arg_zzz, + gen_helper_crypto_aese, a, false) +TRANS_FEAT_NONSTREAMING(AESD, aa64_sve2_aes, gen_gvec_ool_arg_zzz, + gen_helper_crypto_aese, a, true) -static bool trans_SQDMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlsl_zzzw(s, a, true, true); -} +TRANS_FEAT_NONSTREAMING(SM4E, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, + gen_helper_crypto_sm4e, a, 0) +TRANS_FEAT_NONSTREAMING(SM4EKEY, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, + gen_helper_crypto_sm4ekey, a, 0) -static bool trans_SQDMLSLBT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlsl_zzzw(s, a, false, true); -} +TRANS_FEAT_NONSTREAMING(RAX1, aa64_sve2_sha3, gen_gvec_fn_arg_zzz, + gen_gvec_rax1, a) -static bool trans_SQRDMLAH_zzzz(DisasContext *s, arg_rrrr_esz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_sqrdmlah_b, gen_helper_sve2_sqrdmlah_h, - gen_helper_sve2_sqrdmlah_s, gen_helper_sve2_sqrdmlah_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], 0); -} +TRANS_FEAT(FCVTNT_sh, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtnt_sh, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTNT_ds, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtnt_ds, a, 0, FPST_FPCR) -static bool trans_SQRDMLSH_zzzz(DisasContext *s, arg_rrrr_esz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_sqrdmlsh_b, gen_helper_sve2_sqrdmlsh_h, - gen_helper_sve2_sqrdmlsh_s, gen_helper_sve2_sqrdmlsh_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], 0); -} +TRANS_FEAT(BFCVTNT, aa64_sve_bf16, gen_gvec_fpst_arg_zpz, + gen_helper_sve_bfcvtnt, a, 0, FPST_FPCR) -static bool do_smlal_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_smlal_zzzw_h, - gen_helper_sve2_smlal_zzzw_s, gen_helper_sve2_smlal_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} +TRANS_FEAT(FCVTLT_hs, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtlt_hs, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTLT_sd, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtlt_sd, a, 0, FPST_FPCR) -static bool trans_SMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlal_zzzw(s, a, false); -} +TRANS_FEAT(FCVTX_ds, aa64_sve2, do_frint_mode, a, + float_round_to_odd, gen_helper_sve_fcvt_ds) +TRANS_FEAT(FCVTXNT_ds, aa64_sve2, do_frint_mode, a, + float_round_to_odd, gen_helper_sve2_fcvtnt_ds) -static bool trans_SMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlal_zzzw(s, a, true); -} +static gen_helper_gvec_3_ptr * const flogb_fns[] = { + NULL, gen_helper_flogb_h, + gen_helper_flogb_s, gen_helper_flogb_d +}; +TRANS_FEAT(FLOGB, aa64_sve2, gen_gvec_fpst_arg_zpz, flogb_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool do_umlal_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) +static bool do_FMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sub, bool sel) { - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_umlal_zzzw_h, - gen_helper_sve2_umlal_zzzw_s, gen_helper_sve2_umlal_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); + return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzzw_s, + a->rd, a->rn, a->rm, a->ra, + (sel << 1) | sub, cpu_env); } -static bool trans_UMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_umlal_zzzw(s, a, false); -} +TRANS_FEAT(FMLALB_zzzw, aa64_sve2, do_FMLAL_zzzw, a, false, false) +TRANS_FEAT(FMLALT_zzzw, aa64_sve2, do_FMLAL_zzzw, a, false, true) +TRANS_FEAT(FMLSLB_zzzw, aa64_sve2, do_FMLAL_zzzw, a, true, false) +TRANS_FEAT(FMLSLT_zzzw, aa64_sve2, do_FMLAL_zzzw, a, true, true) -static bool trans_UMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) +static bool do_FMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sub, bool sel) { - return do_umlal_zzzw(s, a, true); + return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzxw_s, + a->rd, a->rn, a->rm, a->ra, + (a->index << 2) | (sel << 1) | sub, cpu_env); } -static bool do_smlsl_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_smlsl_zzzw_h, - gen_helper_sve2_smlsl_zzzw_s, gen_helper_sve2_smlsl_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} +TRANS_FEAT(FMLALB_zzxw, aa64_sve2, do_FMLAL_zzxw, a, false, false) +TRANS_FEAT(FMLALT_zzxw, aa64_sve2, do_FMLAL_zzxw, a, false, true) +TRANS_FEAT(FMLSLB_zzxw, aa64_sve2, do_FMLAL_zzxw, a, true, false) +TRANS_FEAT(FMLSLT_zzxw, aa64_sve2, do_FMLAL_zzxw, a, true, true) -static bool trans_SMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlsl_zzzw(s, a, false); -} +TRANS_FEAT_NONSTREAMING(SMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_smmla_b, a, 0) +TRANS_FEAT_NONSTREAMING(USMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_usmmla_b, a, 0) +TRANS_FEAT_NONSTREAMING(UMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_ummla_b, a, 0) -static bool trans_SMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlsl_zzzw(s, a, true); -} +TRANS_FEAT(BFDOT_zzzz, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_bfdot, a, 0) +TRANS_FEAT(BFDOT_zzxz, aa64_sve_bf16, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_bfdot_idx, a) -static bool do_umlsl_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_umlsl_zzzw_h, - gen_helper_sve2_umlsl_zzzw_s, gen_helper_sve2_umlsl_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} +TRANS_FEAT_NONSTREAMING(BFMMLA, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_bfmmla, a, 0) -static bool trans_UMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) +static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) { - return do_umlsl_zzzw(s, a, false); + return gen_gvec_fpst_zzzz(s, gen_helper_gvec_bfmlal, + a->rd, a->rn, a->rm, a->ra, sel, FPST_FPCR); } -static bool trans_UMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_umlsl_zzzw(s, a, true); -} +TRANS_FEAT(BFMLALB_zzzw, aa64_sve_bf16, do_BFMLAL_zzzw, a, false) +TRANS_FEAT(BFMLALT_zzzw, aa64_sve_bf16, do_BFMLAL_zzzw, a, true) -static bool trans_CMLA_zzzz(DisasContext *s, arg_CMLA_zzzz *a) +static bool do_BFMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sel) { - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_cmla_zzzz_b, gen_helper_sve2_cmla_zzzz_h, - gen_helper_sve2_cmla_zzzz_s, gen_helper_sve2_cmla_zzzz_d, - }; - - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot); - } - return true; + return gen_gvec_fpst_zzzz(s, gen_helper_gvec_bfmlal_idx, + a->rd, a->rn, a->rm, a->ra, + (a->index << 1) | sel, FPST_FPCR); } -static bool trans_CDOT_zzzz(DisasContext *s, arg_CMLA_zzzz *a) -{ - if (!dc_isar_feature(aa64_sve2, s) || a->esz < MO_32) { - return false; - } - if (sve_access_check(s)) { - gen_helper_gvec_4 *fn = (a->esz == MO_32 - ? gen_helper_sve2_cdot_zzzz_s - : gen_helper_sve2_cdot_zzzz_d); - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->rot); - } - return true; -} +TRANS_FEAT(BFMLALB_zzxw, aa64_sve_bf16, do_BFMLAL_zzxw, a, false) +TRANS_FEAT(BFMLALT_zzxw, aa64_sve_bf16, do_BFMLAL_zzxw, a, true) -static bool trans_SQRDCMLAH_zzzz(DisasContext *s, arg_SQRDCMLAH_zzzz *a) +static bool trans_PSEL(DisasContext *s, arg_psel *a) { - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_sqrdcmlah_zzzz_b, gen_helper_sve2_sqrdcmlah_zzzz_h, - gen_helper_sve2_sqrdcmlah_zzzz_s, gen_helper_sve2_sqrdcmlah_zzzz_d, - }; + int vl = vec_full_reg_size(s); + int pl = pred_gvec_reg_size(s); + int elements = vl >> a->esz; + TCGv_i64 tmp, didx, dbit; + TCGv_ptr ptr; - if (!dc_isar_feature(aa64_sve2, s)) { + if (!dc_isar_feature(aa64_sme, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot); + if (!sve_access_check(s)) { + return true; } - return true; -} -static bool trans_USDOT_zzzz(DisasContext *s, arg_USDOT_zzzz *a) -{ - if (a->esz != 2 || !dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - vsz, vsz, 0, gen_helper_gvec_usdot_b); - } - return true; -} + tmp = tcg_temp_new_i64(); + dbit = tcg_temp_new_i64(); + didx = tcg_temp_new_i64(); + ptr = tcg_temp_new_ptr(); -static bool trans_AESMC(DisasContext *s, arg_AESMC *a) -{ - if (!dc_isar_feature(aa64_sve2_aes, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zz(s, gen_helper_crypto_aesmc, a->rd, a->rd, a->decrypt); + /* Compute the predicate element. */ + tcg_gen_addi_i64(tmp, cpu_reg(s, a->rv), a->imm); + if (is_power_of_2(elements)) { + tcg_gen_andi_i64(tmp, tmp, elements - 1); + } else { + tcg_gen_remu_i64(tmp, tmp, tcg_constant_i64(elements)); } - return true; -} -static bool do_aese(DisasContext *s, arg_rrr_esz *a, bool decrypt) -{ - if (!dc_isar_feature(aa64_sve2_aes, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, gen_helper_crypto_aese, - a->rd, a->rn, a->rm, decrypt); + /* Extract the predicate byte and bit indices. */ + tcg_gen_shli_i64(tmp, tmp, a->esz); + tcg_gen_andi_i64(dbit, tmp, 7); + tcg_gen_shri_i64(didx, tmp, 3); + if (HOST_BIG_ENDIAN) { + tcg_gen_xori_i64(didx, didx, 7); } - return true; -} -static bool trans_AESE(DisasContext *s, arg_rrr_esz *a) -{ - return do_aese(s, a, false); -} - -static bool trans_AESD(DisasContext *s, arg_rrr_esz *a) -{ - return do_aese(s, a, true); -} + /* Load the predicate word. */ + tcg_gen_trunc_i64_ptr(ptr, didx); + tcg_gen_add_ptr(ptr, ptr, cpu_env); + tcg_gen_ld8u_i64(tmp, ptr, pred_full_reg_offset(s, a->pm)); -static bool do_sm4(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) -{ - if (!dc_isar_feature(aa64_sve2_sm4, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); - } - return true; -} + /* Extract the predicate bit and replicate to MO_64. */ + tcg_gen_shr_i64(tmp, tmp, dbit); + tcg_gen_andi_i64(tmp, tmp, 1); + tcg_gen_neg_i64(tmp, tmp); -static bool trans_SM4E(DisasContext *s, arg_rrr_esz *a) -{ - return do_sm4(s, a, gen_helper_crypto_sm4e); -} + /* Apply to either copy the source, or write zeros. */ + tcg_gen_gvec_ands(MO_64, pred_full_reg_offset(s, a->pd), + pred_full_reg_offset(s, a->pn), tmp, pl, pl); -static bool trans_SM4EKEY(DisasContext *s, arg_rrr_esz *a) -{ - return do_sm4(s, a, gen_helper_crypto_sm4ekey); -} - -static bool trans_RAX1(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2_sha3, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, gen_gvec_rax1, MO_64, a->rd, a->rn, a->rm); - } + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(dbit); + tcg_temp_free_i64(didx); + tcg_temp_free_ptr(ptr); return true; } -static bool trans_FCVTNT_sh(DisasContext *s, arg_rpr_esz *a) +static void gen_sclamp_i32(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m, TCGv_i32 a) { - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtnt_sh); + tcg_gen_smax_i32(d, a, n); + tcg_gen_smin_i32(d, d, m); } -static bool trans_BFCVTNT(DisasContext *s, arg_rpr_esz *a) +static void gen_sclamp_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 a) { - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_bfcvtnt); -} - -static bool trans_FCVTNT_ds(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtnt_ds); + tcg_gen_smax_i64(d, a, n); + tcg_gen_smin_i64(d, d, m); } -static bool trans_FCVTLT_hs(DisasContext *s, arg_rpr_esz *a) +static void gen_sclamp_vec(unsigned vece, TCGv_vec d, TCGv_vec n, + TCGv_vec m, TCGv_vec a) { - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtlt_hs); + tcg_gen_smax_vec(vece, d, a, n); + tcg_gen_smin_vec(vece, d, d, m); } -static bool trans_FCVTLT_sd(DisasContext *s, arg_rpr_esz *a) +static void gen_sclamp(unsigned vece, uint32_t d, uint32_t n, uint32_t m, + uint32_t a, uint32_t oprsz, uint32_t maxsz) { - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtlt_sd); -} - -static bool trans_FCVTX_ds(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_frint_mode(s, a, float_round_to_odd, gen_helper_sve_fcvt_ds); -} - -static bool trans_FCVTXNT_ds(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_frint_mode(s, a, float_round_to_odd, gen_helper_sve2_fcvtnt_ds); -} - -static bool trans_FLOGB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[] = { - NULL, gen_helper_flogb_h, - gen_helper_flogb_s, gen_helper_flogb_d + static const TCGOpcode vecop[] = { + INDEX_op_smin_vec, INDEX_op_smax_vec, 0 }; - - if (!dc_isar_feature(aa64_sve2, s) || fns[a->esz] == NULL) { - return false; - } - if (sve_access_check(s)) { - TCGv_ptr status = - fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - unsigned vsz = vec_full_reg_size(s); - - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fns[a->esz]); - tcg_temp_free_ptr(status); - } - return true; -} - -static bool do_FMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sub, bool sel) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - cpu_env, vsz, vsz, (sel << 1) | sub, - gen_helper_sve2_fmlal_zzzw_s); - } - return true; -} - -static bool trans_FMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, false, false); -} - -static bool trans_FMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, false, true); -} - -static bool trans_FMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, true, false); -} - -static bool trans_FMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, true, true); -} - -static bool do_FMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sub, bool sel) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - cpu_env, vsz, vsz, - (a->index << 2) | (sel << 1) | sub, - gen_helper_sve2_fmlal_zzxw_s); - } - return true; -} - -static bool trans_FMLALB_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, false, false); -} - -static bool trans_FMLALT_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, false, true); -} - -static bool trans_FMLSLB_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, true, false); -} - -static bool trans_FMLSLT_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, true, true); -} - -static bool do_i8mm_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, - gen_helper_gvec_4 *fn, int data) -{ - if (!dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); - } - return true; -} - -static bool trans_SMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - return do_i8mm_zzzz_ool(s, a, gen_helper_gvec_smmla_b, 0); -} - -static bool trans_USMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - return do_i8mm_zzzz_ool(s, a, gen_helper_gvec_usmmla_b, 0); -} - -static bool trans_UMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - return do_i8mm_zzzz_ool(s, a, gen_helper_gvec_ummla_b, 0); -} - -static bool trans_BFDOT_zzzz(DisasContext *s, arg_rrrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot, - a->rd, a->rn, a->rm, a->ra, 0); - } - return true; -} - -static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot_idx, - a->rd, a->rn, a->rm, a->ra, a->index); - } - return true; -} - -static bool trans_BFMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, gen_helper_gvec_bfmmla, - a->rd, a->rn, a->rm, a->ra, 0); - } - return true; + static const GVecGen4 ops[4] = { + { .fniv = gen_sclamp_vec, + .fno = gen_helper_gvec_sclamp_b, + .opt_opc = vecop, + .vece = MO_8 }, + { .fniv = gen_sclamp_vec, + .fno = gen_helper_gvec_sclamp_h, + .opt_opc = vecop, + .vece = MO_16 }, + { .fni4 = gen_sclamp_i32, + .fniv = gen_sclamp_vec, + .fno = gen_helper_gvec_sclamp_s, + .opt_opc = vecop, + .vece = MO_32 }, + { .fni8 = gen_sclamp_i64, + .fniv = gen_sclamp_vec, + .fno = gen_helper_gvec_sclamp_d, + .opt_opc = vecop, + .vece = MO_64, + .prefer_i64 = TCG_TARGET_REG_BITS == 64 } + }; + tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &ops[vece]); } -static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - if (sve_access_check(s)) { - TCGv_ptr status = fpstatus_ptr(FPST_FPCR); - unsigned vsz = vec_full_reg_size(s); +TRANS_FEAT(SCLAMP, aa64_sme, gen_gvec_fn_arg_zzzz, gen_sclamp, a) - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, sel, - gen_helper_gvec_bfmlal); - tcg_temp_free_ptr(status); - } - return true; -} - -static bool trans_BFMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) +static void gen_uclamp_i32(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m, TCGv_i32 a) { - return do_BFMLAL_zzzw(s, a, false); + tcg_gen_umax_i32(d, a, n); + tcg_gen_umin_i32(d, d, m); } -static bool trans_BFMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) +static void gen_uclamp_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 a) { - return do_BFMLAL_zzzw(s, a, true); + tcg_gen_umax_i64(d, a, n); + tcg_gen_umin_i64(d, d, m); } -static bool do_BFMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sel) +static void gen_uclamp_vec(unsigned vece, TCGv_vec d, TCGv_vec n, + TCGv_vec m, TCGv_vec a) { - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - if (sve_access_check(s)) { - TCGv_ptr status = fpstatus_ptr(FPST_FPCR); - unsigned vsz = vec_full_reg_size(s); - - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, (a->index << 1) | sel, - gen_helper_gvec_bfmlal_idx); - tcg_temp_free_ptr(status); - } - return true; + tcg_gen_umax_vec(vece, d, a, n); + tcg_gen_umin_vec(vece, d, d, m); } -static bool trans_BFMLALB_zzxw(DisasContext *s, arg_rrxr_esz *a) +static void gen_uclamp(unsigned vece, uint32_t d, uint32_t n, uint32_t m, + uint32_t a, uint32_t oprsz, uint32_t maxsz) { - return do_BFMLAL_zzxw(s, a, false); + static const TCGOpcode vecop[] = { + INDEX_op_umin_vec, INDEX_op_umax_vec, 0 + }; + static const GVecGen4 ops[4] = { + { .fniv = gen_uclamp_vec, + .fno = gen_helper_gvec_uclamp_b, + .opt_opc = vecop, + .vece = MO_8 }, + { .fniv = gen_uclamp_vec, + .fno = gen_helper_gvec_uclamp_h, + .opt_opc = vecop, + .vece = MO_16 }, + { .fni4 = gen_uclamp_i32, + .fniv = gen_uclamp_vec, + .fno = gen_helper_gvec_uclamp_s, + .opt_opc = vecop, + .vece = MO_32 }, + { .fni8 = gen_uclamp_i64, + .fniv = gen_uclamp_vec, + .fno = gen_helper_gvec_uclamp_d, + .opt_opc = vecop, + .vece = MO_64, + .prefer_i64 = TCG_TARGET_REG_BITS == 64 } + }; + tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &ops[vece]); } -static bool trans_BFMLALT_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_BFMLAL_zzxw(s, a, true); -} +TRANS_FEAT(UCLAMP, aa64_sme, gen_gvec_fn_arg_zzzz, gen_uclamp, a) diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c index 17f796e32a33..5c5d58d2c62d 100644 --- a/target/arm/translate-vfp.c +++ b/target/arm/translate-vfp.c @@ -93,7 +93,7 @@ uint64_t vfp_expand_imm(int size, uint8_t imm8) static inline long vfp_f16_offset(unsigned reg, bool top) { long offs = vfp_reg_offset(false, reg); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN if (!top) { offs += 2; } @@ -180,8 +180,7 @@ static void gen_update_fp_context(DisasContext *s) gen_helper_vfp_set_fpscr(cpu_env, fpscr); tcg_temp_free_i32(fpscr); if (dc_isar_feature(aa32_mve, s)) { - TCGv_i32 z32 = tcg_const_i32(0); - store_cpu_field(z32, v7m.vpr); + store_cpu_field(tcg_constant_i32(0), v7m.vpr); } /* * We just updated the FPSCR and VPR. Some of this state is cached @@ -220,8 +219,30 @@ static void gen_update_fp_context(DisasContext *s) static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled) { if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, false), s->fp_excp_el); + /* + * The full syndrome is only used for HSR when HCPTR traps: + * For v8, when TA==0, coproc is RES0. + * For v7, any use of a Floating-point instruction or access + * to a Floating-point Extension register that is trapped to + * Hyp mode because of a trap configured in the HCPTR sets + * this field to 0xA. + */ + int coproc = arm_dc_feature(s, ARM_FEATURE_V8) ? 0 : 0xa; + uint32_t syn = syn_fp_access_trap(1, 0xe, false, coproc); + + gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->fp_excp_el); + return false; + } + + /* + * Note that rebuild_hflags_a32 has already accounted for being in EL0 + * and the higher EL in A64 mode, etc. Unlike A64 mode, there do not + * appear to be any insns which touch VFP which are allowed. + */ + if (s->sme_trap_nonstreaming) { + gen_exception_insn(s, 0, EXCP_UDEF, + syn_smetrap(SME_ET_Streaming, + curr_insn_len(s) == 2)); return false; } @@ -251,8 +272,8 @@ bool vfp_access_check_m(DisasContext *s, bool skip_context_update) * the encoding space handled by the patterns in m-nocp.decode, * and for them we may need to raise NOCP here. */ - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); + gen_exception_insn_el(s, 0, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); return false; } @@ -317,7 +338,7 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) TCGv_i64 frn, frm, dest; TCGv_i64 tmp, zero, zf, nf, vf; - zero = tcg_const_i64(0); + zero = tcg_constant_i64(0); frn = tcg_temp_new_i64(); frm = tcg_temp_new_i64(); @@ -335,27 +356,22 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) vfp_load_reg64(frm, rm); switch (a->cc) { case 0: /* eq: Z */ - tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero, - frn, frm); + tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero, frn, frm); break; case 1: /* vs: V */ - tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero, - frn, frm); + tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero, frn, frm); break; case 2: /* ge: N == V -> N ^ V == 0 */ tmp = tcg_temp_new_i64(); tcg_gen_xor_i64(tmp, vf, nf); - tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero, - frn, frm); + tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero, frn, frm); tcg_temp_free_i64(tmp); break; case 3: /* gt: !Z && N == V */ - tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero, - frn, frm); + tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero, frn, frm); tmp = tcg_temp_new_i64(); tcg_gen_xor_i64(tmp, vf, nf); - tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero, - dest, frm); + tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero, dest, frm); tcg_temp_free_i64(tmp); break; } @@ -367,13 +383,11 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) tcg_temp_free_i64(zf); tcg_temp_free_i64(nf); tcg_temp_free_i64(vf); - - tcg_temp_free_i64(zero); } else { TCGv_i32 frn, frm, dest; TCGv_i32 tmp, zero; - zero = tcg_const_i32(0); + zero = tcg_constant_i32(0); frn = tcg_temp_new_i32(); frm = tcg_temp_new_i32(); @@ -382,27 +396,22 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) vfp_load_reg32(frm, rm); switch (a->cc) { case 0: /* eq: Z */ - tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero, - frn, frm); + tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero, frn, frm); break; case 1: /* vs: V */ - tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero, - frn, frm); + tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero, frn, frm); break; case 2: /* ge: N == V -> N ^ V == 0 */ tmp = tcg_temp_new_i32(); tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); - tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero, - frn, frm); + tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero, frn, frm); tcg_temp_free_i32(tmp); break; case 3: /* gt: !Z && N == V */ - tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero, - frn, frm); + tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero, frn, frm); tmp = tcg_temp_new_i32(); tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); - tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero, - dest, frm); + tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero, dest, frm); tcg_temp_free_i32(tmp); break; } @@ -414,8 +423,6 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) tcg_temp_free_i32(frn); tcg_temp_free_i32(frm); tcg_temp_free_i32(dest); - - tcg_temp_free_i32(zero); } return true; @@ -547,7 +554,7 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) fpst = fpstatus_ptr(FPST_FPCR); } - tcg_shift = tcg_const_i32(0); + tcg_shift = tcg_constant_i32(0); tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding)); gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); @@ -595,8 +602,6 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); tcg_temp_free_i32(tcg_rmode); - tcg_temp_free_i32(tcg_shift); - tcg_temp_free_ptr(fpst); return true; @@ -850,15 +855,11 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) case ARM_VFP_MVFR2: case ARM_VFP_FPSID: if (s->current_el == 1) { - TCGv_i32 tcg_reg, tcg_rt; - gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); - tcg_reg = tcg_const_i32(a->reg); - tcg_rt = tcg_const_i32(a->rt); - gen_helper_check_hcr_el2_trap(cpu_env, tcg_rt, tcg_reg); - tcg_temp_free_i32(tcg_reg); - tcg_temp_free_i32(tcg_rt); + gen_update_pc(s, 0); + gen_helper_check_hcr_el2_trap(cpu_env, + tcg_constant_i32(a->rt), + tcg_constant_i32(a->reg)); } /* fall through */ case ARM_VFP_FPEXC: @@ -2388,8 +2389,6 @@ MAKE_VFM_TRANS_FNS(dp) static bool trans_VMOV_imm_hp(DisasContext *s, arg_VMOV_imm_sp *a) { - TCGv_i32 fd; - if (!dc_isar_feature(aa32_fp16_arith, s)) { return false; } @@ -2402,9 +2401,7 @@ static bool trans_VMOV_imm_hp(DisasContext *s, arg_VMOV_imm_sp *a) return true; } - fd = tcg_const_i32(vfp_expand_imm(MO_16, a->imm)); - vfp_store_reg32(fd, a->vd); - tcg_temp_free_i32(fd); + vfp_store_reg32(tcg_constant_i32(vfp_expand_imm(MO_16, a->imm)), a->vd); return true; } @@ -2440,7 +2437,7 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a) } } - fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm)); + fd = tcg_constant_i32(vfp_expand_imm(MO_32, a->imm)); for (;;) { vfp_store_reg32(fd, vd); @@ -2454,7 +2451,6 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a) vd = vfp_advance_sreg(vd, delta_d); } - tcg_temp_free_i32(fd); return true; } @@ -2495,7 +2491,7 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a) } } - fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm)); + fd = tcg_constant_i64(vfp_expand_imm(MO_64, a->imm)); for (;;) { vfp_store_reg64(fd, vd); @@ -2509,7 +2505,6 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a) vd = vfp_advance_dreg(vd, delta_d); } - tcg_temp_free_i64(fd); return true; } @@ -3294,7 +3289,7 @@ static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a) vfp_load_reg32(vd, a->vd); fpst = fpstatus_ptr(FPST_FPCR_F16); - shift = tcg_const_i32(frac_bits); + shift = tcg_constant_i32(frac_bits); /* Switch on op:U:sx bits */ switch (a->opc) { @@ -3328,7 +3323,6 @@ static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a) vfp_store_reg32(vd, a->vd); tcg_temp_free_i32(vd); - tcg_temp_free_i32(shift); tcg_temp_free_ptr(fpst); return true; } @@ -3353,7 +3347,7 @@ static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a) vfp_load_reg32(vd, a->vd); fpst = fpstatus_ptr(FPST_FPCR); - shift = tcg_const_i32(frac_bits); + shift = tcg_constant_i32(frac_bits); /* Switch on op:U:sx bits */ switch (a->opc) { @@ -3387,7 +3381,6 @@ static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a) vfp_store_reg32(vd, a->vd); tcg_temp_free_i32(vd); - tcg_temp_free_i32(shift); tcg_temp_free_ptr(fpst); return true; } @@ -3418,7 +3411,7 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a) vfp_load_reg64(vd, a->vd); fpst = fpstatus_ptr(FPST_FPCR); - shift = tcg_const_i32(frac_bits); + shift = tcg_constant_i32(frac_bits); /* Switch on op:U:sx bits */ switch (a->opc) { @@ -3452,7 +3445,6 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a) vfp_store_reg64(vd, a->vd); tcg_temp_free_i64(vd); - tcg_temp_free_i32(shift); tcg_temp_free_ptr(fpst); return true; } diff --git a/target/arm/translate.c b/target/arm/translate.c index bf2196b9e24c..1dcaefb8e756 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -30,11 +30,10 @@ #include "qemu/bitops.h" #include "arm_ldst.h" #include "semihosting/semihost.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" - #include "exec/log.h" +#include "cpregs.h" #define ENABLE_ARCH_4T arm_dc_feature(s, ARM_FEATURE_V4T) @@ -163,7 +162,7 @@ uint64_t asimd_imm_const(uint32_t imm, int cmode, int op) void arm_gen_condlabel(DisasContext *s) { if (!s->condjmp) { - s->condlabel = gen_new_label(); + s->condlabel = gen_disas_label(s); s->condjmp = 1; } } @@ -180,6 +179,25 @@ typedef enum ISSInfo { ISSIs16Bit = (1 << 8), } ISSInfo; +/* + * Store var into env + offset to a member with size bytes. + * Free var after use. + */ +void store_cpu_offset(TCGv_i32 var, int offset, int size) +{ + switch (size) { + case 1: + tcg_gen_st8_i32(var, cpu_env, offset); + break; + case 4: + tcg_gen_st_i32(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } + tcg_temp_free_i32(var); +} + /* Save the syndrome information for a Data Abort */ static void disas_set_da_iss(DisasContext *s, MemOp memop, ISSInfo issinfo) { @@ -219,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); @@ -246,17 +260,27 @@ static inline int get_a32_user_mem_index(DisasContext *s) } } -/* The architectural value of PC. */ -static uint32_t read_pc(DisasContext *s) +/* The pc_curr difference for an architectural jump. */ +static target_long jmp_diff(DisasContext *s, target_long diff) { - return s->pc_curr + (s->thumb ? 4 : 8); + return diff + (s->thumb ? 4 : 8); +} + +static void gen_pc_plus_diff(DisasContext *s, TCGv_i32 var, target_long diff) +{ + assert(s->pc_save != -1); + if (TARGET_TB_PCREL) { + tcg_gen_addi_i32(var, cpu_R[15], (s->pc_curr - s->pc_save) + diff); + } else { + tcg_gen_movi_i32(var, s->pc_curr + diff); + } } /* Set a variable to the value of a CPU register. */ void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) { if (reg == 15) { - tcg_gen_movi_i32(var, read_pc(s)); + gen_pc_plus_diff(s, var, jmp_diff(s, 0)); } else { tcg_gen_mov_i32(var, cpu_R[reg]); } @@ -272,7 +296,11 @@ TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) TCGv_i32 tmp = tcg_temp_new_i32(); if (reg == 15) { - tcg_gen_movi_i32(tmp, (read_pc(s) & ~3) + ofs); + /* + * This address is computed from an aligned PC: + * subtract off the low bits. + */ + gen_pc_plus_diff(s, tmp, jmp_diff(s, ofs - (s->pc_curr & 3))); } else { tcg_gen_addi_i32(tmp, cpu_R[reg], ofs); } @@ -291,6 +319,7 @@ void store_reg(DisasContext *s, int reg, TCGv_i32 var) */ tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3); s->base.is_jmp = DISAS_JUMP; + s->pc_save = -1; } else if (reg == 13 && arm_dc_feature(s, ARM_FEATURE_M)) { /* For M-profile SP bits [1:0] are always zero */ tcg_gen_andi_i32(var, var, ~3); @@ -327,18 +356,33 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var) void gen_set_cpsr(TCGv_i32 var, uint32_t mask) { - TCGv_i32 tmp_mask = tcg_const_i32(mask); - gen_helper_cpsr_write(cpu_env, var, tmp_mask); - tcg_temp_free_i32(tmp_mask); + gen_helper_cpsr_write(cpu_env, var, tcg_constant_i32(mask)); } -static void gen_exception_internal(int excp) +static void gen_rebuild_hflags(DisasContext *s, bool new_el) { - TCGv_i32 tcg_excp = tcg_const_i32(excp); + bool m_profile = arm_dc_feature(s, ARM_FEATURE_M); + if (new_el) { + if (m_profile) { + gen_helper_rebuild_hflags_m32_newel(cpu_env); + } else { + gen_helper_rebuild_hflags_a32_newel(cpu_env); + } + } else { + TCGv_i32 tcg_el = tcg_constant_i32(s->current_el); + if (m_profile) { + gen_helper_rebuild_hflags_m32(cpu_env, tcg_el); + } else { + gen_helper_rebuild_hflags_a32(cpu_env, tcg_el); + } + } +} + +static void gen_exception_internal(int excp) +{ assert(excp_is_internal(excp)); - gen_helper_exception_internal(cpu_env, tcg_excp); - tcg_temp_free_i32(tcg_excp); + gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp)); } static void gen_singlestep_exception(DisasContext *s) @@ -513,16 +557,14 @@ static void gen_sbc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) #define GEN_SHIFT(name) \ static void gen_##name(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) \ { \ - TCGv_i32 tmp1, tmp2, tmp3; \ - tmp1 = tcg_temp_new_i32(); \ - tcg_gen_andi_i32(tmp1, t1, 0xff); \ - tmp2 = tcg_const_i32(0); \ - tmp3 = tcg_const_i32(0x1f); \ - tcg_gen_movcond_i32(TCG_COND_GTU, tmp2, tmp1, tmp3, tmp2, t0); \ - tcg_temp_free_i32(tmp3); \ - tcg_gen_andi_i32(tmp1, tmp1, 0x1f); \ - tcg_gen_##name##_i32(dest, tmp2, tmp1); \ - tcg_temp_free_i32(tmp2); \ + TCGv_i32 tmpd = tcg_temp_new_i32(); \ + TCGv_i32 tmp1 = tcg_temp_new_i32(); \ + TCGv_i32 zero = tcg_constant_i32(0); \ + tcg_gen_andi_i32(tmp1, t1, 0x1f); \ + tcg_gen_##name##_i32(tmpd, t0, tmp1); \ + tcg_gen_andi_i32(tmp1, t1, 0xe0); \ + tcg_gen_movcond_i32(TCG_COND_NE, dest, tmp1, zero, zero, tmpd); \ + tcg_temp_free_i32(tmpd); \ tcg_temp_free_i32(tmp1); \ } GEN_SHIFT(shl) @@ -531,12 +573,10 @@ GEN_SHIFT(shr) static void gen_sar(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) { - TCGv_i32 tmp1, tmp2; - tmp1 = tcg_temp_new_i32(); + TCGv_i32 tmp1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp1, t1, 0xff); - tmp2 = tcg_const_i32(0x1f); - tcg_gen_movcond_i32(TCG_COND_GTU, tmp1, tmp1, tmp2, tmp2, tmp1); - tcg_temp_free_i32(tmp2); + tcg_gen_umin_i32(tmp1, tmp1, tcg_constant_i32(31)); tcg_gen_sar_i32(dest, t0, tmp1); tcg_temp_free_i32(tmp1); } @@ -743,9 +783,10 @@ void gen_set_condexec(DisasContext *s) } } -void gen_set_pc_im(DisasContext *s, target_ulong val) +void gen_update_pc(DisasContext *s, target_long diff) { - tcg_gen_movi_i32(cpu_R[15], val); + gen_pc_plus_diff(s, cpu_R[15], diff); + s->pc_save = s->pc_curr + diff; } /* Set PC and Thumb state from var. var is marked as dead. */ @@ -755,6 +796,7 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var) tcg_gen_andi_i32(cpu_R[15], var, ~1); tcg_gen_andi_i32(var, var, 1); store_cpu_field(var, thumb); + s->pc_save = -1; } /* @@ -796,7 +838,7 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) static inline void gen_bx_excret_final_code(DisasContext *s) { /* Generate the code to finish possible exception return and end the TB */ - TCGLabel *excret_label = gen_new_label(); + DisasLabel excret_label = gen_disas_label(s); uint32_t min_magic; if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY)) { @@ -808,14 +850,14 @@ static inline void gen_bx_excret_final_code(DisasContext *s) } /* Is the new PC value in the magic range indicating exception return? */ - tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label); + tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label.label); /* No: end the TB as we would for a DISAS_JMP */ if (s->ss_active) { gen_singlestep_exception(s); } else { tcg_gen_exit_tb(NULL, 0); } - gen_set_label(excret_label); + set_disas_label(s, excret_label); /* Yes: this is an exception return. * At this point in runtime env->regs[15] and env->thumb will hold * the exception-return magic number, which do_v7m_exception_exit() @@ -837,7 +879,7 @@ static inline void gen_bxns(DisasContext *s, int rm) /* The bxns helper may raise an EXCEPTION_EXIT exception, so in theory * we need to sync state before calling it, but: - * - we don't need to do gen_set_pc_im() because the bxns helper will + * - we don't need to do gen_update_pc() because the bxns helper will * always set the PC itself * - we don't need to do gen_set_condexec() because BXNS is UNPREDICTABLE * unless it's outside an IT block or the last insn in an IT block, @@ -858,7 +900,7 @@ static inline void gen_blxns(DisasContext *s, int rm) * We do however need to set the PC, because the blxns helper reads it. * The blxns helper may throw an exception. */ - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); gen_helper_v7m_blxns(cpu_env, var); tcg_temp_free_i32(var); s->base.is_jmp = DISAS_EXIT; @@ -1026,7 +1068,7 @@ static inline void gen_hvc(DisasContext *s, int imm16) * as an undefined insn by runtime configuration (ie before * the insn really executes). */ - gen_set_pc_im(s, s->pc_curr); + gen_update_pc(s, 0); gen_helper_pre_hvc(cpu_env); /* Otherwise we will treat this as a real exception which * happens after execution of the insn. (The distinction matters @@ -1034,7 +1076,7 @@ static inline void gen_hvc(DisasContext *s, int imm16) * for single stepping.) */ s->svc_imm = imm16; - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_HVC; } @@ -1043,76 +1085,88 @@ static inline void gen_smc(DisasContext *s) /* As with HVC, we may take an exception either before or after * the insn executes. */ - TCGv_i32 tmp; - - gen_set_pc_im(s, s->pc_curr); - tmp = tcg_const_i32(syn_aa32_smc()); - gen_helper_pre_smc(cpu_env, tmp); - tcg_temp_free_i32(tmp); - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, 0); + gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa32_smc())); + gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_SMC; } -static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp) +static void gen_exception_internal_insn(DisasContext *s, int excp) { gen_set_condexec(s); - gen_set_pc_im(s, pc); + gen_update_pc(s, 0); gen_exception_internal(excp); s->base.is_jmp = DISAS_NORETURN; } -void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, - uint32_t syn, uint32_t target_el) +static void gen_exception_el_v(int excp, uint32_t syndrome, TCGv_i32 tcg_el) +{ + gen_helper_exception_with_syndrome_el(cpu_env, tcg_constant_i32(excp), + tcg_constant_i32(syndrome), tcg_el); +} + +static void gen_exception_el(int excp, uint32_t syndrome, uint32_t target_el) +{ + gen_exception_el_v(excp, syndrome, tcg_constant_i32(target_el)); +} + +static void gen_exception(int excp, uint32_t syndrome) +{ + gen_helper_exception_with_syndrome(cpu_env, tcg_constant_i32(excp), + tcg_constant_i32(syndrome)); +} + +static void gen_exception_insn_el_v(DisasContext *s, target_long pc_diff, + int excp, uint32_t syn, TCGv_i32 tcg_el) { if (s->aarch64) { - gen_a64_set_pc_im(pc); + gen_a64_update_pc(s, pc_diff); } else { gen_set_condexec(s); - gen_set_pc_im(s, pc); + gen_update_pc(s, pc_diff); } - gen_exception(excp, syn, target_el); + gen_exception_el_v(excp, syn, tcg_el); s->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn) +void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp, + uint32_t syn, uint32_t target_el) { - TCGv_i32 tcg_syn; - - gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); - tcg_syn = tcg_const_i32(syn); - gen_helper_exception_bkpt_insn(cpu_env, tcg_syn); - tcg_temp_free_i32(tcg_syn); - s->base.is_jmp = DISAS_NORETURN; + gen_exception_insn_el_v(s, pc_diff, excp, syn, + tcg_constant_i32(target_el)); } -void unallocated_encoding(DisasContext *s) +void gen_exception_insn(DisasContext *s, target_long pc_diff, + int excp, uint32_t syn) { - /* Unallocated and reserved encodings are uncategorized */ - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), - default_exception_el(s)); + if (s->aarch64) { + gen_a64_update_pc(s, pc_diff); + } else { + gen_set_condexec(s); + gen_update_pc(s, pc_diff); + } + gen_exception(excp, syn); + s->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_el(DisasContext *s, int excp, uint32_t syn, - TCGv_i32 tcg_el) +static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn) { - TCGv_i32 tcg_excp; - TCGv_i32 tcg_syn; - gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); - tcg_excp = tcg_const_i32(excp); - tcg_syn = tcg_const_i32(syn); - gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn, tcg_el); - tcg_temp_free_i32(tcg_syn); - tcg_temp_free_i32(tcg_excp); + gen_update_pc(s, 0); + gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syn)); s->base.is_jmp = DISAS_NORETURN; } +void unallocated_encoding(DisasContext *s) +{ + /* Unallocated and reserved encodings are uncategorized */ + gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized()); +} + /* Force a TB lookup after an instruction that changes the CPU state. */ void gen_lookup_tb(DisasContext *s) { - tcg_gen_movi_i32(cpu_R[15], s->base.pc_next); + gen_pc_plus_diff(s, cpu_R[15], curr_insn_len(s)); s->base.is_jmp = DISAS_EXIT; } @@ -1130,12 +1184,9 @@ 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); + gen_exception_internal_insn(s, EXCP_SEMIHOST); return; } @@ -1158,7 +1209,7 @@ long neon_element_offset(int reg, int element, MemOp memop) { int element_size = 1 << (memop & MO_SIZE); int ofs = element * element_size; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN /* * Calculate the offset assuming fully little-endian, * then XOR to account for the order of the 8-byte units. @@ -1828,24 +1879,21 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) gen_op_iwmmxt_movq_M0_wRn(wrd); switch ((insn >> 6) & 3) { case 0: - tmp2 = tcg_const_i32(0xff); - tmp3 = tcg_const_i32((insn & 7) << 3); + tmp2 = tcg_constant_i32(0xff); + tmp3 = tcg_constant_i32((insn & 7) << 3); break; case 1: - tmp2 = tcg_const_i32(0xffff); - tmp3 = tcg_const_i32((insn & 3) << 4); + tmp2 = tcg_constant_i32(0xffff); + tmp3 = tcg_constant_i32((insn & 3) << 4); break; case 2: - tmp2 = tcg_const_i32(0xffffffff); - tmp3 = tcg_const_i32((insn & 1) << 5); + tmp2 = tcg_constant_i32(0xffffffff); + tmp3 = tcg_constant_i32((insn & 1) << 5); break; default: - tmp2 = NULL; - tmp3 = NULL; + g_assert_not_reached(); } gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3); - tcg_temp_free_i32(tmp3); - tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp); gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); @@ -2301,10 +2349,9 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) rd0 = (insn >> 16) & 0xf; rd1 = (insn >> 0) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); - tmp = tcg_const_i32((insn >> 20) & 3); iwmmxt_load_reg(cpu_V1, rd1); - gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp); - tcg_temp_free_i32(tmp); + gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, + tcg_constant_i32((insn >> 20) & 3)); gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); break; @@ -2358,9 +2405,8 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) wrd = (insn >> 12) & 0xf; rd0 = (insn >> 16) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); - tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f)); + tmp = tcg_constant_i32(((insn >> 16) & 0xf0) | (insn & 0x0f)); gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp); - tcg_temp_free_i32(tmp); gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); gen_op_iwmmxt_set_cup(); @@ -2563,25 +2609,38 @@ static void gen_goto_ptr(void) * cpu_loop_exec. Any live exit_requests will be processed as we * enter the next TB. */ -static void gen_goto_tb(DisasContext *s, int n, target_ulong dest) +static void gen_goto_tb(DisasContext *s, int n, target_long diff) { - if (translator_use_goto_tb(&s->base, dest)) { - tcg_gen_goto_tb(n); - gen_set_pc_im(s, dest); + if (translator_use_goto_tb(&s->base, s->pc_curr + diff)) { + /* + * For pcrel, the pc must always be up-to-date on entry to + * the linked TB, so that it can use simple additions for all + * further adjustments. For !pcrel, the linked TB is compiled + * to know its full virtual address, so we can delay the + * update to pc to the unlinked path. A long chain of links + * can thus avoid many updates to the PC. + */ + if (TARGET_TB_PCREL) { + gen_update_pc(s, diff); + tcg_gen_goto_tb(n); + } else { + tcg_gen_goto_tb(n); + gen_update_pc(s, diff); + } tcg_gen_exit_tb(s->base.tb, n); } else { - gen_set_pc_im(s, dest); + gen_update_pc(s, diff); gen_goto_ptr(); } s->base.is_jmp = DISAS_NORETURN; } /* Jump, specifying which TB number to use if we gen_goto_tb() */ -static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno) +static void gen_jmp_tb(DisasContext *s, target_long diff, int tbno) { if (unlikely(s->ss_active)) { /* An indirect jump so that we still trigger the debug exception. */ - gen_set_pc_im(s, dest); + gen_update_pc(s, diff); s->base.is_jmp = DISAS_JUMP; return; } @@ -2598,7 +2657,7 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno) * gen_jmp(); * on the second call to gen_jmp(). */ - gen_goto_tb(s, tbno, dest); + gen_goto_tb(s, tbno, diff); break; case DISAS_UPDATE_NOCHAIN: case DISAS_UPDATE_EXIT: @@ -2607,7 +2666,7 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno) * Avoid using goto_tb so we really do exit back to the main loop * and don't chain to another TB. */ - gen_set_pc_im(s, dest); + gen_update_pc(s, diff); gen_goto_ptr(); s->base.is_jmp = DISAS_NORETURN; break; @@ -2620,9 +2679,9 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno) } } -static inline void gen_jmp(DisasContext *s, uint32_t dest) +static inline void gen_jmp(DisasContext *s, target_long diff) { - gen_jmp_tb(s, dest, 0); + gen_jmp_tb(s, diff, 0); } static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y) @@ -2724,8 +2783,6 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn, * an exception and return false. Otherwise it will return true, * and set *tgtmode and *regno appropriately. */ - int exc_target = default_exception_el(s); - /* These instructions are present only in ARMv8, or in ARMv7 with the * Virtualization Extensions. */ @@ -2833,10 +2890,11 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn, tcg_gen_sextract_i32(tcg_el, tcg_el, ctz32(SCR_EEL2), 1); tcg_gen_addi_i32(tcg_el, tcg_el, 3); } else { - tcg_el = tcg_const_i32(3); + tcg_el = tcg_constant_i32(3); } - gen_exception_el(s, EXCP_UDEF, syn_uncategorized(), tcg_el); + gen_exception_insn_el_v(s, 0, EXCP_UDEF, + syn_uncategorized(), tcg_el); tcg_temp_free_i32(tcg_el); return false; } @@ -2861,14 +2919,13 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn, undef: /* If we get here then some access check did not pass */ - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_uncategorized(), exc_target); + gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized()); return false; } static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn) { - TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno; + TCGv_i32 tcg_reg; int tgtmode = 0, regno = 0; if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, ®no)) { @@ -2877,20 +2934,18 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn) /* Sync state because msr_banked() can raise exceptions */ gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); + gen_update_pc(s, 0); tcg_reg = load_reg(s, rn); - tcg_tgtmode = tcg_const_i32(tgtmode); - tcg_regno = tcg_const_i32(regno); - gen_helper_msr_banked(cpu_env, tcg_reg, tcg_tgtmode, tcg_regno); - tcg_temp_free_i32(tcg_tgtmode); - tcg_temp_free_i32(tcg_regno); + gen_helper_msr_banked(cpu_env, tcg_reg, + tcg_constant_i32(tgtmode), + tcg_constant_i32(regno)); tcg_temp_free_i32(tcg_reg); s->base.is_jmp = DISAS_UPDATE_EXIT; } static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn) { - TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno; + TCGv_i32 tcg_reg; int tgtmode = 0, regno = 0; if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, ®no)) { @@ -2899,13 +2954,11 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn) /* Sync state because mrs_banked() can raise exceptions */ gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); + gen_update_pc(s, 0); tcg_reg = tcg_temp_new_i32(); - tcg_tgtmode = tcg_const_i32(tgtmode); - tcg_regno = tcg_const_i32(regno); - gen_helper_mrs_banked(tcg_reg, cpu_env, tcg_tgtmode, tcg_regno); - tcg_temp_free_i32(tcg_tgtmode); - tcg_temp_free_i32(tcg_regno); + gen_helper_mrs_banked(tcg_reg, cpu_env, + tcg_constant_i32(tgtmode), + tcg_constant_i32(regno)); store_reg(s, rn, tcg_reg); s->base.is_jmp = DISAS_UPDATE_EXIT; } @@ -2988,9 +3041,8 @@ void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, } \ static void gen_##NAME##0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) \ { \ - TCGv_vec zero = tcg_const_zeros_vec_matching(d); \ + TCGv_vec zero = tcg_constant_vec_matching(d, vece, 0); \ tcg_gen_cmp_vec(COND, vece, d, a, zero); \ - tcg_temp_free_vec(zero); \ } \ void gen_gvec_##NAME##0(unsigned vece, uint32_t d, uint32_t m, \ uint32_t opr_sz, uint32_t max_sz) \ @@ -3980,8 +4032,8 @@ void gen_ushl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift) TCGv_i32 rval = tcg_temp_new_i32(); TCGv_i32 lsh = tcg_temp_new_i32(); TCGv_i32 rsh = tcg_temp_new_i32(); - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 max = tcg_const_i32(32); + TCGv_i32 zero = tcg_constant_i32(0); + TCGv_i32 max = tcg_constant_i32(32); /* * Rely on the TCG guarantee that out of range shifts produce @@ -3999,8 +4051,6 @@ void gen_ushl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift) tcg_temp_free_i32(rval); tcg_temp_free_i32(lsh); tcg_temp_free_i32(rsh); - tcg_temp_free_i32(zero); - tcg_temp_free_i32(max); } void gen_ushl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift) @@ -4009,8 +4059,8 @@ void gen_ushl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift) TCGv_i64 rval = tcg_temp_new_i64(); TCGv_i64 lsh = tcg_temp_new_i64(); TCGv_i64 rsh = tcg_temp_new_i64(); - TCGv_i64 zero = tcg_const_i64(0); - TCGv_i64 max = tcg_const_i64(64); + TCGv_i64 zero = tcg_constant_i64(0); + TCGv_i64 max = tcg_constant_i64(64); /* * Rely on the TCG guarantee that out of range shifts produce @@ -4028,8 +4078,6 @@ void gen_ushl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift) tcg_temp_free_i64(rval); tcg_temp_free_i64(lsh); tcg_temp_free_i64(rsh); - tcg_temp_free_i64(zero); - tcg_temp_free_i64(max); } static void gen_ushl_vec(unsigned vece, TCGv_vec dst, @@ -4124,8 +4172,8 @@ void gen_sshl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift) TCGv_i32 rval = tcg_temp_new_i32(); TCGv_i32 lsh = tcg_temp_new_i32(); TCGv_i32 rsh = tcg_temp_new_i32(); - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 max = tcg_const_i32(31); + TCGv_i32 zero = tcg_constant_i32(0); + TCGv_i32 max = tcg_constant_i32(31); /* * Rely on the TCG guarantee that out of range shifts produce @@ -4144,8 +4192,6 @@ void gen_sshl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift) tcg_temp_free_i32(rval); tcg_temp_free_i32(lsh); tcg_temp_free_i32(rsh); - tcg_temp_free_i32(zero); - tcg_temp_free_i32(max); } void gen_sshl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift) @@ -4154,8 +4200,8 @@ void gen_sshl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift) TCGv_i64 rval = tcg_temp_new_i64(); TCGv_i64 lsh = tcg_temp_new_i64(); TCGv_i64 rsh = tcg_temp_new_i64(); - TCGv_i64 zero = tcg_const_i64(0); - TCGv_i64 max = tcg_const_i64(63); + TCGv_i64 zero = tcg_constant_i64(0); + TCGv_i64 max = tcg_constant_i64(63); /* * Rely on the TCG guarantee that out of range shifts produce @@ -4174,8 +4220,6 @@ void gen_sshl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift) tcg_temp_free_i64(rval); tcg_temp_free_i64(lsh); tcg_temp_free_i64(rsh); - tcg_temp_free_i64(zero); - tcg_temp_free_i64(max); } static void gen_sshl_vec(unsigned vece, TCGv_vec dst, @@ -4690,8 +4734,6 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, * Note that on XScale all cp0..c13 registers do an access check * call in order to handle c15_cpar. */ - TCGv_ptr tmpptr; - TCGv_i32 tcg_syn, tcg_isread; uint32_t syndrome; /* Note that since we are an implementation which takes an @@ -4733,26 +4775,24 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, } gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); - tmpptr = tcg_const_ptr(ri); - tcg_syn = tcg_const_i32(syndrome); - tcg_isread = tcg_const_i32(isread); - gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn, - tcg_isread); - tcg_temp_free_ptr(tmpptr); - tcg_temp_free_i32(tcg_syn); - tcg_temp_free_i32(tcg_isread); + gen_update_pc(s, 0); + gen_helper_access_check_cp_reg(cpu_env, + tcg_constant_ptr(ri), + tcg_constant_i32(syndrome), + tcg_constant_i32(isread)); } else if (ri->type & ARM_CP_RAISES_EXC) { /* * The readfn or writefn might raise an exception; * synchronize the CPU state in case it does. */ gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); + gen_update_pc(s, 0); } /* Handle special cases first */ - switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) { + switch (ri->type & ARM_CP_SPECIAL_MASK) { + case 0: + break; case ARM_CP_NOP: return; case ARM_CP_WFI: @@ -4760,11 +4800,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, unallocated_encoding(s); return; } - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_WFI; return; default: - break; + g_assert_not_reached(); } if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { @@ -4777,13 +4817,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, TCGv_i64 tmp64; TCGv_i32 tmp; if (ri->type & ARM_CP_CONST) { - tmp64 = tcg_const_i64(ri->resetvalue); + tmp64 = tcg_constant_i64(ri->resetvalue); } else if (ri->readfn) { - TCGv_ptr tmpptr; tmp64 = tcg_temp_new_i64(); - tmpptr = tcg_const_ptr(ri); - gen_helper_get_cp_reg64(tmp64, cpu_env, tmpptr); - tcg_temp_free_ptr(tmpptr); + gen_helper_get_cp_reg64(tmp64, cpu_env, + tcg_constant_ptr(ri)); } else { tmp64 = tcg_temp_new_i64(); tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset); @@ -4798,13 +4836,10 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, } else { TCGv_i32 tmp; if (ri->type & ARM_CP_CONST) { - tmp = tcg_const_i32(ri->resetvalue); + tmp = tcg_constant_i32(ri->resetvalue); } else if (ri->readfn) { - TCGv_ptr tmpptr; tmp = tcg_temp_new_i32(); - tmpptr = tcg_const_ptr(ri); - gen_helper_get_cp_reg(tmp, cpu_env, tmpptr); - tcg_temp_free_ptr(tmpptr); + gen_helper_get_cp_reg(tmp, cpu_env, tcg_constant_ptr(ri)); } else { tmp = load_cpu_offset(ri->fieldoffset); } @@ -4834,25 +4869,19 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, tcg_temp_free_i32(tmplo); tcg_temp_free_i32(tmphi); if (ri->writefn) { - TCGv_ptr tmpptr = tcg_const_ptr(ri); - gen_helper_set_cp_reg64(cpu_env, tmpptr, tmp64); - tcg_temp_free_ptr(tmpptr); + gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), + tmp64); } else { tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); } tcg_temp_free_i64(tmp64); } else { + TCGv_i32 tmp = load_reg(s, rt); if (ri->writefn) { - TCGv_i32 tmp; - TCGv_ptr tmpptr; - tmp = load_reg(s, rt); - tmpptr = tcg_const_ptr(ri); - gen_helper_set_cp_reg(cpu_env, tmpptr, tmp); - tcg_temp_free_ptr(tmpptr); + gen_helper_set_cp_reg(cpu_env, tcg_constant_ptr(ri), tmp); tcg_temp_free_i32(tmp); } else { - TCGv_i32 tmp = load_reg(s, rt); - store_cpu_offset(tmp, ri->fieldoffset); + store_cpu_offset(tmp, ri->fieldoffset, 4); } } } @@ -4866,17 +4895,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, * A write to any coprocessor register that ends a TB * must rebuild the hflags for the next TB. */ - TCGv_i32 tcg_el = tcg_const_i32(s->current_el); - if (arm_dc_feature(s, ARM_FEATURE_M)) { - gen_helper_rebuild_hflags_m32(cpu_env, tcg_el); - } else { - if (ri->type & ARM_CP_NEWEL) { - gen_helper_rebuild_hflags_a32_newel(cpu_env); - } else { - gen_helper_rebuild_hflags_a32(cpu_env, tcg_el); - } - } - tcg_temp_free_i32(tcg_el); + gen_rebuild_hflags(s, ri->type & ARM_CP_NEWEL); /* * We default to ending the TB on a coprocessor register write, * but allow this to be suppressed by the register definition @@ -5124,7 +5143,7 @@ static void gen_srs(DisasContext *s, * For the UNPREDICTABLE cases we choose to UNDEF. */ if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), 3); + gen_exception_insn_el(s, 0, EXCP_UDEF, syn_uncategorized(), 3); return; } @@ -5165,12 +5184,10 @@ static void gen_srs(DisasContext *s, } addr = tcg_temp_new_i32(); - tmp = tcg_const_i32(mode); /* get_r13_banked() will raise an exception if called from System mode */ gen_set_condexec(s); - gen_set_pc_im(s, s->pc_curr); - gen_helper_get_r13_banked(addr, cpu_env, tmp); - tcg_temp_free_i32(tmp); + gen_update_pc(s, 0); + gen_helper_get_r13_banked(addr, cpu_env, tcg_constant_i32(mode)); switch (amode) { case 0: /* DA */ offset = -4; @@ -5185,7 +5202,7 @@ static void gen_srs(DisasContext *s, offset = 4; break; default: - abort(); + g_assert_not_reached(); } tcg_gen_addi_i32(addr, addr, offset); tmp = load_reg(s, 14); @@ -5210,12 +5227,10 @@ static void gen_srs(DisasContext *s, offset = 0; break; default: - abort(); + g_assert_not_reached(); } tcg_gen_addi_i32(addr, addr, offset); - tmp = tcg_const_i32(mode); - gen_helper_set_r13_banked(cpu_env, tmp, addr); - tcg_temp_free_i32(tmp); + gen_helper_set_r13_banked(cpu_env, tcg_constant_i32(mode), addr); } tcg_temp_free_i32(addr); s->base.is_jmp = DISAS_UPDATE_EXIT; @@ -5225,7 +5240,7 @@ static void gen_srs(DisasContext *s, static void arm_skip_unless(DisasContext *s, uint32_t cond) { arm_gen_condlabel(s); - arm_gen_test_cc(cond ^ 1, s->condlabel); + arm_gen_test_cc(cond ^ 1, s->condlabel.label); } @@ -5527,18 +5542,16 @@ static bool op_s_rri_rot(DisasContext *s, arg_s_rri_rot *a, void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32), int logic_cc, StoreRegKind kind) { - TCGv_i32 tmp1, tmp2; + TCGv_i32 tmp1; uint32_t imm; imm = ror32(a->imm, a->rot); if (logic_cc && a->rot) { tcg_gen_movi_i32(cpu_CF, imm >> 31); } - tmp2 = tcg_const_i32(imm); tmp1 = load_reg(s, a->rn); - gen(tmp1, tmp1, tmp2); - tcg_temp_free_i32(tmp2); + gen(tmp1, tmp1, tcg_constant_i32(imm)); if (logic_cc) { gen_logic_CC(tmp1); @@ -5557,9 +5570,10 @@ static bool op_s_rxi_rot(DisasContext *s, arg_s_rri_rot *a, if (logic_cc && a->rot) { tcg_gen_movi_i32(cpu_CF, imm >> 31); } - tmp = tcg_const_i32(imm); - gen(tmp, tmp); + tmp = tcg_temp_new_i32(); + gen(tmp, tcg_constant_i32(imm)); + if (logic_cc) { gen_logic_CC(tmp); } @@ -5685,14 +5699,11 @@ static bool trans_ADR(DisasContext *s, arg_ri *a) static bool trans_MOVW(DisasContext *s, arg_MOVW *a) { - TCGv_i32 tmp; - if (!ENABLE_ARCH_6T2) { return false; } - tmp = tcg_const_i32(a->imm); - store_reg(s, a->rd, tmp); + store_reg(s, a->rd, tcg_constant_i32(a->imm)); return true; } @@ -6063,14 +6074,13 @@ static bool trans_UMAAL(DisasContext *s, arg_UMAAL *a) t0 = load_reg(s, a->rm); t1 = load_reg(s, a->rn); tcg_gen_mulu2_i32(t0, t1, t0, t1); - zero = tcg_const_i32(0); + zero = tcg_constant_i32(0); t2 = load_reg(s, a->ra); tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero); tcg_temp_free_i32(t2); t2 = load_reg(s, a->rd); tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero); tcg_temp_free_i32(t2); - tcg_temp_free_i32(zero); store_reg(s, a->ra, t0); store_reg(s, a->rd, t1); return true; @@ -6245,7 +6255,7 @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a) * scheduling of other vCPUs. */ if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_YIELD; } return true; @@ -6261,7 +6271,7 @@ static bool trans_WFE(DisasContext *s, arg_WFE *a) * implemented so we can't sleep like WFI does. */ if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_WFE; } return true; @@ -6270,11 +6280,34 @@ static bool trans_WFE(DisasContext *s, arg_WFE *a) static bool trans_WFI(DisasContext *s, arg_WFI *a) { /* For WFI, halt the vCPU until an IRQ. */ - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); s->base.is_jmp = DISAS_WFI; return true; } +static bool trans_ESB(DisasContext *s, arg_ESB *a) +{ + /* + * For M-profile, minimal-RAS ESB can be a NOP. + * Without RAS, we must implement this as NOP. + */ + if (!arm_dc_feature(s, ARM_FEATURE_M) && dc_isar_feature(aa32_ras, s)) { + /* + * QEMU does not have a source of physical SErrors, + * so we are only concerned with virtual SErrors. + * The pseudocode in the ARM for this case is + * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then + * AArch32.vESBOperation(); + * Most of the condition can be evaluated at translation time. + * Test for EL2 present, and defer test for SEL2 to runtime. + */ + if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { + gen_helper_vesb(cpu_env); + } + } + return true; +} + static bool trans_NOP(DisasContext *s, arg_NOP *a) { return true; @@ -6317,14 +6350,13 @@ static bool op_crc32(DisasContext *s, arg_rrr *a, bool c, MemOp sz) default: g_assert_not_reached(); } - t3 = tcg_const_i32(1 << sz); + t3 = tcg_constant_i32(1 << sz); if (c) { gen_helper_crc32c(t1, t1, t2, t3); } else { gen_helper_crc32(t1, t1, t2, t3); } tcg_temp_free_i32(t2); - tcg_temp_free_i32(t3); store_reg(s, a->rd, t1); return true; } @@ -6407,8 +6439,8 @@ static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a) if (!arm_dc_feature(s, ARM_FEATURE_M)) { return false; } - tmp = tcg_const_i32(a->sysm); - gen_helper_v7m_mrs(tmp, cpu_env, tmp); + tmp = tcg_temp_new_i32(); + gen_helper_v7m_mrs(tmp, cpu_env, tcg_constant_i32(a->sysm)); store_reg(s, a->rd, tmp); return true; } @@ -6420,13 +6452,12 @@ static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a) if (!arm_dc_feature(s, ARM_FEATURE_M)) { return false; } - addr = tcg_const_i32((a->mask << 10) | a->sysm); + addr = tcg_constant_i32((a->mask << 10) | a->sysm); reg = load_reg(s, a->rn); gen_helper_v7m_msr(cpu_env, addr, reg); - tcg_temp_free_i32(addr); tcg_temp_free_i32(reg); /* If we wrote to CONTROL, the EL might have changed */ - gen_helper_rebuild_hflags_m32_newel(cpu_env); + gen_rebuild_hflags(s, true); gen_lookup_tb(s); return true; } @@ -6470,7 +6501,7 @@ static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a) return false; } tmp = load_reg(s, a->rm); - tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb); + gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb); gen_bx(s, tmp); return true; } @@ -6549,12 +6580,9 @@ 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); + gen_exception_internal_insn(s, EXCP_SEMIHOST); } else { gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false)); } @@ -6635,8 +6663,8 @@ static bool trans_TT(DisasContext *s, arg_TT *a) } addr = load_reg(s, a->rn); - tmp = tcg_const_i32((a->A << 1) | a->T); - gen_helper_v7m_tt(tmp, cpu_env, addr, tmp); + tmp = tcg_temp_new_i32(); + gen_helper_v7m_tt(tmp, cpu_env, addr, tcg_constant_i32((a->A << 1) | a->T)); tcg_temp_free_i32(addr); store_reg(s, a->rd, tmp); return true; @@ -6653,7 +6681,7 @@ static ISSInfo make_issinfo(DisasContext *s, int rd, bool p, bool w) /* ISS not valid if writeback */ if (p && !w) { ret = rd; - if (s->base.pc_next - s->pc_curr == 2) { + if (curr_insn_len(s) == 2) { ret |= ISSIs16Bit; } } else { @@ -7603,7 +7631,7 @@ static bool trans_PKH(DisasContext *s, arg_PKH *a) static bool op_sat(DisasContext *s, arg_sat *a, void (*gen)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) { - TCGv_i32 tmp, satimm; + TCGv_i32 tmp; int shift = a->imm; if (!ENABLE_ARCH_6) { @@ -7617,9 +7645,7 @@ static bool op_sat(DisasContext *s, arg_sat *a, tcg_gen_shli_i32(tmp, tmp, shift); } - satimm = tcg_const_i32(a->satimm); - gen(tmp, cpu_env, tmp, satimm); - tcg_temp_free_i32(satimm); + gen(tmp, cpu_env, tmp, tcg_constant_i32(a->satimm)); store_reg(s, a->rd, tmp); return true; @@ -7954,9 +7980,7 @@ static bool op_smmla(DisasContext *s, arg_rrrr *a, bool round, bool sub) * a non-zero multiplicand lowpart, and the correct result * lowpart for rounding. */ - TCGv_i32 zero = tcg_const_i32(0); - tcg_gen_sub2_i32(t2, t1, zero, t3, t2, t1); - tcg_temp_free_i32(zero); + tcg_gen_sub2_i32(t2, t1, tcg_constant_i32(0), t3, t2, t1); } else { tcg_gen_add_i32(t1, t1, t3); } @@ -8053,7 +8077,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 @@ -8093,7 +8117,7 @@ static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) { int i, j, n, list, mem_idx; bool user = a->u; - TCGv_i32 addr, tmp, tmp2; + TCGv_i32 addr, tmp; if (user) { /* STM (user) */ @@ -8123,9 +8147,7 @@ static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) if (user && i != 15) { tmp = tcg_temp_new_i32(); - tmp2 = tcg_const_i32(i); - gen_helper_get_user_reg(tmp, cpu_env, tmp2); - tcg_temp_free_i32(tmp2); + gen_helper_get_user_reg(tmp, cpu_env, tcg_constant_i32(i)); } else { tmp = load_reg(s, i); } @@ -8166,7 +8188,7 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) bool loaded_base; bool user = a->u; bool exc_return = false; - TCGv_i32 addr, tmp, tmp2, loaded_var; + TCGv_i32 addr, tmp, loaded_var; if (user) { /* LDM (user), LDM (exception return) */ @@ -8209,9 +8231,7 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) tmp = tcg_temp_new_i32(); gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); if (user) { - tmp2 = tcg_const_i32(i); - gen_helper_set_user_reg(cpu_env, tmp2, tmp); - tcg_temp_free_i32(tmp2); + gen_helper_set_user_reg(cpu_env, tcg_constant_i32(i), tmp); tcg_temp_free_i32(tmp); } else if (i == a->rn) { loaded_var = tmp; @@ -8304,7 +8324,7 @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a) s->eci_handled = true; - zero = tcg_const_i32(0); + zero = tcg_constant_i32(0); for (i = 0; i < 15; i++) { if (extract32(a->list, i, 1)) { /* Clear R[i] */ @@ -8316,11 +8336,8 @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a) * Clear APSR (by calling the MSR helper with the same argument * as for "MSR APSR_nzcvqg, Rn": mask = 0b1100, SYSM=0) */ - TCGv_i32 maskreg = tcg_const_i32(0xc << 8); - gen_helper_v7m_msr(cpu_env, maskreg, zero); - tcg_temp_free_i32(maskreg); + gen_helper_v7m_msr(cpu_env, tcg_constant_i32(0xc00), zero); } - tcg_temp_free_i32(zero); clear_eci_state(s); return true; } @@ -8331,7 +8348,7 @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a) static bool trans_B(DisasContext *s, arg_i *a) { - gen_jmp(s, read_pc(s) + a->imm); + gen_jmp(s, jmp_diff(s, a->imm)); return true; } @@ -8346,14 +8363,14 @@ static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a) return true; } arm_skip_unless(s, a->cond); - gen_jmp(s, read_pc(s) + a->imm); + gen_jmp(s, jmp_diff(s, a->imm)); return true; } static bool trans_BL(DisasContext *s, arg_i *a) { - tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb); - gen_jmp(s, read_pc(s) + a->imm); + gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb); + gen_jmp(s, jmp_diff(s, a->imm)); return true; } @@ -8371,16 +8388,17 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a) if (s->thumb && (a->imm & 2)) { return false; } - tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb); + gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb); store_cpu_field_constant(!s->thumb, thumb); - gen_jmp(s, (read_pc(s) & ~3) + a->imm); + /* This jump is computed from an aligned PC: subtract off the low bits. */ + gen_jmp(s, jmp_diff(s, a->imm - (s->pc_curr & 3))); return true; } static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a) { assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); - tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12)); + gen_pc_plus_diff(s, cpu_R[14], jmp_diff(s, a->imm << 12)); return true; } @@ -8390,7 +8408,7 @@ static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a) assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1); - tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1); + gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1); gen_bx(s, tmp); return true; } @@ -8406,7 +8424,7 @@ static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a) tmp = tcg_temp_new_i32(); tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1); tcg_gen_andi_i32(tmp, tmp, 0xfffffffc); - tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1); + gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1); gen_bx(s, tmp); return true; } @@ -8463,8 +8481,7 @@ static bool trans_DLS(DisasContext *s, arg_DLS *a) store_reg(s, 14, tmp); if (a->size != 4) { /* DLSTP: set FPSCR.LTPSIZE */ - tmp = tcg_const_i32(a->size); - store_cpu_field(tmp, v7m.ltpsize); + store_cpu_field(tcg_constant_i32(a->size), v7m.ltpsize); s->base.is_jmp = DISAS_UPDATE_NOCHAIN; } return true; @@ -8474,7 +8491,7 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a) { /* M-profile low-overhead while-loop start */ TCGv_i32 tmp; - TCGLabel *nextlabel; + DisasLabel nextlabel; if (!dc_isar_feature(aa32_lob, s)) { return false; @@ -8509,14 +8526,14 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a) * Do the check-and-raise-exception by hand. */ if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); + gen_exception_insn_el(s, 0, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); return true; } } - nextlabel = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel); + nextlabel = gen_disas_label(s); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel.label); tmp = load_reg(s, a->rn); store_reg(s, 14, tmp); if (a->size != 4) { @@ -8529,17 +8546,16 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a) */ bool ok = vfp_access_check(s); assert(ok); - tmp = tcg_const_i32(a->size); - store_cpu_field(tmp, v7m.ltpsize); + store_cpu_field(tcg_constant_i32(a->size), v7m.ltpsize); /* * LTPSIZE updated, but MVE_NO_PRED will always be the same thing (0) * when we take this upcoming exit from this TB, so gen_jmp_tb() is OK. */ } - gen_jmp_tb(s, s->base.pc_next, 1); + gen_jmp_tb(s, curr_insn_len(s), 1); - gen_set_label(nextlabel); - gen_jmp(s, read_pc(s) + a->imm); + set_disas_label(s, nextlabel); + gen_jmp(s, jmp_diff(s, a->imm)); return true; } @@ -8554,7 +8570,7 @@ static bool trans_LE(DisasContext *s, arg_LE *a) * any faster. */ TCGv_i32 tmp; - TCGLabel *loopend; + DisasLabel loopend; bool fpu_active; if (!dc_isar_feature(aa32_lob, s)) { @@ -8609,18 +8625,17 @@ static bool trans_LE(DisasContext *s, arg_LE *a) if (!a->tp && dc_isar_feature(aa32_mve, s) && fpu_active) { /* Need to do a runtime check for LTPSIZE != 4 */ - TCGLabel *skipexc = gen_new_label(); + DisasLabel skipexc = gen_disas_label(s); tmp = load_cpu_field(v7m.ltpsize); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc.label); tcg_temp_free_i32(tmp); - gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), - default_exception_el(s)); - gen_set_label(skipexc); + gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized()); + set_disas_label(s, skipexc); } if (a->f) { /* Loop-forever: just jump back to the loop start */ - gen_jmp(s, read_pc(s) - a->imm); + gen_jmp(s, jmp_diff(s, -a->imm)); return true; } @@ -8630,9 +8645,9 @@ static bool trans_LE(DisasContext *s, arg_LE *a) * loop decrement value is 1. For LETP we need to calculate the decrement * value from LTPSIZE. */ - loopend = gen_new_label(); + loopend = gen_disas_label(s); if (!a->tp) { - tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend); + tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend.label); tcg_gen_addi_i32(cpu_R[14], cpu_R[14], -1); } else { /* @@ -8645,22 +8660,21 @@ static bool trans_LE(DisasContext *s, arg_LE *a) tcg_gen_shl_i32(decr, tcg_constant_i32(1), decr); tcg_temp_free_i32(ltpsize); - tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend); + tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend.label); tcg_gen_sub_i32(cpu_R[14], cpu_R[14], decr); tcg_temp_free_i32(decr); } /* Jump back to the loop start */ - gen_jmp(s, read_pc(s) - a->imm); + gen_jmp(s, jmp_diff(s, -a->imm)); - gen_set_label(loopend); + set_disas_label(s, loopend); if (a->tp) { /* Exits from tail-pred loops must reset LTPSIZE to 4 */ - tmp = tcg_const_i32(4); - store_cpu_field(tmp, v7m.ltpsize); + store_cpu_field(tcg_constant_i32(4), v7m.ltpsize); } /* End TB, continuing to following insn */ - gen_jmp_tb(s, s->base.pc_next, 1); + gen_jmp_tb(s, curr_insn_len(s), 1); return true; } @@ -8733,10 +8747,11 @@ static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half) tcg_gen_add_i32(addr, addr, tmp); gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), half ? MO_UW : MO_UB); - tcg_temp_free_i32(addr); tcg_gen_add_i32(tmp, tmp, tmp); - tcg_gen_addi_i32(tmp, tmp, read_pc(s)); + gen_pc_plus_diff(s, addr, jmp_diff(s, 0)); + tcg_gen_add_i32(tmp, tmp, addr); + tcg_temp_free_i32(addr); store_reg(s, 15, tmp); return true; } @@ -8757,9 +8772,9 @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a) arm_gen_condlabel(s); tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE, - tmp, 0, s->condlabel); + tmp, 0, s->condlabel.label); tcg_temp_free_i32(tmp); - gen_jmp(s, read_pc(s) + a->imm); + gen_jmp(s, jmp_diff(s, a->imm)); return true; } @@ -8772,14 +8787,12 @@ 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); + gen_exception_internal_insn(s, EXCP_SEMIHOST); } else { - gen_set_pc_im(s, s->base.pc_next); + gen_update_pc(s, curr_insn_len(s)); s->svc_imm = a->imm; s->base.is_jmp = DISAS_SWI; } @@ -8878,7 +8891,7 @@ static bool trans_CPS(DisasContext *s, arg_CPS *a) static bool trans_CPS_v7m(DisasContext *s, arg_CPS_v7m *a) { - TCGv_i32 tmp, addr, el; + TCGv_i32 tmp, addr; if (!arm_dc_feature(s, ARM_FEATURE_M)) { return false; @@ -8888,23 +8901,18 @@ static bool trans_CPS_v7m(DisasContext *s, arg_CPS_v7m *a) return true; } - tmp = tcg_const_i32(a->im); + tmp = tcg_constant_i32(a->im); /* FAULTMASK */ if (a->F) { - addr = tcg_const_i32(19); + addr = tcg_constant_i32(19); gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); } /* PRIMASK */ if (a->I) { - addr = tcg_const_i32(16); + addr = tcg_constant_i32(16); gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); } - el = tcg_const_i32(s->current_el); - gen_helper_rebuild_hflags_m32(cpu_env, el); - tcg_temp_free_i32(el); - tcg_temp_free_i32(tmp); + gen_rebuild_hflags(s, false); gen_lookup_tb(s); return true; } @@ -9040,13 +9048,14 @@ static bool trans_CSEL(DisasContext *s, arg_CSEL *a) } /* In this insn input reg fields of 0b1111 mean "zero", not "PC" */ + zero = tcg_constant_i32(0); if (a->rn == 15) { - rn = tcg_const_i32(0); + rn = zero; } else { rn = load_reg(s, a->rn); } if (a->rm == 15) { - rm = tcg_const_i32(0); + rm = zero; } else { rm = load_reg(s, a->rm); } @@ -9068,10 +9077,8 @@ static bool trans_CSEL(DisasContext *s, arg_CSEL *a) } arm_test_cc(&c, a->fcond); - zero = tcg_const_i32(0); tcg_gen_movcond_i32(c.cond, rn, c.value, zero, rn, rm); arm_free_cc(&c); - tcg_temp_free_i32(zero); store_reg(s, a->rd, rn); tcg_temp_free_i32(rm); @@ -9091,8 +9098,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) * UsageFault exception. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { - gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), - default_exception_el(s)); + gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized()); return; } @@ -9101,8 +9107,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) * Illegal execution state. This has priority over BTI * exceptions, but comes after instruction abort exceptions. */ - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_illegalstate(), default_exception_el(s)); + gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate()); return; } @@ -9333,13 +9338,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->isar = &cpu->isar; dc->condjmp = 0; - - dc->aarch64 = 0; - /* If we are coming from secure EL0 in a system with a 32-bit EL3, then - * there is no secure EL1, so we route exceptions to EL3. - */ - dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) && - !arm_el_is_aa64(env, 3); + dc->pc_save = dc->base.pc_first; + dc->aarch64 = false; dc->thumb = EX_TBFLAG_AM32(tb_flags, THUMB); dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE; condexec = EX_TBFLAG_AM32(tb_flags, CONDEXEC); @@ -9356,7 +9356,6 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) */ dc->eci = dc->condexec_mask = dc->condexec_cond = 0; dc->eci_handled = false; - dc->insn_eci_rewind = NULL; if (condexec & 0xf) { dc->condexec_mask = (condexec & 0xf) << 1; dc->condexec_cond = condexec >> 4; @@ -9380,8 +9379,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 = @@ -9389,7 +9387,6 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->v7m_lspact = EX_TBFLAG_M32(tb_flags, LSPACT); dc->mve_no_pred = EX_TBFLAG_M32(tb_flags, MVE_NO_PRED); } else { - dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL); dc->sctlr_b = EX_TBFLAG_A32(tb_flags, SCTLR__B); dc->hstr_active = EX_TBFLAG_A32(tb_flags, HSTR_ACTIVE); dc->ns = EX_TBFLAG_A32(tb_flags, NS); @@ -9400,6 +9397,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->vec_len = EX_TBFLAG_A32(tb_flags, VECLEN); dc->vec_stride = EX_TBFLAG_A32(tb_flags, VECSTRIDE); } + dc->sme_trap_nonstreaming = + EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING); } dc->cp_regs = cpu->cp_regs; dc->features = env->features; @@ -9492,13 +9491,17 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) * fields here. */ uint32_t condexec_bits; + target_ulong pc_arg = dc->base.pc_next; + if (TARGET_TB_PCREL) { + pc_arg &= ~TARGET_PAGE_MASK; + } if (dc->eci) { condexec_bits = dc->eci << 4; } else { condexec_bits = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1); } - tcg_gen_insn_start(dc->base.pc_next, condexec_bits, 0); + tcg_gen_insn_start(pc_arg, condexec_bits, 0); dc->insn_start = tcg_last_op(); } @@ -9541,8 +9544,11 @@ static bool arm_check_ss_active(DisasContext *dc) static void arm_post_translate_insn(DisasContext *dc) { - if (dc->condjmp && !dc->base.is_jmp) { - gen_set_label(dc->condlabel); + if (dc->condjmp && dc->base.is_jmp == DISAS_NEXT) { + if (dc->pc_save != dc->condlabel.pc_save) { + gen_update_pc(dc, dc->condlabel.pc_save - dc->pc_save); + } + gen_set_label(dc->condlabel.label); dc->condjmp = 0; } translator_loop_temp_check(&dc->base); @@ -9645,6 +9651,9 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) uint32_t pc = dc->base.pc_next; uint32_t insn; bool is_16bit; + /* TCG op to rewind to if this turns out to be an invalid ECI state */ + TCGOp *insn_eci_rewind = NULL; + target_ulong insn_eci_pc_save = -1; /* Misaligned thumb PC is architecturally impossible. */ assert((dc->base.pc_next & 1) == 0); @@ -9671,8 +9680,7 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * Illegal execution state. This has priority over BTI * exceptions, but comes after instruction abort exceptions. */ - gen_exception_insn(dc, dc->pc_curr, EXCP_UDEF, - syn_illegalstate(), default_exception_el(dc)); + gen_exception_insn(dc, 0, EXCP_UDEF, syn_illegalstate()); return; } @@ -9707,7 +9715,8 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * insn" case. We will rewind to the marker (ie throwing away * all the generated code) and instead emit "take exception". */ - dc->insn_eci_rewind = tcg_last_op(); + insn_eci_rewind = tcg_last_op(); + insn_eci_pc_save = dc->pc_save; } if (dc->condexec_mask && !thumb_insn_is_unconditional(dc, insn)) { @@ -9743,10 +9752,10 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * Insn wasn't valid for ECI/ICI at all: undo what we * just generated and instead emit an exception */ - tcg_remove_ops_after(dc->insn_eci_rewind); + tcg_remove_ops_after(insn_eci_rewind); + dc->pc_save = insn_eci_pc_save; dc->condjmp = 0; - gen_exception_insn(dc, dc->pc_curr, EXCP_INVSTATE, syn_uncategorized(), - default_exception_el(dc)); + gen_exception_insn(dc, 0, EXCP_INVSTATE, syn_uncategorized()); } arm_post_translate_insn(dc); @@ -9792,22 +9801,21 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) switch (dc->base.is_jmp) { case DISAS_SWI: gen_ss_advance(dc); - gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb), - default_exception_el(dc)); + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); break; case DISAS_HVC: gen_ss_advance(dc); - gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); + gen_exception_el(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); break; case DISAS_SMC: gen_ss_advance(dc); - gen_exception(EXCP_SMC, syn_aa32_smc(), 3); + gen_exception_el(EXCP_SMC, syn_aa32_smc(), 3); break; case DISAS_NEXT: case DISAS_TOO_MANY: case DISAS_UPDATE_EXIT: case DISAS_UPDATE_NOCHAIN: - gen_set_pc_im(dc, dc->base.pc_next); + gen_update_pc(dc, curr_insn_len(dc)); /* fall through */ default: /* FIXME: Single stepping a WFI insn will not halt the CPU. */ @@ -9828,16 +9836,16 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) switch (dc->base.is_jmp) { case DISAS_NEXT: case DISAS_TOO_MANY: - gen_goto_tb(dc, 1, dc->base.pc_next); + gen_goto_tb(dc, 1, curr_insn_len(dc)); break; case DISAS_UPDATE_NOCHAIN: - gen_set_pc_im(dc, dc->base.pc_next); + gen_update_pc(dc, curr_insn_len(dc)); /* fall through */ case DISAS_JUMP: gen_goto_ptr(); break; case DISAS_UPDATE_EXIT: - gen_set_pc_im(dc, dc->base.pc_next); + gen_update_pc(dc, curr_insn_len(dc)); /* fall through */ default: /* indicate that the hash table must be used to find the next TB */ @@ -9847,18 +9855,13 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) /* nothing more to generate */ break; case DISAS_WFI: - { - TCGv_i32 tmp = tcg_const_i32((dc->thumb && - !(dc->insn & (1U << 31))) ? 2 : 4); - - gen_helper_wfi(cpu_env, tmp); - tcg_temp_free_i32(tmp); - /* The helper doesn't necessarily throw an exception, but we + gen_helper_wfi(cpu_env, tcg_constant_i32(curr_insn_len(dc))); + /* + * The helper doesn't necessarily throw an exception, but we * must go back to the main loop to check for interrupts anyway. */ tcg_gen_exit_tb(NULL, 0); break; - } case DISAS_WFE: gen_helper_wfe(cpu_env); break; @@ -9866,37 +9869,37 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) gen_helper_yield(cpu_env); break; case DISAS_SWI: - gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb), - default_exception_el(dc)); + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); break; case DISAS_HVC: - gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); + gen_exception_el(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); break; case DISAS_SMC: - gen_exception(EXCP_SMC, syn_aa32_smc(), 3); + gen_exception_el(EXCP_SMC, syn_aa32_smc(), 3); break; } } if (dc->condjmp) { /* "Condition failed" instruction codepath for the branch/trap insn */ - gen_set_label(dc->condlabel); + set_disas_label(dc, dc->condlabel); gen_set_condexec(dc); if (unlikely(dc->ss_active)) { - gen_set_pc_im(dc, dc->base.pc_next); + gen_update_pc(dc, curr_insn_len(dc)); gen_singlestep_exception(dc); } else { - gen_goto_tb(dc, 1, dc->base.pc_next); + gen_goto_tb(dc, 1, curr_insn_len(dc)); } } } -static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void arm_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { DisasContext *dc = container_of(dcbase, DisasContext, base); - qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first)); - log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first)); + target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size); } static const TranslatorOps arm_translator_ops = { @@ -9918,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; @@ -9933,19 +9937,5 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) } #endif - translator_loop(ops, &dc.base, cpu, tb, max_insns); -} - -void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, - target_ulong *data) -{ - if (is_a64(env)) { - env->pc = data[0]; - env->condexec_bits = 0; - env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; - } else { - env->regs[15] = data[0]; - env->condexec_bits = data[1]; - env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; - } + translator_loop(cpu, tb, max_insns, pc, host_pc, ops, &dc.base); } diff --git a/target/arm/translate.h b/target/arm/translate.h index 3a0db801d3bf..3cdc7dbc2fb1 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -6,18 +6,42 @@ /* internal defines */ + +/* + * Save pc_save across a branch, so that we may restore the value from + * before the branch at the point the label is emitted. + */ +typedef struct DisasLabel { + TCGLabel *label; + target_ulong pc_save; +} DisasLabel; + typedef struct DisasContext { DisasContextBase base; const ARMISARegisters *isar; /* The address of the current instruction being translated. */ target_ulong pc_curr; + /* + * For TARGET_TB_PCREL, the full value of cpu_pc is not known + * (although the page offset is known). For convenience, the + * translation loop uses the full virtual address that triggered + * the translation, from base.pc_start through pc_curr. + * For efficiency, we do not update cpu_pc for every instruction. + * Instead, pc_save has the value of pc_curr at the time of the + * last update to cpu_pc, which allows us to compute the addend + * needed to bring cpu_pc current: pc_curr - pc_save. + * If cpu_pc now contains the destination of an indirect branch, + * pc_save contains -1 to indicate that relative updates are no + * longer possible. + */ + target_ulong pc_save; target_ulong page_start; uint32_t insn; /* Nonzero if this instruction has been conditionally skipped. */ int condjmp; /* The label that will be jumped to when the instruction is skipped. */ - TCGLabel *condlabel; + DisasLabel condlabel; /* Thumb-2 conditional execution bits. */ int condexec_mask; int condexec_cond; @@ -28,9 +52,6 @@ typedef struct DisasContext { * after decode (ie after any UNDEF checks) */ bool eci_handled; - /* TCG op to rewind to if this turns out to be an invalid ECI state */ - TCGOp *insn_eci_rewind; - int thumb; int sctlr_b; MemOp be_data; #if !defined(CONFIG_USER_ONLY) @@ -43,9 +64,9 @@ typedef struct DisasContext { bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ int sve_excp_el; /* SVE exception EL or 0 if enabled */ - int sve_len; /* SVE vector length in bytes */ - /* Flag indicating that exceptions from secure mode are routed to EL3. */ - bool secure_routed_to_el3; + int sme_excp_el; /* SME exception EL or 0 if enabled */ + int vl; /* current vector length in bytes */ + int svl; /* current streaming vector length in bytes */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ int vec_len; int vec_stride; @@ -59,12 +80,11 @@ typedef struct DisasContext { * so that top level loop can generate correct syndrome information. */ uint32_t svc_imm; - int aarch64; int current_el; - /* Debug target exception level for single-step exceptions */ - int debug_target_el; GHashTable *cp_regs; uint64_t features; /* CPU features bits */ + bool aarch64; + bool thumb; /* Because unallocated encodings generate different exception syndrome * information from traps due to FP being disabled, we can't do a single * "is fp access disabled" check at a high level in the decode tree. @@ -100,6 +120,14 @@ typedef struct DisasContext { bool align_mem; /* True if PSTATE.IL is set */ bool pstate_il; + /* True if PSTATE.SM is set. */ + bool pstate_sm; + /* True if PSTATE.ZA is set. */ + bool pstate_za; + /* True if non-streaming insns should raise an SME Streaming exception. */ + bool sme_trap_nonstreaming; + /* True if the current instruction is non-streaming. */ + bool is_nonstreaming; /* True if MVE insns are definitely not predicated by VPR or LTPSIZE */ bool mve_no_pred; /* @@ -150,6 +178,11 @@ static inline int plus_2(DisasContext *s, int x) return x + 2; } +static inline int plus_12(DisasContext *s, int x) +{ + return x + 12; +} + static inline int times_2(DisasContext *s, int x) { return x * 2; @@ -201,20 +234,6 @@ static inline int get_mem_index(DisasContext *s) return arm_to_core_mmu_idx(s->mmu_idx); } -/* Function used to determine the target exception EL when otherwise not known - * or default. - */ -static inline int default_exception_el(DisasContext *s) -{ - /* If we are coming from secure EL0 in a system with a 32-bit EL3, then - * there is no secure EL1, so we route exceptions to EL3. Otherwise, - * exceptions can only be routed to ELs above 1, so we target the higher of - * 1 or the current EL. - */ - return (s->mmu_idx == ARMMMUIdx_SE10_0 && s->secure_routed_to_el3) - ? 3 : MAX(1, s->current_el); -} - static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) { /* We don't need to save all of the syndrome so we mask and shift @@ -229,6 +248,11 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) s->insn_start = NULL; } +static inline int curr_insn_len(DisasContext *s) +{ + return s->base.pc_next - s->pc_curr; +} + /* is_jmp field values */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ /* CPU state was modified dynamically; exit to main loop for interrupts. */ @@ -252,7 +276,7 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) * For instructions which want an immediate exit to the main loop, as opposed * to attempting to use lookup_and_goto_ptr. Unlike DISAS_UPDATE_EXIT, this * doesn't write the PC on exiting the translation loop so you need to ensure - * something (gen_a64_set_pc_im or runtime helper) has done so before we reach + * something (gen_a64_update_pc or runtime helper) has done so before we reach * return from cpu_tb_exec. */ #define DISAS_EXIT DISAS_TARGET_9 @@ -261,14 +285,14 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) #ifdef TARGET_AARCH64 void a64_translate_init(void); -void gen_a64_set_pc_im(uint64_t val); +void gen_a64_update_pc(DisasContext *s, target_long diff); extern const TranslatorOps aarch64_translator_ops; #else static inline void a64_translate_init(void) { } -static inline void gen_a64_set_pc_im(uint64_t val) +static inline void gen_a64_update_pc(DisasContext *s, target_long diff) { } #endif @@ -279,8 +303,10 @@ void arm_jump_cc(DisasCompare *cmp, TCGLabel *label); void arm_gen_test_cc(int cc, TCGLabel *label); MemOp pow2_align(unsigned i); void unallocated_encoding(DisasContext *s); -void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, - uint32_t syn, uint32_t target_el); +void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp, + uint32_t syn, uint32_t target_el); +void gen_exception_insn(DisasContext *s, target_long pc_diff, + int excp, uint32_t syn); /* Return state of Alternate Half-precision flag, caller frees result */ static inline TCGv_i32 get_ahp_flag(void) @@ -329,33 +355,12 @@ static inline void gen_ss_advance(DisasContext *s) } } -static inline void gen_exception(int excp, uint32_t syndrome, - uint32_t target_el) -{ - TCGv_i32 tcg_excp = tcg_const_i32(excp); - TCGv_i32 tcg_syn = tcg_const_i32(syndrome); - TCGv_i32 tcg_el = tcg_const_i32(target_el); - - gen_helper_exception_with_syndrome(cpu_env, tcg_excp, - tcg_syn, tcg_el); - - tcg_temp_free_i32(tcg_el); - tcg_temp_free_i32(tcg_syn); - tcg_temp_free_i32(tcg_excp); -} - /* Generate an architectural singlestep exception */ static inline void gen_swstep_exception(DisasContext *s, int isv, int ex) { - bool same_el = (s->debug_target_el == s->current_el); - - /* - * If singlestep is targeting a lower EL than the current one, - * then s->ss_active must be false and we can never get here. - */ - assert(s->debug_target_el >= s->current_el); - - gen_exception(EXCP_UDEF, syn_swstep(same_el, isv, ex), s->debug_target_el); + /* Fill in the same_el field of the syndrome in the helper. */ + uint32_t syn = syn_swstep(false, isv, ex); + gen_helper_exception_swstep(cpu_env, tcg_constant_i32(syn)); } /* @@ -583,4 +588,44 @@ static inline MemOp finalize_memop(DisasContext *s, MemOp opc) */ uint64_t asimd_imm_const(uint32_t imm, int cmode, int op); +/* + * gen_disas_label: + * Create a label and cache a copy of pc_save. + */ +static inline DisasLabel gen_disas_label(DisasContext *s) +{ + return (DisasLabel){ + .label = gen_new_label(), + .pc_save = s->pc_save, + }; +} + +/* + * set_disas_label: + * Emit a label and restore the cached copy of pc_save. + */ +static inline void set_disas_label(DisasContext *s, DisasLabel l) +{ + gen_set_label(l.label); + s->pc_save = l.pc_save; +} + +/* + * Helpers for implementing sets of trans_* functions. + * Defer the implementation of NAME to FUNC, with optional extra arguments. + */ +#define TRANS(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { return FUNC(s, __VA_ARGS__); } +#define TRANS_FEAT(NAME, FEAT, FUNC, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); } + +#define TRANS_FEAT_NONSTREAMING(NAME, FEAT, FUNC, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { \ + s->is_nonstreaming = true; \ + return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); \ + } + #endif /* TARGET_ARM_TRANSLATE_H */ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 17fb1583622e..f59d3b26eacf 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -127,6 +127,32 @@ const uint64_t expand_pred_b_data[256] = { 0xffffffffffffffff, }; +/* + * Similarly for half-word elements. + * for (i = 0; i < 256; ++i) { + * unsigned long m = 0; + * if (i & 0xaa) { + * continue; + * } + * for (j = 0; j < 8; j += 2) { + * if ((i >> j) & 1) { + * m |= 0xfffful << (j << 3); + * } + * } + * printf("[0x%x] = 0x%016lx,\n", i, m); + * } + */ +const uint64_t expand_pred_h_data[0x55 + 1] = { + [0x01] = 0x000000000000ffff, [0x04] = 0x00000000ffff0000, + [0x05] = 0x00000000ffffffff, [0x10] = 0x0000ffff00000000, + [0x11] = 0x0000ffff0000ffff, [0x14] = 0x0000ffffffff0000, + [0x15] = 0x0000ffffffffffff, [0x40] = 0xffff000000000000, + [0x41] = 0xffff00000000ffff, [0x44] = 0xffff0000ffff0000, + [0x45] = 0xffff0000ffffffff, [0x50] = 0xffffffff00000000, + [0x51] = 0xffffffff0000ffff, [0x54] = 0xffffffffffff0000, + [0x55] = 0xffffffffffffffff, +}; + /* Signed saturating rounding doubling multiply-accumulate high half, 8-bit */ int8_t do_sqrdmlah_b(int8_t src1, int8_t src2, int8_t src3, bool neg, bool round) @@ -2531,7 +2557,7 @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b) * BFloat16 Dot Product */ -static float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2) +float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2) { /* FPCR is ignored for BFDOT and BFMMLA. */ float_status bf_status = { @@ -2664,3 +2690,27 @@ void HELPER(gvec_bfmlal_idx)(void *vd, void *vn, void *vm, } clear_tail(d, opr_sz, simd_maxsz(desc)); } + +#define DO_CLAMP(NAME, TYPE) \ +void HELPER(NAME)(void *d, void *n, void *m, void *a, uint32_t desc) \ +{ \ + intptr_t i, opr_sz = simd_oprsz(desc); \ + for (i = 0; i < opr_sz; i += sizeof(TYPE)) { \ + TYPE aa = *(TYPE *)(a + i); \ + TYPE nn = *(TYPE *)(n + i); \ + TYPE mm = *(TYPE *)(m + i); \ + TYPE dd = MIN(MAX(aa, nn), mm); \ + *(TYPE *)(d + i) = dd; \ + } \ + clear_tail(d, opr_sz, simd_maxsz(desc)); \ +} + +DO_CLAMP(gvec_sclamp_b, int8_t) +DO_CLAMP(gvec_sclamp_h, int16_t) +DO_CLAMP(gvec_sclamp_s, int32_t) +DO_CLAMP(gvec_sclamp_d, int64_t) + +DO_CLAMP(gvec_uclamp_b, uint8_t) +DO_CLAMP(gvec_uclamp_h, uint16_t) +DO_CLAMP(gvec_uclamp_s, uint32_t) +DO_CLAMP(gvec_uclamp_d, uint64_t) diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h index 2a3355829068..1f4ed80ff76e 100644 --- a/target/arm/vec_internal.h +++ b/target/arm/vec_internal.h @@ -17,8 +17,8 @@ * License along with this library; if not, see . */ -#ifndef TARGET_ARM_VEC_INTERNALS_H -#define TARGET_ARM_VEC_INTERNALS_H +#ifndef TARGET_ARM_VEC_INTERNAL_H +#define TARGET_ARM_VEC_INTERNAL_H /* * Note that vector data is stored in host-endian 64-bit chunks, @@ -29,7 +29,7 @@ * The H1_ macros are used when performing byte arithmetic and then * casting the final pointer to a type of size N. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define H1(x) ((x) ^ 7) #define H1_2(x) ((x) ^ 6) #define H1_4(x) ((x) ^ 4) @@ -50,8 +50,21 @@ #define H8(x) (x) #define H1_8(x) (x) -/* Data for expanding active predicate bits to bytes, for byte elements. */ +/* + * Expand active predicate bits to bytes, for byte elements. + */ extern const uint64_t expand_pred_b_data[256]; +static inline uint64_t expand_pred_b(uint8_t byte) +{ + return expand_pred_b_data[byte]; +} + +/* Similarly for half-word elements. */ +extern const uint64_t expand_pred_h_data[0x55 + 1]; +static inline uint64_t expand_pred_h(uint8_t byte) +{ + return expand_pred_h_data[byte & 0x55]; +} static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) { @@ -217,4 +230,17 @@ uint64_t pmull_h(uint64_t op1, uint64_t op2); */ uint64_t pmull_w(uint64_t op1, uint64_t op2); -#endif /* TARGET_ARM_VEC_INTERNALS_H */ +/** + * bfdotadd: + * @sum: addend + * @e1, @e2: multiplicand vectors + * + * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum. + * The @e1 and @e2 operands correspond to the 32-bit source vector + * slots and contain two Bfloat16 values each. + * + * Corresponds to the ARM pseudocode function BFDotAdd. + */ +float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2); + +#endif /* TARGET_ARM_VEC_INTERNAL_H */ diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h index 32a1c762e647..01ea5f160b6e 100644 --- a/target/avr/cpu-qom.h +++ b/target/avr/cpu-qom.h @@ -18,8 +18,8 @@ * */ -#ifndef QEMU_AVR_QOM_H -#define QEMU_AVR_QOM_H +#ifndef TARGET_AVR_CPU_QOM_H +#define TARGET_AVR_CPU_QOM_H #include "hw/core/cpu.h" #include "qom/object.h" @@ -31,7 +31,7 @@ OBJECT_DECLARE_CPU_TYPE(AVRCPU, AVRCPUClass, AVR_CPU) /** * AVRCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A AVR CPU model. */ @@ -40,8 +40,8 @@ struct AVRCPUClass { CPUClass parent_class; /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; -#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ +#endif /* TARGET_AVR_CPU_QOM_H */ diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 5d70e34dd544..d0139804b9f7 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,17 +54,29 @@ 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) +static void avr_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { - CPUState *cs = CPU(ds); + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + env->pc_w = data[0]; +} + +static void avr_cpu_reset_hold(Object *obj) +{ + CPUState *cs = CPU(obj); AVRCPU *cpu = AVR_CPU(cs); AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); CPUAVRState *env = &cpu->env; - mcc->parent_reset(ds); + if (mcc->parent_phases.hold) { + mcc->parent_phases.hold(obj); + } env->pc_w = 0; env->sregI = 1; @@ -195,6 +214,7 @@ static const struct SysemuCPUOps avr_sysemu_ops = { static const struct TCGCPUOps avr_tcg_ops = { .initialize = avr_cpu_tcg_init, .synchronize_from_tb = avr_cpu_synchronize_from_tb, + .restore_state_to_opc = avr_restore_state_to_opc, .cpu_exec_interrupt = avr_cpu_exec_interrupt, .tlb_fill = avr_cpu_tlb_fill, .do_interrupt = avr_cpu_do_interrupt, @@ -205,16 +225,19 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); AVRCPUClass *mcc = AVR_CPU_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, avr_cpu_realizefn, &mcc->parent_realize); - device_class_set_parent_reset(dc, avr_cpu_reset, &mcc->parent_reset); + + resettable_class_set_parent_phases(rc, NULL, avr_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = avr_cpu_class_by_name; cc->has_work = avr_cpu_has_work; cc->dump_state = avr_cpu_dump_state; cc->set_pc = avr_cpu_set_pc; - cc->memory_rw_debug = avr_cpu_memory_rw_debug; + 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/cpu.h b/target/avr/cpu.h index 55497f851dc8..f19dd72926a7 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -184,8 +184,6 @@ void avr_cpu_tcg_init(void); void avr_cpu_list(void); int cpu_avr_exec(CPUState *cpu); -int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, - int len, bool is_write); enum { TB_FLAGS_FULL_ACCESS = 1, @@ -217,8 +215,7 @@ static inline int cpu_interrupts_enabled(CPUAVRState *env) static inline uint8_t cpu_get_sreg(CPUAVRState *env) { - uint8_t sreg; - sreg = (env->sregC) << 0 + return (env->sregC) << 0 | (env->sregZ) << 1 | (env->sregN) << 2 | (env->sregV) << 3 @@ -226,7 +223,6 @@ static inline uint8_t cpu_get_sreg(CPUAVRState *env) | (env->sregH) << 5 | (env->sregT) << 6 | (env->sregI) << 7; - return sreg; } static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg) @@ -247,4 +243,4 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #include "exec/cpu-all.h" -#endif /* !defined (QEMU_AVR_CPU_H) */ +#endif /* QEMU_AVR_CPU_H */ diff --git a/target/avr/helper.c b/target/avr/helper.c index c27f7029010f..156dde4e9268 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) @@ -93,12 +98,6 @@ void avr_cpu_do_interrupt(CPUState *cs) cs->exception_index = -1; } -int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, - int len, bool is_write) -{ - return cpu_memory_rw_debug(cs, addr, buf, len, is_write); -} - hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { return addr; /* I assume 1:1 address correspondence */ @@ -108,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 af8a3e0f9ce6..2bed56f13568 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; @@ -3015,10 +3033,11 @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void avr_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void avr_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps avr_tr_ops = { @@ -3030,14 +3049,9 @@ 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); -} - -void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc_w = data[0]; + translator_loop(cs, tb, max_insns, pc, host_pc, &avr_tr_ops, &dc.base); } diff --git a/target/cris/cpu-param.h b/target/cris/cpu-param.h index 36a305876126..12ec22d8df15 100644 --- a/target/cris/cpu-param.h +++ b/target/cris/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef CRIS_CPU_PARAM_H -#define CRIS_CPU_PARAM_H 1 +#define CRIS_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 13 diff --git a/target/cris/cpu-qom.h b/target/cris/cpu-qom.h index 71e8af0e70a4..431a1d536a96 100644 --- a/target/cris/cpu-qom.h +++ b/target/cris/cpu-qom.h @@ -30,7 +30,7 @@ OBJECT_DECLARE_CPU_TYPE(CRISCPU, CRISCPUClass, CRIS_CPU) /** * CRISCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * @vr: Version Register value. * * A CRIS CPU model. @@ -41,7 +41,7 @@ struct CRISCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; uint32_t vr; }; diff --git a/target/cris/cpu.c b/target/cris/cpu.c index ed6c7813424b..a6a93c235951 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -35,20 +35,38 @@ 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 void cris_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + CRISCPU *cpu = CRIS_CPU(cs); + + cpu->env.pc = data[0]; +} + static bool cris_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); } -static void cris_cpu_reset(DeviceState *dev) +static void cris_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); CRISCPU *cpu = CRIS_CPU(s); CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(cpu); CPUCRISState *env = &cpu->env; uint32_t vr; - ccc->parent_reset(dev); + if (ccc->parent_phases.hold) { + ccc->parent_phases.hold(obj); + } vr = env->pregs[PR_VR]; memset(env, 0, offsetof(CPUCRISState, end_reset_fields)); @@ -205,6 +223,7 @@ static const struct SysemuCPUOps cris_sysemu_ops = { static const struct TCGCPUOps crisv10_tcg_ops = { .initialize = cris_initialize_crisv10_tcg, + .restore_state_to_opc = cris_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = cris_cpu_tlb_fill, @@ -215,6 +234,7 @@ static const struct TCGCPUOps crisv10_tcg_ops = { static const struct TCGCPUOps crisv32_tcg_ops = { .initialize = cris_initialize_tcg, + .restore_state_to_opc = cris_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = cris_cpu_tlb_fill, @@ -287,16 +307,19 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, cris_cpu_realizefn, &ccc->parent_realize); - device_class_set_parent_reset(dc, cris_cpu_reset, &ccc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, cris_cpu_reset_hold, NULL, + &ccc->parent_phases); cc->class_by_name = cris_cpu_class_by_name; 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/helper.c b/target/cris/helper.c index 91e4aeb17806..81a72699b5ae 100644 --- a/target/cris/helper.c +++ b/target/cris/helper.c @@ -87,7 +87,7 @@ bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size, cs->exception_index = EXCP_BUSFAULT; env->fault_vector = res.bf_vec; if (retaddr) { - if (cpu_restore_state(cs, retaddr, true)) { + if (cpu_restore_state(cs, retaddr)) { /* Evaluate flags after retranslation. */ helper_top_evaluate_flags(env); } diff --git a/target/cris/translate.c b/target/cris/translate.c index 3656cd6db16e..fbc3fd586537 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -3268,11 +3268,12 @@ static void cris_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void cris_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void cris_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { if (!DISAS_CRIS) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } } @@ -3285,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) @@ -3390,9 +3392,3 @@ void cris_initialize_tcg(void) pregnames_v32[i]); } } - -void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} diff --git a/target/hexagon/README b/target/hexagon/README index 372e24747c9f..6cb5affddb20 100644 --- a/target/hexagon/README +++ b/target/hexagon/README @@ -27,6 +27,10 @@ Hexagon-specific code are encode*.def Encoding patterns for each instruction iclass.def Instruction class definitions used to determine legal VLIW slots for each instruction + qemu/target/hexagon/idef-parser + Parser that, given the high-level definitions of an instruction, + produces a C function generating equivalent tiny code instructions. + See README.rst. qemu/linux-user/hexagon Helpers for loading the ELF file and making Linux system calls, signals, etc @@ -47,6 +51,7 @@ header files in /target/hexagon gen_tcg_funcs.py -> tcg_funcs_generated.c.inc gen_tcg_func_table.py -> tcg_func_table_generated.c.inc gen_helper_funcs.py -> helper_funcs_generated.c.inc + gen_idef_parser_funcs.py -> idef_parser_input.h Qemu helper functions have 3 parts DEF_HELPER declaration indicates the signature of the helper diff --git a/target/hexagon/attribs.h b/target/hexagon/attribs.h index 54576f4143b6..d51bb4f7325c 100644 --- a/target/hexagon/attribs.h +++ b/target/hexagon/attribs.h @@ -32,4 +32,4 @@ extern DECLARE_BITMAP(opcode_attribs[XX_LAST_OPCODE], A_ZZ_LASTATTRIB); #define GET_ATTRIB(opcode, attrib) \ test_bit(attrib, opcode_attribs[opcode]) -#endif /* ATTRIBS_H */ +#endif /* HEXAGON_ATTRIBS_H */ diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index dc890a557f5e..5d2a102c180d 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 fa9bd702d63d..807037c58624 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -86,7 +86,7 @@ static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr) return addr; } -/* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */ +/* HEX_REG_P3_0_ALIASED (aka C4) is an alias for the predicate registers */ static target_ulong read_p3_0(CPUHexagonState *env) { int32_t control_reg = 0; @@ -102,7 +102,7 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum) { target_ulong value; - if (regnum == HEX_REG_P3_0) { + if (regnum == HEX_REG_P3_0_ALIASED) { value = read_p3_0(env); } else { value = regnum < 32 ? adjust_stack_ptrs(env, env->gpr[regnum]) @@ -198,7 +198,7 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags) print_reg(f, env, HEX_REG_M0); print_reg(f, env, HEX_REG_M1); print_reg(f, env, HEX_REG_USR); - print_reg(f, env, HEX_REG_P3_0); + print_reg(f, env, HEX_REG_P3_0_ALIASED); print_reg(f, env, HEX_REG_GP); print_reg(f, env, HEX_REG_UGP); print_reg(f, env, HEX_REG_PC); @@ -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) @@ -264,20 +271,26 @@ static bool hexagon_cpu_has_work(CPUState *cs) return true; } -void restore_state_to_opc(CPUHexagonState *env, TranslationBlock *tb, - target_ulong *data) +static void hexagon_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + env->gpr[HEX_REG_PC] = data[0]; } -static void hexagon_cpu_reset(DeviceState *dev) +static void hexagon_cpu_reset_hold(Object *obj) { - CPUState *cs = CPU(dev); + CPUState *cs = CPU(obj); HexagonCPU *cpu = HEXAGON_CPU(cs); HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(cpu); CPUHexagonState *env = &cpu->env; - mcc->parent_reset(dev); + if (mcc->parent_phases.hold) { + mcc->parent_phases.hold(obj); + } set_default_nan_mode(1, &env->fp_status); set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); @@ -320,6 +333,7 @@ static void hexagon_cpu_init(Object *obj) static const struct TCGCPUOps hexagon_tcg_ops = { .initialize = hexagon_translate_init, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, + .restore_state_to_opc = hexagon_restore_state_to_opc, }; static void hexagon_cpu_class_init(ObjectClass *c, void *data) @@ -327,16 +341,19 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); device_class_set_parent_realize(dc, hexagon_cpu_realize, &mcc->parent_realize); - device_class_set_parent_reset(dc, hexagon_cpu_reset, &mcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, hexagon_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = hexagon_cpu_class_by_name; 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/cpu.h b/target/hexagon/cpu.h index 2a65a57bab38..34c0ae0a672c 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -25,6 +25,7 @@ #include "mmvec/mmvec.h" #include "qom/object.h" #include "hw/core/cpu.h" +#include "hw/registerfields.h" #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 @@ -78,7 +79,6 @@ typedef struct CPUArchState { target_ulong gpr[TOTAL_PER_THREAD_REGS]; target_ulong pred[NUM_PREGS]; target_ulong branch_taken; - target_ulong next_PC; /* For comparing with LLDB on target - see adjust_stack_ptrs function */ target_ulong last_pc_dumped; @@ -137,7 +137,7 @@ typedef struct HexagonCPUClass { CPUClass parent_class; /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; } HexagonCPUClass; struct ArchCPU { @@ -153,16 +153,18 @@ struct ArchCPU { #include "cpu_bits.h" +FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1) + static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { + uint32_t hex_flags = 0; *pc = env->gpr[HEX_REG_PC]; *cs_base = 0; -#ifdef CONFIG_USER_ONLY - *flags = 0; -#else -#error System mode not supported on Hexagon yet -#endif + if (*pc == env->gpr[HEX_REG_SA0]) { + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1); + } + *flags = hex_flags; } static inline int cpu_mmu_index(CPUHexagonState *env, bool ifetch) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 6f0f27b4ba59..041c8de751b4 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 @@ -388,6 +388,7 @@ static void decode_set_insn_attr_fields(Packet *pkt) uint16_t opcode; pkt->pkt_has_cof = false; + pkt->pkt_has_multi_cof = false; pkt->pkt_has_endloop = false; pkt->pkt_has_dczeroa = false; @@ -402,20 +403,33 @@ 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; + } } } - pkt->pkt_has_cof |= decode_opcode_can_jump(opcode); + if (decode_opcode_can_jump(opcode)) { + if (pkt->pkt_has_cof) { + pkt->pkt_has_multi_cof = true; + } + pkt->pkt_has_cof = true; + } pkt->insn[i].is_endloop = decode_opcode_ends_loop(opcode); pkt->pkt_has_endloop |= pkt->insn[i].is_endloop; - pkt->pkt_has_cof |= pkt->pkt_has_endloop; + if (pkt->pkt_has_endloop) { + if (pkt->pkt_has_cof) { + pkt->pkt_has_multi_cof = true; + } + pkt->pkt_has_cof = true; + } } } diff --git a/target/hexagon/gdbstub.c b/target/hexagon/gdbstub.c index 9c8c04c961b1..d152d01bfe7e 100644 --- a/target/hexagon/gdbstub.c +++ b/target/hexagon/gdbstub.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "exec/gdbstub.h" #include "cpu.h" #include "internal.h" diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py index a446c4538452..19e9883f4c0c 100755 --- a/target/hexagon/gen_helper_funcs.py +++ b/target/hexagon/gen_helper_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 @@ -238,6 +238,17 @@ def gen_helper_function(f, tag, tagregs, tagimms): gen_helper_arg_imm(f,immlett) i += 1 + if (hex_common.need_pkt_has_multi_cof(tag)): + f.write(", uint32_t pkt_has_multi_cof") + + if hex_common.need_PC(tag): + if i > 0: f.write(", ") + f.write("target_ulong PC") + i += 1 + if hex_common.helper_needs_next_PC(tag): + if i > 0: f.write(", ") + f.write("target_ulong next_PC") + i += 1 if hex_common.need_slot(tag): if i > 0: f.write(", ") f.write("uint32_t slot") @@ -287,11 +298,24 @@ def main(): hex_common.read_attribs_file(sys.argv[2]) hex_common.read_overrides_file(sys.argv[3]) hex_common.read_overrides_file(sys.argv[4]) + ## Whether or not idef-parser is enabled is + ## determined by the number of arguments to + ## this script: + ## + ## 5 args. -> not enabled, + ## 6 args. -> idef-parser enabled. + ## + ## The 6:th arg. then holds a list of the successfully + ## parsed instructions. + is_idef_parser_enabled = len(sys.argv) > 6 + if is_idef_parser_enabled: + hex_common.read_idef_parser_enabled_file(sys.argv[5]) hex_common.calculate_attribs() tagregs = hex_common.get_tagregs() tagimms = hex_common.get_tagimms() - with open(sys.argv[5], 'w') as f: + output_file = sys.argv[-1] + with open(output_file, 'w') as f: for tag in hex_common.tags: ## Skip the priv instructions if ( "A_PRIV" in hex_common.attribdict[tag] ) : @@ -308,6 +332,8 @@ def main(): continue if ( hex_common.skip_qemu_helper(tag) ): continue + if ( hex_common.is_idef_parser_enabled(tag) ): + continue gen_helper_function(f, tag, tagregs, tagimms) diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py index 3b4e993fd177..674bf370facc 100755 --- a/target/hexagon/gen_helper_protos.py +++ b/target/hexagon/gen_helper_protos.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 @@ -82,15 +82,21 @@ def gen_helper_prototype(f, tag, tagregs, tagimms): ## Figure out how many arguments the helper will take if (numscalarresults == 0): def_helper_size = len(regs)+len(imms)+numscalarreadwrite+1 + if hex_common.need_pkt_has_multi_cof(tag): def_helper_size += 1 if hex_common.need_part1(tag): def_helper_size += 1 if hex_common.need_slot(tag): def_helper_size += 1 + if hex_common.need_PC(tag): def_helper_size += 1 + if hex_common.helper_needs_next_PC(tag): def_helper_size += 1 f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag)) ## The return type is void f.write(', void' ) else: def_helper_size = len(regs)+len(imms)+numscalarreadwrite + if hex_common.need_pkt_has_multi_cof(tag): def_helper_size += 1 if hex_common.need_part1(tag): def_helper_size += 1 if hex_common.need_slot(tag): def_helper_size += 1 + if hex_common.need_PC(tag): def_helper_size += 1 + if hex_common.helper_needs_next_PC(tag): def_helper_size += 1 f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag)) ## Generate the qemu DEF_HELPER type for each result @@ -126,7 +132,11 @@ def gen_helper_prototype(f, tag, tagregs, tagimms): for immlett,bits,immshift in imms: f.write(", s32") - ## Add the arguments for the instruction slot and part1 (if needed) + ## Add the arguments for the instruction pkt_has_multi_cof, slot and + ## part1 (if needed) + if hex_common.need_pkt_has_multi_cof(tag): f.write(', i32') + if hex_common.need_PC(tag): f.write(', i32') + if hex_common.helper_needs_next_PC(tag): f.write(', i32') if hex_common.need_slot(tag): f.write(', i32' ) if hex_common.need_part1(tag): f.write(' , i32' ) f.write(')\n') @@ -136,11 +146,24 @@ def main(): hex_common.read_attribs_file(sys.argv[2]) hex_common.read_overrides_file(sys.argv[3]) hex_common.read_overrides_file(sys.argv[4]) + ## Whether or not idef-parser is enabled is + ## determined by the number of arguments to + ## this script: + ## + ## 5 args. -> not enabled, + ## 6 args. -> idef-parser enabled. + ## + ## The 6:th arg. then holds a list of the successfully + ## parsed instructions. + is_idef_parser_enabled = len(sys.argv) > 6 + if is_idef_parser_enabled: + hex_common.read_idef_parser_enabled_file(sys.argv[5]) hex_common.calculate_attribs() tagregs = hex_common.get_tagregs() tagimms = hex_common.get_tagimms() - with open(sys.argv[5], 'w') as f: + output_file = sys.argv[-1] + with open(output_file, 'w') as f: for tag in hex_common.tags: ## Skip the priv instructions if ( "A_PRIV" in hex_common.attribdict[tag] ) : @@ -158,6 +181,8 @@ def main(): if ( hex_common.skip_qemu_helper(tag) ): continue + if ( hex_common.is_idef_parser_enabled(tag) ): + continue gen_helper_prototype(f, tag, tagregs, tagimms) diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_idef_parser_funcs.py new file mode 100644 index 000000000000..917753d6d847 --- /dev/null +++ b/target/hexagon/gen_idef_parser_funcs.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2022 rev.ng Labs Srl. 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 +## 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 sys +import re +import string +from io import StringIO + +import hex_common + +## +## Generate code to be fed to the idef_parser +## +## Consider A2_add: +## +## Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} +## +## We produce: +## +## A2_add(RdV, in RsV, in RtV) { +## { RdV=RsV+RtV;} +## } +## +## A2_add represents the instruction tag. Then we have a list of TCGv +## that the code generated by the parser can expect in input. Some of +## them are inputs ("in" prefix), while some others are outputs. +## +def main(): + hex_common.read_semantics_file(sys.argv[1]) + hex_common.read_attribs_file(sys.argv[2]) + hex_common.calculate_attribs() + tagregs = hex_common.get_tagregs() + tagimms = hex_common.get_tagimms() + + with open(sys.argv[3], 'w') as f: + f.write('#include "macros.inc"\n\n') + + for tag in hex_common.tags: + ## Skip the priv instructions + if ( "A_PRIV" in hex_common.attribdict[tag] ) : + continue + ## Skip the guest instructions + if ( "A_GUEST" in hex_common.attribdict[tag] ) : + continue + ## Skip instructions that saturate in a ternary expression + if ( tag in {'S2_asr_r_r_sat', 'S2_asl_r_r_sat'} ) : + continue + ## Skip instructions using switch + if ( tag in {'S4_vrcrotate_acc', 'S4_vrcrotate'} ) : + continue + ## Skip trap instructions + if ( tag in {'J2_trap0', 'J2_trap1'} ) : + continue + ## Skip 128-bit instructions + if ( tag in {'A7_croundd_ri', 'A7_croundd_rr'} ) : + continue + if ( tag in {'M7_wcmpyrw', 'M7_wcmpyrwc', + 'M7_wcmpyiw', 'M7_wcmpyiwc', + 'M7_wcmpyrw_rnd', 'M7_wcmpyrwc_rnd', + 'M7_wcmpyiw_rnd', 'M7_wcmpyiwc_rnd'} ) : + continue + ## Skip interleave/deinterleave instructions + if ( tag in {'S2_interleave', 'S2_deinterleave'} ) : + continue + ## Skip instructions using bit reverse + if ( tag in {'S2_brev', 'S2_brevp', 'S2_ct0', 'S2_ct1', + 'S2_ct0p', 'S2_ct1p', 'A4_tlbmatch'} ) : + continue + ## Skip other unsupported instructions + if ( tag == 'S2_cabacdecbin' or tag == 'A5_ACS' ) : + continue + if ( tag.startswith('Y') ) : + continue + if ( tag.startswith('V6_') ) : + continue + if ( tag.startswith('F') ) : + continue + if ( tag.endswith('_locked') ) : + continue + if ( "A_COF" in hex_common.attribdict[tag] ) : + continue + + regs = tagregs[tag] + imms = tagimms[tag] + + arguments = [] + for regtype,regid,toss,numregs in regs: + prefix = "in " if hex_common.is_read(regid) else "" + + is_pair = hex_common.is_pair(regid) + is_single_old = (hex_common.is_single(regid) + and hex_common.is_old_val(regtype, regid, tag)) + is_single_new = (hex_common.is_single(regid) + and hex_common.is_new_val(regtype, regid, tag)) + + if is_pair or is_single_old: + arguments.append("%s%s%sV" % (prefix, regtype, regid)) + elif is_single_new: + arguments.append("%s%s%sN" % (prefix, regtype, regid)) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + + for immlett,bits,immshift in imms: + arguments.append(hex_common.imm_name(immlett)) + + f.write("%s(%s) {\n" % (tag, ", ".join(arguments))) + f.write(" "); + if hex_common.need_ea(tag): + f.write("size4u_t EA; "); + f.write("%s\n" % hex_common.semdict[tag]) + f.write("}\n\n") + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index c6f0879b6ee3..19697b42a501 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -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 @@ -339,12 +339,13 @@ do { \ TCGv LSB = tcg_temp_local_new(); \ TCGLabel *label = gen_new_label(); \ - GET_EA; \ + tcg_gen_movi_tl(EA, 0); \ PRED; \ + CHECK_NOSHUF_PRED(GET_EA, SIZE, LSB); \ PRED_LOAD_CANCEL(LSB, EA); \ tcg_gen_movi_tl(RdV, 0); \ tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \ - fLOAD(1, SIZE, SIGN, EA, RdV); \ + fLOAD(1, SIZE, SIGN, EA, RdV); \ gen_set_label(label); \ tcg_temp_free(LSB); \ } while (0) @@ -398,12 +399,13 @@ do { \ TCGv LSB = tcg_temp_local_new(); \ TCGLabel *label = gen_new_label(); \ - GET_EA; \ + tcg_gen_movi_tl(EA, 0); \ PRED; \ + CHECK_NOSHUF_PRED(GET_EA, 8, LSB); \ PRED_LOAD_CANCEL(LSB, EA); \ tcg_gen_movi_i64(RddV, 0); \ tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \ - fLOAD(1, 8, u, EA, RddV); \ + fLOAD(1, 8, u, EA, RddV); \ gen_set_label(label); \ tcg_temp_free(LSB); \ } while (0) @@ -610,6 +612,409 @@ tcg_temp_free(tmp); \ } while (0) +#define fGEN_TCG_J2_call(SHORTCODE) \ + gen_call(ctx, riV) + +#define fGEN_TCG_J2_callt(SHORTCODE) \ + gen_cond_call(ctx, PuV, TCG_COND_EQ, riV) +#define fGEN_TCG_J2_callf(SHORTCODE) \ + gen_cond_call(ctx, PuV, TCG_COND_NE, riV) + +#define fGEN_TCG_J2_endloop0(SHORTCODE) \ + gen_endloop0(ctx) + +/* + * Compound compare and jump instructions + * Here is a primer to understand the tag names + * + * Comparison + * cmpeqi compare equal to an immediate + * cmpgti compare greater than an immediate + * cmpgtiu compare greater than an unsigned immediate + * cmpeqn1 compare equal to negative 1 + * cmpgtn1 compare greater than negative 1 + * cmpeq compare equal (two registers) + * cmpgtu compare greater than unsigned (two registers) + * tstbit0 test bit zero + * + * Condition + * tp0 p0 is true p0 = cmp.eq(r0,#5); if (p0.new) jump:nt address + * fp0 p0 is false p0 = cmp.eq(r0,#5); if (!p0.new) jump:nt address + * tp1 p1 is true p1 = cmp.eq(r0,#5); if (p1.new) jump:nt address + * fp1 p1 is false p1 = cmp.eq(r0,#5); if (!p1.new) jump:nt address + * + * Prediction (not modelled in qemu) + * _nt not taken + * _t taken + */ +#define fGEN_TCG_J4_cmpeq_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 0, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 0, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 0, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 0, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 1, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 1, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 1, TCG_COND_EQ, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpeq_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 1, TCG_COND_EQ, RsV, RtV, riV) + +#define fGEN_TCG_J4_cmpgt_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 0, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 0, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 0, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 0, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 1, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 1, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 1, TCG_COND_GT, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgt_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 1, TCG_COND_GT, RsV, RtV, riV) + +#define fGEN_TCG_J4_cmpgtu_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 0, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 0, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 0, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 0, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 1, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_t(ctx, 1, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 1, TCG_COND_GTU, RsV, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_jmp_f(ctx, 1, TCG_COND_GTU, RsV, RtV, riV) + +#define fGEN_TCG_J4_cmpeqi_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 0, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 0, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 0, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 0, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 1, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 1, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 1, TCG_COND_EQ, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 1, TCG_COND_EQ, RsV, UiV, riV) + +#define fGEN_TCG_J4_cmpgti_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 0, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 0, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 0, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 0, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 1, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 1, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 1, TCG_COND_GT, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgti_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 1, TCG_COND_GT, RsV, UiV, riV) + +#define fGEN_TCG_J4_cmpgtui_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 0, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 0, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 0, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 0, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 1, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_t(ctx, 1, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 1, TCG_COND_GTU, RsV, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmpi_jmp_f(ctx, 1, TCG_COND_GTU, RsV, UiV, riV) + +#define fGEN_TCG_J4_cmpeqn1_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 0, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 0, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 0, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 0, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 1, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 1, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 1, TCG_COND_EQ, RsV, riV) +#define fGEN_TCG_J4_cmpeqn1_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 1, TCG_COND_EQ, RsV, riV) + +#define fGEN_TCG_J4_cmpgtn1_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 0, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 0, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 0, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 0, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 1, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_t(ctx, 1, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 1, TCG_COND_GT, RsV, riV) +#define fGEN_TCG_J4_cmpgtn1_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_cmp_n1_jmp_f(ctx, 1, TCG_COND_GT, RsV, riV) + +#define fGEN_TCG_J4_tstbit0_tp0_jump_nt(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_EQ, riV) +#define fGEN_TCG_J4_tstbit0_tp0_jump_t(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_EQ, riV) +#define fGEN_TCG_J4_tstbit0_fp0_jump_nt(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_NE, riV) +#define fGEN_TCG_J4_tstbit0_fp0_jump_t(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_NE, riV) +#define fGEN_TCG_J4_tstbit0_tp1_jump_nt(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_EQ, riV) +#define fGEN_TCG_J4_tstbit0_tp1_jump_t(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_EQ, riV) +#define fGEN_TCG_J4_tstbit0_fp1_jump_nt(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_NE, riV) +#define fGEN_TCG_J4_tstbit0_fp1_jump_t(SHORTCODE) \ + gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_NE, riV) + +#define fGEN_TCG_J2_jump(SHORTCODE) \ + gen_jump(ctx, riV) +#define fGEN_TCG_J2_jumpr(SHORTCODE) \ + gen_jumpr(ctx, RsV) +#define fGEN_TCG_J4_jumpseti(SHORTCODE) \ + do { \ + tcg_gen_movi_tl(RdV, UiV); \ + gen_jump(ctx, riV); \ + } while (0) + +#define fGEN_TCG_cond_jumpt(COND) \ + do { \ + TCGv LSB = tcg_temp_new(); \ + COND; \ + gen_cond_jump(ctx, TCG_COND_EQ, LSB, riV); \ + tcg_temp_free(LSB); \ + } while (0) +#define fGEN_TCG_cond_jumpf(COND) \ + do { \ + TCGv LSB = tcg_temp_new(); \ + COND; \ + gen_cond_jump(ctx, TCG_COND_NE, LSB, riV); \ + tcg_temp_free(LSB); \ + } while (0) + +#define fGEN_TCG_J2_jumpt(SHORTCODE) \ + fGEN_TCG_cond_jumpt(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumptpt(SHORTCODE) \ + fGEN_TCG_cond_jumpt(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumpf(SHORTCODE) \ + fGEN_TCG_cond_jumpf(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumpfpt(SHORTCODE) \ + fGEN_TCG_cond_jumpf(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumptnew(SHORTCODE) \ + gen_cond_jump(ctx, TCG_COND_EQ, PuN, riV) +#define fGEN_TCG_J2_jumptnewpt(SHORTCODE) \ + gen_cond_jump(ctx, TCG_COND_EQ, PuN, riV) +#define fGEN_TCG_J2_jumpfnewpt(SHORTCODE) \ + fGEN_TCG_cond_jumpf(fLSBNEW(PuN)) +#define fGEN_TCG_J2_jumpfnew(SHORTCODE) \ + fGEN_TCG_cond_jumpf(fLSBNEW(PuN)) +#define fGEN_TCG_J2_jumprz(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_NE, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprzpt(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_NE, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprnz(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_EQ, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprnzpt(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_EQ, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprgtez(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_GE, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprgtezpt(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_GE, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprltez(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_LE, LSB, RsV, 0)) +#define fGEN_TCG_J2_jumprltezpt(SHORTCODE) \ + fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_LE, LSB, RsV, 0)) + +#define fGEN_TCG_cond_jumprt(COND) \ + do { \ + TCGv LSB = tcg_temp_new(); \ + COND; \ + gen_cond_jumpr(ctx, RsV, TCG_COND_EQ, LSB); \ + tcg_temp_free(LSB); \ + } while (0) +#define fGEN_TCG_cond_jumprf(COND) \ + do { \ + TCGv LSB = tcg_temp_new(); \ + COND; \ + gen_cond_jumpr(ctx, RsV, TCG_COND_NE, LSB); \ + tcg_temp_free(LSB); \ + } while (0) + +#define fGEN_TCG_J2_jumprt(SHORTCODE) \ + fGEN_TCG_cond_jumprt(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumprtpt(SHORTCODE) \ + fGEN_TCG_cond_jumprt(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumprf(SHORTCODE) \ + fGEN_TCG_cond_jumprf(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumprfpt(SHORTCODE) \ + fGEN_TCG_cond_jumprf(fLSBOLD(PuV)) +#define fGEN_TCG_J2_jumprtnew(SHORTCODE) \ + fGEN_TCG_cond_jumprt(fLSBNEW(PuN)) +#define fGEN_TCG_J2_jumprtnewpt(SHORTCODE) \ + fGEN_TCG_cond_jumprt(fLSBNEW(PuN)) +#define fGEN_TCG_J2_jumprfnew(SHORTCODE) \ + fGEN_TCG_cond_jumprf(fLSBNEW(PuN)) +#define fGEN_TCG_J2_jumprfnewpt(SHORTCODE) \ + fGEN_TCG_cond_jumprf(fLSBNEW(PuN)) + +/* + * New value compare & jump instructions + * if ([!]COND(r0.new, r1) jump:t address + * if ([!]COND(r0.new, #7) jump:t address + */ +#define fGEN_TCG_J4_cmpgt_t_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GT, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpgt_t_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GT, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpgt_f_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LE, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpgt_f_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LE, NsN, RtV, riV) + +#define fGEN_TCG_J4_cmpeq_t_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_EQ, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpeq_t_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_EQ, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpeq_f_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_NE, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpeq_f_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_NE, NsN, RtV, riV) + +#define fGEN_TCG_J4_cmplt_t_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LT, NsN, RtV, riV) +#define fGEN_TCG_J4_cmplt_t_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LT, NsN, RtV, riV) +#define fGEN_TCG_J4_cmplt_f_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GE, NsN, RtV, riV) +#define fGEN_TCG_J4_cmplt_f_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GE, NsN, RtV, riV) + +#define fGEN_TCG_J4_cmpeqi_t_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_EQ, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_t_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_EQ, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_f_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_NE, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpeqi_f_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_NE, NsN, UiV, riV) + +#define fGEN_TCG_J4_cmpgti_t_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_GT, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpgti_t_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_GT, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpgti_f_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_LE, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpgti_f_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_LE, NsN, UiV, riV) + +#define fGEN_TCG_J4_cmpltu_t_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LTU, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpltu_t_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LTU, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpltu_f_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GEU, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpltu_f_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GEU, NsN, RtV, riV) + +#define fGEN_TCG_J4_cmpgtui_t_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_GTU, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_t_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_GTU, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_f_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_LEU, NsN, UiV, riV) +#define fGEN_TCG_J4_cmpgtui_f_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_LEU, NsN, UiV, riV) + +#define fGEN_TCG_J4_cmpgtu_t_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GTU, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_t_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_GTU, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_f_jumpnv_t(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LEU, NsN, RtV, riV) +#define fGEN_TCG_J4_cmpgtu_f_jumpnv_nt(SHORTCODE) \ + gen_cmp_jumpnv(ctx, TCG_COND_LEU, NsN, RtV, riV) + +#define fGEN_TCG_J4_cmpeqn1_t_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_EQ, NsN, -1, riV) +#define fGEN_TCG_J4_cmpeqn1_t_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_EQ, NsN, -1, riV) +#define fGEN_TCG_J4_cmpeqn1_f_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_NE, NsN, -1, riV) +#define fGEN_TCG_J4_cmpeqn1_f_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_NE, NsN, -1, riV) + +#define fGEN_TCG_J4_cmpgtn1_t_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_GT, NsN, -1, riV) +#define fGEN_TCG_J4_cmpgtn1_t_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_GT, NsN, -1, riV) +#define fGEN_TCG_J4_cmpgtn1_f_jumpnv_t(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_LE, NsN, -1, riV) +#define fGEN_TCG_J4_cmpgtn1_f_jumpnv_nt(SHORTCODE) \ + gen_cmpi_jumpnv(ctx, TCG_COND_LE, NsN, -1, riV) + +#define fGEN_TCG_J4_tstbit0_t_jumpnv_t(SHORTCODE) \ + gen_testbit0_jumpnv(ctx, NsN, TCG_COND_EQ, riV) +#define fGEN_TCG_J4_tstbit0_t_jumpnv_nt(SHORTCODE) \ + gen_testbit0_jumpnv(ctx, NsN, TCG_COND_EQ, riV) +#define fGEN_TCG_J4_tstbit0_f_jumpnv_t(SHORTCODE) \ + gen_testbit0_jumpnv(ctx, NsN, TCG_COND_NE, riV) +#define fGEN_TCG_J4_tstbit0_f_jumpnv_nt(SHORTCODE) \ + gen_testbit0_jumpnv(ctx, NsN, TCG_COND_NE, riV) + +/* r0 = r1 ; jump address */ +#define fGEN_TCG_J4_jumpsetr(SHORTCODE) \ + do { \ + tcg_gen_mov_tl(RdV, RsV); \ + gen_jump(ctx, riV); \ + } while (0) + +#define fGEN_TCG_J2_pause(SHORTCODE) \ + do { \ + uiV = uiV; \ + tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC); \ + } while (0) + +/* r0 = asr(r1, r2):sat */ +#define fGEN_TCG_S2_asr_r_r_sat(SHORTCODE) \ + gen_asr_r_r_sat(RdV, RsV, RtV) + +/* r0 = asl(r1, r2):sat */ +#define fGEN_TCG_S2_asl_r_r_sat(SHORTCODE) \ + gen_asl_r_r_sat(RdV, RsV, RtV) + /* Floating point */ #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \ gen_helper_conv_sf2df(RddV, cpu_env, RsV) @@ -740,4 +1145,11 @@ RsV = RsV; \ } while (0) +#define fGEN_TCG_J2_trap0(SHORTCODE) \ + do { \ + uiV = uiV; \ + tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->pkt->pc); \ + TCGv excp = tcg_constant_tl(HEX_EXCP_TRAP0); \ + gen_helper_raise_exception(cpu_env, excp); \ + } while (0) #endif diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index 1fd9de95d560..7e8ba17ca2df 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,13 +164,27 @@ 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: f.write(" ctx_future_vreg_off(ctx, %s%sN," % \ (regtype, regid)) f.write(" 1, true);\n"); + if 'A_CONDEXEC' in hex_common.attribdict[tag]: + f.write(" if (!is_vreg_preloaded(ctx, %s)) {\n" % (regN)) + f.write(" intptr_t src_off =") + f.write(" offsetof(CPUHexagonState, VRegs[%s%sN]);\n"% \ + (regtype, regid)) + f.write(" tcg_gen_gvec_mov(MO_64, %s%sV_off,\n" % \ + (regtype, regid)) + f.write(" src_off,\n") + f.write(" sizeof(MMVector),\n") + f.write(" sizeof(MMVector));\n") + f.write(" }\n") + if (not hex_common.skip_qemu_helper(tag)): f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \ (regtype, regid)) @@ -379,9 +393,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 +560,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") @@ -562,11 +573,7 @@ def genptr_dst_write_opn(f,regtype, regid, tag): ## Generate the TCG code to call the helper ## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} ## We produce: -## static void generate_A2_add() -## CPUHexagonState *env -## DisasContext *ctx, -## Insn *insn, -## Packet *pkt) +## static void generate_A2_add(DisasContext *ctx) ## { ## TCGv RdV = tcg_temp_local_new(); ## const int RdN = insn->regno[0]; @@ -585,12 +592,11 @@ def genptr_dst_write_opn(f,regtype, regid, tag): ## is gen_helper_A2_add(RdV, cpu_env, RsV, RtV); ## def gen_tcg_func(f, tag, regs, imms): - f.write("static void generate_%s(\n" %tag) - f.write(" CPUHexagonState *env,\n") - f.write(" DisasContext *ctx,\n") - f.write(" Insn *insn,\n") - f.write(" Packet *pkt)\n") + f.write("static void generate_%s(DisasContext *ctx)\n" %tag) f.write('{\n') + + f.write(" Insn *insn __attribute__((unused)) = ctx->insn;\n") + if hex_common.need_ea(tag): gen_decl_ea_tcg(f, tag) i=0 ## Declare all the operands (regs and immediates) @@ -610,16 +616,45 @@ def gen_tcg_func(f, tag, regs, imms): if (hex_common.is_read(regid)): genptr_src_read_opn(f,regtype,regid,tag) - if ( hex_common.skip_qemu_helper(tag) ): + if hex_common.is_idef_parser_enabled(tag): + declared = [] + ## Handle registers + for regtype,regid,toss,numregs in regs: + if (hex_common.is_pair(regid) + or (hex_common.is_single(regid) + and hex_common.is_old_val(regtype, regid, tag))): + declared.append("%s%sV" % (regtype, regid)) + if regtype == "M": + declared.append("%s%sN" % (regtype, regid)) + elif hex_common.is_new_val(regtype, regid, tag): + declared.append("%s%sN" % (regtype,regid)) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + + ## Handle immediates + for immlett,bits,immshift in imms: + declared.append(hex_common.imm_name(immlett)) + + arguments = ", ".join(["ctx", "ctx->insn", "ctx->pkt"] + declared) + f.write(" emit_%s(%s);\n" % (tag, arguments)) + + elif ( hex_common.skip_qemu_helper(tag) ): f.write(" fGEN_TCG_%s(%s);\n" % (tag, hex_common.semdict[tag])) else: ## Generate the call to the helper for immlett,bits,immshift in imms: gen_helper_decl_imm(f,immlett) + if hex_common.need_pkt_has_multi_cof(tag): + f.write(" TCGv pkt_has_multi_cof = ") + f.write("tcg_constant_tl(ctx->pkt->pkt_has_multi_cof);\n") if hex_common.need_part1(tag): f.write(" TCGv part1 = tcg_constant_tl(insn->part1);\n") if hex_common.need_slot(tag): f.write(" TCGv slot = tcg_constant_tl(insn->slot);\n") + if hex_common.need_PC(tag): + f.write(" TCGv PC = tcg_constant_tl(ctx->pkt->pc);\n") + if hex_common.helper_needs_next_PC(tag): + f.write(" TCGv next_PC = tcg_constant_tl(ctx->next_PC);\n") f.write(" gen_helper_%s(" % (tag)) i=0 ## If there is a scalar result, it is the return type @@ -648,6 +683,10 @@ def gen_tcg_func(f, tag, regs, imms): for immlett,bits,immshift in imms: gen_helper_call_imm(f,immlett) + if hex_common.need_pkt_has_multi_cof(tag): + f.write(", pkt_has_multi_cof") + if hex_common.need_PC(tag): f.write(", PC") + if hex_common.helper_needs_next_PC(tag): f.write(", next_PC") if hex_common.need_slot(tag): f.write(", slot") if hex_common.need_part1(tag): f.write(", part1" ) f.write(");\n") @@ -677,12 +716,27 @@ def main(): hex_common.read_overrides_file(sys.argv[3]) hex_common.read_overrides_file(sys.argv[4]) hex_common.calculate_attribs() + ## Whether or not idef-parser is enabled is + ## determined by the number of arguments to + ## this script: + ## + ## 5 args. -> not enabled, + ## 6 args. -> idef-parser enabled. + ## + ## The 6:th arg. then holds a list of the successfully + ## parsed instructions. + is_idef_parser_enabled = len(sys.argv) > 6 + if is_idef_parser_enabled: + hex_common.read_idef_parser_enabled_file(sys.argv[5]) tagregs = hex_common.get_tagregs() tagimms = hex_common.get_tagimms() - with open(sys.argv[5], 'w') as f: + output_file = sys.argv[-1] + with open(output_file, 'w') as f: f.write("#ifndef HEXAGON_TCG_FUNCS_H\n") f.write("#define HEXAGON_TCG_FUNCS_H\n\n") + if is_idef_parser_enabled: + f.write("#include \"idef-generated-emitter.h.inc\"\n\n") for tag in hex_common.tags: ## Skip the priv instructions diff --git a/target/hexagon/gen_tcg_hvx.h b/target/hexagon/gen_tcg_hvx.h index cdcc9382bb26..083f4d92c6ff 100644 --- a/target/hexagon/gen_tcg_hvx.h +++ b/target/hexagon/gen_tcg_hvx.h @@ -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 @@ -697,7 +697,7 @@ static inline void assert_vhist_tmp(DisasContext *ctx) #define fGEN_TCG_NEWVAL_VEC_STORE(GET_EA, INC) \ do { \ GET_EA; \ - gen_vreg_store(ctx, insn, pkt, EA, OsN_off, insn->slot, true); \ + gen_vreg_store(ctx, EA, OsN_off, insn->slot, true); \ INC; \ } while (0) @@ -736,7 +736,7 @@ static inline void assert_vhist_tmp(DisasContext *ctx) PRED; \ tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, false_label); \ tcg_temp_free(LSB); \ - gen_vreg_store(ctx, insn, pkt, EA, SRCOFF, insn->slot, ALIGN); \ + gen_vreg_store(ctx, EA, SRCOFF, insn->slot, ALIGN); \ INC; \ tcg_gen_br(end_label); \ gen_set_label(false_label); \ diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index cd6af4bcebf3..90db99024ffb 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -29,8 +29,49 @@ #undef QEMU_GENERATE #include "gen_tcg.h" #include "gen_tcg_hvx.h" +#include "genptr.h" -static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot) +TCGv gen_read_reg(TCGv result, int num) +{ + tcg_gen_mov_tl(result, hex_gpr[num]); + return result; +} + +TCGv gen_read_preg(TCGv pred, uint8_t num) +{ + tcg_gen_mov_tl(pred, hex_pred[num]); + return pred; +} + +#define IMMUTABLE (~0) + +static const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS] = { + [HEX_REG_USR] = 0xc13000c0, + [HEX_REG_PC] = IMMUTABLE, + [HEX_REG_GP] = 0x3f, + [HEX_REG_UPCYCLELO] = IMMUTABLE, + [HEX_REG_UPCYCLEHI] = IMMUTABLE, + [HEX_REG_UTIMERLO] = IMMUTABLE, + [HEX_REG_UTIMERHI] = IMMUTABLE, +}; + +static inline void gen_masked_reg_write(TCGv new_val, TCGv cur_val, + target_ulong reg_mask) +{ + if (reg_mask) { + TCGv tmp = tcg_temp_new(); + + /* new_val = (new_val & ~reg_mask) | (cur_val & reg_mask) */ + tcg_gen_andi_tl(new_val, new_val, ~reg_mask); + tcg_gen_andi_tl(tmp, cur_val, reg_mask); + tcg_gen_or_tl(new_val, new_val, tmp); + + tcg_temp_free(tmp); + } +} + +static inline void gen_log_predicated_reg_write(int rnum, TCGv val, + uint32_t slot) { TCGv zero = tcg_constant_tl(0); TCGv slot_mask = tcg_temp_new(); @@ -53,8 +94,11 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot) tcg_temp_free(slot_mask); } -static inline void gen_log_reg_write(int rnum, TCGv val) +void gen_log_reg_write(int rnum, TCGv val) { + const target_ulong reg_mask = reg_immut_masks[rnum]; + + gen_masked_reg_write(val, hex_gpr[rnum], reg_mask); tcg_gen_mov_tl(hex_new_value[rnum], val); if (HEX_DEBUG) { /* Do this so HELPER(debug_commit_end) will know */ @@ -62,7 +106,8 @@ static inline void gen_log_reg_write(int rnum, TCGv val) } } -static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot) +static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, + uint32_t slot) { TCGv val32 = tcg_temp_new(); TCGv zero = tcg_constant_tl(0); @@ -99,22 +144,32 @@ static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot) static void gen_log_reg_write_pair(int rnum, TCGv_i64 val) { + const target_ulong reg_mask_low = reg_immut_masks[rnum]; + const target_ulong reg_mask_high = reg_immut_masks[rnum + 1]; + TCGv val32 = tcg_temp_new(); + /* Low word */ - tcg_gen_extrl_i64_i32(hex_new_value[rnum], val); + tcg_gen_extrl_i64_i32(val32, val); + gen_masked_reg_write(val32, hex_gpr[rnum], reg_mask_low); + tcg_gen_mov_tl(hex_new_value[rnum], val32); if (HEX_DEBUG) { /* Do this so HELPER(debug_commit_end) will know */ tcg_gen_movi_tl(hex_reg_written[rnum], 1); } /* High word */ - tcg_gen_extrh_i64_i32(hex_new_value[rnum + 1], val); + tcg_gen_extrh_i64_i32(val32, val); + gen_masked_reg_write(val32, hex_gpr[rnum + 1], reg_mask_high); + tcg_gen_mov_tl(hex_new_value[rnum + 1], val32); if (HEX_DEBUG) { /* Do this so HELPER(debug_commit_end) will know */ tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1); } + + tcg_temp_free(val32); } -static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) +void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) { TCGv base_val = tcg_temp_new(); @@ -148,7 +203,7 @@ static inline void gen_read_p3_0(TCGv control_reg) /* * Certain control registers require special handling on read - * HEX_REG_P3_0 aliased to the predicate registers + * HEX_REG_P3_0_ALIASED aliased to the predicate registers * -> concat the 4 predicate registers together * HEX_REG_PC actual value stored in DisasContext * -> assign from ctx->base.pc_next @@ -158,7 +213,7 @@ static inline void gen_read_p3_0(TCGv control_reg) static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num, TCGv dest) { - if (reg_num == HEX_REG_P3_0) { + if (reg_num == HEX_REG_P3_0_ALIASED) { gen_read_p3_0(dest); } else if (reg_num == HEX_REG_PC) { tcg_gen_movi_tl(dest, ctx->base.pc_next); @@ -179,7 +234,7 @@ static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num, static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num, TCGv_i64 dest) { - if (reg_num == HEX_REG_P3_0) { + if (reg_num == HEX_REG_P3_0_ALIASED) { TCGv p3_0 = tcg_temp_new(); gen_read_p3_0(p3_0); tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]); @@ -223,7 +278,7 @@ static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg) /* * Certain control registers require special handling on write - * HEX_REG_P3_0 aliased to the predicate registers + * HEX_REG_P3_0_ALIASED aliased to the predicate registers * -> break the value across 4 predicate registers * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext * -> clear the changes @@ -231,7 +286,7 @@ static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg) static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num, TCGv val) { - if (reg_num == HEX_REG_P3_0) { + if (reg_num == HEX_REG_P3_0_ALIASED) { gen_write_p3_0(ctx, val); } else { gen_log_reg_write(reg_num, val); @@ -251,7 +306,7 @@ static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num, static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num, TCGv_i64 val) { - if (reg_num == HEX_REG_P3_0) { + if (reg_num == HEX_REG_P3_0_ALIASED) { TCGv val32 = tcg_temp_new(); tcg_gen_extrl_i64_i32(val32, val); gen_write_p3_0(ctx, val32); @@ -272,7 +327,7 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num, } } -static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign) +TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign) { if (sign) { tcg_gen_sextract_tl(result, src, N * 8, 8); @@ -282,7 +337,7 @@ static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign) return result; } -static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) +TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) { TCGv_i64 res64 = tcg_temp_new_i64(); if (sign) { @@ -296,7 +351,7 @@ static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) return result; } -static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) +TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) { if (sign) { tcg_gen_sextract_tl(result, src, N * 16, 16); @@ -306,12 +361,12 @@ static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) return result; } -static inline void gen_set_half(int N, TCGv result, TCGv src) +void gen_set_half(int N, TCGv result, TCGv src) { tcg_gen_deposit_tl(result, result, src, N * 16, 16); } -static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src) +void gen_set_half_i64(int N, TCGv_i64 result, TCGv src) { TCGv_i64 src64 = tcg_temp_new_i64(); tcg_gen_extu_i32_i64(src64, src); @@ -319,7 +374,7 @@ static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src) tcg_temp_free_i64(src64); } -static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) +void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) { TCGv_i64 src64 = tcg_temp_new_i64(); tcg_gen_extu_i32_i64(src64, src); @@ -394,72 +449,60 @@ static inline void gen_store_conditional8(DisasContext *ctx, tcg_gen_movi_tl(hex_llsc_addr, ~0); } -static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot) +void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot) { tcg_gen_mov_tl(hex_store_addr[slot], vaddr); tcg_gen_movi_tl(hex_store_width[slot], width); 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) +void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t 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) +void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t 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) +void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t 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) +void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t 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) +void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t 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) +void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t 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) +void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t 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) +void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t 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) +TCGv gen_8bitsof(TCGv result, TCGv value) { TCGv zero = tcg_constant_tl(0); TCGv ones = tcg_constant_tl(0xff); @@ -468,6 +511,392 @@ static TCGv gen_8bitsof(TCGv result, TCGv value) return result; } +static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr, + TCGCond cond, TCGv pred) +{ + TCGLabel *pred_false = NULL; + if (cond != TCG_COND_ALWAYS) { + pred_false = gen_new_label(); + tcg_gen_brcondi_tl(cond, pred, 0, pred_false); + } + + if (ctx->pkt->pkt_has_multi_cof) { + /* If there are multiple branches in a packet, ignore the second one */ + tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC], + hex_branch_taken, tcg_constant_tl(0), + hex_gpr[HEX_REG_PC], addr); + tcg_gen_movi_tl(hex_branch_taken, 1); + } else { + tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr); + } + + if (cond != TCG_COND_ALWAYS) { + gen_set_label(pred_false); + } +} + +static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off, + TCGCond cond, TCGv pred) +{ + target_ulong dest = ctx->pkt->pc + pc_off; + if (ctx->pkt->pkt_has_multi_cof) { + gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred); + } else { + /* Defer this jump to the end of the TB */ + ctx->branch_cond = TCG_COND_ALWAYS; + if (pred != NULL) { + ctx->branch_cond = cond; + tcg_gen_mov_tl(hex_branch_taken, pred); + } + ctx->branch_dest = dest; + } +} + +void gen_set_usr_field(int field, TCGv val) +{ + tcg_gen_deposit_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR], + val, + reg_field_info[field].offset, + reg_field_info[field].width); +} + +void gen_set_usr_fieldi(int field, int x) +{ + if (reg_field_info[field].width == 1) { + target_ulong bit = 1 << reg_field_info[field].offset; + if ((x & 1) == 1) { + tcg_gen_ori_tl(hex_new_value[HEX_REG_USR], + hex_new_value[HEX_REG_USR], + bit); + } else { + tcg_gen_andi_tl(hex_new_value[HEX_REG_USR], + hex_new_value[HEX_REG_USR], + ~bit); + } + } else { + TCGv val = tcg_constant_tl(x); + gen_set_usr_field(field, val); + } +} + +static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2) +{ + TCGv one = tcg_constant_tl(0xff); + TCGv zero = tcg_constant_tl(0); + + tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero); +} + +static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc, + TCGCond cond, TCGv pred) +{ + gen_write_new_pc_addr(ctx, dst_pc, cond, pred); +} + +static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred, + int pc_off) +{ + gen_write_new_pc_pcrel(ctx, pc_off, cond, pred); +} + +static void gen_cmpnd_cmp_jmp(DisasContext *ctx, + int pnum, TCGCond cond1, TCGv arg1, TCGv arg2, + TCGCond cond2, int pc_off) +{ + if (ctx->insn->part1) { + TCGv pred = tcg_temp_new(); + gen_compare(cond1, pred, arg1, arg2); + gen_log_pred_write(ctx, pnum, pred); + tcg_temp_free(pred); + } else { + TCGv pred = tcg_temp_new(); + tcg_gen_mov_tl(pred, hex_new_pred_value[pnum]); + gen_cond_jump(ctx, cond2, pred, pc_off); + tcg_temp_free(pred); + } +} + +static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx, + int pnum, TCGCond cond, TCGv arg1, TCGv arg2, + int pc_off) +{ + gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off); +} + +static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx, + int pnum, TCGCond cond, TCGv arg1, TCGv arg2, + int pc_off) +{ + gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off); +} + +static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx, + int pnum, TCGCond cond, TCGv arg1, int arg2, + int pc_off) +{ + TCGv tmp = tcg_constant_tl(arg2); + gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off); +} + +static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx, + int pnum, TCGCond cond, TCGv arg1, int arg2, + int pc_off) +{ + TCGv tmp = tcg_constant_tl(arg2); + gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off); +} + +static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond, + TCGv arg, int pc_off) +{ + gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off); +} + +static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond, + TCGv arg, int pc_off) +{ + gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off); +} + +static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx, + int pnum, TCGv arg, TCGCond cond, int pc_off) +{ + if (ctx->insn->part1) { + TCGv pred = tcg_temp_new(); + tcg_gen_andi_tl(pred, arg, 1); + gen_8bitsof(pred, pred); + gen_log_pred_write(ctx, pnum, pred); + tcg_temp_free(pred); + } else { + TCGv pred = tcg_temp_new(); + tcg_gen_mov_tl(pred, hex_new_pred_value[pnum]); + gen_cond_jump(ctx, cond, pred, pc_off); + tcg_temp_free(pred); + } +} + +static void gen_testbit0_jumpnv(DisasContext *ctx, + TCGv arg, TCGCond cond, int pc_off) +{ + TCGv pred = tcg_temp_new(); + tcg_gen_andi_tl(pred, arg, 1); + gen_cond_jump(ctx, cond, pred, pc_off); + tcg_temp_free(pred); +} + +static void gen_jump(DisasContext *ctx, int pc_off) +{ + gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); +} + +static void gen_jumpr(DisasContext *ctx, TCGv new_pc) +{ + gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); +} + +static void gen_call(DisasContext *ctx, int pc_off) +{ + TCGv next_PC = + tcg_constant_tl(ctx->pkt->pc + ctx->pkt->encod_pkt_size_in_bytes); + gen_log_reg_write(HEX_REG_LR, next_PC); + gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); +} + +static void gen_cond_call(DisasContext *ctx, TCGv pred, + TCGCond cond, int pc_off) +{ + TCGv next_PC; + TCGv lsb = tcg_temp_local_new(); + TCGLabel *skip = gen_new_label(); + tcg_gen_andi_tl(lsb, pred, 1); + gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb); + tcg_gen_brcondi_tl(cond, lsb, 0, skip); + tcg_temp_free(lsb); + next_PC = + tcg_constant_tl(ctx->pkt->pc + ctx->pkt->encod_pkt_size_in_bytes); + gen_log_reg_write(HEX_REG_LR, next_PC); + gen_set_label(skip); +} + +static void gen_endloop0(DisasContext *ctx) +{ + TCGv lpcfg = tcg_temp_local_new(); + + GET_USR_FIELD(USR_LPCFG, lpcfg); + + /* + * if (lpcfg == 1) { + * hex_new_pred_value[3] = 0xff; + * hex_pred_written |= 1 << 3; + * } + */ + TCGLabel *label1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1); + { + tcg_gen_movi_tl(hex_new_pred_value[3], 0xff); + tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << 3); + } + gen_set_label(label1); + + /* + * if (lpcfg) { + * SET_USR_FIELD(USR_LPCFG, lpcfg - 1); + * } + */ + TCGLabel *label2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2); + { + tcg_gen_subi_tl(lpcfg, lpcfg, 1); + SET_USR_FIELD(USR_LPCFG, lpcfg); + } + gen_set_label(label2); + + /* + * If we're in a tight loop, we'll do this at the end of the TB to take + * advantage of direct block chaining. + */ + if (!ctx->is_tight_loop) { + /* + * if (hex_gpr[HEX_REG_LC0] > 1) { + * PC = hex_gpr[HEX_REG_SA0]; + * hex_new_value[HEX_REG_LC0] = hex_gpr[HEX_REG_LC0] - 1; + * } + */ + TCGLabel *label3 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); + { + gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); + tcg_gen_subi_tl(hex_new_value[HEX_REG_LC0], + hex_gpr[HEX_REG_LC0], 1); + } + gen_set_label(label3); + } + + tcg_temp_free(lpcfg); +} + +static void gen_cmp_jumpnv(DisasContext *ctx, + TCGCond cond, TCGv val, TCGv src, int pc_off) +{ + TCGv pred = tcg_temp_new(); + tcg_gen_setcond_tl(cond, pred, val, src); + gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); + tcg_temp_free(pred); +} + +static void gen_cmpi_jumpnv(DisasContext *ctx, + TCGCond cond, TCGv val, int src, int pc_off) +{ + TCGv pred = tcg_temp_new(); + tcg_gen_setcondi_tl(cond, pred, val, src); + gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); + tcg_temp_free(pred); +} + +/* Shift left with saturation */ +static void gen_shl_sat(TCGv dst, TCGv src, TCGv shift_amt) +{ + TCGv sh32 = tcg_temp_new(); + TCGv dst_sar = tcg_temp_new(); + TCGv ovf = tcg_temp_new(); + TCGv satval = tcg_temp_new(); + TCGv min = tcg_constant_tl(0x80000000); + TCGv max = tcg_constant_tl(0x7fffffff); + + /* + * Possible values for shift_amt are 0 .. 64 + * We need special handling for values above 31 + * + * sh32 = shift & 31; + * dst = sh32 == shift ? src : 0; + * dst <<= sh32; + * dst_sar = dst >> sh32; + * satval = src < 0 ? min : max; + * if (dst_asr != src) { + * usr.OVF |= 1; + * dst = satval; + * } + */ + + tcg_gen_andi_tl(sh32, shift_amt, 31); + tcg_gen_movcond_tl(TCG_COND_EQ, dst, sh32, shift_amt, + src, tcg_constant_tl(0)); + tcg_gen_shl_tl(dst, dst, sh32); + tcg_gen_sar_tl(dst_sar, dst, sh32); + tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max); + + tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src); + tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset); + tcg_gen_or_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR], ovf); + + tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, dst, satval); + + tcg_temp_free(sh32); + tcg_temp_free(dst_sar); + tcg_temp_free(ovf); + tcg_temp_free(satval); +} + +static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt) +{ + /* + * Shift arithmetic right + * Robust when shift_amt is >31 bits + */ + TCGv tmp = tcg_temp_new(); + tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31)); + tcg_gen_sar_tl(dst, src, tmp); + tcg_temp_free(tmp); +} + +/* Bidirectional shift right with saturation */ +static void gen_asr_r_r_sat(TCGv RdV, TCGv RsV, TCGv RtV) +{ + TCGv shift_amt = tcg_temp_local_new(); + TCGLabel *positive = gen_new_label(); + TCGLabel *done = gen_new_label(); + + tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); + tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); + + /* Negative shift amount => shift left */ + tcg_gen_neg_tl(shift_amt, shift_amt); + gen_shl_sat(RdV, RsV, shift_amt); + tcg_gen_br(done); + + gen_set_label(positive); + /* Positive shift amount => shift right */ + gen_sar(RdV, RsV, shift_amt); + + gen_set_label(done); + + tcg_temp_free(shift_amt); +} + +/* Bidirectional shift left with saturation */ +static void gen_asl_r_r_sat(TCGv RdV, TCGv RsV, TCGv RtV) +{ + TCGv shift_amt = tcg_temp_local_new(); + TCGLabel *positive = gen_new_label(); + TCGLabel *done = gen_new_label(); + + tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); + tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); + + /* Negative shift amount => shift right */ + tcg_gen_neg_tl(shift_amt, shift_amt); + gen_sar(RdV, RsV, shift_amt); + tcg_gen_br(done); + + gen_set_label(positive); + /* Positive shift amount => shift left */ + gen_shl_sat(RdV, RsV, shift_amt); + + gen_set_label(done); + + tcg_temp_free(shift_amt); +} + static intptr_t vreg_src_off(DisasContext *ctx, int num) { intptr_t offset = offsetof(CPUHexagonState, VRegs[num]); @@ -563,13 +992,13 @@ static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, tcg_temp_free_i64(tmp); } -static void gen_vreg_store(DisasContext *ctx, Insn *insn, Packet *pkt, - TCGv EA, intptr_t srcoff, int slot, bool aligned) +static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, + int slot, bool aligned) { intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); - if (is_gather_store_insn(insn, pkt)) { + if (is_gather_store_insn(ctx)) { TCGv sl = tcg_constant_tl(slot); gen_helper_gather_store(cpu_env, EA, sl); return; @@ -638,5 +1067,148 @@ static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) tcg_temp_free_i64(mask); } +void probe_noshuf_load(TCGv va, int s, int mi) +{ + TCGv size = tcg_constant_tl(s); + TCGv mem_idx = tcg_constant_tl(mi); + gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx); +} + +/* + * Note: Since this function might branch, `val` is + * required to be a `tcg_temp_local`. + */ +void gen_set_usr_field_if(int field, TCGv val) +{ + /* Sets the USR field if `val` is non-zero */ + if (reg_field_info[field].width == 1) { + TCGv tmp = tcg_temp_new(); + tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width); + tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset); + tcg_gen_or_tl(hex_new_value[HEX_REG_USR], + hex_new_value[HEX_REG_USR], + tmp); + tcg_temp_free(tmp); + } else { + TCGLabel *skip_label = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label); + gen_set_usr_field(field, val); + gen_set_label(skip_label); + } +} + +void gen_sat_i32(TCGv dest, TCGv source, int width) +{ + TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1); + TCGv min_val = tcg_constant_tl(-(1 << (width - 1))); + tcg_gen_smin_tl(dest, source, max_val); + tcg_gen_smax_tl(dest, dest, min_val); +} + +void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) +{ + gen_sat_i32(dest, source, width); + tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest); +} + +void gen_satu_i32(TCGv dest, TCGv source, int width) +{ + TCGv max_val = tcg_constant_tl((1 << width) - 1); + TCGv zero = tcg_constant_tl(0); + tcg_gen_movcond_tl(TCG_COND_GTU, dest, source, max_val, max_val, source); + tcg_gen_movcond_tl(TCG_COND_LT, dest, source, zero, zero, dest); +} + +void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) +{ + gen_satu_i32(dest, source, width); + tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest); +} + +void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) +{ + TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL); + TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1))); + tcg_gen_smin_i64(dest, source, max_val); + tcg_gen_smax_i64(dest, dest, min_val); +} + +void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) +{ + TCGv_i64 ovfl_64; + gen_sat_i64(dest, source, width); + ovfl_64 = tcg_temp_new_i64(); + tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source); + tcg_gen_trunc_i64_tl(ovfl, ovfl_64); + tcg_temp_free_i64(ovfl_64); +} + +void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) +{ + TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL); + TCGv_i64 zero = tcg_constant_i64(0); + tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source); + tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest); +} + +void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) +{ + TCGv_i64 ovfl_64; + gen_satu_i64(dest, source, width); + ovfl_64 = tcg_temp_new_i64(); + tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source); + tcg_gen_trunc_i64_tl(ovfl, ovfl_64); + tcg_temp_free_i64(ovfl_64); +} + +/* Implements the fADDSAT64 macro in TCG */ +void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 sum = tcg_temp_local_new_i64(); + TCGv_i64 xor = tcg_temp_new_i64(); + TCGv_i64 cond1 = tcg_temp_new_i64(); + TCGv_i64 cond2 = tcg_temp_local_new_i64(); + TCGv_i64 cond3 = tcg_temp_new_i64(); + TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL); + TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL); + TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL); + TCGv_i64 zero = tcg_constant_i64(0); + TCGLabel *no_ovfl_label = gen_new_label(); + TCGLabel *ovfl_label = gen_new_label(); + TCGLabel *ret_label = gen_new_label(); + + tcg_gen_add_i64(sum, a, b); + tcg_gen_xor_i64(xor, a, b); + + /* if (xor & mask) */ + tcg_gen_and_i64(cond1, xor, mask); + tcg_temp_free_i64(xor); + tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label); + tcg_temp_free_i64(cond1); + + /* else if ((a ^ sum) & mask) */ + tcg_gen_xor_i64(cond2, a, sum); + tcg_gen_and_i64(cond2, cond2, mask); + tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label); + tcg_temp_free_i64(cond2); + /* fallthrough to no_ovfl_label branch */ + + /* if branch */ + gen_set_label(no_ovfl_label); + tcg_gen_mov_i64(ret, sum); + tcg_gen_br(ret_label); + + /* else if branch */ + gen_set_label(ovfl_label); + tcg_gen_and_i64(cond3, sum, mask); + tcg_temp_free_i64(mask); + tcg_temp_free_i64(sum); + tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg); + tcg_temp_free_i64(cond3); + SET_USR_FIELD(USR_OVF, 1); + + gen_set_label(ret_label); +} + #include "tcg_funcs_generated.c.inc" #include "tcg_func_table_generated.c.inc" diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h index c158005d2a17..591b05969868 100644 --- a/target/hexagon/genptr.h +++ b/target/hexagon/genptr.h @@ -19,7 +19,43 @@ #define HEXAGON_GENPTR_H #include "insn.h" +#include "tcg/tcg.h" +#include "translate.h" extern const SemanticInsn opcode_genptr[]; +void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot); +void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot); +void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot); +void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot); +void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t slot); +void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot); +void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot); +void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot); +void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot); +TCGv gen_read_reg(TCGv result, int num); +TCGv gen_read_preg(TCGv pred, uint8_t num); +void gen_log_reg_write(int rnum, TCGv val); +void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val); +void gen_set_usr_field(int field, TCGv val); +void gen_set_usr_fieldi(int field, int x); +void gen_set_usr_field_if(int field, TCGv val); +void gen_sat_i32(TCGv dest, TCGv source, int width); +void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width); +void gen_satu_i32(TCGv dest, TCGv source, int width); +void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width); +void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width); +void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width); +void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width); +void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width); +void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b); +TCGv gen_8bitsof(TCGv result, TCGv value); +void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src); +TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign); +TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign); +TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign); +void gen_set_half(int N, TCGv result, TCGv src); +void gen_set_half_i64(int N, TCGv_i64 result, TCGv src); +void probe_noshuf_load(TCGv va, int s, int mi); + #endif diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index c89aa4ed4d6d..368f0b57085b 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -104,6 +104,7 @@ DEF_HELPER_1(vwhist128q, void, env) DEF_HELPER_2(vwhist128m, void, env, s32) DEF_HELPER_2(vwhist128qm, void, env, s32) +DEF_HELPER_4(probe_noshuf_load, void, env, i32, int, int) DEF_HELPER_2(probe_pkt_scalar_store_s0, void, env, int) DEF_HELPER_2(probe_hvx_stores, void, env, int) DEF_HELPER_3(probe_pkt_scalar_hvx_stores, void, env, int, int) diff --git a/target/hexagon/hex_arch_types.h b/target/hexagon/hex_arch_types.h index 78ad607f5385..885f68f76054 100644 --- a/target/hexagon/hex_arch_types.h +++ b/target/hexagon/hex_arch_types.h @@ -15,8 +15,8 @@ * along with this program; if not, see . */ -#ifndef HEXAGON_ARCH_TYPES_H -#define HEXAGON_ARCH_TYPES_H +#ifndef HEXAGON_HEX_ARCH_TYPES_H +#define HEXAGON_HEX_ARCH_TYPES_H #include "qemu/osdep.h" #include "mmvec/mmvec.h" diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index c81aca8d2af5..a29f61bb4f08 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 @@ -28,6 +28,7 @@ attribinfo = {} # Register information and misc tags = [] # list of all tags overrides = {} # tags with helper overrides +idef_parser_enabled = {} # tags enabled for idef-parser # We should do this as a hash for performance, # but to keep order let's keep it as a list. @@ -66,6 +67,19 @@ def add_qemu_macro_attrib(name, attrib): macros[name].attribs.add(attrib) immextre = re.compile(r'f(MUST_)?IMMEXT[(]([UuSsRr])') + +def is_cond_jump(tag): + if tag == 'J2_rte': + return False + if ('A_HWLOOP0_END' in attribdict[tag] or + 'A_HWLOOP1_END' in attribdict[tag]): + return False + return \ + re.compile(r"(if.*fBRANCH)|(if.*fJUMPR)").search(semdict[tag]) != None + +def is_cond_call(tag): + return re.compile(r"(if.*fCALL)").search(semdict[tag]) != None + def calculate_attribs(): add_qemu_macro_attrib('fREAD_PC', 'A_IMPLICIT_READS_PC') add_qemu_macro_attrib('fTRAP', 'A_IMPLICIT_READS_PC') @@ -75,6 +89,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()) @@ -95,6 +110,11 @@ def calculate_attribs(): for regtype, regid, toss, numregs in regs: if regtype == "P" and is_written(regid): attribdict[tag].add('A_WRITES_PRED_REG') + # Mark conditional jumps and calls + # Not all instructions are properly marked with A_CONDEXEC + for tag in tags: + if is_cond_jump(tag) or is_cond_call(tag): + attribdict[tag].add('A_CONDEXEC') def SEMANTICS(tag, beh, sem): #print tag,beh,sem @@ -193,7 +213,8 @@ def is_new_val(regtype, regid, tag): return regtype+regid+'N' in semdict[tag] def need_slot(tag): - if ('A_CONDEXEC' in attribdict[tag] or + if (('A_CONDEXEC' in attribdict[tag] and + 'A_JUMP' not in attribdict[tag]) or 'A_STORE' in attribdict[tag] or 'A_LOAD' in attribdict[tag]): return 1 @@ -206,6 +227,15 @@ def need_part1(tag): def need_ea(tag): return re.compile(r"\bEA\b").search(semdict[tag]) +def need_PC(tag): + return 'A_IMPLICIT_READS_PC' in attribdict[tag] + +def helper_needs_next_PC(tag): + return 'A_CALL' in attribdict[tag] + +def need_pkt_has_multi_cof(tag): + return 'A_COF' in attribdict[tag] + def skip_qemu_helper(tag): return tag in overrides.keys() @@ -216,6 +246,9 @@ def is_tmp_result(tag): def is_new_result(tag): return ('A_CVI_NEW' in attribdict[tag]) +def is_idef_parser_enabled(tag): + return tag in idef_parser_enabled + def imm_name(immlett): return "%siV" % immlett @@ -247,3 +280,9 @@ def read_overrides_file(name): continue tag = overridere.findall(line)[0] overrides[tag] = True + +def read_idef_parser_enabled_file(name): + global idef_parser_enabled + with open(name, "r") as idef_parser_enabled_file: + lines = idef_parser_enabled_file.read().strip().split("\n") + idef_parser_enabled = set(lines) diff --git a/target/hexagon/hex_regs.h b/target/hexagon/hex_regs.h index e1b3149b074e..bddfc28021c6 100644 --- a/target/hexagon/hex_regs.h +++ b/target/hexagon/hex_regs.h @@ -15,8 +15,8 @@ * along with this program; if not, see . */ -#ifndef HEXAGON_REGS_H -#define HEXAGON_REGS_H +#ifndef HEXAGON_HEX_REGS_H +#define HEXAGON_HEX_REGS_H enum { HEX_REG_R00 = 0, @@ -58,7 +58,7 @@ enum { HEX_REG_LC0 = 33, HEX_REG_SA1 = 34, HEX_REG_LC1 = 35, - HEX_REG_P3_0 = 36, + HEX_REG_P3_0_ALIASED = 36, HEX_REG_M0 = 38, HEX_REG_M1 = 39, HEX_REG_USR = 40, diff --git a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-parser/README.rst new file mode 100644 index 000000000000..ff6d14150aec --- /dev/null +++ b/target/hexagon/idef-parser/README.rst @@ -0,0 +1,722 @@ +Hexagon ISA instruction definitions to tinycode generator compiler +------------------------------------------------------------------ + +idef-parser is a small compiler able to translate the Hexagon ISA description +language into tinycode generator code, that can be easily integrated into QEMU. + +Compilation Example +------------------- + +To better understand the scope of the idef-parser, we'll explore an applicative +example. Let's start by one of the simplest Hexagon instruction: the ``add``. + +The ISA description language represents the ``add`` instruction as +follows: + +.. code:: c + + A2_add(RdV, in RsV, in RtV) { + { RdV=RsV+RtV;} + } + +idef-parser will compile the above code into the following code: + +.. code:: c + + /* A2_add */ + void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV, + TCGv_i32 RsV, TCGv_i32 RtV) + /* { RdV=RsV+RtV;} */ + { + TCGv_i32 tmp_0 = tcg_temp_new_i32(); + tcg_gen_add_i32(tmp_0, RsV, RtV); + tcg_gen_mov_i32(RdV, tmp_0); + tcg_temp_free_i32(tmp_0); + } + +The output of the compilation process will be a function, containing the +tinycode generator code, implementing the correct semantics. That function will +not access any global variable, because all the accessed data structures will be +passed explicitly as function parameters. Among the passed parameters we will +have TCGv (tinycode variables) representing the input and output registers of +the architecture, integers representing the immediates that come from the code, +and other data structures which hold information about the disassemblation +context (``DisasContext`` struct). + +Let's begin by describing the input code. The ``add`` instruction is associated +with a unique identifier, in this case ``A2_add``, which allows to distinguish +variants of the same instruction, and expresses the class to which the +instruction belongs, in this case ``A2`` corresponds to the Hexagon +``ALU32/ALU`` instruction subclass. + +After the instruction identifier, we have a series of parameters that represents +TCG variables that will be passed to the generated function. Parameters marked +with ``in`` are already initialized, while the others are output parameters. + +We will leverage this information to infer several information: + +- Fill in the output function signature with the correct TCGv registers +- Fill in the output function signature with the immediate integers +- Keep track of which registers, among the declared one, have been + initialized + +Let's now observe the actual instruction description code, in this case: + +.. code:: c + + { RdV=RsV+RtV;} + +This code is composed by a subset of the C syntax, and is the result of the +application of some macro definitions contained in the ``macros.h`` file. + +This file is used to reduce the complexity of the input language where complex +variants of similar constructs can be mapped to a unique primitive, so that the +idef-parser has to handle a lower number of computation primitives. + +As you may notice, the description code modifies the registers which have been +declared by the declaration statements. In this case all the three registers +will be declared, ``RsV`` and ``RtV`` will also be read and ``RdV`` will be +written. + +Now let's have a quick look at the generated code, line by line. + +:: + + TCGv_i32 tmp_0 = tcg_temp_new_i32(); + +This code starts by declaring a temporary TCGv to hold the result from the sum +operation. + +:: + + tcg_gen_add_i32(tmp_0, RsV, RtV); + +Then, we are generating the sum tinycode operator between the selected +registers, storing the result in the just declared temporary. + +:: + + tcg_gen_mov_i32(RdV, tmp_0); + +The result of the addition is now stored in the temporary, we move it into the +correct destination register. This code may seem inefficient, but QEMU will +perform some optimizations on the tinycode, reducing the unnecessary copy. + +:: + + tcg_temp_free_i32(tmp_0); + +Finally, we free the temporary we used to hold the addition result. + +Parser Input +------------ + +Before moving on to the structure of idef-parser itself, let us spend some words +on its' input. There are two preprocessing steps applied to the generated +instruction semantics in ``semantics_generated.pyinc`` that we need to consider. +Firstly, + +:: + + gen_idef_parser_funcs.py + +which takes instruction semantics in ``semantics_generated.pyinc`` to C-like +pseudo code, output into ``idef_parser_input.h.inc``. For instance, the +``J2_jumpr`` instruction which jumps to an address stored in a register +argument. This is instruction is defined as + +:: + + SEMANTICS( \ + "J2_jumpr", \ + "jumpr Rs32", \ + """{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);}""" \ + ) + +in ``semantics_generated.pyinc``. Running ``gen_idef_parser_funcs.py`` +we obtain the pseudo code + +:: + + J2_jumpr(in RsV) { + {fJUMPR(RsN,RsV,COF_TYPE_JUMPR);} + } + +with macros such as ``fJUMPR`` intact. + +The second step is to expand macros into a form suitable for our parser. +These macros are defined in ``idef-parser/macros.inc`` and the step is +carried out by the ``prepare`` script which runs the C preprocessor on +``idef_parser_input.h.inc`` to produce +``idef_parser_input.preprocessed.h.inc``. + +To finish the above example, after preprocessing ``J2_jumpr`` we obtain + +:: + + J2_jumpr(in RsV) { + {(PC = RsV);} + } + +where ``fJUMPR(RsN,RsV,COF_TYPE_JUMPR);`` was expanded to ``(PC = RsV)``, +signifying a write to the Program Counter ``PC``. Note, that ``PC`` in +this expression is not a variable in the strict C sense since it is not +declared anywhere, but rather a symbol which is easy to match in +idef-parser later on. + +Parser Structure +---------------- + +The idef-parser is built using the ``flex`` and ``bison``. + +``flex`` is used to split the input string into tokens, each described using a +regular expression. The token description is contained in the +``idef-parser.lex`` source file. The flex-generated scanner takes care also to +extract from the input text other meaningful information, e.g., the numerical +value in case of an immediate constant, and decorates the token with the +extracted information. + +``bison`` is used to generate the actual parser, starting from the parsing +description contained in the ``idef-parser.y`` file. The generated parser +executes the ``main`` function at the end of the ``idef-parser.y`` file, which +opens input and output files, creates the parsing context, and eventually calls +the ``yyparse()`` function, which starts the execution of the LALR(1) parser +(see `Wikipedia `__ for more +information about LALR parsing techniques). The LALR(1) parser, whenever it has +to shift a token, calls the ``yylex()`` function, which is defined by the +flex-generated code, and reads the input file returning the next scanned token. + +The tokens are mapped on the source language grammar, defined in the +``idef-parser.y`` file to build a unique syntactic tree, according to the +specified operator precedences and associativity rules. + +The grammar describes the whole file which contains the Hexagon instruction +descriptions, therefore it starts from the ``input`` nonterminal, which is a +list of instructions, each instruction is represented by the following grammar +rule, representing the structure of the input file shown above: + +:: + + instruction : INAME arguments code + | error + + arguments : '(' ')' + | '(' argument_list ')'; + + argument_list : argument_decl ',' argument_list + | argument_decl + + argument_decl : REG + | PRED + | IN REG + | IN PRED + | IMM + | var + ; + + code : '{' statements '}' + + statements : statements statement + | statement + + statement : control_statement + | var_decl ';' + | rvalue ';' + | code_block + | ';' + + code_block : '{' statements '}' + | '{' '}' + +With this initial portion of the grammar we are defining the instruction, its' +arguments, and its' statements. Each argument is defined by the +``argument_decl`` rule, and can be either + +:: + + Description Example + ---------------------------------------- + output register RsV + output predicate register P0 + input register in RsV + input predicate register in P0 + immediate value 1234 + local variable EA + +Note, the only local variable allowed to be used as an argument is the effective +address ``EA``. Similarly, each statement can be a ``control_statement``, a +variable declaration such as ``int a;``, a code block, which is just a +bracket-enclosed list of statements, a ``';'``, which is a ``nop`` instruction, +and an ``rvalue ';'``. + +Expressions +~~~~~~~~~~~ + +Allowed in the input code are C language expressions with a few exceptions +to simplify parsing. For instance, variable names such as ``RdV``, ``RssV``, +``PdV``, ``CsV``, and other idiomatic register names from Hexagon, are +reserved specifically for register arguments. These arguments then map to +``TCGv_i32`` or ``TCGv_i64`` depending on the register size. Similarly, ``UiV``, +``riV``, etc. refer to immediate arguments and will map to C integers. + +Also, as mentioned earlier, the names ``PC``, ``SP``, ``FP``, etc. are used to +refer to Hexagon registers such as the program counter, stack pointer, and frame +pointer seen here. Writes to these registers then correspond to assignments +``PC = ...``, and reads correspond to uses of the variable ``PC``. + +Moreover, another example of one such exception is the selective expansion of +macros present in ``macros.h``. As an example, consider the ``fABS`` macro which +in plain C is defined as + +:: + + #define fABS(A) (((A) < 0) ? (-(A)) : (A)) + +and returns the absolute value of the argument ``A``. This macro is not included +in ``idef-parser/macros.inc`` and as such is not expanded and kept as a "call" +``fABS(...)``. Reason being, that ``fABS`` is easier to match and map to +``tcg_gen_abs_``, compared to the full ternary expression above. Loads of +macros in ``macros.h`` are kept unexpanded to aid in parsing, as seen in the +example above, for more information see ``idef-parser/idef-parser.lex``. + +Finally, in mapping these input expressions to tinycode generators, idef-parser +tries to perform as much as possible in plain C. Such as, performing binary +operations in C instead of tinycode generators, thus effectively constant +folding the expression. + +Variables and Variable Declarations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similarly to C, variables in the input code must be explicitly declared, such as +``int var1;`` which declares an uninitialized variable ``var1``. Initialization +``int var2 = 0;`` is also allowed and behaves as expected. In tinycode +generators the previous declarations are mapped to + +:: + + int var1; -> TCGv_i32 var1 = tcg_temp_local_new_i32(); + + int var2 = 0; -> TCGv_i32 var1 = tcg_temp_local_new_i32(); + tcg_gen_movi_i32(j, ((int64_t) 0ULL)); + +which are later automatically freed at the end of the function they're declared +in. Contrary to C, we only allow variables to be declared with an integer type +specified in the following table (without permutation of keywords) + +:: + + type bit-width signedness + ---------------------------------------------------------- + int 32 signed + signed + signed int + + unsigned 32 unsigned + unsigned int + + long 64 signed + long int + signed long + signed long int + + unsigned long 64 unsigned + unsigned long int + + long long 64 signed + long long int + signed long long + signed long long int + + unsigned long long 64 unsigned + unsigned long long int + + size[1,2,4,8][s,u]_t 8-64 signed or unsigned + +In idef-parser, variable names are matched by a generic ``VARID`` token, +which will feature the variable name as a decoration. For a variable declaration +idef-parser calls ``gen_varid_allocate`` with the ``VARID`` token to save the +name, size, and bit width of the newly declared variable. In addition, this +function also ensures that variables aren't declared multiple times, and prints +and error message if that is the case. Upon use of a variable, the ``VARID`` +token is used to lookup the size and bit width of the variable. + +Type System +~~~~~~~~~~~ + +idef-parser features a simple type system which is used to correctly implement +the signedness and bit width of the operations. + +The type of each ``rvalue`` is determined by two attributes: its bit width +(``unsigned bit_width``) and its signedness (``HexSignedness signedness``). + +For each operation, the type of ``rvalue``\ s influence the way in which the +operands are handled and emitted. For example a right shift between signed +operators will be an arithmetic shift, while one between unsigned operators +will be a logical shift. If one of the two operands is signed, and the other +is unsigned, the operation will be signed. + +The bit width also influences the outcome of the operations, in particular while +the input languages features a fine granularity type system, with types of 8, +16, 32, 64 (and more for vectorial instructions) bits, the tinycode only +features 32 and 64 bit widths. We propagate as much as possible the fine +granularity type, until the value has to be used inside an operation between +``rvalue``\ s; in that case if one of the two operands is greater than 32 bits +we promote the whole operation to 64 bit, taking care of properly extending the +two operands. Fortunately, the most critical instructions already feature +explicit casts and zero/sign extensions which are properly propagated down to +our parser. + +The combination of ``rvalue``\ s are handled through the use of the +``gen_bin_op`` and ``gen_bin_cmp`` helper functions. These two functions handle +the appropriate compile-time or run-time emission of operations to perform the +required computation. + +Control Statements +~~~~~~~~~~~~~~~~~~ + +``control_statement``\ s are all the statements which modify the order of +execution of the generated code according to input parameters. They are expanded +by the following grammar rule: + +:: + + control_statement : frame_check + | cancel_statement + | if_statement + | for_statement + | fpart1_statement + +``if_statement``\ s require the emission of labels and branch instructions which +effectively perform conditional jumps (``tcg_gen_brcondi``) according to the +value of an expression. Note, the tinycode generators we produce for conditional +statements do not perfectly mirror what would be expected in C, for instance we +do not reproduce short-circuiting of the ``&&`` operator, and use of the ``||`` +operator is disallowed. All the predicated instructions, and in general all the +instructions where there could be alternative values assigned to an ``lvalue``, +like C-style ternary expressions: + +:: + + rvalue : rvalue QMARK rvalue COLON rvalue + +are handled using the conditional move tinycode instruction +(``tcg_gen_movcond``), which avoids the additional complexity of managing labels +and jumps. + +Instead, regarding the ``for`` loops, exploiting the fact that they always +iterate on immediate values, therefore their iteration ranges are always known +at compile time, we implemented those emitting plain C ``for`` loops. This is +possible because the loops will be executed in the QEMU code, leading to the +consequential unrolling of the for loop, since the tinycode generator +instructions will be executed multiple times, and the respective generated +tinycode will represent the unrolled execution of the loop. + +Parsing Context +~~~~~~~~~~~~~~~ + +All the helper functions in ``idef-parser.y`` carry two fixed parameters, which +are the parsing context ``c`` and the ``YYLLOC`` location information. The +context is explicitly passed to all the functions because the parser we generate +is a reentrant one, meaning that it does not have any global variable, and +therefore the instruction compilation could easily be parallelized in the +future. Finally for each rule we propagate information about the location of the +involved tokens to generate pretty error reporting, able to highlight the +portion of the input code which generated each error. + +Debugging +--------- + +Developing the idef-parser can lead to two types of errors: compile-time errors +and parsing errors. + +Compile-time errors in Bison-generated parsers are usually due to conflicts in +the described grammar. Conflicts forbid the grammar to produce a unique +derivation tree, thus must be solved (except for the dangling else problem, +which is marked as expected through the ``%expect 1`` Bison option). + +For solving conflicts you need a basic understanding of `shift-reduce conflicts +`__ +and `reduce-reduce conflicts +`__, +then, if you are using a Bison version > 3.7.1 you can ask Bison to generate +some counterexamples which highlight ambiguous derivations, passing the +``-Wcex`` option to Bison. In general shift/reduce conflicts are solved by +redesigning the grammar in an unambiguous way or by setting the token priority +correctly, while reduce/reduce conflicts are solved by redesigning the +interested part of the grammar. + +Run-time errors can be divided between lexing and parsing errors, lexing errors +are hard to detect, since the ``var`` token will catch everything which is not +catched by other tokens, but easy to fix, because most of the time a simple +regex editing will be enough. + +idef-parser features a fancy parsing error reporting scheme, which for each +parsing error reports the fragment of the input text which was involved in the +parsing rule that generated an error. + +Implementing an instruction goes through several sequential steps, here are some +suggestions to make each instruction proceed to the next step. + +- not-emitted + + Means that the parsing of the input code relative to that instruction failed, + this could be due to a lexical error or to some mismatch between the order of + valid tokens and a parser rule. You should check that tokens are correctly + identified and mapped, and that there is a rule matching the token sequence + that you need to parse. + +- emitted + + This instruction class contains all the instructions which are emitted but + fail to compile when included in QEMU. The compilation errors are shown by + the QEMU building process and will lead to fixing the bug. Most common + errors regard the mismatch of parameters for tinycode generator functions, + which boil down to errors in the idef-parser type system. + +- compiled + + These instruction generate valid tinycode generator code, which however fail + the QEMU or the harness tests, these cases must be handled manually by + looking into the failing tests and looking at the generated tinycode + generator instruction and at the generated tinycode itself. Tip: handle the + failing harness tests first, because they usually feature only a single + instruction, thus will require less execution trace navigation. If a + multi-threaded test fail, fixing all the other tests will be the easier + option, hoping that the multi-threaded one will be indirectly fixed. + + An example of debugging this type of failure is provided in the following + section. + +- tests-passed + + This is the final goal for each instruction, meaning that the instruction + passes the test suite. + +Another approach to fix QEMU system test, where many instructions might fail, is +to compare the execution trace of your implementation with the reference +implementations already present in QEMU. To do so you should obtain a QEMU build +where the instruction pass the test, and run it with the following command: + +:: + + sudo unshare -p sudo -u bash -c \ + 'env -i -d cpu ' + +And do the same for your implementation, the generated execution traces will be +inherently aligned and can be inspected for behavioral differences using the +``diff`` tool. + +Example of debugging erroneous tinycode generator code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The goal of this section is to provide a complete example of debugging +incorrectly emitted tinycode generator for a single instruction. + +Let's first introduce a bug in the tinycode generator of the ``A2_add`` +instruction, + +:: + + void emit_A2_add(DisasContext *ctx, Insn *insn, Packet *pkt, TCGv_i32 RdV, + TCGv_i32 RsV, TCGv_i32 RtV) + /* RdV=RsV+RtV;} */ + { + TCGv_i32 tmp_0 = tcg_temp_new_i32(); + tcg_gen_add_i32(tmp_0, RsV, RsV); + tcg_gen_mov_i32(RdV, tmp_0); + tcg_temp_free_i32(tmp_0); + } + +Here the bug, albeit hard to spot, is in ``tcg_gen_add_i32(tmp_0, RsV, RsV);`` +where we compute ``RsV + RsV`` instead of ``RsV + RtV``, as would be expected. +This particular bug is a bit tricky to pinpoint when debugging, since the +``A2_add`` instruction is so ubiquitous. As a result, pretty much all tests will +fail and therefore not provide a lot of information about the bug. + +For example, let's run the ``check-tcg`` tests + +:: + + make check-tcg TIMEOUT=1200 \ + DOCKER_IMAGE=debian-hexagon-cross \ + ENGINE=podman V=1 \ + DOCKER_CROSS_CC_GUEST=hexagon-unknown-linux-musl-clang + +In the output, we find a failure in the very first test case ``float_convs`` +due to a segmentation fault. Similarly, all harness and libc tests will fail as +well. At this point we have no clue where the actual bug lies, and need to start +ruling out instructions. As such a good starting point is to utilize the debug +options ``-d in_asm,cpu`` of QEMU to inspect the Hexagon instructions being run, +alongside the CPU state. We additionally need a working version of the emulator +to compare our buggy CPU state against, running + +:: + + meson configure -Dhexagon_idef_parser=false + +will disable the idef-parser for all instructions and fallback on manual +tinycode generator overrides, or on helper function implementations. Recompiling +gives us ``qemu-hexagon`` which passes all tests. If ``qemu-hexagon-buggy`` is +our binary with the incorrect tinycode generators, we can compare the CPU state +between the two versions + +:: + + ./qemu-hexagon-buggy -d in_asm,cpu float_convs &> out_buggy + ./qemu-hexagon -d in_asm,cpu float_convs &> out_working + +Looking at ``diff -u out_buggy out_working`` shows us that the CPU state begins +to diverge on line 141, with an incorrect value in the ``R1`` register + +:: + + @@ -138,7 +138,7 @@ + + General Purpose Registers = { + r0 = 0x4100f9c0 + - r1 = 0x00042108 + + r1 = 0x00000000 + r2 = 0x00021084 + r3 = 0x00000000 + r4 = 0x00000000 + +If we also look into ``out_buggy`` directly we can inspect the input assembly +which the caused the incorrect CPU state, around line 141 we find + +:: + + 116 | ---------------- + 117 | IN: _start_c + 118 | 0x000210b0: 0xa09dc002 { allocframe(R29,#0x10):raw } + ... | ... + 137 | 0x000210fc: 0x5a00c4aa { call PC+2388 } + 138 | + 139 | General Purpose Registers = { + 140 | r0 = 0x4100fa70 + 141 | r1 = 0x00042108 + 142 | r2 = 0x00021084 + 143 | r3 = 0x00000000 + +Importantly, we see some Hexagon assembly followed by a dump of the CPU state, +now the CPU state is actually dumped before the input assembly above is ran. +As such, we are actually interested in the instructions ran before this. + +Scrolling up a bit, we find + +:: + + 54 | ---------------- + 55 | IN: _start + 56 | 0x00021088: 0x6a09c002 { R2 = C9/pc } + 57 | 0x0002108c: 0xbfe2ff82 { R2 = add(R2,#0xfffffffc) } + 58 | 0x00021090: 0x9182c001 { R1 = memw(R2+#0x0) } + 59 | 0x00021094: 0xf302c101 { R1 = add(R2,R1) } + 60 | 0x00021098: 0x7800c01e { R30 = #0x0 } + 61 | 0x0002109c: 0x707dc000 { R0 = R29 } + 62 | 0x000210a0: 0x763dfe1d { R29 = and(R29,#0xfffffff0) } + 63 | 0x000210a4: 0xa79dfdfe { memw(R29+#0xfffffff8) = R29 } + 64 | 0x000210a8: 0xbffdff1d { R29 = add(R29,#0xfffffff8) } + 65 | 0x000210ac: 0x5a00c002 { call PC+4 } + 66 | + 67 | General Purpose Registers = { + 68 | r0 = 0x00000000 + 69 | r1 = 0x00000000 + 70 | r2 = 0x00000000 + 71 | r3 = 0x00000000 + +Remember, the instructions on lines 56-65 are ran on the CPU state shown below +instructions, and as the CPU state has not diverged at this point, we know the +starting state is accurate. The bug must then lie within the instructions shown +here. Next we may notice that ``R1`` is only touched by lines 57 and 58, that is +by + +:: + + 58 | 0x00021090: 0x9182c001 { R1 = memw(R2+#0x0) } + 59 | 0x00021094: 0xf302c101 { R1 = add(R2,R1) } + +Therefore, we are either dealing with an correct load instruction +``R1 = memw(R2+#0x0)`` or with an incorrect add ``R1 = add(R2,R1)``. At this +point it might be easy enough to go directly to the emitted code for the +instructions mentioned and look for bugs, but we could also run +``./qemu-heaxgon -d op,in_asm float_conv`` where we find for the following +tinycode for the Hexagon ``add`` instruction + +:: + + ---- 00021094 + mov_i32 pkt_has_store_s1,$0x0 + add_i32 tmp0,r2,r2 + mov_i32 loc2,tmp0 + mov_i32 new_r1,loc2 + mov_i32 r1,new_r1 + +Here we have finally located our bug ``add_i32 tmp0,r2,r2``. + +Limitations and Future Development +---------------------------------- + +The main limitation of the current parser is given by the syntax-driven nature +of the Bison-generated parsers. This has the severe implication of only being +able to generate code in the order of evaluation of the various rules, without, +in any case, being able to backtrack and alter the generated code. + +An example limitation is highlighted by this statement of the input language: + +:: + + { (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); } + +This ternary assignment, when written in this form requires us to emit some +proper control flow statements, which emit a jump to the first or to the second +code block, whose implementation is extremely convoluted, because when matching +the ternary assignment, the code evaluating the two assignments will be already +generated. + +Instead we pre-process that statement, making it become: + +:: + + { PdV = ((PsV==0xff)) ? 0xff : 0x00; } + +Which can be easily matched by the following parser rules: + +:: + + statement | rvalue ';' + + rvalue : rvalue QMARK rvalue COLON rvalue + | rvalue EQ rvalue + | LPAR rvalue RPAR + | assign_statement + | IMM + + assign_statement : pred ASSIGN rvalue + +Another example that highlight the limitation of the flex/bison parser can be +found even in the add operation we already saw: + +:: + + TCGv_i32 tmp_0 = tcg_temp_new_i32(); + tcg_gen_add_i32(tmp_0, RsV, RtV); + tcg_gen_mov_i32(RdV, tmp_0); + +The fact that we cannot directly use ``RdV`` as the destination of the sum is a +consequence of the syntax-driven nature of the parser. In fact when we parse the +assignment, the ``rvalue`` token, representing the sum has already been reduced, +and thus its code emitted and unchangeable. We rely on the fact that QEMU will +optimize our code reducing the useless move operations and the relative +temporaries. + +A possible improvement of the parser regards the support for vectorial +instructions and floating point instructions, which will require the extension +of the scanner, the parser, and a partial re-design of the type system, allowing +to build the vectorial semantics over the available vectorial tinycode generator +primitives. + +A more radical improvement will use the parser, not to generate directly the +tinycode generator code, but to generate an intermediate representation like the +LLVM IR, which in turn could be compiled using the clang TCG backend. That code +could be furtherly optimized, overcoming the limitations of the syntax-driven +parsing and could lead to a more optimized generated code. diff --git a/target/hexagon/idef-parser/idef-parser.h b/target/hexagon/idef-parser/idef-parser.h new file mode 100644 index 000000000000..5c49d4da3e7e --- /dev/null +++ b/target/hexagon/idef-parser/idef-parser.h @@ -0,0 +1,253 @@ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. 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 + * 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 . + */ + +#ifndef IDEF_PARSER_H +#define IDEF_PARSER_H + +#include +#include +#include +#include + +#define TCGV_NAME_SIZE 7 +#define MAX_WRITTEN_REGS 32 +#define OFFSET_STR_LEN 32 +#define ALLOC_LIST_LEN 32 +#define ALLOC_NAME_SIZE 32 +#define INIT_LIST_LEN 32 +#define OUT_BUF_LEN (1024 * 1024) +#define SIGNATURE_BUF_LEN (128 * 1024) +#define HEADER_BUF_LEN (128 * 1024) + +/* Variadic macros to wrap the buffer printing functions */ +#define EMIT(c, ...) \ + do { \ + g_string_append_printf((c)->out_str, __VA_ARGS__); \ + } while (0) + +#define EMIT_SIG(c, ...) \ + do { \ + g_string_append_printf((c)->signature_str, __VA_ARGS__); \ + } while (0) + +#define EMIT_HEAD(c, ...) \ + do { \ + g_string_append_printf((c)->header_str, __VA_ARGS__); \ + } while (0) + +/** + * Type of register, assigned to the HexReg.type field + */ +typedef enum { GENERAL_PURPOSE, CONTROL, MODIFIER, DOTNEW } HexRegType; + +typedef enum { UNKNOWN_SIGNEDNESS, SIGNED, UNSIGNED } HexSignedness; + +/** + * Semantic record of the REG tokens, identifying registers + */ +typedef struct HexReg { + uint8_t id; /**< Identifier of the register */ + HexRegType type; /**< Type of the register */ + unsigned bit_width; /**< Bit width of the reg, 32 or 64 bits */ +} HexReg; + +/** + * Data structure, identifying a TCGv temporary value + */ +typedef struct HexTmp { + unsigned index; /**< Index of the TCGv temporary value */ +} HexTmp; + +/** + * Enum of the possible immediated, an immediate is a value which is known + * at tinycode generation time, e.g. an integer value, not a TCGv + */ +enum ImmUnionTag { + I, + VARIABLE, + VALUE, + QEMU_TMP, + IMM_PC, + IMM_NPC, + IMM_CONSTEXT, +}; + +/** + * Semantic record of the IMM token, identifying an immediate constant + */ +typedef struct HexImm { + union { + char id; /**< Identifier, used when type is VARIABLE */ + uint64_t value; /**< Immediate value, used when type is VALUE */ + uint64_t index; /**< Index, used when type is QEMU_TMP */ + }; + enum ImmUnionTag type; /**< Type of the immediate */ +} HexImm; + +/** + * Semantic record of the PRED token, identifying a predicate + */ +typedef struct HexPred { + char id; /**< Identifier of the predicate */ +} HexPred; + +/** + * Semantic record of the SAT token, identifying the saturate operator + * Note: All saturates are assumed to implicitly set overflow. + */ +typedef struct HexSat { + HexSignedness signedness; /**< Signedness of the sat. op. */ +} HexSat; + +/** + * Semantic record of the CAST token, identifying the cast operator + */ +typedef struct HexCast { + unsigned bit_width; /**< Bit width of the cast operator */ + HexSignedness signedness; /**< Unsigned flag for the cast operator */ +} HexCast; + +/** + * Semantic record of the EXTRACT token, identifying the cast operator + */ +typedef struct HexExtract { + unsigned bit_width; /**< Bit width of the extract operator */ + unsigned storage_bit_width; /**< Actual bit width of the extract operator */ + HexSignedness signedness; /**< Unsigned flag for the extract operator */ +} HexExtract; + +/** + * Semantic record of the MPY token, identifying the fMPY multiplication + * operator + */ +typedef struct HexMpy { + unsigned first_bit_width; /**< Bit width of 1st operand of fMPY */ + unsigned second_bit_width; /**< Bit width of 2nd operand of fMPY */ + HexSignedness first_signedness; /**< Signedness of 1st operand of fMPY */ + HexSignedness second_signedness; /**< Signedness of 2nd operand of fMPY */ +} HexMpy; + +/** + * Semantic record of the VARID token, identifying declared variables + * of the input language + */ +typedef struct HexVar { + GString *name; /**< Name of the VARID variable */ +} HexVar; + +/** + * Data structure uniquely identifying a declared VARID variable, used for + * keeping track of declared variable, so that any variable is declared only + * once, and its properties are propagated through all the subsequent instances + * of that variable + */ +typedef struct Var { + GString *name; /**< Name of the VARID variable */ + uint8_t bit_width; /**< Bit width of the VARID variable */ + HexSignedness signedness; /**< Unsigned flag for the VARID var */ +} Var; + +/** + * Enum of the possible rvalue types, used in the HexValue.type field + */ +typedef enum RvalueUnionTag { + REGISTER, REGISTER_ARG, TEMP, IMMEDIATE, PREDICATE, VARID +} RvalueUnionTag; + +/** + * Semantic record of the rvalue token, identifying any numeric value, + * immediate or register based. The rvalue tokens are combined together + * through the use of several operators, to encode expressions + */ +typedef struct HexValue { + union { + HexReg reg; /**< rvalue of register type */ + HexTmp tmp; /**< rvalue of temporary type */ + HexImm imm; /**< rvalue of immediate type */ + HexPred pred; /**< rvalue of predicate type */ + HexVar var; /**< rvalue of declared variable type */ + }; + RvalueUnionTag type; /**< Type of the rvalue */ + unsigned bit_width; /**< Bit width of the rvalue */ + HexSignedness signedness; /**< Unsigned flag for the rvalue */ + bool is_dotnew; /**< rvalue of predicate type is dotnew? */ + bool is_manual; /**< Opt out of automatic freeing of params */ +} HexValue; + +/** + * State of ternary operator + */ +typedef enum TernaryState { IN_LEFT, IN_RIGHT } TernaryState; + +/** + * Data structure used to handle side effects inside ternary operators + */ +typedef struct Ternary { + TernaryState state; + HexValue cond; +} Ternary; + +/** + * Operator type, used for referencing the correct operator when calling the + * gen_bin_op() function, which in turn will generate the correct code to + * execute the operation between the two rvalues + */ +typedef enum OpType { + ADD_OP, SUB_OP, MUL_OP, ASL_OP, ASR_OP, LSR_OP, ANDB_OP, ORB_OP, + XORB_OP, ANDL_OP, MINI_OP, MAXI_OP +} OpType; + +/** + * Data structure including instruction specific information, to be cleared + * out after the compilation of each instruction + */ +typedef struct Inst { + GString *name; /**< Name of the compiled instruction */ + char *code_begin; /**< Beginning of instruction input code */ + char *code_end; /**< End of instruction input code */ + unsigned tmp_count; /**< Index of the last declared TCGv temp */ + unsigned qemu_tmp_count; /**< Index of the last declared int temp */ + unsigned if_count; /**< Index of the last declared if label */ + unsigned error_count; /**< Number of generated errors */ + GArray *allocated; /**< Allocated declaredVARID vars */ + GArray *init_list; /**< List of initialized registers */ + GArray *strings; /**< Strings allocated by the instruction */ +} Inst; + +/** + * Data structure representing the whole translation context, which in a + * reentrant flex/bison parser just like ours is passed between the scanner + * and the parser, holding all the necessary information to perform the + * parsing, this data structure survives between the compilation of different + * instructions + */ +typedef struct Context { + void *scanner; /**< Reentrant parser state pointer */ + char *input_buffer; /**< Buffer containing the input code */ + GString *out_str; /**< String containing the output code */ + GString *signature_str; /**< String containing the signatures code */ + GString *header_str; /**< String containing the header code */ + FILE *defines_file; /**< FILE * of the generated header */ + FILE *output_file; /**< FILE * of the C output file */ + FILE *enabled_file; /**< FILE * of the list of enabled inst */ + GArray *ternary; /**< Array to track nesting of ternary ops */ + unsigned total_insn; /**< Number of instructions in input file */ + unsigned implemented_insn; /**< Instruction compiled without errors */ + Inst inst; /**< Parsing data of the current inst */ +} Context; + +#endif /* IDEF_PARSER_H */ diff --git a/target/hexagon/idef-parser/idef-parser.lex b/target/hexagon/idef-parser/idef-parser.lex new file mode 100644 index 000000000000..ff87a02c3ab9 --- /dev/null +++ b/target/hexagon/idef-parser/idef-parser.lex @@ -0,0 +1,471 @@ +%option noyywrap noinput nounput +%option 8bit reentrant bison-bridge +%option warn nodefault +%option bison-locations + +%{ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. 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 + * 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 . + */ + +#include +#include + +#include "hex_regs.h" + +#include "idef-parser.h" +#include "idef-parser.tab.h" + +/* Keep track of scanner position for error message printout */ +#define YY_USER_ACTION yylloc->first_column = yylloc->last_column; \ + for (int i = 0; yytext[i] != '\0'; i++) { \ + yylloc->last_column++; \ + } + +/* Global Error Counter */ +int error_count; + +%} + +/* Definitions */ +DIGIT [0-9] +LOWER_ID [a-z] +UPPER_ID [A-Z] +ID LOWER_ID|UPPER_ID +INST_NAME [A-Z]+[0-9]_([A-Za-z]|[0-9]|_)+ +HEX_DIGIT [0-9a-fA-F] +REG_ID_32 e|s|d|t|u|v|x|y +REG_ID_64 ee|ss|dd|tt|uu|vv|xx|yy +SYS_ID_32 s|d +SYS_ID_64 ss|dd +PRED_ID d|s|t|u|v|e|x|x +IMM_ID r|s|S|u|U +VAR_ID [a-zA-Z_][a-zA-Z0-9_]* +SIGN_ID s|u +STRING_LIT \"(\\.|[^"\\])*\" + +/* Tokens */ +%% + +[ \t\f\v]+ { /* Ignore whitespaces. */ } +[\n\r]+ { /* Ignore newlines. */ } +^#.*$ { /* Ignore linemarkers. */ } + +{INST_NAME} { yylval->string = g_string_new(yytext); + return INAME; } +"fFLOAT" | +"fUNFLOAT" | +"fDOUBLE" | +"fUNDOUBLE" | +"0.0" | +"0x1.0p52" | +"0x1.0p-52" { return FAIL; } +"in" { return IN; } +"R"{REG_ID_32}"V" { + yylval->rvalue.type = REGISTER_ARG; + yylval->rvalue.reg.type = GENERAL_PURPOSE; + yylval->rvalue.reg.id = yytext[1]; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = false; + yylval->rvalue.signedness = SIGNED; + return REG; } +"R"{REG_ID_64}"V" { + yylval->rvalue.type = REGISTER_ARG; + yylval->rvalue.reg.type = GENERAL_PURPOSE; + yylval->rvalue.reg.id = yytext[1]; + yylval->rvalue.reg.bit_width = 64; + yylval->rvalue.bit_width = 64; + yylval->rvalue.is_dotnew = false; + yylval->rvalue.signedness = SIGNED; + return REG; } +"MuV" { + yylval->rvalue.type = REGISTER_ARG; + yylval->rvalue.reg.type = MODIFIER; + yylval->rvalue.reg.id = 'u'; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = SIGNED; + return REG; } +"C"{REG_ID_32}"V" { + yylval->rvalue.type = REGISTER_ARG; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = yytext[1]; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = false; + yylval->rvalue.signedness = SIGNED; + return REG; } +"C"{REG_ID_64}"V" { + yylval->rvalue.type = REGISTER_ARG; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = yytext[1]; + yylval->rvalue.reg.bit_width = 64; + yylval->rvalue.bit_width = 64; + yylval->rvalue.is_dotnew = false; + yylval->rvalue.signedness = SIGNED; + return REG; } +{IMM_ID}"iV" { + yylval->rvalue.type = IMMEDIATE; + yylval->rvalue.signedness = SIGNED; + yylval->rvalue.imm.type = VARIABLE; + yylval->rvalue.imm.id = yytext[0]; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = false; + return IMM; } +"P"{PRED_ID}"V" { + yylval->rvalue.type = PREDICATE; + yylval->rvalue.pred.id = yytext[1]; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = false; + yylval->rvalue.signedness = SIGNED; + return PRED; } +"P"{PRED_ID}"N" { + yylval->rvalue.type = PREDICATE; + yylval->rvalue.pred.id = yytext[1]; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = true; + yylval->rvalue.signedness = SIGNED; + return PRED; } +"IV1DEAD()" | +"fPAUSE(uiV);" { return ';'; } +"+=" { return INC; } +"-=" { return DEC; } +"++" { return PLUSPLUS; } +"&=" { return ANDA; } +"|=" { return ORA; } +"^=" { return XORA; } +"<<" { return ASL; } +">>" { return ASR; } +">>>" { return LSR; } +"==" { return EQ; } +"!=" { return NEQ; } +"<=" { return LTE; } +">=" { return GTE; } +"&&" { return ANDL; } +"else" { return ELSE; } +"for" { return FOR; } +"fREAD_IREG" { return ICIRC; } +"fPART1" { return PART1; } +"if" { return IF; } +"fFRAME_SCRAMBLE" { return FSCR; } +"fFRAME_UNSCRAMBLE" { return FSCR; } +"fFRAMECHECK" { return FCHK; } +"Constant_extended" { return CONSTEXT; } +"fCL1_"{DIGIT} { return LOCNT; } +"fbrev" { return BREV; } +"fSXTN" { return SXT; } +"fZXTN" { return ZXT; } +"fDF_MAX" | +"fSF_MAX" | +"fMAX" { return MAX; } +"fDF_MIN" | +"fSF_MIN" | +"fMIN" { return MIN; } +"fABS" { return ABS; } +"fRNDN" { return ROUND; } +"fCRND" { return CROUND; } +"fCRNDN" { return CROUND; } +"fPM_CIRI" { return CIRCADD; } +"fPM_CIRR" { return CIRCADD; } +"fCOUNTONES_"{DIGIT} { return COUNTONES; } +"fSATN" { yylval->sat.signedness = SIGNED; + return SAT; } +"fSATUN" { yylval->sat.signedness = UNSIGNED; + return SAT; } +"fCONSTLL" { yylval->cast.bit_width = 64; + yylval->cast.signedness = SIGNED; + return CAST; } +"fSE32_64" { yylval->cast.bit_width = 64; + yylval->cast.signedness = SIGNED; + return CAST; } +"fCAST4_4u" { yylval->cast.bit_width = 32; + yylval->cast.signedness = UNSIGNED; + return CAST; } +"fCAST4_8s" { yylval->cast.bit_width = 64; + yylval->cast.signedness = SIGNED; + return CAST; } +"fCAST4_8u" { return CAST4_8U; } +"fCAST4u" { yylval->cast.bit_width = 32; + yylval->cast.signedness = UNSIGNED; + return CAST; } +"fNEWREG" | +"fCAST4_4s" | +"fCAST4s" { yylval->cast.bit_width = 32; + yylval->cast.signedness = SIGNED; + return CAST; } +"fCAST8_8u" { yylval->cast.bit_width = 64; + yylval->cast.signedness = UNSIGNED; + return CAST; } +"fCAST8u" { yylval->cast.bit_width = 64; + yylval->cast.signedness = UNSIGNED; + return CAST; } +"fCAST8_8s" | +"fCAST8s" { yylval->cast.bit_width = 64; + yylval->cast.signedness = SIGNED; + return CAST; } +"fGETBIT" { yylval->extract.bit_width = 1; + yylval->extract.storage_bit_width = 1; + yylval->extract.signedness = UNSIGNED; + return EXTRACT; } +"fGETBYTE" { yylval->extract.bit_width = 8; + yylval->extract.storage_bit_width = 8; + yylval->extract.signedness = SIGNED; + return EXTRACT; } +"fGETUBYTE" { yylval->extract.bit_width = 8; + yylval->extract.storage_bit_width = 8; + yylval->extract.signedness = UNSIGNED; + return EXTRACT; } +"fGETHALF" { yylval->extract.bit_width = 16; + yylval->extract.storage_bit_width = 16; + yylval->extract.signedness = SIGNED; + return EXTRACT; } +"fGETUHALF" { yylval->extract.bit_width = 16; + yylval->extract.storage_bit_width = 16; + yylval->extract.signedness = UNSIGNED; + return EXTRACT; } +"fGETWORD" { yylval->extract.bit_width = 32; + yylval->extract.storage_bit_width = 64; + yylval->extract.signedness = SIGNED; + return EXTRACT; } +"fGETUWORD" { yylval->extract.bit_width = 32; + yylval->extract.storage_bit_width = 64; + yylval->extract.signedness = UNSIGNED; + return EXTRACT; } +"fEXTRACTU_RANGE" { return EXTRANGE; } +"fSETBIT" { yylval->cast.bit_width = 1; + yylval->cast.signedness = SIGNED; + return DEPOSIT; } +"fSETBYTE" { yylval->cast.bit_width = 8; + yylval->cast.signedness = SIGNED; + return DEPOSIT; } +"fSETHALF" { yylval->cast.bit_width = 16; + yylval->cast.signedness = SIGNED; + return SETHALF; } +"fSETWORD" { yylval->cast.bit_width = 32; + yylval->cast.signedness = SIGNED; + return DEPOSIT; } +"fINSERT_BITS" { return INSBITS; } +"fSETBITS" { return SETBITS; } +"fMPY16UU" { yylval->mpy.first_bit_width = 16; + yylval->mpy.second_bit_width = 16; + yylval->mpy.first_signedness = UNSIGNED; + yylval->mpy.second_signedness = UNSIGNED; + return MPY; } +"fMPY16SU" { yylval->mpy.first_bit_width = 16; + yylval->mpy.second_bit_width = 16; + yylval->mpy.first_signedness = SIGNED; + yylval->mpy.second_signedness = UNSIGNED; + return MPY; } +"fMPY16SS" { yylval->mpy.first_bit_width = 16; + yylval->mpy.second_bit_width = 16; + yylval->mpy.first_signedness = SIGNED; + yylval->mpy.second_signedness = SIGNED; + return MPY; } +"fMPY32UU" { yylval->mpy.first_bit_width = 32; + yylval->mpy.second_bit_width = 32; + yylval->mpy.first_signedness = UNSIGNED; + yylval->mpy.second_signedness = UNSIGNED; + return MPY; } +"fMPY32SU" { yylval->mpy.first_bit_width = 32; + yylval->mpy.second_bit_width = 32; + yylval->mpy.first_signedness = SIGNED; + yylval->mpy.second_signedness = UNSIGNED; + return MPY; } +"fSFMPY" | +"fMPY32SS" { yylval->mpy.first_bit_width = 32; + yylval->mpy.second_bit_width = 32; + yylval->mpy.first_signedness = SIGNED; + yylval->mpy.second_signedness = SIGNED; + return MPY; } +"fMPY3216SS" { yylval->mpy.first_bit_width = 32; + yylval->mpy.second_bit_width = 16; + yylval->mpy.first_signedness = SIGNED; + yylval->mpy.second_signedness = SIGNED; + return MPY; } +"fMPY3216SU" { yylval->mpy.first_bit_width = 32; + yylval->mpy.second_bit_width = 16; + yylval->mpy.first_signedness = SIGNED; + yylval->mpy.second_signedness = UNSIGNED; + return MPY; } +"fNEWREG_ST" | +"fIMMEXT" | +"fMUST_IMMEXT" | +"fPASS" | +"fECHO" { return IDENTITY; } +"(size8u_t)" { yylval->cast.bit_width = 64; + yylval->cast.signedness = UNSIGNED; + return CAST; } +"(unsigned int)" { yylval->cast.bit_width = 32; + yylval->cast.signedness = UNSIGNED; + return CAST; } +"fREAD_PC()" | +"PC" { return PC; } +"fREAD_NPC()" | +"NPC" { return NPC; } +"fGET_LPCFG" | +"USR.LPCFG" { return LPCFG; } +"LOAD_CANCEL(EA)" { return LOAD_CANCEL; } +"STORE_CANCEL(EA)" | +"CANCEL" { return CANCEL; } +"N"{LOWER_ID}"N" { yylval->rvalue.type = REGISTER_ARG; + yylval->rvalue.reg.type = DOTNEW; + yylval->rvalue.reg.id = yytext[1]; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_SP()" | +"SP" { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = GENERAL_PURPOSE; + yylval->rvalue.reg.id = HEX_REG_SP; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_FP()" | +"FP" { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = GENERAL_PURPOSE; + yylval->rvalue.reg.id = HEX_REG_FP; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_LR()" | +"LR" { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = GENERAL_PURPOSE; + yylval->rvalue.reg.id = HEX_REG_LR; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_GP()" | +"GP" { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = HEX_REG_GP; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_LC"[01] { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = HEX_REG_LC0 + + (yytext[8] - '0') * 2; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"LC"[01] { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = HEX_REG_LC0 + + (yytext[2] - '0') * 2; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_SA"[01] { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = HEX_REG_SA0 + + (yytext[8] - '0') * 2; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"SA"[01] { yylval->rvalue.type = REGISTER; + yylval->rvalue.reg.type = CONTROL; + yylval->rvalue.reg.id = HEX_REG_SA0 + + (yytext[2] - '0') * 2; + yylval->rvalue.reg.bit_width = 32; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = UNSIGNED; + return REG; } +"fREAD_P0()" { yylval->rvalue.type = PREDICATE; + yylval->rvalue.pred.id = '0'; + yylval->rvalue.bit_width = 32; + return PRED; } +[pP]{DIGIT} { yylval->rvalue.type = PREDICATE; + yylval->rvalue.pred.id = yytext[1]; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = false; + return PRED; } +[pP]{DIGIT}[nN] { yylval->rvalue.type = PREDICATE; + yylval->rvalue.pred.id = yytext[1]; + yylval->rvalue.bit_width = 32; + yylval->rvalue.is_dotnew = true; + return PRED; } +"fLSBNEW" { return LSBNEW; } +"N" { yylval->rvalue.type = IMMEDIATE; + yylval->rvalue.bit_width = 32; + yylval->rvalue.imm.type = VARIABLE; + yylval->rvalue.imm.id = 'N'; + return IMM; } +"i" { yylval->rvalue.type = IMMEDIATE; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = SIGNED; + yylval->rvalue.imm.type = I; + return IMM; } +{SIGN_ID} { if (yytext[0] == 'u') { + yylval->signedness = UNSIGNED; + } else { + yylval->signedness = SIGNED; + } + return SIGN; + } +"0x"{HEX_DIGIT}+ | +{DIGIT}+ { yylval->rvalue.type = IMMEDIATE; + yylval->rvalue.bit_width = 32; + yylval->rvalue.signedness = SIGNED; + yylval->rvalue.imm.type = VALUE; + yylval->rvalue.imm.value = strtoull(yytext, NULL, 0); + return IMM; } +"0x"{HEX_DIGIT}+"ULL" | +{DIGIT}+"ULL" { yylval->rvalue.type = IMMEDIATE; + yylval->rvalue.bit_width = 64; + yylval->rvalue.signedness = UNSIGNED; + yylval->rvalue.imm.type = VALUE; + yylval->rvalue.imm.value = strtoull(yytext, NULL, 0); + return IMM; } +"fLOAD" { return LOAD; } +"fSTORE" { return STORE; } +"fROTL" { return ROTL; } +"fCARRY_FROM_ADD" { return CARRY_FROM_ADD; } +"fADDSAT64" { return ADDSAT64; } +"size"[1248][us]"_t" { /* Handles "size_t" variants of int types */ + const unsigned int bits_per_byte = 8; + const unsigned int bytes = yytext[4] - '0'; + yylval->rvalue.bit_width = bits_per_byte * bytes; + if (yytext[5] == 'u') { + yylval->rvalue.signedness = UNSIGNED; + } else { + yylval->rvalue.signedness = SIGNED; + } + return TYPE_SIZE_T; } +"unsigned" { return TYPE_UNSIGNED; } +"long" { return TYPE_LONG; } +"int" { return TYPE_INT; } +"const" { /* Emit no token */ } +{VAR_ID} { /* Variable name, we adopt the C names convention */ + yylval->rvalue.type = VARID; + yylval->rvalue.var.name = g_string_new(yytext); + /* Default to an unknown signedness and 0 width. */ + yylval->rvalue.bit_width = 0; + yylval->rvalue.signedness = UNKNOWN_SIGNEDNESS; + return VAR; } +"fatal("{STRING_LIT}")" { /* Emit no token */ } +"fHINTJR(RsV)" { /* Emit no token */ } +. { return yytext[0]; } + +%% diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y new file mode 100644 index 000000000000..c14cb3950054 --- /dev/null +++ b/target/hexagon/idef-parser/idef-parser.y @@ -0,0 +1,967 @@ +%{ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved. + * + * 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 "idef-parser.h" +#include "parser-helpers.h" +#include "idef-parser.tab.h" +#include "idef-parser.yy.h" + +/* Uncomment this to disable yyasserts */ +/* #define NDEBUG */ + +#define ERR_LINE_CONTEXT 40 + +%} + +%lex-param {void *scanner} +%parse-param {void *scanner} +%parse-param {Context *c} + +%define parse.error verbose +%define parse.lac full +%define api.pure full + +%locations + +%union { + GString *string; + HexValue rvalue; + HexSat sat; + HexCast cast; + HexExtract extract; + HexMpy mpy; + HexSignedness signedness; + int index; +} + +/* Tokens */ +%start input + +%expect 1 + +%token IN INAME VAR +%token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL +%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT +%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC NPC LPCFG +%token LOAD_CANCEL CANCEL IDENTITY PART1 ROTL INSBITS SETBITS EXTRANGE +%token CAST4_8U FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW +%token TYPE_SIZE_T TYPE_INT TYPE_SIGNED TYPE_UNSIGNED TYPE_LONG + +%token REG IMM PRED +%token ELSE +%token MPY +%token SAT +%token CAST DEPOSIT SETHALF +%token EXTRACT +%type INAME +%type rvalue lvalue VAR assign_statement var var_decl var_type +%type FAIL +%type TYPE_SIGNED TYPE_UNSIGNED TYPE_INT TYPE_LONG TYPE_SIZE_T +%type if_stmt IF +%type SIGN + +/* Operator Precedences */ +%left MIN MAX +%left '(' +%left ',' +%left '=' +%right CIRCADD +%right INC DEC ANDA ORA XORA +%left '?' ':' +%left ANDL +%left '|' +%left '^' ANDOR +%left '&' +%left EQ NEQ +%left '<' '>' LTE GTE +%left ASL ASR LSR +%right ABS +%left '-' '+' +%left '*' '/' '%' MPY +%right '~' '!' +%left '[' +%right CAST +%right LOCNT BREV + +/* Bison Grammar */ +%% + +/* Input file containing the description of each hexagon instruction */ +input : instructions + { + /* Suppress warning about unused yynerrs */ + (void) yynerrs; + YYACCEPT; + } + ; + +instructions : instruction instructions + | %empty + ; + +instruction : INAME + { + gen_inst(c, $1); + } + arguments + { + EMIT_SIG(c, ")"); + EMIT_HEAD(c, "{\n"); + } + code + { + gen_inst_code(c, &@1); + } + | error /* Recover gracefully after instruction compilation error */ + { + free_instruction(c); + } + ; + +arguments : '(' ')' + | '(' argument_list ')'; + +argument_list : argument_decl ',' argument_list + | argument_decl + ; + +var : VAR + { + track_string(c, $1.var.name); + $$ = $1; + } + ; + +/* + * Here the integer types are defined from valid combinations of + * `signed`, `unsigned`, `int`, and `long` tokens. The `signed` + * and `unsigned` tokens are here assumed to always be placed + * first in the type declaration, which is not the case in + * normal C. Similarly, `int` is assumed to always be placed + * last in the type. + */ +type_int : TYPE_INT + | TYPE_SIGNED + | TYPE_SIGNED TYPE_INT; +type_uint : TYPE_UNSIGNED + | TYPE_UNSIGNED TYPE_INT; +type_ulonglong : TYPE_UNSIGNED TYPE_LONG TYPE_LONG + | TYPE_UNSIGNED TYPE_LONG TYPE_LONG TYPE_INT; + +/* + * Here the various valid int types defined above specify + * their `signedness` and `bit_width`. The LP64 convention + * is assumed where longs are 64-bit, long longs are then + * assumed to also be 64-bit. + */ +var_type : TYPE_SIZE_T + { + yyassert(c, &@1, $1.bit_width <= 64, + "Variables with size > 64-bit are not supported!"); + $$ = $1; + } + | type_int + { + $$.signedness = SIGNED; + $$.bit_width = 32; + } + | type_uint + { + $$.signedness = UNSIGNED; + $$.bit_width = 32; + } + | type_ulonglong + { + $$.signedness = UNSIGNED; + $$.bit_width = 64; + } + ; + +/* Rule to capture declarations of VARs */ +var_decl : var_type IMM + { + /* + * Rule to capture "int i;" declarations since "i" is special + * and assumed to be always be IMM. Moreover, "i" is only + * assumed to be used in for-loops. + * + * Therefore we want to NOP these declarations. + */ + yyassert(c, &@2, $2.imm.type == I, + "Variable declaration with immedaties only allowed" + " for the loop induction variable \"i\""); + $$ = $2; + } + | var_type var + { + /* + * Allocate new variable, this checks that it hasn't already + * been declared. + */ + gen_varid_allocate(c, &@1, &$2, $1.bit_width, $1.signedness); + /* Copy var for variable name */ + $$ = $2; + /* Copy type info from var_type */ + $$.signedness = $1.signedness; + $$.bit_width = $1.bit_width; + } + ; + +/* Return the modified registers list */ +code : '{' statements '}' + { + c->inst.code_begin = c->input_buffer + @2.first_column - 1; + c->inst.code_end = c->input_buffer + @2.last_column - 1; + } + | '{' + { + /* Nop */ + } + '}' + ; + +argument_decl : REG + { + emit_arg(c, &@1, &$1); + /* Enqueue register into initialization list */ + g_array_append_val(c->inst.init_list, $1); + } + | PRED + { + emit_arg(c, &@1, &$1); + /* Enqueue predicate into initialization list */ + g_array_append_val(c->inst.init_list, $1); + } + | IN REG + { + emit_arg(c, &@2, &$2); + } + | IN PRED + { + emit_arg(c, &@2, &$2); + } + | IMM + { + EMIT_SIG(c, ", int %ciV", $1.imm.id); + } + ; + +code_block : '{' statements '}' + | '{' '}' + ; + +/* A list of one or more statements */ +statements : statements statement + | statement + ; + +/* Statements can be assignment (rvalue ';'), control or memory statements */ +statement : control_statement + | var_decl ';' + | rvalue ';' + { + gen_rvalue_free(c, &@1, &$1); + } + | code_block + | ';' + ; + +assign_statement : lvalue '=' rvalue + { + @1.last_column = @3.last_column; + gen_assign(c, &@1, &$1, &$3); + $$ = $1; + } + | var_decl '=' rvalue + { + @1.last_column = @3.last_column; + gen_assign(c, &@1, &$1, &$3); + $$ = $1; + } + | lvalue INC rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, ADD_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue DEC rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, SUB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue ANDA rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue ORA rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, ORB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | lvalue XORA rvalue + { + @1.last_column = @3.last_column; + HexValue tmp = gen_bin_op(c, &@1, XORB_OP, &$1, &$3); + gen_assign(c, &@1, &$1, &tmp); + $$ = $1; + } + | PRED '=' rvalue + { + @1.last_column = @3.last_column; + gen_pred_assign(c, &@1, &$1, &$3); + } + | IMM '=' rvalue + { + @1.last_column = @3.last_column; + yyassert(c, &@1, $3.type == IMMEDIATE, + "Cannot assign non-immediate to immediate!"); + yyassert(c, &@1, $1.imm.type == VARIABLE, + "Cannot assign to non-variable!"); + /* Assign to the function argument */ + OUT(c, &@1, &$1, " = ", &$3, ";\n"); + $$ = $1; + } + | PC '=' rvalue + { + @1.last_column = @3.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + $3 = gen_rvalue_truncate(c, &@1, &$3); + $3 = rvalue_materialize(c, &@1, &$3); + OUT(c, &@1, "gen_write_new_pc(", &$3, ");\n"); + gen_rvalue_free(c, &@1, &$3); /* Free temporary value */ + } + | LOAD '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')' + { + @1.last_column = @12.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + yyassert(c, &@1, $3.imm.value == 1, + "LOAD of arrays not supported!"); + gen_load(c, &@1, &$5, $7, &$9, &$11); + } + | STORE '(' IMM ',' IMM ',' var ',' rvalue ')' + /* Store primitive */ + { + @1.last_column = @10.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + yyassert(c, &@1, $3.imm.value == 1, + "STORE of arrays not supported!"); + gen_store(c, &@1, &$5, &$7, &$9); + } + | LPCFG '=' rvalue + { + @1.last_column = @3.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + $3 = gen_rvalue_truncate(c, &@1, &$3); + $3 = rvalue_materialize(c, &@1, &$3); + OUT(c, &@1, "SET_USR_FIELD(USR_LPCFG, ", &$3, ");\n"); + gen_rvalue_free(c, &@1, &$3); + } + | DEPOSIT '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1); + } + | SETHALF '(' rvalue ',' lvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_sethalf(c, &@1, &$1, &$3, &$5, &$7); + } + | SETBITS '(' rvalue ',' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @10.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_setbits(c, &@1, &$3, &$5, &$7, &$9); + } + | INSBITS '(' lvalue ',' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @10.last_column; + yyassert(c, &@1, !is_inside_ternary(c), + "Assignment side-effect not modeled!"); + gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5); + } + | IDENTITY '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = $3; + } + ; + +control_statement : frame_check + | cancel_statement + | if_statement + | for_statement + | fpart1_statement + ; + +frame_check : FCHK '(' rvalue ',' rvalue ')' ';' + { + gen_rvalue_free(c, &@1, &$3); + gen_rvalue_free(c, &@1, &$5); + } + ; + +cancel_statement : LOAD_CANCEL + { + gen_load_cancel(c, &@1); + } + | CANCEL + { + gen_cancel(c, &@1); + } + ; + +if_statement : if_stmt + { + /* Fix else label */ + OUT(c, &@1, "gen_set_label(if_label_", &$1, ");\n"); + } + | if_stmt ELSE + { + @1.last_column = @2.last_column; + $2 = gen_if_else(c, &@1, $1); + } + statement + { + OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n"); + } + ; + +for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')' + { + yyassert(c, &@3, + $3.imm.type == I && + $7.imm.type == I && + $11.imm.type == I, + "Loop induction variable must be \"i\""); + @1.last_column = @13.last_column; + OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ", + &$7, " < ", &$9); + OUT(c, &@1, "; ", &$11, "++) {\n"); + } + code_block + { + OUT(c, &@1, "}\n"); + } + ; + +fpart1_statement : PART1 + { + OUT(c, &@1, "if (insn->part1) {\n"); + } + '(' statements ')' + { + @1.last_column = @3.last_column; + OUT(c, &@1, "return; }\n"); + } + ; + +if_stmt : IF '(' rvalue ')' + { + @1.last_column = @3.last_column; + $1 = gen_if_cond(c, &@1, &$3); + } + statement + { + $$ = $1; + } + ; + +rvalue : FAIL + { + yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n"); + } + | assign_statement + | REG + { + $$ = $1; + } + | IMM + { + $$ = $1; + } + | PRED + { + $$ = gen_rvalue_pred(c, &@1, &$1); + } + | PC + { + /* Read PC from the CR */ + HexValue rvalue; + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.imm.type = IMM_PC; + rvalue.bit_width = 32; + rvalue.signedness = UNSIGNED; + $$ = rvalue; + } + | NPC + { + /* + * NPC is only read from CALLs, so we can hardcode it + * at translation time + */ + HexValue rvalue; + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.imm.type = IMM_NPC; + rvalue.bit_width = 32; + rvalue.signedness = UNSIGNED; + $$ = rvalue; + } + | CONSTEXT + { + HexValue rvalue; + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.imm.type = IMM_CONSTEXT; + rvalue.signedness = UNSIGNED; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + $$ = rvalue; + } + | var + { + $$ = gen_rvalue_var(c, &@1, &$1); + } + | MPY '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_rvalue_mpy(c, &@1, &$1, &$3, &$5); + } + | rvalue '+' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3); + } + | rvalue '-' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3); + } + | rvalue '*' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3); + } + | rvalue ASL rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ASL_OP, &$1, &$3); + } + | rvalue ASR rvalue + { + @1.last_column = @3.last_column; + assert_signedness(c, &@1, $1.signedness); + if ($1.signedness == UNSIGNED) { + $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3); + } else if ($1.signedness == SIGNED) { + $$ = gen_bin_op(c, &@1, ASR_OP, &$1, &$3); + } + } + | rvalue LSR rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3); + } + | rvalue '&' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3); + } + | rvalue '|' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3); + } + | rvalue '^' rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, XORB_OP, &$1, &$3); + } + | rvalue ANDL rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, ANDL_OP, &$1, &$3); + } + | MIN '(' rvalue ',' rvalue ')' + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5); + } + | MAX '(' rvalue ',' rvalue ')' + { + @1.last_column = @3.last_column; + $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5); + } + | '~' rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_not(c, &@1, &$2); + } + | '!' rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_notl(c, &@1, &$2); + } + | SAT '(' IMM ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_rvalue_sat(c, &@1, &$1, &$3, &$5); + } + | CAST rvalue + { + @1.last_column = @2.last_column; + /* Assign target signedness */ + $2.signedness = $1.signedness; + $$ = gen_cast_op(c, &@1, &$2, $1.bit_width, $1.signedness); + } + | rvalue EQ rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_cmp(c, &@1, TCG_COND_EQ, &$1, &$3); + } + | rvalue NEQ rvalue + { + @1.last_column = @3.last_column; + $$ = gen_bin_cmp(c, &@1, TCG_COND_NE, &$1, &$3); + } + | rvalue '<' rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LTU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LT, &$1, &$3); + } + } + | rvalue '>' rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GTU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GT, &$1, &$3); + } + } + | rvalue LTE rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LEU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_LE, &$1, &$3); + } + } + | rvalue GTE rvalue + { + @1.last_column = @3.last_column; + + assert_signedness(c, &@1, $1.signedness); + assert_signedness(c, &@1, $3.signedness); + if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GEU, &$1, &$3); + } else { + $$ = gen_bin_cmp(c, &@1, TCG_COND_GE, &$1, &$3); + } + } + | rvalue '?' + { + $1.is_manual = true; + Ternary t = { 0 }; + t.state = IN_LEFT; + t.cond = $1; + g_array_append_val(c->ternary, t); + } + rvalue ':' + { + Ternary *t = &g_array_index(c->ternary, Ternary, + c->ternary->len - 1); + t->state = IN_RIGHT; + } + rvalue + { + @1.last_column = @5.last_column; + $$ = gen_rvalue_ternary(c, &@1, &$1, &$4, &$7); + } + | FSCR '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_rvalue_fscr(c, &@1, &$3); + } + | SXT '(' rvalue ',' IMM ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, $5.type == IMMEDIATE && + $5.imm.type == VALUE, + "SXT expects immediate values\n"); + $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, SIGNED); + } + | ZXT '(' rvalue ',' IMM ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, $5.type == IMMEDIATE && + $5.imm.type == VALUE, + "ZXT expects immediate values\n"); + $$ = gen_extend_op(c, &@1, &$3, $5.imm.value, &$7, UNSIGNED); + } + | '(' rvalue ')' + { + $$ = $2; + } + | ABS rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_abs(c, &@1, &$2); + } + | CROUND '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_convround_n(c, &@1, &$3, &$5); + } + | CROUND '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_convround(c, &@1, &$3); + } + | ROUND '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_round(c, &@1, &$3, &$5); + } + | '-' rvalue + { + @1.last_column = @2.last_column; + $$ = gen_rvalue_neg(c, &@1, &$2); + } + | ICIRC '(' rvalue ')' ASL IMM + { + @1.last_column = @6.last_column; + $$ = gen_tmp(c, &@1, 32, UNSIGNED); + OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n"); + gen_rvalue_free(c, &@1, &$3); + } + | CIRCADD '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + gen_circ_op(c, &@1, &$3, &$5, &$7); + } + | LOCNT '(' rvalue ')' + { + @1.last_column = @4.last_column; + /* Leading ones count */ + $$ = gen_locnt_op(c, &@1, &$3); + } + | COUNTONES '(' rvalue ')' + { + @1.last_column = @4.last_column; + /* Ones count */ + $$ = gen_ctpop_op(c, &@1, &$3); + } + | LPCFG + { + $$ = gen_tmp_value(c, &@1, "0", 32, UNSIGNED); + OUT(c, &@1, "GET_USR_FIELD(USR_LPCFG, ", &$$, ");\n"); + } + | EXTRACT '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_extract_op(c, &@1, &$5, &$3, &$1); + } + | EXTRANGE '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + yyassert(c, &@1, $5.type == IMMEDIATE && + $5.imm.type == VALUE && + $7.type == IMMEDIATE && + $7.imm.type == VALUE, + "Range extract needs immediate values!\n"); + $$ = gen_rextract_op(c, + &@1, + &$3, + $7.imm.value, + $5.imm.value - $7.imm.value + 1); + } + | CAST4_8U '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_rvalue_truncate(c, &@1, &$3); + $$.signedness = UNSIGNED; + $$ = rvalue_materialize(c, &@1, &$$); + $$ = gen_rvalue_extend(c, &@1, &$$); + } + | BREV '(' rvalue ')' + { + @1.last_column = @4.last_column; + $$ = gen_rvalue_brev(c, &@1, &$3); + } + | ROTL '(' rvalue ',' rvalue ')' + { + @1.last_column = @6.last_column; + $$ = gen_rotl(c, &@1, &$3, &$5); + } + | ADDSAT64 '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + gen_addsat64(c, &@1, &$3, &$5, &$7); + } + | CARRY_FROM_ADD '(' rvalue ',' rvalue ',' rvalue ')' + { + @1.last_column = @8.last_column; + $$ = gen_carry_from_add(c, &@1, &$3, &$5, &$7); + } + | LSBNEW '(' rvalue ')' + { + @1.last_column = @4.last_column; + HexValue one = gen_imm_value(c, &@1, 1, 32, UNSIGNED); + $$ = gen_bin_op(c, &@1, ANDB_OP, &$3, &one); + } + ; + +lvalue : FAIL + { + @1.last_column = @1.last_column; + yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n"); + } + | REG + { + $$ = $1; + } + | var + { + $$ = $1; + } + ; + +%% + +int main(int argc, char **argv) +{ + if (argc != 5) { + fprintf(stderr, + "Semantics: Hexagon ISA to tinycode generator compiler\n\n"); + fprintf(stderr, + "Usage: ./semantics IDEFS EMITTER_C EMITTER_H " + "ENABLED_INSTRUCTIONS_LIST\n"); + return 1; + } + + enum { + ARG_INDEX_ARGV0 = 0, + ARG_INDEX_IDEFS, + ARG_INDEX_EMITTER_C, + ARG_INDEX_EMITTER_H, + ARG_INDEX_ENABLED_INSTRUCTIONS_LIST + }; + + FILE *enabled_file = fopen(argv[ARG_INDEX_ENABLED_INSTRUCTIONS_LIST], "w"); + + FILE *output_file = fopen(argv[ARG_INDEX_EMITTER_C], "w"); + fputs("#include \"qemu/osdep.h\"\n", output_file); + fputs("#include \"qemu/log.h\"\n", output_file); + fputs("#include \"cpu.h\"\n", output_file); + fputs("#include \"internal.h\"\n", output_file); + fputs("#include \"tcg/tcg-op.h\"\n", output_file); + fputs("#include \"insn.h\"\n", output_file); + fputs("#include \"opcodes.h\"\n", output_file); + fputs("#include \"translate.h\"\n", output_file); + fputs("#define QEMU_GENERATE\n", output_file); + fputs("#include \"genptr.h\"\n", output_file); + fputs("#include \"tcg/tcg.h\"\n", output_file); + fputs("#include \"macros.h\"\n", output_file); + fprintf(output_file, "#include \"%s\"\n", argv[ARG_INDEX_EMITTER_H]); + + FILE *defines_file = fopen(argv[ARG_INDEX_EMITTER_H], "w"); + assert(defines_file != NULL); + fputs("#ifndef HEX_EMITTER_H\n", defines_file); + fputs("#define HEX_EMITTER_H\n", defines_file); + fputs("\n", defines_file); + fputs("#include \"insn.h\"\n\n", defines_file); + + /* Parser input file */ + Context context = { 0 }; + context.defines_file = defines_file; + context.output_file = output_file; + context.enabled_file = enabled_file; + /* Initialize buffers */ + context.out_str = g_string_new(NULL); + context.signature_str = g_string_new(NULL); + context.header_str = g_string_new(NULL); + context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary)); + /* Read input file */ + FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "r"); + fseek(input_file, 0L, SEEK_END); + long input_size = ftell(input_file); + context.input_buffer = (char *) calloc(input_size + 1, sizeof(char)); + fseek(input_file, 0L, SEEK_SET); + size_t read_chars = fread(context.input_buffer, + sizeof(char), + input_size, + input_file); + if (read_chars != (size_t) input_size) { + fprintf(stderr, "Error: an error occurred while reading input file!\n"); + return -1; + } + yylex_init(&context.scanner); + YY_BUFFER_STATE buffer; + buffer = yy_scan_string(context.input_buffer, context.scanner); + /* Start the parsing procedure */ + yyparse(context.scanner, &context); + if (context.implemented_insn != context.total_insn) { + fprintf(stderr, + "Warning: %d/%d meta instructions have been implemented!\n", + context.implemented_insn, + context.total_insn); + } + fputs("#endif " START_COMMENT " HEX_EMITTER_h " END_COMMENT "\n", + defines_file); + /* Cleanup */ + yy_delete_buffer(buffer, context.scanner); + yylex_destroy(context.scanner); + free(context.input_buffer); + g_string_free(context.out_str, TRUE); + g_string_free(context.signature_str, TRUE); + g_string_free(context.header_str, TRUE); + g_array_free(context.ternary, TRUE); + fclose(output_file); + fclose(input_file); + fclose(defines_file); + fclose(enabled_file); + + return 0; +} diff --git a/target/hexagon/idef-parser/macros.inc b/target/hexagon/idef-parser/macros.inc new file mode 100644 index 000000000000..6b697da87a77 --- /dev/null +++ b/target/hexagon/idef-parser/macros.inc @@ -0,0 +1,140 @@ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. 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 + * 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 . + */ + +/* Copy rules */ +#define fLSBOLD(VAL) (fGETBIT(0, VAL)) +#define fSATH(VAL) fSATN(16, VAL) +#define fSATUH(VAL) fSATUN(16, VAL) +#define fVSATH(VAL) fVSATN(16, VAL) +#define fVSATUH(VAL) fVSATUN(16, VAL) +#define fSATUB(VAL) fSATUN(8, VAL) +#define fSATB(VAL) fSATN(8, VAL) +#define fVSATUB(VAL) fVSATUN(8, VAL) +#define fVSATB(VAL) fVSATN(8, VAL) +#define fCALL(A) fWRITE_LR(fREAD_NPC()); fWRITE_NPC(A); +#define fCALLR(A) fWRITE_LR(fREAD_NPC()); fWRITE_NPC(A); +#define fCAST2_8s(A) fSXTN(16, 64, A) +#define fCAST2_8u(A) fZXTN(16, 64, A) +#define fVSATW(A) fVSATN(32, fCAST8_8s(A)) +#define fSATW(A) fSATN(32, fCAST8_8s(A)) +#define fVSAT(A) fVSATN(32, A) +#define fSAT(A) fSATN(32, A) + +/* Ease parsing */ +#define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00) +#define fREAD_GP() (Constant_extended ? (0) : GP) +#define fCLIP(DST, SRC, U) (DST = fMIN((1 << U) - 1, fMAX(SRC, -(1 << U)))) +#define fBIDIR_ASHIFTL(SRC, SHAMT, REGSTYPE) \ + ((SHAMT > 0) ? \ + (fCAST##REGSTYPE##s(SRC) << SHAMT) : \ + (fCAST##REGSTYPE##s(SRC) >> -SHAMT)) + +#define fBIDIR_LSHIFTL(SRC, SHAMT, REGSTYPE) \ + ((SHAMT > 0) ? \ + (fCAST##REGSTYPE##u(SRC) << SHAMT) : \ + (fCAST##REGSTYPE##u(SRC) >>> -SHAMT)) + +#define fBIDIR_ASHIFTR(SRC, SHAMT, REGSTYPE) \ + ((SHAMT > 0) ? \ + (fCAST##REGSTYPE##s(SRC) >> SHAMT) : \ + (fCAST##REGSTYPE##s(SRC) << -SHAMT)) + +#define fBIDIR_SHIFTR(SRC, SHAMT, REGSTYPE) \ + (((SHAMT) < 0) ? ((fCAST##REGSTYPE(SRC) << ((-(SHAMT)) - 1)) << 1) \ + : (fCAST##REGSTYPE(SRC) >> (SHAMT))) + +#define fBIDIR_LSHIFTR(SRC, SHAMT, REGSTYPE) \ + fBIDIR_SHIFTR(SRC, SHAMT, REGSTYPE##u) + +#define fSATVALN(N, VAL) \ + fSET_OVERFLOW( \ + ((VAL) < 0) ? (-(1LL << ((N) - 1))) : ((1LL << ((N) - 1)) - 1) \ + ) + +#define fSAT_ORIG_SHL(A, ORIG_REG) \ + (((fCAST4s((fSAT(A)) ^ (fCAST4s(ORIG_REG)))) < 0) \ + ? fSATVALN(32, (fCAST4s(ORIG_REG))) \ + : ((((ORIG_REG) > 0) && ((A) == 0)) ? fSATVALN(32, (ORIG_REG)) \ + : fSAT(A))) + +#define fBIDIR_ASHIFTR_SAT(SRC, SHAMT, REGSTYPE) \ + (((SHAMT) < 0) ? fSAT_ORIG_SHL((fCAST##REGSTYPE##s(SRC) \ + << ((-(SHAMT)) - 1)) << 1, (SRC)) \ + : (fCAST##REGSTYPE##s(SRC) >> (SHAMT))) + +#define fBIDIR_ASHIFTL_SAT(SRC, SHAMT, REGSTYPE) \ + (((SHAMT) < 0) \ + ? ((fCAST##REGSTYPE##s(SRC) >> ((-(SHAMT)) - 1)) >> 1) \ + : fSAT_ORIG_SHL(fCAST##REGSTYPE##s(SRC) << (SHAMT), (SRC))) + +#define fEXTRACTU_BIDIR(INREG, WIDTH, OFFSET) \ + (fZXTN(WIDTH, 32, fBIDIR_LSHIFTR((INREG), (OFFSET), 4_8))) + +/* Least significant bit operations */ +#define fLSBNEW0 fLSBNEW(P0N) +#define fLSBNEW1 fLSBNEW(P1N) +#define fLSBOLDNOT(VAL) fGETBIT(0, ~VAL) +#define fLSBNEWNOT(PRED) (fLSBNEW(~PRED)) +#define fLSBNEW0NOT fLSBNEW(~P0N) +#define fLSBNEW1NOT fLSBNEW(~P1N) + +/* Assignments */ +#define fPCALIGN(IMM) (IMM = IMM & ~3) +#define fWRITE_LR(A) (LR = A) +#define fWRITE_FP(A) (FP = A) +#define fWRITE_SP(A) (SP = A) +/* + * Note: There is a rule in the parser that matches `PC = ...` and emits + * a call to `gen_write_new_pc`. We need to call `gen_write_new_pc` to + * get the correct semantics when there are multiple stores in a packet. + */ +#define fBRANCH(LOC, TYPE) (PC = LOC) +#define fJUMPR(REGNO, TARGET, TYPE) (PC = TARGET) +#define fWRITE_LOOP_REGS0(START, COUNT) SA0 = START; (LC0 = COUNT) +#define fWRITE_LOOP_REGS1(START, COUNT) SA1 = START; (LC1 = COUNT) +#define fWRITE_LC0(VAL) (LC0 = VAL) +#define fWRITE_LC1(VAL) (LC1 = VAL) +#define fSET_LPCFG(VAL) (USR.LPCFG = VAL) +#define fWRITE_P0(VAL) P0 = VAL; +#define fWRITE_P1(VAL) P1 = VAL; +#define fWRITE_P3(VAL) P3 = VAL; +#define fEA_RI(REG, IMM) (EA = REG + IMM) +#define fEA_RRs(REG, REG2, SCALE) (EA = REG + (REG2 << SCALE)) +#define fEA_IRs(IMM, REG, SCALE) (EA = IMM + (REG << SCALE)) +#define fEA_IMM(IMM) (EA = IMM) +#define fEA_REG(REG) (EA = REG) +#define fEA_BREVR(REG) (EA = fbrev(REG)) +#define fEA_GPI(IMM) (EA = fREAD_GP() + IMM) +#define fPM_I(REG, IMM) (REG = REG + IMM) +#define fPM_M(REG, MVAL) (REG = REG + MVAL) +#define fWRITE_NPC(VAL) (PC = VAL) + +/* Unary operators */ +#define fROUND(A) (A + 0x8000) + +/* Binary operators */ +#define fSCALE(N, A) (A << N) +#define fASHIFTR(SRC, SHAMT, REGSTYPE) (fCAST##REGSTYPE##s(SRC) >> SHAMT) +#define fLSHIFTR(SRC, SHAMT, REGSTYPE) (SRC >>> SHAMT) +#define fROTL(SRC, SHAMT, REGSTYPE) fROTL(SRC, SHAMT) +#define fASHIFTL(SRC, SHAMT, REGSTYPE) (fCAST##REGSTYPE##s(SRC) << SHAMT) + +/* Include fHIDE macros which hide type declarations */ +#define fHIDE(A) A + +/* Purge non-relavant parts */ +#define fBRANCH_SPECULATE_STALL(A, B, C, D, E) diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c new file mode 100644 index 000000000000..8110686c5111 --- /dev/null +++ b/target/hexagon/idef-parser/parser-helpers.c @@ -0,0 +1,2360 @@ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. 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 + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "idef-parser.h" +#include "parser-helpers.h" +#include "idef-parser.tab.h" +#include "idef-parser.yy.h" + +void yyerror(YYLTYPE *locp, + yyscan_t scanner __attribute__((unused)), + Context *c, + const char *s) +{ + const char *code_ptr = c->input_buffer; + + fprintf(stderr, "WARNING (%s): '%s'\n", c->inst.name->str, s); + + fprintf(stderr, "Problematic range: "); + for (int i = locp->first_column; i < locp->last_column; i++) { + if (code_ptr[i] != '\n') { + fprintf(stderr, "%c", code_ptr[i]); + } + } + fprintf(stderr, "\n"); + + for (unsigned i = 0; + i < 80 && + code_ptr[locp->first_column - 10 + i] != '\0' && + code_ptr[locp->first_column - 10 + i] != '\n'; + i++) { + fprintf(stderr, "%c", code_ptr[locp->first_column - 10 + i]); + } + fprintf(stderr, "\n"); + for (unsigned i = 0; i < 9; i++) { + fprintf(stderr, " "); + } + fprintf(stderr, "^"); + for (int i = 0; i < (locp->last_column - locp->first_column) - 1; i++) { + fprintf(stderr, "~"); + } + fprintf(stderr, "\n"); + c->inst.error_count++; +} + +bool is_direct_predicate(HexValue *value) +{ + return value->pred.id >= '0' && value->pred.id <= '3'; +} + +bool is_inside_ternary(Context *c) +{ + return c->ternary->len > 0; +} + +/* Print functions */ +void str_print(Context *c, YYLTYPE *locp, const char *string) +{ + (void) locp; + EMIT(c, "%s", string); +} + +void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num) +{ + (void) locp; + EMIT(c, "%u", *num); +} + +void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num) +{ + (void) locp; + EMIT(c, "%" PRIu64, *num); +} + +void int_print(Context *c, YYLTYPE *locp, int *num) +{ + (void) locp; + EMIT(c, "%d", *num); +} + +void uint_print(Context *c, YYLTYPE *locp, unsigned *num) +{ + (void) locp; + EMIT(c, "%u", *num); +} + +void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp) +{ + (void) locp; + EMIT(c, "tmp_%d", tmp->index); +} + +void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew) +{ + (void) locp; + char suffix = is_dotnew ? 'N' : 'V'; + EMIT(c, "P%c%c", pred->id, suffix); +} + +void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5]) +{ + memset(reg_id, 0, 5 * sizeof(char)); + switch (reg->type) { + case GENERAL_PURPOSE: + reg_id[0] = 'R'; + break; + case CONTROL: + reg_id[0] = 'C'; + break; + case MODIFIER: + reg_id[0] = 'M'; + break; + case DOTNEW: + reg_id[0] = 'N'; + reg_id[1] = reg->id; + reg_id[2] = 'N'; + return; + } + switch (reg->bit_width) { + case 32: + reg_id[1] = reg->id; + reg_id[2] = 'V'; + break; + case 64: + reg_id[1] = reg->id; + reg_id[2] = reg->id; + reg_id[3] = 'V'; + break; + default: + yyassert(c, locp, false, "Unhandled register bit width!\n"); + } +} + +static void reg_arg_print(Context *c, YYLTYPE *locp, HexReg *reg) +{ + char reg_id[5]; + reg_compose(c, locp, reg, reg_id); + EMIT(c, "%s", reg_id); +} + +void reg_print(Context *c, YYLTYPE *locp, HexReg *reg) +{ + (void) locp; + EMIT(c, "hex_gpr[%u]", reg->id); +} + +void imm_print(Context *c, YYLTYPE *locp, HexImm *imm) +{ + switch (imm->type) { + case I: + EMIT(c, "i"); + break; + case VARIABLE: + EMIT(c, "%ciV", imm->id); + break; + case VALUE: + EMIT(c, "((int64_t) %" PRIu64 "ULL)", (int64_t) imm->value); + break; + case QEMU_TMP: + EMIT(c, "qemu_tmp_%" PRIu64, imm->index); + break; + case IMM_PC: + EMIT(c, "ctx->base.pc_next"); + break; + case IMM_NPC: + EMIT(c, "ctx->npc"); + break; + case IMM_CONSTEXT: + EMIT(c, "insn->extension_valid"); + break; + default: + yyassert(c, locp, false, "Cannot print this expression!"); + } +} + +void var_print(Context *c, YYLTYPE *locp, HexVar *var) +{ + (void) locp; + EMIT(c, "%s", var->name->str); +} + +void rvalue_print(Context *c, YYLTYPE *locp, void *pointer) +{ + HexValue *rvalue = (HexValue *) pointer; + switch (rvalue->type) { + case REGISTER: + reg_print(c, locp, &rvalue->reg); + break; + case REGISTER_ARG: + reg_arg_print(c, locp, &rvalue->reg); + break; + case TEMP: + tmp_print(c, locp, &rvalue->tmp); + break; + case IMMEDIATE: + imm_print(c, locp, &rvalue->imm); + break; + case VARID: + var_print(c, locp, &rvalue->var); + break; + case PREDICATE: + pred_print(c, locp, &rvalue->pred, rvalue->is_dotnew); + break; + default: + yyassert(c, locp, false, "Cannot print this expression!"); + } +} + +void out_assert(Context *c, YYLTYPE *locp, + void *dummy __attribute__((unused))) +{ + yyassert(c, locp, false, "Unhandled print type!"); +} + +/* Copy output code buffer */ +void commit(Context *c) +{ + /* Emit instruction pseudocode */ + EMIT_SIG(c, "\n" START_COMMENT " "); + for (char *x = c->inst.code_begin; x < c->inst.code_end; x++) { + EMIT_SIG(c, "%c", *x); + } + EMIT_SIG(c, " " END_COMMENT "\n"); + + /* Commit instruction code to output file */ + fwrite(c->signature_str->str, sizeof(char), c->signature_str->len, + c->output_file); + fwrite(c->header_str->str, sizeof(char), c->header_str->len, + c->output_file); + fwrite(c->out_str->str, sizeof(char), c->out_str->len, + c->output_file); + + fwrite(c->signature_str->str, sizeof(char), c->signature_str->len, + c->defines_file); + fprintf(c->defines_file, ";\n"); +} + +static void gen_c_int_type(Context *c, YYLTYPE *locp, unsigned bit_width, + HexSignedness signedness) +{ + const char *signstr = (signedness == UNSIGNED) ? "u" : ""; + OUT(c, locp, signstr, "int", &bit_width, "_t"); +} + +static HexValue gen_constant(Context *c, + YYLTYPE *locp, + const char *value, + unsigned bit_width, + HexSignedness signedness) +{ + HexValue rvalue; + assert(bit_width == 32 || bit_width == 64); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = TEMP; + rvalue.bit_width = bit_width; + rvalue.signedness = signedness; + rvalue.is_dotnew = false; + rvalue.is_manual = true; + rvalue.tmp.index = c->inst.tmp_count; + OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count, + " = tcg_constant_i", &bit_width, "(", value, ");\n"); + c->inst.tmp_count++; + return rvalue; +} + +/* Temporary values creation */ +HexValue gen_tmp(Context *c, + YYLTYPE *locp, + unsigned bit_width, + HexSignedness signedness) +{ + HexValue rvalue; + assert(bit_width == 32 || bit_width == 64); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = TEMP; + rvalue.bit_width = bit_width; + rvalue.signedness = signedness; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + rvalue.tmp.index = c->inst.tmp_count; + OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count, + " = tcg_temp_new_i", &bit_width, "();\n"); + c->inst.tmp_count++; + return rvalue; +} + +HexValue gen_tmp_local(Context *c, + YYLTYPE *locp, + unsigned bit_width, + HexSignedness signedness) +{ + HexValue rvalue; + assert(bit_width == 32 || bit_width == 64); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = TEMP; + rvalue.bit_width = bit_width; + rvalue.signedness = signedness; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + rvalue.tmp.index = c->inst.tmp_count; + OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count, + " = tcg_temp_local_new_i", &bit_width, "();\n"); + c->inst.tmp_count++; + return rvalue; +} + +HexValue gen_tmp_value(Context *c, + YYLTYPE *locp, + const char *value, + unsigned bit_width, + HexSignedness signedness) +{ + HexValue rvalue; + assert(bit_width == 32 || bit_width == 64); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = TEMP; + rvalue.bit_width = bit_width; + rvalue.signedness = signedness; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + rvalue.tmp.index = c->inst.tmp_count; + OUT(c, locp, "TCGv_i", &bit_width, " tmp_", &c->inst.tmp_count, + " = tcg_const_i", &bit_width, "(", value, ");\n"); + c->inst.tmp_count++; + return rvalue; +} + +static HexValue gen_tmp_value_from_imm(Context *c, + YYLTYPE *locp, + HexValue *value) +{ + HexValue rvalue; + assert(value->type == IMMEDIATE); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = TEMP; + rvalue.bit_width = value->bit_width; + rvalue.signedness = value->signedness; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + rvalue.tmp.index = c->inst.tmp_count; + /* + * Here we output the call to `tcg_const_i` in + * order to create the temporary value. Note, that we + * add a cast + * + * `tcg_const_i`((int_t) ...)` + * + * This cast is required to avoid implicit integer + * conversion warnings since all immediates are + * output as `((int64_t) 123ULL)`, even if the + * integer is 32-bit. + */ + OUT(c, locp, "TCGv_i", &rvalue.bit_width, " tmp_", &c->inst.tmp_count); + OUT(c, locp, " = tcg_const_i", &rvalue.bit_width, + "((int", &rvalue.bit_width, "_t) (", value, "));\n"); + + c->inst.tmp_count++; + return rvalue; +} + +HexValue gen_imm_value(Context *c __attribute__((unused)), + YYLTYPE *locp, + int value, + unsigned bit_width, + HexSignedness signedness) +{ + (void) locp; + HexValue rvalue; + assert(bit_width == 32 || bit_width == 64); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.bit_width = bit_width; + rvalue.signedness = signedness; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + rvalue.imm.type = VALUE; + rvalue.imm.value = value; + return rvalue; +} + +HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width, + HexSignedness signedness) +{ + (void) locp; + HexValue rvalue; + assert(bit_width == 32 || bit_width == 64); + memset(&rvalue, 0, sizeof(HexValue)); + rvalue.type = IMMEDIATE; + rvalue.is_dotnew = false; + rvalue.is_manual = false; + rvalue.bit_width = bit_width; + rvalue.signedness = signedness; + rvalue.imm.type = QEMU_TMP; + rvalue.imm.index = c->inst.qemu_tmp_count++; + return rvalue; +} + +void gen_rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue) +{ + if (rvalue->type == TEMP && !rvalue->is_manual) { + const char *bit_suffix = (rvalue->bit_width == 64) ? "i64" : "i32"; + OUT(c, locp, "tcg_temp_free_", bit_suffix, "(", rvalue, ");\n"); + } +} + +static void gen_rvalue_free_manual(Context *c, YYLTYPE *locp, HexValue *rvalue) +{ + rvalue->is_manual = false; + gen_rvalue_free(c, locp, rvalue); +} + +HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue) +{ + if (rvalue->type == IMMEDIATE) { + HexValue res = gen_tmp_value_from_imm(c, locp, rvalue); + gen_rvalue_free(c, locp, rvalue); + return res; + } + return *rvalue; +} + +HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue) +{ + assert_signedness(c, locp, rvalue->signedness); + if (rvalue->bit_width > 32) { + return *rvalue; + } + + if (rvalue->type == IMMEDIATE) { + HexValue res = gen_imm_qemu_tmp(c, locp, 64, rvalue->signedness); + bool is_unsigned = (rvalue->signedness == UNSIGNED); + const char *sign_suffix = is_unsigned ? "u" : ""; + gen_c_int_type(c, locp, 64, rvalue->signedness); + OUT(c, locp, " ", &res, " = "); + OUT(c, locp, "(", sign_suffix, "int64_t) "); + OUT(c, locp, "(", sign_suffix, "int32_t) "); + OUT(c, locp, rvalue, ";\n"); + return res; + } else { + HexValue res = gen_tmp(c, locp, 64, rvalue->signedness); + bool is_unsigned = (rvalue->signedness == UNSIGNED); + const char *sign_suffix = is_unsigned ? "u" : ""; + OUT(c, locp, "tcg_gen_ext", sign_suffix, + "_i32_i64(", &res, ", ", rvalue, ");\n"); + gen_rvalue_free(c, locp, rvalue); + return res; + } +} + +HexValue gen_rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue) +{ + if (rvalue->type == IMMEDIATE) { + HexValue res = *rvalue; + res.bit_width = 32; + return res; + } else { + if (rvalue->bit_width == 64) { + HexValue res = gen_tmp(c, locp, 32, rvalue->signedness); + OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", rvalue, ");\n"); + gen_rvalue_free(c, locp, rvalue); + return res; + } + } + return *rvalue; +} + +/* + * Attempts to lookup the `Var` struct associated with the given `varid`. + * The `dst` argument is populated with the found name, bit_width, and + * signedness, given that `dst` is non-NULL. Returns true if the lookup + * succeeded and false otherwise. + */ +static bool try_find_variable(Context *c, YYLTYPE *locp, + HexValue *dst, + HexValue *varid) +{ + yyassert(c, locp, varid, "varid to lookup is NULL"); + yyassert(c, locp, varid->type == VARID, + "Can only lookup variables by varid"); + for (unsigned i = 0; i < c->inst.allocated->len; i++) { + Var *curr = &g_array_index(c->inst.allocated, Var, i); + if (g_string_equal(varid->var.name, curr->name)) { + if (dst) { + dst->var.name = curr->name; + dst->bit_width = curr->bit_width; + dst->signedness = curr->signedness; + } + return true; + } + } + return false; +} + +/* Calls `try_find_variable` and asserts succcess. */ +static void find_variable(Context *c, YYLTYPE *locp, + HexValue *dst, + HexValue *varid) +{ + bool found = try_find_variable(c, locp, dst, varid); + yyassert(c, locp, found, "Use of undeclared variable!\n"); +} + +/* Handle signedness, if both unsigned -> result is unsigned, else signed */ +static inline HexSignedness bin_op_signedness(Context *c, YYLTYPE *locp, + HexSignedness sign1, + HexSignedness sign2) +{ + assert_signedness(c, locp, sign1); + assert_signedness(c, locp, sign2); + return (sign1 == UNSIGNED && sign2 == UNSIGNED) ? UNSIGNED : SIGNED; +} + +void gen_varid_allocate(Context *c, + YYLTYPE *locp, + HexValue *varid, + unsigned bit_width, + HexSignedness signedness) +{ + const char *bit_suffix = (bit_width == 64) ? "i64" : "i32"; + bool found = try_find_variable(c, locp, NULL, varid); + Var new_var; + + memset(&new_var, 0, sizeof(Var)); + + yyassert(c, locp, !found, "Redeclaration of variables not allowed!"); + assert_signedness(c, locp, signedness); + + /* `varid` only carries name information */ + new_var.name = varid->var.name; + new_var.bit_width = bit_width; + new_var.signedness = signedness; + + EMIT_HEAD(c, "TCGv_%s %s", bit_suffix, varid->var.name->str); + EMIT_HEAD(c, " = tcg_temp_local_new_%s();\n", bit_suffix); + g_array_append_val(c->inst.allocated, new_var); +} + +enum OpTypes { + IMM_IMM = 0, + IMM_REG = 1, + REG_IMM = 2, + REG_REG = 3, +}; + +HexValue gen_bin_cmp(Context *c, + YYLTYPE *locp, + TCGCond type, + HexValue *op1, + HexValue *op2) +{ + HexValue op1_m = *op1; + HexValue op2_m = *op2; + enum OpTypes op_types = (op1_m.type != IMMEDIATE) << 1 + | (op2_m.type != IMMEDIATE); + + bool op_is64bit = op1_m.bit_width == 64 || op2_m.bit_width == 64; + const char *bit_suffix = op_is64bit ? "i64" : "i32"; + unsigned bit_width = (op_is64bit) ? 64 : 32; + HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED); + + /* Extend to 64-bits, if required */ + if (op_is64bit) { + op1_m = gen_rvalue_extend(c, locp, &op1_m); + op2_m = gen_rvalue_extend(c, locp, &op2_m); + } + + switch (op_types) { + case IMM_IMM: + case IMM_REG: + yyassert(c, locp, false, "Binary comparisons between IMM op IMM and" + "IMM op REG not handled!"); + break; + case REG_IMM: + OUT(c, locp, "tcg_gen_setcondi_", bit_suffix, "("); + OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1_m, ", ", &op2_m, + ");\n"); + break; + case REG_REG: + OUT(c, locp, "tcg_gen_setcond_", bit_suffix, "("); + OUT(c, locp, cond_to_str(type), ", ", &res, ", ", &op1_m, ", ", &op2_m, + ");\n"); + break; + default: + fprintf(stderr, "Error in evalutating immediateness!"); + abort(); + } + + /* Free operands */ + gen_rvalue_free(c, locp, &op1_m); + gen_rvalue_free(c, locp, &op2_m); + + return res; +} + +static void gen_simple_op(Context *c, YYLTYPE *locp, unsigned bit_width, + const char *bit_suffix, HexValue *res, + enum OpTypes op_types, + HexValue *op1, + HexValue *op2, + const char *imm_imm, + const char *imm_reg, + const char *reg_imm, + const char *reg_reg) +{ + switch (op_types) { + case IMM_IMM: { + HexSignedness signedness = bin_op_signedness(c, locp, + op1->signedness, + op2->signedness); + gen_c_int_type(c, locp, bit_width, signedness); + OUT(c, locp, " ", res, + " = ", op1, imm_imm, op2, ";\n"); + } break; + case IMM_REG: + OUT(c, locp, imm_reg, bit_suffix, + "(", res, ", ", op2, ", ", op1, ");\n"); + break; + case REG_IMM: + OUT(c, locp, reg_imm, bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + break; + case REG_REG: + OUT(c, locp, reg_reg, bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + break; + } + gen_rvalue_free(c, locp, op1); + gen_rvalue_free(c, locp, op2); +} + +static void gen_sub_op(Context *c, YYLTYPE *locp, unsigned bit_width, + const char *bit_suffix, HexValue *res, + enum OpTypes op_types, HexValue *op1, + HexValue *op2) +{ + switch (op_types) { + case IMM_IMM: { + HexSignedness signedness = bin_op_signedness(c, locp, + op1->signedness, + op2->signedness); + gen_c_int_type(c, locp, bit_width, signedness); + OUT(c, locp, " ", res, + " = ", op1, " - ", op2, ";\n"); + } break; + case IMM_REG: { + OUT(c, locp, "tcg_gen_subfi_", bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + } break; + case REG_IMM: { + OUT(c, locp, "tcg_gen_subi_", bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + } break; + case REG_REG: { + OUT(c, locp, "tcg_gen_sub_", bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + } break; + } + gen_rvalue_free(c, locp, op1); + gen_rvalue_free(c, locp, op2); +} + +static void gen_asl_op(Context *c, YYLTYPE *locp, unsigned bit_width, + bool op_is64bit, const char *bit_suffix, + HexValue *res, enum OpTypes op_types, + HexValue *op1, HexValue *op2) +{ + HexValue op1_m = *op1; + HexValue op2_m = *op2; + switch (op_types) { + case IMM_IMM: { + HexSignedness signedness = bin_op_signedness(c, locp, + op1->signedness, + op2->signedness); + gen_c_int_type(c, locp, bit_width, signedness); + OUT(c, locp, " ", res, + " = ", op1, " << ", op2, ";\n"); + } break; + case REG_IMM: { + OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n"); + OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n"); + OUT(c, locp, "} else {\n"); + OUT(c, locp, "tcg_gen_shli_", bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + OUT(c, locp, "}\n"); + } break; + case IMM_REG: + op1_m.bit_width = bit_width; + op1_m = rvalue_materialize(c, locp, &op1_m); + /* fallthrough */ + case REG_REG: { + OUT(c, locp, "tcg_gen_shl_", bit_suffix, + "(", res, ", ", &op1_m, ", ", op2, ");\n"); + } break; + } + if (op_types == IMM_REG || op_types == REG_REG) { + /* + * Handle left shift by 64/32 which hexagon-sim expects to clear out + * register + */ + HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED); + HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED); + edge = rvalue_materialize(c, locp, &edge); + if (op_is64bit) { + op2_m = gen_rvalue_extend(c, locp, &op2_m); + } + op1_m = rvalue_materialize(c, locp, &op1_m); + op2_m = rvalue_materialize(c, locp, &op2_m); + OUT(c, locp, "tcg_gen_movcond_i", &bit_width); + OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge); + OUT(c, locp, ", ", &zero, ", ", res, ");\n"); + gen_rvalue_free(c, locp, &edge); + } + gen_rvalue_free(c, locp, &op1_m); + gen_rvalue_free(c, locp, &op2_m); +} + +static void gen_asr_op(Context *c, YYLTYPE *locp, unsigned bit_width, + bool op_is64bit, const char *bit_suffix, + HexValue *res, enum OpTypes op_types, + HexValue *op1, HexValue *op2) +{ + HexValue op1_m = *op1; + HexValue op2_m = *op2; + switch (op_types) { + case IMM_IMM: + case IMM_REG: + yyassert(c, locp, false, "ASR between IMM op IMM, and IMM op REG" + " not handled!"); + break; + case REG_IMM: { + HexSignedness signedness = bin_op_signedness(c, locp, + op1->signedness, + op2->signedness); + OUT(c, locp, "{\n"); + gen_c_int_type(c, locp, bit_width, signedness); + OUT(c, locp, " shift = ", op2, ";\n"); + OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n"); + OUT(c, locp, " shift = ", &bit_width, " - 1;\n"); + OUT(c, locp, "}\n"); + OUT(c, locp, "tcg_gen_sari_", bit_suffix, + "(", res, ", ", op1, ", shift);\n}\n"); + } break; + case REG_REG: + OUT(c, locp, "tcg_gen_sar_", bit_suffix, + "(", res, ", ", &op1_m, ", ", op2, ");\n"); + break; + } + if (op_types == REG_REG) { + /* Handle right shift by values >= bit_width */ + const char *offset = op_is64bit ? "63" : "31"; + HexValue tmp = gen_tmp(c, locp, bit_width, SIGNED); + HexValue zero = gen_constant(c, locp, "0", bit_width, SIGNED); + HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED); + + edge = rvalue_materialize(c, locp, &edge); + if (op_is64bit) { + op2_m = gen_rvalue_extend(c, locp, &op2_m); + } + op1_m = rvalue_materialize(c, locp, &op1_m); + op2_m = rvalue_materialize(c, locp, &op2_m); + + OUT(c, locp, "tcg_gen_extract_", bit_suffix, "(", + &tmp, ", ", &op1_m, ", ", offset, ", 1);\n"); + OUT(c, locp, "tcg_gen_sub_", bit_suffix, "(", + &tmp, ", ", &zero, ", ", &tmp, ");\n"); + OUT(c, locp, "tcg_gen_movcond_i", &bit_width); + OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge); + OUT(c, locp, ", ", &tmp, ", ", res, ");\n"); + gen_rvalue_free(c, locp, &edge); + gen_rvalue_free(c, locp, &tmp); + } + gen_rvalue_free(c, locp, &op1_m); + gen_rvalue_free(c, locp, &op2_m); +} + +static void gen_lsr_op(Context *c, YYLTYPE *locp, unsigned bit_width, + bool op_is64bit, const char *bit_suffix, + HexValue *res, enum OpTypes op_types, + HexValue *op1, HexValue *op2) +{ + HexValue op1_m = *op1; + HexValue op2_m = *op2; + switch (op_types) { + case IMM_IMM: + case IMM_REG: + yyassert(c, locp, false, "LSR between IMM op IMM, and IMM op REG" + " not handled!"); + break; + case REG_IMM: + OUT(c, locp, "if (", op2, " >= ", &bit_width, ") {\n"); + OUT(c, locp, "tcg_gen_movi_", bit_suffix, "(", res, ", 0);\n"); + OUT(c, locp, "} else {\n"); + OUT(c, locp, "tcg_gen_shri_", bit_suffix, + "(", res, ", ", op1, ", ", op2, ");\n"); + OUT(c, locp, "}\n"); + break; + case REG_REG: + OUT(c, locp, "tcg_gen_shr_", bit_suffix, + "(", res, ", ", &op1_m, ", ", op2, ");\n"); + break; + } + if (op_types == REG_REG) { + /* Handle right shift by values >= bit_width */ + HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED); + HexValue edge = gen_imm_value(c, locp, bit_width, bit_width, UNSIGNED); + edge = rvalue_materialize(c, locp, &edge); + if (op_is64bit) { + op2_m = gen_rvalue_extend(c, locp, &op2_m); + } + op1_m = rvalue_materialize(c, locp, &op1_m); + op2_m = rvalue_materialize(c, locp, &op2_m); + OUT(c, locp, "tcg_gen_movcond_i", &bit_width); + OUT(c, locp, "(TCG_COND_GEU, ", res, ", ", &op2_m, ", ", &edge); + OUT(c, locp, ", ", &zero, ", ", res, ");\n"); + gen_rvalue_free(c, locp, &edge); + } + gen_rvalue_free(c, locp, &op1_m); + gen_rvalue_free(c, locp, &op2_m); +} + +/* + * Note: This implementation of logical `and` does not mirror that in C. + * We do not short-circuit logical expressions! + */ +static void gen_andl_op(Context *c, YYLTYPE *locp, unsigned bit_width, + const char *bit_suffix, HexValue *res, + enum OpTypes op_types, HexValue *op1, + HexValue *op2) +{ + (void) bit_width; + HexValue tmp1, tmp2; + HexValue zero = gen_constant(c, locp, "0", 32, UNSIGNED); + memset(&tmp1, 0, sizeof(HexValue)); + memset(&tmp2, 0, sizeof(HexValue)); + switch (op_types) { + case IMM_IMM: + case IMM_REG: + case REG_IMM: + yyassert(c, locp, false, "ANDL between IMM op IMM, IMM op REG, and" + " REG op IMM, not handled!"); + break; + case REG_REG: + tmp1 = gen_bin_cmp(c, locp, TCG_COND_NE, op1, &zero); + tmp2 = gen_bin_cmp(c, locp, TCG_COND_NE, op2, &zero); + OUT(c, locp, "tcg_gen_and_", bit_suffix, + "(", res, ", ", &tmp1, ", ", &tmp2, ");\n"); + gen_rvalue_free_manual(c, locp, &zero); + gen_rvalue_free(c, locp, &tmp1); + gen_rvalue_free(c, locp, &tmp2); + break; + } +} + +static void gen_minmax_op(Context *c, YYLTYPE *locp, unsigned bit_width, + HexValue *res, enum OpTypes op_types, + HexValue *op1, HexValue *op2, bool minmax) +{ + const char *mm; + HexValue op1_m = *op1; + HexValue op2_m = *op2; + bool is_unsigned; + + assert_signedness(c, locp, res->signedness); + is_unsigned = res->signedness == UNSIGNED; + + if (minmax) { + /* Max */ + mm = is_unsigned ? "tcg_gen_umax" : "tcg_gen_smax"; + } else { + /* Min */ + mm = is_unsigned ? "tcg_gen_umin" : "tcg_gen_smin"; + } + switch (op_types) { + case IMM_IMM: + yyassert(c, locp, false, "MINMAX between IMM op IMM, not handled!"); + break; + case IMM_REG: + op1_m.bit_width = bit_width; + op1_m = rvalue_materialize(c, locp, &op1_m); + OUT(c, locp, mm, "_i", &bit_width, "("); + OUT(c, locp, res, ", ", &op1_m, ", ", op2, ");\n"); + break; + case REG_IMM: + op2_m.bit_width = bit_width; + op2_m = rvalue_materialize(c, locp, &op2_m); + /* Fallthrough */ + case REG_REG: + OUT(c, locp, mm, "_i", &bit_width, "("); + OUT(c, locp, res, ", ", op1, ", ", &op2_m, ");\n"); + break; + } + gen_rvalue_free(c, locp, &op1_m); + gen_rvalue_free(c, locp, &op2_m); +} + +/* Code generation functions */ +HexValue gen_bin_op(Context *c, + YYLTYPE *locp, + OpType type, + HexValue *op1, + HexValue *op2) +{ + /* Replicate operands to avoid side effects */ + HexValue op1_m = *op1; + HexValue op2_m = *op2; + enum OpTypes op_types; + bool op_is64bit; + HexSignedness signedness; + unsigned bit_width; + const char *bit_suffix; + HexValue res; + + memset(&res, 0, sizeof(HexValue)); + + /* + * If the operands are VARID's we need to look up the + * type information. + */ + if (op1_m.type == VARID) { + find_variable(c, locp, &op1_m, &op1_m); + } + if (op2_m.type == VARID) { + find_variable(c, locp, &op2_m, &op2_m); + } + + op_types = (op1_m.type != IMMEDIATE) << 1 + | (op2_m.type != IMMEDIATE); + op_is64bit = op1_m.bit_width == 64 || op2_m.bit_width == 64; + /* Shift greater than 32 are 64 bits wide */ + + if (type == ASL_OP && op2_m.type == IMMEDIATE && + op2_m.imm.type == VALUE && op2_m.imm.value >= 32) { + op_is64bit = true; + } + + bit_width = (op_is64bit) ? 64 : 32; + bit_suffix = op_is64bit ? "i64" : "i32"; + + /* Extend to 64-bits, if required */ + if (op_is64bit) { + op1_m = gen_rvalue_extend(c, locp, &op1_m); + op2_m = gen_rvalue_extend(c, locp, &op2_m); + } + + signedness = bin_op_signedness(c, locp, op1_m.signedness, op2_m.signedness); + if (op_types != IMM_IMM) { + res = gen_tmp(c, locp, bit_width, signedness); + } else { + res = gen_imm_qemu_tmp(c, locp, bit_width, signedness); + } + + switch (type) { + case ADD_OP: + gen_simple_op(c, locp, bit_width, bit_suffix, &res, + op_types, &op1_m, &op2_m, + " + ", + "tcg_gen_addi_", + "tcg_gen_addi_", + "tcg_gen_add_"); + break; + case SUB_OP: + gen_sub_op(c, locp, bit_width, bit_suffix, &res, op_types, + &op1_m, &op2_m); + break; + case MUL_OP: + gen_simple_op(c, locp, bit_width, bit_suffix, &res, + op_types, &op1_m, &op2_m, + " * ", + "tcg_gen_muli_", + "tcg_gen_muli_", + "tcg_gen_mul_"); + break; + case ASL_OP: + gen_asl_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types, + &op1_m, &op2_m); + break; + case ASR_OP: + gen_asr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types, + &op1_m, &op2_m); + break; + case LSR_OP: + gen_lsr_op(c, locp, bit_width, op_is64bit, bit_suffix, &res, op_types, + &op1_m, &op2_m); + break; + case ANDB_OP: + gen_simple_op(c, locp, bit_width, bit_suffix, &res, + op_types, &op1_m, &op2_m, + " & ", + "tcg_gen_andi_", + "tcg_gen_andi_", + "tcg_gen_and_"); + break; + case ORB_OP: + gen_simple_op(c, locp, bit_width, bit_suffix, &res, + op_types, &op1_m, &op2_m, + " | ", + "tcg_gen_ori_", + "tcg_gen_ori_", + "tcg_gen_or_"); + break; + case XORB_OP: + gen_simple_op(c, locp, bit_width, bit_suffix, &res, + op_types, &op1_m, &op2_m, + " ^ ", + "tcg_gen_xori_", + "tcg_gen_xori_", + "tcg_gen_xor_"); + break; + case ANDL_OP: + gen_andl_op(c, locp, bit_width, bit_suffix, &res, op_types, &op1_m, + &op2_m); + break; + case MINI_OP: + gen_minmax_op(c, locp, bit_width, &res, op_types, &op1_m, &op2_m, + false); + break; + case MAXI_OP: + gen_minmax_op(c, locp, bit_width, &res, op_types, &op1_m, &op2_m, true); + break; + } + return res; +} + +HexValue gen_cast_op(Context *c, + YYLTYPE *locp, + HexValue *src, + unsigned target_width, + HexSignedness signedness) +{ + assert_signedness(c, locp, src->signedness); + if (src->bit_width == target_width) { + return *src; + } else if (src->type == IMMEDIATE) { + HexValue res = *src; + res.bit_width = target_width; + res.signedness = signedness; + return res; + } else { + HexValue res = gen_tmp(c, locp, target_width, signedness); + /* Truncate */ + if (src->bit_width > target_width) { + OUT(c, locp, "tcg_gen_trunc_i64_tl(", &res, ", ", src, ");\n"); + } else { + assert_signedness(c, locp, src->signedness); + if (src->signedness == UNSIGNED) { + /* Extend unsigned */ + OUT(c, locp, "tcg_gen_extu_i32_i64(", + &res, ", ", src, ");\n"); + } else { + /* Extend signed */ + OUT(c, locp, "tcg_gen_ext_i32_i64(", + &res, ", ", src, ");\n"); + } + } + gen_rvalue_free(c, locp, src); + return res; + } +} + + +/* + * Implements an extension when the `src_width` is an immediate. + * If the `value` to extend is also an immediate we use `extract/sextract` + * from QEMU `bitops.h`. If `value` is a TCGv then we rely on + * `tcg_gen_extract/tcg_gen_sextract`. + */ +static HexValue gen_extend_imm_width_op(Context *c, + YYLTYPE *locp, + HexValue *src_width, + unsigned dst_width, + HexValue *value, + HexSignedness signedness) +{ + /* + * If the source width is not an immediate value, we need to guard + * our extend op with if statements to handle the case where + * `src_width_m` is 0. + */ + const char *sign_prefix; + bool need_guarding; + + assert_signedness(c, locp, signedness); + assert(dst_width == 64 || dst_width == 32); + assert(src_width->type == IMMEDIATE); + + sign_prefix = (signedness == UNSIGNED) ? "" : "s"; + need_guarding = (src_width->imm.type != VALUE); + + if (src_width->imm.type == VALUE && + src_width->imm.value == 0) { + /* + * We can bail out early if the source width is known to be zero + * at translation time. + */ + return gen_imm_value(c, locp, 0, dst_width, signedness); + } + + if (value->type == IMMEDIATE) { + /* + * If both the value and source width are immediates, + * we can perform the extension at translation time + * using QEMUs bitops. + */ + HexValue res = gen_imm_qemu_tmp(c, locp, dst_width, signedness); + gen_c_int_type(c, locp, dst_width, signedness); + OUT(c, locp, " ", &res, " = 0;\n"); + if (need_guarding) { + OUT(c, locp, "if (", src_width, " != 0) {\n"); + } + OUT(c, locp, &res, " = ", sign_prefix, "extract", &dst_width); + OUT(c, locp, "(", value, ", 0, ", src_width, ");\n"); + if (need_guarding) { + OUT(c, locp, "}\n"); + } + + gen_rvalue_free(c, locp, value); + return res; + } else { + /* + * If the source width is an immediate and the value to + * extend is a TCGv, then use tcg_gen_extract/tcg_gen_sextract + */ + HexValue res = gen_tmp(c, locp, dst_width, signedness); + + /* + * If the width is an immediate value we know it is non-zero + * at this point, otherwise we need an if-statement + */ + if (need_guarding) { + OUT(c, locp, "if (", src_width, " != 0) {\n"); + } + OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &dst_width); + OUT(c, locp, "(", &res, ", ", value, ", 0, ", src_width, + ");\n"); + if (need_guarding) { + OUT(c, locp, "} else {\n"); + OUT(c, locp, "tcg_gen_movi_i", &dst_width, "(", &res, + ", 0);\n"); + OUT(c, locp, "}\n"); + } + + gen_rvalue_free(c, locp, value); + return res; + } +} + +/* + * Implements an extension when the `src_width` is given by + * a TCGv. Here we need to reimplement the behaviour of + * `tcg_gen_extract` and the like using shifts and masks. + */ +static HexValue gen_extend_tcg_width_op(Context *c, + YYLTYPE *locp, + HexValue *src_width, + unsigned dst_width, + HexValue *value, + HexSignedness signedness) +{ + HexValue src_width_m = rvalue_materialize(c, locp, src_width); + HexValue zero = gen_constant(c, locp, "0", dst_width, UNSIGNED); + HexValue shift = gen_tmp(c, locp, dst_width, UNSIGNED); + HexValue res; + + assert_signedness(c, locp, signedness); + assert(dst_width == 64 || dst_width == 32); + assert(src_width->type != IMMEDIATE); + + res = gen_tmp(c, locp, dst_width, signedness); + + OUT(c, locp, "tcg_gen_subfi_i", &dst_width); + OUT(c, locp, "(", &shift, ", ", &dst_width, ", ", &src_width_m, ");\n"); + if (signedness == UNSIGNED) { + const char *mask_str = (dst_width == 32) + ? "0xffffffff" + : "0xffffffffffffffff"; + HexValue mask = gen_tmp_value(c, locp, mask_str, + dst_width, UNSIGNED); + OUT(c, locp, "tcg_gen_shr_i", &dst_width, "(", + &mask, ", ", &mask, ", ", &shift, ");\n"); + OUT(c, locp, "tcg_gen_and_i", &dst_width, "(", + &res, ", ", value, ", ", &mask, ");\n"); + gen_rvalue_free(c, locp, &mask); + } else { + OUT(c, locp, "tcg_gen_shl_i", &dst_width, "(", + &res, ", ", value, ", ", &shift, ");\n"); + OUT(c, locp, "tcg_gen_sar_i", &dst_width, "(", + &res, ", ", &res, ", ", &shift, ");\n"); + } + OUT(c, locp, "tcg_gen_movcond_i", &dst_width, "(TCG_COND_EQ, ", &res, + ", "); + OUT(c, locp, &src_width_m, ", ", &zero, ", ", &zero, ", ", &res, + ");\n"); + + gen_rvalue_free(c, locp, &src_width_m); + gen_rvalue_free(c, locp, value); + gen_rvalue_free(c, locp, &shift); + + return res; +} + +HexValue gen_extend_op(Context *c, + YYLTYPE *locp, + HexValue *src_width, + unsigned dst_width, + HexValue *value, + HexSignedness signedness) +{ + unsigned bit_width = (dst_width = 64) ? 64 : 32; + HexValue value_m = *value; + HexValue src_width_m = *src_width; + + assert_signedness(c, locp, signedness); + yyassert(c, locp, value_m.bit_width <= bit_width && + src_width_m.bit_width <= bit_width, + "Extending to a size smaller than the current size" + " makes no sense"); + + if (value_m.bit_width < bit_width) { + value_m = gen_rvalue_extend(c, locp, &value_m); + } + + if (src_width_m.bit_width < bit_width) { + src_width_m = gen_rvalue_extend(c, locp, &src_width_m); + } + + if (src_width_m.type == IMMEDIATE) { + return gen_extend_imm_width_op(c, locp, &src_width_m, bit_width, + &value_m, signedness); + } else { + return gen_extend_tcg_width_op(c, locp, &src_width_m, bit_width, + &value_m, signedness); + } +} + +/* + * Implements `rdeposit` for the special case where `width` + * is of TCGv type. In this case we need to reimplement the behaviour + * of `tcg_gen_deposit*` using binary operations and masks/shifts. + * + * Note: this is the only type of `rdeposit` that occurs, meaning the + * `width` is _NEVER_ of IMMEDIATE type. + */ +void gen_rdeposit_op(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *value, + HexValue *begin, + HexValue *width) +{ + /* + * Otherwise if the width is not known, we fallback on reimplementing + * desposit in TCG. + */ + HexValue begin_m = *begin; + HexValue value_m = *value; + HexValue width_m = *width; + const char *mask_str = (dst->bit_width == 32) + ? "0xffffffffUL" + : "0xffffffffffffffffUL"; + HexValue mask = gen_constant(c, locp, mask_str, dst->bit_width, + UNSIGNED); + const char *dst_width_str = (dst->bit_width == 32) ? "32" : "64"; + HexValue k64 = gen_constant(c, locp, dst_width_str, dst->bit_width, + UNSIGNED); + HexValue res; + HexValue zero; + + assert(dst->bit_width >= value->bit_width); + assert(begin->type == IMMEDIATE && begin->imm.type == VALUE); + assert(dst->type == REGISTER_ARG); + + yyassert(c, locp, width->type != IMMEDIATE, + "Immediate index to rdeposit not handled!"); + + yyassert(c, locp, value_m.bit_width == dst->bit_width && + begin_m.bit_width == dst->bit_width && + width_m.bit_width == dst->bit_width, + "Extension/truncation should be taken care of" + " before rdeposit!"); + + width_m = rvalue_materialize(c, locp, &width_m); + + /* + * mask = 0xffffffffffffffff >> (64 - width) + * mask = mask << begin + * value = (value << begin) & mask + * res = dst & ~mask + * res = res | value + * dst = (width != 0) ? res : dst + */ + k64 = gen_bin_op(c, locp, SUB_OP, &k64, &width_m); + mask = gen_bin_op(c, locp, LSR_OP, &mask, &k64); + begin_m.is_manual = true; + mask = gen_bin_op(c, locp, ASL_OP, &mask, &begin_m); + mask.is_manual = true; + value_m = gen_bin_op(c, locp, ASL_OP, &value_m, &begin_m); + value_m = gen_bin_op(c, locp, ANDB_OP, &value_m, &mask); + + OUT(c, locp, "tcg_gen_not_i", &dst->bit_width, "(", &mask, ", ", + &mask, ");\n"); + mask.is_manual = false; + res = gen_bin_op(c, locp, ANDB_OP, dst, &mask); + res = gen_bin_op(c, locp, ORB_OP, &res, &value_m); + + /* + * We don't need to truncate `res` here, since all operations involved use + * the same bit width. + */ + + /* If the width is zero, then return the identity dst = dst */ + zero = gen_constant(c, locp, "0", res.bit_width, UNSIGNED); + OUT(c, locp, "tcg_gen_movcond_i", &res.bit_width, "(TCG_COND_NE, ", + dst); + OUT(c, locp, ", ", &width_m, ", ", &zero, ", ", &res, ", ", dst, + ");\n"); + + gen_rvalue_free(c, locp, width); + gen_rvalue_free(c, locp, &res); +} + +void gen_deposit_op(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *value, + HexValue *index, + HexCast *cast) +{ + HexValue value_m = *value; + unsigned bit_width = (dst->bit_width == 64) ? 64 : 32; + unsigned width = cast->bit_width; + + yyassert(c, locp, index->type == IMMEDIATE, + "Deposit index must be immediate!\n"); + + /* + * Using tcg_gen_deposit_i**(dst, dst, ...) requires dst to be + * initialized. + */ + gen_inst_init_args(c, locp); + + /* If the destination value is 32, truncate the value, otherwise extend */ + if (dst->bit_width != value->bit_width) { + if (bit_width == 32) { + value_m = gen_rvalue_truncate(c, locp, &value_m); + } else { + value_m = gen_rvalue_extend(c, locp, &value_m); + } + } + value_m = rvalue_materialize(c, locp, &value_m); + OUT(c, locp, "tcg_gen_deposit_i", &bit_width, "(", dst, ", ", dst, ", "); + OUT(c, locp, &value_m, ", ", index, " * ", &width, ", ", &width, ");\n"); + gen_rvalue_free(c, locp, index); + gen_rvalue_free(c, locp, &value_m); +} + +HexValue gen_rextract_op(Context *c, + YYLTYPE *locp, + HexValue *src, + unsigned begin, + unsigned width) +{ + unsigned bit_width = (src->bit_width == 64) ? 64 : 32; + HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED); + OUT(c, locp, "tcg_gen_extract_i", &bit_width, "(", &res); + OUT(c, locp, ", ", src, ", ", &begin, ", ", &width, ");\n"); + gen_rvalue_free(c, locp, src); + return res; +} + +HexValue gen_extract_op(Context *c, + YYLTYPE *locp, + HexValue *src, + HexValue *index, + HexExtract *extract) +{ + unsigned bit_width = (src->bit_width == 64) ? 64 : 32; + unsigned width = extract->bit_width; + const char *sign_prefix; + HexValue res; + + yyassert(c, locp, index->type == IMMEDIATE, + "Extract index must be immediate!\n"); + assert_signedness(c, locp, extract->signedness); + + sign_prefix = (extract->signedness == UNSIGNED) ? "" : "s"; + res = gen_tmp(c, locp, bit_width, extract->signedness); + + OUT(c, locp, "tcg_gen_", sign_prefix, "extract_i", &bit_width, + "(", &res, ", ", src); + OUT(c, locp, ", ", index, " * ", &width, ", ", &width, ");\n"); + + /* Some extract operations have bit_width != storage_bit_width */ + if (extract->storage_bit_width > bit_width) { + HexValue tmp = gen_tmp(c, locp, extract->storage_bit_width, + extract->signedness); + const char *sign_suffix = (extract->signedness == UNSIGNED) ? "u" : ""; + OUT(c, locp, "tcg_gen_ext", sign_suffix, "_i32_i64(", + &tmp, ", ", &res, ");\n"); + gen_rvalue_free(c, locp, &res); + res = tmp; + } + + gen_rvalue_free(c, locp, src); + gen_rvalue_free(c, locp, index); + return res; +} + +void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value) +{ + HexValue value_m = *value; + yyassert(c, locp, reg->type == REGISTER, "reg must be a register!"); + value_m = gen_rvalue_truncate(c, locp, &value_m); + value_m = rvalue_materialize(c, locp, &value_m); + OUT(c, + locp, + "gen_log_reg_write(", ®->reg.id, ", ", + &value_m, ");\n"); + OUT(c, + locp, + "ctx_log_reg_write(ctx, ", ®->reg.id, + ");\n"); + gen_rvalue_free(c, locp, reg); + gen_rvalue_free(c, locp, &value_m); +} + +void gen_assign(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *value) +{ + HexValue value_m = *value; + unsigned bit_width; + + yyassert(c, locp, !is_inside_ternary(c), + "Assign in ternary not allowed!"); + + if (dst->type == REGISTER) { + gen_write_reg(c, locp, dst, &value_m); + return; + } + + if (dst->type == VARID) { + find_variable(c, locp, dst, dst); + } + bit_width = dst->bit_width == 64 ? 64 : 32; + + if (bit_width != value_m.bit_width) { + if (bit_width == 64) { + value_m = gen_rvalue_extend(c, locp, &value_m); + } else { + value_m = gen_rvalue_truncate(c, locp, &value_m); + } + } + + const char *imm_suffix = (value_m.type == IMMEDIATE) ? "i" : ""; + OUT(c, locp, "tcg_gen_mov", imm_suffix, "_i", &bit_width, + "(", dst, ", ", &value_m, ");\n"); + + gen_rvalue_free(c, locp, &value_m); +} + +HexValue gen_convround(Context *c, + YYLTYPE *locp, + HexValue *src) +{ + HexValue src_m = *src; + unsigned bit_width = src_m.bit_width; + const char *size = (bit_width == 32) ? "32" : "64"; + HexValue res = gen_tmp(c, locp, bit_width, src->signedness); + HexValue mask = gen_constant(c, locp, "0x3", bit_width, UNSIGNED); + HexValue one = gen_constant(c, locp, "1", bit_width, UNSIGNED); + HexValue and; + HexValue src_p1; + + src_m.is_manual = true; + + and = gen_bin_op(c, locp, ANDB_OP, &src_m, &mask); + src_p1 = gen_bin_op(c, locp, ADD_OP, &src_m, &one); + + OUT(c, locp, "tcg_gen_movcond_i", size, "(TCG_COND_EQ, ", &res); + OUT(c, locp, ", ", &and, ", ", &mask, ", "); + OUT(c, locp, &src_p1, ", ", &src_m, ");\n"); + + /* Free src but use the original `is_manual` value */ + gen_rvalue_free(c, locp, src); + + /* Free the rest of the values */ + gen_rvalue_free(c, locp, &src_p1); + + return res; +} + +static HexValue gen_convround_n_b(Context *c, + YYLTYPE *locp, + HexValue *a, + HexValue *n) +{ + HexValue one = gen_constant(c, locp, "1", 32, UNSIGNED); + HexValue res = gen_tmp(c, locp, 64, UNSIGNED); + HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED); + HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED); + + assert(n->type != IMMEDIATE); + OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n"); + OUT(c, locp, "tcg_gen_shl_i32(", &tmp); + OUT(c, locp, ", ", &one, ", ", n, ");\n"); + OUT(c, locp, "tcg_gen_and_i32(", &tmp); + OUT(c, locp, ", ", &tmp, ", ", a, ");\n"); + OUT(c, locp, "tcg_gen_shri_i32(", &tmp); + OUT(c, locp, ", ", &tmp, ", 1);\n"); + OUT(c, locp, "tcg_gen_ext_i32_i64(", &tmp_64, ", ", &tmp, ");\n"); + OUT(c, locp, "tcg_gen_add_i64(", &res); + OUT(c, locp, ", ", &res, ", ", &tmp_64, ");\n"); + + gen_rvalue_free(c, locp, &tmp); + gen_rvalue_free(c, locp, &tmp_64); + + return res; +} + +static HexValue gen_convround_n_c(Context *c, + YYLTYPE *locp, + HexValue *a, + HexValue *n) +{ + HexValue res = gen_tmp(c, locp, 64, UNSIGNED); + HexValue one = gen_constant(c, locp, "1", 32, UNSIGNED); + HexValue tmp = gen_tmp(c, locp, 32, UNSIGNED); + HexValue tmp_64 = gen_tmp(c, locp, 64, UNSIGNED); + + OUT(c, locp, "tcg_gen_ext_i32_i64(", &res, ", ", a, ");\n"); + OUT(c, locp, "tcg_gen_subi_i32(", &tmp); + OUT(c, locp, ", ", n, ", 1);\n"); + OUT(c, locp, "tcg_gen_shl_i32(", &tmp); + OUT(c, locp, ", ", &one, ", ", &tmp, ");\n"); + OUT(c, locp, "tcg_gen_ext_i32_i64(", &tmp_64, ", ", &tmp, ");\n"); + OUT(c, locp, "tcg_gen_add_i64(", &res); + OUT(c, locp, ", ", &res, ", ", &tmp_64, ");\n"); + + gen_rvalue_free(c, locp, &one); + gen_rvalue_free(c, locp, &tmp); + gen_rvalue_free(c, locp, &tmp_64); + + return res; +} + +HexValue gen_convround_n(Context *c, + YYLTYPE *locp, + HexValue *src, + HexValue *pos) +{ + HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED); + HexValue l_32 = gen_constant(c, locp, "1", 32, UNSIGNED); + HexValue cond = gen_tmp(c, locp, 32, UNSIGNED); + HexValue cond_64 = gen_tmp(c, locp, 64, UNSIGNED); + HexValue mask = gen_tmp(c, locp, 32, UNSIGNED); + HexValue n_64 = gen_tmp(c, locp, 64, UNSIGNED); + HexValue res = gen_tmp(c, locp, 64, UNSIGNED); + /* If input is 64 bit cast it to 32 */ + HexValue src_casted = gen_cast_op(c, locp, src, 32, src->signedness); + HexValue pos_casted = gen_cast_op(c, locp, pos, 32, pos->signedness); + HexValue r1; + HexValue r2; + HexValue r3; + + src_casted = rvalue_materialize(c, locp, &src_casted); + pos_casted = rvalue_materialize(c, locp, &pos_casted); + + /* + * r1, r2, and r3 represent the results of three different branches. + * - r1 picked if pos_casted == 0 + * - r2 picked if (src_casted & ((1 << (pos_casted - 1)) - 1)) == 0), + * that is if bits 0, ..., pos_casted-1 are all 0. + * - r3 picked otherwise. + */ + r1 = gen_rvalue_extend(c, locp, &src_casted); + r2 = gen_convround_n_b(c, locp, &src_casted, &pos_casted); + r3 = gen_convround_n_c(c, locp, &src_casted, &pos_casted); + + /* + * Calculate the condition + * (src_casted & ((1 << (pos_casted - 1)) - 1)) == 0), + * which checks if the bits 0,...,pos-1 are all 0. + */ + OUT(c, locp, "tcg_gen_sub_i32(", &mask); + OUT(c, locp, ", ", &pos_casted, ", ", &l_32, ");\n"); + OUT(c, locp, "tcg_gen_shl_i32(", &mask); + OUT(c, locp, ", ", &l_32, ", ", &mask, ");\n"); + OUT(c, locp, "tcg_gen_sub_i32(", &mask); + OUT(c, locp, ", ", &mask, ", ", &l_32, ");\n"); + OUT(c, locp, "tcg_gen_and_i32(", &cond); + OUT(c, locp, ", ", &src_casted, ", ", &mask, ");\n"); + OUT(c, locp, "tcg_gen_extu_i32_i64(", &cond_64, ", ", &cond, ");\n"); + + OUT(c, locp, "tcg_gen_ext_i32_i64(", &n_64, ", ", &pos_casted, ");\n"); + + /* + * if the bits 0, ..., pos_casted-1 are all 0, then pick r2 otherwise, + * pick r3. + */ + OUT(c, locp, "tcg_gen_movcond_i64"); + OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &cond_64, ", ", &zero); + OUT(c, locp, ", ", &r2, ", ", &r3, ");\n"); + + /* Lastly, if the pos_casted == 0, then pick r1 */ + OUT(c, locp, "tcg_gen_movcond_i64"); + OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &n_64, ", ", &zero); + OUT(c, locp, ", ", &r1, ", ", &res, ");\n"); + + /* Finally shift back val >>= n */ + OUT(c, locp, "tcg_gen_shr_i64(", &res); + OUT(c, locp, ", ", &res, ", ", &n_64, ");\n"); + + gen_rvalue_free(c, locp, &src_casted); + gen_rvalue_free(c, locp, &pos_casted); + + gen_rvalue_free(c, locp, &r1); + gen_rvalue_free(c, locp, &r2); + gen_rvalue_free(c, locp, &r3); + + gen_rvalue_free(c, locp, &cond); + gen_rvalue_free(c, locp, &cond_64); + gen_rvalue_free(c, locp, &mask); + gen_rvalue_free(c, locp, &n_64); + + res = gen_rvalue_truncate(c, locp, &res); + return res; +} + +HexValue gen_round(Context *c, + YYLTYPE *locp, + HexValue *src, + HexValue *pos) +{ + HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED); + HexValue one = gen_constant(c, locp, "1", 64, UNSIGNED); + HexValue res; + HexValue n_m1; + HexValue shifted; + HexValue sum; + HexValue src_width; + HexValue a; + HexValue b; + + assert_signedness(c, locp, src->signedness); + yyassert(c, locp, src->bit_width <= 32, + "fRNDN not implemented for bit widths > 32!"); + + res = gen_tmp(c, locp, 64, src->signedness); + + src_width = gen_imm_value(c, locp, src->bit_width, 32, UNSIGNED); + a = gen_extend_op(c, locp, &src_width, 64, src, SIGNED); + a = rvalue_materialize(c, locp, &a); + + src_width = gen_imm_value(c, locp, 5, 32, UNSIGNED); + b = gen_extend_op(c, locp, &src_width, 64, pos, UNSIGNED); + b = rvalue_materialize(c, locp, &b); + + /* Disable auto-free of values used more than once */ + a.is_manual = true; + b.is_manual = true; + + n_m1 = gen_bin_op(c, locp, SUB_OP, &b, &one); + shifted = gen_bin_op(c, locp, ASL_OP, &one, &n_m1); + sum = gen_bin_op(c, locp, ADD_OP, &shifted, &a); + + OUT(c, locp, "tcg_gen_movcond_i64"); + OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", &b, ", ", &zero); + OUT(c, locp, ", ", &a, ", ", &sum, ");\n"); + + gen_rvalue_free_manual(c, locp, &a); + gen_rvalue_free_manual(c, locp, &b); + gen_rvalue_free(c, locp, &sum); + + return res; +} + +/* Circular addressing mode with auto-increment */ +void gen_circ_op(Context *c, + YYLTYPE *locp, + HexValue *addr, + HexValue *increment, + HexValue *modifier) +{ + HexValue cs = gen_tmp(c, locp, 32, UNSIGNED); + HexValue increment_m = *increment; + increment_m = rvalue_materialize(c, locp, &increment_m); + OUT(c, locp, "gen_read_reg(", &cs, ", HEX_REG_CS0 + MuN);\n"); + OUT(c, + locp, + "gen_helper_fcircadd(", + addr, + ", ", + addr, + ", ", + &increment_m, + ", ", + modifier); + OUT(c, locp, ", ", &cs, ");\n"); + gen_rvalue_free(c, locp, &increment_m); + gen_rvalue_free(c, locp, modifier); + gen_rvalue_free(c, locp, &cs); +} + +HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src) +{ + const char *bit_suffix = src->bit_width == 64 ? "64" : "32"; + HexValue src_m = *src; + HexValue res; + + assert_signedness(c, locp, src->signedness); + res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32, src->signedness); + src_m = rvalue_materialize(c, locp, &src_m); + OUT(c, locp, "tcg_gen_not_i", bit_suffix, "(", + &res, ", ", &src_m, ");\n"); + OUT(c, locp, "tcg_gen_clzi_i", bit_suffix, "(", &res, ", ", &res, ", "); + OUT(c, locp, bit_suffix, ");\n"); + gen_rvalue_free(c, locp, &src_m); + return res; +} + +HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src) +{ + const char *bit_suffix = src->bit_width == 64 ? "64" : "32"; + HexValue src_m = *src; + HexValue res; + assert_signedness(c, locp, src->signedness); + res = gen_tmp(c, locp, src->bit_width == 64 ? 64 : 32, src->signedness); + src_m = rvalue_materialize(c, locp, &src_m); + OUT(c, locp, "tcg_gen_ctpop_i", bit_suffix, + "(", &res, ", ", &src_m, ");\n"); + gen_rvalue_free(c, locp, &src_m); + return res; +} + +HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *width) +{ + const char *suffix = src->bit_width == 64 ? "i64" : "i32"; + HexValue amount = *width; + HexValue res; + assert_signedness(c, locp, src->signedness); + res = gen_tmp(c, locp, src->bit_width, src->signedness); + if (amount.bit_width < src->bit_width) { + amount = gen_rvalue_extend(c, locp, &amount); + } else { + amount = gen_rvalue_truncate(c, locp, &amount); + } + amount = rvalue_materialize(c, locp, &amount); + OUT(c, locp, "tcg_gen_rotl_", suffix, "(", + &res, ", ", src, ", ", &amount, ");\n"); + gen_rvalue_free(c, locp, src); + gen_rvalue_free(c, locp, &amount); + + return res; +} + +HexValue gen_carry_from_add(Context *c, + YYLTYPE *locp, + HexValue *op1, + HexValue *op2, + HexValue *op3) +{ + HexValue zero = gen_constant(c, locp, "0", 64, UNSIGNED); + HexValue res = gen_tmp(c, locp, 64, UNSIGNED); + HexValue cf = gen_tmp(c, locp, 64, UNSIGNED); + HexValue op1_m = rvalue_materialize(c, locp, op1); + HexValue op2_m = rvalue_materialize(c, locp, op2); + HexValue op3_m = rvalue_materialize(c, locp, op3); + op3_m = gen_rvalue_extend(c, locp, &op3_m); + + OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &op1_m, ", ", + &zero); + OUT(c, locp, ", ", &op3_m, ", ", &zero, ");\n"); + OUT(c, locp, "tcg_gen_add2_i64(", &res, ", ", &cf, ", ", &res, ", ", &cf); + OUT(c, locp, ", ", &op2_m, ", ", &zero, ");\n"); + + gen_rvalue_free(c, locp, &op1_m); + gen_rvalue_free(c, locp, &op2_m); + gen_rvalue_free(c, locp, &op3_m); + gen_rvalue_free(c, locp, &res); + return cf; +} + +void gen_addsat64(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *op1, + HexValue *op2) +{ + HexValue op1_m = rvalue_materialize(c, locp, op1); + HexValue op2_m = rvalue_materialize(c, locp, op2); + OUT(c, locp, "gen_add_sat_i64(", dst, ", ", &op1_m, ", ", &op2_m, ");\n"); +} + +void gen_inst(Context *c, GString *iname) +{ + c->total_insn++; + c->inst.name = iname; + c->inst.allocated = g_array_new(FALSE, FALSE, sizeof(Var)); + c->inst.init_list = g_array_new(FALSE, FALSE, sizeof(HexValue)); + c->inst.strings = g_array_new(FALSE, FALSE, sizeof(GString *)); + EMIT_SIG(c, "void emit_%s(DisasContext *ctx, Insn *insn, Packet *pkt", + c->inst.name->str); +} + + +/* + * Initialize declared but uninitialized registers, but only for + * non-conditional instructions + */ +void gen_inst_init_args(Context *c, YYLTYPE *locp) +{ + if (!c->inst.init_list) { + return; + } + + for (unsigned i = 0; i < c->inst.init_list->len; i++) { + HexValue *val = &g_array_index(c->inst.init_list, HexValue, i); + if (val->type == REGISTER_ARG) { + char reg_id[5]; + reg_compose(c, locp, &val->reg, reg_id); + EMIT_HEAD(c, "tcg_gen_movi_i%u(%s, 0);\n", val->bit_width, reg_id); + } else if (val->type == PREDICATE) { + char suffix = val->is_dotnew ? 'N' : 'V'; + EMIT_HEAD(c, "tcg_gen_movi_i%u(P%c%c, 0);\n", val->bit_width, + val->pred.id, suffix); + } else { + yyassert(c, locp, false, "Invalid arg type!"); + } + } + + /* Free argument init list once we have initialized everything */ + g_array_free(c->inst.init_list, TRUE); + c->inst.init_list = NULL; +} + +void gen_inst_code(Context *c, YYLTYPE *locp) +{ + if (c->inst.error_count != 0) { + fprintf(stderr, + "Parsing of instruction %s generated %d errors!\n", + c->inst.name->str, + c->inst.error_count); + } else { + free_variables(c, locp); + c->implemented_insn++; + fprintf(c->enabled_file, "%s\n", c->inst.name->str); + emit_footer(c); + commit(c); + } + free_instruction(c); +} + +void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred, + HexValue *right_pred) +{ + char pred_id[2] = {left_pred->pred.id, 0}; + bool is_direct = is_direct_predicate(left_pred); + HexValue r = rvalue_materialize(c, locp, right_pred); + r = gen_rvalue_truncate(c, locp, &r); + yyassert(c, locp, !is_inside_ternary(c), + "Predicate assign not allowed in ternary!"); + /* Extract predicate TCGv */ + if (is_direct) { + *left_pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED); + } + /* Extract first 8 bits, and store new predicate value */ + OUT(c, locp, "tcg_gen_mov_i32(", left_pred, ", ", &r, ");\n"); + OUT(c, locp, "tcg_gen_andi_i32(", left_pred, ", ", left_pred, + ", 0xff);\n"); + if (is_direct) { + OUT(c, locp, "gen_log_pred_write(ctx, ", pred_id, ", ", left_pred, + ");\n"); + OUT(c, locp, "ctx_log_pred_write(ctx, ", pred_id, ");\n"); + gen_rvalue_free(c, locp, left_pred); + } + /* Free temporary value */ + gen_rvalue_free(c, locp, &r); +} + +void gen_cancel(Context *c, YYLTYPE *locp) +{ + OUT(c, locp, "gen_cancel(insn->slot);\n"); +} + +void gen_load_cancel(Context *c, YYLTYPE *locp) +{ + gen_cancel(c, locp); + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n"); + OUT(c, locp, "ctx->s1_store_processed = false;\n"); + OUT(c, locp, "process_store(ctx, 1);\n"); + OUT(c, locp, "}\n"); +} + +void gen_load(Context *c, YYLTYPE *locp, HexValue *width, + HexSignedness signedness, HexValue *ea, HexValue *dst) +{ + char size_suffix[4] = {0}; + const char *sign_suffix; + /* Memop width is specified in the load macro */ + assert_signedness(c, locp, signedness); + sign_suffix = (width->imm.value > 4) + ? "" + : ((signedness == UNSIGNED) ? "u" : "s"); + /* If dst is a variable, assert that is declared and load the type info */ + if (dst->type == VARID) { + find_variable(c, locp, dst, dst); + } + + snprintf(size_suffix, 4, "%" PRIu64, width->imm.value * 8); + /* Lookup the effective address EA */ + find_variable(c, locp, ea, ea); + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n"); + OUT(c, locp, "probe_noshuf_load(", ea, ", ", width, ", ctx->mem_idx);\n"); + OUT(c, locp, "process_store(ctx, 1);\n"); + OUT(c, locp, "}\n"); + OUT(c, locp, "tcg_gen_qemu_ld", size_suffix, sign_suffix); + OUT(c, locp, "("); + if (dst->bit_width > width->imm.value * 8) { + /* + * Cast to the correct TCG type if necessary, to avoid implict cast + * warnings. This is needed when the width of the destination var is + * larger than the size of the requested load. + */ + OUT(c, locp, "(TCGv) "); + } + OUT(c, locp, dst, ", ", ea, ", ctx->mem_idx);\n"); + /* If the var in EA was truncated it is now a tmp HexValue, so free it. */ + gen_rvalue_free(c, locp, ea); +} + +void gen_store(Context *c, YYLTYPE *locp, HexValue *width, HexValue *ea, + HexValue *src) +{ + HexValue src_m = *src; + /* Memop width is specified in the store macro */ + unsigned mem_width = width->imm.value; + /* Lookup the effective address EA */ + find_variable(c, locp, ea, ea); + src_m = rvalue_materialize(c, locp, &src_m); + OUT(c, locp, "gen_store", &mem_width, "(cpu_env, ", ea, ", ", &src_m); + OUT(c, locp, ", insn->slot);\n"); + gen_rvalue_free(c, locp, &src_m); + /* If the var in ea was truncated it is now a tmp HexValue, so free it. */ + gen_rvalue_free(c, locp, ea); +} + +void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n, + HexValue *dst, HexValue *value) +{ + yyassert(c, locp, n->type == IMMEDIATE, + "Deposit index must be immediate!\n"); + if (dst->type == VARID) { + find_variable(c, locp, dst, dst); + } + + gen_deposit_op(c, locp, dst, value, n, sh); +} + +void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo, + HexValue *dst, HexValue *value) +{ + unsigned len; + HexValue tmp; + + yyassert(c, locp, hi->type == IMMEDIATE && + hi->imm.type == VALUE && + lo->type == IMMEDIATE && + lo->imm.type == VALUE, + "Range deposit needs immediate values!\n"); + + *value = gen_rvalue_truncate(c, locp, value); + len = hi->imm.value + 1 - lo->imm.value; + tmp = gen_tmp(c, locp, 32, value->signedness); + /* Emit an `and` to ensure `value` is either 0 or 1. */ + OUT(c, locp, "tcg_gen_andi_i32(", &tmp, ", ", value, ", 1);\n"); + /* Use `neg` to map 0 -> 0 and 1 -> 0xffff... */ + OUT(c, locp, "tcg_gen_neg_i32(", &tmp, ", ", &tmp, ");\n"); + OUT(c, locp, "tcg_gen_deposit_i32(", dst, ", ", dst, + ", ", &tmp, ", "); + OUT(c, locp, lo, ", ", &len, ");\n"); + + gen_rvalue_free(c, locp, &tmp); + gen_rvalue_free(c, locp, hi); + gen_rvalue_free(c, locp, lo); + gen_rvalue_free(c, locp, value); +} + +unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond) +{ + const char *bit_suffix; + /* Generate an end label, if false branch to that label */ + OUT(c, locp, "TCGLabel *if_label_", &c->inst.if_count, + " = gen_new_label();\n"); + *cond = rvalue_materialize(c, locp, cond); + bit_suffix = (cond->bit_width == 64) ? "i64" : "i32"; + OUT(c, locp, "tcg_gen_brcondi_", bit_suffix, "(TCG_COND_EQ, ", cond, + ", 0, if_label_", &c->inst.if_count, ");\n"); + gen_rvalue_free(c, locp, cond); + return c->inst.if_count++; +} + +unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index) +{ + unsigned if_index = c->inst.if_count++; + /* Generate label to jump if else is not verified */ + OUT(c, locp, "TCGLabel *if_label_", &if_index, + " = gen_new_label();\n"); + /* Jump out of the else statement */ + OUT(c, locp, "tcg_gen_br(if_label_", &if_index, ");\n"); + /* Fix the else label */ + OUT(c, locp, "gen_set_label(if_label_", &index, ");\n"); + return if_index; +} + +HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred) +{ + /* Predicted instructions need to zero out result args */ + gen_inst_init_args(c, locp); + + if (is_direct_predicate(pred)) { + bool is_dotnew = pred->is_dotnew; + char predicate_id[2] = { pred->pred.id, '\0' }; + char *pred_str = (char *) &predicate_id; + *pred = gen_tmp_value(c, locp, "0", 32, UNSIGNED); + if (is_dotnew) { + OUT(c, locp, "tcg_gen_mov_i32(", pred, + ", hex_new_pred_value["); + OUT(c, locp, pred_str, "]);\n"); + } else { + OUT(c, locp, "gen_read_preg(", pred, ", ", pred_str, ");\n"); + } + } + + return *pred; +} + +HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var) +{ + find_variable(c, locp, var, var); + return *var; +} + +HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, + HexValue *op1, HexValue *op2) +{ + HexValue res; + memset(&res, 0, sizeof(HexValue)); + + assert_signedness(c, locp, mpy->first_signedness); + assert_signedness(c, locp, mpy->second_signedness); + + *op1 = gen_cast_op(c, locp, op1, mpy->first_bit_width * 2, + mpy->first_signedness); + /* Handle fMPTY3216.. */ + if (mpy->first_bit_width == 32) { + *op2 = gen_cast_op(c, locp, op2, 64, mpy->second_signedness); + } else { + *op2 = gen_cast_op(c, locp, op2, mpy->second_bit_width * 2, + mpy->second_signedness); + } + res = gen_bin_op(c, locp, MUL_OP, op1, op2); + /* Handle special cases required by the language */ + if (mpy->first_bit_width == 16 && mpy->second_bit_width == 16) { + HexValue src_width = gen_imm_value(c, locp, 32, 32, UNSIGNED); + HexSignedness signedness = bin_op_signedness(c, locp, + mpy->first_signedness, + mpy->second_signedness); + res = gen_extend_op(c, locp, &src_width, 64, &res, + signedness); + } + return res; +} + +static inline HexValue gen_rvalue_simple_unary(Context *c, YYLTYPE *locp, + HexValue *value, + const char *c_code, + const char *tcg_code) +{ + unsigned bit_width = (value->bit_width == 64) ? 64 : 32; + HexValue res; + if (value->type == IMMEDIATE) { + res = gen_imm_qemu_tmp(c, locp, bit_width, value->signedness); + gen_c_int_type(c, locp, value->bit_width, value->signedness); + OUT(c, locp, " ", &res, " = ", c_code, "(", value, ");\n"); + } else { + res = gen_tmp(c, locp, bit_width, value->signedness); + OUT(c, locp, tcg_code, "_i", &bit_width, "(", &res, ", ", value, + ");\n"); + gen_rvalue_free(c, locp, value); + } + return res; +} + + +HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value) +{ + return gen_rvalue_simple_unary(c, locp, value, "~", "tcg_gen_not"); +} + +HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value) +{ + unsigned bit_width = (value->bit_width == 64) ? 64 : 32; + HexValue res; + if (value->type == IMMEDIATE) { + res = gen_imm_qemu_tmp(c, locp, bit_width, value->signedness); + gen_c_int_type(c, locp, value->bit_width, value->signedness); + OUT(c, locp, " ", &res, " = !(", value, ");\n"); + } else { + HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED); + HexValue one = gen_constant(c, locp, "0xff", bit_width, UNSIGNED); + res = gen_tmp(c, locp, bit_width, value->signedness); + OUT(c, locp, "tcg_gen_movcond_i", &bit_width); + OUT(c, locp, "(TCG_COND_EQ, ", &res, ", ", value, ", ", &zero); + OUT(c, locp, ", ", &one, ", ", &zero, ");\n"); + gen_rvalue_free(c, locp, value); + } + return res; +} + +HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, + HexValue *width, HexValue *value) +{ + const char *unsigned_str; + const char *bit_suffix = (value->bit_width == 64) ? "i64" : "i32"; + HexValue res; + HexValue ovfl; + /* + * Note: all saturates are assumed to implicitly set overflow. + * This assumption holds for the instructions currently parsed + * by idef-parser. + */ + yyassert(c, locp, width->imm.value < value->bit_width, + "To compute overflow, source width must be greater than" + " saturation width!"); + yyassert(c, locp, !is_inside_ternary(c), + "Saturating from within a ternary is not allowed!"); + assert_signedness(c, locp, sat->signedness); + + unsigned_str = (sat->signedness == UNSIGNED) ? "u" : ""; + res = gen_tmp_local(c, locp, value->bit_width, sat->signedness); + ovfl = gen_tmp_local(c, locp, 32, sat->signedness); + OUT(c, locp, "gen_sat", unsigned_str, "_", bit_suffix, "_ovfl("); + OUT(c, locp, &ovfl, ", ", &res, ", ", value, ", ", &width->imm.value, + ");\n"); + OUT(c, locp, "gen_set_usr_field_if(USR_OVF,", &ovfl, ");\n"); + gen_rvalue_free(c, locp, value); + + return res; +} + +HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value) +{ + HexValue key = gen_tmp(c, locp, 64, UNSIGNED); + HexValue res = gen_tmp(c, locp, 64, UNSIGNED); + HexValue frame_key = gen_tmp(c, locp, 32, UNSIGNED); + *value = gen_rvalue_extend(c, locp, value); + OUT(c, locp, "gen_read_reg(", &frame_key, ", HEX_REG_FRAMEKEY);\n"); + OUT(c, locp, "tcg_gen_concat_i32_i64(", + &key, ", ", &frame_key, ", ", &frame_key, ");\n"); + OUT(c, locp, "tcg_gen_xor_i64(", &res, ", ", value, ", ", &key, ");\n"); + gen_rvalue_free(c, locp, &key); + gen_rvalue_free(c, locp, &frame_key); + gen_rvalue_free(c, locp, value); + return res; +} + +HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value) +{ + return gen_rvalue_simple_unary(c, locp, value, "abs", "tcg_gen_abs"); +} + +HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value) +{ + return gen_rvalue_simple_unary(c, locp, value, "-", "tcg_gen_neg"); +} + +HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value) +{ + HexValue res; + yyassert(c, locp, value->bit_width <= 32, + "fbrev not implemented for 64-bit integers!"); + res = gen_tmp(c, locp, value->bit_width, value->signedness); + *value = rvalue_materialize(c, locp, value); + OUT(c, locp, "gen_helper_fbrev(", &res, ", ", value, ");\n"); + gen_rvalue_free(c, locp, value); + return res; +} + +HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond, + HexValue *true_branch, HexValue *false_branch) +{ + bool is_64bit = (true_branch->bit_width == 64) || + (false_branch->bit_width == 64); + unsigned bit_width = (is_64bit) ? 64 : 32; + HexValue zero = gen_constant(c, locp, "0", bit_width, UNSIGNED); + HexValue res = gen_tmp(c, locp, bit_width, UNSIGNED); + Ternary *ternary = NULL; + + if (is_64bit) { + *cond = gen_rvalue_extend(c, locp, cond); + *true_branch = gen_rvalue_extend(c, locp, true_branch); + *false_branch = gen_rvalue_extend(c, locp, false_branch); + } else { + *cond = gen_rvalue_truncate(c, locp, cond); + } + *cond = rvalue_materialize(c, locp, cond); + *true_branch = rvalue_materialize(c, locp, true_branch); + *false_branch = rvalue_materialize(c, locp, false_branch); + + OUT(c, locp, "tcg_gen_movcond_i", &bit_width); + OUT(c, locp, "(TCG_COND_NE, ", &res, ", ", cond, ", ", &zero); + OUT(c, locp, ", ", true_branch, ", ", false_branch, ");\n"); + + assert(c->ternary->len > 0); + ternary = &g_array_index(c->ternary, Ternary, c->ternary->len - 1); + gen_rvalue_free_manual(c, locp, &ternary->cond); + g_array_remove_index(c->ternary, c->ternary->len - 1); + + gen_rvalue_free(c, locp, cond); + gen_rvalue_free(c, locp, true_branch); + gen_rvalue_free(c, locp, false_branch); + return res; +} + +const char *cond_to_str(TCGCond cond) +{ + switch (cond) { + case TCG_COND_NEVER: + return "TCG_COND_NEVER"; + case TCG_COND_ALWAYS: + return "TCG_COND_ALWAYS"; + case TCG_COND_EQ: + return "TCG_COND_EQ"; + case TCG_COND_NE: + return "TCG_COND_NE"; + case TCG_COND_LT: + return "TCG_COND_LT"; + case TCG_COND_GE: + return "TCG_COND_GE"; + case TCG_COND_LE: + return "TCG_COND_LE"; + case TCG_COND_GT: + return "TCG_COND_GT"; + case TCG_COND_LTU: + return "TCG_COND_LTU"; + case TCG_COND_GEU: + return "TCG_COND_GEU"; + case TCG_COND_LEU: + return "TCG_COND_LEU"; + case TCG_COND_GTU: + return "TCG_COND_GTU"; + default: + abort(); + } +} + +void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg) +{ + switch (arg->type) { + case REGISTER_ARG: + if (arg->reg.type == DOTNEW) { + EMIT_SIG(c, ", TCGv N%cN", arg->reg.id); + } else { + bool is64 = (arg->bit_width == 64); + const char *type = is64 ? "TCGv_i64" : "TCGv_i32"; + char reg_id[5]; + reg_compose(c, locp, &(arg->reg), reg_id); + EMIT_SIG(c, ", %s %s", type, reg_id); + /* MuV register requires also MuN to provide its index */ + if (arg->reg.type == MODIFIER) { + EMIT_SIG(c, ", int MuN"); + } + } + break; + case PREDICATE: + { + char suffix = arg->is_dotnew ? 'N' : 'V'; + EMIT_SIG(c, ", TCGv P%c%c", arg->pred.id, suffix); + } + break; + default: + { + fprintf(stderr, "emit_arg got unsupported argument!"); + abort(); + } + } +} + +void emit_footer(Context *c) +{ + EMIT(c, "}\n"); + EMIT(c, "\n"); +} + +void track_string(Context *c, GString *s) +{ + g_array_append_val(c->inst.strings, s); +} + +void free_variables(Context *c, YYLTYPE *locp) +{ + for (unsigned i = 0; i < c->inst.allocated->len; ++i) { + Var *var = &g_array_index(c->inst.allocated, Var, i); + const char *suffix = var->bit_width == 64 ? "i64" : "i32"; + OUT(c, locp, "tcg_temp_free_", suffix, "(", var->name->str, ");\n"); + } +} + +void free_instruction(Context *c) +{ + assert(!is_inside_ternary(c)); + /* Free the strings */ + g_string_truncate(c->signature_str, 0); + g_string_truncate(c->out_str, 0); + g_string_truncate(c->header_str, 0); + /* Free strings allocated by the instruction */ + for (unsigned i = 0; i < c->inst.strings->len; i++) { + g_string_free(g_array_index(c->inst.strings, GString*, i), TRUE); + } + g_array_free(c->inst.strings, TRUE); + /* Free INAME token value */ + g_string_free(c->inst.name, TRUE); + /* Free variables and registers */ + g_array_free(c->inst.allocated, TRUE); + /* Initialize instruction-specific portion of the context */ + memset(&(c->inst), 0, sizeof(Inst)); +} + +void assert_signedness(Context *c, + YYLTYPE *locp, + HexSignedness signedness) +{ + yyassert(c, locp, + signedness != UNKNOWN_SIGNEDNESS, + "Unspecified signedness"); +} diff --git a/target/hexagon/idef-parser/parser-helpers.h b/target/hexagon/idef-parser/parser-helpers.h new file mode 100644 index 000000000000..276629641763 --- /dev/null +++ b/target/hexagon/idef-parser/parser-helpers.h @@ -0,0 +1,376 @@ +/* + * Copyright(c) 2019-2022 rev.ng Labs Srl. 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 + * 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 . + */ + +#ifndef PARSER_HELPERS_H +#define PARSER_HELPERS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcg/tcg-cond.h" + +#include "idef-parser.tab.h" +#include "idef-parser.yy.h" +#include "idef-parser.h" + +/* Decomment this to disable yyasserts */ +/* #define NDEBUG */ + +#define ERR_LINE_CONTEXT 40 + +#define START_COMMENT "/" "*" +#define END_COMMENT "*" "/" + +void yyerror(YYLTYPE *locp, + yyscan_t scanner __attribute__((unused)), + Context *c, + const char *s); + +#ifndef NDEBUG +#define yyassert(context, locp, condition, msg) \ + if (!(condition)) { \ + yyerror(locp, (context)->scanner, (context), (msg)); \ + } +#endif + +bool is_direct_predicate(HexValue *value); + +bool is_inside_ternary(Context *c); + +/** + * Print functions + */ + +void str_print(Context *c, YYLTYPE *locp, const char *string); + +void uint8_print(Context *c, YYLTYPE *locp, uint8_t *num); + +void uint64_print(Context *c, YYLTYPE *locp, uint64_t *num); + +void int_print(Context *c, YYLTYPE *locp, int *num); + +void uint_print(Context *c, YYLTYPE *locp, unsigned *num); + +void tmp_print(Context *c, YYLTYPE *locp, HexTmp *tmp); + +void pred_print(Context *c, YYLTYPE *locp, HexPred *pred, bool is_dotnew); + +void reg_compose(Context *c, YYLTYPE *locp, HexReg *reg, char reg_id[5]); + +void reg_print(Context *c, YYLTYPE *locp, HexReg *reg); + +void imm_print(Context *c, YYLTYPE *locp, HexImm *imm); + +void var_print(Context *c, YYLTYPE *locp, HexVar *var); + +void rvalue_print(Context *c, YYLTYPE *locp, void *pointer); + +void out_assert(Context *c, YYLTYPE *locp, void *dummy); + +/** + * Copies output code buffer into stdout + */ +void commit(Context *c); + +#define OUT_IMPL(c, locp, x) \ + _Generic(*(x), \ + char: str_print, \ + uint8_t: uint8_print, \ + uint64_t: uint64_print, \ + int: int_print, \ + unsigned: uint_print, \ + HexValue: rvalue_print, \ + default: out_assert \ + )(c, locp, x); + +/* FOREACH macro */ +#define FE_1(c, locp, WHAT, X) WHAT(c, locp, X) +#define FE_2(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_1(c, locp, WHAT, __VA_ARGS__) +#define FE_3(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_2(c, locp, WHAT, __VA_ARGS__) +#define FE_4(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_3(c, locp, WHAT, __VA_ARGS__) +#define FE_5(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_4(c, locp, WHAT, __VA_ARGS__) +#define FE_6(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_5(c, locp, WHAT, __VA_ARGS__) +#define FE_7(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_6(c, locp, WHAT, __VA_ARGS__) +#define FE_8(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_7(c, locp, WHAT, __VA_ARGS__) +#define FE_9(c, locp, WHAT, X, ...) \ + WHAT(c, locp, X)FE_8(c, locp, WHAT, __VA_ARGS__) +/* repeat as needed */ + +#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME + +#define FOR_EACH(c, locp, action, ...) \ + do { \ + GET_MACRO(__VA_ARGS__, \ + FE_9, \ + FE_8, \ + FE_7, \ + FE_6, \ + FE_5, \ + FE_4, \ + FE_3, \ + FE_2, \ + FE_1)(c, locp, action, \ + __VA_ARGS__) \ + } while (0) + +#define OUT(c, locp, ...) FOR_EACH((c), (locp), OUT_IMPL, __VA_ARGS__) + +const char *cmp_swap(Context *c, YYLTYPE *locp, const char *type); + +/** + * Temporary values creation + */ + +HexValue gen_tmp(Context *c, + YYLTYPE *locp, + unsigned bit_width, + HexSignedness signedness); + +HexValue gen_tmp_value(Context *c, + YYLTYPE *locp, + const char *value, + unsigned bit_width, + HexSignedness signedness); + +HexValue gen_imm_value(Context *c __attribute__((unused)), + YYLTYPE *locp, + int value, + unsigned bit_width, + HexSignedness signedness); + +HexValue gen_imm_qemu_tmp(Context *c, YYLTYPE *locp, unsigned bit_width, + HexSignedness signedness); + +void gen_rvalue_free(Context *c, YYLTYPE *locp, HexValue *rvalue); + +HexValue rvalue_materialize(Context *c, YYLTYPE *locp, HexValue *rvalue); + +HexValue gen_rvalue_extend(Context *c, YYLTYPE *locp, HexValue *rvalue); + +HexValue gen_rvalue_truncate(Context *c, YYLTYPE *locp, HexValue *rvalue); + +void gen_varid_allocate(Context *c, + YYLTYPE *locp, + HexValue *varid, + unsigned bit_width, + HexSignedness signedness); + +/** + * Code generation functions + */ + +HexValue gen_bin_cmp(Context *c, + YYLTYPE *locp, + TCGCond type, + HexValue *op1, + HexValue *op2); + +HexValue gen_bin_op(Context *c, + YYLTYPE *locp, + OpType type, + HexValue *op1, + HexValue *op2); + +HexValue gen_cast_op(Context *c, + YYLTYPE *locp, + HexValue *src, + unsigned target_width, + HexSignedness signedness); + +/** + * gen_extend_op extends a region of src_width_ptr bits stored in a + * value_ptr to the size of dst_width. Note: src_width_ptr is a + * HexValue * to handle the special case where it is unknown at + * translation time. + */ +HexValue gen_extend_op(Context *c, + YYLTYPE *locp, + HexValue *src_width, + unsigned dst_width, + HexValue *value, + HexSignedness signedness); + +void gen_rdeposit_op(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *value, + HexValue *begin, + HexValue *width); + +void gen_deposit_op(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *value, + HexValue *index, + HexCast *cast); + +HexValue gen_rextract_op(Context *c, + YYLTYPE *locp, + HexValue *src, + unsigned begin, + unsigned width); + +HexValue gen_extract_op(Context *c, + YYLTYPE *locp, + HexValue *src, + HexValue *index, + HexExtract *extract); + +HexValue gen_read_reg(Context *c, YYLTYPE *locp, HexValue *reg); + +void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value); + +void gen_assign(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *value); + +HexValue gen_convround(Context *c, + YYLTYPE *locp, + HexValue *src); + +HexValue gen_round(Context *c, + YYLTYPE *locp, + HexValue *src, + HexValue *position); + +HexValue gen_convround_n(Context *c, + YYLTYPE *locp, + HexValue *src, + HexValue *pos); + +/** + * Circular addressing mode with auto-increment + */ +void gen_circ_op(Context *c, + YYLTYPE *locp, + HexValue *addr, + HexValue *increment, + HexValue *modifier); + +HexValue gen_locnt_op(Context *c, YYLTYPE *locp, HexValue *src); + +HexValue gen_ctpop_op(Context *c, YYLTYPE *locp, HexValue *src); + +HexValue gen_rotl(Context *c, YYLTYPE *locp, HexValue *src, HexValue *n); + +HexValue gen_deinterleave(Context *c, YYLTYPE *locp, HexValue *mixed); + +HexValue gen_interleave(Context *c, + YYLTYPE *locp, + HexValue *odd, + HexValue *even); + +HexValue gen_carry_from_add(Context *c, + YYLTYPE *locp, + HexValue *op1, + HexValue *op2, + HexValue *op3); + +void gen_addsat64(Context *c, + YYLTYPE *locp, + HexValue *dst, + HexValue *op1, + HexValue *op2); + +void gen_inst(Context *c, GString *iname); + +void gen_inst_init_args(Context *c, YYLTYPE *locp); + +void gen_inst_code(Context *c, YYLTYPE *locp); + +void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred, + HexValue *right_pred); + +void gen_cancel(Context *c, YYLTYPE *locp); + +void gen_load_cancel(Context *c, YYLTYPE *locp); + +void gen_load(Context *c, YYLTYPE *locp, HexValue *size, + HexSignedness signedness, HexValue *ea, HexValue *dst); + +void gen_store(Context *c, YYLTYPE *locp, HexValue *size, HexValue *ea, + HexValue *src); + +void gen_sethalf(Context *c, YYLTYPE *locp, HexCast *sh, HexValue *n, + HexValue *dst, HexValue *value); + +void gen_setbits(Context *c, YYLTYPE *locp, HexValue *hi, HexValue *lo, + HexValue *dst, HexValue *value); + +unsigned gen_if_cond(Context *c, YYLTYPE *locp, HexValue *cond); + +unsigned gen_if_else(Context *c, YYLTYPE *locp, unsigned index); + +HexValue gen_rvalue_pred(Context *c, YYLTYPE *locp, HexValue *pred); + +HexValue gen_rvalue_var(Context *c, YYLTYPE *locp, HexValue *var); + +HexValue gen_rvalue_mpy(Context *c, YYLTYPE *locp, HexMpy *mpy, HexValue *op1, + HexValue *op2); + +HexValue gen_rvalue_not(Context *c, YYLTYPE *locp, HexValue *value); + +HexValue gen_rvalue_notl(Context *c, YYLTYPE *locp, HexValue *value); + +HexValue gen_rvalue_sat(Context *c, YYLTYPE *locp, HexSat *sat, HexValue *n, + HexValue *value); + +HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value); + +HexValue gen_rvalue_abs(Context *c, YYLTYPE *locp, HexValue *value); + +HexValue gen_rvalue_neg(Context *c, YYLTYPE *locp, HexValue *value); + +HexValue gen_rvalue_brev(Context *c, YYLTYPE *locp, HexValue *value); + +HexValue gen_rvalue_ternary(Context *c, YYLTYPE *locp, HexValue *cond, + HexValue *true_branch, HexValue *false_branch); + +const char *cond_to_str(TCGCond cond); + +void emit_header(Context *c); + +void emit_arg(Context *c, YYLTYPE *locp, HexValue *arg); + +void emit_footer(Context *c); + +void track_string(Context *c, GString *s); + +void free_variables(Context *c, YYLTYPE *locp); + +void free_instruction(Context *c); + +void assert_signedness(Context *c, + YYLTYPE *locp, + HexSignedness signedness); + +#endif /* PARSER_HELPERS_h */ diff --git a/target/hexagon/idef-parser/prepare b/target/hexagon/idef-parser/prepare new file mode 100755 index 000000000000..72d6fcbd21a5 --- /dev/null +++ b/target/hexagon/idef-parser/prepare @@ -0,0 +1,24 @@ +#!/bin/bash + +# +# Copyright(c) 2019-2021 rev.ng Labs Srl. 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 +# 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 . +# + +set -e +set -o pipefail + +# Run the preprocessor and drop comments +cpp "$@" diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 939c6fc55fbc..d71c04cd30e8 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 359d3b744e68..237634bdd948 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)<slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + probe_noshuf_load(VA, SIZE, ctx->mem_idx); \ + process_store(ctx, 1); \ + } \ + } while (0) + +#define CHECK_NOSHUF_PRED(GET_EA, SIZE, PRED) \ do { \ - if (insn->slot == 0 && pkt->pkt_has_store_s1) { \ - process_store(ctx, pkt, 1); \ + TCGLabel *label = gen_new_label(); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, PRED, 0, label); \ + GET_EA; \ + if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + probe_noshuf_load(EA, SIZE, ctx->mem_idx); \ + } \ + gen_set_label(label); \ + if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + process_store(ctx, 1); \ } \ } while (0) #define MEM_LOAD1s(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 1); \ tcg_gen_qemu_ld8s(DST, VA, ctx->mem_idx); \ } while (0) #define MEM_LOAD1u(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 1); \ tcg_gen_qemu_ld8u(DST, VA, ctx->mem_idx); \ } while (0) #define MEM_LOAD2s(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 2); \ tcg_gen_qemu_ld16s(DST, VA, ctx->mem_idx); \ } while (0) #define MEM_LOAD2u(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 2); \ tcg_gen_qemu_ld16u(DST, VA, ctx->mem_idx); \ } while (0) #define MEM_LOAD4s(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 4); \ tcg_gen_qemu_ld32s(DST, VA, ctx->mem_idx); \ } while (0) #define MEM_LOAD4u(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 4); \ tcg_gen_qemu_ld32s(DST, VA, ctx->mem_idx); \ } while (0) #define MEM_LOAD8u(DST, VA) \ do { \ - CHECK_NOSHUF; \ + CHECK_NOSHUF(VA, 8); \ tcg_gen_qemu_ld64(DST, VA, ctx->mem_idx); \ } while (0) @@ -139,7 +156,7 @@ __builtin_choose_expr(TYPE_TCGV(X), \ gen_store1, (void)0)) #define MEM_STORE1(VA, DATA, SLOT) \ - MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT) + MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, SLOT) #define MEM_STORE2_FUNC(X) \ __builtin_choose_expr(TYPE_INT(X), \ @@ -147,7 +164,7 @@ __builtin_choose_expr(TYPE_TCGV(X), \ gen_store2, (void)0)) #define MEM_STORE2(VA, DATA, SLOT) \ - MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT) + MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, SLOT) #define MEM_STORE4_FUNC(X) \ __builtin_choose_expr(TYPE_INT(X), \ @@ -155,7 +172,7 @@ __builtin_choose_expr(TYPE_TCGV(X), \ gen_store4, (void)0)) #define MEM_STORE4(VA, DATA, SLOT) \ - MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT) + MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, SLOT) #define MEM_STORE8_FUNC(X) \ __builtin_choose_expr(TYPE_INT(X), \ @@ -163,7 +180,7 @@ __builtin_choose_expr(TYPE_TCGV_I64(X), \ gen_store8, (void)0)) #define MEM_STORE8(VA, DATA, SLOT) \ - MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT) + MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, SLOT) #else #define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA)) #define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA)) @@ -180,12 +197,21 @@ #define MEM_STORE8(VA, DATA, SLOT) log_store64(env, VA, DATA, 8, SLOT) #endif +#ifdef QEMU_GENERATE +static inline void gen_cancel(uint32_t slot) +{ + tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, 1 << slot); +} + +#define CANCEL gen_cancel(slot); +#else #define CANCEL cancel_slot(env, slot) +#endif #define LOAD_CANCEL(EA) do { CANCEL; } while (0) #ifdef QEMU_GENERATE -static inline void gen_pred_cancel(TCGv pred, int slot_num) +static inline void gen_pred_cancel(TCGv pred, uint32_t slot_num) { TCGv slot_mask = tcg_temp_new(); TCGv tmp = tcg_temp_new(); @@ -381,16 +407,16 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #else #define fREAD_GP() READ_REG(HEX_REG_GP) #endif -#define fREAD_PC() (READ_REG(HEX_REG_PC)) +#define fREAD_PC() (PC) -#define fREAD_NPC() (env->next_PC & (0xfffffffe)) +#define fREAD_NPC() (next_PC & (0xfffffffe)) #define fREAD_P0() (READ_PREG(0)) #define fREAD_P3() (READ_PREG(3)) #define fCHECK_PCALIGN(A) -#define fWRITE_NPC(A) write_new_pc(env, A) +#define fWRITE_NPC(A) write_new_pc(env, pkt_has_multi_cof != 0, A) #define fBRANCH(LOC, TYPE) fWRITE_NPC(LOC) #define fJUMPR(REGNO, TARGET, TYPE) fBRANCH(TARGET, COF_TYPE_JUMPR) diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index b61243103f6c..c9d31d095caa 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -21,6 +21,7 @@ hex_common_py = 'hex_common.py' attribs_def = meson.current_source_dir() / 'attribs_def.h.inc' gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h' gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h' +idef_parser_dir = meson.current_source_dir() / 'idef-parser' # # Step 1 @@ -42,10 +43,7 @@ hexagon_ss.add(semantics_generated) # Step 2 # We use Python scripts to generate the following files # shortcode_generated.h.inc -# helper_protos_generated.h.inc -# tcg_funcs_generated.c.inc # tcg_func_table_generated.c.inc -# helper_funcs_generated.c.inc # printinsn_generated.h.inc # op_regs_generated.h.inc # op_attribs_generated.h.inc @@ -60,24 +58,6 @@ shortcode_generated = custom_target( ) hexagon_ss.add(shortcode_generated) -helper_protos_generated = custom_target( - 'helper_protos_generated.h.inc', - output: 'helper_protos_generated.h.inc', - depends: [semantics_generated], - depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h], - command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'], -) -hexagon_ss.add(helper_protos_generated) - -tcg_funcs_generated = custom_target( - 'tcg_funcs_generated.c.inc', - output: 'tcg_funcs_generated.c.inc', - depends: [semantics_generated], - depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h], - command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'], -) -hexagon_ss.add(tcg_funcs_generated) - tcg_func_table_generated = custom_target( 'tcg_func_table_generated.c.inc', output: 'tcg_func_table_generated.c.inc', @@ -87,15 +67,6 @@ tcg_func_table_generated = custom_target( ) hexagon_ss.add(tcg_func_table_generated) -helper_funcs_generated = custom_target( - 'helper_funcs_generated.c.inc', - output: 'helper_funcs_generated.c.inc', - depends: [semantics_generated], - depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h], - command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'], -) -hexagon_ss.add(helper_funcs_generated) - printinsn_generated = custom_target( 'printinsn_generated.h.inc', output: 'printinsn_generated.h.inc', @@ -179,4 +150,130 @@ hexagon_ss.add(files( 'mmvec/system_ext_mmvec.c', )) +# +# Step 4.5 +# We use flex/bison based idef-parser to generate TCG code for a lot +# of instructions. idef-parser outputs +# idef-generated-emitter.c +# idef-generated-emitter.h.inc +# idef-generated-enabled-instructions +# +idef_parser_enabled = get_option('hexagon_idef_parser') +if idef_parser_enabled and 'hexagon-linux-user' in target_dirs + idef_parser_input_generated = custom_target( + 'idef_parser_input.h.inc', + output: 'idef_parser_input.h.inc', + depends: [semantics_generated], + depend_files: [hex_common_py], + command: [python, files('gen_idef_parser_funcs.py'), semantics_generated, attribs_def, '@OUTPUT@'], + ) + + preprocessed_idef_parser_input_generated = custom_target( + 'idef_parser_input.preprocessed.h.inc', + output: 'idef_parser_input.preprocessed.h.inc', + input: idef_parser_input_generated, + depend_files: [idef_parser_dir / 'macros.inc'], + command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'], + ) + + flex = generator( + find_program('flex'), + output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'], + arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@'] + ) + + bison = generator( + find_program('bison'), + output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'], + arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'] + ) + + glib_dep = dependency('glib-2.0', native: true) + + idef_parser = executable( + 'idef-parser', + [flex.process(idef_parser_dir / 'idef-parser.lex'), + bison.process(idef_parser_dir / 'idef-parser.y'), + idef_parser_dir / 'parser-helpers.c'], + include_directories: ['idef-parser', '../../include/'], + dependencies: [glib_dep], + native: true + ) + + idef_generated_tcg = custom_target( + 'idef-generated-tcg', + output: ['idef-generated-emitter.c', + 'idef-generated-emitter.h.inc', + 'idef-generated-enabled-instructions'], + input: preprocessed_idef_parser_input_generated, + depend_files: [hex_common_py], + command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@'] + ) + + indent = find_program('indent', required: false) + if indent.found() + idef_generated_tcg_c = custom_target( + 'indent', + input: idef_generated_tcg[0], + output: 'idef-generated-emitter.indented.c', + command: [indent, '-linux', '@INPUT@', '-o', '@OUTPUT@'] + ) + else + idef_generated_tcg_c = custom_target( + 'copy', + input: idef_generated_tcg[0], + output: 'idef-generated-emitter.indented.c', + command: ['cp', '@INPUT@', '@OUTPUT@'] + ) + endif + + idef_generated_list = idef_generated_tcg[2].full_path() + + hexagon_ss.add(idef_generated_tcg_c) + + # Setup input and dependencies for the next step, this depends on whether or + # not idef-parser is enabled + helper_dep = [semantics_generated, idef_generated_tcg_c, idef_generated_tcg] + helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, idef_generated_list] +else + # Setup input and dependencies for the next step, this depends on whether or + # not idef-parser is enabled + helper_dep = [semantics_generated] + helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h] +endif + +# +# Step 5 +# We use Python scripts to generate the following files +# helper_protos_generated.h.inc +# helper_funcs_generated.c.inc +# tcg_funcs_generated.c.inc +# +helper_protos_generated = custom_target( + 'helper_protos_generated.h.inc', + output: 'helper_protos_generated.h.inc', + depends: helper_dep, + depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h], + command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'], +) +hexagon_ss.add(helper_protos_generated) + +helper_funcs_generated = custom_target( + 'helper_funcs_generated.c.inc', + output: 'helper_funcs_generated.c.inc', + depends: helper_dep, + depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h], + command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'], +) +hexagon_ss.add(helper_funcs_generated) + +tcg_funcs_generated = custom_target( + 'tcg_funcs_generated.c.inc', + output: 'tcg_funcs_generated.c.inc', + depends: helper_dep, + depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h], + command: [python, files('gen_tcg_funcs.py'), helper_in, '@OUTPUT@'], +) +hexagon_ss.add(tcg_funcs_generated) + target_arch += {'hexagon': hexagon_ss} diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index 8345753580df..8c864e8c6886 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -288,7 +288,7 @@ #endif #ifdef QEMU_GENERATE #define fSTOREMMV(EA, SRC) \ - gen_vreg_store(ctx, insn, pkt, EA, SRC##_off, insn->slot, true) + gen_vreg_store(ctx, EA, SRC##_off, insn->slot, true) #endif #ifdef QEMU_GENERATE #define fSTOREMMVQ(EA, SRC, MASK) \ @@ -300,7 +300,7 @@ #endif #ifdef QEMU_GENERATE #define fSTOREMMVU(EA, SRC) \ - gen_vreg_store(ctx, insn, pkt, EA, SRC##_off, insn->slot, false) + gen_vreg_store(ctx, EA, SRC##_off, insn->slot, false) #endif #define fVFOREACH(WIDTH, VAR) for (VAR = 0; VAR < fVELEM(WIDTH); VAR++) #define fVARRAY_ELEMENT_ACCESS(ARRAY, TYPE, INDEX) \ diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 63e5ad5d68e2..35449ef52436 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -29,14 +29,16 @@ #include "fma_emu.h" #include "mmvec/mmvec.h" #include "mmvec/macros.h" +#include "op_helper.h" #define SF_BIAS 127 #define SF_MANTBITS 23 /* Exceptions processing helpers */ -static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env, - uint32_t exception, - uintptr_t pc) +static G_NORETURN +void do_raise_exception_err(CPUHexagonState *env, + uint32_t exception, + uintptr_t pc) { CPUState *cs = env_cpu(env); qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); @@ -44,13 +46,13 @@ static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env, cpu_loop_exit_restore(cs, pc); } -void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) +G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) { do_raise_exception_err(env, excp, 0); } -static void log_reg_write(CPUHexagonState *env, int rnum, - target_ulong val, uint32_t slot) +void log_reg_write(CPUHexagonState *env, int rnum, + target_ulong val, uint32_t slot) { HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")", rnum, val, val); @@ -81,8 +83,8 @@ static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val) } } -static void log_store32(CPUHexagonState *env, target_ulong addr, - target_ulong val, int width, int slot) +void log_store32(CPUHexagonState *env, target_ulong addr, + target_ulong val, int width, int slot) { HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx ", %" PRId32 " [0x08%" PRIx32 "])\n", @@ -92,8 +94,8 @@ static void log_store32(CPUHexagonState *env, target_ulong addr, env->mem_log_stores[slot].data32 = val; } -static void log_store64(CPUHexagonState *env, target_ulong addr, - int64_t val, int width, int slot) +void log_store64(CPUHexagonState *env, target_ulong addr, + int64_t val, int width, int slot) { HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx ", %" PRId64 " [0x016%" PRIx64 "])\n", @@ -103,21 +105,27 @@ static void log_store64(CPUHexagonState *env, target_ulong addr, env->mem_log_stores[slot].data64 = val; } -static void write_new_pc(CPUHexagonState *env, target_ulong addr) +void write_new_pc(CPUHexagonState *env, bool pkt_has_multi_cof, + target_ulong addr) { HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr); - /* - * If more than one branch is taken in a packet, only the first one - * is actually done. - */ - if (env->branch_taken) { - HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, " - "ignoring the second one\n"); + if (pkt_has_multi_cof) { + /* + * If more than one branch is taken in a packet, only the first one + * is actually done. + */ + if (env->branch_taken) { + HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, " + "ignoring the second one\n"); + } else { + fCHECK_PCALIGN(addr); + env->gpr[HEX_REG_PC] = addr; + env->branch_taken = 1; + } } else { fCHECK_PCALIGN(addr); - env->branch_taken = 1; - env->next_PC = addr; + env->gpr[HEX_REG_PC] = addr; } } @@ -292,7 +300,7 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1) } } - HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC); + HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->gpr[HEX_REG_PC]); HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx ", insn = " TARGET_FMT_lx ", hvx = " TARGET_FMT_lx "\n", @@ -441,6 +449,17 @@ static void probe_store(CPUHexagonState *env, int slot, int mmu_idx) } } +/* + * Called from a mem_noshuf packet to make sure the load doesn't + * raise an exception + */ +void HELPER(probe_noshuf_load)(CPUHexagonState *env, target_ulong va, + int size, int mmu_idx) +{ + uintptr_t retaddr = GETPC(); + probe_read(env, va, size, mmu_idx, retaddr); +} + /* Called during packet commit when there are two scalar stores */ void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int mmu_idx) { @@ -513,43 +532,41 @@ void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask, * If the load is in slot 0 and there is a store in slot1 (that * wasn't cancelled), we have to do the store first. */ -static void check_noshuf(CPUHexagonState *env, uint32_t slot) +static void check_noshuf(CPUHexagonState *env, uint32_t slot, + target_ulong vaddr, int size) { if (slot == 0 && env->pkt_has_store_s1 && ((env->slot_cancelled & (1 << 1)) == 0)) { + HELPER(probe_noshuf_load)(env, vaddr, size, MMU_USER_IDX); HELPER(commit_store)(env, 1); } } -static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { uintptr_t ra = GETPC(); - check_noshuf(env, slot); + check_noshuf(env, slot, vaddr, 1); return cpu_ldub_data_ra(env, vaddr, ra); } -static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { uintptr_t ra = GETPC(); - check_noshuf(env, slot); + check_noshuf(env, slot, vaddr, 2); return cpu_lduw_data_ra(env, vaddr, ra); } -static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { uintptr_t ra = GETPC(); - check_noshuf(env, slot); + check_noshuf(env, slot, vaddr, 4); return cpu_ldl_data_ra(env, vaddr, ra); } -static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr) { uintptr_t ra = GETPC(); - check_noshuf(env, slot); + check_noshuf(env, slot, vaddr, 8); return cpu_ldq_data_ra(env, vaddr, ra); } @@ -1451,7 +1468,7 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV) } } -static void cancel_slot(CPUHexagonState *env, uint32_t slot) +void cancel_slot(CPUHexagonState *env, uint32_t slot) { HEX_DEBUG_LOG("Slot %d cancelled\n", slot); env->slot_cancelled |= (1 << slot); diff --git a/target/hexagon/op_helper.h b/target/hexagon/op_helper.h new file mode 100644 index 000000000000..02347edee8c1 --- /dev/null +++ b/target/hexagon/op_helper.h @@ -0,0 +1,37 @@ +/* + * Copyright(c) 2019-2021 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 + * 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 . + */ + +#ifndef HEXAGON_OP_HELPER_H +#define HEXAGON_OP_HELPER_H + +/* Misc functions */ +void cancel_slot(CPUHexagonState *env, uint32_t slot); +void write_new_pc(CPUHexagonState *env, bool pkt_has_multi_cof, target_ulong addr); + +uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr); +uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr); +uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr); +uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr); + +void log_reg_write(CPUHexagonState *env, int rnum, + target_ulong val, uint32_t slot); +void log_store64(CPUHexagonState *env, target_ulong addr, + int64_t val, int width, int slot); +void log_store32(CPUHexagonState *env, target_ulong addr, + target_ulong val, int width, int slot); + +#endif diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index b6f541ecb237..75f28e08adb7 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.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 @@ -31,7 +31,6 @@ TCGv hex_gpr[TOTAL_PER_THREAD_REGS]; TCGv hex_pred[NUM_PREGS]; -TCGv hex_next_PC; TCGv hex_this_PC; TCGv hex_slot_cancelled; TCGv hex_branch_taken; @@ -117,18 +116,62 @@ static void gen_exec_counters(DisasContext *ctx) hex_gpr[HEX_REG_QEMU_HVX_CNT], ctx->num_hvx_insns); } +static bool use_goto_tb(DisasContext *ctx, target_ulong dest) +{ + return translator_use_goto_tb(&ctx->base, dest); +} + +static void gen_goto_tb(DisasContext *ctx, int idx, target_ulong dest) +{ + if (use_goto_tb(ctx, dest)) { + tcg_gen_goto_tb(idx); + tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], dest); + tcg_gen_exit_tb(ctx->base.tb, idx); + } else { + tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], dest); + tcg_gen_lookup_and_goto_ptr(); + } +} + static void gen_end_tb(DisasContext *ctx) { + Packet *pkt = ctx->pkt; + gen_exec_counters(ctx); - tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC); - tcg_gen_exit_tb(NULL, 0); + + if (ctx->branch_cond != TCG_COND_NEVER) { + if (ctx->branch_cond != TCG_COND_ALWAYS) { + TCGLabel *skip = gen_new_label(); + tcg_gen_brcondi_tl(ctx->branch_cond, hex_branch_taken, 0, skip); + gen_goto_tb(ctx, 0, ctx->branch_dest); + gen_set_label(skip); + gen_goto_tb(ctx, 1, ctx->next_PC); + } else { + gen_goto_tb(ctx, 0, ctx->branch_dest); + } + } else if (ctx->is_tight_loop && + pkt->insn[pkt->num_insns - 1].opcode == J2_endloop0) { + /* + * When we're in a tight loop, we defer the endloop0 processing + * to take advantage of direct block chaining + */ + TCGLabel *skip = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, skip); + tcg_gen_subi_tl(hex_gpr[HEX_REG_LC0], hex_gpr[HEX_REG_LC0], 1); + gen_goto_tb(ctx, 0, ctx->base.tb->pc); + gen_set_label(skip); + gen_goto_tb(ctx, 1, ctx->next_PC); + } else { + tcg_gen_lookup_and_goto_ptr(); + } + ctx->base.is_jmp = DISAS_NORETURN; } static void gen_exception_end_tb(DisasContext *ctx, int excp) { gen_exec_counters(ctx); - tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC); + tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC); gen_exception_raw(excp); ctx->base.is_jmp = DISAS_NORETURN; @@ -194,11 +237,6 @@ static bool check_for_attrib(Packet *pkt, int attrib) return false; } -static bool need_pc(Packet *pkt) -{ - return check_for_attrib(pkt, A_IMPLICIT_READS_PC); -} - static bool need_slot_cancelled(Packet *pkt) { return check_for_attrib(pkt, A_CONDEXEC); @@ -209,12 +247,32 @@ static bool need_pred_written(Packet *pkt) return check_for_attrib(pkt, A_WRITES_PRED_REG); } -static void gen_start_packet(DisasContext *ctx, Packet *pkt) +static bool need_next_PC(DisasContext *ctx) +{ + Packet *pkt = ctx->pkt; + + /* Check for conditional control flow or HW loop end */ + for (int i = 0; i < pkt->num_insns; i++) { + uint16_t opcode = pkt->insn[i].opcode; + if (GET_ATTRIB(opcode, A_CONDEXEC) && GET_ATTRIB(opcode, A_COF)) { + return true; + } + if (GET_ATTRIB(opcode, A_HWLOOP0_END) || + GET_ATTRIB(opcode, A_HWLOOP1_END)) { + return true; + } + } + return false; +} + +static void gen_start_packet(DisasContext *ctx) { + Packet *pkt = ctx->pkt; target_ulong next_PC = ctx->base.pc_next + pkt->encod_pkt_size_in_bytes; int i; /* Clear out the disassembly context */ + ctx->next_PC = next_PC; ctx->reg_log_idx = 0; bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS); ctx->preg_log_idx = 0; @@ -240,15 +298,16 @@ static void gen_start_packet(DisasContext *ctx, Packet *pkt) } /* Initialize the runtime state for packet semantics */ - if (need_pc(pkt)) { - tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next); - } if (need_slot_cancelled(pkt)) { tcg_gen_movi_tl(hex_slot_cancelled, 0); } if (pkt->pkt_has_cof) { - tcg_gen_movi_tl(hex_branch_taken, 0); - tcg_gen_movi_tl(hex_next_PC, next_PC); + if (pkt->pkt_has_multi_cof) { + tcg_gen_movi_tl(hex_branch_taken, 0); + } + if (need_next_PC(ctx)) { + tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], next_PC); + } } if (need_pred_written(pkt)) { tcg_gen_movi_tl(hex_pred_written, 0); @@ -260,8 +319,10 @@ static void gen_start_packet(DisasContext *ctx, Packet *pkt) } } -bool is_gather_store_insn(Insn *insn, Packet *pkt) +bool is_gather_store_insn(DisasContext *ctx) { + Packet *pkt = ctx->pkt; + Insn *insn = ctx->insn; if (GET_ATTRIB(insn->opcode, A_CVI_NEW) && insn->new_value_producer_slot == 1) { /* Look for gather instruction */ @@ -280,16 +341,25 @@ bool is_gather_store_insn(Insn *insn, Packet *pkt) * However, there are some implicit writes marked as attributes * of the applicable instructions. */ -static void mark_implicit_reg_write(DisasContext *ctx, Insn *insn, - int attrib, int rnum) +static void mark_implicit_reg_write(DisasContext *ctx, int attrib, int rnum) { - if (GET_ATTRIB(insn->opcode, attrib)) { + uint16_t opcode = ctx->insn->opcode; + if (GET_ATTRIB(opcode, attrib)) { /* * USR is used to set overflow and FP exceptions, * so treat it as conditional */ - bool is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC) || + bool is_predicated = GET_ATTRIB(opcode, A_CONDEXEC) || rnum == HEX_REG_USR; + + /* LC0/LC1 is conditionally written by endloop instructions */ + if ((rnum == HEX_REG_LC0 || rnum == HEX_REG_LC1) && + (opcode == J2_endloop0 || + opcode == J2_endloop1 || + opcode == J2_endloop01)) { + is_predicated = true; + } + if (is_predicated && !is_preloaded(ctx, rnum)) { tcg_gen_mov_tl(hex_new_value[rnum], hex_gpr[rnum]); } @@ -298,42 +368,65 @@ static void mark_implicit_reg_write(DisasContext *ctx, Insn *insn, } } -static void mark_implicit_pred_write(DisasContext *ctx, Insn *insn, - int attrib, int pnum) +static void mark_implicit_pred_write(DisasContext *ctx, int attrib, int pnum) { - if (GET_ATTRIB(insn->opcode, attrib)) { + if (GET_ATTRIB(ctx->insn->opcode, attrib)) { ctx_log_pred_write(ctx, pnum); } } -static void mark_implicit_reg_writes(DisasContext *ctx, Insn *insn) +static void mark_implicit_reg_writes(DisasContext *ctx) { - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_FP, HEX_REG_FP); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SP, HEX_REG_SP); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LR, HEX_REG_LR); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LC0, HEX_REG_LC0); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1); - mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_USR, HEX_REG_USR); - mark_implicit_reg_write(ctx, insn, A_FPOP, HEX_REG_USR); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_FP, HEX_REG_FP); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SP, HEX_REG_SP); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LR, HEX_REG_LR); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LC0, HEX_REG_LC0); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1); + mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_USR, HEX_REG_USR); + mark_implicit_reg_write(ctx, A_FPOP, HEX_REG_USR); } -static void mark_implicit_pred_writes(DisasContext *ctx, Insn *insn) +static void mark_implicit_pred_writes(DisasContext *ctx) { - mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P0, 0); - mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P1, 1); - mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P2, 2); - mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P3, 3); + mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P0, 0); + mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P1, 1); + mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P2, 2); + mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P3, 3); +} + +static void mark_store_width(DisasContext *ctx) +{ + uint16_t opcode = ctx->insn->opcode; + uint32_t slot = ctx->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) +static void gen_insn(DisasContext *ctx) { - if (insn->generate) { - mark_implicit_reg_writes(ctx, insn); - insn->generate(env, ctx, insn, pkt); - mark_implicit_pred_writes(ctx, insn); + if (ctx->insn->generate) { + mark_implicit_reg_writes(ctx); + ctx->insn->generate(ctx); + mark_implicit_pred_writes(ctx); + mark_store_width(ctx); } else { gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE); } @@ -350,10 +443,18 @@ static void gen_reg_writes(DisasContext *ctx) int reg_num = ctx->reg_log[i]; tcg_gen_mov_tl(hex_gpr[reg_num], hex_new_value[reg_num]); + + /* + * ctx->is_tight_loop is set when SA0 points to the beginning of the TB. + * If we write to SA0, we have to turn off tight loop handling. + */ + if (reg_num == HEX_REG_SA0) { + ctx->is_tight_loop = false; + } } } -static void gen_pred_writes(DisasContext *ctx, Packet *pkt) +static void gen_pred_writes(DisasContext *ctx) { int i; @@ -368,7 +469,7 @@ static void gen_pred_writes(DisasContext *ctx, Packet *pkt) * instructions, we can use the non-conditional * write of the predicates. */ - if (pkt->pkt_has_endloop) { + if (ctx->pkt->pkt_has_endloop) { TCGv zero = tcg_constant_tl(0); TCGv pred_written = tcg_temp_new(); for (i = 0; i < ctx->preg_log_idx; i++) { @@ -414,9 +515,9 @@ static bool slot_is_predicated(Packet *pkt, int slot_num) g_assert_not_reached(); } -void process_store(DisasContext *ctx, Packet *pkt, int slot_num) +void process_store(DisasContext *ctx, int slot_num) { - bool is_predicated = slot_is_predicated(pkt, slot_num); + bool is_predicated = slot_is_predicated(ctx->pkt, slot_num); TCGLabel *label_end = NULL; /* @@ -492,25 +593,28 @@ void process_store(DisasContext *ctx, Packet *pkt, int slot_num) } } -static void process_store_log(DisasContext *ctx, Packet *pkt) +static void process_store_log(DisasContext *ctx) { /* * When a packet has two stores, the hardware processes * 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) { - process_store(ctx, pkt, 1); + Packet *pkt = ctx->pkt; + if (pkt->pkt_has_store_s1) { + g_assert(!pkt->pkt_has_dczeroa); + process_store(ctx, 1); } - if (pkt->pkt_has_store_s0 && !pkt->pkt_has_dczeroa) { - process_store(ctx, pkt, 0); + if (pkt->pkt_has_store_s0) { + g_assert(!pkt->pkt_has_dczeroa); + process_store(ctx, 0); } } /* Zero out a 32-bit cache line */ -static void process_dczeroa(DisasContext *ctx, Packet *pkt) +static void process_dczeroa(DisasContext *ctx) { - if (pkt->pkt_has_dczeroa) { + if (ctx->pkt->pkt_has_dczeroa) { /* Store 32 bytes of zero starting at (addr & ~0x1f) */ TCGv addr = tcg_temp_new(); TCGv_i64 zero = tcg_constant_i64(0); @@ -540,7 +644,7 @@ static bool pkt_has_hvx_store(Packet *pkt) return false; } -static void gen_commit_hvx(DisasContext *ctx, Packet *pkt) +static void gen_commit_hvx(DisasContext *ctx) { int i; @@ -610,13 +714,14 @@ static void gen_commit_hvx(DisasContext *ctx, Packet *pkt) } } - if (pkt_has_hvx_store(pkt)) { + if (pkt_has_hvx_store(ctx->pkt)) { gen_helper_commit_hvx_stores(cpu_env); } } -static void update_exec_counters(DisasContext *ctx, Packet *pkt) +static void update_exec_counters(DisasContext *ctx) { + Packet *pkt = ctx->pkt; int num_insns = pkt->num_insns; int num_real_insns = 0; int num_hvx_insns = 0; @@ -637,8 +742,7 @@ static void update_exec_counters(DisasContext *ctx, Packet *pkt) ctx->num_hvx_insns += num_hvx_insns; } -static void gen_commit_packet(CPUHexagonState *env, DisasContext *ctx, - Packet *pkt) +static void gen_commit_packet(DisasContext *ctx) { /* * If there is more than one store in a packet, make sure they are all OK @@ -657,6 +761,7 @@ static void gen_commit_packet(CPUHexagonState *env, DisasContext *ctx, * store. Therefore, we call process_store_log before anything else * involved in committing the packet. */ + Packet *pkt = ctx->pkt; bool has_store_s0 = pkt->pkt_has_store_s0; bool has_store_s1 = (pkt->pkt_has_store_s1 && !ctx->s1_store_processed); bool has_hvx_store = pkt_has_hvx_store(pkt); @@ -665,8 +770,8 @@ 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); - process_dczeroa(ctx, pkt); + g_assert(!has_store_s1 && !has_hvx_store); + process_dczeroa(ctx); } else if (has_hvx_store) { TCGv mem_idx = tcg_constant_tl(ctx->mem_idx); @@ -697,14 +802,14 @@ static void gen_commit_packet(CPUHexagonState *env, DisasContext *ctx, gen_helper_probe_pkt_scalar_store_s0(cpu_env, mem_idx); } - process_store_log(ctx, pkt); + process_store_log(ctx); gen_reg_writes(ctx); - gen_pred_writes(ctx, pkt); + gen_pred_writes(ctx); if (pkt->pkt_has_hvx) { - gen_commit_hvx(ctx, pkt); + gen_commit_hvx(ctx); } - update_exec_counters(ctx, pkt); + update_exec_counters(ctx); if (HEX_DEBUG) { TCGv has_st0 = tcg_constant_tl(pkt->pkt_has_store_s0 && !pkt->pkt_has_dczeroa); @@ -717,7 +822,8 @@ static void gen_commit_packet(CPUHexagonState *env, DisasContext *ctx, if (pkt->vhist_insn != NULL) { ctx->pre_commit = false; - pkt->vhist_insn->generate(env, ctx, pkt->vhist_insn, pkt); + ctx->insn = pkt->vhist_insn; + pkt->vhist_insn->generate(ctx); } if (pkt->pkt_has_cof) { @@ -739,12 +845,15 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx) } if (decode_packet(nwords, words, &pkt, false) > 0) { + pkt.pc = ctx->base.pc_next; HEX_DEBUG_PRINT_PKT(&pkt); - gen_start_packet(ctx, &pkt); + ctx->pkt = &pkt; + gen_start_packet(ctx); for (i = 0; i < pkt.num_insns; i++) { - gen_insn(env, ctx, &pkt.insn[i], &pkt); + ctx->insn = &pkt.insn[i]; + gen_insn(ctx); } - gen_commit_packet(env, ctx, &pkt); + gen_commit_packet(ctx); ctx->base.pc_next += pkt.encod_pkt_size_in_bytes; } else { gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET); @@ -755,11 +864,14 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); + uint32_t hex_flags = dcbase->tb->flags; ctx->mem_idx = MMU_USER_IDX; ctx->num_packets = 0; ctx->num_insns = 0; ctx->num_hvx_insns = 0; + ctx->branch_cond = TCG_COND_NEVER; + ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP); } static void hexagon_tr_tb_start(DisasContextBase *db, CPUState *cpu) @@ -833,10 +945,11 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void hexagon_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void hexagon_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } @@ -849,11 +962,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 @@ -874,12 +989,6 @@ void hexagon_translate_init(void) opcode_init(); - if (HEX_DEBUG) { - if (!qemu_logfile) { - qemu_set_log(qemu_loglevel); - } - } - for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { hex_gpr[i] = tcg_global_mem_new(cpu_env, offsetof(CPUHexagonState, gpr[i]), @@ -911,8 +1020,6 @@ void hexagon_translate_init(void) } hex_pred_written = tcg_global_mem_new(cpu_env, offsetof(CPUHexagonState, pred_written), "pred_written"); - hex_next_PC = tcg_global_mem_new(cpu_env, - offsetof(CPUHexagonState, next_PC), "next_PC"); hex_this_PC = tcg_global_mem_new(cpu_env, offsetof(CPUHexagonState, this_PC), "this_PC"); hex_slot_cancelled = tcg_global_mem_new(cpu_env, diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index a2451728277d..d971f4f095eb 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -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 @@ -23,10 +23,14 @@ #include "cpu.h" #include "exec/translator.h" #include "tcg/tcg-op.h" +#include "insn.h" #include "internal.h" typedef struct DisasContext { DisasContextBase base; + Packet *pkt; + Insn *insn; + uint32_t next_PC; uint32_t mem_idx; uint32_t num_packets; uint32_t num_insns; @@ -53,6 +57,9 @@ typedef struct DisasContext { bool qreg_is_predicated[NUM_QREGS]; int qreg_log_idx; bool pre_commit; + TCGCond branch_cond; + target_ulong branch_dest; + bool is_tight_loop; } DisasContext; static inline void ctx_log_reg_write(DisasContext *ctx, int rnum) @@ -83,6 +90,12 @@ static inline bool is_preloaded(DisasContext *ctx, int num) return test_bit(num, ctx->regs_written); } +static inline bool is_vreg_preloaded(DisasContext *ctx, int num) +{ + return test_bit(num, ctx->vregs_updated) || + test_bit(num, ctx->vregs_updated_tmp); +} + intptr_t ctx_future_vreg_off(DisasContext *ctx, int regnum, int num, bool alloc_ok); intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum, @@ -125,7 +138,6 @@ static inline void ctx_log_qreg_write(DisasContext *ctx, extern TCGv hex_gpr[TOTAL_PER_THREAD_REGS]; extern TCGv hex_pred[NUM_PREGS]; -extern TCGv hex_next_PC; extern TCGv hex_this_PC; extern TCGv hex_slot_cancelled; extern TCGv hex_branch_taken; @@ -147,6 +159,6 @@ extern TCGv hex_vstore_addr[VSTORES_MAX]; extern TCGv hex_vstore_size[VSTORES_MAX]; extern TCGv hex_vstore_pending[VSTORES_MAX]; -bool is_gather_store_insn(Insn *insn, Packet *pkt); -void process_store(DisasContext *ctx, Packet *pkt, int slot_num); +bool is_gather_store_insn(DisasContext *ctx); +void process_store(DisasContext *ctx, int slot_num); #endif diff --git a/target/hppa/cpu-param.h b/target/hppa/cpu-param.h index a97d1428dff4..a48a2701ae47 100644 --- a/target/hppa/cpu-param.h +++ b/target/hppa/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef HPPA_CPU_PARAM_H -#define HPPA_CPU_PARAM_H 1 +#define HPPA_CPU_PARAM_H #ifdef TARGET_HPPA64 # define TARGET_LONG_BITS 64 diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 5f46ba801eef..55c190280ee6 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; } @@ -61,6 +68,24 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs, cpu->env.psw_n = (tb->flags & PSW_N) != 0; } +static void hppa_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + HPPACPU *cpu = HPPA_CPU(cs); + + cpu->env.iaoq_f = data[0]; + if (data[1] != (target_ureg)-1) { + cpu->env.iaoq_b = data[1]; + } + /* + * Since we were executing the instruction at IAOQ_F, and took some + * sort of action that provoked the cpu_restore_state, we can infer + * that the instruction was not nullified. + */ + cpu->env.psw_n = 0; +} + static bool hppa_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); @@ -73,10 +98,10 @@ static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info) } #ifndef CONFIG_USER_ONLY -static void QEMU_NORETURN -hppa_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) +static G_NORETURN +void hppa_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr) { HPPACPU *cpu = HPPA_CPU(cs); CPUHPPAState *env = &cpu->env; @@ -146,6 +171,7 @@ static const struct SysemuCPUOps hppa_sysemu_ops = { static const struct TCGCPUOps hppa_tcg_ops = { .initialize = hppa_translate_init, .synchronize_from_tb = hppa_cpu_synchronize_from_tb, + .restore_state_to_opc = hppa_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = hppa_cpu_tlb_fill, @@ -168,6 +194,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/cpu.h b/target/hppa/cpu.h index 4cc936b6bfda..6f3b6beecf40 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" /* PA-RISC 1.x processors have a strong memory model. */ /* ??? While we do not yet implement PA-RISC 2.0, those processors have @@ -338,6 +339,6 @@ extern const VMStateDescription vmstate_hppa_cpu; void hppa_cpu_alarm_timer(void *); int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr); #endif -void QEMU_NORETURN hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra); +G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra); #endif /* HPPA_CPU_H */ diff --git a/target/hppa/helper.c b/target/hppa/helper.c index e2758d8df380..74b8747083f9 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/insns.decode b/target/hppa/insns.decode index c7a7e997f9ec..27341d27b282 100644 --- a/target/hppa/insns.decode +++ b/target/hppa/insns.decode @@ -388,10 +388,7 @@ fmpyfadd_d 101110 rm1:5 rm2:5 ... 0 1 ..0 0 0 neg:1 t:5 ra3=%rc32 # Floating point class 0 -# FID. With r = t = 0, which via fcpy puts 0 into fr0. -# This is machine/revision = 0, which is reserved for simulator. -fcpy_f 001100 00000 00000 00000 000000 00000 \ - &fclass01 r=0 t=0 +fid_f 001100 00000 00000 000 00 000000 00000 fcpy_f 001100 ..... ..... 010 00 ...... ..... @f0c_0 fabs_f 001100 ..... ..... 011 00 ...... ..... @f0c_0 diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 2810361be0b7..fbd80e424803 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -28,7 +28,7 @@ #include "fpu/softfloat.h" #include "trace.h" -void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp) +G_NORETURN void HELPER(excp)(CPUHPPAState *env, int excp) { CPUState *cs = env_cpu(env); @@ -36,7 +36,7 @@ void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp) cpu_loop_exit(cs); } -void QEMU_NORETURN hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra) +G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra) { CPUState *cs = env_cpu(env); @@ -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 5c0b1eb274aa..981f8ee03d54 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -566,7 +566,7 @@ static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_reg t) } } -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define HI_OFS 0 # define LO_OFS 4 #else @@ -2899,14 +2899,22 @@ static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf *a) static bool trans_ld(DisasContext *ctx, arg_ldst *a) { - return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, + if (unlikely(TARGET_REGISTER_BITS == 32 && a->size > MO_32)) { + return gen_illegal(ctx); + } else { + return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, a->disp, a->sp, a->m, a->size | MO_TE); + } } static bool trans_st(DisasContext *ctx, arg_ldst *a) { assert(a->x == 0 && a->scale == 0); - return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); + if (unlikely(TARGET_REGISTER_BITS == 32 && a->size > MO_32)) { + return gen_illegal(ctx); + } else { + return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); + } } static bool trans_ldc(DisasContext *ctx, arg_ldst *a) @@ -3614,6 +3622,17 @@ static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) tcg_gen_mov_i32(dst, src); } +static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) +{ + nullify_over(ctx); +#if TARGET_REGISTER_BITS == 64 + save_frd(0, tcg_const_i64(0x13080000000000ULL)); /* PA8700 (PCX-W2) */ +#else + save_frd(0, tcg_const_i64(0x0f080000000000ULL)); /* PA7300LC (PCX-L2) */ +#endif + return nullify_end(ctx); +} + static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) { return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); @@ -4305,29 +4324,30 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void hppa_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { target_ulong pc = dcbase->pc_first; #ifdef CONFIG_USER_ONLY switch (pc) { case 0x00: - qemu_log("IN:\n0x00000000: (null)\n"); + fprintf(logfile, "IN:\n0x00000000: (null)\n"); return; case 0xb0: - qemu_log("IN:\n0x000000b0: light-weight-syscall\n"); + fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); return; case 0xe0: - qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n"); + fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); return; case 0x100: - qemu_log("IN:\n0x00000100: syscall\n"); + fprintf(logfile, "IN:\n0x00000100: syscall\n"); return; } #endif - qemu_log("IN: %s\n", lookup_symbol(pc)); - log_target_disas(cs, pc, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); + target_disas(logfile, cs, pc, dcbase->tb->size); } static const TranslatorOps hppa_tr_ops = { @@ -4339,21 +4359,9 @@ 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); -} - -void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->iaoq_f = data[0]; - if (data[1] != (target_ureg)-1) { - env->iaoq_b = data[1]; - } - /* Since we were executing the instruction at IAOQ_F, and took some - sort of action that provoked the cpu_restore_state, we can infer - that the instruction was not nullified. */ - env->psw_n = 0; + translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); } diff --git a/target/i386/arch_dump.c b/target/i386/arch_dump.c index 004141fc0421..c290910a04b4 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-param.h b/target/i386/cpu-param.h index 57abc64c0d88..f579b16bd279 100644 --- a/target/i386/cpu-param.h +++ b/target/i386/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef I386_CPU_PARAM_H -#define I386_CPU_PARAM_H 1 +#define I386_CPU_PARAM_H #ifdef TARGET_X86_64 # define TARGET_LONG_BITS 64 @@ -23,6 +23,10 @@ # define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif #define TARGET_PAGE_BITS 12 -#define NB_MMU_MODES 3 +#define NB_MMU_MODES 5 + +#ifndef CONFIG_USER_ONLY +# define TARGET_TB_PCREL 1 +#endif #endif diff --git a/target/i386/cpu-qom.h b/target/i386/cpu-qom.h index c557a522e1e8..2350f4ae6098 100644 --- a/target/i386/cpu-qom.h +++ b/target/i386/cpu-qom.h @@ -42,7 +42,7 @@ typedef struct X86CPUModel X86CPUModel; * @migration_safe: See CpuDefinitionInfo::migration_safe * @static_model: See CpuDefinitionInfo::static * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * An x86 CPU model or family. */ @@ -67,7 +67,7 @@ struct X86CPUClass { DeviceRealize parent_realize; DeviceUnrealize parent_unrealize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c index e254d8ba10fb..28115edf44f7 100644 --- a/target/i386/cpu-sysemu.c +++ b/target/i386/cpu-sysemu.c @@ -103,7 +103,7 @@ static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) /* Convert CPU model data from X86CPU object to a property dictionary * that can recreate exactly the same CPU model, including every - * writeable QOM property. + * writable QOM property. */ static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) { @@ -187,10 +187,8 @@ qmp_query_cpu_model_expansion(CpuModelExpansionType type, QDict *props = NULL; const char *base_name; - xc = x86_cpu_from_model(model->name, - model->has_props ? - qobject_to(QDict, model->props) : - NULL, &err); + xc = x86_cpu_from_model(model->name, qobject_to(QDict, model->props), + &err); if (err) { goto out; } @@ -198,7 +196,6 @@ qmp_query_cpu_model_expansion(CpuModelExpansionType type, props = qdict_new(); ret->model = g_new0(CpuModelInfo, 1); ret->model->props = QOBJECT(props); - ret->model->has_props = true; switch (type) { case CPU_MODEL_EXPANSION_TYPE_STATIC: @@ -250,12 +247,16 @@ void x86_cpu_machine_reset_cb(void *opaque) cpu_reset(CPU(cpu)); } -APICCommonClass *apic_get_class(void) +APICCommonClass *apic_get_class(Error **errp) { const char *apic_type = "apic"; /* TODO: in-kernel irqchip for hvf */ - if (kvm_apic_in_kernel()) { + if (kvm_enabled()) { + if (!kvm_apic_in_kernel()) { + error_setg(errp, "KVM does not support userspace APIC"); + return NULL; + } apic_type = "kvm-apic"; } else if (xen_enabled()) { apic_type = "xen-apic"; @@ -269,10 +270,13 @@ APICCommonClass *apic_get_class(void) void x86_cpu_apic_create(X86CPU *cpu, Error **errp) { APICCommonState *apic; - ObjectClass *apic_class = OBJECT_CLASS(apic_get_class()); + APICCommonClass *apic_class = apic_get_class(errp); - cpu->apic_state = DEVICE(object_new_with_class(apic_class)); + if (!apic_class) { + return; + } + cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class))); object_property_add_child(OBJECT(cpu), "lapic", OBJECT(cpu->apic_state)); object_unref(OBJECT(cpu->apic_state)); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index cb6b5467d067..4d2b8d0444df 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -625,13 +625,13 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \ CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \ CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR | \ - CPUID_EXT_RDRAND) + CPUID_EXT_RDRAND | CPUID_EXT_AVX | CPUID_EXT_F16C | \ + CPUID_EXT_FMA) /* missing: CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX, - CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA, + CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA, - CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AVX, - CPUID_EXT_F16C */ + CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER */ #ifdef TARGET_X86_64 #define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM) @@ -653,14 +653,14 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \ - CPUID_7_0_EBX_ERMS) + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2) /* missing: - CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, + CPUID_7_0_EBX_HLE CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_RDSEED */ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) + CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES) #define TCG_7_0_EDX_FEATURES 0 #define TCG_7_1_EAX_FEATURES 0 #define TCG_APM_FEATURES 0 @@ -855,7 +855,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "fsrm", NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, - "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, + "tsx-ldtrk", NULL, NULL /* pconfig */, "arch-lbr", NULL, NULL, "amx-bf16", "avx512-fp16", "amx-tile", "amx-int8", "spec-ctrl", "stibp", NULL, "arch-capabilities", "core-capability", "ssbd", @@ -937,6 +937,34 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .tcg_features = TCG_XSAVE_FEATURES, }, + [FEAT_XSAVE_XSS_LO] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid = { + .eax = 0xD, + .needs_ecx = true, + .ecx = 1, + .reg = R_ECX, + }, + }, + [FEAT_XSAVE_XSS_HI] = { + .type = CPUID_FEATURE_WORD, + .cpuid = { + .eax = 0xD, + .needs_ecx = true, + .ecx = 1, + .reg = R_EDX + }, + }, [FEAT_6_EAX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -952,7 +980,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid = { .eax = 6, .reg = R_EAX, }, .tcg_features = TCG_6_EAX_FEATURES, }, - [FEAT_XSAVE_COMP_LO] = { + [FEAT_XSAVE_XCR0_LO] = { .type = CPUID_FEATURE_WORD, .cpuid = { .eax = 0xD, @@ -965,7 +993,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK, }, - [FEAT_XSAVE_COMP_HI] = { + [FEAT_XSAVE_XCR0_HI] = { .type = CPUID_FEATURE_WORD, .cpuid = { .eax = 0xD, @@ -1205,7 +1233,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .feat_names = { "sgx1", "sgx2", NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "sgx-edeccssa", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1245,7 +1273,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .feat_names = { NULL, "sgx-debug", "sgx-mode64", NULL, "sgx-provisionkey", "sgx-tokenkey", NULL, "sgx-kss", - NULL, NULL, NULL, NULL, + NULL, NULL, "sgx-aex-notify", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1327,6 +1355,14 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID }, .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID }, }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_MPX }, + .to = { FEAT_VMX_EXIT_CTLS, VMX_VM_EXIT_CLEAR_BNDCFGS }, + }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_MPX }, + .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_LOAD_BNDCFGS }, + }, { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED }, .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING }, @@ -1382,6 +1418,9 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { }; #undef REGISTER +/* CPUID feature bits available in XSS */ +#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK) + ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_FP_BIT] = { /* x87 FP state component is always enabled if XSAVE is supported */ @@ -1414,6 +1453,10 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_PKRU_BIT] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, .size = sizeof(XSavePKRU) }, + [XSTATE_ARCH_LBR_BIT] = { + .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_ARCH_LBR, + .offset = 0 /*supervisor mode component, offset = 0 */, + .size = sizeof(XSavesArchLBR) }, [XSTATE_XTILE_CFG_BIT] = { .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, .size = sizeof(XSaveXTILECFG), @@ -1424,15 +1467,18 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { }, }; -static uint32_t xsave_area_size(uint64_t mask) +uint32_t xsave_area_size(uint64_t mask, bool compacted) { + uint64_t ret = x86_ext_save_areas[0].size; + const ExtSaveArea *esa; + uint32_t offset = 0; int i; - uint64_t ret = 0; - for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) { - const ExtSaveArea *esa = &x86_ext_save_areas[i]; + for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + esa = &x86_ext_save_areas[i]; if ((mask >> i) & 1) { - ret = MAX(ret, esa->offset + esa->size); + offset = compacted ? ret : esa->offset; + ret = MAX(ret, offset + esa->size); } } return ret; @@ -1443,10 +1489,10 @@ static inline bool accel_uses_host_cpuid(void) return kvm_enabled() || hvf_enabled(); } -static inline uint64_t x86_cpu_xsave_components(X86CPU *cpu) +static inline uint64_t x86_cpu_xsave_xcr0_components(X86CPU *cpu) { - return ((uint64_t)cpu->env.features[FEAT_XSAVE_COMP_HI]) << 32 | - cpu->env.features[FEAT_XSAVE_COMP_LO]; + return ((uint64_t)cpu->env.features[FEAT_XSAVE_XCR0_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_XCR0_LO]; } /* Return name of 32-bit register, from a R_* constant */ @@ -1458,6 +1504,12 @@ static const char *get_register_name_32(unsigned int reg) return x86_reg_info_32[reg].name; } +static inline uint64_t x86_cpu_xsave_xss_components(X86CPU *cpu) +{ + return ((uint64_t)cpu->env.features[FEAT_XSAVE_XSS_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_XSS_LO]; +} + /* * Returns the set of feature flags that are supported and migratable by * QEMU, for a given FeatureWord. @@ -3258,128 +3310,6 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } } }, - { - .name = "Icelake-Client", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, - .family = 6, - .model = 126, - .stepping = 0, - .features[FEAT_1_EDX] = - CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | - CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | - CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | - CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | - CPUID_DE | CPUID_FP87, - .features[FEAT_1_ECX] = - CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | - CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | - CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | - CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | - CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | - CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, - .features[FEAT_8000_0001_EDX] = - CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | - CPUID_EXT2_SYSCALL, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, - .features[FEAT_8000_0008_EBX] = - CPUID_8000_0008_EBX_WBNOINVD, - .features[FEAT_7_0_EBX] = - CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | - CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | - CPUID_7_0_EBX_SMAP, - .features[FEAT_7_0_ECX] = - CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | - CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | - CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | - CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | - CPUID_7_0_ECX_AVX512_VPOPCNTDQ, - .features[FEAT_7_0_EDX] = - CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD, - /* XSAVES is added in version 3 */ - .features[FEAT_XSAVE] = - CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, - /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ - .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | - MSR_VMX_BASIC_TRUE_CTLS, - .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | - VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | - VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, - .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | - MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | - MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | - MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | - MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | - MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | - MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, - .features[FEAT_VMX_EXIT_CTLS] = - VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | - VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | - VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | - VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | - VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, - .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | - MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, - .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | - VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | - VMX_PIN_BASED_VMX_PREEMPTION_TIMER, - .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | - VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | - VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | - VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | - VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | - VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | - VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | - VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | - VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | - VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | - VMX_CPU_BASED_MONITOR_TRAP_FLAG | - VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, - .features[FEAT_VMX_SECONDARY_CTLS] = - VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | - VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | - VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | - VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | - VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | - VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | - VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, - .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Icelake)", - .versions = (X86CPUVersionDefinition[]) { - { - .version = 1, - .note = "deprecated" - }, - { - .version = 2, - .note = "no TSX, deprecated", - .alias = "Icelake-Client-noTSX", - .props = (PropValue[]) { - { "hle", "off" }, - { "rtm", "off" }, - { /* end of list */ } - }, - }, - { - .version = 3, - .note = "no TSX, XSAVES, deprecated", - .props = (PropValue[]) { - { "xsaves", "on" }, - { "vmx-xsaves", "on" }, - { /* end of list */ } - }, - }, - { /* end of list */ } - }, - .deprecation_note = "use Icelake-Server instead" - }, { .name = "Icelake-Server", .level = 0xd, @@ -3702,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, @@ -4633,8 +4563,8 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) /* XSAVE components are automatically enabled by other features, * so return the original feature name instead */ - if (w == FEAT_XSAVE_COMP_LO || w == FEAT_XSAVE_COMP_HI) { - int comp = (w == FEAT_XSAVE_COMP_HI) ? bitnr + 32 : bitnr; + if (w == FEAT_XSAVE_XCR0_LO || w == FEAT_XSAVE_XCR0_HI) { + int comp = (w == FEAT_XSAVE_XCR0_HI) ? bitnr + 32 : bitnr; if (comp < ARRAY_SIZE(x86_ext_save_areas) && x86_ext_save_areas[comp].bits) { @@ -4907,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); } @@ -4966,7 +4901,6 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data) */ if (default_cpu_version != CPU_VERSION_LEGACY) { info->alias_of = x86_cpu_class_get_alias_of(cc); - info->has_alias_of = !!info->alias_of; } QAPI_LIST_PREPEND(*cpu_list, info); @@ -5022,6 +4956,59 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } +static void x86_cpu_get_supported_cpuid(uint32_t func, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + if (kvm_enabled()) { + *eax = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EAX); + *ebx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EBX); + *ecx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_ECX); + *edx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EDX); + } else if (hvf_enabled()) { + *eax = hvf_get_supported_cpuid(func, index, R_EAX); + *ebx = hvf_get_supported_cpuid(func, index, R_EBX); + *ecx = hvf_get_supported_cpuid(func, index, R_ECX); + *edx = hvf_get_supported_cpuid(func, index, R_EDX); + } else { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } +} + +static void x86_cpu_get_cache_cpuid(uint32_t func, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + uint32_t level, unused; + + /* Only return valid host leaves. */ + switch (func) { + case 2: + case 4: + host_cpuid(0, 0, &level, &unused, &unused, &unused); + break; + case 0x80000005: + case 0x80000006: + case 0x8000001d: + host_cpuid(0x80000000, 0, &level, &unused, &unused, &unused); + break; + default: + return; + } + + if (func > level) { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } else { + host_cpuid(func, index, eax, ebx, ecx, edx); + } +} + /* * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. */ @@ -5280,7 +5267,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 2: /* cache info: needed for Pentium Pro compatibility */ if (cpu->cache_info_passthrough) { - host_cpuid(index, 0, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); break; } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { *eax = *ebx = *ecx = *edx = 0; @@ -5300,11 +5287,23 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 4: /* cache info: needed for Core compatibility */ if (cpu->cache_info_passthrough) { - host_cpuid(index, count, eax, ebx, ecx, edx); - /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ - *eax &= ~0xFC000000; - if ((*eax & 31) && cs->nr_cores > 1) { - *eax |= (cs->nr_cores - 1) << 26; + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); + /* + * QEMU has its own number of cores/logical cpus, + * set 24..14, 31..26 bit to configured values + */ + if (*eax & 31) { + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); + int vcpus_per_socket = env->nr_dies * cs->nr_cores * + cs->nr_threads; + if (cs->nr_cores > 1) { + *eax &= ~0xFC000000; + *eax |= (pow2ceil(cs->nr_cores) - 1) << 26; + } + if (host_vcpus_per_cache > vcpus_per_socket) { + *eax &= ~0x3FFC000; + *eax |= (pow2ceil(vcpus_per_socket) - 1) << 14; + } } } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { *eax = *ebx = *ecx = *edx = 0; @@ -5406,18 +5405,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0xA: /* Architectural Performance Monitoring Leaf */ - if (kvm_enabled() && cpu->enable_pmu) { - KVMState *s = cs->kvm_state; - - *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); - } else if (hvf_enabled() && cpu->enable_pmu) { - *eax = hvf_get_supported_cpuid(0xA, count, R_EAX); - *ebx = hvf_get_supported_cpuid(0xA, count, R_EBX); - *ecx = hvf_get_supported_cpuid(0xA, count, R_ECX); - *edx = hvf_get_supported_cpuid(0xA, count, R_EDX); + if (accel_uses_host_cpuid() && cpu->enable_pmu) { + x86_cpu_get_supported_cpuid(0xA, count, eax, ebx, ecx, edx); } else { *eax = 0; *ebx = 0; @@ -5455,6 +5444,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, assert(!(*eax & ~0x1f)); *ebx &= 0xffff; /* The count doesn't need to be reliable. */ break; + case 0x1C: + if (accel_uses_host_cpuid() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx); + *edx = 0; + } + break; case 0x1F: /* V2 Extended Topology Enumeration Leaf */ if (env->nr_dies < 2) { @@ -5499,25 +5495,47 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } if (count == 0) { - *ecx = xsave_area_size(x86_cpu_xsave_components(cpu)); - *eax = env->features[FEAT_XSAVE_COMP_LO]; - *edx = env->features[FEAT_XSAVE_COMP_HI]; + *ecx = xsave_area_size(x86_cpu_xsave_xcr0_components(cpu), false); + *eax = env->features[FEAT_XSAVE_XCR0_LO]; + *edx = env->features[FEAT_XSAVE_XCR0_HI]; /* * The initial value of xcr0 and ebx == 0, On host without kvm * commit 412a3c41(e.g., CentOS 6), the ebx's value always == 0 * even through guest update xcr0, this will crash some legacy guest * (e.g., CentOS 6), So set ebx == ecx to workaroud it. */ - *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0); + *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0, false); } else if (count == 1) { + uint64_t xstate = x86_cpu_xsave_xcr0_components(cpu) | + x86_cpu_xsave_xss_components(cpu); + *eax = env->features[FEAT_XSAVE]; + *ebx = xsave_area_size(xstate, true); + *ecx = env->features[FEAT_XSAVE_XSS_LO]; + *edx = env->features[FEAT_XSAVE_XSS_HI]; + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR) && + (*eax & CPUID_XSAVE_XSAVES)) { + *ecx |= XSTATE_ARCH_LBR_MASK; + } else { + *ecx &= ~XSTATE_ARCH_LBR_MASK; + } + } else if (count == 0xf && + accel_uses_host_cpuid() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + x86_cpu_get_supported_cpuid(0xD, count, eax, ebx, ecx, edx); } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { - if ((x86_cpu_xsave_components(cpu) >> count) & 1) { - const ExtSaveArea *esa = &x86_ext_save_areas[count]; + const ExtSaveArea *esa = &x86_ext_save_areas[count]; + + if (x86_cpu_xsave_xcr0_components(cpu) & (1ULL << count)) { *eax = esa->size; *ebx = esa->offset; *ecx = esa->ecx & (ESA_FEATURE_ALIGN64_MASK | ESA_FEATURE_XFD_MASK); + } else if (x86_cpu_xsave_xss_components(cpu) & (1ULL << count)) { + *eax = esa->size; + *ebx = 0; + *ecx = 1; } } break; @@ -5557,10 +5575,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * supports. Features can be further restricted by userspace, but not * made more permissive. */ - *eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EDX); + x86_cpu_get_supported_cpuid(0x12, count, eax, ebx, ecx, edx); if (count == 0) { *eax &= env->features[FEAT_SGX_12_0_EAX]; @@ -5568,8 +5583,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } else { *eax &= env->features[FEAT_SGX_12_1_EAX]; *ebx &= 0; /* ebx reserve */ - *ecx &= env->features[FEAT_XSAVE_COMP_LO]; - *edx &= env->features[FEAT_XSAVE_COMP_HI]; + *ecx &= env->features[FEAT_XSAVE_XSS_LO]; + *edx &= env->features[FEAT_XSAVE_XSS_HI]; /* FP and SSE are always allowed regardless of XSAVE/XCR0. */ *ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK; @@ -5702,7 +5717,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x80000005: /* cache info (L1 cache) */ if (cpu->cache_info_passthrough) { - host_cpuid(index, 0, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); break; } *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | @@ -5715,7 +5730,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x80000006: /* cache info (L2 cache) */ if (cpu->cache_info_passthrough) { - host_cpuid(index, 0, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); break; } *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | @@ -5775,7 +5790,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x8000001D: *eax = 0; if (cpu->cache_info_passthrough) { - host_cpuid(index, count, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); break; } switch (count) { @@ -5862,9 +5877,9 @@ static void x86_cpu_set_sgxlepubkeyhash(CPUX86State *env) #endif } -static void x86_cpu_reset(DeviceState *dev) +static void x86_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); X86CPU *cpu = X86_CPU(s); X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu); CPUX86State *env = &cpu->env; @@ -5872,7 +5887,9 @@ static void x86_cpu_reset(DeviceState *dev) uint64_t xcr0; int i; - xcc->parent_reset(dev); + if (xcc->parent_phases.hold) { + xcc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUX86State, end_reset_fields)); @@ -5965,6 +5982,9 @@ static void x86_cpu_reset(DeviceState *dev) } for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; + if (!((1 << i) & CPUID_XSTATE_XCR0_MASK)) { + continue; + } if (env->features[esa->feature] & esa->bits) { xcr0 |= 1ull << i; } @@ -5998,6 +6018,7 @@ static void x86_cpu_reset(DeviceState *dev) env->exception_has_payload = false; env->exception_payload = 0; env->nmi_injected = false; + env->triple_fault_pending = false; #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ apic_designate_bsp(cpu->apic_state, s->cpu_index == 0); @@ -6015,6 +6036,19 @@ static void x86_cpu_reset(DeviceState *dev) #endif } +void x86_cpu_after_reset(X86CPU *cpu) +{ +#ifndef CONFIG_USER_ONLY + if (kvm_enabled()) { + kvm_arch_after_reset_vcpu(cpu); + } + + if (cpu->apic_state) { + device_cold_reset(cpu->apic_state); + } +#endif +} + static void mce_init(X86CPU *cpu) { CPUX86State *cenv = &cpu->env; @@ -6079,8 +6113,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) static bool request_perm; if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { - env->features[FEAT_XSAVE_COMP_LO] = 0; - env->features[FEAT_XSAVE_COMP_HI] = 0; + env->features[FEAT_XSAVE_XCR0_LO] = 0; + env->features[FEAT_XSAVE_XCR0_HI] = 0; return; } @@ -6098,8 +6132,10 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) request_perm = true; } - env->features[FEAT_XSAVE_COMP_LO] = mask; - env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; + env->features[FEAT_XSAVE_XCR0_LO] = mask & CPUID_XSTATE_XCR0_MASK; + env->features[FEAT_XSAVE_XCR0_HI] = mask >> 32; + env->features[FEAT_XSAVE_XSS_LO] = mask & CPUID_XSTATE_XSS_MASK; + env->features[FEAT_XSAVE_XSS_HI] = mask >> 32; } /***** Steps involved on loading and filtering CPUID data @@ -6366,6 +6402,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) CPUX86State *env = &cpu->env; Error *local_err = NULL; static bool ht_warned; + unsigned requested_lbr_fmt; if (cpu->apic_id == UNASSIGNED_APIC_ID) { error_setg(errp, "apic-id property was not initialized properly"); @@ -6383,6 +6420,42 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) goto out; } + /* + * Override env->features[FEAT_PERF_CAPABILITIES].LBR_FMT + * with user-provided setting. + */ + if (cpu->lbr_fmt != ~PERF_CAP_LBR_FMT) { + if ((cpu->lbr_fmt & PERF_CAP_LBR_FMT) != cpu->lbr_fmt) { + error_setg(errp, "invalid lbr-fmt"); + return; + } + env->features[FEAT_PERF_CAPABILITIES] &= ~PERF_CAP_LBR_FMT; + env->features[FEAT_PERF_CAPABILITIES] |= cpu->lbr_fmt; + } + + /* + * vPMU LBR is supported when 1) KVM is enabled 2) Option pmu=on and + * 3)vPMU LBR format matches that of host setting. + */ + requested_lbr_fmt = + env->features[FEAT_PERF_CAPABILITIES] & PERF_CAP_LBR_FMT; + if (requested_lbr_fmt && kvm_enabled()) { + uint64_t host_perf_cap = + x86_cpu_get_supported_feature_word(FEAT_PERF_CAPABILITIES, false); + unsigned host_lbr_fmt = host_perf_cap & PERF_CAP_LBR_FMT; + + if (!cpu->enable_pmu) { + error_setg(errp, "vPMU: LBR is unsupported without pmu=on"); + return; + } + if (requested_lbr_fmt != host_lbr_fmt) { + error_setg(errp, "vPMU: the lbr-fmt value (0x%x) does not match " + "the host value (0x%x).", + requested_lbr_fmt, host_lbr_fmt); + return; + } + } + x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid); if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) { @@ -6735,6 +6808,8 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "sse4_2", obj, "sse4.2"); object_property_add_alias(obj, "hv-apicv", obj, "hv-avic"); + cpu->lbr_fmt = ~PERF_CAP_LBR_FMT; + object_property_add_alias(obj, "lbr_fmt", obj, "lbr-fmt"); if (xcc->model) { x86_cpu_load_model(cpu, xcc->model); @@ -6764,6 +6839,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); @@ -6821,7 +6904,6 @@ static void x86_disas_set_info(CPUState *cs, disassemble_info *info) info->mach = (env->hflags & HF_CS64_MASK ? bfd_mach_x86_64 : env->hflags & HF_CS32_MASK ? bfd_mach_i386_i386 : bfd_mach_i386_i8086); - info->print_insn = print_insn_i386; info->cap_arch = CS_ARCH_X86; info->cap_mode = (env->hflags & HF_CS64_MASK ? CS_MODE_64 @@ -6890,6 +6972,7 @@ static Property x86_cpu_properties[] = { #endif DEFINE_PROP_INT32("node-id", X86CPU, node_id, CPU_UNSET_NUMA_NODE_ID), DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), + DEFINE_PROP_UINT64_CHECKMASK("lbr-fmt", X86CPU, lbr_fmt, PERF_CAP_LBR_FMT), DEFINE_PROP_UINT32("hv-spinlocks", X86CPU, hyperv_spinlock_attempts, HYPERV_SPINLOCK_NEVER_NOTIFY), @@ -6925,8 +7008,18 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_STIMER_DIRECT, 0), DEFINE_PROP_BIT64("hv-avic", X86CPU, hyperv_features, HYPERV_FEAT_AVIC, 0), + DEFINE_PROP_BIT64("hv-emsr-bitmap", X86CPU, hyperv_features, + HYPERV_FEAT_MSR_BITMAP, 0), + DEFINE_PROP_BIT64("hv-xmm-input", X86CPU, hyperv_features, + HYPERV_FEAT_XMM_INPUT, 0), + DEFINE_PROP_BIT64("hv-tlbflush-ext", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH_EXT, 0), + DEFINE_PROP_BIT64("hv-tlbflush-direct", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH_DIRECT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), + DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, + HYPERV_FEAT_SYNDBG, 0), DEFINE_PROP_BOOL("hv-passthrough", X86CPU, hyperv_passthrough, false), DEFINE_PROP_BOOL("hv-enforce-cpuid", X86CPU, hyperv_enforce_cpuid, false), @@ -7020,6 +7113,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) X86CPUClass *xcc = X86_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); FeatureWord w; device_class_set_parent_realize(dc, x86_cpu_realizefn, @@ -7028,7 +7122,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) &xcc->parent_unrealize); device_class_set_props(dc, x86_cpu_properties); - device_class_set_parent_reset(dc, x86_cpu_reset, &xcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, x86_cpu_reset_hold, NULL, + &xcc->parent_phases); cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP; cc->class_by_name = x86_cpu_class_by_name; @@ -7036,6 +7131,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 982c5323537c..d4bc19577a21 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -25,6 +25,7 @@ #include "kvm/hyperv-proto.h" #include "exec/cpu-defs.h" #include "qapi/qapi-types-common.h" +#include "qemu/cpu-float.h" /* The x86 has a strong memory model with some store-after-load re-ordering */ #define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) @@ -168,6 +169,7 @@ typedef enum X86Seg { #define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */ #define HF_MPX_IU_SHIFT 26 /* BND registers in-use */ #define HF_UMIP_SHIFT 27 /* CR4.UMIP */ +#define HF_AVX_EN_SHIFT 28 /* AVX Enabled (CR4+XCR0) */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) @@ -194,6 +196,7 @@ typedef enum X86Seg { #define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT) #define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT) #define HF_UMIP_MASK (1 << HF_UMIP_SHIFT) +#define HF_AVX_EN_MASK (1 << HF_AVX_EN_SHIFT) /* hflags2 */ @@ -385,10 +388,16 @@ typedef enum X86Seg { #define ARCH_CAP_TSX_CTRL_MSR (1<<7) #define MSR_IA32_PERF_CAPABILITIES 0x345 +#define PERF_CAP_LBR_FMT 0x3f #define MSR_IA32_TSX_CTRL 0x122 #define MSR_IA32_TSCDEADLINE 0x6e0 #define MSR_IA32_PKRS 0x6e1 +#define MSR_ARCH_LBR_CTL 0x000014ce +#define MSR_ARCH_LBR_DEPTH 0x000014cf +#define MSR_ARCH_LBR_FROM_0 0x00001500 +#define MSR_ARCH_LBR_TO_0 0x00001600 +#define MSR_ARCH_LBR_INFO_0 0x00001200 #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1ULL << 1) @@ -542,6 +551,7 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_BIT 6 #define XSTATE_Hi16_ZMM_BIT 7 #define XSTATE_PKRU_BIT 9 +#define XSTATE_ARCH_LBR_BIT 15 #define XSTATE_XTILE_CFG_BIT 17 #define XSTATE_XTILE_DATA_BIT 18 @@ -554,6 +564,7 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) +#define XSTATE_ARCH_LBR_MASK (1ULL << XSTATE_ARCH_LBR_BIT) #define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT) #define XSTATE_XTILE_DATA_MASK (1ULL << XSTATE_XTILE_DATA_BIT) @@ -566,6 +577,14 @@ typedef enum X86Seg { #define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) +/* CPUID feature bits available in XCR0 */ +#define CPUID_XSTATE_XCR0_MASK (XSTATE_FP_MASK | XSTATE_SSE_MASK | \ + XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | \ + XSTATE_BNDCSR_MASK | XSTATE_OPMASK_MASK | \ + XSTATE_ZMM_Hi256_MASK | \ + XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK | \ + XSTATE_XTILE_CFG_MASK | XSTATE_XTILE_DATA_MASK) + /* CPUID feature words */ typedef enum FeatureWord { FEAT_1_EDX, /* CPUID[1].EDX */ @@ -584,8 +603,8 @@ typedef enum FeatureWord { FEAT_SVM, /* CPUID[8000_000A].EDX */ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ FEAT_6_EAX, /* CPUID[6].EAX */ - FEAT_XSAVE_COMP_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ - FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ + FEAT_XSAVE_XCR0_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ + FEAT_XSAVE_XCR0_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEAT_ARCH_CAPABILITIES, FEAT_CORE_CAPABILITY, FEAT_PERF_CAPABILITIES, @@ -602,6 +621,8 @@ typedef enum FeatureWord { FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ + FEAT_XSAVE_XSS_LO, /* CPUID[EAX=0xd,ECX=1].ECX */ + FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */ FEATURE_WORDS, } FeatureWord; @@ -858,6 +879,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define CPUID_7_0_EDX_SERIALIZE (1U << 14) /* TSX Suspend Load Address Tracking instruction */ #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) +/* Architectural LBRs */ +#define CPUID_7_0_EDX_ARCH_LBR (1U << 19) /* AVX512_FP16 instruction */ #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) /* AMX tile (two-dimensional register) */ @@ -1084,6 +1107,11 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_IPI 13 #define HYPERV_FEAT_STIMER_DIRECT 14 #define HYPERV_FEAT_AVIC 15 +#define HYPERV_FEAT_SYNDBG 16 +#define HYPERV_FEAT_MSR_BITMAP 17 +#define HYPERV_FEAT_XMM_INPUT 18 +#define HYPERV_FEAT_TLBFLUSH_EXT 19 +#define HYPERV_FEAT_TLBFLUSH_DIRECT 20 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF @@ -1207,32 +1235,35 @@ typedef struct SegmentCache { uint32_t flags; } SegmentCache; -#define MMREG_UNION(n, bits) \ - union n { \ - uint8_t _b_##n[(bits)/8]; \ - uint16_t _w_##n[(bits)/16]; \ - uint32_t _l_##n[(bits)/32]; \ - uint64_t _q_##n[(bits)/64]; \ - float32 _s_##n[(bits)/32]; \ - float64 _d_##n[(bits)/64]; \ - } - -typedef union { - uint8_t _b[16]; - uint16_t _w[8]; - uint32_t _l[4]; - uint64_t _q[2]; +typedef union MMXReg { + uint8_t _b_MMXReg[64 / 8]; + uint16_t _w_MMXReg[64 / 16]; + uint32_t _l_MMXReg[64 / 32]; + uint64_t _q_MMXReg[64 / 64]; + float32 _s_MMXReg[64 / 32]; + float64 _d_MMXReg[64 / 64]; +} MMXReg; + +typedef union XMMReg { + uint64_t _q_XMMReg[128 / 64]; } XMMReg; -typedef union { - uint8_t _b[32]; - uint16_t _w[16]; - uint32_t _l[8]; - uint64_t _q[4]; +typedef union YMMReg { + uint64_t _q_YMMReg[256 / 64]; + XMMReg _x_YMMReg[256 / 128]; } YMMReg; -typedef MMREG_UNION(ZMMReg, 512) ZMMReg; -typedef MMREG_UNION(MMXReg, 64) MMXReg; +typedef union ZMMReg { + uint8_t _b_ZMMReg[512 / 8]; + uint16_t _w_ZMMReg[512 / 16]; + uint32_t _l_ZMMReg[512 / 32]; + uint64_t _q_ZMMReg[512 / 64]; + float16 _h_ZMMReg[512 / 16]; + float32 _s_ZMMReg[512 / 32]; + float64 _d_ZMMReg[512 / 64]; + XMMReg _x_ZMMReg[512 / 128]; + YMMReg _y_ZMMReg[512 / 256]; +} ZMMReg; typedef struct BNDReg { uint64_t lb; @@ -1248,13 +1279,21 @@ typedef struct BNDCSReg { #define BNDCFG_BNDPRESERVE 2ULL #define BNDCFG_BDIR_MASK TARGET_PAGE_MASK -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define ZMM_B(n) _b_ZMMReg[63 - (n)] #define ZMM_W(n) _w_ZMMReg[31 - (n)] #define ZMM_L(n) _l_ZMMReg[15 - (n)] +#define ZMM_H(n) _h_ZMMReg[31 - (n)] #define ZMM_S(n) _s_ZMMReg[15 - (n)] #define ZMM_Q(n) _q_ZMMReg[7 - (n)] #define ZMM_D(n) _d_ZMMReg[7 - (n)] +#define ZMM_X(n) _x_ZMMReg[3 - (n)] +#define ZMM_Y(n) _y_ZMMReg[1 - (n)] + +#define XMM_Q(n) _q_XMMReg[1 - (n)] + +#define YMM_Q(n) _q_YMMReg[3 - (n)] +#define YMM_X(n) _x_YMMReg[1 - (n)] #define MMX_B(n) _b_MMXReg[7 - (n)] #define MMX_W(n) _w_MMXReg[3 - (n)] @@ -1264,9 +1303,17 @@ typedef struct BNDCSReg { #define ZMM_B(n) _b_ZMMReg[n] #define ZMM_W(n) _w_ZMMReg[n] #define ZMM_L(n) _l_ZMMReg[n] +#define ZMM_H(n) _h_ZMMReg[n] #define ZMM_S(n) _s_ZMMReg[n] #define ZMM_Q(n) _q_ZMMReg[n] #define ZMM_D(n) _d_ZMMReg[n] +#define ZMM_X(n) _x_ZMMReg[n] +#define ZMM_Y(n) _y_ZMMReg[n] + +#define XMM_Q(n) _q_XMMReg[n] + +#define YMM_Q(n) _q_YMMReg[n] +#define YMM_X(n) _x_YMMReg[n] #define MMX_B(n) _b_MMXReg[n] #define MMX_W(n) _w_MMXReg[n] @@ -1377,6 +1424,24 @@ typedef struct XSaveXTILEDATA { uint8_t xtiledata[8][1024]; } XSaveXTILEDATA; +typedef struct { + uint64_t from; + uint64_t to; + uint64_t info; +} LBREntry; + +#define ARCH_LBR_NR_ENTRIES 32 + +/* Ext. save area 19: Supervisor mode Arch LBR state */ +typedef struct XSavesArchLBR { + uint64_t lbr_ctl; + uint64_t lbr_depth; + uint64_t ler_from; + uint64_t ler_to; + uint64_t ler_info; + LBREntry lbr_records[ARCH_LBR_NR_ENTRIES]; +} XSavesArchLBR; + QEMU_BUILD_BUG_ON(sizeof(XSaveAVX) != 0x100); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDCSR) != 0x40); @@ -1386,6 +1451,7 @@ QEMU_BUILD_BUG_ON(sizeof(XSaveHi16_ZMM) != 0x400); QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); QEMU_BUILD_BUG_ON(sizeof(XSaveXTILECFG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveXTILEDATA) != 0x2000); +QEMU_BUILD_BUG_ON(sizeof(XSavesArchLBR) != 0x328); typedef struct ExtSaveArea { uint32_t feature, bits; @@ -1525,15 +1591,11 @@ typedef struct CPUArchState { float_status mmx_status; /* for 3DNow! float ops */ float_status sse_status; uint32_t mxcsr; - ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32]; - ZMMReg xmm_t0; + ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32] QEMU_ALIGNED(16); + ZMMReg xmm_t0 QEMU_ALIGNED(16); MMXReg mmx_t0; - XMMReg ymmh_regs[CPU_NB_REGS]; - uint64_t opmask_regs[NB_OPMASK_REGS]; - YMMReg zmmh_regs[CPU_NB_REGS]; - ZMMReg hi16_zmm_regs[CPU_NB_REGS]; #ifdef TARGET_X86_64 uint8_t xtilecfg[64]; uint8_t xtiledata[8192]; @@ -1600,6 +1662,12 @@ typedef struct CPUArchState { uint64_t msr_hv_hypercall; uint64_t msr_hv_guest_os_id; uint64_t msr_hv_tsc; + uint64_t msr_hv_syndbg_control; + uint64_t msr_hv_syndbg_status; + uint64_t msr_hv_syndbg_send_page; + uint64_t msr_hv_syndbg_recv_page; + uint64_t msr_hv_syndbg_pending_page; + uint64_t msr_hv_syndbg_options; /* Per-VCPU HV MSRs */ uint64_t msr_hv_vapic; @@ -1626,6 +1694,11 @@ typedef struct CPUArchState { uint64_t msr_xfd; uint64_t msr_xfd_err; + /* Per-VCPU Arch LBR MSRs */ + uint64_t msr_lbr_ctl; + uint64_t msr_lbr_depth; + LBREntry lbr_records[ARCH_LBR_NR_ENTRIES]; + /* exception/interrupt handling */ int error_code; int exception_is_int; @@ -1701,6 +1774,7 @@ typedef struct CPUArchState { uint8_t has_error_code; uint8_t exception_has_payload; uint64_t exception_payload; + uint8_t triple_fault_pending; uint32_t ins_len; uint32_t sipi_vector; bool tsc_valid; @@ -1770,7 +1844,6 @@ struct ArchCPU { uint32_t hyperv_vendor_id[3]; uint32_t hyperv_interface_id[4]; uint32_t hyperv_limits[3]; - uint32_t hyperv_nested[4]; bool hyperv_enforce_cpuid; uint32_t hyperv_ver_id_build; uint16_t hyperv_ver_id_major; @@ -1820,6 +1893,15 @@ struct ArchCPU { */ bool enable_pmu; + /* + * Enable LBR_FMT bits of IA32_PERF_CAPABILITIES MSR. + * This can't be initialized with a default because it doesn't have + * stable ABI support yet. It is only allowed to pass all LBR_FMT bits + * returned by kvm_arch_get_supported_msr_feature()(which depends on both + * host CPU and kernel capabilities) to the guest. + */ + uint64_t lbr_fmt; + /* LMCE support can be enabled/disabled via cpu option 'lmce=on/off'. It is * disabled by default to avoid breaking migration between QEMU with * different LMCE configurations. @@ -1892,13 +1974,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); @@ -2024,6 +2106,8 @@ void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32); void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32); void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr); void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr); +void cpu_x86_xsave(CPUX86State *s, target_ulong ptr); +void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr); /* cpu.c */ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, @@ -2033,6 +2117,8 @@ typedef struct PropValue { } PropValue; void x86_cpu_apply_props(X86CPU *cpu, PropValue *props); +void x86_cpu_after_reset(X86CPU *cpu); + uint32_t cpu_x86_virtual_addr_width(CPUX86State *env); /* cpu.c other functions (cpuid) */ @@ -2045,6 +2131,7 @@ void host_cpuid(uint32_t function, uint32_t count, /* helper.c */ void x86_cpu_set_a20(X86CPU *cpu, int a20_state); +void cpu_sync_avx_hflag(CPUX86State *env); #ifndef CONFIG_USER_ONLY static inline int x86_asidx_from_attrs(CPUState *cs, MemTxAttrs attrs) @@ -2098,6 +2185,9 @@ uint64_t cpu_get_tsc(CPUX86State *env); #define MMU_KSMAP_IDX 0 #define MMU_USER_IDX 1 #define MMU_KNOSMAP_IDX 2 +#define MMU_NESTED_IDX 3 +#define MMU_PHYS_IDX 4 + static inline int cpu_mmu_index(CPUX86State *env, bool ifetch) { return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX : @@ -2280,6 +2370,7 @@ bool cpu_is_bsp(X86CPU *cpu); void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen); void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen); +uint32_t xsave_area_size(uint64_t mask, bool compacted); void x86_update_hflags(CPUX86State* env); static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat) @@ -2332,8 +2423,6 @@ static inline bool ctl_has_irq(CPUX86State *env) return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); } -hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, - int *prot); #if defined(TARGET_X86_64) && \ defined(CONFIG_USER_ONLY) && \ defined(CONFIG_LINUX) diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index 098a2ad15a9c..c3a2cf6f2825 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -129,8 +129,8 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) n -= IDX_XMM_REGS; if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) { return gdb_get_reg128(mem_buf, - env->xmm_regs[n].ZMM_Q(0), - env->xmm_regs[n].ZMM_Q(1)); + env->xmm_regs[n].ZMM_Q(1), + env->xmm_regs[n].ZMM_Q(0)); } } else { switch (n) { diff --git a/target/i386/hax/hax-accel-ops.h b/target/i386/hax/hax-accel-ops.h index c7698519cd5e..9e357e7b4042 100644 --- a/target/i386/hax/hax-accel-ops.h +++ b/target/i386/hax/hax-accel-ops.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef HAX_CPUS_H -#define HAX_CPUS_H +#ifndef TARGET_I386_HAX_ACCEL_OPS_H +#define TARGET_I386_HAX_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -28,4 +28,4 @@ int hax_vcpu_destroy(CPUState *cpu); void hax_raise_event(CPUState *cpu); void hax_reset_vcpu_state(void *opaque); -#endif /* HAX_CPUS_H */ +#endif /* TARGET_I386_HAX_ACCEL_OPS_H */ diff --git a/target/i386/hax/hax-all.c b/target/i386/hax/hax-all.c index 81f665e21245..b7fb5385b251 100644 --- a/target/i386/hax/hax-all.c +++ b/target/i386/hax/hax-all.c @@ -27,7 +27,6 @@ #include "cpu.h" #include "exec/address-spaces.h" -#include "qemu-common.h" #include "qemu/accel.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" @@ -389,7 +388,7 @@ static int hax_handle_io(CPUArchState *env, uint32_t df, uint16_t port, MemTxAttrs attrs = { 0 }; if (!df) { - ptr = (uint8_t *) buffer; + ptr = buffer; } else { ptr = buffer + size * count - size; } diff --git a/target/i386/hax/hax-mem.c b/target/i386/hax/hax-mem.c index a226d174d8ef..05dbe8cce3ae 100644 --- a/target/i386/hax/hax-mem.c +++ b/target/i386/hax/hax-mem.c @@ -188,15 +188,15 @@ static void hax_process_section(MemoryRegionSection *section, uint8_t flags) /* Adjust start_pa and size so that they are page-aligned. (Cf * kvm_set_phys_mem() in kvm-all.c). */ - delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask); - delta &= ~qemu_real_host_page_mask; + delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask()); + delta &= ~qemu_real_host_page_mask(); if (delta > size) { return; } start_pa += delta; size -= delta; - size &= qemu_real_host_page_mask; - if (!size || (start_pa & ~qemu_real_host_page_mask)) { + size &= qemu_real_host_page_mask(); + if (!size || (start_pa & ~qemu_real_host_page_mask())) { return; } @@ -214,7 +214,7 @@ static void hax_process_section(MemoryRegionSection *section, uint8_t flags) * call into the kernel. Instead, we split the mapping into smaller ones, * and call hax_update_mapping() on each. */ - max_mapping_size = UINT32_MAX & qemu_real_host_page_mask; + max_mapping_size = UINT32_MAX & qemu_real_host_page_mask(); while (size > max_mapping_size) { hax_update_mapping(start_pa, max_mapping_size, host_va, flags); start_pa += max_mapping_size; diff --git a/target/i386/helper.c b/target/i386/helper.c index fa409e9c44a8..0ac2da066d5a 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -29,6 +29,17 @@ #endif #include "qemu/log.h" +void cpu_sync_avx_hflag(CPUX86State *env) +{ + if ((env->cr[4] & CR4_OSXSAVE_MASK) + && (env->xcr0 & (XSTATE_SSE_MASK | XSTATE_YMM_MASK)) + == (XSTATE_SSE_MASK | XSTATE_YMM_MASK)) { + env->hflags |= HF_AVX_EN_MASK; + } else{ + env->hflags &= ~HF_AVX_EN_MASK; + } +} + void cpu_sync_bndcs_hflags(CPUX86State *env) { uint32_t hflags = env->hflags; @@ -209,6 +220,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) env->hflags = hflags; cpu_sync_bndcs_hflags(env); + cpu_sync_avx_hflag(env); } #if !defined(CONFIG_USER_ONLY) @@ -415,7 +427,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; @@ -497,6 +509,27 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, } } +static inline target_ulong get_memio_eip(CPUX86State *env) +{ +#ifdef CONFIG_TCG + uint64_t data[TARGET_INSN_START_WORDS]; + CPUState *cs = env_cpu(env); + + if (!cpu_unwind_state_data(cs, cs->mem_io_pc, data)) { + return env->eip; + } + + /* Per x86_restore_state_to_opc. */ + if (TARGET_TB_PCREL) { + return (env->eip & TARGET_PAGE_MASK) | data[0]; + } else { + return data[0] - env->segs[R_CS].base; + } +#else + qemu_build_not_reached(); +#endif +} + void cpu_report_tpr_access(CPUX86State *env, TPRAccess access) { X86CPU *cpu = env_archcpu(env); @@ -507,9 +540,9 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access) cpu_interrupt(cs, CPU_INTERRUPT_TPR); } else if (tcg_enabled()) { - cpu_restore_state(cs, cs->mem_io_pc, false); + target_ulong eip = get_memio_eip(env); - apic_handle_tpr_access_report(cpu->apic_state, env->eip, access); + apic_handle_tpr_access_report(cpu->apic_state, eip, access); } } #endif /* !CONFIG_USER_ONLY */ diff --git a/target/i386/helper.h b/target/i386/helper.h index ac3b4d1ee329..b7de5429ef62 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -37,7 +37,7 @@ DEF_HELPER_2(lldt, void, env, int) DEF_HELPER_2(ltr, void, env, int) DEF_HELPER_3(load_seg, void, env, int, int) DEF_HELPER_4(ljmp_protected, void, env, int, tl, tl) -DEF_HELPER_5(lcall_real, void, env, int, tl, int, int) +DEF_HELPER_5(lcall_real, void, env, i32, i32, int, i32) DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl) DEF_HELPER_2(iret_real, void, env, int) DEF_HELPER_3(iret_protected, void, env, int, int) @@ -56,13 +56,8 @@ DEF_HELPER_2(syscall, void, env, int) DEF_HELPER_2(sysret, void, env, int) #endif DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int) -DEF_HELPER_1(reset_rf, void, env) DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int) DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int) -DEF_HELPER_1(cli, void, env) -DEF_HELPER_1(sti, void, env) -DEF_HELPER_1(clac, void, env) -DEF_HELPER_1(stac, void, env) DEF_HELPER_3(boundw, void, env, tl, int) DEF_HELPER_3(boundl, void, env, tl, int) @@ -212,12 +207,13 @@ DEF_HELPER_2(ldmxcsr, void, env, i32) DEF_HELPER_1(update_mxcsr, void, env) DEF_HELPER_1(enter_mmx, void, env) DEF_HELPER_1(emms, void, env) -DEF_HELPER_3(movq, void, env, ptr, ptr) #define SHIFT 0 #include "ops_sse_header.h" #define SHIFT 1 #include "ops_sse_header.h" +#define SHIFT 2 +#include "ops_sse_header.h" DEF_HELPER_3(rclb, tl, env, tl, tl) DEF_HELPER_3(rclw, tl, env, tl, tl) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index fc12c02fb217..8d2248bb3f6f 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -47,7 +47,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/memalign.h" @@ -222,6 +221,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) { X86CPU *x86cpu = X86_CPU(cpu); CPUX86State *env = &x86cpu->env; + uint64_t reqCap; init_emu(); init_decoder(); @@ -258,19 +258,26 @@ int hvf_arch_init_vcpu(CPUState *cpu) /* set VMCS control fields */ wvmcs(cpu->hvf->fd, VMCS_PIN_BASED_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_pinbased, - VMCS_PIN_BASED_CTLS_EXTINT | - VMCS_PIN_BASED_CTLS_NMI | - VMCS_PIN_BASED_CTLS_VNMI)); + VMCS_PIN_BASED_CTLS_EXTINT | + VMCS_PIN_BASED_CTLS_NMI | + VMCS_PIN_BASED_CTLS_VNMI)); wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased, - VMCS_PRI_PROC_BASED_CTLS_HLT | - VMCS_PRI_PROC_BASED_CTLS_MWAIT | - VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET | - VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW) | + VMCS_PRI_PROC_BASED_CTLS_HLT | + VMCS_PRI_PROC_BASED_CTLS_MWAIT | + VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET | + VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW) | VMCS_PRI_PROC_BASED_CTLS_SEC_CONTROL); + + reqCap = VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES; + + /* Is RDTSCP support in CPUID? If so, enable it in the VMCS. */ + if (hvf_get_supported_cpuid(0x80000001, 0, R_EDX) & CPUID_EXT2_RDTSCP) { + reqCap |= VMCS_PRI_PROC_BASED2_CTLS_RDTSCP; + } + wvmcs(cpu->hvf->fd, VMCS_SEC_PROC_BASED_CTLS, - cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2, - VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES)); + cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2, reqCap)); wvmcs(cpu->hvf->fd, VMCS_ENTRY_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_entry, 0)); diff --git a/target/i386/hvf/vmcs.h b/target/i386/hvf/vmcs.h index 42de7ebc3af2..aee6f75dfd57 100644 --- a/target/i386/hvf/vmcs.h +++ b/target/i386/hvf/vmcs.h @@ -330,7 +330,7 @@ #define EPT_VIOLATION_DATA_WRITE (1UL << 1) #define EPT_VIOLATION_INST_FETCH (1UL << 2) #define EPT_VIOLATION_GPA_READABLE (1UL << 3) -#define EPT_VIOLATION_GPA_WRITEABLE (1UL << 4) +#define EPT_VIOLATION_GPA_WRITABLE (1UL << 4) #define EPT_VIOLATION_GPA_EXECUTABLE (1UL << 5) #define EPT_VIOLATION_GLA_VALID (1UL << 7) #define EPT_VIOLATION_XLAT_VALID (1UL << 8) @@ -354,7 +354,7 @@ #define VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET (1 << 3) #define VMCS_PRI_PROC_BASED_CTLS_HLT (1 << 7) #define VMCS_PRI_PROC_BASED_CTLS_MWAIT (1 << 10) -#define VMCS_PRI_PROC_BASED_CTLS_TSC (1 << 12) +#define VMCS_PRI_PROC_BASED_CTLS_RDTSC (1 << 12) #define VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD (1 << 19) #define VMCS_PRI_PROC_BASED_CTLS_CR8_STORE (1 << 20) #define VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW (1 << 21) @@ -362,6 +362,7 @@ #define VMCS_PRI_PROC_BASED_CTLS_SEC_CONTROL (1 << 31) #define VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES (1 << 0) +#define VMCS_PRI_PROC_BASED2_CTLS_RDTSCP (1 << 3) #define VMCS_PRI_PROC_BASED2_CTLS_X2APIC (1 << 4) enum task_switch_reason { diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 573ddc33c07b..fcd9a95e5b5c 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -80,7 +80,7 @@ static inline uint64_t cap2ctrl(uint64_t cap, uint64_t ctrl) #define AR_TYPE_ACCESSES_MASK 1 #define AR_TYPE_READABLE_MASK (1 << 1) -#define AR_TYPE_WRITEABLE_MASK (1 << 2) +#define AR_TYPE_WRITABLE_MASK (1 << 2) #define AR_TYPE_CODE_MASK (1 << 3) #define AR_TYPE_MASK 0x0f #define AR_TYPE_BUSY_64_TSS 11 diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index 91a3fe002c73..d086584f26d9 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "qemu-common.h" #include "x86_decode.h" #include "x86_emu.h" #include "vmcs.h" diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c index 32b0d131df86..7323a7a94b1e 100644 --- a/target/i386/hvf/x86_cpuid.c +++ b/target/i386/hvf/x86_cpuid.c @@ -21,7 +21,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "x86.h" #include "vmx.h" @@ -96,7 +95,8 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, ebx &= ~CPUID_7_0_EBX_INVPCID; } - ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ; + ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ | + CPUID_7_0_ECX_RDPID; edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS; } else { ebx = 0; @@ -133,11 +133,11 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX; hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap); - if (!(cap & CPU_BASED2_RDTSCP)) { + if (!(cap2ctrl(cap, CPU_BASED2_RDTSCP) & CPU_BASED2_RDTSCP)) { edx &= ~CPUID_EXT2_RDTSCP; } hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap); - if (!(cap & CPU_BASED_TSC_OFFSET)) { + if (!(cap2ctrl(cap, CPU_BASED_TSC_OFFSET) & CPU_BASED_TSC_OFFSET)) { edx &= ~CPUID_EXT2_RDTSCP; } ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG | diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 062713b1a450..3728d7705e21 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "panic.h" #include "x86_decode.h" #include "vmx.h" diff --git a/target/i386/hvf/x86_descr.c b/target/i386/hvf/x86_descr.c index af15c06ac5db..a484942cfcd4 100644 --- a/target/i386/hvf/x86_descr.c +++ b/target/i386/hvf/x86_descr.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "vmx.h" #include "x86_descr.h" diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 050428795bbc..f5704f63e8da 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -37,7 +37,6 @@ #include "qemu/osdep.h" #include "panic.h" -#include "qemu-common.h" #include "x86_decode.h" #include "x86.h" #include "x86_emu.h" diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index fecbca751770..03d6de5efc3e 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "panic.h" #include "cpu.h" #include "x86_flags.h" diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index df0b91cd4208..96d117567ee8 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "panic.h" -#include "qemu-common.h" #include "cpu.h" #include "x86.h" #include "x86_mmu.h" diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index d24daf6a4110..beaeec068731 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -8,7 +8,6 @@ // GNU General Public License for more details. #include "qemu/osdep.h" #include "panic.h" -#include "qemu-common.h" #include "qemu/error-report.h" #include "sysemu/hvf.h" diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index bec9fc581463..69d4fb8cf555 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "x86hvf.h" #include "vmx.h" #include "vmcs.h" diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index 89f81afda7c6..464fbf09e35a 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -19,6 +19,9 @@ #define HV_CPUID_ENLIGHTMENT_INFO 0x40000004 #define HV_CPUID_IMPLEMENT_LIMITS 0x40000005 #define HV_CPUID_NESTED_FEATURES 0x4000000A +#define HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS 0x40000080 +#define HV_CPUID_SYNDBG_INTERFACE 0x40000081 +#define HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES 0x40000082 #define HV_CPUID_MIN 0x40000005 #define HV_CPUID_MAX 0x4000ffff #define HV_HYPERVISOR_PRESENT_BIT 0x80000000 @@ -51,12 +54,19 @@ #define HV_GUEST_DEBUGGING_AVAILABLE (1u << 1) #define HV_PERF_MONITOR_AVAILABLE (1u << 2) #define HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1u << 3) -#define HV_HYPERCALL_PARAMS_XMM_AVAILABLE (1u << 4) +#define HV_HYPERCALL_XMM_INPUT_AVAILABLE (1u << 4) #define HV_GUEST_IDLE_STATE_AVAILABLE (1u << 5) #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) #define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) +#define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11) +#define HV_EXT_GVA_RANGES_FLUSH_AVAILABLE (1u << 14) #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19) +/* + * HV_CPUID_FEATURES.EBX bits + */ +#define HV_PARTITION_DEBUGGING_ALLOWED (1u << 12) + /* * HV_CPUID_ENLIGHTMENT_INFO.EAX bits */ @@ -72,6 +82,17 @@ #define HV_ENLIGHTENED_VMCS_RECOMMENDED (1u << 14) #define HV_NO_NONARCH_CORESHARING (1u << 18) +/* + * HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX bits + */ +#define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING (1u << 1) + +/* + * HV_CPUID_NESTED_FEATURES.EAX bits + */ +#define HV_NESTED_DIRECT_FLUSH (1u << 17) +#define HV_NESTED_MSR_BITMAP (1u << 19) + /* * Basic virtualized MSRs */ @@ -130,6 +151,18 @@ #define HV_X64_MSR_STIMER3_CONFIG 0x400000B6 #define HV_X64_MSR_STIMER3_COUNT 0x400000B7 +/* + * Hyper-V Synthetic debug options MSR + */ +#define HV_X64_MSR_SYNDBG_CONTROL 0x400000F1 +#define HV_X64_MSR_SYNDBG_STATUS 0x400000F2 +#define HV_X64_MSR_SYNDBG_SEND_BUFFER 0x400000F3 +#define HV_X64_MSR_SYNDBG_RECV_BUFFER 0x400000F4 +#define HV_X64_MSR_SYNDBG_PENDING_BUFFER 0x400000F5 +#define HV_X64_MSR_SYNDBG_OPTIONS 0x400000FF + +#define HV_X64_SYNDBG_OPTION_USE_HCALLS BIT(2) + /* * Guest crash notification MSRs */ @@ -168,5 +201,16 @@ #define HV_STIMER_COUNT 4 +/* + * Synthetic debugger control definitions + */ +#define HV_SYNDBG_CONTROL_SEND (1u << 0) +#define HV_SYNDBG_CONTROL_RECV (1u << 1) +#define HV_SYNDBG_CONTROL_SEND_SIZE(ctl) ((ctl >> 16) & 0xffff) +#define HV_SYNDBG_STATUS_INVALID (0) +#define HV_SYNDBG_STATUS_SEND_SUCCESS (1u << 0) +#define HV_SYNDBG_STATUS_RECV_SUCCESS (1u << 2) +#define HV_SYNDBG_STATUS_RESET (1u << 3) +#define HV_SYNDBG_STATUS_SET_SIZE(st, sz) (st | (sz << 16)) #endif diff --git a/target/i386/kvm/hyperv-stub.c b/target/i386/kvm/hyperv-stub.c index 0028527e7977..778ed782e6fc 100644 --- a/target/i386/kvm/hyperv-stub.c +++ b/target/i386/kvm/hyperv-stub.c @@ -27,6 +27,12 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) return 0; case KVM_EXIT_HYPERV_HCALL: exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; + return 0; + case KVM_EXIT_HYPERV_SYNDBG: + if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { + return -1; + } + return 0; default: return -1; diff --git a/target/i386/kvm/hyperv.c b/target/i386/kvm/hyperv.c index 26efc1e0e67d..e3ac978648b8 100644 --- a/target/i386/kvm/hyperv.c +++ b/target/i386/kvm/hyperv.c @@ -23,6 +23,10 @@ int hyperv_x86_synic_add(X86CPU *cpu) return 0; } +/* + * All devices possibly using SynIC have to be reset before calling this to let + * them remove their SINT routes first. + */ void hyperv_x86_synic_reset(X86CPU *cpu) { hyperv_synic_reset(CPU(cpu)); @@ -81,20 +85,66 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) case KVM_EXIT_HYPERV_HCALL: { uint16_t code = exit->u.hcall.input & 0xffff; bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST; - uint64_t param = exit->u.hcall.params[0]; + uint64_t in_param = exit->u.hcall.params[0]; + uint64_t out_param = exit->u.hcall.params[1]; switch (code) { case HV_POST_MESSAGE: - exit->u.hcall.result = hyperv_hcall_post_message(param, fast); + exit->u.hcall.result = hyperv_hcall_post_message(in_param, fast); break; case HV_SIGNAL_EVENT: - exit->u.hcall.result = hyperv_hcall_signal_event(param, fast); + exit->u.hcall.result = hyperv_hcall_signal_event(in_param, fast); + break; + case HV_POST_DEBUG_DATA: + exit->u.hcall.result = + hyperv_hcall_post_dbg_data(in_param, out_param, fast); + break; + case HV_RETRIEVE_DEBUG_DATA: + exit->u.hcall.result = + hyperv_hcall_retreive_dbg_data(in_param, out_param, fast); + break; + case HV_RESET_DEBUG_SESSION: + exit->u.hcall.result = + hyperv_hcall_reset_dbg_session(out_param); break; default: exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; } return 0; } + + case KVM_EXIT_HYPERV_SYNDBG: + if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { + return -1; + } + + switch (exit->u.syndbg.msr) { + case HV_X64_MSR_SYNDBG_CONTROL: { + uint64_t control = exit->u.syndbg.control; + env->msr_hv_syndbg_control = control; + env->msr_hv_syndbg_send_page = exit->u.syndbg.send_page; + env->msr_hv_syndbg_recv_page = exit->u.syndbg.recv_page; + exit->u.syndbg.status = HV_STATUS_SUCCESS; + if (control & HV_SYNDBG_CONTROL_SEND) { + exit->u.syndbg.status = + hyperv_syndbg_send(env->msr_hv_syndbg_send_page, + HV_SYNDBG_CONTROL_SEND_SIZE(control)); + } else if (control & HV_SYNDBG_CONTROL_RECV) { + exit->u.syndbg.status = + hyperv_syndbg_recv(env->msr_hv_syndbg_recv_page, + TARGET_PAGE_SIZE); + } + break; + } + case HV_X64_MSR_SYNDBG_PENDING_BUFFER: + env->msr_hv_syndbg_pending_page = exit->u.syndbg.pending_page; + hyperv_syndbg_set_pending_page(env->msr_hv_syndbg_pending_page); + break; + default: + return -1; + } + + return 0; default: return -1; } diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 5eb955ce9a69..7237378a7d4e 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -171,7 +171,7 @@ static void kvm_cpu_instance_init(CPUState *cs) /* only applies to builtin_x86_defs cpus */ if (!kvm_irqchip_in_kernel()) { x86_cpu_change_kvm_default("x2apic", "off"); - } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { + } else if (kvm_irqchip_is_split()) { x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); } diff --git a/target/i386/kvm/kvm-stub.c b/target/i386/kvm/kvm-stub.c index f6e7e4466e1a..e052f1c7b0ef 100644 --- a/target/i386/kvm/kvm-stub.c +++ b/target/i386/kvm/kvm-stub.c @@ -44,3 +44,8 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp) { abort(); } + +void kvm_set_max_apic_id(uint32_t max_apic_id) +{ + return; +} diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 9cf8e036698d..0ab4e0734a02 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -15,6 +15,7 @@ #include "qemu/osdep.h" #include "qapi/qapi-events-run-state.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include #include #include @@ -54,6 +55,8 @@ #include "exec/memattrs.h" #include "trace.h" +#include CONFIG_DEVICES + //#define DEBUG_KVM #ifdef DEBUG_KVM @@ -104,6 +107,7 @@ static bool has_msr_hv_synic; static bool has_msr_hv_stimer; static bool has_msr_hv_frequencies; static bool has_msr_hv_reenlightenment; +static bool has_msr_hv_syndbg_options; static bool has_msr_xss; static bool has_msr_umwait; static bool has_msr_spec_ctrl; @@ -129,6 +133,7 @@ static int has_xcrs; static int has_pit_state2; static int has_sregs2; static int has_exception_payload; +static int has_triple_fault_event; static bool has_msr_mcg_ext_ctl; @@ -136,8 +141,11 @@ static struct kvm_cpuid2 *cpuid_cache; static struct kvm_cpuid2 *hv_cpuid_cache; static struct kvm_msr_list *kvm_feature_msrs; +static KVMMSRHandlers msr_handlers[KVM_MSR_FILTER_MAX_RANGES]; + #define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */ static RateLimit bus_lock_ratelimit_ctrl; +static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value); int kvm_has_pit_state2(void) { @@ -153,7 +161,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) @@ -208,28 +216,21 @@ static int kvm_get_tsc(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - struct { - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data = {}; + uint64_t value; int ret; if (env->tsc_valid) { return 0; } - memset(&msr_data, 0, sizeof(msr_data)); - msr_data.info.nmsrs = 1; - msr_data.entries[0].index = MSR_IA32_TSC; env->tsc_valid = !runstate_is_running(); - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); + ret = kvm_get_one_msr(cpu, MSR_IA32_TSC, &value); if (ret < 0) { return ret; } - assert(ret == 1); - env->tsc = msr_data.entries[0].data; + env->tsc = value; return 0; } @@ -834,6 +835,8 @@ static bool tsc_is_stable_and_known(CPUX86State *env) || env->user_tsc_khz; } +#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) + static struct { const char *desc; struct { @@ -964,6 +967,46 @@ static struct { .bits = HV_DEPRECATING_AEOI_RECOMMENDED} } }, +#ifdef CONFIG_SYNDBG + [HYPERV_FEAT_SYNDBG] = { + .desc = "Enable synthetic kernel debugger channel (hv-syndbg)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_FEATURE_DEBUG_MSRS_AVAILABLE} + }, + .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED) + }, +#endif + [HYPERV_FEAT_MSR_BITMAP] = { + .desc = "enlightened MSR-Bitmap (hv-emsr-bitmap)", + .flags = { + {.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX, + .bits = HV_NESTED_MSR_BITMAP} + } + }, + [HYPERV_FEAT_XMM_INPUT] = { + .desc = "XMM fast hypercall input (hv-xmm-input)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_HYPERCALL_XMM_INPUT_AVAILABLE} + } + }, + [HYPERV_FEAT_TLBFLUSH_EXT] = { + .desc = "Extended gva ranges for TLB flush hypercalls (hv-tlbflush-ext)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_EXT_GVA_RANGES_FLUSH_AVAILABLE} + }, + .dependencies = BIT(HYPERV_FEAT_TLBFLUSH) + }, + [HYPERV_FEAT_TLBFLUSH_DIRECT] = { + .desc = "direct TLB flush (hv-tlbflush-direct)", + .flags = { + {.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX, + .bits = HV_NESTED_DIRECT_FLUSH} + }, + .dependencies = BIT(HYPERV_FEAT_VAPIC) + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, @@ -1004,8 +1047,8 @@ static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs) { struct kvm_cpuid2 *cpuid; - /* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000080 leaves */ - int max = 10; + /* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000082 leaves */ + int max = 11; int i; bool do_sys_ioctl; @@ -1118,6 +1161,12 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid_legacy(CPUState *cs) entry_feat->eax |= HV_SYNTIMERS_AVAILABLE; } + if (has_msr_hv_syndbg_options) { + entry_feat->edx |= HV_GUEST_DEBUGGING_AVAILABLE; + entry_feat->edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE; + entry_feat->ebx |= HV_PARTITION_DEBUGGING_ALLOWED; + } + if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TLBFLUSH) > 0) { entry_recomm->eax |= HV_REMOTE_TLB_FLUSH_RECOMMENDED; @@ -1241,6 +1290,13 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) } } + /* HV_CPUID_NESTED_FEATURES.EAX also encodes the supported eVMCS range */ + if (func == HV_CPUID_NESTED_FEATURES && reg == R_EAX) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + r |= DEFAULT_EVMCS_VERSION; + } + } + return r; } @@ -1369,12 +1425,22 @@ static int hyperv_fill_cpuids(CPUState *cs, { X86CPU *cpu = X86_CPU(cs); struct kvm_cpuid_entry2 *c; - uint32_t cpuid_i = 0; + uint32_t signature[3]; + uint32_t cpuid_i = 0, max_cpuid_leaf = 0; + uint32_t nested_eax = + hv_build_cpuid_leaf(cs, HV_CPUID_NESTED_FEATURES, R_EAX); + + max_cpuid_leaf = nested_eax ? HV_CPUID_NESTED_FEATURES : + HV_CPUID_IMPLEMENT_LIMITS; + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { + max_cpuid_leaf = + MAX(max_cpuid_leaf, HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES); + } c = &cpuid_ent[cpuid_i++]; c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS; - c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ? - HV_CPUID_NESTED_FEATURES : HV_CPUID_IMPLEMENT_LIMITS; + c->eax = max_cpuid_leaf; c->ebx = cpu->hyperv_vendor_id[0]; c->ecx = cpu->hyperv_vendor_id[1]; c->edx = cpu->hyperv_vendor_id[2]; @@ -1438,7 +1504,7 @@ static int hyperv_fill_cpuids(CPUState *cs, c->ecx = cpu->hyperv_limits[1]; c->edx = cpu->hyperv_limits[2]; - if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + if (nested_eax) { uint32_t function; /* Create zeroed 0x40000006..0x40000009 leaves */ @@ -1450,7 +1516,34 @@ static int hyperv_fill_cpuids(CPUState *cs, c = &cpuid_ent[cpuid_i++]; c->function = HV_CPUID_NESTED_FEATURES; - c->eax = cpu->hyperv_nested[0]; + c->eax = nested_eax; + } + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS; + c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ? + HV_CPUID_NESTED_FEATURES : HV_CPUID_IMPLEMENT_LIMITS; + memcpy(signature, "Microsoft VS", 12); + c->eax = 0; + c->ebx = signature[0]; + c->ecx = signature[1]; + c->edx = signature[2]; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_SYNDBG_INTERFACE; + memcpy(signature, "VS#1\0\0\0\0\0\0\0\0", 12); + c->eax = signature[0]; + c->ebx = 0; + c->ecx = 0; + c->edx = 0; + + c = &cpuid_ent[cpuid_i++]; + c->function = HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES; + c->eax = HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + c->ebx = 0; + c->ecx = 0; + c->edx = 0; } return cpuid_i; @@ -1472,8 +1565,6 @@ static bool evmcs_version_supported(uint16_t evmcs_version, (max_version <= max_supported_version); } -#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) - static int hyperv_init_vcpu(X86CPU *cpu) { CPUState *cs = CPU(cpu); @@ -1510,21 +1601,14 @@ static int hyperv_init_vcpu(X86CPU *cpu) * the kernel doesn't support setting vp_index; assert that its value * is in sync */ - struct { - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data = { - .info.nmsrs = 1, - .entries[0].index = HV_X64_MSR_VP_INDEX, - }; + uint64_t value; - ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, &msr_data); + ret = kvm_get_one_msr(cpu, HV_X64_MSR_VP_INDEX, &value); if (ret < 0) { return ret; } - assert(ret == 1); - if (msr_data.entries[0].data != hyperv_vp_index(CPU(cpu))) { + if (value != hyperv_vp_index(CPU(cpu))) { error_report("kernel's vp_index != QEMU's vp_index"); return -ENXIO; } @@ -1577,8 +1661,6 @@ static int hyperv_init_vcpu(X86CPU *cpu) supported_evmcs_version >> 8); return -ENOTSUP; } - - cpu->hyperv_nested[0] = evmcs_version; } if (cpu->hyperv_enforce_cpuid) { @@ -1617,6 +1699,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 { @@ -2044,19 +2150,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); } } @@ -2083,15 +2180,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); @@ -2110,18 +2203,30 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) env->mp_state = KVM_MP_STATE_RUNNABLE; } + /* enabled by default */ + env->poll_control_msr = 1; + + kvm_init_nested_state(env); + + sev_es_set_reset_vector(CPU(cpu)); +} + +void kvm_arch_after_reset_vcpu(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + int i; + + /* + * Reset SynIC after all other devices have been reset to let them remove + * their SINT routes first. + */ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) { - int i; for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) { env->msr_hv_synic_sint[i] = HV_SINT_MASKED; } hyperv_x86_synic_reset(cpu); } - /* enabled by default */ - env->poll_control_msr = 1; - - sev_es_set_reset_vector(CPU(cpu)); } void kvm_arch_do_init_vcpu(X86CPU *cpu) @@ -2157,8 +2262,7 @@ static int kvm_get_supported_feature_msrs(KVMState *s) } assert(msr_list.nmsrs > 0); - kvm_feature_msrs = (struct kvm_msr_list *) \ - g_malloc0(sizeof(msr_list) + + kvm_feature_msrs = g_malloc0(sizeof(msr_list) + msr_list.nmsrs * sizeof(msr_list.indices[0])); kvm_feature_msrs->nmsrs = msr_list.nmsrs; @@ -2261,6 +2365,9 @@ static int kvm_get_supported_msrs(KVMState *s) case HV_X64_MSR_REENLIGHTENMENT_CONTROL: has_msr_hv_reenlightenment = true; break; + case HV_X64_MSR_SYNDBG_OPTIONS: + has_msr_hv_syndbg_options = true; + break; case MSR_IA32_SPEC_CTRL: has_msr_spec_ctrl = true; break; @@ -2303,6 +2410,17 @@ static int kvm_get_supported_msrs(KVMState *s) return ret; } +static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr, + uint64_t *val) +{ + CPUState *cs = CPU(cpu); + + *val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */ + *val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */ + + return true; +} + static Notifier smram_machine_done; static KVMMemoryListener smram_listener; static AddressSpace smram_address_space; @@ -2385,6 +2503,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + has_triple_fault_event = kvm_check_extension(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT); + if (has_triple_fault_event) { + ret = kvm_vm_enable_cap(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 0, true); + if (ret < 0) { + error_report("kvm: Failed to enable triple fault event cap: %s", + strerror(-ret)); + return ret; + } + } + ret = kvm_get_supported_msrs(s); if (ret < 0) { return ret; @@ -2490,6 +2618,40 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + if (s->notify_vmexit != NOTIFY_VMEXIT_OPTION_DISABLE && + kvm_check_extension(s, KVM_CAP_X86_NOTIFY_VMEXIT)) { + uint64_t notify_window_flags = + ((uint64_t)s->notify_window << 32) | + KVM_X86_NOTIFY_VMEXIT_ENABLED | + KVM_X86_NOTIFY_VMEXIT_USER; + ret = kvm_vm_enable_cap(s, KVM_CAP_X86_NOTIFY_VMEXIT, 0, + notify_window_flags); + if (ret < 0) { + error_report("kvm: Failed to enable notify vmexit cap: %s", + strerror(-ret)); + return ret; + } + } + if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) { + bool r; + + ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, + KVM_MSR_EXIT_REASON_FILTER); + if (ret) { + error_report("Could not enable user space MSRs: %s", + strerror(-ret)); + exit(1); + } + + r = kvm_filter_msr(s, MSR_CORE_THREAD_COUNT, + kvm_rdmsr_core_thread_count, NULL); + if (!r) { + error_report("Could not install MSR_CORE_THREAD_COUNT handler: %s", + strerror(-ret)); + exit(1); + } + } + return 0; } @@ -2780,6 +2942,25 @@ static int kvm_put_one_msr(X86CPU *cpu, int index, uint64_t value) return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); } +static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value) +{ + int ret; + struct { + struct kvm_msrs info; + struct kvm_msr_entry entries[1]; + } msr_data = { + .info.nmsrs = 1, + .entries[0].index = index, + }; + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); + if (ret < 0) { + return ret; + } + assert(ret == 1); + *value = msr_data.entries[0].data; + return ret; +} void kvm_put_apicbase(X86CPU *cpu, uint64_t value) { int ret; @@ -3178,6 +3359,13 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_STATUS, env->msr_hv_tsc_emulation_status); } +#ifdef CONFIG_SYNDBG + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG) && + has_msr_hv_syndbg_options) { + kvm_msr_entry_add(cpu, HV_X64_MSR_SYNDBG_OPTIONS, + hyperv_syndbg_query_options()); + } +#endif } if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VAPIC)) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, @@ -3295,6 +3483,37 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_xfd_err); } + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + uint64_t depth; + int i, ret; + + /* + * Only migrate Arch LBR states when the host Arch LBR depth + * equals that of source guest's, this is to avoid mismatch + * of guest/host config for the msr hence avoid unexpected + * misbehavior. + */ + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + + if (ret == 1 && !!depth && depth == env->msr_lbr_depth) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, env->msr_lbr_ctl); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, env->msr_lbr_depth); + + for (i = 0; i < ARCH_LBR_NR_ENTRIES; i++) { + if (!env->lbr_records[i].from) { + continue; + } + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_FROM_0 + i, + env->lbr_records[i].from); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_TO_0 + i, + env->lbr_records[i].to); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_INFO_0 + i, + env->lbr_records[i].info); + } + } + } + /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see * kvm_put_msr_feature_control. */ } @@ -3619,6 +3838,9 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_CONTROL, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_STATUS, 0); } + if (has_msr_hv_syndbg_options) { + kvm_msr_entry_add(cpu, HV_X64_MSR_SYNDBG_OPTIONS, 0); + } if (has_msr_hv_crash) { int j; @@ -3692,6 +3914,24 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); } + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + uint64_t depth; + int i, ret; + + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + if (ret == 1 && depth == ARCH_LBR_NR_ENTRIES) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, 0); + + for (i = 0; i < ARCH_LBR_NR_ENTRIES; i++) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_FROM_0 + i, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_TO_0 + i, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_INFO_0 + i, 0); + } + } + } + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); if (ret < 0) { return ret; @@ -3910,6 +4150,9 @@ static int kvm_get_msrs(X86CPU *cpu) case HV_X64_MSR_TSC_EMULATION_STATUS: env->msr_hv_tsc_emulation_status = msrs[i].data; break; + case HV_X64_MSR_SYNDBG_OPTIONS: + env->msr_hv_syndbg_options = msrs[i].data; + break; case MSR_MTRRdefType: env->mtrr_deftype = msrs[i].data; break; @@ -3994,6 +4237,21 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_IA32_XFD_ERR: env->msr_xfd_err = msrs[i].data; break; + case MSR_ARCH_LBR_CTL: + env->msr_lbr_ctl = msrs[i].data; + break; + case MSR_ARCH_LBR_DEPTH: + env->msr_lbr_depth = msrs[i].data; + break; + case MSR_ARCH_LBR_FROM_0 ... MSR_ARCH_LBR_FROM_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_FROM_0].from = msrs[i].data; + break; + case MSR_ARCH_LBR_TO_0 ... MSR_ARCH_LBR_TO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_TO_0].to = msrs[i].data; + break; + case MSR_ARCH_LBR_INFO_0 ... MSR_ARCH_LBR_INFO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_INFO_0].info = msrs[i].data; + break; } } @@ -4105,6 +4363,11 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) } } + if (has_triple_fault_event) { + events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; + events.triple_fault.pending = env->triple_fault_pending; + } + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events); } @@ -4174,6 +4437,10 @@ static int kvm_get_vcpu_events(X86CPU *cpu) } } + if (events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT) { + env->triple_fault_pending = events.triple_fault.pending; + } + env->sipi_vector = events.sipi_vector; return 0; @@ -4335,6 +4602,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) { @@ -4346,11 +4625,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) { @@ -4876,6 +5150,108 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) } } +static bool kvm_install_msr_filters(KVMState *s) +{ + uint64_t zero = 0; + struct kvm_msr_filter filter = { + .flags = KVM_MSR_FILTER_DEFAULT_ALLOW, + }; + int r, i, j = 0; + + for (i = 0; i < KVM_MSR_FILTER_MAX_RANGES; i++) { + KVMMSRHandlers *handler = &msr_handlers[i]; + if (handler->msr) { + struct kvm_msr_filter_range *range = &filter.ranges[j++]; + + *range = (struct kvm_msr_filter_range) { + .flags = 0, + .nmsrs = 1, + .base = handler->msr, + .bitmap = (__u8 *)&zero, + }; + + if (handler->rdmsr) { + range->flags |= KVM_MSR_FILTER_READ; + } + + if (handler->wrmsr) { + range->flags |= KVM_MSR_FILTER_WRITE; + } + } + } + + r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter); + if (r) { + return false; + } + + return true; +} + +bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, + QEMUWRMSRHandler *wrmsr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { + if (!msr_handlers[i].msr) { + msr_handlers[i] = (KVMMSRHandlers) { + .msr = msr, + .rdmsr = rdmsr, + .wrmsr = wrmsr, + }; + + if (!kvm_install_msr_filters(s)) { + msr_handlers[i] = (KVMMSRHandlers) { }; + return false; + } + + return true; + } + } + + return false; +} + +static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run) +{ + int i; + bool r; + + for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { + KVMMSRHandlers *handler = &msr_handlers[i]; + if (run->msr.index == handler->msr) { + if (handler->rdmsr) { + r = handler->rdmsr(cpu, handler->msr, + (uint64_t *)&run->msr.data); + run->msr.error = r ? 0 : 1; + return 0; + } + } + } + + assert(false); +} + +static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) +{ + int i; + bool r; + + for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { + KVMMSRHandlers *handler = &msr_handlers[i]; + if (run->msr.index == handler->msr) { + if (handler->wrmsr) { + r = handler->wrmsr(cpu, handler->msr, run->msr.data); + run->msr.error = r ? 0 : 1; + return 0; + } + } + } + + assert(false); +} + static bool has_sgx_provisioning; static bool __kvm_enable_sgx_provisioning(KVMState *s) @@ -4920,6 +5296,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) X86CPU *cpu = X86_CPU(cs); uint64_t code; int ret; + bool ctx_invalid; + char str[256]; + KVMState *state; switch (run->exit_reason) { case KVM_EXIT_HLT: @@ -4975,6 +5354,31 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) /* already handled in kvm_arch_post_run */ ret = 0; break; + case KVM_EXIT_NOTIFY: + ctx_invalid = !!(run->notify.flags & KVM_NOTIFY_CONTEXT_INVALID); + state = KVM_STATE(current_accel()); + sprintf(str, "Encounter a notify exit with %svalid context in" + " guest. There can be possible misbehaves in guest." + " Please have a look.", ctx_invalid ? "in" : ""); + if (ctx_invalid || + state->notify_vmexit == NOTIFY_VMEXIT_OPTION_INTERNAL_ERROR) { + warn_report("KVM internal error: %s", str); + ret = -1; + } else { + warn_report_once("KVM: %s", str); + ret = 0; + } + break; + case KVM_EXIT_X86_RDMSR: + /* We only enable MSR filtering, any other exit is bogus */ + assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER); + ret = kvm_handle_rdmsr(cpu, run); + break; + case KVM_EXIT_X86_WRMSR: + /* We only enable MSR filtering, any other exit is bogus */ + assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER); + ret = kvm_handle_wrmsr(cpu, run); + break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; @@ -5251,3 +5655,73 @@ void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask) mask &= ~BIT_ULL(bit); } } + +static int kvm_arch_get_notify_vmexit(Object *obj, Error **errp) +{ + KVMState *s = KVM_STATE(obj); + return s->notify_vmexit; +} + +static void kvm_arch_set_notify_vmexit(Object *obj, int value, Error **errp) +{ + KVMState *s = KVM_STATE(obj); + + if (s->fd != -1) { + error_setg(errp, "Cannot set properties after the accelerator has been initialized"); + return; + } + + s->notify_vmexit = value; +} + +static void kvm_arch_get_notify_window(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + uint32_t value = s->notify_window; + + visit_type_uint32(v, name, &value, errp); +} + +static void kvm_arch_set_notify_window(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + uint32_t value; + + if (s->fd != -1) { + error_setg(errp, "Cannot set properties after the accelerator has been initialized"); + return; + } + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + s->notify_window = value; +} + +void kvm_arch_accel_class_init(ObjectClass *oc) +{ + object_class_property_add_enum(oc, "notify-vmexit", "NotifyVMexitOption", + &NotifyVmexitOption_lookup, + kvm_arch_get_notify_vmexit, + kvm_arch_set_notify_vmexit); + object_class_property_set_description(oc, "notify-vmexit", + "Enable notify VM exit"); + + object_class_property_add(oc, "notify-window", "uint32", + kvm_arch_get_notify_window, + kvm_arch_set_notify_window, + NULL, NULL); + object_class_property_set_description(oc, "notify-window", + "Clock cycles without an event window " + "after which a notification VM exit occurs"); +} + +void kvm_set_max_apic_id(uint32_t max_apic_id) +{ + kvm_vm_enable_cap(kvm_state, KVM_CAP_MAX_VCPU_ID, 0, max_apic_id); +} diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index 4124912c202e..6a5c24e3dc40 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -38,6 +38,7 @@ bool kvm_has_adjust_clock_stable(void); bool kvm_has_exception_payload(void); void kvm_synchronize_all_tsc(void); void kvm_arch_reset_vcpu(X86CPU *cs); +void kvm_arch_after_reset_vcpu(X86CPU *cpu); void kvm_arch_do_init_vcpu(X86CPU *cs); void kvm_put_apicbase(X86CPU *cpu, uint64_t value); @@ -54,4 +55,17 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); bool kvm_enable_sgx_provisioning(KVMState *s); void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); +typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val); +typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val); +typedef struct kvm_msr_handlers { + uint32_t msr; + QEMURDMSRHandler *rdmsr; + QEMUWRMSRHandler *wrmsr; +} KVMMSRHandlers; + +bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, + QEMUWRMSRHandler *wrmsr); + +void kvm_set_max_apic_id(uint32_t max_apic_id); + #endif diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c index 6080c007a2e4..1be5341e8a6a 100644 --- a/target/i386/kvm/sev-stub.c +++ b/target/i386/kvm/sev-stub.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "sev.h" int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) diff --git a/target/i386/machine.c b/target/i386/machine.c index 7c54bada819b..310b12523508 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -136,6 +136,22 @@ static const VMStateDescription vmstate_mtrr_var = { #define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \ VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar) +static const VMStateDescription vmstate_lbr_records_var = { + .name = "lbr_records_var", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(from, LBREntry), + VMSTATE_UINT64(to, LBREntry), + VMSTATE_UINT64(info, LBREntry), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_LBR_VARS(_field, _state, _n, _v) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_lbr_records_var, \ + LBREntry) + typedef struct x86_FPReg_tmp { FPReg *parent; uint64_t tmp_mant; @@ -1525,6 +1541,46 @@ static const VMStateDescription vmstate_amx_xtile = { }; #endif +static bool arch_lbr_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return !!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR); +} + +static const VMStateDescription vmstate_arch_lbr = { + .name = "cpu/arch_lbr", + .version_id = 1, + .minimum_version_id = 1, + .needed = arch_lbr_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.msr_lbr_ctl, X86CPU), + VMSTATE_UINT64(env.msr_lbr_depth, X86CPU), + VMSTATE_LBR_VARS(env.lbr_records, X86CPU, ARCH_LBR_NR_ENTRIES, 1), + VMSTATE_END_OF_LIST() + } +}; + +static bool triple_fault_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return env->triple_fault_pending; +} + +static const VMStateDescription vmstate_triple_fault = { + .name = "cpu/triple_fault", + .version_id = 1, + .minimum_version_id = 1, + .needed = triple_fault_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8(env.triple_fault_pending, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_x86_cpu = { .name = "cpu", .version_id = 12, @@ -1668,6 +1724,8 @@ const VMStateDescription vmstate_x86_cpu = { #ifdef TARGET_X86_64 &vmstate_amx_xtile, #endif + &vmstate_arch_lbr, + &vmstate_triple_fault, NULL } }; diff --git a/target/i386/nvmm/nvmm-accel-ops.h b/target/i386/nvmm/nvmm-accel-ops.h index 43e24adcaf98..7c5461bd7599 100644 --- a/target/i386/nvmm/nvmm-accel-ops.h +++ b/target/i386/nvmm/nvmm-accel-ops.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef NVMM_CPUS_H -#define NVMM_CPUS_H +#ifndef TARGET_I386_NVMM_ACCEL_OPS_H +#define TARGET_I386_NVMM_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -21,4 +21,4 @@ void nvmm_cpu_synchronize_post_reset(CPUState *cpu); void nvmm_cpu_synchronize_post_init(CPUState *cpu); void nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu); -#endif /* NVMM_CPUS_H */ +#endif /* TARGET_I386_NVMM_ACCEL_OPS_H */ diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index b97d091a502d..b75738ee9cdf 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -11,7 +11,6 @@ #include "cpu.h" #include "exec/address-spaces.h" #include "exec/ioport.h" -#include "qemu-common.h" #include "qemu/accel.h" #include "sysemu/nvmm.h" #include "sysemu/cpus.h" @@ -1075,15 +1074,15 @@ nvmm_process_section(MemoryRegionSection *section, int add) } /* Adjust start_pa and size so that they are page-aligned. */ - delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask); - delta &= ~qemu_real_host_page_mask; + delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask()); + delta &= ~qemu_real_host_page_mask(); if (delta > size) { return; } start_pa += delta; size -= delta; - size &= qemu_real_host_page_mask; - if (!size || (start_pa & ~qemu_real_host_page_mask)) { + size &= qemu_real_host_page_mask(); + if (!size || (start_pa & ~qemu_real_host_page_mask())) { return; } diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 6f1fc174b324..0bd6bfad8a17 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -35,262 +35,206 @@ #define W(n) ZMM_W(n) #define L(n) ZMM_L(n) #define Q(n) ZMM_Q(n) +#if SHIFT == 1 #define SUFFIX _xmm +#else +#define SUFFIX _ymm +#endif #endif -void glue(helper_psrlw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - int shift; +#define LANE_WIDTH (SHIFT ? 16 : 8) +#define PACK_WIDTH (LANE_WIDTH / 2) - if (s->Q(0) > 15) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; +#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, Reg *c) +{ + int shift; + 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 *s, Reg *c) { int shift; - - if (s->Q(0) > 15) { - shift = 15; + if (c->Q(0) > 15) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); + shift = c->B(0); + for (int i = 0; i < 4 << SHIFT; i++) { + d->W(i) = FPSLL(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_psraw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { int shift; - - if (s->Q(0) > 15) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 15) { + shift = 15; } 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) = FPSRAW(s->W(i), shift); } } -void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { 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) = FPSRL(s->L(i), shift); + } } } -void glue(helper_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_pslld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { int shift; - - if (s->Q(0) > 31) { - shift = 31; + if (c->Q(0) > 31) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); + shift = c->B(0); + for (int i = 0; i < 2 << SHIFT; i++) { + d->L(i) = FPSLL(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_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { int shift; - - if (s->Q(0) > 31) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 31) { + shift = 31; } 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) = FPSRAL(s->L(i), shift); } } -void glue(helper_psrlq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psrlq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { 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) = FPSRL(s->Q(i), shift); + } } } -void glue(helper_psllq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psllq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { 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); + } } } -#if SHIFT == 1 -void glue(helper_psrldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +#if SHIFT >= 1 +void glue(helper_psrldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, Reg *c) { - int shift, i; + int shift, i, j; - 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 *s, Reg *c) { - int shift, i; + 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_B(name, F) \ +#define SSE_HELPER_1(name, elem, num, 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)); \ - ) \ - } + int n = num; \ + for (int i = 0; i < n; i++) { \ + d->elem(i) = F(s->elem(i)); \ + } \ + } -#define SSE_HELPER_W(name, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ +#define SSE_HELPER_2(name, elem, num, F) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, 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)); \ - ) \ - } + 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) \ + SSE_HELPER_2(name, B, 8 << SHIFT, F) + +#define SSE_HELPER_W(name, F) \ + 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) @@ -353,17 +297,6 @@ static inline int satsw(int x) #define FMAXUB(a, b) ((a) > (b)) ? (a) : (b) #define FMAXSW(a, b) ((int16_t)(a) > (int16_t)(b)) ? (a) : (b) -#define FAND(a, b) ((a) & (b)) -#define FANDN(a, b) ((~(a)) & (b)) -#define FOR(a, b) ((a) | (b)) -#define FXOR(a, b) ((a) ^ (b)) - -#define FCMPGTB(a, b) ((int8_t)(a) > (int8_t)(b) ? -1 : 0) -#define FCMPGTW(a, b) ((int16_t)(a) > (int16_t)(b) ? -1 : 0) -#define FCMPGTL(a, b) ((int32_t)(a) > (int32_t)(b) ? -1 : 0) -#define FCMPEQ(a, b) ((a) == (b) ? -1 : 0) - -#define FMULLW(a, b) ((a) * (b)) #define FMULHRW(a, b) (((int16_t)(a) * (int16_t)(b) + 0x8000) >> 16) #define FMULHUW(a, b) ((a) * (b) >> 16) #define FMULHW(a, b) ((int16_t)(a) * (int16_t)(b) >> 16) @@ -371,70 +304,38 @@ static inline int satsw(int x) #define FAVG(a, b) (((a) + (b) + 1) >> 1) #endif -SSE_HELPER_B(helper_paddb, FADD) -SSE_HELPER_W(helper_paddw, FADD) -SSE_HELPER_L(helper_paddl, FADD) -SSE_HELPER_Q(helper_paddq, FADD) - -SSE_HELPER_B(helper_psubb, FSUB) -SSE_HELPER_W(helper_psubw, FSUB) -SSE_HELPER_L(helper_psubl, FSUB) -SSE_HELPER_Q(helper_psubq, FSUB) - -SSE_HELPER_B(helper_paddusb, FADDUB) -SSE_HELPER_B(helper_paddsb, FADDSB) -SSE_HELPER_B(helper_psubusb, FSUBUB) -SSE_HELPER_B(helper_psubsb, FSUBSB) - -SSE_HELPER_W(helper_paddusw, FADDUW) -SSE_HELPER_W(helper_paddsw, FADDSW) -SSE_HELPER_W(helper_psubusw, FSUBUW) -SSE_HELPER_W(helper_psubsw, FSUBSW) - -SSE_HELPER_B(helper_pminub, FMINUB) -SSE_HELPER_B(helper_pmaxub, FMAXUB) - -SSE_HELPER_W(helper_pminsw, FMINSW) -SSE_HELPER_W(helper_pmaxsw, FMAXSW) - -SSE_HELPER_Q(helper_pand, FAND) -SSE_HELPER_Q(helper_pandn, FANDN) -SSE_HELPER_Q(helper_por, FOR) -SSE_HELPER_Q(helper_pxor, FXOR) - -SSE_HELPER_B(helper_pcmpgtb, FCMPGTB) -SSE_HELPER_W(helper_pcmpgtw, FCMPGTW) -SSE_HELPER_L(helper_pcmpgtl, FCMPGTL) - -SSE_HELPER_B(helper_pcmpeqb, FCMPEQ) -SSE_HELPER_W(helper_pcmpeqw, FCMPEQ) -SSE_HELPER_L(helper_pcmpeql, FCMPEQ) +SSE_HELPER_W(helper_pmulhuw, FMULHUW) +SSE_HELPER_W(helper_pmulhw, FMULHW) -SSE_HELPER_W(helper_pmullw, FMULLW) #if SHIFT == 0 -SSE_HELPER_W(helper_pmulhrw, FMULHRW) +void glue(helper_pmulhrw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + d->W(0) = FMULHRW(d->W(0), s->W(0)); + d->W(1) = FMULHRW(d->W(1), s->W(1)); + d->W(2) = FMULHRW(d->W(2), s->W(2)); + d->W(3) = FMULHRW(d->W(3), s->W(3)); +} #endif -SSE_HELPER_W(helper_pmulhuw, FMULHUW) -SSE_HELPER_W(helper_pmulhw, FMULHW) SSE_HELPER_B(helper_pavgb, FAVG) SSE_HELPER_W(helper_pavgw, FAVG) -void glue(helper_pmuludq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_pmuludq, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, 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 + 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) +void glue(helper_pmaddwd, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) { 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); } } @@ -448,34 +349,25 @@ static inline int abs1(int a) } } #endif -void glue(helper_psadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - unsigned int val; - - 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 +void glue(helper_psadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + int i; + + 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) { @@ -487,128 +379,140 @@ void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, } } } - -void glue(helper_movl_mm_T0, SUFFIX)(Reg *d, uint32_t val) -{ - d->L(0) = val; - d->L(1) = 0; -#if SHIFT == 1 - d->Q(1) = 0; #endif -} -#ifdef TARGET_X86_64 -void glue(helper_movq_mm_T0, SUFFIX)(Reg *d, uint64_t val) -{ - d->Q(0) = val; -#if SHIFT == 1 - d->Q(1) = 0; -#endif -} -#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); - *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 *v, Reg *s, int order) { - Reg r; + 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); - *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 *v, Reg *s, int order) { - Reg r; + uint64_t r0, r1; + int i; - r.Q(0) = d->Q(order & 1); - r.Q(1) = s->Q((order >> 1) & 1); - *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); - *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); - *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)); - *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 *v, 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)); \ + 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 *v, Reg *s) \ { \ - d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0)); \ - } \ + 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 ## pd(CPUX86State *env, Reg *d, Reg *s) \ + void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *v, 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)); \ + int i; \ + d->ZMM_S(0) = F(32, v->ZMM_S(0), s->ZMM_S(0)); \ + for (i = 1; i < 2 << SHIFT; i++) { \ + d->ZMM_L(i) = v->ZMM_L(i); \ + } \ } \ \ - void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s) \ + void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *v, Reg *s)\ { \ - d->ZMM_D(0) = F(64, d->ZMM_D(0), s->ZMM_D(0)); \ + int i; \ + d->ZMM_D(0) = F(64, v->ZMM_D(0), s->ZMM_D(0)); \ + for (i = 1; i < 1 << SHIFT; i++) { \ + d->ZMM_Q(i) = v->ZMM_Q(i); \ + } \ } +#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), @@ -625,56 +529,131 @@ 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 *v, Reg *s) +{ + int i; + d->ZMM_S(0) = float32_sqrt(s->ZMM_S(0), &env->sse_status); + for (i = 1; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = v->ZMM_L(i); + } +} + +void helper_sqrtsd(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + int i; + d->ZMM_D(0) = float64_sqrt(s->ZMM_D(0), &env->sse_status); + for (i = 1; i < 1 << SHIFT; i++) { + d->ZMM_Q(i) = v->ZMM_Q(i); + } +} +#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; + int i; + for (i = 1 << SHIFT; --i >= 0; ) { + d->ZMM_D(i) = float32_to_float64(s->ZMM_S(i), &env->sse_status); + } +} + +void glue(helper_cvtpd2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + 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 glue(helper_cvtph2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + int i; - 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); + for (i = 2 << SHIFT; --i >= 0; ) { + d->ZMM_S(i) = float16_to_float32(s->ZMM_H(i), true, &env->sse_status); + } } -void helper_cvtpd2ps(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_cvtps2ph, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, int mode) { - 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; + FloatRoundMode prev_rounding_mode = env->sse_status.float_rounding_mode; + if (!(mode & (1 << 2))) { + set_x86_rounding_mode(mode & 3, &env->sse_status); + } + + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_H(i) = float32_to_float16(s->ZMM_S(i), true, &env->sse_status); + } + for (i >>= 2; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } + + env->sse_status.float_rounding_mode = prev_rounding_mode; } +#endif -void helper_cvtss2sd(CPUX86State *env, Reg *d, Reg *s) +#if SHIFT == 1 +void helper_cvtss2sd(CPUX86State *env, Reg *d, Reg *v, Reg *s) { + int i; d->ZMM_D(0) = float32_to_float64(s->ZMM_S(0), &env->sse_status); + for (i = 1; i < 1 << SHIFT; i++) { + d->ZMM_Q(i) = v->ZMM_Q(i); + } } -void helper_cvtsd2ss(CPUX86State *env, Reg *d, Reg *s) +void helper_cvtsd2ss(CPUX86State *env, Reg *d, Reg *v, Reg *s) { + int i; d->ZMM_S(0) = float64_to_float32(s->ZMM_D(0), &env->sse_status); + for (i = 1; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = v->ZMM_L(i); + } } +#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); @@ -709,8 +688,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. @@ -741,22 +723,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); @@ -790,23 +778,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); @@ -840,51 +836,59 @@ 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); } -void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *s) +#if SHIFT == 1 +void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *v, ZMMReg *s) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); + int i; d->ZMM_S(0) = float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); set_float_exception_flags(old_flags, &env->sse_status); + for (i = 1; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = v->ZMM_L(i); + } } +#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); } -void helper_rcpss(CPUX86State *env, ZMMReg *d, ZMMReg *s) +#if SHIFT == 1 +void helper_rcpss(CPUX86State *env, ZMMReg *d, ZMMReg *v, ZMMReg *s) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); + int i; d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); + for (i = 1; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = v->ZMM_L(i); + } 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; @@ -899,7 +903,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) @@ -907,7 +911,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; @@ -916,125 +920,184 @@ 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 -void helper_haddps(CPUX86State *env, ZMMReg *d, ZMMReg *s) +#define SSE_HELPER_HPS(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) \ +{ \ + 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]; \ + } \ +} + +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 *v, Reg *s) \ +{ \ + 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 *v, 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); - *d = r; + 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 *v, 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); - *d = r; + 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); - *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); - *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 *v, 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)); \ - } \ - \ - void helper_ ## name ## ss(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)); \ + 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 ## sd(CPUX86State *env, Reg *d, Reg *s) \ + void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *v, Reg *s) \ { \ - d->ZMM_Q(0) = F(64, d->ZMM_D(0), s->ZMM_D(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) - -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) + 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; \ + } \ + } + +#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 *v, Reg *s) \ + { \ + int i; \ + d->ZMM_L(0) = C(F(32, v->ZMM_S(0), s->ZMM_S(0))) ? -1 : 0; \ + for (i = 1; i < 2 << SHIFT; i++) { \ + d->ZMM_L(i) = v->ZMM_L(i); \ + } \ + } \ + \ + void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *v, Reg *s) \ + { \ + int i; \ + d->ZMM_Q(0) = C(F(64, v->ZMM_D(0), s->ZMM_D(0))) ? -1 : 0; \ + for (i = 1; i < 1 << SHIFT; i++) { \ + d->ZMM_Q(i) = v->ZMM_Q(i); \ + } \ + } + +static inline bool FPU_EQU(FloatRelation x) +{ + return (x == float_relation_equal || x == float_relation_unordered); +} +static inline bool FPU_GE(FloatRelation x) +{ + return (x == float_relation_equal || x == float_relation_greater); +} +#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_GT(x) (x == float_relation_greater) +#define FPU_UNORD(x) (x == float_relation_unordered) +/* We must make sure we evaluate the argument in case it is a signalling NAN */ +#define FPU_FALSE(x) (x == float_relation_equal && 0) + +#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) + +SSE_HELPER_CMP(cmpequ, FPU_CMPQ, FPU_EQU) +SSE_HELPER_CMP(cmpnge, FPU_CMPS, !FPU_GE) +SSE_HELPER_CMP(cmpngt, FPU_CMPS, !FPU_GT) +SSE_HELPER_CMP(cmpfalse, FPU_CMPQ, FPU_FALSE) +SSE_HELPER_CMP(cmpnequ, FPU_CMPQ, !FPU_EQU) +SSE_HELPER_CMP(cmpge, FPU_CMPS, FPU_GE) +SSE_HELPER_CMP(cmpgt, FPU_CMPS, FPU_GT) +SSE_HELPER_CMP(cmptrue, FPU_CMPQ, !FPU_FALSE) + +SSE_HELPER_CMP(cmpeqs, FPU_CMPS, FPU_EQ) +SSE_HELPER_CMP(cmpltq, FPU_CMPQ, FPU_LT) +SSE_HELPER_CMP(cmpleq, FPU_CMPQ, FPU_LE) +SSE_HELPER_CMP(cmpunords, FPU_CMPS, FPU_UNORD) +SSE_HELPER_CMP(cmpneqq, FPU_CMPS, !FPU_EQ) +SSE_HELPER_CMP(cmpnltq, FPU_CMPQ, !FPU_LT) +SSE_HELPER_CMP(cmpnleq, FPU_CMPQ, !FPU_LE) +SSE_HELPER_CMP(cmpords, FPU_CMPS, !FPU_UNORD) + +SSE_HELPER_CMP(cmpequs, FPU_CMPS, FPU_EQU) +SSE_HELPER_CMP(cmpngeq, FPU_CMPQ, !FPU_GE) +SSE_HELPER_CMP(cmpngtq, FPU_CMPQ, !FPU_GT) +SSE_HELPER_CMP(cmpfalses, FPU_CMPS, FPU_FALSE) +SSE_HELPER_CMP(cmpnequs, FPU_CMPS, !FPU_EQU) +SSE_HELPER_CMP(cmpgeq, FPU_CMPQ, FPU_GE) +SSE_HELPER_CMP(cmpgtq, FPU_CMPQ, FPU_GT) +SSE_HELPER_CMP(cmptrues, FPU_CMPS, !FPU_FALSE) + +#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) @@ -1080,205 +1143,154 @@ void helper_comisd(CPUX86State *env, Reg *d, Reg *s) ret = float64_compare(d0, d1, &env->sse_status); CC_SRC = comis_eflags[ret + 1]; } - -uint32_t helper_movmskps(CPUX86State *env, Reg *s) -{ - int b0, b1, b2, b3; - - 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); -} - -uint32_t helper_movmskpd(CPUX86State *env, Reg *s) -{ - int b0, b1; - - b0 = s->ZMM_L(1) >> 31; - b1 = s->ZMM_L(3) >> 31; - return b0 | (b1 << 1); -} - #endif -uint32_t glue(helper_pmovmskb, SUFFIX)(CPUX86State *env, Reg *s) +uint32_t glue(helper_movmskps, SUFFIX)(CPUX86State *env, Reg *s) { - uint32_t val; + uint32_t mask; + 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 - return val; + mask = 0; + for (i = 0; i < 2 << SHIFT; i++) { + mask |= (s->ZMM_L(i) >> (31 - i)) & (1 << i); + } + return mask; } -void glue(helper_packsswb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +uint32_t glue(helper_movmskpd, SUFFIX)(CPUX86State *env, Reg *s) { - Reg r; + uint32_t mask; + int i; - 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 - *d = r; + mask = 0; + for (i = 0; i < 1 << SHIFT; i++) { + mask |= (s->ZMM_Q(i) >> (63 - i)) & (1 << i); + } + return mask; } -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 - *d = r; -} -void glue(helper_packssdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - Reg r; - - 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 - *d = r; +#define PACK_HELPER_B(name, F) \ +void glue(helper_pack ## name, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *v, Reg *s) \ +{ \ + 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]; \ + } \ + } \ +} + +PACK_HELPER_B(sswb, satsb) +PACK_HELPER_B(uswb, satub) + +void glue(helper_packssdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + uint16_t r[PACK_WIDTH]; + int j, k; + + 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 *v, Reg *s) \ { \ - Reg r; \ + 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); \ - ) \ - *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 *v, Reg *s) \ { \ - Reg r; \ + 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); \ - ) \ - *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 *v, Reg *s) \ { \ - Reg r; \ + 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); \ - ) \ - *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 *v, Reg *s) \ { \ - Reg r; \ + uint64_t r[2]; \ + int i; \ \ - r.Q(0) = d->Q(base); \ - r.Q(1) = s->Q(base); \ - *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) @@ -1309,11 +1321,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); - *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) @@ -1374,20 +1386,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); - *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); - *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) @@ -1420,133 +1432,95 @@ 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); - *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) +void glue(helper_pshufb, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) { 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]; - *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)); - - *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)); - - *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))); - - *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) +#define SSE_HELPER_HW(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) \ +{ \ + 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]; \ + } \ +} + +#define SSE_HELPER_HL(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) \ +{ \ + 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]; \ + } \ +} + +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 *v, 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)); -} - -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)); -} - -void glue(helper_phsubsw, 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))); + 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 FMULHRSW(d, s) (((int16_t) d * (int16_t)s + 0x4000) >> 15) SSE_HELPER_W(helper_pmulhrsw, FMULHRSW) @@ -1557,186 +1531,146 @@ SSE_HELPER_B(helper_psignb, FSIGNB) SSE_HELPER_W(helper_psignw, FSIGNW) SSE_HELPER_L(helper_psignd, FSIGNL) -void glue(helper_palignr, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, - int32_t shift) +void glue(helper_palignr, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, + uint32_t imm) { - Reg r; + int i; /* XXX could be checked during translation */ - if (shift >= (16 << SHIFT)) { - r.Q(0) = 0; - XMM_ONLY(r.Q(1) = 0); + if (imm >= (SHIFT ? 32 : 16)) { + for (i = 0; i < (1 << SHIFT); i++) { + d->Q(i) = 0; + } } else { - shift <<= 3; + int shift = imm * 8; #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 } - - *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 *v, Reg *s, \ + Reg *m) \ { \ - 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)); \ - } \ - } \ + 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 *v, 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)); \ - } \ - } \ + 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); \ - } - -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) - -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); -} - -#define FCMPEQQ(d, s) (d == s ? -1 : 0) -SSE_HELPER_Q(helper_pcmpeqq, FCMPEQQ) - -void glue(helper_packusdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - Reg r; - - 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)); - *d = r; -} - -#define FMINSB(d, s) MIN((int8_t)d, (int8_t)s) -#define FMINSD(d, s) MIN((int32_t)d, (int32_t)s) -#define FMAXSB(d, s) MAX((int8_t)d, (int8_t)s) -#define FMAXSD(d, s) MAX((int32_t)d, (int32_t)s) -SSE_HELPER_B(helper_pminsb, FMINSB) -SSE_HELPER_L(helper_pminsd, FMINSD) -SSE_HELPER_W(helper_pminuw, MIN) -SSE_HELPER_L(helper_pminud, MIN) -SSE_HELPER_B(helper_pmaxsb, FMAXSB) -SSE_HELPER_L(helper_pmaxsd, FMAXSD) -SSE_HELPER_W(helper_pmaxuw, MAX) -SSE_HELPER_L(helper_pmaxud, MAX) - -#define FMULLD(d, s) ((int32_t)d * (int32_t)s) -SSE_HELPER_L(helper_pmulld, FMULLD) +#define FMOVSLDUP(i) s->L((i) & ~1) +#define FMOVSHDUP(i) s->L((i) | 1) +#define FMOVDLDUP(i) s->Q((i) & ~1) + +#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); \ + } \ + } + +#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) +SSE_HELPER_F(helper_pmovsldup, L, 2 << SHIFT, FMOVSLDUP) +SSE_HELPER_F(helper_pmovshdup, L, 2 << SHIFT, FMOVSHDUP) +SSE_HELPER_F(helper_pmovdldup, Q, 1 << SHIFT, FMOVDLDUP) +#endif + +void glue(helper_pmuldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + 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); + } +} + +void glue(helper_packusdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + uint16_t r[8]; + int i, j, k; + + 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]; + } + } +} +#if SHIFT == 1 void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { int idx = 0; @@ -1768,35 +1702,23 @@ 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))) { - switch (mode & 3) { - case 0: - set_float_rounding_mode(float_round_nearest_even, &env->sse_status); - break; - case 1: - set_float_rounding_mode(float_round_down, &env->sse_status); - break; - case 2: - set_float_rounding_mode(float_round_up, &env->sse_status); - break; - case 3: - set_float_rounding_mode(float_round_to_zero, &env->sse_status); - break; - } + set_x86_rounding_mode(mode & 3, &env->sse_status); } - 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) & @@ -1811,27 +1733,16 @@ 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))) { - switch (mode & 3) { - case 0: - set_float_rounding_mode(float_round_nearest_even, &env->sse_status); - break; - case 1: - set_float_rounding_mode(float_round_down, &env->sse_status); - break; - case 2: - set_float_rounding_mode(float_round_up, &env->sse_status); - break; - case 3: - set_float_rounding_mode(float_round_to_zero, &env->sse_status); - break; - } + set_x86_rounding_mode(mode & 3, &env->sse_status); } - 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) & @@ -1841,31 +1752,23 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, env->sse_status.float_rounding_mode = prev_rounding_mode; } -void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, +#if SHIFT == 1 +void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, 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))) { - switch (mode & 3) { - case 0: - set_float_rounding_mode(float_round_nearest_even, &env->sse_status); - break; - case 1: - set_float_rounding_mode(float_round_down, &env->sse_status); - break; - case 2: - set_float_rounding_mode(float_round_up, &env->sse_status); - break; - case 3: - set_float_rounding_mode(float_round_to_zero, &env->sse_status); - break; - } + set_x86_rounding_mode(mode & 3, &env->sse_status); } d->ZMM_S(0) = float32_round_to_int(s->ZMM_S(0), &env->sse_status); + for (i = 1; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = v->ZMM_L(i); + } if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & @@ -1875,31 +1778,22 @@ void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, env->sse_status.float_rounding_mode = prev_rounding_mode; } -void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, +void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, 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))) { - switch (mode & 3) { - case 0: - set_float_rounding_mode(float_round_nearest_even, &env->sse_status); - break; - case 1: - set_float_rounding_mode(float_round_down, &env->sse_status); - break; - case 2: - set_float_rounding_mode(float_round_up, &env->sse_status); - break; - case 3: - set_float_rounding_mode(float_round_to_zero, &env->sse_status); - break; - } + set_x86_rounding_mode(mode & 3, &env->sse_status); } d->ZMM_D(0) = float64_round_to_int(s->ZMM_D(0), &env->sse_status); + for (i = 1; i < 1 << SHIFT; i++) { + d->ZMM_Q(i) = v->ZMM_Q(i); + } if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & @@ -1908,110 +1802,122 @@ 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 *v, Reg *s, + uint32_t mask) { - float32 iresult = float32_zero; + 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); - } - 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); + 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; } - 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 *v, Reg *s, uint32_t mask) { - float64 iresult = float64_zero; + 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, +void glue(helper_mpsadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, uint32_t offset) { - int s0 = (offset & 3) << 2; - int d0 = (offset & 4) << 0; - int i; - Reg r; - - 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)); + int i, j; + uint16_t r[8]; + + 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; } - - *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) { - int val; + target_long val, limit; /* Presence of REX.W is indicated by a bit higher than 7 set */ if (ctrl >> 8) { - val = abs1((int64_t)env->regs[reg]); + val = (target_long)env->regs[reg]; } else { - val = abs1((int32_t)env->regs[reg]); + val = (int32_t)env->regs[reg]; } - if (ctrl & 1) { - if (val > 8) { - return 8; - } + limit = 8; } else { - if (val > 16) { - return 16; - } + limit = 16; } - return val; + if ((val > limit) || (val < -limit)) { + return limit; + } + return abs1(val); } static inline int pcmp_ilen(Reg *r, uint8_t ctrl) @@ -2047,7 +1953,7 @@ static inline int pcmp_val(Reg *r, uint8_t ctrl, int i) } static inline unsigned pcmpxstrx(CPUX86State *env, Reg *d, Reg *s, - int8_t ctrl, int valids, int validd) + uint8_t ctrl, int valids, int validd) { unsigned int res = 0; int v; @@ -2213,14 +2119,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) { @@ -2233,71 +2141,87 @@ 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_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s, + uint32_t ctrl) { + uint64_t a, b; int i; - 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 < 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_aesdeclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) { int i; - Reg st = *d; + Reg st = *v; 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 < 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])]); } } -void glue(helper_aesenc, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_aesdeclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) { int i; - Reg st = *d; + Reg st = *v; 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 < 8 << SHIFT; i++) { + d->B(i) = rk.B(i) ^ (AES_isbox[st.B(AES_ishifts[i & 15] + (i & ~15))]); } } -void glue(helper_aesenclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_aesenc, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) { int i; - Reg st = *d; + Reg st = *v; 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 < 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])]); } +} + +void glue(helper_aesenclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + int i; + Reg st = *v; + Reg rk = *s; + 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]); } } @@ -2315,7 +2239,323 @@ 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 + +#if SHIFT >= 1 +void glue(helper_vpermilpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + uint64_t r0, r1; + int i; + + for (i = 0; i < 1 << SHIFT; i += 2) { + r0 = v->Q(i + ((s->Q(i) >> 1) & 1)); + r1 = v->Q(i + ((s->Q(i+1) >> 1) & 1)); + d->Q(i) = r0; + d->Q(i+1) = r1; + } +} + +void glue(helper_vpermilps, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + uint32_t r0, r1, r2, r3; + int i; + + for (i = 0; i < 2 << SHIFT; i += 4) { + r0 = v->L(i + (s->L(i) & 3)); + r1 = v->L(i + (s->L(i+1) & 3)); + r2 = v->L(i + (s->L(i+2) & 3)); + r3 = v->L(i + (s->L(i+3) & 3)); + d->L(i) = r0; + d->L(i+1) = r1; + d->L(i+2) = r2; + d->L(i+3) = r3; + } +} + +void glue(helper_vpermilpd_imm, SUFFIX)(Reg *d, Reg *s, uint32_t order) +{ + uint64_t r0, r1; + int i; + + for (i = 0; i < 1 << SHIFT; i += 2) { + r0 = s->Q(i + ((order >> 0) & 1)); + r1 = s->Q(i + ((order >> 1) & 1)); + d->Q(i) = r0; + d->Q(i+1) = r1; + + order >>= 2; + } +} + +void glue(helper_vpermilps_imm, SUFFIX)(Reg *d, Reg *s, uint32_t order) +{ + uint32_t r0, r1, r2, r3; + int i; + + for (i = 0; i < 2 << SHIFT; i += 4) { + r0 = s->L(i + ((order >> 0) & 3)); + r1 = s->L(i + ((order >> 2) & 3)); + r2 = s->L(i + ((order >> 4) & 3)); + r3 = s->L(i + ((order >> 6) & 3)); + d->L(i) = r0; + d->L(i+1) = r1; + d->L(i+2) = r2; + d->L(i+3) = r3; + } +} + +#if SHIFT == 1 +#define FPSRLVD(x, c) (c < 32 ? ((x) >> c) : 0) +#define FPSRLVQ(x, c) (c < 64 ? ((x) >> c) : 0) +#define FPSRAVD(x, c) ((int32_t)(x) >> (c < 32 ? c : 31)) +#define FPSRAVQ(x, c) ((int64_t)(x) >> (c < 64 ? c : 63)) +#define FPSLLVD(x, c) (c < 32 ? ((x) << c) : 0) +#define FPSLLVQ(x, c) (c < 64 ? ((x) << c) : 0) +#endif + +SSE_HELPER_L(helper_vpsrlvd, FPSRLVD) +SSE_HELPER_L(helper_vpsravd, FPSRAVD) +SSE_HELPER_L(helper_vpsllvd, FPSLLVD) + +SSE_HELPER_Q(helper_vpsrlvq, FPSRLVQ) +SSE_HELPER_Q(helper_vpsravq, FPSRAVQ) +SSE_HELPER_Q(helper_vpsllvq, FPSLLVQ) + +void glue(helper_vtestps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + uint32_t zf = 0, cf = 0; + int i; + + for (i = 0; i < 2 << SHIFT; i++) { + zf |= (s->L(i) & d->L(i)); + cf |= (s->L(i) & ~d->L(i)); + } + CC_SRC = ((zf >> 31) ? 0 : CC_Z) | ((cf >> 31) ? 0 : CC_C); +} + +void glue(helper_vtestpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + 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 >> 63) ? 0 : CC_Z) | ((cf >> 63) ? 0 : CC_C); +} + +void glue(helper_vpmaskmovd_st, SUFFIX)(CPUX86State *env, + Reg *v, Reg *s, target_ulong a0) +{ + int i; + + for (i = 0; i < (2 << SHIFT); i++) { + if (v->L(i) >> 31) { + cpu_stl_data_ra(env, a0 + i * 4, s->L(i), GETPC()); + } + } +} + +void glue(helper_vpmaskmovq_st, SUFFIX)(CPUX86State *env, + Reg *v, Reg *s, target_ulong a0) +{ + int i; + + for (i = 0; i < (1 << SHIFT); i++) { + if (v->Q(i) >> 63) { + cpu_stq_data_ra(env, a0 + i * 8, s->Q(i), GETPC()); + } + } +} + +void glue(helper_vpmaskmovd, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + int i; + + for (i = 0; i < (2 << SHIFT); i++) { + d->L(i) = (v->L(i) >> 31) ? s->L(i) : 0; + } +} + +void glue(helper_vpmaskmovq, SUFFIX)(CPUX86State *env, Reg *d, Reg *v, Reg *s) +{ + int i; + + for (i = 0; i < (1 << SHIFT); i++) { + d->Q(i) = (v->Q(i) >> 63) ? s->Q(i) : 0; + } +} + +void glue(helper_vpgatherdd, SUFFIX)(CPUX86State *env, + Reg *d, Reg *v, Reg *s, target_ulong a0, unsigned scale) +{ + int i; + for (i = 0; i < (2 << SHIFT); i++) { + if (v->L(i) >> 31) { + target_ulong addr = a0 + + ((target_ulong)(int32_t)s->L(i) << scale); + d->L(i) = cpu_ldl_data_ra(env, addr, GETPC()); + } + v->L(i) = 0; + } +} + +void glue(helper_vpgatherdq, SUFFIX)(CPUX86State *env, + Reg *d, Reg *v, Reg *s, target_ulong a0, unsigned scale) +{ + int i; + for (i = 0; i < (1 << SHIFT); i++) { + if (v->Q(i) >> 63) { + target_ulong addr = a0 + + ((target_ulong)(int32_t)s->L(i) << scale); + d->Q(i) = cpu_ldq_data_ra(env, addr, GETPC()); + } + v->Q(i) = 0; + } +} + +void glue(helper_vpgatherqd, SUFFIX)(CPUX86State *env, + Reg *d, Reg *v, Reg *s, target_ulong a0, unsigned scale) +{ + int i; + for (i = 0; i < (1 << SHIFT); i++) { + if (v->L(i) >> 31) { + target_ulong addr = a0 + + ((target_ulong)(int64_t)s->Q(i) << scale); + d->L(i) = cpu_ldl_data_ra(env, addr, GETPC()); + } + v->L(i) = 0; + } + for (i /= 2; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + v->Q(i) = 0; + } +} + +void glue(helper_vpgatherqq, SUFFIX)(CPUX86State *env, + Reg *d, Reg *v, Reg *s, target_ulong a0, unsigned scale) +{ + int i; + for (i = 0; i < (1 << SHIFT); i++) { + if (v->Q(i) >> 63) { + target_ulong addr = a0 + + ((target_ulong)(int64_t)s->Q(i) << scale); + d->Q(i) = cpu_ldq_data_ra(env, addr, GETPC()); + } + v->Q(i) = 0; + } +} +#endif + +#if SHIFT >= 2 +void helper_vpermdq_ymm(Reg *d, Reg *v, Reg *s, uint32_t order) +{ + uint64_t r0, r1, r2, r3; + + switch (order & 3) { + case 0: + r0 = v->Q(0); + r1 = v->Q(1); + break; + case 1: + r0 = v->Q(2); + r1 = v->Q(3); + break; + case 2: + r0 = s->Q(0); + r1 = s->Q(1); + break; + case 3: + r0 = s->Q(2); + r1 = s->Q(3); + break; + default: /* default case added to help the compiler to avoid warnings */ + g_assert_not_reached(); + } + switch ((order >> 4) & 3) { + case 0: + r2 = v->Q(0); + r3 = v->Q(1); + break; + case 1: + r2 = v->Q(2); + r3 = v->Q(3); + break; + case 2: + r2 = s->Q(0); + r3 = s->Q(1); + break; + case 3: + r2 = s->Q(2); + r3 = s->Q(3); + break; + default: /* default case added to help the compiler to avoid warnings */ + g_assert_not_reached(); + } + d->Q(0) = r0; + d->Q(1) = r1; + d->Q(2) = r2; + d->Q(3) = r3; +} + +void helper_vpermq_ymm(Reg *d, Reg *s, uint32_t order) +{ + uint64_t r0, r1, r2, r3; + r0 = s->Q(order & 3); + r1 = s->Q((order >> 2) & 3); + r2 = s->Q((order >> 4) & 3); + r3 = s->Q((order >> 6) & 3); + d->Q(0) = r0; + d->Q(1) = r1; + d->Q(2) = r2; + d->Q(3) = r3; +} + +void helper_vpermd_ymm(Reg *d, Reg *v, Reg *s) +{ + uint32_t r[8]; + int i; + + for (i = 0; i < 8; i++) { + r[i] = s->L(v->L(i) & 7); + } + for (i = 0; i < 8; i++) { + d->L(i) = r[i]; + } +} +#endif + +/* FMA3 op helpers */ +#if SHIFT == 1 +#define SSE_HELPER_FMAS(name, elem, F) \ + void name(CPUX86State *env, Reg *d, Reg *a, Reg *b, Reg *c, int flags) \ + { \ + d->elem(0) = F(a->elem(0), b->elem(0), c->elem(0), flags, &env->sse_status); \ + } +#define SSE_HELPER_FMAP(name, elem, num, F) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *a, Reg *b, Reg *c, \ + int flags, int flip) \ + { \ + int i; \ + for (i = 0; i < num; i++) { \ + d->elem(i) = F(a->elem(i), b->elem(i), c->elem(i), flags, &env->sse_status); \ + flags ^= flip; \ + } \ + } + +SSE_HELPER_FMAS(helper_fma4ss, ZMM_S, float32_muladd) +SSE_HELPER_FMAS(helper_fma4sd, ZMM_D, float64_muladd) +#endif + +#if SHIFT >= 1 +SSE_HELPER_FMAP(helper_fma4ps, ZMM_S, 2 << SHIFT, float32_muladd) +SSE_HELPER_FMAP(helper_fma4pd, ZMM_D, 1 << SHIFT, float64_muladd) +#endif + +#undef SSE_HELPER_S +#undef LANE_WIDTH #undef SHIFT #undef XMM_ONLY #undef Reg diff --git a/target/i386/ops_sse_header.h b/target/i386/ops_sse_header.h index cef28f2aae2f..8a7b2f4e2f67 100644 --- a/target/i386/ops_sse_header.h +++ b/target/i386/ops_sse_header.h @@ -21,7 +21,11 @@ #define SUFFIX _mmx #else #define Reg ZMMReg +#if SHIFT == 1 #define SUFFIX _xmm +#else +#define SUFFIX _ymm +#endif #endif #define dh_alias_Reg ptr @@ -34,74 +38,34 @@ #define dh_typecode_ZMMReg dh_typecode_ptr #define dh_typecode_MMXReg dh_typecode_ptr -DEF_HELPER_3(glue(psrlw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psraw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psllw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psrld, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psrad, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pslld, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psrlq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psllq, SUFFIX), void, env, Reg, Reg) - -#if SHIFT == 1 -DEF_HELPER_3(glue(psrldq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pslldq, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_4(glue(psrlw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psraw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psllw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psrld, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psrad, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(pslld, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psrlq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psllq, SUFFIX), void, env, Reg, Reg, Reg) + +#if SHIFT >= 1 +DEF_HELPER_4(glue(psrldq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(pslldq, SUFFIX), void, env, Reg, Reg, Reg) #endif #define SSE_HELPER_B(name, F)\ - DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) + DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg) #define SSE_HELPER_W(name, F)\ - DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) + DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg) #define SSE_HELPER_L(name, F)\ - DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) + DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg) #define SSE_HELPER_Q(name, F)\ - DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) - -SSE_HELPER_B(paddb, FADD) -SSE_HELPER_W(paddw, FADD) -SSE_HELPER_L(paddl, FADD) -SSE_HELPER_Q(paddq, FADD) - -SSE_HELPER_B(psubb, FSUB) -SSE_HELPER_W(psubw, FSUB) -SSE_HELPER_L(psubl, FSUB) -SSE_HELPER_Q(psubq, FSUB) - -SSE_HELPER_B(paddusb, FADDUB) -SSE_HELPER_B(paddsb, FADDSB) -SSE_HELPER_B(psubusb, FSUBUB) -SSE_HELPER_B(psubsb, FSUBSB) - -SSE_HELPER_W(paddusw, FADDUW) -SSE_HELPER_W(paddsw, FADDSW) -SSE_HELPER_W(psubusw, FSUBUW) -SSE_HELPER_W(psubsw, FSUBSW) - -SSE_HELPER_B(pminub, FMINUB) -SSE_HELPER_B(pmaxub, FMAXUB) - -SSE_HELPER_W(pminsw, FMINSW) -SSE_HELPER_W(pmaxsw, FMAXSW) - -SSE_HELPER_Q(pand, FAND) -SSE_HELPER_Q(pandn, FANDN) -SSE_HELPER_Q(por, FOR) -SSE_HELPER_Q(pxor, FXOR) - -SSE_HELPER_B(pcmpgtb, FCMPGTB) -SSE_HELPER_W(pcmpgtw, FCMPGTW) -SSE_HELPER_L(pcmpgtl, FCMPGTL) - -SSE_HELPER_B(pcmpeqb, FCMPEQ) -SSE_HELPER_W(pcmpeqw, FCMPEQ) -SSE_HELPER_L(pcmpeql, FCMPEQ) + DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg) -SSE_HELPER_W(pmullw, FMULLW) #if SHIFT == 0 -SSE_HELPER_W(pmulhrw, FMULHRW) +DEF_HELPER_3(glue(pmulhrw, SUFFIX), void, env, Reg, Reg) #endif SSE_HELPER_W(pmulhuw, FMULHUW) SSE_HELPER_W(pmulhw, FMULHW) @@ -109,51 +73,74 @@ SSE_HELPER_W(pmulhw, FMULHW) SSE_HELPER_B(pavgb, FAVG) SSE_HELPER_W(pavgw, FAVG) -DEF_HELPER_3(glue(pmuludq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmaddwd, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_4(glue(pmuludq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(pmaddwd, SUFFIX), void, env, Reg, Reg, Reg) -DEF_HELPER_3(glue(psadbw, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_4(glue(psadbw, SUFFIX), void, env, Reg, Reg, Reg) +#if SHIFT < 2 DEF_HELPER_4(glue(maskmov, SUFFIX), void, env, Reg, Reg, tl) -DEF_HELPER_2(glue(movl_mm_T0, SUFFIX), void, Reg, i32) -#ifdef TARGET_X86_64 -DEF_HELPER_2(glue(movq_mm_T0, SUFFIX), void, Reg, i64) #endif #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(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) #endif -#if SHIFT == 1 +#if SHIFT >= 1 /* FPU ops */ /* XXX: not accurate */ -#define SSE_HELPER_S(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) \ - DEF_HELPER_3(name ## sd, void, env, Reg, Reg) - -SSE_HELPER_S(add, FPU_ADD) -SSE_HELPER_S(sub, FPU_SUB) -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) - - -DEF_HELPER_3(cvtps2pd, void, env, Reg, Reg) -DEF_HELPER_3(cvtpd2ps, 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) +#define SSE_HELPER_P4(name) \ + DEF_HELPER_4(glue(name ## ps, SUFFIX), void, env, Reg, Reg, Reg) \ + DEF_HELPER_4(glue(name ## pd, SUFFIX), void, env, Reg, Reg, Reg) + +#define SSE_HELPER_P3(name, ...) \ + DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \ + DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg) + +#if SHIFT == 1 +#define SSE_HELPER_S4(name) \ + SSE_HELPER_P4(name) \ + DEF_HELPER_4(name ## ss, void, env, Reg, Reg, Reg) \ + DEF_HELPER_4(name ## sd, void, env, Reg, Reg, Reg) +#define SSE_HELPER_S3(name) \ + SSE_HELPER_P3(name) \ + DEF_HELPER_4(name ## ss, void, env, Reg, Reg, Reg) \ + DEF_HELPER_4(name ## sd, void, env, Reg, Reg, Reg) +#else +#define SSE_HELPER_S4(name, ...) SSE_HELPER_P4(name) +#define SSE_HELPER_S3(name, ...) SSE_HELPER_P3(name) +#endif + +DEF_HELPER_4(glue(shufps, SUFFIX), void, Reg, Reg, Reg, int) +DEF_HELPER_4(glue(shufpd, SUFFIX), void, Reg, Reg, Reg, int) + +SSE_HELPER_S4(add) +SSE_HELPER_S4(sub) +SSE_HELPER_S4(mul) +SSE_HELPER_S4(div) +SSE_HELPER_S4(min) +SSE_HELPER_S4(max) + +SSE_HELPER_S3(sqrt) + +DEF_HELPER_3(glue(cvtps2pd, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(cvtpd2ps, SUFFIX), 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(glue(cvtps2dq, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(cvtpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg) + +DEF_HELPER_3(glue(cvttps2dq, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(cvttpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg) + +#if SHIFT == 1 +DEF_HELPER_4(cvtss2sd, void, env, Reg, Reg, Reg) +DEF_HELPER_4(cvtsd2ss, void, env, Reg, 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 +151,6 @@ 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(cvtps2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvtpd2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_2(cvtss2si, s32, env, ZMMReg) @@ -175,8 +160,6 @@ 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(cvttps2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvttpd2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_2(cvttss2si, s32, env, ZMMReg) @@ -185,60 +168,87 @@ DEF_HELPER_2(cvttsd2si, s32, env, ZMMReg) DEF_HELPER_2(cvttss2sq, s64, env, ZMMReg) DEF_HELPER_2(cvttsd2sq, s64, env, ZMMReg) #endif +#endif -DEF_HELPER_3(rsqrtps, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(rsqrtss, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(rcpps, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(rcpss, void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(rsqrtps, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(rcpps, SUFFIX), void, env, ZMMReg, ZMMReg) + +#if SHIFT == 1 +DEF_HELPER_4(rsqrtss, void, env, ZMMReg, ZMMReg, ZMMReg) +DEF_HELPER_4(rcpss, void, env, ZMMReg, 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) - -#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) \ - 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) +DEF_HELPER_5(insertq_i, void, env, ZMMReg, ZMMReg, int, int) +#endif + +SSE_HELPER_P4(hadd) +SSE_HELPER_P4(hsub) +SSE_HELPER_P4(addsub) + +#define SSE_HELPER_CMP(name, F, C) SSE_HELPER_S4(name) + +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) + +SSE_HELPER_CMP(cmpequ, FPU_CMPQ, FPU_EQU) +SSE_HELPER_CMP(cmpnge, FPU_CMPS, !FPU_GE) +SSE_HELPER_CMP(cmpngt, FPU_CMPS, !FPU_GT) +SSE_HELPER_CMP(cmpfalse, FPU_CMPQ, FPU_FALSE) +SSE_HELPER_CMP(cmpnequ, FPU_CMPQ, !FPU_EQU) +SSE_HELPER_CMP(cmpge, FPU_CMPS, FPU_GE) +SSE_HELPER_CMP(cmpgt, FPU_CMPS, FPU_GT) +SSE_HELPER_CMP(cmptrue, FPU_CMPQ, !FPU_FALSE) + +SSE_HELPER_CMP(cmpeqs, FPU_CMPS, FPU_EQ) +SSE_HELPER_CMP(cmpltq, FPU_CMPQ, FPU_LT) +SSE_HELPER_CMP(cmpleq, FPU_CMPQ, FPU_LE) +SSE_HELPER_CMP(cmpunords, FPU_CMPS, FPU_UNORD) +SSE_HELPER_CMP(cmpneqq, FPU_CMPS, !FPU_EQ) +SSE_HELPER_CMP(cmpnltq, FPU_CMPQ, !FPU_LT) +SSE_HELPER_CMP(cmpnleq, FPU_CMPQ, !FPU_LE) +SSE_HELPER_CMP(cmpords, FPU_CMPS, !FPU_UNORD) + +SSE_HELPER_CMP(cmpequs, FPU_CMPS, FPU_EQU) +SSE_HELPER_CMP(cmpngeq, FPU_CMPQ, !FPU_GE) +SSE_HELPER_CMP(cmpngtq, FPU_CMPQ, !FPU_GT) +SSE_HELPER_CMP(cmpfalses, FPU_CMPS, FPU_FALSE) +SSE_HELPER_CMP(cmpnequs, FPU_CMPS, !FPU_EQU) +SSE_HELPER_CMP(cmpgeq, FPU_CMPQ, FPU_GE) +SSE_HELPER_CMP(cmpgtq, FPU_CMPQ, FPU_GT) +SSE_HELPER_CMP(cmptrues, FPU_CMPS, !FPU_FALSE) +#if SHIFT == 1 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) #endif -DEF_HELPER_2(glue(pmovmskb, SUFFIX), i32, env, Reg) -DEF_HELPER_3(glue(packsswb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(packuswb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(packssdw, SUFFIX), void, env, Reg, Reg) -#define UNPCK_OP(base_name, base) \ - DEF_HELPER_3(glue(punpck ## base_name ## bw, SUFFIX), void, env, Reg, Reg) \ - DEF_HELPER_3(glue(punpck ## base_name ## wd, SUFFIX), void, env, Reg, Reg) \ - DEF_HELPER_3(glue(punpck ## base_name ## dq, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_2(glue(movmskps, SUFFIX), i32, env, Reg) +DEF_HELPER_2(glue(movmskpd, SUFFIX), i32, env, Reg) +#endif + +DEF_HELPER_4(glue(packsswb, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(packuswb, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(packssdw, SUFFIX), void, env, Reg, Reg, Reg) +#define UNPCK_OP(name, base) \ + DEF_HELPER_4(glue(punpck ## name ## bw, SUFFIX), void, env, Reg, Reg, Reg) \ + DEF_HELPER_4(glue(punpck ## name ## wd, SUFFIX), void, env, Reg, Reg, Reg) \ + DEF_HELPER_4(glue(punpck ## name ## dq, SUFFIX), void, env, Reg, Reg, Reg) UNPCK_OP(l, 0) UNPCK_OP(h, 1) -#if SHIFT == 1 -DEF_HELPER_3(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg) +#if SHIFT >= 1 +DEF_HELPER_4(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg, Reg) #endif /* 3DNow! float ops */ @@ -265,28 +275,25 @@ DEF_HELPER_3(pswapd, void, env, MMXReg, MMXReg) #endif /* SSSE3 op helpers */ -DEF_HELPER_3(glue(phaddw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(phaddd, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(phaddsw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(phsubw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(phsubd, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(phsubsw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pabsb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pabsw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pabsd, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pshufb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psignb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psignw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(psignd, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_4(glue(palignr, SUFFIX), void, env, Reg, Reg, s32) +DEF_HELPER_4(glue(phaddw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(phaddd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(phaddsw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(phsubw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(phsubd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(phsubsw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(pshufb, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psignb, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psignw, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(psignd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_5(glue(palignr, SUFFIX), void, env, Reg, Reg, Reg, i32) /* SSE4.1 op helpers */ -#if SHIFT == 1 -DEF_HELPER_3(glue(pblendvb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(blendvps, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(blendvpd, SUFFIX), void, env, Reg, Reg) +#if SHIFT >= 1 +DEF_HELPER_5(glue(pblendvb, SUFFIX), void, env, Reg, Reg, Reg, Reg) +DEF_HELPER_5(glue(blendvps, SUFFIX), void, env, Reg, Reg, Reg, Reg) +DEF_HELPER_5(glue(blendvpd, SUFFIX), void, env, Reg, Reg, Reg, Reg) DEF_HELPER_3(glue(ptest, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovsxbw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovsxbd, SUFFIX), void, env, Reg, Reg) @@ -300,34 +307,32 @@ DEF_HELPER_3(glue(pmovzxbq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovzxwd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovzxwq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovzxdq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmuldq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pcmpeqq, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(packusdw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pminsb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pminsd, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pminuw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pminud, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmaxsb, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmaxsd, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmaxuw, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmaxud, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(pmulld, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(pmovsldup, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(pmovshdup, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(pmovdldup, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_4(glue(pmuldq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(packusdw, SUFFIX), void, env, Reg, Reg, Reg) +#if SHIFT == 1 DEF_HELPER_3(glue(phminposuw, SUFFIX), void, env, Reg, Reg) +#endif DEF_HELPER_4(glue(roundps, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(roundpd, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(roundss, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(roundsd, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(blendps, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(blendpd, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(pblendw, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(dpps, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(dppd, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(mpsadbw, SUFFIX), void, env, Reg, Reg, i32) +#if SHIFT == 1 +DEF_HELPER_5(roundss_xmm, void, env, Reg, Reg, Reg, i32) +DEF_HELPER_5(roundsd_xmm, void, env, Reg, Reg, Reg, i32) +#endif +DEF_HELPER_5(glue(blendps, SUFFIX), void, env, Reg, Reg, Reg, i32) +DEF_HELPER_5(glue(blendpd, SUFFIX), void, env, Reg, Reg, Reg, i32) +DEF_HELPER_5(glue(pblendw, SUFFIX), void, env, Reg, Reg, Reg, i32) +DEF_HELPER_5(glue(dpps, SUFFIX), void, env, Reg, Reg, Reg, i32) +#if SHIFT == 1 +DEF_HELPER_5(glue(dppd, SUFFIX), void, env, Reg, Reg, Reg, i32) +#endif +DEF_HELPER_5(glue(mpsadbw, SUFFIX), void, env, Reg, Reg, Reg, i32) #endif /* SSE4.2 op helpers */ #if SHIFT == 1 -DEF_HELPER_3(glue(pcmpgtq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pcmpestri, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(pcmpestrm, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(pcmpistri, SUFFIX), void, env, Reg, Reg, i32) @@ -336,14 +341,62 @@ DEF_HELPER_3(crc32, tl, i32, tl, i32) #endif /* AES-NI op helpers */ +#if SHIFT >= 1 +DEF_HELPER_4(glue(aesdec, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(aesdeclast, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(aesenc, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(aesenclast, SUFFIX), void, env, Reg, Reg, Reg) #if SHIFT == 1 -DEF_HELPER_3(glue(aesdec, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(aesdeclast, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(aesenc, SUFFIX), void, env, Reg, Reg) -DEF_HELPER_3(glue(aesenclast, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(aesimc, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(aeskeygenassist, SUFFIX), void, env, Reg, Reg, i32) -DEF_HELPER_4(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, i32) +#endif +DEF_HELPER_5(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, Reg, i32) +#endif + +/* F16C helpers */ +#if SHIFT >= 1 +DEF_HELPER_3(glue(cvtph2ps, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_4(glue(cvtps2ph, SUFFIX), void, env, Reg, Reg, int) +#endif + +/* FMA3 helpers */ +#if SHIFT == 1 +DEF_HELPER_6(fma4ss, void, env, Reg, Reg, Reg, Reg, int) +DEF_HELPER_6(fma4sd, void, env, Reg, Reg, Reg, Reg, int) +#endif + +#if SHIFT >= 1 +DEF_HELPER_7(glue(fma4ps, SUFFIX), void, env, Reg, Reg, Reg, Reg, int, int) +DEF_HELPER_7(glue(fma4pd, SUFFIX), void, env, Reg, Reg, Reg, Reg, int, int) +#endif + +/* AVX helpers */ +#if SHIFT >= 1 +DEF_HELPER_4(glue(vpermilpd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpermilps, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_3(glue(vpermilpd_imm, SUFFIX), void, Reg, Reg, i32) +DEF_HELPER_3(glue(vpermilps_imm, SUFFIX), void, Reg, Reg, i32) +DEF_HELPER_4(glue(vpsrlvd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpsravd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpsllvd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpsrlvq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpsravq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpsllvq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_3(glue(vtestps, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(vtestpd, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_4(glue(vpmaskmovd_st, SUFFIX), void, env, Reg, Reg, tl) +DEF_HELPER_4(glue(vpmaskmovq_st, SUFFIX), void, env, Reg, Reg, tl) +DEF_HELPER_4(glue(vpmaskmovd, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_4(glue(vpmaskmovq, SUFFIX), void, env, Reg, Reg, Reg) +DEF_HELPER_6(glue(vpgatherdd, SUFFIX), void, env, Reg, Reg, Reg, tl, i32) +DEF_HELPER_6(glue(vpgatherdq, SUFFIX), void, env, Reg, Reg, Reg, tl, i32) +DEF_HELPER_6(glue(vpgatherqd, SUFFIX), void, env, Reg, Reg, Reg, tl, i32) +DEF_HELPER_6(glue(vpgatherqq, SUFFIX), void, env, Reg, Reg, Reg, tl, i32) +#if SHIFT == 2 +DEF_HELPER_3(vpermd_ymm, void, Reg, Reg, Reg) +DEF_HELPER_4(vpermdq_ymm, void, Reg, Reg, Reg, i32) +DEF_HELPER_3(vpermq_ymm, void, Reg, Reg, i32) +#endif #endif #undef SHIFT @@ -354,6 +407,9 @@ DEF_HELPER_4(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, i32) #undef SSE_HELPER_W #undef SSE_HELPER_L #undef SSE_HELPER_Q -#undef SSE_HELPER_S +#undef SSE_HELPER_S3 +#undef SSE_HELPER_S4 +#undef SSE_HELPER_P3 +#undef SSE_HELPER_P4 #undef SSE_HELPER_CMP #undef UNPCK_OP diff --git a/target/i386/sev.c b/target/i386/sev.c index 025ff7a6f845..32f7dbac4efa 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -531,12 +531,46 @@ sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, return 1; } +static int sev_get_cpu0_id(int fd, guchar **id, size_t *id_len, Error **errp) +{ + guchar *id_data; + struct sev_user_data_get_id2 get_id2 = {}; + int err, r; + + /* query the ID length */ + r = sev_platform_ioctl(fd, SEV_GET_ID2, &get_id2, &err); + if (r < 0 && err != SEV_RET_INVALID_LEN) { + error_setg(errp, "SEV: Failed to get ID ret=%d fw_err=%d (%s)", + r, err, fw_error_to_str(err)); + return 1; + } + + id_data = g_new(guchar, get_id2.length); + get_id2.address = (unsigned long)id_data; + + r = sev_platform_ioctl(fd, SEV_GET_ID2, &get_id2, &err); + if (r < 0) { + error_setg(errp, "SEV: Failed to get ID ret=%d fw_err=%d (%s)", + r, err, fw_error_to_str(err)); + goto err; + } + + *id = id_data; + *id_len = get_id2.length; + return 0; + +err: + g_free(id_data); + return 1; +} + static SevCapability *sev_get_capabilities(Error **errp) { SevCapability *cap = NULL; guchar *pdh_data = NULL; guchar *cert_chain_data = NULL; - size_t pdh_len = 0, cert_chain_len = 0; + guchar *cpu0_id_data = NULL; + size_t pdh_len = 0, cert_chain_len = 0, cpu0_id_len = 0; uint32_t ebx; int fd; @@ -561,9 +595,14 @@ static SevCapability *sev_get_capabilities(Error **errp) goto out; } + if (sev_get_cpu0_id(fd, &cpu0_id_data, &cpu0_id_len, errp)) { + goto out; + } + cap = g_new0(SevCapability, 1); cap->pdh = g_base64_encode(pdh_data, pdh_len); cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len); + cap->cpu0_id = g_base64_encode(cpu0_id_data, cpu0_id_len); host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL); cap->cbitpos = ebx & 0x3f; @@ -575,6 +614,7 @@ static SevCapability *sev_get_capabilities(Error **errp) cap->reduced_phys_bits = 1; out: + g_free(cpu0_id_data); g_free(pdh_data); g_free(cert_chain_data); close(fd); diff --git a/target/i386/sev.h b/target/i386/sev.h index 83e82aa42c41..7b1528248a54 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -11,8 +11,8 @@ * */ -#ifndef QEMU_SEV_I386_H -#define QEMU_SEV_I386_H +#ifndef I386_SEV_H +#define I386_SEV_H #ifndef CONFIG_USER_ONLY #include CONFIG_DEVICES /* CONFIG_SEV */ diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c index b6c1fff16e51..bc34ac27fea7 100644 --- a/target/i386/tcg/bpt_helper.c +++ b/target/i386/tcg/bpt_helper.c @@ -22,7 +22,7 @@ #include "exec/helper-proto.h" #include "helper-tcg.h" -void QEMU_NORETURN helper_single_step(CPUX86State *env) +G_NORETURN void helper_single_step(CPUX86State *env) { #ifndef CONFIG_USER_ONLY check_hw_breakpoints(env, true); diff --git a/target/i386/tcg/cc_helper.c b/target/i386/tcg/cc_helper.c index cc7ea9e8b9d9..6227dbb30b7d 100644 --- a/target/i386/tcg/cc_helper.c +++ b/target/i386/tcg/cc_helper.c @@ -346,44 +346,3 @@ void helper_clts(CPUX86State *env) env->cr[0] &= ~CR0_TS_MASK; env->hflags &= ~HF_TS_MASK; } - -void helper_reset_rf(CPUX86State *env) -{ - env->eflags &= ~RF_MASK; -} - -void helper_cli(CPUX86State *env) -{ - env->eflags &= ~IF_MASK; -} - -void helper_sti(CPUX86State *env) -{ - env->eflags |= IF_MASK; -} - -void helper_clac(CPUX86State *env) -{ - env->eflags &= ~AC_MASK; -} - -void helper_stac(CPUX86State *env) -{ - env->eflags |= AC_MASK; -} - -#if 0 -/* vm86plus instructions */ -void helper_cli_vm(CPUX86State *env) -{ - env->eflags &= ~VIF_MASK; -} - -void helper_sti_vm(CPUX86State *env) -{ - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - raise_exception_ra(env, EXCP0D_GPF, GETPC()); - } -} -#endif diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc new file mode 100644 index 000000000000..d5fd8d965c44 --- /dev/null +++ b/target/i386/tcg/decode-new.c.inc @@ -0,0 +1,1845 @@ +/* + * New-style decoder for i386 instructions + * + * Copyright (c) 2022 Red Hat, Inc. + * + * Author: Paolo Bonzini + * + * 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 . + */ + +/* + * The decoder is mostly based on tables copied from the Intel SDM. As + * a result, most operand load and writeback is done entirely in common + * table-driven code using the same operand type (X86_TYPE_*) and + * size (X86_SIZE_*) codes used in the manual. + * + * The main difference is that the V, U and W types are extended to + * cover MMX as well; if an instruction is like + * + * por Pq, Qq + * 66 por Vx, Hx, Wx + * + * only the second row is included and the instruction is marked as a + * valid MMX instruction. The MMX flag directs the decoder to rewrite + * the V/U/H/W types to P/N/P/Q if there is no prefix, as well as changing + * "x" to "q" if there is no prefix. + * + * In addition, the ss/ps/sd/pd types are sometimes mushed together as "x" + * if the difference is expressed via prefixes. Individual instructions + * are separated by prefix in the generator functions. + * + * There are a couple cases in which instructions (e.g. MOVD) write the + * whole XMM or MM register but are established incorrectly in the manual + * as "d" or "q". These have to be fixed for the decoder to work correctly. + */ + +#define X86_OP_NONE { 0 }, + +#define X86_OP_GROUP3(op, op0_, s0_, op1_, s1_, op2_, s2_, ...) { \ + .decode = glue(decode_, op), \ + .op0 = glue(X86_TYPE_, op0_), \ + .s0 = glue(X86_SIZE_, s0_), \ + .op1 = glue(X86_TYPE_, op1_), \ + .s1 = glue(X86_SIZE_, s1_), \ + .op2 = glue(X86_TYPE_, op2_), \ + .s2 = glue(X86_SIZE_, s2_), \ + .is_decode = true, \ + ## __VA_ARGS__ \ +} + +#define X86_OP_GROUP2(op, op0, s0, op1, s1, ...) \ + X86_OP_GROUP3(op, op0, s0, 2op, s0, op1, s1, ## __VA_ARGS__) +#define X86_OP_GROUP0(op, ...) \ + X86_OP_GROUP3(op, None, None, None, None, None, None, ## __VA_ARGS__) + +#define X86_OP_ENTRY3(op, op0_, s0_, op1_, s1_, op2_, s2_, ...) { \ + .gen = glue(gen_, op), \ + .op0 = glue(X86_TYPE_, op0_), \ + .s0 = glue(X86_SIZE_, s0_), \ + .op1 = glue(X86_TYPE_, op1_), \ + .s1 = glue(X86_SIZE_, s1_), \ + .op2 = glue(X86_TYPE_, op2_), \ + .s2 = glue(X86_SIZE_, s2_), \ + ## __VA_ARGS__ \ +} + +#define X86_OP_ENTRY4(op, op0_, s0_, op1_, s1_, op2_, s2_, ...) \ + X86_OP_ENTRY3(op, op0_, s0_, op1_, s1_, op2_, s2_, \ + .op3 = X86_TYPE_I, .s3 = X86_SIZE_b, \ + ## __VA_ARGS__) + +#define X86_OP_ENTRY2(op, op0, s0, op1, s1, ...) \ + X86_OP_ENTRY3(op, op0, s0, 2op, s0, op1, s1, ## __VA_ARGS__) +#define X86_OP_ENTRYw(op, op0, s0, ...) \ + X86_OP_ENTRY3(op, op0, s0, None, None, None, None, ## __VA_ARGS__) +#define X86_OP_ENTRYr(op, op0, s0, ...) \ + X86_OP_ENTRY3(op, None, None, None, None, op0, s0, ## __VA_ARGS__) +#define X86_OP_ENTRY0(op, ...) \ + X86_OP_ENTRY3(op, None, None, None, None, None, None, ## __VA_ARGS__) + +#define cpuid(feat) .cpuid = X86_FEAT_##feat, +#define i64 .special = X86_SPECIAL_i64, +#define o64 .special = X86_SPECIAL_o64, +#define xchg .special = X86_SPECIAL_Locked, +#define mmx .special = X86_SPECIAL_MMX, +#define zext0 .special = X86_SPECIAL_ZExtOp0, +#define zext2 .special = X86_SPECIAL_ZExtOp2, +#define avx_movx .special = X86_SPECIAL_AVXExtMov, + +#define vex1 .vex_class = 1, +#define vex1_rep3 .vex_class = 1, .vex_special = X86_VEX_REPScalar, +#define vex2 .vex_class = 2, +#define vex2_rep3 .vex_class = 2, .vex_special = X86_VEX_REPScalar, +#define vex3 .vex_class = 3, +#define vex4 .vex_class = 4, +#define vex4_unal .vex_class = 4, .vex_special = X86_VEX_SSEUnaligned, +#define vex4_rep5 .vex_class = 4, .vex_special = X86_VEX_REPScalar, +#define vex5 .vex_class = 5, +#define vex6 .vex_class = 6, +#define vex7 .vex_class = 7, +#define vex8 .vex_class = 8, +#define vex11 .vex_class = 11, +#define vex12 .vex_class = 12, +#define vex13 .vex_class = 13, + +#define avx2_256 .vex_special = X86_VEX_AVX2_256, + +#define P_00 1 +#define P_66 (1 << PREFIX_DATA) +#define P_F3 (1 << PREFIX_REPZ) +#define P_F2 (1 << PREFIX_REPNZ) + +#define p_00 .valid_prefix = P_00, +#define p_66 .valid_prefix = P_66, +#define p_f3 .valid_prefix = P_F3, +#define p_f2 .valid_prefix = P_F2, +#define p_00_66 .valid_prefix = P_00 | P_66, +#define p_00_f3 .valid_prefix = P_00 | P_F3, +#define p_66_f2 .valid_prefix = P_66 | P_F2, +#define p_00_66_f3 .valid_prefix = P_00 | P_66 | P_F3, +#define p_66_f3_f2 .valid_prefix = P_66 | P_F3 | P_F2, +#define p_00_66_f3_f2 .valid_prefix = P_00 | P_66 | P_F3 | P_F2, + +static uint8_t get_modrm(DisasContext *s, CPUX86State *env) +{ + if (!s->has_modrm) { + s->modrm = x86_ldub_code(env, s); + s->has_modrm = true; + } + return s->modrm; +} + +static inline const X86OpEntry *decode_by_prefix(DisasContext *s, const X86OpEntry entries[4]) +{ + if (s->prefix & PREFIX_REPNZ) { + return &entries[3]; + } else if (s->prefix & PREFIX_REPZ) { + return &entries[2]; + } else if (s->prefix & PREFIX_DATA) { + return &entries[1]; + } else { + return &entries[0]; + } +} + +static void decode_group15(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + /* only includes ldmxcsr and stmxcsr, because they have AVX variants. */ + static const X86OpEntry group15_reg[8] = { + }; + + static const X86OpEntry group15_mem[8] = { + [2] = X86_OP_ENTRYr(LDMXCSR, E,d, vex5), + [3] = X86_OP_ENTRYw(STMXCSR, E,d, vex5), + }; + + uint8_t modrm = get_modrm(s, env); + if ((modrm >> 6) == 3) { + *entry = group15_reg[(modrm >> 3) & 7]; + } else { + *entry = group15_mem[(modrm >> 3) & 7]; + } +} + +static void decode_group17(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86GenFunc group17_gen[8] = { + NULL, gen_BLSR, gen_BLSMSK, gen_BLSI, + }; + int op = (get_modrm(s, env) >> 3) & 7; + entry->gen = group17_gen[op]; +} + +static void decode_group12(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_group12[8] = { + {}, + {}, + X86_OP_ENTRY3(PSRLW_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + {}, + X86_OP_ENTRY3(PSRAW_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + {}, + X86_OP_ENTRY3(PSLLW_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + {}, + }; + + int op = (get_modrm(s, env) >> 3) & 7; + *entry = opcodes_group12[op]; +} + +static void decode_group13(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_group13[8] = { + {}, + {}, + X86_OP_ENTRY3(PSRLD_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + {}, + X86_OP_ENTRY3(PSRAD_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + {}, + X86_OP_ENTRY3(PSLLD_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + {}, + }; + + int op = (get_modrm(s, env) >> 3) & 7; + *entry = opcodes_group13[op]; +} + +static void decode_group14(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_group14[8] = { + /* grp14 */ + {}, + {}, + X86_OP_ENTRY3(PSRLQ_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + X86_OP_ENTRY3(PSRLDQ_i, H,x, U,x, I,b, vex7 avx2_256 p_66), + {}, + {}, + X86_OP_ENTRY3(PSLLQ_i, H,x, U,x, I,b, vex7 mmx avx2_256 p_00_66), + X86_OP_ENTRY3(PSLLDQ_i, H,x, U,x, I,b, vex7 avx2_256 p_66), + }; + + int op = (get_modrm(s, env) >> 3) & 7; + *entry = opcodes_group14[op]; +} + +static void decode_0F6F(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F6F[4] = { + X86_OP_ENTRY3(MOVDQ, P,q, None,None, Q,q, vex1 mmx), /* movq */ + X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex1), /* movdqa */ + X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* movdqu */ + {}, + }; + *entry = *decode_by_prefix(s, opcodes_0F6F); +} + +static void decode_0F70(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry pshufw[4] = { + X86_OP_ENTRY3(PSHUFW, P,q, Q,q, I,b, vex4 mmx), + X86_OP_ENTRY3(PSHUFD, V,x, W,x, I,b, vex4 avx2_256), + X86_OP_ENTRY3(PSHUFHW, V,x, W,x, I,b, vex4 avx2_256), + X86_OP_ENTRY3(PSHUFLW, V,x, W,x, I,b, vex4 avx2_256), + }; + + *entry = *decode_by_prefix(s, pshufw); +} + +static void decode_0F77(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + if (!(s->prefix & PREFIX_VEX)) { + entry->gen = gen_EMMS; + } else if (!s->vex_l) { + entry->gen = gen_VZEROUPPER; + entry->vex_class = 8; + } else { + entry->gen = gen_VZEROALL; + entry->vex_class = 8; + } +} + +static void decode_0F78(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F78[4] = { + {}, + X86_OP_ENTRY3(EXTRQ_i, V,x, None,None, I,w, cpuid(SSE4A)), + {}, + X86_OP_ENTRY3(INSERTQ_i, V,x, U,x, I,w, cpuid(SSE4A)), + }; + *entry = *decode_by_prefix(s, opcodes_0F78); +} + +static void decode_0F79(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + if (s->prefix & PREFIX_REPNZ) { + entry->gen = gen_INSERTQ_r; + } else if (s->prefix & PREFIX_DATA) { + entry->gen = gen_EXTRQ_r; + } else { + entry->gen = NULL; + }; +} + +static void decode_0F7E(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F7E[4] = { + X86_OP_ENTRY3(MOVD_from, E,y, None,None, P,y, vex5 mmx), + X86_OP_ENTRY3(MOVD_from, E,y, None,None, V,y, vex5), + X86_OP_ENTRY3(MOVQ, V,x, None,None, W,q, vex5), /* wrong dest Vy on SDM! */ + {}, + }; + *entry = *decode_by_prefix(s, opcodes_0F7E); +} + +static void decode_0F7F(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F7F[4] = { + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex1 mmx), /* movq */ + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex1), /* movdqa */ + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4_unal), /* movdqu */ + {}, + }; + *entry = *decode_by_prefix(s, opcodes_0F7F); +} + +static void decode_0FD6(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry movq[4] = { + {}, + X86_OP_ENTRY3(MOVQ, W,x, None, None, V,q, vex5), + X86_OP_ENTRY3(MOVq_dq, V,dq, None, None, N,q), + X86_OP_ENTRY3(MOVq_dq, P,q, None, None, U,q), + }; + + *entry = *decode_by_prefix(s, movq); +} + +static const X86OpEntry opcodes_0F38_00toEF[240] = { + [0x00] = X86_OP_ENTRY3(PSHUFB, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x01] = X86_OP_ENTRY3(PHADDW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x02] = X86_OP_ENTRY3(PHADDD, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x03] = X86_OP_ENTRY3(PHADDSW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x04] = X86_OP_ENTRY3(PMADDUBSW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x05] = X86_OP_ENTRY3(PHSUBW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x06] = X86_OP_ENTRY3(PHSUBD, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x07] = X86_OP_ENTRY3(PHSUBSW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + + [0x10] = X86_OP_ENTRY2(PBLENDVB, V,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x13] = X86_OP_ENTRY2(VCVTPH2PS, V,x, W,ph, vex11 cpuid(F16C) p_66), + [0x14] = X86_OP_ENTRY2(BLENDVPS, V,x, W,x, vex4 cpuid(SSE41) p_66), + [0x15] = X86_OP_ENTRY2(BLENDVPD, V,x, W,x, vex4 cpuid(SSE41) p_66), + /* Listed incorrectly as type 4 */ + [0x16] = X86_OP_ENTRY3(VPERMD, V,qq, H,qq, W,qq, vex6 cpuid(AVX2) p_66), + [0x17] = X86_OP_ENTRY3(VPTEST, None,None, V,x, W,x, vex4 cpuid(SSE41) p_66), + + /* + * Source operand listed as Mq/Ux and similar in the manual; incorrectly listed + * as 128-bit only in 2-17. + */ + [0x20] = X86_OP_ENTRY3(VPMOVSXBW, V,x, None,None, W,q, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x21] = X86_OP_ENTRY3(VPMOVSXBD, V,x, None,None, W,d, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x22] = X86_OP_ENTRY3(VPMOVSXBQ, V,x, None,None, W,w, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x23] = X86_OP_ENTRY3(VPMOVSXWD, V,x, None,None, W,q, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x24] = X86_OP_ENTRY3(VPMOVSXWQ, V,x, None,None, W,d, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x25] = X86_OP_ENTRY3(VPMOVSXDQ, V,x, None,None, W,q, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + + /* Same as PMOVSX. */ + [0x30] = X86_OP_ENTRY3(VPMOVZXBW, V,x, None,None, W,q, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x31] = X86_OP_ENTRY3(VPMOVZXBD, V,x, None,None, W,d, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x32] = X86_OP_ENTRY3(VPMOVZXBQ, V,x, None,None, W,w, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x33] = X86_OP_ENTRY3(VPMOVZXWD, V,x, None,None, W,q, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x34] = X86_OP_ENTRY3(VPMOVZXWQ, V,x, None,None, W,d, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x35] = X86_OP_ENTRY3(VPMOVZXDQ, V,x, None,None, W,q, vex5 cpuid(SSE41) avx_movx avx2_256 p_66), + [0x36] = X86_OP_ENTRY3(VPERMD, V,qq, H,qq, W,qq, vex6 cpuid(AVX2) p_66), + [0x37] = X86_OP_ENTRY3(PCMPGTQ, V,x, H,x, W,x, vex4 cpuid(SSE42) avx2_256 p_66), + + [0x40] = X86_OP_ENTRY3(PMULLD, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x41] = X86_OP_ENTRY3(VPHMINPOSUW, V,dq, None,None, W,dq, vex4 cpuid(SSE41) p_66), + /* Listed incorrectly as type 4 */ + [0x45] = X86_OP_ENTRY3(VPSRLV, V,x, H,x, W,x, vex6 cpuid(AVX2) p_66), + [0x46] = X86_OP_ENTRY3(VPSRAV, V,x, H,x, W,x, vex6 cpuid(AVX2) p_66), + [0x47] = X86_OP_ENTRY3(VPSLLV, V,x, H,x, W,x, vex6 cpuid(AVX2) p_66), + + [0x90] = X86_OP_ENTRY3(VPGATHERD, V,x, H,x, M,d, vex12 cpuid(AVX2) p_66), /* vpgatherdd/q */ + [0x91] = X86_OP_ENTRY3(VPGATHERQ, V,x, H,x, M,q, vex12 cpuid(AVX2) p_66), /* vpgatherqd/q */ + [0x92] = X86_OP_ENTRY3(VPGATHERD, V,x, H,x, M,d, vex12 cpuid(AVX2) p_66), /* vgatherdps/d */ + [0x93] = X86_OP_ENTRY3(VPGATHERQ, V,x, H,x, M,q, vex12 cpuid(AVX2) p_66), /* vgatherqps/d */ + + /* Should be exception type 2 but they do not have legacy SSE equivalents? */ + [0x96] = X86_OP_ENTRY3(VFMADDSUB132Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x97] = X86_OP_ENTRY3(VFMSUBADD132Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + + [0xa6] = X86_OP_ENTRY3(VFMADDSUB213Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xa7] = X86_OP_ENTRY3(VFMSUBADD213Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + + [0xb6] = X86_OP_ENTRY3(VFMADDSUB231Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xb7] = X86_OP_ENTRY3(VFMSUBADD231Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + + [0x08] = X86_OP_ENTRY3(PSIGNB, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x09] = X86_OP_ENTRY3(PSIGNW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x0a] = X86_OP_ENTRY3(PSIGND, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x0b] = X86_OP_ENTRY3(PMULHRSW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x0c] = X86_OP_ENTRY3(VPERMILPS, V,x, H,x, W,x, vex4 cpuid(AVX) p_00_66), + [0x0d] = X86_OP_ENTRY3(VPERMILPD, V,x, H,x, W,x, vex4 cpuid(AVX) p_66), + [0x0e] = X86_OP_ENTRY3(VTESTPS, None,None, V,x, W,x, vex4 cpuid(AVX) p_66), + [0x0f] = X86_OP_ENTRY3(VTESTPD, None,None, V,x, W,x, vex4 cpuid(AVX) p_66), + + [0x18] = X86_OP_ENTRY3(VPBROADCASTD, V,x, None,None, W,d, vex6 cpuid(AVX) p_66), /* vbroadcastss */ + [0x19] = X86_OP_ENTRY3(VPBROADCASTQ, V,qq, None,None, W,q, vex6 cpuid(AVX) p_66), /* vbroadcastsd */ + [0x1a] = X86_OP_ENTRY3(VBROADCASTx128, V,qq, None,None, WM,dq,vex6 cpuid(AVX) p_66), + [0x1c] = X86_OP_ENTRY3(PABSB, V,x, None,None, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x1d] = X86_OP_ENTRY3(PABSW, V,x, None,None, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + [0x1e] = X86_OP_ENTRY3(PABSD, V,x, None,None, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + + [0x28] = X86_OP_ENTRY3(PMULDQ, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x29] = X86_OP_ENTRY3(PCMPEQQ, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x2a] = X86_OP_ENTRY3(MOVDQ, V,x, None,None, WM,x, vex1 cpuid(SSE41) avx2_256 p_66), /* movntdqa */ + [0x2b] = X86_OP_ENTRY3(VPACKUSDW, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x2c] = X86_OP_ENTRY3(VMASKMOVPS, V,x, H,x, WM,x, vex6 cpuid(AVX) p_66), + [0x2d] = X86_OP_ENTRY3(VMASKMOVPD, V,x, H,x, WM,x, vex6 cpuid(AVX) p_66), + /* Incorrectly listed as Mx,Hx,Vx in the manual */ + [0x2e] = X86_OP_ENTRY3(VMASKMOVPS_st, M,x, V,x, H,x, vex6 cpuid(AVX) p_66), + [0x2f] = X86_OP_ENTRY3(VMASKMOVPD_st, M,x, V,x, H,x, vex6 cpuid(AVX) p_66), + + [0x38] = X86_OP_ENTRY3(PMINSB, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x39] = X86_OP_ENTRY3(PMINSD, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x3a] = X86_OP_ENTRY3(PMINUW, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x3b] = X86_OP_ENTRY3(PMINUD, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x3c] = X86_OP_ENTRY3(PMAXSB, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x3d] = X86_OP_ENTRY3(PMAXSD, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x3e] = X86_OP_ENTRY3(PMAXUW, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x3f] = X86_OP_ENTRY3(PMAXUD, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + + [0x58] = X86_OP_ENTRY3(VPBROADCASTD, V,x, None,None, W,d, vex6 cpuid(AVX2) p_66), + [0x59] = X86_OP_ENTRY3(VPBROADCASTQ, V,x, None,None, W,q, vex6 cpuid(AVX2) p_66), + [0x5a] = X86_OP_ENTRY3(VBROADCASTx128, V,qq, None,None, WM,dq,vex6 cpuid(AVX2) p_66), + + [0x78] = X86_OP_ENTRY3(VPBROADCASTB, V,x, None,None, W,b, vex6 cpuid(AVX2) p_66), + [0x79] = X86_OP_ENTRY3(VPBROADCASTW, V,x, None,None, W,w, vex6 cpuid(AVX2) p_66), + + [0x8c] = X86_OP_ENTRY3(VPMASKMOV, V,x, H,x, WM,x, vex6 cpuid(AVX2) p_66), + [0x8e] = X86_OP_ENTRY3(VPMASKMOV_st, M,x, V,x, H,x, vex6 cpuid(AVX2) p_66), + + /* Should be exception type 2 or 3 but they do not have legacy SSE equivalents? */ + [0x98] = X86_OP_ENTRY3(VFMADD132Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x99] = X86_OP_ENTRY3(VFMADD132Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x9a] = X86_OP_ENTRY3(VFMSUB132Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x9b] = X86_OP_ENTRY3(VFMSUB132Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x9c] = X86_OP_ENTRY3(VFNMADD132Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x9d] = X86_OP_ENTRY3(VFNMADD132Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x9e] = X86_OP_ENTRY3(VFNMSUB132Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0x9f] = X86_OP_ENTRY3(VFNMSUB132Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + + [0xa8] = X86_OP_ENTRY3(VFMADD213Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xa9] = X86_OP_ENTRY3(VFMADD213Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xaa] = X86_OP_ENTRY3(VFMSUB213Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xab] = X86_OP_ENTRY3(VFMSUB213Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xac] = X86_OP_ENTRY3(VFNMADD213Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xad] = X86_OP_ENTRY3(VFNMADD213Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xae] = X86_OP_ENTRY3(VFNMSUB213Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xaf] = X86_OP_ENTRY3(VFNMSUB213Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + + [0xb8] = X86_OP_ENTRY3(VFMADD231Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xb9] = X86_OP_ENTRY3(VFMADD231Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xba] = X86_OP_ENTRY3(VFMSUB231Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xbb] = X86_OP_ENTRY3(VFMSUB231Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xbc] = X86_OP_ENTRY3(VFNMADD231Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xbd] = X86_OP_ENTRY3(VFNMADD231Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xbe] = X86_OP_ENTRY3(VFNMSUB231Px, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + [0xbf] = X86_OP_ENTRY3(VFNMSUB231Sx, V,x, H,x, W,x, vex6 cpuid(FMA) p_66), + + [0xdb] = X86_OP_ENTRY3(VAESIMC, V,dq, None,None, W,dq, vex4 cpuid(AES) p_66), + [0xdc] = X86_OP_ENTRY3(VAESENC, V,x, H,x, W,x, vex4 cpuid(AES) p_66), + [0xdd] = X86_OP_ENTRY3(VAESENCLAST, V,x, H,x, W,x, vex4 cpuid(AES) p_66), + [0xde] = X86_OP_ENTRY3(VAESDEC, V,x, H,x, W,x, vex4 cpuid(AES) p_66), + [0xdf] = X86_OP_ENTRY3(VAESDECLAST, V,x, H,x, W,x, vex4 cpuid(AES) p_66), +}; + +/* five rows for no prefix, 66, F3, F2, 66+F2 */ +static const X86OpEntry opcodes_0F38_F0toFF[16][5] = { + [0] = { + X86_OP_ENTRY3(MOVBE, G,y, M,y, None,None, cpuid(MOVBE)), + X86_OP_ENTRY3(MOVBE, G,w, M,w, None,None, cpuid(MOVBE)), + {}, + X86_OP_ENTRY2(CRC32, G,d, E,b, cpuid(SSE42)), + X86_OP_ENTRY2(CRC32, G,d, E,b, cpuid(SSE42)), + }, + [1] = { + X86_OP_ENTRY3(MOVBE, M,y, G,y, None,None, cpuid(MOVBE)), + X86_OP_ENTRY3(MOVBE, M,w, G,w, None,None, cpuid(MOVBE)), + {}, + X86_OP_ENTRY2(CRC32, G,d, E,y, cpuid(SSE42)), + X86_OP_ENTRY2(CRC32, G,d, E,w, cpuid(SSE42)), + }, + [2] = { + X86_OP_ENTRY3(ANDN, G,y, B,y, E,y, vex13 cpuid(BMI1)), + {}, + {}, + {}, + {}, + }, + [3] = { + X86_OP_GROUP3(group17, B,y, E,y, None,None, vex13 cpuid(BMI1)), + {}, + {}, + {}, + {}, + }, + [5] = { + X86_OP_ENTRY3(BZHI, G,y, E,y, B,y, vex13 cpuid(BMI1)), + {}, + X86_OP_ENTRY3(PEXT, G,y, B,y, E,y, vex13 cpuid(BMI2)), + X86_OP_ENTRY3(PDEP, G,y, B,y, E,y, vex13 cpuid(BMI2)), + {}, + }, + [6] = { + {}, + X86_OP_ENTRY2(ADCX, G,y, E,y, cpuid(ADX)), + X86_OP_ENTRY2(ADOX, G,y, E,y, cpuid(ADX)), + X86_OP_ENTRY3(MULX, /* B,y, */ G,y, E,y, 2,y, vex13 cpuid(BMI2)), + {}, + }, + [7] = { + X86_OP_ENTRY3(BEXTR, G,y, E,y, B,y, vex13 cpuid(BMI1)), + X86_OP_ENTRY3(SHLX, G,y, E,y, B,y, vex13 cpuid(BMI1)), + X86_OP_ENTRY3(SARX, G,y, E,y, B,y, vex13 cpuid(BMI1)), + X86_OP_ENTRY3(SHRX, G,y, E,y, B,y, vex13 cpuid(BMI1)), + {}, + }, +}; + +static void decode_0F38(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + *b = x86_ldub_code(env, s); + if (*b < 0xf0) { + *entry = opcodes_0F38_00toEF[*b]; + } else { + int row = 0; + if (s->prefix & PREFIX_REPZ) { + /* The REPZ (F3) prefix has priority over 66 */ + row = 2; + } else { + row += s->prefix & PREFIX_REPNZ ? 3 : 0; + row += s->prefix & PREFIX_DATA ? 1 : 0; + } + *entry = opcodes_0F38_F0toFF[*b & 15][row]; + } +} + +static void decode_VINSERTPS(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry + vinsertps_reg = X86_OP_ENTRY4(VINSERTPS_r, V,dq, H,dq, U,dq, vex5 cpuid(SSE41) p_66), + vinsertps_mem = X86_OP_ENTRY4(VINSERTPS_m, V,dq, H,dq, M,d, vex5 cpuid(SSE41) p_66); + + int modrm = get_modrm(s, env); + *entry = (modrm >> 6) == 3 ? vinsertps_reg : vinsertps_mem; +} + +static const X86OpEntry opcodes_0F3A[256] = { + /* + * These are VEX-only, but incorrectly listed in the manual as exception type 4. + * Also the "qq" instructions are sometimes omitted by Table 2-17, but are VEX256 + * only. + */ + [0x00] = X86_OP_ENTRY3(VPERMQ, V,qq, W,qq, I,b, vex6 cpuid(AVX2) p_66), + [0x01] = X86_OP_ENTRY3(VPERMQ, V,qq, W,qq, I,b, vex6 cpuid(AVX2) p_66), /* VPERMPD */ + [0x02] = X86_OP_ENTRY4(VBLENDPS, V,x, H,x, W,x, vex6 cpuid(AVX2) p_66), /* VPBLENDD */ + [0x04] = X86_OP_ENTRY3(VPERMILPS_i, V,x, W,x, I,b, vex6 cpuid(AVX) p_66), + [0x05] = X86_OP_ENTRY3(VPERMILPD_i, V,x, W,x, I,b, vex6 cpuid(AVX) p_66), + [0x06] = X86_OP_ENTRY4(VPERM2x128, V,qq, H,qq, W,qq, vex6 cpuid(AVX) p_66), + + [0x14] = X86_OP_ENTRY3(PEXTRB, E,b, V,dq, I,b, vex5 cpuid(SSE41) zext0 p_66), + [0x15] = X86_OP_ENTRY3(PEXTRW, E,w, V,dq, I,b, vex5 cpuid(SSE41) zext0 p_66), + [0x16] = X86_OP_ENTRY3(PEXTR, E,y, V,dq, I,b, vex5 cpuid(SSE41) p_66), + [0x17] = X86_OP_ENTRY3(VEXTRACTPS, E,d, V,dq, I,b, vex5 cpuid(SSE41) p_66), + [0x1d] = X86_OP_ENTRY3(VCVTPS2PH, W,ph, V,x, I,b, vex11 cpuid(F16C) p_66), + + [0x20] = X86_OP_ENTRY4(PINSRB, V,dq, H,dq, E,b, vex5 cpuid(SSE41) zext2 p_66), + [0x21] = X86_OP_GROUP0(VINSERTPS), + [0x22] = X86_OP_ENTRY4(PINSR, V,dq, H,dq, E,y, vex5 cpuid(SSE41) p_66), + + [0x40] = X86_OP_ENTRY4(VDDPS, V,x, H,x, W,x, vex2 cpuid(SSE41) p_66), + [0x41] = X86_OP_ENTRY4(VDDPD, V,dq, H,dq, W,dq, vex2 cpuid(SSE41) p_66), + [0x42] = X86_OP_ENTRY4(VMPSADBW, V,x, H,x, W,x, vex2 cpuid(SSE41) avx2_256 p_66), + [0x44] = X86_OP_ENTRY4(PCLMULQDQ, V,dq, H,dq, W,dq, vex4 cpuid(PCLMULQDQ) p_66), + [0x46] = X86_OP_ENTRY4(VPERM2x128, V,qq, H,qq, W,qq, vex6 cpuid(AVX2) p_66), + + [0x60] = X86_OP_ENTRY4(PCMPESTRM, None,None, V,dq, W,dq, vex4_unal cpuid(SSE42) p_66), + [0x61] = X86_OP_ENTRY4(PCMPESTRI, None,None, V,dq, W,dq, vex4_unal cpuid(SSE42) p_66), + [0x62] = X86_OP_ENTRY4(PCMPISTRM, None,None, V,dq, W,dq, vex4_unal cpuid(SSE42) p_66), + [0x63] = X86_OP_ENTRY4(PCMPISTRI, None,None, V,dq, W,dq, vex4_unal cpuid(SSE42) p_66), + + [0x08] = X86_OP_ENTRY3(VROUNDPS, V,x, W,x, I,b, vex2 cpuid(SSE41) p_66), + [0x09] = X86_OP_ENTRY3(VROUNDPD, V,x, W,x, I,b, vex2 cpuid(SSE41) p_66), + /* + * Not listed as four operand in the manual. Also writes and reads 128-bits + * from the first two operands due to the V operand picking higher entries of + * the H operand; the "Vss,Hss,Wss" description from the manual is incorrect. + * For other unary operations such as VSQRTSx this is hidden by the "REPScalar" + * value of vex_special, because the table lists the operand types of VSQRTPx. + */ + [0x0a] = X86_OP_ENTRY4(VROUNDSS, V,x, H,x, W,ss, vex3 cpuid(SSE41) p_66), + [0x0b] = X86_OP_ENTRY4(VROUNDSD, V,x, H,x, W,sd, vex3 cpuid(SSE41) p_66), + [0x0c] = X86_OP_ENTRY4(VBLENDPS, V,x, H,x, W,x, vex4 cpuid(SSE41) p_66), + [0x0d] = X86_OP_ENTRY4(VBLENDPD, V,x, H,x, W,x, vex4 cpuid(SSE41) p_66), + [0x0e] = X86_OP_ENTRY4(VPBLENDW, V,x, H,x, W,x, vex4 cpuid(SSE41) avx2_256 p_66), + [0x0f] = X86_OP_ENTRY4(PALIGNR, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), + + [0x18] = X86_OP_ENTRY4(VINSERTx128, V,qq, H,qq, W,qq, vex6 cpuid(AVX) p_66), + [0x19] = X86_OP_ENTRY3(VEXTRACTx128, W,dq, V,qq, I,b, vex6 cpuid(AVX) p_66), + + [0x38] = X86_OP_ENTRY4(VINSERTx128, V,qq, H,qq, W,qq, vex6 cpuid(AVX2) p_66), + [0x39] = X86_OP_ENTRY3(VEXTRACTx128, W,dq, V,qq, I,b, vex6 cpuid(AVX2) p_66), + + /* Listed incorrectly as type 4 */ + [0x4a] = X86_OP_ENTRY4(VBLENDVPS, V,x, H,x, W,x, vex6 cpuid(AVX) p_66), + [0x4b] = X86_OP_ENTRY4(VBLENDVPD, V,x, H,x, W,x, vex6 cpuid(AVX) p_66), + [0x4c] = X86_OP_ENTRY4(VPBLENDVB, V,x, H,x, W,x, vex6 cpuid(AVX) p_66 avx2_256), + + [0xdf] = X86_OP_ENTRY3(VAESKEYGEN, V,dq, W,dq, I,b, vex4 cpuid(AES) p_66), + + [0xF0] = X86_OP_ENTRY3(RORX, G,y, E,y, I,b, vex13 cpuid(BMI2) p_f2), +}; + +static void decode_0F3A(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + *b = x86_ldub_code(env, s); + *entry = opcodes_0F3A[*b]; +} + +/* + * There are some mistakes in the operands in the manual, and the load/store/register + * cases are easiest to keep separate, so the entries for 10-17 follow simplicity and + * efficiency of implementation rather than copying what the manual says. + * + * In particular: + * + * 1) "VMOVSS m32, xmm1" and "VMOVSD m64, xmm1" do not support VEX.vvvv != 1111b, + * but this is not mentioned in the tables. + * + * 2) MOVHLPS, MOVHPS, MOVHPD, MOVLPD, MOVLPS read the high quadword of one of their + * operands, which must therefore be dq; MOVLPD and MOVLPS also write the high + * quadword of the V operand. + */ +static void decode_0F10(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F10_reg[4] = { + X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* MOVUPS */ + X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* MOVUPD */ + X86_OP_ENTRY3(VMOVSS, V,x, H,x, W,x, vex4), + X86_OP_ENTRY3(VMOVLPx, V,x, H,x, W,x, vex4), /* MOVSD */ + }; + + static const X86OpEntry opcodes_0F10_mem[4] = { + X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* MOVUPS */ + X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex4_unal), /* MOVUPD */ + X86_OP_ENTRY3(VMOVSS_ld, V,x, H,x, M,ss, vex4), + X86_OP_ENTRY3(VMOVSD_ld, V,x, H,x, M,sd, vex4), + }; + + if ((get_modrm(s, env) >> 6) == 3) { + *entry = *decode_by_prefix(s, opcodes_0F10_reg); + } else { + *entry = *decode_by_prefix(s, opcodes_0F10_mem); + } +} + +static void decode_0F11(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F11_reg[4] = { + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4), /* MOVPS */ + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4), /* MOVPD */ + X86_OP_ENTRY3(VMOVSS, W,x, H,x, V,x, vex4), + X86_OP_ENTRY3(VMOVLPx, W,x, H,x, V,q, vex4), /* MOVSD */ + }; + + static const X86OpEntry opcodes_0F11_mem[4] = { + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4), /* MOVPS */ + X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex4), /* MOVPD */ + X86_OP_ENTRY3(VMOVSS_st, M,ss, None,None, V,x, vex4), + X86_OP_ENTRY3(VMOVLPx_st, M,sd, None,None, V,x, vex4), /* MOVSD */ + }; + + if ((get_modrm(s, env) >> 6) == 3) { + *entry = *decode_by_prefix(s, opcodes_0F11_reg); + } else { + *entry = *decode_by_prefix(s, opcodes_0F11_mem); + } +} + +static void decode_0F12(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F12_mem[4] = { + /* + * Use dq for operand for compatibility with gen_MOVSD and + * to allow VEX128 only. + */ + X86_OP_ENTRY3(VMOVLPx_ld, V,dq, H,dq, M,q, vex4), /* MOVLPS */ + X86_OP_ENTRY3(VMOVLPx_ld, V,dq, H,dq, M,q, vex4), /* MOVLPD */ + X86_OP_ENTRY3(VMOVSLDUP, V,x, None,None, W,x, vex4 cpuid(SSE3)), + X86_OP_ENTRY3(VMOVDDUP, V,x, None,None, WM,q, vex4 cpuid(SSE3)), /* qq if VEX.256 */ + }; + static const X86OpEntry opcodes_0F12_reg[4] = { + X86_OP_ENTRY3(VMOVHLPS, V,dq, H,dq, U,dq, vex4), + X86_OP_ENTRY3(VMOVLPx, W,x, H,x, U,q, vex4), /* MOVLPD */ + X86_OP_ENTRY3(VMOVSLDUP, V,x, None,None, U,x, vex4 cpuid(SSE3)), + X86_OP_ENTRY3(VMOVDDUP, V,x, None,None, U,x, vex4 cpuid(SSE3)), + }; + + if ((get_modrm(s, env) >> 6) == 3) { + *entry = *decode_by_prefix(s, opcodes_0F12_reg); + } else { + *entry = *decode_by_prefix(s, opcodes_0F12_mem); + if ((s->prefix & PREFIX_REPNZ) && s->vex_l) { + entry->s2 = X86_SIZE_qq; + } + } +} + +static void decode_0F16(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F16_mem[4] = { + /* + * Operand 1 technically only reads the low 64 bits, but uses dq so that + * it is easier to check for op0 == op1 in an endianness-neutral manner. + */ + X86_OP_ENTRY3(VMOVHPx_ld, V,dq, H,dq, M,q, vex4), /* MOVHPS */ + X86_OP_ENTRY3(VMOVHPx_ld, V,dq, H,dq, M,q, vex4), /* MOVHPD */ + X86_OP_ENTRY3(VMOVSHDUP, V,x, None,None, W,x, vex4 cpuid(SSE3)), + {}, + }; + static const X86OpEntry opcodes_0F16_reg[4] = { + /* Same as above, operand 1 could be Hq if it wasn't for big-endian. */ + X86_OP_ENTRY3(VMOVLHPS, V,dq, H,dq, U,q, vex4), + X86_OP_ENTRY3(VMOVHPx, V,x, H,x, U,x, vex4), /* MOVHPD */ + X86_OP_ENTRY3(VMOVSHDUP, V,x, None,None, U,x, vex4 cpuid(SSE3)), + {}, + }; + + if ((get_modrm(s, env) >> 6) == 3) { + *entry = *decode_by_prefix(s, opcodes_0F16_reg); + } else { + *entry = *decode_by_prefix(s, opcodes_0F16_mem); + } +} + +static void decode_0F2A(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F2A[4] = { + X86_OP_ENTRY3(CVTPI2Px, V,x, None,None, Q,q), + X86_OP_ENTRY3(CVTPI2Px, V,x, None,None, Q,q), + X86_OP_ENTRY3(VCVTSI2Sx, V,x, H,x, E,y, vex3), + X86_OP_ENTRY3(VCVTSI2Sx, V,x, H,x, E,y, vex3), + }; + *entry = *decode_by_prefix(s, opcodes_0F2A); +} + +static void decode_0F2B(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F2B[4] = { + X86_OP_ENTRY3(MOVDQ, M,x, None,None, V,x, vex4), /* MOVNTPS */ + X86_OP_ENTRY3(MOVDQ, M,x, None,None, V,x, vex4), /* MOVNTPD */ + X86_OP_ENTRY3(VMOVSS_st, M,ss, None,None, V,x, vex4 cpuid(SSE4A)), /* MOVNTSS */ + X86_OP_ENTRY3(VMOVLPx_st, M,sd, None,None, V,x, vex4 cpuid(SSE4A)), /* MOVNTSD */ + }; + + *entry = *decode_by_prefix(s, opcodes_0F2B); +} + +static void decode_0F2C(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F2C[4] = { + /* Listed as ps/pd in the manual, but CVTTPS2PI only reads 64-bit. */ + X86_OP_ENTRY3(CVTTPx2PI, P,q, None,None, W,q), + X86_OP_ENTRY3(CVTTPx2PI, P,q, None,None, W,dq), + X86_OP_ENTRY3(VCVTTSx2SI, G,y, None,None, W,ss, vex3), + X86_OP_ENTRY3(VCVTTSx2SI, G,y, None,None, W,sd, vex3), + }; + *entry = *decode_by_prefix(s, opcodes_0F2C); +} + +static void decode_0F2D(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F2D[4] = { + /* Listed as ps/pd in the manual, but CVTPS2PI only reads 64-bit. */ + X86_OP_ENTRY3(CVTPx2PI, P,q, None,None, W,q), + X86_OP_ENTRY3(CVTPx2PI, P,q, None,None, W,dq), + X86_OP_ENTRY3(VCVTSx2SI, G,y, None,None, W,ss, vex3), + X86_OP_ENTRY3(VCVTSx2SI, G,y, None,None, W,sd, vex3), + }; + *entry = *decode_by_prefix(s, opcodes_0F2D); +} + +static void decode_sse_unary(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + if (!(s->prefix & (PREFIX_REPZ | PREFIX_REPNZ))) { + entry->op1 = X86_TYPE_None; + entry->s1 = X86_SIZE_None; + } + switch (*b) { + case 0x51: entry->gen = gen_VSQRT; break; + case 0x52: entry->gen = gen_VRSQRT; break; + case 0x53: entry->gen = gen_VRCP; break; + case 0x5A: entry->gen = gen_VCVTfp2fp; break; + } +} + +static void decode_0F5B(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0F5B[4] = { + X86_OP_ENTRY2(VCVTDQ2PS, V,x, W,x, vex2), + X86_OP_ENTRY2(VCVTPS2DQ, V,x, W,x, vex2), + X86_OP_ENTRY2(VCVTTPS2DQ, V,x, W,x, vex2), + {}, + }; + *entry = *decode_by_prefix(s, opcodes_0F5B); +} + +static void decode_0FE6(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + static const X86OpEntry opcodes_0FE6[4] = { + {}, + X86_OP_ENTRY2(VCVTTPD2DQ, V,x, W,x, vex2), + X86_OP_ENTRY2(VCVTDQ2PD, V,x, W,x, vex2), + X86_OP_ENTRY2(VCVTPD2DQ, V,x, W,x, vex2), + }; + *entry = *decode_by_prefix(s, opcodes_0FE6); +} + +static const X86OpEntry opcodes_0F[256] = { + [0x0E] = X86_OP_ENTRY0(EMMS, cpuid(3DNOW)), /* femms */ + /* + * 3DNow!'s opcode byte comes *after* modrm and displacements, making it + * more like an Ib operand. Dispatch to the right helper in a single gen_* + * function. + */ + [0x0F] = X86_OP_ENTRY3(3dnow, P,q, Q,q, I,b, cpuid(3DNOW)), + + [0x10] = X86_OP_GROUP0(0F10), + [0x11] = X86_OP_GROUP0(0F11), + [0x12] = X86_OP_GROUP0(0F12), + [0x13] = X86_OP_ENTRY3(VMOVLPx_st, M,q, None,None, V,q, vex4 p_00_66), + [0x14] = X86_OP_ENTRY3(VUNPCKLPx, V,x, H,x, W,x, vex4 p_00_66), + [0x15] = X86_OP_ENTRY3(VUNPCKHPx, V,x, H,x, W,x, vex4 p_00_66), + [0x16] = X86_OP_GROUP0(0F16), + /* Incorrectly listed as Mq,Vq in the manual */ + [0x17] = X86_OP_ENTRY3(VMOVHPx_st, M,q, None,None, V,dq, vex4 p_00_66), + + [0x50] = X86_OP_ENTRY3(MOVMSK, G,y, None,None, U,x, vex7 p_00_66), + [0x51] = X86_OP_GROUP3(sse_unary, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x52] = X86_OP_GROUP3(sse_unary, V,x, H,x, W,x, vex4_rep5 p_00_f3), + [0x53] = X86_OP_GROUP3(sse_unary, V,x, H,x, W,x, vex4_rep5 p_00_f3), + [0x54] = X86_OP_ENTRY3(PAND, V,x, H,x, W,x, vex4 p_00_66), /* vand */ + [0x55] = X86_OP_ENTRY3(PANDN, V,x, H,x, W,x, vex4 p_00_66), /* vandn */ + [0x56] = X86_OP_ENTRY3(POR, V,x, H,x, W,x, vex4 p_00_66), /* vor */ + [0x57] = X86_OP_ENTRY3(PXOR, V,x, H,x, W,x, vex4 p_00_66), /* vxor */ + + [0x60] = X86_OP_ENTRY3(PUNPCKLBW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x61] = X86_OP_ENTRY3(PUNPCKLWD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x62] = X86_OP_ENTRY3(PUNPCKLDQ, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x63] = X86_OP_ENTRY3(PACKSSWB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x64] = X86_OP_ENTRY3(PCMPGTB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x65] = X86_OP_ENTRY3(PCMPGTW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x66] = X86_OP_ENTRY3(PCMPGTD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x67] = X86_OP_ENTRY3(PACKUSWB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + + [0x70] = X86_OP_GROUP0(0F70), + [0x71] = X86_OP_GROUP0(group12), + [0x72] = X86_OP_GROUP0(group13), + [0x73] = X86_OP_GROUP0(group14), + [0x74] = X86_OP_ENTRY3(PCMPEQB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x75] = X86_OP_ENTRY3(PCMPEQW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x76] = X86_OP_ENTRY3(PCMPEQD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x77] = X86_OP_GROUP0(0F77), + + [0x28] = X86_OP_ENTRY3(MOVDQ, V,x, None,None, W,x, vex1 p_00_66), /* MOVAPS */ + [0x29] = X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex1 p_00_66), /* MOVAPS */ + [0x2A] = X86_OP_GROUP0(0F2A), + [0x2B] = X86_OP_GROUP0(0F2B), + [0x2C] = X86_OP_GROUP0(0F2C), + [0x2D] = X86_OP_GROUP0(0F2D), + [0x2E] = X86_OP_ENTRY3(VUCOMI, None,None, V,x, W,x, vex4 p_00_66), + [0x2F] = X86_OP_ENTRY3(VCOMI, None,None, V,x, W,x, vex4 p_00_66), + + [0x38] = X86_OP_GROUP0(0F38), + [0x3a] = X86_OP_GROUP0(0F3A), + + [0x58] = X86_OP_ENTRY3(VADD, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x59] = X86_OP_ENTRY3(VMUL, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x5a] = X86_OP_GROUP3(sse_unary, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x5b] = X86_OP_GROUP0(0F5B), + [0x5c] = X86_OP_ENTRY3(VSUB, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x5d] = X86_OP_ENTRY3(VMIN, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x5e] = X86_OP_ENTRY3(VDIV, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0x5f] = X86_OP_ENTRY3(VMAX, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + + [0x68] = X86_OP_ENTRY3(PUNPCKHBW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x69] = X86_OP_ENTRY3(PUNPCKHWD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x6a] = X86_OP_ENTRY3(PUNPCKHDQ, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x6b] = X86_OP_ENTRY3(PACKSSDW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0x6c] = X86_OP_ENTRY3(PUNPCKLQDQ, V,x, H,x, W,x, vex4 p_66 avx2_256), + [0x6d] = X86_OP_ENTRY3(PUNPCKHQDQ, V,x, H,x, W,x, vex4 p_66 avx2_256), + [0x6e] = X86_OP_ENTRY3(MOVD_to, V,x, None,None, E,y, vex5 mmx p_00_66), /* wrong dest Vy on SDM! */ + [0x6f] = X86_OP_GROUP0(0F6F), + + [0x78] = X86_OP_GROUP0(0F78), + [0x79] = X86_OP_GROUP2(0F79, V,x, U,x, cpuid(SSE4A)), + [0x7c] = X86_OP_ENTRY3(VHADD, V,x, H,x, W,x, vex2 cpuid(SSE3) p_66_f2), + [0x7d] = X86_OP_ENTRY3(VHSUB, V,x, H,x, W,x, vex2 cpuid(SSE3) p_66_f2), + [0x7e] = X86_OP_GROUP0(0F7E), + [0x7f] = X86_OP_GROUP0(0F7F), + + [0xae] = X86_OP_GROUP0(group15), + + [0xc2] = X86_OP_ENTRY4(VCMP, V,x, H,x, W,x, vex2_rep3 p_00_66_f3_f2), + [0xc4] = X86_OP_ENTRY4(PINSRW, V,dq,H,dq,E,w, vex5 mmx p_00_66), + [0xc5] = X86_OP_ENTRY3(PEXTRW, G,d, U,dq,I,b, vex5 mmx p_00_66), + [0xc6] = X86_OP_ENTRY4(VSHUF, V,x, H,x, W,x, vex4 p_00_66), + + [0xd0] = X86_OP_ENTRY3(VADDSUB, V,x, H,x, W,x, vex2 cpuid(SSE3) p_66_f2), + [0xd1] = X86_OP_ENTRY3(PSRLW_r, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xd2] = X86_OP_ENTRY3(PSRLD_r, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xd3] = X86_OP_ENTRY3(PSRLQ_r, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xd4] = X86_OP_ENTRY3(PADDQ, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xd5] = X86_OP_ENTRY3(PMULLW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xd6] = X86_OP_GROUP0(0FD6), + [0xd7] = X86_OP_ENTRY3(PMOVMSKB, G,d, None,None, U,x, vex7 mmx avx2_256 p_00_66), + + [0xe0] = X86_OP_ENTRY3(PAVGB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xe1] = X86_OP_ENTRY3(PSRAW_r, V,x, H,x, W,x, vex7 mmx avx2_256 p_00_66), + [0xe2] = X86_OP_ENTRY3(PSRAD_r, V,x, H,x, W,x, vex7 mmx avx2_256 p_00_66), + [0xe3] = X86_OP_ENTRY3(PAVGW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xe4] = X86_OP_ENTRY3(PMULHUW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xe5] = X86_OP_ENTRY3(PMULHW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xe6] = X86_OP_GROUP0(0FE6), + [0xe7] = X86_OP_ENTRY3(MOVDQ, W,x, None,None, V,x, vex1 mmx p_00_66), /* MOVNTQ/MOVNTDQ */ + + [0xf0] = X86_OP_ENTRY3(MOVDQ, V,x, None,None, WM,x, vex4_unal cpuid(SSE3) p_f2), /* LDDQU */ + [0xf1] = X86_OP_ENTRY3(PSLLW_r, V,x, H,x, W,x, vex7 mmx avx2_256 p_00_66), + [0xf2] = X86_OP_ENTRY3(PSLLD_r, V,x, H,x, W,x, vex7 mmx avx2_256 p_00_66), + [0xf3] = X86_OP_ENTRY3(PSLLQ_r, V,x, H,x, W,x, vex7 mmx avx2_256 p_00_66), + [0xf4] = X86_OP_ENTRY3(PMULUDQ, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xf5] = X86_OP_ENTRY3(PMADDWD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xf6] = X86_OP_ENTRY3(PSADBW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xf7] = X86_OP_ENTRY3(MASKMOV, None,None, V,dq, U,dq, vex4_unal avx2_256 mmx p_00_66), + + /* Incorrectly missing from 2-17 */ + [0xd8] = X86_OP_ENTRY3(PSUBUSB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xd9] = X86_OP_ENTRY3(PSUBUSW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xda] = X86_OP_ENTRY3(PMINUB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xdb] = X86_OP_ENTRY3(PAND, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xdc] = X86_OP_ENTRY3(PADDUSB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xdd] = X86_OP_ENTRY3(PADDUSW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xde] = X86_OP_ENTRY3(PMAXUB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xdf] = X86_OP_ENTRY3(PANDN, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + + [0xe8] = X86_OP_ENTRY3(PSUBSB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xe9] = X86_OP_ENTRY3(PSUBSW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xea] = X86_OP_ENTRY3(PMINSW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xeb] = X86_OP_ENTRY3(POR, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xec] = X86_OP_ENTRY3(PADDSB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xed] = X86_OP_ENTRY3(PADDSW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xee] = X86_OP_ENTRY3(PMAXSW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xef] = X86_OP_ENTRY3(PXOR, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + + [0xf8] = X86_OP_ENTRY3(PSUBB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xf9] = X86_OP_ENTRY3(PSUBW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xfa] = X86_OP_ENTRY3(PSUBD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xfb] = X86_OP_ENTRY3(PSUBQ, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xfc] = X86_OP_ENTRY3(PADDB, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xfd] = X86_OP_ENTRY3(PADDW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + [0xfe] = X86_OP_ENTRY3(PADDD, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66), + /* 0xff = UD0 */ +}; + +static void do_decode_0F(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + *entry = opcodes_0F[*b]; +} + +static void decode_0F(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + *b = x86_ldub_code(env, s); + do_decode_0F(s, env, entry, b); +} + +static const X86OpEntry opcodes_root[256] = { + [0x0F] = X86_OP_GROUP0(0F), +}; + +#undef mmx +#undef vex1 +#undef vex2 +#undef vex3 +#undef vex4 +#undef vex4_unal +#undef vex5 +#undef vex6 +#undef vex7 +#undef vex8 +#undef vex11 +#undef vex12 +#undef vex13 + +/* + * Decode the fixed part of the opcode and place the last + * in b. + */ +static void decode_root(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + *entry = opcodes_root[*b]; +} + + +static int decode_modrm(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + X86DecodedOp *op, X86OpType type) +{ + int modrm = get_modrm(s, env); + if ((modrm >> 6) == 3) { + if (s->prefix & PREFIX_LOCK) { + decode->e.gen = gen_illegal; + return 0xff; + } + op->n = (modrm & 7); + if (type != X86_TYPE_Q && type != X86_TYPE_N) { + op->n |= REX_B(s); + } + } else { + op->has_ea = true; + op->n = -1; + decode->mem = gen_lea_modrm_0(env, s, get_modrm(s, env)); + } + return modrm; +} + +static bool decode_op_size(DisasContext *s, X86OpEntry *e, X86OpSize size, MemOp *ot) +{ + switch (size) { + case X86_SIZE_b: /* byte */ + *ot = MO_8; + return true; + + case X86_SIZE_d: /* 32-bit */ + case X86_SIZE_ss: /* SSE/AVX scalar single precision */ + *ot = MO_32; + return true; + + case X86_SIZE_p: /* Far pointer, return offset size */ + case X86_SIZE_s: /* Descriptor, return offset size */ + case X86_SIZE_v: /* 16/32/64-bit, based on operand size */ + *ot = s->dflag; + return true; + + case X86_SIZE_pi: /* MMX */ + case X86_SIZE_q: /* 64-bit */ + case X86_SIZE_sd: /* SSE/AVX scalar double precision */ + *ot = MO_64; + return true; + + case X86_SIZE_w: /* 16-bit */ + *ot = MO_16; + return true; + + case X86_SIZE_y: /* 32/64-bit, based on operand size */ + *ot = s->dflag == MO_16 ? MO_32 : s->dflag; + return true; + + case X86_SIZE_z: /* 16-bit for 16-bit operand size, else 32-bit */ + *ot = s->dflag == MO_16 ? MO_16 : MO_32; + return true; + + case X86_SIZE_dq: /* SSE/AVX 128-bit */ + if (e->special == X86_SPECIAL_MMX && + !(s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) { + *ot = MO_64; + return true; + } + if (s->vex_l && e->s0 != X86_SIZE_qq && e->s1 != X86_SIZE_qq) { + return false; + } + *ot = MO_128; + return true; + + case X86_SIZE_qq: /* AVX 256-bit */ + if (!s->vex_l) { + return false; + } + *ot = MO_256; + return true; + + case X86_SIZE_x: /* 128/256-bit, based on operand size */ + if (e->special == X86_SPECIAL_MMX && + !(s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) { + *ot = MO_64; + return true; + } + /* fall through */ + case X86_SIZE_ps: /* SSE/AVX packed single precision */ + case X86_SIZE_pd: /* SSE/AVX packed double precision */ + *ot = s->vex_l ? MO_256 : MO_128; + return true; + + case X86_SIZE_ph: /* SSE/AVX packed half precision */ + *ot = s->vex_l ? MO_128 : MO_64; + return true; + + case X86_SIZE_d64: /* Default to 64-bit in 64-bit mode */ + *ot = CODE64(s) && s->dflag == MO_32 ? MO_64 : s->dflag; + return true; + + case X86_SIZE_f64: /* Ignore size override prefix in 64-bit mode */ + *ot = CODE64(s) ? MO_64 : s->dflag; + return true; + + default: + *ot = -1; + return true; + } +} + +static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + X86DecodedOp *op, X86OpType type, int b) +{ + int modrm; + + switch (type) { + case X86_TYPE_None: /* Implicit or absent */ + case X86_TYPE_A: /* Implicit */ + case X86_TYPE_F: /* EFLAGS/RFLAGS */ + break; + + case X86_TYPE_B: /* VEX.vvvv selects a GPR */ + op->unit = X86_OP_INT; + op->n = s->vex_v; + break; + + case X86_TYPE_C: /* REG in the modrm byte selects a control register */ + op->unit = X86_OP_CR; + goto get_reg; + + case X86_TYPE_D: /* REG in the modrm byte selects a debug register */ + op->unit = X86_OP_DR; + goto get_reg; + + case X86_TYPE_G: /* REG in the modrm byte selects a GPR */ + op->unit = X86_OP_INT; + goto get_reg; + + case X86_TYPE_S: /* reg selects a segment register */ + op->unit = X86_OP_SEG; + goto get_reg; + + case X86_TYPE_P: + op->unit = X86_OP_MMX; + goto get_reg; + + case X86_TYPE_V: /* reg in the modrm byte selects an XMM/YMM register */ + if (decode->e.special == X86_SPECIAL_MMX && + !(s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) { + op->unit = X86_OP_MMX; + } else { + op->unit = X86_OP_SSE; + } + get_reg: + op->n = ((get_modrm(s, env) >> 3) & 7) | REX_R(s); + break; + + case X86_TYPE_E: /* ALU modrm operand */ + op->unit = X86_OP_INT; + goto get_modrm; + + case X86_TYPE_Q: /* MMX modrm operand */ + op->unit = X86_OP_MMX; + goto get_modrm; + + case X86_TYPE_W: /* XMM/YMM modrm operand */ + if (decode->e.special == X86_SPECIAL_MMX && + !(s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) { + op->unit = X86_OP_MMX; + } else { + op->unit = X86_OP_SSE; + } + goto get_modrm; + + case X86_TYPE_N: /* R/M in the modrm byte selects an MMX register */ + op->unit = X86_OP_MMX; + goto get_modrm_reg; + + case X86_TYPE_U: /* R/M in the modrm byte selects an XMM/YMM register */ + if (decode->e.special == X86_SPECIAL_MMX && + !(s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) { + op->unit = X86_OP_MMX; + } else { + op->unit = X86_OP_SSE; + } + goto get_modrm_reg; + + case X86_TYPE_R: /* R/M in the modrm byte selects a register */ + op->unit = X86_OP_INT; + get_modrm_reg: + modrm = get_modrm(s, env); + if ((modrm >> 6) != 3) { + return false; + } + goto get_modrm; + + case X86_TYPE_WM: /* modrm byte selects an XMM/YMM memory operand */ + op->unit = X86_OP_SSE; + /* fall through */ + case X86_TYPE_M: /* modrm byte selects a memory operand */ + modrm = get_modrm(s, env); + if ((modrm >> 6) == 3) { + return false; + } + get_modrm: + decode_modrm(s, env, decode, op, type); + break; + + case X86_TYPE_O: /* Absolute address encoded in the instruction */ + op->unit = X86_OP_INT; + op->has_ea = true; + op->n = -1; + decode->mem = (AddressParts) { + .def_seg = R_DS, + .base = -1, + .index = -1, + .disp = insn_get_addr(env, s, s->aflag) + }; + break; + + case X86_TYPE_H: /* For AVX, VEX.vvvv selects an XMM/YMM register */ + if ((s->prefix & PREFIX_VEX)) { + op->unit = X86_OP_SSE; + op->n = s->vex_v; + break; + } + if (op == &decode->op[0]) { + /* shifts place the destination in VEX.vvvv, use modrm */ + return decode_op(s, env, decode, op, decode->e.op1, b); + } else { + return decode_op(s, env, decode, op, decode->e.op0, b); + } + + case X86_TYPE_I: /* Immediate */ + op->unit = X86_OP_IMM; + decode->immediate = insn_get_signed(env, s, op->ot); + break; + + case X86_TYPE_J: /* Relative offset for a jump */ + op->unit = X86_OP_IMM; + decode->immediate = insn_get_signed(env, s, op->ot); + decode->immediate += s->pc - s->cs_base; + if (s->dflag == MO_16) { + decode->immediate &= 0xffff; + } else if (!CODE64(s)) { + decode->immediate &= 0xffffffffu; + } + break; + + case X86_TYPE_L: /* The upper 4 bits of the immediate select a 128-bit register */ + op->n = insn_get(env, s, op->ot) >> 4; + break; + + case X86_TYPE_X: /* string source */ + op->n = -1; + decode->mem = (AddressParts) { + .def_seg = R_DS, + .base = R_ESI, + .index = -1, + }; + break; + + case X86_TYPE_Y: /* string destination */ + op->n = -1; + decode->mem = (AddressParts) { + .def_seg = R_ES, + .base = R_EDI, + .index = -1, + }; + break; + + case X86_TYPE_2op: + *op = decode->op[0]; + break; + + case X86_TYPE_LoBits: + op->n = (b & 7) | REX_B(s); + op->unit = X86_OP_INT; + break; + + case X86_TYPE_0 ... X86_TYPE_7: + op->n = type - X86_TYPE_0; + op->unit = X86_OP_INT; + break; + + case X86_TYPE_ES ... X86_TYPE_GS: + op->n = type - X86_TYPE_ES; + op->unit = X86_OP_SEG; + break; + } + + return true; +} + +static bool validate_sse_prefix(DisasContext *s, X86OpEntry *e) +{ + uint16_t sse_prefixes; + + if (!e->valid_prefix) { + return true; + } + if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) { + /* In SSE instructions, 0xF3 and 0xF2 cancel 0x66. */ + s->prefix &= ~PREFIX_DATA; + } + + /* Now, either zero or one bit is set in sse_prefixes. */ + sse_prefixes = s->prefix & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA); + return e->valid_prefix & (1 << sse_prefixes); +} + +static bool decode_insn(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_func, + X86DecodedInsn *decode) +{ + X86OpEntry *e = &decode->e; + + decode_func(s, env, e, &decode->b); + while (e->is_decode) { + e->is_decode = false; + e->decode(s, env, e, &decode->b); + } + + if (!validate_sse_prefix(s, e)) { + return false; + } + + /* First compute size of operands in order to initialize s->rip_offset. */ + if (e->op0 != X86_TYPE_None) { + if (!decode_op_size(s, e, e->s0, &decode->op[0].ot)) { + return false; + } + if (e->op0 == X86_TYPE_I) { + s->rip_offset += 1 << decode->op[0].ot; + } + } + if (e->op1 != X86_TYPE_None) { + if (!decode_op_size(s, e, e->s1, &decode->op[1].ot)) { + return false; + } + if (e->op1 == X86_TYPE_I) { + s->rip_offset += 1 << decode->op[1].ot; + } + } + if (e->op2 != X86_TYPE_None) { + if (!decode_op_size(s, e, e->s2, &decode->op[2].ot)) { + return false; + } + if (e->op2 == X86_TYPE_I) { + s->rip_offset += 1 << decode->op[2].ot; + } + } + if (e->op3 != X86_TYPE_None) { + /* + * A couple instructions actually use the extra immediate byte for an Lx + * register operand; those are handled in the gen_* functions as one off. + */ + assert(e->op3 == X86_TYPE_I && e->s3 == X86_SIZE_b); + s->rip_offset += 1; + } + + if (e->op0 != X86_TYPE_None && + !decode_op(s, env, decode, &decode->op[0], e->op0, decode->b)) { + return false; + } + + if (e->op1 != X86_TYPE_None && + !decode_op(s, env, decode, &decode->op[1], e->op1, decode->b)) { + return false; + } + + if (e->op2 != X86_TYPE_None && + !decode_op(s, env, decode, &decode->op[2], e->op2, decode->b)) { + return false; + } + + if (e->op3 != X86_TYPE_None) { + decode->immediate = insn_get_signed(env, s, MO_8); + } + + return true; +} + +static bool has_cpuid_feature(DisasContext *s, X86CPUIDFeature cpuid) +{ + switch (cpuid) { + case X86_FEAT_None: + return true; + case X86_FEAT_F16C: + return (s->cpuid_ext_features & CPUID_EXT_F16C); + case X86_FEAT_FMA: + return (s->cpuid_ext_features & CPUID_EXT_FMA); + case X86_FEAT_MOVBE: + return (s->cpuid_ext_features & CPUID_EXT_MOVBE); + case X86_FEAT_PCLMULQDQ: + return (s->cpuid_ext_features & CPUID_EXT_PCLMULQDQ); + case X86_FEAT_SSE: + return (s->cpuid_ext_features & CPUID_SSE); + case X86_FEAT_SSE2: + return (s->cpuid_ext_features & CPUID_SSE2); + case X86_FEAT_SSE3: + return (s->cpuid_ext_features & CPUID_EXT_SSE3); + case X86_FEAT_SSSE3: + return (s->cpuid_ext_features & CPUID_EXT_SSSE3); + case X86_FEAT_SSE41: + return (s->cpuid_ext_features & CPUID_EXT_SSE41); + case X86_FEAT_SSE42: + return (s->cpuid_ext_features & CPUID_EXT_SSE42); + case X86_FEAT_AES: + if (!(s->cpuid_ext_features & CPUID_EXT_AES)) { + return false; + } else if (!(s->prefix & PREFIX_VEX)) { + return true; + } else if (!(s->cpuid_ext_features & CPUID_EXT_AVX)) { + return false; + } else { + return !s->vex_l || (s->cpuid_7_0_ecx_features & CPUID_7_0_ECX_VAES); + } + + case X86_FEAT_AVX: + return (s->cpuid_ext_features & CPUID_EXT_AVX); + + case X86_FEAT_3DNOW: + return (s->cpuid_ext2_features & CPUID_EXT2_3DNOW); + case X86_FEAT_SSE4A: + return (s->cpuid_ext3_features & CPUID_EXT3_SSE4A); + + case X86_FEAT_ADX: + return (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX); + case X86_FEAT_BMI1: + return (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1); + case X86_FEAT_BMI2: + return (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2); + case X86_FEAT_AVX2: + return (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_AVX2); + } + g_assert_not_reached(); +} + +static bool validate_vex(DisasContext *s, X86DecodedInsn *decode) +{ + X86OpEntry *e = &decode->e; + + switch (e->vex_special) { + case X86_VEX_REPScalar: + /* + * Instructions which differ between 00/66 and F2/F3 in the + * exception classification and the size of the memory operand. + */ + assert(e->vex_class == 1 || e->vex_class == 2 || e->vex_class == 4); + if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) { + e->vex_class = e->vex_class < 4 ? 3 : 5; + if (s->vex_l) { + goto illegal; + } + assert(decode->e.s2 == X86_SIZE_x); + if (decode->op[2].has_ea) { + decode->op[2].ot = s->prefix & PREFIX_REPZ ? MO_32 : MO_64; + } + } + break; + + case X86_VEX_SSEUnaligned: + /* handled in sse_needs_alignment. */ + break; + + case X86_VEX_AVX2_256: + if ((s->prefix & PREFIX_VEX) && s->vex_l && !has_cpuid_feature(s, X86_FEAT_AVX2)) { + goto illegal; + } + } + + /* TODO: instructions that require VEX.W=0 (Table 2-16) */ + + switch (e->vex_class) { + case 0: + if (s->prefix & PREFIX_VEX) { + goto illegal; + } + return true; + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + if (s->prefix & PREFIX_VEX) { + if (!(s->flags & HF_AVX_EN_MASK)) { + goto illegal; + } + } else if (e->special != X86_SPECIAL_MMX || + (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA))) { + if (!(s->flags & HF_OSFXSR_MASK)) { + goto illegal; + } + } + break; + case 12: + /* Must have a VSIB byte and no address prefix. */ + assert(s->has_modrm); + if ((s->modrm & 7) != 4 || s->aflag == MO_16) { + goto illegal; + } + + /* Check no overlap between registers. */ + if (!decode->op[0].has_ea && + (decode->op[0].n == decode->mem.index || decode->op[0].n == decode->op[1].n)) { + goto illegal; + } + assert(!decode->op[1].has_ea); + if (decode->op[1].n == decode->mem.index) { + goto illegal; + } + if (!decode->op[2].has_ea && + (decode->op[2].n == decode->mem.index || decode->op[2].n == decode->op[1].n)) { + goto illegal; + } + /* fall through */ + case 6: + case 11: + if (!(s->prefix & PREFIX_VEX)) { + goto illegal; + } + if (!(s->flags & HF_AVX_EN_MASK)) { + goto illegal; + } + break; + case 8: + /* Non-VEX case handled in decode_0F77. */ + assert(s->prefix & PREFIX_VEX); + if (!(s->flags & HF_AVX_EN_MASK)) { + goto illegal; + } + break; + case 13: + if (!(s->prefix & PREFIX_VEX)) { + goto illegal; + } + if (s->vex_l) { + goto illegal; + } + /* All integer instructions use VEX.vvvv, so exit. */ + return true; + } + + if (s->vex_v != 0 && + e->op0 != X86_TYPE_H && e->op0 != X86_TYPE_B && + e->op1 != X86_TYPE_H && e->op1 != X86_TYPE_B && + e->op2 != X86_TYPE_H && e->op2 != X86_TYPE_B) { + goto illegal; + } + + if (s->flags & HF_TS_MASK) { + goto nm_exception; + } + if (s->flags & HF_EM_MASK) { + goto illegal; + } + return true; + +nm_exception: + gen_NM_exception(s); + return false; +illegal: + gen_illegal_opcode(s); + return false; +} + +static void decode_temp_free(X86DecodedOp *op) +{ + if (op->v_ptr) { + tcg_temp_free_ptr(op->v_ptr); + } +} + +static void decode_temps_free(X86DecodedInsn *decode) +{ + decode_temp_free(&decode->op[0]); + decode_temp_free(&decode->op[1]); + decode_temp_free(&decode->op[2]); +} + +/* + * Convert one instruction. s->base.is_jmp is set if the translation must + * be stopped. + */ +static void disas_insn_new(DisasContext *s, CPUState *cpu, int b) +{ + CPUX86State *env = cpu->env_ptr; + bool first = true; + X86DecodedInsn decode; + X86DecodeFunc decode_func = decode_root; + + s->has_modrm = false; + + next_byte: + if (first) { + first = false; + } else { + b = x86_ldub_code(env, s); + } + /* Collect prefixes. */ + switch (b) { + case 0xf3: + s->prefix |= PREFIX_REPZ; + s->prefix &= ~PREFIX_REPNZ; + goto next_byte; + case 0xf2: + s->prefix |= PREFIX_REPNZ; + s->prefix &= ~PREFIX_REPZ; + goto next_byte; + case 0xf0: + s->prefix |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + s->prefix |= PREFIX_DATA; + goto next_byte; + case 0x67: + s->prefix |= PREFIX_ADR; + goto next_byte; +#ifdef TARGET_X86_64 + case 0x40 ... 0x4f: + if (CODE64(s)) { + /* REX prefix */ + s->prefix |= PREFIX_REX; + s->vex_w = (b >> 3) & 1; + s->rex_r = (b & 0x4) << 1; + s->rex_x = (b & 0x2) << 2; + s->rex_b = (b & 0x1) << 3; + goto next_byte; + } + break; +#endif + case 0xc5: /* 2-byte VEX */ + case 0xc4: /* 3-byte VEX */ + /* + * VEX prefixes cannot be used except in 32-bit mode. + * Otherwise the instruction is LES or LDS. + */ + if (CODE32(s) && !VM86(s)) { + static const int pp_prefix[4] = { + 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ + }; + int vex3, vex2 = x86_ldub_code(env, s); + + if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) { + /* + * 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b, + * otherwise the instruction is LES or LDS. + */ + s->pc--; /* rewind the advance_pc() x86_ldub_code() did */ + break; + } + + /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */ + if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ + | PREFIX_LOCK | PREFIX_DATA | PREFIX_REX)) { + goto illegal_op; + } +#ifdef TARGET_X86_64 + s->rex_r = (~vex2 >> 4) & 8; +#endif + if (b == 0xc5) { + /* 2-byte VEX prefix: RVVVVlpp, implied 0f leading opcode byte */ + vex3 = vex2; + decode_func = decode_0F; + } else { + /* 3-byte VEX prefix: RXBmmmmm wVVVVlpp */ + vex3 = x86_ldub_code(env, s); +#ifdef TARGET_X86_64 + s->rex_x = (~vex2 >> 3) & 8; + s->rex_b = (~vex2 >> 2) & 8; +#endif + s->vex_w = (vex3 >> 7) & 1; + switch (vex2 & 0x1f) { + case 0x01: /* Implied 0f leading opcode bytes. */ + decode_func = decode_0F; + break; + case 0x02: /* Implied 0f 38 leading opcode bytes. */ + decode_func = decode_0F38; + break; + case 0x03: /* Implied 0f 3a leading opcode bytes. */ + decode_func = decode_0F3A; + break; + default: /* Reserved for future use. */ + goto unknown_op; + } + } + s->vex_v = (~vex3 >> 3) & 0xf; + s->vex_l = (vex3 >> 2) & 1; + s->prefix |= pp_prefix[vex3 & 3] | PREFIX_VEX; + } + break; + default: + if (b >= 0x100) { + b -= 0x100; + decode_func = do_decode_0F; + } + break; + } + + /* Post-process prefixes. */ + if (CODE64(s)) { + /* + * In 64-bit mode, the default data size is 32-bit. Select 64-bit + * data with rex_w, and 16-bit data with 0x66; rex_w takes precedence + * over 0x66 if both are present. + */ + s->dflag = (REX_W(s) ? MO_64 : s->prefix & PREFIX_DATA ? MO_16 : MO_32); + /* In 64-bit mode, 0x67 selects 32-bit addressing. */ + s->aflag = (s->prefix & PREFIX_ADR ? MO_32 : MO_64); + } else { + /* In 16/32-bit mode, 0x66 selects the opposite data size. */ + if (CODE32(s) ^ ((s->prefix & PREFIX_DATA) != 0)) { + s->dflag = MO_32; + } else { + s->dflag = MO_16; + } + /* In 16/32-bit mode, 0x67 selects the opposite addressing. */ + if (CODE32(s) ^ ((s->prefix & PREFIX_ADR) != 0)) { + s->aflag = MO_32; + } else { + s->aflag = MO_16; + } + } + + memset(&decode, 0, sizeof(decode)); + decode.b = b; + if (!decode_insn(s, env, decode_func, &decode)) { + goto illegal_op; + } + if (!decode.e.gen) { + goto unknown_op; + } + + if (!has_cpuid_feature(s, decode.e.cpuid)) { + goto illegal_op; + } + + switch (decode.e.special) { + case X86_SPECIAL_None: + break; + + case X86_SPECIAL_Locked: + if (decode.op[0].has_ea) { + s->prefix |= PREFIX_LOCK; + } + break; + + case X86_SPECIAL_ProtMode: + if (!PE(s) || VM86(s)) { + goto illegal_op; + } + break; + + case X86_SPECIAL_i64: + if (CODE64(s)) { + goto illegal_op; + } + break; + case X86_SPECIAL_o64: + if (!CODE64(s)) { + goto illegal_op; + } + break; + + case X86_SPECIAL_ZExtOp0: + assert(decode.op[0].unit == X86_OP_INT); + if (!decode.op[0].has_ea) { + decode.op[0].ot = MO_32; + } + break; + + case X86_SPECIAL_ZExtOp2: + assert(decode.op[2].unit == X86_OP_INT); + if (!decode.op[2].has_ea) { + decode.op[2].ot = MO_32; + } + break; + + case X86_SPECIAL_AVXExtMov: + if (!decode.op[2].has_ea) { + decode.op[2].ot = s->vex_l ? MO_256 : MO_128; + } else if (s->vex_l) { + decode.op[2].ot++; + } + break; + + case X86_SPECIAL_MMX: + if (!(s->prefix & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA))) { + gen_helper_enter_mmx(cpu_env); + } + break; + } + + if (!validate_vex(s, &decode)) { + return; + } + if (decode.op[0].has_ea || decode.op[1].has_ea || decode.op[2].has_ea) { + gen_load_ea(s, &decode.mem, decode.e.vex_class == 12); + } + if (s->prefix & PREFIX_LOCK) { + if (decode.op[0].unit != X86_OP_INT || !decode.op[0].has_ea) { + goto illegal_op; + } + gen_load(s, &decode, 2, s->T1); + decode.e.gen(s, env, &decode); + } else { + if (decode.op[0].unit == X86_OP_MMX) { + compute_mmx_offset(&decode.op[0]); + } else if (decode.op[0].unit == X86_OP_SSE) { + compute_xmm_offset(&decode.op[0]); + } + gen_load(s, &decode, 1, s->T0); + gen_load(s, &decode, 2, s->T1); + decode.e.gen(s, env, &decode); + gen_writeback(s, &decode, 0, s->T0); + } + decode_temps_free(&decode); + return; + illegal_op: + gen_illegal_opcode(s); + return; + unknown_op: + gen_unknown_opcode(env, s); +} diff --git a/target/i386/tcg/decode-new.h b/target/i386/tcg/decode-new.h new file mode 100644 index 000000000000..cb6b8bcf678c --- /dev/null +++ b/target/i386/tcg/decode-new.h @@ -0,0 +1,252 @@ +/* + * Decode table flags, mostly based on Intel SDM. + * + * Copyright (c) 2022 Red Hat, Inc. + * + * Author: Paolo Bonzini + * + * 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 . + */ + +typedef enum X86OpType { + X86_TYPE_None, + + X86_TYPE_A, /* Implicit */ + X86_TYPE_B, /* VEX.vvvv selects a GPR */ + X86_TYPE_C, /* REG in the modrm byte selects a control register */ + X86_TYPE_D, /* REG in the modrm byte selects a debug register */ + X86_TYPE_E, /* ALU modrm operand */ + X86_TYPE_F, /* EFLAGS/RFLAGS */ + X86_TYPE_G, /* REG in the modrm byte selects a GPR */ + X86_TYPE_H, /* For AVX, VEX.vvvv selects an XMM/YMM register */ + X86_TYPE_I, /* Immediate */ + X86_TYPE_J, /* Relative offset for a jump */ + X86_TYPE_L, /* The upper 4 bits of the immediate select a 128-bit register */ + X86_TYPE_M, /* modrm byte selects a memory operand */ + X86_TYPE_N, /* R/M in the modrm byte selects an MMX register */ + X86_TYPE_O, /* Absolute address encoded in the instruction */ + X86_TYPE_P, /* reg in the modrm byte selects an MMX register */ + X86_TYPE_Q, /* MMX modrm operand */ + X86_TYPE_R, /* R/M in the modrm byte selects a register */ + X86_TYPE_S, /* reg selects a segment register */ + X86_TYPE_U, /* R/M in the modrm byte selects an XMM/YMM register */ + X86_TYPE_V, /* reg in the modrm byte selects an XMM/YMM register */ + X86_TYPE_W, /* XMM/YMM modrm operand */ + X86_TYPE_X, /* string source */ + X86_TYPE_Y, /* string destination */ + + /* Custom */ + X86_TYPE_WM, /* modrm byte selects an XMM/YMM memory operand */ + X86_TYPE_2op, /* 2-operand RMW instruction */ + X86_TYPE_LoBits, /* encoded in bits 0-2 of the operand + REX.B */ + X86_TYPE_0, /* Hard-coded GPRs (RAX..RDI) */ + X86_TYPE_1, + X86_TYPE_2, + X86_TYPE_3, + X86_TYPE_4, + X86_TYPE_5, + X86_TYPE_6, + X86_TYPE_7, + X86_TYPE_ES, /* Hard-coded segment registers */ + X86_TYPE_CS, + X86_TYPE_SS, + X86_TYPE_DS, + X86_TYPE_FS, + X86_TYPE_GS, +} X86OpType; + +typedef enum X86OpSize { + X86_SIZE_None, + + X86_SIZE_a, /* BOUND operand */ + X86_SIZE_b, /* byte */ + X86_SIZE_d, /* 32-bit */ + X86_SIZE_dq, /* SSE/AVX 128-bit */ + X86_SIZE_p, /* Far pointer */ + X86_SIZE_pd, /* SSE/AVX packed double precision */ + X86_SIZE_pi, /* MMX */ + X86_SIZE_ps, /* SSE/AVX packed single precision */ + X86_SIZE_q, /* 64-bit */ + X86_SIZE_qq, /* AVX 256-bit */ + X86_SIZE_s, /* Descriptor */ + X86_SIZE_sd, /* SSE/AVX scalar double precision */ + X86_SIZE_ss, /* SSE/AVX scalar single precision */ + X86_SIZE_si, /* 32-bit GPR */ + X86_SIZE_v, /* 16/32/64-bit, based on operand size */ + X86_SIZE_w, /* 16-bit */ + X86_SIZE_x, /* 128/256-bit, based on operand size */ + X86_SIZE_y, /* 32/64-bit, based on operand size */ + X86_SIZE_z, /* 16-bit for 16-bit operand size, else 32-bit */ + + /* Custom */ + X86_SIZE_d64, + X86_SIZE_f64, + X86_SIZE_ph, /* SSE/AVX packed half precision */ +} X86OpSize; + +typedef enum X86CPUIDFeature { + X86_FEAT_None, + X86_FEAT_3DNOW, + X86_FEAT_ADX, + X86_FEAT_AES, + X86_FEAT_AVX, + X86_FEAT_AVX2, + X86_FEAT_BMI1, + X86_FEAT_BMI2, + X86_FEAT_F16C, + X86_FEAT_FMA, + X86_FEAT_MOVBE, + X86_FEAT_PCLMULQDQ, + X86_FEAT_SSE, + X86_FEAT_SSE2, + X86_FEAT_SSE3, + X86_FEAT_SSSE3, + X86_FEAT_SSE41, + X86_FEAT_SSE42, + X86_FEAT_SSE4A, +} X86CPUIDFeature; + +/* Execution flags */ + +typedef enum X86OpUnit { + X86_OP_SKIP, /* not valid or managed by emission function */ + X86_OP_SEG, /* segment selector */ + X86_OP_CR, /* control register */ + X86_OP_DR, /* debug register */ + X86_OP_INT, /* loaded into/stored from s->T0/T1 */ + X86_OP_IMM, /* immediate */ + X86_OP_SSE, /* address in either s->ptrX or s->A0 depending on has_ea */ + X86_OP_MMX, /* address in either s->ptrX or s->A0 depending on has_ea */ +} X86OpUnit; + +typedef enum X86InsnSpecial { + X86_SPECIAL_None, + + /* Always locked if it has a memory operand (XCHG) */ + X86_SPECIAL_Locked, + + /* Fault outside protected mode */ + X86_SPECIAL_ProtMode, + + /* + * Register operand 0/2 is zero extended to 32 bits. Rd/Mb or Rd/Mw + * in the manual. + */ + X86_SPECIAL_ZExtOp0, + X86_SPECIAL_ZExtOp2, + + /* + * Register operand 2 is extended to full width, while a memory operand + * is doubled in size if VEX.L=1. + */ + X86_SPECIAL_AVXExtMov, + + /* + * MMX instruction exists with no prefix; if there is no prefix, V/H/W/U operands + * become P/P/Q/N, and size "x" becomes "q". + */ + X86_SPECIAL_MMX, + + /* Illegal or exclusive to 64-bit mode */ + X86_SPECIAL_i64, + X86_SPECIAL_o64, +} X86InsnSpecial; + +/* + * Special cases for instructions that operate on XMM/YMM registers. Intel + * retconned all of them to have VEX exception classes other than 0 and 13, so + * all these only matter for instructions that have a VEX exception class. + * Based on tables in the "AVX and SSE Instruction Exception Specification" + * section of the manual. + */ +typedef enum X86VEXSpecial { + /* Legacy SSE instructions that allow unaligned operands */ + X86_VEX_SSEUnaligned, + + /* + * Used for instructions that distinguish the XMM operand type with an + * instruction prefix; legacy SSE encodings will allow unaligned operands + * for scalar operands only (identified by a REP prefix). In this case, + * the decoding table uses "x" for the vector operands instead of specifying + * pd/ps/sd/ss individually. + */ + X86_VEX_REPScalar, + + /* + * VEX instructions that only support 256-bit operands with AVX2 (Table 2-17 + * column 3). Columns 2 and 4 (instructions limited to 256- and 127-bit + * operands respectively) are implicit in the presence of dq and qq + * operands, and thus handled by decode_op_size. + */ + X86_VEX_AVX2_256, +} X86VEXSpecial; + + +typedef struct X86OpEntry X86OpEntry; +typedef struct X86DecodedInsn X86DecodedInsn; + +/* Decode function for multibyte opcodes. */ +typedef void (*X86DecodeFunc)(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b); + +/* Code generation function. */ +typedef void (*X86GenFunc)(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode); + +struct X86OpEntry { + /* Based on the is_decode flags. */ + union { + X86GenFunc gen; + X86DecodeFunc decode; + }; + /* op0 is always written, op1 and op2 are always read. */ + X86OpType op0:8; + X86OpSize s0:8; + X86OpType op1:8; + X86OpSize s1:8; + X86OpType op2:8; + X86OpSize s2:8; + /* Must be I and b respectively if present. */ + X86OpType op3:8; + X86OpSize s3:8; + + X86InsnSpecial special:8; + X86CPUIDFeature cpuid:8; + unsigned vex_class:8; + X86VEXSpecial vex_special:8; + uint16_t valid_prefix:16; + bool is_decode:1; +}; + +typedef struct X86DecodedOp { + int8_t n; + MemOp ot; /* For b/c/d/p/s/q/v/w/y/z */ + X86OpUnit unit; + bool has_ea; + int offset; /* For MMX and SSE */ + + /* + * This field is used internally by macros OP0_PTR/OP1_PTR/OP2_PTR, + * do not access directly! + */ + TCGv_ptr v_ptr; +} X86DecodedOp; + +struct X86DecodedInsn { + X86OpEntry e; + X86DecodedOp op[3]; + target_ulong immediate; + AddressParts mem; + + uint8_t b; +}; + diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc new file mode 100644 index 000000000000..7037ff91c612 --- /dev/null +++ b/target/i386/tcg/emit.c.inc @@ -0,0 +1,2300 @@ +/* + * New-style TCG opcode generator for i386 instructions + * + * Copyright (c) 2022 Red Hat, Inc. + * + * Author: Paolo Bonzini + * + * 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 . + */ + +#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_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_epppp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_ptr reg_c, TCGv_ptr reg_d); +typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_i32 val); +typedef void (*SSEFunc_0_epppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_ptr reg_c, TCGv_i32 val); +typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); +typedef void (*SSEFunc_0_pppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_ptr reg_c, + TCGv_i32 val); +typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv val); +typedef void (*SSEFunc_0_epppti)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_ptr reg_c, TCGv a0, TCGv_i32 scale); +typedef void (*SSEFunc_0_eppppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_ptr reg_c, TCGv_ptr reg_d, TCGv_i32 flags); +typedef void (*SSEFunc_0_eppppii)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_ptr reg_c, TCGv_ptr reg_d, TCGv_i32 even, + TCGv_i32 odd); + +static inline TCGv_i32 tcg_constant8u_i32(uint8_t val) +{ + return tcg_constant_i32(val); +} + +static void gen_NM_exception(DisasContext *s) +{ + gen_exception(s, EXCP07_PREX); +} + +static void gen_illegal(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_illegal_opcode(s); +} + +static void gen_load_ea(DisasContext *s, AddressParts *mem, bool is_vsib) +{ + TCGv ea = gen_lea_modrm_1(s, *mem, is_vsib); + gen_lea_v_seg(s, s->aflag, ea, mem->def_seg, s->override); +} + +static inline int mmx_offset(MemOp ot) +{ + switch (ot) { + case MO_8: + return offsetof(MMXReg, MMX_B(0)); + case MO_16: + return offsetof(MMXReg, MMX_W(0)); + case MO_32: + return offsetof(MMXReg, MMX_L(0)); + case MO_64: + return offsetof(MMXReg, MMX_Q(0)); + default: + g_assert_not_reached(); + } +} + +static inline int xmm_offset(MemOp ot) +{ + switch (ot) { + case MO_8: + return offsetof(ZMMReg, ZMM_B(0)); + case MO_16: + return offsetof(ZMMReg, ZMM_W(0)); + case MO_32: + return offsetof(ZMMReg, ZMM_L(0)); + case MO_64: + return offsetof(ZMMReg, ZMM_Q(0)); + case MO_128: + return offsetof(ZMMReg, ZMM_X(0)); + case MO_256: + return offsetof(ZMMReg, ZMM_Y(0)); + default: + g_assert_not_reached(); + } +} + +static int vector_reg_offset(X86DecodedOp *op) +{ + assert(op->unit == X86_OP_MMX || op->unit == X86_OP_SSE); + + if (op->unit == X86_OP_MMX) { + return op->offset - mmx_offset(op->ot); + } else { + return op->offset - xmm_offset(op->ot); + } +} + +static int vector_elem_offset(X86DecodedOp *op, MemOp ot, int n) +{ + int base_ofs = vector_reg_offset(op); + switch(ot) { + case MO_8: + if (op->unit == X86_OP_MMX) { + return base_ofs + offsetof(MMXReg, MMX_B(n)); + } else { + return base_ofs + offsetof(ZMMReg, ZMM_B(n)); + } + case MO_16: + if (op->unit == X86_OP_MMX) { + return base_ofs + offsetof(MMXReg, MMX_W(n)); + } else { + return base_ofs + offsetof(ZMMReg, ZMM_W(n)); + } + case MO_32: + if (op->unit == X86_OP_MMX) { + return base_ofs + offsetof(MMXReg, MMX_L(n)); + } else { + return base_ofs + offsetof(ZMMReg, ZMM_L(n)); + } + case MO_64: + if (op->unit == X86_OP_MMX) { + return base_ofs; + } else { + return base_ofs + offsetof(ZMMReg, ZMM_Q(n)); + } + case MO_128: + assert(op->unit == X86_OP_SSE); + return base_ofs + offsetof(ZMMReg, ZMM_X(n)); + case MO_256: + assert(op->unit == X86_OP_SSE); + return base_ofs + offsetof(ZMMReg, ZMM_Y(n)); + default: + g_assert_not_reached(); + } +} + +static void compute_mmx_offset(X86DecodedOp *op) +{ + if (!op->has_ea) { + op->offset = offsetof(CPUX86State, fpregs[op->n].mmx) + mmx_offset(op->ot); + } else { + op->offset = offsetof(CPUX86State, mmx_t0) + mmx_offset(op->ot); + } +} + +static void compute_xmm_offset(X86DecodedOp *op) +{ + if (!op->has_ea) { + op->offset = ZMM_OFFSET(op->n) + xmm_offset(op->ot); + } else { + op->offset = offsetof(CPUX86State, xmm_t0) + xmm_offset(op->ot); + } +} + +static void gen_load_sse(DisasContext *s, TCGv temp, MemOp ot, int dest_ofs, bool aligned) +{ + switch(ot) { + case MO_8: + gen_op_ld_v(s, MO_8, temp, s->A0); + tcg_gen_st8_tl(temp, cpu_env, dest_ofs); + break; + case MO_16: + gen_op_ld_v(s, MO_16, temp, s->A0); + tcg_gen_st16_tl(temp, cpu_env, dest_ofs); + break; + case MO_32: + gen_op_ld_v(s, MO_32, temp, s->A0); + tcg_gen_st32_tl(temp, cpu_env, dest_ofs); + break; + case MO_64: + gen_ldq_env_A0(s, dest_ofs); + break; + case MO_128: + gen_ldo_env_A0(s, dest_ofs, aligned); + break; + case MO_256: + gen_ldy_env_A0(s, dest_ofs, aligned); + break; + default: + g_assert_not_reached(); + } +} + +static bool sse_needs_alignment(DisasContext *s, X86DecodedInsn *decode, MemOp ot) +{ + switch (decode->e.vex_class) { + case 2: + case 4: + if ((s->prefix & PREFIX_VEX) || + decode->e.vex_special == X86_VEX_SSEUnaligned) { + /* MOST legacy SSE instructions require aligned memory operands, but not all. */ + return false; + } + /* fall through */ + case 1: + return ot >= MO_128; + + default: + return false; + } +} + +static void gen_load(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv v) +{ + X86DecodedOp *op = &decode->op[opn]; + + switch (op->unit) { + case X86_OP_SKIP: + return; + case X86_OP_SEG: + tcg_gen_ld32u_tl(v, cpu_env, + offsetof(CPUX86State,segs[op->n].selector)); + break; + case X86_OP_CR: + tcg_gen_ld_tl(v, cpu_env, offsetof(CPUX86State, cr[op->n])); + break; + case X86_OP_DR: + tcg_gen_ld_tl(v, cpu_env, offsetof(CPUX86State, dr[op->n])); + break; + case X86_OP_INT: + if (op->has_ea) { + gen_op_ld_v(s, op->ot, v, s->A0); + } else { + gen_op_mov_v_reg(s, op->ot, v, op->n); + } + break; + case X86_OP_IMM: + tcg_gen_movi_tl(v, decode->immediate); + break; + + case X86_OP_MMX: + compute_mmx_offset(op); + goto load_vector; + + case X86_OP_SSE: + compute_xmm_offset(op); + load_vector: + if (op->has_ea) { + bool aligned = sse_needs_alignment(s, decode, op->ot); + gen_load_sse(s, v, op->ot, op->offset, aligned); + } + break; + + default: + g_assert_not_reached(); + } +} + +static TCGv_ptr op_ptr(X86DecodedInsn *decode, int opn) +{ + X86DecodedOp *op = &decode->op[opn]; + if (op->v_ptr) { + return op->v_ptr; + } + op->v_ptr = tcg_temp_new_ptr(); + + /* The temporary points to the MMXReg or ZMMReg. */ + tcg_gen_addi_ptr(op->v_ptr, cpu_env, vector_reg_offset(op)); + return op->v_ptr; +} + +#define OP_PTR0 op_ptr(decode, 0) +#define OP_PTR1 op_ptr(decode, 1) +#define OP_PTR2 op_ptr(decode, 2) + +static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv v) +{ + X86DecodedOp *op = &decode->op[opn]; + switch (op->unit) { + case X86_OP_SKIP: + break; + case X86_OP_SEG: + /* Note that gen_movl_seg_T0 takes care of interrupt shadow and TF. */ + gen_movl_seg_T0(s, op->n); + break; + case X86_OP_INT: + if (op->has_ea) { + gen_op_st_v(s, op->ot, v, s->A0); + } else { + gen_op_mov_reg_v(s, op->ot, op->n, v); + } + break; + case X86_OP_MMX: + break; + case X86_OP_SSE: + if (!op->has_ea && (s->prefix & PREFIX_VEX) && op->ot <= MO_128) { + tcg_gen_gvec_dup_imm(MO_64, + offsetof(CPUX86State, xmm_regs[op->n].ZMM_X(1)), + 16, 16, 0); + } + break; + case X86_OP_CR: + case X86_OP_DR: + default: + g_assert_not_reached(); + } +} + +static inline int vector_len(DisasContext *s, X86DecodedInsn *decode) +{ + if (decode->e.special == X86_SPECIAL_MMX && + !(s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) { + return 8; + } + return s->vex_l ? 32 : 16; +} + +static void gen_store_sse(DisasContext *s, X86DecodedInsn *decode, int src_ofs) +{ + MemOp ot = decode->op[0].ot; + int vec_len = vector_len(s, decode); + bool aligned = sse_needs_alignment(s, decode, ot); + + if (!decode->op[0].has_ea) { + tcg_gen_gvec_mov(MO_64, decode->op[0].offset, src_ofs, vec_len, vec_len); + return; + } + + switch (ot) { + case MO_64: + gen_stq_env_A0(s, src_ofs); + break; + case MO_128: + gen_sto_env_A0(s, src_ofs, aligned); + break; + case MO_256: + gen_sty_env_A0(s, src_ofs, aligned); + break; + default: + g_assert_not_reached(); + } +} + +static void gen_helper_pavgusb(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b) +{ + gen_helper_pavgb_mmx(env, reg_a, reg_a, reg_b); +} + +#define FN_3DNOW_MOVE ((SSEFunc_0_epp) (uintptr_t) 1) +static const SSEFunc_0_epp fns_3dnow[] = { + [0x0c] = gen_helper_pi2fw, + [0x0d] = gen_helper_pi2fd, + [0x1c] = gen_helper_pf2iw, + [0x1d] = gen_helper_pf2id, + [0x8a] = gen_helper_pfnacc, + [0x8e] = gen_helper_pfpnacc, + [0x90] = gen_helper_pfcmpge, + [0x94] = gen_helper_pfmin, + [0x96] = gen_helper_pfrcp, + [0x97] = gen_helper_pfrsqrt, + [0x9a] = gen_helper_pfsub, + [0x9e] = gen_helper_pfadd, + [0xa0] = gen_helper_pfcmpgt, + [0xa4] = gen_helper_pfmax, + [0xa6] = FN_3DNOW_MOVE, /* PFRCPIT1; no need to actually increase precision */ + [0xa7] = FN_3DNOW_MOVE, /* PFRSQIT1 */ + [0xb6] = FN_3DNOW_MOVE, /* PFRCPIT2 */ + [0xaa] = gen_helper_pfsubr, + [0xae] = gen_helper_pfacc, + [0xb0] = gen_helper_pfcmpeq, + [0xb4] = gen_helper_pfmul, + [0xb7] = gen_helper_pmulhrw_mmx, + [0xbb] = gen_helper_pswapd, + [0xbf] = gen_helper_pavgusb, +}; + +static void gen_3dnow(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + uint8_t b = decode->immediate; + SSEFunc_0_epp fn = b < ARRAY_SIZE(fns_3dnow) ? fns_3dnow[b] : NULL; + + if (!fn) { + gen_illegal_opcode(s); + return; + } + if (s->flags & HF_TS_MASK) { + gen_NM_exception(s); + return; + } + if (s->flags & HF_EM_MASK) { + gen_illegal_opcode(s); + return; + } + + gen_helper_enter_mmx(cpu_env); + if (fn == FN_3DNOW_MOVE) { + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset); + } else { + fn(cpu_env, OP_PTR0, OP_PTR1); + } +} + +/* + * 00 = v*ps Vps, Hps, Wpd + * 66 = v*pd Vpd, Hpd, Wps + * f3 = v*ss Vss, Hss, Wps + * f2 = v*sd Vsd, Hsd, Wps + */ +static inline void gen_unary_fp_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_epp pd_xmm, SSEFunc_0_epp ps_xmm, + SSEFunc_0_epp pd_ymm, SSEFunc_0_epp ps_ymm, + SSEFunc_0_eppp sd, SSEFunc_0_eppp ss) +{ + if ((s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) != 0) { + SSEFunc_0_eppp fn = s->prefix & PREFIX_REPZ ? ss : sd; + if (!fn) { + gen_illegal_opcode(s); + return; + } + fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + } else { + SSEFunc_0_epp ps, pd, fn; + ps = s->vex_l ? ps_ymm : ps_xmm; + pd = s->vex_l ? pd_ymm : pd_xmm; + fn = s->prefix & PREFIX_DATA ? pd : ps; + if (!fn) { + gen_illegal_opcode(s); + return; + } + fn(cpu_env, OP_PTR0, OP_PTR2); + } +} +#define UNARY_FP_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_unary_fp_sse(s, env, decode, \ + gen_helper_##lname##pd_xmm, \ + gen_helper_##lname##ps_xmm, \ + gen_helper_##lname##pd_ymm, \ + gen_helper_##lname##ps_ymm, \ + gen_helper_##lname##sd, \ + gen_helper_##lname##ss); \ +} +UNARY_FP_SSE(VSQRT, sqrt) + +/* + * 00 = v*ps Vps, Hps, Wpd + * 66 = v*pd Vpd, Hpd, Wps + * f3 = v*ss Vss, Hss, Wps + * f2 = v*sd Vsd, Hsd, Wps + */ +static inline void gen_fp_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_eppp pd_xmm, SSEFunc_0_eppp ps_xmm, + SSEFunc_0_eppp pd_ymm, SSEFunc_0_eppp ps_ymm, + SSEFunc_0_eppp sd, SSEFunc_0_eppp ss) +{ + SSEFunc_0_eppp ps, pd, fn; + if ((s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) != 0) { + fn = s->prefix & PREFIX_REPZ ? ss : sd; + } else { + ps = s->vex_l ? ps_ymm : ps_xmm; + pd = s->vex_l ? pd_ymm : pd_xmm; + fn = s->prefix & PREFIX_DATA ? pd : ps; + } + if (fn) { + fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + } else { + gen_illegal_opcode(s); + } +} + +#define FP_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_fp_sse(s, env, decode, \ + gen_helper_##lname##pd_xmm, \ + gen_helper_##lname##ps_xmm, \ + gen_helper_##lname##pd_ymm, \ + gen_helper_##lname##ps_ymm, \ + gen_helper_##lname##sd, \ + gen_helper_##lname##ss); \ +} +FP_SSE(VADD, add) +FP_SSE(VMUL, mul) +FP_SSE(VSUB, sub) +FP_SSE(VMIN, min) +FP_SSE(VDIV, div) +FP_SSE(VMAX, max) + +#define FMA_SSE_PACKED(uname, ptr0, ptr1, ptr2, even, odd) \ +static void gen_##uname##Px(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + SSEFunc_0_eppppii xmm = s->vex_w ? gen_helper_fma4pd_xmm : gen_helper_fma4ps_xmm; \ + SSEFunc_0_eppppii ymm = s->vex_w ? gen_helper_fma4pd_ymm : gen_helper_fma4ps_ymm; \ + SSEFunc_0_eppppii fn = s->vex_l ? ymm : xmm; \ + \ + fn(cpu_env, OP_PTR0, ptr0, ptr1, ptr2, \ + tcg_constant_i32(even), \ + tcg_constant_i32((even) ^ (odd))); \ +} + +#define FMA_SSE(uname, ptr0, ptr1, ptr2, flags) \ +FMA_SSE_PACKED(uname, ptr0, ptr1, ptr2, flags, flags) \ +static void gen_##uname##Sx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + SSEFunc_0_eppppi fn = s->vex_w ? gen_helper_fma4sd : gen_helper_fma4ss; \ + \ + fn(cpu_env, OP_PTR0, ptr0, ptr1, ptr2, \ + tcg_constant_i32(flags)); \ +} \ + +FMA_SSE(VFMADD231, OP_PTR1, OP_PTR2, OP_PTR0, 0) +FMA_SSE(VFMADD213, OP_PTR1, OP_PTR0, OP_PTR2, 0) +FMA_SSE(VFMADD132, OP_PTR0, OP_PTR2, OP_PTR1, 0) + +FMA_SSE(VFNMADD231, OP_PTR1, OP_PTR2, OP_PTR0, float_muladd_negate_product) +FMA_SSE(VFNMADD213, OP_PTR1, OP_PTR0, OP_PTR2, float_muladd_negate_product) +FMA_SSE(VFNMADD132, OP_PTR0, OP_PTR2, OP_PTR1, float_muladd_negate_product) + +FMA_SSE(VFMSUB231, OP_PTR1, OP_PTR2, OP_PTR0, float_muladd_negate_c) +FMA_SSE(VFMSUB213, OP_PTR1, OP_PTR0, OP_PTR2, float_muladd_negate_c) +FMA_SSE(VFMSUB132, OP_PTR0, OP_PTR2, OP_PTR1, float_muladd_negate_c) + +FMA_SSE(VFNMSUB231, OP_PTR1, OP_PTR2, OP_PTR0, float_muladd_negate_c|float_muladd_negate_product) +FMA_SSE(VFNMSUB213, OP_PTR1, OP_PTR0, OP_PTR2, float_muladd_negate_c|float_muladd_negate_product) +FMA_SSE(VFNMSUB132, OP_PTR0, OP_PTR2, OP_PTR1, float_muladd_negate_c|float_muladd_negate_product) + +FMA_SSE_PACKED(VFMADDSUB231, OP_PTR1, OP_PTR2, OP_PTR0, float_muladd_negate_c, 0) +FMA_SSE_PACKED(VFMADDSUB213, OP_PTR1, OP_PTR0, OP_PTR2, float_muladd_negate_c, 0) +FMA_SSE_PACKED(VFMADDSUB132, OP_PTR0, OP_PTR2, OP_PTR1, float_muladd_negate_c, 0) + +FMA_SSE_PACKED(VFMSUBADD231, OP_PTR1, OP_PTR2, OP_PTR0, 0, float_muladd_negate_c) +FMA_SSE_PACKED(VFMSUBADD213, OP_PTR1, OP_PTR0, OP_PTR2, 0, float_muladd_negate_c) +FMA_SSE_PACKED(VFMSUBADD132, OP_PTR0, OP_PTR2, OP_PTR1, 0, float_muladd_negate_c) + +#define FP_UNPACK_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + /* PS maps to the DQ integer instruction, PD maps to QDQ. */ \ + gen_fp_sse(s, env, decode, \ + gen_helper_##lname##qdq_xmm, \ + gen_helper_##lname##dq_xmm, \ + gen_helper_##lname##qdq_ymm, \ + gen_helper_##lname##dq_ymm, \ + NULL, NULL); \ +} +FP_UNPACK_SSE(VUNPCKLPx, punpckl) +FP_UNPACK_SSE(VUNPCKHPx, punpckh) + +/* + * 00 = v*ps Vps, Wpd + * f3 = v*ss Vss, Wps + */ +static inline void gen_unary_fp32_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_epp ps_xmm, + SSEFunc_0_epp ps_ymm, + SSEFunc_0_eppp ss) +{ + if ((s->prefix & (PREFIX_DATA | PREFIX_REPNZ)) != 0) { + goto illegal_op; + } else if (s->prefix & PREFIX_REPZ) { + if (!ss) { + goto illegal_op; + } + ss(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + } else { + SSEFunc_0_epp fn = s->vex_l ? ps_ymm : ps_xmm; + if (!fn) { + goto illegal_op; + } + fn(cpu_env, OP_PTR0, OP_PTR2); + } + return; + +illegal_op: + gen_illegal_opcode(s); +} +#define UNARY_FP32_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_unary_fp32_sse(s, env, decode, \ + gen_helper_##lname##ps_xmm, \ + gen_helper_##lname##ps_ymm, \ + gen_helper_##lname##ss); \ +} +UNARY_FP32_SSE(VRSQRT, rsqrt) +UNARY_FP32_SSE(VRCP, rcp) + +/* + * 66 = v*pd Vpd, Hpd, Wpd + * f2 = v*ps Vps, Hps, Wps + */ +static inline void gen_horizontal_fp_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_eppp pd_xmm, SSEFunc_0_eppp ps_xmm, + SSEFunc_0_eppp pd_ymm, SSEFunc_0_eppp ps_ymm) +{ + SSEFunc_0_eppp ps, pd, fn; + ps = s->vex_l ? ps_ymm : ps_xmm; + pd = s->vex_l ? pd_ymm : pd_xmm; + fn = s->prefix & PREFIX_DATA ? pd : ps; + fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); +} +#define HORIZONTAL_FP_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_horizontal_fp_sse(s, env, decode, \ + gen_helper_##lname##pd_xmm, gen_helper_##lname##ps_xmm, \ + gen_helper_##lname##pd_ymm, gen_helper_##lname##ps_ymm); \ +} +HORIZONTAL_FP_SSE(VHADD, hadd) +HORIZONTAL_FP_SSE(VHSUB, hsub) +HORIZONTAL_FP_SSE(VADDSUB, addsub) + +static inline void gen_ternary_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + int op3, SSEFunc_0_epppp xmm, SSEFunc_0_epppp ymm) +{ + SSEFunc_0_epppp fn = s->vex_l ? ymm : xmm; + TCGv_ptr ptr3 = tcg_temp_new_ptr(); + + /* The format of the fourth input is Lx */ + tcg_gen_addi_ptr(ptr3, cpu_env, ZMM_OFFSET(op3)); + fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, ptr3); + tcg_temp_free_ptr(ptr3); +} +#define TERNARY_SSE(uname, uvname, lname) \ +static void gen_##uvname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_ternary_sse(s, env, decode, (uint8_t)decode->immediate >> 4, \ + gen_helper_##lname##_xmm, gen_helper_##lname##_ymm); \ +} \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_ternary_sse(s, env, decode, 0, \ + gen_helper_##lname##_xmm, gen_helper_##lname##_ymm); \ +} +TERNARY_SSE(BLENDVPS, VBLENDVPS, blendvps) +TERNARY_SSE(BLENDVPD, VBLENDVPD, blendvpd) +TERNARY_SSE(PBLENDVB, VPBLENDVB, pblendvb) + +static inline void gen_binary_imm_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_epppi xmm, SSEFunc_0_epppi ymm) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + if (!s->vex_l) { + xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + } else { + ymm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + } +} + +#define BINARY_IMM_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_binary_imm_sse(s, env, decode, \ + gen_helper_##lname##_xmm, \ + gen_helper_##lname##_ymm); \ +} + +BINARY_IMM_SSE(VBLENDPD, blendpd) +BINARY_IMM_SSE(VBLENDPS, blendps) +BINARY_IMM_SSE(VPBLENDW, pblendw) +BINARY_IMM_SSE(VDDPS, dpps) +#define gen_helper_dppd_ymm NULL +BINARY_IMM_SSE(VDDPD, dppd) +BINARY_IMM_SSE(VMPSADBW, mpsadbw) +BINARY_IMM_SSE(PCLMULQDQ, pclmulqdq) + + +#define UNARY_INT_GVEC(uname, func, ...) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + int vec_len = vector_len(s, decode); \ + \ + func(__VA_ARGS__, decode->op[0].offset, \ + decode->op[2].offset, vec_len, vec_len); \ +} +UNARY_INT_GVEC(PABSB, tcg_gen_gvec_abs, MO_8) +UNARY_INT_GVEC(PABSW, tcg_gen_gvec_abs, MO_16) +UNARY_INT_GVEC(PABSD, tcg_gen_gvec_abs, MO_32) +UNARY_INT_GVEC(VBROADCASTx128, tcg_gen_gvec_dup_mem, MO_128) +UNARY_INT_GVEC(VPBROADCASTB, tcg_gen_gvec_dup_mem, MO_8) +UNARY_INT_GVEC(VPBROADCASTW, tcg_gen_gvec_dup_mem, MO_16) +UNARY_INT_GVEC(VPBROADCASTD, tcg_gen_gvec_dup_mem, MO_32) +UNARY_INT_GVEC(VPBROADCASTQ, tcg_gen_gvec_dup_mem, MO_64) + + +#define BINARY_INT_GVEC(uname, func, ...) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + int vec_len = vector_len(s, decode); \ + \ + func(__VA_ARGS__, \ + decode->op[0].offset, decode->op[1].offset, \ + decode->op[2].offset, vec_len, vec_len); \ +} + +BINARY_INT_GVEC(PADDB, tcg_gen_gvec_add, MO_8) +BINARY_INT_GVEC(PADDW, tcg_gen_gvec_add, MO_16) +BINARY_INT_GVEC(PADDD, tcg_gen_gvec_add, MO_32) +BINARY_INT_GVEC(PADDQ, tcg_gen_gvec_add, MO_64) +BINARY_INT_GVEC(PADDSB, tcg_gen_gvec_ssadd, MO_8) +BINARY_INT_GVEC(PADDSW, tcg_gen_gvec_ssadd, MO_16) +BINARY_INT_GVEC(PADDUSB, tcg_gen_gvec_usadd, MO_8) +BINARY_INT_GVEC(PADDUSW, tcg_gen_gvec_usadd, MO_16) +BINARY_INT_GVEC(PAND, tcg_gen_gvec_and, MO_64) +BINARY_INT_GVEC(PCMPEQB, tcg_gen_gvec_cmp, TCG_COND_EQ, MO_8) +BINARY_INT_GVEC(PCMPEQD, tcg_gen_gvec_cmp, TCG_COND_EQ, MO_32) +BINARY_INT_GVEC(PCMPEQW, tcg_gen_gvec_cmp, TCG_COND_EQ, MO_16) +BINARY_INT_GVEC(PCMPEQQ, tcg_gen_gvec_cmp, TCG_COND_EQ, MO_64) +BINARY_INT_GVEC(PCMPGTB, tcg_gen_gvec_cmp, TCG_COND_GT, MO_8) +BINARY_INT_GVEC(PCMPGTW, tcg_gen_gvec_cmp, TCG_COND_GT, MO_16) +BINARY_INT_GVEC(PCMPGTD, tcg_gen_gvec_cmp, TCG_COND_GT, MO_32) +BINARY_INT_GVEC(PCMPGTQ, tcg_gen_gvec_cmp, TCG_COND_GT, MO_64) +BINARY_INT_GVEC(PMAXSB, tcg_gen_gvec_smax, MO_8) +BINARY_INT_GVEC(PMAXSW, tcg_gen_gvec_smax, MO_16) +BINARY_INT_GVEC(PMAXSD, tcg_gen_gvec_smax, MO_32) +BINARY_INT_GVEC(PMAXUB, tcg_gen_gvec_umax, MO_8) +BINARY_INT_GVEC(PMAXUW, tcg_gen_gvec_umax, MO_16) +BINARY_INT_GVEC(PMAXUD, tcg_gen_gvec_umax, MO_32) +BINARY_INT_GVEC(PMINSB, tcg_gen_gvec_smin, MO_8) +BINARY_INT_GVEC(PMINSW, tcg_gen_gvec_smin, MO_16) +BINARY_INT_GVEC(PMINSD, tcg_gen_gvec_smin, MO_32) +BINARY_INT_GVEC(PMINUB, tcg_gen_gvec_umin, MO_8) +BINARY_INT_GVEC(PMINUW, tcg_gen_gvec_umin, MO_16) +BINARY_INT_GVEC(PMINUD, tcg_gen_gvec_umin, MO_32) +BINARY_INT_GVEC(PMULLW, tcg_gen_gvec_mul, MO_16) +BINARY_INT_GVEC(PMULLD, tcg_gen_gvec_mul, MO_32) +BINARY_INT_GVEC(POR, tcg_gen_gvec_or, MO_64) +BINARY_INT_GVEC(PSUBB, tcg_gen_gvec_sub, MO_8) +BINARY_INT_GVEC(PSUBW, tcg_gen_gvec_sub, MO_16) +BINARY_INT_GVEC(PSUBD, tcg_gen_gvec_sub, MO_32) +BINARY_INT_GVEC(PSUBQ, tcg_gen_gvec_sub, MO_64) +BINARY_INT_GVEC(PSUBSB, tcg_gen_gvec_sssub, MO_8) +BINARY_INT_GVEC(PSUBSW, tcg_gen_gvec_sssub, MO_16) +BINARY_INT_GVEC(PSUBUSB, tcg_gen_gvec_ussub, MO_8) +BINARY_INT_GVEC(PSUBUSW, tcg_gen_gvec_ussub, MO_16) +BINARY_INT_GVEC(PXOR, tcg_gen_gvec_xor, MO_64) + + +/* + * 00 = p* Pq, Qq (if mmx not NULL; no VEX) + * 66 = vp* Vx, Hx, Wx + * + * These are really the same encoding, because 1) V is the same as P when VEX.V + * is not present 2) P and Q are the same as H and W apart from MM/XMM + */ +static inline void gen_binary_int_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_eppp mmx, SSEFunc_0_eppp xmm, SSEFunc_0_eppp ymm) +{ + assert(!!mmx == !!(decode->e.special == X86_SPECIAL_MMX)); + + if (mmx && (s->prefix & PREFIX_VEX) && !(s->prefix & PREFIX_DATA)) { + /* VEX encoding is not applicable to MMX instructions. */ + gen_illegal_opcode(s); + return; + } + if (!(s->prefix & PREFIX_DATA)) { + mmx(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + } else if (!s->vex_l) { + xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + } else { + ymm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); + } +} + + +#define BINARY_INT_MMX(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_binary_int_sse(s, env, decode, \ + gen_helper_##lname##_mmx, \ + gen_helper_##lname##_xmm, \ + gen_helper_##lname##_ymm); \ +} +BINARY_INT_MMX(PUNPCKLBW, punpcklbw) +BINARY_INT_MMX(PUNPCKLWD, punpcklwd) +BINARY_INT_MMX(PUNPCKLDQ, punpckldq) +BINARY_INT_MMX(PACKSSWB, packsswb) +BINARY_INT_MMX(PACKUSWB, packuswb) +BINARY_INT_MMX(PUNPCKHBW, punpckhbw) +BINARY_INT_MMX(PUNPCKHWD, punpckhwd) +BINARY_INT_MMX(PUNPCKHDQ, punpckhdq) +BINARY_INT_MMX(PACKSSDW, packssdw) + +BINARY_INT_MMX(PAVGB, pavgb) +BINARY_INT_MMX(PAVGW, pavgw) +BINARY_INT_MMX(PMADDWD, pmaddwd) +BINARY_INT_MMX(PMULHUW, pmulhuw) +BINARY_INT_MMX(PMULHW, pmulhw) +BINARY_INT_MMX(PMULUDQ, pmuludq) +BINARY_INT_MMX(PSADBW, psadbw) + +BINARY_INT_MMX(PSLLW_r, psllw) +BINARY_INT_MMX(PSLLD_r, pslld) +BINARY_INT_MMX(PSLLQ_r, psllq) +BINARY_INT_MMX(PSRLW_r, psrlw) +BINARY_INT_MMX(PSRLD_r, psrld) +BINARY_INT_MMX(PSRLQ_r, psrlq) +BINARY_INT_MMX(PSRAW_r, psraw) +BINARY_INT_MMX(PSRAD_r, psrad) + +BINARY_INT_MMX(PHADDW, phaddw) +BINARY_INT_MMX(PHADDSW, phaddsw) +BINARY_INT_MMX(PHADDD, phaddd) +BINARY_INT_MMX(PHSUBW, phsubw) +BINARY_INT_MMX(PHSUBSW, phsubsw) +BINARY_INT_MMX(PHSUBD, phsubd) +BINARY_INT_MMX(PMADDUBSW, pmaddubsw) +BINARY_INT_MMX(PSHUFB, pshufb) +BINARY_INT_MMX(PSIGNB, psignb) +BINARY_INT_MMX(PSIGNW, psignw) +BINARY_INT_MMX(PSIGND, psignd) +BINARY_INT_MMX(PMULHRSW, pmulhrsw) + +/* Instructions with no MMX equivalent. */ +#define BINARY_INT_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_binary_int_sse(s, env, decode, \ + NULL, \ + gen_helper_##lname##_xmm, \ + gen_helper_##lname##_ymm); \ +} + +/* Instructions with no MMX equivalent. */ +BINARY_INT_SSE(PUNPCKLQDQ, punpcklqdq) +BINARY_INT_SSE(PUNPCKHQDQ, punpckhqdq) +BINARY_INT_SSE(VPACKUSDW, packusdw) +BINARY_INT_SSE(VPERMILPS, vpermilps) +BINARY_INT_SSE(VPERMILPD, vpermilpd) +BINARY_INT_SSE(VMASKMOVPS, vpmaskmovd) +BINARY_INT_SSE(VMASKMOVPD, vpmaskmovq) + +BINARY_INT_SSE(PMULDQ, pmuldq) + +BINARY_INT_SSE(VAESDEC, aesdec) +BINARY_INT_SSE(VAESDECLAST, aesdeclast) +BINARY_INT_SSE(VAESENC, aesenc) +BINARY_INT_SSE(VAESENCLAST, aesenclast) + +#define UNARY_CMP_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + if (!s->vex_l) { \ + gen_helper_##lname##_xmm(cpu_env, OP_PTR1, OP_PTR2); \ + } else { \ + gen_helper_##lname##_ymm(cpu_env, OP_PTR1, OP_PTR2); \ + } \ + set_cc_op(s, CC_OP_EFLAGS); \ +} +UNARY_CMP_SSE(VPTEST, ptest) +UNARY_CMP_SSE(VTESTPS, vtestps) +UNARY_CMP_SSE(VTESTPD, vtestpd) + +static inline void gen_unary_int_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_epp xmm, SSEFunc_0_epp ymm) +{ + if (!s->vex_l) { + xmm(cpu_env, OP_PTR0, OP_PTR2); + } else { + ymm(cpu_env, OP_PTR0, OP_PTR2); + } +} + +#define UNARY_INT_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_unary_int_sse(s, env, decode, \ + gen_helper_##lname##_xmm, \ + gen_helper_##lname##_ymm); \ +} + +UNARY_INT_SSE(VPMOVSXBW, pmovsxbw) +UNARY_INT_SSE(VPMOVSXBD, pmovsxbd) +UNARY_INT_SSE(VPMOVSXBQ, pmovsxbq) +UNARY_INT_SSE(VPMOVSXWD, pmovsxwd) +UNARY_INT_SSE(VPMOVSXWQ, pmovsxwq) +UNARY_INT_SSE(VPMOVSXDQ, pmovsxdq) + +UNARY_INT_SSE(VPMOVZXBW, pmovzxbw) +UNARY_INT_SSE(VPMOVZXBD, pmovzxbd) +UNARY_INT_SSE(VPMOVZXBQ, pmovzxbq) +UNARY_INT_SSE(VPMOVZXWD, pmovzxwd) +UNARY_INT_SSE(VPMOVZXWQ, pmovzxwq) +UNARY_INT_SSE(VPMOVZXDQ, pmovzxdq) + +UNARY_INT_SSE(VMOVSLDUP, pmovsldup) +UNARY_INT_SSE(VMOVSHDUP, pmovshdup) +UNARY_INT_SSE(VMOVDDUP, pmovdldup) + +UNARY_INT_SSE(VCVTDQ2PD, cvtdq2pd) +UNARY_INT_SSE(VCVTPD2DQ, cvtpd2dq) +UNARY_INT_SSE(VCVTTPD2DQ, cvttpd2dq) +UNARY_INT_SSE(VCVTDQ2PS, cvtdq2ps) +UNARY_INT_SSE(VCVTPS2DQ, cvtps2dq) +UNARY_INT_SSE(VCVTTPS2DQ, cvttps2dq) +UNARY_INT_SSE(VCVTPH2PS, cvtph2ps) + + +static inline void gen_unary_imm_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_ppi xmm, SSEFunc_0_ppi ymm) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + if (!s->vex_l) { + xmm(OP_PTR0, OP_PTR1, imm); + } else { + ymm(OP_PTR0, OP_PTR1, imm); + } +} + +#define UNARY_IMM_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_unary_imm_sse(s, env, decode, \ + gen_helper_##lname##_xmm, \ + gen_helper_##lname##_ymm); \ +} + +UNARY_IMM_SSE(PSHUFD, pshufd) +UNARY_IMM_SSE(PSHUFHW, pshufhw) +UNARY_IMM_SSE(PSHUFLW, pshuflw) +#define gen_helper_vpermq_xmm NULL +UNARY_IMM_SSE(VPERMQ, vpermq) +UNARY_IMM_SSE(VPERMILPS_i, vpermilps_imm) +UNARY_IMM_SSE(VPERMILPD_i, vpermilpd_imm) + +static inline void gen_unary_imm_fp_sse(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_eppi xmm, SSEFunc_0_eppi ymm) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + if (!s->vex_l) { + xmm(cpu_env, OP_PTR0, OP_PTR1, imm); + } else { + ymm(cpu_env, OP_PTR0, OP_PTR1, imm); + } +} + +#define UNARY_IMM_FP_SSE(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_unary_imm_fp_sse(s, env, decode, \ + gen_helper_##lname##_xmm, \ + gen_helper_##lname##_ymm); \ +} + +UNARY_IMM_FP_SSE(VROUNDPS, roundps) +UNARY_IMM_FP_SSE(VROUNDPD, roundpd) + +static inline void gen_vexw_avx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_eppp d_xmm, SSEFunc_0_eppp q_xmm, + SSEFunc_0_eppp d_ymm, SSEFunc_0_eppp q_ymm) +{ + SSEFunc_0_eppp d = s->vex_l ? d_ymm : d_xmm; + SSEFunc_0_eppp q = s->vex_l ? q_ymm : q_xmm; + SSEFunc_0_eppp fn = s->vex_w ? q : d; + fn(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); +} + +/* VEX.W affects whether to operate on 32- or 64-bit elements. */ +#define VEXW_AVX(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_vexw_avx(s, env, decode, \ + gen_helper_##lname##d_xmm, gen_helper_##lname##q_xmm, \ + gen_helper_##lname##d_ymm, gen_helper_##lname##q_ymm); \ +} +VEXW_AVX(VPSLLV, vpsllv) +VEXW_AVX(VPSRLV, vpsrlv) +VEXW_AVX(VPSRAV, vpsrav) +VEXW_AVX(VPMASKMOV, vpmaskmov) + +/* Same as above, but with extra arguments to the helper. */ +static inline void gen_vsib_avx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_epppti d_xmm, SSEFunc_0_epppti q_xmm, + SSEFunc_0_epppti d_ymm, SSEFunc_0_epppti q_ymm) +{ + SSEFunc_0_epppti d = s->vex_l ? d_ymm : d_xmm; + SSEFunc_0_epppti q = s->vex_l ? q_ymm : q_xmm; + SSEFunc_0_epppti fn = s->vex_w ? q : d; + TCGv_i32 scale = tcg_constant_i32(decode->mem.scale); + TCGv_ptr index = tcg_temp_new_ptr(); + + /* Pass third input as (index, base, scale) */ + tcg_gen_addi_ptr(index, cpu_env, ZMM_OFFSET(decode->mem.index)); + fn(cpu_env, OP_PTR0, OP_PTR1, index, s->A0, scale); + + /* + * There are two output operands, so zero OP1's high 128 bits + * in the VEX.128 case. + */ + if (!s->vex_l) { + int ymmh_ofs = vector_elem_offset(&decode->op[1], MO_128, 1); + tcg_gen_gvec_dup_imm(MO_64, ymmh_ofs, 16, 16, 0); + } + tcg_temp_free_ptr(index); +} +#define VSIB_AVX(uname, lname) \ +static void gen_##uname(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) \ +{ \ + gen_vsib_avx(s, env, decode, \ + gen_helper_##lname##d_xmm, gen_helper_##lname##q_xmm, \ + gen_helper_##lname##d_ymm, gen_helper_##lname##q_ymm); \ +} +VSIB_AVX(VPGATHERD, vpgatherd) +VSIB_AVX(VPGATHERQ, vpgatherq) + +static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op) +{ + TCGv carry_in = NULL; + TCGv carry_out = (cc_op == CC_OP_ADCX ? cpu_cc_dst : cpu_cc_src2); + TCGv zero; + + if (cc_op == s->cc_op || s->cc_op == CC_OP_ADCOX) { + /* Re-use the carry-out from a previous round. */ + carry_in = carry_out; + cc_op = s->cc_op; + } else if (s->cc_op == CC_OP_ADCX || s->cc_op == CC_OP_ADOX) { + /* Merge with the carry-out from the opposite instruction. */ + cc_op = CC_OP_ADCOX; + } + + /* If we don't have a carry-in, get it out of EFLAGS. */ + if (!carry_in) { + if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) { + gen_compute_eflags(s); + } + carry_in = s->tmp0; + tcg_gen_extract_tl(carry_in, cpu_cc_src, + ctz32(cc_op == CC_OP_ADCX ? CC_C : CC_O), 1); + } + + switch (ot) { +#ifdef TARGET_X86_64 + case MO_32: + /* If TL is 64-bit just do everything in 64-bit arithmetic. */ + tcg_gen_add_i64(s->T0, s->T0, s->T1); + tcg_gen_add_i64(s->T0, s->T0, carry_in); + tcg_gen_shri_i64(carry_out, s->T0, 32); + break; +#endif + default: + zero = tcg_constant_tl(0); + tcg_gen_add2_tl(s->T0, carry_out, s->T0, zero, carry_in, zero); + tcg_gen_add2_tl(s->T0, carry_out, s->T0, carry_out, s->T1, zero); + break; + } + set_cc_op(s, cc_op); +} + +static void gen_ADCX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_ADCOX(s, env, decode->op[0].ot, CC_OP_ADCX); +} + +static void gen_ADOX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_ADCOX(s, env, decode->op[0].ot, CC_OP_ADOX); +} + +static void gen_ANDN(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + + tcg_gen_andc_tl(s->T0, s->T1, s->T0); + gen_op_update1_cc(s); + set_cc_op(s, CC_OP_LOGICB + ot); +} + +static void gen_BEXTR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + TCGv bound, zero; + + /* + * Extract START, and shift the operand. + * Shifts larger than operand size get zeros. + */ + tcg_gen_ext8u_tl(s->A0, s->T1); + tcg_gen_shr_tl(s->T0, s->T0, s->A0); + + bound = tcg_constant_tl(ot == MO_64 ? 63 : 31); + zero = tcg_constant_tl(0); + tcg_gen_movcond_tl(TCG_COND_LEU, s->T0, s->A0, bound, s->T0, zero); + + /* + * Extract the LEN into a mask. Lengths larger than + * operand size get all ones. + */ + tcg_gen_extract_tl(s->A0, s->T1, 8, 8); + tcg_gen_movcond_tl(TCG_COND_LEU, s->A0, s->A0, bound, s->A0, bound); + + tcg_gen_movi_tl(s->T1, 1); + tcg_gen_shl_tl(s->T1, s->T1, s->A0); + tcg_gen_subi_tl(s->T1, s->T1, 1); + tcg_gen_and_tl(s->T0, s->T0, s->T1); + + gen_op_update1_cc(s); + set_cc_op(s, CC_OP_LOGICB + ot); +} + +static void gen_BLSI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + + tcg_gen_neg_tl(s->T1, s->T0); + tcg_gen_and_tl(s->T0, s->T0, s->T1); + tcg_gen_mov_tl(cpu_cc_dst, s->T0); + set_cc_op(s, CC_OP_BMILGB + ot); +} + +static void gen_BLSMSK(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + + tcg_gen_subi_tl(s->T1, s->T0, 1); + tcg_gen_xor_tl(s->T0, s->T0, s->T1); + tcg_gen_mov_tl(cpu_cc_dst, s->T0); + set_cc_op(s, CC_OP_BMILGB + ot); +} + +static void gen_BLSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + + tcg_gen_subi_tl(s->T1, s->T0, 1); + tcg_gen_and_tl(s->T0, s->T0, s->T1); + tcg_gen_mov_tl(cpu_cc_dst, s->T0); + set_cc_op(s, CC_OP_BMILGB + ot); +} + +static void gen_BZHI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + TCGv bound; + + tcg_gen_ext8u_tl(s->T1, cpu_regs[s->vex_v]); + bound = tcg_constant_tl(ot == MO_64 ? 63 : 31); + + /* + * Note that since we're using BMILG (in order to get O + * cleared) we need to store the inverse into C. + */ + tcg_gen_setcond_tl(TCG_COND_LT, cpu_cc_src, s->T1, bound); + tcg_gen_movcond_tl(TCG_COND_GT, s->T1, s->T1, bound, bound, s->T1); + + tcg_gen_movi_tl(s->A0, -1); + tcg_gen_shl_tl(s->A0, s->A0, s->T1); + tcg_gen_andc_tl(s->T0, s->T0, s->A0); + + gen_op_update1_cc(s); + set_cc_op(s, CC_OP_BMILGB + ot); +} + +static void gen_CRC32(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[2].ot; + + tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); + gen_helper_crc32(s->T0, s->tmp2_i32, s->T1, tcg_constant_i32(8 << ot)); +} + +static void gen_CVTPI2Px(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_enter_mmx(cpu_env); + if (s->prefix & PREFIX_DATA) { + gen_helper_cvtpi2pd(cpu_env, OP_PTR0, OP_PTR2); + } else { + gen_helper_cvtpi2ps(cpu_env, OP_PTR0, OP_PTR2); + } +} + +static void gen_CVTPx2PI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_enter_mmx(cpu_env); + if (s->prefix & PREFIX_DATA) { + gen_helper_cvtpd2pi(cpu_env, OP_PTR0, OP_PTR2); + } else { + gen_helper_cvtps2pi(cpu_env, OP_PTR0, OP_PTR2); + } +} + +static void gen_CVTTPx2PI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_enter_mmx(cpu_env); + if (s->prefix & PREFIX_DATA) { + gen_helper_cvttpd2pi(cpu_env, OP_PTR0, OP_PTR2); + } else { + gen_helper_cvttps2pi(cpu_env, OP_PTR0, OP_PTR2); + } +} + +static void gen_EMMS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_emms(cpu_env); +} + +static void gen_EXTRQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 length = tcg_constant_i32(decode->immediate & 63); + TCGv_i32 index = tcg_constant_i32((decode->immediate >> 8) & 63); + + gen_helper_extrq_i(cpu_env, OP_PTR0, index, length); +} + +static void gen_EXTRQ_r(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_extrq_r(cpu_env, OP_PTR0, OP_PTR2); +} + +static void gen_INSERTQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 length = tcg_constant_i32(decode->immediate & 63); + TCGv_i32 index = tcg_constant_i32((decode->immediate >> 8) & 63); + + gen_helper_insertq_i(cpu_env, OP_PTR0, OP_PTR1, index, length); +} + +static void gen_INSERTQ_r(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_insertq_r(cpu_env, OP_PTR0, OP_PTR2); +} + +static void gen_LDMXCSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if (s->vex_l) { + gen_illegal_opcode(s); + return; + } + tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T1); + gen_helper_ldmxcsr(cpu_env, s->tmp2_i32); +} + +static void gen_MASKMOV(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_mov_tl(s->A0, cpu_regs[R_EDI]); + gen_extu(s->aflag, s->A0); + gen_add_A0_ds_seg(s); + + if (s->prefix & PREFIX_DATA) { + gen_helper_maskmov_xmm(cpu_env, OP_PTR1, OP_PTR2, s->A0); + } else { + gen_helper_maskmov_mmx(cpu_env, OP_PTR1, OP_PTR2, s->A0); + } +} + +static void gen_MOVBE(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + + /* M operand type does not load/store */ + if (decode->e.op0 == X86_TYPE_M) { + tcg_gen_qemu_st_tl(s->T0, s->A0, s->mem_index, ot | MO_BE); + } else { + tcg_gen_qemu_ld_tl(s->T0, s->A0, s->mem_index, ot | MO_BE); + } +} + +static void gen_MOVD_from(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[2].ot; + + switch (ot) { + case MO_32: +#ifdef TARGET_X86_64 + tcg_gen_ld32u_tl(s->T0, cpu_env, decode->op[2].offset); + break; + case MO_64: +#endif + tcg_gen_ld_tl(s->T0, cpu_env, decode->op[2].offset); + break; + default: + abort(); + } +} + +static void gen_MOVD_to(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[2].ot; + int vec_len = vector_len(s, decode); + int lo_ofs = vector_elem_offset(&decode->op[0], ot, 0); + + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + + switch (ot) { + case MO_32: +#ifdef TARGET_X86_64 + tcg_gen_st32_tl(s->T1, cpu_env, lo_ofs); + break; + case MO_64: +#endif + tcg_gen_st_tl(s->T1, cpu_env, lo_ofs); + break; + default: + g_assert_not_reached(); + } +} + +static void gen_MOVDQ(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_store_sse(s, decode, decode->op[2].offset); +} + +static void gen_MOVMSK(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + typeof(gen_helper_movmskps_ymm) *ps, *pd, *fn; + ps = s->vex_l ? gen_helper_movmskps_ymm : gen_helper_movmskps_xmm; + pd = s->vex_l ? gen_helper_movmskpd_ymm : gen_helper_movmskpd_xmm; + fn = s->prefix & PREFIX_DATA ? pd : ps; + fn(s->tmp2_i32, cpu_env, OP_PTR2); + tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); +} + +static void gen_MOVQ(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + int lo_ofs = vector_elem_offset(&decode->op[0], MO_64, 0); + + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset); + if (decode->op[0].has_ea) { + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); + } else { + /* + * tcg_gen_gvec_dup_i64(MO_64, op0.offset, 8, vec_len, s->tmp1_64) would + * seem to work, but it does not on big-endian platforms; the cleared parts + * are always at higher addresses, but cross-endian emulation inverts the + * byte order so that the cleared parts need to be at *lower* addresses. + * Because oprsz is 8, we see this here even for SSE; but more in general, + * it disqualifies using oprsz < maxsz to emulate VEX128. + */ + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, lo_ofs); + } +} + +static void gen_MOVq_dq(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_helper_enter_mmx(cpu_env); + /* Otherwise the same as any other movq. */ + return gen_MOVQ(s, env, decode); +} + +static void gen_MULX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + + /* low part of result in VEX.vvvv, high in MODRM */ + switch (ot) { + default: + tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); + tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); + tcg_gen_mulu2_i32(s->tmp2_i32, s->tmp3_i32, + s->tmp2_i32, s->tmp3_i32); + tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], s->tmp2_i32); + tcg_gen_extu_i32_tl(s->T0, s->tmp3_i32); + break; +#ifdef TARGET_X86_64 + case MO_64: + tcg_gen_mulu2_i64(cpu_regs[s->vex_v], s->T0, s->T0, s->T1); + break; +#endif + } + +} + +static void gen_PALIGNR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + if (!(s->prefix & PREFIX_DATA)) { + gen_helper_palignr_mmx(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + } else if (!s->vex_l) { + gen_helper_palignr_xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + } else { + gen_helper_palignr_ymm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); + } +} + +static void gen_PANDN(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + /* Careful, operand order is reversed! */ + tcg_gen_gvec_andc(MO_64, + decode->op[0].offset, decode->op[2].offset, + decode->op[1].offset, vec_len, vec_len); +} + +static void gen_PCMPESTRI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + gen_helper_pcmpestri_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + set_cc_op(s, CC_OP_EFLAGS); +} + +static void gen_PCMPESTRM(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + gen_helper_pcmpestrm_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + set_cc_op(s, CC_OP_EFLAGS); + if ((s->prefix & PREFIX_VEX) && !s->vex_l) { + tcg_gen_gvec_dup_imm(MO_64, offsetof(CPUX86State, xmm_regs[0].ZMM_X(1)), + 16, 16, 0); + } +} + +static void gen_PCMPISTRI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + gen_helper_pcmpistri_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + set_cc_op(s, CC_OP_EFLAGS); +} + +static void gen_PCMPISTRM(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + gen_helper_pcmpistrm_xmm(cpu_env, OP_PTR1, OP_PTR2, imm); + set_cc_op(s, CC_OP_EFLAGS); + if ((s->prefix & PREFIX_VEX) && !s->vex_l) { + tcg_gen_gvec_dup_imm(MO_64, offsetof(CPUX86State, xmm_regs[0].ZMM_X(1)), + 16, 16, 0); + } +} + +static void gen_PDEP(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[1].ot; + if (ot < MO_64) { + tcg_gen_ext32u_tl(s->T0, s->T0); + } + gen_helper_pdep(s->T0, s->T0, s->T1); +} + +static void gen_PEXT(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[1].ot; + if (ot < MO_64) { + tcg_gen_ext32u_tl(s->T0, s->T0); + } + gen_helper_pext(s->T0, s->T0, s->T1); +} + +static inline void gen_pextr(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, MemOp ot) +{ + int vec_len = vector_len(s, decode); + int mask = (vec_len >> ot) - 1; + int val = decode->immediate & mask; + + switch (ot) { + case MO_8: + tcg_gen_ld8u_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + break; + case MO_16: + tcg_gen_ld16u_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + break; + case MO_32: +#ifdef TARGET_X86_64 + tcg_gen_ld32u_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + break; + case MO_64: +#endif + tcg_gen_ld_tl(s->T0, cpu_env, vector_elem_offset(&decode->op[1], ot, val)); + break; + default: + abort(); + } +} + +static void gen_PEXTRB(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_pextr(s, env, decode, MO_8); +} + +static void gen_PEXTRW(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_pextr(s, env, decode, MO_16); +} + +static void gen_PEXTR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + gen_pextr(s, env, decode, ot); +} + +static inline void gen_pinsr(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, MemOp ot) +{ + int vec_len = vector_len(s, decode); + int mask = (vec_len >> ot) - 1; + int val = decode->immediate & mask; + + if (decode->op[1].offset != decode->op[0].offset) { + assert(vec_len == 16); + gen_store_sse(s, decode, decode->op[1].offset); + } + + switch (ot) { + case MO_8: + tcg_gen_st8_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + break; + case MO_16: + tcg_gen_st16_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + break; + case MO_32: +#ifdef TARGET_X86_64 + tcg_gen_st32_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + break; + case MO_64: +#endif + tcg_gen_st_tl(s->T1, cpu_env, vector_elem_offset(&decode->op[0], ot, val)); + break; + default: + abort(); + } +} + +static void gen_PINSRB(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_pinsr(s, env, decode, MO_8); +} + +static void gen_PINSRW(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_pinsr(s, env, decode, MO_16); +} + +static void gen_PINSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_pinsr(s, env, decode, decode->op[2].ot); +} + +static void gen_pmovmskb_i64(TCGv_i64 d, TCGv_i64 s) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_andi_i64(d, s, 0x8080808080808080ull); + + /* + * After each shift+or pair: + * 0: a.......b.......c.......d.......e.......f.......g.......h....... + * 7: ab......bc......cd......de......ef......fg......gh......h....... + * 14: abcd....bcde....cdef....defg....efgh....fgh.....gh......h....... + * 28: abcdefghbcdefgh.cdefgh..defgh...efgh....fgh.....gh......h....... + * The result is left in the high bits of the word. + */ + tcg_gen_shli_i64(t, d, 7); + tcg_gen_or_i64(d, d, t); + tcg_gen_shli_i64(t, d, 14); + tcg_gen_or_i64(d, d, t); + tcg_gen_shli_i64(t, d, 28); + tcg_gen_or_i64(d, d, t); +} + +static void gen_pmovmskb_vec(unsigned vece, TCGv_vec d, TCGv_vec s) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + TCGv_vec m = tcg_constant_vec_matching(d, MO_8, 0x80); + + /* See above */ + tcg_gen_and_vec(vece, d, s, m); + tcg_gen_shli_vec(vece, t, d, 7); + tcg_gen_or_vec(vece, d, d, t); + tcg_gen_shli_vec(vece, t, d, 14); + tcg_gen_or_vec(vece, d, d, t); + tcg_gen_shli_vec(vece, t, d, 28); + tcg_gen_or_vec(vece, d, d, t); +} + +#ifdef TARGET_X86_64 +#define TCG_TARGET_HAS_extract2_tl TCG_TARGET_HAS_extract2_i64 +#else +#define TCG_TARGET_HAS_extract2_tl TCG_TARGET_HAS_extract2_i32 +#endif + +static void gen_PMOVMSKB(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_shli_vec, 0 }; + static const GVecGen2 g = { + .fni8 = gen_pmovmskb_i64, + .fniv = gen_pmovmskb_vec, + .opt_opc = vecop_list, + .vece = MO_64, + .prefer_i64 = TCG_TARGET_REG_BITS == 64 + }; + MemOp ot = decode->op[2].ot; + int vec_len = vector_len(s, decode); + TCGv t = tcg_temp_new(); + + tcg_gen_gvec_2(offsetof(CPUX86State, xmm_t0) + xmm_offset(ot), decode->op[2].offset, + vec_len, vec_len, &g); + tcg_gen_ld8u_tl(s->T0, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); + while (vec_len > 8) { + vec_len -= 8; + if (TCG_TARGET_HAS_extract2_tl) { + /* + * Load the next byte of the result into the high byte of T. + * TCG does a similar expansion of deposit to shl+extract2; by + * loading the whole word, the shift left is avoided. + */ +#ifdef TARGET_X86_64 + tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_Q((vec_len - 1) / 8))); +#else + tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_L((vec_len - 1) / 4))); +#endif + + tcg_gen_extract2_tl(s->T0, t, s->T0, TARGET_LONG_BITS - 8); + } else { + /* + * The _previous_ value is deposited into bits 8 and higher of t. Because + * those bits are known to be zero after ld8u, this becomes a shift+or + * if deposit is not available. + */ + tcg_gen_ld8u_tl(t, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); + tcg_gen_deposit_tl(s->T0, t, s->T0, 8, TARGET_LONG_BITS - 8); + } + } + tcg_temp_free(t); +} + +static void gen_PSHUFW(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + gen_helper_pshufw_mmx(OP_PTR0, OP_PTR1, imm); +} + +static void gen_PSRLW_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 16) { + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else { + tcg_gen_gvec_shri(MO_16, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); + } +} + +static void gen_PSLLW_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 16) { + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else { + tcg_gen_gvec_shli(MO_16, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); + } +} + +static void gen_PSRAW_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 16) { + decode->immediate = 15; + } + tcg_gen_gvec_sari(MO_16, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); +} + +static void gen_PSRLD_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 32) { + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else { + tcg_gen_gvec_shri(MO_32, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); + } +} + +static void gen_PSLLD_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 32) { + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else { + tcg_gen_gvec_shli(MO_32, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); + } +} + +static void gen_PSRAD_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 32) { + decode->immediate = 31; + } + tcg_gen_gvec_sari(MO_32, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); +} + +static void gen_PSRLQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 64) { + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else { + tcg_gen_gvec_shri(MO_64, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); + } +} + +static void gen_PSLLQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + if (decode->immediate >= 64) { + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else { + tcg_gen_gvec_shli(MO_64, + decode->op[0].offset, decode->op[1].offset, + decode->immediate, vec_len, vec_len); + } +} + +static TCGv_ptr make_imm8u_xmm_vec(uint8_t imm, int vec_len) +{ + MemOp ot = vec_len == 16 ? MO_128 : MO_256; + TCGv_i32 imm_v = tcg_constant8u_i32(imm); + TCGv_ptr ptr = tcg_temp_new_ptr(); + + tcg_gen_gvec_dup_imm(MO_64, offsetof(CPUX86State, xmm_t0) + xmm_offset(ot), + vec_len, vec_len, 0); + + tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_t0)); + tcg_gen_st_i32(imm_v, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_L(0))); + return ptr; +} + +static void gen_PSRLDQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + TCGv_ptr imm_vec = make_imm8u_xmm_vec(decode->immediate, vec_len); + + if (s->vex_l) { + gen_helper_psrldq_ymm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + } else { + gen_helper_psrldq_xmm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + } + tcg_temp_free_ptr(imm_vec); +} + +static void gen_PSLLDQ_i(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + TCGv_ptr imm_vec = make_imm8u_xmm_vec(decode->immediate, vec_len); + + if (s->vex_l) { + gen_helper_pslldq_ymm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + } else { + gen_helper_pslldq_xmm(cpu_env, OP_PTR0, OP_PTR1, imm_vec); + } + tcg_temp_free_ptr(imm_vec); +} + +static void gen_RORX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + int b = decode->immediate; + + if (ot == MO_64) { + tcg_gen_rotri_tl(s->T0, s->T0, b & 63); + } else { + tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); + tcg_gen_rotri_i32(s->tmp2_i32, s->tmp2_i32, b & 31); + tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); + } +} + +static void gen_SARX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + int mask; + + mask = ot == MO_64 ? 63 : 31; + tcg_gen_andi_tl(s->T1, s->T1, mask); + if (ot != MO_64) { + tcg_gen_ext32s_tl(s->T0, s->T0); + } + tcg_gen_sar_tl(s->T0, s->T0, s->T1); +} + +static void gen_SHLX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + int mask; + + mask = ot == MO_64 ? 63 : 31; + tcg_gen_andi_tl(s->T1, s->T1, mask); + tcg_gen_shl_tl(s->T0, s->T0, s->T1); +} + +static void gen_SHRX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[0].ot; + int mask; + + mask = ot == MO_64 ? 63 : 31; + tcg_gen_andi_tl(s->T1, s->T1, mask); + if (ot != MO_64) { + tcg_gen_ext32u_tl(s->T0, s->T0); + } + tcg_gen_shr_tl(s->T0, s->T0, s->T1); +} + +static void gen_VAESKEYGEN(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + assert(!s->vex_l); + gen_helper_aeskeygenassist_xmm(cpu_env, OP_PTR0, OP_PTR1, imm); +} + +static void gen_STMXCSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if (s->vex_l) { + gen_illegal_opcode(s); + return; + } + gen_helper_update_mxcsr(cpu_env); + tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr)); +} + +static void gen_VAESIMC(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + assert(!s->vex_l); + gen_helper_aesimc_xmm(cpu_env, OP_PTR0, OP_PTR2); +} + +/* + * 00 = v*ps Vps, Hps, Wpd + * 66 = v*pd Vpd, Hpd, Wps + * f3 = v*ss Vss, Hss, Wps + * f2 = v*sd Vsd, Hsd, Wps + */ +#define SSE_CMP(x) { \ + gen_helper_ ## x ## ps ## _xmm, gen_helper_ ## x ## pd ## _xmm, \ + gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, \ + gen_helper_ ## x ## ps ## _ymm, gen_helper_ ## x ## pd ## _ymm} +static const SSEFunc_0_eppp gen_helper_cmp_funcs[32][6] = { + SSE_CMP(cmpeq), + SSE_CMP(cmplt), + SSE_CMP(cmple), + SSE_CMP(cmpunord), + SSE_CMP(cmpneq), + SSE_CMP(cmpnlt), + SSE_CMP(cmpnle), + SSE_CMP(cmpord), + + SSE_CMP(cmpequ), + SSE_CMP(cmpnge), + SSE_CMP(cmpngt), + SSE_CMP(cmpfalse), + SSE_CMP(cmpnequ), + SSE_CMP(cmpge), + SSE_CMP(cmpgt), + SSE_CMP(cmptrue), + + SSE_CMP(cmpeqs), + SSE_CMP(cmpltq), + SSE_CMP(cmpleq), + SSE_CMP(cmpunords), + SSE_CMP(cmpneqq), + SSE_CMP(cmpnltq), + SSE_CMP(cmpnleq), + SSE_CMP(cmpords), + + SSE_CMP(cmpequs), + SSE_CMP(cmpngeq), + SSE_CMP(cmpngtq), + SSE_CMP(cmpfalses), + SSE_CMP(cmpnequs), + SSE_CMP(cmpgeq), + SSE_CMP(cmpgtq), + SSE_CMP(cmptrues), +}; +#undef SSE_CMP + +static void gen_VCMP(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int index = decode->immediate & (s->prefix & PREFIX_VEX ? 31 : 7); + int b = + s->prefix & PREFIX_REPZ ? 2 /* ss */ : + s->prefix & PREFIX_REPNZ ? 3 /* sd */ : + !!(s->prefix & PREFIX_DATA) /* pd */ + (s->vex_l << 2); + + gen_helper_cmp_funcs[index][b](cpu_env, OP_PTR0, OP_PTR1, OP_PTR2); +} + +static void gen_VCOMI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + SSEFunc_0_epp fn; + fn = s->prefix & PREFIX_DATA ? gen_helper_comisd : gen_helper_comiss; + fn(cpu_env, OP_PTR1, OP_PTR2); + set_cc_op(s, CC_OP_EFLAGS); +} + +static void gen_VCVTfp2fp(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_unary_fp_sse(s, env, decode, + gen_helper_cvtpd2ps_xmm, gen_helper_cvtps2pd_xmm, + gen_helper_cvtpd2ps_ymm, gen_helper_cvtps2pd_ymm, + gen_helper_cvtsd2ss, gen_helper_cvtss2sd); +} + +static void gen_VCVTPS2PH(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_unary_imm_fp_sse(s, env, decode, + gen_helper_cvtps2ph_xmm, + gen_helper_cvtps2ph_ymm); + /* + * VCVTPS2PH is the only instruction that performs an operation on a + * register source and then *stores* into memory. + */ + if (decode->op[0].has_ea) { + gen_store_sse(s, decode, decode->op[0].offset); + } +} + +static void gen_VCVTSI2Sx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + TCGv_i32 in; + + tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len); + +#ifdef TARGET_X86_64 + MemOp ot = decode->op[2].ot; + if (ot == MO_64) { + if (s->prefix & PREFIX_REPNZ) { + gen_helper_cvtsq2sd(cpu_env, OP_PTR0, s->T1); + } else { + gen_helper_cvtsq2ss(cpu_env, OP_PTR0, s->T1); + } + return; + } + in = s->tmp2_i32; + tcg_gen_trunc_tl_i32(in, s->T1); +#else + in = s->T1; +#endif + + if (s->prefix & PREFIX_REPNZ) { + gen_helper_cvtsi2sd(cpu_env, OP_PTR0, in); + } else { + gen_helper_cvtsi2ss(cpu_env, OP_PTR0, in); + } +} + +static inline void gen_VCVTtSx2SI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_i_ep ss2si, SSEFunc_l_ep ss2sq, + SSEFunc_i_ep sd2si, SSEFunc_l_ep sd2sq) +{ + TCGv_i32 out; + +#ifdef TARGET_X86_64 + MemOp ot = decode->op[0].ot; + if (ot == MO_64) { + if (s->prefix & PREFIX_REPNZ) { + sd2sq(s->T0, cpu_env, OP_PTR2); + } else { + ss2sq(s->T0, cpu_env, OP_PTR2); + } + return; + } + + out = s->tmp2_i32; +#else + out = s->T0; +#endif + if (s->prefix & PREFIX_REPNZ) { + sd2si(out, cpu_env, OP_PTR2); + } else { + ss2si(out, cpu_env, OP_PTR2); + } +#ifdef TARGET_X86_64 + tcg_gen_extu_i32_tl(s->T0, out); +#endif +} + +#ifndef TARGET_X86_64 +#define gen_helper_cvtss2sq NULL +#define gen_helper_cvtsd2sq NULL +#define gen_helper_cvttss2sq NULL +#define gen_helper_cvttsd2sq NULL +#endif + +static void gen_VCVTSx2SI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_VCVTtSx2SI(s, env, decode, + gen_helper_cvtss2si, gen_helper_cvtss2sq, + gen_helper_cvtsd2si, gen_helper_cvtsd2sq); +} + +static void gen_VCVTTSx2SI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_VCVTtSx2SI(s, env, decode, + gen_helper_cvttss2si, gen_helper_cvttss2sq, + gen_helper_cvttsd2si, gen_helper_cvttsd2sq); +} + +static void gen_VEXTRACTx128(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int mask = decode->immediate & 1; + int src_ofs = vector_elem_offset(&decode->op[1], MO_128, mask); + if (decode->op[0].has_ea) { + /* VEX-only instruction, no alignment requirements. */ + gen_sto_env_A0(s, src_ofs, false); + } else { + tcg_gen_gvec_mov(MO_64, decode->op[0].offset, src_ofs, 16, 16); + } +} + +static void gen_VEXTRACTPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_pextr(s, env, decode, MO_32); +} + +static void gen_vinsertps(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int val = decode->immediate; + int dest_word = (val >> 4) & 3; + int new_mask = (val & 15) | (1 << dest_word); + int vec_len = 16; + + assert(!s->vex_l); + + if (new_mask == 15) { + /* All zeroes except possibly for the inserted element */ + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + } else if (decode->op[1].offset != decode->op[0].offset) { + gen_store_sse(s, decode, decode->op[1].offset); + } + + if (new_mask != (val & 15)) { + tcg_gen_st_i32(s->tmp2_i32, cpu_env, + vector_elem_offset(&decode->op[0], MO_32, dest_word)); + } + + if (new_mask != 15) { + TCGv_i32 zero = tcg_constant_i32(0); /* float32_zero */ + int i; + for (i = 0; i < 4; i++) { + if ((val >> i) & 1) { + tcg_gen_st_i32(zero, cpu_env, + vector_elem_offset(&decode->op[0], MO_32, i)); + } + } + } +} + +static void gen_VINSERTPS_r(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int val = decode->immediate; + tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + vector_elem_offset(&decode->op[2], MO_32, (val >> 6) & 3)); + gen_vinsertps(s, env, decode); +} + +static void gen_VINSERTPS_m(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); + gen_vinsertps(s, env, decode); +} + +static void gen_VINSERTx128(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int mask = decode->immediate & 1; + tcg_gen_gvec_mov(MO_64, + decode->op[0].offset + offsetof(YMMReg, YMM_X(mask)), + decode->op[2].offset + offsetof(YMMReg, YMM_X(0)), 16, 16); + tcg_gen_gvec_mov(MO_64, + decode->op[0].offset + offsetof(YMMReg, YMM_X(!mask)), + decode->op[1].offset + offsetof(YMMReg, YMM_X(!mask)), 16, 16); +} + +static inline void gen_maskmov(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, + SSEFunc_0_eppt xmm, SSEFunc_0_eppt ymm) +{ + if (!s->vex_l) { + xmm(cpu_env, OP_PTR2, OP_PTR1, s->A0); + } else { + ymm(cpu_env, OP_PTR2, OP_PTR1, s->A0); + } +} + +static void gen_VMASKMOVPD_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_maskmov(s, env, decode, gen_helper_vpmaskmovq_st_xmm, gen_helper_vpmaskmovq_st_ymm); +} + +static void gen_VMASKMOVPS_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_maskmov(s, env, decode, gen_helper_vpmaskmovd_st_xmm, gen_helper_vpmaskmovd_st_ymm); +} + +static void gen_VMOVHPx_ld(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_ldq_env_A0(s, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + if (decode->op[0].offset != decode->op[1].offset) { + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + } +} + +static void gen_VMOVHPx_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_stq_env_A0(s, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); +} + +static void gen_VMOVHPx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if (decode->op[0].offset != decode->op[2].offset) { + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + } + if (decode->op[0].offset != decode->op[1].offset) { + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + } +} + +static void gen_VMOVHLPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + if (decode->op[0].offset != decode->op[1].offset) { + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + } +} + +static void gen_VMOVLHPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(1))); + if (decode->op[0].offset != decode->op[1].offset) { + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); + } +} + +/* + * Note that MOVLPx supports 256-bit operation unlike MOVHLPx, MOVLHPx, MOXHPx. + * Use a gvec move to move everything above the bottom 64 bits. + */ + +static void gen_VMOVLPx(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[2].offset + offsetof(XMMReg, XMM_Q(0))); + tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset + offsetof(XMMReg, XMM_Q(0))); +} + +static void gen_VMOVLPx_ld(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); + tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len); + tcg_gen_st_i64(s->tmp1_i64, OP_PTR0, offsetof(ZMMReg, ZMM_Q(0))); +} + +static void gen_VMOVLPx_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_ld_i64(s->tmp1_i64, OP_PTR2, offsetof(ZMMReg, ZMM_Q(0))); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); +} + +static void gen_VMOVSD_ld(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i64 zero = tcg_constant_i64(0); + + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); + tcg_gen_st_i64(zero, OP_PTR0, offsetof(ZMMReg, ZMM_Q(1))); + tcg_gen_st_i64(s->tmp1_i64, OP_PTR0, offsetof(ZMMReg, ZMM_Q(0))); +} + +static void gen_VMOVSS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + tcg_gen_ld_i32(s->tmp2_i32, OP_PTR2, offsetof(ZMMReg, ZMM_L(0))); + tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len); + tcg_gen_st_i32(s->tmp2_i32, OP_PTR0, offsetof(ZMMReg, ZMM_L(0))); +} + +static void gen_VMOVSS_ld(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int vec_len = vector_len(s, decode); + + tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); + tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); + tcg_gen_st_i32(s->tmp2_i32, OP_PTR0, offsetof(ZMMReg, ZMM_L(0))); +} + +static void gen_VMOVSS_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_ld_i32(s->tmp2_i32, OP_PTR2, offsetof(ZMMReg, ZMM_L(0))); + tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); +} + +static void gen_VPMASKMOV_st(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if (s->vex_w) { + gen_VMASKMOVPD_st(s, env, decode); + } else { + gen_VMASKMOVPS_st(s, env, decode); + } +} + +static void gen_VPERMD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + assert(s->vex_l); + gen_helper_vpermd_ymm(OP_PTR0, OP_PTR1, OP_PTR2); +} + +static void gen_VPERM2x128(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + assert(s->vex_l); + gen_helper_vpermdq_ymm(OP_PTR0, OP_PTR1, OP_PTR2, imm); +} + +static void gen_VPHMINPOSUW(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + assert(!s->vex_l); + gen_helper_phminposuw_xmm(cpu_env, OP_PTR0, OP_PTR2); +} + +static void gen_VROUNDSD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + assert(!s->vex_l); + gen_helper_roundsd_xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); +} + +static void gen_VROUNDSS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant8u_i32(decode->immediate); + assert(!s->vex_l); + gen_helper_roundss_xmm(cpu_env, OP_PTR0, OP_PTR1, OP_PTR2, imm); +} + +static void gen_VSHUF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_i32 imm = tcg_constant_i32(decode->immediate); + SSEFunc_0_pppi ps, pd, fn; + ps = s->vex_l ? gen_helper_shufps_ymm : gen_helper_shufps_xmm; + pd = s->vex_l ? gen_helper_shufpd_ymm : gen_helper_shufpd_xmm; + fn = s->prefix & PREFIX_DATA ? pd : ps; + fn(OP_PTR0, OP_PTR1, OP_PTR2, imm); +} + +static void gen_VUCOMI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + SSEFunc_0_epp fn; + fn = s->prefix & PREFIX_DATA ? gen_helper_ucomisd : gen_helper_ucomiss; + fn(cpu_env, OP_PTR1, OP_PTR2); + set_cc_op(s, CC_OP_EFLAGS); +} + +static void gen_VZEROALL(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + TCGv_ptr ptr = tcg_temp_new_ptr(); + + tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_t0)); + gen_helper_memset(ptr, ptr, tcg_constant_i32(0), + tcg_constant_ptr(CPU_NB_REGS * sizeof(ZMMReg))); + tcg_temp_free_ptr(ptr); +} + +static void gen_VZEROUPPER(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int i; + + for (i = 0; i < CPU_NB_REGS; i++) { + int offset = offsetof(CPUX86State, xmm_regs[i].ZMM_X(1)); + tcg_gen_gvec_dup_imm(MO_64, offset, 16, 16, 0); + } +} diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index bdae887d0abc..7c3c8dc7fe84 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -25,13 +25,13 @@ #include "exec/helper-proto.h" #include "helper-tcg.h" -void QEMU_NORETURN helper_raise_interrupt(CPUX86State *env, int intno, +G_NORETURN void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend) { raise_interrupt(env, intno, 1, 0, next_eip_addend); } -void QEMU_NORETURN helper_raise_exception(CPUX86State *env, int exception_index) +G_NORETURN void helper_raise_exception(CPUX86State *env, int exception_index) { raise_exception(env, exception_index); } @@ -87,10 +87,11 @@ static int check_exception(CPUX86State *env, int intno, int *error_code, * env->eip value AFTER the interrupt instruction. It is only relevant if * is_int is TRUE. */ -static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, - int is_int, int error_code, - int next_eip_addend, - uintptr_t retaddr) +static G_NORETURN +void raise_interrupt2(CPUX86State *env, int intno, + int is_int, int error_code, + int next_eip_addend, + uintptr_t retaddr) { CPUState *cs = env_cpu(env); @@ -111,31 +112,44 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, /* shortcuts to generate exceptions */ -void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int, - int error_code, int next_eip_addend) +G_NORETURN void raise_interrupt(CPUX86State *env, int intno, int is_int, + int error_code, int next_eip_addend) { raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0); } -void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index, - int error_code) +G_NORETURN void raise_exception_err(CPUX86State *env, int exception_index, + int error_code) { raise_interrupt2(env, exception_index, 0, error_code, 0, 0); } -void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int exception_index, - int error_code, uintptr_t retaddr) +G_NORETURN void raise_exception_err_ra(CPUX86State *env, int exception_index, + int error_code, uintptr_t retaddr) { raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr); } -void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index) +G_NORETURN void raise_exception(CPUX86State *env, int exception_index) { raise_interrupt2(env, exception_index, 0, 0, 0, 0); } -void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index, - uintptr_t retaddr) +G_NORETURN void raise_exception_ra(CPUX86State *env, int exception_index, + uintptr_t retaddr) { 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/fpu_helper.c b/target/i386/tcg/fpu_helper.c index ebf5e73df9fc..6f3741b63544 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -32,7 +32,8 @@ #define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) #define ST1 ST(1) -#define FPU_RC_MASK 0xc00 +#define FPU_RC_SHIFT 10 +#define FPU_RC_MASK (3 << FPU_RC_SHIFT) #define FPU_RC_NEAR 0x000 #define FPU_RC_DOWN 0x400 #define FPU_RC_UP 0x800 @@ -685,28 +686,26 @@ uint32_t helper_fnstcw(CPUX86State *env) return env->fpuc; } +static void set_x86_rounding_mode(unsigned mode, float_status *status) +{ + static FloatRoundMode x86_round_mode[4] = { + float_round_nearest_even, + float_round_down, + float_round_up, + float_round_to_zero + }; + assert(mode < ARRAY_SIZE(x86_round_mode)); + set_float_rounding_mode(x86_round_mode[mode], status); +} + void update_fp_status(CPUX86State *env) { - FloatRoundMode rnd_mode; + int rnd_mode; FloatX80RoundPrec rnd_prec; /* set rounding mode */ - switch (env->fpuc & FPU_RC_MASK) { - default: - case FPU_RC_NEAR: - rnd_mode = float_round_nearest_even; - break; - case FPU_RC_DOWN: - rnd_mode = float_round_down; - break; - case FPU_RC_UP: - rnd_mode = float_round_up; - break; - case FPU_RC_CHOP: - rnd_mode = float_round_to_zero; - break; - } - set_float_rounding_mode(rnd_mode, &env->fp_status); + rnd_mode = (env->fpuc & FPU_RC_MASK) >> FPU_RC_SHIFT; + set_x86_rounding_mode(rnd_mode, &env->fp_status); switch ((env->fpuc >> 8) & 3) { case 0: @@ -2466,7 +2465,7 @@ static void do_fsave(CPUX86State *env, target_ulong ptr, int data32, do_fstenv(env, ptr, data32, retaddr); - ptr += (14 << data32); + ptr += (target_ulong)14 << data32; for (i = 0; i < 8; i++) { tmp = ST(i); do_fstt(env, tmp, ptr, retaddr); @@ -2488,7 +2487,7 @@ static void do_frstor(CPUX86State *env, target_ulong ptr, int data32, int i; do_fldenv(env, ptr, data32, retaddr); - ptr += (14 << data32); + ptr += (target_ulong)14 << data32; for (i = 0; i < 8; i++) { tmp = do_fldt(env, ptr, retaddr); @@ -2502,18 +2501,6 @@ void helper_frstor(CPUX86State *env, target_ulong ptr, int data32) do_frstor(env, ptr, data32, GETPC()); } -#if defined(CONFIG_USER_ONLY) -void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32) -{ - do_fsave(env, ptr, data32, 0); -} - -void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32) -{ - do_frstor(env, ptr, data32, 0); -} -#endif - #define XO(X) offsetof(X86XSaveArea, X) static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) @@ -2571,6 +2558,22 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) } } +static void do_xsave_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra) +{ + int i, nb_xmm_regs; + + if (env->hflags & HF_CS64_MASK) { + nb_xmm_regs = 16; + } else { + nb_xmm_regs = 8; + } + + for (i = 0; i < nb_xmm_regs; i++, ptr += 16) { + cpu_stq_data_ra(env, ptr, env->xmm_regs[i].ZMM_Q(2), ra); + cpu_stq_data_ra(env, ptr + 8, env->xmm_regs[i].ZMM_Q(3), ra); + } +} + static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra) { target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs); @@ -2663,6 +2666,9 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm, if (opt & XSTATE_SSE_MASK) { do_xsave_sse(env, ptr, ra); } + if (opt & XSTATE_YMM_MASK) { + do_xsave_ymmh(env, ptr + XO(avx_state), ra); + } if (opt & XSTATE_BNDREGS_MASK) { do_xsave_bndregs(env, ptr + XO(bndreg_state), ra); } @@ -2737,6 +2743,54 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) } } +static void do_clear_sse(CPUX86State *env) +{ + int i, nb_xmm_regs; + + if (env->hflags & HF_CS64_MASK) { + nb_xmm_regs = 16; + } else { + nb_xmm_regs = 8; + } + + for (i = 0; i < nb_xmm_regs; i++) { + env->xmm_regs[i].ZMM_Q(0) = 0; + env->xmm_regs[i].ZMM_Q(1) = 0; + } +} + +static void do_xrstor_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra) +{ + int i, nb_xmm_regs; + + if (env->hflags & HF_CS64_MASK) { + nb_xmm_regs = 16; + } else { + nb_xmm_regs = 8; + } + + for (i = 0; i < nb_xmm_regs; i++, ptr += 16) { + env->xmm_regs[i].ZMM_Q(2) = cpu_ldq_data_ra(env, ptr, ra); + env->xmm_regs[i].ZMM_Q(3) = cpu_ldq_data_ra(env, ptr + 8, ra); + } +} + +static void do_clear_ymmh(CPUX86State *env) +{ + int i, nb_xmm_regs; + + if (env->hflags & HF_CS64_MASK) { + nb_xmm_regs = 16; + } else { + nb_xmm_regs = 8; + } + + for (i = 0; i < nb_xmm_regs; i++) { + env->xmm_regs[i].ZMM_Q(2) = 0; + env->xmm_regs[i].ZMM_Q(3) = 0; + } +} + static void do_xrstor_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra) { target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs); @@ -2787,21 +2841,8 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr) do_fxrstor(env, ptr, GETPC()); } -#if defined(CONFIG_USER_ONLY) -void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr) -{ - do_fxsave(env, ptr, 0); -} - -void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr) -{ - do_fxrstor(env, ptr, 0); -} -#endif - -void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) +static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr_t ra) { - uintptr_t ra = GETPC(); uint64_t xstate_bv, xcomp_bv, reserve0; rfbm &= env->xcr0; @@ -2856,9 +2897,14 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) if (xstate_bv & XSTATE_SSE_MASK) { do_xrstor_sse(env, ptr, ra); } else { - /* ??? When AVX is implemented, we may have to be more - selective in the clearing. */ - memset(env->xmm_regs, 0, sizeof(env->xmm_regs)); + do_clear_sse(env); + } + } + if (rfbm & XSTATE_YMM_MASK) { + if (xstate_bv & XSTATE_YMM_MASK) { + do_xrstor_ymmh(env, ptr + XO(avx_state), ra); + } else { + do_clear_ymmh(env); } } if (rfbm & XSTATE_BNDREGS_MASK) { @@ -2894,6 +2940,43 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) #undef XO +void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) +{ + do_xrstor(env, ptr, rfbm, GETPC()); +} + +#if defined(CONFIG_USER_ONLY) +void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32) +{ + do_fsave(env, ptr, data32, 0); +} + +void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32) +{ + do_frstor(env, ptr, data32, 0); +} + +void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr) +{ + do_fxsave(env, ptr, 0); +} + +void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr) +{ + do_fxrstor(env, ptr, 0); +} + +void cpu_x86_xsave(CPUX86State *env, target_ulong ptr) +{ + do_xsave(env, ptr, -1, get_xinuse(env), -1, 0); +} + +void cpu_x86_xrstor(CPUX86State *env, target_ulong ptr) +{ + do_xrstor(env, ptr, -1, 0); +} +#endif + uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx) { /* The OS must have enabled XSAVE. */ @@ -2943,6 +3026,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask) env->xcr0 = mask; cpu_sync_bndcs_hflags(env); + cpu_sync_avx_hflag(env); return; do_gpf: @@ -2953,11 +3037,8 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask) /* XXX: optimize by storing fptt and fptags in the static cpu state */ #define SSE_DAZ 0x0040 -#define SSE_RC_MASK 0x6000 -#define SSE_RC_NEAR 0x0000 -#define SSE_RC_DOWN 0x2000 -#define SSE_RC_UP 0x4000 -#define SSE_RC_CHOP 0x6000 +#define SSE_RC_SHIFT 13 +#define SSE_RC_MASK (3 << SSE_RC_SHIFT) #define SSE_FZ 0x8000 void update_mxcsr_status(CPUX86State *env) @@ -2966,22 +3047,8 @@ void update_mxcsr_status(CPUX86State *env) int rnd_type; /* set rounding mode */ - switch (mxcsr & SSE_RC_MASK) { - default: - case SSE_RC_NEAR: - rnd_type = float_round_nearest_even; - break; - case SSE_RC_DOWN: - rnd_type = float_round_down; - break; - case SSE_RC_UP: - rnd_type = float_round_up; - break; - case SSE_RC_CHOP: - rnd_type = float_round_to_zero; - break; - } - set_float_rounding_mode(rnd_type, &env->sse_status); + rnd_type = (mxcsr & SSE_RC_MASK) >> SSE_RC_SHIFT; + set_x86_rounding_mode(rnd_type, &env->sse_status); /* Set exception flags. */ set_float_exception_flags((mxcsr & FPUS_IE ? float_flag_invalid : 0) | @@ -3041,14 +3108,11 @@ void helper_emms(CPUX86State *env) *(uint32_t *)(env->fptags + 4) = 0x01010101; } -/* XXX: suppress */ -void helper_movq(CPUX86State *env, void *d, void *s) -{ - *(uint64_t *)d = *(uint64_t *)s; -} - #define SHIFT 0 #include "ops_sse.h" #define SHIFT 1 #include "ops_sse.h" + +#define SHIFT 2 +#include "ops_sse.h" diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index 0a4401e917f9..cd1723389ada 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 */ @@ -69,27 +58,44 @@ static inline target_long lshift(target_long x, int n) void tcg_x86_init(void); /* excp_helper.c */ -void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index); -void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index, - uintptr_t retaddr); -void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index, - int error_code); -void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int exception_index, - int error_code, uintptr_t retaddr); -void QEMU_NORETURN raise_interrupt(CPUX86State *nenv, int intno, int is_int, - int error_code, int next_eip_addend); +G_NORETURN void raise_exception(CPUX86State *env, int exception_index); +G_NORETURN void raise_exception_ra(CPUX86State *env, int exception_index, + uintptr_t retaddr); +G_NORETURN void raise_exception_err(CPUX86State *env, int exception_index, + int error_code); +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]; /* misc_helper.c */ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask); -void do_pause(CPUX86State *env) QEMU_NORETURN; +G_NORETURN void do_pause(CPUX86State *env); /* sysemu/svm_helper.c */ #ifndef CONFIG_USER_ONLY -void QEMU_NORETURN cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, - uint64_t exit_info_1, uintptr_t retaddr); +G_NORETURN void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, + uint64_t exit_info_1, uintptr_t retaddr); void do_vmexit(CPUX86State *env); #endif diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index 24a0eaa3d596..5f7a3061ca59 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -81,7 +81,7 @@ void helper_rdtscp(CPUX86State *env) env->regs[R_ECX] = (uint32_t)(env->tsc_aux); } -void QEMU_NORETURN helper_rdpmc(CPUX86State *env) +G_NORETURN void helper_rdpmc(CPUX86State *env) { if (((env->cr[4] & CR4_PCE_MASK) == 0 ) && ((env->hflags & HF_CPL_MASK) != 0)) { @@ -94,7 +94,7 @@ void QEMU_NORETURN helper_rdpmc(CPUX86State *env) raise_exception_err(env, EXCP06_ILLOP, 0); } -void QEMU_NORETURN do_pause(CPUX86State *env) +G_NORETURN void do_pause(CPUX86State *env) { CPUState *cs = env_cpu(env); @@ -103,7 +103,7 @@ void QEMU_NORETURN do_pause(CPUX86State *env) cpu_loop_exit(cs); } -void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend) +G_NORETURN void helper_pause(CPUX86State *env, int next_eip_addend) { cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC()); env->eip += next_eip_addend; diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index bffd82923f1a..03b58e94a2d4 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -882,7 +882,7 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, dt = &env->idt; if (intno * 16 + 15 > dt->limit) { - raise_exception_err(env, EXCP0D_GPF, intno * 16 + 2); + raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2); } ptr = dt->base + intno * 16; e1 = cpu_ldl_kernel(env, ptr); @@ -895,18 +895,18 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, case 15: /* 386 trap gate */ break; default: - raise_exception_err(env, EXCP0D_GPF, intno * 16 + 2); + raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2); break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privilege if software int */ if (is_int && dpl < cpl) { - raise_exception_err(env, EXCP0D_GPF, intno * 16 + 2); + raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2); } /* check valid bit */ if (!(e2 & DESC_P_MASK)) { - raise_exception_err(env, EXCP0B_NOSEG, intno * 16 + 2); + raise_exception_err(env, EXCP0B_NOSEG, intno * 8 + 2); } selector = e1 >> 16; offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); @@ -1504,14 +1504,12 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip, } /* real mode call */ -void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1, - int shift, int next_eip) +void helper_lcall_real(CPUX86State *env, uint32_t new_cs, uint32_t new_eip, + int shift, uint32_t next_eip) { - int new_eip; uint32_t esp, esp_mask; target_ulong ssp; - new_eip = new_eip1; esp = env->regs[R_ESP]; esp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index e1b6d8868338..55bd1194d31b 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -22,150 +22,275 @@ #include "exec/exec-all.h" #include "tcg/helper-tcg.h" -#define PG_ERROR_OK (-1) +typedef struct TranslateParams { + target_ulong addr; + target_ulong cr3; + int pg_mode; + int mmu_idx; + int ptw_idx; + MMUAccessType access_type; +} TranslateParams; + +typedef struct TranslateResult { + hwaddr paddr; + int prot; + int page_size; +} TranslateResult; + +typedef enum TranslateFaultStage2 { + S2_NONE, + S2_GPA, + S2_GPT, +} TranslateFaultStage2; + +typedef struct TranslateFault { + int exception_index; + int error_code; + target_ulong cr2; + TranslateFaultStage2 stage2; +} TranslateFault; + +typedef struct PTETranslate { + CPUX86State *env; + TranslateFault *err; + int ptw_idx; + void *haddr; + hwaddr gaddr; +} PTETranslate; + +static bool ptw_translate(PTETranslate *inout, hwaddr addr) +{ + CPUTLBEntryFull *full; + int flags; + + inout->gaddr = addr; + flags = probe_access_full(inout->env, addr, MMU_DATA_STORE, + inout->ptw_idx, true, &inout->haddr, &full, 0); + + if (unlikely(flags & TLB_INVALID_MASK)) { + TranslateFault *err = inout->err; + + assert(inout->ptw_idx == MMU_NESTED_IDX); + *err = (TranslateFault){ + .error_code = inout->env->error_code, + .cr2 = addr, + .stage2 = S2_GPT, + }; + return false; + } + return true; +} + +static inline uint32_t ptw_ldl(const PTETranslate *in) +{ + if (likely(in->haddr)) { + return ldl_p(in->haddr); + } + return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0); +} + +static inline uint64_t ptw_ldq(const PTETranslate *in) +{ + if (likely(in->haddr)) { + return ldq_p(in->haddr); + } + return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0); +} -typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type, - int *prot); +/* + * Note that we can use a 32-bit cmpxchg for all page table entries, + * even 64-bit ones, because PG_PRESENT_MASK, PG_ACCESSED_MASK and + * PG_DIRTY_MASK are all in the low 32 bits. + */ +static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new) +{ + uint32_t cmp; -#define GET_HPHYS(cs, gpa, access_type, prot) \ - (get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa) + /* Does x86 really perform a rmw cycle on mmio for ptw? */ + start_exclusive(); + cmp = cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0); + if (cmp == old) { + cpu_stl_mmuidx_ra(in->env, in->gaddr, new, in->ptw_idx, 0); + } + end_exclusive(); + return cmp == old; +} -static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_func, - uint64_t cr3, int is_write1, int mmu_idx, int pg_mode, - hwaddr *xlat, int *page_size, int *prot) +static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set) { - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint64_t ptep, pte; - int32_t a20_mask; - target_ulong pde_addr, pte_addr; - int error_code = 0; - int is_dirty, is_write, is_user; - uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); - uint32_t page_offset; - uint32_t pkr; + if (set & ~old) { + uint32_t new = old | set; + if (likely(in->haddr)) { + old = cpu_to_le32(old); + new = cpu_to_le32(new); + return qatomic_cmpxchg((uint32_t *)in->haddr, old, new) == old; + } + return ptw_setl_slow(in, old, new); + } + return true; +} - is_user = (mmu_idx == MMU_USER_IDX); - is_write = is_write1 & 1; - a20_mask = x86_get_a20_mask(env); +static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + TranslateResult *out, TranslateFault *err) +{ + const int32_t a20_mask = x86_get_a20_mask(env); + const target_ulong addr = in->addr; + const int pg_mode = in->pg_mode; + const bool is_user = (in->mmu_idx == MMU_USER_IDX); + const MMUAccessType access_type = in->access_type; + uint64_t ptep, pte, rsvd_mask; + PTETranslate pte_trans = { + .env = env, + .err = err, + .ptw_idx = in->ptw_idx, + }; + hwaddr pte_addr, paddr; + uint32_t pkr; + int page_size; + restart_all: + rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits); + rsvd_mask &= PG_ADDRESS_MASK; if (!(pg_mode & PG_MODE_NXE)) { rsvd_mask |= PG_NX_MASK; } if (pg_mode & PG_MODE_PAE) { - uint64_t pde, pdpe; - target_ulong pdpe_addr; - #ifdef TARGET_X86_64 if (pg_mode & PG_MODE_LMA) { - bool la57 = pg_mode & PG_MODE_LA57; - uint64_t pml5e_addr, pml5e; - uint64_t pml4e_addr, pml4e; - - if (la57) { - pml5e_addr = ((cr3 & ~0xfff) + - (((addr >> 48) & 0x1ff) << 3)) & a20_mask; - pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL); - pml5e = x86_ldq_phys(cs, pml5e_addr); - if (!(pml5e & PG_PRESENT_MASK)) { + if (pg_mode & PG_MODE_LA57) { + /* + * Page table level 5 + */ + pte_addr = ((in->cr3 & ~0xfff) + + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } + restart_5: + pte = ptw_ldq(&pte_trans); + if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } - if (pml5e & (rsvd_mask | PG_PSE_MASK)) { + if (pte & (rsvd_mask | PG_PSE_MASK)) { goto do_fault_rsvd; } - if (!(pml5e & PG_ACCESSED_MASK)) { - pml5e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); + if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) { + goto restart_5; } - ptep = pml5e ^ PG_NX_MASK; + ptep = pte ^ PG_NX_MASK; } else { - pml5e = cr3; + pte = in->cr3; ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; } - pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + - (((addr >> 39) & 0x1ff) << 3)) & a20_mask; - pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL); - pml4e = x86_ldq_phys(cs, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { + /* + * Page table level 4 + */ + pte_addr = ((pte & PG_ADDRESS_MASK) + + (((addr >> 39) & 0x1ff) << 3)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } + restart_4: + pte = ptw_ldq(&pte_trans); + if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } - if (pml4e & (rsvd_mask | PG_PSE_MASK)) { + if (pte & (rsvd_mask | PG_PSE_MASK)) { goto do_fault_rsvd; } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); + if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) { + goto restart_4; + } + ptep &= pte ^ PG_NX_MASK; + + /* + * Page table level 3 + */ + pte_addr = ((pte & PG_ADDRESS_MASK) + + (((addr >> 30) & 0x1ff) << 3)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; } - ptep &= pml4e ^ PG_NX_MASK; - pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & - a20_mask; - pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { + restart_3_lma: + pte = ptw_ldq(&pte_trans); + if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } - if (pdpe & rsvd_mask) { + if (pte & rsvd_mask) { goto do_fault_rsvd; } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); + if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) { + goto restart_3_lma; } - if (pdpe & PG_PSE_MASK) { + ptep &= pte ^ PG_NX_MASK; + if (pte & PG_PSE_MASK) { /* 1 GB page */ - *page_size = 1024 * 1024 * 1024; - pte_addr = pdpe_addr; - pte = pdpe; + page_size = 1024 * 1024 * 1024; goto do_check_protect; } } else #endif { - /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & - a20_mask; - pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; + /* + * Page table level 3 + */ + pte_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; } rsvd_mask |= PG_HI_USER_MASK; - if (pdpe & (rsvd_mask | PG_NX_MASK)) { + restart_3_nolma: + pte = ptw_ldq(&pte_trans); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pte & (rsvd_mask | PG_NX_MASK)) { goto do_fault_rsvd; } + if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) { + goto restart_3_nolma; + } ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; } - pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & - a20_mask; - pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); - pde = x86_ldq_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { + /* + * Page table level 2 + */ + pte_addr = ((pte & PG_ADDRESS_MASK) + + (((addr >> 21) & 0x1ff) << 3)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } + restart_2_pae: + pte = ptw_ldq(&pte_trans); + if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } - if (pde & rsvd_mask) { + if (pte & rsvd_mask) { goto do_fault_rsvd; } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { + if (pte & PG_PSE_MASK) { /* 2 MB page */ - *page_size = 2048 * 1024; - pte_addr = pde_addr; - pte = pde; + page_size = 2048 * 1024; + ptep &= pte ^ PG_NX_MASK; goto do_check_protect; } - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); + if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) { + goto restart_2_pae; + } + ptep &= pte ^ PG_NX_MASK; + + /* + * Page table level 1 + */ + pte_addr = ((pte & PG_ADDRESS_MASK) + + (((addr >> 12) & 0x1ff) << 3)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; } - pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & - a20_mask; - pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); - pte = x86_ldq_phys(cs, pte_addr); + pte = ptw_ldq(&pte_trans); if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -174,54 +299,56 @@ static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_f } /* combine pde and pte nx, user and rw protections */ ptep &= pte ^ PG_NX_MASK; - *page_size = 4096; + page_size = 4096; } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & - a20_mask; - pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); - pde = x86_ldl_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { + /* + * Page table level 2 + */ + pte_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } + restart_2_nopae: + pte = ptw_ldl(&pte_trans); + if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } - ptep = pde | PG_NX_MASK; + ptep = pte | PG_NX_MASK; /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { - *page_size = 4096 * 1024; - pte_addr = pde_addr; - - /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. + if ((pte & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { + page_size = 4096 * 1024; + /* + * Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. * Leave bits 20-13 in place for setting accessed/dirty bits below. */ - pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); + pte = (uint32_t)pte | ((pte & 0x1fe000LL) << (32 - 13)); rsvd_mask = 0x200000; goto do_check_protect_pse36; } - - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); + if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) { + goto restart_2_nopae; } - /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & - a20_mask; - pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); - pte = x86_ldl_phys(cs, pte_addr); + /* + * Page table level 1 + */ + pte_addr = ((pte & ~0xfffu) + ((addr >> 10) & 0xffc)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } + pte = ptw_ldl(&pte_trans); if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } /* combine pde and pte user and rw protections */ ptep &= pte | PG_NX_MASK; - *page_size = 4096; + page_size = 4096; rsvd_mask = 0; } do_check_protect: - rsvd_mask |= (*page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; + rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; do_check_protect_pse36: if (pte & rsvd_mask) { goto do_fault_rsvd; @@ -233,17 +360,17 @@ static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_f goto do_fault_protect; } - *prot = 0; - if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { - *prot |= PAGE_READ; + int prot = 0; + if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { + prot |= PAGE_READ; if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { - *prot |= PAGE_WRITE; + prot |= PAGE_WRITE; } } if (!(ptep & PG_NX_MASK) && - (mmu_idx == MMU_USER_IDX || + (is_user || !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { - *prot |= PAGE_EXEC; + prot |= PAGE_EXEC; } if (ptep & PG_USER_MASK) { @@ -262,178 +389,255 @@ static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_f } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { pkr_prot &= ~PAGE_WRITE; } - - *prot &= pkr_prot; - if ((pkr_prot & (1 << is_write1)) == 0) { - assert(is_write1 != 2); - error_code |= PG_ERROR_PK_MASK; - goto do_fault_protect; + if ((pkr_prot & (1 << access_type)) == 0) { + goto do_fault_pk_protect; } + prot &= pkr_prot; } - if ((*prot & (1 << is_write1)) == 0) { + if ((prot & (1 << access_type)) == 0) { goto do_fault_protect; } /* yes, it can! */ - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) { - pte |= PG_DIRTY_MASK; + { + uint32_t set = PG_ACCESSED_MASK; + if (access_type == MMU_DATA_STORE) { + set |= PG_DIRTY_MASK; + } else if (!(pte & PG_DIRTY_MASK)) { + /* + * Only set write access if already dirty... + * otherwise wait for dirty access. + */ + prot &= ~PAGE_WRITE; + } + if (!ptw_setl(&pte_trans, pte, set)) { + /* + * We can arrive here from any of 3 levels and 2 formats. + * The only safe thing is to restart the entire lookup. + */ + goto restart_all; } - x86_stl_phys_notdirty(cs, pte_addr, pte); } - if (!(pte & PG_DIRTY_MASK)) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - assert(!is_write); - *prot &= ~PAGE_WRITE; - } + /* align to page_size */ + paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) + | (addr & (page_size - 1)); + + if (in->ptw_idx == MMU_NESTED_IDX) { + CPUTLBEntryFull *full; + int flags, nested_page_size; + + flags = probe_access_full(env, paddr, access_type, + MMU_NESTED_IDX, true, + &pte_trans.haddr, &full, 0); + if (unlikely(flags & TLB_INVALID_MASK)) { + *err = (TranslateFault){ + .error_code = env->error_code, + .cr2 = paddr, + .stage2 = S2_GPA, + }; + return false; + } - pte = pte & a20_mask; + /* Merge stage1 & stage2 protection bits. */ + prot &= full->prot; - /* align to page_size */ - pte &= PG_ADDRESS_MASK & ~(*page_size - 1); - page_offset = addr & (*page_size - 1); - *xlat = GET_HPHYS(cs, pte + page_offset, is_write1, prot); - return PG_ERROR_OK; + /* Re-verify resulting protection. */ + if ((prot & (1 << access_type)) == 0) { + goto do_fault_protect; + } + + /* Merge stage1 & stage2 addresses to final physical address. */ + nested_page_size = 1 << full->lg_page_size; + paddr = (full->phys_addr & ~(nested_page_size - 1)) + | (paddr & (nested_page_size - 1)); + + /* + * Use the larger of stage1 & stage2 page sizes, so that + * invalidation works. + */ + if (nested_page_size > page_size) { + page_size = nested_page_size; + } + } + out->paddr = paddr; + out->prot = prot; + out->page_size = page_size; + return true; + + int error_code; do_fault_rsvd: - error_code |= PG_ERROR_RSVD_MASK; + error_code = PG_ERROR_RSVD_MASK; + goto do_fault_cont; do_fault_protect: - error_code |= PG_ERROR_P_MASK; + error_code = PG_ERROR_P_MASK; + goto do_fault_cont; + do_fault_pk_protect: + assert(access_type != MMU_INST_FETCH); + error_code = PG_ERROR_PK_MASK | PG_ERROR_P_MASK; + goto do_fault_cont; do_fault: - error_code |= (is_write << PG_ERROR_W_BIT); - if (is_user) + error_code = 0; + do_fault_cont: + if (is_user) { error_code |= PG_ERROR_U_MASK; - if (is_write1 == 2 && - ((pg_mode & PG_MODE_NXE) || (pg_mode & PG_MODE_SMEP))) - error_code |= PG_ERROR_I_D_MASK; - return error_code; + } + switch (access_type) { + case MMU_DATA_LOAD: + break; + case MMU_DATA_STORE: + error_code |= PG_ERROR_W_MASK; + break; + case MMU_INST_FETCH: + if (pg_mode & (PG_MODE_NXE | PG_MODE_SMEP)) { + error_code |= PG_ERROR_I_D_MASK; + } + break; + } + *err = (TranslateFault){ + .exception_index = EXCP0E_PAGE, + .error_code = error_code, + .cr2 = addr, + }; + return false; } -hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, - int *prot) +static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err, + uintptr_t retaddr) { - CPUX86State *env = &X86_CPU(cs)->env; - uint64_t exit_info_1; - int page_size; - int next_prot; - hwaddr hphys; + uint64_t exit_info_1 = err->error_code; - if (likely(!(env->hflags2 & HF2_NPT_MASK))) { - return gphys; + switch (err->stage2) { + case S2_GPT: + exit_info_1 |= SVM_NPTEXIT_GPT; + break; + case S2_GPA: + exit_info_1 |= SVM_NPTEXIT_GPA; + break; + default: + g_assert_not_reached(); } - exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3, - access_type, MMU_USER_IDX, env->nested_pg_mode, - &hphys, &page_size, &next_prot); - if (exit_info_1 == PG_ERROR_OK) { - if (prot) { - *prot &= next_prot; + x86_stq_phys(env_cpu(env), + env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + err->cr2); + cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr); +} + +static bool get_physical_address(CPUX86State *env, vaddr addr, + MMUAccessType access_type, int mmu_idx, + TranslateResult *out, TranslateFault *err) +{ + TranslateParams in; + bool use_stage2 = env->hflags2 & HF2_NPT_MASK; + + in.addr = addr; + in.access_type = access_type; + + switch (mmu_idx) { + case MMU_PHYS_IDX: + break; + + case MMU_NESTED_IDX: + if (likely(use_stage2)) { + in.cr3 = env->nested_cr3; + in.pg_mode = env->nested_pg_mode; + in.mmu_idx = MMU_USER_IDX; + in.ptw_idx = MMU_PHYS_IDX; + + if (!mmu_translate(env, &in, out, err)) { + err->stage2 = S2_GPA; + return false; + } + return true; } - return hphys; + break; + + default: + if (likely(env->cr[0] & CR0_PG_MASK)) { + in.cr3 = env->cr[3]; + in.mmu_idx = mmu_idx; + in.ptw_idx = use_stage2 ? MMU_NESTED_IDX : MMU_PHYS_IDX; + in.pg_mode = get_pg_mode(env); + + if (in.pg_mode & PG_MODE_LMA) { + /* test virtual address sign extension */ + int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47; + int64_t sext = (int64_t)addr >> shift; + if (sext != 0 && sext != -1) { + *err = (TranslateFault){ + .exception_index = EXCP0D_GPF, + .cr2 = addr, + }; + return false; + } + } + return mmu_translate(env, &in, out, err); + } + break; } - x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - gphys); - if (prot) { - exit_info_1 |= SVM_NPTEXIT_GPA; - } else { /* page table access */ - exit_info_1 |= SVM_NPTEXIT_GPT; + /* Translation disabled. */ + out->paddr = addr & x86_get_a20_mask(env); +#ifdef TARGET_X86_64 + if (!(env->hflags & HF_LMA_MASK)) { + /* Without long mode we can only address 32bits in real mode */ + out->paddr = (uint32_t)out->paddr; } - cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); +#endif + out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + out->page_size = TARGET_PAGE_SIZE; + return true; } -/* return value: - * -1 = cannot handle fault - * 0 = nothing more to do - * 1 = generate PF fault - */ -static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, - int is_write1, int mmu_idx) +bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) { - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - int error_code = PG_ERROR_OK; - int pg_mode, prot, page_size; - hwaddr paddr; - hwaddr vaddr; - -#if defined(DEBUG_MMU) - printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n", - addr, is_write1, mmu_idx, env->eip); -#endif - - if (!(env->cr[0] & CR0_PG_MASK)) { - paddr = addr; -#ifdef TARGET_X86_64 - if (!(env->hflags & HF_LMA_MASK)) { - /* Without long mode we can only address 32bits in real mode */ - paddr = (uint32_t)paddr; - } -#endif - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = 4096; - } else { - pg_mode = get_pg_mode(env); - if (pg_mode & PG_MODE_LMA) { - int32_t sext; - - /* test virtual address sign extension */ - sext = (int64_t)addr >> (pg_mode & PG_MODE_LA57 ? 56 : 47); - if (sext != 0 && sext != -1) { - env->error_code = 0; - cs->exception_index = EXCP0D_GPF; - return 1; - } - } + CPUX86State *env = cs->env_ptr; + TranslateResult out; + TranslateFault err; + + if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) { + /* + * Even if 4MB pages, we map only one 4KB page in the cache to + * avoid filling it too fast. + */ + assert(out.prot & (1 << access_type)); + tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK, + out.paddr & TARGET_PAGE_MASK, + cpu_get_mem_attrs(env), + out.prot, mmu_idx, out.page_size); + return true; + } - error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1, - mmu_idx, pg_mode, - &paddr, &page_size, &prot); + if (probe) { + /* This will be used if recursing for stage2 translation. */ + env->error_code = err.error_code; + return false; } - if (error_code == PG_ERROR_OK) { - /* Even if 4MB pages, we map only one 4KB page in the cache to - avoid filling it too fast */ - vaddr = addr & TARGET_PAGE_MASK; - paddr &= TARGET_PAGE_MASK; + if (err.stage2 != S2_NONE) { + raise_stage2(env, &err, retaddr); + } - assert(prot & (1 << is_write1)); - tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), - prot, mmu_idx, page_size); - return 0; + if (env->intercept_exceptions & (1 << err.exception_index)) { + /* cr2 is not modified in case of exceptions */ + x86_stq_phys(cs, env->vm_vmcb + + offsetof(struct vmcb, control.exit_info_2), + err.cr2); } else { - if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { - /* cr2 is not modified in case of exceptions */ - x86_stq_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - addr); - } else { - env->cr[2] = addr; - } - env->error_code = error_code; - cs->exception_index = EXCP0E_PAGE; - return 1; + env->cr[2] = err.cr2; } + raise_exception_err_ra(env, err.exception_index, err.error_code, retaddr); } -bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, 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) { X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - - env->retaddr = retaddr; - if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { - /* FIXME: On error in get_hphys we have already jumped out. */ - g_assert(!probe); - raise_exception_err_ra(env, cs->exception_index, - env->error_code, retaddr); - } - return true; + handle_unaligned_access(&cpu->env, vaddr, access_type, retaddr); } diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index 3715c1e2625b..e1528b7f80be 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -450,6 +450,11 @@ void helper_rdmsr(CPUX86State *env) case MSR_IA32_UCODE_REV: val = x86_cpu->ucode_rev; break; + case MSR_CORE_THREAD_COUNT: { + CPUState *cs = CPU(x86_cpu); + val = (cs->nr_threads * cs->nr_cores) | (cs->nr_cores << 16); + break; + } default: if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + @@ -471,7 +476,8 @@ void helper_flush_page(CPUX86State *env, target_ulong addr) tlb_flush_page(env_cpu(env), addr); } -static void QEMU_NORETURN do_hlt(CPUX86State *env) +static G_NORETURN +void do_hlt(CPUX86State *env) { CPUState *cs = env_cpu(env); @@ -481,7 +487,7 @@ static void QEMU_NORETURN do_hlt(CPUX86State *env) cpu_loop_exit(cs); } -void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend) +G_NORETURN void helper_hlt(CPUX86State *env, int next_eip_addend) { cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC()); env->eip += next_eip_addend; @@ -498,7 +504,7 @@ void helper_monitor(CPUX86State *env, target_ulong ptr) cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC()); } -void QEMU_NORETURN helper_mwait(CPUX86State *env, int next_eip_addend) +G_NORETURN void helper_mwait(CPUX86State *env, int next_eip_addend) { CPUState *cs = env_cpu(env); diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 2b6f450af959..2d27731b608e 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -27,19 +27,19 @@ /* Secure Virtual Machine helpers */ -static inline void svm_save_seg(CPUX86State *env, hwaddr addr, - const SegmentCache *sc) +static void svm_save_seg(CPUX86State *env, int mmu_idx, hwaddr addr, + const SegmentCache *sc) { - CPUState *cs = env_cpu(env); - - x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector), - sc->selector); - x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base), - sc->base); - x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit), - sc->limit); - x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib), - ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); + cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector), + sc->selector, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base), + sc->base, mmu_idx, 0); + cpu_stl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit), + sc->limit, mmu_idx, 0); + cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib), + ((sc->flags >> 8) & 0xff) + | ((sc->flags >> 12) & 0x0f00), + mmu_idx, 0); } /* @@ -52,29 +52,36 @@ static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt); } -static inline void svm_load_seg(CPUX86State *env, hwaddr addr, - SegmentCache *sc) +static void svm_load_seg(CPUX86State *env, int mmu_idx, hwaddr addr, + SegmentCache *sc) { - CPUState *cs = env_cpu(env); unsigned int flags; - sc->selector = x86_lduw_phys(cs, - addr + offsetof(struct vmcb_seg, selector)); - sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base)); - sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit)); - flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib)); + sc->selector = + cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector), + mmu_idx, 0); + sc->base = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base), + mmu_idx, 0); + sc->limit = + cpu_ldl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit), + mmu_idx, 0); + flags = + cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib), + mmu_idx, 0); sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); + svm_canonicalization(env, &sc->base); } -static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, - int seg_reg) +static void svm_load_seg_cache(CPUX86State *env, int mmu_idx, + hwaddr addr, int seg_reg) { - SegmentCache sc1, *sc = &sc1; + SegmentCache sc; - svm_load_seg(env, addr, sc); - cpu_x86_load_seg_cache(env, seg_reg, sc->selector, - sc->base, sc->limit, sc->flags); + svm_load_seg(env, mmu_idx, addr, &sc); + cpu_x86_load_seg_cache(env, seg_reg, sc.selector, + sc.base, sc.limit, sc.flags); } static inline bool is_efer_invalid_state (CPUX86State *env) @@ -199,13 +206,17 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->vm_hsave + offsetof(struct vmcb, save.rflags), cpu_compute_eflags(env)); - svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.es), &env->segs[R_ES]); - svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.cs), &env->segs[R_CS]); - svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.ss), &env->segs[R_SS]); - svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.ds), &env->segs[R_DS]); x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip), @@ -271,6 +282,8 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->hflags2 |= HF2_NPT_MASK; env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK; + + tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX); } /* enable intercepts */ @@ -323,18 +336,18 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) save.rflags)), ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es), - R_ES); - svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs), - R_CS); - svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss), - R_SS); - svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), - R_DS); - svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr), - &env->idt); - svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr), - &env->gdt); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.es), R_ES); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.cs), R_CS); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.ss), R_SS); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS); + svm_load_seg(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.idtr), &env->idt); + svm_load_seg(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.gdtr), &env->gdt); env->eip = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip)); @@ -449,9 +462,8 @@ void helper_vmmcall(CPUX86State *env) void helper_vmload(CPUX86State *env, int aflag) { - CPUState *cs = env_cpu(env); + int mmu_idx = MMU_PHYS_IDX; target_ulong addr; - int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); @@ -462,43 +474,52 @@ void helper_vmload(CPUX86State *env, int aflag) } if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { - addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot); + mmu_idx = MMU_NESTED_IDX; } - qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx - "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", - addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb, - save.fs.base)), - env->segs[R_FS].base); - - svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS); - svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS); - svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr); - svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt); + svm_load_seg_cache(env, mmu_idx, + addr + offsetof(struct vmcb, save.fs), R_FS); + svm_load_seg_cache(env, mmu_idx, + addr + offsetof(struct vmcb, save.gs), R_GS); + svm_load_seg(env, mmu_idx, + addr + offsetof(struct vmcb, save.tr), &env->tr); + svm_load_seg(env, mmu_idx, + addr + offsetof(struct vmcb, save.ldtr), &env->ldt); #ifdef TARGET_X86_64 - env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb, - save.kernel_gs_base)); - env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar)); - env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar)); - env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask)); + env->kernelgsbase = + cpu_ldq_mmuidx_ra(env, + addr + offsetof(struct vmcb, save.kernel_gs_base), + mmu_idx, 0); + env->lstar = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar), + mmu_idx, 0); + env->cstar = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar), + mmu_idx, 0); + env->fmask = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask), + mmu_idx, 0); svm_canonicalization(env, &env->kernelgsbase); #endif - env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star)); - env->sysenter_cs = x86_ldq_phys(cs, - addr + offsetof(struct vmcb, save.sysenter_cs)); - env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb, - save.sysenter_esp)); - env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb, - save.sysenter_eip)); - + env->star = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star), + mmu_idx, 0); + env->sysenter_cs = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs), + mmu_idx, 0); + env->sysenter_esp = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp), + mmu_idx, 0); + env->sysenter_eip = + cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip), + mmu_idx, 0); } void helper_vmsave(CPUX86State *env, int aflag) { - CPUState *cs = env_cpu(env); + int mmu_idx = MMU_PHYS_IDX; target_ulong addr; - int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); @@ -509,38 +530,36 @@ void helper_vmsave(CPUX86State *env, int aflag) } if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { - addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot); + mmu_idx = MMU_NESTED_IDX; } - qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx - "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", - addr, x86_ldq_phys(cs, - addr + offsetof(struct vmcb, save.fs.base)), - env->segs[R_FS].base); - - svm_save_seg(env, addr + offsetof(struct vmcb, save.fs), + svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.fs), &env->segs[R_FS]); - svm_save_seg(env, addr + offsetof(struct vmcb, save.gs), + svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.gs), &env->segs[R_GS]); - svm_save_seg(env, addr + offsetof(struct vmcb, save.tr), + svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.tr), &env->tr); - svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr), + svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.ldtr), &env->ldt); #ifdef TARGET_X86_64 - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base), - env->kernelgsbase); - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar); - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar); - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.kernel_gs_base), + env->kernelgsbase, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar), + env->lstar, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar), + env->cstar, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask), + env->fmask, mmu_idx, 0); #endif - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star); - x86_stq_phys(cs, - addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp), - env->sysenter_esp); - x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip), - env->sysenter_eip); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star), + env->star, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs), + env->sysenter_cs, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp), + env->sysenter_esp, mmu_idx, 0); + cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip), + env->sysenter_eip, mmu_idx, 0); } void helper_stgi(CPUX86State *env) @@ -685,7 +704,7 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, { CPUState *cs = env_cpu(env); - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", @@ -720,15 +739,20 @@ void do_vmexit(CPUX86State *env) env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); } env->hflags2 &= ~HF2_NPT_MASK; + tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX); /* Save the VM state in the vmcb */ - svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.es), &env->segs[R_ES]); - svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.cs), &env->segs[R_CS]); - svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.ss), &env->segs[R_SS]); - svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), + svm_save_seg(env, MMU_PHYS_IDX, + env->vm_vmcb + offsetof(struct vmcb, save.ds), &env->segs[R_DS]); x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), @@ -809,14 +833,14 @@ void do_vmexit(CPUX86State *env) ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK | VM_MASK)); - svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es), - R_ES); - svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs), - R_CS); - svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss), - R_SS); - svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds), - R_DS); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.es), R_ES); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.cs), R_CS); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.ss), R_SS); + svm_load_seg_cache(env, MMU_PHYS_IDX, + env->vm_hsave + offsetof(struct vmcb, save.ds), R_DS); env->eip = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip)); diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 6fdfdf959899..79ac5908f79a 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -48,10 +48,30 @@ static void x86_cpu_exec_exit(CPUState *cs) static void x86_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) +{ + /* The instruction pointer is always up to date with TARGET_TB_PCREL. */ + if (!TARGET_TB_PCREL) { + CPUX86State *env = cs->env_ptr; + env->eip = tb_pc(tb) - tb->cs_base; + } +} + +static void x86_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + int cc_op = data[1]; - cpu->env.eip = tb->pc - tb->cs_base; + if (TARGET_TB_PCREL) { + env->eip = (env->eip & TARGET_PAGE_MASK) | data[0]; + } else { + env->eip = data[0] - tb->cs_base; + } + if (cc_op != CC_OP_DYNAMIC) { + env->cc_op = cc_op; + } } #ifndef CONFIG_USER_ONLY @@ -70,15 +90,18 @@ static bool x86_debug_check_breakpoint(CPUState *cs) static const struct TCGCPUOps x86_tcg_ops = { .initialize = tcg_x86_init, .synchronize_from_tb = x86_cpu_synchronize_from_tb, + .restore_state_to_opc = x86_restore_state_to_opc, .cpu_exec_enter = x86_cpu_exec_enter, .cpu_exec_exit = x86_cpu_exec_exit, #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 c393913fe010..7e0b2a709ae1 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -23,8 +23,10 @@ #include "disas/disas.h" #include "exec/exec-all.h" #include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" #include "exec/cpu_ldst.h" #include "exec/translator.h" +#include "fpu/softfloat.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" @@ -64,6 +66,7 @@ /* global register indexes */ static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2; +static TCGv cpu_eip; static TCGv_i32 cpu_cc_op; static TCGv cpu_regs[CPU_NB_REGS]; static TCGv cpu_seg_base[6]; @@ -76,8 +79,8 @@ typedef struct DisasContext { DisasContextBase base; target_ulong pc; /* pc = eip + cs_base */ - target_ulong pc_start; /* pc at TB entry */ target_ulong cs_base; /* base of CS segment */ + target_ulong pc_save; MemOp aflag; MemOp dflag; @@ -85,6 +88,9 @@ typedef struct DisasContext { int8_t override; /* -1 if no override, else R_CS, R_DS, etc */ uint8_t prefix; + bool has_modrm; + uint8_t modrm; + #ifndef CONFIG_USER_ONLY uint8_t cpl; /* code priv level */ uint8_t iopl; /* i/o priv level */ @@ -98,8 +104,8 @@ typedef struct DisasContext { uint8_t rex_r; uint8_t rex_x; uint8_t rex_b; - bool rex_w; #endif + bool vex_w; /* used by AVX even on 32-bit processors */ bool jmp_opt; /* use direct block chaining for direct jumps */ bool repz_opt; /* optimize jumps within repz instructions */ bool cc_op_dirty; @@ -112,6 +118,7 @@ typedef struct DisasContext { int cpuid_ext2_features; int cpuid_ext3_features; int cpuid_7_0_ebx_features; + int cpuid_7_0_ecx_features; int cpuid_xsave_features; /* TCG local temps */ @@ -123,15 +130,19 @@ typedef struct DisasContext { /* TCG local register indexes (only used inside old micro ops) */ TCGv tmp0; TCGv tmp4; - TCGv_ptr ptr0; - TCGv_ptr ptr1; TCGv_i32 tmp2_i32; TCGv_i32 tmp3_i32; TCGv_i64 tmp1_i64; sigjmp_buf jmpbuf; + TCGOp *prev_insn_end; } DisasContext; +#define DISAS_EOB_ONLY DISAS_TARGET_0 +#define DISAS_EOB_NEXT DISAS_TARGET_1 +#define DISAS_EOB_INHIBIT_IRQ DISAS_TARGET_2 +#define DISAS_JUMP DISAS_TARGET_3 + /* The environment in which user-only runs is constrained. */ #ifdef CONFIG_USER_ONLY #define PE(S) true @@ -170,7 +181,7 @@ typedef struct DisasContext { #ifdef TARGET_X86_64 #define REX_PREFIX(S) (((S)->prefix & PREFIX_REX) != 0) -#define REX_W(S) ((S)->rex_w) +#define REX_W(S) ((S)->vex_w) #define REX_R(S) ((S)->rex_r + 0) #define REX_X(S) ((S)->rex_x + 0) #define REX_B(S) ((S)->rex_b + 0) @@ -218,9 +229,9 @@ STUB_HELPER(wrmsr, TCGv_env env) #endif static void gen_eob(DisasContext *s); -static void gen_jr(DisasContext *s, TCGv dest); -static void gen_jmp(DisasContext *s, target_ulong eip); -static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); +static void gen_jr(DisasContext *s); +static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num); +static void gen_jmp_rel_csize(DisasContext *s, int diff, int tb_num); static void gen_op(DisasContext *s1, int op, MemOp ot, int d); static void gen_exception_gpf(DisasContext *s); @@ -359,7 +370,7 @@ static void gen_update_cc_op(DisasContext *s) #endif /* !TARGET_X86_64 */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define REG_B_OFFSET (sizeof(target_ulong) - 1) #define REG_H_OFFSET (sizeof(target_ulong) - 2) #define REG_W_OFFSET (sizeof(target_ulong) - 2) @@ -428,32 +439,51 @@ static inline MemOp mo_b_d32(int b, MemOp ot) return b & 1 ? (ot == MO_16 ? MO_16 : MO_32) : MO_8; } -static void gen_op_mov_reg_v(DisasContext *s, MemOp ot, int reg, TCGv t0) +/* Compute the result of writing t0 to the OT-sized register REG. + * + * If DEST is NULL, store the result into the register and return the + * register's TCGv. + * + * If DEST is not NULL, store the result into DEST and return the + * register's TCGv. + */ +static TCGv gen_op_deposit_reg_v(DisasContext *s, MemOp ot, int reg, TCGv dest, TCGv t0) { switch(ot) { case MO_8: - if (!byte_reg_is_xH(s, reg)) { - tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 8); - } else { - tcg_gen_deposit_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], t0, 8, 8); + if (byte_reg_is_xH(s, reg)) { + dest = dest ? dest : cpu_regs[reg - 4]; + tcg_gen_deposit_tl(dest, cpu_regs[reg - 4], t0, 8, 8); + return cpu_regs[reg - 4]; } + dest = dest ? dest : cpu_regs[reg]; + tcg_gen_deposit_tl(dest, cpu_regs[reg], t0, 0, 8); break; case MO_16: - tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 16); + dest = dest ? dest : cpu_regs[reg]; + tcg_gen_deposit_tl(dest, cpu_regs[reg], t0, 0, 16); break; case MO_32: /* For x86_64, this sets the higher half of register to zero. For i386, this is equivalent to a mov. */ - tcg_gen_ext32u_tl(cpu_regs[reg], t0); + dest = dest ? dest : cpu_regs[reg]; + tcg_gen_ext32u_tl(dest, t0); break; #ifdef TARGET_X86_64 case MO_64: - tcg_gen_mov_tl(cpu_regs[reg], t0); + dest = dest ? dest : cpu_regs[reg]; + tcg_gen_mov_tl(dest, t0); break; #endif default: tcg_abort(); } + return cpu_regs[reg]; +} + +static void gen_op_mov_reg_v(DisasContext *s, MemOp ot, int reg, TCGv t0) +{ + gen_op_deposit_reg_v(s, ot, reg, NULL, t0); } static inline @@ -474,9 +504,10 @@ static void gen_add_A0_im(DisasContext *s, int val) } } -static inline void gen_op_jmp_v(TCGv dest) +static inline void gen_op_jmp_v(DisasContext *s, TCGv dest) { - tcg_gen_st_tl(dest, cpu_env, offsetof(CPUX86State, eip)); + tcg_gen_mov_tl(cpu_eip, dest); + s->pc_save = -1; } static inline @@ -511,10 +542,84 @@ static inline void gen_op_st_rm_T0_A0(DisasContext *s, int idx, int d) } } -static inline void gen_jmp_im(DisasContext *s, target_ulong pc) +static void gen_update_eip_cur(DisasContext *s) +{ + assert(s->pc_save != -1); + if (TARGET_TB_PCREL) { + tcg_gen_addi_tl(cpu_eip, cpu_eip, s->base.pc_next - s->pc_save); + } else { + tcg_gen_movi_tl(cpu_eip, s->base.pc_next - s->cs_base); + } + s->pc_save = s->base.pc_next; +} + +static void gen_update_eip_next(DisasContext *s) +{ + assert(s->pc_save != -1); + if (TARGET_TB_PCREL) { + tcg_gen_addi_tl(cpu_eip, cpu_eip, s->pc - s->pc_save); + } else { + tcg_gen_movi_tl(cpu_eip, s->pc - s->cs_base); + } + s->pc_save = s->pc; +} + +static int cur_insn_len(DisasContext *s) +{ + return s->pc - s->base.pc_next; +} + +static TCGv_i32 cur_insn_len_i32(DisasContext *s) +{ + return tcg_constant_i32(cur_insn_len(s)); +} + +static TCGv_i32 eip_next_i32(DisasContext *s) +{ + assert(s->pc_save != -1); + /* + * This function has two users: lcall_real (always 16-bit mode), and + * iret_protected (16, 32, or 64-bit mode). IRET only uses the value + * when EFLAGS.NT is set, which is illegal in 64-bit mode, which is + * why passing a 32-bit value isn't broken. To avoid using this where + * we shouldn't, return -1 in 64-bit mode so that execution goes into + * the weeds quickly. + */ + if (CODE64(s)) { + return tcg_constant_i32(-1); + } + if (TARGET_TB_PCREL) { + TCGv_i32 ret = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(ret, cpu_eip); + tcg_gen_addi_i32(ret, ret, s->pc - s->pc_save); + return ret; + } else { + return tcg_constant_i32(s->pc - s->cs_base); + } +} + +static TCGv eip_next_tl(DisasContext *s) +{ + assert(s->pc_save != -1); + if (TARGET_TB_PCREL) { + TCGv ret = tcg_temp_new(); + tcg_gen_addi_tl(ret, cpu_eip, s->pc - s->pc_save); + return ret; + } else { + return tcg_constant_tl(s->pc - s->cs_base); + } +} + +static TCGv eip_cur_tl(DisasContext *s) { - tcg_gen_movi_tl(s->tmp0, pc); - gen_op_jmp_v(s->tmp0); + assert(s->pc_save != -1); + if (TARGET_TB_PCREL) { + TCGv ret = tcg_temp_new(); + tcg_gen_addi_tl(ret, cpu_eip, s->base.pc_next - s->pc_save); + return ret; + } else { + return tcg_constant_tl(s->base.pc_next - s->cs_base); + } } /* Compute SEG:REG into A0. SEG is selected from the override segment @@ -630,20 +735,21 @@ static void gen_exts(MemOp ot, TCGv reg) gen_ext_tl(reg, reg, ot, true); } -static inline -void gen_op_jnz_ecx(DisasContext *s, MemOp size, TCGLabel *label1) +static void gen_op_j_ecx(DisasContext *s, TCGCond cond, TCGLabel *label1) { tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]); - gen_extu(size, s->tmp0); - tcg_gen_brcondi_tl(TCG_COND_NE, s->tmp0, 0, label1); + gen_extu(s->aflag, s->tmp0); + tcg_gen_brcondi_tl(cond, s->tmp0, 0, label1); } -static inline -void gen_op_jz_ecx(DisasContext *s, MemOp size, TCGLabel *label1) +static inline void gen_op_jz_ecx(DisasContext *s, TCGLabel *label1) { - tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]); - gen_extu(size, s->tmp0); - tcg_gen_brcondi_tl(TCG_COND_EQ, s->tmp0, 0, label1); + gen_op_j_ecx(s, TCG_COND_EQ, label1); +} + +static inline void gen_op_jnz_ecx(DisasContext *s, TCGLabel *label1) +{ + gen_op_j_ecx(s, TCG_COND_NE, label1); } static void gen_helper_in_func(MemOp ot, TCGv v, TCGv_i32 n) @@ -699,24 +805,21 @@ static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port, gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot)); } if (GUEST(s)) { - target_ulong cur_eip = s->base.pc_next - s->cs_base; - target_ulong next_eip = s->pc - s->cs_base; - gen_update_cc_op(s); - gen_jmp_im(s, cur_eip); + gen_update_eip_cur(s); if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) { svm_flags |= SVM_IOIO_REP_MASK; } svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot); gen_helper_svm_check_io(cpu_env, port, tcg_constant_i32(svm_flags), - tcg_constant_i32(next_eip - cur_eip)); + cur_insn_len_i32(s)); } return true; #endif } -static inline void gen_movs(DisasContext *s, MemOp ot) +static void gen_movs(DisasContext *s, MemOp ot) { gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -1136,18 +1239,18 @@ static inline void gen_jcc1(DisasContext *s, int b, TCGLabel *l1) /* XXX: does not work with gdbstub "ice" single step - not a serious problem */ -static TCGLabel *gen_jz_ecx_string(DisasContext *s, target_ulong next_eip) +static TCGLabel *gen_jz_ecx_string(DisasContext *s) { TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - gen_op_jnz_ecx(s, s->aflag, l1); + gen_op_jnz_ecx(s, l1); gen_set_label(l2); - gen_jmp_tb(s, next_eip, 1); + gen_jmp_rel_csize(s, 0, 1); gen_set_label(l1); return l2; } -static inline void gen_stos(DisasContext *s, MemOp ot) +static void gen_stos(DisasContext *s, MemOp ot) { gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX); gen_string_movl_A0_EDI(s); @@ -1156,7 +1259,7 @@ static inline void gen_stos(DisasContext *s, MemOp ot) gen_op_add_reg_T0(s, s->aflag, R_EDI); } -static inline void gen_lods(DisasContext *s, MemOp ot) +static void gen_lods(DisasContext *s, MemOp ot) { gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -1165,7 +1268,7 @@ static inline void gen_lods(DisasContext *s, MemOp ot) gen_op_add_reg_T0(s, s->aflag, R_ESI); } -static inline void gen_scas(DisasContext *s, MemOp ot) +static void gen_scas(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); gen_op_ld_v(s, ot, s->T1, s->A0); @@ -1174,7 +1277,7 @@ static inline void gen_scas(DisasContext *s, MemOp ot) gen_op_add_reg_T0(s, s->aflag, R_EDI); } -static inline void gen_cmps(DisasContext *s, MemOp ot) +static void gen_cmps(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); gen_op_ld_v(s, ot, s->T1, s->A0); @@ -1192,17 +1295,14 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) /* user-mode cpu should not be in IOBPT mode */ g_assert_not_reached(); #else - TCGv_i32 t_size = tcg_const_i32(1 << ot); - TCGv t_next = tcg_const_tl(s->pc - s->cs_base); - + TCGv_i32 t_size = tcg_constant_i32(1 << ot); + TCGv t_next = eip_next_tl(s); gen_helper_bpt_io(cpu_env, t_port, t_size, t_next); - tcg_temp_free_i32(t_size); - tcg_temp_free(t_next); #endif /* CONFIG_USER_ONLY */ } } -static inline void gen_ins(DisasContext *s, MemOp ot) +static void gen_ins(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); /* Note: we must do this dummy write first to be restartable in @@ -1218,7 +1318,7 @@ static inline void gen_ins(DisasContext *s, MemOp ot) gen_bpt_io(s, s->tmp2_i32, ot); } -static inline void gen_outs(DisasContext *s, MemOp ot) +static void gen_outs(DisasContext *s, MemOp ot) { gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -1232,42 +1332,49 @@ static inline void gen_outs(DisasContext *s, MemOp ot) gen_bpt_io(s, s->tmp2_i32, ot); } -/* same method as Valgrind : we generate jumps to current or next - instruction */ -#define GEN_REPZ(op) \ -static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \ - target_ulong cur_eip, target_ulong next_eip) \ -{ \ - TCGLabel *l2; \ - gen_update_cc_op(s); \ - l2 = gen_jz_ecx_string(s, next_eip); \ - gen_ ## op(s, ot); \ - gen_op_add_reg_im(s, s->aflag, R_ECX, -1); \ - /* a loop would cause two single step exceptions if ECX = 1 \ - before rep string_insn */ \ - if (s->repz_opt) \ - gen_op_jz_ecx(s, s->aflag, l2); \ - gen_jmp(s, cur_eip); \ -} - -#define GEN_REPZ2(op) \ -static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \ - target_ulong cur_eip, \ - target_ulong next_eip, \ - int nz) \ -{ \ - TCGLabel *l2; \ - gen_update_cc_op(s); \ - l2 = gen_jz_ecx_string(s, next_eip); \ - gen_ ## op(s, ot); \ - gen_op_add_reg_im(s, s->aflag, R_ECX, -1); \ - gen_update_cc_op(s); \ - gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); \ - if (s->repz_opt) \ - gen_op_jz_ecx(s, s->aflag, l2); \ - gen_jmp(s, cur_eip); \ +/* Generate jumps to current or next instruction */ +static void gen_repz(DisasContext *s, MemOp ot, + void (*fn)(DisasContext *s, MemOp ot)) +{ + TCGLabel *l2; + gen_update_cc_op(s); + l2 = gen_jz_ecx_string(s); + fn(s, ot); + gen_op_add_reg_im(s, s->aflag, R_ECX, -1); + /* + * A loop would cause two single step exceptions if ECX = 1 + * before rep string_insn + */ + if (s->repz_opt) { + gen_op_jz_ecx(s, l2); + } + gen_jmp_rel_csize(s, -cur_insn_len(s), 0); +} + +#define GEN_REPZ(op) \ + static inline void gen_repz_ ## op(DisasContext *s, MemOp ot) \ + { gen_repz(s, ot, gen_##op); } + +static void gen_repz2(DisasContext *s, MemOp ot, int nz, + void (*fn)(DisasContext *s, MemOp ot)) +{ + TCGLabel *l2; + gen_update_cc_op(s); + l2 = gen_jz_ecx_string(s); + fn(s, ot); + gen_op_add_reg_im(s, s->aflag, R_ECX, -1); + gen_update_cc_op(s); + gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); + if (s->repz_opt) { + gen_op_jz_ecx(s, l2); + } + gen_jmp_rel_csize(s, -cur_insn_len(s), 0); } +#define GEN_REPZ2(op) \ + static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, int nz) \ + { gen_repz2(s, ot, nz, gen_##op); } + GEN_REPZ(movs) GEN_REPZ(stos) GEN_REPZ(lods) @@ -1332,10 +1439,10 @@ static void gen_helper_fp_arith_STN_ST0(int op, int opreg) } } -static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) +static void gen_exception(DisasContext *s, int trapno) { gen_update_cc_op(s); - gen_jmp_im(s, cur_eip); + gen_update_eip_cur(s); gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno)); s->base.is_jmp = DISAS_NORETURN; } @@ -1344,13 +1451,13 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) the instruction is known, but it isn't allowed in the current cpu mode. */ static void gen_illegal_opcode(DisasContext *s) { - gen_exception(s, EXCP06_ILLOP, s->pc_start - s->cs_base); + gen_exception(s, EXCP06_ILLOP); } /* Generate #GP for the current instruction. */ static void gen_exception_gpf(DisasContext *s) { - gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base); + gen_exception(s, EXCP0D_GPF); } /* Check for cpl == 0; if not, raise #GP and return false. */ @@ -2008,8 +2115,14 @@ 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 (unlikely(cur_insn_len(s) > X86_MAX_INSN_LENGTH)) { /* If the instruction's 16th byte is on a different page than the 1st, a * page fault on the second page wins over the general protection fault * caused by the instruction being too long. @@ -2033,7 +2146,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) @@ -2187,11 +2300,11 @@ static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s, } /* Compute the address, with a minimum number of TCG ops. */ -static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a) +static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a, bool is_vsib) { TCGv ea = NULL; - if (a.index >= 0) { + if (a.index >= 0 && !is_vsib) { if (a.scale == 0) { ea = cpu_regs[a.index]; } else { @@ -2206,7 +2319,12 @@ static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a) ea = cpu_regs[a.base]; } if (!ea) { - tcg_gen_movi_tl(s->A0, a.disp); + if (TARGET_TB_PCREL && a.base == -2) { + /* With cpu_eip ~= pc_save, the expression is pc-relative. */ + tcg_gen_addi_tl(s->A0, cpu_eip, a.disp - s->pc_save); + } else { + tcg_gen_movi_tl(s->A0, a.disp); + } ea = s->A0; } else if (a.disp != 0) { tcg_gen_addi_tl(s->A0, ea, a.disp); @@ -2219,7 +2337,7 @@ static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a) static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm) { AddressParts a = gen_lea_modrm_0(env, s, modrm); - TCGv ea = gen_lea_modrm_1(s, a); + TCGv ea = gen_lea_modrm_1(s, a, false); gen_lea_v_seg(s, s->aflag, ea, a.def_seg, s->override); } @@ -2232,7 +2350,8 @@ static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm) static void gen_bndck(CPUX86State *env, DisasContext *s, int modrm, TCGCond cond, TCGv_i64 bndv) { - TCGv ea = gen_lea_modrm_1(s, gen_lea_modrm_0(env, s, modrm)); + AddressParts a = gen_lea_modrm_0(env, s, modrm); + TCGv ea = gen_lea_modrm_1(s, a, false); tcg_gen_extu_tl_i64(s->tmp1_i64, ea); if (!CODE64(s)) { @@ -2282,6 +2401,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; @@ -2305,58 +2449,48 @@ static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot) return ret; } -static inline int insn_const_size(MemOp ot) +static target_long insn_get_signed(CPUX86State *env, DisasContext *s, MemOp ot) { - if (ot <= MO_32) { - return 1 << ot; - } else { - return 4; + target_long ret; + + switch (ot) { + case MO_8: + ret = (int8_t) x86_ldub_code(env, s); + break; + case MO_16: + ret = (int16_t) x86_lduw_code(env, s); + break; + case MO_32: + ret = (int32_t) 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 void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) +static inline int insn_const_size(MemOp ot) { - target_ulong pc = s->cs_base + eip; - - if (translator_use_goto_tb(&s->base, pc)) { - /* jump to same page: we can use a direct jump */ - tcg_gen_goto_tb(tb_num); - gen_jmp_im(s, eip); - tcg_gen_exit_tb(s->base.tb, tb_num); - s->base.is_jmp = DISAS_NORETURN; + if (ot <= MO_32) { + return 1 << ot; } else { - /* jump to another page */ - gen_jmp_im(s, eip); - gen_jr(s, s->tmp0); + return 4; } } -static inline void gen_jcc(DisasContext *s, int b, - target_ulong val, target_ulong next_eip) +static void gen_jcc(DisasContext *s, int b, int diff) { - TCGLabel *l1, *l2; - - if (s->jmp_opt) { - l1 = gen_new_label(); - gen_jcc1(s, b, l1); - - gen_goto_tb(s, 0, next_eip); - - gen_set_label(l1); - gen_goto_tb(s, 1, val); - } else { - l1 = gen_new_label(); - l2 = gen_new_label(); - gen_jcc1(s, b, l1); - - gen_jmp_im(s, next_eip); - tcg_gen_br(l2); + TCGLabel *l1 = gen_new_label(); - gen_set_label(l1); - gen_jmp_im(s, val); - gen_set_label(l2); - gen_eob(s); - } + gen_jcc1(s, b, l1); + gen_jmp_rel_csize(s, 0, 1); + gen_set_label(l1); + gen_jmp_rel(s, s->dflag, diff, 0); } static void gen_cmovcc1(CPUX86State *env, DisasContext *s, MemOp ot, int b, @@ -2413,13 +2547,15 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg) because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware interrupts for the next instruction */ - if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) { - s->base.is_jmp = DISAS_TOO_MANY; + if (seg_reg == R_SS) { + s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ; + } else if (CODE32(s) && seg_reg < R_FS) { + s->base.is_jmp = DISAS_EOB_NEXT; } } else { gen_op_movl_seg_T0_vm(s, seg_reg); if (seg_reg == R_SS) { - s->base.is_jmp = DISAS_TOO_MANY; + s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ; } } } @@ -2580,27 +2716,28 @@ static void gen_unknown_opcode(CPUX86State *env, DisasContext *s) gen_illegal_opcode(s); if (qemu_loglevel_mask(LOG_UNIMP)) { - FILE *logfile = qemu_log_lock(); - target_ulong pc = s->pc_start, end = s->pc; + FILE *logfile = qemu_log_trylock(); + if (logfile) { + target_ulong pc = s->base.pc_next, end = s->pc; - qemu_log("ILLOPC: " TARGET_FMT_lx ":", pc); - for (; pc < end; ++pc) { - qemu_log(" %02x", cpu_ldub_code(env, pc)); + fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc); + for (; pc < end; ++pc) { + fprintf(logfile, " %02x", cpu_ldub_code(env, pc)); + } + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); } - qemu_log("\n"); - qemu_log_unlock(logfile); } } /* an interrupt is different from an exception because of the privilege checks */ -static void gen_interrupt(DisasContext *s, int intno, - target_ulong cur_eip, target_ulong next_eip) +static void gen_interrupt(DisasContext *s, int intno) { gen_update_cc_op(s); - gen_jmp_im(s, cur_eip); - gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno), - tcg_const_i32(next_eip - cur_eip)); + gen_update_eip_cur(s); + gen_helper_raise_interrupt(cpu_env, tcg_constant_i32(intno), + cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; } @@ -2628,6 +2765,26 @@ static void gen_reset_hflag(DisasContext *s, uint32_t mask) } } +static void gen_set_eflags(DisasContext *s, target_ulong mask) +{ + TCGv t = tcg_temp_new(); + + tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_gen_ori_tl(t, t, mask); + tcg_gen_st_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_temp_free(t); +} + +static void gen_reset_eflags(DisasContext *s, target_ulong mask) +{ + TCGv t = tcg_temp_new(); + + tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_gen_andi_tl(t, t, ~mask); + tcg_gen_st_tl(t, cpu_env, offsetof(CPUX86State, eflags)); + tcg_temp_free(t); +} + /* Clear BND registers during legacy branches. */ static void gen_bnd_jmp(DisasContext *s) { @@ -2658,7 +2815,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr) } if (s->base.tb->flags & HF_RF_MASK) { - gen_helper_reset_rf(cpu_env); + gen_reset_eflags(s, RF_MASK); } if (recheck_tf) { gen_helper_rechecking_single_step(cpu_env); @@ -2693,1872 +2850,165 @@ static void gen_eob(DisasContext *s) } /* Jump to register */ -static void gen_jr(DisasContext *s, TCGv dest) -{ - do_gen_eob_worker(s, false, false, true); -} - -/* generate a jump to eip. No segment change must happen before as a - direct call to the next block may occur */ -static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) -{ - gen_update_cc_op(s); - set_cc_op(s, CC_OP_DYNAMIC); - if (s->jmp_opt) { - gen_goto_tb(s, tb_num, eip); - } else { - gen_jmp_im(s, eip); - gen_eob(s); - } -} - -static void gen_jmp(DisasContext *s, target_ulong eip) -{ - gen_jmp_tb(s, eip, 0); -} - -static inline void gen_ldq_env_A0(DisasContext *s, int offset) -{ - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset); -} - -static inline void gen_stq_env_A0(DisasContext *s, int offset) -{ - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, 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) -{ - int mem_index = s->mem_index; - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ); - 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 void gen_jr(DisasContext *s) { - 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_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); -} - -static inline void gen_op_movo(DisasContext *s, int d_offset, int s_offset) -{ - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset + offsetof(ZMMReg, ZMM_Q(0))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset + offsetof(ZMMReg, ZMM_Q(0))); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset + offsetof(ZMMReg, ZMM_Q(1))); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset + offsetof(ZMMReg, ZMM_Q(1))); -} - -static inline void gen_op_movq(DisasContext *s, int d_offset, int s_offset) -{ - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset); -} - -static inline void gen_op_movl(DisasContext *s, int d_offset, int s_offset) -{ - tcg_gen_ld_i32(s->tmp2_i32, cpu_env, s_offset); - tcg_gen_st_i32(s->tmp2_i32, cpu_env, d_offset); -} - -static inline void gen_op_movq_env_0(DisasContext *s, int d_offset) -{ - tcg_gen_movi_i64(s->tmp1_i64, 0); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset); -} - -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_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 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, } - -static const SSEFunc_0_epp sse_op_table1[256][4] = { - /* 3DNow! extensions */ - [0x0e] = { SSE_DUMMY }, /* femms */ - [0x0f] = { SSE_DUMMY }, /* pf... */ - /* 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 */ - - [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 */ - [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 }, - [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 */ - - /* 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 }, - - /* 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), -}; - -static const SSEFunc_0_epp sse_op_table2[3 * 8][2] = { - [0 + 2] = MMX_OP2(psrlw), - [0 + 4] = MMX_OP2(psraw), - [0 + 6] = MMX_OP2(psllw), - [8 + 2] = MMX_OP2(psrld), - [8 + 4] = MMX_OP2(psrad), - [8 + 6] = MMX_OP2(pslld), - [16 + 2] = MMX_OP2(psrlq), - [16 + 3] = { NULL, gen_helper_psrldq_xmm }, - [16 + 6] = MMX_OP2(psllq), - [16 + 7] = { NULL, gen_helper_pslldq_xmm }, -}; - -static const SSEFunc_0_epi sse_op_table3ai[] = { - gen_helper_cvtsi2ss, - gen_helper_cvtsi2sd -}; - -#ifdef TARGET_X86_64 -static const SSEFunc_0_epl sse_op_table3aq[] = { - gen_helper_cvtsq2ss, - gen_helper_cvtsq2sd -}; -#endif - -static const SSEFunc_i_ep sse_op_table3bi[] = { - gen_helper_cvttss2si, - gen_helper_cvtss2si, - gen_helper_cvttsd2si, - gen_helper_cvtsd2si -}; - -#ifdef TARGET_X86_64 -static const SSEFunc_l_ep sse_op_table3bq[] = { - gen_helper_cvttss2sq, - gen_helper_cvtss2sq, - gen_helper_cvttsd2sq, - gen_helper_cvtsd2sq -}; -#endif - -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), -}; - -static const SSEFunc_0_epp sse_op_table5[256] = { - [0x0c] = gen_helper_pi2fw, - [0x0d] = gen_helper_pi2fd, - [0x1c] = gen_helper_pf2iw, - [0x1d] = gen_helper_pf2id, - [0x8a] = gen_helper_pfnacc, - [0x8e] = gen_helper_pfpnacc, - [0x90] = gen_helper_pfcmpge, - [0x94] = gen_helper_pfmin, - [0x96] = gen_helper_pfrcp, - [0x97] = gen_helper_pfrsqrt, - [0x9a] = gen_helper_pfsub, - [0x9e] = gen_helper_pfadd, - [0xa0] = gen_helper_pfcmpgt, - [0xa4] = gen_helper_pfmax, - [0xa6] = gen_helper_movq, /* pfrcpit1; no need to actually increase precision */ - [0xa7] = gen_helper_movq, /* pfrsqit1 */ - [0xaa] = gen_helper_pfsubr, - [0xae] = gen_helper_pfacc, - [0xb0] = gen_helper_pfcmpeq, - [0xb4] = gen_helper_pfmul, - [0xb6] = gen_helper_movq, /* pfrcpit2 */ - [0xb7] = gen_helper_pmulhrw_mmx, - [0xbb] = gen_helper_pswapd, - [0xbf] = gen_helper_pavgb_mmx /* pavgusb */ -}; - -struct SSEOpHelper_epp { - SSEFunc_0_epp op[2]; - uint32_t ext_mask; -}; - -struct SSEOpHelper_eppi { - SSEFunc_0_eppi op[2]; - uint32_t ext_mask; -}; - -#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 } - -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), -}; - -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), -}; - -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; - MemOp ot; - - b &= 0xff; - if (s->prefix & PREFIX_DATA) - b1 = 1; - else if (s->prefix & PREFIX_REPZ) - b1 = 2; - else if (s->prefix & PREFIX_REPNZ) - b1 = 3; - else - b1 = 0; - sse_fn_epp = sse_op_table1[b][b1]; - if (!sse_fn_epp) { - goto unknown_op; - } - if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) { - is_xmm = 1; - } else { - if (b1 == 0) { - /* MMX case */ - is_xmm = 0; - } else { - is_xmm = 1; - } - } - /* simple MMX/SSE operation */ - if (s->flags & HF_TS_MASK) { - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); - return; - } - if (s->flags & HF_EM_MASK) { - illegal_op: - gen_illegal_opcode(s); - return; - } - if (is_xmm - && !(s->flags & HF_OSFXSR_MASK) - && (b != 0x38 && b != 0x3a)) { - goto unknown_op; - } - if (b == 0x0e) { - if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) { - /* If we were fully decoding this we might use illegal_op. */ - goto unknown_op; - } - /* femms */ - gen_helper_emms(cpu_env); - return; - } - if (b == 0x77) { - /* emms */ - gen_helper_emms(cpu_env); - return; - } - /* prepare MMX state (XXX: optimize by storing fptt and fptags in - the static cpu state) */ - if (!is_xmm) { - gen_helper_enter_mmx(cpu_env); - } - - modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7); - if (is_xmm) { - reg |= REX_R(s); - } - mod = (modrm >> 6) & 3; - if (sse_fn_epp == SSE_SPECIAL) { - b |= (b1 << 8); - switch(b) { - case 0x0e7: /* movntq */ - if (mod == 3) { - goto illegal_op; - } - gen_lea_modrm(env, s, modrm); - gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx)); - break; - case 0x1e7: /* movntdq */ - case 0x02b: /* movntps */ - case 0x12b: /* movntps */ - if (mod == 3) - goto illegal_op; - gen_lea_modrm(env, s, modrm); - gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); - 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])); - break; - case 0x22b: /* movntss */ - case 0x32b: /* movntsd */ - if (mod == 3) - goto illegal_op; - gen_lea_modrm(env, s, modrm); - if (b1 & 1) { - gen_stq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } else { - tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(0))); - gen_op_st_v(s, MO_32, s->T0, s->A0); - } - break; - case 0x6e: /* movd mm, ea */ -#ifdef TARGET_X86_64 - if (s->dflag == MO_64) { - gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0); - tcg_gen_st_tl(s->T0, cpu_env, - offsetof(CPUX86State, fpregs[reg].mmx)); - } else -#endif - { - gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 0); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State,fpregs[reg].mmx)); - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_movl_mm_T0_mmx(s->ptr0, s->tmp2_i32); - } - break; - case 0x16e: /* movd xmm, ea */ -#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])); - 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_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 */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx)); - } else { - rm = (modrm & 7); - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, - offsetof(CPUX86State,fpregs[rm].mmx)); - tcg_gen_st_i64(s->tmp1_i64, cpu_env, - offsetof(CPUX86State,fpregs[reg].mmx)); - } - break; - case 0x010: /* movups */ - case 0x110: /* movupd */ - case 0x028: /* movaps */ - case 0x128: /* movapd */ - case 0x16f: /* movdqa xmm, ea */ - case 0x26f: /* movdqu xmm, ea */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movo(s, offsetof(CPUX86State, xmm_regs[reg]), - offsetof(CPUX86State,xmm_regs[rm])); - } - break; - case 0x210: /* movss xmm, ea */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_op_ld_v(s, MO_32, s->T0, s->A0); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0))); - tcg_gen_movi_tl(s->T0, 0); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1))); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2))); - tcg_gen_st32_tl(s->T0, cpu_env, - 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))); - } - break; - case 0x310: /* movsd xmm, ea */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - tcg_gen_movi_tl(s->T0, 0); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2))); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3))); - } 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))); - } - break; - case 0x012: /* movlps */ - case 0x112: /* movlpd */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } else { - /* movhlps */ - 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(1))); - } - break; - case 0x212: /* movsldup */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); - } 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))); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2)), - offsetof(CPUX86State,xmm_regs[rm].ZMM_L(2))); - } - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_L(0))); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_L(2))); - break; - case 0x312: /* movddup */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } 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))); - } - gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0))); - break; - case 0x016: /* movhps */ - case 0x116: /* movhpd */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(1))); - } else { - /* movlhps */ - rm = (modrm & 7) | REX_B(s); - gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1)), - offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0))); - } - break; - case 0x216: /* movshdup */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)), - offsetof(CPUX86State,xmm_regs[rm].ZMM_L(1))); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)), - offsetof(CPUX86State,xmm_regs[rm].ZMM_L(3))); - } - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_L(1))); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_L(3))); - break; - case 0x178: - case 0x378: - { - int bit_index, field_length; - - if (b1 == 1 && reg != 0) - 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])); - 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, - tcg_const_i32(bit_index), - tcg_const_i32(field_length)); - } - break; - case 0x7e: /* movd ea, mm */ -#ifdef TARGET_X86_64 - if (s->dflag == MO_64) { - tcg_gen_ld_i64(s->T0, cpu_env, - offsetof(CPUX86State,fpregs[reg].mmx)); - gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 1); - } else -#endif - { - tcg_gen_ld32u_tl(s->T0, cpu_env, - offsetof(CPUX86State,fpregs[reg].mmx.MMX_L(0))); - gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 1); - } - break; - case 0x17e: /* movd ea, xmm */ -#ifdef TARGET_X86_64 - if (s->dflag == MO_64) { - tcg_gen_ld_i64(s->T0, cpu_env, - offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0))); - gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 1); - } else -#endif - { - tcg_gen_ld32u_tl(s->T0, cpu_env, - offsetof(CPUX86State,xmm_regs[reg].ZMM_L(0))); - gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 1); - } - break; - case 0x27e: /* movq xmm, ea */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } 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))); - } - gen_op_movq_env_0(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1))); - break; - case 0x7f: /* movq ea, mm */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx)); - } else { - rm = (modrm & 7); - gen_op_movq(s, offsetof(CPUX86State, fpregs[rm].mmx), - offsetof(CPUX86State,fpregs[reg].mmx)); - } - break; - case 0x011: /* movups */ - case 0x111: /* movupd */ - case 0x029: /* movaps */ - case 0x129: /* movapd */ - case 0x17f: /* movdqa ea, xmm */ - case 0x27f: /* movdqu ea, xmm */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movo(s, offsetof(CPUX86State, xmm_regs[rm]), - offsetof(CPUX86State,xmm_regs[reg])); - } - break; - case 0x211: /* movss ea, xmm */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - tcg_gen_ld32u_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0))); - gen_op_st_v(s, MO_32, s->T0, s->A0); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[rm].ZMM_L(0)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_L(0))); - } - break; - case 0x311: /* movsd ea, xmm */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_stq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movq(s, offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(0)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0))); - } - break; - case 0x013: /* movlps */ - case 0x113: /* movlpd */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_stq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } else { - goto illegal_op; - } - break; - case 0x017: /* movhps */ - case 0x117: /* movhpd */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_stq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(1))); - } else { - goto illegal_op; - } - break; - case 0x71: /* shift mm, im */ - case 0x72: - case 0x73: - case 0x171: /* shift xmm, im */ - case 0x172: - case 0x173: - val = x86_ldub_code(env, s); - if (is_xmm) { - tcg_gen_movi_tl(s->T0, val); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_t0.ZMM_L(0))); - tcg_gen_movi_tl(s->T0, 0); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, xmm_t0.ZMM_L(1))); - op1_offset = offsetof(CPUX86State,xmm_t0); - } else { - tcg_gen_movi_tl(s->T0, val); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, mmx_t0.MMX_L(0))); - tcg_gen_movi_tl(s->T0, 0); - tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State, mmx_t0.MMX_L(1))); - op1_offset = offsetof(CPUX86State,mmx_t0); - } - assert(b1 < 2); - sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 + - (((modrm >> 3)) & 7)][b1]; - if (!sse_fn_epp) { - goto unknown_op; - } - if (is_xmm) { - rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[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); - 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_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_extu_i32_tl(cpu_regs[reg], s->tmp2_i32); - break; - case 0x02a: /* cvtpi2ps */ - case 0x12a: /* cvtpi2pd */ - gen_helper_enter_mmx(cpu_env); - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - op2_offset = offsetof(CPUX86State,mmx_t0); - gen_ldq_env_A0(s, op2_offset); - } else { - rm = (modrm & 7); - op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); - } - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - switch(b >> 8) { - case 0x0: - gen_helper_cvtpi2ps(cpu_env, s->ptr0, s->ptr1); - break; - default: - case 0x1: - gen_helper_cvtpi2pd(cpu_env, s->ptr0, s->ptr1); - break; - } - break; - case 0x22a: /* cvtsi2ss */ - 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]); - 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]; - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - sse_fn_epi(cpu_env, s->ptr0, s->tmp2_i32); - } else { -#ifdef TARGET_X86_64 - SSEFunc_0_epl sse_fn_epl = sse_op_table3aq[(b >> 8) & 1]; - sse_fn_epl(cpu_env, s->ptr0, s->T0); -#else - goto illegal_op; -#endif - } - break; - case 0x02c: /* cvttps2pi */ - case 0x12c: /* cvttpd2pi */ - case 0x02d: /* cvtps2pi */ - case 0x12d: /* cvtpd2pi */ - 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); - } else { - rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); - } - op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx); - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - switch(b) { - case 0x02c: - gen_helper_cvttps2pi(cpu_env, s->ptr0, s->ptr1); - break; - case 0x12c: - gen_helper_cvttpd2pi(cpu_env, s->ptr0, s->ptr1); - break; - case 0x02d: - gen_helper_cvtps2pi(cpu_env, s->ptr0, s->ptr1); - break; - case 0x12d: - gen_helper_cvtpd2pi(cpu_env, s->ptr0, s->ptr1); - break; - } - break; - case 0x22c: /* cvttss2si */ - case 0x32c: /* cvttsd2si */ - case 0x22d: /* cvtss2si */ - case 0x32d: /* cvtsd2si */ - ot = mo_64_32(s->dflag); - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - if ((b >> 8) & 1) { - gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.ZMM_Q(0))); - } else { - 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))); - } - op2_offset = offsetof(CPUX86State,xmm_t0); - } else { - rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); - } - tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset); - if (ot == MO_32) { - SSEFunc_i_ep sse_fn_i_ep = - sse_op_table3bi[((b >> 7) & 2) | (b & 1)]; - sse_fn_i_ep(s->tmp2_i32, cpu_env, s->ptr0); - tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); - } else { -#ifdef TARGET_X86_64 - SSEFunc_l_ep sse_fn_l_ep = - sse_op_table3bq[((b >> 7) & 2) | (b & 1)]; - sse_fn_l_ep(s->T0, cpu_env, s->ptr0); -#else - goto illegal_op; -#endif - } - gen_op_mov_reg_v(s, ot, reg, s->T0); - break; - case 0xc4: /* pinsrw */ - case 0x1c4: - s->rip_offset = 1; - gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); - val = x86_ldub_code(env, s); - if (b1) { - val &= 7; - tcg_gen_st16_tl(s->T0, cpu_env, - offsetof(CPUX86State,xmm_regs[reg].ZMM_W(val))); - } else { - val &= 3; - tcg_gen_st16_tl(s->T0, cpu_env, - offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val))); - } - break; - case 0xc5: /* pextrw */ - case 0x1c5: - if (mod != 3) - goto illegal_op; - ot = mo_64_32(s->dflag); - val = x86_ldub_code(env, s); - if (b1) { - val &= 7; - rm = (modrm & 7) | REX_B(s); - tcg_gen_ld16u_tl(s->T0, cpu_env, - offsetof(CPUX86State,xmm_regs[rm].ZMM_W(val))); - } else { - val &= 3; - rm = (modrm & 7); - tcg_gen_ld16u_tl(s->T0, cpu_env, - offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val))); - } - reg = ((modrm >> 3) & 7) | REX_R(s); - gen_op_mov_reg_v(s, ot, reg, s->T0); - break; - case 0x1d6: /* movq ea, xmm */ - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - gen_stq_env_A0(s, offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(0))); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movq(s, offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(0)), - offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0))); - gen_op_movq_env_0(s, - offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(1))); - } - break; - case 0x2d6: /* movq2dq */ - gen_helper_enter_mmx(cpu_env); - rm = (modrm & 7); - gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)), - offsetof(CPUX86State,fpregs[rm].mmx)); - gen_op_movq_env_0(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1))); - break; - case 0x3d6: /* movdq2q */ - gen_helper_enter_mmx(cpu_env); - rm = (modrm & 7) | REX_B(s); - gen_op_movq(s, offsetof(CPUX86State, fpregs[reg & 7].mmx), - offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0))); - break; - case 0xd7: /* pmovmskb */ - case 0x1d7: - if (mod != 3) - goto illegal_op; - if (b1) { - rm = (modrm & 7) | REX_B(s); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State, xmm_regs[rm])); - gen_helper_pmovmskb_xmm(s->tmp2_i32, cpu_env, s->ptr0); - } else { - rm = (modrm & 7); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State, fpregs[rm].mmx)); - gen_helper_pmovmskb_mmx(s->tmp2_i32, cpu_env, s->ptr0); - } - reg = ((modrm >> 3) & 7) | REX_R(s); - tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32); - break; - - case 0x138: - case 0x038: - b = modrm; - if ((b & 0xf0) == 0xf0) { - goto do_0f_38_fx; - } - modrm = x86_ldub_code(env, s); - rm = modrm & 7; - reg = ((modrm >> 3) & 7) | REX_R(s); - mod = (modrm >> 6) & 3; - - assert(b1 < 2); - sse_fn_epp = sse_op_table6[b].op[b1]; - if (!sse_fn_epp) { - goto unknown_op; - } - if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask)) - goto illegal_op; - - 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); - switch (b) { - case 0x20: case 0x30: /* pmovsxbw, pmovzxbw */ - case 0x23: case 0x33: /* pmovsxwd, pmovzxwd */ - case 0x25: case 0x35: /* pmovsxdq, pmovzxdq */ - gen_ldq_env_A0(s, op2_offset + - offsetof(ZMMReg, ZMM_Q(0))); - break; - case 0x21: case 0x31: /* pmovsxbd, pmovzxbd */ - case 0x24: case 0x34: /* pmovsxwq, pmovzxwq */ - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - tcg_gen_st_i32(s->tmp2_i32, cpu_env, op2_offset + - offsetof(ZMMReg, ZMM_L(0))); - break; - case 0x22: case 0x32: /* pmovsxbq, pmovzxbq */ - tcg_gen_qemu_ld_tl(s->tmp0, s->A0, - s->mem_index, MO_LEUW); - 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); - return; - default: - gen_ldo_env_A0(s, op2_offset); - } - } - } else { - op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); - if (mod == 3) { - op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); - } else { - op2_offset = offsetof(CPUX86State,mmx_t0); - 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); - sse_fn_epp(cpu_env, s->ptr0, s->ptr1); - - if (b == 0x17) { - set_cc_op(s, CC_OP_EFLAGS); - } - break; - - case 0x238: - case 0x338: - do_0f_38_fx: - /* Various integer extensions at 0f 38 f[0-f]. */ - b = modrm | (b1 << 8); - modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | REX_R(s); - - switch (b) { - case 0x3f0: /* crc32 Gd,Eb */ - case 0x3f1: /* crc32 Gd,Ey */ - do_crc32: - if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) { - goto illegal_op; - } - if ((b & 0xff) == 0xf0) { - ot = MO_8; - } else if (s->dflag != MO_64) { - ot = (s->prefix & PREFIX_DATA ? MO_16 : MO_32); - } else { - ot = MO_64; - } - - tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[reg]); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - gen_helper_crc32(s->T0, s->tmp2_i32, - s->T0, tcg_const_i32(8 << ot)); - - ot = mo_64_32(s->dflag); - gen_op_mov_reg_v(s, ot, reg, s->T0); - break; - - case 0x1f0: /* crc32 or movbe */ - case 0x1f1: - /* 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. */ - if (s->prefix & PREFIX_REPNZ) { - goto do_crc32; - } - /* FALLTHRU */ - case 0x0f0: /* movbe Gy,My */ - case 0x0f1: /* movbe My,Gy */ - if (!(s->cpuid_ext_features & CPUID_EXT_MOVBE)) { - goto illegal_op; - } - if (s->dflag != MO_64) { - ot = (s->prefix & PREFIX_DATA ? MO_16 : MO_32); - } else { - ot = MO_64; - } - - gen_lea_modrm(env, s, modrm); - if ((b & 1) == 0) { - tcg_gen_qemu_ld_tl(s->T0, s->A0, - s->mem_index, ot | MO_BE); - gen_op_mov_reg_v(s, ot, reg, s->T0); - } else { - tcg_gen_qemu_st_tl(cpu_regs[reg], s->A0, - s->mem_index, ot | MO_BE); - } - break; - - case 0x0f2: /* andn Gy, By, Ey */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - tcg_gen_andc_tl(s->T0, s->T0, cpu_regs[s->vex_v]); - gen_op_mov_reg_v(s, ot, reg, s->T0); - gen_op_update1_cc(s); - set_cc_op(s, CC_OP_LOGICB + ot); - break; - - case 0x0f7: /* bextr Gy, Ey, By */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - { - TCGv bound, zero; - - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - /* Extract START, and shift the operand. - Shifts larger than operand size get zeros. */ - tcg_gen_ext8u_tl(s->A0, cpu_regs[s->vex_v]); - tcg_gen_shr_tl(s->T0, s->T0, s->A0); - - bound = tcg_const_tl(ot == MO_64 ? 63 : 31); - zero = tcg_const_tl(0); - tcg_gen_movcond_tl(TCG_COND_LEU, s->T0, s->A0, bound, - s->T0, zero); - tcg_temp_free(zero); - - /* Extract the LEN into a mask. Lengths larger than - operand size get all ones. */ - tcg_gen_extract_tl(s->A0, cpu_regs[s->vex_v], 8, 8); - tcg_gen_movcond_tl(TCG_COND_LEU, s->A0, s->A0, bound, - s->A0, bound); - tcg_temp_free(bound); - tcg_gen_movi_tl(s->T1, 1); - tcg_gen_shl_tl(s->T1, s->T1, s->A0); - tcg_gen_subi_tl(s->T1, s->T1, 1); - tcg_gen_and_tl(s->T0, s->T0, s->T1); - - gen_op_mov_reg_v(s, ot, reg, s->T0); - gen_op_update1_cc(s); - set_cc_op(s, CC_OP_LOGICB + ot); - } - break; - - case 0x0f5: /* bzhi Gy, Ey, By */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - tcg_gen_ext8u_tl(s->T1, cpu_regs[s->vex_v]); - { - TCGv bound = tcg_const_tl(ot == MO_64 ? 63 : 31); - /* Note that since we're using BMILG (in order to get O - cleared) we need to store the inverse into C. */ - tcg_gen_setcond_tl(TCG_COND_LT, cpu_cc_src, - s->T1, bound); - tcg_gen_movcond_tl(TCG_COND_GT, s->T1, s->T1, - bound, bound, s->T1); - tcg_temp_free(bound); - } - tcg_gen_movi_tl(s->A0, -1); - tcg_gen_shl_tl(s->A0, s->A0, s->T1); - tcg_gen_andc_tl(s->T0, s->T0, s->A0); - gen_op_mov_reg_v(s, ot, reg, s->T0); - gen_op_update1_cc(s); - set_cc_op(s, CC_OP_BMILGB + ot); - break; - - case 0x3f6: /* mulx By, Gy, rdx, Ey */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - switch (ot) { - default: - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - tcg_gen_trunc_tl_i32(s->tmp3_i32, cpu_regs[R_EDX]); - tcg_gen_mulu2_i32(s->tmp2_i32, s->tmp3_i32, - s->tmp2_i32, s->tmp3_i32); - tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], s->tmp2_i32); - tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp3_i32); - break; -#ifdef TARGET_X86_64 - case MO_64: - tcg_gen_mulu2_i64(s->T0, s->T1, - s->T0, cpu_regs[R_EDX]); - tcg_gen_mov_i64(cpu_regs[s->vex_v], s->T0); - tcg_gen_mov_i64(cpu_regs[reg], s->T1); - break; -#endif - } - break; - - case 0x3f5: /* pdep Gy, By, Ey */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - /* Note that by zero-extending the source operand, we - automatically handle zero-extending the result. */ - if (ot == MO_64) { - tcg_gen_mov_tl(s->T1, cpu_regs[s->vex_v]); - } else { - tcg_gen_ext32u_tl(s->T1, cpu_regs[s->vex_v]); - } - gen_helper_pdep(cpu_regs[reg], s->T1, s->T0); - break; - - case 0x2f5: /* pext Gy, By, Ey */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - /* Note that by zero-extending the source operand, we - automatically handle zero-extending the result. */ - if (ot == MO_64) { - tcg_gen_mov_tl(s->T1, cpu_regs[s->vex_v]); - } else { - tcg_gen_ext32u_tl(s->T1, cpu_regs[s->vex_v]); - } - gen_helper_pext(cpu_regs[reg], s->T1, s->T0); - break; - - case 0x1f6: /* adcx Gy, Ey */ - case 0x2f6: /* adox Gy, Ey */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX)) { - goto illegal_op; - } else { - TCGv carry_in, carry_out, zero; - int end_op; - - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - - /* Re-use the carry-out from a previous round. */ - carry_in = NULL; - carry_out = (b == 0x1f6 ? cpu_cc_dst : cpu_cc_src2); - switch (s->cc_op) { - case CC_OP_ADCX: - if (b == 0x1f6) { - carry_in = cpu_cc_dst; - end_op = CC_OP_ADCX; - } else { - end_op = CC_OP_ADCOX; - } - break; - case CC_OP_ADOX: - if (b == 0x1f6) { - end_op = CC_OP_ADCOX; - } else { - carry_in = cpu_cc_src2; - end_op = CC_OP_ADOX; - } - break; - case CC_OP_ADCOX: - end_op = CC_OP_ADCOX; - carry_in = carry_out; - break; - default: - end_op = (b == 0x1f6 ? CC_OP_ADCX : CC_OP_ADOX); - break; - } - /* If we can't reuse carry-out, get it out of EFLAGS. */ - if (!carry_in) { - if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) { - gen_compute_eflags(s); - } - carry_in = s->tmp0; - tcg_gen_extract_tl(carry_in, cpu_cc_src, - ctz32(b == 0x1f6 ? CC_C : CC_O), 1); - } - - switch (ot) { -#ifdef TARGET_X86_64 - case MO_32: - /* If we know TL is 64-bit, and we want a 32-bit - result, just do everything in 64-bit arithmetic. */ - tcg_gen_ext32u_i64(cpu_regs[reg], cpu_regs[reg]); - tcg_gen_ext32u_i64(s->T0, s->T0); - tcg_gen_add_i64(s->T0, s->T0, cpu_regs[reg]); - tcg_gen_add_i64(s->T0, s->T0, carry_in); - tcg_gen_ext32u_i64(cpu_regs[reg], s->T0); - tcg_gen_shri_i64(carry_out, s->T0, 32); - break; -#endif - default: - /* Otherwise compute the carry-out in two steps. */ - zero = tcg_const_tl(0); - tcg_gen_add2_tl(s->T0, carry_out, - s->T0, zero, - carry_in, zero); - tcg_gen_add2_tl(cpu_regs[reg], carry_out, - cpu_regs[reg], carry_out, - s->T0, zero); - tcg_temp_free(zero); - break; - } - set_cc_op(s, end_op); - } - break; - - case 0x1f7: /* shlx Gy, Ey, By */ - case 0x2f7: /* sarx Gy, Ey, By */ - case 0x3f7: /* shrx Gy, Ey, By */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - if (ot == MO_64) { - tcg_gen_andi_tl(s->T1, cpu_regs[s->vex_v], 63); - } else { - tcg_gen_andi_tl(s->T1, cpu_regs[s->vex_v], 31); - } - if (b == 0x1f7) { - tcg_gen_shl_tl(s->T0, s->T0, s->T1); - } else if (b == 0x2f7) { - if (ot != MO_64) { - tcg_gen_ext32s_tl(s->T0, s->T0); - } - tcg_gen_sar_tl(s->T0, s->T0, s->T1); - } else { - if (ot != MO_64) { - tcg_gen_ext32u_tl(s->T0, s->T0); - } - tcg_gen_shr_tl(s->T0, s->T0, s->T1); - } - gen_op_mov_reg_v(s, ot, reg, s->T0); - break; - - case 0x0f3: - case 0x1f3: - case 0x2f3: - case 0x3f3: /* Group 17 */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - - tcg_gen_mov_tl(cpu_cc_src, s->T0); - switch (reg & 7) { - case 1: /* blsr By,Ey */ - tcg_gen_subi_tl(s->T1, s->T0, 1); - tcg_gen_and_tl(s->T0, s->T0, s->T1); - break; - case 2: /* blsmsk By,Ey */ - tcg_gen_subi_tl(s->T1, s->T0, 1); - tcg_gen_xor_tl(s->T0, s->T0, s->T1); - break; - case 3: /* blsi By, Ey */ - tcg_gen_neg_tl(s->T1, s->T0); - tcg_gen_and_tl(s->T0, s->T0, s->T1); - break; - default: - goto unknown_op; - } - tcg_gen_mov_tl(cpu_cc_dst, s->T0); - gen_op_mov_reg_v(s, ot, s->vex_v, s->T0); - set_cc_op(s, CC_OP_BMILGB + ot); - break; - - default: - goto unknown_op; - } - break; - - case 0x03a: - case 0x13a: - b = modrm; - modrm = x86_ldub_code(env, s); - rm = modrm & 7; - reg = ((modrm >> 3) & 7) | REX_R(s); - mod = (modrm >> 6) & 3; - - assert(b1 < 2); - sse_fn_eppi = sse_op_table7[b].op[b1]; - if (!sse_fn_eppi) { - goto unknown_op; - } - if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask)) - goto illegal_op; - - s->rip_offset = 1; - - if (sse_fn_eppi == SSE_SPECIAL) { - ot = mo_64_32(s->dflag); - rm = (modrm & 7) | REX_B(s); - if (mod != 3) - gen_lea_modrm(env, s, modrm); - reg = ((modrm >> 3) & 7) | REX_R(s); - val = x86_ldub_code(env, s); - switch (b) { - case 0x14: /* pextrb */ - tcg_gen_ld8u_tl(s->T0, cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_B(val & 15))); - if (mod == 3) { - gen_op_mov_reg_v(s, ot, rm, s->T0); - } else { - tcg_gen_qemu_st_tl(s->T0, s->A0, - s->mem_index, MO_UB); - } - break; - case 0x15: /* pextrw */ - tcg_gen_ld16u_tl(s->T0, cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_W(val & 7))); - if (mod == 3) { - gen_op_mov_reg_v(s, ot, rm, s->T0); - } else { - tcg_gen_qemu_st_tl(s->T0, s->A0, - s->mem_index, MO_LEUW); - } - break; - case 0x16: - if (ot == MO_32) { /* pextrd */ - tcg_gen_ld_i32(s->tmp2_i32, cpu_env, - offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(val & 3))); - if (mod == 3) { - tcg_gen_extu_i32_tl(cpu_regs[rm], s->tmp2_i32); - } else { - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - } - } else { /* pextrq */ -#ifdef TARGET_X86_64 - tcg_gen_ld_i64(s->tmp1_i64, cpu_env, - offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(val & 1))); - if (mod == 3) { - tcg_gen_mov_i64(cpu_regs[rm], s->tmp1_i64); - } else { - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, - s->mem_index, MO_LEUQ); - } -#else - goto illegal_op; -#endif - } - break; - case 0x17: /* extractps */ - tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(val & 3))); - if (mod == 3) { - gen_op_mov_reg_v(s, ot, rm, s->T0); - } else { - tcg_gen_qemu_st_tl(s->T0, s->A0, - s->mem_index, MO_LEUL); - } - break; - case 0x20: /* pinsrb */ - if (mod == 3) { - gen_op_mov_v_reg(s, MO_32, s->T0, rm); - } else { - tcg_gen_qemu_ld_tl(s->T0, s->A0, - s->mem_index, MO_UB); - } - tcg_gen_st8_tl(s->T0, cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_B(val & 15))); - break; - case 0x21: /* insertps */ - if (mod == 3) { - tcg_gen_ld_i32(s->tmp2_i32, cpu_env, - offsetof(CPUX86State,xmm_regs[rm] - .ZMM_L((val >> 6) & 3))); - } else { - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - } - tcg_gen_st_i32(s->tmp2_i32, cpu_env, - offsetof(CPUX86State,xmm_regs[reg] - .ZMM_L((val >> 4) & 3))); - if ((val >> 0) & 1) - tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), - cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(0))); - if ((val >> 1) & 1) - tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), - cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(1))); - if ((val >> 2) & 1) - tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), - cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(2))); - if ((val >> 3) & 1) - tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/), - cpu_env, offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(3))); - break; - case 0x22: - if (ot == MO_32) { /* pinsrd */ - if (mod == 3) { - tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[rm]); - } else { - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, - s->mem_index, MO_LEUL); - } - tcg_gen_st_i32(s->tmp2_i32, cpu_env, - offsetof(CPUX86State, - xmm_regs[reg].ZMM_L(val & 3))); - } else { /* pinsrq */ -#ifdef TARGET_X86_64 - if (mod == 3) { - gen_op_mov_v_reg(s, ot, s->tmp1_i64, rm); - } else { - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, - s->mem_index, MO_LEUQ); - } - tcg_gen_st_i64(s->tmp1_i64, cpu_env, - offsetof(CPUX86State, - xmm_regs[reg].ZMM_Q(val & 1))); -#else - goto illegal_op; -#endif - } - break; - } - 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); - } - } else { - op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); - if (mod == 3) { - op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); - } else { - op2_offset = offsetof(CPUX86State,mmx_t0); - gen_lea_modrm(env, s, modrm); - gen_ldq_env_A0(s, op2_offset); - } - } - val = x86_ldub_code(env, s); + do_gen_eob_worker(s, false, false, true); +} - if ((b & 0xfc) == 0x60) { /* pcmpXstrX */ - set_cc_op(s, CC_OP_EFLAGS); +/* Jump to eip+diff, truncating the result to OT. */ +static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num) +{ + bool use_goto_tb = s->jmp_opt; + target_ulong mask = -1; + target_ulong new_pc = s->pc + diff; + target_ulong new_eip = new_pc - s->cs_base; - if (s->dflag == MO_64) { - /* The helper must use entire 64-bit gp registers */ - val |= 1 << 8; - } + /* In 64-bit mode, operand size is fixed at 64 bits. */ + if (!CODE64(s)) { + if (ot == MO_16) { + mask = 0xffff; + if (TARGET_TB_PCREL && CODE32(s)) { + use_goto_tb = false; } + } else { + mask = 0xffffffff; + } + } + new_eip &= mask; - 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)); - break; - - case 0x33a: - /* Various integer extensions at 0f 3a f[0-f]. */ - b = modrm | (b1 << 8); - modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | REX_R(s); - - switch (b) { - case 0x3f0: /* rorx Gy,Ey, Ib */ - if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) - || !(s->prefix & PREFIX_VEX) - || s->vex_l != 0) { - goto illegal_op; - } - ot = mo_64_32(s->dflag); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - b = x86_ldub_code(env, s); - if (ot == MO_64) { - tcg_gen_rotri_tl(s->T0, s->T0, b & 63); - } else { - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - tcg_gen_rotri_i32(s->tmp2_i32, s->tmp2_i32, b & 31); - tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); - } - gen_op_mov_reg_v(s, ot, reg, s->T0); - break; + gen_update_cc_op(s); + set_cc_op(s, CC_OP_DYNAMIC); - default: - goto unknown_op; - } - break; + if (TARGET_TB_PCREL) { + tcg_gen_addi_tl(cpu_eip, cpu_eip, new_pc - s->pc_save); + /* + * If we can prove the branch does not leave the page and we have + * no extra masking to apply (data16 branch in code32, see above), + * then we have also proven that the addition does not wrap. + */ + if (!use_goto_tb || !is_same_page(&s->base, new_pc)) { + tcg_gen_andi_tl(cpu_eip, cpu_eip, mask); + use_goto_tb = false; + } + } - default: - unknown_op: - gen_unknown_opcode(env, s); - return; + if (use_goto_tb && + translator_use_goto_tb(&s->base, new_eip + s->cs_base)) { + /* jump to same page: we can use a direct jump */ + tcg_gen_goto_tb(tb_num); + if (!TARGET_TB_PCREL) { + tcg_gen_movi_tl(cpu_eip, new_eip); } + tcg_gen_exit_tb(s->base.tb, tb_num); + s->base.is_jmp = DISAS_NORETURN; } else { - /* generic MMX or SSE operation */ - switch(b) { - case 0x70: /* pshufx insn */ - case 0xc6: /* pshufx insn */ - case 0xc2: /* compare insns */ - s->rip_offset = 1; - break; - default: - break; + if (!TARGET_TB_PCREL) { + tcg_gen_movi_tl(cpu_eip, new_eip); } - if (is_xmm) { - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); - if (mod != 3) { - int sz = 4; + if (s->jmp_opt) { + gen_jr(s); /* jump to another page */ + } else { + gen_eob(s); /* exit to main loop */ + } + } +} - gen_lea_modrm(env, s, modrm); - 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; +/* Jump to eip+diff, truncating to the current code size. */ +static void gen_jmp_rel_csize(DisasContext *s, int diff, int tb_num) +{ + /* CODE64 ignores the OT argument, so we need not consider it. */ + gen_jmp_rel(s, CODE32(s) ? MO_32 : MO_16, diff, tb_num); +} - case 0x2e: /* ucomis[sd] */ - case 0x2f: /* comis[sd] */ - if (b1 == 0) { - sz = 2; - } else { - sz = 3; - } - break; - } +static inline void gen_ldq_env_A0(DisasContext *s, int offset) +{ + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset); +} - switch (sz) { - case 2: - /* 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))); - break; - case 3: - /* 64 bit access */ - gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.ZMM_D(0))); - break; - default: - /* 128 bit access */ - gen_ldo_env_A0(s, op2_offset); - break; - } - } else { - rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); - } - } else { - op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); - if (mod != 3) { - gen_lea_modrm(env, s, modrm); - op2_offset = offsetof(CPUX86State,mmx_t0); - gen_ldq_env_A0(s, op2_offset); - } else { - rm = (modrm & 7); - op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); - } - } - switch(b) { - case 0x0f: /* 3DNow! data insns */ - 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: - /* maskmov : we must prepare A0 */ - 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); +static inline void gen_stq_env_A0(DisasContext *s, int offset) +{ + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); +} - 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; - } - if (b == 0x2e || b == 0x2f) { - set_cc_op(s, CC_OP_EFLAGS); - } - } +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 | (align ? MO_ALIGN_16 : 0)); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_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(XMMReg, XMM_Q(1))); +} + +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(XMMReg, XMM_Q(0))); + 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(XMMReg, XMM_Q(1))); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); +} + +static void gen_ldy_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 | (align ? MO_ALIGN_32 : 0)); + tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_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(YMMReg, YMM_Q(1))); + + tcg_gen_addi_tl(s->tmp0, s->A0, 16); + 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(YMMReg, YMM_Q(2))); + tcg_gen_addi_tl(s->tmp0, s->A0, 24); + 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(YMMReg, YMM_Q(3))); +} + +static void gen_sty_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(YMMReg, YMM_Q(0))); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, + MO_LEUQ | (align ? MO_ALIGN_32 : 0)); + tcg_gen_addi_tl(s->tmp0, s->A0, 8); + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(1))); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); + tcg_gen_addi_tl(s->tmp0, s->A0, 16); + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(2))); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); + tcg_gen_addi_tl(s->tmp0, s->A0, 24); + tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(YMMReg, YMM_Q(3))); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); } +#include "decode-new.h" +#include "emit.c.inc" +#include "decode-new.c.inc" + /* convert one instruction. s->base.is_jmp is set if the translation must be stopped. Return the next pc value */ -static target_ulong disas_insn(DisasContext *s, CPUState *cpu) +static bool disas_insn(DisasContext *s, CPUState *cpu) { CPUX86State *env = cpu->env_ptr; int b, prefixes; int shift; MemOp ot, aflag, dflag; 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; + target_ulong orig_pc_save = s->pc_save; - s->pc_start = s->pc = pc_start; + s->pc = s->base.pc_next; s->override = -1; #ifdef TARGET_X86_64 - s->rex_w = false; s->rex_r = 0; s->rex_x = 0; s->rex_b = 0; @@ -4566,22 +3016,52 @@ 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) { + s->vex_w = false; + switch (sigsetjmp(s->jmpbuf, 0)) { + case 0: + break; + case 1: gen_exception_gpf(s); - return s->pc; + return true; + case 2: + /* Restore state that may affect the next instruction. */ + s->pc = s->base.pc_next; + /* + * TODO: These save/restore can be removed after the table-based + * decoder is complete; we will be decoding the insn completely + * before any code generation that might affect these variables. + */ + s->cc_op_dirty = orig_cc_op_dirty; + s->cc_op = orig_cc_op; + s->pc_save = orig_pc_save; + /* END TODO */ + s->base.num_insns--; + tcg_remove_ops_after(s->prev_insn_end); + s->base.is_jmp = DISAS_TOO_MANY; + return false; + default: + g_assert_not_reached(); } prefixes = 0; next_byte: + s->prefix = prefixes; b = x86_ldub_code(env, s); /* Collect prefixes. */ switch (b) { + default: + break; + case 0x0f: + b = x86_ldub_code(env, s) + 0x100; + break; 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; @@ -4615,7 +3095,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (CODE64(s)) { /* REX prefix */ prefixes |= PREFIX_REX; - s->rex_w = (b >> 3) & 1; + s->vex_w = (b >> 3) & 1; s->rex_r = (b & 0x4) << 1; s->rex_x = (b & 0x2) << 2; s->rex_b = (b & 0x1) << 3; @@ -4625,58 +3105,17 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) #endif case 0xc5: /* 2-byte VEX */ case 0xc4: /* 3-byte VEX */ - /* VEX prefixes cannot be used except in 32-bit mode. - Otherwise the instruction is LES or LDS. */ if (CODE32(s) && !VM86(s)) { - static const int pp_prefix[4] = { - 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ - }; - int vex3, vex2 = x86_ldub_code(env, s); + int vex2 = x86_ldub_code(env, s); + s->pc--; /* rewind the advance_pc() x86_ldub_code() did */ if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) { /* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b, otherwise the instruction is LES or LDS. */ - s->pc--; /* rewind the advance_pc() x86_ldub_code() did */ break; } - - /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */ - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ - | PREFIX_LOCK | PREFIX_DATA | PREFIX_REX)) { - goto illegal_op; - } -#ifdef TARGET_X86_64 - s->rex_r = (~vex2 >> 4) & 8; -#endif - if (b == 0xc5) { - /* 2-byte VEX prefix: RVVVVlpp, implied 0f leading opcode byte */ - vex3 = vex2; - b = x86_ldub_code(env, s) | 0x100; - } else { - /* 3-byte VEX prefix: RXBmmmmm wVVVVlpp */ - vex3 = x86_ldub_code(env, s); -#ifdef TARGET_X86_64 - s->rex_x = (~vex2 >> 3) & 8; - s->rex_b = (~vex2 >> 2) & 8; - s->rex_w = (vex3 >> 7) & 1; -#endif - switch (vex2 & 0x1f) { - case 0x01: /* Implied 0f leading opcode bytes. */ - b = x86_ldub_code(env, s) | 0x100; - break; - case 0x02: /* Implied 0f 38 leading opcode bytes. */ - b = 0x138; - break; - case 0x03: /* Implied 0f 3a leading opcode bytes. */ - b = 0x13a; - break; - default: /* Reserved for future use. */ - goto unknown_op; - } - } - s->vex_v = (~vex3 >> 3) & 0xf; - s->vex_l = (vex3 >> 2) & 1; - prefixes |= pp_prefix[vex3 & 3] | PREFIX_VEX; + disas_insn_new(s, cpu, b); + return s->pc; } break; } @@ -4709,14 +3148,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) s->dflag = dflag; /* now check op code */ - reswitch: - switch(b) { - case 0x0f: - /**************************/ - /* extended op code */ - b = x86_ldub_code(env, s) | 0x100; - goto reswitch; - + switch (b) { /**************************/ /* arith & logic */ case 0x00 ... 0x05: @@ -4907,7 +3339,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_temp_free(t2); tcg_temp_free(a0); - tcg_gen_mov_tl(s->T0, t0); + tcg_gen_neg_tl(s->T0, t0); tcg_temp_free(t0); } else { tcg_gen_neg_tl(s->T0, s->T0); @@ -5116,12 +3548,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (dflag == MO_16) { tcg_gen_ext16u_tl(s->T0, s->T0); } - next_eip = s->pc - s->cs_base; - tcg_gen_movi_tl(s->T1, next_eip); - gen_push_v(s, s->T1); - gen_op_jmp_v(s->T0); + gen_push_v(s, eip_next_tl(s)); + gen_op_jmp_v(s, s->T0); gen_bnd_jmp(s); - gen_jr(s, s->T0); + s->base.is_jmp = DISAS_JUMP; break; case 3: /* lcall Ev */ if (mod == 3) { @@ -5134,24 +3564,24 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1, - tcg_const_i32(dflag - 1), - tcg_const_tl(s->pc - s->cs_base)); + tcg_constant_i32(dflag - 1), + eip_next_tl(s)); } else { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->T1, - tcg_const_i32(dflag - 1), - tcg_const_i32(s->pc - s->cs_base)); + tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); + gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->tmp3_i32, + tcg_constant_i32(dflag - 1), + eip_next_i32(s)); } - tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip)); - gen_jr(s, s->tmp4); + s->base.is_jmp = DISAS_JUMP; break; case 4: /* jmp Ev */ if (dflag == MO_16) { tcg_gen_ext16u_tl(s->T0, s->T0); } - gen_op_jmp_v(s->T0); + gen_op_jmp_v(s, s->T0); gen_bnd_jmp(s); - gen_jr(s, s->T0); + s->base.is_jmp = DISAS_JUMP; break; case 5: /* ljmp Ev */ if (mod == 3) { @@ -5164,13 +3594,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1, - tcg_const_tl(s->pc - s->cs_base)); + eip_next_tl(s)); } else { gen_op_movl_seg_T0_vm(s, R_CS); - gen_op_jmp_v(s->T1); + gen_op_jmp_v(s, s->T1); } - tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip)); - gen_jr(s, s->tmp4); + s->base.is_jmp = DISAS_JUMP; break; case 6: /* push Ev */ gen_push_v(s, s->T0); @@ -5337,7 +3766,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x1b0: case 0x1b1: /* cmpxchg Ev, Gv */ { - TCGv oldv, newv, cmpv; + TCGv oldv, newv, cmpv, dest; ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); @@ -5348,7 +3777,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) cmpv = tcg_temp_new(); gen_op_mov_v_reg(s, ot, newv, reg); tcg_gen_mov_tl(cmpv, cpu_regs[R_EAX]); - + gen_extu(ot, cmpv); if (s->prefix & PREFIX_LOCK) { if (mod == 3) { goto illegal_op; @@ -5356,32 +3785,43 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_lea_modrm(env, s, modrm); tcg_gen_atomic_cmpxchg_tl(oldv, s->A0, cmpv, newv, s->mem_index, ot | MO_LE); - gen_op_mov_reg_v(s, ot, R_EAX, oldv); } else { if (mod == 3) { rm = (modrm & 7) | REX_B(s); gen_op_mov_v_reg(s, ot, oldv, rm); + gen_extu(ot, oldv); + + /* + * Unlike the memory case, where "the destination operand receives + * a write cycle without regard to the result of the comparison", + * rm must not be touched altogether if the write fails, including + * not zero-extending it on 64-bit processors. So, precompute + * the result of a successful writeback and perform the movcond + * directly on cpu_regs. Also need to write accumulator first, in + * case rm is part of RAX too. + */ + dest = gen_op_deposit_reg_v(s, ot, rm, newv, newv); + tcg_gen_movcond_tl(TCG_COND_EQ, dest, oldv, cmpv, newv, dest); } else { gen_lea_modrm(env, s, modrm); gen_op_ld_v(s, ot, oldv, s->A0); - rm = 0; /* avoid warning */ - } - gen_extu(ot, oldv); - gen_extu(ot, cmpv); - /* store value = (old == cmp ? new : old); */ - tcg_gen_movcond_tl(TCG_COND_EQ, newv, oldv, cmpv, newv, oldv); - if (mod == 3) { - gen_op_mov_reg_v(s, ot, R_EAX, oldv); - gen_op_mov_reg_v(s, ot, rm, newv); - } else { - /* Perform an unconditional store cycle like physical cpu; - must be before changing accumulator to ensure - idempotency if the store faults and the instruction - is restarted */ + + /* + * Perform an unconditional store cycle like physical cpu; + * must be before changing accumulator to ensure + * idempotency if the store faults and the instruction + * is restarted + */ + tcg_gen_movcond_tl(TCG_COND_EQ, newv, oldv, cmpv, newv, oldv); gen_op_st_v(s, ot, newv, s->A0); - gen_op_mov_reg_v(s, ot, R_EAX, oldv); } } + /* + * Write EAX only if the cmpxchg fails; reuse newv as the destination, + * since it's dead here. + */ + dest = gen_op_deposit_reg_v(s, ot, R_EAX, newv, oldv); + tcg_gen_movcond_tl(TCG_COND_EQ, dest, oldv, cmpv, dest, newv); tcg_gen_mov_tl(cpu_cc_src, oldv); tcg_gen_mov_tl(s->cc_srcT, cmpv); tcg_gen_sub_tl(cpu_cc_dst, cmpv, oldv); @@ -5437,14 +3877,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_helper_rdrand(s->T0, cpu_env); rm = (modrm & 7) | REX_B(s); gen_op_mov_reg_v(s, dflag, rm, s->T0); set_cc_op(s, CC_OP_EFLAGS); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; default: @@ -5535,26 +3973,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) ot = gen_pop_T0(s); gen_movl_seg_T0(s, reg); gen_pop_update(s, ot); - /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */ - if (s->base.is_jmp) { - gen_jmp_im(s, s->pc - s->cs_base); - if (reg == R_SS) { - s->flags &= ~HF_TF_MASK; - gen_eob_inhibit_irq(s, true); - } else { - gen_eob(s); - } - } break; case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ ot = gen_pop_T0(s); gen_movl_seg_T0(s, (b >> 3) & 7); gen_pop_update(s, ot); - if (s->base.is_jmp) { - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); - } break; /**************************/ @@ -5601,16 +4025,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_movl_seg_T0(s, reg); - /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */ - if (s->base.is_jmp) { - gen_jmp_im(s, s->pc - s->cs_base); - if (reg == R_SS) { - s->flags &= ~HF_TF_MASK; - gen_eob_inhibit_irq(s, true); - } else { - gen_eob(s); - } - } break; case 0x8c: /* mov Gv, seg */ modrm = x86_ldub_code(env, s); @@ -5681,7 +4095,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) reg = ((modrm >> 3) & 7) | REX_R(s); { AddressParts a = gen_lea_modrm_0(env, s, modrm); - TCGv ea = gen_lea_modrm_1(s, a); + TCGv ea = gen_lea_modrm_1(s, a, false); gen_lea_v_seg(s, s->aflag, ea, -1, -1); gen_op_mov_reg_v(s, dflag, reg, s->A0); } @@ -5695,16 +4109,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) { @@ -5809,10 +4214,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_movl_seg_T0(s, op); /* then put the data */ gen_op_mov_reg_v(s, ot, reg, s->T1); - if (s->base.is_jmp) { - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); - } break; /************************/ @@ -5907,7 +4308,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { /* if CR0.EM or CR0.TS are set, generate an FPU exception */ /* XXX: what to do if illegal op ? */ - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + gen_exception(s, EXCP07_PREX); break; } modrm = x86_ldub_code(env, s); @@ -5917,7 +4318,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (mod != 3) { /* memory op */ AddressParts a = gen_lea_modrm_0(env, s, modrm); - TCGv ea = gen_lea_modrm_1(s, a); + TCGv ea = gen_lea_modrm_1(s, a, false); TCGv last_addr = tcg_temp_new(); bool update_fdp = true; @@ -6448,7 +4849,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) offsetof(CPUX86State, segs[R_CS].selector)); tcg_gen_st16_i32(s->tmp2_i32, cpu_env, offsetof(CPUX86State, fpcs)); - tcg_gen_st_tl(tcg_constant_tl(pc_start - s->cs_base), + tcg_gen_st_tl(eip_cur_tl(s), cpu_env, offsetof(CPUX86State, fpip)); } } @@ -6460,7 +4861,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xa5: ot = mo_b_d(b, dflag); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + gen_repz_movs(s, ot); } else { gen_movs(s, ot); } @@ -6470,7 +4871,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xab: ot = mo_b_d(b, dflag); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + gen_repz_stos(s, ot); } else { gen_stos(s, ot); } @@ -6479,7 +4880,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xad: ot = mo_b_d(b, dflag); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + gen_repz_lods(s, ot); } else { gen_lods(s, ot); } @@ -6488,9 +4889,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xaf: ot = mo_b_d(b, dflag); if (prefixes & PREFIX_REPNZ) { - gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); + gen_repz_scas(s, ot, 1); } else if (prefixes & PREFIX_REPZ) { - gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); + gen_repz_scas(s, ot, 0); } else { gen_scas(s, ot); } @@ -6500,9 +4901,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xa7: ot = mo_b_d(b, dflag); if (prefixes & PREFIX_REPNZ) { - gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); + gen_repz_cmps(s, ot, 1); } else if (prefixes & PREFIX_REPZ) { - gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); + gen_repz_cmps(s, ot, 0); } else { gen_cmps(s, ot); } @@ -6518,15 +4919,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - /* jump generated by gen_repz_ins */ + gen_repz_ins(s, ot); } else { gen_ins(s, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } } break; case 0x6e: /* outsS */ @@ -6539,15 +4937,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - /* jump generated by gen_repz_outs */ + gen_repz_outs(s, ot); } else { gen_outs(s, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } } break; @@ -6564,13 +4959,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_helper_in_func(ot, s->T1, s->tmp2_i32); gen_op_mov_reg_v(s, ot, R_EAX, s->T1); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; case 0xe6: case 0xe7: @@ -6582,14 +4975,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_op_mov_v_reg(s, ot, s->T1, R_EAX); tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; case 0xec: case 0xed: @@ -6601,13 +4992,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_helper_in_func(ot, s->T1, s->tmp2_i32); gen_op_mov_reg_v(s, ot, R_EAX, s->T1); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; case 0xee: case 0xef: @@ -6619,14 +5008,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_op_mov_v_reg(s, ot, s->T1, R_EAX); tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; /************************/ @@ -6636,24 +5023,24 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) ot = gen_pop_T0(s); gen_stack_update(s, val + (1 << ot)); /* Note that gen_pop_T0 uses a zero-extending load. */ - gen_op_jmp_v(s->T0); + gen_op_jmp_v(s, s->T0); gen_bnd_jmp(s); - gen_jr(s, s->T0); + s->base.is_jmp = DISAS_JUMP; break; case 0xc3: /* ret */ ot = gen_pop_T0(s); gen_pop_update(s, ot); /* Note that gen_pop_T0 uses a zero-extending load. */ - gen_op_jmp_v(s->T0); + gen_op_jmp_v(s, s->T0); gen_bnd_jmp(s); - gen_jr(s, s->T0); + s->base.is_jmp = DISAS_JUMP; break; case 0xca: /* lret im */ val = x86_ldsw_code(env, s); do_lret: if (PE(s) && !VM86(s)) { gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1), tcg_const_i32(val)); } else { @@ -6662,7 +5049,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_ld_v(s, dflag, s->T0, s->A0); /* NOTE: keeping EIP updated is not a problem in case of exception */ - gen_op_jmp_v(s->T0); + gen_op_jmp_v(s, s->T0); /* pop selector */ gen_add_A0_im(s, 1 << dflag); gen_op_ld_v(s, dflag, s->T0, s->A0); @@ -6670,7 +5057,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* add stack offset */ gen_stack_update(s, val + (2 << dflag)); } - gen_eob(s); + s->base.is_jmp = DISAS_EOB_ONLY; break; case 0xcb: /* lret */ val = 0; @@ -6684,30 +5071,20 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1)); } else { - gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1), - tcg_const_i32(s->pc - s->cs_base)); + gen_helper_iret_protected(cpu_env, tcg_constant_i32(dflag - 1), + eip_next_i32(s)); } set_cc_op(s, CC_OP_EFLAGS); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_ONLY; break; case 0xe8: /* call im */ { - if (dflag != MO_16) { - tval = (int32_t)insn_get(env, s, MO_32); - } else { - tval = (int16_t)insn_get(env, s, MO_16); - } - next_eip = s->pc - s->cs_base; - tval += next_eip; - if (dflag == MO_16) { - tval &= 0xffff; - } else if (!CODE64(s)) { - tval &= 0xffffffff; - } - tcg_gen_movi_tl(s->T0, next_eip); - gen_push_v(s, s->T0); + int diff = (dflag != MO_16 + ? (int32_t)insn_get(env, s, MO_32) + : (int16_t)insn_get(env, s, MO_16)); + gen_push_v(s, eip_next_tl(s)); gen_bnd_jmp(s); - gen_jmp(s, tval); + gen_jmp_rel(s, dflag, diff, 0); } break; case 0x9a: /* lcall im */ @@ -6725,19 +5102,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } goto do_lcall; case 0xe9: /* jmp im */ - if (dflag != MO_16) { - tval = (int32_t)insn_get(env, s, MO_32); - } else { - tval = (int16_t)insn_get(env, s, MO_16); - } - tval += s->pc - s->cs_base; - if (dflag == MO_16) { - tval &= 0xffff; - } else if (!CODE64(s)) { - tval &= 0xffffffff; + { + int diff = (dflag != MO_16 + ? (int32_t)insn_get(env, s, MO_32) + : (int16_t)insn_get(env, s, MO_16)); + gen_bnd_jmp(s); + gen_jmp_rel(s, dflag, diff, 0); } - gen_bnd_jmp(s); - gen_jmp(s, tval); break; case 0xea: /* ljmp im */ { @@ -6754,30 +5125,26 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } goto do_ljmp; case 0xeb: /* jmp Jb */ - tval = (int8_t)insn_get(env, s, MO_8); - tval += s->pc - s->cs_base; - if (dflag == MO_16) { - tval &= 0xffff; + { + int diff = (int8_t)insn_get(env, s, MO_8); + gen_jmp_rel(s, dflag, diff, 0); } - gen_jmp(s, tval); break; case 0x70 ... 0x7f: /* jcc Jb */ - tval = (int8_t)insn_get(env, s, MO_8); - goto do_jcc; - case 0x180 ... 0x18f: /* jcc Jv */ - if (dflag != MO_16) { - tval = (int32_t)insn_get(env, s, MO_32); - } else { - tval = (int16_t)insn_get(env, s, MO_16); + { + int diff = (int8_t)insn_get(env, s, MO_8); + gen_bnd_jmp(s); + gen_jcc(s, b, diff); } - do_jcc: - next_eip = s->pc - s->cs_base; - tval += next_eip; - if (dflag == MO_16) { - tval &= 0xffff; + break; + case 0x180 ... 0x18f: /* jcc Jv */ + { + int diff = (dflag != MO_16 + ? (int32_t)insn_get(env, s, MO_32) + : (int16_t)insn_get(env, s, MO_16)); + gen_bnd_jmp(s); + gen_jcc(s, b, diff); } - gen_bnd_jmp(s); - gen_jcc(s, b, tval, next_eip); break; case 0x190 ... 0x19f: /* setcc Gv */ @@ -6857,14 +5224,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_pop_update(s, ot); set_cc_op(s, CC_OP_EFLAGS); /* abort translation because TF/AC flag may change */ - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; } break; case 0x9e: /* sahf */ if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; - gen_op_mov_v_reg(s, MO_8, s->T0, R_AH); + tcg_gen_shri_tl(s->T0, cpu_regs[R_EAX], 8); gen_compute_eflags(s); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); tcg_gen_andi_tl(s->T0, s->T0, CC_S | CC_Z | CC_A | CC_P | CC_C); @@ -6876,7 +5242,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_compute_eflags(s); /* Note: gen_compute_eflags() only gives the condition codes */ tcg_gen_ori_tl(s->T0, cpu_cc_src, 0x02); - gen_op_mov_reg_v(s, MO_8, R_AH, s->T0); + tcg_gen_deposit_tl(cpu_regs[R_EAX], cpu_regs[R_EAX], s->T0, 8, 8); break; case 0xf5: /* cmc */ gen_compute_eflags(s); @@ -6947,7 +5313,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_exts(ot, s->T1); tcg_gen_sari_tl(s->tmp0, s->T1, 3 + ot); tcg_gen_shli_tl(s->tmp0, s->tmp0, ot); - tcg_gen_add_tl(s->A0, gen_lea_modrm_1(s, a), s->tmp0); + tcg_gen_add_tl(s->A0, gen_lea_modrm_1(s, a, false), s->tmp0); gen_lea_v_seg(s, s->aflag, s->A0, a.def_seg, s->override); if (!(s->prefix & PREFIX_LOCK)) { gen_op_ld_v(s, ot, s->T0, s->A0); @@ -7123,7 +5489,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; val = x86_ldub_code(env, s); if (val == 0) { - gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base); + gen_exception(s, EXCP00_DIVZ); } else { gen_helper_aam(cpu_env, tcg_const_i32(val)); set_cc_op(s, CC_OP_LOGICB); @@ -7149,34 +5515,34 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } if (prefixes & PREFIX_REPZ) { gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start)); + gen_update_eip_cur(s); + gen_helper_pause(cpu_env, cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; } break; case 0x9b: /* fwait */ if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == (HF_MP_MASK | HF_TS_MASK)) { - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + gen_exception(s, EXCP07_PREX); } else { gen_helper_fwait(cpu_env); } break; case 0xcc: /* int3 */ - gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); + gen_interrupt(s, EXCP03_INT3); break; case 0xcd: /* int N */ val = x86_ldub_code(env, s); if (check_vm86_iopl(s)) { - gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); + gen_interrupt(s, val); } break; case 0xce: /* into */ if (CODE64(s)) goto illegal_op; gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_into(cpu_env, tcg_const_i32(s->pc - pc_start)); + gen_update_eip_cur(s); + gen_helper_into(cpu_env, cur_insn_len_i32(s)); break; #ifdef WANT_ICEBP case 0xf1: /* icebp (undocumented, exits to external debugger) */ @@ -7186,14 +5552,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) #endif case 0xfa: /* cli */ if (check_iopl(s)) { - gen_helper_cli(cpu_env); + gen_reset_eflags(s, IF_MASK); } break; case 0xfb: /* sti */ if (check_iopl(s)) { - gen_helper_sti(cpu_env); + gen_set_eflags(s, IF_MASK); /* interruptions are enabled only the first insn after sti */ - gen_jmp_im(s, s->pc - s->cs_base); + gen_update_eip_next(s); gen_eob_inhibit_irq(s, true); } break; @@ -7237,75 +5603,62 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xe2: /* loop */ case 0xe3: /* jecxz */ { - TCGLabel *l1, *l2, *l3; - - tval = (int8_t)insn_get(env, s, MO_8); - next_eip = s->pc - s->cs_base; - tval += next_eip; - if (dflag == MO_16) { - tval &= 0xffff; - } + TCGLabel *l1, *l2; + int diff = (int8_t)insn_get(env, s, MO_8); l1 = gen_new_label(); l2 = gen_new_label(); - l3 = gen_new_label(); gen_update_cc_op(s); b &= 3; switch(b) { case 0: /* loopnz */ case 1: /* loopz */ gen_op_add_reg_im(s, s->aflag, R_ECX, -1); - gen_op_jz_ecx(s, s->aflag, l3); + gen_op_jz_ecx(s, l2); gen_jcc1(s, (JCC_Z << 1) | (b ^ 1), l1); break; case 2: /* loop */ gen_op_add_reg_im(s, s->aflag, R_ECX, -1); - gen_op_jnz_ecx(s, s->aflag, l1); + gen_op_jnz_ecx(s, l1); break; default: case 3: /* jcxz */ - gen_op_jz_ecx(s, s->aflag, l1); + gen_op_jz_ecx(s, l1); break; } - gen_set_label(l3); - gen_jmp_im(s, next_eip); - tcg_gen_br(l2); + gen_set_label(l2); + gen_jmp_rel_csize(s, 0, 1); gen_set_label(l1); - gen_jmp_im(s, tval); - gen_set_label(l2); - gen_eob(s); + gen_jmp_rel(s, dflag, diff, 0); } break; case 0x130: /* wrmsr */ case 0x132: /* rdmsr */ if (check_cpl0(s)) { gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); if (b & 2) { gen_helper_rdmsr(cpu_env); } else { gen_helper_wrmsr(cpu_env); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; } } break; case 0x131: /* rdtsc */ gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_helper_rdtsc(cpu_env); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; case 0x133: /* rdpmc */ gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_rdpmc(cpu_env); s->base.is_jmp = DISAS_NORETURN; break; @@ -7317,7 +5670,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_exception_gpf(s); } else { gen_helper_sysenter(cpu_env); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_ONLY; } break; case 0x135: /* sysexit */ @@ -7328,15 +5681,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_exception_gpf(s); } else { gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1)); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_ONLY; } break; #ifdef TARGET_X86_64 case 0x105: /* syscall */ /* XXX: is it usable in real mode ? */ gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_syscall(cpu_env, tcg_const_i32(s->pc - pc_start)); + gen_update_eip_cur(s); + gen_helper_syscall(cpu_env, cur_insn_len_i32(s)); /* TF handling for the syscall insn is different. The TF bit is checked after the syscall insn completes. This allows #DB to not be generated after one has entered CPL0 if TF is set in FMASK. */ @@ -7361,14 +5714,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) #endif case 0x1a2: /* cpuid */ gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_cpuid(cpu_env); break; case 0xf4: /* hlt */ if (check_cpl0(s)) { gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start)); + gen_update_eip_cur(s); + gen_helper_hlt(cpu_env, cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; } break; @@ -7464,7 +5817,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]); gen_extu(s->aflag, s->A0); gen_add_A0_ds_seg(s); @@ -7476,8 +5829,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start)); + gen_update_eip_cur(s); + gen_helper_mwait(cpu_env, cur_insn_len_i32(s)); s->base.is_jmp = DISAS_NORETURN; break; @@ -7486,9 +5839,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) || CPL(s) != 0) { goto illegal_op; } - gen_helper_clac(cpu_env); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + gen_reset_eflags(s, AC_MASK); + s->base.is_jmp = DISAS_EOB_NEXT; break; case 0xcb: /* stac */ @@ -7496,9 +5848,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) || CPL(s) != 0) { goto illegal_op; } - gen_helper_stac(cpu_env); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + gen_set_eflags(s, AC_MASK); + s->base.is_jmp = DISAS_EOB_NEXT; break; CASE_MODRM_MEM_OP(1): /* sidt */ @@ -7542,8 +5893,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]); gen_helper_xsetbv(cpu_env, s->tmp2_i32, s->tmp1_i64); /* End TB because translation flags may change. */ - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; break; case 0xd8: /* VMRUN */ @@ -7554,9 +5904,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1), - tcg_const_i32(s->pc - pc_start)); + cur_insn_len_i32(s)); tcg_gen_exit_tb(NULL, 0); s->base.is_jmp = DISAS_NORETURN; break; @@ -7566,7 +5916,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_vmmcall(cpu_env); break; @@ -7578,7 +5928,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag - 1)); break; @@ -7590,7 +5940,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag - 1)); break; @@ -7604,8 +5954,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } gen_update_cc_op(s); gen_helper_stgi(cpu_env); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; break; case 0xdd: /* CLGI */ @@ -7616,7 +5965,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); gen_helper_clgi(cpu_env); break; @@ -7643,8 +5992,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]); } gen_helper_flush_page(cpu_env, s->A0); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; break; CASE_MODRM_MEM_OP(2): /* lgdt */ @@ -7727,8 +6075,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_andi_tl(s->T1, s->T1, ~0xe); tcg_gen_or_tl(s->T0, s->T0, s->T1); gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; break; CASE_MODRM_MEM_OP(7): /* invlpg */ @@ -7738,8 +6085,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_INVLPG); gen_lea_modrm(env, s, modrm); gen_helper_flush_page(cpu_env, s->A0); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; break; case 0xf8: /* swapgs */ @@ -7762,14 +6108,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_update_eip_cur(s); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } gen_helper_rdtscp(cpu_env); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } break; default: @@ -8018,7 +6362,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* rip-relative generates #ud */ goto illegal_op; } - tcg_gen_not_tl(s->A0, gen_lea_modrm_1(s, a)); + tcg_gen_not_tl(s->A0, gen_lea_modrm_1(s, a, false)); if (!CODE64(s)) { tcg_gen_ext32u_tl(s->A0, s->A0); } @@ -8133,20 +6477,17 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); + s->base.is_jmp = DISAS_TOO_MANY; } if (b & 2) { gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg); gen_op_mov_v_reg(s, ot, s->T0, rm); gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; } else { gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg); gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg)); gen_op_mov_reg_v(s, ot, rm, s->T0); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } } break; @@ -8173,8 +6514,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_mov_v_reg(s, ot, s->T0, rm); tcg_gen_movi_i32(s->tmp2_i32, reg); gen_helper_set_dr(cpu_env, s->tmp2_i32, s->T0); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; } else { gen_svm_check_intercept(s, SVM_EXIT_READ_DR0 + reg); tcg_gen_movi_i32(s->tmp2_i32, reg); @@ -8188,8 +6528,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0); gen_helper_clts(cpu_env); /* abort block because static cpu state changed */ - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; } break; /* MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4 support */ @@ -8214,7 +6553,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) { - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + gen_exception(s, EXCP07_PREX); break; } gen_lea_modrm(env, s, modrm); @@ -8227,7 +6566,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) { - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + gen_exception(s, EXCP07_PREX); break; } gen_lea_modrm(env, s, modrm); @@ -8239,7 +6578,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } if (s->flags & HF_TS_MASK) { - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + gen_exception(s, EXCP07_PREX); break; } gen_lea_modrm(env, s, modrm); @@ -8252,7 +6591,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } if (s->flags & HF_TS_MASK) { - gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + gen_exception(s, EXCP07_PREX); break; } gen_helper_update_mxcsr(cpu_env); @@ -8285,9 +6624,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_xrstor(cpu_env, s->A0, s->tmp1_i64); /* XRSTOR is how MPX is enabled, which changes how we translate. Thus we need to end the TB. */ - gen_update_cc_op(s); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); + s->base.is_jmp = DISAS_EOB_NEXT; break; CASE_MODRM_MEM_OP(6): /* xsaveopt / clwb */ @@ -8420,10 +6757,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) g_assert_not_reached(); #else gen_update_cc_op(s); - gen_jmp_im(s, s->pc - s->cs_base); + gen_update_eip_next(s); gen_helper_rsm(cpu_env); #endif /* CONFIG_USER_ONLY */ - gen_eob(s); + s->base.is_jmp = DISAS_EOB_ONLY; break; case 0x1b8: /* SSE4.2 popcnt */ if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) != @@ -8449,11 +6786,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) set_cc_op(s, CC_OP_POPCNT); break; - case 0x10e ... 0x10f: - /* 3DNow! instructions, ignore prefixes */ - s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA); - /* fall through */ - case 0x110 ... 0x117: + case 0x10e ... 0x117: case 0x128 ... 0x12f: case 0x138 ... 0x13a: case 0x150 ... 0x179: @@ -8461,18 +6794,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x1c2: case 0x1c4 ... 0x1c6: case 0x1d0 ... 0x1fe: - gen_sse(env, s, b, pc_start); + disas_insn_new(s, cpu, b); break; default: goto unknown_op; } - return s->pc; + return true; illegal_op: gen_illegal_opcode(s); - return s->pc; + return true; unknown_op: gen_unknown_opcode(env, s); - return s->pc; + return true; } void tcg_x86_init(void) @@ -8504,6 +6837,13 @@ void tcg_x86_init(void) [R_EDI] = "edi", [R_EBP] = "ebp", [R_ESP] = "esp", +#endif + }; + static const char eip_name[] = { +#ifdef TARGET_X86_64 + "rip" +#else + "eip" #endif }; static const char seg_base_names[6][8] = { @@ -8530,6 +6870,7 @@ void tcg_x86_init(void) "cc_src"); cpu_cc_src2 = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_src2), "cc_src2"); + cpu_eip = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, eip), eip_name); for (i = 0; i < CPU_NB_REGS; ++i) { cpu_regs[i] = tcg_global_mem_new(cpu_env, @@ -8566,6 +6907,7 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) int iopl = (flags >> IOPL_SHIFT) & 3; dc->cs_base = dc->base.tb->cs_base; + dc->pc_save = dc->base.pc_next; dc->flags = flags; #ifndef CONFIG_USER_ONLY dc->cpl = cpl; @@ -8598,6 +6940,7 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->cpuid_ext2_features = env->features[FEAT_8000_0001_EDX]; dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX]; dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX]; + dc->cpuid_7_0_ecx_features = env->features[FEAT_7_0_ECX]; dc->cpuid_xsave_features = env->features[FEAT_XSAVE]; dc->jmp_opt = !((cflags & CF_NO_GOTO_TB) || (flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK))); @@ -8617,8 +6960,6 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->tmp2_i32 = tcg_temp_new_i32(); dc->tmp3_i32 = tcg_temp_new_i32(); dc->tmp4 = tcg_temp_new(); - dc->ptr0 = tcg_temp_new_ptr(); - dc->ptr1 = tcg_temp_new_ptr(); dc->cc_srcT = tcg_temp_local_new(); } @@ -8629,71 +6970,90 @@ static void i386_tr_tb_start(DisasContextBase *db, CPUState *cpu) static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); + target_ulong pc_arg = dc->base.pc_next; - tcg_gen_insn_start(dc->base.pc_next, dc->cc_op); + dc->prev_insn_end = tcg_last_op(); + if (TARGET_TB_PCREL) { + pc_arg -= dc->cs_base; + pc_arg &= ~TARGET_PAGE_MASK; + } + tcg_gen_insn_start(pc_arg, dc->cc_op); } static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - target_ulong pc_next; #ifdef TARGET_VSYSCALL_PAGE /* * Detect entry into the vsyscall page and invoke the syscall. */ if ((dc->base.pc_next & TARGET_PAGE_MASK) == TARGET_VSYSCALL_PAGE) { - gen_exception(dc, EXCP_VSYSCALL, dc->base.pc_next); + gen_exception(dc, EXCP_VSYSCALL); dc->base.pc_next = dc->pc + 1; return; } #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; - } + if (disas_insn(dc, cpu)) { + target_ulong pc_next = dc->pc; + dc->base.pc_next = pc_next; - 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_EOB_NEXT; + } 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) { DisasContext *dc = container_of(dcbase, DisasContext, base); - if (dc->base.is_jmp == DISAS_TOO_MANY) { - gen_jmp_im(dc, dc->base.pc_next - dc->cs_base); + switch (dc->base.is_jmp) { + case DISAS_NORETURN: + break; + case DISAS_TOO_MANY: + gen_update_cc_op(dc); + gen_jmp_rel_csize(dc, 0, 0); + break; + case DISAS_EOB_NEXT: + gen_update_cc_op(dc); + gen_update_eip_cur(dc); + /* fall through */ + case DISAS_EOB_ONLY: gen_eob(dc); + break; + case DISAS_EOB_INHIBIT_IRQ: + gen_update_cc_op(dc); + gen_update_eip_cur(dc); + gen_eob_inhibit_irq(dc, true); + break; + case DISAS_JUMP: + gen_jr(dc); + break; + default: + g_assert_not_reached(); } } static void i386_tr_disas_log(const DisasContextBase *dcbase, - CPUState *cpu) + CPUState *cpu, FILE *logfile) { DisasContext *dc = container_of(dcbase, DisasContext, base); - qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first)); - log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first)); + target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size); } static const TranslatorOps i386_tr_ops = { @@ -8706,19 +7066,10 @@ 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); -} - -void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb, - target_ulong *data) -{ - int cc_op = data[1]; - env->eip = data[0] - tb->cs_base; - if (cc_op != CC_OP_DYNAMIC) { - env->cc_op = cc_op; - } + translator_loop(cpu, tb, max_insns, pc, host_pc, &i386_tr_ops, &dc.base); } diff --git a/target/i386/tcg/user/excp_helper.c b/target/i386/tcg/user/excp_helper.c index cd507e2a1b53..b3bdb7831a7a 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-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c index dd2a9f7657c2..e8dc4b3a4777 100644 --- a/target/i386/whpx/whpx-accel-ops.c +++ b/target/i386/whpx/whpx-accel-ops.c @@ -100,6 +100,7 @@ static void whpx_accel_ops_class_init(ObjectClass *oc, void *data) ops->synchronize_post_init = whpx_cpu_synchronize_post_init; ops->synchronize_state = whpx_cpu_synchronize_state; ops->synchronize_pre_loadvm = whpx_cpu_synchronize_pre_loadvm; + ops->synchronize_pre_resume = whpx_cpu_synchronize_pre_resume; } static const TypeInfo whpx_accel_ops_type = { diff --git a/target/i386/whpx/whpx-accel-ops.h b/target/i386/whpx/whpx-accel-ops.h index 2dee6d61eaf7..7a1bb1ab5753 100644 --- a/target/i386/whpx/whpx-accel-ops.h +++ b/target/i386/whpx/whpx-accel-ops.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef WHPX_CPUS_H -#define WHPX_CPUS_H +#ifndef TARGET_I386_WHPX_ACCEL_OPS_H +#define TARGET_I386_WHPX_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -21,6 +21,7 @@ void whpx_cpu_synchronize_state(CPUState *cpu); void whpx_cpu_synchronize_post_reset(CPUState *cpu); void whpx_cpu_synchronize_post_init(CPUState *cpu); void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu); +void whpx_cpu_synchronize_pre_resume(bool step_pending); /* state subset only touched by the VCPU itself during runtime */ #define WHPX_SET_RUNTIME_STATE 1 @@ -29,4 +30,4 @@ void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu); /* full state set, modified during initialization or on vmload */ #define WHPX_SET_FULL_STATE 3 -#endif /* WHPX_CPUS_H */ +#endif /* TARGET_I386_WHPX_ACCEL_OPS_H */ diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 03ba52da89fb..e738d83e8191 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -12,7 +12,7 @@ #include "cpu.h" #include "exec/address-spaces.h" #include "exec/ioport.h" -#include "qemu-common.h" +#include "exec/gdbstub.h" #include "qemu/accel.h" #include "sysemu/whpx.h" #include "sysemu/cpus.h" @@ -148,6 +148,87 @@ struct whpx_register_set { WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)]; }; +/* + * The current implementation of instruction stepping sets the TF flag + * in RFLAGS, causing the CPU to raise an INT1 after each instruction. + * This corresponds to the WHvX64ExceptionTypeDebugTrapOrFault exception. + * + * This approach has a few limitations: + * 1. Stepping over a PUSHF/SAHF instruction will save the TF flag + * along with the other flags, possibly restoring it later. It would + * result in another INT1 when the flags are restored, triggering + * a stop in gdb that could be cleared by doing another step. + * + * Stepping over a POPF/LAHF instruction will let it overwrite the + * TF flags, ending the stepping mode. + * + * 2. Stepping over an instruction raising an exception (e.g. INT, DIV, + * or anything that could result in a page fault) will save the flags + * to the stack, clear the TF flag, and let the guest execute the + * handler. Normally, the guest will restore the original flags, + * that will continue single-stepping. + * + * 3. Debuggers running on the guest may wish to set TF to do instruction + * stepping. INT1 events generated by it would be intercepted by us, + * as long as the gdb is connected to QEMU. + * + * In practice this means that: + * 1. Stepping through flags-modifying instructions may cause gdb to + * continue or stop in unexpected places. This will be fully recoverable + * and will not crash the target. + * + * 2. Stepping over an instruction that triggers an exception will step + * over the exception handler, not into it. + * + * 3. Debugging the guest via gdb, while running debugger on the guest + * at the same time may lead to unexpected effects. Removing all + * breakpoints set via QEMU will prevent any further interference + * with the guest-level debuggers. + * + * The limitations can be addressed as shown below: + * 1. PUSHF/SAHF/POPF/LAHF/IRET instructions can be emulated instead of + * stepping through them. The exact semantics of the instructions is + * defined in the "Combined Volume Set of Intel 64 and IA-32 + * Architectures Software Developer's Manuals", however it involves a + * fair amount of corner cases due to compatibility with real mode, + * virtual 8086 mode, and differences between 64-bit and 32-bit modes. + * + * 2. We could step into the guest's exception handlers using the following + * sequence: + * a. Temporarily enable catching of all exception types via + * whpx_set_exception_exit_bitmap(). + * b. Once an exception is intercepted, read the IDT/GDT and locate + * the original handler. + * c. Patch the original handler, injecting an INT3 at the beginning. + * d. Update the exception exit bitmap to only catch the + * WHvX64ExceptionTypeBreakpointTrap exception. + * e. Let the affected CPU run in the exclusive mode. + * f. Restore the original handler and the exception exit bitmap. + * Note that handling all corner cases related to IDT/GDT is harder + * than it may seem. See x86_cpu_get_phys_page_attrs_debug() for a + * rough idea. + * + * 3. In order to properly support guest-level debugging in parallel with + * the QEMU-level debugging, we would need to be able to pass some INT1 + * events to the guest. This could be done via the following methods: + * a. Using the WHvRegisterPendingEvent register. As of Windows 21H1, + * it seems to only work for interrupts and not software + * exceptions. + * b. Locating and patching the original handler by parsing IDT/GDT. + * This involves relatively complex logic outlined in the previous + * paragraph. + * c. Emulating the exception invocation (i.e. manually updating RIP, + * RFLAGS, and pushing the old values to stack). This is even more + * complicated than the previous option, since it involves checking + * CPL, gate attributes, and doing various adjustments depending + * on the current CPU mode, whether the CPL is changing, etc. + */ +typedef enum WhpxStepMode { + WHPX_STEP_NONE = 0, + /* Halt other VCPUs */ + WHPX_STEP_EXCLUSIVE, +} WhpxStepMode; + struct whpx_vcpu { WHV_EMULATOR_HANDLE emulator; bool window_registered; @@ -165,9 +246,15 @@ static bool whpx_allowed; static bool whp_dispatch_initialized; static HMODULE hWinHvPlatform, hWinHvEmulation; static uint32_t max_vcpu_index; +static WHV_PROCESSOR_XSAVE_FEATURES whpx_xsave_cap; + struct whpx_state whpx_global; struct WHPDispatch whp_dispatch; +static bool whpx_has_xsave(void) +{ + return whpx_xsave_cap.XsaveSupport; +} /* * VP support @@ -219,6 +306,28 @@ static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs) return qs; } +/* X64 Extended Control Registers */ +static void whpx_set_xcrs(CPUState *cpu) +{ + CPUX86State *env = cpu->env_ptr; + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + WHV_REGISTER_VALUE xcr0; + WHV_REGISTER_NAME xcr0_name = WHvX64RegisterXCr0; + + if (!whpx_has_xsave()) { + return; + } + + /* Only xcr0 is supported by the hypervisor currently */ + xcr0.Reg64 = env->xcr0; + hr = whp_dispatch.WHvSetVirtualProcessorRegisters( + whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0); + if (FAILED(hr)) { + error_report("WHPX: Failed to set register xcr0, hr=%08lx", hr); + } +} + static int whpx_set_tsc(CPUState *cpu) { CPUX86State *env = cpu->env_ptr; @@ -264,6 +373,8 @@ static int whpx_set_tsc(CPUState *cpu) * * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64 * and IA-32 Architectures Software Developer's Manual. + * + * The functions below translate the value of CR8 to TPR and vice versa. */ static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) @@ -271,6 +382,11 @@ static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) return tpr >> 4; } +static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8) +{ + return cr8 << 4; +} + static void whpx_set_registers(CPUState *cpu, int level) { struct whpx_state *whpx = &whpx_global; @@ -354,6 +470,12 @@ static void whpx_set_registers(CPUState *cpu, int level) /* 8 Debug Registers - Skipped */ + /* + * Extended control registers needs to be handled separately depending + * on whether xsave is supported/enabled or not. + */ + whpx_set_xcrs(cpu); + /* 16 XMM registers */ assert(whpx_register_names[idx] == WHvX64RegisterXmm0); idx_next = idx + 16; @@ -460,6 +582,30 @@ static int whpx_get_tsc(CPUState *cpu) return 0; } +/* X64 Extended Control Registers */ +static void whpx_get_xcrs(CPUState *cpu) +{ + CPUX86State *env = cpu->env_ptr; + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + WHV_REGISTER_VALUE xcr0; + WHV_REGISTER_NAME xcr0_name = WHvX64RegisterXCr0; + + if (!whpx_has_xsave()) { + return; + } + + /* Only xcr0 is supported by the hypervisor currently */ + hr = whp_dispatch.WHvGetVirtualProcessorRegisters( + whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0); + if (FAILED(hr)) { + error_report("WHPX: Failed to get register xcr0, hr=%08lx", hr); + return; + } + + env->xcr0 = xcr0.Reg64; +} + static void whpx_get_registers(CPUState *cpu) { struct whpx_state *whpx = &whpx_global; @@ -548,11 +694,17 @@ static void whpx_get_registers(CPUState *cpu) tpr = vcxt.values[idx++].Reg64; if (tpr != vcpu->tpr) { vcpu->tpr = tpr; - cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr)); } /* 8 Debug Registers - Skipped */ + /* + * Extended control registers needs to be handled separately depending + * on whether xsave is supported/enabled or not. + */ + whpx_get_xcrs(cpu); + /* 16 XMM registers */ assert(whpx_register_names[idx] == WHvX64RegisterXmm0); idx_next = idx + 16; @@ -786,6 +938,514 @@ static int whpx_handle_portio(CPUState *cpu, return 0; } +/* + * Controls whether we should intercept various exceptions on the guest, + * namely breakpoint/single-step events. + * + * The 'exceptions' argument accepts a bitmask, e.g: + * (1 << WHvX64ExceptionTypeDebugTrapOrFault) | (...) + */ +static HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions) +{ + struct whpx_state *whpx = &whpx_global; + WHV_PARTITION_PROPERTY prop = { 0, }; + HRESULT hr; + + if (exceptions == whpx->exception_exit_bitmap) { + return S_OK; + } + + prop.ExceptionExitBitmap = exceptions; + + hr = whp_dispatch.WHvSetPartitionProperty( + whpx->partition, + WHvPartitionPropertyCodeExceptionExitBitmap, + &prop, + sizeof(WHV_PARTITION_PROPERTY)); + + if (SUCCEEDED(hr)) { + whpx->exception_exit_bitmap = exceptions; + } + + return hr; +} + + +/* + * This function is called before/after stepping over a single instruction. + * It will update the CPU registers to arm/disarm the instruction stepping + * accordingly. + */ +static HRESULT whpx_vcpu_configure_single_stepping(CPUState *cpu, + bool set, + uint64_t *exit_context_rflags) +{ + WHV_REGISTER_NAME reg_name; + WHV_REGISTER_VALUE reg_value; + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + + /* + * If we are trying to step over a single instruction, we need to set the + * TF bit in rflags. Otherwise, clear it. + */ + reg_name = WHvX64RegisterRflags; + hr = whp_dispatch.WHvGetVirtualProcessorRegisters( + whpx->partition, + cpu->cpu_index, + ®_name, + 1, + ®_value); + + if (FAILED(hr)) { + error_report("WHPX: Failed to get rflags, hr=%08lx", hr); + return hr; + } + + if (exit_context_rflags) { + assert(*exit_context_rflags == reg_value.Reg64); + } + + if (set) { + /* Raise WHvX64ExceptionTypeDebugTrapOrFault after each instruction */ + reg_value.Reg64 |= TF_MASK; + } else { + reg_value.Reg64 &= ~TF_MASK; + } + + if (exit_context_rflags) { + *exit_context_rflags = reg_value.Reg64; + } + + hr = whp_dispatch.WHvSetVirtualProcessorRegisters( + whpx->partition, + cpu->cpu_index, + ®_name, + 1, + ®_value); + + if (FAILED(hr)) { + error_report("WHPX: Failed to set rflags," + " hr=%08lx", + hr); + return hr; + } + + reg_name = WHvRegisterInterruptState; + reg_value.Reg64 = 0; + + /* Suspend delivery of hardware interrupts during single-stepping. */ + reg_value.InterruptState.InterruptShadow = set != 0; + + hr = whp_dispatch.WHvSetVirtualProcessorRegisters( + whpx->partition, + cpu->cpu_index, + ®_name, + 1, + ®_value); + + if (FAILED(hr)) { + error_report("WHPX: Failed to set InterruptState," + " hr=%08lx", + hr); + return hr; + } + + if (!set) { + /* + * We have just finished stepping over a single instruction, + * and intercepted the INT1 generated by it. + * We need to now hide the INT1 from the guest, + * as it would not be expecting it. + */ + + reg_name = WHvX64RegisterPendingDebugException; + hr = whp_dispatch.WHvGetVirtualProcessorRegisters( + whpx->partition, + cpu->cpu_index, + ®_name, + 1, + ®_value); + + if (FAILED(hr)) { + error_report("WHPX: Failed to get pending debug exceptions," + "hr=%08lx", hr); + return hr; + } + + if (reg_value.PendingDebugException.SingleStep) { + reg_value.PendingDebugException.SingleStep = 0; + + hr = whp_dispatch.WHvSetVirtualProcessorRegisters( + whpx->partition, + cpu->cpu_index, + ®_name, + 1, + ®_value); + + if (FAILED(hr)) { + error_report("WHPX: Failed to clear pending debug exceptions," + "hr=%08lx", hr); + return hr; + } + } + + } + + return S_OK; +} + +/* Tries to find a breakpoint at the specified address. */ +static struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address) +{ + struct whpx_state *whpx = &whpx_global; + int i; + + if (whpx->breakpoints.breakpoints) { + for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) { + if (address == whpx->breakpoints.breakpoints->data[i].address) { + return &whpx->breakpoints.breakpoints->data[i]; + } + } + } + + return NULL; +} + +/* + * Linux uses int3 (0xCC) during startup (see int3_selftest()) and for + * debugging user-mode applications. Since the WHPX API does not offer + * an easy way to pass the intercepted exception back to the guest, we + * resort to using INT1 instead, and let the guest always handle INT3. + */ +static const uint8_t whpx_breakpoint_instruction = 0xF1; + +/* + * The WHPX QEMU backend implements breakpoints by writing the INT1 + * instruction into memory (ignoring the DRx registers). This raises a few + * issues that need to be carefully handled: + * + * 1. Although unlikely, other parts of QEMU may set multiple breakpoints + * at the same location, and later remove them in arbitrary order. + * This should not cause memory corruption, and should only remove the + * physical breakpoint instruction when the last QEMU breakpoint is gone. + * + * 2. Writing arbitrary virtual memory may fail if it's not mapped to a valid + * physical location. Hence, physically adding/removing a breakpoint can + * theoretically fail at any time. We need to keep track of it. + * + * The function below rebuilds a list of low-level breakpoints (one per + * address, tracking the original instruction and any errors) from the list of + * high-level breakpoints (set via cpu_breakpoint_insert()). + * + * In order to optimize performance, this function stores the list of + * high-level breakpoints (a.k.a. CPU breakpoints) used to compute the + * low-level ones, so that it won't be re-invoked until these breakpoints + * change. + * + * Note that this function decides which breakpoints should be inserted into, + * memory, but doesn't actually do it. The memory accessing is done in + * whpx_apply_breakpoints(). + */ +static void whpx_translate_cpu_breakpoints( + struct whpx_breakpoints *breakpoints, + CPUState *cpu, + int cpu_breakpoint_count) +{ + CPUBreakpoint *bp; + int cpu_bp_index = 0; + + breakpoints->original_addresses = + g_renew(vaddr, breakpoints->original_addresses, cpu_breakpoint_count); + + breakpoints->original_address_count = cpu_breakpoint_count; + + int max_breakpoints = cpu_breakpoint_count + + (breakpoints->breakpoints ? breakpoints->breakpoints->used : 0); + + struct whpx_breakpoint_collection *new_breakpoints = + g_malloc0(sizeof(struct whpx_breakpoint_collection) + + max_breakpoints * sizeof(struct whpx_breakpoint)); + + new_breakpoints->allocated = max_breakpoints; + new_breakpoints->used = 0; + + /* + * 1. Preserve all old breakpoints that could not be automatically + * cleared when the CPU got stopped. + */ + if (breakpoints->breakpoints) { + int i; + for (i = 0; i < breakpoints->breakpoints->used; i++) { + if (breakpoints->breakpoints->data[i].state != WHPX_BP_CLEARED) { + new_breakpoints->data[new_breakpoints->used++] = + breakpoints->breakpoints->data[i]; + } + } + } + + /* 2. Map all CPU breakpoints to WHPX breakpoints */ + QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { + int i; + bool found = false; + + /* This will be used to detect changed CPU breakpoints later. */ + breakpoints->original_addresses[cpu_bp_index++] = bp->pc; + + for (i = 0; i < new_breakpoints->used; i++) { + /* + * WARNING: This loop has O(N^2) complexity, where N is the + * number of breakpoints. It should not be a bottleneck in + * real-world scenarios, since it only needs to run once after + * the breakpoints have been modified. + * If this ever becomes a concern, it can be optimized by storing + * high-level breakpoint objects in a tree or hash map. + */ + + if (new_breakpoints->data[i].address == bp->pc) { + /* There was already a breakpoint at this address. */ + if (new_breakpoints->data[i].state == WHPX_BP_CLEAR_PENDING) { + new_breakpoints->data[i].state = WHPX_BP_SET; + } else if (new_breakpoints->data[i].state == WHPX_BP_SET) { + new_breakpoints->data[i].state = WHPX_BP_SET_PENDING; + } + + found = true; + break; + } + } + + if (!found && new_breakpoints->used < new_breakpoints->allocated) { + /* No WHPX breakpoint at this address. Create one. */ + new_breakpoints->data[new_breakpoints->used].address = bp->pc; + new_breakpoints->data[new_breakpoints->used].state = + WHPX_BP_SET_PENDING; + new_breakpoints->used++; + } + } + + /* + * 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; +} + +/* + * Physically inserts/removes the breakpoints by reading and writing the + * physical memory, keeping a track of the failed attempts. + * + * Passing resuming=true will try to set all previously unset breakpoints. + * Passing resuming=false will remove all inserted ones. + */ +static void whpx_apply_breakpoints( + struct whpx_breakpoint_collection *breakpoints, + CPUState *cpu, + bool resuming) +{ + int i, rc; + if (!breakpoints) { + return; + } + + for (i = 0; i < breakpoints->used; i++) { + /* Decide what to do right now based on the last known state. */ + WhpxBreakpointState state = breakpoints->data[i].state; + switch (state) { + case WHPX_BP_CLEARED: + if (resuming) { + state = WHPX_BP_SET_PENDING; + } + break; + case WHPX_BP_SET_PENDING: + if (!resuming) { + state = WHPX_BP_CLEARED; + } + break; + case WHPX_BP_SET: + if (!resuming) { + state = WHPX_BP_CLEAR_PENDING; + } + break; + case WHPX_BP_CLEAR_PENDING: + if (resuming) { + state = WHPX_BP_SET; + } + break; + } + + if (state == WHPX_BP_SET_PENDING) { + /* Remember the original instruction. */ + rc = cpu_memory_rw_debug(cpu, + breakpoints->data[i].address, + &breakpoints->data[i].original_instruction, + 1, + false); + + if (!rc) { + /* Write the breakpoint instruction. */ + rc = cpu_memory_rw_debug(cpu, + breakpoints->data[i].address, + (void *)&whpx_breakpoint_instruction, + 1, + true); + } + + if (!rc) { + state = WHPX_BP_SET; + } + + } + + if (state == WHPX_BP_CLEAR_PENDING) { + /* Restore the original instruction. */ + rc = cpu_memory_rw_debug(cpu, + breakpoints->data[i].address, + &breakpoints->data[i].original_instruction, + 1, + true); + + if (!rc) { + state = WHPX_BP_CLEARED; + } + } + + breakpoints->data[i].state = state; + } +} + +/* + * This function is called when the a VCPU is about to start and no other + * VCPUs have been started so far. Since the VCPU start order could be + * arbitrary, it doesn't have to be VCPU#0. + * + * It is used to commit the breakpoints into memory, and configure WHPX + * to intercept debug exceptions. + * + * Note that whpx_set_exception_exit_bitmap() cannot be called if one or + * more VCPUs are already running, so this is the best place to do it. + */ +static int whpx_first_vcpu_starting(CPUState *cpu) +{ + struct whpx_state *whpx = &whpx_global; + HRESULT hr; + + g_assert(qemu_mutex_iothread_locked()); + + if (!QTAILQ_EMPTY(&cpu->breakpoints) || + (whpx->breakpoints.breakpoints && + whpx->breakpoints.breakpoints->used)) { + CPUBreakpoint *bp; + int i = 0; + bool update_pending = false; + + QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { + if (i >= whpx->breakpoints.original_address_count || + bp->pc != whpx->breakpoints.original_addresses[i]) { + update_pending = true; + } + + i++; + } + + if (i != whpx->breakpoints.original_address_count) { + update_pending = true; + } + + if (update_pending) { + /* + * The CPU breakpoints have changed since the last call to + * whpx_translate_cpu_breakpoints(). WHPX breakpoints must + * now be recomputed. + */ + whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i); + } + + /* Actually insert the breakpoints into the memory. */ + whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true); + } + + uint64_t exception_mask; + if (whpx->step_pending || + (whpx->breakpoints.breakpoints && + whpx->breakpoints.breakpoints->used)) { + /* + * We are either attempting to single-step one or more CPUs, or + * have one or more breakpoints enabled. Both require intercepting + * the WHvX64ExceptionTypeBreakpointTrap exception. + */ + + exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault; + } else { + /* Let the guest handle all exceptions. */ + exception_mask = 0; + } + + hr = whpx_set_exception_exit_bitmap(exception_mask); + if (!SUCCEEDED(hr)) { + error_report("WHPX: Failed to update exception exit mask," + "hr=%08lx.", hr); + return 1; + } + + return 0; +} + +/* + * This function is called when the last VCPU has finished running. + * It is used to remove any previously set breakpoints from memory. + */ +static int whpx_last_vcpu_stopping(CPUState *cpu) +{ + whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false); + return 0; +} + +/* Returns the address of the next instruction that is about to be executed. */ +static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid) +{ + if (cpu->vcpu_dirty) { + /* The CPU registers have been modified by other parts of QEMU. */ + CPUArchState *env = (CPUArchState *)(cpu->env_ptr); + return env->eip; + } else if (exit_context_valid) { + /* + * The CPU registers have not been modified by neither other parts + * of QEMU, nor this port by calling WHvSetVirtualProcessorRegisters(). + * This is the most common case. + */ + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + return vcpu->exit_ctx.VpContext.Rip; + } else { + /* + * The CPU registers have been modified by a call to + * WHvSetVirtualProcessorRegisters() and must be re-queried from + * the target. + */ + WHV_REGISTER_VALUE reg_value; + WHV_REGISTER_NAME reg_name = WHvX64RegisterRip; + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + + hr = whp_dispatch.WHvGetVirtualProcessorRegisters( + whpx->partition, + cpu->cpu_index, + ®_name, + 1, + ®_value); + + if (FAILED(hr)) { + error_report("WHPX: Failed to get PC, hr=%08lx", hr); + return 0; + } + + return reg_value.Reg64; + } +} + static int whpx_handle_halt(CPUState *cpu) { CPUX86State *env = cpu->env_ptr; @@ -891,7 +1551,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) } /* Sync the TPR to the CR8 if was modified during the intercept */ - tpr = cpu_get_apic_tpr(x86_cpu->apic_state); + tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state)); if (tpr != vcpu->tpr) { vcpu->tpr = tpr; reg_values[reg_count].Reg64 = tpr; @@ -940,7 +1600,7 @@ static void whpx_vcpu_post_run(CPUState *cpu) if (vcpu->tpr != tpr) { vcpu->tpr = tpr; qemu_mutex_lock_iothread(); - cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr); + cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(vcpu->tpr)); qemu_mutex_unlock_iothread(); } @@ -997,17 +1657,75 @@ static int whpx_vcpu_run(CPUState *cpu) HRESULT hr; struct whpx_state *whpx = &whpx_global; struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + struct whpx_breakpoint *stepped_over_bp = NULL; + WhpxStepMode exclusive_step_mode = WHPX_STEP_NONE; int ret; - whpx_vcpu_process_async_events(cpu); - if (cpu->halted && !whpx_apic_in_platform()) { - cpu->exception_index = EXCP_HLT; - qatomic_set(&cpu->exit_request, false); - return 0; + g_assert(qemu_mutex_iothread_locked()); + + if (whpx->running_cpus++ == 0) { + /* Insert breakpoints into memory, update exception exit bitmap. */ + ret = whpx_first_vcpu_starting(cpu); + if (ret != 0) { + return ret; + } + } + + if (whpx->breakpoints.breakpoints && + whpx->breakpoints.breakpoints->used > 0) + { + uint64_t pc = whpx_vcpu_get_pc(cpu, true); + stepped_over_bp = whpx_lookup_breakpoint_by_addr(pc); + if (stepped_over_bp && stepped_over_bp->state != WHPX_BP_SET) { + stepped_over_bp = NULL; + } + + if (stepped_over_bp) { + /* + * We are trying to run the instruction overwritten by an active + * breakpoint. We will temporarily disable the breakpoint, suspend + * other CPUs, and step over the instruction. + */ + exclusive_step_mode = WHPX_STEP_EXCLUSIVE; + } + } + + if (exclusive_step_mode == WHPX_STEP_NONE) { + whpx_vcpu_process_async_events(cpu); + if (cpu->halted && !whpx_apic_in_platform()) { + cpu->exception_index = EXCP_HLT; + qatomic_set(&cpu->exit_request, false); + return 0; + } } qemu_mutex_unlock_iothread(); - cpu_exec_start(cpu); + + if (exclusive_step_mode != WHPX_STEP_NONE) { + start_exclusive(); + g_assert(cpu == current_cpu); + g_assert(!cpu->running); + cpu->running = true; + + hr = whpx_set_exception_exit_bitmap( + 1UL << WHvX64ExceptionTypeDebugTrapOrFault); + if (!SUCCEEDED(hr)) { + error_report("WHPX: Failed to update exception exit mask, " + "hr=%08lx.", hr); + return 1; + } + + if (stepped_over_bp) { + /* Temporarily disable the triggered breakpoint. */ + cpu_memory_rw_debug(cpu, + stepped_over_bp->address, + &stepped_over_bp->original_instruction, + 1, + true); + } + } else { + cpu_exec_start(cpu); + } do { if (cpu->vcpu_dirty) { @@ -1015,10 +1733,16 @@ static int whpx_vcpu_run(CPUState *cpu) cpu->vcpu_dirty = false; } - whpx_vcpu_pre_run(cpu); + if (exclusive_step_mode == WHPX_STEP_NONE) { + whpx_vcpu_pre_run(cpu); - if (qatomic_read(&cpu->exit_request)) { - whpx_vcpu_kick(cpu); + if (qatomic_read(&cpu->exit_request)) { + whpx_vcpu_kick(cpu); + } + } + + if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) { + whpx_vcpu_configure_single_stepping(cpu, true, NULL); } hr = whp_dispatch.WHvRunVirtualProcessor( @@ -1032,6 +1756,12 @@ static int whpx_vcpu_run(CPUState *cpu) break; } + if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) { + whpx_vcpu_configure_single_stepping(cpu, + false, + &vcpu->exit_ctx.VpContext.Rflags); + } + whpx_vcpu_post_run(cpu); switch (vcpu->exit_ctx.ExitReason) { @@ -1055,6 +1785,10 @@ static int whpx_vcpu_run(CPUState *cpu) break; case WHvRunVpExitReasonX64Halt: + /* + * WARNING: as of build 19043.1526 (21H1), this exit reason is no + * longer used. + */ ret = whpx_handle_halt(cpu); break; @@ -1153,10 +1887,19 @@ static int whpx_vcpu_run(CPUState *cpu) } case WHvRunVpExitReasonCanceled: - cpu->exception_index = EXCP_INTERRUPT; - ret = 1; + if (exclusive_step_mode != WHPX_STEP_NONE) { + /* + * We are trying to step over a single instruction, and + * likely got a request to stop from another thread. + * Delay it until we are done stepping + * over. + */ + ret = 0; + } else { + cpu->exception_index = EXCP_INTERRUPT; + ret = 1; + } break; - case WHvRunVpExitReasonX64MsrAccess: { WHV_REGISTER_VALUE reg_values[3] = {0}; WHV_REGISTER_NAME reg_names[3]; @@ -1260,11 +2003,36 @@ static int whpx_vcpu_run(CPUState *cpu) ret = 0; break; } + case WHvRunVpExitReasonException: + whpx_get_registers(cpu); + + if ((vcpu->exit_ctx.VpException.ExceptionType == + WHvX64ExceptionTypeDebugTrapOrFault) && + (vcpu->exit_ctx.VpException.InstructionByteCount >= 1) && + (vcpu->exit_ctx.VpException.InstructionBytes[0] == + whpx_breakpoint_instruction)) { + /* Stopped at a software breakpoint. */ + cpu->exception_index = EXCP_DEBUG; + } else if ((vcpu->exit_ctx.VpException.ExceptionType == + WHvX64ExceptionTypeDebugTrapOrFault) && + !cpu->singlestep_enabled) { + /* + * Just finished stepping over a breakpoint, but the + * gdb does not expect us to do single-stepping. + * Don't do anything special. + */ + cpu->exception_index = EXCP_INTERRUPT; + } else { + /* Another exception or debug event. Report it to GDB. */ + cpu->exception_index = EXCP_DEBUG; + } + + ret = 1; + break; case WHvRunVpExitReasonNone: case WHvRunVpExitReasonUnrecoverableException: case WHvRunVpExitReasonInvalidVpRegisterValue: case WHvRunVpExitReasonUnsupportedFeature: - case WHvRunVpExitReasonException: default: error_report("WHPX: Unexpected VP exit code %d", vcpu->exit_ctx.ExitReason); @@ -1277,10 +2045,32 @@ static int whpx_vcpu_run(CPUState *cpu) } while (!ret); - cpu_exec_end(cpu); + if (stepped_over_bp) { + /* Restore the breakpoint we stepped over */ + cpu_memory_rw_debug(cpu, + stepped_over_bp->address, + (void *)&whpx_breakpoint_instruction, + 1, + true); + } + + if (exclusive_step_mode != WHPX_STEP_NONE) { + g_assert(cpu_in_exclusive_context(cpu)); + cpu->running = false; + end_exclusive(); + + exclusive_step_mode = WHPX_STEP_NONE; + } else { + cpu_exec_end(cpu); + } + qemu_mutex_lock_iothread(); current_cpu = cpu; + if (--whpx->running_cpus == 0) { + whpx_last_vcpu_stopping(cpu); + } + qatomic_set(&cpu->exit_request, false); return ret < 0; @@ -1340,6 +2130,11 @@ void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu) run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); } +void whpx_cpu_synchronize_pre_resume(bool step_pending) +{ + whpx_global.step_pending = step_pending; +} + /* * Vcpu support. */ @@ -1572,15 +2367,15 @@ static void whpx_process_section(MemoryRegionSection *section, int add) return; } - delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask); - delta &= ~qemu_real_host_page_mask; + delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask()); + delta &= ~qemu_real_host_page_mask(); if (delta > size) { return; } start_pa += delta; size -= delta; - size &= qemu_real_host_page_mask; - if (!size || (start_pa & ~qemu_real_host_page_mask)) { + size &= qemu_real_host_page_mask(); + if (!size || (start_pa & ~qemu_real_host_page_mask())) { return; } @@ -1786,6 +2581,29 @@ static int whpx_accel_init(MachineState *ms) goto error; } + /* + * Query the XSAVE capability of the partition. Any error here is not + * considered fatal. + */ + hr = whp_dispatch.WHvGetPartitionProperty( + whpx->partition, + WHvPartitionPropertyCodeProcessorXsaveFeatures, + &whpx_xsave_cap, + sizeof(whpx_xsave_cap), + &whpx_cap_size); + + /* + * Windows version which don't support this property will return with the + * specific error code. + */ + if (FAILED(hr) && hr != WHV_E_UNKNOWN_PROPERTY) { + error_report("WHPX: Failed to query XSAVE capability, hr=%08lx", hr); + } + + if (!whpx_has_xsave()) { + printf("WHPX: Partition is not XSAVE capable\n"); + } + memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); prop.ProcessorCount = ms->smp.cpus; hr = whp_dispatch.WHvSetPartitionProperty( @@ -1839,6 +2657,7 @@ static int whpx_accel_init(MachineState *ms) memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); prop.ExtendedVmExits.X64MsrExit = 1; prop.ExtendedVmExits.X64CpuidExit = 1; + prop.ExtendedVmExits.ExceptionExit = 1; if (whpx_apic_in_platform()) { prop.ExtendedVmExits.X64ApicInitSipiExitTrap = 1; } @@ -1867,6 +2686,19 @@ static int whpx_accel_init(MachineState *ms) goto error; } + /* + * We do not want to intercept any exceptions from the guest, + * until we actually start debugging with gdb. + */ + whpx->exception_exit_bitmap = -1; + hr = whpx_set_exception_exit_bitmap(0); + + if (FAILED(hr)) { + error_report("WHPX: Failed to set exception exit bitmap, hr=%08lx", hr); + ret = -EINVAL; + goto error; + } + hr = whp_dispatch.WHvSetupPartition(whpx->partition); if (FAILED(hr)) { error_report("WHPX: Failed to setup partition, hr=%08lx", hr); diff --git a/target/i386/whpx/whpx-apic.c b/target/i386/whpx/whpx-apic.c index bba36f3ec98f..c15df35ad60a 100644 --- a/target/i386/whpx/whpx-apic.c +++ b/target/i386/whpx/whpx-apic.c @@ -11,7 +11,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "hw/i386/apic_internal.h" #include "hw/i386/apic-msidef.h" diff --git a/target/i386/whpx/whpx-internal.h b/target/i386/whpx/whpx-internal.h index 908ababf6dc5..06429d8ccd4c 100644 --- a/target/i386/whpx/whpx-internal.h +++ b/target/i386/whpx/whpx-internal.h @@ -1,13 +1,43 @@ -#ifndef WHP_INTERNAL_H -#define WHP_INTERNAL_H +#ifndef TARGET_I386_WHPX_INTERNAL_H +#define TARGET_I386_WHPX_INTERNAL_H #include #include #include +typedef enum WhpxBreakpointState { + WHPX_BP_CLEARED = 0, + WHPX_BP_SET_PENDING, + WHPX_BP_SET, + WHPX_BP_CLEAR_PENDING, +} WhpxBreakpointState; + +struct whpx_breakpoint { + vaddr address; + WhpxBreakpointState state; + uint8_t original_instruction; +}; + +struct whpx_breakpoint_collection { + int allocated, used; + struct whpx_breakpoint data[0]; +}; + +struct whpx_breakpoints { + int original_address_count; + vaddr *original_addresses; + + struct whpx_breakpoint_collection *breakpoints; +}; + struct whpx_state { uint64_t mem_quota; WHV_PARTITION_HANDLE partition; + uint64_t exception_exit_bitmap; + int32_t running_cpus; + struct whpx_breakpoints breakpoints; + bool step_pending; + bool kernel_irqchip_allowed; bool kernel_irqchip_required; bool apic_in_platform; @@ -18,6 +48,9 @@ void whpx_apic_get(DeviceState *s); #define WHV_E_UNKNOWN_CAPABILITY 0x80370300L +/* This should eventually come from the Windows SDK */ +#define WHV_E_UNKNOWN_PROPERTY 0x80370302 + #define LIST_WINHVPLATFORM_FUNCTIONS(X) \ X(HRESULT, WHvGetCapability, (WHV_CAPABILITY_CODE CapabilityCode, VOID* CapabilityBuffer, UINT32 CapabilityBufferSizeInBytes, UINT32* WrittenSizeInBytes)) \ X(HRESULT, WHvCreatePartition, (WHV_PARTITION_HANDLE* Partition)) \ @@ -83,4 +116,4 @@ typedef enum WHPFunctionList { WINHV_PLATFORM_FNS_SUPPLEMENTAL } WHPFunctionList; -#endif /* WHP_INTERNAL_H */ +#endif /* TARGET_I386_WHPX_INTERNAL_H */ diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig new file mode 100644 index 000000000000..46b26b1a8571 --- /dev/null +++ b/target/loongarch/Kconfig @@ -0,0 +1,2 @@ +config LOONGARCH64 + bool diff --git a/target/loongarch/README b/target/loongarch/README new file mode 100644 index 000000000000..0b9dc0d40a04 --- /dev/null +++ b/target/loongarch/README @@ -0,0 +1,52 @@ +- Introduction + + LoongArch is the general processor architecture of Loongson. + + The following versions of the LoongArch core are supported + core: 3A5000 + https://github.com/loongson/LoongArch-Documentation/releases/download/2021.08.17/LoongArch-Vol1-v1.00-EN.pdf + + We can get the latest loongarch documents at https://github.com/loongson/LoongArch-Documentation/tags. + + +- System emulation + + You can reference docs/system/loongarch/loongson3.rst to get the information about system emulation of LoongArch. + +- Linux-user emulation + + We already support Linux user emulation. We can use LoongArch cross-tools to build LoongArch executables on X86 machines, + and We can also use qemu-loongarch64 to run LoongArch executables. + + 1. Config cross-tools env. + + see System emulation. + + 2. Test tests/tcg/multiarch. + + ./configure --static --prefix=/usr --disable-werror --target-list="loongarch64-linux-user" --enable-debug + + cd build + + make && make check-tcg + + 3. Run LoongArch system basic command with loongarch-clfs-system. + + - Config clfs env. + + wget https://github.com/loongson/build-tools/releases/download/2022.05.29/loongarch64-clfs-system-5.0.tar.bz2 + + tar -vxf loongarch64-clfs-system-5.0.tar.bz2 -C /opt/clfs + + cp /opt/clfs/lib64/ld-linux-loongarch-lp64d.so.1 /lib64 + + export LD_LIBRARY_PATH="/opt/clfs/lib64" + + - Run LoongArch system basic command. + + ./qemu-loongarch64 /opt/clfs/usr/bin/bash + ./qemu-loongarch64 /opt/clfs/usr/bin/ls + ./qemu-loongarch64 /opt/clfs/usr/bin/pwd + +- Note. + We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/ diff --git a/target/loongarch/constant_timer.c b/target/loongarch/constant_timer.c new file mode 100644 index 000000000000..1851f53fd658 --- /dev/null +++ b/target/loongarch/constant_timer.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch constant timer support + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/timer.h" +#include "cpu.h" +#include "internals.h" +#include "cpu-csr.h" + +#define TIMER_PERIOD 10 /* 10 ns period for 100 MHz frequency */ +#define CONSTANT_TIMER_TICK_MASK 0xfffffffffffcUL +#define CONSTANT_TIMER_ENABLE 0x1UL + +uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu) +{ + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; +} + +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) +{ + uint64_t now, expire; + + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + expire = timer_expire_time_ns(&cpu->timer); + + return (expire - now) / TIMER_PERIOD; +} + +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, + uint64_t value) +{ + CPULoongArchState *env = &cpu->env; + uint64_t now, next; + + env->CSR_TCFG = value; + if (value & CONSTANT_TIMER_ENABLE) { + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; + timer_mod(&cpu->timer, next); + } else { + timer_del(&cpu->timer); + } +} + +void loongarch_constant_timer_cb(void *opaque) +{ + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; + uint64_t now, next; + + if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) { + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; + timer_mod(&cpu->timer, next); + } else { + env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); + } + + loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); +} diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h new file mode 100644 index 000000000000..4c8ce7fed506 --- /dev/null +++ b/target/loongarch/cpu-csr.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CSRs + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_CPU_CSR_H +#define LOONGARCH_CPU_CSR_H + +#include "hw/registerfields.h" + +/* Base on kernal definitions: arch/loongarch/include/asm/loongarch.h */ + +/* Basic CSRs */ +#define LOONGARCH_CSR_CRMD 0x0 /* Current mode info */ + +#define LOONGARCH_CSR_PRMD 0x1 /* Prev-exception mode info */ +FIELD(CSR_PRMD, PPLV, 0, 2) +FIELD(CSR_PRMD, PIE, 2, 1) +FIELD(CSR_PRMD, PWE, 3, 1) + +#define LOONGARCH_CSR_EUEN 0x2 /* Extended unit enable */ +FIELD(CSR_EUEN, FPE, 0, 1) +FIELD(CSR_EUEN, SXE, 1, 1) +FIELD(CSR_EUEN, ASXE, 2, 1) +FIELD(CSR_EUEN, BTE, 3, 1) + +#define LOONGARCH_CSR_MISC 0x3 /* Misc config */ +FIELD(CSR_MISC, VA32, 0, 4) +FIELD(CSR_MISC, DRDTL, 4, 4) +FIELD(CSR_MISC, RPCNTL, 8, 4) +FIELD(CSR_MISC, ALCL, 12, 4) +FIELD(CSR_MISC, DWPL, 16, 3) + +#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */ +FIELD(CSR_ECFG, LIE, 0, 13) +FIELD(CSR_ECFG, VS, 16, 3) + +#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ +FIELD(CSR_ESTAT, IS, 0, 13) +FIELD(CSR_ESTAT, ECODE, 16, 6) +FIELD(CSR_ESTAT, ESUBCODE, 22, 9) + +#define LOONGARCH_CSR_ERA 0x6 /* Exception return address */ + +#define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ + +#define LOONGARCH_CSR_BADI 0x8 /* Bad instruction */ + +#define LOONGARCH_CSR_EENTRY 0xc /* Exception entry address */ + +/* TLB related CSRs */ +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */ +FIELD(CSR_TLBIDX, INDEX, 0, 12) +FIELD(CSR_TLBIDX, PS, 24, 6) +FIELD(CSR_TLBIDX, NE, 31, 1) + +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */ +FIELD(CSR_TLBEHI, VPPN, 13, 35) + +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */ +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */ +FIELD(TLBENTRY, V, 0, 1) +FIELD(TLBENTRY, D, 1, 1) +FIELD(TLBENTRY, PLV, 2, 2) +FIELD(TLBENTRY, MAT, 4, 2) +FIELD(TLBENTRY, G, 6, 1) +FIELD(TLBENTRY, PPN, 12, 36) +FIELD(TLBENTRY, NR, 61, 1) +FIELD(TLBENTRY, NX, 62, 1) +FIELD(TLBENTRY, RPLV, 63, 1) + +#define LOONGARCH_CSR_ASID 0x18 /* Address space identifier */ +FIELD(CSR_ASID, ASID, 0, 10) +FIELD(CSR_ASID, ASIDBITS, 16, 8) + +/* Page table base address when badv[47] = 0 */ +#define LOONGARCH_CSR_PGDL 0x19 +/* Page table base address when badv[47] = 1 */ +#define LOONGARCH_CSR_PGDH 0x1a + +#define LOONGARCH_CSR_PGD 0x1b /* Page table base address */ + +/* Page walk controller's low addr */ +#define LOONGARCH_CSR_PWCL 0x1c +FIELD(CSR_PWCL, PTBASE, 0, 5) +FIELD(CSR_PWCL, PTWIDTH, 5, 5) +FIELD(CSR_PWCL, DIR1_BASE, 10, 5) +FIELD(CSR_PWCL, DIR1_WIDTH, 15, 5) +FIELD(CSR_PWCL, DIR2_BASE, 20, 5) +FIELD(CSR_PWCL, DIR2_WIDTH, 25, 5) +FIELD(CSR_PWCL, PTEWIDTH, 30, 2) + +/* Page walk controller's high addr */ +#define LOONGARCH_CSR_PWCH 0x1d +FIELD(CSR_PWCH, DIR3_BASE, 0, 6) +FIELD(CSR_PWCH, DIR3_WIDTH, 6, 6) +FIELD(CSR_PWCH, DIR4_BASE, 12, 6) +FIELD(CSR_PWCH, DIR4_WIDTH, 18, 6) + +#define LOONGARCH_CSR_STLBPS 0x1e /* Stlb page size */ +FIELD(CSR_STLBPS, PS, 0, 5) + +#define LOONGARCH_CSR_RVACFG 0x1f /* Reduced virtual address config */ +FIELD(CSR_RVACFG, RBITS, 0, 4) + +/* Config CSRs */ +#define LOONGARCH_CSR_CPUID 0x20 /* CPU core id */ + +#define LOONGARCH_CSR_PRCFG1 0x21 /* Config1 */ +FIELD(CSR_PRCFG1, SAVE_NUM, 0, 4) +FIELD(CSR_PRCFG1, TIMER_BITS, 4, 8) +FIELD(CSR_PRCFG1, VSMAX, 12, 3) + +#define LOONGARCH_CSR_PRCFG2 0x22 /* Config2 */ + +#define LOONGARCH_CSR_PRCFG3 0x23 /* Config3 */ +FIELD(CSR_PRCFG3, TLB_TYPE, 0, 4) +FIELD(CSR_PRCFG3, MTLB_ENTRY, 4, 8) +FIELD(CSR_PRCFG3, STLB_WAYS, 12, 8) +FIELD(CSR_PRCFG3, STLB_SETS, 20, 8) + +/* + * Save registers count can read from PRCFG1.SAVE_NUM + * The Min count is 1. Max count is 15. + */ +#define LOONGARCH_CSR_SAVE(N) (0x30 + N) + +/* Timer CSRs */ +#define LOONGARCH_CSR_TID 0x40 /* Timer ID */ + +#define LOONGARCH_CSR_TCFG 0x41 /* Timer config */ +FIELD(CSR_TCFG, EN, 0, 1) +FIELD(CSR_TCFG, PERIODIC, 1, 1) +FIELD(CSR_TCFG, INIT_VAL, 2, 46) + +#define LOONGARCH_CSR_TVAL 0x42 /* Timer ticks remain */ + +#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */ + +#define LOONGARCH_CSR_TICLR 0x44 /* Timer interrupt clear */ + +/* LLBCTL CSRs */ +#define LOONGARCH_CSR_LLBCTL 0x60 /* LLBit control */ +FIELD(CSR_LLBCTL, ROLLB, 0, 1) +FIELD(CSR_LLBCTL, WCLLB, 1, 1) +FIELD(CSR_LLBCTL, KLO, 2, 1) + +/* Implement dependent */ +#define LOONGARCH_CSR_IMPCTL1 0x80 /* LoongArch config1 */ + +#define LOONGARCH_CSR_IMPCTL2 0x81 /* LoongArch config2*/ + +/* TLB Refill CSRs */ +#define LOONGARCH_CSR_TLBRENTRY 0x88 /* TLB refill exception address */ +#define LOONGARCH_CSR_TLBRBADV 0x89 /* TLB refill badvaddr */ +#define LOONGARCH_CSR_TLBRERA 0x8a /* TLB refill ERA */ +#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill */ +FIELD(CSR_TLBRERA, ISTLBR, 0, 1) +FIELD(CSR_TLBRERA, PC, 2, 62) +#define LOONGARCH_CSR_TLBRELO0 0x8c /* TLB refill entrylo0 */ +#define LOONGARCH_CSR_TLBRELO1 0x8d /* TLB refill entrylo1 */ +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */ +FIELD(CSR_TLBREHI, PS, 0, 6) +FIELD(CSR_TLBREHI, VPPN, 13, 35) +#define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */ +FIELD(CSR_TLBRPRMD, PPLV, 0, 2) +FIELD(CSR_TLBRPRMD, PIE, 2, 1) +FIELD(CSR_TLBRPRMD, PWE, 4, 1) + +/* Machine Error CSRs */ +#define LOONGARCH_CSR_MERRCTL 0x90 /* ERRCTL */ +FIELD(CSR_MERRCTL, ISMERR, 0, 1) +#define LOONGARCH_CSR_MERRINFO1 0x91 +#define LOONGARCH_CSR_MERRINFO2 0x92 +#define LOONGARCH_CSR_MERRENTRY 0x93 /* MError exception base */ +#define LOONGARCH_CSR_MERRERA 0x94 /* MError exception PC */ +#define LOONGARCH_CSR_MERRSAVE 0x95 /* KScratch for error exception */ + +#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ + +/* Direct map windows CSRs*/ +#define LOONGARCH_CSR_DMW(N) (0x180 + N) +FIELD(CSR_DMW, PLV0, 0, 1) +FIELD(CSR_DMW, PLV1, 1, 1) +FIELD(CSR_DMW, PLV2, 2, 1) +FIELD(CSR_DMW, PLV3, 3, 1) +FIELD(CSR_DMW, MAT, 4, 2) +FIELD(CSR_DMW, VSEG, 60, 4) + +#define dmw_va2pa(va) \ + (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)) + +/* Debug CSRs */ +#define LOONGARCH_CSR_DBG 0x500 /* debug config */ +FIELD(CSR_DBG, DST, 0, 1) +FIELD(CSR_DBG, DREV, 1, 7) +FIELD(CSR_DBG, DEI, 8, 1) +FIELD(CSR_DBG, DCL, 9, 1) +FIELD(CSR_DBG, DFW, 10, 1) +FIELD(CSR_DBG, DMW, 11, 1) +FIELD(CSR_DBG, ECODE, 16, 6) + +#define LOONGARCH_CSR_DERA 0x501 /* Debug era */ +#define LOONGARCH_CSR_DSAVE 0x502 /* Debug save */ + +#endif /* LOONGARCH_CPU_CSR_H */ diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h new file mode 100644 index 000000000000..414d8fff46ff --- /dev/null +++ b/target/loongarch/cpu-param.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch CPU parameters for QEMU. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_CPU_PARAM_H +#define LOONGARCH_CPU_PARAM_H + +#define TARGET_LONG_BITS 64 +#define TARGET_PHYS_ADDR_SPACE_BITS 48 +#define TARGET_VIRT_ADDR_SPACE_BITS 48 + +#define TARGET_PAGE_BITS 14 +#define NB_MMU_MODES 5 + +#endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c new file mode 100644 index 000000000000..290ab4d526b4 --- /dev/null +++ b/target/loongarch/cpu.c @@ -0,0 +1,776 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/qemu-print.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "sysemu/qtest.h" +#include "exec/exec-all.h" +#include "qapi/qapi-commands-machine-target.h" +#include "cpu.h" +#include "internals.h" +#include "fpu/softfloat-helpers.h" +#include "cpu-csr.h" +#include "sysemu/reset.h" + +const char * const regnames[32] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; + +const char * const fregnames[32] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", +}; + +static const char * const excp_names[] = { + [EXCCODE_INT] = "Interrupt", + [EXCCODE_PIL] = "Page invalid exception for load", + [EXCCODE_PIS] = "Page invalid exception for store", + [EXCCODE_PIF] = "Page invalid exception for fetch", + [EXCCODE_PME] = "Page modified exception", + [EXCCODE_PNR] = "Page Not Readable exception", + [EXCCODE_PNX] = "Page Not Executable exception", + [EXCCODE_PPI] = "Page Privilege error", + [EXCCODE_ADEF] = "Address error for instruction fetch", + [EXCCODE_ADEM] = "Address error for Memory access", + [EXCCODE_SYS] = "Syscall", + [EXCCODE_BRK] = "Break", + [EXCCODE_INE] = "Instruction Non-Existent", + [EXCCODE_IPE] = "Instruction privilege error", + [EXCCODE_FPD] = "Floating Point Disabled", + [EXCCODE_FPE] = "Floating Point Exception", + [EXCCODE_DBP] = "Debug breakpoint", + [EXCCODE_BCE] = "Bound Check Exception", +}; + +const char *loongarch_exception_name(int32_t exception) +{ + assert(excp_names[exception]); + return excp_names[exception]; +} + +void G_NORETURN do_raise_exception(CPULoongArchState *env, + uint32_t exception, + uintptr_t pc) +{ + CPUState *cs = env_cpu(env); + + qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n", + __func__, + exception, + loongarch_exception_name(exception)); + cs->exception_index = exception; + + cpu_loop_exit_restore(cs, pc); +} + +static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + 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" + +void loongarch_cpu_set_irq(void *opaque, int irq, int level) +{ + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + if (irq < 0 || irq >= N_IRQS) { + return; + } + + env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0); + + if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env) +{ + bool ret = 0; + + ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) && + !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST))); + + return ret; +} + +/* Check if there is pending and not masked out interrupt */ +static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env) +{ + uint32_t pending; + uint32_t status; + + pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); + status = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); + + return (pending & status) != 0; +} + +static void loongarch_cpu_do_interrupt(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + bool update_badinstr = 1; + int cause = -1; + const char *name; + bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR); + uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS); + + if (cs->exception_index != EXCCODE_INT) { + if (cs->exception_index < 0 || + cs->exception_index >= ARRAY_SIZE(excp_names)) { + name = "unknown"; + } else { + name = excp_names[cs->exception_index]; + } + + qemu_log_mask(CPU_LOG_INT, + "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__, + env->pc, env->CSR_ERA, env->CSR_TLBRERA, name); + } + + switch (cs->exception_index) { + case EXCCODE_DBP: + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1); + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC); + goto set_DERA; + set_DERA: + env->CSR_DERA = env->pc; + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1); + env->pc = env->CSR_EENTRY + 0x480; + break; + case EXCCODE_INT: + if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1); + goto set_DERA; + } + QEMU_FALLTHROUGH; + case EXCCODE_PIF: + case EXCCODE_ADEF: + cause = cs->exception_index; + update_badinstr = 0; + break; + case EXCCODE_SYS: + case EXCCODE_BRK: + case EXCCODE_INE: + case EXCCODE_IPE: + case EXCCODE_FPD: + case EXCCODE_FPE: + case EXCCODE_BCE: + env->CSR_BADV = env->pc; + QEMU_FALLTHROUGH; + case EXCCODE_ADEM: + case EXCCODE_PIL: + case EXCCODE_PIS: + case EXCCODE_PME: + case EXCCODE_PNR: + case EXCCODE_PNX: + case EXCCODE_PPI: + cause = cs->exception_index; + break; + default: + qemu_log("Error: exception(%d) has not been supported\n", + cs->exception_index); + abort(); + } + + if (update_badinstr) { + env->CSR_BADI = cpu_ldl_code(env, env->pc); + } + + /* Save PLV and IE */ + if (tlbfill) { + env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV, + FIELD_EX64(env->CSR_CRMD, + CSR_CRMD, PLV)); + env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)); + /* set the DA mode */ + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, + PC, (env->pc >> 2)); + } else { + env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, + EXCODE_MCODE(cause)); + env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ESUBCODE, + EXCODE_SUBCODE(cause)); + env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV)); + env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)); + env->CSR_ERA = env->pc; + } + + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + + if (vec_size) { + vec_size = (1 << vec_size) * 4; + } + + if (cs->exception_index == EXCCODE_INT) { + /* Interrupt */ + uint32_t vector = 0; + uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); + pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); + + /* Find the highest-priority interrupt. */ + vector = 31 - clz32(pending); + env->pc = env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * vec_size; + qemu_log_mask(CPU_LOG_INT, + "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " cause %d\n" " A " TARGET_FMT_lx " D " + TARGET_FMT_lx " vector = %d ExC " TARGET_FMT_lx "ExS" + TARGET_FMT_lx "\n", + __func__, env->pc, env->CSR_ERA, + cause, env->CSR_BADV, env->CSR_DERA, vector, + env->CSR_ECFG, env->CSR_ESTAT); + } else { + if (tlbfill) { + env->pc = env->CSR_TLBRENTRY; + } else { + env->pc = env->CSR_EENTRY; + env->pc += EXCODE_MCODE(cause) * vec_size; + } + qemu_log_mask(CPU_LOG_INT, + "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " cause %d%s\n, ESTAT " TARGET_FMT_lx + " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx + "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu + " cpu %d asid " TARGET_FMT_lx "\n", __func__, env->pc, + tlbfill ? env->CSR_TLBRERA : env->CSR_ERA, + cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT, + env->CSR_ECFG, + tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV, + env->CSR_BADI, env->gpr[11], cs->cpu_index, + env->CSR_ASID); + } + cs->exception_index = -1; +} + +static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, + uintptr_t retaddr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (access_type == MMU_INST_FETCH) { + do_raise_exception(env, EXCCODE_ADEF, retaddr); + } else { + do_raise_exception(env, EXCCODE_ADEM, retaddr); + } +} + +static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + if (interrupt_request & CPU_INTERRUPT_HARD) { + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (cpu_loongarch_hw_interrupts_enabled(env) && + cpu_loongarch_hw_interrupts_pending(env)) { + /* Raise it */ + cs->exception_index = EXCCODE_INT; + loongarch_cpu_do_interrupt(cs); + return true; + } + } + return false; +} +#endif + +#ifdef CONFIG_TCG +static void loongarch_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + env->pc = tb_pc(tb); +} + +static void loongarch_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + env->pc = data[0]; +} +#endif /* CONFIG_TCG */ + +static bool loongarch_cpu_has_work(CPUState *cs) +{ +#ifdef CONFIG_USER_ONLY + return true; +#else + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + bool has_work = false; + + if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_loongarch_hw_interrupts_pending(env)) { + has_work = true; + } + + return has_work; +#endif +} + +static void loongarch_la464_initfn(Object *obj) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + CPULoongArchState *env = &cpu->env; + int i; + + for (i = 0; i < 21; i++) { + env->cpucfg[i] = 0x0; + } + + cpu->dtb_compatible = "loongarch,Loongson-3A5000"; + env->cpucfg[0] = 0x14c010; /* PRID */ + + uint32_t data = 0; + data = FIELD_DP32(data, CPUCFG1, ARCH, 2); + data = FIELD_DP32(data, CPUCFG1, PGMMU, 1); + data = FIELD_DP32(data, CPUCFG1, IOCSR, 1); + data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f); + data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f); + data = FIELD_DP32(data, CPUCFG1, UAL, 1); + data = FIELD_DP32(data, CPUCFG1, RI, 1); + data = FIELD_DP32(data, CPUCFG1, EP, 1); + data = FIELD_DP32(data, CPUCFG1, RPLV, 1); + data = FIELD_DP32(data, CPUCFG1, HP, 1); + data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); + env->cpucfg[1] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG2, FP, 1); + data = FIELD_DP32(data, CPUCFG2, FP_SP, 1); + data = FIELD_DP32(data, CPUCFG2, FP_DP, 1); + data = FIELD_DP32(data, CPUCFG2, FP_VER, 1); + data = FIELD_DP32(data, CPUCFG2, LLFTP, 1); + data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1); + data = FIELD_DP32(data, CPUCFG2, LAM, 1); + env->cpucfg[2] = data; + + env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */ + + data = 0; + data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1); + data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1); + env->cpucfg[5] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1); + data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1); + data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1); + data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1); + env->cpucfg[16] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3); + data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8); + data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6); + env->cpucfg[17] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3); + data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8); + data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6); + env->cpucfg[18] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15); + data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8); + data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6); + env->cpucfg[19] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15); + data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14); + data = FIELD_DP32(data, CPUCFG20, L3IU_SIZE, 6); + env->cpucfg[20] = data; + + env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); +} + +static void loongarch_cpu_list_entry(gpointer data, gpointer user_data) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(data)); + + qemu_printf("%s\n", typename); +} + +void loongarch_cpu_list(void) +{ + GSList *list; + list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false); + g_slist_foreach(list, loongarch_cpu_list_entry, NULL); + g_slist_free(list); +} + +static void loongarch_cpu_reset_hold(Object *obj) +{ + CPUState *cs = CPU(obj); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu); + CPULoongArchState *env = &cpu->env; + + if (lacc->parent_phases.hold) { + lacc->parent_phases.hold(obj); + } + + env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; + env->fcsr0 = 0x0; + + int n; + /* Set csr registers value after reset */ + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1); + + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0); + + env->CSR_MISC = 0; + + env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0); + env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0); + + env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2)); + env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0); + env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); + env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0); + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); + env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); + + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); + + for (n = 0; n < 4; n++) { + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); + } + +#ifndef CONFIG_USER_ONLY + env->pc = 0x1c000000; + memset(env->tlb, 0, sizeof(env->tlb)); +#endif + + restore_fp_status(env); + cs->exception_index = -1; +} + +static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) +{ + info->print_insn = print_insn_loongarch; +} + +static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + loongarch_cpu_register_gdb_regs_for_features(cs); + + cpu_reset(cs); + qemu_init_vcpu(cs); + + lacc->parent_realize(dev, errp); +} + +#ifndef CONFIG_USER_ONLY +static void loongarch_qemu_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ +} + +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size) +{ + switch (addr) { + case FEATURE_REG: + return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI | + 1ULL << IOCSRF_CSRIPI; + case VENDOR_REG: + return 0x6e6f73676e6f6f4cULL; /* "Loongson" */ + case CPUNAME_REG: + return 0x303030354133ULL; /* "3A5000" */ + case MISC_FUNC_REG: + return 1ULL << IOCSRM_EXTIOI_EN; + } + return 0ULL; +} + +static const MemoryRegionOps loongarch_qemu_ops = { + .read = loongarch_qemu_read, + .write = loongarch_qemu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 8, + .max_access_size = 8, + }, +}; +#endif + +static void loongarch_cpu_init(Object *obj) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + + cpu_set_cpustate_pointers(cpu); + +#ifndef CONFIG_USER_ONLY + CPULoongArchState *env = &cpu->env; + qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); + timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, + &loongarch_constant_timer_cb, cpu); + memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL, + env, "iocsr", UINT64_MAX); + address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR"); + memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops, + NULL, "iocsr_misc", 0x428); + memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem); +#endif +} + +static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + oc = object_class_by_name(cpu_model); + if (!oc) { + g_autofree char *typename + = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); + oc = object_class_by_name(typename); + if (!oc) { + return NULL; + } + } + + if (object_class_dynamic_cast(oc, TYPE_LOONGARCH_CPU) + && !object_class_is_abstract(oc)) { + return oc; + } + return NULL; +} + +void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + int i; + + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); + qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, + get_float_exception_flags(&env->fp_status)); + + /* gpr */ + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) { + qemu_fprintf(f, " GPR%02d:", i); + } + qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]); + if ((i & 3) == 3) { + qemu_fprintf(f, "\n"); + } + } + + qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD); + qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD); + qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN); + qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT); + qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA); + qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV); + qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI); + qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY); + qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 "," + " PRCFG3=%016" PRIx64 "\n", + env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); + qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY); + qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV); + qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA); + + /* fpr */ + if (flags & CPU_DUMP_FPU) { + for (i = 0; i < 32; i++) { + qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]); + if ((i & 3) == 3) { + qemu_fprintf(f, "\n"); + } + } + } +} + +#ifdef CONFIG_TCG +#include "hw/core/tcg-cpu-ops.h" + +static struct TCGCPUOps loongarch_tcg_ops = { + .initialize = loongarch_translate_init, + .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, + .restore_state_to_opc = loongarch_restore_state_to_opc, + +#ifndef CONFIG_USER_ONLY + .tlb_fill = loongarch_cpu_tlb_fill, + .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, + .do_interrupt = loongarch_cpu_do_interrupt, + .do_transaction_failed = loongarch_cpu_do_transaction_failed, +#endif +}; +#endif /* CONFIG_TCG */ + +#ifndef CONFIG_USER_ONLY +#include "hw/core/sysemu-cpu-ops.h" + +static const struct SysemuCPUOps loongarch_sysemu_ops = { + .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, +}; +#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); + CPUClass *cc = CPU_CLASS(c); + DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); + + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &lacc->parent_realize); + resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL, + &lacc->parent_phases); + + cc->class_by_name = loongarch_cpu_class_by_name; + 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; +#endif + cc->disas_set_info = loongarch_cpu_disas_set_info; + 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 = 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; +#endif +} + +#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \ + { \ + .parent = TYPE_LOONGARCH_CPU, \ + .instance_init = initfn, \ + .name = LOONGARCH_CPU_TYPE_NAME(model), \ + } + +static const TypeInfo loongarch_cpu_type_infos[] = { + { + .name = TYPE_LOONGARCH_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(LoongArchCPU), + .instance_init = loongarch_cpu_init, + + .abstract = true, + .class_size = sizeof(LoongArchCPUClass), + .class_init = loongarch_cpu_class_init, + }, + DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn), +}; + +DEFINE_TYPES(loongarch_cpu_type_infos) + +static void loongarch_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfo *info = g_new0(CpuDefinitionInfo, 1); + const char *typename = object_class_get_name(oc); + + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_LOONGARCH_CPU)); + info->q_typename = g_strdup(typename); + + QAPI_LIST_PREPEND(*cpu_list, info); +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_LOONGARCH_CPU, false); + g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h new file mode 100644 index 000000000000..e35cf655975d --- /dev/null +++ b/target/loongarch/cpu.h @@ -0,0 +1,423 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_CPU_H +#define LOONGARCH_CPU_H + +#include "exec/cpu-defs.h" +#include "fpu/softfloat-types.h" +#include "hw/registerfields.h" +#include "qemu/timer.h" +#include "exec/memory.h" +#include "hw/sysbus.h" +#include "cpu-csr.h" + +#define IOCSRF_TEMP 0 +#define IOCSRF_NODECNT 1 +#define IOCSRF_MSI 2 +#define IOCSRF_EXTIOI 3 +#define IOCSRF_CSRIPI 4 +#define IOCSRF_FREQCSR 5 +#define IOCSRF_FREQSCALE 6 +#define IOCSRF_DVFSV1 7 +#define IOCSRF_GMOD 9 +#define IOCSRF_VM 11 + +#define FEATURE_REG 0x8 +#define VENDOR_REG 0x10 +#define CPUNAME_REG 0x20 +#define MISC_FUNC_REG 0x420 +#define IOCSRM_EXTIOI_EN 48 + +#define IOCSR_MEM_SIZE 0x428 + +#define TCG_GUEST_DEFAULT_MO (0) + +#define FCSR0_M1 0x1f /* FCSR1 mask, Enables */ +#define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */ +#define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */ +#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */ + +FIELD(FCSR0, ENABLES, 0, 5) +FIELD(FCSR0, RM, 8, 2) +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) \ + 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) \ + 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) \ + do { \ + (REG) = FIELD_DP32(REG, FCSR0, FLAGS, V); \ + } while (0) + +#define UPDATE_FP_FLAGS(REG, V) \ + do { \ + (REG) |= FIELD_DP32(0, FCSR0, FLAGS, V); \ + } while (0) + +#define FP_INEXACT 1 +#define FP_UNDERFLOW 2 +#define FP_OVERFLOW 4 +#define FP_DIV0 8 +#define FP_INVALID 16 + +#define EXCODE(code, subcode) ( ((subcode) << 6) | (code) ) +#define EXCODE_MCODE(code) ( (code) & 0x3f ) +#define EXCODE_SUBCODE(code) ( (code) >> 6 ) + +#define EXCCODE_EXTERNAL_INT 64 /* plus external interrupt number */ +#define EXCCODE_INT EXCODE(0, 0) +#define EXCCODE_PIL EXCODE(1, 0) +#define EXCCODE_PIS EXCODE(2, 0) +#define EXCCODE_PIF EXCODE(3, 0) +#define EXCCODE_PME EXCODE(4, 0) +#define EXCCODE_PNR EXCODE(5, 0) +#define EXCCODE_PNX EXCODE(6, 0) +#define EXCCODE_PPI EXCODE(7, 0) +#define EXCCODE_ADEF EXCODE(8, 0) /* Different exception subcode */ +#define EXCCODE_ADEM EXCODE(8, 1) +#define EXCCODE_ALE EXCODE(9, 0) +#define EXCCODE_BCE EXCODE(10, 0) +#define EXCCODE_SYS EXCODE(11, 0) +#define EXCCODE_BRK EXCODE(12, 0) +#define EXCCODE_INE EXCODE(13, 0) +#define EXCCODE_IPE EXCODE(14, 0) +#define EXCCODE_FPD EXCODE(15, 0) +#define EXCCODE_SXD EXCODE(16, 0) +#define EXCCODE_ASXD EXCODE(17, 0) +#define EXCCODE_FPE EXCODE(18, 0) /* Different exception subcode */ +#define EXCCODE_VFPE EXCODE(18, 1) +#define EXCCODE_WPEF EXCODE(19, 0) /* Different exception subcode */ +#define EXCCODE_WPEM EXCODE(19, 1) +#define EXCCODE_BTD EXCODE(20, 0) +#define EXCCODE_BTE EXCODE(21, 0) +#define EXCCODE_DBP EXCODE(26, 0) /* Reserved subcode used for debug */ + +/* cpucfg[0] bits */ +FIELD(CPUCFG0, PRID, 0, 32) + +/* cpucfg[1] bits */ +FIELD(CPUCFG1, ARCH, 0, 2) +FIELD(CPUCFG1, PGMMU, 2, 1) +FIELD(CPUCFG1, IOCSR, 3, 1) +FIELD(CPUCFG1, PALEN, 4, 8) +FIELD(CPUCFG1, VALEN, 12, 8) +FIELD(CPUCFG1, UAL, 20, 1) +FIELD(CPUCFG1, RI, 21, 1) +FIELD(CPUCFG1, EP, 22, 1) +FIELD(CPUCFG1, RPLV, 23, 1) +FIELD(CPUCFG1, HP, 24, 1) +FIELD(CPUCFG1, IOCSR_BRD, 25, 1) +FIELD(CPUCFG1, MSG_INT, 26, 1) + +/* cpucfg[2] bits */ +FIELD(CPUCFG2, FP, 0, 1) +FIELD(CPUCFG2, FP_SP, 1, 1) +FIELD(CPUCFG2, FP_DP, 2, 1) +FIELD(CPUCFG2, FP_VER, 3, 3) +FIELD(CPUCFG2, LSX, 6, 1) +FIELD(CPUCFG2, LASX, 7, 1) +FIELD(CPUCFG2, COMPLEX, 8, 1) +FIELD(CPUCFG2, CRYPTO, 9, 1) +FIELD(CPUCFG2, LVZ, 10, 1) +FIELD(CPUCFG2, LVZ_VER, 11, 3) +FIELD(CPUCFG2, LLFTP, 14, 1) +FIELD(CPUCFG2, LLFTP_VER, 15, 3) +FIELD(CPUCFG2, LBT_X86, 18, 1) +FIELD(CPUCFG2, LBT_ARM, 19, 1) +FIELD(CPUCFG2, LBT_MIPS, 20, 1) +FIELD(CPUCFG2, LSPW, 21, 1) +FIELD(CPUCFG2, LAM, 22, 1) + +/* cpucfg[3] bits */ +FIELD(CPUCFG3, CCDMA, 0, 1) +FIELD(CPUCFG3, SFB, 1, 1) +FIELD(CPUCFG3, UCACC, 2, 1) +FIELD(CPUCFG3, LLEXC, 3, 1) +FIELD(CPUCFG3, SCDLY, 4, 1) +FIELD(CPUCFG3, LLDBAR, 5, 1) +FIELD(CPUCFG3, ITLBHMC, 6, 1) +FIELD(CPUCFG3, ICHMC, 7, 1) +FIELD(CPUCFG3, SPW_LVL, 8, 3) +FIELD(CPUCFG3, SPW_HP_HF, 11, 1) +FIELD(CPUCFG3, RVA, 12, 1) +FIELD(CPUCFG3, RVAMAX, 13, 4) + +/* cpucfg[4] bits */ +FIELD(CPUCFG4, CC_FREQ, 0, 32) + +/* cpucfg[5] bits */ +FIELD(CPUCFG5, CC_MUL, 0, 16) +FIELD(CPUCFG5, CC_DIV, 16, 16) + +/* cpucfg[6] bits */ +FIELD(CPUCFG6, PMP, 0, 1) +FIELD(CPUCFG6, PMVER, 1, 3) +FIELD(CPUCFG6, PMNUM, 4, 4) +FIELD(CPUCFG6, PMBITS, 8, 6) +FIELD(CPUCFG6, UPM, 14, 1) + +/* cpucfg[16] bits */ +FIELD(CPUCFG16, L1_IUPRE, 0, 1) +FIELD(CPUCFG16, L1_IUUNIFY, 1, 1) +FIELD(CPUCFG16, L1_DPRE, 2, 1) +FIELD(CPUCFG16, L2_IUPRE, 3, 1) +FIELD(CPUCFG16, L2_IUUNIFY, 4, 1) +FIELD(CPUCFG16, L2_IUPRIV, 5, 1) +FIELD(CPUCFG16, L2_IUINCL, 6, 1) +FIELD(CPUCFG16, L2_DPRE, 7, 1) +FIELD(CPUCFG16, L2_DPRIV, 8, 1) +FIELD(CPUCFG16, L2_DINCL, 9, 1) +FIELD(CPUCFG16, L3_IUPRE, 10, 1) +FIELD(CPUCFG16, L3_IUUNIFY, 11, 1) +FIELD(CPUCFG16, L3_IUPRIV, 12, 1) +FIELD(CPUCFG16, L3_IUINCL, 13, 1) +FIELD(CPUCFG16, L3_DPRE, 14, 1) +FIELD(CPUCFG16, L3_DPRIV, 15, 1) +FIELD(CPUCFG16, L3_DINCL, 16, 1) + +/* cpucfg[17] bits */ +FIELD(CPUCFG17, L1IU_WAYS, 0, 16) +FIELD(CPUCFG17, L1IU_SETS, 16, 8) +FIELD(CPUCFG17, L1IU_SIZE, 24, 7) + +/* cpucfg[18] bits */ +FIELD(CPUCFG18, L1D_WAYS, 0, 16) +FIELD(CPUCFG18, L1D_SETS, 16, 8) +FIELD(CPUCFG18, L1D_SIZE, 24, 7) + +/* cpucfg[19] bits */ +FIELD(CPUCFG19, L2IU_WAYS, 0, 16) +FIELD(CPUCFG19, L2IU_SETS, 16, 8) +FIELD(CPUCFG19, L2IU_SIZE, 24, 7) + +/* cpucfg[20] bits */ +FIELD(CPUCFG20, L3IU_WAYS, 0, 16) +FIELD(CPUCFG20, L3IU_SETS, 16, 8) +FIELD(CPUCFG20, L3IU_SIZE, 24, 7) + +/*CSR_CRMD */ +FIELD(CSR_CRMD, PLV, 0, 2) +FIELD(CSR_CRMD, IE, 2, 1) +FIELD(CSR_CRMD, DA, 3, 1) +FIELD(CSR_CRMD, PG, 4, 1) +FIELD(CSR_CRMD, DATF, 5, 2) +FIELD(CSR_CRMD, DATM, 7, 2) +FIELD(CSR_CRMD, WE, 9, 1) + +extern const char * const regnames[32]; +extern const char * const fregnames[32]; + +#define N_IRQS 13 +#define IRQ_TIMER 11 +#define IRQ_IPI 12 + +#define LOONGARCH_STLB 2048 /* 2048 STLB */ +#define LOONGARCH_MTLB 64 /* 64 MTLB */ +#define LOONGARCH_TLB_MAX (LOONGARCH_STLB + LOONGARCH_MTLB) + +/* + * define the ASID PS E VPPN field of TLB + */ +FIELD(TLB_MISC, E, 0, 1) +FIELD(TLB_MISC, ASID, 1, 10) +FIELD(TLB_MISC, VPPN, 13, 35) +FIELD(TLB_MISC, PS, 48, 6) + +struct LoongArchTLB { + uint64_t tlb_misc; + /* Fields corresponding to CSR_TLBELO0/1 */ + uint64_t tlb_entry0; + uint64_t tlb_entry1; +}; +typedef struct LoongArchTLB LoongArchTLB; + +typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; + + uint64_t fpr[32]; + float_status fp_status; + bool cf[8]; + + uint32_t fcsr0; + uint32_t fcsr0_mask; + + uint32_t cpucfg[21]; + + uint64_t lladdr; /* LL virtual address compared against SC */ + uint64_t llval; + + /* LoongArch CSRs */ + uint64_t CSR_CRMD; + uint64_t CSR_PRMD; + uint64_t CSR_EUEN; + uint64_t CSR_MISC; + uint64_t CSR_ECFG; + uint64_t CSR_ESTAT; + uint64_t CSR_ERA; + uint64_t CSR_BADV; + uint64_t CSR_BADI; + uint64_t CSR_EENTRY; + uint64_t CSR_TLBIDX; + uint64_t CSR_TLBEHI; + uint64_t CSR_TLBELO0; + uint64_t CSR_TLBELO1; + uint64_t CSR_ASID; + uint64_t CSR_PGDL; + uint64_t CSR_PGDH; + uint64_t CSR_PGD; + uint64_t CSR_PWCL; + uint64_t CSR_PWCH; + uint64_t CSR_STLBPS; + uint64_t CSR_RVACFG; + uint64_t CSR_PRCFG1; + uint64_t CSR_PRCFG2; + uint64_t CSR_PRCFG3; + uint64_t CSR_SAVE[16]; + uint64_t CSR_TID; + uint64_t CSR_TCFG; + uint64_t CSR_TVAL; + uint64_t CSR_CNTC; + uint64_t CSR_TICLR; + uint64_t CSR_LLBCTL; + uint64_t CSR_IMPCTL1; + uint64_t CSR_IMPCTL2; + uint64_t CSR_TLBRENTRY; + uint64_t CSR_TLBRBADV; + uint64_t CSR_TLBRERA; + uint64_t CSR_TLBRSAVE; + uint64_t CSR_TLBRELO0; + uint64_t CSR_TLBRELO1; + uint64_t CSR_TLBREHI; + uint64_t CSR_TLBRPRMD; + uint64_t CSR_MERRCTL; + uint64_t CSR_MERRINFO1; + uint64_t CSR_MERRINFO2; + uint64_t CSR_MERRENTRY; + uint64_t CSR_MERRERA; + uint64_t CSR_MERRSAVE; + uint64_t CSR_CTAG; + uint64_t CSR_DMW[4]; + uint64_t CSR_DBG; + uint64_t CSR_DERA; + uint64_t CSR_DSAVE; + +#ifndef CONFIG_USER_ONLY + LoongArchTLB tlb[LOONGARCH_TLB_MAX]; + + AddressSpace address_space_iocsr; + MemoryRegion system_iocsr; + MemoryRegion iocsr_mem; + bool load_elf; + uint64_t elf_address; +#endif +} CPULoongArchState; + +/** + * LoongArchCPU: + * @env: #CPULoongArchState + * + * A LoongArch CPU. + */ +struct ArchCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPULoongArchState env; + QEMUTimer timer; + + /* 'compatible' string for this CPU for Linux device trees */ + const char *dtb_compatible; +}; + +#define TYPE_LOONGARCH_CPU "loongarch-cpu" + +OBJECT_DECLARE_CPU_TYPE(LoongArchCPU, LoongArchCPUClass, + LOONGARCH_CPU) + +/** + * LoongArchCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_phases: The parent class' reset phase handlers. + * + * A LoongArch CPU model. + */ +struct LoongArchCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; + ResettablePhases parent_phases; +}; + +/* + * LoongArch CPUs has 4 privilege levels. + * 0 for kernel mode, 3 for user mode. + * Define an extra index for DA(direct addressing) mode. + */ +#define MMU_PLV_KERNEL 0 +#define MMU_PLV_USER 3 +#define MMU_IDX_KERNEL MMU_PLV_KERNEL +#define MMU_IDX_USER MMU_PLV_USER +#define MMU_IDX_DA 4 + +static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch) +{ +#ifdef CONFIG_USER_ONLY + return MMU_IDX_USER; +#else + if (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG)) { + return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); + } + return MMU_IDX_DA; +#endif +} + +/* + * LoongArch CPUs hardware flags. + */ +#define HW_FLAGS_PLV_MASK R_CSR_CRMD_PLV_MASK /* 0x03 */ +#define HW_FLAGS_CRMD_PG R_CSR_CRMD_PG_MASK /* 0x10 */ +#define HW_FLAGS_EUEN_FPE 0x04 + +static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, + target_ulong *pc, + target_ulong *cs_base, + uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = env->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); + *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; +} + +void loongarch_cpu_list(void); + +#define cpu_list loongarch_cpu_list + +#include "exec/cpu-all.h" + +#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU +#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX +#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU + +#endif /* LOONGARCH_CPU_H */ diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c new file mode 100644 index 000000000000..7e027878957f --- /dev/null +++ b/target/loongarch/csr_helper.c @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation helpers for CSRs + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "internals.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "hw/irq.h" +#include "cpu-csr.h" +#include "tcg/tcg-ldst.h" + +target_ulong helper_csrrd_pgd(CPULoongArchState *env) +{ + int64_t v; + + if (env->CSR_TLBRERA & 0x1) { + v = env->CSR_TLBRBADV; + } else { + v = env->CSR_BADV; + } + + if ((v >> 63) & 0x1) { + v = env->CSR_PGDH; + } else { + v = env->CSR_PGDL; + } + + return v; +} + +target_ulong helper_csrrd_tval(CPULoongArchState *env) +{ + LoongArchCPU *cpu = env_archcpu(env); + + return cpu_loongarch_get_constant_timer_ticks(cpu); +} + +target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) +{ + int64_t old_v = env->CSR_ESTAT; + + /* Only IS[1:0] can be written */ + env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); + + return old_v; +} + +target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) +{ + int64_t old_v = env->CSR_ASID; + + /* Only ASID filed of CSR_ASID can be written */ + env->CSR_ASID = deposit64(env->CSR_ASID, 0, 10, val); + if (old_v != env->CSR_ASID) { + tlb_flush(env_cpu(env)); + } + return old_v; +} + +target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) +{ + LoongArchCPU *cpu = env_archcpu(env); + int64_t old_v = env->CSR_TCFG; + + cpu_loongarch_store_constant_timer_config(cpu, val); + + return old_v; +} + +target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) +{ + LoongArchCPU *cpu = env_archcpu(env); + int64_t old_v = 0; + + if (val & 0x1) { + qemu_mutex_lock_iothread(); + loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); + qemu_mutex_unlock_iothread(); + } + return old_v; +} diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c new file mode 100644 index 000000000000..858dfcc53ab8 --- /dev/null +++ b/target/loongarch/disas.c @@ -0,0 +1,757 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch Disassembler + * + * Copyright (c) 2021 Loongson Technology Corporation Limited. + */ + +#include "qemu/osdep.h" +#include "disas/dis-asm.h" +#include "qemu/bitops.h" +#include "cpu-csr.h" + +typedef struct { + disassemble_info *info; + uint64_t pc; + uint32_t insn; +} DisasContext; + +static inline int plus_1(DisasContext *ctx, int x) +{ + return x + 1; +} + +static inline int shl_2(DisasContext *ctx, int x) +{ + return x << 2; +} + +#define CSR_NAME(REG) \ + [LOONGARCH_CSR_##REG] = (#REG) + +static const char * const csr_names[] = { + CSR_NAME(CRMD), + CSR_NAME(PRMD), + CSR_NAME(EUEN), + CSR_NAME(MISC), + CSR_NAME(ECFG), + CSR_NAME(ESTAT), + CSR_NAME(ERA), + CSR_NAME(BADV), + CSR_NAME(BADI), + CSR_NAME(EENTRY), + CSR_NAME(TLBIDX), + CSR_NAME(TLBEHI), + CSR_NAME(TLBELO0), + CSR_NAME(TLBELO1), + CSR_NAME(ASID), + CSR_NAME(PGDL), + CSR_NAME(PGDH), + CSR_NAME(PGD), + CSR_NAME(PWCL), + CSR_NAME(PWCH), + CSR_NAME(STLBPS), + CSR_NAME(RVACFG), + CSR_NAME(CPUID), + CSR_NAME(PRCFG1), + CSR_NAME(PRCFG2), + CSR_NAME(PRCFG3), + CSR_NAME(SAVE(0)), + CSR_NAME(SAVE(1)), + CSR_NAME(SAVE(2)), + CSR_NAME(SAVE(3)), + CSR_NAME(SAVE(4)), + CSR_NAME(SAVE(5)), + CSR_NAME(SAVE(6)), + CSR_NAME(SAVE(7)), + CSR_NAME(SAVE(8)), + CSR_NAME(SAVE(9)), + CSR_NAME(SAVE(10)), + CSR_NAME(SAVE(11)), + CSR_NAME(SAVE(12)), + CSR_NAME(SAVE(13)), + CSR_NAME(SAVE(14)), + CSR_NAME(SAVE(15)), + CSR_NAME(TID), + CSR_NAME(TCFG), + CSR_NAME(TVAL), + CSR_NAME(CNTC), + CSR_NAME(TICLR), + CSR_NAME(LLBCTL), + CSR_NAME(IMPCTL1), + CSR_NAME(IMPCTL2), + CSR_NAME(TLBRENTRY), + CSR_NAME(TLBRBADV), + CSR_NAME(TLBRERA), + CSR_NAME(TLBRSAVE), + CSR_NAME(TLBRELO0), + CSR_NAME(TLBRELO1), + CSR_NAME(TLBREHI), + CSR_NAME(TLBRPRMD), + CSR_NAME(MERRCTL), + CSR_NAME(MERRINFO1), + CSR_NAME(MERRINFO2), + CSR_NAME(MERRENTRY), + CSR_NAME(MERRERA), + CSR_NAME(MERRSAVE), + CSR_NAME(CTAG), + CSR_NAME(DMW(0)), + CSR_NAME(DMW(1)), + CSR_NAME(DMW(2)), + CSR_NAME(DMW(3)), + CSR_NAME(DBG), + CSR_NAME(DERA), + CSR_NAME(DSAVE), +}; + +static const char *get_csr_name(unsigned num) +{ + return ((num < ARRAY_SIZE(csr_names)) && (csr_names[num] != NULL)) ? + csr_names[num] : "Undefined CSR"; +} + +#define output(C, INSN, FMT, ...) \ +{ \ + (C)->info->fprintf_func((C)->info->stream, "%08x %-9s\t" FMT, \ + (C)->insn, INSN, ##__VA_ARGS__); \ +} + +#include "decode-insns.c.inc" + +int print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) +{ + bfd_byte buffer[4]; + uint32_t insn; + int status; + + status = (*info->read_memory_func)(memaddr, buffer, 4, info); + if (status != 0) { + (*info->memory_error_func)(status, memaddr, info); + return -1; + } + insn = bfd_getl32(buffer); + DisasContext ctx = { + .info = info, + .pc = memaddr, + .insn = insn + }; + + if (!decode(&ctx, insn)) { + output(&ctx, "illegal", ""); + } + return 4; +} + +static void output_r_i(DisasContext *ctx, arg_r_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d", a->rd, a->imm); +} + +static void output_rrr(DisasContext *ctx, arg_rrr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, r%d", a->rd, a->rj, a->rk); +} + +static void output_rr_i(DisasContext *ctx, arg_rr_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->imm); +} + +static void output_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, r%d, %d", a->rd, a->rj, a->rk, a->sa); +} + +static void output_rr(DisasContext *ctx, arg_rr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d", a->rd, a->rj); +} + +static void output_rr_ms_ls(DisasContext *ctx, arg_rr_ms_ls *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d, %d", a->rd, a->rj, a->ms, a->ls); +} + +static void output_hint_r_i(DisasContext *ctx, arg_hint_r_i *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, %d", a->hint, a->rj, a->imm); +} + +static void output_i(DisasContext *ctx, arg_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "%d", a->imm); +} + +static void output_rr_jk(DisasContext *ctx, arg_rr_jk *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d", a->rj, a->rk); +} + +static void output_ff(DisasContext *ctx, arg_ff *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d", a->fd, a->fj); +} + +static void output_fff(DisasContext *ctx, arg_fff *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d, f%d", a->fd, a->fj, a->fk); +} + +static void output_ffff(DisasContext *ctx, arg_ffff *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d, f%d, f%d", a->fd, a->fj, a->fk, a->fa); +} + +static void output_fffc(DisasContext *ctx, arg_fffc *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d, f%d, %d", a->fd, a->fj, a->fk, a->ca); +} + +static void output_fr(DisasContext *ctx, arg_fr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, r%d", a->fd, a->rj); +} + +static void output_rf(DisasContext *ctx, arg_rf *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, f%d", a->rd, a->fj); +} + +static void output_fcsrd_r(DisasContext *ctx, arg_fcsrd_r *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "fcsr%d, r%d", a->fcsrd, a->rj); +} + +static void output_r_fcsrs(DisasContext *ctx, arg_r_fcsrs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, fcsr%d", a->rd, a->fcsrs); +} + +static void output_cf(DisasContext *ctx, arg_cf *a, const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, f%d", a->cd, a->fj); +} + +static void output_fc(DisasContext *ctx, arg_fc *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, fcc%d", a->fd, a->cj); +} + +static void output_cr(DisasContext *ctx, arg_cr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, r%d", a->cd, a->rj); +} + +static void output_rc(DisasContext *ctx, arg_rc *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, fcc%d", a->rd, a->cj); +} + +static void output_frr(DisasContext *ctx, arg_frr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, r%d, r%d", a->fd, a->rj, a->rk); +} + +static void output_fr_i(DisasContext *ctx, arg_fr_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, r%d, %d", a->fd, a->rj, a->imm); +} + +static void output_r_offs(DisasContext *ctx, arg_r_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d # 0x%" PRIx64, a->rj, a->offs, + ctx->pc + a->offs); +} + +static void output_c_offs(DisasContext *ctx, arg_c_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, %d # 0x%" PRIx64, a->cj, a->offs, + ctx->pc + a->offs); +} + +static void output_offs(DisasContext *ctx, arg_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d # 0x%" PRIx64, a->offs, ctx->pc + a->offs); +} + +static void output_rr_offs(DisasContext *ctx, arg_rr_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d # 0x%" PRIx64, a->rj, + a->rd, a->offs, ctx->pc + a->offs); +} + +static void output_r_csr(DisasContext *ctx, arg_r_csr *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d # %s", a->rd, a->csr, get_csr_name(a->csr)); +} + +static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d # %s", + a->rd, a->rj, a->csr, get_csr_name(a->csr)); +} + +static void output_empty(DisasContext *ctx, arg_empty *a, + const char *mnemonic) +{ + output(ctx, mnemonic, ""); +} + +static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk); +} + +static void output_cop_r_i(DisasContext *ctx, arg_cop_r_i *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, %d", a->cop, a->rj, a->imm); +} + +static void output_j_i(DisasContext *ctx, arg_j_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d", a->rj, a->imm); +} + +#define INSN(insn, type) \ +static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ +{ \ + output_##type(ctx, a, #insn); \ + return true; \ +} + +INSN(clo_w, rr) +INSN(clz_w, rr) +INSN(cto_w, rr) +INSN(ctz_w, rr) +INSN(clo_d, rr) +INSN(clz_d, rr) +INSN(cto_d, rr) +INSN(ctz_d, rr) +INSN(revb_2h, rr) +INSN(revb_4h, rr) +INSN(revb_2w, rr) +INSN(revb_d, rr) +INSN(revh_2w, rr) +INSN(revh_d, rr) +INSN(bitrev_4b, rr) +INSN(bitrev_8b, rr) +INSN(bitrev_w, rr) +INSN(bitrev_d, rr) +INSN(ext_w_h, rr) +INSN(ext_w_b, rr) +INSN(rdtimel_w, rr) +INSN(rdtimeh_w, rr) +INSN(rdtime_d, rr) +INSN(cpucfg, rr) +INSN(asrtle_d, rr_jk) +INSN(asrtgt_d, rr_jk) +INSN(alsl_w, rrr_sa) +INSN(alsl_wu, rrr_sa) +INSN(bytepick_w, rrr_sa) +INSN(bytepick_d, rrr_sa) +INSN(add_w, rrr) +INSN(add_d, rrr) +INSN(sub_w, rrr) +INSN(sub_d, rrr) +INSN(slt, rrr) +INSN(sltu, rrr) +INSN(maskeqz, rrr) +INSN(masknez, rrr) +INSN(nor, rrr) +INSN(and, rrr) +INSN(or, rrr) +INSN(xor, rrr) +INSN(orn, rrr) +INSN(andn, rrr) +INSN(sll_w, rrr) +INSN(srl_w, rrr) +INSN(sra_w, rrr) +INSN(sll_d, rrr) +INSN(srl_d, rrr) +INSN(sra_d, rrr) +INSN(rotr_w, rrr) +INSN(rotr_d, rrr) +INSN(mul_w, rrr) +INSN(mulh_w, rrr) +INSN(mulh_wu, rrr) +INSN(mul_d, rrr) +INSN(mulh_d, rrr) +INSN(mulh_du, rrr) +INSN(mulw_d_w, rrr) +INSN(mulw_d_wu, rrr) +INSN(div_w, rrr) +INSN(mod_w, rrr) +INSN(div_wu, rrr) +INSN(mod_wu, rrr) +INSN(div_d, rrr) +INSN(mod_d, rrr) +INSN(div_du, rrr) +INSN(mod_du, rrr) +INSN(crc_w_b_w, rrr) +INSN(crc_w_h_w, rrr) +INSN(crc_w_w_w, rrr) +INSN(crc_w_d_w, rrr) +INSN(crcc_w_b_w, rrr) +INSN(crcc_w_h_w, rrr) +INSN(crcc_w_w_w, rrr) +INSN(crcc_w_d_w, rrr) +INSN(break, i) +INSN(syscall, i) +INSN(alsl_d, rrr_sa) +INSN(slli_w, rr_i) +INSN(slli_d, rr_i) +INSN(srli_w, rr_i) +INSN(srli_d, rr_i) +INSN(srai_w, rr_i) +INSN(srai_d, rr_i) +INSN(rotri_w, rr_i) +INSN(rotri_d, rr_i) +INSN(bstrins_w, rr_ms_ls) +INSN(bstrpick_w, rr_ms_ls) +INSN(bstrins_d, rr_ms_ls) +INSN(bstrpick_d, rr_ms_ls) +INSN(fadd_s, fff) +INSN(fadd_d, fff) +INSN(fsub_s, fff) +INSN(fsub_d, fff) +INSN(fmul_s, fff) +INSN(fmul_d, fff) +INSN(fdiv_s, fff) +INSN(fdiv_d, fff) +INSN(fmax_s, fff) +INSN(fmax_d, fff) +INSN(fmin_s, fff) +INSN(fmin_d, fff) +INSN(fmaxa_s, fff) +INSN(fmaxa_d, fff) +INSN(fmina_s, fff) +INSN(fmina_d, fff) +INSN(fscaleb_s, fff) +INSN(fscaleb_d, fff) +INSN(fcopysign_s, fff) +INSN(fcopysign_d, fff) +INSN(fabs_s, ff) +INSN(fabs_d, ff) +INSN(fneg_s, ff) +INSN(fneg_d, ff) +INSN(flogb_s, ff) +INSN(flogb_d, ff) +INSN(fclass_s, ff) +INSN(fclass_d, ff) +INSN(fsqrt_s, ff) +INSN(fsqrt_d, ff) +INSN(frecip_s, ff) +INSN(frecip_d, ff) +INSN(frsqrt_s, ff) +INSN(frsqrt_d, ff) +INSN(fmov_s, ff) +INSN(fmov_d, ff) +INSN(movgr2fr_w, fr) +INSN(movgr2fr_d, fr) +INSN(movgr2frh_w, fr) +INSN(movfr2gr_s, rf) +INSN(movfr2gr_d, rf) +INSN(movfrh2gr_s, rf) +INSN(movgr2fcsr, fcsrd_r) +INSN(movfcsr2gr, r_fcsrs) +INSN(movfr2cf, cf) +INSN(movcf2fr, fc) +INSN(movgr2cf, cr) +INSN(movcf2gr, rc) +INSN(fcvt_s_d, ff) +INSN(fcvt_d_s, ff) +INSN(ftintrm_w_s, ff) +INSN(ftintrm_w_d, ff) +INSN(ftintrm_l_s, ff) +INSN(ftintrm_l_d, ff) +INSN(ftintrp_w_s, ff) +INSN(ftintrp_w_d, ff) +INSN(ftintrp_l_s, ff) +INSN(ftintrp_l_d, ff) +INSN(ftintrz_w_s, ff) +INSN(ftintrz_w_d, ff) +INSN(ftintrz_l_s, ff) +INSN(ftintrz_l_d, ff) +INSN(ftintrne_w_s, ff) +INSN(ftintrne_w_d, ff) +INSN(ftintrne_l_s, ff) +INSN(ftintrne_l_d, ff) +INSN(ftint_w_s, ff) +INSN(ftint_w_d, ff) +INSN(ftint_l_s, ff) +INSN(ftint_l_d, ff) +INSN(ffint_s_w, ff) +INSN(ffint_s_l, ff) +INSN(ffint_d_w, ff) +INSN(ffint_d_l, ff) +INSN(frint_s, ff) +INSN(frint_d, ff) +INSN(slti, rr_i) +INSN(sltui, rr_i) +INSN(addi_w, rr_i) +INSN(addi_d, rr_i) +INSN(lu52i_d, rr_i) +INSN(andi, rr_i) +INSN(ori, rr_i) +INSN(xori, rr_i) +INSN(fmadd_s, ffff) +INSN(fmadd_d, ffff) +INSN(fmsub_s, ffff) +INSN(fmsub_d, ffff) +INSN(fnmadd_s, ffff) +INSN(fnmadd_d, ffff) +INSN(fnmsub_s, ffff) +INSN(fnmsub_d, ffff) +INSN(fsel, fffc) +INSN(addu16i_d, rr_i) +INSN(lu12i_w, r_i) +INSN(lu32i_d, r_i) +INSN(pcaddi, r_i) +INSN(pcalau12i, r_i) +INSN(pcaddu12i, r_i) +INSN(pcaddu18i, r_i) +INSN(ll_w, rr_i) +INSN(sc_w, rr_i) +INSN(ll_d, rr_i) +INSN(sc_d, rr_i) +INSN(ldptr_w, rr_i) +INSN(stptr_w, rr_i) +INSN(ldptr_d, rr_i) +INSN(stptr_d, rr_i) +INSN(ld_b, rr_i) +INSN(ld_h, rr_i) +INSN(ld_w, rr_i) +INSN(ld_d, rr_i) +INSN(st_b, rr_i) +INSN(st_h, rr_i) +INSN(st_w, rr_i) +INSN(st_d, rr_i) +INSN(ld_bu, rr_i) +INSN(ld_hu, rr_i) +INSN(ld_wu, rr_i) +INSN(preld, hint_r_i) +INSN(fld_s, fr_i) +INSN(fst_s, fr_i) +INSN(fld_d, fr_i) +INSN(fst_d, fr_i) +INSN(ldx_b, rrr) +INSN(ldx_h, rrr) +INSN(ldx_w, rrr) +INSN(ldx_d, rrr) +INSN(stx_b, rrr) +INSN(stx_h, rrr) +INSN(stx_w, rrr) +INSN(stx_d, rrr) +INSN(ldx_bu, rrr) +INSN(ldx_hu, rrr) +INSN(ldx_wu, rrr) +INSN(fldx_s, frr) +INSN(fldx_d, frr) +INSN(fstx_s, frr) +INSN(fstx_d, frr) +INSN(amswap_w, rrr) +INSN(amswap_d, rrr) +INSN(amadd_w, rrr) +INSN(amadd_d, rrr) +INSN(amand_w, rrr) +INSN(amand_d, rrr) +INSN(amor_w, rrr) +INSN(amor_d, rrr) +INSN(amxor_w, rrr) +INSN(amxor_d, rrr) +INSN(ammax_w, rrr) +INSN(ammax_d, rrr) +INSN(ammin_w, rrr) +INSN(ammin_d, rrr) +INSN(ammax_wu, rrr) +INSN(ammax_du, rrr) +INSN(ammin_wu, rrr) +INSN(ammin_du, rrr) +INSN(amswap_db_w, rrr) +INSN(amswap_db_d, rrr) +INSN(amadd_db_w, rrr) +INSN(amadd_db_d, rrr) +INSN(amand_db_w, rrr) +INSN(amand_db_d, rrr) +INSN(amor_db_w, rrr) +INSN(amor_db_d, rrr) +INSN(amxor_db_w, rrr) +INSN(amxor_db_d, rrr) +INSN(ammax_db_w, rrr) +INSN(ammax_db_d, rrr) +INSN(ammin_db_w, rrr) +INSN(ammin_db_d, rrr) +INSN(ammax_db_wu, rrr) +INSN(ammax_db_du, rrr) +INSN(ammin_db_wu, rrr) +INSN(ammin_db_du, rrr) +INSN(dbar, i) +INSN(ibar, i) +INSN(fldgt_s, frr) +INSN(fldgt_d, frr) +INSN(fldle_s, frr) +INSN(fldle_d, frr) +INSN(fstgt_s, frr) +INSN(fstgt_d, frr) +INSN(fstle_s, frr) +INSN(fstle_d, frr) +INSN(ldgt_b, rrr) +INSN(ldgt_h, rrr) +INSN(ldgt_w, rrr) +INSN(ldgt_d, rrr) +INSN(ldle_b, rrr) +INSN(ldle_h, rrr) +INSN(ldle_w, rrr) +INSN(ldle_d, rrr) +INSN(stgt_b, rrr) +INSN(stgt_h, rrr) +INSN(stgt_w, rrr) +INSN(stgt_d, rrr) +INSN(stle_b, rrr) +INSN(stle_h, rrr) +INSN(stle_w, rrr) +INSN(stle_d, rrr) +INSN(beqz, r_offs) +INSN(bnez, r_offs) +INSN(bceqz, c_offs) +INSN(bcnez, c_offs) +INSN(jirl, rr_offs) +INSN(b, offs) +INSN(bl, offs) +INSN(beq, rr_offs) +INSN(bne, rr_offs) +INSN(blt, rr_offs) +INSN(bge, rr_offs) +INSN(bltu, rr_offs) +INSN(bgeu, rr_offs) +INSN(csrrd, r_csr) +INSN(csrwr, r_csr) +INSN(csrxchg, rr_csr) +INSN(iocsrrd_b, rr) +INSN(iocsrrd_h, rr) +INSN(iocsrrd_w, rr) +INSN(iocsrrd_d, rr) +INSN(iocsrwr_b, rr) +INSN(iocsrwr_h, rr) +INSN(iocsrwr_w, rr) +INSN(iocsrwr_d, rr) +INSN(tlbsrch, empty) +INSN(tlbrd, empty) +INSN(tlbwr, empty) +INSN(tlbfill, empty) +INSN(tlbclr, empty) +INSN(tlbflush, empty) +INSN(invtlb, i_rr) +INSN(cacop, cop_r_i) +INSN(lddir, rr_i) +INSN(ldpte, j_i) +INSN(ertn, empty) +INSN(idle, i) +INSN(dbcl, i) + +#define output_fcmp(C, PREFIX, SUFFIX) \ +{ \ + (C)->info->fprintf_func((C)->info->stream, "%08x %s%s\tfcc%d, f%d, f%d", \ + (C)->insn, PREFIX, SUFFIX, a->cd, \ + a->fj, a->fk); \ +} + +static bool output_cff_fcond(DisasContext *ctx, arg_cff_fcond * a, + const char *suffix) +{ + bool ret = true; + switch (a->fcond) { + case 0x0: + output_fcmp(ctx, "fcmp_caf_", suffix); + break; + case 0x1: + output_fcmp(ctx, "fcmp_saf_", suffix); + break; + case 0x2: + output_fcmp(ctx, "fcmp_clt_", suffix); + break; + case 0x3: + output_fcmp(ctx, "fcmp_slt_", suffix); + break; + case 0x4: + output_fcmp(ctx, "fcmp_ceq_", suffix); + break; + case 0x5: + output_fcmp(ctx, "fcmp_seq_", suffix); + break; + case 0x6: + output_fcmp(ctx, "fcmp_cle_", suffix); + break; + case 0x7: + output_fcmp(ctx, "fcmp_sle_", suffix); + break; + case 0x8: + output_fcmp(ctx, "fcmp_cun_", suffix); + break; + case 0x9: + output_fcmp(ctx, "fcmp_sun_", suffix); + break; + case 0xA: + output_fcmp(ctx, "fcmp_cult_", suffix); + break; + case 0xB: + output_fcmp(ctx, "fcmp_sult_", suffix); + break; + case 0xC: + output_fcmp(ctx, "fcmp_cueq_", suffix); + break; + case 0xD: + output_fcmp(ctx, "fcmp_sueq_", suffix); + break; + case 0xE: + output_fcmp(ctx, "fcmp_cule_", suffix); + break; + case 0xF: + output_fcmp(ctx, "fcmp_sule_", suffix); + break; + case 0x10: + output_fcmp(ctx, "fcmp_cne_", suffix); + break; + case 0x11: + output_fcmp(ctx, "fcmp_sne_", suffix); + break; + case 0x14: + output_fcmp(ctx, "fcmp_cor_", suffix); + break; + case 0x15: + output_fcmp(ctx, "fcmp_sor_", suffix); + break; + case 0x18: + output_fcmp(ctx, "fcmp_cune_", suffix); + break; + case 0x19: + output_fcmp(ctx, "fcmp_sune_", suffix); + break; + default: + ret = false; + } + return ret; +} + +#define FCMP_INSN(suffix) \ +static bool trans_fcmp_cond_##suffix(DisasContext *ctx, \ + arg_cff_fcond * a) \ +{ \ + return output_cff_fcond(ctx, a, #suffix); \ +} + +FCMP_INSN(s) +FCMP_INSN(d) diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c new file mode 100644 index 000000000000..4b9637210a95 --- /dev/null +++ b/target/loongarch/fpu_helper.c @@ -0,0 +1,879 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch float point emulation helpers for QEMU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "fpu/softfloat.h" +#include "internals.h" + +static inline uint64_t nanbox_s(float32 fp) +{ + return fp | MAKE_64BIT_MASK(32, 32); +} + +/* Convert loongarch rounding mode in fcsr0 to IEEE library */ +static const FloatRoundMode ieee_rm[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +void restore_fp_status(CPULoongArchState *env) +{ + set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], + &env->fp_status); + set_flush_to_zero(0, &env->fp_status); +} + +static int ieee_ex_to_loongarch(int xcpt) +{ + int ret = 0; + if (xcpt & float_flag_invalid) { + ret |= FP_INVALID; + } + if (xcpt & float_flag_overflow) { + ret |= FP_OVERFLOW; + } + if (xcpt & float_flag_underflow) { + ret |= FP_UNDERFLOW; + } + if (xcpt & float_flag_divbyzero) { + ret |= FP_DIV0; + } + if (xcpt & float_flag_inexact) { + ret |= FP_INEXACT; + } + return ret; +} + +static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask) +{ + int flags = get_float_exception_flags(&env->fp_status); + + set_float_exception_flags(0, &env->fp_status); + + flags &= ~mask; + + if (!flags) { + SET_FP_CAUSE(env->fcsr0, flags); + return; + } else { + flags = ieee_ex_to_loongarch(flags); + SET_FP_CAUSE(env->fcsr0, flags); + } + + if (GET_FP_ENABLES(env->fcsr0) & flags) { + do_raise_exception(env, EXCCODE_FPE, pc); + } else { + UPDATE_FP_FLAGS(env->fcsr0, flags); + } +} + +static void update_fcsr0(CPULoongArchState *env, uintptr_t pc) +{ + update_fcsr0_mask(env, pc, 0); +} + +uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_add(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_sub(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_mul(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_div(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_maxnum(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_minnum(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_maxnummag((uint32_t)fj, + (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_maxnummag(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_minnummag((uint32_t)fj, + (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_minnummag(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + int32_t n = (int32_t)fk; + + fd = nanbox_s(float32_scalbn((uint32_t)fj, + n > 0x200 ? 0x200 : + n < -0x200 ? -0x200 : n, + &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + int64_t n = (int64_t)fk; + + fd = float64_scalbn(fj, + n > 0x1000 ? 0x1000 : + n < -0x1000 ? -0x1000 : n, + &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_sqrt(fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_div(float64_one, fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + uint32_t fp; + + fp = float32_sqrt((uint32_t)fj, &env->fp_status); + fd = nanbox_s(float32_div(float32_one, fp, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fp, fd; + + fp = float64_sqrt(fj, &env->fp_status); + fd = float64_div(float64_one, fp, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + uint32_t fp; + float_status *status = &env->fp_status; + FloatRoundMode old_mode = get_float_rounding_mode(status); + + set_float_rounding_mode(float_round_down, status); + fp = float32_log2((uint32_t)fj, status); + fd = nanbox_s(float32_round_to_int(fp, status)); + set_float_rounding_mode(old_mode, status); + update_fcsr0_mask(env, GETPC(), float_flag_inexact); + return fd; +} + +uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + float_status *status = &env->fp_status; + FloatRoundMode old_mode = get_float_rounding_mode(status); + + set_float_rounding_mode(float_round_down, status); + fd = float64_log2(fj, status); + fd = float64_round_to_int(fd, status); + set_float_rounding_mode(old_mode, status); + update_fcsr0_mask(env, GETPC(), float_flag_inexact); + return fd; +} + +uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj) +{ + float32 f = fj; + bool sign = float32_is_neg(f); + + if (float32_is_infinity(f)) { + return sign ? 1 << 2 : 1 << 6; + } else if (float32_is_zero(f)) { + return sign ? 1 << 5 : 1 << 9; + } else if (float32_is_zero_or_denormal(f)) { + return sign ? 1 << 4 : 1 << 8; + } else if (float32_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; + } else { + return sign ? 1 << 3 : 1 << 7; + } +} + +uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj) +{ + float64 f = fj; + bool sign = float64_is_neg(f); + + if (float64_is_infinity(f)) { + return sign ? 1 << 2 : 1 << 6; + } else if (float64_is_zero(f)) { + return sign ? 1 << 5 : 1 << 9; + } else if (float64_is_zero_or_denormal(f)) { + return sign ? 1 << 4 : 1 << 8; + } else if (float64_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; + } else { + return sign ? 1 << 3 : 1 << 7; + } +} + +uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint64_t fa, uint32_t flag) +{ + uint64_t fd; + + fd = nanbox_s(float32_muladd((uint32_t)fj, (uint32_t)fk, + (uint32_t)fa, flag, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint64_t fa, uint32_t flag) +{ + uint64_t fd; + + fd = float64_muladd(fj, fk, fa, flag, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +static uint64_t fcmp_common(CPULoongArchState *env, FloatRelation cmp, + uint32_t flags) +{ + bool ret; + + switch (cmp) { + case float_relation_less: + ret = (flags & FCMP_LT); + break; + case float_relation_equal: + ret = (flags & FCMP_EQ); + break; + case float_relation_greater: + ret = (flags & FCMP_GT); + break; + case float_relation_unordered: + ret = (flags & FCMP_UN); + break; + default: + g_assert_not_reached(); + } + update_fcsr0(env, GETPC()); + + return ret; +} + +/* fcmp_cXXX_s */ +uint64_t helper_fcmp_c_s(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float32_compare_quiet((uint32_t)fj, + (uint32_t)fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* fcmp_sXXX_s */ +uint64_t helper_fcmp_s_s(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float32_compare((uint32_t)fj, + (uint32_t)fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* fcmp_cXXX_d */ +uint64_t helper_fcmp_c_d(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float64_compare_quiet(fj, fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* fcmp_sXXX_d */ +uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float64_compare(fj, fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* floating point conversion */ +uint64_t helper_fcvt_s_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(float64_to_float32(fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fcvt_d_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float32_to_float64((uint32_t)fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_s_w(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(int32_to_float32((int32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_s_l(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(int64_to_float32(fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_d_w(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = int32_to_float64((int32_t)fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_d_l(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = int64_to_float64(fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frint_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = (uint64_t)(float32_round_to_int((uint32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frint_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_round_to_int(fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = float64_to_int64(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = float64_to_int64(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = float64_to_int64_round_to_zero(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = float32_to_int64_round_to_zero((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = (uint64_t)float64_to_int32_round_to_zero(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint32_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = float32_to_int32_round_to_zero((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return (uint64_t)fd; +} + +uint64_t helper_ftintrne_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = float64_to_int64(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrne_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrne_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrne_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint32_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = float32_to_int32((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return (uint64_t)fd; +} + +uint64_t helper_ftint_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_to_int64(fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftint_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftint_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float32_is_any_nan((uint32_t)fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { + if (float64_is_any_nan(fj)) { + fd = 0; + } + } + update_fcsr0(env, GETPC()); + return fd; +} + +void helper_set_rounding_mode(CPULoongArchState *env) +{ + 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 new file mode 100644 index 000000000000..a4d1e28e3648 --- /dev/null +++ b/target/loongarch/gdbstub.c @@ -0,0 +1,104 @@ +/* + * LOONGARCH gdb server stub + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#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); + CPULoongArchState *env = &cpu->env; + + if (0 <= n && n < 32) { + return gdb_get_regl(mem_buf, env->gpr[n]); + } else if (n == 32) { + /* 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; +} + +int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + target_ulong tmp = ldtul_p(mem_buf); + int length = 0; + + if (0 <= n && n < 32) { + env->gpr[n] = tmp; + length = sizeof(target_ulong); + } else if (n == 33) { + env->pc = tmp; + length = sizeof(target_ulong); + } + return length; +} + +static int loongarch_gdb_get_fpu(CPULoongArchState *env, + GByteArray *mem_buf, int n) +{ + if (0 <= n && n < 32) { + return gdb_get_reg64(mem_buf, env->fpr[n]); + } 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; +} + +static int loongarch_gdb_set_fpu(CPULoongArchState *env, + uint8_t *mem_buf, int n) +{ + int length = 0; + + if (0 <= n && n < 32) { + env->fpr[n] = ldq_p(mem_buf); + length = 8; + } 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; + } + return length; +} + +void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) +{ + gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, + 41, "loongarch-fpu.xml", 0); +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h new file mode 100644 index 000000000000..9c01823a26bb --- /dev/null +++ b/target/loongarch/helper.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +DEF_HELPER_2(raise_exception, noreturn, env, i32) + +DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) + +DEF_HELPER_FLAGS_3(asrtle_d, TCG_CALL_NO_WG, void, env, tl, tl) +DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) + +DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl) + +/* Floating-point helper */ +DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxa_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxa_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmina_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmina_d, TCG_CALL_NO_WG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_5(fmuladd_s, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) +DEF_HELPER_FLAGS_5(fmuladd_d, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) + +DEF_HELPER_FLAGS_3(fscaleb_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fscaleb_d, TCG_CALL_NO_WG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_2(flogb_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(flogb_d, TCG_CALL_NO_WG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_d, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_d, TCG_CALL_NO_WG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64) +DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64) + +/* fcmp.cXXX.s */ +DEF_HELPER_4(fcmp_c_s, i64, env, i64, i64, i32) +/* fcmp.sXXX.s */ +DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32) +/* fcmp.cXXX.d */ +DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32) +/* fcmp.sXXX.d */ +DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32) + +DEF_HELPER_2(fcvt_d_s, i64, env, i64) +DEF_HELPER_2(fcvt_s_d, i64, env, i64) +DEF_HELPER_2(ffint_d_w, i64, env, i64) +DEF_HELPER_2(ffint_d_l, i64, env, i64) +DEF_HELPER_2(ffint_s_w, i64, env, i64) +DEF_HELPER_2(ffint_s_l, i64, env, i64) +DEF_HELPER_2(ftintrm_l_s, i64, env, i64) +DEF_HELPER_2(ftintrm_l_d, i64, env, i64) +DEF_HELPER_2(ftintrm_w_s, i64, env, i64) +DEF_HELPER_2(ftintrm_w_d, i64, env, i64) +DEF_HELPER_2(ftintrp_l_s, i64, env, i64) +DEF_HELPER_2(ftintrp_l_d, i64, env, i64) +DEF_HELPER_2(ftintrp_w_s, i64, env, i64) +DEF_HELPER_2(ftintrp_w_d, i64, env, i64) +DEF_HELPER_2(ftintrz_l_s, i64, env, i64) +DEF_HELPER_2(ftintrz_l_d, i64, env, i64) +DEF_HELPER_2(ftintrz_w_s, i64, env, i64) +DEF_HELPER_2(ftintrz_w_d, i64, env, i64) +DEF_HELPER_2(ftintrne_l_s, i64, env, i64) +DEF_HELPER_2(ftintrne_l_d, i64, env, i64) +DEF_HELPER_2(ftintrne_w_s, i64, env, i64) +DEF_HELPER_2(ftintrne_w_d, i64, env, i64) +DEF_HELPER_2(ftint_l_s, i64, env, i64) +DEF_HELPER_2(ftint_l_d, i64, env, i64) +DEF_HELPER_2(ftint_w_s, i64, env, i64) +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_1(set_rounding_mode, TCG_CALL_NO_RWG, void, env) + +DEF_HELPER_1(rdtime_d, i64, env) + +#ifndef CONFIG_USER_ONLY +/* CSRs helper */ +DEF_HELPER_1(csrrd_pgd, i64, env) +DEF_HELPER_1(csrrd_tval, i64, env) +DEF_HELPER_2(csrwr_estat, i64, env, tl) +DEF_HELPER_2(csrwr_asid, i64, env, tl) +DEF_HELPER_2(csrwr_tcfg, i64, env, tl) +DEF_HELPER_2(csrwr_ticlr, i64, env, tl) +DEF_HELPER_2(iocsrrd_b, i64, env, tl) +DEF_HELPER_2(iocsrrd_h, i64, env, tl) +DEF_HELPER_2(iocsrrd_w, i64, env, tl) +DEF_HELPER_2(iocsrrd_d, i64, env, tl) +DEF_HELPER_3(iocsrwr_b, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_h, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_w, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_d, void, env, tl, tl) + +/* TLB helper */ +DEF_HELPER_1(tlbwr, void, env) +DEF_HELPER_1(tlbfill, void, env) +DEF_HELPER_1(tlbsrch, void, env) +DEF_HELPER_1(tlbrd, void, env) +DEF_HELPER_1(tlbclr, void, env) +DEF_HELPER_1(tlbflush, void, env) +DEF_HELPER_1(invtlb_all, void, env) +DEF_HELPER_2(invtlb_all_g, void, env, i32) +DEF_HELPER_2(invtlb_all_asid, void, env, tl) +DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl) +DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl) + +DEF_HELPER_4(lddir, tl, env, tl, tl, i32) +DEF_HELPER_4(ldpte, void, env, tl, tl, i32) +DEF_HELPER_1(ertn, void, env) +DEF_HELPER_1(idle, void, env) +#endif diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/insn_trans/trans_arith.c.inc new file mode 100644 index 000000000000..8e45eadbc8aa --- /dev/null +++ b/target/loongarch/insn_trans/trans_arith.c.inc @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_rrr(DisasContext *ctx, arg_rrr *a, + DisasExtend src1_ext, DisasExtend src2_ext, + DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src1_ext); + TCGv src2 = gpr_src(ctx, a->rk, src2_ext); + + func(dest, src1, src2); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool gen_rri_v(DisasContext *ctx, arg_rr_i *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + TCGv src2 = tcg_constant_tl(a->imm); + + func(dest, src1, src2); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool gen_rri_c(DisasContext *ctx, arg_rr_i *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, target_long)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + + func(dest, src1, a->imm); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool gen_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, TCGv, target_long)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + TCGv src2 = gpr_src(ctx, a->rk, src_ext); + + func(dest, src1, src2, a->sa); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + tcg_gen_movi_tl(dest, a->imm << 12); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_pc(DisasContext *ctx, arg_r_i *a, + target_ulong (*func)(target_ulong, int)) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + target_ulong addr = func(ctx->base.pc_next, a->imm); + + tcg_gen_movi_tl(dest, addr); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static void gen_slt(TCGv dest, TCGv src1, TCGv src2) +{ + tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2); +} + +static void gen_sltu(TCGv dest, TCGv src1, TCGv src2) +{ + tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2); +} + +static void gen_mulh_w(TCGv dest, TCGv src1, TCGv src2) +{ + tcg_gen_mul_i64(dest, src1, src2); + tcg_gen_sari_i64(dest, dest, 32); +} + +static void gen_mulh_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv discard = tcg_temp_new(); + tcg_gen_muls2_tl(discard, dest, src1, src2); + tcg_temp_free(discard); +} + +static void gen_mulh_du(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv discard = tcg_temp_new(); + tcg_gen_mulu2_tl(discard, dest, src1, src2); + tcg_temp_free(discard); +} + +static void prep_divisor_d(TCGv ret, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv zero = tcg_constant_tl(0); + + /* + * If min / -1, set the divisor to 1. + * This avoids potential host overflow trap and produces min. + * If x / 0, set the divisor to 1. + * This avoids potential host overflow trap; + * the required result is undefined. + */ + tcg_gen_setcondi_tl(TCG_COND_EQ, ret, src1, INT64_MIN); + tcg_gen_setcondi_tl(TCG_COND_EQ, t0, src2, -1); + tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src2, 0); + tcg_gen_and_tl(ret, ret, t0); + tcg_gen_or_tl(ret, ret, t1); + tcg_gen_movcond_tl(TCG_COND_NE, ret, ret, zero, ret, src2); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void prep_divisor_du(TCGv ret, TCGv src2) +{ + TCGv zero = tcg_constant_tl(0); + TCGv one = tcg_constant_tl(1); + + /* + * If x / 0, set the divisor to 1. + * This avoids potential host overflow trap; + * the required result is undefined. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, ret, src2, zero, one, src2); +} + +static void gen_div_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_d(t0, src1, src2); + tcg_gen_div_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rem_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_d(t0, src1, src2); + tcg_gen_rem_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_div_du(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_du(t0, src2); + tcg_gen_divu_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rem_du(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_du(t0, src2); + tcg_gen_remu_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_div_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + /* We need not check for integer overflow for div_w. */ + prep_divisor_du(t0, src2); + tcg_gen_div_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rem_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + /* We need not check for integer overflow for rem_w. */ + prep_divisor_du(t0, src2); + tcg_gen_rem_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_alsl(TCGv dest, TCGv src1, TCGv src2, target_long sa) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_shli_tl(t0, src1, sa); + tcg_gen_add_tl(dest, t0, src2); + tcg_temp_free(t0); +} + +static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src2 = tcg_constant_tl(a->imm); + + tcg_gen_deposit_tl(dest, src1, src2, 32, 32); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = tcg_constant_tl(a->imm); + + tcg_gen_deposit_tl(dest, src1, src2, 52, 12); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static target_ulong gen_pcaddi(target_ulong pc, int imm) +{ + return pc + (imm << 2); +} + +static target_ulong gen_pcalau12i(target_ulong pc, int imm) +{ + return (pc + (imm << 12)) & ~0xfff; +} + +static target_ulong gen_pcaddu12i(target_ulong pc, int imm) +{ + return pc + (imm << 12); +} + +static target_ulong gen_pcaddu18i(target_ulong pc, int imm) +{ + return pc + ((target_ulong)(imm) << 18); +} + +static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + tcg_gen_addi_tl(dest, src1, a->imm << 16); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +TRANS(add_w, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) +TRANS(add_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) +TRANS(sub_w, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) +TRANS(sub_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) +TRANS(and, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) +TRANS(or, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) +TRANS(xor, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) +TRANS(nor, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) +TRANS(andn, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) +TRANS(orn, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) +TRANS(slt, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) +TRANS(sltu, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) +TRANS(mul_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) +TRANS(mul_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulh_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) +TRANS(mulh_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) +TRANS(mulh_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) +TRANS(mulh_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) +TRANS(mulw_d_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulw_d_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) +TRANS(div_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) +TRANS(mod_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) +TRANS(div_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) +TRANS(mod_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) +TRANS(div_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) +TRANS(mod_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) +TRANS(div_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) +TRANS(mod_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) +TRANS(slti, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) +TRANS(sltui, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) +TRANS(addi_w, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) +TRANS(addi_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) +TRANS(alsl_w, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) +TRANS(alsl_wu, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) +TRANS(alsl_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) +TRANS(pcaddi, gen_pc, gen_pcaddi) +TRANS(pcalau12i, gen_pc, gen_pcalau12i) +TRANS(pcaddu12i, gen_pc, gen_pcaddu12i) +TRANS(pcaddu18i, gen_pc, gen_pcaddu18i) +TRANS(andi, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) +TRANS(ori, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) +TRANS(xori, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc new file mode 100644 index 000000000000..6763c1c301f7 --- /dev/null +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv t0 = tcg_temp_new(); + + tcg_gen_addi_tl(t0, src1, a->imm); + tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPULoongArchState, lladdr)); + tcg_gen_st_tl(dest, cpu_env, offsetof(CPULoongArchState, llval)); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free(t0); + + return true; +} + +static bool gen_sc(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); + TCGv t0 = tcg_temp_new(); + TCGv val = tcg_temp_new(); + + TCGLabel *l1 = gen_new_label(); + TCGLabel *done = gen_new_label(); + + tcg_gen_addi_tl(t0, src1, a->imm); + tcg_gen_brcond_tl(TCG_COND_EQ, t0, cpu_lladdr, l1); + tcg_gen_movi_tl(dest, 0); + tcg_gen_br(done); + + gen_set_label(l1); + tcg_gen_mov_tl(val, src2); + /* generate cmpxchg */ + tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, + val, ctx->mem_idx, mop); + tcg_gen_setcond_tl(TCG_COND_EQ, dest, t0, cpu_llval); + gen_set_label(done); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free(t0); + tcg_temp_free(val); + + return true; +} + +static bool gen_am(DisasContext *ctx, arg_rrr *a, + void (*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), + MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv val = gpr_src(ctx, a->rk, EXT_NONE); + + if (a->rd != 0 && (a->rj == a->rd || a->rk == a->rd)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Warning: source register overlaps destination register" + "in atomic insn at pc=0x" TARGET_FMT_lx "\n", + ctx->base.pc_next - 4); + return false; + } + + func(dest, addr, val, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +TRANS(ll_w, gen_ll, MO_TESL) +TRANS(sc_w, gen_sc, MO_TESL) +TRANS(ll_d, gen_ll, MO_TEUQ) +TRANS(sc_d, gen_sc, MO_TEUQ) +TRANS(amswap_w, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_d, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_w, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_d, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_w, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_d, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_w, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_d, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_w, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_d, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_w, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_d, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_w, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_d, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_wu, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_du, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_wu, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_du, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(amswap_db_w, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_db_d, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_db_w, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_db_d, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_db_w, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_db_d, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_db_w, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_db_d, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_db_w, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_db_d, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_db_w, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_db_d, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_db_w, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_db_d, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_db_wu, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_db_du, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_db_wu, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_db_du, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_bit.c.inc b/target/loongarch/insn_trans/trans_bit.c.inc new file mode 100644 index 000000000000..b01e4aeb2373 --- /dev/null +++ b/target/loongarch/insn_trans/trans_bit.c.inc @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_rr(DisasContext *ctx, arg_rr *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + + func(dest, src1); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static void gen_bytepick_w(TCGv dest, TCGv src1, TCGv src2, target_long sa) +{ + tcg_gen_concat_tl_i64(dest, src1, src2); + tcg_gen_sextract_i64(dest, dest, (32 - sa * 8), 32); +} + +static void gen_bytepick_d(TCGv dest, TCGv src1, TCGv src2, target_long sa) +{ + tcg_gen_extract2_i64(dest, src1, src2, (64 - sa * 8)); +} + +static bool gen_bstrins(DisasContext *ctx, arg_rr_ms_ls *a, + DisasExtend dst_ext) +{ + TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + if (a->ls > a->ms) { + return false; + } + + tcg_gen_deposit_tl(dest, src1, src2, a->ls, a->ms - a->ls + 1); + gen_set_gpr(a->rd, dest, dst_ext); + return true; +} + +static bool gen_bstrpick(DisasContext *ctx, arg_rr_ms_ls *a, + DisasExtend dst_ext) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + if (a->ls > a->ms) { + return false; + } + + tcg_gen_extract_tl(dest, src1, a->ls, a->ms - a->ls + 1); + gen_set_gpr(a->rd, dest, dst_ext); + return true; +} + +static void gen_clz_w(TCGv dest, TCGv src1) +{ + tcg_gen_clzi_tl(dest, src1, TARGET_LONG_BITS); + tcg_gen_subi_tl(dest, dest, TARGET_LONG_BITS - 32); +} + +static void gen_clo_w(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + tcg_gen_ext32u_tl(dest, dest); + gen_clz_w(dest, dest); +} + +static void gen_ctz_w(TCGv dest, TCGv src1) +{ + tcg_gen_ori_tl(dest, src1, (target_ulong)MAKE_64BIT_MASK(32, 32)); + tcg_gen_ctzi_tl(dest, dest, TARGET_LONG_BITS); +} + +static void gen_cto_w(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + gen_ctz_w(dest, dest); +} + +static void gen_clz_d(TCGv dest, TCGv src1) +{ + tcg_gen_clzi_i64(dest, src1, TARGET_LONG_BITS); +} + +static void gen_clo_d(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + gen_clz_d(dest, dest); +} + +static void gen_ctz_d(TCGv dest, TCGv src1) +{ + tcg_gen_ctzi_tl(dest, src1, TARGET_LONG_BITS); +} + +static void gen_cto_d(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + gen_ctz_d(dest, dest); +} + +static void gen_revb_2w(TCGv dest, TCGv src1) +{ + tcg_gen_bswap64_i64(dest, src1); + tcg_gen_rotri_i64(dest, dest, 32); +} + +static void gen_revb_2h(TCGv dest, TCGv src1) +{ + TCGv mask = tcg_constant_tl(0x00FF00FF); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t0, src1, 8); + tcg_gen_and_tl(t0, t0, mask); + tcg_gen_and_tl(t1, src1, mask); + tcg_gen_shli_tl(t1, t1, 8); + tcg_gen_or_tl(dest, t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_revb_4h(TCGv dest, TCGv src1) +{ + TCGv mask = tcg_constant_tl(0x00FF00FF00FF00FFULL); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t0, src1, 8); + tcg_gen_and_tl(t0, t0, mask); + tcg_gen_and_tl(t1, src1, mask); + tcg_gen_shli_tl(t1, t1, 8); + tcg_gen_or_tl(dest, t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_revh_2w(TCGv dest, TCGv src1) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 mask = tcg_constant_i64(0x0000ffff0000ffffull); + + tcg_gen_shri_i64(t0, src1, 16); + tcg_gen_and_i64(t1, src1, mask); + tcg_gen_and_i64(t0, t0, mask); + tcg_gen_shli_i64(t1, t1, 16); + tcg_gen_or_i64(dest, t1, t0); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +static void gen_revh_d(TCGv dest, TCGv src1) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv mask = tcg_constant_tl(0x0000FFFF0000FFFFULL); + + tcg_gen_shri_tl(t1, src1, 16); + tcg_gen_and_tl(t1, t1, mask); + tcg_gen_and_tl(t0, src1, mask); + tcg_gen_shli_tl(t0, t0, 16); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_rotri_tl(dest, t0, 32); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_maskeqz(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv zero = tcg_constant_tl(0); + + tcg_gen_movcond_tl(TCG_COND_EQ, dest, src2, zero, zero, src1); +} + +static void gen_masknez(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv zero = tcg_constant_tl(0); + + tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, zero, zero, src1); +} + +TRANS(ext_w_h, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) +TRANS(ext_w_b, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) +TRANS(clo_w, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) +TRANS(clz_w, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) +TRANS(cto_w, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) +TRANS(ctz_w, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) +TRANS(clo_d, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) +TRANS(clz_d, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) +TRANS(cto_d, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) +TRANS(ctz_d, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) +TRANS(revb_2h, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) +TRANS(revb_4h, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) +TRANS(revb_2w, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) +TRANS(revb_d, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) +TRANS(revh_2w, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) +TRANS(revh_d, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) +TRANS(bitrev_4b, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) +TRANS(bitrev_8b, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) +TRANS(bitrev_w, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) +TRANS(bitrev_d, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) +TRANS(maskeqz, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) +TRANS(masknez, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) +TRANS(bytepick_w, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) +TRANS(bytepick_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) +TRANS(bstrins_w, gen_bstrins, EXT_SIGN) +TRANS(bstrins_d, gen_bstrins, EXT_NONE) +TRANS(bstrpick_w, gen_bstrpick, EXT_SIGN) +TRANS(bstrpick_d, gen_bstrpick, EXT_NONE) diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc new file mode 100644 index 000000000000..65dbdff41eed --- /dev/null +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool trans_b(DisasContext *ctx, arg_b *a) +{ + gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool trans_bl(DisasContext *ctx, arg_bl *a) +{ + tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); + gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool trans_jirl(DisasContext *ctx, arg_jirl *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + tcg_gen_addi_tl(cpu_pc, src1, a->offs); + tcg_gen_movi_tl(dest, ctx->base.pc_next + 4); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_gen_lookup_and_goto_ptr(); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static void gen_bc(DisasContext *ctx, TCGv src1, TCGv src2, + target_long offs, TCGCond cond) +{ + TCGLabel *l = gen_new_label(); + tcg_gen_brcond_tl(cond, src1, src2, l); + gen_goto_tb(ctx, 1, ctx->base.pc_next + 4); + gen_set_label(l); + gen_goto_tb(ctx, 0, ctx->base.pc_next + offs); + ctx->base.is_jmp = DISAS_NORETURN; +} + +static bool gen_rr_bc(DisasContext *ctx, arg_rr_offs *a, TCGCond cond) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); + + gen_bc(ctx, src1, src2, a->offs, cond); + return true; +} + +static bool gen_rz_bc(DisasContext *ctx, arg_r_offs *a, TCGCond cond) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = tcg_constant_tl(0); + + gen_bc(ctx, src1, src2, a->offs, cond); + return true; +} + +static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) +{ + TCGv src1 = tcg_temp_new(); + TCGv src2 = tcg_constant_tl(0); + + tcg_gen_ld8u_tl(src1, cpu_env, + offsetof(CPULoongArchState, cf[a->cj])); + gen_bc(ctx, src1, src2, a->offs, cond); + return true; +} + +TRANS(beq, gen_rr_bc, TCG_COND_EQ) +TRANS(bne, gen_rr_bc, TCG_COND_NE) +TRANS(blt, gen_rr_bc, TCG_COND_LT) +TRANS(bge, gen_rr_bc, TCG_COND_GE) +TRANS(bltu, gen_rr_bc, TCG_COND_LTU) +TRANS(bgeu, gen_rr_bc, TCG_COND_GEU) +TRANS(beqz, gen_rz_bc, TCG_COND_EQ) +TRANS(bnez, gen_rz_bc, TCG_COND_NE) +TRANS(bceqz, gen_cz_bc, TCG_COND_EQ) +TRANS(bcnez, gen_cz_bc, TCG_COND_NE) diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc new file mode 100644 index 000000000000..ad713cd61e7b --- /dev/null +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool trans_break(DisasContext *ctx, arg_break *a) +{ + generate_exception(ctx, EXCCODE_BRK); + return true; +} + +static bool trans_syscall(DisasContext *ctx, arg_syscall *a) +{ + generate_exception(ctx, EXCCODE_SYS); + return true; +} + +static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtle_d(cpu_env, src1, src2); + return true; +} + +static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + return true; +} + +static bool gen_rdtime(DisasContext *ctx, arg_rr *a, + bool word, bool high) +{ + TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE); + + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_rdtime_d(dst1, cpu_env); + if (word) { + tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32); + } + tcg_gen_ld_i64(dst2, cpu_env, offsetof(CPULoongArchState, CSR_TID)); + + return true; +} + +static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a) +{ + return gen_rdtime(ctx, a, 1, 0); +} + +static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a) +{ + return gen_rdtime(ctx, a, 1, 1); +} + +static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) +{ + return gen_rdtime(ctx, a, 0, 0); +} + +static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + gen_helper_cpucfg(dest, cpu_env, src1); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_crc(DisasContext *ctx, arg_rrr *a, + void (*func)(TCGv, TCGv, TCGv, TCGv), + TCGv tsz) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_SIGN); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + func(dest, src2, src1, tsz); + gen_set_gpr(a->rd, dest, EXT_SIGN); + + return true; +} + +TRANS(crc_w_b_w, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) +TRANS(crc_w_h_w, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) +TRANS(crc_w_w_w, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) +TRANS(crc_w_d_w, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) +TRANS(crcc_w_b_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) +TRANS(crcc_w_h_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) +TRANS(crcc_w_w_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) +TRANS(crcc_w_d_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/insn_trans/trans_farith.c.inc new file mode 100644 index 000000000000..7081fbb89bbc --- /dev/null +++ b/target/loongarch/insn_trans/trans_farith.c.inc @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef CONFIG_USER_ONLY +#define CHECK_FPE do { \ + if ((ctx->base.tb->flags & HW_FLAGS_EUEN_FPE) == 0) { \ + generate_exception(ctx, EXCCODE_FPD); \ + return true; \ + } \ +} while (0) +#else +#define CHECK_FPE +#endif + +static bool gen_fff(DisasContext *ctx, arg_fff *a, + void (*func)(TCGv, TCGv_env, TCGv, TCGv)) +{ + CHECK_FPE; + + func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk]); + return true; +} + +static bool gen_ff(DisasContext *ctx, arg_ff *a, + void (*func)(TCGv, TCGv_env, TCGv)) +{ + CHECK_FPE; + + func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj]); + return true; +} + +static bool gen_muladd(DisasContext *ctx, arg_ffff *a, + void (*func)(TCGv, TCGv_env, TCGv, TCGv, TCGv, TCGv_i32), + int flag) +{ + TCGv_i32 tflag = tcg_constant_i32(flag); + + CHECK_FPE; + + func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj], + cpu_fpr[a->fk], cpu_fpr[a->fa], tflag); + return true; +} + +static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) +{ + CHECK_FPE; + + tcg_gen_deposit_i64(cpu_fpr[a->fd], cpu_fpr[a->fk], cpu_fpr[a->fj], 0, 31); + return true; +} + +static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) +{ + CHECK_FPE; + + tcg_gen_deposit_i64(cpu_fpr[a->fd], cpu_fpr[a->fk], cpu_fpr[a->fj], 0, 63); + return true; +} + +static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) +{ + CHECK_FPE; + + tcg_gen_andi_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], MAKE_64BIT_MASK(0, 31)); + gen_nanbox_s(cpu_fpr[a->fd], cpu_fpr[a->fd]); + return true; +} + +static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) +{ + CHECK_FPE; + + tcg_gen_andi_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], MAKE_64BIT_MASK(0, 63)); + return true; +} + +static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) +{ + CHECK_FPE; + + tcg_gen_xori_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], 0x80000000); + gen_nanbox_s(cpu_fpr[a->fd], cpu_fpr[a->fd]); + return true; +} + +static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) +{ + CHECK_FPE; + + tcg_gen_xori_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], 0x8000000000000000LL); + return true; +} + +TRANS(fadd_s, gen_fff, gen_helper_fadd_s) +TRANS(fadd_d, gen_fff, gen_helper_fadd_d) +TRANS(fsub_s, gen_fff, gen_helper_fsub_s) +TRANS(fsub_d, gen_fff, gen_helper_fsub_d) +TRANS(fmul_s, gen_fff, gen_helper_fmul_s) +TRANS(fmul_d, gen_fff, gen_helper_fmul_d) +TRANS(fdiv_s, gen_fff, gen_helper_fdiv_s) +TRANS(fdiv_d, gen_fff, gen_helper_fdiv_d) +TRANS(fmax_s, gen_fff, gen_helper_fmax_s) +TRANS(fmax_d, gen_fff, gen_helper_fmax_d) +TRANS(fmin_s, gen_fff, gen_helper_fmin_s) +TRANS(fmin_d, gen_fff, gen_helper_fmin_d) +TRANS(fmaxa_s, gen_fff, gen_helper_fmaxa_s) +TRANS(fmaxa_d, gen_fff, gen_helper_fmaxa_d) +TRANS(fmina_s, gen_fff, gen_helper_fmina_s) +TRANS(fmina_d, gen_fff, gen_helper_fmina_d) +TRANS(fscaleb_s, gen_fff, gen_helper_fscaleb_s) +TRANS(fscaleb_d, gen_fff, gen_helper_fscaleb_d) +TRANS(fsqrt_s, gen_ff, gen_helper_fsqrt_s) +TRANS(fsqrt_d, gen_ff, gen_helper_fsqrt_d) +TRANS(frecip_s, gen_ff, gen_helper_frecip_s) +TRANS(frecip_d, gen_ff, gen_helper_frecip_d) +TRANS(frsqrt_s, gen_ff, gen_helper_frsqrt_s) +TRANS(frsqrt_d, gen_ff, gen_helper_frsqrt_d) +TRANS(flogb_s, gen_ff, gen_helper_flogb_s) +TRANS(flogb_d, gen_ff, gen_helper_flogb_d) +TRANS(fclass_s, gen_ff, gen_helper_fclass_s) +TRANS(fclass_d, gen_ff, gen_helper_fclass_d) +TRANS(fmadd_s, gen_muladd, gen_helper_fmuladd_s, 0) +TRANS(fmadd_d, gen_muladd, gen_helper_fmuladd_d, 0) +TRANS(fmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) +TRANS(fmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) +TRANS(fnmadd_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) +TRANS(fnmadd_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) +TRANS(fnmsub_s, gen_muladd, gen_helper_fmuladd_s, + float_muladd_negate_c | float_muladd_negate_result) +TRANS(fnmsub_d, gen_muladd, gen_helper_fmuladd_d, + float_muladd_negate_c | float_muladd_negate_result) diff --git a/target/loongarch/insn_trans/trans_fcmp.c.inc b/target/loongarch/insn_trans/trans_fcmp.c.inc new file mode 100644 index 000000000000..2ccf646ccb8d --- /dev/null +++ b/target/loongarch/insn_trans/trans_fcmp.c.inc @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +/* bit0(signaling/quiet) bit1(lt) bit2(eq) bit3(un) bit4(neq) */ +static uint32_t get_fcmp_flags(int cond) +{ + uint32_t flags = 0; + + if (cond & 0x1) { + flags |= FCMP_LT; + } + if (cond & 0x2) { + flags |= FCMP_EQ; + } + if (cond & 0x4) { + flags |= FCMP_UN; + } + if (cond & 0x8) { + flags |= FCMP_GT | FCMP_LT; + } + return flags; +} + +static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) +{ + TCGv var; + uint32_t flags; + void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + + CHECK_FPE; + + var = tcg_temp_new(); + fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s); + flags = get_fcmp_flags(a->fcond >> 1); + + fn(var, cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk], tcg_constant_i32(flags)); + + tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd])); + tcg_temp_free(var); + return true; +} + +static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) +{ + TCGv var; + uint32_t flags; + void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + + CHECK_FPE; + + var = tcg_temp_new(); + fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d); + flags = get_fcmp_flags(a->fcond >> 1); + + fn(var, cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk], tcg_constant_i32(flags)); + + tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd])); + + tcg_temp_free(var); + return true; +} diff --git a/target/loongarch/insn_trans/trans_fcnv.c.inc b/target/loongarch/insn_trans/trans_fcnv.c.inc new file mode 100644 index 000000000000..c1c6918ad1a1 --- /dev/null +++ b/target/loongarch/insn_trans/trans_fcnv.c.inc @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +TRANS(fcvt_s_d, gen_ff, gen_helper_fcvt_s_d) +TRANS(fcvt_d_s, gen_ff, gen_helper_fcvt_d_s) +TRANS(ftintrm_w_s, gen_ff, gen_helper_ftintrm_w_s) +TRANS(ftintrm_w_d, gen_ff, gen_helper_ftintrm_w_d) +TRANS(ftintrm_l_s, gen_ff, gen_helper_ftintrm_l_s) +TRANS(ftintrm_l_d, gen_ff, gen_helper_ftintrm_l_d) +TRANS(ftintrp_w_s, gen_ff, gen_helper_ftintrp_w_s) +TRANS(ftintrp_w_d, gen_ff, gen_helper_ftintrp_w_d) +TRANS(ftintrp_l_s, gen_ff, gen_helper_ftintrp_l_s) +TRANS(ftintrp_l_d, gen_ff, gen_helper_ftintrp_l_d) +TRANS(ftintrz_w_s, gen_ff, gen_helper_ftintrz_w_s) +TRANS(ftintrz_w_d, gen_ff, gen_helper_ftintrz_w_d) +TRANS(ftintrz_l_s, gen_ff, gen_helper_ftintrz_l_s) +TRANS(ftintrz_l_d, gen_ff, gen_helper_ftintrz_l_d) +TRANS(ftintrne_w_s, gen_ff, gen_helper_ftintrne_w_s) +TRANS(ftintrne_w_d, gen_ff, gen_helper_ftintrne_w_d) +TRANS(ftintrne_l_s, gen_ff, gen_helper_ftintrne_l_s) +TRANS(ftintrne_l_d, gen_ff, gen_helper_ftintrne_l_d) +TRANS(ftint_w_s, gen_ff, gen_helper_ftint_w_s) +TRANS(ftint_w_d, gen_ff, gen_helper_ftint_w_d) +TRANS(ftint_l_s, gen_ff, gen_helper_ftint_l_s) +TRANS(ftint_l_d, gen_ff, gen_helper_ftint_l_d) +TRANS(ffint_s_w, gen_ff, gen_helper_ffint_s_w) +TRANS(ffint_s_l, gen_ff, gen_helper_ffint_s_l) +TRANS(ffint_d_w, gen_ff, gen_helper_ffint_d_w) +TRANS(ffint_d_l, gen_ff, gen_helper_ffint_d_l) +TRANS(frint_s, gen_ff, gen_helper_frint_s) +TRANS(frint_d, gen_ff, gen_helper_frint_d) diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc new file mode 100644 index 000000000000..3025a1d3e927 --- /dev/null +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static void maybe_nanbox_load(TCGv freg, MemOp mop) +{ + if ((mop & MO_SIZE) == MO_32) { + gen_nanbox_s(freg, freg); + } +} + +static bool gen_fload_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) +{ + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + CHECK_FPE; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_fstore_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) +{ + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + CHECK_FPE; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + + if (temp) { + tcg_temp_free(temp); + } + return true; +} + +static bool gen_floadx(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr; + + CHECK_FPE; + + addr = tcg_temp_new(); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fstorex(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr; + + CHECK_FPE; + + addr = tcg_temp_new(); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fload_gt(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr; + + CHECK_FPE; + + addr = tcg_temp_new(); + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fstore_gt(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr; + + CHECK_FPE; + + addr = tcg_temp_new(); + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fload_le(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr; + + CHECK_FPE; + + addr = tcg_temp_new(); + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr; + + CHECK_FPE; + + addr = tcg_temp_new(); + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +TRANS(fld_s, gen_fload_i, MO_TEUL) +TRANS(fst_s, gen_fstore_i, MO_TEUL) +TRANS(fld_d, gen_fload_i, MO_TEUQ) +TRANS(fst_d, gen_fstore_i, MO_TEUQ) +TRANS(fldx_s, gen_floadx, MO_TEUL) +TRANS(fldx_d, gen_floadx, MO_TEUQ) +TRANS(fstx_s, gen_fstorex, MO_TEUL) +TRANS(fstx_d, gen_fstorex, MO_TEUQ) +TRANS(fldgt_s, gen_fload_gt, MO_TEUL) +TRANS(fldgt_d, gen_fload_gt, MO_TEUQ) +TRANS(fldle_s, gen_fload_le, MO_TEUL) +TRANS(fldle_d, gen_fload_le, MO_TEUQ) +TRANS(fstgt_s, gen_fstore_gt, MO_TEUL) +TRANS(fstgt_d, gen_fstore_gt, MO_TEUQ) +TRANS(fstle_s, gen_fstore_le, MO_TEUL) +TRANS(fstle_d, gen_fstore_le, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc new file mode 100644 index 000000000000..8e5106db4e1a --- /dev/null +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static const uint32_t fcsr_mask[4] = { + UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3 +}; + +static bool trans_fsel(DisasContext *ctx, arg_fsel *a) +{ + TCGv zero = tcg_constant_tl(0); + TCGv cond; + + CHECK_FPE; + + cond = tcg_temp_new(); + tcg_gen_ld8u_tl(cond, cpu_env, offsetof(CPULoongArchState, cf[a->ca])); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_fpr[a->fd], cond, zero, + cpu_fpr[a->fj], cpu_fpr[a->fk]); + tcg_temp_free(cond); + + return true; +} + +static bool gen_f2f(DisasContext *ctx, arg_ff *a, + void (*func)(TCGv, TCGv), bool nanbox) +{ + TCGv dest = cpu_fpr[a->fd]; + TCGv src = cpu_fpr[a->fj]; + + CHECK_FPE; + + func(dest, src); + if (nanbox) { + gen_nanbox_s(cpu_fpr[a->fd], cpu_fpr[a->fd]); + } + + return true; +} + +static bool gen_r2f(DisasContext *ctx, arg_fr *a, + void (*func)(TCGv, TCGv)) +{ + TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + CHECK_FPE; + + func(cpu_fpr[a->fd], src); + return true; +} + +static bool gen_f2r(DisasContext *ctx, arg_rf *a, + void (*func)(TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + CHECK_FPE; + + func(dest, cpu_fpr[a->fj]); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) +{ + uint32_t mask = fcsr_mask[a->fcsrd]; + TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); + + CHECK_FPE; + + if (mask == UINT32_MAX) { + 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(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); + tcg_temp_free_i32(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 dest = gpr_dst(ctx, a->rd, EXT_NONE); + + CHECK_FPE; + + 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); + + return true; +} + +static void gen_movgr2fr_w(TCGv dest, TCGv src) +{ + tcg_gen_deposit_i64(dest, dest, src, 0, 32); +} + +static void gen_movgr2frh_w(TCGv dest, TCGv src) +{ + tcg_gen_deposit_i64(dest, dest, src, 32, 32); +} + +static void gen_movfrh2gr_s(TCGv dest, TCGv src) +{ + tcg_gen_sextract_tl(dest, src, 32, 32); +} + +static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) +{ + TCGv t0; + + CHECK_FPE; + + t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, cpu_fpr[a->fj], 0x1); + tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); + tcg_temp_free(t0); + + return true; +} + +static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) +{ + CHECK_FPE; + + tcg_gen_ld8u_tl(cpu_fpr[a->fd], cpu_env, + offsetof(CPULoongArchState, cf[a->cj & 0x7])); + return true; +} + +static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) +{ + TCGv t0; + + CHECK_FPE; + + t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1); + tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); + tcg_temp_free(t0); + + return true; +} + +static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) +{ + CHECK_FPE; + + tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), cpu_env, + offsetof(CPULoongArchState, cf[a->cj & 0x7])); + return true; +} + +TRANS(fmov_s, gen_f2f, tcg_gen_mov_tl, true) +TRANS(fmov_d, gen_f2f, tcg_gen_mov_tl, false) +TRANS(movgr2fr_w, gen_r2f, gen_movgr2fr_w) +TRANS(movgr2fr_d, gen_r2f, tcg_gen_mov_tl) +TRANS(movgr2frh_w, gen_r2f, gen_movgr2frh_w) +TRANS(movfr2gr_s, gen_f2r, tcg_gen_ext32s_tl) +TRANS(movfr2gr_d, gen_f2r, tcg_gen_mov_tl) +TRANS(movfrh2gr_s, gen_f2r, gen_movfrh2gr_s) diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc new file mode 100644 index 000000000000..d5eb31147c92 --- /dev/null +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_load(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_store(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_loadx(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free(addr); + + return true; +} + +static bool gen_storex(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_load_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_load_le(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_store_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); + + return true; +} + +static bool gen_store_le(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); + + return true; +} + +static bool trans_preld(DisasContext *ctx, arg_preld *a) +{ + return true; +} + +static bool trans_dbar(DisasContext *ctx, arg_dbar * a) +{ + tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); + return true; +} + +static bool trans_ibar(DisasContext *ctx, arg_ibar *a) +{ + ctx->base.is_jmp = DISAS_STOP; + return true; +} + +static bool gen_ldptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +TRANS(ld_b, gen_load, MO_SB) +TRANS(ld_h, gen_load, MO_TESW) +TRANS(ld_w, gen_load, MO_TESL) +TRANS(ld_d, gen_load, MO_TEUQ) +TRANS(st_b, gen_store, MO_UB) +TRANS(st_h, gen_store, MO_TEUW) +TRANS(st_w, gen_store, MO_TEUL) +TRANS(st_d, gen_store, MO_TEUQ) +TRANS(ld_bu, gen_load, MO_UB) +TRANS(ld_hu, gen_load, MO_TEUW) +TRANS(ld_wu, gen_load, MO_TEUL) +TRANS(ldx_b, gen_loadx, MO_SB) +TRANS(ldx_h, gen_loadx, MO_TESW) +TRANS(ldx_w, gen_loadx, MO_TESL) +TRANS(ldx_d, gen_loadx, MO_TEUQ) +TRANS(stx_b, gen_storex, MO_UB) +TRANS(stx_h, gen_storex, MO_TEUW) +TRANS(stx_w, gen_storex, MO_TEUL) +TRANS(stx_d, gen_storex, MO_TEUQ) +TRANS(ldx_bu, gen_loadx, MO_UB) +TRANS(ldx_hu, gen_loadx, MO_TEUW) +TRANS(ldx_wu, gen_loadx, MO_TEUL) +TRANS(ldptr_w, gen_ldptr, MO_TESL) +TRANS(stptr_w, gen_stptr, MO_TEUL) +TRANS(ldptr_d, gen_ldptr, MO_TEUQ) +TRANS(stptr_d, gen_stptr, MO_TEUQ) +TRANS(ldgt_b, gen_load_gt, MO_SB) +TRANS(ldgt_h, gen_load_gt, MO_TESW) +TRANS(ldgt_w, gen_load_gt, MO_TESL) +TRANS(ldgt_d, gen_load_gt, MO_TEUQ) +TRANS(ldle_b, gen_load_le, MO_SB) +TRANS(ldle_h, gen_load_le, MO_TESW) +TRANS(ldle_w, gen_load_le, MO_TESL) +TRANS(ldle_d, gen_load_le, MO_TEUQ) +TRANS(stgt_b, gen_store_gt, MO_UB) +TRANS(stgt_h, gen_store_gt, MO_TEUW) +TRANS(stgt_w, gen_store_gt, MO_TEUL) +TRANS(stgt_d, gen_store_gt, MO_TEUQ) +TRANS(stle_b, gen_store_le, MO_UB) +TRANS(stle_h, gen_store_le, MO_TEUW) +TRANS(stle_w, gen_store_le, MO_TEUL) +TRANS(stle_d, gen_store_le, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc new file mode 100644 index 000000000000..40f82becb04c --- /dev/null +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -0,0 +1,502 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * LoongArch translation routines for the privileged instructions. + */ + +#include "cpu-csr.h" + +#ifdef CONFIG_USER_ONLY + +#define GEN_FALSE_TRANS(name) \ +static bool trans_##name(DisasContext *ctx, arg_##name * a) \ +{ \ + return false; \ +} + +GEN_FALSE_TRANS(csrrd) +GEN_FALSE_TRANS(csrwr) +GEN_FALSE_TRANS(csrxchg) +GEN_FALSE_TRANS(iocsrrd_b) +GEN_FALSE_TRANS(iocsrrd_h) +GEN_FALSE_TRANS(iocsrrd_w) +GEN_FALSE_TRANS(iocsrrd_d) +GEN_FALSE_TRANS(iocsrwr_b) +GEN_FALSE_TRANS(iocsrwr_h) +GEN_FALSE_TRANS(iocsrwr_w) +GEN_FALSE_TRANS(iocsrwr_d) +GEN_FALSE_TRANS(tlbsrch) +GEN_FALSE_TRANS(tlbrd) +GEN_FALSE_TRANS(tlbwr) +GEN_FALSE_TRANS(tlbfill) +GEN_FALSE_TRANS(tlbclr) +GEN_FALSE_TRANS(tlbflush) +GEN_FALSE_TRANS(invtlb) +GEN_FALSE_TRANS(cacop) +GEN_FALSE_TRANS(ldpte) +GEN_FALSE_TRANS(lddir) +GEN_FALSE_TRANS(ertn) +GEN_FALSE_TRANS(dbcl) +GEN_FALSE_TRANS(idle) + +#else + +typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env); +typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src); + +typedef struct { + int offset; + int flags; + GenCSRRead readfn; + GenCSRWrite writefn; +} CSRInfo; + +enum { + CSRFL_READONLY = (1 << 0), + CSRFL_EXITTB = (1 << 1), + CSRFL_IO = (1 << 2), +}; + +#define CSR_OFF_FUNCS(NAME, FL, RD, WR) \ + [LOONGARCH_CSR_##NAME] = { \ + .offset = offsetof(CPULoongArchState, CSR_##NAME), \ + .flags = FL, .readfn = RD, .writefn = WR \ + } + +#define CSR_OFF_ARRAY(NAME, N) \ + [LOONGARCH_CSR_##NAME(N)] = { \ + .offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \ + .flags = 0, .readfn = NULL, .writefn = NULL \ + } + +#define CSR_OFF_FLAGS(NAME, FL) \ + CSR_OFF_FUNCS(NAME, FL, NULL, NULL) + +#define CSR_OFF(NAME) \ + CSR_OFF_FLAGS(NAME, 0) + +static const CSRInfo csr_info[] = { + CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), + CSR_OFF(PRMD), + CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB), + CSR_OFF_FLAGS(MISC, CSRFL_READONLY), + CSR_OFF(ECFG), + CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat), + CSR_OFF(ERA), + CSR_OFF(BADV), + CSR_OFF_FLAGS(BADI, CSRFL_READONLY), + CSR_OFF(EENTRY), + CSR_OFF(TLBIDX), + CSR_OFF(TLBEHI), + CSR_OFF(TLBELO0), + CSR_OFF(TLBELO1), + CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid), + CSR_OFF(PGDL), + CSR_OFF(PGDH), + CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL), + CSR_OFF(PWCL), + CSR_OFF(PWCH), + CSR_OFF(STLBPS), + CSR_OFF(RVACFG), + [LOONGARCH_CSR_CPUID] = { + .offset = (int)offsetof(CPUState, cpu_index) + - (int)offsetof(LoongArchCPU, env), + .flags = CSRFL_READONLY, + .readfn = NULL, + .writefn = NULL + }, + CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY), + CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY), + CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY), + CSR_OFF_ARRAY(SAVE, 0), + CSR_OFF_ARRAY(SAVE, 1), + CSR_OFF_ARRAY(SAVE, 2), + CSR_OFF_ARRAY(SAVE, 3), + CSR_OFF_ARRAY(SAVE, 4), + CSR_OFF_ARRAY(SAVE, 5), + CSR_OFF_ARRAY(SAVE, 6), + CSR_OFF_ARRAY(SAVE, 7), + CSR_OFF_ARRAY(SAVE, 8), + CSR_OFF_ARRAY(SAVE, 9), + CSR_OFF_ARRAY(SAVE, 10), + CSR_OFF_ARRAY(SAVE, 11), + CSR_OFF_ARRAY(SAVE, 12), + CSR_OFF_ARRAY(SAVE, 13), + CSR_OFF_ARRAY(SAVE, 14), + CSR_OFF_ARRAY(SAVE, 15), + CSR_OFF(TID), + CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg), + CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL), + CSR_OFF(CNTC), + CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr), + CSR_OFF(LLBCTL), + CSR_OFF(IMPCTL1), + CSR_OFF(IMPCTL2), + CSR_OFF(TLBRENTRY), + CSR_OFF(TLBRBADV), + CSR_OFF(TLBRERA), + CSR_OFF(TLBRSAVE), + CSR_OFF(TLBRELO0), + CSR_OFF(TLBRELO1), + CSR_OFF(TLBREHI), + CSR_OFF(TLBRPRMD), + CSR_OFF(MERRCTL), + CSR_OFF(MERRINFO1), + CSR_OFF(MERRINFO2), + CSR_OFF(MERRENTRY), + CSR_OFF(MERRERA), + CSR_OFF(MERRSAVE), + CSR_OFF(CTAG), + CSR_OFF_ARRAY(DMW, 0), + CSR_OFF_ARRAY(DMW, 1), + CSR_OFF_ARRAY(DMW, 2), + CSR_OFF_ARRAY(DMW, 3), + CSR_OFF(DBG), + CSR_OFF(DERA), + CSR_OFF(DSAVE), +}; + +static bool check_plv(DisasContext *ctx) +{ + if (ctx->plv == MMU_PLV_USER) { + generate_exception(ctx, EXCCODE_IPE); + return true; + } + return false; +} + +static const CSRInfo *get_csr(unsigned csr_num) +{ + const CSRInfo *csr; + + if (csr_num >= ARRAY_SIZE(csr_info)) { + return NULL; + } + csr = &csr_info[csr_num]; + if (csr->offset == 0) { + return NULL; + } + return csr; +} + +static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write) +{ + if ((csr->flags & CSRFL_READONLY) && write) { + return false; + } + if ((csr->flags & CSRFL_IO) && + (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT)) { + gen_io_start(); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; + } else if ((csr->flags & CSRFL_EXITTB) && write) { + ctx->base.is_jmp = DISAS_EXIT_UPDATE; + } + return true; +} + +static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) +{ + TCGv dest; + const CSRInfo *csr; + + if (check_plv(ctx)) { + return false; + } + csr = get_csr(a->csr); + if (csr == NULL) { + /* CSR is undefined: read as 0. */ + dest = tcg_constant_tl(0); + } else { + check_csr_flags(ctx, csr, false); + dest = gpr_dst(ctx, a->rd, EXT_NONE); + if (csr->readfn) { + csr->readfn(dest, cpu_env); + } else { + tcg_gen_ld_tl(dest, cpu_env, csr->offset); + } + } + gen_set_gpr(a->rd, dest, EXT_NONE); + return true; +} + +static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) +{ + TCGv dest, src1; + const CSRInfo *csr; + + if (check_plv(ctx)) { + return false; + } + csr = get_csr(a->csr); + if (csr == NULL) { + /* CSR is undefined: write ignored, read old_value as 0. */ + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + if (!check_csr_flags(ctx, csr, true)) { + /* CSR is readonly: trap. */ + return false; + } + src1 = gpr_src(ctx, a->rd, EXT_NONE); + if (csr->writefn) { + dest = gpr_dst(ctx, a->rd, EXT_NONE); + csr->writefn(dest, cpu_env, src1); + } else { + dest = temp_new(ctx); + tcg_gen_ld_tl(dest, cpu_env, csr->offset); + tcg_gen_st_tl(src1, cpu_env, csr->offset); + } + gen_set_gpr(a->rd, dest, EXT_NONE); + return true; +} + +static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) +{ + TCGv src1, mask, oldv, newv, temp; + const CSRInfo *csr; + + if (check_plv(ctx)) { + return false; + } + csr = get_csr(a->csr); + if (csr == NULL) { + /* CSR is undefined: write ignored, read old_value as 0. */ + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + + if (!check_csr_flags(ctx, csr, true)) { + /* CSR is readonly: trap. */ + return false; + } + + /* So far only readonly csrs have readfn. */ + assert(csr->readfn == NULL); + + src1 = gpr_src(ctx, a->rd, EXT_NONE); + mask = gpr_src(ctx, a->rj, EXT_NONE); + oldv = tcg_temp_new(); + newv = tcg_temp_new(); + temp = tcg_temp_new(); + + tcg_gen_ld_tl(oldv, cpu_env, csr->offset); + tcg_gen_and_tl(newv, src1, mask); + tcg_gen_andc_tl(temp, oldv, mask); + tcg_gen_or_tl(newv, newv, temp); + + if (csr->writefn) { + csr->writefn(oldv, cpu_env, newv); + } else { + tcg_gen_st_tl(newv, cpu_env, csr->offset); + } + gen_set_gpr(a->rd, oldv, EXT_NONE); + + tcg_temp_free(temp); + tcg_temp_free(newv); + tcg_temp_free(oldv); + return true; +} + +static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, + void (*func)(TCGv, TCGv_ptr, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + func(dest, cpu_env, src1); + return true; +} + +static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, + void (*func)(TCGv_ptr, TCGv, TCGv)) +{ + TCGv val = gpr_src(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + func(cpu_env, addr, val); + return true; +} + +TRANS(iocsrrd_b, gen_iocsrrd, gen_helper_iocsrrd_b) +TRANS(iocsrrd_h, gen_iocsrrd, gen_helper_iocsrrd_h) +TRANS(iocsrrd_w, gen_iocsrrd, gen_helper_iocsrrd_w) +TRANS(iocsrrd_d, gen_iocsrrd, gen_helper_iocsrrd_d) +TRANS(iocsrwr_b, gen_iocsrwr, gen_helper_iocsrwr_b) +TRANS(iocsrwr_h, gen_iocsrwr, gen_helper_iocsrwr_h) +TRANS(iocsrwr_w, gen_iocsrwr, gen_helper_iocsrwr_w) +TRANS(iocsrwr_d, gen_iocsrwr, gen_helper_iocsrwr_d) + +static void check_mmu_idx(DisasContext *ctx) +{ + if (ctx->mem_idx != MMU_IDX_DA) { + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; + } +} + +static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbsrch(cpu_env); + return true; +} + +static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbrd(cpu_env); + return true; +} + +static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbwr(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbfill(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbclr(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbflush(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) +{ + TCGv rj = gpr_src(ctx, a->rj, EXT_NONE); + TCGv rk = gpr_src(ctx, a->rk, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + + switch (a->imm) { + case 0: + case 1: + gen_helper_invtlb_all(cpu_env); + break; + case 2: + gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1)); + break; + case 3: + gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0)); + break; + case 4: + gen_helper_invtlb_all_asid(cpu_env, rj); + break; + case 5: + gen_helper_invtlb_page_asid(cpu_env, rj, rk); + break; + case 6: + gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk); + break; + default: + return false; + } + ctx->base.is_jmp = DISAS_STOP; + return true; +} + +static bool trans_cacop(DisasContext *ctx, arg_cacop *a) +{ + /* Treat the cacop as a nop */ + if (check_plv(ctx)) { + return false; + } + return true; +} + +static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) +{ + TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx); + return true; +} + +static bool trans_lddir(DisasContext *ctx, arg_lddir *a) +{ + TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); + TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx); + return true; +} + +static bool trans_ertn(DisasContext *ctx, arg_ertn *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_ertn(cpu_env); + ctx->base.is_jmp = DISAS_EXIT; + return true; +} + +static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) +{ + if (check_plv(ctx)) { + return false; + } + generate_exception(ctx, EXCCODE_DBP); + return true; +} + +static bool trans_idle(DisasContext *ctx, arg_idle *a) +{ + if (check_plv(ctx)) { + return false; + } + + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); + gen_helper_idle(cpu_env); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} +#endif diff --git a/target/loongarch/insn_trans/trans_shift.c.inc b/target/loongarch/insn_trans/trans_shift.c.inc new file mode 100644 index 000000000000..5260af23372a --- /dev/null +++ b/target/loongarch/insn_trans/trans_shift.c.inc @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static void gen_sll_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x1f); + tcg_gen_shl_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_srl_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x1f); + tcg_gen_shr_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_sra_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x1f); + tcg_gen_sar_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_sll_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_shl_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_srl_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_shr_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_sra_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_sar_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rotr_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, src2, 0x1f); + + tcg_gen_trunc_tl_i32(t1, src1); + tcg_gen_trunc_tl_i32(t2, t0); + + tcg_gen_rotr_i32(t1, t1, t2); + tcg_gen_ext_i32_tl(dest, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free(t0); +} + +static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_rotr_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); + + tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +TRANS(sll_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) +TRANS(srl_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) +TRANS(sra_w, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) +TRANS(sll_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) +TRANS(srl_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) +TRANS(sra_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) +TRANS(rotr_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) +TRANS(rotr_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) +TRANS(slli_w, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) +TRANS(slli_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) +TRANS(srli_w, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) +TRANS(srli_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +TRANS(srai_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) +TRANS(rotri_w, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) +TRANS(rotri_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode new file mode 100644 index 000000000000..3fdc6e148cdb --- /dev/null +++ b/target/loongarch/insns.decode @@ -0,0 +1,486 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# LoongArch instruction decode definitions. +# +# Copyright (c) 2021 Loongson Technology Corporation Limited +# + +# +# Fields +# +%i14s2 10:s14 !function=shl_2 +%sa2p1 15:2 !function=plus_1 +%offs21 0:s5 10:16 !function=shl_2 +%offs16 10:s16 !function=shl_2 +%offs26 0:s10 10:16 !function=shl_2 + +# +# Argument sets +# +&i imm +&r_i rd imm +&rr rd rj +&rr_jk rj rk +&rrr rd rj rk +&rr_i rd rj imm +&hint_r_i hint rj imm +&rrr_sa rd rj rk sa +&rr_ms_ls rd rj ms ls +&ff fd fj +&fff fd fj fk +&ffff fd fj fk fa +&cff_fcond cd fj fk fcond +&fffc fd fj fk ca +&fr fd rj +&rf rd fj +&fcsrd_r fcsrd rj +&r_fcsrs rd fcsrs +&cf cd fj +&fc fd cj +&cr cd rj +&rc rd cj +&frr fd rj rk +&fr_i fd rj imm +&r_offs rj offs +&c_offs cj offs +&offs offs +&rr_offs rj rd offs +&r_csr rd csr +&rr_csr rd rj csr +&empty +&i_rr imm rj rk +&cop_r_i cop rj imm +&j_i rj imm + +# +# Formats +# +@i15 .... ........ ..... imm:15 &i +@rr .... ........ ..... ..... rj:5 rd:5 &rr +@rr_jk .... ........ ..... rk:5 rj:5 ..... &rr_jk +@rrr .... ........ ..... rk:5 rj:5 rd:5 &rrr +@r_i20 .... ... imm:s20 rd:5 &r_i +@rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i +@rr_ui6 .... ........ .... imm:6 rj:5 rd:5 &rr_i +@rr_ui8 .. ........ .... imm:8 rj:5 rd:5 &rr_i +@rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i +@rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i +@rr_i14s2 .... .... .............. rj:5 rd:5 &rr_i imm=%i14s2 +@rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i +@hint_r_i12 .... ...... imm:s12 rj:5 hint:5 &hint_r_i +@rrr_sa2p1 .... ........ ... .. rk:5 rj:5 rd:5 &rrr_sa sa=%sa2p1 +@rrr_sa2 .... ........ ... sa:2 rk:5 rj:5 rd:5 &rrr_sa +@rrr_sa3 .... ........ .. sa:3 rk:5 rj:5 rd:5 &rrr_sa +@rr_2bw .... ....... ms:5 . ls:5 rj:5 rd:5 &rr_ms_ls +@rr_2bd .... ...... ms:6 ls:6 rj:5 rd:5 &rr_ms_ls +@ff .... ........ ..... ..... fj:5 fd:5 &ff +@fff .... ........ ..... fk:5 fj:5 fd:5 &fff +@ffff .... ........ fa:5 fk:5 fj:5 fd:5 &ffff +@cff_fcond .... ........ fcond:5 fk:5 fj:5 .. cd:3 &cff_fcond +@fffc .... ........ .. ca:3 fk:5 fj:5 fd:5 &fffc +@fr .... ........ ..... ..... rj:5 fd:5 &fr +@rf .... ........ ..... ..... fj:5 rd:5 &rf +@fcsrd_r .... ........ ..... ..... rj:5 fcsrd:5 &fcsrd_r +@r_fcsrs .... ........ ..... ..... fcsrs:5 rd:5 &r_fcsrs +@cf .... ........ ..... ..... fj:5 .. cd:3 &cf +@fc .... ........ ..... ..... .. cj:3 fd:5 &fc +@cr .... ........ ..... ..... rj:5 .. cd:3 &cr +@rc .... ........ ..... ..... .. cj:3 rd:5 &rc +@frr .... ........ ..... rk:5 rj:5 fd:5 &frr +@fr_i12 .... ...... imm:s12 rj:5 fd:5 &fr_i +@r_offs21 .... .. ................ rj:5 ..... &r_offs offs=%offs21 +@c_offs21 .... .. ................ .. cj:3 ..... &c_offs offs=%offs21 +@offs26 .... .. .......................... &offs offs=%offs26 +@rr_offs16 .... .. ................ rj:5 rd:5 &rr_offs offs=%offs16 +@r_csr .... .... csr:14 ..... rd:5 &r_csr +@rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr +@empty .... ........ ..... ..... ..... ..... &empty +@i_rr ...... ...... ..... rk:5 rj:5 imm:5 &i_rr +@cop_r_i .... ...... imm:s12 rj:5 cop:5 &cop_r_i +@j_i .... ........ .. imm:8 rj:5 ..... &j_i + +# +# Fixed point arithmetic operation instruction +# +add_w 0000 00000001 00000 ..... ..... ..... @rrr +add_d 0000 00000001 00001 ..... ..... ..... @rrr +sub_w 0000 00000001 00010 ..... ..... ..... @rrr +sub_d 0000 00000001 00011 ..... ..... ..... @rrr +slt 0000 00000001 00100 ..... ..... ..... @rrr +sltu 0000 00000001 00101 ..... ..... ..... @rrr +slti 0000 001000 ............ ..... ..... @rr_i12 +sltui 0000 001001 ............ ..... ..... @rr_i12 +nor 0000 00000001 01000 ..... ..... ..... @rrr +and 0000 00000001 01001 ..... ..... ..... @rrr +or 0000 00000001 01010 ..... ..... ..... @rrr +xor 0000 00000001 01011 ..... ..... ..... @rrr +orn 0000 00000001 01100 ..... ..... ..... @rrr +andn 0000 00000001 01101 ..... ..... ..... @rrr +mul_w 0000 00000001 11000 ..... ..... ..... @rrr +mulh_w 0000 00000001 11001 ..... ..... ..... @rrr +mulh_wu 0000 00000001 11010 ..... ..... ..... @rrr +mul_d 0000 00000001 11011 ..... ..... ..... @rrr +mulh_d 0000 00000001 11100 ..... ..... ..... @rrr +mulh_du 0000 00000001 11101 ..... ..... ..... @rrr +mulw_d_w 0000 00000001 11110 ..... ..... ..... @rrr +mulw_d_wu 0000 00000001 11111 ..... ..... ..... @rrr +div_w 0000 00000010 00000 ..... ..... ..... @rrr +mod_w 0000 00000010 00001 ..... ..... ..... @rrr +div_wu 0000 00000010 00010 ..... ..... ..... @rrr +mod_wu 0000 00000010 00011 ..... ..... ..... @rrr +div_d 0000 00000010 00100 ..... ..... ..... @rrr +mod_d 0000 00000010 00101 ..... ..... ..... @rrr +div_du 0000 00000010 00110 ..... ..... ..... @rrr +mod_du 0000 00000010 00111 ..... ..... ..... @rrr +alsl_w 0000 00000000 010 .. ..... ..... ..... @rrr_sa2p1 +alsl_wu 0000 00000000 011 .. ..... ..... ..... @rrr_sa2p1 +alsl_d 0000 00000010 110 .. ..... ..... ..... @rrr_sa2p1 +lu12i_w 0001 010 .................... ..... @r_i20 +lu32i_d 0001 011 .................... ..... @r_i20 +lu52i_d 0000 001100 ............ ..... ..... @rr_i12 +pcaddi 0001 100 .................... ..... @r_i20 +pcalau12i 0001 101 .................... ..... @r_i20 +pcaddu12i 0001 110 .................... ..... @r_i20 +pcaddu18i 0001 111 .................... ..... @r_i20 +addi_w 0000 001010 ............ ..... ..... @rr_i12 +addi_d 0000 001011 ............ ..... ..... @rr_i12 +addu16i_d 0001 00 ................ ..... ..... @rr_i16 +andi 0000 001101 ............ ..... ..... @rr_ui12 +ori 0000 001110 ............ ..... ..... @rr_ui12 +xori 0000 001111 ............ ..... ..... @rr_ui12 + +# +# Fixed point shift operation instruction +# +sll_w 0000 00000001 01110 ..... ..... ..... @rrr +srl_w 0000 00000001 01111 ..... ..... ..... @rrr +sra_w 0000 00000001 10000 ..... ..... ..... @rrr +sll_d 0000 00000001 10001 ..... ..... ..... @rrr +srl_d 0000 00000001 10010 ..... ..... ..... @rrr +sra_d 0000 00000001 10011 ..... ..... ..... @rrr +rotr_w 0000 00000001 10110 ..... ..... ..... @rrr +rotr_d 0000 00000001 10111 ..... ..... ..... @rrr +slli_w 0000 00000100 00001 ..... ..... ..... @rr_ui5 +slli_d 0000 00000100 0001 ...... ..... ..... @rr_ui6 +srli_w 0000 00000100 01001 ..... ..... ..... @rr_ui5 +srli_d 0000 00000100 0101 ...... ..... ..... @rr_ui6 +srai_w 0000 00000100 10001 ..... ..... ..... @rr_ui5 +srai_d 0000 00000100 1001 ...... ..... ..... @rr_ui6 +rotri_w 0000 00000100 11001 ..... ..... ..... @rr_ui5 +rotri_d 0000 00000100 1101 ...... ..... ..... @rr_ui6 + +# +# Fixed point bit operation instruction +# +ext_w_h 0000 00000000 00000 10110 ..... ..... @rr +ext_w_b 0000 00000000 00000 10111 ..... ..... @rr +clo_w 0000 00000000 00000 00100 ..... ..... @rr +clz_w 0000 00000000 00000 00101 ..... ..... @rr +cto_w 0000 00000000 00000 00110 ..... ..... @rr +ctz_w 0000 00000000 00000 00111 ..... ..... @rr +clo_d 0000 00000000 00000 01000 ..... ..... @rr +clz_d 0000 00000000 00000 01001 ..... ..... @rr +cto_d 0000 00000000 00000 01010 ..... ..... @rr +ctz_d 0000 00000000 00000 01011 ..... ..... @rr +revb_2h 0000 00000000 00000 01100 ..... ..... @rr +revb_4h 0000 00000000 00000 01101 ..... ..... @rr +revb_2w 0000 00000000 00000 01110 ..... ..... @rr +revb_d 0000 00000000 00000 01111 ..... ..... @rr +revh_2w 0000 00000000 00000 10000 ..... ..... @rr +revh_d 0000 00000000 00000 10001 ..... ..... @rr +bitrev_4b 0000 00000000 00000 10010 ..... ..... @rr +bitrev_8b 0000 00000000 00000 10011 ..... ..... @rr +bitrev_w 0000 00000000 00000 10100 ..... ..... @rr +bitrev_d 0000 00000000 00000 10101 ..... ..... @rr +bytepick_w 0000 00000000 100 .. ..... ..... ..... @rrr_sa2 +bytepick_d 0000 00000000 11 ... ..... ..... ..... @rrr_sa3 +maskeqz 0000 00000001 00110 ..... ..... ..... @rrr +masknez 0000 00000001 00111 ..... ..... ..... @rrr +bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @rr_2bw +bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @rr_2bw +bstrins_d 0000 000010 ...... ...... ..... ..... @rr_2bd +bstrpick_d 0000 000011 ...... ...... ..... ..... @rr_2bd + +# +# Fixed point load/store instruction +# +ld_b 0010 100000 ............ ..... ..... @rr_i12 +ld_h 0010 100001 ............ ..... ..... @rr_i12 +ld_w 0010 100010 ............ ..... ..... @rr_i12 +ld_d 0010 100011 ............ ..... ..... @rr_i12 +st_b 0010 100100 ............ ..... ..... @rr_i12 +st_h 0010 100101 ............ ..... ..... @rr_i12 +st_w 0010 100110 ............ ..... ..... @rr_i12 +st_d 0010 100111 ............ ..... ..... @rr_i12 +ld_bu 0010 101000 ............ ..... ..... @rr_i12 +ld_hu 0010 101001 ............ ..... ..... @rr_i12 +ld_wu 0010 101010 ............ ..... ..... @rr_i12 +ldx_b 0011 10000000 00000 ..... ..... ..... @rrr +ldx_h 0011 10000000 01000 ..... ..... ..... @rrr +ldx_w 0011 10000000 10000 ..... ..... ..... @rrr +ldx_d 0011 10000000 11000 ..... ..... ..... @rrr +stx_b 0011 10000001 00000 ..... ..... ..... @rrr +stx_h 0011 10000001 01000 ..... ..... ..... @rrr +stx_w 0011 10000001 10000 ..... ..... ..... @rrr +stx_d 0011 10000001 11000 ..... ..... ..... @rrr +ldx_bu 0011 10000010 00000 ..... ..... ..... @rrr +ldx_hu 0011 10000010 01000 ..... ..... ..... @rrr +ldx_wu 0011 10000010 10000 ..... ..... ..... @rrr +preld 0010 101011 ............ ..... ..... @hint_r_i12 +dbar 0011 10000111 00100 ............... @i15 +ibar 0011 10000111 00101 ............... @i15 +ldptr_w 0010 0100 .............. ..... ..... @rr_i14s2 +stptr_w 0010 0101 .............. ..... ..... @rr_i14s2 +ldptr_d 0010 0110 .............. ..... ..... @rr_i14s2 +stptr_d 0010 0111 .............. ..... ..... @rr_i14s2 +ldgt_b 0011 10000111 10000 ..... ..... ..... @rrr +ldgt_h 0011 10000111 10001 ..... ..... ..... @rrr +ldgt_w 0011 10000111 10010 ..... ..... ..... @rrr +ldgt_d 0011 10000111 10011 ..... ..... ..... @rrr +ldle_b 0011 10000111 10100 ..... ..... ..... @rrr +ldle_h 0011 10000111 10101 ..... ..... ..... @rrr +ldle_w 0011 10000111 10110 ..... ..... ..... @rrr +ldle_d 0011 10000111 10111 ..... ..... ..... @rrr +stgt_b 0011 10000111 11000 ..... ..... ..... @rrr +stgt_h 0011 10000111 11001 ..... ..... ..... @rrr +stgt_w 0011 10000111 11010 ..... ..... ..... @rrr +stgt_d 0011 10000111 11011 ..... ..... ..... @rrr +stle_b 0011 10000111 11100 ..... ..... ..... @rrr +stle_h 0011 10000111 11101 ..... ..... ..... @rrr +stle_w 0011 10000111 11110 ..... ..... ..... @rrr +stle_d 0011 10000111 11111 ..... ..... ..... @rrr + +# +# Fixed point atomic instruction +# +ll_w 0010 0000 .............. ..... ..... @rr_i14s2 +sc_w 0010 0001 .............. ..... ..... @rr_i14s2 +ll_d 0010 0010 .............. ..... ..... @rr_i14s2 +sc_d 0010 0011 .............. ..... ..... @rr_i14s2 +amswap_w 0011 10000110 00000 ..... ..... ..... @rrr +amswap_d 0011 10000110 00001 ..... ..... ..... @rrr +amadd_w 0011 10000110 00010 ..... ..... ..... @rrr +amadd_d 0011 10000110 00011 ..... ..... ..... @rrr +amand_w 0011 10000110 00100 ..... ..... ..... @rrr +amand_d 0011 10000110 00101 ..... ..... ..... @rrr +amor_w 0011 10000110 00110 ..... ..... ..... @rrr +amor_d 0011 10000110 00111 ..... ..... ..... @rrr +amxor_w 0011 10000110 01000 ..... ..... ..... @rrr +amxor_d 0011 10000110 01001 ..... ..... ..... @rrr +ammax_w 0011 10000110 01010 ..... ..... ..... @rrr +ammax_d 0011 10000110 01011 ..... ..... ..... @rrr +ammin_w 0011 10000110 01100 ..... ..... ..... @rrr +ammin_d 0011 10000110 01101 ..... ..... ..... @rrr +ammax_wu 0011 10000110 01110 ..... ..... ..... @rrr +ammax_du 0011 10000110 01111 ..... ..... ..... @rrr +ammin_wu 0011 10000110 10000 ..... ..... ..... @rrr +ammin_du 0011 10000110 10001 ..... ..... ..... @rrr +amswap_db_w 0011 10000110 10010 ..... ..... ..... @rrr +amswap_db_d 0011 10000110 10011 ..... ..... ..... @rrr +amadd_db_w 0011 10000110 10100 ..... ..... ..... @rrr +amadd_db_d 0011 10000110 10101 ..... ..... ..... @rrr +amand_db_w 0011 10000110 10110 ..... ..... ..... @rrr +amand_db_d 0011 10000110 10111 ..... ..... ..... @rrr +amor_db_w 0011 10000110 11000 ..... ..... ..... @rrr +amor_db_d 0011 10000110 11001 ..... ..... ..... @rrr +amxor_db_w 0011 10000110 11010 ..... ..... ..... @rrr +amxor_db_d 0011 10000110 11011 ..... ..... ..... @rrr +ammax_db_w 0011 10000110 11100 ..... ..... ..... @rrr +ammax_db_d 0011 10000110 11101 ..... ..... ..... @rrr +ammin_db_w 0011 10000110 11110 ..... ..... ..... @rrr +ammin_db_d 0011 10000110 11111 ..... ..... ..... @rrr +ammax_db_wu 0011 10000111 00000 ..... ..... ..... @rrr +ammax_db_du 0011 10000111 00001 ..... ..... ..... @rrr +ammin_db_wu 0011 10000111 00010 ..... ..... ..... @rrr +ammin_db_du 0011 10000111 00011 ..... ..... ..... @rrr + +# +# Fixed point extra instruction +# +crc_w_b_w 0000 00000010 01000 ..... ..... ..... @rrr +crc_w_h_w 0000 00000010 01001 ..... ..... ..... @rrr +crc_w_w_w 0000 00000010 01010 ..... ..... ..... @rrr +crc_w_d_w 0000 00000010 01011 ..... ..... ..... @rrr +crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @rrr +crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @rrr +crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @rrr +crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @rrr +break 0000 00000010 10100 ............... @i15 +syscall 0000 00000010 10110 ............... @i15 +asrtle_d 0000 00000000 00010 ..... ..... 00000 @rr_jk +asrtgt_d 0000 00000000 00011 ..... ..... 00000 @rr_jk +rdtimel_w 0000 00000000 00000 11000 ..... ..... @rr +rdtimeh_w 0000 00000000 00000 11001 ..... ..... @rr +rdtime_d 0000 00000000 00000 11010 ..... ..... @rr +cpucfg 0000 00000000 00000 11011 ..... ..... @rr + +# +# Floating point arithmetic operation instruction +# +fadd_s 0000 00010000 00001 ..... ..... ..... @fff +fadd_d 0000 00010000 00010 ..... ..... ..... @fff +fsub_s 0000 00010000 00101 ..... ..... ..... @fff +fsub_d 0000 00010000 00110 ..... ..... ..... @fff +fmul_s 0000 00010000 01001 ..... ..... ..... @fff +fmul_d 0000 00010000 01010 ..... ..... ..... @fff +fdiv_s 0000 00010000 01101 ..... ..... ..... @fff +fdiv_d 0000 00010000 01110 ..... ..... ..... @fff +fmadd_s 0000 10000001 ..... ..... ..... ..... @ffff +fmadd_d 0000 10000010 ..... ..... ..... ..... @ffff +fmsub_s 0000 10000101 ..... ..... ..... ..... @ffff +fmsub_d 0000 10000110 ..... ..... ..... ..... @ffff +fnmadd_s 0000 10001001 ..... ..... ..... ..... @ffff +fnmadd_d 0000 10001010 ..... ..... ..... ..... @ffff +fnmsub_s 0000 10001101 ..... ..... ..... ..... @ffff +fnmsub_d 0000 10001110 ..... ..... ..... ..... @ffff +fmax_s 0000 00010000 10001 ..... ..... ..... @fff +fmax_d 0000 00010000 10010 ..... ..... ..... @fff +fmin_s 0000 00010000 10101 ..... ..... ..... @fff +fmin_d 0000 00010000 10110 ..... ..... ..... @fff +fmaxa_s 0000 00010000 11001 ..... ..... ..... @fff +fmaxa_d 0000 00010000 11010 ..... ..... ..... @fff +fmina_s 0000 00010000 11101 ..... ..... ..... @fff +fmina_d 0000 00010000 11110 ..... ..... ..... @fff +fabs_s 0000 00010001 01000 00001 ..... ..... @ff +fabs_d 0000 00010001 01000 00010 ..... ..... @ff +fneg_s 0000 00010001 01000 00101 ..... ..... @ff +fneg_d 0000 00010001 01000 00110 ..... ..... @ff +fsqrt_s 0000 00010001 01000 10001 ..... ..... @ff +fsqrt_d 0000 00010001 01000 10010 ..... ..... @ff +frecip_s 0000 00010001 01000 10101 ..... ..... @ff +frecip_d 0000 00010001 01000 10110 ..... ..... @ff +frsqrt_s 0000 00010001 01000 11001 ..... ..... @ff +frsqrt_d 0000 00010001 01000 11010 ..... ..... @ff +fscaleb_s 0000 00010001 00001 ..... ..... ..... @fff +fscaleb_d 0000 00010001 00010 ..... ..... ..... @fff +flogb_s 0000 00010001 01000 01001 ..... ..... @ff +flogb_d 0000 00010001 01000 01010 ..... ..... @ff +fcopysign_s 0000 00010001 00101 ..... ..... ..... @fff +fcopysign_d 0000 00010001 00110 ..... ..... ..... @fff +fclass_s 0000 00010001 01000 01101 ..... ..... @ff +fclass_d 0000 00010001 01000 01110 ..... ..... @ff + +# +# Floating point compare instruction +# +fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @cff_fcond +fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @cff_fcond + +# +# Floating point conversion instruction +# +fcvt_s_d 0000 00010001 10010 00110 ..... ..... @ff +fcvt_d_s 0000 00010001 10010 01001 ..... ..... @ff +ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @ff +ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @ff +ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @ff +ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @ff +ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @ff +ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @ff +ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @ff +ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @ff +ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @ff +ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @ff +ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @ff +ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @ff +ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @ff +ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @ff +ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @ff +ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @ff +ftint_w_s 0000 00010001 10110 00001 ..... ..... @ff +ftint_w_d 0000 00010001 10110 00010 ..... ..... @ff +ftint_l_s 0000 00010001 10110 01001 ..... ..... @ff +ftint_l_d 0000 00010001 10110 01010 ..... ..... @ff +ffint_s_w 0000 00010001 11010 00100 ..... ..... @ff +ffint_s_l 0000 00010001 11010 00110 ..... ..... @ff +ffint_d_w 0000 00010001 11010 01000 ..... ..... @ff +ffint_d_l 0000 00010001 11010 01010 ..... ..... @ff +frint_s 0000 00010001 11100 10001 ..... ..... @ff +frint_d 0000 00010001 11100 10010 ..... ..... @ff + +# +# Floating point move instruction +# +fmov_s 0000 00010001 01001 00101 ..... ..... @ff +fmov_d 0000 00010001 01001 00110 ..... ..... @ff +fsel 0000 11010000 00 ... ..... ..... ..... @fffc +movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fr +movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fr +movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fr +movfr2gr_s 0000 00010001 01001 01101 ..... ..... @rf +movfr2gr_d 0000 00010001 01001 01110 ..... ..... @rf +movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @rf +movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fcsrd_r +movfcsr2gr 0000 00010001 01001 10010 ..... ..... @r_fcsrs +movfr2cf 0000 00010001 01001 10100 ..... 00 ... @cf +movcf2fr 0000 00010001 01001 10101 00 ... ..... @fc +movgr2cf 0000 00010001 01001 10110 ..... 00 ... @cr +movcf2gr 0000 00010001 01001 10111 00 ... ..... @rc + +# +# Floating point load/store instruction +# +fld_s 0010 101100 ............ ..... ..... @fr_i12 +fst_s 0010 101101 ............ ..... ..... @fr_i12 +fld_d 0010 101110 ............ ..... ..... @fr_i12 +fst_d 0010 101111 ............ ..... ..... @fr_i12 +fldx_s 0011 10000011 00000 ..... ..... ..... @frr +fldx_d 0011 10000011 01000 ..... ..... ..... @frr +fstx_s 0011 10000011 10000 ..... ..... ..... @frr +fstx_d 0011 10000011 11000 ..... ..... ..... @frr +fldgt_s 0011 10000111 01000 ..... ..... ..... @frr +fldgt_d 0011 10000111 01001 ..... ..... ..... @frr +fldle_s 0011 10000111 01010 ..... ..... ..... @frr +fldle_d 0011 10000111 01011 ..... ..... ..... @frr +fstgt_s 0011 10000111 01100 ..... ..... ..... @frr +fstgt_d 0011 10000111 01101 ..... ..... ..... @frr +fstle_s 0011 10000111 01110 ..... ..... ..... @frr +fstle_d 0011 10000111 01111 ..... ..... ..... @frr + +# +# Branch instructions +# +beqz 0100 00 ................ ..... ..... @r_offs21 +bnez 0100 01 ................ ..... ..... @r_offs21 +bceqz 0100 10 ................ 00 ... ..... @c_offs21 +bcnez 0100 10 ................ 01 ... ..... @c_offs21 +jirl 0100 11 ................ ..... ..... @rr_offs16 +b 0101 00 .......................... @offs26 +bl 0101 01 .......................... @offs26 +beq 0101 10 ................ ..... ..... @rr_offs16 +bne 0101 11 ................ ..... ..... @rr_offs16 +blt 0110 00 ................ ..... ..... @rr_offs16 +bge 0110 01 ................ ..... ..... @rr_offs16 +bltu 0110 10 ................ ..... ..... @rr_offs16 +bgeu 0110 11 ................ ..... ..... @rr_offs16 + +# +# Core instructions +# +{ + csrrd 0000 0100 .............. 00000 ..... @r_csr + csrwr 0000 0100 .............. 00001 ..... @r_csr + csrxchg 0000 0100 .............. ..... ..... @rr_csr +} + +iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr +iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr +iocsrrd_w 0000 01100100 10000 00010 ..... ..... @rr +iocsrrd_d 0000 01100100 10000 00011 ..... ..... @rr +iocsrwr_b 0000 01100100 10000 00100 ..... ..... @rr +iocsrwr_h 0000 01100100 10000 00101 ..... ..... @rr +iocsrwr_w 0000 01100100 10000 00110 ..... ..... @rr +iocsrwr_d 0000 01100100 10000 00111 ..... ..... @rr +tlbsrch 0000 01100100 10000 01010 00000 00000 @empty +tlbrd 0000 01100100 10000 01011 00000 00000 @empty +tlbwr 0000 01100100 10000 01100 00000 00000 @empty +tlbfill 0000 01100100 10000 01101 00000 00000 @empty +tlbclr 0000 01100100 10000 01000 00000 00000 @empty +tlbflush 0000 01100100 10000 01001 00000 00000 @empty +invtlb 0000 01100100 10011 ..... ..... ..... @i_rr +cacop 0000 011000 ............ ..... ..... @cop_r_i +lddir 0000 01100100 00 ........ ..... ..... @rr_ui8 +ldpte 0000 01100100 01 ........ ..... 00000 @j_i +ertn 0000 01100100 10000 01110 00000 00000 @empty +idle 0000 01100100 10001 ............... @i15 +dbcl 0000 00000010 10101 ............... @i15 diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h new file mode 100644 index 000000000000..f01635aed629 --- /dev/null +++ b/target/loongarch/internals.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU -- internal functions and types + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_INTERNALS_H +#define LOONGARCH_INTERNALS_H + +#define FCMP_LT 0b0001 /* fp0 < fp1 */ +#define FCMP_EQ 0b0010 /* fp0 = fp1 */ +#define FCMP_UN 0b0100 /* unordered */ +#define FCMP_GT 0b1000 /* fp0 > fp1 */ + +#define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS) +#define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS) + +/* Global bit used for lddir/ldpte */ +#define LOONGARCH_PAGE_HUGE_SHIFT 6 +/* Global bit for huge page */ +#define LOONGARCH_HGLOBAL_SHIFT 12 + +void loongarch_translate_init(void); + +void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); + +void G_NORETURN do_raise_exception(CPULoongArchState *env, + uint32_t exception, + uintptr_t pc); + +const char *loongarch_exception_name(int32_t exception); + +void restore_fp_status(CPULoongArchState *env); + +#ifndef CONFIG_USER_ONLY +extern const VMStateDescription vmstate_loongarch_cpu; + +void loongarch_cpu_set_irq(void *opaque, int irq, int level); + +void loongarch_constant_timer_cb(void *opaque); +uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu); +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, + uint64_t value); + +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +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); + +#endif diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/iocsr_helper.c new file mode 100644 index 000000000000..505853e17b22 --- /dev/null +++ b/target/loongarch/iocsr_helper.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * Helpers for IOCSR reads/writes + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "tcg/tcg-ldst.h" + +#define GET_MEMTXATTRS(cas) \ + ((MemTxAttrs){.requester_id = env_cpu(cas)->cpu_index}) + +uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_ldub(&env->address_space_iocsr, r_addr, + GET_MEMTXATTRS(env), NULL); +} + +uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_lduw(&env->address_space_iocsr, r_addr, + GET_MEMTXATTRS(env), NULL); +} + +uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_ldl(&env->address_space_iocsr, r_addr, + GET_MEMTXATTRS(env), NULL); +} + +uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_ldq(&env->address_space_iocsr, r_addr, + GET_MEMTXATTRS(env), NULL); +} + +void helper_iocsrwr_b(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stb(&env->address_space_iocsr, w_addr, + val, GET_MEMTXATTRS(env), NULL); +} + +void helper_iocsrwr_h(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stw(&env->address_space_iocsr, w_addr, + val, GET_MEMTXATTRS(env), NULL); +} + +void helper_iocsrwr_w(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stl(&env->address_space_iocsr, w_addr, + val, GET_MEMTXATTRS(env), NULL); +} + +void helper_iocsrwr_d(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stq(&env->address_space_iocsr, w_addr, + val, GET_MEMTXATTRS(env), NULL); +} diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c new file mode 100644 index 000000000000..b1e523ea72c7 --- /dev/null +++ b/target/loongarch/machine.c @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch Machine State + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" +#include "internals.h" + +/* TLB state */ +const VMStateDescription vmstate_tlb = { + .name = "cpu/tlb", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(tlb_misc, LoongArchTLB), + VMSTATE_UINT64(tlb_entry0, LoongArchTLB), + VMSTATE_UINT64(tlb_entry1, LoongArchTLB), + VMSTATE_END_OF_LIST() + } +}; + +/* LoongArch CPU state */ + +const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + + VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), + VMSTATE_UINTTL(env.pc, LoongArchCPU), + VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32), + VMSTATE_UINT32(env.fcsr0, LoongArchCPU), + VMSTATE_BOOL_ARRAY(env.cf, LoongArchCPU, 8), + + /* Remaining CSRs */ + VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_EUEN, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MISC, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ECFG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ESTAT, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_BADV, LoongArchCPU), + VMSTATE_UINT64(env.CSR_BADI, LoongArchCPU), + VMSTATE_UINT64(env.CSR_EENTRY, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBIDX, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBEHI, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBELO0, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBELO1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ASID, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PGDL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PGDH, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PGD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PWCL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PWCH, LoongArchCPU), + VMSTATE_UINT64(env.CSR_STLBPS, LoongArchCPU), + VMSTATE_UINT64(env.CSR_RVACFG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRCFG1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRCFG2, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRCFG3, LoongArchCPU), + VMSTATE_UINT64_ARRAY(env.CSR_SAVE, LoongArchCPU, 16), + VMSTATE_UINT64(env.CSR_TID, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TCFG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TVAL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_CNTC, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TICLR, LoongArchCPU), + VMSTATE_UINT64(env.CSR_LLBCTL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_IMPCTL1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_IMPCTL2, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRENTRY, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRBADV, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRSAVE, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRELO0, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRELO1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBREHI, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRPRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRCTL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRINFO1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRINFO2, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRENTRY, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRSAVE, LoongArchCPU), + VMSTATE_UINT64(env.CSR_CTAG, LoongArchCPU), + VMSTATE_UINT64_ARRAY(env.CSR_DMW, LoongArchCPU, 4), + + /* Debug CSRs */ + VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), + /* TLB */ + VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, + 0, vmstate_tlb, LoongArchTLB), + + VMSTATE_END_OF_LIST() + }, +}; diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build new file mode 100644 index 000000000000..6376f9e84bca --- /dev/null +++ b/target/loongarch/meson.build @@ -0,0 +1,30 @@ +gen = decodetree.process('insns.decode') + +loongarch_ss = ss.source_set() +loongarch_ss.add(files( + 'cpu.c', + 'disas.c', +)) +loongarch_tcg_ss = ss.source_set() +loongarch_tcg_ss.add(gen) +loongarch_tcg_ss.add(files( + 'fpu_helper.c', + 'op_helper.c', + 'translate.c', + 'gdbstub.c', +)) +loongarch_tcg_ss.add(zlib) + +loongarch_softmmu_ss = ss.source_set() +loongarch_softmmu_ss.add(files( + 'machine.c', + 'tlb_helper.c', + 'constant_timer.c', + 'csr_helper.c', + 'iocsr_helper.c', +)) + +loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) + +target_arch += {'loongarch': loongarch_ss} +target_softmmu_arch += {'loongarch': loongarch_softmmu_ss} diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c new file mode 100644 index 000000000000..568c07160161 --- /dev/null +++ b/target/loongarch/op_helper.c @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation helpers for QEMU. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "internals.h" +#include "qemu/crc32c.h" +#include +#include "cpu-csr.h" + +/* Exceptions helpers */ +void helper_raise_exception(CPULoongArchState *env, uint32_t exception) +{ + do_raise_exception(env, exception, GETPC()); +} + +target_ulong helper_bitrev_w(target_ulong rj) +{ + return (int32_t)revbit32(rj); +} + +target_ulong helper_bitrev_d(target_ulong rj) +{ + return revbit64(rj); +} + +target_ulong helper_bitswap(target_ulong v) +{ + v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | + ((v & (target_ulong)0x5555555555555555ULL) << 1); + v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | + ((v & (target_ulong)0x3333333333333333ULL) << 2); + v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | + ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); + return v; +} + +/* loongarch assert op */ +void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +{ + if (rj > rk) { + do_raise_exception(env, EXCCODE_BCE, 0); + } +} + +void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +{ + if (rj <= rk) { + do_raise_exception(env, EXCCODE_BCE, 0); + } +} + +target_ulong helper_crc32(target_ulong val, target_ulong m, uint64_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) +{ + return rj >= ARRAY_SIZE(env->cpucfg) ? 0 : env->cpucfg[rj]; +} + +uint64_t helper_rdtime_d(CPULoongArchState *env) +{ +#ifdef CONFIG_USER_ONLY + return cpu_get_host_ticks(); +#else + uint64_t plv; + LoongArchCPU *cpu = env_archcpu(env); + + plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); + if (extract64(env->CSR_MISC, R_CSR_MISC_DRDTL_SHIFT + plv, 1)) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + + return cpu_loongarch_get_constant_timer_counter(cpu); +#endif +} + +#ifndef CONFIG_USER_ONLY +void helper_ertn(CPULoongArchState *env) +{ + uint64_t csr_pplv, csr_pie; + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); + csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE); + + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1); + env->pc = env->CSR_TLBRERA; + qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n", + __func__, env->CSR_TLBRERA); + } else { + csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV); + csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE); + + env->pc = env->CSR_ERA; + qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n", + __func__, env->CSR_ERA); + } + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie); + + env->lladdr = 1; +} + +void helper_idle(CPULoongArchState *env) +{ + CPUState *cs = env_cpu(env); + + cs->halted = 1; + do_raise_exception(env, EXCP_HLT, 0); +} +#endif diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c new file mode 100644 index 000000000000..c6d1de50fed1 --- /dev/null +++ b/target/loongarch/tlb_helper.c @@ -0,0 +1,764 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch TLB helpers + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + */ + +#include "qemu/osdep.h" +#include "qemu/guest-random.h" + +#include "cpu.h" +#include "internals.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/log.h" +#include "cpu-csr.h" + +enum { + TLBRET_MATCH = 0, + TLBRET_BADADDR = 1, + TLBRET_NOMATCH = 2, + TLBRET_INVALID = 3, + TLBRET_DIRTY = 4, + TLBRET_RI = 5, + TLBRET_XI = 6, + TLBRET_PE = 7, +}; + +static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + int access_type, int index, int mmu_idx) +{ + LoongArchTLB *tlb = &env->tlb[index]; + uint64_t plv = mmu_idx; + uint64_t tlb_entry, tlb_ppn; + uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + n = (address >> tlb_ps) & 0x1;/* Odd or even */ + + tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; + tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); + tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); + tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY, PPN); + tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY, NX); + tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY, NR); + tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY, RPLV); + + /* Check access rights */ + if (!tlb_v) { + return TLBRET_INVALID; + } + + if (access_type == MMU_INST_FETCH && tlb_nx) { + return TLBRET_XI; + } + + if (access_type == MMU_DATA_LOAD && tlb_nr) { + return TLBRET_RI; + } + + if (((tlb_rplv == 0) && (plv > tlb_plv)) || + ((tlb_rplv == 1) && (plv != tlb_plv))) { + return TLBRET_PE; + } + + if ((access_type == MMU_DATA_STORE) && !tlb_d) { + return TLBRET_DIRTY; + } + + /* + * tlb_entry contains ppn[47:12] while 16KiB ppn is [47:15] + * need adjust. + */ + *physical = (tlb_ppn << R_TLBENTRY_PPN_SHIFT) | + (address & MAKE_64BIT_MASK(0, tlb_ps)); + *prot = PAGE_READ; + if (tlb_d) { + *prot |= PAGE_WRITE; + } + if (!tlb_nx) { + *prot |= PAGE_EXEC; + } + return TLBRET_MATCH; +} + +/* + * One tlb entry holds an adjacent odd/even pair, the vpn is the + * content of the virtual page number divided by 2. So the + * compare vpn is bit[47:15] for 16KiB page. while the vppn + * field in tlb entry contains bit[47:13], so need adjust. + * virt_vpn = vaddr[47:13] + */ +static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, + int *index) +{ + LoongArchTLB *tlb; + uint16_t csr_asid, tlb_asid, stlb_idx; + uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps; + int i, compare_shift; + uint64_t vpn, tlb_vppn; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); + stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */ + compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + /* Search STLB */ + for (i = 0; i < 8; ++i) { + tlb = &env->tlb[i * 256 + stlb_idx]; + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + if (tlb_e) { + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + + if ((tlb_g == 1 || tlb_asid == csr_asid) && + (vpn == (tlb_vppn >> compare_shift))) { + *index = i * 256 + stlb_idx; + return true; + } + } + } + + /* Search MTLB */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { + tlb = &env->tlb[i]; + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + if (tlb_e) { + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + if ((tlb_g == 1 || tlb_asid == csr_asid) && + (vpn == (tlb_vppn >> compare_shift))) { + *index = i; + return true; + } + } + } + return false; +} + +static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int index, match; + + match = loongarch_tlb_search(env, address, &index); + if (match) { + return loongarch_map_tlb_entry(env, physical, prot, + address, access_type, index, mmu_idx); + } + + return TLBRET_NOMATCH; +} + +static int get_physical_address(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int user_mode = mmu_idx == MMU_IDX_USER; + int kernel_mode = mmu_idx == MMU_IDX_KERNEL; + uint32_t plv, base_c, base_v; + int64_t addr_high; + uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA); + uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG); + + /* Check PG and DA */ + if (da & !pg) { + *physical = address & TARGET_PHYS_MASK; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TLBRET_MATCH; + } + + plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT); + base_v = address >> TARGET_VIRT_ADDR_SPACE_BITS; + /* Check direct map window */ + for (int i = 0; i < 4; i++) { + base_c = env->CSR_DMW[i] >> TARGET_VIRT_ADDR_SPACE_BITS; + if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) { + *physical = dmw_va2pa(address); + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TLBRET_MATCH; + } + } + + /* Check valid extension */ + addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16); + if (!(addr_high == 0 || addr_high == -1)) { + return TLBRET_BADADDR; + } + + /* Mapped address */ + return loongarch_map_address(env, physical, prot, address, + access_type, mmu_idx); +} + +hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + hwaddr phys_addr; + int prot; + + if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, + cpu_mmu_index(env, false)) != 0) { + return -1; + } + return phys_addr; +} + +static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, + MMUAccessType access_type, int tlb_error) +{ + CPUState *cs = env_cpu(env); + + switch (tlb_error) { + default: + case TLBRET_BADADDR: + cs->exception_index = access_type == MMU_INST_FETCH + ? EXCCODE_ADEF : EXCCODE_ADEM; + break; + case TLBRET_NOMATCH: + /* No TLB match for a mapped address */ + if (access_type == MMU_DATA_LOAD) { + cs->exception_index = EXCCODE_PIL; + } else if (access_type == MMU_DATA_STORE) { + cs->exception_index = EXCCODE_PIS; + } else if (access_type == MMU_INST_FETCH) { + cs->exception_index = EXCCODE_PIF; + } + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1); + break; + case TLBRET_INVALID: + /* TLB match with no valid bit */ + if (access_type == MMU_DATA_LOAD) { + cs->exception_index = EXCCODE_PIL; + } else if (access_type == MMU_DATA_STORE) { + cs->exception_index = EXCCODE_PIS; + } else if (access_type == MMU_INST_FETCH) { + cs->exception_index = EXCCODE_PIF; + } + break; + case TLBRET_DIRTY: + /* TLB match but 'D' bit is cleared */ + cs->exception_index = EXCCODE_PME; + break; + case TLBRET_XI: + /* Execute-Inhibit Exception */ + cs->exception_index = EXCCODE_PNX; + break; + case TLBRET_RI: + /* Read-Inhibit Exception */ + cs->exception_index = EXCCODE_PNR; + break; + case TLBRET_PE: + /* Privileged Exception */ + cs->exception_index = EXCCODE_PPI; + break; + } + + if (tlb_error == TLBRET_NOMATCH) { + env->CSR_TLBRBADV = address; + env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN, + extract64(address, 13, 35)); + } else { + if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { + env->CSR_BADV = address; + } + env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); + } +} + +static void invalidate_tlb_entry(CPULoongArchState *env, int index) +{ + target_ulong addr, mask, pagesize; + uint8_t tlb_ps; + LoongArchTLB *tlb = &env->tlb[index]; + + int mmu_idx = cpu_mmu_index(env, false); + uint8_t tlb_v0 = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, V); + uint8_t tlb_v1 = FIELD_EX64(tlb->tlb_entry1, TLBENTRY, V); + uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + pagesize = MAKE_64BIT_MASK(tlb_ps, 1); + mask = MAKE_64BIT_MASK(0, tlb_ps + 1); + + if (tlb_v0) { + addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask; /* even */ + tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, + mmu_idx, TARGET_LONG_BITS); + } + + if (tlb_v1) { + addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & pagesize; /* odd */ + tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, + mmu_idx, TARGET_LONG_BITS); + } +} + +static void invalidate_tlb(CPULoongArchState *env, int index) +{ + LoongArchTLB *tlb; + uint16_t csr_asid, tlb_asid, tlb_g; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + tlb = &env->tlb[index]; + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + if (tlb_g == 0 && tlb_asid != csr_asid) { + return; + } + invalidate_tlb_entry(env, index); +} + +static void fill_tlb_entry(CPULoongArchState *env, int index) +{ + LoongArchTLB *tlb = &env->tlb[index]; + uint64_t lo0, lo1, csr_vppn; + uint16_t csr_asid; + uint8_t csr_ps; + + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); + csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN); + lo0 = env->CSR_TLBRELO0; + lo1 = env->CSR_TLBRELO1; + } else { + csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); + csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI, VPPN); + lo0 = env->CSR_TLBELO0; + lo1 = env->CSR_TLBELO1; + } + + if (csr_ps == 0) { + qemu_log_mask(CPU_LOG_MMU, "page size is 0\n"); + } + + /* Only MTLB has the ps fields */ + if (index >= LOONGARCH_STLB) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps); + } + + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn); + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1); + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid); + + tlb->tlb_entry0 = lo0; + tlb->tlb_entry1 = lo1; +} + +/* Return an random value between low and high */ +static uint32_t get_random_tlb(uint32_t low, uint32_t high) +{ + uint32_t val; + + qemu_guest_getrandom_nofail(&val, sizeof(val)); + return val % (high - low + 1) + low; +} + +void helper_tlbsrch(CPULoongArchState *env) +{ + int index, match; + + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + match = loongarch_tlb_search(env, env->CSR_TLBREHI, &index); + } else { + match = loongarch_tlb_search(env, env->CSR_TLBEHI, &index); + } + + if (match) { + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX, index); + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); + return; + } + + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); +} + +void helper_tlbrd(CPULoongArchState *env) +{ + LoongArchTLB *tlb; + int index; + uint8_t tlb_ps, tlb_e; + + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + tlb = &env->tlb[index]; + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + + if (!tlb_e) { + /* Invalid TLB entry */ + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); + env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID, 0); + env->CSR_TLBEHI = 0; + env->CSR_TLBELO0 = 0; + env->CSR_TLBELO1 = 0; + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, PS, 0); + } else { + /* Valid TLB entry */ + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, + PS, (tlb_ps & 0x3f)); + env->CSR_TLBEHI = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) << + R_TLB_MISC_VPPN_SHIFT; + env->CSR_TLBELO0 = tlb->tlb_entry0; + env->CSR_TLBELO1 = tlb->tlb_entry1; + } +} + +void helper_tlbwr(CPULoongArchState *env) +{ + int index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + + invalidate_tlb(env, index); + + if (FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, NE)) { + env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc, + TLB_MISC, E, 0); + return; + } + + fill_tlb_entry(env, index); +} + +void helper_tlbfill(CPULoongArchState *env) +{ + uint64_t address, entryhi; + int index, set, stlb_idx; + uint16_t pagesize, stlb_ps; + + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + entryhi = env->CSR_TLBREHI; + pagesize = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); + } else { + entryhi = env->CSR_TLBEHI; + pagesize = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); + } + + stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + + if (pagesize == stlb_ps) { + /* Only write into STLB bits [47:13] */ + address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_VPPN_SHIFT); + + /* Choose one set ramdomly */ + set = get_random_tlb(0, 7); + + /* Index in one set */ + stlb_idx = (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */ + + index = set * 256 + stlb_idx; + } else { + /* Only write into MTLB */ + index = get_random_tlb(LOONGARCH_STLB, LOONGARCH_TLB_MAX - 1); + } + + invalidate_tlb(env, index); + fill_tlb_entry(env, index); +} + +void helper_tlbclr(CPULoongArchState *env) +{ + LoongArchTLB *tlb; + int i, index; + uint16_t csr_asid, tlb_asid, tlb_g; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + + if (index < LOONGARCH_STLB) { + /* STLB. One line per operation */ + for (i = 0; i < 8; i++) { + tlb = &env->tlb[i * 256 + (index % 256)]; + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + if (!tlb_g && tlb_asid == csr_asid) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + } else if (index < LOONGARCH_TLB_MAX) { + /* All MTLB entries */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { + tlb = &env->tlb[i]; + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + if (!tlb_g && tlb_asid == csr_asid) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + } + + tlb_flush(env_cpu(env)); +} + +void helper_tlbflush(CPULoongArchState *env) +{ + int i, index; + + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + + if (index < LOONGARCH_STLB) { + /* STLB. One line per operation */ + for (i = 0; i < 8; i++) { + int s_idx = i * 256 + (index % 256); + env->tlb[s_idx].tlb_misc = FIELD_DP64(env->tlb[s_idx].tlb_misc, + TLB_MISC, E, 0); + } + } else if (index < LOONGARCH_TLB_MAX) { + /* All MTLB entries */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { + env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, + TLB_MISC, E, 0); + } + } + + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_all(CPULoongArchState *env) +{ + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, + TLB_MISC, E, 0); + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g) +{ + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + + if (tlb_g == g) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info) +{ + uint16_t asid = info & R_CSR_ASID_ASID_MASK; + + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + + if (!tlb_g && (tlb_asid == asid)) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info, + target_ulong addr) +{ + uint16_t asid = info & 0x3ff; + + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + uint64_t vpn, tlb_vppn; + uint8_t tlb_ps, compare_shift; + + if (i >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + if (!tlb_g && (tlb_asid == asid) && + (vpn == (tlb_vppn >> compare_shift))) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_page_asid_or_g(CPULoongArchState *env, + target_ulong info, target_ulong addr) +{ + uint16_t asid = info & 0x3ff; + + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + uint64_t vpn, tlb_vppn; + uint8_t tlb_ps, compare_shift; + + if (i >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + if ((tlb_g || (tlb_asid == asid)) && + (vpn == (tlb_vppn >> compare_shift))) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + hwaddr physical; + int prot; + int ret; + + /* Data access */ + ret = get_physical_address(env, &physical, &prot, address, + access_type, mmu_idx); + + if (ret == TLBRET_MATCH) { + tlb_set_page(cs, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot, + mmu_idx, TARGET_PAGE_SIZE); + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx + " prot %d\n", __func__, address, physical, prot); + return true; + } else { + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " ret %d\n", __func__, address, + ret); + } + if (probe) { + return false; + } + raise_mmu_exception(env, address, access_type, ret); + cpu_loop_exit_restore(cs, retaddr); +} + +target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, + target_ulong level, uint32_t mem_idx) +{ + CPUState *cs = env_cpu(env); + target_ulong badvaddr, index, phys, ret; + int shift; + uint64_t dir_base, dir_width; + bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; + + badvaddr = env->CSR_TLBRBADV; + base = base & TARGET_PHYS_MASK; + + /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ + shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); + shift = (shift + 1) * 3; + + if (huge) { + return base; + } + switch (level) { + case 1: + dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); + dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); + break; + case 2: + dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); + dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); + break; + case 3: + dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); + dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); + break; + case 4: + dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); + dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); + break; + default: + do_raise_exception(env, EXCCODE_INE, GETPC()); + return 0; + } + index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); + phys = base | index << shift; + ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; + return ret; +} + +void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, + uint32_t mem_idx) +{ + CPUState *cs = env_cpu(env); + target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; + int shift; + bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; + uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); + uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); + + base = base & TARGET_PHYS_MASK; + + if (huge) { + /* Huge Page. base is paddr */ + tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT); + /* Move Global bit */ + tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >> + LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT | + (tmp0 & (~(1 << R_TLBENTRY_G_SHIFT))); + ps = ptbase + ptwidth - 1; + if (odd) { + tmp0 += MAKE_64BIT_MASK(ps, 1); + } + } else { + /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ + shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); + shift = (shift + 1) * 3; + badv = env->CSR_TLBRBADV; + + ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1); + ptindex = ptindex & ~0x1; /* clear bit 0 */ + ptoffset0 = ptindex << shift; + ptoffset1 = (ptindex + 1) << shift; + + phys = base | (odd ? ptoffset1 : ptoffset0); + tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; + ps = ptbase; + } + + if (odd) { + env->CSR_TLBRELO1 = tmp0; + } else { + env->CSR_TLBRELO0 = tmp0; + } + env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps); +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c new file mode 100644 index 000000000000..38ced698031f --- /dev/null +++ b/target/loongarch/translate.c @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation for QEMU - main translation routines. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/tcg-op.h" +#include "exec/translator.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" + +#include "exec/translator.h" +#include "exec/log.h" +#include "qemu/qemu-print.h" +#include "fpu/softfloat.h" +#include "translate.h" +#include "internals.h" + +/* Global register indices */ +TCGv cpu_gpr[32], cpu_pc; +static TCGv cpu_lladdr, cpu_llval; +TCGv_i64 cpu_fpr[32]; + +#include "exec/gen-icount.h" + +#define DISAS_STOP DISAS_TARGET_0 +#define DISAS_EXIT DISAS_TARGET_1 +#define DISAS_EXIT_UPDATE DISAS_TARGET_2 + +static inline int plus_1(DisasContext *ctx, int x) +{ + return x + 1; +} + +static inline int shl_2(DisasContext *ctx, int x) +{ + return x << 2; +} + +/* + * LoongArch the upper 32 bits are undefined ("can be any value"). + * QEMU chooses to nanbox, because it is most likely to show guest bugs early. + */ +static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in) +{ + tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32)); +} + +void generate_exception(DisasContext *ctx, int excp) +{ + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); + ctx->base.is_jmp = DISAS_NORETURN; +} + +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + if (translator_use_goto_tb(&ctx->base, dest)) { + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(cpu_pc, dest); + tcg_gen_exit_tb(ctx->base.tb, n); + } else { + tcg_gen_movi_tl(cpu_pc, dest); + tcg_gen_lookup_and_goto_ptr(); + } +} + +static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, + CPUState *cs) +{ + int64_t bound; + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; + ctx->plv = ctx->base.tb->flags & HW_FLAGS_PLV_MASK; + if (ctx->base.tb->flags & HW_FLAGS_CRMD_PG) { + ctx->mem_idx = ctx->plv; + } else { + ctx->mem_idx = MMU_IDX_DA; + } + + /* Bound the number of insns to execute to those left on the page. */ + bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; + ctx->base.max_insns = MIN(ctx->base.max_insns, bound); + + ctx->ntemp = 0; + memset(ctx->temp, 0, sizeof(ctx->temp)); + + ctx->zero = tcg_constant_tl(0); +} + +static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) +{ +} + +static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + tcg_gen_insn_start(ctx->base.pc_next); +} + +/* + * Wrappers for getting reg values. + * + * The $zero register does not have cpu_gpr[0] allocated -- we supply the + * constant zero as a source, and an uninitialized sink as destination. + * + * Further, we may provide an extension for word operations. + */ +static TCGv temp_new(DisasContext *ctx) +{ + assert(ctx->ntemp < ARRAY_SIZE(ctx->temp)); + return ctx->temp[ctx->ntemp++] = tcg_temp_new(); +} + +static TCGv gpr_src(DisasContext *ctx, int reg_num, DisasExtend src_ext) +{ + TCGv t; + + if (reg_num == 0) { + return ctx->zero; + } + + switch (src_ext) { + case EXT_NONE: + return cpu_gpr[reg_num]; + case EXT_SIGN: + t = temp_new(ctx); + tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); + return t; + case EXT_ZERO: + t = temp_new(ctx); + tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); + return t; + } + g_assert_not_reached(); +} + +static TCGv gpr_dst(DisasContext *ctx, int reg_num, DisasExtend dst_ext) +{ + if (reg_num == 0 || dst_ext) { + return temp_new(ctx); + } + return cpu_gpr[reg_num]; +} + +static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) +{ + if (reg_num != 0) { + switch (dst_ext) { + case EXT_NONE: + tcg_gen_mov_tl(cpu_gpr[reg_num], t); + break; + case EXT_SIGN: + tcg_gen_ext32s_tl(cpu_gpr[reg_num], t); + break; + case EXT_ZERO: + tcg_gen_ext32u_tl(cpu_gpr[reg_num], t); + break; + default: + g_assert_not_reached(); + } + } +} + +#include "decode-insns.c.inc" +#include "insn_trans/trans_arith.c.inc" +#include "insn_trans/trans_shift.c.inc" +#include "insn_trans/trans_bit.c.inc" +#include "insn_trans/trans_memory.c.inc" +#include "insn_trans/trans_atomic.c.inc" +#include "insn_trans/trans_extra.c.inc" +#include "insn_trans/trans_farith.c.inc" +#include "insn_trans/trans_fcmp.c.inc" +#include "insn_trans/trans_fcnv.c.inc" +#include "insn_trans/trans_fmov.c.inc" +#include "insn_trans/trans_fmemory.c.inc" +#include "insn_trans/trans_branch.c.inc" +#include "insn_trans/trans_privileged.c.inc" + +static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +{ + CPULoongArchState *env = cs->env_ptr; + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); + + if (!decode(ctx, ctx->opcode)) { + qemu_log_mask(LOG_UNIMP, "Error: unknown opcode. " + TARGET_FMT_lx ": 0x%x\n", + ctx->base.pc_next, ctx->opcode); + generate_exception(ctx, EXCCODE_INE); + } + + for (int i = ctx->ntemp - 1; i >= 0; --i) { + tcg_temp_free(ctx->temp[i]); + ctx->temp[i] = NULL; + } + ctx->ntemp = 0; + + ctx->base.pc_next += 4; +} + +static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + switch (ctx->base.is_jmp) { + case DISAS_STOP: + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + tcg_gen_lookup_and_goto_ptr(); + break; + case DISAS_TOO_MANY: + gen_goto_tb(ctx, 0, ctx->base.pc_next); + break; + case DISAS_NORETURN: + break; + case DISAS_EXIT_UPDATE: + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + QEMU_FALLTHROUGH; + case DISAS_EXIT: + tcg_gen_exit_tb(NULL, 0); + break; + default: + g_assert_not_reached(); + } +} + +static void loongarch_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) +{ + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); +} + +static const TranslatorOps loongarch_tr_ops = { + .init_disas_context = loongarch_tr_init_disas_context, + .tb_start = loongarch_tr_tb_start, + .insn_start = loongarch_tr_insn_start, + .translate_insn = loongarch_tr_translate_insn, + .tb_stop = loongarch_tr_tb_stop, + .disas_log = loongarch_tr_disas_log, +}; + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) +{ + DisasContext ctx; + + translator_loop(cs, tb, max_insns, pc, host_pc, + &loongarch_tr_ops, &ctx.base); +} + +void loongarch_translate_init(void) +{ + int i; + + cpu_gpr[0] = NULL; + for (i = 1; i < 32; i++) { + cpu_gpr[i] = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, gpr[i]), + regnames[i]); + } + + for (i = 0; i < 32; i++) { + int off = offsetof(CPULoongArchState, fpr[i]); + cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); + } + + cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPULoongArchState, pc), "pc"); + cpu_lladdr = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, lladdr), "lladdr"); + cpu_llval = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, llval), "llval"); +} diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h new file mode 100644 index 000000000000..6d2e382e8b2b --- /dev/null +++ b/target/loongarch/translate.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch translation routines. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef TARGET_LOONGARCH_TRANSLATE_H +#define TARGET_LOONGARCH_TRANSLATE_H + +#include "exec/translator.h" + +#define TRANS(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \ + { return FUNC(ctx, a, __VA_ARGS__); } + +/* + * If an operation is being performed on less than TARGET_LONG_BITS, + * it may require the inputs to be sign- or zero-extended; which will + * depend on the exact operation being performed. + */ +typedef enum { + EXT_NONE, + EXT_SIGN, + EXT_ZERO, +} DisasExtend; + +typedef struct DisasContext { + DisasContextBase base; + target_ulong page_start; + uint32_t opcode; + uint16_t mem_idx; + uint16_t plv; + TCGv zero; + /* Space for 3 operands plus 1 extra for address computation. */ + TCGv temp[4]; + uint8_t ntemp; +} DisasContext; + +void generate_exception(DisasContext *ctx, int excp); + +extern TCGv cpu_gpr[32], cpu_pc; +extern TCGv_i32 cpu_fscr0; +extern TCGv_i64 cpu_fpr[32]; + +#endif diff --git a/target/m68k/cpu-param.h b/target/m68k/cpu-param.h index 06556dfbf3ee..44a8d193f0b8 100644 --- a/target/m68k/cpu-param.h +++ b/target/m68k/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef M68K_CPU_PARAM_H -#define M68K_CPU_PARAM_H 1 +#define M68K_CPU_PARAM_H #define TARGET_LONG_BITS 32 /* diff --git a/target/m68k/cpu-qom.h b/target/m68k/cpu-qom.h index cd9687192cd2..0ec7750a926b 100644 --- a/target/m68k/cpu-qom.h +++ b/target/m68k/cpu-qom.h @@ -30,7 +30,7 @@ OBJECT_DECLARE_CPU_TYPE(M68kCPU, M68kCPUClass, M68K_CPU) /* * M68kCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A Motorola 68k CPU model. */ @@ -40,7 +40,7 @@ struct M68kCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index c7aeb7da9c42..99af1ab541a6 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -31,6 +31,26 @@ 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 void m68k_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + M68kCPU *cpu = M68K_CPU(cs); + int cc_op = data[1]; + + cpu->env.pc = data[0]; + if (cc_op != CC_OP_DYNAMIC) { + cpu->env.cc_op = cc_op; + } +} + static bool m68k_cpu_has_work(CPUState *cs) { return cs->interrupt_request & CPU_INTERRUPT_HARD; @@ -38,24 +58,26 @@ 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) +static void m68k_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); M68kCPU *cpu = M68K_CPU(s); M68kCPUClass *mcc = M68K_CPU_GET_CLASS(cpu); CPUM68KState *env = &cpu->env; floatx80 nan = floatx80_default_nan(NULL); int i; - mcc->parent_reset(dev); + if (mcc->parent_phases.hold) { + mcc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUM68KState, end_reset_fields)); #ifdef CONFIG_SOFTMMU @@ -75,12 +97,8 @@ static void m68k_cpu_reset(DeviceState *dev) static void m68k_cpu_disas_set_info(CPUState *s, disassemble_info *info) { - M68kCPU *cpu = M68K_CPU(s); - CPUM68KState *env = &cpu->env; info->print_insn = print_insn_m68k; - if (m68k_feature(env, M68K_FEATURE_M68000)) { - info->mach = bfd_mach_m68040; - } + info->mach = 0; } /* CPU models */ @@ -106,6 +124,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 */ @@ -114,7 +133,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); @@ -133,6 +152,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); } /* @@ -162,6 +182,7 @@ static void m68020_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CHK2); m68k_set_feature(env, M68K_FEATURE_MSP); m68k_set_feature(env, M68K_FEATURE_UNALIGNED_DATA); + m68k_set_feature(env, M68K_FEATURE_TRAPCC); } /* @@ -244,6 +265,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) @@ -257,6 +279,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) @@ -278,6 +301,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) @@ -515,6 +539,7 @@ static const struct SysemuCPUOps m68k_sysemu_ops = { static const struct TCGCPUOps m68k_tcg_ops = { .initialize = m68k_tcg_init, + .restore_state_to_opc = m68k_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = m68k_cpu_tlb_fill, @@ -529,15 +554,18 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) M68kCPUClass *mcc = M68K_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); device_class_set_parent_realize(dc, m68k_cpu_realizefn, &mcc->parent_realize); - device_class_set_parent_reset(dc, m68k_cpu_reset, &mcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, m68k_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = m68k_cpu_class_by_name; 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 872e8ce63758..3a9cfe2f33a7 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -22,6 +22,7 @@ #define M68K_CPU_H #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" #include "cpu-qom.h" #define OS_BYTE 0 @@ -121,6 +122,12 @@ typedef struct CPUArchState { /* MMU status. */ struct { + /* + * Holds the "address" value in between raising an exception + * and creation of the exception stack frame. + * Used for both Format 7 exceptions (Access, i.e. mmu) + * and Format 2 exceptions (chk, div0, trapcc, etc). + */ uint32_t ar; uint32_t ssw; /* 68040 */ @@ -147,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; /* @@ -473,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, @@ -527,11 +535,15 @@ enum m68k_features { M68K_FEATURE_MOVEC, /* Unaligned data accesses (680[2346]0) */ 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 5728e48585fc..4621cf24027e 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/helper.h b/target/m68k/helper.h index 0a6b4146f635..c9bed2b88456 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -1,12 +1,12 @@ DEF_HELPER_1(bitrev, i32, i32) DEF_HELPER_1(ff1, i32, i32) DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32) -DEF_HELPER_3(divuw, void, env, int, i32) -DEF_HELPER_3(divsw, void, env, int, s32) -DEF_HELPER_4(divul, void, env, int, int, i32) -DEF_HELPER_4(divsl, void, env, int, int, s32) -DEF_HELPER_4(divull, void, env, int, int, i32) -DEF_HELPER_4(divsll, void, env, int, int, s32) +DEF_HELPER_4(divuw, void, env, int, i32, int) +DEF_HELPER_4(divsw, void, env, int, s32, int) +DEF_HELPER_5(divul, void, env, int, int, i32, int) +DEF_HELPER_5(divsl, void, env, int, int, s32, int) +DEF_HELPER_5(divull, void, env, int, int, i32, int) +DEF_HELPER_5(divsll, void, env, int, int, s32, int) DEF_HELPER_2(set_sr, void, env, i32) DEF_HELPER_3(cf_movec_to, void, env, i32, i32) DEF_HELPER_3(m68k_movec_to, void, env, i32, i32) @@ -109,7 +109,7 @@ DEF_HELPER_3(set_mac_extu, void, env, i32, i32) DEF_HELPER_2(flush_flags, void, env, i32) DEF_HELPER_2(set_ccr, void, env, i32) DEF_HELPER_FLAGS_1(get_ccr, TCG_CALL_NO_WG_SE, i32, env) -DEF_HELPER_2(raise_exception, void, env, i32) +DEF_HELPER_2(raise_exception, noreturn, env, i32) DEF_HELPER_FLAGS_3(bfffo_reg, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c index c5c164e096c8..87b13149253c 100644 --- a/target/m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c @@ -21,13 +21,9 @@ #include "cpu.h" #include "exec/gdbstub.h" -#if defined(CONFIG_USER_ONLY) -#include "qemu.h" -#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024) -#else -#include "exec/softmmu-semi.h" +#include "semihosting/syscalls.h" +#include "semihosting/softmmu-uaccess.h" #include "hw/boards.h" -#endif #include "qemu/log.h" #define HOSTED_EXIT 0 @@ -45,91 +41,43 @@ #define HOSTED_ISATTY 12 #define HOSTED_SYSTEM 13 -typedef uint32_t gdb_mode_t; -typedef uint32_t gdb_time_t; - -struct m68k_gdb_stat { - uint32_t gdb_st_dev; /* device */ - uint32_t gdb_st_ino; /* inode */ - gdb_mode_t gdb_st_mode; /* protection */ - uint32_t gdb_st_nlink; /* number of hard links */ - uint32_t gdb_st_uid; /* user ID of owner */ - uint32_t gdb_st_gid; /* group ID of owner */ - uint32_t gdb_st_rdev; /* device type (if inode device) */ - uint64_t gdb_st_size; /* total size, in bytes */ - uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ - uint64_t gdb_st_blocks; /* number of blocks allocated */ - gdb_time_t gdb_st_atime; /* time of last access */ - gdb_time_t gdb_st_mtime; /* time of last modification */ - gdb_time_t gdb_st_ctime; /* time of last change */ -} QEMU_PACKED; - -struct gdb_timeval { - gdb_time_t tv_sec; /* second */ - uint64_t tv_usec; /* microsecond */ -} QEMU_PACKED; - -#define GDB_O_RDONLY 0x0 -#define GDB_O_WRONLY 0x1 -#define GDB_O_RDWR 0x2 -#define GDB_O_APPEND 0x8 -#define GDB_O_CREAT 0x200 -#define GDB_O_TRUNC 0x400 -#define GDB_O_EXCL 0x800 - -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; +#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; + } +#undef E } -static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s) +static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err) { - struct m68k_gdb_stat *p; - - if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0))) - /* FIXME - should this return an error code? */ - return; - 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 m68k_gdb_stat)); -} + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; -static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, uint32_t 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. @@ -140,330 +88,147 @@ static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, uint32_t err) } } -static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, uint32_t err) +static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err) { + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + 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"); } } -static int m68k_semi_is_fseek; - -static void m68k_semi_cb(CPUState *cs, target_ulong ret, target_ulong err) -{ - M68kCPU *cpu = M68K_CPU(cs); - CPUM68KState *env = &cpu->env; - - if (m68k_semi_is_fseek) { - /* - * FIXME: We've already lost the high bits of the fseek - * return value. - */ - m68k_semi_return_u64(env, ret, err); - m68k_semi_is_fseek = 0; - } else { - m68k_semi_return_u32(env, ret, err); - } -} - /* * Read the input value from the argument block; fail the semihosting * call if the memory read fails. */ #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_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_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_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_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()) { - m68k_semi_is_fseek = 1; - gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x", - arg0, off, arg3); - } else { - off = lseek(arg0, off, arg3); - m68k_semi_return_u64(env, 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_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_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_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_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_cb, "gettimeofday,%x,%x", - arg0, arg1); - return; - } else { - qemu_timeval tv; - struct gdb_timeval *p; - result = qemu_gettimeofday(&tv); - if (result == 0) { - if (!(p = lock_user(VERIFY_WRITE, - arg0, sizeof(struct gdb_timeval), 0))) { - /* FIXME - check error code? */ - result = -1; - } else { - p->tv_sec = cpu_to_be32(tv.tv_sec); - p->tv_usec = cpu_to_be64(tv.tv_usec); - 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_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_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: -#if defined(CONFIG_USER_ONLY) - { - CPUState *cs = env_cpu(env); - TaskState *ts = cs->opaque; - /* Allocate the heap using sbrk. */ - if (!ts->heap_limit) { - abi_ulong ret; - uint32_t size; - uint32_t base; - base = do_brk(0); - size = SEMIHOSTING_HEAP_SIZE; - /* Try a big heap, and reduce the size if that fails. */ - for (;;) { - ret = do_brk(base + size); - if (ret >= (base + size)) { - break; - } - size >>= 1; - } - ts->heap_limit = base + size; - } - /* - * This call may happen before we have writable memory, so return - * values directly in registers. - */ - env->dregs[1] = ts->heap_limit; - env->aregs[7] = ts->stack_base; - } -#else + case HOSTED_INIT_SIM: /* * FIXME: This is wrong for boards where RAM does not start at * address zero. */ env->dregs[1] = current_machine->ram_size; env->aregs[7] = current_machine->ram_size; -#endif 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_return_u32(env, result, errno); } diff --git a/target/m68k/meson.build b/target/m68k/meson.build index 05cd9fbd1e8d..27d2d7ba874b 100644 --- a/target/m68k/meson.build +++ b/target/m68k/meson.build @@ -4,14 +4,16 @@ m68k_ss.add(files( 'fpu_helper.c', 'gdbstub.c', 'helper.c', - 'm68k-semi.c', 'op_helper.c', 'softfloat.c', 'translate.c', )) m68k_softmmu_ss = ss.source_set() -m68k_softmmu_ss.add(files('monitor.c')) +m68k_softmmu_ss.add(files( + 'm68k-semi.c', + 'monitor.c' +)) target_arch += {'m68k': m68k_ss} target_softmmu_arch += {'m68k': m68k_softmmu_ss} diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 8decc612409c..1ce850bbc594 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) { @@ -217,11 +216,6 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw) cpu_loop_exit(cs); return; } - if (cs->exception_index >= EXCP_TRAP0 - && cs->exception_index <= EXCP_TRAP15) { - /* Move the PC after the trap instruction. */ - retaddr += 2; - } } vector = cs->exception_index << 2; @@ -292,22 +286,15 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) { CPUState *cs = env_cpu(env); uint32_t sp; - uint32_t retaddr; uint32_t vector; uint16_t sr, oldsr; - retaddr = env->pc; - if (!is_hw) { switch (cs->exception_index) { case EXCP_RTE: /* Return from an exception. */ m68k_rte(env); return; - case EXCP_TRAP0 ... EXCP_TRAP15: - /* Move the PC after the trap instruction. */ - retaddr += 2; - break; } } @@ -342,7 +329,8 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) sp &= ~1; } - if (cs->exception_index == EXCP_ACCESS) { + switch (cs->exception_index) { + case EXCP_ACCESS: if (env->mmu.fault) { cpu_abort(cs, "DOUBLE MMU FAULT\n"); } @@ -393,36 +381,48 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) sp -= 4; cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0); - do_stack_frame(env, &sp, 7, oldsr, 0, retaddr); + do_stack_frame(env, &sp, 7, oldsr, 0, env->pc); env->mmu.fault = false; if (qemu_loglevel_mask(CPU_LOG_INT)) { qemu_log(" " "ssw: %08x ea: %08x sfc: %d dfc: %d\n", env->mmu.ssw, env->mmu.ar, env->sfc, env->dfc); } - } else if (cs->exception_index == EXCP_ADDRESS) { - do_stack_frame(env, &sp, 2, oldsr, 0, retaddr); - } else if (cs->exception_index == EXCP_ILLEGAL || - cs->exception_index == EXCP_DIV0 || - cs->exception_index == EXCP_CHK || - cs->exception_index == EXCP_TRAPCC || - cs->exception_index == EXCP_TRACE) { - /* FIXME: addr is not only env->pc */ - do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr); - } else if (is_hw && oldsr & SR_M && - cs->exception_index >= EXCP_SPURIOUS && - cs->exception_index <= EXCP_INT_LEVEL_7) { - do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); - oldsr = sr; - env->aregs[7] = sp; - cpu_m68k_set_sr(env, sr &= ~SR_M); - sp = env->aregs[7]; - if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { - sp &= ~1; + break; + + case EXCP_ILLEGAL: + do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); + break; + + case EXCP_ADDRESS: + do_stack_frame(env, &sp, 2, oldsr, 0, env->pc); + break; + + case EXCP_CHK: + case EXCP_DIV0: + case EXCP_TRACE: + case EXCP_TRAPCC: + do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc); + break; + + case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7: + if (is_hw && (oldsr & SR_M)) { + do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); + oldsr = sr; + env->aregs[7] = sp; + cpu_m68k_set_sr(env, sr & ~SR_M); + sp = env->aregs[7]; + if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { + sp &= ~1; + } + do_stack_frame(env, &sp, 1, oldsr, 0, env->pc); + break; } - do_stack_frame(env, &sp, 1, oldsr, 0, retaddr); - } else { - do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + /* fall through */ + + default: + do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); + break; } env->aregs[7] = sp; @@ -432,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; } @@ -460,7 +460,7 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, M68kCPU *cpu = M68K_CPU(cs); CPUM68KState *env = &cpu->env; - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); if (m68k_feature(env, M68K_FEATURE_M68040)) { env->mmu.mmusr = 0; @@ -531,7 +531,8 @@ bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) #endif /* !CONFIG_USER_ONLY */ -static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) +G_NORETURN static void +raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) { CPUState *cs = env_cpu(env); @@ -539,7 +540,7 @@ static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) cpu_loop_exit_restore(cs, raddr); } -static void raise_exception(CPUM68KState *env, int tt) +G_NORETURN static void raise_exception(CPUM68KState *env, int tt) { raise_exception_ra(env, tt, 0); } @@ -549,18 +550,42 @@ void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) raise_exception(env, tt); } -void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) +G_NORETURN static void +raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = tt; + + /* Recover PC and CC_OP for the beginning of the insn. */ + cpu_restore_state(cs, raddr); + + /* Flags are current in env->cc_*, or are undefined. */ + env->cc_op = CC_OP_FLAGS; + + /* + * Remember original pc in mmu.ar, for the Format 2 stack frame. + * Adjust PC to end of the insn. + */ + env->mmu.ar = env->pc; + env->pc += ilen; + + cpu_loop_exit(cs); +} + +void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den, int ilen) { uint32_t num = env->dregs[destr]; uint32_t quot, rem; + env->cc_c = 0; /* always cleared, even if div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot > 0xffff) { env->cc_v = -1; /* @@ -576,18 +601,19 @@ void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) env->cc_v = 0; } -void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) +void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den, int ilen) { int32_t num = env->dregs[destr]; uint32_t quot, rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot != (int16_t)quot) { env->cc_v = -1; /* nothing else is modified */ @@ -604,18 +630,20 @@ void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) env->cc_v = 0; } -void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) +void HELPER(divul)(CPUM68KState *env, int numr, int regr, + uint32_t den, int ilen) { uint32_t num = env->dregs[numr]; uint32_t quot, rem; + env->cc_c = 0; /* always cleared, even if div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; env->cc_z = quot; env->cc_n = quot; env->cc_v = 0; @@ -632,18 +660,20 @@ void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) } } -void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) +void HELPER(divsl)(CPUM68KState *env, int numr, int regr, + int32_t den, int ilen) { int32_t num = env->dregs[numr]; int32_t quot, rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; env->cc_z = quot; env->cc_n = quot; env->cc_v = 0; @@ -660,19 +690,21 @@ void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) } } -void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) +void HELPER(divull)(CPUM68KState *env, int numr, int regr, + uint32_t den, int ilen) { uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); uint64_t quot; uint32_t rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot > 0xffffffffULL) { env->cc_v = -1; /* @@ -695,19 +727,21 @@ void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) env->dregs[numr] = quot; } -void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den) +void HELPER(divsll)(CPUM68KState *env, int numr, int regr, + int32_t den, int ilen) { int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); int64_t quot; int32_t rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot != (int32_t)quot) { env->cc_v = -1; /* @@ -1066,18 +1100,7 @@ void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub) env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0; if (val < 0 || val > ub) { - CPUState *cs = env_cpu(env); - - /* Recover PC and CC_OP for the beginning of the insn. */ - cpu_restore_state(cs, GETPC(), true); - - /* flags have been modified by gen_flush_flags() */ - env->cc_op = CC_OP_FLAGS; - /* Adjust PC to end of the insn. */ - env->pc += 2; - - cs->exception_index = EXCP_CHK; - cpu_loop_exit(cs); + raise_exception_format2(env, EXCP_CHK, 2, GETPC()); } } @@ -1098,17 +1121,6 @@ void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub) env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb; if (env->cc_c) { - CPUState *cs = env_cpu(env); - - /* Recover PC and CC_OP for the beginning of the insn. */ - cpu_restore_state(cs, GETPC(), true); - - /* flags have been modified by gen_flush_flags() */ - env->cc_op = CC_OP_FLAGS; - /* Adjust PC to end of the insn. */ - env->pc += 4; - - cs->exception_index = EXCP_CHK; - cpu_loop_exit(cs); + raise_exception_format2(env, EXCP_CHK, 4, GETPC()); } } diff --git a/target/m68k/qregs.def b/target/m68k/qregs.h.inc similarity index 100% rename from target/m68k/qregs.def rename to target/m68k/qregs.h.inc diff --git a/target/m68k/translate.c b/target/m68k/translate.c index af43c8eab8e6..18418312b14b 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -39,7 +39,7 @@ #define DEFO32(name, offset) static TCGv QREG_##name; #define DEFO64(name, offset) static TCGv_i64 QREG_##name; -#include "qregs.def" +#include "qregs.h.inc" #undef DEFO32 #undef DEFO64 @@ -75,7 +75,7 @@ void m68k_tcg_init(void) #define DEFO64(name, offset) \ QREG_##name = tcg_global_mem_new_i64(cpu_env, \ offsetof(CPUM68KState, offset), #name); -#include "qregs.def" +#include "qregs.h.inc" #undef DEFO32 #undef DEFO64 @@ -114,6 +114,7 @@ typedef struct DisasContext { DisasContextBase base; CPUM68KState *env; target_ulong pc; + target_ulong pc_prev; CCOp cc_op; /* Current CC operation */ int cc_op_synced; TCGv_i64 mactmp; @@ -298,6 +299,21 @@ static void gen_raise_exception(int nr) tcg_temp_free_i32(tmp); } +static void gen_raise_exception_format2(DisasContext *s, int nr, + target_ulong this_pc) +{ + /* + * Pass the address of the insn to the exception handler, + * for recording in the Format $2 (6-word) stack frame. + * Re-use mmu.ar for the purpose, since that's only valid + * after tlb_fill. + */ + tcg_gen_st_i32(tcg_constant_i32(this_pc), cpu_env, + offsetof(CPUM68KState, mmu.ar)); + gen_raise_exception(nr); + s->base.is_jmp = DISAS_NORETURN; +} + static void gen_exception(DisasContext *s, uint32_t dest, int nr) { update_cc_op(s); @@ -455,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); } @@ -788,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)); @@ -872,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)); @@ -1494,12 +1510,13 @@ static void gen_exit_tb(DisasContext *s) } while (0) /* Generate a jump to an immediate address. */ -static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) +static void gen_jmp_tb(DisasContext *s, int n, target_ulong dest, + target_ulong src) { if (unlikely(s->ss_active)) { update_cc_op(s); tcg_gen_movi_i32(QREG_PC, dest); - gen_raise_exception(EXCP_TRACE); + gen_raise_exception_format2(s, EXCP_TRACE, src); } else if (translator_use_goto_tb(&s->base, dest)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(QREG_PC, dest); @@ -1548,9 +1565,9 @@ DISAS_INSN(dbcc) tcg_gen_addi_i32(tmp, tmp, -1); gen_partset_reg(OS_WORD, reg, tmp); tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1); - gen_jmp_tb(s, 1, base + offset); + gen_jmp_tb(s, 1, base + offset, s->base.pc_next); gen_set_label(l1); - gen_jmp_tb(s, 0, s->pc); + gen_jmp_tb(s, 0, s->pc, s->base.pc_next); } DISAS_INSN(undef_mac) @@ -1601,6 +1618,7 @@ DISAS_INSN(divw) int sign; TCGv src; TCGv destr; + TCGv ilen; /* divX.w ,Dn 32/16 -> 16r:16q */ @@ -1609,20 +1627,20 @@ DISAS_INSN(divw) /* dest.l / src.w */ SRC_EA(env, src, OS_WORD, sign, NULL); - destr = tcg_const_i32(REG(insn, 9)); + destr = tcg_constant_i32(REG(insn, 9)); + ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsw(cpu_env, destr, src); + gen_helper_divsw(cpu_env, destr, src, ilen); } else { - gen_helper_divuw(cpu_env, destr, src); + gen_helper_divuw(cpu_env, destr, src, ilen); } - tcg_temp_free(destr); set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(divl) { - TCGv num, reg, den; + TCGv num, reg, den, ilen; int sign; uint16_t ext; @@ -1639,15 +1657,14 @@ DISAS_INSN(divl) /* divX.l , Dr:Dq 64/32 -> 32r:32q */ SRC_EA(env, den, OS_LONG, 0, NULL); - num = tcg_const_i32(REG(ext, 12)); - reg = tcg_const_i32(REG(ext, 0)); + num = tcg_constant_i32(REG(ext, 12)); + reg = tcg_constant_i32(REG(ext, 0)); + ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsll(cpu_env, num, reg, den); + gen_helper_divsll(cpu_env, num, reg, den, ilen); } else { - gen_helper_divull(cpu_env, num, reg, den); + gen_helper_divull(cpu_env, num, reg, den, ilen); } - tcg_temp_free(reg); - tcg_temp_free(num); set_cc_op(s, CC_OP_FLAGS); return; } @@ -1656,15 +1673,14 @@ DISAS_INSN(divl) /* divXl.l , Dr:Dq 32/32 -> 32r:32q */ SRC_EA(env, den, OS_LONG, 0, NULL); - num = tcg_const_i32(REG(ext, 12)); - reg = tcg_const_i32(REG(ext, 0)); + num = tcg_constant_i32(REG(ext, 12)); + reg = tcg_constant_i32(REG(ext, 0)); + ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsl(cpu_env, num, reg, den); + gen_helper_divsl(cpu_env, num, reg, den, ilen); } else { - gen_helper_divul(cpu_env, num, reg, den); + gen_helper_divul(cpu_env, num, reg, den, ilen); } - tcg_temp_free(reg); - tcg_temp_free(num); set_cc_op(s, CC_OP_FLAGS); } @@ -2194,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; @@ -2269,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); } @@ -2281,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); @@ -2357,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); @@ -2366,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); @@ -2389,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); @@ -2809,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) @@ -2859,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)); @@ -3059,22 +3100,6 @@ DISAS_INSN(addsubq) tcg_temp_free(dest); } -DISAS_INSN(tpf) -{ - switch (insn & 7) { - case 2: /* One extension word. */ - s->pc += 2; - break; - case 3: /* Two extension words. */ - s->pc += 4; - break; - case 4: /* No extension words. */ - break; - default: - disas_undef(env, s, insn); - } -} - DISAS_INSN(branch) { int32_t offset; @@ -3097,13 +3122,13 @@ DISAS_INSN(branch) /* Bcc */ TCGLabel *l1 = gen_new_label(); gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1); - gen_jmp_tb(s, 1, base + offset); + gen_jmp_tb(s, 1, base + offset, s->base.pc_next); gen_set_label(l1); - gen_jmp_tb(s, 0, s->pc); + gen_jmp_tb(s, 0, s->pc, s->base.pc_next); } else { /* Unconditional branch. */ update_cc_op(s); - gen_jmp_tb(s, 0, base + offset); + gen_jmp_tb(s, 0, base + offset, s->base.pc_next); } } @@ -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; } @@ -4860,7 +4886,62 @@ DISAS_INSN(wdebug) DISAS_INSN(trap) { - gen_exception(s, s->base.pc_next, EXCP_TRAP0 + (insn & 0xf)); + gen_exception(s, s->pc, EXCP_TRAP0 + (insn & 0xf)); +} + +static void do_trapcc(DisasContext *s, DisasCompare *c) +{ + if (c->tcond != TCG_COND_NEVER) { + TCGLabel *over = NULL; + + update_cc_op(s); + + if (c->tcond != TCG_COND_ALWAYS) { + /* Jump over if !c. */ + over = gen_new_label(); + tcg_gen_brcond_i32(tcg_invert_cond(c->tcond), c->v1, c->v2, over); + } + + tcg_gen_movi_i32(QREG_PC, s->pc); + gen_raise_exception_format2(s, EXCP_TRAPCC, s->base.pc_next); + + if (over != NULL) { + gen_set_label(over); + s->base.is_jmp = DISAS_NEXT; + } + } + free_cond(c); +} + +DISAS_INSN(trapcc) +{ + DisasCompare c; + + /* Consume and discard the immediate operand. */ + switch (extract32(insn, 0, 3)) { + case 2: /* trapcc.w */ + (void)read_im16(env, s); + break; + case 3: /* trapcc.l */ + (void)read_im32(env, s); + break; + case 4: /* trapcc (no operand) */ + break; + default: + /* trapcc registered with only valid opmodes */ + g_assert_not_reached(); + } + + gen_cc_cond(&c, s, extract32(insn, 8, 4)); + do_trapcc(s, &c); +} + +DISAS_INSN(trapv) +{ + DisasCompare c; + + gen_cc_cond(&c, s, 9); /* V set */ + do_trapcc(s, &c); } static void gen_load_fcr(DisasContext *s, TCGv res, int reg) @@ -5486,9 +5567,9 @@ DISAS_INSN(fbcc) l1 = gen_new_label(); update_cc_op(s); gen_fjmpcc(s, insn & 0x3f, l1); - gen_jmp_tb(s, 0, s->pc); + gen_jmp_tb(s, 0, s->pc, s->base.pc_next); gen_set_label(l1); - gen_jmp_tb(s, 1, base + offset); + gen_jmp_tb(s, 1, base + offset, s->base.pc_next); } DISAS_INSN(fscc) @@ -5511,6 +5592,34 @@ DISAS_INSN(fscc) tcg_temp_free(tmp); } +DISAS_INSN(ftrapcc) +{ + DisasCompare c; + uint16_t ext; + int cond; + + ext = read_im16(env, s); + cond = ext & 0x3f; + + /* Consume and discard the immediate operand. */ + switch (extract32(insn, 0, 3)) { + case 2: /* ftrapcc.w */ + (void)read_im16(env, s); + break; + case 3: /* ftrapcc.l */ + (void)read_im32(env, s); + break; + case 4: /* ftrapcc (no operand) */ + break; + default: + /* ftrapcc registered with only valid opmodes */ + g_assert_not_reached(); + } + + gen_fcc_cond(&c, s, cond); + do_trapcc(s, &c); +} + #if defined(CONFIG_SOFTMMU) DISAS_INSN(frestore) { @@ -5809,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); } @@ -5928,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); @@ -5937,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); @@ -5966,43 +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, M68K); #endif INSN(pulse, 4acc, ffff, CF_ISA_A); BASE(illegal, 4afc, ffff); @@ -6017,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); @@ -6026,15 +6138,19 @@ void register_m68k_insns (CPUM68KState *env) BASE(nop, 4e71, ffff); INSN(rtd, 4e74, ffff, RTD); BASE(rts, 4e75, ffff); - 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(tpf, 51f8, fff8, CF_ISA_A); + 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 */ + INSN(trapcc, 51fc, ffff, CF_ISA_A); /* TPF (trapf) opmode 100 */ /* Branch instructions. */ BASE(branch, 6000, f000); @@ -6049,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); @@ -6078,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); @@ -6132,6 +6248,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(fbcc, f280, ffc0, CF_FPU); INSN(fpu, f200, ffc0, FPU); INSN(fscc, f240, ffc0, FPU); + INSN(ftrapcc, f27a, fffe, FPU); /* opmode 010, 011 */ + INSN(ftrapcc, f27c, ffff, FPU); /* opmode 100 */ INSN(fbcc, f280, ff80, FPU); #if defined(CONFIG_SOFTMMU) INSN(frestore, f340, ffc0, CF_FPU); @@ -6159,6 +6277,8 @@ static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->env = env; dc->pc = dc->base.pc_first; + /* This value will always be filled in properly before m68k_tr_tb_stop. */ + dc->pc_prev = 0xdeadbeef; dc->cc_op = CC_OP_DYNAMIC; dc->cc_op_synced = 1; dc->done_mac = 0; @@ -6192,6 +6312,7 @@ static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) do_writebacks(dc); do_release(dc); + dc->pc_prev = dc->base.pc_next; dc->base.pc_next = dc->pc; if (dc->base.is_jmp == DISAS_NEXT) { @@ -6226,17 +6347,12 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) break; case DISAS_TOO_MANY: update_cc_op(dc); - if (dc->ss_active) { - tcg_gen_movi_i32(QREG_PC, dc->pc); - gen_raise_exception(EXCP_TRACE); - } else { - gen_jmp_tb(dc, 0, dc->pc); - } + gen_jmp_tb(dc, 0, dc->pc, dc->pc_prev); break; case DISAS_JUMP: /* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */ if (dc->ss_active) { - gen_raise_exception(EXCP_TRACE); + gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev); } else { tcg_gen_lookup_and_goto_ptr(); } @@ -6247,7 +6363,7 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) * other state that may require returning to the main loop. */ if (dc->ss_active) { - gen_raise_exception(EXCP_TRACE); + gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev); } else { tcg_gen_exit_tb(NULL, 0); } @@ -6257,10 +6373,11 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void m68k_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void m68k_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps m68k_tr_ops = { @@ -6272,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) @@ -6361,13 +6479,3 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, int flags) env->mmu.mmusr, env->mmu.ar); #endif } - -void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb, - target_ulong *data) -{ - int cc_op = data[1]; - env->pc = data[0]; - if (cc_op != CC_OP_DYNAMIC) { - env->cc_op = cc_op; - } -} diff --git a/target/meson.build b/target/meson.build index 2f6940255e65..a53a60486fcc 100644 --- a/target/meson.build +++ b/target/meson.build @@ -5,6 +5,7 @@ subdir('cris') subdir('hexagon') subdir('hppa') subdir('i386') +subdir('loongarch') subdir('m68k') subdir('microblaze') subdir('mips') diff --git a/target/microblaze/cpu-param.h b/target/microblaze/cpu-param.h index 4d8297fa9407..5e54ea010818 100644 --- a/target/microblaze/cpu-param.h +++ b/target/microblaze/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef MICROBLAZE_CPU_PARAM_H -#define MICROBLAZE_CPU_PARAM_H 1 +#define MICROBLAZE_CPU_PARAM_H /* * While system mode can address up to 64 bits of address space, diff --git a/target/microblaze/cpu-qom.h b/target/microblaze/cpu-qom.h index 255b39a45dfa..cda9220fa99f 100644 --- a/target/microblaze/cpu-qom.h +++ b/target/microblaze/cpu-qom.h @@ -30,7 +30,7 @@ OBJECT_DECLARE_CPU_TYPE(MicroBlazeCPU, MicroBlazeCPUClass, MICROBLAZE_CPU) /** * MicroBlazeCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A MicroBlaze CPU model. */ @@ -40,7 +40,7 @@ struct MicroBlazeCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index aed200dcff83..817681f9b218 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -84,15 +84,32 @@ 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; } +static void mb_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + + cpu->env.pc = data[0]; + cpu->env.iflags = data[1]; +} + static bool mb_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); @@ -145,14 +162,16 @@ static void microblaze_cpu_set_irq(void *opaque, int irq, int level) } #endif -static void mb_cpu_reset(DeviceState *dev) +static void mb_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); MicroBlazeCPU *cpu = MICROBLAZE_CPU(s); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu); CPUMBState *env = &cpu->env; - mcc->parent_reset(dev); + if (mcc->parent_phases.hold) { + mcc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUMBState, end_reset_fields)); env->res_addr = RES_ADDR_NONE; @@ -366,6 +385,7 @@ static const struct SysemuCPUOps mb_sysemu_ops = { static const struct TCGCPUOps mb_tcg_ops = { .initialize = mb_tcg_init, .synchronize_from_tb = mb_cpu_synchronize_from_tb, + .restore_state_to_opc = mb_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = mb_cpu_tlb_fill, @@ -381,16 +401,19 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, mb_cpu_realizefn, &mcc->parent_realize); - device_class_set_parent_reset(dc, mb_cpu_reset, &mcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, mb_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = mb_cpu_class_by_name; cc->has_work = mb_cpu_has_work; 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/cpu.h b/target/microblaze/cpu.h index 0a0ce71b6a5c..1e84dd8f47bb 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -22,7 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" -#include "fpu/softfloat-types.h" +#include "qemu/cpu-float.h" typedef struct CPUArchState CPUMBState; #if !defined(CONFIG_USER_ONLY) @@ -359,9 +359,9 @@ struct ArchCPU { void mb_cpu_do_interrupt(CPUState *cs); bool mb_cpu_exec_interrupt(CPUState *cs, int int_req); #endif /* !CONFIG_USER_ONLY */ -void mb_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void mb_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr mb_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs); diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index a607fe68e587..98bdb82de874 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -277,7 +277,7 @@ void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, uint32_t esr, iflags; /* Recover the pc and iflags from the corresponding insn_start. */ - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); iflags = cpu->env.iflags; qemu_log_mask(CPU_LOG_INT, diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 2561b904b9c2..974f21eb3136 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1833,10 +1833,11 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) } } -static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) +static void mb_tr_disas_log(const DisasContextBase *dcb, + CPUState *cs, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); - log_target_disas(cs, dcb->pc_first, dcb->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first)); + target_disas(logfile, cs, dcb->pc_first, dcb->tb->size); } static const TranslatorOps mb_tr_ops = { @@ -1848,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) @@ -1944,10 +1946,3 @@ void mb_tcg_init(void) cpu_res_addr = tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); } - -void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; - env->iflags = data[1]; -} diff --git a/target/mips/TODO b/target/mips/TODO deleted file mode 100644 index 1d782d8027e0..000000000000 --- a/target/mips/TODO +++ /dev/null @@ -1,51 +0,0 @@ -Unsolved issues/bugs in the mips/mipsel backend ------------------------------------------------ - -General -------- -- Unimplemented ASEs: - - MDMX - - SmartMIPS - - microMIPS DSP r1 & r2 encodings -- MT ASE only partially implemented and not functional -- Shadow register support only partially implemented, - lacks set switching on interrupt/exception. -- 34K ITC not implemented. -- A general lack of documentation, especially for technical internals. - Existing documentation is x86-centric. -- Reverse endianness bit not implemented -- The TLB emulation is very inefficient: - QEMU's softmmu implements a x86-style MMU, with separate entries - for read/write/execute, a TLB index which is just a modulo of the - virtual address, and a set of TLBs for each user/kernel/supervisor - MMU mode. - MIPS has a single entry for read/write/execute and only one MMU mode. - But it is fully associative with randomized entry indices, and uses - up to 256 ASID tags as additional matching criterion (which roughly - equates to 256 MMU modes). It also has a global flag which causes - entries to match regardless of ASID. - To cope with these differences, QEMU currently flushes the TLB at - each ASID change. Using the MMU modes to implement ASIDs hinges on - implementing the global bit efficiently. -- save/restore of the CPU state is not implemented (see machine.c). - -MIPS64 ------- -- Userland emulation (both n32 and n64) not functional. - -"Generic" 4Kc system emulation ------------------------------- -- Doesn't correspond to any real hardware. Should be removed some day, - U-Boot is the last remaining user. - -PICA 61 system emulation ------------------------- -- No framebuffer support yet. - -MALTA system emulation ----------------------- -- We fake firmware support instead of doing the real thing -- Real firmware (YAMON) falls over when trying to init RAM, presumably - due to lacking system controller emulation. -- Bonito system controller not implemented -- MSC1 system controller not implemented diff --git a/target/mips/cpu-defs.c.inc b/target/mips/cpu-defs.c.inc index 582f94007022..480e60aeec8f 100644 --- a/target/mips/cpu-defs.c.inc +++ b/target/mips/cpu-defs.c.inc @@ -921,6 +921,34 @@ const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSP_R2, .mmu_type = MMU_TYPE_R4000, }, + { + /* + * Octeon 68xx with MIPS64 Cavium Octeon features. + */ + .name = "Octeon68XX", + .CP0_PRid = 0x000D9100, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (0x3F << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA), + .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | + (0x3c << CP0C4_KScrExist) | (1U << CP0C4_MMUExtDef) | + (3U << CP0C4_MMUSizeExt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .CP0_PageGrain = (1 << CP0PG_ELPA), + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x12F8FFFF, + .SEGBITS = 42, + .PABITS = 49, + .insn_flags = CPU_MIPS64R2 | INSN_OCTEON, + .mmu_type = MMU_TYPE_R4000, + }, #endif }; diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h index 1aebd01df9c2..f4c76994ea4b 100644 --- a/target/mips/cpu-param.h +++ b/target/mips/cpu-param.h @@ -5,7 +5,7 @@ */ #ifndef MIPS_CPU_PARAM_H -#define MIPS_CPU_PARAM_H 1 +#define MIPS_CPU_PARAM_H #ifdef TARGET_MIPS64 # define TARGET_LONG_BITS 64 diff --git a/target/mips/cpu-qom.h b/target/mips/cpu-qom.h index e28b52960731..0dffab453b24 100644 --- a/target/mips/cpu-qom.h +++ b/target/mips/cpu-qom.h @@ -34,7 +34,7 @@ OBJECT_DECLARE_CPU_TYPE(MIPSCPU, MIPSCPUClass, MIPS_CPU) /** * MIPSCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A MIPS CPU model. */ @@ -44,7 +44,7 @@ struct MIPSCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; const struct mips_def_t *cpu_def; /* Used for the jazz board to modify mips_cpu_do_transaction_failed. */ diff --git a/target/mips/cpu.c b/target/mips/cpu.c index af287177d5af..c614b04607a2 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); @@ -175,21 +182,23 @@ static bool mips_cpu_has_work(CPUState *cs) #include "cpu-defs.c.inc" -static void mips_cpu_reset(DeviceState *dev) +static void mips_cpu_reset_hold(Object *obj) { - CPUState *cs = CPU(dev); + CPUState *cs = CPU(obj); MIPSCPU *cpu = MIPS_CPU(cs); MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu); CPUMIPSState *env = &cpu->env; - mcc->parent_reset(dev); + if (mcc->parent_phases.hold) { + mcc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUMIPSState, end_reset_fields)); /* Reset registers to their default values */ env->CP0_PRid = env->cpu_model->CP0_PRid; env->CP0_Config0 = env->cpu_model->CP0_Config0; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN env->CP0_Config0 |= (1 << CP0C0_BE); #endif env->CP0_Config1 = env->cpu_model->CP0_Config1; @@ -295,6 +304,12 @@ static void mips_cpu_reset(DeviceState *dev) env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ? 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); + if (env->insn_flags & INSN_LOONGSON2F) { + /* Loongson-2F has those bits hardcoded to 1 */ + env->CP0_Status |= (1 << CP0St_KX) | (1 << CP0St_SX) | + (1 << CP0St_UX); + } + /* * Vectored interrupts not implemented, timer on int 7, * no performance counters. @@ -305,7 +320,7 @@ static void mips_cpu_reset(DeviceState *dev) for (i = 0; i < 7; i++) { env->CP0_WatchLo[i] = 0; - env->CP0_WatchHi[i] = 0x80000000; + env->CP0_WatchHi[i] = 1 << CP0WH_M; } env->CP0_WatchLo[7] = 0; env->CP0_WatchHi[7] = 0; @@ -418,7 +433,7 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) CPUMIPSState *env = &cpu->env; if (!(env->insn_flags & ISA_NANOMIPS32)) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN info->print_insn = print_insn_big_mips; #else info->print_insn = print_insn_little_mips; @@ -531,6 +546,7 @@ static const struct SysemuCPUOps mips_sysemu_ops = { static const struct TCGCPUOps mips_tcg_ops = { .initialize = mips_tcg_init, .synchronize_from_tb = mips_cpu_synchronize_from_tb, + .restore_state_to_opc = mips_restore_state_to_opc, #if !defined(CONFIG_USER_ONLY) .tlb_fill = mips_cpu_tlb_fill, @@ -548,15 +564,18 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) MIPSCPUClass *mcc = MIPS_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); device_class_set_parent_realize(dc, mips_cpu_realizefn, &mcc->parent_realize); - device_class_set_parent_reset(dc, mips_cpu_reset, &mcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, mips_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = mips_cpu_class_by_name; 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/cpu.h b/target/mips/cpu.h index 52ce08a94d36..0a085643a3f1 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -35,7 +35,7 @@ union fpr_t { *define FP_ENDIAN_IDX to access the same location * in the fpr_t union regardless of the host endianness */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN # define FP_ENDIAN_IDX 1 #else # define FP_ENDIAN_IDX 0 @@ -1005,6 +1005,7 @@ typedef struct CPUArchState { */ uint64_t CP0_WatchHi[8]; #define CP0WH_ASID 16 +#define CP0WH_M 31 /* * CP0 Register 20 */ @@ -1076,7 +1077,7 @@ typedef struct CPUArchState { #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x1F5807FF +#define MIPS_HFLAG_TMASK 0x3F5807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* * The KSU flags must be the lowest bits in hflags. The flag order @@ -1251,8 +1252,9 @@ enum { EXCP_MSAFPE, EXCP_TLBXI, EXCP_TLBRI, + EXCP_SEMIHOST, - EXCP_LAST = EXCP_TLBRI, + EXCP_LAST = EXCP_SEMIHOST, }; /* diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 086debd9f013..bcb8e06b2cb4 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -14,7 +14,6 @@ #include -#include "qemu-common.h" #include "cpu.h" #include "internal.h" #include "qemu/error-report.h" @@ -1295,3 +1294,7 @@ bool kvm_arch_cpu_check_are_resettable(void) { return true; } + +void kvm_arch_accel_class_init(ObjectClass *oc) +{ +} diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index 0a12d982a722..a6cebe0265cf 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -42,6 +42,7 @@ #define INSN_LOONGSON2E 0x0000040000000000ULL #define INSN_LOONGSON2F 0x0000080000000000ULL #define INSN_LOONGSON3A 0x0000100000000000ULL +#define INSN_OCTEON 0x0000200000000000ULL /* * bits 52-63: vendor-specific ASEs */ diff --git a/target/mips/tcg/dsp_helper.c b/target/mips/tcg/dsp_helper.c index 09b6e5fb15aa..7a4362c8ef49 100644 --- a/target/mips/tcg/dsp_helper.c +++ b/target/mips/tcg/dsp_helper.c @@ -3281,15 +3281,12 @@ target_ulong helper_dextr_l(target_ulong ac, target_ulong shift, CPUMIPSState *env) { uint64_t temp[3]; - target_ulong ret; shift = shift & 0x3F; mipsdsp_rndrashift_acc(temp, ac, shift, env); - ret = (temp[1] << 63) | (temp[0] >> 1); - - return ret; + return (temp[1] << 63) | (temp[0] >> 1); } target_ulong helper_dextr_r_l(target_ulong ac, target_ulong shift, @@ -3297,7 +3294,6 @@ target_ulong helper_dextr_r_l(target_ulong ac, target_ulong shift, { uint64_t temp[3]; uint32_t temp128; - target_ulong ret; shift = shift & 0x3F; mipsdsp_rndrashift_acc(temp, ac, shift, env); @@ -3317,9 +3313,7 @@ target_ulong helper_dextr_r_l(target_ulong ac, target_ulong shift, set_DSPControl_overflow_flag(1, 23, env); } - ret = (temp[1] << 63) | (temp[0] >> 1); - - return ret; + return (temp[1] << 63) | (temp[0] >> 1); } target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift, @@ -3327,7 +3321,6 @@ target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift, { uint64_t temp[3]; uint32_t temp128; - target_ulong ret; shift = shift & 0x3F; mipsdsp_rndrashift_acc(temp, ac, shift, env); @@ -3354,9 +3347,7 @@ target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift, set_DSPControl_overflow_flag(1, 23, env); } - ret = (temp[1] << 63) | (temp[0] >> 1); - - return ret; + return (temp[1] << 63) | (temp[0] >> 1); } #endif diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c index 0b21e0872bd1..96e61170e608 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; } @@ -125,6 +125,7 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_TLBRI] = "TLB read-inhibit", [EXCP_MSADIS] = "MSA disabled", [EXCP_MSAFPE] = "MSA floating point", + [EXCP_SEMIHOST] = "Semihosting", }; const char *mips_exception_name(int32_t exception) diff --git a/target/mips/tcg/lmmi_helper.c b/target/mips/tcg/lmmi_helper.c index abeb7736aeb2..2c8732525ce3 100644 --- a/target/mips/tcg/lmmi_helper.c +++ b/target/mips/tcg/lmmi_helper.c @@ -37,7 +37,7 @@ typedef union { } LMIValue; /* Some byte ordering issues can be mitigated by XORing in the following. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define BYTE_ORDER_XOR(N) N #else # define BYTE_ORDER_XOR(N) 0 diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build index 98003779ae8b..7ee969ec8f23 100644 --- a/target/mips/tcg/meson.build +++ b/target/mips/tcg/meson.build @@ -3,6 +3,7 @@ gen = [ decodetree.process('msa.decode', extra_args: '--decode=decode_ase_msa'), decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'), decodetree.process('vr54xx.decode', extra_args: '--decode=decode_ext_vr54xx'), + decodetree.process('octeon.decode', extra_args: '--decode=decode_ext_octeon'), ] mips_ss.add(gen) @@ -24,6 +25,7 @@ mips_ss.add(files( )) mips_ss.add(when: 'TARGET_MIPS64', if_true: files( 'tx79_translate.c', + 'octeon_translate.c', ), if_false: files( 'mxu_translate.c', )) diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc index fc6ede75b804..632895cc9ef0 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))) { - gen_helper_do_semihosting(cpu_env); + 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))) { - gen_helper_do_semihosting(cpu_env); + 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))) { - gen_helper_do_semihosting(cpu_env); + 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 f57e0a5f2a95..918b15d55ce8 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))) { - gen_helper_do_semihosting(cpu_env); + 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/msa_helper.c b/target/mips/tcg/msa_helper.c index 5667b1f0a15c..736283e2af8c 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -4146,7 +4146,7 @@ void helper_msa_ilvev_b(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->b[8] = pws->b[9]; pwd->b[9] = pwt->b[9]; pwd->b[10] = pws->b[11]; @@ -4190,7 +4190,7 @@ void helper_msa_ilvev_h(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->h[4] = pws->h[5]; pwd->h[5] = pwt->h[5]; pwd->h[6] = pws->h[7]; @@ -4218,7 +4218,7 @@ void helper_msa_ilvev_w(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->w[2] = pws->w[3]; pwd->w[3] = pwt->w[3]; pwd->w[0] = pws->w[1]; @@ -4250,7 +4250,7 @@ void helper_msa_ilvod_b(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->b[7] = pwt->b[6]; pwd->b[6] = pws->b[6]; pwd->b[5] = pwt->b[4]; @@ -4294,7 +4294,7 @@ void helper_msa_ilvod_h(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->h[3] = pwt->h[2]; pwd->h[2] = pws->h[2]; pwd->h[1] = pwt->h[0]; @@ -4322,7 +4322,7 @@ void helper_msa_ilvod_w(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->w[1] = pwt->w[0]; pwd->w[0] = pws->w[0]; pwd->w[3] = pwt->w[2]; @@ -4354,7 +4354,7 @@ void helper_msa_ilvl_b(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->b[7] = pwt->b[15]; pwd->b[6] = pws->b[15]; pwd->b[5] = pwt->b[14]; @@ -4398,7 +4398,7 @@ void helper_msa_ilvl_h(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->h[3] = pwt->h[7]; pwd->h[2] = pws->h[7]; pwd->h[1] = pwt->h[6]; @@ -4426,7 +4426,7 @@ void helper_msa_ilvl_w(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->w[1] = pwt->w[3]; pwd->w[0] = pws->w[3]; pwd->w[3] = pwt->w[2]; @@ -4458,7 +4458,7 @@ void helper_msa_ilvr_b(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->b[8] = pws->b[0]; pwd->b[9] = pwt->b[0]; pwd->b[10] = pws->b[1]; @@ -4502,7 +4502,7 @@ void helper_msa_ilvr_h(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->h[4] = pws->h[0]; pwd->h[5] = pwt->h[0]; pwd->h[6] = pws->h[1]; @@ -4530,7 +4530,7 @@ void helper_msa_ilvr_w(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->w[2] = pws->w[0]; pwd->w[3] = pwt->w[0]; pwd->w[0] = pws->w[1]; @@ -4661,7 +4661,7 @@ void helper_msa_pckev_b(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->b[8] = pws->b[9]; pwd->b[10] = pws->b[13]; pwd->b[12] = pws->b[1]; @@ -4705,7 +4705,7 @@ void helper_msa_pckev_h(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->h[4] = pws->h[5]; pwd->h[6] = pws->h[1]; pwd->h[0] = pwt->h[5]; @@ -4733,7 +4733,7 @@ void helper_msa_pckev_w(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->w[2] = pws->w[3]; pwd->w[0] = pwt->w[3]; pwd->w[3] = pws->w[1]; @@ -4765,7 +4765,7 @@ void helper_msa_pckod_b(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->b[7] = pwt->b[6]; pwd->b[5] = pwt->b[2]; pwd->b[3] = pwt->b[14]; @@ -4810,7 +4810,7 @@ void helper_msa_pckod_h(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->h[3] = pwt->h[2]; pwd->h[1] = pwt->h[6]; pwd->h[7] = pws->h[2]; @@ -4838,7 +4838,7 @@ void helper_msa_pckod_w(CPUMIPSState *env, wr_t *pws = &(env->active_fpu.fpr[ws].wr); wr_t *pwt = &(env->active_fpu.fpr[wt].wr); -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN pwd->w[1] = pwt->w[0]; pwd->w[3] = pws->w[0]; pwd->w[0] = pwt->w[2]; @@ -5926,7 +5926,7 @@ void helper_msa_copy_s_b(CPUMIPSState *env, uint32_t rd, uint32_t ws, uint32_t n) { n %= 16; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 8) { n = 8 - n - 1; } else { @@ -5940,7 +5940,7 @@ void helper_msa_copy_s_h(CPUMIPSState *env, uint32_t rd, uint32_t ws, uint32_t n) { n %= 8; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 4) { n = 4 - n - 1; } else { @@ -5954,7 +5954,7 @@ void helper_msa_copy_s_w(CPUMIPSState *env, uint32_t rd, uint32_t ws, uint32_t n) { n %= 4; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 2) { n = 2 - n - 1; } else { @@ -5975,7 +5975,7 @@ void helper_msa_copy_u_b(CPUMIPSState *env, uint32_t rd, uint32_t ws, uint32_t n) { n %= 16; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 8) { n = 8 - n - 1; } else { @@ -5989,7 +5989,7 @@ void helper_msa_copy_u_h(CPUMIPSState *env, uint32_t rd, uint32_t ws, uint32_t n) { n %= 8; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 4) { n = 4 - n - 1; } else { @@ -6003,7 +6003,7 @@ void helper_msa_copy_u_w(CPUMIPSState *env, uint32_t rd, uint32_t ws, uint32_t n) { n %= 4; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 2) { n = 2 - n - 1; } else { @@ -6019,7 +6019,7 @@ void helper_msa_insert_b(CPUMIPSState *env, uint32_t wd, wr_t *pwd = &(env->active_fpu.fpr[wd].wr); target_ulong rs = env->active_tc.gpr[rs_num]; n %= 16; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 8) { n = 8 - n - 1; } else { @@ -6035,7 +6035,7 @@ void helper_msa_insert_h(CPUMIPSState *env, uint32_t wd, wr_t *pwd = &(env->active_fpu.fpr[wd].wr); target_ulong rs = env->active_tc.gpr[rs_num]; n %= 8; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 4) { n = 4 - n - 1; } else { @@ -6051,7 +6051,7 @@ void helper_msa_insert_w(CPUMIPSState *env, uint32_t wd, wr_t *pwd = &(env->active_fpu.fpr[wd].wr); target_ulong rs = env->active_tc.gpr[rs_num]; n %= 4; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN if (n < 2) { n = 2 - n - 1; } else { @@ -8218,7 +8218,7 @@ void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MEMOP_IDX(DF) #endif -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN static inline uint64_t bswap16x4(uint64_t x) { uint64_t m = 0x00ff00ff00ff00ffull; @@ -8258,7 +8258,7 @@ void helper_msa_ld_h(CPUMIPSState *env, uint32_t wd, */ d0 = cpu_ldq_le_data_ra(env, addr + 0, ra); d1 = cpu_ldq_le_data_ra(env, addr + 8, ra); -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN d0 = bswap16x4(d0); d1 = bswap16x4(d1); #endif @@ -8279,7 +8279,7 @@ void helper_msa_ld_w(CPUMIPSState *env, uint32_t wd, */ d0 = cpu_ldq_le_data_ra(env, addr + 0, ra); d1 = cpu_ldq_le_data_ra(env, addr + 8, ra); -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN d0 = bswap32x2(d0); d1 = bswap32x2(d1); #endif @@ -8329,7 +8329,7 @@ void helper_msa_st_b(CPUMIPSState *env, uint32_t wd, /* Store 8 bytes at a time. Vector element ordering makes this LE. */ cpu_stq_le_data_ra(env, addr + 0, pwd->d[0], ra); - cpu_stq_le_data_ra(env, addr + 0, pwd->d[1], ra); + cpu_stq_le_data_ra(env, addr + 8, pwd->d[1], ra); } void helper_msa_st_h(CPUMIPSState *env, uint32_t wd, @@ -8345,7 +8345,7 @@ void helper_msa_st_h(CPUMIPSState *env, uint32_t wd, /* Store 8 bytes at a time. See helper_msa_ld_h. */ d0 = pwd->d[0]; d1 = pwd->d[1]; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN d0 = bswap16x4(d0); d1 = bswap16x4(d1); #endif @@ -8366,7 +8366,7 @@ void helper_msa_st_w(CPUMIPSState *env, uint32_t wd, /* Store 8 bytes at a time. See helper_msa_ld_w. */ d0 = pwd->d[0]; d1 = pwd->d[1]; -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN d0 = bswap32x2(d0); d1 = bswap32x2(d1); #endif diff --git a/target/mips/tcg/msa_translate.c b/target/mips/tcg/msa_translate.c index 7576b3ed86b6..1bcdbb112159 100644 --- a/target/mips/tcg/msa_translate.c +++ b/target/mips/tcg/msa_translate.c @@ -68,8 +68,8 @@ struct dfe { static int df_extract_val(DisasContext *ctx, int x, const struct dfe *s) { for (unsigned i = 0; i < 4; i++) { - if (extract32(x, s->start, s->length) == s->mask) { - return extract32(x, 0, s->start); + if (extract32(x, s[i].start, s[i].length) == s[i].mask) { + return extract32(x, 0, s[i].start); } } return -1; @@ -82,7 +82,7 @@ static int df_extract_val(DisasContext *ctx, int x, const struct dfe *s) static int df_extract_df(DisasContext *ctx, int x, const struct dfe *s) { for (unsigned i = 0; i < 4; i++) { - if (extract32(x, s->start, s->length) == s->mask) { + if (extract32(x, s[i].start, s[i].length) == s[i].mask) { return i; } } @@ -399,7 +399,7 @@ TRANS(BSETI, trans_msa_bit, gen_helper_msa_bseti_df); TRANS(BNEGI, trans_msa_bit, gen_helper_msa_bnegi_df); TRANS(BINSLI, trans_msa_bit, gen_helper_msa_binsli_df); TRANS(BINSRI, trans_msa_bit, gen_helper_msa_binsri_df); -TRANS(SAT_S, trans_msa_bit, gen_helper_msa_sat_u_df); +TRANS(SAT_S, trans_msa_bit, gen_helper_msa_sat_s_df); TRANS(SAT_U, trans_msa_bit, gen_helper_msa_sat_u_df); TRANS(SRARI, trans_msa_bit, gen_helper_msa_srari_df); TRANS(SRLRI, trans_msa_bit, gen_helper_msa_srlri_df); @@ -599,12 +599,7 @@ static bool trans_msa_elm_fn(DisasContext *ctx, arg_msa_elm_df *a, return false; } - if (check_msa_enabled(ctx)) { - return true; - } - - if (a->wd == 0) { - /* Treat as NOP. */ + if (!check_msa_enabled(ctx)) { return true; } @@ -624,6 +619,11 @@ static bool trans_msa_elm_fn(DisasContext *ctx, arg_msa_elm_df *a, static bool trans_COPY_U(DisasContext *ctx, arg_msa_elm_df *a) { + if (a->wd == 0) { + /* Treat as NOP. */ + return true; + } + static gen_helper_piii * const gen_msa_copy_u[4] = { gen_helper_msa_copy_u_b, gen_helper_msa_copy_u_h, NULL_IF_MIPS32(gen_helper_msa_copy_u_w), NULL @@ -634,6 +634,11 @@ static bool trans_COPY_U(DisasContext *ctx, arg_msa_elm_df *a) static bool trans_COPY_S(DisasContext *ctx, arg_msa_elm_df *a) { + if (a->wd == 0) { + /* Treat as NOP. */ + return true; + } + static gen_helper_piii * const gen_msa_copy_s[4] = { gen_helper_msa_copy_s_b, gen_helper_msa_copy_s_h, gen_helper_msa_copy_s_w, NULL_IF_MIPS32(gen_helper_msa_copy_s_d) @@ -747,8 +752,8 @@ static bool trans_msa_2rf(DisasContext *ctx, arg_msa_r *a, } TRANS(FCLASS, trans_msa_2rf, gen_helper_msa_fclass_df); -TRANS(FTRUNC_S, trans_msa_2rf, gen_helper_msa_fclass_df); -TRANS(FTRUNC_U, trans_msa_2rf, gen_helper_msa_ftrunc_s_df); +TRANS(FTRUNC_S, trans_msa_2rf, gen_helper_msa_ftrunc_s_df); +TRANS(FTRUNC_U, trans_msa_2rf, gen_helper_msa_ftrunc_u_df); TRANS(FSQRT, trans_msa_2rf, gen_helper_msa_fsqrt_df); TRANS(FRSQRT, trans_msa_2rf, gen_helper_msa_frsqrt_df); TRANS(FRCP, trans_msa_2rf, gen_helper_msa_frcp_df); diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc index 916cece4d27e..812c111e3c38 100644 --- a/target/mips/tcg/nanomips_translate.c.inc +++ b/target/mips/tcg/nanomips_translate.c.inc @@ -1597,7 +1597,7 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, check_dsp(ctx); switch (extract32(ctx->opcode, 12, 2)) { case NM_MTHLIP: - tcg_gen_movi_tl(t0, v2); + tcg_gen_movi_tl(t0, v2 >> 3); gen_helper_mthlip(t0, v0_t, cpu_env); break; case NM_SHILOV: @@ -2036,7 +2036,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, case NM_EXTRV_S_H: check_dsp(ctx); tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_s_h(t0, t0, v0_t, cpu_env); + gen_helper_extr_s_h(t0, t0, v1_t, cpu_env); gen_store_gpr(t0, ret); break; } @@ -2707,6 +2707,9 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt) case NM_SDC1XS: tcg_gen_shli_tl(t0, t0, 3); break; + default: + gen_reserved_instruction(ctx); + goto out; } } gen_op_addr_add(ctx, t0, t0, t1); @@ -2797,6 +2800,7 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt) break; } +out: tcg_temp_free(t0); tcg_temp_free(t1); } @@ -3690,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))) { - gen_helper_do_semihosting(cpu_env); + 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); @@ -3944,6 +3948,9 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) gen_shift_imm(ctx, OPC_ROTR, rt, rs, extract32(ctx->opcode, 0, 5)); break; + default: + gen_reserved_instruction(ctx); + break; } } break; @@ -4245,6 +4252,9 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) check_xnp(ctx); gen_llwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5)); break; + default: + gen_reserved_instruction(ctx); + break; } break; case NM_P_SC: @@ -4257,6 +4267,9 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) gen_scwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5), false); break; + default: + gen_reserved_instruction(ctx); + break; } break; case NM_CACHE: @@ -4265,6 +4278,9 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) gen_cache_operation(ctx, rt, rs, s); } break; + default: + gen_reserved_instruction(ctx); + break; } break; case NM_P_LS_E0: @@ -4371,6 +4387,9 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) break; } break; + default: + gen_reserved_instruction(ctx); + break; } break; case NM_P_LS_WM: @@ -4478,12 +4497,13 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) case NM_P_BR3A: s = sextract32(ctx->opcode, 0, 1) << 14 | extract32(ctx->opcode, 1, 13) << 1; - check_cp1_enabled(ctx); switch (extract32(ctx->opcode, 16, 5)) { case NM_BC1EQZC: + check_cp1_enabled(ctx); gen_compute_branch_cp1_nm(ctx, OPC_BC1EQZ, rt, s); break; case NM_BC1NEZC: + check_cp1_enabled(ctx); gen_compute_branch_cp1_nm(ctx, OPC_BC1NEZ, rt, s); break; case NM_BPOSGE32C: @@ -4527,7 +4547,12 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) switch (extract32(ctx->opcode, 14, 2)) { case NM_BNEC: check_nms(ctx); - gen_compute_branch_nm(ctx, OPC_BNE, 4, rs, rt, s); + if (rs == rt) { + /* NOP */ + ctx->hflags |= MIPS_HFLAG_FBNSLOT; + } else { + gen_compute_branch_nm(ctx, OPC_BNE, 4, rs, rt, s); + } break; case NM_BLTC: if (rs != 0 && rt != 0 && rs == rt) { @@ -4608,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))) { - gen_helper_do_semihosting(cpu_env); + 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/octeon.decode b/target/mips/tcg/octeon.decode new file mode 100644 index 000000000000..0c787cb498c6 --- /dev/null +++ b/target/mips/tcg/octeon.decode @@ -0,0 +1,41 @@ +# Octeon Architecture Module instruction set +# +# Copyright (C) 2022 Pavel Dovgalyuk +# +# SPDX-License-Identifier: LGPL-2.1-or-later +# + +# Branch on bit set or clear +# BBIT0 110010 ..... ..... ................ +# BBIT032 110110 ..... ..... ................ +# BBIT1 111010 ..... ..... ................ +# BBIT132 111110 ..... ..... ................ + +%bbit_p 28:1 16:5 +BBIT 11 set:1 . 10 rs:5 ..... offset:s16 p=%bbit_p + +# Arithmetic +# BADDU rd, rs, rt +# DMUL rd, rs, rt +# EXTS rt, rs, p, lenm1 +# EXTS32 rt, rs, p, lenm1 +# CINS rt, rs, p, lenm1 +# CINS32 rt, rs, p, lenm1 +# DPOP rd, rs +# POP rd, rs +# SEQ rd, rs, rt +# SEQI rt, rs, immediate +# SNE rd, rs, rt +# SNEI rt, rs, immediate + +@r3 ...... rs:5 rt:5 rd:5 ..... ...... +%bitfield_p 0:1 6:5 +@bitfield ...... rs:5 rt:5 lenm1:5 ..... ..... . p=%bitfield_p + +BADDU 011100 ..... ..... ..... 00000 101000 @r3 +DMUL 011100 ..... ..... ..... 00000 000011 @r3 +EXTS 011100 ..... ..... ..... ..... 11101 . @bitfield +CINS 011100 ..... ..... ..... ..... 11001 . @bitfield +POP 011100 rs:5 00000 rd:5 00000 10110 dw:1 +SEQNE 011100 rs:5 rt:5 rd:5 00000 10101 ne:1 +SEQNEI 011100 rs:5 rt:5 imm:s10 10111 ne:1 diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c new file mode 100644 index 000000000000..6a207d2e7ed3 --- /dev/null +++ b/target/mips/tcg/octeon_translate.c @@ -0,0 +1,201 @@ +/* + * Octeon-specific instructions translation routines + * + * Copyright (c) 2022 Pavel Dovgalyuk + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "exec/helper-gen.h" +#include "translate.h" + +/* Include the auto-generated decoder. */ +#include "decode-octeon.c.inc" + +static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a) +{ + TCGv p; + + if (ctx->hflags & MIPS_HFLAG_BMASK) { + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" + TARGET_FMT_lx "\n", ctx->base.pc_next); + generate_exception_end(ctx, EXCP_RI); + return true; + } + + /* Load needed operands */ + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + + p = tcg_constant_tl(1ULL << a->p); + if (a->set) { + tcg_gen_and_tl(bcond, p, t0); + } else { + tcg_gen_andc_tl(bcond, p, t0); + } + + ctx->hflags |= MIPS_HFLAG_BC; + ctx->btarget = ctx->base.pc_next + 4 + a->offset * 4; + ctx->hflags |= MIPS_HFLAG_BDS32; + + tcg_temp_free(t0); + return true; +} + +static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a) +{ + TCGv t0, t1; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + gen_load_gpr(t1, a->rt); + + tcg_gen_add_tl(t0, t0, t1); + tcg_gen_andi_i64(cpu_gpr[a->rd], t0, 0xff); + + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a) +{ + TCGv t0, t1; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + gen_load_gpr(t1, a->rt); + + tcg_gen_mul_i64(cpu_gpr[a->rd], t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_EXTS(DisasContext *ctx, arg_EXTS *a) +{ + TCGv t0; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + tcg_gen_sextract_tl(t0, t0, a->p, a->lenm1 + 1); + gen_store_gpr(t0, a->rt); + tcg_temp_free(t0); + + return true; +} + +static bool trans_CINS(DisasContext *ctx, arg_CINS *a) +{ + TCGv t0; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + tcg_gen_deposit_z_tl(t0, t0, a->p, a->lenm1 + 1); + gen_store_gpr(t0, a->rt); + tcg_temp_free(t0); + + return true; +} + +static bool trans_POP(DisasContext *ctx, arg_POP *a) +{ + TCGv t0; + + if (a->rd == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rs); + if (!a->dw) { + tcg_gen_andi_i64(t0, t0, 0xffffffff); + } + tcg_gen_ctpop_tl(t0, t0); + gen_store_gpr(t0, a->rd); + tcg_temp_free(t0); + + return true; +} + +static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a) +{ + TCGv t0, t1; + + if (a->rd == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, a->rs); + gen_load_gpr(t1, a->rt); + + if (a->ne) { + tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr[a->rd], t1, t0); + } else { + tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr[a->rd], t1, t0); + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a) +{ + TCGv t0; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rs); + + /* Sign-extend to 64 bit value */ + target_ulong imm = a->imm; + if (a->ne) { + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr[a->rt], t0, imm); + } else { + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], t0, imm); + } + + tcg_temp_free(t0); + + return true; +} diff --git a/target/mips/tcg/sysemu/cp0_helper.c b/target/mips/tcg/sysemu/cp0_helper.c index aae2af6eccc6..5da112458928 100644 --- a/target/mips/tcg/sysemu/cp0_helper.c +++ b/target/mips/tcg/sysemu/cp0_helper.c @@ -1396,10 +1396,11 @@ void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel) void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel) { uint64_t mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID); + uint64_t m_bit = env->CP0_WatchHi[sel] & (1 << CP0WH_M); /* read-only */ if ((env->CP0_Config5 >> CP0C5_MI) & 1) { mask |= 0xFFFFFFFF00000000ULL; /* MMID */ } - env->CP0_WatchHi[sel] = arg1 & mask; + env->CP0_WatchHi[sel] = m_bit | (arg1 & mask); env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7); } diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c index b4a383ae90c3..85f0567a7faf 100644 --- a/target/mips/tcg/sysemu/mips-semi.c +++ b/target/mips/tcg/sysemu/mips-semi.c @@ -20,10 +20,12 @@ #include "qemu/osdep.h" #include "cpu.h" #include "qemu/log.h" -#include "exec/helper-proto.h" -#include "exec/softmmu-semi.h" +#include "exec/gdbstub.h" +#include "semihosting/softmmu-uaccess.h" #include "semihosting/semihost.h" #include "semihosting/console.h" +#include "semihosting/syscalls.h" +#include "internal.h" typedef enum UHIOp { UHI_exit = 1, @@ -74,293 +76,284 @@ enum UHIOpenFlags { UHIOpen_EXCL = 0x800 }; -static int errno_mips(int host_errno) +enum UHIErrno { + UHI_EACCESS = 13, + UHI_EAGAIN = 11, + UHI_EBADF = 9, + UHI_EBADMSG = 77, + UHI_EBUSY = 16, + UHI_ECONNRESET = 104, + UHI_EEXIST = 17, + UHI_EFBIG = 27, + UHI_EINTR = 4, + UHI_EINVAL = 22, + UHI_EIO = 5, + UHI_EISDIR = 21, + UHI_ELOOP = 92, + UHI_EMFILE = 24, + UHI_EMLINK = 31, + UHI_ENAMETOOLONG = 91, + UHI_ENETDOWN = 115, + UHI_ENETUNREACH = 114, + UHI_ENFILE = 23, + UHI_ENOBUFS = 105, + UHI_ENOENT = 2, + UHI_ENOMEM = 12, + UHI_ENOSPC = 28, + UHI_ENOSR = 63, + UHI_ENOTCONN = 128, + UHI_ENOTDIR = 20, + UHI_ENXIO = 6, + UHI_EOVERFLOW = 139, + UHI_EPERM = 1, + UHI_EPIPE = 32, + UHI_ERANGE = 34, + UHI_EROFS = 30, + UHI_ESPIPE = 29, + UHI_ETIMEDOUT = 116, + UHI_ETXTBSY = 26, + UHI_EWOULDBLOCK = 11, + UHI_EXDEV = 18, +}; + +static void report_fault(CPUMIPSState *env) { - /* Errno values taken from asm-mips/errno.h */ - switch (host_errno) { - case 0: return 0; - case ENAMETOOLONG: return 78; -#ifdef EOVERFLOW - case EOVERFLOW: return 79; -#endif -#ifdef ELOOP - case ELOOP: return 90; -#endif - default: return EINVAL; - } + int op = env->active_tc.gpr[25]; + error_report("Fault during UHI operation %d", op); + abort(); } -static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src, - target_ulong vaddr) +static void uhi_cb(CPUState *cs, uint64_t ret, int err) { - hwaddr len = sizeof(struct UHIStat); - UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); - if (!dst) { - errno = EFAULT; - return -1; - } + CPUMIPSState *env = cs->env_ptr; - dst->uhi_st_dev = tswap16(src->st_dev); - dst->uhi_st_ino = tswap16(src->st_ino); - dst->uhi_st_mode = tswap32(src->st_mode); - dst->uhi_st_nlink = tswap16(src->st_nlink); - dst->uhi_st_uid = tswap16(src->st_uid); - dst->uhi_st_gid = tswap16(src->st_gid); - dst->uhi_st_rdev = tswap16(src->st_rdev); - dst->uhi_st_size = tswap64(src->st_size); - dst->uhi_st_atime = tswap64(src->st_atime); - dst->uhi_st_mtime = tswap64(src->st_mtime); - dst->uhi_st_ctime = tswap64(src->st_ctime); -#ifdef _WIN32 - dst->uhi_st_blksize = 0; - dst->uhi_st_blocks = 0; -#else - dst->uhi_st_blksize = tswap64(src->st_blksize); - dst->uhi_st_blocks = tswap64(src->st_blocks); -#endif - unlock_user(dst, vaddr, len); - return 0; -} +#define E(N) case E##N: err = UHI_E##N; break -static int get_open_flags(target_ulong target_flags) -{ - int open_flags = 0; - - if (target_flags & UHIOpen_RDWR) { - open_flags |= O_RDWR; - } else if (target_flags & UHIOpen_WRONLY) { - open_flags |= O_WRONLY; - } else { - open_flags |= O_RDONLY; + switch (err) { + case 0: + break; + E(PERM); + E(NOENT); + E(INTR); + E(BADF); + E(BUSY); + E(EXIST); + E(NOTDIR); + E(ISDIR); + E(INVAL); + E(NFILE); + E(MFILE); + E(FBIG); + E(NOSPC); + E(SPIPE); + E(ROFS); + E(NAMETOOLONG); + default: + err = UHI_EINVAL; + break; + case EFAULT: + report_fault(env); } - open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0; - open_flags |= (target_flags & UHIOpen_CREAT) ? O_CREAT : 0; - open_flags |= (target_flags & UHIOpen_TRUNC) ? O_TRUNC : 0; - open_flags |= (target_flags & UHIOpen_EXCL) ? O_EXCL : 0; +#undef E - return open_flags; + env->active_tc.gpr[2] = ret; + env->active_tc.gpr[3] = err; } -static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr, - target_ulong len, target_ulong offset) +static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err) { - int num_of_bytes; - void *dst = lock_user(VERIFY_READ, vaddr, len, 1); - if (!dst) { - errno = EFAULT; - return -1; - } + QEMU_BUILD_BUG_ON(sizeof(UHIStat) < sizeof(struct gdb_stat)); - if (offset) { -#ifdef _WIN32 - num_of_bytes = 0; -#else - num_of_bytes = pwrite(fd, dst, len, offset); -#endif - } else { - num_of_bytes = write(fd, dst, len); - } + if (!err) { + CPUMIPSState *env = cs->env_ptr; + target_ulong addr = env->active_tc.gpr[5]; + UHIStat *dst = lock_user(VERIFY_WRITE, addr, sizeof(UHIStat), 1); + struct gdb_stat s; - unlock_user(dst, vaddr, 0); - return num_of_bytes; -} + if (!dst) { + report_fault(env); + } -static int read_from_file(CPUMIPSState *env, target_ulong fd, - target_ulong vaddr, target_ulong len, - target_ulong offset) -{ - int num_of_bytes; - void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); - if (!dst) { - errno = EFAULT; - return -1; - } + memcpy(&s, dst, sizeof(struct gdb_stat)); + memset(dst, 0, sizeof(UHIStat)); - if (offset) { -#ifdef _WIN32 - num_of_bytes = 0; -#else - num_of_bytes = pread(fd, dst, len, offset); -#endif - } else { - num_of_bytes = read(fd, dst, len); - } + dst->uhi_st_dev = tswap16(be32_to_cpu(s.gdb_st_dev)); + dst->uhi_st_ino = tswap16(be32_to_cpu(s.gdb_st_ino)); + dst->uhi_st_mode = tswap32(be32_to_cpu(s.gdb_st_mode)); + dst->uhi_st_nlink = tswap16(be32_to_cpu(s.gdb_st_nlink)); + dst->uhi_st_uid = tswap16(be32_to_cpu(s.gdb_st_uid)); + dst->uhi_st_gid = tswap16(be32_to_cpu(s.gdb_st_gid)); + dst->uhi_st_rdev = tswap16(be32_to_cpu(s.gdb_st_rdev)); + dst->uhi_st_size = tswap64(be64_to_cpu(s.gdb_st_size)); + dst->uhi_st_atime = tswap64(be32_to_cpu(s.gdb_st_atime)); + dst->uhi_st_mtime = tswap64(be32_to_cpu(s.gdb_st_mtime)); + dst->uhi_st_ctime = tswap64(be32_to_cpu(s.gdb_st_ctime)); + dst->uhi_st_blksize = tswap64(be64_to_cpu(s.gdb_st_blksize)); + dst->uhi_st_blocks = tswap64(be64_to_cpu(s.gdb_st_blocks)); - unlock_user(dst, vaddr, len); - return num_of_bytes; -} - -static int copy_argn_to_target(CPUMIPSState *env, int arg_num, - target_ulong vaddr) -{ - int strsize = strlen(semihosting_get_arg(arg_num)) + 1; - char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0); - if (!dst) { - return -1; + unlock_user(dst, addr, sizeof(UHIStat)); } - strcpy(dst, semihosting_get_arg(arg_num)); - - unlock_user(dst, vaddr, strsize); - return 0; + uhi_cb(cs, ret, err); } -#define GET_TARGET_STRING(p, addr) \ - do { \ - p = lock_user_string(addr); \ - if (!p) { \ - gpr[2] = -1; \ - gpr[3] = EFAULT; \ - return; \ - } \ - } while (0) - -#define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \ - do { \ - p = lock_user_string(addr); \ - if (!p) { \ - gpr[2] = -1; \ - gpr[3] = EFAULT; \ - return; \ - } \ - p2 = lock_user_string(addr2); \ - if (!p2) { \ - unlock_user(p, addr, 0); \ - gpr[2] = -1; \ - gpr[3] = EFAULT; \ - return; \ - } \ - } while (0) - -#define FREE_TARGET_STRING(p, gpr) \ - do { \ - unlock_user(p, gpr, 0); \ - } while (0) - -void helper_do_semihosting(CPUMIPSState *env) +void mips_semihosting(CPUMIPSState *env) { + CPUState *cs = env_cpu(env); target_ulong *gpr = env->active_tc.gpr; const UHIOp op = gpr[25]; - char *p, *p2; + char *p; switch (op) { case UHI_exit: - qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]); + gdb_exit(gpr[4]); exit(gpr[4]); + case UHI_open: - GET_TARGET_STRING(p, gpr[4]); - if (!strcmp("/dev/stdin", p)) { - gpr[2] = 0; - } else if (!strcmp("/dev/stdout", p)) { - gpr[2] = 1; - } else if (!strcmp("/dev/stderr", p)) { - gpr[2] = 2; - } else { - gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]); - gpr[3] = errno_mips(errno); + { + target_ulong fname = gpr[4]; + int ret = -1; + + p = lock_user_string(fname); + if (!p) { + report_fault(env); + } + if (!strcmp("/dev/stdin", p)) { + ret = 0; + } else if (!strcmp("/dev/stdout", p)) { + ret = 1; + } else if (!strcmp("/dev/stderr", p)) { + ret = 2; + } + unlock_user(p, fname, 0); + + /* FIXME: reusing a guest fd doesn't seem correct. */ + if (ret >= 0) { + gpr[2] = ret; + break; + } + + semihost_sys_open(cs, uhi_cb, fname, 0, gpr[5], gpr[6]); } - FREE_TARGET_STRING(p, gpr[4]); break; + case UHI_close: - if (gpr[4] < 3) { - /* ignore closing stdin/stdout/stderr */ - gpr[2] = 0; - return; - } - gpr[2] = close(gpr[4]); - gpr[3] = errno_mips(errno); + semihost_sys_close(cs, uhi_cb, gpr[4]); break; case UHI_read: - gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0); - gpr[3] = errno_mips(errno); + semihost_sys_read(cs, uhi_cb, gpr[4], gpr[5], gpr[6]); break; case UHI_write: - gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0); - gpr[3] = errno_mips(errno); + semihost_sys_write(cs, uhi_cb, gpr[4], gpr[5], gpr[6]); break; case UHI_lseek: - gpr[2] = lseek(gpr[4], gpr[5], gpr[6]); - gpr[3] = errno_mips(errno); + semihost_sys_lseek(cs, uhi_cb, gpr[4], gpr[5], gpr[6]); break; case UHI_unlink: - GET_TARGET_STRING(p, gpr[4]); - gpr[2] = remove(p); - gpr[3] = errno_mips(errno); - FREE_TARGET_STRING(p, gpr[4]); + semihost_sys_remove(cs, uhi_cb, gpr[4], 0); break; case UHI_fstat: - { - struct stat sbuf; - memset(&sbuf, 0, sizeof(sbuf)); - gpr[2] = fstat(gpr[4], &sbuf); - gpr[3] = errno_mips(errno); - if (gpr[2]) { - return; - } - gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]); - gpr[3] = errno_mips(errno); - } + semihost_sys_fstat(cs, uhi_fstat_cb, gpr[4], gpr[5]); break; + case UHI_argc: gpr[2] = semihosting_get_argc(); break; case UHI_argnlen: - if (gpr[4] >= semihosting_get_argc()) { - gpr[2] = -1; - return; + { + const char *s = semihosting_get_arg(gpr[4]); + gpr[2] = s ? strlen(s) : -1; } - gpr[2] = strlen(semihosting_get_arg(gpr[4])); break; case UHI_argn: - if (gpr[4] >= semihosting_get_argc()) { - gpr[2] = -1; - return; + { + const char *s = semihosting_get_arg(gpr[4]); + target_ulong addr; + size_t len; + + if (!s) { + gpr[2] = -1; + break; + } + len = strlen(s) + 1; + addr = gpr[5]; + p = lock_user(VERIFY_WRITE, addr, len, 0); + if (!p) { + report_fault(env); + } + memcpy(p, s, len); + unlock_user(p, addr, len); + gpr[2] = 0; } - gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]); break; + case UHI_plog: - GET_TARGET_STRING(p, gpr[4]); - p2 = strstr(p, "%d"); - if (p2) { - int char_num = p2 - p; - GString *s = g_string_new_len(p, char_num); - g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2); - gpr[2] = qemu_semihosting_log_out(s->str, s->len); - g_string_free(s, true); - } else { - gpr[2] = qemu_semihosting_log_out(p, strlen(p)); + { + target_ulong addr = gpr[4]; + ssize_t len = target_strlen(addr); + GString *str; + char *pct_d; + + if (len < 0) { + report_fault(env); + } + p = lock_user(VERIFY_READ, addr, len, 1); + if (!p) { + report_fault(env); + } + + pct_d = strstr(p, "%d"); + if (!pct_d) { + unlock_user(p, addr, 0); + semihost_sys_write(cs, uhi_cb, 2, addr, len); + break; + } + + str = g_string_new_len(p, pct_d - p); + g_string_append_printf(str, "%d%s", (int)gpr[5], pct_d + 2); + unlock_user(p, addr, 0); + + /* + * When we're using gdb, we need a guest address, so + * drop the string onto the stack below the stack pointer. + */ + 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); + } else { + gpr[2] = qemu_semihosting_console_write(str->str, str->len); + } + g_string_free(str, true); } - FREE_TARGET_STRING(p, gpr[4]); break; + case UHI_assert: - GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]); - printf("assertion '"); - printf("\"%s\"", p); - printf("': file \"%s\", line %d\n", p2, (int)gpr[6]); - FREE_TARGET_STRING(p2, gpr[5]); - FREE_TARGET_STRING(p, gpr[4]); - abort(); - break; - case UHI_pread: - gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); - gpr[3] = errno_mips(errno); - break; - case UHI_pwrite: - gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); - gpr[3] = errno_mips(errno); - break; -#ifndef _WIN32 - case UHI_link: - GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]); - gpr[2] = link(p, p2); - gpr[3] = errno_mips(errno); - FREE_TARGET_STRING(p2, gpr[5]); - FREE_TARGET_STRING(p, gpr[4]); - break; -#endif + { + const char *msg, *file; + + msg = lock_user_string(gpr[4]); + if (!msg) { + msg = ""; + } + file = lock_user_string(gpr[5]); + if (!file) { + file = ""; + } + + error_report("UHI assertion \"%s\": file \"%s\", line %d", + msg, file, (int)gpr[6]); + abort(); + } + default: - fprintf(stderr, "Unknown UHI operation %d\n", op); + error_report("Unknown UHI operation %d", op); abort(); } return; diff --git a/target/mips/tcg/sysemu/special_helper.c b/target/mips/tcg/sysemu/special_helper.c index f4f8fe8afce2..3c5f35c759b4 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 73254d19298d..9d16859c0a62 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -1053,6 +1053,11 @@ void mips_cpu_do_interrupt(CPUState *cs) } offset = 0x180; switch (cs->exception_index) { + 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/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc index 4353a966f976..af585b5d9c13 100644 --- a/target/mips/tcg/sysemu_helper.h.inc +++ b/target/mips/tcg/sysemu_helper.h.inc @@ -9,8 +9,6 @@ * SPDX-License-Identifier: LGPL-2.1-or-later */ -DEF_HELPER_1(do_semihosting, void, env) - /* CP0 helpers */ DEF_HELPER_1(mfc0_mvpcontrol, tl, env) DEF_HELPER_1(mfc0_mvpconf0, tl, env) diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 466768aec487..aef032c48dc5 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -18,18 +18,22 @@ void mips_tcg_init(void); void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); -void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); +void mips_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data); const char *mips_exception_name(int32_t exception); -void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code, uintptr_t pc); +G_NORETURN void do_raise_exception_err(CPUMIPSState *env, uint32_t exception, + int error_code, uintptr_t pc); -static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, - uint32_t exception, - uintptr_t pc) +static inline G_NORETURN +void do_raise_exception(CPUMIPSState *env, + uint32_t exception, + uintptr_t pc) { do_raise_exception_err(env, exception, 0, pc); } @@ -61,6 +65,8 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); +void mips_semihosting(CPUMIPSState *env); + #endif /* !CONFIG_USER_ONLY */ #endif diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index b82a7ec6ad50..624e6b778603 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", }; @@ -1548,7 +1545,7 @@ void check_cop1x(DisasContext *ctx) */ void check_cp1_64bitmode(DisasContext *ctx) { - if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) { + if (unlikely(~ctx->hflags & MIPS_HFLAG_F64)) { gen_reserved_instruction(ctx); } } @@ -12085,23 +12082,16 @@ 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 } -#ifdef CONFIG_USER_ONLY -/* The above should dead-code away any calls to this..*/ -static inline void gen_helper_do_semihosting(void *env) -{ - g_assert_not_reached(); -} -#endif - void gen_ldxs(DisasContext *ctx, int base, int index, int rd) { TCGv t0 = tcg_temp_new(); @@ -12183,12 +12173,16 @@ enum { #include "nanomips_translate.c.inc" /* MIPSDSP functions. */ -static void gen_mipsdsp_ld(DisasContext *ctx, uint32_t opc, - int rd, int base, int offset) + +/* Indexed load is not for DSP only */ +static void gen_mips_lx(DisasContext *ctx, uint32_t opc, + int rd, int base, int offset) { TCGv t0; - check_dsp(ctx); + if (!(ctx->insn_flags & INSN_OCTEON)) { + check_dsp(ctx); + } t0 = tcg_temp_new(); if (base == 0) { @@ -13909,8 +13903,8 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) } break; case R6_OPC_SDBBP: - if (is_uhi(extract32(ctx->opcode, 6, 20))) { - gen_helper_do_semihosting(cpu_env); + 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); @@ -14321,8 +14315,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))) { - gen_helper_do_semihosting(cpu_env); + if (is_uhi(ctx, extract32(ctx->opcode, 6, 20))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { /* * XXX: not clear which exception should be raised @@ -14533,7 +14527,7 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_LBUX: case OPC_LHX: case OPC_LWX: - gen_mipsdsp_ld(ctx, op2, rd, rs, rt); + gen_mips_lx(ctx, op2, rd, rs, rt); break; default: /* Invalid */ MIPS_INVAL("MASK LX"); @@ -15963,6 +15957,11 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) if (cpu_supports_isa(env, INSN_VR54XX) && decode_ext_vr54xx(ctx, ctx->opcode)) { return; } +#if defined(TARGET_MIPS64) + if (cpu_supports_isa(env, INSN_OCTEON) && decode_ext_octeon(ctx, ctx->opcode)) { + return; + } +#endif /* ISA extensions */ if (ase_msa_available(env) && decode_ase_msa(ctx, ctx->opcode)) { @@ -16023,8 +16022,9 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) #else ctx->mem_idx = hflags_mmu_index(ctx->hflags); #endif - ctx->default_tcg_memop_mask = (ctx->insn_flags & (ISA_MIPS_R6 | - INSN_LOONGSON3A)) ? MO_UNALN : MO_ALIGN; + ctx->default_tcg_memop_mask = (!(ctx->insn_flags & ISA_NANOMIPS32) && + (ctx->insn_flags & (ISA_MIPS_R6 | + INSN_LOONGSON3A))) ? MO_UNALN : MO_ALIGN; /* * Execute a branch and its delay slot as a single instruction. @@ -16100,6 +16100,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) { @@ -16141,10 +16144,11 @@ static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void mips_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void mips_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps mips_tr_ops = { @@ -16156,11 +16160,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) @@ -16228,9 +16233,13 @@ void mips_tcg_init(void) } } -void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, - target_ulong *data) +void mips_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + env->active_tc.PC = data[0]; env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= data[1]; diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index 9997fe2f3c2a..69f85841d213 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)) @@ -215,6 +219,7 @@ bool decode_ase_msa(DisasContext *ctx, uint32_t insn); bool decode_ext_txx9(DisasContext *ctx, uint32_t insn); #if defined(TARGET_MIPS64) bool decode_ext_tx79(DisasContext *ctx, uint32_t insn); +bool decode_ext_octeon(DisasContext *ctx, uint32_t insn); #endif bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn); diff --git a/target/nios2/cpu-param.h b/target/nios2/cpu-param.h index 38bedbfd617d..177d72086446 100644 --- a/target/nios2/cpu-param.h +++ b/target/nios2/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef NIOS2_CPU_PARAM_H -#define NIOS2_CPU_PARAM_H 1 +#define NIOS2_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index 6975ae4bdb56..cff30823dad3 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -31,49 +31,79 @@ static void nios2_cpu_set_pc(CPUState *cs, vaddr value) Nios2CPU *cpu = NIOS2_CPU(cs); CPUNios2State *env = &cpu->env; - env->regs[R_PC] = 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 void nios2_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + Nios2CPU *cpu = NIOS2_CPU(cs); + CPUNios2State *env = &cpu->env; + + env->pc = data[0]; } static bool nios2_cpu_has_work(CPUState *cs) { - return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); + return cs->interrupt_request & CPU_INTERRUPT_HARD; } -static void nios2_cpu_reset(DeviceState *dev) +static void nios2_cpu_reset_hold(Object *obj) { - CPUState *cs = CPU(dev); + CPUState *cs = CPU(obj); Nios2CPU *cpu = NIOS2_CPU(cs); Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(cpu); CPUNios2State *env = &cpu->env; - if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", cs->cpu_index); - log_cpu_state(cs, 0); + if (ncc->parent_phases.hold) { + ncc->parent_phases.hold(obj); } - ncc->parent_reset(dev); - - memset(env->regs, 0, sizeof(uint32_t) * NUM_CORE_REGS); - env->regs[R_PC] = cpu->reset_addr; + memset(env->ctrl, 0, sizeof(env->ctrl)); + env->pc = cpu->reset_addr; #if defined(CONFIG_USER_ONLY) /* Start in user mode with interrupts enabled. */ - env->regs[CR_STATUS] = CR_STATUS_U | CR_STATUS_PIE; + env->ctrl[CR_STATUS] = CR_STATUS_RSIE | CR_STATUS_U | CR_STATUS_PIE; + memset(env->regs, 0, sizeof(env->regs)); #else - env->regs[CR_STATUS] = 0; + env->ctrl[CR_STATUS] = CR_STATUS_RSIE; + nios2_update_crs(env); + memset(env->shadow_regs, 0, sizeof(env->shadow_regs)); #endif } #ifndef CONFIG_USER_ONLY -static void nios2_cpu_set_irq(void *opaque, int irq, int level) +static void eic_set_irq(void *opaque, int irq, int level) +{ + Nios2CPU *cpu = opaque; + CPUState *cs = CPU(cpu); + + if (level) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +static void iic_set_irq(void *opaque, int irq, int level) { Nios2CPU *cpu = opaque; CPUNios2State *env = &cpu->env; CPUState *cs = CPU(cpu); - env->regs[CR_IPENDING] = deposit32(env->regs[CR_IPENDING], irq, 1, !!level); + env->ctrl[CR_IPENDING] = deposit32(env->ctrl[CR_IPENDING], irq, 1, !!level); - if (env->regs[CR_IPENDING]) { + if (env->ctrl[CR_IPENDING]) { cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); @@ -89,15 +119,6 @@ static void nios2_cpu_initfn(Object *obj) #if !defined(CONFIG_USER_ONLY) mmu_init(&cpu->env); - - /* - * These interrupt lines model the IIC (internal interrupt - * controller). QEMU does not currently support the EIC - * (external interrupt controller) -- if we did it would be - * a separate device in hw/intc with a custom interface to - * the CPU, and boards using it would not wire up these IRQ lines. - */ - qdev_init_gpio_in_named(DEVICE(cpu), nios2_cpu_set_irq, "IRQ", 32); #endif } @@ -106,37 +127,148 @@ static ObjectClass *nios2_cpu_class_by_name(const char *cpu_model) return object_class_by_name(TYPE_NIOS2_CPU); } +static void realize_cr_status(CPUState *cs) +{ + Nios2CPU *cpu = NIOS2_CPU(cs); + + /* Begin with all fields of all registers are reserved. */ + memset(cpu->cr_state, 0, sizeof(cpu->cr_state)); + + /* + * The combination of writable and readonly is the set of all + * non-reserved fields. We apply writable as a mask to bits, + * and merge in existing readonly bits, before storing. + */ +#define WR_REG(C) cpu->cr_state[C].writable = -1 +#define RO_REG(C) cpu->cr_state[C].readonly = -1 +#define WR_FIELD(C, F) cpu->cr_state[C].writable |= R_##C##_##F##_MASK +#define RO_FIELD(C, F) cpu->cr_state[C].readonly |= R_##C##_##F##_MASK + + WR_FIELD(CR_STATUS, PIE); + WR_REG(CR_ESTATUS); + WR_REG(CR_BSTATUS); + RO_REG(CR_CPUID); + RO_REG(CR_EXCEPTION); + WR_REG(CR_BADADDR); + + if (cpu->eic_present) { + WR_FIELD(CR_STATUS, RSIE); + RO_FIELD(CR_STATUS, NMI); + WR_FIELD(CR_STATUS, PRS); + RO_FIELD(CR_STATUS, CRS); + WR_FIELD(CR_STATUS, IL); + WR_FIELD(CR_STATUS, IH); + } else { + RO_FIELD(CR_STATUS, RSIE); + WR_REG(CR_IENABLE); + RO_REG(CR_IPENDING); + } + + if (cpu->mmu_present) { + WR_FIELD(CR_STATUS, U); + WR_FIELD(CR_STATUS, EH); + + WR_FIELD(CR_PTEADDR, VPN); + WR_FIELD(CR_PTEADDR, PTBASE); + + RO_FIELD(CR_TLBMISC, D); + RO_FIELD(CR_TLBMISC, PERM); + RO_FIELD(CR_TLBMISC, BAD); + RO_FIELD(CR_TLBMISC, DBL); + WR_FIELD(CR_TLBMISC, PID); + WR_FIELD(CR_TLBMISC, WE); + WR_FIELD(CR_TLBMISC, RD); + WR_FIELD(CR_TLBMISC, WAY); + + WR_REG(CR_TLBACC); + } + + /* + * TODO: ECC (config, eccinj) and MPU (config, mpubase, mpuacc) are + * unimplemented, so their corresponding control regs remain reserved. + */ + +#undef WR_REG +#undef RO_REG +#undef WR_FIELD +#undef RO_FIELD +} + static void nios2_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + Nios2CPU *cpu = NIOS2_CPU(cs); Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(dev); Error *local_err = NULL; +#ifndef CONFIG_USER_ONLY + if (cpu->eic_present) { + qdev_init_gpio_in_named(DEVICE(cpu), eic_set_irq, "EIC", 1); + } else { + qdev_init_gpio_in_named(DEVICE(cpu), iic_set_irq, "IRQ", 32); + } +#endif + cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; } + realize_cr_status(cs); qemu_init_vcpu(cs); cpu_reset(cs); + /* We have reserved storage for cpuid; might as well use it. */ + cpu->env.ctrl[CR_CPUID] = cs->cpu_index; + ncc->parent_realize(dev, errp); } #ifndef CONFIG_USER_ONLY -static bool nios2_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +static bool eic_take_interrupt(Nios2CPU *cpu) { - Nios2CPU *cpu = NIOS2_CPU(cs); CPUNios2State *env = &cpu->env; + const uint32_t status = env->ctrl[CR_STATUS]; - if ((interrupt_request & CPU_INTERRUPT_HARD) && - (env->regs[CR_STATUS] & CR_STATUS_PIE) && - (env->regs[CR_IPENDING] & env->regs[CR_IENABLE])) { - cs->exception_index = EXCP_IRQ; - nios2_cpu_do_interrupt(cs); + if (cpu->rnmi) { + return !(status & CR_STATUS_NMI); + } + if (!(status & CR_STATUS_PIE)) { + return false; + } + if (cpu->ril <= FIELD_EX32(status, CR_STATUS, IL)) { + return false; + } + if (cpu->rrs != FIELD_EX32(status, CR_STATUS, CRS)) { return true; } + return status & CR_STATUS_RSIE; +} + +static bool iic_take_interrupt(Nios2CPU *cpu) +{ + CPUNios2State *env = &cpu->env; + + if (!(env->ctrl[CR_STATUS] & CR_STATUS_PIE)) { + return false; + } + return env->ctrl[CR_IPENDING] & env->ctrl[CR_IENABLE]; +} + +static bool nios2_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + Nios2CPU *cpu = NIOS2_CPU(cs); + + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu->eic_present + ? eic_take_interrupt(cpu) + : iic_take_interrupt(cpu)) { + cs->exception_index = EXCP_IRQ; + nios2_cpu_do_interrupt(cs); + return true; + } + } return false; } #endif /* !CONFIG_USER_ONLY */ @@ -151,23 +283,26 @@ static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { Nios2CPU *cpu = NIOS2_CPU(cs); - CPUClass *cc = CPU_GET_CLASS(cs); CPUNios2State *env = &cpu->env; - - if (n > cc->gdb_num_core_regs) { - return 0; - } + uint32_t val; if (n < 32) { /* GP regs */ - return gdb_get_reg32(mem_buf, env->regs[n]); + val = env->regs[n]; } else if (n == 32) { /* PC */ - return gdb_get_reg32(mem_buf, env->regs[R_PC]); + val = env->pc; } else if (n < 49) { /* Status regs */ - return gdb_get_reg32(mem_buf, env->regs[n - 1]); + unsigned cr = n - 33; + if (nios2_cr_reserved(&cpu->cr_state[cr])) { + val = 0; + } else { + val = env->ctrl[n - 33]; + } + } else { + /* Invalid regs */ + return 0; } - /* Invalid regs */ - return 0; + return gdb_get_reg32(mem_buf, val); } static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) @@ -175,23 +310,32 @@ static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) Nios2CPU *cpu = NIOS2_CPU(cs); CPUClass *cc = CPU_GET_CLASS(cs); CPUNios2State *env = &cpu->env; + uint32_t val; if (n > cc->gdb_num_core_regs) { return 0; } + val = ldl_p(mem_buf); if (n < 32) { /* GP regs */ - env->regs[n] = ldl_p(mem_buf); + env->regs[n] = val; } else if (n == 32) { /* PC */ - env->regs[R_PC] = ldl_p(mem_buf); + env->pc = val; } else if (n < 49) { /* Status regs */ - env->regs[n - 1] = ldl_p(mem_buf); + unsigned cr = n - 33; + /* ??? Maybe allow the debugger to write to readonly fields. */ + val &= cpu->cr_state[cr].writable; + val |= cpu->cr_state[cr].readonly & env->ctrl[cr]; + env->ctrl[cr] = val; + } else { + g_assert_not_reached(); } return 4; } static Property nios2_properties[] = { + DEFINE_PROP_BOOL("diverr_present", Nios2CPU, diverr_present, true), DEFINE_PROP_BOOL("mmu_present", Nios2CPU, mmu_present, true), /* ALTR,pid-num-bits */ DEFINE_PROP_UINT32("mmu_pid_num_bits", Nios2CPU, pid_num_bits, 8), @@ -214,10 +358,9 @@ static const struct SysemuCPUOps nios2_sysemu_ops = { static const struct TCGCPUOps nios2_tcg_ops = { .initialize = nios2_tcg_init, + .restore_state_to_opc = nios2_restore_state_to_opc, -#ifdef CONFIG_USER_ONLY - .record_sigsegv = nios2_cpu_record_sigsegv, -#else +#ifndef CONFIG_USER_ONLY .tlb_fill = nios2_cpu_tlb_fill, .cpu_exec_interrupt = nios2_cpu_exec_interrupt, .do_interrupt = nios2_cpu_do_interrupt, @@ -230,16 +373,19 @@ static void nios2_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); Nios2CPUClass *ncc = NIOS2_CPU_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, nios2_cpu_realizefn, &ncc->parent_realize); device_class_set_props(dc, nios2_properties); - device_class_set_parent_reset(dc, nios2_cpu_reset, &ncc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, nios2_cpu_reset_hold, NULL, + &ncc->parent_phases); cc->class_by_name = nios2_cpu_class_by_name; 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/cpu.h b/target/nios2/cpu.h index ca0f3420cd1b..b1a55490747c 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -23,6 +23,7 @@ #include "exec/cpu-defs.h" #include "hw/core/cpu.h" +#include "hw/registerfields.h" #include "qom/object.h" typedef struct CPUArchState CPUNios2State; @@ -36,7 +37,7 @@ OBJECT_DECLARE_CPU_TYPE(Nios2CPU, Nios2CPUClass, NIOS2_CPU) /** * Nios2CPUClass: - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A Nios2 CPU model. */ @@ -46,7 +47,7 @@ struct Nios2CPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; #define TARGET_HAS_ICE 1 @@ -56,83 +57,114 @@ struct Nios2CPUClass { #define EXCEPTION_ADDRESS 0x00000004 #define FAST_TLB_MISS_ADDRESS 0x00000008 +#define NUM_GP_REGS 32 +#define NUM_CR_REGS 32 -/* GP regs + CR regs + PC */ -#define NUM_CORE_REGS (32 + 32 + 1) +#ifndef CONFIG_USER_ONLY +/* 63 shadow register sets; index 0 is the primary register set. */ +#define NUM_REG_SETS 64 +#endif /* General purpose register aliases */ -#define R_ZERO 0 -#define R_AT 1 -#define R_RET0 2 -#define R_RET1 3 -#define R_ARG0 4 -#define R_ARG1 5 -#define R_ARG2 6 -#define R_ARG3 7 -#define R_ET 24 -#define R_BT 25 -#define R_GP 26 -#define R_SP 27 -#define R_FP 28 -#define R_EA 29 -#define R_BA 30 -#define R_RA 31 +enum { + R_ZERO = 0, + R_AT = 1, + R_RET0 = 2, + R_RET1 = 3, + R_ARG0 = 4, + R_ARG1 = 5, + R_ARG2 = 6, + R_ARG3 = 7, + R_ET = 24, + R_BT = 25, + R_GP = 26, + R_SP = 27, + R_FP = 28, + R_EA = 29, + R_BA = 30, + R_SSTATUS = 30, + R_RA = 31, +}; /* Control register aliases */ -#define CR_BASE 32 -#define CR_STATUS (CR_BASE + 0) -#define CR_STATUS_PIE (1 << 0) -#define CR_STATUS_U (1 << 1) -#define CR_STATUS_EH (1 << 2) -#define CR_STATUS_IH (1 << 3) -#define CR_STATUS_IL (63 << 4) -#define CR_STATUS_CRS (63 << 10) -#define CR_STATUS_PRS (63 << 16) -#define CR_STATUS_NMI (1 << 22) -#define CR_STATUS_RSIE (1 << 23) -#define CR_ESTATUS (CR_BASE + 1) -#define CR_BSTATUS (CR_BASE + 2) -#define CR_IENABLE (CR_BASE + 3) -#define CR_IPENDING (CR_BASE + 4) -#define CR_CPUID (CR_BASE + 5) -#define CR_CTL6 (CR_BASE + 6) -#define CR_EXCEPTION (CR_BASE + 7) -#define CR_PTEADDR (CR_BASE + 8) -#define CR_PTEADDR_PTBASE_SHIFT 22 -#define CR_PTEADDR_PTBASE_MASK (0x3FF << CR_PTEADDR_PTBASE_SHIFT) -#define CR_PTEADDR_VPN_SHIFT 2 -#define CR_PTEADDR_VPN_MASK (0xFFFFF << CR_PTEADDR_VPN_SHIFT) -#define CR_TLBACC (CR_BASE + 9) -#define CR_TLBACC_IGN_SHIFT 25 -#define CR_TLBACC_IGN_MASK (0x7F << CR_TLBACC_IGN_SHIFT) -#define CR_TLBACC_C (1 << 24) -#define CR_TLBACC_R (1 << 23) -#define CR_TLBACC_W (1 << 22) -#define CR_TLBACC_X (1 << 21) -#define CR_TLBACC_G (1 << 20) -#define CR_TLBACC_PFN_MASK 0x000FFFFF -#define CR_TLBMISC (CR_BASE + 10) -#define CR_TLBMISC_WAY_SHIFT 20 -#define CR_TLBMISC_WAY_MASK (0xF << CR_TLBMISC_WAY_SHIFT) -#define CR_TLBMISC_RD (1 << 19) -#define CR_TLBMISC_WR (1 << 18) -#define CR_TLBMISC_PID_SHIFT 4 -#define CR_TLBMISC_PID_MASK (0x3FFF << CR_TLBMISC_PID_SHIFT) -#define CR_TLBMISC_DBL (1 << 3) -#define CR_TLBMISC_BAD (1 << 2) -#define CR_TLBMISC_PERM (1 << 1) -#define CR_TLBMISC_D (1 << 0) -#define CR_ENCINJ (CR_BASE + 11) -#define CR_BADADDR (CR_BASE + 12) -#define CR_CONFIG (CR_BASE + 13) -#define CR_MPUBASE (CR_BASE + 14) -#define CR_MPUACC (CR_BASE + 15) - -/* Other registers */ -#define R_PC 64 +enum { + CR_STATUS = 0, + CR_ESTATUS = 1, + CR_BSTATUS = 2, + CR_IENABLE = 3, + CR_IPENDING = 4, + CR_CPUID = 5, + CR_EXCEPTION = 7, + CR_PTEADDR = 8, + CR_TLBACC = 9, + CR_TLBMISC = 10, + CR_ENCINJ = 11, + CR_BADADDR = 12, + CR_CONFIG = 13, + CR_MPUBASE = 14, + CR_MPUACC = 15, +}; + +FIELD(CR_STATUS, PIE, 0, 1) +FIELD(CR_STATUS, U, 1, 1) +FIELD(CR_STATUS, EH, 2, 1) +FIELD(CR_STATUS, IH, 3, 1) +FIELD(CR_STATUS, IL, 4, 6) +FIELD(CR_STATUS, CRS, 10, 6) +FIELD(CR_STATUS, PRS, 16, 6) +FIELD(CR_STATUS, NMI, 22, 1) +FIELD(CR_STATUS, RSIE, 23, 1) +FIELD(CR_STATUS, SRS, 31, 1) /* only in sstatus */ + +#define CR_STATUS_PIE R_CR_STATUS_PIE_MASK +#define CR_STATUS_U R_CR_STATUS_U_MASK +#define CR_STATUS_EH R_CR_STATUS_EH_MASK +#define CR_STATUS_IH R_CR_STATUS_IH_MASK +#define CR_STATUS_NMI R_CR_STATUS_NMI_MASK +#define CR_STATUS_RSIE R_CR_STATUS_RSIE_MASK +#define CR_STATUS_SRS R_CR_STATUS_SRS_MASK + +FIELD(CR_EXCEPTION, CAUSE, 2, 5) +FIELD(CR_EXCEPTION, ECCFTL, 31, 1) + +FIELD(CR_PTEADDR, VPN, 2, 20) +FIELD(CR_PTEADDR, PTBASE, 22, 10) + +FIELD(CR_TLBACC, PFN, 0, 20) +FIELD(CR_TLBACC, G, 20, 1) +FIELD(CR_TLBACC, X, 21, 1) +FIELD(CR_TLBACC, W, 22, 1) +FIELD(CR_TLBACC, R, 23, 1) +FIELD(CR_TLBACC, C, 24, 1) +FIELD(CR_TLBACC, IG, 25, 7) + +#define CR_TLBACC_C R_CR_TLBACC_C_MASK +#define CR_TLBACC_R R_CR_TLBACC_R_MASK +#define CR_TLBACC_W R_CR_TLBACC_W_MASK +#define CR_TLBACC_X R_CR_TLBACC_X_MASK +#define CR_TLBACC_G R_CR_TLBACC_G_MASK + +FIELD(CR_TLBMISC, D, 0, 1) +FIELD(CR_TLBMISC, PERM, 1, 1) +FIELD(CR_TLBMISC, BAD, 2, 1) +FIELD(CR_TLBMISC, DBL, 3, 1) +FIELD(CR_TLBMISC, PID, 4, 14) +FIELD(CR_TLBMISC, WE, 18, 1) +FIELD(CR_TLBMISC, RD, 19, 1) +FIELD(CR_TLBMISC, WAY, 20, 4) +FIELD(CR_TLBMISC, EE, 24, 1) + +#define CR_TLBMISC_EE R_CR_TLBMISC_EE_MASK +#define CR_TLBMISC_RD R_CR_TLBMISC_RD_MASK +#define CR_TLBMISC_WE R_CR_TLBMISC_WE_MASK +#define CR_TLBMISC_DBL R_CR_TLBMISC_DBL_MASK +#define CR_TLBMISC_BAD R_CR_TLBMISC_BAD_MASK +#define CR_TLBMISC_PERM R_CR_TLBMISC_PERM_MASK +#define CR_TLBMISC_D R_CR_TLBMISC_D_MASK /* Exceptions */ #define EXCP_BREAK 0x1000 +#define EXCP_SEMIHOST 0x1001 #define EXCP_RESET 0 #define EXCP_PRESET 1 #define EXCP_IRQ 2 @@ -142,20 +174,27 @@ struct Nios2CPUClass { #define EXCP_UNALIGN 6 #define EXCP_UNALIGND 7 #define EXCP_DIV 8 -#define EXCP_SUPERA 9 +#define EXCP_SUPERA_X 9 #define EXCP_SUPERI 10 -#define EXCP_SUPERD 11 -#define EXCP_TLBD 12 -#define EXCP_TLBX 13 -#define EXCP_TLBR 14 -#define EXCP_TLBW 15 +#define EXCP_SUPERA_D 11 +#define EXCP_TLB_X 12 +#define EXCP_TLB_D (0x1000 | EXCP_TLB_X) +#define EXCP_PERM_X 13 +#define EXCP_PERM_R 14 +#define EXCP_PERM_W 15 #define EXCP_MPUI 16 #define EXCP_MPUD 17 -#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 - struct CPUArchState { - uint32_t regs[NUM_CORE_REGS]; +#ifdef CONFIG_USER_ONLY + uint32_t regs[NUM_GP_REGS]; +#else + uint32_t shadow_regs[NUM_REG_SETS][NUM_GP_REGS]; + /* Pointer into shadow_regs for the current register set. */ + uint32_t *regs; +#endif + uint32_t ctrl[NUM_CR_REGS]; + uint32_t pc; #if !defined(CONFIG_USER_ONLY) Nios2MMU mmu; @@ -163,6 +202,11 @@ struct CPUArchState { int error_code; }; +typedef struct { + uint32_t writable; + uint32_t readonly; +} ControlRegState; + /** * Nios2CPU: * @env: #CPUNios2State @@ -177,7 +221,10 @@ struct ArchCPU { CPUNegativeOffsetState neg; CPUNios2State env; + bool diverr_present; bool mmu_present; + bool eic_present; + uint32_t pid_num_bits; uint32_t tlb_num_ways; uint32_t tlb_num_entries; @@ -186,17 +233,41 @@ struct ArchCPU { uint32_t reset_addr; uint32_t exception_addr; uint32_t fast_tlb_miss_addr; + + /* Bits within each control register which are reserved or readonly. */ + ControlRegState cr_state[NUM_CR_REGS]; + + /* External Interrupt Controller Interface */ + uint32_t rha; /* Requested handler address */ + uint32_t ril; /* Requested interrupt level */ + uint32_t rrs; /* Requested register set */ + bool rnmi; /* Requested nonmaskable interrupt */ }; +static inline bool nios2_cr_reserved(const ControlRegState *s) +{ + return (s->writable | s->readonly) == 0; +} + +static inline void nios2_update_crs(CPUNios2State *env) +{ +#ifndef CONFIG_USER_ONLY + unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS); + env->regs = env->shadow_regs[crs]; +#endif +} + void nios2_tcg_init(void); void nios2_cpu_do_interrupt(CPUState *cs); void dump_mmu(CPUNios2State *env); void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); +G_NORETURN void nios2_cpu_loop_exit_advance(CPUNios2State *env, + uintptr_t retaddr); void do_nios2_semihosting(CPUNios2State *env); @@ -212,36 +283,35 @@ void do_nios2_semihosting(CPUNios2State *env); static inline int cpu_mmu_index(CPUNios2State *env, bool ifetch) { - return (env->regs[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX : + return (env->ctrl[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX : MMU_SUPERVISOR_IDX; } -#ifdef CONFIG_USER_ONLY -void nios2_cpu_record_sigsegv(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - bool maperr, uintptr_t ra); -#else +#ifndef CONFIG_USER_ONLY bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); #endif -static inline int cpu_interrupts_enabled(CPUNios2State *env) -{ - return env->regs[CR_STATUS] & CR_STATUS_PIE; -} - typedef CPUNios2State CPUArchState; typedef Nios2CPU ArchCPU; #include "exec/cpu-all.h" +FIELD(TBFLAGS, CRS0, 0, 1) /* Set if CRS == 0. */ +FIELD(TBFLAGS, U, 1, 1) /* Overlaps CR_STATUS_U */ +FIELD(TBFLAGS, R0_0, 2, 1) /* Set if R0 == 0. */ + static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { - *pc = env->regs[R_PC]; + unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS); + + *pc = env->pc; *cs_base = 0; - *flags = (env->regs[CR_STATUS] & (CR_STATUS_EH | CR_STATUS_U)); + *flags = (env->ctrl[CR_STATUS] & CR_STATUS_U) + | (crs ? 0 : R_TBFLAGS_CRS0_MASK) + | (env->regs[0] ? 0 : R_TBFLAGS_R0_0_MASK); } #endif /* NIOS2_CPU_H */ diff --git a/target/nios2/helper.c b/target/nios2/helper.c index e5c98650e1aa..bb3b09e5a773 100644 --- a/target/nios2/helper.c +++ b/target/nios2/helper.c @@ -28,176 +28,234 @@ #include "exec/helper-proto.h" #include "semihosting/semihost.h" -#if defined(CONFIG_USER_ONLY) -void nios2_cpu_do_interrupt(CPUState *cs) +static void do_exception(Nios2CPU *cpu, uint32_t exception_addr, + uint32_t tlbmisc_set, bool is_break) { - Nios2CPU *cpu = NIOS2_CPU(cs); CPUNios2State *env = &cpu->env; - cs->exception_index = -1; - env->regs[R_EA] = env->regs[R_PC] + 4; -} + CPUState *cs = CPU(cpu); + uint32_t old_status = env->ctrl[CR_STATUS]; + uint32_t new_status = old_status; -void nios2_cpu_record_sigsegv(CPUState *cs, vaddr addr, - MMUAccessType access_type, - bool maperr, uintptr_t retaddr) -{ - /* FIXME: Disentangle kuser page from linux-user sigsegv handling. */ - cs->exception_index = 0xaa; - cpu_loop_exit_restore(cs, retaddr); -} + /* With shadow regs, exceptions are always taken into CRS 0. */ + new_status &= ~R_CR_STATUS_CRS_MASK; + env->regs = env->shadow_regs[0]; -#else /* !CONFIG_USER_ONLY */ + if ((old_status & CR_STATUS_EH) == 0) { + int r_ea = R_EA, cr_es = CR_ESTATUS; -void nios2_cpu_do_interrupt(CPUState *cs) -{ - Nios2CPU *cpu = NIOS2_CPU(cs); - CPUNios2State *env = &cpu->env; + if (is_break) { + r_ea = R_BA; + cr_es = CR_BSTATUS; + } + env->ctrl[cr_es] = old_status; + env->regs[r_ea] = env->pc; + + if (cpu->mmu_present) { + new_status |= CR_STATUS_EH; + + /* + * There are 4 bits that are always written. + * Explicitly clear them, to be set via the argument. + */ + env->ctrl[CR_TLBMISC] &= ~(CR_TLBMISC_D | + CR_TLBMISC_PERM | + CR_TLBMISC_BAD | + CR_TLBMISC_DBL); + env->ctrl[CR_TLBMISC] |= tlbmisc_set; + } - switch (cs->exception_index) { - case EXCP_IRQ: - assert(env->regs[CR_STATUS] & CR_STATUS_PIE); + /* + * With shadow regs, and EH == 0, PRS is set from CRS. + * At least, so says Table 3-9, and some other text, + * though Table 3-38 says otherwise. + */ + new_status = FIELD_DP32(new_status, CR_STATUS, PRS, + FIELD_EX32(old_status, CR_STATUS, CRS)); + } - qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->regs[R_PC]); + new_status &= ~(CR_STATUS_PIE | CR_STATUS_U); - env->regs[CR_ESTATUS] = env->regs[CR_STATUS]; - env->regs[CR_STATUS] |= CR_STATUS_IH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); + env->ctrl[CR_STATUS] = new_status; + if (!is_break) { + env->ctrl[CR_EXCEPTION] = FIELD_DP32(0, CR_EXCEPTION, CAUSE, + cs->exception_index); + } + env->pc = exception_addr; +} - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; +static void do_iic_irq(Nios2CPU *cpu) +{ + do_exception(cpu, cpu->exception_addr, 0, false); +} - env->regs[R_EA] = env->regs[R_PC] + 4; - env->regs[R_PC] = cpu->exception_addr; - break; +static void do_eic_irq(Nios2CPU *cpu) +{ + CPUNios2State *env = &cpu->env; + uint32_t old_status = env->ctrl[CR_STATUS]; + uint32_t new_status = old_status; + uint32_t old_rs = FIELD_EX32(old_status, CR_STATUS, CRS); + uint32_t new_rs = cpu->rrs; + + new_status = FIELD_DP32(new_status, CR_STATUS, CRS, new_rs); + new_status = FIELD_DP32(new_status, CR_STATUS, IL, cpu->ril); + new_status = FIELD_DP32(new_status, CR_STATUS, NMI, cpu->rnmi); + new_status &= ~(CR_STATUS_RSIE | CR_STATUS_U); + new_status |= CR_STATUS_IH; + + if (!(new_status & CR_STATUS_EH)) { + new_status = FIELD_DP32(new_status, CR_STATUS, PRS, old_rs); + if (new_rs == 0) { + env->ctrl[CR_ESTATUS] = old_status; + } else { + if (new_rs != old_rs) { + old_status |= CR_STATUS_SRS; + } + env->shadow_regs[new_rs][R_SSTATUS] = old_status; + } + env->shadow_regs[new_rs][R_EA] = env->pc; + } - case EXCP_TLBD: - if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { - qemu_log_mask(CPU_LOG_INT, "TLB MISS (fast) at pc=%x\n", - env->regs[R_PC]); + env->ctrl[CR_STATUS] = new_status; + nios2_update_crs(env); - /* Fast TLB miss */ - /* Variation from the spec. Table 3-35 of the cpu reference shows - * estatus not being changed for TLB miss but this appears to - * be incorrect. */ - env->regs[CR_ESTATUS] = env->regs[CR_STATUS]; - env->regs[CR_STATUS] |= CR_STATUS_EH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); + env->pc = cpu->rha; +} - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; +void nios2_cpu_do_interrupt(CPUState *cs) +{ + Nios2CPU *cpu = NIOS2_CPU(cs); + CPUNios2State *env = &cpu->env; + uint32_t tlbmisc_set = 0; - env->regs[CR_TLBMISC] &= ~CR_TLBMISC_DBL; - env->regs[CR_TLBMISC] |= CR_TLBMISC_WR; + if (qemu_loglevel_mask(CPU_LOG_INT)) { + const char *name = NULL; - env->regs[R_EA] = env->regs[R_PC] + 4; - env->regs[R_PC] = cpu->fast_tlb_miss_addr; + switch (cs->exception_index) { + case EXCP_IRQ: + name = "interrupt"; + break; + case EXCP_TLB_X: + case EXCP_TLB_D: + if (env->ctrl[CR_STATUS] & CR_STATUS_EH) { + name = "TLB MISS (double)"; + } else { + name = "TLB MISS (fast)"; + } + break; + case EXCP_PERM_R: + case EXCP_PERM_W: + case EXCP_PERM_X: + name = "TLB PERM"; + break; + case EXCP_SUPERA_X: + case EXCP_SUPERA_D: + name = "SUPERVISOR (address)"; + break; + case EXCP_SUPERI: + name = "SUPERVISOR (insn)"; + break; + case EXCP_ILLEGAL: + name = "ILLEGAL insn"; + break; + case EXCP_UNALIGN: + name = "Misaligned (data)"; + break; + case EXCP_UNALIGND: + name = "Misaligned (destination)"; + break; + case EXCP_DIV: + name = "DIV error"; + break; + case EXCP_TRAP: + name = "TRAP insn"; + break; + case EXCP_BREAK: + name = "BREAK insn"; + break; + case EXCP_SEMIHOST: + name = "SEMIHOST insn"; + break; + } + if (name) { + qemu_log("%s at pc=0x%08x\n", name, env->pc); } else { - qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n", - env->regs[R_PC]); - - /* Double TLB miss */ - env->regs[CR_STATUS] |= CR_STATUS_EH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); - - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; - - env->regs[CR_TLBMISC] |= CR_TLBMISC_DBL; + qemu_log("Unknown exception %d at pc=0x%08x\n", + cs->exception_index, env->pc); + } + } - env->regs[R_PC] = cpu->exception_addr; + switch (cs->exception_index) { + case EXCP_IRQ: + /* Note that PC is advanced for interrupts as well. */ + env->pc += 4; + if (cpu->eic_present) { + do_eic_irq(cpu); + } else { + do_iic_irq(cpu); } break; - case EXCP_TLBR: - case EXCP_TLBW: - case EXCP_TLBX: - qemu_log_mask(CPU_LOG_INT, "TLB PERM at pc=%x\n", env->regs[R_PC]); - - env->regs[CR_ESTATUS] = env->regs[CR_STATUS]; - env->regs[CR_STATUS] |= CR_STATUS_EH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); - - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; - - if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { - env->regs[CR_TLBMISC] |= CR_TLBMISC_WR; + case EXCP_TLB_D: + tlbmisc_set = CR_TLBMISC_D; + /* fall through */ + case EXCP_TLB_X: + if (env->ctrl[CR_STATUS] & CR_STATUS_EH) { + tlbmisc_set |= CR_TLBMISC_DBL; + /* + * Normally, we don't write to tlbmisc unless !EH, + * so do it manually for the double-tlb miss exception. + */ + env->ctrl[CR_TLBMISC] &= ~(CR_TLBMISC_D | + CR_TLBMISC_PERM | + CR_TLBMISC_BAD); + env->ctrl[CR_TLBMISC] |= tlbmisc_set; + do_exception(cpu, cpu->exception_addr, 0, false); + } else { + tlbmisc_set |= CR_TLBMISC_WE; + do_exception(cpu, cpu->fast_tlb_miss_addr, tlbmisc_set, false); } - - env->regs[R_EA] = env->regs[R_PC] + 4; - env->regs[R_PC] = cpu->exception_addr; break; - case EXCP_SUPERA: - case EXCP_SUPERI: - case EXCP_SUPERD: - qemu_log_mask(CPU_LOG_INT, "SUPERVISOR exception at pc=%x\n", - env->regs[R_PC]); - - if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { - env->regs[CR_ESTATUS] = env->regs[CR_STATUS]; - env->regs[R_EA] = env->regs[R_PC] + 4; + case EXCP_PERM_R: + case EXCP_PERM_W: + tlbmisc_set = CR_TLBMISC_D; + /* fall through */ + case EXCP_PERM_X: + tlbmisc_set |= CR_TLBMISC_PERM; + if (!(env->ctrl[CR_STATUS] & CR_STATUS_EH)) { + tlbmisc_set |= CR_TLBMISC_WE; } + do_exception(cpu, cpu->exception_addr, tlbmisc_set, false); + break; - env->regs[CR_STATUS] |= CR_STATUS_EH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); - - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; - - env->regs[R_PC] = cpu->exception_addr; + case EXCP_SUPERA_D: + case EXCP_UNALIGN: + tlbmisc_set = CR_TLBMISC_D; + /* fall through */ + case EXCP_SUPERA_X: + case EXCP_UNALIGND: + tlbmisc_set |= CR_TLBMISC_BAD; + do_exception(cpu, cpu->exception_addr, tlbmisc_set, false); break; + case EXCP_SUPERI: case EXCP_ILLEGAL: + case EXCP_DIV: case EXCP_TRAP: - qemu_log_mask(CPU_LOG_INT, "TRAP exception at pc=%x\n", - env->regs[R_PC]); - - if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { - env->regs[CR_ESTATUS] = env->regs[CR_STATUS]; - env->regs[R_EA] = env->regs[R_PC] + 4; - } - - env->regs[CR_STATUS] |= CR_STATUS_EH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); - - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; - - env->regs[R_PC] = cpu->exception_addr; + do_exception(cpu, cpu->exception_addr, 0, false); break; case EXCP_BREAK: - qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n", - env->regs[R_PC]); - /* The semihosting instruction is "break 1". */ - if (semihosting_enabled() && - cpu_ldl_code(env, env->regs[R_PC]) == 0x003da07a) { - qemu_log_mask(CPU_LOG_INT, "Entering semihosting\n"); - env->regs[R_PC] += 4; - do_nios2_semihosting(env); - break; - } - - if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { - env->regs[CR_BSTATUS] = env->regs[CR_STATUS]; - env->regs[R_BA] = env->regs[R_PC] + 4; - } - - env->regs[CR_STATUS] |= CR_STATUS_EH; - env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U); - - env->regs[CR_EXCEPTION] &= ~(0x1F << 2); - env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2; + do_exception(cpu, cpu->exception_addr, 0, true); + break; - env->regs[R_PC] = cpu->exception_addr; + case EXCP_SEMIHOST: + do_nios2_semihosting(env); break; default: - cpu_abort(cs, "unhandled exception type=%d\n", - cs->exception_index); - break; + cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index); } } @@ -232,9 +290,9 @@ void nios2_cpu_do_unaligned_access(CPUState *cs, vaddr addr, Nios2CPU *cpu = NIOS2_CPU(cs); CPUNios2State *env = &cpu->env; - env->regs[CR_BADADDR] = addr; - env->regs[CR_EXCEPTION] = EXCP_UNALIGN << 2; - helper_raise_exception(env, EXCP_UNALIGN); + env->ctrl[CR_BADADDR] = addr; + cs->exception_index = EXCP_UNALIGN; + nios2_cpu_loop_exit_advance(env, retaddr); } bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size, @@ -243,7 +301,7 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size, { Nios2CPU *cpu = NIOS2_CPU(cs); CPUNios2State *env = &cpu->env; - unsigned int excp = EXCP_TLBD; + unsigned int excp; target_ulong vaddr, paddr; Nios2MMULookup lu; unsigned int hit; @@ -270,9 +328,10 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size, if (probe) { return false; } - cs->exception_index = EXCP_SUPERA; - env->regs[CR_BADADDR] = address; - cpu_loop_exit_restore(cs, retaddr); + cs->exception_index = (access_type == MMU_INST_FETCH + ? EXCP_SUPERA_X : EXCP_SUPERA_D); + env->ctrl[CR_BADADDR] = address; + nios2_cpu_loop_exit_advance(env, retaddr); } } @@ -291,25 +350,23 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } /* Permission violation */ - excp = (access_type == MMU_DATA_LOAD ? EXCP_TLBR : - access_type == MMU_DATA_STORE ? EXCP_TLBW : EXCP_TLBX); + excp = (access_type == MMU_DATA_LOAD ? EXCP_PERM_R : + access_type == MMU_DATA_STORE ? EXCP_PERM_W : EXCP_PERM_X); + } else { + excp = (access_type == MMU_INST_FETCH ? EXCP_TLB_X: EXCP_TLB_D); } if (probe) { return false; } - if (access_type == MMU_INST_FETCH) { - env->regs[CR_TLBMISC] &= ~CR_TLBMISC_D; - } else { - env->regs[CR_TLBMISC] |= CR_TLBMISC_D; - } - env->regs[CR_PTEADDR] &= CR_PTEADDR_PTBASE_MASK; - env->regs[CR_PTEADDR] |= (address >> 10) & CR_PTEADDR_VPN_MASK; - env->mmu.pteaddr_wr = env->regs[CR_PTEADDR]; + env->ctrl[CR_TLBMISC] = FIELD_DP32(env->ctrl[CR_TLBMISC], CR_TLBMISC, D, + access_type != MMU_INST_FETCH); + env->ctrl[CR_PTEADDR] = FIELD_DP32(env->ctrl[CR_PTEADDR], CR_PTEADDR, VPN, + address >> TARGET_PAGE_BITS); + env->mmu.pteaddr_wr = env->ctrl[CR_PTEADDR]; cs->exception_index = excp; - env->regs[CR_BADADDR] = address; - cpu_loop_exit_restore(cs, retaddr); + env->ctrl[CR_BADADDR] = address; + nios2_cpu_loop_exit_advance(env, retaddr); } -#endif /* !CONFIG_USER_ONLY */ diff --git a/target/nios2/helper.h b/target/nios2/helper.h index a44ecfdf7a61..1648d76adea7 100644 --- a/target/nios2/helper.h +++ b/target/nios2/helper.h @@ -19,8 +19,13 @@ */ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) +DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, s32, env, s32, s32) +DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32) #if !defined(CONFIG_USER_ONLY) +DEF_HELPER_3(eret, noreturn, env, i32, i32) +DEF_HELPER_FLAGS_2(rdprs, TCG_CALL_NO_WG, i32, env, i32) +DEF_HELPER_3(wrprs, void, env, i32, i32) DEF_HELPER_2(mmu_write_tlbacc, void, env, i32) DEF_HELPER_2(mmu_write_tlbmisc, void, env, i32) DEF_HELPER_2(mmu_write_pteaddr, void, env, i32) diff --git a/target/nios2/meson.build b/target/nios2/meson.build index 62b384702d75..c6e2243cc3aa 100644 --- a/target/nios2/meson.build +++ b/target/nios2/meson.build @@ -1,14 +1,17 @@ nios2_ss = ss.source_set() nios2_ss.add(files( 'cpu.c', - 'helper.c', - 'nios2-semi.c', 'op_helper.c', 'translate.c', )) nios2_softmmu_ss = ss.source_set() -nios2_softmmu_ss.add(files('monitor.c', 'mmu.c')) +nios2_softmmu_ss.add(files( + 'helper.c', + 'monitor.c', + 'mmu.c', + 'nios2-semi.c', +)) target_arch += {'nios2': nios2_ss} target_softmmu_arch += {'nios2': nios2_softmmu_ss} diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c index 4daab2a7ab31..d9b690b78e10 100644 --- a/target/nios2/mmu.c +++ b/target/nios2/mmu.c @@ -33,7 +33,7 @@ unsigned int mmu_translate(CPUNios2State *env, target_ulong vaddr, int rw, int mmu_idx) { Nios2CPU *cpu = env_archcpu(env); - int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4; + int pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID); int vpn = vaddr >> 12; int way, n_ways = cpu->tlb_num_ways; @@ -49,7 +49,7 @@ unsigned int mmu_translate(CPUNios2State *env, } lu->vaddr = vaddr & TARGET_PAGE_MASK; - lu->paddr = (entry->data & CR_TLBACC_PFN_MASK) << TARGET_PAGE_BITS; + lu->paddr = FIELD_EX32(entry->data, CR_TLBACC, PFN) << TARGET_PAGE_BITS; lu->prot = ((entry->data & CR_TLBACC_R) ? PAGE_READ : 0) | ((entry->data & CR_TLBACC_W) ? PAGE_WRITE : 0) | ((entry->data & CR_TLBACC_X) ? PAGE_EXEC : 0); @@ -86,27 +86,27 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v) CPUState *cs = env_cpu(env); Nios2CPU *cpu = env_archcpu(env); - trace_nios2_mmu_write_tlbacc(v >> CR_TLBACC_IGN_SHIFT, + trace_nios2_mmu_write_tlbacc(FIELD_EX32(v, CR_TLBACC, IG), (v & CR_TLBACC_C) ? 'C' : '.', (v & CR_TLBACC_R) ? 'R' : '.', (v & CR_TLBACC_W) ? 'W' : '.', (v & CR_TLBACC_X) ? 'X' : '.', (v & CR_TLBACC_G) ? 'G' : '.', - v & CR_TLBACC_PFN_MASK); + FIELD_EX32(v, CR_TLBACC, PFN)); /* if tlbmisc.WE == 1 then trigger a TLB write on writes to TLBACC */ - if (env->regs[CR_TLBMISC] & CR_TLBMISC_WR) { - int way = (env->regs[CR_TLBMISC] >> CR_TLBMISC_WAY_SHIFT); - int vpn = (env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK) >> 2; - int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4; - int g = (v & CR_TLBACC_G) ? 1 : 0; - int valid = ((vpn & CR_TLBACC_PFN_MASK) < 0xC0000) ? 1 : 0; + if (env->ctrl[CR_TLBMISC] & CR_TLBMISC_WE) { + int way = FIELD_EX32(env->ctrl[CR_TLBMISC], CR_TLBMISC, WAY); + int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN); + int pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID); + int g = FIELD_EX32(v, CR_TLBACC, G); + int valid = FIELD_EX32(vpn, CR_TLBACC, PFN) < 0xC0000; Nios2TLBEntry *entry = &env->mmu.tlb[(way * cpu->tlb_num_ways) + (vpn & env->mmu.tlb_entry_mask)]; uint32_t newTag = (vpn << 12) | (g << 11) | (valid << 10) | pid; uint32_t newData = v & (CR_TLBACC_C | CR_TLBACC_R | CR_TLBACC_W | - CR_TLBACC_X | CR_TLBACC_PFN_MASK); + CR_TLBACC_X | R_CR_TLBACC_PFN_MASK); if ((entry->tag != newTag) || (entry->data != newData)) { if (entry->tag & (1 << 10)) { @@ -117,10 +117,9 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v) entry->data = newData; } /* Auto-increment tlbmisc.WAY */ - env->regs[CR_TLBMISC] = - (env->regs[CR_TLBMISC] & ~CR_TLBMISC_WAY_MASK) | - (((way + 1) & (cpu->tlb_num_ways - 1)) << - CR_TLBMISC_WAY_SHIFT); + env->ctrl[CR_TLBMISC] = FIELD_DP32(env->ctrl[CR_TLBMISC], + CR_TLBMISC, WAY, + (way + 1) & (cpu->tlb_num_ways - 1)); } /* Writes to TLBACC don't change the read-back value */ @@ -130,40 +129,41 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v) void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v) { Nios2CPU *cpu = env_archcpu(env); + uint32_t new_pid = FIELD_EX32(v, CR_TLBMISC, PID); + uint32_t old_pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID); + uint32_t way = FIELD_EX32(v, CR_TLBMISC, WAY); - trace_nios2_mmu_write_tlbmisc(v >> CR_TLBMISC_WAY_SHIFT, + trace_nios2_mmu_write_tlbmisc(way, (v & CR_TLBMISC_RD) ? 'R' : '.', - (v & CR_TLBMISC_WR) ? 'W' : '.', + (v & CR_TLBMISC_WE) ? 'W' : '.', (v & CR_TLBMISC_DBL) ? '2' : '.', (v & CR_TLBMISC_BAD) ? 'B' : '.', (v & CR_TLBMISC_PERM) ? 'P' : '.', (v & CR_TLBMISC_D) ? 'D' : '.', - (v & CR_TLBMISC_PID_MASK) >> 4); + new_pid); - if ((v & CR_TLBMISC_PID_MASK) != - (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK)) { - mmu_flush_pid(env, (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> - CR_TLBMISC_PID_SHIFT); + if (new_pid != old_pid) { + mmu_flush_pid(env, old_pid); } + /* if tlbmisc.RD == 1 then trigger a TLB read on writes to TLBMISC */ if (v & CR_TLBMISC_RD) { - int way = (v >> CR_TLBMISC_WAY_SHIFT); - int vpn = (env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK) >> 2; + int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN); Nios2TLBEntry *entry = &env->mmu.tlb[(way * cpu->tlb_num_ways) + (vpn & env->mmu.tlb_entry_mask)]; - env->regs[CR_TLBACC] &= CR_TLBACC_IGN_MASK; - env->regs[CR_TLBACC] |= entry->data; - env->regs[CR_TLBACC] |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0; - env->regs[CR_TLBMISC] = - (v & ~CR_TLBMISC_PID_MASK) | - ((entry->tag & ((1 << cpu->pid_num_bits) - 1)) << - CR_TLBMISC_PID_SHIFT); - env->regs[CR_PTEADDR] &= ~CR_PTEADDR_VPN_MASK; - env->regs[CR_PTEADDR] |= (entry->tag >> 12) << CR_PTEADDR_VPN_SHIFT; + env->ctrl[CR_TLBACC] &= R_CR_TLBACC_IG_MASK; + env->ctrl[CR_TLBACC] |= entry->data; + env->ctrl[CR_TLBACC] |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0; + env->ctrl[CR_TLBMISC] = FIELD_DP32(v, CR_TLBMISC, PID, + entry->tag & + ((1 << cpu->pid_num_bits) - 1)); + env->ctrl[CR_PTEADDR] = FIELD_DP32(env->ctrl[CR_PTEADDR], + CR_PTEADDR, VPN, + entry->tag >> TARGET_PAGE_BITS); } else { - env->regs[CR_TLBMISC] = v; + env->ctrl[CR_TLBMISC] = v; } env->mmu.tlbmisc_wr = v; @@ -171,12 +171,12 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v) void helper_mmu_write_pteaddr(CPUNios2State *env, uint32_t v) { - trace_nios2_mmu_write_pteaddr(v >> CR_PTEADDR_PTBASE_SHIFT, - (v & CR_PTEADDR_VPN_MASK) >> CR_PTEADDR_VPN_SHIFT); + trace_nios2_mmu_write_pteaddr(FIELD_EX32(v, CR_PTEADDR, PTBASE), + FIELD_EX32(v, CR_PTEADDR, VPN)); /* Writes to PTEADDR don't change the read-back VPN value */ - env->regs[CR_PTEADDR] = (v & ~CR_PTEADDR_VPN_MASK) | - (env->regs[CR_PTEADDR] & CR_PTEADDR_VPN_MASK); + env->ctrl[CR_PTEADDR] = ((v & ~R_CR_PTEADDR_VPN_MASK) | + (env->ctrl[CR_PTEADDR] & R_CR_PTEADDR_VPN_MASK)); env->mmu.pteaddr_wr = v; } @@ -207,7 +207,7 @@ void dump_mmu(CPUNios2State *env) entry->tag >> 12, entry->tag & ((1 << cpu->pid_num_bits) - 1), (entry->tag & (1 << 11)) ? 'G' : '-', - entry->data & CR_TLBACC_PFN_MASK, + FIELD_EX32(entry->data, CR_TLBACC, PFN), (entry->data & CR_TLBACC_C) ? 'C' : '-', (entry->data & CR_TLBACC_R) ? 'R' : '-', (entry->data & CR_TLBACC_W) ? 'W' : '-', diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c index 5a7ad0c7108d..f76e8588c5be 100644 --- a/target/nios2/nios2-semi.c +++ b/target/nios2/nios2-semi.c @@ -22,15 +22,10 @@ */ #include "qemu/osdep.h" - #include "cpu.h" #include "exec/gdbstub.h" -#if defined(CONFIG_USER_ONLY) -#include "qemu.h" -#else -#include "qemu-common.h" -#include "exec/softmmu-semi.h" -#endif +#include "semihosting/syscalls.h" +#include "semihosting/softmmu-uaccess.h" #include "qemu/log.h" #define HOSTED_EXIT 0 @@ -48,105 +43,43 @@ #define HOSTED_ISATTY 12 #define HOSTED_SYSTEM 13 -typedef uint32_t gdb_mode_t; -typedef uint32_t gdb_time_t; - -struct nios2_gdb_stat { - uint32_t gdb_st_dev; /* device */ - uint32_t gdb_st_ino; /* inode */ - gdb_mode_t gdb_st_mode; /* protection */ - uint32_t gdb_st_nlink; /* number of hard links */ - uint32_t gdb_st_uid; /* user ID of owner */ - uint32_t gdb_st_gid; /* group ID of owner */ - uint32_t gdb_st_rdev; /* device type (if inode device) */ - uint64_t gdb_st_size; /* total size, in bytes */ - uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ - uint64_t gdb_st_blocks; /* number of blocks allocated */ - gdb_time_t gdb_st_atime; /* time of last access */ - gdb_time_t gdb_st_mtime; /* time of last modification */ - gdb_time_t gdb_st_ctime; /* time of last change */ -} QEMU_PACKED; - -struct gdb_timeval { - gdb_time_t tv_sec; /* second */ - uint64_t tv_usec; /* microsecond */ -} QEMU_PACKED; - -#define GDB_O_RDONLY 0x0 -#define GDB_O_WRONLY 0x1 -#define GDB_O_RDWR 0x2 -#define GDB_O_APPEND 0x8 -#define GDB_O_CREAT 0x200 -#define GDB_O_TRUNC 0x400 -#define GDB_O_EXCL 0x800 - -static int translate_openflags(int flags) -{ - 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 bool translate_stat(CPUNios2State *env, target_ulong addr, - struct stat *s) +static int host_to_gdb_errno(int err) { - struct nios2_gdb_stat *p; - - p = lock_user(VERIFY_WRITE, addr, sizeof(struct nios2_gdb_stat), 0); - - if (!p) { - return false; +#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 nios2_gdb_stat)); - return true; +#undef E } -static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, - uint32_t err) +static void nios2_semi_u32_cb(CPUState *cs, uint64_t ret, int err) { + Nios2CPU *cpu = NIOS2_CPU(cs); + CPUNios2State *env = &cpu->env; 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. @@ -157,59 +90,43 @@ static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, } } -static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret, - uint32_t err) +static void nios2_semi_u64_cb(CPUState *cs, uint64_t ret, int err) { + Nios2CPU *cpu = NIOS2_CPU(cs); + CPUNios2State *env = &cpu->env; target_ulong args = env->regs[R_ARG1]; + 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"); } } -static int nios2_semi_is_lseek; - -static void nios2_semi_cb(CPUState *cs, target_ulong ret, target_ulong err) -{ - Nios2CPU *cpu = NIOS2_CPU(cs); - CPUNios2State *env = &cpu->env; - - if (nios2_semi_is_lseek) { - /* - * FIXME: We've already lost the high bits of the lseek - * return value. - */ - nios2_semi_return_u64(env, ret, err); - nios2_semi_is_lseek = 0; - } else { - nios2_semi_return_u32(env, ret, err); - } -} - /* * Read the input value from the argument block; fail the semihosting * call if the memory read fails. */ #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]; @@ -217,238 +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_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_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_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_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()) { - nios2_semi_is_lseek = 1; - gdb_do_syscall(nios2_semi_cb, "lseek,%x,%lx,%x", - arg0, off, arg3); - } else { - off = lseek(arg0, off, arg3); - nios2_semi_return_u64(env, 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_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_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_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_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_cb, "gettimeofday,%x,%x", - arg0, 0); - return; - } else { - qemu_timeval tv; - struct gdb_timeval *p; - result = qemu_gettimeofday(&tv); - if (result == 0) { - p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), - 0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - p->tv_sec = cpu_to_be32(tv.tv_sec); - p->tv_usec = cpu_to_be64(tv.tv_usec); - 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_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_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_return_u32(env, result, errno); } diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c index caa885f7b4d7..0aaf33ffc2b0 100644 --- a/target/nios2/op_helper.c +++ b/target/nios2/op_helper.c @@ -30,3 +30,91 @@ void helper_raise_exception(CPUNios2State *env, uint32_t index) cs->exception_index = index; cpu_loop_exit(cs); } + +void nios2_cpu_loop_exit_advance(CPUNios2State *env, uintptr_t retaddr) +{ + CPUState *cs = env_cpu(env); + + /* + * Note that PC is advanced for all hardware exceptions. + * Do this here, rather than in restore_state_to_opc(), + * lest we affect QEMU internal exceptions, like EXCP_DEBUG. + */ + cpu_restore_state(cs, retaddr); + env->pc += 4; + cpu_loop_exit(cs); +} + +static void maybe_raise_div(CPUNios2State *env, uintptr_t ra) +{ + Nios2CPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + if (cpu->diverr_present) { + cs->exception_index = EXCP_DIV; + nios2_cpu_loop_exit_advance(env, ra); + } +} + +int32_t helper_divs(CPUNios2State *env, int32_t num, int32_t den) +{ + if (unlikely(den == 0) || unlikely(den == -1 && num == INT32_MIN)) { + maybe_raise_div(env, GETPC()); + return num; /* undefined */ + } + return num / den; +} + +uint32_t helper_divu(CPUNios2State *env, uint32_t num, uint32_t den) +{ + if (unlikely(den == 0)) { + maybe_raise_div(env, GETPC()); + return num; /* undefined */ + } + return num / den; +} + +#ifndef CONFIG_USER_ONLY +void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc) +{ + Nios2CPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + if (unlikely(new_pc & 3)) { + env->ctrl[CR_BADADDR] = new_pc; + cs->exception_index = EXCP_UNALIGND; + nios2_cpu_loop_exit_advance(env, GETPC()); + } + + /* + * None of estatus, bstatus, or sstatus have constraints on write; + * do not allow reserved fields in status to be set. + * When shadow registers are enabled, eret *does* restore CRS. + * Rather than testing eic_present to decide, mask CRS out of + * the set of readonly fields. + */ + new_status &= cpu->cr_state[CR_STATUS].writable | + (cpu->cr_state[CR_STATUS].readonly & R_CR_STATUS_CRS_MASK); + + env->ctrl[CR_STATUS] = new_status; + env->pc = new_pc; + nios2_update_crs(env); + cpu_loop_exit(cs); +} + +/* + * RDPRS and WRPRS are implemented out of line so that if PRS == CRS, + * all of the tcg global temporaries are synced back to ENV. + */ +uint32_t helper_rdprs(CPUNios2State *env, uint32_t regno) +{ + unsigned prs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, PRS); + return env->shadow_regs[prs][regno]; +} + +void helper_wrprs(CPUNios2State *env, uint32_t regno, uint32_t val) +{ + unsigned prs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, PRS); + env->shadow_regs[prs][regno] = val; +} +#endif /* !CONFIG_USER_ONLY */ diff --git a/target/nios2/translate.c b/target/nios2/translate.c index f89271dbed68..4db8b47744bc 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -33,9 +33,9 @@ #include "exec/translator.h" #include "qemu/qemu-print.h" #include "exec/gen-icount.h" +#include "semihosting/semihost.h" /* is_jmp field values */ -#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ #define INSTRUCTION_FLG(func, flags) { (func), (flags) } @@ -52,32 +52,53 @@ #define INSN_R_TYPE 0x3A /* I-Type instruction parsing */ +typedef struct { + uint8_t op; + union { + uint16_t u; + int16_t s; + } imm16; + uint8_t b; + uint8_t a; +} InstrIType; + #define I_TYPE(instr, code) \ - struct { \ - uint8_t op; \ - union { \ - uint16_t u; \ - int16_t s; \ - } imm16; \ - uint8_t b; \ - uint8_t a; \ - } (instr) = { \ + InstrIType (instr) = { \ .op = extract32((code), 0, 6), \ .imm16.u = extract32((code), 6, 16), \ .b = extract32((code), 22, 5), \ .a = extract32((code), 27, 5), \ } +typedef target_ulong ImmFromIType(const InstrIType *); + +static target_ulong imm_unsigned(const InstrIType *i) +{ + return i->imm16.u; +} + +static target_ulong imm_signed(const InstrIType *i) +{ + return i->imm16.s; +} + +static target_ulong imm_shifted(const InstrIType *i) +{ + return i->imm16.u << 16; +} + /* R-Type instruction parsing */ +typedef struct { + uint8_t op; + uint8_t imm5; + uint8_t opx; + uint8_t c; + uint8_t b; + uint8_t a; +} InstrRType; + #define R_TYPE(instr, code) \ - struct { \ - uint8_t op; \ - uint8_t imm5; \ - uint8_t opx; \ - uint8_t c; \ - uint8_t b; \ - uint8_t a; \ - } (instr) = { \ + InstrRType (instr) = { \ .op = extract32((code), 0, 6), \ .imm5 = extract32((code), 6, 5), \ .opx = extract32((code), 11, 6), \ @@ -87,23 +108,36 @@ } /* J-Type instruction parsing */ +typedef struct { + uint8_t op; + uint32_t imm26; +} InstrJType; + #define J_TYPE(instr, code) \ - struct { \ - uint8_t op; \ - uint32_t imm26; \ - } (instr) = { \ + InstrJType (instr) = { \ .op = extract32((code), 0, 6), \ .imm26 = extract32((code), 6, 26), \ } +typedef void GenFn2i(TCGv, TCGv, target_long); +typedef void GenFn3(TCGv, TCGv, TCGv); +typedef void GenFn4(TCGv, TCGv, TCGv, TCGv); + typedef struct DisasContext { DisasContextBase base; - TCGv_i32 zero; target_ulong pc; int mem_idx; + uint32_t tb_flags; + TCGv sink; + const ControlRegState *cr_state; + bool eic_present; } DisasContext; -static TCGv cpu_R[NUM_CORE_REGS]; +static TCGv cpu_R[NUM_GP_REGS]; +static TCGv cpu_pc; +#ifndef CONFIG_USER_ONLY +static TCGv cpu_crs_R[NUM_GP_REGS]; +#endif typedef struct Nios2Instruction { void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags); @@ -122,31 +156,57 @@ static uint8_t get_opxcode(uint32_t code) return instr.opx; } -static TCGv load_zero(DisasContext *dc) +static TCGv load_gpr(DisasContext *dc, unsigned reg) { - if (!dc->zero) { - dc->zero = tcg_const_i32(0); + assert(reg < NUM_GP_REGS); + + /* + * With shadow register sets, register r0 does not necessarily contain 0, + * but it is overwhelmingly likely that it does -- software is supposed + * to have set r0 to 0 in every shadow register set before use. + */ + if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) { + return tcg_constant_tl(0); + } + if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { + return cpu_R[reg]; } - return dc->zero; +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + return cpu_crs_R[reg]; +#endif } -static TCGv load_gpr(DisasContext *dc, uint8_t reg) +static TCGv dest_gpr(DisasContext *dc, unsigned reg) { - if (likely(reg != R_ZERO)) { + assert(reg < NUM_GP_REGS); + + /* + * The spec for shadow register sets isn't clear, but we assume that + * writes to r0 are discarded regardless of CRS. + */ + if (unlikely(reg == R_ZERO)) { + if (dc->sink == NULL) { + dc->sink = tcg_temp_new(); + } + return dc->sink; + } + if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { return cpu_R[reg]; - } else { - return load_zero(dc); } +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + return cpu_crs_R[reg]; +#endif } -static void t_gen_helper_raise_exception(DisasContext *dc, - uint32_t index) +static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index) { - TCGv_i32 tmp = tcg_const_i32(index); - - tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); - gen_helper_raise_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + /* Note that PC is advanced for all hardware exceptions. */ + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); + gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); dc->base.is_jmp = DISAS_NORETURN; } @@ -156,12 +216,36 @@ static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest) if (translator_use_goto_tb(&dc->base, dest)) { tcg_gen_goto_tb(n); - tcg_gen_movi_tl(cpu_R[R_PC], dest); + tcg_gen_movi_tl(cpu_pc, dest); tcg_gen_exit_tb(tb, n); } else { - tcg_gen_movi_tl(cpu_R[R_PC], dest); - tcg_gen_exit_tb(NULL, 0); + tcg_gen_movi_tl(cpu_pc, dest); + tcg_gen_lookup_and_goto_ptr(); } + dc->base.is_jmp = DISAS_NORETURN; +} + +static void gen_jumpr(DisasContext *dc, int regno, bool is_call) +{ + TCGLabel *l = gen_new_label(); + TCGv test = tcg_temp_new(); + TCGv dest = load_gpr(dc, regno); + + tcg_gen_andi_tl(test, dest, 3); + tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l); + tcg_temp_free(test); + + tcg_gen_mov_tl(cpu_pc, dest); + if (is_call) { + tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next); + } + tcg_gen_lookup_and_goto_ptr(); + + gen_set_label(l); + tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR])); + t_gen_helper_raise_exception(dc, EXCP_UNALIGND); + + dc->base.is_jmp = DISAS_NORETURN; } static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags) @@ -169,12 +253,14 @@ static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags) t_gen_helper_raise_exception(dc, flags); } -static void gen_check_supervisor(DisasContext *dc) +static bool gen_check_supervisor(DisasContext *dc) { - if (dc->base.tb->flags & CR_STATUS_U) { + if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) { /* CPU in user mode, privileged instruction called, stop. */ t_gen_helper_raise_exception(dc, EXCP_SUPERI); + return false; } + return true; } /* @@ -193,12 +279,11 @@ static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags) { J_TYPE(instr, code); gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2)); - dc->base.is_jmp = DISAS_NORETURN; } static void call(DisasContext *dc, uint32_t code, uint32_t flags) { - tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next); + tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next); jmpi(dc, code, flags); } @@ -211,27 +296,10 @@ static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags) I_TYPE(instr, code); TCGv addr = tcg_temp_new(); - TCGv data; - - /* - * WARNING: Loads into R_ZERO are ignored, but we must generate the - * memory access itself to emulate the CPU precisely. Load - * from a protected page to R_ZERO will cause SIGSEGV on - * the Nios2 CPU. - */ - if (likely(instr.b != R_ZERO)) { - data = cpu_R[instr.b]; - } else { - data = tcg_temp_new(); - } + TCGv data = dest_gpr(dc, instr.b); tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags); - - if (unlikely(instr.b == R_ZERO)) { - tcg_temp_free(data); - } - tcg_temp_free(addr); } @@ -253,7 +321,6 @@ static void br(DisasContext *dc, uint32_t code, uint32_t flags) I_TYPE(instr, code); gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4)); - dc->base.is_jmp = DISAS_NORETURN; } static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags) @@ -261,48 +328,86 @@ static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags) I_TYPE(instr, code); TCGLabel *l1 = gen_new_label(); - tcg_gen_brcond_tl(flags, cpu_R[instr.a], cpu_R[instr.b], l1); + tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1); gen_goto_tb(dc, 0, dc->base.pc_next); gen_set_label(l1); gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4)); - dc->base.is_jmp = DISAS_NORETURN; } /* Comparison instructions */ -#define gen_i_cmpxx(fname, op3) \ -static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ -{ \ - I_TYPE(instr, (code)); \ - tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3)); \ +static void do_i_cmpxx(DisasContext *dc, uint32_t insn, + TCGCond cond, ImmFromIType *imm) +{ + I_TYPE(instr, insn); + tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b), + load_gpr(dc, instr.a), imm(&instr)); } -gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s) -gen_i_cmpxx(gen_cmpxxui, instr.imm16.u) +#define gen_i_cmpxx(fname, imm) \ + static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ + { do_i_cmpxx(dc, code, flags, imm); } + +gen_i_cmpxx(gen_cmpxxsi, imm_signed) +gen_i_cmpxx(gen_cmpxxui, imm_unsigned) /* Math/logic instructions */ -#define gen_i_math_logic(fname, insn, resimm, op3) \ -static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ -{ \ - I_TYPE(instr, (code)); \ - if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \ - return; \ - } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \ - tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0); \ - } else { \ - tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3)); \ - } \ -} - -gen_i_math_logic(addi, addi, 1, instr.imm16.s) -gen_i_math_logic(muli, muli, 0, instr.imm16.s) - -gen_i_math_logic(andi, andi, 0, instr.imm16.u) -gen_i_math_logic(ori, ori, 1, instr.imm16.u) -gen_i_math_logic(xori, xori, 1, instr.imm16.u) - -gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16) -gen_i_math_logic(orhi , ori, 1, instr.imm16.u << 16) -gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16) +static void do_i_math_logic(DisasContext *dc, uint32_t insn, + GenFn2i *fn, ImmFromIType *imm, + bool x_op_0_eq_x) +{ + I_TYPE(instr, insn); + target_ulong val; + + if (unlikely(instr.b == R_ZERO)) { + /* Store to R_ZERO is ignored -- this catches the canonical NOP. */ + return; + } + + val = imm(&instr); + + if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) { + /* This catches the canonical expansions of movi and movhi. */ + tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0); + } else { + fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val); + } +} + +#define gen_i_math_logic(fname, insn, x_op_0, imm) \ + static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ + { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); } + +gen_i_math_logic(addi, addi, 1, imm_signed) +gen_i_math_logic(muli, muli, 0, imm_signed) + +gen_i_math_logic(andi, andi, 0, imm_unsigned) +gen_i_math_logic(ori, ori, 1, imm_unsigned) +gen_i_math_logic(xori, xori, 1, imm_unsigned) + +gen_i_math_logic(andhi, andi, 0, imm_shifted) +gen_i_math_logic(orhi , ori, 1, imm_shifted) +gen_i_math_logic(xorhi, xori, 1, imm_shifted) + +/* rB <- prs.rA + sigma(IMM16) */ +static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags) +{ + if (!dc->eic_present) { + t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); + return; + } + if (!gen_check_supervisor(dc)) { + return; + } + +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + I_TYPE(instr, code); + TCGv dest = dest_gpr(dc, instr.b); + gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a)); + tcg_gen_addi_tl(dest, dest, instr.imm16.s); +#endif +} /* Prototype only, defined below */ static void handle_r_type_instr(DisasContext *dc, uint32_t code, @@ -365,7 +470,7 @@ static const Nios2Instruction i_type_instructions[] = { INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */ INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */ INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */ - INSTRUCTION_UNIMPLEMENTED(), /* rdprs */ + INSTRUCTION(rdprs), /* rdprs */ INSTRUCTION_ILLEGAL(), INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */ INSTRUCTION_NOP(), /* flushd */ @@ -384,26 +489,51 @@ static const Nios2Instruction i_type_instructions[] = { */ static void eret(DisasContext *dc, uint32_t code, uint32_t flags) { - tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]); - tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]); + if (!gen_check_supervisor(dc)) { + return; + } - dc->base.is_jmp = DISAS_JUMP; +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { + TCGv tmp = tcg_temp_new(); + tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS])); + gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA)); + tcg_temp_free(tmp); + } else { + gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA)); + } + dc->base.is_jmp = DISAS_NORETURN; +#endif } /* PC <- ra */ static void ret(DisasContext *dc, uint32_t code, uint32_t flags) { - tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_RA]); - - dc->base.is_jmp = DISAS_JUMP; + gen_jumpr(dc, R_RA, false); } -/* PC <- ba */ +/* + * status <- bstatus + * PC <- ba + */ static void bret(DisasContext *dc, uint32_t code, uint32_t flags) { - tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_BA]); + if (!gen_check_supervisor(dc)) { + return; + } - dc->base.is_jmp = DISAS_JUMP; +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + TCGv tmp = tcg_temp_new(); + tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS])); + gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA)); + tcg_temp_free(tmp); + + dc->base.is_jmp = DISAS_NORETURN; +#endif } /* PC <- rA */ @@ -411,9 +541,7 @@ static void jmp(DisasContext *dc, uint32_t code, uint32_t flags) { R_TYPE(instr, code); - tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a)); - - dc->base.is_jmp = DISAS_JUMP; + gen_jumpr(dc, instr.a, false); } /* rC <- PC + 4 */ @@ -421,9 +549,7 @@ static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags) { R_TYPE(instr, code); - if (likely(instr.c != R_ZERO)) { - tcg_gen_movi_tl(cpu_R[instr.c], dc->base.pc_next); - } + tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next); } /* @@ -434,24 +560,29 @@ static void callr(DisasContext *dc, uint32_t code, uint32_t flags) { R_TYPE(instr, code); - tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a)); - tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next); - - dc->base.is_jmp = DISAS_JUMP; + gen_jumpr(dc, instr.a, true); } /* rC <- ctlN */ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags) { - R_TYPE(instr, code); + if (!gen_check_supervisor(dc)) { + return; + } - gen_check_supervisor(dc); +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + R_TYPE(instr, code); + TCGv t1, t2, dest = dest_gpr(dc, instr.c); - if (unlikely(instr.c == R_ZERO)) { + /* Reserved registers read as zero. */ + if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) { + tcg_gen_movi_tl(dest, 0); return; } - switch (instr.imm5 + CR_BASE) { + switch (instr.imm5) { case CR_IPENDING: /* * The value of the ipending register is synthetic. @@ -461,24 +592,44 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags) * must perform the AND here, and anywhere else we need the * guest value of ipending. */ - tcg_gen_and_tl(cpu_R[instr.c], cpu_R[CR_IPENDING], cpu_R[CR_IENABLE]); + t1 = tcg_temp_new(); + t2 = tcg_temp_new(); + tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING])); + tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE])); + tcg_gen_and_tl(dest, t1, t2); + tcg_temp_free(t1); + tcg_temp_free(t2); break; default: - tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]); + tcg_gen_ld_tl(dest, cpu_env, + offsetof(CPUNios2State, ctrl[instr.imm5])); break; } +#endif } /* ctlN <- rA */ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) { - gen_check_supervisor(dc); + if (!gen_check_supervisor(dc)) { + return; + } -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else R_TYPE(instr, code); TCGv v = load_gpr(dc, instr.a); + uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]); + uint32_t wr = dc->cr_state[instr.imm5].writable; + uint32_t ro = dc->cr_state[instr.imm5].readonly; + + /* Skip reserved or readonly registers. */ + if (wr == 0) { + return; + } - switch (instr.imm5 + CR_BASE) { + switch (instr.imm5) { case CR_PTEADDR: gen_helper_mmu_write_pteaddr(cpu_env, v); break; @@ -488,145 +639,163 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) case CR_TLBMISC: gen_helper_mmu_write_tlbmisc(cpu_env, v); break; - case CR_IPENDING: - /* ipending is read only, writes ignored. */ - break; case CR_STATUS: case CR_IENABLE: /* If interrupts were enabled using WRCTL, trigger them. */ dc->base.is_jmp = DISAS_UPDATE; /* fall through */ default: - tcg_gen_mov_tl(cpu_R[instr.imm5 + CR_BASE], v); + if (wr == -1) { + /* The register is entirely writable. */ + tcg_gen_st_tl(v, cpu_env, ofs); + } else { + /* + * The register is partially read-only or reserved: + * merge the value. + */ + TCGv n = tcg_temp_new(); + + tcg_gen_andi_tl(n, v, wr); + + if (ro != 0) { + TCGv o = tcg_temp_new(); + tcg_gen_ld_tl(o, cpu_env, ofs); + tcg_gen_andi_tl(o, o, ro); + tcg_gen_or_tl(n, n, o); + tcg_temp_free(o); + } + + tcg_gen_st_tl(n, cpu_env, ofs); + tcg_temp_free(n); + } break; } #endif } +/* prs.rC <- rA */ +static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags) +{ + if (!dc->eic_present) { + t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); + return; + } + if (!gen_check_supervisor(dc)) { + return; + } + +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + R_TYPE(instr, code); + gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c), + load_gpr(dc, instr.a)); + /* + * The expected write to PRS[r0] is 0, from CRS[r0]. + * If not, and CRS == PRS (which we cannot tell from here), + * we may now have a non-zero value in our current r0. + * By ending the TB, we re-evaluate tb_flags and find out. + */ + if (instr.c == 0 + && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) { + dc->base.is_jmp = DISAS_UPDATE; + } +#endif +} + /* Comparison instructions */ static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags) { R_TYPE(instr, code); - if (likely(instr.c != R_ZERO)) { - tcg_gen_setcond_tl(flags, cpu_R[instr.c], cpu_R[instr.a], - cpu_R[instr.b]); - } + tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c), + load_gpr(dc, instr.a), load_gpr(dc, instr.b)); } /* Math/logic instructions */ -#define gen_r_math_logic(fname, insn, op3) \ -static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ -{ \ - R_TYPE(instr, (code)); \ - if (likely(instr.c != R_ZERO)) { \ - tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3)); \ - } \ -} - -gen_r_math_logic(add, add_tl, load_gpr(dc, instr.b)) -gen_r_math_logic(sub, sub_tl, load_gpr(dc, instr.b)) -gen_r_math_logic(mul, mul_tl, load_gpr(dc, instr.b)) - -gen_r_math_logic(and, and_tl, load_gpr(dc, instr.b)) -gen_r_math_logic(or, or_tl, load_gpr(dc, instr.b)) -gen_r_math_logic(xor, xor_tl, load_gpr(dc, instr.b)) -gen_r_math_logic(nor, nor_tl, load_gpr(dc, instr.b)) - -gen_r_math_logic(srai, sari_tl, instr.imm5) -gen_r_math_logic(srli, shri_tl, instr.imm5) -gen_r_math_logic(slli, shli_tl, instr.imm5) -gen_r_math_logic(roli, rotli_tl, instr.imm5) - -#define gen_r_mul(fname, insn) \ -static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ -{ \ - R_TYPE(instr, (code)); \ - if (likely(instr.c != R_ZERO)) { \ - TCGv t0 = tcg_temp_new(); \ - tcg_gen_##insn(t0, cpu_R[instr.c], \ - load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \ - tcg_temp_free(t0); \ - } \ -} - -gen_r_mul(mulxss, muls2_tl) -gen_r_mul(mulxuu, mulu2_tl) -gen_r_mul(mulxsu, mulsu2_tl) - -#define gen_r_shift_s(fname, insn) \ -static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ -{ \ - R_TYPE(instr, (code)); \ - if (likely(instr.c != R_ZERO)) { \ - TCGv t0 = tcg_temp_new(); \ - tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \ - tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0); \ - tcg_temp_free(t0); \ - } \ -} - -gen_r_shift_s(sra, sar_tl) -gen_r_shift_s(srl, shr_tl) -gen_r_shift_s(sll, shl_tl) -gen_r_shift_s(rol, rotl_tl) -gen_r_shift_s(ror, rotr_tl) +static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn) +{ + R_TYPE(instr, insn); + fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5); +} -static void divs(DisasContext *dc, uint32_t code, uint32_t flags) +static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn) { - R_TYPE(instr, (code)); + R_TYPE(instr, insn); + fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b)); +} - /* Stores into R_ZERO are ignored */ - if (unlikely(instr.c == R_ZERO)) { - return; - } +#define gen_ri_math_logic(fname, insn) \ + static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ + { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); } - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - TCGv t3 = tcg_temp_new(); +#define gen_rr_math_logic(fname, insn) \ + static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ + { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); } - tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a)); - tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b)); - tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); - tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); - tcg_gen_and_tl(t2, t2, t3); - tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); - tcg_gen_or_tl(t2, t2, t3); - tcg_gen_movi_tl(t3, 0); - tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); - tcg_gen_div_tl(cpu_R[instr.c], t0, t1); - tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]); +gen_rr_math_logic(add, add) +gen_rr_math_logic(sub, sub) +gen_rr_math_logic(mul, mul) - tcg_temp_free(t3); - tcg_temp_free(t2); - tcg_temp_free(t1); - tcg_temp_free(t0); +gen_rr_math_logic(and, and) +gen_rr_math_logic(or, or) +gen_rr_math_logic(xor, xor) +gen_rr_math_logic(nor, nor) + +gen_ri_math_logic(srai, sari) +gen_ri_math_logic(srli, shri) +gen_ri_math_logic(slli, shli) +gen_ri_math_logic(roli, rotli) + +static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn) +{ + R_TYPE(instr, insn); + TCGv discard = tcg_temp_new(); + + fn(discard, dest_gpr(dc, instr.c), + load_gpr(dc, instr.a), load_gpr(dc, instr.b)); + tcg_temp_free(discard); } -static void divu(DisasContext *dc, uint32_t code, uint32_t flags) +#define gen_rr_mul_high(fname, insn) \ + static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ + { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); } + +gen_rr_mul_high(mulxss, muls2) +gen_rr_mul_high(mulxuu, mulu2) +gen_rr_mul_high(mulxsu, mulsu2) + +static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn) { - R_TYPE(instr, (code)); + R_TYPE(instr, insn); + TCGv sh = tcg_temp_new(); - /* Stores into R_ZERO are ignored */ - if (unlikely(instr.c == R_ZERO)) { - return; - } + tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31); + fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh); + tcg_temp_free(sh); +} - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_const_tl(0); - TCGv t3 = tcg_const_tl(1); +#define gen_rr_shift(fname, insn) \ + static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ + { do_rr_shift(dc, code, tcg_gen_##insn##_tl); } - tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a)); - tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b)); - tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); - tcg_gen_divu_tl(cpu_R[instr.c], t0, t1); - tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]); +gen_rr_shift(sra, sar) +gen_rr_shift(srl, shr) +gen_rr_shift(sll, shl) +gen_rr_shift(rol, rotl) +gen_rr_shift(ror, rotr) - tcg_temp_free(t3); - tcg_temp_free(t2); - tcg_temp_free(t1); - tcg_temp_free(t0); +static void divs(DisasContext *dc, uint32_t code, uint32_t flags) +{ + R_TYPE(instr, (code)); + gen_helper_divs(dest_gpr(dc, instr.c), cpu_env, + load_gpr(dc, instr.a), load_gpr(dc, instr.b)); +} + +static void divu(DisasContext *dc, uint32_t code, uint32_t flags) +{ + R_TYPE(instr, (code)); + gen_helper_divu(dest_gpr(dc, instr.c), cpu_env, + load_gpr(dc, instr.a), load_gpr(dc, instr.b)); } static void trap(DisasContext *dc, uint32_t code, uint32_t flags) @@ -644,6 +813,21 @@ static void trap(DisasContext *dc, uint32_t code, uint32_t flags) t_gen_helper_raise_exception(dc, EXCP_TRAP); } +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(is_user) && instr.imm5 == 1) { + t_gen_helper_raise_exception(dc, EXCP_SEMIHOST); + return; + } +#endif + + t_gen_helper_raise_exception(dc, EXCP_BREAK); +} + static const Nios2Instruction r_type_instructions[] = { INSTRUCTION_ILLEGAL(), INSTRUCTION(eret), /* eret */ @@ -665,7 +849,7 @@ static const Nios2Instruction r_type_instructions[] = { INSTRUCTION_ILLEGAL(), INSTRUCTION(slli), /* slli */ INSTRUCTION(sll), /* sll */ - INSTRUCTION_UNIMPLEMENTED(), /* wrprs */ + INSTRUCTION(wrprs), /* wrprs */ INSTRUCTION_ILLEGAL(), INSTRUCTION(or), /* or */ INSTRUCTION(mulxsu), /* mulxsu */ @@ -697,7 +881,7 @@ static const Nios2Instruction r_type_instructions[] = { INSTRUCTION(add), /* add */ INSTRUCTION_ILLEGAL(), INSTRUCTION_ILLEGAL(), - INSTRUCTION_FLG(gen_excp, EXCP_BREAK), /* break */ + INSTRUCTION(gen_break), /* break */ INSTRUCTION_ILLEGAL(), INSTRUCTION(nop), /* nop */ INSTRUCTION_ILLEGAL(), @@ -730,7 +914,7 @@ static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags) t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); } -static const char * const regnames[] = { +static const char * const gr_regnames[NUM_GP_REGS] = { "zero", "at", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", @@ -739,16 +923,20 @@ static const char * const regnames[] = { "r20", "r21", "r22", "r23", "et", "bt", "gp", "sp", "fp", "ea", "ba", "ra", +}; + +#ifndef CONFIG_USER_ONLY +static const char * const cr_regnames[NUM_CR_REGS] = { "status", "estatus", "bstatus", "ienable", - "ipending", "cpuid", "reserved0", "exception", + "ipending", "cpuid", "res6", "exception", "pteaddr", "tlbacc", "tlbmisc", "reserved1", "badaddr", "config", "mpubase", "mpuacc", - "reserved2", "reserved3", "reserved4", "reserved5", - "reserved6", "reserved7", "reserved8", "reserved9", - "reserved10", "reserved11", "reserved12", "reserved13", - "reserved14", "reserved15", "reserved16", "reserved17", - "rpc" + "res16", "res17", "res18", "res19", + "res20", "res21", "res22", "res23", + "res24", "res25", "res26", "res27", + "res28", "res29", "res30", "res31", }; +#endif #include "exec/gen-icount.h" @@ -757,9 +945,13 @@ static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); CPUNios2State *env = cs->env_ptr; + Nios2CPU *cpu = env_archcpu(env); int page_insns; dc->mem_idx = cpu_mmu_index(env, false); + dc->cr_state = cpu->cr_state; + dc->tb_flags = dc->base.tb->flags; + dc->eic_present = cpu->eic_present; /* Bound the number of insns to execute to those left on the page. */ page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; @@ -796,13 +988,13 @@ static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) return; } - dc->zero = NULL; + dc->sink = NULL; instr = &i_type_instructions[op]; instr->handler(dc, code, instr->flags); - if (dc->zero) { - tcg_temp_free(dc->zero); + if (dc->sink) { + tcg_temp_free(dc->sink); } } @@ -813,14 +1005,12 @@ static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) /* Indicate where the next block should start */ switch (dc->base.is_jmp) { case DISAS_TOO_MANY: - case DISAS_UPDATE: - /* Save the current PC back into the CPU register */ - tcg_gen_movi_tl(cpu_R[R_PC], dc->base.pc_next); - tcg_gen_exit_tb(NULL, 0); + gen_goto_tb(dc, 0, dc->base.pc_next); break; - case DISAS_JUMP: - /* The jump will already have updated the PC register */ + case DISAS_UPDATE: + /* Save the current PC, and return to the main loop. */ + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); tcg_gen_exit_tb(NULL, 0); break; @@ -833,10 +1023,11 @@ static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void nios2_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void nios2_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps nios2_tr_ops = { @@ -848,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) @@ -860,41 +1052,61 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) CPUNios2State *env = &cpu->env; int i; - if (!env) { - return; - } - - qemu_fprintf(f, "IN: PC=%x %s\n", - env->regs[R_PC], lookup_symbol(env->regs[R_PC])); + qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); - for (i = 0; i < NUM_CORE_REGS; i++) { - qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]); + for (i = 0; i < NUM_GP_REGS; i++) { + qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]); if ((i + 1) % 4 == 0) { qemu_fprintf(f, "\n"); } } + #if !defined(CONFIG_USER_ONLY) - qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", - env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK, - (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4, - env->mmu.tlbacc_wr); + int j; + + for (i = j = 0; i < NUM_CR_REGS; i++) { + if (!nios2_cr_reserved(&cpu->cr_state[i])) { + qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]); + if (++j % 4 == 0) { + qemu_fprintf(f, "\n"); + } + } + } + if (j % 4 != 0) { + qemu_fprintf(f, "\n"); + } + if (cpu->mmu_present) { + qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", + env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK, + FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID), + env->mmu.tlbacc_wr); + } #endif qemu_fprintf(f, "\n\n"); } void nios2_tcg_init(void) { - int i; +#ifndef CONFIG_USER_ONLY + TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env, + offsetof(CPUNios2State, regs), "crs"); - for (i = 0; i < NUM_CORE_REGS; i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, - offsetof(CPUNios2State, regs[i]), - regnames[i]); + for (int i = 0; i < NUM_GP_REGS; i++) { + cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]); } -} -void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->regs[R_PC] = data[0]; +#define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N]) +#else +#define offsetof_regs0(N) offsetof(CPUNios2State, regs[N]) +#endif + + for (int i = 0; i < NUM_GP_REGS; i++) { + cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i), + gr_regnames[i]); + } + +#undef offsetof_regs0 + + cpu_pc = tcg_global_mem_new(cpu_env, + offsetof(CPUNios2State, pc), "pc"); } diff --git a/target/openrisc/cpu-param.h b/target/openrisc/cpu-param.h index 06ee64d1712c..73be699f361b 100644 --- a/target/openrisc/cpu-param.h +++ b/target/openrisc/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef OPENRISC_CPU_PARAM_H -#define OPENRISC_CPU_PARAM_H 1 +#define OPENRISC_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 13 diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dfbafc5236eb..4c11a1f7ada4 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" +#include "exec/exec-all.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) { @@ -30,6 +31,34 @@ 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(tb); +} + +static void openrisc_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(cs); + + cpu->env.pc = data[0]; + cpu->env.dflag = data[1] & 1; + if (data[1] & 2) { + cpu->env.ppc = cpu->env.pc - 4; + } +} + static bool openrisc_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | @@ -41,13 +70,15 @@ static void openrisc_disas_set_info(CPUState *cpu, disassemble_info *info) info->print_insn = print_insn_or1k; } -static void openrisc_cpu_reset(DeviceState *dev) +static void openrisc_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); OpenRISCCPU *cpu = OPENRISC_CPU(s); OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu); - occ->parent_reset(dev); + if (occ->parent_phases.hold) { + occ->parent_phases.hold(obj); + } memset(&cpu->env, 0, offsetof(CPUOpenRISCState, end_reset_fields)); @@ -88,7 +119,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 @@ -186,6 +216,8 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const struct TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, + .synchronize_from_tb = openrisc_cpu_synchronize_from_tb, + .restore_state_to_opc = openrisc_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, @@ -199,15 +231,18 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(occ); DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, openrisc_cpu_realizefn, &occ->parent_realize); - device_class_set_parent_reset(dc, openrisc_cpu_reset, &occ->parent_reset); + resettable_class_set_parent_phases(rc, NULL, openrisc_cpu_reset_hold, NULL, + &occ->parent_phases); cc->class_by_name = openrisc_cpu_class_by_name; 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 bdf29d2dc4c3..5f607497052b 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -21,9 +21,12 @@ #define OPENRISC_CPU_H #include "exec/cpu-defs.h" +#include "fpu/softfloat-types.h" #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) @@ -31,7 +34,7 @@ OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) /** * OpenRISCCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A OpenRISC CPU model. */ @@ -41,7 +44,7 @@ struct OpenRISCCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; #define TARGET_INSN_START_EXTRA_WORDS 1 diff --git a/target/openrisc/exception.c b/target/openrisc/exception.c index 28c1fce5232a..8699c3dcea42 100644 --- a/target/openrisc/exception.c +++ b/target/openrisc/exception.c @@ -22,7 +22,7 @@ #include "exec/exec-all.h" #include "exception.h" -void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp) +G_NORETURN void raise_exception(OpenRISCCPU *cpu, uint32_t excp) { CPUState *cs = CPU(cpu); diff --git a/target/openrisc/exception.h b/target/openrisc/exception.h index 333bf846388d..f62fc314c1f4 100644 --- a/target/openrisc/exception.h +++ b/target/openrisc/exception.h @@ -22,6 +22,6 @@ #include "cpu.h" -void QEMU_NORETURN raise_exception(OpenRISCCPU *cpu, uint32_t excp); +G_NORETURN void raise_exception(OpenRISCCPU *cpu, uint32_t excp); #endif /* TARGET_OPENRISC_EXCEPTION_H */ diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index d02a1cf0aa14..1f5be4bed907 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -30,7 +30,8 @@ void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) raise_exception(cpu, excp); } -static void QEMU_NORETURN do_range(CPUOpenRISCState *env, uintptr_t pc) +static G_NORETURN +void do_range(CPUOpenRISCState *env, uintptr_t pc) { CPUState *cs = env_cpu(env); diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f537195..c31c6f12c4f2 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 d7e1320998eb..0b8afdbacfc2 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 48674231e743..ec145960e3e5 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -45,14 +45,14 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(0, 16): /* NPC */ - cpu_restore_state(cs, GETPC(), true); + cpu_restore_state(cs, GETPC()); /* ??? Mirror or1ksim in not trashing delayed branch state when "jumping" to the current instruction. */ if (env->pc != rb) { env->pc = rb; env->dflag = 0; - cpu_loop_exit(cs); } + cpu_loop_exit(cs); break; case TO_SPR(0, 17): /* SR */ @@ -131,7 +131,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) case TO_SPR(8, 0): /* PMR */ env->pmr = rb; if (env->pmr & PMR_DME || env->pmr & PMR_SME) { - cpu_restore_state(cs, GETPC(), true); + cpu_restore_state(cs, GETPC()); env->pc += 4; cs->halted = 1; raise_exception(cpu, EXCP_HALTED); @@ -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 @@ -189,6 +199,7 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, target_ulong spr) { #ifndef CONFIG_USER_ONLY + uint64_t data[TARGET_INSN_START_WORDS]; MachineState *ms = MACHINE(qdev_get_machine()); OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); @@ -222,14 +233,20 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->evbar; case TO_SPR(0, 16): /* NPC (equals PC) */ - cpu_restore_state(cs, GETPC(), false); + if (cpu_unwind_state_data(cs, GETPC(), data)) { + return data[0]; + } return env->pc; case TO_SPR(0, 17): /* SR */ return cpu_get_sr(env); case TO_SPR(0, 18): /* PPC */ - cpu_restore_state(cs, GETPC(), false); + if (cpu_unwind_state_data(cs, GETPC(), data)) { + if (data[1] & 2) { + return data[0] - 4; + } + } return env->ppc; case TO_SPR(0, 32): /* EPCR */ @@ -303,7 +320,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 ca79e609dadf..2f3d7c5fd107 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1687,12 +1687,13 @@ static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void openrisc_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void openrisc_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { DisasContext *s = container_of(dcbase, DisasContext, base); - qemu_log("IN: %s\n", lookup_symbol(s->base.pc_first)); - log_target_disas(cs, s->base.pc_first, s->base.tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(s->base.pc_first)); + target_disas(logfile, cs, s->base.pc_first, s->base.tb->size); } static const TranslatorOps openrisc_tr_ops = { @@ -1704,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) @@ -1723,13 +1726,3 @@ void openrisc_cpu_dump_state(CPUState *cs, FILE *f, int flags) (i % 4) == 3 ? '\n' : ' '); } } - -void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; - env->dflag = data[1] & 1; - if (data[1] & 2) { - env->ppc = env->pc - 4; - } -} diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index 993740897d83..f58e6359d5eb 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -161,7 +161,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) bool needs_byteswap; ppc_avr_t *avr = cpu_avr_ptr(&cpu->env, i); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB; #else needs_byteswap = s->dump_info.d_endian == ELFDATA2MSB; @@ -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-models.c b/target/ppc/cpu-models.c index 976be5e0d171..912b037c6357 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -385,19 +385,19 @@ POWERPC_DEF_SVR("mpc8548e_v21", "MPC8548E v2.1", CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2) POWERPC_DEF_SVR("mpc8555_v10", "MPC8555 v1.0", - CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2) + CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v1) POWERPC_DEF_SVR("mpc8555_v11", "MPC8555 v1.1", - CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2) + CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v1) POWERPC_DEF_SVR("mpc8555e_v10", "MPC8555E v1.0", - CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2) + CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v1) POWERPC_DEF_SVR("mpc8555e_v11", "MPC8555E v1.1", - CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2) + CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v1) POWERPC_DEF_SVR("mpc8560_v10", "MPC8560 v1.0", - CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2) + CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v1) POWERPC_DEF_SVR("mpc8560_v20", "MPC8560 v2.0", - CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2) + CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v1) POWERPC_DEF_SVR("mpc8560_v21", "MPC8560 v2.1", - CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2) + CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v1) POWERPC_DEF_SVR("mpc8567", "MPC8567", CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2) POWERPC_DEF_SVR("mpc8567e", "MPC8567E", @@ -879,7 +879,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "755", "755_v2.8" }, { "goldfinger", "755_v2.8" }, { "7400", "7400_v2.9" }, - { "max", "7400_v2.9" }, { "g4", "7400_v2.9" }, { "7410", "7410_v1.4" }, { "nitro", "7410_v1.4" }, @@ -918,6 +917,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { #endif { "ppc32", "604" }, { "ppc", "604" }, - { "default", "604" }, + { NULL, NULL } }; diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index 76775a74a9b6..1326493a9a05 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -184,13 +184,13 @@ enum { #define CPU_POWERPC_MPC8548E_v11 CPU_POWERPC_e500v2_v11 #define CPU_POWERPC_MPC8548E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8548E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v1_v10 +#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v1_v20 #define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22 #define CPU_POWERPC_MPC8567E CPU_POWERPC_e500v2_v22 #define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22 diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h index 37b458d33d45..ea377b7d0644 100644 --- a/target/ppc/cpu-param.h +++ b/target/ppc/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef PPC_CPU_PARAM_H -#define PPC_CPU_PARAM_H 1 +#define PPC_CPU_PARAM_H #ifdef TARGET_PPC64 # define TARGET_LONG_BITS 64 diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index ad7e3c3db90d..0fbd8b724680 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -143,7 +143,7 @@ typedef struct PPCHash64Options PPCHash64Options; /** * PowerPCCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A PowerPC CPU model. */ @@ -154,11 +154,15 @@ struct PowerPCCPUClass { DeviceRealize parent_realize; DeviceUnrealize parent_unrealize; - DeviceReset parent_reset; + ResettablePhases parent_phases; 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 d7b42bae52d6..1a97b41c6b90 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -73,6 +73,7 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) hreg_store_msr(env, value, 0); } +#if !defined(CONFIG_USER_ONLY) void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) { PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); @@ -81,14 +82,17 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) env->spr[SPR_LPCR] = val & pcc->lpcr_mask; /* The gtse bit affects hflags */ hreg_compute_hflags(env); + + ppc_maybe_interrupt(env); } +#endif static inline void fpscr_set_rounding_mode(CPUPPCState *env) { int rnd_type; /* Set rounding mode */ - switch (fpscr_rn) { + switch (env->fpscr & FP_RN) { case 0: /* Best approximation (round to nearest) */ rnd_type = float_round_nearest_even; @@ -120,6 +124,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 047b24ba50ea..3923f174f8c6 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -21,9 +21,11 @@ #define PPC_CPU_H #include "qemu/int128.h" +#include "qemu/cpu-float.h" #include "exec/cpu-defs.h" #include "cpu-qom.h" #include "qom/object.h" +#include "hw/registerfields.h" #define TCG_GUEST_DEFAULT_MO 0 @@ -36,6 +38,7 @@ #define PPC_ELF_MACHINE EM_PPC #endif +#define PPC_BIT_NR(bit) (63 - (bit)) #define PPC_BIT(bit) (0x8000000000000000ULL >> (bit)) #define PPC_BIT32(bit) (0x80000000 >> (bit)) #define PPC_BIT8(bit) (0x80 >> (bit)) @@ -44,6 +47,18 @@ PPC_BIT32(bs)) #define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be)) | PPC_BIT8(bs)) +/* + * QEMU version of the GETFIELD/SETFIELD macros from skiboot + * + * It might be better to use the existing extract64() and + * deposit64() but this means that all the register definitions will + * change and become incompatible with the ones found in skiboot. + */ +#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1) +#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m)) +#define SETFIELD(m, v, val) \ + (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m))) + /*****************************************************************************/ /* Exception vectors definitions */ enum { @@ -224,17 +239,19 @@ typedef union _ppc_vsr_t { int16_t s16[8]; int32_t s32[4]; int64_t s64[2]; + float16 f16[8]; float32 f32[4]; float64 f64[2]; float128 f128; #ifdef CONFIG_INT128 __uint128_t u128; #endif - Int128 s128; + Int128 s128; } ppc_vsr_t; typedef ppc_vsr_t ppc_avr_t; typedef ppc_vsr_t ppc_fprp_t; +typedef ppc_vsr_t ppc_acc_t; #if !defined(CONFIG_USER_ONLY) /* Software TLB cache */ @@ -308,49 +325,106 @@ typedef enum { /*****************************************************************************/ /* Machine state register bits definition */ -#define MSR_SF 63 /* Sixty-four-bit mode hflags */ -#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */ -#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ -#define MSR_HV 60 /* hypervisor state hflags */ -#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */ -#define MSR_TS1 33 -#define MSR_TM 32 /* Transactional Memory Available (Book3s) */ -#define MSR_CM 31 /* Computation mode for BookE hflags */ -#define MSR_ICM 30 /* Interrupt computation mode for BookE */ -#define MSR_GS 28 /* guest state for BookE */ -#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ -#define MSR_VR 25 /* altivec available x hflags */ -#define MSR_SPE 25 /* SPE enable for BookE x hflags */ -#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */ -#define MSR_S 22 /* Secure state */ -#define MSR_KEY 19 /* key bit on 603e */ -#define MSR_POW 18 /* Power management */ -#define MSR_WE 18 /* Wait State Enable on 405 */ -#define MSR_TGPR 17 /* TGPR usage on 602/603 x */ -#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */ -#define MSR_ILE 16 /* Interrupt little-endian mode */ -#define MSR_EE 15 /* External interrupt enable */ -#define MSR_PR 14 /* Problem state hflags */ -#define MSR_FP 13 /* Floating point available hflags */ -#define MSR_ME 12 /* Machine check interrupt enable */ -#define MSR_FE0 11 /* Floating point exception mode 0 */ -#define MSR_SE 10 /* Single-step trace enable x hflags */ -#define MSR_DWE 10 /* Debug wait enable on 405 x */ -#define MSR_UBLE 10 /* User BTB lock enable on e500 x */ -#define MSR_BE 9 /* Branch trace enable x hflags */ -#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ -#define MSR_FE1 8 /* Floating point exception mode 1 */ -#define MSR_AL 7 /* AL bit on POWER */ -#define MSR_EP 6 /* Exception prefix on 601 */ -#define MSR_IR 5 /* Instruction relocate */ -#define MSR_DR 4 /* Data relocate */ -#define MSR_IS 5 /* Instruction address space (BookE) */ -#define MSR_DS 4 /* Data address space (BookE) */ -#define MSR_PE 3 /* Protection enable on 403 */ -#define MSR_PX 2 /* Protection exclusive on 403 x */ -#define MSR_PMM 2 /* Performance monitor mark on POWER x */ -#define MSR_RI 1 /* Recoverable interrupt 1 */ -#define MSR_LE 0 /* Little-endian mode 1 hflags */ +#define MSR_SF PPC_BIT_NR(0) /* Sixty-four-bit mode hflags */ +#define MSR_TAG PPC_BIT_NR(1) /* Tag-active mode (POWERx ?) */ +#define MSR_ISF PPC_BIT_NR(2) /* Sixty-four-bit interrupt mode on 630 */ +#define MSR_HV PPC_BIT_NR(3) /* hypervisor state hflags */ +#define MSR_TS0 PPC_BIT_NR(29) /* Transactional state, 2 bits (Book3s) */ +#define MSR_TS1 PPC_BIT_NR(30) +#define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */ +#define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */ +#define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */ +#define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */ +#define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */ +#define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */ +#define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */ +#define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */ +#define MSR_S PPC_BIT_NR(41) /* Secure state */ +#define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */ +#define MSR_POW PPC_BIT_NR(45) /* Power management */ +#define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */ +#define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */ +#define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */ +#define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */ +#define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */ +#define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */ +#define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */ +#define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */ +#define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */ +#define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */ +#define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */ +#define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */ +#define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */ +#define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */ +#define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */ +#define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */ +#define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */ +#define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */ +#define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */ +#define MSR_DR PPC_BIT_NR(59) /* Data relocate */ +#define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */ +#define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */ +#define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */ +#define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */ +#define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */ +#define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */ + +FIELD(MSR, SF, MSR_SF, 1) +FIELD(MSR, TAG, MSR_TAG, 1) +FIELD(MSR, ISF, MSR_ISF, 1) +#if defined(TARGET_PPC64) +FIELD(MSR, HV, MSR_HV, 1) +#define FIELD_EX64_HV(storage) FIELD_EX64(storage, MSR, HV) +#else +#define FIELD_EX64_HV(storage) 0 +#endif +FIELD(MSR, TS0, MSR_TS0, 1) +FIELD(MSR, TS1, MSR_TS1, 1) +FIELD(MSR, TS, MSR_TS0, 2) +FIELD(MSR, TM, MSR_TM, 1) +FIELD(MSR, CM, MSR_CM, 1) +FIELD(MSR, ICM, MSR_ICM, 1) +FIELD(MSR, GS, MSR_GS, 1) +FIELD(MSR, UCLE, MSR_UCLE, 1) +FIELD(MSR, VR, MSR_VR, 1) +FIELD(MSR, SPE, MSR_SPE, 1) +FIELD(MSR, VSX, MSR_VSX, 1) +FIELD(MSR, S, MSR_S, 1) +FIELD(MSR, KEY, MSR_KEY, 1) +FIELD(MSR, POW, MSR_POW, 1) +FIELD(MSR, WE, MSR_WE, 1) +FIELD(MSR, TGPR, MSR_TGPR, 1) +FIELD(MSR, CE, MSR_CE, 1) +FIELD(MSR, ILE, MSR_ILE, 1) +FIELD(MSR, EE, MSR_EE, 1) +FIELD(MSR, PR, MSR_PR, 1) +FIELD(MSR, FP, MSR_FP, 1) +FIELD(MSR, ME, MSR_ME, 1) +FIELD(MSR, FE0, MSR_FE0, 1) +FIELD(MSR, SE, MSR_SE, 1) +FIELD(MSR, DWE, MSR_DWE, 1) +FIELD(MSR, UBLE, MSR_UBLE, 1) +FIELD(MSR, BE, MSR_BE, 1) +FIELD(MSR, DE, MSR_DE, 1) +FIELD(MSR, FE1, MSR_FE1, 1) +FIELD(MSR, AL, MSR_AL, 1) +FIELD(MSR, EP, MSR_EP, 1) +FIELD(MSR, IR, MSR_IR, 1) +FIELD(MSR, DR, MSR_DR, 1) +FIELD(MSR, IS, MSR_IS, 1) +FIELD(MSR, DS, MSR_DS, 1) +FIELD(MSR, PE, MSR_PE, 1) +FIELD(MSR, PX, MSR_PX, 1) +FIELD(MSR, PMM, MSR_PMM, 1) +FIELD(MSR, RI, MSR_RI, 1) +FIELD(MSR, LE, MSR_LE, 1) + +/* + * FE0 and FE1 bits are not side-by-side + * so we can't combine them using FIELD() + */ +#define FIELD_EX64_FE(msr) \ + ((FIELD_EX64(msr, MSR, FE0) << 1) | FIELD_EX64(msr, MSR, FE1)) /* PMU bits */ #define MMCR0_FC PPC_BIT(32) /* Freeze Counters */ @@ -462,50 +536,6 @@ typedef enum { #define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */ #define HFSCR_IC_MSGP 0xA -#define msr_sf ((env->msr >> MSR_SF) & 1) -#define msr_isf ((env->msr >> MSR_ISF) & 1) -#if defined(TARGET_PPC64) -#define msr_hv ((env->msr >> MSR_HV) & 1) -#else -#define msr_hv (0) -#endif -#define msr_cm ((env->msr >> MSR_CM) & 1) -#define msr_icm ((env->msr >> MSR_ICM) & 1) -#define msr_gs ((env->msr >> MSR_GS) & 1) -#define msr_ucle ((env->msr >> MSR_UCLE) & 1) -#define msr_vr ((env->msr >> MSR_VR) & 1) -#define msr_spe ((env->msr >> MSR_SPE) & 1) -#define msr_vsx ((env->msr >> MSR_VSX) & 1) -#define msr_key ((env->msr >> MSR_KEY) & 1) -#define msr_pow ((env->msr >> MSR_POW) & 1) -#define msr_tgpr ((env->msr >> MSR_TGPR) & 1) -#define msr_ce ((env->msr >> MSR_CE) & 1) -#define msr_ile ((env->msr >> MSR_ILE) & 1) -#define msr_ee ((env->msr >> MSR_EE) & 1) -#define msr_pr ((env->msr >> MSR_PR) & 1) -#define msr_fp ((env->msr >> MSR_FP) & 1) -#define msr_me ((env->msr >> MSR_ME) & 1) -#define msr_fe0 ((env->msr >> MSR_FE0) & 1) -#define msr_se ((env->msr >> MSR_SE) & 1) -#define msr_dwe ((env->msr >> MSR_DWE) & 1) -#define msr_uble ((env->msr >> MSR_UBLE) & 1) -#define msr_be ((env->msr >> MSR_BE) & 1) -#define msr_de ((env->msr >> MSR_DE) & 1) -#define msr_fe1 ((env->msr >> MSR_FE1) & 1) -#define msr_al ((env->msr >> MSR_AL) & 1) -#define msr_ep ((env->msr >> MSR_EP) & 1) -#define msr_ir ((env->msr >> MSR_IR) & 1) -#define msr_dr ((env->msr >> MSR_DR) & 1) -#define msr_is ((env->msr >> MSR_IS) & 1) -#define msr_ds ((env->msr >> MSR_DS) & 1) -#define msr_pe ((env->msr >> MSR_PE) & 1) -#define msr_px ((env->msr >> MSR_PX) & 1) -#define msr_pmm ((env->msr >> MSR_PMM) & 1) -#define msr_ri ((env->msr >> MSR_RI) & 1) -#define msr_le ((env->msr >> MSR_LE) & 1) -#define msr_ts ((env->msr >> MSR_TS1) & 3) -#define msr_tm ((env->msr >> MSR_TM) & 1) - #define DBCR0_ICMP (1 << 27) #define DBCR0_BRT (1 << 26) #define DBSR_ICMP (1 << 27) @@ -666,7 +696,9 @@ enum { HFLAGS_PR = 14, /* MSR_PR */ HFLAGS_PMCC0 = 15, /* MMCR0 PMCC bit 0 */ HFLAGS_PMCC1 = 16, /* MMCR0 PMCC bit 1 */ - HFLAGS_INSN_CNT = 17, /* PMU instruction count enabled */ + HFLAGS_PMCJCE = 17, /* MMCR0 PMCjCE bit */ + HFLAGS_PMC_OTHER = 18, /* PMC other than PMC5-6 is enabled */ + HFLAGS_INSN_CNT = 19, /* PMU instruction count enabled */ HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */ HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */ @@ -676,77 +708,50 @@ enum { /*****************************************************************************/ /* Floating point status and control register */ -#define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */ -#define FPSCR_DRN1 33 /* Decimal Floating-Point rounding control */ -#define FPSCR_DRN0 32 /* Decimal Floating-Point rounding control */ -#define FPSCR_FX 31 /* Floating-point exception summary */ -#define FPSCR_FEX 30 /* Floating-point enabled exception summary */ -#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */ -#define FPSCR_OX 28 /* Floating-point overflow exception */ -#define FPSCR_UX 27 /* Floating-point underflow exception */ -#define FPSCR_ZX 26 /* Floating-point zero divide exception */ -#define FPSCR_XX 25 /* Floating-point inexact exception */ -#define FPSCR_VXSNAN 24 /* Floating-point invalid operation exception (sNan) */ -#define FPSCR_VXISI 23 /* Floating-point invalid operation exception (inf) */ -#define FPSCR_VXIDI 22 /* Floating-point invalid operation exception (inf) */ -#define FPSCR_VXZDZ 21 /* Floating-point invalid operation exception (zero) */ -#define FPSCR_VXIMZ 20 /* Floating-point invalid operation exception (inf) */ -#define FPSCR_VXVC 19 /* Floating-point invalid operation exception (comp) */ -#define FPSCR_FR 18 /* Floating-point fraction rounded */ -#define FPSCR_FI 17 /* Floating-point fraction inexact */ -#define FPSCR_C 16 /* Floating-point result class descriptor */ -#define FPSCR_FL 15 /* Floating-point less than or negative */ -#define FPSCR_FG 14 /* Floating-point greater than or negative */ -#define FPSCR_FE 13 /* Floating-point equal or zero */ -#define FPSCR_FU 12 /* Floating-point unordered or NaN */ -#define FPSCR_FPCC 12 /* Floating-point condition code */ -#define FPSCR_FPRF 12 /* Floating-point result flags */ -#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */ -#define FPSCR_VXSQRT 9 /* Floating-point invalid operation exception (sqrt) */ -#define FPSCR_VXCVI 8 /* Floating-point invalid operation exception (int) */ -#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */ -#define FPSCR_OE 6 /* Floating-point overflow exception enable */ -#define FPSCR_UE 5 /* Floating-point underflow exception enable */ -#define FPSCR_ZE 4 /* Floating-point zero divide exception enable */ -#define FPSCR_XE 3 /* Floating-point inexact exception enable */ -#define FPSCR_NI 2 /* Floating-point non-IEEE mode */ -#define FPSCR_RN1 1 -#define FPSCR_RN0 0 /* Floating-point rounding control */ -#define fpscr_drn (((env->fpscr) & FP_DRN) >> FPSCR_DRN0) -#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) -#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) -#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) -#define fpscr_ux (((env->fpscr) >> FPSCR_UX) & 0x1) -#define fpscr_zx (((env->fpscr) >> FPSCR_ZX) & 0x1) -#define fpscr_xx (((env->fpscr) >> FPSCR_XX) & 0x1) -#define fpscr_vxsnan (((env->fpscr) >> FPSCR_VXSNAN) & 0x1) -#define fpscr_vxisi (((env->fpscr) >> FPSCR_VXISI) & 0x1) -#define fpscr_vxidi (((env->fpscr) >> FPSCR_VXIDI) & 0x1) -#define fpscr_vxzdz (((env->fpscr) >> FPSCR_VXZDZ) & 0x1) -#define fpscr_vximz (((env->fpscr) >> FPSCR_VXIMZ) & 0x1) -#define fpscr_vxvc (((env->fpscr) >> FPSCR_VXVC) & 0x1) -#define fpscr_fpcc (((env->fpscr) >> FPSCR_FPCC) & 0xF) -#define fpscr_vxsoft (((env->fpscr) >> FPSCR_VXSOFT) & 0x1) -#define fpscr_vxsqrt (((env->fpscr) >> FPSCR_VXSQRT) & 0x1) -#define fpscr_vxcvi (((env->fpscr) >> FPSCR_VXCVI) & 0x1) -#define fpscr_ve (((env->fpscr) >> FPSCR_VE) & 0x1) -#define fpscr_oe (((env->fpscr) >> FPSCR_OE) & 0x1) -#define fpscr_ue (((env->fpscr) >> FPSCR_UE) & 0x1) -#define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1) -#define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1) -#define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1) -#define fpscr_rn (((env->fpscr) >> FPSCR_RN0) & 0x3) +#define FPSCR_DRN2 PPC_BIT_NR(29) /* Decimal Floating-Point rounding ctrl. */ +#define FPSCR_DRN1 PPC_BIT_NR(30) /* Decimal Floating-Point rounding ctrl. */ +#define FPSCR_DRN0 PPC_BIT_NR(31) /* Decimal Floating-Point rounding ctrl. */ +#define FPSCR_FX PPC_BIT_NR(32) /* Floating-point exception summary */ +#define FPSCR_FEX PPC_BIT_NR(33) /* Floating-point enabled exception summ.*/ +#define FPSCR_VX PPC_BIT_NR(34) /* Floating-point invalid op. excp. summ.*/ +#define FPSCR_OX PPC_BIT_NR(35) /* Floating-point overflow exception */ +#define FPSCR_UX PPC_BIT_NR(36) /* Floating-point underflow exception */ +#define FPSCR_ZX PPC_BIT_NR(37) /* Floating-point zero divide exception */ +#define FPSCR_XX PPC_BIT_NR(38) /* Floating-point inexact exception */ +#define FPSCR_VXSNAN PPC_BIT_NR(39) /* Floating-point invalid op. excp (sNan)*/ +#define FPSCR_VXISI PPC_BIT_NR(40) /* Floating-point invalid op. excp (inf) */ +#define FPSCR_VXIDI PPC_BIT_NR(41) /* Floating-point invalid op. excp (inf) */ +#define FPSCR_VXZDZ PPC_BIT_NR(42) /* Floating-point invalid op. excp (zero)*/ +#define FPSCR_VXIMZ PPC_BIT_NR(43) /* Floating-point invalid op. excp (inf) */ +#define FPSCR_VXVC PPC_BIT_NR(44) /* Floating-point invalid op. excp (comp)*/ +#define FPSCR_FR PPC_BIT_NR(45) /* Floating-point fraction rounded */ +#define FPSCR_FI PPC_BIT_NR(46) /* Floating-point fraction inexact */ +#define FPSCR_C PPC_BIT_NR(47) /* Floating-point result class descriptor*/ +#define FPSCR_FL PPC_BIT_NR(48) /* Floating-point less than or negative */ +#define FPSCR_FG PPC_BIT_NR(49) /* Floating-point greater than or neg. */ +#define FPSCR_FE PPC_BIT_NR(50) /* Floating-point equal or zero */ +#define FPSCR_FU PPC_BIT_NR(51) /* Floating-point unordered or NaN */ +#define FPSCR_FPCC PPC_BIT_NR(51) /* Floating-point condition code */ +#define FPSCR_FPRF PPC_BIT_NR(51) /* Floating-point result flags */ +#define FPSCR_VXSOFT PPC_BIT_NR(53) /* Floating-point invalid op. excp (soft)*/ +#define FPSCR_VXSQRT PPC_BIT_NR(54) /* Floating-point invalid op. excp (sqrt)*/ +#define FPSCR_VXCVI PPC_BIT_NR(55) /* Floating-point invalid op. excp (int) */ +#define FPSCR_VE PPC_BIT_NR(56) /* Floating-point invalid op. excp enable*/ +#define FPSCR_OE PPC_BIT_NR(57) /* Floating-point overflow excp. enable */ +#define FPSCR_UE PPC_BIT_NR(58) /* Floating-point underflow excp. enable */ +#define FPSCR_ZE PPC_BIT_NR(59) /* Floating-point zero divide excp enable*/ +#define FPSCR_XE PPC_BIT_NR(60) /* Floating-point inexact excp. enable */ +#define FPSCR_NI PPC_BIT_NR(61) /* Floating-point non-IEEE mode */ +#define FPSCR_RN1 PPC_BIT_NR(62) +#define FPSCR_RN0 PPC_BIT_NR(63) /* Floating-point rounding control */ /* Invalid operation exception summary */ #define FPSCR_IX ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \ (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \ (1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \ (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \ (1 << FPSCR_VXCVI)) -/* exception summary */ -#define fpscr_ex (((env->fpscr) >> FPSCR_XX) & 0x1F) -/* enabled exception summary */ -#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ - 0x1F) + +FIELD(FPSCR, FI, FPSCR_FI, 1) #define FP_DRN2 (1ull << FPSCR_DRN2) #define FP_DRN1 (1ull << FPSCR_DRN1) @@ -1063,6 +1068,21 @@ struct ppc_radix_page_info { uint32_t entries[PPC_PAGE_SIZES_MAX_SZ]; }; +/*****************************************************************************/ +/* Dynamic Execution Control Register */ + +#define DEXCR_ASPECT(name, num) \ +FIELD(DEXCR, PNH_##name, PPC_BIT_NR(num), 1) \ +FIELD(DEXCR, PRO_##name, PPC_BIT_NR(num + 32), 1) \ +FIELD(HDEXCR, HNU_##name, PPC_BIT_NR(num), 1) \ +FIELD(HDEXCR, ENF_##name, PPC_BIT_NR(num + 32), 1) \ + +DEXCR_ASPECT(SBHE, 0) +DEXCR_ASPECT(IBRTPD, 1) +DEXCR_ASPECT(SRAPD, 4) +DEXCR_ASPECT(NPHIE, 5) +DEXCR_ASPECT(PHIE, 6) + /*****************************************************************************/ /* The whole PowerPC CPU context */ @@ -1181,7 +1201,6 @@ struct CPUArchState { * by recent Book3s compatible CPUs (POWER7 and newer). */ uint32_t irq_input_state; - void **irq_inputs; target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */ target_ulong excp_prefix; @@ -1352,10 +1371,11 @@ 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_maybe_interrupt(CPUPPCState *env); void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); void ppc_cpu_do_system_reset(CPUState *cs); @@ -1368,9 +1388,9 @@ void ppc_translate_init(void); #if !defined(CONFIG_USER_ONLY) void ppc_store_sdr1(CPUPPCState *env, target_ulong value); +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr(CPUPPCState *env, target_ulong value); -void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); void ppc_cpu_list(void); @@ -1504,10 +1524,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) @@ -1673,7 +1689,11 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_GIVOR13 (0x1BC) #define SPR_BOOKE_GIVOR14 (0x1BD) #define SPR_TIR (0x1BE) +#define SPR_UHDEXCR (0x1C7) #define SPR_PTCR (0x1D0) +#define SPR_HASHKEYR (0x1D4) +#define SPR_HASHPKEYR (0x1D5) +#define SPR_HDEXCR (0x1D7) #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_Exxx_BBEAR (0x201) #define SPR_Exxx_BBTAR (0x202) @@ -1862,8 +1882,10 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_RCPU_L2U_RA2 (0x32A) #define SPR_MPC_MD_DBRAM1 (0x32A) #define SPR_RCPU_L2U_RA3 (0x32B) +#define SPR_UDEXCR (0x32C) #define SPR_TAR (0x32F) #define SPR_ASDR (0x330) +#define SPR_DEXCR (0x33C) #define SPR_IC (0x350) #define SPR_VTB (0x351) #define SPR_MMCRC (0x353) @@ -2212,8 +2234,6 @@ enum { PPC_DCR = 0x1000000000000000ULL, /* DCR extended accesse */ PPC_DCRX = 0x2000000000000000ULL, - /* user-mode DCR access, implemented in PowerPC 460 */ - PPC_DCRUX = 0x4000000000000000ULL, /* popcntw and popcntd instructions */ PPC_POPCNTWD = 0x8000000000000000ULL, @@ -2237,8 +2257,8 @@ enum { | PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \ | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \ - | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \ - | PPC_POPCNTWD | PPC_CILDST) + | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_POPCNTWD \ + | PPC_CILDST) /* extended type values */ @@ -2284,6 +2304,10 @@ enum { PPC2_ISA300 = 0x0000000000080000ULL, /* POWER ISA 3.1 */ PPC2_ISA310 = 0x0000000000100000ULL, + /* lwsync instruction */ + PPC2_MEM_LWSYNC = 0x0000000000200000ULL, + /* ISA 2.06 BCD assist instructions */ + PPC2_BCDA_ISA206 = 0x0000000000400000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2292,7 +2316,8 @@ enum { PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \ - PPC2_ISA300 | PPC2_ISA310) + PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \ + PPC2_BCDA_ISA206) }; /*****************************************************************************/ @@ -2413,27 +2438,27 @@ enum { /* Hardware exceptions definitions */ enum { /* External hardware exception sources */ - PPC_INTERRUPT_RESET = 0, /* Reset exception */ - PPC_INTERRUPT_WAKEUP, /* Wakeup exception */ - PPC_INTERRUPT_MCK, /* Machine check exception */ - PPC_INTERRUPT_EXT, /* External interrupt */ - PPC_INTERRUPT_SMI, /* System management interrupt */ - PPC_INTERRUPT_CEXT, /* Critical external interrupt */ - PPC_INTERRUPT_DEBUG, /* External debug exception */ - PPC_INTERRUPT_THERM, /* Thermal exception */ + PPC_INTERRUPT_RESET = 0x00001, /* Reset exception */ + PPC_INTERRUPT_WAKEUP = 0x00002, /* Wakeup exception */ + PPC_INTERRUPT_MCK = 0x00004, /* Machine check exception */ + PPC_INTERRUPT_EXT = 0x00008, /* External interrupt */ + PPC_INTERRUPT_SMI = 0x00010, /* System management interrupt */ + PPC_INTERRUPT_CEXT = 0x00020, /* Critical external interrupt */ + PPC_INTERRUPT_DEBUG = 0x00040, /* External debug exception */ + PPC_INTERRUPT_THERM = 0x00080, /* Thermal exception */ /* Internal hardware exception sources */ - PPC_INTERRUPT_DECR, /* Decrementer exception */ - PPC_INTERRUPT_HDECR, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT, /* Programmable interval timer interrupt */ - PPC_INTERRUPT_FIT, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT, /* Watchdog timer interrupt */ - PPC_INTERRUPT_CDOORBELL, /* Critical doorbell interrupt */ - PPC_INTERRUPT_DOORBELL, /* Doorbell interrupt */ - PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ - PPC_INTERRUPT_HMI, /* Hypervisor Maintenance interrupt */ - PPC_INTERRUPT_HDOORBELL, /* Hypervisor Doorbell interrupt */ - PPC_INTERRUPT_HVIRT, /* Hypervisor virtualization interrupt */ - PPC_INTERRUPT_EBB, /* Event-based Branch exception */ + PPC_INTERRUPT_DECR = 0x00100, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 0x00200, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 0x00400, /* Programmable interval timer int. */ + PPC_INTERRUPT_FIT = 0x00800, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 0x01000, /* Watchdog timer interrupt */ + PPC_INTERRUPT_CDOORBELL = 0x02000, /* Critical doorbell interrupt */ + PPC_INTERRUPT_DOORBELL = 0x04000, /* Doorbell interrupt */ + PPC_INTERRUPT_PERFM = 0x08000, /* Performance monitor interrupt */ + PPC_INTERRUPT_HMI = 0x10000, /* Hypervisor Maintenance interrupt */ + PPC_INTERRUPT_HDOORBELL = 0x20000, /* Hypervisor Doorbell interrupt */ + PPC_INTERRUPT_HVIRT = 0x40000, /* Hypervisor virtualization interrupt */ + PPC_INTERRUPT_EBB = 0x80000, /* Event-based Branch exception */ }; /* Processor Compatibility mask (PCR) */ @@ -2491,13 +2516,13 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, } #endif -void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception); -void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception, - uintptr_t raddr); -void QEMU_NORETURN raise_exception_err(CPUPPCState *env, uint32_t exception, - uint32_t error_code); -void QEMU_NORETURN raise_exception_err_ra(CPUPPCState *env, uint32_t exception, - uint32_t error_code, uintptr_t raddr); +G_NORETURN void raise_exception(CPUPPCState *env, uint32_t exception); +G_NORETURN void raise_exception_ra(CPUPPCState *env, uint32_t exception, + uintptr_t raddr); +G_NORETURN void raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code); +G_NORETURN void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, + uint32_t error_code, uintptr_t raddr); /* PERFM EBB helper*/ #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) @@ -2642,7 +2667,7 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) } /* Accessors for FP, VMX and VSX registers */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define VsrB(i) u8[i] #define VsrSB(i) s8[i] #define VsrH(i) u16[i] @@ -2651,6 +2676,9 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) #define VsrSW(i) s32[i] #define VsrD(i) u64[i] #define VsrSD(i) s64[i] +#define VsrHF(i) f16[i] +#define VsrSF(i) f32[i] +#define VsrDF(i) f64[i] #else #define VsrB(i) u8[15 - (i)] #define VsrSB(i) s8[15 - (i)] @@ -2660,6 +2688,9 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) #define VsrSW(i) s32[3 - (i)] #define VsrD(i) u64[1 - (i)] #define VsrSD(i) s64[1 - (i)] +#define VsrHF(i) f16[7 - (i)] +#define VsrSF(i) f32[3 - (i)] +#define VsrDF(i) f64[1 - (i)] #endif static inline int vsr64_offset(int i, bool high) @@ -2672,6 +2703,11 @@ static inline int vsr_full_offset(int i) return offsetof(CPUPPCState, vsr[i].u64[0]); } +static inline int acc_full_offset(int i) +{ + return vsr_full_offset(i * 4); +} + static inline int fpr_offset(int i) { return vsr64_offset(i, true); @@ -2725,7 +2761,7 @@ static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu, bool hv) } else if (pcc->lpcr_mask & LPCR_ILE) { ile = !!(env->spr[SPR_LPCR] & LPCR_ILE); } else { - ile = !!(msr_ile); + ile = FIELD_EX64(env->msr, MSR, ILE); } return ile; diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 073fd101687c..abee71d4072c 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -47,6 +47,10 @@ #include "spr_common.h" #include "power8-pmu.h" +#ifndef CONFIG_USER_ONLY +#include "hw/boards.h" +#endif + /* #define PPC_DEBUG_SPR */ /* #define USE_APPLE_GDB */ @@ -5696,6 +5700,57 @@ 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); +} + +static void register_power10_dexcr_sprs(CPUPPCState *env) +{ + spr_register(env, SPR_DEXCR, "DEXCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0); + + spr_register(env, SPR_UDEXCR, "DEXCR", + &spr_read_dexcr_ureg, SPR_NOACCESS, + &spr_read_dexcr_ureg, SPR_NOACCESS, + 0); + + spr_register_hv(env, SPR_HDEXCR, "HDEXCR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0); + + spr_register(env, SPR_UHDEXCR, "HDEXCR", + &spr_read_dexcr_ureg, SPR_NOACCESS, + &spr_read_dexcr_ureg, SPR_NOACCESS, + 0); +} + /* * Initialize PMU counter overflow timers for Power8 and * newer Power chips when using TCG. @@ -5769,7 +5824,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC2_FP_CVT_S64; + pcc->insns_flags2 = PPC2_FP_CVT_S64 | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_POW) | @@ -5846,7 +5901,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) PPC_64B | PPC_POPCNTB | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC2_FP_CVT_S64; + pcc->insns_flags2 = PPC2_FP_CVT_S64 | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_POW) | @@ -5908,56 +5963,31 @@ static void init_proc_POWER7(CPUPPCState *env) ppcPOWER7_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr) -{ - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7P_BASE) { - return true; - } - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7_BASE) { - return true; - } - return false; -} - -static bool cpu_has_work_POWER7(CPUState *cs) +static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; - if (cs->halted) { - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { + if (!best) { + if (base == CPU_POWERPC_POWER7_BASE) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { - return true; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { - return true; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { - return true; - } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (base == CPU_POWERPC_POWER7P_BASE) { return true; } + } + + if (base != pcc_base) { return false; - } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); } + + return true; } POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER7"; dc->desc = "POWER7"; @@ -5966,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER7; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -5984,7 +6013,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64 | - PPC2_PM_ISA206; + PPC2_PM_ISA206 | PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_VSX) | @@ -6068,67 +6097,33 @@ 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; - } - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8E_BASE) { - return true; - } - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8_BASE) { - return true; - } - return false; -} + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; -static bool cpu_has_work_POWER8(CPUState *cs) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - if (cs->halted) { - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { + if (!best) { + if (base == CPU_POWERPC_POWER8_BASE) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { + if (base == CPU_POWERPC_POWER8E_BASE) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { - return true; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { - return true; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { - return true; - } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { - return true; - } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (base == CPU_POWERPC_POWER8NVL_BASE) { return true; } + } + if (base != pcc_base) { return false; - } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); } + + return true; } POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER8"; dc->desc = "POWER8"; @@ -6137,7 +6132,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER8; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER8; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6157,7 +6151,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_PM_ISA206; + PPC2_TM | PPC2_PM_ISA206 | PPC2_MEM_LWSYNC | + PPC2_BCDA_ISA206; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_HV) | (1ull << MSR_TM) | @@ -6275,77 +6270,33 @@ static void init_proc_POWER9(CPUPPCState *env) ppcPOWER9_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr) -{ - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER9_BASE) { - return true; - } - return false; -} - -static bool cpu_has_work_POWER9(CPUState *cs) +static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; - if (cs->halted) { - uint64_t psscr = env->spr[SPR_PSSCR]; - - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - - /* If EC is clear, just return true on any pending interrupt */ - if (!(psscr & PSSCR_EC)) { - return true; - } - /* External Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && - (env->spr[SPR_LPCR] & LPCR_EEE)) { - bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (heic == 0 || !msr_hv || msr_pr) { - return true; - } - } - /* Decrementer Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && - (env->spr[SPR_LPCR] & LPCR_DEE)) { - return true; - } - /* Machine Check or Hypervisor Maintenance Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK | - 1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) { - return true; - } - /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && - (env->spr[SPR_LPCR] & LPCR_PDEE)) { - return true; - } - /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && - (env->spr[SPR_LPCR] & LPCR_HDEE)) { - return true; - } - /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) && - (env->spr[SPR_LPCR] & LPCR_HVEE)) { - return true; - } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (!best) { + if (base == CPU_POWERPC_POWER9_BASE) { return true; } + } + + if (base != pcc_base) { return false; - } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); } + + if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) { + /* Major DD version matches to power9_v1.0 and power9_v2.0 */ + return true; + } + + return false; } POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER9"; dc->desc = "POWER9"; @@ -6355,7 +6306,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER9; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER9; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6364,7 +6314,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PPC_FLOAT_EXT | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBSYNC | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD | @@ -6375,7 +6325,8 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL; + PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_MEM_LWSYNC | + PPC2_BCDA_ISA206; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_HV) | (1ull << MSR_TM) | @@ -6457,6 +6408,7 @@ static void init_proc_POWER10(CPUPPCState *env) register_power5p_common_sprs(env); register_power5p_lpar_sprs(env); register_power5p_ear_sprs(env); + register_power5p_tb_sprs(env); register_power6_common_sprs(env); register_power6_dbg_sprs(env); register_power8_tce_address_control_sprs(env); @@ -6467,11 +6419,14 @@ static void init_proc_POWER10(CPUPPCState *env) register_power8_pmu_user_sprs(env); register_power8_tm_sprs(env); register_power8_pspb_sprs(env); + register_power8_dpdes_sprs(env); register_vtb_sprs(env); register_power8_ic_sprs(env); register_power8_book4_sprs(env); register_power8_rpr_sprs(env); register_power9_mmu_sprs(env); + register_power10_hash_sprs(env); + register_power10_dexcr_sprs(env); /* FIXME: Filter fields properly based on privilege level */ spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL, @@ -6487,77 +6442,33 @@ static void init_proc_POWER10(CPUPPCState *env) ppcPOWER9_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr) -{ - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER10_BASE) { - return true; - } - return false; -} - -static bool cpu_has_work_POWER10(CPUState *cs) +static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; - if (cs->halted) { - uint64_t psscr = env->spr[SPR_PSSCR]; - - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - - /* If EC is clear, just return true on any pending interrupt */ - if (!(psscr & PSSCR_EC)) { - return true; - } - /* External Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && - (env->spr[SPR_LPCR] & LPCR_EEE)) { - bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (heic == 0 || !msr_hv || msr_pr) { - return true; - } - } - /* Decrementer Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && - (env->spr[SPR_LPCR] & LPCR_DEE)) { - return true; - } - /* Machine Check or Hypervisor Maintenance Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK | - 1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) { - return true; - } - /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && - (env->spr[SPR_LPCR] & LPCR_PDEE)) { - return true; - } - /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && - (env->spr[SPR_LPCR] & LPCR_HDEE)) { - return true; - } - /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) && - (env->spr[SPR_LPCR] & LPCR_HVEE)) { - return true; - } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (!best) { + if (base == CPU_POWERPC_POWER10_BASE) { return true; } + } + + if (base != pcc_base) { return false; - } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); } + + if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) { + /* Major DD version matches to power10_v1.0 and power10_v2.0 */ + return true; + } + + return false; } POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER10"; dc->desc = "POWER10"; @@ -6568,7 +6479,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER10; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER10; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6577,7 +6487,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) PPC_FLOAT_EXT | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBSYNC | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD | @@ -6588,7 +6498,8 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310; + PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310 | + PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_HV) | (1ull << MSR_TM) | @@ -6663,7 +6574,6 @@ static void init_ppc_proc(PowerPCCPU *cpu) #if !defined(CONFIG_USER_ONLY) int i; - env->irq_inputs = NULL; /* Set all exception vectors to an invalid address */ for (i = 0; i < POWERPC_EXCP_NB; i++) { env->excp_vectors[i] = (target_ulong)(-1ULL); @@ -6793,10 +6703,6 @@ static void init_ppc_proc(PowerPCCPU *cpu) /* Pre-compute some useful values */ env->tlb_per_way = env->nb_tlb / env->nb_ways; } - if (env->irq_inputs == NULL) { - warn_report("no internal IRQ controller registered." - " Attempt QEMU to crash very soon !"); - } #endif if (env->check_pow == NULL) { warn_report("no power management check handler registered." @@ -6900,7 +6806,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; } @@ -6954,6 +6860,21 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) } } + /* + * All ppc CPUs represent hardware that exists in the real world, i.e.: we + * do not have a "max" CPU with all possible emulated features enabled. + * Return the default CPU type for the machine because that has greater + * chance of being useful as the "max" CPU. + */ +#if !defined(CONFIG_USER_ONLY) + if (strcmp(name, "max") == 0) { + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); + if (mc) { + return object_class_by_name(mc->default_cpu_type); + } + } +#endif + cpu_model = g_ascii_strdown(name, -1); p = ppc_cpu_lookup_alias(cpu_model); if (p) { @@ -7112,24 +7033,41 @@ static void ppc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.nip = value; } -static bool ppc_cpu_has_work(CPUState *cs) +static vaddr ppc_cpu_get_pc(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + return cpu->env.nip; +} + +#ifdef CONFIG_TCG +static void ppc_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + + cpu->env.nip = data[0]; +} +#endif /* CONFIG_TCG */ + +static bool ppc_cpu_has_work(CPUState *cs) +{ + return cs->interrupt_request & CPU_INTERRUPT_HARD; } -static void ppc_cpu_reset(DeviceState *dev) +static void ppc_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); PowerPCCPU *cpu = POWERPC_CPU(s); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; target_ulong msr; int i; - pcc->parent_reset(dev); + if (pcc->parent_phases.hold) { + pcc->parent_phases.hold(obj); + } msr = (target_ulong)0; msr |= (target_ulong)MSR_HVB; @@ -7150,7 +7088,7 @@ static void ppc_cpu_reset(DeviceState *dev) #if defined(TARGET_PPC64) msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */ #endif -#if !defined(TARGET_WORDS_BIGENDIAN) +#if !TARGET_BIG_ENDIAN msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ if (!((env->msr_mask >> MSR_LE) & 1)) { fprintf(stderr, "Selected CPU does not support little-endian.\n"); @@ -7176,6 +7114,9 @@ static void ppc_cpu_reset(DeviceState *dev) } pmu_update_summaries(env); } + + /* clean any pending stop state */ + env->resume_as_sreset = 0; #endif hreg_compute_hflags(env); env->reserve_addr = (target_ulong)-1ULL; @@ -7208,7 +7149,7 @@ static bool ppc_cpu_is_big_endian(CPUState *cs) cpu_synchronize_state(cs); - return !msr_le; + return !FIELD_EX64(env->msr, MSR, LE); } #ifdef CONFIG_TCG @@ -7279,7 +7220,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; } @@ -7300,8 +7241,6 @@ static void ppc_disas_set_info(CPUState *cs, disassemble_info *info) info->mach = bfd_mach_ppc; #endif } - info->disassembler_options = (char *)"any"; - info->print_insn = print_insn_ppc; info->cap_arch = CS_ARCH_PPC; #ifdef TARGET_PPC64 @@ -7335,6 +7274,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = { static const struct TCGCPUOps ppc_tcg_ops = { .initialize = ppc_translate_init, + .restore_state_to_opc = ppc_restore_state_to_opc, #ifdef CONFIG_USER_ONLY .record_sigsegv = ppc_cpu_record_sigsegv, @@ -7354,6 +7294,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, ppc_cpu_realize, &pcc->parent_realize); @@ -7362,12 +7303,14 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) pcc->pvr_match = ppc_pvr_match_default; device_class_set_props(dc, ppc_cpu_properties); - device_class_set_parent_reset(dc, ppc_cpu_reset, &pcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, ppc_cpu_reset_hold, NULL, + &pcc->parent_phases); cc->class_by_name = ppc_cpu_class_by_name; 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 @@ -7444,17 +7387,15 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) "%08x iidx %d didx %d\n", env->msr, env->spr[SPR_HID0], env->hflags, cpu_mmu_index(env, true), cpu_mmu_index(env, false)); -#if !defined(NO_TIMER_DUMP) - qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY) - " DECR " TARGET_FMT_lu -#endif - "\n", - cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) -#if !defined(CONFIG_USER_ONLY) - , cpu_ppc_load_decr(env) -#endif - ); + if (env->tb_env) { + qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 + " DECR " TARGET_FMT_lu "\n", cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env)); + } +#else + qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 "\n", cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env)); #endif for (i = 0; i < 32; i++) { if ((i & (RGPL - 1)) == 0) { diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 0d01ac3de0b7..cc024316d526 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); \ @@ -1391,3 +1416,68 @@ DFP_HELPER_SHIFT(DSCLI, 64, 1) DFP_HELPER_SHIFT(DSCLIQ, 128, 1) DFP_HELPER_SHIFT(DSCRI, 64, 0) DFP_HELPER_SHIFT(DSCRIQ, 128, 0) + +target_ulong helper_CDTBCD(target_ulong s) +{ + uint64_t res = 0; + uint32_t dec32, declets; + uint8_t bcd[6]; + int i, w, sh; + decNumber a; + + for (w = 1; w >= 0; w--) { + res <<= 32; + declets = extract64(s, 32 * w, 20); + if (declets) { + /* decimal32 with zero exponent and word "w" declets */ + dec32 = (0x225ULL << 20) | declets; + decimal32ToNumber((decimal32 *)&dec32, &a); + decNumberGetBCD(&a, bcd); + for (i = 0; i < a.digits; i++) { + sh = 4 * (a.digits - 1 - i); + res |= (uint64_t)bcd[i] << sh; + } + } + } + + return res; +} + +target_ulong helper_CBCDTD(target_ulong s) +{ + uint64_t res = 0; + uint32_t dec32; + uint8_t bcd[6]; + int w, i, offs; + decNumber a; + decContext context; + + decContextDefault(&context, DEC_INIT_DECIMAL32); + + for (w = 1; w >= 0; w--) { + res <<= 32; + decNumberZero(&a); + /* Extract each BCD field of word "w" */ + for (i = 5; i >= 0; i--) { + offs = 4 * (5 - i) + 32 * w; + bcd[i] = extract64(s, offs, 4); + if (bcd[i] > 9) { + /* + * If the field value is greater than 9, the results are + * undefined. We could use a fixed value like 0 or 9, but + * an and with 9 seems to better match the hardware behavior. + */ + bcd[i] &= 9; + } + } + + /* Create a decNumber with the BCD values and convert to decimal32 */ + decNumberSetBCD(&a, bcd, 6); + decimal32FromNumber((decimal32 *)&dec32, &a, &context); + + /* Extract the two declets from the decimal32 value */ + res |= dec32 & 0xfffff; + } + + return res; +} diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index d3e2cfcd7120..287659c74dbc 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "internal.h" #include "helper_regs.h" +#include "hw/ppc/ppc.h" #include "trace.h" @@ -389,6 +390,7 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector, env->nip = vector; env->msr = msr; hreg_compute_hflags(env); + ppc_maybe_interrupt(env); powerpc_reset_excp_state(cpu); @@ -444,7 +446,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -478,7 +480,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -575,7 +577,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_CRITICAL: /* Critical input */ break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -615,7 +617,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -661,7 +663,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_ITLB: /* Instruction TLB error */ break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -748,7 +750,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -788,7 +790,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -853,7 +855,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_DECR: /* Decrementer exception */ break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -933,7 +935,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -973,7 +975,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1038,7 +1040,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_DECR: /* Decrementer exception */ break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -1128,7 +1130,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) srr1 = SPR_BOOKE_CSRR1; break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -1171,7 +1173,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1247,8 +1249,14 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */ env->spr[SPR_BOOKE_ESR] = ESR_SPV; break; + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ + break; + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; + break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -1366,7 +1374,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -1434,7 +1442,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1507,7 +1515,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) break; case POWERPC_EXCP_RESET: /* System reset exception */ /* A power-saving exception sets ME, otherwise it is unchanged */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { /* indicate that we resumed from power save mode */ msr |= 0x10000; new_msr |= ((target_ulong)1 << MSR_ME); @@ -1519,7 +1527,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) */ new_msr |= (target_ulong)MSR_HVB; } else { - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -1677,29 +1685,355 @@ void ppc_cpu_do_interrupt(CPUState *cs) powerpc_excp(cpu, cs->exception_index); } -static void ppc_hw_interrupt(CPUPPCState *env) +#if defined(TARGET_PPC64) +#define P7_UNUSED_INTERRUPTS \ + (PPC_INTERRUPT_RESET | PPC_INTERRUPT_HVIRT | PPC_INTERRUPT_CEXT | \ + PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ + PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \ + PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB) + +static int p7_interrupt_powersave(CPUPPCState *env) +{ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { + return PPC_INTERRUPT_EXT; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { + return PPC_INTERRUPT_DECR; + } + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return PPC_INTERRUPT_MCK; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return PPC_INTERRUPT_HMI; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + +static int p7_next_unmasked_interrupt(CPUPPCState *env) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Ignore MSR[EE] when coming out of some power management states */ + bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; + + assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0); + + if (cs->halted) { + /* LPCR[PECE] controls which interrupts can exit power-saving mode */ + return p7_interrupt_powersave(env); + } + + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { + /* LPCR will be clear when not supported so this will work */ + bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { + /* HDEC clears on delivery */ + return PPC_INTERRUPT_HDECR; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; + } + } + if (msr_ee != 0) { + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; + } + } + + return 0; +} + +#define P8_UNUSED_INTERRUPTS \ + (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT | \ + PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | \ + PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) + +static int p8_interrupt_powersave(CPUPPCState *env) +{ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { + return PPC_INTERRUPT_EXT; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { + return PPC_INTERRUPT_DECR; + } + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return PPC_INTERRUPT_MCK; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return PPC_INTERRUPT_HMI; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { + return PPC_INTERRUPT_DOORBELL; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + +static int p8_next_unmasked_interrupt(CPUPPCState *env) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Ignore MSR[EE] when coming out of some power management states */ + bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; + + assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0); + + if (cs->halted) { + /* LPCR[PECE] controls which interrupts can exit power-saving mode */ + return p8_interrupt_powersave(env); + } + + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { + /* LPCR will be clear when not supported so this will work */ + bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { + /* HDEC clears on delivery */ + return PPC_INTERRUPT_HDECR; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; + } + } + if (msr_ee != 0) { + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + return PPC_INTERRUPT_DOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; + } + /* EBB exception */ + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { + /* + * EBB exception must be taken in problem state and + * with BESCR_GE set. + */ + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { + return PPC_INTERRUPT_EBB; + } + } + } + + return 0; +} + +#define P9_UNUSED_INTERRUPTS \ + (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT | \ + PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ + PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) + +static int p9_interrupt_powersave(CPUPPCState *env) +{ + /* External Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_EEE)) { + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + if (!heic || !FIELD_EX64_HV(env->msr) || + FIELD_EX64(env->msr, MSR, PR)) { + return PPC_INTERRUPT_EXT; + } + } + /* Decrementer Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_DEE)) { + return PPC_INTERRUPT_DECR; + } + /* Machine Check or Hypervisor Maintenance Exception */ + if (env->spr[SPR_LPCR] & LPCR_OEE) { + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + if (env->pending_interrupts & PPC_INTERRUPT_HMI) { + return PPC_INTERRUPT_HMI; + } + } + /* Privileged Doorbell Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && + (env->spr[SPR_LPCR] & LPCR_PDEE)) { + return PPC_INTERRUPT_DOORBELL; + } + /* Hypervisor Doorbell Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && + (env->spr[SPR_LPCR] & LPCR_HDEE)) { + return PPC_INTERRUPT_HDOORBELL; + } + /* Hypervisor virtualization exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && + (env->spr[SPR_LPCR] & LPCR_HVEE)) { + return PPC_INTERRUPT_HVIRT; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + +static int p9_next_unmasked_interrupt(CPUPPCState *env) { PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Ignore MSR[EE] when coming out of some power management states */ + bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; + + assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0); + + if (cs->halted) { + if (env->spr[SPR_PSSCR] & PSSCR_EC) { + /* + * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can + * wakeup the processor + */ + return p9_interrupt_powersave(env); + } else { + /* + * When it's clear, any system-caused exception exits power-saving + * mode, even the ones that gate on MSR[EE]. + */ + msr_ee = true; + } + } + + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { + /* LPCR will be clear when not supported so this will work */ + bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { + /* HDEC clears on delivery */ + return PPC_INTERRUPT_HDECR; + } + } + + /* Hypervisor virtualization interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { + /* LPCR will be clear when not supported so this will work */ + bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) { + return PPC_INTERRUPT_HVIRT; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; + } + } + if (msr_ee != 0) { + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + return PPC_INTERRUPT_DOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; + } + /* EBB exception */ + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { + /* + * EBB exception must be taken in problem state and + * with BESCR_GE set. + */ + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { + return PPC_INTERRUPT_EBB; + } + } + } + + return 0; +} +#endif + +static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env) +{ bool async_deliver; /* External reset */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); - powerpc_excp(cpu, POWERPC_EXCP_RESET); - return; + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; } /* Machine check exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); - powerpc_excp(cpu, POWERPC_EXCP_MCHECK); - return; + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; } #if 0 /* TODO */ /* External debug exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); - powerpc_excp(cpu, POWERPC_EXCP_DEBUG); - return; + if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) { + return PPC_INTERRUPT_DEBUG; } #endif @@ -1709,130 +2043,424 @@ static void ppc_hw_interrupt(CPUPPCState *env) * clear when coming out of some power management states (in order * for them to become a 0x100). */ - async_deliver = (msr_ee != 0) || env->resume_as_sreset; + async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; /* Hypervisor decrementer exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); - if ((async_deliver || msr_hv == 0) && hdice) { + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); - powerpc_excp(cpu, POWERPC_EXCP_HDECR); - return; + return PPC_INTERRUPT_HDECR; } } /* Hypervisor virtualization interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { + if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { /* LPCR will be clear when not supported so this will work */ bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); - if ((async_deliver || msr_hv == 0) && hvice) { - powerpc_excp(cpu, POWERPC_EXCP_HVIRT); - return; + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { + return PPC_INTERRUPT_HVIRT; } } /* External interrupt can ignore MSR:EE under some circumstances */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ - if ((async_deliver && !(heic && msr_hv && !msr_pr)) || - (env->has_hv_mode && msr_hv == 0 && !lpes0)) { - if (books_vhyp_promotes_external_to_hvirt(cpu)) { - powerpc_excp(cpu, POWERPC_EXCP_HVIRT); - } else { - powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); - } - return; + if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; } } - if (msr_ce != 0) { + if (FIELD_EX64(env->msr, MSR, CE)) { /* External critical interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { - powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); - return; + if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { + return PPC_INTERRUPT_CEXT; } } if (async_deliver != 0) { /* Watchdog timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); - powerpc_excp(cpu, POWERPC_EXCP_WDT); - return; + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + return PPC_INTERRUPT_WDT; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); - powerpc_excp(cpu, POWERPC_EXCP_DOORCI); - return; + if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { + return PPC_INTERRUPT_CDOORBELL; } /* Fixed interval timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); - powerpc_excp(cpu, POWERPC_EXCP_FIT); - return; + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + return PPC_INTERRUPT_FIT; } /* Programmable interval timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); - powerpc_excp(cpu, POWERPC_EXCP_PIT); - return; + if (env->pending_interrupts & PPC_INTERRUPT_PIT) { + return PPC_INTERRUPT_PIT; } /* Decrementer exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { - if (ppc_decr_clear_on_delivery(env)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); - } - powerpc_excp(cpu, POWERPC_EXCP_DECR); - return; + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); - if (is_book3s_arch2x(env)) { - powerpc_excp(cpu, POWERPC_EXCP_SDOOR); - } else { - powerpc_excp(cpu, POWERPC_EXCP_DOORI); - } - return; + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + return PPC_INTERRUPT_DOORBELL; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); - powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); - return; + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + return PPC_INTERRUPT_HDOORBELL; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); - powerpc_excp(cpu, POWERPC_EXCP_PERFM); - return; + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; } /* Thermal interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); - powerpc_excp(cpu, POWERPC_EXCP_THERM); - return; + if (env->pending_interrupts & PPC_INTERRUPT_THERM) { + return PPC_INTERRUPT_THERM; } /* EBB exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_EBB)) { + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { /* * EBB exception must be taken in problem state and * with BESCR_GE set. */ - if (msr_pr == 1 && env->spr[SPR_BESCR] & BESCR_GE) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EBB); + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { + return PPC_INTERRUPT_EBB; + } + } + } - if (env->spr[SPR_BESCR] & BESCR_PMEO) { - powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); - } else if (env->spr[SPR_BESCR] & BESCR_EEO) { - powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); - } + return 0; +} - return; - } +static int ppc_next_unmasked_interrupt(CPUPPCState *env) +{ + switch (env->excp_model) { +#if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER7: + return p7_next_unmasked_interrupt(env); + case POWERPC_EXCP_POWER8: + return p8_next_unmasked_interrupt(env); + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + return p9_next_unmasked_interrupt(env); +#endif + default: + return ppc_next_unmasked_interrupt_generic(env); + } +} + +/* + * Sets CPU_INTERRUPT_HARD if there is at least one unmasked interrupt to be + * delivered and clears CPU_INTERRUPT_HARD otherwise. + * + * This method is called by ppc_set_interrupt when an interrupt is raised or + * lowered, and should also be called whenever an interrupt masking condition + * is changed, e.g.: + * - When relevant bits of MSR are altered, like EE, HV, PR, etc.; + * - When relevant bits of LPCR are altered, like PECE, HDICE, HVICE, etc.; + * - When PSSCR[EC] or env->resume_as_sreset are changed; + * - When cs->halted is changed and the CPU has a different interrupt masking + * logic in power-saving mode (e.g., POWER7/8/9/10); + */ +void ppc_maybe_interrupt(CPUPPCState *env) +{ + CPUState *cs = env_cpu(env); + QEMU_IOTHREAD_LOCK_GUARD(); + + if (ppc_next_unmasked_interrupt(env)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +#if defined(TARGET_PPC64) +static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); } + break; + + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case 0: + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakeup conditions in the + * processor has_work implementation and the logic in this function. + */ + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); } +} - if (env->resume_as_sreset) { +static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + if (is_book3s_arch2x(env)) { + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + } else { + powerpc_excp(cpu, POWERPC_EXCP_DOORI); + } + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakeup conditions in the + * processor has_work implementation and the logic in this function. + */ + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); + } +} + +static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) && + !FIELD_EX64(env->msr, MSR, EE)) { + /* + * A pending interrupt took us out of power-saving, but MSR[EE] says + * that we should return to NIP+4 instead of delivering it. + */ + return; + } + + switch (interrupt) { + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakeup conditions in the + * processor has_work implementation and the logic in this function. + */ + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); + } +} +#endif + +static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_RESET: /* External reset */ + env->pending_interrupts &= ~PPC_INTERRUPT_RESET; + powerpc_excp(cpu, POWERPC_EXCP_RESET); + break; + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + case PPC_INTERRUPT_CEXT: /* External critical interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); + break; + + case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_WDT; + powerpc_excp(cpu, POWERPC_EXCP_WDT); + break; + case PPC_INTERRUPT_CDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_DOORCI); + break; + case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_FIT; + powerpc_excp(cpu, POWERPC_EXCP_FIT); + break; + case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ + env->pending_interrupts &= ~PPC_INTERRUPT_PIT; + powerpc_excp(cpu, POWERPC_EXCP_PIT); + break; + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + if (ppc_decr_clear_on_delivery(env)) { + env->pending_interrupts &= ~PPC_INTERRUPT_DECR; + } + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + if (is_book3s_arch2x(env)) { + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + } else { + powerpc_excp(cpu, POWERPC_EXCP_DOORI); + } + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_THERM: /* Thermal interrupt */ + env->pending_interrupts &= ~PPC_INTERRUPT_THERM; + powerpc_excp(cpu, POWERPC_EXCP_THERM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: /* * This is a bug ! It means that has_work took us out of halt without * anything to deliver while in a PM state that requires getting @@ -1844,8 +2472,30 @@ static void ppc_hw_interrupt(CPUPPCState *env) * It generally means a discrepancy between the wakeup conditions in the * processor has_work implementation and the logic in this function. */ - cpu_abort(env_cpu(env), - "Wakeup from PM state but interrupt Undelivered"); + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); + } +} + +static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + switch (env->excp_model) { +#if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER7: + p7_deliver_interrupt(env, interrupt); + break; + case POWERPC_EXCP_POWER8: + p8_deliver_interrupt(env, interrupt); + break; + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + p9_deliver_interrupt(env, interrupt); + break; +#endif + default: + ppc_deliver_interrupt_generic(env, interrupt); } } @@ -1881,15 +2531,22 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + int interrupt; - if (interrupt_request & CPU_INTERRUPT_HARD) { - ppc_hw_interrupt(env); - if (env->pending_interrupts == 0) { - cs->interrupt_request &= ~CPU_INTERRUPT_HARD; - } - return true; + if ((interrupt_request & CPU_INTERRUPT_HARD) == 0) { + return false; } - return false; + + interrupt = ppc_next_unmasked_interrupt(env); + if (interrupt == 0) { + return false; + } + + ppc_deliver_interrupt(env, interrupt); + if (env->pending_interrupts == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + return true; } #endif /* !CONFIG_USER_ONLY */ @@ -1950,6 +2607,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } } +void helper_ppc_maybe_interrupt(CPUPPCState *env) +{ + ppc_maybe_interrupt(env); +} + #if defined(TARGET_PPC64) void helper_scv(CPUPPCState *env, uint32_t lev) { @@ -1970,6 +2632,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) /* Condition for waking up at 0x100 */ env->resume_as_sreset = (insn != PPC_PM_STOP) || (env->spr[SPR_PSSCR] & PSSCR_EC); + + ppc_maybe_interrupt(env); } #endif /* defined(TARGET_PPC64) */ @@ -2013,7 +2677,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) { @@ -2079,7 +2742,6 @@ void helper_rfebb(CPUPPCState *env, target_ulong s) static void do_ebb(CPUPPCState *env, int ebb_excp) { PowerPCCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); /* * FSCR_EBB and FSCR_IC_EBB are the same bits used with @@ -2094,11 +2756,10 @@ static void do_ebb(CPUPPCState *env, int ebb_excp) env->spr[SPR_BESCR] |= BESCR_EEO; } - if (msr_pr == 1) { + if (FIELD_EX64(env->msr, MSR, PR)) { powerpc_excp(cpu, ebb_excp); } else { - env->pending_interrupts |= 1 << PPC_INTERRUPT_EBB; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1); } } @@ -2172,6 +2833,119 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, #endif #endif +#ifdef CONFIG_TCG +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; +} + +static void do_hash(CPUPPCState *env, target_ulong ea, target_ulong ra, + target_ulong rb, uint64_t key, bool store) +{ + 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()); + } + } +} + +#include "qemu/guest-random.h" + +#ifdef TARGET_PPC64 +#define HELPER_HASH(op, key, store, dexcr_aspect) \ +void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ + target_ulong rb) \ +{ \ + if (env->msr & R_MSR_PR_MASK) { \ + if (!(env->spr[SPR_DEXCR] & R_DEXCR_PRO_##dexcr_aspect##_MASK || \ + env->spr[SPR_HDEXCR] & R_HDEXCR_ENF_##dexcr_aspect##_MASK)) \ + return; \ + } else if (!(env->msr & R_MSR_HV_MASK)) { \ + if (!(env->spr[SPR_DEXCR] & R_DEXCR_PNH_##dexcr_aspect##_MASK || \ + env->spr[SPR_HDEXCR] & R_HDEXCR_ENF_##dexcr_aspect##_MASK)) \ + return; \ + } else if (!(env->msr & R_MSR_S_MASK)) { \ + if (!(env->spr[SPR_HDEXCR] & R_HDEXCR_HNU_##dexcr_aspect##_MASK)) \ + return; \ + } \ + \ + do_hash(env, ea, ra, rb, key, store); \ +} +#else +#define HELPER_HASH(op, key, store, dexcr_aspect) \ +void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ + target_ulong rb) \ +{ \ + do_hash(env, ea, ra, rb, key, store); \ +} +#endif /* TARGET_PPC64 */ + +HELPER_HASH(HASHST, env->spr[SPR_HASHKEYR], true, NPHIE) +HELPER_HASH(HASHCHK, env->spr[SPR_HASHKEYR], false, NPHIE) +HELPER_HASH(HASHSTP, env->spr[SPR_HASHPKEYR], true, PHIE) +HELPER_HASH(HASHCHKP, env->spr[SPR_HASHPKEYR], false, PHIE) +#endif /* CONFIG_TCG */ + #if !defined(CONFIG_USER_ONLY) #ifdef CONFIG_TCG @@ -2208,7 +2982,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~(1 << irq); + ppc_set_irq(env_archcpu(env), irq, 0); } void helper_msgsnd(target_ulong rb) @@ -2227,8 +3001,7 @@ void helper_msgsnd(target_ulong rb) CPUPPCState *cenv = &cpu->env; if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { - cenv->pending_interrupts |= 1 << irq; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + ppc_set_irq(cpu, irq, 1); } } qemu_mutex_unlock_iothread(); @@ -2252,7 +3025,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); + ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0); } static void book3s_msgsnd_common(int pir, int irq) @@ -2266,8 +3039,7 @@ static void book3s_msgsnd_common(int pir, int irq) /* TODO: broadcast message to all threads of the same processor */ if (cenv->spr_cb[SPR_PIR].default_value == pir) { - cenv->pending_interrupts |= 1 << irq; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + ppc_set_irq(cpu, irq, 1); } } qemu_mutex_unlock_iothread(); @@ -2293,7 +3065,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); + ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0); } /* @@ -2324,7 +3096,7 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, uint32_t insn; /* Restore state and reload the insn we executed, for filling in DSISR. */ - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); insn = cpu_ldl_code(env, env->nip); switch (env->mmu_model) { diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 7e8be99cc0c8..a66e16c2128c 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -36,6 +36,15 @@ static inline float128 float128_snan_to_qnan(float128 x) #define float32_snan_to_qnan(x) ((x) | 0x00400000) #define float16_snan_to_qnan(x) ((x) | 0x0200) +static inline float32 bfp32_neg(float32 a) +{ + if (unlikely(float32_is_any_nan(a))) { + return a; + } else { + return float32_chs(a); + } +} + static inline bool fp_exceptions_enabled(CPUPPCState *env) { #ifdef CONFIG_USER_ONLY @@ -202,7 +211,7 @@ static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) env->fpscr |= FP_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_ve != 0) { + if (env->fpscr & FP_VE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { @@ -216,7 +225,7 @@ static void finish_invalid_op_arith(CPUPPCState *env, int op, bool set_fpcc, uintptr_t retaddr) { env->fpscr &= ~(FP_FR | FP_FI); - if (fpscr_ve == 0) { + if (!(env->fpscr & FP_VE)) { if (set_fpcc) { env->fpscr &= ~FP_FPCC; env->fpscr |= (FP_C | FP_FU); @@ -286,7 +295,7 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, /* Update the floating-point exception summary */ env->fpscr |= FP_FX; /* We must update the target FPR before raising the exception */ - if (fpscr_ve != 0) { + if (env->fpscr & FP_VE) { CPUState *cs = env_cpu(env); cs->exception_index = POWERPC_EXCP_PROGRAM; @@ -303,7 +312,7 @@ static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, { env->fpscr |= FP_VXCVI; env->fpscr &= ~(FP_FR | FP_FI); - if (fpscr_ve == 0) { + if (!(env->fpscr & FP_VE)) { if (set_fpcc) { env->fpscr &= ~FP_FPCC; env->fpscr |= (FP_C | FP_FU); @@ -318,7 +327,7 @@ static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) env->fpscr &= ~(FP_FR | FP_FI); /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_ze != 0) { + if (env->fpscr & FP_ZE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { @@ -329,24 +338,24 @@ static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) } } -static inline void float_overflow_excp(CPUPPCState *env) +static inline int float_overflow_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); env->fpscr |= FP_OX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_oe != 0) { - /* XXX: should adjust the result */ + + bool overflow_enabled = !!(env->fpscr & FP_OE); + if (overflow_enabled) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; - } else { - env->fpscr |= FP_XX; - env->fpscr |= FP_FI; } + + return overflow_enabled ? 0 : float_flag_inexact; } static inline void float_underflow_excp(CPUPPCState *env) @@ -356,8 +365,7 @@ static inline void float_underflow_excp(CPUPPCState *env) env->fpscr |= FP_UX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_ue != 0) { - /* XXX: should adjust the result */ + if (env->fpscr & FP_UE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ @@ -370,11 +378,10 @@ static inline void float_inexact_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= FP_FI; env->fpscr |= FP_XX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_xe != 0) { + if (env->fpscr & FP_XE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ @@ -414,7 +421,7 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles) ppc_store_fpscr(env, val); } -void helper_fpscr_check_status(CPUPPCState *env) +static void do_fpscr_check_status(CPUPPCState *env, uintptr_t raddr) { CPUState *cs = env_cpu(env); target_ulong fpscr = env->fpscr; @@ -455,27 +462,36 @@ void helper_fpscr_check_status(CPUPPCState *env) } cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = error | POWERPC_EXCP_FP; + env->fpscr |= FP_FEX; /* Deferred floating-point exception after target FPSCR update */ if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, cs->exception_index, - env->error_code, GETPC()); + env->error_code, raddr); } } -static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) +void helper_fpscr_check_status(CPUPPCState *env) +{ + do_fpscr_check_status(env, GETPC()); +} + +static void do_float_check_status(CPUPPCState *env, bool change_fi, + uintptr_t raddr) { CPUState *cs = env_cpu(env); int status = get_float_exception_flags(&env->fp_status); if (status & float_flag_overflow) { - float_overflow_excp(env); + status |= float_overflow_excp(env); } else if (status & float_flag_underflow) { float_underflow_excp(env); } if (status & float_flag_inexact) { float_inexact_excp(env); - } else { - env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */ + } + if (change_fi) { + env->fpscr = FIELD_DP64(env->fpscr, FPSCR, FI, + !!(status & float_flag_inexact)); } if (cs->exception_index == POWERPC_EXCP_PROGRAM && @@ -490,7 +506,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) void helper_float_check_status(CPUPPCState *env) { - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } void helper_reset_fpstatus(CPUPPCState *env) @@ -684,7 +700,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ } else { \ farg.d = cvtr(arg, &env->fp_status); \ } \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ return farg.ll; \ } @@ -710,7 +726,7 @@ static uint64_t do_fri(CPUPPCState *env, uint64_t arg, /* fri* does not set FPSCR[XX] */ set_float_exception_flags(flags & ~float_flag_inexact, &env->fp_status); - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); return arg; } @@ -814,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) @@ -916,18 +923,17 @@ float64 helper_frsqrtes(CPUPPCState *env, float64 arg) } /* fsel - fsel. */ -uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2, - uint64_t arg3) +uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c) { - CPU_DoubleU farg1; + CPU_DoubleU fa; - farg1.ll = arg1; + fa.ll = a; - if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && - !float64_is_any_nan(farg1.d)) { - return arg2; + if ((!float64_is_neg(fa.d) || float64_is_zero(fa.d)) && + !float64_is_any_nan(fa.d)) { + return c; } else { - return arg3; + return b; } } @@ -1690,9 +1696,9 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_ADD_SUB(name, op, nels, tp, fld, sfifprf, r2sp) \ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *xa, ppc_vsr_t *xb) \ { \ @@ -1709,19 +1715,19 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_addsub(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) @@ -1757,7 +1763,7 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } /* @@ -1766,9 +1772,9 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_MUL(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *xa, ppc_vsr_t *xb) \ { \ @@ -1785,20 +1791,20 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_mul(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) @@ -1828,7 +1834,7 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } /* @@ -1837,9 +1843,9 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_DIV(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *xa, ppc_vsr_t *xb) \ { \ @@ -1856,7 +1862,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_div(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ float_zero_divide_excp(env, GETPC()); \ @@ -1866,13 +1872,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) @@ -1905,7 +1911,7 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } /* @@ -1914,9 +1920,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_RE(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -1934,13 +1940,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) @@ -1954,9 +1960,9 @@ VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0) * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_SQRT(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -1972,20 +1978,20 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_sqrt(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) @@ -1999,9 +2005,9 @@ VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0) * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_RSQRTE(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -2017,19 +2023,19 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_sqrt(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) @@ -2155,13 +2161,13 @@ VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23) * fld - vsr_t field (VsrD(*) or VsrW(*)) * maddflgs - flags for the float*muladd routine that control the * various forms (madd, msub, nmadd, nmsub) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_MADD(op, nels, tp, fld, maddflgs, sfprf) \ +#define VSX_MADD(op, nels, tp, fld, maddflgs, sfifprf) \ 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); \ @@ -2174,15 +2180,15 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_madd(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1) @@ -2234,7 +2240,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *s1, ppc_vsr_t *s2,\ \ helper_compute_fprf_float128(env, t.f128); \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_MADDQ(XSMADDQP, MADD_FLGS, 0) @@ -2274,7 +2280,7 @@ VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0) vxvc = svxvc; \ if (flags & float_flag_invalid_snan) { \ float_invalid_op_vxsnan(env, GETPC()); \ - vxvc &= fpscr_ve == 0; \ + vxvc &= !(env->fpscr & FP_VE); \ } \ if (vxvc) { \ float_invalid_op_vxvc(env, 0, GETPC()); \ @@ -2283,7 +2289,7 @@ VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0) \ memset(xt, 0, sizeof(*xt)); \ memset(&xt->fld, -r, sizeof(xt->fld)); \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, false, GETPC()); \ } VSX_SCALAR_CMP(XSCMPEQDP, float64, eq, VsrD(0), 0) @@ -2319,7 +2325,7 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode, env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, @@ -2348,7 +2354,7 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, @@ -2375,7 +2381,7 @@ static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { vxsnan_flag = true; - if (fpscr_ve == 0 && ordered) { + if (!(env->fpscr & FP_VE) && ordered) { vxvc_flag = true; } } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || @@ -2401,7 +2407,7 @@ static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, float_invalid_op_vxvc(env, 0, GETPC()); } - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, @@ -2440,7 +2446,7 @@ static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, if (float128_is_signaling_nan(xa->f128, &env->fp_status) || float128_is_signaling_nan(xb->f128, &env->fp_status)) { vxsnan_flag = true; - if (fpscr_ve == 0 && ordered) { + if (!(env->fpscr & FP_VE) && ordered) { vxvc_flag = true; } } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || @@ -2466,7 +2472,7 @@ static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, float_invalid_op_vxvc(env, 0, GETPC()); } - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, @@ -2505,7 +2511,7 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, false, GETPC()); \ } VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0)) @@ -2590,7 +2596,7 @@ void helper_##name(CPUPPCState *env, \ t.VsrD(0) = xb->VsrD(0); \ } \ \ - vex_flag = fpscr_ve & vxsnan_flag; \ + vex_flag = (env->fpscr & FP_VE) && vxsnan_flag; \ if (vxsnan_flag) { \ float_invalid_op_vxsnan(env, GETPC()); \ } \ @@ -2622,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))) { \ @@ -2667,14 +2675,16 @@ VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0) * ttp - target type (float32 or float64) * sfld - source vsr_t field * tfld - target vsr_t field (f32 or f64) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \ +#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf) \ 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, \ @@ -2682,24 +2692,26 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ float_invalid_op_vxsnan(env, GETPC()); \ t.tfld = ttp##_snan_to_qnan(t.tfld); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_##ttp(env, t.tfld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0) -#define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfprf) \ +#define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfifprf) \ 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), \ @@ -2707,14 +2719,14 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ float_invalid_op_vxsnan(env, GETPC()); \ t.VsrW(2 * i) = ttp##_snan_to_qnan(t.VsrW(2 * i)); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_##ttp(env, t.VsrW(2 * i)); \ } \ t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0) @@ -2730,13 +2742,15 @@ VSX_CVT_FP_TO_FP2(xscvdpsp, 1, float64, float32, 1) * tfld - target vsr_t field (f32 or f64) * sfprf - set FPRF */ -#define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \ -void helper_##op(CPUPPCState *env, uint32_t opcode, \ - ppc_vsr_t *xt, ppc_vsr_t *xb) \ +#define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \ +void helper_##op(CPUPPCState *env, uint32_t opcode, \ + ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ 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, \ @@ -2750,7 +2764,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) @@ -2764,14 +2778,16 @@ VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) * ttp - target type * sfld - source vsr_t field * tfld - target vsr_t field - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfprf) \ +#define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfifprf) \ 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, \ @@ -2779,13 +2795,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ float_invalid_op_vxsnan(env, GETPC()); \ t.tfld = ttp##_snan_to_qnan(t.tfld); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_##ttp(env, t.tfld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) @@ -2810,7 +2826,7 @@ void helper_XVCVSPBF16(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) } *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, @@ -2819,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; @@ -2833,13 +2851,14 @@ void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, helper_compute_fprf_float64(env, t.VsrD(0)); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } 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); @@ -2876,7 +2895,7 @@ uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) return (result << 32) | result; } -uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) +uint64_t helper_XSCVSPDPN(uint64_t xb) { return helper_todouble(xb >> 32); } @@ -2889,41 +2908,64 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) * ttp - target type (int32, uint32, int64 or uint64) * sfld - source vsr_t field * tfld - target vsr_t field + * sfi - set FI * rnan - resulting NaN */ -#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \ +#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, GETPC()); \ + do_float_check_status(env, sfi, GETPC()); \ } -VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ +VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), true, \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), 0ULL) -VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), \ +VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), true, 0ULL) +VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), false, \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), 0ULL) -VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), \ +VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), false, \ + 0ULL) +VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), false, \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U) -VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), 0ULL) -VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U) +VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), false, \ + 0x80000000ULL) +VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), \ + false, 0ULL) +VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), false, 0U) + +#define VSX_CVT_FP_TO_INT128(op, tp, rnan) \ +void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ +{ \ + ppc_vsr_t t; \ + int flags; \ + \ + helper_reset_fpstatus(env); \ + t.s128 = float128_to_##tp##_round_to_zero(xb->f128, &env->fp_status); \ + flags = get_float_exception_flags(&env->fp_status); \ + if (unlikely(flags & float_flag_invalid)) { \ + t.VsrD(0) = float_invalid_cvt(env, flags, t.VsrD(0), rnan, 0, GETPC());\ + t.VsrD(1) = -(t.VsrD(0) & 1); \ + } \ + \ + *xt = t; \ + do_float_check_status(env, true, GETPC()); \ +} + +VSX_CVT_FP_TO_INT128(XSCVQPUQZ, uint128, 0) +VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL); /* * Likewise, except that the result is duplicated into both subwords. @@ -2934,15 +2976,15 @@ VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U) * words 0 and 1 (and words 2 and 3) of the result register, as * is required by this version of the architecture. */ -#define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, rnan) \ +#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; \ @@ -2951,18 +2993,16 @@ 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, GETPC()); \ + do_float_check_status(env, sfi, GETPC()); \ } -VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, 0x80000000U) -VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, 0U) -VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, 0x80000000U) -VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, 0U) +VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, true, 0x80000000U) +VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, true, 0U) +VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, false, 0x80000000U) +VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, false, 0U) /* * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion @@ -2980,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) { \ @@ -2987,12 +3029,11 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } 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) @@ -3007,26 +3048,28 @@ VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL) * sfld - source vsr_t field * tfld - target vsr_t field * jdef - definition of the j index (i or 2*i) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \ +#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf, r2sp)\ 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) { \ t.tfld = do_frsp(env, t.tfld, GETPC()); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.tfld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) @@ -3052,12 +3095,24 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, false, GETPC()); \ } VSX_CVT_INT_TO_FP2(xvcvsxdsp, int64, float32) VSX_CVT_INT_TO_FP2(xvcvuxdsp, uint64, float32) +#define VSX_CVT_INT128_TO_FP(op, tp) \ +void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)\ +{ \ + helper_reset_fpstatus(env); \ + xt->f128 = tp##_to_float128(xb->s128, &env->fp_status); \ + helper_compute_fprf_float128(env, xt->f128); \ + do_float_check_status(env, true, GETPC()); \ +} + +VSX_CVT_INT128_TO_FP(XSCVUQQP, uint128); +VSX_CVT_INT128_TO_FP(XSCVSQQP, int128); + /* * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion * op - instruction mnemonic @@ -3072,11 +3127,12 @@ 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); \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) @@ -3096,15 +3152,17 @@ VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) * rmode - rounding mode - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \ +#define VSX_ROUND(op, nels, tp, fld, rmode, sfifprf) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ 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); \ @@ -3118,7 +3176,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } else { \ t.fld = tp##_round_to_int(xb->fld, &env->fp_status); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ @@ -3134,7 +3192,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) @@ -3162,11 +3220,11 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) uint64_t xt = do_frsp(env, xb, GETPC()); helper_compute_fprf_float64(env, xt); - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); return xt; } -void helper_xvxsigsp(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) +void helper_XVXSIGSP(ppc_vsr_t *xt, ppc_vsr_t *xb) { ppc_vsr_t t = { }; uint32_t exp, i, fraction; @@ -3183,93 +3241,82 @@ void helper_xvxsigsp(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) *xt = t; } -/* - * VSX_TEST_DC - VSX floating point test data class - * op - instruction mnemonic - * nels - number of elements (1, 2 or 4) - * xbn - VSR register number - * tp - type (float32 or float64) - * fld - vsr_t field (VsrD(*) or VsrW(*)) - * tfld - target vsr_t field (VsrD(*) or VsrW(*)) - * fld_max - target field max - * scrf - set result in CR and FPCC - */ -#define VSX_TEST_DC(op, nels, xbn, tp, fld, tfld, fld_max, scrf) \ -void helper_##op(CPUPPCState *env, uint32_t opcode) \ +#define VSX_TSTDC(tp) \ +static int32_t tp##_tstdc(tp b, uint32_t dcmx) \ { \ - ppc_vsr_t *xt = &env->vsr[xT(opcode)]; \ - ppc_vsr_t *xb = &env->vsr[xbn]; \ - ppc_vsr_t t = { }; \ - uint32_t i, sign, dcmx; \ - uint32_t cc, match = 0; \ - \ - if (!scrf) { \ - dcmx = DCMX_XV(opcode); \ - } else { \ - t = *xt; \ - dcmx = DCMX(opcode); \ - } \ - \ - for (i = 0; i < nels; i++) { \ - sign = tp##_is_neg(xb->fld); \ - if (tp##_is_any_nan(xb->fld)) { \ - match = extract32(dcmx, 6, 1); \ - } else if (tp##_is_infinity(xb->fld)) { \ - match = extract32(dcmx, 4 + !sign, 1); \ - } else if (tp##_is_zero(xb->fld)) { \ - match = extract32(dcmx, 2 + !sign, 1); \ - } else if (tp##_is_zero_or_denormal(xb->fld)) { \ - match = extract32(dcmx, 0 + !sign, 1); \ - } \ - \ - if (scrf) { \ - cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ - env->fpscr &= ~FP_FPCC; \ - env->fpscr |= cc << FPSCR_FPCC; \ - env->crf[BF(opcode)] = cc; \ - } else { \ - t.tfld = match ? fld_max : 0; \ - } \ - match = 0; \ - } \ - if (!scrf) { \ - *xt = t; \ + uint32_t match = 0; \ + uint32_t sign = tp##_is_neg(b); \ + if (tp##_is_any_nan(b)) { \ + match = extract32(dcmx, 6, 1); \ + } else if (tp##_is_infinity(b)) { \ + match = extract32(dcmx, 4 + !sign, 1); \ + } else if (tp##_is_zero(b)) { \ + match = extract32(dcmx, 2 + !sign, 1); \ + } else if (tp##_is_zero_or_denormal(b)) { \ + match = extract32(dcmx, 0 + !sign, 1); \ } \ + return (match != 0); \ } -VSX_TEST_DC(xvtstdcdp, 2, xB(opcode), float64, VsrD(i), VsrD(i), UINT64_MAX, 0) -VSX_TEST_DC(xvtstdcsp, 4, xB(opcode), float32, VsrW(i), VsrW(i), UINT32_MAX, 0) -VSX_TEST_DC(xststdcdp, 1, xB(opcode), float64, VsrD(0), VsrD(0), 0, 1) -VSX_TEST_DC(xststdcqp, 1, (rB(opcode) + 32), float128, f128, VsrD(0), 0, 1) +VSX_TSTDC(float32) +VSX_TSTDC(float64) +VSX_TSTDC(float128) +#undef VSX_TSTDC -void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) +void helper_XVTSTDCDP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) { - uint32_t dcmx, sign, exp; - uint32_t cc, match = 0, not_sp = 0; - float64 arg = xb->VsrD(0); - float64 arg_sp; - - dcmx = DCMX(opcode); - exp = (arg >> 52) & 0x7FF; - sign = float64_is_neg(arg); + int i; + for (i = 0; i < 2; i++) { + t->s64[i] = (int64_t)-float64_tstdc(b->f64[i], dcmx); + } +} - if (float64_is_any_nan(arg)) { - match = extract32(dcmx, 6, 1); - } else if (float64_is_infinity(arg)) { - match = extract32(dcmx, 4 + !sign, 1); - } else if (float64_is_zero(arg)) { - match = extract32(dcmx, 2 + !sign, 1); - } else if (float64_is_zero_or_denormal(arg) || (exp > 0 && exp < 0x381)) { - match = extract32(dcmx, 0 + !sign, 1); +void helper_XVTSTDCSP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) +{ + int i; + for (i = 0; i < 4; i++) { + t->s32[i] = (int32_t)-float32_tstdc(b->f32[i], dcmx); } +} - arg_sp = helper_todouble(helper_tosingle(arg)); - not_sp = arg != arg_sp; +static bool not_SP_value(float64 val) +{ + return val != helper_todouble(helper_tosingle(val)); +} +/* + * VSX_XS_TSTDC - VSX Scalar Test Data Class + * NAME - instruction name + * FLD - vsr_t field (VsrD(0) or f128) + * TP - type (float64 or float128) + */ +#define VSX_XS_TSTDC(NAME, FLD, TP) \ + void helper_##NAME(CPUPPCState *env, uint32_t bf, \ + uint32_t dcmx, ppc_vsr_t *b) \ + { \ + uint32_t cc, match, sign = TP##_is_neg(b->FLD); \ + match = TP##_tstdc(b->FLD, dcmx); \ + cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ + env->crf[bf] = cc; \ + } + +VSX_XS_TSTDC(XSTSTDCDP, VsrD(0), float64) +VSX_XS_TSTDC(XSTSTDCQP, f128, float128) +#undef VSX_XS_TSTDC + +void helper_XSTSTDCSP(CPUPPCState *env, uint32_t bf, + uint32_t dcmx, ppc_vsr_t *b) +{ + uint32_t cc, match, sign = float64_is_neg(b->VsrD(0)); + uint32_t exp = (b->VsrD(0) >> 52) & 0x7FF; + int not_sp = (int)not_SP_value(b->VsrD(0)); + match = float64_tstdc(b->VsrD(0), dcmx) || (exp > 0 && exp < 0x381); cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; env->fpscr &= ~FP_FPCC; env->fpscr |= cc << FPSCR_FPCC; - env->crf[BF(opcode)] = cc; + env->crf[bf] = cc; } void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, @@ -3287,7 +3334,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, if (r == 0 && rmc == 0) { rmode = float_round_ties_away; } else if (r == 0 && rmc == 0x3) { - rmode = fpscr_rn; + rmode = env->fpscr & FP_RN; } else if (r == 1) { switch (rmc) { case 0: @@ -3322,7 +3369,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, } helper_compute_fprf_float128(env, t.f128); - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); *xt = t; } @@ -3341,7 +3388,7 @@ void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode, if (r == 0 && rmc == 0) { rmode = float_round_ties_away; } else if (r == 0 && rmc == 0x3) { - rmode = fpscr_rn; + rmode = env->fpscr & FP_RN; } else if (r == 1) { switch (rmc) { case 0: @@ -3375,7 +3422,7 @@ void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, @@ -3401,7 +3448,7 @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } void helper_xssubqp(CPUPPCState *env, uint32_t opcode, @@ -3427,5 +3474,315 @@ void helper_xssubqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); +} + +static inline void vsxger_excp(CPUPPCState *env, uintptr_t retaddr) +{ + /* + * XV*GER instructions execute and set the FPSCR as if exceptions + * are disabled and only at the end throw an exception + */ + target_ulong enable; + enable = env->fpscr & (FP_ENABLES | FP_FI | FP_FR); + env->fpscr &= ~(FP_ENABLES | FP_FI | FP_FR); + int status = get_float_exception_flags(&env->fp_status); + if (unlikely(status & float_flag_invalid)) { + if (status & float_flag_invalid_snan) { + float_invalid_op_vxsnan(env, 0); + } + if (status & float_flag_invalid_imz) { + float_invalid_op_vximz(env, false, 0); + } + if (status & float_flag_invalid_isi) { + float_invalid_op_vxisi(env, false, 0); + } + } + do_float_check_status(env, false, retaddr); + env->fpscr |= enable; + do_fpscr_check_status(env, retaddr); +} + +typedef float64 extract_f16(float16, float_status *); + +static float64 extract_hf16(float16 in, float_status *fp_status) +{ + return float16_to_float64(in, true, fp_status); +} + +static float64 extract_bf16(bfloat16 in, float_status *fp_status) +{ + return bfloat16_to_float64(in, fp_status); +} + +static void vsxger16(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask, bool acc, + bool neg_mul, bool neg_acc, extract_f16 extract) +{ + float32 r, aux_acc; + float64 psum, va, vb, vc, vd; + int i, j, xmsk_bit, ymsk_bit; + uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK), + xmsk = FIELD_EX32(mask, GER_MSK, XMSK), + ymsk = FIELD_EX32(mask, GER_MSK, YMSK); + float_status *excp_ptr = &env->fp_status; + for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { + for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { + if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { + va = !(pmsk & 2) ? float64_zero : + extract(a->VsrHF(2 * i), excp_ptr); + vb = !(pmsk & 2) ? float64_zero : + extract(b->VsrHF(2 * j), excp_ptr); + vc = !(pmsk & 1) ? float64_zero : + extract(a->VsrHF(2 * i + 1), excp_ptr); + vd = !(pmsk & 1) ? float64_zero : + extract(b->VsrHF(2 * j + 1), excp_ptr); + psum = float64_mul(va, vb, excp_ptr); + psum = float64r32_muladd(vc, vd, psum, 0, excp_ptr); + r = float64_to_float32(psum, excp_ptr); + if (acc) { + aux_acc = at[i].VsrSF(j); + if (neg_mul) { + r = bfp32_neg(r); + } + if (neg_acc) { + aux_acc = bfp32_neg(aux_acc); + } + r = float32_add(r, aux_acc, excp_ptr); + } + at[i].VsrSF(j) = r; + } else { + at[i].VsrSF(j) = float32_zero; + } + } + } + vsxger_excp(env, GETPC()); +} + +typedef void vsxger_zero(ppc_vsr_t *at, int, int); + +typedef void vsxger_muladd_f(ppc_vsr_t *, ppc_vsr_t *, ppc_vsr_t *, int, int, + int flags, float_status *s); + +static void vsxger_muladd32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + at[i].VsrSF(j) = float32_muladd(a->VsrSF(i), b->VsrSF(j), + at[i].VsrSF(j), flags, s); +} + +static void vsxger_mul32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + at[i].VsrSF(j) = float32_mul(a->VsrSF(i), b->VsrSF(j), s); +} + +static void vsxger_zero32(ppc_vsr_t *at, int i, int j) +{ + at[i].VsrSF(j) = float32_zero; +} + +static void vsxger_muladd64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + if (j >= 2) { + j -= 2; + at[i].VsrDF(j) = float64_muladd(a[i / 2].VsrDF(i % 2), b->VsrDF(j), + at[i].VsrDF(j), flags, s); + } +} + +static void vsxger_mul64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + if (j >= 2) { + j -= 2; + at[i].VsrDF(j) = float64_mul(a[i / 2].VsrDF(i % 2), b->VsrDF(j), s); + } +} + +static void vsxger_zero64(ppc_vsr_t *at, int i, int j) +{ + if (j >= 2) { + j -= 2; + at[i].VsrDF(j) = float64_zero; + } +} + +static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask, bool acc, bool neg_mul, + bool neg_acc, vsxger_muladd_f mul, vsxger_muladd_f muladd, + vsxger_zero zero) +{ + int i, j, xmsk_bit, ymsk_bit, op_flags; + uint8_t xmsk = mask & 0x0F; + uint8_t ymsk = (mask >> 4) & 0x0F; + float_status *excp_ptr = &env->fp_status; + op_flags = (neg_acc ^ neg_mul) ? float_muladd_negate_c : 0; + op_flags |= (neg_mul) ? float_muladd_negate_result : 0; + helper_reset_fpstatus(env); + for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { + for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { + if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { + if (acc) { + muladd(at, a, b, i, j, op_flags, excp_ptr); + } else { + mul(at, a, b, i, j, op_flags, excp_ptr); + } + } else { + zero(at, i, j); + } + } + } + vsxger_excp(env, GETPC()); +} + +QEMU_FLATTEN +void helper_XVBF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, false, false, false, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, false, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, true, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, false, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, true, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, false, false, false, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, false, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, true, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, false, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, true, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF32GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, false, false, false, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, false, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, true, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, false, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, true, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF64GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, false, false, false, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, false, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, true, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, false, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, true, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); } diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 105c2f7dd13f..1a0b9ca82c38 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -87,15 +87,15 @@ static int ppc_gdb_register_len(int n) /* * We need to present the registers to gdb in the "current" memory * ordering. For user-only mode we get this for free; - * TARGET_WORDS_BIGENDIAN is set to the proper ordering for the + * TARGET_BIG_ENDIAN is set to the proper ordering for the * binary, and cannot be changed. For system mode, - * TARGET_WORDS_BIGENDIAN is always set, and we must check the current + * TARGET_BIG_ENDIAN is always set, and we must check the current * mode of the chip to see if we're running in little-endian. */ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len) { #ifndef CONFIG_USER_ONLY - if (!msr_le) { + if (!FIELD_EX64(env->msr, MSR, LE)) { /* do nothing */ } else if (len == 4) { bswap32s((uint32_t *)mem_buf); diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 57da11c77ec9..8dd22a35e46f 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -4,8 +4,13 @@ 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(ppc_maybe_interrupt, void, env) DEF_HELPER_1(rfi, void, env) DEF_HELPER_1(40x_rfci, void, env) DEF_HELPER_1(rfci, void, env) @@ -25,6 +30,7 @@ DEF_HELPER_2(store_mmcr1, void, env, tl) DEF_HELPER_3(store_pmc, void, env, i32, i64) DEF_HELPER_2(read_pmc, tl, env, i32) DEF_HELPER_2(insns_inc, void, env, i32) +DEF_HELPER_1(handle_pmc5_overflow, void, env) #endif DEF_HELPER_1(check_tlb_flush_local, void, env) DEF_HELPER_1(check_tlb_flush_global, void, env) @@ -54,13 +60,15 @@ DEF_HELPER_3(sraw, tl, env, tl, tl) DEF_HELPER_FLAGS_2(CFUGED, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(PDEPD, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(PEXTD, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_1(CDTBCD, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(CBCDTD, TCG_CALL_NO_RWG_SE, tl, tl) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_2(cmpeqb, TCG_CALL_NO_RWG_SE, i32, tl, tl) DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(srad, tl, env, tl, tl) -DEF_HELPER_0(darn32, tl) -DEF_HELPER_0(darn64, tl) +DEF_HELPER_FLAGS_0(darn32, TCG_CALL_NO_RWG, tl) +DEF_HELPER_FLAGS_0(darn64, TCG_CALL_NO_RWG, tl) #endif DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32) @@ -114,13 +122,13 @@ 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) DEF_HELPER_2(frsqrtes, i64, env, i64) -DEF_HELPER_4(fsel, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(FSEL, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) DEF_HELPER_FLAGS_2(ftdiv, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) @@ -133,15 +141,19 @@ DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) #define dh_ctype_vsr ppc_vsr_t * #define dh_typecode_vsr dh_typecode_ptr -DEF_HELPER_3(vavgub, void, avr, avr, avr) -DEF_HELPER_3(vavguh, void, avr, avr, avr) -DEF_HELPER_3(vavguw, void, avr, avr, avr) -DEF_HELPER_3(vabsdub, void, avr, avr, avr) -DEF_HELPER_3(vabsduh, void, avr, avr, avr) -DEF_HELPER_3(vabsduw, void, avr, avr, avr) -DEF_HELPER_3(vavgsb, void, avr, avr, avr) -DEF_HELPER_3(vavgsh, void, avr, avr, avr) -DEF_HELPER_3(vavgsw, void, avr, avr, avr) +#define dh_alias_acc ptr +#define dh_ctype_acc ppc_acc_t * +#define dh_typecode_acc dh_typecode_ptr + +DEF_HELPER_FLAGS_4(VAVGUB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGUH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGUW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VABSDUB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VABSDUH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VABSDUW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGSB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGSH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGSW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_4(vcmpeqfp, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgefp, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtfp, void, env, avr, avr, avr) @@ -153,12 +165,12 @@ DEF_HELPER_4(vcmpeqfp_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgefp_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtfp_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpbfp_dot, void, env, avr, avr, avr) -DEF_HELPER_3(vmrglb, void, avr, avr, avr) -DEF_HELPER_3(vmrglh, void, avr, avr, avr) -DEF_HELPER_3(vmrglw, void, avr, avr, avr) -DEF_HELPER_3(vmrghb, void, avr, avr, avr) -DEF_HELPER_3(vmrghh, void, avr, avr, avr) -DEF_HELPER_3(vmrghw, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrglb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrglh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrglw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrghb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrghh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrghw, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULESB, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULESH, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULESW, TCG_CALL_NO_RWG, void, avr, avr, avr) @@ -171,15 +183,19 @@ DEF_HELPER_FLAGS_3(VMULOSW, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULOUB, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULOUH, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULOUW, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_3(vslo, void, avr, avr, avr) -DEF_HELPER_3(vsro, void, avr, avr, avr) -DEF_HELPER_3(vsrv, void, avr, avr, avr) -DEF_HELPER_3(vslv, void, avr, avr, avr) -DEF_HELPER_3(vaddcuw, void, avr, avr, avr) -DEF_HELPER_2(vprtybw, void, avr, avr) -DEF_HELPER_2(vprtybd, void, avr, avr) -DEF_HELPER_2(vprtybq, void, avr, avr) -DEF_HELPER_3(vsubcuw, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VDIVSQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VDIVUQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VDIVESD, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VDIVEUD, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VDIVESQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VDIVEUQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VMODSQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VMODUQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vslo, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vsro, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vsrv, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vslv, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VPRTYBQ, TCG_CALL_NO_RWG, void, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) @@ -192,19 +208,19 @@ DEF_HELPER_FLAGS_5(vadduws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) -DEF_HELPER_3(vadduqm, void, avr, avr, avr) -DEF_HELPER_4(vaddecuq, void, avr, avr, avr, avr) -DEF_HELPER_4(vaddeuqm, void, avr, avr, avr, avr) -DEF_HELPER_3(vaddcuq, void, avr, avr, avr) -DEF_HELPER_3(vsubuqm, void, avr, avr, avr) -DEF_HELPER_4(vsubecuq, void, avr, avr, avr, avr) -DEF_HELPER_4(vsubeuqm, void, avr, avr, avr, avr) -DEF_HELPER_3(vsubcuq, void, avr, avr, avr) -DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32) -DEF_HELPER_3(vextractub, void, avr, avr, i32) -DEF_HELPER_3(vextractuh, void, avr, avr, i32) -DEF_HELPER_3(vextractuw, void, avr, avr, i32) -DEF_HELPER_3(vextractd, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(VADDECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VADDEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_3(VADDCUQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VSUBUQM, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(VSUBECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VSUBEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_3(VSUBCUQ, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(vsldoi, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractub, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractuh, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractuw, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractd, TCG_CALL_NO_RWG, void, avr, avr, i32) DEF_HELPER_4(VINSBLX, void, env, avr, i64, tl) DEF_HELPER_4(VINSHLX, void, env, avr, i64, tl) DEF_HELPER_4(VINSWLX, void, env, avr, i64, tl) @@ -213,18 +229,16 @@ DEF_HELPER_FLAGS_2(VSTRIBL, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIBR, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIHL, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIHR, TCG_CALL_NO_RWG, i32, avr, avr) -DEF_HELPER_2(vnegw, void, avr, avr) -DEF_HELPER_2(vnegd, void, avr, avr) -DEF_HELPER_2(vupkhpx, void, avr, avr) -DEF_HELPER_2(vupklpx, void, avr, avr) -DEF_HELPER_2(vupkhsb, void, avr, avr) -DEF_HELPER_2(vupkhsh, void, avr, avr) -DEF_HELPER_2(vupkhsw, void, avr, avr) -DEF_HELPER_2(vupklsb, void, avr, avr) -DEF_HELPER_2(vupklsh, void, avr, avr) -DEF_HELPER_2(vupklsw, void, avr, avr) -DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_2(vupkhpx, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklpx, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhsb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhsh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhsw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklsb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklsh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklsw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMUBM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMMBM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VPERM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VPERMR, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_4(vpkshss, void, env, avr, avr, avr) @@ -239,14 +253,14 @@ DEF_HELPER_4(vpkudus, void, env, avr, avr, avr) DEF_HELPER_4(vpkuhum, void, env, avr, avr, avr) DEF_HELPER_4(vpkuwum, void, env, avr, avr, avr) DEF_HELPER_4(vpkudum, void, env, avr, avr, avr) -DEF_HELPER_3(vpkpx, void, avr, avr, avr) -DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumuhm, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumuhs, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr) -DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpkpx, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_5(VMHADDSHS, void, env, avr, avr, avr, avr) +DEF_HELPER_5(VMHRADDSHS, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_5(VMSUMUHS, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMSHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_5(VMSUMSHS, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_5(VMLADDUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env) DEF_HELPER_3(lvebx, void, env, avr, tl) @@ -289,59 +303,59 @@ DEF_HELPER_4(vcfsx, void, env, avr, avr, i32) DEF_HELPER_4(vctuxs, void, env, avr, avr, i32) DEF_HELPER_4(vctsxs, void, env, avr, avr, i32) -DEF_HELPER_2(vclzb, void, avr, avr) -DEF_HELPER_2(vclzh, void, avr, avr) -DEF_HELPER_2(vctzb, void, avr, avr) -DEF_HELPER_2(vctzh, void, avr, avr) -DEF_HELPER_2(vctzw, void, avr, avr) -DEF_HELPER_2(vctzd, void, avr, avr) -DEF_HELPER_2(vpopcntb, void, avr, avr) -DEF_HELPER_2(vpopcnth, void, avr, avr) -DEF_HELPER_2(vpopcntw, void, avr, avr) -DEF_HELPER_2(vpopcntd, void, avr, avr) -DEF_HELPER_1(vclzlsbb, tl, avr) -DEF_HELPER_1(vctzlsbb, tl, avr) -DEF_HELPER_3(vbpermd, void, avr, avr, avr) -DEF_HELPER_3(vbpermq, void, avr, avr, avr) -DEF_HELPER_3(vpmsumb, void, avr, avr, avr) -DEF_HELPER_3(vpmsumh, void, avr, avr, avr) -DEF_HELPER_3(vpmsumw, void, avr, avr, avr) -DEF_HELPER_3(vpmsumd, void, avr, avr, avr) -DEF_HELPER_2(vextublx, tl, tl, avr) -DEF_HELPER_2(vextuhlx, tl, tl, avr) -DEF_HELPER_2(vextuwlx, tl, tl, avr) -DEF_HELPER_2(vextubrx, tl, tl, avr) -DEF_HELPER_2(vextuhrx, tl, tl, avr) -DEF_HELPER_2(vextuwrx, tl, tl, avr) +DEF_HELPER_FLAGS_2(vclzb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vclzh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzd, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcntb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcnth, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcntw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcntd, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_1(vclzlsbb, TCG_CALL_NO_RWG, tl, avr) +DEF_HELPER_FLAGS_1(vctzlsbb, TCG_CALL_NO_RWG, tl, avr) +DEF_HELPER_FLAGS_3(vbpermd, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vbpermq, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(VPMSUMD, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_2(vextublx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuhlx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuwlx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextubrx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuhrx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuwrx, TCG_CALL_NO_RWG, tl, tl, avr) DEF_HELPER_5(VEXTDUBVLX, void, env, avr, avr, avr, tl) DEF_HELPER_5(VEXTDUHVLX, void, env, avr, avr, avr, tl) DEF_HELPER_5(VEXTDUWVLX, void, env, avr, avr, avr, tl) DEF_HELPER_5(VEXTDDVLX, void, env, avr, avr, avr, tl) -DEF_HELPER_2(vsbox, void, avr, avr) -DEF_HELPER_3(vcipher, void, avr, avr, avr) -DEF_HELPER_3(vcipherlast, void, avr, avr, avr) -DEF_HELPER_3(vncipher, void, avr, avr, avr) -DEF_HELPER_3(vncipherlast, void, avr, avr, avr) -DEF_HELPER_3(vshasigmaw, void, avr, avr, i32) -DEF_HELPER_3(vshasigmad, void, avr, avr, i32) -DEF_HELPER_4(vpermxor, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_2(vsbox, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_3(vcipher, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vcipherlast, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vncipher, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vncipherlast, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vshasigmaw, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vshasigmad, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_4(vpermxor, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) -DEF_HELPER_4(bcdadd, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdsub, i32, avr, avr, avr, i32) -DEF_HELPER_3(bcdcfn, i32, avr, avr, i32) -DEF_HELPER_3(bcdctn, i32, avr, avr, i32) -DEF_HELPER_3(bcdcfz, i32, avr, avr, i32) -DEF_HELPER_3(bcdctz, i32, avr, avr, i32) -DEF_HELPER_3(bcdcfsq, i32, avr, avr, i32) -DEF_HELPER_3(bcdctsq, i32, avr, avr, i32) -DEF_HELPER_4(bcdcpsgn, i32, avr, avr, avr, i32) -DEF_HELPER_3(bcdsetsgn, i32, avr, avr, i32) -DEF_HELPER_4(bcds, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdus, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdsr, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdtrunc, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdutrunc, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdadd, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdsub, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdcfn, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdctn, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdcfz, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdctz, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdcfsq, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdctsq, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdcpsgn, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdsetsgn, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcds, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdus, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdsr, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdtrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdutrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) DEF_HELPER_4(xsadddp, void, env, vsr, vsr, vsr) DEF_HELPER_5(xsaddqp, void, env, i32, vsr, vsr, vsr) @@ -388,10 +402,14 @@ DEF_HELPER_4(xscvqpsdz, void, env, i32, vsr, vsr) DEF_HELPER_4(xscvqpswz, void, env, i32, vsr, vsr) DEF_HELPER_4(xscvqpudz, void, env, i32, vsr, vsr) DEF_HELPER_4(xscvqpuwz, void, env, i32, vsr, vsr) +DEF_HELPER_3(XSCVQPUQZ, void, env, vsr, vsr) +DEF_HELPER_3(XSCVQPSQZ, void, env, vsr, vsr) +DEF_HELPER_3(XSCVUQQP, void, env, vsr, vsr) +DEF_HELPER_3(XSCVSQQP, void, env, vsr, vsr) DEF_HELPER_3(xscvhpdp, void, env, vsr, vsr) DEF_HELPER_4(xscvsdqp, void, env, i32, vsr, vsr) DEF_HELPER_3(xscvspdp, void, env, vsr, vsr) -DEF_HELPER_2(xscvspdpn, i64, env, i64) +DEF_HELPER_FLAGS_1(XSCVSPDPN, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_3(xscvdpsxds, void, env, vsr, vsr) DEF_HELPER_3(xscvdpsxws, void, env, vsr, vsr) DEF_HELPER_3(xscvdpuxds, void, env, vsr, vsr) @@ -401,9 +419,9 @@ DEF_HELPER_3(xscvuxdsp, void, env, vsr, vsr) DEF_HELPER_3(xscvsxdsp, void, env, vsr, vsr) DEF_HELPER_4(xscvudqp, void, env, i32, vsr, vsr) DEF_HELPER_3(xscvuxddp, void, env, vsr, vsr) -DEF_HELPER_3(xststdcsp, void, env, i32, vsr) -DEF_HELPER_2(xststdcdp, void, env, i32) -DEF_HELPER_2(xststdcqp, void, env, i32) +DEF_HELPER_4(XSTSTDCSP, void, env, i32, i32, vsr) +DEF_HELPER_4(XSTSTDCDP, void, env, i32, i32, vsr) +DEF_HELPER_4(XSTSTDCQP, void, env, i32, i32, vsr) DEF_HELPER_3(xsrdpi, void, env, vsr, vsr) DEF_HELPER_3(xsrdpic, void, env, vsr, vsr) DEF_HELPER_3(xsrdpim, void, env, vsr, vsr) @@ -501,8 +519,8 @@ DEF_HELPER_3(xvcvsxdsp, void, env, vsr, vsr) DEF_HELPER_3(xvcvuxdsp, void, env, vsr, vsr) DEF_HELPER_3(xvcvsxwsp, void, env, vsr, vsr) DEF_HELPER_3(xvcvuxwsp, void, env, vsr, vsr) -DEF_HELPER_2(xvtstdcsp, void, env, i32) -DEF_HELPER_2(xvtstdcdp, void, env, i32) +DEF_HELPER_FLAGS_4(XVTSTDCSP, TCG_CALL_NO_RWG, void, vsr, vsr, i64, i32) +DEF_HELPER_FLAGS_4(XVTSTDCDP, TCG_CALL_NO_RWG, void, vsr, vsr, i64, i32) DEF_HELPER_3(xvrspi, void, env, vsr, vsr) DEF_HELPER_3(xvrspic, void, env, vsr, vsr) DEF_HELPER_3(xvrspim, void, env, vsr, vsr) @@ -524,15 +542,44 @@ DEF_HELPER_FLAGS_2(XXGENPCVDM_be_exp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_FLAGS_2(XXGENPCVDM_be_comp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_FLAGS_2(XXGENPCVDM_le_exp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_FLAGS_2(XXGENPCVDM_le_comp, TCG_CALL_NO_RWG, void, vsr, avr) -DEF_HELPER_4(xxextractuw, void, env, vsr, vsr, i32) +DEF_HELPER_FLAGS_3(XXEXTRACTUW, TCG_CALL_NO_RWG, void, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXPERMX, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, tl) -DEF_HELPER_4(xxinsertw, void, env, vsr, vsr, i32) -DEF_HELPER_3(xvxsigsp, void, env, vsr, vsr) +DEF_HELPER_FLAGS_3(XXINSERTW, TCG_CALL_NO_RWG, void, vsr, vsr, i32) +DEF_HELPER_FLAGS_2(XVXSIGSP, TCG_CALL_NO_RWG, void, vsr, vsr) DEF_HELPER_FLAGS_5(XXEVAL, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVB, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVH, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVW, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVD, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVB, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVH, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVW, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVD, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_5(XVI4GER8, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI4GER8PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI8GER4, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI8GER4PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI8GER4SPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2S, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2SPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2PN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2NP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2NN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2PN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2NP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2NN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GER, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERPN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERNP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERNN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GER, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERPN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERNP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERNN, void, env, vsr, vsr, acc, i32) DEF_HELPER_2(efscfsi, i32, env, i32) DEF_HELPER_2(efscfui, i32, env, i32) @@ -627,13 +674,16 @@ DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(tlbiva, TCG_CALL_NO_RWG, void, env, tl) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG, void, env, tl, tl) -DEF_HELPER_2(load_slb_esid, tl, env, tl) -DEF_HELPER_2(load_slb_vsid, tl, env, tl) -DEF_HELPER_2(find_slb_vsid, tl, env, tl) -DEF_HELPER_FLAGS_2(slbia, TCG_CALL_NO_RWG, void, env, i32) -DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl) -DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_4(tlbie_isa300, TCG_CALL_NO_WG, void, \ + env, tl, tl, i32) +DEF_HELPER_FLAGS_3(SLBMTE, TCG_CALL_NO_RWG, void, env, tl, tl) +DEF_HELPER_2(SLBMFEE, tl, env, tl) +DEF_HELPER_2(SLBMFEV, tl, env, tl) +DEF_HELPER_2(SLBFEE, tl, env, tl) +DEF_HELPER_FLAGS_2(SLBIA, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_3(SLBIAG, TCG_CALL_NO_RWG, void, env, tl, i32) +DEF_HELPER_FLAGS_2(SLBIE, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(SLBIEG, TCG_CALL_NO_RWG, void, env, tl) #endif DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl) DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl) @@ -647,10 +697,10 @@ DEF_HELPER_2(book3s_msgclr, void, env, tl) DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(rac, tl, env, tl) -#endif DEF_HELPER_2(load_dcr, tl, env, tl) DEF_HELPER_3(store_dcr, void, env, tl, tl) +#endif DEF_HELPER_2(load_dump_spr, void, env, i32) DEF_HELPER_2(store_dump_spr, void, env, i32) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 9a691d6833fb..779e7db51343 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -22,6 +22,7 @@ #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "sysemu/kvm.h" +#include "sysemu/tcg.h" #include "helper_regs.h" #include "power8-pmu.h" #include "cpu-models.h" @@ -63,10 +64,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (ppc_flags & POWERPC_FLAG_DE) { target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; - if (dbcr0 & DBCR0_ICMP) { + if ((dbcr0 & DBCR0_ICMP) && FIELD_EX64(env->msr, MSR, DE)) { hflags |= 1 << HFLAGS_SE; } - if (dbcr0 & DBCR0_BRT) { + if ((dbcr0 & DBCR0_BRT) && FIELD_EX64(env->msr, MSR, DE)) { hflags |= 1 << HFLAGS_BE; } } else { @@ -109,6 +110,9 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) { hflags |= 1 << HFLAGS_PMCC1; } + if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) { + hflags |= 1 << HFLAGS_PMCJCE; + } #ifndef CONFIG_USER_ONLY if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { @@ -119,6 +123,9 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (env->pmc_ins_cnt) { hflags |= 1 << HFLAGS_INSN_CNT; } + if (env->pmc_ins_cnt & 0x1e) { + hflags |= 1 << HFLAGS_PMC_OTHER; + } #endif /* @@ -197,17 +204,10 @@ void cpu_interrupt_exittb(CPUState *cs) { /* * We don't need to worry about translation blocks - * when running with KVM. + * unless running with TCG. */ - if (kvm_enabled()) { - return; - } - - if (!qemu_mutex_iothread_locked()) { - qemu_mutex_lock_iothread(); - cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); - qemu_mutex_unlock_iothread(); - } else { + if (tcg_enabled()) { + QEMU_IOTHREAD_LOCK_GUARD(); cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); } } @@ -227,13 +227,12 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) value &= ~MSR_HVB; value |= env->msr & MSR_HVB; } - if (((value >> MSR_IR) & 1) != msr_ir || - ((value >> MSR_DR) & 1) != msr_dr) { + if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { cpu_interrupt_exittb(cs); } if ((env->mmu_model == POWERPC_MMU_BOOKE || env->mmu_model == POWERPC_MMU_BOOKE206) && - ((value >> MSR_GS) & 1) != msr_gs) { + ((value ^ env->msr) & R_MSR_GS_MASK)) { cpu_interrupt_exittb(cs); } if (unlikely((env->flags & POWERPC_FLAG_TGPR) && @@ -241,8 +240,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) /* Swap temporary saved registers with GPRs */ hreg_swap_gpr_tgpr(env); } - if (unlikely((value >> MSR_EP) & 1) != msr_ep) { - env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { + env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; } /* * If PR=1 then EE, IR and DR must be 1 @@ -261,7 +260,9 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) env->msr = value; hreg_compute_hflags(env); #if !defined(CONFIG_USER_ONLY) - if (unlikely(msr_pow == 1)) { + ppc_maybe_interrupt(env); + + if (unlikely(FIELD_EX64(env->msr, MSR, POW))) { if (!env->pending_interrupts && (*env->check_pow)(env)) { cs->halted = 1; excp = EXCP_HALTED; @@ -293,7 +294,7 @@ void check_tlb_flush(CPUPPCState *env, bool global) if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; - tlb_flush_all_cpus_synced(cs); + tlb_flush_all_cpus(cs); return; } diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index ac2d3da9a781..f8f589e9fd06 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -17,12 +17,18 @@ # License along with this library; if not, see . # +&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 +@D ...... rt:5 ra:5 si:s16 &D &D_bf bf l:bool ra imm -@D_bfs ...... bf:3 - l:1 ra:5 imm:s16 &D_bf -@D_bfu ...... bf:3 - l:1 ra:5 imm:16 &D_bf +@D_bfs ...... bf:3 . l:1 ra:5 imm:s16 &D_bf +@D_bfu ...... bf:3 . l:1 ra:5 imm:16 &D_bf %dq_si 4:s12 !function=times_16 %dq_rtp 22:4 !function=times_2 @@ -35,7 +41,7 @@ @DQ_TSXP ...... ..... ra:5 ............ .... &D si=%dq_si rt=%rt_tsxp %ds_si 2:s14 !function=times_4 -@DS ...... rt:5 ra:5 .............. .. &D si=%ds_si +@DS ...... rt:5 ra:5 .............. .. &D si=%ds_si %ds_rtp 22:4 !function=times_2 @DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si @@ -46,10 +52,10 @@ &DX rt d %dx_d 6:s10 16:5 0:1 -@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d +@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d &VA vrt vra vrb rc -@VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA +@VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA &VC vrt vra vrb rc:bool @VC ...... vrt:5 vra:5 vrb:5 rc:1 .......... &VC @@ -58,7 +64,7 @@ @VN ...... vrt:5 vra:5 vrb:5 .. sh:3 ...... &VN &VX vrt vra vrb -@VX ...... vrt:5 vra:5 vrb:5 .......... . &VX +@VX ...... vrt:5 vra:5 vrb:5 .......... . &VX &VX_bf bf vra vrb @VX_bf ...... bf:3 .. vra:5 vrb:5 ........... &VX_bf @@ -73,17 +79,20 @@ @VX_tb_rc ...... vrt:5 ..... vrb:5 rc:1 .......... &VX_tb_rc &VX_uim4 vrt uim vrb -@VX_uim4 ...... vrt:5 . uim:4 vrb:5 ........... &VX_uim4 +@VX_uim4 ...... vrt:5 . uim:4 vrb:5 ........... &VX_uim4 &VX_tb vrt vrb -@VX_tb ...... vrt:5 ..... vrb:5 ........... &VX_tb +@VX_tb ...... vrt:5 ..... vrb:5 ........... &VX_tb &X rt ra rb -@X ...... rt:5 ra:5 rb:5 .......... . &X +@X ...... rt:5 ra:5 rb:5 .......... . &X &X_rc rt ra rb rc:bool @X_rc ...... rt:5 ra:5 rb:5 .......... rc:1 &X_rc +&X_sa rs ra +@X_sa ...... rs:5 ra:5 ..... .......... . &X_sa + %x_frtp 22:4 !function=times_2 %x_frap 17:4 !function=times_2 %x_frbp 12:4 !function=times_2 @@ -91,6 +100,15 @@ @X_tp_a_bp_rc ...... ....0 ra:5 ....0 .......... rc:1 &X_rc rt=%x_frtp rb=%x_frbp +&X_t rt +@X_t ...... rt:5 ..... ..... .......... . &X_t + +&X_tb rt rb +@X_tb ...... rt:5 ..... rb:5 .......... . &X_tb + +&X_t_rc rt rc:bool +@X_t_rc ...... rt:5 ..... ..... .......... rc:1 &X_t_rc + &X_tb_rc rt rb rc:bool @X_tb_rc ...... rt:5 ..... rb:5 .......... rc:1 &X_tb_rc @@ -101,7 +119,7 @@ @X_t_bp_rc ...... rt:5 ..... ....0 .......... rc:1 &X_tb_rc rb=%x_frbp &X_bi rt bi -@X_bi ...... rt:5 bi:5 ----- .......... - &X_bi +@X_bi ...... rt:5 bi:5 ..... .......... . &X_bi &X_bf bf ra rb @X_bf ...... bf:3 .. ra:5 rb:5 .......... . &X_bf @@ -116,7 +134,13 @@ @X_bf_uim_bp ...... bf:3 . uim:6 ....0 .......... . &X_bf_uim rb=%x_frbp &X_bfl bf l:bool ra rb -@X_bfl ...... bf:3 - l:1 ra:5 rb:5 ..........- &X_bfl +@X_bfl ...... bf:3 . l:1 ra:5 rb:5 .......... . &X_bfl + +&X_imm2 rt imm +@X_imm2 ...... rt:5 ..... ... imm:2 .......... . &X_imm2 + +&X_imm3 rt imm +@X_imm3 ...... rt:5 ..... .. imm:3 .......... . &X_imm3 %x_xt 0:1 21:5 &X_imm5 xt imm:uint8_t vrb @@ -125,6 +149,15 @@ &X_imm8 xt imm:uint8_t @X_imm8 ...... ..... .. imm:8 .......... . &X_imm8 xt=%x_xt +&X_ih ih:uint8_t +@X_ih ...... .. ih:3 ..... ..... .......... . &X_ih + +&X_rb rb +@X_rb ...... ..... ..... rb:5 .......... . &X_rb + +&X_rs_l rs l:bool +@X_rs_l ...... rs:5 .... l:1 ..... .......... . &X_rs_l + &X_uim5 xt uim:uint8_t @X_uim5 ...... ..... ..... uim:5 .......... . &X_uim5 xt=%x_xt @@ -142,12 +175,18 @@ @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 &X_vrt_frbp vrt frbp @X_vrt_frbp ...... vrt:5 ..... ....0 .......... . &X_vrt_frbp frbp=%x_frbp +&X_a ra +@X_a ...... ra:3 .. ..... ..... .......... . &X_a + %xx_xt 0:1 21:5 %xx_xb 1:1 11:5 %xx_xa 2:1 16:5 @@ -155,8 +194,16 @@ &XX2 xt xb @XX2 ...... ..... ..... ..... ......... .. &XX2 xt=%xx_xt xb=%xx_xb -&XX2_uim2 xt xb uim:uint8_t -@XX2_uim2 ...... ..... ... uim:2 ..... ......... .. &XX2_uim2 xt=%xx_xt xb=%xx_xb +&XX2_uim xt xb uim:uint8_t +@XX2_uim2 ...... ..... ... uim:2 ..... ......... .. &XX2_uim xt=%xx_xt xb=%xx_xb + +@XX2_uim4 ...... ..... . uim:4 ..... ......... .. &XX2_uim xt=%xx_xt xb=%xx_xb + +%xx_uim7 6:1 2:1 16:5 +@XX2_uim7 ...... ..... ..... ..... .... . ... . .. &XX2_uim xt=%xx_xt xb=%xx_xb uim=%xx_uim7 + +&XX2_bf_uim bf xb uim +@XX2_bf_uim ...... bf:3 uim:7 ..... ......... . . &XX2_bf_uim &XX2_bf_xb bf xb @XX2_bf_xb ...... bf:3 .. ..... ..... ......... . . &XX2_bf_xb xb=%xx_xb @@ -164,6 +211,13 @@ &XX3 xt xa xb @XX3 ...... ..... ..... ..... ........ ... &XX3 xt=%xx_xt xa=%xx_xa xb=%xx_xb +# 32 bit GER instructions have all mask bits considered 1 +&MMIRR_XX3 xa xb xt pmsk xmsk ymsk +%xx_at 23:3 +%xx_xa_pair 2:1 17:4 !function=times_2 +@XX3_at ...... ... .. ..... ..... ........ ... &MMIRR_XX3 xt=%xx_at xb=%xx_xb \ + pmsk=255 xmsk=15 ymsk=15 + &XX3_dm xt xa xb dm @XX3_dm ...... ..... ..... ..... . dm:2 ..... ... &XX3_dm xt=%xx_xt xa=%xx_xa xb=%xx_xb @@ -281,6 +335,19 @@ 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 +CDTBCD 011111 ..... ..... ----- 0100011010 - @X_sa +CBCDTD 011111 ..... ..... ----- 0100111010 - @X_sa + ### Float-Point Load Instructions LFS 110000 ..... ..... ................ @D @@ -305,6 +372,15 @@ 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 + ### Move To/From System Register Instructions SETBC 011111 ..... ..... ----- 0110000000 - @X_bi @@ -312,6 +388,16 @@ SETBCR 011111 ..... ..... ----- 0110100000 - @X_bi SETNBC 011111 ..... ..... ----- 0111000000 - @X_bi SETNBCR 011111 ..... ..... ----- 0111100000 - @X_bi +### Move To/From FPSCR + +MFFS 111111 ..... 00000 ----- 1001000111 . @X_t_rc +MFFSCE 111111 ..... 00001 ----- 1001000111 - @X_t +MFFSCRN 111111 ..... 10110 ..... 1001000111 - @X_tb +MFFSCDRN 111111 ..... 10100 ..... 1001000111 - @X_tb +MFFSCRNI 111111 ..... 10111 ---.. 1001000111 - @X_imm2 +MFFSCDRNI 111111 ..... 10101 --... 1001000111 - @X_imm3 +MFFSL 111111 ..... 11000 ----- 1001000111 - @X_t + ### Decimal Floating-Point Arithmetic Instructions DADD 111011 ..... ..... ..... 0000000010 . @X_rc @@ -404,6 +490,10 @@ DSCLIQ 111111 ..... ..... ...... 001000010 . @Z22_tap_sh_rc DSCRI 111011 ..... ..... ...... 001100010 . @Z22_ta_sh_rc DSCRIQ 111111 ..... ..... ...... 001100010 . @Z22_tap_sh_rc +## Vector Exclusive-OR-based Instructions + +VPMSUMD 000100 ..... ..... ..... 10011001000 @VX + ## Vector Integer Instructions VCMPEQUB 000100 ..... ..... ..... . 0000000110 @VC @@ -435,6 +525,21 @@ VCMPNEZW 000100 ..... ..... ..... . 0110000111 @VC VCMPSQ 000100 ... -- ..... ..... 00101000001 @VX_bf VCMPUQ 000100 ... -- ..... ..... 00100000001 @VX_bf +## Vector Integer Average Instructions + +VAVGSB 000100 ..... ..... ..... 10100000010 @VX +VAVGSH 000100 ..... ..... ..... 10101000010 @VX +VAVGSW 000100 ..... ..... ..... 10110000010 @VX +VAVGUB 000100 ..... ..... ..... 10000000010 @VX +VAVGUH 000100 ..... ..... ..... 10001000010 @VX +VAVGUW 000100 ..... ..... ..... 10010000010 @VX + +## Vector Integer Absolute Difference Instructions + +VABSDUB 000100 ..... ..... ..... 10000000011 @VX +VABSDUH 000100 ..... ..... ..... 10001000011 @VX +VABSDUW 000100 ..... ..... ..... 10010000011 @VX + ## Vector Bit Manipulation Instruction VGNB 000100 ..... -- ... ..... 10011001100 @VX_n @@ -445,6 +550,10 @@ VCTZDM 000100 ..... ..... ..... 11111000100 @VX VPDEPD 000100 ..... ..... ..... 10111001101 @VX VPEXTD 000100 ..... ..... ..... 10110001101 @VX +VPRTYBD 000100 ..... 01001 ..... 11000000010 @VX_tb +VPRTYBQ 000100 ..... 01010 ..... 11000000010 @VX_tb +VPRTYBW 000100 ..... 01000 ..... 11000000010 @VX_tb + ## Vector Permute and Formatting Instruction VEXTDUBVLX 000100 ..... ..... ..... ..... 011000 @VA @@ -524,6 +633,20 @@ VRLQNM 000100 ..... ..... ..... 00101000101 @VX ## Vector Integer Arithmetic Instructions +VADDCUW 000100 ..... ..... ..... 00110000000 @VX +VADDCUQ 000100 ..... ..... ..... 00101000000 @VX +VADDUQM 000100 ..... ..... ..... 00100000000 @VX + +VADDEUQM 000100 ..... ..... ..... ..... 111100 @VA +VADDECUQ 000100 ..... ..... ..... ..... 111101 @VA + +VSUBCUW 000100 ..... ..... ..... 10110000000 @VX +VSUBCUQ 000100 ..... ..... ..... 10101000000 @VX +VSUBUQM 000100 ..... ..... ..... 10100000000 @VX + +VSUBECUQ 000100 ..... ..... ..... ..... 111111 @VA +VSUBEUQM 000100 ..... ..... ..... ..... 111110 @VA + VEXTSB2W 000100 ..... 10000 ..... 11000000010 @VX_tb VEXTSH2W 000100 ..... 10001 ..... 11000000010 @VX_tb VEXTSB2D 000100 ..... 11000 ..... 11000000010 @VX_tb @@ -531,6 +654,9 @@ VEXTSH2D 000100 ..... 11001 ..... 11000000010 @VX_tb VEXTSW2D 000100 ..... 11010 ..... 11000000010 @VX_tb VEXTSD2Q 000100 ..... 11011 ..... 11000000010 @VX_tb +VNEGD 000100 ..... 00111 ..... 11000000010 @VX_tb +VNEGW 000100 ..... 00110 ..... 11000000010 @VX_tb + ## Vector Mask Manipulation Instructions MTVSRBM 000100 ..... 10000 ..... 11001000010 @VX_tb @@ -587,9 +713,20 @@ VMULLD 000100 ..... ..... ..... 00111001001 @VX ## Vector Multiply-Sum Instructions +VMSUMUBM 000100 ..... ..... ..... ..... 100100 @VA +VMSUMMBM 000100 ..... ..... ..... ..... 100101 @VA +VMSUMSHM 000100 ..... ..... ..... ..... 101000 @VA +VMSUMSHS 000100 ..... ..... ..... ..... 101001 @VA +VMSUMUHM 000100 ..... ..... ..... ..... 100110 @VA +VMSUMUHS 000100 ..... ..... ..... ..... 100111 @VA + VMSUMCUD 000100 ..... ..... ..... ..... 010111 @VA VMSUMUDM 000100 ..... ..... ..... ..... 100011 @VA +VMLADDUHM 000100 ..... ..... ..... ..... 100010 @VA +VMHADDSHS 000100 ..... ..... ..... ..... 100000 @VA +VMHRADDSHS 000100 ..... ..... ..... ..... 100001 @VA + ## Vector String Instructions VSTRIBL 000100 ..... 00000 ..... . 0000001101 @VX_tb_rc @@ -623,6 +760,17 @@ STXVRHX 011111 ..... ..... ..... 0010101101 . @X_TSX STXVRWX 011111 ..... ..... ..... 0011001101 . @X_TSX STXVRDX 011111 ..... ..... ..... 0011101101 . @X_TSX +## VSX Vector Binary Floating-Point Sign Manipulation Instructions + +XVABSDP 111100 ..... 00000 ..... 111011001 .. @XX2 +XVABSSP 111100 ..... 00000 ..... 110011001 .. @XX2 +XVNABSDP 111100 ..... 00000 ..... 111101001 .. @XX2 +XVNABSSP 111100 ..... 00000 ..... 110101001 .. @XX2 +XVNEGDP 111100 ..... 00000 ..... 111111001 .. @XX2 +XVNEGSP 111100 ..... 00000 ..... 110111001 .. @XX2 +XVCPSGNDP 111100 ..... ..... ..... 11110000 ... @XX3 +XVCPSGNSP 111100 ..... ..... ..... 11010000 ... @XX3 + ## VSX Scalar Multiply-Add Instructions XSMADDADP 111100 ..... ..... ..... 00100001 . . . @XX3 @@ -656,6 +804,9 @@ XXSPLTW 111100 ..... ---.. ..... 010100100 . . @XX2_uim2 ## VSX Permute Instructions +XXEXTRACTUW 111100 ..... - .... ..... 010100101 .. @XX2_uim4 +XXINSERTW 111100 ..... - .... ..... 010110101 .. @XX2_uim4 + XXPERM 111100 ..... ..... ..... 00011010 ... @XX3 XXPERMR 111100 ..... ..... ..... 00111010 ... @XX3 XXPERMDI 111100 ..... ..... ..... 0 .. 01010 ... @XX3_dm @@ -692,8 +843,22 @@ XSCMPGTQP 111111 ..... ..... ..... 0011100100 - @X ## VSX Binary Floating-Point Convert Instructions XSCVQPDP 111111 ..... 10100 ..... 1101000100 . @X_tb_rc +XSCVQPUQZ 111111 ..... 00000 ..... 1101000100 - @X_tb +XSCVQPSQZ 111111 ..... 01000 ..... 1101000100 - @X_tb +XSCVUQQP 111111 ..... 00011 ..... 1101000100 - @X_tb +XSCVSQQP 111111 ..... 01011 ..... 1101000100 - @X_tb XVCVBF16SPN 111100 ..... 10000 ..... 111011011 .. @XX2 XVCVSPBF16 111100 ..... 10001 ..... 111011011 .. @XX2 +XSCVSPDPN 111100 ..... ----- ..... 101001011 .. @XX2 + +## VSX Binary Floating-Point Math Support Instructions + +XVXSIGSP 111100 ..... 01001 ..... 111011011 .. @XX2 +XVTSTDCDP 111100 ..... ..... ..... 1111 . 101 ... @XX2_uim7 +XVTSTDCSP 111100 ..... ..... ..... 1101 . 101 ... @XX2_uim7 +XSTSTDCSP 111100 ... ....... ..... 100101010 . - @XX2_bf_uim xb=%xx_xb +XSTSTDCDP 111100 ... ....... ..... 101101010 . - @XX2_bf_uim xb=%xx_xb +XSTSTDCQP 111111 ... ....... xb:5 1011000100 - @XX2_bf_uim ## VSX Vector Test Least-Significant Bit by Byte Instruction @@ -703,3 +868,101 @@ XVTLSBB 111100 ... -- 00010 ..... 111011011 . - @XX2_bf_xb &XL_s s:uint8_t @XL_s ......-------------- s:1 .......... - &XL_s RFEBB 010011-------------- . 0010010010 - @XL_s + +## Accumulator Instructions + +XXMFACC 011111 ... -- 00000 ----- 0010110001 - @X_a +XXMTACC 011111 ... -- 00001 ----- 0010110001 - @X_a +XXSETACCZ 011111 ... -- 00011 ----- 0010110001 - @X_a + +## VSX GER instruction + +XVI4GER8 111011 ... -- ..... ..... 00100011 ..- @XX3_at xa=%xx_xa +XVI4GER8PP 111011 ... -- ..... ..... 00100010 ..- @XX3_at xa=%xx_xa +XVI8GER4 111011 ... -- ..... ..... 00000011 ..- @XX3_at xa=%xx_xa +XVI8GER4PP 111011 ... -- ..... ..... 00000010 ..- @XX3_at xa=%xx_xa +XVI16GER2 111011 ... -- ..... ..... 01001011 ..- @XX3_at xa=%xx_xa +XVI16GER2PP 111011 ... -- ..... ..... 01101011 ..- @XX3_at xa=%xx_xa +XVI8GER4SPP 111011 ... -- ..... ..... 01100011 ..- @XX3_at xa=%xx_xa +XVI16GER2S 111011 ... -- ..... ..... 00101011 ..- @XX3_at xa=%xx_xa +XVI16GER2SPP 111011 ... -- ..... ..... 00101010 ..- @XX3_at xa=%xx_xa + +XVBF16GER2 111011 ... -- ..... ..... 00110011 ..- @XX3_at xa=%xx_xa +XVBF16GER2PP 111011 ... -- ..... ..... 00110010 ..- @XX3_at xa=%xx_xa +XVBF16GER2PN 111011 ... -- ..... ..... 10110010 ..- @XX3_at xa=%xx_xa +XVBF16GER2NP 111011 ... -- ..... ..... 01110010 ..- @XX3_at xa=%xx_xa +XVBF16GER2NN 111011 ... -- ..... ..... 11110010 ..- @XX3_at xa=%xx_xa + +XVF16GER2 111011 ... -- ..... ..... 00010011 ..- @XX3_at xa=%xx_xa +XVF16GER2PP 111011 ... -- ..... ..... 00010010 ..- @XX3_at xa=%xx_xa +XVF16GER2PN 111011 ... -- ..... ..... 10010010 ..- @XX3_at xa=%xx_xa +XVF16GER2NP 111011 ... -- ..... ..... 01010010 ..- @XX3_at xa=%xx_xa +XVF16GER2NN 111011 ... -- ..... ..... 11010010 ..- @XX3_at xa=%xx_xa + +XVF32GER 111011 ... -- ..... ..... 00011011 ..- @XX3_at xa=%xx_xa +XVF32GERPP 111011 ... -- ..... ..... 00011010 ..- @XX3_at xa=%xx_xa +XVF32GERPN 111011 ... -- ..... ..... 10011010 ..- @XX3_at xa=%xx_xa +XVF32GERNP 111011 ... -- ..... ..... 01011010 ..- @XX3_at xa=%xx_xa +XVF32GERNN 111011 ... -- ..... ..... 11011010 ..- @XX3_at xa=%xx_xa + +XVF64GER 111011 ... -- .... 0 ..... 00111011 ..- @XX3_at xa=%xx_xa_pair +XVF64GERPP 111011 ... -- .... 0 ..... 00111010 ..- @XX3_at xa=%xx_xa_pair +XVF64GERPN 111011 ... -- .... 0 ..... 10111010 ..- @XX3_at xa=%xx_xa_pair +XVF64GERNP 111011 ... -- .... 0 ..... 01111010 ..- @XX3_at xa=%xx_xa_pair +XVF64GERNN 111011 ... -- .... 0 ..... 11111010 ..- @XX3_at xa=%xx_xa_pair + +## Vector Division Instructions + +VDIVSW 000100 ..... ..... ..... 00110001011 @VX +VDIVUW 000100 ..... ..... ..... 00010001011 @VX +VDIVSD 000100 ..... ..... ..... 00111001011 @VX +VDIVUD 000100 ..... ..... ..... 00011001011 @VX +VDIVSQ 000100 ..... ..... ..... 00100001011 @VX +VDIVUQ 000100 ..... ..... ..... 00000001011 @VX + +VDIVESW 000100 ..... ..... ..... 01110001011 @VX +VDIVEUW 000100 ..... ..... ..... 01010001011 @VX +VDIVESD 000100 ..... ..... ..... 01111001011 @VX +VDIVEUD 000100 ..... ..... ..... 01011001011 @VX +VDIVESQ 000100 ..... ..... ..... 01100001011 @VX +VDIVEUQ 000100 ..... ..... ..... 01000001011 @VX + +VMODSW 000100 ..... ..... ..... 11110001011 @VX +VMODUW 000100 ..... ..... ..... 11010001011 @VX +VMODSD 000100 ..... ..... ..... 11111001011 @VX +VMODUD 000100 ..... ..... ..... 11011001011 @VX +VMODSQ 000100 ..... ..... ..... 11100001011 @VX +VMODUQ 000100 ..... ..... ..... 11000001011 @VX + +## SLB Management Instructions + +SLBIE 011111 ----- ----- ..... 0110110010 - @X_rb +SLBIEG 011111 ..... ----- ..... 0111010010 - @X_tb + +SLBIA 011111 --... ----- ----- 0111110010 - @X_ih +SLBIAG 011111 ..... ----. ----- 1101010010 - @X_rs_l + +SLBMTE 011111 ..... ----- ..... 0110010010 - @X_tb + +SLBMFEV 011111 ..... ----- ..... 1101010011 - @X_tb +SLBMFEE 011111 ..... ----- ..... 1110010011 - @X_tb + +SLBFEE 011111 ..... ----- ..... 1111010011 1 @X_tb + +SLBSYNC 011111 ----- ----- ----- 0101010010 - + +## TLB Management Instructions + +&X_tlbie rb rs ric prs:bool r:bool +@X_tlbie ...... rs:5 - ric:2 prs:1 r:1 rb:5 .......... - &X_tlbie + +TLBIE 011111 ..... - .. . . ..... 0100110010 - @X_tlbie +TLBIEL 011111 ..... - .. . . ..... 0100010010 - @X_tlbie + +# Processor Control Instructions + +MSGCLR 011111 ----- ----- ..... 0011101110 - @X_rb +MSGSND 011111 ----- ----- ..... 0011001110 - @X_rb +MSGCLRP 011111 ----- ----- ..... 0010101110 - @X_rb +MSGSNDP 011111 ----- ----- ..... 0010001110 - @X_rb +MSGSYNC 011111 ----- ----- ----- 1101110110 - diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode index 691e8fe6c0bb..de115c1943a0 100644 --- a/target/ppc/insn64.decode +++ b/target/ppc/insn64.decode @@ -68,6 +68,20 @@ ...... ..... ..... ..... ..... .. .... \ &8RR_XX4_uim3 xt=%8rr_xx_xt xa=%8rr_xx_xa xb=%8rr_xx_xb xc=%8rr_xx_xc +# Format MMIRR:XX3 +&MMIRR_XX3 !extern xa xb xt pmsk xmsk ymsk +%xx3_xa 2:1 16:5 +%xx3_xb 1:1 11:5 +%xx3_at 23:3 +%xx3_xa_pair 2:1 17:4 !function=times_2 +@MMIRR_XX3 ...... .. .... .. . . ........ xmsk:4 ymsk:4 \ + ...... ... .. ..... ..... ........ ... \ + &MMIRR_XX3 xa=%xx3_xa xb=%xx3_xb xt=%xx3_at + +@MMIRR_XX3_NO_P ...... .. .... .. . . ........ xmsk:4 .... \ + ...... ... .. ..... ..... ........ ... \ + &MMIRR_XX3 xb=%xx3_xb xt=%xx3_at pmsk=1 + ### Fixed-Point Load Instructions PLBZ 000001 10 0--.-- .................. \ @@ -115,6 +129,71 @@ PSTFS 000001 10 0--.-- .................. \ PSTFD 000001 10 0--.-- .................. \ 110110 ..... ..... ................ @PLS_D +## VSX GER instruction + +PMXVI4GER8 000001 11 1001 -- - - pmsk:8 ........ \ + 111011 ... -- ..... ..... 00100011 ..- @MMIRR_XX3 +PMXVI4GER8PP 000001 11 1001 -- - - pmsk:8 ........ \ + 111011 ... -- ..... ..... 00100010 ..- @MMIRR_XX3 +PMXVI8GER4 000001 11 1001 -- - - pmsk:4 ---- ........ \ + 111011 ... -- ..... ..... 00000011 ..- @MMIRR_XX3 +PMXVI8GER4PP 000001 11 1001 -- - - pmsk:4 ---- ........ \ + 111011 ... -- ..... ..... 00000010 ..- @MMIRR_XX3 +PMXVI16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01001011 ..- @MMIRR_XX3 +PMXVI16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01101011 ..- @MMIRR_XX3 +PMXVI8GER4SPP 000001 11 1001 -- - - pmsk:4 ---- ........ \ + 111011 ... -- ..... ..... 01100011 ..- @MMIRR_XX3 +PMXVI16GER2S 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00101011 ..- @MMIRR_XX3 +PMXVI16GER2SPP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00101010 ..- @MMIRR_XX3 + +PMXVBF16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00110011 ..- @MMIRR_XX3 +PMXVBF16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00110010 ..- @MMIRR_XX3 +PMXVBF16GER2PN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 10110010 ..- @MMIRR_XX3 +PMXVBF16GER2NP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01110010 ..- @MMIRR_XX3 +PMXVBF16GER2NN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 11110010 ..- @MMIRR_XX3 + +PMXVF16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00010011 ..- @MMIRR_XX3 +PMXVF16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00010010 ..- @MMIRR_XX3 +PMXVF16GER2PN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 10010010 ..- @MMIRR_XX3 +PMXVF16GER2NP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01010010 ..- @MMIRR_XX3 +PMXVF16GER2NN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 11010010 ..- @MMIRR_XX3 + +PMXVF32GER 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 00011011 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERPP 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 00011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERPN 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 10011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERNP 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 01011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERNN 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 11011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa + +PMXVF64GER 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 00111011 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERPP 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 00111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERPN 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 10111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERNP 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 01111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERNN 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 11111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair + ### Prefixed No-operation Instruction @PNOP 000001 11 0000-- 000000000000000000 \ diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 492f34c4992b..d97a7f1f28b7 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; } } @@ -425,7 +425,7 @@ uint64_t helper_PEXTD(uint64_t src, uint64_t mask) /*****************************************************************************/ /* Altivec extension helpers */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define VECTOR_FOR_INORDER_I(index, element) \ for (index = 0; index < ARRAY_SIZE(r->element); index++) #else @@ -492,40 +492,8 @@ static inline void set_vscr_sat(CPUPPCState *env) env->vscr_sat.u32[0] = 1; } -void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - r->u32[i] = ~a->u32[i] < b->u32[i]; - } -} - -/* vprtybw */ -void helper_vprtybw(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - uint64_t res = b->u32[i] ^ (b->u32[i] >> 16); - res ^= res >> 8; - r->u32[i] = res & 1; - } -} - -/* vprtybd */ -void helper_vprtybd(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - for (i = 0; i < ARRAY_SIZE(r->u64); i++) { - uint64_t res = b->u64[i] ^ (b->u64[i] >> 32); - res ^= res >> 16; - res ^= res >> 8; - r->u64[i] = res & 1; - } -} - /* vprtybq */ -void helper_vprtybq(ppc_avr_t *r, ppc_avr_t *b) +void helper_VPRTYBQ(ppc_avr_t *r, ppc_avr_t *b, uint32_t v) { uint64_t res = b->u64[0] ^ b->u64[1]; res ^= res >> 32; @@ -602,29 +570,27 @@ VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw) #undef VARITHSAT_SIGNED #undef VARITHSAT_UNSIGNED -#define VAVG_DO(name, element, etype) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ - r->element[i] = x >> 1; \ - } \ +#define VAVG(name, element, etype) \ + void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t v)\ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ + r->element[i] = x >> 1; \ + } \ } -#define VAVG(type, signed_element, signed_type, unsigned_element, \ - unsigned_type) \ - VAVG_DO(avgs##type, signed_element, signed_type) \ - VAVG_DO(avgu##type, unsigned_element, unsigned_type) -VAVG(b, s8, int16_t, u8, uint16_t) -VAVG(h, s16, int32_t, u16, uint32_t) -VAVG(w, s32, int64_t, u32, uint64_t) -#undef VAVG_DO +VAVG(VAVGSB, s8, int16_t) +VAVG(VAVGUB, u8, uint16_t) +VAVG(VAVGSH, s16, int32_t) +VAVG(VAVGUH, u16, uint32_t) +VAVG(VAVGSW, s32, int64_t) +VAVG(VAVGUW, u32, uint64_t) #undef VAVG -#define VABSDU_DO(name, element) \ -void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ +#define VABSDU(name, element) \ +void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t v)\ { \ int i; \ \ @@ -640,12 +606,9 @@ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ * name - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ -#define VABSDU(type, element) \ - VABSDU_DO(absdu##type, element) -VABSDU(b, u8) -VABSDU(h, u16) -VABSDU(w, u32) -#undef VABSDU_DO +VABSDU(VABSDUB, u8) +VABSDU(VABSDUH, u16) +VABSDU(VABSDUW, u32) #undef VABSDU #define VCF(suffix, cvt, element) \ @@ -782,6 +745,137 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT +typedef int64_t do_ger(uint32_t, uint32_t, uint32_t); + +static int64_t ger_rank8(uint32_t a, uint32_t b, uint32_t mask) +{ + int64_t psum = 0; + for (int i = 0; i < 8; i++, mask >>= 1) { + if (mask & 1) { + psum += (int64_t)sextract32(a, 4 * i, 4) * sextract32(b, 4 * i, 4); + } + } + return psum; +} + +static int64_t ger_rank4(uint32_t a, uint32_t b, uint32_t mask) +{ + int64_t psum = 0; + for (int i = 0; i < 4; i++, mask >>= 1) { + if (mask & 1) { + psum += sextract32(a, 8 * i, 8) * (int64_t)extract32(b, 8 * i, 8); + } + } + return psum; +} + +static int64_t ger_rank2(uint32_t a, uint32_t b, uint32_t mask) +{ + int64_t psum = 0; + for (int i = 0; i < 2; i++, mask >>= 1) { + if (mask & 1) { + psum += (int64_t)sextract32(a, 16 * i, 16) * + sextract32(b, 16 * i, 16); + } + } + return psum; +} + +static void xviger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, ppc_acc_t *at, + uint32_t mask, bool sat, bool acc, do_ger ger) +{ + uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK), + xmsk = FIELD_EX32(mask, GER_MSK, XMSK), + ymsk = FIELD_EX32(mask, GER_MSK, YMSK); + uint8_t xmsk_bit, ymsk_bit; + int64_t psum; + int i, j; + for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { + for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { + if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { + psum = ger(a->VsrW(i), b->VsrW(j), pmsk); + if (acc) { + psum += at[i].VsrSW(j); + } + if (sat && psum > INT32_MAX) { + set_vscr_sat(env); + at[i].VsrSW(j) = INT32_MAX; + } else if (sat && psum < INT32_MIN) { + set_vscr_sat(env); + at[i].VsrSW(j) = INT32_MIN; + } else { + at[i].VsrSW(j) = (int32_t) psum; + } + } else { + at[i].VsrSW(j) = 0; + } + } + } +} + +QEMU_FLATTEN +void helper_XVI4GER8(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, false, ger_rank8); +} + +QEMU_FLATTEN +void helper_XVI4GER8PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, true, ger_rank8); +} + +QEMU_FLATTEN +void helper_XVI8GER4(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, false, ger_rank4); +} + +QEMU_FLATTEN +void helper_XVI8GER4PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, true, ger_rank4); +} + +QEMU_FLATTEN +void helper_XVI8GER4SPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, true, true, ger_rank4); +} + +QEMU_FLATTEN +void helper_XVI16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, false, ger_rank2); +} + +QEMU_FLATTEN +void helper_XVI16GER2S(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, true, false, ger_rank2); +} + +QEMU_FLATTEN +void helper_XVI16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, true, ger_rank2); +} + +QEMU_FLATTEN +void helper_XVI16GER2SPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, true, true, ger_rank2); +} + target_ulong helper_vclzlsbb(ppc_avr_t *r) { target_ulong count = 0; @@ -808,7 +902,7 @@ target_ulong helper_vctzlsbb(ppc_avr_t *r) return count; } -void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMHADDSHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; @@ -826,7 +920,7 @@ void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMHRADDSHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; @@ -843,7 +937,8 @@ void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_VMLADDUHM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c, + uint32_t v) { int i; @@ -875,8 +970,7 @@ VMRG(w, u32, VsrW) #undef VMRG_DO #undef VMRG -void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMMBM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[16]; int i; @@ -891,8 +985,7 @@ void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMSHM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; int i; @@ -906,7 +999,7 @@ void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMSUMSHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; @@ -928,8 +1021,7 @@ void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMUBM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint16_t prod[16]; int i; @@ -944,8 +1036,7 @@ void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMUHM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; int i; @@ -959,7 +1050,7 @@ void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMSUMUHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; @@ -1036,6 +1127,112 @@ void helper_XXPERMX(ppc_vsr_t *t, ppc_vsr_t *s0, ppc_vsr_t *s1, ppc_vsr_t *pcv, *t = tmp; } +void helper_VDIVSQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + Int128 neg1 = int128_makes64(-1); + Int128 int128_min = int128_make128(0, INT64_MIN); + if (likely(int128_nz(b->s128) && + (int128_ne(a->s128, int128_min) || int128_ne(b->s128, neg1)))) { + t->s128 = int128_divs(a->s128, b->s128); + } else { + t->s128 = a->s128; /* Undefined behavior */ + } +} + +void helper_VDIVUQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + if (int128_nz(b->s128)) { + t->s128 = int128_divu(a->s128, b->s128); + } else { + t->s128 = a->s128; /* Undefined behavior */ + } +} + +void helper_VDIVESD(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + int i; + int64_t high; + uint64_t low; + for (i = 0; i < 2; i++) { + high = a->s64[i]; + low = 0; + if (unlikely((high == INT64_MIN && b->s64[i] == -1) || !b->s64[i])) { + t->s64[i] = a->s64[i]; /* Undefined behavior */ + } else { + divs128(&low, &high, b->s64[i]); + t->s64[i] = low; + } + } +} + +void helper_VDIVEUD(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + int i; + uint64_t high, low; + for (i = 0; i < 2; i++) { + high = a->u64[i]; + low = 0; + if (unlikely(!b->u64[i])) { + t->u64[i] = a->u64[i]; /* Undefined behavior */ + } else { + divu128(&low, &high, b->u64[i]); + t->u64[i] = low; + } + } +} + +void helper_VDIVESQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + Int128 high, low; + Int128 int128_min = int128_make128(0, INT64_MIN); + Int128 neg1 = int128_makes64(-1); + + high = a->s128; + low = int128_zero(); + if (unlikely(!int128_nz(b->s128) || + (int128_eq(b->s128, neg1) && int128_eq(high, int128_min)))) { + t->s128 = a->s128; /* Undefined behavior */ + } else { + divs256(&low, &high, b->s128); + t->s128 = low; + } +} + +void helper_VDIVEUQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + Int128 high, low; + + high = a->s128; + low = int128_zero(); + if (unlikely(!int128_nz(b->s128))) { + t->s128 = a->s128; /* Undefined behavior */ + } else { + divu256(&low, &high, b->s128); + t->s128 = low; + } +} + +void helper_VMODSQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + Int128 neg1 = int128_makes64(-1); + Int128 int128_min = int128_make128(0, INT64_MIN); + if (likely(int128_nz(b->s128) && + (int128_ne(a->s128, int128_min) || int128_ne(b->s128, neg1)))) { + t->s128 = int128_rems(a->s128, b->s128); + } else { + t->s128 = int128_zero(); /* Undefined behavior */ + } +} + +void helper_VMODUQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b) +{ + if (likely(int128_nz(b->s128))) { + t->s128 = int128_remu(a->s128, b->s128); + } else { + t->s128 = int128_zero(); /* Undefined behavior */ + } +} + void helper_VPERM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { ppc_avr_t result; @@ -1177,18 +1374,17 @@ XXGENPCV(XXGENPCVDM, 8) #undef XXGENPCV_LE_COMP #undef XXGENPCV -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)]) #define VBPERMD_INDEX(i) (i) #define VBPERMQ_DW(index) (((index) & 0x40) != 0) -#define EXTRACT_BIT(avr, i, index) (extract64((avr)->u64[i], index, 1)) #else #define VBPERMQ_INDEX(avr, i) ((avr)->u8[15 - (i)]) #define VBPERMD_INDEX(i) (1 - i) #define VBPERMQ_DW(index) (((index) & 0x40) == 0) -#define EXTRACT_BIT(avr, i, index) \ - (extract64((avr)->u64[1 - i], 63 - index, 1)) #endif +#define EXTRACT_BIT(avr, i, index) \ + (extract64((avr)->VsrD(i), 63 - index, 1)) void helper_vbpermd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { @@ -1252,53 +1448,25 @@ PMSUM(vpmsumb, u8, u16, uint16_t) PMSUM(vpmsumh, u16, u32, uint32_t) PMSUM(vpmsumw, u32, u64, uint64_t) -void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_VPMSUMD(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - -#ifdef CONFIG_INT128 int i, j; - __uint128_t prod[2]; - - VECTOR_FOR_INORDER_I(i, u64) { - prod[i] = 0; - for (j = 0; j < 64; j++) { - if (a->u64[i] & (1ull << j)) { - prod[i] ^= (((__uint128_t)b->u64[i]) << j); + Int128 tmp, prod[2] = {int128_zero(), int128_zero()}; + + for (j = 0; j < 64; j++) { + for (i = 0; i < ARRAY_SIZE(r->u64); i++) { + if (a->VsrD(i) & (1ull << j)) { + tmp = int128_make64(b->VsrD(i)); + tmp = int128_lshift(tmp, j); + prod[i] = int128_xor(prod[i], tmp); } } } - r->u128 = prod[0] ^ prod[1]; - -#else - int i, j; - ppc_avr_t prod[2]; - - VECTOR_FOR_INORDER_I(i, u64) { - prod[i].VsrD(1) = prod[i].VsrD(0) = 0; - for (j = 0; j < 64; j++) { - if (a->u64[i] & (1ull << j)) { - ppc_avr_t bshift; - if (j == 0) { - bshift.VsrD(0) = 0; - bshift.VsrD(1) = b->u64[i]; - } else { - bshift.VsrD(0) = b->u64[i] >> (64 - j); - bshift.VsrD(1) = b->u64[i] << j; - } - prod[i].VsrD(1) ^= bshift.VsrD(1); - prod[i].VsrD(0) ^= bshift.VsrD(0); - } - } - } - - r->VsrD(1) = prod[0].VsrD(1) ^ prod[1].VsrD(1); - r->VsrD(0) = prod[0].VsrD(0) ^ prod[1].VsrD(0); -#endif + r->s128 = int128_xor(prod[0], prod[1]); } - -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define PKBIG 1 #else #define PKBIG 0 @@ -1307,7 +1475,7 @@ void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j; ppc_avr_t result; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN const ppc_avr_t *x[2] = { a, b }; #else const ppc_avr_t *x[2] = { b, a }; @@ -1516,7 +1684,7 @@ void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int sh = (b->VsrB(0xf) >> 3) & 0xf; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN memmove(&r->u8[0], &a->u8[sh], 16 - sh); memset(&r->u8[16 - sh], 0, sh); #else @@ -1525,7 +1693,7 @@ void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #endif } -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define ELEM_ADDR(VEC, IDX, SIZE) (&(VEC)->u8[IDX]) #else #define ELEM_ADDR(VEC, IDX, SIZE) (&(VEC)->u8[15 - (IDX)] - (SIZE) + 1) @@ -1554,7 +1722,7 @@ VINSX(W, uint32_t) VINSX(D, uint64_t) #undef ELEM_ADDR #undef VINSX -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define VEXTDVLX(NAME, SIZE) \ void helper_##NAME(CPUPPCState *env, ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, \ target_ulong index) \ @@ -1593,7 +1761,7 @@ VEXTDVLX(VEXTDUHVLX, 2) VEXTDVLX(VEXTDUWVLX, 4) VEXTDVLX(VEXTDDVLX, 8) #undef VEXTDVLX -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define VEXTRACT(suffix, element) \ void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ { \ @@ -1647,8 +1815,7 @@ VSTRI(VSTRIHL, H, 8, true) VSTRI(VSTRIHR, H, 8, false) #undef VSTRI -void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt, - ppc_vsr_t *xb, uint32_t index) +void helper_XXEXTRACTUW(ppc_vsr_t *xt, ppc_vsr_t *xb, uint32_t index) { ppc_vsr_t t = { }; size_t es = sizeof(uint32_t); @@ -1663,8 +1830,7 @@ void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt, *xt = t; } -void helper_xxinsertw(CPUPPCState *env, ppc_vsr_t *xt, - ppc_vsr_t *xb, uint32_t index) +void helper_XXINSERTW(ppc_vsr_t *xt, ppc_vsr_t *xb, uint32_t index) { ppc_vsr_t t = *xt; size_t es = sizeof(uint32_t); @@ -1734,23 +1900,11 @@ XXBLEND(W, 32) XXBLEND(D, 64) #undef XXBLEND -#define VNEG(name, element) \ -void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \ -{ \ - int i; \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - r->element[i] = -b->element[i]; \ - } \ -} -VNEG(vnegw, s32) -VNEG(vnegd, s64) -#undef VNEG - void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int sh = (b->VsrB(0xf) >> 3) & 0xf; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN memmove(&r->u8[sh], &a->u8[0], 16 - sh); memset(&r->u8[0], 0, sh); #else @@ -1759,15 +1913,6 @@ void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #endif } -void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - r->u32[i] = a->u32[i] >= b->u32[i]; - } -} - void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int64_t t; @@ -1867,7 +2012,7 @@ void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define UPKHI 1 #define UPKLO 0 #else @@ -1974,189 +2119,66 @@ VGENERIC_DO(popcntd, u64) #undef VGENERIC_DO -#if defined(HOST_WORDS_BIGENDIAN) -#define QW_ONE { .u64 = { 0, 1 } } -#else -#define QW_ONE { .u64 = { 1, 0 } } -#endif - -#ifndef CONFIG_INT128 - -static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a) -{ - t->u64[0] = ~a.u64[0]; - t->u64[1] = ~a.u64[1]; -} - -static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b) -{ - if (a.VsrD(0) < b.VsrD(0)) { - return -1; - } else if (a.VsrD(0) > b.VsrD(0)) { - return 1; - } else if (a.VsrD(1) < b.VsrD(1)) { - return -1; - } else if (a.VsrD(1) > b.VsrD(1)) { - return 1; - } else { - return 0; - } -} - -static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b) -{ - t->VsrD(1) = a.VsrD(1) + b.VsrD(1); - t->VsrD(0) = a.VsrD(0) + b.VsrD(0) + - (~a.VsrD(1) < b.VsrD(1)); -} - -static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b) +void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - ppc_avr_t not_a; - t->VsrD(1) = a.VsrD(1) + b.VsrD(1); - t->VsrD(0) = a.VsrD(0) + b.VsrD(0) + - (~a.VsrD(1) < b.VsrD(1)); - avr_qw_not(¬_a, a); - return avr_qw_cmpu(not_a, b) < 0; + r->s128 = int128_add(a->s128, b->s128); } -#endif - -void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ -#ifdef CONFIG_INT128 - r->u128 = a->u128 + b->u128; -#else - avr_qw_add(r, *a, *b); -#endif -} - -void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_VADDEUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { -#ifdef CONFIG_INT128 - r->u128 = a->u128 + b->u128 + (c->u128 & 1); -#else - - if (c->VsrD(1) & 1) { - ppc_avr_t tmp; - - tmp.VsrD(0) = 0; - tmp.VsrD(1) = c->VsrD(1) & 1; - avr_qw_add(&tmp, *a, tmp); - avr_qw_add(r, tmp, *b); - } else { - avr_qw_add(r, *a, *b); - } -#endif + r->s128 = int128_add(int128_add(a->s128, b->s128), + int128_make64(int128_getlo(c->s128) & 1)); } -void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_VADDCUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { -#ifdef CONFIG_INT128 - r->u128 = (~a->u128 < b->u128); -#else - ppc_avr_t not_a; - - avr_qw_not(¬_a, *a); - + r->VsrD(1) = int128_ult(int128_not(a->s128), b->s128); r->VsrD(0) = 0; - r->VsrD(1) = (avr_qw_cmpu(not_a, *b) < 0); -#endif } -void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_VADDECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { -#ifdef CONFIG_INT128 - int carry_out = (~a->u128 < b->u128); - if (!carry_out && (c->u128 & 1)) { - carry_out = ((a->u128 + b->u128 + 1) == 0) && - ((a->u128 != 0) || (b->u128 != 0)); - } - r->u128 = carry_out; -#else - - int carry_in = c->VsrD(1) & 1; - int carry_out = 0; - ppc_avr_t tmp; - - carry_out = avr_qw_addc(&tmp, *a, *b); + bool carry_out = int128_ult(int128_not(a->s128), b->s128), + carry_in = int128_getlo(c->s128) & 1; if (!carry_out && carry_in) { - ppc_avr_t one = QW_ONE; - carry_out = avr_qw_addc(&tmp, tmp, one); + carry_out = (int128_nz(a->s128) || int128_nz(b->s128)) && + int128_eq(int128_add(a->s128, b->s128), int128_makes64(-1)); } + r->VsrD(0) = 0; r->VsrD(1) = carry_out; -#endif } -void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_VSUBUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { -#ifdef CONFIG_INT128 - r->u128 = a->u128 - b->u128; -#else - ppc_avr_t tmp; - ppc_avr_t one = QW_ONE; - - avr_qw_not(&tmp, *b); - avr_qw_add(&tmp, *a, tmp); - avr_qw_add(r, tmp, one); -#endif + r->s128 = int128_sub(a->s128, b->s128); } -void helper_vsubeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_VSUBEUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { -#ifdef CONFIG_INT128 - r->u128 = a->u128 + ~b->u128 + (c->u128 & 1); -#else - ppc_avr_t tmp, sum; - - avr_qw_not(&tmp, *b); - avr_qw_add(&sum, *a, tmp); - - tmp.VsrD(0) = 0; - tmp.VsrD(1) = c->VsrD(1) & 1; - avr_qw_add(r, sum, tmp); -#endif + r->s128 = int128_add(int128_add(a->s128, int128_not(b->s128)), + int128_make64(int128_getlo(c->s128) & 1)); } -void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_VSUBCUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { -#ifdef CONFIG_INT128 - r->u128 = (~a->u128 < ~b->u128) || - (a->u128 + ~b->u128 == (__uint128_t)-1); -#else - int carry = (avr_qw_cmpu(*a, *b) > 0); - if (!carry) { - ppc_avr_t tmp; - avr_qw_not(&tmp, *b); - avr_qw_add(&tmp, *a, tmp); - carry = ((tmp.VsrSD(0) == -1ull) && (tmp.VsrSD(1) == -1ull)); - } + Int128 tmp = int128_not(b->s128); + + r->VsrD(1) = int128_ult(int128_not(a->s128), tmp) || + int128_eq(int128_add(a->s128, tmp), int128_makes64(-1)); r->VsrD(0) = 0; - r->VsrD(1) = carry; -#endif } -void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_VSUBECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { -#ifdef CONFIG_INT128 - r->u128 = - (~a->u128 < ~b->u128) || - ((c->u128 & 1) && (a->u128 + ~b->u128 == (__uint128_t)-1)); -#else - int carry_in = c->VsrD(1) & 1; - int carry_out = (avr_qw_cmpu(*a, *b) > 0); - if (!carry_out && carry_in) { - ppc_avr_t tmp; - avr_qw_not(&tmp, *b); - avr_qw_add(&tmp, *a, tmp); - carry_out = ((tmp.VsrD(0) == -1ull) && (tmp.VsrD(1) == -1ull)); - } + Int128 tmp = int128_not(b->s128); + bool carry_out = int128_ult(int128_not(a->s128), tmp), + carry_in = int128_getlo(c->s128) & 1; + r->VsrD(1) = carry_out || (carry_in && int128_eq(int128_add(a->s128, tmp), + int128_makes64(-1))); r->VsrD(0) = 0; - r->VsrD(1) = carry_out; -#endif } #define BCD_PLUS_PREF_1 0xC diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 6aa9484f34a5..337a362205af 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -18,6 +18,8 @@ #ifndef PPC_INTERNAL_H #define PPC_INTERNAL_H +#include "hw/registerfields.h" + #define FUNC_MASK(name, ret_type, size, max_val) \ static inline ret_type name(uint##size##_t start, \ uint##size##_t end) \ @@ -157,15 +159,15 @@ EXTRACT_HELPER(FPL, 25, 1); EXTRACT_HELPER(FPFLM, 17, 8); EXTRACT_HELPER(FPW, 16, 1); -/* mffscrni */ -EXTRACT_HELPER(RM, 11, 2); - /* addpcis */ EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) #if defined(TARGET_PPC64) /* darn */ EXTRACT_HELPER(L, 16, 2); #endif +/* wait */ +EXTRACT_HELPER(WC, 21, 2); +EXTRACT_HELPER(PL, 16, 2); /*** Jump target decoding ***/ /* Immediate address */ @@ -286,9 +288,22 @@ void ppc_cpu_record_sigsegv(CPUState *cs, vaddr addr, bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); -void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); #endif +FIELD(GER_MSK, XMSK, 0, 4) +FIELD(GER_MSK, YMSK, 4, 4) +FIELD(GER_MSK, PMSK, 8, 8) + +static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) +{ + int msk = 0; + msk = FIELD_DP32(msk, GER_MSK, XMSK, xmsk); + msk = FIELD_DP32(msk, GER_MSK, YMSK, ymsk); + msk = FIELD_DP32(msk, GER_MSK, PMSK, pmsk); + return msk; +} + #endif /* PPC_INTERNAL_H */ diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index dc93b99189ea..7c25348b7b24 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -21,7 +21,6 @@ #include -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "cpu.h" @@ -267,7 +266,7 @@ struct ppc_radix_page_info *kvm_get_radix_page_info(void) { KVMState *s = KVM_STATE(current_accel()); struct ppc_radix_page_info *radix_page_info; - struct kvm_ppc_rmmu_info rmmu_info; + struct kvm_ppc_rmmu_info rmmu_info = { }; int i; if (!kvm_check_extension(s, KVM_CAP_PPC_MMU_RADIX)) { @@ -418,7 +417,7 @@ void kvm_check_mmu(PowerPCCPU *cpu, Error **errp) * will be a normal mapping, not a special hugepage one used * for RAM. */ - if (qemu_real_host_page_size < 0x10000) { + if (qemu_real_host_page_size() < 0x10000) { error_setg(errp, "KVM can't supply 64kiB CI pages, which guest expects"); } @@ -543,10 +542,11 @@ static void kvm_get_one_spr(CPUState *cs, uint64_t id, int spr) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + /* Init 'val' to avoid "uninitialised value" Valgrind warnings */ union { uint32_t u32; uint64_t u64; - } val; + } val = { }; struct kvm_one_reg reg = { .id = id, .addr = (uintptr_t) &val, @@ -632,7 +632,7 @@ static int kvm_put_fp(CPUState *cs) uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i); uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN vsr[0] = float64_val(*fpr); vsr[1] = *vsrl; #else @@ -710,7 +710,7 @@ static int kvm_get_fp(CPUState *cs) strerror(errno)); return ret; } else { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN *fpr = vsr[0]; if (vsx) { *vsrl = vsr[1]; @@ -850,7 +850,7 @@ static int kvm_put_vpa(CPUState *cs) int kvmppc_put_books_sregs(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; - struct kvm_sregs sregs; + struct kvm_sregs sregs = { }; int i; sregs.pvr = env->spr[SPR_PVR]; @@ -974,7 +974,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) } #ifdef TARGET_PPC64 - if (msr_ts) { + if (FIELD_EX64(env->msr, MSR, TS)) { for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) { kvm_set_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]); } @@ -1282,7 +1282,7 @@ int kvm_arch_get_registers(CPUState *cs) } #ifdef TARGET_PPC64 - if (msr_ts) { + if (FIELD_EX64(env->msr, MSR, TS)) { for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) { kvm_get_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]); } @@ -1352,7 +1352,8 @@ static int kvmppc_handle_halt(PowerPCCPU *cpu) CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) { + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && + FIELD_EX64(env->msr, MSR, EE)) { cs->halted = 1; cs->exception_index = EXCP_HLT; } @@ -1681,7 +1682,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) break; #if defined(TARGET_PPC64) case KVM_EXIT_PAPR_HCALL: - trace_kvm_handle_papr_hcall(); + trace_kvm_handle_papr_hcall(run->papr_hcall.nr); run->papr_hcall.ret = spapr_hypercall(cpu, run->papr_hcall.nr, run->papr_hcall.args); @@ -1876,6 +1877,12 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) buf[0] = '\0'; while ((dirp = readdir(dp)) != NULL) { FILE *f; + + /* Don't accidentally read from the current and parent directories */ + if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) { + continue; + } + snprintf(buf, buf_len, "%s%s/clock-frequency", PROC_DEVTREE_CPU, dirp->d_name); f = fopen(buf, "r"); @@ -2537,7 +2544,7 @@ int kvmppc_get_cap_large_decr(void) int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable) { CPUState *cs = CPU(cpu); - uint64_t lpcr; + uint64_t lpcr = 0; kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr); /* Do we need to modify the LPCR? */ @@ -2959,3 +2966,7 @@ bool kvm_arch_cpu_check_are_resettable(void) { return true; } + +void kvm_arch_accel_class_init(ObjectClass *oc) +{ +} diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index ee9325bf9ae6..5fd9753953cb 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -9,6 +9,9 @@ #ifndef KVM_PPC_H #define KVM_PPC_H +#include "exec/hwaddr.h" +#include "cpu.h" + #define TYPE_HOST_POWERPC_CPU POWERPC_CPU_TYPE_NAME("host") #ifdef CONFIG_KVM diff --git a/target/ppc/machine.c b/target/ppc/machine.c index e67394459792..be6eb3d96843 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -157,7 +157,8 @@ static int cpu_pre_save(void *opaque) | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 - | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM; + | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM + | PPC2_MEM_LWSYNC; env->spr[SPR_LR] = env->lr; env->spr[SPR_CTR] = env->ctr; @@ -233,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) @@ -417,7 +418,7 @@ static bool tm_needed(void *opaque) { PowerPCCPU *cpu = opaque; CPUPPCState *env = &cpu->env; - return msr_ts; + return FIELD_EX64(env->msr, MSR, TS); } static const VMStateDescription vmstate_tm = { diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 39945d9ea585..d1163f316cad 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -32,10 +32,10 @@ static inline bool needs_byteswap(const CPUPPCState *env) { -#if defined(TARGET_WORDS_BIGENDIAN) - return msr_le; +#if TARGET_BIG_ENDIAN + return FIELD_EX64(env->msr, MSR, LE); #else - return !msr_le; + return !FIELD_EX64(env->msr, MSR, LE); #endif } @@ -461,7 +461,7 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, /*****************************************************************************/ /* Altivec extension helpers */ -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN #define HI_IDX 0 #define LO_IDX 1 #else @@ -470,8 +470,8 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, #endif /* - * We use msr_le to determine index ordering in a vector. However, - * byteswapping is not simply controlled by msr_le. We also need to + * We use MSR_LE to determine index ordering in a vector. However, + * byteswapping is not simply controlled by MSR_LE. We also need to * take into account endianness of the target. This is done for the * little-endian PPC64 user-mode target. */ @@ -484,7 +484,7 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - if (msr_le) { \ + if (FIELD_EX64(env->msr, MSR, LE)) { \ index = n_elems - index - 1; \ } \ \ @@ -511,7 +511,7 @@ LVE(lvewx, cpu_ldl_data_ra, bswap32, u32) int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - if (msr_le) { \ + if (FIELD_EX64(env->msr, MSR, LE)) { \ index = n_elems - index - 1; \ } \ \ @@ -545,7 +545,7 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \ t.s128 = int128_zero(); \ if (nb) { \ nb = (nb >= 16) ? 16 : nb; \ - if (msr_le && !lj) { \ + if (FIELD_EX64(env->msr, MSR, LE) && !lj) { \ for (i = 16; i > 16 - nb; i--) { \ t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \ addr = addr_add(env, addr, 1); \ @@ -576,7 +576,7 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \ } \ \ nb = (nb >= 16) ? 16 : nb; \ - if (msr_le && !lj) { \ + if (FIELD_EX64(env->msr, MSR, LE) && !lj) { \ for (i = 16; i > 16 - nb; i--) { \ cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \ addr = addr_add(env, addr, 1); \ @@ -612,11 +612,12 @@ void helper_tbegin(CPUPPCState *env) env->spr[SPR_TEXASR] = (1ULL << TEXASR_FAILURE_PERSISTENT) | (1ULL << TEXASR_NESTING_OVERFLOW) | - (msr_hv << TEXASR_PRIVILEGE_HV) | - (msr_pr << TEXASR_PRIVILEGE_PR) | + (FIELD_EX64_HV(env->msr) << TEXASR_PRIVILEGE_HV) | + (FIELD_EX64(env->msr, MSR, PR) << TEXASR_PRIVILEGE_PR) | (1ULL << TEXASR_FAILURE_SUMMARY) | (1ULL << TEXASR_TFIAR_EXACT); - env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr; + env->spr[SPR_TFIAR] = env->nip | (FIELD_EX64_HV(env->msr) << 1) | + FIELD_EX64(env->msr, MSR, PR); env->spr[SPR_TFHAR] = env->nip + 4; env->crf[0] = 0xB; /* 0b1010 = transaction failure */ } diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 06aa716cab7a..a9bc1522e24e 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -25,6 +25,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "mmu-book3s-v3.h" +#include "hw/ppc/ppc.h" #include "helper_regs.h" @@ -73,7 +74,7 @@ void helper_hfscr_facility_check(CPUPPCState *env, uint32_t bit, const char *caller, uint32_t cause) { #ifdef TARGET_PPC64 - if ((env->msr_mask & MSR_HVB) && !msr_hv && + if ((env->msr_mask & MSR_HVB) && !FIELD_EX64(env->msr, MSR, HV) && !(env->spr[SPR_HFSCR] & (1UL << bit))) { raise_hv_fu_exception(env, bit, caller, cause, GETPC()); } @@ -163,7 +164,7 @@ target_ulong helper_load_dpdes(CPUPPCState *env) helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP); /* TODO: TCG supports only one thread */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { dpdes = 1; } @@ -173,7 +174,6 @@ target_ulong helper_load_dpdes(CPUPPCState *env) void helper_store_dpdes(CPUPPCState *env, target_ulong val) { PowerPCCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP); @@ -184,12 +184,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val) return; } - if (val & 0x1) { - env->pending_interrupts |= 1 << PPC_INTERRUPT_DOORBELL; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); - } + ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1); } #endif /* defined(TARGET_PPC64) */ diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c index f4985bae7881..c8f69b3df9b1 100644 --- a/target/ppc/mmu-book3s-v3.c +++ b/target/ppc/mmu-book3s-v3.c @@ -28,6 +28,11 @@ bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry) uint64_t patb = cpu->env.spr[SPR_PTCR] & PTCR_PATB; uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS; + /* Check if partition table is properly aligned */ + if (patb & MAKE_64BIT_MASK(0, pats + 12)) { + return false; + } + /* Calculate number of entries */ pats = 1ull << (pats + 12 - 4); if (pats <= lpid) { diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h index d6d5ed8f8ed4..674377a19e08 100644 --- a/target/ppc/mmu-book3s-v3.h +++ b/target/ppc/mmu-book3s-v3.h @@ -50,6 +50,21 @@ struct prtb_entry { #ifdef TARGET_PPC64 +/* + * tlbie[l] helper flags + * + * RIC, PRS, R and local are passed as flags in the last argument. + */ +#define TLBIE_F_RIC_SHIFT 0 +#define TLBIE_F_PRS_SHIFT 2 +#define TLBIE_F_R_SHIFT 3 +#define TLBIE_F_LOCAL_SHIFT 4 + +#define TLBIE_F_RIC_MASK (3 << TLBIE_F_RIC_SHIFT) +#define TLBIE_F_PRS (1 << TLBIE_F_PRS_SHIFT) +#define TLBIE_F_R (1 << TLBIE_F_R_SHIFT) +#define TLBIE_F_LOCAL (1 << TLBIE_F_LOCAL_SHIFT) + static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu) { return !!(cpu->env.spr[SPR_LPCR] & LPCR_UPRT); diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index da9fe99ff8bd..b9b31fd27637 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -101,7 +101,7 @@ void dump_slb(PowerPCCPU *cpu) } #ifdef CONFIG_TCG -void helper_slbia(CPUPPCState *env, uint32_t ih) +void helper_SLBIA(CPUPPCState *env, uint32_t ih) { PowerPCCPU *cpu = env_archcpu(env); int starting_entry; @@ -173,6 +173,33 @@ void helper_slbia(CPUPPCState *env, uint32_t ih) } } +#if defined(TARGET_PPC64) +void helper_SLBIAG(CPUPPCState *env, target_ulong rs, uint32_t l) +{ + PowerPCCPU *cpu = env_archcpu(env); + int n; + + /* + * slbiag must always flush all TLB (which is equivalent to ERAT in ppc + * architecture). Matching on SLB_ESID_V is not good enough, because slbmte + * can overwrite a valid SLB without flushing its lookaside information. + * + * It would be possible to keep the TLB in synch with the SLB by flushing + * when a valid entry is overwritten by slbmte, and therefore slbiag would + * not have to flush unless it evicts a valid SLB entry. However it is + * expected that slbmte is more common than slbiag, and slbiag is usually + * going to evict valid SLB entries, so that tradeoff is unlikely to be a + * good one. + */ + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; + + for (n = 0; n < cpu->hash64_opts->slb_size; n++) { + ppc_slb_t *slb = &env->slb[n]; + slb->esid &= ~SLB_ESID_V; + } +} +#endif + static void __helper_slbie(CPUPPCState *env, target_ulong addr, target_ulong global) { @@ -197,12 +224,12 @@ static void __helper_slbie(CPUPPCState *env, target_ulong addr, } } -void helper_slbie(CPUPPCState *env, target_ulong addr) +void helper_SLBIE(CPUPPCState *env, target_ulong addr) { __helper_slbie(env, addr, false); } -void helper_slbieg(CPUPPCState *env, target_ulong addr) +void helper_SLBIEG(CPUPPCState *env, target_ulong addr) { __helper_slbie(env, addr, true); } @@ -309,7 +336,7 @@ static int ppc_find_slb_vsid(PowerPCCPU *cpu, target_ulong rb, return 0; } -void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) +void helper_SLBMTE(CPUPPCState *env, target_ulong rb, target_ulong rs) { PowerPCCPU *cpu = env_archcpu(env); @@ -319,7 +346,7 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) } } -target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) +target_ulong helper_SLBMFEE(CPUPPCState *env, target_ulong rb) { PowerPCCPU *cpu = env_archcpu(env); target_ulong rt = 0; @@ -331,7 +358,7 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) return rt; } -target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb) +target_ulong helper_SLBFEE(CPUPPCState *env, target_ulong rb) { PowerPCCPU *cpu = env_archcpu(env); target_ulong rt = 0; @@ -343,7 +370,7 @@ target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb) return rt; } -target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) +target_ulong helper_SLBMFEV(CPUPPCState *env, target_ulong rb) { PowerPCCPU *cpu = env_archcpu(env); target_ulong rt = 0; diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 5414fd63c10f..031efda0df6a 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -37,7 +37,7 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env, return false; } - if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */ + if (FIELD_EX64(env->msr, MSR, HV)) { /* MSR[HV] -> Hypervisor/bare metal */ switch (eaddr & R_EADDR_QUADRANT) { case R_EADDR_QUADRANT0: *lpid = 0; @@ -191,12 +191,13 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type, } /* Determine permissions allowed by Encoded Access Authority */ - if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) { + if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && + FIELD_EX64(env->msr, MSR, PR)) { *prot = 0; } else if (mmuidx_pr(mmu_idx) || (pte & R_PTE_EAA_PRIV) || partition_scoped) { *prot = ppc_radix64_get_prot_eaa(pte); - } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */ + } else { /* !MSR_PR && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */ *prot = ppc_radix64_get_prot_eaa(pte); *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */ } @@ -235,16 +236,47 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type, } } +static bool ppc_radix64_is_valid_level(int level, int psize, uint64_t nls) +{ + bool ret; + + /* + * Check if this is a valid level, according to POWER9 and POWER10 + * Processor User's Manuals, sections 4.10.4.1 and 5.10.6.1, respectively: + * Supported Radix Tree Configurations and Resulting Page Sizes. + * + * Note: these checks are specific to POWER9 and POWER10 CPUs. Any future + * CPUs that supports a different Radix MMU configuration will need their + * own implementation. + */ + switch (level) { + case 0: /* Root Page Dir */ + ret = psize == 52 && nls == 13; + break; + case 1: + case 2: + ret = nls == 9; + break; + case 3: + ret = nls == 9 || nls == 5; + break; + default: + ret = false; + } + + if (unlikely(!ret)) { + qemu_log_mask(LOG_GUEST_ERROR, "invalid radix configuration: " + "level %d size %d nls %"PRIu64"\n", + level, psize, nls); + } + return ret; +} + static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr, uint64_t *pte_addr, uint64_t *nls, int *psize, uint64_t *pte, int *fault_cause) { - uint64_t index, pde; - - if (*nls < 5) { /* Directory maps less than 2**5 entries */ - *fault_cause |= DSISR_R_BADCONFIG; - return 1; - } + uint64_t index, mask, nlb, pde; /* Read page entry from guest address space */ pde = ldq_phys(as, *pte_addr); @@ -259,7 +291,17 @@ static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr, *nls = pde & R_PDE_NLS; index = eaddr >> (*psize - *nls); /* Shift */ index &= ((1UL << *nls) - 1); /* Mask */ - *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde)); + nlb = pde & R_PDE_NLB; + mask = MAKE_64BIT_MASK(0, *nls + 3); + + if (nlb & mask) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: misaligned page dir/table base: 0x"TARGET_FMT_lx + " page dir size: 0x"TARGET_FMT_lx"\n", + __func__, nlb, mask + 1); + nlb &= ~mask; + } + *pte_addr = nlb + index * sizeof(pde); } return 0; } @@ -269,19 +311,30 @@ static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr, hwaddr *raddr, int *psize, uint64_t *pte, int *fault_cause, hwaddr *pte_addr) { - uint64_t index, pde, rpn , mask; + uint64_t index, pde, rpn, mask; + int level = 0; - if (nls < 5) { /* Directory maps less than 2**5 entries */ - *fault_cause |= DSISR_R_BADCONFIG; - return 1; + index = eaddr >> (*psize - nls); /* Shift */ + index &= ((1UL << nls) - 1); /* Mask */ + mask = MAKE_64BIT_MASK(0, nls + 3); + + if (base_addr & mask) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: misaligned page dir base: 0x"TARGET_FMT_lx + " page dir size: 0x"TARGET_FMT_lx"\n", + __func__, base_addr, mask + 1); + base_addr &= ~mask; } + *pte_addr = base_addr + index * sizeof(pde); - index = eaddr >> (*psize - nls); /* Shift */ - index &= ((1UL << nls) - 1); /* Mask */ - *pte_addr = base_addr + (index * sizeof(pde)); do { int ret; + if (!ppc_radix64_is_valid_level(level++, *psize, nls)) { + *fault_cause |= DSISR_R_BADCONFIG; + return 1; + } + ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde, fault_cause); if (ret) { @@ -305,7 +358,7 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) if (!(pate->dw0 & PATE0_HR)) { return false; } - if (lpid == 0 && !msr_hv) { + if (lpid == 0 && !FIELD_EX64(env->msr, MSR, HV)) { return false; } if ((pate->dw0 & PATE1_R_PRTS) < 5) { @@ -382,7 +435,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte; + uint64_t offset, size, prtb, prtbe_addr, prtbe0, base_addr, nls, index, pte; int fault_cause = 0, h_page_size, h_prot; hwaddr h_raddr, pte_addr; int ret; @@ -392,9 +445,18 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, __func__, access_str(access_type), eaddr, mmu_idx, pid); + prtb = (pate.dw1 & PATE1_R_PRTB); + size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); + if (prtb & (size - 1)) { + /* Process Table not properly aligned */ + if (guest_visible) { + ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG); + } + return 1; + } + /* Index Process Table by PID to Find Corresponding Process Table Entry */ offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); if (offset >= size) { /* offset exceeds size of the process table */ if (guest_visible) { @@ -402,7 +464,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, } return 1; } - prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset; + prtbe_addr = prtb + offset; if (vhyp_flat_addressing(cpu)) { prtbe0 = ldq_phys(cs->as, prtbe_addr); @@ -430,7 +492,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, *g_page_size = PRTBE_R_GET_RTS(prtbe0); base_addr = prtbe0 & PRTBE_R_RPDB; nls = prtbe0 & PRTBE_R_RPDS; - if (msr_hv || vhyp_flat_addressing(cpu)) { + if (FIELD_EX64(env->msr, MSR, HV) || vhyp_flat_addressing(cpu)) { /* * Can treat process table addresses as real addresses */ @@ -446,6 +508,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, } } else { uint64_t rpn, mask; + int level = 0; index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */ index &= ((1UL << nls) - 1); /* Mask */ @@ -465,8 +528,15 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, return ret; } - ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr, - &nls, g_page_size, &pte, &fault_cause); + if (!ppc_radix64_is_valid_level(level++, *g_page_size, nls)) { + fault_cause |= DSISR_R_BADCONFIG; + ret = 1; + } else { + ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, + &h_raddr, &nls, g_page_size, + &pte, &fault_cause); + } + if (ret) { /* No valid pte */ if (guest_visible) { @@ -567,7 +637,7 @@ static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr, return false; } - /* Get Process Table */ + /* Get Partition Table */ if (cpu->vhyp) { PPCVirtualHypervisorClass *vhc; vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index e9c5b14c0f48..8901f4d134db 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -273,8 +273,8 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, bl = (*BATu & 0x00001FFC) << 15; valid = 0; prot = 0; - if (((msr_pr == 0) && (*BATu & 0x00000002)) || - ((msr_pr != 0) && (*BATu & 0x00000001))) { + if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) || + (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) { valid = 1; pp = *BATl & 0x00000003; if (pp != 0) { @@ -368,16 +368,17 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, PowerPCCPU *cpu = env_archcpu(env); hwaddr hash; target_ulong vsid; - int ds, pr, target_page_bits; + int ds, target_page_bits; + bool pr; int ret; target_ulong sr, pgidx; - pr = msr_pr; + pr = FIELD_EX64(env->msr, MSR, PR); ctx->eaddr = eaddr; sr = env->sr[eaddr >> 28]; - ctx->key = (((sr & 0x20000000) && (pr != 0)) || - ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; + ctx->key = (((sr & 0x20000000) && pr) || + ((sr & 0x40000000) && !pr)) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; @@ -386,8 +387,9 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx " ir=%d dr=%d pr=%d %d t=%d\n", - eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, - (int)msr_dr, pr != 0 ? 1 : 0, + eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, + (int)FIELD_EX64(env->msr, MSR, IR), + (int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0, access_type == MMU_DATA_STORE, type); pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; hash = vsid ^ pgidx; @@ -530,7 +532,7 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, ret = -1; raddr = (hwaddr)-1ULL; - pr = msr_pr; + pr = FIELD_EX64(env->msr, MSR, PR); for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, @@ -618,14 +620,16 @@ static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, found_tlb: - if (msr_pr != 0) { + if (FIELD_EX64(env->msr, MSR, PR)) { prot2 = tlb->prot & 0xF; } else { prot2 = (tlb->prot >> 4) & 0xF; } /* Check the address space */ - if ((access_type == MMU_INST_FETCH ? msr_ir : msr_dr) != (tlb->attr & 1)) { + if ((access_type == MMU_INST_FETCH ? + FIELD_EX64(env->msr, MSR, IR) : + FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) { qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__); return -1; } @@ -691,7 +695,7 @@ int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr mask; uint32_t tlb_pid; - if (!msr_cm) { + if (!FIELD_EX64(env->msr, MSR, CM)) { /* In 32bit mode we can only address 32bit EAs */ address = (uint32_t)address; } @@ -767,8 +771,8 @@ static bool mmubooke206_get_as(CPUPPCState *env, *pr_out = !!(epidr & EPID_EPR); return true; } else { - *as_out = msr_ds; - *pr_out = msr_pr; + *as_out = FIELD_EX64(env->msr, MSR, DS); + *pr_out = FIELD_EX64(env->msr, MSR, PR); return false; } } @@ -807,7 +811,8 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, } } - qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__); + qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address " + "0x" TARGET_FMT_lx "\n", __func__, address); return -1; found_tlb: @@ -838,7 +843,7 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, if (access_type == MMU_INST_FETCH) { /* There is no way to fetch code using epid load */ assert(!use_epid); - as = msr_ir; + as = FIELD_EX64(env->msr, MSR, IR); } if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { @@ -975,7 +980,7 @@ static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset, pa = entry->mas7_3 & ~(size - 1); qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c" - "U%c%c%c %c%c%c%c%c U%c%c%c%c\n", + " U%c%c%c %c%c%c%c%c U%c%c%c%c\n", (uint64_t)ea, (uint64_t)pa, book3e_tsize_to_str[tsize], (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT, @@ -1168,8 +1173,8 @@ int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx, int mmu_idx) { int ret = -1; - bool real_mode = (type == ACCESS_CODE && msr_ir == 0) - || (type != ACCESS_CODE && msr_dr == 0); + bool real_mode = (type == ACCESS_CODE && !FIELD_EX64(env->msr, MSR, IR)) || + (type != ACCESS_CODE && !FIELD_EX64(env->msr, MSR, DR)); switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: @@ -1230,7 +1235,7 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); if (access_type == MMU_INST_FETCH) { - as = msr_ir; + as = FIELD_EX64(env->msr, MSR, IR); } env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 142a717255c4..2a91f3f46af1 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -429,6 +429,160 @@ void helper_tlbie(CPUPPCState *env, target_ulong addr) ppc_tlb_invalidate_one(env, addr); } +#if defined(TARGET_PPC64) + +/* Invalidation Selector */ +#define TLBIE_IS_VA 0 +#define TLBIE_IS_PID 1 +#define TLBIE_IS_LPID 2 +#define TLBIE_IS_ALL 3 + +/* Radix Invalidation Control */ +#define TLBIE_RIC_TLB 0 +#define TLBIE_RIC_PWC 1 +#define TLBIE_RIC_ALL 2 +#define TLBIE_RIC_GRP 3 + +/* Radix Actual Page sizes */ +#define TLBIE_R_AP_4K 0 +#define TLBIE_R_AP_64K 5 +#define TLBIE_R_AP_2M 1 +#define TLBIE_R_AP_1G 2 + +/* RB field masks */ +#define TLBIE_RB_EPN_MASK PPC_BITMASK(0, 51) +#define TLBIE_RB_IS_MASK PPC_BITMASK(52, 53) +#define TLBIE_RB_AP_MASK PPC_BITMASK(56, 58) + +void helper_tlbie_isa300(CPUPPCState *env, target_ulong rb, target_ulong rs, + uint32_t flags) +{ + unsigned ric = (flags & TLBIE_F_RIC_MASK) >> TLBIE_F_RIC_SHIFT; + /* + * With the exception of the checks for invalid instruction forms, + * PRS is currently ignored, because we don't know if a given TLB entry + * is process or partition scoped. + */ + bool prs = flags & TLBIE_F_PRS; + bool r = flags & TLBIE_F_R; + bool local = flags & TLBIE_F_LOCAL; + bool effR; + unsigned is = extract64(rb, PPC_BIT_NR(53), 2); + unsigned ap; /* actual page size */ + target_ulong addr, pgoffs_mask; + + qemu_log_mask(CPU_LOG_MMU, + "%s: local=%d addr=" TARGET_FMT_lx " ric=%u prs=%d r=%d is=%u\n", + __func__, local, rb & TARGET_PAGE_MASK, ric, prs, r, is); + + effR = FIELD_EX64(env->msr, MSR, HV) ? r : env->spr[SPR_LPCR] & LPCR_HR; + + /* Partial TLB invalidation is supported for Radix only for now. */ + if (!effR) { + goto inval_all; + } + + /* Check for invalid instruction forms (effR=1). */ + if (unlikely(ric == TLBIE_RIC_GRP || + ((ric == TLBIE_RIC_PWC || ric == TLBIE_RIC_ALL) && + is == TLBIE_IS_VA) || + (!prs && is == TLBIE_IS_PID))) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid instruction form: ric=%u prs=%d r=%d is=%u\n", + __func__, ric, prs, r, is); + goto invalid; + } + + /* We don't cache Page Walks. */ + if (ric == TLBIE_RIC_PWC) { + if (local) { + unsigned set = extract64(rb, PPC_BIT_NR(51), 12); + if (set != 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid set: %d\n", + __func__, set); + goto invalid; + } + } + return; + } + + /* + * Invalidation by LPID or PID is not supported, so fallback + * to full TLB flush in these cases. + */ + if (is != TLBIE_IS_VA) { + goto inval_all; + } + + /* + * The results of an attempt to invalidate a translation outside of + * quadrant 0 for Radix Tree translation (effR=1, RIC=0, PRS=1, IS=0, + * and EA 0:1 != 0b00) are boundedly undefined. + */ + if (unlikely(ric == TLBIE_RIC_TLB && prs && is == TLBIE_IS_VA && + (rb & R_EADDR_QUADRANT) != R_EADDR_QUADRANT0)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: attempt to invalidate a translation outside of quadrant 0\n", + __func__); + goto inval_all; + } + + assert(is == TLBIE_IS_VA); + assert(ric == TLBIE_RIC_TLB || ric == TLBIE_RIC_ALL); + + ap = extract64(rb, PPC_BIT_NR(58), 3); + switch (ap) { + case TLBIE_R_AP_4K: + pgoffs_mask = 0xfffull; + break; + + case TLBIE_R_AP_64K: + pgoffs_mask = 0xffffull; + break; + + case TLBIE_R_AP_2M: + pgoffs_mask = 0x1fffffull; + break; + + case TLBIE_R_AP_1G: + pgoffs_mask = 0x3fffffffull; + break; + + default: + /* + * If the value specified in RS 0:31, RS 32:63, RB 54:55, RB 56:58, + * RB 44:51, or RB 56:63, when it is needed to perform the specified + * operation, is not supported by the implementation, the instruction + * is treated as if the instruction form were invalid. + */ + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid AP: %d\n", __func__, ap); + goto invalid; + } + + addr = rb & TLBIE_RB_EPN_MASK & ~pgoffs_mask; + + if (local) { + tlb_flush_page(env_cpu(env), addr); + } else { + tlb_flush_page_all_cpus(env_cpu(env), addr); + } + return; + +inval_all: + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; + if (!local) { + env->tlb_need_flush |= TLB_NEED_GLOBAL_FLUSH; + } + return; + +invalid: + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL, GETPC()); +} + +#endif + void helper_tlbiva(CPUPPCState *env, target_ulong addr) { /* tlbiva instruction only exists on BookE */ @@ -935,7 +1089,7 @@ void helper_booke206_tlbwe(CPUPPCState *env) } if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && - !msr_gs) { + !FIELD_EX64(env->msr, MSR, GS)) { /* XXX we don't support direct LRAT setting yet */ fprintf(stderr, "cpu: don't support LRAT setting yet\n"); return; @@ -962,7 +1116,7 @@ void helper_booke206_tlbwe(CPUPPCState *env) POWERPC_EXCP_INVAL_INVAL, GETPC()); } - if (msr_gs) { + if (FIELD_EX64(env->msr, MSR, GS)) { cpu_abort(env_cpu(env), "missing HV implementation\n"); } @@ -1003,7 +1157,7 @@ void helper_booke206_tlbwe(CPUPPCState *env) /* Add a mask for page attributes */ mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E; - if (!msr_cm) { + if (!FIELD_EX64(env->msr, MSR, CM)) { /* * Executing a tlbwe instruction in 32-bit mode will set bits * 0:31 of the TLB EPN field to zero. diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c index 0b805ef6e927..8250b1304e6b 100644 --- a/target/ppc/monitor.c +++ b/target/ppc/monitor.c @@ -55,6 +55,9 @@ static target_long monitor_get_decr(Monitor *mon, const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(mon); + if (!env->tb_env) { + return 0; + } return cpu_ppc_load_decr(env); } @@ -62,6 +65,9 @@ static target_long monitor_get_tbu(Monitor *mon, const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(mon); + if (!env->tb_env) { + return 0; + } return cpu_ppc_load_tbu(env); } @@ -69,6 +75,9 @@ static target_long monitor_get_tbl(Monitor *mon, const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(mon); + if (!env->tb_env) { + return 0; + } return cpu_ppc_load_tbl(env); } diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc index 2bab6cece709..c3cc919ee41d 100644 --- a/target/ppc/power8-pmu-regs.c.inc +++ b/target/ppc/power8-pmu-regs.c.inc @@ -22,7 +22,7 @@ static bool spr_groupA_read_allowed(DisasContext *ctx) { if (!ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) { - gen_hvpriv_exception(ctx, POWERPC_EXCP_FU); + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU); return false; } @@ -46,10 +46,10 @@ static bool spr_groupA_write_allowed(DisasContext *ctx) if (ctx->mmcr0_pmcc1) { /* PMCC = 0b01 */ - gen_hvpriv_exception(ctx, POWERPC_EXCP_FU); + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU); } else { /* PMCC = 0b00 */ - gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG); } return false; @@ -214,7 +214,7 @@ void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn) * Interrupt. */ if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) { - gen_hvpriv_exception(ctx, POWERPC_EXCP_FU); + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU); return; } @@ -249,7 +249,7 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn) * Interrupt. */ if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) { - gen_hvpriv_exception(ctx, POWERPC_EXCP_FU); + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU); return; } diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c index beeab5c494e1..1381072b9e54 100644 --- a/target/ppc/power8-pmu.c +++ b/target/ppc/power8-pmu.c @@ -22,8 +22,6 @@ #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL - static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn) { if (sprn == SPR_POWER_PMC1) { @@ -88,49 +86,47 @@ static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns) bool overflow_triggered = false; target_ulong tmp; - if (unlikely(ins_cnt & 0x1e)) { - if (ins_cnt & (1 << 1)) { - tmp = env->spr[SPR_POWER_PMC1]; - tmp += num_insns; - if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) { - tmp = PMC_COUNTER_NEGATIVE_VAL; - overflow_triggered = true; - } - env->spr[SPR_POWER_PMC1] = tmp; + if (ins_cnt & (1 << 1)) { + tmp = env->spr[SPR_POWER_PMC1]; + tmp += num_insns; + if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) { + tmp = PMC_COUNTER_NEGATIVE_VAL; + overflow_triggered = true; } + env->spr[SPR_POWER_PMC1] = tmp; + } - if (ins_cnt & (1 << 2)) { - tmp = env->spr[SPR_POWER_PMC2]; - tmp += num_insns; - if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { - tmp = PMC_COUNTER_NEGATIVE_VAL; - overflow_triggered = true; - } - env->spr[SPR_POWER_PMC2] = tmp; + if (ins_cnt & (1 << 2)) { + tmp = env->spr[SPR_POWER_PMC2]; + tmp += num_insns; + if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { + tmp = PMC_COUNTER_NEGATIVE_VAL; + overflow_triggered = true; + } + env->spr[SPR_POWER_PMC2] = tmp; + } + + if (ins_cnt & (1 << 3)) { + tmp = env->spr[SPR_POWER_PMC3]; + tmp += num_insns; + if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { + tmp = PMC_COUNTER_NEGATIVE_VAL; + overflow_triggered = true; } + env->spr[SPR_POWER_PMC3] = tmp; + } - if (ins_cnt & (1 << 3)) { - tmp = env->spr[SPR_POWER_PMC3]; + if (ins_cnt & (1 << 4)) { + target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1]; + int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE); + if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) { + tmp = env->spr[SPR_POWER_PMC4]; tmp += num_insns; if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { tmp = PMC_COUNTER_NEGATIVE_VAL; overflow_triggered = true; } - env->spr[SPR_POWER_PMC3] = tmp; - } - - if (ins_cnt & (1 << 4)) { - target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1]; - int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE); - if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) { - tmp = env->spr[SPR_POWER_PMC4]; - tmp += num_insns; - if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { - tmp = PMC_COUNTER_NEGATIVE_VAL; - overflow_triggered = true; - } - env->spr[SPR_POWER_PMC4] = tmp; - } + env->spr[SPR_POWER_PMC4] = tmp; } } @@ -310,6 +306,12 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu) raise_ebb_perfm_exception(env); } +void helper_handle_pmc5_overflow(CPUPPCState *env) +{ + env->spr[SPR_POWER_PMC5] = PMC_COUNTER_NEGATIVE_VAL; + fire_PMC_interrupt(env_archcpu(env)); +} + /* This helper assumes that the PMC is running. */ void helper_insns_inc(CPUPPCState *env, uint32_t num_insns) { diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h index 256d90f523c9..c0093e221911 100644 --- a/target/ppc/power8-pmu.h +++ b/target/ppc/power8-pmu.h @@ -10,10 +10,13 @@ * See the COPYING file in the top-level directory. */ -#ifndef POWER8_PMU -#define POWER8_PMU +#ifndef POWER8_PMU_H +#define POWER8_PMU_H #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + +#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL + void cpu_ppc_pmu_init(CPUPPCState *env); void pmu_update_summaries(CPUPPCState *env); #else diff --git a/target/ppc/spr_common.h b/target/ppc/spr_common.h index b5a5bc68952e..8437eb03401c 100644 --- a/target/ppc/spr_common.h +++ b/target/ppc/spr_common.h @@ -195,6 +195,7 @@ void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn); void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn); void spr_write_hmer(DisasContext *ctx, int sprn, int gprn); void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn); +void spr_read_dexcr_ureg(DisasContext *ctx, int gprn, int sprn); #endif void register_low_BATs(CPUPPCState *env); diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c index 86d01d6e4e7a..b80f56af7e40 100644 --- a/target/ppc/timebase_helper.c +++ b/target/ppc/timebase_helper.c @@ -143,7 +143,6 @@ void helper_store_booke_tsr(CPUPPCState *env, target_ulong val) { store_booke_tsr(env, val); } -#endif /*****************************************************************************/ /* Embedded PowerPC specific helpers */ @@ -169,7 +168,7 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn) (uint32_t)dcrn, (uint32_t)dcrn); raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | - POWERPC_EXCP_PRIV_REG, GETPC()); + POWERPC_EXCP_INVAL_INVAL, GETPC()); } } return val; @@ -192,7 +191,8 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val) (uint32_t)dcrn, (uint32_t)dcrn); raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | - POWERPC_EXCP_PRIV_REG, GETPC()); + POWERPC_EXCP_INVAL_INVAL, GETPC()); } } } +#endif diff --git a/target/ppc/trace-events b/target/ppc/trace-events index 53b107f56eb6..a79f1b437072 100644 --- a/target/ppc/trace-events +++ b/target/ppc/trace-events @@ -23,7 +23,7 @@ kvm_failed_get_vpa(void) "Warning: Unable to get VPA information from KVM" kvm_handle_dcr_write(void) "handle dcr write" kvm_handle_dcr_read(void) "handle dcr read" kvm_handle_halt(void) "handle halt" -kvm_handle_papr_hcall(void) "handle PAPR hypercall" +kvm_handle_papr_hcall(uint64_t hcall) "0x%" PRIx64 kvm_handle_epr(void) "handle epr" kvm_handle_watchdog_expiry(void) "handle watchdog expiry" kvm_handle_debug_exception(void) "handle debug exception" diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 408ae26173de..edb3daa9b503 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -36,6 +36,7 @@ #include "exec/log.h" #include "qemu/atomic128.h" #include "spr_common.h" +#include "power8-pmu.h" #include "qemu/qemu-print.h" #include "qapi/error.h" @@ -177,6 +178,8 @@ struct DisasContext { bool hr; bool mmcr0_pmcc0; bool mmcr0_pmcc1; + bool mmcr0_pmcjce; + bool pmc_other; bool pmu_insn_cnt; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; @@ -193,7 +196,7 @@ struct DisasContext { /* Return true iff byteswap is needed in a scalar memop */ static inline bool need_byteswap(const DisasContext *ctx) { -#if defined(TARGET_WORDS_BIGENDIAN) +#if TARGET_BIG_ENDIAN return ctx->le_mode; #else return !ctx->le_mode; @@ -305,6 +308,14 @@ static void gen_icount_io_start(DisasContext *ctx) } } +#if !defined(CONFIG_USER_ONLY) +static void gen_ppc_maybe_interrupt(DisasContext *ctx) +{ + gen_icount_io_start(ctx); + gen_helper_ppc_maybe_interrupt(cpu_env); +} +#endif + /* * Tells the caller what is the appropriate exception to generate and prepares * SPR registers for this exception. @@ -907,9 +918,9 @@ void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn) } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) { sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38; } else { - printf("Trying to write an unknown exception vector %d %03x\n", - sprn, sprn); - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + qemu_log_mask(LOG_GUEST_ERROR, "Trying to write an unknown exception" + " vector 0x%03x\n", sprn); + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); return; } @@ -1238,6 +1249,25 @@ void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn) gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); spr_write_prev_upper32(ctx, sprn, gprn); } + +void spr_read_dexcr_ureg(DisasContext *ctx, int gprn, int sprn) +{ + TCGv t0 = tcg_temp_new(); + + /* + * Access to the (H)DEXCR in problem state is done using separated + * SPR indexes which are 16 below the SPR indexes which have full + * access to the (H)DEXCR in privileged state. Problem state can + * only read bits 32:63, bits 0:31 return 0. + * + * See section 9.3.1-9.3.2 of PowerISA v3.1B + */ + + gen_load_spr(t0, sprn + 16); + tcg_gen_ext32u_tl(cpu_gpr[gprn], t0); + + tcg_temp_free(t0); +} #endif #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ @@ -1267,38 +1297,43 @@ typedef struct opcode_t { const char *oname; } opcode_t; +static void gen_priv_opc(DisasContext *ctx) +{ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); +} + /* Helpers for priv. check */ -#define GEN_PRIV \ - do { \ - gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; \ +#define GEN_PRIV(CTX) \ + do { \ + gen_priv_opc(CTX); return; \ } while (0) #if defined(CONFIG_USER_ONLY) -#define CHK_HV GEN_PRIV -#define CHK_SV GEN_PRIV -#define CHK_HVRM GEN_PRIV +#define CHK_HV(CTX) GEN_PRIV(CTX) +#define CHK_SV(CTX) GEN_PRIV(CTX) +#define CHK_HVRM(CTX) GEN_PRIV(CTX) #else -#define CHK_HV \ - do { \ - if (unlikely(ctx->pr || !ctx->hv)) { \ - GEN_PRIV; \ - } \ +#define CHK_HV(CTX) \ + do { \ + if (unlikely(ctx->pr || !ctx->hv)) {\ + GEN_PRIV(CTX); \ + } \ } while (0) -#define CHK_SV \ +#define CHK_SV(CTX) \ do { \ if (unlikely(ctx->pr)) { \ - GEN_PRIV; \ + GEN_PRIV(CTX); \ } \ } while (0) -#define CHK_HVRM \ - do { \ - if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) { \ - GEN_PRIV; \ - } \ +#define CHK_HVRM(CTX) \ + do { \ + if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) { \ + GEN_PRIV(CTX); \ + } \ } while (0) #endif -#define CHK_NONE +#define CHK_NONE(CTX) /*****************************************************************************/ /* PowerPC instructions table */ @@ -3252,7 +3287,7 @@ GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_UQ)) static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ - chk; \ + chk(ctx); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ @@ -3270,7 +3305,7 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ static void glue(gen_, name##epx)(DisasContext *ctx) \ { \ TCGv EA; \ - CHK_SV; \ + CHK_SV(ctx); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ @@ -3298,7 +3333,7 @@ GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ - chk; \ + chk(ctx); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ @@ -3315,7 +3350,7 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ static void glue(gen_, name##epx)(DisasContext *ctx) \ { \ TCGv EA; \ - CHK_SV; \ + CHK_SV(ctx); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ @@ -3513,7 +3548,32 @@ static void gen_stswx(DisasContext *ctx) /* eieio */ static void gen_eieio(DisasContext *ctx) { - TCGBar bar = TCG_MO_LD_ST; + TCGBar bar = TCG_MO_ALL; + + /* + * eieio has complex semanitcs. It provides memory ordering between + * operations in the set: + * - loads from CI memory. + * - stores to CI memory. + * - stores to WT memory. + * + * It separately also orders memory for operations in the set: + * - stores to cacheble memory. + * + * It also serializes instructions: + * - dcbt and dcbst. + * + * It separately serializes: + * - tlbie and tlbsync. + * + * And separately serializes: + * - slbieg, slbiag, and slbsync. + * + * The end result is that CI memory ordering requires TCG_MO_ALL + * and it is not possible to special-case more relaxed ordering for + * cacheable accesses. TCG_BAR_SC is required to provide this + * serialization. + */ /* * POWER9 has a eieio instruction variant using bit 6 as a hint to @@ -4016,8 +4076,13 @@ static void gen_stqcx_(DisasContext *ctx) /* sync */ static void gen_sync(DisasContext *ctx) { + TCGBar bar = TCG_MO_ALL; uint32_t l = (ctx->opcode >> 21) & 3; + if ((l == 1) && (ctx->insns_flags2 & PPC2_MEM_LWSYNC)) { + bar = TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST; + } + /* * We may need to check for a pending TLB flush. * @@ -4029,29 +4094,109 @@ static void gen_sync(DisasContext *ctx) if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) { gen_check_tlb_flush(ctx, true); } - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); + + tcg_gen_mb(bar | TCG_BAR_SC); } /* 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) static void gen_doze(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv_i32 t; - CHK_HV; + CHK_HV(ctx); t = tcg_const_i32(PPC_PM_DOZE); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); @@ -4063,11 +4208,11 @@ static void gen_doze(DisasContext *ctx) static void gen_nap(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv_i32 t; - CHK_HV; + CHK_HV(ctx); t = tcg_const_i32(PPC_PM_NAP); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); @@ -4079,11 +4224,11 @@ static void gen_nap(DisasContext *ctx) static void gen_stop(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv_i32 t; - CHK_HV; + CHK_HV(ctx); t = tcg_const_i32(PPC_PM_STOP); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); @@ -4095,11 +4240,11 @@ static void gen_stop(DisasContext *ctx) static void gen_sleep(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv_i32 t; - CHK_HV; + CHK_HV(ctx); t = tcg_const_i32(PPC_PM_SLEEP); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); @@ -4111,11 +4256,11 @@ static void gen_sleep(DisasContext *ctx) static void gen_rvwinkle(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv_i32 t; - CHK_HV; + CHK_HV(ctx); t = tcg_const_i32(PPC_PM_RVWINKLE); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); @@ -4146,6 +4291,9 @@ static void pmu_count_insns(DisasContext *ctx) } #if !defined(CONFIG_USER_ONLY) + TCGLabel *l; + TCGv t0; + /* * The PMU insns_inc() helper stops the internal PMU timer if a * counter overflows happens. In that case, if the guest is @@ -4154,8 +4302,26 @@ static void pmu_count_insns(DisasContext *ctx) */ gen_icount_io_start(ctx); - gen_helper_insns_inc(cpu_env, tcg_constant_i32(ctx->base.num_insns)); -#else + /* Avoid helper calls when only PMC5-6 are enabled. */ + if (!ctx->pmc_other) { + l = gen_new_label(); + t0 = tcg_temp_new(); + + gen_load_spr(t0, SPR_POWER_PMC5); + tcg_gen_addi_tl(t0, t0, ctx->base.num_insns); + gen_store_spr(SPR_POWER_PMC5, t0); + /* Check for overflow, if it's enabled */ + if (ctx->mmcr0_pmcjce) { + tcg_gen_brcondi_tl(TCG_COND_LT, t0, PMC_COUNTER_NEGATIVE_VAL, l); + gen_helper_handle_pmc5_overflow(cpu_env); + } + + gen_set_label(l); + tcg_temp_free(t0); + } else { + gen_helper_insns_inc(cpu_env, tcg_constant_i32(ctx->base.num_insns)); + } + #else /* * User mode can read (but not write) PMC5 and start/stop * the PMU via MMCR0_FC. In this case just increment @@ -4168,7 +4334,7 @@ static void pmu_count_insns(DisasContext *ctx) gen_store_spr(SPR_POWER_PMC5, t0); tcg_temp_free(t0); -#endif /* #if !defined(CONFIG_USER_ONLY) */ + #endif /* #if !defined(CONFIG_USER_ONLY) */ } #else static void pmu_count_insns(DisasContext *ctx) @@ -4445,7 +4611,7 @@ static void gen_mcrf(DisasContext *ctx) static void gen_rfi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else /* * This instruction doesn't exist anymore on 64-bit server @@ -4456,7 +4622,7 @@ static void gen_rfi(DisasContext *ctx) return; } /* Restore CPU state */ - CHK_SV; + CHK_SV(ctx); gen_icount_io_start(ctx); gen_update_cfar(ctx, ctx->cia); gen_helper_rfi(cpu_env); @@ -4468,10 +4634,10 @@ static void gen_rfi(DisasContext *ctx) static void gen_rfid(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else /* Restore CPU state */ - CHK_SV; + CHK_SV(ctx); gen_icount_io_start(ctx); gen_update_cfar(ctx, ctx->cia); gen_helper_rfid(cpu_env); @@ -4483,10 +4649,10 @@ static void gen_rfid(DisasContext *ctx) static void gen_rfscv(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else /* Restore CPU state */ - CHK_SV; + CHK_SV(ctx); gen_icount_io_start(ctx); gen_update_cfar(ctx, ctx->cia); gen_helper_rfscv(cpu_env); @@ -4498,10 +4664,10 @@ static void gen_rfscv(DisasContext *ctx) static void gen_hrfid(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else /* Restore CPU state */ - CHK_HV; + CHK_HV(ctx); gen_helper_hrfid(cpu_env); ctx->base.is_jmp = DISAS_EXIT; #endif @@ -4702,7 +4868,7 @@ static void gen_mfcr(DisasContext *ctx) /* mfmsr */ static void gen_mfmsr(DisasContext *ctx) { - CHK_SV; + CHK_SV(ctx); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr); } @@ -4758,11 +4924,11 @@ static inline void gen_op_mfspr(DisasContext *ctx) */ if (sprn & 0x10) { if (ctx->pr) { - gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { if (ctx->pr || sprn == 0 || sprn == 4 || sprn == 5 || sprn == 6) { - gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } } @@ -4816,7 +4982,7 @@ static void gen_mtmsrd(DisasContext *ctx) return; } - CHK_SV; + CHK_SV(ctx); #if !defined(CONFIG_USER_ONLY) TCGv t0, t1; @@ -4859,7 +5025,7 @@ static void gen_mtmsrd(DisasContext *ctx) static void gen_mtmsr(DisasContext *ctx) { - CHK_SV; + CHK_SV(ctx); #if !defined(CONFIG_USER_ONLY) TCGv t0, t1; @@ -4945,11 +5111,11 @@ static void gen_mtspr(DisasContext *ctx) */ if (sprn & 0x10) { if (ctx->pr) { - gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { if (ctx->pr || sprn == 0) { - gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } } @@ -4991,7 +5157,7 @@ static void gen_dcbfep(DisasContext *ctx) { /* XXX: specification says this is treated as a load by the MMU */ TCGv t0; - CHK_SV; + CHK_SV(ctx); gen_set_access_type(ctx, ACCESS_CACHE); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); @@ -5003,11 +5169,11 @@ static void gen_dcbfep(DisasContext *ctx) static void gen_dcbi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv EA, val; - CHK_SV; + CHK_SV(ctx); EA = tcg_temp_new(); gen_set_access_type(ctx, ACCESS_CACHE); gen_addr_reg_index(ctx, EA); @@ -5192,11 +5358,11 @@ static void gen_dcba(DisasContext *ctx) static void gen_mfsr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); @@ -5207,11 +5373,11 @@ static void gen_mfsr(DisasContext *ctx) static void gen_mfsrin(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); @@ -5223,11 +5389,11 @@ static void gen_mfsrin(DisasContext *ctx) static void gen_mtsr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); @@ -5238,10 +5404,10 @@ static void gen_mtsr(DisasContext *ctx) static void gen_mtsrin(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); @@ -5257,11 +5423,11 @@ static void gen_mtsrin(DisasContext *ctx) static void gen_mfsr_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); @@ -5272,11 +5438,11 @@ static void gen_mfsr_64b(DisasContext *ctx) static void gen_mfsrin_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); @@ -5288,11 +5454,11 @@ static void gen_mfsrin_64b(DisasContext *ctx) static void gen_mtsr_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); @@ -5303,11 +5469,11 @@ static void gen_mtsr_64b(DisasContext *ctx) static void gen_mtsrin_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_extract_tl(t0, cpu_gpr[rB(ctx->opcode)], 28, 4); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); @@ -5315,67 +5481,6 @@ static void gen_mtsrin_64b(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } -/* slbmte */ -static void gen_slbmte(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - - gen_helper_store_slb(cpu_env, cpu_gpr[rB(ctx->opcode)], - cpu_gpr[rS(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_slbmfee(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - - gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], cpu_env, - cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_slbmfev(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - - gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env, - cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_slbfee_(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); -#else - TCGLabel *l1, *l2; - - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } - gen_helper_find_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env, - cpu_gpr[rB(ctx->opcode)]); - l1 = gen_new_label(); - l2 = gen_new_label(); - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rS(ctx->opcode)], -1, l1); - tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_movi_tl(cpu_gpr[rS(ctx->opcode)], 0); - gen_set_label(l2); -#endif -} #endif /* defined(TARGET_PPC64) */ /*** Lookaside buffer management ***/ @@ -5385,83 +5490,25 @@ static void gen_slbfee_(DisasContext *ctx) static void gen_tlbia(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_HV; + CHK_HV(ctx); gen_helper_tlbia(cpu_env); #endif /* defined(CONFIG_USER_ONLY) */ } -/* tlbiel */ -static void gen_tlbiel(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - bool psr = (ctx->opcode >> 17) & 0x1; - - if (ctx->pr || (!ctx->hv && !psr && ctx->hr)) { - /* - * tlbiel is privileged except when PSR=0 and HR=1, making it - * hypervisor privileged. - */ - GEN_PRIV; - } - - gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -/* tlbie */ -static void gen_tlbie(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - bool psr = (ctx->opcode >> 17) & 0x1; - TCGv_i32 t1; - - if (ctx->pr) { - /* tlbie is privileged... */ - GEN_PRIV; - } else if (!ctx->hv) { - if (!ctx->gtse || (!psr && ctx->hr)) { - /* - * ... except when GTSE=0 or when PSR=0 and HR=1, making it - * hypervisor privileged. - */ - GEN_PRIV; - } - } - - if (NARROW_MODE(ctx)) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); - gen_helper_tlbie(cpu_env, t0); - tcg_temp_free(t0); - } else { - gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); - } - t1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); - tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); - tcg_gen_st_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); - tcg_temp_free_i32(t1); -#endif /* defined(CONFIG_USER_ONLY) */ -} - /* tlbsync */ static void gen_tlbsync(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else if (ctx->gtse) { - CHK_SV; /* If gtse is set then tlbsync is supervisor privileged */ + CHK_SV(ctx); /* If gtse is set then tlbsync is supervisor privileged */ } else { - CHK_HV; /* Else hypervisor privileged */ + CHK_HV(ctx); /* Else hypervisor privileged */ } /* BookS does both ptesync and tlbsync make tlbsync a nop for server */ @@ -5471,60 +5518,6 @@ static void gen_tlbsync(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } -#if defined(TARGET_PPC64) -/* slbia */ -static void gen_slbia(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - uint32_t ih = (ctx->opcode >> 21) & 0x7; - TCGv_i32 t0 = tcg_const_i32(ih); - - CHK_SV; - - gen_helper_slbia(cpu_env, t0); - tcg_temp_free_i32(t0); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -/* slbie */ -static void gen_slbie(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - - gen_helper_slbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -/* slbieg */ -static void gen_slbieg(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - - gen_helper_slbieg(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -/* slbsync */ -static void gen_slbsync(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - gen_check_tlb_flush(ctx, true); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -#endif /* defined(TARGET_PPC64) */ - /*** External control ***/ /* Optional: */ @@ -5560,9 +5553,9 @@ static void gen_ecowx(DisasContext *ctx) static void gen_tlbld_6xx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); gen_helper_6xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5571,9 +5564,9 @@ static void gen_tlbld_6xx(DisasContext *ctx) static void gen_tlbli_6xx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); gen_helper_6xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -5591,11 +5584,11 @@ static void gen_mfapidi(DisasContext *ctx) static void gen_tlbiva(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_tlbiva(cpu_env, cpu_gpr[rB(ctx->opcode)]); @@ -5822,11 +5815,11 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); static void gen_mfdcr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv dcrn; - CHK_SV; + CHK_SV(ctx); dcrn = tcg_const_tl(SPR(ctx->opcode)); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn); tcg_temp_free(dcrn); @@ -5837,11 +5830,11 @@ static void gen_mfdcr(DisasContext *ctx) static void gen_mtdcr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv dcrn; - CHK_SV; + CHK_SV(ctx); dcrn = tcg_const_tl(SPR(ctx->opcode)); gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(dcrn); @@ -5853,9 +5846,9 @@ static void gen_mtdcr(DisasContext *ctx) static void gen_mfdcrx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ @@ -5867,35 +5860,19 @@ static void gen_mfdcrx(DisasContext *ctx) static void gen_mtdcrx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif /* defined(CONFIG_USER_ONLY) */ } -/* mfdcrux (PPC 460) : user-mode access to DCR */ -static void gen_mfdcrux(DisasContext *ctx) -{ - gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, - cpu_gpr[rA(ctx->opcode)]); - /* Note: Rc update flag set leads to undefined state of Rc0 */ -} - -/* mtdcrux (PPC 460) : user-mode access to DCR */ -static void gen_mtdcrux(DisasContext *ctx) -{ - gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], - cpu_gpr[rS(ctx->opcode)]); - /* Note: Rc update flag set leads to undefined state of Rc0 */ -} - /* dccci */ static void gen_dccci(DisasContext *ctx) { - CHK_SV; + CHK_SV(ctx); /* interpreted as no-op */ } @@ -5903,11 +5880,11 @@ static void gen_dccci(DisasContext *ctx) static void gen_dcread(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv EA, val; - CHK_SV; + CHK_SV(ctx); gen_set_access_type(ctx, ACCESS_CACHE); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -5932,14 +5909,14 @@ static void gen_icbt_40x(DisasContext *ctx) /* iccci */ static void gen_iccci(DisasContext *ctx) { - CHK_SV; + CHK_SV(ctx); /* interpreted as no-op */ } /* icread */ static void gen_icread(DisasContext *ctx) { - CHK_SV; + CHK_SV(ctx); /* interpreted as no-op */ } @@ -5947,9 +5924,9 @@ static void gen_icread(DisasContext *ctx) static void gen_rfci_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); /* Restore CPU state */ gen_helper_40x_rfci(cpu_env); ctx->base.is_jmp = DISAS_EXIT; @@ -5959,9 +5936,9 @@ static void gen_rfci_40x(DisasContext *ctx) static void gen_rfci(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); /* Restore CPU state */ gen_helper_rfci(cpu_env); ctx->base.is_jmp = DISAS_EXIT; @@ -5974,9 +5951,9 @@ static void gen_rfci(DisasContext *ctx) static void gen_rfdi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); /* Restore CPU state */ gen_helper_rfdi(cpu_env); ctx->base.is_jmp = DISAS_EXIT; @@ -5987,9 +5964,9 @@ static void gen_rfdi(DisasContext *ctx) static void gen_rfmci(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); /* Restore CPU state */ gen_helper_rfmci(cpu_env); ctx->base.is_jmp = DISAS_EXIT; @@ -6002,9 +5979,9 @@ static void gen_rfmci(DisasContext *ctx) static void gen_tlbre_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); switch (rB(ctx->opcode)) { case 0: gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_env, @@ -6025,11 +6002,11 @@ static void gen_tlbre_40x(DisasContext *ctx) static void gen_tlbsx_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); @@ -6048,9 +6025,9 @@ static void gen_tlbsx_40x(DisasContext *ctx) static void gen_tlbwe_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); switch (rB(ctx->opcode)) { case 0: @@ -6074,9 +6051,9 @@ static void gen_tlbwe_40x(DisasContext *ctx) static void gen_tlbre_440(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); switch (rB(ctx->opcode)) { case 0: @@ -6100,11 +6077,11 @@ static void gen_tlbre_440(DisasContext *ctx) static void gen_tlbsx_440(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); @@ -6123,9 +6100,9 @@ static void gen_tlbsx_440(DisasContext *ctx) static void gen_tlbwe_440(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); switch (rB(ctx->opcode)) { case 0: case 1: @@ -6150,9 +6127,9 @@ static void gen_tlbwe_440(DisasContext *ctx) static void gen_tlbre_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); gen_helper_booke206_tlbre(cpu_env); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6161,11 +6138,11 @@ static void gen_tlbre_booke206(DisasContext *ctx) static void gen_tlbsx_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); if (rA(ctx->opcode)) { t0 = tcg_temp_new(); tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]); @@ -6183,9 +6160,9 @@ static void gen_tlbsx_booke206(DisasContext *ctx) static void gen_tlbwe_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); gen_helper_booke206_tlbwe(cpu_env); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6193,11 +6170,11 @@ static void gen_tlbwe_booke206(DisasContext *ctx) static void gen_tlbivax_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_booke206_tlbivax(cpu_env, t0); @@ -6208,11 +6185,11 @@ static void gen_tlbivax_booke206(DisasContext *ctx) static void gen_tlbilx_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); @@ -6235,20 +6212,20 @@ static void gen_tlbilx_booke206(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } - /* wrtee */ static void gen_wrtee(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else TCGv t0; - CHK_SV; + CHK_SV(ctx); t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE)); tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE)); tcg_gen_or_tl(cpu_msr, cpu_msr, t0); + gen_ppc_maybe_interrupt(ctx); tcg_temp_free(t0); /* * Stop translation to have a chance to raise an exception if we @@ -6262,11 +6239,12 @@ static void gen_wrtee(DisasContext *ctx) static void gen_wrteei(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - GEN_PRIV; + GEN_PRIV(ctx); #else - CHK_SV; + CHK_SV(ctx); if (ctx->opcode & 0x00008000) { tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE)); + gen_ppc_maybe_interrupt(ctx); /* Stop translation to have a chance to raise an exception */ ctx->base.is_jmp = DISAS_EXIT_UPDATE; } else { @@ -6313,68 +6291,6 @@ static void gen_icbt_440(DisasContext *ctx) */ } -/* Embedded.Processor Control */ - -static void gen_msgclr(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_HV; - if (is_book3s_arch2x(ctx)) { - gen_helper_book3s_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); - } else { - gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); - } -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_msgsnd(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_HV; - if (is_book3s_arch2x(ctx)) { - gen_helper_book3s_msgsnd(cpu_gpr[rB(ctx->opcode)]); - } else { - gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); - } -#endif /* defined(CONFIG_USER_ONLY) */ -} - -#if defined(TARGET_PPC64) -static void gen_msgclrp(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_msgsndp(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} -#endif - -static void gen_msgsync(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_HV; -#endif /* defined(CONFIG_USER_ONLY) */ - /* interpreted as no-op */ -} - #if defined(TARGET_PPC64) static void gen_maddld(DisasContext *ctx) { @@ -6481,7 +6397,7 @@ static void gen_tcheck(DisasContext *ctx) #define GEN_TM_PRIV_NOOP(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ + gen_priv_opc(ctx); \ } #else @@ -6489,7 +6405,7 @@ static inline void gen_##name(DisasContext *ctx) \ #define GEN_TM_PRIV_NOOP(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - CHK_SV; \ + CHK_SV(ctx); \ if (unlikely(!ctx->tm_enabled)) { \ gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \ return; \ @@ -6517,6 +6433,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) @@ -6547,6 +6471,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 @@ -6597,6 +6526,27 @@ static int times_16(DisasContext *ctx, int x) } \ } while (0) +#if !defined(CONFIG_USER_ONLY) +#define REQUIRE_SV(CTX) \ + do { \ + if (unlikely((CTX)->pr)) { \ + gen_priv_opc(CTX); \ + return true; \ + } \ + } while (0) + +#define REQUIRE_HV(CTX) \ + do { \ + if (unlikely((CTX)->pr || !(CTX)->hv)) { \ + gen_priv_opc(CTX); \ + return true; \ + } \ + } while (0) +#else +#define REQUIRE_SV(CTX) do { gen_priv_opc(CTX); return true; } while (0) +#define REQUIRE_HV(CTX) do { gen_priv_opc(CTX); return true; } while (0) +#endif + /* * Helpers for implementing sets of trans_* functions. * Defer the implementation of NAME to FUNC, with optional extra arguments. @@ -6668,6 +6618,10 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) #include "translate/branch-impl.c.inc" +#include "translate/processor-ctrl-impl.c.inc" + +#include "translate/storage-ctrl-impl.c.inc" + /* Handles lfdp */ static void gen_dform39(DisasContext *ctx) { @@ -6821,8 +6775,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), @@ -6896,27 +6851,13 @@ GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001, GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B), GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B), -GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x001F0001, PPC_SEGMENT_64B), -GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B), -GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B), -GEN_HANDLER2(slbfee_, "slbfee.", 0x1F, 0x13, 0x1E, 0x001F0000, PPC_SEGMENT_64B), #endif GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), /* * XXX Those instructions will need to be handled differently for * different ISA versions */ -GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x001F0001, PPC_MEM_TLBIE), -GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE), -GEN_HANDLER_E(tlbiel, 0x1F, 0x12, 0x08, 0x00100001, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E(tlbie, 0x1F, 0x12, 0x09, 0x00100001, PPC_NONE, PPC2_ISA300), GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC), -#if defined(TARGET_PPC64) -GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x031FFC01, PPC_SLBI), -GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI), -GEN_HANDLER_E(slbieg, 0x1F, 0x12, 0x0E, 0x001F0001, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E(slbsync, 0x1F, 0x12, 0x0A, 0x03FFF801, PPC_NONE, PPC2_ISA300), -#endif GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN), GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN), GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB), @@ -6927,8 +6868,6 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR), GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR), GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX), GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX), -GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX), -GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX), GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON), GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON), GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT), @@ -6954,12 +6893,6 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, PPC_NONE, PPC2_BOOKE206), -GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001, - PPC_NONE, PPC2_PRCNTL), -GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, - PPC_NONE, PPC2_PRCNTL), -GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x00000000, - PPC_NONE, PPC2_PRCNTL), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), @@ -6974,15 +6907,10 @@ GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC), GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC), -GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC), #if defined(TARGET_PPC64) GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), -GEN_HANDLER2_E(msgsndp, "msgsndp", 0x1F, 0x0E, 0x04, 0x03ff0001, - PPC_NONE, PPC2_ISA207S), -GEN_HANDLER2_E(msgclrp, "msgclrp", 0x1F, 0x0E, 0x05, 0x03ff0001, - PPC_NONE, PPC2_ISA207S), #endif #undef GEN_INT_ARITH_ADD @@ -7627,6 +7555,8 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->hr = (hflags >> HFLAGS_HR) & 1; ctx->mmcr0_pmcc0 = (hflags >> HFLAGS_PMCC0) & 1; ctx->mmcr0_pmcc1 = (hflags >> HFLAGS_PMCC1) & 1; + ctx->mmcr0_pmcjce = (hflags >> HFLAGS_PMCJCE) & 1; + ctx->pmc_other = (hflags >> HFLAGS_PMC_OTHER) & 1; ctx->pmu_insn_cnt = (hflags >> HFLAGS_INSN_CNT) & 1; ctx->singlestep_enabled = 0; @@ -7769,10 +7699,11 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void ppc_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void ppc_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps ppc_tr_ops = { @@ -7784,15 +7715,10 @@ 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); -} - -void restore_state_to_opc(CPUPPCState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->nip = data[0]; + translator_loop(cs, tb, max_insns, pc, host_pc, &ppc_tr_ops, &ctx.base); } diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 1aab32be0364..1ba56cbed59c 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -79,11 +79,8 @@ static bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed) REQUIRE_INSNS_FLAGS(ctx, 64BX); if (!prefixed && !(ctx->insns_flags2 & PPC2_LSQ_ISA207)) { - if (ctx->pr) { - /* lq and stq were privileged prior to V. 2.07 */ - gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return true; - } + /* lq and stq were privileged prior to V. 2.07 */ + REQUIRE_SV(ctx); if (ctx->le_mode) { gen_align_no_le(ctx); @@ -492,3 +489,88 @@ static bool trans_PEXTD(DisasContext *ctx, arg_X *a) #endif return true; } + +static bool trans_ADDG6S(DisasContext *ctx, arg_X *a) +{ + const uint64_t carry_bits = 0x1111111111111111ULL; + TCGv t0, t1, carry, zero = tcg_constant_tl(0); + + REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); + + t0 = tcg_temp_new(); + t1 = tcg_const_tl(0); + carry = tcg_const_tl(0); + + for (int i = 0; i < 16; i++) { + tcg_gen_shri_tl(t0, cpu_gpr[a->ra], i * 4); + tcg_gen_andi_tl(t0, t0, 0xf); + tcg_gen_add_tl(t1, t1, t0); + + tcg_gen_shri_tl(t0, cpu_gpr[a->rb], i * 4); + tcg_gen_andi_tl(t0, t0, 0xf); + tcg_gen_add_tl(t1, t1, t0); + + tcg_gen_andi_tl(t1, t1, 0x10); + tcg_gen_setcond_tl(TCG_COND_NE, t1, t1, zero); + + tcg_gen_shli_tl(t0, t1, i * 4); + tcg_gen_or_tl(carry, carry, t0); + } + + tcg_gen_xori_tl(carry, carry, (target_long)carry_bits); + tcg_gen_muli_tl(cpu_gpr[a->rt], carry, 6); + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(carry); + + return true; +} + +static bool trans_CDTBCD(DisasContext *ctx, arg_X_sa *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); + gen_helper_CDTBCD(cpu_gpr[a->ra], cpu_gpr[a->rs]); + return true; +} + +static bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); + 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 cfb27bd02040..8d5cf0f982de 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -222,57 +222,67 @@ static void gen_frsqrtes(DisasContext *ctx) tcg_temp_free_i64(t1); } -/* fsel */ -_GEN_FLOAT_ACB(sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL); -/* fsub - fsubs */ -GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); -/* Optional: */ - -/* fsqrt */ -static void gen_fsqrt(DisasContext *ctx) +static bool trans_FSEL(DisasContext *ctx, arg_A *a) { - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1, t2; + + REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSEL); + 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); - gen_compute_fprf_float64(t1); - if (unlikely(Rc(ctx->opcode) != 0)) { + t2 = tcg_temp_new_i64(); + + get_fpr(t0, a->fra); + get_fpr(t1, a->frb); + get_fpr(t2, a->frc); + + gen_helper_FSEL(t0, t0, t1, t2); + set_fpr(a->frt, t0); + if (a->rc) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + + return true; } -static void gen_fsqrts(DisasContext *ctx) +/* fsub - fsubs */ +GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); +/* Optional: */ + +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_fsqrts(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; } +TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); +TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); + /*** Floating-Point multiply-and-add ***/ /* fmadd - fmadds */ GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT); @@ -589,141 +599,162 @@ static void gen_mcrfs(DisasContext *ctx) tcg_temp_free_i64(tnew_fpscr); } -/* mffs */ -static void gen_mffs(DisasContext *ctx) +static TCGv_i64 place_from_fpscr(int rt, uint64_t mask) { - TCGv_i64 t0; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); + TCGv_i64 fpscr = tcg_temp_new_i64(); + TCGv_i64 fpscr_masked = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(fpscr, cpu_fpscr); + tcg_gen_andi_i64(fpscr_masked, fpscr, mask); + set_fpr(rt, fpscr_masked); + + tcg_temp_free_i64(fpscr_masked); + + return fpscr; +} + +static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask, + TCGv_i64 set_mask, uint32_t store_mask) +{ + TCGv_i64 fpscr_masked = tcg_temp_new_i64(); + TCGv_i32 st_mask = tcg_constant_i32(store_mask); + + tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask); + tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask); + gen_helper_store_fpscr(cpu_env, fpscr_masked, st_mask); + + tcg_temp_free_i64(fpscr_masked); +} + +static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a) +{ + TCGv_i64 fpscr; + + REQUIRE_FPU(ctx); + gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - set_fpr(rD(ctx->opcode), t0); - if (unlikely(Rc(ctx->opcode))) { + fpscr = place_from_fpscr(a->rt, UINT64_MAX); + if (a->rc) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); + + tcg_temp_free_i64(fpscr); + + return true; } -/* mffsl */ -static void gen_mffsl(DisasContext *ctx) +static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a) { - TCGv_i64 t0; + TCGv_i64 fpscr; - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_FPU(ctx); - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - /* Mask everything except mode, status, and enables. */ - tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN); - set_fpr(rD(ctx->opcode), t0); - tcg_temp_free_i64(t0); + fpscr = place_from_fpscr(a->rt, UINT64_MAX); + store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003); + + tcg_temp_free_i64(fpscr); + + return true; } -/* mffsce */ -static void gen_mffsce(DisasContext *ctx) +static bool trans_MFFSCRN(DisasContext *ctx, arg_X_tb *a) { - TCGv_i64 t0; - TCGv_i32 mask; + TCGv_i64 t1, fpscr; - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_FPU(ctx); - t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + get_fpr(t1, a->rb); + tcg_gen_andi_i64(t1, t1, FP_RN); gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - set_fpr(rD(ctx->opcode), t0); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_RN, t1, 0x0001); - /* Clear exception enable bits in the FPSCR. */ - tcg_gen_andi_i64(t0, t0, ~FP_ENABLES); - mask = tcg_const_i32(0x0003); - gen_helper_store_fpscr(cpu_env, t0, mask); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(fpscr); - tcg_temp_free_i32(mask); - tcg_temp_free_i64(t0); + return true; } -static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1) +static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *a) { - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i32 mask = tcg_const_i32(0x0001); + TCGv_i64 t1, fpscr; - gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN); - set_fpr(rD(ctx->opcode), t0); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_FPU(ctx); - /* Mask FPSCR value to clear RN. */ - tcg_gen_andi_i64(t0, t0, ~FP_RN); + t1 = tcg_temp_new_i64(); + get_fpr(t1, a->rb); + tcg_gen_andi_i64(t1, t1, FP_DRN); - /* Merge RN into FPSCR value. */ - tcg_gen_or_i64(t0, t0, t1); + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100); - gen_helper_store_fpscr(cpu_env, t0, mask); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(fpscr); - tcg_temp_free_i32(mask); - tcg_temp_free_i64(t0); + return true; } -/* mffscrn */ -static void gen_mffscrn(DisasContext *ctx) +static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a) { - TCGv_i64 t1; - - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } + TCGv_i64 t1, fpscr; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_FPU(ctx); t1 = tcg_temp_new_i64(); - get_fpr(t1, rB(ctx->opcode)); - /* Mask FRB to get just RN. */ - tcg_gen_andi_i64(t1, t1, FP_RN); + tcg_gen_movi_i64(t1, a->imm); - gen_helper_mffscrn(ctx, t1); + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_RN, t1, 0x0001); tcg_temp_free_i64(t1); + tcg_temp_free_i64(fpscr); + + return true; } -/* mffscrni */ -static void gen_mffscrni(DisasContext *ctx) +static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a) { - TCGv_i64 t1; + TCGv_i64 t1, fpscr; - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_FPU(ctx); - t1 = tcg_const_i64((uint64_t)RM(ctx->opcode)); + t1 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0); - gen_helper_mffscrn(ctx, t1); + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100); tcg_temp_free_i64(t1); + tcg_temp_free_i64(fpscr); + + return true; +} + +static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a) +{ + TCGv_i64 fpscr; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_FPU(ctx); + + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, + FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN); + + tcg_temp_free_i64(fpscr); + + return true; } /* mtfsb0 */ @@ -854,7 +885,7 @@ static void gen_lfdepx(DisasContext *ctx) { TCGv EA; TCGv_i64 t0; - CHK_SV; + CHK_SV(ctx); if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; @@ -1011,7 +1042,7 @@ static void gen_stfdepx(DisasContext *ctx) { TCGv EA; TCGv_i64 t0; - CHK_SV; + CHK_SV(ctx); if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc index 4260635a126d..d4c6c4bed13e 100644 --- a/target/ppc/translate/fp-ops.c.inc +++ b/target/ppc/translate/fp-ops.c.inc @@ -24,7 +24,6 @@ GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT), GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT), GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES), GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE), -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL), GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT), GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT), GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT), @@ -63,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), @@ -75,15 +72,6 @@ GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), -GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), -GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT, - PPC2_ISA300), -GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, - PPC2_ISA300), -GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT, - PPC_NONE), -GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT, - PPC_NONE), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc b/target/ppc/translate/processor-ctrl-impl.c.inc new file mode 100644 index 000000000000..cc7a50d579ee --- /dev/null +++ b/target/ppc/translate/processor-ctrl-impl.c.inc @@ -0,0 +1,105 @@ +/* + * Power ISA decode for Storage Control instructions + * + * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * 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 . + */ + +/* + * Processor Control Instructions + */ + +static bool trans_MSGCLR(DisasContext *ctx, arg_X_rb *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA207S)) { + /* + * Before Power ISA 2.07, processor control instructions were only + * implemented in the "Embedded.Processor Control" category. + */ + REQUIRE_INSNS_FLAGS2(ctx, PRCNTL); + } + + REQUIRE_HV(ctx); + +#if !defined(CONFIG_USER_ONLY) + if (is_book3s_arch2x(ctx)) { + gen_helper_book3s_msgclr(cpu_env, cpu_gpr[a->rb]); + } else { + gen_helper_msgclr(cpu_env, cpu_gpr[a->rb]); + } +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA207S)) { + /* + * Before Power ISA 2.07, processor control instructions were only + * implemented in the "Embedded.Processor Control" category. + */ + REQUIRE_INSNS_FLAGS2(ctx, PRCNTL); + } + + REQUIRE_HV(ctx); + +#if !defined(CONFIG_USER_ONLY) + if (is_book3s_arch2x(ctx)) { + gen_helper_book3s_msgsnd(cpu_gpr[a->rb]); + } else { + gen_helper_msgsnd(cpu_gpr[a->rb]); + } +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGCLRP(DisasContext *ctx, arg_X_rb *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + REQUIRE_SV(ctx); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + REQUIRE_SV(ctx); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSYNC(DisasContext *ctx, arg_MSGSYNC *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_HV(ctx); + + /* interpreted as no-op */ + return true; +} diff --git a/target/ppc/translate/storage-ctrl-impl.c.inc b/target/ppc/translate/storage-ctrl-impl.c.inc new file mode 100644 index 000000000000..6ea1d22ef997 --- /dev/null +++ b/target/ppc/translate/storage-ctrl-impl.c.inc @@ -0,0 +1,250 @@ +/* + * Power ISA decode for Storage Control instructions + * + * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * 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 . + */ + +/* + * Store Control Instructions + */ + +#include "mmu-book3s-v3.h" + +static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SLBI); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIE(cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIEG(cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SLBI); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIA(cpu_env, tcg_constant_i32(a->ih)); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIAG(cpu_env, cpu_gpr[a->rs], tcg_constant_i32(a->l)); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBMTE(cpu_env, cpu_gpr[a->rb], cpu_gpr[a->rt]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBMFEV(cpu_gpr[a->rt], cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBMFEE(cpu_gpr[a->rt], cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); +#else + +#if defined(TARGET_PPC64) + TCGLabel *l1, *l2; + + if (unlikely(ctx->pr)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + return true; + } + gen_helper_SLBFEE(cpu_gpr[a->rt], cpu_env, + cpu_gpr[a->rb]); + l1 = gen_new_label(); + l2 = gen_new_label(); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], -1, l1); + tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[a->rt], 0); + gen_set_label(l2); +#else + qemu_build_not_reached(); +#endif +#endif + return true; +} + +static bool trans_SLBSYNC(DisasContext *ctx, arg_SLBSYNC *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_check_tlb_flush(ctx, true); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) +{ +#if defined(CONFIG_USER_ONLY) + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; +#else + TCGv_i32 t1; + int rb; + + rb = a->rb; + + if ((ctx->insns_flags2 & PPC2_ISA300) == 0) { + /* + * Before Power ISA 3.0, the corresponding bits of RIC, PRS, and R + * (and RS for tlbiel) were reserved fields and should be ignored. + */ + a->ric = 0; + a->prs = false; + a->r = false; + if (local) { + a->rs = 0; + } + } + + if (ctx->pr) { + /* tlbie[l] is privileged... */ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; + } else if (!ctx->hv) { + if ((!a->prs && ctx->hr) || (!local && !ctx->gtse)) { + /* + * ... except when PRS=0 and HR=1, or when GTSE=0 for tlbie, + * making it hypervisor privileged. + */ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; + } + } + + if (!local && NARROW_MODE(ctx)) { + TCGv t0 = tcg_temp_new(); + tcg_gen_ext32u_tl(t0, cpu_gpr[rb]); + gen_helper_tlbie(cpu_env, t0); + tcg_temp_free(t0); + +#if defined(TARGET_PPC64) + /* + * ISA 3.1B says that MSR SF must be 1 when this instruction is executed; + * otherwise the results are undefined. + */ + } else if (a->r) { + gen_helper_tlbie_isa300(cpu_env, cpu_gpr[rb], cpu_gpr[a->rs], + tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT | + a->prs << TLBIE_F_PRS_SHIFT | + a->r << TLBIE_F_R_SHIFT | + local << TLBIE_F_LOCAL_SHIFT)); + return true; +#endif + + } else { + gen_helper_tlbie(cpu_env, cpu_gpr[rb]); + } + + if (local) { + return true; + } + + t1 = tcg_temp_new_i32(); + tcg_gen_ld_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); + tcg_gen_st_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_temp_free_i32(t1); + + return true; +#endif +} + +TRANS_FLAGS(MEM_TLBIE, TLBIE, do_tlbie, false) +TRANS_FLAGS(MEM_TLBIE, TLBIEL, do_tlbie, true) diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 6101bca3fd7a..7741f2eb49f3 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -173,7 +173,7 @@ static void gen_mtvscr(DisasContext *ctx) val = tcg_temp_new_i32(); bofs = avr_full_offset(rB(ctx->opcode)); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN bofs += 3 * 4; #endif @@ -431,21 +431,6 @@ GEN_VXFORM_V(vminsb, MO_8, tcg_gen_gvec_smin, 1, 12); GEN_VXFORM_V(vminsh, MO_16, tcg_gen_gvec_smin, 1, 13); GEN_VXFORM_V(vminsw, MO_32, tcg_gen_gvec_smin, 1, 14); GEN_VXFORM_V(vminsd, MO_64, tcg_gen_gvec_smin, 1, 15); -GEN_VXFORM(vavgub, 1, 16); -GEN_VXFORM(vabsdub, 1, 16); -GEN_VXFORM_DUAL(vavgub, PPC_ALTIVEC, PPC_NONE, \ - vabsdub, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavguh, 1, 17); -GEN_VXFORM(vabsduh, 1, 17); -GEN_VXFORM_DUAL(vavguh, PPC_ALTIVEC, PPC_NONE, \ - vabsduh, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavguw, 1, 18); -GEN_VXFORM(vabsduw, 1, 18); -GEN_VXFORM_DUAL(vavguw, PPC_ALTIVEC, PPC_NONE, \ - vabsduw, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavgsb, 1, 20); -GEN_VXFORM(vavgsh, 1, 21); -GEN_VXFORM(vavgsw, 1, 22); GEN_VXFORM(vmrghb, 6, 0); GEN_VXFORM(vmrghh, 6, 1); GEN_VXFORM(vmrghw, 6, 2); @@ -803,8 +788,6 @@ GEN_VXFORM(vsrv, 2, 28); GEN_VXFORM(vslv, 2, 29); GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); -GEN_VXFORM(vaddcuw, 0, 6); -GEN_VXFORM(vsubcuw, 0, 22); static bool do_vector_gvec3_VX(DisasContext *ctx, arg_VX *a, int vece, void (*gen_gvec)(unsigned, uint32_t, uint32_t, @@ -1234,18 +1217,6 @@ GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26); GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28); GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29); GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30); -GEN_VXFORM(vadduqm, 0, 4); -GEN_VXFORM(vaddcuq, 0, 5); -GEN_VXFORM3(vaddeuqm, 30, 0); -GEN_VXFORM3(vaddecuq, 30, 0); -GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ - vaddecuq, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vsubuqm, 0, 20); -GEN_VXFORM(vsubcuq, 0, 21); -GEN_VXFORM3(vsubeuqm, 31, 0); -GEN_VXFORM3(vsubecuq, 31, 0); -GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ - vsubecuq, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXFORM_TRANS(vsl, 2, 7); GEN_VXFORM_TRANS(vsr, 2, 11); GEN_VXFORM_ENV(vpkuhum, 7, 0); @@ -1673,9 +1644,71 @@ GEN_VXFORM_NOA_ENV(vrfim, 5, 11); GEN_VXFORM_NOA_ENV(vrfin, 5, 8); GEN_VXFORM_NOA_ENV(vrfip, 5, 10); GEN_VXFORM_NOA_ENV(vrfiz, 5, 9); -GEN_VXFORM_NOA(vprtybw, 1, 24); -GEN_VXFORM_NOA(vprtybd, 1, 24); -GEN_VXFORM_NOA(vprtybq, 1, 24); + +static void gen_vprtyb_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + int i; + TCGv_vec tmp = tcg_temp_new_vec_matching(b); + /* MO_32 is 2, so 2 iteractions for MO_32 and 3 for MO_64 */ + for (i = 0; i < vece; i++) { + tcg_gen_shri_vec(vece, tmp, b, (4 << (vece - i))); + tcg_gen_xor_vec(vece, b, tmp, b); + } + tcg_gen_and_vec(vece, t, b, tcg_constant_vec_matching(t, vece, 1)); + tcg_temp_free_vec(tmp); +} + +/* vprtybw */ +static void gen_vprtyb_i32(TCGv_i32 t, TCGv_i32 b) +{ + tcg_gen_ctpop_i32(t, b); + tcg_gen_and_i32(t, t, tcg_constant_i32(1)); +} + +/* vprtybd */ +static void gen_vprtyb_i64(TCGv_i64 t, TCGv_i64 b) +{ + tcg_gen_ctpop_i64(t, b); + tcg_gen_and_i64(t, t, tcg_constant_i64(1)); +} + +static bool do_vx_vprtyb(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, 0 + }; + + static const GVecGen2 op[] = { + { + .fniv = gen_vprtyb_vec, + .fni4 = gen_vprtyb_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_vprtyb_vec, + .fni8 = gen_vprtyb_i64, + .opt_opc = vecop_list, + .vece = MO_64 + }, + { + .fno = gen_helper_VPRTYBQ, + .vece = MO_128 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_2(avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16, &op[vece - MO_32]); + + return true; +} + +TRANS(VPRTYBW, do_vx_vprtyb, MO_32) +TRANS(VPRTYBD, do_vx_vprtyb, MO_64) +TRANS(VPRTYBQ, do_vx_vprtyb, MO_128) static void gen_vsplt(DisasContext *ctx, int vece) { @@ -1692,7 +1725,7 @@ static void gen_vsplt(DisasContext *ctx, int vece) /* Experimental testing shows that hardware masks the immediate. */ bofs += (uimm << vece) & 15; -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN bofs ^= 15; bofs &= ~((1 << vece) - 1); #endif @@ -2533,40 +2566,19 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16) - -static void gen_vmladduhm(DisasContext *ctx) -{ - TCGv_ptr ra, rb, rc, rd; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rb = gen_avr_ptr(rB(ctx->opcode)); - rc = gen_avr_ptr(rC(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_vmladduhm(rd, ra, rb, rc); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rc); - tcg_temp_free_ptr(rd); -} +GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) -static bool trans_VPERM(DisasContext *ctx, arg_VA *a) +static bool do_va_helper(DisasContext *ctx, arg_VA *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) { TCGv_ptr vrt, vra, vrb, vrc; - - REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); REQUIRE_VECTOR(ctx); vrt = gen_avr_ptr(a->vrt); vra = gen_avr_ptr(a->vra); vrb = gen_avr_ptr(a->vrb); vrc = gen_avr_ptr(a->rc); - - gen_helper_VPERM(vrt, vra, vrb, vrc); - + gen_helper(vrt, vra, vrb, vrc); tcg_temp_free_ptr(vrt); tcg_temp_free_ptr(vra); tcg_temp_free_ptr(vrb); @@ -2575,24 +2587,41 @@ static bool trans_VPERM(DisasContext *ctx, arg_VA *a) return true; } -static bool trans_VPERMR(DisasContext *ctx, arg_VA *a) +TRANS_FLAGS2(ALTIVEC_207, VADDECUQ, do_va_helper, gen_helper_VADDECUQ) +TRANS_FLAGS2(ALTIVEC_207, VADDEUQM, do_va_helper, gen_helper_VADDEUQM) + +TRANS_FLAGS2(ALTIVEC_207, VSUBEUQM, do_va_helper, gen_helper_VSUBEUQM) +TRANS_FLAGS2(ALTIVEC_207, VSUBECUQ, do_va_helper, gen_helper_VSUBECUQ) + +TRANS_FLAGS(ALTIVEC, VPERM, do_va_helper, gen_helper_VPERM) +TRANS_FLAGS2(ISA300, VPERMR, do_va_helper, gen_helper_VPERMR) + +static void gen_vmladduhm_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + TCGv_vec c) { - TCGv_ptr vrt, vra, vrb, vrc; + tcg_gen_mul_vec(vece, t, a, b); + tcg_gen_add_vec(vece, t, t, c); +} - REQUIRE_INSNS_FLAGS2(ctx, ISA300); - REQUIRE_VECTOR(ctx); +static bool trans_VMLADDUHM(DisasContext *ctx, arg_VA *a) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_add_vec, INDEX_op_mul_vec, 0 + }; - vrt = gen_avr_ptr(a->vrt); - vra = gen_avr_ptr(a->vra); - vrb = gen_avr_ptr(a->vrb); - vrc = gen_avr_ptr(a->rc); + static const GVecGen4 op = { + .fno = gen_helper_VMLADDUHM, + .fniv = gen_vmladduhm_vec, + .opt_opc = vecop_list, + .vece = MO_16 + }; - gen_helper_VPERMR(vrt, vra, vrb, vrc); + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); - tcg_temp_free_ptr(vrt); - tcg_temp_free_ptr(vra); - tcg_temp_free_ptr(vrb); - tcg_temp_free_ptr(vrc); + tcg_gen_gvec_4(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), avr_full_offset(a->rc), + 16, 16, &op); return true; } @@ -2609,17 +2638,53 @@ static bool trans_VSEL(DisasContext *ctx, arg_VA *a) return true; } -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) -GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) +TRANS_FLAGS(ALTIVEC, VMSUMUBM, do_va_helper, gen_helper_VMSUMUBM) +TRANS_FLAGS(ALTIVEC, VMSUMMBM, do_va_helper, gen_helper_VMSUMMBM) +TRANS_FLAGS(ALTIVEC, VMSUMSHM, do_va_helper, gen_helper_VMSUMSHM) +TRANS_FLAGS(ALTIVEC, VMSUMUHM, do_va_helper, gen_helper_VMSUMUHM) + +static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr vrt, vra, vrb, vrc; + REQUIRE_VECTOR(ctx); + + vrt = gen_avr_ptr(a->vrt); + vra = gen_avr_ptr(a->vra); + vrb = gen_avr_ptr(a->vrb); + vrc = gen_avr_ptr(a->rc); + gen_helper(cpu_env, vrt, vra, vrb, vrc); + tcg_temp_free_ptr(vrt); + tcg_temp_free_ptr(vra); + tcg_temp_free_ptr(vrb); + tcg_temp_free_ptr(vrc); + + return true; +} + +TRANS_FLAGS(ALTIVEC, VMSUMUHS, do_va_env_helper, gen_helper_VMSUMUHS) +TRANS_FLAGS(ALTIVEC, VMSUMSHS, do_va_env_helper, gen_helper_VMSUMSHS) + +TRANS_FLAGS(ALTIVEC, VMHADDSHS, do_va_env_helper, gen_helper_VMHADDSHS) +TRANS_FLAGS(ALTIVEC, VMHRADDSHS, do_va_env_helper, gen_helper_VMHRADDSHS) GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_TRANS(vclzw, 1, 30) GEN_VXFORM_TRANS(vclzd, 1, 31) -GEN_VXFORM_NOA_2(vnegw, 1, 24, 6) -GEN_VXFORM_NOA_2(vnegd, 1, 24, 7) + +static bool do_vneg(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_neg(vece, avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16); + return true; +} + +TRANS(VNEGW, do_vneg, MO_32) +TRANS(VNEGD, do_vneg, MO_64) static void gen_vexts_i64(TCGv_i64 t, TCGv_i64 b, int64_t s) { @@ -2715,7 +2780,6 @@ GEN_VXFORM_TRANS(vgbbd, 6, 20); GEN_VXFORM(vpmsumb, 4, 16) GEN_VXFORM(vpmsumh, 4, 17) GEN_VXFORM(vpmsumw, 4, 18) -GEN_VXFORM(vpmsumd, 4, 19) #define GEN_BCD(op) \ static void gen_##op(DisasContext *ctx) \ @@ -2839,8 +2903,6 @@ static void gen_xpnd04_2(DisasContext *ctx) } -GEN_VXFORM_DUAL(vsubcuw, PPC_ALTIVEC, PPC_NONE, \ - xpnd04_1, PPC_NONE, PPC2_ISA300) GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \ xpnd04_2, PPC_NONE, PPC2_ISA300) @@ -2860,11 +2922,6 @@ GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \ bcdus, PPC_NONE, PPC2_ISA300) GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \ bcdtrunc, PPC_NONE, PPC2_ISA300) -GEN_VXFORM_DUAL(vsubuqm, PPC2_ALTIVEC_207, PPC_NONE, \ - bcdtrunc, PPC_NONE, PPC2_ISA300) -GEN_VXFORM_DUAL(vsubcuq, PPC2_ALTIVEC_207, PPC_NONE, \ - bcdutrunc, PPC_NONE, PPC2_ISA300) - static void gen_vsbox(DisasContext *ctx) { @@ -3099,6 +3156,71 @@ static bool do_vx_helper(DisasContext *ctx, arg_VX *a, return true; } +TRANS_FLAGS2(ALTIVEC_207, VADDCUQ, do_vx_helper, gen_helper_VADDCUQ) +TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, gen_helper_VADDUQM) + +TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD) + +TRANS_FLAGS2(ALTIVEC_207, VSUBCUQ, do_vx_helper, gen_helper_VSUBCUQ) +TRANS_FLAGS2(ALTIVEC_207, VSUBUQM, do_vx_helper, gen_helper_VSUBUQM) + +static void gen_VADDCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_not_vec(vece, a, a); + tcg_gen_cmp_vec(TCG_COND_LTU, vece, t, a, b); + tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1)); +} + +static void gen_VADDCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_not_i32(a, a); + tcg_gen_setcond_i32(TCG_COND_LTU, t, a, b); +} + +static void gen_VSUBCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_cmp_vec(TCG_COND_GEU, vece, t, a, b); + tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1)); +} + +static void gen_VSUBCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_setcond_i32(TCG_COND_GEU, t, a, b); +} + +static bool do_vx_vaddsubcuw(DisasContext *ctx, arg_VX *a, int add) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + + static const GVecGen3 op[] = { + { + .fniv = gen_VSUBCUW_vec, + .fni4 = gen_VSUBCUW_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_VADDCUW_vec, + .fni4 = gen_VADDCUW_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + }; + + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[add]); + + return true; +} + +TRANS(VSUBCUW, do_vx_vaddsubcuw, 0) +TRANS(VADDCUW, do_vx_vaddsubcuw, 1) + static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even, void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) { @@ -3236,6 +3358,297 @@ TRANS(VMULHSD, do_vx_mulh, true , do_vx_vmulhd_i64) TRANS(VMULHUW, do_vx_mulh, false, do_vx_vmulhw_i64) TRANS(VMULHUD, do_vx_mulh, false, do_vx_vmulhd_i64) +static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + void (*gen_shr_vec)(unsigned, TCGv_vec, TCGv_vec, int64_t)) +{ + TCGv_vec tmp = tcg_temp_new_vec_matching(t); + tcg_gen_or_vec(vece, tmp, a, b); + tcg_gen_and_vec(vece, tmp, tmp, tcg_constant_vec_matching(t, vece, 1)); + gen_shr_vec(vece, a, a, 1); + gen_shr_vec(vece, b, b, 1); + tcg_gen_add_vec(vece, t, a, b); + tcg_gen_add_vec(vece, t, t, tmp); + tcg_temp_free_vec(tmp); +} + +QEMU_FLATTEN +static void gen_vavgu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + do_vavg(vece, t, a, b, tcg_gen_shri_vec); +} + +QEMU_FLATTEN +static void gen_vavgs(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + do_vavg(vece, t, a, b, tcg_gen_sari_vec); +} + +static bool do_vx_vavg(DisasContext *ctx, arg_VX *a, int sign, int vece) +{ + static const TCGOpcode vecop_list_s[] = { + INDEX_op_add_vec, INDEX_op_sari_vec, 0 + }; + static const TCGOpcode vecop_list_u[] = { + INDEX_op_add_vec, INDEX_op_shri_vec, 0 + }; + + static const GVecGen3 op[2][3] = { + { + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUB, + .opt_opc = vecop_list_u, + .vece = MO_8 + }, + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUH, + .opt_opc = vecop_list_u, + .vece = MO_16 + }, + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUW, + .opt_opc = vecop_list_u, + .vece = MO_32 + }, + }, + { + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSB, + .opt_opc = vecop_list_s, + .vece = MO_8 + }, + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSH, + .opt_opc = vecop_list_s, + .vece = MO_16 + }, + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSW, + .opt_opc = vecop_list_s, + .vece = MO_32 + }, + }, + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[sign][vece]); + + + return true; +} + + +TRANS_FLAGS(ALTIVEC, VAVGSB, do_vx_vavg, 1, MO_8) +TRANS_FLAGS(ALTIVEC, VAVGSH, do_vx_vavg, 1, MO_16) +TRANS_FLAGS(ALTIVEC, VAVGSW, do_vx_vavg, 1, MO_32) +TRANS_FLAGS(ALTIVEC, VAVGUB, do_vx_vavg, 0, MO_8) +TRANS_FLAGS(ALTIVEC, VAVGUH, do_vx_vavg, 0, MO_16) +TRANS_FLAGS(ALTIVEC, VAVGUW, do_vx_vavg, 0, MO_32) + +static void gen_vabsdu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_umax_vec(vece, t, a, b); + tcg_gen_umin_vec(vece, a, a, b); + tcg_gen_sub_vec(vece, t, t, a); +} + +static bool do_vabsdu(DisasContext *ctx, arg_VX *a, const int vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_umax_vec, INDEX_op_umin_vec, INDEX_op_sub_vec, 0 + }; + + static const GVecGen3 op[] = { + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUB, + .opt_opc = vecop_list, + .vece = MO_8 + }, + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUH, + .opt_opc = vecop_list, + .vece = MO_16 + }, + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUW, + .opt_opc = vecop_list, + .vece = MO_32 + }, + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[vece]); + + return true; +} + +TRANS_FLAGS2(ISA300, VABSDUB, do_vabsdu, MO_8) +TRANS_FLAGS2(ISA300, VABSDUH, do_vabsdu, MO_16) +TRANS_FLAGS2(ISA300, VABSDUW, do_vabsdu, MO_32) + +static bool do_vdiv_vmod(DisasContext *ctx, arg_VX *a, const int vece, + void (*func_32)(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b), + void (*func_64)(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b)) +{ + const GVecGen3 op = { + .fni4 = func_32, + .fni8 = func_64, + .vece = vece + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op); + + return true; +} + +#define DIVU32(NAME, DIV) \ +static void NAME(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) \ +{ \ + TCGv_i32 zero = tcg_constant_i32(0); \ + TCGv_i32 one = tcg_constant_i32(1); \ + tcg_gen_movcond_i32(TCG_COND_EQ, b, b, zero, one, b); \ + DIV(t, a, b); \ +} + +#define DIVS32(NAME, DIV) \ +static void NAME(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) \ +{ \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + TCGv_i32 t1 = tcg_temp_new_i32(); \ + tcg_gen_setcondi_i32(TCG_COND_EQ, t0, a, INT32_MIN); \ + tcg_gen_setcondi_i32(TCG_COND_EQ, t1, b, -1); \ + tcg_gen_and_i32(t0, t0, t1); \ + tcg_gen_setcondi_i32(TCG_COND_EQ, t1, b, 0); \ + tcg_gen_or_i32(t0, t0, t1); \ + tcg_gen_movi_i32(t1, 0); \ + tcg_gen_movcond_i32(TCG_COND_NE, b, t0, t1, t0, b); \ + DIV(t, a, b); \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_i32(t1); \ +} + +#define DIVU64(NAME, DIV) \ +static void NAME(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) \ +{ \ + TCGv_i64 zero = tcg_constant_i64(0); \ + TCGv_i64 one = tcg_constant_i64(1); \ + tcg_gen_movcond_i64(TCG_COND_EQ, b, b, zero, one, b); \ + DIV(t, a, b); \ +} + +#define DIVS64(NAME, DIV) \ +static void NAME(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) \ +{ \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i64 t1 = tcg_temp_new_i64(); \ + tcg_gen_setcondi_i64(TCG_COND_EQ, t0, a, INT64_MIN); \ + tcg_gen_setcondi_i64(TCG_COND_EQ, t1, b, -1); \ + tcg_gen_and_i64(t0, t0, t1); \ + tcg_gen_setcondi_i64(TCG_COND_EQ, t1, b, 0); \ + tcg_gen_or_i64(t0, t0, t1); \ + tcg_gen_movi_i64(t1, 0); \ + tcg_gen_movcond_i64(TCG_COND_NE, b, t0, t1, t0, b); \ + DIV(t, a, b); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ +} + +DIVS32(do_divsw, tcg_gen_div_i32) +DIVU32(do_divuw, tcg_gen_divu_i32) +DIVS64(do_divsd, tcg_gen_div_i64) +DIVU64(do_divud, tcg_gen_divu_i64) + +TRANS_FLAGS2(ISA310, VDIVSW, do_vdiv_vmod, MO_32, do_divsw, NULL) +TRANS_FLAGS2(ISA310, VDIVUW, do_vdiv_vmod, MO_32, do_divuw, NULL) +TRANS_FLAGS2(ISA310, VDIVSD, do_vdiv_vmod, MO_64, NULL, do_divsd) +TRANS_FLAGS2(ISA310, VDIVUD, do_vdiv_vmod, MO_64, NULL, do_divud) +TRANS_FLAGS2(ISA310, VDIVSQ, do_vx_helper, gen_helper_VDIVSQ) +TRANS_FLAGS2(ISA310, VDIVUQ, do_vx_helper, gen_helper_VDIVUQ) + +static void do_dives_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i64 val1, val2; + + val1 = tcg_temp_new_i64(); + val2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(val1, a); + tcg_gen_ext_i32_i64(val2, b); + + /* (a << 32)/b */ + tcg_gen_shli_i64(val1, val1, 32); + tcg_gen_div_i64(val1, val1, val2); + + /* if quotient doesn't fit in 32 bits the result is undefined */ + tcg_gen_extrl_i64_i32(t, val1); + + tcg_temp_free_i64(val1); + tcg_temp_free_i64(val2); +} + +static void do_diveu_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i64 val1, val2; + + val1 = tcg_temp_new_i64(); + val2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(val1, a); + tcg_gen_extu_i32_i64(val2, b); + + /* (a << 32)/b */ + tcg_gen_shli_i64(val1, val1, 32); + tcg_gen_divu_i64(val1, val1, val2); + + /* if quotient doesn't fit in 32 bits the result is undefined */ + tcg_gen_extrl_i64_i32(t, val1); + + tcg_temp_free_i64(val1); + tcg_temp_free_i64(val2); +} + +DIVS32(do_divesw, do_dives_i32) +DIVU32(do_diveuw, do_diveu_i32) + +DIVS32(do_modsw, tcg_gen_rem_i32) +DIVU32(do_moduw, tcg_gen_remu_i32) +DIVS64(do_modsd, tcg_gen_rem_i64) +DIVU64(do_modud, tcg_gen_remu_i64) + +TRANS_FLAGS2(ISA310, VDIVESW, do_vdiv_vmod, MO_32, do_divesw, NULL) +TRANS_FLAGS2(ISA310, VDIVEUW, do_vdiv_vmod, MO_32, do_diveuw, NULL) +TRANS_FLAGS2(ISA310, VDIVESD, do_vx_helper, gen_helper_VDIVESD) +TRANS_FLAGS2(ISA310, VDIVEUD, do_vx_helper, gen_helper_VDIVEUD) +TRANS_FLAGS2(ISA310, VDIVESQ, do_vx_helper, gen_helper_VDIVESQ) +TRANS_FLAGS2(ISA310, VDIVEUQ, do_vx_helper, gen_helper_VDIVEUQ) + +TRANS_FLAGS2(ISA310, VMODSW, do_vdiv_vmod, MO_32, do_modsw , NULL) +TRANS_FLAGS2(ISA310, VMODUW, do_vdiv_vmod, MO_32, do_moduw, NULL) +TRANS_FLAGS2(ISA310, VMODSD, do_vdiv_vmod, MO_64, NULL, do_modsd) +TRANS_FLAGS2(ISA310, VMODUD, do_vdiv_vmod, MO_64, NULL, do_modud) +TRANS_FLAGS2(ISA310, VMODSQ, do_vx_helper, gen_helper_VMODSQ) +TRANS_FLAGS2(ISA310, VMODUQ, do_vx_helper, gen_helper_VMODUQ) + +#undef DIVS32 +#undef DIVU32 +#undef DIVS64 +#undef DIVU64 + #undef GEN_VR_LDX #undef GEN_VR_STX #undef GEN_VR_LVE diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index d960648d5231..33fec8aca4cd 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -83,12 +83,6 @@ GEN_VXFORM(vminsb, 1, 12), GEN_VXFORM(vminsh, 1, 13), GEN_VXFORM(vminsw, 1, 14), GEN_VXFORM_207(vminsd, 1, 15), -GEN_VXFORM_DUAL(vavgub, vabsdub, 1, 16, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vavguh, vabsduh, 1, 17, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vavguw, vabsduw, 1, 18, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vavgsb, 1, 20), -GEN_VXFORM(vavgsh, 1, 21), -GEN_VXFORM(vavgsw, 1, 22), GEN_VXFORM(vmrghb, 6, 0), GEN_VXFORM(vmrghh, 6, 1), GEN_VXFORM(vmrghw, 6, 2), @@ -106,12 +100,8 @@ GEN_VXFORM_300(vsrv, 2, 28), GEN_VXFORM_300(vslv, 2, 29), GEN_VXFORM(vslo, 6, 16), GEN_VXFORM(vsro, 6, 17), -GEN_VXFORM(vaddcuw, 0, 6), -GEN_HANDLER_E_2(vprtybw, 0x4, 0x1, 0x18, 8, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E_2(vprtybd, 0x4, 0x1, 0x18, 9, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E_2(vprtybq, 0x4, 0x1, 0x18, 10, 0, PPC_NONE, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubcuw, xpnd04_1, 0, 22, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM(xpnd04_1, 0, 22), GEN_VXFORM_300(bcdsr, 0, 23), GEN_VXFORM_300(bcdsr, 0, 31), GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE), @@ -126,12 +116,8 @@ GEN_VXFORM(vsubuws, 0, 26), GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300), GEN_VXFORM(vsubshs, 0, 29), GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_207(vadduqm, 0, 4), -GEN_VXFORM_207(vaddcuq, 0, 5), -GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vsubuqm, bcdtrunc, 0, 20, PPC2_ALTIVEC_207, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubcuq, bcdutrunc, 0, 21, PPC2_ALTIVEC_207, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_300(bcdtrunc, 0, 20), +GEN_VXFORM_300(bcdutrunc, 0, 21), GEN_VXFORM(vsl, 2, 7), GEN_VXFORM(vsr, 2, 11), GEN_VXFORM(vpkuhum, 7, 0), @@ -186,8 +172,6 @@ GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), GEN_VXFORM(vspltisb, 6, 12), GEN_VXFORM(vspltish, 6, 13), GEN_VXFORM(vspltisw, 6, 14), -GEN_VXFORM_300_EO(vnegw, 0x01, 0x18, 0x06), -GEN_VXFORM_300_EO(vnegd, 0x01, 0x18, 0x07), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), @@ -221,13 +205,8 @@ GEN_VXFORM_UIMM(vcfsx, 5, 13), GEN_VXFORM_UIMM(vctuxs, 5, 14), GEN_VXFORM_UIMM(vctsxs, 5, 15), - #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18), -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19), -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207), @@ -241,7 +220,6 @@ GEN_VXFORM_207(vgbbd, 6, 20), GEN_VXFORM_207(vpmsumb, 4, 16), GEN_VXFORM_207(vpmsumh, 4, 17), GEN_VXFORM_207(vpmsumw, 4, 18), -GEN_VXFORM_207(vpmsumd, 4, 19), GEN_VXFORM_207(vsbox, 4, 23), diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index d1f633331444..4deb29ee4252 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -17,6 +17,13 @@ static inline TCGv_ptr gen_vsr_ptr(int reg) return r; } +static inline TCGv_ptr gen_acc_ptr(int reg) +{ + TCGv_ptr r = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(r, cpu_env, acc_full_offset(reg)); + return r; +} + #define VSX_LOAD_SCALAR(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -623,6 +630,10 @@ static void gen_mtvsrws(DisasContext *ctx) #define OP_CPSGN 4 #define SGN_MASK_DP 0x8000000000000000ull #define SGN_MASK_SP 0x8000000080000000ull +#define EXP_MASK_DP 0x7FF0000000000000ull +#define EXP_MASK_SP 0x7F8000007F800000ull +#define FRC_MASK_DP (~(SGN_MASK_DP | EXP_MASK_DP)) +#define FRC_MASK_SP (~(SGN_MASK_SP | EXP_MASK_SP)) #define VSX_SCALAR_MOVE(name, op, sgn_mask) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -722,67 +733,125 @@ VSX_SCALAR_MOVE_QP(xsnabsqp, OP_NABS, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xsnegqp, OP_NEG, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xscpsgnqp, OP_CPSGN, SGN_MASK_DP) -#define VSX_VECTOR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_i64 xbh, xbl, sgm; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xbh = tcg_temp_new_i64(); \ - xbl = tcg_temp_new_i64(); \ - sgm = tcg_temp_new_i64(); \ - get_cpu_vsr(xbh, xB(ctx->opcode), true); \ - get_cpu_vsr(xbl, xB(ctx->opcode), false); \ - tcg_gen_movi_i64(sgm, sgn_mask); \ - switch (op) { \ - case OP_ABS: { \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NABS: { \ - tcg_gen_or_i64(xbh, xbh, sgm); \ - tcg_gen_or_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NEG: { \ - tcg_gen_xor_i64(xbh, xbh, sgm); \ - tcg_gen_xor_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_CPSGN: { \ - TCGv_i64 xah = tcg_temp_new_i64(); \ - TCGv_i64 xal = tcg_temp_new_i64(); \ - get_cpu_vsr(xah, xA(ctx->opcode), true); \ - get_cpu_vsr(xal, xA(ctx->opcode), false); \ - tcg_gen_and_i64(xah, xah, sgm); \ - tcg_gen_and_i64(xal, xal, sgm); \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - tcg_gen_or_i64(xbh, xbh, xah); \ - tcg_gen_or_i64(xbl, xbl, xal); \ - tcg_temp_free_i64(xah); \ - tcg_temp_free_i64(xal); \ - break; \ - } \ - } \ - set_cpu_vsr(xT(ctx->opcode), xbh, true); \ - set_cpu_vsr(xT(ctx->opcode), xbl, false); \ - tcg_temp_free_i64(xbh); \ - tcg_temp_free_i64(xbl); \ - tcg_temp_free_i64(sgm); \ - } - -VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) +#define TCG_OP_IMM_i64(FUNC, OP, IMM) \ + static void FUNC(TCGv_i64 t, TCGv_i64 b) \ + { \ + OP(t, b, IMM); \ + } + +TCG_OP_IMM_i64(do_xvabssp_i64, tcg_gen_andi_i64, ~SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvnabssp_i64, tcg_gen_ori_i64, SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvnegsp_i64, tcg_gen_xori_i64, SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvabsdp_i64, tcg_gen_andi_i64, ~SGN_MASK_DP) +TCG_OP_IMM_i64(do_xvnabsdp_i64, tcg_gen_ori_i64, SGN_MASK_DP) +TCG_OP_IMM_i64(do_xvnegdp_i64, tcg_gen_xori_i64, SGN_MASK_DP) +#undef TCG_OP_IMM_i64 + +static void xv_msb_op1(unsigned vece, TCGv_vec t, TCGv_vec b, + void (*tcg_gen_op_vec)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) +{ + uint64_t msb = (vece == MO_32) ? SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_op_vec(vece, t, b, tcg_constant_vec_matching(t, vece, msb)); +} + +static void do_xvabs_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_andc_vec); +} + +static void do_xvnabs_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_or_vec); +} + +static void do_xvneg_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_xor_vec); +} + +static bool do_vsx_msb_op(DisasContext *ctx, arg_XX2 *a, unsigned vece, + void (*vec)(unsigned, TCGv_vec, TCGv_vec), + void (*i64)(TCGv_i64, TCGv_i64)) +{ + static const TCGOpcode vecop_list[] = { + 0 + }; + + const GVecGen2 op = { + .fni8 = i64, + .fniv = vec, + .opt_opc = vecop_list, + .vece = vece + }; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_2(vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, &op); + + return true; +} + +TRANS(XVABSDP, do_vsx_msb_op, MO_64, do_xvabs_vec, do_xvabsdp_i64) +TRANS(XVNABSDP, do_vsx_msb_op, MO_64, do_xvnabs_vec, do_xvnabsdp_i64) +TRANS(XVNEGDP, do_vsx_msb_op, MO_64, do_xvneg_vec, do_xvnegdp_i64) +TRANS(XVABSSP, do_vsx_msb_op, MO_32, do_xvabs_vec, do_xvabssp_i64) +TRANS(XVNABSSP, do_vsx_msb_op, MO_32, do_xvnabs_vec, do_xvnabssp_i64) +TRANS(XVNEGSP, do_vsx_msb_op, MO_32, do_xvneg_vec, do_xvnegsp_i64) + +static void do_xvcpsgndp_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_andi_i64(a, a, SGN_MASK_DP); + tcg_gen_andi_i64(b, b, ~SGN_MASK_DP); + tcg_gen_or_i64(t, a, b); +} + +static void do_xvcpsgnsp_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_andi_i64(a, a, SGN_MASK_SP); + tcg_gen_andi_i64(b, b, ~SGN_MASK_SP); + tcg_gen_or_i64(t, a, b); +} + +static void do_xvcpsgn_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + uint64_t msb = (vece == MO_32) ? SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_bitsel_vec(vece, t, tcg_constant_vec_matching(t, vece, msb), a, b); +} + +static bool do_xvcpsgn(DisasContext *ctx, arg_XX3 *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + 0 + }; + + static const GVecGen3 op[] = { + { + .fni8 = do_xvcpsgnsp_i64, + .fniv = do_xvcpsgn_vec, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fni8 = do_xvcpsgndp_i64, + .fniv = do_xvcpsgn_vec, + .opt_opc = vecop_list, + .vece = MO_64 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_3(vsr_full_offset(a->xt), vsr_full_offset(a->xa), + vsr_full_offset(a->xb), 16, 16, &op[vece - MO_32]); + + return true; +} + +TRANS(XVCPSGNSP, do_xvcpsgn, MO_32) +TRANS(XVCPSGNDP, do_xvcpsgn, MO_64) #define VSX_CMP(name, op1, op2, inval, type) \ static void gen_##name(DisasContext *ctx) \ @@ -803,7 +872,6 @@ static void gen_##name(DisasContext *ctx) \ gen_helper_##name(ignored, cpu_env, xt, xa, xb); \ tcg_temp_free_i32(ignored); \ } \ - gen_helper_float_check_status(cpu_env); \ tcg_temp_free_ptr(xt); \ tcg_temp_free_ptr(xa); \ tcg_temp_free_ptr(xb); \ @@ -838,6 +906,28 @@ static bool trans_XSCVQPDP(DisasContext *ctx, arg_X_tb_rc *a) return true; } +static bool do_helper_env_X_tb(DisasContext *ctx, arg_X_tb *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr xt, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + xt = gen_avr_ptr(a->rt); + xb = gen_avr_ptr(a->rb); + gen_helper(cpu_env, xt, xb); + tcg_temp_free_ptr(xt); + tcg_temp_free_ptr(xb); + + return true; +} + +TRANS(XSCVUQQP, do_helper_env_X_tb, gen_helper_XSCVUQQP) +TRANS(XSCVSQQP, do_helper_env_X_tb, gen_helper_XSCVSQQP) +TRANS(XSCVQPUQZ, do_helper_env_X_tb, gen_helper_XSCVQPUQZ) +TRANS(XSCVQPSQZ, do_helper_env_X_tb, gen_helper_XSCVQPSQZ) + #define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -1023,7 +1113,213 @@ GEN_VSX_HELPER_R2(xscvqpuwz, 0x04, 0x1A, 0x01, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300) GEN_VSX_HELPER_R2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207) + +/* test if +Inf */ +static void gen_is_pos_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +/* test if -Inf */ +static void gen_is_neg_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk | exp_msk)); +} + +/* test if +Inf or -Inf */ +static void gen_is_any_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +/* test if +0 */ +static void gen_is_pos_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, 0)); +} + +/* test if -0 */ +static void gen_is_neg_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk)); +} + +/* test if +0 or -0 */ +static void gen_is_any_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, 0)); +} + +/* test if +Denormal */ +static void gen_is_pos_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_LEU, vece, t, b, + tcg_constant_vec_matching(t, vece, frc_msk)); + tcg_gen_cmp_vec(TCG_COND_NE, vece, b, b, + tcg_constant_vec_matching(t, vece, 0)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if -Denormal */ +static void gen_is_neg_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_LEU, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk | frc_msk)); + tcg_gen_cmp_vec(TCG_COND_GTU, vece, b, b, + tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if +Denormal or -Denormal */ +static void gen_is_any_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_LE, vece, t, b, + tcg_constant_vec_matching(t, vece, frc_msk)); + tcg_gen_cmp_vec(TCG_COND_NE, vece, b, b, + tcg_constant_vec_matching(t, vece, 0)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if NaN */ +static void gen_is_nan(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_and_vec(vece, b, b, tcg_constant_vec_matching(t, vece, ~sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_GT, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +static bool do_xvtstdc(DisasContext *ctx, arg_XX2_uim *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + + GVecGen2i op = { + .fnoi = (vece == MO_32) ? gen_helper_XVTSTDCSP : gen_helper_XVTSTDCDP, + .vece = vece, + .opt_opc = vecop_list + }; + + REQUIRE_VSX(ctx); + + switch (a->uim) { + case 0: + set_cpu_vsr(a->xt, tcg_constant_i64(0), true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + return true; + case ((1 << 0) | (1 << 1)): + /* test if +Denormal or -Denormal */ + op.fniv = gen_is_any_denormal; + break; + case (1 << 0): + /* test if -Denormal */ + op.fniv = gen_is_neg_denormal; + break; + case (1 << 1): + /* test if +Denormal */ + op.fniv = gen_is_pos_denormal; + break; + case ((1 << 2) | (1 << 3)): + /* test if +0 or -0 */ + op.fniv = gen_is_any_zero; + break; + case (1 << 2): + /* test if -0 */ + op.fniv = gen_is_neg_zero; + break; + case (1 << 3): + /* test if +0 */ + op.fniv = gen_is_pos_zero; + break; + case ((1 << 4) | (1 << 5)): + /* test if +Inf or -Inf */ + op.fniv = gen_is_any_inf; + break; + case (1 << 4): + /* test if -Inf */ + op.fniv = gen_is_neg_inf; + break; + case (1 << 5): + /* test if +Inf */ + op.fniv = gen_is_pos_inf; + break; + case (1 << 6): + /* test if NaN */ + op.fniv = gen_is_nan; + break; + } + tcg_gen_gvec_2i(vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, a->uim, &op); + + return true; +} + +TRANS_FLAGS2(VSX, XVTSTDCSP, do_xvtstdc, MO_32) +TRANS_FLAGS2(VSX, XVTSTDCDP, do_xvtstdc, MO_64) + +static bool do_XX2_bf_uim(DisasContext *ctx, arg_XX2_bf_uim *a, bool vsr, + void (*gen_helper)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_ptr)) +{ + TCGv_ptr xb; + + REQUIRE_VSX(ctx); + xb = vsr ? gen_vsr_ptr(a->xb) : gen_avr_ptr(a->xb); + gen_helper(cpu_env, tcg_constant_i32(a->bf), tcg_constant_i32(a->uim), xb); + tcg_temp_free_ptr(xb); + + return true; +} + +TRANS_FLAGS2(ISA300, XSTSTDCSP, do_XX2_bf_uim, true, gen_helper_XSTSTDCSP) +TRANS_FLAGS2(ISA300, XSTSTDCDP, do_XX2_bf_uim, true, gen_helper_XSTSTDCDP) +TRANS_FLAGS2(ISA300, XSTSTDCQP, do_XX2_bf_uim, false, gen_helper_XSTSTDCQP) + +bool trans_XSCVSPDPN(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_VSX(ctx); + + tmp = tcg_temp_new_i64(); + get_cpu_vsr(tmp, a->xb, true); + + gen_helper_XSCVSPDPN(tmp, tmp); + + set_cpu_vsr(a->xt, tmp, true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + + tcg_temp_free_i64(tmp); + + return true; +} + GEN_VSX_HELPER_X2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX) @@ -1050,9 +1346,6 @@ GEN_VSX_HELPER_X2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207) -GEN_VSX_HELPER_X1(xststdcsp, 0x14, 0x12, 0, PPC2_ISA300) -GEN_VSX_HELPER_2(xststdcdp, 0x14, 0x16, 0, PPC2_ISA300) -GEN_VSX_HELPER_2(xststdcqp, 0x04, 0x16, 0, PPC2_ISA300) GEN_VSX_HELPER_X3(xvadddp, 0x00, 0x0C, 0, PPC2_VSX) GEN_VSX_HELPER_X3(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX) @@ -1107,8 +1400,6 @@ GEN_VSX_HELPER_X2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtstdcsp, 0x14, 0x1A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtstdcdp, 0x14, 0x1E, 0, PPC2_VSX) static bool trans_XXPERM(DisasContext *ctx, arg_XX3 *a) { @@ -1543,7 +1834,7 @@ static bool trans_XXSEL(DisasContext *ctx, arg_XX4 *a) return true; } -static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim2 *a) +static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim *a) { int tofs, bofs; @@ -1552,7 +1843,7 @@ static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim2 *a) tofs = vsr_full_offset(a->xt); bofs = vsr_full_offset(a->xb); bofs += a->uim << MO_32; -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN bofs ^= 8 | 4; #endif @@ -1753,42 +2044,35 @@ static void gen_xxsldwi(DisasContext *ctx) tcg_temp_free_i64(xtl); } -#define VSX_EXTRACT_INSERT(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr xt, xb; \ - TCGv_i32 t0; \ - TCGv_i64 t1; \ - uint8_t uimm = UIMM4(ctx->opcode); \ - \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xt = gen_vsr_ptr(xT(ctx->opcode)); \ - xb = gen_vsr_ptr(xB(ctx->opcode)); \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i64(); \ - /* \ - * uimm > 15 out of bound and for \ - * uimm > 12 handle as per hardware in helper \ - */ \ - if (uimm > 15) { \ - tcg_gen_movi_i64(t1, 0); \ - set_cpu_vsr(xT(ctx->opcode), t1, true); \ - set_cpu_vsr(xT(ctx->opcode), t1, false); \ - return; \ - } \ - tcg_gen_movi_i32(t0, uimm); \ - gen_helper_##name(cpu_env, xt, xb, t0); \ - tcg_temp_free_ptr(xb); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i64(t1); \ -} - -VSX_EXTRACT_INSERT(xxextractuw) -VSX_EXTRACT_INSERT(xxinsertw) +static bool do_vsx_extract_insert(DisasContext *ctx, arg_XX2_uim *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i32)) +{ + TCGv_i64 zero = tcg_constant_i64(0); + TCGv_ptr xt, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + /* + * uim > 15 out of bound and for + * uim > 12 handle as per hardware in helper + */ + if (a->uim > 15) { + set_cpu_vsr(a->xt, zero, true); + set_cpu_vsr(a->xt, zero, false); + } else { + xt = gen_vsr_ptr(a->xt); + xb = gen_vsr_ptr(a->xb); + gen_helper(xt, xb, tcg_constant_i32(a->uim)); + tcg_temp_free_ptr(xb); + tcg_temp_free_ptr(xt); + } + + return true; +} + +TRANS(XXEXTRACTUW, do_vsx_extract_insert, gen_helper_XXEXTRACTUW) +TRANS(XXINSERTW, do_vsx_extract_insert, gen_helper_XXINSERTW) #ifdef TARGET_PPC64 static void gen_xsxexpdp(DisasContext *ctx) @@ -2109,7 +2393,23 @@ static void gen_xvxexpdp(DisasContext *ctx) tcg_temp_free_i64(xbl); } -GEN_VSX_HELPER_X2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300) +static bool trans_XVXSIGSP(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_ptr t, b; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + t = gen_vsr_ptr(a->xt); + b = gen_vsr_ptr(a->xb); + + gen_helper_XVXSIGSP(t, b); + + tcg_temp_free_ptr(t); + tcg_temp_free_ptr(b); + + return true; +} static void gen_xvxsigdp(DisasContext *ctx) { @@ -2765,6 +3065,129 @@ static bool trans_XVCVBF16SPN(DisasContext *ctx, arg_XX2 *a) return true; } + /* + * The PowerISA 3.1 mentions that for the current version of the + * architecture, "the hardware implementation provides the effect of + * ACC[i] and VSRs 4*i to 4*i + 3 logically containing the same data" + * and "The Accumulators introduce no new logical state at this time" + * (page 501). For now it seems unnecessary to create new structures, + * so ACC[i] is the same as VSRs 4*i to 4*i+3 and therefore + * move to and from accumulators are no-ops. + */ +static bool trans_XXMFACC(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + return true; +} + +static bool trans_XXMTACC(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + return true; +} + +static bool trans_XXSETACCZ(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + tcg_gen_gvec_dup_imm(MO_64, acc_full_offset(a->ra), 64, 64, 0); + return true; +} + +static bool do_ger(DisasContext *ctx, arg_MMIRR_XX3 *a, + void (*helper)(TCGv_env, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32)) +{ + uint32_t mask; + TCGv_ptr xt, xa, xb; + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + if (unlikely((a->xa / 4 == a->xt) || (a->xb / 4 == a->xt))) { + gen_invalid(ctx); + return true; + } + + xt = gen_acc_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + + mask = ger_pack_masks(a->pmsk, a->ymsk, a->xmsk); + helper(cpu_env, xa, xb, xt, tcg_constant_i32(mask)); + tcg_temp_free_ptr(xt); + tcg_temp_free_ptr(xa); + tcg_temp_free_ptr(xb); + return true; +} + +TRANS(XVI4GER8, do_ger, gen_helper_XVI4GER8) +TRANS(XVI4GER8PP, do_ger, gen_helper_XVI4GER8PP) +TRANS(XVI8GER4, do_ger, gen_helper_XVI8GER4) +TRANS(XVI8GER4PP, do_ger, gen_helper_XVI8GER4PP) +TRANS(XVI8GER4SPP, do_ger, gen_helper_XVI8GER4SPP) +TRANS(XVI16GER2, do_ger, gen_helper_XVI16GER2) +TRANS(XVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) +TRANS(XVI16GER2S, do_ger, gen_helper_XVI16GER2S) +TRANS(XVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) + +TRANS64(PMXVI4GER8, do_ger, gen_helper_XVI4GER8) +TRANS64(PMXVI4GER8PP, do_ger, gen_helper_XVI4GER8PP) +TRANS64(PMXVI8GER4, do_ger, gen_helper_XVI8GER4) +TRANS64(PMXVI8GER4PP, do_ger, gen_helper_XVI8GER4PP) +TRANS64(PMXVI8GER4SPP, do_ger, gen_helper_XVI8GER4SPP) +TRANS64(PMXVI16GER2, do_ger, gen_helper_XVI16GER2) +TRANS64(PMXVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) +TRANS64(PMXVI16GER2S, do_ger, gen_helper_XVI16GER2S) +TRANS64(PMXVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) + +TRANS(XVBF16GER2, do_ger, gen_helper_XVBF16GER2) +TRANS(XVBF16GER2PP, do_ger, gen_helper_XVBF16GER2PP) +TRANS(XVBF16GER2PN, do_ger, gen_helper_XVBF16GER2PN) +TRANS(XVBF16GER2NP, do_ger, gen_helper_XVBF16GER2NP) +TRANS(XVBF16GER2NN, do_ger, gen_helper_XVBF16GER2NN) + +TRANS(XVF16GER2, do_ger, gen_helper_XVF16GER2) +TRANS(XVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) +TRANS(XVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) +TRANS(XVF16GER2NP, do_ger, gen_helper_XVF16GER2NP) +TRANS(XVF16GER2NN, do_ger, gen_helper_XVF16GER2NN) + +TRANS(XVF32GER, do_ger, gen_helper_XVF32GER) +TRANS(XVF32GERPP, do_ger, gen_helper_XVF32GERPP) +TRANS(XVF32GERPN, do_ger, gen_helper_XVF32GERPN) +TRANS(XVF32GERNP, do_ger, gen_helper_XVF32GERNP) +TRANS(XVF32GERNN, do_ger, gen_helper_XVF32GERNN) + +TRANS(XVF64GER, do_ger, gen_helper_XVF64GER) +TRANS(XVF64GERPP, do_ger, gen_helper_XVF64GERPP) +TRANS(XVF64GERPN, do_ger, gen_helper_XVF64GERPN) +TRANS(XVF64GERNP, do_ger, gen_helper_XVF64GERNP) +TRANS(XVF64GERNN, do_ger, gen_helper_XVF64GERNN) + +TRANS64(PMXVBF16GER2, do_ger, gen_helper_XVBF16GER2) +TRANS64(PMXVBF16GER2PP, do_ger, gen_helper_XVBF16GER2PP) +TRANS64(PMXVBF16GER2PN, do_ger, gen_helper_XVBF16GER2PN) +TRANS64(PMXVBF16GER2NP, do_ger, gen_helper_XVBF16GER2NP) +TRANS64(PMXVBF16GER2NN, do_ger, gen_helper_XVBF16GER2NN) + +TRANS64(PMXVF16GER2, do_ger, gen_helper_XVF16GER2) +TRANS64(PMXVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) +TRANS64(PMXVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) +TRANS64(PMXVF16GER2NP, do_ger, gen_helper_XVF16GER2NP) +TRANS64(PMXVF16GER2NN, do_ger, gen_helper_XVF16GER2NN) + +TRANS64(PMXVF32GER, do_ger, gen_helper_XVF32GER) +TRANS64(PMXVF32GERPP, do_ger, gen_helper_XVF32GERPP) +TRANS64(PMXVF32GERPN, do_ger, gen_helper_XVF32GERPN) +TRANS64(PMXVF32GERNP, do_ger, gen_helper_XVF32GERNP) +TRANS64(PMXVF32GERNN, do_ger, gen_helper_XVF32GERNN) + +TRANS64(PMXVF64GER, do_ger, gen_helper_XVF64GER) +TRANS64(PMXVF64GERPP, do_ger, gen_helper_XVF64GERPP) +TRANS64(PMXVF64GERPN, do_ger, gen_helper_XVF64GERPN) +TRANS64(PMXVF64GERNP, do_ger, gen_helper_XVF64GERNP) +TRANS64(PMXVF64GERNN, do_ger, gen_helper_XVF64GERNN) + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index b8fd116728bd..a3ba094d6285 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -147,33 +147,11 @@ GEN_HANDLER_E(xsiexpdp, 0x3C, 0x16, 0x1C, 0, PPC_NONE, PPC2_ISA300), GEN_VSX_XFORM_300(xsiexpqp, 0x4, 0x1B, 0x00000001), #endif -GEN_XX2FORM(xststdcdp, 0x14, 0x16, PPC2_ISA300), -GEN_XX2FORM(xststdcsp, 0x14, 0x12, PPC2_ISA300), -GEN_VSX_XFORM_300(xststdcqp, 0x04, 0x16, 0x00000001), - GEN_XX3FORM(xviexpsp, 0x00, 0x1B, PPC2_ISA300), GEN_XX3FORM(xviexpdp, 0x00, 0x1F, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300), GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300), -GEN_XX2FORM_EO(xvxsigsp, 0x16, 0x1D, 0x09, PPC2_ISA300), - -/* DCMX = bit[25] << 6 | bit[29] << 5 | bit[11:15] */ -#define GEN_XX2FORM_DCMX(name, opc2, opc3, fl2) \ -GEN_XX3FORM(name, opc2, opc3 | 0, fl2), \ -GEN_XX3FORM(name, opc2, opc3 | 1, fl2) - -GEN_XX2FORM_DCMX(xvtstdcdp, 0x14, 0x1E, PPC2_ISA300), -GEN_XX2FORM_DCMX(xvtstdcsp, 0x14, 0x1A, PPC2_ISA300), - -GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX), -GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX), -GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX), -GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX), -GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX), -GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0), @@ -200,7 +178,6 @@ GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207), GEN_XX2FORM_EO(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300), GEN_VSX_XFORM_300_EO(xscvsdqp, 0x04, 0x1A, 0x0A, 0x00000001), GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX), -GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207), GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX), GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX), GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX), @@ -322,5 +299,3 @@ VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), -GEN_XX2FORM_EXT(xxextractuw, 0x0A, 0x0A, PPC2_ISA300), -GEN_XX2FORM_EXT(xxinsertw, 0x0A, 0x0B, PPC2_ISA300), diff --git a/target/riscv/arch_dump.c b/target/riscv/arch_dump.c index 709f621d826a..736a232956e1 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/bitmanip_helper.c b/target/riscv/bitmanip_helper.c index f1b5e5549f47..b99c4a39a1f2 100644 --- a/target/riscv/bitmanip_helper.c +++ b/target/riscv/bitmanip_helper.c @@ -49,3 +49,83 @@ target_ulong HELPER(clmulr)(target_ulong rs1, target_ulong rs2) return result; } + +static inline target_ulong do_swap(target_ulong x, uint64_t mask, int shift) +{ + return ((x & mask) << shift) | ((x & ~mask) >> shift); +} + +target_ulong HELPER(brev8)(target_ulong rs1) +{ + target_ulong x = rs1; + + x = do_swap(x, 0x5555555555555555ull, 1); + x = do_swap(x, 0x3333333333333333ull, 2); + x = do_swap(x, 0x0f0f0f0f0f0f0f0full, 4); + return x; +} + +static const uint64_t shuf_masks[] = { + dup_const(MO_8, 0x44), + dup_const(MO_8, 0x30), + dup_const(MO_16, 0x0f00), + dup_const(MO_32, 0xff0000) +}; + +static inline target_ulong do_shuf_stage(target_ulong src, uint64_t maskL, + uint64_t maskR, int shift) +{ + target_ulong x = src & ~(maskL | maskR); + + x |= ((src << shift) & maskL) | ((src >> shift) & maskR); + return x; +} + +target_ulong HELPER(unzip)(target_ulong rs1) +{ + target_ulong x = rs1; + + x = do_shuf_stage(x, shuf_masks[0], shuf_masks[0] >> 1, 1); + x = do_shuf_stage(x, shuf_masks[1], shuf_masks[1] >> 2, 2); + x = do_shuf_stage(x, shuf_masks[2], shuf_masks[2] >> 4, 4); + x = do_shuf_stage(x, shuf_masks[3], shuf_masks[3] >> 8, 8); + return x; +} + +target_ulong HELPER(zip)(target_ulong rs1) +{ + target_ulong x = rs1; + + x = do_shuf_stage(x, shuf_masks[3], shuf_masks[3] >> 8, 8); + x = do_shuf_stage(x, shuf_masks[2], shuf_masks[2] >> 4, 4); + x = do_shuf_stage(x, shuf_masks[1], shuf_masks[1] >> 2, 2); + x = do_shuf_stage(x, shuf_masks[0], shuf_masks[0] >> 1, 1); + return x; +} + +static inline target_ulong do_xperm(target_ulong rs1, target_ulong rs2, + uint32_t sz_log2) +{ + target_ulong r = 0; + target_ulong sz = 1LL << sz_log2; + target_ulong mask = (1LL << sz) - 1; + target_ulong pos; + + for (int i = 0; i < TARGET_LONG_BITS; i += sz) { + pos = ((rs2 >> i) & mask) << sz_log2; + if (pos < sizeof(target_ulong) * 8) { + r |= ((rs1 >> pos) & mask) << i; + } + } + return r; +} + +target_ulong HELPER(xperm4)(target_ulong rs1, target_ulong rs2) +{ + return do_xperm(rs1, rs2, 2); +} + +target_ulong HELPER(xperm8)(target_ulong rs1, target_ulong rs2) +{ + return do_xperm(rs1, rs2, 3); +} diff --git a/target/riscv/common-semi-target.h b/target/riscv/common-semi-target.h new file mode 100644 index 000000000000..7c8a59e0cc3c --- /dev/null +++ b/target/riscv/common-semi-target.h @@ -0,0 +1,50 @@ +/* + * Target-specific parts of semihosting/arm-compat-semi.c. + * + * Copyright (c) 2005, 2007 CodeSourcery. + * Copyright (c) 2019, 2022 Linaro + * Copyright © 2020 by Keith Packard + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_RISCV_COMMON_SEMI_TARGET_H +#define TARGET_RISCV_COMMON_SEMI_TARGET_H + +static inline target_ulong common_semi_arg(CPUState *cs, int argno) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + return env->gpr[xA0 + argno]; +} + +static inline void common_semi_set_ret(CPUState *cs, target_ulong ret) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + env->gpr[xA0] = ret; +} + +static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr) +{ + return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8); +} + +static inline bool is_64bit_semihosting(CPUArchState *env) +{ + return riscv_cpu_mxl(env) != MXL_RV32; +} + +static inline target_ulong common_semi_stack_bottom(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + return env->gpr[xSP]; +} + +static inline bool common_semi_has_synccache(CPUArchState *env) +{ + return true; +} + +#endif diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h index 80eb615f93f4..ebaf26d26ddc 100644 --- a/target/riscv/cpu-param.h +++ b/target/riscv/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef RISCV_CPU_PARAM_H -#define RISCV_CPU_PARAM_H 1 +#define RISCV_CPU_PARAM_H #if defined(TARGET_RISCV64) # define TARGET_LONG_BITS 64 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ddda4906ffb7..cc75ca76677f 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" @@ -34,7 +36,97 @@ /* RISC-V CPU definitions */ -static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG"; +#define RISCV_CPU_MARCHID ((QEMU_VERSION_MAJOR << 16) | \ + (QEMU_VERSION_MINOR << 8) | \ + (QEMU_VERSION_MICRO)) +#define RISCV_CPU_MIMPID RISCV_CPU_MARCHID + +static const char riscv_single_letter_exts[] = "IEMAFDQCPVH"; + +struct isa_ext_data { + const char *name; + 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(zawrs, true, PRIV_VERSION_1_12_0, ext_zawrs), + 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", @@ -108,6 +200,8 @@ static const char * const riscv_intr_names[] = { "reserved" }; +static void register_cpu_props(DeviceState *dev); + const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { if (async) { @@ -135,13 +229,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; @@ -150,7 +237,8 @@ static void riscv_any_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif - set_priv_version(env, PRIV_VERSION_1_11_0); + set_priv_version(env, PRIV_VERSION_1_12_0); + register_cpu_props(DEVICE(obj)); } #if defined(TARGET_RISCV64) @@ -159,6 +247,9 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); + register_cpu_props(DEVICE(obj)); + /* Set latest version of privileged specification */ + set_priv_version(env, PRIV_VERSION_1_12_0); } static void rv64_sifive_u_cpu_init(Object *obj) @@ -171,9 +262,11 @@ static void rv64_sifive_u_cpu_init(Object *obj) static void rv64_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); + cpu->cfg.mmu = false; } static void rv128_base_cpu_init(Object *obj) @@ -187,6 +280,9 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); + register_cpu_props(DEVICE(obj)); + /* Set latest version of privileged specification */ + set_priv_version(env, PRIV_VERSION_1_12_0); } #else static void rv32_base_cpu_init(Object *obj) @@ -194,6 +290,9 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); + register_cpu_props(DEVICE(obj)); + /* Set latest version of privileged specification */ + set_priv_version(env, PRIV_VERSION_1_12_0); } static void rv32_sifive_u_cpu_init(Object *obj) @@ -206,27 +305,32 @@ static void rv32_sifive_u_cpu_init(Object *obj) static void rv32_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); + cpu->cfg.mmu = false; } static void rv32_ibex_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); - set_priv_version(env, PRIV_VERSION_1_10_0); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); - qdev_prop_set_bit(DEVICE(obj), "x-epmp", true); + set_priv_version(env, PRIV_VERSION_1_11_0); + cpu->cfg.mmu = false; + cpu->cfg.epmp = true; } static void rv32_imafcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(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); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); + cpu->cfg.mmu = false; } #endif @@ -239,6 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif + register_cpu_props(DEVICE(obj)); } #endif @@ -278,6 +383,10 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) CSR_MHARTID, CSR_MSTATUS, CSR_MSTATUSH, + /* + * CSR_SSTATUS is intentionally omitted here as its value + * can be figured out by looking at CSR_MSTATUS + */ CSR_HSTATUS, CSR_VSSTATUS, CSR_MIP, @@ -358,6 +467,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) { @@ -366,9 +487,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); } } @@ -381,35 +502,42 @@ static bool riscv_cpu_has_work(CPUState *cs) * Definition of the WFI instruction requires it to ignore the privilege * mode and delegation registers, but respect individual enables */ - return (env->mip & env->mie) != 0; + return riscv_cpu_all_pending(env) != 0; #else return true; #endif } -void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, - target_ulong *data) +static void riscv_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); + if (xl == MXL_RV32) { env->pc = (int32_t)data[0]; } else { env->pc = data[0]; } + env->bins = data[1]; } -static void riscv_cpu_reset(DeviceState *dev) +static void riscv_cpu_reset_hold(Object *obj) { #ifndef CONFIG_USER_ONLY uint8_t iprio; int i, irq, rdzero; #endif - CPUState *cs = CPU(dev); + CPUState *cs = CPU(obj); RISCVCPU *cpu = RISCV_CPU(cs); RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); CPURISCVState *env = &cpu->env; - mcc->parent_reset(dev); + if (mcc->parent_phases.hold) { + mcc->parent_phases.hold(obj); + } #ifndef CONFIG_USER_ONLY env->misa_mxl = env->misa_mxl_max; env->priv = PRV_M; @@ -435,6 +563,7 @@ static void riscv_cpu_reset(DeviceState *dev) env->mcause = 0; env->miclaim = MIP_SGEIP; env->pc = env->resetvec; + env->bins = 0; env->two_stage_lookup = false; /* Initialized default priorities of local interrupts. */ @@ -461,6 +590,10 @@ static void riscv_cpu_reset(DeviceState *dev) set_default_nan_mode(1, &env->fp_status); #ifndef CONFIG_USER_ONLY + if (riscv_feature(env, RISCV_FEATURE_DEBUG)) { + riscv_trigger_init(env); + } + if (kvm_enabled()) { kvm_riscv_reset_vcpu(cpu); } @@ -493,7 +626,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 = 0; + int i, priv_version = -1; Error *local_err = NULL; cpu_exec_realizefn(cs, &local_err); @@ -503,7 +636,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } if (cpu->cfg.priv_spec) { - if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) { + if (!g_strcmp0(cpu->cfg.priv_spec, "v1.12.0")) { + priv_version = PRIV_VERSION_1_12_0; + } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) { priv_version = PRIV_VERSION_1_11_0; } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { priv_version = PRIV_VERSION_1_10_0; @@ -515,10 +650,25 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } } - if (priv_version) { + if (priv_version >= PRIV_VERSION_1_10_0) { set_priv_version(env, priv_version); - } else if (!env->priv_ver) { - set_priv_version(env, PRIV_VERSION_1_11_0); + } + + /* 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) { @@ -537,11 +687,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) { @@ -564,35 +719,120 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) uint32_t ext = 0; /* Do some ISA extension error checking */ + if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m && + cpu->cfg.ext_a && cpu->cfg.ext_f && + cpu->cfg.ext_d && + cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); + cpu->cfg.ext_i = true; + cpu->cfg.ext_m = true; + cpu->cfg.ext_a = true; + cpu->cfg.ext_f = true; + cpu->cfg.ext_d = true; + cpu->cfg.ext_icsr = true; + cpu->cfg.ext_ifencei = true; + } + if (cpu->cfg.ext_i && cpu->cfg.ext_e) { error_setg(errp, "I and E extensions are incompatible"); - return; - } + return; + } if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { error_setg(errp, "Either I or E extension must be set"); - return; - } + return; + } - if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m & - cpu->cfg.ext_a & cpu->cfg.ext_f & - cpu->cfg.ext_d)) { - warn_report("Setting G will also set IMAFD"); - cpu->cfg.ext_i = true; - cpu->cfg.ext_m = true; - cpu->cfg.ext_a = true; - cpu->cfg.ext_f = true; - cpu->cfg.ext_d = true; + 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; + } + + if ((cpu->cfg.ext_zawrs) && !cpu->cfg.ext_a) { + error_setg(errp, "Zawrs extension requires A extension"); + return; + } + + if ((cpu->cfg.ext_zfh || cpu->cfg.ext_zfhmin) && !cpu->cfg.ext_f) { + error_setg(errp, "Zfh/Zfhmin extensions require F extension"); + return; + } + + if (cpu->cfg.ext_d && !cpu->cfg.ext_f) { + error_setg(errp, "D extension requires F extension"); + return; + } + + if (cpu->cfg.ext_v && !cpu->cfg.ext_d) { + error_setg(errp, "V extension requires D extension"); + return; + } + + if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { + error_setg(errp, "Zve32f/Zve64f extensions require F extension"); + return; + } + + /* Set the ISA extensions, checks should have happened above */ if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx || cpu->cfg.ext_zhinxmin) { cpu->cfg.ext_zfinx = true; } - /* Set the ISA extensions, checks should have happened above */ + if (cpu->cfg.ext_zfinx) { + if (!cpu->cfg.ext_icsr) { + error_setg(errp, "Zfinx extension requires Zicsr"); + return; + } + if (cpu->cfg.ext_f) { + error_setg(errp, + "Zfinx cannot be supported together with F extension"); + return; + } + } + + if (cpu->cfg.ext_zk) { + cpu->cfg.ext_zkn = true; + cpu->cfg.ext_zkr = true; + cpu->cfg.ext_zkt = true; + } + + if (cpu->cfg.ext_zkn) { + cpu->cfg.ext_zbkb = true; + cpu->cfg.ext_zbkc = true; + cpu->cfg.ext_zbkx = true; + cpu->cfg.ext_zkne = true; + cpu->cfg.ext_zknd = true; + cpu->cfg.ext_zknh = true; + } + + if (cpu->cfg.ext_zks) { + cpu->cfg.ext_zbkb = true; + cpu->cfg.ext_zbkc = true; + cpu->cfg.ext_zbkx = true; + cpu->cfg.ext_zksed = true; + cpu->cfg.ext_zksh = true; + } + if (cpu->cfg.ext_i) { ext |= RVI; } @@ -663,24 +903,22 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } set_vext_version(env, vext_version); } - if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { - error_setg(errp, "Zve32f/Zve64f extension depends upon RVF."); - return; - } if (cpu->cfg.ext_j) { ext |= RVJ; } - if (cpu->cfg.ext_zfinx && ((ext & (RVF | RVD)) || cpu->cfg.ext_zfh || - cpu->cfg.ext_zfhmin)) { - error_setg(errp, - "'Zfinx' cannot be supported together with 'F', 'D', 'Zfh'," - " 'Zfhmin'"); - return; - } 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); @@ -706,15 +944,23 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level) case IRQ_VS_TIMER: case IRQ_M_TIMER: case IRQ_U_EXT: - case IRQ_S_EXT: case IRQ_VS_EXT: case IRQ_M_EXT: - if (kvm_enabled()) { + if (kvm_enabled()) { kvm_riscv_set_irq(cpu, irq, level); - } else { + } else { riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level)); - } + } break; + case IRQ_S_EXT: + if (kvm_enabled()) { + kvm_riscv_set_irq(cpu, irq, level); + } else { + env->external_seip = level; + riscv_cpu_update_mip(cpu, 1 << irq, + BOOL_TO_MASK(level | env->software_seip)); + } + break; default: g_assert_not_reached(); } @@ -749,6 +995,11 @@ static void riscv_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); + cpu->cfg.ext_ifencei = true; + cpu->cfg.ext_icsr = true; + cpu->cfg.mmu = true; + cpu->cfg.pmp = true; + cpu_set_cpustate_pointers(cpu); #ifndef CONFIG_USER_ONLY @@ -757,11 +1008,11 @@ static void riscv_cpu_init(Object *obj) #endif /* CONFIG_USER_ONLY */ } -static Property riscv_cpu_properties[] = { +static Property riscv_cpu_extensions[] = { /* Defaults for standard extensions */ DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true), DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false), - DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true), + DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, false), DEFINE_PROP_BOOL("m", RISCVCPU, cfg.ext_m, true), DEFINE_PROP_BOOL("a", RISCVCPU, cfg.ext_a, true), DEFINE_PROP_BOOL("f", RISCVCPU, cfg.ext_f, true), @@ -771,15 +1022,19 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true), DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false), DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, true), - DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, 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("Zawrs", RISCVCPU, cfg.ext_zawrs, 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), @@ -793,13 +1048,28 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("zba", RISCVCPU, cfg.ext_zba, true), DEFINE_PROP_BOOL("zbb", RISCVCPU, cfg.ext_zbb, true), DEFINE_PROP_BOOL("zbc", RISCVCPU, cfg.ext_zbc, true), + DEFINE_PROP_BOOL("zbkb", RISCVCPU, cfg.ext_zbkb, false), + DEFINE_PROP_BOOL("zbkc", RISCVCPU, cfg.ext_zbkc, false), + DEFINE_PROP_BOOL("zbkx", RISCVCPU, cfg.ext_zbkx, false), DEFINE_PROP_BOOL("zbs", RISCVCPU, cfg.ext_zbs, true), + DEFINE_PROP_BOOL("zk", RISCVCPU, cfg.ext_zk, false), + DEFINE_PROP_BOOL("zkn", RISCVCPU, cfg.ext_zkn, false), + DEFINE_PROP_BOOL("zknd", RISCVCPU, cfg.ext_zknd, false), + DEFINE_PROP_BOOL("zkne", RISCVCPU, cfg.ext_zkne, false), + DEFINE_PROP_BOOL("zknh", RISCVCPU, cfg.ext_zknh, false), + DEFINE_PROP_BOOL("zkr", RISCVCPU, cfg.ext_zkr, false), + DEFINE_PROP_BOOL("zks", RISCVCPU, cfg.ext_zks, false), + DEFINE_PROP_BOOL("zksed", RISCVCPU, cfg.ext_zksed, false), + DEFINE_PROP_BOOL("zksh", RISCVCPU, cfg.ext_zksh, false), + DEFINE_PROP_BOOL("zkt", RISCVCPU, cfg.ext_zkt, false), DEFINE_PROP_BOOL("zdinx", RISCVCPU, cfg.ext_zdinx, false), DEFINE_PROP_BOOL("zfinx", RISCVCPU, cfg.ext_zfinx, false), 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), @@ -807,9 +1077,36 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, 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(), +}; + +static void register_cpu_props(DeviceState *dev) +{ + Property *prop; + + for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { + qdev_property_add_static(dev, prop); + } +} + +static Property riscv_cpu_properties[] = { + DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), + + DEFINE_PROP_UINT32("mvendorid", RISCVCPU, cfg.mvendorid, 0), + DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID), + DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID), + +#ifndef CONFIG_USER_ONLY + DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), +#endif - DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), + 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(), }; @@ -858,6 +1155,7 @@ static const struct SysemuCPUOps riscv_sysemu_ops = { static const struct TCGCPUOps riscv_tcg_ops = { .initialize = riscv_translate_init, .synchronize_from_tb = riscv_cpu_synchronize_from_tb, + .restore_state_to_opc = riscv_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = riscv_cpu_tlb_fill, @@ -865,6 +1163,9 @@ static const struct TCGCPUOps riscv_tcg_ops = { .do_interrupt = riscv_cpu_do_interrupt, .do_transaction_failed = riscv_cpu_do_transaction_failed, .do_unaligned_access = riscv_cpu_do_unaligned_access, + .debug_excp_handler = riscv_cpu_debug_excp_handler, + .debug_check_breakpoint = riscv_cpu_debug_check_breakpoint, + .debug_check_watchpoint = riscv_cpu_debug_check_watchpoint, #endif /* !CONFIG_USER_ONLY */ }; @@ -873,16 +1174,19 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); device_class_set_parent_realize(dc, riscv_cpu_realize, &mcc->parent_realize); - device_class_set_parent_reset(dc, riscv_cpu_reset, &mcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, riscv_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = riscv_cpu_class_by_name; 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; @@ -898,18 +1202,39 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) device_class_set_props(dc, riscv_cpu_properties); } +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; + + for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { + 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; + } + } + + *isa_str = new; +} + char *riscv_isa_string(RISCVCPU *cpu) { int i; - const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1; + const size_t maxlen = sizeof("rv128") + sizeof(riscv_single_letter_exts); char *isa_str = g_new(char, maxlen); char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS); - for (i = 0; i < sizeof(riscv_exts); i++) { - if (cpu->env.misa_ext & RV(riscv_exts[i])) { - *p++ = qemu_tolower(riscv_exts[i]); + for (i = 0; i < sizeof(riscv_single_letter_exts) - 1; i++) { + if (cpu->env.misa_ext & RV(riscv_single_letter_exts[i])) { + *p++ = qemu_tolower(riscv_single_letter_exts[i]); } } *p = '\0'; + if (!cpu->cfg.short_isa_string) { + riscv_isa_string_ext(cpu, &isa_str, maxlen); + } return isa_str; } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index c069fe85fa1b..f5609b62a23b 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -23,13 +23,19 @@ #include "hw/core/cpu.h" #include "hw/registerfields.h" #include "exec/cpu-defs.h" -#include "fpu/softfloat-types.h" +#include "qemu/cpu-float.h" #include "qom/object.h" #include "qemu/int128.h" #include "cpu_bits.h" #define TCG_GUEST_DEFAULT_MO 0 +/* + * RISC-V-specific extra insn start words: + * 1: Original instruction opcode + */ +#define TARGET_INSN_START_EXTRA_WORDS 1 + #define TYPE_RISCV_CPU "riscv-cpu" #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU @@ -79,11 +85,15 @@ enum { RISCV_FEATURE_PMP, RISCV_FEATURE_EPMP, RISCV_FEATURE_MISA, - RISCV_FEATURE_AIA + RISCV_FEATURE_DEBUG }; -#define PRIV_VERSION_1_10_0 0x00011000 -#define PRIV_VERSION_1_11_0 0x00011100 +/* Privileged specification version */ +enum { + PRIV_VERSION_1_10_0 = 0, + PRIV_VERSION_1_11_0, + PRIV_VERSION_1_12_0, +}; #define VEXT_VERSION_1_00_0 0x00010000 @@ -102,9 +112,12 @@ typedef struct CPUArchState CPURISCVState; #if !defined(CONFIG_USER_ONLY) #include "pmp.h" +#include "debug.h" #endif #define RV_VLEN_MAX 1024 +#define RV_MAX_MHPMEVENTS 32 +#define RV_MAX_MHPMCOUNTERS 32 FIELD(VTYPE, VLMUL, 0, 3) FIELD(VTYPE, VSEW, 3, 3) @@ -113,6 +126,20 @@ FIELD(VTYPE, VMA, 7, 1) FIELD(VTYPE, VEDIV, 8, 2) FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11) +typedef struct PMUCTRState { + /* Current value of a counter */ + target_ulong mhpmcounter_val; + /* Current value of a counter in RV32*/ + target_ulong mhpmcounterh_val; + /* Snapshot values of counter */ + target_ulong mhpmcounter_prev; + /* 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 { target_ulong gpr[32]; target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */ @@ -134,7 +161,7 @@ struct CPUArchState { target_ulong frm; target_ulong badaddr; - uint32_t bins; + target_ulong bins; target_ulong guest_phys_fault_addr; @@ -163,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; /* @@ -173,6 +200,14 @@ struct CPUArchState { uint64_t mstatus; uint64_t mip; + /* + * MIP contains the software writable version of SEIP ORed with the + * external interrupt value. The MIP register is always up-to-date. + * To keep track of the current source, we also save booleans of the values + * here. + */ + bool external_seip; + bool software_seip; uint64_t miclaim; @@ -251,25 +286,56 @@ 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; + target_ulong mcountinhibit; + + /* PMU counter state */ + PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS]; + + /* 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; target_ulong mseccfg; + /* trigger module */ + target_ulong trigger_cur; + 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]; + QEMUTimer *itrigger_timer[RV_MAX_TRIGGERS]; + int64_t last_icount; + bool itrigger_enabled; + /* machine specific rdtime callback */ - uint64_t (*rdtime_fn)(uint32_t); - uint32_t rdtime_fn_arg; + uint64_t (*rdtime_fn)(void *); + void *rdtime_fn_arg; /* machine specific AIA ireg read-modify-write callback */ #define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen) \ @@ -300,6 +366,14 @@ struct CPUArchState { target_ulong spmbase; target_ulong upmmask; target_ulong upmbase; + + /* CSRs for execution enviornment configuration */ + uint64_t menvcfg; + uint64_t mstateen[SMSTATEEN_MAX_COUNT]; + uint64_t hstateen[SMSTATEEN_MAX_COUNT]; + uint64_t sstateen[SMSTATEEN_MAX_COUNT]; + target_ulong senvcfg; + uint64_t henvcfg; #endif target_ulong cur_pmmask; target_ulong cur_pmbase; @@ -307,7 +381,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; @@ -325,7 +401,7 @@ OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) /** * RISCVCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A RISCV CPU model. */ @@ -334,7 +410,7 @@ struct RISCVCPUClass { CPUClass parent_class; /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; struct RISCVCPUConfig { @@ -354,14 +430,30 @@ struct RISCVCPUConfig { bool ext_zba; bool ext_zbb; bool ext_zbc; + bool ext_zbkb; + bool ext_zbkc; + bool ext_zbkx; bool ext_zbs; - bool ext_counters; + bool ext_zk; + bool ext_zkn; + bool ext_zknd; + bool ext_zkne; + bool ext_zknh; + bool ext_zkr; + bool ext_zks; + bool ext_zksed; + bool ext_zksh; + bool ext_zkt; bool ext_ifencei; bool ext_icsr; + bool ext_zihintpause; + bool ext_smstateen; + bool ext_sstc; bool ext_svinval; bool ext_svnapot; bool ext_svpbmt; bool ext_zdinx; + bool ext_zawrs; bool ext_zfh; bool ext_zfhmin; bool ext_zfinx; @@ -369,10 +461,21 @@ struct RISCVCPUConfig { bool ext_zhinxmin; 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; + uint64_t mimpid; /* Vendor-specific custom extensions */ bool ext_XVentanaCondOps; + uint8_t pmu_num; char *priv_spec; char *user_spec; char *bext_spec; @@ -382,8 +485,9 @@ struct RISCVCPUConfig { bool mmu; bool pmp; bool epmp; - bool aia; - uint64_t resetvec; + bool debug; + + bool short_isa_string; }; typedef struct RISCVCPUConfig RISCVCPUConfig; @@ -406,6 +510,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) @@ -432,13 +542,14 @@ 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); uint8_t riscv_cpu_default_priority(int irq); +uint64_t riscv_cpu_all_pending(CPURISCVState *env); int riscv_cpu_mirq_pending(CPURISCVState *env); int riscv_cpu_sirq_pending(CPURISCVState *env); int riscv_cpu_vsirq_pending(CPURISCVState *env); @@ -451,9 +562,9 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable); bool riscv_cpu_two_stage_lookup(int mmu_idx); int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch); hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); @@ -474,8 +585,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts); uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value); #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ -void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), - uint32_t arg); +void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *), + void *arg); void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv, int (*rmw_fn)(void *arg, target_ulong reg, @@ -487,8 +598,8 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv, void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv); void riscv_translate_init(void); -void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env, - uint32_t exception, uintptr_t pc); +G_NORETURN void riscv_raise_exception(CPURISCVState *env, + uint32_t exception, uintptr_t pc); target_ulong riscv_cpu_get_fflags(CPURISCVState *env); void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); @@ -516,6 +627,10 @@ FIELD(TB_FLAGS, XL, 20, 2) /* If PointerMasking should be applied */ 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) +/* Native debug itrigger */ +FIELD(TB_FLAGS, ITRIGGER, 26, 1) #ifdef TARGET_RISCV32 #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) @@ -654,6 +769,8 @@ typedef struct { riscv_csr_op_fn op; riscv_csr_read128_fn read128; riscv_csr_write128_fn write128; + /* The default priv spec version should be PRIV_VERSION_1_10_0 (i.e 0) */ + uint32_t min_priv_ver; } riscv_csr_operations; /* CSR function table constants */ @@ -661,6 +778,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 0fe01d7da57f..8b0d7e20eac8 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -148,6 +148,7 @@ #define CSR_MARCHID 0xf12 #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 +#define CSR_MCONFIGPTR 0xf15 /* Machine Trap Setup */ #define CSR_MSTATUS 0x300 @@ -173,14 +174,8 @@ #define CSR_MIREG 0x351 /* Machine-Level Interrupts (AIA) */ -#define CSR_MTOPI 0xfb0 - -/* Machine-Level IMSIC Interface (AIA) */ -#define CSR_MSETEIPNUM 0x358 -#define CSR_MCLREIPNUM 0x359 -#define CSR_MSETEIENUM 0x35a -#define CSR_MCLREIENUM 0x35b #define CSR_MTOPEI 0x35c +#define CSR_MTOPI 0xfb0 /* Virtual Interrupts for Supervisor Level (AIA) */ #define CSR_MVIEN 0x308 @@ -195,12 +190,19 @@ /* 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 +/* Supervisor Configuration CSRs */ +#define CSR_SENVCFG 0x10A + +/* Supervisor state CSRs */ +#define CSR_SSTATEEN0 0x10C +#define CSR_SSTATEEN1 0x10D +#define CSR_SSTATEEN2 0x10E +#define CSR_SSTATEEN3 0x10F + /* Supervisor Trap Handling */ #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 @@ -208,6 +210,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 @@ -217,14 +223,8 @@ #define CSR_SIREG 0x151 /* Supervisor-Level Interrupts (AIA) */ -#define CSR_STOPI 0xdb0 - -/* Supervisor-Level IMSIC Interface (AIA) */ -#define CSR_SSETEIPNUM 0x158 -#define CSR_SCLREIPNUM 0x159 -#define CSR_SSETEIENUM 0x15a -#define CSR_SCLREIENUM 0x15b #define CSR_STOPEI 0x15c +#define CSR_STOPI 0xdb0 /* Supervisor-Level High-Half CSRs (AIA) */ #define CSR_SIEH 0x114 @@ -246,6 +246,20 @@ #define CSR_HTIMEDELTA 0x605 #define CSR_HTIMEDELTAH 0x615 +/* Hypervisor Configuration CSRs */ +#define CSR_HENVCFG 0x60A +#define CSR_HENVCFGH 0x61A + +/* Hypervisor state CSRs */ +#define CSR_HSTATEEN0 0x60C +#define CSR_HSTATEEN0H 0x61C +#define CSR_HSTATEEN1 0x60D +#define CSR_HSTATEEN1H 0x61D +#define CSR_HSTATEEN2 0x60E +#define CSR_HSTATEEN2H 0x61E +#define CSR_HSTATEEN3 0x60F +#define CSR_HSTATEEN3H 0x61F + /* Virtual CSRs */ #define CSR_VSSTATUS 0x200 #define CSR_VSIE 0x204 @@ -257,6 +271,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 @@ -271,14 +289,8 @@ #define CSR_VSIREG 0x251 /* VS-Level Interrupts (H-extension with AIA) */ -#define CSR_VSTOPI 0xeb0 - -/* VS-Level IMSIC Interface (H-extension with AIA) */ -#define CSR_VSSETEIPNUM 0x258 -#define CSR_VSCLREIPNUM 0x259 -#define CSR_VSSETEIENUM 0x25a -#define CSR_VSCLREIENUM 0x25b #define CSR_VSTOPEI 0x25c +#define CSR_VSTOPI 0xeb0 /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ #define CSR_HIDELEGH 0x613 @@ -289,6 +301,31 @@ #define CSR_VSIEH 0x214 #define CSR_VSIPH 0x254 +/* Machine Configuration CSRs */ +#define CSR_MENVCFG 0x30A +#define CSR_MENVCFGH 0x31A + +/* Machine state CSRs */ +#define CSR_MSTATEEN0 0x30C +#define CSR_MSTATEEN0H 0x31C +#define CSR_MSTATEEN1 0x30D +#define CSR_MSTATEEN1H 0x31D +#define CSR_MSTATEEN2 0x30E +#define CSR_MSTATEEN2H 0x31E +#define CSR_MSTATEEN3 0x30F +#define CSR_MSTATEEN3H 0x31F + +/* Common defines for all smstateen */ +#define SMSTATEEN_MAX_COUNT 4 +#define SMSTATEEN0_CS (1ULL << 0) +#define SMSTATEEN0_FCSR (1ULL << 1) +#define SMSTATEEN0_HSCONTXT (1ULL << 57) +#define SMSTATEEN0_IMSIC (1ULL << 58) +#define SMSTATEEN0_AIA (1ULL << 59) +#define SMSTATEEN0_SVSLCT (1ULL << 60) +#define SMSTATEEN0_HSENVCFG (1ULL << 62) +#define SMSTATEEN_STATEEN (1ULL << 63) + /* Enhanced Physical Memory Protection (ePMP) */ #define CSR_MSECCFG 0x747 #define CSR_MSECCFGH 0x757 @@ -319,6 +356,7 @@ #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 +#define CSR_TINFO 0x7a4 /* Debug Mode Registers */ #define CSR_DCSR 0x7b0 @@ -355,6 +393,10 @@ #define CSR_MHPMCOUNTER29 0xb1d #define CSR_MHPMCOUNTER30 0xb1e #define CSR_MHPMCOUNTER31 0xb1f + +/* Machine counter-inhibit register */ +#define CSR_MCOUNTINHIBIT 0x320 + #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 @@ -384,6 +426,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 @@ -445,6 +518,10 @@ #define CSR_VSMTE 0x2c0 #define CSR_VSPMMASK 0x2c1 #define CSR_VSPMBASE 0x2c2 +#define CSR_SCOUNTOVF 0xda0 + +/* Crypto Extension */ +#define CSR_SEED 0x015 /* mstatus CSR bits */ #define MSTATUS_UIE 0x00000001 @@ -619,6 +696,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) @@ -636,11 +714,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) @@ -662,6 +742,34 @@ typedef enum RISCVException { #define PM_EXT_CLEAN 0x00000002ULL #define PM_EXT_DIRTY 0x00000003ULL +/* Execution enviornment configuration bits */ +#define MENVCFG_FIOM BIT(0) +#define MENVCFG_CBIE (3UL << 4) +#define MENVCFG_CBCFE BIT(6) +#define MENVCFG_CBZE BIT(7) +#define MENVCFG_PBMTE (1ULL << 62) +#define MENVCFG_STCE (1ULL << 63) + +/* For RV32 */ +#define MENVCFGH_PBMTE BIT(30) +#define MENVCFGH_STCE BIT(31) + +#define SENVCFG_FIOM MENVCFG_FIOM +#define SENVCFG_CBIE MENVCFG_CBIE +#define SENVCFG_CBCFE MENVCFG_CBCFE +#define SENVCFG_CBZE MENVCFG_CBZE + +#define HENVCFG_FIOM MENVCFG_FIOM +#define HENVCFG_CBIE MENVCFG_CBIE +#define HENVCFG_CBCFE MENVCFG_CBCFE +#define HENVCFG_CBZE MENVCFG_CBZE +#define HENVCFG_PBMTE MENVCFG_PBMTE +#define HENVCFG_STCE MENVCFG_STCE + +/* For RV32 */ +#define HENVCFGH_PBMTE MENVCFGH_PBMTE +#define HENVCFGH_STCE MENVCFGH_STCE + /* Offsets for every pair of control bits per each priv level */ #define XS_OFFSET 0ULL #define U_OFFSET 2ULL @@ -745,7 +853,7 @@ typedef enum RISCVException { #define IPRIO_IRQ_BITS 8 #define IPRIO_MMAXIPRIO 255 #define IPRIO_DEFAULT_UPPER 4 -#define IPRIO_DEFAULT_MIDDLE (IPRIO_DEFAULT_UPPER + 24) +#define IPRIO_DEFAULT_MIDDLE (IPRIO_DEFAULT_UPPER + 12) #define IPRIO_DEFAULT_M IPRIO_DEFAULT_MIDDLE #define IPRIO_DEFAULT_S (IPRIO_DEFAULT_M + 3) #define IPRIO_DEFAULT_SGEXT (IPRIO_DEFAULT_S + 3) @@ -760,4 +868,30 @@ typedef enum RISCVException { #define HVICTL_VALID_MASK \ (HVICTL_VTI | HVICTL_IID | HVICTL_IPRIOM | HVICTL_IPRIO) +/* seed CSR bits */ +#define SEED_OPST (0b11 << 30) +#define SEED_OPST_BIST (0b00 << 30) +#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 1c60fb2e8057..8ea3442b4a39 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -21,10 +21,15 @@ #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 "sysemu/cpu-timers.h" +#include "cpu_bits.h" +#include "debug.h" int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) { @@ -65,6 +70,10 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, flags = FIELD_DP32(flags, TB_FLAGS, LMUL, FIELD_EX64(env->vtype, VTYPE, VLMUL)); 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); } @@ -96,6 +105,9 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_VS, get_field(env->mstatus_hs, MSTATUS_VS)); } + if (riscv_feature(env, RISCV_FEATURE_DEBUG) && !icount_enabled()) { + flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled); + } #endif flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl); @@ -166,17 +178,17 @@ void riscv_cpu_update_mask(CPURISCVState *env) * 14 " * 15 " * 16 " - * 18 Debug/trace interrupt - * 20 (Reserved interrupt) + * 17 " + * 18 " + * 19 " + * 20 " + * 21 " * 22 " - * 24 " - * 26 " - * 28 " - * 30 (Reserved for standard reporting of bus or system errors) + * 23 " */ static const int hviprio_index2irq[] = { - 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 }; + 0, 1, 4, 5, 8, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; static const int hviprio_index2rdzero[] = { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -205,50 +217,60 @@ int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero) * Default | * Priority | Major Interrupt Numbers * ---------------------------------------------------------------- - * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c), - * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38), - * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34), - * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30) + * Highest | 47, 23, 46, 45, 22, 44, + * | 43, 21, 42, 41, 20, 40 * | * | 11 (0b), 3 (03), 7 (07) * | 9 (09), 1 (01), 5 (05) * | 12 (0c) * | 10 (0a), 2 (02), 6 (06) * | - * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c), - * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28), - * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24), - * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20) + * | 39, 19, 38, 37, 18, 36, + * Lowest | 35, 17, 34, 33, 16, 32 * ---------------------------------------------------------------- */ static const uint8_t default_iprio[64] = { - [63] = IPRIO_DEFAULT_UPPER, - [62] = IPRIO_DEFAULT_UPPER + 1, - [31] = IPRIO_DEFAULT_UPPER + 2, - [30] = IPRIO_DEFAULT_UPPER + 3, - [61] = IPRIO_DEFAULT_UPPER + 4, - [60] = IPRIO_DEFAULT_UPPER + 5, - - [59] = IPRIO_DEFAULT_UPPER + 6, - [58] = IPRIO_DEFAULT_UPPER + 7, - [29] = IPRIO_DEFAULT_UPPER + 8, - [28] = IPRIO_DEFAULT_UPPER + 9, - [57] = IPRIO_DEFAULT_UPPER + 10, - [56] = IPRIO_DEFAULT_UPPER + 11, - - [55] = IPRIO_DEFAULT_UPPER + 12, - [54] = IPRIO_DEFAULT_UPPER + 13, - [27] = IPRIO_DEFAULT_UPPER + 14, - [26] = IPRIO_DEFAULT_UPPER + 15, - [53] = IPRIO_DEFAULT_UPPER + 16, - [52] = IPRIO_DEFAULT_UPPER + 17, - - [51] = IPRIO_DEFAULT_UPPER + 18, - [50] = IPRIO_DEFAULT_UPPER + 19, - [25] = IPRIO_DEFAULT_UPPER + 20, - [24] = IPRIO_DEFAULT_UPPER + 21, - [49] = IPRIO_DEFAULT_UPPER + 22, - [48] = IPRIO_DEFAULT_UPPER + 23, + /* Custom interrupts 48 to 63 */ + [63] = IPRIO_MMAXIPRIO, + [62] = IPRIO_MMAXIPRIO, + [61] = IPRIO_MMAXIPRIO, + [60] = IPRIO_MMAXIPRIO, + [59] = IPRIO_MMAXIPRIO, + [58] = IPRIO_MMAXIPRIO, + [57] = IPRIO_MMAXIPRIO, + [56] = IPRIO_MMAXIPRIO, + [55] = IPRIO_MMAXIPRIO, + [54] = IPRIO_MMAXIPRIO, + [53] = IPRIO_MMAXIPRIO, + [52] = IPRIO_MMAXIPRIO, + [51] = IPRIO_MMAXIPRIO, + [50] = IPRIO_MMAXIPRIO, + [49] = IPRIO_MMAXIPRIO, + [48] = IPRIO_MMAXIPRIO, + + /* Custom interrupts 24 to 31 */ + [31] = IPRIO_MMAXIPRIO, + [30] = IPRIO_MMAXIPRIO, + [29] = IPRIO_MMAXIPRIO, + [28] = IPRIO_MMAXIPRIO, + [27] = IPRIO_MMAXIPRIO, + [26] = IPRIO_MMAXIPRIO, + [25] = IPRIO_MMAXIPRIO, + [24] = IPRIO_MMAXIPRIO, + + [47] = IPRIO_DEFAULT_UPPER, + [23] = IPRIO_DEFAULT_UPPER + 1, + [46] = IPRIO_DEFAULT_UPPER + 2, + [45] = IPRIO_DEFAULT_UPPER + 3, + [22] = IPRIO_DEFAULT_UPPER + 4, + [44] = IPRIO_DEFAULT_UPPER + 5, + + [43] = IPRIO_DEFAULT_UPPER + 6, + [21] = IPRIO_DEFAULT_UPPER + 7, + [42] = IPRIO_DEFAULT_UPPER + 8, + [41] = IPRIO_DEFAULT_UPPER + 9, + [20] = IPRIO_DEFAULT_UPPER + 10, + [40] = IPRIO_DEFAULT_UPPER + 11, [11] = IPRIO_DEFAULT_M, [3] = IPRIO_DEFAULT_M + 1, @@ -264,33 +286,19 @@ static const uint8_t default_iprio[64] = { [2] = IPRIO_DEFAULT_VS + 1, [6] = IPRIO_DEFAULT_VS + 2, - [47] = IPRIO_DEFAULT_LOWER, - [46] = IPRIO_DEFAULT_LOWER + 1, - [23] = IPRIO_DEFAULT_LOWER + 2, - [22] = IPRIO_DEFAULT_LOWER + 3, - [45] = IPRIO_DEFAULT_LOWER + 4, - [44] = IPRIO_DEFAULT_LOWER + 5, - - [43] = IPRIO_DEFAULT_LOWER + 6, - [42] = IPRIO_DEFAULT_LOWER + 7, - [21] = IPRIO_DEFAULT_LOWER + 8, - [20] = IPRIO_DEFAULT_LOWER + 9, - [41] = IPRIO_DEFAULT_LOWER + 10, - [40] = IPRIO_DEFAULT_LOWER + 11, - - [39] = IPRIO_DEFAULT_LOWER + 12, - [38] = IPRIO_DEFAULT_LOWER + 13, - [19] = IPRIO_DEFAULT_LOWER + 14, - [18] = IPRIO_DEFAULT_LOWER + 15, - [37] = IPRIO_DEFAULT_LOWER + 16, - [36] = IPRIO_DEFAULT_LOWER + 17, - - [35] = IPRIO_DEFAULT_LOWER + 18, - [34] = IPRIO_DEFAULT_LOWER + 19, - [17] = IPRIO_DEFAULT_LOWER + 20, - [16] = IPRIO_DEFAULT_LOWER + 21, - [33] = IPRIO_DEFAULT_LOWER + 22, - [32] = IPRIO_DEFAULT_LOWER + 23, + [39] = IPRIO_DEFAULT_LOWER, + [19] = IPRIO_DEFAULT_LOWER + 1, + [38] = IPRIO_DEFAULT_LOWER + 2, + [37] = IPRIO_DEFAULT_LOWER + 3, + [18] = IPRIO_DEFAULT_LOWER + 4, + [36] = IPRIO_DEFAULT_LOWER + 5, + + [35] = IPRIO_DEFAULT_LOWER + 6, + [17] = IPRIO_DEFAULT_LOWER + 7, + [34] = IPRIO_DEFAULT_LOWER + 8, + [33] = IPRIO_DEFAULT_LOWER + 9, + [16] = IPRIO_DEFAULT_LOWER + 10, + [32] = IPRIO_DEFAULT_LOWER + 11, }; uint8_t riscv_cpu_default_priority(int irq) @@ -306,6 +314,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; @@ -314,7 +323,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; } @@ -340,12 +349,13 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env, return best_irq; } -static uint64_t riscv_cpu_all_pending(CPURISCVState *env) +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) @@ -604,36 +614,32 @@ 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; - bool locked = false; + uint64_t gein, vsgein = 0, vstip = 0, old = env->mip; if (riscv_cpu_virt_enabled(env)) { gein = get_field(env->hstatus, HSTATUS_VGEIN); vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; } - if (!qemu_mutex_iothread_locked()) { - locked = true; - qemu_mutex_lock_iothread(); - } + /* No need to update mip for VSTIP */ + mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask; + vstip = env->vstime_irq ? MIP_VSTIP : 0; + + QEMU_IOTHREAD_LOCK_GUARD(); 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); } - if (locked) { - qemu_mutex_unlock_iothread(); - } - return old; } -void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), - uint32_t arg) +void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *), + void *arg) { env->rdtime_fn = fn; env->rdtime_fn_arg = arg; @@ -661,6 +667,9 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) if (newpriv == PRV_H) { newpriv = PRV_U; } + if (icount_enabled() && newpriv != env->priv) { + riscv_itrigger_update_priv(env); + } /* tlb_flush is unnecessary as mode is contained in mmu_idx */ env->priv = newpriv; env->xl = cpu_recompute_xl(env); @@ -697,24 +706,26 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot, int mode) { pmp_priv_t pmp_priv; - target_ulong tlb_size_pmp = 0; + int pmp_index = -1; if (!riscv_feature(env, RISCV_FEATURE_PMP)) { *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TRANSLATE_SUCCESS; } - if (!pmp_hart_has_privs(env, addr, size, 1 << access_type, &pmp_priv, - mode)) { + pmp_index = pmp_hart_has_privs(env, addr, size, 1 << access_type, + &pmp_priv, mode); + if (pmp_index < 0) { *prot = 0; return TRANSLATE_PMP_FAIL; } *prot = pmp_priv_to_page_prot(pmp_priv); - if (tlb_size != NULL) { - if (pmp_is_range_in_tlb(env, addr & ~(*tlb_size - 1), &tlb_size_pmp)) { - *tlb_size = tlb_size_pmp; - } + if ((tlb_size != NULL) && pmp_index != MAX_RISCV_PMPS) { + target_ulong tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1); + target_ulong tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1; + + *tlb_size = pmp_get_tlb_size(env, pmp_index, tlb_sa, tlb_ea); } return TRANSLATE_SUCCESS; @@ -1055,7 +1066,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, 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; @@ -1105,6 +1117,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) @@ -1150,7 +1163,8 @@ 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); - riscv_raise_exception(&cpu->env, cs->exception_index, retaddr); + env->two_stage_indirect_lookup = false; + cpu_loop_exit_restore(cs, retaddr); } void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, @@ -1175,7 +1189,30 @@ 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); - riscv_raise_exception(env, cs->exception_index, retaddr); + 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, @@ -1190,6 +1227,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 */ @@ -1212,6 +1250,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } } + pmu_tlb_fill_incr_ctr(cpu, access_type); if (riscv_cpu_virt_enabled(env) || ((riscv_cpu_two_stage_lookup(mmu_idx) || two_stage_lookup) && access_type != MMU_INST_FETCH)) { @@ -1227,6 +1266,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; } @@ -1310,12 +1350,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_raise_exception(env, cs->exception_index, retaddr); + 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 */ /* @@ -1340,37 +1586,59 @@ 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) { - env->gpr[xA0] = 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 = true; + 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: tval = env->bins; break; default: @@ -1434,7 +1702,6 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* Trap into HS mode */ env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false); htval = env->guest_phys_fault_addr; - write_gva = false; } env->hstatus = set_field(env->hstatus, HSTATUS_GVA, write_gva); } @@ -1448,6 +1715,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); @@ -1478,6 +1746,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); @@ -1490,6 +1759,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/crypto_helper.c b/target/riscv/crypto_helper.c new file mode 100644 index 000000000000..2ef30281b100 --- /dev/null +++ b/target/riscv/crypto_helper.c @@ -0,0 +1,302 @@ +/* + * RISC-V Crypto Emulation Helpers for QEMU. + * + * Copyright (c) 2021 Ruibo Lu, luruibo2000@163.com + * Copyright (c) 2021 Zewen Ye, lustrew@foxmail.com + * + * 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 "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "crypto/aes.h" +#include "crypto/sm4.h" + +#define AES_XTIME(a) \ + ((a << 1) ^ ((a & 0x80) ? 0x1b : 0)) + +#define AES_GFMUL(a, b) (( \ + (((b) & 0x1) ? (a) : 0) ^ \ + (((b) & 0x2) ? AES_XTIME(a) : 0) ^ \ + (((b) & 0x4) ? AES_XTIME(AES_XTIME(a)) : 0) ^ \ + (((b) & 0x8) ? AES_XTIME(AES_XTIME(AES_XTIME(a))) : 0)) & 0xFF) + +static inline uint32_t aes_mixcolumn_byte(uint8_t x, bool fwd) +{ + uint32_t u; + + if (fwd) { + u = (AES_GFMUL(x, 3) << 24) | (x << 16) | (x << 8) | + (AES_GFMUL(x, 2) << 0); + } else { + u = (AES_GFMUL(x, 0xb) << 24) | (AES_GFMUL(x, 0xd) << 16) | + (AES_GFMUL(x, 0x9) << 8) | (AES_GFMUL(x, 0xe) << 0); + } + return u; +} + +#define sext32_xlen(x) (target_ulong)(int32_t)(x) + +static inline target_ulong aes32_operation(target_ulong shamt, + target_ulong rs1, target_ulong rs2, + bool enc, bool mix) +{ + uint8_t si = rs2 >> shamt; + uint8_t so; + uint32_t mixed; + target_ulong res; + + if (enc) { + so = AES_sbox[si]; + if (mix) { + mixed = aes_mixcolumn_byte(so, true); + } else { + mixed = so; + } + } else { + so = AES_isbox[si]; + if (mix) { + mixed = aes_mixcolumn_byte(so, false); + } else { + mixed = so; + } + } + mixed = rol32(mixed, shamt); + res = rs1 ^ mixed; + + return sext32_xlen(res); +} + +target_ulong HELPER(aes32esmi)(target_ulong rs1, target_ulong rs2, + target_ulong shamt) +{ + return aes32_operation(shamt, rs1, rs2, true, true); +} + +target_ulong HELPER(aes32esi)(target_ulong rs1, target_ulong rs2, + target_ulong shamt) +{ + return aes32_operation(shamt, rs1, rs2, true, false); +} + +target_ulong HELPER(aes32dsmi)(target_ulong rs1, target_ulong rs2, + target_ulong shamt) +{ + return aes32_operation(shamt, rs1, rs2, false, true); +} + +target_ulong HELPER(aes32dsi)(target_ulong rs1, target_ulong rs2, + target_ulong shamt) +{ + return aes32_operation(shamt, rs1, rs2, false, false); +} + +#define BY(X, I) ((X >> (8 * I)) & 0xFF) + +#define AES_SHIFROWS_LO(RS1, RS2) ( \ + (((RS1 >> 24) & 0xFF) << 56) | (((RS2 >> 48) & 0xFF) << 48) | \ + (((RS2 >> 8) & 0xFF) << 40) | (((RS1 >> 32) & 0xFF) << 32) | \ + (((RS2 >> 56) & 0xFF) << 24) | (((RS2 >> 16) & 0xFF) << 16) | \ + (((RS1 >> 40) & 0xFF) << 8) | (((RS1 >> 0) & 0xFF) << 0)) + +#define AES_INVSHIFROWS_LO(RS1, RS2) ( \ + (((RS2 >> 24) & 0xFF) << 56) | (((RS2 >> 48) & 0xFF) << 48) | \ + (((RS1 >> 8) & 0xFF) << 40) | (((RS1 >> 32) & 0xFF) << 32) | \ + (((RS1 >> 56) & 0xFF) << 24) | (((RS2 >> 16) & 0xFF) << 16) | \ + (((RS2 >> 40) & 0xFF) << 8) | (((RS1 >> 0) & 0xFF) << 0)) + +#define AES_MIXBYTE(COL, B0, B1, B2, B3) ( \ + BY(COL, B3) ^ BY(COL, B2) ^ AES_GFMUL(BY(COL, B1), 3) ^ \ + AES_GFMUL(BY(COL, B0), 2)) + +#define AES_MIXCOLUMN(COL) ( \ + AES_MIXBYTE(COL, 3, 0, 1, 2) << 24 | \ + AES_MIXBYTE(COL, 2, 3, 0, 1) << 16 | \ + AES_MIXBYTE(COL, 1, 2, 3, 0) << 8 | AES_MIXBYTE(COL, 0, 1, 2, 3) << 0) + +#define AES_INVMIXBYTE(COL, B0, B1, B2, B3) ( \ + AES_GFMUL(BY(COL, B3), 0x9) ^ AES_GFMUL(BY(COL, B2), 0xd) ^ \ + AES_GFMUL(BY(COL, B1), 0xb) ^ AES_GFMUL(BY(COL, B0), 0xe)) + +#define AES_INVMIXCOLUMN(COL) ( \ + AES_INVMIXBYTE(COL, 3, 0, 1, 2) << 24 | \ + AES_INVMIXBYTE(COL, 2, 3, 0, 1) << 16 | \ + AES_INVMIXBYTE(COL, 1, 2, 3, 0) << 8 | \ + AES_INVMIXBYTE(COL, 0, 1, 2, 3) << 0) + +static inline target_ulong aes64_operation(target_ulong rs1, target_ulong rs2, + bool enc, bool mix) +{ + uint64_t RS1 = rs1; + uint64_t RS2 = rs2; + uint64_t result; + uint64_t temp; + uint32_t col_0; + uint32_t col_1; + + if (enc) { + temp = AES_SHIFROWS_LO(RS1, RS2); + temp = (((uint64_t)AES_sbox[(temp >> 0) & 0xFF] << 0) | + ((uint64_t)AES_sbox[(temp >> 8) & 0xFF] << 8) | + ((uint64_t)AES_sbox[(temp >> 16) & 0xFF] << 16) | + ((uint64_t)AES_sbox[(temp >> 24) & 0xFF] << 24) | + ((uint64_t)AES_sbox[(temp >> 32) & 0xFF] << 32) | + ((uint64_t)AES_sbox[(temp >> 40) & 0xFF] << 40) | + ((uint64_t)AES_sbox[(temp >> 48) & 0xFF] << 48) | + ((uint64_t)AES_sbox[(temp >> 56) & 0xFF] << 56)); + if (mix) { + col_0 = temp & 0xFFFFFFFF; + col_1 = temp >> 32; + + col_0 = AES_MIXCOLUMN(col_0); + col_1 = AES_MIXCOLUMN(col_1); + + result = ((uint64_t)col_1 << 32) | col_0; + } else { + result = temp; + } + } else { + temp = AES_INVSHIFROWS_LO(RS1, RS2); + temp = (((uint64_t)AES_isbox[(temp >> 0) & 0xFF] << 0) | + ((uint64_t)AES_isbox[(temp >> 8) & 0xFF] << 8) | + ((uint64_t)AES_isbox[(temp >> 16) & 0xFF] << 16) | + ((uint64_t)AES_isbox[(temp >> 24) & 0xFF] << 24) | + ((uint64_t)AES_isbox[(temp >> 32) & 0xFF] << 32) | + ((uint64_t)AES_isbox[(temp >> 40) & 0xFF] << 40) | + ((uint64_t)AES_isbox[(temp >> 48) & 0xFF] << 48) | + ((uint64_t)AES_isbox[(temp >> 56) & 0xFF] << 56)); + if (mix) { + col_0 = temp & 0xFFFFFFFF; + col_1 = temp >> 32; + + col_0 = AES_INVMIXCOLUMN(col_0); + col_1 = AES_INVMIXCOLUMN(col_1); + + result = ((uint64_t)col_1 << 32) | col_0; + } else { + result = temp; + } + } + + return result; +} + +target_ulong HELPER(aes64esm)(target_ulong rs1, target_ulong rs2) +{ + return aes64_operation(rs1, rs2, true, true); +} + +target_ulong HELPER(aes64es)(target_ulong rs1, target_ulong rs2) +{ + return aes64_operation(rs1, rs2, true, false); +} + +target_ulong HELPER(aes64ds)(target_ulong rs1, target_ulong rs2) +{ + return aes64_operation(rs1, rs2, false, false); +} + +target_ulong HELPER(aes64dsm)(target_ulong rs1, target_ulong rs2) +{ + return aes64_operation(rs1, rs2, false, true); +} + +target_ulong HELPER(aes64ks2)(target_ulong rs1, target_ulong rs2) +{ + uint64_t RS1 = rs1; + uint64_t RS2 = rs2; + uint32_t rs1_hi = RS1 >> 32; + uint32_t rs2_lo = RS2; + uint32_t rs2_hi = RS2 >> 32; + + uint32_t r_lo = (rs1_hi ^ rs2_lo); + uint32_t r_hi = (rs1_hi ^ rs2_lo ^ rs2_hi); + target_ulong result = ((uint64_t)r_hi << 32) | r_lo; + + return result; +} + +target_ulong HELPER(aes64ks1i)(target_ulong rs1, target_ulong rnum) +{ + uint64_t RS1 = rs1; + static const uint8_t round_consts[10] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 + }; + + uint8_t enc_rnum = rnum; + uint32_t temp = (RS1 >> 32) & 0xFFFFFFFF; + uint8_t rcon_ = 0; + target_ulong result; + + if (enc_rnum != 0xA) { + temp = ror32(temp, 8); /* Rotate right by 8 */ + rcon_ = round_consts[enc_rnum]; + } + + temp = ((uint32_t)AES_sbox[(temp >> 24) & 0xFF] << 24) | + ((uint32_t)AES_sbox[(temp >> 16) & 0xFF] << 16) | + ((uint32_t)AES_sbox[(temp >> 8) & 0xFF] << 8) | + ((uint32_t)AES_sbox[(temp >> 0) & 0xFF] << 0); + + temp ^= rcon_; + + result = ((uint64_t)temp << 32) | temp; + + return result; +} + +target_ulong HELPER(aes64im)(target_ulong rs1) +{ + uint64_t RS1 = rs1; + uint32_t col_0 = RS1 & 0xFFFFFFFF; + uint32_t col_1 = RS1 >> 32; + target_ulong result; + + col_0 = AES_INVMIXCOLUMN(col_0); + col_1 = AES_INVMIXCOLUMN(col_1); + + result = ((uint64_t)col_1 << 32) | col_0; + + return result; +} + +target_ulong HELPER(sm4ed)(target_ulong rs1, target_ulong rs2, + target_ulong shamt) +{ + uint32_t sb_in = (uint8_t)(rs2 >> shamt); + uint32_t sb_out = (uint32_t)sm4_sbox[sb_in]; + + uint32_t x = sb_out ^ (sb_out << 8) ^ (sb_out << 2) ^ (sb_out << 18) ^ + ((sb_out & 0x3f) << 26) ^ ((sb_out & 0xC0) << 10); + + uint32_t rotl = rol32(x, shamt); + + return sext32_xlen(rotl ^ (uint32_t)rs1); +} + +target_ulong HELPER(sm4ks)(target_ulong rs1, target_ulong rs2, + target_ulong shamt) +{ + uint32_t sb_in = (uint8_t)(rs2 >> shamt); + uint32_t sb_out = sm4_sbox[sb_in]; + + uint32_t x = sb_out ^ ((sb_out & 0x07) << 29) ^ ((sb_out & 0xFE) << 7) ^ + ((sb_out & 0x01) << 23) ^ ((sb_out & 0xF8) << 13); + + uint32_t rotl = rol32(x, shamt); + + return sext32_xlen(rotl ^ (uint32_t)rs1); +} +#undef sext32_xlen diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 341c2e6f23cb..0db2c233e5df 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -21,9 +21,13 @@ #include "qemu/log.h" #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" +#include "qemu/guest-random.h" +#include "qapi/error.h" /* CSR function table public API */ void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops) @@ -37,6 +41,42 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) } /* Predicates */ +#if !defined(CONFIG_USER_ONLY) +static RISCVException smstateen_acc_ok(CPURISCVState *env, int index, + uint64_t bit) +{ + bool virt = riscv_cpu_virt_enabled(env); + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (env->priv == PRV_M || !cpu->cfg.ext_smstateen) { + return RISCV_EXCP_NONE; + } + + if (!(env->mstateen[index] & bit)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (virt) { + if (!(env->hstateen[index] & bit)) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + + if (env->priv == PRV_U && !(env->sstateen[index] & bit)) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + } + + if (env->priv == PRV_U && riscv_has_ext(env, RVS)) { + if (!(env->sstateen[index] & bit)) { + return RISCV_EXCP_ILLEGAL_INST; + } + } + + return RISCV_EXCP_NONE; +} +#endif + static RISCVException fs(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) @@ -70,68 +110,46 @@ static RISCVException ctr(CPURISCVState *env, int csrno) #if !defined(CONFIG_USER_ONLY) CPUState *cs = env_cpu(env); RISCVCPU *cpu = RISCV_CPU(cs); + int ctr_index; + target_ulong ctr_mask; + int base_csrno = CSR_CYCLE; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false; - if (!cpu->cfg.ext_counters) { - /* The Counters extensions is not enabled */ + if (rv32 && csrno >= CSR_CYCLEH) { + /* Offset for RV32 hpmcounternh counters */ + base_csrno += 0x80; + } + ctr_index = csrno - base_csrno; + ctr_mask = BIT(ctr_index); + + 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; + } + +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: - if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) && - get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - } - if (riscv_cpu_mxl(env) == MXL_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: - if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) && - get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) { - 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; } @@ -146,6 +164,47 @@ static RISCVException ctr32(CPURISCVState *env, int csrno) } #if !defined(CONFIG_USER_ONLY) +static RISCVException mctr(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + int ctr_index; + int base_csrno = CSR_MHPMCOUNTER3; + + if ((riscv_cpu_mxl(env) == MXL_RV32) && csrno >= CSR_MCYCLEH) { + /* Offset for RV32 mhpmcounternh counters */ + base_csrno += 0x80; + } + ctr_index = csrno - base_csrno; + if (!cpu->cfg.pmu_num || ctr_index >= cpu->cfg.pmu_num) { + /* The PMU is not enabled or counter is out of range*/ + return RISCV_EXCP_ILLEGAL_INST; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException mctr32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + 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; @@ -163,7 +222,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; } @@ -172,7 +233,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; } @@ -199,7 +262,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; } @@ -208,7 +273,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; } @@ -217,15 +284,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; @@ -234,15 +294,95 @@ 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; + } + + 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); +} + +static RISCVException mstateen(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_smstateen) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return any(env, csrno); +} + +static RISCVException hstateen_pred(CPURISCVState *env, int csrno, int base) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_smstateen) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv < PRV_M) { + if (!(env->mstateen[csrno - base] & SMSTATEEN_STATEEN)) { return RISCV_EXCP_ILLEGAL_INST; - } else { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } } return hmode(env, csrno); +} +static RISCVException hstateen(CPURISCVState *env, int csrno) +{ + return hstateen_pred(env, csrno, CSR_HSTATEEN0); +} + +static RISCVException hstateenh(CPURISCVState *env, int csrno) +{ + return hstateen_pred(env, csrno, CSR_HSTATEEN0H); +} + +static RISCVException sstateen(CPURISCVState *env, int csrno) +{ + bool virt = riscv_cpu_virt_enabled(env); + int index = csrno - CSR_SSTATEEN0; + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_smstateen) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv < PRV_M) { + if (!(env->mstateen[index] & SMSTATEEN_STATEEN)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (virt) { + if (!(env->hstateen[index] & SMSTATEEN_STATEEN)) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + } + } + + return smode(env, csrno); } /* Checks if PointerMasking registers could be accessed */ @@ -257,7 +397,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; } @@ -266,7 +408,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; } @@ -290,8 +434,57 @@ static RISCVException epmp(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } + +static RISCVException debug(CPURISCVState *env, int csrno) +{ + if (riscv_feature(env, RISCV_FEATURE_DEBUG)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; +} #endif +static RISCVException seed(CPURISCVState *env, int csrno) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_zkr) { + return RISCV_EXCP_ILLEGAL_INST; + } + +#if !defined(CONFIG_USER_ONLY) + /* + * With a CSR read-write instruction: + * 1) The seed CSR is always available in machine mode as normal. + * 2) Attempted access to seed from virtual modes VS and VU always raises + * an exception(virtual instruction exception only if mseccfg.sseed=1). + * 3) Without the corresponding access control bit set to 1, any attempted + * access to seed from U, S or HS modes will raise an illegal instruction + * exception. + */ + if (env->priv == PRV_M) { + return RISCV_EXCP_NONE; + } else if (riscv_cpu_virt_enabled(env)) { + if (env->mseccfg & MSECCFG_SSEED) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } else { + return RISCV_EXCP_ILLEGAL_INST; + } + } else { + if (env->priv == PRV_S && (env->mseccfg & MSECCFG_SSEED)) { + return RISCV_EXCP_NONE; + } else if (env->priv == PRV_U && (env->mseccfg & MSECCFG_USEED)) { + return RISCV_EXCP_NONE; + } else { + return RISCV_EXCP_ILLEGAL_INST; + } + } +#else + return RISCV_EXCP_NONE; +#endif +} + /* User Floating-Point CSRs */ static RISCVException read_fflags(CPURISCVState *env, int csrno, target_ulong *val) @@ -455,34 +648,28 @@ static int write_vcsr(CPURISCVState *env, int csrno, target_ulong val) } /* User Timers and Counters */ -static RISCVException read_instret(CPURISCVState *env, int csrno, - target_ulong *val) +static target_ulong get_ticks(bool shift) { + int64_t val; + target_ulong result; + #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { - *val = icount_get(); + val = icount_get(); } else { - *val = cpu_get_host_ticks(); + val = cpu_get_host_ticks(); } #else - *val = cpu_get_host_ticks(); + val = cpu_get_host_ticks(); #endif - return RISCV_EXCP_NONE; -} -static RISCVException read_instreth(CPURISCVState *env, int csrno, - target_ulong *val) -{ -#if !defined(CONFIG_USER_ONLY) - if (icount_enabled()) { - *val = icount_get() >> 32; + if (shift) { + result = val >> 32; } else { - *val = cpu_get_host_ticks() >> 32; + result = val; } -#else - *val = cpu_get_host_ticks() >> 32; -#endif - return RISCV_EXCP_NONE; + + return result; } #if defined(CONFIG_USER_ONLY) @@ -500,38 +687,390 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = get_ticks(false); + return RISCV_EXCP_NONE; +} + +static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = get_ticks(true); + return RISCV_EXCP_NONE; +} + #else /* CONFIG_USER_ONLY */ +static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) +{ + int evt_index = csrno - CSR_MCOUNTINHIBIT; + + *val = env->mhpmevent_val[evt_index]; + + return RISCV_EXCP_NONE; +} + +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; +} + +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); + 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; + } + + return RISCV_EXCP_NONE; +} + +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; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, + bool upper_half, uint32_t ctr_idx) +{ + PMUCTRState counter = env->pmu_ctrs[ctr_idx]; + target_ulong ctr_prev = upper_half ? counter.mhpmcounterh_prev : + counter.mhpmcounter_prev; + target_ulong ctr_val = upper_half ? counter.mhpmcounterh_val : + counter.mhpmcounter_val; + + if (get_field(env->mcountinhibit, BIT(ctr_idx))) { + /** + * Counter should not increment if inhibit bit is set. We can't really + * stop the icount counting. Just return the counter value written by + * the supervisor to indicate that counter was not incremented. + */ + if (!counter.started) { + *val = ctr_val; + return RISCV_EXCP_NONE; + } else { + /* Mark that the counter has been stopped */ + counter.started = false; + } + } + + /** + * The kernel computes the perf delta by subtracting the current value from + * the value it initialized previously (ctr_val). + */ + if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + *val = get_ticks(upper_half) - ctr_prev + ctr_val; + } else { + *val = ctr_val; + } + + return RISCV_EXCP_NONE; +} + +static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint16_t ctr_index; + + if (csrno >= CSR_MCYCLE && csrno <= CSR_MHPMCOUNTER31) { + ctr_index = csrno - CSR_MCYCLE; + } else if (csrno >= CSR_CYCLE && csrno <= CSR_HPMCOUNTER31) { + ctr_index = csrno - CSR_CYCLE; + } else { + return RISCV_EXCP_ILLEGAL_INST; + } + + return riscv_pmu_read_ctr(env, val, false, ctr_index); +} + +static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint16_t ctr_index; + + if (csrno >= CSR_MCYCLEH && csrno <= CSR_MHPMCOUNTER31H) { + ctr_index = csrno - CSR_MCYCLEH; + } else if (csrno >= CSR_CYCLEH && csrno <= CSR_HPMCOUNTER31H) { + ctr_index = csrno - CSR_CYCLEH; + } else { + return RISCV_EXCP_ILLEGAL_INST; + } + + 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) { uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; - if (!env->rdtime_fn) { - return RISCV_EXCP_ILLEGAL_INST; + if (!env->rdtime_fn) { + return RISCV_EXCP_ILLEGAL_INST; + } + + *val = env->rdtime_fn(env->rdtime_fn_arg) + delta; + return RISCV_EXCP_NONE; +} + +static RISCVException read_timeh(CPURISCVState *env, int csrno, + target_ulong *val) +{ + uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; + + if (!env->rdtime_fn) { + return RISCV_EXCP_ILLEGAL_INST; + } + + *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32; + 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); } - *val = env->rdtime_fn(env->rdtime_fn_arg) + delta; + 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 read_timeh(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException write_stimecmph(CPURISCVState *env, int csrno, + target_ulong val) { - uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; + RISCVCPU *cpu = env_archcpu(env); - if (!env->rdtime_fn) { - return RISCV_EXCP_ILLEGAL_INST; + if (riscv_cpu_virt_enabled(env)) { + return write_vstimecmph(env, csrno, val); } - *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32; + 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)) @@ -572,7 +1111,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; @@ -603,6 +1143,36 @@ static RISCVException write_ignore(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException read_mvendorid(CPURISCVState *env, int csrno, + target_ulong *val) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + *val = cpu->cfg.mvendorid; + return RISCV_EXCP_NONE; +} + +static RISCVException read_marchid(CPURISCVState *env, int csrno, + target_ulong *val) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + *val = cpu->cfg.marchid; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mimpid(CPURISCVState *env, int csrno, + target_ulong *val) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + *val = cpu->cfg.mimpid; + return RISCV_EXCP_NONE; +} + static RISCVException read_mhartid(CPURISCVState *env, int csrno, target_ulong *val) { @@ -959,14 +1529,6 @@ static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno) return CSR_VSISELECT; case CSR_SIREG: return CSR_VSIREG; - case CSR_SSETEIPNUM: - return CSR_VSSETEIPNUM; - case CSR_SCLREIPNUM: - return CSR_VSCLREIPNUM; - case CSR_SSETEIENUM: - return CSR_VSSETEIENUM; - case CSR_SCLREIENUM: - return CSR_VSCLREIENUM; case CSR_STOPEI: return CSR_VSTOPEI; default: @@ -1121,73 +1683,31 @@ static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val, return RISCV_EXCP_NONE; } -static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) +static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) { + bool virt; int ret = -EINVAL; - bool set, pend, virt; - target_ulong priv, isel, vgein, xlen, nval, wmask; + target_ulong priv, vgein; /* Translate CSR number for VS-mode */ csrno = aia_xlate_vs_csrno(env, csrno); /* Decode register details from CSR number */ - virt = set = pend = false; + virt = false; switch (csrno) { - case CSR_MSETEIPNUM: - priv = PRV_M; - set = true; - pend = true; - break; - case CSR_MCLREIPNUM: - priv = PRV_M; - pend = true; - break; - case CSR_MSETEIENUM: - priv = PRV_M; - set = true; - break; - case CSR_MCLREIENUM: + case CSR_MTOPEI: priv = PRV_M; break; - case CSR_SSETEIPNUM: - priv = PRV_S; - set = true; - pend = true; - break; - case CSR_SCLREIPNUM: - priv = PRV_S; - pend = true; - break; - case CSR_SSETEIENUM: - priv = PRV_S; - set = true; - break; - case CSR_SCLREIENUM: - priv = PRV_S; - break; - case CSR_VSSETEIPNUM: - priv = PRV_S; - virt = true; - set = true; - pend = true; - break; - case CSR_VSCLREIPNUM: - priv = PRV_S; - virt = true; - pend = true; - break; - case CSR_VSSETEIENUM: + case CSR_STOPEI: priv = PRV_S; - virt = true; - set = true; break; - case CSR_VSCLREIENUM: + case CSR_VSTOPEI: priv = PRV_S; virt = true; break; default: - goto done; + goto done; }; /* IMSIC CSRs only available when machine implements IMSIC. */ @@ -1203,33 +1723,11 @@ static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val, goto done; } - /* Set/Clear CSRs always read zero */ - if (val) { - *val = 0; - } - - if (wr_mask) { - /* Get interrupt number */ - new_val &= wr_mask; - - /* Find target interrupt pending/enable register */ - xlen = riscv_cpu_mxl_bits(env); - isel = (new_val / xlen); - isel *= (xlen / IMSIC_EIPx_BITS); - isel += (pend) ? ISELECT_IMSIC_EIP0 : ISELECT_IMSIC_EIE0; - - /* Find the interrupt bit to be set/clear */ - wmask = ((target_ulong)1) << (new_val % xlen); - nval = (set) ? wmask : 0; - - /* Call machine specific IMSIC register emulation */ - ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], - AIA_MAKE_IREG(isel, priv, virt, - vgein, xlen), - NULL, nval, wmask); - } else { - ret = 0; - } + /* Call machine specific IMSIC register emulation for TOPEI */ + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], + AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein, + riscv_cpu_mxl_bits(env)), + val, new_val, wr_mask); done: if (ret) { @@ -1239,174 +1737,479 @@ static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val, return RISCV_EXCP_NONE; } -static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) +static RISCVException read_mtvec(CPURISCVState *env, int csrno, + target_ulong *val) { - bool virt; - int ret = -EINVAL; - target_ulong priv, vgein; + *val = env->mtvec; + return RISCV_EXCP_NONE; +} - /* Translate CSR number for VS-mode */ - csrno = aia_xlate_vs_csrno(env, csrno); +static RISCVException write_mtvec(CPURISCVState *env, int csrno, + target_ulong val) +{ + /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ + if ((val & 3) < 2) { + env->mtvec = val; + } else { + qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n"); + } + return RISCV_EXCP_NONE; +} - /* Decode register details from CSR number */ - virt = false; - switch (csrno) { - case CSR_MTOPEI: - priv = PRV_M; - break; - case CSR_STOPEI: - priv = PRV_S; - break; - case CSR_VSTOPEI: - priv = PRV_S; - virt = true; - break; - default: - goto done; - }; +static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mcountinhibit; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, + target_ulong val) +{ + int cidx; + PMUCTRState *counter; + + env->mcountinhibit = val; + + /* Check if any other counter is also monitoring cycles/instructions */ + for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) { + if (!get_field(env->mcountinhibit, BIT(cidx))) { + counter = &env->pmu_ctrs[cidx]; + counter->started = true; + } + } + + return RISCV_EXCP_NONE; +} + +static RISCVException read_mcounteren(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mcounteren; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcounteren(CPURISCVState *env, int csrno, + target_ulong val) +{ + env->mcounteren = val; + return RISCV_EXCP_NONE; +} + +/* Machine Trap Handling */ +static RISCVException read_mscratch_i128(CPURISCVState *env, int csrno, + Int128 *val) +{ + *val = int128_make128(env->mscratch, env->mscratchh); + return RISCV_EXCP_NONE; +} + +static RISCVException write_mscratch_i128(CPURISCVState *env, int csrno, + Int128 val) +{ + env->mscratch = int128_getlo(val); + env->mscratchh = int128_gethi(val); + return RISCV_EXCP_NONE; +} + +static RISCVException read_mscratch(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mscratch; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mscratch(CPURISCVState *env, int csrno, + target_ulong val) +{ + env->mscratch = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mepc(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mepc; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mepc(CPURISCVState *env, int csrno, + target_ulong val) +{ + env->mepc = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mcause(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mcause; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcause(CPURISCVState *env, int csrno, + target_ulong val) +{ + env->mcause = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mtval(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mtval; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mtval(CPURISCVState *env, int csrno, + target_ulong val) +{ + env->mtval = val; + return RISCV_EXCP_NONE; +} + +/* Execution environment configuration setup */ +static RISCVException read_menvcfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->menvcfg; + return RISCV_EXCP_NONE; +} + +static RISCVException write_menvcfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | MENVCFG_CBZE; + + if (riscv_cpu_mxl(env) == MXL_RV64) { + mask |= MENVCFG_PBMTE | MENVCFG_STCE; + } + env->menvcfg = (env->menvcfg & ~mask) | (val & mask); + + return RISCV_EXCP_NONE; +} + +static RISCVException read_menvcfgh(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->menvcfg >> 32; + return RISCV_EXCP_NONE; +} + +static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, + target_ulong val) +{ + uint64_t mask = MENVCFG_PBMTE | MENVCFG_STCE; + uint64_t valh = (uint64_t)val << 32; + + env->menvcfg = (env->menvcfg & ~mask) | (valh & mask); + + return RISCV_EXCP_NONE; +} + +static RISCVException read_senvcfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + RISCVException ret; + + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); + if (ret != RISCV_EXCP_NONE) { + return ret; + } - /* IMSIC CSRs only available when machine implements IMSIC. */ - if (!env->aia_ireg_rmw_fn[priv]) { - goto done; + *val = env->senvcfg; + return RISCV_EXCP_NONE; +} + +static RISCVException write_senvcfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE; + RISCVException ret; + + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); + if (ret != RISCV_EXCP_NONE) { + return ret; } - /* Find the selected guest interrupt file */ - vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; + env->senvcfg = (env->senvcfg & ~mask) | (val & mask); + return RISCV_EXCP_NONE; +} - /* Selected guest interrupt file should be valid */ - if (virt && (!vgein || env->geilen < vgein)) { - goto done; +static RISCVException read_henvcfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + RISCVException ret; + + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); + if (ret != RISCV_EXCP_NONE) { + return ret; } - /* Call machine specific IMSIC register emulation for TOPEI */ - ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], - AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein, - riscv_cpu_mxl_bits(env)), - val, new_val, wr_mask); + *val = env->henvcfg; + return RISCV_EXCP_NONE; +} -done: - if (ret) { - return (riscv_cpu_virt_enabled(env) && virt) ? - RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; +static RISCVException write_henvcfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; + RISCVException ret; + + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); + if (ret != RISCV_EXCP_NONE) { + return ret; + } + + if (riscv_cpu_mxl(env) == MXL_RV64) { + mask |= HENVCFG_PBMTE | HENVCFG_STCE; } + + env->henvcfg = (env->henvcfg & ~mask) | (val & mask); + return RISCV_EXCP_NONE; } -static RISCVException read_mtvec(CPURISCVState *env, int csrno, +static RISCVException read_henvcfgh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mtvec; + RISCVException ret; + + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); + if (ret != RISCV_EXCP_NONE) { + return ret; + } + + *val = env->henvcfg >> 32; return RISCV_EXCP_NONE; } -static RISCVException write_mtvec(CPURISCVState *env, int csrno, +static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, target_ulong val) { - /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ - if ((val & 3) < 2) { - env->mtvec = val; - } else { - qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n"); + uint64_t mask = HENVCFG_PBMTE | HENVCFG_STCE; + uint64_t valh = (uint64_t)val << 32; + RISCVException ret; + + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); + if (ret != RISCV_EXCP_NONE) { + return ret; } + + env->henvcfg = (env->henvcfg & ~mask) | (valh & mask); return RISCV_EXCP_NONE; } -static RISCVException read_mcounteren(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException read_mstateen(CPURISCVState *env, int csrno, + target_ulong *val) { - *val = env->mcounteren; + *val = env->mstateen[csrno - CSR_MSTATEEN0]; + return RISCV_EXCP_NONE; } -static RISCVException write_mcounteren(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException write_mstateen(CPURISCVState *env, int csrno, + uint64_t wr_mask, target_ulong new_val) { - env->mcounteren = val; + uint64_t *reg; + + reg = &env->mstateen[csrno - CSR_MSTATEEN0]; + *reg = (*reg & ~wr_mask) | (new_val & wr_mask); + return RISCV_EXCP_NONE; } -/* Machine Trap Handling */ -static RISCVException read_mscratch_i128(CPURISCVState *env, int csrno, - Int128 *val) +static RISCVException write_mstateen0(CPURISCVState *env, int csrno, + target_ulong new_val) { - *val = int128_make128(env->mscratch, env->mscratchh); + uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + + return write_mstateen(env, csrno, wr_mask, new_val); +} + +static RISCVException write_mstateen_1_3(CPURISCVState *env, int csrno, + target_ulong new_val) +{ + return write_mstateen(env, csrno, SMSTATEEN_STATEEN, new_val); +} + +static RISCVException read_mstateenh(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mstateen[csrno - CSR_MSTATEEN0H] >> 32; + return RISCV_EXCP_NONE; } -static RISCVException write_mscratch_i128(CPURISCVState *env, int csrno, - Int128 val) +static RISCVException write_mstateenh(CPURISCVState *env, int csrno, + uint64_t wr_mask, target_ulong new_val) { - env->mscratch = int128_getlo(val); - env->mscratchh = int128_gethi(val); + uint64_t *reg, val; + + reg = &env->mstateen[csrno - CSR_MSTATEEN0H]; + val = (uint64_t)new_val << 32; + val |= *reg & 0xFFFFFFFF; + *reg = (*reg & ~wr_mask) | (val & wr_mask); + return RISCV_EXCP_NONE; } -static RISCVException read_mscratch(CPURISCVState *env, int csrno, +static RISCVException write_mstateen0h(CPURISCVState *env, int csrno, + target_ulong new_val) +{ + uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + + return write_mstateenh(env, csrno, wr_mask, new_val); +} + +static RISCVException write_mstateenh_1_3(CPURISCVState *env, int csrno, + target_ulong new_val) +{ + return write_mstateenh(env, csrno, SMSTATEEN_STATEEN, new_val); +} + +static RISCVException read_hstateen(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mscratch; + int index = csrno - CSR_HSTATEEN0; + + *val = env->hstateen[index] & env->mstateen[index]; + return RISCV_EXCP_NONE; } -static RISCVException write_mscratch(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException write_hstateen(CPURISCVState *env, int csrno, + uint64_t mask, target_ulong new_val) { - env->mscratch = val; + int index = csrno - CSR_HSTATEEN0; + uint64_t *reg, wr_mask; + + reg = &env->hstateen[index]; + wr_mask = env->mstateen[index] & mask; + *reg = (*reg & ~wr_mask) | (new_val & wr_mask); + return RISCV_EXCP_NONE; } -static RISCVException read_mepc(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException write_hstateen0(CPURISCVState *env, int csrno, + target_ulong new_val) { - *val = env->mepc; - return RISCV_EXCP_NONE; + uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + + return write_hstateen(env, csrno, wr_mask, new_val); } -static RISCVException write_mepc(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException write_hstateen_1_3(CPURISCVState *env, int csrno, + target_ulong new_val) { - env->mepc = val; - return RISCV_EXCP_NONE; + return write_hstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } -static RISCVException read_mcause(CPURISCVState *env, int csrno, +static RISCVException read_hstateenh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mcause; + int index = csrno - CSR_HSTATEEN0H; + + *val = (env->hstateen[index] >> 32) & (env->mstateen[index] >> 32); + return RISCV_EXCP_NONE; } -static RISCVException write_mcause(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException write_hstateenh(CPURISCVState *env, int csrno, + uint64_t mask, target_ulong new_val) { - env->mcause = val; + int index = csrno - CSR_HSTATEEN0H; + uint64_t *reg, wr_mask, val; + + reg = &env->hstateen[index]; + val = (uint64_t)new_val << 32; + val |= *reg & 0xFFFFFFFF; + wr_mask = env->mstateen[index] & mask; + *reg = (*reg & ~wr_mask) | (val & wr_mask); + return RISCV_EXCP_NONE; } -static RISCVException read_mtval(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException write_hstateen0h(CPURISCVState *env, int csrno, + target_ulong new_val) { - *val = env->mtval; + uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + + return write_hstateenh(env, csrno, wr_mask, new_val); +} + +static RISCVException write_hstateenh_1_3(CPURISCVState *env, int csrno, + target_ulong new_val) +{ + return write_hstateenh(env, csrno, SMSTATEEN_STATEEN, new_val); +} + +static RISCVException read_sstateen(CPURISCVState *env, int csrno, + target_ulong *val) +{ + bool virt = riscv_cpu_virt_enabled(env); + int index = csrno - CSR_SSTATEEN0; + + *val = env->sstateen[index] & env->mstateen[index]; + if (virt) { + *val &= env->hstateen[index]; + } + return RISCV_EXCP_NONE; } -static RISCVException write_mtval(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException write_sstateen(CPURISCVState *env, int csrno, + uint64_t mask, target_ulong new_val) { - env->mtval = val; + bool virt = riscv_cpu_virt_enabled(env); + int index = csrno - CSR_SSTATEEN0; + uint64_t wr_mask; + uint64_t *reg; + + wr_mask = env->mstateen[index] & mask; + if (virt) { + wr_mask &= env->hstateen[index]; + } + + reg = &env->sstateen[index]; + *reg = (*reg & ~wr_mask) | (new_val & wr_mask); + return RISCV_EXCP_NONE; } +static RISCVException write_sstateen0(CPURISCVState *env, int csrno, + target_ulong new_val) +{ + uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + + return write_sstateen(env, csrno, wr_mask, new_val); +} + +static RISCVException write_sstateen_1_3(CPURISCVState *env, int csrno, + target_ulong new_val) +{ + return write_sstateen(env, csrno, SMSTATEEN_STATEEN, new_val); +} + static RISCVException rmw_mip64(CPURISCVState *env, int csrno, uint64_t *ret_val, uint64_t new_val, uint64_t wr_mask) { RISCVCPU *cpu = env_archcpu(env); - /* Allow software control of delegable interrupts not claimed by hardware */ - uint64_t old_mip, mask = wr_mask & delegable_ints & ~env->miclaim; + uint64_t old_mip, mask = wr_mask & delegable_ints; uint32_t gin; + if (mask & MIP_SEIP) { + env->software_seip = new_val & MIP_SEIP; + 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 { @@ -1416,6 +2219,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) { @@ -2578,6 +3382,55 @@ static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException read_tselect(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = tselect_csr_read(env); + return RISCV_EXCP_NONE; +} + +static RISCVException write_tselect(CPURISCVState *env, int csrno, + target_ulong val) +{ + tselect_csr_write(env, val); + return RISCV_EXCP_NONE; +} + +static RISCVException read_tdata(CPURISCVState *env, int csrno, + target_ulong *val) +{ + /* return 0 in tdata1 to end the trigger enumeration */ + if (env->trigger_cur >= RV_MAX_TRIGGERS && csrno == CSR_TDATA1) { + *val = 0; + return RISCV_EXCP_NONE; + } + + if (!tdata_available(env, csrno - CSR_TDATA1)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + *val = tdata_csr_read(env, csrno - CSR_TDATA1); + return RISCV_EXCP_NONE; +} + +static RISCVException write_tdata(CPURISCVState *env, int csrno, + target_ulong val) +{ + if (!tdata_available(env, csrno - CSR_TDATA1)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + tdata_csr_write(env, csrno - CSR_TDATA1, val); + 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 @@ -2864,6 +3717,41 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno, #endif +/* Crypto Extension */ +static RISCVException rmw_seed(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask) +{ + uint16_t random_v; + Error *random_e = NULL; + int random_r; + target_ulong rval; + + random_r = qemu_guest_getrandom(&random_v, 2, &random_e); + if (unlikely(random_r < 0)) { + /* + * Failed, for unknown reasons in the crypto subsystem. + * The best we can do is log the reason and return a + * failure indication to the guest. There is no reason + * we know to expect the failure to be transitory, so + * indicate DEAD to avoid having the guest spin on WAIT. + */ + qemu_log_mask(LOG_UNIMP, "%s: Crypto failure: %s", + __func__, error_get_pretty(random_e)); + error_free(random_e); + rval = SEED_OPST_DEAD; + } else { + rval = random_v | SEED_OPST_ES16; + } + + if (ret_value) { + *ret_value = rval; + } + + return RISCV_EXCP_NONE; +} + /* * riscv_csrrw - read and/or update control and status register * @@ -2880,39 +3768,52 @@ 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; -#if !defined(CONFIG_USER_ONLY) - int effective_priv = env->priv; + int csr_min_priv = csr_ops[csrno].min_priv_ver; - if (riscv_has_ext(env, RVH) && - env->priv == PRV_S && - !riscv_cpu_virt_enabled(env)) { - /* - * We are in S mode without virtualisation, therefore we are in HS Mode. - * Add 1 to the effective privledge level to allow us to access the - * Hypervisor CSRs. - */ - effective_priv++; + /* ensure the CSR extension is enabled. */ + if (!cpu->cfg.ext_icsr) { + return RISCV_EXCP_ILLEGAL_INST; } - if (!env->debugger && (effective_priv < get_field(csrno, 0x300))) { + if (env->priv_ver < csr_min_priv) { return RISCV_EXCP_ILLEGAL_INST; } -#endif - if (write_mask && read_only) { + + /* check predicate */ + if (!csr_ops[csrno].predicate) { return RISCV_EXCP_ILLEGAL_INST; } - /* ensure the CSR extension is enabled. */ - if (!cpu->cfg.ext_icsr) { + if (write_mask && read_only) { return RISCV_EXCP_ILLEGAL_INST; } - /* check predicate */ - if (!csr_ops[csrno].predicate) { - 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 && + !riscv_cpu_virt_enabled(env)) { + /* + * We are in HS mode. Add 1 to the effective privledge level to + * allow us to access the Hypervisor CSRs. + */ + effective_priv++; } - return csr_ops[csrno].predicate(env, csrno); + csr_priv = get_field(csrno, 0x300); + if (!env->debugger && (effective_priv < csr_priv)) { + if (csr_priv == (PRV_S + 1) && riscv_cpu_virt_enabled(env)) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return RISCV_EXCP_ILLEGAL_INST; + } +#endif + return RISCV_EXCP_NONE; } static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, @@ -3070,18 +3971,25 @@ 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 }, - [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat }, - [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm }, - [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr }, - [CSR_VL] = { "vl", vs, read_vl }, - [CSR_VTYPE] = { "vtype", vs, read_vtype }, - [CSR_VLENB] = { "vlenb", vs, read_vlenb }, + [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_instret }, - [CSR_INSTRET] = { "instret", ctr, read_instret }, - [CSR_CYCLEH] = { "cycleh", ctr32, read_instreth }, - [CSR_INSTRETH] = { "instreth", ctr32, read_instreth }, + [CSR_CYCLE] = { "cycle", ctr, read_hpmcounter }, + [CSR_INSTRET] = { "instret", ctr, read_hpmcounter }, + [CSR_CYCLEH] = { "cycleh", ctr32, read_hpmcounterh }, + [CSR_INSTRETH] = { "instreth", ctr32, read_hpmcounterh }, /* * In privileged mode, the monitor will have to emulate TIME CSRs only if @@ -3090,35 +3998,46 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_TIME] = { "time", ctr, read_time }, [CSR_TIMEH] = { "timeh", ctr32, read_timeh }, + /* Crypto Extension */ + [CSR_SEED] = { "seed", seed, NULL, NULL, rmw_seed }, + #if !defined(CONFIG_USER_ONLY) /* Machine Timers and Counters */ - [CSR_MCYCLE] = { "mcycle", any, read_instret }, - [CSR_MINSTRET] = { "minstret", any, read_instret }, - [CSR_MCYCLEH] = { "mcycleh", any32, read_instreth }, - [CSR_MINSTRETH] = { "minstreth", any32, read_instreth }, + [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_zero }, - [CSR_MARCHID] = { "marchid", any, read_zero }, - [CSR_MIMPID] = { "mimpid", any, read_zero }, - [CSR_MHARTID] = { "mhartid", any, read_mhartid }, + [CSR_MVENDORID] = { "mvendorid", any, read_mvendorid }, + [CSR_MARCHID] = { "marchid", any, read_marchid }, + [CSR_MIMPID] = { "mimpid", any, read_mimpid }, + [CSR_MHARTID] = { "mhartid", any, read_mhartid }, + [CSR_MCONFIGPTR] = { "mconfigptr", any, read_zero, + .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_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush }, + [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 }, /* 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 }, @@ -3129,18 +4048,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MIREG] = { "mireg", aia_any, NULL, NULL, rmw_xireg }, /* Machine-Level Interrupts (AIA) */ - [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, - - /* Machine-Level IMSIC Interface (AIA) */ - [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, NULL, NULL, rmw_xsetclreinum }, - [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, NULL, NULL, rmw_xsetclreinum }, - [CSR_MSETEIENUM] = { "mseteienum", aia_any, NULL, NULL, rmw_xsetclreinum }, - [CSR_MCLREIENUM] = { "mclreienum", aia_any, NULL, NULL, rmw_xsetclreinum }, - [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, + [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 }, @@ -3149,103 +4062,212 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MVIPH] = { "mviph", aia_any32, read_zero, write_ignore }, [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, + /* Execution environment configuration */ + [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 }, + [CSR_HENVCFG] = { "henvcfg", hmode, read_henvcfg, write_henvcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HENVCFGH] = { "henvcfgh", hmode32, read_henvcfgh, write_henvcfgh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + + /* Smstateen extension CSRs */ + [CSR_MSTATEEN0] = { "mstateen0", mstateen, read_mstateen, write_mstateen0, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN0H] = { "mstateen0h", mstateen, read_mstateenh, + write_mstateen0h, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN1] = { "mstateen1", mstateen, read_mstateen, + write_mstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN1H] = { "mstateen1h", mstateen, read_mstateenh, + write_mstateenh_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN2] = { "mstateen2", mstateen, read_mstateen, + write_mstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN2H] = { "mstateen2h", mstateen, read_mstateenh, + write_mstateenh_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN3] = { "mstateen3", mstateen, read_mstateen, + write_mstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MSTATEEN3H] = { "mstateen3h", mstateen, read_mstateenh, + write_mstateenh_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN0] = { "hstateen0", hstateen, read_hstateen, write_hstateen0, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN0H] = { "hstateen0h", hstateenh, read_hstateenh, + write_hstateen0h, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN1] = { "hstateen1", hstateen, read_hstateen, + write_hstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN1H] = { "hstateen1h", hstateenh, read_hstateenh, + write_hstateenh_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN2] = { "hstateen2", hstateen, read_hstateen, + write_hstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN2H] = { "hstateen2h", hstateenh, read_hstateenh, + write_hstateenh_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN3] = { "hstateen3", hstateen, read_hstateen, + write_hstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATEEN3H] = { "hstateen3h", hstateenh, read_hstateenh, + write_hstateenh_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_SSTATEEN0] = { "sstateen0", sstateen, read_sstateen, write_sstateen0, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_SSTATEEN1] = { "sstateen1", sstateen, read_sstateen, + write_sstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_SSTATEEN2] = { "sstateen2", sstateen, read_sstateen, + write_sstateen_1_3, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_SSTATEEN3] = { "sstateen3", sstateen, read_sstateen, + write_sstateen_1_3, + .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 }, [CSR_SIREG] = { "sireg", aia_smode, NULL, NULL, rmw_xireg }, /* Supervisor-Level Interrupts (AIA) */ - [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, - - /* Supervisor-Level IMSIC Interface (AIA) */ - [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, NULL, NULL, rmw_xsetclreinum }, - [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, NULL, NULL, rmw_xsetclreinum }, - [CSR_SSETEIENUM] = { "sseteienum", aia_smode, NULL, NULL, rmw_xsetclreinum }, - [CSR_SCLREIENUM] = { "sclreienum", aia_smode, NULL, NULL, rmw_xsetclreinum }, [CSR_STOPEI] = { "stopei", aia_smode, NULL, NULL, rmw_xtopei }, + [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, /* Supervisor-Level High-Half CSRs (AIA) */ [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 }, - [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg }, - [CSR_HIDELEG] = { "hideleg", hmode, NULL, NULL, rmw_hideleg }, - [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip }, - [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip }, - [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie }, - [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren }, - [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie }, - [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval }, - [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst }, - [CSR_HGEIP] = { "hgeip", hmode, read_hgeip, NULL }, - [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp }, - [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta }, - [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah }, - - [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, write_vsstatus }, - [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip }, - [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie }, - [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec }, - [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, write_vsscratch }, - [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc }, - [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause }, - [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval }, - [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp }, - - [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2 }, - [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst }, + [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 }, + [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 }, + + [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 }, /* 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_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, - - /* VS-Level IMSIC Interface (H-extension with AIA) */ - [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, - [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, - [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, - [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, [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 }, + [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg, + .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 }, @@ -3267,168 +4289,363 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr }, [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr }, + /* Debug CSRs */ + [CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect }, + [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_zero }, - [CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_zero }, - [CSR_HPMCOUNTER5] = { "hpmcounter5", ctr, read_zero }, - [CSR_HPMCOUNTER6] = { "hpmcounter6", ctr, read_zero }, - [CSR_HPMCOUNTER7] = { "hpmcounter7", ctr, read_zero }, - [CSR_HPMCOUNTER8] = { "hpmcounter8", ctr, read_zero }, - [CSR_HPMCOUNTER9] = { "hpmcounter9", ctr, read_zero }, - [CSR_HPMCOUNTER10] = { "hpmcounter10", ctr, read_zero }, - [CSR_HPMCOUNTER11] = { "hpmcounter11", ctr, read_zero }, - [CSR_HPMCOUNTER12] = { "hpmcounter12", ctr, read_zero }, - [CSR_HPMCOUNTER13] = { "hpmcounter13", ctr, read_zero }, - [CSR_HPMCOUNTER14] = { "hpmcounter14", ctr, read_zero }, - [CSR_HPMCOUNTER15] = { "hpmcounter15", ctr, read_zero }, - [CSR_HPMCOUNTER16] = { "hpmcounter16", ctr, read_zero }, - [CSR_HPMCOUNTER17] = { "hpmcounter17", ctr, read_zero }, - [CSR_HPMCOUNTER18] = { "hpmcounter18", ctr, read_zero }, - [CSR_HPMCOUNTER19] = { "hpmcounter19", ctr, read_zero }, - [CSR_HPMCOUNTER20] = { "hpmcounter20", ctr, read_zero }, - [CSR_HPMCOUNTER21] = { "hpmcounter21", ctr, read_zero }, - [CSR_HPMCOUNTER22] = { "hpmcounter22", ctr, read_zero }, - [CSR_HPMCOUNTER23] = { "hpmcounter23", ctr, read_zero }, - [CSR_HPMCOUNTER24] = { "hpmcounter24", ctr, read_zero }, - [CSR_HPMCOUNTER25] = { "hpmcounter25", ctr, read_zero }, - [CSR_HPMCOUNTER26] = { "hpmcounter26", ctr, read_zero }, - [CSR_HPMCOUNTER27] = { "hpmcounter27", ctr, read_zero }, - [CSR_HPMCOUNTER28] = { "hpmcounter28", ctr, read_zero }, - [CSR_HPMCOUNTER29] = { "hpmcounter29", ctr, read_zero }, - [CSR_HPMCOUNTER30] = { "hpmcounter30", ctr, read_zero }, - [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_zero }, - - [CSR_MHPMCOUNTER3] = { "mhpmcounter3", any, read_zero }, - [CSR_MHPMCOUNTER4] = { "mhpmcounter4", any, read_zero }, - [CSR_MHPMCOUNTER5] = { "mhpmcounter5", any, read_zero }, - [CSR_MHPMCOUNTER6] = { "mhpmcounter6", any, read_zero }, - [CSR_MHPMCOUNTER7] = { "mhpmcounter7", any, read_zero }, - [CSR_MHPMCOUNTER8] = { "mhpmcounter8", any, read_zero }, - [CSR_MHPMCOUNTER9] = { "mhpmcounter9", any, read_zero }, - [CSR_MHPMCOUNTER10] = { "mhpmcounter10", any, read_zero }, - [CSR_MHPMCOUNTER11] = { "mhpmcounter11", any, read_zero }, - [CSR_MHPMCOUNTER12] = { "mhpmcounter12", any, read_zero }, - [CSR_MHPMCOUNTER13] = { "mhpmcounter13", any, read_zero }, - [CSR_MHPMCOUNTER14] = { "mhpmcounter14", any, read_zero }, - [CSR_MHPMCOUNTER15] = { "mhpmcounter15", any, read_zero }, - [CSR_MHPMCOUNTER16] = { "mhpmcounter16", any, read_zero }, - [CSR_MHPMCOUNTER17] = { "mhpmcounter17", any, read_zero }, - [CSR_MHPMCOUNTER18] = { "mhpmcounter18", any, read_zero }, - [CSR_MHPMCOUNTER19] = { "mhpmcounter19", any, read_zero }, - [CSR_MHPMCOUNTER20] = { "mhpmcounter20", any, read_zero }, - [CSR_MHPMCOUNTER21] = { "mhpmcounter21", any, read_zero }, - [CSR_MHPMCOUNTER22] = { "mhpmcounter22", any, read_zero }, - [CSR_MHPMCOUNTER23] = { "mhpmcounter23", any, read_zero }, - [CSR_MHPMCOUNTER24] = { "mhpmcounter24", any, read_zero }, - [CSR_MHPMCOUNTER25] = { "mhpmcounter25", any, read_zero }, - [CSR_MHPMCOUNTER26] = { "mhpmcounter26", any, read_zero }, - [CSR_MHPMCOUNTER27] = { "mhpmcounter27", any, read_zero }, - [CSR_MHPMCOUNTER28] = { "mhpmcounter28", any, read_zero }, - [CSR_MHPMCOUNTER29] = { "mhpmcounter29", any, read_zero }, - [CSR_MHPMCOUNTER30] = { "mhpmcounter30", any, read_zero }, - [CSR_MHPMCOUNTER31] = { "mhpmcounter31", any, read_zero }, - - [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_zero }, - [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_zero }, - [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_zero }, - [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_zero }, - [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_zero }, - [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_zero }, - [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_zero }, - [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_zero }, - [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_zero }, - [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_zero }, - [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_zero }, - [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_zero }, - [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_zero }, - [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_zero }, - [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_zero }, - [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_zero }, - [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_zero }, - [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_zero }, - [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_zero }, - [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_zero }, - [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_zero }, - [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_zero }, - [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_zero }, - [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_zero }, - [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_zero }, - [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_zero }, - [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_zero }, - [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_zero }, - [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_zero }, - - [CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_zero }, - [CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_zero }, - [CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_zero }, - [CSR_HPMCOUNTER6H] = { "hpmcounter6h", ctr32, read_zero }, - [CSR_HPMCOUNTER7H] = { "hpmcounter7h", ctr32, read_zero }, - [CSR_HPMCOUNTER8H] = { "hpmcounter8h", ctr32, read_zero }, - [CSR_HPMCOUNTER9H] = { "hpmcounter9h", ctr32, read_zero }, - [CSR_HPMCOUNTER10H] = { "hpmcounter10h", ctr32, read_zero }, - [CSR_HPMCOUNTER11H] = { "hpmcounter11h", ctr32, read_zero }, - [CSR_HPMCOUNTER12H] = { "hpmcounter12h", ctr32, read_zero }, - [CSR_HPMCOUNTER13H] = { "hpmcounter13h", ctr32, read_zero }, - [CSR_HPMCOUNTER14H] = { "hpmcounter14h", ctr32, read_zero }, - [CSR_HPMCOUNTER15H] = { "hpmcounter15h", ctr32, read_zero }, - [CSR_HPMCOUNTER16H] = { "hpmcounter16h", ctr32, read_zero }, - [CSR_HPMCOUNTER17H] = { "hpmcounter17h", ctr32, read_zero }, - [CSR_HPMCOUNTER18H] = { "hpmcounter18h", ctr32, read_zero }, - [CSR_HPMCOUNTER19H] = { "hpmcounter19h", ctr32, read_zero }, - [CSR_HPMCOUNTER20H] = { "hpmcounter20h", ctr32, read_zero }, - [CSR_HPMCOUNTER21H] = { "hpmcounter21h", ctr32, read_zero }, - [CSR_HPMCOUNTER22H] = { "hpmcounter22h", ctr32, read_zero }, - [CSR_HPMCOUNTER23H] = { "hpmcounter23h", ctr32, read_zero }, - [CSR_HPMCOUNTER24H] = { "hpmcounter24h", ctr32, read_zero }, - [CSR_HPMCOUNTER25H] = { "hpmcounter25h", ctr32, read_zero }, - [CSR_HPMCOUNTER26H] = { "hpmcounter26h", ctr32, read_zero }, - [CSR_HPMCOUNTER27H] = { "hpmcounter27h", ctr32, read_zero }, - [CSR_HPMCOUNTER28H] = { "hpmcounter28h", ctr32, read_zero }, - [CSR_HPMCOUNTER29H] = { "hpmcounter29h", ctr32, read_zero }, - [CSR_HPMCOUNTER30H] = { "hpmcounter30h", ctr32, read_zero }, - [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_zero }, - - [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", any32, read_zero }, - [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", any32, read_zero }, - [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", any32, read_zero }, - [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", any32, read_zero }, - [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", any32, read_zero }, - [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", any32, read_zero }, - [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", any32, read_zero }, - [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", any32, read_zero }, - [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", any32, read_zero }, - [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", any32, read_zero }, - [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", any32, read_zero }, - [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", any32, read_zero }, - [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", any32, read_zero }, - [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", any32, read_zero }, - [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", any32, read_zero }, - [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", any32, read_zero }, - [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", any32, read_zero }, - [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", any32, read_zero }, - [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", any32, read_zero }, - [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", any32, read_zero }, - [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", any32, read_zero }, - [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", any32, read_zero }, - [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", any32, read_zero }, - [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", any32, read_zero }, - [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", any32, read_zero }, - [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", any32, read_zero }, - [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", any32, read_zero }, - [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", any32, read_zero }, - [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", any32, read_zero }, + [CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER5] = { "hpmcounter5", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER6] = { "hpmcounter6", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER7] = { "hpmcounter7", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER8] = { "hpmcounter8", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER9] = { "hpmcounter9", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER10] = { "hpmcounter10", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER11] = { "hpmcounter11", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER12] = { "hpmcounter12", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER13] = { "hpmcounter13", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER14] = { "hpmcounter14", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER15] = { "hpmcounter15", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER16] = { "hpmcounter16", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER17] = { "hpmcounter17", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER18] = { "hpmcounter18", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER19] = { "hpmcounter19", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER20] = { "hpmcounter20", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER21] = { "hpmcounter21", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER22] = { "hpmcounter22", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER23] = { "hpmcounter23", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER24] = { "hpmcounter24", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER25] = { "hpmcounter25", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER26] = { "hpmcounter26", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER27] = { "hpmcounter27", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER28] = { "hpmcounter28", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER29] = { "hpmcounter29", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER30] = { "hpmcounter30", ctr, read_hpmcounter }, + [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_hpmcounter }, + + [CSR_MHPMCOUNTER3] = { "mhpmcounter3", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER4] = { "mhpmcounter4", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER5] = { "mhpmcounter5", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER6] = { "mhpmcounter6", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER7] = { "mhpmcounter7", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER8] = { "mhpmcounter8", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER9] = { "mhpmcounter9", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER10] = { "mhpmcounter10", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER11] = { "mhpmcounter11", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER12] = { "mhpmcounter12", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER13] = { "mhpmcounter13", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER14] = { "mhpmcounter14", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER15] = { "mhpmcounter15", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER16] = { "mhpmcounter16", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER17] = { "mhpmcounter17", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER18] = { "mhpmcounter18", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER19] = { "mhpmcounter19", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER20] = { "mhpmcounter20", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER21] = { "mhpmcounter21", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER22] = { "mhpmcounter22", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER23] = { "mhpmcounter23", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER24] = { "mhpmcounter24", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER25] = { "mhpmcounter25", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER26] = { "mhpmcounter26", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER27] = { "mhpmcounter27", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER28] = { "mhpmcounter28", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER29] = { "mhpmcounter29", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER30] = { "mhpmcounter30", mctr, read_hpmcounter, + write_mhpmcounter }, + [CSR_MHPMCOUNTER31] = { "mhpmcounter31", mctr, read_hpmcounter, + write_mhpmcounter }, + + [CSR_MCOUNTINHIBIT] = { "mcountinhibit", any, read_mcountinhibit, + write_mcountinhibit, + .min_priv_ver = PRIV_VERSION_1_11_0 }, + + [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_mhpmevent, + write_mhpmevent }, + [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_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 }, + [CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER6H] = { "hpmcounter6h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER7H] = { "hpmcounter7h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER8H] = { "hpmcounter8h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER9H] = { "hpmcounter9h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER10H] = { "hpmcounter10h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER11H] = { "hpmcounter11h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER12H] = { "hpmcounter12h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER13H] = { "hpmcounter13h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER14H] = { "hpmcounter14h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER15H] = { "hpmcounter15h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER16H] = { "hpmcounter16h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER17H] = { "hpmcounter17h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER18H] = { "hpmcounter18h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER19H] = { "hpmcounter19h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER20H] = { "hpmcounter20h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER21H] = { "hpmcounter21h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER22H] = { "hpmcounter22h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER23H] = { "hpmcounter23h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER24H] = { "hpmcounter24h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER25H] = { "hpmcounter25h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER26H] = { "hpmcounter26h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER27H] = { "hpmcounter27h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER28H] = { "hpmcounter28h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER29H] = { "hpmcounter29h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER30H] = { "hpmcounter30h", ctr32, read_hpmcounterh }, + [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_hpmcounterh }, + + [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", mctr32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", mctr32, read_hpmcounterh, + 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 new file mode 100644 index 000000000000..bf4840a6a3da --- /dev/null +++ b/target/riscv/debug.c @@ -0,0 +1,934 @@ +/* + * QEMU RISC-V Native Debug Support + * + * Copyright (c) 2022 Wind River Systems, Inc. + * + * Author: + * Bin Meng + * + * This provides the native debug support via the Trigger Module, as defined + * in the RISC-V Debug Specification: + * https://github.com/riscv/riscv-debug-spec/raw/master/riscv-debug-stable.pdf + * + * 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 "qapi/error.h" +#include "cpu.h" +#include "trace.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "sysemu/cpu-timers.h" + +/* + * The following M-mode trigger CSRs are implemented: + * + * - tselect + * - tdata1 + * - tdata2 + * - tdata3 + * - tinfo + * + * The following triggers are initialized by default: + * + * Index | Type | tdata mapping | Description + * ------+------+------------------------+------------ + * 0 | 2 | tdata1, tdata2 | Address / Data Match + * 1 | 2 | tdata1, tdata2 | Address / Data Match + */ + +/* tdata availability of a trigger */ +typedef bool tdata_avail[TDATA_NUM]; + +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 */ +static int access_size[SIZE_NUM] = { + [SIZE_ANY] = 0, + [SIZE_1B] = 1, + [SIZE_2B] = 2, + [SIZE_4B] = 4, + [SIZE_6B] = -1, + [SIZE_8B] = 8, + [6 ... 15] = -1, +}; + +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) | + (dmode ? RV32_DMODE : 0) | + (data & RV32_DATA_MASK); + break; + case MXL_RV64: + case MXL_RV128: + tdata1 = RV64_TYPE(type) | + (dmode ? RV64_DMODE : 0) | + (data & RV64_DATA_MASK); + break; + default: + g_assert_not_reached(); + } + + return tdata1; +} + +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; + } + + return tdata_mapping[trigger_type][tdata_index]; +} + +target_ulong tselect_csr_read(CPURISCVState *env) +{ + return env->trigger_cur; +} + +void tselect_csr_write(CPURISCVState *env, target_ulong val) +{ + if (val < RV_MAX_TRIGGERS) { + env->trigger_cur = val; + } +} + +static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, + trigger_type_t t) +{ + uint32_t type, dmode; + target_ulong tdata1; + + switch (riscv_cpu_mxl(env)) { + case MXL_RV32: + type = extract32(val, 28, 4); + dmode = extract32(val, 27, 1); + tdata1 = RV32_TYPE(t); + break; + case MXL_RV64: + case MXL_RV128: + type = extract64(val, 60, 4); + dmode = extract64(val, 59, 1); + tdata1 = RV64_TYPE(t); + break; + default: + g_assert_not_reached(); + } + + if (type != t) { + 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"); + } + + return tdata1; +} + +static inline void warn_always_zero_bit(target_ulong val, target_ulong mask, + const char *msg) +{ + if (val & mask) { + qemu_log_mask(LOG_UNIMP, "%s bit is always zero\n", msg); + } +} + +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 sizelo, sizehi = 0; + + if (riscv_cpu_mxl(env) == MXL_RV64) { + sizehi = extract32(ctrl, 21, 2); + } + sizelo = extract32(ctrl, 16, 2); + return (sizehi << 2) | sizelo; +} + +static inline bool type2_breakpoint_enabled(target_ulong ctrl) +{ + bool mode = !!(ctrl & (TYPE2_U | TYPE2_S | TYPE2_M)); + bool rwx = !!(ctrl & (TYPE2_LOAD | TYPE2_STORE | TYPE2_EXEC)); + + return mode && rwx; +} + +static target_ulong type2_mcontrol_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_MATCH); + + /* validate unimplemented (always zero) bits */ + warn_always_zero_bit(ctrl, TYPE2_MATCH, "match"); + warn_always_zero_bit(ctrl, TYPE2_CHAIN, "chain"); + warn_always_zero_bit(ctrl, TYPE2_ACTION, "action"); + warn_always_zero_bit(ctrl, TYPE2_TIMING, "timing"); + warn_always_zero_bit(ctrl, TYPE2_SELECT, "select"); + warn_always_zero_bit(ctrl, TYPE2_HIT, "hit"); + + /* validate size encoding */ + size = type2_breakpoint_size(env, ctrl); + if (access_size[size] == -1) { + qemu_log_mask(LOG_UNIMP, "access size %d is not supported, using SIZE_ANY\n", + size); + } else { + val |= (ctrl & TYPE2_SIZELO); + if (riscv_cpu_mxl(env) == MXL_RV64) { + val |= (ctrl & TYPE2_SIZEHI); + } + } + + /* keep the mode and attribute bits */ + val |= (ctrl & (TYPE2_U | TYPE2_S | TYPE2_M | + TYPE2_LOAD | TYPE2_STORE | TYPE2_EXEC)); + + return val; +} + +static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) +{ + 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; + uint32_t size; + + if (!enabled) { + return; + } + + if (ctrl & TYPE2_EXEC) { + cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); + } + + if (ctrl & TYPE2_LOAD) { + flags |= BP_MEM_READ; + } + if (ctrl & TYPE2_STORE) { + flags |= BP_MEM_WRITE; + } + + if (flags & BP_MEM_ACCESS) { + size = type2_breakpoint_size(env, ctrl); + 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 type2_breakpoint_remove(CPURISCVState *env, target_ulong index) +{ + CPUState *cs = env_cpu(env); + + if (env->cpu_breakpoint[index]) { + cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); + env->cpu_breakpoint[index] = NULL; + } + + if (env->cpu_watchpoint[index]) { + cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); + env->cpu_watchpoint[index] = NULL; + } +} + +static void type2_reg_write(CPURISCVState *env, target_ulong index, + int tdata_index, target_ulong val) +{ + target_ulong new_val; + + switch (tdata_index) { + case TDATA1: + new_val = type2_mcontrol_validate(env, 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->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(); + } + + return; +} + +/* type 6 trigger */ + +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)); + + return mode && rwx; +} + +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; +} + +/* icount trigger type */ +static inline int +itrigger_get_count(CPURISCVState *env, int index) +{ + return get_field(env->tdata1[index], ITRIGGER_COUNT); +} + +static inline void +itrigger_set_count(CPURISCVState *env, int index, int value) +{ + env->tdata1[index] = set_field(env->tdata1[index], + ITRIGGER_COUNT, value); +} + +static bool check_itrigger_priv(CPURISCVState *env, int index) +{ + target_ulong tdata1 = env->tdata1[index]; + if (riscv_cpu_virt_enabled(env)) { + /* check VU/VS bit against current privilege level */ + return (get_field(tdata1, ITRIGGER_VS) == env->priv) || + (get_field(tdata1, ITRIGGER_VU) == env->priv); + } else { + /* check U/S/M bit against current privilege level */ + return (get_field(tdata1, ITRIGGER_M) == env->priv) || + (get_field(tdata1, ITRIGGER_S) == env->priv) || + (get_field(tdata1, ITRIGGER_U) == env->priv); + } +} + +bool riscv_itrigger_enabled(CPURISCVState *env) +{ + int count; + for (int i = 0; i < RV_MAX_TRIGGERS; i++) { + if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) { + continue; + } + if (check_itrigger_priv(env, i)) { + continue; + } + count = itrigger_get_count(env, i); + if (!count) { + continue; + } + return true; + } + + return false; +} + +void helper_itrigger_match(CPURISCVState *env) +{ + int count; + for (int i = 0; i < RV_MAX_TRIGGERS; i++) { + if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) { + continue; + } + if (check_itrigger_priv(env, i)) { + continue; + } + count = itrigger_get_count(env, i); + if (!count) { + continue; + } + itrigger_set_count(env, i, count--); + if (!count) { + env->itrigger_enabled = riscv_itrigger_enabled(env); + do_trigger_action(env, i); + } + } +} + +static void riscv_itrigger_update_count(CPURISCVState *env) +{ + int count, executed; + /* + * Record last icount, so that we can evaluate the executed instructions + * since last priviledge mode change or timer expire. + */ + int64_t last_icount = env->last_icount, current_icount; + current_icount = env->last_icount = icount_get_raw(); + + for (int i = 0; i < RV_MAX_TRIGGERS; i++) { + if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) { + continue; + } + count = itrigger_get_count(env, i); + if (!count) { + continue; + } + /* + * Only when priviledge is changed or itrigger timer expires, + * the count field in itrigger tdata1 register is updated. + * And the count field in itrigger only contains remaining value. + */ + if (check_itrigger_priv(env, i)) { + /* + * If itrigger enabled in this priviledge mode, the number of + * executed instructions since last priviledge change + * should be reduced from current itrigger count. + */ + executed = current_icount - last_icount; + itrigger_set_count(env, i, count - executed); + if (count == executed) { + do_trigger_action(env, i); + } + } else { + /* + * If itrigger is not enabled in this priviledge mode, + * the number of executed instructions will be discard and + * the count field in itrigger will not change. + */ + timer_mod(env->itrigger_timer[i], + current_icount + count); + } + } +} + +static void riscv_itrigger_timer_cb(void *opaque) +{ + riscv_itrigger_update_count((CPURISCVState *)opaque); +} + +void riscv_itrigger_update_priv(CPURISCVState *env) +{ + riscv_itrigger_update_count(env); +} + +static target_ulong itrigger_validate(CPURISCVState *env, + target_ulong ctrl) +{ + target_ulong val; + + /* validate the generic part first */ + val = tdata1_validate(env, ctrl, TRIGGER_TYPE_INST_CNT); + + /* validate unimplemented (always zero) bits */ + warn_always_zero_bit(ctrl, ITRIGGER_ACTION, "action"); + warn_always_zero_bit(ctrl, ITRIGGER_HIT, "hit"); + warn_always_zero_bit(ctrl, ITRIGGER_PENDING, "pending"); + + /* keep the mode and attribute bits */ + val |= ctrl & (ITRIGGER_VU | ITRIGGER_VS | ITRIGGER_U | ITRIGGER_S | + ITRIGGER_M | ITRIGGER_COUNT); + + return val; +} + +static void itrigger_reg_write(CPURISCVState *env, target_ulong index, + int tdata_index, target_ulong val) +{ + target_ulong new_val; + + switch (tdata_index) { + case TDATA1: + /* set timer for icount */ + new_val = itrigger_validate(env, val); + if (new_val != env->tdata1[index]) { + env->tdata1[index] = new_val; + if (icount_enabled()) { + env->last_icount = icount_get_raw(); + /* set the count to timer */ + timer_mod(env->itrigger_timer[index], + env->last_icount + itrigger_get_count(env, index)); + } else { + env->itrigger_enabled = riscv_itrigger_enabled(env); + } + } + break; + case TDATA2: + qemu_log_mask(LOG_UNIMP, + "tdata2 is not supported for icount trigger\n"); + break; + case TDATA3: + qemu_log_mask(LOG_UNIMP, + "tdata3 is not supported for icount trigger\n"); + break; + default: + g_assert_not_reached(); + } + + return; +} + +static int itrigger_get_adjust_count(CPURISCVState *env) +{ + int count = itrigger_get_count(env, env->trigger_cur), executed; + if ((count != 0) && check_itrigger_priv(env, env->trigger_cur)) { + executed = icount_get_raw() - env->last_icount; + count += executed; + } + return count; +} + +target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index) +{ + int trigger_type; + switch (tdata_index) { + case TDATA1: + trigger_type = extract_trigger_type(env, env->tdata1[env->trigger_cur]); + if ((trigger_type == TRIGGER_TYPE_INST_CNT) && icount_enabled()) { + return deposit64(env->tdata1[env->trigger_cur], 10, 14, + itrigger_get_adjust_count(env)); + } + 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) +{ + int trigger_type; + + 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: + itrigger_reg_write(env, env->trigger_cur, tdata_index, val); + break; + 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) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + + if (cs->watchpoint_hit) { + if (cs->watchpoint_hit->flags & BP_CPU) { + cs->watchpoint_hit = NULL; + do_trigger_action(env, DBG_ACTION_BP); + } + } else { + if (cpu_breakpoint_test(cs, env->pc, BP_CPU)) { + do_trigger_action(env, DBG_ACTION_BP); + } + } +} + +bool riscv_cpu_debug_check_breakpoint(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + CPUBreakpoint *bp; + target_ulong ctrl; + target_ulong pc; + int trigger_type; + int i; + + QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { + for (i = 0; i < RV_MAX_TRIGGERS; i++) { + trigger_type = get_trigger_type(env, i); + + 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; + } + } + } + + return false; +} + +bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + target_ulong ctrl; + target_ulong addr; + int trigger_type; + int flags; + int i; + + for (i = 0; i < RV_MAX_TRIGGERS; i++) { + trigger_type = get_trigger_type(env, i); + + 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; + } + } + + return false; +} + +void riscv_trigger_init(CPURISCVState *env) +{ + target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0); + int 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) + * maskmax = 0 (unimplemented, always 0) + * sizehi = 0 (match against any size, RV64 only) + * hit = 0 (unimplemented, always 0) + * select = 0 (always 0, perform match on address) + * timing = 0 (always 0, trigger before instruction) + * sizelo = 0 (match against any size) + * action = 0 (always 0, raise a breakpoint exception) + * chain = 0 (unimplemented, always 0) + * match = 0 (always 0, when any compare value equals tdata2) + */ + env->tdata1[i] = tdata1; + env->tdata2[i] = 0; + env->tdata3[i] = 0; + env->cpu_breakpoint[i] = NULL; + env->cpu_watchpoint[i] = NULL; + env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL, + riscv_itrigger_timer_cb, env); + } +} diff --git a/target/riscv/debug.h b/target/riscv/debug.h new file mode 100644 index 000000000000..c471748d5a90 --- /dev/null +++ b/target/riscv/debug.h @@ -0,0 +1,150 @@ +/* + * QEMU RISC-V Native Debug Support + * + * Copyright (c) 2022 Wind River Systems, Inc. + * + * Author: + * Bin Meng + * + * 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_DEBUG_H +#define RISCV_DEBUG_H + +#define RV_MAX_TRIGGERS 2 + +/* register index of tdata CSRs */ +enum { + TDATA1 = 0, + TDATA2, + TDATA3, + TDATA_NUM +}; + +typedef enum { + TRIGGER_TYPE_NO_EXIST = 0, /* trigger does not exist */ + TRIGGER_TYPE_AD_MATCH = 2, /* address/data match trigger */ + TRIGGER_TYPE_INST_CNT = 3, /* instruction count trigger */ + TRIGGER_TYPE_INT = 4, /* interrupt trigger */ + 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_NUM +} trigger_type_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; + +/* 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 */ + +#define TYPE2_LOAD BIT(0) +#define TYPE2_STORE BIT(1) +#define TYPE2_EXEC BIT(2) +#define TYPE2_U BIT(3) +#define TYPE2_S BIT(4) +#define TYPE2_M BIT(6) +#define TYPE2_MATCH (0xf << 7) +#define TYPE2_CHAIN BIT(11) +#define TYPE2_ACTION (0xf << 12) +#define TYPE2_SIZELO (0x3 << 16) +#define TYPE2_TIMING BIT(18) +#define TYPE2_SELECT BIT(19) +#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, + SIZE_1B, + SIZE_2B, + SIZE_4B, + SIZE_6B, + SIZE_8B, + SIZE_10B, + SIZE_12B, + SIZE_14B, + SIZE_16B, + SIZE_NUM = 16 +}; + +/* itrigger filed masks */ +#define ITRIGGER_ACTION 0x3f +#define ITRIGGER_U BIT(6) +#define ITRIGGER_S BIT(7) +#define ITRIGGER_PENDING BIT(8) +#define ITRIGGER_M BIT(9) +#define ITRIGGER_COUNT (0x3fff << 10) +#define ITRIGGER_HIT BIT(24) +#define ITRIGGER_VU BIT(25) +#define ITRIGGER_VS BIT(26) + +bool tdata_available(CPURISCVState *env, int tdata_index); + +target_ulong tselect_csr_read(CPURISCVState *env); +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); + +void riscv_trigger_init(CPURISCVState *env); + +bool riscv_itrigger_enabled(CPURISCVState *env); +void riscv_itrigger_update_priv(CPURISCVState *env); +#endif /* RISCV_DEBUG_H */ diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 9ed049c29ea5..6e7bbdbd5eb3 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 26bbab2fabcd..227c7122ef9a 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -66,6 +66,11 @@ DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64) /* Bitmanip */ DEF_HELPER_FLAGS_2(clmul, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_FLAGS_2(clmulr, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_1(brev8, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(unzip, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(zip, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_2(xperm4, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(xperm8, TCG_CALL_NO_RWG_SE, tl, tl, tl) /* Floating Point - Half Precision */ DEF_HELPER_FLAGS_3(fadd_h, TCG_CALL_NO_RWG, i64, env, i64, i64) @@ -104,6 +109,8 @@ DEF_HELPER_1(sret, tl, env) DEF_HELPER_1(mret, tl, env) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(tlb_flush, void, env) +/* Native Debug */ +DEF_HELPER_1(itrigger_match, void, env) #endif /* Hypervisor functions */ @@ -1004,9 +1011,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) @@ -1014,8 +1024,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) @@ -1086,10 +1098,7 @@ DEF_HELPER_6(vcompress_vm_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vcompress_vm_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vcompress_vm_d, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_4(vmv1r_v, void, ptr, ptr, env, i32) -DEF_HELPER_4(vmv2r_v, void, ptr, ptr, env, i32) -DEF_HELPER_4(vmv4r_v, void, ptr, ptr, env, i32) -DEF_HELPER_4(vmv8r_v, void, ptr, ptr, env, i32) +DEF_HELPER_4(vmvr_v, void, ptr, ptr, env, i32) DEF_HELPER_5(vzext_vf2_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vzext_vf2_w, void, ptr, ptr, ptr, env, i32) @@ -1110,3 +1119,20 @@ DEF_HELPER_5(divu_i128, tl, env, tl, tl, tl, tl) DEF_HELPER_5(divs_i128, tl, env, tl, tl, tl, tl) DEF_HELPER_5(remu_i128, tl, env, tl, tl, tl, tl) DEF_HELPER_5(rems_i128, tl, env, tl, tl, tl, tl) + +/* Crypto functions */ +DEF_HELPER_FLAGS_3(aes32esmi, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(aes32esi, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(aes32dsmi, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(aes32dsi, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) + +DEF_HELPER_FLAGS_2(aes64esm, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(aes64es, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(aes64ds, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(aes64dsm, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(aes64ks2, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(aes64ks1i, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_1(aes64im, TCG_CALL_NO_RWG_SE, tl, tl) + +DEF_HELPER_FLAGS_3(sm4ed, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(sm4ks, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index 02c8f61b4814..ccfe59f294d0 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 1d3ff1efe1db..b7e7613ea236 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -35,6 +35,8 @@ %imm_b 31:s1 7:1 25:6 8:4 !function=ex_shift_1 %imm_j 31:s1 12:8 20:1 21:10 !function=ex_shift_1 %imm_u 12:s20 !function=ex_shift_12 +%imm_bs 30:2 !function=ex_shift_3 +%imm_rnum 20:4 # Argument sets: &empty @@ -52,6 +54,7 @@ &rmr vm rd rs2 &r2nfvm vm rd rs1 nf &rnfvm vm rd rs1 rs2 nf +&k_aes shamt rs2 rs1 rd # Formats 32: @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd @@ -89,6 +92,9 @@ @sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vm ....... ..... ..... ... ..... ....... %rs1 +@k_aes .. ..... ..... ..... ... ..... ....... &k_aes shamt=%imm_bs %rs2 %rs1 %rd +@i_aes .. ..... ..... ..... ... ..... ....... &i imm=%imm_rnum %rs1 %rd + # Formats 64: @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd @@ -143,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 @@ -653,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 @@ -705,6 +718,10 @@ vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm11 vsetivli 11 .......... ..... 111 ..... 1010111 @r2_zimm10 vsetvl 1000000 ..... ..... 111 ..... 1010111 @r +# *** Zawrs Standard Extension *** +wrs_nto 000000001101 00000 000 00000 1110011 +wrs_sto 000000011101 00000 000 00000 1110011 + # *** RV32 Zba Standard Extension *** sh1add 0010000 .......... 010 ..... 0110011 @r sh2add 0010000 .......... 100 ..... 0110011 @r @@ -717,8 +734,22 @@ sh2add_uw 0010000 .......... 100 ..... 0111011 @r sh3add_uw 0010000 .......... 110 ..... 0111011 @r slli_uw 00001 ............ 001 ..... 0011011 @sh -# *** RV32 Zbb Standard Extension *** +# *** RV32 Zbb/Zbkb Standard Extension *** andn 0100000 .......... 111 ..... 0110011 @r +rol 0110000 .......... 001 ..... 0110011 @r +ror 0110000 .......... 101 ..... 0110011 @r +rori 01100 ............ 101 ..... 0010011 @sh +# The encoding for rev8 differs between RV32 and RV64. +# rev8_32 denotes the RV32 variant. +rev8_32 011010 011000 ..... 101 ..... 0010011 @r2 +# The encoding for zext.h differs between RV32 and RV64. +# zext_h_32 denotes the RV32 variant. +{ + zext_h_32 0000100 00000 ..... 100 ..... 0110011 @r2 + pack 0000100 ..... ..... 100 ..... 0110011 @r +} +xnor 0100000 .......... 100 ..... 0110011 @r +# *** RV32 extra Zbb Standard Extension *** clz 011000 000000 ..... 001 ..... 0010011 @r2 cpop 011000 000010 ..... 001 ..... 0010011 @r2 ctz 011000 000001 ..... 001 ..... 0010011 @r2 @@ -728,23 +759,15 @@ min 0000101 .......... 100 ..... 0110011 @r minu 0000101 .......... 101 ..... 0110011 @r orc_b 001010 000111 ..... 101 ..... 0010011 @r2 orn 0100000 .......... 110 ..... 0110011 @r -# The encoding for rev8 differs between RV32 and RV64. -# rev8_32 denotes the RV32 variant. -rev8_32 011010 011000 ..... 101 ..... 0010011 @r2 -rol 0110000 .......... 001 ..... 0110011 @r -ror 0110000 .......... 101 ..... 0110011 @r -rori 01100 ............ 101 ..... 0010011 @sh sext_b 011000 000100 ..... 001 ..... 0010011 @r2 sext_h 011000 000101 ..... 001 ..... 0010011 @r2 -xnor 0100000 .......... 100 ..... 0110011 @r -# The encoding for zext.h differs between RV32 and RV64. -# zext_h_32 denotes the RV32 variant. -zext_h_32 0000100 00000 ..... 100 ..... 0110011 @r2 +# *** RV32 extra Zbkb Standard Extension *** +brev8 0110100 00111 ..... 101 ..... 0010011 @r2 #grevi +packh 0000100 .......... 111 ..... 0110011 @r +unzip 0000100 01111 ..... 101 ..... 0010011 @r2 #unshfl +zip 0000100 01111 ..... 001 ..... 0010011 @r2 #shfl -# *** RV64 Zbb Standard Extension (in addition to RV32 Zbb) *** -clzw 0110000 00000 ..... 001 ..... 0011011 @r2 -ctzw 0110000 00001 ..... 001 ..... 0011011 @r2 -cpopw 0110000 00010 ..... 001 ..... 0011011 @r2 +# *** RV64 Zbb/Zbkb Standard Extension (in addition to RV32 Zbb/Zbkb) *** # The encoding for rev8 differs between RV32 and RV64. # When executing on RV64, the encoding used in RV32 is an illegal # instruction, so we use different handler functions to differentiate. @@ -755,13 +778,25 @@ rorw 0110000 .......... 101 ..... 0111011 @r # The encoding for zext.h differs between RV32 and RV64. # When executing on RV64, the encoding used in RV32 is an illegal # instruction, so we use different handler functions to differentiate. -zext_h_64 0000100 00000 ..... 100 ..... 0111011 @r2 +{ + zext_h_64 0000100 00000 ..... 100 ..... 0111011 @r2 + packw 0000100 ..... ..... 100 ..... 0111011 @r +} +# *** RV64 extra Zbb Standard Extension (in addition to RV32 Zbb) *** +clzw 0110000 00000 ..... 001 ..... 0011011 @r2 +ctzw 0110000 00001 ..... 001 ..... 0011011 @r2 +cpopw 0110000 00010 ..... 001 ..... 0011011 @r2 -# *** RV32 Zbc Standard Extension *** +# *** RV32 Zbc/Zbkc Standard Extension *** clmul 0000101 .......... 001 ..... 0110011 @r clmulh 0000101 .......... 011 ..... 0110011 @r +# *** RV32 extra Zbc Standard Extension *** clmulr 0000101 .......... 010 ..... 0110011 @r +# *** RV32 Zbkx Standard Extension *** +xperm4 0010100 .......... 010 ..... 0110011 @r +xperm8 0010100 .......... 100 ..... 0110011 @r + # *** RV32 Zbs Standard Extension *** bclr 0100100 .......... 001 ..... 0110011 @r bclri 01001. ........... 001 ..... 0010011 @sh @@ -816,3 +851,42 @@ sfence_w_inval 0001100 00000 00000 000 00000 1110011 sfence_inval_ir 0001100 00001 00000 000 00000 1110011 hinval_vvma 0010011 ..... ..... 000 00000 1110011 @hfence_vvma hinval_gvma 0110011 ..... ..... 000 00000 1110011 @hfence_gvma + +# *** RV32 Zknd Standard Extension *** +aes32dsmi .. 10111 ..... ..... 000 ..... 0110011 @k_aes +aes32dsi .. 10101 ..... ..... 000 ..... 0110011 @k_aes +# *** RV64 Zknd Standard Extension *** +aes64dsm 00 11111 ..... ..... 000 ..... 0110011 @r +aes64ds 00 11101 ..... ..... 000 ..... 0110011 @r +aes64im 00 11000 00000 ..... 001 ..... 0010011 @r2 +# *** RV32 Zkne Standard Extension *** +aes32esmi .. 10011 ..... ..... 000 ..... 0110011 @k_aes +aes32esi .. 10001 ..... ..... 000 ..... 0110011 @k_aes +# *** RV64 Zkne Standard Extension *** +aes64es 00 11001 ..... ..... 000 ..... 0110011 @r +aes64esm 00 11011 ..... ..... 000 ..... 0110011 @r +# *** RV64 Zkne/zknd Standard Extension *** +aes64ks2 01 11111 ..... ..... 000 ..... 0110011 @r +aes64ks1i 00 11000 1.... ..... 001 ..... 0010011 @i_aes +# *** RV32 Zknh Standard Extension *** +sha256sig0 00 01000 00010 ..... 001 ..... 0010011 @r2 +sha256sig1 00 01000 00011 ..... 001 ..... 0010011 @r2 +sha256sum0 00 01000 00000 ..... 001 ..... 0010011 @r2 +sha256sum1 00 01000 00001 ..... 001 ..... 0010011 @r2 +sha512sum0r 01 01000 ..... ..... 000 ..... 0110011 @r +sha512sum1r 01 01001 ..... ..... 000 ..... 0110011 @r +sha512sig0l 01 01010 ..... ..... 000 ..... 0110011 @r +sha512sig0h 01 01110 ..... ..... 000 ..... 0110011 @r +sha512sig1l 01 01011 ..... ..... 000 ..... 0110011 @r +sha512sig1h 01 01111 ..... ..... 000 ..... 0110011 @r +# *** RV64 Zknh Standard Extension *** +sha512sig0 00 01000 00110 ..... 001 ..... 0010011 @r2 +sha512sig1 00 01000 00111 ..... 001 ..... 0010011 @r2 +sha512sum0 00 01000 00100 ..... 001 ..... 0010011 @r2 +sha512sum1 00 01000 00101 ..... 001 ..... 0010011 @r2 +# *** RV32 Zksh Standard Extension *** +sm3p0 00 01000 01000 ..... 001 ..... 0010011 @r2 +sm3p1 00 01000 01001 ..... 001 ..... 0010011 @r2 +# *** RV32 Zksed Standard Extension *** +sm4ed .. 11000 ..... ..... 000 ..... 0110011 @k_aes +sm4ks .. 11010 ..... ..... 000 ..... 0110011 @k_aes diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 53613682e885..59501b278093 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); @@ -75,8 +76,9 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) { #ifndef CONFIG_USER_ONLY if (has_ext(ctx, RVS)) { + decode_save_opc(ctx); gen_helper_sret(cpu_pc, cpu_env); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ + exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; } else { return false; @@ -90,8 +92,9 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) static bool trans_mret(DisasContext *ctx, arg_mret *a) { #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_mret(cpu_pc, cpu_env); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ + exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; #else @@ -102,6 +105,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a) static bool trans_wfi(DisasContext *ctx, arg_wfi *a) { #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_set_pc_imm(ctx, ctx->pc_succ_insn); gen_helper_wfi(cpu_env); return true; @@ -113,6 +117,7 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a) static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a) { #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_tlb_flush(cpu_env); return true; #endif diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc index e8519a6d6989..e2b8329f1e5b 100644 --- a/target/riscv/insn_trans/trans_rvb.c.inc +++ b/target/riscv/insn_trans/trans_rvb.c.inc @@ -1,5 +1,5 @@ /* - * RISC-V translation routines for the Zb[abcs] Standard Extension. + * RISC-V translation routines for the Zb[abcs] and Zbk[bcx] Standard Extension. * * Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com * Copyright (c) 2020 Frank Chang, frank.chang@sifive.com @@ -42,6 +42,18 @@ } \ } while (0) +#define REQUIRE_ZBKB(ctx) do { \ + if (!ctx->cfg_ptr->ext_zbkb) { \ + return false; \ + } \ +} while (0) + +#define REQUIRE_ZBKX(ctx) do { \ + if (!ctx->cfg_ptr->ext_zbkx) { \ + return false; \ + } \ +} while (0) + static void gen_clz(TCGv ret, TCGv arg1) { tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS); @@ -85,19 +97,19 @@ static bool trans_cpop(DisasContext *ctx, arg_cpop *a) static bool trans_andn(DisasContext *ctx, arg_andn *a) { - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_logic(ctx, a, tcg_gen_andc_tl); } static bool trans_orn(DisasContext *ctx, arg_orn *a) { - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_logic(ctx, a, tcg_gen_orc_tl); } static bool trans_xnor(DisasContext *ctx, arg_xnor *a) { - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_logic(ctx, a, tcg_gen_eqv_tl); } @@ -247,7 +259,7 @@ static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2) static bool trans_ror(DisasContext *ctx, arg_ror *a) { - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotr_tl, gen_rorw, NULL); } @@ -264,7 +276,7 @@ static void gen_roriw(TCGv ret, TCGv arg1, target_long shamt) static bool trans_rori(DisasContext *ctx, arg_rori *a) { - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE, tcg_gen_rotri_tl, gen_roriw, NULL); } @@ -289,7 +301,7 @@ static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2) static bool trans_rol(DisasContext *ctx, arg_rol *a) { - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotl_tl, gen_rolw, NULL); } @@ -301,14 +313,14 @@ static void gen_rev8_32(TCGv ret, TCGv src1) static bool trans_rev8_32(DisasContext *ctx, arg_rev8_32 *a) { REQUIRE_32BIT(ctx); - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_unary(ctx, a, EXT_NONE, gen_rev8_32); } static bool trans_rev8_64(DisasContext *ctx, arg_rev8_64 *a) { REQUIRE_64BIT(ctx); - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); return gen_unary(ctx, a, EXT_NONE, tcg_gen_bswap_tl); } @@ -403,7 +415,7 @@ static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a) static bool trans_rorw(DisasContext *ctx, arg_rorw *a) { REQUIRE_64BIT(ctx); - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_NONE, gen_rorw, NULL); } @@ -411,7 +423,7 @@ static bool trans_rorw(DisasContext *ctx, arg_rorw *a) static bool trans_roriw(DisasContext *ctx, arg_roriw *a) { REQUIRE_64BIT(ctx); - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); ctx->ol = MXL_RV32; return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw, NULL); } @@ -419,7 +431,7 @@ static bool trans_roriw(DisasContext *ctx, arg_roriw *a) static bool trans_rolw(DisasContext *ctx, arg_rolw *a) { REQUIRE_64BIT(ctx); - REQUIRE_ZBB(ctx); + REQUIRE_EITHER_EXT(ctx, zbb, zbkb); ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_NONE, gen_rolw, NULL); } @@ -483,7 +495,7 @@ static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a) static bool trans_clmul(DisasContext *ctx, arg_clmul *a) { - REQUIRE_ZBC(ctx); + REQUIRE_EITHER_EXT(ctx, zbc, zbkc); return gen_arith(ctx, a, EXT_NONE, gen_helper_clmul, NULL); } @@ -495,7 +507,7 @@ static void gen_clmulh(TCGv dst, TCGv src1, TCGv src2) static bool trans_clmulh(DisasContext *ctx, arg_clmulr *a) { - REQUIRE_ZBC(ctx); + REQUIRE_EITHER_EXT(ctx, zbc, zbkc); return gen_arith(ctx, a, EXT_NONE, gen_clmulh, NULL); } @@ -504,3 +516,79 @@ static bool trans_clmulr(DisasContext *ctx, arg_clmulh *a) REQUIRE_ZBC(ctx); return gen_arith(ctx, a, EXT_NONE, gen_helper_clmulr, NULL); } + +static void gen_pack(TCGv ret, TCGv src1, TCGv src2) +{ + tcg_gen_deposit_tl(ret, src1, src2, + TARGET_LONG_BITS / 2, + TARGET_LONG_BITS / 2); +} + +static void gen_packh(TCGv ret, TCGv src1, TCGv src2) +{ + TCGv t = tcg_temp_new(); + + tcg_gen_ext8u_tl(t, src2); + tcg_gen_deposit_tl(ret, src1, t, 8, TARGET_LONG_BITS - 8); + tcg_temp_free(t); +} + +static void gen_packw(TCGv ret, TCGv src1, TCGv src2) +{ + TCGv t = tcg_temp_new(); + + tcg_gen_ext16s_tl(t, src2); + tcg_gen_deposit_tl(ret, src1, t, 16, TARGET_LONG_BITS - 16); + tcg_temp_free(t); +} + +static bool trans_brev8(DisasContext *ctx, arg_brev8 *a) +{ + REQUIRE_ZBKB(ctx); + return gen_unary(ctx, a, EXT_NONE, gen_helper_brev8); +} + +static bool trans_pack(DisasContext *ctx, arg_pack *a) +{ + REQUIRE_ZBKB(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_pack, NULL); +} + +static bool trans_packh(DisasContext *ctx, arg_packh *a) +{ + REQUIRE_ZBKB(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_packh, NULL); +} + +static bool trans_packw(DisasContext *ctx, arg_packw *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZBKB(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_packw, NULL); +} + +static bool trans_unzip(DisasContext *ctx, arg_unzip *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZBKB(ctx); + return gen_unary(ctx, a, EXT_NONE, gen_helper_unzip); +} + +static bool trans_zip(DisasContext *ctx, arg_zip *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZBKB(ctx); + return gen_unary(ctx, a, EXT_NONE, gen_helper_zip); +} + +static bool trans_xperm4(DisasContext *ctx, arg_xperm4 *a) +{ + REQUIRE_ZBKX(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_helper_xperm4, NULL); +} + +static bool trans_xperm8(DisasContext *ctx, arg_xperm8 *a) +{ + REQUIRE_ZBKX(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_helper_xperm8, NULL); +} diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc index cebcb3f8f603..4f8aecddc7d4 100644 --- a/target/riscv/insn_trans/trans_rvh.c.inc +++ b/target/riscv/insn_trans/trans_rvh.c.inc @@ -169,6 +169,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) { REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_hyp_gvma_tlb_flush(cpu_env); return true; #endif @@ -179,6 +180,7 @@ static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) { REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_hyp_tlb_flush(cpu_env); return true; #endif diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index f1342f30f8e7..5c69b88d1ef7 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -32,17 +32,13 @@ static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a) static bool trans_lui(DisasContext *ctx, arg_lui *a) { - if (a->rd != 0) { - gen_set_gpri(ctx, a->rd, a->imm); - } + gen_set_gpri(ctx, a->rd, a->imm); return true; } static bool trans_auipc(DisasContext *ctx, arg_auipc *a) { - if (a->rd != 0) { - gen_set_gpri(ctx, a->rd, a->imm + ctx->base.pc_next); - } + gen_set_gpri(ctx, a->rd, a->imm + ctx->base.pc_next); return true; } @@ -70,7 +66,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a) } gen_set_gpri(ctx, a->rd, ctx->pc_succ_insn); - tcg_gen_lookup_and_goto_ptr(); + lookup_and_goto_ptr(ctx); if (misaligned) { gen_set_label(misaligned); @@ -796,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); + exit_tb(ctx); + ctx->base.is_jmp = DISAS_NORETURN; + + return true; +} static bool trans_fence(DisasContext *ctx, arg_fence *a) { @@ -815,16 +827,18 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) * however we need to end the translation block */ gen_set_pc_imm(ctx, ctx->pc_succ_insn); - tcg_gen_exit_tb(NULL, 0); + exit_tb(ctx); ctx->base.is_jmp = DISAS_NORETURN; return true; } static bool do_csr_post(DisasContext *ctx) { + /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ + decode_save_opc(ctx); /* We may have changed important cpu state -- exit to main loop. */ gen_set_pc_imm(ctx, ctx->pc_succ_insn); - tcg_gen_exit_tb(NULL, 0); + exit_tb(ctx); ctx->base.is_jmp = DISAS_NORETURN; return true; } diff --git a/target/riscv/insn_trans/trans_rvk.c.inc b/target/riscv/insn_trans/trans_rvk.c.inc new file mode 100644 index 000000000000..90f4eeff60a9 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvk.c.inc @@ -0,0 +1,391 @@ +/* + * RISC-V translation routines for the Zk[nd,ne,nh,sed,sh] Standard Extension. + * + * Copyright (c) 2021 Ruibo Lu, luruibo2000@163.com + * Copyright (c) 2021 Zewen Ye, lustrew@foxmail.com + * + * 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 . + */ + +#define REQUIRE_ZKND(ctx) do { \ + if (!ctx->cfg_ptr->ext_zknd) { \ + return false; \ + } \ +} while (0) + +#define REQUIRE_ZKNE(ctx) do { \ + if (!ctx->cfg_ptr->ext_zkne) { \ + return false; \ + } \ +} while (0) + +#define REQUIRE_ZKNH(ctx) do { \ + if (!ctx->cfg_ptr->ext_zknh) { \ + return false; \ + } \ +} while (0) + +#define REQUIRE_ZKSED(ctx) do { \ + if (!ctx->cfg_ptr->ext_zksed) { \ + return false; \ + } \ +} while (0) + +#define REQUIRE_ZKSH(ctx) do { \ + if (!ctx->cfg_ptr->ext_zksh) { \ + return false; \ + } \ +} while (0) + +static bool gen_aes32_sm4(DisasContext *ctx, arg_k_aes *a, + void (*func)(TCGv, TCGv, TCGv, TCGv)) +{ + TCGv shamt = tcg_constant_tl(a->shamt); + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); + + func(dest, src1, src2, shamt); + gen_set_gpr(ctx, a->rd, dest); + return true; +} + +static bool trans_aes32esmi(DisasContext *ctx, arg_aes32esmi *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNE(ctx); + return gen_aes32_sm4(ctx, a, gen_helper_aes32esmi); +} + +static bool trans_aes32esi(DisasContext *ctx, arg_aes32esi *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNE(ctx); + return gen_aes32_sm4(ctx, a, gen_helper_aes32esi); +} + +static bool trans_aes32dsmi(DisasContext *ctx, arg_aes32dsmi *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKND(ctx); + return gen_aes32_sm4(ctx, a, gen_helper_aes32dsmi); +} + +static bool trans_aes32dsi(DisasContext *ctx, arg_aes32dsi *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKND(ctx); + return gen_aes32_sm4(ctx, a, gen_helper_aes32dsi); +} + +static bool trans_aes64es(DisasContext *ctx, arg_aes64es *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKNE(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_helper_aes64es, NULL); +} + +static bool trans_aes64esm(DisasContext *ctx, arg_aes64esm *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKNE(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_helper_aes64esm, NULL); +} + +static bool trans_aes64ds(DisasContext *ctx, arg_aes64ds *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKND(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_helper_aes64ds, NULL); +} + +static bool trans_aes64dsm(DisasContext *ctx, arg_aes64dsm *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKND(ctx); + return gen_arith(ctx, a, EXT_NONE, gen_helper_aes64dsm, NULL); +} + +static bool trans_aes64ks2(DisasContext *ctx, arg_aes64ks2 *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_EITHER_EXT(ctx, zknd, zkne); + return gen_arith(ctx, a, EXT_NONE, gen_helper_aes64ks2, NULL); +} + +static bool trans_aes64ks1i(DisasContext *ctx, arg_aes64ks1i *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_EITHER_EXT(ctx, zknd, zkne); + + if (a->imm > 0xA) { + return false; + } + + return gen_arith_imm_tl(ctx, a, EXT_NONE, gen_helper_aes64ks1i, NULL); +} + +static bool trans_aes64im(DisasContext *ctx, arg_aes64im *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKND(ctx); + return gen_unary(ctx, a, EXT_NONE, gen_helper_aes64im); +} + +static bool gen_sha256(DisasContext *ctx, arg_r2 *a, DisasExtend ext, + void (*func)(TCGv_i32, TCGv_i32, int32_t), + int32_t num1, int32_t num2, int32_t num3) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, ext); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t0, src1); + tcg_gen_rotri_i32(t1, t0, num1); + tcg_gen_rotri_i32(t2, t0, num2); + tcg_gen_xor_i32(t1, t1, t2); + func(t2, t0, num3); + tcg_gen_xor_i32(t1, t1, t2); + tcg_gen_ext_i32_tl(dest, t1); + + gen_set_gpr(ctx, a->rd, dest); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + return true; +} + +static bool trans_sha256sig0(DisasContext *ctx, arg_sha256sig0 *a) +{ + REQUIRE_ZKNH(ctx); + return gen_sha256(ctx, a, EXT_NONE, tcg_gen_shri_i32, 7, 18, 3); +} + +static bool trans_sha256sig1(DisasContext *ctx, arg_sha256sig1 *a) +{ + REQUIRE_ZKNH(ctx); + return gen_sha256(ctx, a, EXT_NONE, tcg_gen_shri_i32, 17, 19, 10); +} + +static bool trans_sha256sum0(DisasContext *ctx, arg_sha256sum0 *a) +{ + REQUIRE_ZKNH(ctx); + return gen_sha256(ctx, a, EXT_NONE, tcg_gen_rotri_i32, 2, 13, 22); +} + +static bool trans_sha256sum1(DisasContext *ctx, arg_sha256sum1 *a) +{ + REQUIRE_ZKNH(ctx); + return gen_sha256(ctx, a, EXT_NONE, tcg_gen_rotri_i32, 6, 11, 25); +} + +static bool gen_sha512_rv32(DisasContext *ctx, arg_r *a, DisasExtend ext, + void (*func1)(TCGv_i64, TCGv_i64, int64_t), + void (*func2)(TCGv_i64, TCGv_i64, int64_t), + int64_t num1, int64_t num2, int64_t num3) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, ext); + TCGv src2 = get_gpr(ctx, a->rs2, ext); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_concat_tl_i64(t0, src1, src2); + func1(t1, t0, num1); + func2(t2, t0, num2); + tcg_gen_xor_i64(t1, t1, t2); + tcg_gen_rotri_i64(t2, t0, num3); + tcg_gen_xor_i64(t1, t1, t2); + tcg_gen_trunc_i64_tl(dest, t1); + + gen_set_gpr(ctx, a->rd, dest); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return true; +} + +static bool trans_sha512sum0r(DisasContext *ctx, arg_sha512sum0r *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv32(ctx, a, EXT_NONE, tcg_gen_rotli_i64, + tcg_gen_rotli_i64, 25, 30, 28); +} + +static bool trans_sha512sum1r(DisasContext *ctx, arg_sha512sum1r *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv32(ctx, a, EXT_NONE, tcg_gen_rotli_i64, + tcg_gen_rotri_i64, 23, 14, 18); +} + +static bool trans_sha512sig0l(DisasContext *ctx, arg_sha512sig0l *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv32(ctx, a, EXT_NONE, tcg_gen_rotri_i64, + tcg_gen_rotri_i64, 1, 7, 8); +} + +static bool trans_sha512sig1l(DisasContext *ctx, arg_sha512sig1l *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv32(ctx, a, EXT_NONE, tcg_gen_rotli_i64, + tcg_gen_rotri_i64, 3, 6, 19); +} + +static bool gen_sha512h_rv32(DisasContext *ctx, arg_r *a, DisasExtend ext, + void (*func)(TCGv_i64, TCGv_i64, int64_t), + int64_t num1, int64_t num2, int64_t num3) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, ext); + TCGv src2 = get_gpr(ctx, a->rs2, ext); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_concat_tl_i64(t0, src1, src2); + func(t1, t0, num1); + tcg_gen_ext32u_i64(t2, t0); + tcg_gen_shri_i64(t2, t2, num2); + tcg_gen_xor_i64(t1, t1, t2); + tcg_gen_rotri_i64(t2, t0, num3); + tcg_gen_xor_i64(t1, t1, t2); + tcg_gen_trunc_i64_tl(dest, t1); + + gen_set_gpr(ctx, a->rd, dest); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return true; +} + +static bool trans_sha512sig0h(DisasContext *ctx, arg_sha512sig0h *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512h_rv32(ctx, a, EXT_NONE, tcg_gen_rotri_i64, 1, 7, 8); +} + +static bool trans_sha512sig1h(DisasContext *ctx, arg_sha512sig1h *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512h_rv32(ctx, a, EXT_NONE, tcg_gen_rotli_i64, 3, 6, 19); +} + +static bool gen_sha512_rv64(DisasContext *ctx, arg_r2 *a, DisasExtend ext, + void (*func)(TCGv_i64, TCGv_i64, int64_t), + int64_t num1, int64_t num2, int64_t num3) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, ext); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t0, src1); + tcg_gen_rotri_i64(t1, t0, num1); + tcg_gen_rotri_i64(t2, t0, num2); + tcg_gen_xor_i64(t1, t1, t2); + func(t2, t0, num3); + tcg_gen_xor_i64(t1, t1, t2); + tcg_gen_trunc_i64_tl(dest, t1); + + gen_set_gpr(ctx, a->rd, dest); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return true; +} + +static bool trans_sha512sig0(DisasContext *ctx, arg_sha512sig0 *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv64(ctx, a, EXT_NONE, tcg_gen_shri_i64, 1, 8, 7); +} + +static bool trans_sha512sig1(DisasContext *ctx, arg_sha512sig1 *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv64(ctx, a, EXT_NONE, tcg_gen_shri_i64, 19, 61, 6); +} + +static bool trans_sha512sum0(DisasContext *ctx, arg_sha512sum0 *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv64(ctx, a, EXT_NONE, tcg_gen_rotri_i64, 28, 34, 39); +} + +static bool trans_sha512sum1(DisasContext *ctx, arg_sha512sum1 *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZKNH(ctx); + return gen_sha512_rv64(ctx, a, EXT_NONE, tcg_gen_rotri_i64, 14, 18, 41); +} + +/* SM3 */ +static bool gen_sm3(DisasContext *ctx, arg_r2 *a, int32_t b, int32_t c) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t0, src1); + tcg_gen_rotli_i32(t1, t0, b); + tcg_gen_xor_i32(t1, t0, t1); + tcg_gen_rotli_i32(t0, t0, c); + tcg_gen_xor_i32(t1, t1, t0); + tcg_gen_ext_i32_tl(dest, t1); + gen_set_gpr(ctx, a->rd, dest); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + return true; +} + +static bool trans_sm3p0(DisasContext *ctx, arg_sm3p0 *a) +{ + REQUIRE_ZKSH(ctx); + return gen_sm3(ctx, a, 9, 17); +} + +static bool trans_sm3p1(DisasContext *ctx, arg_sm3p1 *a) +{ + REQUIRE_ZKSH(ctx); + return gen_sm3(ctx, a, 15, 23); +} + +/* SM4 */ +static bool trans_sm4ed(DisasContext *ctx, arg_sm4ed *a) +{ + REQUIRE_ZKSED(ctx); + return gen_aes32_sm4(ctx, a, gen_helper_sm4ed); +} + +static bool trans_sm4ks(DisasContext *ctx, arg_sm4ks *a) +{ + REQUIRE_ZKSED(ctx); + return gen_aes32_sm4(ctx, a, gen_helper_sm4ks); +} diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc index 16b029edf004..ec7f705aabb3 100644 --- a/target/riscv/insn_trans/trans_rvm.c.inc +++ b/target/riscv/insn_trans/trans_rvm.c.inc @@ -18,6 +18,12 @@ * this program. If not, see . */ +#define REQUIRE_M_OR_ZMMUL(ctx) do { \ + if (!ctx->cfg_ptr->ext_zmmul && !has_ext(ctx, RVM)) { \ + return false; \ + } \ +} while (0) + static void gen_mulhu_i128(TCGv r2, TCGv r3, TCGv al, TCGv ah, TCGv bl, TCGv bh) { TCGv tmpl = tcg_temp_new(); @@ -65,7 +71,7 @@ static void gen_mul_i128(TCGv rl, TCGv rh, static bool trans_mul(DisasContext *ctx, arg_mul *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, gen_mul_i128); } @@ -109,7 +115,7 @@ static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2) static bool trans_mulh(DisasContext *ctx, arg_mulh *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w, gen_mulh_i128); } @@ -161,7 +167,7 @@ static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2) static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w, gen_mulhsu_i128); } @@ -176,7 +182,7 @@ static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2) static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); /* gen_mulh_w works for either sign as input. */ return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w, gen_mulhu_i128); @@ -349,7 +355,7 @@ static bool trans_remu(DisasContext *ctx, arg_remu *a) static bool trans_mulw(DisasContext *ctx, arg_mulw *a) { REQUIRE_64_OR_128BIT(ctx); - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL); } @@ -389,7 +395,7 @@ static bool trans_remuw(DisasContext *ctx, arg_remuw *a) static bool trans_muld(DisasContext *ctx, arg_muld *a) { REQUIRE_128BIT(ctx); - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); ctx->ol = MXL_RV64; return gen_arith(ctx, a, EXT_SIGN, tcg_gen_mul_tl, NULL); } diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 4ea7e41e1a80..d455acedbfe8 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -196,7 +196,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) mark_vs_dirty(s); gen_set_pc_imm(s, s->pc_succ_insn); - tcg_gen_lookup_and_goto_ptr(); + lookup_and_goto_ptr(s); s->base.is_jmp = DISAS_NORETURN; if (rd == 0 && rs1 == 0) { @@ -222,7 +222,7 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) gen_set_gpr(s, rd, dst); mark_vs_dirty(s); gen_set_pc_imm(s, s->pc_succ_insn); - tcg_gen_lookup_and_goto_ptr(); + lookup_and_goto_ptr(s); s->base.is_jmp = DISAS_NORETURN; return true; @@ -652,6 +652,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -710,6 +711,8 @@ static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); 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); } @@ -773,6 +776,9 @@ static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew) /* EMUL = 1, NFIELDS = 1 */ data = FIELD_DP32(data, VDATA, LMUL, 0); 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); } @@ -818,6 +824,7 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -860,6 +867,8 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); 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); } @@ -925,6 +934,7 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -988,6 +998,8 @@ static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); 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); } @@ -1067,6 +1079,7 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1104,6 +1117,8 @@ static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); 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); } @@ -1118,10 +1133,10 @@ GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, - gen_helper_ldst_whole *fn, DisasContext *s, - bool is_store) + uint32_t width, gen_helper_ldst_whole *fn, + DisasContext *s, bool is_store) { - uint32_t evl = (s->cfg_ptr->vlen / 8) * nf / (1 << s->sew); + uint32_t evl = (s->cfg_ptr->vlen / 8) * nf / width; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, evl, over); @@ -1153,38 +1168,42 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, * load and store whole register instructions ignore vtype and vl setting. * Thus, we don't need to check vill bit. (Section 7.9) */ -#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, IS_STORE) \ +#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, WIDTH, IS_STORE) \ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ { \ if (require_rvv(s) && \ QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ - return ldst_whole_trans(a->rd, a->rs1, ARG_NF, gen_helper_##NAME, \ - s, IS_STORE); \ + return ldst_whole_trans(a->rd, a->rs1, ARG_NF, WIDTH, \ + gen_helper_##NAME, s, IS_STORE); \ } \ return false; \ } -GEN_LDST_WHOLE_TRANS(vl1re8_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl2re8_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl4re8_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl8re8_v, 8, false) -GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, false) -GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, false) -GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, false) - -GEN_LDST_WHOLE_TRANS(vs1r_v, 1, true) -GEN_LDST_WHOLE_TRANS(vs2r_v, 2, true) -GEN_LDST_WHOLE_TRANS(vs4r_v, 4, true) -GEN_LDST_WHOLE_TRANS(vs8r_v, 8, true) +GEN_LDST_WHOLE_TRANS(vl1re8_v, 1, 1, false) +GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, 2, false) +GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, 4, false) +GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, 8, false) +GEN_LDST_WHOLE_TRANS(vl2re8_v, 2, 1, false) +GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, 2, false) +GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, 4, false) +GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, 8, false) +GEN_LDST_WHOLE_TRANS(vl4re8_v, 4, 1, false) +GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, 2, false) +GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, 4, false) +GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, 8, false) +GEN_LDST_WHOLE_TRANS(vl8re8_v, 8, 1, false) +GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, 2, false) +GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, 4, false) +GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, 8, false) + +/* + * The vector whole register store instructions are encoded similar to + * unmasked unit-stride store of elements with EEW=8. + */ +GEN_LDST_WHOLE_TRANS(vs1r_v, 1, 1, true) +GEN_LDST_WHOLE_TRANS(vs2r_v, 2, 1, true) +GEN_LDST_WHOLE_TRANS(vs4r_v, 4, 1, true) +GEN_LDST_WHOLE_TRANS(vs8r_v, 8, 1, true) /* *** Vector Integer Arithmetic Instructions @@ -1198,7 +1217,7 @@ GEN_LDST_WHOLE_TRANS(vs8r_v, 8, true) static inline uint32_t MAXSZ(DisasContext *s) { int scale = s->lmul - 3; - return scale < 0 ? s->cfg_ptr->vlen >> -scale : s->cfg_ptr->vlen << scale; + return s->cfg_ptr->vlen >> -scale; } static bool opivv_check(DisasContext *s, arg_rmrr *a) @@ -1221,8 +1240,9 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, } tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), MAXSZ(s), MAXSZ(s)); @@ -1231,6 +1251,8 @@ 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, @@ -1268,6 +1290,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1276,6 +1299,9 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VM, 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)); @@ -1311,7 +1337,7 @@ do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { TCGv_i64 src1 = tcg_temp_new_i64(); tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); @@ -1432,6 +1458,7 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1440,6 +1467,9 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VM, 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)); @@ -1468,7 +1498,7 @@ do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s)); mark_vs_dirty(s); @@ -1518,9 +1548,12 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, uint32_t data = 0; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 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), @@ -1598,9 +1631,12 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, uint32_t data = 0; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 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), @@ -1675,9 +1711,14 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ }; \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, 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, \ @@ -1801,7 +1842,7 @@ do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { TCGv_i32 src1 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); @@ -1856,9 +1897,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ }; \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, \ @@ -2054,18 +2098,20 @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) vext_check_isa_ill(s) && /* vmv.v.v has rs2 = 0 and vm = 1 */ vext_check_sss(s, a->rd, a->rs1, 0, 1)) { - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), MAXSZ(s), MAXSZ(s)); } else { uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_gvec_2_ptr * const fns[4] = { gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, }; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), cpu_env, s->cfg_ptr->vlen / 8, @@ -2089,17 +2135,27 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) TCGv s1; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); s1 = get_gpr(s, a->rs1, EXT_SIGN); - if (s->vl_eq_vlmax) { - tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), - MAXSZ(s), MAXSZ(s), s1); + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { + if (get_xl(s) == MXL_RV32 && s->sew == MO_64) { + TCGv_i64 s1_i64 = tcg_temp_new_i64(); + tcg_gen_ext_tl_i64(s1_i64, s1); + tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), s1_i64); + tcg_temp_free_i64(s1_i64); + } else { + tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), s1); + } } else { TCGv_i32 desc; TCGv_i64 s1_i64 = tcg_temp_new_i64(); TCGv_ptr dest = tcg_temp_new_ptr(); uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_vmv_vx * const fns[4] = { gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, @@ -2129,7 +2185,7 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) /* vmv.v.i has rs2 = 0 and vm = 1 */ vext_check_ss(s, a->rd, 0, 1)) { int64_t simm = sextract64(a->rs1, 0, 5); - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), MAXSZ(s), MAXSZ(s), simm); mark_vs_dirty(s); @@ -2138,12 +2194,14 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) TCGv_i64 s1; TCGv_ptr dest; uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_vmv_vx * const fns[4] = { gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, }; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); s1 = tcg_constant_i64(simm); dest = tcg_temp_new_ptr(); @@ -2296,9 +2354,14 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, 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, \ @@ -2326,6 +2389,7 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -2380,6 +2444,10 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ gen_set_rm(s, RISCV_FRM_DYN); \ 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, 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); \ } \ @@ -2414,9 +2482,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);\ \ 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, \ @@ -2456,6 +2527,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ gen_set_rm(s, RISCV_FRM_DYN); \ 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); \ } \ @@ -2488,9 +2561,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, \ @@ -2530,6 +2606,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ gen_set_rm(s, RISCV_FRM_DYN); \ 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); \ } \ @@ -2609,9 +2687,12 @@ static bool do_opfv(DisasContext *s, arg_rmr *a, TCGLabel *over = gen_new_label(); gen_set_rm(s, rm); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 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, @@ -2703,7 +2784,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) TCGv_i64 t1; - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { t1 = tcg_temp_new_i64(); /* NaN-box f[rs1] */ do_nanbox(s, t1, cpu_fpr[a->rs1]); @@ -2715,6 +2796,8 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) TCGv_ptr dest; 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, @@ -2722,6 +2805,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) }; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); t1 = tcg_temp_new_i64(); /* NaN-box f[rs1] */ @@ -2810,9 +2894,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, \ @@ -2861,8 +2948,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, \ @@ -2926,9 +3017,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, \ @@ -2979,8 +3073,12 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ 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, \ @@ -3038,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) @@ -3050,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 @@ -3066,8 +3166,11 @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \ gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = \ + FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 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, \ @@ -3172,6 +3275,9 @@ 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_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, \ @@ -3209,6 +3315,8 @@ 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, @@ -3234,9 +3342,12 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) uint32_t data = 0; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 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, @@ -3293,7 +3404,7 @@ static void load_element(TCGv_i64 dest, TCGv_ptr base, /* offset of the idx element with base regsiter r */ static uint32_t endian_ofs(DisasContext *s, int r, int idx) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); #else return vreg_ofs(s, r) + (idx << s->sew); @@ -3303,7 +3414,7 @@ static uint32_t endian_ofs(DisasContext *s, int r, int idx) /* adjust the index according to the endian */ static void endian_adjust(TCGv_i32 ofs, int sew) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN tcg_gen_xori_i32(ofs, ofs, 7 >> sew); #endif } @@ -3595,10 +3706,9 @@ static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { int scale = s->lmul - (s->sew + 3); - int vlmax = scale < 0 ? - s->cfg_ptr->vlen >> -scale : s->cfg_ptr->vlen << scale; + int vlmax = s->cfg_ptr->vlen >> -scale; TCGv_i64 dest = tcg_temp_new_i64(); if (a->rs1 == 0) { @@ -3628,10 +3738,9 @@ static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { int scale = s->lmul - (s->sew + 3); - int vlmax = scale < 0 ? - s->cfg_ptr->vlen >> -scale : s->cfg_ptr->vlen << scale; + int vlmax = s->cfg_ptr->vlen >> -scale; if (a->rs1 >= vlmax) { tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), MAXSZ(s), MAXSZ(s), 0); @@ -3681,6 +3790,7 @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a) tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); 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, @@ -3697,7 +3807,7 @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a) * Whole Vector Register Move Instructions ignore vtype and vl setting. * Thus, we don't need to check vill bit. (Section 16.6) */ -#define GEN_VMV_WHOLE_TRANS(NAME, LEN, SEQ) \ +#define GEN_VMV_WHOLE_TRANS(NAME, LEN) \ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ { \ if (require_rvv(s) && \ @@ -3712,13 +3822,8 @@ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ } else { \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \ - \ - static gen_helper_gvec_2_ptr * const fns[4] = { \ - gen_helper_vmv1r_v, gen_helper_vmv2r_v, \ - gen_helper_vmv4r_v, gen_helper_vmv8r_v, \ - }; \ tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ - cpu_env, maxsz, maxsz, 0, fns[SEQ]); \ + cpu_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \ mark_vs_dirty(s); \ gen_set_label(over); \ } \ @@ -3727,10 +3832,10 @@ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ return false; \ } -GEN_VMV_WHOLE_TRANS(vmv1r_v, 1, 0) -GEN_VMV_WHOLE_TRANS(vmv2r_v, 2, 1) -GEN_VMV_WHOLE_TRANS(vmv4r_v, 4, 2) -GEN_VMV_WHOLE_TRANS(vmv8r_v, 8, 3) +GEN_VMV_WHOLE_TRANS(vmv1r_v, 1) +GEN_VMV_WHOLE_TRANS(vmv2r_v, 2) +GEN_VMV_WHOLE_TRANS(vmv4r_v, 4) +GEN_VMV_WHOLE_TRANS(vmv8r_v, 8) static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) { @@ -3751,6 +3856,7 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) gen_helper_gvec_3_ptr *fn; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); static gen_helper_gvec_3_ptr * const fns[6][4] = { { @@ -3785,6 +3891,9 @@ 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/insn_trans/trans_rvzawrs.c.inc b/target/riscv/insn_trans/trans_rvzawrs.c.inc new file mode 100644 index 000000000000..8254e7dfe279 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzawrs.c.inc @@ -0,0 +1,51 @@ +/* + * RISC-V translation routines for the RISC-V Zawrs Extension. + * + * Copyright (c) 2022 Christoph Muellner, christoph.muellner@vrull.io + * + * 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 . + */ + +static bool trans_wrs(DisasContext *ctx) +{ + if (!ctx->cfg_ptr->ext_zawrs) { + return false; + } + + /* + * The specification says: + * While stalled, an implementation is permitted to occasionally + * terminate the stall and complete execution for any reason. + * + * So let's just exit TB and return to the main loop. + */ + + /* Clear the load reservation (if any). */ + tcg_gen_movi_tl(load_res, -1); + + gen_set_pc_imm(ctx, ctx->pc_succ_insn); + tcg_gen_exit_tb(NULL, 0); + ctx->base.is_jmp = DISAS_NORETURN; + + return true; +} + +#define GEN_TRANS_WRS(insn) \ +static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn *a) \ +{ \ + (void)a; \ + return trans_wrs(ctx); \ +} + +GEN_TRANS_WRS(wrs_nto) +GEN_TRANS_WRS(wrs_sto) diff --git a/target/riscv/instmap.h b/target/riscv/instmap.h index 40b6d2b64dee..f87753057680 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 dbb322bfa7e5..5620fbffb6e2 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -24,8 +24,11 @@ /* share data between vector helpers and decode code */ FIELD(VDATA, VM, 0, 1) FIELD(VDATA, LMUL, 1, 3) -FIELD(VDATA, NF, 4, 4) -FIELD(VDATA, WD, 4, 1) +FIELD(VDATA, VTA, 4, 1) +FIELD(VDATA, VTA_ALL_1S, 5, 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/kvm.c b/target/riscv/kvm.c index e6b7cb6d4d5f..30f21453d69c 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -21,7 +21,6 @@ #include -#include "qemu-common.h" #include "qemu/timer.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" @@ -533,3 +532,7 @@ bool kvm_arch_cpu_check_are_resettable(void) { return true; } + +void kvm_arch_accel_class_init(ObjectClass *oc) +{ +} diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 5178b3fec92a..65a8549ec217 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -21,6 +21,8 @@ #include "qemu/error-report.h" #include "sysemu/kvm.h" #include "migration/cpu.h" +#include "sysemu/cpu-timers.h" +#include "debug.h" static bool pmp_needed(void *opaque) { @@ -92,6 +94,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), @@ -216,7 +219,41 @@ static const VMStateDescription vmstate_kvmtimer = { VMSTATE_UINT64(env.kvm_timer_time, RISCVCPU), VMSTATE_UINT64(env.kvm_timer_compare, RISCVCPU), VMSTATE_UINT64(env.kvm_timer_state, RISCVCPU), + VMSTATE_END_OF_LIST() + } +}; + +static bool debug_needed(void *opaque) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + + return riscv_feature(env, RISCV_FEATURE_DEBUG); +} + +static int debug_post_load(void *opaque, int version_id) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + + if (icount_enabled()) { + env->itrigger_enabled = riscv_itrigger_enabled(env); + } + return 0; +} + +static const VMStateDescription vmstate_debug = { + .name = "cpu/debug", + .version_id = 2, + .minimum_version_id = 2, + .needed = debug_needed, + .post_load = debug_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINTTL(env.trigger_cur, RISCVCPU), + 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() } }; @@ -231,10 +268,73 @@ static int riscv_cpu_post_load(void *opaque, int version_id) return 0; } +static bool smstateen_needed(void *opaque) +{ + RISCVCPU *cpu = opaque; + + return cpu->cfg.ext_smstateen; +} + +static const VMStateDescription vmstate_smstateen = { + .name = "cpu/smtateen", + .version_id = 1, + .minimum_version_id = 1, + .needed = smstateen_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64_ARRAY(env.mstateen, RISCVCPU, 4), + VMSTATE_UINT64_ARRAY(env.hstateen, RISCVCPU, 4), + VMSTATE_UINT64_ARRAY(env.sstateen, RISCVCPU, 4), + VMSTATE_END_OF_LIST() + } +}; + +static bool envcfg_needed(void *opaque) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + + return (env->priv_ver >= PRIV_VERSION_1_12_0 ? 1 : 0); +} + +static const VMStateDescription vmstate_envcfg = { + .name = "cpu/envcfg", + .version_id = 1, + .minimum_version_id = 1, + .needed = envcfg_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.menvcfg, RISCVCPU), + VMSTATE_UINTTL(env.senvcfg, RISCVCPU), + VMSTATE_UINT64(env.henvcfg, RISCVCPU), + VMSTATE_END_OF_LIST() + } +}; + +static bool pmu_needed(void *opaque) +{ + RISCVCPU *cpu = opaque; + + return cpu->cfg.pmu_num; +} + +static const VMStateDescription vmstate_pmu_ctr_state = { + .name = "cpu/pmu", + .version_id = 1, + .minimum_version_id = 1, + .needed = pmu_needed, + .fields = (VMStateField[]) { + VMSTATE_UINTTL(mhpmcounter_val, PMUCTRState), + VMSTATE_UINTTL(mhpmcounterh_val, PMUCTRState), + VMSTATE_UINTTL(mhpmcounter_prev, PMUCTRState), + VMSTATE_UINTTL(mhpmcounterh_prev, PMUCTRState), + VMSTATE_BOOL(started, PMUCTRState), + VMSTATE_END_OF_LIST() + } +}; + 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), @@ -256,7 +356,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), @@ -277,11 +377,16 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.siselect, RISCVCPU), VMSTATE_UINTTL(env.scounteren, RISCVCPU), VMSTATE_UINTTL(env.mcounteren, RISCVCPU), + VMSTATE_UINTTL(env.mcountinhibit, RISCVCPU), + 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() }, @@ -292,6 +397,9 @@ const VMStateDescription vmstate_riscv_cpu = { &vmstate_pointermasking, &vmstate_rv128, &vmstate_kvmtimer, + &vmstate_envcfg, + &vmstate_debug, + &vmstate_smstateen, NULL } }; diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 91f0ac32ff3d..ba25164d7417 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'), @@ -19,7 +17,8 @@ riscv_ss.add(files( 'vector_helper.c', 'bitmanip_helper.c', 'translate.c', - 'm128_helper.c' + 'm128_helper.c', + 'crypto_helper.c' )) riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c')) @@ -27,8 +26,11 @@ riscv_softmmu_ss = ss.source_set() riscv_softmmu_ss.add(files( 'arch_dump.c', 'pmp.c', + 'debug.c', 'monitor.c', - 'machine.c' + 'machine.c', + 'pmu.c', + 'time_helper.c' )) target_arch += {'riscv': riscv_ss} diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index 7efb4b62c187..17e63fab005a 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -84,6 +84,7 @@ static void walk_pte(Monitor *mon, hwaddr base, target_ulong start, { hwaddr pte_addr; hwaddr paddr; + target_ulong last_start = -1; target_ulong pgsize; target_ulong pte; int ptshift; @@ -111,12 +112,13 @@ static void walk_pte(Monitor *mon, hwaddr base, target_ulong start, * A leaf PTE has been found * * If current PTE's permission bits differ from the last one, - * or current PTE's ppn does not make a contiguous physical - * address block together with the last one, print out the last - * contiguous mapped block details. + * or the current PTE breaks up a contiguous virtual or + * physical mapping, address block together with the last one, + * print out the last contiguous mapped block details. */ if ((*last_attr != attr) || - (*last_paddr + *last_size != paddr)) { + (*last_paddr + *last_size != paddr) || + (last_start + *last_size != start)) { print_pte(mon, va_bits, *vbase, *pbase, *last_paddr + *last_size - *pbase, *last_attr); @@ -125,6 +127,7 @@ static void walk_pte(Monitor *mon, hwaddr base, target_ulong start, *last_attr = attr; } + last_start = start; *last_paddr = paddr; *last_size = pgsize; } else { diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 1a75ba11e68f..878bcb03b8b2 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -24,8 +24,8 @@ #include "exec/helper-proto.h" /* Exceptions processing helpers */ -void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env, - uint32_t exception, uintptr_t pc) +G_NORETURN void riscv_raise_exception(CPURISCVState *env, + uint32_t exception, uintptr_t pc) { CPUState *cs = env_cpu(env); cs->exception_index = exception; @@ -39,6 +39,15 @@ void helper_raise_exception(CPURISCVState *env, uint32_t exception) target_ulong helper_csrr(CPURISCVState *env, int csr) { + /* + * The seed CSR must be accessed with a read-write instruction. A + * read-only instruction such as CSRRS/CSRRC with rs1=x0 or CSRRSI/ + * CSRRCI with uimm=0 will raise an illegal instruction exception. + */ + if (csr == CSR_SEED) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } + target_ulong val = 0; RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0); @@ -140,21 +149,24 @@ target_ulong helper_sret(CPURISCVState *env) } mstatus = env->mstatus; + prev_priv = get_field(mstatus, MSTATUS_SPP); + mstatus = set_field(mstatus, MSTATUS_SIE, + get_field(mstatus, MSTATUS_SPIE)); + mstatus = set_field(mstatus, MSTATUS_SPIE, 1); + mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U); + if (env->priv_ver >= PRIV_VERSION_1_12_0) { + mstatus = set_field(mstatus, MSTATUS_MPRV, 0); + } + env->mstatus = mstatus; if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) { /* We support Hypervisor extensions and virtulisation is disabled */ target_ulong hstatus = env->hstatus; - prev_priv = get_field(mstatus, MSTATUS_SPP); prev_virt = get_field(hstatus, HSTATUS_SPV); hstatus = set_field(hstatus, HSTATUS_SPV, 0); - mstatus = set_field(mstatus, MSTATUS_SPP, 0); - mstatus = set_field(mstatus, SSTATUS_SIE, - get_field(mstatus, SSTATUS_SPIE)); - mstatus = set_field(mstatus, SSTATUS_SPIE, 1); - env->mstatus = mstatus; env->hstatus = hstatus; if (prev_virt) { @@ -162,14 +174,6 @@ target_ulong helper_sret(CPURISCVState *env) } riscv_cpu_set_virt_enabled(env, prev_virt); - } else { - prev_priv = get_field(mstatus, MSTATUS_SPP); - - mstatus = set_field(mstatus, MSTATUS_SIE, - get_field(mstatus, MSTATUS_SPIE)); - mstatus = set_field(mstatus, MSTATUS_SPIE, 1); - mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U); - env->mstatus = mstatus; } riscv_cpu_set_mode(env, prev_priv); @@ -193,7 +197,7 @@ target_ulong helper_mret(CPURISCVState *env) if (riscv_feature(env, RISCV_FEATURE_PMP) && !pmp_get_num_rules(env) && (prev_priv != PRV_M)) { - riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC()); } target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV); @@ -202,6 +206,9 @@ target_ulong helper_mret(CPURISCVState *env) mstatus = set_field(mstatus, MSTATUS_MPIE, 1); mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U); mstatus = set_field(mstatus, MSTATUS_MPV, 0); + if ((env->priv_ver >= PRIV_VERSION_1_12_0) && (prev_priv != PRV_M)) { + mstatus = set_field(mstatus, MSTATUS_MPRV, 0); + } env->mstatus = mstatus; riscv_cpu_set_mode(env, prev_priv); diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 81b61bb65c3a..d1126a606633 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -141,17 +141,9 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea) 0111...1111 2^(XLEN+2)-byte NAPOT range 1111...1111 Reserved */ - if (a == -1) { - *sa = 0u; - *ea = -1; - return; - } else { - target_ulong t1 = ctz64(~a); - target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 2; - target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1; - *sa = base; - *ea = base + range; - } + a = (a << 2) | 0x3; + *sa = a & (a + 1); + *ea = a | (a + 1); } void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index) @@ -175,6 +167,9 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index) case PMP_AMATCH_TOR: sa = prev_addr << 2; /* shift up from [xx:0] to [xx+2:2] */ ea = (this_addr << 2) - 1u; + if (sa > ea) { + sa = ea = 0u; + } break; case PMP_AMATCH_NA4: @@ -297,8 +292,11 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr, /* * Check if the address has required RWX privs to complete desired operation + * Return PMP rule index if a pmp rule match + * Return MAX_RISCV_PMPS if default match + * Return negtive value if no match */ -bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, +int pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs, target_ulong mode) { @@ -310,8 +308,10 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, /* Short cut if no rules */ if (0 == pmp_get_num_rules(env)) { - return pmp_hart_has_privs_default(env, addr, size, privs, - allowed_privs, mode); + if (pmp_hart_has_privs_default(env, addr, size, privs, + allowed_privs, mode)) { + ret = MAX_RISCV_PMPS; + } } if (size == 0) { @@ -338,7 +338,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, if ((s + e) == 1) { qemu_log_mask(LOG_GUEST_ERROR, "pmp violation - access is partially inside\n"); - ret = 0; + ret = -1; break; } @@ -441,18 +441,22 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, } } - ret = ((privs & *allowed_privs) == privs); + if ((privs & *allowed_privs) == privs) { + ret = i; + } break; } } /* No rule matched */ if (ret == -1) { - return pmp_hart_has_privs_default(env, addr, size, privs, - allowed_privs, mode); + if (pmp_hart_has_privs_default(env, addr, size, privs, + allowed_privs, mode)) { + ret = MAX_RISCV_PMPS; + } } - return ret == 1 ? true : false; + return ret; } /* @@ -591,52 +595,25 @@ target_ulong mseccfg_csr_read(CPURISCVState *env) * Calculate the TLB size if the start address or the end address of * PMP entry is presented in the TLB page. */ -static target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index, - target_ulong tlb_sa, target_ulong tlb_ea) +target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index, + target_ulong tlb_sa, target_ulong tlb_ea) { target_ulong pmp_sa = env->pmp_state.addr[pmp_index].sa; target_ulong pmp_ea = env->pmp_state.addr[pmp_index].ea; - if (pmp_sa >= tlb_sa && pmp_ea <= tlb_ea) { - return pmp_ea - pmp_sa + 1; - } - - if (pmp_sa >= tlb_sa && pmp_sa <= tlb_ea && pmp_ea >= tlb_ea) { - return tlb_ea - pmp_sa + 1; - } - - if (pmp_ea <= tlb_ea && pmp_ea >= tlb_sa && pmp_sa <= tlb_sa) { - return pmp_ea - tlb_sa + 1; - } - - return 0; -} - -/* - * Check is there a PMP entry which range covers this page. If so, - * try to find the minimum granularity for the TLB size. - */ -bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa, - target_ulong *tlb_size) -{ - int i; - target_ulong val; - target_ulong tlb_ea = (tlb_sa + TARGET_PAGE_SIZE - 1); - - for (i = 0; i < MAX_RISCV_PMPS; i++) { - val = pmp_get_tlb_size(env, i, tlb_sa, tlb_ea); - if (val) { - if (*tlb_size == 0 || *tlb_size > val) { - *tlb_size = val; - } - } - } - - if (*tlb_size != 0) { - return true; + if (pmp_sa <= tlb_sa && pmp_ea >= tlb_ea) { + return TARGET_PAGE_SIZE; + } else { + /* + * At this point we have a tlb_size that is the smallest possible size + * That fits within a TARGET_PAGE_SIZE and the PMP region. + * + * If the size is less then TARGET_PAGE_SIZE we drop the size to 1. + * This means the result isn't cached in the TLB and is only used for + * a single translation. + */ + return 1; } - - return false; } /* diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index fcb6b7c46772..da32c61c85b1 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -39,9 +39,11 @@ typedef enum { } pmp_am_t; typedef enum { - MSECCFG_MML = 1 << 0, - MSECCFG_MMWP = 1 << 1, - MSECCFG_RLB = 1 << 2 + MSECCFG_MML = 1 << 0, + MSECCFG_MMWP = 1 << 1, + MSECCFG_RLB = 1 << 2, + MSECCFG_USEED = 1 << 8, + MSECCFG_SSEED = 1 << 9 } mseccfg_field_t; typedef struct { @@ -70,11 +72,11 @@ target_ulong mseccfg_csr_read(CPURISCVState *env); void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val); target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index); -bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, +int pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs, target_ulong mode); -bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa, - target_ulong *tlb_size); +target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index, + target_ulong tlb_sa, target_ulong tlb_ea); void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index); void pmp_update_rule_nums(CPURISCVState *env); uint32_t pmp_get_num_rules(CPURISCVState *env); diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c new file mode 100644 index 000000000000..b8e56d2b7b8e --- /dev/null +++ b/target/riscv/pmu.c @@ -0,0 +1,453 @@ +/* + * RISC-V PMU file. + * + * Copyright (c) 2021 Western Digital Corporation or its affiliates. + * + * 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 "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) +{ + 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) +{ + 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 new file mode 100644 index 000000000000..3004ce37b636 --- /dev/null +++ b/target/riscv/pmu.h @@ -0,0 +1,36 @@ +/* + * RISC-V PMU header file. + * + * Copyright (c) 2021 Western Digital Corporation or its affiliates. + * + * 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.h" +#include "qemu/main-loop.h" +#include "exec/exec-all.h" + +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/sbi_ecall_interface.h b/target/riscv/sbi_ecall_interface.h index fb1a3fa8f23f..77574ed4cb6d 100644 --- a/target/riscv/sbi_ecall_interface.h +++ b/target/riscv/sbi_ecall_interface.h @@ -7,8 +7,8 @@ * Anup Patel */ -#ifndef __SBI_ECALL_INTERFACE_H__ -#define __SBI_ECALL_INTERFACE_H__ +#ifndef SBI_ECALL_INTERFACE_H +#define SBI_ECALL_INTERFACE_H /* clang-format off */ diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c new file mode 100644 index 000000000000..8cce667dfd47 --- /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 000000000000..7b3cdcc35020 --- /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 fac998a6b547..df38db7553b8 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" @@ -75,6 +76,7 @@ typedef struct DisasContext { to reset this known value. */ int frm; RISCVMXL ol; + bool virt_inst_excp; bool virt_enabled; const RISCVCPUConfig *cfg_ptr; bool hlsx; @@ -94,6 +96,9 @@ 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; uint8_t ntemp; @@ -107,6 +112,10 @@ typedef struct DisasContext { /* PointerMasking extension */ bool pm_mask_enabled; bool pm_base_enabled; + /* Use icount trigger for native debug */ + bool itrigger; + /* TCG of the current insn_start */ + TCGOp *insn_start; } DisasContext; static inline bool has_ext(DisasContext *ctx, uint32_t ext) @@ -202,6 +211,13 @@ static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in) tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan); } +static void decode_save_opc(DisasContext *ctx) +{ + assert(ctx->insn_start != NULL); + tcg_set_insn_start_param(ctx->insn_start, 1, ctx->opcode); + ctx->insn_start = NULL; +} + static void gen_set_pc_imm(DisasContext *ctx, target_ulong dest) { if (get_xl(ctx) == MXL_RV32) { @@ -226,36 +242,56 @@ static void generate_exception(DisasContext *ctx, int excp) ctx->base.is_jmp = DISAS_NORETURN; } -static void generate_exception_mtval(DisasContext *ctx, int excp) -{ - gen_set_pc_imm(ctx, ctx->base.pc_next); - tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr)); - gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); - ctx->base.is_jmp = DISAS_NORETURN; -} - static void gen_exception_illegal(DisasContext *ctx) { tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env, offsetof(CPURISCVState, bins)); - - generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); + if (ctx->virt_inst_excp) { + generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT); + } else { + generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); + } } static void gen_exception_inst_addr_mis(DisasContext *ctx) { - generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS); + tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr)); + generate_exception(ctx, RISCV_EXCP_INST_ADDR_MIS); +} + +static void lookup_and_goto_ptr(DisasContext *ctx) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->itrigger) { + gen_helper_itrigger_match(cpu_env); + } +#endif + tcg_gen_lookup_and_goto_ptr(); +} + +static void exit_tb(DisasContext *ctx) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->itrigger) { + gen_helper_itrigger_match(cpu_env); + } +#endif + tcg_gen_exit_tb(NULL, 0); } static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { - if (translator_use_goto_tb(&ctx->base, dest)) { + /* + * Under itrigger, instruction executes one by one like singlestep, + * direct block chain benefits will be small. + */ + if (translator_use_goto_tb(&ctx->base, dest) && !ctx->itrigger) { tcg_gen_goto_tb(n); gen_set_pc_imm(ctx, dest); tcg_gen_exit_tb(ctx->base.tb, n); } else { gen_set_pc_imm(ctx, dest); - tcg_gen_lookup_and_goto_ptr(); + lookup_and_goto_ptr(ctx); } } @@ -541,7 +577,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); } @@ -639,6 +675,8 @@ static void gen_set_rm(DisasContext *ctx, int rm) return; } + /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ + decode_save_opc(ctx); gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm)); } @@ -688,15 +726,38 @@ EX_SH(12) } \ } while (0) +#define REQUIRE_EITHER_EXT(ctx, A, B) do { \ + if (!ctx->cfg_ptr->ext_##A && \ + !ctx->cfg_ptr->ext_##B) { \ + return false; \ + } \ +} while (0) + 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 */ @@ -999,7 +1060,9 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvh.c.inc" #include "insn_trans/trans_rvv.c.inc" #include "insn_trans/trans_rvb.c.inc" +#include "insn_trans/trans_rvzawrs.c.inc" #include "insn_trans/trans_rvzfh.c.inc" +#include "insn_trans/trans_rvk.c.inc" #include "insn_trans/trans_privileged.c.inc" #include "insn_trans/trans_svinval.c.inc" #include "insn_trans/trans_xventanacondops.c.inc" @@ -1009,6 +1072,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) { /* @@ -1023,16 +1094,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) { has_XVentanaCondOps_p, decode_XVentanaCodeOps }, }; + ctx->virt_inst_excp = false; /* Check for compressed insn */ - if (extract16(opcode, 0, 2) != 3) { - if (!has_ext(ctx, RVC)) { - gen_exception_illegal(ctx); - } else { - ctx->opcode = opcode; - ctx->pc_succ_insn = ctx->base.pc_next + 2; - if (decode_insn16(ctx, opcode)) { - return; - } + if (insn_len(opcode) == 2) { + ctx->opcode = opcode; + ctx->pc_succ_insn = ctx->base.pc_next + 2; + if (has_ext(ctx, RVC) && decode_insn16(ctx, opcode)) { + return; } } else { uint32_t opcode32 = opcode; @@ -1083,6 +1151,9 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL); 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); ctx->misa_mxl_max = env->misa_mxl_max; @@ -1094,6 +1165,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) memset(ctx->ftemp, 0, sizeof(ctx->ftemp)); ctx->pm_mask_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_MASK_ENABLED); ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED); + ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER); ctx->zero = tcg_constant_tl(0); } @@ -1105,7 +1177,8 @@ static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - tcg_gen_insn_start(ctx->base.pc_next); + tcg_gen_insn_start(ctx->base.pc_next, 0); + ctx->insn_start = tcg_last_op(); } static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) @@ -1130,12 +1203,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 (ctx->itrigger || !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; + } + } } } } @@ -1155,18 +1237,20 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void riscv_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { #ifndef CONFIG_USER_ONLY RISCVCPU *rvcpu = RISCV_CPU(cpu); CPURISCVState *env = &rvcpu->env; #endif - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); #ifndef CONFIG_USER_ONLY - qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt); + fprintf(logfile, "Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", + env->priv, env->virt); #endif - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps riscv_tr_ops = { @@ -1178,11 +1262,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 3bd4aac9c970..00de8797878b 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -79,7 +79,7 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, * Note that vector data is stored in host-endian 64-bit chunks, * so addressing units smaller than that needs a host-endian fixup. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define H1(x) ((x) ^ 7) #define H1_2(x) ((x) ^ 6) #define H1_4(x) ((x) ^ 4) @@ -122,12 +122,27 @@ static inline int32_t vext_lmul(uint32_t desc) return sextract32(FIELD_EX32(simd_data(desc), VDATA, LMUL), 0, 3); } +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); +} + /* * Get the maximum number of elements can be operated. * - * esz: log2 of element size in bytes. + * log2_esz: log2 of element size in bytes. */ -static inline uint32_t vext_max_elems(uint32_t desc, uint32_t esz) +static inline uint32_t vext_max_elems(uint32_t desc, uint32_t log2_esz) { /* * As simd_desc support at most 2048 bytes, the max vlen is 1024 bits. @@ -136,10 +151,25 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t esz) uint32_t vlenb = simd_maxsz(desc); /* Return VLMAX */ - int scale = vext_lmul(desc) - esz; + int scale = vext_lmul(desc) - log2_esz; return scale < 0 ? vlenb >> -scale : vlenb << scale; } +/* + * Get number of total elements, including prestart, body and tail elements. + * Note that when LMUL < 1, the tail includes the elements past VLMAX that + * are held in the same vector register. + */ +static inline uint32_t vext_get_total_elems(CPURISCVState *env, uint32_t desc, + uint32_t esz) +{ + uint32_t vlenb = simd_maxsz(desc); + uint32_t sew = 1 << FIELD_EX64(env->vtype, VTYPE, VSEW); + int8_t emul = ctzl(esz) - ctzl(sew) + vext_lmul(desc) < 0 ? 0 : + ctzl(esz) - ctzl(sew) + vext_lmul(desc); + return (vlenb << emul) / esz; +} + static inline target_ulong adjust_addr(CPURISCVState *env, target_ulong addr) { return (addr & env->cur_pmmask) | env->cur_pmbase; @@ -172,6 +202,20 @@ static void probe_pages(CPURISCVState *env, target_ulong addr, } } +/* set agnostic elements to 1s */ +static void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt, + uint32_t tot) +{ + if (is_agnostic == 0) { + /* policy undisturbed */ + return; + } + if (tot - cnt == 0) { + return; + } + memset(base + cnt, -1, tot - cnt); +} + static inline void vext_set_elem_mask(void *v0, int index, uint8_t value) { @@ -231,25 +275,44 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, target_ulong stride, CPURISCVState *env, uint32_t desc, uint32_t vm, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra, MMUAccessType access_type) + uint32_t log2_esz, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); + 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) { - target_ulong addr = base + stride * i + (k << esz); + 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++; } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + env->vl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } #define GEN_VEXT_LD_STRIDE(NAME, ETYPE, LOAD_FN) \ @@ -259,7 +322,7 @@ void HELPER(NAME)(void *vd, void * v0, target_ulong base, \ { \ uint32_t vm = vext_vm(desc); \ vext_ldst_stride(vd, v0, base, stride, env, desc, vm, LOAD_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_LD_STRIDE(vlse8_v, int8_t, lde_b) @@ -274,7 +337,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ { \ uint32_t vm = vext_vm(desc); \ vext_ldst_stride(vd, v0, base, stride, env, desc, vm, STORE_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_ST_STRIDE(vsse8_v, int8_t, ste_b) @@ -289,23 +352,38 @@ GEN_VEXT_ST_STRIDE(vsse64_v, int64_t, ste_d) /* unmasked unit-stride load and store operation*/ static void vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, - vext_ldst_elem_fn *ldst_elem, uint32_t esz, uint32_t evl, - uintptr_t ra, MMUAccessType access_type) + vext_ldst_elem_fn *ldst_elem, uint32_t log2_esz, uint32_t evl, + uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); + uint32_t esz = 1 << log2_esz; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); /* load bytes from guest memory */ for (i = env->vstart; i < evl; i++, env->vstart++) { k = 0; while (k < nf) { - target_ulong addr = base + ((i * nf + k) << esz); + target_ulong addr = base + ((i * nf + k) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + evl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } /* @@ -319,14 +397,14 @@ void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \ { \ uint32_t stride = vext_nf(desc) << ctzl(sizeof(ETYPE)); \ vext_ldst_stride(vd, v0, base, stride, env, desc, false, LOAD_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } \ \ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_us(vd, base, env, desc, LOAD_FN, \ - ctzl(sizeof(ETYPE)), env->vl, GETPC(), MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), env->vl, GETPC()); \ } GEN_VEXT_LD_US(vle8_v, int8_t, lde_b) @@ -340,14 +418,14 @@ void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \ { \ uint32_t stride = vext_nf(desc) << ctzl(sizeof(ETYPE)); \ vext_ldst_stride(vd, v0, base, stride, env, desc, false, STORE_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } \ \ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_us(vd, base, env, desc, STORE_FN, \ - ctzl(sizeof(ETYPE)), env->vl, GETPC(), MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), env->vl, GETPC()); \ } GEN_VEXT_ST_US(vse8_v, int8_t, ste_b) @@ -364,7 +442,7 @@ void HELPER(vlm_v)(void *vd, void *v0, target_ulong base, /* evl = ceil(vl/8) */ uint8_t evl = (env->vl + 7) >> 3; vext_ldst_us(vd, base, env, desc, lde_b, - 0, evl, GETPC(), MMU_DATA_LOAD); + 0, evl, GETPC()); } void HELPER(vsm_v)(void *vd, void *v0, target_ulong base, @@ -373,7 +451,7 @@ void HELPER(vsm_v)(void *vd, void *v0, target_ulong base, /* evl = ceil(vl/8) */ uint8_t evl = (env->vl + 7) >> 3; vext_ldst_us(vd, base, env, desc, ste_b, - 0, evl, GETPC(), MMU_DATA_STORE); + 0, evl, GETPC()); } /* @@ -399,27 +477,46 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, void *vs2, CPURISCVState *env, uint32_t desc, vext_get_index_addr get_index_addr, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra, MMUAccessType access_type) + uint32_t log2_esz, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); uint32_t vm = vext_vm(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); + 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) { - abi_ptr addr = get_index_addr(base, i, vs2) + (k << esz); + 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++; } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + env->vl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } #define GEN_VEXT_LD_INDEX(NAME, ETYPE, INDEX_FN, LOAD_FN) \ @@ -427,7 +524,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \ - LOAD_FN, ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_LOAD); \ + LOAD_FN, ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_LD_INDEX(vlxei8_8_v, int8_t, idx_b, lde_b) @@ -453,7 +550,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ { \ vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \ STORE_FN, ctzl(sizeof(ETYPE)), \ - GETPC(), MMU_DATA_STORE); \ + GETPC()); \ } GEN_VEXT_ST_INDEX(vsxei8_8_v, int8_t, idx_b, ste_b) @@ -480,13 +577,17 @@ static inline void vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, uint32_t desc, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra) + uint32_t log2_esz, uintptr_t ra) { void *host; uint32_t i, k, vl = 0; uint32_t nf = vext_nf(desc); uint32_t vm = vext_vm(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); + 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*/ @@ -494,12 +595,12 @@ vext_ldff(void *vd, void *v0, target_ulong base, if (!vm && !vext_elem_mask(v0, i)) { continue; } - addr = adjust_addr(env, base + i * (nf << esz)); + addr = adjust_addr(env, base + i * (nf << log2_esz)); if (i == 0) { - probe_pages(env, addr, nf << esz, ra, MMU_DATA_LOAD); + probe_pages(env, addr, nf << log2_esz, ra, MMU_DATA_LOAD); } else { /* if it triggers an exception, no need to check watchpoint */ - remain = nf << esz; + remain = nf << log2_esz; while (remain > 0) { offset = -(addr | TARGET_PAGE_MASK); host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, @@ -532,16 +633,32 @@ vext_ldff(void *vd, void *v0, target_ulong base, } for (i = env->vstart; i < env->vl; i++) { k = 0; - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } while (k < nf) { - target_ulong addr = base + ((i * nf + k) << esz); + 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++; } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + env->vl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } #define GEN_VEXT_LDFF(NAME, ETYPE, LOAD_FN) \ @@ -576,13 +693,12 @@ GEN_VEXT_LDFF(vle64ff_v, int64_t, lde_d) */ static void vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, - vext_ldst_elem_fn *ldst_elem, uint32_t esz, uintptr_t ra, - MMUAccessType access_type) + vext_ldst_elem_fn *ldst_elem, uint32_t log2_esz, uintptr_t ra) { uint32_t i, k, off, pos; uint32_t nf = vext_nf(desc); uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; - uint32_t max_elems = vlenb >> esz; + uint32_t max_elems = vlenb >> log2_esz; k = env->vstart / max_elems; off = env->vstart % max_elems; @@ -590,7 +706,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, if (off) { /* load/store rest of elements of current segment pointed by vstart */ for (pos = off; pos < max_elems; pos++, env->vstart++) { - target_ulong addr = base + ((pos + k * max_elems) << esz); + target_ulong addr = base + ((pos + k * max_elems) << log2_esz); ldst_elem(env, adjust_addr(env, addr), pos + k * max_elems, vd, ra); } k++; @@ -599,7 +715,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, /* load/store elements for rest of segments */ for (; k < nf; k++) { for (i = 0; i < max_elems; i++, env->vstart++) { - target_ulong addr = base + ((i + k * max_elems) << esz); + target_ulong addr = base + ((i + k * max_elems) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); } } @@ -612,8 +728,7 @@ void HELPER(NAME)(void *vd, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_whole(vd, base, env, desc, LOAD_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), \ - MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_LD_WHOLE(vl1re8_v, int8_t, lde_b) @@ -638,8 +753,7 @@ void HELPER(NAME)(void *vd, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_whole(vd, base, env, desc, STORE_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), \ - MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_ST_WHOLE(vs1r_v, int8_t, ste_b) @@ -710,40 +824,46 @@ RVVCALL(OPIVV2, vsub_vv_d, OP_SSS_D, H8, H8, H8, DO_SUB) static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, uint32_t desc, - uint32_t esz, uint32_t dsz, - opivv2_fn *fn) + opivv2_fn *fn, uint32_t esz) { uint32_t vm = vext_vm(desc); 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); } env->vstart = 0; + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate the helpers for OPIVV */ -#define GEN_VEXT_VV(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VV(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ - do_vext_vv(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \ - do_##NAME); \ + do_vext_vv(vd, v0, vs1, vs2, env, desc, \ + do_##NAME, ESZ); \ } -GEN_VEXT_VV(vadd_vv_b, 1, 1) -GEN_VEXT_VV(vadd_vv_h, 2, 2) -GEN_VEXT_VV(vadd_vv_w, 4, 4) -GEN_VEXT_VV(vadd_vv_d, 8, 8) -GEN_VEXT_VV(vsub_vv_b, 1, 1) -GEN_VEXT_VV(vsub_vv_h, 2, 2) -GEN_VEXT_VV(vsub_vv_w, 4, 4) -GEN_VEXT_VV(vsub_vv_d, 8, 8) +GEN_VEXT_VV(vadd_vv_b, 1) +GEN_VEXT_VV(vadd_vv_h, 2) +GEN_VEXT_VV(vadd_vv_w, 4) +GEN_VEXT_VV(vadd_vv_d, 8) +GEN_VEXT_VV(vsub_vv_b, 1) +GEN_VEXT_VV(vsub_vv_h, 2) +GEN_VEXT_VV(vsub_vv_w, 4) +GEN_VEXT_VV(vsub_vv_d, 8) typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i); @@ -773,44 +893,50 @@ RVVCALL(OPIVX2, vrsub_vx_d, OP_SSS_D, H8, H8, DO_RSUB) static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, uint32_t desc, - uint32_t esz, uint32_t dsz, - opivx2_fn fn) + opivx2_fn fn, uint32_t esz) { uint32_t vm = vext_vm(desc); 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); } env->vstart = 0; + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate the helpers for OPIVX */ -#define GEN_VEXT_VX(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VX(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ - do_vext_vx(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \ - do_##NAME); \ -} - -GEN_VEXT_VX(vadd_vx_b, 1, 1) -GEN_VEXT_VX(vadd_vx_h, 2, 2) -GEN_VEXT_VX(vadd_vx_w, 4, 4) -GEN_VEXT_VX(vadd_vx_d, 8, 8) -GEN_VEXT_VX(vsub_vx_b, 1, 1) -GEN_VEXT_VX(vsub_vx_h, 2, 2) -GEN_VEXT_VX(vsub_vx_w, 4, 4) -GEN_VEXT_VX(vsub_vx_d, 8, 8) -GEN_VEXT_VX(vrsub_vx_b, 1, 1) -GEN_VEXT_VX(vrsub_vx_h, 2, 2) -GEN_VEXT_VX(vrsub_vx_w, 4, 4) -GEN_VEXT_VX(vrsub_vx_d, 8, 8) + do_vext_vx(vd, v0, s1, vs2, env, desc, \ + do_##NAME, ESZ); \ +} + +GEN_VEXT_VX(vadd_vx_b, 1) +GEN_VEXT_VX(vadd_vx_h, 2) +GEN_VEXT_VX(vadd_vx_w, 4) +GEN_VEXT_VX(vadd_vx_d, 8) +GEN_VEXT_VX(vsub_vx_b, 1) +GEN_VEXT_VX(vsub_vx_h, 2) +GEN_VEXT_VX(vsub_vx_w, 4) +GEN_VEXT_VX(vsub_vx_d, 8) +GEN_VEXT_VX(vrsub_vx_b, 1) +GEN_VEXT_VX(vrsub_vx_h, 2) +GEN_VEXT_VX(vrsub_vx_w, 4) +GEN_VEXT_VX(vrsub_vx_d, 8) void HELPER(vec_rsubs8)(void *d, void *a, uint64_t b, uint32_t desc) { @@ -889,30 +1015,30 @@ RVVCALL(OPIVV2, vwadd_wv_w, WOP_WSSS_W, H8, H4, H4, DO_ADD) RVVCALL(OPIVV2, vwsub_wv_b, WOP_WSSS_B, H2, H1, H1, DO_SUB) RVVCALL(OPIVV2, vwsub_wv_h, WOP_WSSS_H, H4, H2, H2, DO_SUB) RVVCALL(OPIVV2, vwsub_wv_w, WOP_WSSS_W, H8, H4, H4, DO_SUB) -GEN_VEXT_VV(vwaddu_vv_b, 1, 2) -GEN_VEXT_VV(vwaddu_vv_h, 2, 4) -GEN_VEXT_VV(vwaddu_vv_w, 4, 8) -GEN_VEXT_VV(vwsubu_vv_b, 1, 2) -GEN_VEXT_VV(vwsubu_vv_h, 2, 4) -GEN_VEXT_VV(vwsubu_vv_w, 4, 8) -GEN_VEXT_VV(vwadd_vv_b, 1, 2) -GEN_VEXT_VV(vwadd_vv_h, 2, 4) -GEN_VEXT_VV(vwadd_vv_w, 4, 8) -GEN_VEXT_VV(vwsub_vv_b, 1, 2) -GEN_VEXT_VV(vwsub_vv_h, 2, 4) -GEN_VEXT_VV(vwsub_vv_w, 4, 8) -GEN_VEXT_VV(vwaddu_wv_b, 1, 2) -GEN_VEXT_VV(vwaddu_wv_h, 2, 4) -GEN_VEXT_VV(vwaddu_wv_w, 4, 8) -GEN_VEXT_VV(vwsubu_wv_b, 1, 2) -GEN_VEXT_VV(vwsubu_wv_h, 2, 4) -GEN_VEXT_VV(vwsubu_wv_w, 4, 8) -GEN_VEXT_VV(vwadd_wv_b, 1, 2) -GEN_VEXT_VV(vwadd_wv_h, 2, 4) -GEN_VEXT_VV(vwadd_wv_w, 4, 8) -GEN_VEXT_VV(vwsub_wv_b, 1, 2) -GEN_VEXT_VV(vwsub_wv_h, 2, 4) -GEN_VEXT_VV(vwsub_wv_w, 4, 8) +GEN_VEXT_VV(vwaddu_vv_b, 2) +GEN_VEXT_VV(vwaddu_vv_h, 4) +GEN_VEXT_VV(vwaddu_vv_w, 8) +GEN_VEXT_VV(vwsubu_vv_b, 2) +GEN_VEXT_VV(vwsubu_vv_h, 4) +GEN_VEXT_VV(vwsubu_vv_w, 8) +GEN_VEXT_VV(vwadd_vv_b, 2) +GEN_VEXT_VV(vwadd_vv_h, 4) +GEN_VEXT_VV(vwadd_vv_w, 8) +GEN_VEXT_VV(vwsub_vv_b, 2) +GEN_VEXT_VV(vwsub_vv_h, 4) +GEN_VEXT_VV(vwsub_vv_w, 8) +GEN_VEXT_VV(vwaddu_wv_b, 2) +GEN_VEXT_VV(vwaddu_wv_h, 4) +GEN_VEXT_VV(vwaddu_wv_w, 8) +GEN_VEXT_VV(vwsubu_wv_b, 2) +GEN_VEXT_VV(vwsubu_wv_h, 4) +GEN_VEXT_VV(vwsubu_wv_w, 8) +GEN_VEXT_VV(vwadd_wv_b, 2) +GEN_VEXT_VV(vwadd_wv_h, 4) +GEN_VEXT_VV(vwadd_wv_w, 8) +GEN_VEXT_VV(vwsub_wv_b, 2) +GEN_VEXT_VV(vwsub_wv_h, 4) +GEN_VEXT_VV(vwsub_wv_w, 8) RVVCALL(OPIVX2, vwaddu_vx_b, WOP_UUU_B, H2, H1, DO_ADD) RVVCALL(OPIVX2, vwaddu_vx_h, WOP_UUU_H, H4, H2, DO_ADD) @@ -938,30 +1064,30 @@ RVVCALL(OPIVX2, vwadd_wx_w, WOP_WSSS_W, H8, H4, DO_ADD) RVVCALL(OPIVX2, vwsub_wx_b, WOP_WSSS_B, H2, H1, DO_SUB) RVVCALL(OPIVX2, vwsub_wx_h, WOP_WSSS_H, H4, H2, DO_SUB) RVVCALL(OPIVX2, vwsub_wx_w, WOP_WSSS_W, H8, H4, DO_SUB) -GEN_VEXT_VX(vwaddu_vx_b, 1, 2) -GEN_VEXT_VX(vwaddu_vx_h, 2, 4) -GEN_VEXT_VX(vwaddu_vx_w, 4, 8) -GEN_VEXT_VX(vwsubu_vx_b, 1, 2) -GEN_VEXT_VX(vwsubu_vx_h, 2, 4) -GEN_VEXT_VX(vwsubu_vx_w, 4, 8) -GEN_VEXT_VX(vwadd_vx_b, 1, 2) -GEN_VEXT_VX(vwadd_vx_h, 2, 4) -GEN_VEXT_VX(vwadd_vx_w, 4, 8) -GEN_VEXT_VX(vwsub_vx_b, 1, 2) -GEN_VEXT_VX(vwsub_vx_h, 2, 4) -GEN_VEXT_VX(vwsub_vx_w, 4, 8) -GEN_VEXT_VX(vwaddu_wx_b, 1, 2) -GEN_VEXT_VX(vwaddu_wx_h, 2, 4) -GEN_VEXT_VX(vwaddu_wx_w, 4, 8) -GEN_VEXT_VX(vwsubu_wx_b, 1, 2) -GEN_VEXT_VX(vwsubu_wx_h, 2, 4) -GEN_VEXT_VX(vwsubu_wx_w, 4, 8) -GEN_VEXT_VX(vwadd_wx_b, 1, 2) -GEN_VEXT_VX(vwadd_wx_h, 2, 4) -GEN_VEXT_VX(vwadd_wx_w, 4, 8) -GEN_VEXT_VX(vwsub_wx_b, 1, 2) -GEN_VEXT_VX(vwsub_wx_h, 2, 4) -GEN_VEXT_VX(vwsub_wx_w, 4, 8) +GEN_VEXT_VX(vwaddu_vx_b, 2) +GEN_VEXT_VX(vwaddu_vx_h, 4) +GEN_VEXT_VX(vwaddu_vx_w, 8) +GEN_VEXT_VX(vwsubu_vx_b, 2) +GEN_VEXT_VX(vwsubu_vx_h, 4) +GEN_VEXT_VX(vwsubu_vx_w, 8) +GEN_VEXT_VX(vwadd_vx_b, 2) +GEN_VEXT_VX(vwadd_vx_h, 4) +GEN_VEXT_VX(vwadd_vx_w, 8) +GEN_VEXT_VX(vwsub_vx_b, 2) +GEN_VEXT_VX(vwsub_vx_h, 4) +GEN_VEXT_VX(vwsub_vx_w, 8) +GEN_VEXT_VX(vwaddu_wx_b, 2) +GEN_VEXT_VX(vwaddu_wx_h, 4) +GEN_VEXT_VX(vwaddu_wx_w, 8) +GEN_VEXT_VX(vwsubu_wx_b, 2) +GEN_VEXT_VX(vwsubu_wx_h, 4) +GEN_VEXT_VX(vwsubu_wx_w, 8) +GEN_VEXT_VX(vwadd_wx_b, 2) +GEN_VEXT_VX(vwadd_wx_h, 4) +GEN_VEXT_VX(vwadd_wx_w, 8) +GEN_VEXT_VX(vwsub_wx_b, 2) +GEN_VEXT_VX(vwsub_wx_h, 4) +GEN_VEXT_VX(vwsub_wx_w, 8) /* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ #define DO_VADC(N, M, C) (N + M + C) @@ -972,6 +1098,10 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -982,6 +1112,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ *((ETYPE *)vd + H(i)) = DO_OP(s2, s1, carry); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VADC_VVM(vadc_vvm_b, uint8_t, H1, DO_VADC) @@ -999,6 +1131,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1008,6 +1143,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ *((ETYPE *)vd + H(i)) = DO_OP(s2, (ETYPE)(target_long)s1, carry);\ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VADC_VXM(vadc_vxm_b, uint8_t, H1, DO_VADC) @@ -1030,6 +1167,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1039,6 +1178,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ vext_set_elem_mask(vd, i, DO_OP(s2, s1, carry)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_VMADC_VVM(vmadc_vvm_b, uint8_t, H1, DO_MADC) @@ -1057,6 +1203,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1066,6 +1214,13 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ DO_OP(s2, (ETYPE)(target_long)s1, carry)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_VMADC_VXM(vmadc_vxm_b, uint8_t, H1, DO_MADC) @@ -1091,18 +1246,18 @@ RVVCALL(OPIVV2, vxor_vv_b, OP_SSS_B, H1, H1, H1, DO_XOR) RVVCALL(OPIVV2, vxor_vv_h, OP_SSS_H, H2, H2, H2, DO_XOR) RVVCALL(OPIVV2, vxor_vv_w, OP_SSS_W, H4, H4, H4, DO_XOR) RVVCALL(OPIVV2, vxor_vv_d, OP_SSS_D, H8, H8, H8, DO_XOR) -GEN_VEXT_VV(vand_vv_b, 1, 1) -GEN_VEXT_VV(vand_vv_h, 2, 2) -GEN_VEXT_VV(vand_vv_w, 4, 4) -GEN_VEXT_VV(vand_vv_d, 8, 8) -GEN_VEXT_VV(vor_vv_b, 1, 1) -GEN_VEXT_VV(vor_vv_h, 2, 2) -GEN_VEXT_VV(vor_vv_w, 4, 4) -GEN_VEXT_VV(vor_vv_d, 8, 8) -GEN_VEXT_VV(vxor_vv_b, 1, 1) -GEN_VEXT_VV(vxor_vv_h, 2, 2) -GEN_VEXT_VV(vxor_vv_w, 4, 4) -GEN_VEXT_VV(vxor_vv_d, 8, 8) +GEN_VEXT_VV(vand_vv_b, 1) +GEN_VEXT_VV(vand_vv_h, 2) +GEN_VEXT_VV(vand_vv_w, 4) +GEN_VEXT_VV(vand_vv_d, 8) +GEN_VEXT_VV(vor_vv_b, 1) +GEN_VEXT_VV(vor_vv_h, 2) +GEN_VEXT_VV(vor_vv_w, 4) +GEN_VEXT_VV(vor_vv_d, 8) +GEN_VEXT_VV(vxor_vv_b, 1) +GEN_VEXT_VV(vxor_vv_h, 2) +GEN_VEXT_VV(vxor_vv_w, 4) +GEN_VEXT_VV(vxor_vv_d, 8) RVVCALL(OPIVX2, vand_vx_b, OP_SSS_B, H1, H1, DO_AND) RVVCALL(OPIVX2, vand_vx_h, OP_SSS_H, H2, H2, DO_AND) @@ -1116,18 +1271,18 @@ RVVCALL(OPIVX2, vxor_vx_b, OP_SSS_B, H1, H1, DO_XOR) RVVCALL(OPIVX2, vxor_vx_h, OP_SSS_H, H2, H2, DO_XOR) RVVCALL(OPIVX2, vxor_vx_w, OP_SSS_W, H4, H4, DO_XOR) RVVCALL(OPIVX2, vxor_vx_d, OP_SSS_D, H8, H8, DO_XOR) -GEN_VEXT_VX(vand_vx_b, 1, 1) -GEN_VEXT_VX(vand_vx_h, 2, 2) -GEN_VEXT_VX(vand_vx_w, 4, 4) -GEN_VEXT_VX(vand_vx_d, 8, 8) -GEN_VEXT_VX(vor_vx_b, 1, 1) -GEN_VEXT_VX(vor_vx_h, 2, 2) -GEN_VEXT_VX(vor_vx_w, 4, 4) -GEN_VEXT_VX(vor_vx_d, 8, 8) -GEN_VEXT_VX(vxor_vx_b, 1, 1) -GEN_VEXT_VX(vxor_vx_h, 2, 2) -GEN_VEXT_VX(vxor_vx_w, 4, 4) -GEN_VEXT_VX(vxor_vx_d, 8, 8) +GEN_VEXT_VX(vand_vx_b, 1) +GEN_VEXT_VX(vand_vx_h, 2) +GEN_VEXT_VX(vand_vx_w, 4) +GEN_VEXT_VX(vand_vx_d, 8) +GEN_VEXT_VX(vor_vx_b, 1) +GEN_VEXT_VX(vor_vx_h, 2) +GEN_VEXT_VX(vor_vx_w, 4) +GEN_VEXT_VX(vor_vx_d, 8) +GEN_VEXT_VX(vxor_vx_b, 1) +GEN_VEXT_VX(vxor_vx_h, 2) +GEN_VEXT_VX(vxor_vx_w, 4) +GEN_VEXT_VX(vxor_vx_d, 8) /* Vector Single-Width Bit Shift Instructions */ #define DO_SLL(N, M) (N << (M)) @@ -1140,10 +1295,16 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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)); \ @@ -1151,6 +1312,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ *((TS1 *)vd + HS1(i)) = OP(s2, s1 & MASK); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_SHIFT_VV(vsll_vv_b, uint8_t, uint8_t, H1, H1, DO_SLL, 0x7) @@ -1175,16 +1338,26 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + 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)); \ *((TD *)vd + HD(i)) = OP(s2, s1 & MASK); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz);\ } GEN_VEXT_SHIFT_VX(vsll_vx_b, uint8_t, int8_t, H1, H1, DO_SLL, 0x7) @@ -1229,17 +1402,31 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ 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)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VV(vmseq_vv_b, uint8_t, H1, DO_MSEQ) @@ -1278,17 +1465,31 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ 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, \ DO_OP(s2, (ETYPE)(target_long)s1)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VX(vmseq_vx_b, uint8_t, H1, DO_MSEQ) @@ -1348,22 +1549,22 @@ RVVCALL(OPIVV2, vmax_vv_b, OP_SSS_B, H1, H1, H1, DO_MAX) RVVCALL(OPIVV2, vmax_vv_h, OP_SSS_H, H2, H2, H2, DO_MAX) RVVCALL(OPIVV2, vmax_vv_w, OP_SSS_W, H4, H4, H4, DO_MAX) RVVCALL(OPIVV2, vmax_vv_d, OP_SSS_D, H8, H8, H8, DO_MAX) -GEN_VEXT_VV(vminu_vv_b, 1, 1) -GEN_VEXT_VV(vminu_vv_h, 2, 2) -GEN_VEXT_VV(vminu_vv_w, 4, 4) -GEN_VEXT_VV(vminu_vv_d, 8, 8) -GEN_VEXT_VV(vmin_vv_b, 1, 1) -GEN_VEXT_VV(vmin_vv_h, 2, 2) -GEN_VEXT_VV(vmin_vv_w, 4, 4) -GEN_VEXT_VV(vmin_vv_d, 8, 8) -GEN_VEXT_VV(vmaxu_vv_b, 1, 1) -GEN_VEXT_VV(vmaxu_vv_h, 2, 2) -GEN_VEXT_VV(vmaxu_vv_w, 4, 4) -GEN_VEXT_VV(vmaxu_vv_d, 8, 8) -GEN_VEXT_VV(vmax_vv_b, 1, 1) -GEN_VEXT_VV(vmax_vv_h, 2, 2) -GEN_VEXT_VV(vmax_vv_w, 4, 4) -GEN_VEXT_VV(vmax_vv_d, 8, 8) +GEN_VEXT_VV(vminu_vv_b, 1) +GEN_VEXT_VV(vminu_vv_h, 2) +GEN_VEXT_VV(vminu_vv_w, 4) +GEN_VEXT_VV(vminu_vv_d, 8) +GEN_VEXT_VV(vmin_vv_b, 1) +GEN_VEXT_VV(vmin_vv_h, 2) +GEN_VEXT_VV(vmin_vv_w, 4) +GEN_VEXT_VV(vmin_vv_d, 8) +GEN_VEXT_VV(vmaxu_vv_b, 1) +GEN_VEXT_VV(vmaxu_vv_h, 2) +GEN_VEXT_VV(vmaxu_vv_w, 4) +GEN_VEXT_VV(vmaxu_vv_d, 8) +GEN_VEXT_VV(vmax_vv_b, 1) +GEN_VEXT_VV(vmax_vv_h, 2) +GEN_VEXT_VV(vmax_vv_w, 4) +GEN_VEXT_VV(vmax_vv_d, 8) RVVCALL(OPIVX2, vminu_vx_b, OP_UUU_B, H1, H1, DO_MIN) RVVCALL(OPIVX2, vminu_vx_h, OP_UUU_H, H2, H2, DO_MIN) @@ -1381,22 +1582,22 @@ RVVCALL(OPIVX2, vmax_vx_b, OP_SSS_B, H1, H1, DO_MAX) RVVCALL(OPIVX2, vmax_vx_h, OP_SSS_H, H2, H2, DO_MAX) RVVCALL(OPIVX2, vmax_vx_w, OP_SSS_W, H4, H4, DO_MAX) RVVCALL(OPIVX2, vmax_vx_d, OP_SSS_D, H8, H8, DO_MAX) -GEN_VEXT_VX(vminu_vx_b, 1, 1) -GEN_VEXT_VX(vminu_vx_h, 2, 2) -GEN_VEXT_VX(vminu_vx_w, 4, 4) -GEN_VEXT_VX(vminu_vx_d, 8, 8) -GEN_VEXT_VX(vmin_vx_b, 1, 1) -GEN_VEXT_VX(vmin_vx_h, 2, 2) -GEN_VEXT_VX(vmin_vx_w, 4, 4) -GEN_VEXT_VX(vmin_vx_d, 8, 8) -GEN_VEXT_VX(vmaxu_vx_b, 1, 1) -GEN_VEXT_VX(vmaxu_vx_h, 2, 2) -GEN_VEXT_VX(vmaxu_vx_w, 4, 4) -GEN_VEXT_VX(vmaxu_vx_d, 8, 8) -GEN_VEXT_VX(vmax_vx_b, 1, 1) -GEN_VEXT_VX(vmax_vx_h, 2, 2) -GEN_VEXT_VX(vmax_vx_w, 4, 4) -GEN_VEXT_VX(vmax_vx_d, 8, 8) +GEN_VEXT_VX(vminu_vx_b, 1) +GEN_VEXT_VX(vminu_vx_h, 2) +GEN_VEXT_VX(vminu_vx_w, 4) +GEN_VEXT_VX(vminu_vx_d, 8) +GEN_VEXT_VX(vmin_vx_b, 1) +GEN_VEXT_VX(vmin_vx_h, 2) +GEN_VEXT_VX(vmin_vx_w, 4) +GEN_VEXT_VX(vmin_vx_d, 8) +GEN_VEXT_VX(vmaxu_vx_b, 1) +GEN_VEXT_VX(vmaxu_vx_h, 2) +GEN_VEXT_VX(vmaxu_vx_w, 4) +GEN_VEXT_VX(vmaxu_vx_d, 8) +GEN_VEXT_VX(vmax_vx_b, 1) +GEN_VEXT_VX(vmax_vx_h, 2) +GEN_VEXT_VX(vmax_vx_w, 4) +GEN_VEXT_VX(vmax_vx_d, 8) /* Vector Single-Width Integer Multiply Instructions */ #define DO_MUL(N, M) (N * M) @@ -1404,10 +1605,10 @@ RVVCALL(OPIVV2, vmul_vv_b, OP_SSS_B, H1, H1, H1, DO_MUL) RVVCALL(OPIVV2, vmul_vv_h, OP_SSS_H, H2, H2, H2, DO_MUL) RVVCALL(OPIVV2, vmul_vv_w, OP_SSS_W, H4, H4, H4, DO_MUL) RVVCALL(OPIVV2, vmul_vv_d, OP_SSS_D, H8, H8, H8, DO_MUL) -GEN_VEXT_VV(vmul_vv_b, 1, 1) -GEN_VEXT_VV(vmul_vv_h, 2, 2) -GEN_VEXT_VV(vmul_vv_w, 4, 4) -GEN_VEXT_VV(vmul_vv_d, 8, 8) +GEN_VEXT_VV(vmul_vv_b, 1) +GEN_VEXT_VV(vmul_vv_h, 2) +GEN_VEXT_VV(vmul_vv_w, 4) +GEN_VEXT_VV(vmul_vv_d, 8) static int8_t do_mulh_b(int8_t s2, int8_t s1) { @@ -1511,18 +1712,18 @@ RVVCALL(OPIVV2, vmulhsu_vv_b, OP_SUS_B, H1, H1, H1, do_mulhsu_b) RVVCALL(OPIVV2, vmulhsu_vv_h, OP_SUS_H, H2, H2, H2, do_mulhsu_h) RVVCALL(OPIVV2, vmulhsu_vv_w, OP_SUS_W, H4, H4, H4, do_mulhsu_w) RVVCALL(OPIVV2, vmulhsu_vv_d, OP_SUS_D, H8, H8, H8, do_mulhsu_d) -GEN_VEXT_VV(vmulh_vv_b, 1, 1) -GEN_VEXT_VV(vmulh_vv_h, 2, 2) -GEN_VEXT_VV(vmulh_vv_w, 4, 4) -GEN_VEXT_VV(vmulh_vv_d, 8, 8) -GEN_VEXT_VV(vmulhu_vv_b, 1, 1) -GEN_VEXT_VV(vmulhu_vv_h, 2, 2) -GEN_VEXT_VV(vmulhu_vv_w, 4, 4) -GEN_VEXT_VV(vmulhu_vv_d, 8, 8) -GEN_VEXT_VV(vmulhsu_vv_b, 1, 1) -GEN_VEXT_VV(vmulhsu_vv_h, 2, 2) -GEN_VEXT_VV(vmulhsu_vv_w, 4, 4) -GEN_VEXT_VV(vmulhsu_vv_d, 8, 8) +GEN_VEXT_VV(vmulh_vv_b, 1) +GEN_VEXT_VV(vmulh_vv_h, 2) +GEN_VEXT_VV(vmulh_vv_w, 4) +GEN_VEXT_VV(vmulh_vv_d, 8) +GEN_VEXT_VV(vmulhu_vv_b, 1) +GEN_VEXT_VV(vmulhu_vv_h, 2) +GEN_VEXT_VV(vmulhu_vv_w, 4) +GEN_VEXT_VV(vmulhu_vv_d, 8) +GEN_VEXT_VV(vmulhsu_vv_b, 1) +GEN_VEXT_VV(vmulhsu_vv_h, 2) +GEN_VEXT_VV(vmulhsu_vv_w, 4) +GEN_VEXT_VV(vmulhsu_vv_d, 8) RVVCALL(OPIVX2, vmul_vx_b, OP_SSS_B, H1, H1, DO_MUL) RVVCALL(OPIVX2, vmul_vx_h, OP_SSS_H, H2, H2, DO_MUL) @@ -1540,22 +1741,22 @@ RVVCALL(OPIVX2, vmulhsu_vx_b, OP_SUS_B, H1, H1, do_mulhsu_b) RVVCALL(OPIVX2, vmulhsu_vx_h, OP_SUS_H, H2, H2, do_mulhsu_h) RVVCALL(OPIVX2, vmulhsu_vx_w, OP_SUS_W, H4, H4, do_mulhsu_w) RVVCALL(OPIVX2, vmulhsu_vx_d, OP_SUS_D, H8, H8, do_mulhsu_d) -GEN_VEXT_VX(vmul_vx_b, 1, 1) -GEN_VEXT_VX(vmul_vx_h, 2, 2) -GEN_VEXT_VX(vmul_vx_w, 4, 4) -GEN_VEXT_VX(vmul_vx_d, 8, 8) -GEN_VEXT_VX(vmulh_vx_b, 1, 1) -GEN_VEXT_VX(vmulh_vx_h, 2, 2) -GEN_VEXT_VX(vmulh_vx_w, 4, 4) -GEN_VEXT_VX(vmulh_vx_d, 8, 8) -GEN_VEXT_VX(vmulhu_vx_b, 1, 1) -GEN_VEXT_VX(vmulhu_vx_h, 2, 2) -GEN_VEXT_VX(vmulhu_vx_w, 4, 4) -GEN_VEXT_VX(vmulhu_vx_d, 8, 8) -GEN_VEXT_VX(vmulhsu_vx_b, 1, 1) -GEN_VEXT_VX(vmulhsu_vx_h, 2, 2) -GEN_VEXT_VX(vmulhsu_vx_w, 4, 4) -GEN_VEXT_VX(vmulhsu_vx_d, 8, 8) +GEN_VEXT_VX(vmul_vx_b, 1) +GEN_VEXT_VX(vmul_vx_h, 2) +GEN_VEXT_VX(vmul_vx_w, 4) +GEN_VEXT_VX(vmul_vx_d, 8) +GEN_VEXT_VX(vmulh_vx_b, 1) +GEN_VEXT_VX(vmulh_vx_h, 2) +GEN_VEXT_VX(vmulh_vx_w, 4) +GEN_VEXT_VX(vmulh_vx_d, 8) +GEN_VEXT_VX(vmulhu_vx_b, 1) +GEN_VEXT_VX(vmulhu_vx_h, 2) +GEN_VEXT_VX(vmulhu_vx_w, 4) +GEN_VEXT_VX(vmulhu_vx_d, 8) +GEN_VEXT_VX(vmulhsu_vx_b, 1) +GEN_VEXT_VX(vmulhsu_vx_h, 2) +GEN_VEXT_VX(vmulhsu_vx_w, 4) +GEN_VEXT_VX(vmulhsu_vx_d, 8) /* Vector Integer Divide Instructions */ #define DO_DIVU(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) : N / M) @@ -1581,22 +1782,22 @@ RVVCALL(OPIVV2, vrem_vv_b, OP_SSS_B, H1, H1, H1, DO_REM) RVVCALL(OPIVV2, vrem_vv_h, OP_SSS_H, H2, H2, H2, DO_REM) RVVCALL(OPIVV2, vrem_vv_w, OP_SSS_W, H4, H4, H4, DO_REM) RVVCALL(OPIVV2, vrem_vv_d, OP_SSS_D, H8, H8, H8, DO_REM) -GEN_VEXT_VV(vdivu_vv_b, 1, 1) -GEN_VEXT_VV(vdivu_vv_h, 2, 2) -GEN_VEXT_VV(vdivu_vv_w, 4, 4) -GEN_VEXT_VV(vdivu_vv_d, 8, 8) -GEN_VEXT_VV(vdiv_vv_b, 1, 1) -GEN_VEXT_VV(vdiv_vv_h, 2, 2) -GEN_VEXT_VV(vdiv_vv_w, 4, 4) -GEN_VEXT_VV(vdiv_vv_d, 8, 8) -GEN_VEXT_VV(vremu_vv_b, 1, 1) -GEN_VEXT_VV(vremu_vv_h, 2, 2) -GEN_VEXT_VV(vremu_vv_w, 4, 4) -GEN_VEXT_VV(vremu_vv_d, 8, 8) -GEN_VEXT_VV(vrem_vv_b, 1, 1) -GEN_VEXT_VV(vrem_vv_h, 2, 2) -GEN_VEXT_VV(vrem_vv_w, 4, 4) -GEN_VEXT_VV(vrem_vv_d, 8, 8) +GEN_VEXT_VV(vdivu_vv_b, 1) +GEN_VEXT_VV(vdivu_vv_h, 2) +GEN_VEXT_VV(vdivu_vv_w, 4) +GEN_VEXT_VV(vdivu_vv_d, 8) +GEN_VEXT_VV(vdiv_vv_b, 1) +GEN_VEXT_VV(vdiv_vv_h, 2) +GEN_VEXT_VV(vdiv_vv_w, 4) +GEN_VEXT_VV(vdiv_vv_d, 8) +GEN_VEXT_VV(vremu_vv_b, 1) +GEN_VEXT_VV(vremu_vv_h, 2) +GEN_VEXT_VV(vremu_vv_w, 4) +GEN_VEXT_VV(vremu_vv_d, 8) +GEN_VEXT_VV(vrem_vv_b, 1) +GEN_VEXT_VV(vrem_vv_h, 2) +GEN_VEXT_VV(vrem_vv_w, 4) +GEN_VEXT_VV(vrem_vv_d, 8) RVVCALL(OPIVX2, vdivu_vx_b, OP_UUU_B, H1, H1, DO_DIVU) RVVCALL(OPIVX2, vdivu_vx_h, OP_UUU_H, H2, H2, DO_DIVU) @@ -1614,22 +1815,22 @@ RVVCALL(OPIVX2, vrem_vx_b, OP_SSS_B, H1, H1, DO_REM) RVVCALL(OPIVX2, vrem_vx_h, OP_SSS_H, H2, H2, DO_REM) RVVCALL(OPIVX2, vrem_vx_w, OP_SSS_W, H4, H4, DO_REM) RVVCALL(OPIVX2, vrem_vx_d, OP_SSS_D, H8, H8, DO_REM) -GEN_VEXT_VX(vdivu_vx_b, 1, 1) -GEN_VEXT_VX(vdivu_vx_h, 2, 2) -GEN_VEXT_VX(vdivu_vx_w, 4, 4) -GEN_VEXT_VX(vdivu_vx_d, 8, 8) -GEN_VEXT_VX(vdiv_vx_b, 1, 1) -GEN_VEXT_VX(vdiv_vx_h, 2, 2) -GEN_VEXT_VX(vdiv_vx_w, 4, 4) -GEN_VEXT_VX(vdiv_vx_d, 8, 8) -GEN_VEXT_VX(vremu_vx_b, 1, 1) -GEN_VEXT_VX(vremu_vx_h, 2, 2) -GEN_VEXT_VX(vremu_vx_w, 4, 4) -GEN_VEXT_VX(vremu_vx_d, 8, 8) -GEN_VEXT_VX(vrem_vx_b, 1, 1) -GEN_VEXT_VX(vrem_vx_h, 2, 2) -GEN_VEXT_VX(vrem_vx_w, 4, 4) -GEN_VEXT_VX(vrem_vx_d, 8, 8) +GEN_VEXT_VX(vdivu_vx_b, 1) +GEN_VEXT_VX(vdivu_vx_h, 2) +GEN_VEXT_VX(vdivu_vx_w, 4) +GEN_VEXT_VX(vdivu_vx_d, 8) +GEN_VEXT_VX(vdiv_vx_b, 1) +GEN_VEXT_VX(vdiv_vx_h, 2) +GEN_VEXT_VX(vdiv_vx_w, 4) +GEN_VEXT_VX(vdiv_vx_d, 8) +GEN_VEXT_VX(vremu_vx_b, 1) +GEN_VEXT_VX(vremu_vx_h, 2) +GEN_VEXT_VX(vremu_vx_w, 4) +GEN_VEXT_VX(vremu_vx_d, 8) +GEN_VEXT_VX(vrem_vx_b, 1) +GEN_VEXT_VX(vrem_vx_h, 2) +GEN_VEXT_VX(vrem_vx_w, 4) +GEN_VEXT_VX(vrem_vx_d, 8) /* Vector Widening Integer Multiply Instructions */ RVVCALL(OPIVV2, vwmul_vv_b, WOP_SSS_B, H2, H1, H1, DO_MUL) @@ -1641,15 +1842,15 @@ RVVCALL(OPIVV2, vwmulu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_b, WOP_SUS_B, H2, H1, H1, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_h, WOP_SUS_H, H4, H2, H2, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_w, WOP_SUS_W, H8, H4, H4, DO_MUL) -GEN_VEXT_VV(vwmul_vv_b, 1, 2) -GEN_VEXT_VV(vwmul_vv_h, 2, 4) -GEN_VEXT_VV(vwmul_vv_w, 4, 8) -GEN_VEXT_VV(vwmulu_vv_b, 1, 2) -GEN_VEXT_VV(vwmulu_vv_h, 2, 4) -GEN_VEXT_VV(vwmulu_vv_w, 4, 8) -GEN_VEXT_VV(vwmulsu_vv_b, 1, 2) -GEN_VEXT_VV(vwmulsu_vv_h, 2, 4) -GEN_VEXT_VV(vwmulsu_vv_w, 4, 8) +GEN_VEXT_VV(vwmul_vv_b, 2) +GEN_VEXT_VV(vwmul_vv_h, 4) +GEN_VEXT_VV(vwmul_vv_w, 8) +GEN_VEXT_VV(vwmulu_vv_b, 2) +GEN_VEXT_VV(vwmulu_vv_h, 4) +GEN_VEXT_VV(vwmulu_vv_w, 8) +GEN_VEXT_VV(vwmulsu_vv_b, 2) +GEN_VEXT_VV(vwmulsu_vv_h, 4) +GEN_VEXT_VV(vwmulsu_vv_w, 8) RVVCALL(OPIVX2, vwmul_vx_b, WOP_SSS_B, H2, H1, DO_MUL) RVVCALL(OPIVX2, vwmul_vx_h, WOP_SSS_H, H4, H2, DO_MUL) @@ -1660,15 +1861,15 @@ RVVCALL(OPIVX2, vwmulu_vx_w, WOP_UUU_W, H8, H4, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_b, WOP_SUS_B, H2, H1, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_h, WOP_SUS_H, H4, H2, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_w, WOP_SUS_W, H8, H4, DO_MUL) -GEN_VEXT_VX(vwmul_vx_b, 1, 2) -GEN_VEXT_VX(vwmul_vx_h, 2, 4) -GEN_VEXT_VX(vwmul_vx_w, 4, 8) -GEN_VEXT_VX(vwmulu_vx_b, 1, 2) -GEN_VEXT_VX(vwmulu_vx_h, 2, 4) -GEN_VEXT_VX(vwmulu_vx_w, 4, 8) -GEN_VEXT_VX(vwmulsu_vx_b, 1, 2) -GEN_VEXT_VX(vwmulsu_vx_h, 2, 4) -GEN_VEXT_VX(vwmulsu_vx_w, 4, 8) +GEN_VEXT_VX(vwmul_vx_b, 2) +GEN_VEXT_VX(vwmul_vx_h, 4) +GEN_VEXT_VX(vwmul_vx_w, 8) +GEN_VEXT_VX(vwmulu_vx_b, 2) +GEN_VEXT_VX(vwmulu_vx_h, 4) +GEN_VEXT_VX(vwmulu_vx_w, 8) +GEN_VEXT_VX(vwmulsu_vx_b, 2) +GEN_VEXT_VX(vwmulsu_vx_h, 4) +GEN_VEXT_VX(vwmulsu_vx_w, 8) /* Vector Single-Width Integer Multiply-Add Instructions */ #define OPIVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ @@ -1700,22 +1901,22 @@ RVVCALL(OPIVV3, vnmsub_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSUB) -GEN_VEXT_VV(vmacc_vv_b, 1, 1) -GEN_VEXT_VV(vmacc_vv_h, 2, 2) -GEN_VEXT_VV(vmacc_vv_w, 4, 4) -GEN_VEXT_VV(vmacc_vv_d, 8, 8) -GEN_VEXT_VV(vnmsac_vv_b, 1, 1) -GEN_VEXT_VV(vnmsac_vv_h, 2, 2) -GEN_VEXT_VV(vnmsac_vv_w, 4, 4) -GEN_VEXT_VV(vnmsac_vv_d, 8, 8) -GEN_VEXT_VV(vmadd_vv_b, 1, 1) -GEN_VEXT_VV(vmadd_vv_h, 2, 2) -GEN_VEXT_VV(vmadd_vv_w, 4, 4) -GEN_VEXT_VV(vmadd_vv_d, 8, 8) -GEN_VEXT_VV(vnmsub_vv_b, 1, 1) -GEN_VEXT_VV(vnmsub_vv_h, 2, 2) -GEN_VEXT_VV(vnmsub_vv_w, 4, 4) -GEN_VEXT_VV(vnmsub_vv_d, 8, 8) +GEN_VEXT_VV(vmacc_vv_b, 1) +GEN_VEXT_VV(vmacc_vv_h, 2) +GEN_VEXT_VV(vmacc_vv_w, 4) +GEN_VEXT_VV(vmacc_vv_d, 8) +GEN_VEXT_VV(vnmsac_vv_b, 1) +GEN_VEXT_VV(vnmsac_vv_h, 2) +GEN_VEXT_VV(vnmsac_vv_w, 4) +GEN_VEXT_VV(vnmsac_vv_d, 8) +GEN_VEXT_VV(vmadd_vv_b, 1) +GEN_VEXT_VV(vmadd_vv_h, 2) +GEN_VEXT_VV(vmadd_vv_w, 4) +GEN_VEXT_VV(vmadd_vv_d, 8) +GEN_VEXT_VV(vnmsub_vv_b, 1) +GEN_VEXT_VV(vnmsub_vv_h, 2) +GEN_VEXT_VV(vnmsub_vv_w, 4) +GEN_VEXT_VV(vnmsub_vv_d, 8) #define OPIVX3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \ @@ -1741,22 +1942,22 @@ RVVCALL(OPIVX3, vnmsub_vx_b, OP_SSS_B, H1, H1, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_h, OP_SSS_H, H2, H2, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_w, OP_SSS_W, H4, H4, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_d, OP_SSS_D, H8, H8, DO_NMSUB) -GEN_VEXT_VX(vmacc_vx_b, 1, 1) -GEN_VEXT_VX(vmacc_vx_h, 2, 2) -GEN_VEXT_VX(vmacc_vx_w, 4, 4) -GEN_VEXT_VX(vmacc_vx_d, 8, 8) -GEN_VEXT_VX(vnmsac_vx_b, 1, 1) -GEN_VEXT_VX(vnmsac_vx_h, 2, 2) -GEN_VEXT_VX(vnmsac_vx_w, 4, 4) -GEN_VEXT_VX(vnmsac_vx_d, 8, 8) -GEN_VEXT_VX(vmadd_vx_b, 1, 1) -GEN_VEXT_VX(vmadd_vx_h, 2, 2) -GEN_VEXT_VX(vmadd_vx_w, 4, 4) -GEN_VEXT_VX(vmadd_vx_d, 8, 8) -GEN_VEXT_VX(vnmsub_vx_b, 1, 1) -GEN_VEXT_VX(vnmsub_vx_h, 2, 2) -GEN_VEXT_VX(vnmsub_vx_w, 4, 4) -GEN_VEXT_VX(vnmsub_vx_d, 8, 8) +GEN_VEXT_VX(vmacc_vx_b, 1) +GEN_VEXT_VX(vmacc_vx_h, 2) +GEN_VEXT_VX(vmacc_vx_w, 4) +GEN_VEXT_VX(vmacc_vx_d, 8) +GEN_VEXT_VX(vnmsac_vx_b, 1) +GEN_VEXT_VX(vnmsac_vx_h, 2) +GEN_VEXT_VX(vnmsac_vx_w, 4) +GEN_VEXT_VX(vnmsac_vx_d, 8) +GEN_VEXT_VX(vmadd_vx_b, 1) +GEN_VEXT_VX(vmadd_vx_h, 2) +GEN_VEXT_VX(vmadd_vx_w, 4) +GEN_VEXT_VX(vmadd_vx_d, 8) +GEN_VEXT_VX(vnmsub_vx_b, 1) +GEN_VEXT_VX(vnmsub_vx_h, 2) +GEN_VEXT_VX(vnmsub_vx_w, 4) +GEN_VEXT_VX(vnmsub_vx_d, 8) /* Vector Widening Integer Multiply-Add Instructions */ RVVCALL(OPIVV3, vwmaccu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MACC) @@ -1768,15 +1969,15 @@ RVVCALL(OPIVV3, vwmacc_vv_w, WOP_SSS_W, H8, H4, H4, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, DO_MACC) -GEN_VEXT_VV(vwmaccu_vv_b, 1, 2) -GEN_VEXT_VV(vwmaccu_vv_h, 2, 4) -GEN_VEXT_VV(vwmaccu_vv_w, 4, 8) -GEN_VEXT_VV(vwmacc_vv_b, 1, 2) -GEN_VEXT_VV(vwmacc_vv_h, 2, 4) -GEN_VEXT_VV(vwmacc_vv_w, 4, 8) -GEN_VEXT_VV(vwmaccsu_vv_b, 1, 2) -GEN_VEXT_VV(vwmaccsu_vv_h, 2, 4) -GEN_VEXT_VV(vwmaccsu_vv_w, 4, 8) +GEN_VEXT_VV(vwmaccu_vv_b, 2) +GEN_VEXT_VV(vwmaccu_vv_h, 4) +GEN_VEXT_VV(vwmaccu_vv_w, 8) +GEN_VEXT_VV(vwmacc_vv_b, 2) +GEN_VEXT_VV(vwmacc_vv_h, 4) +GEN_VEXT_VV(vwmacc_vv_w, 8) +GEN_VEXT_VV(vwmaccsu_vv_b, 2) +GEN_VEXT_VV(vwmaccsu_vv_h, 4) +GEN_VEXT_VV(vwmaccsu_vv_w, 8) RVVCALL(OPIVX3, vwmaccu_vx_b, WOP_UUU_B, H2, H1, DO_MACC) RVVCALL(OPIVX3, vwmaccu_vx_h, WOP_UUU_H, H4, H2, DO_MACC) @@ -1790,18 +1991,18 @@ RVVCALL(OPIVX3, vwmaccsu_vx_w, WOP_SSU_W, H8, H4, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_b, WOP_SUS_B, H2, H1, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_h, WOP_SUS_H, H4, H2, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_w, WOP_SUS_W, H8, H4, DO_MACC) -GEN_VEXT_VX(vwmaccu_vx_b, 1, 2) -GEN_VEXT_VX(vwmaccu_vx_h, 2, 4) -GEN_VEXT_VX(vwmaccu_vx_w, 4, 8) -GEN_VEXT_VX(vwmacc_vx_b, 1, 2) -GEN_VEXT_VX(vwmacc_vx_h, 2, 4) -GEN_VEXT_VX(vwmacc_vx_w, 4, 8) -GEN_VEXT_VX(vwmaccsu_vx_b, 1, 2) -GEN_VEXT_VX(vwmaccsu_vx_h, 2, 4) -GEN_VEXT_VX(vwmaccsu_vx_w, 4, 8) -GEN_VEXT_VX(vwmaccus_vx_b, 1, 2) -GEN_VEXT_VX(vwmaccus_vx_h, 2, 4) -GEN_VEXT_VX(vwmaccus_vx_w, 4, 8) +GEN_VEXT_VX(vwmaccu_vx_b, 2) +GEN_VEXT_VX(vwmaccu_vx_h, 4) +GEN_VEXT_VX(vwmaccu_vx_w, 8) +GEN_VEXT_VX(vwmacc_vx_b, 2) +GEN_VEXT_VX(vwmacc_vx_h, 4) +GEN_VEXT_VX(vwmacc_vx_w, 8) +GEN_VEXT_VX(vwmaccsu_vx_b, 2) +GEN_VEXT_VX(vwmaccsu_vx_h, 4) +GEN_VEXT_VX(vwmaccsu_vx_w, 8) +GEN_VEXT_VX(vwmaccus_vx_b, 2) +GEN_VEXT_VX(vwmaccus_vx_h, 4) +GEN_VEXT_VX(vwmaccus_vx_w, 8) /* Vector Integer Merge and Move Instructions */ #define GEN_VEXT_VMV_VV(NAME, ETYPE, H) \ @@ -1809,6 +2010,9 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1816,6 +2020,8 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \ *((ETYPE *)vd + H(i)) = s1; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMV_VV(vmv_v_v_b, int8_t, H1) @@ -1828,12 +2034,17 @@ void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ *((ETYPE *)vd + H(i)) = (ETYPE)s1; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMV_VX(vmv_v_x_b, int8_t, H1) @@ -1846,6 +2057,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1853,6 +2067,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ *((ETYPE *)vd + H(i)) = *(vt + H(i)); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMERGE_VV(vmerge_vvm_b, int8_t, H1) @@ -1865,6 +2081,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1874,6 +2093,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ *((ETYPE *)vd + H(i)) = d; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMERGE_VX(vmerge_vxm_b, int8_t, H1) @@ -1908,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); @@ -1922,39 +2145,44 @@ vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2, static inline void vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, - uint32_t desc, uint32_t esz, uint32_t dsz, - opivv2_rm_fn *fn) + uint32_t desc, + opivv2_rm_fn *fn, uint32_t esz) { uint32_t vm = vext_vm(desc); 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 */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate helpers for fixed point instructions with OPIVV format */ -#define GEN_VEXT_VV_RM(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VV_RM(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \ - do_##NAME); \ + vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, \ + do_##NAME, ESZ); \ } static inline uint8_t saddu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) @@ -2004,10 +2232,10 @@ RVVCALL(OPIVV2_RM, vsaddu_vv_b, OP_UUU_B, H1, H1, H1, saddu8) RVVCALL(OPIVV2_RM, vsaddu_vv_h, OP_UUU_H, H2, H2, H2, saddu16) RVVCALL(OPIVV2_RM, vsaddu_vv_w, OP_UUU_W, H4, H4, H4, saddu32) RVVCALL(OPIVV2_RM, vsaddu_vv_d, OP_UUU_D, H8, H8, H8, saddu64) -GEN_VEXT_VV_RM(vsaddu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vsaddu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vsaddu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vsaddu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vsaddu_vv_b, 1) +GEN_VEXT_VV_RM(vsaddu_vv_h, 2) +GEN_VEXT_VV_RM(vsaddu_vv_w, 4) +GEN_VEXT_VV_RM(vsaddu_vv_d, 8) typedef void opivx2_rm_fn(void *vd, target_long s1, void *vs2, int i, CPURISCVState *env, int vxrm); @@ -2025,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); @@ -2039,49 +2269,54 @@ vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2, static inline void vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, - uint32_t desc, uint32_t esz, uint32_t dsz, - opivx2_rm_fn *fn) + uint32_t desc, + opivx2_rm_fn *fn, uint32_t esz) { uint32_t vm = vext_vm(desc); 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 */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate helpers for fixed point instructions with OPIVX format */ -#define GEN_VEXT_VX_RM(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VX_RM(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ - vext_vx_rm_2(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \ - do_##NAME); \ + vext_vx_rm_2(vd, v0, s1, vs2, env, desc, \ + do_##NAME, ESZ); \ } RVVCALL(OPIVX2_RM, vsaddu_vx_b, OP_UUU_B, H1, H1, saddu8) RVVCALL(OPIVX2_RM, vsaddu_vx_h, OP_UUU_H, H2, H2, saddu16) RVVCALL(OPIVX2_RM, vsaddu_vx_w, OP_UUU_W, H4, H4, saddu32) RVVCALL(OPIVX2_RM, vsaddu_vx_d, OP_UUU_D, H8, H8, saddu64) -GEN_VEXT_VX_RM(vsaddu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vsaddu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vsaddu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vsaddu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vsaddu_vx_b, 1) +GEN_VEXT_VX_RM(vsaddu_vx_h, 2) +GEN_VEXT_VX_RM(vsaddu_vx_w, 4) +GEN_VEXT_VX_RM(vsaddu_vx_d, 8) static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { @@ -2127,19 +2362,19 @@ RVVCALL(OPIVV2_RM, vsadd_vv_b, OP_SSS_B, H1, H1, H1, sadd8) RVVCALL(OPIVV2_RM, vsadd_vv_h, OP_SSS_H, H2, H2, H2, sadd16) RVVCALL(OPIVV2_RM, vsadd_vv_w, OP_SSS_W, H4, H4, H4, sadd32) RVVCALL(OPIVV2_RM, vsadd_vv_d, OP_SSS_D, H8, H8, H8, sadd64) -GEN_VEXT_VV_RM(vsadd_vv_b, 1, 1) -GEN_VEXT_VV_RM(vsadd_vv_h, 2, 2) -GEN_VEXT_VV_RM(vsadd_vv_w, 4, 4) -GEN_VEXT_VV_RM(vsadd_vv_d, 8, 8) +GEN_VEXT_VV_RM(vsadd_vv_b, 1) +GEN_VEXT_VV_RM(vsadd_vv_h, 2) +GEN_VEXT_VV_RM(vsadd_vv_w, 4) +GEN_VEXT_VV_RM(vsadd_vv_d, 8) RVVCALL(OPIVX2_RM, vsadd_vx_b, OP_SSS_B, H1, H1, sadd8) RVVCALL(OPIVX2_RM, vsadd_vx_h, OP_SSS_H, H2, H2, sadd16) RVVCALL(OPIVX2_RM, vsadd_vx_w, OP_SSS_W, H4, H4, sadd32) RVVCALL(OPIVX2_RM, vsadd_vx_d, OP_SSS_D, H8, H8, sadd64) -GEN_VEXT_VX_RM(vsadd_vx_b, 1, 1) -GEN_VEXT_VX_RM(vsadd_vx_h, 2, 2) -GEN_VEXT_VX_RM(vsadd_vx_w, 4, 4) -GEN_VEXT_VX_RM(vsadd_vx_d, 8, 8) +GEN_VEXT_VX_RM(vsadd_vx_b, 1) +GEN_VEXT_VX_RM(vsadd_vx_h, 2) +GEN_VEXT_VX_RM(vsadd_vx_w, 4) +GEN_VEXT_VX_RM(vsadd_vx_d, 8) static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) { @@ -2188,19 +2423,19 @@ RVVCALL(OPIVV2_RM, vssubu_vv_b, OP_UUU_B, H1, H1, H1, ssubu8) RVVCALL(OPIVV2_RM, vssubu_vv_h, OP_UUU_H, H2, H2, H2, ssubu16) RVVCALL(OPIVV2_RM, vssubu_vv_w, OP_UUU_W, H4, H4, H4, ssubu32) RVVCALL(OPIVV2_RM, vssubu_vv_d, OP_UUU_D, H8, H8, H8, ssubu64) -GEN_VEXT_VV_RM(vssubu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssubu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssubu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssubu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssubu_vv_b, 1) +GEN_VEXT_VV_RM(vssubu_vv_h, 2) +GEN_VEXT_VV_RM(vssubu_vv_w, 4) +GEN_VEXT_VV_RM(vssubu_vv_d, 8) RVVCALL(OPIVX2_RM, vssubu_vx_b, OP_UUU_B, H1, H1, ssubu8) RVVCALL(OPIVX2_RM, vssubu_vx_h, OP_UUU_H, H2, H2, ssubu16) RVVCALL(OPIVX2_RM, vssubu_vx_w, OP_UUU_W, H4, H4, ssubu32) RVVCALL(OPIVX2_RM, vssubu_vx_d, OP_UUU_D, H8, H8, ssubu64) -GEN_VEXT_VX_RM(vssubu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssubu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssubu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssubu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssubu_vx_b, 1) +GEN_VEXT_VX_RM(vssubu_vx_h, 2) +GEN_VEXT_VX_RM(vssubu_vx_w, 4) +GEN_VEXT_VX_RM(vssubu_vx_d, 8) static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { @@ -2246,19 +2481,19 @@ RVVCALL(OPIVV2_RM, vssub_vv_b, OP_SSS_B, H1, H1, H1, ssub8) RVVCALL(OPIVV2_RM, vssub_vv_h, OP_SSS_H, H2, H2, H2, ssub16) RVVCALL(OPIVV2_RM, vssub_vv_w, OP_SSS_W, H4, H4, H4, ssub32) RVVCALL(OPIVV2_RM, vssub_vv_d, OP_SSS_D, H8, H8, H8, ssub64) -GEN_VEXT_VV_RM(vssub_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssub_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssub_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssub_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssub_vv_b, 1) +GEN_VEXT_VV_RM(vssub_vv_h, 2) +GEN_VEXT_VV_RM(vssub_vv_w, 4) +GEN_VEXT_VV_RM(vssub_vv_d, 8) RVVCALL(OPIVX2_RM, vssub_vx_b, OP_SSS_B, H1, H1, ssub8) RVVCALL(OPIVX2_RM, vssub_vx_h, OP_SSS_H, H2, H2, ssub16) RVVCALL(OPIVX2_RM, vssub_vx_w, OP_SSS_W, H4, H4, ssub32) RVVCALL(OPIVX2_RM, vssub_vx_d, OP_SSS_D, H8, H8, ssub64) -GEN_VEXT_VX_RM(vssub_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssub_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssub_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssub_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssub_vx_b, 1) +GEN_VEXT_VX_RM(vssub_vx_h, 2) +GEN_VEXT_VX_RM(vssub_vx_w, 4) +GEN_VEXT_VX_RM(vssub_vx_d, 8) /* Vector Single-Width Averaging Add and Subtract */ static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift) @@ -2310,19 +2545,19 @@ RVVCALL(OPIVV2_RM, vaadd_vv_b, OP_SSS_B, H1, H1, H1, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_h, OP_SSS_H, H2, H2, H2, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_w, OP_SSS_W, H4, H4, H4, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_d, OP_SSS_D, H8, H8, H8, aadd64) -GEN_VEXT_VV_RM(vaadd_vv_b, 1, 1) -GEN_VEXT_VV_RM(vaadd_vv_h, 2, 2) -GEN_VEXT_VV_RM(vaadd_vv_w, 4, 4) -GEN_VEXT_VV_RM(vaadd_vv_d, 8, 8) +GEN_VEXT_VV_RM(vaadd_vv_b, 1) +GEN_VEXT_VV_RM(vaadd_vv_h, 2) +GEN_VEXT_VV_RM(vaadd_vv_w, 4) +GEN_VEXT_VV_RM(vaadd_vv_d, 8) RVVCALL(OPIVX2_RM, vaadd_vx_b, OP_SSS_B, H1, H1, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_h, OP_SSS_H, H2, H2, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_w, OP_SSS_W, H4, H4, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_d, OP_SSS_D, H8, H8, aadd64) -GEN_VEXT_VX_RM(vaadd_vx_b, 1, 1) -GEN_VEXT_VX_RM(vaadd_vx_h, 2, 2) -GEN_VEXT_VX_RM(vaadd_vx_w, 4, 4) -GEN_VEXT_VX_RM(vaadd_vx_d, 8, 8) +GEN_VEXT_VX_RM(vaadd_vx_b, 1) +GEN_VEXT_VX_RM(vaadd_vx_h, 2) +GEN_VEXT_VX_RM(vaadd_vx_w, 4) +GEN_VEXT_VX_RM(vaadd_vx_d, 8) static inline uint32_t aaddu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) @@ -2347,19 +2582,19 @@ RVVCALL(OPIVV2_RM, vaaddu_vv_b, OP_UUU_B, H1, H1, H1, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_h, OP_UUU_H, H2, H2, H2, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_w, OP_UUU_W, H4, H4, H4, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_d, OP_UUU_D, H8, H8, H8, aaddu64) -GEN_VEXT_VV_RM(vaaddu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vaaddu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vaaddu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vaaddu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vaaddu_vv_b, 1) +GEN_VEXT_VV_RM(vaaddu_vv_h, 2) +GEN_VEXT_VV_RM(vaaddu_vv_w, 4) +GEN_VEXT_VV_RM(vaaddu_vv_d, 8) RVVCALL(OPIVX2_RM, vaaddu_vx_b, OP_UUU_B, H1, H1, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_h, OP_UUU_H, H2, H2, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_w, OP_UUU_W, H4, H4, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_d, OP_UUU_D, H8, H8, aaddu64) -GEN_VEXT_VX_RM(vaaddu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vaaddu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vaaddu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vaaddu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vaaddu_vx_b, 1) +GEN_VEXT_VX_RM(vaaddu_vx_h, 2) +GEN_VEXT_VX_RM(vaaddu_vx_w, 4) +GEN_VEXT_VX_RM(vaaddu_vx_d, 8) static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) { @@ -2383,19 +2618,19 @@ RVVCALL(OPIVV2_RM, vasub_vv_b, OP_SSS_B, H1, H1, H1, asub32) RVVCALL(OPIVV2_RM, vasub_vv_h, OP_SSS_H, H2, H2, H2, asub32) RVVCALL(OPIVV2_RM, vasub_vv_w, OP_SSS_W, H4, H4, H4, asub32) RVVCALL(OPIVV2_RM, vasub_vv_d, OP_SSS_D, H8, H8, H8, asub64) -GEN_VEXT_VV_RM(vasub_vv_b, 1, 1) -GEN_VEXT_VV_RM(vasub_vv_h, 2, 2) -GEN_VEXT_VV_RM(vasub_vv_w, 4, 4) -GEN_VEXT_VV_RM(vasub_vv_d, 8, 8) +GEN_VEXT_VV_RM(vasub_vv_b, 1) +GEN_VEXT_VV_RM(vasub_vv_h, 2) +GEN_VEXT_VV_RM(vasub_vv_w, 4) +GEN_VEXT_VV_RM(vasub_vv_d, 8) RVVCALL(OPIVX2_RM, vasub_vx_b, OP_SSS_B, H1, H1, asub32) RVVCALL(OPIVX2_RM, vasub_vx_h, OP_SSS_H, H2, H2, asub32) RVVCALL(OPIVX2_RM, vasub_vx_w, OP_SSS_W, H4, H4, asub32) RVVCALL(OPIVX2_RM, vasub_vx_d, OP_SSS_D, H8, H8, asub64) -GEN_VEXT_VX_RM(vasub_vx_b, 1, 1) -GEN_VEXT_VX_RM(vasub_vx_h, 2, 2) -GEN_VEXT_VX_RM(vasub_vx_w, 4, 4) -GEN_VEXT_VX_RM(vasub_vx_d, 8, 8) +GEN_VEXT_VX_RM(vasub_vx_b, 1) +GEN_VEXT_VX_RM(vasub_vx_h, 2) +GEN_VEXT_VX_RM(vasub_vx_w, 4) +GEN_VEXT_VX_RM(vasub_vx_d, 8) static inline uint32_t asubu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) @@ -2420,19 +2655,19 @@ RVVCALL(OPIVV2_RM, vasubu_vv_b, OP_UUU_B, H1, H1, H1, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_h, OP_UUU_H, H2, H2, H2, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_w, OP_UUU_W, H4, H4, H4, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_d, OP_UUU_D, H8, H8, H8, asubu64) -GEN_VEXT_VV_RM(vasubu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vasubu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vasubu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vasubu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vasubu_vv_b, 1) +GEN_VEXT_VV_RM(vasubu_vv_h, 2) +GEN_VEXT_VV_RM(vasubu_vv_w, 4) +GEN_VEXT_VV_RM(vasubu_vv_d, 8) RVVCALL(OPIVX2_RM, vasubu_vx_b, OP_UUU_B, H1, H1, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_h, OP_UUU_H, H2, H2, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_w, OP_UUU_W, H4, H4, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_d, OP_UUU_D, H8, H8, asubu64) -GEN_VEXT_VX_RM(vasubu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vasubu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vasubu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vasubu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vasubu_vx_b, 1) +GEN_VEXT_VX_RM(vasubu_vx_h, 2) +GEN_VEXT_VX_RM(vasubu_vx_w, 4) +GEN_VEXT_VX_RM(vasubu_vx_d, 8) /* Vector Single-Width Fractional Multiply with Rounding and Saturation */ static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) @@ -2527,19 +2762,19 @@ RVVCALL(OPIVV2_RM, vsmul_vv_b, OP_SSS_B, H1, H1, H1, vsmul8) RVVCALL(OPIVV2_RM, vsmul_vv_h, OP_SSS_H, H2, H2, H2, vsmul16) RVVCALL(OPIVV2_RM, vsmul_vv_w, OP_SSS_W, H4, H4, H4, vsmul32) RVVCALL(OPIVV2_RM, vsmul_vv_d, OP_SSS_D, H8, H8, H8, vsmul64) -GEN_VEXT_VV_RM(vsmul_vv_b, 1, 1) -GEN_VEXT_VV_RM(vsmul_vv_h, 2, 2) -GEN_VEXT_VV_RM(vsmul_vv_w, 4, 4) -GEN_VEXT_VV_RM(vsmul_vv_d, 8, 8) +GEN_VEXT_VV_RM(vsmul_vv_b, 1) +GEN_VEXT_VV_RM(vsmul_vv_h, 2) +GEN_VEXT_VV_RM(vsmul_vv_w, 4) +GEN_VEXT_VV_RM(vsmul_vv_d, 8) RVVCALL(OPIVX2_RM, vsmul_vx_b, OP_SSS_B, H1, H1, vsmul8) RVVCALL(OPIVX2_RM, vsmul_vx_h, OP_SSS_H, H2, H2, vsmul16) RVVCALL(OPIVX2_RM, vsmul_vx_w, OP_SSS_W, H4, H4, vsmul32) RVVCALL(OPIVX2_RM, vsmul_vx_d, OP_SSS_D, H8, H8, vsmul64) -GEN_VEXT_VX_RM(vsmul_vx_b, 1, 1) -GEN_VEXT_VX_RM(vsmul_vx_h, 2, 2) -GEN_VEXT_VX_RM(vsmul_vx_w, 4, 4) -GEN_VEXT_VX_RM(vsmul_vx_d, 8, 8) +GEN_VEXT_VX_RM(vsmul_vx_b, 1) +GEN_VEXT_VX_RM(vsmul_vx_h, 2) +GEN_VEXT_VX_RM(vsmul_vx_w, 4) +GEN_VEXT_VX_RM(vsmul_vx_d, 8) /* Vector Single-Width Scaling Shift Instructions */ static inline uint8_t @@ -2556,108 +2791,94 @@ static inline uint16_t vssrl16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b) { uint8_t round, shift = b & 0xf; - uint16_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } static inline uint32_t vssrl32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) { uint8_t round, shift = b & 0x1f; - uint32_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } static inline uint64_t vssrl64(CPURISCVState *env, int vxrm, uint64_t a, uint64_t b) { uint8_t round, shift = b & 0x3f; - uint64_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } RVVCALL(OPIVV2_RM, vssrl_vv_b, OP_UUU_B, H1, H1, H1, vssrl8) RVVCALL(OPIVV2_RM, vssrl_vv_h, OP_UUU_H, H2, H2, H2, vssrl16) RVVCALL(OPIVV2_RM, vssrl_vv_w, OP_UUU_W, H4, H4, H4, vssrl32) RVVCALL(OPIVV2_RM, vssrl_vv_d, OP_UUU_D, H8, H8, H8, vssrl64) -GEN_VEXT_VV_RM(vssrl_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssrl_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssrl_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssrl_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssrl_vv_b, 1) +GEN_VEXT_VV_RM(vssrl_vv_h, 2) +GEN_VEXT_VV_RM(vssrl_vv_w, 4) +GEN_VEXT_VV_RM(vssrl_vv_d, 8) RVVCALL(OPIVX2_RM, vssrl_vx_b, OP_UUU_B, H1, H1, vssrl8) RVVCALL(OPIVX2_RM, vssrl_vx_h, OP_UUU_H, H2, H2, vssrl16) RVVCALL(OPIVX2_RM, vssrl_vx_w, OP_UUU_W, H4, H4, vssrl32) RVVCALL(OPIVX2_RM, vssrl_vx_d, OP_UUU_D, H8, H8, vssrl64) -GEN_VEXT_VX_RM(vssrl_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssrl_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssrl_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssrl_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssrl_vx_b, 1) +GEN_VEXT_VX_RM(vssrl_vx_h, 2) +GEN_VEXT_VX_RM(vssrl_vx_w, 4) +GEN_VEXT_VX_RM(vssrl_vx_d, 8) static inline int8_t vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { uint8_t round, shift = b & 0x7; - int8_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } static inline int16_t vssra16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) { uint8_t round, shift = b & 0xf; - int16_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } static inline int32_t vssra32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) { uint8_t round, shift = b & 0x1f; - int32_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } static inline int64_t vssra64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) { uint8_t round, shift = b & 0x3f; - int64_t res; round = get_round(vxrm, a, shift); - res = (a >> shift) + round; - return res; + return (a >> shift) + round; } RVVCALL(OPIVV2_RM, vssra_vv_b, OP_SSS_B, H1, H1, H1, vssra8) RVVCALL(OPIVV2_RM, vssra_vv_h, OP_SSS_H, H2, H2, H2, vssra16) RVVCALL(OPIVV2_RM, vssra_vv_w, OP_SSS_W, H4, H4, H4, vssra32) RVVCALL(OPIVV2_RM, vssra_vv_d, OP_SSS_D, H8, H8, H8, vssra64) -GEN_VEXT_VV_RM(vssra_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssra_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssra_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssra_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssra_vv_b, 1) +GEN_VEXT_VV_RM(vssra_vv_h, 2) +GEN_VEXT_VV_RM(vssra_vv_w, 4) +GEN_VEXT_VV_RM(vssra_vv_d, 8) RVVCALL(OPIVX2_RM, vssra_vx_b, OP_SSS_B, H1, H1, vssra8) RVVCALL(OPIVX2_RM, vssra_vx_h, OP_SSS_H, H2, H2, vssra16) RVVCALL(OPIVX2_RM, vssra_vx_w, OP_SSS_W, H4, H4, vssra32) RVVCALL(OPIVX2_RM, vssra_vx_d, OP_SSS_D, H8, H8, vssra64) -GEN_VEXT_VX_RM(vssra_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssra_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssra_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssra_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssra_vx_b, 1) +GEN_VEXT_VX_RM(vssra_vx_h, 2) +GEN_VEXT_VX_RM(vssra_vx_w, 4) +GEN_VEXT_VX_RM(vssra_vx_d, 8) /* Vector Narrowing Fixed-Point Clip Instructions */ static inline int8_t @@ -2720,16 +2941,16 @@ vnclip32(CPURISCVState *env, int vxrm, int64_t a, int32_t b) RVVCALL(OPIVV2_RM, vnclip_wv_b, NOP_SSS_B, H1, H2, H1, vnclip8) RVVCALL(OPIVV2_RM, vnclip_wv_h, NOP_SSS_H, H2, H4, H2, vnclip16) RVVCALL(OPIVV2_RM, vnclip_wv_w, NOP_SSS_W, H4, H8, H4, vnclip32) -GEN_VEXT_VV_RM(vnclip_wv_b, 1, 1) -GEN_VEXT_VV_RM(vnclip_wv_h, 2, 2) -GEN_VEXT_VV_RM(vnclip_wv_w, 4, 4) +GEN_VEXT_VV_RM(vnclip_wv_b, 1) +GEN_VEXT_VV_RM(vnclip_wv_h, 2) +GEN_VEXT_VV_RM(vnclip_wv_w, 4) RVVCALL(OPIVX2_RM, vnclip_wx_b, NOP_SSS_B, H1, H2, vnclip8) RVVCALL(OPIVX2_RM, vnclip_wx_h, NOP_SSS_H, H2, H4, vnclip16) RVVCALL(OPIVX2_RM, vnclip_wx_w, NOP_SSS_W, H4, H8, vnclip32) -GEN_VEXT_VX_RM(vnclip_wx_b, 1, 1) -GEN_VEXT_VX_RM(vnclip_wx_h, 2, 2) -GEN_VEXT_VX_RM(vnclip_wx_w, 4, 4) +GEN_VEXT_VX_RM(vnclip_wx_b, 1) +GEN_VEXT_VX_RM(vnclip_wx_h, 2) +GEN_VEXT_VX_RM(vnclip_wx_w, 4) static inline uint8_t vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b) @@ -2782,16 +3003,16 @@ vnclipu32(CPURISCVState *env, int vxrm, uint64_t a, uint32_t b) RVVCALL(OPIVV2_RM, vnclipu_wv_b, NOP_UUU_B, H1, H2, H1, vnclipu8) RVVCALL(OPIVV2_RM, vnclipu_wv_h, NOP_UUU_H, H2, H4, H2, vnclipu16) RVVCALL(OPIVV2_RM, vnclipu_wv_w, NOP_UUU_W, H4, H8, H4, vnclipu32) -GEN_VEXT_VV_RM(vnclipu_wv_b, 1, 1) -GEN_VEXT_VV_RM(vnclipu_wv_h, 2, 2) -GEN_VEXT_VV_RM(vnclipu_wv_w, 4, 4) +GEN_VEXT_VV_RM(vnclipu_wv_b, 1) +GEN_VEXT_VV_RM(vnclipu_wv_h, 2) +GEN_VEXT_VV_RM(vnclipu_wv_w, 4) RVVCALL(OPIVX2_RM, vnclipu_wx_b, NOP_UUU_B, H1, H2, vnclipu8) RVVCALL(OPIVX2_RM, vnclipu_wx_h, NOP_UUU_H, H2, H4, vnclipu16) RVVCALL(OPIVX2_RM, vnclipu_wx_w, NOP_UUU_W, H4, H8, vnclipu32) -GEN_VEXT_VX_RM(vnclipu_wx_b, 1, 1) -GEN_VEXT_VX_RM(vnclipu_wx_h, 2, 2) -GEN_VEXT_VX_RM(vnclipu_wx_w, 4, 4) +GEN_VEXT_VX_RM(vnclipu_wx_b, 1) +GEN_VEXT_VX_RM(vnclipu_wx_h, 2) +GEN_VEXT_VX_RM(vnclipu_wx_w, 4) /* *** Vector Float Point Arithmetic Instructions @@ -2806,30 +3027,40 @@ static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, s1, &env->fp_status); \ } -#define GEN_VEXT_VV_ENV(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VV_ENV(NAME, ESZ) \ void HELPER(NAME)(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 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); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } RVVCALL(OPFVV2, vfadd_vv_h, OP_UUU_H, H2, H2, H2, float16_add) RVVCALL(OPFVV2, vfadd_vv_w, OP_UUU_W, H4, H4, H4, float32_add) RVVCALL(OPFVV2, vfadd_vv_d, OP_UUU_D, H8, H8, H8, float64_add) -GEN_VEXT_VV_ENV(vfadd_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfadd_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfadd_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfadd_vv_h, 2) +GEN_VEXT_VV_ENV(vfadd_vv_w, 4) +GEN_VEXT_VV_ENV(vfadd_vv_d, 8) #define OPFVF2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ @@ -2839,43 +3070,53 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, &env->fp_status);\ } -#define GEN_VEXT_VF(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VF(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ 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; \ } \ do_##NAME(vd, s1, vs2, i, env); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } RVVCALL(OPFVF2, vfadd_vf_h, OP_UUU_H, H2, H2, float16_add) RVVCALL(OPFVF2, vfadd_vf_w, OP_UUU_W, H4, H4, float32_add) RVVCALL(OPFVF2, vfadd_vf_d, OP_UUU_D, H8, H8, float64_add) -GEN_VEXT_VF(vfadd_vf_h, 2, 2) -GEN_VEXT_VF(vfadd_vf_w, 4, 4) -GEN_VEXT_VF(vfadd_vf_d, 8, 8) +GEN_VEXT_VF(vfadd_vf_h, 2) +GEN_VEXT_VF(vfadd_vf_w, 4) +GEN_VEXT_VF(vfadd_vf_d, 8) RVVCALL(OPFVV2, vfsub_vv_h, OP_UUU_H, H2, H2, H2, float16_sub) RVVCALL(OPFVV2, vfsub_vv_w, OP_UUU_W, H4, H4, H4, float32_sub) RVVCALL(OPFVV2, vfsub_vv_d, OP_UUU_D, H8, H8, H8, float64_sub) -GEN_VEXT_VV_ENV(vfsub_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsub_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsub_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsub_vv_h, 2) +GEN_VEXT_VV_ENV(vfsub_vv_w, 4) +GEN_VEXT_VV_ENV(vfsub_vv_d, 8) RVVCALL(OPFVF2, vfsub_vf_h, OP_UUU_H, H2, H2, float16_sub) RVVCALL(OPFVF2, vfsub_vf_w, OP_UUU_W, H4, H4, float32_sub) RVVCALL(OPFVF2, vfsub_vf_d, OP_UUU_D, H8, H8, float64_sub) -GEN_VEXT_VF(vfsub_vf_h, 2, 2) -GEN_VEXT_VF(vfsub_vf_w, 4, 4) -GEN_VEXT_VF(vfsub_vf_d, 8, 8) +GEN_VEXT_VF(vfsub_vf_h, 2) +GEN_VEXT_VF(vfsub_vf_w, 4) +GEN_VEXT_VF(vfsub_vf_d, 8) static uint16_t float16_rsub(uint16_t a, uint16_t b, float_status *s) { @@ -2895,9 +3136,9 @@ static uint64_t float64_rsub(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVF2, vfrsub_vf_h, OP_UUU_H, H2, H2, float16_rsub) RVVCALL(OPFVF2, vfrsub_vf_w, OP_UUU_W, H4, H4, float32_rsub) RVVCALL(OPFVF2, vfrsub_vf_d, OP_UUU_D, H8, H8, float64_rsub) -GEN_VEXT_VF(vfrsub_vf_h, 2, 2) -GEN_VEXT_VF(vfrsub_vf_w, 4, 4) -GEN_VEXT_VF(vfrsub_vf_d, 8, 8) +GEN_VEXT_VF(vfrsub_vf_h, 2) +GEN_VEXT_VF(vfrsub_vf_w, 4) +GEN_VEXT_VF(vfrsub_vf_d, 8) /* Vector Widening Floating-Point Add/Subtract Instructions */ static uint32_t vfwadd16(uint16_t a, uint16_t b, float_status *s) @@ -2915,12 +3156,12 @@ static uint64_t vfwadd32(uint32_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwadd_vv_h, WOP_UUU_H, H4, H2, H2, vfwadd16) RVVCALL(OPFVV2, vfwadd_vv_w, WOP_UUU_W, H8, H4, H4, vfwadd32) -GEN_VEXT_VV_ENV(vfwadd_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwadd_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwadd_vv_h, 4) +GEN_VEXT_VV_ENV(vfwadd_vv_w, 8) RVVCALL(OPFVF2, vfwadd_vf_h, WOP_UUU_H, H4, H2, vfwadd16) RVVCALL(OPFVF2, vfwadd_vf_w, WOP_UUU_W, H8, H4, vfwadd32) -GEN_VEXT_VF(vfwadd_vf_h, 2, 4) -GEN_VEXT_VF(vfwadd_vf_w, 4, 8) +GEN_VEXT_VF(vfwadd_vf_h, 4) +GEN_VEXT_VF(vfwadd_vf_w, 8) static uint32_t vfwsub16(uint16_t a, uint16_t b, float_status *s) { @@ -2937,12 +3178,12 @@ static uint64_t vfwsub32(uint32_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwsub_vv_h, WOP_UUU_H, H4, H2, H2, vfwsub16) RVVCALL(OPFVV2, vfwsub_vv_w, WOP_UUU_W, H8, H4, H4, vfwsub32) -GEN_VEXT_VV_ENV(vfwsub_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwsub_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwsub_vv_h, 4) +GEN_VEXT_VV_ENV(vfwsub_vv_w, 8) RVVCALL(OPFVF2, vfwsub_vf_h, WOP_UUU_H, H4, H2, vfwsub16) RVVCALL(OPFVF2, vfwsub_vf_w, WOP_UUU_W, H8, H4, vfwsub32) -GEN_VEXT_VF(vfwsub_vf_h, 2, 4) -GEN_VEXT_VF(vfwsub_vf_w, 4, 8) +GEN_VEXT_VF(vfwsub_vf_h, 4) +GEN_VEXT_VF(vfwsub_vf_w, 8) static uint32_t vfwaddw16(uint32_t a, uint16_t b, float_status *s) { @@ -2956,12 +3197,12 @@ static uint64_t vfwaddw32(uint64_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwadd_wv_h, WOP_WUUU_H, H4, H2, H2, vfwaddw16) RVVCALL(OPFVV2, vfwadd_wv_w, WOP_WUUU_W, H8, H4, H4, vfwaddw32) -GEN_VEXT_VV_ENV(vfwadd_wv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwadd_wv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwadd_wv_h, 4) +GEN_VEXT_VV_ENV(vfwadd_wv_w, 8) RVVCALL(OPFVF2, vfwadd_wf_h, WOP_WUUU_H, H4, H2, vfwaddw16) RVVCALL(OPFVF2, vfwadd_wf_w, WOP_WUUU_W, H8, H4, vfwaddw32) -GEN_VEXT_VF(vfwadd_wf_h, 2, 4) -GEN_VEXT_VF(vfwadd_wf_w, 4, 8) +GEN_VEXT_VF(vfwadd_wf_h, 4) +GEN_VEXT_VF(vfwadd_wf_w, 8) static uint32_t vfwsubw16(uint32_t a, uint16_t b, float_status *s) { @@ -2975,39 +3216,39 @@ static uint64_t vfwsubw32(uint64_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwsub_wv_h, WOP_WUUU_H, H4, H2, H2, vfwsubw16) RVVCALL(OPFVV2, vfwsub_wv_w, WOP_WUUU_W, H8, H4, H4, vfwsubw32) -GEN_VEXT_VV_ENV(vfwsub_wv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwsub_wv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwsub_wv_h, 4) +GEN_VEXT_VV_ENV(vfwsub_wv_w, 8) RVVCALL(OPFVF2, vfwsub_wf_h, WOP_WUUU_H, H4, H2, vfwsubw16) RVVCALL(OPFVF2, vfwsub_wf_w, WOP_WUUU_W, H8, H4, vfwsubw32) -GEN_VEXT_VF(vfwsub_wf_h, 2, 4) -GEN_VEXT_VF(vfwsub_wf_w, 4, 8) +GEN_VEXT_VF(vfwsub_wf_h, 4) +GEN_VEXT_VF(vfwsub_wf_w, 8) /* Vector Single-Width Floating-Point Multiply/Divide Instructions */ RVVCALL(OPFVV2, vfmul_vv_h, OP_UUU_H, H2, H2, H2, float16_mul) RVVCALL(OPFVV2, vfmul_vv_w, OP_UUU_W, H4, H4, H4, float32_mul) RVVCALL(OPFVV2, vfmul_vv_d, OP_UUU_D, H8, H8, H8, float64_mul) -GEN_VEXT_VV_ENV(vfmul_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmul_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmul_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmul_vv_h, 2) +GEN_VEXT_VV_ENV(vfmul_vv_w, 4) +GEN_VEXT_VV_ENV(vfmul_vv_d, 8) RVVCALL(OPFVF2, vfmul_vf_h, OP_UUU_H, H2, H2, float16_mul) RVVCALL(OPFVF2, vfmul_vf_w, OP_UUU_W, H4, H4, float32_mul) RVVCALL(OPFVF2, vfmul_vf_d, OP_UUU_D, H8, H8, float64_mul) -GEN_VEXT_VF(vfmul_vf_h, 2, 2) -GEN_VEXT_VF(vfmul_vf_w, 4, 4) -GEN_VEXT_VF(vfmul_vf_d, 8, 8) +GEN_VEXT_VF(vfmul_vf_h, 2) +GEN_VEXT_VF(vfmul_vf_w, 4) +GEN_VEXT_VF(vfmul_vf_d, 8) RVVCALL(OPFVV2, vfdiv_vv_h, OP_UUU_H, H2, H2, H2, float16_div) RVVCALL(OPFVV2, vfdiv_vv_w, OP_UUU_W, H4, H4, H4, float32_div) RVVCALL(OPFVV2, vfdiv_vv_d, OP_UUU_D, H8, H8, H8, float64_div) -GEN_VEXT_VV_ENV(vfdiv_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfdiv_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfdiv_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfdiv_vv_h, 2) +GEN_VEXT_VV_ENV(vfdiv_vv_w, 4) +GEN_VEXT_VV_ENV(vfdiv_vv_d, 8) RVVCALL(OPFVF2, vfdiv_vf_h, OP_UUU_H, H2, H2, float16_div) RVVCALL(OPFVF2, vfdiv_vf_w, OP_UUU_W, H4, H4, float32_div) RVVCALL(OPFVF2, vfdiv_vf_d, OP_UUU_D, H8, H8, float64_div) -GEN_VEXT_VF(vfdiv_vf_h, 2, 2) -GEN_VEXT_VF(vfdiv_vf_w, 4, 4) -GEN_VEXT_VF(vfdiv_vf_d, 8, 8) +GEN_VEXT_VF(vfdiv_vf_h, 2) +GEN_VEXT_VF(vfdiv_vf_w, 4) +GEN_VEXT_VF(vfdiv_vf_d, 8) static uint16_t float16_rdiv(uint16_t a, uint16_t b, float_status *s) { @@ -3027,9 +3268,9 @@ static uint64_t float64_rdiv(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVF2, vfrdiv_vf_h, OP_UUU_H, H2, H2, float16_rdiv) RVVCALL(OPFVF2, vfrdiv_vf_w, OP_UUU_W, H4, H4, float32_rdiv) RVVCALL(OPFVF2, vfrdiv_vf_d, OP_UUU_D, H8, H8, float64_rdiv) -GEN_VEXT_VF(vfrdiv_vf_h, 2, 2) -GEN_VEXT_VF(vfrdiv_vf_w, 4, 4) -GEN_VEXT_VF(vfrdiv_vf_d, 8, 8) +GEN_VEXT_VF(vfrdiv_vf_h, 2) +GEN_VEXT_VF(vfrdiv_vf_w, 4) +GEN_VEXT_VF(vfrdiv_vf_d, 8) /* Vector Widening Floating-Point Multiply */ static uint32_t vfwmul16(uint16_t a, uint16_t b, float_status *s) @@ -3046,12 +3287,12 @@ static uint64_t vfwmul32(uint32_t a, uint32_t b, float_status *s) } RVVCALL(OPFVV2, vfwmul_vv_h, WOP_UUU_H, H4, H2, H2, vfwmul16) RVVCALL(OPFVV2, vfwmul_vv_w, WOP_UUU_W, H8, H4, H4, vfwmul32) -GEN_VEXT_VV_ENV(vfwmul_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwmul_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwmul_vv_h, 4) +GEN_VEXT_VV_ENV(vfwmul_vv_w, 8) RVVCALL(OPFVF2, vfwmul_vf_h, WOP_UUU_H, H4, H2, vfwmul16) RVVCALL(OPFVF2, vfwmul_vf_w, WOP_UUU_W, H8, H4, vfwmul32) -GEN_VEXT_VF(vfwmul_vf_h, 2, 4) -GEN_VEXT_VF(vfwmul_vf_w, 4, 8) +GEN_VEXT_VF(vfwmul_vf_h, 4) +GEN_VEXT_VF(vfwmul_vf_w, 8) /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ #define OPFVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ @@ -3082,9 +3323,9 @@ static uint64_t fmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmacc_vv_h, OP_UUU_H, H2, H2, H2, fmacc16) RVVCALL(OPFVV3, vfmacc_vv_w, OP_UUU_W, H4, H4, H4, fmacc32) RVVCALL(OPFVV3, vfmacc_vv_d, OP_UUU_D, H8, H8, H8, fmacc64) -GEN_VEXT_VV_ENV(vfmacc_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmacc_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmacc_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmacc_vv_h, 2) +GEN_VEXT_VV_ENV(vfmacc_vv_w, 4) +GEN_VEXT_VV_ENV(vfmacc_vv_d, 8) #define OPFVF3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ @@ -3098,9 +3339,9 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ RVVCALL(OPFVF3, vfmacc_vf_h, OP_UUU_H, H2, H2, fmacc16) RVVCALL(OPFVF3, vfmacc_vf_w, OP_UUU_W, H4, H4, fmacc32) RVVCALL(OPFVF3, vfmacc_vf_d, OP_UUU_D, H8, H8, fmacc64) -GEN_VEXT_VF(vfmacc_vf_h, 2, 2) -GEN_VEXT_VF(vfmacc_vf_w, 4, 4) -GEN_VEXT_VF(vfmacc_vf_d, 8, 8) +GEN_VEXT_VF(vfmacc_vf_h, 2) +GEN_VEXT_VF(vfmacc_vf_w, 4) +GEN_VEXT_VF(vfmacc_vf_d, 8) static uint16_t fnmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3123,15 +3364,15 @@ static uint64_t fnmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmacc_vv_h, OP_UUU_H, H2, H2, H2, fnmacc16) RVVCALL(OPFVV3, vfnmacc_vv_w, OP_UUU_W, H4, H4, H4, fnmacc32) RVVCALL(OPFVV3, vfnmacc_vv_d, OP_UUU_D, H8, H8, H8, fnmacc64) -GEN_VEXT_VV_ENV(vfnmacc_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmacc_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmacc_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmacc_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmacc_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmacc_vv_d, 8) RVVCALL(OPFVF3, vfnmacc_vf_h, OP_UUU_H, H2, H2, fnmacc16) RVVCALL(OPFVF3, vfnmacc_vf_w, OP_UUU_W, H4, H4, fnmacc32) RVVCALL(OPFVF3, vfnmacc_vf_d, OP_UUU_D, H8, H8, fnmacc64) -GEN_VEXT_VF(vfnmacc_vf_h, 2, 2) -GEN_VEXT_VF(vfnmacc_vf_w, 4, 4) -GEN_VEXT_VF(vfnmacc_vf_d, 8, 8) +GEN_VEXT_VF(vfnmacc_vf_h, 2) +GEN_VEXT_VF(vfnmacc_vf_w, 4) +GEN_VEXT_VF(vfnmacc_vf_d, 8) static uint16_t fmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3151,15 +3392,15 @@ static uint64_t fmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmsac_vv_h, OP_UUU_H, H2, H2, H2, fmsac16) RVVCALL(OPFVV3, vfmsac_vv_w, OP_UUU_W, H4, H4, H4, fmsac32) RVVCALL(OPFVV3, vfmsac_vv_d, OP_UUU_D, H8, H8, H8, fmsac64) -GEN_VEXT_VV_ENV(vfmsac_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmsac_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmsac_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmsac_vv_h, 2) +GEN_VEXT_VV_ENV(vfmsac_vv_w, 4) +GEN_VEXT_VV_ENV(vfmsac_vv_d, 8) RVVCALL(OPFVF3, vfmsac_vf_h, OP_UUU_H, H2, H2, fmsac16) RVVCALL(OPFVF3, vfmsac_vf_w, OP_UUU_W, H4, H4, fmsac32) RVVCALL(OPFVF3, vfmsac_vf_d, OP_UUU_D, H8, H8, fmsac64) -GEN_VEXT_VF(vfmsac_vf_h, 2, 2) -GEN_VEXT_VF(vfmsac_vf_w, 4, 4) -GEN_VEXT_VF(vfmsac_vf_d, 8, 8) +GEN_VEXT_VF(vfmsac_vf_h, 2) +GEN_VEXT_VF(vfmsac_vf_w, 4) +GEN_VEXT_VF(vfmsac_vf_d, 8) static uint16_t fnmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3179,15 +3420,15 @@ static uint64_t fnmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmsac_vv_h, OP_UUU_H, H2, H2, H2, fnmsac16) RVVCALL(OPFVV3, vfnmsac_vv_w, OP_UUU_W, H4, H4, H4, fnmsac32) RVVCALL(OPFVV3, vfnmsac_vv_d, OP_UUU_D, H8, H8, H8, fnmsac64) -GEN_VEXT_VV_ENV(vfnmsac_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmsac_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmsac_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmsac_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmsac_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmsac_vv_d, 8) RVVCALL(OPFVF3, vfnmsac_vf_h, OP_UUU_H, H2, H2, fnmsac16) RVVCALL(OPFVF3, vfnmsac_vf_w, OP_UUU_W, H4, H4, fnmsac32) RVVCALL(OPFVF3, vfnmsac_vf_d, OP_UUU_D, H8, H8, fnmsac64) -GEN_VEXT_VF(vfnmsac_vf_h, 2, 2) -GEN_VEXT_VF(vfnmsac_vf_w, 4, 4) -GEN_VEXT_VF(vfnmsac_vf_d, 8, 8) +GEN_VEXT_VF(vfnmsac_vf_h, 2) +GEN_VEXT_VF(vfnmsac_vf_w, 4) +GEN_VEXT_VF(vfnmsac_vf_d, 8) static uint16_t fmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3207,15 +3448,15 @@ static uint64_t fmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmadd_vv_h, OP_UUU_H, H2, H2, H2, fmadd16) RVVCALL(OPFVV3, vfmadd_vv_w, OP_UUU_W, H4, H4, H4, fmadd32) RVVCALL(OPFVV3, vfmadd_vv_d, OP_UUU_D, H8, H8, H8, fmadd64) -GEN_VEXT_VV_ENV(vfmadd_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmadd_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmadd_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmadd_vv_h, 2) +GEN_VEXT_VV_ENV(vfmadd_vv_w, 4) +GEN_VEXT_VV_ENV(vfmadd_vv_d, 8) RVVCALL(OPFVF3, vfmadd_vf_h, OP_UUU_H, H2, H2, fmadd16) RVVCALL(OPFVF3, vfmadd_vf_w, OP_UUU_W, H4, H4, fmadd32) RVVCALL(OPFVF3, vfmadd_vf_d, OP_UUU_D, H8, H8, fmadd64) -GEN_VEXT_VF(vfmadd_vf_h, 2, 2) -GEN_VEXT_VF(vfmadd_vf_w, 4, 4) -GEN_VEXT_VF(vfmadd_vf_d, 8, 8) +GEN_VEXT_VF(vfmadd_vf_h, 2) +GEN_VEXT_VF(vfmadd_vf_w, 4) +GEN_VEXT_VF(vfmadd_vf_d, 8) static uint16_t fnmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3238,15 +3479,15 @@ static uint64_t fnmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmadd_vv_h, OP_UUU_H, H2, H2, H2, fnmadd16) RVVCALL(OPFVV3, vfnmadd_vv_w, OP_UUU_W, H4, H4, H4, fnmadd32) RVVCALL(OPFVV3, vfnmadd_vv_d, OP_UUU_D, H8, H8, H8, fnmadd64) -GEN_VEXT_VV_ENV(vfnmadd_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmadd_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmadd_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmadd_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmadd_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmadd_vv_d, 8) RVVCALL(OPFVF3, vfnmadd_vf_h, OP_UUU_H, H2, H2, fnmadd16) RVVCALL(OPFVF3, vfnmadd_vf_w, OP_UUU_W, H4, H4, fnmadd32) RVVCALL(OPFVF3, vfnmadd_vf_d, OP_UUU_D, H8, H8, fnmadd64) -GEN_VEXT_VF(vfnmadd_vf_h, 2, 2) -GEN_VEXT_VF(vfnmadd_vf_w, 4, 4) -GEN_VEXT_VF(vfnmadd_vf_d, 8, 8) +GEN_VEXT_VF(vfnmadd_vf_h, 2) +GEN_VEXT_VF(vfnmadd_vf_w, 4) +GEN_VEXT_VF(vfnmadd_vf_d, 8) static uint16_t fmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3266,15 +3507,15 @@ static uint64_t fmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmsub_vv_h, OP_UUU_H, H2, H2, H2, fmsub16) RVVCALL(OPFVV3, vfmsub_vv_w, OP_UUU_W, H4, H4, H4, fmsub32) RVVCALL(OPFVV3, vfmsub_vv_d, OP_UUU_D, H8, H8, H8, fmsub64) -GEN_VEXT_VV_ENV(vfmsub_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmsub_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmsub_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmsub_vv_h, 2) +GEN_VEXT_VV_ENV(vfmsub_vv_w, 4) +GEN_VEXT_VV_ENV(vfmsub_vv_d, 8) RVVCALL(OPFVF3, vfmsub_vf_h, OP_UUU_H, H2, H2, fmsub16) RVVCALL(OPFVF3, vfmsub_vf_w, OP_UUU_W, H4, H4, fmsub32) RVVCALL(OPFVF3, vfmsub_vf_d, OP_UUU_D, H8, H8, fmsub64) -GEN_VEXT_VF(vfmsub_vf_h, 2, 2) -GEN_VEXT_VF(vfmsub_vf_w, 4, 4) -GEN_VEXT_VF(vfmsub_vf_d, 8, 8) +GEN_VEXT_VF(vfmsub_vf_h, 2) +GEN_VEXT_VF(vfmsub_vf_w, 4) +GEN_VEXT_VF(vfmsub_vf_d, 8) static uint16_t fnmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3294,15 +3535,15 @@ static uint64_t fnmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmsub_vv_h, OP_UUU_H, H2, H2, H2, fnmsub16) RVVCALL(OPFVV3, vfnmsub_vv_w, OP_UUU_W, H4, H4, H4, fnmsub32) RVVCALL(OPFVV3, vfnmsub_vv_d, OP_UUU_D, H8, H8, H8, fnmsub64) -GEN_VEXT_VV_ENV(vfnmsub_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmsub_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmsub_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmsub_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmsub_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmsub_vv_d, 8) RVVCALL(OPFVF3, vfnmsub_vf_h, OP_UUU_H, H2, H2, fnmsub16) RVVCALL(OPFVF3, vfnmsub_vf_w, OP_UUU_W, H4, H4, fnmsub32) RVVCALL(OPFVF3, vfnmsub_vf_d, OP_UUU_D, H8, H8, fnmsub64) -GEN_VEXT_VF(vfnmsub_vf_h, 2, 2) -GEN_VEXT_VF(vfnmsub_vf_w, 4, 4) -GEN_VEXT_VF(vfnmsub_vf_d, 8, 8) +GEN_VEXT_VF(vfnmsub_vf_h, 2) +GEN_VEXT_VF(vfnmsub_vf_w, 4) +GEN_VEXT_VF(vfnmsub_vf_d, 8) /* Vector Widening Floating-Point Fused Multiply-Add Instructions */ static uint32_t fwmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) @@ -3319,12 +3560,12 @@ static uint64_t fwmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwmacc16) RVVCALL(OPFVV3, vfwmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwmacc32) -GEN_VEXT_VV_ENV(vfwmacc_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwmacc_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwmacc_vv_h, 4) +GEN_VEXT_VV_ENV(vfwmacc_vv_w, 8) RVVCALL(OPFVF3, vfwmacc_vf_h, WOP_UUU_H, H4, H2, fwmacc16) RVVCALL(OPFVF3, vfwmacc_vf_w, WOP_UUU_W, H8, H4, fwmacc32) -GEN_VEXT_VF(vfwmacc_vf_h, 2, 4) -GEN_VEXT_VF(vfwmacc_vf_w, 4, 8) +GEN_VEXT_VF(vfwmacc_vf_h, 4) +GEN_VEXT_VF(vfwmacc_vf_w, 8) static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3342,12 +3583,12 @@ static uint64_t fwnmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwnmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwnmacc16) RVVCALL(OPFVV3, vfwnmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwnmacc32) -GEN_VEXT_VV_ENV(vfwnmacc_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwnmacc_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwnmacc_vv_h, 4) +GEN_VEXT_VV_ENV(vfwnmacc_vv_w, 8) RVVCALL(OPFVF3, vfwnmacc_vf_h, WOP_UUU_H, H4, H2, fwnmacc16) RVVCALL(OPFVF3, vfwnmacc_vf_w, WOP_UUU_W, H8, H4, fwnmacc32) -GEN_VEXT_VF(vfwnmacc_vf_h, 2, 4) -GEN_VEXT_VF(vfwnmacc_vf_w, 4, 8) +GEN_VEXT_VF(vfwnmacc_vf_h, 4) +GEN_VEXT_VF(vfwnmacc_vf_w, 8) static uint32_t fwmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3365,12 +3606,12 @@ static uint64_t fwmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwmsac16) RVVCALL(OPFVV3, vfwmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwmsac32) -GEN_VEXT_VV_ENV(vfwmsac_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwmsac_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwmsac_vv_h, 4) +GEN_VEXT_VV_ENV(vfwmsac_vv_w, 8) RVVCALL(OPFVF3, vfwmsac_vf_h, WOP_UUU_H, H4, H2, fwmsac16) RVVCALL(OPFVF3, vfwmsac_vf_w, WOP_UUU_W, H8, H4, fwmsac32) -GEN_VEXT_VF(vfwmsac_vf_h, 2, 4) -GEN_VEXT_VF(vfwmsac_vf_w, 4, 8) +GEN_VEXT_VF(vfwmsac_vf_h, 4) +GEN_VEXT_VF(vfwmsac_vf_w, 8) static uint32_t fwnmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3388,12 +3629,12 @@ static uint64_t fwnmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwnmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwnmsac16) RVVCALL(OPFVV3, vfwnmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwnmsac32) -GEN_VEXT_VV_ENV(vfwnmsac_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwnmsac_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwnmsac_vv_h, 4) +GEN_VEXT_VV_ENV(vfwnmsac_vv_w, 8) RVVCALL(OPFVF3, vfwnmsac_vf_h, WOP_UUU_H, H4, H2, fwnmsac16) RVVCALL(OPFVF3, vfwnmsac_vf_w, WOP_UUU_W, H8, H4, fwnmsac32) -GEN_VEXT_VF(vfwnmsac_vf_h, 2, 4) -GEN_VEXT_VF(vfwnmsac_vf_w, 4, 8) +GEN_VEXT_VF(vfwnmsac_vf_h, 4) +GEN_VEXT_VF(vfwnmsac_vf_w, 8) /* Vector Floating-Point Square-Root Instruction */ /* (TD, T2, TX2) */ @@ -3409,12 +3650,16 @@ static void do_##NAME(void *vd, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, &env->fp_status); \ } -#define GEN_VEXT_V_ENV(NAME, ESZ, DSZ) \ +#define GEN_VEXT_V_ENV(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ 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; \ \ if (vl == 0) { \ @@ -3422,19 +3667,24 @@ 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); \ } \ env->vstart = 0; \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } RVVCALL(OPFVV1, vfsqrt_v_h, OP_UU_H, H2, H2, float16_sqrt) RVVCALL(OPFVV1, vfsqrt_v_w, OP_UU_W, H4, H4, float32_sqrt) RVVCALL(OPFVV1, vfsqrt_v_d, OP_UU_D, H8, H8, float64_sqrt) -GEN_VEXT_V_ENV(vfsqrt_v_h, 2, 2) -GEN_VEXT_V_ENV(vfsqrt_v_w, 4, 4) -GEN_VEXT_V_ENV(vfsqrt_v_d, 8, 8) +GEN_VEXT_V_ENV(vfsqrt_v_h, 2) +GEN_VEXT_V_ENV(vfsqrt_v_w, 4) +GEN_VEXT_V_ENV(vfsqrt_v_d, 8) /* * Vector Floating-Point Reciprocal Square-Root Estimate Instruction @@ -3614,9 +3864,9 @@ static float64 frsqrt7_d(float64 f, float_status *s) RVVCALL(OPFVV1, vfrsqrt7_v_h, OP_UU_H, H2, H2, frsqrt7_h) RVVCALL(OPFVV1, vfrsqrt7_v_w, OP_UU_W, H4, H4, frsqrt7_s) RVVCALL(OPFVV1, vfrsqrt7_v_d, OP_UU_D, H8, H8, frsqrt7_d) -GEN_VEXT_V_ENV(vfrsqrt7_v_h, 2, 2) -GEN_VEXT_V_ENV(vfrsqrt7_v_w, 4, 4) -GEN_VEXT_V_ENV(vfrsqrt7_v_d, 8, 8) +GEN_VEXT_V_ENV(vfrsqrt7_v_h, 2) +GEN_VEXT_V_ENV(vfrsqrt7_v_w, 4) +GEN_VEXT_V_ENV(vfrsqrt7_v_d, 8) /* * Vector Floating-Point Reciprocal Estimate Instruction @@ -3805,36 +4055,36 @@ static float64 frec7_d(float64 f, float_status *s) RVVCALL(OPFVV1, vfrec7_v_h, OP_UU_H, H2, H2, frec7_h) RVVCALL(OPFVV1, vfrec7_v_w, OP_UU_W, H4, H4, frec7_s) RVVCALL(OPFVV1, vfrec7_v_d, OP_UU_D, H8, H8, frec7_d) -GEN_VEXT_V_ENV(vfrec7_v_h, 2, 2) -GEN_VEXT_V_ENV(vfrec7_v_w, 4, 4) -GEN_VEXT_V_ENV(vfrec7_v_d, 8, 8) +GEN_VEXT_V_ENV(vfrec7_v_h, 2) +GEN_VEXT_V_ENV(vfrec7_v_w, 4) +GEN_VEXT_V_ENV(vfrec7_v_d, 8) /* Vector Floating-Point MIN/MAX Instructions */ RVVCALL(OPFVV2, vfmin_vv_h, OP_UUU_H, H2, H2, H2, float16_minimum_number) RVVCALL(OPFVV2, vfmin_vv_w, OP_UUU_W, H4, H4, H4, float32_minimum_number) RVVCALL(OPFVV2, vfmin_vv_d, OP_UUU_D, H8, H8, H8, float64_minimum_number) -GEN_VEXT_VV_ENV(vfmin_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmin_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmin_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmin_vv_h, 2) +GEN_VEXT_VV_ENV(vfmin_vv_w, 4) +GEN_VEXT_VV_ENV(vfmin_vv_d, 8) RVVCALL(OPFVF2, vfmin_vf_h, OP_UUU_H, H2, H2, float16_minimum_number) RVVCALL(OPFVF2, vfmin_vf_w, OP_UUU_W, H4, H4, float32_minimum_number) RVVCALL(OPFVF2, vfmin_vf_d, OP_UUU_D, H8, H8, float64_minimum_number) -GEN_VEXT_VF(vfmin_vf_h, 2, 2) -GEN_VEXT_VF(vfmin_vf_w, 4, 4) -GEN_VEXT_VF(vfmin_vf_d, 8, 8) +GEN_VEXT_VF(vfmin_vf_h, 2) +GEN_VEXT_VF(vfmin_vf_w, 4) +GEN_VEXT_VF(vfmin_vf_d, 8) RVVCALL(OPFVV2, vfmax_vv_h, OP_UUU_H, H2, H2, H2, float16_maximum_number) RVVCALL(OPFVV2, vfmax_vv_w, OP_UUU_W, H4, H4, H4, float32_maximum_number) RVVCALL(OPFVV2, vfmax_vv_d, OP_UUU_D, H8, H8, H8, float64_maximum_number) -GEN_VEXT_VV_ENV(vfmax_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmax_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmax_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmax_vv_h, 2) +GEN_VEXT_VV_ENV(vfmax_vv_w, 4) +GEN_VEXT_VV_ENV(vfmax_vv_d, 8) RVVCALL(OPFVF2, vfmax_vf_h, OP_UUU_H, H2, H2, float16_maximum_number) RVVCALL(OPFVF2, vfmax_vf_w, OP_UUU_W, H4, H4, float32_maximum_number) RVVCALL(OPFVF2, vfmax_vf_d, OP_UUU_D, H8, H8, float64_maximum_number) -GEN_VEXT_VF(vfmax_vf_h, 2, 2) -GEN_VEXT_VF(vfmax_vf_w, 4, 4) -GEN_VEXT_VF(vfmax_vf_d, 8, 8) +GEN_VEXT_VF(vfmax_vf_h, 2) +GEN_VEXT_VF(vfmax_vf_w, 4) +GEN_VEXT_VF(vfmax_vf_d, 8) /* Vector Floating-Point Sign-Injection Instructions */ static uint16_t fsgnj16(uint16_t a, uint16_t b, float_status *s) @@ -3855,15 +4105,15 @@ static uint64_t fsgnj64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnj_vv_h, OP_UUU_H, H2, H2, H2, fsgnj16) RVVCALL(OPFVV2, vfsgnj_vv_w, OP_UUU_W, H4, H4, H4, fsgnj32) RVVCALL(OPFVV2, vfsgnj_vv_d, OP_UUU_D, H8, H8, H8, fsgnj64) -GEN_VEXT_VV_ENV(vfsgnj_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsgnj_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsgnj_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsgnj_vv_h, 2) +GEN_VEXT_VV_ENV(vfsgnj_vv_w, 4) +GEN_VEXT_VV_ENV(vfsgnj_vv_d, 8) RVVCALL(OPFVF2, vfsgnj_vf_h, OP_UUU_H, H2, H2, fsgnj16) RVVCALL(OPFVF2, vfsgnj_vf_w, OP_UUU_W, H4, H4, fsgnj32) RVVCALL(OPFVF2, vfsgnj_vf_d, OP_UUU_D, H8, H8, fsgnj64) -GEN_VEXT_VF(vfsgnj_vf_h, 2, 2) -GEN_VEXT_VF(vfsgnj_vf_w, 4, 4) -GEN_VEXT_VF(vfsgnj_vf_d, 8, 8) +GEN_VEXT_VF(vfsgnj_vf_h, 2) +GEN_VEXT_VF(vfsgnj_vf_w, 4) +GEN_VEXT_VF(vfsgnj_vf_d, 8) static uint16_t fsgnjn16(uint16_t a, uint16_t b, float_status *s) { @@ -3883,15 +4133,15 @@ static uint64_t fsgnjn64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnjn_vv_h, OP_UUU_H, H2, H2, H2, fsgnjn16) RVVCALL(OPFVV2, vfsgnjn_vv_w, OP_UUU_W, H4, H4, H4, fsgnjn32) RVVCALL(OPFVV2, vfsgnjn_vv_d, OP_UUU_D, H8, H8, H8, fsgnjn64) -GEN_VEXT_VV_ENV(vfsgnjn_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsgnjn_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsgnjn_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsgnjn_vv_h, 2) +GEN_VEXT_VV_ENV(vfsgnjn_vv_w, 4) +GEN_VEXT_VV_ENV(vfsgnjn_vv_d, 8) RVVCALL(OPFVF2, vfsgnjn_vf_h, OP_UUU_H, H2, H2, fsgnjn16) RVVCALL(OPFVF2, vfsgnjn_vf_w, OP_UUU_W, H4, H4, fsgnjn32) RVVCALL(OPFVF2, vfsgnjn_vf_d, OP_UUU_D, H8, H8, fsgnjn64) -GEN_VEXT_VF(vfsgnjn_vf_h, 2, 2) -GEN_VEXT_VF(vfsgnjn_vf_w, 4, 4) -GEN_VEXT_VF(vfsgnjn_vf_d, 8, 8) +GEN_VEXT_VF(vfsgnjn_vf_h, 2) +GEN_VEXT_VF(vfsgnjn_vf_w, 4) +GEN_VEXT_VF(vfsgnjn_vf_d, 8) static uint16_t fsgnjx16(uint16_t a, uint16_t b, float_status *s) { @@ -3911,15 +4161,15 @@ static uint64_t fsgnjx64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnjx_vv_h, OP_UUU_H, H2, H2, H2, fsgnjx16) RVVCALL(OPFVV2, vfsgnjx_vv_w, OP_UUU_W, H4, H4, H4, fsgnjx32) RVVCALL(OPFVV2, vfsgnjx_vv_d, OP_UUU_D, H8, H8, H8, fsgnjx64) -GEN_VEXT_VV_ENV(vfsgnjx_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsgnjx_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsgnjx_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsgnjx_vv_h, 2) +GEN_VEXT_VV_ENV(vfsgnjx_vv_w, 4) +GEN_VEXT_VV_ENV(vfsgnjx_vv_d, 8) RVVCALL(OPFVF2, vfsgnjx_vf_h, OP_UUU_H, H2, H2, fsgnjx16) RVVCALL(OPFVF2, vfsgnjx_vf_w, OP_UUU_W, H4, H4, fsgnjx32) RVVCALL(OPFVF2, vfsgnjx_vf_d, OP_UUU_D, H8, H8, fsgnjx64) -GEN_VEXT_VF(vfsgnjx_vf_h, 2, 2) -GEN_VEXT_VF(vfsgnjx_vf_w, 4, 4) -GEN_VEXT_VF(vfsgnjx_vf_d, 8, 8) +GEN_VEXT_VF(vfsgnjx_vf_h, 2) +GEN_VEXT_VF(vfsgnjx_vf_w, 4) +GEN_VEXT_VF(vfsgnjx_vf_d, 8) /* Vector Floating-Point Compare Instructions */ #define GEN_VEXT_CMP_VV_ENV(NAME, ETYPE, H, DO_OP) \ @@ -3928,18 +4178,32 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ 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, &env->fp_status)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VV_ENV(vmfeq_vv_h, uint16_t, H2, float16_eq_quiet) @@ -3952,17 +4216,31 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ 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, \ DO_OP(s2, (ETYPE)s1, &env->fp_status)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VF(vmfeq_vf_h, uint16_t, H2, float16_eq_quiet) @@ -4063,21 +4341,31 @@ static void do_##NAME(void *vd, void *vs2, int i) \ *((TD *)vd + HD(i)) = OP(s2); \ } -#define GEN_VEXT_V(NAME, ESZ, DSZ) \ +#define GEN_VEXT_V(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ 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; \ } \ do_##NAME(vd, vs2, i); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } target_ulong fclass_h(uint64_t frs1) @@ -4140,17 +4428,22 @@ target_ulong fclass_d(uint64_t frs1) RVVCALL(OPIVV1, vfclass_v_h, OP_UU_H, H2, H2, fclass_h) RVVCALL(OPIVV1, vfclass_v_w, OP_UU_W, H4, H4, fclass_s) RVVCALL(OPIVV1, vfclass_v_d, OP_UU_D, H8, H8, fclass_d) -GEN_VEXT_V(vfclass_v_h, 2, 2) -GEN_VEXT_V(vfclass_v_w, 4, 4) -GEN_VEXT_V(vfclass_v_d, 8, 8) +GEN_VEXT_V(vfclass_v_h, 2) +GEN_VEXT_V(vfclass_v_w, 4) +GEN_VEXT_V(vfclass_v_d, 8) /* Vector Floating-Point Merge Instruction */ + #define GEN_VFMERGE_VF(NAME, ETYPE, H) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4159,6 +4452,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ = (!vm && !vext_elem_mask(v0, i) ? s2 : s1); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VFMERGE_VF(vfmerge_vfm_h, int16_t, H2) @@ -4170,33 +4465,33 @@ GEN_VFMERGE_VF(vfmerge_vfm_d, int64_t, H8) RVVCALL(OPFVV1, vfcvt_xu_f_v_h, OP_UU_H, H2, H2, float16_to_uint16) RVVCALL(OPFVV1, vfcvt_xu_f_v_w, OP_UU_W, H4, H4, float32_to_uint32) RVVCALL(OPFVV1, vfcvt_xu_f_v_d, OP_UU_D, H8, H8, float64_to_uint64) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_d, 8) /* vfcvt.x.f.v vd, vs2, vm # Convert float to signed integer. */ RVVCALL(OPFVV1, vfcvt_x_f_v_h, OP_UU_H, H2, H2, float16_to_int16) RVVCALL(OPFVV1, vfcvt_x_f_v_w, OP_UU_W, H4, H4, float32_to_int32) RVVCALL(OPFVV1, vfcvt_x_f_v_d, OP_UU_D, H8, H8, float64_to_int64) -GEN_VEXT_V_ENV(vfcvt_x_f_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_x_f_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_x_f_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_x_f_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_x_f_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_x_f_v_d, 8) /* vfcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to float. */ RVVCALL(OPFVV1, vfcvt_f_xu_v_h, OP_UU_H, H2, H2, uint16_to_float16) RVVCALL(OPFVV1, vfcvt_f_xu_v_w, OP_UU_W, H4, H4, uint32_to_float32) RVVCALL(OPFVV1, vfcvt_f_xu_v_d, OP_UU_D, H8, H8, uint64_to_float64) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_d, 8) /* vfcvt.f.x.v vd, vs2, vm # Convert integer to float. */ RVVCALL(OPFVV1, vfcvt_f_x_v_h, OP_UU_H, H2, H2, int16_to_float16) RVVCALL(OPFVV1, vfcvt_f_x_v_w, OP_UU_W, H4, H4, int32_to_float32) RVVCALL(OPFVV1, vfcvt_f_x_v_d, OP_UU_D, H8, H8, int64_to_float64) -GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8) /* Widening Floating-Point/Integer Type-Convert Instructions */ /* (TD, T2, TX2) */ @@ -4206,30 +4501,30 @@ GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8) /* vfwcvt.xu.f.v vd, vs2, vm # Convert float to double-width unsigned integer.*/ RVVCALL(OPFVV1, vfwcvt_xu_f_v_h, WOP_UU_H, H4, H2, float16_to_uint32) RVVCALL(OPFVV1, vfwcvt_xu_f_v_w, WOP_UU_W, H8, H4, float32_to_uint64) -GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w, 8) /* vfwcvt.x.f.v vd, vs2, vm # Convert float to double-width signed integer. */ RVVCALL(OPFVV1, vfwcvt_x_f_v_h, WOP_UU_H, H4, H2, float16_to_int32) RVVCALL(OPFVV1, vfwcvt_x_f_v_w, WOP_UU_W, H8, H4, float32_to_int64) -GEN_VEXT_V_ENV(vfwcvt_x_f_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_x_f_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_w, 8) /* vfwcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to double-width float */ RVVCALL(OPFVV1, vfwcvt_f_xu_v_b, WOP_UU_B, H2, H1, uint8_to_float16) RVVCALL(OPFVV1, vfwcvt_f_xu_v_h, WOP_UU_H, H4, H2, uint16_to_float32) RVVCALL(OPFVV1, vfwcvt_f_xu_v_w, WOP_UU_W, H8, H4, uint32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_b, 1, 2) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_b, 2) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w, 8) /* vfwcvt.f.x.v vd, vs2, vm # Convert integer to double-width float. */ RVVCALL(OPFVV1, vfwcvt_f_x_v_b, WOP_UU_B, H2, H1, int8_to_float16) RVVCALL(OPFVV1, vfwcvt_f_x_v_h, WOP_UU_H, H4, H2, int16_to_float32) RVVCALL(OPFVV1, vfwcvt_f_x_v_w, WOP_UU_W, H8, H4, int32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_b, 1, 2) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_b, 2) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_w, 8) /* * vfwcvt.f.f.v vd, vs2, vm @@ -4242,8 +4537,8 @@ static uint32_t vfwcvtffv16(uint16_t a, float_status *s) RVVCALL(OPFVV1, vfwcvt_f_f_v_h, WOP_UU_H, H4, H2, vfwcvtffv16) RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 8) /* Narrowing Floating-Point/Integer Type-Convert Instructions */ /* (TD, T2, TX2) */ @@ -4254,29 +4549,29 @@ GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8) RVVCALL(OPFVV1, vfncvt_xu_f_w_b, NOP_UU_B, H1, H2, float16_to_uint8) RVVCALL(OPFVV1, vfncvt_xu_f_w_h, NOP_UU_H, H2, H4, float32_to_uint16) RVVCALL(OPFVV1, vfncvt_xu_f_w_w, NOP_UU_W, H4, H8, float64_to_uint32) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_b, 1, 1) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_b, 1) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_w, 4) /* vfncvt.x.f.v vd, vs2, vm # Convert double-width float to signed integer. */ RVVCALL(OPFVV1, vfncvt_x_f_w_b, NOP_UU_B, H1, H2, float16_to_int8) RVVCALL(OPFVV1, vfncvt_x_f_w_h, NOP_UU_H, H2, H4, float32_to_int16) RVVCALL(OPFVV1, vfncvt_x_f_w_w, NOP_UU_W, H4, H8, float64_to_int32) -GEN_VEXT_V_ENV(vfncvt_x_f_w_b, 1, 1) -GEN_VEXT_V_ENV(vfncvt_x_f_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_x_f_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_x_f_w_b, 1) +GEN_VEXT_V_ENV(vfncvt_x_f_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_x_f_w_w, 4) /* vfncvt.f.xu.v vd, vs2, vm # Convert double-width unsigned integer to float */ RVVCALL(OPFVV1, vfncvt_f_xu_w_h, NOP_UU_H, H2, H4, uint32_to_float16) RVVCALL(OPFVV1, vfncvt_f_xu_w_w, NOP_UU_W, H4, H8, uint64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_xu_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_f_xu_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_f_xu_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_f_xu_w_w, 4) /* vfncvt.f.x.v vd, vs2, vm # Convert double-width integer to float. */ RVVCALL(OPFVV1, vfncvt_f_x_w_h, NOP_UU_H, H2, H4, int32_to_float16) RVVCALL(OPFVV1, vfncvt_f_x_w_w, NOP_UU_W, H4, H8, int64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_x_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_f_x_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_f_x_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_f_x_w_w, 4) /* vfncvt.f.f.v vd, vs2, vm # Convert double float to single-width float. */ static uint16_t vfncvtffv16(uint32_t a, float_status *s) @@ -4286,8 +4581,8 @@ static uint16_t vfncvtffv16(uint32_t a, float_status *s) RVVCALL(OPFVV1, vfncvt_f_f_w_h, NOP_UU_H, H2, H4, vfncvtffv16) RVVCALL(OPFVV1, vfncvt_f_f_w_w, NOP_UU_W, H4, H8, float64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_f_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_f_f_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_f_f_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_f_f_w_w, 4) /* *** Vector Reduction Operations @@ -4299,6 +4594,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + uint32_t vlenb = simd_maxsz(desc); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ TD s1 = *((TD *)vs1 + HD(0)); \ \ @@ -4311,6 +4609,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ } \ *((TD *)vd + HD(0)) = s1; \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, esz, vlenb); \ } /* vd[0] = sum(vs1[0], vs2[*]) */ @@ -4380,6 +4680,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + uint32_t vlenb = simd_maxsz(desc); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ TD s1 = *((TD *)vs1 + HD(0)); \ \ @@ -4392,12 +4695,19 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ } \ *((TD *)vd + HD(0)) = s1; \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, esz, vlenb); \ } /* 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) @@ -4409,48 +4719,24 @@ 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 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) +/* Vector Widening Floating-Point Add Instructions */ +static uint32_t fwadd16(uint32_t a, uint16_t b, float_status *s) { - uint32_t vm = vext_vm(desc); - uint32_t vl = env->vl; - 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; + return float32_add(a, float16_to_float32(b, true, s), s); } -void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, - void *vs2, CPURISCVState *env, uint32_t desc) +static uint64_t fwadd32(uint64_t a, uint32_t b, float_status *s) { - uint32_t vm = vext_vm(desc); - uint32_t vl = env->vl; - 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; + return float64_add(a, float32_to_float64(b, s), s); } +/* Vector Widening Floating-Point Reduction Instructions */ +/* 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 */ @@ -4461,6 +4747,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t desc) \ { \ 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 i; \ int a, b; \ \ @@ -4470,6 +4758,15 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ vext_set_elem_mask(vd, i, OP(b, a)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail- \ + * agnostic \ + */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } #define DO_NAND(N, M) (!(N & M)) @@ -4537,11 +4834,18 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, { uint32_t vm = vext_vm(desc); 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 */ @@ -4565,6 +4869,13 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, } } env->vstart = 0; + /* mask destination register are always tail-agnostic */ + /* set tail elements to 1s */ + if (vta_all_1s) { + for (; i < total_elems; i++) { + vext_set_elem_mask(vd, i, 1); + } + } } void HELPER(vmsbf_m)(void *vd, void *v0, void *vs2, CPURISCVState *env, @@ -4592,11 +4903,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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; \ @@ -4605,6 +4922,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VIOTA_M(viota_m_b, uint8_t, H1) @@ -4618,15 +4937,23 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VID_V(vid_v_b, uint8_t, H1) @@ -4645,15 +4972,23 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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)); \ } \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vslideup.vx vd, vs2, rs1, vm # vd[i+rs1] = vs2[i] */ @@ -4669,13 +5004,20 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vlmax = vext_max_elems(desc, ctzl(sizeof(ETYPE))); \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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) { \ @@ -4685,6 +5027,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vslidedown.vx vd, vs2, rs1, vm # vd[i] = vs2[i+rs1] */ @@ -4693,17 +5037,23 @@ GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_h, uint16_t, H2) GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_w, uint32_t, H4) GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_d, uint64_t, H8) -#define GEN_VEXT_VSLIE1UP(ESZ, H) \ -static void vslide1up_##ESZ(void *vd, void *v0, target_ulong s1, void *vs2, \ - CPURISCVState *env, uint32_t desc) \ +#define GEN_VEXT_VSLIE1UP(BITWIDTH, H) \ +static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ { \ - typedef uint##ESZ##_t ETYPE; \ + typedef uint##BITWIDTH##_t ETYPE; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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) { \ @@ -4713,6 +5063,8 @@ static void vslide1up_##ESZ(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VSLIE1UP(8, H1) @@ -4720,11 +5072,11 @@ GEN_VEXT_VSLIE1UP(16, H2) GEN_VEXT_VSLIE1UP(32, H4) GEN_VEXT_VSLIE1UP(64, H8) -#define GEN_VEXT_VSLIDE1UP_VX(NAME, ESZ) \ +#define GEN_VEXT_VSLIDE1UP_VX(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1up_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1up_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vslide1up.vx vd, vs2, rs1, vm # vd[0]=x[rs1], vd[i+1] = vs2[i] */ @@ -4733,17 +5085,23 @@ GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_h, 16) GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_w, 32) GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_d, 64) -#define GEN_VEXT_VSLIDE1DOWN(ESZ, H) \ -static void vslide1down_##ESZ(void *vd, void *v0, target_ulong s1, void *vs2, \ - CPURISCVState *env, uint32_t desc) \ +#define GEN_VEXT_VSLIDE1DOWN(BITWIDTH, H) \ +static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ { \ - typedef uint##ESZ##_t ETYPE; \ + typedef uint##BITWIDTH##_t ETYPE; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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) { \ @@ -4753,6 +5111,8 @@ static void vslide1down_##ESZ(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VSLIDE1DOWN(8, H1) @@ -4760,11 +5120,11 @@ GEN_VEXT_VSLIDE1DOWN(16, H2) GEN_VEXT_VSLIDE1DOWN(32, H4) GEN_VEXT_VSLIDE1DOWN(64, H8) -#define GEN_VEXT_VSLIDE1DOWN_VX(NAME, ESZ) \ +#define GEN_VEXT_VSLIDE1DOWN_VX(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1down_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1down_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vslide1down.vx vd, vs2, rs1, vm # vd[i] = vs2[i+1], vd[vl-1]=x[rs1] */ @@ -4774,11 +5134,11 @@ GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_w, 32) GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_d, 64) /* Vector Floating-Point Slide Instructions */ -#define GEN_VEXT_VFSLIDE1UP_VF(NAME, ESZ) \ +#define GEN_VEXT_VFSLIDE1UP_VF(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1up_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1up_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vfslide1up.vf vd, vs2, rs1, vm # vd[0]=f[rs1], vd[i+1] = vs2[i] */ @@ -4786,11 +5146,11 @@ GEN_VEXT_VFSLIDE1UP_VF(vfslide1up_vf_h, 16) GEN_VEXT_VFSLIDE1UP_VF(vfslide1up_vf_w, 32) GEN_VEXT_VFSLIDE1UP_VF(vfslide1up_vf_d, 64) -#define GEN_VEXT_VFSLIDE1DOWN_VF(NAME, ESZ) \ +#define GEN_VEXT_VFSLIDE1DOWN_VF(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1down_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1down_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vfslide1down.vf vd, vs2, rs1, vm # vd[i] = vs2[i+1], vd[vl-1]=f[rs1] */ @@ -4806,11 +5166,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vlmax = vext_max_elems(desc, ctzl(sizeof(TS2))); \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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)); \ @@ -4821,6 +5187,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vd[i] = (vs1[i] >= VLMAX) ? 0 : vs2[vs1[i]]; */ @@ -4841,11 +5209,17 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vlmax = vext_max_elems(desc, ctzl(sizeof(ETYPE))); \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + 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) { \ @@ -4855,6 +5229,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ @@ -4869,6 +5245,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t num = 0, i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4879,6 +5258,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ num++; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* Compress into vd elements of vs2 where vs1 is enabled */ @@ -4888,25 +5269,20 @@ GEN_VEXT_VCOMPRESS_VM(vcompress_vm_w, uint32_t, H4) GEN_VEXT_VCOMPRESS_VM(vcompress_vm_d, uint64_t, H8) /* Vector Whole Register Move */ -#define GEN_VEXT_VMV_WHOLE(NAME, LEN) \ -void HELPER(NAME)(void *vd, void *vs2, CPURISCVState *env, \ - uint32_t desc) \ -{ \ - /* EEW = 8 */ \ - uint32_t maxsz = simd_maxsz(desc); \ - uint32_t i = env->vstart; \ - \ - memcpy((uint8_t *)vd + H1(i), \ - (uint8_t *)vs2 + H1(i), \ - maxsz - env->vstart); \ - \ - env->vstart = 0; \ -} +void HELPER(vmvr_v)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc) +{ + /* EEW = SEW */ + uint32_t maxsz = simd_maxsz(desc); + uint32_t sewb = 1 << FIELD_EX64(env->vtype, VTYPE, VSEW); + uint32_t startb = env->vstart * sewb; + uint32_t i = startb; -GEN_VEXT_VMV_WHOLE(vmv1r_v, 1) -GEN_VEXT_VMV_WHOLE(vmv2r_v, 2) -GEN_VEXT_VMV_WHOLE(vmv4r_v, 4) -GEN_VEXT_VMV_WHOLE(vmv8r_v, 8) + memcpy((uint8_t *)vd + H1(i), + (uint8_t *)vs2 + H1(i), + maxsz - startb); + + env->vstart = 0; +} /* Vector Integer Extension */ #define GEN_VEXT_INT_EXT(NAME, ETYPE, DTYPE, HD, HS1) \ @@ -4915,15 +5291,23 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(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); \ 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)); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_INT_EXT(vzext_vf2_h, uint16_t, uint8_t, H2, H1) diff --git a/target/rx/cpu-qom.h b/target/rx/cpu-qom.h index 4533759d966f..1c8466a1870e 100644 --- a/target/rx/cpu-qom.h +++ b/target/rx/cpu-qom.h @@ -31,7 +31,7 @@ OBJECT_DECLARE_CPU_TYPE(RXCPU, RXCPUClass, RX_CPU) /* * RXCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A RX CPU model. */ @@ -41,7 +41,7 @@ struct RXCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; #endif diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 25a4aa2976d3..219ef28e4632 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -20,7 +20,6 @@ #include "qemu/qemu-print.h" #include "qapi/error.h" #include "cpu.h" -#include "qemu-common.h" #include "migration/vmstate.h" #include "exec/exec-all.h" #include "hw/loader.h" @@ -33,12 +32,28 @@ 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 void rx_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + RXCPU *cpu = RX_CPU(cs); + + cpu->env.pc = data[0]; } static bool rx_cpu_has_work(CPUState *cs) @@ -47,14 +62,16 @@ static bool rx_cpu_has_work(CPUState *cs) (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR); } -static void rx_cpu_reset(DeviceState *dev) +static void rx_cpu_reset_hold(Object *obj) { - RXCPU *cpu = RX_CPU(dev); + RXCPU *cpu = RX_CPU(obj); RXCPUClass *rcc = RX_CPU_GET_CLASS(cpu); CPURXState *env = &cpu->env; uint32_t *resetvec; - rcc->parent_reset(dev); + if (rcc->parent_phases.hold) { + rcc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPURXState, end_reset_fields)); @@ -186,6 +203,7 @@ static const struct SysemuCPUOps rx_sysemu_ops = { static const struct TCGCPUOps rx_tcg_ops = { .initialize = rx_translate_init, .synchronize_from_tb = rx_cpu_synchronize_from_tb, + .restore_state_to_opc = rx_restore_state_to_opc, .tlb_fill = rx_cpu_tlb_fill, #ifndef CONFIG_USER_ONLY @@ -199,16 +217,18 @@ static void rx_cpu_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); CPUClass *cc = CPU_CLASS(klass); RXCPUClass *rcc = RX_CPU_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_parent_realize(dc, rx_cpu_realize, &rcc->parent_realize); - device_class_set_parent_reset(dc, rx_cpu_reset, - &rcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, rx_cpu_reset_hold, NULL, + &rcc->parent_phases); cc->class_by_name = rx_cpu_class_by_name; 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/cpu.h b/target/rx/cpu.h index b4abd90ccd1e..5655dffeff6b 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -24,6 +24,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" /* PSW define */ REG32(PSW, 0) @@ -148,6 +149,7 @@ static inline void cpu_get_tb_cpu_state(CPURXState *env, target_ulong *pc, *pc = env->pc; *cs_base = 0; *flags = FIELD_DP32(0, PSW, PM, env->psw_pm); + *flags = FIELD_DP32(*flags, PSW, U, env->psw_u); } static inline int cpu_mmu_index(CPURXState *env, bool ifetch) diff --git a/target/rx/gdbstub.c b/target/rx/gdbstub.c index c811d4810b45..7eb2059a841b 100644 --- a/target/rx/gdbstub.c +++ b/target/rx/gdbstub.c @@ -16,7 +16,6 @@ * this program. If not, see . */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "exec/gdbstub.h" diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c index 11f952d34099..acce650185f0 100644 --- a/target/rx/op_helper.c +++ b/target/rx/op_helper.c @@ -24,8 +24,9 @@ #include "exec/cpu_ldst.h" #include "fpu/softfloat.h" -static inline void QEMU_NORETURN raise_exception(CPURXState *env, int index, - uintptr_t retaddr); +static inline G_NORETURN +void raise_exception(CPURXState *env, int index, + uintptr_t retaddr); static void _set_psw(CPURXState *env, uint32_t psw, uint32_t rte) { @@ -285,7 +286,7 @@ void helper_suntil(CPURXState *env, uint32_t sz) uint32_t tmp; tcg_debug_assert(sz < 3); if (env->regs[3] == 0) { - return ; + return; } do { tmp = cpu_ldufn[sz](env, env->regs[1], GETPC()); @@ -304,7 +305,7 @@ void helper_swhile(CPURXState *env, uint32_t sz) uint32_t tmp; tcg_debug_assert(sz < 3); if (env->regs[3] == 0) { - return ; + return; } do { tmp = cpu_ldufn[sz](env, env->regs[1], GETPC()); @@ -418,8 +419,9 @@ uint32_t helper_divu(CPURXState *env, uint32_t num, uint32_t den) } /* exception */ -static inline void QEMU_NORETURN raise_exception(CPURXState *env, int index, - uintptr_t retaddr) +static inline G_NORETURN +void raise_exception(CPURXState *env, int index, + uintptr_t retaddr) { CPUState *cs = env_cpu(env); @@ -427,36 +429,37 @@ static inline void QEMU_NORETURN raise_exception(CPURXState *env, int index, cpu_loop_exit_restore(cs, retaddr); } -void QEMU_NORETURN helper_raise_privilege_violation(CPURXState *env) +G_NORETURN void helper_raise_privilege_violation(CPURXState *env) { raise_exception(env, 20, GETPC()); } -void QEMU_NORETURN helper_raise_access_fault(CPURXState *env) +G_NORETURN void helper_raise_access_fault(CPURXState *env) { raise_exception(env, 21, GETPC()); } -void QEMU_NORETURN helper_raise_illegal_instruction(CPURXState *env) +G_NORETURN void helper_raise_illegal_instruction(CPURXState *env) { raise_exception(env, 23, GETPC()); } -void QEMU_NORETURN helper_wait(CPURXState *env) +G_NORETURN void helper_wait(CPURXState *env) { CPUState *cs = env_cpu(env); cs->halted = 1; env->in_sleep = 1; + env->psw_i = 1; raise_exception(env, EXCP_HLT, 0); } -void QEMU_NORETURN helper_rxint(CPURXState *env, uint32_t vec) +G_NORETURN void helper_rxint(CPURXState *env, uint32_t vec) { raise_exception(env, 0x100 + vec, 0); } -void QEMU_NORETURN helper_rxbrk(CPURXState *env) +G_NORETURN void helper_rxbrk(CPURXState *env) { raise_exception(env, 0x100, 0); } diff --git a/target/rx/translate.c b/target/rx/translate.c index 5db8f79a82e4..87a3f54adb7d 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -32,6 +32,7 @@ typedef struct DisasContext { DisasContextBase base; CPURXState *env; uint32_t pc; + uint32_t tb_flags; } DisasContext; typedef struct DisasCompare { @@ -231,7 +232,7 @@ static inline TCGv rx_load_source(DisasContext *ctx, TCGv mem, /* Processor mode check */ static int is_privileged(DisasContext *ctx, int is_exception) { - if (FIELD_EX32(ctx->base.tb->flags, PSW, PM)) { + if (FIELD_EX32(ctx->tb_flags, PSW, PM)) { if (is_exception) { gen_helper_raise_privilege_violation(cpu_env); } @@ -310,9 +311,8 @@ static void psw_cond(DisasCompare *dc, uint32_t cond) } } -static void move_from_cr(TCGv ret, int cr, uint32_t pc) +static void move_from_cr(DisasContext *ctx, TCGv ret, int cr, uint32_t pc) { - TCGv z = tcg_const_i32(0); switch (cr) { case 0: /* PSW */ gen_helper_pack_psw(ret, cpu_env); @@ -321,8 +321,11 @@ static void move_from_cr(TCGv ret, int cr, uint32_t pc) tcg_gen_movi_i32(ret, pc); break; case 2: /* USP */ - tcg_gen_movcond_i32(TCG_COND_NE, ret, - cpu_psw_u, z, cpu_sp, cpu_usp); + if (FIELD_EX32(ctx->tb_flags, PSW, U)) { + tcg_gen_mov_i32(ret, cpu_sp); + } else { + tcg_gen_mov_i32(ret, cpu_usp); + } break; case 3: /* FPSW */ tcg_gen_mov_i32(ret, cpu_fpsw); @@ -334,8 +337,11 @@ static void move_from_cr(TCGv ret, int cr, uint32_t pc) tcg_gen_mov_i32(ret, cpu_bpc); break; case 10: /* ISP */ - tcg_gen_movcond_i32(TCG_COND_EQ, ret, - cpu_psw_u, z, cpu_sp, cpu_isp); + if (FIELD_EX32(ctx->tb_flags, PSW, U)) { + tcg_gen_mov_i32(ret, cpu_isp); + } else { + tcg_gen_mov_i32(ret, cpu_sp); + } break; case 11: /* FINTV */ tcg_gen_mov_i32(ret, cpu_fintv); @@ -349,28 +355,31 @@ static void move_from_cr(TCGv ret, int cr, uint32_t pc) tcg_gen_movi_i32(ret, 0); break; } - tcg_temp_free(z); } static void move_to_cr(DisasContext *ctx, TCGv val, int cr) { - TCGv z; if (cr >= 8 && !is_privileged(ctx, 0)) { /* Some control registers can only be written in privileged mode. */ qemu_log_mask(LOG_GUEST_ERROR, "disallow control register write %s", rx_crname(cr)); return; } - z = tcg_const_i32(0); switch (cr) { case 0: /* PSW */ gen_helper_set_psw(cpu_env, val); + if (is_privileged(ctx, 0)) { + /* PSW.{I,U} may be updated here. exit TB. */ + ctx->base.is_jmp = DISAS_UPDATE; + } break; /* case 1: to PC not supported */ case 2: /* USP */ - tcg_gen_mov_i32(cpu_usp, val); - tcg_gen_movcond_i32(TCG_COND_NE, cpu_sp, - cpu_psw_u, z, cpu_usp, cpu_sp); + if (FIELD_EX32(ctx->tb_flags, PSW, U)) { + tcg_gen_mov_i32(cpu_sp, val); + } else { + tcg_gen_mov_i32(cpu_usp, val); + } break; case 3: /* FPSW */ gen_helper_set_fpsw(cpu_env, val); @@ -382,10 +391,11 @@ static void move_to_cr(DisasContext *ctx, TCGv val, int cr) tcg_gen_mov_i32(cpu_bpc, val); break; case 10: /* ISP */ - tcg_gen_mov_i32(cpu_isp, val); - /* if PSW.U is 0, copy isp to r0 */ - tcg_gen_movcond_i32(TCG_COND_EQ, cpu_sp, - cpu_psw_u, z, cpu_isp, cpu_sp); + if (FIELD_EX32(ctx->tb_flags, PSW, U)) { + tcg_gen_mov_i32(cpu_isp, val); + } else { + tcg_gen_mov_i32(cpu_sp, val); + } break; case 11: /* FINTV */ tcg_gen_mov_i32(cpu_fintv, val); @@ -398,7 +408,6 @@ static void move_to_cr(DisasContext *ctx, TCGv val, int cr) "Unimplement control register %d", cr); break; } - tcg_temp_free(z); } static void push(TCGv val) @@ -626,10 +635,6 @@ static bool trans_POPC(DisasContext *ctx, arg_POPC *a) val = tcg_temp_new(); pop(val); move_to_cr(ctx, val, a->cr); - if (a->cr == 0 && is_privileged(ctx, 0)) { - /* PSW.I may be updated here. exit TB. */ - ctx->base.is_jmp = DISAS_UPDATE; - } tcg_temp_free(val); return true; } @@ -682,7 +687,7 @@ static bool trans_PUSHC(DisasContext *ctx, arg_PUSHC *a) { TCGv val; val = tcg_temp_new(); - move_from_cr(val, a->cr, ctx->pc); + move_from_cr(ctx, val, a->cr, ctx->pc); push(val); tcg_temp_free(val); return true; @@ -2160,7 +2165,12 @@ static inline void clrsetpsw(DisasContext *ctx, int cb, int val) ctx->base.is_jmp = DISAS_UPDATE; break; case PSW_U: - tcg_gen_movi_i32(cpu_psw_u, val); + if (FIELD_EX32(ctx->tb_flags, PSW, U) != val) { + ctx->tb_flags = FIELD_DP32(ctx->tb_flags, PSW, U, val); + tcg_gen_movi_i32(cpu_psw_u, val); + tcg_gen_mov_i32(val ? cpu_isp : cpu_usp, cpu_sp); + tcg_gen_mov_i32(cpu_sp, val ? cpu_usp : cpu_isp); + } break; default: qemu_log_mask(LOG_GUEST_ERROR, "Invalid distination %d", cb); @@ -2200,9 +2210,6 @@ static bool trans_MVTC_i(DisasContext *ctx, arg_MVTC_i *a) imm = tcg_const_i32(a->imm); move_to_cr(ctx, imm, a->cr); - if (a->cr == 0 && is_privileged(ctx, 0)) { - ctx->base.is_jmp = DISAS_UPDATE; - } tcg_temp_free(imm); return true; } @@ -2211,16 +2218,13 @@ static bool trans_MVTC_i(DisasContext *ctx, arg_MVTC_i *a) static bool trans_MVTC_r(DisasContext *ctx, arg_MVTC_r *a) { move_to_cr(ctx, cpu_regs[a->rs], a->cr); - if (a->cr == 0 && is_privileged(ctx, 0)) { - ctx->base.is_jmp = DISAS_UPDATE; - } return true; } /* mvfc rs, rd */ static bool trans_MVFC(DisasContext *ctx, arg_MVFC *a) { - move_from_cr(cpu_regs[a->rd], a->cr, ctx->pc); + move_from_cr(ctx, cpu_regs[a->rd], a->cr, ctx->pc); return true; } @@ -2281,7 +2285,7 @@ static bool trans_INT(DisasContext *ctx, arg_INT *a) static bool trans_WAIT(DisasContext *ctx, arg_WAIT *a) { if (is_privileged(ctx, 1)) { - tcg_gen_addi_i32(cpu_pc, cpu_pc, 2); + tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); gen_helper_wait(cpu_env); } return true; @@ -2292,6 +2296,7 @@ static void rx_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) CPURXState *env = cs->env_ptr; DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->env = env; + ctx->tb_flags = ctx->base.tb->flags; } static void rx_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) @@ -2342,10 +2347,11 @@ static void rx_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void rx_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void rx_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { - qemu_log("IN:\n"); /* , lookup_symbol(dcbase->pc_first)); */ - log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps rx_tr_ops = { @@ -2357,17 +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); -} - -void restore_state_to_opc(CPURXState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; + translator_loop(cs, tb, max_insns, pc, host_pc, &rx_tr_ops, &dc.base); } #define ALLOC_REGISTER(sym, name) \ diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index 08daf93ae1f0..a2329141e8ad 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -12,11 +12,13 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "cpu.h" #include "s390x-internal.h" #include "elf.h" #include "sysemu/dump.h" - +#include "hw/s390x/pv.h" +#include "kvm/kvm_s390x.h" struct S390xUserRegsStruct { uint64_t psw[2]; @@ -76,9 +78,16 @@ typedef struct noteStruct { uint64_t todcmp; uint32_t todpreg; uint64_t ctrs[16]; + uint8_t dynamic[1]; /* + * Would be a flexible array member, if + * that was legal inside a union. Real + * size comes from PV info interface. + */ } contents; } QEMU_PACKED Note; +static bool pv_dump_initialized; + static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id) { int i; @@ -177,52 +186,82 @@ static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id) note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); } +static void s390x_write_elf64_pv(Note *note, S390CPU *cpu, int id) +{ + note->hdr.n_type = cpu_to_be32(NT_S390_PV_CPU_DATA); + if (!pv_dump_initialized) { + return; + } + kvm_s390_dump_cpu(cpu, ¬e->contents.dynamic); +} typedef struct NoteFuncDescStruct { int contents_size; + uint64_t (*note_size_func)(void); /* NULL for non-dynamic sized contents */ void (*note_contents_func)(Note *note, S390CPU *cpu, int id); + bool pvonly; } NoteFuncDesc; static const NoteFuncDesc note_core[] = { - {sizeof_field(Note, contents.prstatus), s390x_write_elf64_prstatus}, - {sizeof_field(Note, contents.fpregset), s390x_write_elf64_fpregset}, - { 0, NULL} + {sizeof_field(Note, contents.prstatus), NULL, s390x_write_elf64_prstatus, false}, + {sizeof_field(Note, contents.fpregset), NULL, s390x_write_elf64_fpregset, false}, + { 0, NULL, NULL, false} }; static const NoteFuncDesc note_linux[] = { - {sizeof_field(Note, contents.prefix), s390x_write_elf64_prefix}, - {sizeof_field(Note, contents.ctrs), s390x_write_elf64_ctrs}, - {sizeof_field(Note, contents.timer), s390x_write_elf64_timer}, - {sizeof_field(Note, contents.todcmp), s390x_write_elf64_todcmp}, - {sizeof_field(Note, contents.todpreg), s390x_write_elf64_todpreg}, - {sizeof_field(Note, contents.vregslo), s390x_write_elf64_vregslo}, - {sizeof_field(Note, contents.vregshi), s390x_write_elf64_vregshi}, - {sizeof_field(Note, contents.gscb), s390x_write_elf64_gscb}, - { 0, NULL} + {sizeof_field(Note, contents.prefix), NULL, s390x_write_elf64_prefix, false}, + {sizeof_field(Note, contents.ctrs), NULL, s390x_write_elf64_ctrs, false}, + {sizeof_field(Note, contents.timer), NULL, s390x_write_elf64_timer, false}, + {sizeof_field(Note, contents.todcmp), NULL, s390x_write_elf64_todcmp, false}, + {sizeof_field(Note, contents.todpreg), NULL, s390x_write_elf64_todpreg, false}, + {sizeof_field(Note, contents.vregslo), NULL, s390x_write_elf64_vregslo, false}, + {sizeof_field(Note, contents.vregshi), NULL, s390x_write_elf64_vregshi, false}, + {sizeof_field(Note, contents.gscb), NULL, s390x_write_elf64_gscb, false}, + {0, kvm_s390_pv_dmp_get_size_cpu, s390x_write_elf64_pv, true}, + { 0, NULL, NULL, false} }; 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; + Note note, *notep; const NoteFuncDesc *nf; - int note_size; + int note_size, content_size; int ret = -1; assert(strlen(note_name) < sizeof(note.name)); for (nf = funcs; nf->note_contents_func; nf++) { - memset(¬e, 0, sizeof(note)); - note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); - note.hdr.n_descsz = cpu_to_be32(nf->contents_size); - g_strlcpy(note.name, note_name, sizeof(note.name)); - (*nf->note_contents_func)(¬e, cpu, id); + notep = ¬e; + if (nf->pvonly && !s390_is_pv()) { + continue; + } + + content_size = nf->note_size_func ? nf->note_size_func() : nf->contents_size; + note_size = sizeof(note) - sizeof(notep->contents) + content_size; + + /* Notes with dynamic sizes need to allocate a note */ + if (nf->note_size_func) { + notep = g_malloc(note_size); + } + + memset(notep, 0, sizeof(note)); - note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; - ret = f(¬e, note_size, opaque); + /* Setup note header data */ + notep->hdr.n_descsz = cpu_to_be32(content_size); + notep->hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); + g_strlcpy(notep->name, note_name, sizeof(notep->name)); + + /* Get contents and write them out */ + (*nf->note_contents_func)(notep, cpu, id); + ret = f(notep, note_size, s); + + if (nf->note_size_func) { + g_free(notep); + } if (ret < 0) { return -1; @@ -235,16 +274,169 @@ 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); +} + +/* PV dump section size functions */ +static uint64_t get_mem_state_size_from_len(uint64_t len) +{ + return (len / (MiB)) * kvm_s390_pv_dmp_get_size_mem_state(); +} + +static uint64_t get_size_mem_state(DumpState *s) +{ + return get_mem_state_size_from_len(s->total_size); +} + +static uint64_t get_size_completion_data(DumpState *s) +{ + return kvm_s390_pv_dmp_get_size_completion_data(); +} + +/* PV dump section data functions*/ +static int get_data_completion(DumpState *s, uint8_t *buff) +{ + int rc; + + if (!pv_dump_initialized) { + return 0; + } + rc = kvm_s390_dump_completion_data(buff); + if (!rc) { + pv_dump_initialized = false; + } + return rc; +} + +static int get_mem_state(DumpState *s, uint8_t *buff) +{ + int64_t memblock_size, memblock_start; + GuestPhysBlock *block; + uint64_t off; + int rc; + + 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; + } + + memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin, + s->filter_area_length); + + off = get_mem_state_size_from_len(block->target_start); + + rc = kvm_s390_dump_mem_state(block->target_start, + get_mem_state_size_from_len(memblock_size), + buff + off); + if (rc) { + return rc; + } + } + + return 0; +} + +static struct sections { + uint64_t (*sections_size_func)(DumpState *s); + int (*sections_contents_func)(DumpState *s, uint8_t *buff); + char sctn_str[12]; +} sections[] = { + { get_size_mem_state, get_mem_state, "pv_mem_meta"}, + { get_size_completion_data, get_data_completion, "pv_compl"}, + {NULL , NULL, ""} +}; + +static uint64_t arch_sections_write_hdr(DumpState *s, uint8_t *buff) +{ + Elf64_Shdr *shdr = (void *)buff; + struct sections *sctn = sections; + uint64_t off = s->section_offset; + + if (!pv_dump_initialized) { + return 0; + } + + for (; sctn->sections_size_func; off += shdr->sh_size, sctn++, shdr++) { + memset(shdr, 0, sizeof(*shdr)); + shdr->sh_type = SHT_PROGBITS; + shdr->sh_offset = off; + shdr->sh_size = sctn->sections_size_func(s); + shdr->sh_name = s->string_table_buf->len; + g_array_append_vals(s->string_table_buf, sctn->sctn_str, sizeof(sctn->sctn_str)); + } + + return (uintptr_t)shdr - (uintptr_t)buff; +} + + +/* Add arch specific number of sections and their respective sizes */ +static void arch_sections_add(DumpState *s) +{ + struct sections *sctn = sections; + + /* + * We only do a PV dump if we are running a PV guest, KVM supports + * the dump API and we got valid dump length information. + */ + if (!s390_is_pv() || !kvm_s390_get_protected_dump() || + !kvm_s390_pv_info_basic_valid()) { + return; + } + + /* + * Start the UV dump process by doing the initialize dump call via + * KVM as the proxy. + */ + if (!kvm_s390_dump_init()) { + pv_dump_initialized = true; + } else { + /* + * Dump init failed, maybe the guest owner disabled dumping. + * We'll continue the non-PV dump process since this is no + * reason to crash qemu. + */ + return; + } + + for (; sctn->sections_size_func; sctn++) { + s->shdr_num += 1; + s->elf_section_data_size += sctn->sections_size_func(s); + } +} + +/* + * After the PV dump has been initialized, the CPU data has been + * fetched and memory has been dumped, we need to grab the tweak data + * and the completion data. + */ +static int arch_sections_write(DumpState *s, uint8_t *buff) +{ + struct sections *sctn = sections; + int rc; + + if (!pv_dump_initialized) { + return -EINVAL; + } + + for (; sctn->sections_size_func; sctn++) { + rc = sctn->sections_contents_func(s, buff); + buff += sctn->sections_size_func(s); + if (rc) { + return rc; + } + } + return 0; } int cpu_get_dump_info(ArchDumpInfo *info, @@ -253,7 +445,20 @@ int cpu_get_dump_info(ArchDumpInfo *info, info->d_machine = EM_S390; info->d_endian = ELFDATA2MSB; info->d_class = ELFCLASS64; - + /* + * This is evaluated for each dump so we can freely switch + * between PV and non-PV. + */ + if (s390_is_pv() && kvm_s390_get_protected_dump() && + kvm_s390_pv_info_basic_valid()) { + info->arch_sections_add_fn = *arch_sections_add; + info->arch_sections_write_hdr_fn = *arch_sections_write_hdr; + info->arch_sections_write_fn = *arch_sections_write; + } else { + info->arch_sections_add_fn = NULL; + info->arch_sections_write_hdr_fn = NULL; + info->arch_sections_write_fn = NULL; + } return 0; } @@ -261,7 +466,7 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) { int name_size = 8; /* "LINUX" or "CORE" + pad */ size_t elf_note_size = 0; - int note_head_size; + int note_head_size, content_size; const NoteFuncDesc *nf; assert(class == ELFCLASS64); @@ -270,12 +475,15 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) note_head_size = sizeof(Elf64_Nhdr); for (nf = note_core; nf->note_contents_func; nf++) { - elf_note_size = elf_note_size + note_head_size + name_size + - nf->contents_size; + elf_note_size = elf_note_size + note_head_size + name_size + nf->contents_size; } for (nf = note_linux; nf->note_contents_func; nf++) { + if (nf->pvonly && !s390_is_pv()) { + continue; + } + content_size = nf->contents_size ? nf->contents_size : nf->note_size_func(); elf_note_size = elf_note_size + note_head_size + name_size + - nf->contents_size; + content_size; } return (elf_note_size) * nr_cpus; diff --git a/target/s390x/cpu-param.h b/target/s390x/cpu-param.h index 472db648d780..bf951a002e08 100644 --- a/target/s390x/cpu-param.h +++ b/target/s390x/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef S390_CPU_PARAM_H -#define S390_CPU_PARAM_H 1 +#define S390_CPU_PARAM_H #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 12 diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index ccdbaf84d541..b10a8541ff83 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -26,7 +26,6 @@ #include "s390x-internal.h" #include "kvm/kvm_s390x.h" #include "sysemu/kvm.h" -#include "sysemu/reset.h" #include "qemu/module.h" #include "trace.h" #include "qapi/qapi-types-machine.h" @@ -35,6 +34,9 @@ #include "fpu/softfloat-helpers.h" #include "disas/capstone.h" #include "sysemu/tcg.h" +#ifndef CONFIG_USER_ONLY +#include "sysemu/reset.h" +#endif #define CR0_RESET 0xE0UL #define CR14_RESET 0xC2000000UL; @@ -88,6 +90,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); @@ -178,7 +187,6 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type) static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) { info->mach = bfd_mach_s390_64; - info->print_insn = print_insn_s390; info->cap_arch = CS_ARCH_SYSZ; info->cap_insn_unit = 2; info->cap_insn_split = 6; @@ -266,6 +274,7 @@ static void s390_cpu_reset_full(DeviceState *dev) static const struct TCGCPUOps s390_tcg_ops = { .initialize = s390x_translate_init, + .restore_state_to_opc = s390x_restore_state_to_opc, #ifdef CONFIG_USER_ONLY .record_sigsegv = s390_cpu_record_sigsegv, @@ -298,6 +307,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.h b/target/s390x/cpu.h index c49c8466e74d..7d6d01325b2d 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -28,6 +28,7 @@ #include "cpu-qom.h" #include "cpu_models.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" #define ELF_MACHINE_UNAME "S390X" diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c index 5528acd08289..2e4e11d264b5 100644 --- a/target/s390x/cpu_features.c +++ b/target/s390x/cpu_features.c @@ -14,7 +14,9 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "cpu_features.h" +#ifndef CONFIG_USER_ONLY #include "hw/s390x/pv.h" +#endif #define DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC) \ [S390_FEAT_##_FEAT] = { \ @@ -107,6 +109,7 @@ void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type, feat = find_next_bit(features, S390_FEAT_MAX, feat + 1); } +#ifndef CONFIG_USER_ONLY if (!s390_is_pv()) { return; } @@ -147,6 +150,7 @@ void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type, default: return; } +#endif } void s390_add_from_feat_block(S390FeatBitmap features, S390FeatType type, diff --git a/target/s390x/cpu_features_def.h.inc b/target/s390x/cpu_features_def.h.inc index e86662bb3b8a..e3cfe637354b 100644 --- a/target/s390x/cpu_features_def.h.inc +++ b/target/s390x/cpu_features_def.h.inc @@ -58,7 +58,7 @@ DEF_FEAT(ENHANCED_MONITOR, "emon", STFL, 36, "Enhanced-monitor facility") DEF_FEAT(FLOATING_POINT_EXT, "fpe", STFL, 37, "Floating-point extension facility") DEF_FEAT(ORDER_PRESERVING_COMPRESSION, "opc", STFL, 38, "Order Preserving Compression facility") DEF_FEAT(SET_PROGRAM_PARAMETERS, "sprogp", STFL, 40, "Set-program-parameters facility") -DEF_FEAT(FLOATING_POINT_SUPPPORT_ENH, "fpseh", STFL, 41, "Floating-point-support-enhancement facilities") +DEF_FEAT(FLOATING_POINT_SUPPORT_ENH, "fpseh", STFL, 41, "Floating-point-support-enhancement facilities") DEF_FEAT(DFP, "dfp", STFL, 42, "DFP (decimal-floating-point) facility") DEF_FEAT(DFP_FAST, "dfphp", STFL, 43, "DFP (decimal-floating-point) facility has high performance") DEF_FEAT(PFPO, "pfpo", STFL, 44, "PFPO instruction") @@ -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 6d7142805699..065ec6d66cdb 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -23,8 +23,8 @@ #include "qemu/qemu-print.h" #ifndef CONFIG_USER_ONLY #include "sysemu/sysemu.h" -#endif #include "hw/s390x/pv.h" +#endif #define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \ { \ @@ -89,7 +89,6 @@ static S390CPUDef s390_cpu_defs[] = { #define QEMU_MAX_CPU_TYPE 0x8561 #define QEMU_MAX_CPU_GEN 15 #define QEMU_MAX_CPU_EC_GA 1 -static const S390FeatInit qemu_max_cpu_feat_init = { S390_FEAT_LIST_QEMU_MAX }; static S390FeatBitmap qemu_max_cpu_feat; /* features part of a base model but not relevant for finding a base model */ @@ -237,6 +236,7 @@ bool s390_has_feat(S390Feat feat) return 0; } +#ifndef CONFIG_USER_ONLY if (s390_is_pv()) { switch (feat) { case S390_FEAT_DIAG_318: @@ -260,6 +260,7 @@ bool s390_has_feat(S390Feat feat) break; } } +#endif return test_bit(feat, cpu->model->features); } @@ -335,18 +336,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); } @@ -728,7 +742,6 @@ static void s390_cpu_model_initfn(Object *obj) } } -static S390CPUDef s390_qemu_cpu_def; static S390CPUModel s390_qemu_cpu_model; /* Set the qemu CPU model (on machine initialization). Must not be called @@ -742,17 +755,8 @@ void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, g_assert(def); g_assert(QTAILQ_EMPTY_RCU(&cpus)); - /* TCG emulates some features that can usually not be enabled with - * the emulated machine generation. Make sure they can be enabled - * when using the QEMU model by adding them to full_feat. We have - * to copy the definition to do that. - */ - memcpy(&s390_qemu_cpu_def, def, sizeof(s390_qemu_cpu_def)); - bitmap_or(s390_qemu_cpu_def.full_feat, s390_qemu_cpu_def.full_feat, - qemu_max_cpu_feat, S390_FEAT_MAX); - /* build the CPU model */ - s390_qemu_cpu_model.def = &s390_qemu_cpu_def; + s390_qemu_cpu_model.def = def; bitmap_zero(s390_qemu_cpu_model.features, S390_FEAT_MAX); s390_init_feat_bitmap(feat_init, s390_qemu_cpu_model.features); } @@ -885,9 +889,8 @@ static void s390_max_cpu_model_class_init(ObjectClass *oc, void *data) /* * The "max" model is neither static nor migration safe. Under KVM - * it represents the "host" model. Under TCG it represents some kind of - * "qemu" CPU model without compat handling and maybe with some additional - * CPU features that are not yet unlocked in the "qemu" model. + * it represents the "host" model. Under TCG it represents the "qemu" CPU + * model of the latest QEMU machine. */ xcc->desc = "Enables all features supported by the accelerator in the current host"; @@ -966,13 +969,13 @@ static void init_ignored_base_feat(void) static void register_types(void) { - static const S390FeatInit qemu_latest_init = { S390_FEAT_LIST_QEMU_LATEST }; + static const S390FeatInit qemu_max_init = { S390_FEAT_LIST_QEMU_MAX }; int i; init_ignored_base_feat(); /* init all bitmaps from gnerated data initially */ - s390_init_feat_bitmap(qemu_max_cpu_feat_init, qemu_max_cpu_feat); + s390_init_feat_bitmap(qemu_max_init, qemu_max_cpu_feat); for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { s390_init_feat_bitmap(s390_cpu_defs[i].base_init, s390_cpu_defs[i].base_feat); @@ -982,9 +985,9 @@ static void register_types(void) s390_cpu_defs[i].full_feat); } - /* initialize the qemu model with latest definition */ + /* initialize the qemu model with the maximum definition ("max" model) */ s390_set_qemu_cpu_model(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN, - QEMU_MAX_CPU_EC_GA, qemu_latest_init); + QEMU_MAX_CPU_EC_GA, qemu_max_init); for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { char *base_name = s390_base_cpu_type_name(s390_cpu_defs[i].name); diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index 74d1f87e4fd5..fb1adc8b210b 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -24,13 +24,13 @@ struct S390CPUDef { uint8_t gen; /* hw generation identification */ uint16_t type; /* cpu type identification */ uint8_t ec_ga; /* EC GA version (on which also the BC is based) */ - uint8_t mha_pow; /* Maximum Host Adress Power, mha = 2^pow-1 */ + uint8_t mha_pow; /* maximum host address power, mha = 2^pow-1 */ uint32_t hmfai; /* hypervisor-managed facilities */ /* base/min features, must never be changed between QEMU versions */ S390FeatBitmap base_feat; /* used to init base_feat from generated data */ S390FeatInit base_init; - /* deafault features, QEMU version specific */ + /* default features, QEMU version specific */ S390FeatBitmap default_feat; /* used to init default_feat from generated data */ S390FeatInit default_init; diff --git a/target/s390x/cpu_models_sysemu.c b/target/s390x/cpu_models_sysemu.c index 05c3ccaaff2c..63981bf36b6e 100644 --- a/target/s390x/cpu_models_sysemu.c +++ b/target/s390x/cpu_models_sysemu.c @@ -15,7 +15,6 @@ #include "s390x-internal.h" #include "kvm/kvm_s390x.h" #include "sysemu/kvm.h" -#include "sysemu/tcg.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "qapi/qmp/qerror.h" @@ -211,7 +210,6 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model, qobject_unref(qdict); } else { info->props = QOBJECT(qdict); - info->has_props = true; } } diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 22846121c468..1e3b7c0dc9db 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -374,7 +374,7 @@ static uint16_t base_GEN10_GA1[] = { S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2, S390_FEAT_GENERAL_INSTRUCTIONS_EXT, S390_FEAT_EXECUTE_EXT, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_FLOATING_POINT_SUPPORT_ENH, S390_FEAT_DFP, S390_FEAT_DFP_FAST, S390_FEAT_PFPO, @@ -476,7 +476,7 @@ static uint16_t full_GEN9_GA2[] = { S390_FEAT_MOVE_WITH_OPTIONAL_SPEC, S390_FEAT_EXTRACT_CPU_TIME, S390_FEAT_COMPARE_AND_SWAP_AND_STORE, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_FLOATING_POINT_SUPPORT_ENH, S390_FEAT_DFP, }; @@ -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 */ @@ -700,7 +702,7 @@ static uint16_t qemu_V3_1[] = { S390_FEAT_GENERAL_INSTRUCTIONS_EXT, S390_FEAT_EXECUTE_EXT, S390_FEAT_SET_PROGRAM_PARAMETERS, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_FLOATING_POINT_SUPPORT_ENH, S390_FEAT_STFLE_45, S390_FEAT_STFLE_49, S390_FEAT_LOCAL_TLB_CLEARING, @@ -738,13 +740,24 @@ static uint16_t qemu_V6_2[] = { S390_FEAT_VECTOR_ENH, }; -static uint16_t qemu_LATEST[] = { +static uint16_t qemu_V7_0[] = { S390_FEAT_MISC_INSTRUCTION_EXT3, }; -/* add all new definitions before this point */ + +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[] = { - /* generates a dependency warning, leave it out for now */ S390_FEAT_MSA_EXT_5, + S390_FEAT_KIMD_SHA_512, + S390_FEAT_KLMD_SHA_512, + S390_FEAT_PRNO_TRNG, }; /****** END FEATURE DEFS ******/ @@ -866,7 +879,8 @@ static FeatGroupDefSpec QemuFeatDef[] = { QEMU_FEAT_INITIALIZER(V4_1), QEMU_FEAT_INITIALIZER(V6_0), QEMU_FEAT_INITIALIZER(V6_2), - QEMU_FEAT_INITIALIZER(LATEST), + QEMU_FEAT_INITIALIZER(V7_0), + QEMU_FEAT_INITIALIZER(V7_1), QEMU_FEAT_INITIALIZER(MAX), }; diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 6e35473c7f8a..473c8e51b00e 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -27,7 +27,6 @@ #include "hw/s390x/pv.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" -#include "sysemu/tcg.h" void s390x_tod_timer(void *opaque) { diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 69f69cf7186d..93923ca15358 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -203,8 +203,11 @@ DEF_HELPER_FLAGS_3(gvec_vpopct16, TCG_CALL_NO_RWG, void, ptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_verim8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_verim16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vsl, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32) +DEF_HELPER_FLAGS_4(gvec_vsl_ve2, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vsra, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32) +DEF_HELPER_FLAGS_4(gvec_vsra_ve2, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vsrl, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32) +DEF_HELPER_FLAGS_4(gvec_vsrl_ve2, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vscbi8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vscbi16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_4(gvec_vtm, void, ptr, cptr, env, i32) @@ -246,6 +249,12 @@ DEF_HELPER_6(gvec_vstrc_cc32, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_6(gvec_vstrc_cc_rt8, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_6(gvec_vstrc_cc_rt16, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_6(gvec_vstrs_8, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_6(gvec_vstrs_16, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_6(gvec_vstrs_32, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_6(gvec_vstrs_zs8, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_6(gvec_vstrs_zs16, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_6(gvec_vstrs_zs32, void, ptr, cptr, cptr, cptr, env, i32) /* === Vector Floating-Point Instructions */ DEF_HELPER_FLAGS_5(gvec_vfa32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) @@ -275,6 +284,10 @@ DEF_HELPER_FLAGS_5(gvec_vfche64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32 DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfche128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfche128_cc, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vcdg32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vcdlg32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vcgd32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vclgd32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) @@ -340,8 +353,8 @@ DEF_HELPER_FLAGS_3(tprot, TCG_CALL_NO_WG, i32, env, i64, i64) DEF_HELPER_2(iske, i64, env, i64) DEF_HELPER_3(sske, void, env, i64, i64) DEF_HELPER_2(rrbe, i32, env, i64) -DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) -DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) +DEF_HELPER_5(mvcs, i32, env, i64, i64, i64, i64) +DEF_HELPER_5(mvcp, i32, env, i64, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i32) DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_4(idte, TCG_CALL_NO_RWG, void, env, i64, i64, i32) diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index bdae5090bc8c..053aaabb5a64 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -284,8 +284,8 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, g_assert(!s390_is_pv()); /* * As operand exceptions have a lower priority than access exceptions, - * we check whether the memory area is writeable (injecting the - * access execption if it is not) first. + * we check whether the memory area is writable (injecting the + * access exception if it is not) first. */ if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { s390_program_interrupt(env, PGM_OPERAND, ra); diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 6acf14d5ecb4..3ac7ec9acf4e 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -24,7 +24,6 @@ #include #include -#include "qemu-common.h" #include "cpu.h" #include "s390x-internal.h" #include "kvm_s390x.h" @@ -152,11 +151,16 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static int cap_sync_regs; static int cap_async_pf; static int cap_mem_op; +static int cap_mem_op_extension; static int cap_s390_irq; static int cap_ri; static int cap_hpage_1m; static int cap_vcpu_resets; static int cap_protected; +static int cap_zpci_op; +static int cap_protected_dump; + +static bool mem_op_storage_key_support; static int active_cmma; @@ -355,9 +359,13 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); + cap_mem_op_extension = kvm_check_extension(s, KVM_CAP_S390_MEM_OP_EXTENSION); + mem_op_storage_key_support = cap_mem_op_extension > 0; 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); + cap_protected_dump = kvm_check_extension(s, KVM_CAP_S390_PROTECTED_DUMP); kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0); kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0); @@ -843,6 +851,7 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, : KVM_S390_MEMOP_LOGICAL_READ, .buf = (uint64_t)hostbuf, .ar = ar, + .key = (cpu->env.psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY, }; int ret; @@ -852,6 +861,9 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, if (!hostbuf) { mem_op.flags |= KVM_S390_MEMOP_F_CHECK_ONLY; } + if (mem_op_storage_key_support) { + mem_op.flags |= KVM_S390_MEMOP_F_SKEY_PROTECTION; + } ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op); if (ret < 0) { @@ -1023,7 +1035,7 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr, } size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint); hw_breakpoints = - (struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size); + g_realloc(hw_breakpoints, size); } else { g_free(hw_breakpoints); hw_breakpoints = NULL; @@ -2035,6 +2047,11 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); } +int kvm_s390_get_protected_dump(void) +{ + return cap_protected_dump; +} + int kvm_s390_get_ri(void) { return cap_ri; @@ -2566,3 +2583,12 @@ bool kvm_arch_cpu_check_are_resettable(void) { return true; } + +int kvm_s390_get_zpci_op(void) +{ + return cap_zpci_op; +} + +void kvm_arch_accel_class_init(ObjectClass *oc) +{ +} diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h index 05a5e1e6f46d..f9785564d0ba 100644 --- a/target/s390x/kvm/kvm_s390x.h +++ b/target/s390x/kvm/kvm_s390x.h @@ -26,7 +26,9 @@ int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); 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_protected_dump(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/kvm/meson.build b/target/s390x/kvm/meson.build index d1356356b1f6..aef52b6686b3 100644 --- a/target/s390x/kvm/meson.build +++ b/target/s390x/kvm/meson.build @@ -1,6 +1,8 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files( 'kvm.c' +), if_false: files( + 'stubs.c' )) # Newer kernels on s390 check for an S390_PGSTE program header and diff --git a/target/s390x/kvm/stubs.c b/target/s390x/kvm/stubs.c new file mode 100644 index 000000000000..5fd63b9a7e32 --- /dev/null +++ b/target/s390x/kvm/stubs.c @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "kvm_s390x.h" + +int kvm_s390_get_protected_dump(void) +{ + return false; +} diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h index 6fc8cad2d586..5d4361d35b5e 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 */ @@ -280,9 +280,9 @@ void s390_cpu_record_sigbus(CPUState *cs, vaddr address, bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); -void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); #endif @@ -398,7 +398,9 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, /* translate.c */ void s390x_translate_init(void); - +void s390x_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data); /* sigp.c */ int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3); diff --git a/target/s390x/tcg/cc_helper.c b/target/s390x/tcg/cc_helper.c index b2e8d3d9f597..b36f8cdc8b9e 100644 --- a/target/s390x/tcg/cc_helper.c +++ b/target/s390x/tcg/cc_helper.c @@ -487,6 +487,10 @@ void HELPER(sacf)(CPUS390XState *env, uint64_t a1) { HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); + if (!(env->psw.mask & PSW_MASK_DAT)) { + tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC()); + } + switch (a1 & 0xf00) { case 0x000: env->psw.mask &= ~PSW_MASK_ASC; @@ -497,6 +501,9 @@ void HELPER(sacf)(CPUS390XState *env, uint64_t a1) env->psw.mask |= PSW_ASC_SECONDARY; break; case 0x300: + if ((env->psw.mask & PSW_MASK_PSTATE) != 0) { + tcg_s390_program_interrupt(env, PGM_PRIVILEGED, GETPC()); + } env->psw.mask &= ~PSW_MASK_ASC; env->psw.mask |= PSW_ASC_HOME; break; diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 138d9e7ad956..762b2778840c 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/excp_helper.c b/target/s390x/tcg/excp_helper.c index be6c966cfa4c..bc767f044381 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -21,33 +21,33 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "s390x-internal.h" #include "exec/helper-proto.h" -#include "qemu/timer.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "hw/s390x/ioinst.h" -#include "exec/address-spaces.h" +#include "s390x-internal.h" #include "tcg_s390x.h" #ifndef CONFIG_USER_ONLY +#include "qemu/timer.h" +#include "exec/address-spaces.h" +#include "hw/s390x/ioinst.h" #include "hw/s390x/s390_flic.h" #include "hw/boards.h" #endif -void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, - uint32_t code, uintptr_t ra) +G_NORETURN void tcg_s390_program_interrupt(CPUS390XState *env, + uint32_t code, uintptr_t ra) { CPUState *cs = env_cpu(env); - cpu_restore_state(cs, ra, true); + cpu_restore_state(cs, ra); qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", env->psw.addr); trigger_pgm_exception(env, code); cpu_loop_exit(cs); } -void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc, - uintptr_t ra) +G_NORETURN void tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc, + uintptr_t ra) { g_assert(dxc <= 0xff); #if !defined(CONFIG_USER_ONLY) @@ -63,8 +63,8 @@ void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc, tcg_s390_program_interrupt(env, PGM_DATA, ra); } -void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc, - uintptr_t ra) +G_NORETURN void tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc, + uintptr_t ra) { g_assert(vxc <= 0xff); #if !defined(CONFIG_USER_ONLY) @@ -88,7 +88,8 @@ void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc) * this is only for the atomic operations, for which we want to raise a * specification exception. */ -static void QEMU_NORETURN do_unaligned_access(CPUState *cs, uintptr_t retaddr) +static G_NORETURN +void do_unaligned_access(CPUState *cs, uintptr_t retaddr) { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; @@ -552,7 +553,7 @@ void s390_cpu_do_interrupt(CPUState *cs) /* don't trigger a cpu_loop_exit(), use an interrupt instead */ cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT); } else if (cs->halted) { - /* unhalt if we had a WAIT PSW somehwere in our injection chain */ + /* unhalt if we had a WAIT PSW somewhere in our injection chain */ s390_cpu_unhalt(cpu); } } @@ -620,9 +621,10 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, do_unaligned_access(cs, retaddr); } -static void QEMU_NORETURN monitor_event(CPUS390XState *env, - uint64_t monitor_code, - uint8_t monitor_class, uintptr_t ra) +static G_NORETURN +void monitor_event(CPUS390XState *env, + uint64_t monitor_code, + uint8_t monitor_class, uintptr_t ra) { /* Store the Monitor Code and the Monitor Class Number into the lowcore */ stq_phys(env_cpu(env)->as, diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index 40672054052a..be80b2373c36 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -89,7 +89,7 @@ static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) /* * invalid/divbyzero cannot coexist with other conditions. * overflow/underflow however can coexist with inexact, we have to - * handle it separatly. + * handle it separately. */ if (s390_exc & ~S390_IEEE_MASK_INEXACT) { if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { diff --git a/target/s390x/tcg/insn-data.def b/target/s390x/tcg/insn-data.def deleted file mode 100644 index 6c8a8b229fbb..000000000000 --- a/target/s390x/tcg/insn-data.def +++ /dev/null @@ -1,1422 +0,0 @@ -/* - * Arguments to the opcode prototypes - * - * C(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC) - * D(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC, DATA) - * E(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC, DATA, FLAGS) - * F(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC, FLAGS) - * - * OPC = (op << 8) | op2 where op is the major, op2 the minor opcode - * NAME = name of the opcode, used internally - * FMT = format of the opcode (defined in insn-format.def) - * FAC = facility the opcode is available in (defined in DisasFacility) - * I1 = func in1_xx fills o->in1 - * I2 = func in2_xx fills o->in2 - * P = func prep_xx initializes o->*out* - * W = func wout_xx writes o->*out* somewhere - * OP = func op_xx does the bulk of the operation - * CC = func cout_xx defines how cc should get set - * DATA = immediate argument to op_xx function - * FLAGS = categorize the type of instruction (e.g. for advanced checks) - * - * The helpers get called in order: I1, I2, P, OP, W, CC - */ - -/* ADD */ - C(0x1a00, AR, RR_a, Z, r1, r2, new, r1_32, add, adds32) - C(0xb9f8, ARK, RRF_a, DO, r2, r3, new, r1_32, add, adds32) - C(0x5a00, A, RX_a, Z, r1, m2_32s, new, r1_32, add, adds32) - C(0xe35a, AY, RXY_a, LD, r1, m2_32s, new, r1_32, add, adds32) - C(0xb908, AGR, RRE, Z, r1, r2, r1, 0, add, adds64) - C(0xb918, AGFR, RRE, Z, r1, r2_32s, r1, 0, add, adds64) - C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) - C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) - C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) - F(0xb30a, AEBR, RRE, Z, e1, e2, new, e1, aeb, f32, IF_BFP) - F(0xb31a, ADBR, RRE, Z, f1, f2, new, f1, adb, f64, IF_BFP) - F(0xb34a, AXBR, RRE, Z, x2h, x2l, x1, x1, axb, f128, IF_BFP) - F(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32, IF_BFP) - F(0xed1a, ADB, RXE, Z, f1, m2_64, new, f1, adb, f64, IF_BFP) -/* ADD HIGH */ - C(0xb9c8, AHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, adds32) - C(0xb9d8, AHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, adds32) -/* ADD IMMEDIATE */ - C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) - D(0xeb6a, ASI, SIY, GIE, la1, i2, new, 0, asi, adds32, MO_TESL) - C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32) - C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) - D(0xeb7a, AGSI, SIY, GIE, la1, i2, new, 0, asi, adds64, MO_TEUQ) - C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) -/* ADD IMMEDIATE HIGH */ - C(0xcc08, AIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, adds32) -/* ADD HALFWORD */ - C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) - C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) - C(0xe338, AGH, RXY_a, MIE2,r1, m2_16s, r1, 0, add, adds64) -/* ADD HALFWORD IMMEDIATE */ - C(0xa70a, AHI, RI_a, Z, r1, i2, new, r1_32, add, adds32) - C(0xa70b, AGHI, RI_a, Z, r1, i2, r1, 0, add, adds64) - -/* ADD LOGICAL */ - C(0x1e00, ALR, RR_a, Z, r1_32u, r2_32u, new, r1_32, add, addu32) - C(0xb9fa, ALRK, RRF_a, DO, r2_32u, r3_32u, new, r1_32, add, addu32) - C(0x5e00, AL, RX_a, Z, r1_32u, m2_32u, new, r1_32, add, addu32) - C(0xe35e, ALY, RXY_a, LD, r1_32u, m2_32u, new, r1_32, add, addu32) - C(0xb90a, ALGR, RRE, Z, r1, r2, r1, 0, addu64, addu64) - C(0xb91a, ALGFR, RRE, Z, r1, r2_32u, r1, 0, addu64, addu64) - C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, addu64, addu64) - C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, addu64, addu64) - C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, addu64, addu64) -/* ADD LOGICAL HIGH */ - C(0xb9ca, ALHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, addu32) - C(0xb9da, ALHHLR, RRF_a, HW, r2_sr32, r3_32u, new, r1_32h, add, addu32) -/* ADD LOGICAL IMMEDIATE */ - C(0xc20b, ALFI, RIL_a, EI, r1_32u, i2_32u, new, r1_32, add, addu32) - C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, addu64, addu64) -/* ADD LOGICAL WITH SIGNED IMMEDIATE */ - D(0xeb6e, ALSI, SIY, GIE, la1, i2_32u, new, 0, asi, addu32, MO_TEUL) - C(0xecda, ALHSIK, RIE_d, DO, r3_32u, i2_32u, new, r1_32, add, addu32) - D(0xeb7e, ALGSI, SIY, GIE, la1, i2, new, 0, asiu64, addu64, MO_TEUQ) - C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, addu64, addu64) -/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */ - C(0xcc0a, ALSIH, RIL_a, HW, r1_sr32, i2_32u, new, r1_32h, add, addu32) - C(0xcc0b, ALSIHN, RIL_a, HW, r1_sr32, i2_32u, new, r1_32h, add, 0) -/* ADD LOGICAL WITH CARRY */ - C(0xb998, ALCR, RRE, Z, r1_32u, r2_32u, new, r1_32, addc32, addu32) - C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc64, addu64) - C(0xe398, ALC, RXY_a, Z, r1_32u, m2_32u, new, r1_32, addc32, addu32) - C(0xe388, ALCG, RXY_a, Z, r1, m2_64, r1, 0, addc64, addu64) - -/* AND */ - C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) - C(0xb9f4, NRK, RRF_a, DO, r2, r3, new, r1_32, and, nz32) - C(0x5400, N, RX_a, Z, r1, m2_32s, new, r1_32, and, nz32) - C(0xe354, NY, RXY_a, LD, r1, m2_32s, new, r1_32, and, nz32) - C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) - C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) - C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) - C(0xd400, NC, SS_a, Z, la1, a2, 0, 0, nc, 0) -/* AND IMMEDIATE */ - D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) - D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) - D(0xa504, NIHH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1030) - D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) - D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) - D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) - D(0x9400, NI, SI, Z, la1, i2_8u, new, 0, ni, nz64, MO_UB) - D(0xeb54, NIY, SIY, LD, la1, i2_8u, new, 0, ni, nz64, MO_UB) -/* AND WITH COMPLEMENT */ - C(0xb9f5, NCRK, RRF_a, MIE3, r2, r3, new, r1_32, andc, nz32) - C(0xb9e5, NCGRK, RRF_a, MIE3, r2, r3, r1, 0, andc, nz64) - -/* BRANCH AND LINK */ - C(0x0500, BALR, RR_a, Z, 0, r2_nz, r1, 0, bal, 0) - C(0x4500, BAL, RX_a, Z, 0, a2, r1, 0, bal, 0) -/* BRANCH AND SAVE */ - C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) - C(0x4d00, BAS, RX_a, Z, 0, a2, r1, 0, bas, 0) -/* BRANCH RELATIVE AND SAVE */ - C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) - C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) -/* BRANCH INDIRECT ON CONDITION */ - C(0xe347, BIC, RXY_b, MIE2,0, m2_64w, 0, 0, bc, 0) -/* BRANCH ON CONDITION */ - C(0x0700, BCR, RR_b, Z, 0, r2_nz, 0, 0, bc, 0) - C(0x4700, BC, RX_b, Z, 0, a2, 0, 0, bc, 0) -/* BRANCH RELATIVE ON CONDITION */ - C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) - C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) -/* BRANCH ON COUNT */ - C(0x0600, BCTR, RR_a, Z, 0, r2_nz, 0, 0, bct32, 0) - C(0xb946, BCTGR, RRE, Z, 0, r2_nz, 0, 0, bct64, 0) - C(0x4600, BCT, RX_a, Z, 0, a2, 0, 0, bct32, 0) - C(0xe346, BCTG, RXY_a, Z, 0, a2, 0, 0, bct64, 0) -/* BRANCH RELATIVE ON COUNT */ - C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) - C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) -/* BRANCH RELATIVE ON COUNT HIGH */ - C(0xcc06, BRCTH, RIL_b, HW, 0, 0, 0, 0, bcth, 0) -/* BRANCH ON INDEX */ - D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) - D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) - D(0xeb44, BXHG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 0) - D(0xeb45, BXLEG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 1) -/* BRANCH RELATIVE ON INDEX */ - D(0x8400, BRXH, RSI, Z, 0, 0, 0, 0, bx32, 0, 0) - D(0x8500, BRXLE, RSI, Z, 0, 0, 0, 0, bx32, 0, 1) - D(0xec44, BRXHG, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 0) - D(0xec45, BRXHLE, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 1) -/* BRANCH PREDICTION PRELOAD */ - /* ??? Format is SMI, but implemented as NOP, so we need no fields. */ - C(0xc700, BPP, E, EH, 0, 0, 0, 0, 0, 0) -/* BRANCH PREDICTION RELATIVE PRELOAD */ - /* ??? Format is MII, but implemented as NOP, so we need no fields. */ - C(0xc500, BPRP, E, EH, 0, 0, 0, 0, 0, 0) -/* NEXT INSTRUCTION ACCESS INTENT */ - /* ??? Format is IE, but implemented as NOP, so we need no fields. */ - C(0xb2fa, NIAI, E, EH, 0, 0, 0, 0, 0, 0) - -/* CHECKSUM */ - C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) - -/* COPY SIGN */ - F(0xb372, CPSDR, RRF_b, FPSSH, f3, f2, new, f1, cps, 0, IF_AFP1 | IF_AFP2 | IF_AFP3) - -/* COMPARE */ - C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) - C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) - C(0xe359, CY, RXY_a, LD, r1_o, m2_32s, 0, 0, 0, cmps32) - C(0xb920, CGR, RRE, Z, r1_o, r2_o, 0, 0, 0, cmps64) - C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) - C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) - C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) - F(0xb309, CEBR, RRE, Z, e1, e2, 0, 0, ceb, 0, IF_BFP) - F(0xb319, CDBR, RRE, Z, f1, f2, 0, 0, cdb, 0, IF_BFP) - F(0xb349, CXBR, RRE, Z, x2h, x2l, x1, 0, cxb, 0, IF_BFP) - F(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0, IF_BFP) - F(0xed19, CDB, RXE, Z, f1, m2_64, 0, 0, cdb, 0, IF_BFP) -/* COMPARE AND SIGNAL */ - F(0xb308, KEBR, RRE, Z, e1, e2, 0, 0, keb, 0, IF_BFP) - F(0xb318, KDBR, RRE, Z, f1, f2, 0, 0, kdb, 0, IF_BFP) - F(0xb348, KXBR, RRE, Z, x2h, x2l, x1, 0, kxb, 0, IF_BFP) - F(0xed08, KEB, RXE, Z, e1, m2_32u, 0, 0, keb, 0, IF_BFP) - F(0xed18, KDB, RXE, Z, f1, m2_64, 0, 0, kdb, 0, IF_BFP) -/* COMPARE IMMEDIATE */ - C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) - C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) -/* COMPARE RELATIVE LONG */ - C(0xc60d, CRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32) - C(0xc608, CGRL, RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64) - C(0xc60c, CGFRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64) -/* COMPARE HALFWORD */ - C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) - C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) - C(0xe334, CGH, RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64) -/* COMPARE HALFWORD IMMEDIATE */ - C(0xa70e, CHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps32) - C(0xa70f, CGHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps64) - C(0xe554, CHHSI, SIL, GIE, m1_16s, i2, 0, 0, 0, cmps64) - C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64) - C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64) -/* COMPARE HALFWORD RELATIVE LONG */ - C(0xc605, CHRL, RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) - C(0xc604, CGHRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) -/* COMPARE HIGH */ - C(0xb9cd, CHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmps32) - C(0xb9dd, CHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmps32) - C(0xe3cd, CHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmps32) -/* COMPARE IMMEDIATE HIGH */ - C(0xcc0d, CIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmps32) - -/* COMPARE LOGICAL */ - C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) - C(0x5500, CL, RX_a, Z, r1, m2_32s, 0, 0, 0, cmpu32) - C(0xe355, CLY, RXY_a, LD, r1, m2_32s, 0, 0, 0, cmpu32) - C(0xb921, CLGR, RRE, Z, r1, r2, 0, 0, 0, cmpu64) - C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) - C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) - C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) - C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0) -/* COMPARE LOGICAL HIGH */ - C(0xb9cf, CLHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmpu32) - C(0xb9df, CLHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmpu32) - C(0xe3cf, CLHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmpu32) -/* COMPARE LOGICAL IMMEDIATE */ - C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) - C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) - C(0x9500, CLI, SI, Z, m1_8u, i2_8u, 0, 0, 0, cmpu64) - C(0xeb55, CLIY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, cmpu64) - C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64) - C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64) - C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64) -/* COMPARE LOGICAL IMMEDIATE HIGH */ - C(0xcc0f, CLIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmpu32) -/* COMPARE LOGICAL RELATIVE LONG */ - C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32) - C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64) - C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) - C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) - C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) -/* COMPARE LOGICAL LONG */ - C(0x0f00, CLCL, RR_a, Z, 0, 0, 0, 0, clcl, 0) -/* COMPARE LOGICAL LONG EXTENDED */ - C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) -/* COMPARE LOGICAL LONG UNICODE */ - C(0xeb8f, CLCLU, RSY_a, E2, 0, a2, 0, 0, clclu, 0) -/* COMPARE LOGICAL CHARACTERS UNDER MASK */ - C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) - C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) - C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) -/* COMPARE LOGICAL STRING */ - C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) - -/* COMPARE AND BRANCH */ - D(0xecf6, CRB, RRS, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) - D(0xece4, CGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) - D(0xec76, CRJ, RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) - D(0xec64, CGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) - D(0xecfe, CIB, RIS, GIE, r1_32s, i2, 0, 0, cj, 0, 0) - D(0xecfc, CGIB, RIS, GIE, r1_o, i2, 0, 0, cj, 0, 0) - D(0xec7e, CIJ, RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0) - D(0xec7c, CGIJ, RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0) -/* COMPARE LOGICAL AND BRANCH */ - D(0xecf7, CLRB, RRS, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) - D(0xece5, CLGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) - D(0xec77, CLRJ, RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) - D(0xec65, CLGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) - D(0xecff, CLIB, RIS, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) - D(0xecfd, CLGIB, RIS, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) - D(0xec7f, CLIJ, RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) - D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) - -/* COMPARE AND SWAP */ - D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL) - D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL) - D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, MO_TEUQ) -/* COMPARE DOUBLE AND SWAP */ - D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ) - D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ) - C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0) -/* COMPARE AND SWAP AND STORE */ - C(0xc802, CSST, SSF, CASS, la1, a2, 0, 0, csst, 0) - -/* COMPARE AND TRAP */ - D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) - D(0xb960, CGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0) - D(0xec72, CIT, RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0) - D(0xec70, CGIT, RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0) -/* COMPARE LOGICAL AND TRAP */ - D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) - 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) - -/* CONVERT TO DECIMAL */ - C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) - C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) -/* CONVERT TO FIXED */ - F(0xb398, CFEBR, RRF_e, Z, 0, e2, new, r1_32, cfeb, 0, IF_BFP) - F(0xb399, CFDBR, RRF_e, Z, 0, f2, new, r1_32, cfdb, 0, IF_BFP) - F(0xb39a, CFXBR, RRF_e, Z, x2h, x2l, new, r1_32, cfxb, 0, IF_BFP) - F(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0, IF_BFP) - F(0xb3a9, CGDBR, RRF_e, Z, 0, f2, r1, 0, cgdb, 0, IF_BFP) - F(0xb3aa, CGXBR, RRF_e, Z, x2h, x2l, r1, 0, cgxb, 0, IF_BFP) -/* CONVERT FROM FIXED */ - F(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0, IF_BFP) - F(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, new, f1, cdgb, 0, IF_BFP) - F(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, new_P, x1, cxgb, 0, IF_BFP) - F(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0, IF_BFP) - F(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, new, f1, cdgb, 0, IF_BFP) - F(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, new_P, x1, cxgb, 0, IF_BFP) -/* CONVERT TO LOGICAL */ - F(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0, IF_BFP) - F(0xb39d, CLFDBR, RRF_e, FPE, 0, f2, new, r1_32, clfdb, 0, IF_BFP) - F(0xb39e, CLFXBR, RRF_e, FPE, x2h, x2l, new, r1_32, clfxb, 0, IF_BFP) - F(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0, IF_BFP) - F(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2, r1, 0, clgdb, 0, IF_BFP) - F(0xb3ae, CLGXBR, RRF_e, FPE, x2h, x2l, r1, 0, clgxb, 0, IF_BFP) -/* CONVERT FROM LOGICAL */ - F(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0, IF_BFP) - F(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, new, f1, cdlgb, 0, IF_BFP) - F(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, new_P, x1, cxlgb, 0, IF_BFP) - F(0xb3a0, CELGBR, RRF_e, FPE, 0, r2_o, new, e1, celgb, 0, IF_BFP) - F(0xb3a1, CDLGBR, RRF_e, FPE, 0, r2_o, new, f1, cdlgb, 0, IF_BFP) - F(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, new_P, x1, cxlgb, 0, IF_BFP) - -/* CONVERT UTF-8 TO UTF-16 */ - D(0xb2a7, CU12, RRF_c, Z, 0, 0, 0, 0, cuXX, 0, 12) -/* CONVERT UTF-8 TO UTF-32 */ - D(0xb9b0, CU14, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 14) -/* CONVERT UTF-16 to UTF-8 */ - D(0xb2a6, CU21, RRF_c, Z, 0, 0, 0, 0, cuXX, 0, 21) -/* CONVERT UTF-16 to UTF-32 */ - D(0xb9b1, CU24, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 24) -/* CONVERT UTF-32 to UTF-8 */ - D(0xb9b2, CU41, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 41) -/* CONVERT UTF-32 to UTF-16 */ - D(0xb9b3, CU42, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 42) - -/* DIVIDE */ - C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) - C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) - F(0xb30d, DEBR, RRE, Z, e1, e2, new, e1, deb, 0, IF_BFP) - F(0xb31d, DDBR, RRE, Z, f1, f2, new, f1, ddb, 0, IF_BFP) - F(0xb34d, DXBR, RRE, Z, x2h, x2l, x1, x1, dxb, 0, IF_BFP) - F(0xed0d, DEB, RXE, Z, e1, m2_32u, new, e1, deb, 0, IF_BFP) - F(0xed1d, DDB, RXE, Z, f1, m2_64, new, f1, ddb, 0, IF_BFP) -/* DIVIDE LOGICAL */ - C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) - C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) - C(0xb987, DLGR, RRE, Z, 0, r2_o, r1_P, 0, divu64, 0) - C(0xe387, DLG, RXY_a, Z, 0, m2_64, r1_P, 0, divu64, 0) -/* DIVIDE SINGLE */ - C(0xb90d, DSGR, RRE, Z, r1p1, r2, r1_P, 0, divs64, 0) - C(0xb91d, DSGFR, RRE, Z, r1p1, r2_32s, r1_P, 0, divs64, 0) - C(0xe30d, DSG, RXY_a, Z, r1p1, m2_64, r1_P, 0, divs64, 0) - C(0xe31d, DSGF, RXY_a, Z, r1p1, m2_32s, r1_P, 0, divs64, 0) - -/* EXCLUSIVE OR */ - C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) - C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) - C(0x5700, X, RX_a, Z, r1, m2_32s, new, r1_32, xor, nz32) - C(0xe357, XY, RXY_a, LD, r1, m2_32s, new, r1_32, xor, nz32) - C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) - C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) - C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) - C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0) -/* EXCLUSIVE OR IMMEDIATE */ - D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) - D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) - D(0x9700, XI, SI, Z, la1, i2_8u, new, 0, xi, nz64, MO_UB) - D(0xeb57, XIY, SIY, LD, la1, i2_8u, new, 0, xi, nz64, MO_UB) - -/* EXECUTE */ - C(0x4400, EX, RX_a, Z, 0, a2, 0, 0, ex, 0) -/* EXECUTE RELATIVE LONG */ - C(0xc600, EXRL, RIL_b, EE, 0, ri2, 0, 0, ex, 0) - -/* EXTRACT ACCESS */ - C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) -/* EXTRACT CPU ATTRIBUTE */ - C(0xeb4c, ECAG, RSY_a, GIE, 0, a2, r1, 0, ecag, 0) -/* EXTRACT CPU TIME */ - F(0xc801, ECTG, SSF, ECT, 0, 0, 0, 0, ectg, 0, IF_IO) -/* EXTRACT FPC */ - F(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0, IF_BFP) -/* EXTRACT PSW */ - C(0xb98d, EPSW, RRE, Z, 0, 0, 0, 0, epsw, 0) - -/* FIND LEFTMOST ONE */ - C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0) - -/* INSERT CHARACTER */ - C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) - C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) -/* INSERT CHARACTERS UNDER MASK */ - D(0xbf00, ICM, RS_b, Z, 0, a2, r1, 0, icm, 0, 0) - D(0xeb81, ICMY, RSY_b, LD, 0, a2, r1, 0, icm, 0, 0) - D(0xeb80, ICMH, RSY_b, Z, 0, a2, r1, 0, icm, 0, 32) -/* INSERT IMMEDIATE */ - D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) - D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) - D(0xa500, IIHH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1030) - D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) - D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) - D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) -/* INSERT PROGRAM MASK */ - C(0xb222, IPM, RRE, Z, 0, 0, r1, 0, ipm, 0) - -/* LOAD */ - C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) - C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) - C(0xe358, LY, RXY_a, LD, 0, a2, new, r1_32, ld32s, 0) - C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) - C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) - C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) - C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) - F(0x2800, LDR, RR_a, Z, 0, f2, 0, f1, mov2, 0, IF_AFP1 | IF_AFP2) - F(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0, IF_AFP1) - F(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0, IF_AFP1) - F(0x3800, LER, RR_a, Z, 0, e2, 0, cond_e1e2, mov2, 0, IF_AFP1 | IF_AFP2) - F(0x7800, LE, RX_a, Z, 0, m2_32u, 0, e1, mov2, 0, IF_AFP1) - F(0xed64, LEY, RXY_a, LD, 0, m2_32u, 0, e1, mov2, 0, IF_AFP1) - F(0xb365, LXR, RRE, Z, x2h, x2l, 0, x1, movx, 0, IF_AFP1) -/* LOAD IMMEDIATE */ - C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) -/* LOAD RELATIVE LONG */ - C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) - C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) - C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) -/* LOAD ADDRESS */ - C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) - C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) -/* LOAD ADDRESS EXTENDED */ - C(0x5100, LAE, RX_a, Z, 0, a2, 0, r1, mov2e, 0) - C(0xe375, LAEY, RXY_a, GIE, 0, a2, 0, r1, mov2e, 0) -/* LOAD ADDRESS RELATIVE LONG */ - C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) -/* LOAD AND ADD */ - D(0xebf8, LAA, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, laa, adds32, MO_TESL) - D(0xebe8, LAAG, RSY_a, ILA, r3, a2, new, in2_r1, laa, adds64, MO_TEUQ) -/* LOAD AND ADD LOGICAL */ - D(0xebfa, LAAL, RSY_a, ILA, r3_32u, a2, new, in2_r1_32, laa, addu32, MO_TEUL) - D(0xebea, LAALG, RSY_a, ILA, r3, a2, new, in2_r1, laa, addu64, MO_TEUQ) -/* LOAD AND AND */ - D(0xebf4, LAN, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lan, nz32, MO_TESL) - D(0xebe4, LANG, RSY_a, ILA, r3, a2, new, in2_r1, lan, nz64, MO_TEUQ) -/* LOAD AND EXCLUSIVE OR */ - D(0xebf7, LAX, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lax, nz32, MO_TESL) - D(0xebe7, LAXG, RSY_a, ILA, r3, a2, new, in2_r1, lax, nz64, MO_TEUQ) -/* LOAD AND OR */ - D(0xebf6, LAO, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lao, nz32, MO_TESL) - D(0xebe6, LAOG, RSY_a, ILA, r3, a2, new, in2_r1, lao, nz64, MO_TEUQ) -/* LOAD AND TEST */ - C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32) - C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64) - C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64) - C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) - C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) - C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) - F(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32, IF_BFP) - F(0xb312, LTDBR, RRE, Z, 0, f2, 0, f1, mov2, f64, IF_BFP) - F(0xb342, LTXBR, RRE, Z, x2h, x2l, 0, x1, movx, f128, IF_BFP) -/* LOAD AND TRAP */ - 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(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) -/* LOAD BYTE */ - C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) - C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) - C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) - C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) -/* LOAD BYTE HIGH */ - C(0xe3c0, LBH, RXY_a, HW, 0, a2, new, r1_32h, ld8s, 0) -/* LOAD COMPLEMENT */ - C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) - C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) - C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) - F(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32, IF_BFP) - F(0xb313, LCDBR, RRE, Z, 0, f2, new, f1, negf64, f64, IF_BFP) - F(0xb343, LCXBR, RRE, Z, x2h, x2l, new_P, x1, negf128, f128, IF_BFP) - F(0xb373, LCDFR, RRE, FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2) -/* LOAD COUNT TO BLOCK BOUNDARY */ - C(0xe727, LCBB, RXE, V, la2, 0, r1, 0, lcbb, 0) -/* LOAD HALFWORD */ - C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) - C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) - C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0) - C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0) - C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0) -/* LOAD HALFWORD HIGH */ - C(0xe3c4, LHH, RXY_a, HW, 0, a2, new, r1_32h, ld16s, 0) -/* LOAD HALFWORD IMMEDIATE */ - C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0) - C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0) -/* LOAD HALFWORD RELATIVE LONG */ - C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) - C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) -/* LOAD HIGH */ - C(0xe3ca, LFH, RXY_a, HW, 0, a2, new, r1_32h, ld32u, 0) -/* LOAG HIGH AND TRAP */ - C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0) -/* LOAD LOGICAL */ - C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) - C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) -/* LOAD LOGICAL AND TRAP */ - C(0xe39d, LLGFAT, RXY_a, LAT, 0, a2, r1, 0, llgfat, 0) -/* LOAD LOGICAL RELATIVE LONG */ - C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) -/* LOAD LOGICAL CHARACTER */ - C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0) - C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) - C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0) - C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0) -/* LOAD LOGICAL CHARACTER HIGH */ - C(0xe3c2, LLCH, RXY_a, HW, 0, a2, new, r1_32h, ld8u, 0) -/* LOAD LOGICAL HALFWORD */ - C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0) - C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0) - C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0) - C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0) -/* LOAD LOGICAL HALFWORD HIGH */ - C(0xe3c6, LLHH, RXY_a, HW, 0, a2, new, r1_32h, ld16u, 0) -/* LOAD LOGICAL HALFWORD RELATIVE LONG */ - C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) - C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) -/* LOAD LOGICAL IMMEDATE */ - D(0xc00e, LLIHF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32) - D(0xc00f, LLILF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0) - D(0xa50c, LLIHH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 48) - D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) - D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) - D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) -/* LOAD LOGICAL THIRTY ONE BITS */ - C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) - C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) -/* LOAD LOGICAL THIRTY ONE BITS AND TRAP */ - C(0xe39c, LLGTAT, RXY_a, LAT, 0, m2_32u, r1, 0, llgtat, 0) - -/* LOAD FPR FROM GR */ - F(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0, IF_AFP1) -/* LOAD GR FROM FPR */ - F(0xb3cd, LGDR, RRE, FPRGR, 0, f2, 0, r1, mov2, 0, IF_AFP2) -/* LOAD NEGATIVE */ - C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) - C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) - C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) - F(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32, IF_BFP) - F(0xb311, LNDBR, RRE, Z, 0, f2, new, f1, nabsf64, f64, IF_BFP) - F(0xb341, LNXBR, RRE, Z, x2h, x2l, new_P, x1, nabsf128, f128, IF_BFP) - F(0xb371, LNDFR, RRE, FPSSH, 0, f2, new, f1, nabsf64, 0, IF_AFP1 | IF_AFP2) -/* LOAD ON CONDITION */ - C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) - C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0) - C(0xebf2, LOC, RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0) - C(0xebe2, LOCG, RSY_b, LOC, r1, m2_64, r1, 0, loc, 0) -/* LOAD HALFWORD IMMEDIATE ON CONDITION */ - C(0xec42, LOCHI, RIE_g, LOC2, r1, i2, new, r1_32, loc, 0) - C(0xec46, LOCGHI, RIE_g, LOC2, r1, i2, r1, 0, loc, 0) - C(0xec4e, LOCHHI, RIE_g, LOC2, r1_sr32, i2, new, r1_32h, loc, 0) -/* LOAD HIGH ON CONDITION */ - C(0xb9e0, LOCFHR, RRF_c, LOC2, r1_sr32, r2, new, r1_32h, loc, 0) - C(0xebe0, LOCFH, RSY_b, LOC2, r1_sr32, m2_32u, new, r1_32h, loc, 0) -/* LOAD PAIR DISJOINT */ - D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL) - D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEUQ) -/* LOAD PAIR FROM QUADWORD */ - C(0xe38f, LPQ, RXY_a, Z, 0, a2, r1_P, 0, lpq, 0) -/* LOAD POSITIVE */ - C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) - C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) - C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) - F(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32, IF_BFP) - F(0xb310, LPDBR, RRE, Z, 0, f2, new, f1, absf64, f64, IF_BFP) - F(0xb340, LPXBR, RRE, Z, x2h, x2l, new_P, x1, absf128, f128, IF_BFP) - F(0xb370, LPDFR, RRE, FPSSH, 0, f2, new, f1, absf64, 0, IF_AFP1 | IF_AFP2) -/* LOAD REVERSED */ - C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) - C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) - C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) - C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) - C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) -/* LOAD ZERO */ - F(0xb374, LZER, RRE, Z, 0, 0, 0, e1, zero, 0, IF_AFP1) - F(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0, IF_AFP1) - F(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0, IF_AFP1) - -/* LOAD FPC */ - F(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0, IF_BFP) -/* LOAD FPC AND SIGNAL */ - F(0xb2bd, LFAS, S, IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0, IF_DFP) -/* LOAD FP INTEGER */ - F(0xb357, FIEBR, RRF_e, Z, 0, e2, new, e1, fieb, 0, IF_BFP) - F(0xb35f, FIDBR, RRF_e, Z, 0, f2, new, f1, fidb, 0, IF_BFP) - F(0xb347, FIXBR, RRF_e, Z, x2h, x2l, new_P, x1, fixb, 0, IF_BFP) - -/* LOAD LENGTHENED */ - F(0xb304, LDEBR, RRE, Z, 0, e2, new, f1, ldeb, 0, IF_BFP) - F(0xb305, LXDBR, RRE, Z, 0, f2, new_P, x1, lxdb, 0, IF_BFP) - F(0xb306, LXEBR, RRE, Z, 0, e2, new_P, x1, lxeb, 0, IF_BFP) - F(0xed04, LDEB, RXE, Z, 0, m2_32u, new, f1, ldeb, 0, IF_BFP) - F(0xed05, LXDB, RXE, Z, 0, m2_64, new_P, x1, lxdb, 0, IF_BFP) - F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_P, x1, lxeb, 0, IF_BFP) - F(0xb324, LDER, RXE, Z, 0, e2, new, f1, lde, 0, IF_AFP1) - F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1) -/* LOAD ROUNDED */ - F(0xb344, LEDBR, RRF_e, Z, 0, f2, new, e1, ledb, 0, IF_BFP) - F(0xb345, LDXBR, RRF_e, Z, x2h, x2l, new, f1, ldxb, 0, IF_BFP) - F(0xb346, LEXBR, RRF_e, Z, x2h, x2l, new, e1, lexb, 0, IF_BFP) - -/* LOAD MULTIPLE */ - C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) - C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) - C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) -/* LOAD MULTIPLE HIGH */ - C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) -/* LOAD ACCESS MULTIPLE */ - C(0x9a00, LAM, RS_a, Z, 0, a2, 0, 0, lam, 0) - C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) - -/* MONITOR CALL */ - C(0xaf00, MC, SI, Z, la1, 0, 0, 0, mc, 0) - -/* MOVE */ - C(0xd200, MVC, SS_a, Z, la1, a2, 0, 0, mvc, 0) - C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) - C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) - C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) - C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) - C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) -/* MOVE INVERSE */ - C(0xe800, MVCIN, SS_a, Z, la1, a2, 0, 0, mvcin, 0) -/* MOVE LONG */ - C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) -/* MOVE LONG EXTENDED */ - C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) -/* MOVE LONG UNICODE */ - C(0xeb8e, MVCLU, RSY_a, E2, 0, a2, 0, 0, mvclu, 0) -/* MOVE NUMERICS */ - C(0xd100, MVN, SS_a, Z, la1, a2, 0, 0, mvn, 0) -/* MOVE RIGHT TO LEFT */ - C(0xe50a, MVCRL, SSE, MIE3, la1, a2, 0, 0, mvcrl, 0) -/* MOVE PAGE */ - C(0xb254, MVPG, RRE, Z, 0, 0, 0, 0, mvpg, 0) -/* MOVE STRING */ - C(0xb255, MVST, RRE, Z, 0, 0, 0, 0, mvst, 0) -/* MOVE WITH OPTIONAL SPECIFICATION */ - C(0xc800, MVCOS, SSF, MVCOS, la1, a2, 0, 0, mvcos, 0) -/* MOVE WITH OFFSET */ - /* Really format SS_b, but we pack both lengths into one argument - for the helper call, so we might as well leave one 8-bit field. */ - C(0xf100, MVO, SS_a, Z, la1, a2, 0, 0, mvo, 0) -/* MOVE ZONES */ - C(0xd300, MVZ, SS_a, Z, la1, a2, 0, 0, mvz, 0) - -/* MULTIPLY */ - C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) - C(0xb9ec, MGRK, RRF_a, MIE2,r3_o, r2_o, r1_P, 0, muls128, 0) - C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) - C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) - C(0xe384, MG, RXY_a, MIE2,r1p1_o, m2_64, r1_P, 0, muls128, 0) - F(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0, IF_BFP) - F(0xb31c, MDBR, RRE, Z, f1, f2, new, f1, mdb, 0, IF_BFP) - F(0xb34c, MXBR, RRE, Z, x2h, x2l, x1, x1, mxb, 0, IF_BFP) - F(0xb30c, MDEBR, RRE, Z, f1, e2, new, f1, mdeb, 0, IF_BFP) - F(0xb307, MXDBR, RRE, Z, 0, f2, x1, x1, mxdb, 0, IF_BFP) - F(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0, IF_BFP) - F(0xed1c, MDB, RXE, Z, f1, m2_64, new, f1, mdb, 0, IF_BFP) - F(0xed0c, MDEB, RXE, Z, f1, m2_32u, new, f1, mdeb, 0, IF_BFP) - F(0xed07, MXDB, RXE, Z, 0, m2_64, x1, x1, mxdb, 0, IF_BFP) -/* MULTIPLY HALFWORD */ - C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) - C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) - C(0xe33c, MGH, RXY_a, MIE2,r1_o, m2_16s, r1, 0, mul, 0) -/* MULTIPLY HALFWORD IMMEDIATE */ - C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) - C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) -/* MULTIPLY LOGICAL */ - C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) - C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) - C(0xb986, MLGR, RRE, Z, r1p1, r2_o, r1_P, 0, mul128, 0) - C(0xe386, MLG, RXY_a, Z, r1p1, m2_64, r1_P, 0, mul128, 0) -/* MULTIPLY SINGLE */ - C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) - C(0xb9fd, MSRKC, RRF_a, MIE2,r3_32s, r2_32s, new, r1_32, mul, muls32) - C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) - C(0xe351, MSY, RXY_a, LD, r1_o, m2_32s, new, r1_32, mul, 0) - C(0xe353, MSC, RXY_a, MIE2,r1_32s, m2_32s, new, r1_32, mul, muls32) - C(0xb90c, MSGR, RRE, Z, r1_o, r2_o, r1, 0, mul, 0) - C(0xb9ed, MSGRKC, RRF_a, MIE2,r3_o, r2_o, new_P, out2_r1, muls128, muls64) - C(0xb91c, MSGFR, RRE, Z, r1_o, r2_32s, r1, 0, mul, 0) - C(0xe30c, MSG, RXY_a, Z, r1_o, m2_64, r1, 0, mul, 0) - C(0xe383, MSGC, RXY_a, MIE2,r1_o, m2_64, new_P, out2_r1, muls128, muls64) - C(0xe31c, MSGF, RXY_a, Z, r1_o, m2_32s, r1, 0, mul, 0) -/* MULTIPLY SINGLE IMMEDIATE */ - C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) - C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) - -/* MULTIPLY AND ADD */ - F(0xb30e, MAEBR, RRD, Z, e1, e2, new, e1, maeb, 0, IF_BFP) - F(0xb31e, MADBR, RRD, Z, f1, f2, new, f1, madb, 0, IF_BFP) - F(0xed0e, MAEB, RXF, Z, e1, m2_32u, new, e1, maeb, 0, IF_BFP) - F(0xed1e, MADB, RXF, Z, f1, m2_64, new, f1, madb, 0, IF_BFP) -/* MULTIPLY AND SUBTRACT */ - F(0xb30f, MSEBR, RRD, Z, e1, e2, new, e1, mseb, 0, IF_BFP) - F(0xb31f, MSDBR, RRD, Z, f1, f2, new, f1, msdb, 0, IF_BFP) - F(0xed0f, MSEB, RXF, Z, e1, m2_32u, new, e1, mseb, 0, IF_BFP) - F(0xed1f, MSDB, RXF, Z, f1, m2_64, new, f1, msdb, 0, IF_BFP) - -/* NAND */ - C(0xb974, NNRK, RRF_a, MIE3, r2, r3, new, r1_32, nand, nz32) - C(0xb964, NNGRK, RRF_a, MIE3, r2, r3, r1, 0, nand, nz64) -/* NOR */ - C(0xb976, NORK, RRF_a, MIE3, r2, r3, new, r1_32, nor, nz32) - C(0xb966, NOGRK, RRF_a, MIE3, r2, r3, r1, 0, nor, nz64) -/* NOT EXCLUSIVE OR */ - C(0xb977, NXRK, RRF_a, MIE3, r2, r3, new, r1_32, nxor, nz32) - C(0xb967, NXGRK, RRF_a, MIE3, r2, r3, r1, 0, nxor, nz64) - -/* OR */ - C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) - C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) - C(0x5600, O, RX_a, Z, r1, m2_32s, new, r1_32, or, nz32) - C(0xe356, OY, RXY_a, LD, r1, m2_32s, new, r1_32, or, nz32) - C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) - C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) - C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) - C(0xd600, OC, SS_a, Z, la1, a2, 0, 0, oc, 0) -/* OR IMMEDIATE */ - D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) - D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) - D(0xa508, OIHH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1030) - D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) - D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) - D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) - D(0x9600, OI, SI, Z, la1, i2_8u, new, 0, oi, nz64, MO_UB) - D(0xeb56, OIY, SIY, LD, la1, i2_8u, new, 0, oi, nz64, MO_UB) -/* OR WITH COMPLEMENT */ - C(0xb975, OCRK, RRF_a, MIE3, r2, r3, new, r1_32, orc, nz32) - C(0xb965, OCGRK, RRF_a, MIE3, r2, r3, r1, 0, orc, nz64) - -/* PACK */ - /* Really format SS_b, but we pack both lengths into one argument - for the helper call, so we might as well leave one 8-bit field. */ - C(0xf200, PACK, SS_a, Z, la1, a2, 0, 0, pack, 0) -/* PACK ASCII */ - C(0xe900, PKA, SS_f, E2, la1, a2, 0, 0, pka, 0) -/* PACK UNICODE */ - C(0xe100, PKU, SS_f, E2, la1, a2, 0, 0, pku, 0) - -/* POPULATION COUNT */ - C(0xb9e1, POPCNT, RRF_c, PC, 0, r2_o, r1, 0, popcnt, nz64) - -/* PREFETCH */ - /* Implemented as nops of course. */ - C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) - C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) -/* PERFORM PROCESSOR ASSIST */ - /* Implemented as nop of course. */ - C(0xb2e8, PPA, RRF_c, PPA, 0, 0, 0, 0, 0, 0) - -/* ROTATE LEFT SINGLE LOGICAL */ - C(0xeb1d, RLL, RSY_a, Z, r3_o, sh, new, r1_32, rll32, 0) - C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh, r1, 0, rll64, 0) - -/* ROTATE THEN INSERT SELECTED BITS */ - C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) - C(0xec59, RISBGN, RIE_f, MIE, 0, r2, r1, 0, risbg, 0) - C(0xec5d, RISBHG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) - C(0xec51, RISBLG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) -/* ROTATE_THEN SELECTED BITS */ - C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) - C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) - C(0xec57, RXSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) - -/* SEARCH STRING */ - C(0xb25e, SRST, RRE, Z, 0, 0, 0, 0, srst, 0) -/* SEARCH STRING UNICODE */ - C(0xb9be, SRSTU, RRE, ETF3, 0, 0, 0, 0, srstu, 0) - -/* SELECT */ - C(0xb9f0, SELR, RRF_a, MIE3, r3, r2, new, r1_32, loc, 0) - C(0xb9e3, SELGR, RRF_a, MIE3, r3, r2, r1, 0, loc, 0) -/* SELECT HIGH */ - C(0xb9c0, SELFHR, RRF_a, MIE3, r3_sr32, r2_sr32, new, r1_32h, loc, 0) - -/* SET ACCESS */ - C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) -/* SET ADDRESSING MODE */ - D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0) - D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1) - D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3) -/* SET FPC */ - F(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0, IF_BFP) -/* SET FPC AND SIGNAL */ - F(0xb385, SFASR, RRE, IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0, IF_DFP) -/* SET BFP ROUNDING MODE */ - F(0xb299, SRNM, S, Z, la2, 0, 0, 0, srnm, 0, IF_BFP) - F(0xb2b8, SRNMB, S, FPE, la2, 0, 0, 0, srnmb, 0, IF_BFP) -/* SET DFP ROUNDING MODE */ - F(0xb2b9, SRNMT, S, DFPR, la2, 0, 0, 0, srnmt, 0, IF_DFP) -/* SET PROGRAM MASK */ - C(0x0400, SPM, RR_a, Z, r1, 0, 0, 0, spm, 0) - -/* SHIFT LEFT SINGLE */ - D(0x8b00, SLA, RS_a, Z, r1, sh, new, r1_32, sla, 0, 31) - D(0xebdd, SLAK, RSY_a, DO, r3, sh, new, r1_32, sla, 0, 31) - D(0xeb0b, SLAG, RSY_a, Z, r3, sh, r1, 0, sla, 0, 63) -/* SHIFT LEFT SINGLE LOGICAL */ - C(0x8900, SLL, RS_a, Z, r1_o, sh, new, r1_32, sll, 0) - C(0xebdf, SLLK, RSY_a, DO, r3_o, sh, new, r1_32, sll, 0) - C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh, r1, 0, sll, 0) -/* SHIFT RIGHT SINGLE */ - C(0x8a00, SRA, RS_a, Z, r1_32s, sh, new, r1_32, sra, s32) - C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh, new, r1_32, sra, s32) - C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh, r1, 0, sra, s64) -/* SHIFT RIGHT SINGLE LOGICAL */ - C(0x8800, SRL, RS_a, Z, r1_32u, sh, new, r1_32, srl, 0) - C(0xebde, SRLK, RSY_a, DO, r3_32u, sh, new, r1_32, srl, 0) - C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh, r1, 0, srl, 0) -/* SHIFT LEFT DOUBLE */ - D(0x8f00, SLDA, RS_a, Z, r1_D32, sh, new, r1_D32, sla, 0, 63) -/* SHIFT LEFT DOUBLE LOGICAL */ - C(0x8d00, SLDL, RS_a, Z, r1_D32, sh, new, r1_D32, sll, 0) -/* SHIFT RIGHT DOUBLE */ - C(0x8e00, SRDA, RS_a, Z, r1_D32, sh, new, r1_D32, sra, s64) -/* SHIFT RIGHT DOUBLE LOGICAL */ - C(0x8c00, SRDL, RS_a, Z, r1_D32, sh, new, r1_D32, srl, 0) - -/* SQUARE ROOT */ - F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP) - F(0xb315, SQDBR, RRE, Z, 0, f2, new, f1, sqdb, 0, IF_BFP) - F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_P, x1, sqxb, 0, IF_BFP) - F(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0, IF_BFP) - F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP) - -/* STORE */ - C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) - C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) - C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) - F(0x6000, STD, RX_a, Z, f1, a2, 0, 0, st64, 0, IF_AFP1) - F(0xed67, STDY, RXY_a, LD, f1, a2, 0, 0, st64, 0, IF_AFP1) - F(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0, IF_AFP1) - F(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0, IF_AFP1) -/* STORE RELATIVE LONG */ - C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) - C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) -/* STORE CHARACTER */ - C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) - C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) -/* STORE CHARACTER HIGH */ - C(0xe3c3, STCH, RXY_a, HW, r1_sr32, a2, 0, 0, st8, 0) -/* STORE CHARACTERS UNDER MASK */ - D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) - D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) - D(0xeb2c, STCMH, RSY_b, Z, r1_o, a2, 0, 0, stcm, 0, 32) -/* STORE HALFWORD */ - C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) - C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) -/* STORE HALFWORD HIGH */ - C(0xe3c7, STHH, RXY_a, HW, r1_sr32, a2, 0, 0, st16, 0) -/* STORE HALFWORD RELATIVE LONG */ - C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) -/* STORE HIGH */ - C(0xe3cb, STFH, RXY_a, HW, r1_sr32, a2, 0, 0, st32, 0) -/* STORE ON CONDITION */ - D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) - D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) -/* STORE HIGH ON CONDITION */ - D(0xebe1, STOCFH, RSY_b, LOC2, 0, 0, 0, 0, soc, 0, 2) -/* STORE REVERSED */ - C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) - C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) - C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) - -/* STORE CLOCK */ - F(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0, IF_IO) - F(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0, IF_IO) -/* STORE CLOCK EXTENDED */ - F(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0, IF_IO) - -/* STORE FACILITY LIST EXTENDED */ - C(0xb2b0, STFLE, S, SFLE, 0, a2, 0, 0, stfle, 0) -/* STORE FPC */ - F(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0, IF_BFP) - -/* STORE MULTIPLE */ - D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) - D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) - D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) -/* STORE MULTIPLE HIGH */ - C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) -/* STORE ACCESS MULTIPLE */ - C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) - C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) -/* STORE PAIR TO QUADWORD */ - C(0xe38e, STPQ, RXY_a, Z, 0, a2, r1_P, 0, stpq, 0) - -/* SUBTRACT */ - C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) - C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) - C(0x5b00, S, RX_a, Z, r1, m2_32s, new, r1_32, sub, subs32) - C(0xe35b, SY, RXY_a, LD, r1, m2_32s, new, r1_32, sub, subs32) - C(0xb909, SGR, RRE, Z, r1, r2, r1, 0, sub, subs64) - C(0xb919, SGFR, RRE, Z, r1, r2_32s, r1, 0, sub, subs64) - C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) - C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) - C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) - F(0xb30b, SEBR, RRE, Z, e1, e2, new, e1, seb, f32, IF_BFP) - F(0xb31b, SDBR, RRE, Z, f1, f2, new, f1, sdb, f64, IF_BFP) - F(0xb34b, SXBR, RRE, Z, x2h, x2l, x1, x1, sxb, f128, IF_BFP) - F(0xed0b, SEB, RXE, Z, e1, m2_32u, new, e1, seb, f32, IF_BFP) - F(0xed1b, SDB, RXE, Z, f1, m2_64, new, f1, sdb, f64, IF_BFP) -/* SUBTRACT HALFWORD */ - C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) - C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) - C(0xe339, SGH, RXY_a, MIE2,r1, m2_16s, r1, 0, sub, subs64) -/* SUBTRACT HIGH */ - C(0xb9c9, SHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subs32) - C(0xb9d9, SHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subs32) -/* SUBTRACT LOGICAL */ - C(0x1f00, SLR, RR_a, Z, r1_32u, r2_32u, new, r1_32, sub, subu32) - C(0xb9fb, SLRK, RRF_a, DO, r2_32u, r3_32u, new, r1_32, sub, subu32) - C(0x5f00, SL, RX_a, Z, r1_32u, m2_32u, new, r1_32, sub, subu32) - C(0xe35f, SLY, RXY_a, LD, r1_32u, m2_32u, new, r1_32, sub, subu32) - C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, subu64, subu64) - C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, subu64, subu64) - C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, subu64, subu64) - C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, subu64, subu64) - C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, subu64, subu64) -/* SUBTRACT LOCICAL HIGH */ - C(0xb9cb, SLHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subu32) - C(0xb9db, SLHHLR, RRF_a, HW, r2_sr32, r3_32u, new, r1_32h, sub, subu32) -/* SUBTRACT LOGICAL IMMEDIATE */ - C(0xc205, SLFI, RIL_a, EI, r1_32u, i2_32u, new, r1_32, sub, subu32) - C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, subu64, subu64) -/* SUBTRACT LOGICAL WITH BORROW */ - C(0xb999, SLBR, RRE, Z, r1_32u, r2_32u, new, r1_32, subb32, subu32) - C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb64, subu64) - C(0xe399, SLB, RXY_a, Z, r1_32u, m2_32u, new, r1_32, subb32, subu32) - C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb64, subu64) - -/* SUPERVISOR CALL */ - C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) - -/* TEST ADDRESSING MODE */ - C(0x010b, TAM, E, Z, 0, 0, 0, 0, tam, 0) - -/* TEST AND SET */ - C(0x9300, TS, S, Z, 0, a2, 0, 0, ts, 0) - -/* TEST DATA CLASS */ - F(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0, IF_BFP) - F(0xed11, TCDB, RXE, Z, f1, a2, 0, 0, tcdb, 0, IF_BFP) - F(0xed12, TCXB, RXE, Z, 0, a2, x1, 0, tcxb, 0, IF_BFP) - -/* TEST DECIMAL */ - C(0xebc0, TP, RSL, E2, la1, 0, 0, 0, tp, 0) - -/* TEST UNDER MASK */ - C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) - C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) - D(0xa702, TMHH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 48) - D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) - D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) - D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) - -/* TRANSLATE */ - C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) -/* TRANSLATE AND TEST */ - C(0xdd00, TRT, SS_a, Z, la1, a2, 0, 0, trt, 0) -/* TRANSLATE AND TEST REVERSE */ - C(0xd000, TRTR, SS_a, ETF3, la1, a2, 0, 0, trtr, 0) -/* TRANSLATE EXTENDED */ - C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0) - -/* TRANSLATE ONE TO ONE */ - C(0xb993, TROO, RRF_c, E2, 0, 0, 0, 0, trXX, 0) -/* TRANSLATE ONE TO TWO */ - C(0xb992, TROT, RRF_c, E2, 0, 0, 0, 0, trXX, 0) -/* TRANSLATE TWO TO ONE */ - C(0xb991, TRTO, RRF_c, E2, 0, 0, 0, 0, trXX, 0) -/* TRANSLATE TWO TO TWO */ - C(0xb990, TRTT, RRF_c, E2, 0, 0, 0, 0, trXX, 0) - -/* UNPACK */ - /* Really format SS_b, but we pack both lengths into one argument - for the helper call, so we might as well leave one 8-bit field. */ - C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) -/* UNPACK ASCII */ - C(0xea00, UNPKA, SS_a, E2, la1, a2, 0, 0, unpka, 0) -/* UNPACK UNICODE */ - C(0xe200, UNPKU, SS_a, E2, la1, a2, 0, 0, unpku, 0) - -/* MSA Instructions */ - D(0xb91e, KMAC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMAC) - D(0xb928, PCKMO, RRE, MSA3, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCKMO) - D(0xb92a, KMF, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMF) - D(0xb92b, KMO, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMO) - D(0xb92c, PCC, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCC) - D(0xb92d, KMCTR, RRF_b, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMCTR) - D(0xb92e, KM, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM) - D(0xb92f, KMC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC) - D(0xb929, KMA, RRF_b, MSA8, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMA) - D(0xb93c, PPNO, RRE, MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO) - D(0xb93e, KIMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD) - D(0xb93f, KLMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD) - -/* === Vector Support Instructions === */ - -/* VECTOR BIT PERMUTE */ - E(0xe785, VBPERM, VRR_c, VE, 0, 0, 0, 0, vbperm, 0, 0, IF_VEC) -/* VECTOR GATHER ELEMENT */ - E(0xe713, VGEF, VRV, V, la2, 0, 0, 0, vge, 0, ES_32, IF_VEC) - E(0xe712, VGEG, VRV, V, la2, 0, 0, 0, vge, 0, ES_64, IF_VEC) -/* VECTOR GENERATE BYTE MASK */ - F(0xe744, VGBM, VRI_a, V, 0, 0, 0, 0, vgbm, 0, IF_VEC) -/* VECTOR GENERATE MASK */ - F(0xe746, VGM, VRI_b, V, 0, 0, 0, 0, vgm, 0, IF_VEC) -/* VECTOR LOAD */ - F(0xe706, VL, VRX, V, la2, 0, 0, 0, vl, 0, IF_VEC) - F(0xe756, VLR, VRR_a, V, 0, 0, 0, 0, vlr, 0, IF_VEC) -/* VECTOR LOAD AND REPLICATE */ - F(0xe705, VLREP, VRX, V, la2, 0, 0, 0, vlrep, 0, IF_VEC) -/* VECTOR LOAD ELEMENT */ - E(0xe700, VLEB, VRX, V, la2, 0, 0, 0, vle, 0, ES_8, IF_VEC) - E(0xe701, VLEH, VRX, V, la2, 0, 0, 0, vle, 0, ES_16, IF_VEC) - E(0xe703, VLEF, VRX, V, la2, 0, 0, 0, vle, 0, ES_32, IF_VEC) - E(0xe702, VLEG, VRX, V, la2, 0, 0, 0, vle, 0, ES_64, IF_VEC) -/* VECTOR LOAD ELEMENT IMMEDIATE */ - E(0xe740, VLEIB, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_8, IF_VEC) - E(0xe741, VLEIH, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_16, IF_VEC) - E(0xe743, VLEIF, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_32, IF_VEC) - E(0xe742, VLEIG, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_64, IF_VEC) -/* VECTOR LOAD GR FROM VR ELEMENT */ - F(0xe721, VLGV, VRS_c, V, la2, 0, r1, 0, vlgv, 0, IF_VEC) -/* VECTOR LOAD LOGICAL ELEMENT AND ZERO */ - F(0xe704, VLLEZ, VRX, V, la2, 0, 0, 0, vllez, 0, IF_VEC) -/* VECTOR LOAD MULTIPLE */ - F(0xe736, VLM, VRS_a, V, la2, 0, 0, 0, vlm, 0, IF_VEC) -/* VECTOR LOAD TO BLOCK BOUNDARY */ - F(0xe707, VLBB, VRX, V, la2, 0, 0, 0, vlbb, 0, IF_VEC) -/* VECTOR LOAD VR ELEMENT FROM GR */ - F(0xe722, VLVG, VRS_b, V, la2, r3, 0, 0, vlvg, 0, IF_VEC) -/* VECTOR LOAD VR FROM GRS DISJOINT */ - F(0xe762, VLVGP, VRR_f, V, r2, r3, 0, 0, vlvgp, 0, IF_VEC) -/* VECTOR LOAD WITH LENGTH */ - F(0xe737, VLL, VRS_b, V, la2, r3_32u, 0, 0, vll, 0, IF_VEC) -/* VECTOR MERGE HIGH */ - F(0xe761, VMRH, VRR_c, V, 0, 0, 0, 0, vmr, 0, IF_VEC) -/* VECTOR MERGE LOW */ - F(0xe760, VMRL, VRR_c, V, 0, 0, 0, 0, vmr, 0, IF_VEC) -/* VECTOR PACK */ - F(0xe794, VPK, VRR_c, V, 0, 0, 0, 0, vpk, 0, IF_VEC) -/* VECTOR PACK SATURATE */ - F(0xe797, VPKS, VRR_b, V, 0, 0, 0, 0, vpk, 0, IF_VEC) -/* VECTOR PACK LOGICAL SATURATE */ - F(0xe795, VPKLS, VRR_b, V, 0, 0, 0, 0, vpk, 0, IF_VEC) - F(0xe78c, VPERM, VRR_e, V, 0, 0, 0, 0, vperm, 0, IF_VEC) -/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */ - F(0xe784, VPDI, VRR_c, V, 0, 0, 0, 0, vpdi, 0, IF_VEC) -/* VECTOR REPLICATE */ - F(0xe74d, VREP, VRI_c, V, 0, 0, 0, 0, vrep, 0, IF_VEC) -/* VECTOR REPLICATE IMMEDIATE */ - F(0xe745, VREPI, VRI_a, V, 0, 0, 0, 0, vrepi, 0, IF_VEC) -/* VECTOR SCATTER ELEMENT */ - E(0xe71b, VSCEF, VRV, V, la2, 0, 0, 0, vsce, 0, ES_32, IF_VEC) - E(0xe71a, VSCEG, VRV, V, la2, 0, 0, 0, vsce, 0, ES_64, IF_VEC) -/* VECTOR SELECT */ - F(0xe78d, VSEL, VRR_e, V, 0, 0, 0, 0, vsel, 0, IF_VEC) -/* VECTOR SIGN EXTEND TO DOUBLEWORD */ - F(0xe75f, VSEG, VRR_a, V, 0, 0, 0, 0, vseg, 0, IF_VEC) -/* VECTOR STORE */ - F(0xe70e, VST, VRX, V, la2, 0, 0, 0, vst, 0, IF_VEC) -/* VECTOR STORE ELEMENT */ - E(0xe708, VSTEB, VRX, V, la2, 0, 0, 0, vste, 0, ES_8, IF_VEC) - E(0xe709, VSTEH, VRX, V, la2, 0, 0, 0, vste, 0, ES_16, IF_VEC) - E(0xe70b, VSTEF, VRX, V, la2, 0, 0, 0, vste, 0, ES_32, IF_VEC) - E(0xe70a, VSTEG, VRX, V, la2, 0, 0, 0, vste, 0, ES_64, IF_VEC) -/* VECTOR STORE MULTIPLE */ - F(0xe73e, VSTM, VRS_a, V, la2, 0, 0, 0, vstm, 0, IF_VEC) -/* VECTOR STORE WITH LENGTH */ - F(0xe73f, VSTL, VRS_b, V, la2, r3_32u, 0, 0, vstl, 0, IF_VEC) -/* VECTOR UNPACK HIGH */ - F(0xe7d7, VUPH, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) -/* VECTOR UNPACK LOGICAL HIGH */ - F(0xe7d5, VUPLH, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) -/* VECTOR UNPACK LOW */ - F(0xe7d6, VUPL, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) -/* VECTOR UNPACK LOGICAL LOW */ - F(0xe7d4, VUPLL, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) - -/* === Vector Integer Instructions === */ - -/* VECTOR ADD */ - F(0xe7f3, VA, VRR_c, V, 0, 0, 0, 0, va, 0, IF_VEC) -/* VECTOR ADD COMPUTE CARRY */ - F(0xe7f1, VACC, VRR_c, V, 0, 0, 0, 0, vacc, 0, IF_VEC) -/* VECTOR ADD WITH CARRY */ - F(0xe7bb, VAC, VRR_d, V, 0, 0, 0, 0, vac, 0, IF_VEC) -/* VECTOR ADD WITH CARRY COMPUTE CARRY */ - F(0xe7b9, VACCC, VRR_d, V, 0, 0, 0, 0, vaccc, 0, IF_VEC) -/* VECTOR AND */ - F(0xe768, VN, VRR_c, V, 0, 0, 0, 0, vn, 0, IF_VEC) -/* VECTOR AND WITH COMPLEMENT */ - F(0xe769, VNC, VRR_c, V, 0, 0, 0, 0, vnc, 0, IF_VEC) -/* VECTOR AVERAGE */ - F(0xe7f2, VAVG, VRR_c, V, 0, 0, 0, 0, vavg, 0, IF_VEC) -/* VECTOR AVERAGE LOGICAL */ - F(0xe7f0, VAVGL, VRR_c, V, 0, 0, 0, 0, vavgl, 0, IF_VEC) -/* VECTOR CHECKSUM */ - F(0xe766, VCKSM, VRR_c, V, 0, 0, 0, 0, vcksm, 0, IF_VEC) -/* VECTOR ELEMENT COMPARE */ - F(0xe7db, VEC, VRR_a, V, 0, 0, 0, 0, vec, cmps64, IF_VEC) -/* VECTOR ELEMENT COMPARE LOGICAL */ - F(0xe7d9, VECL, VRR_a, V, 0, 0, 0, 0, vec, cmpu64, IF_VEC) -/* VECTOR COMPARE EQUAL */ - E(0xe7f8, VCEQ, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_EQ, IF_VEC) -/* VECTOR COMPARE HIGH */ - E(0xe7fb, VCH, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_GT, IF_VEC) -/* VECTOR COMPARE HIGH LOGICAL */ - E(0xe7f9, VCHL, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_GTU, IF_VEC) -/* VECTOR COUNT LEADING ZEROS */ - F(0xe753, VCLZ, VRR_a, V, 0, 0, 0, 0, vclz, 0, IF_VEC) -/* VECTOR COUNT TRAILING ZEROS */ - F(0xe752, VCTZ, VRR_a, V, 0, 0, 0, 0, vctz, 0, IF_VEC) -/* VECTOR EXCLUSIVE OR */ - F(0xe76d, VX, VRR_c, V, 0, 0, 0, 0, vx, 0, IF_VEC) -/* VECTOR GALOIS FIELD MULTIPLY SUM */ - F(0xe7b4, VGFM, VRR_c, V, 0, 0, 0, 0, vgfm, 0, IF_VEC) -/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */ - F(0xe7bc, VGFMA, VRR_d, V, 0, 0, 0, 0, vgfma, 0, IF_VEC) -/* VECTOR LOAD COMPLEMENT */ - F(0xe7de, VLC, VRR_a, V, 0, 0, 0, 0, vlc, 0, IF_VEC) -/* VECTOR LOAD POSITIVE */ - F(0xe7df, VLP, VRR_a, V, 0, 0, 0, 0, vlp, 0, IF_VEC) -/* VECTOR MAXIMUM */ - F(0xe7ff, VMX, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) -/* VECTOR MAXIMUM LOGICAL */ - F(0xe7fd, VMXL, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) -/* VECTOR MINIMUM */ - F(0xe7fe, VMN, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) -/* VECTOR MINIMUM LOGICAL */ - F(0xe7fc, VMNL, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD LOW */ - F(0xe7aa, VMAL, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD HIGH */ - F(0xe7ab, VMAH, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD LOGICAL HIGH */ - F(0xe7a9, VMALH, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD EVEN */ - F(0xe7ae, VMAE, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD LOGICAL EVEN */ - F(0xe7ac, VMALE, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD ODD */ - F(0xe7af, VMAO, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY AND ADD LOGICAL ODD */ - F(0xe7ad, VMALO, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) -/* VECTOR MULTIPLY HIGH */ - F(0xe7a3, VMH, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY LOGICAL HIGH */ - F(0xe7a1, VMLH, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY LOW */ - F(0xe7a2, VML, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY EVEN */ - F(0xe7a6, VME, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY LOGICAL EVEN */ - F(0xe7a4, VMLE, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY ODD */ - F(0xe7a7, VMO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY LOGICAL ODD */ - F(0xe7a5, VMLO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) -/* VECTOR MULTIPLY SUM LOGICAL */ - F(0xe7b8, VMSL, VRR_d, VE, 0, 0, 0, 0, vmsl, 0, IF_VEC) -/* VECTOR NAND */ - F(0xe76e, VNN, VRR_c, VE, 0, 0, 0, 0, vnn, 0, IF_VEC) -/* VECTOR NOR */ - F(0xe76b, VNO, VRR_c, V, 0, 0, 0, 0, vno, 0, IF_VEC) -/* VECTOR NOT EXCLUSIVE OR */ - F(0xe76c, VNX, VRR_c, VE, 0, 0, 0, 0, vnx, 0, IF_VEC) -/* VECTOR OR */ - F(0xe76a, VO, VRR_c, V, 0, 0, 0, 0, vo, 0, IF_VEC) -/* VECTOR OR WITH COMPLEMENT */ - F(0xe76f, VOC, VRR_c, VE, 0, 0, 0, 0, voc, 0, IF_VEC) -/* VECTOR POPULATION COUNT */ - F(0xe750, VPOPCT, VRR_a, V, 0, 0, 0, 0, vpopct, 0, IF_VEC) -/* VECTOR ELEMENT ROTATE LEFT LOGICAL */ - F(0xe773, VERLLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) - F(0xe733, VERLL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) -/* VECTOR ELEMENT ROTATE AND INSERT UNDER MASK */ - F(0xe772, VERIM, VRI_d, V, 0, 0, 0, 0, verim, 0, IF_VEC) -/* VECTOR ELEMENT SHIFT LEFT */ - F(0xe770, VESLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) - F(0xe730, VESL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) -/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */ - F(0xe77a, VESRAV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) - F(0xe73a, VESRA, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) -/* VECTOR ELEMENT SHIFT RIGHT LOGICAL */ - F(0xe778, VESRLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) - F(0xe738, VESRL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) -/* VECTOR SHIFT LEFT */ - F(0xe774, VSL, VRR_c, V, 0, 0, 0, 0, vsl, 0, IF_VEC) -/* VECTOR SHIFT LEFT BY BYTE */ - F(0xe775, VSLB, VRR_c, V, 0, 0, 0, 0, vsl, 0, IF_VEC) -/* VECTOR SHIFT LEFT DOUBLE BY BYTE */ - F(0xe777, VSLDB, VRI_d, V, 0, 0, 0, 0, vsldb, 0, IF_VEC) -/* VECTOR SHIFT RIGHT ARITHMETIC */ - F(0xe77e, VSRA, VRR_c, V, 0, 0, 0, 0, vsra, 0, IF_VEC) -/* VECTOR SHIFT RIGHT ARITHMETIC BY BYTE */ - F(0xe77f, VSRAB, VRR_c, V, 0, 0, 0, 0, vsra, 0, IF_VEC) -/* VECTOR SHIFT RIGHT LOGICAL */ - F(0xe77c, VSRL, VRR_c, V, 0, 0, 0, 0, vsrl, 0, IF_VEC) -/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */ - F(0xe77d, VSRLB, VRR_c, V, 0, 0, 0, 0, vsrl, 0, IF_VEC) -/* VECTOR SUBTRACT */ - F(0xe7f7, VS, VRR_c, V, 0, 0, 0, 0, vs, 0, IF_VEC) -/* VECTOR SUBTRACT COMPUTE BORROW INDICATION */ - F(0xe7f5, VSCBI, VRR_c, V, 0, 0, 0, 0, vscbi, 0, IF_VEC) -/* VECTOR SUBTRACT WITH BORROW INDICATION */ - F(0xe7bf, VSBI, VRR_d, V, 0, 0, 0, 0, vsbi, 0, IF_VEC) -/* VECTOR SUBTRACT WITH BORROW COMPUTE BORROW INDICATION */ - F(0xe7bd, VSBCBI, VRR_d, V, 0, 0, 0, 0, vsbcbi, 0, IF_VEC) -/* VECTOR SUM ACROSS DOUBLEWORD */ - F(0xe765, VSUMG, VRR_c, V, 0, 0, 0, 0, vsumg, 0, IF_VEC) -/* VECTOR SUM ACROSS QUADWORD */ - F(0xe767, VSUMQ, VRR_c, V, 0, 0, 0, 0, vsumq, 0, IF_VEC) -/* VECTOR SUM ACROSS WORD */ - F(0xe764, VSUM, VRR_c, V, 0, 0, 0, 0, vsum, 0, IF_VEC) -/* VECTOR TEST UNDER MASK */ - F(0xe7d8, VTM, VRR_a, V, 0, 0, 0, 0, vtm, 0, IF_VEC) - -/* === Vector String Instructions === */ - -/* VECTOR FIND ANY ELEMENT EQUAL */ - F(0xe782, VFAE, VRR_b, V, 0, 0, 0, 0, vfae, 0, IF_VEC) -/* VECTOR FIND ELEMENT EQUAL */ - F(0xe780, VFEE, VRR_b, V, 0, 0, 0, 0, vfee, 0, IF_VEC) -/* VECTOR FIND ELEMENT NOT EQUAL */ - F(0xe781, VFENE, VRR_b, V, 0, 0, 0, 0, vfene, 0, IF_VEC) -/* VECTOR ISOLATE STRING */ - F(0xe75c, VISTR, VRR_a, V, 0, 0, 0, 0, vistr, 0, IF_VEC) -/* VECTOR STRING RANGE COMPARE */ - F(0xe78a, VSTRC, VRR_d, V, 0, 0, 0, 0, vstrc, 0, IF_VEC) - -/* === Vector Floating-Point Instructions */ - -/* VECTOR FP ADD */ - F(0xe7e3, VFA, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) -/* VECTOR FP COMPARE SCALAR */ - F(0xe7cb, WFC, VRR_a, V, 0, 0, 0, 0, wfc, 0, IF_VEC) -/* VECTOR FP COMPARE AND SIGNAL SCALAR */ - F(0xe7ca, WFK, VRR_a, V, 0, 0, 0, 0, wfc, 0, IF_VEC) -/* VECTOR FP COMPARE EQUAL */ - F(0xe7e8, VFCE, VRR_c, V, 0, 0, 0, 0, vfc, 0, IF_VEC) -/* VECTOR FP COMPARE HIGH */ - F(0xe7eb, VFCH, VRR_c, V, 0, 0, 0, 0, vfc, 0, IF_VEC) -/* VECTOR FP COMPARE HIGH OR EQUAL */ - F(0xe7ea, VFCHE, VRR_c, V, 0, 0, 0, 0, vfc, 0, IF_VEC) -/* VECTOR FP CONVERT FROM FIXED 64-BIT */ - F(0xe7c3, VCDG, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR FP CONVERT FROM LOGICAL 64-BIT */ - F(0xe7c1, VCDLG, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR FP CONVERT TO FIXED 64-BIT */ - F(0xe7c2, VCGD, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR FP CONVERT TO LOGICAL 64-BIT */ - F(0xe7c0, VCLGD, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR FP DIVIDE */ - F(0xe7e5, VFD, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) -/* VECTOR LOAD FP INTEGER */ - F(0xe7c7, VFI, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR FP LOAD LENGTHENED */ - F(0xe7c4, VFLL, VRR_a, V, 0, 0, 0, 0, vfll, 0, IF_VEC) -/* VECTOR FP LOAD ROUNDED */ - F(0xe7c5, VFLR, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR FP MAXIMUM */ - F(0xe7ef, VFMAX, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC) -/* VECTOR FP MINIMUM */ - F(0xe7ee, VFMIN, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC) -/* VECTOR FP MULTIPLY */ - F(0xe7e7, VFM, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) -/* VECTOR FP MULTIPLY AND ADD */ - F(0xe78f, VFMA, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC) -/* VECTOR FP MULTIPLY AND SUBTRACT */ - F(0xe78e, VFMS, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC) -/* VECTOR FP NEGATIVE MULTIPLY AND ADD */ - F(0xe79f, VFNMA, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC) -/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */ - F(0xe79e, VFNMS, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC) -/* VECTOR FP PERFORM SIGN OPERATION */ - F(0xe7cc, VFPSO, VRR_a, V, 0, 0, 0, 0, vfpso, 0, IF_VEC) -/* VECTOR FP SQUARE ROOT */ - F(0xe7ce, VFSQ, VRR_a, V, 0, 0, 0, 0, vfsq, 0, IF_VEC) -/* VECTOR FP SUBTRACT */ - F(0xe7e2, VFS, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) -/* VECTOR FP TEST DATA CLASS IMMEDIATE */ - F(0xe74a, VFTCI, VRI_e, V, 0, 0, 0, 0, vftci, 0, IF_VEC) - -#ifndef CONFIG_USER_ONLY -/* COMPARE AND SWAP AND PURGE */ - E(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL, IF_PRIV) - E(0xb98a, CSPG, RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEUQ, IF_PRIV) -/* DIAGNOSE (KVM hypercall) */ - F(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0, IF_PRIV | IF_IO) -/* INSERT STORAGE KEY EXTENDED */ - F(0xb229, ISKE, RRE, Z, 0, r2_o, new, r1_8, iske, 0, IF_PRIV) -/* INVALIDATE DAT TABLE ENTRY */ - F(0xb98e, IPDE, RRF_b, Z, r1_o, r2_o, 0, 0, idte, 0, IF_PRIV) -/* INVALIDATE PAGE TABLE ENTRY */ - F(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0, IF_PRIV) -/* LOAD CONTROL */ - F(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0, IF_PRIV) - F(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0, IF_PRIV) -/* LOAD PROGRAM PARAMETER */ - F(0xb280, LPP, S, LPP, 0, m2_64, 0, 0, lpp, 0, IF_PRIV) -/* LOAD PSW */ - F(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0, IF_PRIV) -/* LOAD PSW EXTENDED */ - F(0xb2b2, LPSWE, S, Z, 0, a2, 0, 0, lpswe, 0, IF_PRIV) -/* LOAD REAL ADDRESS */ - F(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0, IF_PRIV) - F(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0, IF_PRIV) - F(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0, IF_PRIV) -/* LOAD USING REAL ADDRESS */ - E(0xb24b, LURA, RRE, Z, 0, ra2, new, r1_32, lura, 0, MO_TEUL, IF_PRIV) - E(0xb905, LURAG, RRE, Z, 0, ra2, r1, 0, lura, 0, MO_TEUQ, IF_PRIV) -/* MOVE TO PRIMARY */ - F(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0, IF_PRIV) -/* MOVE TO SECONDARY */ - F(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0, IF_PRIV) -/* PURGE TLB */ - F(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0, IF_PRIV) -/* RESET REFERENCE BIT EXTENDED */ - F(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0, IF_PRIV) -/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ - F(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0, IF_PRIV | IF_IO) -/* SET ADDRESS SPACE CONTROL FAST */ - F(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0, IF_PRIV) -/* SET CLOCK */ - F(0xb204, SCK, S, Z, 0, m2_64a, 0, 0, sck, 0, IF_PRIV | IF_IO) -/* SET CLOCK COMPARATOR */ - F(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0, IF_PRIV | IF_IO) -/* SET CLOCK PROGRAMMABLE FIELD */ - F(0x0107, SCKPF, E, Z, 0, 0, 0, 0, sckpf, 0, IF_PRIV) -/* SET CPU TIMER */ - F(0xb208, SPT, S, Z, 0, m2_64a, 0, 0, spt, 0, IF_PRIV | IF_IO) -/* SET PREFIX */ - F(0xb210, SPX, S, Z, 0, m2_32ua, 0, 0, spx, 0, IF_PRIV) -/* SET PSW KEY FROM ADDRESS */ - F(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0, IF_PRIV) -/* SET STORAGE KEY EXTENDED */ - F(0xb22b, SSKE, RRF_c, Z, r1_o, r2_o, 0, 0, sske, 0, IF_PRIV) -/* SET SYSTEM MASK */ - F(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0, IF_PRIV) -/* SIGNAL PROCESSOR */ - F(0xae00, SIGP, RS_a, Z, 0, a2, 0, 0, sigp, 0, IF_PRIV | IF_IO) -/* STORE CLOCK COMPARATOR */ - F(0xb207, STCKC, S, Z, la2, 0, new, m1_64a, stckc, 0, IF_PRIV) -/* STORE CONTROL */ - F(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0, IF_PRIV) - F(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0, IF_PRIV) -/* STORE CPU ADDRESS */ - F(0xb212, STAP, S, Z, la2, 0, new, m1_16a, stap, 0, IF_PRIV) -/* STORE CPU ID */ - F(0xb202, STIDP, S, Z, la2, 0, new, m1_64a, stidp, 0, IF_PRIV) -/* STORE CPU TIMER */ - F(0xb209, STPT, S, Z, la2, 0, new, m1_64a, stpt, 0, IF_PRIV | IF_IO) -/* STORE FACILITY LIST */ - F(0xb2b1, STFL, S, Z, 0, 0, 0, 0, stfl, 0, IF_PRIV) -/* STORE PREFIX */ - F(0xb211, STPX, S, Z, la2, 0, new, m1_32a, stpx, 0, IF_PRIV) -/* STORE SYSTEM INFORMATION */ - F(0xb27d, STSI, S, Z, 0, a2, 0, 0, stsi, 0, IF_PRIV) -/* STORE THEN AND SYSTEM MASK */ - F(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0, IF_PRIV) -/* STORE THEN OR SYSTEM MASK */ - F(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0, IF_PRIV) -/* STORE USING REAL ADDRESS */ - E(0xb246, STURA, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEUL, IF_PRIV) - E(0xb925, STURG, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEUQ, IF_PRIV) -/* TEST BLOCK */ - F(0xb22c, TB, RRE, Z, 0, r2_o, 0, 0, testblock, 0, IF_PRIV) -/* TEST PROTECTION */ - C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) - -/* CCW I/O Instructions */ - F(0xb276, XSCH, S, Z, 0, 0, 0, 0, xsch, 0, IF_PRIV | IF_IO) - F(0xb230, CSCH, S, Z, 0, 0, 0, 0, csch, 0, IF_PRIV | IF_IO) - F(0xb231, HSCH, S, Z, 0, 0, 0, 0, hsch, 0, IF_PRIV | IF_IO) - F(0xb232, MSCH, S, Z, 0, insn, 0, 0, msch, 0, IF_PRIV | IF_IO) - F(0xb23b, RCHP, S, Z, 0, 0, 0, 0, rchp, 0, IF_PRIV | IF_IO) - F(0xb238, RSCH, S, Z, 0, 0, 0, 0, rsch, 0, IF_PRIV | IF_IO) - F(0xb237, SAL, S, Z, 0, 0, 0, 0, sal, 0, IF_PRIV | IF_IO) - F(0xb23c, SCHM, S, Z, 0, insn, 0, 0, schm, 0, IF_PRIV | IF_IO) - F(0xb274, SIGA, S, Z, 0, 0, 0, 0, siga, 0, IF_PRIV | IF_IO) - F(0xb23a, STCPS, S, Z, 0, 0, 0, 0, stcps, 0, IF_PRIV | IF_IO) - F(0xb233, SSCH, S, Z, 0, insn, 0, 0, ssch, 0, IF_PRIV | IF_IO) - F(0xb239, STCRW, S, Z, 0, insn, 0, 0, stcrw, 0, IF_PRIV | IF_IO) - F(0xb234, STSCH, S, Z, 0, insn, 0, 0, stsch, 0, IF_PRIV | IF_IO) - F(0xb236, TPI , S, Z, la2, 0, 0, 0, tpi, 0, IF_PRIV | IF_IO) - F(0xb235, TSCH, S, Z, 0, insn, 0, 0, tsch, 0, IF_PRIV | IF_IO) - /* ??? Not listed in PoO ninth edition, but there's a linux driver that - uses it: "A CHSC subchannel is usually present on LPAR only." */ - F(0xb25f, CHSC, RRE, Z, 0, insn, 0, 0, chsc, 0, IF_PRIV | IF_IO) - -/* zPCI Instructions */ - /* None of these instructions are documented in the PoP, so this is all - based upon target/s390x/kvm.c and Linux code and likely incomplete */ - F(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0, IF_PRIV | IF_IO) - F(0xebd1, SIC, RSY_a, AIS, r1, r3, 0, 0, sic, 0, IF_PRIV | IF_IO) - F(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0, IF_PRIV | IF_IO) - F(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0, IF_PRIV | IF_IO) - F(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0, IF_PRIV | IF_IO) - F(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0, IF_PRIV | IF_IO) - F(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0, IF_PRIV | IF_IO) - F(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0, IF_PRIV | IF_IO) - -#endif /* CONFIG_USER_ONLY */ diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc new file mode 100644 index 000000000000..79c6ab509ab3 --- /dev/null +++ b/target/s390x/tcg/insn-data.h.inc @@ -0,0 +1,1448 @@ +/* + * Arguments to the opcode prototypes + * + * C(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC) + * D(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC, DATA) + * E(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC, DATA, FLAGS) + * F(OPC, NAME, FMT, FAC, I1, I2, P, W, OP, CC, FLAGS) + * + * OPC = (op << 8) | op2 where op is the major, op2 the minor opcode + * NAME = name of the opcode, used internally + * FMT = format of the opcode (defined in insn-format.h.inc) + * FAC = facility the opcode is available in (defined in DisasFacility) + * I1 = func in1_xx fills o->in1 + * I2 = func in2_xx fills o->in2 + * P = func prep_xx initializes o->*out* + * W = func wout_xx writes o->*out* somewhere + * OP = func op_xx does the bulk of the operation + * CC = func cout_xx defines how cc should get set + * DATA = immediate argument to op_xx function + * FLAGS = categorize the type of instruction (e.g. for advanced checks) + * + * The helpers get called in order: I1, I2, P, OP, W, CC + */ + +/* ADD */ + C(0x1a00, AR, RR_a, Z, r1, r2, new, r1_32, add, adds32) + C(0xb9f8, ARK, RRF_a, DO, r2, r3, new, r1_32, add, adds32) + C(0x5a00, A, RX_a, Z, r1, m2_32s, new, r1_32, add, adds32) + C(0xe35a, AY, RXY_a, LD, r1, m2_32s, new, r1_32, add, adds32) + C(0xb908, AGR, RRE, Z, r1, r2, r1, 0, add, adds64) + C(0xb918, AGFR, RRE, Z, r1, r2_32s, r1, 0, add, adds64) + C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) + C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) + C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) + F(0xb30a, AEBR, RRE, Z, e1, e2, new, e1, aeb, f32, IF_BFP) + F(0xb31a, ADBR, RRE, Z, f1, f2, new, f1, adb, f64, IF_BFP) + F(0xb34a, AXBR, RRE, Z, x2h, x2l, x1, x1, axb, f128, IF_BFP) + F(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32, IF_BFP) + F(0xed1a, ADB, RXE, Z, f1, m2_64, new, f1, adb, f64, IF_BFP) +/* ADD HIGH */ + C(0xb9c8, AHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, adds32) + C(0xb9d8, AHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, adds32) +/* ADD IMMEDIATE */ + C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) + D(0xeb6a, ASI, SIY, GIE, la1, i2, new, 0, asi, adds32, MO_TESL) + C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32) + C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) + D(0xeb7a, AGSI, SIY, GIE, la1, i2, new, 0, asi, adds64, MO_TEUQ) + C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD IMMEDIATE HIGH */ + C(0xcc08, AIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, adds32) +/* ADD HALFWORD */ + C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) + C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) + C(0xe338, AGH, RXY_a, MIE2,r1, m2_16s, r1, 0, add, adds64) +/* ADD HALFWORD IMMEDIATE */ + C(0xa70a, AHI, RI_a, Z, r1, i2, new, r1_32, add, adds32) + C(0xa70b, AGHI, RI_a, Z, r1, i2, r1, 0, add, adds64) + +/* ADD LOGICAL */ + C(0x1e00, ALR, RR_a, Z, r1_32u, r2_32u, new, r1_32, add, addu32) + C(0xb9fa, ALRK, RRF_a, DO, r2_32u, r3_32u, new, r1_32, add, addu32) + C(0x5e00, AL, RX_a, Z, r1_32u, m2_32u, new, r1_32, add, addu32) + C(0xe35e, ALY, RXY_a, LD, r1_32u, m2_32u, new, r1_32, add, addu32) + C(0xb90a, ALGR, RRE, Z, r1, r2, r1, 0, addu64, addu64) + C(0xb91a, ALGFR, RRE, Z, r1, r2_32u, r1, 0, addu64, addu64) + C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, addu64, addu64) + C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, addu64, addu64) + C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, addu64, addu64) +/* ADD LOGICAL HIGH */ + C(0xb9ca, ALHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, addu32) + C(0xb9da, ALHHLR, RRF_a, HW, r2_sr32, r3_32u, new, r1_32h, add, addu32) +/* ADD LOGICAL IMMEDIATE */ + C(0xc20b, ALFI, RIL_a, EI, r1_32u, i2_32u, new, r1_32, add, addu32) + C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, addu64, addu64) +/* ADD LOGICAL WITH SIGNED IMMEDIATE */ + D(0xeb6e, ALSI, SIY, GIE, la1, i2_32u, new, 0, asi, addu32, MO_TEUL) + C(0xecda, ALHSIK, RIE_d, DO, r3_32u, i2_32u, new, r1_32, add, addu32) + D(0xeb7e, ALGSI, SIY, GIE, la1, i2, new, 0, asiu64, addu64, MO_TEUQ) + C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, addu64, addu64) +/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */ + C(0xcc0a, ALSIH, RIL_a, HW, r1_sr32, i2_32u, new, r1_32h, add, addu32) + C(0xcc0b, ALSIHN, RIL_a, HW, r1_sr32, i2_32u, new, r1_32h, add, 0) +/* ADD LOGICAL WITH CARRY */ + C(0xb998, ALCR, RRE, Z, r1_32u, r2_32u, new, r1_32, addc32, addu32) + C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc64, addu64) + C(0xe398, ALC, RXY_a, Z, r1_32u, m2_32u, new, r1_32, addc32, addu32) + C(0xe388, ALCG, RXY_a, Z, r1, m2_64, r1, 0, addc64, addu64) + +/* AND */ + C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) + C(0xb9f4, NRK, RRF_a, DO, r2, r3, new, r1_32, and, nz32) + C(0x5400, N, RX_a, Z, r1, m2_32s, new, r1_32, and, nz32) + C(0xe354, NY, RXY_a, LD, r1, m2_32s, new, r1_32, and, nz32) + C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) + C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) + C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) + C(0xd400, NC, SS_a, Z, la1, a2, 0, 0, nc, 0) +/* AND IMMEDIATE */ + D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) + D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) + D(0xa504, NIHH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1030) + D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) + D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) + D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) + D(0x9400, NI, SI, Z, la1, i2_8u, new, 0, ni, nz64, MO_UB) + D(0xeb54, NIY, SIY, LD, la1, i2_8u, new, 0, ni, nz64, MO_UB) +/* AND WITH COMPLEMENT */ + C(0xb9f5, NCRK, RRF_a, MIE3, r2, r3, new, r1_32, andc, nz32) + C(0xb9e5, NCGRK, RRF_a, MIE3, r2, r3, r1, 0, andc, nz64) + +/* BRANCH AND LINK */ + C(0x0500, BALR, RR_a, Z, 0, r2_nz, r1, 0, bal, 0) + C(0x4500, BAL, RX_a, Z, 0, a2, r1, 0, bal, 0) +/* BRANCH AND SAVE */ + C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) + C(0x4d00, BAS, RX_a, Z, 0, a2, r1, 0, bas, 0) +/* BRANCH RELATIVE AND SAVE */ + C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) + C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) +/* BRANCH INDIRECT ON CONDITION */ + C(0xe347, BIC, RXY_b, MIE2,0, m2_64w, 0, 0, bc, 0) +/* BRANCH ON CONDITION */ + C(0x0700, BCR, RR_b, Z, 0, r2_nz, 0, 0, bc, 0) + C(0x4700, BC, RX_b, Z, 0, a2, 0, 0, bc, 0) +/* BRANCH RELATIVE ON CONDITION */ + C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) + C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) +/* BRANCH ON COUNT */ + C(0x0600, BCTR, RR_a, Z, 0, r2_nz, 0, 0, bct32, 0) + C(0xb946, BCTGR, RRE, Z, 0, r2_nz, 0, 0, bct64, 0) + C(0x4600, BCT, RX_a, Z, 0, a2, 0, 0, bct32, 0) + C(0xe346, BCTG, RXY_a, Z, 0, a2, 0, 0, bct64, 0) +/* BRANCH RELATIVE ON COUNT */ + C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) + C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* BRANCH RELATIVE ON COUNT HIGH */ + C(0xcc06, BRCTH, RIL_b, HW, 0, 0, 0, 0, bcth, 0) +/* BRANCH ON INDEX */ + D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) + D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) + D(0xeb44, BXHG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 0) + D(0xeb45, BXLEG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 1) +/* BRANCH RELATIVE ON INDEX */ + D(0x8400, BRXH, RSI, Z, 0, 0, 0, 0, bx32, 0, 0) + D(0x8500, BRXLE, RSI, Z, 0, 0, 0, 0, bx32, 0, 1) + D(0xec44, BRXHG, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 0) + D(0xec45, BRXHLE, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 1) +/* BRANCH PREDICTION PRELOAD */ + /* ??? Format is SMI, but implemented as NOP, so we need no fields. */ + C(0xc700, BPP, E, EH, 0, 0, 0, 0, 0, 0) +/* BRANCH PREDICTION RELATIVE PRELOAD */ + /* ??? Format is MII, but implemented as NOP, so we need no fields. */ + C(0xc500, BPRP, E, EH, 0, 0, 0, 0, 0, 0) +/* NEXT INSTRUCTION ACCESS INTENT */ + /* ??? Format is IE, but implemented as NOP, so we need no fields. */ + C(0xb2fa, NIAI, E, EH, 0, 0, 0, 0, 0, 0) + +/* CHECKSUM */ + C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) + +/* COPY SIGN */ + F(0xb372, CPSDR, RRF_b, FPSSH, f3, f2, new, f1, cps, 0, IF_AFP1 | IF_AFP2 | IF_AFP3) + +/* COMPARE */ + C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) + C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xe359, CY, RXY_a, LD, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xb920, CGR, RRE, Z, r1_o, r2_o, 0, 0, 0, cmps64) + C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) + C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) + C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) + F(0xb309, CEBR, RRE, Z, e1, e2, 0, 0, ceb, 0, IF_BFP) + F(0xb319, CDBR, RRE, Z, f1, f2, 0, 0, cdb, 0, IF_BFP) + F(0xb349, CXBR, RRE, Z, x2h, x2l, x1, 0, cxb, 0, IF_BFP) + F(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0, IF_BFP) + F(0xed19, CDB, RXE, Z, f1, m2_64, 0, 0, cdb, 0, IF_BFP) +/* COMPARE AND SIGNAL */ + F(0xb308, KEBR, RRE, Z, e1, e2, 0, 0, keb, 0, IF_BFP) + F(0xb318, KDBR, RRE, Z, f1, f2, 0, 0, kdb, 0, IF_BFP) + F(0xb348, KXBR, RRE, Z, x2h, x2l, x1, 0, kxb, 0, IF_BFP) + F(0xed08, KEB, RXE, Z, e1, m2_32u, 0, 0, keb, 0, IF_BFP) + F(0xed18, KDB, RXE, Z, f1, m2_64, 0, 0, kdb, 0, IF_BFP) +/* COMPARE IMMEDIATE */ + C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) + C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) +/* COMPARE RELATIVE LONG */ + C(0xc60d, CRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32) + C(0xc608, CGRL, RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64) + C(0xc60c, CGFRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64) +/* COMPARE HALFWORD */ + C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe334, CGH, RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64) +/* COMPARE HALFWORD IMMEDIATE */ + C(0xa70e, CHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps32) + C(0xa70f, CGHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps64) + C(0xe554, CHHSI, SIL, GIE, m1_16s, i2, 0, 0, 0, cmps64) + C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64) + C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64) +/* COMPARE HALFWORD RELATIVE LONG */ + C(0xc605, CHRL, RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) + C(0xc604, CGHRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) +/* COMPARE HIGH */ + C(0xb9cd, CHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmps32) + C(0xb9dd, CHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmps32) + C(0xe3cd, CHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmps32) +/* COMPARE IMMEDIATE HIGH */ + C(0xcc0d, CIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmps32) + +/* COMPARE LOGICAL */ + C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) + C(0x5500, CL, RX_a, Z, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xe355, CLY, RXY_a, LD, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xb921, CLGR, RRE, Z, r1, r2, 0, 0, 0, cmpu64) + C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) + C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) + C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) + C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0) +/* COMPARE LOGICAL HIGH */ + C(0xb9cf, CLHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmpu32) + C(0xb9df, CLHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmpu32) + C(0xe3cf, CLHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmpu32) +/* COMPARE LOGICAL IMMEDIATE */ + C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) + C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) + C(0x9500, CLI, SI, Z, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xeb55, CLIY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64) + C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64) + C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL IMMEDIATE HIGH */ + C(0xcc0f, CLIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmpu32) +/* COMPARE LOGICAL RELATIVE LONG */ + C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32) + C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64) + C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) + C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) + C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL LONG */ + C(0x0f00, CLCL, RR_a, Z, 0, 0, 0, 0, clcl, 0) +/* COMPARE LOGICAL LONG EXTENDED */ + C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE LOGICAL LONG UNICODE */ + C(0xeb8f, CLCLU, RSY_a, E2, 0, a2, 0, 0, clclu, 0) +/* COMPARE LOGICAL CHARACTERS UNDER MASK */ + C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) + C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) + C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) +/* COMPARE LOGICAL STRING */ + C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) + +/* COMPARE AND BRANCH */ + D(0xecf6, CRB, RRS, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xece4, CGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xec76, CRJ, RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xec64, CGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xecfe, CIB, RIS, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xecfc, CGIB, RIS, GIE, r1_o, i2, 0, 0, cj, 0, 0) + D(0xec7e, CIJ, RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xec7c, CGIJ, RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0) +/* COMPARE LOGICAL AND BRANCH */ + D(0xecf7, CLRB, RRS, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xece5, CLGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xec77, CLRJ, RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xec65, CLGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xecff, CLIB, RIS, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xecfd, CLGIB, RIS, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + D(0xec7f, CLIJ, RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + +/* COMPARE AND SWAP */ + D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL) + D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL) + D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, MO_TEUQ) +/* COMPARE DOUBLE AND SWAP */ + D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ) + D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ) + C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0) +/* COMPARE AND SWAP AND STORE */ + C(0xc802, CSST, SSF, CASS, la1, a2, 0, 0, csst, 0) + +/* COMPARE AND TRAP */ + D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) + D(0xb960, CGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0) + D(0xec72, CIT, RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0) + D(0xec70, CGIT, RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0) +/* COMPARE LOGICAL AND TRAP */ + D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) + 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_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) + C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) +/* CONVERT TO FIXED */ + F(0xb398, CFEBR, RRF_e, Z, 0, e2, new, r1_32, cfeb, 0, IF_BFP) + F(0xb399, CFDBR, RRF_e, Z, 0, f2, new, r1_32, cfdb, 0, IF_BFP) + F(0xb39a, CFXBR, RRF_e, Z, x2h, x2l, new, r1_32, cfxb, 0, IF_BFP) + F(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0, IF_BFP) + F(0xb3a9, CGDBR, RRF_e, Z, 0, f2, r1, 0, cgdb, 0, IF_BFP) + F(0xb3aa, CGXBR, RRF_e, Z, x2h, x2l, r1, 0, cgxb, 0, IF_BFP) +/* CONVERT FROM FIXED */ + F(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0, IF_BFP) + F(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, new, f1, cdgb, 0, IF_BFP) + F(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, new_P, x1, cxgb, 0, IF_BFP) + F(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0, IF_BFP) + F(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, new, f1, cdgb, 0, IF_BFP) + F(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, new_P, x1, cxgb, 0, IF_BFP) +/* CONVERT TO LOGICAL */ + F(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0, IF_BFP) + F(0xb39d, CLFDBR, RRF_e, FPE, 0, f2, new, r1_32, clfdb, 0, IF_BFP) + F(0xb39e, CLFXBR, RRF_e, FPE, x2h, x2l, new, r1_32, clfxb, 0, IF_BFP) + F(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0, IF_BFP) + F(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2, r1, 0, clgdb, 0, IF_BFP) + F(0xb3ae, CLGXBR, RRF_e, FPE, x2h, x2l, r1, 0, clgxb, 0, IF_BFP) +/* CONVERT FROM LOGICAL */ + F(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0, IF_BFP) + F(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, new, f1, cdlgb, 0, IF_BFP) + F(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, new_P, x1, cxlgb, 0, IF_BFP) + F(0xb3a0, CELGBR, RRF_e, FPE, 0, r2_o, new, e1, celgb, 0, IF_BFP) + F(0xb3a1, CDLGBR, RRF_e, FPE, 0, r2_o, new, f1, cdlgb, 0, IF_BFP) + F(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, new_P, x1, cxlgb, 0, IF_BFP) + +/* CONVERT UTF-8 TO UTF-16 */ + D(0xb2a7, CU12, RRF_c, Z, 0, 0, 0, 0, cuXX, 0, 12) +/* CONVERT UTF-8 TO UTF-32 */ + D(0xb9b0, CU14, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 14) +/* CONVERT UTF-16 to UTF-8 */ + D(0xb2a6, CU21, RRF_c, Z, 0, 0, 0, 0, cuXX, 0, 21) +/* CONVERT UTF-16 to UTF-32 */ + D(0xb9b1, CU24, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 24) +/* CONVERT UTF-32 to UTF-8 */ + D(0xb9b2, CU41, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 41) +/* CONVERT UTF-32 to UTF-16 */ + D(0xb9b3, CU42, RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 42) + +/* DIVIDE */ + C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) + C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) + F(0xb30d, DEBR, RRE, Z, e1, e2, new, e1, deb, 0, IF_BFP) + F(0xb31d, DDBR, RRE, Z, f1, f2, new, f1, ddb, 0, IF_BFP) + F(0xb34d, DXBR, RRE, Z, x2h, x2l, x1, x1, dxb, 0, IF_BFP) + F(0xed0d, DEB, RXE, Z, e1, m2_32u, new, e1, deb, 0, IF_BFP) + F(0xed1d, DDB, RXE, Z, f1, m2_64, new, f1, ddb, 0, IF_BFP) +/* DIVIDE LOGICAL */ + C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) + C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) + C(0xb987, DLGR, RRE, Z, 0, r2_o, r1_P, 0, divu64, 0) + C(0xe387, DLG, RXY_a, Z, 0, m2_64, r1_P, 0, divu64, 0) +/* DIVIDE SINGLE */ + C(0xb90d, DSGR, RRE, Z, r1p1, r2, r1_P, 0, divs64, 0) + C(0xb91d, DSGFR, RRE, Z, r1p1, r2_32s, r1_P, 0, divs64, 0) + C(0xe30d, DSG, RXY_a, Z, r1p1, m2_64, r1_P, 0, divs64, 0) + C(0xe31d, DSGF, RXY_a, Z, r1p1, m2_32s, r1_P, 0, divs64, 0) + +/* EXCLUSIVE OR */ + C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) + C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) + C(0x5700, X, RX_a, Z, r1, m2_32s, new, r1_32, xor, nz32) + C(0xe357, XY, RXY_a, LD, r1, m2_32s, new, r1_32, xor, nz32) + C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) + C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) + C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) + C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0) +/* EXCLUSIVE OR IMMEDIATE */ + D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) + D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) + D(0x9700, XI, SI, Z, la1, i2_8u, new, 0, xi, nz64, MO_UB) + D(0xeb57, XIY, SIY, LD, la1, i2_8u, new, 0, xi, nz64, MO_UB) + +/* EXECUTE */ + C(0x4400, EX, RX_a, Z, 0, a2, 0, 0, ex, 0) +/* EXECUTE RELATIVE LONG */ + C(0xc600, EXRL, RIL_b, EE, 0, ri2, 0, 0, ex, 0) + +/* EXTRACT ACCESS */ + C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) +/* EXTRACT CPU ATTRIBUTE */ + C(0xeb4c, ECAG, RSY_a, GIE, 0, a2, r1, 0, ecag, 0) +/* EXTRACT CPU TIME */ + F(0xc801, ECTG, SSF, ECT, 0, 0, 0, 0, ectg, 0, IF_IO) +/* EXTRACT FPC */ + F(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0, IF_BFP) +/* EXTRACT PSW */ + C(0xb98d, EPSW, RRE, Z, 0, 0, 0, 0, epsw, 0) + +/* FIND LEFTMOST ONE */ + C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0) + +/* INSERT CHARACTER */ + C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) + C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) +/* INSERT CHARACTERS UNDER MASK */ + D(0xbf00, ICM, RS_b, Z, 0, a2, r1, 0, icm, 0, 0) + D(0xeb81, ICMY, RSY_b, LD, 0, a2, r1, 0, icm, 0, 0) + D(0xeb80, ICMH, RSY_b, Z, 0, a2, r1, 0, icm, 0, 32) +/* INSERT IMMEDIATE */ + D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) + D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) + D(0xa500, IIHH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1030) + D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) + D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) + D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) +/* INSERT PROGRAM MASK */ + C(0xb222, IPM, RRE, Z, 0, 0, r1, 0, ipm, 0) + +/* LOAD */ + C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) + C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xe358, LY, RXY_a, LD, 0, a2, new, r1_32, ld32s, 0) + C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) + C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) + C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) + C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) + F(0x2800, LDR, RR_a, Z, 0, f2, 0, f1, mov2, 0, IF_AFP1 | IF_AFP2) + F(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0, IF_AFP1) + F(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0, IF_AFP1) + F(0x3800, LER, RR_a, Z, 0, e2, 0, cond_e1e2, mov2, 0, IF_AFP1 | IF_AFP2) + F(0x7800, LE, RX_a, Z, 0, m2_32u, 0, e1, mov2, 0, IF_AFP1) + F(0xed64, LEY, RXY_a, LD, 0, m2_32u, 0, e1, mov2, 0, IF_AFP1) + F(0xb365, LXR, RRE, Z, x2h, x2l, 0, x1, movx, 0, IF_AFP1) +/* LOAD IMMEDIATE */ + C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) +/* LOAD RELATIVE LONG */ + C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) + C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) + C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) +/* LOAD ADDRESS */ + C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) + C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) +/* LOAD ADDRESS EXTENDED */ + C(0x5100, LAE, RX_a, Z, 0, a2, 0, r1, mov2e, 0) + C(0xe375, LAEY, RXY_a, GIE, 0, a2, 0, r1, mov2e, 0) +/* LOAD ADDRESS RELATIVE LONG */ + C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) +/* LOAD AND ADD */ + D(0xebf8, LAA, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, laa, adds32, MO_TESL) + D(0xebe8, LAAG, RSY_a, ILA, r3, a2, new, in2_r1, laa, adds64, MO_TEUQ) +/* LOAD AND ADD LOGICAL */ + D(0xebfa, LAAL, RSY_a, ILA, r3_32u, a2, new, in2_r1_32, laa, addu32, MO_TEUL) + D(0xebea, LAALG, RSY_a, ILA, r3, a2, new, in2_r1, laa, addu64, MO_TEUQ) +/* LOAD AND AND */ + D(0xebf4, LAN, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lan, nz32, MO_TESL) + D(0xebe4, LANG, RSY_a, ILA, r3, a2, new, in2_r1, lan, nz64, MO_TEUQ) +/* LOAD AND EXCLUSIVE OR */ + D(0xebf7, LAX, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lax, nz32, MO_TESL) + D(0xebe7, LAXG, RSY_a, ILA, r3, a2, new, in2_r1, lax, nz64, MO_TEUQ) +/* LOAD AND OR */ + D(0xebf6, LAO, RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lao, nz32, MO_TESL) + D(0xebe6, LAOG, RSY_a, ILA, r3, a2, new, in2_r1, lao, nz64, MO_TEUQ) +/* LOAD AND TEST */ + C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32) + C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64) + C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64) + C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) + C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) + C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) + F(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32, IF_BFP) + F(0xb312, LTDBR, RRE, Z, 0, f2, 0, f1, mov2, f64, IF_BFP) + F(0xb342, LTXBR, RRE, Z, x2h, x2l, 0, x1, movx, f128, IF_BFP) +/* LOAD AND TRAP */ + 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(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) +/* LOAD BYTE */ + C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) + C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) + C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) + C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD BYTE HIGH */ + C(0xe3c0, LBH, RXY_a, HW, 0, a2, new, r1_32h, ld8s, 0) +/* LOAD COMPLEMENT */ + C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) + C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) + C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) + F(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32, IF_BFP) + F(0xb313, LCDBR, RRE, Z, 0, f2, new, f1, negf64, f64, IF_BFP) + F(0xb343, LCXBR, RRE, Z, x2h, x2l, new_P, x1, negf128, f128, IF_BFP) + F(0xb373, LCDFR, RRE, FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2) +/* LOAD COUNT TO BLOCK BOUNDARY */ + C(0xe727, LCBB, RXE, V, la2, 0, r1, 0, lcbb, 0) +/* LOAD HALFWORD */ + C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) + C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) + C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0) + C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0) + C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0) +/* LOAD HALFWORD HIGH */ + C(0xe3c4, LHH, RXY_a, HW, 0, a2, new, r1_32h, ld16s, 0) +/* LOAD HALFWORD IMMEDIATE */ + C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0) + C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0) +/* LOAD HALFWORD RELATIVE LONG */ + C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) + C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) +/* LOAD HIGH */ + C(0xe3ca, LFH, RXY_a, HW, 0, a2, new, r1_32h, ld32u, 0) +/* LOAG HIGH AND TRAP */ + C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0) +/* LOAD LOGICAL */ + C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) + C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) +/* LOAD LOGICAL AND TRAP */ + C(0xe39d, LLGFAT, RXY_a, LAT, 0, a2, r1, 0, llgfat, 0) +/* LOAD LOGICAL RELATIVE LONG */ + C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) +/* LOAD LOGICAL CHARACTER */ + C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0) + C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) + C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0) + C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0) +/* LOAD LOGICAL CHARACTER HIGH */ + C(0xe3c2, LLCH, RXY_a, HW, 0, a2, new, r1_32h, ld8u, 0) +/* LOAD LOGICAL HALFWORD */ + C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0) + C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0) + C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0) + C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0) +/* LOAD LOGICAL HALFWORD HIGH */ + C(0xe3c6, LLHH, RXY_a, HW, 0, a2, new, r1_32h, ld16u, 0) +/* LOAD LOGICAL HALFWORD RELATIVE LONG */ + C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) + C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) +/* LOAD LOGICAL IMMEDATE */ + D(0xc00e, LLIHF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32) + D(0xc00f, LLILF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0) + D(0xa50c, LLIHH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 48) + D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) + D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) + D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) +/* LOAD LOGICAL THIRTY ONE BITS */ + C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) + C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) +/* LOAD LOGICAL THIRTY ONE BITS AND TRAP */ + C(0xe39c, LLGTAT, RXY_a, LAT, 0, m2_32u, r1, 0, llgtat, 0) + +/* LOAD FPR FROM GR */ + F(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0, IF_AFP1) +/* LOAD GR FROM FPR */ + F(0xb3cd, LGDR, RRE, FPRGR, 0, f2, 0, r1, mov2, 0, IF_AFP2) +/* LOAD NEGATIVE */ + C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) + C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) + C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) + F(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32, IF_BFP) + F(0xb311, LNDBR, RRE, Z, 0, f2, new, f1, nabsf64, f64, IF_BFP) + F(0xb341, LNXBR, RRE, Z, x2h, x2l, new_P, x1, nabsf128, f128, IF_BFP) + F(0xb371, LNDFR, RRE, FPSSH, 0, f2, new, f1, nabsf64, 0, IF_AFP1 | IF_AFP2) +/* LOAD ON CONDITION */ + C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) + C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0) + C(0xebf2, LOC, RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0) + C(0xebe2, LOCG, RSY_b, LOC, r1, m2_64, r1, 0, loc, 0) +/* LOAD HALFWORD IMMEDIATE ON CONDITION */ + C(0xec42, LOCHI, RIE_g, LOC2, r1, i2, new, r1_32, loc, 0) + C(0xec46, LOCGHI, RIE_g, LOC2, r1, i2, r1, 0, loc, 0) + C(0xec4e, LOCHHI, RIE_g, LOC2, r1_sr32, i2, new, r1_32h, loc, 0) +/* LOAD HIGH ON CONDITION */ + C(0xb9e0, LOCFHR, RRF_c, LOC2, r1_sr32, r2, new, r1_32h, loc, 0) + C(0xebe0, LOCFH, RSY_b, LOC2, r1_sr32, m2_32u, new, r1_32h, loc, 0) +/* LOAD PAIR DISJOINT */ + D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL) + D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEUQ) +/* LOAD PAIR FROM QUADWORD */ + C(0xe38f, LPQ, RXY_a, Z, 0, a2, r1_P, 0, lpq, 0) +/* LOAD POSITIVE */ + C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) + C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) + C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) + F(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32, IF_BFP) + F(0xb310, LPDBR, RRE, Z, 0, f2, new, f1, absf64, f64, IF_BFP) + F(0xb340, LPXBR, RRE, Z, x2h, x2l, new_P, x1, absf128, f128, IF_BFP) + F(0xb370, LPDFR, RRE, FPSSH, 0, f2, new, f1, absf64, 0, IF_AFP1 | IF_AFP2) +/* LOAD REVERSED */ + C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) + C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) + C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) + C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) + C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) +/* LOAD ZERO */ + F(0xb374, LZER, RRE, Z, 0, 0, 0, e1, zero, 0, IF_AFP1) + F(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0, IF_AFP1) + F(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0, IF_AFP1) + +/* LOAD FPC */ + F(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0, IF_BFP) +/* LOAD FPC AND SIGNAL */ + F(0xb2bd, LFAS, S, IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0, IF_DFP) +/* LOAD FP INTEGER */ + F(0xb357, FIEBR, RRF_e, Z, 0, e2, new, e1, fieb, 0, IF_BFP) + F(0xb35f, FIDBR, RRF_e, Z, 0, f2, new, f1, fidb, 0, IF_BFP) + F(0xb347, FIXBR, RRF_e, Z, x2h, x2l, new_P, x1, fixb, 0, IF_BFP) + +/* LOAD LENGTHENED */ + F(0xb304, LDEBR, RRE, Z, 0, e2, new, f1, ldeb, 0, IF_BFP) + F(0xb305, LXDBR, RRE, Z, 0, f2, new_P, x1, lxdb, 0, IF_BFP) + F(0xb306, LXEBR, RRE, Z, 0, e2, new_P, x1, lxeb, 0, IF_BFP) + F(0xed04, LDEB, RXE, Z, 0, m2_32u, new, f1, ldeb, 0, IF_BFP) + F(0xed05, LXDB, RXE, Z, 0, m2_64, new_P, x1, lxdb, 0, IF_BFP) + F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_P, x1, lxeb, 0, IF_BFP) + F(0xb324, LDER, RXE, Z, 0, e2, new, f1, lde, 0, IF_AFP1) + F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1) +/* LOAD ROUNDED */ + F(0xb344, LEDBR, RRF_e, Z, 0, f2, new, e1, ledb, 0, IF_BFP) + F(0xb345, LDXBR, RRF_e, Z, x2h, x2l, new, f1, ldxb, 0, IF_BFP) + F(0xb346, LEXBR, RRF_e, Z, x2h, x2l, new, e1, lexb, 0, IF_BFP) + +/* LOAD MULTIPLE */ + C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) + C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) + C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) +/* LOAD MULTIPLE HIGH */ + C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) +/* LOAD ACCESS MULTIPLE */ + C(0x9a00, LAM, RS_a, Z, 0, a2, 0, 0, lam, 0) + C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) + +/* MONITOR CALL */ + C(0xaf00, MC, SI, Z, la1, 0, 0, 0, mc, 0) + +/* MOVE */ + C(0xd200, MVC, SS_a, Z, la1, a2, 0, 0, mvc, 0) + C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) + C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) + C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) + C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) + C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) +/* MOVE INVERSE */ + C(0xe800, MVCIN, SS_a, Z, la1, a2, 0, 0, mvcin, 0) +/* MOVE LONG */ + C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) +/* MOVE LONG EXTENDED */ + C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) +/* MOVE LONG UNICODE */ + C(0xeb8e, MVCLU, RSY_a, E2, 0, a2, 0, 0, mvclu, 0) +/* MOVE NUMERICS */ + C(0xd100, MVN, SS_a, Z, la1, a2, 0, 0, mvn, 0) +/* MOVE RIGHT TO LEFT */ + C(0xe50a, MVCRL, SSE, MIE3, la1, a2, 0, 0, mvcrl, 0) +/* MOVE PAGE */ + C(0xb254, MVPG, RRE, Z, 0, 0, 0, 0, mvpg, 0) +/* MOVE STRING */ + C(0xb255, MVST, RRE, Z, 0, 0, 0, 0, mvst, 0) +/* MOVE WITH OPTIONAL SPECIFICATION */ + C(0xc800, MVCOS, SSF, MVCOS, la1, a2, 0, 0, mvcos, 0) +/* MOVE WITH OFFSET */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf100, MVO, SS_a, Z, la1, a2, 0, 0, mvo, 0) +/* MOVE ZONES */ + C(0xd300, MVZ, SS_a, Z, la1, a2, 0, 0, mvz, 0) + +/* MULTIPLY */ + C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) + C(0xb9ec, MGRK, RRF_a, MIE2,r3_o, r2_o, r1_P, 0, muls128, 0) + C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xe384, MG, RXY_a, MIE2,r1p1_o, m2_64, r1_P, 0, muls128, 0) + F(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0, IF_BFP) + F(0xb31c, MDBR, RRE, Z, f1, f2, new, f1, mdb, 0, IF_BFP) + F(0xb34c, MXBR, RRE, Z, x2h, x2l, x1, x1, mxb, 0, IF_BFP) + F(0xb30c, MDEBR, RRE, Z, f1, e2, new, f1, mdeb, 0, IF_BFP) + F(0xb307, MXDBR, RRE, Z, 0, f2, x1, x1, mxdb, 0, IF_BFP) + F(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0, IF_BFP) + F(0xed1c, MDB, RXE, Z, f1, m2_64, new, f1, mdb, 0, IF_BFP) + F(0xed0c, MDEB, RXE, Z, f1, m2_32u, new, f1, mdeb, 0, IF_BFP) + F(0xed07, MXDB, RXE, Z, 0, m2_64, x1, x1, mxdb, 0, IF_BFP) +/* MULTIPLY HALFWORD */ + C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) + C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) + C(0xe33c, MGH, RXY_a, MIE2,r1_o, m2_16s, r1, 0, mul, 0) +/* MULTIPLY HALFWORD IMMEDIATE */ + C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) + C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY LOGICAL */ + C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) + C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) + C(0xb986, MLGR, RRE, Z, r1p1, r2_o, r1_P, 0, mul128, 0) + C(0xe386, MLG, RXY_a, Z, r1p1, m2_64, r1_P, 0, mul128, 0) +/* MULTIPLY SINGLE */ + C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) + C(0xb9fd, MSRKC, RRF_a, MIE2,r3_32s, r2_32s, new, r1_32, mul, muls32) + C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xe351, MSY, RXY_a, LD, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xe353, MSC, RXY_a, MIE2,r1_32s, m2_32s, new, r1_32, mul, muls32) + C(0xb90c, MSGR, RRE, Z, r1_o, r2_o, r1, 0, mul, 0) + C(0xb9ed, MSGRKC, RRF_a, MIE2,r3_o, r2_o, new_P, out2_r1, muls128, muls64) + C(0xb91c, MSGFR, RRE, Z, r1_o, r2_32s, r1, 0, mul, 0) + C(0xe30c, MSG, RXY_a, Z, r1_o, m2_64, r1, 0, mul, 0) + C(0xe383, MSGC, RXY_a, MIE2,r1_o, m2_64, new_P, out2_r1, muls128, muls64) + C(0xe31c, MSGF, RXY_a, Z, r1_o, m2_32s, r1, 0, mul, 0) +/* MULTIPLY SINGLE IMMEDIATE */ + C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) + C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) + +/* MULTIPLY AND ADD */ + F(0xb30e, MAEBR, RRD, Z, e1, e2, new, e1, maeb, 0, IF_BFP) + F(0xb31e, MADBR, RRD, Z, f1, f2, new, f1, madb, 0, IF_BFP) + F(0xed0e, MAEB, RXF, Z, e1, m2_32u, new, e1, maeb, 0, IF_BFP) + F(0xed1e, MADB, RXF, Z, f1, m2_64, new, f1, madb, 0, IF_BFP) +/* MULTIPLY AND SUBTRACT */ + F(0xb30f, MSEBR, RRD, Z, e1, e2, new, e1, mseb, 0, IF_BFP) + F(0xb31f, MSDBR, RRD, Z, f1, f2, new, f1, msdb, 0, IF_BFP) + F(0xed0f, MSEB, RXF, Z, e1, m2_32u, new, e1, mseb, 0, IF_BFP) + F(0xed1f, MSDB, RXF, Z, f1, m2_64, new, f1, msdb, 0, IF_BFP) + +/* NAND */ + C(0xb974, NNRK, RRF_a, MIE3, r2, r3, new, r1_32, nand, nz32) + C(0xb964, NNGRK, RRF_a, MIE3, r2, r3, r1, 0, nand, nz64) +/* NOR */ + C(0xb976, NORK, RRF_a, MIE3, r2, r3, new, r1_32, nor, nz32) + C(0xb966, NOGRK, RRF_a, MIE3, r2, r3, r1, 0, nor, nz64) +/* NOT EXCLUSIVE OR */ + C(0xb977, NXRK, RRF_a, MIE3, r2, r3, new, r1_32, nxor, nz32) + C(0xb967, NXGRK, RRF_a, MIE3, r2, r3, r1, 0, nxor, nz64) + +/* OR */ + C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) + C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) + C(0x5600, O, RX_a, Z, r1, m2_32s, new, r1_32, or, nz32) + C(0xe356, OY, RXY_a, LD, r1, m2_32s, new, r1_32, or, nz32) + C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) + C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) + C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) + C(0xd600, OC, SS_a, Z, la1, a2, 0, 0, oc, 0) +/* OR IMMEDIATE */ + D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) + D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) + D(0xa508, OIHH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1030) + D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) + D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) + D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) + D(0x9600, OI, SI, Z, la1, i2_8u, new, 0, oi, nz64, MO_UB) + D(0xeb56, OIY, SIY, LD, la1, i2_8u, new, 0, oi, nz64, MO_UB) +/* OR WITH COMPLEMENT */ + C(0xb975, OCRK, RRF_a, MIE3, r2, r3, new, r1_32, orc, nz32) + C(0xb965, OCGRK, RRF_a, MIE3, r2, r3, r1, 0, orc, nz64) + +/* PACK */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf200, PACK, SS_a, Z, la1, a2, 0, 0, pack, 0) +/* PACK ASCII */ + C(0xe900, PKA, SS_f, E2, la1, a2, 0, 0, pka, 0) +/* PACK UNICODE */ + C(0xe100, PKU, SS_f, E2, la1, a2, 0, 0, pku, 0) + +/* POPULATION COUNT */ + C(0xb9e1, POPCNT, RRF_c, PC, 0, r2_o, r1, 0, popcnt, nz64) + +/* PREFETCH */ + /* Implemented as nops of course. */ + C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) + C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) +/* PERFORM PROCESSOR ASSIST */ + /* Implemented as nop of course. */ + C(0xb2e8, PPA, RRF_c, PPA, 0, 0, 0, 0, 0, 0) + +/* ROTATE LEFT SINGLE LOGICAL */ + C(0xeb1d, RLL, RSY_a, Z, r3_o, sh, new, r1_32, rll32, 0) + C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh, r1, 0, rll64, 0) + +/* ROTATE THEN INSERT SELECTED BITS */ + C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) + C(0xec59, RISBGN, RIE_f, MIE, 0, r2, r1, 0, risbg, 0) + C(0xec5d, RISBHG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) + C(0xec51, RISBLG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) +/* ROTATE_THEN SELECTED BITS */ + C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec57, RXSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + +/* SEARCH STRING */ + C(0xb25e, SRST, RRE, Z, 0, 0, 0, 0, srst, 0) +/* SEARCH STRING UNICODE */ + C(0xb9be, SRSTU, RRE, ETF3, 0, 0, 0, 0, srstu, 0) + +/* SELECT */ + C(0xb9f0, SELR, RRF_a, MIE3, r3, r2, new, r1_32, loc, 0) + C(0xb9e3, SELGR, RRF_a, MIE3, r3, r2, r1, 0, loc, 0) +/* SELECT HIGH */ + C(0xb9c0, SELFHR, RRF_a, MIE3, r3_sr32, r2_sr32, new, r1_32h, loc, 0) + +/* SET ACCESS */ + C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) +/* SET ADDRESSING MODE */ + D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0) + D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1) + D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3) +/* SET FPC */ + F(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0, IF_BFP) +/* SET FPC AND SIGNAL */ + F(0xb385, SFASR, RRE, IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0, IF_DFP) +/* SET BFP ROUNDING MODE */ + F(0xb299, SRNM, S, Z, la2, 0, 0, 0, srnm, 0, IF_BFP) + F(0xb2b8, SRNMB, S, FPE, la2, 0, 0, 0, srnmb, 0, IF_BFP) +/* SET DFP ROUNDING MODE */ + F(0xb2b9, SRNMT, S, DFPR, la2, 0, 0, 0, srnmt, 0, IF_DFP) +/* SET PROGRAM MASK */ + C(0x0400, SPM, RR_a, Z, r1, 0, 0, 0, spm, 0) + +/* SHIFT LEFT SINGLE */ + D(0x8b00, SLA, RS_a, Z, r1, sh, new, r1_32, sla, 0, 31) + D(0xebdd, SLAK, RSY_a, DO, r3, sh, new, r1_32, sla, 0, 31) + D(0xeb0b, SLAG, RSY_a, Z, r3, sh, r1, 0, sla, 0, 63) +/* SHIFT LEFT SINGLE LOGICAL */ + C(0x8900, SLL, RS_a, Z, r1_o, sh, new, r1_32, sll, 0) + C(0xebdf, SLLK, RSY_a, DO, r3_o, sh, new, r1_32, sll, 0) + C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh, r1, 0, sll, 0) +/* SHIFT RIGHT SINGLE */ + C(0x8a00, SRA, RS_a, Z, r1_32s, sh, new, r1_32, sra, s32) + C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh, new, r1_32, sra, s32) + C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh, r1, 0, sra, s64) +/* SHIFT RIGHT SINGLE LOGICAL */ + C(0x8800, SRL, RS_a, Z, r1_32u, sh, new, r1_32, srl, 0) + C(0xebde, SRLK, RSY_a, DO, r3_32u, sh, new, r1_32, srl, 0) + C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh, r1, 0, srl, 0) +/* SHIFT LEFT DOUBLE */ + D(0x8f00, SLDA, RS_a, Z, r1_D32, sh, new, r1_D32, sla, 0, 63) +/* SHIFT LEFT DOUBLE LOGICAL */ + C(0x8d00, SLDL, RS_a, Z, r1_D32, sh, new, r1_D32, sll, 0) +/* SHIFT RIGHT DOUBLE */ + C(0x8e00, SRDA, RS_a, Z, r1_D32, sh, new, r1_D32, sra, s64) +/* SHIFT RIGHT DOUBLE LOGICAL */ + C(0x8c00, SRDL, RS_a, Z, r1_D32, sh, new, r1_D32, srl, 0) + +/* SQUARE ROOT */ + F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP) + F(0xb315, SQDBR, RRE, Z, 0, f2, new, f1, sqdb, 0, IF_BFP) + F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_P, x1, sqxb, 0, IF_BFP) + F(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0, IF_BFP) + F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP) + +/* STORE */ + C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) + C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) + C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) + F(0x6000, STD, RX_a, Z, f1, a2, 0, 0, st64, 0, IF_AFP1) + F(0xed67, STDY, RXY_a, LD, f1, a2, 0, 0, st64, 0, IF_AFP1) + F(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0, IF_AFP1) + F(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0, IF_AFP1) +/* STORE RELATIVE LONG */ + C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) + C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) +/* STORE CHARACTER */ + C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) + C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE CHARACTER HIGH */ + C(0xe3c3, STCH, RXY_a, HW, r1_sr32, a2, 0, 0, st8, 0) +/* STORE CHARACTERS UNDER MASK */ + D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2c, STCMH, RSY_b, Z, r1_o, a2, 0, 0, stcm, 0, 32) +/* STORE HALFWORD */ + C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) + C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) +/* STORE HALFWORD HIGH */ + C(0xe3c7, STHH, RXY_a, HW, r1_sr32, a2, 0, 0, st16, 0) +/* STORE HALFWORD RELATIVE LONG */ + C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE HIGH */ + C(0xe3cb, STFH, RXY_a, HW, r1_sr32, a2, 0, 0, st32, 0) +/* STORE ON CONDITION */ + D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) + D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) +/* STORE HIGH ON CONDITION */ + D(0xebe1, STOCFH, RSY_b, LOC2, 0, 0, 0, 0, soc, 0, 2) +/* STORE REVERSED */ + C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) + C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) + C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) + +/* STORE CLOCK */ + F(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0, IF_IO) + F(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0, IF_IO) +/* STORE CLOCK EXTENDED */ + F(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0, IF_IO) + +/* STORE FACILITY LIST EXTENDED */ + C(0xb2b0, STFLE, S, SFLE, 0, a2, 0, 0, stfle, 0) +/* STORE FPC */ + F(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0, IF_BFP) + +/* STORE MULTIPLE */ + D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) + D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) + D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) +/* STORE MULTIPLE HIGH */ + C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) +/* STORE ACCESS MULTIPLE */ + C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) + C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) +/* STORE PAIR TO QUADWORD */ + C(0xe38e, STPQ, RXY_a, Z, 0, a2, r1_P, 0, stpq, 0) + +/* SUBTRACT */ + C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) + C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) + C(0x5b00, S, RX_a, Z, r1, m2_32s, new, r1_32, sub, subs32) + C(0xe35b, SY, RXY_a, LD, r1, m2_32s, new, r1_32, sub, subs32) + C(0xb909, SGR, RRE, Z, r1, r2, r1, 0, sub, subs64) + C(0xb919, SGFR, RRE, Z, r1, r2_32s, r1, 0, sub, subs64) + C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) + C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) + C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) + F(0xb30b, SEBR, RRE, Z, e1, e2, new, e1, seb, f32, IF_BFP) + F(0xb31b, SDBR, RRE, Z, f1, f2, new, f1, sdb, f64, IF_BFP) + F(0xb34b, SXBR, RRE, Z, x2h, x2l, x1, x1, sxb, f128, IF_BFP) + F(0xed0b, SEB, RXE, Z, e1, m2_32u, new, e1, seb, f32, IF_BFP) + F(0xed1b, SDB, RXE, Z, f1, m2_64, new, f1, sdb, f64, IF_BFP) +/* SUBTRACT HALFWORD */ + C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) + C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) + C(0xe339, SGH, RXY_a, MIE2,r1, m2_16s, r1, 0, sub, subs64) +/* SUBTRACT HIGH */ + C(0xb9c9, SHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subs32) + C(0xb9d9, SHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subs32) +/* SUBTRACT LOGICAL */ + C(0x1f00, SLR, RR_a, Z, r1_32u, r2_32u, new, r1_32, sub, subu32) + C(0xb9fb, SLRK, RRF_a, DO, r2_32u, r3_32u, new, r1_32, sub, subu32) + C(0x5f00, SL, RX_a, Z, r1_32u, m2_32u, new, r1_32, sub, subu32) + C(0xe35f, SLY, RXY_a, LD, r1_32u, m2_32u, new, r1_32, sub, subu32) + C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, subu64, subu64) + C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, subu64, subu64) + C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, subu64, subu64) + C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, subu64, subu64) + C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, subu64, subu64) +/* SUBTRACT LOCICAL HIGH */ + C(0xb9cb, SLHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subu32) + C(0xb9db, SLHHLR, RRF_a, HW, r2_sr32, r3_32u, new, r1_32h, sub, subu32) +/* SUBTRACT LOGICAL IMMEDIATE */ + C(0xc205, SLFI, RIL_a, EI, r1_32u, i2_32u, new, r1_32, sub, subu32) + C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, subu64, subu64) +/* SUBTRACT LOGICAL WITH BORROW */ + C(0xb999, SLBR, RRE, Z, r1_32u, r2_32u, new, r1_32, subb32, subu32) + C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb64, subu64) + C(0xe399, SLB, RXY_a, Z, r1_32u, m2_32u, new, r1_32, subb32, subu32) + C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb64, subu64) + +/* SUPERVISOR CALL */ + C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) + +/* TEST ADDRESSING MODE */ + C(0x010b, TAM, E, Z, 0, 0, 0, 0, tam, 0) + +/* TEST AND SET */ + C(0x9300, TS, S, Z, 0, a2, 0, 0, ts, 0) + +/* TEST DATA CLASS */ + F(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0, IF_BFP) + F(0xed11, TCDB, RXE, Z, f1, a2, 0, 0, tcdb, 0, IF_BFP) + F(0xed12, TCXB, RXE, Z, 0, a2, x1, 0, tcxb, 0, IF_BFP) + +/* TEST DECIMAL */ + C(0xebc0, TP, RSL, E2, la1, 0, 0, 0, tp, 0) + +/* TEST UNDER MASK */ + C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) + C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) + D(0xa702, TMHH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 48) + D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) + D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) + D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) + +/* TRANSLATE */ + C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) +/* TRANSLATE AND TEST */ + C(0xdd00, TRT, SS_a, Z, la1, a2, 0, 0, trt, 0) +/* TRANSLATE AND TEST REVERSE */ + C(0xd000, TRTR, SS_a, ETF3, la1, a2, 0, 0, trtr, 0) +/* TRANSLATE EXTENDED */ + C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0) + +/* TRANSLATE ONE TO ONE */ + C(0xb993, TROO, RRF_c, E2, 0, 0, 0, 0, trXX, 0) +/* TRANSLATE ONE TO TWO */ + C(0xb992, TROT, RRF_c, E2, 0, 0, 0, 0, trXX, 0) +/* TRANSLATE TWO TO ONE */ + C(0xb991, TRTO, RRF_c, E2, 0, 0, 0, 0, trXX, 0) +/* TRANSLATE TWO TO TWO */ + C(0xb990, TRTT, RRF_c, E2, 0, 0, 0, 0, trXX, 0) + +/* UNPACK */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) +/* UNPACK ASCII */ + C(0xea00, UNPKA, SS_a, E2, la1, a2, 0, 0, unpka, 0) +/* UNPACK UNICODE */ + C(0xe200, UNPKU, SS_a, E2, la1, a2, 0, 0, unpku, 0) + +/* MSA Instructions */ + D(0xb91e, KMAC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMAC) + D(0xb928, PCKMO, RRE, MSA3, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCKMO) + D(0xb92a, KMF, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMF) + D(0xb92b, KMO, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMO) + D(0xb92c, PCC, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCC) + D(0xb92d, KMCTR, RRF_b, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMCTR) + D(0xb92e, KM, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM) + D(0xb92f, KMC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC) + D(0xb929, KMA, RRF_b, MSA8, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMA) + D(0xb93c, PPNO, RRE, MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO) + D(0xb93e, KIMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD) + D(0xb93f, KLMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD) + +/* === Vector Support Instructions === */ + +/* VECTOR BIT PERMUTE */ + E(0xe785, VBPERM, VRR_c, VE, 0, 0, 0, 0, vbperm, 0, 0, IF_VEC) +/* VECTOR GATHER ELEMENT */ + E(0xe713, VGEF, VRV, V, la2, 0, 0, 0, vge, 0, ES_32, IF_VEC) + E(0xe712, VGEG, VRV, V, la2, 0, 0, 0, vge, 0, ES_64, IF_VEC) +/* VECTOR GENERATE BYTE MASK */ + F(0xe744, VGBM, VRI_a, V, 0, 0, 0, 0, vgbm, 0, IF_VEC) +/* VECTOR GENERATE MASK */ + F(0xe746, VGM, VRI_b, V, 0, 0, 0, 0, vgm, 0, IF_VEC) +/* VECTOR LOAD */ + F(0xe706, VL, VRX, V, la2, 0, 0, 0, vl, 0, IF_VEC) + F(0xe756, VLR, VRR_a, V, 0, 0, 0, 0, vlr, 0, IF_VEC) +/* VECTOR LOAD AND REPLICATE */ + F(0xe705, VLREP, VRX, V, la2, 0, 0, 0, vlrep, 0, IF_VEC) +/* VECTOR LOAD BYTE REVERSED ELEMENT */ + E(0xe601, VLEBRH, VRX, VE2, la2, 0, 0, 0, vlebr, 0, ES_16, IF_VEC) + E(0xe603, VLEBRF, VRX, VE2, la2, 0, 0, 0, vlebr, 0, ES_32, IF_VEC) + E(0xe602, VLEBRG, VRX, VE2, la2, 0, 0, 0, vlebr, 0, ES_64, IF_VEC) +/* VECTOR LOAD BYTE REVERSED ELEMENT AND REPLICATE */ + F(0xe605, VLBRREP, VRX, VE2, la2, 0, 0, 0, vlbrrep, 0, IF_VEC) +/* VECTOR LOAD BYTE REVERSED ELEMENT AND ZERO */ + F(0xe604, VLLEBRZ, VRX, VE2, la2, 0, 0, 0, vllebrz, 0, IF_VEC) +/* VECTOR LOAD BYTE REVERSED ELEMENTS */ + F(0xe606, VLBR, VRX, VE2, la2, 0, 0, 0, vlbr, 0, IF_VEC) +/* VECTOR LOAD ELEMENT */ + E(0xe700, VLEB, VRX, V, la2, 0, 0, 0, vle, 0, ES_8, IF_VEC) + E(0xe701, VLEH, VRX, V, la2, 0, 0, 0, vle, 0, ES_16, IF_VEC) + E(0xe703, VLEF, VRX, V, la2, 0, 0, 0, vle, 0, ES_32, IF_VEC) + E(0xe702, VLEG, VRX, V, la2, 0, 0, 0, vle, 0, ES_64, IF_VEC) +/* VECTOR LOAD ELEMENT IMMEDIATE */ + E(0xe740, VLEIB, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_8, IF_VEC) + E(0xe741, VLEIH, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_16, IF_VEC) + E(0xe743, VLEIF, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_32, IF_VEC) + E(0xe742, VLEIG, VRI_a, V, 0, 0, 0, 0, vlei, 0, ES_64, IF_VEC) +/* VECTOR LOAD ELEMENTS REVERSED */ + F(0xe607, VLER, VRX, VE2, la2, 0, 0, 0, vler, 0, IF_VEC) +/* VECTOR LOAD GR FROM VR ELEMENT */ + F(0xe721, VLGV, VRS_c, V, la2, 0, r1, 0, vlgv, 0, IF_VEC) +/* VECTOR LOAD LOGICAL ELEMENT AND ZERO */ + F(0xe704, VLLEZ, VRX, V, la2, 0, 0, 0, vllez, 0, IF_VEC) +/* VECTOR LOAD MULTIPLE */ + F(0xe736, VLM, VRS_a, V, la2, 0, 0, 0, vlm, 0, IF_VEC) +/* VECTOR LOAD TO BLOCK BOUNDARY */ + F(0xe707, VLBB, VRX, V, la2, 0, 0, 0, vlbb, 0, IF_VEC) +/* VECTOR LOAD VR ELEMENT FROM GR */ + F(0xe722, VLVG, VRS_b, V, la2, r3, 0, 0, vlvg, 0, IF_VEC) +/* VECTOR LOAD VR FROM GRS DISJOINT */ + F(0xe762, VLVGP, VRR_f, V, r2, r3, 0, 0, vlvgp, 0, IF_VEC) +/* VECTOR LOAD WITH LENGTH */ + F(0xe737, VLL, VRS_b, V, la2, r3_32u, 0, 0, vll, 0, IF_VEC) +/* VECTOR MERGE HIGH */ + F(0xe761, VMRH, VRR_c, V, 0, 0, 0, 0, vmr, 0, IF_VEC) +/* VECTOR MERGE LOW */ + F(0xe760, VMRL, VRR_c, V, 0, 0, 0, 0, vmr, 0, IF_VEC) +/* VECTOR PACK */ + F(0xe794, VPK, VRR_c, V, 0, 0, 0, 0, vpk, 0, IF_VEC) +/* VECTOR PACK SATURATE */ + F(0xe797, VPKS, VRR_b, V, 0, 0, 0, 0, vpk, 0, IF_VEC) +/* VECTOR PACK LOGICAL SATURATE */ + F(0xe795, VPKLS, VRR_b, V, 0, 0, 0, 0, vpk, 0, IF_VEC) + F(0xe78c, VPERM, VRR_e, V, 0, 0, 0, 0, vperm, 0, IF_VEC) +/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */ + F(0xe784, VPDI, VRR_c, V, 0, 0, 0, 0, vpdi, 0, IF_VEC) +/* VECTOR REPLICATE */ + F(0xe74d, VREP, VRI_c, V, 0, 0, 0, 0, vrep, 0, IF_VEC) +/* VECTOR REPLICATE IMMEDIATE */ + F(0xe745, VREPI, VRI_a, V, 0, 0, 0, 0, vrepi, 0, IF_VEC) +/* VECTOR SCATTER ELEMENT */ + E(0xe71b, VSCEF, VRV, V, la2, 0, 0, 0, vsce, 0, ES_32, IF_VEC) + E(0xe71a, VSCEG, VRV, V, la2, 0, 0, 0, vsce, 0, ES_64, IF_VEC) +/* VECTOR SELECT */ + F(0xe78d, VSEL, VRR_e, V, 0, 0, 0, 0, vsel, 0, IF_VEC) +/* VECTOR SIGN EXTEND TO DOUBLEWORD */ + F(0xe75f, VSEG, VRR_a, V, 0, 0, 0, 0, vseg, 0, IF_VEC) +/* VECTOR STORE */ + F(0xe70e, VST, VRX, V, la2, 0, 0, 0, vst, 0, IF_VEC) +/* VECTOR STORE BYTE REVERSED ELEMENT */ + E(0xe609, VSTEBRH, VRX, VE2, la2, 0, 0, 0, vstebr, 0, ES_16, IF_VEC) + E(0xe60b, VSTEBRF, VRX, VE2, la2, 0, 0, 0, vstebr, 0, ES_32, IF_VEC) + E(0xe60a, VSTEBRG, VRX, VE2, la2, 0, 0, 0, vstebr, 0, ES_64, IF_VEC) +/* VECTOR STORE BYTE REVERSED ELEMENTS */ + F(0xe60e, VSTBR, VRX, VE2, la2, 0, 0, 0, vstbr, 0, IF_VEC) +/* VECTOR STORE ELEMENT */ + E(0xe708, VSTEB, VRX, V, la2, 0, 0, 0, vste, 0, ES_8, IF_VEC) + E(0xe709, VSTEH, VRX, V, la2, 0, 0, 0, vste, 0, ES_16, IF_VEC) + E(0xe70b, VSTEF, VRX, V, la2, 0, 0, 0, vste, 0, ES_32, IF_VEC) + E(0xe70a, VSTEG, VRX, V, la2, 0, 0, 0, vste, 0, ES_64, IF_VEC) +/* VECTOR STORE ELEMENTS REVERSED */ + F(0xe60f, VSTER, VRX, VE2, la2, 0, 0, 0, vster, 0, IF_VEC) +/* VECTOR STORE MULTIPLE */ + F(0xe73e, VSTM, VRS_a, V, la2, 0, 0, 0, vstm, 0, IF_VEC) +/* VECTOR STORE WITH LENGTH */ + F(0xe73f, VSTL, VRS_b, V, la2, r3_32u, 0, 0, vstl, 0, IF_VEC) +/* VECTOR UNPACK HIGH */ + F(0xe7d7, VUPH, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) +/* VECTOR UNPACK LOGICAL HIGH */ + F(0xe7d5, VUPLH, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) +/* VECTOR UNPACK LOW */ + F(0xe7d6, VUPL, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) +/* VECTOR UNPACK LOGICAL LOW */ + F(0xe7d4, VUPLL, VRR_a, V, 0, 0, 0, 0, vup, 0, IF_VEC) + +/* === Vector Integer Instructions === */ + +/* VECTOR ADD */ + F(0xe7f3, VA, VRR_c, V, 0, 0, 0, 0, va, 0, IF_VEC) +/* VECTOR ADD COMPUTE CARRY */ + F(0xe7f1, VACC, VRR_c, V, 0, 0, 0, 0, vacc, 0, IF_VEC) +/* VECTOR ADD WITH CARRY */ + F(0xe7bb, VAC, VRR_d, V, 0, 0, 0, 0, vac, 0, IF_VEC) +/* VECTOR ADD WITH CARRY COMPUTE CARRY */ + F(0xe7b9, VACCC, VRR_d, V, 0, 0, 0, 0, vaccc, 0, IF_VEC) +/* VECTOR AND */ + F(0xe768, VN, VRR_c, V, 0, 0, 0, 0, vn, 0, IF_VEC) +/* VECTOR AND WITH COMPLEMENT */ + F(0xe769, VNC, VRR_c, V, 0, 0, 0, 0, vnc, 0, IF_VEC) +/* VECTOR AVERAGE */ + F(0xe7f2, VAVG, VRR_c, V, 0, 0, 0, 0, vavg, 0, IF_VEC) +/* VECTOR AVERAGE LOGICAL */ + F(0xe7f0, VAVGL, VRR_c, V, 0, 0, 0, 0, vavgl, 0, IF_VEC) +/* VECTOR CHECKSUM */ + F(0xe766, VCKSM, VRR_c, V, 0, 0, 0, 0, vcksm, 0, IF_VEC) +/* VECTOR ELEMENT COMPARE */ + F(0xe7db, VEC, VRR_a, V, 0, 0, 0, 0, vec, cmps64, IF_VEC) +/* VECTOR ELEMENT COMPARE LOGICAL */ + F(0xe7d9, VECL, VRR_a, V, 0, 0, 0, 0, vec, cmpu64, IF_VEC) +/* VECTOR COMPARE EQUAL */ + E(0xe7f8, VCEQ, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_EQ, IF_VEC) +/* VECTOR COMPARE HIGH */ + E(0xe7fb, VCH, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_GT, IF_VEC) +/* VECTOR COMPARE HIGH LOGICAL */ + E(0xe7f9, VCHL, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_GTU, IF_VEC) +/* VECTOR COUNT LEADING ZEROS */ + F(0xe753, VCLZ, VRR_a, V, 0, 0, 0, 0, vclz, 0, IF_VEC) +/* VECTOR COUNT TRAILING ZEROS */ + F(0xe752, VCTZ, VRR_a, V, 0, 0, 0, 0, vctz, 0, IF_VEC) +/* VECTOR EXCLUSIVE OR */ + F(0xe76d, VX, VRR_c, V, 0, 0, 0, 0, vx, 0, IF_VEC) +/* VECTOR GALOIS FIELD MULTIPLY SUM */ + F(0xe7b4, VGFM, VRR_c, V, 0, 0, 0, 0, vgfm, 0, IF_VEC) +/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */ + F(0xe7bc, VGFMA, VRR_d, V, 0, 0, 0, 0, vgfma, 0, IF_VEC) +/* VECTOR LOAD COMPLEMENT */ + F(0xe7de, VLC, VRR_a, V, 0, 0, 0, 0, vlc, 0, IF_VEC) +/* VECTOR LOAD POSITIVE */ + F(0xe7df, VLP, VRR_a, V, 0, 0, 0, 0, vlp, 0, IF_VEC) +/* VECTOR MAXIMUM */ + F(0xe7ff, VMX, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) +/* VECTOR MAXIMUM LOGICAL */ + F(0xe7fd, VMXL, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) +/* VECTOR MINIMUM */ + F(0xe7fe, VMN, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) +/* VECTOR MINIMUM LOGICAL */ + F(0xe7fc, VMNL, VRR_c, V, 0, 0, 0, 0, vmx, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD LOW */ + F(0xe7aa, VMAL, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD HIGH */ + F(0xe7ab, VMAH, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD LOGICAL HIGH */ + F(0xe7a9, VMALH, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD EVEN */ + F(0xe7ae, VMAE, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD LOGICAL EVEN */ + F(0xe7ac, VMALE, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD ODD */ + F(0xe7af, VMAO, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY AND ADD LOGICAL ODD */ + F(0xe7ad, VMALO, VRR_d, V, 0, 0, 0, 0, vma, 0, IF_VEC) +/* VECTOR MULTIPLY HIGH */ + F(0xe7a3, VMH, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY LOGICAL HIGH */ + F(0xe7a1, VMLH, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY LOW */ + F(0xe7a2, VML, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY EVEN */ + F(0xe7a6, VME, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY LOGICAL EVEN */ + F(0xe7a4, VMLE, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY ODD */ + F(0xe7a7, VMO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY LOGICAL ODD */ + F(0xe7a5, VMLO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY SUM LOGICAL */ + F(0xe7b8, VMSL, VRR_d, VE, 0, 0, 0, 0, vmsl, 0, IF_VEC) +/* VECTOR NAND */ + F(0xe76e, VNN, VRR_c, VE, 0, 0, 0, 0, vnn, 0, IF_VEC) +/* VECTOR NOR */ + F(0xe76b, VNO, VRR_c, V, 0, 0, 0, 0, vno, 0, IF_VEC) +/* VECTOR NOT EXCLUSIVE OR */ + F(0xe76c, VNX, VRR_c, VE, 0, 0, 0, 0, vnx, 0, IF_VEC) +/* VECTOR OR */ + F(0xe76a, VO, VRR_c, V, 0, 0, 0, 0, vo, 0, IF_VEC) +/* VECTOR OR WITH COMPLEMENT */ + F(0xe76f, VOC, VRR_c, VE, 0, 0, 0, 0, voc, 0, IF_VEC) +/* VECTOR POPULATION COUNT */ + F(0xe750, VPOPCT, VRR_a, V, 0, 0, 0, 0, vpopct, 0, IF_VEC) +/* VECTOR ELEMENT ROTATE LEFT LOGICAL */ + F(0xe773, VERLLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) + F(0xe733, VERLL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) +/* VECTOR ELEMENT ROTATE AND INSERT UNDER MASK */ + F(0xe772, VERIM, VRI_d, V, 0, 0, 0, 0, verim, 0, IF_VEC) +/* VECTOR ELEMENT SHIFT LEFT */ + F(0xe770, VESLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) + F(0xe730, VESL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) +/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */ + F(0xe77a, VESRAV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) + F(0xe73a, VESRA, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) +/* VECTOR ELEMENT SHIFT RIGHT LOGICAL */ + F(0xe778, VESRLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) + F(0xe738, VESRL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) +/* VECTOR SHIFT LEFT */ + E(0xe774, VSL, VRR_c, V, 0, 0, 0, 0, vsl, 0, 0, IF_VEC) +/* VECTOR SHIFT LEFT BY BYTE */ + E(0xe775, VSLB, VRR_c, V, 0, 0, 0, 0, vsl, 0, 1, IF_VEC) +/* VECTOR SHIFT LEFT DOUBLE BY BIT */ + E(0xe786, VSLD, VRI_d, VE2, 0, 0, 0, 0, vsld, 0, 0, IF_VEC) +/* VECTOR SHIFT LEFT DOUBLE BY BYTE */ + E(0xe777, VSLDB, VRI_d, V, 0, 0, 0, 0, vsld, 0, 1, IF_VEC) +/* VECTOR SHIFT RIGHT ARITHMETIC */ + E(0xe77e, VSRA, VRR_c, V, 0, 0, 0, 0, vsra, 0, 0, IF_VEC) +/* VECTOR SHIFT RIGHT ARITHMETIC BY BYTE */ + E(0xe77f, VSRAB, VRR_c, V, 0, 0, 0, 0, vsra, 0, 1, IF_VEC) +/* VECTOR SHIFT RIGHT DOUBLE BY BIT */ + F(0xe787, VSRD, VRI_d, VE2, 0, 0, 0, 0, vsrd, 0, IF_VEC) +/* VECTOR SHIFT RIGHT LOGICAL */ + E(0xe77c, VSRL, VRR_c, V, 0, 0, 0, 0, vsrl, 0, 0, IF_VEC) +/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */ + E(0xe77d, VSRLB, VRR_c, V, 0, 0, 0, 0, vsrl, 0, 1, IF_VEC) +/* VECTOR SUBTRACT */ + F(0xe7f7, VS, VRR_c, V, 0, 0, 0, 0, vs, 0, IF_VEC) +/* VECTOR SUBTRACT COMPUTE BORROW INDICATION */ + F(0xe7f5, VSCBI, VRR_c, V, 0, 0, 0, 0, vscbi, 0, IF_VEC) +/* VECTOR SUBTRACT WITH BORROW INDICATION */ + F(0xe7bf, VSBI, VRR_d, V, 0, 0, 0, 0, vsbi, 0, IF_VEC) +/* VECTOR SUBTRACT WITH BORROW COMPUTE BORROW INDICATION */ + F(0xe7bd, VSBCBI, VRR_d, V, 0, 0, 0, 0, vsbcbi, 0, IF_VEC) +/* VECTOR SUM ACROSS DOUBLEWORD */ + F(0xe765, VSUMG, VRR_c, V, 0, 0, 0, 0, vsumg, 0, IF_VEC) +/* VECTOR SUM ACROSS QUADWORD */ + F(0xe767, VSUMQ, VRR_c, V, 0, 0, 0, 0, vsumq, 0, IF_VEC) +/* VECTOR SUM ACROSS WORD */ + F(0xe764, VSUM, VRR_c, V, 0, 0, 0, 0, vsum, 0, IF_VEC) +/* VECTOR TEST UNDER MASK */ + F(0xe7d8, VTM, VRR_a, V, 0, 0, 0, 0, vtm, 0, IF_VEC) + +/* === Vector String Instructions === */ + +/* VECTOR FIND ANY ELEMENT EQUAL */ + F(0xe782, VFAE, VRR_b, V, 0, 0, 0, 0, vfae, 0, IF_VEC) +/* VECTOR FIND ELEMENT EQUAL */ + F(0xe780, VFEE, VRR_b, V, 0, 0, 0, 0, vfee, 0, IF_VEC) +/* VECTOR FIND ELEMENT NOT EQUAL */ + F(0xe781, VFENE, VRR_b, V, 0, 0, 0, 0, vfene, 0, IF_VEC) +/* VECTOR ISOLATE STRING */ + F(0xe75c, VISTR, VRR_a, V, 0, 0, 0, 0, vistr, 0, IF_VEC) +/* VECTOR STRING RANGE COMPARE */ + F(0xe78a, VSTRC, VRR_d, V, 0, 0, 0, 0, vstrc, 0, IF_VEC) +/* VECTOR STRING SEARCH */ + F(0xe78b, VSTRS, VRR_d, VE2, 0, 0, 0, 0, vstrs, 0, IF_VEC) + +/* === Vector Floating-Point Instructions */ + +/* VECTOR FP ADD */ + F(0xe7e3, VFA, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) +/* VECTOR FP COMPARE SCALAR */ + F(0xe7cb, WFC, VRR_a, V, 0, 0, 0, 0, wfc, 0, IF_VEC) +/* VECTOR FP COMPARE AND SIGNAL SCALAR */ + F(0xe7ca, WFK, VRR_a, V, 0, 0, 0, 0, wfc, 0, IF_VEC) +/* VECTOR FP COMPARE EQUAL */ + F(0xe7e8, VFCE, VRR_c, V, 0, 0, 0, 0, vfc, 0, IF_VEC) +/* VECTOR FP COMPARE HIGH */ + F(0xe7eb, VFCH, VRR_c, V, 0, 0, 0, 0, vfc, 0, IF_VEC) +/* VECTOR FP COMPARE HIGH OR EQUAL */ + F(0xe7ea, VFCHE, VRR_c, V, 0, 0, 0, 0, vfc, 0, IF_VEC) +/* VECTOR FP CONVERT FROM FIXED 64-BIT */ + F(0xe7c3, VCDG, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP CONVERT FROM LOGICAL 64-BIT */ + F(0xe7c1, VCDLG, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP CONVERT TO FIXED 64-BIT */ + F(0xe7c2, VCGD, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP CONVERT TO LOGICAL 64-BIT */ + F(0xe7c0, VCLGD, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP DIVIDE */ + F(0xe7e5, VFD, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) +/* VECTOR LOAD FP INTEGER */ + F(0xe7c7, VFI, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP LOAD LENGTHENED */ + F(0xe7c4, VFLL, VRR_a, V, 0, 0, 0, 0, vfll, 0, IF_VEC) +/* VECTOR FP LOAD ROUNDED */ + F(0xe7c5, VFLR, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP MAXIMUM */ + F(0xe7ef, VFMAX, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC) +/* VECTOR FP MINIMUM */ + F(0xe7ee, VFMIN, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC) +/* VECTOR FP MULTIPLY */ + F(0xe7e7, VFM, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) +/* VECTOR FP MULTIPLY AND ADD */ + F(0xe78f, VFMA, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC) +/* VECTOR FP MULTIPLY AND SUBTRACT */ + F(0xe78e, VFMS, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC) +/* VECTOR FP NEGATIVE MULTIPLY AND ADD */ + F(0xe79f, VFNMA, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC) +/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */ + F(0xe79e, VFNMS, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC) +/* VECTOR FP PERFORM SIGN OPERATION */ + F(0xe7cc, VFPSO, VRR_a, V, 0, 0, 0, 0, vfpso, 0, IF_VEC) +/* VECTOR FP SQUARE ROOT */ + F(0xe7ce, VFSQ, VRR_a, V, 0, 0, 0, 0, vfsq, 0, IF_VEC) +/* VECTOR FP SUBTRACT */ + F(0xe7e2, VFS, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) +/* VECTOR FP TEST DATA CLASS IMMEDIATE */ + F(0xe74a, VFTCI, VRI_e, V, 0, 0, 0, 0, vftci, 0, IF_VEC) + +#ifndef CONFIG_USER_ONLY +/* COMPARE AND SWAP AND PURGE */ + E(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL, IF_PRIV) + E(0xb98a, CSPG, RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEUQ, IF_PRIV) +/* DIAGNOSE (KVM hypercall) */ + F(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0, IF_PRIV | IF_IO) +/* INSERT STORAGE KEY EXTENDED */ + F(0xb229, ISKE, RRE, Z, 0, r2_o, new, r1_8, iske, 0, IF_PRIV) +/* INVALIDATE DAT TABLE ENTRY */ + F(0xb98e, IPDE, RRF_b, Z, r1_o, r2_o, 0, 0, idte, 0, IF_PRIV) +/* INVALIDATE PAGE TABLE ENTRY */ + F(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0, IF_PRIV) +/* LOAD CONTROL */ + F(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0, IF_PRIV) + F(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0, IF_PRIV) +/* LOAD PROGRAM PARAMETER */ + F(0xb280, LPP, S, LPP, 0, m2_64, 0, 0, lpp, 0, IF_PRIV) +/* LOAD PSW */ + F(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0, IF_PRIV) +/* LOAD PSW EXTENDED */ + F(0xb2b2, LPSWE, S, Z, 0, a2, 0, 0, lpswe, 0, IF_PRIV) +/* LOAD REAL ADDRESS */ + F(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0, IF_PRIV) + F(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0, IF_PRIV) + F(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0, IF_PRIV) +/* LOAD USING REAL ADDRESS */ + E(0xb24b, LURA, RRE, Z, 0, ra2, new, r1_32, lura, 0, MO_TEUL, IF_PRIV) + E(0xb905, LURAG, RRE, Z, 0, ra2, r1, 0, lura, 0, MO_TEUQ, IF_PRIV) +/* MOVE TO PRIMARY */ + C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) +/* MOVE TO SECONDARY */ + C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) +/* PURGE TLB */ + F(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0, IF_PRIV) +/* RESET REFERENCE BIT EXTENDED */ + F(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0, IF_PRIV) +/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ + F(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0, IF_PRIV | IF_IO) +/* SET ADDRESS SPACE CONTROL FAST */ + C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) +/* SET CLOCK */ + F(0xb204, SCK, S, Z, 0, m2_64a, 0, 0, sck, 0, IF_PRIV | IF_IO) +/* SET CLOCK COMPARATOR */ + F(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0, IF_PRIV | IF_IO) +/* SET CLOCK PROGRAMMABLE FIELD */ + F(0x0107, SCKPF, E, Z, 0, 0, 0, 0, sckpf, 0, IF_PRIV) +/* SET CPU TIMER */ + F(0xb208, SPT, S, Z, 0, m2_64a, 0, 0, spt, 0, IF_PRIV | IF_IO) +/* SET PREFIX */ + F(0xb210, SPX, S, Z, 0, m2_32ua, 0, 0, spx, 0, IF_PRIV) +/* SET PSW KEY FROM ADDRESS */ + F(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0, IF_PRIV) +/* SET STORAGE KEY EXTENDED */ + F(0xb22b, SSKE, RRF_c, Z, r1_o, r2_o, 0, 0, sske, 0, IF_PRIV) +/* SET SYSTEM MASK */ + F(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0, IF_PRIV) +/* SIGNAL PROCESSOR */ + F(0xae00, SIGP, RS_a, Z, 0, a2, 0, 0, sigp, 0, IF_PRIV | IF_IO) +/* STORE CLOCK COMPARATOR */ + F(0xb207, STCKC, S, Z, la2, 0, new, m1_64a, stckc, 0, IF_PRIV) +/* STORE CONTROL */ + F(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0, IF_PRIV) + F(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0, IF_PRIV) +/* STORE CPU ADDRESS */ + F(0xb212, STAP, S, Z, la2, 0, new, m1_16a, stap, 0, IF_PRIV) +/* STORE CPU ID */ + F(0xb202, STIDP, S, Z, la2, 0, new, m1_64a, stidp, 0, IF_PRIV) +/* STORE CPU TIMER */ + F(0xb209, STPT, S, Z, la2, 0, new, m1_64a, stpt, 0, IF_PRIV | IF_IO) +/* STORE FACILITY LIST */ + F(0xb2b1, STFL, S, Z, 0, 0, 0, 0, stfl, 0, IF_PRIV) +/* STORE PREFIX */ + F(0xb211, STPX, S, Z, la2, 0, new, m1_32a, stpx, 0, IF_PRIV) +/* STORE SYSTEM INFORMATION */ + F(0xb27d, STSI, S, Z, 0, a2, 0, 0, stsi, 0, IF_PRIV) +/* STORE THEN AND SYSTEM MASK */ + F(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0, IF_PRIV) +/* STORE THEN OR SYSTEM MASK */ + F(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0, IF_PRIV) +/* STORE USING REAL ADDRESS */ + E(0xb246, STURA, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEUL, IF_PRIV) + E(0xb925, STURG, RRE, Z, r1_o, ra2, 0, 0, stura, 0, MO_TEUQ, IF_PRIV) +/* TEST BLOCK */ + F(0xb22c, TB, RRE, Z, 0, r2_o, 0, 0, testblock, 0, IF_PRIV) +/* TEST PROTECTION */ + C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) + +/* CCW I/O Instructions */ + F(0xb276, XSCH, S, Z, 0, 0, 0, 0, xsch, 0, IF_PRIV | IF_IO) + F(0xb230, CSCH, S, Z, 0, 0, 0, 0, csch, 0, IF_PRIV | IF_IO) + F(0xb231, HSCH, S, Z, 0, 0, 0, 0, hsch, 0, IF_PRIV | IF_IO) + F(0xb232, MSCH, S, Z, 0, insn, 0, 0, msch, 0, IF_PRIV | IF_IO) + F(0xb23b, RCHP, S, Z, 0, 0, 0, 0, rchp, 0, IF_PRIV | IF_IO) + F(0xb238, RSCH, S, Z, 0, 0, 0, 0, rsch, 0, IF_PRIV | IF_IO) + F(0xb237, SAL, S, Z, 0, 0, 0, 0, sal, 0, IF_PRIV | IF_IO) + F(0xb23c, SCHM, S, Z, 0, insn, 0, 0, schm, 0, IF_PRIV | IF_IO) + F(0xb274, SIGA, S, Z, 0, 0, 0, 0, siga, 0, IF_PRIV | IF_IO) + F(0xb23a, STCPS, S, Z, 0, 0, 0, 0, stcps, 0, IF_PRIV | IF_IO) + F(0xb233, SSCH, S, Z, 0, insn, 0, 0, ssch, 0, IF_PRIV | IF_IO) + F(0xb239, STCRW, S, Z, 0, insn, 0, 0, stcrw, 0, IF_PRIV | IF_IO) + F(0xb234, STSCH, S, Z, 0, insn, 0, 0, stsch, 0, IF_PRIV | IF_IO) + F(0xb236, TPI , S, Z, la2, 0, 0, 0, tpi, 0, IF_PRIV | IF_IO) + F(0xb235, TSCH, S, Z, 0, insn, 0, 0, tsch, 0, IF_PRIV | IF_IO) + /* ??? Not listed in PoO ninth edition, but there's a linux driver that + uses it: "A CHSC subchannel is usually present on LPAR only." */ + F(0xb25f, CHSC, RRE, Z, 0, insn, 0, 0, chsc, 0, IF_PRIV | IF_IO) + +/* zPCI Instructions */ + /* None of these instructions are documented in the PoP, so this is all + based upon target/s390x/kvm.c and Linux code and likely incomplete */ + F(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0, IF_PRIV | IF_IO) + F(0xebd1, SIC, RSY_a, AIS, r1, r3, 0, 0, sic, 0, IF_PRIV | IF_IO) + F(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0, IF_PRIV | IF_IO) + F(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0, IF_PRIV | IF_IO) + F(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0, IF_PRIV | IF_IO) + F(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0, IF_PRIV | IF_IO) + F(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0, IF_PRIV | IF_IO) + F(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0, IF_PRIV | IF_IO) + +#endif /* CONFIG_USER_ONLY */ diff --git a/target/s390x/tcg/insn-format.def b/target/s390x/tcg/insn-format.h.inc similarity index 100% rename from target/s390x/tcg/insn-format.def rename to target/s390x/tcg/insn-format.h.inc diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index fc52aa128bb3..cb82cd1c1d87 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -51,7 +51,7 @@ static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key) if (env->psw.mask & PSW_MASK_PSTATE) { /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */ - return pkm & (0x80 >> psw_key); + return pkm & (0x8000 >> psw_key); } return true; } @@ -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); @@ -2299,7 +2295,8 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) return re >> 1; } -uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) +uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2, + uint64_t key) { const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC; S390Access srca, desta; @@ -2314,6 +2311,10 @@ uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } + if (!psw_key_valid(env, (key >> 4) & 0xf)) { + s390_program_interrupt(env, PGM_PRIVILEGED, ra); + } + l = wrap_length32(env, l); if (l > 256) { /* max 256 */ @@ -2323,14 +2324,14 @@ uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) return cc; } - /* TODO: Access key handling */ srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra); desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra); access_memmove(env, &desta, &srca, ra); return cc; } -uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) +uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2, + uint64_t key) { const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC; S390Access srca, desta; @@ -2345,6 +2346,10 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } + if (!psw_key_valid(env, (key >> 4) & 0xf)) { + s390_program_interrupt(env, PGM_PRIVILEGED, ra); + } + l = wrap_length32(env, l); if (l > 256) { /* max 256 */ @@ -2354,7 +2359,6 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) return cc; } - /* TODO: Access key handling */ srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra); desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra); access_memmove(env, &desta, &srca, ra); diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index aab9c47747ee..576157b1f317 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -23,7 +23,6 @@ #include "qemu/main-loop.h" #include "cpu.h" #include "s390x-internal.h" -#include "exec/memory.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "qemu/timer.h" @@ -158,6 +157,13 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) if (prefix == old_prefix) { return; } + /* + * Since prefix got aligned to 8k and memory increments are a multiple of + * 8k checking the first page is sufficient + */ + if (!mmu_absolute_addr_valid(prefix, true)) { + tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC()); + } env->psa = prefix; HELPER_LOG("prefix: %#x\n", prefix); @@ -326,7 +332,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) /* same as machine type number in STORE CPU ID, but in EBCDIC */ snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type); ebcdic_put(sysib.sysib_111.type, type, 4); - /* model number (not stored in STORE CPU ID for z/Architecure) */ + /* model number (not stored in STORE CPU ID for z/Architecture) */ ebcdic_put(sysib.sysib_111.model, "QEMU ", 16); ebcdic_put(sysib.sysib_111.sequence, "QEMU ", 16); ebcdic_put(sysib.sysib_111.plant, "QEMU", 4); diff --git a/target/s390x/tcg/tcg_s390x.h b/target/s390x/tcg/tcg_s390x.h index 2f54ccb02745..78558912f99f 100644 --- a/target/s390x/tcg/tcg_s390x.h +++ b/target/s390x/tcg/tcg_s390x.h @@ -14,11 +14,11 @@ #define TCG_S390X_H void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque); -void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, - uint32_t code, uintptr_t ra); -void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc, - uintptr_t ra); -void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc, - uintptr_t ra); +G_NORETURN void tcg_s390_program_interrupt(CPUS390XState *env, + uint32_t code, uintptr_t ra); +G_NORETURN void tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc, + uintptr_t ra); +G_NORETURN void tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc, + uintptr_t ra); #endif /* TCG_S390X_H */ diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 5acfc0ff9b4e..a339b277e984 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -149,6 +149,7 @@ struct DisasContext { uint64_t pc_tmp; uint32_t ilen; enum cc_op cc_op; + bool exit_to_mainloop; }; /* Information carried about a condition to be evaluated. */ @@ -263,7 +264,7 @@ static inline int vec_reg_offset(uint8_t reg, uint8_t enr, MemOp es) * 16 byte operations to handle it in a special way. */ g_assert(es <= MO_64); -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN offs ^= (8 - bytes); #endif return offs + vec_full_reg_offset(reg); @@ -434,7 +435,7 @@ static void gen_program_exception(DisasContext *s, int code) { TCGv_i32 tmp; - /* Remember what pgm exeption this was. */ + /* Remember what pgm exception this was. */ tmp = tcg_const_i32(code); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); @@ -490,7 +491,7 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) /* * Note that d2 is limited to 20 bits, signed. If we crop negative - * displacements early we create larger immedate addends. + * displacements early we create larger immediate addends. */ if (b2 && x2) { tcg_gen_add_i64(tmp, regs[b2], regs[x2]); @@ -1010,7 +1011,7 @@ static void free_compare(DisasCompare *c) #define F6(N, X1, X2, X3, X4, X5, X6) F0(N) typedef enum { -#include "insn-format.def" +#include "insn-format.h.inc" } DisasFormat; #undef F0 @@ -1075,7 +1076,7 @@ typedef struct DisasFormatInfo { #define F6(N, X1, X2, X3, X4, X5, X6) { { X1, X2, X3, X4, X5, X6 } }, static const DisasFormatInfo format_info[] = { -#include "insn-format.def" +#include "insn-format.h.inc" }; #undef F0 @@ -1123,19 +1124,9 @@ typedef struct { exiting the TB. */ #define DISAS_PC_UPDATED DISAS_TARGET_0 -/* We have emitted one or more goto_tb. No fixup required. */ -#define DISAS_GOTO_TB DISAS_TARGET_1 - /* We have updated the PC and CC values. */ #define DISAS_PC_CC_UPDATED DISAS_TARGET_2 -/* We are exiting the TB, but have neither emitted a goto_tb, nor - updated the PC for the next instruction to be executed. */ -#define DISAS_PC_STALE DISAS_TARGET_3 - -/* We are exiting the TB to the main loop. */ -#define DISAS_PC_STALE_NOCHAIN DISAS_TARGET_4 - /* Instruction flags */ #define IF_AFP1 0x0001 /* r1 is a fp reg for HFP/FPS instructions */ @@ -1189,7 +1180,7 @@ static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest) tcg_gen_goto_tb(0); tcg_gen_movi_i64(psw_addr, dest); tcg_gen_exit_tb(s->base.tb, 0); - return DISAS_GOTO_TB; + return DISAS_NORETURN; } else { tcg_gen_movi_i64(psw_addr, dest); per_branch(s, false); @@ -1258,7 +1249,7 @@ static DisasJumpType help_branch(DisasContext *s, DisasCompare *c, tcg_gen_movi_i64(psw_addr, dest); tcg_gen_exit_tb(s->base.tb, 1); - ret = DISAS_GOTO_TB; + ret = DISAS_NORETURN; } else { /* Fallthru can use goto_tb, but taken branch cannot. */ /* Store taken branch destination before the brcond. This @@ -2622,7 +2613,7 @@ static DisasJumpType op_icm(DisasContext *s, DisasOps *o) tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); tcg_gen_addi_i64(o->in2, o->in2, 1); tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8); - ccm |= 0xff << pos; + ccm |= 0xffull << pos; } m3 = (m3 << 1) & 0xf; pos -= 8; @@ -3029,7 +3020,8 @@ static DisasJumpType op_lctl(DisasContext *s, DisasOps *o) tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ - return DISAS_PC_STALE_NOCHAIN; + s->exit_to_mainloop = true; + return DISAS_TOO_MANY; } static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o) @@ -3040,7 +3032,8 @@ static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o) tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ - return DISAS_PC_STALE_NOCHAIN; + s->exit_to_mainloop = true; + return DISAS_TOO_MANY; } static DisasJumpType op_lra(DisasContext *s, DisasOps *o) @@ -3483,7 +3476,8 @@ static DisasJumpType op_mvcos(DisasContext *s, DisasOps *o) static DisasJumpType op_mvcp(DisasContext *s, DisasOps *o) { int r1 = get_field(s, l1); - gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + int r3 = get_field(s, r3); + gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2, regs[r3]); set_cc_static(s); return DISAS_NEXT; } @@ -3491,7 +3485,8 @@ static DisasJumpType op_mvcp(DisasContext *s, DisasOps *o) static DisasJumpType op_mvcs(DisasContext *s, DisasOps *o) { int r1 = get_field(s, l1); - gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + int r3 = get_field(s, r3); + gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2, regs[r3]); set_cc_static(s); return DISAS_NEXT; } @@ -3996,7 +3991,7 @@ static DisasJumpType op_sacf(DisasContext *s, DisasOps *o) { gen_helper_sacf(cpu_env, o->in2); /* Addressing mode has changed, so end the block. */ - return DISAS_PC_STALE; + return DISAS_TOO_MANY; } #endif @@ -4032,7 +4027,7 @@ static DisasJumpType op_sam(DisasContext *s, DisasOps *o) tcg_temp_free_i64(tsam); /* Always exit the TB, since we (may have) changed execution mode. */ - return DISAS_PC_STALE; + return DISAS_TOO_MANY; } static DisasJumpType op_sar(DisasContext *s, DisasOps *o) @@ -4290,7 +4285,8 @@ static DisasJumpType op_ssm(DisasContext *s, DisasOps *o) { tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ - return DISAS_PC_STALE_NOCHAIN; + s->exit_to_mainloop = true; + return DISAS_TOO_MANY; } static DisasJumpType op_stap(DisasContext *s, DisasOps *o) @@ -4555,7 +4551,8 @@ static DisasJumpType op_stnosm(DisasContext *s, DisasOps *o) } /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ - return DISAS_PC_STALE_NOCHAIN; + s->exit_to_mainloop = true; + return DISAS_TOO_MANY; } static DisasJumpType op_stura(DisasContext *s, DisasOps *o) @@ -6148,7 +6145,7 @@ static void in2_insn(DisasContext *s, DisasOps *o) #define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) insn_ ## NM, enum DisasInsnEnum { -#include "insn-data.def" +#include "insn-data.h.inc" }; #undef E @@ -6185,17 +6182,17 @@ enum DisasInsnEnum { #define FAC_Z S390_FEAT_ZARCH #define FAC_CASS S390_FEAT_COMPARE_AND_SWAP_AND_STORE #define FAC_DFP S390_FEAT_DFP -#define FAC_DFPR S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* DFP-rounding */ +#define FAC_DFPR S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* DFP-rounding */ #define FAC_DO S390_FEAT_STFLE_45 /* distinct-operands */ #define FAC_EE S390_FEAT_EXECUTE_EXT #define FAC_EI S390_FEAT_EXTENDED_IMMEDIATE #define FAC_FPE S390_FEAT_FLOATING_POINT_EXT -#define FAC_FPSSH S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPS-sign-handling */ -#define FAC_FPRGR S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPR-GR-transfer */ +#define FAC_FPSSH S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* FPS-sign-handling */ +#define FAC_FPRGR S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* FPR-GR-transfer */ #define FAC_GIE S390_FEAT_GENERAL_INSTRUCTIONS_EXT #define FAC_HFP_MA S390_FEAT_HFP_MADDSUB #define FAC_HW S390_FEAT_STFLE_45 /* high-word */ -#define FAC_IEEEE_SIM S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* IEEE-exception-simulation */ +#define FAC_IEEEE_SIM S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* IEEE-exception-simulation */ #define FAC_MIE S390_FEAT_STFLE_49 /* misc-instruction-extensions */ #define FAC_LAT S390_FEAT_STFLE_49 /* load-and-trap */ #define FAC_LOC S390_FEAT_STFLE_45 /* load/store on condition 1 */ @@ -6222,12 +6219,13 @@ enum DisasInsnEnum { #define FAC_PCI S390_FEAT_ZPCI /* z/PCI facility */ #define FAC_AIS S390_FEAT_ADAPTER_INT_SUPPRESSION #define FAC_V S390_FEAT_VECTOR /* vector facility */ -#define FAC_VE S390_FEAT_VECTOR_ENH /* vector enhancements facility 1 */ +#define FAC_VE S390_FEAT_VECTOR_ENH /* vector enhancements facility 1 */ +#define FAC_VE2 S390_FEAT_VECTOR_ENH2 /* vector enhancements facility 2 */ #define FAC_MIE2 S390_FEAT_MISC_INSTRUCTION_EXT2 /* miscellaneous-instruction-extensions facility 2 */ #define FAC_MIE3 S390_FEAT_MISC_INSTRUCTION_EXT3 /* miscellaneous-instruction-extensions facility 3 */ static const DisasInsn insn_info[] = { -#include "insn-data.def" +#include "insn-data.h.inc" }; #undef E @@ -6237,7 +6235,7 @@ static const DisasInsn insn_info[] = { static const DisasInsn *lookup_opc(uint16_t opc) { switch (opc) { -#include "insn-data.def" +#include "insn-data.h.inc" default: return NULL; } @@ -6321,12 +6319,18 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s) if (unlikely(s->ex_value)) { /* Drop the EX data now, so that it's clear on exception paths. */ TCGv_i64 zero = tcg_const_i64(0); + int i; tcg_gen_st_i64(zero, cpu_env, offsetof(CPUS390XState, ex_value)); tcg_temp_free_i64(zero); /* Extract the values saved by EXECUTE. */ insn = s->ex_value & 0xffffffffffff0000ull; ilen = s->ex_value & 0xf; + /* register insn bytes with translator so plugins work */ + for (i = 0; i < ilen; i++) { + uint8_t byte = extract64(insn, 56 - (i * 8), 8); + translator_fake_ldb(byte, pc + i); + } op = insn >> 56; } else { insn = ld_code2(env, s, pc); @@ -6564,13 +6568,13 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) /* io should be the last instruction in tb when icount is enabled */ if (unlikely(icount && ret == DISAS_NEXT)) { - ret = DISAS_PC_STALE; + ret = DISAS_TOO_MANY; } #ifndef CONFIG_USER_ONLY if (s->base.tb->flags & FLAG_MASK_PER) { /* An exception might be triggered, save PSW if not already done. */ - if (ret == DISAS_NEXT || ret == DISAS_PC_STALE) { + if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) { tcg_gen_movi_i64(psw_addr, s->pc_tmp); } @@ -6597,6 +6601,7 @@ static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->cc_op = CC_OP_DYNAMIC; dc->ex_value = dc->base.tb->cs_base; + dc->exit_to_mainloop = (dc->base.tb->flags & FLAG_MASK_PER) || dc->ex_value; } static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs) @@ -6612,6 +6617,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 = cpu_lduw_code(env, pc); + + return pc + get_ilen((insn >> 8) & 0xff); +} + static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPUS390XState *env = cs->env_ptr; @@ -6619,10 +6632,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 (dc->ex_value || + !is_same_page(dcbase, dc->base.pc_next) || + !is_same_page(dcbase, get_next_pc(env, dc, dc->base.pc_next))) { dc->base.is_jmp = DISAS_TOO_MANY; } } @@ -6633,12 +6645,9 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) DisasContext *dc = container_of(dcbase, DisasContext, base); switch (dc->base.is_jmp) { - case DISAS_GOTO_TB: case DISAS_NORETURN: break; case DISAS_TOO_MANY: - case DISAS_PC_STALE: - case DISAS_PC_STALE_NOCHAIN: update_psw_addr(dc); /* FALLTHRU */ case DISAS_PC_UPDATED: @@ -6648,8 +6657,7 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) /* FALLTHRU */ case DISAS_PC_CC_UPDATED: /* Exit the TB, either by raising a debug exception or by return. */ - if ((dc->base.tb->flags & FLAG_MASK_PER) || - dc->base.is_jmp == DISAS_PC_STALE_NOCHAIN) { + if (dc->exit_to_mainloop) { tcg_gen_exit_tb(NULL, 0); } else { tcg_gen_lookup_and_goto_ptr(); @@ -6660,16 +6668,17 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void s390x_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void s390x_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { DisasContext *dc = container_of(dcbase, DisasContext, base); if (unlikely(dc->ex_value)) { - /* ??? Unfortunately log_target_disas can't use host memory. */ - qemu_log("IN: EXECUTE %016" PRIx64, dc->ex_value); + /* ??? Unfortunately target_disas can't use host memory. */ + fprintf(logfile, "IN: EXECUTE %016" PRIx64, dc->ex_value); } else { - qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first)); - log_target_disas(cs, dc->base.pc_first, dc->base.tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first)); + target_disas(logfile, cs, dc->base.pc_first, dc->base.tb->size); } } @@ -6682,16 +6691,20 @@ 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, - target_ulong *data) +void s390x_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; int cc_op = data[1]; env->psw.addr = data[0]; diff --git a/target/s390x/tcg/translate_vx.c.inc b/target/s390x/tcg/translate_vx.c.inc index 98eb7710a4a9..d39ee81cd6da 100644 --- a/target/s390x/tcg/translate_vx.c.inc +++ b/target/s390x/tcg/translate_vx.c.inc @@ -175,7 +175,7 @@ static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr, /* convert it to an element offset relative to cpu_env (vec_reg_offset() */ tcg_gen_shli_i64(tmp, tmp, es); -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es)); #endif tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg)); @@ -457,6 +457,129 @@ static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vlebr(DisasContext *s, DisasOps *o) +{ + const uint8_t es = s->insn->data; + const uint8_t enr = get_field(s, m3); + TCGv_i64 tmp; + + if (!valid_vec_element(enr, es)) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es); + write_vec_element_i64(tmp, get_field(s, v1), enr, es); + tcg_temp_free_i64(tmp); + return DISAS_NEXT; +} + +static DisasJumpType op_vlbrrep(DisasContext *s, DisasOps *o) +{ + const uint8_t es = get_field(s, m3); + TCGv_i64 tmp; + + if (es < ES_16 || es > ES_64) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es); + gen_gvec_dup_i64(es, get_field(s, v1), tmp); + tcg_temp_free_i64(tmp); + return DISAS_NEXT; +} + +static DisasJumpType op_vllebrz(DisasContext *s, DisasOps *o) +{ + const uint8_t m3 = get_field(s, m3); + TCGv_i64 tmp; + int es, lshift; + + switch (m3) { + case ES_16: + case ES_32: + case ES_64: + es = m3; + lshift = 0; + break; + case 6: + es = ES_32; + lshift = 32; + break; + default: + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es); + tcg_gen_shli_i64(tmp, tmp, lshift); + + write_vec_element_i64(tmp, get_field(s, v1), 0, ES_64); + write_vec_element_i64(tcg_constant_i64(0), get_field(s, v1), 1, ES_64); + tcg_temp_free_i64(tmp); + return DISAS_NEXT; +} + +static DisasJumpType op_vlbr(DisasContext *s, DisasOps *o) +{ + const uint8_t es = get_field(s, m3); + TCGv_i64 t0, t1; + + if (es < ES_16 || es > ES_128) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + + if (es == ES_128) { + tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_LEUQ); + gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8); + tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_LEUQ); + goto write; + } + + /* Begin with byte reversed doublewords... */ + tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_LEUQ); + gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8); + tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_LEUQ); + + /* + * For 16 and 32-bit elements, the doubleword bswap also reversed + * the order of the elements. Perform a larger order swap to put + * them back into place. For the 128-bit "element", finish the + * bswap by swapping the doublewords. + */ + switch (es) { + case ES_16: + tcg_gen_hswap_i64(t0, t0); + tcg_gen_hswap_i64(t1, t1); + break; + case ES_32: + tcg_gen_wswap_i64(t0, t0); + tcg_gen_wswap_i64(t1, t1); + break; + case ES_64: + break; + default: + g_assert_not_reached(); + } + +write: + write_vec_element_i64(t0, get_field(s, v1), 0, ES_64); + write_vec_element_i64(t1, get_field(s, v1), 1, ES_64); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return DISAS_NEXT; +} + static DisasJumpType op_vle(DisasContext *s, DisasOps *o) { const uint8_t es = s->insn->data; @@ -492,6 +615,46 @@ static DisasJumpType op_vlei(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vler(DisasContext *s, DisasOps *o) +{ + const uint8_t es = get_field(s, m3); + + if (es < ES_16 || es > ES_64) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + /* Begin with the two doublewords swapped... */ + tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ); + gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8); + tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEUQ); + + /* ... then swap smaller elements within the doublewords as required. */ + switch (es) { + case MO_16: + tcg_gen_hswap_i64(t1, t1); + tcg_gen_hswap_i64(t0, t0); + break; + case MO_32: + tcg_gen_wswap_i64(t1, t1); + tcg_gen_wswap_i64(t0, t0); + break; + case MO_64: + break; + default: + g_assert_not_reached(); + } + + write_vec_element_i64(t0, get_field(s, v1), 0, ES_64); + write_vec_element_i64(t1, get_field(s, v1), 1, ES_64); + tcg_temp_free(t0); + tcg_temp_free(t1); + return DISAS_NEXT; +} + static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o) { const uint8_t es = get_field(s, m4); @@ -797,7 +960,7 @@ static DisasJumpType op_vpk(DisasContext *s, DisasOps *o) } break; case 0x94: - /* If sources and destination dont't overlap -> fast path */ + /* If sources and destination don't overlap -> fast path */ if (v1 != v2 && v1 != v3) { const uint8_t src_es = get_field(s, m4); const uint8_t dst_es = src_es - 1; @@ -958,6 +1121,81 @@ static DisasJumpType op_vst(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vstebr(DisasContext *s, DisasOps *o) +{ + const uint8_t es = s->insn->data; + const uint8_t enr = get_field(s, m3); + TCGv_i64 tmp; + + if (!valid_vec_element(enr, es)) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + tmp = tcg_temp_new_i64(); + read_vec_element_i64(tmp, get_field(s, v1), enr, es); + tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_LE | es); + tcg_temp_free_i64(tmp); + return DISAS_NEXT; +} + +static DisasJumpType op_vstbr(DisasContext *s, DisasOps *o) +{ + const uint8_t es = get_field(s, m3); + TCGv_i64 t0, t1; + + if (es < ES_16 || es > ES_128) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + /* Probe write access before actually modifying memory */ + gen_helper_probe_write_access(cpu_env, o->addr1, tcg_constant_i64(16)); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + + if (es == ES_128) { + read_vec_element_i64(t1, get_field(s, v1), 0, ES_64); + read_vec_element_i64(t0, get_field(s, v1), 1, ES_64); + goto write; + } + + read_vec_element_i64(t0, get_field(s, v1), 0, ES_64); + read_vec_element_i64(t1, get_field(s, v1), 1, ES_64); + + /* + * For 16 and 32-bit elements, the doubleword bswap below will + * reverse the order of the elements. Perform a larger order + * swap to put them back into place. For the 128-bit "element", + * finish the bswap by swapping the doublewords. + */ + switch (es) { + case MO_16: + tcg_gen_hswap_i64(t0, t0); + tcg_gen_hswap_i64(t1, t1); + break; + case MO_32: + tcg_gen_wswap_i64(t0, t0); + tcg_gen_wswap_i64(t1, t1); + break; + case MO_64: + break; + default: + g_assert_not_reached(); + } + +write: + tcg_gen_qemu_st_i64(t0, o->addr1, get_mem_index(s), MO_LEUQ); + gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8); + tcg_gen_qemu_st_i64(t1, o->addr1, get_mem_index(s), MO_LEUQ); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return DISAS_NEXT; +} + static DisasJumpType op_vste(DisasContext *s, DisasOps *o) { const uint8_t es = s->insn->data; @@ -976,6 +1214,50 @@ static DisasJumpType op_vste(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vster(DisasContext *s, DisasOps *o) +{ + const uint8_t es = get_field(s, m3); + TCGv_i64 t0, t1; + + if (es < ES_16 || es > ES_64) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + /* Probe write access before actually modifying memory */ + gen_helper_probe_write_access(cpu_env, o->addr1, tcg_constant_i64(16)); + + /* Begin with the two doublewords swapped... */ + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + read_vec_element_i64(t1, get_field(s, v1), 0, ES_64); + read_vec_element_i64(t0, get_field(s, v1), 1, ES_64); + + /* ... then swap smaller elements within the doublewords as required. */ + switch (es) { + case MO_16: + tcg_gen_hswap_i64(t1, t1); + tcg_gen_hswap_i64(t0, t0); + break; + case MO_32: + tcg_gen_wswap_i64(t1, t1); + tcg_gen_wswap_i64(t0, t0); + break; + case MO_64: + break; + default: + g_assert_not_reached(); + } + + tcg_gen_qemu_st_i64(t0, o->addr1, get_mem_index(s), MO_TEUQ); + gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8); + tcg_gen_qemu_st_i64(t1, o->addr1, get_mem_index(s), MO_TEUQ); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return DISAS_NEXT; +} + static DisasJumpType op_vstm(DisasContext *s, DisasOps *o) { const uint8_t v3 = get_field(s, v3); @@ -1793,7 +2075,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) l2 = tcg_temp_new_i64(); h2 = tcg_temp_new_i64(); - /* Multipy both even elements from v2 and v3 */ + /* Multiply both even elements from v2 and v3 */ read_vec_element_i64(l1, get_field(s, v2), 0, ES_64); read_vec_element_i64(h1, get_field(s, v3), 0, ES_64); tcg_gen_mulu2_i64(l1, h1, l1, h1); @@ -1802,7 +2084,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1); } - /* Multipy both odd elements from v2 and v3 */ + /* Multiply both odd elements from v2 and v3 */ read_vec_element_i64(l2, get_field(s, v2), 1, ES_64); read_vec_element_i64(h2, get_field(s, v3), 1, ES_64); tcg_gen_mulu2_i64(l2, h2, l2, h2); @@ -2018,31 +2300,61 @@ static DisasJumpType op_ves(DisasContext *s, DisasOps *o) return DISAS_NEXT; } -static DisasJumpType op_vsl(DisasContext *s, DisasOps *o) +static DisasJumpType gen_vsh_by_byte(DisasContext *s, DisasOps *o, + gen_helper_gvec_2i *gen, + gen_helper_gvec_3 *gen_ve2) { - TCGv_i64 shift = tcg_temp_new_i64(); + bool byte = s->insn->data; - read_vec_element_i64(shift, get_field(s, v3), 7, ES_8); - if (s->fields.op2 == 0x74) { - tcg_gen_andi_i64(shift, shift, 0x7); + if (!byte && s390_has_feat(S390_FEAT_VECTOR_ENH2)) { + gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), + get_field(s, v3), 0, gen_ve2); } else { - tcg_gen_andi_i64(shift, shift, 0x78); - } + TCGv_i64 shift = tcg_temp_new_i64(); - gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2), - shift, 0, gen_helper_gvec_vsl); - tcg_temp_free_i64(shift); + read_vec_element_i64(shift, get_field(s, v3), 7, ES_8); + tcg_gen_andi_i64(shift, shift, byte ? 0x78 : 7); + gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2), shift, 0, gen); + tcg_temp_free_i64(shift); + } return DISAS_NEXT; } -static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o) +static DisasJumpType op_vsl(DisasContext *s, DisasOps *o) +{ + return gen_vsh_by_byte(s, o, gen_helper_gvec_vsl, + gen_helper_gvec_vsl_ve2); +} + +static DisasJumpType op_vsra(DisasContext *s, DisasOps *o) { - const uint8_t i4 = get_field(s, i4) & 0xf; - const int left_shift = (i4 & 7) * 8; - const int right_shift = 64 - left_shift; - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); + return gen_vsh_by_byte(s, o, gen_helper_gvec_vsra, + gen_helper_gvec_vsra_ve2); +} + +static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o) +{ + return gen_vsh_by_byte(s, o, gen_helper_gvec_vsrl, + gen_helper_gvec_vsrl_ve2); +} + +static DisasJumpType op_vsld(DisasContext *s, DisasOps *o) +{ + const bool byte = s->insn->data; + const uint8_t mask = byte ? 15 : 7; + const uint8_t mul = byte ? 8 : 1; + const uint8_t i4 = get_field(s, i4); + const int right_shift = 64 - (i4 & 7) * mul; + TCGv_i64 t0, t1, t2; + + if (i4 & ~mask) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); if ((i4 & 8) == 0) { read_vec_element_i64(t0, get_field(s, v2), 0, ES_64); @@ -2053,8 +2365,10 @@ static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o) read_vec_element_i64(t1, get_field(s, v3), 0, ES_64); read_vec_element_i64(t2, get_field(s, v3), 1, ES_64); } + tcg_gen_extract2_i64(t0, t1, t0, right_shift); tcg_gen_extract2_i64(t1, t2, t1, right_shift); + write_vec_element_i64(t0, get_field(s, v1), 0, ES_64); write_vec_element_i64(t1, get_field(s, v1), 1, ES_64); @@ -2064,37 +2378,33 @@ static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o) return DISAS_NEXT; } -static DisasJumpType op_vsra(DisasContext *s, DisasOps *o) +static DisasJumpType op_vsrd(DisasContext *s, DisasOps *o) { - TCGv_i64 shift = tcg_temp_new_i64(); + const uint8_t i4 = get_field(s, i4); + TCGv_i64 t0, t1, t2; - read_vec_element_i64(shift, get_field(s, v3), 7, ES_8); - if (s->fields.op2 == 0x7e) { - tcg_gen_andi_i64(shift, shift, 0x7); - } else { - tcg_gen_andi_i64(shift, shift, 0x78); + if (i4 & ~7) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; } - gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2), - shift, 0, gen_helper_gvec_vsra); - tcg_temp_free_i64(shift); - return DISAS_NEXT; -} + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); -static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o) -{ - TCGv_i64 shift = tcg_temp_new_i64(); + read_vec_element_i64(t0, get_field(s, v2), 1, ES_64); + read_vec_element_i64(t1, get_field(s, v3), 0, ES_64); + read_vec_element_i64(t2, get_field(s, v3), 1, ES_64); - read_vec_element_i64(shift, get_field(s, v3), 7, ES_8); - if (s->fields.op2 == 0x7c) { - tcg_gen_andi_i64(shift, shift, 0x7); - } else { - tcg_gen_andi_i64(shift, shift, 0x78); - } + tcg_gen_extract2_i64(t0, t1, t0, i4); + tcg_gen_extract2_i64(t1, t2, t1, i4); + + write_vec_element_i64(t0, get_field(s, v1), 0, ES_64); + write_vec_element_i64(t1, get_field(s, v1), 1, ES_64); - gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2), - shift, 0, gen_helper_gvec_vsrl); - tcg_temp_free_i64(shift); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); return DISAS_NEXT; } @@ -2413,7 +2723,7 @@ static DisasJumpType op_vfene(DisasContext *s, DisasOps *o) static DisasJumpType op_vistr(DisasContext *s, DisasOps *o) { - const uint8_t es = get_field(s, m4); + const uint8_t es = get_field(s, m3); const uint8_t m5 = get_field(s, m5); static gen_helper_gvec_2 * const g[3] = { gen_helper_gvec_vistr8, @@ -2497,6 +2807,31 @@ static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vstrs(DisasContext *s, DisasOps *o) +{ + typedef void (*helper_vstrs)(TCGv_ptr, TCGv_ptr, TCGv_ptr, + TCGv_ptr, TCGv_ptr, TCGv_i32); + static const helper_vstrs fns[3][2] = { + { gen_helper_gvec_vstrs_8, gen_helper_gvec_vstrs_zs8 }, + { gen_helper_gvec_vstrs_16, gen_helper_gvec_vstrs_zs16 }, + { gen_helper_gvec_vstrs_32, gen_helper_gvec_vstrs_zs32 }, + }; + const uint8_t es = get_field(s, m5); + const uint8_t m6 = get_field(s, m6); + const bool zs = extract32(m6, 1, 1); + + if (es > ES_32 || m6 & ~2) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), + get_field(s, v3), get_field(s, v4), + cpu_env, 0, fns[es][zs]); + set_cc_static(s); + return DISAS_NEXT; +} + static DisasJumpType op_vfa(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m4); @@ -2720,23 +3055,59 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) switch (s->fields.op2) { case 0xc3: - if (fpf == FPF_LONG) { + switch (fpf) { + case FPF_LONG: fn = gen_helper_gvec_vcdg64; + break; + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) { + fn = gen_helper_gvec_vcdg32; + } + break; + default: + break; } break; case 0xc1: - if (fpf == FPF_LONG) { + switch (fpf) { + case FPF_LONG: fn = gen_helper_gvec_vcdlg64; + break; + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) { + fn = gen_helper_gvec_vcdlg32; + } + break; + default: + break; } break; case 0xc2: - if (fpf == FPF_LONG) { + switch (fpf) { + case FPF_LONG: fn = gen_helper_gvec_vcgd64; + break; + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) { + fn = gen_helper_gvec_vcgd32; + } + break; + default: + break; } break; case 0xc0: - if (fpf == FPF_LONG) { + switch (fpf) { + case FPF_LONG: fn = gen_helper_gvec_vclgd64; + break; + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH2)) { + fn = gen_helper_gvec_vclgd32; + } + break; + default: + break; } break; case 0xc7: diff --git a/target/s390x/tcg/vec.h b/target/s390x/tcg/vec.h index a6e361869b2e..8d095efcfc6f 100644 --- a/target/s390x/tcg/vec.h +++ b/target/s390x/tcg/vec.h @@ -38,7 +38,7 @@ typedef union S390Vector { * W: [ 1][ 0] - [ 3][ 2] * DW: [ 0] - [ 1] */ -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN #define H1(x) ((x) ^ 7) #define H2(x) ((x) ^ 3) #define H4(x) ((x) ^ 1) diff --git a/target/s390x/tcg/vec_fpu_helper.c b/target/s390x/tcg/vec_fpu_helper.c index 1a779934715f..75cf605b9f4c 100644 --- a/target/s390x/tcg/vec_fpu_helper.c +++ b/target/s390x/tcg/vec_fpu_helper.c @@ -10,7 +10,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "s390x-internal.h" #include "vec.h" @@ -176,6 +175,30 @@ static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, *v1 = tmp; } +static float32 vcdg32(float32 a, float_status *s) +{ + return int32_to_float32(a, s); +} + +static float32 vcdlg32(float32 a, float_status *s) +{ + return uint32_to_float32(a, s); +} + +static float32 vcgd32(float32 a, float_status *s) +{ + const float32 tmp = float32_to_int32(a, s); + + return float32_is_any_nan(a) ? INT32_MIN : tmp; +} + +static float32 vclgd32(float32 a, float_status *s) +{ + const float32 tmp = float32_to_uint32(a, s); + + return float32_is_any_nan(a) ? 0 : tmp; +} + static float64 vcdg64(float64 a, float_status *s) { return int64_to_float64(a, s); @@ -211,6 +234,9 @@ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \ vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC()); \ } +#define DEF_GVEC_VOP2_32(NAME) \ +DEF_GVEC_VOP2_FN(NAME, NAME##32, 32) + #define DEF_GVEC_VOP2_64(NAME) \ DEF_GVEC_VOP2_FN(NAME, NAME##64, 64) @@ -219,6 +245,10 @@ DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32) \ DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) \ DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128) +DEF_GVEC_VOP2_32(vcdg) +DEF_GVEC_VOP2_32(vcdlg) +DEF_GVEC_VOP2_32(vcgd) +DEF_GVEC_VOP2_32(vclgd) DEF_GVEC_VOP2_64(vcdg) DEF_GVEC_VOP2_64(vcdlg) DEF_GVEC_VOP2_64(vcgd) @@ -794,7 +824,7 @@ static S390MinMaxRes vfmin_res(uint16_t dcmask_a, uint16_t dcmask_b, default: g_assert_not_reached(); } - } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) { + } else if (unlikely((dcmask_a & DCMASK_ZERO) && (dcmask_b & DCMASK_ZERO))) { switch (type) { case S390_MINMAX_TYPE_JAVA: return neg_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B; @@ -844,7 +874,7 @@ static S390MinMaxRes vfmax_res(uint16_t dcmask_a, uint16_t dcmask_b, default: g_assert_not_reached(); } - } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) { + } else if (unlikely((dcmask_a & DCMASK_ZERO) && (dcmask_b & DCMASK_ZERO))) { const bool neg_a = dcmask_a & DCMASK_NEGATIVE; switch (type) { diff --git a/target/s390x/tcg/vec_helper.c b/target/s390x/tcg/vec_helper.c index ededf13cf099..48d86722b2d0 100644 --- a/target/s390x/tcg/vec_helper.c +++ b/target/s390x/tcg/vec_helper.c @@ -200,7 +200,6 @@ void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr, addr = wrap_address(env, addr + 8); cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC()); } else { - S390Vector tmp = {}; int i; for (i = 0; i < bytes; i++) { @@ -209,6 +208,5 @@ void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr, cpu_stb_data_ra(env, addr, byte, GETPC()); addr = wrap_address(env, addr + 1); } - *(S390Vector *)v1 = tmp; } } diff --git a/target/s390x/tcg/vec_int_helper.c b/target/s390x/tcg/vec_int_helper.c index 5561b3ed9096..53ab5c5eb31b 100644 --- a/target/s390x/tcg/vec_int_helper.c +++ b/target/s390x/tcg/vec_int_helper.c @@ -10,7 +10,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "vec.h" #include "exec/helper-proto.h" @@ -540,18 +539,73 @@ void HELPER(gvec_vsl)(void *v1, const void *v2, uint64_t count, s390_vec_shl(v1, v2, count); } +void HELPER(gvec_vsl_ve2)(void *v1, const void *v2, const void *v3, + uint32_t desc) +{ + S390Vector tmp; + uint32_t sh, e0, e1 = 0; + int i; + + for (i = 15; i >= 0; --i, e1 = e0) { + e0 = s390_vec_read_element8(v2, i); + sh = s390_vec_read_element8(v3, i) & 7; + + s390_vec_write_element8(&tmp, i, rol32(e0 | (e1 << 24), sh)); + } + + *(S390Vector *)v1 = tmp; +} + void HELPER(gvec_vsra)(void *v1, const void *v2, uint64_t count, uint32_t desc) { s390_vec_sar(v1, v2, count); } +void HELPER(gvec_vsra_ve2)(void *v1, const void *v2, const void *v3, + uint32_t desc) +{ + S390Vector tmp; + uint32_t sh, e0, e1 = 0; + int i = 0; + + /* Byte 0 is special only. */ + e0 = (int32_t)(int8_t)s390_vec_read_element8(v2, i); + sh = s390_vec_read_element8(v3, i) & 7; + s390_vec_write_element8(&tmp, i, e0 >> sh); + + e1 = e0; + for (i = 1; i < 16; ++i, e1 = e0) { + e0 = s390_vec_read_element8(v2, i); + sh = s390_vec_read_element8(v3, i) & 7; + s390_vec_write_element8(&tmp, i, (e0 | e1 << 8) >> sh); + } + + *(S390Vector *)v1 = tmp; +} + void HELPER(gvec_vsrl)(void *v1, const void *v2, uint64_t count, uint32_t desc) { s390_vec_shr(v1, v2, count); } +void HELPER(gvec_vsrl_ve2)(void *v1, const void *v2, const void *v3, + uint32_t desc) +{ + S390Vector tmp; + uint32_t sh, e0, e1 = 0; + + for (int i = 0; i < 16; ++i, e1 = e0) { + e0 = s390_vec_read_element8(v2, i); + sh = s390_vec_read_element8(v3, i) & 7; + + s390_vec_write_element8(&tmp, i, (e0 | (e1 << 8)) >> sh); + } + + *(S390Vector *)v1 = tmp; +} + #define DEF_VSCBI(BITS) \ void HELPER(gvec_vscbi##BITS)(void *v1, const void *v2, const void *v3, \ uint32_t desc) \ diff --git a/target/s390x/tcg/vec_string_helper.c b/target/s390x/tcg/vec_string_helper.c index ac315eb095c1..9b85becdfbff 100644 --- a/target/s390x/tcg/vec_string_helper.c +++ b/target/s390x/tcg/vec_string_helper.c @@ -10,7 +10,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "s390x-internal.h" #include "vec.h" @@ -471,3 +470,102 @@ void HELPER(gvec_vstrc_cc_rt##BITS)(void *v1, const void *v2, const void *v3, \ DEF_VSTRC_CC_RT_HELPER(8) DEF_VSTRC_CC_RT_HELPER(16) DEF_VSTRC_CC_RT_HELPER(32) + +static int vstrs(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + const S390Vector *v4, uint8_t es, bool zs) +{ + int substr_elen, substr_0, str_elen, i, j, k, cc; + int nelem = 16 >> es; + bool eos = false; + + substr_elen = s390_vec_read_element8(v4, 7) >> es; + + /* If ZS, bound substr length by min(nelem, strlen(v3)). */ + if (zs) { + substr_elen = MIN(substr_elen, nelem); + for (i = 0; i < substr_elen; i++) { + if (s390_vec_read_element(v3, i, es) == 0) { + substr_elen = i; + break; + } + } + } + + if (substr_elen == 0) { + cc = 2; /* full match for degenerate case of empty substr */ + k = 0; + goto done; + } + + /* If ZS, look for eos in the searched string. */ + if (zs) { + for (k = 0; k < nelem; k++) { + if (s390_vec_read_element(v2, k, es) == 0) { + eos = true; + break; + } + } + str_elen = k; + } else { + str_elen = nelem; + } + + substr_0 = s390_vec_read_element(v3, 0, es); + + for (k = 0; ; k++) { + for (; k < str_elen; k++) { + if (s390_vec_read_element(v2, k, es) == substr_0) { + break; + } + } + + /* If we reached the end of the string, no match. */ + if (k == str_elen) { + cc = eos; /* no match (with or without zero char) */ + goto done; + } + + /* If the substring is only one char, match. */ + if (substr_elen == 1) { + cc = 2; /* full match */ + goto done; + } + + /* If the match begins at the last char, we have a partial match. */ + if (k == str_elen - 1) { + cc = 3; /* partial match */ + goto done; + } + + i = MIN(nelem, k + substr_elen); + for (j = k + 1; j < i; j++) { + uint32_t e2 = s390_vec_read_element(v2, j, es); + uint32_t e3 = s390_vec_read_element(v3, j - k, es); + if (e2 != e3) { + break; + } + } + if (j == i) { + /* Matched up until "end". */ + cc = i - k == substr_elen ? 2 : 3; /* full or partial match */ + goto done; + } + } + + done: + s390_vec_write_element64(v1, 0, k << es); + s390_vec_write_element64(v1, 1, 0); + return cc; +} + +#define DEF_VSTRS_HELPER(BITS) \ +void QEMU_FLATTEN HELPER(gvec_vstrs_##BITS)(void *v1, const void *v2, \ + const void *v3, const void *v4, CPUS390XState *env, uint32_t desc) \ + { env->cc_op = vstrs(v1, v2, v3, v4, MO_##BITS, false); } \ +void QEMU_FLATTEN HELPER(gvec_vstrs_zs##BITS)(void *v1, const void *v2, \ + const void *v3, const void *v4, CPUS390XState *env, uint32_t desc) \ + { env->cc_op = vstrs(v1, v2, v3, v4, MO_##BITS, true); } + +DEF_VSTRS_HELPER(8) +DEF_VSTRS_HELPER(16) +DEF_VSTRS_HELPER(32) diff --git a/target/sh4/cpu-param.h b/target/sh4/cpu-param.h index 81ace3503bc9..98a02509bbbe 100644 --- a/target/sh4/cpu-param.h +++ b/target/sh4/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef SH4_CPU_PARAM_H -#define SH4_CPU_PARAM_H 1 +#define SH4_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 /* 4k */ diff --git a/target/sh4/cpu-qom.h b/target/sh4/cpu-qom.h index d4192d109083..89785a90f02a 100644 --- a/target/sh4/cpu-qom.h +++ b/target/sh4/cpu-qom.h @@ -34,7 +34,7 @@ OBJECT_DECLARE_CPU_TYPE(SuperHCPU, SuperHCPUClass, SUPERH_CPU) /** * SuperHCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * @pvr: Processor Version Register * @prr: Processor Revision Register * @cvr: Cache Version Register @@ -47,7 +47,7 @@ struct SuperHCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; uint32_t pvr; uint32_t prr; diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 06b2691dc411..f0934b20fa56 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -34,15 +34,37 @@ 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.pc = tb_pc(tb); cpu->env.flags = tb->flags & TB_FLAG_ENVFLAGS_MASK; } +static void superh_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + SuperHCPU *cpu = SUPERH_CPU(cs); + + cpu->env.pc = data[0]; + cpu->env.flags = data[1]; + /* + * Theoretically delayed_pc should also be restored. In practice the + * branch instruction is re-executed after exception, so the delayed + * branch target will be recomputed. + */ +} + #ifndef CONFIG_USER_ONLY static bool superh_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb) @@ -50,10 +72,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; @@ -65,14 +87,16 @@ static bool superh_cpu_has_work(CPUState *cs) return cs->interrupt_request & CPU_INTERRUPT_HARD; } -static void superh_cpu_reset(DeviceState *dev) +static void superh_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); SuperHCPU *cpu = SUPERH_CPU(s); SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(cpu); CPUSH4State *env = &cpu->env; - scc->parent_reset(dev); + if (scc->parent_phases.hold) { + scc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUSH4State, end_reset_fields)); @@ -236,6 +260,7 @@ static const struct SysemuCPUOps sh4_sysemu_ops = { static const struct TCGCPUOps superh_tcg_ops = { .initialize = sh4_translate_init, .synchronize_from_tb = superh_cpu_synchronize_from_tb, + .restore_state_to_opc = superh_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = superh_cpu_tlb_fill, @@ -251,16 +276,19 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, superh_cpu_realizefn, &scc->parent_realize); - device_class_set_parent_reset(dc, superh_cpu_reset, &scc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, superh_cpu_reset_hold, NULL, + &scc->parent_phases); cc->class_by_name = superh_cpu_class_by_name; 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 c72a30edfd41..727b8295986c 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" /* CPU Subtypes */ #define SH_CPU_SH7750 (1 << 0) @@ -77,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_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 (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_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 */ @@ -209,9 +217,9 @@ void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int superh_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); void sh4_translate_init(void); void sh4_cpu_list(void); @@ -257,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; @@ -365,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 6a620e36fc36..e02e7af60799 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/op_helper.c b/target/sh4/op_helper.c index 752669825f02..a663335c39ae 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -57,8 +57,9 @@ void helper_ldtlb(CPUSH4State *env) #endif } -static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index, - uintptr_t retaddr) +static inline G_NORETURN +void raise_exception(CPUSH4State *env, int index, + uintptr_t retaddr) { CPUState *cs = env_cpu(env); diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 43bc88b7b32b..7db3468b0118 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) { @@ -2352,10 +2358,11 @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void sh4_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +static void sh4_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cs, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps sh4_tr_ops = { @@ -2367,19 +2374,10 @@ 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); -} - -void restore_state_to_opc(CPUSH4State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; - env->flags = data[1]; - /* Theoretically delayed_pc should also be restored. In practice the - branch instruction is re-executed after exception, so the delayed - branch target will be recomputed. */ + translator_loop(cs, tb, max_insns, pc, host_pc, &sh4_tr_ops, &ctx.base); } diff --git a/target/sparc/cpu-param.h b/target/sparc/cpu-param.h index 4746d8941158..72ddc4a34f09 100644 --- a/target/sparc/cpu-param.h +++ b/target/sparc/cpu-param.h @@ -5,7 +5,7 @@ */ #ifndef SPARC_CPU_PARAM_H -#define SPARC_CPU_PARAM_H 1 +#define SPARC_CPU_PARAM_H #ifdef TARGET_SPARC64 # define TARGET_LONG_BITS 64 diff --git a/target/sparc/cpu-qom.h b/target/sparc/cpu-qom.h index 86ed37d9333f..78bf00b9a232 100644 --- a/target/sparc/cpu-qom.h +++ b/target/sparc/cpu-qom.h @@ -35,7 +35,7 @@ typedef struct sparc_def_t sparc_def_t; /** * SPARCCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * * A SPARC CPU model. */ @@ -45,7 +45,7 @@ struct SPARCCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; sparc_def_t *cpu_def; }; diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 55268ed2a19e..1734ef8dc6b5 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -28,14 +28,16 @@ //#define DEBUG_FEATURES -static void sparc_cpu_reset(DeviceState *dev) +static void sparc_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); SPARCCPU *cpu = SPARC_CPU(s); SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(cpu); CPUSPARCState *env = &cpu->env; - scc->parent_reset(dev); + if (scc->parent_phases.hold) { + scc->parent_phases.hold(obj); + } memset(env, 0, offsetof(CPUSPARCState, end_reset_fields)); env->cwp = 0; @@ -693,12 +695,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; } @@ -865,6 +874,7 @@ static const struct SysemuCPUOps sparc_sysemu_ops = { static const struct TCGCPUOps sparc_tcg_ops = { .initialize = sparc_tcg_init, .synchronize_from_tb = sparc_cpu_synchronize_from_tb, + .restore_state_to_opc = sparc_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = sparc_cpu_tlb_fill, @@ -881,12 +891,14 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) SPARCCPUClass *scc = SPARC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, sparc_cpu_realizefn, &scc->parent_realize); device_class_set_props(dc, sparc_cpu_properties); - device_class_set_parent_reset(dc, sparc_cpu_reset, &scc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, sparc_cpu_reset_hold, NULL, + &scc->parent_phases); cc->class_by_name = sparc_cpu_class_by_name; cc->parse_features = sparc_cpu_parse_features; @@ -896,6 +908,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/cpu.h b/target/sparc/cpu.h index abb38db6749d..e478c5eb16e0 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -4,6 +4,7 @@ #include "qemu/bswap.h" #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" #if !defined(TARGET_SPARC64) #define TARGET_DPREGS 16 @@ -574,11 +575,11 @@ void sparc_cpu_do_interrupt(CPUState *cpu); hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int sparc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, - uintptr_t retaddr); -void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t) QEMU_NORETURN; +G_NORETURN void sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, + int mmu_idx, + uintptr_t retaddr); +G_NORETURN void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t); #ifndef NO_CPU_IO_DEFS /* cpu_init.c */ @@ -599,6 +600,9 @@ int sparc_cpu_memory_rw_debug(CPUState *cpu, vaddr addr, /* translate.c */ void sparc_tcg_init(void); +void sparc_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data); /* cpu-exec.c */ diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 346a6dfa3537..919448a49401 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -925,10 +925,10 @@ hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) } #ifndef CONFIG_USER_ONLY -void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, - int mmu_idx, - uintptr_t retaddr) +G_NORETURN void sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, + int mmu_idx, + uintptr_t retaddr) { SPARCCPU *cpu = SPARC_CPU(cs); CPUSPARCState *env = &cpu->env; diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 4c7c7b534703..150aeecd14b8 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -163,13 +163,6 @@ static inline void gen_update_fprs_dirty(DisasContext *dc, int rd) /* floating point registers moves */ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) { -#if TCG_TARGET_REG_BITS == 32 - if (src & 1) { - return TCGV_LOW(cpu_fpr[src / 2]); - } else { - return TCGV_HIGH(cpu_fpr[src / 2]); - } -#else TCGv_i32 ret = get_temp_i32(dc); if (src & 1) { tcg_gen_extrl_i64_i32(ret, cpu_fpr[src / 2]); @@ -177,22 +170,16 @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) tcg_gen_extrh_i64_i32(ret, cpu_fpr[src / 2]); } return ret; -#endif } static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v) { -#if TCG_TARGET_REG_BITS == 32 - if (dst & 1) { - tcg_gen_mov_i32(TCGV_LOW(cpu_fpr[dst / 2]), v); - } else { - tcg_gen_mov_i32(TCGV_HIGH(cpu_fpr[dst / 2]), v); - } -#else - TCGv_i64 t = (TCGv_i64)v; + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t, v); tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t, (dst & 1 ? 0 : 32), 32); -#endif + tcg_temp_free_i64(t); gen_update_fprs_dirty(dc, dst); } @@ -5901,10 +5888,11 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } } -static void sparc_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void sparc_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps sparc_tr_ops = { @@ -5916,11 +5904,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) @@ -6009,9 +5998,12 @@ void sparc_tcg_init(void) } } -void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, - target_ulong *data) +void sparc_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; target_ulong pc = data[0]; target_ulong npc = data[1]; diff --git a/target/sparc/vis_helper.c b/target/sparc/vis_helper.c index f917e5992dc7..3afdc6975cff 100644 --- a/target/sparc/vis_helper.c +++ b/target/sparc/vis_helper.c @@ -42,7 +42,7 @@ target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize) GET_FIELD_SP(pixel_addr, 11, 12); } -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN #define VIS_B64(n) b[7 - (n)] #define VIS_W64(n) w[3 - (n)] #define VIS_SW64(n) sw[3 - (n)] @@ -470,7 +470,7 @@ uint64_t helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2) uint32_t i, mask, host; /* Set up S such that we can index across all of the bytes. */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN s.ll[0] = src1; s.ll[1] = src2; host = 0; diff --git a/target/tricore/cpu-param.h b/target/tricore/cpu-param.h index cf5d9af89d3f..27279130479f 100644 --- a/target/tricore/cpu-param.h +++ b/target/tricore/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef TRICORE_CPU_PARAM_H -#define TRICORE_CPU_PARAM_H 1 +#define TRICORE_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 14 diff --git a/target/tricore/cpu-qom.h b/target/tricore/cpu-qom.h index ee24e9fa76af..612731daa09a 100644 --- a/target/tricore/cpu-qom.h +++ b/target/tricore/cpu-qom.h @@ -32,7 +32,7 @@ struct TriCoreCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index b95682b7f04d..594cd1efd5ee 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -41,23 +41,43 @@ 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) +static void tricore_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { - CPUState *s = CPU(dev); + TriCoreCPU *cpu = TRICORE_CPU(cs); + CPUTriCoreState *env = &cpu->env; + + env->PC = data[0]; +} + +static void tricore_cpu_reset_hold(Object *obj) +{ + CPUState *s = CPU(obj); TriCoreCPU *cpu = TRICORE_CPU(s); TriCoreCPUClass *tcc = TRICORE_CPU_GET_CLASS(cpu); CPUTriCoreState *env = &cpu->env; - tcc->parent_reset(dev); + if (tcc->parent_phases.hold) { + tcc->parent_phases.hold(obj); + } cpu_state_reset(env); } @@ -153,6 +173,7 @@ static const struct SysemuCPUOps tricore_sysemu_ops = { static const struct TCGCPUOps tricore_tcg_ops = { .initialize = tricore_tcg_init, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, + .restore_state_to_opc = tricore_restore_state_to_opc, .tlb_fill = tricore_cpu_tlb_fill, }; @@ -161,11 +182,13 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) TriCoreCPUClass *mcc = TRICORE_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); device_class_set_parent_realize(dc, tricore_cpu_realizefn, &mcc->parent_realize); - device_class_set_parent_reset(dc, tricore_cpu_reset, &mcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, tricore_cpu_reset_hold, NULL, + &mcc->parent_phases); cc->class_by_name = tricore_cpu_class_by_name; cc->has_work = tricore_cpu_has_work; @@ -176,6 +199,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/cpu.h b/target/tricore/cpu.h index 108d6b8288fb..3b9c533a7c3b 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "qemu/cpu-float.h" #include "tricore-defs.h" struct tricore_boot_info; diff --git a/target/tricore/csfr.def b/target/tricore/csfr.h.inc similarity index 100% rename from target/tricore/csfr.def rename to target/tricore/csfr.h.inc diff --git a/target/tricore/gdbstub.c b/target/tricore/gdbstub.c index 3ce55abb8e3b..3a27a7e65d91 100644 --- a/target/tricore/gdbstub.c +++ b/target/tricore/gdbstub.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "exec/gdbstub.h" @@ -131,7 +130,7 @@ int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) if (n < 16) { /* data registers */ env->gpr_d[n] = tmp; } else if (n < 32) { /* address registers */ - env->gpr_d[n - 16] = tmp; + env->gpr_a[n - 16] = tmp; } else { tricore_cpu_gdb_write_csfr(env, n, tmp); } diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 9476d10d0065..532ae6b74c79 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -25,13 +25,13 @@ /* Exception helpers */ -static void QEMU_NORETURN -raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin, - uintptr_t pc, uint32_t fcd_pc) +static G_NORETURN +void raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin, + uintptr_t pc, uint32_t fcd_pc) { CPUState *cs = env_cpu(env); /* in case we come from a helper-call we need to restore the PC */ - cpu_restore_state(cs, pc, true); + cpu_restore_state(cs, pc); /* Tin is loaded into d[15] */ env->gpr_d[15] = tin; diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 417edbd3f0fe..df9e46c6495e 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -388,7 +388,7 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset) gen_helper_psw_read(ret, cpu_env); } else { switch (offset) { -#include "csfr.def" +#include "csfr.h.inc" } } } @@ -418,7 +418,7 @@ static inline void gen_mtcr(DisasContext *ctx, TCGv r1, gen_helper_psw_write(cpu_env, r1); } else { switch (offset) { -#include "csfr.def" +#include "csfr.h.inc" } } } else { @@ -8861,10 +8861,11 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void tricore_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void tricore_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps tricore_tr_ops = { @@ -8877,18 +8878,14 @@ 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 -restore_state_to_opc(CPUTriCoreState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->PC = data[0]; -} /* * * Initialization diff --git a/target/xtensa/core-de233_fpu.c b/target/xtensa/core-de233_fpu.c index c7cbeb1b4834..41af8057fbb9 100644 --- a/target/xtensa/core-de233_fpu.c +++ b/target/xtensa/core-de233_fpu.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" -#include "qemu-common.h" #include "qemu/host-utils.h" #include "core-de233_fpu/core-isa.h" diff --git a/target/xtensa/core-de233_fpu/core-isa.h b/target/xtensa/core-de233_fpu/core-isa.h index f125619e8de5..40543b2c5e59 100644 --- a/target/xtensa/core-de233_fpu/core-isa.h +++ b/target/xtensa/core-de233_fpu/core-isa.h @@ -28,8 +28,8 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef XTENSA_CORE_CONFIGURATION_H_ -#define XTENSA_CORE_CONFIGURATION_H_ +#ifndef XTENSA_CORE_DE233_FPU_CORE_ISA_H +#define XTENSA_CORE_DE233_FPU_CORE_ISA_H //depot/dev/Homewood/Xtensa/SWConfig/hal/core-common.h.tph#24 - edit change 444323 (text+ko) @@ -723,5 +723,4 @@ #endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ -#endif /* XTENSA_CORE_CONFIGURATION_H_ */ - +#endif /* XTENSA_CORE_DE233_FPU_CORE_ISA_H */ diff --git a/target/xtensa/core-de233_fpu/core-matmap.h b/target/xtensa/core-de233_fpu/core-matmap.h index cca51c7af1b5..e99e7d312331 100644 --- a/target/xtensa/core-de233_fpu/core-matmap.h +++ b/target/xtensa/core-de233_fpu/core-matmap.h @@ -43,11 +43,9 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #ifndef XTENSA_CONFIG_CORE_MATMAP_H #define XTENSA_CONFIG_CORE_MATMAP_H - /*---------------------------------------------------------------------- CACHE (MEMORY ACCESS) ATTRIBUTES ----------------------------------------------------------------------*/ @@ -713,5 +711,5 @@ -#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ +#endif /* XTENSA_CONFIG_CORE_MATMAP_H */ diff --git a/target/xtensa/core-dsp3400.c b/target/xtensa/core-dsp3400.c index 4e0bc8a8c46c..81e425c56828 100644 --- a/target/xtensa/core-dsp3400.c +++ b/target/xtensa/core-dsp3400.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" -#include "qemu-common.h" #include "qemu/host-utils.h" #include "core-dsp3400/core-isa.h" diff --git a/target/xtensa/core-dsp3400/core-isa.h b/target/xtensa/core-dsp3400/core-isa.h index 336b2467c6ac..1499ef291400 100644 --- a/target/xtensa/core-dsp3400/core-isa.h +++ b/target/xtensa/core-dsp3400/core-isa.h @@ -28,9 +28,8 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef _XTENSA_CORE_CONFIGURATION_H -#define _XTENSA_CORE_CONFIGURATION_H - +#ifndef XTENSA_CORE_DSP3400_CORE_ISA_H +#define XTENSA_CORE_DSP3400_CORE_ISA_H /**************************************************************************** Parameters Useful for Any Code, USER or PRIVILEGED @@ -448,5 +447,4 @@ #endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ -#endif /* _XTENSA_CORE_CONFIGURATION_H */ - +#endif /* XTENSA_CORE_DSP3400_CORE_ISA_H */ diff --git a/target/xtensa/core-dsp3400/core-matmap.h b/target/xtensa/core-dsp3400/core-matmap.h index 8d1aa8336ec6..692012f9f4a0 100644 --- a/target/xtensa/core-dsp3400/core-matmap.h +++ b/target/xtensa/core-dsp3400/core-matmap.h @@ -43,11 +43,9 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #ifndef XTENSA_CONFIG_CORE_MATMAP_H #define XTENSA_CONFIG_CORE_MATMAP_H - /*---------------------------------------------------------------------- CACHE (MEMORY ACCESS) ATTRIBUTES ----------------------------------------------------------------------*/ @@ -308,5 +306,5 @@ -#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ +#endif /* XTENSA_CONFIG_CORE_MATMAP_H */ diff --git a/target/xtensa/core-lx106.c b/target/xtensa/core-lx106.c new file mode 100644 index 000000000000..7a771d09a6aa --- /dev/null +++ b/target/xtensa/core-lx106.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, Simon Safar, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" + +#include "core-lx106/core-isa.h" +#include "overlay_tool.h" + +#define xtensa_modules xtensa_modules_lx106 +#include "core-lx106/xtensa-modules.c.inc" + +static XtensaConfig lx106 __attribute__((unused)) = { + .name = "lx106", + .gdb_regmap = { + .reg = { +#include "core-lx106/gdb-config.c.inc" + } + }, + .isa_internal = &xtensa_modules, + .clock_freq_khz = 40000, + DEFAULT_SECTIONS +}; + +REGISTER_CORE(lx106) diff --git a/target/xtensa/core-lx106/core-isa.h b/target/xtensa/core-lx106/core-isa.h new file mode 100644 index 000000000000..86bcf1a5d6f9 --- /dev/null +++ b/target/xtensa/core-lx106/core-isa.h @@ -0,0 +1,470 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See , which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + + Copyright (c) 1999-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 0 /* windowed registers option */ +#define XCHAL_NUM_AREGS 16 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 4 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 0 /* zero-overhead loops */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 0 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 0 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 0 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_THREADPTR 0 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */ +#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_FP 0 /* floating point pkg */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 1 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 4 /* data width in bytes */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/ + +#define XCHAL_SW_VERSION 800001 /* sw version of this header */ + +#define XCHAL_CORE_ID "lx106" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x0002B6F6 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC28CDAFA /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x1082B6F6 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX3.0.1" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2300 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 230001 /* major*100+minor */ +#define XCHAL_HW_REL_LX3 1 +#define XCHAL_HW_REL_LX3_0 1 +#define XCHAL_HW_REL_LX3_0_1 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2300 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 230001 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2300 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 230001 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 4 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 4 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 2 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 2 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 0 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 0 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 0 +#define XCHAL_DCACHE_SETWIDTH 0 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 1 +#define XCHAL_DCACHE_WAYS 1 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 0 +#define XCHAL_DCACHE_LINE_LOCKABLE 0 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 1 +#define XCHAL_DCACHE_ACCESS_SIZE 1 + +/* Number of encoded cache attr bits (see for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 1 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 1 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */ + +/* Instruction ROM 0: */ +#define XCHAL_INSTROM0_VADDR 0x40200000 +#define XCHAL_INSTROM0_PADDR 0x40200000 +// #define XCHAL_INSTROM0_VADDR 0x400000 +// #define XCHAL_INSTROM0_PADDR 0x400000 +#define XCHAL_INSTROM0_SIZE 1048576 +#define XCHAL_INSTROM0_ECC_PARITY 0 + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x40000000 +#define XCHAL_INSTRAM0_PADDR 0x40000000 +#define XCHAL_INSTRAM0_SIZE 1048576 +#define XCHAL_INSTRAM0_ECC_PARITY 0 + +/* Instruction RAM 1: */ +#define XCHAL_INSTRAM1_VADDR 0x40100000 +#define XCHAL_INSTRAM1_PADDR 0x40100000 +#define XCHAL_INSTRAM1_SIZE 1048576 +#define XCHAL_INSTRAM1_ECC_PARITY 0 + +/* Data ROM 0: */ +#define XCHAL_DATAROM0_VADDR 0x3FF40000 +#define XCHAL_DATAROM0_PADDR 0x3FF40000 +#define XCHAL_DATAROM0_SIZE 262144 +#define XCHAL_DATAROM0_ECC_PARITY 0 + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x3FFC0000 +#define XCHAL_DATARAM0_PADDR 0x3FFC0000 +#define XCHAL_DATARAM0_SIZE 262144 +#define XCHAL_DATARAM0_ECC_PARITY 0 + +/* Data RAM 1: */ +#define XCHAL_DATARAM1_VADDR 0x3FF80000 +#define XCHAL_DATARAM1_PADDR 0x3FF80000 +#define XCHAL_DATARAM1_SIZE 262144 +#define XCHAL_DATARAM1_ECC_PARITY 0 + +/* XLMI Port 0: */ +#define XCHAL_XLMI0_VADDR 0x3FF00000 +#define XCHAL_XLMI0_PADDR 0x3FF00000 +#define XCHAL_XLMI0_SIZE 262144 +#define XCHAL_XLMI0_ECC_PARITY 0 + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 1 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 15 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 4 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 13 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 2 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x00003FFF +#define XCHAL_INTLEVEL2_MASK 0x00000000 +#define XCHAL_INTLEVEL3_MASK 0x00004000 +#define XCHAL_INTLEVEL4_MASK 0x00000000 +#define XCHAL_INTLEVEL5_MASK 0x00000000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00003FFF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x00003FFF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x00007FFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 1 +#define XCHAL_INT9_LEVEL 1 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 1 +#define XCHAL_INT12_LEVEL 1 +#define XCHAL_INT13_LEVEL 1 +#define XCHAL_INT14_LEVEL 3 +#define XCHAL_DEBUGLEVEL 2 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 3 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFF8000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000080 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00003F00 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000003F +#define XCHAL_INTTYPE_MASK_TIMER 0x00000040 +#define XCHAL_INTTYPE_MASK_NMI 0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER2_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */ + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL3_NUM 14 +/* (There are many interrupts each at level(s) 1.) */ + + +/* + * External interrupt vectors/levels. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 8 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 9 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 10 /* (intlevel 1) */ +#define XCHAL_EXTINT9_NUM 11 /* (intlevel 1) */ +#define XCHAL_EXTINT10_NUM 12 /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM 13 /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM 14 /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0x40000000 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x40000000 +#define XCHAL_RESET_VECBASE_OVERLAP 0 + +#define XCHAL_RESET_VECTOR0_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR0_PADDR 0x50000000 +#define XCHAL_RESET_VECTOR1_VADDR 0x40000080 +#define XCHAL_RESET_VECTOR1_PADDR 0x40000080 +#define XCHAL_RESET_VECTOR_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR_PADDR 0x50000000 + +// #define XCHAL_RESET_VECTOR0_VADDR 0x4000f8 +// #define XCHAL_RESET_VECTOR0_PADDR 0x4000f8 +// #define XCHAL_RESET_VECTOR1_VADDR 0x40000080 +// #define XCHAL_RESET_VECTOR1_PADDR 0x40000080 +// #define XCHAL_RESET_VECTOR_VADDR 0x4000f8 +// #define XCHAL_RESET_VECTOR_PADDR 0x4000f8 + + +#define XCHAL_USER_VECOFS 0x00000050 +#define XCHAL_USER_VECTOR_VADDR 0x40000050 +#define XCHAL_USER_VECTOR_PADDR 0x40000050 +#define XCHAL_KERNEL_VECOFS 0x00000030 +#define XCHAL_KERNEL_VECTOR_VADDR 0x40000030 +#define XCHAL_KERNEL_VECTOR_PADDR 0x40000030 +#define XCHAL_DOUBLEEXC_VECOFS 0x00000070 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x40000070 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x40000070 +#define XCHAL_INTLEVEL2_VECOFS 0x00000010 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000010 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000010 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL2_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL2_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL2_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x00000020 +#define XCHAL_NMI_VECTOR_VADDR 0x40000020 +#define XCHAL_NMI_VECTOR_PADDR 0x40000020 +#define XCHAL_INTLEVEL3_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL3_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL3_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 1 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 1 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */ +#define XCHAL_SPANNING_WAY 0 /* TLB spanning way number */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/target/xtensa/core-lx106/gdb-config.c.inc b/target/xtensa/core-lx106/gdb-config.c.inc new file mode 100644 index 000000000000..365d6fe60936 --- /dev/null +++ b/target/xtensa/core-lx106/gdb-config.c.inc @@ -0,0 +1,83 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + + Copyright (c) 2003-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + XTREG( 0, 0,32, 4, 4,0x0000,0x0006,-2, 8,0x0100,a0, 0,0,0,0,0,0) + XTREG( 1, 4,32, 4, 4,0x0001,0x0006,-2, 8,0x0100,a1, 0,0,0,0,0,0) + XTREG( 2, 8,32, 4, 4,0x0002,0x0006,-2, 8,0x0100,a2, 0,0,0,0,0,0) + XTREG( 3, 12,32, 4, 4,0x0003,0x0006,-2, 8,0x0100,a3, 0,0,0,0,0,0) + XTREG( 4, 16,32, 4, 4,0x0004,0x0006,-2, 8,0x0100,a4, 0,0,0,0,0,0) + XTREG( 5, 20,32, 4, 4,0x0005,0x0006,-2, 8,0x0100,a5, 0,0,0,0,0,0) + XTREG( 6, 24,32, 4, 4,0x0006,0x0006,-2, 8,0x0100,a6, 0,0,0,0,0,0) + XTREG( 7, 28,32, 4, 4,0x0007,0x0006,-2, 8,0x0100,a7, 0,0,0,0,0,0) + XTREG( 8, 32,32, 4, 4,0x0008,0x0006,-2, 8,0x0100,a8, 0,0,0,0,0,0) + XTREG( 9, 36,32, 4, 4,0x0009,0x0006,-2, 8,0x0100,a9, 0,0,0,0,0,0) + XTREG( 10, 40,32, 4, 4,0x000a,0x0006,-2, 8,0x0100,a10, 0,0,0,0,0,0) + XTREG( 11, 44,32, 4, 4,0x000b,0x0006,-2, 8,0x0100,a11, 0,0,0,0,0,0) + XTREG( 12, 48,32, 4, 4,0x000c,0x0006,-2, 8,0x0100,a12, 0,0,0,0,0,0) + XTREG( 13, 52,32, 4, 4,0x000d,0x0006,-2, 8,0x0100,a13, 0,0,0,0,0,0) + XTREG( 14, 56,32, 4, 4,0x000e,0x0006,-2, 8,0x0100,a14, 0,0,0,0,0,0) + XTREG( 15, 60,32, 4, 4,0x000f,0x0006,-2, 8,0x0100,a15, 0,0,0,0,0,0) + XTREG( 16, 64,32, 4, 4,0x0020,0x0006,-2, 9,0x0100,pc, 0,0,0,0,0,0) + XTREG( 17, 68, 6, 4, 4,0x0203,0x0006,-2, 2,0x1100,sar, 0,0,0,0,0,0) + XTREG( 18, 72,32, 4, 4,0x0205,0x0006,-2, 2,0x1100,litbase, 0,0,0,0,0,0) + XTREG( 19, 76,32, 4, 4,0x02b0,0x0002,-2, 2,0x1000,sr176, 0,0,0,0,0,0) + XTREG( 20, 80,32, 4, 4,0x02d0,0x0002,-2, 2,0x1000,sr208, 0,0,0,0,0,0) + XTREG( 21, 84, 6, 4, 4,0x02e6,0x0006,-2, 2,0x1100,ps, 0,0,0,0,0,0) + XTREG( 22, 88,32, 4, 4,0x0259,0x000d,-2, 2,0x1000,mmid, 0,0,0,0,0,0) + XTREG( 23, 92, 1, 4, 4,0x0260,0x0007,-2, 2,0x1000,ibreakenable,0,0,0,0,0,0) + XTREG( 24, 96,32, 4, 4,0x0268,0x0007,-2, 2,0x1000,ddr, 0,0,0,0,0,0) + XTREG( 25,100,32, 4, 4,0x0280,0x0007,-2, 2,0x1000,ibreaka0, 0,0,0,0,0,0) + XTREG( 26,104,32, 4, 4,0x0290,0x0007,-2, 2,0x1000,dbreaka0, 0,0,0,0,0,0) + XTREG( 27,108,32, 4, 4,0x02a0,0x0007,-2, 2,0x1000,dbreakc0, 0,0,0,0,0,0) + XTREG( 28,112,32, 4, 4,0x02b1,0x0007,-2, 2,0x1000,epc1, 0,0,0,0,0,0) + XTREG( 29,116,32, 4, 4,0x02b2,0x0007,-2, 2,0x1000,epc2, 0,0,0,0,0,0) + XTREG( 30,120,32, 4, 4,0x02b3,0x0007,-2, 2,0x1000,epc3, 0,0,0,0,0,0) + XTREG( 31,124,32, 4, 4,0x02c0,0x0007,-2, 2,0x1000,depc, 0,0,0,0,0,0) + XTREG( 32,128, 6, 4, 4,0x02c2,0x0007,-2, 2,0x1000,eps2, 0,0,0,0,0,0) + XTREG( 33,132, 6, 4, 4,0x02c3,0x0007,-2, 2,0x1000,eps3, 0,0,0,0,0,0) + XTREG( 34,136,32, 4, 4,0x02d1,0x0007,-2, 2,0x1000,excsave1, 0,0,0,0,0,0) + XTREG( 35,140,32, 4, 4,0x02d2,0x0007,-2, 2,0x1000,excsave2, 0,0,0,0,0,0) + XTREG( 36,144,32, 4, 4,0x02d3,0x0007,-2, 2,0x1000,excsave3, 0,0,0,0,0,0) + XTREG( 37,148,15, 4, 4,0x02e2,0x000b,-2, 2,0x1000,interrupt, 0,0,0,0,0,0) + XTREG( 38,152,15, 4, 4,0x02e2,0x000d,-2, 2,0x1000,intset, 0,0,0,0,0,0) + XTREG( 39,156,15, 4, 4,0x02e3,0x000d,-2, 2,0x1000,intclear, 0,0,0,0,0,0) + XTREG( 40,160,15, 4, 4,0x02e4,0x0007,-2, 2,0x1000,intenable, 0,0,0,0,0,0) + XTREG( 41,164,32, 4, 4,0x02e7,0x0007,-2, 2,0x1000,vecbase, 0,0,0,0,0,0) + XTREG( 42,168, 6, 4, 4,0x02e8,0x0007,-2, 2,0x1000,exccause, 0,0,0,0,0,0) + XTREG( 43,172,12, 4, 4,0x02e9,0x0003,-2, 2,0x1000,debugcause, 0,0,0,0,0,0) + XTREG( 44,176,32, 4, 4,0x02ea,0x000f,-2, 2,0x1000,ccount, 0,0,0,0,0,0) + XTREG( 45,180,32, 4, 4,0x02eb,0x0003,-2, 2,0x1000,prid, 0,0,0,0,0,0) + XTREG( 46,184,32, 4, 4,0x02ec,0x000f,-2, 2,0x1000,icount, 0,0,0,0,0,0) + XTREG( 47,188, 4, 4, 4,0x02ed,0x0007,-2, 2,0x1000,icountlevel, 0,0,0,0,0,0) + XTREG( 48,192,32, 4, 4,0x02ee,0x0007,-2, 2,0x1000,excvaddr, 0,0,0,0,0,0) + XTREG( 49,196,32, 4, 4,0x02f0,0x000f,-2, 2,0x1000,ccompare0, 0,0,0,0,0,0) + XTREG( 50,200, 4, 4, 4,0x2002,0x0006,-2, 6,0x1010,psintlevel, + 0,0,&xtensa_mask0,0,0,0) + XTREG( 51,204, 1, 4, 4,0x2003,0x0006,-2, 6,0x1010,psum, + 0,0,&xtensa_mask1,0,0,0) + XTREG( 52,208, 1, 4, 4,0x2004,0x0006,-2, 6,0x1010,psexcm, + 0,0,&xtensa_mask2,0,0,0) + XTREG( 53,212,20, 4, 4,0x2005,0x0006,-2, 6,0x1010,litbaddr, + 0,0,&xtensa_mask3,0,0,0) + XTREG( 54,216, 1, 4, 4,0x2006,0x0006,-2, 6,0x1010,litben, + 0,0,&xtensa_mask4,0,0,0) + XTREG_END diff --git a/target/xtensa/core-lx106/xtensa-modules.c.inc b/target/xtensa/core-lx106/xtensa-modules.c.inc new file mode 100644 index 000000000000..f2b5efc6ec88 --- /dev/null +++ b/target/xtensa/core-lx106/xtensa-modules.c.inc @@ -0,0 +1,7668 @@ +/* Xtensa configuration-specific ISA information. + + Copyright (c) 2003-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "xtensa-isa.h" +#include "xtensa-isa-internal.h" + + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "MMID", 89, 0 }, + { "DDR", 104, 0 }, + { "176", 176, 0 }, + { "208", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "VECBASE", 231, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "SAR", 3, 0 }, + { "LITBASE", 5, 0 }, + { "PS", 230, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 } +}; + +#define NUM_SYSREGS 32 +#define MAX_SPECIAL_REG 240 +#define MAX_USER_REG 0 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 15, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "VECBASE", 25, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EPS2", 6, 0 }, + { "EPS3", 6, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "SAR", 6, 0 }, + { "LITBADDR", 20, 0 }, + { "LITBEN", 1, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 15, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKENABLE", 1, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 } +}; + +#define NUM_STATES 34 + +enum xtensa_state_id { + STATE_PC, + STATE_ICOUNT, + STATE_DDR, + STATE_INTERRUPT, + STATE_CCOUNT, + STATE_XTSYNC, + STATE_VECBASE, + STATE_EPC1, + STATE_EPC2, + STATE_EPC3, + STATE_EXCSAVE1, + STATE_EXCSAVE2, + STATE_EXCSAVE3, + STATE_EPS2, + STATE_EPS3, + STATE_EXCCAUSE, + STATE_PSINTLEVEL, + STATE_PSUM, + STATE_PSEXCM, + STATE_DEPC, + STATE_EXCVADDR, + STATE_SAR, + STATE_LITBADDR, + STATE_LITBEN, + STATE_InOCDMode, + STATE_INTENABLE, + STATE_DBREAKA0, + STATE_DBREAKC0, + STATE_IBREAKA0, + STATE_IBREAKENABLE, + STATE_ICOUNTLEVEL, + STATE_DEBUGCAUSE, + STATE_DBNUM, + STATE_CCOMPARE0 +}; + + +/* Field definitions. */ + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 8) >> 20); + return tie_t; +} + +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff000) | (tie_t << 12); +} + +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 8) >> 16); + return tie_t; +} + +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff00) | (tie_t << 8); +} + +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + return tie_t; +} + +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; +} + +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; +} + +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_xt_wbr15_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 15) | ((insn[0] << 8) >> 17); + return tie_t; +} + +static void +Field_xt_wbr15_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 17) >> 17; + insn[0] = (insn[0] & ~0xfffe00) | (tie_t << 9); +} + +static unsigned +Field_xt_wbr18_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_xt_wbr18_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) +{ + /* Do nothing. */ +} + +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +enum xtensa_field_id { + FIELD_t, + FIELD_bbi4, + FIELD_bbi, + FIELD_imm12, + FIELD_imm8, + FIELD_s, + FIELD_imm12b, + FIELD_imm16, + FIELD_m, + FIELD_n, + FIELD_offset, + FIELD_op0, + FIELD_op1, + FIELD_op2, + FIELD_r, + FIELD_sa4, + FIELD_sae4, + FIELD_sae, + FIELD_sal, + FIELD_sargt, + FIELD_sas4, + FIELD_sas, + FIELD_sr, + FIELD_st, + FIELD_thi3, + FIELD_imm4, + FIELD_i, + FIELD_imm6lo, + FIELD_imm6hi, + FIELD_imm7lo, + FIELD_imm7hi, + FIELD_z, + FIELD_imm6, + FIELD_imm7, + FIELD_xt_wbr15_imm, + FIELD_xt_wbr18_imm, + FIELD__ar0 +}; + + +/* Functional units. */ + +static xtensa_funcUnit_internal funcUnits[] = { + +}; + + +/* Register files. */ + +enum xtensa_regfile_id { + REGFILE_AR +}; + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", REGFILE_AR, 32, 16 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + + +/* Instruction operands. */ + +static int +Operand_art_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_art_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ars_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_arr_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_arr_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ar0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_soffsetx4_decode (uint32 *valp) +{ + unsigned soffsetx4_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffsetx4_0 = 0x4 + ((((int) offset_0 << 14) >> 14) << 2); + *valp = soffsetx4_0; + return 0; +} + +static int +Operand_soffsetx4_encode (uint32 *valp) +{ + unsigned offset_0, soffsetx4_0; + soffsetx4_0 = *valp; + offset_0 = ((soffsetx4_0 - 0x4) >> 2) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) +{ + *valp -= (pc & ~0x3); + return 0; +} + +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += (pc & ~0x3); + return 0; +} + +static int +Operand_lsi4x4_decode (uint32 *valp) +{ + unsigned lsi4x4_0, r_0; + r_0 = *valp & 0xf; + lsi4x4_0 = r_0 << 2; + *valp = lsi4x4_0; + return 0; +} + +static int +Operand_lsi4x4_encode (uint32 *valp) +{ + unsigned r_0, lsi4x4_0; + lsi4x4_0 = *valp; + r_0 = ((lsi4x4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_simm7_decode (uint32 *valp) +{ + unsigned simm7_0, imm7_0; + imm7_0 = *valp & 0x7f; + simm7_0 = ((((-((((imm7_0 >> 6) & 1)) & (((imm7_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | imm7_0; + *valp = simm7_0; + return 0; +} + +static int +Operand_simm7_encode (uint32 *valp) +{ + unsigned imm7_0, simm7_0; + simm7_0 = *valp; + imm7_0 = (simm7_0 & 0x7f); + *valp = imm7_0; + return 0; +} + +static int +Operand_uimm6_decode (uint32 *valp) +{ + unsigned uimm6_0, imm6_0; + imm6_0 = *valp & 0x3f; + uimm6_0 = 0x4 + (((0) << 6) | imm6_0); + *valp = uimm6_0; + return 0; +} + +static int +Operand_uimm6_encode (uint32 *valp) +{ + unsigned imm6_0, uimm6_0; + uimm6_0 = *valp; + imm6_0 = (uimm6_0 - 0x4) & 0x3f; + *valp = imm6_0; + return 0; +} + +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ai4const_decode (uint32 *valp) +{ + unsigned ai4const_0, t_0; + t_0 = *valp & 0xf; + ai4const_0 = CONST_TBL_ai4c_0[t_0 & 0xf]; + *valp = ai4const_0; + return 0; +} + +static int +Operand_ai4const_encode (uint32 *valp) +{ + unsigned t_0, ai4const_0; + ai4const_0 = *valp; + switch (ai4const_0) + { + case 0xffffffff: t_0 = 0; break; + case 0x1: t_0 = 0x1; break; + case 0x2: t_0 = 0x2; break; + case 0x3: t_0 = 0x3; break; + case 0x4: t_0 = 0x4; break; + case 0x5: t_0 = 0x5; break; + case 0x6: t_0 = 0x6; break; + case 0x7: t_0 = 0x7; break; + case 0x8: t_0 = 0x8; break; + case 0x9: t_0 = 0x9; break; + case 0xa: t_0 = 0xa; break; + case 0xb: t_0 = 0xb; break; + case 0xc: t_0 = 0xc; break; + case 0xd: t_0 = 0xd; break; + case 0xe: t_0 = 0xe; break; + default: t_0 = 0xf; break; + } + *valp = t_0; + return 0; +} + +static int +Operand_b4const_decode (uint32 *valp) +{ + unsigned b4const_0, r_0; + r_0 = *valp & 0xf; + b4const_0 = CONST_TBL_b4c_0[r_0 & 0xf]; + *valp = b4const_0; + return 0; +} + +static int +Operand_b4const_encode (uint32 *valp) +{ + unsigned r_0, b4const_0; + b4const_0 = *valp; + switch (b4const_0) + { + case 0xffffffff: r_0 = 0; break; + case 0x1: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_b4constu_decode (uint32 *valp) +{ + unsigned b4constu_0, r_0; + r_0 = *valp & 0xf; + b4constu_0 = CONST_TBL_b4cu_0[r_0 & 0xf]; + *valp = b4constu_0; + return 0; +} + +static int +Operand_b4constu_encode (uint32 *valp) +{ + unsigned r_0, b4constu_0; + b4constu_0 = *valp; + switch (b4constu_0) + { + case 0x8000: r_0 = 0; break; + case 0x10000: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_uimm8_decode (uint32 *valp) +{ + unsigned uimm8_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8_0 = imm8_0; + *valp = uimm8_0; + return 0; +} + +static int +Operand_uimm8_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8_0; + uimm8_0 = *valp; + imm8_0 = (uimm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x2_decode (uint32 *valp) +{ + unsigned uimm8x2_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x2_0 = imm8_0 << 1; + *valp = uimm8x2_0; + return 0; +} + +static int +Operand_uimm8x2_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x2_0; + uimm8x2_0 = *valp; + imm8_0 = ((uimm8x2_0 >> 1) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x4_decode (uint32 *valp) +{ + unsigned uimm8x4_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x4_0 = imm8_0 << 2; + *valp = uimm8x4_0; + return 0; +} + +static int +Operand_uimm8x4_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x4_0; + uimm8x4_0 = *valp; + imm8_0 = ((uimm8x4_0 >> 2) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm4x16_decode (uint32 *valp) +{ + unsigned uimm4x16_0, op2_0; + op2_0 = *valp & 0xf; + uimm4x16_0 = op2_0 << 4; + *valp = uimm4x16_0; + return 0; +} + +static int +Operand_uimm4x16_encode (uint32 *valp) +{ + unsigned op2_0, uimm4x16_0; + uimm4x16_0 = *valp; + op2_0 = ((uimm4x16_0 >> 4) & 0xf); + *valp = op2_0; + return 0; +} + +static int +Operand_simm8_decode (uint32 *valp) +{ + unsigned simm8_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8_0 = ((int) imm8_0 << 24) >> 24; + *valp = simm8_0; + return 0; +} + +static int +Operand_simm8_encode (uint32 *valp) +{ + unsigned imm8_0, simm8_0; + simm8_0 = *valp; + imm8_0 = (simm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm8x256_decode (uint32 *valp) +{ + unsigned simm8x256_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8x256_0 = (((int) imm8_0 << 24) >> 24) << 8; + *valp = simm8x256_0; + return 0; +} + +static int +Operand_simm8x256_encode (uint32 *valp) +{ + unsigned imm8_0, simm8x256_0; + simm8x256_0 = *valp; + imm8_0 = ((simm8x256_0 >> 8) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm12b_decode (uint32 *valp) +{ + unsigned simm12b_0, imm12b_0; + imm12b_0 = *valp & 0xfff; + simm12b_0 = ((int) imm12b_0 << 20) >> 20; + *valp = simm12b_0; + return 0; +} + +static int +Operand_simm12b_encode (uint32 *valp) +{ + unsigned imm12b_0, simm12b_0; + simm12b_0 = *valp; + imm12b_0 = (simm12b_0 & 0xfff); + *valp = imm12b_0; + return 0; +} + +static int +Operand_msalp32_decode (uint32 *valp) +{ + unsigned msalp32_0, sal_0; + sal_0 = *valp & 0x1f; + msalp32_0 = 0x20 - sal_0; + *valp = msalp32_0; + return 0; +} + +static int +Operand_msalp32_encode (uint32 *valp) +{ + unsigned sal_0, msalp32_0; + msalp32_0 = *valp; + sal_0 = (0x20 - msalp32_0) & 0x1f; + *valp = sal_0; + return 0; +} + +static int +Operand_op2p1_decode (uint32 *valp) +{ + unsigned op2p1_0, op2_0; + op2_0 = *valp & 0xf; + op2p1_0 = op2_0 + 0x1; + *valp = op2p1_0; + return 0; +} + +static int +Operand_op2p1_encode (uint32 *valp) +{ + unsigned op2_0, op2p1_0; + op2p1_0 = *valp; + op2_0 = (op2p1_0 - 0x1) & 0xf; + *valp = op2_0; + return 0; +} + +static int +Operand_label8_decode (uint32 *valp) +{ + unsigned label8_0, imm8_0; + imm8_0 = *valp & 0xff; + label8_0 = 0x4 + (((int) imm8_0 << 24) >> 24); + *valp = label8_0; + return 0; +} + +static int +Operand_label8_encode (uint32 *valp) +{ + unsigned imm8_0, label8_0; + label8_0 = *valp; + imm8_0 = (label8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_label8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label12_decode (uint32 *valp) +{ + unsigned label12_0, imm12_0; + imm12_0 = *valp & 0xfff; + label12_0 = 0x4 + (((int) imm12_0 << 20) >> 20); + *valp = label12_0; + return 0; +} + +static int +Operand_label12_encode (uint32 *valp) +{ + unsigned imm12_0, label12_0; + label12_0 = *valp; + imm12_0 = (label12_0 - 0x4) & 0xfff; + *valp = imm12_0; + return 0; +} + +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_soffset_decode (uint32 *valp) +{ + unsigned soffset_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffset_0 = 0x4 + (((int) offset_0 << 14) >> 14); + *valp = soffset_0; + return 0; +} + +static int +Operand_soffset_encode (uint32 *valp) +{ + unsigned offset_0, soffset_0; + soffset_0 = *valp; + offset_0 = (soffset_0 - 0x4) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_uimm16x4_decode (uint32 *valp) +{ + unsigned uimm16x4_0, imm16_0; + imm16_0 = *valp & 0xffff; + uimm16x4_0 = (((0xffff) << 16) | imm16_0) << 2; + *valp = uimm16x4_0; + return 0; +} + +static int +Operand_uimm16x4_encode (uint32 *valp) +{ + unsigned imm16_0, uimm16x4_0; + uimm16x4_0 = *valp; + imm16_0 = (uimm16x4_0 >> 2) & 0xffff; + *valp = imm16_0; + return 0; +} + +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) +{ + *valp -= ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_immt_decode (uint32 *valp) +{ + unsigned immt_0, t_0; + t_0 = *valp & 0xf; + immt_0 = t_0; + *valp = immt_0; + return 0; +} + +static int +Operand_immt_encode (uint32 *valp) +{ + unsigned t_0, immt_0; + immt_0 = *valp; + t_0 = immt_0 & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_imms_decode (uint32 *valp) +{ + unsigned imms_0, s_0; + s_0 = *valp & 0xf; + imms_0 = s_0; + *valp = imms_0; + return 0; +} + +static int +Operand_imms_encode (uint32 *valp) +{ + unsigned s_0, imms_0; + imms_0 = *valp; + s_0 = imms_0 & 0xf; + *valp = s_0; + return 0; +} + +static int +Operand_xt_wbr15_label_decode (uint32 *valp) +{ + unsigned xt_wbr15_label_0, xt_wbr15_imm_0; + xt_wbr15_imm_0 = *valp & 0x7fff; + xt_wbr15_label_0 = 0x4 + (((int) xt_wbr15_imm_0 << 17) >> 17); + *valp = xt_wbr15_label_0; + return 0; +} + +static int +Operand_xt_wbr15_label_encode (uint32 *valp) +{ + unsigned xt_wbr15_imm_0, xt_wbr15_label_0; + xt_wbr15_label_0 = *valp; + xt_wbr15_imm_0 = (xt_wbr15_label_0 - 0x4) & 0x7fff; + *valp = xt_wbr15_imm_0; + return 0; +} + +static int +Operand_xt_wbr15_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr15_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_xt_wbr18_label_decode (uint32 *valp) +{ + unsigned xt_wbr18_label_0, xt_wbr18_imm_0; + xt_wbr18_imm_0 = *valp & 0x3ffff; + xt_wbr18_label_0 = 0x4 + (((int) xt_wbr18_imm_0 << 14) >> 14); + *valp = xt_wbr18_label_0; + return 0; +} + +static int +Operand_xt_wbr18_label_encode (uint32 *valp) +{ + unsigned xt_wbr18_imm_0, xt_wbr18_label_0; + xt_wbr18_label_0 = *valp; + xt_wbr18_imm_0 = (xt_wbr18_label_0 - 0x4) & 0x3ffff; + *valp = xt_wbr18_imm_0; + return 0; +} + +static int +Operand_xt_wbr18_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr18_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "art", FIELD_t, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_art_encode, Operand_art_decode, + 0, 0 }, + { "ars", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "*ars_invisible", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "arr", FIELD_r, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_arr_encode, Operand_arr_decode, + 0, 0 }, + { "ar0", FIELD__ar0, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar0_encode, Operand_ar0_decode, + 0, 0 }, + { "soffsetx4", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffsetx4_encode, Operand_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "lsi4x4", FIELD_r, -1, 0, + 0, + Operand_lsi4x4_encode, Operand_lsi4x4_decode, + 0, 0 }, + { "simm7", FIELD_imm7, -1, 0, + 0, + Operand_simm7_encode, Operand_simm7_decode, + 0, 0 }, + { "uimm6", FIELD_imm6, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm6_encode, Operand_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", FIELD_t, -1, 0, + 0, + Operand_ai4const_encode, Operand_ai4const_decode, + 0, 0 }, + { "b4const", FIELD_r, -1, 0, + 0, + Operand_b4const_encode, Operand_b4const_decode, + 0, 0 }, + { "b4constu", FIELD_r, -1, 0, + 0, + Operand_b4constu_encode, Operand_b4constu_decode, + 0, 0 }, + { "uimm8", FIELD_imm8, -1, 0, + 0, + Operand_uimm8_encode, Operand_uimm8_decode, + 0, 0 }, + { "uimm8x2", FIELD_imm8, -1, 0, + 0, + Operand_uimm8x2_encode, Operand_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", FIELD_imm8, -1, 0, + 0, + Operand_uimm8x4_encode, Operand_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", FIELD_op2, -1, 0, + 0, + Operand_uimm4x16_encode, Operand_uimm4x16_decode, + 0, 0 }, + { "simm8", FIELD_imm8, -1, 0, + 0, + Operand_simm8_encode, Operand_simm8_decode, + 0, 0 }, + { "simm8x256", FIELD_imm8, -1, 0, + 0, + Operand_simm8x256_encode, Operand_simm8x256_decode, + 0, 0 }, + { "simm12b", FIELD_imm12b, -1, 0, + 0, + Operand_simm12b_encode, Operand_simm12b_decode, + 0, 0 }, + { "msalp32", FIELD_sal, -1, 0, + 0, + Operand_msalp32_encode, Operand_msalp32_decode, + 0, 0 }, + { "op2p1", FIELD_op2, -1, 0, + 0, + Operand_op2p1_encode, Operand_op2p1_decode, + 0, 0 }, + { "label8", FIELD_imm8, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label8_encode, Operand_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "label12", FIELD_imm12, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label12_encode, Operand_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffset_encode, Operand_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", FIELD_imm16, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm16x4_encode, Operand_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "immt", FIELD_t, -1, 0, + 0, + Operand_immt_encode, Operand_immt_decode, + 0, 0 }, + { "imms", FIELD_s, -1, 0, + 0, + Operand_imms_encode, Operand_imms_decode, + 0, 0 }, + { "xt_wbr15_label", FIELD_xt_wbr15_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr15_label_encode, Operand_xt_wbr15_label_decode, + Operand_xt_wbr15_label_ator, Operand_xt_wbr15_label_rtoa }, + { "xt_wbr18_label", FIELD_xt_wbr18_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr18_label_encode, Operand_xt_wbr18_label_decode, + Operand_xt_wbr18_label_ator, Operand_xt_wbr18_label_rtoa }, + { "t", FIELD_t, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", FIELD_bbi4, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi", FIELD_bbi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", FIELD_imm12, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", FIELD_imm8, -1, 0, 0, 0, 0, 0, 0 }, + { "s", FIELD_s, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", FIELD_imm12b, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", FIELD_imm16, -1, 0, 0, 0, 0, 0, 0 }, + { "m", FIELD_m, -1, 0, 0, 0, 0, 0, 0 }, + { "n", FIELD_n, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", FIELD_offset, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", FIELD_op0, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", FIELD_op1, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", FIELD_op2, -1, 0, 0, 0, 0, 0, 0 }, + { "r", FIELD_r, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", FIELD_sa4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", FIELD_sae4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae", FIELD_sae, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", FIELD_sal, -1, 0, 0, 0, 0, 0, 0 }, + { "sargt", FIELD_sargt, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", FIELD_sas4, -1, 0, 0, 0, 0, 0, 0 }, + { "sas", FIELD_sas, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", FIELD_sr, -1, 0, 0, 0, 0, 0, 0 }, + { "st", FIELD_st, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", FIELD_thi3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", FIELD_imm4, -1, 0, 0, 0, 0, 0, 0 }, + { "i", FIELD_i, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", FIELD_imm6lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", FIELD_imm6hi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", FIELD_imm7lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", FIELD_imm7hi, -1, 0, 0, 0, 0, 0, 0 }, + { "z", FIELD_z, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", FIELD_imm6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", FIELD_imm7, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr15_imm", FIELD_xt_wbr15_imm, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr18_imm", FIELD_xt_wbr18_imm, -1, 0, 0, 0, 0, 0, 0 } +}; + +enum xtensa_operand_id { + OPERAND_art, + OPERAND_ars, + OPERAND__ars_invisible, + OPERAND_arr, + OPERAND_ar0, + OPERAND_soffsetx4, + OPERAND_lsi4x4, + OPERAND_simm7, + OPERAND_uimm6, + OPERAND_ai4const, + OPERAND_b4const, + OPERAND_b4constu, + OPERAND_uimm8, + OPERAND_uimm8x2, + OPERAND_uimm8x4, + OPERAND_uimm4x16, + OPERAND_simm8, + OPERAND_simm8x256, + OPERAND_simm12b, + OPERAND_msalp32, + OPERAND_op2p1, + OPERAND_label8, + OPERAND_label12, + OPERAND_soffset, + OPERAND_uimm16x4, + OPERAND_immt, + OPERAND_imms, + OPERAND_xt_wbr15_label, + OPERAND_xt_wbr18_label, + OPERAND_t, + OPERAND_bbi4, + OPERAND_bbi, + OPERAND_imm12, + OPERAND_imm8, + OPERAND_s, + OPERAND_imm12b, + OPERAND_imm16, + OPERAND_m, + OPERAND_n, + OPERAND_offset, + OPERAND_op0, + OPERAND_op1, + OPERAND_op2, + OPERAND_r, + OPERAND_sa4, + OPERAND_sae4, + OPERAND_sae, + OPERAND_sal, + OPERAND_sargt, + OPERAND_sas4, + OPERAND_sas, + OPERAND_sr, + OPERAND_st, + OPERAND_thi3, + OPERAND_imm4, + OPERAND_i, + OPERAND_imm6lo, + OPERAND_imm6hi, + OPERAND_imm7lo, + OPERAND_imm7hi, + OPERAND_z, + OPERAND_imm6, + OPERAND_imm7, + OPERAND_xt_wbr15_imm, + OPERAND_xt_wbr18_imm +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSEXCM }, 'o' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_ai4const }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { OPERAND_ars }, 'o' }, + { { OPERAND_simm7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8x256 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4const }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_bbi }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4constu }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_label12 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sae }, 'i' }, + { { OPERAND_op2p1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { OPERAND_soffset }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_uimm16x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_simm12b }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { OPERAND_arr }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { OPERAND_sas }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_msalp32 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sargt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'o' }, + { { STATE_LITBEN }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'm' }, + { { STATE_LITBEN }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_176_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_mul16_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_mul32_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { OPERAND_imms }, 'i' }, + { { OPERAND_immt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 2, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 1, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 2, Iclass_xt_iclass_l32r_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 3, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 2, Iclass_xt_iclass_rsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 2, Iclass_xt_iclass_wsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 2, Iclass_xt_iclass_xsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_176_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_176_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_208_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 3, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 3, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 3, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 1, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 1, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 1, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 1, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 1, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 1, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 1, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 1, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 1, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 1, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 1, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 1, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 1, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 1, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 1, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 1, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 1, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 1, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 1, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 1, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 1, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 1, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 1, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 1, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 1, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 1, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 1, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 1, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 1, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 1, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 2, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 1, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 1, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_vecbase_args, + 1, Iclass_xt_iclass_rsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_vecbase_args, + 1, Iclass_xt_iclass_wsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_vecbase_args, + 1, Iclass_xt_iclass_xsr_vecbase_stateArgs, 0, 0 }, + { 3, Iclass_xt_mul16_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_mul32_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 9, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 1, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 1, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 2, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 2, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 1, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 1, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 1, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 1, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 2, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 2, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 1, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 2, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 2, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 1, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 1, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 1, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 1, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 1, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 1, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 2, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 2, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 2, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 1, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 2, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 2, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 1, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 1, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 1, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 1, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 2, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 2, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfdo_args, + 6, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_mmid_args, + 1, Iclass_xt_iclass_wsr_mmid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 1, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 2, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 2, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 1, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 2, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 2, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 1, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 1, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rer */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_wer */, + 0, 0, 0, 0 } +}; + +enum xtensa_iclass_id { + ICLASS_xt_iclass_excw, + ICLASS_xt_iclass_rfe, + ICLASS_xt_iclass_rfde, + ICLASS_xt_iclass_syscall, + ICLASS_xt_iclass_simcall, + ICLASS_xt_iclass_add_n, + ICLASS_xt_iclass_addi_n, + ICLASS_xt_iclass_bz6, + ICLASS_xt_iclass_ill_n, + ICLASS_xt_iclass_loadi4, + ICLASS_xt_iclass_mov_n, + ICLASS_xt_iclass_movi_n, + ICLASS_xt_iclass_nopn, + ICLASS_xt_iclass_retn, + ICLASS_xt_iclass_storei4, + ICLASS_xt_iclass_addi, + ICLASS_xt_iclass_addmi, + ICLASS_xt_iclass_addsub, + ICLASS_xt_iclass_bit, + ICLASS_xt_iclass_bsi8, + ICLASS_xt_iclass_bsi8b, + ICLASS_xt_iclass_bsi8u, + ICLASS_xt_iclass_bst8, + ICLASS_xt_iclass_bsz12, + ICLASS_xt_iclass_call0, + ICLASS_xt_iclass_callx0, + ICLASS_xt_iclass_exti, + ICLASS_xt_iclass_ill, + ICLASS_xt_iclass_jump, + ICLASS_xt_iclass_jumpx, + ICLASS_xt_iclass_l16ui, + ICLASS_xt_iclass_l16si, + ICLASS_xt_iclass_l32i, + ICLASS_xt_iclass_l32r, + ICLASS_xt_iclass_l8i, + ICLASS_xt_iclass_movi, + ICLASS_xt_iclass_movz, + ICLASS_xt_iclass_neg, + ICLASS_xt_iclass_nop, + ICLASS_xt_iclass_return, + ICLASS_xt_iclass_s16i, + ICLASS_xt_iclass_s32i, + ICLASS_xt_iclass_s8i, + ICLASS_xt_iclass_sar, + ICLASS_xt_iclass_sari, + ICLASS_xt_iclass_shifts, + ICLASS_xt_iclass_shiftst, + ICLASS_xt_iclass_shiftt, + ICLASS_xt_iclass_slli, + ICLASS_xt_iclass_srai, + ICLASS_xt_iclass_srli, + ICLASS_xt_iclass_memw, + ICLASS_xt_iclass_extw, + ICLASS_xt_iclass_isync, + ICLASS_xt_iclass_sync, + ICLASS_xt_iclass_rsil, + ICLASS_xt_iclass_rsr_sar, + ICLASS_xt_iclass_wsr_sar, + ICLASS_xt_iclass_xsr_sar, + ICLASS_xt_iclass_rsr_litbase, + ICLASS_xt_iclass_wsr_litbase, + ICLASS_xt_iclass_xsr_litbase, + ICLASS_xt_iclass_rsr_176, + ICLASS_xt_iclass_wsr_176, + ICLASS_xt_iclass_rsr_208, + ICLASS_xt_iclass_rsr_ps, + ICLASS_xt_iclass_wsr_ps, + ICLASS_xt_iclass_xsr_ps, + ICLASS_xt_iclass_rsr_epc1, + ICLASS_xt_iclass_wsr_epc1, + ICLASS_xt_iclass_xsr_epc1, + ICLASS_xt_iclass_rsr_excsave1, + ICLASS_xt_iclass_wsr_excsave1, + ICLASS_xt_iclass_xsr_excsave1, + ICLASS_xt_iclass_rsr_epc2, + ICLASS_xt_iclass_wsr_epc2, + ICLASS_xt_iclass_xsr_epc2, + ICLASS_xt_iclass_rsr_excsave2, + ICLASS_xt_iclass_wsr_excsave2, + ICLASS_xt_iclass_xsr_excsave2, + ICLASS_xt_iclass_rsr_epc3, + ICLASS_xt_iclass_wsr_epc3, + ICLASS_xt_iclass_xsr_epc3, + ICLASS_xt_iclass_rsr_excsave3, + ICLASS_xt_iclass_wsr_excsave3, + ICLASS_xt_iclass_xsr_excsave3, + ICLASS_xt_iclass_rsr_eps2, + ICLASS_xt_iclass_wsr_eps2, + ICLASS_xt_iclass_xsr_eps2, + ICLASS_xt_iclass_rsr_eps3, + ICLASS_xt_iclass_wsr_eps3, + ICLASS_xt_iclass_xsr_eps3, + ICLASS_xt_iclass_rsr_excvaddr, + ICLASS_xt_iclass_wsr_excvaddr, + ICLASS_xt_iclass_xsr_excvaddr, + ICLASS_xt_iclass_rsr_depc, + ICLASS_xt_iclass_wsr_depc, + ICLASS_xt_iclass_xsr_depc, + ICLASS_xt_iclass_rsr_exccause, + ICLASS_xt_iclass_wsr_exccause, + ICLASS_xt_iclass_xsr_exccause, + ICLASS_xt_iclass_rsr_prid, + ICLASS_xt_iclass_rsr_vecbase, + ICLASS_xt_iclass_wsr_vecbase, + ICLASS_xt_iclass_xsr_vecbase, + ICLASS_xt_mul16, + ICLASS_xt_mul32, + ICLASS_xt_iclass_rfi, + ICLASS_xt_iclass_wait, + ICLASS_xt_iclass_rsr_interrupt, + ICLASS_xt_iclass_wsr_intset, + ICLASS_xt_iclass_wsr_intclear, + ICLASS_xt_iclass_rsr_intenable, + ICLASS_xt_iclass_wsr_intenable, + ICLASS_xt_iclass_xsr_intenable, + ICLASS_xt_iclass_break, + ICLASS_xt_iclass_break_n, + ICLASS_xt_iclass_rsr_dbreaka0, + ICLASS_xt_iclass_wsr_dbreaka0, + ICLASS_xt_iclass_xsr_dbreaka0, + ICLASS_xt_iclass_rsr_dbreakc0, + ICLASS_xt_iclass_wsr_dbreakc0, + ICLASS_xt_iclass_xsr_dbreakc0, + ICLASS_xt_iclass_rsr_ibreaka0, + ICLASS_xt_iclass_wsr_ibreaka0, + ICLASS_xt_iclass_xsr_ibreaka0, + ICLASS_xt_iclass_rsr_ibreakenable, + ICLASS_xt_iclass_wsr_ibreakenable, + ICLASS_xt_iclass_xsr_ibreakenable, + ICLASS_xt_iclass_rsr_debugcause, + ICLASS_xt_iclass_wsr_debugcause, + ICLASS_xt_iclass_xsr_debugcause, + ICLASS_xt_iclass_rsr_icount, + ICLASS_xt_iclass_wsr_icount, + ICLASS_xt_iclass_xsr_icount, + ICLASS_xt_iclass_rsr_icountlevel, + ICLASS_xt_iclass_wsr_icountlevel, + ICLASS_xt_iclass_xsr_icountlevel, + ICLASS_xt_iclass_rsr_ddr, + ICLASS_xt_iclass_wsr_ddr, + ICLASS_xt_iclass_xsr_ddr, + ICLASS_xt_iclass_rfdo, + ICLASS_xt_iclass_rfdd, + ICLASS_xt_iclass_wsr_mmid, + ICLASS_xt_iclass_rsr_ccount, + ICLASS_xt_iclass_wsr_ccount, + ICLASS_xt_iclass_xsr_ccount, + ICLASS_xt_iclass_rsr_ccompare0, + ICLASS_xt_iclass_wsr_ccompare0, + ICLASS_xt_iclass_xsr_ccompare0, + ICLASS_xt_iclass_idtlb, + ICLASS_xt_iclass_rdtlb, + ICLASS_xt_iclass_wdtlb, + ICLASS_xt_iclass_iitlb, + ICLASS_xt_iclass_ritlb, + ICLASS_xt_iclass_witlb, + ICLASS_xt_iclass_nsa, + ICLASS_xt_iclass_rer, + ICLASS_xt_iclass_wer +}; + + +/* Opcode encodings. */ + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2080; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3000; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3200; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5000; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5100; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8c; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf06d; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf03d; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00d; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc002; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd002; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800000; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc00000; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900000; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa00000; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb00000; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00000; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe00000; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00000; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300000; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x26; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x66; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe6; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa6; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6007; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe007; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf6; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb6; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1007; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9007; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa007; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2007; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb007; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3007; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8007; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4007; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc007; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5007; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd007; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x56; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd6; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x96; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40000; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1002; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9002; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2002; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa002; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x830000; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x930000; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa30000; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb30000; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600100; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20f0; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5002; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6002; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4002; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x400000; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x401000; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x402000; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x403000; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404000; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa10000; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x810000; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x910000; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb10000; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10000; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x210000; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x410000; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20c0; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20d0; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2000; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2010; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2020; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2030; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6000; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30300; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130300; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610300; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30500; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130500; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610500; +} + +static void +Opcode_rsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b000; +} + +static void +Opcode_wsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b000; +} + +static void +Opcode_rsr_208_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d000; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e600; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e600; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e600; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b100; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b100; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b100; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d100; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d100; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d100; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b200; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b200; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b200; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d200; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d200; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d200; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b300; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b300; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b300; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d300; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d300; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d300; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c200; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c200; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c200; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c300; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c300; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c300; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ee00; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ee00; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ee00; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c000; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c000; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c000; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e800; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e800; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e800; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3eb00; +} + +static void +Opcode_rsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e700; +} + +static void +Opcode_wsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e700; +} + +static void +Opcode_xsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e700; +} + +static void +Opcode_mul16u_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc10000; +} + +static void +Opcode_mul16s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10000; +} + +static void +Opcode_mull_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x820000; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3010; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7000; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e200; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e200; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e300; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e400; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e400; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e400; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4000; +} + +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf02d; +} + +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39000; +} + +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139000; +} + +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619000; +} + +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a000; +} + +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a000; +} + +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a000; +} + +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38000; +} + +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138000; +} + +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618000; +} + +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36000; +} + +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136000; +} + +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616000; +} + +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e900; +} + +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e900; +} + +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e900; +} + +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ec00; +} + +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ec00; +} + +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ec00; +} + +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ed00; +} + +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ed00; +} + +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ed00; +} + +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36800; +} + +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136800; +} + +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616800; +} + +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e000; +} + +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e010; +} + +static void +Opcode_wsr_mmid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135900; +} + +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ea00; +} + +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ea00; +} + +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ea00; +} + +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f000; +} + +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f000; +} + +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f000; +} + +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50c000; +} + +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50d000; +} + +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50b000; +} + +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50f000; +} + +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50e000; +} + +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x504000; +} + +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x505000; +} + +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x503000; +} + +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x507000; +} + +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x506000; +} + +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40e000; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40f000; +} + +static void +Opcode_rer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x406000; +} + +static void +Opcode_wer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x407000; +} + +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { + Opcode_rsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_176_encode_fns[] = { + Opcode_wsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { + Opcode_rsr_208_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { + Opcode_rsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { + Opcode_wsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { + Opcode_xsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { + Opcode_mul16u_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { + Opcode_mul16s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { + Opcode_mull_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_mmid_encode_fns[] = { + Opcode_wsr_mmid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rer_encode_fns[] = { + Opcode_rer_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wer_encode_fns[] = { + Opcode_wer_Slot_inst_encode, 0, 0 +}; + + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "excw", ICLASS_xt_iclass_excw, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", ICLASS_xt_iclass_rfe, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", ICLASS_xt_iclass_rfde, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", ICLASS_xt_iclass_syscall, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "simcall", ICLASS_xt_iclass_simcall, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "add.n", ICLASS_xt_iclass_add_n, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", ICLASS_xt_iclass_addi_n, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", ICLASS_xt_iclass_ill_n, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", ICLASS_xt_iclass_loadi4, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", ICLASS_xt_iclass_mov_n, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", ICLASS_xt_iclass_movi_n, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", ICLASS_xt_iclass_nopn, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", ICLASS_xt_iclass_retn, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", ICLASS_xt_iclass_storei4, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "addi", ICLASS_xt_iclass_addi, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", ICLASS_xt_iclass_addmi, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", ICLASS_xt_iclass_addsub, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", ICLASS_xt_iclass_addsub, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", ICLASS_xt_iclass_bit, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", ICLASS_xt_iclass_bit, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", ICLASS_xt_iclass_bit, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", ICLASS_xt_iclass_call0, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", ICLASS_xt_iclass_callx0, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", ICLASS_xt_iclass_exti, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", ICLASS_xt_iclass_ill, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", ICLASS_xt_iclass_jump, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", ICLASS_xt_iclass_jumpx, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", ICLASS_xt_iclass_l16ui, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", ICLASS_xt_iclass_l16si, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", ICLASS_xt_iclass_l32i, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", ICLASS_xt_iclass_l32r, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", ICLASS_xt_iclass_l8i, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "movi", ICLASS_xt_iclass_movi, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", ICLASS_xt_iclass_movz, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", ICLASS_xt_iclass_movz, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", ICLASS_xt_iclass_movz, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", ICLASS_xt_iclass_movz, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", ICLASS_xt_iclass_neg, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", ICLASS_xt_iclass_neg, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", ICLASS_xt_iclass_nop, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", ICLASS_xt_iclass_return, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "s16i", ICLASS_xt_iclass_s16i, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", ICLASS_xt_iclass_s32i, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s8i", ICLASS_xt_iclass_s8i, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", ICLASS_xt_iclass_sar, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", ICLASS_xt_iclass_sar, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", ICLASS_xt_iclass_sari, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", ICLASS_xt_iclass_shifts, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", ICLASS_xt_iclass_shiftst, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", ICLASS_xt_iclass_shiftt, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", ICLASS_xt_iclass_shiftt, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", ICLASS_xt_iclass_slli, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", ICLASS_xt_iclass_srai, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", ICLASS_xt_iclass_srli, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", ICLASS_xt_iclass_memw, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", ICLASS_xt_iclass_extw, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", ICLASS_xt_iclass_isync, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", ICLASS_xt_iclass_sync, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", ICLASS_xt_iclass_sync, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", ICLASS_xt_iclass_sync, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", ICLASS_xt_iclass_rsil, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.sar", ICLASS_xt_iclass_rsr_sar, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", ICLASS_xt_iclass_wsr_sar, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", ICLASS_xt_iclass_xsr_sar, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.litbase", ICLASS_xt_iclass_rsr_litbase, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", ICLASS_xt_iclass_wsr_litbase, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", ICLASS_xt_iclass_xsr_litbase, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.176", ICLASS_xt_iclass_rsr_176, + 0, + Opcode_rsr_176_encode_fns, 0, 0 }, + { "wsr.176", ICLASS_xt_iclass_wsr_176, + 0, + Opcode_wsr_176_encode_fns, 0, 0 }, + { "rsr.208", ICLASS_xt_iclass_rsr_208, + 0, + Opcode_rsr_208_encode_fns, 0, 0 }, + { "rsr.ps", ICLASS_xt_iclass_rsr_ps, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", ICLASS_xt_iclass_wsr_ps, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", ICLASS_xt_iclass_xsr_ps, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", ICLASS_xt_iclass_rsr_epc1, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", ICLASS_xt_iclass_wsr_epc1, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", ICLASS_xt_iclass_xsr_epc1, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", ICLASS_xt_iclass_rsr_excsave1, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", ICLASS_xt_iclass_wsr_excsave1, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", ICLASS_xt_iclass_xsr_excsave1, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", ICLASS_xt_iclass_rsr_epc2, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", ICLASS_xt_iclass_wsr_epc2, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", ICLASS_xt_iclass_xsr_epc2, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", ICLASS_xt_iclass_rsr_excsave2, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", ICLASS_xt_iclass_wsr_excsave2, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", ICLASS_xt_iclass_xsr_excsave2, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", ICLASS_xt_iclass_rsr_epc3, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", ICLASS_xt_iclass_wsr_epc3, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", ICLASS_xt_iclass_xsr_epc3, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", ICLASS_xt_iclass_rsr_excsave3, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", ICLASS_xt_iclass_wsr_excsave3, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", ICLASS_xt_iclass_xsr_excsave3, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.eps2", ICLASS_xt_iclass_rsr_eps2, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", ICLASS_xt_iclass_wsr_eps2, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", ICLASS_xt_iclass_xsr_eps2, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", ICLASS_xt_iclass_rsr_eps3, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", ICLASS_xt_iclass_wsr_eps3, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", ICLASS_xt_iclass_xsr_eps3, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.excvaddr", ICLASS_xt_iclass_rsr_excvaddr, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", ICLASS_xt_iclass_wsr_excvaddr, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", ICLASS_xt_iclass_xsr_excvaddr, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", ICLASS_xt_iclass_rsr_depc, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", ICLASS_xt_iclass_wsr_depc, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", ICLASS_xt_iclass_xsr_depc, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", ICLASS_xt_iclass_rsr_exccause, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", ICLASS_xt_iclass_wsr_exccause, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", ICLASS_xt_iclass_xsr_exccause, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.prid", ICLASS_xt_iclass_rsr_prid, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rsr.vecbase", ICLASS_xt_iclass_rsr_vecbase, + 0, + Opcode_rsr_vecbase_encode_fns, 0, 0 }, + { "wsr.vecbase", ICLASS_xt_iclass_wsr_vecbase, + 0, + Opcode_wsr_vecbase_encode_fns, 0, 0 }, + { "xsr.vecbase", ICLASS_xt_iclass_xsr_vecbase, + 0, + Opcode_xsr_vecbase_encode_fns, 0, 0 }, + { "mul16u", ICLASS_xt_mul16, + 0, + Opcode_mul16u_encode_fns, 0, 0 }, + { "mul16s", ICLASS_xt_mul16, + 0, + Opcode_mul16s_encode_fns, 0, 0 }, + { "mull", ICLASS_xt_mul32, + 0, + Opcode_mull_encode_fns, 0, 0 }, + { "rfi", ICLASS_xt_iclass_rfi, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", ICLASS_xt_iclass_wait, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", ICLASS_xt_iclass_rsr_interrupt, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", ICLASS_xt_iclass_wsr_intset, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", ICLASS_xt_iclass_wsr_intclear, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", ICLASS_xt_iclass_rsr_intenable, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", ICLASS_xt_iclass_wsr_intenable, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", ICLASS_xt_iclass_xsr_intenable, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", ICLASS_xt_iclass_break, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", ICLASS_xt_iclass_break_n, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", ICLASS_xt_iclass_rsr_dbreaka0, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", ICLASS_xt_iclass_wsr_dbreaka0, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", ICLASS_xt_iclass_xsr_dbreaka0, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", ICLASS_xt_iclass_rsr_dbreakc0, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", ICLASS_xt_iclass_wsr_dbreakc0, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", ICLASS_xt_iclass_xsr_dbreakc0, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.ibreaka0", ICLASS_xt_iclass_rsr_ibreaka0, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", ICLASS_xt_iclass_wsr_ibreaka0, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", ICLASS_xt_iclass_xsr_ibreaka0, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreakenable", ICLASS_xt_iclass_rsr_ibreakenable, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", ICLASS_xt_iclass_wsr_ibreakenable, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", ICLASS_xt_iclass_xsr_ibreakenable, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", ICLASS_xt_iclass_rsr_debugcause, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", ICLASS_xt_iclass_wsr_debugcause, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", ICLASS_xt_iclass_xsr_debugcause, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", ICLASS_xt_iclass_rsr_icount, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", ICLASS_xt_iclass_wsr_icount, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", ICLASS_xt_iclass_xsr_icount, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", ICLASS_xt_iclass_rsr_icountlevel, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", ICLASS_xt_iclass_wsr_icountlevel, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", ICLASS_xt_iclass_xsr_icountlevel, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", ICLASS_xt_iclass_rsr_ddr, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", ICLASS_xt_iclass_wsr_ddr, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", ICLASS_xt_iclass_xsr_ddr, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "rfdo", ICLASS_xt_iclass_rfdo, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", ICLASS_xt_iclass_rfdd, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "wsr.mmid", ICLASS_xt_iclass_wsr_mmid, + 0, + Opcode_wsr_mmid_encode_fns, 0, 0 }, + { "rsr.ccount", ICLASS_xt_iclass_rsr_ccount, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", ICLASS_xt_iclass_wsr_ccount, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", ICLASS_xt_iclass_xsr_ccount, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", ICLASS_xt_iclass_rsr_ccompare0, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", ICLASS_xt_iclass_wsr_ccompare0, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", ICLASS_xt_iclass_xsr_ccompare0, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "idtlb", ICLASS_xt_iclass_idtlb, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", ICLASS_xt_iclass_wdtlb, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", ICLASS_xt_iclass_iitlb, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", ICLASS_xt_iclass_ritlb, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", ICLASS_xt_iclass_witlb, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "nsa", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsau_encode_fns, 0, 0 }, + { "rer", ICLASS_xt_iclass_rer, + 0, + Opcode_rer_encode_fns, 0, 0 }, + { "wer", ICLASS_xt_iclass_wer, + 0, + Opcode_wer_encode_fns, 0, 0 } +}; + +enum xtensa_opcode_id { + OPCODE_EXCW, + OPCODE_RFE, + OPCODE_RFDE, + OPCODE_SYSCALL, + OPCODE_SIMCALL, + OPCODE_ADD_N, + OPCODE_ADDI_N, + OPCODE_BEQZ_N, + OPCODE_BNEZ_N, + OPCODE_ILL_N, + OPCODE_L32I_N, + OPCODE_MOV_N, + OPCODE_MOVI_N, + OPCODE_NOP_N, + OPCODE_RET_N, + OPCODE_S32I_N, + OPCODE_ADDI, + OPCODE_ADDMI, + OPCODE_ADD, + OPCODE_SUB, + OPCODE_ADDX2, + OPCODE_ADDX4, + OPCODE_ADDX8, + OPCODE_SUBX2, + OPCODE_SUBX4, + OPCODE_SUBX8, + OPCODE_AND, + OPCODE_OR, + OPCODE_XOR, + OPCODE_BEQI, + OPCODE_BNEI, + OPCODE_BGEI, + OPCODE_BLTI, + OPCODE_BBCI, + OPCODE_BBSI, + OPCODE_BGEUI, + OPCODE_BLTUI, + OPCODE_BEQ, + OPCODE_BNE, + OPCODE_BGE, + OPCODE_BLT, + OPCODE_BGEU, + OPCODE_BLTU, + OPCODE_BANY, + OPCODE_BNONE, + OPCODE_BALL, + OPCODE_BNALL, + OPCODE_BBC, + OPCODE_BBS, + OPCODE_BEQZ, + OPCODE_BNEZ, + OPCODE_BGEZ, + OPCODE_BLTZ, + OPCODE_CALL0, + OPCODE_CALLX0, + OPCODE_EXTUI, + OPCODE_ILL, + OPCODE_J, + OPCODE_JX, + OPCODE_L16UI, + OPCODE_L16SI, + OPCODE_L32I, + OPCODE_L32R, + OPCODE_L8UI, + OPCODE_MOVI, + OPCODE_MOVEQZ, + OPCODE_MOVNEZ, + OPCODE_MOVLTZ, + OPCODE_MOVGEZ, + OPCODE_NEG, + OPCODE_ABS, + OPCODE_NOP, + OPCODE_RET, + OPCODE_S16I, + OPCODE_S32I, + OPCODE_S8I, + OPCODE_SSR, + OPCODE_SSL, + OPCODE_SSA8L, + OPCODE_SSA8B, + OPCODE_SSAI, + OPCODE_SLL, + OPCODE_SRC, + OPCODE_SRL, + OPCODE_SRA, + OPCODE_SLLI, + OPCODE_SRAI, + OPCODE_SRLI, + OPCODE_MEMW, + OPCODE_EXTW, + OPCODE_ISYNC, + OPCODE_RSYNC, + OPCODE_ESYNC, + OPCODE_DSYNC, + OPCODE_RSIL, + OPCODE_RSR_SAR, + OPCODE_WSR_SAR, + OPCODE_XSR_SAR, + OPCODE_RSR_LITBASE, + OPCODE_WSR_LITBASE, + OPCODE_XSR_LITBASE, + OPCODE_RSR_176, + OPCODE_WSR_176, + OPCODE_RSR_208, + OPCODE_RSR_PS, + OPCODE_WSR_PS, + OPCODE_XSR_PS, + OPCODE_RSR_EPC1, + OPCODE_WSR_EPC1, + OPCODE_XSR_EPC1, + OPCODE_RSR_EXCSAVE1, + OPCODE_WSR_EXCSAVE1, + OPCODE_XSR_EXCSAVE1, + OPCODE_RSR_EPC2, + OPCODE_WSR_EPC2, + OPCODE_XSR_EPC2, + OPCODE_RSR_EXCSAVE2, + OPCODE_WSR_EXCSAVE2, + OPCODE_XSR_EXCSAVE2, + OPCODE_RSR_EPC3, + OPCODE_WSR_EPC3, + OPCODE_XSR_EPC3, + OPCODE_RSR_EXCSAVE3, + OPCODE_WSR_EXCSAVE3, + OPCODE_XSR_EXCSAVE3, + OPCODE_RSR_EPS2, + OPCODE_WSR_EPS2, + OPCODE_XSR_EPS2, + OPCODE_RSR_EPS3, + OPCODE_WSR_EPS3, + OPCODE_XSR_EPS3, + OPCODE_RSR_EXCVADDR, + OPCODE_WSR_EXCVADDR, + OPCODE_XSR_EXCVADDR, + OPCODE_RSR_DEPC, + OPCODE_WSR_DEPC, + OPCODE_XSR_DEPC, + OPCODE_RSR_EXCCAUSE, + OPCODE_WSR_EXCCAUSE, + OPCODE_XSR_EXCCAUSE, + OPCODE_RSR_PRID, + OPCODE_RSR_VECBASE, + OPCODE_WSR_VECBASE, + OPCODE_XSR_VECBASE, + OPCODE_MUL16U, + OPCODE_MUL16S, + OPCODE_MULL, + OPCODE_RFI, + OPCODE_WAITI, + OPCODE_RSR_INTERRUPT, + OPCODE_WSR_INTSET, + OPCODE_WSR_INTCLEAR, + OPCODE_RSR_INTENABLE, + OPCODE_WSR_INTENABLE, + OPCODE_XSR_INTENABLE, + OPCODE_BREAK, + OPCODE_BREAK_N, + OPCODE_RSR_DBREAKA0, + OPCODE_WSR_DBREAKA0, + OPCODE_XSR_DBREAKA0, + OPCODE_RSR_DBREAKC0, + OPCODE_WSR_DBREAKC0, + OPCODE_XSR_DBREAKC0, + OPCODE_RSR_IBREAKA0, + OPCODE_WSR_IBREAKA0, + OPCODE_XSR_IBREAKA0, + OPCODE_RSR_IBREAKENABLE, + OPCODE_WSR_IBREAKENABLE, + OPCODE_XSR_IBREAKENABLE, + OPCODE_RSR_DEBUGCAUSE, + OPCODE_WSR_DEBUGCAUSE, + OPCODE_XSR_DEBUGCAUSE, + OPCODE_RSR_ICOUNT, + OPCODE_WSR_ICOUNT, + OPCODE_XSR_ICOUNT, + OPCODE_RSR_ICOUNTLEVEL, + OPCODE_WSR_ICOUNTLEVEL, + OPCODE_XSR_ICOUNTLEVEL, + OPCODE_RSR_DDR, + OPCODE_WSR_DDR, + OPCODE_XSR_DDR, + OPCODE_RFDO, + OPCODE_RFDD, + OPCODE_WSR_MMID, + OPCODE_RSR_CCOUNT, + OPCODE_WSR_CCOUNT, + OPCODE_XSR_CCOUNT, + OPCODE_RSR_CCOMPARE0, + OPCODE_WSR_CCOMPARE0, + OPCODE_XSR_CCOMPARE0, + OPCODE_IDTLB, + OPCODE_PDTLB, + OPCODE_RDTLB0, + OPCODE_RDTLB1, + OPCODE_WDTLB, + OPCODE_IITLB, + OPCODE_PITLB, + OPCODE_RITLB0, + OPCODE_RITLB1, + OPCODE_WITLB, + OPCODE_NSA, + OPCODE_NSAU, + OPCODE_RER, + OPCODE_WER +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_n_Slot_inst_get (insn) == 0) + return OPCODE_ILL; + break; + case 2: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RET; + case 2: + return OPCODE_JX; + } + break; + case 3: + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_CALLX0; + break; + } + break; + case 2: + if (Field_s_Slot_inst_get (insn) == 0) + { + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return OPCODE_ISYNC; + case 1: + return OPCODE_RSYNC; + case 2: + return OPCODE_ESYNC; + case 3: + return OPCODE_DSYNC; + case 8: + return OPCODE_EXCW; + case 12: + return OPCODE_MEMW; + case 13: + return OPCODE_EXTW; + case 15: + return OPCODE_NOP; + } + } + break; + case 3: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RFE; + case 2: + return OPCODE_RFDE; + } + break; + case 1: + return OPCODE_RFI; + } + break; + case 4: + return OPCODE_BREAK; + case 5: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SYSCALL; + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SIMCALL; + break; + } + break; + case 6: + return OPCODE_RSIL; + case 7: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_WAITI; + break; + } + break; + case 1: + return OPCODE_AND; + case 2: + return OPCODE_OR; + case 3: + return OPCODE_XOR; + case 4: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSR; + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSL; + break; + case 2: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8L; + break; + case 3: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8B; + break; + case 4: + if (Field_thi3_Slot_inst_get (insn) == 0) + return OPCODE_SSAI; + break; + case 6: + return OPCODE_RER; + case 7: + return OPCODE_WER; + case 14: + return OPCODE_NSA; + case 15: + return OPCODE_NSAU; + } + break; + case 5: + switch (Field_r_Slot_inst_get (insn)) + { + case 3: + return OPCODE_RITLB0; + case 4: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IITLB; + break; + case 5: + return OPCODE_PITLB; + case 6: + return OPCODE_WITLB; + case 7: + return OPCODE_RITLB1; + case 11: + return OPCODE_RDTLB0; + case 12: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IDTLB; + break; + case 13: + return OPCODE_PDTLB; + case 14: + return OPCODE_WDTLB; + case 15: + return OPCODE_RDTLB1; + } + break; + case 6: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return OPCODE_NEG; + case 1: + return OPCODE_ABS; + } + break; + case 8: + return OPCODE_ADD; + case 9: + return OPCODE_ADDX2; + case 10: + return OPCODE_ADDX4; + case 11: + return OPCODE_ADDX8; + case 12: + return OPCODE_SUB; + case 13: + return OPCODE_SUBX2; + case 14: + return OPCODE_SUBX4; + case 15: + return OPCODE_SUBX8; + } + break; + case 1: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + case 1: + return OPCODE_SLLI; + case 2: + case 3: + return OPCODE_SRAI; + case 4: + return OPCODE_SRLI; + case 6: + switch (Field_sr_Slot_inst_get (insn)) + { + case 3: + return OPCODE_XSR_SAR; + case 5: + return OPCODE_XSR_LITBASE; + case 96: + return OPCODE_XSR_IBREAKENABLE; + case 104: + return OPCODE_XSR_DDR; + case 128: + return OPCODE_XSR_IBREAKA0; + case 144: + return OPCODE_XSR_DBREAKA0; + case 160: + return OPCODE_XSR_DBREAKC0; + case 177: + return OPCODE_XSR_EPC1; + case 178: + return OPCODE_XSR_EPC2; + case 179: + return OPCODE_XSR_EPC3; + case 192: + return OPCODE_XSR_DEPC; + case 194: + return OPCODE_XSR_EPS2; + case 195: + return OPCODE_XSR_EPS3; + case 209: + return OPCODE_XSR_EXCSAVE1; + case 210: + return OPCODE_XSR_EXCSAVE2; + case 211: + return OPCODE_XSR_EXCSAVE3; + case 228: + return OPCODE_XSR_INTENABLE; + case 230: + return OPCODE_XSR_PS; + case 231: + return OPCODE_XSR_VECBASE; + case 232: + return OPCODE_XSR_EXCCAUSE; + case 233: + return OPCODE_XSR_DEBUGCAUSE; + case 234: + return OPCODE_XSR_CCOUNT; + case 236: + return OPCODE_XSR_ICOUNT; + case 237: + return OPCODE_XSR_ICOUNTLEVEL; + case 238: + return OPCODE_XSR_EXCVADDR; + case 240: + return OPCODE_XSR_CCOMPARE0; + } + break; + case 8: + return OPCODE_SRC; + case 9: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRL; + break; + case 10: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SLL; + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRA; + break; + case 12: + return OPCODE_MUL16U; + case 13: + return OPCODE_MUL16S; + case 15: + switch (Field_r_Slot_inst_get (insn)) + { + case 14: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_RFDO; + if (Field_t_Slot_inst_get (insn) == 1) + return OPCODE_RFDD; + break; + } + break; + } + break; + case 2: + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_MULL; + break; + case 3: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_sr_Slot_inst_get (insn)) + { + case 3: + return OPCODE_RSR_SAR; + case 5: + return OPCODE_RSR_LITBASE; + case 96: + return OPCODE_RSR_IBREAKENABLE; + case 104: + return OPCODE_RSR_DDR; + case 128: + return OPCODE_RSR_IBREAKA0; + case 144: + return OPCODE_RSR_DBREAKA0; + case 160: + return OPCODE_RSR_DBREAKC0; + case 176: + return OPCODE_RSR_176; + case 177: + return OPCODE_RSR_EPC1; + case 178: + return OPCODE_RSR_EPC2; + case 179: + return OPCODE_RSR_EPC3; + case 192: + return OPCODE_RSR_DEPC; + case 194: + return OPCODE_RSR_EPS2; + case 195: + return OPCODE_RSR_EPS3; + case 208: + return OPCODE_RSR_208; + case 209: + return OPCODE_RSR_EXCSAVE1; + case 210: + return OPCODE_RSR_EXCSAVE2; + case 211: + return OPCODE_RSR_EXCSAVE3; + case 226: + return OPCODE_RSR_INTERRUPT; + case 228: + return OPCODE_RSR_INTENABLE; + case 230: + return OPCODE_RSR_PS; + case 231: + return OPCODE_RSR_VECBASE; + case 232: + return OPCODE_RSR_EXCCAUSE; + case 233: + return OPCODE_RSR_DEBUGCAUSE; + case 234: + return OPCODE_RSR_CCOUNT; + case 235: + return OPCODE_RSR_PRID; + case 236: + return OPCODE_RSR_ICOUNT; + case 237: + return OPCODE_RSR_ICOUNTLEVEL; + case 238: + return OPCODE_RSR_EXCVADDR; + case 240: + return OPCODE_RSR_CCOMPARE0; + } + break; + case 1: + switch (Field_sr_Slot_inst_get (insn)) + { + case 3: + return OPCODE_WSR_SAR; + case 5: + return OPCODE_WSR_LITBASE; + case 89: + return OPCODE_WSR_MMID; + case 96: + return OPCODE_WSR_IBREAKENABLE; + case 104: + return OPCODE_WSR_DDR; + case 128: + return OPCODE_WSR_IBREAKA0; + case 144: + return OPCODE_WSR_DBREAKA0; + case 160: + return OPCODE_WSR_DBREAKC0; + case 176: + return OPCODE_WSR_176; + case 177: + return OPCODE_WSR_EPC1; + case 178: + return OPCODE_WSR_EPC2; + case 179: + return OPCODE_WSR_EPC3; + case 192: + return OPCODE_WSR_DEPC; + case 194: + return OPCODE_WSR_EPS2; + case 195: + return OPCODE_WSR_EPS3; + case 209: + return OPCODE_WSR_EXCSAVE1; + case 210: + return OPCODE_WSR_EXCSAVE2; + case 211: + return OPCODE_WSR_EXCSAVE3; + case 226: + return OPCODE_WSR_INTSET; + case 227: + return OPCODE_WSR_INTCLEAR; + case 228: + return OPCODE_WSR_INTENABLE; + case 230: + return OPCODE_WSR_PS; + case 231: + return OPCODE_WSR_VECBASE; + case 232: + return OPCODE_WSR_EXCCAUSE; + case 233: + return OPCODE_WSR_DEBUGCAUSE; + case 234: + return OPCODE_WSR_CCOUNT; + case 236: + return OPCODE_WSR_ICOUNT; + case 237: + return OPCODE_WSR_ICOUNTLEVEL; + case 238: + return OPCODE_WSR_EXCVADDR; + case 240: + return OPCODE_WSR_CCOMPARE0; + } + break; + case 8: + return OPCODE_MOVEQZ; + case 9: + return OPCODE_MOVNEZ; + case 10: + return OPCODE_MOVLTZ; + case 11: + return OPCODE_MOVGEZ; + } + break; + case 4: + case 5: + return OPCODE_EXTUI; + } + break; + case 1: + return OPCODE_L32R; + case 2: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_L8UI; + case 1: + return OPCODE_L16UI; + case 2: + return OPCODE_L32I; + case 4: + return OPCODE_S8I; + case 5: + return OPCODE_S16I; + case 6: + return OPCODE_S32I; + case 9: + return OPCODE_L16SI; + case 10: + return OPCODE_MOVI; + case 12: + return OPCODE_ADDI; + case 13: + return OPCODE_ADDMI; + } + break; + case 5: + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_CALL0; + break; + case 6: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_J; + case 1: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BEQZ; + case 1: + return OPCODE_BNEZ; + case 2: + return OPCODE_BLTZ; + case 3: + return OPCODE_BGEZ; + } + break; + case 2: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BEQI; + case 1: + return OPCODE_BNEI; + case 2: + return OPCODE_BLTI; + case 3: + return OPCODE_BGEI; + } + break; + case 3: + switch (Field_m_Slot_inst_get (insn)) + { + case 2: + return OPCODE_BLTUI; + case 3: + return OPCODE_BGEUI; + } + break; + } + break; + case 7: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BNONE; + case 1: + return OPCODE_BEQ; + case 2: + return OPCODE_BLT; + case 3: + return OPCODE_BLTU; + case 4: + return OPCODE_BALL; + case 5: + return OPCODE_BBC; + case 6: + case 7: + return OPCODE_BBCI; + case 8: + return OPCODE_BANY; + case 9: + return OPCODE_BNE; + case 10: + return OPCODE_BGE; + case 11: + return OPCODE_BGEU; + case 12: + return OPCODE_BNALL; + case 13: + return OPCODE_BBS; + case 14: + case 15: + return OPCODE_BBSI; + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16a_get (insn)) + { + case 8: + return OPCODE_L32I_N; + case 9: + return OPCODE_S32I_N; + case 10: + return OPCODE_ADD_N; + case 11: + return OPCODE_ADDI_N; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16b_get (insn)) + { + case 12: + switch (Field_i_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_MOVI_N; + case 1: + switch (Field_z_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_BEQZ_N; + case 1: + return OPCODE_BNEZ_N; + } + break; + } + break; + case 13: + switch (Field_r_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_MOV_N; + case 15: + switch (Field_t_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_RET_N; + case 2: + return OPCODE_BREAK_N; + case 3: + if (Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_NOP_N; + break; + case 6: + if (Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_ILL_N; + break; + } + break; + } + break; + } + return XTENSA_UNDEFINED; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_xt_wbr15_imm_Slot_inst_get, + Field_xt_wbr18_imm_Slot_inst_get, + Implicit_Field_ar0_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_xt_wbr15_imm_Slot_inst_set, + Field_xt_wbr18_imm_Slot_inst_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + 0, + 0, + Implicit_Field_ar0_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + 0, + 0, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + 0, + 0, + Implicit_Field_ar0_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + 0, + 0, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x8; +} + +static void +Format_x16b_encode (xtensa_insnbuf insn) +{ + insn[0] = 0xc; +} + +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } +}; + + +static int +format_decoder (const xtensa_insnbuf insn) +{ + if ((insn[0] & 0x8) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc) == 0x8) + return 1; /* x16a */ + if ((insn[0] & 0xe) == 0xc) + return 2; /* x16b */ + return -1; +} + +static int length_table[16] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const unsigned char *insn) +{ + int op0 = insn[0] & 0xf; + return length_table[op0]; +} + + +/* Top-level ISA structure. */ + +static xtensa_isa_internal xtensa_modules = { + 0 /* little-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 37 /* num_fields */, + 65, operands, + 159, iclasses, + 204, opcodes, 0, + 1, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 0, interfaces, 0, + 0, funcUnits, 0 +}; diff --git a/target/xtensa/core-test_mmuhifi_c3.c b/target/xtensa/core-test_mmuhifi_c3.c index 123c630b0da7..c0e5d32d1e47 100644 --- a/target/xtensa/core-test_mmuhifi_c3.c +++ b/target/xtensa/core-test_mmuhifi_c3.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" -#include "qemu-common.h" #include "qemu/host-utils.h" #include "core-test_mmuhifi_c3/core-isa.h" diff --git a/target/xtensa/cores.list b/target/xtensa/cores.list index 5772a00ab2c8..a526a71cfd98 100644 --- a/target/xtensa/cores.list +++ b/target/xtensa/cores.list @@ -4,6 +4,7 @@ core-de212.c core-de233_fpu.c core-dsp3400.c core-fsf.c +core-lx106.c core-sample_controller.c core-test_kc705_be.c core-test_mmuhifi_c3.c diff --git a/target/xtensa/cpu-param.h b/target/xtensa/cpu-param.h index 4fde21b941b8..b53e9a3e0819 100644 --- a/target/xtensa/cpu-param.h +++ b/target/xtensa/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef XTENSA_CPU_PARAM_H -#define XTENSA_CPU_PARAM_H 1 +#define XTENSA_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 diff --git a/target/xtensa/cpu-qom.h b/target/xtensa/cpu-qom.h index 4fc35ee49b8d..419c7d8e4a33 100644 --- a/target/xtensa/cpu-qom.h +++ b/target/xtensa/cpu-qom.h @@ -41,7 +41,7 @@ typedef struct XtensaConfig XtensaConfig; /** * XtensaCPUClass: * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. + * @parent_phases: The parent class' reset phase handlers. * @config: The CPU core configuration. * * An Xtensa CPU model. @@ -52,7 +52,7 @@ struct XtensaCPUClass { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; const XtensaConfig *config; }; diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 224f72323693..2dc8f2d232fb 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -34,6 +34,7 @@ #include "fpu/softfloat.h" #include "qemu/module.h" #include "migration/vmstate.h" +#include "hw/qdev-clock.h" static void xtensa_cpu_set_pc(CPUState *cs, vaddr value) @@ -43,6 +44,22 @@ 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 void xtensa_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) +{ + XtensaCPU *cpu = XTENSA_CPU(cs); + + cpu->env.pc = data[0]; +} + static bool xtensa_cpu_has_work(CPUState *cs) { #ifndef CONFIG_USER_ONLY @@ -68,16 +85,18 @@ bool xtensa_abi_call0(void) } #endif -static void xtensa_cpu_reset(DeviceState *dev) +static void xtensa_cpu_reset_hold(Object *obj) { - CPUState *s = CPU(dev); + CPUState *s = CPU(obj); XtensaCPU *cpu = XTENSA_CPU(s); XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu); CPUXtensaState *env = &cpu->env; bool dfpu = xtensa_option_enabled(env->config, XTENSA_OPTION_DFP_COPROCESSOR); - xcc->parent_reset(dev); + if (xcc->parent_phases.hold) { + xcc->parent_phases.hold(obj); + } env->pc = env->config->exception_vector[EXC_RESET0 + env->static_vectors]; env->sregs[LITBASE] &= ~1; @@ -172,9 +191,23 @@ static void xtensa_cpu_initfn(Object *obj) memory_region_init_io(env->system_er, obj, NULL, env, "er", UINT64_C(0x100000000)); address_space_init(env->address_space_er, env->system_er, "ER"); + + cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0); + clock_set_hz(cpu->clock, env->config->clock_freq_khz * 1000); #endif } +XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) +{ + DeviceState *cpu; + + cpu = DEVICE(object_new(cpu_type)); + qdev_connect_clock_in(cpu, "clk-in", cpu_refclk); + qdev_realize(cpu, NULL, &error_abort); + + return XTENSA_CPU(cpu); +} + #ifndef CONFIG_USER_ONLY static const VMStateDescription vmstate_xtensa_cpu = { .name = "cpu", @@ -193,6 +226,7 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = { static const struct TCGCPUOps xtensa_tcg_ops = { .initialize = xtensa_translate_init, .debug_excp_handler = xtensa_breakpoint_handler, + .restore_state_to_opc = xtensa_restore_state_to_opc, #ifndef CONFIG_USER_ONLY .tlb_fill = xtensa_cpu_tlb_fill, @@ -208,16 +242,19 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); + ResettableClass *rc = RESETTABLE_CLASS(oc); device_class_set_parent_realize(dc, xtensa_cpu_realizefn, &xcc->parent_realize); - device_class_set_parent_reset(dc, xtensa_cpu_reset, &xcc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, xtensa_cpu_reset_hold, NULL, + &xcc->parent_phases); cc->class_by_name = xtensa_cpu_class_by_name; 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/cpu.h b/target/xtensa/cpu.h index 4515f682aa26..579adcb769e2 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -29,7 +29,9 @@ #define XTENSA_CPU_H #include "cpu-qom.h" +#include "qemu/cpu-float.h" #include "exec/cpu-defs.h" +#include "hw/clock.h" #include "xtensa-isa.h" /* Xtensa processors have a weak memory model */ @@ -494,7 +496,7 @@ typedef struct XtensaConfigList { struct XtensaConfigList *next; } XtensaConfigList; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN enum { FP_F32_HIGH, FP_F32_LOW, @@ -558,6 +560,7 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ + Clock *clock; CPUNegativeOffsetState neg; CPUXtensaState env; }; @@ -580,9 +583,9 @@ void xtensa_count_regs(const XtensaConfig *config, unsigned *n_regs, unsigned *n_core_regs); int xtensa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, int mmu_idx, - uintptr_t retaddr) QEMU_NORETURN; +G_NORETURN void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); #define cpu_list xtensa_cpu_list @@ -590,7 +593,7 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, #define XTENSA_CPU_TYPE_NAME(model) model XTENSA_CPU_TYPE_SUFFIX #define CPU_RESOLVING_TYPE TYPE_XTENSA_CPU -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN #define XTENSA_DEFAULT_CPU_MODEL "fsf" #define XTENSA_DEFAULT_CPU_NOMMU_MODEL "fsf" #else @@ -792,4 +795,7 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, } } +XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, + Clock *cpu_refclk); + #endif diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index e0a9caab4bfd..2aa9777a8ebb 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -253,7 +253,7 @@ void xtensa_cpu_do_unaligned_access(CPUState *cs, assert(xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION)); - cpu_restore_state(CPU(cpu), retaddr, true); + cpu_restore_state(CPU(cpu), retaddr); HELPER(exception_cause_vaddr)(env, env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr); @@ -284,7 +284,7 @@ bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } else if (probe) { return false; } else { - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); HELPER(exception_cause_vaddr)(env, env->pc, ret, address); } } @@ -297,7 +297,7 @@ void xtensa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, XtensaCPU *cpu = XTENSA_CPU(cs); CPUXtensaState *env = &cpu->env; - cpu_restore_state(cs, retaddr, true); + cpu_restore_state(cs, retaddr); HELPER(exception_cause_vaddr)(env, env->pc, access_type == MMU_INST_FETCH ? INSTR_PIF_ADDR_ERROR_CAUSE : diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh index df66d09393af..b4c15556c2c4 100755 --- a/target/xtensa/import_core.sh +++ b/target/xtensa/import_core.sh @@ -42,7 +42,6 @@ cat < "${TARGET}.c" #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" -#include "qemu-common.h" #include "qemu/host-utils.h" #include "core-$NAME/core-isa.h" diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index d85d3516d6a5..1af7becc54b1 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -38,12 +38,12 @@ void HELPER(update_ccount)(CPUXtensaState *env) { + XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); env->ccount_time = now; env->sregs[CCOUNT] = env->ccount_base + - (uint32_t)((now - env->time_base) * - env->config->clock_freq_khz / 1000000); + (uint32_t)clock_ns_to_ticks(cpu->clock, now - env->time_base); } void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) @@ -59,6 +59,7 @@ void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) { + XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); uint64_t dcc; qatomic_and(&env->sregs[INTSET], @@ -66,7 +67,7 @@ void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) HELPER(update_ccount)(env); dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; timer_mod(env->ccompare[i].timer, - env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz); + env->ccount_time + clock_ticks_to_ns(cpu->clock, dcc)); env->yield_needed = 1; } diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index 78720734fe92..701c00eed20a 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -449,7 +449,7 @@ #endif -#if (defined(TARGET_WORDS_BIGENDIAN) != 0) == (XCHAL_HAVE_BE != 0) +#if TARGET_BIG_ENDIAN == (XCHAL_HAVE_BE != 0) #define REGISTER_CORE(core) \ static void __attribute__((constructor)) register_core(void) \ { \ diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index b1491ed625e5..77bcd71030c1 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -306,32 +306,25 @@ static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa) static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) { - TCGv_i32 tmp = tcg_const_i32(32); if (!dc->sar_m32_allocated) { dc->sar_m32 = tcg_temp_local_new_i32(); dc->sar_m32_allocated = true; } tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f); - tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32); + tcg_gen_sub_i32(cpu_SR[SAR], tcg_constant_i32(32), dc->sar_m32); dc->sar_5bit = false; dc->sar_m32_5bit = true; - tcg_temp_free(tmp); } static void gen_exception(DisasContext *dc, int excp) { - TCGv_i32 tmp = tcg_const_i32(excp); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_exception(cpu_env, tcg_constant_i32(excp)); } static void gen_exception_cause(DisasContext *dc, uint32_t cause) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); - TCGv_i32 tcause = tcg_const_i32(cause); - gen_helper_exception_cause(cpu_env, tpc, tcause); - tcg_temp_free(tpc); - tcg_temp_free(tcause); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + gen_helper_exception_cause(cpu_env, pc, tcg_constant_i32(cause)); if (cause == ILLEGAL_INSTRUCTION_CAUSE || cause == SYSCALL_CAUSE) { dc->base.is_jmp = DISAS_NORETURN; @@ -340,11 +333,8 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause) static void gen_debug_exception(DisasContext *dc, uint32_t cause) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); - TCGv_i32 tcause = tcg_const_i32(cause); - gen_helper_debug_exception(cpu_env, tpc, tcause); - tcg_temp_free(tpc); - tcg_temp_free(tcause); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + gen_helper_debug_exception(cpu_env, pc, tcg_constant_i32(cause)); if (cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BI | DEBUGCAUSE_BN)) { dc->base.is_jmp = DISAS_NORETURN; } @@ -406,19 +396,15 @@ static int adjust_jump_slot(DisasContext *dc, uint32_t dest, int slot) static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot) { - TCGv_i32 tmp = tcg_const_i32(dest); - gen_jump_slot(dc, tmp, adjust_jump_slot(dc, dest, slot)); - tcg_temp_free(tmp); + gen_jump_slot(dc, tcg_constant_i32(dest), + adjust_jump_slot(dc, dest, slot)); } static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest, int slot) { - TCGv_i32 tcallinc = tcg_const_i32(callinc); - tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS], - tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN); - tcg_temp_free(tcallinc); + tcg_constant_i32(callinc), PS_CALLINC_SHIFT, PS_CALLINC_LEN); tcg_gen_movi_i32(cpu_R[callinc << 2], (callinc << 30) | (dc->base.pc_next & 0x3fffffff)); gen_jump_slot(dc, dest, slot); @@ -464,9 +450,7 @@ static void gen_brcond(DisasContext *dc, TCGCond cond, static void gen_brcondi(DisasContext *dc, TCGCond cond, TCGv_i32 t0, uint32_t t1, uint32_t addr) { - TCGv_i32 tmp = tcg_const_i32(t1); - gen_brcond(dc, cond, t0, tmp, addr); - tcg_temp_free(tmp); + gen_brcond(dc, cond, t0, tcg_constant_i32(t1), addr); } static uint32_t test_exceptions_sr(DisasContext *dc, const OpcodeArg arg[], @@ -551,28 +535,13 @@ static MemOp gen_load_store_alignment(DisasContext *dc, MemOp mop, return mop; } -#ifndef CONFIG_USER_ONLY -static void gen_waiti(DisasContext *dc, uint32_t imm4) -{ - TCGv_i32 pc = tcg_const_i32(dc->base.pc_next); - TCGv_i32 intlevel = tcg_const_i32(imm4); - - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_waiti(cpu_env, pc, intlevel); - tcg_temp_free(pc); - tcg_temp_free(intlevel); -} -#endif - static bool gen_window_check(DisasContext *dc, uint32_t mask) { unsigned r = 31 - clz32(mask); if (r / 4 > dc->window) { - TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 w = tcg_const_i32(r / 4); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + TCGv_i32 w = tcg_constant_i32(r / 4); gen_helper_window_check(cpu_env, pc, w); dc->base.is_jmp = DISAS_NORETURN; @@ -1080,17 +1049,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) } if (op_flags & XTENSA_OP_UNDERFLOW) { - TCGv_i32 tmp = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_test_underflow_retw(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_test_underflow_retw(cpu_env, pc); } if (op_flags & XTENSA_OP_ALLOCA) { - TCGv_i32 tmp = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_movsp(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_movsp(cpu_env, pc); } if (coprocessor && !gen_check_cpenable(dc, coprocessor)) { @@ -1296,10 +1263,11 @@ static void xtensa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) } } -static void xtensa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) +static void xtensa_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) { - qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); - log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); + fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); } static const TranslatorOps xtensa_translator_ops = { @@ -1311,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) @@ -1385,12 +1355,6 @@ void xtensa_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } -void restore_state_to_opc(CPUXtensaState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} - static void translate_abs(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { @@ -1471,14 +1435,14 @@ static void translate_b(DisasContext *dc, const OpcodeArg arg[], static void translate_bb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN TCGv_i32 bit = tcg_const_i32(0x80000000u); #else TCGv_i32 bit = tcg_const_i32(0x00000001u); #endif TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, arg[1].in, 0x1f); -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN tcg_gen_shr_i32(bit, bit, tmp); #else tcg_gen_shl_i32(bit, bit, tmp); @@ -1493,7 +1457,7 @@ static void translate_bbi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); -#ifdef TARGET_WORDS_BIGENDIAN +#if TARGET_BIG_ENDIAN tcg_gen_andi_i32(tmp, arg[0].in, 0x80000000u >> arg[1].imm); #else tcg_gen_andi_i32(tmp, arg[0].in, 0x00000001u << arg[1].imm); @@ -1669,13 +1633,10 @@ static uint32_t test_overflow_entry(DisasContext *dc, const OpcodeArg arg[], static void translate_entry(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 s = tcg_const_i32(arg[0].imm); - TCGv_i32 imm = tcg_const_i32(arg[1].imm); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + TCGv_i32 s = tcg_constant_i32(arg[0].imm); + TCGv_i32 imm = tcg_constant_i32(arg[1].imm); gen_helper_entry(cpu_env, pc, s, imm); - tcg_temp_free(imm); - tcg_temp_free(s); - tcg_temp_free(pc); } static void translate_extui(DisasContext *dc, const OpcodeArg arg[], @@ -1717,10 +1678,9 @@ static void translate_itlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); gen_helper_itlb(cpu_env, arg[0].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -1756,12 +1716,10 @@ static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write) static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write) { if (!option_enabled(dc, XTENSA_OPTION_MPU)) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); - TCGv_i32 write = tcg_const_i32(is_write); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_check_exclusive(cpu_env, tpc, addr, write); - tcg_temp_free(tpc); - tcg_temp_free(write); + gen_helper_check_exclusive(cpu_env, pc, addr, + tcg_constant_i32(is_write)); } } #endif @@ -1804,6 +1762,12 @@ static void translate_ldst(DisasContext *dc, const OpcodeArg arg[], tcg_temp_free(addr); } +static void translate_lct(DisasContext *dc, const OpcodeArg arg[], + const uint32_t par[]) +{ + tcg_gen_movi_i32(arg[0].out, 0); +} + static void translate_l32r(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { @@ -1956,11 +1920,10 @@ static void translate_mov(DisasContext *dc, const OpcodeArg arg[], static void translate_movcond(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_movcond_i32(par[0], arg[0].out, arg[2].in, zero, arg[1].in, arg[0].in); - tcg_temp_free(zero); } static void translate_movi(DisasContext *dc, const OpcodeArg arg[], @@ -1972,7 +1935,7 @@ static void translate_movi(DisasContext *dc, const OpcodeArg arg[], static void translate_movp(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, arg[2].in, 1 << arg[2].imm); @@ -1980,7 +1943,6 @@ static void translate_movp(DisasContext *dc, const OpcodeArg arg[], arg[0].out, tmp, zero, arg[1].in, arg[0].in); tcg_temp_free(tmp); - tcg_temp_free(zero); } static void translate_movsp(DisasContext *dc, const OpcodeArg arg[], @@ -2059,11 +2021,10 @@ static void translate_ptlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); tcg_gen_movi_i32(cpu_pc, dc->pc); gen_helper_ptlb(arg[0].out, cpu_env, arg[1].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -2141,10 +2102,9 @@ static uint32_t test_exceptions_retw(DisasContext *dc, const OpcodeArg arg[], "Illegal retw instruction(pc = %08x)\n", dc->pc); return XTENSA_OP_ILL; } else { - TCGv_i32 tmp = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_test_ill_retw(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_test_ill_retw(cpu_env, pc); return 0; } } @@ -2262,10 +2222,9 @@ static void translate_rtlb(DisasContext *dc, const OpcodeArg arg[], gen_helper_rtlb0, gen_helper_rtlb1, }; - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); helper[par[1]](arg[0].out, cpu_env, arg[1].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -2305,10 +2264,9 @@ static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr) #else static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_check_atomctl(cpu_env, tpc, addr); - tcg_temp_free(tpc); + gen_helper_check_atomctl(cpu_env, pc, addr); } #endif @@ -2398,13 +2356,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; @@ -2414,7 +2373,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 @@ -2529,9 +2488,7 @@ static void translate_ssa8l(DisasContext *dc, const OpcodeArg arg[], static void translate_ssai(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_const_i32(arg[0].imm); - gen_right_shift_sar(dc, tmp); - tcg_temp_free(tmp); + gen_right_shift_sar(dc, tcg_constant_i32(arg[0].imm)); } static void translate_ssl(DisasContext *dc, const OpcodeArg arg[], @@ -2565,7 +2522,12 @@ static void translate_waiti(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_waiti(dc, arg[0].imm); + TCGv_i32 pc = tcg_constant_i32(dc->base.pc_next); + + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_waiti(cpu_env, pc, tcg_constant_i32(arg[0].imm)); #endif } @@ -2573,10 +2535,9 @@ static void translate_wtlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); gen_helper_wtlb(cpu_env, arg[0].in, arg[1].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -2628,15 +2589,13 @@ static void translate_wsr_ccompare(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY uint32_t id = par[0] - CCOMPARE; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->nccompare); if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in); - gen_helper_update_ccompare(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_update_ccompare(cpu_env, tcg_constant_i32(id)); #endif } @@ -2656,11 +2615,9 @@ static void translate_wsr_dbreaka(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY unsigned id = par[0] - DBREAKA; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->ndbreak); - gen_helper_wsr_dbreaka(cpu_env, tmp, arg[0].in); - tcg_temp_free(tmp); + gen_helper_wsr_dbreaka(cpu_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2669,11 +2626,9 @@ static void translate_wsr_dbreakc(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY unsigned id = par[0] - DBREAKC; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->ndbreak); - gen_helper_wsr_dbreakc(cpu_env, tmp, arg[0].in); - tcg_temp_free(tmp); + gen_helper_wsr_dbreakc(cpu_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2682,11 +2637,9 @@ static void translate_wsr_ibreaka(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY unsigned id = par[0] - IBREAKA; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->nibreak); - gen_helper_wsr_ibreaka(cpu_env, tmp, arg[0].in); - tcg_temp_free(tmp); + gen_helper_wsr_ibreaka(cpu_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -3369,6 +3322,14 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_ldst, .par = (const uint32_t[]){MO_UB, false, false}, .op_flags = XTENSA_OP_LOAD, + }, { + .name = "ldct", + .translate = translate_lct, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "ldcw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = "lddec", .translate = translate_mac16, @@ -3382,6 +3343,14 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "ldpte", .op_flags = XTENSA_OP_ILL, + }, { + .name = "lict", + .translate = translate_lct, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "licw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = (const char * const[]) { "loop", "loop.w15", NULL, @@ -4685,12 +4654,28 @@ static const XtensaOpcodeOps core_ops[] = { .name = "saltu", .translate = translate_salt, .par = (const uint32_t[]){TCG_COND_LTU}, + }, { + .name = "sdct", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "sdcw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = "setb_expstate", .translate = translate_setb_expstate, }, { .name = "sext", .translate = translate_sext, + }, { + .name = "sict", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "sicw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = "simcall", .translate = translate_simcall, @@ -6443,7 +6428,7 @@ static void translate_compare_d(DisasContext *dc, const OpcodeArg arg[], [COMPARE_OLE] = gen_helper_ole_d, [COMPARE_ULE] = gen_helper_ule_d, }; - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 res = tcg_temp_new_i32(); TCGv_i32 set_br = tcg_temp_new_i32(); TCGv_i32 clr_br = tcg_temp_new_i32(); @@ -6455,7 +6440,6 @@ static void translate_compare_d(DisasContext *dc, const OpcodeArg arg[], tcg_gen_movcond_i32(TCG_COND_NE, arg[0].out, res, zero, set_br, clr_br); - tcg_temp_free(zero); tcg_temp_free(res); tcg_temp_free(set_br); tcg_temp_free(clr_br); @@ -6475,7 +6459,7 @@ static void translate_compare_s(DisasContext *dc, const OpcodeArg arg[], [COMPARE_ULE] = gen_helper_ule_s, }; OpcodeArg arg32[3]; - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 res = tcg_temp_new_i32(); TCGv_i32 set_br = tcg_temp_new_i32(); TCGv_i32 clr_br = tcg_temp_new_i32(); @@ -6489,7 +6473,6 @@ static void translate_compare_s(DisasContext *dc, const OpcodeArg arg[], arg[0].out, res, zero, set_br, clr_br); put_f32_i2(arg, arg32, 1, 2); - tcg_temp_free(zero); tcg_temp_free(res); tcg_temp_free(set_br); tcg_temp_free(clr_br); @@ -6538,20 +6521,19 @@ static void translate_const_s(DisasContext *dc, const OpcodeArg arg[], static void translate_float_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 scale = tcg_const_i32(-arg[2].imm); + TCGv_i32 scale = tcg_constant_i32(-arg[2].imm); if (par[0]) { gen_helper_uitof_d(arg[0].out, cpu_env, arg[1].in, scale); } else { gen_helper_itof_d(arg[0].out, cpu_env, arg[1].in, scale); } - tcg_temp_free(scale); } static void translate_float_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 scale = tcg_const_i32(-arg[2].imm); + TCGv_i32 scale = tcg_constant_i32(-arg[2].imm); OpcodeArg arg32[1]; get_f32_o1(arg, arg32, 0); @@ -6561,14 +6543,13 @@ static void translate_float_s(DisasContext *dc, const OpcodeArg arg[], gen_helper_itof_s(arg32[0].out, cpu_env, arg[1].in, scale); } put_f32_o1(arg, arg32, 0); - tcg_temp_free(scale); } static void translate_ftoi_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 rounding_mode = tcg_const_i32(par[0]); - TCGv_i32 scale = tcg_const_i32(arg[2].imm); + TCGv_i32 rounding_mode = tcg_constant_i32(par[0]); + TCGv_i32 scale = tcg_constant_i32(arg[2].imm); if (par[1]) { gen_helper_ftoui_d(arg[0].out, cpu_env, arg[1].in, @@ -6577,15 +6558,13 @@ static void translate_ftoi_d(DisasContext *dc, const OpcodeArg arg[], gen_helper_ftoi_d(arg[0].out, cpu_env, arg[1].in, rounding_mode, scale); } - tcg_temp_free(rounding_mode); - tcg_temp_free(scale); } static void translate_ftoi_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 rounding_mode = tcg_const_i32(par[0]); - TCGv_i32 scale = tcg_const_i32(arg[2].imm); + TCGv_i32 rounding_mode = tcg_constant_i32(par[0]); + TCGv_i32 scale = tcg_constant_i32(arg[2].imm); OpcodeArg arg32[2]; get_f32_i1(arg, arg32, 1); @@ -6597,8 +6576,6 @@ static void translate_ftoi_s(DisasContext *dc, const OpcodeArg arg[], rounding_mode, scale); } put_f32_i1(arg, arg32, 1); - tcg_temp_free(rounding_mode); - tcg_temp_free(scale); } static void translate_ldsti(DisasContext *dc, const OpcodeArg arg[], @@ -6665,14 +6642,13 @@ static void translate_mov_s(DisasContext *dc, const OpcodeArg arg[], static void translate_movcond_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 zero = tcg_constant_i64(0); TCGv_i64 arg2 = tcg_temp_new_i64(); tcg_gen_ext_i32_i64(arg2, arg[2].in); tcg_gen_movcond_i64(par[0], arg[0].out, arg2, zero, arg[1].in, arg[0].in); - tcg_temp_free_i64(zero); tcg_temp_free_i64(arg2); } @@ -6680,12 +6656,11 @@ static void translate_movcond_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (arg[0].num_bits == 32) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_movcond_i32(par[0], arg[0].out, arg[2].in, zero, arg[1].in, arg[0].in); - tcg_temp_free(zero); } else { translate_movcond_d(dc, arg, par); } @@ -6694,7 +6669,7 @@ static void translate_movcond_s(DisasContext *dc, const OpcodeArg arg[], static void translate_movp_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 zero = tcg_constant_i64(0); TCGv_i32 tmp1 = tcg_temp_new_i32(); TCGv_i64 tmp2 = tcg_temp_new_i64(); @@ -6703,7 +6678,6 @@ static void translate_movp_d(DisasContext *dc, const OpcodeArg arg[], tcg_gen_movcond_i64(par[0], arg[0].out, tmp2, zero, arg[1].in, arg[0].in); - tcg_temp_free_i64(zero); tcg_temp_free_i32(tmp1); tcg_temp_free_i64(tmp2); } @@ -6712,7 +6686,7 @@ static void translate_movp_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (arg[0].num_bits == 32) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, arg[2].in, 1 << arg[2].imm); @@ -6720,7 +6694,6 @@ static void translate_movp_s(DisasContext *dc, const OpcodeArg arg[], arg[0].out, tmp, zero, arg[1].in, arg[0].in); tcg_temp_free(tmp); - tcg_temp_free(zero); } else { translate_movp_d(dc, arg, par); } diff --git a/tcg/README b/tcg/README deleted file mode 100644 index bc15cc3b32fd..000000000000 --- a/tcg/README +++ /dev/null @@ -1,784 +0,0 @@ -Tiny Code Generator - Fabrice Bellard. - -1) Introduction - -TCG (Tiny Code Generator) began as a generic backend for a C -compiler. It was simplified to be used in QEMU. It also has its roots -in the QOP code generator written by Paul Brook. - -2) Definitions - -TCG receives RISC-like "TCG ops" and performs some optimizations on them, -including liveness analysis and trivial constant expression -evaluation. TCG ops are then implemented in the host CPU back end, -also known as the TCG "target". - -The TCG "target" is the architecture for which we generate the -code. It is of course not the same as the "target" of QEMU which is -the emulated architecture. As TCG started as a generic C backend used -for cross compiling, it is assumed that the TCG target is different -from the host, although it is never the case for QEMU. - -In this document, we use "guest" to specify what architecture we are -emulating; "target" always means the TCG target, the machine on which -we are running QEMU. - -A TCG "function" corresponds to a QEMU Translated Block (TB). - -A TCG "temporary" is a variable only live in a basic -block. Temporaries are allocated explicitly in each function. - -A TCG "local temporary" is a variable only live in a function. Local -temporaries are allocated explicitly in each function. - -A TCG "global" is a variable which is live in all the functions -(equivalent of a C global variable). They are defined before the -functions defined. A TCG global can be a memory location (e.g. a QEMU -CPU register), a fixed host register (e.g. the QEMU CPU state pointer) -or a memory location which is stored in a register outside QEMU TBs -(not implemented yet). - -A TCG "basic block" corresponds to a list of instructions terminated -by a branch instruction. - -An operation with "undefined behavior" may result in a crash. - -An operation with "unspecified behavior" shall not crash. However, -the result may be one of several possibilities so may be considered -an "undefined result". - -3) Intermediate representation - -3.1) Introduction - -TCG instructions operate on variables which are temporaries, local -temporaries or globals. TCG instructions and variables are strongly -typed. Two types are supported: 32 bit integers and 64 bit -integers. Pointers are defined as an alias to 32 bit or 64 bit -integers depending on the TCG target word size. - -Each instruction has a fixed number of output variable operands, input -variable operands and always constant operands. - -The notable exception is the call instruction which has a variable -number of outputs and inputs. - -In the textual form, output operands usually come first, followed by -input operands, followed by constant operands. The output type is -included in the instruction name. Constants are prefixed with a '$'. - -add_i32 t0, t1, t2 (t0 <- t1 + t2) - -3.2) Assumptions - -* Basic blocks - -- Basic blocks end after branches (e.g. brcond_i32 instruction), - goto_tb and exit_tb instructions. -- Basic blocks start after the end of a previous basic block, or at a - set_label instruction. - -After the end of a basic block, the content of temporaries is -destroyed, but local temporaries and globals are preserved. - -* Floating point types are not supported yet - -* Pointers: depending on the TCG target, pointer size is 32 bit or 64 - bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or - TCG_TYPE_I64. - -* Helpers: - -Using the tcg_gen_helper_x_y it is possible to call any function -taking i32, i64 or pointer types. By default, before calling a helper, -all globals are stored at their canonical location and it is assumed -that the function can modify them. By default, the helper is allowed to -modify the CPU state or raise an exception. - -This can be overridden using the following function modifiers: -- TCG_CALL_NO_READ_GLOBALS means that the helper does not read globals, - either directly or via an exception. They will not be saved to their - canonical locations before calling the helper. -- TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals. - They will only be saved to their canonical location before calling helpers, - but they won't be reloaded afterwards. -- TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if - the return value is not used. - -Note that TCG_CALL_NO_READ_GLOBALS implies TCG_CALL_NO_WRITE_GLOBALS. - -On some TCG targets (e.g. x86), several calling conventions are -supported. - -* Branches: - -Use the instruction 'br' to jump to a label. - -3.3) Code Optimizations - -When generating instructions, you can count on at least the following -optimizations: - -- Single instructions are simplified, e.g. - - and_i32 t0, t0, $0xffffffff - - is suppressed. - -- A liveness analysis is done at the basic block level. The - information is used to suppress moves from a dead variable to - another one. It is also used to remove instructions which compute - dead results. The later is especially useful for condition code - optimization in QEMU. - - In the following example: - - add_i32 t0, t1, t2 - add_i32 t0, t0, $1 - mov_i32 t0, $1 - - only the last instruction is kept. - -3.4) Instruction Reference - -********* Function call - -* call ptr - -call function 'ptr' (pointer type) - - optional 32 bit or 64 bit return value - optional 32 bit or 64 bit parameters - -********* Jumps/Labels - -* set_label $label - -Define label 'label' at the current program point. - -* br $label - -Jump to label. - -* brcond_i32/i64 t0, t1, cond, label - -Conditional jump if t0 cond t1 is true. cond can be: - TCG_COND_EQ - TCG_COND_NE - TCG_COND_LT /* signed */ - TCG_COND_GE /* signed */ - TCG_COND_LE /* signed */ - TCG_COND_GT /* signed */ - TCG_COND_LTU /* unsigned */ - TCG_COND_GEU /* unsigned */ - TCG_COND_LEU /* unsigned */ - TCG_COND_GTU /* unsigned */ - -********* Arithmetic - -* add_i32/i64 t0, t1, t2 - -t0=t1+t2 - -* sub_i32/i64 t0, t1, t2 - -t0=t1-t2 - -* neg_i32/i64 t0, t1 - -t0=-t1 (two's complement) - -* mul_i32/i64 t0, t1, t2 - -t0=t1*t2 - -* div_i32/i64 t0, t1, t2 - -t0=t1/t2 (signed). Undefined behavior if division by zero or overflow. - -* divu_i32/i64 t0, t1, t2 - -t0=t1/t2 (unsigned). Undefined behavior if division by zero. - -* rem_i32/i64 t0, t1, t2 - -t0=t1%t2 (signed). Undefined behavior if division by zero or overflow. - -* remu_i32/i64 t0, t1, t2 - -t0=t1%t2 (unsigned). Undefined behavior if division by zero. - -********* Logical - -* and_i32/i64 t0, t1, t2 - -t0=t1&t2 - -* or_i32/i64 t0, t1, t2 - -t0=t1|t2 - -* xor_i32/i64 t0, t1, t2 - -t0=t1^t2 - -* not_i32/i64 t0, t1 - -t0=~t1 - -* andc_i32/i64 t0, t1, t2 - -t0=t1&~t2 - -* eqv_i32/i64 t0, t1, t2 - -t0=~(t1^t2), or equivalently, t0=t1^~t2 - -* nand_i32/i64 t0, t1, t2 - -t0=~(t1&t2) - -* nor_i32/i64 t0, t1, t2 - -t0=~(t1|t2) - -* orc_i32/i64 t0, t1, t2 - -t0=t1|~t2 - -* clz_i32/i64 t0, t1, t2 - -t0 = t1 ? clz(t1) : t2 - -* ctz_i32/i64 t0, t1, t2 - -t0 = t1 ? ctz(t1) : t2 - -* ctpop_i32/i64 t0, t1 - -t0 = number of bits set in t1 -With "ctpop" short for "count population", matching -the function name used in include/qemu/host-utils.h. - -********* Shifts/Rotates - -* shl_i32/i64 t0, t1, t2 - -t0=t1 << t2. Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) - -* shr_i32/i64 t0, t1, t2 - -t0=t1 >> t2 (unsigned). Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) - -* sar_i32/i64 t0, t1, t2 - -t0=t1 >> t2 (signed). Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) - -* rotl_i32/i64 t0, t1, t2 - -Rotation of t2 bits to the left. -Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) - -* rotr_i32/i64 t0, t1, t2 - -Rotation of t2 bits to the right. -Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) - -********* Misc - -* mov_i32/i64 t0, t1 - -t0 = t1 - -Move t1 to t0 (both operands must have the same type). - -* ext8s_i32/i64 t0, t1 -ext8u_i32/i64 t0, t1 -ext16s_i32/i64 t0, t1 -ext16u_i32/i64 t0, t1 -ext32s_i64 t0, t1 -ext32u_i64 t0, t1 - -8, 16 or 32 bit sign/zero extension (both operands must have the same type) - -* bswap16_i32/i64 t0, t1, flags - -16 bit byte swap on the low bits of a 32/64 bit input. -If flags & TCG_BSWAP_IZ, then t1 is known to be zero-extended from bit 15. -If flags & TCG_BSWAP_OZ, then t0 will be zero-extended from bit 15. -If flags & TCG_BSWAP_OS, then t0 will be sign-extended from bit 15. -If neither TCG_BSWAP_OZ nor TCG_BSWAP_OS are set, then the bits of -t0 above bit 15 may contain any value. - -* bswap32_i64 t0, t1, flags - -32 bit byte swap on a 64-bit value. The flags are the same as for bswap16, -except they apply from bit 31 instead of bit 15. - -* bswap32_i32 t0, t1, flags -* bswap64_i64 t0, t1, flags - -32/64 bit byte swap. The flags are ignored, but still present -for consistency with the other bswap opcodes. - -* discard_i32/i64 t0 - -Indicate that the value of t0 won't be used later. It is useful to -force dead code elimination. - -* deposit_i32/i64 dest, t1, t2, pos, len - -Deposit T2 as a bitfield into T1, placing the result in DEST. -The bitfield is described by POS/LEN, which are immediate values: - - LEN - the length of the bitfield - POS - the position of the first bit, counting from the LSB - -For example, "deposit_i32 dest, t1, t2, 8, 4" indicates a 4-bit field -at bit 8. This operation would be equivalent to - - dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00) - -* extract_i32/i64 dest, t1, pos, len -* sextract_i32/i64 dest, t1, pos, len - -Extract a bitfield from T1, placing the result in DEST. -The bitfield is described by POS/LEN, which are immediate values, -as above for deposit. For extract_*, the result will be extended -to the left with zeros; for sextract_*, the result will be extended -to the left with copies of the bitfield sign bit at pos + len - 1. - -For example, "sextract_i32 dest, t1, 8, 4" indicates a 4-bit field -at bit 8. This operation would be equivalent to - - dest = (t1 << 20) >> 28 - -(using an arithmetic right shift). - -* extract2_i32/i64 dest, t1, t2, pos - -For N = {32,64}, extract an N-bit quantity from the concatenation -of t2:t1, beginning at pos. The tcg_gen_extract2_{i32,i64} expander -accepts 0 <= pos <= N as inputs. The backend code generator will -not see either 0 or N as inputs for these opcodes. - -* extrl_i64_i32 t0, t1 - -For 64-bit hosts only, extract the low 32-bits of input T1 and place it -into 32-bit output T0. Depending on the host, this may be a simple move, -or may require additional canonicalization. - -* extrh_i64_i32 t0, t1 - -For 64-bit hosts only, extract the high 32-bits of input T1 and place it -into 32-bit output T0. Depending on the host, this may be a simple shift, -or may require additional canonicalization. - -********* Conditional moves - -* setcond_i32/i64 dest, t1, t2, cond - -dest = (t1 cond t2) - -Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0. - -* movcond_i32/i64 dest, c1, c2, v1, v2, cond - -dest = (c1 cond c2 ? v1 : v2) - -Set DEST to V1 if (C1 cond C2) is true, otherwise set to V2. - -********* Type conversions - -* ext_i32_i64 t0, t1 -Convert t1 (32 bit) to t0 (64 bit) and does sign extension - -* extu_i32_i64 t0, t1 -Convert t1 (32 bit) to t0 (64 bit) and does zero extension - -* trunc_i64_i32 t0, t1 -Truncate t1 (64 bit) to t0 (32 bit) - -* concat_i32_i64 t0, t1, t2 -Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half -from t2 (32 bit). - -* concat32_i64 t0, t1, t2 -Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half -from t2 (64 bit). - -********* Load/Store - -* ld_i32/i64 t0, t1, offset -ld8s_i32/i64 t0, t1, offset -ld8u_i32/i64 t0, t1, offset -ld16s_i32/i64 t0, t1, offset -ld16u_i32/i64 t0, t1, offset -ld32s_i64 t0, t1, offset -ld32u_i64 t0, t1, offset - -t0 = read(t1 + offset) -Load 8, 16, 32 or 64 bits with or without sign extension from host memory. -offset must be a constant. - -* st_i32/i64 t0, t1, offset -st8_i32/i64 t0, t1, offset -st16_i32/i64 t0, t1, offset -st32_i64 t0, t1, offset - -write(t0, t1 + offset) -Write 8, 16, 32 or 64 bits to host memory. - -All this opcodes assume that the pointed host memory doesn't correspond -to a global. In the latter case the behaviour is unpredictable. - -********* Multiword arithmetic support - -* add2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high -* sub2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high - -Similar to add/sub, except that the double-word inputs T1 and T2 are -formed from two single-word arguments, and the double-word output T0 -is returned in two single-word outputs. - -* mulu2_i32/i64 t0_low, t0_high, t1, t2 - -Similar to mul, except two unsigned inputs T1 and T2 yielding the full -double-word product T0. The later is returned in two single-word outputs. - -* muls2_i32/i64 t0_low, t0_high, t1, t2 - -Similar to mulu2, except the two inputs T1 and T2 are signed. - -* mulsh_i32/i64 t0, t1, t2 -* muluh_i32/i64 t0, t1, t2 - -Provide the high part of a signed or unsigned multiply, respectively. -If mulu2/muls2 are not provided by the backend, the tcg-op generator -can obtain the same results can be obtained by emitting a pair of -opcodes, mul+muluh/mulsh. - -********* Memory Barrier support - -* mb <$arg> - -Generate a target memory barrier instruction to ensure memory ordering as being -enforced by a corresponding guest memory barrier instruction. The ordering -enforced by the backend may be stricter than the ordering required by the guest. -It cannot be weaker. This opcode takes a constant argument which is required to -generate the appropriate barrier instruction. The backend should take care to -emit the target barrier instruction only when necessary i.e., for SMP guests and -when MTTCG is enabled. - -The guest translators should generate this opcode for all guest instructions -which have ordering side effects. - -Please see docs/devel/atomics.rst for more information on memory barriers. - -********* 64-bit guest on 32-bit host support - -The following opcodes are internal to TCG. Thus they are to be implemented by -32-bit host code generators, but are not to be emitted by guest translators. -They are emitted as needed by inline functions within "tcg-op.h". - -* brcond2_i32 t0_low, t0_high, t1_low, t1_high, cond, label - -Similar to brcond, except that the 64-bit values T0 and T1 -are formed from two 32-bit arguments. - -* setcond2_i32 dest, t1_low, t1_high, t2_low, t2_high, cond - -Similar to setcond, except that the 64-bit values T1 and T2 are -formed from two 32-bit arguments. The result is a 32-bit value. - -********* QEMU specific operations - -* exit_tb t0 - -Exit the current TB and return the value t0 (word type). - -* goto_tb index - -Exit the current TB and jump to the TB index 'index' (constant) if the -current TB was linked to this TB. Otherwise execute the next -instructions. Only indices 0 and 1 are valid and tcg_gen_goto_tb may be issued -at most once with each slot index per TB. - -* lookup_and_goto_ptr tb_addr - -Look up a TB address ('tb_addr') and jump to it if valid. If not valid, -jump to the TCG epilogue to go back to the exec loop. - -This operation is optional. If the TCG backend does not implement the -goto_ptr opcode, emitting this op is equivalent to emitting exit_tb(0). - -* qemu_ld_i32/i64 t0, t1, flags, memidx -* qemu_st_i32/i64 t0, t1, flags, memidx -* qemu_st8_i32 t0, t1, flags, memidx - -Load data at the guest address t1 into t0, or store data in t0 at guest -address t1. The _i32/_i64 size applies to the size of the input/output -register t0 only. The address t1 is always sized according to the guest, -and the width of the memory operation is controlled by flags. - -Both t0 and t1 may be split into little-endian ordered pairs of registers -if dealing with 64-bit quantities on a 32-bit host. - -The memidx selects the qemu tlb index to use (e.g. user or kernel access). -The flags are the MemOp bits, selecting the sign, width, and endianness -of the memory access. - -For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a -64-bit memory access specified in flags. - -For i386, qemu_st8_i32 is exactly like qemu_st_i32, except the size of -the memory operation is known to be 8-bit. This allows the backend to -provide a different set of register constraints. - -********* Host vector operations - -All of the vector ops have two parameters, TCGOP_VECL & TCGOP_VECE. -The former specifies the length of the vector in log2 64-bit units; the -later specifies the length of the element (if applicable) in log2 8-bit units. -E.g. VECL=1 -> 64 << 1 -> v128, and VECE=2 -> 1 << 2 -> i32. - -* mov_vec v0, v1 -* ld_vec v0, t1 -* st_vec v0, t1 - - Move, load and store. - -* dup_vec v0, r1 - - Duplicate the low N bits of R1 into VECL/VECE copies across V0. - -* dupi_vec v0, c - - Similarly, for a constant. - Smaller values will be replicated to host register size by the expanders. - -* dup2_vec v0, r1, r2 - - Duplicate r2:r1 into VECL/64 copies across V0. This opcode is - only present for 32-bit hosts. - -* add_vec v0, v1, v2 - - v0 = v1 + v2, in elements across the vector. - -* sub_vec v0, v1, v2 - - Similarly, v0 = v1 - v2. - -* mul_vec v0, v1, v2 - - Similarly, v0 = v1 * v2. - -* neg_vec v0, v1 - - Similarly, v0 = -v1. - -* abs_vec v0, v1 - - Similarly, v0 = v1 < 0 ? -v1 : v1, in elements across the vector. - -* smin_vec: -* umin_vec: - - Similarly, v0 = MIN(v1, v2), for signed and unsigned element types. - -* smax_vec: -* umax_vec: - - Similarly, v0 = MAX(v1, v2), for signed and unsigned element types. - -* ssadd_vec: -* sssub_vec: -* usadd_vec: -* ussub_vec: - - Signed and unsigned saturating addition and subtraction. If the true - result is not representable within the element type, the element is - set to the minimum or maximum value for the type. - -* and_vec v0, v1, v2 -* or_vec v0, v1, v2 -* xor_vec v0, v1, v2 -* andc_vec v0, v1, v2 -* orc_vec v0, v1, v2 -* not_vec v0, v1 - - Similarly, logical operations with and without complement. - Note that VECE is unused. - -* shli_vec v0, v1, i2 -* shls_vec v0, v1, s2 - - Shift all elements from v1 by a scalar i2/s2. I.e. - - for (i = 0; i < VECL/VECE; ++i) { - v0[i] = v1[i] << s2; - } - -* shri_vec v0, v1, i2 -* sari_vec v0, v1, i2 -* rotli_vec v0, v1, i2 -* shrs_vec v0, v1, s2 -* sars_vec v0, v1, s2 - - Similarly for logical and arithmetic right shift, and left rotate. - -* shlv_vec v0, v1, v2 - - Shift elements from v1 by elements from v2. I.e. - - for (i = 0; i < VECL/VECE; ++i) { - v0[i] = v1[i] << v2[i]; - } - -* shrv_vec v0, v1, v2 -* sarv_vec v0, v1, v2 -* rotlv_vec v0, v1, v2 -* rotrv_vec v0, v1, v2 - - Similarly for logical and arithmetic right shift, and rotates. - -* cmp_vec v0, v1, v2, cond - - Compare vectors by element, storing -1 for true and 0 for false. - -* bitsel_vec v0, v1, v2, v3 - - Bitwise select, v0 = (v2 & v1) | (v3 & ~v1), across the entire vector. - -* cmpsel_vec v0, c1, c2, v3, v4, cond - - Select elements based on comparison results: - for (i = 0; i < n; ++i) { - v0[i] = (c1[i] cond c2[i]) ? v3[i] : v4[i]. - } - -********* - -Note 1: Some shortcuts are defined when the last operand is known to be -a constant (e.g. addi for add, movi for mov). - -Note 2: When using TCG, the opcodes must never be generated directly -as some of them may not be available as "real" opcodes. Always use the -function tcg_gen_xxx(args). - -4) Backend - -tcg-target.h contains the target specific definitions. tcg-target.c.inc -contains the target specific code; it is #included by tcg/tcg.c, rather -than being a standalone C file. - -4.1) Assumptions - -The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or -64 bit. It is expected that the pointer has the same size as the word. - -On a 32 bit target, all 64 bit operations are converted to 32 bits. A -few specific operations must be implemented to allow it (see add2_i32, -sub2_i32, brcond2_i32). - -On a 64 bit target, the values are transferred between 32 and 64-bit -registers using the following ops: -- trunc_shr_i64_i32 -- ext_i32_i64 -- extu_i32_i64 - -They ensure that the values are correctly truncated or extended when -moved from a 32-bit to a 64-bit register or vice-versa. Note that the -trunc_shr_i64_i32 is an optional op. It is not necessary to implement -it if all the following conditions are met: -- 64-bit registers can hold 32-bit values -- 32-bit values in a 64-bit register do not need to stay zero or - sign extended -- all 32-bit TCG ops ignore the high part of 64-bit registers - -Floating point operations are not supported in this version. A -previous incarnation of the code generator had full support of them, -but it is better to concentrate on integer operations first. - -4.2) Constraints - -GCC like constraints are used to define the constraints of every -instruction. Memory constraints are not supported in this -version. Aliases are specified in the input operands as for GCC. - -The same register may be used for both an input and an output, even when -they are not explicitly aliased. If an op expands to multiple target -instructions then care must be taken to avoid clobbering input values. -GCC style "early clobber" outputs are supported, with '&'. - -A target can define specific register or constant constraints. If an -operation uses a constant input constraint which does not allow all -constants, it must also accept registers in order to have a fallback. -The constraint 'i' is defined generically to accept any constant. -The constraint 'r' is not defined generically, but is consistently -used by each backend to indicate all registers. - -The movi_i32 and movi_i64 operations must accept any constants. - -The mov_i32 and mov_i64 operations must accept any registers of the -same type. - -The ld/st/sti instructions must accept signed 32 bit constant offsets. -This can be implemented by reserving a specific register in which to -compute the address if the offset is too big. - -The ld/st instructions must accept any destination (ld) or source (st) -register. - -The sti instruction may fail if it cannot store the given constant. - -4.3) Function call assumptions - -- The only supported types for parameters and return value are: 32 and - 64 bit integers and pointer. -- The stack grows downwards. -- The first N parameters are passed in registers. -- The next parameters are passed on the stack by storing them as words. -- Some registers are clobbered during the call. -- The function can return 0 or 1 value in registers. On a 32 bit - target, functions must be able to return 2 values in registers for - 64 bit return type. - -5) Recommended coding rules for best performance - -- Use globals to represent the parts of the QEMU CPU state which are - often modified, e.g. the integer registers and the condition - codes. TCG will be able to use host registers to store them. - -- Avoid globals stored in fixed registers. They must be used only to - store the pointer to the CPU state and possibly to store a pointer - to a register window. - -- Use temporaries. Use local temporaries only when really needed, - e.g. when you need to use a value after a jump. Local temporaries - introduce a performance hit in the current TCG implementation: their - content is saved to memory at end of each basic block. - -- Free temporaries and local temporaries when they are no longer used - (tcg_temp_free). Since tcg_const_x() also creates a temporary, you - should free it after it is used. Freeing temporaries does not yield - a better generated code, but it reduces the memory usage of TCG and - the speed of the translation. - -- Don't hesitate to use helpers for complicated or seldom used guest - instructions. There is little performance advantage in using TCG to - implement guest instructions taking more than about twenty TCG - instructions. Note that this rule of thumb is more applicable to - helpers doing complex logic or arithmetic, where the C compiler has - scope to do a good job of optimisation; it is less relevant where - the instruction is mostly doing loads and stores, and in those cases - inline TCG may still be faster for longer sequences. - -- The hard limit on the number of TCG instructions you can generate - per guest instruction is set by MAX_OP_PER_INSTR in exec-all.h -- - you cannot exceed this without risking a buffer overrun. - -- Use the 'discard' instruction if you know that TCG won't be able to - prove that a given global is "dead" at a given program point. The - x86 guest uses it to improve the condition codes optimisation. diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 5e67f881f10a..ad1816e32d6e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1261,7 +1261,7 @@ static inline void tcg_out_shl(TCGContext *s, TCGType ext, { int bits = ext ? 64 : 32; int max = bits - 1; - tcg_out_ubfm(s, ext, rd, rn, bits - (m & max), max - (m & max)); + tcg_out_ubfm(s, ext, rd, rn, (bits - m) & max, (max - m) & max); } static inline void tcg_out_shr(TCGContext *s, TCGType ext, @@ -1336,22 +1336,23 @@ static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) } } -static inline void tcg_out_callr(TCGContext *s, TCGReg reg) -{ - tcg_out_insn(s, 3207, BLR, reg); -} - -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *target) { ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; if (offset == sextract64(offset, 0, 26)) { tcg_out_insn(s, 3206, BL, offset); } else { tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); - tcg_out_callr(s, TCG_REG_TMP); + tcg_out_insn(s, 3207, BLR, TCG_REG_TMP); } } +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, + const TCGHelperInfo *info) +{ + tcg_out_call_int(s, target); +} + void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) { @@ -1557,7 +1558,7 @@ static void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target) */ static void * const qemu_ld_helpers[MO_SIZE + 1] = { [MO_8] = helper_ret_ldub_mmu, -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN [MO_16] = helper_be_lduw_mmu, [MO_32] = helper_be_ldul_mmu, [MO_64] = helper_be_ldq_mmu, @@ -1574,7 +1575,7 @@ static void * const qemu_ld_helpers[MO_SIZE + 1] = { */ static void * const qemu_st_helpers[MO_SIZE + 1] = { [MO_8] = helper_ret_stb_mmu, -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN [MO_16] = helper_be_stw_mmu, [MO_32] = helper_be_stl_mmu, [MO_64] = helper_be_stq_mmu, @@ -1599,7 +1600,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg); tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, oi); tcg_out_adr(s, TCG_REG_X3, lb->raddr); - tcg_out_call(s, qemu_ld_helpers[opc & MO_SIZE]); + tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SIZE]); if (opc & MO_SIGN) { tcg_out_sxt(s, lb->type, size, lb->datalo_reg, TCG_REG_X0); } else { @@ -1625,7 +1626,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_mov(s, size == MO_64, TCG_REG_X2, lb->datalo_reg); tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, oi); tcg_out_adr(s, TCG_REG_X4, lb->raddr); - tcg_out_call(s, qemu_st_helpers[opc & MO_SIZE]); + tcg_out_call_int(s, qemu_st_helpers[opc & MO_SIZE]); tcg_out_goto(s, lb->raddr); return true; } @@ -1916,24 +1917,21 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_goto_tb: - if (s->tb_jmp_insn_offset != NULL) { - /* TCG_TARGET_HAS_direct_jump */ - /* Ensure that ADRP+ADD are 8-byte aligned so that an atomic - write can be used to patch the target address. */ - if ((uintptr_t)s->code_ptr & 7) { - tcg_out32(s, NOP); - } - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); - /* actual branch destination will be patched by - tb_target_set_jmp_target later. */ - tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0); - tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0); - } else { - /* !TCG_TARGET_HAS_direct_jump */ - tcg_debug_assert(s->tb_jmp_target_addr != NULL); - intptr_t offset = tcg_pcrel_diff(s, (s->tb_jmp_target_addr + a0)) >> 2; - tcg_out_insn(s, 3305, LDR, offset, TCG_REG_TMP); + tcg_debug_assert(s->tb_jmp_insn_offset != NULL); + /* + * Ensure that ADRP+ADD are 8-byte aligned so that an atomic + * write can be used to patch the target address. + */ + if ((uintptr_t)s->code_ptr & 7) { + tcg_out32(s, NOP); } + s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + /* + * actual branch destination will be patched by + * tb_target_set_jmp_target later + */ + tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0); + tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0); tcg_out_insn(s, 3207, BR, TCG_REG_TMP); set_jmp_reset_offset(s, a0); break; diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 485f685bd2f9..413a5410c503 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -16,7 +16,6 @@ #define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_TLB_DISPLACEMENT_BITS 24 #define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) -#undef TCG_TARGET_STACK_GROWSUP typedef enum { TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, @@ -52,8 +51,9 @@ typedef enum { /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_SP #define TCG_TARGET_STACK_ALIGN 16 -#define TCG_TARGET_CALL_ALIGN_ARGS 1 #define TCG_TARGET_CALL_STACK_OFFSET 0 +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 4bc0420f4d2f..9245ea86d056 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1131,7 +1131,7 @@ static void tcg_out_goto(TCGContext *s, ARMCond cond, const tcg_insn_unit *addr) * The call case is mostly used for helpers - so it's not unreasonable * for them to be beyond branch range. */ -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr) +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *addr) { intptr_t addri = (intptr_t)addr; ptrdiff_t disp = tcg_pcrel_diff(s, addr); @@ -1150,6 +1150,12 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr) tcg_out_blx_reg(s, COND_AL, TCG_REG_TMP); } +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr, + const TCGHelperInfo *info) +{ + tcg_out_call_int(s, addr); +} + static void tcg_out_goto_label(TCGContext *s, ARMCond cond, TCGLabel *l) { if (l->has_value) { @@ -1296,7 +1302,7 @@ static void tcg_out_vldst(TCGContext *s, ARMInsn insn, static void * const qemu_ld_helpers[MO_SSIZE + 1] = { [MO_UB] = helper_ret_ldub_mmu, [MO_SB] = helper_ret_ldsb_mmu, -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN [MO_UW] = helper_be_lduw_mmu, [MO_UL] = helper_be_ldul_mmu, [MO_UQ] = helper_be_ldq_mmu, @@ -1316,7 +1322,7 @@ static void * const qemu_ld_helpers[MO_SSIZE + 1] = { */ static void * const qemu_st_helpers[MO_SIZE + 1] = { [MO_8] = helper_ret_stb_mmu, -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN [MO_16] = helper_be_stw_mmu, [MO_32] = helper_be_stl_mmu, [MO_64] = helper_be_stq_mmu, @@ -1515,7 +1521,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) argreg = tcg_out_arg_reg32(s, argreg, TCG_REG_R14); /* Use the canonical unsigned helpers and minimize icache usage. */ - tcg_out_call(s, qemu_ld_helpers[opc & MO_SIZE]); + tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SIZE]); datalo = lb->datalo_reg; datahi = lb->datahi_reg; diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 7e96495392fe..b7843d2d5417 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -30,7 +30,6 @@ extern int arm_arch; #define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7) -#undef TCG_TARGET_STACK_GROWSUP #define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_TLB_DISPLACEMENT_BITS 16 #define MAX_CODE_GEN_BUFFER_SIZE UINT32_MAX @@ -89,8 +88,9 @@ extern bool use_neon_instructions; /* used for function call generation */ #define TCG_TARGET_STACK_ALIGN 8 -#define TCG_TARGET_CALL_ALIGN_ARGS 1 #define TCG_TARGET_CALL_STACK_OFFSET 0 +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN /* optional instructions */ #define TCG_TARGET_HAS_ext8s_i32 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index b5c615985341..58bd5873f5dd 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -375,7 +375,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) #define OPC_PSLLQ (0xf3 | P_EXT | P_DATA16) #define OPC_PSRAW (0xe1 | P_EXT | P_DATA16) #define OPC_PSRAD (0xe2 | P_EXT | P_DATA16) -#define OPC_VPSRAQ (0x72 | P_EXT | P_DATA16 | P_VEXW | P_EVEX) +#define OPC_VPSRAQ (0xe2 | P_EXT | P_DATA16 | P_VEXW | P_EVEX) #define OPC_PSRLW (0xd1 | P_EXT | P_DATA16) #define OPC_PSRLD (0xd2 | P_EXT | P_DATA16) #define OPC_PSRLQ (0xd3 | P_EXT | P_DATA16) @@ -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); @@ -1661,7 +1661,8 @@ static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest) } } -static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, + const TCGHelperInfo *info) { tcg_out_branch(s, 1, dest); } @@ -1885,7 +1886,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) (uintptr_t)l->raddr); } - tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); + tcg_out_branch(s, 1, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); data_reg = l->datalo_reg; switch (opc & MO_SSIZE) { diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 00fcbe297de8..7edb7f1d9a2c 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -98,6 +98,8 @@ typedef enum { #else #define TCG_TARGET_CALL_STACK_OFFSET 0 #endif +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL extern bool have_bmi1; extern bool have_popcnt; diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index a3debf6da793..c9e99e8ec35e 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -567,7 +567,8 @@ static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) } } -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, + const TCGHelperInfo *info) { tcg_out_call_int(s, arg, false); } @@ -760,7 +761,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A2, oi); tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, (tcg_target_long)l->raddr); - tcg_out_call(s, qemu_ld_helpers[size]); + tcg_out_call_int(s, qemu_ld_helpers[size], false); switch (opc & MO_SSIZE) { case MO_SB: @@ -821,7 +822,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, oi); tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A4, (tcg_target_long)l->raddr); - tcg_out_call(s, qemu_st_helpers[size]); + tcg_out_call_int(s, qemu_st_helpers[size], false); return tcg_out_goto(s, l->raddr); } @@ -1031,6 +1032,36 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) #endif } +/* LoongArch uses `andi zero, zero, 0` as NOP. */ +#define NOP OPC_ANDI +static void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, NOP); +} + +void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, + uintptr_t jmp_rw, uintptr_t addr) +{ + tcg_insn_unit i1, i2; + ptrdiff_t upper, lower; + ptrdiff_t offset = (ptrdiff_t)(addr - jmp_rx) >> 2; + + if (offset == sextreg(offset, 0, 26)) { + i1 = encode_sd10k16_insn(OPC_B, offset); + i2 = NOP; + } else { + tcg_debug_assert(offset == sextreg(offset, 0, 36)); + lower = (int16_t)offset; + upper = (offset - lower) >> 16; + + i1 = encode_dsj20_insn(OPC_PCADDU18I, TCG_REG_TMP0, upper); + i2 = encode_djsk16_insn(OPC_JIRL, TCG_REG_ZERO, TCG_REG_TMP0, lower); + } + uint64_t pair = ((uint64_t)i2 << 32) | i1; + qatomic_set((uint64_t *)jmp_rw, pair); + flush_idcache_range(jmp_rx, jmp_rw, 8); +} + /* * Entry-points */ @@ -1058,10 +1089,20 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_goto_tb: - assert(s->tb_jmp_insn_offset == 0); - /* indirect jump method */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, - (uintptr_t)(s->tb_jmp_target_addr + a0)); + tcg_debug_assert(s->tb_jmp_insn_offset != NULL); + /* + * Ensure that patch area is 8-byte aligned so that an + * atomic write can be used to patch the target address. + */ + if ((uintptr_t)s->code_ptr & 7) { + tcg_out_nop(s); + } + s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + /* + * actual branch destination will be patched by + * tb_target_set_jmp_target later + */ + tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0); tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); set_jmp_reset_offset(s, a0); break; diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index d58a6162f224..e5f7a1f09d2f 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -42,7 +42,11 @@ #define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_NB_REGS 32 -#define MAX_CODE_GEN_BUFFER_SIZE SIZE_MAX +/* + * PCADDU18I + JIRL sequence can give 20 + 16 + 2 = 38 bits + * signed offset, which is +/- 128 GiB. + */ +#define MAX_CODE_GEN_BUFFER_SIZE (128 * GiB) typedef enum { TCG_REG_ZERO, @@ -88,8 +92,9 @@ typedef enum { /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_SP #define TCG_TARGET_STACK_ALIGN 16 -#define TCG_TARGET_CALL_ALIGN_ARGS 1 #define TCG_TARGET_CALL_STACK_OFFSET 0 +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 0 @@ -123,7 +128,7 @@ typedef enum { #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 -#define TCG_TARGET_HAS_direct_jump 0 +#define TCG_TARGET_HAS_direct_jump 1 #define TCG_TARGET_HAS_brcond2 0 #define TCG_TARGET_HAS_setcond2 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -166,7 +171,6 @@ typedef enum { #define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 -/* not defined -- call should be eliminated at compile time */ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); #define TCG_TARGET_DEFAULT_MO (0) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 993149d18a56..292e490b5c8e 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -26,7 +26,7 @@ #include "../tcg-ldst.c.inc" -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define MIPS_BE 1 #else # define MIPS_BE 0 @@ -1020,7 +1020,8 @@ static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) } } -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, + const TCGHelperInfo *info) { tcg_out_call_int(s, arg, false); tcg_out_nop(s); diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 766921317563..15721c3e42ec 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -83,10 +83,12 @@ typedef enum { #define TCG_TARGET_STACK_ALIGN 16 #if _MIPS_SIM == _ABIO32 # define TCG_TARGET_CALL_STACK_OFFSET 16 +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN #else # define TCG_TARGET_CALL_STACK_OFFSET 0 +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL #endif -#define TCG_TARGET_CALL_ALIGN_ARGS 1 +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL /* MOVN/MOVZ instructions detection */ #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \ diff --git a/tcg/optimize.c b/tcg/optimize.c index ae081ab29c08..763bca9ea6cb 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -667,9 +667,7 @@ static void init_arguments(OptContext *ctx, TCGOp *op, int nb_args) { for (int i = 0; i < nb_args; i++) { TCGTemp *ts = arg_temp(op->args[i]); - if (ts) { - init_ts_info(ctx, ts); - } + init_ts_info(ctx, ts); } } @@ -680,7 +678,7 @@ static void copy_propagate(OptContext *ctx, TCGOp *op, for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) { TCGTemp *ts = arg_temp(op->args[i]); - if (ts && ts_is_copy(ts)) { + if (ts_is_copy(ts)) { op->args[i] = temp_arg(find_better_copy(s, ts)); } } @@ -962,7 +960,7 @@ static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add) rh = op->args[1]; /* The proper opcode is supplied by tcg_opt_gen_mov. */ - op2 = tcg_op_insert_before(ctx->tcg, op, 0); + op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2); tcg_opt_gen_movi(ctx, op, rl, al); tcg_opt_gen_movi(ctx, op2, rh, ah); @@ -1613,7 +1611,7 @@ static bool fold_multiply2(OptContext *ctx, TCGOp *op) rh = op->args[1]; /* The proper opcode is supplied by tcg_opt_gen_mov. */ - op2 = tcg_op_insert_before(ctx->tcg, op, 0); + op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2); tcg_opt_gen_movi(ctx, op, rl, l); tcg_opt_gen_movi(ctx, op2, rh, h); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 1f3c5c171cb7..e0621463f674 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -42,10 +42,17 @@ # else # error "Unknown ABI" # endif -#endif +#endif +#if TCG_TARGET_REG_BITS == 64 +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND +#else +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#endif #ifdef _CALL_SYSV -# define TCG_TARGET_CALL_ALIGN_ARGS 1 +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN +#else +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL #endif /* For some memory operations, we need a scratch that isn't R0. For the AIX @@ -371,6 +378,8 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) #define MULHWU XO31( 11) #define DIVW XO31(491) #define DIVWU XO31(459) +#define MODSW XO31(779) +#define MODUW XO31(267) #define CMP XO31( 0) #define CMPL XO31( 32) #define LHBRX XO31(790) @@ -403,6 +412,8 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) #define MULHDU XO31( 9) #define DIVD XO31(489) #define DIVDU XO31(457) +#define MODSD XO31(777) +#define MODUD XO31(265) #define LBZX XO31( 87) #define LHZX XO31(279) @@ -1832,54 +1843,112 @@ static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, static void tcg_out_mb(TCGContext *s, TCGArg a0) { - uint32_t insn = HWSYNC; - a0 &= TCG_MO_ALL; - if (a0 == TCG_MO_LD_LD) { + uint32_t insn; + + if (a0 & TCG_MO_ST_LD) { + insn = HWSYNC; + } else { insn = LWSYNC; - } else if (a0 == TCG_MO_ST_ST) { - insn = EIEIO; } + tcg_out32(s, insn); } -void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) +static inline uint64_t make_pair(tcg_insn_unit i1, tcg_insn_unit i2) { - 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; - - /* 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); - } -#ifdef HOST_WORDS_BIGENDIAN - pair = (uint64_t)i1 << 32 | 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 - pair = (uint64_t)i2 << 32 | i1; + qemu_build_not_reached(); #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 { +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) +{ + 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; + + 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, @@ -1933,7 +2002,8 @@ static void tcg_out_call_int(TCGContext *s, int lk, #endif } -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, + const TCGHelperInfo *info) { tcg_out_call_int(s, LK, target); } @@ -2140,9 +2210,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) lo = lb->addrlo_reg; hi = lb->addrhi_reg; if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { -#ifdef TCG_TARGET_CALL_ALIGN_ARGS - arg |= 1; -#endif + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); tcg_out_mov(s, TCG_TYPE_I32, arg++, hi); tcg_out_mov(s, TCG_TYPE_I32, arg++, lo); } else { @@ -2154,7 +2222,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_movi(s, TCG_TYPE_I32, arg++, oi); tcg_out32(s, MFSPR | RT(arg) | LR); - tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); + tcg_out_call_int(s, LK, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); lo = lb->datalo_reg; hi = lb->datahi_reg; @@ -2188,9 +2256,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) lo = lb->addrlo_reg; hi = lb->addrhi_reg; if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { -#ifdef TCG_TARGET_CALL_ALIGN_ARGS - arg |= 1; -#endif + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); tcg_out_mov(s, TCG_TYPE_I32, arg++, hi); tcg_out_mov(s, TCG_TYPE_I32, arg++, lo); } else { @@ -2204,9 +2270,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) if (TCG_TARGET_REG_BITS == 32) { switch (s_bits) { case MO_64: -#ifdef TCG_TARGET_CALL_ALIGN_ARGS - arg |= 1; -#endif + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); tcg_out_mov(s, TCG_TYPE_I32, arg++, hi); /* FALLTHRU */ case MO_32: @@ -2227,7 +2291,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_movi(s, TCG_TYPE_I32, arg++, oi); tcg_out32(s, MFSPR | RT(arg) | LR); - tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); + tcg_out_call_int(s, LK, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); tcg_out_b(s, 0, lb->raddr); return true; @@ -2262,9 +2326,8 @@ static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l) if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { TCGReg arg = TCG_REG_R4; -#ifdef TCG_TARGET_CALL_ALIGN_ARGS - arg |= 1; -#endif + + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); if (l->addrlo_reg != arg) { tcg_out_mov(s, TCG_TYPE_I32, arg, l->addrhi_reg); tcg_out_mov(s, TCG_TYPE_I32, arg + 1, l->addrlo_reg); @@ -2463,7 +2526,6 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count) /* Parameters for function call generation, used in tcg.c. */ #define TCG_TARGET_STACK_ALIGN 16 -#define TCG_TARGET_EXTEND_ARGS 1 #ifdef _CALL_AIX # define LINK_AREA_SIZE (6 * SZR) @@ -2569,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); @@ -2805,6 +2867,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out32(s, DIVWU | TAB(args[0], args[1], args[2])); break; + case INDEX_op_rem_i32: + tcg_out32(s, MODSW | TAB(args[0], args[1], args[2])); + break; + + case INDEX_op_remu_i32: + tcg_out32(s, MODUW | TAB(args[0], args[1], args[2])); + break; + case INDEX_op_shl_i32: if (const_args[2]) { /* Limit immediate shift count lest we create an illegal insn. */ @@ -2946,6 +3016,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_divu_i64: tcg_out32(s, DIVDU | TAB(args[0], args[1], args[2])); break; + case INDEX_op_rem_i64: + tcg_out32(s, MODSD | TAB(args[0], args[1], args[2])); + break; + case INDEX_op_remu_i64: + tcg_out32(s, MODUD | TAB(args[0], args[1], args[2])); + break; case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args, false); @@ -3235,7 +3311,7 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, tcg_out_mem_long(s, 0, LVEBX, out, base, offset); } elt = extract32(offset, 0, 4); -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN elt ^= 15; #endif tcg_out32(s, VSPLTB | VRT(out) | VRB(out) | (elt << 16)); @@ -3248,7 +3324,7 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, tcg_out_mem_long(s, 0, LVEHX, out, base, offset); } elt = extract32(offset, 1, 3); -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN elt ^= 7; #endif tcg_out32(s, VSPLTH | VRT(out) | VRB(out) | (elt << 16)); @@ -3261,7 +3337,7 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, tcg_debug_assert((offset & 3) == 0); tcg_out_mem_long(s, 0, LVEWX, out, base, offset); elt = extract32(offset, 2, 2); -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN elt ^= 3; #endif tcg_out32(s, VSPLTW | VRT(out) | VRB(out) | (elt << 16)); @@ -3275,7 +3351,7 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, tcg_out_mem_long(s, 0, LVX, out, base, offset & -16); tcg_out_vsldoi(s, TCG_VEC_TMP1, out, out, 8); elt = extract32(offset, 3, 1); -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN elt = !elt; #endif if (elt) { @@ -3721,6 +3797,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_div_i32: case INDEX_op_divu_i32: + case INDEX_op_rem_i32: + case INDEX_op_remu_i32: case INDEX_op_nand_i32: case INDEX_op_nor_i32: case INDEX_op_muluh_i32: @@ -3731,6 +3809,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_nor_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: + case INDEX_op_rem_i64: + case INDEX_op_remu_i64: case INDEX_op_mulsh_i64: case INDEX_op_muluh_i64: return C_O1_I2(r, r, r); @@ -4008,3 +4088,4 @@ void tcg_register_jit(const void *buf, size_t buf_size) #undef VMULOUB #undef VMULOUH #undef VMULOUW +#undef VMSUMUHM diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index e6cf72503f87..b5cd225cfa4b 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -83,7 +83,7 @@ extern bool have_vsx; /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 -#define TCG_TARGET_HAS_rem_i32 0 +#define TCG_TARGET_HAS_rem_i32 have_isa_3_00 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_ext8s_i32 1 #define TCG_TARGET_HAS_ext16s_i32 1 @@ -117,7 +117,7 @@ extern bool have_vsx; #define TCG_TARGET_HAS_extrl_i64_i32 0 #define TCG_TARGET_HAS_extrh_i64_i32 0 #define TCG_TARGET_HAS_div_i64 1 -#define TCG_TARGET_HAS_rem_i64 0 +#define TCG_TARGET_HAS_rem_i64 have_isa_3_00 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_ext8s_i64 1 #define TCG_TARGET_HAS_ext16s_i64 1 diff --git a/tcg/region.c b/tcg/region.c index 97ca5291d52f..88d6bb273f18 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -488,14 +488,14 @@ static int alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp) /* page-align the beginning and end of the buffer */ buf = static_code_gen_buffer; end = static_code_gen_buffer + sizeof(static_code_gen_buffer); - buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size); - end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size); + buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size()); + end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size()); size = end - buf; /* Honor a command-line option limiting the size of the buffer. */ if (size > tb_size) { - size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size); + size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size()); } region.start_aligned = buf; @@ -548,7 +548,7 @@ static int alloc_code_gen_buffer_anon(size_t size, int prot, #ifdef CONFIG_POSIX #include "qemu/memfd.h" -static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp) +static int alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp) { void *buf_rw = NULL, *buf_rx = MAP_FAILED; int fd = -1; @@ -729,7 +729,7 @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp) */ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus) { - const size_t page_size = qemu_real_host_page_size; + const size_t page_size = qemu_real_host_page_size(); size_t region_size; int have_prot, need_prot; diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 6409d9c3d54f..f741e0582d59 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -154,13 +154,26 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) if ((ct & TCG_CT_CONST_ZERO) && val == 0) { return 1; } - if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) { + /* + * Sign extended from 12 bits: [-0x800, 0x7ff]. + * Used for most arithmetic, as this is the isa field. + */ + if ((ct & TCG_CT_CONST_S12) && val >= -0x800 && val <= 0x7ff) { return 1; } - if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) { + /* + * Sign extended from 12 bits, negated: [-0x7ff, 0x800]. + * Used for subtraction, where a constant must be handled by ADDI. + */ + if ((ct & TCG_CT_CONST_N12) && val >= -0x7ff && val <= 0x800) { return 1; } - if ((ct & TCG_CT_CONST_M12) && val >= -0xfff && val <= 0xfff) { + /* + * Sign extended from 12 bits, +/- matching: [-0x7ff, 0x7ff]. + * Used by addsub2, which may need the negative operation, + * and requires the modified constant to be representable. + */ + if ((ct & TCG_CT_CONST_M12) && val >= -0x7ff && val <= 0x7ff) { return 1; } return 0; @@ -687,9 +700,15 @@ static void tcg_out_addsub2(TCGContext *s, if (cbl) { tcg_out_opc_imm(s, opc_addi, rl, al, bl); tcg_out_opc_imm(s, OPC_SLTIU, TCG_REG_TMP0, rl, bl); - } else if (rl == al && rl == bl) { + } else if (al == bl) { + /* + * If the input regs overlap, this is a simple doubling + * and carry-out is the input msb. This special case is + * required when the output reg overlaps the input, + * but we might as well use it always. + */ tcg_out_opc_imm(s, OPC_SLTI, TCG_REG_TMP0, al, 0); - tcg_out_opc_reg(s, opc_addi, rl, al, bl); + tcg_out_opc_reg(s, opc_add, rl, al, al); } else { tcg_out_opc_reg(s, opc_add, rl, al, bl); tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_TMP0, @@ -819,7 +838,8 @@ static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) } } -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, + const TCGHelperInfo *info) { tcg_out_call_int(s, arg, false); } @@ -854,7 +874,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) static void * const qemu_ld_helpers[MO_SSIZE + 1] = { [MO_UB] = helper_ret_ldub_mmu, [MO_SB] = helper_ret_ldsb_mmu, -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN [MO_UW] = helper_be_lduw_mmu, [MO_SW] = helper_be_ldsw_mmu, [MO_UL] = helper_be_ldul_mmu, @@ -879,7 +899,7 @@ static void * const qemu_ld_helpers[MO_SSIZE + 1] = { */ static void * const qemu_st_helpers[MO_SIZE + 1] = { [MO_8] = helper_ret_stb_mmu, -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN [MO_16] = helper_be_stw_mmu, [MO_32] = helper_be_stl_mmu, [MO_64] = helper_be_stq_mmu, @@ -904,9 +924,9 @@ static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) tcg_debug_assert(ok); } -static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl, - TCGReg addrh, MemOpIdx oi, - tcg_insn_unit **label_ptr, bool is_load) +static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addrl, + TCGReg addrh, MemOpIdx oi, + tcg_insn_unit **label_ptr, bool is_load) { MemOp opc = get_memop(oi); unsigned s_bits = opc & MO_SIZE; @@ -956,6 +976,7 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl, addrl = TCG_REG_TMP0; } tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP2, addrl); + return TCG_REG_TMP0; } static void add_qemu_ldst_label(TCGContext *s, int is_ld, MemOpIdx oi, @@ -1002,7 +1023,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) tcg_out_movi(s, TCG_TYPE_PTR, a2, oi); tcg_out_movi(s, TCG_TYPE_PTR, a3, (tcg_target_long)l->raddr); - tcg_out_call(s, qemu_ld_helpers[opc & MO_SSIZE]); + tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SSIZE], false); tcg_out_mov(s, (opc & MO_SIZE) == MO_64, l->datalo_reg, a0); tcg_out_goto(s, l->raddr); @@ -1047,7 +1068,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) tcg_out_movi(s, TCG_TYPE_PTR, a3, oi); tcg_out_movi(s, TCG_TYPE_PTR, a4, (tcg_target_long)l->raddr); - tcg_out_call(s, qemu_st_helpers[opc & MO_SIZE]); + tcg_out_call_int(s, qemu_st_helpers[opc & MO_SIZE], false); tcg_out_goto(s, l->raddr); return true; @@ -1158,7 +1179,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) #else unsigned a_bits; #endif - TCGReg base = TCG_REG_TMP0; + TCGReg base; data_regl = *args++; data_regh = (TCG_TARGET_REG_BITS == 32 && is_64 ? *args++ : 0); @@ -1168,23 +1189,25 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) opc = get_memop(oi); #if defined(CONFIG_SOFTMMU) - tcg_out_tlb_load(s, addr_regl, addr_regh, oi, label_ptr, 1); + base = tcg_out_tlb_load(s, addr_regl, addr_regh, oi, label_ptr, 1); tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64); add_qemu_ldst_label(s, 1, oi, (is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32), data_regl, data_regh, addr_regl, addr_regh, s->code_ptr, label_ptr); #else - if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { - tcg_out_ext32u(s, base, addr_regl); - addr_regl = base; - } a_bits = get_alignment_bits(opc); if (a_bits) { tcg_out_test_alignment(s, true, addr_regl, a_bits); } + base = addr_regl; + if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { + tcg_out_ext32u(s, TCG_REG_TMP0, base); + base = TCG_REG_TMP0; + } if (guest_base != 0) { - tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl); + tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_GUEST_BASE_REG, base); + base = TCG_REG_TMP0; } tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64); #endif @@ -1230,7 +1253,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) #else unsigned a_bits; #endif - TCGReg base = TCG_REG_TMP0; + TCGReg base; data_regl = *args++; data_regh = (TCG_TARGET_REG_BITS == 32 && is_64 ? *args++ : 0); @@ -1240,23 +1263,25 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) opc = get_memop(oi); #if defined(CONFIG_SOFTMMU) - tcg_out_tlb_load(s, addr_regl, addr_regh, oi, label_ptr, 0); + base = tcg_out_tlb_load(s, addr_regl, addr_regh, oi, label_ptr, 0); tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc); add_qemu_ldst_label(s, 0, oi, (is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32), data_regl, data_regh, addr_regl, addr_regh, s->code_ptr, label_ptr); #else - if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { - tcg_out_ext32u(s, base, addr_regl); - addr_regl = base; - } a_bits = get_alignment_bits(opc); if (a_bits) { tcg_out_test_alignment(s, false, addr_regl, a_bits); } + base = addr_regl; + if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { + tcg_out_ext32u(s, TCG_REG_TMP0, base); + base = TCG_REG_TMP0; + } if (guest_base != 0) { - tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl); + tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_GUEST_BASE_REG, base); + base = TCG_REG_TMP0; } tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc); #endif diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index 11c9b3e4f4b8..232537ccea0a 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -81,8 +81,13 @@ typedef enum { /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_SP #define TCG_TARGET_STACK_ALIGN 16 -#define TCG_TARGET_CALL_ALIGN_ARGS 1 #define TCG_TARGET_CALL_STACK_OFFSET 0 +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#if TCG_TARGET_REG_BITS == 32 +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN +#else +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#endif /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 0 diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h index 426dd92e51a1..15f1c5510383 100644 --- a/tcg/s390x/tcg-target-con-set.h +++ b/tcg/s390x/tcg-target-con-set.h @@ -13,6 +13,7 @@ C_O0_I1(r) C_O0_I2(L, L) C_O0_I2(r, r) C_O0_I2(r, ri) +C_O0_I2(r, rA) C_O0_I2(v, r) C_O1_I1(r, L) C_O1_I1(r, r) @@ -22,15 +23,24 @@ C_O1_I1(v, vr) C_O1_I2(r, 0, ri) C_O1_I2(r, 0, rI) C_O1_I2(r, 0, rJ) +C_O1_I2(r, r, r) C_O1_I2(r, r, ri) +C_O1_I2(r, r, rA) +C_O1_I2(r, r, rI) +C_O1_I2(r, r, rJ) +C_O1_I2(r, r, rK) +C_O1_I2(r, r, rKR) +C_O1_I2(r, r, rNK) +C_O1_I2(r, r, rNKR) C_O1_I2(r, rZ, r) C_O1_I2(v, v, r) C_O1_I2(v, v, v) C_O1_I3(v, v, v, v) -C_O1_I4(r, r, ri, r, 0) -C_O1_I4(r, r, ri, rI, 0) -C_O2_I2(b, a, 0, r) -C_O2_I3(b, a, 0, 1, r) +C_O1_I4(r, r, ri, rI, r) +C_O1_I4(r, r, rA, rI, r) +C_O2_I2(o, m, 0, r) +C_O2_I2(o, m, r, r) +C_O2_I3(o, m, 0, 1, r) C_O2_I4(r, r, 0, 1, rA, r) C_O2_I4(r, r, 0, 1, ri, r) C_O2_I4(r, r, 0, 1, r, r) diff --git a/tcg/s390x/tcg-target-con-str.h b/tcg/s390x/tcg-target-con-str.h index 8bb0358ae51c..6fa64a1ed68c 100644 --- a/tcg/s390x/tcg-target-con-str.h +++ b/tcg/s390x/tcg-target-con-str.h @@ -11,13 +11,7 @@ REGS('r', ALL_GENERAL_REGS) REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) REGS('v', ALL_VECTOR_REGS) -/* - * A (single) even/odd pair for division. - * TODO: Add something to the register allocator to allow - * this kind of regno+1 pairing to be done more generally. - */ -REGS('a', 1u << TCG_REG_R2) -REGS('b', 1u << TCG_REG_R3) +REGS('o', 0xaaaa) /* odd numbered general regs */ /* * Define constraint letters for constants: @@ -26,4 +20,7 @@ REGS('b', 1u << TCG_REG_R3) CONST('A', TCG_CT_CONST_S33) CONST('I', TCG_CT_CONST_S16) CONST('J', TCG_CT_CONST_S32) +CONST('K', TCG_CT_CONST_P32) +CONST('N', TCG_CT_CONST_INV) +CONST('R', TCG_CT_CONST_INVRISBG) CONST('Z', TCG_CT_CONST_ZERO) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 33becd76943b..2b38fd991df6 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -33,15 +33,13 @@ #include "../tcg-pool.c.inc" #include "elf.h" -/* ??? The translation blocks produced by TCG are generally small enough to - be entirely reachable with a 16-bit displacement. Leaving the option for - a 32-bit displacement here Just In Case. */ -#define USE_LONG_BRANCHES 0 - -#define TCG_CT_CONST_S16 0x100 -#define TCG_CT_CONST_S32 0x200 -#define TCG_CT_CONST_S33 0x400 -#define TCG_CT_CONST_ZERO 0x800 +#define TCG_CT_CONST_S16 (1 << 8) +#define TCG_CT_CONST_S32 (1 << 9) +#define TCG_CT_CONST_S33 (1 << 10) +#define TCG_CT_CONST_ZERO (1 << 11) +#define TCG_CT_CONST_P32 (1 << 12) +#define TCG_CT_CONST_INV (1 << 13) +#define TCG_CT_CONST_INVRISBG (1 << 14) #define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 16) #define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32) @@ -65,12 +63,6 @@ /* A scratch register that may be be used throughout the backend. */ #define TCG_TMP0 TCG_REG_R1 -/* A scratch register that holds a pointer to the beginning of the TB. - We don't need this when we have pc-relative loads with the general - instructions extension facility. */ -#define TCG_REG_TB TCG_REG_R12 -#define USE_REG_TB (!HAVE_FACILITY(GEN_INST_EXT)) - #ifndef CONFIG_SOFTMMU #define TCG_GUEST_BASE_REG TCG_REG_R13 #endif @@ -139,16 +131,19 @@ typedef enum S390Opcode { RI_OILL = 0xa50b, RI_TMLL = 0xa701, - RIE_CGIJ = 0xec7c, - RIE_CGRJ = 0xec64, - RIE_CIJ = 0xec7e, - RIE_CLGRJ = 0xec65, - RIE_CLIJ = 0xec7f, - RIE_CLGIJ = 0xec7d, - RIE_CLRJ = 0xec77, - RIE_CRJ = 0xec76, - RIE_LOCGHI = 0xec46, - RIE_RISBG = 0xec55, + RIEb_CGRJ = 0xec64, + RIEb_CLGRJ = 0xec65, + RIEb_CLRJ = 0xec77, + RIEb_CRJ = 0xec76, + + RIEc_CGIJ = 0xec7c, + RIEc_CIJ = 0xec7e, + RIEc_CLGIJ = 0xec7d, + RIEc_CLIJ = 0xec7f, + + RIEf_RISBG = 0xec55, + + RIEg_LOCGHI = 0xec46, RRE_AGR = 0xb908, RRE_ALGR = 0xb90a, @@ -183,18 +178,35 @@ typedef enum S390Opcode { RRE_SLBGR = 0xb989, RRE_XGR = 0xb982, - RRF_LOCR = 0xb9f2, - RRF_LOCGR = 0xb9e2, - RRF_NRK = 0xb9f4, - RRF_NGRK = 0xb9e4, - RRF_ORK = 0xb9f6, - RRF_OGRK = 0xb9e6, - RRF_SRK = 0xb9f9, - RRF_SGRK = 0xb9e9, - RRF_SLRK = 0xb9fb, - RRF_SLGRK = 0xb9eb, - RRF_XRK = 0xb9f7, - RRF_XGRK = 0xb9e7, + RRFa_MGRK = 0xb9ec, + RRFa_MSRKC = 0xb9fd, + RRFa_MSGRKC = 0xb9ed, + RRFa_NCRK = 0xb9f5, + RRFa_NCGRK = 0xb9e5, + RRFa_NNRK = 0xb974, + RRFa_NNGRK = 0xb964, + RRFa_NORK = 0xb976, + RRFa_NOGRK = 0xb966, + RRFa_NRK = 0xb9f4, + RRFa_NGRK = 0xb9e4, + RRFa_NXRK = 0xb977, + RRFa_NXGRK = 0xb967, + RRFa_OCRK = 0xb975, + RRFa_OCGRK = 0xb965, + RRFa_ORK = 0xb9f6, + RRFa_OGRK = 0xb9e6, + RRFa_SRK = 0xb9f9, + RRFa_SGRK = 0xb9e9, + RRFa_SLRK = 0xb9fb, + RRFa_SLGRK = 0xb9eb, + RRFa_XRK = 0xb9f7, + RRFa_XGRK = 0xb9e7, + + RRFam_SELGR = 0xb9e3, + + RRFc_LOCR = 0xb9f2, + RRFc_LOCGR = 0xb9e2, + RRFc_POPCNT = 0xb9e1, RR_AR = 0x1a, RR_ALR = 0x1e, @@ -511,6 +523,60 @@ static bool patch_reloc(tcg_insn_unit *src_rw, int type, return false; } +static int is_const_p16(uint64_t val) +{ + for (int i = 0; i < 4; ++i) { + uint64_t mask = 0xffffull << (i * 16); + if ((val & ~mask) == 0) { + return i; + } + } + return -1; +} + +static int is_const_p32(uint64_t val) +{ + if ((val & 0xffffffff00000000ull) == 0) { + return 0; + } + if ((val & 0x00000000ffffffffull) == 0) { + return 1; + } + return -1; +} + +/* + * Accept bit patterns like these: + * 0....01....1 + * 1....10....0 + * 1..10..01..1 + * 0..01..10..0 + * Copied from gcc sources. + */ +static bool risbg_mask(uint64_t c) +{ + uint64_t lsb; + /* We don't change the number of transitions by inverting, + so make sure we start with the LSB zero. */ + if (c & 1) { + c = ~c; + } + /* Reject all zeros or all ones. */ + if (c == 0) { + return false; + } + /* Find the first transition. */ + lsb = c & -c; + /* Invert to look for a second transition. */ + c = ~c; + /* Erase the first transition. */ + c &= -lsb; + /* Find the second transition, if any. */ + lsb = c & -c; + /* Match if all the bits are 1's, or if c is zero. */ + return c == -lsb; +} + /* Test if a constant matches the constraint. */ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) { @@ -533,6 +599,20 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) return val == 0; } + if (ct & TCG_CT_CONST_INV) { + val = ~val; + } + /* + * Note that is_const_p16 is a subset of is_const_p32, + * so we don't need both constraints. + */ + if ((ct & TCG_CT_CONST_P32) && is_const_p32(val) >= 0) { + return true; + } + if ((ct & TCG_CT_CONST_INVRISBG) && risbg_mask(~val)) { + return true; + } + return 0; } @@ -549,8 +629,22 @@ static void tcg_out_insn_RRE(TCGContext *s, S390Opcode op, tcg_out32(s, (op << 16) | (r1 << 4) | r2); } -static void tcg_out_insn_RRF(TCGContext *s, S390Opcode op, - TCGReg r1, TCGReg r2, int m3) +/* RRF-a without the m4 field */ +static void tcg_out_insn_RRFa(TCGContext *s, S390Opcode op, + TCGReg r1, TCGReg r2, TCGReg r3) +{ + tcg_out32(s, (op << 16) | (r3 << 12) | (r1 << 4) | r2); +} + +/* RRF-a with the m4 field */ +static void tcg_out_insn_RRFam(TCGContext *s, S390Opcode op, + TCGReg r1, TCGReg r2, TCGReg r3, int m4) +{ + tcg_out32(s, (op << 16) | (r3 << 12) | (m4 << 8) | (r1 << 4) | r2); +} + +static void tcg_out_insn_RRFc(TCGContext *s, S390Opcode op, + TCGReg r1, TCGReg r2, int m3) { tcg_out32(s, (op << 16) | (m3 << 12) | (r1 << 4) | r2); } @@ -560,7 +654,7 @@ static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2) tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff)); } -static void tcg_out_insn_RIE(TCGContext *s, S390Opcode op, TCGReg r1, +static void tcg_out_insn_RIEg(TCGContext *s, S390Opcode op, TCGReg r1, int i2, int m3) { tcg_out16(s, (op & 0xff00) | (r1 << 4) | m3); @@ -780,14 +874,22 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg dst, TCGReg src) return true; } -static const S390Opcode lli_insns[4] = { +static const S390Opcode li_insns[4] = { RI_LLILL, RI_LLILH, RI_LLIHL, RI_LLIHH }; +static const S390Opcode oi_insns[4] = { + RI_OILL, RI_OILH, RI_OIHL, RI_OIHH +}; +static const S390Opcode lif_insns[2] = { + RIL_LLILF, RIL_LLIHF, +}; -static bool maybe_out_small_movi(TCGContext *s, TCGType type, - TCGReg ret, tcg_target_long sval) +/* load a register with an immediate value */ +static void tcg_out_movi(TCGContext *s, TCGType type, + TCGReg ret, tcg_target_long sval) { tcg_target_ulong uval = sval; + ptrdiff_t pc_off; int i; if (type == TCG_TYPE_I32) { @@ -798,100 +900,51 @@ static bool maybe_out_small_movi(TCGContext *s, TCGType type, /* Try all 32-bit insns that can load it in one go. */ if (sval >= -0x8000 && sval < 0x8000) { tcg_out_insn(s, RI, LGHI, ret, sval); - return true; - } - - for (i = 0; i < 4; i++) { - tcg_target_long mask = 0xffffull << i*16; - if ((uval & mask) == uval) { - tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i*16); - return true; - } - } - - return false; -} - -/* load a register with an immediate value */ -static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, - tcg_target_long sval, bool in_prologue) -{ - tcg_target_ulong uval; - - /* Try all 32-bit insns that can load it in one go. */ - if (maybe_out_small_movi(s, type, ret, sval)) { return; } - uval = sval; - if (type == TCG_TYPE_I32) { - uval = (uint32_t)sval; - sval = (int32_t)sval; + i = is_const_p16(uval); + if (i >= 0) { + tcg_out_insn_RI(s, li_insns[i], ret, uval >> (i * 16)); + return; } /* Try all 48-bit insns that can load it in one go. */ - if (HAVE_FACILITY(EXT_IMM)) { - if (sval == (int32_t)sval) { - tcg_out_insn(s, RIL, LGFI, ret, sval); - return; - } - if (uval <= 0xffffffff) { - tcg_out_insn(s, RIL, LLILF, ret, uval); - return; - } - if ((uval & 0xffffffff) == 0) { - tcg_out_insn(s, RIL, LLIHF, ret, uval >> 32); - return; - } + if (sval == (int32_t)sval) { + tcg_out_insn(s, RIL, LGFI, ret, sval); + return; } - /* Try for PC-relative address load. For odd addresses, - attempt to use an offset from the start of the TB. */ - if ((sval & 1) == 0) { - ptrdiff_t off = tcg_pcrel_diff(s, (void *)sval) >> 1; - if (off == (int32_t)off) { - tcg_out_insn(s, RIL, LARL, ret, off); - return; - } - } else if (USE_REG_TB && !in_prologue) { - ptrdiff_t off = tcg_tbrel_diff(s, (void *)sval); - if (off == sextract64(off, 0, 20)) { - /* This is certain to be an address within TB, and therefore - OFF will be negative; don't try RX_LA. */ - tcg_out_insn(s, RXY, LAY, ret, TCG_REG_TB, TCG_REG_NONE, off); - return; - } + i = is_const_p32(uval); + if (i >= 0) { + tcg_out_insn_RIL(s, lif_insns[i], ret, uval >> (i * 32)); + return; } - /* A 32-bit unsigned value can be loaded in 2 insns. And given - that LLILL, LLIHL, LLILF above did not succeed, we know that - both insns are required. */ - if (uval <= 0xffffffff) { - tcg_out_insn(s, RI, LLILL, ret, uval); - tcg_out_insn(s, RI, IILH, ret, uval >> 16); + /* Try for PC-relative address load. For odd addresses, add one. */ + pc_off = tcg_pcrel_diff(s, (void *)sval) >> 1; + if (pc_off == (int32_t)pc_off) { + tcg_out_insn(s, RIL, LARL, ret, pc_off); + if (sval & 1) { + tcg_out_insn(s, RI, AGHI, ret, 1); + } return; } - /* Otherwise, stuff it in the constant pool. */ - if (HAVE_FACILITY(GEN_INST_EXT)) { - tcg_out_insn(s, RIL, LGRL, ret, 0); - new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2); - } else if (USE_REG_TB && !in_prologue) { - tcg_out_insn(s, RXY, LG, ret, TCG_REG_TB, TCG_REG_NONE, 0); - new_pool_label(s, sval, R_390_20, s->code_ptr - 2, - tcg_tbrel_diff(s, NULL)); + /* Otherwise, load it by parts. */ + i = is_const_p16((uint32_t)uval); + if (i >= 0) { + tcg_out_insn_RI(s, li_insns[i], ret, uval >> (i * 16)); } else { - TCGReg base = ret ? ret : TCG_TMP0; - tcg_out_insn(s, RIL, LARL, base, 0); - new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2); - tcg_out_insn(s, RXY, LG, ret, base, TCG_REG_NONE, 0); + tcg_out_insn(s, RIL, LLILF, ret, uval); + } + uval >>= 32; + i = is_const_p16(uval); + if (i >= 0) { + tcg_out_insn_RI(s, oi_insns[i + 2], ret, uval >> (i * 16)); + } else { + tcg_out_insn(s, RIL, OIHF, ret, uval); } -} - -static void tcg_out_movi(TCGContext *s, TCGType type, - TCGReg ret, tcg_target_long sval) -{ - tcg_out_movi_int(s, type, ret, sval, false); } /* Emit a load/store type instruction. Inputs are: @@ -1020,122 +1073,33 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, return false; } -/* load data from an absolute host address */ -static void tcg_out_ld_abs(TCGContext *s, TCGType type, - TCGReg dest, const void *abs) -{ - intptr_t addr = (intptr_t)abs; - - if (HAVE_FACILITY(GEN_INST_EXT) && !(addr & 1)) { - ptrdiff_t disp = tcg_pcrel_diff(s, abs) >> 1; - if (disp == (int32_t)disp) { - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RIL, LRL, dest, disp); - } else { - tcg_out_insn(s, RIL, LGRL, dest, disp); - } - return; - } - } - if (USE_REG_TB) { - ptrdiff_t disp = tcg_tbrel_diff(s, abs); - if (disp == sextract64(disp, 0, 20)) { - tcg_out_ld(s, type, dest, TCG_REG_TB, disp); - return; - } - } - - tcg_out_movi(s, TCG_TYPE_PTR, dest, addr & ~0xffff); - tcg_out_ld(s, type, dest, dest, addr & 0xffff); -} - static inline void tcg_out_risbg(TCGContext *s, TCGReg dest, TCGReg src, int msb, int lsb, int ofs, int z) { /* Format RIE-f */ - tcg_out16(s, (RIE_RISBG & 0xff00) | (dest << 4) | src); + tcg_out16(s, (RIEf_RISBG & 0xff00) | (dest << 4) | src); tcg_out16(s, (msb << 8) | (z << 7) | lsb); - tcg_out16(s, (ofs << 8) | (RIE_RISBG & 0xff)); + tcg_out16(s, (ofs << 8) | (RIEf_RISBG & 0xff)); } static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) { - if (HAVE_FACILITY(EXT_IMM)) { - tcg_out_insn(s, RRE, LGBR, dest, src); - return; - } - - if (type == TCG_TYPE_I32) { - if (dest == src) { - tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 24); - } else { - tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 24); - } - tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 24); - } else { - tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 56); - tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 56); - } + tcg_out_insn(s, RRE, LGBR, dest, src); } static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) { - if (HAVE_FACILITY(EXT_IMM)) { - tcg_out_insn(s, RRE, LLGCR, dest, src); - return; - } - - if (dest == src) { - tcg_out_movi(s, type, TCG_TMP0, 0xff); - src = TCG_TMP0; - } else { - tcg_out_movi(s, type, dest, 0xff); - } - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, NR, dest, src); - } else { - tcg_out_insn(s, RRE, NGR, dest, src); - } + tcg_out_insn(s, RRE, LLGCR, dest, src); } static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) { - if (HAVE_FACILITY(EXT_IMM)) { - tcg_out_insn(s, RRE, LGHR, dest, src); - return; - } - - if (type == TCG_TYPE_I32) { - if (dest == src) { - tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 16); - } else { - tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 16); - } - tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 16); - } else { - tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 48); - tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 48); - } + tcg_out_insn(s, RRE, LGHR, dest, src); } static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) { - if (HAVE_FACILITY(EXT_IMM)) { - tcg_out_insn(s, RRE, LLGHR, dest, src); - return; - } - - if (dest == src) { - tcg_out_movi(s, type, TCG_TMP0, 0xffff); - src = TCG_TMP0; - } else { - tcg_out_movi(s, type, dest, 0xffff); - } - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, NR, dest, src); - } else { - tcg_out_insn(s, RRE, NGR, dest, src); - } + tcg_out_insn(s, RRE, LLGHR, dest, src); } static inline void tgen_ext32s(TCGContext *s, TCGReg dest, TCGReg src) @@ -1148,36 +1112,6 @@ static inline void tgen_ext32u(TCGContext *s, TCGReg dest, TCGReg src) tcg_out_insn(s, RRE, LLGFR, dest, src); } -/* Accept bit patterns like these: - 0....01....1 - 1....10....0 - 1..10..01..1 - 0..01..10..0 - Copied from gcc sources. */ -static inline bool risbg_mask(uint64_t c) -{ - uint64_t lsb; - /* We don't change the number of transitions by inverting, - so make sure we start with the LSB zero. */ - if (c & 1) { - c = ~c; - } - /* Reject all zeros or all ones. */ - if (c == 0) { - return false; - } - /* Find the first transition. */ - lsb = c & -c; - /* Invert to look for a second transition. */ - c = ~c; - /* Erase the first transition. */ - c &= -lsb; - /* Find the second transition, if any. */ - lsb = c & -c; - /* Match if all the bits are 1's, or if c is zero. */ - return c == -lsb; -} - static void tgen_andi_risbg(TCGContext *s, TCGReg out, TCGReg in, uint64_t val) { int msb, lsb; @@ -1208,157 +1142,78 @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) tgen_ext32u(s, dest, dest); return; } - if (HAVE_FACILITY(EXT_IMM)) { - if ((val & valid) == 0xff) { - tgen_ext8u(s, TCG_TYPE_I64, dest, dest); - return; - } - if ((val & valid) == 0xffff) { - tgen_ext16u(s, TCG_TYPE_I64, dest, dest); - return; - } + if ((val & valid) == 0xff) { + tgen_ext8u(s, TCG_TYPE_I64, dest, dest); + return; + } + if ((val & valid) == 0xffff) { + tgen_ext16u(s, TCG_TYPE_I64, dest, dest); + return; } - /* Try all 32-bit insns that can perform it in one go. */ - for (i = 0; i < 4; i++) { - tcg_target_ulong mask = ~(0xffffull << i*16); - if (((val | ~valid) & mask) == mask) { - tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16); - return; - } + i = is_const_p16(~val & valid); + if (i >= 0) { + tcg_out_insn_RI(s, ni_insns[i], dest, val >> (i * 16)); + return; } - /* Try all 48-bit insns that can perform it in one go. */ - if (HAVE_FACILITY(EXT_IMM)) { - for (i = 0; i < 2; i++) { - tcg_target_ulong mask = ~(0xffffffffull << i*32); - if (((val | ~valid) & mask) == mask) { - tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32); - return; - } - } + i = is_const_p32(~val & valid); + tcg_debug_assert(i == 0 || type != TCG_TYPE_I32); + if (i >= 0) { + tcg_out_insn_RIL(s, nif_insns[i], dest, val >> (i * 32)); + return; } - if (HAVE_FACILITY(GEN_INST_EXT) && risbg_mask(val)) { + + if (risbg_mask(val)) { tgen_andi_risbg(s, dest, dest, val); return; } - /* Use the constant pool if USE_REG_TB, but not for small constants. */ - if (USE_REG_TB) { - if (!maybe_out_small_movi(s, type, TCG_TMP0, val)) { - tcg_out_insn(s, RXY, NG, dest, TCG_REG_TB, TCG_REG_NONE, 0); - new_pool_label(s, val & valid, R_390_20, s->code_ptr - 2, - tcg_tbrel_diff(s, NULL)); - return; - } - } else { - tcg_out_movi(s, type, TCG_TMP0, val); - } - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, NR, dest, TCG_TMP0); - } else { - tcg_out_insn(s, RRE, NGR, dest, TCG_TMP0); - } + g_assert_not_reached(); } -static void tgen_ori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) +static void tgen_ori(TCGContext *s, TCGReg dest, uint64_t val) { - static const S390Opcode oi_insns[4] = { - RI_OILL, RI_OILH, RI_OIHL, RI_OIHH - }; static const S390Opcode oif_insns[2] = { RIL_OILF, RIL_OIHF }; int i; - /* Look for no-op. */ - if (unlikely(val == 0)) { + i = is_const_p16(val); + if (i >= 0) { + tcg_out_insn_RI(s, oi_insns[i], dest, val >> (i * 16)); return; } - /* Try all 32-bit insns that can perform it in one go. */ - for (i = 0; i < 4; i++) { - tcg_target_ulong mask = (0xffffull << i*16); - if ((val & mask) != 0 && (val & ~mask) == 0) { - tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16); - return; - } - } - - /* Try all 48-bit insns that can perform it in one go. */ - if (HAVE_FACILITY(EXT_IMM)) { - for (i = 0; i < 2; i++) { - tcg_target_ulong mask = (0xffffffffull << i*32); - if ((val & mask) != 0 && (val & ~mask) == 0) { - tcg_out_insn_RIL(s, oif_insns[i], dest, val >> i*32); - return; - } - } + i = is_const_p32(val); + if (i >= 0) { + tcg_out_insn_RIL(s, oif_insns[i], dest, val >> (i * 32)); + return; } - /* Use the constant pool if USE_REG_TB, but not for small constants. */ - if (maybe_out_small_movi(s, type, TCG_TMP0, val)) { - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, OR, dest, TCG_TMP0); - } else { - tcg_out_insn(s, RRE, OGR, dest, TCG_TMP0); - } - } else if (USE_REG_TB) { - tcg_out_insn(s, RXY, OG, dest, TCG_REG_TB, TCG_REG_NONE, 0); - new_pool_label(s, val, R_390_20, s->code_ptr - 2, - tcg_tbrel_diff(s, NULL)); - } else { - /* Perform the OR via sequential modifications to the high and - low parts. Do this via recursion to handle 16-bit vs 32-bit - masks in each half. */ - tcg_debug_assert(HAVE_FACILITY(EXT_IMM)); - tgen_ori(s, type, dest, val & 0x00000000ffffffffull); - tgen_ori(s, type, dest, val & 0xffffffff00000000ull); - } + g_assert_not_reached(); } -static void tgen_xori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) +static void tgen_xori(TCGContext *s, TCGReg dest, uint64_t val) { - /* Try all 48-bit insns that can perform it in one go. */ - if (HAVE_FACILITY(EXT_IMM)) { - if ((val & 0xffffffff00000000ull) == 0) { - tcg_out_insn(s, RIL, XILF, dest, val); - return; - } - if ((val & 0x00000000ffffffffull) == 0) { - tcg_out_insn(s, RIL, XIHF, dest, val >> 32); - return; - } - } - - /* Use the constant pool if USE_REG_TB, but not for small constants. */ - if (maybe_out_small_movi(s, type, TCG_TMP0, val)) { - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, XR, dest, TCG_TMP0); - } else { - tcg_out_insn(s, RRE, XGR, dest, TCG_TMP0); - } - } else if (USE_REG_TB) { - tcg_out_insn(s, RXY, XG, dest, TCG_REG_TB, TCG_REG_NONE, 0); - new_pool_label(s, val, R_390_20, s->code_ptr - 2, - tcg_tbrel_diff(s, NULL)); - } else { - /* Perform the xor by parts. */ - tcg_debug_assert(HAVE_FACILITY(EXT_IMM)); - if (val & 0xffffffff) { - tcg_out_insn(s, RIL, XILF, dest, val); - } - if (val > 0xffffffff) { - tcg_out_insn(s, RIL, XIHF, dest, val >> 32); - } + switch (is_const_p32(val)) { + case 0: + tcg_out_insn(s, RIL, XILF, dest, val); + break; + case 1: + tcg_out_insn(s, RIL, XIHF, dest, val >> 32); + break; + default: + g_assert_not_reached(); } } -static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, - TCGArg c2, bool c2const, bool need_carry) +static int tgen_cmp2(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, + TCGArg c2, bool c2const, bool need_carry, int *inv_cc) { bool is_unsigned = is_unsigned_cond(c); + TCGCond inv_c = tcg_invert_cond(c); S390Opcode op; if (c2const) { @@ -1369,6 +1224,7 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, } else { tcg_out_insn(s, RRE, LTGR, r1, r1); } + *inv_cc = tcg_cond_to_ltr_cond[inv_c]; return tcg_cond_to_ltr_cond[c]; } } @@ -1379,48 +1235,25 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, goto exit; } - if (HAVE_FACILITY(EXT_IMM)) { - if (type == TCG_TYPE_I32) { - op = (is_unsigned ? RIL_CLFI : RIL_CFI); - tcg_out_insn_RIL(s, op, r1, c2); - goto exit; - } else if (c2 == (is_unsigned ? (TCGArg)(uint32_t)c2 : (TCGArg)(int32_t)c2)) { - op = (is_unsigned ? RIL_CLGFI : RIL_CGFI); - tcg_out_insn_RIL(s, op, r1, c2); - goto exit; - } + if (type == TCG_TYPE_I32) { + op = (is_unsigned ? RIL_CLFI : RIL_CFI); + tcg_out_insn_RIL(s, op, r1, c2); + goto exit; } - /* Use the constant pool, but not for small constants. */ - if (maybe_out_small_movi(s, type, TCG_TMP0, c2)) { - c2 = TCG_TMP0; - /* fall through to reg-reg */ - } else if (USE_REG_TB) { - if (type == TCG_TYPE_I32) { - op = (is_unsigned ? RXY_CLY : RXY_CY); - tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0); - new_pool_label(s, (uint32_t)c2, R_390_20, s->code_ptr - 2, - 4 - tcg_tbrel_diff(s, NULL)); - } else { - op = (is_unsigned ? RXY_CLG : RXY_CG); - tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0); - new_pool_label(s, c2, R_390_20, s->code_ptr - 2, - tcg_tbrel_diff(s, NULL)); - } - goto exit; - } else { - if (type == TCG_TYPE_I32) { - op = (is_unsigned ? RIL_CLRL : RIL_CRL); - tcg_out_insn_RIL(s, op, r1, 0); - new_pool_label(s, (uint32_t)c2, R_390_PC32DBL, - s->code_ptr - 2, 2 + 4); - } else { - op = (is_unsigned ? RIL_CLGRL : RIL_CGRL); - tcg_out_insn_RIL(s, op, r1, 0); - new_pool_label(s, c2, R_390_PC32DBL, s->code_ptr - 2, 2); - } + /* + * Constraints are for a signed 33-bit operand, which is a + * convenient superset of this signed/unsigned test. + */ + if (c2 == (is_unsigned ? (TCGArg)(uint32_t)c2 : (TCGArg)(int32_t)c2)) { + op = (is_unsigned ? RIL_CLGFI : RIL_CGFI); + tcg_out_insn_RIL(s, op, r1, c2); goto exit; } + + /* Load everything else into a register. */ + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, c2); + c2 = TCG_TMP0; } if (type == TCG_TYPE_I32) { @@ -1432,27 +1265,31 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, } exit: + *inv_cc = tcg_cond_to_s390_cond[inv_c]; return tcg_cond_to_s390_cond[c]; } +static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, + TCGArg c2, bool c2const, bool need_carry) +{ + int inv_cc; + return tgen_cmp2(s, type, c, r1, c2, c2const, need_carry, &inv_cc); +} + static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg dest, TCGReg c1, TCGArg c2, int c2const) { int cc; - bool have_loc; /* With LOC2, we can always emit the minimum 3 insns. */ if (HAVE_FACILITY(LOAD_ON_COND2)) { /* Emit: d = 0, d = (cc ? 1 : d). */ cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); tcg_out_movi(s, TCG_TYPE_I64, dest, 0); - tcg_out_insn(s, RIE, LOCGHI, dest, 1, cc); + tcg_out_insn(s, RIEg, LOCGHI, dest, 1, cc); return; } - have_loc = HAVE_FACILITY(LOAD_ON_COND); - - /* For HAVE_LOC, only the paths through GTU/GT/LEU/LE are smaller. */ restart: switch (cond) { case TCG_COND_NE: @@ -1497,60 +1334,74 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, case TCG_COND_LT: case TCG_COND_GE: /* Swap operands so that we can use LEU/GTU/GT/LE. */ - if (c2const) { - if (have_loc) { - break; - } - tcg_out_movi(s, type, TCG_TMP0, c2); - c2 = c1; - c2const = 0; - c1 = TCG_TMP0; - } else { + if (!c2const) { TCGReg t = c1; c1 = c2; c2 = t; + cond = tcg_swap_cond(cond); + goto restart; } - cond = tcg_swap_cond(cond); - goto restart; + break; default: g_assert_not_reached(); } cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); - if (have_loc) { - /* Emit: d = 0, t = 1, d = (cc ? t : d). */ - tcg_out_movi(s, TCG_TYPE_I64, dest, 0); - tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); - tcg_out_insn(s, RRF, LOCGR, dest, TCG_TMP0, cc); + /* Emit: d = 0, t = 1, d = (cc ? t : d). */ + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); + tcg_out_insn(s, RRFc, LOCGR, dest, TCG_TMP0, cc); +} + +static void tgen_movcond_int(TCGContext *s, TCGType type, TCGReg dest, + TCGArg v3, int v3const, TCGReg v4, + int cc, int inv_cc) +{ + TCGReg src; + + if (v3const) { + if (dest == v4) { + if (HAVE_FACILITY(LOAD_ON_COND2)) { + /* Emit: if (cc) dest = v3. */ + tcg_out_insn(s, RIEg, LOCGHI, dest, v3, cc); + return; + } + tcg_out_insn(s, RI, LGHI, TCG_TMP0, v3); + src = TCG_TMP0; + } else { + /* LGR+LOCGHI is larger than LGHI+LOCGR. */ + tcg_out_insn(s, RI, LGHI, dest, v3); + cc = inv_cc; + src = v4; + } } else { - /* Emit: d = 1; if (cc) goto over; d = 0; over: */ - tcg_out_movi(s, type, dest, 1); - tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); - tcg_out_movi(s, type, dest, 0); + if (HAVE_FACILITY(MISC_INSN_EXT3)) { + /* Emit: dest = cc ? v3 : v4. */ + tcg_out_insn(s, RRFam, SELGR, dest, v3, v4, cc); + return; + } + if (dest == v4) { + src = v3; + } else { + tcg_out_mov(s, type, dest, v3); + cc = inv_cc; + src = v4; + } } + + /* Emit: if (cc) dest = src. */ + tcg_out_insn(s, RRFc, LOCGR, dest, src, cc); } static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, TCGReg c1, TCGArg c2, int c2const, - TCGArg v3, int v3const) + TCGArg v3, int v3const, TCGReg v4) { - int cc; - if (HAVE_FACILITY(LOAD_ON_COND)) { - cc = tgen_cmp(s, type, c, c1, c2, c2const, false); - if (v3const) { - tcg_out_insn(s, RIE, LOCGHI, dest, v3, cc); - } else { - tcg_out_insn(s, RRF, LOCGR, dest, v3, cc); - } - } else { - c = tcg_invert_cond(c); - cc = tgen_cmp(s, type, c, c1, c2, c2const, false); + int cc, inv_cc; - /* Emit: if (cc) goto over; dest = r3; over: */ - tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); - tcg_out_insn(s, RRE, LGR, dest, v3); - } + cc = tgen_cmp2(s, type, c, c1, c2, c2const, false, &inv_cc); + tgen_movcond_int(s, type, dest, v3, v3const, v4, cc, inv_cc); } static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1, @@ -1563,20 +1414,40 @@ static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1, if (a2const && a2 == 64) { tcg_out_mov(s, TCG_TYPE_I64, dest, TCG_REG_R0); - } else { - if (a2const) { - tcg_out_movi(s, TCG_TYPE_I64, dest, a2); - } else { - tcg_out_mov(s, TCG_TYPE_I64, dest, a2); - } - if (HAVE_FACILITY(LOAD_ON_COND)) { - /* Emit: if (one bit found) dest = r0. */ - tcg_out_insn(s, RRF, LOCGR, dest, TCG_REG_R0, 2); - } else { - /* Emit: if (no one bit found) goto over; dest = r0; over: */ - tcg_out_insn(s, RI, BRC, 8, (4 + 4) >> 1); - tcg_out_insn(s, RRE, LGR, dest, TCG_REG_R0); + return; + } + + /* + * Conditions from FLOGR are: + * 2 -> one bit found + * 8 -> no one bit found + */ + tgen_movcond_int(s, TCG_TYPE_I64, dest, a2, a2const, TCG_REG_R0, 8, 2); +} + +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) +{ + /* With MIE3, and bit 0 of m4 set, we get the complete result. */ + if (HAVE_FACILITY(MISC_INSN_EXT3)) { + if (type == TCG_TYPE_I32) { + tgen_ext32u(s, dest, src); + src = dest; } + tcg_out_insn(s, RRFc, POPCNT, dest, src, 8); + return; + } + + /* Without MIE3, each byte gets the count of bits for the byte. */ + tcg_out_insn(s, RRFc, POPCNT, dest, src, 0); + + /* Multiply to sum each byte at the top of the word. */ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIL, MSFI, dest, 0x01010101); + tcg_out_sh32(s, RS_SRL, dest, TCG_REG_NONE, 24); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0x0101010101010101ull); + tcg_out_insn(s, RRE, MSGR, dest, TCG_TMP0); + tcg_out_sh64(s, RSY_SRLG, dest, dest, TCG_REG_NONE, 56); } } @@ -1611,10 +1482,6 @@ static void tgen_branch(TCGContext *s, int cc, TCGLabel *l) { if (l->has_value) { tgen_gotoi(s, cc, l->u.value_ptr); - } else if (USE_LONG_BRANCHES) { - tcg_out16(s, RIL_BRCL | (cc << 4)); - tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, l, 2); - s->code_ptr += 2; } else { tcg_out16(s, RI_BRC | (cc << 4)); tcg_out_reloc(s, s->code_ptr, R_390_PC16DBL, l, 2); @@ -1626,6 +1493,7 @@ static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc, TCGReg r1, TCGReg r2, TCGLabel *l) { tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2); + /* Format RIE-b */ tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2); tcg_out16(s, 0); tcg_out16(s, cc << 12 | (opc & 0xff)); @@ -1635,6 +1503,7 @@ static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc, TCGReg r1, int i2, TCGLabel *l) { tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2); + /* Format RIE-c */ tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc); tcg_out16(s, 0); tcg_out16(s, (i2 << 8) | (opc & 0xff)); @@ -1644,54 +1513,53 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, TCGArg c2, int c2const, TCGLabel *l) { int cc; + bool is_unsigned = is_unsigned_cond(c); + bool in_range; + S390Opcode opc; - if (HAVE_FACILITY(GEN_INST_EXT)) { - bool is_unsigned = is_unsigned_cond(c); - bool in_range; - S390Opcode opc; - - cc = tcg_cond_to_s390_cond[c]; + cc = tcg_cond_to_s390_cond[c]; - if (!c2const) { - opc = (type == TCG_TYPE_I32 - ? (is_unsigned ? RIE_CLRJ : RIE_CRJ) - : (is_unsigned ? RIE_CLGRJ : RIE_CGRJ)); - tgen_compare_branch(s, opc, cc, r1, c2, l); - return; - } + if (!c2const) { + opc = (type == TCG_TYPE_I32 + ? (is_unsigned ? RIEb_CLRJ : RIEb_CRJ) + : (is_unsigned ? RIEb_CLGRJ : RIEb_CGRJ)); + tgen_compare_branch(s, opc, cc, r1, c2, l); + return; + } - /* COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field. - If the immediate we've been given does not fit that range, we'll - fall back to separate compare and branch instructions using the - larger comparison range afforded by COMPARE IMMEDIATE. */ - if (type == TCG_TYPE_I32) { - if (is_unsigned) { - opc = RIE_CLIJ; - in_range = (uint32_t)c2 == (uint8_t)c2; - } else { - opc = RIE_CIJ; - in_range = (int32_t)c2 == (int8_t)c2; - } + /* + * COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field. + * If the immediate we've been given does not fit that range, we'll + * fall back to separate compare and branch instructions using the + * larger comparison range afforded by COMPARE IMMEDIATE. + */ + if (type == TCG_TYPE_I32) { + if (is_unsigned) { + opc = RIEc_CLIJ; + in_range = (uint32_t)c2 == (uint8_t)c2; } else { - if (is_unsigned) { - opc = RIE_CLGIJ; - in_range = (uint64_t)c2 == (uint8_t)c2; - } else { - opc = RIE_CGIJ; - in_range = (int64_t)c2 == (int8_t)c2; - } + opc = RIEc_CIJ; + in_range = (int32_t)c2 == (int8_t)c2; } - if (in_range) { - tgen_compare_imm_branch(s, opc, cc, r1, c2, l); - return; + } else { + if (is_unsigned) { + opc = RIEc_CLGIJ; + in_range = (uint64_t)c2 == (uint8_t)c2; + } else { + opc = RIEc_CGIJ; + in_range = (int64_t)c2 == (int8_t)c2; } } + if (in_range) { + tgen_compare_imm_branch(s, opc, cc, r1, c2, l); + return; + } cc = tgen_cmp(s, type, c, r1, c2, c2const, false); tgen_branch(s, cc, l); } -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *dest) { ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1; if (off == (int32_t)off) { @@ -1702,6 +1570,12 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) } } +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, + const TCGHelperInfo *info) +{ + tcg_out_call_int(s, dest); +} + static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { @@ -1837,7 +1711,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, cross pages using the address of the last byte of the access. */ a_off = (a_bits >= s_bits ? 0 : s_mask - a_mask); tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; - if (HAVE_FACILITY(GEN_INST_EXT) && a_off == 0) { + if (a_off == 0) { tgen_andi_risbg(s, TCG_REG_R3, addr_reg, tlb_mask); } else { tcg_out_insn(s, RX, LA, TCG_REG_R3, addr_reg, TCG_REG_NONE, a_off); @@ -1897,7 +1771,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) } tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, oi); tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R5, (uintptr_t)lb->raddr); - tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]); + tcg_out_call_int(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]); tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_R2); tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr); @@ -1938,7 +1812,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) } tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R5, oi); tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R6, (uintptr_t)lb->raddr); - tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); + tcg_out_call_int(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr); return true; @@ -2095,43 +1969,21 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_goto_tb: a0 = args[0]; - if (s->tb_jmp_insn_offset) { - /* - * branch displacement must be aligned for atomic patching; - * see if we need to add extra nop before branch - */ - if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) { - tcg_out16(s, NOP); - } - tcg_debug_assert(!USE_REG_TB); - tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4)); - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); - s->code_ptr += 2; - } else { - /* load address stored at s->tb_jmp_target_addr + a0 */ - tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_REG_TB, - tcg_splitwx_to_rx(s->tb_jmp_target_addr + a0)); - /* and go there */ - tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_TB); - } + /* + * branch displacement must be aligned for atomic patching; + * see if we need to add extra nop before branch + */ + if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) { + tcg_out16(s, NOP); + } + tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4)); + s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + s->code_ptr += 2; set_jmp_reset_offset(s, a0); - - /* For the unlinked path of goto_tb, we need to reset - TCG_REG_TB to the beginning of this TB. */ - if (USE_REG_TB) { - int ofs = -tcg_current_code_size(s); - /* All TB are restricted to 64KiB by unwind info. */ - tcg_debug_assert(ofs == sextract64(ofs, 0, 20)); - tcg_out_insn(s, RXY, LAY, TCG_REG_TB, - TCG_REG_TB, TCG_REG_NONE, ofs); - } break; case INDEX_op_goto_ptr: a0 = args[0]; - if (USE_REG_TB) { - tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, a0); - } tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0); break; @@ -2183,10 +2035,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_insn(s, RI, AHI, a0, a2); break; } - if (HAVE_FACILITY(EXT_IMM)) { - tcg_out_insn(s, RIL, AFI, a0, a2); - break; - } + tcg_out_insn(s, RIL, AFI, a0, a2); + break; } tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2); } else if (a0 == a1) { @@ -2203,7 +2053,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } else if (a0 == a1) { tcg_out_insn(s, RR, SR, a0, a2); } else { - tcg_out_insn(s, RRF, SRK, a0, a1, a2); + tcg_out_insn(s, RRFa, SRK, a0, a1, a2); } break; @@ -2215,53 +2065,102 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } else if (a0 == a1) { tcg_out_insn(s, RR, NR, a0, a2); } else { - tcg_out_insn(s, RRF, NRK, a0, a1, a2); + tcg_out_insn(s, RRFa, NRK, a0, a1, a2); } break; case INDEX_op_or_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tgen_ori(s, TCG_TYPE_I32, a0, a2); + tgen_ori(s, a0, a2); } else if (a0 == a1) { tcg_out_insn(s, RR, OR, a0, a2); } else { - tcg_out_insn(s, RRF, ORK, a0, a1, a2); + tcg_out_insn(s, RRFa, ORK, a0, a1, a2); } break; case INDEX_op_xor_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tgen_xori(s, TCG_TYPE_I32, a0, a2); + tcg_out_insn(s, RIL, XILF, a0, a2); } else if (a0 == a1) { tcg_out_insn(s, RR, XR, args[0], args[2]); } else { - tcg_out_insn(s, RRF, XRK, a0, a1, a2); + tcg_out_insn(s, RRFa, XRK, a0, a1, a2); + } + break; + + case INDEX_op_andc_i32: + a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; + if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tgen_andi(s, TCG_TYPE_I32, a0, (uint32_t)~a2); + } else { + tcg_out_insn(s, RRFa, NCRK, a0, a1, a2); + } + break; + case INDEX_op_orc_i32: + a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; + if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tgen_ori(s, a0, (uint32_t)~a2); + } else { + tcg_out_insn(s, RRFa, OCRK, a0, a1, a2); } break; + case INDEX_op_eqv_i32: + a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; + if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tcg_out_insn(s, RIL, XILF, a0, ~a2); + } else { + tcg_out_insn(s, RRFa, NXRK, a0, a1, a2); + } + break; + case INDEX_op_nand_i32: + tcg_out_insn(s, RRFa, NNRK, args[0], args[1], args[2]); + break; + case INDEX_op_nor_i32: + tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[2]); + break; case INDEX_op_neg_i32: tcg_out_insn(s, RR, LCR, args[0], args[1]); break; + case INDEX_op_not_i32: + tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[1]); + break; case INDEX_op_mul_i32: + a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; if (const_args[2]) { - if ((int32_t)args[2] == (int16_t)args[2]) { - tcg_out_insn(s, RI, MHI, args[0], args[2]); + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + if (a2 == (int16_t)a2) { + tcg_out_insn(s, RI, MHI, a0, a2); } else { - tcg_out_insn(s, RIL, MSFI, args[0], args[2]); + tcg_out_insn(s, RIL, MSFI, a0, a2); } + } else if (a0 == a1) { + tcg_out_insn(s, RRE, MSR, a0, a2); } else { - tcg_out_insn(s, RRE, MSR, args[0], args[2]); + tcg_out_insn(s, RRFa, MSRKC, a0, a1, a2); } break; case INDEX_op_div2_i32: - tcg_out_insn(s, RR, DR, TCG_REG_R2, args[4]); + tcg_debug_assert(args[0] == args[2]); + tcg_debug_assert(args[1] == args[3]); + tcg_debug_assert((args[1] & 1) == 0); + tcg_debug_assert(args[0] == args[1] + 1); + tcg_out_insn(s, RR, DR, args[1], args[4]); break; case INDEX_op_divu2_i32: - tcg_out_insn(s, RRE, DLR, TCG_REG_R2, args[4]); + tcg_debug_assert(args[0] == args[2]); + tcg_debug_assert(args[1] == args[3]); + tcg_debug_assert((args[1] & 1) == 0); + tcg_debug_assert(args[0] == args[1] + 1); + tcg_out_insn(s, RRE, DLR, args[1], args[4]); break; case INDEX_op_shl_i32: @@ -2387,7 +2286,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_movcond_i32: tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], - args[2], const_args[2], args[3], const_args[3]); + args[2], const_args[2], args[3], const_args[3], args[4]); break; case INDEX_op_qemu_ld_i32: @@ -2429,17 +2328,17 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_insn(s, RI, AGHI, a0, a2); break; } - if (HAVE_FACILITY(EXT_IMM)) { - if (a2 == (int32_t)a2) { - tcg_out_insn(s, RIL, AGFI, a0, a2); - break; - } else if (a2 == (uint32_t)a2) { - tcg_out_insn(s, RIL, ALGFI, a0, a2); - break; - } else if (-a2 == (uint32_t)-a2) { - tcg_out_insn(s, RIL, SLGFI, a0, -a2); - break; - } + if (a2 == (int32_t)a2) { + tcg_out_insn(s, RIL, AGFI, a0, a2); + break; + } + if (a2 == (uint32_t)a2) { + tcg_out_insn(s, RIL, ALGFI, a0, a2); + break; + } + if (-a2 == (uint32_t)-a2) { + tcg_out_insn(s, RIL, SLGFI, a0, -a2); + break; } } tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2); @@ -2454,10 +2353,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, if (const_args[2]) { a2 = -a2; goto do_addi_64; - } else if (a0 == a1) { - tcg_out_insn(s, RRE, SGR, a0, a2); } else { - tcg_out_insn(s, RRF, SGRK, a0, a1, a2); + tcg_out_insn(s, RRFa, SGRK, a0, a1, a2); } break; @@ -2466,66 +2363,119 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, if (const_args[2]) { tcg_out_mov(s, TCG_TYPE_I64, a0, a1); tgen_andi(s, TCG_TYPE_I64, args[0], args[2]); - } else if (a0 == a1) { - tcg_out_insn(s, RRE, NGR, args[0], args[2]); } else { - tcg_out_insn(s, RRF, NGRK, a0, a1, a2); + tcg_out_insn(s, RRFa, NGRK, a0, a1, a2); } break; case INDEX_op_or_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_ori(s, TCG_TYPE_I64, a0, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RRE, OGR, a0, a2); + tgen_ori(s, a0, a2); } else { - tcg_out_insn(s, RRF, OGRK, a0, a1, a2); + tcg_out_insn(s, RRFa, OGRK, a0, a1, a2); } break; case INDEX_op_xor_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_xori(s, TCG_TYPE_I64, a0, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RRE, XGR, a0, a2); + tgen_xori(s, a0, a2); } else { - tcg_out_insn(s, RRF, XGRK, a0, a1, a2); + tcg_out_insn(s, RRFa, XGRK, a0, a1, a2); } break; + case INDEX_op_andc_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; + if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); + tgen_andi(s, TCG_TYPE_I64, a0, ~a2); + } else { + tcg_out_insn(s, RRFa, NCGRK, a0, a1, a2); + } + break; + case INDEX_op_orc_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; + if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); + tgen_ori(s, a0, ~a2); + } else { + tcg_out_insn(s, RRFa, OCGRK, a0, a1, a2); + } + break; + case INDEX_op_eqv_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; + if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); + tgen_xori(s, a0, ~a2); + } else { + tcg_out_insn(s, RRFa, NXGRK, a0, a1, a2); + } + break; + case INDEX_op_nand_i64: + tcg_out_insn(s, RRFa, NNGRK, args[0], args[1], args[2]); + break; + case INDEX_op_nor_i64: + tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[2]); + break; + case INDEX_op_neg_i64: tcg_out_insn(s, RRE, LCGR, args[0], args[1]); break; + case INDEX_op_not_i64: + tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[1]); + break; case INDEX_op_bswap64_i64: tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); break; case INDEX_op_mul_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { - if (args[2] == (int16_t)args[2]) { - tcg_out_insn(s, RI, MGHI, args[0], args[2]); + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); + if (a2 == (int16_t)a2) { + tcg_out_insn(s, RI, MGHI, a0, a2); } else { - tcg_out_insn(s, RIL, MSGFI, args[0], args[2]); + tcg_out_insn(s, RIL, MSGFI, a0, a2); } + } else if (a0 == a1) { + tcg_out_insn(s, RRE, MSGR, a0, a2); } else { - tcg_out_insn(s, RRE, MSGR, args[0], args[2]); + tcg_out_insn(s, RRFa, MSGRKC, a0, a1, a2); } break; case INDEX_op_div2_i64: - /* ??? We get an unnecessary sign-extension of the dividend - into R3 with this definition, but as we do in fact always - produce both quotient and remainder using INDEX_op_div_i64 - instead requires jumping through even more hoops. */ - tcg_out_insn(s, RRE, DSGR, TCG_REG_R2, args[4]); + /* + * ??? We get an unnecessary sign-extension of the dividend + * into op0 with this definition, but as we do in fact always + * produce both quotient and remainder using INDEX_op_div_i64 + * instead requires jumping through even more hoops. + */ + tcg_debug_assert(args[0] == args[2]); + tcg_debug_assert(args[1] == args[3]); + tcg_debug_assert((args[1] & 1) == 0); + tcg_debug_assert(args[0] == args[1] + 1); + tcg_out_insn(s, RRE, DSGR, args[1], args[4]); break; case INDEX_op_divu2_i64: - tcg_out_insn(s, RRE, DLGR, TCG_REG_R2, args[4]); + tcg_debug_assert(args[0] == args[2]); + tcg_debug_assert(args[1] == args[3]); + tcg_debug_assert((args[1] & 1) == 0); + tcg_debug_assert(args[0] == args[1] + 1); + tcg_out_insn(s, RRE, DLGR, args[1], args[4]); break; case INDEX_op_mulu2_i64: - tcg_out_insn(s, RRE, MLGR, TCG_REG_R2, args[3]); + tcg_debug_assert(args[0] == args[2]); + tcg_debug_assert((args[1] & 1) == 0); + tcg_debug_assert(args[0] == args[1] + 1); + tcg_out_insn(s, RRE, MLGR, args[1], args[3]); + break; + case INDEX_op_muls2_i64: + tcg_debug_assert((args[1] & 1) == 0); + tcg_debug_assert(args[0] == args[1] + 1); + tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]); break; case INDEX_op_shl_i64: @@ -2620,7 +2570,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_movcond_i64: tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], - args[2], const_args[2], args[3], const_args[3]); + args[2], const_args[2], args[3], const_args[3], args[4]); break; OP_32_64(deposit): @@ -2650,11 +2600,19 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tgen_clz(s, args[0], args[1], args[2], const_args[2]); break; + case INDEX_op_ctpop_i32: + tgen_ctpop(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ctpop_i64: + tgen_ctpop(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_mb: /* The host memory model is quite strong, we simply need to serialize the instruction stream. */ if (args[0] & TCG_MO_ST_LD) { - tcg_out_insn(s, RR, BCR, HAVE_FACILITY(FAST_BCR_SER) ? 14 : 15, 0); + /* fast-bcr-serialization facility (45) is present */ + tcg_out_insn(s, RR, BCR, 14, 0); } break; @@ -3135,46 +3093,60 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_rotl_i64: case INDEX_op_rotr_i32: case INDEX_op_rotr_i64: - case INDEX_op_clz_i64: case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: return C_O1_I2(r, r, ri); + case INDEX_op_setcond_i64: + return C_O1_I2(r, r, rA); + + case INDEX_op_clz_i64: + return C_O1_I2(r, r, rI); case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_and_i32: - case INDEX_op_and_i64: case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i32: + return C_O1_I2(r, r, ri); + case INDEX_op_and_i64: + return C_O1_I2(r, r, rNKR); + case INDEX_op_or_i64: case INDEX_op_xor_i64: - return (HAVE_FACILITY(DISTINCT_OPS) - ? C_O1_I2(r, r, ri) - : C_O1_I2(r, 0, ri)); + return C_O1_I2(r, r, rK); - case INDEX_op_mul_i32: - /* If we have the general-instruction-extensions, then we have - MULTIPLY SINGLE IMMEDIATE with a signed 32-bit, otherwise we - have only MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */ - return (HAVE_FACILITY(GEN_INST_EXT) - ? C_O1_I2(r, 0, ri) - : C_O1_I2(r, 0, rI)); + case INDEX_op_andc_i32: + case INDEX_op_orc_i32: + case INDEX_op_eqv_i32: + return C_O1_I2(r, r, ri); + case INDEX_op_andc_i64: + return C_O1_I2(r, r, rKR); + case INDEX_op_orc_i64: + case INDEX_op_eqv_i64: + return C_O1_I2(r, r, rNK); + + case INDEX_op_nand_i32: + case INDEX_op_nand_i64: + case INDEX_op_nor_i32: + case INDEX_op_nor_i64: + return C_O1_I2(r, r, r); + case INDEX_op_mul_i32: + return (HAVE_FACILITY(MISC_INSN_EXT2) + ? C_O1_I2(r, r, ri) + : C_O1_I2(r, 0, ri)); case INDEX_op_mul_i64: - return (HAVE_FACILITY(GEN_INST_EXT) - ? C_O1_I2(r, 0, rJ) - : C_O1_I2(r, 0, rI)); + return (HAVE_FACILITY(MISC_INSN_EXT2) + ? C_O1_I2(r, r, rJ) + : C_O1_I2(r, 0, rJ)); case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: - return (HAVE_FACILITY(DISTINCT_OPS) - ? C_O1_I2(r, r, ri) - : C_O1_I2(r, 0, ri)); + return C_O1_I2(r, r, ri); case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: return C_O0_I2(r, ri); + case INDEX_op_brcond_i64: + return C_O0_I2(r, rA); case INDEX_op_bswap16_i32: case INDEX_op_bswap16_i64: @@ -3183,6 +3155,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_bswap64_i64: case INDEX_op_neg_i32: case INDEX_op_neg_i64: + case INDEX_op_not_i32: + case INDEX_op_not_i64: case INDEX_op_ext8s_i32: case INDEX_op_ext8s_i64: case INDEX_op_ext8u_i32: @@ -3197,6 +3171,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_extu_i32_i64: case INDEX_op_extract_i32: case INDEX_op_extract_i64: + case INDEX_op_ctpop_i32: + case INDEX_op_ctpop_i64: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i32: @@ -3211,31 +3187,28 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) return C_O1_I2(r, rZ, r); case INDEX_op_movcond_i32: + return C_O1_I4(r, r, ri, rI, r); case INDEX_op_movcond_i64: - return (HAVE_FACILITY(LOAD_ON_COND2) - ? C_O1_I4(r, r, ri, rI, 0) - : C_O1_I4(r, r, ri, r, 0)); + return C_O1_I4(r, r, rA, rI, r); case INDEX_op_div2_i32: case INDEX_op_div2_i64: case INDEX_op_divu2_i32: case INDEX_op_divu2_i64: - return C_O2_I3(b, a, 0, 1, r); + return C_O2_I3(o, m, 0, 1, r); case INDEX_op_mulu2_i64: - return C_O2_I2(b, a, 0, r); + return C_O2_I2(o, m, 0, r); + case INDEX_op_muls2_i64: + return C_O2_I2(o, m, r, r); case INDEX_op_add2_i32: case INDEX_op_sub2_i32: - return (HAVE_FACILITY(EXT_IMM) - ? C_O2_I4(r, r, 0, 1, ri, r) - : C_O2_I4(r, r, 0, 1, r, r)); + return C_O2_I4(r, r, 0, 1, ri, r); case INDEX_op_add2_i64: case INDEX_op_sub2_i64: - return (HAVE_FACILITY(EXT_IMM) - ? C_O2_I4(r, r, 0, 1, rA, r) - : C_O2_I4(r, r, 0, 1, r, r)); + return C_O2_I4(r, r, 0, 1, rA, r); case INDEX_op_st_vec: return C_O0_I2(v, r); @@ -3301,6 +3274,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) static void query_s390_facilities(void) { unsigned long hwcap = qemu_getauxval(AT_HWCAP); + const char *which; /* Is STORE FACILITY LIST EXTENDED available? Honestly, I believe this is present on all 64-bit systems, but let's check for it anyway. */ @@ -3322,6 +3296,38 @@ static void query_s390_facilities(void) if (!(hwcap & HWCAP_S390_VXRS)) { s390_facilities[2] = 0; } + + /* + * Minimum supported cpu revision is z196. + * Check for all required facilities. + * ZARCH_ACTIVE is done via preprocessor check for 64-bit. + */ + if (!HAVE_FACILITY(LONG_DISP)) { + which = "long-displacement"; + goto fail; + } + if (!HAVE_FACILITY(EXT_IMM)) { + which = "extended-immediate"; + goto fail; + } + if (!HAVE_FACILITY(GEN_INST_EXT)) { + which = "general-instructions-extension"; + goto fail; + } + /* + * Facility 45 is a big bin that contains: distinct-operands, + * fast-BCR-serialization, high-word, population-count, + * interlocked-access-1, and load/store-on-condition-1 + */ + if (!HAVE_FACILITY(45)) { + which = "45"; + goto fail; + } + return; + + fail: + error_report("%s: missing required facility %s", __func__, which); + exit(EXIT_FAILURE); } static void tcg_target_init(TCGContext *s) @@ -3378,9 +3384,6 @@ static void tcg_target_init(TCGContext *s) /* XXX many insns can't be used with R0, so we better avoid it for now */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); - if (USE_REG_TB) { - tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB); - } } #define FRAME_SIZE ((int)(TCG_TARGET_CALL_STACK_OFFSET \ @@ -3401,16 +3404,12 @@ static void tcg_target_qemu_prologue(TCGContext *s) #ifndef CONFIG_SOFTMMU if (guest_base >= 0x80000) { - tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base, true); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } #endif tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); - if (USE_REG_TB) { - tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, - tcg_target_call_iarg_regs[1]); - } /* br %r3 (go to TB) */ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]); diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 23e20636678d..68dcbc6645c9 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -52,17 +52,19 @@ typedef enum TCGReg { #define TCG_TARGET_NB_REGS 64 -/* A list of relevant facilities used by this translator. Some of these - are required for proper operation, and these are checked at startup. */ +/* Facilities required for proper operation; checked at startup. */ #define FACILITY_ZARCH_ACTIVE 2 #define FACILITY_LONG_DISP 18 #define FACILITY_EXT_IMM 21 #define FACILITY_GEN_INST_EXT 34 -#define FACILITY_LOAD_ON_COND 45 -#define FACILITY_FAST_BCR_SER FACILITY_LOAD_ON_COND -#define FACILITY_DISTINCT_OPS FACILITY_LOAD_ON_COND +#define FACILITY_45 45 + +/* Facilities that are checked at runtime. */ + #define FACILITY_LOAD_ON_COND2 53 +#define FACILITY_MISC_INSN_EXT2 58 +#define FACILITY_MISC_INSN_EXT3 61 #define FACILITY_VECTOR 129 #define FACILITY_VECTOR_ENH1 135 @@ -80,18 +82,18 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 0 +#define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_neg_i32 1 -#define TCG_TARGET_HAS_andc_i32 0 -#define TCG_TARGET_HAS_orc_i32 0 -#define TCG_TARGET_HAS_eqv_i32 0 -#define TCG_TARGET_HAS_nand_i32 0 -#define TCG_TARGET_HAS_nor_i32 0 +#define TCG_TARGET_HAS_andc_i32 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_orc_i32 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_eqv_i32 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_nand_i32 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_nor_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 -#define TCG_TARGET_HAS_ctpop_i32 0 -#define TCG_TARGET_HAS_deposit_i32 HAVE_FACILITY(GEN_INST_EXT) -#define TCG_TARGET_HAS_extract_i32 HAVE_FACILITY(GEN_INST_EXT) +#define TCG_TARGET_HAS_ctpop_i32 1 +#define TCG_TARGET_HAS_deposit_i32 1 +#define TCG_TARGET_HAS_extract_i32 1 #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 @@ -103,7 +105,7 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extrl_i64_i32 0 #define TCG_TARGET_HAS_extrh_i64_i32 0 -#define TCG_TARGET_HAS_direct_jump HAVE_FACILITY(GEN_INST_EXT) +#define TCG_TARGET_HAS_direct_jump 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_div2_i64 1 @@ -117,25 +119,25 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_not_i64 0 +#define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_neg_i64 1 -#define TCG_TARGET_HAS_andc_i64 0 -#define TCG_TARGET_HAS_orc_i64 0 -#define TCG_TARGET_HAS_eqv_i64 0 -#define TCG_TARGET_HAS_nand_i64 0 -#define TCG_TARGET_HAS_nor_i64 0 -#define TCG_TARGET_HAS_clz_i64 HAVE_FACILITY(EXT_IMM) +#define TCG_TARGET_HAS_andc_i64 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_orc_i64 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_eqv_i64 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_nand_i64 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_nor_i64 HAVE_FACILITY(MISC_INSN_EXT3) +#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 0 -#define TCG_TARGET_HAS_ctpop_i64 0 -#define TCG_TARGET_HAS_deposit_i64 HAVE_FACILITY(GEN_INST_EXT) -#define TCG_TARGET_HAS_extract_i64 HAVE_FACILITY(GEN_INST_EXT) +#define TCG_TARGET_HAS_ctpop_i64 1 +#define TCG_TARGET_HAS_deposit_i64 1 +#define TCG_TARGET_HAS_extract_i64 1 #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 -#define TCG_TARGET_HAS_muls2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 HAVE_FACILITY(MISC_INSN_EXT2) #define TCG_TARGET_HAS_muluh_i64 0 #define TCG_TARGET_HAS_mulsh_i64 0 @@ -166,8 +168,9 @@ extern uint64_t s390_facilities[3]; /* used for function call generation */ #define TCG_TARGET_STACK_ALIGN 8 #define TCG_TARGET_CALL_STACK_OFFSET 160 +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL -#define TCG_TARGET_EXTEND_ARGS 1 #define TCG_TARGET_HAS_MEMORY_BSWAP 1 #define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) diff --git a/tcg/sparc/tcg-target-con-set.h b/tcg/sparc/tcg-target-con-set.h deleted file mode 100644 index 3b751dc3fb6d..000000000000 --- a/tcg/sparc/tcg-target-con-set.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Define Sparc target-specific constraint sets. - * Copyright (c) 2021 Linaro - */ - -/* - * C_On_Im(...) defines a constraint set with outputs and inputs. - * Each operand should be a sequence of constraint letters as defined by - * tcg-target-con-str.h; the constraint combination is inclusive or. - */ -C_O0_I1(r) -C_O0_I2(rZ, r) -C_O0_I2(RZ, r) -C_O0_I2(rZ, rJ) -C_O0_I2(RZ, RJ) -C_O0_I2(sZ, A) -C_O0_I2(SZ, A) -C_O1_I1(r, A) -C_O1_I1(R, A) -C_O1_I1(r, r) -C_O1_I1(r, R) -C_O1_I1(R, r) -C_O1_I1(R, R) -C_O1_I2(R, R, R) -C_O1_I2(r, rZ, rJ) -C_O1_I2(R, RZ, RJ) -C_O1_I4(r, rZ, rJ, rI, 0) -C_O1_I4(R, RZ, RJ, RI, 0) -C_O2_I2(r, r, rZ, rJ) -C_O2_I4(R, R, RZ, RZ, RJ, RI) -C_O2_I4(r, r, rZ, rZ, rJ, rJ) diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h new file mode 100644 index 000000000000..31e6fea1fc46 --- /dev/null +++ b/tcg/sparc64/tcg-target-con-set.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Define Sparc target-specific constraint sets. + * Copyright (c) 2021 Linaro + */ + +/* + * C_On_Im(...) defines a constraint set with outputs and inputs. + * Each operand should be a sequence of constraint letters as defined by + * tcg-target-con-str.h; the constraint combination is inclusive or. + */ +C_O0_I1(r) +C_O0_I2(rZ, r) +C_O0_I2(rZ, rJ) +C_O0_I2(sZ, s) +C_O1_I1(r, s) +C_O1_I1(r, r) +C_O1_I2(r, r, r) +C_O1_I2(r, rZ, rJ) +C_O1_I4(r, rZ, rJ, rI, 0) +C_O2_I2(r, r, rZ, rJ) +C_O2_I4(r, r, rZ, rZ, rJ, rJ) diff --git a/tcg/sparc/tcg-target-con-str.h b/tcg/sparc64/tcg-target-con-str.h similarity index 77% rename from tcg/sparc/tcg-target-con-str.h rename to tcg/sparc64/tcg-target-con-str.h index fdb25d931366..8f5c7aef97b0 100644 --- a/tcg/sparc/tcg-target-con-str.h +++ b/tcg/sparc64/tcg-target-con-str.h @@ -9,10 +9,7 @@ * REGS(letter, register_mask) */ REGS('r', ALL_GENERAL_REGS) -REGS('R', ALL_GENERAL_REGS64) REGS('s', ALL_QLDST_REGS) -REGS('S', ALL_QLDST_REGS64) -REGS('A', TARGET_LONG_BITS == 64 ? ALL_QLDST_REGS64 : ALL_QLDST_REGS) /* * Define constraint letters for constants: diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc similarity index 91% rename from tcg/sparc/tcg-target.c.inc rename to tcg/sparc64/tcg-target.c.inc index 72d9552fd06e..eb913f33c802 100644 --- a/tcg/sparc/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -22,6 +22,11 @@ * THE SOFTWARE. */ +/* We only support generating code for 64-bit mode. */ +#ifndef __arch64__ +#error "unsupported code generation mode" +#endif + #include "../tcg-pool.c.inc" #ifdef CONFIG_DEBUG_TCG @@ -61,12 +66,6 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { }; #endif -#ifdef __arch64__ -# define SPARC64 1 -#else -# define SPARC64 0 -#endif - #define TCG_CT_CONST_S11 0x100 #define TCG_CT_CONST_S13 0x200 #define TCG_CT_CONST_ZERO 0x400 @@ -81,23 +80,8 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { #else #define SOFTMMU_RESERVE_REGS 0 #endif - -/* - * Note that sparcv8plus can only hold 64 bit quantities in %g and %o - * registers. These are saved manually by the kernel in full 64-bit - * slots. The %i and %l registers are saved by the register window - * mechanism, which only allocates space for 32 bits. Given that this - * window spill/fill can happen on any signal, we must consider the - * high bits of the %i and %l registers garbage at all times. - */ #define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) -#if SPARC64 -# define ALL_GENERAL_REGS64 ALL_GENERAL_REGS -#else -# define ALL_GENERAL_REGS64 MAKE_64BIT_MASK(0, 16) -#endif #define ALL_QLDST_REGS (ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) -#define ALL_QLDST_REGS64 (ALL_GENERAL_REGS64 & ~SOFTMMU_RESERVE_REGS) /* Define some temporary registers. T2 is used for constant generation. */ #define TCG_REG_T1 TCG_REG_G1 @@ -306,11 +290,7 @@ static bool check_fit_i32(int32_t val, unsigned int bits) } #define check_fit_tl check_fit_i64 -#if SPARC64 -# define check_fit_ptr check_fit_i64 -#else -# define check_fit_ptr check_fit_i32 -#endif +#define check_fit_ptr check_fit_i64 static bool patch_reloc(tcg_insn_unit *src_rw, int type, intptr_t value, intptr_t addend) @@ -573,11 +553,6 @@ static void tcg_out_sety(TCGContext *s, TCGReg rs) tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs)); } -static void tcg_out_rdy(TCGContext *s, TCGReg rd) -{ - tcg_out32(s, RDY | INSN_RD(rd)); -} - static void tcg_out_div32(TCGContext *s, TCGReg rd, TCGReg rs1, int32_t val2, int val2const, int uns) { @@ -884,7 +859,8 @@ static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest, } } -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, + const TCGHelperInfo *info) { tcg_out_call_nodelay(s, dest, false); tcg_out_nop(s); @@ -914,9 +890,7 @@ static void emit_extend(TCGContext *s, TCGReg r, int op) tcg_out_arithi(s, r, r, 16, SHIFT_SRL); break; case MO_32: - if (SPARC64) { - tcg_out_arith(s, r, r, 0, SHIFT_SRL); - } + tcg_out_arith(s, r, r, 0, SHIFT_SRL); break; case MO_64: break; @@ -948,7 +922,6 @@ static void build_trampolines(TCGContext *s) }; int i; - TCGReg ra; for (i = 0; i < ARRAY_SIZE(qemu_ld_helpers); ++i) { if (qemu_ld_helpers[i] == NULL) { @@ -961,16 +934,8 @@ static void build_trampolines(TCGContext *s) } qemu_ld_trampoline[i] = tcg_splitwx_to_rx(s->code_ptr); - if (SPARC64 || TARGET_LONG_BITS == 32) { - ra = TCG_REG_O3; - } else { - /* Install the high part of the address. */ - tcg_out_arithi(s, TCG_REG_O1, TCG_REG_O2, 32, SHIFT_SRLX); - ra = TCG_REG_O4; - } - /* Set the retaddr operand. */ - tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O3, TCG_REG_O7); /* Tail call. */ tcg_out_jmpl_const(s, qemu_ld_helpers[i], true, true); /* delay slot -- set the env argument */ @@ -988,37 +953,10 @@ static void build_trampolines(TCGContext *s) } qemu_st_trampoline[i] = tcg_splitwx_to_rx(s->code_ptr); - if (SPARC64) { - emit_extend(s, TCG_REG_O2, i); - ra = TCG_REG_O4; - } else { - ra = TCG_REG_O1; - if (TARGET_LONG_BITS == 64) { - /* Install the high part of the address. */ - tcg_out_arithi(s, ra, ra + 1, 32, SHIFT_SRLX); - ra += 2; - } else { - ra += 1; - } - if ((i & MO_SIZE) == MO_64) { - /* Install the high part of the data. */ - tcg_out_arithi(s, ra, ra + 1, 32, SHIFT_SRLX); - ra += 2; - } else { - emit_extend(s, ra, i); - ra += 1; - } - /* Skip the oi argument. */ - ra += 1; - } - + emit_extend(s, TCG_REG_O2, i); + /* Set the retaddr operand. */ - if (ra >= TCG_REG_O6) { - tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_O7, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET); - } else { - tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7); - } + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O4, TCG_REG_O7); /* Tail call. */ tcg_out_jmpl_const(s, qemu_st_helpers[i], true, true); @@ -1047,11 +985,6 @@ static void build_trampolines(TCGContext *s) qemu_unalign_st_trampoline = tcg_splitwx_to_rx(s->code_ptr); } - if (!SPARC64 && TARGET_LONG_BITS == 64) { - /* Install the high part of the address. */ - tcg_out_arithi(s, TCG_REG_O1, TCG_REG_O2, 32, SHIFT_SRLX); - } - /* Tail call. */ tcg_out_jmpl_const(s, helper, true, true); /* delay slot -- set the env argument */ @@ -1182,7 +1115,7 @@ static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addr, int mem_index, tcg_out_cmp(s, r0, r2, 0); /* If the guest address must be zero-extended, do so now. */ - if (SPARC64 && TARGET_LONG_BITS == 32) { + if (TARGET_LONG_BITS == 32) { tcg_out_arithi(s, r0, addr, 0, SHIFT_SRL); return r0; } @@ -1231,7 +1164,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, #ifdef CONFIG_SOFTMMU unsigned memi = get_mmuidx(oi); - TCGReg addrz, param; + TCGReg addrz; const tcg_insn_unit *func; addrz = tcg_out_tlb_load(s, addr, memi, memop, @@ -1251,12 +1184,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, /* TLB Miss. */ - param = TCG_REG_O1; - if (!SPARC64 && TARGET_LONG_BITS == 64) { - /* Skip the high-part; we'll perform the extract in the trampoline. */ - param++; - } - tcg_out_mov(s, TCG_TYPE_REG, param++, addrz); + tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_O1, addrz); /* We use the helpers to extend SB and SW data, leaving the case of SL needing explicit extending below. */ @@ -1268,30 +1196,13 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, tcg_debug_assert(func != NULL); tcg_out_call_nodelay(s, func, false); /* delay slot */ - tcg_out_movi(s, TCG_TYPE_I32, param, oi); - - /* Recall that all of the helpers return 64-bit results. - Which complicates things for sparcv8plus. */ - if (SPARC64) { - /* We let the helper sign-extend SB and SW, but leave SL for here. */ - if (is_64 && (memop & MO_SSIZE) == MO_SL) { - tcg_out_arithi(s, data, TCG_REG_O0, 0, SHIFT_SRA); - } else { - tcg_out_mov(s, TCG_TYPE_REG, data, TCG_REG_O0); - } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_O2, oi); + + /* We let the helper sign-extend SB and SW, but leave SL for here. */ + if (is_64 && (memop & MO_SSIZE) == MO_SL) { + tcg_out_arithi(s, data, TCG_REG_O0, 0, SHIFT_SRA); } else { - if ((memop & MO_SIZE) == MO_64) { - tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, 32, SHIFT_SLLX); - tcg_out_arithi(s, TCG_REG_O1, TCG_REG_O1, 0, SHIFT_SRL); - tcg_out_arith(s, data, TCG_REG_O0, TCG_REG_O1, ARITH_OR); - } else if (is_64) { - /* Re-extend from 32-bit rather than reassembling when we - know the high register must be an extension. */ - tcg_out_arithi(s, data, TCG_REG_O1, 0, - memop & MO_SIGN ? SHIFT_SRA : SHIFT_SRL); - } else { - tcg_out_mov(s, TCG_TYPE_I32, data, TCG_REG_O1); - } + tcg_out_mov(s, TCG_TYPE_REG, data, TCG_REG_O0); } *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr)); @@ -1301,7 +1212,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, unsigned s_bits = memop & MO_SIZE; unsigned t_bits; - if (SPARC64 && TARGET_LONG_BITS == 32) { + if (TARGET_LONG_BITS == 32) { tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL); addr = TCG_REG_T1; } @@ -1337,10 +1248,9 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, * operation in the delay slot, and failure need only invoke the * handler for SIGBUS. */ - TCGReg arg_low = TCG_REG_O1 + (!SPARC64 && TARGET_LONG_BITS == 64); tcg_out_call_nodelay(s, qemu_unalign_ld_trampoline, false); /* delay slot -- move to low part of argument reg */ - tcg_out_mov_delay(s, arg_low, addr); + tcg_out_mov_delay(s, TCG_REG_O1, addr); } else { /* Underalignment: load by pieces of minimum alignment. */ int ld_opc, a_size, s_size, i; @@ -1400,7 +1310,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, #ifdef CONFIG_SOFTMMU unsigned memi = get_mmuidx(oi); - TCGReg addrz, param; + TCGReg addrz; const tcg_insn_unit *func; addrz = tcg_out_tlb_load(s, addr, memi, memop, @@ -1418,23 +1328,14 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, /* TLB Miss. */ - param = TCG_REG_O1; - if (!SPARC64 && TARGET_LONG_BITS == 64) { - /* Skip the high-part; we'll perform the extract in the trampoline. */ - param++; - } - tcg_out_mov(s, TCG_TYPE_REG, param++, addrz); - if (!SPARC64 && (memop & MO_SIZE) == MO_64) { - /* Skip the high-part; we'll perform the extract in the trampoline. */ - param++; - } - tcg_out_mov(s, TCG_TYPE_REG, param++, data); + tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_O1, addrz); + tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_O2, data); func = qemu_st_trampoline[memop & (MO_BSWAP | MO_SIZE)]; tcg_debug_assert(func != NULL); tcg_out_call_nodelay(s, func, false); /* delay slot */ - tcg_out_movi(s, TCG_TYPE_I32, param, oi); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_O3, oi); *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr)); #else @@ -1443,7 +1344,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, unsigned s_bits = memop & MO_SIZE; unsigned t_bits; - if (SPARC64 && TARGET_LONG_BITS == 32) { + if (TARGET_LONG_BITS == 32) { tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL); addr = TCG_REG_T1; } @@ -1479,10 +1380,9 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, * operation in the delay slot, and failure need only invoke the * handler for SIGBUS. */ - TCGReg arg_low = TCG_REG_O1 + (!SPARC64 && TARGET_LONG_BITS == 64); tcg_out_call_nodelay(s, qemu_unalign_st_trampoline, false); /* delay slot -- move to low part of argument reg */ - tcg_out_mov_delay(s, arg_low, addr); + tcg_out_mov_delay(s, TCG_REG_O1, addr); } else { /* Underalignment: store by pieces of minimum alignment. */ int st_opc, a_size, s_size, i; @@ -1719,14 +1619,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_muls2_i32: c = ARITH_SMUL; do_mul2: - /* The 32-bit multiply insns produce a full 64-bit result. If the - destination register can hold it, we can avoid the slower RDY. */ + /* The 32-bit multiply insns produce a full 64-bit result. */ tcg_out_arithc(s, a0, a2, args[3], const_args[3], c); - if (SPARC64 || a0 <= TCG_REG_O7) { - tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX); - } else { - tcg_out_rdy(s, a1); - } + tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX); break; case INDEX_op_qemu_ld_i32: @@ -1833,107 +1728,91 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) return C_O0_I1(r); case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i32: + case INDEX_op_ld8s_i64: case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: case INDEX_op_ld16s_i32: + case INDEX_op_ld16s_i64: case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + case INDEX_op_ld32s_i64: + case INDEX_op_ld_i64: case INDEX_op_neg_i32: + case INDEX_op_neg_i64: case INDEX_op_not_i32: + case INDEX_op_not_i64: + case INDEX_op_ext32s_i64: + case INDEX_op_ext32u_i64: + case INDEX_op_ext_i32_i64: + case INDEX_op_extu_i32_i64: + case INDEX_op_extrl_i64_i32: + case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); case INDEX_op_st8_i32: + case INDEX_op_st8_i64: case INDEX_op_st16_i32: + case INDEX_op_st16_i64: case INDEX_op_st_i32: + case INDEX_op_st32_i64: + case INDEX_op_st_i64: return C_O0_I2(rZ, r); case INDEX_op_add_i32: + case INDEX_op_add_i64: case INDEX_op_mul_i32: + case INDEX_op_mul_i64: case INDEX_op_div_i32: + case INDEX_op_div_i64: case INDEX_op_divu_i32: + case INDEX_op_divu_i64: case INDEX_op_sub_i32: + case INDEX_op_sub_i64: case INDEX_op_and_i32: + case INDEX_op_and_i64: case INDEX_op_andc_i32: + case INDEX_op_andc_i64: case INDEX_op_or_i32: + case INDEX_op_or_i64: case INDEX_op_orc_i32: + case INDEX_op_orc_i64: case INDEX_op_xor_i32: + case INDEX_op_xor_i64: case INDEX_op_shl_i32: + case INDEX_op_shl_i64: case INDEX_op_shr_i32: + case INDEX_op_shr_i64: case INDEX_op_sar_i32: + case INDEX_op_sar_i64: case INDEX_op_setcond_i32: + case INDEX_op_setcond_i64: return C_O1_I2(r, rZ, rJ); case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: return C_O0_I2(rZ, rJ); case INDEX_op_movcond_i32: + case INDEX_op_movcond_i64: return C_O1_I4(r, rZ, rJ, rI, 0); case INDEX_op_add2_i32: + case INDEX_op_add2_i64: case INDEX_op_sub2_i32: + case INDEX_op_sub2_i64: return C_O2_I4(r, r, rZ, rZ, rJ, rJ); case INDEX_op_mulu2_i32: case INDEX_op_muls2_i32: return C_O2_I2(r, r, rZ, rJ); - - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: - case INDEX_op_ext_i32_i64: - case INDEX_op_extu_i32_i64: - return C_O1_I1(R, r); - - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(RZ, r); - - case INDEX_op_add_i64: - case INDEX_op_mul_i64: - case INDEX_op_div_i64: - case INDEX_op_divu_i64: - case INDEX_op_sub_i64: - case INDEX_op_and_i64: - case INDEX_op_andc_i64: - case INDEX_op_or_i64: - case INDEX_op_orc_i64: - case INDEX_op_xor_i64: - case INDEX_op_shl_i64: - case INDEX_op_shr_i64: - case INDEX_op_sar_i64: - case INDEX_op_setcond_i64: - return C_O1_I2(R, RZ, RJ); - - case INDEX_op_neg_i64: - case INDEX_op_not_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - return C_O1_I1(R, R); - - case INDEX_op_extrl_i64_i32: - case INDEX_op_extrh_i64_i32: - return C_O1_I1(r, R); - - case INDEX_op_brcond_i64: - return C_O0_I2(RZ, RJ); - case INDEX_op_movcond_i64: - return C_O1_I4(R, RZ, RJ, RI, 0); - case INDEX_op_add2_i64: - case INDEX_op_sub2_i64: - return C_O2_I4(R, R, RZ, RZ, RJ, RI); case INDEX_op_muluh_i64: - return C_O1_I2(R, R, R); + return C_O1_I2(r, r, r); case INDEX_op_qemu_ld_i32: - return C_O1_I1(r, A); case INDEX_op_qemu_ld_i64: - return C_O1_I1(R, A); + return C_O1_I1(r, s); case INDEX_op_qemu_st_i32: - return C_O0_I2(sZ, A); case INDEX_op_qemu_st_i64: - return C_O0_I2(SZ, A); + return C_O0_I2(sZ, s); default: g_assert_not_reached(); @@ -1954,7 +1833,7 @@ static void tcg_target_init(TCGContext *s) #endif tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; - tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS64; + tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS; tcg_target_call_clobber_regs = 0; tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_G1); @@ -1984,16 +1863,11 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_T2); /* for internal use */ } -#if SPARC64 -# define ELF_HOST_MACHINE EM_SPARCV9 -#else -# define ELF_HOST_MACHINE EM_SPARC32PLUS -# define ELF_HOST_FLAGS EF_SPARC_32PLUS -#endif +#define ELF_HOST_MACHINE EM_SPARCV9 typedef struct { DebugFrameHeader h; - uint8_t fde_def_cfa[SPARC64 ? 4 : 2]; + uint8_t fde_def_cfa[4]; uint8_t fde_win_save; uint8_t fde_ret_save[3]; } DebugFrame; @@ -2010,12 +1884,8 @@ static const DebugFrame debug_frame = { .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), .fde_def_cfa = { -#if SPARC64 12, 30, /* DW_CFA_def_cfa i6, 2047 */ (2047 & 0x7f) | 0x80, (2047 >> 7) -#else - 13, 30 /* DW_CFA_def_cfa_register i6 */ -#endif }, .fde_win_save = 0x2d, /* DW_CFA_GNU_window_save */ .fde_ret_save = { 9, 15, 31 }, /* DW_CFA_register o7, i7 */ diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc64/tcg-target.h similarity index 95% rename from tcg/sparc/tcg-target.h rename to tcg/sparc64/tcg-target.h index c05076304953..0044ac8d7894 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -25,8 +25,6 @@ #ifndef SPARC_TCG_TARGET_H #define SPARC_TCG_TARGET_H -#define TCG_TARGET_REG_BITS 64 - #define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_TLB_DISPLACEMENT_BITS 32 #define TCG_TARGET_NB_REGS 32 @@ -70,19 +68,11 @@ typedef enum { /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_O6 -#ifdef __arch64__ #define TCG_TARGET_STACK_BIAS 2047 #define TCG_TARGET_STACK_ALIGN 16 #define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS) -#else -#define TCG_TARGET_STACK_BIAS 0 -#define TCG_TARGET_STACK_ALIGN 8 -#define TCG_TARGET_CALL_STACK_OFFSET (64 + 4 + 6*4) -#endif - -#ifdef __arch64__ -#define TCG_TARGET_EXTEND_ARGS 1 -#endif +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL #if defined(__VIS__) && __VIS__ >= 0x300 #define use_vis3_instructions 1 diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index 92c91dcde97b..6e50aeba3aea 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -23,15 +23,55 @@ */ #ifndef TCG_INTERNAL_H -#define TCG_INTERNAL_H 1 +#define TCG_INTERNAL_H + +#ifdef CONFIG_TCG_INTERPRETER +#include +#endif #define TCG_HIGHWATER 1024 +/* + * Describe the calling convention of a given argument type. + */ +typedef enum { + TCG_CALL_RET_NORMAL, /* by registers */ +} TCGCallReturnKind; + +typedef enum { + TCG_CALL_ARG_NORMAL, /* by registers (continuing onto stack) */ + TCG_CALL_ARG_EVEN, /* like normal, but skipping odd slots */ + TCG_CALL_ARG_EXTEND, /* for i32, as a sign/zero-extended i64 */ + TCG_CALL_ARG_EXTEND_U, /* ... as a zero-extended i64 */ + TCG_CALL_ARG_EXTEND_S, /* ... as a sign-extended i64 */ +} TCGCallArgumentKind; + +typedef struct TCGCallArgumentLoc { + TCGCallArgumentKind kind : 8; + unsigned arg_slot : 8; + unsigned ref_slot : 8; + unsigned arg_idx : 4; + unsigned tmp_subindex : 2; +} TCGCallArgumentLoc; + +/* Avoid "unsigned < 0 is always false" Werror, when iarg_regs is empty. */ +#define REG_P(L) \ + ((int)(L)->arg_slot < (int)ARRAY_SIZE(tcg_target_call_iarg_regs)) + typedef struct TCGHelperInfo { void *func; const char *name; - unsigned flags; - unsigned typemask; +#ifdef CONFIG_TCG_INTERPRETER + ffi_cif *cif; +#endif + unsigned typemask : 32; + unsigned flags : 8; + unsigned nr_in : 8; + unsigned nr_out : 8; + TCGCallReturnKind out_kind : 8; + + /* Maximum physical arguments are constrained by TCG_TYPE_I128. */ + TCGCallArgumentLoc in[MAX_CALL_IARGS * (128 / TCG_TARGET_REG_BITS)]; } TCGHelperInfo; extern TCGContext tcg_init_ctx; @@ -59,4 +99,18 @@ static inline unsigned tcg_call_flags(TCGOp *op) return tcg_call_info(op)->flags; } +#if TCG_TARGET_REG_BITS == 32 +static inline TCGv_i32 TCGV_LOW(TCGv_i64 t) +{ + return temp_tcgv_i32(tcgv_i64_temp(t) + HOST_BIG_ENDIAN); +} +static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) +{ + return temp_tcgv_i32(tcgv_i64_temp(t) + !HOST_BIG_ENDIAN); +} +#else +extern TCGv_i32 TCGV_LOW(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); +extern TCGv_i32 TCGV_HIGH(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); +#endif + #endif /* TCG_INTERNAL_H */ diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index 463dabf51503..966d41d65a88 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -21,6 +21,8 @@ #include "tcg/tcg.h" #include "tcg/tcg-op.h" #include "tcg/tcg-mo.h" +#include "tcg-internal.h" + /* Reduce the number of ifdefs below. This assumes that all uses of TCGV_HIGH and TCGV_LOW are properly protected by a conditional that @@ -150,7 +152,7 @@ bool tcg_can_emit_vecop_list(const TCGOpcode *list, void vec_gen_2(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 2); TCGOP_VECL(op) = type - TCG_TYPE_V64; TCGOP_VECE(op) = vece; op->args[0] = r; @@ -160,7 +162,7 @@ void vec_gen_2(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a) void vec_gen_3(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a, TCGArg b) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 3); TCGOP_VECL(op) = type - TCG_TYPE_V64; TCGOP_VECE(op) = vece; op->args[0] = r; @@ -171,7 +173,7 @@ void vec_gen_3(TCGOpcode opc, TCGType type, unsigned vece, void vec_gen_4(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a, TCGArg b, TCGArg c) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 4); TCGOP_VECL(op) = type - TCG_TYPE_V64; TCGOP_VECE(op) = vece; op->args[0] = r; @@ -183,7 +185,7 @@ void vec_gen_4(TCGOpcode opc, TCGType type, unsigned vece, static void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 6); TCGOP_VECL(op) = type - TCG_TYPE_V64; TCGOP_VECE(op) = vece; op->args[0] = r; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 65e1c94c2d5c..cd1cd4e7367a 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -28,33 +28,25 @@ #include "tcg/tcg-op.h" #include "tcg/tcg-mo.h" #include "exec/plugin-gen.h" +#include "tcg-internal.h" -/* Reduce the number of ifdefs below. This assumes that all uses of - TCGV_HIGH and TCGV_LOW are properly protected by a conditional that - the compiler can eliminate. */ -#if TCG_TARGET_REG_BITS == 64 -extern TCGv_i32 TCGV_LOW_link_error(TCGv_i64); -extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64); -#define TCGV_LOW TCGV_LOW_link_error -#define TCGV_HIGH TCGV_HIGH_link_error -#endif void tcg_gen_op1(TCGOpcode opc, TCGArg a1) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 1); op->args[0] = a1; } void tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 2); op->args[0] = a1; op->args[1] = a2; } void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 3); op->args[0] = a1; op->args[1] = a2; op->args[2] = a3; @@ -62,7 +54,7 @@ void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 4); op->args[0] = a1; op->args[1] = a2; op->args[2] = a3; @@ -72,7 +64,7 @@ void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4, TCGArg a5) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 5); op->args[0] = a1; op->args[1] = a2; op->args[2] = a3; @@ -83,7 +75,7 @@ void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4, TCGArg a5, TCGArg a6) { - TCGOp *op = tcg_emit_op(opc); + TCGOp *op = tcg_emit_op(opc, 6); op->args[0] = a1; op->args[1] = a2; op->args[2] = a3; @@ -1056,6 +1048,12 @@ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) } } +void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + /* Swapping 2 16-bit elements is a rotate. */ + tcg_gen_rotli_i32(ret, arg, 16); +} + void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); @@ -1156,7 +1154,7 @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { /* Since arg2 and ret have different types, they cannot be the same temporary */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); #else @@ -1165,9 +1163,24 @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) #endif } +void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); +} + +void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); +} + +void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); +} + void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); #else @@ -1176,6 +1189,18 @@ void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) #endif } +void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), + TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); +} + +void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), + TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); +} + void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); @@ -1792,6 +1817,30 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) } } +void tcg_gen_hswap_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + uint64_t m = 0x0000ffff0000ffffull; + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + /* See include/qemu/bitops.h, hswap64. */ + tcg_gen_rotli_i64(t1, arg, 32); + tcg_gen_andi_i64(t0, t1, m); + tcg_gen_shli_i64(t0, t0, 16); + tcg_gen_shri_i64(t1, t1, 16); + tcg_gen_andi_i64(t1, t1, m); + tcg_gen_or_i64(ret, t0, t1); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +void tcg_gen_wswap_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + /* Swapping 2 32-bit elements is a rotate. */ + tcg_gen_rotli_i64(ret, arg, 32); +} + void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 32) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 33a97eabdb83..da91779890cb 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -51,7 +51,7 @@ #else # define ELF_CLASS ELFCLASS64 #endif -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN # define ELF_DATA ELFDATA2MSB #else # define ELF_DATA ELFDATA2LSB @@ -62,10 +62,6 @@ #include "tcg/tcg-ldst.h" #include "tcg-internal.h" -#ifdef CONFIG_TCG_INTERPRETER -#include -#endif - /* Forward declarations for functions declared in tcg-target.c.inc and used here. */ static void tcg_target_init(TCGContext *s); @@ -149,12 +145,8 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, intptr_t arg2); static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg base, intptr_t ofs); -#ifdef CONFIG_TCG_INTERPRETER static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, - ffi_cif *cif); -#else -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target); -#endif + const TCGHelperInfo *info); static bool tcg_target_const_match(int64_t val, TCGType type, int ct); #ifdef TCG_TARGET_NEED_LDST_LABELS static int tcg_out_ldst_finalize(TCGContext *s); @@ -320,7 +312,8 @@ static void set_jmp_reset_offset(TCGContext *s, int which) } /* Signal overflow, starting over with fewer guest insns. */ -static void QEMU_NORETURN tcg_raise_tb_overflow(TCGContext *s) +static G_NORETURN +void tcg_raise_tb_overflow(TCGContext *s) { siglongjmp(s->jmp_trans, -2); } @@ -495,7 +488,7 @@ void *tcg_malloc_internal(TCGContext *s, int size) { TCGPool *p; int pool_size; - + if (size > TCG_POOL_CHUNK_SIZE) { /* big malloc: insert a new pool (XXX: could optimize) */ p = g_malloc(sizeof(TCGPool) + size); @@ -516,10 +509,11 @@ void *tcg_malloc_internal(TCGContext *s, int size) p = g_malloc(sizeof(TCGPool) + pool_size); p->size = pool_size; p->next = NULL; - if (s->pool_current) + if (s->pool_current) { s->pool_current->next = p; - else + } else { s->pool_first = p; + } } else { p = p->next; } @@ -545,23 +539,230 @@ void tcg_pool_reset(TCGContext *s) #include "exec/helper-proto.h" -static const TCGHelperInfo all_helpers[] = { +static TCGHelperInfo all_helpers[] = { #include "exec/helper-tcg.h" }; static GHashTable *helper_table; #ifdef CONFIG_TCG_INTERPRETER -static GHashTable *ffi_table; - -static ffi_type * const typecode_to_ffi[8] = { - [dh_typecode_void] = &ffi_type_void, - [dh_typecode_i32] = &ffi_type_uint32, - [dh_typecode_s32] = &ffi_type_sint32, - [dh_typecode_i64] = &ffi_type_uint64, - [dh_typecode_s64] = &ffi_type_sint64, - [dh_typecode_ptr] = &ffi_type_pointer, -}; -#endif +static ffi_type *typecode_to_ffi(int argmask) +{ + switch (argmask) { + case dh_typecode_void: + return &ffi_type_void; + case dh_typecode_i32: + return &ffi_type_uint32; + case dh_typecode_s32: + return &ffi_type_sint32; + case dh_typecode_i64: + return &ffi_type_uint64; + case dh_typecode_s64: + return &ffi_type_sint64; + case dh_typecode_ptr: + return &ffi_type_pointer; + } + g_assert_not_reached(); +} + +static void init_ffi_layouts(void) +{ + /* g_direct_hash/equal for direct comparisons on uint32_t. */ + GHashTable *ffi_table = g_hash_table_new(NULL, NULL); + + for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { + TCGHelperInfo *info = &all_helpers[i]; + unsigned typemask = info->typemask; + gpointer hash = (gpointer)(uintptr_t)typemask; + struct { + ffi_cif cif; + ffi_type *args[]; + } *ca; + ffi_status status; + int nargs; + ffi_cif *cif; + + cif = g_hash_table_lookup(ffi_table, hash); + if (cif) { + info->cif = cif; + continue; + } + + /* Ignoring the return type, find the last non-zero field. */ + nargs = 32 - clz32(typemask >> 3); + nargs = DIV_ROUND_UP(nargs, 3); + + ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); + ca->cif.rtype = typecode_to_ffi(typemask & 7); + ca->cif.nargs = nargs; + + if (nargs != 0) { + ca->cif.arg_types = ca->args; + for (int j = 0; j < nargs; ++j) { + int typecode = extract32(typemask, (j + 1) * 3, 3); + ca->args[j] = typecode_to_ffi(typecode); + } + } + + status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, + ca->cif.rtype, ca->cif.arg_types); + assert(status == FFI_OK); + + cif = &ca->cif; + info->cif = cif; + g_hash_table_insert(ffi_table, hash, (gpointer)cif); + } + + g_hash_table_destroy(ffi_table); +} +#endif /* CONFIG_TCG_INTERPRETER */ + +typedef struct TCGCumulativeArgs { + int arg_idx; /* tcg_gen_callN args[] */ + int info_in_idx; /* TCGHelperInfo in[] */ + int arg_slot; /* regs+stack slot */ + int ref_slot; /* stack slots for references */ +} TCGCumulativeArgs; + +static void layout_arg_even(TCGCumulativeArgs *cum) +{ + cum->arg_slot += cum->arg_slot & 1; +} + +static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, + TCGCallArgumentKind kind) +{ + TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; + + *loc = (TCGCallArgumentLoc){ + .kind = kind, + .arg_idx = cum->arg_idx, + .arg_slot = cum->arg_slot, + }; + cum->info_in_idx++; + cum->arg_slot++; +} + +static void layout_arg_normal_n(TCGCumulativeArgs *cum, + TCGHelperInfo *info, int n) +{ + TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; + + for (int i = 0; i < n; ++i) { + /* Layout all using the same arg_idx, adjusting the subindex. */ + loc[i] = (TCGCallArgumentLoc){ + .kind = TCG_CALL_ARG_NORMAL, + .arg_idx = cum->arg_idx, + .tmp_subindex = i, + .arg_slot = cum->arg_slot + i, + }; + } + cum->info_in_idx += n; + cum->arg_slot += n; +} + +static void init_call_layout(TCGHelperInfo *info) +{ + int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); + int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); + unsigned typemask = info->typemask; + unsigned typecode; + TCGCumulativeArgs cum = { }; + + /* + * Parse and place any function return value. + */ + typecode = typemask & 7; + switch (typecode) { + case dh_typecode_void: + info->nr_out = 0; + break; + case dh_typecode_i32: + case dh_typecode_s32: + case dh_typecode_ptr: + info->nr_out = 1; + info->out_kind = TCG_CALL_RET_NORMAL; + break; + case dh_typecode_i64: + case dh_typecode_s64: + info->nr_out = 64 / TCG_TARGET_REG_BITS; + info->out_kind = TCG_CALL_RET_NORMAL; + break; + default: + g_assert_not_reached(); + } + assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); + + /* + * Parse and place function arguments. + */ + for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { + TCGCallArgumentKind kind; + TCGType type; + + typecode = typemask & 7; + switch (typecode) { + case dh_typecode_i32: + case dh_typecode_s32: + type = TCG_TYPE_I32; + break; + case dh_typecode_i64: + case dh_typecode_s64: + type = TCG_TYPE_I64; + break; + case dh_typecode_ptr: + type = TCG_TYPE_PTR; + break; + default: + g_assert_not_reached(); + } + + switch (type) { + case TCG_TYPE_I32: + switch (TCG_TARGET_CALL_ARG_I32) { + case TCG_CALL_ARG_EVEN: + layout_arg_even(&cum); + /* fall through */ + case TCG_CALL_ARG_NORMAL: + layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); + break; + case TCG_CALL_ARG_EXTEND: + kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); + layout_arg_1(&cum, info, kind); + break; + default: + qemu_build_not_reached(); + } + break; + + case TCG_TYPE_I64: + switch (TCG_TARGET_CALL_ARG_I64) { + case TCG_CALL_ARG_EVEN: + layout_arg_even(&cum); + /* fall through */ + case TCG_CALL_ARG_NORMAL: + if (TCG_TARGET_REG_BITS == 32) { + layout_arg_normal_n(&cum, info, 2); + } else { + layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); + } + break; + default: + qemu_build_not_reached(); + } + break; + + default: + g_assert_not_reached(); + } + } + info->nr_in = cum.info_in_idx; + + /* Validate that we didn't overrun the input array. */ + assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); + /* Validate the backend has enough argument space. */ + assert(cum.arg_slot <= max_reg_slots + max_stk_slots); + assert(cum.ref_slot <= max_stk_slots); +} static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; static void process_op_defs(TCGContext *s); @@ -602,49 +803,13 @@ static void tcg_context_init(unsigned max_cpus) helper_table = g_hash_table_new(NULL, NULL); for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { + init_call_layout(&all_helpers[i]); g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, (gpointer)&all_helpers[i]); } #ifdef CONFIG_TCG_INTERPRETER - /* g_direct_hash/equal for direct comparisons on uint32_t. */ - ffi_table = g_hash_table_new(NULL, NULL); - for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { - struct { - ffi_cif cif; - ffi_type *args[]; - } *ca; - uint32_t typemask = all_helpers[i].typemask; - gpointer hash = (gpointer)(uintptr_t)typemask; - ffi_status status; - int nargs; - - if (g_hash_table_lookup(ffi_table, hash)) { - continue; - } - - /* Ignoring the return type, find the last non-zero field. */ - nargs = 32 - clz32(typemask >> 3); - nargs = DIV_ROUND_UP(nargs, 3); - - ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); - ca->cif.rtype = typecode_to_ffi[typemask & 7]; - ca->cif.nargs = nargs; - - if (nargs != 0) { - ca->cif.arg_types = ca->args; - for (i = 0; i < nargs; ++i) { - int typecode = extract32(typemask, (i + 1) * 3, 3); - ca->args[i] = typecode_to_ffi[typecode]; - } - } - - status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, - ca->cif.rtype, ca->cif.arg_types); - assert(status == FFI_OK); - - g_hash_table_insert(ffi_table, hash, (gpointer)&ca->cif); - } + init_ffi_layouts(); #endif tcg_target_init(s); @@ -756,32 +921,35 @@ void tcg_prologue_init(TCGContext *s) #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { - FILE *logfile = qemu_log_lock(); - qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); - if (s->data_gen_ptr) { - size_t code_size = s->data_gen_ptr - s->code_gen_ptr; - size_t data_size = prologue_size - code_size; - size_t i; - - log_disas(s->code_gen_ptr, code_size); - - for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { - if (sizeof(tcg_target_ulong) == 8) { - qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", - (uintptr_t)s->data_gen_ptr + i, - *(uint64_t *)(s->data_gen_ptr + i)); - } else { - qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", - (uintptr_t)s->data_gen_ptr + i, - *(uint32_t *)(s->data_gen_ptr + i)); + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size); + if (s->data_gen_ptr) { + size_t code_size = s->data_gen_ptr - s->code_gen_ptr; + size_t data_size = prologue_size - code_size; + size_t i; + + disas(logfile, s->code_gen_ptr, code_size); + + for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { + if (sizeof(tcg_target_ulong) == 8) { + fprintf(logfile, + "0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", + (uintptr_t)s->data_gen_ptr + i, + *(uint64_t *)(s->data_gen_ptr + i)); + } else { + fprintf(logfile, + "0x%08" PRIxPTR ": .long 0x%08x\n", + (uintptr_t)s->data_gen_ptr + i, + *(uint32_t *)(s->data_gen_ptr + i)); + } } + } else { + disas(logfile, s->code_gen_ptr, prologue_size); } - } else { - log_disas(s->code_gen_ptr, prologue_size); + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); } - qemu_log("\n"); - qemu_log_flush(); - qemu_log_unlock(logfile); } #endif @@ -882,10 +1050,7 @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, TCGContext *s = tcg_ctx; TCGTemp *base_ts = tcgv_ptr_temp(base); TCGTemp *ts = tcg_global_alloc(s); - int indirect_reg = 0, bigendian = 0; -#ifdef HOST_WORDS_BIGENDIAN - bigendian = 1; -#endif + int indirect_reg = 0; switch (base_ts->kind) { case TEMP_FIXED: @@ -911,7 +1076,7 @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, ts->indirect_reg = indirect_reg; ts->mem_allocated = 1; ts->mem_base = base_ts; - ts->mem_offset = offset + bigendian * 4; + ts->mem_offset = offset; pstrcpy(buf, sizeof(buf), name); pstrcat(buf, sizeof(buf), "_0"); ts->name = strdup(buf); @@ -922,7 +1087,8 @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, ts2->indirect_reg = indirect_reg; ts2->mem_allocated = 1; ts2->mem_base = base_ts; - ts2->mem_offset = offset + (1 - bigendian) * 4; + ts2->mem_offset = offset + 4; + ts2->temp_subindex = 1; pstrcpy(buf, sizeof(buf), name); pstrcat(buf, sizeof(buf), "_1"); ts2->name = strdup(buf); @@ -969,6 +1135,7 @@ TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) ts2->base_type = TCG_TYPE_I64; ts2->type = TCG_TYPE_I32; ts2->temp_allocated = 1; + ts2->temp_subindex = 1; ts2->kind = kind; } else { ts->base_type = type; @@ -1024,9 +1191,18 @@ void tcg_temp_free_internal(TCGTemp *ts) TCGContext *s = tcg_ctx; int k, idx; - /* In order to simplify users of tcg_constant_*, silently ignore free. */ - if (ts->kind == TEMP_CONST) { + switch (ts->kind) { + case TEMP_CONST: + /* + * In order to simplify users of tcg_constant_*, + * silently ignore free. + */ return; + case TEMP_NORMAL: + case TEMP_LOCAL: + break; + default: + g_assert_not_reached(); } #if defined(CONFIG_DEBUG_TCG) @@ -1036,7 +1212,6 @@ void tcg_temp_free_internal(TCGTemp *ts) } #endif - tcg_debug_assert(ts->kind < TEMP_GLOBAL); tcg_debug_assert(ts->temp_allocated != 0); ts->temp_allocated = 0; @@ -1058,36 +1233,43 @@ TCGTemp *tcg_constant_internal(TCGType type, int64_t val) ts = g_hash_table_lookup(h, &val); if (ts == NULL) { + int64_t *val_ptr; + ts = tcg_temp_alloc(s); if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { TCGTemp *ts2 = tcg_temp_alloc(s); + tcg_debug_assert(ts2 == ts + 1); + ts->base_type = TCG_TYPE_I64; ts->type = TCG_TYPE_I32; ts->kind = TEMP_CONST; ts->temp_allocated = 1; - /* - * Retain the full value of the 64-bit constant in the low - * part, so that the hash table works. Actual uses will - * truncate the value to the low part. - */ - ts->val = val; - tcg_debug_assert(ts2 == ts + 1); ts2->base_type = TCG_TYPE_I64; ts2->type = TCG_TYPE_I32; ts2->kind = TEMP_CONST; ts2->temp_allocated = 1; - ts2->val = val >> 32; + ts2->temp_subindex = 1; + + /* + * Retain the full value of the 64-bit constant in the low + * part, so that the hash table works. Actual uses will + * truncate the value to the low part. + */ + ts[HOST_BIG_ENDIAN].val = val; + ts[!HOST_BIG_ENDIAN].val = val >> 32; + val_ptr = &ts[HOST_BIG_ENDIAN].val; } else { ts->base_type = type; ts->type = type; ts->kind = TEMP_CONST; ts->temp_allocated = 1; ts->val = val; + val_ptr = &ts->val; } - g_hash_table_insert(h, &ts->val, ts); + g_hash_table_insert(h, val_ptr, ts); } return ts; @@ -1455,18 +1637,19 @@ bool tcg_op_supported(TCGOpcode op) } } -/* Note: we convert the 64 bit args to 32 bit and do some alignment - and endian swap. Maybe it would be better to do the alignment - and endian swap in tcg_reg_alloc_call(). */ +static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); + void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) { - int i, real_args, nb_rets, pi; - unsigned typemask; const TCGHelperInfo *info; + TCGv_i64 extend_free[MAX_CALL_IARGS]; + int n_extend = 0; TCGOp *op; + int i, n, pi = 0, total_args; info = g_hash_table_lookup(helper_table, (gpointer)func); - typemask = info->typemask; + total_args = info->nr_out + info->nr_in + 2; + op = tcg_op_alloc(INDEX_op_call, total_args); #ifdef CONFIG_PLUGIN /* detect non-plugin helpers */ @@ -1475,185 +1658,66 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) } #endif -#if defined(__sparc__) && !defined(__arch64__) \ - && !defined(CONFIG_TCG_INTERPRETER) - /* We have 64-bit values in one register, but need to pass as two - separate parameters. Split them. */ - int orig_typemask = typemask; - int orig_nargs = nargs; - TCGv_i64 retl, reth; - TCGTemp *split_args[MAX_OPC_PARAM]; - - retl = NULL; - reth = NULL; - typemask = 0; - for (i = real_args = 0; i < nargs; ++i) { - int argtype = extract32(orig_typemask, (i + 1) * 3, 3); - bool is_64bit = (argtype & ~1) == dh_typecode_i64; - - if (is_64bit) { - TCGv_i64 orig = temp_tcgv_i64(args[i]); - TCGv_i32 h = tcg_temp_new_i32(); - TCGv_i32 l = tcg_temp_new_i32(); - tcg_gen_extr_i64_i32(l, h, orig); - split_args[real_args++] = tcgv_i32_temp(h); - typemask |= dh_typecode_i32 << (real_args * 3); - split_args[real_args++] = tcgv_i32_temp(l); - typemask |= dh_typecode_i32 << (real_args * 3); - } else { - split_args[real_args++] = args[i]; - typemask |= argtype << (real_args * 3); - } - } - nargs = real_args; - args = split_args; -#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 - for (i = 0; i < nargs; ++i) { - int argtype = extract32(typemask, (i + 1) * 3, 3); - bool is_32bit = (argtype & ~1) == dh_typecode_i32; - bool is_signed = argtype & 1; - - if (is_32bit) { - TCGv_i64 temp = tcg_temp_new_i64(); - TCGv_i32 orig = temp_tcgv_i32(args[i]); - if (is_signed) { - tcg_gen_ext_i32_i64(temp, orig); - } else { - tcg_gen_extu_i32_i64(temp, orig); - } - args[i] = tcgv_i64_temp(temp); - } - } -#endif /* TCG_TARGET_EXTEND_ARGS */ - - op = tcg_emit_op(INDEX_op_call); - - pi = 0; - if (ret != NULL) { -#if defined(__sparc__) && !defined(__arch64__) \ - && !defined(CONFIG_TCG_INTERPRETER) - if ((typemask & 6) == dh_typecode_i64) { - /* The 32-bit ABI is going to return the 64-bit value in - the %o0/%o1 register pair. Prepare for this by using - two return temporaries, and reassemble below. */ - retl = tcg_temp_new_i64(); - reth = tcg_temp_new_i64(); - op->args[pi++] = tcgv_i64_arg(reth); - op->args[pi++] = tcgv_i64_arg(retl); - nb_rets = 2; - } else { - op->args[pi++] = temp_arg(ret); - nb_rets = 1; - } -#else - if (TCG_TARGET_REG_BITS < 64 && (typemask & 6) == dh_typecode_i64) { -#ifdef HOST_WORDS_BIGENDIAN - op->args[pi++] = temp_arg(ret + 1); - op->args[pi++] = temp_arg(ret); -#else - op->args[pi++] = temp_arg(ret); - op->args[pi++] = temp_arg(ret + 1); -#endif - nb_rets = 2; - } else { - op->args[pi++] = temp_arg(ret); - nb_rets = 1; - } -#endif - } else { - nb_rets = 0; + TCGOP_CALLO(op) = n = info->nr_out; + switch (n) { + case 0: + tcg_debug_assert(ret == NULL); + break; + case 1: + tcg_debug_assert(ret != NULL); + op->args[pi++] = temp_arg(ret); + break; + case 2: + tcg_debug_assert(ret != NULL); + tcg_debug_assert(ret->base_type == ret->type + 1); + tcg_debug_assert(ret->temp_subindex == 0); + op->args[pi++] = temp_arg(ret); + op->args[pi++] = temp_arg(ret + 1); + break; + default: + g_assert_not_reached(); } - TCGOP_CALLO(op) = nb_rets; - real_args = 0; - for (i = 0; i < nargs; i++) { - int argtype = extract32(typemask, (i + 1) * 3, 3); - bool is_64bit = (argtype & ~1) == dh_typecode_i64; - bool want_align = false; + TCGOP_CALLI(op) = n = info->nr_in; + for (i = 0; i < n; i++) { + const TCGCallArgumentLoc *loc = &info->in[i]; + TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; -#if defined(CONFIG_TCG_INTERPRETER) - /* - * Align all arguments, so that they land in predictable places - * for passing off to ffi_call. - */ - want_align = true; -#elif defined(TCG_TARGET_CALL_ALIGN_ARGS) - /* Some targets want aligned 64 bit args */ - want_align = is_64bit; -#endif + switch (loc->kind) { + case TCG_CALL_ARG_NORMAL: + op->args[pi++] = temp_arg(ts); + break; - if (TCG_TARGET_REG_BITS < 64 && want_align && (real_args & 1)) { - op->args[pi++] = TCG_CALL_DUMMY_ARG; - real_args++; - } + case TCG_CALL_ARG_EXTEND_U: + case TCG_CALL_ARG_EXTEND_S: + { + TCGv_i64 temp = tcg_temp_new_i64(); + TCGv_i32 orig = temp_tcgv_i32(ts); - if (TCG_TARGET_REG_BITS < 64 && is_64bit) { - /* - * If stack grows up, then we will be placing successive - * arguments at lower addresses, which means we need to - * reverse the order compared to how we would normally - * treat either big or little-endian. For those arguments - * that will wind up in registers, this still works for - * HPPA (the only current STACK_GROWSUP target) since the - * argument registers are *also* allocated in decreasing - * order. If another such target is added, this logic may - * have to get more complicated to differentiate between - * stack arguments and register arguments. - */ -#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) - op->args[pi++] = temp_arg(args[i] + 1); - op->args[pi++] = temp_arg(args[i]); -#else - op->args[pi++] = temp_arg(args[i]); - op->args[pi++] = temp_arg(args[i] + 1); -#endif - real_args += 2; - continue; - } + if (loc->kind == TCG_CALL_ARG_EXTEND_S) { + tcg_gen_ext_i32_i64(temp, orig); + } else { + tcg_gen_extu_i32_i64(temp, orig); + } + op->args[pi++] = tcgv_i64_arg(temp); + extend_free[n_extend++] = temp; + } + break; - op->args[pi++] = temp_arg(args[i]); - real_args++; + default: + g_assert_not_reached(); + } } op->args[pi++] = (uintptr_t)func; op->args[pi++] = (uintptr_t)info; - TCGOP_CALLI(op) = real_args; - - /* Make sure the fields didn't overflow. */ - tcg_debug_assert(TCGOP_CALLI(op) == real_args); - tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); - -#if defined(__sparc__) && !defined(__arch64__) \ - && !defined(CONFIG_TCG_INTERPRETER) - /* Free all of the parts we allocated above. */ - for (i = real_args = 0; i < orig_nargs; ++i) { - int argtype = extract32(orig_typemask, (i + 1) * 3, 3); - bool is_64bit = (argtype & ~1) == dh_typecode_i64; - - if (is_64bit) { - tcg_temp_free_internal(args[real_args++]); - tcg_temp_free_internal(args[real_args++]); - } else { - real_args++; - } - } - if ((orig_typemask & 6) == dh_typecode_i64) { - /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. - Note that describing these as TCGv_i64 eliminates an unnecessary - zero-extension that tcg_gen_concat_i32_i64 would create. */ - tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); - tcg_temp_free_i64(retl); - tcg_temp_free_i64(reth); - } -#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 - for (i = 0; i < nargs; ++i) { - int argtype = extract32(typemask, (i + 1) * 3, 3); - bool is_32bit = (argtype & ~1) == dh_typecode_i32; - - if (is_32bit) { - tcg_temp_free_internal(args[i]); - } + tcg_debug_assert(pi == total_args); + + QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); + + tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); + for (i = 0; i < n_extend; ++i) { + tcg_temp_free_i64(extend_free[i]); } -#endif /* TCG_TARGET_EXTEND_ARGS */ } static void tcg_reg_alloc_start(TCGContext *s) @@ -1674,6 +1738,7 @@ static void tcg_reg_alloc_start(TCGContext *s) case TEMP_GLOBAL: break; case TEMP_NORMAL: + case TEMP_EBB: val = TEMP_VAL_DEAD; /* fall through */ case TEMP_LOCAL: @@ -1701,6 +1766,9 @@ static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, case TEMP_LOCAL: snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); break; + case TEMP_EBB: + snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals); + break; case TEMP_NORMAL: snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); break; @@ -1804,7 +1872,11 @@ static inline TCGReg tcg_regset_first(TCGRegSet d) } } -static void tcg_dump_ops(TCGContext *s, bool have_prefs) +/* Return only the number of characters output -- no error return. */ +#define ne_fprintf(...) \ + ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; }) + +static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) { char buf[128]; TCGOp *op; @@ -1820,7 +1892,7 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) if (c == INDEX_op_insn_start) { nb_oargs = 0; - col += qemu_log("\n ----"); + col += ne_fprintf(f, "\n ----"); for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { target_ulong a; @@ -1829,7 +1901,7 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) #else a = op->args[i]; #endif - col += qemu_log(" " TARGET_FMT_lx, a); + col += ne_fprintf(f, " " TARGET_FMT_lx, a); } } else if (c == INDEX_op_call) { const TCGHelperInfo *info = tcg_call_info(op); @@ -1840,7 +1912,7 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) nb_iargs = TCGOP_CALLI(op); nb_cargs = def->nb_cargs; - col += qemu_log(" %s ", def->name); + col += ne_fprintf(f, " %s ", def->name); /* * Print the function name from TCGHelperInfo, if available. @@ -1848,50 +1920,45 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) * but the actual function pointer comes from the plugin. */ if (func == info->func) { - col += qemu_log("%s", info->name); + col += ne_fprintf(f, "%s", info->name); } else { - col += qemu_log("plugin(%p)", func); + col += ne_fprintf(f, "plugin(%p)", func); } - col += qemu_log(",$0x%x,$%d", info->flags, nb_oargs); + col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs); for (i = 0; i < nb_oargs; i++) { - col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), - op->args[i])); + col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf), + op->args[i])); } for (i = 0; i < nb_iargs; i++) { TCGArg arg = op->args[nb_oargs + i]; - const char *t = ""; - if (arg != TCG_CALL_DUMMY_ARG) { - t = tcg_get_arg_str(s, buf, sizeof(buf), arg); - } - col += qemu_log(",%s", t); + const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); + col += ne_fprintf(f, ",%s", t); } } else { - col += qemu_log(" %s ", def->name); + col += ne_fprintf(f, " %s ", def->name); nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; nb_cargs = def->nb_cargs; if (def->flags & TCG_OPF_VECTOR) { - col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), - 8 << TCGOP_VECE(op)); + col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op), + 8 << TCGOP_VECE(op)); } k = 0; for (i = 0; i < nb_oargs; i++) { - if (k != 0) { - col += qemu_log(","); - } - col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), - op->args[k++])); + const char *sep = k ? "," : ""; + col += ne_fprintf(f, "%s%s", sep, + tcg_get_arg_str(s, buf, sizeof(buf), + op->args[k++])); } for (i = 0; i < nb_iargs; i++) { - if (k != 0) { - col += qemu_log(","); - } - col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), - op->args[k++])); + const char *sep = k ? "," : ""; + col += ne_fprintf(f, "%s%s", sep, + tcg_get_arg_str(s, buf, sizeof(buf), + op->args[k++])); } switch (c) { case INDEX_op_brcond_i32: @@ -1906,9 +1973,9 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) case INDEX_op_cmpsel_vec: if (op->args[k] < ARRAY_SIZE(cond_name) && cond_name[op->args[k]]) { - col += qemu_log(",%s", cond_name[op->args[k++]]); + col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]); } else { - col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); + col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]); } i = 1; break; @@ -1923,12 +1990,12 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) unsigned ix = get_mmuidx(oi); if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { - col += qemu_log(",$0x%x,%u", op, ix); + col += ne_fprintf(f, ",$0x%x,%u", op, ix); } else { const char *s_al, *s_op; s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; - col += qemu_log(",%s%s,%u", s_al, s_op, ix); + col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix); } i = 1; } @@ -1946,9 +2013,9 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) name = bswap_flag_name[flags]; } if (name) { - col += qemu_log(",%s", name); + col += ne_fprintf(f, ",%s", name); } else { - col += qemu_log(",$0x%" TCG_PRIlx, flags); + col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); } i = k = 1; } @@ -1963,49 +2030,42 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: case INDEX_op_brcond2_i32: - col += qemu_log("%s$L%d", k ? "," : "", - arg_label(op->args[k])->id); + col += ne_fprintf(f, "%s$L%d", k ? "," : "", + arg_label(op->args[k])->id); i++, k++; break; default: break; } for (; i < nb_cargs; i++, k++) { - col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); + col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "", + op->args[k]); } } if (have_prefs || op->life) { - - QemuLogFile *logfile; - - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - for (; col < 40; ++col) { - putc(' ', logfile->fd); - } + for (; col < 40; ++col) { + putc(' ', f); } - rcu_read_unlock(); } if (op->life) { unsigned life = op->life; if (life & (SYNC_ARG * 3)) { - qemu_log(" sync:"); + ne_fprintf(f, " sync:"); for (i = 0; i < 2; ++i) { if (life & (SYNC_ARG << i)) { - qemu_log(" %d", i); + ne_fprintf(f, " %d", i); } } } life /= DEAD_ARG; if (life) { - qemu_log(" dead:"); + ne_fprintf(f, " dead:"); for (i = 0; life; ++i, life >>= 1) { if (life & 1) { - qemu_log(" %d", i); + ne_fprintf(f, " %d", i); } } } @@ -2013,31 +2073,31 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) if (have_prefs) { for (i = 0; i < nb_oargs; ++i) { - TCGRegSet set = op->output_pref[i]; + TCGRegSet set = output_pref(op, i); if (i == 0) { - qemu_log(" pref="); + ne_fprintf(f, " pref="); } else { - qemu_log(","); + ne_fprintf(f, ","); } if (set == 0) { - qemu_log("none"); + ne_fprintf(f, "none"); } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { - qemu_log("all"); + ne_fprintf(f, "all"); #ifdef CONFIG_DEBUG_TCG } else if (tcg_regset_single(set)) { TCGReg reg = tcg_regset_first(set); - qemu_log("%s", tcg_target_reg_names[reg]); + ne_fprintf(f, "%s", tcg_target_reg_names[reg]); #endif } else if (TCG_TARGET_NB_REGS <= 32) { - qemu_log("%#x", (uint32_t)set); + ne_fprintf(f, "0x%x", (uint32_t)set); } else { - qemu_log("%#" PRIx64, (uint64_t)set); + ne_fprintf(f, "0x%" PRIx64, (uint64_t)set); } } } - qemu_log("\n"); + putc('\n', f); } } @@ -2045,15 +2105,32 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) static int get_constraint_priority(const TCGOpDef *def, int k) { const TCGArgConstraint *arg_ct = &def->args_ct[k]; - int n; + int n = ctpop64(arg_ct->regs); - if (arg_ct->oalias) { - /* an alias is equivalent to a single register */ - n = 1; - } else { - n = ctpop64(arg_ct->regs); + /* + * Sort constraints of a single register first, which includes output + * aliases (which must exactly match the input already allocated). + */ + if (n == 1 || arg_ct->oalias) { + return INT_MAX; + } + + /* + * Sort register pairs next, first then second immediately after. + * Arbitrarily sort multiple pairs by the index of the first reg; + * there shouldn't be many pairs. + */ + switch (arg_ct->pair) { + case 1: + case 3: + return (k + 1) * 2; + case 2: + return (arg_ct->pair_index + 1) * 2 - 1; } - return TCG_TARGET_NB_REGS - n + 1; + + /* Finally, sort by decreasing register count. */ + assert(n > 1); + return -n; } /* sort from highest priority to lowest */ @@ -2088,7 +2165,8 @@ static void process_op_defs(TCGContext *s) for (op = 0; op < NB_OPS; op++) { TCGOpDef *def = &tcg_op_defs[op]; const TCGTargetOpDef *tdefs; - int i, nb_args; + bool saw_alias_pair = false; + int i, o, i2, o2, nb_args; if (def->flags & TCG_OPF_NOT_PRESENT) { continue; @@ -2110,63 +2188,180 @@ static void process_op_defs(TCGContext *s) for (i = 0; i < nb_args; i++) { const char *ct_str = tdefs->args_ct_str[i]; + bool input_p = i >= def->nb_oargs; + /* Incomplete TCGTargetOpDef entry. */ tcg_debug_assert(ct_str != NULL); - while (*ct_str != '\0') { - switch(*ct_str) { - case '0' ... '9': - { - int oarg = *ct_str - '0'; - tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); - tcg_debug_assert(oarg < def->nb_oargs); - tcg_debug_assert(def->args_ct[oarg].regs != 0); - def->args_ct[i] = def->args_ct[oarg]; - /* The output sets oalias. */ - def->args_ct[oarg].oalias = true; - def->args_ct[oarg].alias_index = i; - /* The input sets ialias. */ - def->args_ct[i].ialias = true; - def->args_ct[i].alias_index = oarg; - } - ct_str++; - break; - case '&': - def->args_ct[i].newreg = true; - ct_str++; - break; + switch (*ct_str) { + case '0' ... '9': + o = *ct_str - '0'; + tcg_debug_assert(input_p); + tcg_debug_assert(o < def->nb_oargs); + tcg_debug_assert(def->args_ct[o].regs != 0); + tcg_debug_assert(!def->args_ct[o].oalias); + def->args_ct[i] = def->args_ct[o]; + /* The output sets oalias. */ + def->args_ct[o].oalias = 1; + def->args_ct[o].alias_index = i; + /* The input sets ialias. */ + def->args_ct[i].ialias = 1; + def->args_ct[i].alias_index = o; + if (def->args_ct[i].pair) { + saw_alias_pair = true; + } + tcg_debug_assert(ct_str[1] == '\0'); + continue; + + case '&': + tcg_debug_assert(!input_p); + def->args_ct[i].newreg = true; + ct_str++; + break; + + case 'p': /* plus */ + /* Allocate to the register after the previous. */ + tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); + o = i - 1; + tcg_debug_assert(!def->args_ct[o].pair); + tcg_debug_assert(!def->args_ct[o].ct); + def->args_ct[i] = (TCGArgConstraint){ + .pair = 2, + .pair_index = o, + .regs = def->args_ct[o].regs << 1, + }; + def->args_ct[o].pair = 1; + def->args_ct[o].pair_index = i; + tcg_debug_assert(ct_str[1] == '\0'); + continue; + + case 'm': /* minus */ + /* Allocate to the register before the previous. */ + tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); + o = i - 1; + tcg_debug_assert(!def->args_ct[o].pair); + tcg_debug_assert(!def->args_ct[o].ct); + def->args_ct[i] = (TCGArgConstraint){ + .pair = 1, + .pair_index = o, + .regs = def->args_ct[o].regs >> 1, + }; + def->args_ct[o].pair = 2; + def->args_ct[o].pair_index = i; + tcg_debug_assert(ct_str[1] == '\0'); + continue; + } + + do { + switch (*ct_str) { case 'i': def->args_ct[i].ct |= TCG_CT_CONST; - ct_str++; break; /* Include all of the target-specific constraints. */ #undef CONST #define CONST(CASE, MASK) \ - case CASE: def->args_ct[i].ct |= MASK; ct_str++; break; + case CASE: def->args_ct[i].ct |= MASK; break; #define REGS(CASE, MASK) \ - case CASE: def->args_ct[i].regs |= MASK; ct_str++; break; + case CASE: def->args_ct[i].regs |= MASK; break; #include "tcg-target-con-str.h" #undef REGS #undef CONST default: + case '0' ... '9': + case '&': + case 'p': + case 'm': /* Typo in TCGTargetOpDef constraint. */ g_assert_not_reached(); } - } + } while (*++ct_str != '\0'); } /* TCGTargetOpDef entry with too much information? */ tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); - /* sort the constraints (XXX: this is just an heuristic) */ - sort_constraints(def, 0, def->nb_oargs); - sort_constraints(def, def->nb_oargs, def->nb_iargs); - } -} + /* + * Fix up output pairs that are aliased with inputs. + * When we created the alias, we copied pair from the output. + * There are three cases: + * (1a) Pairs of inputs alias pairs of outputs. + * (1b) One input aliases the first of a pair of outputs. + * (2) One input aliases the second of a pair of outputs. + * + * Case 1a is handled by making sure that the pair_index'es are + * properly updated so that they appear the same as a pair of inputs. + * + * Case 1b is handled by setting the pair_index of the input to + * itself, simply so it doesn't point to an unrelated argument. + * Since we don't encounter the "second" during the input allocation + * phase, nothing happens with the second half of the input pair. + * + * Case 2 is handled by setting the second input to pair=3, the + * first output to pair=3, and the pair_index'es to match. + */ + if (saw_alias_pair) { + for (i = def->nb_oargs; i < nb_args; i++) { + /* + * Since [0-9pm] must be alone in the constraint string, + * the only way they can both be set is if the pair comes + * from the output alias. + */ + if (!def->args_ct[i].ialias) { + continue; + } + switch (def->args_ct[i].pair) { + case 0: + break; + case 1: + o = def->args_ct[i].alias_index; + o2 = def->args_ct[o].pair_index; + tcg_debug_assert(def->args_ct[o].pair == 1); + tcg_debug_assert(def->args_ct[o2].pair == 2); + if (def->args_ct[o2].oalias) { + /* Case 1a */ + i2 = def->args_ct[o2].alias_index; + tcg_debug_assert(def->args_ct[i2].pair == 2); + def->args_ct[i2].pair_index = i; + def->args_ct[i].pair_index = i2; + } else { + /* Case 1b */ + def->args_ct[i].pair_index = i; + } + break; + case 2: + o = def->args_ct[i].alias_index; + o2 = def->args_ct[o].pair_index; + tcg_debug_assert(def->args_ct[o].pair == 2); + tcg_debug_assert(def->args_ct[o2].pair == 1); + if (def->args_ct[o2].oalias) { + /* Case 1a */ + i2 = def->args_ct[o2].alias_index; + tcg_debug_assert(def->args_ct[i2].pair == 1); + def->args_ct[i2].pair_index = i; + def->args_ct[i].pair_index = i2; + } else { + /* Case 2 */ + def->args_ct[i].pair = 3; + def->args_ct[o2].pair = 3; + def->args_ct[i].pair_index = o2; + def->args_ct[o2].pair_index = i; + } + break; + default: + g_assert_not_reached(); + } + } + } + + /* sort the constraints (XXX: this is just an heuristic) */ + sort_constraints(def, 0, def->nb_oargs); + sort_constraints(def, def->nb_oargs, def->nb_iargs); + } +} void tcg_op_remove(TCGContext *s, TCGOp *op) { @@ -2212,41 +2407,56 @@ void tcg_remove_ops_after(TCGOp *op) } } -static TCGOp *tcg_op_alloc(TCGOpcode opc) +static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) { TCGContext *s = tcg_ctx; - TCGOp *op; - - if (likely(QTAILQ_EMPTY(&s->free_ops))) { - op = tcg_malloc(sizeof(TCGOp)); - } else { - op = QTAILQ_FIRST(&s->free_ops); - QTAILQ_REMOVE(&s->free_ops, op, link); + TCGOp *op = NULL; + + if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { + QTAILQ_FOREACH(op, &s->free_ops, link) { + if (nargs <= op->nargs) { + QTAILQ_REMOVE(&s->free_ops, op, link); + nargs = op->nargs; + goto found; + } + } } + + /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ + nargs = MAX(4, nargs); + op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); + + found: memset(op, 0, offsetof(TCGOp, link)); op->opc = opc; - s->nb_ops++; + op->nargs = nargs; + + /* Check for bitfield overflow. */ + tcg_debug_assert(op->nargs == nargs); + s->nb_ops++; return op; } -TCGOp *tcg_emit_op(TCGOpcode opc) +TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) { - TCGOp *op = tcg_op_alloc(opc); + TCGOp *op = tcg_op_alloc(opc, nargs); QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); return op; } -TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) +TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, + TCGOpcode opc, unsigned nargs) { - TCGOp *new_op = tcg_op_alloc(opc); + TCGOp *new_op = tcg_op_alloc(opc, nargs); QTAILQ_INSERT_BEFORE(old_op, new_op, link); return new_op; } -TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) +TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, + TCGOpcode opc, unsigned nargs) { - TCGOp *new_op = tcg_op_alloc(opc); + TCGOp *new_op = tcg_op_alloc(opc, nargs); QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); return new_op; } @@ -2378,6 +2588,7 @@ static void la_bb_end(TCGContext *s, int ng, int nt) state = TS_DEAD | TS_MEM; break; case TEMP_NORMAL: + case TEMP_EBB: case TEMP_CONST: state = TS_DEAD; break; @@ -2405,8 +2616,9 @@ static void la_global_sync(TCGContext *s, int ng) } /* - * liveness analysis: conditional branch: all temps are dead, - * globals and local temps should be synced. + * liveness analysis: conditional branch: all temps are dead unless + * explicitly live-across-conditional-branch, globals and local temps + * should be synced. */ static void la_bb_sync(TCGContext *s, int ng, int nt) { @@ -2427,6 +2639,7 @@ static void la_bb_sync(TCGContext *s, int ng, int nt) case TEMP_NORMAL: s->temps[i].state = TS_DEAD; break; + case TEMP_EBB: case TEMP_CONST: continue; default: @@ -2500,12 +2713,11 @@ static void liveness_pass_1(TCGContext *s) switch (opc) { case INDEX_op_call: { - int call_flags; - int nb_call_regs; + const TCGHelperInfo *info = tcg_call_info(op); + int call_flags = tcg_call_flags(op); nb_oargs = TCGOP_CALLO(op); nb_iargs = TCGOP_CALLI(op); - call_flags = tcg_call_flags(op); /* pure functions can be removed if their result is unused */ if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { @@ -2530,11 +2742,11 @@ static void liveness_pass_1(TCGContext *s) } ts->state = TS_DEAD; la_reset_pref(ts); - - /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ - op->output_pref[i] = 0; } + /* Not used -- it will be tcg_target_call_oarg_reg(). */ + memset(op->output_pref, 0, sizeof(op->output_pref)); + if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | TCG_CALL_NO_READ_GLOBALS))) { la_global_kill(s, nb_globals); @@ -2545,7 +2757,7 @@ static void liveness_pass_1(TCGContext *s) /* Record arguments that die in this helper. */ for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { ts = arg_temp(op->args[i]); - if (ts && ts->state & TS_DEAD) { + if (ts->state & TS_DEAD) { arg_life |= DEAD_ARG << i; } } @@ -2553,31 +2765,59 @@ static void liveness_pass_1(TCGContext *s) /* For all live registers, remove call-clobbered prefs. */ la_cross_call(s, nb_temps); - nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); + /* + * Input arguments are live for preceding opcodes. + * + * For those arguments that die, and will be allocated in + * registers, clear the register set for that arg, to be + * filled in below. For args that will be on the stack, + * reset to any available reg. Process arguments in reverse + * order so that if a temp is used more than once, the stack + * reset to max happens before the register reset to 0. + */ + for (i = nb_iargs - 1; i >= 0; i--) { + const TCGCallArgumentLoc *loc = &info->in[i]; + ts = arg_temp(op->args[nb_oargs + i]); - /* Input arguments are live for preceding opcodes. */ - for (i = 0; i < nb_iargs; i++) { - ts = arg_temp(op->args[i + nb_oargs]); - if (ts && ts->state & TS_DEAD) { - /* For those arguments that die, and will be allocated - * in registers, clear the register set for that arg, - * to be filled in below. For args that will be on - * the stack, reset to any available reg. - */ - *la_temp_pref(ts) - = (i < nb_call_regs ? 0 : - tcg_target_available_regs[ts->type]); + if (ts->state & TS_DEAD) { + switch (loc->kind) { + case TCG_CALL_ARG_NORMAL: + case TCG_CALL_ARG_EXTEND_U: + case TCG_CALL_ARG_EXTEND_S: + if (REG_P(loc)) { + *la_temp_pref(ts) = 0; + break; + } + /* fall through */ + default: + *la_temp_pref(ts) = + tcg_target_available_regs[ts->type]; + break; + } ts->state &= ~TS_DEAD; } } - /* For each input argument, add its input register to prefs. - If a temp is used once, this produces a single set bit. */ - for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { - ts = arg_temp(op->args[i + nb_oargs]); - if (ts) { - tcg_regset_set_reg(*la_temp_pref(ts), - tcg_target_call_iarg_regs[i]); + /* + * For each input argument, add its input register to prefs. + * If a temp is used once, this produces a single set bit; + * if a temp is used multiple times, this produces a set. + */ + for (i = 0; i < nb_iargs; i++) { + const TCGCallArgumentLoc *loc = &info->in[i]; + ts = arg_temp(op->args[nb_oargs + i]); + + switch (loc->kind) { + case TCG_CALL_ARG_NORMAL: + case TCG_CALL_ARG_EXTEND_U: + case TCG_CALL_ARG_EXTEND_S: + if (REG_P(loc)) { + tcg_regset_set_reg(*la_temp_pref(ts), + tcg_target_call_iarg_regs[loc->arg_slot]); + } + break; + default: + break; } } } @@ -2696,7 +2936,9 @@ static void liveness_pass_1(TCGContext *s) ts = arg_temp(op->args[i]); /* Remember the preference of the uses that followed. */ - op->output_pref[i] = *la_temp_pref(ts); + if (i < ARRAY_SIZE(op->output_pref)) { + op->output_pref[i] = *la_temp_pref(ts); + } /* Output args are dead. */ if (ts->state & TS_DEAD) { @@ -2766,7 +3008,7 @@ static void liveness_pass_1(TCGContext *s) set &= ct->regs; if (ct->ialias) { - set &= op->output_pref[ct->alias_index]; + set &= output_pref(op, ct->alias_index); } /* If the combination is not possible, restart. */ if (set == 0) { @@ -2797,6 +3039,7 @@ static bool liveness_pass_2(TCGContext *s) TCGTemp *dts = tcg_temp_alloc(s); dts->type = its->type; dts->base_type = its->base_type; + dts->kind = TEMP_EBB; its->state_ptr = dts; } else { its->state_ptr = NULL; @@ -2845,21 +3088,19 @@ static bool liveness_pass_2(TCGContext *s) /* Make sure that input arguments are available. */ for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { arg_ts = arg_temp(op->args[i]); - if (arg_ts) { - dir_ts = arg_ts->state_ptr; - if (dir_ts && arg_ts->state == TS_DEAD) { - TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 - ? INDEX_op_ld_i32 - : INDEX_op_ld_i64); - TCGOp *lop = tcg_op_insert_before(s, op, lopc); - - lop->args[0] = temp_arg(dir_ts); - lop->args[1] = temp_arg(arg_ts->mem_base); - lop->args[2] = arg_ts->mem_offset; - - /* Loaded, but synced with memory. */ - arg_ts->state = TS_MEM; - } + dir_ts = arg_ts->state_ptr; + if (dir_ts && arg_ts->state == TS_DEAD) { + TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 + ? INDEX_op_ld_i32 + : INDEX_op_ld_i64); + TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); + + lop->args[0] = temp_arg(dir_ts); + lop->args[1] = temp_arg(arg_ts->mem_base); + lop->args[2] = arg_ts->mem_offset; + + /* Loaded, but synced with memory. */ + arg_ts->state = TS_MEM; } } @@ -2868,14 +3109,12 @@ static bool liveness_pass_2(TCGContext *s) so that we reload when needed. */ for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { arg_ts = arg_temp(op->args[i]); - if (arg_ts) { - dir_ts = arg_ts->state_ptr; - if (dir_ts) { - op->args[i] = temp_arg(dir_ts); - changes = true; - if (IS_DEAD_ARG(i)) { - arg_ts->state = TS_DEAD; - } + dir_ts = arg_ts->state_ptr; + if (dir_ts) { + op->args[i] = temp_arg(dir_ts); + changes = true; + if (IS_DEAD_ARG(i)) { + arg_ts->state = TS_DEAD; } } } @@ -2917,7 +3156,7 @@ static bool liveness_pass_2(TCGContext *s) TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 ? INDEX_op_st_i32 : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc); + TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); TCGTemp *out_ts = dir_ts; if (IS_DEAD_ARG(0)) { @@ -2953,7 +3192,7 @@ static bool liveness_pass_2(TCGContext *s) TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 ? INDEX_op_st_i32 : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc); + TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); sop->args[0] = temp_arg(dir_ts); sop->args[1] = temp_arg(arg_ts->mem_base); @@ -2972,97 +3211,24 @@ static bool liveness_pass_2(TCGContext *s) return changes; } -#ifdef CONFIG_DEBUG_TCG -static void dump_regs(TCGContext *s) -{ - TCGTemp *ts; - int i; - char buf[64]; - - for(i = 0; i < s->nb_temps; i++) { - ts = &s->temps[i]; - printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); - switch(ts->val_type) { - case TEMP_VAL_REG: - printf("%s", tcg_target_reg_names[ts->reg]); - break; - case TEMP_VAL_MEM: - printf("%d(%s)", (int)ts->mem_offset, - tcg_target_reg_names[ts->mem_base->reg]); - break; - case TEMP_VAL_CONST: - printf("$0x%" PRIx64, ts->val); - break; - case TEMP_VAL_DEAD: - printf("D"); - break; - default: - printf("???"); - break; - } - printf("\n"); - } - - for(i = 0; i < TCG_TARGET_NB_REGS; i++) { - if (s->reg_to_temp[i] != NULL) { - printf("%s: %s\n", - tcg_target_reg_names[i], - tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); - } - } -} - -static void check_regs(TCGContext *s) -{ - int reg; - int k; - TCGTemp *ts; - char buf[64]; - - for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { - ts = s->reg_to_temp[reg]; - if (ts != NULL) { - if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { - printf("Inconsistency for register %s:\n", - tcg_target_reg_names[reg]); - goto fail; - } - } - } - for (k = 0; k < s->nb_temps; k++) { - ts = &s->temps[k]; - if (ts->val_type == TEMP_VAL_REG - && ts->kind != TEMP_FIXED - && s->reg_to_temp[ts->reg] != ts) { - printf("Inconsistency for temp %s:\n", - tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); - fail: - printf("reg state:\n"); - dump_regs(s); - tcg_abort(); - } - } -} -#endif - static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) { - intptr_t off, size, align; + int size = tcg_type_size(ts->type); + int align; + intptr_t off; switch (ts->type) { case TCG_TYPE_I32: - size = align = 4; + align = 4; break; case TCG_TYPE_I64: case TCG_TYPE_V64: - size = align = 8; + align = 8; break; case TCG_TYPE_V128: - size = align = 16; - break; case TCG_TYPE_V256: /* Note that we do not require aligned storage for V256. */ - size = 32, align = 16; + align = 16; break; default: g_assert_not_reached(); @@ -3091,6 +3257,35 @@ static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) ts->mem_allocated = 1; } +/* Assign @reg to @ts, and update reg_to_temp[]. */ +static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) +{ + if (ts->val_type == TEMP_VAL_REG) { + TCGReg old = ts->reg; + tcg_debug_assert(s->reg_to_temp[old] == ts); + if (old == reg) { + return; + } + s->reg_to_temp[old] = NULL; + } + tcg_debug_assert(s->reg_to_temp[reg] == NULL); + s->reg_to_temp[reg] = ts; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; +} + +/* Assign a non-register value type to @ts, and update reg_to_temp[]. */ +static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) +{ + tcg_debug_assert(type != TEMP_VAL_REG); + if (ts->val_type == TEMP_VAL_REG) { + TCGReg reg = ts->reg; + tcg_debug_assert(s->reg_to_temp[reg] == ts); + s->reg_to_temp[reg] = NULL; + } + ts->val_type = type; +} + static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); /* Mark a temporary as free or dead. If 'free_or_dead' is negative, @@ -3107,6 +3302,7 @@ static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) new_type = TEMP_VAL_MEM; break; case TEMP_NORMAL: + case TEMP_EBB: new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; break; case TEMP_CONST: @@ -3115,10 +3311,7 @@ static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) default: g_assert_not_reached(); } - if (ts->val_type == TEMP_VAL_REG) { - s->reg_to_temp[ts->reg] = NULL; - } - ts->val_type = new_type; + set_temp_val_nonreg(s, ts, new_type); } /* Mark a temporary as dead. */ @@ -3252,6 +3445,52 @@ static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, tcg_abort(); } +static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, + TCGRegSet allocated_regs, + TCGRegSet preferred_regs, bool rev) +{ + int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); + TCGRegSet reg_ct[2]; + const int *order; + + /* Ensure that if I is not in allocated_regs, I+1 is not either. */ + reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); + tcg_debug_assert(reg_ct[1] != 0); + reg_ct[0] = reg_ct[1] & preferred_regs; + + order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; + + /* + * Skip the preferred_regs option if it cannot be satisfied, + * or if the preference made no difference. + */ + k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; + + /* + * Minimize the number of flushes by looking for 2 free registers first, + * then a single flush, then two flushes. + */ + for (fmin = 2; fmin >= 0; fmin--) { + for (j = k; j < 2; j++) { + TCGRegSet set = reg_ct[j]; + + for (i = 0; i < n; i++) { + TCGReg reg = order[i]; + + if (tcg_regset_test_reg(set, reg)) { + int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; + if (f >= fmin) { + tcg_reg_free(s, reg, allocated_regs); + tcg_reg_free(s, reg + 1, allocated_regs); + return reg; + } + } + } + } + } + tcg_abort(); +} + /* Make sure the temporary is in a register. If needed, allocate the register from DESIRED while avoiding ALLOCATED. */ static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, @@ -3298,9 +3537,7 @@ static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, default: tcg_abort(); } - ts->reg = reg; - ts->val_type = TEMP_VAL_REG; - s->reg_to_temp[reg] = ts; + set_temp_val_reg(s, ts, reg); } /* Save a temporary to memory. 'allocated_regs' is used in case a @@ -3353,6 +3590,7 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) temp_save(s, ts, allocated_regs); break; case TEMP_NORMAL: + case TEMP_EBB: /* The liveness analysis already ensures that temps are dead. Keep an tcg_debug_assert for safety. */ tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); @@ -3370,8 +3608,9 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) } /* - * At a conditional branch, we assume all temporaries are dead and - * all globals and local temps are synced to their location. + * At a conditional branch, we assume all temporaries are dead unless + * explicitly live-across-conditional-branch; all globals and local + * temps are synced to their location. */ static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) { @@ -3390,6 +3629,7 @@ static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) case TEMP_NORMAL: tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); break; + case TEMP_EBB: case TEMP_CONST: break; default: @@ -3409,10 +3649,7 @@ static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, tcg_debug_assert(!temp_readonly(ots)); /* The movi is not explicitly generated here. */ - if (ots->val_type == TEMP_VAL_REG) { - s->reg_to_temp[ots->reg] = NULL; - } - ots->val_type = TEMP_VAL_CONST; + set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); ots->val = val; ots->mem_coherent = 0; if (NEED_SYNC_ARG(0)) { @@ -3431,9 +3668,10 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) TCGRegSet allocated_regs, preferred_regs; TCGTemp *ts, *ots; TCGType otype, itype; + TCGReg oreg, ireg; allocated_regs = s->reserved_regs; - preferred_regs = op->output_pref[0]; + preferred_regs = output_pref(op, 0); ots = arg_temp(op->args[0]); ts = arg_temp(op->args[1]); @@ -3462,8 +3700,9 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs, preferred_regs); } - tcg_debug_assert(ts->val_type == TEMP_VAL_REG); + ireg = ts->reg; + if (IS_DEAD_ARG(0)) { /* mov to a non-saved dead register makes no sense (even with liveness analysis disabled). */ @@ -3471,52 +3710,53 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) if (!ots->mem_allocated) { temp_allocate_frame(s, ots); } - tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); + tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); if (IS_DEAD_ARG(1)) { temp_dead(s, ts); } temp_dead(s, ots); + return; + } + + if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { + /* + * The mov can be suppressed. Kill input first, so that it + * is unlinked from reg_to_temp, then set the output to the + * reg that we saved from the input. + */ + temp_dead(s, ts); + oreg = ireg; } else { - if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { - /* the mov can be suppressed */ - if (ots->val_type == TEMP_VAL_REG) { - s->reg_to_temp[ots->reg] = NULL; - } - ots->reg = ts->reg; - temp_dead(s, ts); + if (ots->val_type == TEMP_VAL_REG) { + oreg = ots->reg; } else { - if (ots->val_type != TEMP_VAL_REG) { - /* When allocating a new register, make sure to not spill the - input one. */ - tcg_regset_set_reg(allocated_regs, ts->reg); - ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], - allocated_regs, preferred_regs, - ots->indirect_base); - } - if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { - /* - * Cross register class move not supported. - * Store the source register into the destination slot - * and leave the destination temp as TEMP_VAL_MEM. - */ - assert(!temp_readonly(ots)); - if (!ts->mem_allocated) { - temp_allocate_frame(s, ots); - } - tcg_out_st(s, ts->type, ts->reg, - ots->mem_base->reg, ots->mem_offset); - ots->mem_coherent = 1; - temp_free_or_dead(s, ots, -1); - return; - } + /* Make sure to not spill the input register during allocation. */ + oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], + allocated_regs | ((TCGRegSet)1 << ireg), + preferred_regs, ots->indirect_base); } - ots->val_type = TEMP_VAL_REG; - ots->mem_coherent = 0; - s->reg_to_temp[ots->reg] = ots; - if (NEED_SYNC_ARG(0)) { - temp_sync(s, ots, allocated_regs, 0, 0); + if (!tcg_out_mov(s, otype, oreg, ireg)) { + /* + * Cross register class move not supported. + * Store the source register into the destination slot + * and leave the destination temp as TEMP_VAL_MEM. + */ + assert(!temp_readonly(ots)); + if (!ts->mem_allocated) { + temp_allocate_frame(s, ots); + } + tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); + set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); + ots->mem_coherent = 1; + return; } } + set_temp_val_reg(s, ots, oreg); + ots->mem_coherent = 0; + + if (NEED_SYNC_ARG(0)) { + temp_sync(s, ots, allocated_regs, 0, 0); + } } /* @@ -3528,8 +3768,8 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) TCGRegSet dup_out_regs, dup_in_regs; TCGTemp *its, *ots; TCGType itype, vtype; - intptr_t endian_fixup; unsigned vece; + int lowpart_ofs; bool ok; ots = arg_temp(op->args[0]); @@ -3548,7 +3788,7 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) if (IS_DEAD_ARG(1)) { temp_dead(s, its); } - tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); + tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); return; } @@ -3558,16 +3798,15 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) /* Allocate the output register now. */ if (ots->val_type != TEMP_VAL_REG) { TCGRegSet allocated_regs = s->reserved_regs; + TCGReg oreg; if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { /* Make sure to not spill the input register. */ tcg_regset_set_reg(allocated_regs, its->reg); } - ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, - op->output_pref[0], ots->indirect_base); - ots->val_type = TEMP_VAL_REG; - ots->mem_coherent = 0; - s->reg_to_temp[ots->reg] = ots; + oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, + output_pref(op, 0), ots->indirect_base); + set_temp_val_reg(s, ots, oreg); } switch (its->val_type) { @@ -3598,16 +3837,15 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) /* fall through */ case TEMP_VAL_MEM: -#ifdef HOST_WORDS_BIGENDIAN - endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; - endian_fixup -= 1 << vece; -#else - endian_fixup = 0; -#endif + lowpart_ofs = 0; + if (HOST_BIG_ENDIAN) { + lowpart_ofs = tcg_type_size(itype) - (1 << vece); + } if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, - its->mem_offset + endian_fixup)) { + its->mem_offset + lowpart_ofs)) { goto done; } + /* Load the input into the destination vector register. */ tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); break; @@ -3620,6 +3858,7 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) tcg_debug_assert(ok); done: + ots->mem_coherent = 0; if (IS_DEAD_ARG(1)) { temp_dead(s, its); } @@ -3649,16 +3888,19 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) nb_iargs = def->nb_iargs; /* copy constants */ - memcpy(new_args + nb_oargs + nb_iargs, + memcpy(new_args + nb_oargs + nb_iargs, op->args + nb_oargs + nb_iargs, sizeof(TCGArg) * def->nb_cargs); i_allocated_regs = s->reserved_regs; o_allocated_regs = s->reserved_regs; - /* satisfy input constraints */ + /* satisfy input constraints */ for (k = 0; k < nb_iargs; k++) { - TCGRegSet i_preferred_regs, o_preferred_regs; + TCGRegSet i_preferred_regs, i_required_regs; + bool allocate_new_reg, copyto_new_reg; + TCGTemp *ts2; + int i1, i2; i = def->args_ct[nb_oargs + k].sort_index; arg = op->args[i]; @@ -3673,49 +3915,166 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) continue; } - i_preferred_regs = o_preferred_regs = 0; - if (arg_ct->ialias) { - o_preferred_regs = op->output_pref[arg_ct->alias_index]; + reg = ts->reg; + i_preferred_regs = 0; + i_required_regs = arg_ct->regs; + allocate_new_reg = false; + copyto_new_reg = false; + + switch (arg_ct->pair) { + case 0: /* not paired */ + if (arg_ct->ialias) { + i_preferred_regs = output_pref(op, arg_ct->alias_index); + + /* + * If the input is readonly, then it cannot also be an + * output and aliased to itself. If the input is not + * dead after the instruction, we must allocate a new + * register and move it. + */ + if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { + allocate_new_reg = true; + } else if (ts->val_type == TEMP_VAL_REG) { + /* + * Check if the current register has already been + * allocated for another input. + */ + allocate_new_reg = + tcg_regset_test_reg(i_allocated_regs, reg); + } + } + if (!allocate_new_reg) { + temp_load(s, ts, i_required_regs, i_allocated_regs, + i_preferred_regs); + reg = ts->reg; + allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); + } + if (allocate_new_reg) { + /* + * Allocate a new register matching the constraint + * and move the temporary register into it. + */ + temp_load(s, ts, tcg_target_available_regs[ts->type], + i_allocated_regs, 0); + reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, + i_preferred_regs, ts->indirect_base); + copyto_new_reg = true; + } + break; + + case 1: + /* First of an input pair; if i1 == i2, the second is an output. */ + i1 = i; + i2 = arg_ct->pair_index; + ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; /* - * If the input is readonly, then it cannot also be an - * output and aliased to itself. If the input is not - * dead after the instruction, we must allocate a new - * register and move it. + * It is easier to default to allocating a new pair + * and to identify a few cases where it's not required. */ - if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { - goto allocate_in_reg; + if (arg_ct->ialias) { + i_preferred_regs = output_pref(op, arg_ct->alias_index); + if (IS_DEAD_ARG(i1) && + IS_DEAD_ARG(i2) && + !temp_readonly(ts) && + ts->val_type == TEMP_VAL_REG && + ts->reg < TCG_TARGET_NB_REGS - 1 && + tcg_regset_test_reg(i_required_regs, reg) && + !tcg_regset_test_reg(i_allocated_regs, reg) && + !tcg_regset_test_reg(i_allocated_regs, reg + 1) && + (ts2 + ? ts2->val_type == TEMP_VAL_REG && + ts2->reg == reg + 1 && + !temp_readonly(ts2) + : s->reg_to_temp[reg + 1] == NULL)) { + break; + } + } else { + /* Without aliasing, the pair must also be an input. */ + tcg_debug_assert(ts2); + if (ts->val_type == TEMP_VAL_REG && + ts2->val_type == TEMP_VAL_REG && + ts2->reg == reg + 1 && + tcg_regset_test_reg(i_required_regs, reg)) { + break; + } } - + reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, + 0, ts->indirect_base); + goto do_pair; + + case 2: /* pair second */ + reg = new_args[arg_ct->pair_index] + 1; + goto do_pair; + + case 3: /* ialias with second output, no first input */ + tcg_debug_assert(arg_ct->ialias); + i_preferred_regs = output_pref(op, arg_ct->alias_index); + + if (IS_DEAD_ARG(i) && + !temp_readonly(ts) && + ts->val_type == TEMP_VAL_REG && + reg > 0 && + s->reg_to_temp[reg - 1] == NULL && + tcg_regset_test_reg(i_required_regs, reg) && + !tcg_regset_test_reg(i_allocated_regs, reg) && + !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { + tcg_regset_set_reg(i_allocated_regs, reg - 1); + break; + } + reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, + i_allocated_regs, 0, + ts->indirect_base); + tcg_regset_set_reg(i_allocated_regs, reg); + reg += 1; + goto do_pair; + + do_pair: /* - * Check if the current register has already been allocated - * for another input aliased to an output. + * If an aliased input is not dead after the instruction, + * we must allocate a new register and move it. */ - if (ts->val_type == TEMP_VAL_REG) { - reg = ts->reg; - for (int k2 = 0; k2 < k; k2++) { - int i2 = def->args_ct[nb_oargs + k2].sort_index; - if (def->args_ct[i2].ialias && reg == new_args[i2]) { - goto allocate_in_reg; - } + if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) { + TCGRegSet t_allocated_regs = i_allocated_regs; + + /* + * Because of the alias, and the continued life, make sure + * that the temp is somewhere *other* than the reg pair, + * and we get a copy in reg. + */ + tcg_regset_set_reg(t_allocated_regs, reg); + tcg_regset_set_reg(t_allocated_regs, reg + 1); + if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { + /* If ts was already in reg, copy it somewhere else. */ + TCGReg nr; + bool ok; + + tcg_debug_assert(ts->kind != TEMP_FIXED); + nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + t_allocated_regs, 0, ts->indirect_base); + ok = tcg_out_mov(s, ts->type, nr, reg); + tcg_debug_assert(ok); + + set_temp_val_reg(s, ts, nr); + } else { + temp_load(s, ts, tcg_target_available_regs[ts->type], + t_allocated_regs, 0); + copyto_new_reg = true; } + } else { + /* Preferably allocate to reg, otherwise copy. */ + i_required_regs = (TCGRegSet)1 << reg; + temp_load(s, ts, i_required_regs, i_allocated_regs, + i_preferred_regs); + copyto_new_reg = ts->reg != reg; } - i_preferred_regs = o_preferred_regs; - } + break; - temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); - reg = ts->reg; + default: + g_assert_not_reached(); + } - if (!tcg_regset_test_reg(arg_ct->regs, reg)) { - allocate_in_reg: - /* - * Allocate a new register matching the constraint - * and move the temporary register into it. - */ - temp_load(s, ts, tcg_target_available_regs[ts->type], - i_allocated_regs, 0); - reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, - o_preferred_regs, ts->indirect_base); + if (copyto_new_reg) { if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { /* * Cross register class move not supported. Sync the @@ -3730,7 +4089,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) const_args[i] = 0; tcg_regset_set_reg(i_allocated_regs, reg); } - + /* mark dead temporaries and free the associated registers */ for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { if (IS_DEAD_ARG(i)) { @@ -3744,7 +4103,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) tcg_reg_alloc_bb_end(s, i_allocated_regs); } else { if (def->flags & TCG_OPF_CALL_CLOBBER) { - /* XXX: permit generic clobber register list ? */ + /* XXX: permit generic clobber register list ? */ for (i = 0; i < TCG_TARGET_NB_REGS; i++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { tcg_reg_free(s, i, i_allocated_regs); @@ -3756,7 +4115,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) an exception. */ sync_globals(s, i_allocated_regs); } - + /* satisfy the output constraints */ for(k = 0; k < nb_oargs; k++) { i = def->args_ct[k].sort_index; @@ -3767,28 +4126,50 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) /* ENV should not be modified. */ tcg_debug_assert(!temp_readonly(ts)); - if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { - reg = new_args[arg_ct->alias_index]; - } else if (arg_ct->newreg) { - reg = tcg_reg_alloc(s, arg_ct->regs, - i_allocated_regs | o_allocated_regs, - op->output_pref[k], ts->indirect_base); - } else { - reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, - op->output_pref[k], ts->indirect_base); + switch (arg_ct->pair) { + case 0: /* not paired */ + if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { + reg = new_args[arg_ct->alias_index]; + } else if (arg_ct->newreg) { + reg = tcg_reg_alloc(s, arg_ct->regs, + i_allocated_regs | o_allocated_regs, + output_pref(op, k), ts->indirect_base); + } else { + reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, + output_pref(op, k), ts->indirect_base); + } + break; + + case 1: /* first of pair */ + tcg_debug_assert(!arg_ct->newreg); + if (arg_ct->oalias) { + reg = new_args[arg_ct->alias_index]; + break; + } + reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, + output_pref(op, k), ts->indirect_base); + break; + + case 2: /* second of pair */ + tcg_debug_assert(!arg_ct->newreg); + if (arg_ct->oalias) { + reg = new_args[arg_ct->alias_index]; + } else { + reg = new_args[arg_ct->pair_index] + 1; + } + break; + + case 3: /* first of pair, aliasing with a second input */ + tcg_debug_assert(!arg_ct->newreg); + reg = new_args[arg_ct->pair_index] - 1; + break; + + default: + g_assert_not_reached(); } tcg_regset_set_reg(o_allocated_regs, reg); - if (ts->val_type == TEMP_VAL_REG) { - s->reg_to_temp[ts->reg] = NULL; - } - ts->val_type = TEMP_VAL_REG; - ts->reg = reg; - /* - * Temp value is modified, so the value kept in memory is - * potentially not the same. - */ + set_temp_val_reg(s, ts, reg); ts->mem_coherent = 0; - s->reg_to_temp[reg] = ts; new_args[i] = reg; } } @@ -3838,6 +4219,7 @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) TCGRegSet allocated_regs = s->reserved_regs; TCGRegSet dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; + TCGReg oreg; /* Make sure to not spill the input registers. */ if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { @@ -3847,11 +4229,9 @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) tcg_regset_set_reg(allocated_regs, itsh->reg); } - ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, - op->output_pref[0], ots->indirect_base); - ots->val_type = TEMP_VAL_REG; - ots->mem_coherent = 0; - s->reg_to_temp[ots->reg] = ots; + oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, + output_pref(op, 0), ots->indirect_base); + set_temp_val_reg(s, ots, oreg); } /* Promote dup2 of immediates to dupi_vec. */ @@ -3872,18 +4252,14 @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) } /* If the two inputs form one 64-bit value, try dupm_vec. */ - if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) { - if (!itsl->mem_coherent) { - temp_sync(s, itsl, s->reserved_regs, 0, 0); - } - if (!itsh->mem_coherent) { - temp_sync(s, itsh, s->reserved_regs, 0, 0); - } -#ifdef HOST_WORDS_BIGENDIAN - TCGTemp *its = itsh; -#else - TCGTemp *its = itsl; -#endif + if (itsl->temp_subindex == HOST_BIG_ENDIAN && + itsh->temp_subindex == !HOST_BIG_ENDIAN && + itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { + TCGTemp *its = itsl - HOST_BIG_ENDIAN; + + temp_sync(s, its + 0, s->reserved_regs, 0, 0); + temp_sync(s, its + 1, s->reserved_regs, 0, 0); + if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, its->mem_base->reg, its->mem_offset)) { goto done; @@ -3894,6 +4270,7 @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) return false; done: + ots->mem_coherent = 0; if (IS_DEAD_ARG(1)) { temp_dead(s, itsl); } @@ -3908,152 +4285,137 @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) return true; } -#ifdef TCG_TARGET_STACK_GROWSUP -#define STACK_DIR(x) (-(x)) -#else -#define STACK_DIR(x) (x) -#endif +static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, + TCGRegSet allocated_regs) +{ + if (ts->val_type == TEMP_VAL_REG) { + if (ts->reg != reg) { + tcg_reg_free(s, reg, allocated_regs); + if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { + /* + * Cross register class move not supported. Sync the + * temp back to its slot and load from there. + */ + temp_sync(s, ts, allocated_regs, 0, 0); + tcg_out_ld(s, ts->type, reg, + ts->mem_base->reg, ts->mem_offset); + } + } + } else { + TCGRegSet arg_set = 0; + + tcg_reg_free(s, reg, allocated_regs); + tcg_regset_set_reg(arg_set, reg); + temp_load(s, ts, arg_set, allocated_regs, 0); + } +} + +static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts, + TCGRegSet allocated_regs) +{ + /* + * When the destination is on the stack, load up the temp and store. + * If there are many call-saved registers, the temp might live to + * see another use; otherwise it'll be discarded. + */ + temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); + tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET + + stk_slot * sizeof(tcg_target_long)); +} + +static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, + TCGTemp *ts, TCGRegSet *allocated_regs) +{ + if (REG_P(l)) { + TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; + load_arg_reg(s, reg, ts, *allocated_regs); + tcg_regset_set_reg(*allocated_regs, reg); + } else { + load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs), + ts, *allocated_regs); + } +} static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) { const int nb_oargs = TCGOP_CALLO(op); const int nb_iargs = TCGOP_CALLI(op); const TCGLifeData arg_life = op->life; - const TCGHelperInfo *info; - int flags, nb_regs, i; - TCGReg reg; - TCGArg arg; - TCGTemp *ts; - intptr_t stack_offset; - size_t call_stack_size; - tcg_insn_unit *func_addr; - int allocate_args; - TCGRegSet allocated_regs; - - func_addr = tcg_call_func(op); - info = tcg_call_info(op); - flags = info->flags; - - nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); - if (nb_regs > nb_iargs) { - nb_regs = nb_iargs; - } - - /* assign stack slots first */ - call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); - call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & - ~(TCG_TARGET_STACK_ALIGN - 1); - allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); - if (allocate_args) { - /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, - preallocate call stack */ - tcg_abort(); - } + const TCGHelperInfo *info = tcg_call_info(op); + TCGRegSet allocated_regs = s->reserved_regs; + int i; - stack_offset = TCG_TARGET_CALL_STACK_OFFSET; - for (i = nb_regs; i < nb_iargs; i++) { - arg = op->args[nb_oargs + i]; -#ifdef TCG_TARGET_STACK_GROWSUP - stack_offset -= sizeof(tcg_target_long); -#endif - if (arg != TCG_CALL_DUMMY_ARG) { - ts = arg_temp(arg); - temp_load(s, ts, tcg_target_available_regs[ts->type], - s->reserved_regs, 0); - tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); + /* + * Move inputs into place in reverse order, + * so that we place stacked arguments first. + */ + for (i = nb_iargs - 1; i >= 0; --i) { + const TCGCallArgumentLoc *loc = &info->in[i]; + TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); + + switch (loc->kind) { + case TCG_CALL_ARG_NORMAL: + case TCG_CALL_ARG_EXTEND_U: + case TCG_CALL_ARG_EXTEND_S: + load_arg_normal(s, loc, ts, &allocated_regs); + break; + default: + g_assert_not_reached(); } -#ifndef TCG_TARGET_STACK_GROWSUP - stack_offset += sizeof(tcg_target_long); -#endif } - - /* assign input registers */ - allocated_regs = s->reserved_regs; - for (i = 0; i < nb_regs; i++) { - arg = op->args[nb_oargs + i]; - if (arg != TCG_CALL_DUMMY_ARG) { - ts = arg_temp(arg); - reg = tcg_target_call_iarg_regs[i]; - - if (ts->val_type == TEMP_VAL_REG) { - if (ts->reg != reg) { - tcg_reg_free(s, reg, allocated_regs); - if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { - /* - * Cross register class move not supported. Sync the - * temp back to its slot and load from there. - */ - temp_sync(s, ts, allocated_regs, 0, 0); - tcg_out_ld(s, ts->type, reg, - ts->mem_base->reg, ts->mem_offset); - } - } - } else { - TCGRegSet arg_set = 0; - tcg_reg_free(s, reg, allocated_regs); - tcg_regset_set_reg(arg_set, reg); - temp_load(s, ts, arg_set, allocated_regs, 0); - } - - tcg_regset_set_reg(allocated_regs, reg); - } - } - - /* mark dead temporaries and free the associated registers */ + /* Mark dead temporaries and free the associated registers. */ for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { if (IS_DEAD_ARG(i)) { temp_dead(s, arg_temp(op->args[i])); } } - - /* clobber call registers */ + + /* Clobber call registers. */ for (i = 0; i < TCG_TARGET_NB_REGS; i++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { tcg_reg_free(s, i, allocated_regs); } } - /* Save globals if they might be written by the helper, sync them if - they might be read. */ - if (flags & TCG_CALL_NO_READ_GLOBALS) { + /* + * Save globals if they might be written by the helper, + * sync them if they might be read. + */ + if (info->flags & TCG_CALL_NO_READ_GLOBALS) { /* Nothing to do */ - } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { + } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { sync_globals(s, allocated_regs); } else { save_globals(s, allocated_regs); } -#ifdef CONFIG_TCG_INTERPRETER - { - gpointer hash = (gpointer)(uintptr_t)info->typemask; - ffi_cif *cif = g_hash_table_lookup(ffi_table, hash); - assert(cif != NULL); - tcg_out_call(s, func_addr, cif); - } -#else - tcg_out_call(s, func_addr); -#endif + tcg_out_call(s, tcg_call_func(op), info); - /* assign output registers and emit moves if needed */ - for(i = 0; i < nb_oargs; i++) { - arg = op->args[i]; - ts = arg_temp(arg); + /* Assign output registers and emit moves if needed. */ + switch (info->out_kind) { + case TCG_CALL_RET_NORMAL: + for (i = 0; i < nb_oargs; i++) { + TCGTemp *ts = arg_temp(op->args[i]); + TCGReg reg = tcg_target_call_oarg_regs[i]; - /* ENV should not be modified. */ - tcg_debug_assert(!temp_readonly(ts)); + /* ENV should not be modified. */ + tcg_debug_assert(!temp_readonly(ts)); - reg = tcg_target_call_oarg_regs[i]; - tcg_debug_assert(s->reg_to_temp[reg] == NULL); - if (ts->val_type == TEMP_VAL_REG) { - s->reg_to_temp[ts->reg] = NULL; + set_temp_val_reg(s, ts, reg); + ts->mem_coherent = 0; } - ts->val_type = TEMP_VAL_REG; - ts->reg = reg; - ts->mem_coherent = 0; - s->reg_to_temp[reg] = ts; + break; + default: + g_assert_not_reached(); + } + + /* Flush or discard output registers as needed. */ + for (i = 0; i < nb_oargs; i++) { + TCGTemp *ts = arg_temp(op->args[i]); if (NEED_SYNC_ARG(i)) { - temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); + temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); } else if (IS_DEAD_ARG(i)) { temp_dead(s, ts); } @@ -4169,7 +4531,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; @@ -4199,12 +4561,14 @@ 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))) { - FILE *logfile = qemu_log_lock(); - qemu_log("OP:\n"); - tcg_dump_ops(s, false); - qemu_log("\n"); - qemu_log_unlock(logfile); + && qemu_log_in_addr_range(pc_start))) { + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "OP:\n"); + tcg_dump_ops(s, logfile, false); + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); + } } #endif @@ -4244,12 +4608,14 @@ 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))) { - FILE *logfile = qemu_log_lock(); - qemu_log("OP before indirect lowering:\n"); - tcg_dump_ops(s, false); - qemu_log("\n"); - qemu_log_unlock(logfile); + && qemu_log_in_addr_range(pc_start))) { + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "OP before indirect lowering:\n"); + tcg_dump_ops(s, logfile, false); + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); + } } #endif /* Replace indirect temps with direct temps. */ @@ -4265,15 +4631,29 @@ 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))) { - FILE *logfile = qemu_log_lock(); - qemu_log("OP after optimization and liveness analysis:\n"); - tcg_dump_ops(s, true); - qemu_log("\n"); - qemu_log_unlock(logfile); + && qemu_log_in_addr_range(pc_start))) { + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "OP after optimization and liveness analysis:\n"); + tcg_dump_ops(s, logfile, true); + fprintf(logfile, "\n"); + qemu_log_unlock(logfile); + } } #endif + /* Initialize goto_tb jump offsets. */ + tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID; + tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID; + tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset; + if (TCG_TARGET_HAS_direct_jump) { + tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg; + tcg_ctx->tb_jmp_target_addr = NULL; + } else { + tcg_ctx->tb_jmp_insn_offset = NULL; + tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg; + } + tcg_reg_alloc_start(s); /* @@ -4350,9 +4730,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) tcg_reg_alloc_op(s, op); break; } -#ifdef CONFIG_DEBUG_TCG - check_regs(s); -#endif /* Test for (pending) buffer overflow. The assumption is that any one operation beginning below the high water mark cannot overrun the buffer completely. Thus we can test for overflow after @@ -4429,7 +4806,7 @@ void tcg_dump_info(GString *buf) (double)s->code_out_len / tb_div_count); g_string_append_printf(buf, "avg search data/TB %0.1f\n", (double)s->search_out_len / tb_div_count); - + g_string_append_printf(buf, "cycles/op %0.1f\n", s->op_count ? (double)tot / s->op_count : 0); g_string_append_printf(buf, "cycles/in byte %0.1f\n", @@ -4704,7 +5081,8 @@ static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size, /* Enable this block to be able to debug the ELF image file creation. One can use readelf, objdump, or other inspection utilities. */ { - FILE *f = fopen("/tmp/qemu.jit", "w+b"); + g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir()); + FILE *f = fopen(jit, "w+b"); if (f) { if (fwrite(img, img_size, 1, f) != img_size) { /* Avoid stupid unused return value warning for fwrite. */ diff --git a/tcg/tci.c b/tcg/tci.c index fe92b5d0844b..05a24163d38d 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -18,8 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "tcg/tcg.h" /* MAX_OPC_PARAM_IARGS */ #include "exec/cpu_ldst.h" #include "tcg/tcg-op.h" #include "tcg/tcg-ldst.h" diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 98337c567a86..d36a7ebdd161 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -197,10 +197,6 @@ static const int tcg_target_reg_alloc_order[] = { TCG_REG_R0, }; -#if MAX_OPC_PARAM_IARGS != 7 -# error Fix needed, number of supported input arguments changed! -#endif - /* No call arguments via registers. All will be stored on the "stack". */ static const int tcg_target_call_iarg_regs[] = { }; @@ -562,8 +558,9 @@ static void tcg_out_movi(TCGContext *s, TCGType type, } static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func, - ffi_cif *cif) + const TCGHelperInfo *info) { + ffi_cif *cif = info->cif; tcg_insn_unit insn = 0; uint8_t which; @@ -823,13 +820,6 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count) static void tcg_target_init(TCGContext *s) { -#if defined(CONFIG_DEBUG_TCG_INTERPRETER) - const char *envval = getenv("DEBUG_TCG"); - if (envval) { - qemu_set_log(strtol(envval, NULL, 0)); - } -#endif - /* The current code uses uint8_t for tcg operations. */ tcg_debug_assert(tcg_op_defs_max <= UINT8_MAX); diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 033e613f241f..94ec541b4e50 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -53,11 +53,6 @@ # error Unknown pointer size for tci target #endif -#ifdef CONFIG_DEBUG_TCG -/* Enable debug output. */ -#define CONFIG_DEBUG_TCG_INTERPRETER -#endif - /* Optional instructions. */ #define TCG_TARGET_HAS_bswap16_i32 1 @@ -163,6 +158,13 @@ typedef enum { /* Used for function call generation. */ #define TCG_TARGET_CALL_STACK_OFFSET 0 #define TCG_TARGET_STACK_ALIGN 8 +#if TCG_TARGET_REG_BITS == 32 +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EVEN +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN +#else +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#endif #define HAVE_TCG_QEMU_TB_EXEC #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tests/Makefile.include b/tests/Makefile.include index 05c534ea56f8..9422ddaece56 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -3,28 +3,28 @@ .PHONY: check-help check-help: @echo "Regression testing targets:" - @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests" - @echo " $(MAKE) bench Run speed tests" + @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests" + @echo " $(MAKE) bench Run speed tests" @echo @echo "Individual test suites:" - @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target" - @echo " $(MAKE) check-qtest Run qtest tests" - @echo " $(MAKE) check-unit Run qobject tests" - @echo " $(MAKE) check-qapi-schema Run QAPI schema tests" - @echo " $(MAKE) check-block Run block tests" + @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target" + @echo " $(MAKE) check-qtest Run qtest tests" + @echo " $(MAKE) check-unit Run qobject tests" + @echo " $(MAKE) check-qapi-schema Run QAPI schema tests" + @echo " $(MAKE) check-block Run block tests" ifneq ($(filter $(all-check-targets), check-softfloat),) - @echo " $(MAKE) check-tcg Run TCG tests" - @echo " $(MAKE) check-softfloat Run FPU emulation tests" + @echo " $(MAKE) check-tcg Run TCG tests" + @echo " $(MAKE) check-softfloat Run FPU emulation tests" endif - @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets" + @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets" @echo - @echo " $(MAKE) check-report.tap Generates an aggregated TAP test report" - @echo " $(MAKE) check-venv Creates a Python venv for tests" - @echo " $(MAKE) check-clean Clean the tests and related data" + @echo " $(MAKE) check-report.junit.xml Generates an aggregated XML test report" + @echo " $(MAKE) check-venv Creates a Python venv for tests" + @echo " $(MAKE) check-clean Clean the tests and related data" @echo @echo "The following are useful for CI builds" - @echo " $(MAKE) check-build Build most test binaries" - @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)" + @echo " $(MAKE) check-build Build most test binaries" + @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)" @echo @echo @echo "The variable SPEED can be set to control the gtester speed setting." @@ -36,54 +36,63 @@ export SRC_PATH SPEED = quick -# Build up our target list from the filtered list of ninja targets -TARGETS=$(patsubst libqemu-%.fa, %, $(filter libqemu-%.fa, $(ninja-targets))) - # Per guest TCG tests -BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TARGETS)) -CLEAN_TCG_TARGET_RULES=$(patsubst %,clean-tcg-tests-%, $(TARGETS)) -RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TARGETS)) - -# Probe for the Docker Builds needed for each build -$(foreach PROBE_TARGET,$(TARGET_DIRS), \ - $(eval -include $(SRC_PATH)/tests/tcg/Makefile.prereqs)) - -$(BUILD_TCG_TARGET_RULES): build-tcg-tests-%: $(if $(CONFIG_PLUGIN),test-plugins) - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \ - -f $(SRC_PATH)/tests/tcg/Makefile.qemu \ - SRC_PATH=$(SRC_PATH) \ - V="$(V)" TARGET="$*" guest-tests, \ - "BUILD", "TCG tests for $*") - -$(RUN_TCG_TARGET_RULES): run-tcg-tests-%: build-tcg-tests-% all - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \ - -f $(SRC_PATH)/tests/tcg/Makefile.qemu \ - SRC_PATH=$(SRC_PATH) SPEED="$(SPEED)" \ - V="$(V)" TARGET="$*" run-guest-tests, \ - "RUN", "TCG tests for $*") - -$(CLEAN_TCG_TARGET_RULES): clean-tcg-tests-%: - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \ - -f $(SRC_PATH)/tests/tcg/Makefile.qemu \ - SRC_PATH=$(SRC_PATH) TARGET="$*" clean-guest-tests, \ - "CLEAN", "TCG tests for $*") +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), \ + $(eval $(BUILD_DIR)/tests/tcg/config-$(TARGET).mak: config-host.mak)) + +.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/$* $(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/$* $(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/$* $(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 build-tcg: $(BUILD_TCG_TARGET_RULES) .PHONY: check-tcg +.ninja-goals.check-tcg = all $(if $(CONFIG_PLUGIN),test-plugins) 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 +# Build up our target list from the filtered list of ninja targets +TARGETS=$(patsubst libqemu-%.fa, %, $(filter libqemu-%.fa, $(ninja-targets))) + TESTS_VENV_DIR=$(BUILD_DIR)/tests/venv TESTS_VENV_REQ=$(SRC_PATH)/tests/requirements.txt TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results +TESTS_PYTHON=$(TESTS_VENV_DIR)/bin/python3 ifndef AVOCADO_TESTS AVOCADO_TESTS=tests/avocado endif @@ -98,13 +107,14 @@ else AVOCADO_CMDLINE_TAGS=$(addprefix -t , $(AVOCADO_TAGS)) endif +quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \ + $(TESTS_PYTHON) -m pip -q --disable-pip-version-check $1, \ + "VENVPIP","$1") + $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) - $(call quiet-command, \ - $(PYTHON) -m venv $@, \ - VENV, $@) - $(call quiet-command, \ - $(TESTS_VENV_DIR)/bin/python -m pip -q install -r $(TESTS_VENV_REQ), \ - PIP, $(TESTS_VENV_REQ)) + $(call quiet-command, $(PYTHON) -m venv $@, VENV, $@) + $(call quiet-venv-pip,install -e "$(SRC_PATH)/python/") + $(call quiet-venv-pip,install -r $(TESTS_VENV_REQ)) $(call quiet-command, touch $@) $(TESTS_RESULTS_DIR): @@ -121,7 +131,7 @@ FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES)) # download one specific Fedora 31 image get-vm-image-fedora-31-%: check-venv $(call quiet-command, \ - $(TESTS_VENV_DIR)/bin/python -m avocado vmimage get \ + $(TESTS_PYTHON) -m avocado vmimage get \ --distro=fedora --distro-version=31 --arch=$*, \ "AVOCADO", "Downloading avocado tests VM image for $*") @@ -130,7 +140,7 @@ get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOW check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images $(call quiet-command, \ - $(TESTS_VENV_DIR)/bin/python -m avocado \ + $(TESTS_PYTHON) -m avocado \ --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \ $(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \ --filter-by-tags-include-empty-key) \ @@ -156,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/acpi-bits.py b/tests/avocado/acpi-bits.py new file mode 100644 index 000000000000..14038fa3c4e1 --- /dev/null +++ b/tests/avocado/acpi-bits.py @@ -0,0 +1,398 @@ +#!/usr/bin/env python3 +# group: rw quick +# Exercize QEMU generated ACPI/SMBIOS tables using biosbits, +# https://biosbits.org/ +# +# 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 . +# +# +# Author: +# Ani Sinha + +# pylint: disable=invalid-name +# pylint: disable=consider-using-f-string + +""" +This is QEMU ACPI/SMBIOS avocado tests using biosbits. +Biosbits is available originally at https://biosbits.org/. +This test uses a fork of the upstream bits and has numerous fixes +including an upgraded acpica. The fork is located here: +https://gitlab.com/qemu-project/biosbits-bits . +""" + +import logging +import os +import platform +import re +import shutil +import subprocess +import tarfile +import tempfile +import time +import zipfile +from typing import ( + List, + Optional, + Sequence, +) +from qemu.machine import QEMUMachine +from avocado import skipIf +from avocado_qemu import QemuBaseTest + +deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box. +supported_platforms = ['x86_64'] # supported test platforms. + + +def which(tool): + """ looks up the full path for @tool, returns None if not found + or if @tool does not have executable permissions. + """ + paths=os.getenv('PATH') + for p in paths.split(os.path.pathsep): + p = os.path.join(p, tool) + if os.path.exists(p) and os.access(p, os.X_OK): + return p + return None + +def missing_deps(): + """ returns True if any of the test dependent tools are absent. + """ + for dep in deps: + if which(dep) is None: + return True + return False + +def supported_platform(): + """ checks if the test is running on a supported platform. + """ + return platform.machine() in supported_platforms + +class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods + """ + A QEMU VM, with isa-debugcon enabled and bits iso passed + using -cdrom to QEMU commandline. + + """ + def __init__(self, + binary: str, + args: Sequence[str] = (), + wrapper: Sequence[str] = (), + name: Optional[str] = None, + base_temp_dir: str = "/var/tmp", + debugcon_log: str = "debugcon-log.txt", + debugcon_addr: str = "0x403", + sock_dir: Optional[str] = None, + qmp_timer: Optional[float] = None): + # pylint: disable=too-many-arguments + + if name is None: + name = "qemu-bits-%d" % os.getpid() + if sock_dir is None: + sock_dir = base_temp_dir + super().__init__(binary, args, wrapper=wrapper, name=name, + base_temp_dir=base_temp_dir, + sock_dir=sock_dir, qmp_timer=qmp_timer) + self.debugcon_log = debugcon_log + self.debugcon_addr = debugcon_addr + self.base_temp_dir = base_temp_dir + + @property + def _base_args(self) -> List[str]: + args = super()._base_args + args.extend([ + '-chardev', + 'file,path=%s,id=debugcon' %os.path.join(self.base_temp_dir, + self.debugcon_log), + '-device', + 'isa-debugcon,iobase=%s,chardev=debugcon' %self.debugcon_addr, + ]) + return args + + def base_args(self): + """return the base argument to QEMU binary""" + return self._base_args + +@skipIf(not supported_platform() or missing_deps() or os.getenv('GITLAB_CI'), + 'incorrect platform or dependencies (%s) not installed ' \ + 'or running on GitLab' % ','.join(deps)) +class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes + """ + ACPI and SMBIOS tests using biosbits. + + :avocado: tags=arch:x86_64 + :avocado: tags=acpi + + """ + # in slower systems the test can take as long as 3 minutes to complete. + timeout = 200 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._vm = None + self._workDir = None + self._baseDir = None + + # following are some standard configuration constants + self._bitsInternalVer = 2020 + self._bitsCommitHash = 'b48b88ff' # commit hash must match + # the artifact tag below + self._bitsTag = "qemu-bits-10182022" # this is the latest bits + # release as of today. + self._bitsArtSHA1Hash = 'b04790ac9b99b5662d0416392c73b97580641fe5' + self._bitsArtURL = ("https://gitlab.com/qemu-project/" + "biosbits-bits/-/jobs/artifacts/%s/" + "download?job=qemu-bits-build" %self._bitsTag) + self._debugcon_addr = '0x403' + self._debugcon_log = 'debugcon-log.txt' + logging.basicConfig(level=logging.INFO) + self.logger = logging.getLogger('acpi-bits') + + def _print_log(self, log): + self.logger.info('\nlogs from biosbits follows:') + self.logger.info('==========================================\n') + self.logger.info(log) + self.logger.info('==========================================\n') + + def copy_bits_config(self): + """ copies the bios bits config file into bits. + """ + config_file = 'bits-cfg.txt' + bits_config_dir = os.path.join(self._baseDir, 'acpi-bits', + 'bits-config') + target_config_dir = os.path.join(self._workDir, + 'bits-%d' %self._bitsInternalVer, + 'boot') + self.assertTrue(os.path.exists(bits_config_dir)) + self.assertTrue(os.path.exists(target_config_dir)) + self.assertTrue(os.access(os.path.join(bits_config_dir, + config_file), os.R_OK)) + shutil.copy2(os.path.join(bits_config_dir, config_file), + target_config_dir) + self.logger.info('copied config file %s to %s', + config_file, target_config_dir) + + def copy_test_scripts(self): + """copies the python test scripts into bits. """ + + bits_test_dir = os.path.join(self._baseDir, 'acpi-bits', + 'bits-tests') + target_test_dir = os.path.join(self._workDir, + 'bits-%d' %self._bitsInternalVer, + 'boot', 'python') + + self.assertTrue(os.path.exists(bits_test_dir)) + self.assertTrue(os.path.exists(target_test_dir)) + + for filename in os.listdir(bits_test_dir): + if os.path.isfile(os.path.join(bits_test_dir, filename)) and \ + filename.endswith('.py2'): + # all test scripts are named with extension .py2 so that + # avocado does not try to load them. These scripts are + # written for python 2.7 not python 3 and hence if avocado + # loaded them, it would complain about python 3 specific + # syntaxes. + newfilename = os.path.splitext(filename)[0] + '.py' + shutil.copy2(os.path.join(bits_test_dir, filename), + os.path.join(target_test_dir, newfilename)) + self.logger.info('copied test file %s to %s', + filename, target_test_dir) + + # now remove the pyc test file if it exists, otherwise the + # changes in the python test script won't be executed. + testfile_pyc = os.path.splitext(filename)[0] + '.pyc' + if os.access(os.path.join(target_test_dir, testfile_pyc), + os.F_OK): + os.remove(os.path.join(target_test_dir, testfile_pyc)) + self.logger.info('removed compiled file %s', + os.path.join(target_test_dir, + testfile_pyc)) + + def fix_mkrescue(self, mkrescue): + """ grub-mkrescue is a bash script with two variables, 'prefix' and + 'libdir'. They must be pointed to the right location so that the + iso can be generated appropriately. We point the two variables to + the directory where we have extracted our pre-built bits grub + tarball. + """ + grub_x86_64_mods = os.path.join(self._workDir, 'grub-inst-x86_64-efi') + grub_i386_mods = os.path.join(self._workDir, 'grub-inst') + + self.assertTrue(os.path.exists(grub_x86_64_mods)) + self.assertTrue(os.path.exists(grub_i386_mods)) + + new_script = "" + with open(mkrescue, 'r', encoding='utf-8') as filehandle: + orig_script = filehandle.read() + new_script = re.sub('(^prefix=)(.*)', + r'\1"%s"' %grub_x86_64_mods, + orig_script, flags=re.M) + new_script = re.sub('(^libdir=)(.*)', r'\1"%s/lib"' %grub_i386_mods, + new_script, flags=re.M) + + with open(mkrescue, 'w', encoding='utf-8') as filehandle: + filehandle.write(new_script) + + def generate_bits_iso(self): + """ Uses grub-mkrescue to generate a fresh bits iso with the python + test scripts + """ + bits_dir = os.path.join(self._workDir, + 'bits-%d' %self._bitsInternalVer) + iso_file = os.path.join(self._workDir, + 'bits-%d.iso' %self._bitsInternalVer) + mkrescue_script = os.path.join(self._workDir, + 'grub-inst-x86_64-efi', 'bin', + 'grub-mkrescue') + + self.assertTrue(os.access(mkrescue_script, + os.R_OK | os.W_OK | os.X_OK)) + + self.fix_mkrescue(mkrescue_script) + + self.logger.info('using grub-mkrescue for generating biosbits iso ...') + + try: + if os.getenv('V') or os.getenv('BITS_DEBUG'): + subprocess.check_call([mkrescue_script, '-o', iso_file, + bits_dir], stderr=subprocess.STDOUT) + else: + subprocess.check_call([mkrescue_script, '-o', + iso_file, bits_dir], + stderr=subprocess.DEVNULL, + stdout=subprocess.DEVNULL) + except Exception as e: # pylint: disable=broad-except + self.skipTest("Error while generating the bits iso. " + "Pass V=1 in the environment to get more details. " + + str(e)) + + self.assertTrue(os.access(iso_file, os.R_OK)) + + self.logger.info('iso file %s successfully generated.', iso_file) + + def setUp(self): # pylint: disable=arguments-differ + super().setUp('qemu-system-') + + self._baseDir = os.getenv('AVOCADO_TEST_BASEDIR') + + # workdir could also be avocado's own workdir in self.workdir. + # At present, I prefer to maintain my own temporary working + # directory. It gives us more control over the generated bits + # log files and also for debugging, we may chose not to remove + # this working directory so that the logs and iso can be + # inspected manually and archived if needed. + self._workDir = tempfile.mkdtemp(prefix='acpi-bits-', + suffix='.tmp') + self.logger.info('working dir: %s', self._workDir) + + prebuiltDir = os.path.join(self._workDir, 'prebuilt') + if not os.path.isdir(prebuiltDir): + os.mkdir(prebuiltDir, mode=0o775) + + bits_zip_file = os.path.join(prebuiltDir, 'bits-%d-%s.zip' + %(self._bitsInternalVer, + self._bitsCommitHash)) + grub_tar_file = os.path.join(prebuiltDir, + 'bits-%d-%s-grub.tar.gz' + %(self._bitsInternalVer, + self._bitsCommitHash)) + + bitsLocalArtLoc = self.fetch_asset(self._bitsArtURL, + asset_hash=self._bitsArtSHA1Hash) + self.logger.info("downloaded bits artifacts to %s", bitsLocalArtLoc) + + # extract the bits artifact in the temp working directory + with zipfile.ZipFile(bitsLocalArtLoc, 'r') as zref: + zref.extractall(prebuiltDir) + + # extract the bits software in the temp working directory + with zipfile.ZipFile(bits_zip_file, 'r') as zref: + zref.extractall(self._workDir) + + with tarfile.open(grub_tar_file, 'r', encoding='utf-8') as tarball: + tarball.extractall(self._workDir) + + self.copy_test_scripts() + self.copy_bits_config() + self.generate_bits_iso() + + def parse_log(self): + """parse the log generated by running bits tests and + check for failures. + """ + debugconf = os.path.join(self._workDir, self._debugcon_log) + log = "" + with open(debugconf, 'r', encoding='utf-8') as filehandle: + log = filehandle.read() + + matchiter = re.finditer(r'(.*Summary: )(\d+ passed), (\d+ failed).*', + log) + for match in matchiter: + # verify that no test cases failed. + try: + self.assertEqual(match.group(3).split()[0], '0', + 'Some bits tests seems to have failed. ' \ + 'Please check the test logs for more info.') + except AssertionError as e: + self._print_log(log) + raise e + else: + if os.getenv('V') or os.getenv('BITS_DEBUG'): + self._print_log(log) + + def tearDown(self): + """ + Lets do some cleanups. + """ + if self._vm: + self.assertFalse(not self._vm.is_running) + if not os.getenv('BITS_DEBUG'): + self.logger.info('removing the work directory %s', self._workDir) + shutil.rmtree(self._workDir) + else: + self.logger.info('not removing the work directory %s ' \ + 'as BITS_DEBUG is ' \ + 'passed in the environment', self._workDir) + super().tearDown() + + def test_acpi_smbios_bits(self): + """The main test case implementaion.""" + + iso_file = os.path.join(self._workDir, + 'bits-%d.iso' %self._bitsInternalVer) + + self.assertTrue(os.access(iso_file, os.R_OK)) + + self._vm = QEMUBitsMachine(binary=self.qemu_bin, + base_temp_dir=self._workDir, + debugcon_log=self._debugcon_log, + debugcon_addr=self._debugcon_addr) + + self._vm.add_args('-cdrom', '%s' %iso_file) + # the vm needs to be run under icount so that TCG emulation is + # consistent in terms of timing. smilatency tests have consistent + # timing requirements. + self._vm.add_args('-icount', 'auto') + + args = " ".join(str(arg) for arg in self._vm.base_args()) + \ + " " + " ".join(str(arg) for arg in self._vm.args) + + self.logger.info("launching QEMU vm with the following arguments: %s", + args) + + self._vm.launch() + # biosbits has been configured to run all the specified test suites + # in batch mode and then automatically initiate a vm shutdown. + # Rely on avocado's unit test timeout. + self._vm.wait(timeout=None) + self.parse_log() diff --git a/tests/avocado/acpi-bits/bits-config/bits-cfg.txt b/tests/avocado/acpi-bits/bits-config/bits-cfg.txt new file mode 100644 index 000000000000..801080445355 --- /dev/null +++ b/tests/avocado/acpi-bits/bits-config/bits-cfg.txt @@ -0,0 +1,18 @@ +# BITS configuration file +[bits] + +# To run BITS in batch mode, set batch to a list of one or more of the +# following keywords; BITS will then run all of the requested operations, then +# save the log file to disk. +# +# test: Run the full BITS testsuite. +# acpi: Dump all ACPI structures. +# smbios: Dump all SMBIOS structures. +# +# Leave batch set to an empty string to disable batch mode. +# batch = + +# Uncomment the following to run all available batch operations +# please take a look at boot/python/init.py in bits zip file +# to see how these options are parsed and used. +batch = test acpi smbios diff --git a/tests/avocado/acpi-bits/bits-tests/smbios.py2 b/tests/avocado/acpi-bits/bits-tests/smbios.py2 new file mode 100644 index 000000000000..fc623de072a7 --- /dev/null +++ b/tests/avocado/acpi-bits/bits-tests/smbios.py2 @@ -0,0 +1,2434 @@ +# Copyright (c) 2015, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This script runs only from the biosbits VM. + +"""SMBIOS/DMI module.""" + +import bits +import bitfields +import ctypes +import redirect +import struct +import uuid +import unpack +import ttypager +import sys + +class SMBIOS(unpack.Struct): + def __new__(cls): + if sys.platform == "BITS-EFI": + import efi + sm_ptr = efi.system_table.ConfigurationTableDict.get(efi.SMBIOS_TABLE_GUID) + else: + address = 0xF0000 + mem = bits.memory(0xF0000, 0x10000) + for offset in range(0, len(mem), 16): + signature = (ctypes.c_char * 4).from_address(address + offset).value + if signature == "_SM_": + entry_point_length = ctypes.c_ubyte.from_address(address + offset + 5).value + csum = sum(map(ord, mem[offset:offset + entry_point_length])) & 0xff + if csum == 0: + sm_ptr = address + offset + break + else: + return None + + if not sm_ptr: + return None + + sm = super(SMBIOS, cls).__new__(cls) + sm._header_memory = bits.memory(sm_ptr, 0x1f) + return sm + + def __init__(self): + super(SMBIOS, self).__init__() + u = unpack.Unpackable(self._header_memory) + self.add_field('header', Header(u)) + self._structure_memory = bits.memory(self.header.structure_table_address, self.header.structure_table_length) + u = unpack.Unpackable(self._structure_memory) + self.add_field('structures', unpack.unpack_all(u, _smbios_structures, self), unpack.format_each("\n\n{!r}")) + + def structure_type(self, num): + '''Dumps structure of given Type if present''' + try: + types_present = [self.structures[x].smbios_structure_type for x in range(len(self.structures))] + matrix = dict() + for index in range(len(types_present)): + if types_present.count(types_present[index]) == 1: + matrix[types_present[index]] = self.structures[index] + else: # if multiple structures of the same type, return a list of structures for the type number + if matrix.has_key(types_present[index]): + matrix[types_present[index]].append(self.structures[index]) + else: + matrix[types_present[index]] = [self.structures[index]] + return matrix[num] + except: + print "Failure: Type {} - not found".format(num) + +class Header(unpack.Struct): + def __new__(cls, u): + return super(Header, cls).__new__(cls) + + def __init__(self, u): + super(Header, self).__init__() + self.raw_data = u.unpack_rest() + u = unpack.Unpackable(self.raw_data) + self.add_field('anchor_string', u.unpack_one("4s")) + self.add_field('checksum', u.unpack_one("B")) + self.add_field('length', u.unpack_one("B")) + self.add_field('major_version', u.unpack_one("B")) + self.add_field('minor_version', u.unpack_one("B")) + self.add_field('max_structure_size', u.unpack_one(" len(self.strings): + return "(error: string index out of range)" + return self.strings[i - 1] + +class BIOSInformation(SmbiosBaseStructure): + smbios_structure_type = 0 + + def __init__(self, u, sm): + super(BIOSInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('vendor', u.unpack_one("B"), self.fmtstr) + self.add_field('version', u.unpack_one("B"), self.fmtstr) + self.add_field('starting_address_segment', u.unpack_one("= (2,"4"): + characteristic_bytes = 2 + else: + characteristic_bytes = self.length - 0x12 + self.add_field('characteristics_extensions', [u.unpack_one("B") for b in range(characteristic_bytes)]) + if (sm.header.major_version, minor_version_str) >= (2,"4"): + self.add_field('major_release', u.unpack_one("B")) + self.add_field('minor_release', u.unpack_one("B")) + self.add_field('ec_major_release', u.unpack_one("B")) + self.add_field('ec_minor_release', u.unpack_one("B")) + except: + self.decode_failure = True + print "Error parsing BIOSInformation" + import traceback + traceback.print_exc() + self.fini() + +class SystemInformation(SmbiosBaseStructure): + smbios_structure_type = 1 + + def __init__(self, u, sm): + super(SystemInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + self.add_field('product_name', u.unpack_one("B"), self.fmtstr) + self.add_field('version', u.unpack_one("B"), self.fmtstr) + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x8: + self.add_field('uuid', uuid.UUID(bytes_le=u.unpack_one("16s"))) + wakeup_types = { + 0: 'Reserved', + 1: 'Other', + 2: 'Unknown', + 3: 'APM Timer', + 4: 'Modem Ring', + 5: 'LAN Remote', + 6: 'Power Switch', + 7: 'PCI PME#', + 8: 'AC Power Restored' + } + self.add_field('wakeup_type', u.unpack_one("B"), unpack.format_table("{}", wakeup_types)) + if self.length > 0x19: + self.add_field('sku_number', u.unpack_one("B"), self.fmtstr) + self.add_field('family', u.unpack_one("B"), self.fmtstr) + except: + self.decode_failure = True + print "Error parsing SystemInformation" + import traceback + traceback.print_exc() + self.fini() + +_board_types = { + 1: 'Unknown', + 2: 'Other', + 3: 'Server Blade', + 4: 'Connectivity Switch', + 5: 'System Management Module', + 6: 'Processor Module', + 7: 'I/O Module', + 8: 'Memory Module', + 9: 'Daughter Board', + 0xA: 'Motherboard', + 0xB: 'Processor/Memory Module', + 0xC: 'Processor/IO Module', + 0xD: 'Interconnect Board' +} + +class BaseboardInformation(SmbiosBaseStructure): + smbios_structure_type = 2 + + def __init__(self, u, sm): + super(BaseboardInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + self.add_field('product', u.unpack_one("B"), self.fmtstr) + self.add_field('version', u.unpack_one("B"), self.fmtstr) + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + + if self.length > 0x8: + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + + if self.length > 0x9: + self.add_field('feature_flags', u.unpack_one("B")) + self.add_field('hosting_board', bool(bitfields.getbits(self.feature_flags, 0)), "feature_flags[0]={}") + self.add_field('requires_daughter_card', bool(bitfields.getbits(self.feature_flags, 1)), "feature_flags[1]={}") + self.add_field('removable', bool(bitfields.getbits(self.feature_flags, 2)), "feature_flags[2]={}") + self.add_field('replaceable', bool(bitfields.getbits(self.feature_flags, 3)), "feature_flags[3]={}") + self.add_field('hot_swappable', bool(bitfields.getbits(self.feature_flags, 4)), "feature_flags[4]={}") + + if self.length > 0xA: + self.add_field('location', u.unpack_one("B"), self.fmtstr) + + if self.length > 0xB: + self.add_field('chassis_handle', u.unpack_one(" 0xD: + self.add_field('board_type', u.unpack_one("B"), unpack.format_table("{}", _board_types)) + + if self.length > 0xE: + self.add_field('handle_count', u.unpack_one("B")) + if self.handle_count > 0: + self.add_field('contained_object_handles', tuple(u.unpack_one(" 9: + chassis_states = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Safe', + 0x04: 'Warning', + 0x05: 'Critical', + 0x06: 'Non-recoverable', + } + self.add_field('bootup_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) + self.add_field('power_supply_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) + self.add_field('thermal_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) + security_states = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'None', + 0x04: 'External interface locked out', + 0x05: 'External interface enabled', + } + self.add_field('security_status', u.unpack_one("B"), unpack.format_table("{}", security_states)) + if self.length > 0xd: + self.add_field('oem_defined', u.unpack_one(" 0x11: + self.add_field('height', u.unpack_one("B")) + self.add_field('num_power_cords', u.unpack_one("B")) + self.add_field('contained_element_count', u.unpack_one("B")) + self.add_field('contained_element_length', u.unpack_one("B")) + if getattr(self, 'contained_element_count', 0): + self.add_field('contained_elements', tuple(SystemEnclosureContainedElement(u, self.contained_element_length) for i in range(self.contained_element_count))) + if self.length > (0x15 + (getattr(self, 'contained_element_count', 0) * getattr(self, 'contained_element_length', 0))): + self.add_field('sku_number', u.unpack_one("B"), self.fmtstr) + except: + self.decode_failure = True + print "Error parsing SystemEnclosure" + import traceback + traceback.print_exc() + self.fini() + +class SystemEnclosureContainedElement(unpack.Struct): + def __init__(self, u, length): + super(SystemEnclosureContainedElement, self).__init__() + self.start_offset = u.offset + self.raw_data = u.unpack_raw(length) + self.u = unpack.Unpackable(self.raw_data) + u = self.u + self.add_field('contained_element_type', u.unpack_one("B")) + type_selections = { + 0: 'SMBIOS baseboard type enumeration', + 1: 'SMBIOS structure type enumeration', + } + self.add_field('type_select', bitfields.getbits(self.contained_element_type, 7), unpack.format_table("contained_element_type[7]={}", type_selections)) + self.add_field('type', bitfields.getbits(self.contained_element_type, 6, 0)) + if self.type_select == 0: + self.add_field('smbios_board_type', self.type, unpack.format_table("{}", _board_types)) + else: + self.add_field('smbios_structure_type', self.type) + self.add_field('minimum', u.unpack_one("B")) + self.add_field('maximum', u.unpack_one("B")) + if not u.at_end(): + self.add_field('data', u.unpack_rest()) + del self.u + +class ProcessorInformation(SmbiosBaseStructure): + smbios_structure_type = 4 + + def __init__(self, u, sm): + super(ProcessorInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('socket_designation', u.unpack_one("B"), self.fmtstr) + processor_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Central Processor', + 0x04: 'Math Processor', + 0x05: 'DSP Processor', + 0x06: 'Video Processor', + } + self.add_field('processor_type', u.unpack_one("B"), unpack.format_table("{}", processor_types)) + self.add_field('processor_family', u.unpack_one("B")) + self.add_field('processor_manufacturer', u.unpack_one("B"), self.fmtstr) + self.add_field('processor_id', u.unpack_one(" 0x1A: + self.add_field('l1_cache_handle', u.unpack_one(" 0x20: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + self.add_field('part_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x24: + self.add_field('core_count', u.unpack_one("B")) + self.add_field('core_enabled', u.unpack_one("B")) + self.add_field('thread_count', u.unpack_one("B")) + self.add_field('processor_characteristics', u.unpack_one(" 0x28: + self.add_field('processor_family_2', u.unpack_one(" 0x2A: + self.add_field('core_count2', u.unpack_one(" 0x0F: + self.add_field('cache_speed', u.unpack_one("B")) + if self.length > 0x10: + _error_correction = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'None', + 0x04: 'Parity', + 0x05: 'Single-bit ECC', + 0x06: 'Multi-bit ECC' + } + self.add_field('error_correction', u.unpack_one("B"), unpack.format_table("{}", _error_correction)) + if self.length > 0x10: + _system_cache_type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Instruction', + 0x04: 'Data', + 0x05: 'Unified' + } + self.add_field('system_cache_type', u.unpack_one("B"), unpack.format_table("{}", _system_cache_type)) + if self.length > 0x12: + _associativity = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Direct Mapped', + 0x04: '2-way Set-Associative', + 0x05: '4-way Set-Associative', + 0x06: 'Fully Associative', + 0x07: '8-way Set-Associative', + 0x08: '16-way Set-Associative', + 0x09: '12-way Set-Associative', + 0x0A: '24-way Set-Associative', + 0x0B: '32-way Set-Associative', + 0x0C: '48-way Set-Associative', + 0x0D: '64-way Set-Associative', + 0x0E: '20-way Set-Associative' + } + self.add_field('associativity', u.unpack_one("B"), unpack.format_table("{}", _associativity)) + + except: + self.decode_failure = True + print "Error parsing CacheInformation" + import traceback + traceback.print_exc() + self.fini() + +class PortConnectorInfo(SmbiosBaseStructure): + smbios_structure_type = 8 + + def __init__(self, u, sm): + super(PortConnectorInfo, self).__init__(u, sm) + u = self.u + try: + self.add_field('internal_reference_designator', u.unpack_one("B"), self.fmtstr) + connector_types = { + 0x00: 'None', + 0x01: 'Centronics', + 0x02: 'Mini Centronics', + 0x03: 'Proprietary', + 0x04: 'DB-25 pin male', + 0x05: 'DB-25 pin female', + 0x06: 'DB-15 pin male', + 0x07: 'DB-15 pin female', + 0x08: 'DB-9 pin male', + 0x09: 'DB-9 pin female', + 0x0A: 'RJ-11', + 0x0B: 'RJ-45', + 0x0C: '50-pin MiniSCSI', + 0x0D: 'Mini-DIN', + 0x0E: 'Micro-DIN', + 0x0F: 'PS/2', + 0x10: 'Infrared', + 0x11: 'HP-HIL', + 0x12: 'Access Bus (USB)', + 0x13: 'SSA SCSI', + 0x14: 'Circular DIN-8 male', + 0x15: 'Circular DIN-8 female', + 0x16: 'On Board IDE', + 0x17: 'On Board Floppy', + 0x18: '9-pin Dual Inline (pin 10 cut)', + 0x19: '25-pin Dual Inline (pin 26 cut)', + 0x1A: '50-pin Dual Inline', + 0x1B: '68-pin Dual Inline', + 0x1C: 'On Board Sound Input from CD-ROM', + 0x1D: 'Mini-Centronics Type-14', + 0x1E: 'Mini-Centronics Type-26', + 0x1F: 'Mini-jack (headphones)', + 0x20: 'BNC', + 0x21: '1394', + 0x22: 'SAS/SATA Plug Receptacle', + 0xA0: 'PC-98', + 0xA1: 'PC-98Hireso', + 0xA2: 'PC-H98', + 0xA3: 'PC-98Note', + 0xA4: 'PC-98Full', + 0xFF: 'Other', + } + self.add_field('internal_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types)) + self.add_field('external_reference_designator', u.unpack_one("B"), self.fmtstr) + self.add_field('external_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types)) + port_types = { + 0x00: 'None', + 0x01: 'Parallel Port XT/AT Compatible', + 0x02: 'Parallel Port PS/2', + 0x03: 'Parallel Port ECP', + 0x04: 'Parallel Port EPP', + 0x05: 'Parallel Port ECP/EPP', + 0x06: 'Serial Port XT/AT Compatible', + 0x07: 'Serial Port 16450 Compatible', + 0x08: 'Serial Port 16550 Compatible', + 0x09: 'Serial Port 16550A Compatible', + 0x0A: 'SCSI Port', + 0x0B: 'MIDI Port', + 0x0C: 'Joy Stick Port', + 0x0D: 'Keyboard Port', + 0x0E: 'Mouse Port', + 0x0F: 'SSA SCSI', + 0x10: 'USB', + 0x11: 'FireWire (IEEE P1394)', + 0x12: 'PCMCIA Type I2', + 0x13: 'PCMCIA Type II', + 0x14: 'PCMCIA Type III', + 0x15: 'Cardbus', + 0x16: 'Access Bus Port', + 0x17: 'SCSI II', + 0x18: 'SCSI Wide', + 0x19: 'PC-98', + 0x1A: 'PC-98-Hireso', + 0x1B: 'PC-H98', + 0x1C: 'Video Port', + 0x1D: 'Audio Port', + 0x1E: 'Modem Port', + 0x1F: 'Network Port', + 0x20: 'SATA', + 0x21: 'SAS', + 0xA0: '8251 Compatible', + 0xA1: '8251 FIFO Compatible', + 0xFF: 'Other', + } + self.add_field('port_type', u.unpack_one("B"), unpack.format_table("{}", port_types)) + except: + self.decodeFailure = True + print "Error parsing PortConnectorInfo" + import traceback + traceback.print_exc() + self.fini() + +class SystemSlots(SmbiosBaseStructure): + smbios_structure_type = 9 + + def __init__(self, u, sm): + super(SystemSlots, self).__init__(u, sm) + u = self.u + try: + self.add_field('designation', u.unpack_one("B"), self.fmtstr) + _slot_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'ISA', + 0x04: 'MCA', + 0x05: 'EISA', + 0x06: 'PCI', + 0x07: 'PC Card (PCMCIA)', + 0x08: 'VL-VESA', + 0x09: 'Proprietary', + 0x0A: 'Processor Card Slot', + 0x0B: 'Proprietary Memory Card Slot', + 0x0C: 'I/O Riser Card Slot', + 0x0D: 'NuBus', + 0x0E: 'PCI 66MHz Capable', + 0x0F: 'AGP', + 0x10: 'AGP 2X', + 0x11: 'AGP 4X', + 0x12: 'PCI-X', + 0x13: 'AGP 8X', + 0xA0: 'PC-98/C20', + 0xA1: 'PC-98/C24', + 0xA2: 'PC-98/E', + 0xA3: 'PC-98/Local Bus', + 0xA4: 'PC-98/Card', + 0xA5: 'PCI Express', + 0xA6: 'PCI Express x1', + 0xA7: 'PCI Express x2', + 0xA8: 'PCI Express x4', + 0xA9: 'PCI Express x8', + 0xAA: 'PCI Express x16', + 0xAB: 'PCI Express Gen 2', + 0xAC: 'PCI Express Gen 2 x1', + 0xAD: 'PCI Express Gen 2 x2', + 0xAE: 'PCI Express Gen 2 x4', + 0xAF: 'PCI Express Gen 2 x8', + 0xB0: 'PCI Express Gen 2 x16', + 0xB1: 'PCI Express Gen 3', + 0xB2: 'PCI Express Gen 3 x1', + 0xB3: 'PCI Express Gen 3 x2', + 0xB4: 'PCI Express Gen 3 x4', + 0xB5: 'PCI Express Gen 3 x8', + 0xB6: 'PCI Express Gen 3 x16', + } + self.add_field('slot_type', u.unpack_one("B"), unpack.format_table("{}", _slot_types)) + _slot_data_bus_widths = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: '8 bit', + 0x04: '16 bit', + 0x05: '32 bit', + 0x06: '64 bit', + 0x07: '128 bit', + 0x08: '1x or x1', + 0x09: '2x or x2', + 0x0A: '4x or x4', + 0x0B: '8x or x8', + 0x0C: '12x or x12', + 0x0D: '16x or x16', + 0x0E: '32x or x32', + } + self.add_field('slot_data_bus_width', u.unpack_one('B'), unpack.format_table("{}", _slot_data_bus_widths)) + _current_usages = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Available', + 0x04: 'In use', + } + self.add_field('current_usage', u.unpack_one('B'), unpack.format_table("{}", _current_usages)) + _slot_lengths = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Short Length', + 0x04: 'Long Length', + } + self.add_field('slot_length', u.unpack_one('B'), unpack.format_table("{}", _slot_lengths)) + self.add_field('slot_id', u.unpack_one(' 0x0C: + self.add_field('characteristics2', u.unpack_one('B')) + self.add_field('supports_PME', bool(bitfields.getbits(self.characteristics2, 0)), "characteristics2[0]={}") + self.add_field('supports_hot_plug', bool(bitfields.getbits(self.characteristics2, 1)), "characteristics2[1]={}") + self.add_field('supports_smbus', bool(bitfields.getbits(self.characteristics2, 2)), "characteristics2[2]={}") + if self.length > 0x0D: + self.add_field('segment_group_number', u.unpack_one(' 0x05: + self.add_field('flags', u.unpack_one('B')) + self.add_field('abbreviated_format', bool(bitfields.getbits(self.flags, 0)), "flags[0]={}") + if self.length > 0x6: + u.skip(15) + self.add_field('current_language', u.unpack_one('B'), self.fmtstr) + except: + self.decodeFailure = True + print "Error parsing BIOSLanguageInformation" + import traceback + traceback.print_exc() + self.fini() + +class GroupAssociations(SmbiosBaseStructure): + smbios_structure_type = 14 + + def __init__(self, u, sm): + super(GroupAssociations, self).__init__(u, sm) + u = self.u + try: + self.add_field('group_name', u.unpack_one("B"), self.fmtstr) + self.add_field('item_type', u.unpack_one('B')) + self.add_field('item_handle', u.unpack_one(' 0x14: + _log_header_formats = { + 0: 'No header', + 1: 'Type 1 log header', + xrange(2, 0x7f): 'Available for future assignment', + xrange(0x80, 0xff): 'BIOS vendor or OEM-specific format' + } + self.add_field('log_header_format', u.unpack_one("B"), unpack.format_table("{}", _log_header_formats)) + if self.length > 0x15: + self.add_field('num_supported_log_type_descriptors', u.unpack_one('B')) + if self.length > 0x16: + self.add_field('length_log_type_descriptor', u.unpack_one('B')) + if self.length != (0x17 + (self.num_supported_log_type_descriptors * self.length_log_type_descriptor)): + print "Error: structure length ({}) != 0x17 + (num_supported_log_type_descriptors ({}) * length_log_type_descriptor({}))".format(self.length, self.num_supported_log_type_descriptors, self.length_log_type_descriptor) + print "structure length = {}".format(self.length) + print "num_supported_log_type_descriptors = {}".format(self.num_supported_log_type_descriptors) + print "length_log_type_descriptor = {}".format(self.length_log_type_descriptor) + self.decodeFailure = True + self.add_field('descriptors', tuple(EventLogDescriptor.unpack(u) for i in range(self.num_supported_log_type_descriptors)), unpack.format_each("\n{!r}")) + except: + self.decodeFailure = True + print "Error parsing SystemEventLog" + import traceback + traceback.print_exc() + self.fini() + +class EventLogDescriptor(unpack.Struct): + @staticmethod + def _unpack(u): + _event_log_type_descriptors = { + 0x00: 'Reserved', + 0x01: 'Single-bit ECC memory error', + 0x02: 'Multi-bit ECC memory error', + 0x03: 'Parity memory error', + 0x04: 'Bus time-out', + 0x05: 'I/O Channel Check', + 0x06: 'Software NMI', + 0x07: 'POST Memory Resize', + 0x08: 'POST Error', + 0x09: 'PCI Parity Error', + 0x0A: 'PCI System Error', + 0x0B: 'CPU Failure', + 0x0C: 'EISA FailSafe Timer time-out', + 0x0D: 'Correctable memory log disabled', + 0x0E: 'Logging disabled for a specific Event Type - too many errors of the same type received in a short amount of time', + 0x0F: 'Reserved', + 0x10: 'System Limit Exceeded', + 0x11: 'Asynchronous hardware timer expired and issued a system reset', + 0x12: 'System configuration information', + 0x13: 'Hard-disk information', + 0x14: 'System reconfigured', + 0x15: 'Uncorrectable CPU-complex error', + 0x16: 'Log Area Reset/Cleared', + 0x17: 'System boot', + xrange(0x18, 0x7F): 'Unused, available for assignment', + xrange(0x80, 0xFE): 'Availalbe for system- and OEM-specific assignments', + 0xFF: 'End of log' + } + yield 'log_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_type_descriptors) + _event_log_format = { + 0x00: 'None', + 0x01: 'Handle', + 0x02: 'Multiple-Event', + 0x03: 'Multiple-Event Handle', + 0x04: 'POST Results Bitmap', + 0x05: 'System Management Type', + 0x06: 'Multiple-Event System Management Type', + xrange(0x80, 0xFF): 'OEM assigned' + } + yield 'variable_data_format_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_format) + +class PhysicalMemoryArray(SmbiosBaseStructure): + smbios_structure_type = 16 + + def __init__(self, u, sm): + super(PhysicalMemoryArray, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + _location_field = { + 0x01: "Other", + 0x02: "Unknown", + 0x03: "System board or motherboard", + 0x04: "ISA add-on card", + 0x05: "EISA add-on card", + 0x06: "PCI add-on card", + 0x07: "MCA add-on card", + 0x08: "PCMCIA add-on card", + 0x09: "Proprietary add-on card", + 0x0A: "NuBus", + 0xA0: "PC-98/C20 add-on card", + 0xA1: "PC-98/C24 add-on card", + 0xA2: "PC-98/E add-on card", + 0xA3: "PC-98/Local bus add-on card" + } + self.add_field('location', u.unpack_one("B"), unpack.format_table("{}", _location_field)) + if self.length > 0x05: + _use = { + 0x01: "Other", + 0x02: "Unknown", + 0x03: "System memory", + 0x04: "Video memory", + 0x05: "Flash memory", + 0x06: "Non-volatile RAM", + 0x07: "Cache memory" + } + self.add_field('use', u.unpack_one('B'), unpack.format_table("{}", _use)) + if self.length > 0x06: + _error_correction = { + 0x01: "Other", + 0x02: "Unknown", + 0x03: "None", + 0x04: "Parity", + 0x05: "Single-bit ECC", + 0x06: "Multi-bit ECC", + 0x07: "CRC" + } + self.add_field('memory_error_correction', u.unpack_one('B'), unpack.format_table("{}", _error_correction)) + if self.length > 0x07: + self.add_field('maximum_capacity', u.unpack_one(' 0x0B: + self.add_field('memory_error_information_handle', u.unpack_one(' 0x0D: + self.add_field('num_memory_devices', u.unpack_one(' 0x0F: + self.add_field('extended_maximum_capacity', u.unpack_one(' 0x4: + self.add_field('physical_memory_array_handle', u.unpack_one(" 0x6: + self.add_field('memory_error_information_handle', u.unpack_one(" 0x8: + self.add_field('total_width', u.unpack_one(" 0xA: + self.add_field('data_width', u.unpack_one(" 0xC: + self.add_field('size', u.unpack_one(" 0xE: + _form_factors = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'SIMM', + 0x04: 'SIP', + 0x05: 'Chip', + 0x06: 'DIP', + 0x07: 'ZIP', + 0x08: 'Proprietary Card', + 0x09: 'DIMM', + 0x0A: 'TSOP', + 0x0B: 'Row of chips', + 0x0C: 'RIMM', + 0x0D: 'SODIMM', + 0x0E: 'SRIMM', + 0x0F: 'FB-DIMM' + } + self.add_field('form_factor', u.unpack_one("B"), unpack.format_table("{}", _form_factors)) + if self.length > 0xF: + self.add_field('device_set', u.unpack_one("B")) + if self.length > 0x10: + self.add_field('device_locator', u.unpack_one("B"), self.fmtstr) + if self.length > 0x11: + self.add_field('bank_locator', u.unpack_one("B"), self.fmtstr) + if self.length > 0x12: + _memory_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'DRAM', + 0x04: 'EDRAM', + 0x05: 'VRAM', + 0x06: 'SRAM', + 0x07: 'RAM', + 0x08: 'ROM', + 0x09: 'FLASH', + 0x0A: 'EEPROM', + 0x0B: 'FEPROM', + 0x0C: 'EPROM', + 0x0D: 'CDRAM', + 0x0E: '3DRAM', + 0x0F: 'SDRAM', + 0x10: 'SGRAM', + 0x11: 'RDRAM', + 0x12: 'DDR', + 0x13: 'DDR2', + 0x14: 'DDR2 FB-DIMM', + xrange(0x15, 0x17): 'Reserved', + 0x18: 'DDR3', + 0x19: 'FBD2' + } + self.add_field('memory_type', u.unpack_one("B"), unpack.format_table("{}", _memory_types)) + if self.length > 0x13: + self.add_field('type_detail', u.unpack_one(' 0x15: + self.add_field('speed', u.unpack_one(" 0x17: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + if self.length > 0x18: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x19: + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + if self.length > 0x1A: + self.add_field('part_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x1B: + self.add_field('attributes', u.unpack_one("B")) + self.add_field('rank', bitfields.getbits(self.attributes, 3, 0), "attributes[3:0]={}") + if self.length > 0x1C: + if self.size == 0x7FFF: + self.add_field('extended_size', u.unpack_one(' 0x20: + self.add_field('configured_memory_clock_speed', u.unpack_one(" 0x22: + self.add_field('minimum_voltage', u.unpack_one(" 0x24: + self.add_field('maximum_voltage', u.unpack_one(" 0x26: + self.add_field('configured_voltage', u.unpack_one(" 0x4: + _error_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'OK', + 0x04: 'Bad read', + 0x05: 'Parity error', + 0x06: 'Single-bit error', + 0x07: 'Double-bit error', + 0x08: 'Multi-bit error', + 0x09: 'Nibble error', + 0x0A: 'Checksum error', + 0x0B: 'CRC error', + 0x0C: 'Corrected single-bit error', + 0x0D: 'Corrected error', + 0x0E: 'Uncorrectable error' + } + self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types)) + if self.length > 0x5: + _error_granularity_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Device level', + 0x04: 'Memory partition level' + } + self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field)) + if self.length > 0x6: + _error_operation_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Read', + 0x04: 'Write', + 0x05: 'Partial write' + } + self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field)) + if self.length > 0x7: + self.add_field('vendor_syndrome', u.unpack_one(" 0xB: + self.add_field('memory_array_error_address', u.unpack_one(" 0xF: + self.add_field('device_error_address', u.unpack_one(" 0x13: + self.add_field('error_resolution', u.unpack_one(" 0x4: + self.add_field('starting_address', u.unpack_one(" 0x8: + self.add_field('ending_address', u.unpack_one(" 0xC: + self.add_field('memory_array_handle', u.unpack_one(" 0xE: + self.add_field('partition_width', u.unpack_one("B")) + if self.length > 0xF: + # valid if starting_address = FFFF FFFF + if self.starting_address == 0xFFFFFFFF: + self.add_field('extended_starting_address', u.unpack_one(" 0x17: + self.add_field('extended_ending_address', u.unpack_one(" 0x4: + self.add_field('starting_address', u.unpack_one(" 0x8: + self.add_field('ending_address', u.unpack_one(" 0xC: + self.add_field('memory_device_handle', u.unpack_one(" 0xE: + self.add_field('memory_array_mapped_address_handle', u.unpack_one(" 0x10: + self.add_field('partition_row_position', u.unpack_one("B")) + if self.length > 0x11: + self.add_field('interleave_position', u.unpack_one("B")) + if self.length > 0x12: + self.add_field('interleave_data_depth', u.unpack_one("B")) + if self.length > 0x13: + # valid if starting_address = FFFF FFFF + if self.starting_address == 0xFFFFFFFF: + self.add_field('extended_starting_address', u.unpack_one(" 0x1B: + self.add_field('extended_ending_address', u.unpack_one(" 0x4: + _pointing_device_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Mouse', + 0x04: 'Track Ball', + 0x05: 'Track Point', + 0x06: 'Glide Point', + 0x07: 'Touch Pad', + 0x08: 'Touch Screen', + 0x09: 'Optical Sensor' + } + self.add_field('pointing_device_type', u.unpack_one("B"), unpack.format_table("{}", _pointing_device_types)) + if self.length > 0x5: + _interfaces = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Serial', + 0x04: 'PS/2', + 0x05: 'Infared', + 0x06: 'HP-HIL', + 0x07: 'Bus mouse', + 0x08: 'ADB (Apple Desktop Bus)', + 0x09: 'Bus mouse DB-9', + 0x0A: 'Bus mouse micro-DIN', + 0x0B: 'USB' + } + self.add_field('interface', u.unpack_one("B"), unpack.format_table("{}", _interfaces)) + if self.length > 0x6: + self.add_field('num_buttons', u.unpack_one("B")) + except: + self.decodeFailure = True + print "Error parsing BuiltInPointingDevice" + import traceback + traceback.print_exc() + self.fini() + +class PortableBattery(SmbiosBaseStructure): + smbios_structure_type = 22 + + def __init__(self, u, sm): + super(PortableBattery, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('location', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + if self.length > 0x6: + self.add_field('manufacturer_date', u.unpack_one("B"), self.fmtstr) + if self.length > 0x7: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x8: + self.add_field('device_name', u.unpack_one("B"), self.fmtstr) + if self.length > 0x9: + _device_chemistry = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Lead Acid', + 0x04: 'Nickel Cadmium', + 0x05: 'Nickel metal hydride', + 0x06: 'Lithium-ion', + 0x07: 'Zinc air', + 0x08: 'Lithium Polymer' + } + self.add_field('device_chemistry', u.unpack_one("B"), unpack.format_table("{}", _device_chemistry)) + if self.length > 0xA: + self.add_field('design_capacity', u.unpack_one(" 0xC: + self.add_field('design_voltage', u.unpack_one(" 0xE: + self.add_field('sbds_version_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0xF: + self.add_field('max_error_battery_data', u.unpack_one("B"), self.fmtstr) + if self.length > 0x10: + if self.serial_number == 0: + self.add_field('sbds_serial_number', u.unpack_one(" 0x12: + if self.manufacturer_date == 0: + self.add_field('sbds_manufacture_date', u.unpack_one(" 0x14: + if self.device_chemistry == 0x02: + self.add_field('sbds_device_chemistry', u.unpack_one("B"), self.fmtstr) + else: + u.skip(1) + if self.length > 0x15: + self.add_field('design_capacity_multiplier', u.unpack_one("B")) + if self.length > 0x16: + self.add_field('oem_specific', u.unpack_one(" 0x4: + self.add_field('capabilities', u.unpack_one("B")) + self.add_field('contains_watchdog_timer', bool(bitfields.getbits(self.capabilities, 5)), "capabilities[5]={}") + _boot_option = { + 0b00: 'Reserved, do not use', + 0b01: 'Operating System', + 0b10: 'System utilities', + 0b11: 'Do not reboot' + } + self.add_field('boot_option_on_limit', bitfields.getbits(self.capabilities, 4, 3), unpack.format_table("capabilities[4:3]={}", _boot_option)) + self.add_field('boot_option_after_watchdog_reset', bitfields.getbits(self.capabilities, 2, 1), unpack.format_table("capabilities[2:1]={}", _boot_option)) + self.add_field('system_reset_enabled_by_user', bool(bitfields.getbits(self.capabilities, 0)), "capabilities[0]={}") + if self.length > 0x5: + self.add_field('reset_count', u.unpack_one(" 0x5: + self.add_field('reset_limit', u.unpack_one(" 0x9: + self.add_field('timer_interval', u.unpack_one(" 0xB: + self.add_field('timeout', u.unpack_one(" 0x4: + self.add_field('hardware_security_settings', u.unpack_one("B")) + _status = { + 0x00: 'Disabled', + 0x01: 'Enabled', + 0x02: 'Not Implemented', + 0x03: 'Unknown' + } + self.add_field('power_on_password_status', bitfields.getbits(self.hardware_security_settings, 7, 6), unpack.format_table("hardware_security_settings[7:6]={}", _status)) + self.add_field('keyboard_password_status', bitfields.getbits(self.hardware_security_settings, 5, 4), unpack.format_table("hardware_security_settings[5:4]={}", _status)) + self.add_field('admin_password_status', bitfields.getbits(self.hardware_security_settings, 3, 2), unpack.format_table("hardware_security_settings0[3:2]={}", _status)) + self.add_field('front_panel_reset_status', bitfields.getbits(self.hardware_security_settings, 1, 0), unpack.format_table("hardware_security_settings[1:0]={}", _status)) + except: + self.decodeFailure = True + print "Error parsing HardwareSecurity" + import traceback + traceback.print_exc() + self.fini() + +class SystemPowerControls(SmbiosBaseStructure): + smbios_structure_type = 25 + + def __init__(self, u, sm): + super(SystemPowerControls, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('next_scheduled_poweron_month', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_day_of_month', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_hour', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_minute', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_second', u.unpack_one("B")) + except: + self.decodeFailure = True + print "Error parsing SystemPowerControls" + import traceback + traceback.print_exc() + self.fini() + +class VoltageProbe(SmbiosBaseStructure): + smbios_structure_type = 26 + + def __init__(self, u, sm): + super(VoltageProbe, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('location_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _location = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Processor', + 0b00100: 'Disk', + 0b00101: 'Peripheral Bay', + 0b00110: 'System Management Module', + 0b00111: 'Motherboard', + 0b01000: 'Memory Module', + 0b01001: 'Processor Module', + 0b01010: 'Power Unit', + 0b01011: 'Add-in Card' + } + self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) + self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) + if self.length > 0x6: + self.add_field('max_value', u.unpack_one(" 0x8: + self.add_field('min_value', u.unpack_one(" 0xA: + self.add_field('resolution', u.unpack_one(" 0xC: + self.add_field('tolerance', u.unpack_one(" 0xE: + self.add_field('accuracy', u.unpack_one(" 0x10: + self.add_field('oem_defined', u.unpack_one(" 0x14: + self.add_field('nominal_value', u.unpack_one(" 0x4: + self.add_field('temperature_probe_handle', u.unpack_one(" 0x6: + self.add_field('device_type_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _type = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Fan', + 0b00100: 'Centrifugal Blower', + 0b00101: 'Chip Fan', + 0b00110: 'Cabinet Fan', + 0b00111: 'Power Supply Fan', + 0b01000: 'Heat Pipe', + 0b01001: 'Integrated Refrigeration', + 0b10000: 'Active Cooling', + 0b10001: 'Passive Cooling' + } + self.add_field('status', bitfields.getbits(self.device_type_and_status, 7, 5), unpack.format_table("device_type_and_status[7:5]={}", _status)) + self.add_field('device_type', bitfields.getbits(self.device_type_and_status, 4, 0), unpack.format_table("device_type_and_status[4:0]={}", _type)) + if self.length > 0x7: + self.add_field('cooling_unit_group', u.unpack_one("B")) + if self.length > 0x8: + self.add_field('OEM_defined', u.unpack_one(" 0xC: + self.add_field('nominal_speed', u.unpack_one(" 0xE: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + except: + self.decodeFailure = True + print "Error parsing CoolingDevice" + import traceback + traceback.print_exc() + self.fini() + +class TemperatureProbe(SmbiosBaseStructure): + smbios_structure_type = 28 + + def __init__(self, u, sm): + super(TemperatureProbe, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('location_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _location = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Processor', + 0b00100: 'Disk', + 0b00101: 'Peripheral Bay', + 0b00110: 'System Management Module', + 0b00111: 'Motherboard', + 0b01000: 'Memory Module', + 0b01001: 'Processor Module', + 0b01010: 'Power Unit', + 0b01011: 'Add-in Card', + 0b01100: 'Front Panel Board', + 0b01101: 'Back Panel Board', + 0b01110: 'Power System Board', + 0b01111: 'Drive Back Plane' + } + self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) + self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) + if self.length > 0x6: + self.add_field('maximum_value', u.unpack_one(" 0x8: + self.add_field('minimum_value', u.unpack_one(" 0xA: + self.add_field('resolution', u.unpack_one(" 0xC: + self.add_field('tolerance', u.unpack_one(" 0xE: + self.add_field('accuracy', u.unpack_one(" 0x10: + self.add_field('OEM_defined', u.unpack_one(" 0x14: + self.add_field('nominal_value', u.unpack_one(" 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('location_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _location = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Processor', + 0b00100: 'Disk', + 0b00101: 'Peripheral Bay', + 0b00110: 'System Management Module', + 0b00111: 'Motherboard', + 0b01000: 'Memory Module', + 0b01001: 'Processor Module', + 0b01010: 'Power Unit', + 0b01011: 'Add-in Card', + 0b01100: 'Front Panel Board', + 0b01101: 'Back Panel Board', + 0b01110: 'Power System Board', + 0b01111: 'Drive Back Plane' + } + self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) + self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) + if self.length > 0x6: + self.add_field('maximum_value', u.unpack_one(" 0x8: + self.add_field('minimum_value', u.unpack_one(" 0xA: + self.add_field('resolution', u.unpack_one(" 0xC: + self.add_field('tolerance', u.unpack_one(" 0xE: + self.add_field('accuracy', u.unpack_one(" 0x10: + self.add_field('OEM_defined', u.unpack_one(" 0x14: + self.add_field('nominal_value', u.unpack_one(" 0x4: + self.add_field('manufacturer_name', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('connections', u.unpack_one("B")) + self.add_field('outbound_connection_enabled', bool(bitfields.getbits(self.connections, 1)), "connections[1]={}") + self.add_field('inbound_connection_enabled', bool(bitfields.getbits(self.connections, 0)), "connections[0]={}") + except: + self.decodeFailure = True + print "Error parsing OutOfBandRemoteAccess" + import traceback + traceback.print_exc() + self.fini() + +class BootIntegrityServicesEntryPoint(SmbiosBaseStructure): + smbios_structure_type = 31 + +class SystemBootInformation(SmbiosBaseStructure): + smbios_structure_type = 32 + + def __init__(self, u, sm): + super(SystemBootInformation, self).__init__(u, sm) + u = self.u + try: + if self.length > 0xA: + u.skip(6) + _boot_status = { + 0: 'No errors detected', + 1: 'No bootable media', + 2: '"normal" operating system failed to load', + 3: 'Firmware-detected hardware failure, including "unknown" failure types', + 4: 'Operating system-detected hardware failure', + 5: 'User-requested boot, usually through a keystroke', + 6: 'System security violation', + 7: 'Previously-requested image', + 8: 'System watchdog timer expired, causing the system to reboot', + xrange(9,127): 'Reserved for future assignment', + xrange(128, 191): 'Vendor/OEM-specific implementations', + xrange(192, 255): 'Product-specific implementations' + } + self.add_field('boot_status', u.unpack_one("B"), unpack.format_table("{}", _boot_status)) + except: + self.decodeFailure = True + print "Error parsing SystemBootInformation" + import traceback + traceback.print_exc() + self.fini() + +class MemoryErrorInfo64Bit(SmbiosBaseStructure): + smbios_structure_type = 33 + + def __init__(self, u, sm): + super(MemoryErrorInfo64Bit, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + _error_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'OK', + 0x04: 'Bad read', + 0x05: 'Parity error', + 0x06: 'Single-bit error', + 0x07: 'Double-bit error', + 0x08: 'Multi-bit error', + 0x09: 'Nibble error', + 0x0A: 'Checksum error', + 0x0B: 'CRC error', + 0x0C: 'Corrected single-bit error', + 0x0D: 'Corrected error', + 0x0E: 'Uncorrectable error' + } + self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types)) + if self.length > 0x5: + _error_granularity_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Device level', + 0x04: 'Memory partition level' + } + self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field)) + if self.length > 0x6: + _error_operation_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Read', + 0x04: 'Write', + 0x05: 'Partial write' + } + self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field)) + if self.length > 0x7: + self.add_field('vendor_syndrome', u.unpack_one(" 0xB: + self.add_field('memory_array_error_address', u.unpack_one(" 0xF: + self.add_field('device_error_address', u.unpack_one(" 0x13: + self.add_field('error_resolution', u.unpack_one(" 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + _type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'National Semiconductor LM75', + 0x04: 'National Semiconductor LM78', + 0x05: 'National Semiconductor LM79', + 0x06: 'National Semiconductor LM80', + 0x07: 'National Semiconductor LM81', + 0x08: 'Analog Devices ADM9240', + 0x09: 'Dallas Semiconductor DS1780', + 0x0A: 'Maxim 1617', + 0x0B: 'Genesys GL518SM', + 0x0C: 'Winbond W83781D', + 0x0D: 'Holtek HT82H791' + } + self.add_field('device_type', u.unpack_one("B"), unpack.format_table("{}", _type)) + if self.length > 0x6: + self.add_field('address', u.unpack_one(" 0xA: + _address_type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'I/O Port', + 0x04: 'Memory', + 0x05: 'SM Bus' + } + self.add_field('address_type', u.unpack_one("B"), unpack.format_table("{}", _address_type)) + except: + self.decodeFailure = True + print "Error parsing ManagementDevice" + import traceback + traceback.print_exc() + self.fini() + +class ManagementDeviceComponent(SmbiosBaseStructure): + smbios_structure_type = 35 + + def __init__(self, u, sm): + super(ManagementDeviceComponent, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('management_device_handle', u.unpack_one(" 0x7: + self.add_field('component_handle', u.unpack_one(" 0x9: + self.add_field('threshold_handle', u.unpack_one(" 0x4: + self.add_field('lower_threshold_noncritical', u.unpack_one(" 0x6: + self.add_field('upper_threshold_noncritical', u.unpack_one(" 0x8: + self.add_field('lower_threshold_critical', u.unpack_one(" 0xA: + self.add_field('upper_threshold_critical', u.unpack_one(" 0xC: + self.add_field('lower_threshold_nonrecoverable', u.unpack_one(" 0xE: + self.add_field('upper_threshold_nonrecoverable', u.unpack_one(" 0x4: + _channel_type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'RamBus', + 0x04: 'SyncLink' + } + self.add_field('channel_type', u.unpack_one("B"), unpack.format_table("{}", _channel_type)) + if self.length > 0x6: + self.add_field('max_channel_load', u.unpack_one("B")) + if self.length > 0x8: + self.add_field('memory_device_count', u.unpack_one("B")) + if self.length > 0xA: + self.add_field('memory_device_load', u.unpack_one("B")) + if self.length > 0xC: + self.add_field('memory_device_handle', u.unpack_one(" 0x4: + self.add_field('power_unit_group', u.unpack_one("B")) + if self.length > 0x5: + self.add_field('location', u.unpack_one("B"), self.fmtstr) + if self.length > 0x6: + self.add_field('device_name', u.unpack_one("B"), self.fmtstr) + if self.length > 0x7: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + if self.length > 0x8: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x9: + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + if self.length > 0xA: + self.add_field('model_part_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0xB: + self.add_field('revision_level', u.unpack_one("B"), self.fmtstr) + if self.length > 0xC: + self.add_field('max_power_capacity', u.unpack_one(" 0xE: + self.add_field('power_supply_characteristics', u.unpack_one(" 0x10: + self.add_field('input_voltage_probe_handle', u.unpack_one(" 0x12: + self.add_field('cooling_device_handle', u.unpack_one(" 0x14: + self.add_field('input_current_probe_handle', u.unpack_one(" 0x4: + self.add_field('num_additional_information_entries', u.unpack_one("B")) + if self.length > 0x5: + self.add_field('additional_information_entry_length', u.unpack_one("B")) + self.add_field('referenced_handle', u.unpack_one(" 0x4: + self.add_field('reference_designation', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('device_type', u.unpack_one("B")) + self.add_field('device_enabled', bool(bitfields.getbits(self.device_type, 7)), "device_type[7]={}") + _device_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Video', + 0x04: 'SCSI Controller', + 0x05: 'Ethernet', + 0x06: 'Token Ring', + 0x07: 'Sound', + 0x08: 'PATA Controller', + 0x09: 'SATA Controller', + 0x0A: 'SAS Controller' + } + self.add_field('type_of_device', bitfields.getbits(self.device_type, 6, 0), unpack.format_table("device_type[6:0]={}", _device_types)) + if self.length > 0x6: + self.add_field('device_type_instance', u.unpack_one("B")) + if self.length > 0x7: + self.add_field('segment_group_number', u.unpack_one(" 0x9: + self.add_field('bus_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0xA: + self.add_field('device_and_function_number', u.unpack_one("B")) + self.add_field('device_number', bitfields.getbits(self.device_type, 7, 3), "device_and_function_number[7:3]={}") + self.add_field('function_number', bitfields.getbits(self.device_type, 2, 0), "device_and_function_number[2:0]={}") + except: + self.decodeFailure = True + print "Error parsing OnboardDevicesExtendedInformation" + import traceback + traceback.print_exc() + self.fini() + +class ManagementControllerHostInterface(SmbiosBaseStructure): + smbios_structure_type = 42 + + def __init__(self, u, sm): + super(ManagementControllerHostInterface, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + _interface_types = { + 0x00: 'Reserved', + 0x01: 'Reserved', + 0x02: 'KCS: Keyboard Controller Style', + 0x03: '8250 UART Register Compatible', + 0x04: '16450 UART Register Compatible', + 0x05: '16550/16550A UART Register Compatible', + 0x06: '16650/16650A UART Register Compatible', + 0x07: '16750/16750A UART Register Compatible', + 0x08: '16850/16850A UART Register Compatible', + 0xF0: 'OEM' + } + self.add_field('interface_type', u.unpack_one("B"), unpack.format_table("{}", _interface_types)) + if self.length > 0x5: + self.add_field('mc_host_interface_data', u.unpack_rest(), self.fmtstr) + except: + self.decodeFailure = True + print "Error parsing ManagementControllerHostInterface" + import traceback + traceback.print_exc() + self.fini() + +class Inactive(SmbiosBaseStructure): + smbios_structure_type = 126 + + def __init__(self, u, sm): + super(Inactive, self).__init__(u, sm) + self.fini() + +class EndOfTable(SmbiosBaseStructure): + smbios_structure_type = 127 + + def __init__(self, u, sm): + super(EndOfTable, self).__init__(u, sm) + self.fini() + +class SmbiosStructureUnknown(SmbiosBaseStructure): + smbios_structure_type = None + + def __init__(self, u, sm): + super(SmbiosStructureUnknown, self).__init__(u, sm) + self.fini() + +_smbios_structures = [ + BIOSInformation, + SystemInformation, + BaseboardInformation, + SystemEnclosure, + ProcessorInformation, + MemoryControllerInformation, + MemoryModuleInformation, + CacheInformation, + PortConnectorInfo, + SystemSlots, + OnBoardDevicesInformation, + OEMStrings, + SystemConfigOptions, + BIOSLanguageInformation, + GroupAssociations, + SystemEventLog, + PhysicalMemoryArray, + MemoryDevice, + MemoryErrorInfo32Bit, + MemoryArrayMappedAddress, + MemoryDeviceMappedAddress, + BuiltInPointingDevice, + PortableBattery, + SystemReset, + HardwareSecurity, + SystemPowerControls, + VoltageProbe, + CoolingDevice, + TemperatureProbe, + ElectricalCurrentProbe, + OutOfBandRemoteAccess, + BootIntegrityServicesEntryPoint, + SystemBootInformation, + MemoryErrorInfo64Bit, + ManagementDevice, + ManagementDeviceComponent, + ManagementDeviceThresholdData, + MemoryChannel, + IPMIDeviceInformation, + SystemPowerSupply, + AdditionalInformation, + OnboardDevicesExtendedInformation, + ManagementControllerHostInterface, + Inactive, + EndOfTable, + SmbiosStructureUnknown, # Must always come last +] + +def log_smbios_info(): + with redirect.logonly(): + try: + sm = SMBIOS() + print + if sm is None: + print "No SMBIOS structures found" + return + output = {} + known_types = (0, 1) + for sm_struct in sm.structures: + if sm_struct.type in known_types: + output.setdefault(sm_struct.type, []).append(sm_struct) + if len(output) == len(known_types): + break + + print "SMBIOS information:" + for key in sorted(known_types): + for s in output.get(key, ["No structure of type {} found".format(key)]): + print ttypager._wrap("{}: {}".format(key, s)) + except: + print "Error parsing SMBIOS information:" + import traceback + traceback.print_exc() + +def dump_raw(): + try: + sm = SMBIOS() + if sm: + s = "SMBIOS -- Raw bytes and structure decode.\n\n" + + s += str(sm.header) + '\n' + s += bits.dumpmem(sm._header_memory) + '\n' + + s += "Raw bytes for the SMBIOS structures\n" + s += bits.dumpmem(sm._structure_memory) + '\n' + + for sm_struct in sm.structures: + s += str(sm_struct) + '\n' + s += bits.dumpmem(sm_struct.raw_data) + + s += "Strings:\n" + for n in range(1, len(getattr(sm_struct, "strings", [])) + 1): + s += str(sm_struct.fmtstr(n)) + '\n' + s += bits.dumpmem(sm_struct.raw_strings) + '\n' + else: + s = "No SMBIOS structures found" + ttypager.ttypager_wrap(s, indent=False) + except: + print "Error parsing SMBIOS information:" + import traceback + traceback.print_exc() + +def dump(): + try: + sm = SMBIOS() + if sm: + s = str(sm) + else: + s = "No SMBIOS structures found" + ttypager.ttypager_wrap(s, indent=False) + except: + print "Error parsing SMBIOS information:" + import traceback + traceback.print_exc() + +def annex_a_conformance(): + try: + sm = SMBIOS() + + # check: 1. The table anchor string "_SM_" is present in the address range 0xF0000 to 0xFFFFF on a 16-byte bound + + def table_entry_point_verification(): + ''' Verify table entry-point''' + if (sm.header.length < 0x1F): + print "Failure: Table entry-point - The entry-point Length must be at least 0x1F" + if sm.header.checksum != 0: + print "Failure: Table entry-point - The entry-point checksum must evaluate to 0" + if ((sm.header.major_version < 2) and (sm.header.minor_version < 4)): + print "Failure: Table entry-point - SMBIOS version must be at least 2.4" + if (sm.header.intermediate_anchor_string == '_DMI_'): + print "Failure: Table entry-point - The Intermediate Anchor String must be '_DMI_'" + if (sm.header.intermediate_checksum != 0): + print "Failure: Table entry-point - The Intermediate checksum must evaluate to 0" + + #check: 3. The structure-table is traversable and conforms to the entry-point specifications: + + def req_structures(): + '''Checks for required structures and corresponding data''' + types_present = [sm.structures[x].smbios_structure_type for x in range(len(sm.structures))] + required = [0, 1, 4, 7, 9, 16, 17, 19, 31, 32] + for s in required: + if s not in set(types_present): + print "Failure: Type {} required but not found".format(s) + + else: + if s == 0: + if types_present.count(s) > 1: + print "Failure: Type {} - One and only one structure of this type must be present.".format(s) + if sm.structure_type(s).length < 0x18: + print "Failure: Type {} - The structure Length field must be at least 0x18".format(s) + if sm.structure_type(s).version is None: + print "Failure: Type {} - BIOS Version string must be present and non-null.".format(s) + if sm.structure_type(s).release_date is None: + print "Failure: Type {} - BIOS Release Date string must be present, non-null, and include a 4-digit year".format(s) + if bitfields.getbits(sm.structure_type(s).characteristics, 3, 0) != 0 or bitfields.getbits(sm.structure_type(s).characteristics, 31, 4) == 0: + print "Failure: Type {} - BIOS Characteristics: bits 3:0 must all be 0, and at least one of bits 31:4 must be set to 1.".format(s) + elif s == 1: + if types_present.count(s) > 1: + print "Failure: Type {} - One and only one structure of this type must be present.".format(s) + if sm.structure_type(s).length < 0x1B: + print "Failure: Type {} - The structure Length field must be at least 0x1B".format(s) + if sm.structure_type(s).manufacturer == None: + print "Failure: Type {} - Manufacturer string must be present and non-null.".format(s) + if sm.structure_type(s).product_name == None: + print "Failure: Type {} - Product Name string must be present and non-null".format(s) + if sm.structure_type(s).uuid == '00000000 00000000' and sm.structure_type(s).uuid == 'FFFFFFFF FFFFFFFF': + print "Failure: Type {} - UUID field must be neither 00000000 00000000 nor FFFFFFFF FFFFFFFF.".format(s) + if sm.structure_type(s).wakeup_type == 00 and sm.structure_type(s).wakeup_type == 0x02: + print "Failure: Type {} - Wake-up Type field must be neither 00h (Reserved) nor 02h (Unknown).".format(s) + # continue for remaining required types + + # check remaining conformance guidelines + + table_entry_point_verification() + req_structures() + except: + print "Error checking ANNEX A conformance guidelines" + import traceback + traceback.print_exc() diff --git a/tests/avocado/acpi-bits/bits-tests/testacpi.py2 b/tests/avocado/acpi-bits/bits-tests/testacpi.py2 new file mode 100644 index 000000000000..f818a9cce66f --- /dev/null +++ b/tests/avocado/acpi-bits/bits-tests/testacpi.py2 @@ -0,0 +1,287 @@ +# Copyright (c) 2015, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This script runs only from the biosbits VM. + +"""Tests for ACPI""" + +import acpi +import bits +import bits.mwait +import struct +import testutil +import testsuite +import time + +def register_tests(): + testsuite.add_test("ACPI _MAT (Multiple APIC Table Entry) under Processor objects", test_mat, submenu="ACPI Tests") +# testsuite.add_test("ACPI _PSS (Pstate) table conformance tests", test_pss, submenu="ACPI Tests") +# testsuite.add_test("ACPI _PSS (Pstate) runtime tests", test_pstates, submenu="ACPI Tests") + testsuite.add_test("ACPI DSDT (Differentiated System Description Table)", test_dsdt, submenu="ACPI Tests") + testsuite.add_test("ACPI FACP (Fixed ACPI Description Table)", test_facp, submenu="ACPI Tests") + testsuite.add_test("ACPI HPET (High Precision Event Timer Table)", test_hpet, submenu="ACPI Tests") + testsuite.add_test("ACPI MADT (Multiple APIC Description Table)", test_apic, submenu="ACPI Tests") + testsuite.add_test("ACPI MPST (Memory Power State Table)", test_mpst, submenu="ACPI Tests") + testsuite.add_test("ACPI RSDP (Root System Description Pointer Structure)", test_rsdp, submenu="ACPI Tests") + testsuite.add_test("ACPI XSDT (Extended System Description Table)", test_xsdt, submenu="ACPI Tests") + +def test_mat(): + cpupaths = acpi.get_cpupaths() + apic = acpi.parse_apic() + procid_apicid = apic.procid_apicid + uid_x2apicid = apic.uid_x2apicid + for cpupath in cpupaths: + # Find the ProcId defined by the processor object + processor = acpi.evaluate(cpupath) + # Find the UID defined by the processor object's _UID method + uid = acpi.evaluate(cpupath + "._UID") + mat_buffer = acpi.evaluate(cpupath + "._MAT") + if mat_buffer is None: + continue + # Process each _MAT subtable + mat = acpi._MAT(mat_buffer) + for index, subtable in enumerate(mat): + if subtable.subtype == acpi.MADT_TYPE_LOCAL_APIC: + if subtable.flags.bits.enabled: + testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id) + testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id)) + testsuite.print_detail("Processor Declaration: {}".format(processor)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid): + testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id) + testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id)) + testsuite.print_detail("Processor Declaration: {}".format(processor)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + if subtable.subtype == acpi.MADT_TYPE_LOCAL_X2APIC: + if subtable.flags.bits.enabled: + if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None): + testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid) + testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid): + testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid) + testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + +def test_pss(): + uniques = acpi.parse_cpu_method("_PSS") + # We special-case None here to avoid a double-failure for CPUs without a _PSS + testsuite.test("_PSS must be identical for all CPUs", len(uniques) <= 1 or (len(uniques) == 2 and None in uniques)) + for pss, cpupaths in uniques.iteritems(): + if not testsuite.test("_PSS must exist", pss is not None): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail('No _PSS exists') + continue + + if not testsuite.test("_PSS must not be empty", pss.pstates): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail('_PSS is empty') + continue + + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + for index, pstate in enumerate(pss.pstates): + testsuite.print_detail("P[{}]: {}".format(index, pstate)) + + testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16) + testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates))) + + frequencies = [p.core_frequency for p in pss.pstates] + testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True)) + + testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies))) + + dissipations = [p.power for p in pss.pstates] + testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True)) + +def test_pstates(): + """Execute and verify frequency for each Pstate in the _PSS""" + IA32_PERF_CTL = 0x199 + with bits.mwait.use_hint(), bits.preserve_msr(IA32_PERF_CTL): + cpupath_procid = acpi.find_procid() + cpupath_uid = acpi.find_uid() + apic = acpi.parse_apic() + procid_apicid = apic.procid_apicid + uid_x2apicid = apic.uid_x2apicid + def cpupath_apicid(cpupath): + if procid_apicid is not None: + procid = cpupath_procid.get(cpupath, None) + if procid is not None: + apicid = procid_apicid.get(procid, None) + if apicid is not None: + return apicid + if uid_x2apicid is not None: + uid = cpupath_uid.get(cpupath, None) + if uid is not None: + apicid = uid_x2apicid.get(uid, None) + if apicid is not None: + return apicid + return bits.cpus()[0] + + bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000 + + uniques = acpi.parse_cpu_method("_PSS") + for pss, cpupaths in uniques.iteritems(): + if not testsuite.test("_PSS must exist", pss is not None): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail('No _PSS exists') + continue + + for n, pstate in enumerate(pss.pstates): + for cpupath in cpupaths: + apicid = cpupath_apicid(cpupath) + if apicid is None: + print 'Failed to find apicid for cpupath {}'.format(cpupath) + continue + bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control) + + # Detecting Turbo frequency requires at least 2 pstates + # since turbo frequency = max non-turbo frequency + 1 + turbo = False + if len(pss.pstates) >= 2: + turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1)) + if turbo: + # Needs to busywait, not sleep + start = time.time() + while (time.time() - start < 2): + pass + + for duration in (0.1, 1.0): + frequency_data = bits.cpu_frequency(duration) + # Abort the test if no cpu frequency is not available + if frequency_data is None: + continue + aperf = frequency_data[1] + aperf = testutil.adjust_to_nearest(aperf, bclk/2) + aperf = int(aperf / 1000000) + if turbo: + if aperf >= pstate.core_frequency: + break + else: + if aperf == pstate.core_frequency: + break + + if turbo: + testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency) + else: + testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency) + +def test_psd_thread_scope(): + uniques = acpi.parse_cpu_method("_PSD") + if not testsuite.test("_PSD (P-State Dependency) must exist for each processor", None not in uniques): + testsuite.print_detail(acpi.factor_commonprefix(uniques[None])) + testsuite.print_detail('No _PSD exists') + return + unique_num_dependencies = {} + unique_num_entries = {} + unique_revision = {} + unique_domain = {} + unique_coordination_type = {} + unique_num_processors = {} + for value, cpupaths in uniques.iteritems(): + unique_num_dependencies.setdefault(len(value.dependencies), []).extend(cpupaths) + unique_num_entries.setdefault(value.dependencies[0].num_entries, []).extend(cpupaths) + unique_revision.setdefault(value.dependencies[0].revision, []).extend(cpupaths) + unique_domain.setdefault(value.dependencies[0].domain, []).extend(cpupaths) + unique_coordination_type.setdefault(value.dependencies[0].coordination_type, []).extend(cpupaths) + unique_num_processors.setdefault(value.dependencies[0].num_processors, []).extend(cpupaths) + def detail(d, fmt): + for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail(fmt.format(value)) + + testsuite.test('Dependency count for each processor must be 1', unique_num_dependencies.keys() == [1]) + detail(unique_num_dependencies, 'Dependency count for each processor = {} (Expected 1)') + testsuite.test('_PSD.num_entries must be 5', unique_num_entries.keys() == [5]) + detail(unique_num_entries, 'num_entries = {} (Expected 5)') + testsuite.test('_PSD.revision must be 0', unique_revision.keys() == [0]) + detail(unique_revision, 'revision = {}') + testsuite.test('_PSD.coordination_type must be 0xFE (HW_ALL)', unique_coordination_type.keys() == [0xfe]) + detail(unique_coordination_type, 'coordination_type = {:#x} (Expected 0xFE HW_ALL)') + testsuite.test('_PSD.domain must be unique (thread-scoped) for each processor', len(unique_domain) == len(acpi.get_cpupaths())) + detail(unique_domain, 'domain = {:#x} (Expected a unique value for each processor)') + testsuite.test('_PSD.num_processors must be 1', unique_num_processors.keys() == [1]) + detail(unique_num_processors, 'num_processors = {} (Expected 1)') + +def test_table_checksum(data): + csum = sum(ord(c) for c in data) % 0x100 + testsuite.test('ACPI table cumulative checksum must equal 0', csum == 0) + testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum)) + +def test_apic(): + data = acpi.get_table("APIC") + if data is None: + return + test_table_checksum(data) + apic = acpi.parse_apic() + +def test_dsdt(): + data = acpi.get_table("DSDT") + if data is None: + return + test_table_checksum(data) + +def test_facp(): + data = acpi.get_table("FACP") + if data is None: + return + test_table_checksum(data) + facp = acpi.parse_facp() + +def test_hpet(): + data = acpi.get_table("HPET") + if data is None: + return + test_table_checksum(data) + hpet = acpi.parse_hpet() + +def test_mpst(): + data = acpi.get_table("MPST") + if data is None: + return + test_table_checksum(data) + mpst = acpi.MPST(data) + +def test_rsdp(): + data = acpi.get_table("RSD PTR ") + if data is None: + return + + # Checksum the first 20 bytes per ACPI 1.0 + csum = sum(ord(c) for c in data[:20]) % 0x100 + testsuite.test('ACPI 1.0 table first 20 bytes cummulative checksum must equal 0', csum == 0) + testsuite.print_detail("Cummulative checksum = {} (Expected 0)".format(csum)) + + test_table_checksum(data) + rsdp = acpi.parse_rsdp() + +def test_xsdt(): + data = acpi.get_table("XSDT") + if data is None: + return + test_table_checksum(data) + xsdt = acpi.parse_xsdt() diff --git a/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 b/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 new file mode 100644 index 000000000000..7adefbe3558c --- /dev/null +++ b/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 @@ -0,0 +1,87 @@ +# Copyright (c) 2012, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This script runs only from the biosbits VM. + +"""Tests and helpers for CPUID.""" + +import bits +import testsuite +import testutil + +def cpuid_helper(function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): + if index is None: + index = 0 + indexdesc = "" + else: + indexdesc = " index {0:#x}".format(index) + + def find_mask(m): + if m == ~0: + return mask + return m + masks = map(find_mask, [eax_mask, ebx_mask, ecx_mask, edx_mask]) + + uniques = {} + for cpu in bits.cpus(): + regs = bits.cpuid_result(*[(r >> shift) & m for r, m in zip(bits.cpuid(cpu, function, index), masks)]) + uniques.setdefault(regs, []).append(cpu) + + desc = ["CPUID function {:#x}{}".format(function, indexdesc)] + + if shift != 0: + desc.append("Register values have been shifted by {}".format(shift)) + if mask != ~0 or eax_mask != ~0 or ebx_mask != ~0 or ecx_mask != ~0 or edx_mask != ~0: + desc.append("Register values have been masked:") + shifted_masks = bits.cpuid_result(*[m << shift for m in masks]) + desc.append("Masks: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**shifted_masks._asdict())) + + if len(uniques) > 1: + regvalues = zip(*uniques.iterkeys()) + common_masks = bits.cpuid_result(*map(testutil.find_common_mask, regvalues)) + common_values = bits.cpuid_result(*[v[0] & m for v, m in zip(regvalues, common_masks)]) + desc.append('Register values are not unique across all logical processors') + desc.append("Common bits: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**common_values._asdict())) + desc.append("Mask of common bits: {eax:#010x} {ebx:#010x} {ecx:#010x} {edx:#010x}".format(**common_masks._asdict())) + + for regs in sorted(uniques.iterkeys()): + cpus = uniques[regs] + desc.append("Register value: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**regs._asdict())) + desc.append("On {0} CPUs: {1}".format(len(cpus), testutil.apicid_list(cpus))) + + return uniques, desc + +def test_cpuid_consistency(text, function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): + uniques, desc = cpuid_helper(function, index, shift, mask, eax_mask, ebx_mask, ecx_mask, edx_mask) + desc[0] += " Consistency Check" + if text: + desc.insert(0, text) + status = testsuite.test(desc[0], len(uniques) == 1) + for line in desc[1:]: + testsuite.print_detail(line) + return status diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index ac85e36a4d26..910f3ba1eab8 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -21,6 +21,11 @@ from avocado.utils import cloudinit, datadrainer, process, ssh, vmimage from avocado.utils.path import find_command +from qemu.machine import QEMUMachine +from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available, + tcg_available) + + #: The QEMU build root directory. It may also be the source directory #: if building from the source dir, but it's safer to use BUILD_DIR for #: that purpose. Be aware that if this code is moved outside of a source @@ -35,12 +40,6 @@ else: SOURCE_DIR = BUILD_DIR -sys.path.append(os.path.join(SOURCE_DIR, 'python')) - -from qemu.machine import QEMUMachine -from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available, - tcg_available) - def has_cmd(name, args=None): """ @@ -121,14 +120,15 @@ def pick_default_qemu_bin(bin_prefix='qemu-system-', arch=None): # qemu binary path does not match arch for powerpc, handle it if 'ppc64le' in arch: arch = 'ppc64' - qemu_bin_relative_path = os.path.join(".", bin_prefix + arch) - if is_readable_executable_file(qemu_bin_relative_path): - return qemu_bin_relative_path - - qemu_bin_from_bld_dir_path = os.path.join(BUILD_DIR, - qemu_bin_relative_path) - if is_readable_executable_file(qemu_bin_from_bld_dir_path): - return qemu_bin_from_bld_dir_path + qemu_bin_name = bin_prefix + arch + qemu_bin_paths = [ + os.path.join(".", qemu_bin_name), + os.path.join(BUILD_DIR, qemu_bin_name), + os.path.join(BUILD_DIR, "build", qemu_bin_name), + ] + for path in qemu_bin_paths: + if is_readable_executable_file(path): + return path return None @@ -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 @@ def require_accelerator(self, accelerator): 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,14 +518,15 @@ def default_kernel_params(self): 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' + smp = '2' + memory = '1024' def _set_distro(self): distro_name = self.params.get( @@ -545,9 +556,10 @@ def _set_distro(self): 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', '2') - self.vm.add_args('-m', '1024') + self.vm.add_args('-smp', self.smp) + self.vm.add_args('-m', self.memory) # The following network device allows for SSH connections self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', '-device', '%s,netdev=vnet' % network_device_type) diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py index ee584d2fdf2a..b3e58fa30936 100644 --- a/tests/avocado/boot_linux.py +++ b/tests/avocado/boot_linux.py @@ -19,6 +19,7 @@ class BootLinuxX8664(LinuxTest): """ :avocado: tags=arch:x86_64 """ + timeout = 480 def test_pc_i440fx_tcg(self): """ @@ -57,12 +58,16 @@ def test_pc_q35_kvm(self): self.launch_and_wait(set_up_ssh_connection=False) +# For Aarch64 we only boot KVM tests in CI as the TCG tests are very +# heavyweight. There are lighter weight distros which we use in the +# machine_aarch64_virt.py tests. class BootLinuxAarch64(LinuxTest): """ :avocado: tags=arch:aarch64 :avocado: tags=machine:virt :avocado: tags=machine:gic-version=2 """ + timeout = 720 def add_common_args(self): self.vm.add_args('-bios', @@ -71,7 +76,8 @@ def add_common_args(self): self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom') - def test_virt_tcg_gicv2(self): + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') + def test_fedora_cloud_tcg_gicv2(self): """ :avocado: tags=accel:tcg :avocado: tags=cpu:max @@ -84,7 +90,8 @@ def test_virt_tcg_gicv2(self): self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) - def test_virt_tcg_gicv3(self): + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') + def test_fedora_cloud_tcg_gicv3(self): """ :avocado: tags=accel:tcg :avocado: tags=cpu:max @@ -114,6 +121,8 @@ class BootLinuxPPC64(LinuxTest): :avocado: tags=arch:ppc64 """ + timeout = 360 + def test_pseries_tcg(self): """ :avocado: tags=machine:pseries @@ -129,6 +138,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 b40a3abc8171..8c1d98158613 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -15,6 +15,7 @@ from avocado import skip from avocado import skipUnless +from avocado import skipIf from avocado_qemu import QemuSystemTest from avocado_qemu import exec_command from avocado_qemu import exec_command_and_wait_for_pattern @@ -325,31 +326,6 @@ def test_mips_malta32el_nanomips_64k_dbg(self): kernel_hash = '18d1c68f2e23429e266ca39ba5349ccd0aeb7180' self.do_test_mips_malta32el_nanomips(kernel_url, kernel_hash) - def test_aarch64_virt(self): - """ - :avocado: tags=arch:aarch64 - :avocado: tags=machine:virt - :avocado: tags=accel:tcg - :avocado: tags=cpu:cortex-a53 - """ - kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' - '/linux/releases/29/Everything/aarch64/os/images/pxeboot' - '/vmlinuz') - kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493' - kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - - self.vm.set_console() - kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + - 'console=ttyAMA0') - self.require_accelerator("tcg") - self.vm.add_args('-cpu', 'cortex-a53', - '-accel', 'tcg', - '-kernel', kernel_path, - '-append', kernel_command_line) - self.vm.launch() - console_pattern = 'Kernel command line: %s' % kernel_command_line - self.wait_for_console_pattern(console_pattern) - def test_aarch64_xlnx_versal_virt(self): """ :avocado: tags=arch:aarch64 @@ -360,13 +336,13 @@ def test_aarch64_xlnx_versal_virt(self): """ 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() @@ -406,6 +382,8 @@ def test_arm_emcraft_sf2(self): :avocado: tags=u-boot :avocado: tags=accel:tcg """ + self.require_netdev('user') + uboot_url = ('https://raw.githubusercontent.com/' 'Subbaraya-Sundeep/qemu-test-binaries/' 'fe371d32e50ca682391e1e70ab98c2942aeffb01/u-boot') @@ -512,7 +490,7 @@ def test_arm_raspi2_initrd(self): 'BCM2835') exec_command_and_wait_for_pattern(self, 'cat /proc/iomem', '/soc/cprman@7e101000') - exec_command(self, 'halt') + exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted') # Wait for VM to shut down gracefully self.vm.wait() @@ -642,6 +620,53 @@ def test_arm_cubieboard_sata(self): 'sda') # cubieboard's reboot is not functioning; omit reboot test. + @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited') + def test_arm_cubieboard_openwrt_22_03_2(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:cubieboard + :avocado: tags=device:sd + """ + + # This test download a 7.5 MiB compressed image and expand it + # to 126 MiB. + image_url = ('https://downloads.openwrt.org/releases/22.03.2/targets/' + 'sunxi/cortexa8/openwrt-22.03.2-sunxi-cortexa8-' + 'cubietech_a10-cubieboard-ext4-sdcard.img.gz') + image_hash = ('94b5ecbfbc0b3b56276e5146b899eafa' + '2ac5dc2d08733d6705af9f144f39f554') + image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + image_path = archive.extract(image_path_gz, self.workdir) + image_pow2ceil_expand(image_path) + + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw', + '-nic', 'user', + '-no-reboot') + self.vm.launch() + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'usbcore.nousb ' + 'noreboot') + + self.wait_for_console_pattern('U-Boot SPL') + + interrupt_interactive_console_until_pattern( + self, 'Hit any key to stop autoboot:', '=>') + exec_command_and_wait_for_pattern(self, "setenv extraargs '" + + kernel_command_line + "'", '=>') + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...'); + + self.wait_for_console_pattern( + 'Please press Enter to activate this console.') + + exec_command_and_wait_for_pattern(self, ' ', 'root@') + + exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo', + 'Allwinner sun4i/sun5i') + # cubieboard's reboot is not functioning; omit reboot test. + @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') def test_arm_quanta_gsj(self): """ @@ -804,6 +829,8 @@ def test_arm_orangepi_sd(self): :avocado: tags=machine:orangepi-pc :avocado: tags=device:sd """ + self.require_netdev('user') + deb_url = ('https://apt.armbian.com/pool/main/l/' 'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb') deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0' @@ -813,8 +840,8 @@ def test_arm_orangepi_sd(self): dtb_path = '/usr/lib/linux-image-current-sunxi/sun8i-h3-orangepi-pc.dtb' dtb_path = self.extract_from_deb(deb_path, dtb_path) rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/' - 'kci-2019.02/armel/base/rootfs.ext2.xz') - rootfs_hash = '692510cb625efda31640d1de0a8d60e26040f061' + 'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz') + rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a' rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash) rootfs_path = os.path.join(self.workdir, 'rootfs.cpio') archive.lzma_uncompress(rootfs_path_xz, rootfs_path) @@ -1049,8 +1076,8 @@ def test_m68k_q800(self): self.wait_for_console_pattern(console_pattern) def do_test_advcal_2018(self, day, tar_hash, kernel_name, console=0): - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day' + day + '.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day' + day + '.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) self.vm.set_console(console_index=console) @@ -1068,49 +1095,6 @@ def test_arm_vexpressa9(self): self.vm.add_args('-dtb', self.workdir + '/day16/vexpress-v2p-ca9.dtb') self.do_test_advcal_2018('16', tar_hash, 'winter.zImage') - def test_arm_ast2400_palmetto_openbmc_v2_9_0(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:palmetto-bmc - """ - - image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/' - 'obmc-phosphor-image-palmetto.static.mtd') - image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d') - image_path = self.fetch_asset(image_url, asset_hash=image_hash, - algorithm='sha256') - - self.do_test_arm_aspeed(image_path) - - def test_arm_ast2500_romulus_openbmc_v2_9_0(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:romulus-bmc - """ - - image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/' - 'obmc-phosphor-image-romulus.static.mtd') - image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25') - image_path = self.fetch_asset(image_url, asset_hash=image_hash, - algorithm='sha256') - - self.do_test_arm_aspeed(image_path) - - def do_test_arm_aspeed(self, image): - self.vm.set_console() - self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', - '-net', 'nic') - self.vm.launch() - - self.wait_for_console_pattern("U-Boot 2016.07") - self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000") - self.wait_for_console_pattern("Starting kernel ...") - self.wait_for_console_pattern("Booting Linux on physical CPU 0x0") - self.wait_for_console_pattern( - "aspeed-smc 1e620000.spi: read control register: 203b0641") - self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ") - self.wait_for_console_pattern("systemd[1]: Set hostname to") - def test_arm_ast2600_debian(self): """ :avocado: tags=arch:arm @@ -1239,6 +1223,10 @@ def test_ppc_mac99(self): self.vm.add_args('-M', 'graphics=off') self.do_test_advcal_2018('15', tar_hash, 'invaders.elf') + # This test has a 6-10% failure rate on various hosts that look + # like issues with a buggy kernel. As a result we don't want it + # gating releases on Gitlab. + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_sh4_r2d(self): """ :avocado: tags=arch:sh4 diff --git a/tests/avocado/info_usernet.py b/tests/avocado/info_usernet.py index dc01f74150cb..fdc4d90c4208 100644 --- a/tests/avocado/info_usernet.py +++ b/tests/avocado/info_usernet.py @@ -14,8 +14,12 @@ class InfoUsernet(QemuSystemTest): + """ + :avocado: tags=machine:none + """ 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_aarch64_virt.py b/tests/avocado/machine_aarch64_virt.py new file mode 100644 index 000000000000..c2b2ba2cf872 --- /dev/null +++ b/tests/avocado/machine_aarch64_virt.py @@ -0,0 +1,95 @@ +# Functional test that boots a various Linux systems and checks the +# console output. +# +# Copyright (c) 2022 Linaro Ltd. +# +# Author: +# Alex Bennée +# +# SPDX-License-Identifier: GPL-2.0-or-later + +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 BUILD_DIR + +class Aarch64VirtMachine(QemuSystemTest): + KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' + timeout = 360 + + 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) + + # This tests the whole boot chain from EFI to Userspace + # We only boot a whole OS for the current top level CPU and GIC + # Other test profiles should use more minimal boots + def test_alpine_virt_tcg_gic_max(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=accel:tcg + """ + iso_url = ('https://dl-cdn.alpinelinux.org/' + 'alpine/v3.16/releases/aarch64/' + 'alpine-virt-3.16.3-aarch64.iso') + + # Alpine use sha256 so I recalculated this myself + iso_sha1 = '0683bc089486d55c91bf6607d5ecb93925769bc0' + iso_path = self.fetch_asset(iso_url, asset_hash=iso_sha1) + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + self.require_accelerator("tcg") + + self.vm.add_args("-accel", "tcg") + self.vm.add_args("-cpu", "max,pauth-impdef=on") + self.vm.add_args("-machine", + "virt,acpi=on," + "virtualization=on," + "mte=on," + "gic-version=max,iommu=smmuv3") + self.vm.add_args("-smp", "2", "-m", "1024") + self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', + 'edk2-aarch64-code.fd')) + self.vm.add_args("-drive", f"file={iso_path},format=raw") + self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') + self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom') + + self.vm.launch() + self.wait_for_console_pattern('Welcome to Alpine Linux 3.16') + + + def test_aarch64_virt(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=accel:tcg + :avocado: tags=cpu:max + """ + kernel_url = ('https://fileserver.linaro.org/s/' + 'z6B2ARM7DQT3HWN/download') + + kernel_hash = 'ed11daab50c151dde0e1e9c9cb8b2d9bd3215347' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + self.require_accelerator("tcg") + self.vm.add_args('-cpu', 'max,pauth-impdef=on', + '-accel', 'tcg', + '-kernel', kernel_path, + '-append', kernel_command_line) + self.vm.launch() + self.wait_for_console_pattern('Welcome to Buildroot') + time.sleep(0.1) + exec_command(self, 'root') + time.sleep(0.1) + exec_command(self, 'cat /proc/self/maps') + time.sleep(0.1) diff --git a/tests/avocado/machine_arm_canona1100.py b/tests/avocado/machine_arm_canona1100.py index 182a0b051341..a42d8b0f2b02 100644 --- a/tests/avocado/machine_arm_canona1100.py +++ b/tests/avocado/machine_arm_canona1100.py @@ -23,8 +23,8 @@ def test_arm_canona1100(self): :avocado: tags=machine:canon-a1100 :avocado: tags=device:pflash_cfi02 """ - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day18.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day18.tar.xz') tar_hash = '068b5fc4242b29381acee94713509f8a876e9db6' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py new file mode 100644 index 000000000000..1fc385e1c8bb --- /dev/null +++ b/tests/avocado/machine_aspeed.py @@ -0,0 +1,272 @@ +# Functional test that boots the ASPEED SoCs with firmware +# +# Copyright (C) 2022 ASPEED Technology 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. + +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_qemu import interrupt_interactive_console_until_pattern +from avocado.utils import archive +from avocado import skipIf + + +class AST1030Machine(QemuSystemTest): + """Boots the zephyr os and checks that the console is operational""" + + timeout = 10 + + def test_ast1030_zephyros(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:ast1030-evb + """ + tar_url = ('https://github.com/AspeedTech-BMC' + '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip') + tar_hash = '4c6a8ce3a8ba76ef1a65dae419ae3409343c4b20' + tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + archive.extract(tar_path, self.workdir) + kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.elf" + self.vm.set_console() + self.vm.add_args('-kernel', kernel_file, + '-nographic') + self.vm.launch() + wait_for_console_pattern(self, "Booting Zephyr OS") + exec_command_and_wait_for_pattern(self, "help", + "Available commands") + +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', + vm=vm) + + def do_test_arm_aspeed(self, image): + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic') + self.vm.launch() + + self.wait_for_console_pattern("U-Boot 2016.07") + self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000") + self.wait_for_console_pattern("Starting kernel ...") + self.wait_for_console_pattern("Booting Linux on physical CPU 0x0") + wait_for_console_pattern(self, + "aspeed-smc 1e620000.spi: read control register: 203b0641") + self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ") + self.wait_for_console_pattern("systemd[1]: Set hostname to") + + def test_arm_ast2400_palmetto_openbmc_v2_9_0(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:palmetto-bmc + """ + + image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/' + 'obmc-phosphor-image-palmetto.static.mtd') + image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + + self.do_test_arm_aspeed(image_path) + + def test_arm_ast2500_romulus_openbmc_v2_9_0(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:romulus-bmc + """ + + image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/' + 'obmc-phosphor-image-romulus.static.mtd') + image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + + self.do_test_arm_aspeed(image_path) + + def do_test_arm_aspeed_buildroot_start(self, image, cpu_id): + self.require_netdev('user') + + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic', '-net', 'user') + self.vm.launch() + + self.wait_for_console_pattern('U-Boot 2019.04') + self.wait_for_console_pattern('## Loading kernel from FIT Image') + 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) + + def do_test_arm_aspeed_buildroot_poweroff(self): + exec_command_and_wait_for_pattern(self, 'poweroff', + 'reboot: System halted'); + + def test_arm_ast2500_evb_buildroot(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:ast2500-evb + """ + + image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/' + 'images/ast2500-evb/buildroot-2022.05/flash.img') + image_hash = ('549db6e9d8cdaf4367af21c36385a68bb465779c18b5e37094fc7343decccd3f') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test'); + self.do_test_arm_aspeed_buildroot_start(image_path, '0x0') + + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', + 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon1/temp1_input', '0') + self.vm.command('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000') + + self.do_test_arm_aspeed_buildroot_poweroff() + + def test_arm_ast2600_evb_buildroot(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:ast2600-evb + """ + + image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/' + 'images/ast2600-evb/buildroot-2022.05/flash.img') + image_hash = ('6cc9e7d128fd4fa1fd01c883af67593cae8072c3239a0b8b6ace857f3538a92d') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test'); + self.vm.add_args('-device', + 'ds1338,bus=aspeed.i2c.bus.3,address=0x32'); + self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00') + + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', + 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon0/temp1_input', '0') + self.vm.command('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon0/temp1_input', '18000') + + exec_command_and_wait_for_pattern(self, + 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device', + 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32'); + year = time.strftime("%Y") + exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year); + + self.do_test_arm_aspeed_buildroot_poweroff() + + +class AST2x00MachineSDK(QemuSystemTest): + + EXTRA_BOOTARGS = ' quiet' + + # 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): + self.require_netdev('user') + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic', '-net', 'user') + self.vm.launch() + + self.wait_for_console_pattern('U-Boot 2019.04') + interrupt_interactive_console_until_pattern( + self, 'Hit any key to stop autoboot:', 'ast#') + exec_command_and_wait_for_pattern( + self, 'setenv bootargs ${bootargs}' + self.EXTRA_BOOTARGS, 'ast#') + exec_command_and_wait_for_pattern( + self, 'boot', '## Loading kernel from FIT Image') + self.wait_for_console_pattern('Starting kernel ...') + + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') + def test_arm_ast2500_evb_sdk(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:ast2500-evb + """ + + image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/' + 'download/v08.01/ast2500-default-obmc.tar.gz') + image_hash = ('5375f82b4c43a79427909342a1e18b4e48bd663e38466862145d27bb358796fd') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + archive.extract(image_path, self.workdir) + + self.do_test_arm_aspeed_sdk_start( + self.workdir + '/ast2500-default/image-bmc') + 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 + :avocado: tags=machine:ast2600-evb + """ + + image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/' + 'download/v08.01/ast2600-default-obmc.tar.gz') + image_hash = ('f12ef15e8c1f03a214df3b91c814515c5e2b2f56119021398c1dbdd626817d15') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + archive.extract(image_path, self.workdir) + + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test'); + self.vm.add_args('-device', + 'ds1338,bus=aspeed.i2c.bus.5,address=0x32'); + self.do_test_arm_aspeed_sdk_start( + self.workdir + '/ast2600-default/image-bmc') + self.wait_for_console_pattern('ast2600-default login:') + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-default:~#') + + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device', + 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d'); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') + self.vm.command('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') + + exec_command_and_wait_for_pattern(self, + 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device', + 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32'); + year = time.strftime("%Y") + exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year); diff --git a/tests/avocado/machine_microblaze.py b/tests/avocado/machine_microblaze.py index 4928920f960a..8d0efff30d28 100644 --- a/tests/avocado/machine_microblaze.py +++ b/tests/avocado/machine_microblaze.py @@ -19,8 +19,8 @@ def test_microblaze_s3adsp1800(self): :avocado: tags=machine:petalogix-s3adsp1800 """ - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day17.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day17.tar.xz') tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) diff --git a/tests/avocado/machine_s390_ccw_virtio.py b/tests/avocado/machine_s390_ccw_virtio.py index 438a6f4321d0..78152f2ad16b 100644 --- a/tests/avocado/machine_s390_ccw_virtio.py +++ b/tests/avocado/machine_s390_ccw_virtio.py @@ -66,6 +66,7 @@ def test_s390x_devices(self): '-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/machine_sparc64_sun4u.py b/tests/avocado/machine_sparc64_sun4u.py index 458165500ec4..d333c0ae91c3 100644 --- a/tests/avocado/machine_sparc64_sun4u.py +++ b/tests/avocado/machine_sparc64_sun4u.py @@ -24,8 +24,8 @@ def test_sparc64_sun4u(self): :avocado: tags=arch:sparc64 :avocado: tags=machine:sun4u """ - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day23.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day23.tar.xz') tar_hash = '142db83cd974ffadc4f75c8a5cad5bcc5722c240' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py index 584d6ef53f5a..4b25680c50f5 100644 --- a/tests/avocado/migration.py +++ b/tests/avocado/migration.py @@ -14,7 +14,7 @@ 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 @@ def do_migrate(self, dest_uri, src_uri=None): 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/ppc_bamboo.py b/tests/avocado/ppc_bamboo.py index 102ff252dff4..a81be3d60888 100644 --- a/tests/avocado/ppc_bamboo.py +++ b/tests/avocado/ppc_bamboo.py @@ -23,6 +23,7 @@ def test_ppc_bamboo(self): :avocado: tags=accel:tcg """ self.require_accelerator("tcg") + self.require_netdev('user') tar_url = ('http://landley.net/aboriginal/downloads/binaries/' 'system-image-powerpc-440fp.tar.gz') tar_hash = '53e5f16414b195b82d2c70272f81c2eedb39bad9' diff --git a/tests/avocado/ppc_mpc8544ds.py b/tests/avocado/ppc_mpc8544ds.py index 8d6a74920106..b599fb1cc9b8 100644 --- a/tests/avocado/ppc_mpc8544ds.py +++ b/tests/avocado/ppc_mpc8544ds.py @@ -22,9 +22,9 @@ def test_ppc_mpc8544ds(self): :avocado: tags=accel:tcg """ self.require_accelerator("tcg") - tar_url = ('https://www.qemu-advent-calendar.org' - '/2020/download/day17.tar.gz') - tar_hash = '7a5239542a7c4257aa4d3b7f6ddf08fb6775c494' + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day04.tar.xz') + tar_hash = 'f46724d281a9f30fa892d458be7beb7d34dc25f9' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) self.vm.set_console() diff --git a/tests/avocado/ppc_virtex_ml507.py b/tests/avocado/ppc_virtex_ml507.py index 6b07686b565a..a73f8ae396ad 100644 --- a/tests/avocado/ppc_virtex_ml507.py +++ b/tests/avocado/ppc_virtex_ml507.py @@ -22,9 +22,9 @@ def test_ppc_virtex_ml507(self): :avocado: tags=accel:tcg """ self.require_accelerator("tcg") - tar_url = ('https://www.qemu-advent-calendar.org' - '/2020/download/hippo.tar.gz') - tar_hash = '306b95bfe7d147f125aa176a877e266db8ef914a' + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day08.tar.xz') + tar_hash = '74c68f5af7a7b8f21c03097b298f3bb77ff52c1f' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) self.vm.set_console() diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py index 0b2b0dc692b1..00a26e4a0c51 100644 --- a/tests/avocado/replay_kernel.py +++ b/tests/avocado/replay_kernel.py @@ -296,8 +296,8 @@ def test_arm_vexpressa9(self): :avocado: tags=machine:vexpress-a9 """ tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day16.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day16.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) dtb_path = self.workdir + '/day16/vexpress-v2p-ca9.dtb' self.do_test_advcal_2018(file_path, 'winter.zImage', @@ -309,8 +309,8 @@ def test_m68k_mcf5208evb(self): :avocado: tags=machine:mcf5208evb """ tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day07.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day07.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'sanity-clause.elf') @@ -321,8 +321,8 @@ def test_microblaze_s3adsp1800(self): :avocado: tags=machine:petalogix-s3adsp1800 """ tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day17.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day17.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'ballerina.bin') @@ -333,8 +333,8 @@ def test_ppc64_e500(self): :avocado: tags=cpu:e5500 """ tar_hash = '6951d86d644b302898da2fd701739c9406527fe1' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day19.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day19.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'uImage') @@ -344,8 +344,8 @@ def test_or1k_sim(self): :avocado: tags=machine:or1k-sim """ tar_hash = '20334cdaf386108c530ff0badaecc955693027dd' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day20.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day20.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'vmlinux') @@ -355,8 +355,8 @@ def test_nios2_10m50(self): :avocado: tags=machine:10m50-ghrd """ tar_hash = 'e4251141726c412ac0407c5a6bceefbbff018918' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day14.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day14.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'vmlinux.elf') @@ -366,8 +366,8 @@ def test_ppc_g3beige(self): :avocado: tags=machine:g3beige """ tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day15.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day15.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'invaders.elf', args=('-M', 'graphics=off')) @@ -378,8 +378,8 @@ def test_ppc_mac99(self): :avocado: tags=machine:mac99 """ tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day15.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day15.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'invaders.elf', args=('-M', 'graphics=off')) @@ -390,8 +390,8 @@ def test_sparc_ss20(self): :avocado: tags=machine:SS-20 """ tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day11.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day11.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'zImage.elf') @@ -402,8 +402,8 @@ def test_xtensa_lx60(self): :avocado: tags=cpu:dc233c """ tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day02.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day02.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf') diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py index 15953f9e4967..a76dd507fc1c 100644 --- a/tests/avocado/replay_linux.py +++ b/tests/avocado/replay_linux.py @@ -13,6 +13,7 @@ import time from avocado import skipUnless +from avocado_qemu import BUILD_DIR from avocado.utils import cloudinit from avocado.utils import network from avocado.utils import vmimage @@ -32,9 +33,16 @@ class ReplayLinux(LinuxTest): bus = 'ide' def setUp(self): - super(ReplayLinux, self).setUp() + # LinuxTest does many replay-incompatible things, but includes + # useful methods. Do not setup LinuxTest here and just + # call some functions. + super(LinuxTest, self).setUp() + self._set_distro() self.boot_path = self.download_boot() - self.cloudinit_path = self.prepare_cloudinit() + self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0), + self.name) + ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys() + self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey) def vm_add_disk(self, vm, path, id, device): bus_string = '' @@ -47,10 +55,13 @@ def vm_add_disk(self, vm, path, id, device): '%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') - vm.add_args('-object', 'filter-replay,id=replay,netdev=hub0port0') + vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', + '-device', 'virtio-net,netdev=vnet') + vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet') if args: vm.add_args(*args) self.vm_add_disk(vm, self.boot_path, 0, self.hdd) @@ -75,8 +86,8 @@ def launch_and_wait(self, record, args, shift): stop_check=(lambda : not vm.is_running())) console_drainer.start() if record: - cloudinit.wait_for_phone_home(('0.0.0.0', self.phone_home_port), - self.name) + while not self.phone_server.instance_phoned_back: + self.phone_server.handle_request() vm.shutdown() logger.info('finished the recording with log size %s bytes' % os.path.getsize(replay_path)) @@ -114,3 +125,69 @@ def test_pc_q35(self): :avocado: tags=machine:q35 """ self.run_rr(shift=3) + +@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') +class ReplayLinuxX8664Virtio(ReplayLinux): + """ + :avocado: tags=arch:x86_64 + :avocado: tags=virtio + :avocado: tags=accel:tcg + """ + + hdd = 'virtio-blk-pci' + cd = 'virtio-blk-pci' + bus = None + + chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0' + + def test_pc_i440fx(self): + """ + :avocado: tags=machine:pc + """ + self.run_rr(shift=1) + + def test_pc_q35(self): + """ + :avocado: tags=machine:q35 + """ + self.run_rr(shift=3) + +@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') +class ReplayLinuxAarch64(ReplayLinux): + """ + :avocado: tags=accel:tcg + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=cpu:max + """ + + chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49' + + hdd = 'virtio-blk-device' + cd = 'virtio-blk-device' + bus = None + + def get_common_args(self): + return ('-bios', + os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'), + "-cpu", "max,lpa2=off", + '-device', 'virtio-rng-pci,rng=rng0', + '-object', 'rng-builtin,id=rng0') + + def test_virt_gicv2(self): + """ + :avocado: tags=machine:gic-version=2 + """ + + self.run_rr(shift=3, + args=(*self.get_common_args(), + "-machine", "virt,gic-version=2")) + + def test_virt_gicv3(self): + """ + :avocado: tags=machine:gic-version=3 + """ + + self.run_rr(shift=3, + args=(*self.get_common_args(), + "-machine", "virt,gic-version=3")) diff --git a/tests/avocado/virtio_check_params.py b/tests/avocado/virtio_check_params.py index e869690473ad..4093da8a6749 100644 --- a/tests/avocado/virtio_check_params.py +++ b/tests/avocado/virtio_check_params.py @@ -22,7 +22,6 @@ import re import logging -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine from avocado_qemu import QemuSystemTest from avocado import skip diff --git a/tests/avocado/virtio_version.py b/tests/avocado/virtio_version.py index 208910bb844c..c84e48813a19 100644 --- a/tests/avocado/virtio_version.py +++ b/tests/avocado/virtio_version.py @@ -11,7 +11,6 @@ import sys import os -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine from avocado_qemu import QemuSystemTest diff --git a/tests/avocado/vnc.py b/tests/avocado/vnc.py index 096432988fbb..aeeefc70be25 100644 --- a/tests/avocado/vnc.py +++ b/tests/avocado/vnc.py @@ -8,12 +8,52 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. +import socket +from typing import List + from avocado_qemu import QemuSystemTest +VNC_ADDR = '127.0.0.1' +VNC_PORT_START = 32768 +VNC_PORT_END = VNC_PORT_START + 1024 + + +def check_bind(port: int) -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + try: + sock.bind((VNC_ADDR, port)) + except OSError: + return False + + return True + + +def check_connect(port: int) -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + try: + sock.connect((VNC_ADDR, port)) + except ConnectionRefusedError: + return False + + return True + + +def find_free_ports(count: int) -> List[int]: + result = [] + for port in range(VNC_PORT_START, VNC_PORT_END): + if check_bind(port): + result.append(port) + if len(result) >= count: + break + assert len(result) == count + return result + + class Vnc(QemuSystemTest): """ :avocado: tags=vnc,quick + :avocado: tags=machine:none """ def test_no_vnc(self): self.vm.add_args('-nodefaults', '-S') @@ -51,3 +91,27 @@ def test_change_password(self): set_password_response = self.vm.qmp('change-vnc-password', password='new_password') self.assertEqual(set_password_response['return'], {}) + + def test_change_listen(self): + a, b, c = find_free_ports(3) + self.assertFalse(check_connect(a)) + self.assertFalse(check_connect(b)) + self.assertFalse(check_connect(c)) + + self.vm.add_args('-nodefaults', '-S', '-vnc', f'{VNC_ADDR}:{a - 5900}') + self.vm.launch() + self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(a)) + self.assertTrue(check_connect(a)) + self.assertFalse(check_connect(b)) + self.assertFalse(check_connect(c)) + + res = self.vm.qmp('display-update', type='vnc', + addresses=[{'type': 'inet', 'host': VNC_ADDR, + 'port': str(b)}, + {'type': 'inet', 'host': VNC_ADDR, + 'port': str(c)}]) + self.assertEqual(res['return'], {}) + self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(b)) + self.assertFalse(check_connect(a)) + self.assertTrue(check_connect(b)) + self.assertTrue(check_connect(c)) diff --git a/tests/bench/benchmark-crypto-akcipher.c b/tests/bench/benchmark-crypto-akcipher.c new file mode 100644 index 000000000000..5e68cb0a1c4d --- /dev/null +++ b/tests/bench/benchmark-crypto-akcipher.c @@ -0,0 +1,135 @@ +/* + * QEMU Crypto akcipher speed benchmark + * + * Copyright (c) 2022 Bytedance + * + * Authors: + * lei he + * + * 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 "crypto/init.h" +#include "crypto/akcipher.h" +#include "standard-headers/linux/virtio_crypto.h" + +#include "test_akcipher_keys.inc" + +static QCryptoAkCipher *create_rsa_akcipher(const uint8_t *priv_key, + size_t keylen, + QCryptoRSAPaddingAlgorithm padding, + QCryptoHashAlgorithm hash) +{ + QCryptoAkCipherOptions opt; + + opt.alg = QCRYPTO_AKCIPHER_ALG_RSA; + opt.u.rsa.padding_alg = padding; + opt.u.rsa.hash_alg = hash; + return qcrypto_akcipher_new(&opt, QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + priv_key, keylen, &error_abort); +} + +static void test_rsa_speed(const uint8_t *priv_key, size_t keylen, + size_t key_size) +{ +#define BYTE 8 +#define SHA1_DGST_LEN 20 +#define SIGN_TIMES 10000 +#define VERIFY_TIMES 100000 +#define PADDING QCRYPTO_RSA_PADDING_ALG_PKCS1 +#define HASH QCRYPTO_HASH_ALG_SHA1 + + g_autoptr(QCryptoAkCipher) rsa = + create_rsa_akcipher(priv_key, keylen, PADDING, HASH); + g_autofree uint8_t *dgst = NULL; + g_autofree uint8_t *signature = NULL; + size_t count; + + dgst = g_new0(uint8_t, SHA1_DGST_LEN); + memset(dgst, g_test_rand_int(), SHA1_DGST_LEN); + signature = g_new0(uint8_t, key_size / BYTE); + + g_test_message("benchmark rsa%zu (%s-%s) sign...", key_size, + QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH)); + g_test_timer_start(); + for (count = 0; count < SIGN_TIMES; ++count) { + g_assert(qcrypto_akcipher_sign(rsa, dgst, SHA1_DGST_LEN, + signature, key_size / BYTE, + &error_abort) > 0); + } + g_test_timer_elapsed(); + g_test_message("rsa%zu (%s-%s) sign %zu times in %.2f seconds," + " %.2f times/sec ", + key_size, QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH), + count, g_test_timer_last(), + (double)count / g_test_timer_last()); + + g_test_message("benchmark rsa%zu (%s-%s) verification...", key_size, + QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH)); + g_test_timer_start(); + for (count = 0; count < VERIFY_TIMES; ++count) { + g_assert(qcrypto_akcipher_verify(rsa, signature, key_size / BYTE, + dgst, SHA1_DGST_LEN, + &error_abort) == 0); + } + g_test_timer_elapsed(); + g_test_message("rsa%zu (%s-%s) verify %zu times in %.2f seconds," + " %.2f times/sec ", + key_size, QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH), + count, g_test_timer_last(), + (double)count / g_test_timer_last()); +} + +static void test_rsa_1024_speed(const void *opaque) +{ + size_t key_size = (size_t)opaque; + test_rsa_speed(rsa1024_priv_key, sizeof(rsa1024_priv_key), key_size); +} + +static void test_rsa_2048_speed(const void *opaque) +{ + size_t key_size = (size_t)opaque; + test_rsa_speed(rsa2048_priv_key, sizeof(rsa2048_priv_key), key_size); +} + +static void test_rsa_4096_speed(const void *opaque) +{ + size_t key_size = (size_t)opaque; + test_rsa_speed(rsa4096_priv_key, sizeof(rsa4096_priv_key), key_size); +} + +int main(int argc, char **argv) +{ + char *alg = NULL; + char *size = NULL; + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + +#define ADD_TEST(asym_alg, keysize) \ + if ((!alg || g_str_equal(alg, #asym_alg)) && \ + (!size || g_str_equal(size, #keysize))) \ + g_test_add_data_func( \ + "/crypto/akcipher/" #asym_alg "-" #keysize, \ + (void *)keysize, \ + test_ ## asym_alg ## _ ## keysize ## _speed) + + if (argc >= 2) { + alg = argv[1]; + } + if (argc >= 3) { + size = argv[2]; + } + + ADD_TEST(rsa, 1024); + ADD_TEST(rsa, 2048); + ADD_TEST(rsa, 4096); + + return g_test_run(); +} diff --git a/tests/bench/meson.build b/tests/bench/meson.build index 00b3c209dcbd..279a8fcc3390 100644 --- a/tests/bench/meson.build +++ b/tests/bench/meson.build @@ -20,6 +20,7 @@ if have_block 'benchmark-crypto-hash': [crypto], 'benchmark-crypto-hmac': [crypto], 'benchmark-crypto-cipher': [crypto], + 'benchmark-crypto-akcipher': [crypto], } endif diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc new file mode 100644 index 000000000000..df3eccb45ecc --- /dev/null +++ b/tests/bench/test_akcipher_keys.inc @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2022 Bytedance, and/or its affiliates + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Author: lei he + */ + +/* RSA test keys, generated by OpenSSL */ +static const uint8_t rsa1024_priv_key[] = { + 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, + 0x81, 0x81, 0x00, 0xe6, 0x4d, 0x76, 0x4f, 0xb2, + 0x97, 0x09, 0xad, 0x9d, 0x17, 0x33, 0xf2, 0x30, + 0x42, 0x83, 0xa9, 0xcb, 0x49, 0xa4, 0x2e, 0x59, + 0x5e, 0x75, 0x51, 0xd1, 0xac, 0xc8, 0x86, 0x3e, + 0xdb, 0x72, 0x2e, 0xb2, 0xf7, 0xc3, 0x5b, 0xc7, + 0xea, 0xed, 0x30, 0xd1, 0xf7, 0x37, 0xee, 0x9d, + 0x36, 0x59, 0x6f, 0xf8, 0xce, 0xc0, 0x5c, 0x82, + 0x80, 0x37, 0x83, 0xd7, 0x45, 0x6a, 0xe9, 0xea, + 0xc5, 0x3a, 0x59, 0x6b, 0x34, 0x31, 0x44, 0x00, + 0x74, 0xa7, 0x29, 0xab, 0x79, 0x4a, 0xbd, 0xe8, + 0x25, 0x35, 0x01, 0x11, 0x40, 0xbf, 0x31, 0xbd, + 0xd3, 0xe0, 0x68, 0x1e, 0xd5, 0x5b, 0x2f, 0xe9, + 0x20, 0xf2, 0x9f, 0x46, 0x35, 0x30, 0xa8, 0xf1, + 0xfe, 0xef, 0xd8, 0x76, 0x23, 0x46, 0x34, 0x70, + 0xa1, 0xce, 0xc6, 0x65, 0x6d, 0xb0, 0x94, 0x7e, + 0xe5, 0x92, 0x45, 0x7b, 0xaa, 0xbb, 0x95, 0x97, + 0x77, 0xcd, 0xd3, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x30, 0x6a, 0xc4, 0x9e, 0xc8, + 0xba, 0xfc, 0x2b, 0xe5, 0xc4, 0xc5, 0x04, 0xfb, + 0xa4, 0x60, 0x2d, 0xc8, 0x31, 0x39, 0x35, 0x0d, + 0x50, 0xd0, 0x75, 0x5d, 0x11, 0x68, 0x2e, 0xe0, + 0xf4, 0x1d, 0xb3, 0x37, 0xa8, 0xe3, 0x07, 0x5e, + 0xa6, 0x43, 0x2b, 0x6a, 0x59, 0x01, 0x07, 0x47, + 0x41, 0xef, 0xd7, 0x9c, 0x85, 0x4a, 0xe7, 0xa7, + 0xff, 0xf0, 0xab, 0xe5, 0x0c, 0x11, 0x08, 0x10, + 0x75, 0x5a, 0x68, 0xa0, 0x08, 0x03, 0xc9, 0x40, + 0x79, 0x67, 0x1d, 0x65, 0x89, 0x2d, 0x08, 0xf9, + 0xb5, 0x1b, 0x7d, 0xd2, 0x41, 0x3b, 0x33, 0xf2, + 0x47, 0x2f, 0x9c, 0x0b, 0xd5, 0xaf, 0xcb, 0xdb, + 0xbb, 0x37, 0x63, 0x03, 0xf8, 0xe7, 0x2e, 0xc7, + 0x3c, 0x86, 0x9f, 0xc2, 0x9b, 0xb4, 0x70, 0x6a, + 0x4d, 0x7c, 0xe4, 0x1b, 0x3a, 0xa9, 0xae, 0xd7, + 0xce, 0x7f, 0x56, 0xc2, 0x73, 0x5e, 0x58, 0x63, + 0xd5, 0x86, 0x41, 0x02, 0x41, 0x00, 0xf6, 0x56, + 0x69, 0xec, 0xef, 0x65, 0x95, 0xdc, 0x25, 0x47, + 0xe0, 0x6f, 0xb0, 0x4f, 0x79, 0x77, 0x0a, 0x5e, + 0x46, 0xcb, 0xbd, 0x0b, 0x71, 0x51, 0x2a, 0xa4, + 0x65, 0x29, 0x18, 0xc6, 0x30, 0xa0, 0x95, 0x4c, + 0x4b, 0xbe, 0x8c, 0x40, 0xe3, 0x9c, 0x23, 0x02, + 0x14, 0x43, 0xe9, 0x64, 0xea, 0xe3, 0xa8, 0xe2, + 0x1a, 0xd5, 0xf9, 0x5c, 0xe0, 0x36, 0x2c, 0x97, + 0xda, 0xd5, 0xc7, 0x46, 0xce, 0x11, 0x02, 0x41, + 0x00, 0xef, 0x56, 0x08, 0xb8, 0x29, 0xa5, 0xa6, + 0x7c, 0xf7, 0x5f, 0xb4, 0xf5, 0x63, 0xe7, 0xeb, + 0x45, 0xfd, 0x89, 0xaa, 0x94, 0xa6, 0x3d, 0x0b, + 0xd9, 0x04, 0x6f, 0x78, 0xe0, 0xbb, 0xa2, 0xd4, + 0x29, 0x83, 0x17, 0x95, 0x6f, 0x50, 0x3d, 0x40, + 0x5d, 0xe5, 0x24, 0xda, 0xc2, 0x23, 0x50, 0x86, + 0xa8, 0x34, 0xc8, 0x6f, 0xec, 0x7f, 0xb6, 0x45, + 0x3a, 0xdd, 0x78, 0x9b, 0xee, 0xa1, 0xe4, 0x09, + 0xa3, 0x02, 0x40, 0x5c, 0xd6, 0x66, 0x67, 0x58, + 0x35, 0xc5, 0xcb, 0xc8, 0xf5, 0x14, 0xbd, 0xa3, + 0x09, 0xe0, 0xb2, 0x1f, 0x63, 0x36, 0x75, 0x34, + 0x52, 0xea, 0xaa, 0xf7, 0x52, 0x2b, 0x99, 0xd8, + 0x6f, 0x61, 0x06, 0x34, 0x1e, 0x23, 0xf1, 0xb5, + 0x34, 0x03, 0x53, 0xe5, 0xd1, 0xb3, 0xc7, 0x80, + 0x5f, 0x7b, 0x32, 0xbf, 0x84, 0x2f, 0x2e, 0xf3, + 0x22, 0xb0, 0x91, 0x5a, 0x2f, 0x04, 0xd7, 0x4a, + 0x9a, 0x01, 0xb1, 0x02, 0x40, 0x34, 0x0b, 0x26, + 0x4c, 0x3d, 0xaa, 0x2a, 0xc0, 0xe3, 0xdd, 0xe8, + 0xf0, 0xaf, 0x6f, 0xe0, 0x06, 0x51, 0x32, 0x9d, + 0x68, 0x43, 0x99, 0xe4, 0xb8, 0xa5, 0x31, 0x44, + 0x3c, 0xc2, 0x30, 0x8f, 0x28, 0x13, 0xbc, 0x8e, + 0x1f, 0x2d, 0x78, 0x94, 0x45, 0x96, 0xad, 0x63, + 0xf0, 0x71, 0x53, 0x72, 0x64, 0xa3, 0x4d, 0xae, + 0xa0, 0xe3, 0xc8, 0x93, 0xd7, 0x50, 0x0f, 0x89, + 0x00, 0xe4, 0x2d, 0x3d, 0x37, 0x02, 0x41, 0x00, + 0xbe, 0xa6, 0x08, 0xe0, 0xc8, 0x15, 0x2a, 0x47, + 0xcb, 0xd5, 0xec, 0x93, 0xd3, 0xaa, 0x12, 0x82, + 0xaf, 0xac, 0x51, 0x5a, 0x5b, 0xa7, 0x93, 0x4b, + 0xb9, 0xab, 0x00, 0xfa, 0x5a, 0xea, 0x34, 0xe4, + 0x80, 0xf1, 0x44, 0x6a, 0x65, 0xe4, 0x33, 0x99, + 0xfb, 0x54, 0xd7, 0x89, 0x5a, 0x1b, 0xd6, 0x2b, + 0xcc, 0x6e, 0x4b, 0x19, 0xa0, 0x6d, 0x93, 0x9f, + 0xc3, 0x91, 0x7a, 0xa5, 0xd8, 0x59, 0x0e, 0x9e, +}; + +static const uint8_t rsa2048_priv_key[] = { + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xbd, 0x9c, 0x83, 0x6b, + 0x0e, 0x8e, 0xcf, 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, + 0xe3, 0x52, 0x0f, 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, + 0x08, 0x24, 0xba, 0x87, 0x46, 0xfb, 0x28, 0x93, + 0xe5, 0xe5, 0x81, 0x42, 0xc0, 0xf9, 0x17, 0xc7, + 0x81, 0x01, 0xf4, 0x18, 0x6a, 0x17, 0xf5, 0x57, + 0x20, 0x37, 0xcf, 0xf9, 0x74, 0x5e, 0xe1, 0x48, + 0x6a, 0x71, 0x0a, 0x0f, 0x79, 0x72, 0x2b, 0x46, + 0x10, 0x53, 0xdc, 0x14, 0x43, 0xbd, 0xbc, 0x6d, + 0x15, 0x6f, 0x15, 0x4e, 0xf0, 0x0d, 0x89, 0x39, + 0x02, 0xc3, 0x68, 0x5c, 0xa8, 0xfc, 0xed, 0x64, + 0x9d, 0x98, 0xb7, 0xcd, 0x83, 0x66, 0x93, 0xc3, + 0xd9, 0x57, 0xa0, 0x21, 0x93, 0xad, 0x5c, 0x75, + 0x69, 0x88, 0x9e, 0x81, 0xdc, 0x7f, 0x1d, 0xd5, + 0xbd, 0x1c, 0xc1, 0x30, 0x56, 0xa5, 0xda, 0x99, + 0x46, 0xa6, 0x6d, 0x0e, 0x6f, 0x5e, 0x51, 0x34, + 0x49, 0x73, 0xc3, 0x67, 0x49, 0x7e, 0x21, 0x2a, + 0x20, 0xa7, 0x2b, 0x92, 0x73, 0x1d, 0xa5, 0x25, + 0x2a, 0xd0, 0x3a, 0x89, 0x75, 0xb2, 0xbb, 0x19, + 0x37, 0x78, 0x48, 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, + 0xc6, 0x26, 0xca, 0x46, 0x8c, 0xf1, 0x42, 0x2a, + 0x31, 0xb2, 0xfc, 0xe7, 0x55, 0x51, 0xff, 0x07, + 0x13, 0x5b, 0x36, 0x59, 0x2b, 0x43, 0x30, 0x4b, + 0x05, 0x5c, 0xd2, 0x45, 0xa0, 0xa0, 0x7c, 0x17, + 0x5b, 0x07, 0xbb, 0x5d, 0x83, 0x80, 0x92, 0x6d, + 0x87, 0x1a, 0x43, 0xac, 0xc7, 0x6b, 0x8d, 0x11, + 0x60, 0x27, 0xd2, 0xdf, 0xdb, 0x71, 0x02, 0x55, + 0x6e, 0xb5, 0xca, 0x4d, 0xda, 0x59, 0x0d, 0xb8, + 0x8c, 0xcd, 0xd3, 0x0e, 0x55, 0xa0, 0xa4, 0x8d, + 0xa0, 0x14, 0x10, 0x48, 0x42, 0x35, 0x56, 0x08, + 0xf7, 0x29, 0x5f, 0xa2, 0xea, 0xa4, 0x5e, 0x8e, + 0x99, 0x56, 0xaa, 0x5a, 0x8c, 0x23, 0x8f, 0x35, + 0x22, 0x8a, 0xff, 0xed, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x01, 0x00, 0x4e, 0x4a, 0xf3, + 0x44, 0xe0, 0x64, 0xfd, 0xe1, 0xde, 0x33, 0x1e, + 0xd1, 0xf1, 0x8f, 0x6f, 0xe0, 0xa2, 0xfa, 0x08, + 0x60, 0xe1, 0xc6, 0xf0, 0xb2, 0x6d, 0x0f, 0xc6, + 0x28, 0x93, 0xb4, 0x19, 0x94, 0xab, 0xc3, 0xef, + 0x1a, 0xb4, 0xdd, 0x4e, 0xa2, 0x4a, 0x24, 0x8c, + 0x6c, 0xa6, 0x64, 0x05, 0x5f, 0x56, 0xba, 0xda, + 0xc1, 0x21, 0x1a, 0x7d, 0xf1, 0xf7, 0xce, 0xb9, + 0xa9, 0x9b, 0x92, 0x54, 0xfc, 0x95, 0x20, 0x22, + 0x4e, 0xd4, 0x9b, 0xe2, 0xab, 0x8e, 0x99, 0xb8, + 0x40, 0xaf, 0x30, 0x6a, 0xc6, 0x60, 0x0c, 0xd8, + 0x25, 0x44, 0xa1, 0xcb, 0xbb, 0x73, 0x77, 0x86, + 0xaa, 0x46, 0xf3, 0x54, 0xae, 0xa8, 0xa0, 0xdb, + 0xdd, 0xab, 0x6e, 0xfb, 0x2c, 0x5a, 0x14, 0xaf, + 0x08, 0x13, 0xa7, 0x6c, 0xe9, 0xfd, 0xcd, 0x4c, + 0x1f, 0x20, 0x3a, 0x16, 0x2b, 0xf0, 0xb6, 0x7c, + 0x47, 0x5f, 0xd1, 0x0a, 0x2c, 0xc4, 0xa5, 0x68, + 0xd0, 0x43, 0x75, 0x6b, 0x65, 0xaa, 0x32, 0xc6, + 0x99, 0x06, 0xcb, 0x8f, 0xe6, 0x8d, 0xce, 0xbf, + 0x4d, 0x0d, 0x7b, 0x22, 0x2a, 0x8a, 0xcb, 0x7d, + 0x7f, 0x16, 0x48, 0x85, 0xf1, 0x86, 0xcb, 0x54, + 0xb9, 0x39, 0xd4, 0xbc, 0xe3, 0x2d, 0x27, 0x59, + 0xf6, 0x81, 0x5e, 0x94, 0x45, 0xdf, 0xb9, 0x22, + 0xaf, 0x64, 0x0d, 0x14, 0xec, 0x8c, 0xeb, 0x71, + 0xac, 0xee, 0x09, 0x4c, 0xbf, 0x34, 0xf9, 0xf4, + 0x66, 0x77, 0x36, 0x3b, 0x41, 0x74, 0x01, 0x4f, + 0xfc, 0x56, 0x83, 0xba, 0x14, 0xb0, 0x2f, 0xdd, + 0x4d, 0xb9, 0x3f, 0xdf, 0x71, 0xbe, 0x7b, 0xba, + 0x66, 0xc8, 0xc5, 0x42, 0xc9, 0xba, 0x18, 0x63, + 0x45, 0x07, 0x2f, 0x84, 0x3e, 0xc3, 0xfb, 0x47, + 0xda, 0xd4, 0x1d, 0x0e, 0x9d, 0x96, 0xc0, 0xea, + 0xee, 0x45, 0x2f, 0xe1, 0x62, 0x23, 0xee, 0xef, + 0x3d, 0x5e, 0x55, 0xa1, 0x0d, 0x02, 0x81, 0x81, + 0x00, 0xeb, 0x76, 0x88, 0xd3, 0xae, 0x3f, 0x1d, + 0xf2, 0x49, 0xe0, 0x37, 0x49, 0x83, 0x82, 0x6c, + 0xf7, 0xf1, 0x17, 0x30, 0x75, 0x2e, 0x89, 0x06, + 0x88, 0x56, 0x32, 0xf6, 0xfa, 0x58, 0xcb, 0x3c, + 0x98, 0x67, 0xc3, 0xde, 0x10, 0x82, 0xe5, 0xfa, + 0xfa, 0x52, 0x47, 0x8d, 0xd7, 0x00, 0xc6, 0xcb, + 0xf7, 0xf6, 0x57, 0x9b, 0x6e, 0x0c, 0xac, 0xe8, + 0x3b, 0xd1, 0xde, 0xb5, 0x34, 0xaf, 0x8b, 0x2a, + 0xb0, 0x2d, 0x01, 0xeb, 0x7c, 0xa0, 0x42, 0x26, + 0xbb, 0x2b, 0x43, 0x0e, 0x1d, 0xe2, 0x4e, 0xc9, + 0xc1, 0x0a, 0x67, 0x1d, 0xfc, 0x83, 0x25, 0xce, + 0xb2, 0x18, 0xd9, 0x0d, 0x70, 0xf5, 0xa3, 0x5a, + 0x9c, 0x99, 0xdd, 0x47, 0xa1, 0x57, 0xe7, 0x20, + 0xde, 0xa1, 0x29, 0x8d, 0x96, 0x62, 0xf9, 0x26, + 0x95, 0x51, 0xa6, 0xe7, 0x09, 0x8b, 0xba, 0x16, + 0x8b, 0x19, 0x5b, 0xf9, 0x27, 0x0d, 0xc5, 0xd6, + 0x5f, 0x02, 0x81, 0x81, 0x00, 0xce, 0x26, 0x31, + 0xb5, 0x43, 0x53, 0x95, 0x39, 0xdd, 0x01, 0x98, + 0x8b, 0x3d, 0x27, 0xeb, 0x0b, 0x87, 0x1c, 0x95, + 0xfc, 0x3e, 0x36, 0x51, 0x31, 0xb5, 0xea, 0x59, + 0x56, 0xc0, 0x97, 0x62, 0xf0, 0x63, 0x2b, 0xb6, + 0x30, 0x9b, 0xdf, 0x19, 0x10, 0xe9, 0xa0, 0x3d, + 0xea, 0x54, 0x5a, 0xe6, 0xc6, 0x9e, 0x7e, 0xb5, + 0xf0, 0xb0, 0x54, 0xef, 0xc3, 0xe1, 0x47, 0xa6, + 0x95, 0xc7, 0xe4, 0xa3, 0x4a, 0x30, 0x68, 0x24, + 0x98, 0x7d, 0xc1, 0x34, 0xa9, 0xcb, 0xbc, 0x3c, + 0x08, 0x9c, 0x7d, 0x0c, 0xa2, 0xb7, 0x60, 0xaa, + 0x38, 0x08, 0x16, 0xa6, 0x7f, 0xdb, 0xd2, 0xb1, + 0x67, 0xe7, 0x93, 0x8e, 0xbb, 0x7e, 0xb9, 0xb5, + 0xd0, 0xd0, 0x9f, 0x7b, 0xcc, 0x46, 0xe6, 0x74, + 0x78, 0x1a, 0x96, 0xd6, 0xd7, 0x74, 0x34, 0x54, + 0x3b, 0x54, 0x55, 0x7f, 0x89, 0x81, 0xbc, 0x40, + 0x55, 0x87, 0x24, 0x95, 0x33, 0x02, 0x81, 0x81, + 0x00, 0xb0, 0x18, 0x5d, 0x2a, 0x1a, 0x95, 0x9f, + 0x9a, 0xd5, 0x3f, 0x37, 0x79, 0xe6, 0x3d, 0x83, + 0xab, 0x46, 0x86, 0x36, 0x3a, 0x5d, 0x0c, 0x23, + 0x73, 0x91, 0x2b, 0xda, 0x63, 0xce, 0x46, 0x68, + 0xd1, 0xfe, 0x40, 0x90, 0xf2, 0x3e, 0x43, 0x2b, + 0x19, 0x4c, 0xb1, 0xb0, 0xd5, 0x8c, 0x02, 0x21, + 0x07, 0x18, 0x17, 0xda, 0xe9, 0x49, 0xd7, 0x82, + 0x73, 0x42, 0x78, 0xd1, 0x82, 0x4e, 0x8a, 0xc0, + 0xe9, 0x33, 0x2f, 0xcd, 0x62, 0xce, 0x23, 0xca, + 0xfd, 0x8d, 0xd4, 0x3f, 0x59, 0x80, 0x27, 0xb6, + 0x61, 0x85, 0x9b, 0x2a, 0xe4, 0xef, 0x5c, 0x36, + 0x22, 0x21, 0xcd, 0x2a, 0x6d, 0x41, 0x77, 0xe2, + 0xcb, 0x5d, 0x93, 0x0d, 0x00, 0x10, 0x52, 0x8d, + 0xd5, 0x92, 0x28, 0x16, 0x78, 0xd3, 0x1a, 0x4c, + 0x8d, 0xbd, 0x9c, 0x1a, 0x0b, 0x9c, 0x91, 0x16, + 0x4c, 0xff, 0x31, 0x36, 0xbb, 0xcb, 0x64, 0x1a, + 0xf7, 0x02, 0x81, 0x80, 0x32, 0x65, 0x09, 0xdf, + 0xca, 0xee, 0xa2, 0xdb, 0x3b, 0x58, 0xc9, 0x86, + 0xb8, 0x53, 0x8a, 0xd5, 0x0d, 0x99, 0x82, 0x5c, + 0xe0, 0x84, 0x7c, 0xc2, 0xcf, 0x3a, 0xd3, 0xce, + 0x2e, 0x54, 0x93, 0xbe, 0x3a, 0x30, 0x14, 0x60, + 0xbb, 0xaa, 0x05, 0x41, 0xaa, 0x2b, 0x1f, 0x17, + 0xaa, 0xb9, 0x72, 0x12, 0xf9, 0xe9, 0xf5, 0xe6, + 0x39, 0xe4, 0xf9, 0x9c, 0x03, 0xf5, 0x75, 0x16, + 0xc6, 0x7f, 0xf1, 0x1f, 0x10, 0xc8, 0x54, 0xb1, + 0xe6, 0x84, 0x15, 0xb0, 0xb0, 0x7a, 0x7a, 0x9e, + 0x8c, 0x4a, 0xd1, 0x8c, 0xf1, 0x91, 0x32, 0xeb, + 0x71, 0xa6, 0xbf, 0xdb, 0x1f, 0xcc, 0xd8, 0xcb, + 0x92, 0xc3, 0xf2, 0xaf, 0x89, 0x22, 0x32, 0xfd, + 0x32, 0x12, 0xda, 0xbb, 0xac, 0x55, 0x68, 0x01, + 0x78, 0x56, 0x89, 0x7c, 0xb0, 0x0e, 0x9e, 0xcc, + 0xc6, 0x28, 0x04, 0x7e, 0x83, 0xf5, 0x96, 0x30, + 0x92, 0x51, 0xf2, 0x1b, 0x02, 0x81, 0x81, 0x00, + 0x83, 0x6d, 0xd1, 0x98, 0x90, 0x41, 0x8c, 0xa7, + 0x92, 0x83, 0xac, 0x89, 0x05, 0x0c, 0x79, 0x67, + 0x90, 0xb6, 0xa1, 0xf3, 0x2f, 0xca, 0xf0, 0x15, + 0xe0, 0x30, 0x58, 0xe9, 0x4f, 0xcb, 0x4c, 0x56, + 0x56, 0x56, 0x14, 0x3f, 0x1b, 0x79, 0xb6, 0xef, + 0x57, 0x4b, 0x28, 0xbd, 0xb0, 0xe6, 0x0c, 0x49, + 0x4b, 0xbe, 0xe1, 0x57, 0x28, 0x2a, 0x23, 0x5e, + 0xc4, 0xa2, 0x19, 0x4b, 0x00, 0x67, 0x78, 0xd9, + 0x26, 0x6e, 0x17, 0x25, 0xce, 0xe4, 0xfd, 0xde, + 0x86, 0xa8, 0x5a, 0x67, 0x47, 0x6b, 0x15, 0x09, + 0xe1, 0xec, 0x8e, 0x62, 0x98, 0x91, 0x6f, 0xc0, + 0x98, 0x0c, 0x70, 0x0e, 0x7d, 0xbe, 0x63, 0xbd, + 0x12, 0x5a, 0x98, 0x1c, 0xe3, 0x0c, 0xfb, 0xc7, + 0xfb, 0x1b, 0xbd, 0x02, 0x87, 0xcc, 0x0c, 0xbb, + 0xc2, 0xd4, 0xb6, 0xc1, 0xa1, 0x23, 0xd3, 0x1e, + 0x21, 0x6f, 0x48, 0xba, 0x0e, 0x2e, 0xc7, 0x42 +}; + +static const uint8_t rsa4096_priv_key[] = { + 0x30, 0x82, 0x09, 0x29, 0x02, 0x01, 0x00, 0x02, + 0x82, 0x02, 0x01, 0x00, 0xcc, 0x30, 0xc6, 0x90, + 0x49, 0x2b, 0x86, 0xe7, 0x7a, 0xa5, 0x7a, 0x9a, + 0x4f, 0xee, 0x0e, 0xa1, 0x5c, 0x43, 0x64, 0xd0, + 0x76, 0xe1, 0xfd, 0x0b, 0xfd, 0x43, 0x7a, 0x65, + 0xe6, 0x20, 0xbd, 0xf2, 0x0e, 0xbe, 0x76, 0x54, + 0xae, 0x37, 0xbe, 0xa0, 0x02, 0x96, 0xae, 0x8d, + 0x8a, 0xae, 0x3b, 0x88, 0xbb, 0x67, 0xce, 0x7c, + 0x20, 0xbf, 0x14, 0xc3, 0x71, 0x51, 0x87, 0x03, + 0x34, 0xaa, 0x3c, 0x09, 0xff, 0xe9, 0xeb, 0xb7, + 0x85, 0x5c, 0xbb, 0x8d, 0xce, 0x8e, 0x3f, 0xd1, + 0x16, 0x30, 0x00, 0x32, 0x2f, 0x25, 0x8d, 0xef, + 0x71, 0xd9, 0xea, 0x6b, 0x45, 0x53, 0x49, 0xc3, + 0x09, 0x4f, 0xb0, 0xa8, 0xa5, 0x89, 0x76, 0x59, + 0x31, 0xa5, 0xf1, 0x5c, 0x42, 0x54, 0x57, 0x70, + 0x57, 0xad, 0xd8, 0xeb, 0x89, 0xa6, 0x87, 0xa2, + 0x6c, 0x95, 0x58, 0x8f, 0xb6, 0x82, 0xc7, 0xde, + 0xc2, 0x3a, 0xdc, 0x5b, 0xe8, 0x02, 0xcc, 0x26, + 0x4b, 0x01, 0xaa, 0xe6, 0xf3, 0x66, 0x4d, 0x90, + 0x85, 0xde, 0xf4, 0x5d, 0x80, 0x98, 0xc6, 0x65, + 0xcf, 0x44, 0x4c, 0xde, 0xb5, 0x4a, 0xfc, 0xda, + 0x0a, 0x0a, 0x10, 0x26, 0xa3, 0xcb, 0x9d, 0xe4, + 0x8d, 0xab, 0x2c, 0x04, 0xfd, 0xaa, 0xfc, 0x3b, + 0xac, 0x4e, 0x56, 0xb8, 0x4c, 0x9f, 0x22, 0x49, + 0xcb, 0x76, 0x45, 0x24, 0x36, 0x2d, 0xbb, 0xe6, + 0x7e, 0xa9, 0x93, 0x13, 0x96, 0x1e, 0xfc, 0x4b, + 0x75, 0xd4, 0x54, 0xc8, 0x8c, 0x55, 0xe6, 0x3f, + 0x09, 0x5a, 0x03, 0x74, 0x7c, 0x8a, 0xc8, 0xe7, + 0x49, 0x0b, 0x86, 0x7c, 0x97, 0xa0, 0xf2, 0x0d, + 0xf1, 0x5c, 0x0e, 0x7a, 0xc0, 0x3f, 0x78, 0x2d, + 0x9b, 0xe2, 0x26, 0xa0, 0x89, 0x49, 0x0c, 0xad, + 0x79, 0xa6, 0x82, 0x98, 0xa6, 0xb7, 0x74, 0xb4, + 0x45, 0xc8, 0xed, 0xea, 0x81, 0xcd, 0xf0, 0x3b, + 0x8e, 0x24, 0xfb, 0x0c, 0xd0, 0x3a, 0x14, 0xb9, + 0xb4, 0x3b, 0x69, 0xd9, 0xf2, 0x42, 0x6e, 0x7f, + 0x6f, 0x5e, 0xb1, 0x52, 0x5b, 0xaa, 0xef, 0xae, + 0x1e, 0x34, 0xca, 0xed, 0x0a, 0x8d, 0x56, 0xd6, + 0xdd, 0xd4, 0x2c, 0x54, 0x7a, 0x57, 0xca, 0x7e, + 0x4a, 0x11, 0xde, 0x48, 0xdf, 0x2b, 0x09, 0x97, + 0x39, 0x24, 0xce, 0x45, 0xe0, 0x75, 0xb1, 0x19, + 0x42, 0xdb, 0x63, 0x40, 0x9b, 0xb9, 0x95, 0x96, + 0x78, 0x91, 0xd5, 0x19, 0x12, 0xab, 0xef, 0x55, + 0x6f, 0x0d, 0x65, 0xc0, 0x8f, 0x62, 0x99, 0x78, + 0xc0, 0xe0, 0xe1, 0x33, 0xc7, 0x68, 0xff, 0x29, + 0x66, 0x22, 0x3a, 0x6f, 0xa0, 0xf8, 0x5c, 0x68, + 0x9b, 0xa9, 0x05, 0xad, 0x6b, 0x1d, 0xae, 0xc1, + 0x30, 0xbb, 0xfe, 0xb7, 0x31, 0x85, 0x0d, 0xd1, + 0xd5, 0xfc, 0x43, 0x1e, 0xb3, 0x61, 0x6f, 0xc4, + 0x75, 0xed, 0x76, 0x9d, 0x13, 0xb3, 0x61, 0x57, + 0xc8, 0x33, 0x0d, 0x77, 0x84, 0xf0, 0xc7, 0x62, + 0xb9, 0x9e, 0xd5, 0x01, 0xfa, 0x87, 0x4a, 0xf5, + 0xd7, 0x4f, 0x5d, 0xae, 0xe7, 0x08, 0xd2, 0x5a, + 0x65, 0x30, 0xc9, 0xf0, 0x0a, 0x11, 0xf1, 0x2a, + 0xd3, 0x43, 0x43, 0xca, 0x05, 0x90, 0x85, 0xf4, + 0xbc, 0x37, 0x49, 0x40, 0x45, 0x35, 0xd3, 0x56, + 0x06, 0x4c, 0x63, 0x93, 0x07, 0x14, 0x8b, 0xd3, + 0x12, 0xd0, 0xe5, 0x00, 0x48, 0x76, 0xd2, 0xdf, + 0x7c, 0xea, 0xc7, 0xff, 0xf0, 0x88, 0xd5, 0xa4, + 0x61, 0x7d, 0x79, 0xc2, 0xda, 0x53, 0x24, 0xdc, + 0x20, 0xae, 0xe6, 0x08, 0x65, 0xef, 0xc9, 0x0d, + 0x7d, 0x66, 0x6d, 0x1b, 0x1c, 0x5d, 0x46, 0xe1, + 0x26, 0x8a, 0x29, 0x77, 0x76, 0x19, 0xe5, 0x19, + 0x2a, 0x75, 0x21, 0xf1, 0x92, 0x8a, 0x9c, 0x7b, + 0xe8, 0x0b, 0x38, 0xc1, 0xbf, 0x76, 0x22, 0x45, + 0x4a, 0xd3, 0x43, 0xc3, 0x8c, 0x74, 0xd8, 0xd8, + 0xec, 0x3e, 0x14, 0xdf, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x02, 0x01, 0x00, 0x9e, 0x13, + 0x64, 0xa5, 0x6e, 0xff, 0xf3, 0x80, 0x60, 0xc2, + 0x9b, 0x17, 0xbb, 0xa9, 0x60, 0x4a, 0x2b, 0x53, + 0x41, 0x48, 0xe1, 0xc0, 0x32, 0x56, 0x85, 0xcb, + 0x27, 0x86, 0x9b, 0x91, 0xdd, 0x7a, 0xf7, 0x4f, + 0x1b, 0xec, 0x92, 0xb3, 0x35, 0x30, 0x4a, 0xd0, + 0xbc, 0x71, 0x77, 0x5b, 0x4b, 0x5b, 0x9f, 0x39, + 0xcd, 0xf0, 0xea, 0xa9, 0x03, 0x3a, 0x0b, 0x10, + 0x42, 0xa5, 0x88, 0xb0, 0x01, 0xaa, 0xfc, 0x23, + 0xec, 0x08, 0x37, 0x86, 0x82, 0xec, 0x55, 0x6c, + 0x6a, 0x9b, 0x43, 0xc2, 0x05, 0x64, 0xd4, 0x7b, + 0x0e, 0x56, 0xc0, 0x9d, 0x23, 0x8d, 0xc8, 0x2d, + 0xa2, 0x7d, 0x0b, 0x48, 0x56, 0x4b, 0x39, 0x5c, + 0x21, 0xf3, 0x0b, 0x2c, 0x9c, 0x9d, 0xff, 0xfb, + 0xab, 0x75, 0x9d, 0x6b, 0x48, 0xf3, 0x8f, 0xad, + 0x0c, 0x74, 0x01, 0xfb, 0xdc, 0x83, 0xe5, 0x97, + 0x79, 0x84, 0x4a, 0x79, 0xa6, 0xfe, 0xbf, 0xae, + 0xea, 0xbc, 0xfa, 0x74, 0x60, 0x0a, 0x4b, 0x84, + 0x77, 0xa7, 0xda, 0xfb, 0xaf, 0xd2, 0x73, 0x2b, + 0xd2, 0xec, 0x1e, 0x79, 0x91, 0xc9, 0x18, 0x30, + 0xe5, 0x6f, 0x27, 0x36, 0x83, 0x2a, 0x66, 0xc3, + 0xcb, 0x88, 0x94, 0xe4, 0x5f, 0x3f, 0xbd, 0xe2, + 0x11, 0x43, 0x61, 0x31, 0x84, 0x91, 0x49, 0x40, + 0x29, 0x1b, 0x58, 0x18, 0x47, 0x8e, 0xb1, 0x22, + 0xd6, 0xc4, 0xaa, 0x6a, 0x3d, 0x22, 0x7c, 0xa5, + 0xa0, 0x4c, 0x0a, 0xfc, 0x46, 0x66, 0xbb, 0xbe, + 0x04, 0x71, 0xe8, 0x9b, 0x76, 0xf1, 0x47, 0x39, + 0x6a, 0x2f, 0x23, 0xad, 0x78, 0x80, 0x1c, 0x22, + 0xcd, 0x41, 0x5e, 0x09, 0x16, 0x6c, 0x91, 0x48, + 0x91, 0x91, 0x3d, 0x8c, 0xe6, 0xba, 0x81, 0x8d, + 0xbb, 0xf2, 0xd0, 0xaa, 0xc7, 0x8f, 0xc6, 0x01, + 0x60, 0xa7, 0xef, 0x1e, 0x8e, 0x91, 0x6d, 0xcc, + 0x30, 0x9e, 0xea, 0x7c, 0x56, 0x9d, 0x42, 0xcf, + 0x44, 0x85, 0x52, 0xa8, 0xf2, 0x36, 0x9c, 0x46, + 0xfa, 0x9d, 0xd3, 0x4e, 0x13, 0x46, 0x81, 0xce, + 0x99, 0xc9, 0x58, 0x47, 0xe4, 0xeb, 0x27, 0x56, + 0x29, 0x61, 0x0f, 0xb5, 0xcb, 0xf3, 0x48, 0x58, + 0x8f, 0xbc, 0xaf, 0x0a, 0xbf, 0x40, 0xd1, 0xf6, + 0x4f, 0xd2, 0x89, 0x4a, 0xff, 0x6f, 0x54, 0x70, + 0x49, 0x42, 0xf6, 0xf8, 0x0e, 0x4f, 0xa5, 0xf6, + 0x8b, 0x49, 0x80, 0xd4, 0xf5, 0x03, 0xf8, 0x65, + 0xe7, 0x1f, 0x0a, 0xc0, 0x8f, 0xd3, 0x7a, 0x70, + 0xca, 0x67, 0xaf, 0x71, 0xfd, 0x4b, 0xe1, 0x17, + 0x76, 0x74, 0x2e, 0x12, 0x7b, 0xad, 0x4b, 0xbb, + 0xd2, 0x64, 0xd0, 0xa9, 0xf9, 0x79, 0xa9, 0xa6, + 0x03, 0xd2, 0xc2, 0x8f, 0x47, 0x59, 0x1b, 0x7c, + 0xe3, 0xce, 0x92, 0xb2, 0xac, 0x3e, 0xee, 0x12, + 0x43, 0x5f, 0x23, 0xec, 0xf1, 0xd3, 0xf2, 0x21, + 0x22, 0xe8, 0x7e, 0x7f, 0xa4, 0x93, 0x8e, 0x78, + 0x69, 0x69, 0xa0, 0xc9, 0xce, 0x86, 0x36, 0x13, + 0x10, 0x21, 0xc4, 0x7a, 0x52, 0xcf, 0x53, 0xd9, + 0x9b, 0x58, 0xe6, 0x2d, 0xeb, 0x60, 0xe3, 0x75, + 0x1a, 0x22, 0xf6, 0x3c, 0x54, 0x6b, 0xfa, 0xa1, + 0x5d, 0xf6, 0x38, 0xf0, 0xd4, 0x26, 0x2d, 0x7d, + 0x74, 0x99, 0x6a, 0x13, 0x8a, 0x07, 0x9f, 0x07, + 0xc5, 0xf4, 0xa8, 0x20, 0x11, 0xa9, 0x76, 0x11, + 0xe4, 0x48, 0xae, 0xa4, 0x8a, 0xa1, 0xbf, 0x1f, + 0xba, 0x37, 0x50, 0x53, 0x43, 0x91, 0x45, 0x88, + 0x03, 0x52, 0xba, 0xac, 0xc8, 0xe3, 0xe1, 0xba, + 0x63, 0x24, 0x72, 0xbe, 0x1d, 0x01, 0x1f, 0x6c, + 0x34, 0x10, 0xb8, 0x56, 0x4a, 0x67, 0x28, 0x4b, + 0x7a, 0x2b, 0x31, 0x29, 0x47, 0xda, 0xdf, 0x53, + 0x88, 0x79, 0x22, 0x31, 0x15, 0x56, 0xe3, 0xa0, + 0x79, 0x75, 0x94, 0x90, 0xb2, 0xe8, 0x4b, 0xca, + 0x82, 0x6d, 0x3c, 0x69, 0x43, 0x01, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xe7, 0x8b, 0xd6, 0x1a, 0xe8, + 0x00, 0xed, 0x9d, 0x7c, 0x5a, 0x32, 0x10, 0xc1, + 0x53, 0x50, 0xbe, 0x27, 0x1d, 0xef, 0x69, 0x73, + 0xa2, 0x8f, 0x95, 0x96, 0x86, 0xfe, 0xfb, 0x82, + 0xdb, 0xea, 0x7d, 0x73, 0x5a, 0x2b, 0xe7, 0x4b, + 0xd5, 0x8f, 0x4f, 0xaf, 0x85, 0x1d, 0x15, 0x1a, + 0x58, 0x5f, 0x41, 0x79, 0x70, 0x5c, 0x8f, 0xa9, + 0x8e, 0x23, 0x31, 0xa7, 0x6d, 0x99, 0x0c, 0xf0, + 0x51, 0xbf, 0xbb, 0xd3, 0xe3, 0xa3, 0x34, 0xf0, + 0x1d, 0x7f, 0x4a, 0xb7, 0x8f, 0xf6, 0x0a, 0x49, + 0x65, 0xaf, 0x35, 0x7b, 0x02, 0x2e, 0x69, 0x49, + 0x95, 0xb5, 0x20, 0x70, 0xb2, 0x98, 0x54, 0x9b, + 0x8e, 0x4f, 0x48, 0xa8, 0xfa, 0x7e, 0xc7, 0x0a, + 0xae, 0x84, 0xe1, 0xba, 0x85, 0x98, 0x96, 0x8a, + 0x7c, 0xdd, 0xcc, 0xcd, 0xd8, 0x5b, 0x50, 0x60, + 0x88, 0x2d, 0xb6, 0x3e, 0xb8, 0xc2, 0xae, 0xa5, + 0x62, 0x10, 0xcd, 0xdc, 0xae, 0x86, 0xfe, 0x31, + 0x8b, 0xf7, 0xee, 0x1a, 0x35, 0x46, 0x83, 0xee, + 0x5f, 0x55, 0x9a, 0xc2, 0xca, 0x53, 0xb7, 0x2c, + 0xbf, 0x03, 0x8a, 0x78, 0xcc, 0x1d, 0x96, 0x7b, + 0xac, 0x00, 0x62, 0x1e, 0xbd, 0x6f, 0x0b, 0xa5, + 0xec, 0xf3, 0x02, 0x47, 0x47, 0x1e, 0x3d, 0xf6, + 0x78, 0x42, 0xe4, 0xcd, 0xf8, 0x14, 0xa3, 0x7d, + 0xd5, 0x2f, 0x6e, 0xcc, 0x1a, 0x9e, 0xe7, 0xcf, + 0x48, 0xb9, 0x80, 0xb8, 0xba, 0xaa, 0x7b, 0xae, + 0x65, 0x74, 0x09, 0x7b, 0x43, 0x26, 0x31, 0xa2, + 0x95, 0x43, 0x69, 0xd0, 0xb7, 0x95, 0xe4, 0x76, + 0x2c, 0x42, 0x19, 0x47, 0x4f, 0x63, 0x35, 0x9c, + 0xa2, 0x1a, 0xce, 0x28, 0xdf, 0x76, 0x98, 0x1d, + 0xd4, 0x2e, 0xf6, 0x3a, 0xc8, 0x3e, 0xc7, 0xaf, + 0xf7, 0x38, 0x3f, 0x83, 0x3a, 0xcb, 0xae, 0x41, + 0x75, 0x46, 0x63, 0xaa, 0x45, 0xb1, 0x2c, 0xd9, + 0x9f, 0x17, 0x37, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xe1, 0xc1, 0x57, 0x4d, 0x0f, 0xa5, 0xea, 0x1d, + 0x39, 0x9c, 0xe0, 0xf0, 0x6d, 0x13, 0x7f, 0x79, + 0xdc, 0x72, 0x61, 0xc0, 0x7f, 0x88, 0xf6, 0x38, + 0x4f, 0x49, 0x06, 0x1e, 0xb8, 0x6c, 0x21, 0x04, + 0x60, 0x76, 0x5a, 0x6d, 0x04, 0xd1, 0x6d, 0xac, + 0x7c, 0x25, 0x4f, 0x32, 0xcb, 0xbc, 0xf8, 0x4a, + 0x22, 0x8f, 0xf5, 0x41, 0xfd, 0x1c, 0x76, 0x30, + 0xc2, 0x5f, 0x99, 0x13, 0x5c, 0x57, 0x0f, 0xfd, + 0xac, 0x0b, 0x10, 0x9a, 0x4f, 0x78, 0x0a, 0x86, + 0xe8, 0x07, 0x40, 0x40, 0x13, 0xba, 0x96, 0x07, + 0xd5, 0x39, 0x91, 0x51, 0x3e, 0x80, 0xd8, 0xa0, + 0x1f, 0xff, 0xdc, 0x9e, 0x09, 0x3b, 0xae, 0x38, + 0xa9, 0xc2, 0x14, 0x7b, 0xee, 0xd2, 0x69, 0x3d, + 0xd6, 0x26, 0x74, 0x72, 0x7b, 0x86, 0xd4, 0x13, + 0x5b, 0xb8, 0x76, 0x4b, 0x08, 0xfb, 0x93, 0xfa, + 0x44, 0xaf, 0x98, 0x3b, 0xfa, 0xd0, 0x2a, 0x04, + 0x8b, 0xb3, 0x3c, 0x6d, 0x32, 0xf7, 0x18, 0x6a, + 0x51, 0x0e, 0x40, 0x90, 0xce, 0x8e, 0xdf, 0xe8, + 0x07, 0x4c, 0x0f, 0xc7, 0xc8, 0xc2, 0x18, 0x58, + 0x6a, 0x01, 0xc8, 0x27, 0xd6, 0x43, 0x2a, 0xfb, + 0xa5, 0x34, 0x01, 0x3c, 0x72, 0xb1, 0x48, 0xce, + 0x2b, 0x9b, 0xb4, 0x69, 0xd9, 0x82, 0xf8, 0xbe, + 0x29, 0x88, 0x75, 0x96, 0xd8, 0xef, 0x78, 0x2a, + 0x07, 0x90, 0xa0, 0x56, 0x33, 0x42, 0x05, 0x19, + 0xb0, 0x69, 0x34, 0xf9, 0x03, 0xc5, 0xa8, 0x0d, + 0x72, 0xa2, 0x27, 0xb4, 0x45, 0x6d, 0xd2, 0x01, + 0x6c, 0xf1, 0x74, 0x51, 0x0a, 0x9a, 0xe2, 0xc1, + 0x96, 0x80, 0x30, 0x0e, 0xc6, 0xa9, 0x79, 0xf7, + 0x6f, 0xaf, 0xf6, 0xe8, 0x2a, 0xcc, 0xbd, 0xad, + 0x8f, 0xe0, 0x32, 0x87, 0x85, 0x49, 0x68, 0x88, + 0x15, 0x5c, 0xdb, 0x48, 0x40, 0xa2, 0xfa, 0x42, + 0xe8, 0x4e, 0x3e, 0xe2, 0x3f, 0xe0, 0xf3, 0x99, + 0x02, 0x82, 0x01, 0x00, 0x08, 0x39, 0x97, 0x69, + 0x6d, 0x44, 0x5b, 0x2c, 0x74, 0xf6, 0x5f, 0x40, + 0xe9, 0x1d, 0x24, 0x89, 0x1c, 0xaa, 0x9b, 0x8e, + 0x8b, 0x65, 0x02, 0xe4, 0xb5, 0x6c, 0x26, 0x32, + 0x98, 0xfb, 0x66, 0xe0, 0xfd, 0xef, 0xfe, 0x0f, + 0x41, 0x4a, 0x5c, 0xc4, 0xdf, 0xdf, 0x42, 0xa1, + 0x35, 0x46, 0x5e, 0x5b, 0xdd, 0x0c, 0x78, 0xbd, + 0x41, 0xb0, 0xa2, 0xdf, 0x68, 0xab, 0x23, 0xfc, + 0xa9, 0xac, 0xbd, 0xba, 0xd6, 0x54, 0x07, 0xc0, + 0x21, 0xa7, 0x6a, 0x96, 0x24, 0xdf, 0x20, 0x46, + 0x4d, 0x45, 0x27, 0x6c, 0x26, 0xea, 0x74, 0xeb, + 0x98, 0x89, 0x90, 0xdd, 0x8e, 0x23, 0x49, 0xf5, + 0xf7, 0x70, 0x9e, 0xb0, 0x5e, 0x10, 0x47, 0xe0, + 0x9a, 0x28, 0x88, 0xdf, 0xdb, 0xd8, 0x53, 0x0b, + 0x45, 0xf0, 0x19, 0x90, 0xe4, 0xdf, 0x02, 0x9f, + 0x60, 0x4e, 0x76, 0x11, 0x3b, 0x39, 0x24, 0xf1, + 0x3f, 0x3e, 0xb4, 0x8a, 0x1b, 0x84, 0xb7, 0x96, + 0xdf, 0xfb, 0xb0, 0xda, 0xec, 0x63, 0x68, 0x15, + 0xd7, 0xa9, 0xdb, 0x48, 0x9c, 0x12, 0xc3, 0xd6, + 0x85, 0xe8, 0x63, 0x1f, 0xd0, 0x1a, 0xb0, 0x12, + 0x60, 0x62, 0x43, 0xc1, 0x38, 0x86, 0x52, 0x23, + 0x7f, 0xc9, 0x62, 0xf8, 0x79, 0xbf, 0xb4, 0xfb, + 0x4e, 0x7e, 0x07, 0x22, 0x49, 0x8e, 0xbe, 0x6c, + 0xf0, 0x53, 0x5a, 0x53, 0xfd, 0x3c, 0x14, 0xd8, + 0xf7, 0x2c, 0x06, 0x2a, 0xe4, 0x64, 0xfd, 0x19, + 0x57, 0xa0, 0x92, 0xf6, 0xa3, 0x42, 0x47, 0x61, + 0x0b, 0xfd, 0x71, 0x5f, 0x98, 0xe2, 0x6c, 0x98, + 0xa8, 0xf9, 0xf9, 0x7f, 0x1c, 0x61, 0x5d, 0x8c, + 0xd1, 0xfb, 0x90, 0x28, 0x32, 0x9b, 0x7d, 0x82, + 0xf9, 0xcc, 0x47, 0xbe, 0xc7, 0x67, 0xc5, 0x93, + 0x22, 0x55, 0x0d, 0xd2, 0x73, 0xbe, 0xea, 0xed, + 0x4d, 0xb5, 0xf4, 0xc2, 0x25, 0x92, 0x44, 0x30, + 0xeb, 0xaa, 0x13, 0x11, 0x02, 0x82, 0x01, 0x01, + 0x00, 0x82, 0x42, 0x02, 0x53, 0x4e, 0x72, 0x16, + 0xf1, 0x21, 0xea, 0xe8, 0xc7, 0x10, 0xc8, 0xad, + 0x46, 0xec, 0xf1, 0x7a, 0x81, 0x8d, 0x94, 0xc3, + 0x2c, 0x9e, 0x62, 0xae, 0x0b, 0x4f, 0xb1, 0xe4, + 0x23, 0x18, 0x5d, 0x71, 0xb3, 0x71, 0x92, 0x3d, + 0x4b, 0xc6, 0x9d, 0xe8, 0x62, 0x90, 0xb7, 0xca, + 0x33, 0x4c, 0x59, 0xef, 0xd3, 0x51, 0x6d, 0xf8, + 0xac, 0x0d, 0x9b, 0x07, 0x41, 0xea, 0x87, 0xb9, + 0x8c, 0x4e, 0x96, 0x5b, 0xd0, 0x0d, 0x86, 0x5f, + 0xdc, 0x93, 0x48, 0x8b, 0xc3, 0xed, 0x1e, 0x3d, + 0xae, 0xeb, 0x52, 0xba, 0x0c, 0x3c, 0x9a, 0x2f, + 0x63, 0xc4, 0xd2, 0xe6, 0xc2, 0xb0, 0xe5, 0x24, + 0x93, 0x41, 0x2f, 0xe0, 0x8d, 0xd9, 0xb0, 0xc2, + 0x54, 0x91, 0x99, 0xc2, 0x9a, 0xc3, 0xb7, 0x79, + 0xea, 0x69, 0x83, 0xb7, 0x8d, 0x77, 0xf3, 0x60, + 0xe0, 0x88, 0x7d, 0x20, 0xc3, 0x8a, 0xe6, 0x4d, + 0x38, 0x2e, 0x3b, 0x0e, 0xe4, 0x9b, 0x01, 0x83, + 0xae, 0xe4, 0x71, 0xea, 0xc3, 0x22, 0xcb, 0xc1, + 0x59, 0xa9, 0xcc, 0x33, 0x56, 0xbc, 0xf9, 0x70, + 0xfe, 0xa2, 0xbb, 0xc0, 0x77, 0x6b, 0xe3, 0x79, + 0x8b, 0x95, 0x38, 0xba, 0x75, 0xdc, 0x5f, 0x7a, + 0x78, 0xab, 0x24, 0xbe, 0x26, 0x4d, 0x00, 0x8a, + 0xf1, 0x7e, 0x19, 0x64, 0x6f, 0xd3, 0x5f, 0xe8, + 0xdf, 0xa7, 0x59, 0xc5, 0x89, 0xb7, 0x2d, 0xa2, + 0xaf, 0xbd, 0xe0, 0x16, 0x56, 0x8f, 0xdc, 0x9e, + 0x28, 0x94, 0x3a, 0x07, 0xda, 0xb6, 0x2c, 0xb5, + 0x7d, 0x69, 0x14, 0xb0, 0x5e, 0x8a, 0x55, 0xef, + 0xfc, 0x6f, 0x10, 0x2b, 0xaa, 0x7a, 0xea, 0x12, + 0x9b, 0xb8, 0x6f, 0xb9, 0x71, 0x20, 0x30, 0xde, + 0x48, 0xa4, 0xb9, 0x61, 0xae, 0x5c, 0x33, 0x8d, + 0x02, 0xe8, 0x00, 0x99, 0xed, 0xc8, 0x8d, 0xc1, + 0x04, 0x95, 0xf1, 0x7f, 0xcb, 0x1f, 0xbc, 0x76, + 0x11, 0x02, 0x82, 0x01, 0x00, 0x2d, 0x0c, 0xa9, + 0x8f, 0x11, 0xc2, 0xf3, 0x02, 0xc8, 0xf2, 0x55, + 0xc5, 0x6d, 0x25, 0x88, 0xba, 0x59, 0xf6, 0xd1, + 0xdb, 0x94, 0x2f, 0x0b, 0x65, 0x2c, 0xad, 0x54, + 0xe0, 0x2b, 0xe6, 0xa3, 0x49, 0xa2, 0xb3, 0xca, + 0xd7, 0xec, 0x27, 0x32, 0xbb, 0xa4, 0x16, 0x90, + 0xbb, 0x67, 0xad, 0x1b, 0xb9, 0x0f, 0x78, 0xcb, + 0xad, 0x5c, 0xc3, 0x66, 0xd6, 0xbb, 0x97, 0x28, + 0x01, 0x31, 0xf9, 0x0f, 0x71, 0x2a, 0xb9, 0x5b, + 0xea, 0x34, 0x49, 0x9c, 0x6b, 0x13, 0x40, 0x65, + 0xbd, 0x18, 0x0a, 0x14, 0xf9, 0x33, 0x47, 0xe8, + 0x9f, 0x64, 0x0e, 0x24, 0xf6, 0xbb, 0x90, 0x23, + 0x66, 0x01, 0xa6, 0xa4, 0xa9, 0x7f, 0x64, 0x51, + 0xa3, 0x8a, 0x73, 0xc1, 0x80, 0xaf, 0x7a, 0x49, + 0x75, 0x5d, 0x56, 0x1c, 0xaa, 0x3f, 0x64, 0xa9, + 0x96, 0xfd, 0xb0, 0x90, 0xc5, 0xe0, 0x3d, 0x36, + 0x05, 0xad, 0xad, 0x84, 0x93, 0x84, 0xab, 0x1b, + 0x34, 0x57, 0x39, 0xae, 0x0e, 0x80, 0x0f, 0x4a, + 0x9b, 0x32, 0x56, 0xbd, 0x30, 0xeb, 0xd1, 0xc8, + 0xc4, 0x9f, 0x9c, 0x07, 0xb6, 0x05, 0xb1, 0x21, + 0x7f, 0x69, 0x92, 0x9f, 0xb7, 0x68, 0xe7, 0xde, + 0xb7, 0xbc, 0xb4, 0x89, 0x5b, 0x1c, 0x1b, 0x48, + 0xd1, 0x44, 0x6e, 0xd7, 0x6b, 0xe2, 0xa1, 0xf4, + 0xbf, 0x17, 0xb4, 0x43, 0x70, 0x26, 0xd4, 0xb9, + 0xf5, 0x19, 0x09, 0x08, 0xe9, 0xa3, 0x49, 0x7d, + 0x2f, 0xdc, 0xe8, 0x75, 0x79, 0xa1, 0xc1, 0x70, + 0x1b, 0x60, 0x97, 0xaf, 0x0c, 0x56, 0x68, 0xac, + 0x0e, 0x53, 0xbe, 0x56, 0xf4, 0xc3, 0xb1, 0xfb, + 0xfb, 0xff, 0x73, 0x5b, 0xa7, 0xf6, 0x99, 0x0e, + 0x14, 0x5a, 0x5f, 0x9d, 0xbd, 0x8e, 0x94, 0xec, + 0x8b, 0x38, 0x72, 0xbc, 0x8b, 0xca, 0x32, 0xa8, + 0x39, 0x43, 0xb1, 0x1d, 0x43, 0x29, 0xbe, 0x60, + 0xdb, 0x91, 0x6c, 0x9c, 0x06, +}; diff --git a/tests/check-block.sh b/tests/check-block.sh index f59496396c01..5de2c1ba0b30 100755 --- a/tests/check-block.sh +++ b/tests/check-block.sh @@ -18,36 +18,10 @@ skip() { exit 0 } -# Disable tests with any sanitizer except for specific ones -SANITIZE_FLAGS=$( grep "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ) -ALLOWED_SANITIZE_FLAGS="safe-stack cfi-icall" -#Remove all occurrencies of allowed Sanitize flags -for j in ${ALLOWED_SANITIZE_FLAGS}; do - TMP_FLAGS=${SANITIZE_FLAGS} - SANITIZE_FLAGS="" - for i in ${TMP_FLAGS}; do - if ! echo ${i} | grep -q "${j}" 2>/dev/null; then - SANITIZE_FLAGS="${SANITIZE_FLAGS} ${i}" - fi - done -done -if echo ${SANITIZE_FLAGS} | grep -q "\-fsanitize" 2>/dev/null; then - # Have a sanitize flag that is not allowed, stop - skip "Sanitizers are enabled ==> Not running the qemu-iotests." -fi - if [ -z "$(find . -name 'qemu-system-*' -print)" ]; then skip "No qemu-system binary available ==> Not running the qemu-iotests." fi -if ! command -v bash >/dev/null 2>&1 ; then - skip "bash not available ==> Not running the qemu-iotests." -fi - -if LANG=C bash --version | grep -q 'GNU bash, version [123]' ; then - skip "bash version too old ==> Not running the qemu-iotests." -fi - cd tests/qemu-iotests # QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index cc1223773e9c..b688686dc361 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 bb0593eeb873..86259be9d1df 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 2d0678eb8327..e2cc2a6fc987 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 77778c3a6994..75016fd4b72a 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 af046b40b0a1..53eb0dd7d422 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 b56b2e089017..9089d994e032 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 bb0593eeb873..86259be9d1df 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 6ff6f198c7ca..578468f4f00a 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 2e618e49d357..39427103aadb 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 c32d28575b96..987a26333922 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 623f06a900d1..fc7598b76287 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 f0a3fa92de94..85af400cdb5d 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 cee3b4d80b51..545512adfa0f 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/pc/SSDT.dimmpxm b/tests/data/acpi/pc/SSDT.dimmpxm index ac55387d57e4..70f133412f5e 100644 Binary files a/tests/data/acpi/pc/SSDT.dimmpxm and b/tests/data/acpi/pc/SSDT.dimmpxm differ diff --git a/tests/data/acpi/q35/APIC.acpihmat-noinitiator b/tests/data/acpi/q35/APIC.acpihmat-noinitiator new file mode 100644 index 000000000000..d904d4a70dde Binary files /dev/null and b/tests/data/acpi/q35/APIC.acpihmat-noinitiator differ diff --git a/tests/data/acpi/q35/APIC.core-count2 b/tests/data/acpi/q35/APIC.core-count2 new file mode 100644 index 000000000000..a255082ef5bc Binary files /dev/null and b/tests/data/acpi/q35/APIC.core-count2 differ diff --git a/tests/data/acpi/q35/CEDT.cxl b/tests/data/acpi/q35/CEDT.cxl new file mode 100644 index 000000000000..ff8203af0702 Binary files /dev/null and b/tests/data/acpi/q35/CEDT.cxl differ diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index c1965f6051ef..2771bcea89b5 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 cad26e3f0c27..b45abca7c289 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 f24d4874bff8..d90fd4723a70 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.acpihmat-noinitiator b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator new file mode 100644 index 000000000000..279fafa82191 Binary files /dev/null and b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator differ diff --git a/tests/data/acpi/q35/DSDT.applesmc b/tests/data/acpi/q35/DSDT.applesmc new file mode 100644 index 000000000000..fdf6d1442868 Binary files /dev/null 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 424d51bd1cb3..b41a4dddc0b7 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.core-count2 b/tests/data/acpi/q35/DSDT.core-count2 new file mode 100644 index 000000000000..375aceed6b16 Binary files /dev/null and b/tests/data/acpi/q35/DSDT.core-count2 differ diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index f1275606f68e..a0ecafc36c57 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 new file mode 100644 index 000000000000..f9c6dd4ee050 Binary files /dev/null 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 76e451e829ec..f0659716e3ce 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 6ad2411d0ec9..9c52529919d7 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 new file mode 100644 index 000000000000..3f32dffdbf3c Binary files /dev/null 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 cad26e3f0c27..b45abca7c289 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 4e9cb3dc6896..28a192c69af3 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 eb5a1c7171c0..8fda921296e4 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 45808eb03b78..3dba4d84369f 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 83d1aa00ac56..b116947dacd4 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 050aaa237b46..5eb6159d5f61 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 new file mode 100644 index 000000000000..908e7b6606b6 Binary files /dev/null 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 fb9dd1f0599a..ce2c2c29c2c1 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 00d732e46f5d..e9e4b7f6ed50 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 1c3b4da5cbe8..6b436f9cd957 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 17552ce363ae..f47f09122287 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/q35/FACP.core-count2 b/tests/data/acpi/q35/FACP.core-count2 new file mode 100644 index 000000000000..31fa5dd19c21 Binary files /dev/null and b/tests/data/acpi/q35/FACP.core-count2 differ diff --git a/tests/data/acpi/q35/HMAT.acpihmat-noinitiator b/tests/data/acpi/q35/HMAT.acpihmat-noinitiator new file mode 100644 index 000000000000..6494d11b9fff Binary files /dev/null and b/tests/data/acpi/q35/HMAT.acpihmat-noinitiator differ diff --git a/tests/data/acpi/q35/SRAT.acpihmat-noinitiator b/tests/data/acpi/q35/SRAT.acpihmat-noinitiator new file mode 100644 index 000000000000..a11d3119ab35 Binary files /dev/null and b/tests/data/acpi/q35/SRAT.acpihmat-noinitiator differ diff --git a/tests/data/acpi/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm index 98e6f0e3f3bb..9ea4e0d0ceaa 100644 Binary files a/tests/data/acpi/q35/SSDT.dimmpxm and b/tests/data/acpi/q35/SSDT.dimmpxm differ diff --git a/tests/data/acpi/q35/VIOT.viot b/tests/data/acpi/q35/VIOT.viot index 9b179266ccbf..275c78fbe8e9 100644 Binary files a/tests/data/acpi/q35/VIOT.viot and b/tests/data/acpi/q35/VIOT.viot differ diff --git a/tests/data/acpi/virt/APIC b/tests/data/acpi/virt/APIC index 023f15f12e74..179d274770a2 100644 Binary files a/tests/data/acpi/virt/APIC and b/tests/data/acpi/virt/APIC differ diff --git a/tests/data/acpi/virt/APIC.acpihmatvirt b/tests/data/acpi/virt/APIC.acpihmatvirt new file mode 100644 index 000000000000..68200204c6f8 Binary files /dev/null and b/tests/data/acpi/virt/APIC.acpihmatvirt differ diff --git a/tests/data/acpi/virt/APIC.memhp b/tests/data/acpi/virt/APIC.memhp index 023f15f12e74..179d274770a2 100644 Binary files a/tests/data/acpi/virt/APIC.memhp and b/tests/data/acpi/virt/APIC.memhp differ diff --git a/tests/data/acpi/virt/APIC.numamem b/tests/data/acpi/virt/APIC.numamem index 023f15f12e74..179d274770a2 100644 Binary files a/tests/data/acpi/virt/APIC.numamem and b/tests/data/acpi/virt/APIC.numamem differ diff --git a/tests/data/acpi/virt/APIC.topology b/tests/data/acpi/virt/APIC.topology new file mode 100644 index 000000000000..3a6ac525e7fa Binary files /dev/null and b/tests/data/acpi/virt/APIC.topology differ diff --git a/tests/data/acpi/virt/DSDT.acpihmatvirt b/tests/data/acpi/virt/DSDT.acpihmatvirt new file mode 100644 index 000000000000..aee6ba017cd7 Binary files /dev/null and b/tests/data/acpi/virt/DSDT.acpihmatvirt differ diff --git a/tests/data/acpi/virt/DSDT.topology b/tests/data/acpi/virt/DSDT.topology new file mode 100644 index 000000000000..501314c91be0 Binary files /dev/null and b/tests/data/acpi/virt/DSDT.topology differ diff --git a/tests/data/acpi/virt/FACP b/tests/data/acpi/virt/FACP index 1f764220f853..ac05c35a6945 100644 Binary files a/tests/data/acpi/virt/FACP and b/tests/data/acpi/virt/FACP differ diff --git a/tests/data/acpi/virt/FACP.memhp b/tests/data/acpi/virt/FACP.memhp index 1f764220f853..ac05c35a6945 100644 Binary files a/tests/data/acpi/virt/FACP.memhp and b/tests/data/acpi/virt/FACP.memhp differ diff --git a/tests/data/acpi/virt/FACP.numamem b/tests/data/acpi/virt/FACP.numamem index 1f764220f853..ac05c35a6945 100644 Binary files a/tests/data/acpi/virt/FACP.numamem and b/tests/data/acpi/virt/FACP.numamem differ diff --git a/tests/data/acpi/virt/GTDT b/tests/data/acpi/virt/GTDT index 9408b71b59c0..6f8cb9b8f30b 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 9408b71b59c0..6f8cb9b8f30b 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 9408b71b59c0..6f8cb9b8f30b 100644 Binary files a/tests/data/acpi/virt/GTDT.numamem and b/tests/data/acpi/virt/GTDT.numamem differ diff --git a/tests/data/acpi/virt/HMAT.acpihmatvirt b/tests/data/acpi/virt/HMAT.acpihmatvirt new file mode 100644 index 000000000000..6494d11b9fff Binary files /dev/null and b/tests/data/acpi/virt/HMAT.acpihmatvirt differ diff --git a/tests/data/acpi/virt/PPTT b/tests/data/acpi/virt/PPTT index f56ea63b369a..7a1258ecf123 100644 Binary files a/tests/data/acpi/virt/PPTT and b/tests/data/acpi/virt/PPTT differ diff --git a/tests/data/acpi/virt/PPTT.acpihmatvirt b/tests/data/acpi/virt/PPTT.acpihmatvirt new file mode 100644 index 000000000000..4eef303a5b61 Binary files /dev/null and b/tests/data/acpi/virt/PPTT.acpihmatvirt differ diff --git a/tests/data/acpi/virt/PPTT.topology b/tests/data/acpi/virt/PPTT.topology new file mode 100644 index 000000000000..3fbcae5ff08a Binary files /dev/null and b/tests/data/acpi/virt/PPTT.topology differ diff --git a/tests/data/acpi/virt/SRAT.acpihmatvirt b/tests/data/acpi/virt/SRAT.acpihmatvirt new file mode 100644 index 000000000000..691ef56e34bc Binary files /dev/null and b/tests/data/acpi/virt/SRAT.acpihmatvirt differ diff --git a/tests/data/acpi/virt/SSDT.memhp b/tests/data/acpi/virt/SSDT.memhp index 4c363a6d95a7..2fcfc5fda955 100644 Binary files a/tests/data/acpi/virt/SSDT.memhp and b/tests/data/acpi/virt/SSDT.memhp differ diff --git a/tests/data/test-qga-config b/tests/data/test-qga-config index 4bb721a4a187..b6b7bc9dfd26 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 e495b163a0ca..665ddde51803 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -8,33 +8,13 @@ COMMA := , HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m)) -# These variables can be set by the user to limit the set of docker -# images and tests to a more restricted subset -TESTS ?= % -IMAGES ?= % - -DOCKER_SUFFIX := .docker DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles -# we don't run tests on intermediate images (used as base by another image) -DOCKER_PARTIAL_IMAGES := debian10 debian11 -# we don't directly build virtual images (they are used to build other images) -DOCKER_VIRTUAL_IMAGES := debian-bootstrap debian-toolchain empty -__IMAGES := $(sort $(filter-out $(DOCKER_VIRTUAL_IMAGES), $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker))))) -DOCKER_IMAGES := $(if $(IMAGES), $(filter $(IMAGES), $(__IMAGES)), $(__IMAGES)) -DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES)) -# Use a global constant ccache directory to speed up repetitive builds -DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache ifeq ($(HOST_ARCH),x86_64) DOCKER_DEFAULT_REGISTRY := registry.gitlab.com/qemu-project/qemu endif DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(DOCKER_DEFAULT_REGISTRY)) -__TESTS := $(notdir $(shell \ - find $(SRC_PATH)/tests/docker/ -name 'test-*' -type f)) -DOCKER_TESTS := $(if $(TESTS), $(filter $(TESTS), $(__TESTS)), $(__TESTS)) - -ENGINE := auto - +ENGINE ?= auto DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(ENGINE) CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) @@ -53,17 +33,7 @@ $(DOCKER_SRC_COPY): docker-qemu-src: $(DOCKER_SRC_COPY) -docker-image: ${DOCKER_TARGETS} - -# General rule for building docker images. If we are a sub-make -# invoked with SKIP_DOCKER_BUILD we still check the image is up to date -# though -ifdef SKIP_DOCKER_BUILD -docker-image-%: $(DOCKER_FILES_DIR)/%.docker - $(call quiet-command, \ - $(DOCKER_SCRIPT) check --quiet qemu/$* $<, \ - "CHECK", "$*") -else +# General rule for building docker images. docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(call quiet-command,\ $(DOCKER_SCRIPT) build -t qemu/$* -f $< \ @@ -99,88 +69,27 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker { echo "You will need to build $(EXECUTABLE)"; exit 1;},\ "CHECK", "debian-$* exists")) -# These are test targets -USER_TCG_TARGETS=$(patsubst %-linux-user,qemu-%,$(filter %-linux-user,$(TARGET_DIRS))) -EXEC_COPY_TESTS=$(patsubst %,docker-exec-copy-test-%, $(USER_TCG_TARGETS)) - -$(EXEC_COPY_TESTS): docker-exec-copy-test-%: $(DOCKER_FILES_DIR)/empty.docker - $(call quiet-command, \ - $(DOCKER_SCRIPT) build -t qemu/exec-copy-test-$* -f $< \ - $(if $V,,--quiet) --no-cache \ - --include-executable=$* \ - --skip-binfmt, \ - "TEST","copy $* to container") - $(call quiet-command, \ - $(DOCKER_SCRIPT) run qemu/exec-copy-test-$* \ - /$* -version > tests/docker-exec-copy-test-$*.out, \ - "TEST","check $* works in container") - -docker-exec-copy-test: $(EXEC_COPY_TESTS) - -endif - -# Enforce dependencies for composite images +# 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-armel-cross: docker-image-debian10 -docker-image-debian-armhf-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-mips64el-cross: docker-image-debian10 -docker-image-debian-mipsel-cross: docker-image-debian10 -docker-image-debian-ppc64el-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 -# -# The build rule for hexagon-cross is special in so far for most of -# the time we don't want to build it. While dockers caching does avoid -# this most of the time sometimes we want to force the issue. -# -docker-image-debian-hexagon-cross: $(DOCKER_FILES_DIR)/debian-hexagon-cross.docker - $(if $(NOCACHE), \ - $(call quiet-command, \ - $(DOCKER_SCRIPT) build -t qemu/debian-hexagon-cross -f $< \ - $(if $V,,--quiet) --no-cache \ - --registry $(DOCKER_REGISTRY) --extra-files \ - $(DOCKER_FILES_DIR)/debian-hexagon-cross.docker.d/build-toolchain.sh, \ - "BUILD", "debian-hexagon-cross"), \ - $(call quiet-command, \ - $(DOCKER_SCRIPT) fetch $(if $V,,--quiet) \ - qemu/debian-hexagon-cross $(DOCKER_REGISTRY), \ - "FETCH", "debian-hexagon-cross") \ - $(call quiet-command, \ - $(DOCKER_SCRIPT) update $(if $V,,--quiet) \ - qemu/debian-hexagon-cross --add-current-user, \ - "PREPARE", "debian-hexagon-cross")) - debian-toolchain-run = \ $(if $(NOCACHE), \ $(call quiet-command, \ @@ -208,20 +117,14 @@ 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-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 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 @@ -229,17 +132,20 @@ DOCKER_PARTIAL_IMAGES += debian-tricore-cross DOCKER_PARTIAL_IMAGES += debian-xtensa-cross DOCKER_PARTIAL_IMAGES += fedora-cris-cross -# Rules for building linux-user powered images -# -# These are slower than using native cross compiler setups but can -# work around issues with poorly working multi-arch systems and broken -# packages. +# images that are only used to build other images +DOCKER_VIRTUAL_IMAGES := debian-bootstrap debian-toolchain + +__IMAGES := $(sort $(filter-out $(DOCKER_VIRTUAL_IMAGES), $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker))))) +DOCKER_IMAGES := $(if $(IMAGES), $(filter $(IMAGES), $(__IMAGES)), $(__IMAGES)) + +__TESTS := $(notdir $(shell find $(SRC_PATH)/tests/docker/ -name 'test-*' -type f)) +DOCKER_TESTS := $(if $(TESTS), $(filter $(TESTS), $(__TESTS)), $(__TESTS)) # Expand all the pre-requistes for each docker image and test combination -$(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES) $(DOCKER_VIRTUAL_IMAGES),$(DOCKER_IMAGES)), \ +$(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES)), \ $(foreach t,$(DOCKER_TESTS), \ $(eval .PHONY: docker-$t@$i) \ - $(eval docker-$t@$i: docker-image-$i docker-run-$t@$i) \ + $(eval docker-$t@$i: docker-image-$i; @$(MAKE) docker-run TEST=$t IMAGE=qemu/$i) \ ) \ $(foreach t,$(DOCKER_TESTS), \ $(eval docker-all-tests: docker-$t@$i) \ @@ -266,11 +172,6 @@ docker: @echo @echo 'Available container images:' @echo ' $(DOCKER_IMAGES)' -ifneq ($(DOCKER_USER_IMAGES),) - @echo - @echo 'Available linux-user images (docker-binfmt-image-debian-%):' - @echo ' $(DOCKER_USER_IMAGES)' -endif @echo @echo 'Available tests:' @echo ' $(DOCKER_TESTS)' @@ -279,6 +180,7 @@ endif @echo ' TARGET_LIST=a,b,c Override target list in builds.' @echo ' EXTRA_CONFIGURE_OPTS="..."' @echo ' Extra configure options.' + @echo ' TEST_COMMAND="..." Override the default `make check` target.' @echo ' IMAGES="a b c ..": Restrict available images to subset.' @echo ' TESTS="x y z .." Restrict available tests to subset.' @echo ' J=[0..9]* Overrides the -jN parameter for make commands' @@ -298,9 +200,12 @@ endif docker-help: docker +# Use a global constant ccache directory to speed up repetitive builds +DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache + # This rule if for directly running against an arbitrary docker target. # It is called by the expanded docker targets (e.g. make -# docker-test-foo@bar) which will do additional verification. +# docker-test-foo@bar) which will also ensure the image is up to date. # # For example: make docker-run TEST="test-quick" IMAGE="debian:arm64" EXECUTABLE=./aarch64-linux-user/qemu-aarch64 # @@ -322,6 +227,7 @@ docker-run: docker-qemu-src $(if $(NETWORK),$(if $(subst $(NETWORK),,1),--net=$(NETWORK)),--net=none) \ -e TARGET_LIST=$(subst $(SPACE),$(COMMA),$(TARGET_LIST)) \ -e EXTRA_CONFIGURE_OPTS="$(EXTRA_CONFIGURE_OPTS)" \ + -e TEST_COMMAND="$(TEST_COMMAND)" \ -e V=$V -e J=$J -e DEBUG=$(DEBUG) \ -e SHOW_ENV=$(SHOW_ENV) \ $(if $(NOUSER),, \ @@ -335,13 +241,7 @@ docker-run: docker-qemu-src $(call quiet-command, rm -r $(DOCKER_SRC_COPY), \ " CLEANUP $(DOCKER_SRC_COPY)") -# Run targets: -# -# Of the form docker-TEST-FOO@IMAGE-BAR which will then be expanded into a call to "make docker-run" -docker-run-%: CMD = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\1/') -docker-run-%: IMAGE = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\2/') -docker-run-%: - @$(MAKE) docker-run TEST=$(CMD) IMAGE=qemu/$(IMAGE) +docker-image: ${DOCKER_IMAGES:%=docker-image-%} docker-clean: $(call quiet-command, $(DOCKER_SCRIPT) clean) diff --git a/tests/docker/common.rc b/tests/docker/common.rc index e6f8cee0d61d..9a33df2832e5 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -63,12 +63,12 @@ check_qemu() { # default to make check unless the caller specifies if [ $# = 0 ]; then - INVOCATION="check" + INVOCATION="${TEST_COMMAND:-make $MAKEFLAGS check}" else - INVOCATION="$@" + INVOCATION="make $MAKEFLAGS $@" fi - make $MAKEFLAGS $INVOCATION + $INVOCATION } test_fail() diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 78dd13171e2d..3a1ed7cb1852 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 @@ def build_image(self, tag, docker_dir, dockerfile, 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 @@ def image_matches_dockerfile(self, tag, dockerfile): 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 @@ -676,63 +658,6 @@ def run(self, args, argv): as_user=True) -class CheckCommand(SubCommand): - """Check if we need to re-build a docker image out of a dockerfile. - Arguments: """ - name = "check" - - def args(self, parser): - parser.add_argument("tag", - help="Image Tag") - parser.add_argument("dockerfile", default=None, - help="Dockerfile name", nargs='?') - parser.add_argument("--checktype", choices=["checksum", "age"], - default="checksum", help="check type") - parser.add_argument("--olderthan", default=60, type=int, - help="number of minutes") - - def run(self, args, argv): - tag = args.tag - - try: - dkr = Docker() - except subprocess.CalledProcessError: - print("Docker not set up") - return 1 - - info = dkr.inspect_tag(tag) - if info is None: - print("Image does not exist") - return 1 - - if args.checktype == "checksum": - if not args.dockerfile: - print("Need a dockerfile for tag:%s" % (tag)) - return 1 - - dockerfile = _read_dockerfile(args.dockerfile) - - if dkr.image_matches_dockerfile(tag, dockerfile): - if not args.quiet: - print("Image is up to date") - return 0 - else: - print("Image needs updating") - return 1 - elif args.checktype == "age": - timestr = dkr.get_image_creation_time(info).split(".")[0] - created = datetime.strptime(timestr, "%Y-%m-%dT%H:%M:%S") - past = datetime.now() - timedelta(minutes=args.olderthan) - if created < past: - print ("Image created @ %s more than %d minutes old" % - (timestr, args.olderthan)) - return 1 - else: - if not args.quiet: - print ("Image less than %d minutes old" % (args.olderthan)) - return 0 - - def main(): global USE_ENGINE diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 591af43d60e2..094f66f4eb05 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 \ @@ -73,7 +78,6 @@ RUN apk update && \ openssh-client \ pcre-dev \ perl \ - perl-test-harness \ pixman-dev \ pkgconf \ pulseaudio-dev \ @@ -82,7 +86,6 @@ RUN apk update && \ py3-pip \ py3-sphinx \ py3-sphinx_rtd_theme \ - py3-virtualenv \ py3-yaml \ python3 \ rpm2cpio \ @@ -91,6 +94,7 @@ RUN apk update && \ sdl2_image-dev \ sed \ snappy-dev \ + sndio-dev \ sparse \ spice-dev \ spice-protocol \ @@ -116,8 +120,8 @@ RUN apk update && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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" diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 3ede55d09bd8..1f70d41aeb31 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,12 +48,14 @@ RUN dnf update -y && \ 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 \ @@ -87,7 +92,6 @@ RUN dnf update -y && \ pam-devel \ pcre-static \ perl \ - perl-Test-Harness \ pixman-devel \ pkgconfig \ pulseaudio-libs-devel \ @@ -98,7 +102,6 @@ RUN dnf update -y && \ python3-pip \ python3-sphinx \ python3-sphinx_rtd_theme \ - python3-virtualenv \ rdma-core-devel \ rpm \ sed \ @@ -127,8 +130,8 @@ RUN dnf update -y && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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" diff --git a/tests/docker/dockerfiles/debian-all-test-cross.docker b/tests/docker/dockerfiles/debian-all-test-cross.docker index dedcea58b467..8dc5e1b5de8f 100644 --- a/tests/docker/dockerfiles/debian-all-test-cross.docker +++ b/tests/docker/dockerfiles/debian-all-test-cross.docker @@ -6,16 +6,26 @@ # 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 \ + bison \ + ccache \ + clang \ + flex \ + 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 10fe30df0dd1..4eeb43c78ac8 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 870109ef6afe..5e57309361b6 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -1,22 +1,172 @@ +# 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 + +FROM docker.io/library/debian:11-slim + +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 \ + libsndio-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 CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" -# 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 +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 -# Specify the cross prefix for this image (see tests/docker/common.rc) +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 ed546edcd65a..bfeab01ee3e2 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -1,59 +1,158 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker x86_64 target +# $ lcitool dockerfile --layers all debian-11 qemu # -# This docker target builds on the Debian Buster base image. Further -# libraries which are not widely available are installed by hand. -# -FROM qemu/debian10 -MAINTAINER Philippe Mathieu-Daudé - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy qemu +# https://gitlab.com/libvirt/libvirt-ci -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - cscope \ - genisoimage \ - exuberant-ctags \ - global \ - libbz2-dev \ - liblzo2-dev \ - libgcrypt20-dev \ - libfdt-dev \ - librdmacm-dev \ - libsasl2-dev \ - libsnappy-dev \ - libvte-dev \ - netcat-openbsd \ - openssh-client \ - python3-numpy \ - python3-opencv \ - python3-venv +FROM docker.io/library/debian:11-slim -# virgl -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libegl1-mesa-dev \ - libepoxy-dev \ - libgbm-dev -RUN git clone https://gitlab.freedesktop.org/virgl/virglrenderer.git /usr/src/virglrenderer && \ - cd /usr/src/virglrenderer && git checkout virglrenderer-0.8.0 -RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --disable-tests && make install +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 \ + clang \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + flex \ + g++ \ + gcc \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libaio-dev \ + libasan5 \ + libasound2-dev \ + libattr1-dev \ + libbpf-dev \ + libbrlapi-dev \ + libbz2-dev \ + libc6-dev \ + libcacard-dev \ + libcap-ng-dev \ + libcapstone-dev \ + libcmocka-dev \ + libcurl4-gnutls-dev \ + libdaxctl-dev \ + libdrm-dev \ + libepoxy-dev \ + libfdt-dev \ + libffi-dev \ + libfuse3-dev \ + libgbm-dev \ + libgcrypt20-dev \ + libglib2.0-dev \ + libglusterfs-dev \ + libgnutls28-dev \ + libgtk-3-dev \ + libibumad-dev \ + libibverbs-dev \ + libiscsi-dev \ + libjemalloc-dev \ + libjpeg62-turbo-dev \ + libjson-c-dev \ + liblttng-ust-dev \ + liblzo2-dev \ + libncursesw5-dev \ + libnfs-dev \ + libnuma-dev \ + libpam0g-dev \ + libpcre2-dev \ + libpixman-1-dev \ + libpmem-dev \ + libpng-dev \ + libpulse-dev \ + librbd-dev \ + librdmacm-dev \ + libsasl2-dev \ + libsdl2-dev \ + libsdl2-image-dev \ + libseccomp-dev \ + libselinux1-dev \ + libslirp-dev \ + libsnappy-dev \ + libsndio-dev \ + libspice-protocol-dev \ + libspice-server-dev \ + libssh-gcrypt-dev \ + libsystemd-dev \ + libtasn1-6-dev \ + libubsan1 \ + libudev-dev \ + liburing-dev \ + libusb-1.0-0-dev \ + libusbredirhost-dev \ + libvdeplug-dev \ + libvirglrenderer-dev \ + libvte-2.91-dev \ + libxen-dev \ + libzstd-dev \ + llvm \ + locales \ + make \ + meson \ + multipath-tools \ + ncat \ + nettle-dev \ + 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 \ + systemtap-sdt-dev \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo \ + xfslibs-dev \ + zlib1g-dev && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales && \ + 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/c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -# netmap -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - linux-headers-amd64 +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +# netmap/cscope/global +RUN DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + cscope\ + global\ + linux-headers-amd64 RUN git clone https://github.com/luigirizzo/netmap.git /usr/src/netmap RUN cd /usr/src/netmap && git checkout v11.3 RUN cd /usr/src/netmap/LINUX && ./configure --no-drivers --no-apps --kernel-dir=$(ls -d /usr/src/linux-headers-*-amd64) && make install ENV QEMU_CONFIGURE_OPTS --enable-netmap - -RUN ldconfig - -# gcrypt -ENV QEMU_CONFIGURE_OPTS $QEMU_CONFIGURE_OPTS --enable-gcrypt diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 589510a7be65..98885bd0eedf 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -11,60 +11,63 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get install -y eatmydata && \ eatmydata apt-get dist-upgrade -y && \ eatmydata apt-get install --no-install-recommends -y \ - bash \ - bc \ - bsdextrautils \ - bzip2 \ - ca-certificates \ - ccache \ - dbus \ - debianutils \ - diffutils \ - exuberant-ctags \ - findutils \ - gcovr \ - genisoimage \ - gettext \ - git \ - hostname \ - libpcre2-dev \ - libspice-protocol-dev \ - libtest-harness-perl \ - 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 && \ + 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 \ + libsndio-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 CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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 arm64 && \ @@ -72,73 +75,75 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ 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++-aarch64-linux-gnu \ - gcc-aarch64-linux-gnu \ - libaio-dev:arm64 \ - libasan5:arm64 \ - libasound2-dev:arm64 \ - libattr1-dev:arm64 \ - libbpf-dev:arm64 \ - libbrlapi-dev:arm64 \ - libbz2-dev:arm64 \ - libc6-dev:arm64 \ - libcacard-dev:arm64 \ - libcap-ng-dev:arm64 \ - libcapstone-dev:arm64 \ - libcurl4-gnutls-dev:arm64 \ - libdaxctl-dev:arm64 \ - libdrm-dev:arm64 \ - libepoxy-dev:arm64 \ - libfdt-dev:arm64 \ - libffi-dev:arm64 \ - libfuse3-dev:arm64 \ - libgbm-dev:arm64 \ - libgcrypt20-dev:arm64 \ - libglib2.0-dev:arm64 \ - libglusterfs-dev:arm64 \ - libgnutls28-dev:arm64 \ - libgtk-3-dev:arm64 \ - libibumad-dev:arm64 \ - libibverbs-dev:arm64 \ - libiscsi-dev:arm64 \ - libjemalloc-dev:arm64 \ - libjpeg62-turbo-dev:arm64 \ - liblttng-ust-dev:arm64 \ - liblzo2-dev:arm64 \ - libncursesw5-dev:arm64 \ - libnfs-dev:arm64 \ - libnuma-dev:arm64 \ - libpam0g-dev:arm64 \ - libpixman-1-dev:arm64 \ - libpng-dev:arm64 \ - libpulse-dev:arm64 \ - librbd-dev:arm64 \ - librdmacm-dev:arm64 \ - libsasl2-dev:arm64 \ - libsdl2-dev:arm64 \ - libsdl2-image-dev:arm64 \ - libseccomp-dev:arm64 \ - libselinux1-dev:arm64 \ - libslirp-dev:arm64 \ - libsnappy-dev:arm64 \ - libspice-server-dev:arm64 \ - libssh-gcrypt-dev:arm64 \ - libsystemd-dev:arm64 \ - libtasn1-6-dev:arm64 \ - libubsan1:arm64 \ - libudev-dev:arm64 \ - liburing-dev:arm64 \ - libusb-1.0-0-dev:arm64 \ - libusbredirhost-dev:arm64 \ - libvdeplug-dev:arm64 \ - libvirglrenderer-dev:arm64 \ - libvte-2.91-dev:arm64 \ - libxen-dev:arm64 \ - libzstd-dev:arm64 \ - nettle-dev:arm64 \ - systemtap-sdt-dev:arm64 \ - xfslibs-dev:arm64 \ - zlib1g-dev:arm64 && \ + g++-aarch64-linux-gnu \ + gcc-aarch64-linux-gnu \ + libaio-dev:arm64 \ + libasan5:arm64 \ + libasound2-dev:arm64 \ + libattr1-dev:arm64 \ + libbpf-dev:arm64 \ + libbrlapi-dev:arm64 \ + libbz2-dev:arm64 \ + libc6-dev:arm64 \ + libcacard-dev:arm64 \ + libcap-ng-dev:arm64 \ + libcapstone-dev:arm64 \ + libcmocka-dev:arm64 \ + libcurl4-gnutls-dev:arm64 \ + libdaxctl-dev:arm64 \ + libdrm-dev:arm64 \ + libepoxy-dev:arm64 \ + libfdt-dev:arm64 \ + libffi-dev:arm64 \ + libfuse3-dev:arm64 \ + libgbm-dev:arm64 \ + libgcrypt20-dev:arm64 \ + libglib2.0-dev:arm64 \ + libglusterfs-dev:arm64 \ + libgnutls28-dev:arm64 \ + libgtk-3-dev:arm64 \ + libibumad-dev:arm64 \ + libibverbs-dev:arm64 \ + libiscsi-dev:arm64 \ + libjemalloc-dev:arm64 \ + libjpeg62-turbo-dev:arm64 \ + libjson-c-dev:arm64 \ + liblttng-ust-dev:arm64 \ + liblzo2-dev:arm64 \ + libncursesw5-dev:arm64 \ + libnfs-dev:arm64 \ + libnuma-dev:arm64 \ + libpam0g-dev:arm64 \ + libpixman-1-dev:arm64 \ + libpng-dev:arm64 \ + libpulse-dev:arm64 \ + librbd-dev:arm64 \ + librdmacm-dev:arm64 \ + libsasl2-dev:arm64 \ + libsdl2-dev:arm64 \ + libsdl2-image-dev:arm64 \ + libseccomp-dev:arm64 \ + libselinux1-dev:arm64 \ + libslirp-dev:arm64 \ + libsnappy-dev:arm64 \ + libspice-server-dev:arm64 \ + libssh-gcrypt-dev:arm64 \ + libsystemd-dev:arm64 \ + libtasn1-6-dev:arm64 \ + libubsan1:arm64 \ + libudev-dev:arm64 \ + liburing-dev:arm64 \ + libusb-1.0-0-dev:arm64 \ + libusbredirhost-dev:arm64 \ + libvdeplug-dev:arm64 \ + libvirglrenderer-dev:arm64 \ + libvte-2.91-dev:arm64 \ + libxen-dev:arm64 \ + libzstd-dev:arm64 \ + nettle-dev:arm64 \ + systemtap-sdt-dev:arm64 \ + xfslibs-dev:arm64 \ + zlib1g-dev:arm64 && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ mkdir -p /usr/local/share/meson/cross && \ diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index b7b1a3585f8d..d5c08714e4de 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -1,26 +1,170 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker armel cross-compiler target +# $ lcitool dockerfile --layers all --cross armv6l debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 -MAINTAINER Philippe Mathieu-Daudé +# https://gitlab.com/libvirt/libvirt-ci + +FROM docker.io/library/debian:11-slim + +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 \ + libsndio-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 -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture armel && \ - apt update && \ - apt install -yy crossbuild-essential-armel && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a armel --arch-only qemu +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" -# Specify the cross prefix for this image (see tests/docker/common.rc) +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture armel && \ + 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++-arm-linux-gnueabi \ + gcc-arm-linux-gnueabi \ + libaio-dev:armel \ + libasan5:armel \ + libasound2-dev:armel \ + libattr1-dev:armel \ + libbpf-dev:armel \ + libbrlapi-dev:armel \ + libbz2-dev:armel \ + libc6-dev:armel \ + libcacard-dev:armel \ + libcap-ng-dev:armel \ + libcapstone-dev:armel \ + libcmocka-dev:armel \ + libcurl4-gnutls-dev:armel \ + libdaxctl-dev:armel \ + libdrm-dev:armel \ + libepoxy-dev:armel \ + libfdt-dev:armel \ + libffi-dev:armel \ + libfuse3-dev:armel \ + libgbm-dev:armel \ + libgcrypt20-dev:armel \ + libglib2.0-dev:armel \ + libglusterfs-dev:armel \ + libgnutls28-dev:armel \ + libgtk-3-dev:armel \ + libibumad-dev:armel \ + libibverbs-dev:armel \ + libiscsi-dev:armel \ + libjemalloc-dev:armel \ + libjpeg62-turbo-dev:armel \ + libjson-c-dev:armel \ + liblttng-ust-dev:armel \ + liblzo2-dev:armel \ + libncursesw5-dev:armel \ + libnfs-dev:armel \ + libnuma-dev:armel \ + libpam0g-dev:armel \ + libpixman-1-dev:armel \ + libpng-dev:armel \ + libpulse-dev:armel \ + librbd-dev:armel \ + librdmacm-dev:armel \ + libsasl2-dev:armel \ + libsdl2-dev:armel \ + libsdl2-image-dev:armel \ + libseccomp-dev:armel \ + libselinux1-dev:armel \ + libslirp-dev:armel \ + libsnappy-dev:armel \ + libspice-server-dev:armel \ + libssh-gcrypt-dev:armel \ + libsystemd-dev:armel \ + libtasn1-6-dev:armel \ + libubsan1:armel \ + libudev-dev:armel \ + liburing-dev:armel \ + libusb-1.0-0-dev:armel \ + libusbredirhost-dev:armel \ + libvdeplug-dev:armel \ + libvirglrenderer-dev:armel \ + libvte-2.91-dev:armel \ + libzstd-dev:armel \ + nettle-dev:armel \ + systemtap-sdt-dev:armel \ + xfslibs-dev:armel \ + zlib1g-dev:armel && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/arm-linux-gnueabi-gcc'\n\ +ar = '/usr/bin/arm-linux-gnueabi-gcc-ar'\n\ +strip = '/usr/bin/arm-linux-gnueabi-strip'\n\ +pkgconfig = '/usr/bin/arm-linux-gnueabi-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'arm'\n\ +cpu = 'arm'\n\ +endian = 'little'" > /usr/local/share/meson/cross/arm-linux-gnueabi && \ + 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/arm-linux-gnueabi-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-gcc + +ENV ABI "arm-linux-gnueabi" +ENV MESON_OPTS "--cross-file=arm-linux-gnueabi" ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabi- ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:armel \ - liblzo2-dev:armel \ - librdmacm-dev:armel \ - libsnappy-dev:armel diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 25d76188337f..471444fcf489 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -1,29 +1,171 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker armhf cross-compiler target +# $ lcitool dockerfile --layers all --cross armv7l debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 +# https://gitlab.com/libvirt/libvirt-ci -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture armhf -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - crossbuild-essential-armhf -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a armhf --arch-only qemu +FROM docker.io/library/debian:11-slim -# Specify the cross prefix for this image (see tests/docker/common.rc) -ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf- -ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user +RUN 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 \ + libsndio-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 CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:armhf \ - liblzo2-dev:armhf \ - librdmacm-dev:armhf \ - libsnappy-dev:armhf \ - libxen-dev:armhf +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture armhf && \ + 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++-arm-linux-gnueabihf \ + gcc-arm-linux-gnueabihf \ + libaio-dev:armhf \ + libasan5:armhf \ + libasound2-dev:armhf \ + libattr1-dev:armhf \ + libbpf-dev:armhf \ + libbrlapi-dev:armhf \ + libbz2-dev:armhf \ + libc6-dev:armhf \ + libcacard-dev:armhf \ + libcap-ng-dev:armhf \ + libcapstone-dev:armhf \ + libcmocka-dev:armhf \ + libcurl4-gnutls-dev:armhf \ + libdaxctl-dev:armhf \ + libdrm-dev:armhf \ + libepoxy-dev:armhf \ + libfdt-dev:armhf \ + libffi-dev:armhf \ + libfuse3-dev:armhf \ + libgbm-dev:armhf \ + libgcrypt20-dev:armhf \ + libglib2.0-dev:armhf \ + libglusterfs-dev:armhf \ + libgnutls28-dev:armhf \ + libgtk-3-dev:armhf \ + libibumad-dev:armhf \ + libibverbs-dev:armhf \ + libiscsi-dev:armhf \ + libjemalloc-dev:armhf \ + libjpeg62-turbo-dev:armhf \ + libjson-c-dev:armhf \ + liblttng-ust-dev:armhf \ + liblzo2-dev:armhf \ + libncursesw5-dev:armhf \ + libnfs-dev:armhf \ + libnuma-dev:armhf \ + libpam0g-dev:armhf \ + libpixman-1-dev:armhf \ + libpng-dev:armhf \ + libpulse-dev:armhf \ + librbd-dev:armhf \ + librdmacm-dev:armhf \ + libsasl2-dev:armhf \ + libsdl2-dev:armhf \ + libsdl2-image-dev:armhf \ + libseccomp-dev:armhf \ + libselinux1-dev:armhf \ + libslirp-dev:armhf \ + libsnappy-dev:armhf \ + libspice-server-dev:armhf \ + libssh-gcrypt-dev:armhf \ + libsystemd-dev:armhf \ + libtasn1-6-dev:armhf \ + libubsan1:armhf \ + libudev-dev:armhf \ + liburing-dev:armhf \ + libusb-1.0-0-dev:armhf \ + libusbredirhost-dev:armhf \ + libvdeplug-dev:armhf \ + libvirglrenderer-dev:armhf \ + libvte-2.91-dev:armhf \ + libxen-dev:armhf \ + libzstd-dev:armhf \ + nettle-dev:armhf \ + systemtap-sdt-dev:armhf \ + xfslibs-dev:armhf \ + zlib1g-dev:armhf && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/arm-linux-gnueabihf-gcc'\n\ +ar = '/usr/bin/arm-linux-gnueabihf-gcc-ar'\n\ +strip = '/usr/bin/arm-linux-gnueabihf-strip'\n\ +pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'arm'\n\ +cpu = 'armhf'\n\ +endian = 'little'" > /usr/local/share/meson/cross/arm-linux-gnueabihf && \ + 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/arm-linux-gnueabihf-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-gcc + +ENV ABI "arm-linux-gnueabihf" +ENV MESON_OPTS "--cross-file=arm-linux-gnueabihf" +ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf- +ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker index d5dc299dc1f5..8a0d74834356 100644 --- a/tests/docker/dockerfiles/debian-hexagon-cross.docker +++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker @@ -2,44 +2,34 @@ # 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 && \ +# 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 && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +# Install common build utilities + apt-get install -y --no-install-recommends \ + curl \ + xz-utils \ + ca-certificates \ bison \ - cmake \ flex \ - lld \ - rsync \ - wget - -ENV TOOLCHAIN_INSTALL /usr/local -ENV ROOTFS /usr/local - -ENV LLVM_URL https://github.com/llvm/llvm-project/archive/bfcd21876adc3498065e4da92799f613e730d475.tar.gz -ENV MUSL_URL https://github.com/quic/musl/archive/aff74b395fbf59cd7e93b3691905aa1af6c0778c.tar.gz -ENV LINUX_URL https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.6.18.tar.xz - -ADD build-toolchain.sh /root/hexagon-toolchain/build-toolchain.sh - -RUN cd /root/hexagon-toolchain && ./build-toolchain.sh - -FROM debian:buster-slim -# Duplicate deb line as deb-src -RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list + git \ + ninja-build && \ # Install QEMU build deps for use in CI -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ - DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy git ninja-build && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt build-dep -yy --arch-only qemu -COPY --from=0 /usr/local /usr/local -ENV PATH $PATH:/usr/local/bin/ + + +ENV TOOLCHAIN_INSTALL /opt +ENV TOOLCHAIN_RELEASE 15.0.3 +ENV TOOLCHAIN_BASENAME "clang+llvm-${TOOLCHAIN_RELEASE}-cross-hexagon-unknown-linux-musl" +ENV TOOLCHAIN_URL https://codelinaro.jfrog.io/artifactory/codelinaro-toolchain-for-hexagon/v${TOOLCHAIN_RELEASE}/${TOOLCHAIN_BASENAME}.tar.xz + +RUN curl -#SL "$TOOLCHAIN_URL" | tar -xJC "$TOOLCHAIN_INSTALL" +ENV PATH $PATH:${TOOLCHAIN_INSTALL}/${TOOLCHAIN_BASENAME}/x86_64-linux-gnu/bin diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh b/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh deleted file mode 100755 index 19b1c9f83e11..000000000000 --- a/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash - -set -e - -BASE=$(readlink -f ${PWD}) - -TOOLCHAIN_INSTALL=$(readlink -f "$TOOLCHAIN_INSTALL") -ROOTFS=$(readlink -f "$ROOTFS") - -TOOLCHAIN_BIN=${TOOLCHAIN_INSTALL}/bin -HEX_SYSROOT=${TOOLCHAIN_INSTALL}/hexagon-unknown-linux-musl -HEX_TOOLS_TARGET_BASE=${HEX_SYSROOT}/usr - -function cdp() { - DIR="$1" - mkdir -p "$DIR" - cd "$DIR" -} - -function fetch() { - DIR="$1" - URL="$2" - TEMP="$(readlink -f "$PWD/tmp.tar.gz")" - wget --quiet "$URL" -O "$TEMP" - cdp "$DIR" - tar xaf "$TEMP" --strip-components=1 - rm "$TEMP" - cd - -} - -build_llvm_clang() { - fetch "$BASE/llvm-project" "$LLVM_URL" - cdp "$BASE/build-llvm" - - cmake -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=${TOOLCHAIN_INSTALL} \ - -DLLVM_ENABLE_LLD=ON \ - -DLLVM_TARGETS_TO_BUILD="Hexagon" \ - -DLLVM_ENABLE_PROJECTS="clang;lld" \ - "$BASE/llvm-project/llvm" - ninja all install - cd ${TOOLCHAIN_BIN} - ln -sf clang hexagon-unknown-linux-musl-clang - ln -sf clang++ hexagon-unknown-linux-musl-clang++ - ln -sf llvm-ar hexagon-unknown-linux-musl-ar - ln -sf llvm-objdump hexagon-unknown-linux-musl-objdump - ln -sf llvm-objcopy hexagon-unknown-linux-musl-objcopy - ln -sf llvm-readelf hexagon-unknown-linux-musl-readelf - ln -sf llvm-ranlib hexagon-unknown-linux-musl-ranlib - - # workaround for now: - cat < hexagon-unknown-linux-musl.cfg --G0 --sysroot=${HEX_SYSROOT} -EOF -} - -build_clang_rt() { - cdp "$BASE/build-clang_rt" - cmake -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DLLVM_CONFIG_PATH="$BASE/build-llvm/bin/llvm-config" \ - -DCMAKE_ASM_FLAGS="-G0 -mlong-calls -fno-pic --target=hexagon-unknown-linux-musl " \ - -DCMAKE_SYSTEM_NAME=Linux \ - -DCMAKE_C_COMPILER="${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang" \ - -DCMAKE_ASM_COMPILER="${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang" \ - -DCMAKE_INSTALL_PREFIX=${HEX_TOOLS_TARGET_BASE} \ - -DCMAKE_CROSSCOMPILING=ON \ - -DCMAKE_C_COMPILER_FORCED=ON \ - -DCMAKE_CXX_COMPILER_FORCED=ON \ - -DCOMPILER_RT_BUILD_BUILTINS=ON \ - -DCOMPILER_RT_BUILTINS_ENABLE_PIC=OFF \ - -DCMAKE_SIZEOF_VOID_P=4 \ - -DCOMPILER_RT_OS_DIR= \ - -DCAN_TARGET_hexagon=1 \ - -DCAN_TARGET_x86_64=0 \ - -DCOMPILER_RT_SUPPORTED_ARCH=hexagon \ - -DLLVM_ENABLE_PROJECTS="compiler-rt" \ - "$BASE/llvm-project/compiler-rt" - ninja install-compiler-rt -} - -build_musl_headers() { - fetch "$BASE/musl" "$MUSL_URL" - cd "$BASE/musl" - make clean - CC=${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang \ - CROSS_COMPILE=hexagon-unknown-linux-musl \ - LIBCC=${HEX_TOOLS_TARGET_BASE}/lib/libclang_rt.builtins-hexagon.a \ - CROSS_CFLAGS="-G0 -O0 -mv65 -fno-builtin -fno-rounding-math --target=hexagon-unknown-linux-musl" \ - ./configure --target=hexagon --prefix=${HEX_TOOLS_TARGET_BASE} - PATH=${TOOLCHAIN_BIN}:$PATH make CROSS_COMPILE= install-headers - - cd ${HEX_SYSROOT}/.. - ln -sf hexagon-unknown-linux-musl hexagon -} - -build_kernel_headers() { - fetch "$BASE/linux" "$LINUX_URL" - mkdir -p "$BASE/build-linux" - cd "$BASE/linux" - make O=../build-linux ARCH=hexagon \ - KBUILD_CFLAGS_KERNEL="-mlong-calls" \ - CC=${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang \ - LD=${TOOLCHAIN_BIN}/ld.lld \ - KBUILD_VERBOSE=1 comet_defconfig - make mrproper - - cd "$BASE/build-linux" - make \ - ARCH=hexagon \ - CC=${TOOLCHAIN_BIN}/clang \ - INSTALL_HDR_PATH=${HEX_TOOLS_TARGET_BASE} \ - V=1 \ - headers_install -} - -build_musl() { - cd "$BASE/musl" - make clean - CROSS_COMPILE=hexagon-unknown-linux-musl- \ - AR=llvm-ar \ - RANLIB=llvm-ranlib \ - STRIP=llvm-strip \ - CC=clang \ - LIBCC=${HEX_TOOLS_TARGET_BASE}/lib/libclang_rt.builtins-hexagon.a \ - CFLAGS="-G0 -O0 -mv65 -fno-builtin -fno-rounding-math --target=hexagon-unknown-linux-musl" \ - ./configure --target=hexagon --prefix=${HEX_TOOLS_TARGET_BASE} - PATH=${TOOLCHAIN_BIN}/:$PATH make CROSS_COMPILE= install - cd ${HEX_TOOLS_TARGET_BASE}/lib - ln -sf libc.so ld-musl-hexagon.so - ln -sf ld-musl-hexagon.so ld-musl-hexagon.so.1 - cdp ${HEX_TOOLS_TARGET_BASE}/../lib - ln -sf ../usr/lib/ld-musl-hexagon.so.1 -} - -build_llvm_clang -build_kernel_headers -build_musl_headers -build_clang_rt -build_musl diff --git a/tests/docker/dockerfiles/debian-hppa-cross.docker b/tests/docker/dockerfiles/debian-hppa-cross.docker index 3d6c65a3efcf..af1c8403d8fd 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 new file mode 100644 index 000000000000..a8e8e98909a6 --- /dev/null +++ b/tests/docker/dockerfiles/debian-loongarch-cross.docker @@ -0,0 +1,27 @@ +# +# Docker cross-compiler target +# +# This docker target uses prebuilt toolchains for LoongArch64 from: +# https://github.com/loongson/build-tools/releases +# +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 && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt-get install -y --no-install-recommends \ + build-essential \ + ca-certificates \ + curl \ + gettext \ + git \ + python3-minimal + +RUN curl -#SL https://github.com/loongson/build-tools/releases/download/2022.05.29/loongarch64-clfs-5.0-cross-tools-gcc-glibc.tar.xz \ + | tar -xJC /opt + +ENV PATH $PATH:/opt/cross-tools/bin +ENV LD_LIBRARY_PATH /opt/cross-tools/lib:/opt/cross-tools/loongarch64-unknown-linux-gnu/lib:$LD_LIBRARY_PATH diff --git a/tests/docker/dockerfiles/debian-m68k-cross.docker b/tests/docker/dockerfiles/debian-m68k-cross.docker index fcb10e353475..dded71c5d261 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 26c154014db2..7b55f0f3b29a 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 - -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 +FROM docker.io/library/debian:11-slim + +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 09c2ba584e51..afcff9726f09 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 c990b683b7a1..15b0224b76bf 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -1,33 +1,168 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker mips64el cross-compiler target -# -# This docker target builds on the debian Stretch base image. +# $ lcitool dockerfile --layers all --cross mips64el debian-11 qemu # +# https://gitlab.com/libvirt/libvirt-ci -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -MAINTAINER Philippe Mathieu-Daudé +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 \ + libsndio-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 -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture mips64el && \ - apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-mips64el-linux-gnuabi64 +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mips64el --arch-only qemu +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture mips64el && \ + 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++-mips64el-linux-gnuabi64 \ + gcc-mips64el-linux-gnuabi64 \ + libaio-dev:mips64el \ + libasound2-dev:mips64el \ + libattr1-dev:mips64el \ + libbpf-dev:mips64el \ + libbrlapi-dev:mips64el \ + libbz2-dev:mips64el \ + libc6-dev:mips64el \ + libcacard-dev:mips64el \ + libcap-ng-dev:mips64el \ + libcapstone-dev:mips64el \ + libcmocka-dev:mips64el \ + libcurl4-gnutls-dev:mips64el \ + libdaxctl-dev:mips64el \ + libdrm-dev:mips64el \ + libepoxy-dev:mips64el \ + libfdt-dev:mips64el \ + libffi-dev:mips64el \ + libfuse3-dev:mips64el \ + libgbm-dev:mips64el \ + libgcrypt20-dev:mips64el \ + libglib2.0-dev:mips64el \ + libglusterfs-dev:mips64el \ + libgnutls28-dev:mips64el \ + libgtk-3-dev:mips64el \ + libibumad-dev:mips64el \ + libibverbs-dev:mips64el \ + libiscsi-dev:mips64el \ + libjemalloc-dev:mips64el \ + libjpeg62-turbo-dev:mips64el \ + libjson-c-dev:mips64el \ + liblttng-ust-dev:mips64el \ + liblzo2-dev:mips64el \ + libncursesw5-dev:mips64el \ + libnfs-dev:mips64el \ + libnuma-dev:mips64el \ + libpam0g-dev:mips64el \ + libpixman-1-dev:mips64el \ + libpng-dev:mips64el \ + libpulse-dev:mips64el \ + librbd-dev:mips64el \ + librdmacm-dev:mips64el \ + libsasl2-dev:mips64el \ + libsdl2-dev:mips64el \ + libsdl2-image-dev:mips64el \ + libseccomp-dev:mips64el \ + libselinux1-dev:mips64el \ + libslirp-dev:mips64el \ + libsnappy-dev:mips64el \ + libspice-server-dev:mips64el \ + libssh-gcrypt-dev:mips64el \ + libsystemd-dev:mips64el \ + libtasn1-6-dev:mips64el \ + libudev-dev:mips64el \ + liburing-dev:mips64el \ + libusb-1.0-0-dev:mips64el \ + libusbredirhost-dev:mips64el \ + libvdeplug-dev:mips64el \ + libvirglrenderer-dev:mips64el \ + libvte-2.91-dev:mips64el \ + libzstd-dev:mips64el \ + nettle-dev:mips64el \ + systemtap-sdt-dev:mips64el \ + xfslibs-dev:mips64el \ + zlib1g-dev:mips64el && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/mips64el-linux-gnuabi64-gcc'\n\ +ar = '/usr/bin/mips64el-linux-gnuabi64-gcc-ar'\n\ +strip = '/usr/bin/mips64el-linux-gnuabi64-strip'\n\ +pkgconfig = '/usr/bin/mips64el-linux-gnuabi64-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'mips64'\n\ +cpu = 'mips64el'\n\ +endian = 'little'" > /usr/local/share/meson/cross/mips64el-linux-gnuabi64 && \ + 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/mips64el-linux-gnuabi64-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-gcc -# Specify the cross prefix for this image (see tests/docker/common.rc) +ENV ABI "mips64el-linux-gnuabi64" +ENV MESON_OPTS "--cross-file=mips64el-linux-gnuabi64" ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64- ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user - -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:mips64el \ - liblzo2-dev:mips64el \ - librdmacm-dev:mips64el \ - libsnappy-dev:mips64el diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index 0e5dd42d3c4b..a5d3ca6e2f7f 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -1,31 +1,168 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker mipsel cross-compiler target +# $ lcitool dockerfile --layers all --cross mipsel debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 +# https://gitlab.com/libvirt/libvirt-ci -MAINTAINER Philippe Mathieu-Daudé +FROM docker.io/library/debian:11-slim -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture mipsel -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-mipsel-linux-gnu +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 \ + libsndio-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 -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mipsel --arch-only qemu +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" -# Specify the cross prefix for this image (see tests/docker/common.rc) -ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu- +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture mipsel && \ + 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++-mipsel-linux-gnu \ + gcc-mipsel-linux-gnu \ + libaio-dev:mipsel \ + libasound2-dev:mipsel \ + libattr1-dev:mipsel \ + libbpf-dev:mipsel \ + libbrlapi-dev:mipsel \ + libbz2-dev:mipsel \ + libc6-dev:mipsel \ + libcacard-dev:mipsel \ + libcap-ng-dev:mipsel \ + libcapstone-dev:mipsel \ + libcmocka-dev:mipsel \ + libcurl4-gnutls-dev:mipsel \ + libdaxctl-dev:mipsel \ + libdrm-dev:mipsel \ + libepoxy-dev:mipsel \ + libfdt-dev:mipsel \ + libffi-dev:mipsel \ + libfuse3-dev:mipsel \ + libgbm-dev:mipsel \ + libgcrypt20-dev:mipsel \ + libglib2.0-dev:mipsel \ + libglusterfs-dev:mipsel \ + libgnutls28-dev:mipsel \ + libgtk-3-dev:mipsel \ + libibumad-dev:mipsel \ + libibverbs-dev:mipsel \ + libiscsi-dev:mipsel \ + libjemalloc-dev:mipsel \ + libjpeg62-turbo-dev:mipsel \ + libjson-c-dev:mipsel \ + liblttng-ust-dev:mipsel \ + liblzo2-dev:mipsel \ + libncursesw5-dev:mipsel \ + libnfs-dev:mipsel \ + libnuma-dev:mipsel \ + libpam0g-dev:mipsel \ + libpixman-1-dev:mipsel \ + libpng-dev:mipsel \ + libpulse-dev:mipsel \ + librbd-dev:mipsel \ + librdmacm-dev:mipsel \ + libsasl2-dev:mipsel \ + libsdl2-dev:mipsel \ + libsdl2-image-dev:mipsel \ + libseccomp-dev:mipsel \ + libselinux1-dev:mipsel \ + libslirp-dev:mipsel \ + libsnappy-dev:mipsel \ + libspice-server-dev:mipsel \ + libssh-gcrypt-dev:mipsel \ + libsystemd-dev:mipsel \ + libtasn1-6-dev:mipsel \ + libudev-dev:mipsel \ + liburing-dev:mipsel \ + libusb-1.0-0-dev:mipsel \ + libusbredirhost-dev:mipsel \ + libvdeplug-dev:mipsel \ + libvirglrenderer-dev:mipsel \ + libvte-2.91-dev:mipsel \ + libzstd-dev:mipsel \ + nettle-dev:mipsel \ + systemtap-sdt-dev:mipsel \ + xfslibs-dev:mipsel \ + zlib1g-dev:mipsel && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/mipsel-linux-gnu-gcc'\n\ +ar = '/usr/bin/mipsel-linux-gnu-gcc-ar'\n\ +strip = '/usr/bin/mipsel-linux-gnu-strip'\n\ +pkgconfig = '/usr/bin/mipsel-linux-gnu-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'mips'\n\ +cpu = 'mipsel'\n\ +endian = 'little'" > /usr/local/share/meson/cross/mipsel-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/mipsel-linux-gnu-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-gcc -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:mipsel \ - liblzo2-dev:mipsel \ - librdmacm-dev:mipsel \ - libsnappy-dev:mipsel +ENV ABI "mipsel-linux-gnu" +ENV MESON_OPTS "--cross-file=mipsel-linux-gnu" +ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu- +ENV DEF_TARGET_LIST mipsel-softmmu,mipsel-linux-user diff --git a/tests/docker/dockerfiles/debian-native.docker b/tests/docker/dockerfiles/debian-native.docker index efd55cb6e0e8..8dd033097c06 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 36b336f709fc..d6b2909cc42f 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 5de12b01cdc9..d2954e61f678 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -1,28 +1,170 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker ppc64el cross-compiler target +# $ lcitool dockerfile --layers all --cross ppc64le debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 +# https://gitlab.com/libvirt/libvirt-ci + +FROM docker.io/library/debian:11-slim -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture ppc64el && \ - apt update && \ - apt install -yy crossbuild-essential-ppc64el +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 \ + libsndio-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 -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a ppc64el --arch-only qemu +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" -# Specify the cross prefix for this image (see tests/docker/common.rc) +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture ppc64el && \ + 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++-powerpc64le-linux-gnu \ + gcc-powerpc64le-linux-gnu \ + libaio-dev:ppc64el \ + libasan5:ppc64el \ + libasound2-dev:ppc64el \ + libattr1-dev:ppc64el \ + libbpf-dev:ppc64el \ + libbrlapi-dev:ppc64el \ + libbz2-dev:ppc64el \ + libc6-dev:ppc64el \ + libcacard-dev:ppc64el \ + libcap-ng-dev:ppc64el \ + libcapstone-dev:ppc64el \ + libcmocka-dev:ppc64el \ + libcurl4-gnutls-dev:ppc64el \ + libdaxctl-dev:ppc64el \ + libdrm-dev:ppc64el \ + libepoxy-dev:ppc64el \ + libfdt-dev:ppc64el \ + libffi-dev:ppc64el \ + libfuse3-dev:ppc64el \ + libgbm-dev:ppc64el \ + libgcrypt20-dev:ppc64el \ + libglib2.0-dev:ppc64el \ + libglusterfs-dev:ppc64el \ + libgnutls28-dev:ppc64el \ + libgtk-3-dev:ppc64el \ + libibumad-dev:ppc64el \ + libibverbs-dev:ppc64el \ + libiscsi-dev:ppc64el \ + libjemalloc-dev:ppc64el \ + libjpeg62-turbo-dev:ppc64el \ + libjson-c-dev:ppc64el \ + liblttng-ust-dev:ppc64el \ + liblzo2-dev:ppc64el \ + libncursesw5-dev:ppc64el \ + libnfs-dev:ppc64el \ + libnuma-dev:ppc64el \ + libpam0g-dev:ppc64el \ + libpixman-1-dev:ppc64el \ + libpng-dev:ppc64el \ + libpulse-dev:ppc64el \ + librbd-dev:ppc64el \ + librdmacm-dev:ppc64el \ + libsasl2-dev:ppc64el \ + libsdl2-dev:ppc64el \ + libsdl2-image-dev:ppc64el \ + libseccomp-dev:ppc64el \ + libselinux1-dev:ppc64el \ + libslirp-dev:ppc64el \ + libsnappy-dev:ppc64el \ + libspice-server-dev:ppc64el \ + libssh-gcrypt-dev:ppc64el \ + libsystemd-dev:ppc64el \ + libtasn1-6-dev:ppc64el \ + libubsan1:ppc64el \ + libudev-dev:ppc64el \ + liburing-dev:ppc64el \ + libusb-1.0-0-dev:ppc64el \ + libusbredirhost-dev:ppc64el \ + libvdeplug-dev:ppc64el \ + libvirglrenderer-dev:ppc64el \ + libvte-2.91-dev:ppc64el \ + libzstd-dev:ppc64el \ + nettle-dev:ppc64el \ + systemtap-sdt-dev:ppc64el \ + xfslibs-dev:ppc64el \ + zlib1g-dev:ppc64el && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/powerpc64le-linux-gnu-gcc'\n\ +ar = '/usr/bin/powerpc64le-linux-gnu-gcc-ar'\n\ +strip = '/usr/bin/powerpc64le-linux-gnu-strip'\n\ +pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'ppc64'\n\ +cpu = 'powerpc64le'\n\ +endian = 'little'" > /usr/local/share/meson/cross/powerpc64le-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/powerpc64le-linux-gnu-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-gcc + +ENV ABI "powerpc64le-linux-gnu" +ENV MESON_OPTS "--cross-file=powerpc64le-linux-gnu" ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu- ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user - -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:ppc64el \ - liblzo2-dev:ppc64el \ - librdmacm-dev:ppc64el \ - libsnappy-dev:ppc64el diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 594d97982c17..9715791e0b72 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 1d909012980f..e5f83a5aebbf 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 aa1bd6eb4c40..d43ce163172e 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -11,60 +11,63 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get install -y eatmydata && \ eatmydata apt-get dist-upgrade -y && \ eatmydata apt-get install --no-install-recommends -y \ - bash \ - bc \ - bsdextrautils \ - bzip2 \ - ca-certificates \ - ccache \ - dbus \ - debianutils \ - diffutils \ - exuberant-ctags \ - findutils \ - gcovr \ - genisoimage \ - gettext \ - git \ - hostname \ - libpcre2-dev \ - libspice-protocol-dev \ - libtest-harness-perl \ - 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 && \ + 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 \ + libsndio-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 CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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 s390x && \ @@ -72,71 +75,73 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ 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++-s390x-linux-gnu \ - gcc-s390x-linux-gnu \ - libaio-dev:s390x \ - libasan5:s390x \ - libasound2-dev:s390x \ - libattr1-dev:s390x \ - libbpf-dev:s390x \ - libbrlapi-dev:s390x \ - libbz2-dev:s390x \ - libc6-dev:s390x \ - libcacard-dev:s390x \ - libcap-ng-dev:s390x \ - libcapstone-dev:s390x \ - libcurl4-gnutls-dev:s390x \ - libdaxctl-dev:s390x \ - libdrm-dev:s390x \ - libepoxy-dev:s390x \ - libfdt-dev:s390x \ - libffi-dev:s390x \ - libfuse3-dev:s390x \ - libgbm-dev:s390x \ - libgcrypt20-dev:s390x \ - libglib2.0-dev:s390x \ - libglusterfs-dev:s390x \ - libgnutls28-dev:s390x \ - libgtk-3-dev:s390x \ - libibumad-dev:s390x \ - libibverbs-dev:s390x \ - libiscsi-dev:s390x \ - libjemalloc-dev:s390x \ - libjpeg62-turbo-dev:s390x \ - liblttng-ust-dev:s390x \ - liblzo2-dev:s390x \ - libncursesw5-dev:s390x \ - libnfs-dev:s390x \ - libnuma-dev:s390x \ - libpam0g-dev:s390x \ - libpixman-1-dev:s390x \ - libpng-dev:s390x \ - libpulse-dev:s390x \ - librbd-dev:s390x \ - librdmacm-dev:s390x \ - libsasl2-dev:s390x \ - libsdl2-dev:s390x \ - libsdl2-image-dev:s390x \ - libseccomp-dev:s390x \ - libselinux1-dev:s390x \ - libslirp-dev:s390x \ - libsnappy-dev:s390x \ - libssh-gcrypt-dev:s390x \ - libsystemd-dev:s390x \ - libtasn1-6-dev:s390x \ - libubsan1:s390x \ - libudev-dev:s390x \ - liburing-dev:s390x \ - libusb-1.0-0-dev:s390x \ - libusbredirhost-dev:s390x \ - libvdeplug-dev:s390x \ - libvirglrenderer-dev:s390x \ - libvte-2.91-dev:s390x \ - libzstd-dev:s390x \ - nettle-dev:s390x \ - systemtap-sdt-dev:s390x \ - xfslibs-dev:s390x \ - zlib1g-dev:s390x && \ + g++-s390x-linux-gnu \ + gcc-s390x-linux-gnu \ + libaio-dev:s390x \ + libasan5:s390x \ + libasound2-dev:s390x \ + libattr1-dev:s390x \ + libbpf-dev:s390x \ + libbrlapi-dev:s390x \ + libbz2-dev:s390x \ + libc6-dev:s390x \ + libcacard-dev:s390x \ + libcap-ng-dev:s390x \ + libcapstone-dev:s390x \ + libcmocka-dev:s390x \ + libcurl4-gnutls-dev:s390x \ + libdaxctl-dev:s390x \ + libdrm-dev:s390x \ + libepoxy-dev:s390x \ + libfdt-dev:s390x \ + libffi-dev:s390x \ + libfuse3-dev:s390x \ + libgbm-dev:s390x \ + libgcrypt20-dev:s390x \ + libglib2.0-dev:s390x \ + libglusterfs-dev:s390x \ + libgnutls28-dev:s390x \ + libgtk-3-dev:s390x \ + libibumad-dev:s390x \ + libibverbs-dev:s390x \ + libiscsi-dev:s390x \ + libjemalloc-dev:s390x \ + libjpeg62-turbo-dev:s390x \ + libjson-c-dev:s390x \ + liblttng-ust-dev:s390x \ + liblzo2-dev:s390x \ + libncursesw5-dev:s390x \ + libnfs-dev:s390x \ + libnuma-dev:s390x \ + libpam0g-dev:s390x \ + libpixman-1-dev:s390x \ + libpng-dev:s390x \ + libpulse-dev:s390x \ + librbd-dev:s390x \ + librdmacm-dev:s390x \ + libsasl2-dev:s390x \ + libsdl2-dev:s390x \ + libsdl2-image-dev:s390x \ + libseccomp-dev:s390x \ + libselinux1-dev:s390x \ + libslirp-dev:s390x \ + libsnappy-dev:s390x \ + libssh-gcrypt-dev:s390x \ + libsystemd-dev:s390x \ + libtasn1-6-dev:s390x \ + libubsan1:s390x \ + libudev-dev:s390x \ + liburing-dev:s390x \ + libusb-1.0-0-dev:s390x \ + libusbredirhost-dev:s390x \ + libvdeplug-dev:s390x \ + libvirglrenderer-dev:s390x \ + libvte-2.91-dev:s390x \ + libzstd-dev:s390x \ + nettle-dev:s390x \ + systemtap-sdt-dev:s390x \ + xfslibs-dev:s390x \ + zlib1g-dev:s390x && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ mkdir -p /usr/local/share/meson/cross && \ diff --git a/tests/docker/dockerfiles/debian-sh4-cross.docker b/tests/docker/dockerfiles/debian-sh4-cross.docker index fd3af8957596..d48ed9065f5c 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 f4bb9b561cfa..8d3d306bc173 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 738d808aa652..d3d4d3344eba 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/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index 3f6b55562c94..b573b9ded235 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -25,7 +25,6 @@ RUN apt update && \ git \ libglib2.0-dev \ libpixman-1-dev \ - libtest-harness-perl \ locales \ make \ ninja-build \ diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker deleted file mode 100644 index b414af1b9f72..000000000000 --- a/tests/docker/dockerfiles/debian10.docker +++ /dev/null @@ -1,37 +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 \ - $(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 febf884f8fde..000000000000 --- 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/empty.docker b/tests/docker/dockerfiles/empty.docker deleted file mode 100644 index 9ba980f1a866..000000000000 --- a/tests/docker/dockerfiles/empty.docker +++ /dev/null @@ -1,8 +0,0 @@ -# -# Empty Dockerfile -# - -FROM scratch - -# Add everything from the context into the container -ADD . / diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 13328e6081f9..7eec648d2d7d 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 \ @@ -20,7 +22,6 @@ ENV PACKAGES \ gnutls-devel.i686 \ nettle-devel.i686 \ pcre-devel.i686 \ - perl-Test-Harness \ pixman-devel.i686 \ sysprof-capture-devel.i686 \ zlib-devel.i686 diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index d80e66c6517d..75383ba185a4 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -1,44 +1,103 @@ -FROM registry.fedoraproject.org/fedora:33 +# THIS FILE WAS AUTO-GENERATED +# +# $ lcitool dockerfile --layers all --cross mingw32 fedora-35 qemu +# +# https://gitlab.com/libvirt/libvirt-ci -# Please keep this list sorted alphabetically -ENV PACKAGES \ - bc \ - bzip2 \ - ccache \ - diffutils \ - findutils \ - gcc \ - gettext \ - git \ - hostname \ - make \ - meson \ - mingw32-bzip2 \ - mingw32-curl \ - mingw32-glib2 \ - mingw32-gmp \ - mingw32-gnutls \ - mingw32-gtk3 \ - mingw32-libffi \ - mingw32-libjpeg-turbo \ - mingw32-libpng \ - mingw32-libtasn1 \ - mingw32-libusbx \ - mingw32-nettle \ - mingw32-nsis \ - mingw32-pixman \ - mingw32-pkg-config \ - mingw32-SDL2 \ - msitools \ - perl \ - perl-Test-Harness \ - python3 \ - python3-PyYAML \ - tar \ - which +FROM registry.fedoraproject.org/fedora:35 -RUN dnf install -y $PACKAGES -RUN rpm -q $PACKAGES | sort > /packages.txt +RUN dnf install -y nosync && \ + echo -e '#!/bin/sh\n\ +if test -d /usr/lib64\n\ +then\n\ + export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ +else\n\ + export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ +fi\n\ +exec "$@"' > /usr/bin/nosync && \ + chmod +x /usr/bin/nosync && \ + nosync dnf update -y && \ + nosync dnf install -y \ + bash \ + bc \ + bison \ + bzip2 \ + ca-certificates \ + ccache \ + ctags \ + dbus-daemon \ + diffutils \ + findutils \ + flex \ + gcovr \ + genisoimage \ + git \ + glib2-devel \ + glibc-langpack-en \ + hostname \ + llvm \ + make \ + meson \ + ninja-build \ + nmap-ncat \ + openssh-clients \ + pcre-static \ + perl-base \ + python3 \ + python3-PyYAML \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx_rtd_theme \ + rpm \ + sed \ + sparse \ + spice-protocol \ + tar \ + tesseract \ + tesseract-langpack-eng \ + texinfo \ + util-linux \ + which && \ + nosync dnf autoremove -y && \ + nosync dnf clean all -y -# Specify the cross prefix for this image (see tests/docker/common.rc) +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" + +RUN nosync dnf install -y \ + mingw32-SDL2 \ + mingw32-SDL2_image \ + mingw32-bzip2 \ + mingw32-curl \ + mingw32-gcc \ + mingw32-gcc-c++ \ + mingw32-gettext \ + mingw32-glib2 \ + mingw32-gnutls \ + mingw32-gtk3 \ + mingw32-libgcrypt \ + mingw32-libjpeg-turbo \ + mingw32-libpng \ + mingw32-libtasn1 \ + mingw32-nettle \ + mingw32-nsis \ + mingw32-pixman \ + mingw32-pkg-config && \ + nosync dnf clean all -y && \ + rpm -qa | sort > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-w64-mingw32-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-w64-mingw32-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-w64-mingw32-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/i686-w64-mingw32-gcc + +ENV ABI "i686-w64-mingw32" +ENV MESON_OPTS "--cross-file=/usr/share/mingw/toolchain-mingw32.meson" ENV QEMU_CONFIGURE_OPTS --cross-prefix=i686-w64-mingw32- +ENV DEF_TARGET_LIST i386-softmmu diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index 2b12b94ccfb4..98c03dc13b9c 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -1,41 +1,103 @@ -FROM registry.fedoraproject.org/fedora:33 +# THIS FILE WAS AUTO-GENERATED +# +# $ lcitool dockerfile --layers all --cross mingw64 fedora-35 qemu +# +# https://gitlab.com/libvirt/libvirt-ci -# Please keep this list sorted alphabetically -ENV PACKAGES \ - bc \ - bzip2 \ - ccache \ - diffutils \ - findutils \ - gcc \ - gettext \ - git \ - hostname \ - make \ - meson \ - mingw32-nsis \ - mingw64-bzip2 \ - mingw64-curl \ - mingw64-glib2 \ - mingw64-gmp \ - mingw64-gtk3 \ - mingw64-libffi \ - mingw64-libjpeg-turbo \ - mingw64-libpng \ - mingw64-libtasn1 \ - mingw64-libusbx \ - mingw64-pixman \ - mingw64-pkg-config \ - msitools \ - perl \ - perl-Test-Harness \ - python3 \ - python3-PyYAML \ - tar \ - which +FROM registry.fedoraproject.org/fedora:35 -RUN dnf install -y $PACKAGES -RUN rpm -q $PACKAGES | sort > /packages.txt +RUN dnf install -y nosync && \ + echo -e '#!/bin/sh\n\ +if test -d /usr/lib64\n\ +then\n\ + export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\ +else\n\ + export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\ +fi\n\ +exec "$@"' > /usr/bin/nosync && \ + chmod +x /usr/bin/nosync && \ + nosync dnf update -y && \ + nosync dnf install -y \ + bash \ + bc \ + bison \ + bzip2 \ + ca-certificates \ + ccache \ + ctags \ + dbus-daemon \ + diffutils \ + findutils \ + flex \ + gcovr \ + genisoimage \ + git \ + glib2-devel \ + glibc-langpack-en \ + hostname \ + llvm \ + make \ + meson \ + ninja-build \ + nmap-ncat \ + openssh-clients \ + pcre-static \ + perl-base \ + python3 \ + python3-PyYAML \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx_rtd_theme \ + rpm \ + sed \ + sparse \ + spice-protocol \ + tar \ + tesseract \ + tesseract-langpack-eng \ + texinfo \ + util-linux \ + which && \ + nosync dnf autoremove -y && \ + nosync dnf clean all -y -# Specify the cross prefix for this image (see tests/docker/common.rc) -ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-w64-mingw32- --disable-capstone +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" + +RUN nosync dnf install -y \ + mingw32-nsis \ + mingw64-SDL2 \ + mingw64-SDL2_image \ + mingw64-bzip2 \ + mingw64-curl \ + mingw64-gcc \ + mingw64-gcc-c++ \ + mingw64-gettext \ + mingw64-glib2 \ + mingw64-gnutls \ + mingw64-gtk3 \ + mingw64-libgcrypt \ + mingw64-libjpeg-turbo \ + mingw64-libpng \ + mingw64-libtasn1 \ + mingw64-nettle \ + mingw64-pixman \ + mingw64-pkg-config && \ + nosync dnf clean all -y && \ + rpm -qa | sort > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-w64-mingw32-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-w64-mingw32-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-w64-mingw32-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-w64-mingw32-gcc + +ENV ABI "x86_64-w64-mingw32" +ENV MESON_OPTS "--cross-file=/usr/share/mingw/toolchain-mingw64.meson" +ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-w64-mingw32- +ENV DEF_TARGET_LIST x86_64-softmmu diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 1d01cd94405e..d200c7fc1055 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -18,118 +18,120 @@ exec "$@"' > /usr/bin/nosync && \ chmod +x /usr/bin/nosync && \ nosync dnf update -y && \ nosync dnf install -y \ - SDL2-devel \ - SDL2_image-devel \ - alsa-lib-devel \ - bash \ - bc \ - brlapi-devel \ - bzip2 \ - bzip2-devel \ - ca-certificates \ - capstone-devel \ - ccache \ - clang \ - ctags \ - cyrus-sasl-devel \ - daxctl-devel \ - dbus-daemon \ - device-mapper-multipath-devel \ - diffutils \ - findutils \ - fuse3-devel \ - gcc \ - gcc-c++ \ - gcovr \ - genisoimage \ - gettext \ - git \ - glib2-devel \ - glib2-static \ - glibc-langpack-en \ - glibc-static \ - glusterfs-api-devel \ - gnutls-devel \ - gtk3-devel \ - hostname \ - jemalloc-devel \ - libaio-devel \ - libasan \ - libattr-devel \ - libbpf-devel \ - libcacard-devel \ - libcap-ng-devel \ - libcurl-devel \ - libdrm-devel \ - libepoxy-devel \ - libfdt-devel \ - libffi-devel \ - libgcrypt-devel \ - libiscsi-devel \ - libjpeg-devel \ - libnfs-devel \ - libpmem-devel \ - libpng-devel \ - librbd-devel \ - libseccomp-devel \ - libselinux-devel \ - libslirp-devel \ - libssh-devel \ - libtasn1-devel \ - libubsan \ - liburing-devel \ - libusbx-devel \ - libzstd-devel \ - llvm \ - lttng-ust-devel \ - lzo-devel \ - make \ - mesa-libgbm-devel \ - meson \ - ncurses-devel \ - nettle-devel \ - ninja-build \ - nmap-ncat \ - numactl-devel \ - openssh-clients \ - pam-devel \ - pcre-static \ - perl-Test-Harness \ - perl-base \ - pixman-devel \ - pkgconfig \ - pulseaudio-libs-devel \ - python3 \ - python3-PyYAML \ - python3-numpy \ - python3-opencv \ - python3-pillow \ - python3-pip \ - python3-sphinx \ - python3-sphinx_rtd_theme \ - python3-virtualenv \ - rdma-core-devel \ - rpm \ - sed \ - snappy-devel \ - sparse \ - spice-protocol \ - spice-server-devel \ - systemd-devel \ - systemtap-sdt-devel \ - tar \ - tesseract \ - tesseract-langpack-eng \ - texinfo \ - usbredir-devel \ - util-linux \ - virglrenderer-devel \ - vte291-devel \ - which \ - xen-devel \ - xfsprogs-devel \ - zlib-devel \ - zlib-static && \ + SDL2-devel \ + SDL2_image-devel \ + alsa-lib-devel \ + bash \ + bc \ + bison \ + brlapi-devel \ + bzip2 \ + bzip2-devel \ + ca-certificates \ + capstone-devel \ + ccache \ + clang \ + ctags \ + cyrus-sasl-devel \ + daxctl-devel \ + dbus-daemon \ + device-mapper-multipath-devel \ + diffutils \ + findutils \ + flex \ + fuse3-devel \ + gcc \ + gcc-c++ \ + gcovr \ + genisoimage \ + gettext \ + git \ + glib2-devel \ + glib2-static \ + glibc-langpack-en \ + glibc-static \ + glusterfs-api-devel \ + gnutls-devel \ + 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 \ + libfdt-devel \ + libffi-devel \ + libgcrypt-devel \ + libiscsi-devel \ + libjpeg-devel \ + libnfs-devel \ + libpmem-devel \ + libpng-devel \ + librbd-devel \ + libseccomp-devel \ + libselinux-devel \ + libslirp-devel \ + libssh-devel \ + libtasn1-devel \ + libubsan \ + liburing-devel \ + libusbx-devel \ + libzstd-devel \ + llvm \ + lttng-ust-devel \ + lzo-devel \ + make \ + mesa-libgbm-devel \ + meson \ + ncurses-devel \ + nettle-devel \ + ninja-build \ + nmap-ncat \ + numactl-devel \ + openssh-clients \ + pam-devel \ + pcre-static \ + perl-base \ + pixman-devel \ + pkgconfig \ + pulseaudio-libs-devel \ + python3 \ + python3-PyYAML \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx_rtd_theme \ + rdma-core-devel \ + rpm \ + sed \ + snappy-devel \ + sparse \ + spice-protocol \ + spice-server-devel \ + systemd-devel \ + systemtap-sdt-devel \ + tar \ + tesseract \ + tesseract-langpack-eng \ + texinfo \ + usbredir-devel \ + util-linux \ + virglrenderer-devel \ + vte291-devel \ + which \ + xen-devel \ + xfsprogs-devel \ + zlib-devel \ + zlib-static && \ nosync dnf autoremove -y && \ nosync dnf clean all -y && \ rpm -qa | sort > /packages.txt && \ @@ -140,8 +142,8 @@ exec "$@"' > /usr/bin/nosync && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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" diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index e1ad9434a355..4361b01464af 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 \ @@ -83,7 +88,6 @@ RUN zypper update -y && \ openssh \ pam-devel \ pcre-devel-static \ - perl-Test-Harness \ perl-base \ pkgconfig \ python3-Pillow \ @@ -95,12 +99,12 @@ RUN zypper update -y && \ python3-pip \ python3-setuptools \ python3-sphinx_rtd_theme \ - python3-virtualenv \ python3-wheel \ rdma-core-devel \ rpm \ sed \ snappy-devel \ + sndio-devel \ sparse \ spice-protocol-devel \ systemd-devel \ @@ -127,10 +131,10 @@ 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 CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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" diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker deleted file mode 100644 index 0a622b467c41..000000000000 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ /dev/null @@ -1,145 +0,0 @@ -# THIS FILE WAS AUTO-GENERATED -# -# $ lcitool dockerfile --layers all ubuntu-1804 qemu -# -# https://gitlab.com/libvirt/libvirt-ci - -FROM docker.io/library/ubuntu:18.04 - -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 \ - bsdmainutils \ - bzip2 \ - ca-certificates \ - ccache \ - clang \ - dbus \ - debianutils \ - diffutils \ - exuberant-ctags \ - findutils \ - g++ \ - gcc \ - gcovr \ - genisoimage \ - gettext \ - git \ - glusterfs-common \ - hostname \ - libaio-dev \ - libasan5 \ - libasound2-dev \ - libattr1-dev \ - libbrlapi-dev \ - libbz2-dev \ - libc6-dev \ - libcacard-dev \ - libcap-ng-dev \ - libcapstone-dev \ - libcurl4-gnutls-dev \ - libdaxctl-dev \ - libdrm-dev \ - libepoxy-dev \ - libfdt-dev \ - libffi-dev \ - libgbm-dev \ - libgcrypt20-dev \ - libglib2.0-dev \ - libgnutls28-dev \ - libgtk-3-dev \ - libibumad-dev \ - libibverbs-dev \ - libiscsi-dev \ - libjemalloc-dev \ - libjpeg-turbo8-dev \ - liblttng-ust-dev \ - liblzo2-dev \ - libncursesw5-dev \ - libnfs-dev \ - libnuma-dev \ - libpam0g-dev \ - libpcre2-dev \ - libpixman-1-dev \ - libpmem-dev \ - libpng-dev \ - libpulse-dev \ - librbd-dev \ - librdmacm-dev \ - libsasl2-dev \ - libsdl2-dev \ - libsdl2-image-dev \ - libseccomp-dev \ - libselinux1-dev \ - libsnappy-dev \ - libspice-protocol-dev \ - libspice-server-dev \ - libssh-dev \ - libsystemd-dev \ - libtasn1-6-dev \ - libtest-harness-perl \ - libubsan1 \ - libudev-dev \ - libusb-1.0-0-dev \ - libusbredirhost-dev \ - libvdeplug-dev \ - libvirglrenderer-dev \ - libvte-2.91-dev \ - libxen-dev \ - libzstd-dev \ - llvm \ - locales \ - make \ - multipath-tools \ - netcat-openbsd \ - nettle-dev \ - ninja-build \ - openssh-client \ - perl-base \ - pkgconf \ - python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ - python3-pip \ - python3-setuptools \ - python3-sphinx \ - python3-sphinx-rtd-theme \ - python3-venv \ - python3-wheel \ - python3-yaml \ - rpm2cpio \ - sed \ - sparse \ - systemtap-sdt-dev \ - tar \ - tesseract-ocr \ - tesseract-ocr-eng \ - texinfo \ - xfslibs-dev \ - zlib1g-dev && \ - eatmydata apt-get autoremove -y && \ - eatmydata apt-get autoclean -y && \ - sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ - dpkg-reconfigure locales && \ - 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/c++ && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ - 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 - -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" -# https://bugs.launchpad.net/qemu/+bug/1838763 -ENV QEMU_CONFIGURE_OPTS --disable-libssh diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index b9d06cb04065..9417bca2fa23 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -11,119 +11,123 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get install -y eatmydata && \ eatmydata apt-get dist-upgrade -y && \ eatmydata apt-get install --no-install-recommends -y \ - bash \ - bc \ - bsdmainutils \ - bzip2 \ - ca-certificates \ - ccache \ - clang \ - dbus \ - debianutils \ - diffutils \ - exuberant-ctags \ - findutils \ - g++ \ - gcc \ - gcovr \ - genisoimage \ - gettext \ - git \ - hostname \ - libaio-dev \ - libasan5 \ - libasound2-dev \ - libattr1-dev \ - libbrlapi-dev \ - libbz2-dev \ - libc6-dev \ - libcacard-dev \ - libcap-ng-dev \ - libcapstone-dev \ - libcurl4-gnutls-dev \ - libdaxctl-dev \ - libdrm-dev \ - libepoxy-dev \ - libfdt-dev \ - libffi-dev \ - libfuse3-dev \ - libgbm-dev \ - libgcrypt20-dev \ - libglib2.0-dev \ - libglusterfs-dev \ - libgnutls28-dev \ - libgtk-3-dev \ - libibumad-dev \ - libibverbs-dev \ - libiscsi-dev \ - libjemalloc-dev \ - libjpeg-turbo8-dev \ - liblttng-ust-dev \ - liblzo2-dev \ - libncursesw5-dev \ - libnfs-dev \ - libnuma-dev \ - libpam0g-dev \ - libpcre2-dev \ - libpixman-1-dev \ - libpmem-dev \ - libpng-dev \ - libpulse-dev \ - librbd-dev \ - librdmacm-dev \ - libsasl2-dev \ - libsdl2-dev \ - libsdl2-image-dev \ - libseccomp-dev \ - libselinux1-dev \ - libslirp-dev \ - libsnappy-dev \ - libspice-protocol-dev \ - libspice-server-dev \ - libssh-dev \ - libsystemd-dev \ - libtasn1-6-dev \ - libtest-harness-perl \ - libubsan1 \ - libudev-dev \ - libusb-1.0-0-dev \ - libusbredirhost-dev \ - libvdeplug-dev \ - libvirglrenderer-dev \ - libvte-2.91-dev \ - libxen-dev \ - libzstd-dev \ - llvm \ - locales \ - make \ - multipath-tools \ - ncat \ - nettle-dev \ - ninja-build \ - openssh-client \ - perl-base \ - pkgconf \ - python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ - python3-pip \ - python3-setuptools \ - python3-sphinx \ - python3-sphinx-rtd-theme \ - python3-venv \ - python3-wheel \ - python3-yaml \ - rpm2cpio \ - sed \ - sparse \ - systemtap-sdt-dev \ - tar \ - tesseract-ocr \ - tesseract-ocr-eng \ - texinfo \ - xfslibs-dev \ - zlib1g-dev && \ + bash \ + bc \ + bison \ + bsdmainutils \ + bzip2 \ + ca-certificates \ + ccache \ + clang \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + flex \ + g++ \ + gcc \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libaio-dev \ + libasan5 \ + libasound2-dev \ + libattr1-dev \ + libbrlapi-dev \ + libbz2-dev \ + libc6-dev \ + libcacard-dev \ + libcap-ng-dev \ + libcapstone-dev \ + libcmocka-dev \ + libcurl4-gnutls-dev \ + libdaxctl-dev \ + libdrm-dev \ + libepoxy-dev \ + libfdt-dev \ + libffi-dev \ + libfuse3-dev \ + libgbm-dev \ + libgcrypt20-dev \ + libglib2.0-dev \ + libglusterfs-dev \ + libgnutls28-dev \ + libgtk-3-dev \ + libibumad-dev \ + libibverbs-dev \ + libiscsi-dev \ + libjemalloc-dev \ + libjpeg-turbo8-dev \ + libjson-c-dev \ + liblttng-ust-dev \ + liblzo2-dev \ + libncursesw5-dev \ + libnfs-dev \ + libnuma-dev \ + libpam0g-dev \ + libpcre2-dev \ + libpixman-1-dev \ + libpmem-dev \ + libpng-dev \ + libpulse-dev \ + librbd-dev \ + librdmacm-dev \ + libsasl2-dev \ + libsdl2-dev \ + libsdl2-image-dev \ + libseccomp-dev \ + libselinux1-dev \ + libslirp-dev \ + libsnappy-dev \ + libsndio-dev \ + libspice-protocol-dev \ + libspice-server-dev \ + libssh-dev \ + libsystemd-dev \ + libtasn1-6-dev \ + libubsan1 \ + libudev-dev \ + libusb-1.0-0-dev \ + libusbredirhost-dev \ + libvdeplug-dev \ + libvirglrenderer-dev \ + libvte-2.91-dev \ + libxen-dev \ + libzstd-dev \ + llvm \ + locales \ + make \ + multipath-tools \ + ncat \ + nettle-dev \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-setuptools \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-wheel \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + systemtap-sdt-dev \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo \ + xfslibs-dev \ + zlib1g-dev && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ @@ -136,13 +140,13 @@ 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 CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" 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" # Apply patch https://reviews.llvm.org/D75820 # This is required for TSan in clang-10 to compile with QEMU. RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h diff --git a/tests/docker/run b/tests/docker/run index 421393046b70..9eb96129dacd 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/docker/test-mingw b/tests/docker/test-mingw index 0bc6d7887200..18366972eb07 100755 --- a/tests/docker/test-mingw +++ b/tests/docker/test-mingw @@ -13,14 +13,12 @@ . common.rc -requires_binary x86_64-w64-mingw32-gcc -requires_binary i686-w64-mingw32-gcc +requires_binary x86_64-w64-mingw32-gcc i686-w64-mingw32-gcc cd "$BUILD_DIR" -for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do - TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ - build_qemu --cross-prefix=$prefix \ +TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ +build_qemu \ --enable-trace-backends=simple \ --enable-gnutls \ --enable-nettle \ @@ -29,8 +27,6 @@ for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do --enable-bzip2 \ --enable-guest-agent \ --enable-docs - install_qemu - make installer - make clean - -done +install_qemu +make installer +make clean diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index c24baf85350a..8ce0ca1545d1 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -545,7 +545,8 @@ static int round_name_to_mode(const char *name) return -1; } -static void QEMU_NORETURN die_host_rounding(enum rounding rounding) +static G_NORETURN +void die_host_rounding(enum rounding rounding) { fprintf(stderr, "fatal: '%s' rounding not supported on this host\n", round_names[rounding]); diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index 352dd71c44fa..35829ad5f71e 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -921,7 +921,8 @@ static void parse_args(int argc, char *argv[]) } } -static void QEMU_NORETURN run_test(void) +static G_NORETURN +void run_test(void) { unsigned int i; diff --git a/tests/fp/meson.build b/tests/fp/meson.build index 8bd0979f67eb..312a4d301fd9 100644 --- a/tests/fp/meson.build +++ b/tests/fp/meson.build @@ -1,3 +1,6 @@ +if 'CONFIG_TCG' not in config_all + subdir_done() +endif # There are namespace pollution issues on Windows, due to osdep.h # bringing in Windows headers that define a FLOAT128 type. if targetos == 'windows' @@ -34,6 +37,7 @@ tfcflags = [ '-Wno-missing-prototypes', '-Wno-return-type', '-Wno-unused-function', + '-Wno-missing-format-attribute', '-Wno-error', ] @@ -629,7 +633,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/fp/platform.h b/tests/fp/platform.h index c20ba70baa07..6c72ad0cd05b 100644 --- a/tests/fp/platform.h +++ b/tests/fp/platform.h @@ -29,9 +29,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config-host.h" +#include "qemu/compiler.h" -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN #define LITTLEENDIAN 1 /* otherwise do not define it */ #endif diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py index 2e58795a1008..d865e46ecddc 100755 --- a/tests/guest-debug/run-test.py +++ b/tests/guest-debug/run-test.py @@ -92,17 +92,18 @@ def log(output, msg): result = subprocess.call(gdb_cmd, shell=True, stdout=output) - # A negative result is the result of an internal gdb failure like - # a crash. We force a return of 0 so we don't fail the test on + # A result of greater than 128 indicates a fatal signal (likely a + # crash due to gdb internal failure). That's a problem for GDB and + # not the test so we force a return of 0 so we don't fail the test on # account of broken external tools. - if result < 0: - print("GDB crashed? SKIPPING") + if result > 128: + log(output, "GDB crashed? (%d, %d) SKIPPING" % (result, result - 128)) exit(0) try: inferior.wait(2) except subprocess.TimeoutExpired: - print("GDB never connected? Killed guest") + log(output, "GDB never connected? Killed guest") inferior.kill() exit(result) diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index f83b916d5efa..e3eb28cf2e17 160000 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit f83b916d5efa4bd33fbf4b7ea41bf6d535cc63fb +Subproject commit e3eb28cf2e17fbcf7fe7e19505ee432b8ec5bbb5 diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index 958868a6ee94..c62dbc00f96b 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 @@ -79,7 +84,6 @@ packages: - pam - pcre-static - perl - - perl-Test-Harness - pixman - pkg-config - pulseaudio @@ -91,12 +95,13 @@ packages: - python3-pip - python3-sphinx - python3-sphinx-rtd-theme - - python3-virtualenv + - python3-venv - rpm2cpio - sdl2 - sdl2-image - sed - snappy + - sndio - sparse - spice-protocol - spice-server diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 2d198ad281a0..fa966e4009d5 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -13,100 +13,172 @@ # the top-level directory. import sys -import os import subprocess from pathlib import Path if len(sys.argv) != 1: - print("syntax: %s" % sys.argv[0], file=sys.stderr) - sys.exit(1) + print("syntax: %s" % sys.argv[0], file=sys.stderr) + sys.exit(1) 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] + def atomic_write(filename, content): - tmp = filename.with_suffix(filename.suffix + ".tmp") - try: - with tmp.open("w") as fp: - print(content, file=fp, end="") - tmp.rename(filename) - except Exception as ex: - tmp.unlink() - raise + tmp = filename.with_suffix(filename.suffix + ".tmp") + try: + with tmp.open("w") as fp: + print(content, file=fp, end="") + tmp.rename(filename) + except Exception as ex: + tmp.unlink() + raise + def generate(filename, cmd, trailer): - print("Generate %s" % filename) - lcitool=subprocess.run(cmd, capture_output=True) + print("Generate %s" % filename) + lcitool = subprocess.run(cmd, capture_output=True) + + if lcitool.returncode != 0: + raise Exception("Failed to generate %s: %s" % (filename, lcitool.stderr)) - if lcitool.returncode != 0: - raise Exception("Failed to generate %s: %s" % (filename, lcitool.stderr)) + content = lcitool.stdout.decode("utf8") + if trailer is not None: + content += trailer + atomic_write(filename, content) - content = lcitool.stdout.decode("utf8") - if trailer is not None: - content += trailer - atomic_write(filename, content) def generate_dockerfile(host, target, cross=None, trailer=None): - filename = Path(src_dir, "tests", "docker", "dockerfiles", host + ".docker") - cmd = lcitool_cmd + ["dockerfile"] - if cross is not None: - cmd.extend(["--cross", cross]) - cmd.extend([target, "qemu"]) - generate(filename, cmd, trailer) + filename = Path(src_dir, "tests", "docker", "dockerfiles", host + ".docker") + cmd = lcitool_cmd + ["dockerfile"] + if cross is not None: + cmd.extend(["--cross", cross]) + cmd.extend([target, "qemu"]) + generate(filename, cmd, trailer) + def generate_cirrus(target, trailer=None): - filename = Path(src_dir, ".gitlab-ci.d", "cirrus", target + ".vars") - cmd = lcitool_cmd + ["variables", target, "qemu"] - generate(filename, cmd, trailer) + filename = Path(src_dir, ".gitlab-ci.d", "cirrus", target + ".vars") + cmd = lcitool_cmd + ["variables", target, "qemu"] + generate(filename, cmd, trailer) -ubuntu1804_skipssh = [ - "# https://bugs.launchpad.net/qemu/+bug/1838763\n", - "ENV QEMU_CONFIGURE_OPTS --disable-libssh\n" -] ubuntu2004_tsanhack = [ - "# Apply patch https://reviews.llvm.org/D75820\n", - "# This is required for TSan in clang-10 to compile with QEMU.\n", - "RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h\n" + "# Apply patch https://reviews.llvm.org/D75820\n", + "# This is required for TSan in clang-10 to compile with QEMU.\n", + "RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h\n" ] -def debian_cross_build(prefix, targets): - conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix) - targets = "ENV DEF_TARGET_LIST %s\n" % (targets) - return "".join([conf, targets]) +# Netmap still needs to be manually built as it is yet to be packaged +# into a distro. We also add cscope and gtags which are used in the CI +# test +debian11_extras = [ + "# netmap/cscope/global\n", + "RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n", + " apt install -y --no-install-recommends \\\n", + " cscope\\\n", + " global\\\n", + " linux-headers-amd64\n", + "RUN git clone https://github.com/luigirizzo/netmap.git /usr/src/netmap\n", + "RUN cd /usr/src/netmap && git checkout v11.3\n", + "RUN cd /usr/src/netmap/LINUX && ./configure --no-drivers --no-apps --kernel-dir=$(ls -d /usr/src/linux-headers-*-amd64) && make install\n", + "ENV QEMU_CONFIGURE_OPTS --enable-netmap\n" +] + + +def cross_build(prefix, targets): + conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix) + targets = "ENV DEF_TARGET_LIST %s\n" % (targets) + return "".join([conf, targets]) + +# +# Update all the various build configurations. +# Please keep each group sorted alphabetically for easy reading. +# try: - generate_dockerfile("centos8", "centos-stream-8") - generate_dockerfile("fedora", "fedora-35") - generate_dockerfile("ubuntu1804", "ubuntu-1804", - trailer="".join(ubuntu1804_skipssh)) - generate_dockerfile("ubuntu2004", "ubuntu-2004", - trailer="".join(ubuntu2004_tsanhack)) - generate_dockerfile("opensuse-leap", "opensuse-leap-152") - generate_dockerfile("alpine", "alpine-edge") - - generate_dockerfile("debian-arm64-cross", "debian-11", - cross="aarch64", - trailer=debian_cross_build("aarch64-linux-gnu-", - "aarch64-softmmu,aarch64-linux-user")) - - generate_dockerfile("debian-s390x-cross", "debian-11", - cross="s390x", - trailer=debian_cross_build("s390x-linux-gnu-", - "s390x-softmmu,s390x-linux-user")) - - generate_cirrus("freebsd-12") - generate_cirrus("freebsd-13") - generate_cirrus("macos-11") - - sys.exit(0) + # + # Standard native builds + # + 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-153") + generate_dockerfile("ubuntu2004", "ubuntu-2004", + trailer="".join(ubuntu2004_tsanhack)) + + # + # Cross compiling builds + # + generate_dockerfile("debian-amd64-cross", "debian-11", + cross="x86_64", + trailer=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=cross_build("aarch64-linux-gnu-", + "aarch64-softmmu,aarch64-linux-user")) + + generate_dockerfile("debian-armel-cross", "debian-11", + cross="armv6l", + trailer=cross_build("arm-linux-gnueabi-", + "arm-softmmu,arm-linux-user,armeb-linux-user")) + + generate_dockerfile("debian-armhf-cross", "debian-11", + cross="armv7l", + trailer=cross_build("arm-linux-gnueabihf-", + "arm-softmmu,arm-linux-user")) + + generate_dockerfile("debian-mips64el-cross", "debian-11", + cross="mips64el", + trailer=cross_build("mips64el-linux-gnuabi64-", + "mips64el-softmmu,mips64el-linux-user")) + + generate_dockerfile("debian-mipsel-cross", "debian-11", + cross="mipsel", + trailer=cross_build("mipsel-linux-gnu-", + "mipsel-softmmu,mipsel-linux-user")) + + generate_dockerfile("debian-ppc64el-cross", "debian-11", + cross="ppc64le", + trailer=cross_build("powerpc64le-linux-gnu-", + "ppc64-softmmu,ppc64-linux-user")) + + generate_dockerfile("debian-s390x-cross", "debian-11", + cross="s390x", + trailer=cross_build("s390x-linux-gnu-", + "s390x-softmmu,s390x-linux-user")) + + generate_dockerfile("fedora-win32-cross", "fedora-35", + cross="mingw32", + trailer=cross_build("i686-w64-mingw32-", + "i386-softmmu")) + + generate_dockerfile("fedora-win64-cross", "fedora-35", + cross="mingw64", + trailer=cross_build("x86_64-w64-mingw32-", + "x86_64-softmmu")) + + # + # Cirrus packages lists for GitLab + # + generate_cirrus("freebsd-12") + generate_cirrus("freebsd-13") + generate_cirrus("macos-12") + + sys.exit(0) except Exception as ex: - print(str(ex), file=sys.stderr) - sys.exit(1) + print(str(ex), file=sys.stderr) + sys.exit(1) diff --git a/tests/meson.build b/tests/meson.build index 1d05109eb43c..8e318ec513aa 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,5 +1,3 @@ -py3 = import('python').find_installation() - subdir('bench') subdir('qemu-iotests') @@ -70,7 +68,7 @@ test_deps = { 'test-qht-par': qht_bench, } -if have_tools and 'CONFIG_VHOST_USER' in config_host and 'CONFIG_LINUX' in config_host +if have_tools and have_vhost_user and 'CONFIG_LINUX' in config_host executable('vhost-user-bridge', sources: files('vhost-user-bridge.c'), dependencies: [qemuutil, vhost_user]) diff --git a/tests/migration/aarch64/a-b-kernel.S b/tests/migration/aarch64/a-b-kernel.S index 02259453483b..a4103ecb712e 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 0a9b01137ea8..34e518d06171 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/guestperf/engine.py b/tests/migration/guestperf/engine.py index 87a6ab200908..59fca2c70b1e 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -65,7 +65,6 @@ def _vcpu_timing(self, pid, tid_list): return records def _cpu_timing(self, pid): - records = [] now = time.time() jiffies_per_sec = os.sysconf(os.sysconf_names['SC_CLK_TCK']) diff --git a/tests/migration/i386/a-b-bootblock.S b/tests/migration/i386/a-b-bootblock.S index 3f97f280233d..3d464c7568e4 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 7d459d4fde92..b7b0fce2ee1a 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 b7240a15c808..88acf8dc2579 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/alternate-array.err b/tests/qapi-schema/alternate-array.err index b1aa1f4e8d5a..e69de29bb2d1 100644 --- a/tests/qapi-schema/alternate-array.err +++ b/tests/qapi-schema/alternate-array.err @@ -1,2 +0,0 @@ -alternate-array.json: In alternate 'Alt': -alternate-array.json:5: 'data' member 'two' cannot be an array diff --git a/tests/qapi-schema/alternate-array.json b/tests/qapi-schema/alternate-array.json index f241aac1220b..b878a2db7709 100644 --- a/tests/qapi-schema/alternate-array.json +++ b/tests/qapi-schema/alternate-array.json @@ -1,5 +1,3 @@ -# we do not allow array branches in alternates -# TODO: should we support this? { 'struct': 'One', 'data': { 'name': 'str' } } { 'alternate': 'Alt', diff --git a/tests/qapi-schema/alternate-array.out b/tests/qapi-schema/alternate-array.out index e69de29bb2d1..a657d85738f7 100644 --- a/tests/qapi-schema/alternate-array.out +++ b/tests/qapi-schema/alternate-array.out @@ -0,0 +1,18 @@ +module ./builtin +object q_empty +enum QType + prefix QTYPE + member none + member qnull + member qnum + member qstring + member qdict + member qlist + member qbool +module alternate-array.json +object One + member name: str optional=False +alternate Alt + tag type + case one: One + case two: intList diff --git a/tests/qapi-schema/alternate-conflict-lists.err b/tests/qapi-schema/alternate-conflict-lists.err new file mode 100644 index 000000000000..f3374ec1e7a1 --- /dev/null +++ b/tests/qapi-schema/alternate-conflict-lists.err @@ -0,0 +1,2 @@ +alternate-conflict-lists.json: In alternate 'Alt': +alternate-conflict-lists.json:4: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-conflict-lists.json b/tests/qapi-schema/alternate-conflict-lists.json new file mode 100644 index 000000000000..a3efd6c50119 --- /dev/null +++ b/tests/qapi-schema/alternate-conflict-lists.json @@ -0,0 +1,6 @@ +# Two lists conflict even if their inner types would be compatible +{ 'struct': 'One', + 'data': { 'name': 'str' } } +{ 'alternate': 'Alt', + 'data': { 'one': [ 'int' ], + 'two': [ 'str' ] } } diff --git a/python/qemu/aqmp/py.typed b/tests/qapi-schema/alternate-conflict-lists.out similarity index 100% rename from python/qemu/aqmp/py.typed rename to tests/qapi-schema/alternate-conflict-lists.out diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index caf0791ba84a..9dfe98bc9a68 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -11,6 +11,7 @@ schemas = [ 'alternate-conflict-dict.json', 'alternate-conflict-enum-bool.json', 'alternate-conflict-enum-int.json', + 'alternate-conflict-lists.json', 'alternate-conflict-string.json', 'alternate-conflict-bool-string.json', 'alternate-conflict-num-string.json', @@ -214,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 @@ -276,10 +277,6 @@ if build_docs command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'], capture: true) - # "full_path()" needed here to work around - # https://github.com/mesonbuild/meson/issues/7585 - test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0].full_path(), - qapi_doc_out_nocr[0].full_path()], - depends: [qapi_doc_ref_nocr, qapi_doc_out_nocr], + test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0], qapi_doc_out_nocr[0]], suite: ['qapi-schema', 'qapi-doc']) endif diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 43b86970029b..ba7302f42b14 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -119,6 +119,7 @@ { 'alternate': 'AltEnumNum', 'data': { 'e': 'EnumOne', 'n': 'number' } } { 'alternate': 'AltNumEnum', 'data': { 'n': 'number', 'e': 'EnumOne' } } { 'alternate': 'AltEnumInt', 'data': { 'e': 'EnumOne', 'i': 'int' } } +{ 'alternate': 'AltListInt', 'data': { 'l': ['int'], 'i': 'int' } } # for testing use of 'str' within alternates { 'alternate': 'AltStrObj', 'data': { 's': 'str', 'o': 'TestStruct' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 1f9585fa9b89..043d75c6551a 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -121,6 +121,10 @@ alternate AltEnumInt tag type case e: EnumOne case i: int +alternate AltListInt + tag type + case l: intList + case i: int alternate AltStrObj tag type case s: str diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 18eddcc73446..98595d47fec3 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -64,16 +64,18 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), - qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), - 'image file map does not match backing file after streaming') + self.assertEqual( + qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, + 'image file map does not match backing file after streaming') def test_stream_intermediate(self): self.assert_no_active_block_jobs() - self.assertNotEqual(qemu_io('-f', 'raw', '-rU', '-c', 'map', backing_img), - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img), - 'image file map matches backing file before streaming') + self.assertNotEqual( + qemu_io('-f', 'raw', '-rU', '-c', 'map', backing_img).stdout, + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img).stdout, + 'image file map matches backing file before streaming') result = self.vm.qmp('block-stream', device='mid', job_id='stream-mid') self.assert_qmp(result, 'return', {}) @@ -83,9 +85,10 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), - qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), - 'image file map does not match backing file after streaming') + self.assertEqual( + qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img).stdout, + 'image file map does not match backing file after streaming') def test_stream_pause(self): self.assert_no_active_block_jobs() @@ -113,15 +116,17 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), - qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), - 'image file map does not match backing file after streaming') + self.assertEqual( + qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, + 'image file map does not match backing file after streaming') def test_stream_no_op(self): self.assert_no_active_block_jobs() # The image map is empty before the operation - empty_map = qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', test_img) + empty_map = qemu_io( + '-f', iotests.imgfmt, '-rU', '-c', 'map', test_img).stdout # This is a no-op: no data should ever be copied from the base image result = self.vm.qmp('block-stream', device='drive0', base=mid_img) @@ -132,8 +137,9 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), - empty_map, 'image file map changed after a no-op') + self.assertEqual( + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, + empty_map, 'image file map changed after a no-op') def test_stream_partial(self): self.assert_no_active_block_jobs() @@ -146,9 +152,10 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), - qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), - 'image file map does not match backing file after streaming') + self.assertEqual( + qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, + 'image file map does not match backing file after streaming') def test_device_not_found(self): result = self.vm.qmp('block-stream', device='nonexistent') @@ -236,9 +243,10 @@ class TestParallelOps(iotests.QMPTestCase): # Check that the maps don't match before the streaming operations for i in range(2, self.num_imgs, 2): - self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i]), - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i-1]), - 'image file map matches backing file before streaming') + self.assertNotEqual( + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i]).stdout, + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i-1]).stdout, + 'image file map matches backing file before streaming') # Create all streaming jobs pending_jobs = [] @@ -278,9 +286,10 @@ class TestParallelOps(iotests.QMPTestCase): # Check that all maps match now for i in range(2, self.num_imgs, 2): - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]), - qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]), - 'image file map does not match backing file after streaming') + self.assertEqual( + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]).stdout, + 'image file map does not match backing file after streaming') # Test that it's not possible to perform two block-stream # operations if there are nodes involved in both. @@ -514,9 +523,10 @@ class TestParallelOps(iotests.QMPTestCase): def test_stream_base_node_name(self): self.assert_no_active_block_jobs() - self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[4]), - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[3]), - 'image file map matches backing file before streaming') + self.assertNotEqual( + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[4]).stdout, + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[3]).stdout, + 'image file map matches backing file before streaming') # Error: the base node does not exist result = self.vm.qmp('block-stream', device='node4', base_node='none', job_id='stream') @@ -547,9 +557,10 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]), - qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]), - 'image file map matches backing file after streaming') + self.assertEqual( + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]).stdout, + 'image file map matches backing file after streaming') class TestQuorum(iotests.QMPTestCase): num_children = 3 @@ -588,9 +599,10 @@ class TestQuorum(iotests.QMPTestCase): os.remove(img) def test_stream_quorum(self): - self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.children[0]), - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.backing[0]), - 'image file map matches backing file before streaming') + self.assertNotEqual( + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.children[0]).stdout, + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.backing[0]).stdout, + 'image file map matches backing file before streaming') self.assert_no_active_block_jobs() @@ -602,9 +614,10 @@ class TestQuorum(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]), - qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]), - 'image file map does not match backing file after streaming') + self.assertEqual( + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]).stdout, + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]).stdout, + 'image file map does not match backing file after streaming') class TestSmallerBackingFile(iotests.QMPTestCase): backing_len = 1 * 1024 * 1024 # MB diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 0e1cfd7e49d1..30eb97829ea6 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -86,8 +86,10 @@ class TestSingleDrive(ImageCommitTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, '-F', iotests.imgfmt, test_img) - qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) + if self.image_len: + qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', + mid_img) self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none") self.vm.add_device('virtio-scsi') self.vm.add_device("scsi-hd,id=scsi0,drive=drive0") @@ -101,13 +103,17 @@ class TestSingleDrive(ImageCommitTestCase): def test_commit(self): self.run_commit_test(mid_img, backing_img) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + if not self.image_len: + return + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) def test_commit_node(self): self.run_commit_test("mid", "base", node_names=True) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + if not self.image_len: + return + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) @iotests.skip_if_unsupported(['throttle']) def test_commit_with_filter_and_quit(self): @@ -192,13 +198,17 @@ class TestSingleDrive(ImageCommitTestCase): def test_top_is_active(self): self.run_commit_test(test_img, backing_img, need_ready=True) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + if not self.image_len: + return + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) def test_top_is_default_active(self): self.run_default_commit_test() - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + if not self.image_len: + return + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) def test_top_and_base_reversed(self): self.assert_no_active_block_jobs() @@ -334,8 +344,8 @@ class TestRelativePaths(ImageCommitTestCase): def test_commit(self): self.run_commit_test(self.mid_img, self.backing_img) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs) + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs) def test_device_not_found(self): result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % self.mid_img) @@ -361,8 +371,8 @@ class TestRelativePaths(ImageCommitTestCase): def test_top_is_active(self): self.run_commit_test(self.test_img, self.backing_img) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs) + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs) def test_top_and_base_reversed(self): self.assert_no_active_block_jobs() @@ -738,11 +748,10 @@ class TestCommitWithFilters(iotests.QMPTestCase): def do_test_io(self, read_or_write): for index, pattern_file in enumerate(self.pattern_files): - result = qemu_io('-f', iotests.imgfmt, - '-c', - f'{read_or_write} -P {index + 1} {index}M 1M', - pattern_file) - self.assertFalse('Pattern verification failed' in result) + qemu_io('-f', iotests.imgfmt, + '-c', + f'{read_or_write} -P {index + 1} {index}M 1M', + pattern_file) @iotests.skip_if_unsupported(['throttle']) def setUp(self): @@ -827,7 +836,8 @@ class TestCommitWithFilters(iotests.QMPTestCase): job_id='commit', device='top-filter', top_node='cow-2', - base_node='cow-1') + base_node='cow-1', + backing_file=self.img1) self.assert_qmp(result, 'return', {}) self.wait_until_completed(drive='commit') @@ -843,7 +853,8 @@ class TestCommitWithFilters(iotests.QMPTestCase): job_id='commit', device='top-filter', top_node='cow-1', - base_node='cow-0') + base_node='cow-0', + backing_file=self.img0) self.assert_qmp(result, 'return', {}) self.wait_until_completed(drive='commit') diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index f1a506518b98..4c079b11e320 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -375,7 +375,8 @@ if [ "${VALGRIND_QEMU_VM}" == "y" ]; then _casenotrun "Valgrind needs a valid TMPDIR for itself" fi VALGRIND_QEMU_VM= \ -TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on +TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on | + sed -e "s#'[^']*/vl\.[A-Za-z0-9]\{6\}'#SNAPSHOT_PATH#g" # Using snapshot=on together with read-only=on echo "info block" | diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 441f83e41ab7..e5ddb03bda1d 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -459,7 +459,7 @@ wrote 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Testing: -drive driver=null-co,snapshot=on -QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory +QEMU_PROG: -drive driver=null-co,snapshot=on: Could not open temporary file SNAPSHOT_PATH: No such file or directory Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index 063e4fc5843e..bade1ff3b929 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -539,7 +539,7 @@ wrote 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Testing: -drive driver=null-co,snapshot=on -QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory +QEMU_PROG: -drive driver=null-co,snapshot=on: Could not open temporary file SNAPSHOT_PATH: No such file or directory Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index b459a3f1e88e..bef865eec486 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -102,7 +102,7 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase): self.vm.shutdown() time.sleep(1) - self.assertEqual(-1, qemu_io('-c', 'read -P0x41 0 512', target_img).find("verification failed")) + qemu_io('-c', 'read -P0x41 0 512', target_img) class TestBeforeWriteNotifier(iotests.QMPTestCase): def setUp(self): diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 index ba94e19349bc..b724c89c7c50 100755 --- a/tests/qemu-iotests/065 +++ b/tests/qemu-iotests/065 @@ -24,7 +24,7 @@ import os import re import json import iotests -from iotests import qemu_img, qemu_img_info +from iotests import qemu_img, qemu_img_info, supports_qcow2_zstd_compression import unittest test_img = os.path.join(iotests.test_dir, 'test.img') @@ -95,11 +95,17 @@ class TestQCow2(TestQemuImgInfo): class TestQCow3NotLazy(TestQemuImgInfo): '''Testing a qcow2 version 3 image with lazy refcounts disabled''' - img_options = 'compat=1.1,lazy_refcounts=off,compression_type=zstd' + if supports_qcow2_zstd_compression(): + compression_type = 'zstd' + else: + compression_type = 'zlib' + + img_options = 'compat=1.1,lazy_refcounts=off' + img_options += f',compression_type={compression_type}' json_compare = { 'compat': '1.1', 'lazy-refcounts': False, 'refcount-bits': 16, 'corrupt': False, - 'compression-type': 'zstd', 'extended-l2': False } - human_compare = [ 'compat: 1.1', 'compression type: zstd', + 'compression-type': compression_type, 'extended-l2': False } + human_compare = [ 'compat: 1.1', f'compression type: {compression_type}', 'lazy refcounts: false', 'refcount bits: 16', 'corrupt: false', 'extended l2: false' ] @@ -126,11 +132,17 @@ class TestQCow3NotLazyQMP(TestQMP): class TestQCow3LazyQMP(TestQMP): '''Testing a qcow2 version 3 image with lazy refcounts enabled, opening with lazy refcounts disabled''' - img_options = 'compat=1.1,lazy_refcounts=on,compression_type=zstd' + if supports_qcow2_zstd_compression(): + compression_type = 'zstd' + else: + compression_type = 'zlib' + + img_options = 'compat=1.1,lazy_refcounts=on' + img_options += f',compression_type={compression_type}' qemu_options = 'lazy-refcounts=off' compare = { 'compat': '1.1', 'lazy-refcounts': True, 'refcount-bits': 16, 'corrupt': False, - 'compression-type': 'zstd', 'extended-l2': False } + 'compression-type': compression_type, 'extended-l2': False } TestImageInfoSpecific = None TestQemuImgInfo = None diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108 index 56339ab2c5cf..54e935acf28a 100755 --- a/tests/qemu-iotests/108 +++ b/tests/qemu-iotests/108 @@ -30,13 +30,20 @@ status=1 # failure is the default! _cleanup() { - _cleanup_test_img + _cleanup_test_img + if [ -f "$TEST_DIR/qsd.pid" ]; then + qsd_pid=$(cat "$TEST_DIR/qsd.pid") + kill -KILL "$qsd_pid" + fusermount -u "$TEST_DIR/fuse-export" &>/dev/null + fi + rm -f "$TEST_DIR/fuse-export" } trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks . ./common.rc . ./common.filter +. ./common.qemu # This tests qcow2-specific low-level functionality _supported_fmt qcow2 @@ -47,6 +54,27 @@ _supported_os Linux # files _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file +# This test either needs sudo -n losetup or FUSE exports to work +if sudo -n losetup &>/dev/null; then + loopdev=true +else + loopdev=false + + # Check for usable FUSE in the host environment: + if test ! -c "/dev/fuse"; then + _notrun 'No passwordless sudo nor usable /dev/fuse' + fi + + # QSD --export fuse will either yield "Parameter 'id' is missing" + # or "Invalid parameter 'fuse'", depending on whether there is + # FUSE support or not. + error=$($QSD --export fuse 2>&1) + if [[ $error = *"'fuse'"* ]]; then + _notrun 'Passwordless sudo for losetup or FUSE support required, but' \ + 'neither is available' + fi +fi + echo echo '=== Repairing an image without any refcount table ===' echo @@ -138,6 +166,240 @@ _make_test_img 64M poke_file "$TEST_IMG" $((0x10008)) "\xff\xff\xff\xff\xff\xff\x00\x00" _check_test_img -r all +echo +echo '=== Check rebuilt reftable location ===' + +# In an earlier version of the refcount rebuild algorithm, the +# reftable was generally placed at the image end (unless something was +# allocated in the area covered by the refblock right before the image +# file end, then we would try to place the reftable in that refblock). +# This was later changed so the reftable would be placed in the +# earliest possible location. Test this. + +echo +echo '--- Does the image size increase? ---' +echo + +# First test: Just create some image, write some data to it, and +# resize it so there is free space at the end of the image (enough +# that it spans at least one full refblock, which for cluster_size=512 +# images, spans 128k). With the old algorithm, the reftable would +# have then been placed at the end of the image file, but with the new +# one, it will be put in that free space. +# We want to check whether the size of the image file increases due to +# rebuilding the refcount structures (it should not). + +_make_test_img -o 'cluster_size=512' 1M +# Write something +$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io + +# Add free space +file_len=$(stat -c '%s' "$TEST_IMG") +truncate -s $((file_len + 256 * 1024)) "$TEST_IMG" + +# Corrupt the image by saying the image header was not allocated +rt_offset=$(peek_file_be "$TEST_IMG" 48 8) +rb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8) +poke_file "$TEST_IMG" $rb_offset "\x00\x00" + +# Check whether rebuilding the refcount structures increases the image +# file size +file_len=$(stat -c '%s' "$TEST_IMG") +echo +# The only leaks there can be are the old refcount structures that are +# leaked during rebuilding, no need to clutter the output with them +_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0' +echo +post_repair_file_len=$(stat -c '%s' "$TEST_IMG") + +if [[ $file_len -eq $post_repair_file_len ]]; then + echo 'OK: Image size did not change' +else + echo 'ERROR: Image size differs' \ + "($file_len before, $post_repair_file_len after)" +fi + +echo +echo '--- Will the reftable occupy a hole specifically left for it? ---' +echo + +# Note: With cluster_size=512, every refblock covers 128k. +# The reftable covers 8M per reftable cluster. + +# Create an image that requires two reftable clusters (just because +# this is more interesting than a single-clustered reftable). +_make_test_img -o 'cluster_size=512' 9M +$QEMU_IO -c 'write 0 8M' "$TEST_IMG" | _filter_qemu_io + +# Writing 8M will have resized the reftable. Unfortunately, doing so +# will leave holes in the file, so we need to fill them up so we can +# be sure the whole file is allocated. Do that by writing +# consecutively smaller chunks starting from 8 MB, until the file +# length increases even with a chunk size of 512. Then we must have +# filled all holes. +ofs=$((8 * 1024 * 1024)) +block_len=$((16 * 1024)) +while [[ $block_len -ge 512 ]]; do + file_len=$(stat -c '%s' "$TEST_IMG") + while [[ $(stat -c '%s' "$TEST_IMG") -eq $file_len ]]; do + # Do not include this in the reference output, it does not + # really matter which qemu-io calls we do here exactly + $QEMU_IO -c "write $ofs $block_len" "$TEST_IMG" >/dev/null + ofs=$((ofs + block_len)) + done + block_len=$((block_len / 2)) +done + +# Fill up to 9M (do not include this in the reference output either, +# $ofs is random for all we know) +$QEMU_IO -c "write $ofs $((9 * 1024 * 1024 - ofs))" "$TEST_IMG" >/dev/null + +# Make space as follows: +# - For the first refblock: Right at the beginning of the image (this +# refblock is placed in the first place possible), +# - For the reftable somewhere soon afterwards, still near the +# beginning of the image (i.e. covered by the first refblock); the +# reftable too is placed in the first place possible, but only after +# all refblocks have been placed) +# No space is needed for the other refblocks, because no refblock is +# put before the space it covers. In this test case, we do not mind +# if they are placed at the image file's end. + +# Before we make that space, we have to find out the host offset of +# the area that belonged to the two data clusters at guest offset 4k, +# because we expect the reftable to be placed there, and we will have +# to verify that it is. + +l1_offset=$(peek_file_be "$TEST_IMG" 40 8) +l2_offset=$(peek_file_be "$TEST_IMG" $l1_offset 8) +l2_offset=$((l2_offset & 0x00fffffffffffe00)) +data_4k_offset=$(peek_file_be "$TEST_IMG" \ + $((l2_offset + 4096 / 512 * 8)) 8) +data_4k_offset=$((data_4k_offset & 0x00fffffffffffe00)) + +$QEMU_IO -c "discard 0 512" -c "discard 4k 1k" "$TEST_IMG" | _filter_qemu_io + +# Corrupt the image by saying the image header was not allocated +rt_offset=$(peek_file_be "$TEST_IMG" 48 8) +rb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8) +poke_file "$TEST_IMG" $rb_offset "\x00\x00" + +echo +# The only leaks there can be are the old refcount structures that are +# leaked during rebuilding, no need to clutter the output with them +_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0' +echo + +# Check whether the reftable was put where we expected +rt_offset=$(peek_file_be "$TEST_IMG" 48 8) +if [[ $rt_offset -eq $data_4k_offset ]]; then + echo 'OK: Reftable is where we expect it' +else + echo "ERROR: Reftable is at $rt_offset, but was expected at $data_4k_offset" +fi + +echo +echo '--- Rebuilding refcount structures on block devices ---' +echo + +# A block device cannot really grow, at least not during qemu-img +# check. As mentioned in the above cases, rebuilding the refcount +# structure may lead to new refcount structures being written after +# the end of the image, and in the past that happened even if there +# was more than sufficient space in the image. Such post-EOF writes +# will not work on block devices, so test that the new algorithm +# avoids it. + +# If we have passwordless sudo and losetup, we can use those to create +# a block device. Otherwise, we can resort to qemu's FUSE export to +# create a file that isn't growable, which effectively tests the same +# thing. + +_cleanup_test_img +truncate -s $((64 * 1024 * 1024)) "$TEST_IMG" + +if $loopdev; then + export_mp=$(sudo -n losetup --show -f "$TEST_IMG") + export_mp_driver=host_device + sudo -n chmod go+rw "$export_mp" +else + # Create non-growable FUSE export that is a bit like an empty + # block device + export_mp="$TEST_DIR/fuse-export" + export_mp_driver=file + touch "$export_mp" + + $QSD \ + --blockdev file,node-name=export-node,filename="$TEST_IMG" \ + --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=off,allow-other=off \ + --pidfile "$TEST_DIR/qsd.pid" \ + --daemonize +fi + +# Now create a qcow2 image on the device -- unfortunately, qemu-img +# create force-creates the file, so we have to resort to the +# blockdev-create job. +_launch_qemu \ + --blockdev $export_mp_driver,node-name=file,filename="$export_mp" + +_send_qemu_cmd \ + $QEMU_HANDLE \ + '{ "execute": "qmp_capabilities" }' \ + 'return' + +# Small cluster size again, so the image needs multiple refblocks +_send_qemu_cmd \ + $QEMU_HANDLE \ + '{ "execute": "blockdev-create", + "arguments": { + "job-id": "create", + "options": { + "driver": "qcow2", + "file": "file", + "size": '$((64 * 1024 * 1024))', + "cluster-size": 512 + } } }' \ + '"concluded"' + +_send_qemu_cmd \ + $QEMU_HANDLE \ + '{ "execute": "job-dismiss", "arguments": { "id": "create" } }' \ + 'return' + +_send_qemu_cmd \ + $QEMU_HANDLE \ + '{ "execute": "quit" }' \ + 'return' + +wait=y _cleanup_qemu +echo + +# Write some data +$QEMU_IO -c 'write 0 64k' "$export_mp" | _filter_qemu_io + +# Corrupt the image by saying the image header was not allocated +rt_offset=$(peek_file_be "$export_mp" 48 8) +rb_offset=$(peek_file_be "$export_mp" $rt_offset 8) +poke_file "$export_mp" $rb_offset "\x00\x00" + +# Repairing such a simple case should just work +# (We used to put the reftable at the end of the image file, which can +# never work for non-growable devices.) +echo +TEST_IMG="$export_mp" _check_test_img -r all \ + | grep -v '^Repairing cluster.*refcount=1 reference=0' + +if $loopdev; then + sudo -n losetup -d "$export_mp" +else + qsd_pid=$(cat "$TEST_DIR/qsd.pid") + kill -TERM "$qsd_pid" + # Wait for process to exit (cannot `wait` because the QSD is daemonized) + while [ -f "$TEST_DIR/qsd.pid" ]; do + true + done +fi + # success, all done echo '*** done' rm -f $seq.full diff --git a/tests/qemu-iotests/108.out b/tests/qemu-iotests/108.out index 75bab8dc84a1..b5401d788dc6 100644 --- a/tests/qemu-iotests/108.out +++ b/tests/qemu-iotests/108.out @@ -105,6 +105,87 @@ The following inconsistencies were found and repaired: 0 leaked clusters 1 corruptions +Double checking the fixed image now... +No errors were found on the image. + +=== Check rebuilt reftable location === + +--- Does the image size increase? --- + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +ERROR cluster 0 refcount=0 reference=1 +Rebuilding refcount structure +The following inconsistencies were found and repaired: + + 0 leaked clusters + 1 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +OK: Image size did not change + +--- Will the reftable occupy a hole specifically left for it? --- + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=9437184 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 1024/1024 bytes at offset 4096 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +ERROR cluster 0 refcount=0 reference=1 +Rebuilding refcount structure +The following inconsistencies were found and repaired: + + 0 leaked clusters + 1 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +OK: Reftable is where we expect it + +--- Rebuilding refcount structures on block devices --- + +{ "execute": "qmp_capabilities" } +{"return": {}} +{ "execute": "blockdev-create", + "arguments": { + "job-id": "create", + "options": { + "driver": "IMGFMT", + "file": "file", + "size": 67108864, + "cluster-size": 512 + } } } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "create"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "create"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "create"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "create"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "create"}} +{ "execute": "job-dismiss", "arguments": { "id": "create" } } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "create"}} +{"return": {}} +{ "execute": "quit" } +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +ERROR cluster 0 refcount=0 reference=1 +Rebuilding refcount structure +The following inconsistencies were found and repaired: + + 0 leaked clusters + 1 corruptions + Double checking the fixed image now... No errors were found on the image. *** done diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131 index d7456cae5bbb..a847692b4cb6 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 70da03dee522..de5ef7a8f570 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/149 b/tests/qemu-iotests/149 index 9bb96d6a1d1c..2ae318f16f01 100755 --- a/tests/qemu-iotests/149 +++ b/tests/qemu-iotests/149 @@ -295,7 +295,8 @@ def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] args.extend(qemu_io_image_args(config, dev)) iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) - iotests.log(check_cipher_support(config, iotests.qemu_io(*args)), + output = iotests.qemu_io(*args, check=False).stdout + iotests.log(check_cipher_support(config, output), filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) @@ -307,7 +308,8 @@ def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] args.extend(qemu_io_image_args(config, dev)) iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) - iotests.log(check_cipher_support(config, iotests.qemu_io(*args)), + output = iotests.qemu_io(*args, check=False).stdout + iotests.log(check_cipher_support(config, output), filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 index 93d14193d0c6..b4d1bc2553f8 100755 --- a/tests/qemu-iotests/151 +++ b/tests/qemu-iotests/151 @@ -19,7 +19,11 @@ # along with this program. If not, see . # +import math import os +import subprocess +import time +from typing import List, Optional import iotests from iotests import qemu_img @@ -50,7 +54,7 @@ class TestActiveMirror(iotests.QMPTestCase): self.vm = iotests.VM() self.vm.add_drive_raw(self.vm.qmp_to_opts(blk_source)) self.vm.add_blockdev(self.vm.qmp_to_opts(blk_target)) - self.vm.add_device('virtio-blk,drive=source') + self.vm.add_device('virtio-blk,id=vblk,drive=source') self.vm.launch() def tearDown(self): @@ -192,6 +196,227 @@ class TestActiveMirror(iotests.QMPTestCase): self.potential_writes_in_flight = False +class TestThrottledWithNbdExportBase(iotests.QMPTestCase): + image_len = 128 * 1024 * 1024 # MB + iops: Optional[int] = None + background_processes: List['subprocess.Popen[str]'] = [] + + def setUp(self): + # Must be set by subclasses + self.assertIsNotNone(self.iops) + + qemu_img('create', '-f', iotests.imgfmt, source_img, '128M') + qemu_img('create', '-f', iotests.imgfmt, target_img, '128M') + + self.vm = iotests.VM() + self.vm.launch() + + result = self.vm.qmp('object-add', **{ + 'qom-type': 'throttle-group', + 'id': 'thrgr', + 'limits': { + 'iops-total': self.iops, + 'iops-total-max': self.iops + } + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('blockdev-add', **{ + 'node-name': 'source-node', + 'driver': 'throttle', + 'throttle-group': 'thrgr', + 'file': { + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': source_img + } + } + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('blockdev-add', **{ + 'node-name': 'target-node', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': target_img + } + }) + self.assert_qmp(result, 'return', {}) + + self.nbd_sock = iotests.file_path('nbd.sock', + base_dir=iotests.sock_dir) + self.nbd_url = f'nbd+unix:///source-node?socket={self.nbd_sock}' + + result = self.vm.qmp('nbd-server-start', addr={ + 'type': 'unix', + 'data': { + 'path': self.nbd_sock + } + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('block-export-add', id='exp0', type='nbd', + node_name='source-node', writable=True) + self.assert_qmp(result, 'return', {}) + + def tearDown(self): + # Wait for background requests to settle + try: + while True: + p = self.background_processes.pop() + while True: + try: + p.wait(timeout=0.0) + break + except subprocess.TimeoutExpired: + self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') + except IndexError: + pass + + # Cancel ongoing block jobs + for job in self.vm.qmp('query-jobs')['return']: + self.vm.qmp('block-job-cancel', device=job['id'], force=True) + + while True: + self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') + if len(self.vm.qmp('query-jobs')['return']) == 0: + break + + self.vm.shutdown() + os.remove(source_img) + os.remove(target_img) + + +class TestLowThrottledWithNbdExport(TestThrottledWithNbdExportBase): + iops = 16 + + def testUnderLoad(self): + ''' + Throttle the source node, then issue a whole bunch of external requests + while the mirror job (in write-blocking mode) is running. We want to + see background requests being issued even while the source is under + full load by active writes, so that progress can be made towards READY. + ''' + + # Fill the first half of the source image; do not fill the second half, + # that is where we will have active requests occur. This ensures that + # active mirroring itself will not directly contribute to the job's + # progress (because when the job was started, those areas were not + # intended to be copied, so active mirroring will only lead to not + # losing progress, but also not making any). + self.vm.hmp_qemu_io('source-node', + f'aio_write -P 1 0 {self.image_len // 2}') + self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') + + # Launch the mirror job + mirror_buf_size = 65536 + result = self.vm.qmp('blockdev-mirror', + job_id='mirror', + filter_node_name='mirror-node', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking', + buf_size=mirror_buf_size) + self.assert_qmp(result, 'return', {}) + + # We create the external requests via qemu-io processes on the NBD + # server. Have their offset start in the middle of the image so they + # do not overlap with the background requests (which start from the + # beginning). + active_request_offset = self.image_len // 2 + active_request_len = 4096 + + # Create enough requests to saturate the node for 5 seconds + for _ in range(0, 5 * self.iops): + req = f'write -P 42 {active_request_offset} {active_request_len}' + active_request_offset += active_request_len + p = iotests.qemu_io_popen('-f', 'nbd', self.nbd_url, '-c', req) + self.background_processes += [p] + + # Now advance the clock one I/O operation at a time by the 4 seconds + # (i.e. one less than 5). We expect the mirror job to issue background + # operations here, even though active requests are still in flight. + # The active requests will take precedence, however, because they have + # been issued earlier than mirror's background requests. + # Once the active requests we have started above are done (i.e. after 5 + # virtual seconds), we expect those background requests to be worked + # on. We only advance 4 seconds here to avoid race conditions. + for _ in range(0, 4 * self.iops): + step = math.ceil(1 * 1000 * 1000 * 1000 / self.iops) + self.vm.qtest(f'clock_step {step}') + + # Note how much remains to be done until the mirror job is finished + job_status = self.vm.qmp('query-jobs')['return'][0] + start_remaining = job_status['total-progress'] - \ + job_status['current-progress'] + + # Create a whole bunch of more active requests + for _ in range(0, 10 * self.iops): + req = f'write -P 42 {active_request_offset} {active_request_len}' + active_request_offset += active_request_len + p = iotests.qemu_io_popen('-f', 'nbd', self.nbd_url, '-c', req) + self.background_processes += [p] + + # Let the clock advance more. After 1 second, as noted above, we + # expect the background requests to be worked on. Give them a couple + # of seconds (specifically 4) to see their impact. + for _ in range(0, 5 * self.iops): + step = math.ceil(1 * 1000 * 1000 * 1000 / self.iops) + self.vm.qtest(f'clock_step {step}') + + # Note how much remains to be done now. We expect this number to be + # reduced thanks to those background requests. + job_status = self.vm.qmp('query-jobs')['return'][0] + end_remaining = job_status['total-progress'] - \ + job_status['current-progress'] + + # See that indeed progress was being made on the job, even while the + # node was saturated with active requests + self.assertGreater(start_remaining - end_remaining, 0) + + +class TestHighThrottledWithNbdExport(TestThrottledWithNbdExportBase): + iops = 1024 + + def testActiveOnCreation(self): + ''' + Issue requests on the mirror source node right as the mirror is + instated. It's possible that requests occur before the actual job is + created, but after the node has been put into the graph. Write + requests across the node must in that case be forwarded to the source + node without attempting to mirror them (there is no job object yet, so + attempting to access it would cause a segfault). + We do this with a lightly throttled node (i.e. quite high IOPS limit). + Using throttling seems to increase reproductivity, but if the limit is + too low, all requests allowed per second will be submitted before + mirror_start_job() gets to the problematic point. + ''' + + # Let qemu-img bench create write requests (enough for two seconds on + # the virtual clock) + bench_args = ['bench', '-w', '-d', '1024', '-f', 'nbd', + '-c', str(self.iops * 2), self.nbd_url] + p = iotests.qemu_tool_popen(iotests.qemu_img_args + bench_args) + self.background_processes += [p] + + # Give qemu-img bench time to start up and issue requests + time.sleep(1.0) + # Flush the request queue, so new requests can come in right as we + # start blockdev-mirror + self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') + + result = self.vm.qmp('blockdev-mirror', + job_id='mirror', + device='source-node', + target='target-node', + sync='full', + copy_mode='write-blocking') + self.assert_qmp(result, 'return', {}) + + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'raw'], supported_protocols=['file']) diff --git a/tests/qemu-iotests/151.out b/tests/qemu-iotests/151.out index 89968f35d783..3f8a935a082d 100644 --- a/tests/qemu-iotests/151.out +++ b/tests/qemu-iotests/151.out @@ -1,5 +1,5 @@ -.... +...... ---------------------------------------------------------------------- -Ran 4 tests +Ran 6 tests OK diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163 index e4cd4b230f37..c94ad16f4a7b 100755 --- a/tests/qemu-iotests/163 +++ b/tests/qemu-iotests/163 @@ -113,10 +113,7 @@ class ShrinkBaseClass(iotests.QMPTestCase): qemu_img('resize', '-f', iotests.imgfmt, '--shrink', test_img, self.shrink_size) - self.assertEqual( - qemu_io('-c', 'read -P 0x00 %s'%self.shrink_size, test_img), - qemu_io('-c', 'read -P 0x00 %s'%self.shrink_size, check_img), - "Verifying image content") + qemu_io('-c', f"read -P 0x00 0 {self.shrink_size}", test_img) self.image_verify() diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 9479b92185d3..07eebf358368 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/205 b/tests/qemu-iotests/205 index c0e107328f16..15f798288a4e 100755 --- a/tests/qemu-iotests/205 +++ b/tests/qemu-iotests/205 @@ -85,13 +85,13 @@ class TestNbdServerRemove(iotests.QMPTestCase): def do_test_connect_after_remove(self, mode=None): args = ('-r', '-f', 'raw', '-c', 'read 0 512', nbd_uri) - self.assertReadOk(qemu_io(*args)) + self.assertReadOk(qemu_io(*args).stdout) result = self.remove_export('exp', mode) self.assert_qmp(result, 'return', {}) self.assertExportNotFound('exp') - self.assertConnectFailed(qemu_io(*args)) + self.assertConnectFailed(qemu_io(*args, check=False).stdout) def test_connect_after_remove_default(self): self.do_test_connect_after_remove() diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216 index c531abfded96..311e02af3a7b 100755 --- a/tests/qemu-iotests/216 +++ b/tests/qemu-iotests/216 @@ -21,7 +21,7 @@ # Creator/Owner: Hanna Reitz import iotests -from iotests import log, qemu_img, qemu_io_silent +from iotests import log, qemu_img, qemu_io # Need backing file support iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk'], @@ -52,10 +52,10 @@ with iotests.FilePath('base.img') as base_img_path, \ log('') qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') - assert qemu_io_silent(base_img_path, '-c', 'write -P 1 0M 1M') == 0 + qemu_io(base_img_path, '-c', 'write -P 1 0M 1M') qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, '-F', iotests.imgfmt, top_img_path) - assert qemu_io_silent(top_img_path, '-c', 'write -P 2 1M 1M') == 0 + qemu_io(top_img_path, '-c', 'write -P 2 1M 1M') log('Done') @@ -110,8 +110,8 @@ with iotests.FilePath('base.img') as base_img_path, \ log('--- Checking COR result ---') log('') - assert qemu_io_silent(base_img_path, '-c', 'discard 0 64M') == 0 - assert qemu_io_silent(top_img_path, '-c', 'read -P 1 0M 1M') == 0 - assert qemu_io_silent(top_img_path, '-c', 'read -P 2 1M 1M') == 0 + qemu_io(base_img_path, '-c', 'discard 0 64M') + qemu_io(top_img_path, '-c', 'read -P 1 0M 1M') + qemu_io(top_img_path, '-c', 'read -P 2 1M 1M') log('Done') diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 index 8345793902e4..6320c4cb56eb 100755 --- a/tests/qemu-iotests/218 +++ b/tests/qemu-iotests/218 @@ -28,7 +28,7 @@ # Creator/Owner: Hanna Reitz import iotests -from iotests import log, qemu_img, qemu_io_silent +from iotests import log, qemu_img, qemu_io iotests.script_initialize(supported_fmts=['qcow2', 'raw']) @@ -146,8 +146,7 @@ with iotests.VM() as vm, \ iotests.FilePath('src.img') as src_img_path: qemu_img('create', '-f', iotests.imgfmt, src_img_path, '64M') - assert qemu_io_silent('-f', iotests.imgfmt, src_img_path, - '-c', 'write -P 42 0M 64M') == 0 + qemu_io('-f', iotests.imgfmt, src_img_path, '-c', 'write -P 42 0M 64M') vm.launch() diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index da87f2f4a233..0bbb28301076 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -120,6 +120,11 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", "arguments":{"node":"n", "name":"b"}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", + "arguments":{"driver":"null-co", "node-name":"null", + "size": 4194304}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-add", + "arguments":{"node":"null", "name":"b3"}}' "return" for attempt in normal iothread; do @@ -155,6 +160,9 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "writable":true, "description":"some text", "bitmap":"b2"}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-export-add", + "arguments":{"type": "nbd", "node-name":"n", "id":"n3", "name": "n3", + "bitmaps":[{"node":"null","name":"b3"}]}}' "return" $QEMU_NBD_PROG -L -k "$SOCK_DIR/nbd" echo @@ -178,6 +186,14 @@ IMG="driver=nbd,export=n2,server.type=unix,server.path=$SOCK_DIR/nbd" $QEMU_IMG map --output=json --image-opts \ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map +echo +echo "=== Check bitmap taken from another node ===" +echo + +IMG="driver=nbd,export=n3,server.type=unix,server.path=$SOCK_DIR/nbd" +$QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b3" | _filter_qemu_img_map + echo echo "=== End qemu NBD server ===" echo diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index e58ea5abbd5a..26fb347c5da4 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -33,6 +33,13 @@ wrote 2097152/2097152 bytes at offset 2097152 {"execute":"block-dirty-bitmap-disable", "arguments":{"node":"n", "name":"b"}} {"return": {}} +{"execute":"blockdev-add", + "arguments":{"driver":"null-co", "node-name":"null", + "size": 4194304}} +{"return": {}} +{"execute":"block-dirty-bitmap-add", + "arguments":{"node":"null", "name":"b3"}} +{"return": {}} === Set up NBD with normal access === @@ -69,7 +76,11 @@ exports available: 0 "arguments":{"device":"n", "name":"n2", "writable":true, "description":"some text", "bitmap":"b2"}} {"return": {}} -exports available: 2 +{"execute":"block-export-add", + "arguments":{"type": "nbd", "node-name":"n", "id":"n3", "name": "n3", + "bitmaps":[{"node":"null","name":"b3"}]}} +{"return": {}} +exports available: 3 export: 'n' size: 4194304 flags: 0x58f ( readonly flush fua df multi cache ) @@ -82,13 +93,22 @@ exports available: 2 export: 'n2' description: some text size: 4194304 - flags: 0xced ( flush fua trim zeroes df cache fast-zero ) + flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) min block: 1 opt block: 4096 max block: 33554432 available meta contexts: 2 base:allocation qemu:dirty-bitmap:b2 + export: 'n3' + size: 4194304 + flags: 0x58f ( readonly flush fua df multi cache ) + min block: 1 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 + base:allocation + qemu:dirty-bitmap:b3 === Contrast normal status to large granularity dirty-bitmap === @@ -114,6 +134,10 @@ read 2097152/2097152 bytes at offset 2097152 { "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, { "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] +=== Check bitmap taken from another node === + +[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] + === End qemu NBD server === {"execute":"nbd-server-remove", @@ -128,6 +152,7 @@ read 2097152/2097152 bytes at offset 2097152 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}} {"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}} {"execute":"nbd-server-stop"} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n3"}} {"return": {}} {"execute":"nbd-server-stop"} {"error": {"class": "GenericError", "desc": "NBD server not running"}} @@ -170,7 +195,11 @@ exports available: 0 "arguments":{"device":"n", "name":"n2", "writable":true, "description":"some text", "bitmap":"b2"}} {"return": {}} -exports available: 2 +{"execute":"block-export-add", + "arguments":{"type": "nbd", "node-name":"n", "id":"n3", "name": "n3", + "bitmaps":[{"node":"null","name":"b3"}]}} +{"return": {}} +exports available: 3 export: 'n' size: 4194304 flags: 0x58f ( readonly flush fua df multi cache ) @@ -183,13 +212,22 @@ exports available: 2 export: 'n2' description: some text size: 4194304 - flags: 0xced ( flush fua trim zeroes df cache fast-zero ) + flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) min block: 1 opt block: 4096 max block: 33554432 available meta contexts: 2 base:allocation qemu:dirty-bitmap:b2 + export: 'n3' + size: 4194304 + flags: 0x58f ( readonly flush fua df multi cache ) + min block: 1 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 + base:allocation + qemu:dirty-bitmap:b3 === Contrast normal status to large granularity dirty-bitmap === @@ -215,6 +253,10 @@ read 2097152/2097152 bytes at offset 2097152 { "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, { "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] +=== Check bitmap taken from another node === + +[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] + === End qemu NBD server === {"execute":"nbd-server-remove", @@ -229,6 +271,7 @@ read 2097152/2097152 bytes at offset 2097152 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}} {"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}} {"execute":"nbd-server-stop"} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n3"}} {"return": {}} {"execute":"nbd-server-stop"} {"error": {"class": "GenericError", "desc": "NBD server not running"}} diff --git a/tests/qemu-iotests/224 b/tests/qemu-iotests/224 index 4df5157e8dfb..542d0eefa605 100755 --- a/tests/qemu-iotests/224 +++ b/tests/qemu-iotests/224 @@ -22,7 +22,7 @@ # Creator/Owner: Hanna Reitz import iotests -from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \ +from iotests import log, qemu_img, qemu_io, filter_qmp_testfiles, \ filter_qmp_imgfmt import json @@ -54,7 +54,7 @@ for filter_node_name in False, True: '-F', iotests.imgfmt, top_img_path) # Something to commit - assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0 + qemu_io(mid_img_path, '-c', 'write -P 1 0 1M') vm.launch() diff --git a/tests/qemu-iotests/227.out b/tests/qemu-iotests/227.out index 9c09ee3917b9..378c1b8fb128 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/242 b/tests/qemu-iotests/242 index b3afd36d7242..c89f0c6cb322 100755 --- a/tests/qemu-iotests/242 +++ b/tests/qemu-iotests/242 @@ -22,8 +22,8 @@ import iotests import json import struct -from iotests import qemu_img_create, qemu_io, qemu_img_info, \ - file_path, img_info_log, log, filter_qemu_io +from iotests import qemu_img_create, qemu_io_log, qemu_img_info, \ + file_path, img_info_log, log iotests.script_initialize(supported_fmts=['qcow2'], supported_protocols=['file'], @@ -61,7 +61,7 @@ def add_bitmap(bitmap_number, persistent, disabled): def write_to_disk(offset, size): write = 'write {} {}'.format(offset, size) - log(qemu_io('-c', write, disk), filters=[filter_qemu_io]) + qemu_io_log('-c', write, disk) def toggle_flag(offset): diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index 8cbed7821b0f..edaf29094b55 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -20,11 +20,13 @@ # along with this program. If not, see . # +import copy +import json import os import re +from subprocess import CalledProcessError + import iotests -import copy -import json from iotests import qemu_img, qemu_io hd_path = [ @@ -216,11 +218,14 @@ class TestBlockdevReopen(iotests.QMPTestCase): # Reopen an image several times changing some of its options def test_reopen(self): - # Check whether the filesystem supports O_DIRECT - if 'O_DIRECT' in qemu_io('-f', 'raw', '-t', 'none', '-c', 'quit', hd_path[0]): - supports_direct = False - else: + try: + qemu_io('-f', 'raw', '-t', 'none', '-c', 'quit', hd_path[0]) supports_direct = True + except CalledProcessError as exc: + if 'O_DIRECT' in exc.stdout: + supports_direct = False + else: + raise # Open the hd1 image passing all backing options opts = hd_opts(1) diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255 index f86fa851b62f..88b29d64b44e 100755 --- a/tests/qemu-iotests/255 +++ b/tests/qemu-iotests/255 @@ -95,9 +95,7 @@ with iotests.FilePath('src.qcow2') as src_path, \ iotests.qemu_img_create('-f', iotests.imgfmt, src_path, size_str) iotests.qemu_img_create('-f', iotests.imgfmt, dst_path, size_str) - iotests.log(iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 0 1M', - src_path), - filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) + iotests.qemu_io_log('-f', iotests.imgfmt, '-c', 'write 0 1M', src_path), vm.add_object('throttle-group,x-bps-read=4096,id=throttle0') diff --git a/tests/qemu-iotests/258 b/tests/qemu-iotests/258 index cfd536d6dced..73d4af645f0c 100755 --- a/tests/qemu-iotests/258 +++ b/tests/qemu-iotests/258 @@ -21,7 +21,7 @@ # Creator/Owner: Hanna Reitz import iotests -from iotests import log, qemu_img, qemu_io_silent, \ +from iotests import log, qemu_img, qemu_io, \ filter_qmp_testfiles, filter_qmp_imgfmt # Returns a node for blockdev-add @@ -86,15 +86,14 @@ def test_concurrent_finish(write_to_stream_node): if write_to_stream_node: # This is what (most of the time) makes commit finish # earlier and then pull in stream - assert qemu_io_silent(node2_path, - '-c', 'write %iK 64K' % (65536 - 192), - '-c', 'write %iK 64K' % (65536 - 64)) == 0 + qemu_io(node2_path, + '-c', 'write %iK 64K' % (65536 - 192), + '-c', 'write %iK 64K' % (65536 - 64)) stream_throttle='tg' else: # And this makes stream finish earlier - assert qemu_io_silent(node1_path, - '-c', 'write %iK 64K' % (65536 - 64)) == 0 + qemu_io(node1_path, '-c', 'write %iK 64K' % (65536 - 64)) commit_throttle='tg' diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index bc431d1a19bc..289381e315f4 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/298 b/tests/qemu-iotests/298 index fae72211b11d..ad560e2941ff 100755 --- a/tests/qemu-iotests/298 +++ b/tests/qemu-iotests/298 @@ -129,16 +129,13 @@ class TestTruncate(iotests.QMPTestCase): os.remove(refdisk) def do_test(self, prealloc_mode, new_size): - ret = iotests.qemu_io_silent('--image-opts', '-c', 'write 0 10M', '-c', - f'truncate -m {prealloc_mode} {new_size}', - drive_opts) - self.assertEqual(ret, 0) - - ret = iotests.qemu_io_silent('-f', iotests.imgfmt, '-c', 'write 0 10M', - '-c', - f'truncate -m {prealloc_mode} {new_size}', - refdisk) - self.assertEqual(ret, 0) + iotests.qemu_io('--image-opts', '-c', 'write 0 10M', '-c', + f'truncate -m {prealloc_mode} {new_size}', + drive_opts) + + iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 0 10M', + '-c', f'truncate -m {prealloc_mode} {new_size}', + refdisk) stat = os.stat(disk) refstat = os.stat(refdisk) diff --git a/tests/qemu-iotests/303 b/tests/qemu-iotests/303 index 93aa5ce9b7d9..a8cc6a23dfe7 100755 --- a/tests/qemu-iotests/303 +++ b/tests/qemu-iotests/303 @@ -21,10 +21,12 @@ import iotests import subprocess -from iotests import qemu_img_create, qemu_io, file_path, log, filter_qemu_io +from iotests import qemu_img_create, qemu_io_log, file_path, log, \ + verify_qcow2_zstd_compression iotests.script_initialize(supported_fmts=['qcow2'], unsupported_imgopts=['refcount_bits', 'compat']) +verify_qcow2_zstd_compression() disk = file_path('disk') chunk = 1024 * 1024 @@ -43,7 +45,7 @@ def create_bitmap(bitmap_number, disabled): def write_to_disk(offset, size): write = f'write {offset} {size}' - log(qemu_io('-c', write, disk), filters=[filter_qemu_io]) + qemu_io_log('-c', write, disk) def add_bitmap(num, begin, end, disabled): diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index ec8d2be0e0a4..390f05d1b78e 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -83,7 +83,7 @@ exports available: 2 export: 'export1' description: This is the writable second export size: 67108864 - flags: 0xced ( flush fua trim zeroes df cache fast-zero ) + flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) min block: XXX opt block: XXX max block: XXX @@ -109,7 +109,7 @@ exports available: 1 export: 'export1' description: This is the writable second export size: 67108864 - flags: 0xced ( flush fua trim zeroes df cache fast-zero ) + flags: 0xded ( flush fua trim zeroes df multi cache fast-zero ) min block: XXX opt block: XXX max block: XXX diff --git a/tests/qemu-iotests/310 b/tests/qemu-iotests/310 index 00fc5618f664..650d2cb6fb3e 100755 --- a/tests/qemu-iotests/310 +++ b/tests/qemu-iotests/310 @@ -21,7 +21,7 @@ # import iotests -from iotests import log, qemu_img, qemu_io_silent +from iotests import log, qemu_img, qemu_io # Need backing file support iotests.script_initialize(supported_fmts=['qcow2'], @@ -44,15 +44,15 @@ with iotests.FilePath('base.img') as base_img_path, \ log('') qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') - assert qemu_io_silent(base_img_path, '-c', 'write -P 1 0M 1M') == 0 - assert qemu_io_silent(base_img_path, '-c', 'write -P 1 3M 1M') == 0 + qemu_io(base_img_path, '-c', 'write -P 1 0M 1M') + qemu_io(base_img_path, '-c', 'write -P 1 3M 1M') qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, '-F', iotests.imgfmt, mid_img_path) - assert qemu_io_silent(mid_img_path, '-c', 'write -P 3 2M 1M') == 0 - assert qemu_io_silent(mid_img_path, '-c', 'write -P 3 4M 1M') == 0 + qemu_io(mid_img_path, '-c', 'write -P 3 2M 1M') + qemu_io(mid_img_path, '-c', 'write -P 3 4M 1M') qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path, '-F', iotests.imgfmt, top_img_path) - assert qemu_io_silent(top_img_path, '-c', 'write -P 2 1M 1M') == 0 + qemu_io(top_img_path, '-c', 'write -P 2 1M 1M') # 0 1 2 3 4 # top 2 @@ -107,10 +107,10 @@ with iotests.FilePath('base.img') as base_img_path, \ # Detach backing to check that we can read the data from the top level now qemu_img('rebase', '-u', '-b', '', '-f', iotests.imgfmt, top_img_path) - assert qemu_io_silent(top_img_path, '-c', 'read -P 0 0 1M') == 0 - assert qemu_io_silent(top_img_path, '-c', 'read -P 2 1M 1M') == 0 - assert qemu_io_silent(top_img_path, '-c', 'read -P 3 2M 1M') == 0 - assert qemu_io_silent(top_img_path, '-c', 'read -P 0 3M 1M') == 0 - assert qemu_io_silent(top_img_path, '-c', 'read -P 3 4M 1M') == 0 + qemu_io(top_img_path, '-c', 'read -P 0 0 1M') + qemu_io(top_img_path, '-c', 'read -P 2 1M 1M') + qemu_io(top_img_path, '-c', 'read -P 3 2M 1M') + qemu_io(top_img_path, '-c', 'read -P 0 3M 1M') + qemu_io(top_img_path, '-c', 'read -P 3 4M 1M') log('Done') diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 75de1b4691eb..9bdda1394e73 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -159,7 +159,7 @@ if __name__ == '__main__': if not tests: raise ValueError('No tests selected') except ValueError as e: - sys.exit(e) + sys.exit(str(e)) if args.dry_run: print('\n'.join(tests)) diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config deleted file mode 100644 index 9bd1a5a6fc83..000000000000 --- a/tests/qemu-iotests/common.config +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2003,2006 Silicon Graphics, 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 the Free Software Foundation. -# -# This program is distributed in the hope that it would 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 . -# -# all tests should use a common language setting to prevent golden -# output mismatches. -export LANG=C - -PATH=".:$PATH" - -HOSTOS=$(uname -s) -arch=$(uname -m) -[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" - -# make sure we have a standard umask -umask 022 - -_optstr_add() -{ - if [ -n "$1" ]; then - echo "$1,$2" - else - echo "$2" - fi -} - -# make sure this script returns success -true diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 227e0a5be917..db757025cbd3 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -17,6 +17,17 @@ # along with this program. If not, see . # +export LANG=C + +PATH=".:$PATH" + +HOSTOS=$(uname -s) +arch=$(uname -m) +[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" + +# make sure we have a standard umask +umask 022 + # bail out, setting up .notrun file _notrun() { @@ -120,18 +131,14 @@ peek_file_raw() dd if="$1" bs=1 skip="$2" count="$3" status=none } -config=common.config -test -f $config || config=../common.config -if ! test -f $config -then - echo "$0: failed to find common.config" - exit 1 -fi -if ! . $config - then - echo "$0: failed to source common.config" - exit 1 -fi +_optstr_add() +{ + if [ -n "$1" ]; then + echo "$1,$2" + else + echo "$2" + fi +} # Set the variables to the empty string to turn Valgrind off # for specific processes, e.g. @@ -975,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 @@ -987,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/iotests.py b/tests/qemu-iotests/iotests.py index fcec3e51e515..da7d6637e13f 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -37,9 +37,8 @@ from contextlib import contextmanager -from qemu.aqmp.legacy import QEMUMonitorProtocol from qemu.machine import qtest -from qemu.qmp import QMPMessage +from qemu.qmp.legacy import QMPMessage, QEMUMonitorProtocol from qemu.utils import VerboseProcessError # Use this logger for logging messages directly from the iotests module @@ -207,15 +206,13 @@ def qemu_img_create_prepare_args(args: List[str]) -> List[str]: return result -def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True - ) -> 'subprocess.CompletedProcess[str]': - """ - Run qemu_img and return the status code and console output. - This function always prepends QEMU_IMG_OPTIONS and may further alter - the args for 'create' commands. +def qemu_tool(*args: str, check: bool = True, combine_stdio: bool = True + ) -> 'subprocess.CompletedProcess[str]': + """ + Run a qemu tool and return its status code and console output. - :param args: command-line arguments to qemu-img. + :param args: full command line to run. :param check: Enforce a return code of zero. :param combine_stdio: set to False to keep stdout/stderr separated. @@ -232,10 +229,8 @@ def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True properties. If streams are not combined, it will also have a stderr property. """ - full_args = qemu_img_args + qemu_img_create_prepare_args(list(args)) - subp = subprocess.run( - full_args, + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT if combine_stdio else subprocess.PIPE, universal_newlines=True, @@ -244,7 +239,7 @@ def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True if check and subp.returncode or (subp.returncode < 0): raise VerboseProcessError( - subp.returncode, full_args, + subp.returncode, args, output=subp.stdout, stderr=subp.stderr, ) @@ -252,6 +247,20 @@ def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True return subp +def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True + ) -> 'subprocess.CompletedProcess[str]': + """ + Run QEMU_IMG_PROG and return its status code and console output. + + This function always prepends QEMU_IMG_OPTIONS and may further alter + the args for 'create' commands. + + See `qemu_tool()` for greater detail. + """ + full_args = qemu_img_args + qemu_img_create_prepare_args(list(args)) + return qemu_tool(*full_args, check=check, combine_stdio=combine_stdio) + + def ordered_qmp(qmsg, conv_keys=True): # Dictionaries are not ordered prior to 3.6, therefore: if isinstance(qmsg, list): @@ -344,34 +353,23 @@ def qemu_io_wrap_args(args: Sequence[str]) -> List[str]: def qemu_io_popen(*args): return qemu_tool_popen(qemu_io_wrap_args(args)) -def qemu_io(*args): - '''Run qemu-io and return the stdout data''' - return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args))[0] +def qemu_io(*args: str, check: bool = True, combine_stdio: bool = True + ) -> 'subprocess.CompletedProcess[str]': + """ + Run QEMU_IO_PROG and return the status code and console output. -def qemu_io_pipe_and_status(*args): - return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args)) + This function always prepends either QEMU_IO_OPTIONS or + QEMU_IO_OPTIONS_NO_FMT. + """ + return qemu_tool(*qemu_io_wrap_args(args), + check=check, combine_stdio=combine_stdio) -def qemu_io_log(*args): - result = qemu_io(*args) - log(result, filters=[filter_testfiles, filter_qemu_io]) +def qemu_io_log(*args: str, check: bool = True + ) -> 'subprocess.CompletedProcess[str]': + result = qemu_io(*args, check=check) + log(result.stdout, filters=[filter_testfiles, filter_qemu_io]) return result -def qemu_io_silent(*args): - '''Run qemu-io and return the exit code, suppressing stdout''' - args = qemu_io_wrap_args(args) - result = subprocess.run(args, stdout=subprocess.DEVNULL, check=False) - if result.returncode < 0: - sys.stderr.write('qemu-io received signal %i: %s\n' % - (-result.returncode, ' '.join(args))) - return result.returncode - -def qemu_io_silent_check(*args): - '''Run qemu-io and return the true if subprocess returned 0''' - args = qemu_io_wrap_args(args) - result = subprocess.run(args, stdout=subprocess.DEVNULL, - stderr=subprocess.STDOUT, check=False) - return result.returncode == 0 - class QemuIoInteractive: def __init__(self, *args): self.args = qemu_io_wrap_args(args) @@ -1471,6 +1469,26 @@ def verify_working_luks(): if not working: notrun(reason) +def supports_qcow2_zstd_compression() -> bool: + img_file = f'{test_dir}/qcow2-zstd-test.qcow2' + res = qemu_img('create', '-f', 'qcow2', '-o', 'compression_type=zstd', + img_file, '0', + check=False) + try: + os.remove(img_file) + except OSError: + pass + + if res.returncode == 1 and \ + "'compression-type' does not accept value 'zstd'" in res.stdout: + return False + else: + return True + +def verify_qcow2_zstd_compression(): + if not supports_qcow2_zstd_compression(): + notrun('zstd compression not supported') + def qemu_pipe(*args: str) -> str: """ Run qemu with an option to print something and exit (e.g. a help option). diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build index 9747bb68a524..323a4acb6a3f 100644 --- a/tests/qemu-iotests/meson.build +++ b/tests/qemu-iotests/meson.build @@ -1,30 +1,47 @@ -if have_tools and targetos != 'windows' and not get_option('gprof') - qemu_iotests_binaries = [qemu_img, qemu_io, qemu_nbd, qsd] - qemu_iotests_env = {'PYTHON': python.full_path()} - qemu_iotests_formats = { - 'qcow2': 'quick', - 'raw': 'slow', - 'qed': 'thorough', - 'vmdk': 'thorough', - 'vpc': 'thorough' - } +if not have_tools or targetos == 'windows' or get_option('gprof') + subdir_done() +endif + +foreach cflag: config_host['QEMU_CFLAGS'].split() + if cflag.startswith('-fsanitize') and \ + not cflag.contains('safe-stack') and not cflag.contains('cfi-icall') + message('Sanitizers are enabled ==> Disabled the qemu-iotests.') + subdir_done() + endif +endforeach - foreach k, v : emulators - if k.startswith('qemu-system-') - qemu_iotests_binaries += v - endif - endforeach - foreach format, speed: qemu_iotests_formats - if speed == 'quick' - suites = 'block' - else - suites = ['block-' + speed, speed] - endif - test('qemu-iotests ' + format, sh, args: [files('../check-block.sh'), format], - depends: qemu_iotests_binaries, env: qemu_iotests_env, - protocol: 'tap', - suite: suites, - timeout: 0, - is_parallel: false) - endforeach +bash = find_program('bash', required: false, version: '>= 4.0') +if not bash.found() + message('bash >= v4.0 not available ==> Disabled the qemu-iotests.') + subdir_done() endif + +qemu_iotests_binaries = [qemu_img, qemu_io, qemu_nbd, qsd] +qemu_iotests_env = {'PYTHON': python.full_path()} +qemu_iotests_formats = { + 'qcow2': 'quick', + 'raw': 'slow', + 'qed': 'thorough', + 'vmdk': 'thorough', + 'vpc': 'thorough' +} + +foreach k, v : emulators + if k.startswith('qemu-system-') + qemu_iotests_binaries += v + endif +endforeach + +foreach format, speed: qemu_iotests_formats + if speed == 'quick' + suites = 'block' + else + suites = ['block-' + speed, speed] + endif + test('qemu-iotests ' + format, sh, args: [files('../check-block.sh'), format], + depends: qemu_iotests_binaries, env: qemu_iotests_env, + protocol: 'tap', + suite: suites, + timeout: 0, + is_parallel: false) +endforeach diff --git a/tests/qemu-iotests/mypy.ini b/tests/qemu-iotests/mypy.ini index 4c0339f5589f..d66ffc2e3c78 100644 --- a/tests/qemu-iotests/mypy.ini +++ b/tests/qemu-iotests/mypy.ini @@ -9,4 +9,4 @@ no_implicit_optional = True scripts_are_modules = True warn_redundant_casts = True warn_unused_configs = True -warn_unused_ignores = True +warn_unused_ignores = False diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc index 32ab77b8bb97..f4f823a9915d 100644 --- a/tests/qemu-iotests/pylintrc +++ b/tests/qemu-iotests/pylintrc @@ -51,3 +51,8 @@ notes=FIXME, # Maximum number of characters on a single line. max-line-length=79 + + +[SIMILARITIES] + +min-similarity-lines=6 diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index aae70a834172..5a771da86ed3 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -361,6 +361,9 @@ def run_test(self, test: str, starttime=start, lasttime=last_el, end = '\n' if mp else '\r') + else: + testname = os.path.basename(test) + print(f'# running {self.env.imgfmt} {testname}') res = self.do_run_test(test, mp) @@ -378,6 +381,7 @@ def run_test(self, test: str, else: print(res.casenotrun) + sys.stdout.flush() return res def run_tests(self, tests: List[str], jobs: int = 1) -> bool: diff --git a/tests/qemu-iotests/tests/backing-file-invalidation b/tests/qemu-iotests/tests/backing-file-invalidation new file mode 100755 index 000000000000..4eccc801532e --- /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 000000000000..ae1213e6f863 --- /dev/null +++ b/tests/qemu-iotests/tests/backing-file-invalidation.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write new file mode 100755 index 000000000000..2ffe092b3187 --- /dev/null +++ b/tests/qemu-iotests/tests/copy-before-write @@ -0,0 +1,222 @@ +#!/usr/bin/env python3 +# group: auto backup +# +# Copyright (c) 2022 Virtuozzo International GmbH +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import re + +from qemu.machine import QEMUMachine + +import iotests +from iotests import qemu_img_create, qemu_io + + +temp_img = os.path.join(iotests.test_dir, 'temp') +source_img = os.path.join(iotests.test_dir, 'source') +size = '1M' + + +class TestCbwError(iotests.QMPTestCase): + def tearDown(self): + self.vm.shutdown() + os.remove(temp_img) + os.remove(source_img) + + def setUp(self): + qemu_img_create('-f', iotests.imgfmt, source_img, size) + qemu_img_create('-f', iotests.imgfmt, temp_img, size) + qemu_io('-c', 'write 0 1M', source_img) + + opts = ['-nodefaults', '-display', 'none', '-machine', 'none'] + self.vm = QEMUMachine(iotests.qemu_prog, opts, + base_temp_dir=iotests.test_dir, + sock_dir=iotests.sock_dir) + self.vm.launch() + + def do_cbw_error(self, on_cbw_error): + result = self.vm.qmp('blockdev-add', { + 'node-name': 'cbw', + 'driver': 'copy-before-write', + 'on-cbw-error': on_cbw_error, + 'file': { + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': source_img, + } + }, + 'target': { + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': temp_img + }, + 'inject-error': [ + { + 'event': 'write_aio', + 'errno': 5, + 'immediately': False, + 'once': True + } + ] + } + } + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('blockdev-add', { + 'node-name': 'access', + 'driver': 'snapshot-access', + 'file': 'cbw' + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io cbw "write 0 1M"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io access "read 0 1M"') + self.assert_qmp(result, 'return', '') + + self.vm.shutdown() + log = self.vm.get_log() + log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) + log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) + log = iotests.filter_qemu_io(log) + return log + + def test_break_snapshot_on_cbw_error(self): + """break-snapshot behavior: + Guest write succeed, but further snapshot-read fails, as snapshot is + broken. + """ + log = self.do_cbw_error('break-snapshot') + + self.assertEqual(log, """\ +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read failed: Permission denied +""") + + def test_break_guest_write_on_cbw_error(self): + """break-guest-write behavior: + Guest write fails, but snapshot-access continues working and further + snapshot-read succeeds. + """ + log = self.do_cbw_error('break-guest-write') + + self.assertEqual(log, """\ +write failed: Input/output error +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +""") + + def do_cbw_timeout(self, on_cbw_error): + result = self.vm.qmp('object-add', { + 'qom-type': 'throttle-group', + 'id': 'group0', + 'limits': {'bps-write': 300 * 1024} + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('blockdev-add', { + 'node-name': 'cbw', + 'driver': 'copy-before-write', + 'on-cbw-error': on_cbw_error, + 'cbw-timeout': 1, + 'file': { + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': source_img, + } + }, + 'target': { + 'driver': 'throttle', + 'throttle-group': 'group0', + 'file': { + 'driver': 'qcow2', + 'file': { + 'driver': 'file', + 'filename': temp_img + } + } + } + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('blockdev-add', { + 'node-name': 'access', + 'driver': 'snapshot-access', + 'file': 'cbw' + }) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io cbw "write 0 512K"') + self.assert_qmp(result, 'return', '') + + # We need second write to trigger throttling + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io cbw "write 512K 512K"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io access "read 0 1M"') + self.assert_qmp(result, 'return', '') + + self.vm.shutdown() + log = self.vm.get_log() + log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) + log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) + log = iotests.filter_qemu_io(log) + return log + + def test_timeout_break_guest(self): + log = self.do_cbw_timeout('break-guest-write') + # macOS and FreeBSD tend to represent ETIMEDOUT as + # "Operation timed out", when Linux prefer + # "Connection timed out" + log = log.replace('Operation timed out', + 'Connection timed out') + self.assertEqual(log, """\ +wrote 524288/524288 bytes at offset 0 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +write failed: Connection timed out +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +""") + + def test_timeout_break_snapshot(self): + log = self.do_cbw_timeout('break-snapshot') + self.assertEqual(log, """\ +wrote 524288/524288 bytes at offset 0 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 524288/524288 bytes at offset 524288 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read failed: Permission denied +""") + + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2'], + supported_protocols=['file'], + required_fmts=['copy-before-write']) diff --git a/tests/qemu-iotests/tests/copy-before-write.out b/tests/qemu-iotests/tests/copy-before-write.out new file mode 100644 index 000000000000..89968f35d783 --- /dev/null +++ b/tests/qemu-iotests/tests/copy-before-write.out @@ -0,0 +1,5 @@ +.... +---------------------------------------------------------------------- +Ran 4 tests + +OK diff --git a/tests/qemu-iotests/tests/export-incoming-iothread b/tests/qemu-iotests/tests/export-incoming-iothread new file mode 100755 index 000000000000..7679e491035f --- /dev/null +++ b/tests/qemu-iotests/tests/export-incoming-iothread @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# group: rw quick migration +# +# Regression test for issue 945: +# https://gitlab.com/qemu-project/qemu/-/issues/945 +# Test adding an export on top of an iothread-ed block device while in +# -incoming defer. +# +# 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 os +import iotests +from iotests import qemu_img_create + + +image_size = 1 * 1024 * 1024 +test_img = os.path.join(iotests.test_dir, 'test.img') +node_name = 'node0' +iothread_id = 'iothr0' + +nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') + + +class TestExportIncomingIothread(iotests.QMPTestCase): + def setUp(self) -> None: + qemu_img_create('-f', iotests.imgfmt, test_img, str(image_size)) + + self.vm = iotests.VM() + self.vm.add_object(f'iothread,id={iothread_id}') + self.vm.add_blockdev(( + f'driver={iotests.imgfmt}', + f'node-name={node_name}', + 'file.driver=file', + f'file.filename={test_img}' + )) + self.vm.add_incoming('defer') + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + + def test_export_add(self): + result = self.vm.qmp('nbd-server-start', { + 'addr': { + 'type': 'unix', + 'data': { + 'path': nbd_sock + } + } + }) + self.assert_qmp(result, 'return', {}) + + # Regression test for issue 945: This should not fail an assertion + result = self.vm.qmp('block-export-add', { + 'type': 'nbd', + 'id': 'exp0', + 'node-name': node_name, + 'iothread': iothread_id + }) + self.assert_qmp(result, 'return', {}) + + +if __name__ == '__main__': + iotests.main(supported_fmts=['generic'], + unsupported_fmts=['luks'], # Would need a secret + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/export-incoming-iothread.out b/tests/qemu-iotests/tests/export-incoming-iothread.out new file mode 100644 index 000000000000..ae1213e6f863 --- /dev/null +++ b/tests/qemu-iotests/tests/export-incoming-iothread.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing index b7e507610449..f6e449d0711b 100755 --- a/tests/qemu-iotests/tests/image-fleecing +++ b/tests/qemu-iotests/tests/image-fleecing @@ -22,9 +22,10 @@ # # Creator/Owner: John Snow +from subprocess import CalledProcessError + import iotests -from iotests import log, qemu_img, qemu_io, qemu_io_silent, \ - qemu_io_pipe_and_status +from iotests import log, qemu_img, qemu_io iotests.script_initialize( supported_fmts=['qcow2'], @@ -185,10 +186,14 @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, for p in patterns + zeroes: cmd = 'read -P%s %s %s' % p log(cmd) - out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd, - nbd_uri) - if ret != 0: - print(out) + + try: + qemu_io('-r', '-f', 'raw', '-c', cmd, nbd_uri) + except CalledProcessError as exc: + if bitmap and p in zeroes: + log(exc.stdout) + else: + raise log('') log('--- Testing COW ---') @@ -228,9 +233,14 @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, args += [target_img_path] else: args += ['-f', 'raw', nbd_uri] - out, ret = qemu_io_pipe_and_status(*args) - if ret != 0: - print(out) + + try: + qemu_io(*args) + except CalledProcessError as exc: + if bitmap and p in zeroes: + log(exc.stdout) + else: + raise log('') log('--- Cleanup ---') @@ -260,7 +270,7 @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, for p in overwrite + remainder: cmd = 'read -P%s %s %s' % p log(cmd) - assert qemu_io_silent(base_img_path, '-c', cmd) == 0 + qemu_io(base_img_path, '-c', cmd) log('') log('Done') diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions index 6be02581c71d..4e1da369c949 100755 --- a/tests/qemu-iotests/tests/migration-permissions +++ b/tests/qemu-iotests/tests/migration-permissions @@ -18,6 +18,8 @@ # import os +from subprocess import CalledProcessError + import iotests from iotests import imgfmt, qemu_img_create, qemu_io @@ -69,13 +71,12 @@ class TestMigrationPermissions(iotests.QMPTestCase): def test_post_migration_permissions(self): # Try to access the image R/W, which should fail because virtio-blk # has not been configured with share-rw=on - log = qemu_io('-f', imgfmt, '-c', 'quit', test_img) - if not log.strip(): - print('ERROR (pre-migration): qemu-io should not be able to ' - 'access this image, but it reported no error') - else: - # This is the expected output - assert 'Is another process using the image' in log + emsg = ('ERROR (pre-migration): qemu-io should not be able to ' + 'access this image, but it reported no error') + with self.assertRaises(CalledProcessError, msg=emsg) as ctx: + qemu_io('-f', imgfmt, '-c', 'quit', test_img) + if 'Is another process using the image' not in ctx.exception.stdout: + raise ctx.exception # Now migrate the VM self.vm_s.qmp('migrate', uri=f'unix:{mig_sock}') @@ -84,13 +85,12 @@ class TestMigrationPermissions(iotests.QMPTestCase): # Try the same qemu-io access again, verifying that the WRITE # permission remains unshared - log = qemu_io('-f', imgfmt, '-c', 'quit', test_img) - if not log.strip(): - print('ERROR (post-migration): qemu-io should not be able to ' - 'access this image, but it reported no error') - else: - # This is the expected output - assert 'Is another process using the image' in log + emsg = ('ERROR (post-migration): qemu-io should not be able to ' + 'access this image, but it reported no error') + with self.assertRaises(CalledProcessError, msg=emsg) as ctx: + qemu_io('-f', imgfmt, '-c', 'quit', test_img) + if 'Is another process using the image' not in ctx.exception.stdout: + raise ctx.exception if __name__ == '__main__': diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error index 1d0e333b5ef9..01217459b980 100755 --- a/tests/qemu-iotests/tests/mirror-ready-cancel-error +++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error @@ -37,7 +37,7 @@ class TestMirrorReadyCancelError(iotests.QMPTestCase): # Ensure that mirror will copy something before READY so the # target format layer will forward the pre-READY flush to its # file child - assert iotests.qemu_io_silent('-c', 'write -P 1 0 64k', source) == 0 + iotests.qemu_io('-c', 'write -P 1 0 64k', source) self.vm = iotests.VM() self.vm.launch() diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms index 6ac8d5efccbc..8bca59270898 100755 --- a/tests/qemu-iotests/tests/mirror-top-perms +++ b/tests/qemu-iotests/tests/mirror-top-perms @@ -22,7 +22,6 @@ import os from qemu.machine import machine -from qemu.qmp import QMPConnectError import iotests from iotests import change_log_level, qemu_img @@ -98,15 +97,13 @@ class TestMirrorTopPerms(iotests.QMPTestCase): self.vm_b.add_blockdev(f'file,node-name=drive0,filename={source}') self.vm_b.add_device('virtio-blk,drive=drive0,share-rw=on') try: - # Silence AQMP errors temporarily. - # TODO: Remove this and just allow the errors to be logged when - # AQMP fully replaces QMP. - with change_log_level('qemu.aqmp'): + # Silence QMP logging errors temporarily. + with change_log_level('qemu.qmp'): self.vm_b.launch() print('ERROR: VM B launched successfully, ' 'this should not have happened') - except (QMPConnectError, machine.VMLaunchFailure): - assert 'Is another process using the image' in self.vm_b.get_log() + except machine.VMLaunchFailure as exc: + assert 'Is another process using the image' in exc.output result = self.vm.qmp('block-job-cancel', device='mirror') diff --git a/tests/qemu-iotests/tests/nbd-multiconn b/tests/qemu-iotests/tests/nbd-multiconn new file mode 100755 index 000000000000..b121f2e363dc --- /dev/null +++ b/tests/qemu-iotests/tests/nbd-multiconn @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# group: rw auto quick +# +# Test cases for NBD multi-conn advertisement +# +# 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 os +from contextlib import contextmanager +import iotests +from iotests import qemu_img_create, qemu_io + + +disk = os.path.join(iotests.test_dir, 'disk') +size = '4M' +nbd_sock = os.path.join(iotests.sock_dir, 'nbd_sock') +nbd_uri = 'nbd+unix:///{}?socket=' + nbd_sock + + +@contextmanager +def open_nbd(export_name): + h = nbd.NBD() + try: + h.connect_uri(nbd_uri.format(export_name)) + yield h + finally: + h.shutdown() + +class TestNbdMulticonn(iotests.QMPTestCase): + def setUp(self): + qemu_img_create('-f', iotests.imgfmt, disk, size) + qemu_io('-c', 'w -P 1 0 2M', '-c', 'w -P 2 2M 2M', disk) + + self.vm = iotests.VM() + self.vm.launch() + result = self.vm.qmp('blockdev-add', { + 'driver': 'qcow2', + 'node-name': 'n', + 'file': {'driver': 'file', 'filename': disk} + }) + self.assert_qmp(result, 'return', {}) + + def tearDown(self): + self.vm.shutdown() + os.remove(disk) + try: + os.remove(nbd_sock) + except OSError: + pass + + @contextmanager + def run_server(self, max_connections=None): + args = { + 'addr': { + 'type': 'unix', + 'data': {'path': nbd_sock} + } + } + if max_connections is not None: + args['max-connections'] = max_connections + + result = self.vm.qmp('nbd-server-start', args) + self.assert_qmp(result, 'return', {}) + yield + + result = self.vm.qmp('nbd-server-stop') + self.assert_qmp(result, 'return', {}) + + def add_export(self, name, writable=None): + args = { + 'type': 'nbd', + 'id': name, + 'node-name': 'n', + 'name': name, + } + if writable is not None: + args['writable'] = writable + + result = self.vm.qmp('block-export-add', args) + self.assert_qmp(result, 'return', {}) + + def test_default_settings(self): + with self.run_server(): + self.add_export('r') + self.add_export('w', writable=True) + with open_nbd('r') as h: + self.assertTrue(h.can_multi_conn()) + with open_nbd('w') as h: + self.assertTrue(h.can_multi_conn()) + + def test_limited_connections(self): + with self.run_server(max_connections=1): + self.add_export('r') + self.add_export('w', writable=True) + with open_nbd('r') as h: + self.assertFalse(h.can_multi_conn()) + with open_nbd('w') as h: + self.assertFalse(h.can_multi_conn()) + + def test_parallel_writes(self): + with self.run_server(): + self.add_export('w', writable=True) + + clients = [nbd.NBD() for _ in range(3)] + for c in clients: + c.connect_uri(nbd_uri.format('w')) + self.assertTrue(c.can_multi_conn()) + + initial_data = clients[0].pread(1024 * 1024, 0) + self.assertEqual(initial_data, b'\x01' * 1024 * 1024) + + updated_data = b'\x03' * 1024 * 1024 + clients[1].pwrite(updated_data, 0) + clients[2].flush() + current_data = clients[0].pread(1024 * 1024, 0) + + self.assertEqual(updated_data, current_data) + + for i in range(3): + clients[i].shutdown() + + +if __name__ == '__main__': + try: + # Easier to use libnbd than to try and set up parallel + # 'qemu-nbd --list' or 'qemu-io' processes, but not all systems + # have libnbd installed. + import nbd # type: ignore + + iotests.main(supported_fmts=['qcow2']) + except ImportError: + iotests.notrun('libnbd not installed') diff --git a/tests/qemu-iotests/tests/nbd-multiconn.out b/tests/qemu-iotests/tests/nbd-multiconn.out new file mode 100644 index 000000000000..8d7e99670093 --- /dev/null +++ b/tests/qemu-iotests/tests/nbd-multiconn.out @@ -0,0 +1,5 @@ +... +---------------------------------------------------------------------- +Ran 3 tests + +OK diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out index 0bf1abb06338..9d938db24e6f 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -17,7 +17,7 @@ wrote 2097152/2097152 bytes at offset 1048576 exports available: 1 export: '' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x48f ( readonly flush fua df cache ) min block: 1 opt block: 4096 max block: 33554432 diff --git a/tests/qemu-iotests/tests/nbd-reconnect-on-open b/tests/qemu-iotests/tests/nbd-reconnect-on-open index 8be721a24fb4..d0b401b06028 100755 --- a/tests/qemu-iotests/tests/nbd-reconnect-on-open +++ b/tests/qemu-iotests/tests/nbd-reconnect-on-open @@ -39,7 +39,7 @@ def check_fail_to_connect(open_timeout): log(f'Check fail to connect with {open_timeout} seconds of timeout') start_t = time.time() - qemu_io_log(*create_args(open_timeout)) + qemu_io_log(*create_args(open_timeout), check=False) delta_t = time.time() - start_t max_delta = open_timeout + 0.2 diff --git a/tests/qemu-iotests/tests/reopen-file b/tests/qemu-iotests/tests/reopen-file new file mode 100755 index 000000000000..8590a94d536e --- /dev/null +++ b/tests/qemu-iotests/tests/reopen-file @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# group: rw quick +# +# Test reopening a format driver's file child +# +# 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 os +import iotests +from iotests import imgfmt, qemu_img_create, QMPTestCase + + +image_size = 1 * 1024 * 1024 +test_img = os.path.join(iotests.test_dir, 'test.img') + + +class TestReopenFile(QMPTestCase): + def setUp(self) -> None: + res = qemu_img_create('-f', imgfmt, test_img, str(image_size)) + assert res.returncode == 0 + + # Add format driver node ('format') on top of the file ('file'), then + # add another raw node ('raw') on top of 'file' so for the reopen we + # can just switch from 'file' to 'raw' + self.vm = iotests.VM() + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': imgfmt, + 'node-name': 'format', + 'file': { + 'driver': 'file', + 'node-name': 'file', + 'filename': test_img + } + })) + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': 'raw', + 'node-name': 'raw', + 'file': 'file' + })) + self.vm.launch() + + def tearDown(self) -> None: + self.vm.shutdown() + os.remove(test_img) + + # Check if there was any qemu-io run that failed + if 'Pattern verification failed' in self.vm.get_log(): + print('ERROR: Pattern verification failed:') + print(self.vm.get_log()) + self.fail('qemu-io pattern verification failed') + + def test_reopen_file(self) -> None: + result = self.vm.qmp('blockdev-reopen', options=[{ + 'driver': imgfmt, + 'node-name': 'format', + 'file': 'raw' + }]) + self.assert_qmp(result, 'return', {}) + + # Do some I/O to the image to see whether it still works + # (Pattern verification will be checked by tearDown()) + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io format "write -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io format "read -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + +if __name__ == '__main__': + # Must support creating images and reopen + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed', 'raw', 'vdi', 'vhdx', + 'vmdk', 'vpc'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/reopen-file.out b/tests/qemu-iotests/tests/reopen-file.out new file mode 100644 index 000000000000..ae1213e6f863 --- /dev/null +++ b/tests/qemu-iotests/tests/reopen-file.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/tests/stream-error-on-reset b/tests/qemu-iotests/tests/stream-error-on-reset index 389ae822b8b3..5a8c3a9e8d28 100755 --- a/tests/qemu-iotests/tests/stream-error-on-reset +++ b/tests/qemu-iotests/tests/stream-error-on-reset @@ -21,7 +21,7 @@ import os import iotests -from iotests import imgfmt, qemu_img_create, qemu_io_silent, QMPTestCase +from iotests import imgfmt, qemu_img_create, qemu_io, QMPTestCase image_size = 1 * 1024 * 1024 @@ -55,7 +55,7 @@ class TestStreamErrorOnReset(QMPTestCase): - top image is attached to a virtio-scsi device """ qemu_img_create('-f', imgfmt, base, str(image_size)) - assert qemu_io_silent('-c', f'write 0 {data_size}', base) == 0 + qemu_io('-c', f'write 0 {data_size}', base) qemu_img_create('-f', imgfmt, top, str(image_size)) self.vm = iotests.VM() diff --git a/tests/qemu-iotests/tests/stream-under-throttle b/tests/qemu-iotests/tests/stream-under-throttle new file mode 100755 index 000000000000..c24dfbcaa2f2 --- /dev/null +++ b/tests/qemu-iotests/tests/stream-under-throttle @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# group: rw +# +# Test streaming with throttle nodes on top +# +# 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 asyncio +import os +from typing import List +import iotests +from iotests import qemu_img_create, qemu_io + + +image_size = 256 * 1024 * 1024 +base_img = os.path.join(iotests.test_dir, 'base.img') +top_img = os.path.join(iotests.test_dir, 'top.img') + + +class TcgVM(iotests.VM): + ''' + Variant of iotests.VM that uses -accel tcg. Simply using + iotests.VM.add_args('-accel', 'tcg') is not sufficient, because that will + put -accel qtest before -accel tcg, and -accel arguments are prioritized in + the order they appear. + ''' + @property + def _base_args(self) -> List[str]: + # Put -accel tcg first so it takes precedence + return ['-accel', 'tcg'] + super()._base_args + + +class TestStreamWithThrottle(iotests.QMPTestCase): + def setUp(self) -> None: + ''' + Create a simple backing chain between two images, write something to + the base image. Attach them to the VM underneath two throttle nodes, + one of which has actually no limits set, but the other does. Then put + a virtio-blk device on top. + This test configuration has been taken from + https://gitlab.com/qemu-project/qemu/-/issues/1215 + ''' + qemu_img_create('-f', iotests.imgfmt, base_img, str(image_size)) + qemu_img_create('-f', iotests.imgfmt, '-b', base_img, '-F', + iotests.imgfmt, top_img, str(image_size)) + + # Write something to stream + qemu_io(base_img, '-c', f'write 0 {image_size}') + + blockdev = { + 'driver': 'throttle', + 'node-name': 'throttled-node', + 'throttle-group': 'thrgr-limited', + 'file': { + 'driver': 'throttle', + 'throttle-group': 'thrgr-unlimited', + 'file': { + 'driver': iotests.imgfmt, + 'node-name': 'unthrottled-node', + 'file': { + 'driver': 'file', + 'filename': top_img + } + } + } + } + + # Issue 1215 is not reproducible in qtest mode, which is why we need to + # create an -accel tcg VM + self.vm = TcgVM() + self.vm.add_object('iothread,id=iothr0') + self.vm.add_object('throttle-group,id=thrgr-unlimited') + self.vm.add_object('throttle-group,id=thrgr-limited,' + 'x-iops-total=10000,x-bps-total=104857600') + self.vm.add_blockdev(self.vm.qmp_to_opts(blockdev)) + self.vm.add_device('virtio-blk,iothread=iothr0,drive=throttled-node') + if iotests.qemu_default_machine == 's390-ccw-virtio': + self.vm.add_args('-no-shutdown') + self.vm.launch() + + def tearDown(self) -> None: + self.vm.shutdown() + os.remove(top_img) + os.remove(base_img) + + def test_stream(self) -> None: + ''' + Do a simple stream beneath the two throttle nodes. Should complete + with no problems. + ''' + result = self.vm.qmp('block-stream', + job_id='stream', + device='unthrottled-node') + self.assert_qmp(result, 'return', {}) + + # Should succeed and not time out + try: + self.vm.run_job('stream') + except asyncio.TimeoutError: + # VM may be stuck, kill it before tearDown() + self.vm.kill() + raise + + +if __name__ == '__main__': + # Must support backing images + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed'], + supported_protocols=['file'], + required_fmts=['throttle']) diff --git a/tests/qemu-iotests/tests/stream-under-throttle.out b/tests/qemu-iotests/tests/stream-under-throttle.out new file mode 100644 index 000000000000..ae1213e6f863 --- /dev/null +++ b/tests/qemu-iotests/tests/stream-under-throttle.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qtest/ac97-test.c b/tests/qtest/ac97-test.c index e09f2495d24d..74103efdfa01 100644 --- a/tests/qtest/ac97-test.c +++ b/tests/qtest/ac97-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" @@ -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/acpi-utils.c b/tests/qtest/acpi-utils.c index 766c48e3a6a4..673fc975862c 100644 --- a/tests/qtest/acpi-utils.c +++ b/tests/qtest/acpi-utils.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "qemu/bitmap.h" #include "acpi-utils.h" #include "boot-sector.h" diff --git a/tests/qtest/acpi-utils.h b/tests/qtest/acpi-utils.h index 261784d25189..0c8678068931 100644 --- a/tests/qtest/acpi-utils.h +++ b/tests/qtest/acpi-utils.h @@ -13,7 +13,7 @@ #ifndef TEST_ACPI_UTILS_H #define TEST_ACPI_UTILS_H -#include "libqos/libqtest.h" +#include "libqtest.h" /* DSDT and SSDTs format */ typedef struct { diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 8073ccc20521..1967cd589855 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -25,12 +25,11 @@ #include "qemu/osdep.h" #include -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/libqos-pc.h" #include "libqos/ahci.h" #include "libqos/pci-pc.h" -#include "qemu-common.h" #include "qapi/qmp/qdict.h" #include "qemu/host-utils.h" @@ -45,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; @@ -155,6 +154,7 @@ static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri) /** * Start a Q35 machine and bookmark a handle to the AHCI device. */ +G_GNUC_PRINTF(1, 0) static AHCIQState *ahci_vboot(const char *cli, va_list ap) { AHCIQState *s; @@ -172,6 +172,7 @@ static AHCIQState *ahci_vboot(const char *cli, va_list ap) /** * Start a Q35 machine and bookmark a handle to the AHCI device. */ +G_GNUC_PRINTF(1, 2) static AHCIQState *ahci_boot(const char *cli, ...) { AHCIQState *s; @@ -210,6 +211,7 @@ static void ahci_shutdown(AHCIQState *ahci) * Boot and fully enable the HBA device. * @see ahci_boot, ahci_pci_enable and ahci_hba_enable. */ +G_GNUC_PRINTF(1, 2) static AHCIQState *ahci_boot_and_enable(const char *cli, ...) { AHCIQState *ahci; @@ -1438,10 +1440,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); @@ -1834,7 +1836,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; @@ -1872,8 +1874,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"; @@ -1890,12 +1906,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); @@ -1948,8 +1965,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/am53c974-test.c b/tests/qtest/am53c974-test.c index d214a912b3b4..ed3ac7db20de 100644 --- a/tests/qtest/am53c974-test.c +++ b/tests/qtest/am53c974-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" static void test_cmdfifo_underflow_ok(void) diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index f76652143acc..8691802950ca 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -10,7 +10,7 @@ */ #include "qemu/osdep.h" #include "qemu/bitops.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" @@ -32,6 +32,7 @@ static QDict *do_query_no_props(QTestState *qts, const char *cpu_type) QUERY_TAIL, cpu_type); } +G_GNUC_PRINTF(3, 4) static QDict *do_query(QTestState *qts, const char *cpu_type, const char *fmt, ...) { diff --git a/tests/qtest/aspeed_gpio-test.c b/tests/qtest/aspeed_gpio-test.c new file mode 100644 index 000000000000..d38f51d71908 --- /dev/null +++ b/tests/qtest/aspeed_gpio-test.c @@ -0,0 +1,90 @@ +/* + * QTest testcase for the Aspeed GPIO Controller. + * + * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "qemu/timer.h" +#include "qapi/qmp/qdict.h" +#include "libqtest-single.h" + +#define AST2600_GPIO_BASE 0x1E780000 + +#define GPIO_ABCD_DATA_VALUE 0x000 +#define GPIO_ABCD_DIRECTION 0x004 + +static void test_set_colocated_pins(const void *data) +{ + QTestState *s = (QTestState *)data; + + /* + * gpioV4-7 occupy bits within a single 32-bit value, so we want to make + * sure that modifying one doesn't affect the other. + */ + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV4", true); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV5", false); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV6", true); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV7", false); + g_assert(qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV4")); + g_assert(!qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV5")); + g_assert(qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV6")); + g_assert(!qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV7")); +} + +static void test_set_input_pins(const void *data) +{ + QTestState *s = (QTestState *)data; + char name[16]; + uint32_t value; + + qtest_writel(s, AST2600_GPIO_BASE + GPIO_ABCD_DIRECTION, 0x00000000); + for (char c = 'A'; c <= 'D'; c++) { + for (int i = 0; i < 8; i++) { + sprintf(name, "gpio%c%d", c, i); + qtest_qom_set_bool(s, "/machine/soc/gpio", name, true); + } + } + value = qtest_readl(s, AST2600_GPIO_BASE + GPIO_ABCD_DATA_VALUE); + g_assert_cmphex(value, ==, 0xffffffff); + + qtest_writel(s, AST2600_GPIO_BASE + GPIO_ABCD_DATA_VALUE, 0x00000000); + value = qtest_readl(s, AST2600_GPIO_BASE + GPIO_ABCD_DATA_VALUE); + g_assert_cmphex(value, ==, 0xffffffff); +} + +int main(int argc, char **argv) +{ + QTestState *s; + int r; + + g_test_init(&argc, &argv, NULL); + + s = qtest_init("-machine ast2600-evb"); + qtest_add_data_func("/ast2600/gpio/set_colocated_pins", s, + test_set_colocated_pins); + qtest_add_data_func("/ast2600/gpio/set_input_pins", s, test_set_input_pins); + r = g_test_run(); + qtest_quit(s); + + return r; +} diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index 09ee31545e41..ce86a44672ec 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -7,8 +7,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" -#include "qemu-common.h" +#include "libqtest.h" #include "qemu/bitops.h" #define HACE_CMD 0x10 @@ -21,6 +20,7 @@ #define HACE_ALGO_SHA512 (BIT(5) | BIT(6)) #define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10)) #define HACE_SG_EN BIT(18) +#define HACE_ACCUM_EN BIT(8) #define HACE_STS 0x1c #define HACE_RSA_ISR BIT(13) @@ -96,6 +96,57 @@ static const uint8_t test_result_sg_sha256[] = { 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3, 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4}; +/* + * The accumulative mode requires firmware to provide internal initial state + * and message padding (including length L at the end of padding). + * + * This test vector is a ascii text "abc" with padding message. + * + * Expected results were generated using command line utitiles: + * + * echo -n -e 'abc' | dd of=/tmp/test + * for hash in sha512sum sha256sum; do $hash /tmp/test; done + */ +static const uint8_t test_vector_accum_512[] = { + 0x61, 0x62, 0x63, 0x80, 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, + 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, 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, 0x18}; + +static const uint8_t test_vector_accum_256[] = { + 0x61, 0x62, 0x63, 0x80, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; + +static const uint8_t test_result_accum_sha512[] = { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, + 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, + 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, + 0xa5, 0x4c, 0xa4, 0x9f}; + +static const uint8_t test_result_accum_sha256[] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; static void write_regs(QTestState *s, uint32_t base, uint32_t src, uint32_t length, uint32_t out, uint32_t method) @@ -308,6 +359,88 @@ static void test_sha512_sg(const char *machine, const uint32_t base, qtest_quit(s); } +static void test_sha256_accum(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t buffer_addr = src_addr + 0x1000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[32] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST), + cpu_to_le32(buffer_addr) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, buffer_addr, test_vector_accum_256, + sizeof(test_vector_accum_256)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, sizeof(test_vector_accum_256), + digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN | HACE_ACCUM_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_accum_sha256, sizeof(digest)); + + qtest_quit(s); +} + +static void test_sha512_accum(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t buffer_addr = src_addr + 0x1000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[64] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST), + cpu_to_le32(buffer_addr) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, buffer_addr, test_vector_accum_512, + sizeof(test_vector_accum_512)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, sizeof(test_vector_accum_512), + digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN | HACE_ACCUM_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_accum_sha512, sizeof(digest)); + + qtest_quit(s); +} + struct masks { uint32_t src; uint32_t dest; @@ -396,6 +529,16 @@ static void test_sha512_sg_ast2600(void) test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } +static void test_sha256_accum_ast2600(void) +{ + test_sha256_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_sha512_accum_ast2600(void) +{ + test_sha512_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + static void test_addresses_ast2600(void) { test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks); @@ -455,6 +598,9 @@ int main(int argc, char **argv) qtest_add_func("ast2600/hace/sha512_sg", test_sha512_sg_ast2600); qtest_add_func("ast2600/hace/sha256_sg", test_sha256_sg_ast2600); + qtest_add_func("ast2600/hace/sha512_accum", test_sha512_accum_ast2600); + qtest_add_func("ast2600/hace/sha256_accum", test_sha256_accum_ast2600); + qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500); qtest_add_func("ast2500/hace/sha512", test_sha512_ast2500); qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500); diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index 87b40a0ef186..c713a3700b6d 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/bswap.h" #include "libqtest-single.h" +#include "qemu/bitops.h" /* * ASPEED SPI Controller registers @@ -40,6 +41,7 @@ #define CTRL_FREADMODE 0x1 #define CTRL_WRITEMODE 0x2 #define CTRL_USERMODE 0x3 +#define SR_WEL BIT(1) #define ASPEED_FMC_BASE 0x1E620000 #define ASPEED_FLASH_BASE 0x20000000 @@ -49,10 +51,14 @@ */ enum { JEDEC_READ = 0x9f, + RDSR = 0x5, + WRDI = 0x4, BULK_ERASE = 0xc7, READ = 0x03, PP = 0x02, + WRSR = 0x1, WREN = 0x6, + SRWD = 0x80, RESET_ENABLE = 0x66, RESET_MEMORY = 0x99, EN_4BYTE_ADDR = 0xB7, @@ -131,6 +137,9 @@ static void flash_reset(void) spi_ctrl_start_user(); writeb(ASPEED_FLASH_BASE, RESET_ENABLE); writeb(ASPEED_FLASH_BASE, RESET_MEMORY); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, BULK_ERASE); + writeb(ASPEED_FLASH_BASE, WRDI); spi_ctrl_stop_user(); spi_conf_remove(CONF_ENABLE_W0); @@ -183,6 +192,24 @@ static void read_page_mem(uint32_t addr, uint32_t *page) } } +static void write_page_mem(uint32_t addr, uint32_t write_value) +{ + spi_ctrl_setmode(CTRL_WRITEMODE, PP); + + for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + writel(ASPEED_FLASH_BASE + addr + i * 4, write_value); + } +} + +static void assert_page_mem(uint32_t addr, uint32_t expected_value) +{ + uint32_t page[FLASH_PAGE_SIZE / 4]; + read_page_mem(addr, page); + for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, expected_value); + } +} + static void test_erase_sector(void) { uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE; @@ -191,21 +218,41 @@ static void test_erase_sector(void) spi_conf(CONF_ENABLE_W0); + /* + * Previous page should be full of 0xffs after backend is + * initialized + */ + read_page(some_page_addr - FLASH_PAGE_SIZE, page); + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } + spi_ctrl_start_user(); - writeb(ASPEED_FLASH_BASE, WREN); writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); - writeb(ASPEED_FLASH_BASE, ERASE_SECTOR); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, PP); writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); + + /* Fill the page with its own addresses */ + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4)); + } spi_ctrl_stop_user(); - /* Previous page should be full of zeroes as backend is not - * initialized */ - read_page(some_page_addr - FLASH_PAGE_SIZE, page); + /* Check the page is correctly written */ + read_page(some_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { - g_assert_cmphex(page[i], ==, 0x0); + g_assert_cmphex(page[i], ==, some_page_addr + i * 4); } - /* But this one was erased */ + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, ERASE_SECTOR); + writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); + spi_ctrl_stop_user(); + + /* Check the page is erased */ read_page(some_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); @@ -222,11 +269,31 @@ static void test_erase_all(void) spi_conf(CONF_ENABLE_W0); - /* Check some random page. Should be full of zeroes as backend is - * not initialized */ + /* + * Previous page should be full of 0xffs after backend is + * initialized + */ + read_page(some_page_addr - FLASH_PAGE_SIZE, page); + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, PP); + writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); + + /* Fill the page with its own addresses */ + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4)); + } + spi_ctrl_stop_user(); + + /* Check the page is correctly written */ read_page(some_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { - g_assert_cmphex(page[i], ==, 0x0); + g_assert_cmphex(page[i], ==, some_page_addr + i * 4); } spi_ctrl_start_user(); @@ -234,7 +301,7 @@ static void test_erase_all(void) writeb(ASPEED_FLASH_BASE, BULK_ERASE); spi_ctrl_stop_user(); - /* Recheck that some random page */ + /* Check the page is erased */ read_page(some_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); @@ -295,6 +362,14 @@ static void test_read_page_mem(void) spi_conf(CONF_ENABLE_W0); spi_ctrl_start_user(); writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, PP); + writel(ASPEED_FLASH_BASE, make_be32(my_page_addr)); + + /* Fill the page with its own addresses */ + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4)); + } spi_ctrl_stop_user(); spi_conf_remove(CONF_ENABLE_W0); @@ -348,16 +423,200 @@ static void test_write_page_mem(void) flash_reset(); } -static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX"; +static void test_read_status_reg(void) +{ + uint8_t r; + + spi_conf(CONF_ENABLE_W0); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(r & SR_WEL, ==, 0); + g_assert(!qtest_qom_get_bool + (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(r & SR_WEL, ==, SR_WEL); + g_assert(qtest_qom_get_bool + (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WRDI); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(r & SR_WEL, ==, 0); + g_assert(!qtest_qom_get_bool + (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); + + flash_reset(); +} + +static void test_status_reg_write_protection(void) +{ + uint8_t r; + + spi_conf(CONF_ENABLE_W0); + + /* default case: WP# is high and SRWD is low -> status register writable */ + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + /* test ability to write SRWD */ + writeb(ASPEED_FLASH_BASE, WRSR); + writeb(ASPEED_FLASH_BASE, SRWD); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + g_assert_cmphex(r & SRWD, ==, SRWD); + + /* WP# high and SRWD high -> status register writable */ + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + /* test ability to write SRWD */ + writeb(ASPEED_FLASH_BASE, WRSR); + writeb(ASPEED_FLASH_BASE, 0); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + g_assert_cmphex(r & SRWD, ==, 0); + + /* WP# low and SRWD low -> status register writable */ + qtest_set_irq_in(global_qtest, + "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0); + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + /* test ability to write SRWD */ + writeb(ASPEED_FLASH_BASE, WRSR); + writeb(ASPEED_FLASH_BASE, SRWD); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + g_assert_cmphex(r & SRWD, ==, SRWD); + + /* WP# low and SRWD high -> status register NOT writable */ + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + /* test ability to write SRWD */ + writeb(ASPEED_FLASH_BASE, WRSR); + writeb(ASPEED_FLASH_BASE, 0); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + /* write is not successful */ + g_assert_cmphex(r & SRWD, ==, SRWD); + + qtest_set_irq_in(global_qtest, + "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1); + flash_reset(); +} + +static void test_write_block_protect(void) +{ + uint32_t sector_size = 65536; + uint32_t n_sectors = 512; + + spi_ce_ctrl(1 << CRTL_EXTENDED0); + spi_conf(CONF_ENABLE_W0); + + uint32_t bp_bits = 0b0; + + for (int i = 0; i < 16; i++) { + bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, BULK_ERASE); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, WRSR); + writeb(ASPEED_FLASH_BASE, bp_bits); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, WREN); + spi_ctrl_stop_user(); + + uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0; + uint32_t protection_start = n_sectors - num_protected_sectors; + uint32_t protection_end = n_sectors; + + for (int sector = 0; sector < n_sectors; sector++) { + uint32_t addr = sector * sector_size; + + assert_page_mem(addr, 0xffffffff); + write_page_mem(addr, make_be32(0xabcdef12)); + + uint32_t expected_value = protection_start <= sector + && sector < protection_end + ? 0xffffffff : 0xabcdef12; + + assert_page_mem(addr, expected_value); + } + } + + flash_reset(); +} + +static void test_write_block_protect_bottom_bit(void) +{ + uint32_t sector_size = 65536; + uint32_t n_sectors = 512; + + spi_ce_ctrl(1 << CRTL_EXTENDED0); + spi_conf(CONF_ENABLE_W0); + + /* top bottom bit is enabled */ + uint32_t bp_bits = 0b00100 << 3; + + for (int i = 0; i < 16; i++) { + bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, BULK_ERASE); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, WRSR); + writeb(ASPEED_FLASH_BASE, bp_bits); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, WREN); + spi_ctrl_stop_user(); + + uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0; + uint32_t protection_start = 0; + uint32_t protection_end = num_protected_sectors; + + for (int sector = 0; sector < n_sectors; sector++) { + uint32_t addr = sector * sector_size; + + assert_page_mem(addr, 0xffffffff); + write_page_mem(addr, make_be32(0xabcdef12)); + + uint32_t expected_value = protection_start <= sector + && sector < protection_end + ? 0xffffffff : 0xabcdef12; + + assert_page_mem(addr, expected_value); + } + } + + flash_reset(); +} 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); @@ -373,7 +632,15 @@ int main(int argc, char **argv) qtest_add_func("/ast2400/smc/write_page", test_write_page); qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem); qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem); + qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg); + qtest_add_func("/ast2400/smc/status_reg_write_protection", + test_status_reg_write_protection); + qtest_add_func("/ast2400/smc/write_block_protect", + test_write_block_protect); + qtest_add_func("/ast2400/smc/write_block_protect_bottom_bit", + test_write_block_protect_bottom_bit); + flash_reset(); ret = g_test_run(); qtest_quit(global_qtest); diff --git a/tests/qtest/bcm2835-dma-test.c b/tests/qtest/bcm2835-dma-test.c new file mode 100644 index 000000000000..8293d822b945 --- /dev/null +++ b/tests/qtest/bcm2835-dma-test.c @@ -0,0 +1,118 @@ +/* + * QTest testcase for BCM283x DMA engine (on Raspberry Pi 3) + * and its interrupts coming to Interrupt Controller. + * + * Copyright (c) 2022 Auriga LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" + +/* Offsets in raspi3b platform: */ +#define RASPI3_DMA_BASE 0x3f007000 +#define RASPI3_IC_BASE 0x3f00b200 + +/* Used register/fields definitions */ + +/* DMA engine registers: */ +#define BCM2708_DMA_CS 0 +#define BCM2708_DMA_ACTIVE (1 << 0) +#define BCM2708_DMA_INT (1 << 2) + +#define BCM2708_DMA_ADDR 0x04 + +#define BCM2708_DMA_INT_STATUS 0xfe0 + +/* DMA Trasfer Info fields: */ +#define BCM2708_DMA_INT_EN (1 << 0) +#define BCM2708_DMA_D_INC (1 << 4) +#define BCM2708_DMA_S_INC (1 << 8) + +/* Interrupt controller registers: */ +#define IRQ_PENDING_BASIC 0x00 +#define IRQ_GPU_PENDING1_AGGR (1 << 8) +#define IRQ_PENDING_1 0x04 +#define IRQ_ENABLE_1 0x10 + +/* Data for the test: */ +#define SCB_ADDR 256 +#define S_ADDR 32 +#define D_ADDR 64 +#define TXFR_LEN 32 +const uint32_t check_data = 0x12345678; + +static void bcm2835_dma_test_interrupt(int dma_c, int irq_line) +{ + uint64_t dma_base = RASPI3_DMA_BASE + dma_c * 0x100; + int gpu_irq_line = 16 + irq_line; + + /* Check that interrupts are silent by default: */ + writel(RASPI3_IC_BASE + IRQ_ENABLE_1, 1 << gpu_irq_line); + int isr = readl(dma_base + BCM2708_DMA_INT_STATUS); + g_assert_cmpint(isr, ==, 0); + uint32_t reg0 = readl(dma_base + BCM2708_DMA_CS); + g_assert_cmpint(reg0, ==, 0); + uint32_t ic_pending = readl(RASPI3_IC_BASE + IRQ_PENDING_BASIC); + g_assert_cmpint(ic_pending, ==, 0); + uint32_t gpu_pending1 = readl(RASPI3_IC_BASE + IRQ_PENDING_1); + g_assert_cmpint(gpu_pending1, ==, 0); + + /* Prepare Control Block: */ + writel(SCB_ADDR + 0, BCM2708_DMA_S_INC | BCM2708_DMA_D_INC | + BCM2708_DMA_INT_EN); /* transfer info */ + writel(SCB_ADDR + 4, S_ADDR); /* source address */ + writel(SCB_ADDR + 8, D_ADDR); /* destination address */ + writel(SCB_ADDR + 12, TXFR_LEN); /* transfer length */ + writel(dma_base + BCM2708_DMA_ADDR, SCB_ADDR); + + writel(S_ADDR, check_data); + for (int word = S_ADDR + 4; word < S_ADDR + TXFR_LEN; word += 4) { + writel(word, ~check_data); + } + /* Perform the transfer: */ + writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_ACTIVE); + + /* Check that destination == source: */ + uint32_t data = readl(D_ADDR); + g_assert_cmpint(data, ==, check_data); + for (int word = D_ADDR + 4; word < D_ADDR + TXFR_LEN; word += 4) { + data = readl(word); + g_assert_cmpint(data, ==, ~check_data); + } + + /* Check that interrupt status is set both in DMA and IC controllers: */ + isr = readl(RASPI3_DMA_BASE + BCM2708_DMA_INT_STATUS); + g_assert_cmpint(isr, ==, 1 << dma_c); + + ic_pending = readl(RASPI3_IC_BASE + IRQ_PENDING_BASIC); + g_assert_cmpint(ic_pending, ==, IRQ_GPU_PENDING1_AGGR); + + gpu_pending1 = readl(RASPI3_IC_BASE + IRQ_PENDING_1); + g_assert_cmpint(gpu_pending1, ==, 1 << gpu_irq_line); + + /* Clean up, clear interrupt: */ + writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_INT); +} + +static void bcm2835_dma_test_interrupts(void) +{ + /* DMA engines 0--10 have separate IRQ lines, 11--14 - only one: */ + bcm2835_dma_test_interrupt(0, 0); + bcm2835_dma_test_interrupt(10, 10); + bcm2835_dma_test_interrupt(11, 11); + bcm2835_dma_test_interrupt(14, 11); +} + +int main(int argc, char **argv) +{ + int ret; + g_test_init(&argc, &argv, NULL); + qtest_add_func("/bcm2835/dma/test_interrupts", + bcm2835_dma_test_interrupts); + qtest_start("-machine raspi3b"); + ret = g_test_run(); + qtest_end(); + return ret; +} diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index c4a2d1e1664b..8608408213d5 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -57,7 +57,6 @@ #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "hw/firmware/smbios.h" #include "qemu/bitmap.h" #include "acpi-utils.h" @@ -79,6 +78,7 @@ typedef struct { bool tcg_only; const char *machine; + const char *machine_param; const char *variant; const char *uefi_fl1; const char *uefi_fl2; @@ -89,10 +89,12 @@ typedef struct { uint64_t rsdp_addr; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; GArray *tables; - uint32_t smbios_ep_addr; - struct smbios_21_entry_point smbios_ep_table; + uint64_t smbios_ep_addr[SMBIOS_ENTRY_POINT_TYPE__MAX]; + SmbiosEntryPoint smbios_ep_table; uint16_t smbios_cpu_max_speed; uint16_t smbios_cpu_curr_speed; + uint8_t smbios_core_count; + uint16_t smbios_core_count2; uint8_t *required_struct_types; int required_struct_types_len; QTestState *qts; @@ -534,10 +536,9 @@ static void test_acpi_asl(test_data *data) free_test_data(&exp_data); } -static bool smbios_ep_table_ok(test_data *data) +static bool smbios_ep2_table_ok(test_data *data, uint32_t addr) { - struct smbios_21_entry_point *ep_table = &data->smbios_ep_table; - uint32_t addr = data->smbios_ep_addr; + struct smbios_21_entry_point *ep_table = &data->smbios_ep_table.ep21; qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table)); if (memcmp(ep_table->anchor_string, "_SM_", 4)) { @@ -560,13 +561,29 @@ static bool smbios_ep_table_ok(test_data *data) return true; } -static void test_smbios_entry_point(test_data *data) +static bool smbios_ep3_table_ok(test_data *data, uint64_t addr) +{ + struct smbios_30_entry_point *ep_table = &data->smbios_ep_table.ep30; + + qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table)); + if (memcmp(ep_table->anchor_string, "_SM3_", 5)) { + return false; + } + + if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table)) { + return false; + } + + return true; +} + +static SmbiosEntryPointType test_smbios_entry_point(test_data *data) { uint32_t off; /* find smbios entry point structure */ for (off = 0xf0000; off < 0x100000; off += 0x10) { - uint8_t sig[] = "_SM_"; + uint8_t sig[] = "_SM_", sig3[] = "_SM3_"; int i; for (i = 0; i < sizeof sig - 1; ++i) { @@ -575,14 +592,30 @@ static void test_smbios_entry_point(test_data *data) if (!memcmp(sig, "_SM_", sizeof sig)) { /* signature match, but is this a valid entry point? */ - data->smbios_ep_addr = off; - if (smbios_ep_table_ok(data)) { + if (smbios_ep2_table_ok(data, off)) { + data->smbios_ep_addr[SMBIOS_ENTRY_POINT_TYPE_32] = off; + } + } + + for (i = 0; i < sizeof sig3 - 1; ++i) { + sig3[i] = qtest_readb(data->qts, off + i); + } + + if (!memcmp(sig3, "_SM3_", sizeof sig3)) { + if (smbios_ep3_table_ok(data, off)) { + data->smbios_ep_addr[SMBIOS_ENTRY_POINT_TYPE_64] = off; + /* found 64-bit entry point, no need to look for 32-bit one */ break; } } } - g_assert_cmphex(off, <, 0x100000); + /* found at least one entry point */ + g_assert_true(data->smbios_ep_addr[SMBIOS_ENTRY_POINT_TYPE_32] || + data->smbios_ep_addr[SMBIOS_ENTRY_POINT_TYPE_64]); + + return data->smbios_ep_addr[SMBIOS_ENTRY_POINT_TYPE_64] ? + SMBIOS_ENTRY_POINT_TYPE_64 : SMBIOS_ENTRY_POINT_TYPE_32; } static inline bool smbios_single_instance(uint8_t type) @@ -601,41 +634,61 @@ static inline bool smbios_single_instance(uint8_t type) } } -static bool smbios_cpu_test(test_data *data, uint32_t addr) +static void smbios_cpu_test(test_data *data, uint32_t addr, + SmbiosEntryPointType ep_type) { - uint16_t expect_speed[2]; - uint16_t real; + uint8_t core_count, expected_core_count = data->smbios_core_count; + uint16_t speed, expected_speed[2]; + uint16_t core_count2, expected_core_count2 = data->smbios_core_count2; int offset[2]; int i; /* Check CPU speed for backward compatibility */ offset[0] = offsetof(struct smbios_type_4, max_speed); offset[1] = offsetof(struct smbios_type_4, current_speed); - expect_speed[0] = data->smbios_cpu_max_speed ? : 2000; - expect_speed[1] = data->smbios_cpu_curr_speed ? : 2000; + expected_speed[0] = data->smbios_cpu_max_speed ? : 2000; + expected_speed[1] = data->smbios_cpu_curr_speed ? : 2000; for (i = 0; i < 2; i++) { - real = qtest_readw(data->qts, addr + offset[i]); - if (real != expect_speed[i]) { - fprintf(stderr, "Unexpected SMBIOS CPU speed: real %u expect %u\n", - real, expect_speed[i]); - return false; - } + speed = qtest_readw(data->qts, addr + offset[i]); + g_assert_cmpuint(speed, ==, expected_speed[i]); } - return true; + core_count = qtest_readb(data->qts, + addr + offsetof(struct smbios_type_4, core_count)); + + if (expected_core_count) { + g_assert_cmpuint(core_count, ==, expected_core_count); + } + + if (ep_type == SMBIOS_ENTRY_POINT_TYPE_64) { + core_count2 = qtest_readw(data->qts, + addr + offsetof(struct smbios_type_4, core_count2)); + + /* Core Count has reached its limit, checking Core Count 2 */ + if (expected_core_count == 0xFF && expected_core_count2) { + g_assert_cmpuint(core_count2, ==, expected_core_count2); + } + } } -static void test_smbios_structs(test_data *data) +static void test_smbios_structs(test_data *data, SmbiosEntryPointType ep_type) { DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 }; - struct smbios_21_entry_point *ep_table = &data->smbios_ep_table; - uint32_t addr = le32_to_cpu(ep_table->structure_table_address); - int i, len, max_len = 0; + + SmbiosEntryPoint *ep_table = &data->smbios_ep_table; + int i = 0, len, max_len = 0; uint8_t type, prv, crt; + uint64_t addr; + + if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32) { + addr = le32_to_cpu(ep_table->ep21.structure_table_address); + } else { + addr = le64_to_cpu(ep_table->ep30.structure_table_address); + } /* walk the smbios tables */ - for (i = 0; i < le16_to_cpu(ep_table->number_of_structures); i++) { + do { /* grab type and formatted area length from struct header */ type = qtest_readb(data->qts, addr); @@ -649,7 +702,7 @@ static void test_smbios_structs(test_data *data) set_bit(type, struct_bitmap); if (type == 4) { - g_assert(smbios_cpu_test(data, addr)); + smbios_cpu_test(data, addr, ep_type); } /* seek to end of unformatted string area of this struct ("\0\0") */ @@ -661,19 +714,33 @@ static void test_smbios_structs(test_data *data) } /* keep track of max. struct size */ - if (max_len < len) { + if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32 && max_len < len) { max_len = len; - g_assert_cmpuint(max_len, <=, ep_table->max_structure_size); + g_assert_cmpuint(max_len, <=, ep_table->ep21.max_structure_size); } /* start of next structure */ addr += len; - } - /* total table length and max struct size must match entry point values */ - g_assert_cmpuint(le16_to_cpu(ep_table->structure_table_length), ==, - addr - le32_to_cpu(ep_table->structure_table_address)); - g_assert_cmpuint(le16_to_cpu(ep_table->max_structure_size), ==, max_len); + /* + * Until all structures have been scanned (ep21) + * or an EOF structure is found (ep30) + */ + } while (ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ? + ++i < le16_to_cpu(ep_table->ep21.number_of_structures) : + type != 127); + + if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32) { + /* + * Total table length and max struct size + * must match entry point values + */ + g_assert_cmpuint(le16_to_cpu(ep_table->ep21.structure_table_length), ==, + addr - le32_to_cpu(ep_table->ep21.structure_table_address)); + + g_assert_cmpuint(le16_to_cpu(ep_table->ep21.max_structure_size), ==, + max_len); + } /* required struct types must all be present */ for (i = 0; i < data->required_struct_types_len; i++) { @@ -710,26 +777,29 @@ static char *test_acpi_create_args(test_data *data, const char *params, * when arm/virt boad starts to support it. */ if (data->cd) { - args = g_strdup_printf("-machine %s %s -accel tcg " + args = g_strdup_printf("-machine %s%s %s -accel tcg " "-nodefaults -nographic " "-drive if=pflash,format=raw,file=%s,readonly=on " "-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s", - data->machine, data->tcg_only ? "" : "-accel kvm", + data->machine, data->machine_param ?: "", + data->tcg_only ? "" : "-accel kvm", data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : ""); } else { - args = g_strdup_printf("-machine %s %s -accel tcg " + args = g_strdup_printf("-machine %s%s %s -accel tcg " "-nodefaults -nographic " "-drive if=pflash,format=raw,file=%s,readonly=on " "-drive if=pflash,format=raw,file=%s,snapshot=on %s", - data->machine, data->tcg_only ? "" : "-accel kvm", + data->machine, data->machine_param ?: "", + data->tcg_only ? "" : "-accel kvm", data->uefi_fl1, data->uefi_fl2, params ? params : ""); } } else { - args = g_strdup_printf("-machine %s %s -accel tcg " - "-net none -display none %s " + args = g_strdup_printf("-machine %s%s %s -accel tcg " + "-net none %s " "-drive id=hd0,if=none,file=%s,format=raw " "-device %s,drive=hd0 ", - data->machine, data->tcg_only ? "" : "-accel kvm", + data->machine, data->machine_param ?: "", + data->tcg_only ? "" : "-accel kvm", params ? params : "", disk, data->blkdev ?: "ide-hd"); } @@ -757,8 +827,8 @@ static void test_acpi_one(const char *params, test_data *data) * https://bugs.launchpad.net/qemu/+bug/1821884 */ if (!use_uefi) { - test_smbios_entry_point(data); - test_smbios_structs(data); + SmbiosEntryPointType ep_type = test_smbios_entry_point(data); + test_smbios_structs(data, ep_type); } qtest_quit(data->qts); @@ -857,6 +927,21 @@ static void test_acpi_q35_tcg(void) free_test_data(&data); } +static void test_acpi_q35_tcg_core_count2(void) +{ + test_data data = { + .machine = MACHINE_Q35, + .variant = ".core-count2", + .required_struct_types = base_required_struct_types, + .required_struct_types_len = ARRAY_SIZE(base_required_struct_types), + .smbios_core_count = 0xFF, + .smbios_core_count2 = 275, + }; + + test_acpi_one("-machine smbios-entry-point-type=64 -smp 275", &data); + free_test_data(&data); +} + static void test_acpi_q35_tcg_bridge(void) { test_data data; @@ -956,6 +1041,21 @@ static void test_acpi_q35_tcg_ipmi(void) free_test_data(&data); } +static void test_acpi_q35_tcg_smbus_ipmi(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = MACHINE_Q35; + data.variant = ".ipmismbus"; + data.required_struct_types = ipmi_required_struct_types; + data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types); + test_acpi_one("-device ipmi-bmc-sim,id=bmc0" + " -device smbus-ipmi,bmc=bmc0", + &data); + free_test_data(&data); +} + static void test_acpi_piix4_tcg_ipmi(void) { test_data data; @@ -1045,8 +1145,9 @@ static void test_acpi_piix4_tcg_nohpet(void) memset(&data, 0, sizeof(data)); data.machine = MACHINE_PC; + data.machine_param = ",hpet=off"; data.variant = ".nohpet"; - test_acpi_one("-no-hpet", &data); + test_acpi_one(NULL, &data); free_test_data(&data); } @@ -1114,8 +1215,9 @@ static void test_acpi_q35_tcg_nohpet(void) memset(&data, 0, sizeof(data)); data.machine = MACHINE_Q35; + data.machine_param = ",hpet=off"; data.variant = ".nohpet"; - test_acpi_one("-no-hpet", &data); + test_acpi_one(NULL, &data); free_test_data(&data); } @@ -1447,6 +1549,112 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +static void test_acpi_virt_tcg_acpi_hmat(void) +{ + test_data data = { + .machine = "virt", + .tcg_only = true, + .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", + .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", + .ram_start = 0x40000000ULL, + .scan_len = 128ULL * 1024 * 1024, + }; + + data.variant = ".acpihmatvirt"; + + test_acpi_one(" -machine hmat=on" + " -cpu cortex-a57" + " -smp 4,sockets=2" + " -m 256M" + " -object memory-backend-ram,size=64M,id=ram0" + " -object memory-backend-ram,size=64M,id=ram1" + " -object memory-backend-ram,size=128M,id=ram2" + " -numa node,nodeid=0,memdev=ram0" + " -numa node,nodeid=1,memdev=ram1" + " -numa node,nodeid=2,memdev=ram2" + " -numa cpu,node-id=0,socket-id=0" + " -numa cpu,node-id=0,socket-id=0" + " -numa cpu,node-id=1,socket-id=1" + " -numa cpu,node-id=1,socket-id=1" + " -numa hmat-lb,initiator=0,target=0,hierarchy=memory," + "data-type=access-latency,latency=10" + " -numa hmat-lb,initiator=0,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=10485760" + " -numa hmat-lb,initiator=0,target=1,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=0,target=1,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=5242880" + " -numa hmat-lb,initiator=0,target=2,hierarchy=memory," + "data-type=access-latency,latency=30" + " -numa hmat-lb,initiator=0,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=1048576" + " -numa hmat-lb,initiator=1,target=0,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=1,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=5242880" + " -numa hmat-lb,initiator=1,target=1,hierarchy=memory," + "data-type=access-latency,latency=10" + " -numa hmat-lb,initiator=1,target=1,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=10485760" + " -numa hmat-lb,initiator=1,target=2,hierarchy=memory," + "data-type=access-latency,latency=30" + " -numa hmat-lb,initiator=1,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=1048576", + &data); + + free_test_data(&data); +} + +static void test_acpi_q35_tcg_acpi_hmat_noinitiator(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = MACHINE_Q35; + data.variant = ".acpihmat-noinitiator"; + test_acpi_one(" -machine hmat=on" + " -smp 4,sockets=2" + " -m 128M" + " -object memory-backend-ram,size=32M,id=ram0" + " -object memory-backend-ram,size=32M,id=ram1" + " -object memory-backend-ram,size=64M,id=ram2" + " -numa node,nodeid=0,memdev=ram0" + " -numa node,nodeid=1,memdev=ram1" + " -numa node,nodeid=2,memdev=ram2" + " -numa cpu,node-id=0,socket-id=0" + " -numa cpu,node-id=0,socket-id=0" + " -numa cpu,node-id=1,socket-id=1" + " -numa cpu,node-id=1,socket-id=1" + " -numa hmat-lb,initiator=0,target=0,hierarchy=memory," + "data-type=access-latency,latency=10" + " -numa hmat-lb,initiator=0,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=10485760" + " -numa hmat-lb,initiator=0,target=1,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=0,target=1,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=5242880" + " -numa hmat-lb,initiator=0,target=2,hierarchy=memory," + "data-type=access-latency,latency=30" + " -numa hmat-lb,initiator=0,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=1048576" + " -numa hmat-lb,initiator=1,target=0,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=1,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=5242880" + " -numa hmat-lb,initiator=1,target=1,hierarchy=memory," + "data-type=access-latency,latency=10" + " -numa hmat-lb,initiator=1,target=1,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=10485760" + " -numa hmat-lb,initiator=1,target=2,hierarchy=memory," + "data-type=access-latency,latency=30" + " -numa hmat-lb,initiator=1,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=1048576", + &data); + free_test_data(&data); +} + +#ifdef CONFIG_POSIX static void test_acpi_erst(const char *machine) { gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XXXXXX", NULL); @@ -1497,6 +1705,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) { @@ -1517,6 +1726,24 @@ static void test_acpi_virt_tcg(void) free_test_data(&data); } +static void test_acpi_virt_tcg_topology(void) +{ + test_data data = { + .machine = "virt", + .variant = ".topology", + .tcg_only = true, + .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", + .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", + .ram_start = 0x40000000ULL, + .scan_len = 128ULL * 1024 * 1024, + }; + + test_acpi_one("-cpu cortex-a57 " + "-smp sockets=1,clusters=2,cores=2,threads=2", &data); + free_test_data(&data); +} + static void test_acpi_q35_viot(void) { test_data data = { @@ -1537,6 +1764,51 @@ 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); + gchar *params; + + test_data data = { + .machine = MACHINE_Q35, + .variant = ".cxl", + }; + /* + * A complex CXL setup. + */ + params = g_strdup_printf(" -machine cxl=on" + " -object memory-backend-file,id=cxl-mem1,mem-path=%s,size=256M" + " -object memory-backend-file,id=cxl-mem2,mem-path=%s,size=256M" + " -object memory-backend-file,id=cxl-mem3,mem-path=%s,size=256M" + " -object memory-backend-file,id=cxl-mem4,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa1,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa2,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa3,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa4,mem-path=%s,size=256M" + " -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1" + " -device pxb-cxl,bus_nr=222,bus=pcie.0,id=cxl.2" + " -device cxl-rp,port=0,bus=cxl.1,id=rp1,chassis=0,slot=2" + " -device cxl-type3,bus=rp1,memdev=cxl-mem1,lsa=lsa1" + " -device cxl-rp,port=1,bus=cxl.1,id=rp2,chassis=0,slot=3" + " -device cxl-type3,bus=rp2,memdev=cxl-mem2,lsa=lsa2" + " -device cxl-rp,port=0,bus=cxl.2,id=rp3,chassis=0,slot=5" + " -device cxl-type3,bus=rp3,memdev=cxl-mem3,lsa=lsa3" + " -device cxl-rp,port=1,bus=cxl.2,id=rp4,chassis=0,slot=6" + " -device cxl-type3,bus=rp4,memdev=cxl-mem4,lsa=lsa4" + " -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=8k," + "cxl-fmw.1.targets.0=cxl.1,cxl-fmw.1.targets.1=cxl.2,cxl-fmw.1.size=4G,cxl-fmw.1.interleave-granularity=8k", + tmp_path, tmp_path, tmp_path, tmp_path, + tmp_path, tmp_path, tmp_path, tmp_path); + test_acpi_one(params, &data); + + g_free(params); + g_assert(g_rmdir(tmp_path) == 0); + g_free(tmp_path); + free_test_data(&data); +} +#endif /* CONFIG_POSIX */ + static void test_acpi_virt_viot(void) { test_data data = { @@ -1554,6 +1826,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 = { @@ -1561,13 +1839,37 @@ 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); } +static void test_acpi_q35_applesmc(void) +{ + test_data data = { + .machine = MACHINE_Q35, + .variant = ".applesmc", + }; + + /* supply fake 64-byte OSK to silence missing key warning */ + test_acpi_one("-device isa-applesmc,osk=any64characterfakeoskisenough" + "topreventinvalidkeywarningsonstderr", &data); + free_test_data(&data); +} + +static void test_acpi_q35_pvpanic_isa(void) +{ + test_data data = { + .machine = MACHINE_Q35, + .variant = ".pvpanic-isa", + }; + + test_acpi_one("-device pvpanic", &data); + free_test_data(&data); +} + static void test_oem_fields(test_data *data) { int i; @@ -1586,7 +1888,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; @@ -1606,7 +1908,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; @@ -1626,7 +1928,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; @@ -1643,7 +1945,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", @@ -1681,75 +1983,109 @@ 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/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/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); + qtest_add_func("acpi/q35/acpihmat-noinitiator", + test_acpi_q35_tcg_acpi_hmat_noinitiator); +#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/core-count2", + test_acpi_q35_tcg_core_count2); + } + 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 (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); + 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 + } + } } - qtest_add_func("acpi/q35/viot", test_acpi_q35_viot); - 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/acpihmatvirt", + test_acpi_virt_tcg_acpi_hmat); + qtest_add_func("acpi/virt/topology", test_acpi_virt_tcg_topology); 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-order-test.c b/tests/qtest/boot-order-test.c index f1f59b1261fe..0680d79d6da3 100644 --- a/tests/qtest/boot-order-test.c +++ b/tests/qtest/boot-order-test.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "libqos/fw_cfg.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "standard-headers/linux/qemu_fw_cfg.h" diff --git a/tests/qtest/boot-sector.c b/tests/qtest/boot-sector.c index ea8f264661c3..44a109abd8f0 100644 --- a/tests/qtest/boot-sector.c +++ b/tests/qtest/boot-sector.c @@ -12,8 +12,7 @@ */ #include "qemu/osdep.h" #include "boot-sector.h" -#include "qemu-common.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #define LOW(x) ((x) & 0xff) #define HIGH(x) ((x) >> 8) diff --git a/tests/qtest/boot-sector.h b/tests/qtest/boot-sector.h index b339fdee4c84..6ee6bb4d97f4 100644 --- a/tests/qtest/boot-sector.h +++ b/tests/qtest/boot-sector.h @@ -14,7 +14,7 @@ #ifndef TEST_BOOT_SECTOR_H #define TEST_BOOT_SECTOR_H -#include "libqos/libqtest.h" +#include "libqtest.h" /* Create boot disk file. fname must be a suitable string for mkstemp() */ int boot_sector_init(char *fname); diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index d72a82d6292e..b216519b62ff 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -14,7 +14,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/libqos-spapr.h" static const uint8_t bios_avr[] = { @@ -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 fdd889a487db..26a2400181a6 100644 --- a/tests/qtest/cdrom-test.c +++ b/tests/qtest/cdrom-test.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "boot-sector.h" #include "qapi/qmp/qdict.h" @@ -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/cpu-plug-test.c b/tests/qtest/cpu-plug-test.c index a1c689414be5..7f5dd5f85a78 100644 --- a/tests/qtest/cpu-plug-test.c +++ b/tests/qtest/cpu-plug-test.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "libqtest-single.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c new file mode 100644 index 000000000000..61f25a72b67b --- /dev/null +++ b/tests/qtest/cxl-test.c @@ -0,0 +1,155 @@ +/* + * QTest testcase for CXL + * + * 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-single.h" + +#define QEMU_PXB_CMD "-machine q35,cxl=on " \ + "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \ + "-M cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.size=4G " + +#define QEMU_2PXB_CMD "-machine q35,cxl=on " \ + "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \ + "-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 " \ + "-M cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=4G " + +#define QEMU_RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " + +/* Dual ports on first pxb */ +#define QEMU_2RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " \ + "-device cxl-rp,id=rp1,bus=cxl.0,chassis=0,slot=1 " + +/* Dual ports on each of the pxb instances */ +#define QEMU_4RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " \ + "-device cxl-rp,id=rp1,bus=cxl.0,chassis=0,slot=1 " \ + "-device cxl-rp,id=rp2,bus=cxl.1,chassis=0,slot=2 " \ + "-device cxl-rp,id=rp3,bus=cxl.1,chassis=0,slot=3 " + +#define QEMU_T3D "-object memory-backend-file,id=cxl-mem0,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa0,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp0,memdev=cxl-mem0,lsa=lsa0,id=cxl-pmem0 " + +#define QEMU_2T3D "-object memory-backend-file,id=cxl-mem0,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa0,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp0,memdev=cxl-mem0,lsa=lsa0,id=cxl-pmem0 " \ + "-object memory-backend-file,id=cxl-mem1,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa1,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp1,memdev=cxl-mem1,lsa=lsa1,id=cxl-pmem1 " + +#define QEMU_4T3D "-object memory-backend-file,id=cxl-mem0,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa0,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp0,memdev=cxl-mem0,lsa=lsa0,id=cxl-pmem0 " \ + "-object memory-backend-file,id=cxl-mem1,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa1,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp1,memdev=cxl-mem1,lsa=lsa1,id=cxl-pmem1 " \ + "-object memory-backend-file,id=cxl-mem2,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa2,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp2,memdev=cxl-mem2,lsa=lsa2,id=cxl-pmem2 " \ + "-object memory-backend-file,id=cxl-mem3,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa3,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp3,memdev=cxl-mem3,lsa=lsa3,id=cxl-pmem3 " + +static void cxl_basic_hb(void) +{ + qtest_start("-machine q35,cxl=on"); + qtest_end(); +} + +static void cxl_basic_pxb(void) +{ + qtest_start("-machine q35,cxl=on -device pxb-cxl,bus=pcie.0"); + qtest_end(); +} + +static void cxl_pxb_with_window(void) +{ + qtest_start(QEMU_PXB_CMD); + qtest_end(); +} + +static void cxl_2pxb_with_window(void) +{ + qtest_start(QEMU_2PXB_CMD); + qtest_end(); +} + +static void cxl_root_port(void) +{ + qtest_start(QEMU_PXB_CMD QEMU_RP); + qtest_end(); +} + +static void cxl_2root_port(void) +{ + qtest_start(QEMU_PXB_CMD QEMU_2RP); + qtest_end(); +} + +#ifdef CONFIG_POSIX +static void cxl_t3d(void) +{ + g_autoptr(GString) cmdline = g_string_new(NULL); + g_autofree const char *tmpfs = NULL; + + tmpfs = g_dir_make_tmp("cxl-test-XXXXXX", NULL); + + g_string_printf(cmdline, QEMU_PXB_CMD QEMU_RP QEMU_T3D, tmpfs, tmpfs); + + qtest_start(cmdline->str); + qtest_end(); + rmdir(tmpfs); +} + +static void cxl_1pxb_2rp_2t3d(void) +{ + g_autoptr(GString) cmdline = g_string_new(NULL); + g_autofree const char *tmpfs = NULL; + + tmpfs = g_dir_make_tmp("cxl-test-XXXXXX", NULL); + + g_string_printf(cmdline, QEMU_PXB_CMD QEMU_2RP QEMU_2T3D, + tmpfs, tmpfs, tmpfs, tmpfs); + + qtest_start(cmdline->str); + qtest_end(); + rmdir(tmpfs); +} + +static void cxl_2pxb_4rp_4t3d(void) +{ + g_autoptr(GString) cmdline = g_string_new(NULL); + g_autofree const char *tmpfs = NULL; + + 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, + tmpfs, tmpfs); + + qtest_start(cmdline->str); + qtest_end(); + rmdir(tmpfs); +} +#endif /* CONFIG_POSIX */ + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/pci/cxl/basic_hostbridge", cxl_basic_hb); + qtest_add_func("/pci/cxl/basic_pxb", cxl_basic_pxb); + qtest_add_func("/pci/cxl/pxb_with_window", cxl_pxb_with_window); + 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 43c77aff045c..cb1b62d1d11a 100644 --- a/tests/qtest/dbus-display-test.c +++ b/tests/qtest/dbus-display-test.c @@ -2,9 +2,8 @@ #include "qemu/dbus.h" #include #include -#include "libqos/libqtest.h" -#include "qemu-common.h" -#include "dbus-display1.h" +#include "libqtest.h" +#include "ui/dbus-display1.h" static GDBusConnection* test_dbus_p2p_from_fd(int fd) diff --git a/tests/qtest/dbus-vmstate-test.c b/tests/qtest/dbus-vmstate-test.c index aca9b98b7a35..6c990864e3eb 100644 --- a/tests/qtest/dbus-vmstate-test.c +++ b/tests/qtest/dbus-vmstate-test.c @@ -1,8 +1,7 @@ #include "qemu/osdep.h" #include #include -#include "libqos/libqtest.h" -#include "qemu-common.h" +#include "libqtest.h" #include "dbus-vmstate1.h" #include "migration-helpers.h" @@ -234,7 +233,7 @@ test_dbus_vmstate(Test *test) test->src_qemu = src_qemu; if (test->migrate_fail) { wait_for_migration_fail(src_qemu, true); - qtest_set_expected_status(dst_qemu, 1); + qtest_set_expected_status(dst_qemu, EXIT_FAILURE); } else { wait_for_migration_complete(src_qemu); } diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c index bbec166dbc2f..5b0ffe43f5f4 100644 --- a/tests/qtest/device-introspect-test.c +++ b/tests/qtest/device-introspect-test.c @@ -18,11 +18,10 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/qmp/qstring.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" -#include "libqos/libqtest.h" +#include "libqtest.h" const char common_args[] = "-nodefaults -machine none"; diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index 404a92e1328a..5a6afa2b57fa 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -11,21 +11,10 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" -static void device_del(QTestState *qtest, const char *id) -{ - QDict *resp; - - resp = qtest_qmp(qtest, - "{'execute': 'device_del', 'arguments': { 'id': %s } }", id); - - g_assert(qdict_haskey(resp, "return")); - qobject_unref(resp); -} - static void system_reset(QTestState *qtest) { QDict *resp; @@ -61,6 +50,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. + */ + qtest_qmp_device_del_send(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 +74,20 @@ 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); +} + +static void test_q35_pci_unplug_request(void) +{ + + QTestState *qtest = qtest_initf("-machine q35 " + "-device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1 " + "-device virtio-mouse-pci,bus=b1,id=dev0"); + + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } @@ -95,17 +102,31 @@ 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); +} + +static void test_q35_pci_unplug_json_request(void) +{ + const char *port = "-device \"{'driver': 'pcie-root-port', " + "'id': 'p1'}\""; + + const char *bridge = "-device \"{'driver': 'pcie-pci-bridge', " + "'id': 'b1', " + "'bus': 'p1'}\""; + + const char *device = "-device \"{'driver': 'virtio-mouse-pci', " + "'bus': 'b1', " + "'id': 'dev0'}\""; + + QTestState *qtest = qtest_initf("-machine q35 %s %s %s", + port, bridge, device); + + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } @@ -114,7 +135,7 @@ static void test_ccw_unplug(void) { QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0"); - device_del(qtest, "dev0"); + qtest_qmp_device_del_send(qtest, "dev0"); wait_device_deleted_event(qtest, "dev0"); qtest_quit(qtest); @@ -128,9 +149,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 +163,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 +175,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); } @@ -195,5 +210,12 @@ int main(int argc, char **argv) test_spapr_phb_unplug_request); } + if (!strcmp(arch, "x86_64") && qtest_has_machine("q35")) { + qtest_add_func("/device-plug/q35-pci-unplug-request", + test_q35_pci_unplug_request); + qtest_add_func("/device-plug/q35-pci-unplug-json-request", + test_q35_pci_unplug_json_request); + } + return g_test_run(); } diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c index 0cc18dfa4aae..9a750395a9d8 100644 --- a/tests/qtest/drive_del-test.c +++ b/tests/qtest/drive_del-test.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/virtio.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" @@ -123,12 +123,10 @@ static const char *qvirtio_get_dev_type(void) static void device_add(QTestState *qts) { - QDict *response; - char driver[32]; - snprintf(driver, sizeof(driver), "virtio-blk-%s", - qvirtio_get_dev_type()); - - response = qtest_qmp(qts, "{'execute': 'device_add'," + g_autofree char *driver = g_strdup_printf("virtio-blk-%s", + qvirtio_get_dev_type()); + QDict *response = + qtest_qmp(qts, "{'execute': 'device_add'," " 'arguments': {" " 'driver': %s," " 'drive': 'drive0'," @@ -143,11 +141,7 @@ static void device_del(QTestState *qts, bool and_reset) { QDict *response; - response = qtest_qmp(qts, "{'execute': 'device_del'," - " 'arguments': { 'id': 'dev0' } }"); - g_assert(response); - g_assert(qdict_haskey(response, "return")); - qobject_unref(response); + qtest_qmp_device_del_send(qts, "dev0"); if (and_reset) { response = qtest_qmp(qts, "{'execute': 'system_reset' }"); @@ -258,6 +252,27 @@ static void test_cli_device_del(void) qtest_quit(qts); } +static void test_cli_device_del_q35(void) +{ + QTestState *qts; + + /* + * -drive/-device and device_del. Start with a drive used by a + * device that unplugs after reset. + */ + qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," + "file.read-zeroes=on,format=raw " + "-machine q35 -device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1 " + "-device virtio-blk-%s,drive=drive0,bus=b1,id=dev0", + qvirtio_get_dev_type()); + + device_del(qts, true); + g_assert(!has_drive(qts)); + + qtest_quit(qts); +} + static void test_empty_device_del(void) { QTestState *qts; @@ -294,6 +309,43 @@ static void test_device_add_and_del(void) qtest_quit(qts); } +static void device_add_q35(QTestState *qts) +{ + g_autofree char *driver = g_strdup_printf("virtio-blk-%s", + qvirtio_get_dev_type()); + QDict *response = + qtest_qmp(qts, "{'execute': 'device_add'," + " 'arguments': {" + " 'driver': %s," + " 'drive': 'drive0'," + " 'id': 'dev0'," + " 'bus': 'b1'" + "}}", driver); + g_assert(response); + g_assert(qdict_haskey(response, "return")); + qobject_unref(response); +} + +static void test_device_add_and_del_q35(void) +{ + QTestState *qts; + + /* + * -drive/device_add and device_del. Start with a drive used by a + * device that unplugs after reset. + */ + qts = qtest_initf("-machine q35 -device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1 " + "-drive if=none,id=drive0,file=null-co://," + "file.read-zeroes=on,format=raw"); + + device_add_q35(qts); + device_del(qts, true); + g_assert(!has_drive(qts)); + + qtest_quit(qts); +} + static void test_drive_add_device_add_and_del(void) { QTestState *qts; @@ -318,6 +370,25 @@ static void test_drive_add_device_add_and_del(void) qtest_quit(qts); } +static void test_drive_add_device_add_and_del_q35(void) +{ + QTestState *qts; + + qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1"); + + /* + * drive_add/device_add and device_del. The drive is used by a + * device that unplugs after reset. + */ + drive_add_with_media(qts); + device_add_q35(qts); + device_del(qts, true); + g_assert(!has_drive(qts)); + + qtest_quit(qts); +} + static void test_blockdev_add_device_add_and_del(void) { QTestState *qts; @@ -331,7 +402,7 @@ static void test_blockdev_add_device_add_and_del(void) qts = qtest_init(machine_addition); /* - * blockdev_add/device_add and device_del. The it drive is used by a + * blockdev_add/device_add and device_del. The drive is used by a * device that unplugs after reset, but it doesn't go away. */ blockdev_add_with_media(qts); @@ -342,6 +413,25 @@ static void test_blockdev_add_device_add_and_del(void) qtest_quit(qts); } +static void test_blockdev_add_device_add_and_del_q35(void) +{ + QTestState *qts; + + qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1"); + + /* + * blockdev_add/device_add and device_del. The drive is used by a + * device that unplugs after reset, but it doesn't go away. + */ + blockdev_add_with_media(qts); + device_add_q35(qts); + device_del(qts, true); + g_assert(has_blockdev(qts)); + + qtest_quit(qts); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -363,6 +453,17 @@ int main(int argc, char **argv) test_empty_device_del); qtest_add_func("/device_del/blockdev", test_blockdev_add_device_add_and_del); + + if (qtest_has_machine("q35")) { + qtest_add_func("/device_del/drive/cli_device_q35", + test_cli_device_del_q35); + qtest_add_func("/device_del/drive/device_add_q35", + test_device_add_and_del_q35); + qtest_add_func("/device_del/drive/drive_add_device_add_q35", + test_drive_add_device_add_and_del_q35); + qtest_add_func("/device_del/blockdev_q35", + test_blockdev_add_device_add_and_del_q35); + } } return g_test_run(); diff --git a/tests/qtest/ds1338-test.c b/tests/qtest/ds1338-test.c index c5d46bcc643d..f6ade9a050fb 100644 --- a/tests/qtest/ds1338-test.c +++ b/tests/qtest/ds1338-test.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/i2c.h" #define DS1338_ADDR 0x68 diff --git a/tests/qtest/e1000-test.c b/tests/qtest/e1000-test.c index ea286d179304..4e0d7a560732 100644 --- a/tests/qtest/e1000-test.c +++ b/tests/qtest/e1000-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" @@ -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 e648fdd409cd..3fc92046be32 100644 --- a/tests/qtest/e1000e-test.c +++ b/tests/qtest/e1000e-test.c @@ -25,61 +25,36 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "libqtest-single.h" -#include "qemu-common.h" #include "libqos/pci-pc.h" #include "qemu/sockets.h" #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" +#include "hw/net/e1000_regs.h" static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc) { - struct { - uint64_t buffer_addr; - union { - uint32_t data; - struct { - uint16_t length; - uint8_t cso; - uint8_t cmd; - } flags; - } lower; - union { - uint32_t data; - struct { - uint8_t status; - uint8_t css; - uint16_t special; - } fields; - } upper; - } descr; - - static const uint32_t dtyp_data = BIT(20); - static const uint32_t dtyp_ext = BIT(29); - static const uint32_t dcmd_rs = BIT(27); - static const uint32_t dcmd_eop = BIT(24); - static const uint32_t dsta_dd = BIT(0); - static const int data_len = 64; + static const char test[] = "TEST"; + struct e1000_tx_desc descr; char buffer[64]; int ret; uint32_t recv_len; /* Prepare test data buffer */ - uint64_t data = guest_alloc(alloc, data_len); - memwrite(data, "TEST", 5); + uint64_t data = guest_alloc(alloc, sizeof(buffer)); + memwrite(data, test, sizeof(test)); /* Prepare TX descriptor */ memset(&descr, 0, sizeof(descr)); descr.buffer_addr = cpu_to_le64(data); - descr.lower.data = cpu_to_le32(dcmd_rs | - dcmd_eop | - dtyp_ext | - dtyp_data | - data_len); + descr.lower.data = cpu_to_le32(E1000_TXD_CMD_RS | + E1000_TXD_CMD_EOP | + E1000_TXD_CMD_DEXT | + E1000_TXD_DTYP_D | + sizeof(buffer)); /* Put descriptor to the ring */ e1000e_tx_ring_push(d, &descr); @@ -88,14 +63,15 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a e1000e_wait_isr(d, E1000E_TX0_MSG_ID); /* Check DD bit */ - g_assert_cmphex(le32_to_cpu(descr.upper.data) & dsta_dd, ==, dsta_dd); + g_assert_cmphex(le32_to_cpu(descr.upper.data) & E1000_TXD_STAT_DD, ==, + E1000_TXD_STAT_DD); /* Check data sent to the backend */ ret = recv(test_sockets[0], &recv_len, sizeof(recv_len), 0); g_assert_cmpint(ret, == , sizeof(recv_len)); - ret = recv(test_sockets[0], buffer, 64, 0); - g_assert_cmpint(ret, >=, 5); - g_assert_cmpstr(buffer, == , "TEST"); + ret = recv(test_sockets[0], buffer, sizeof(buffer), 0); + g_assert_cmpint(ret, ==, sizeof(buffer)); + g_assert_cmpstr(buffer, == , test); /* Free test data buffer */ guest_free(alloc, data); @@ -103,31 +79,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc) { - union { - struct { - uint64_t buffer_addr; - uint64_t reserved; - } read; - struct { - struct { - uint32_t mrq; - union { - uint32_t rss; - struct { - uint16_t ip_id; - uint16_t csum; - } csum_ip; - } hi_dword; - } lower; - struct { - uint32_t status_error; - uint16_t length; - uint16_t vlan; - } upper; - } wb; - } descr; - - static const uint32_t esta_dd = BIT(0); + union e1000_rx_desc_extended descr; char test[] = "TEST"; int len = htonl(sizeof(test)); @@ -141,7 +93,6 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator }, }; - static const int data_len = 64; char buffer[64]; int ret; @@ -150,7 +101,7 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator g_assert_cmpint(ret, == , sizeof(test) + sizeof(len)); /* Prepare test data buffer */ - uint64_t data = guest_alloc(alloc, data_len); + uint64_t data = guest_alloc(alloc, sizeof(buffer)); /* Prepare RX descriptor */ memset(&descr, 0, sizeof(descr)); @@ -164,11 +115,11 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator /* Check DD bit */ g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) & - esta_dd, ==, esta_dd); + E1000_RXD_STAT_DD, ==, E1000_RXD_STAT_DD); /* Check data sent to the backend */ memread(data, buffer, sizeof(buffer)); - g_assert_cmpstr(buffer, == , "TEST"); + g_assert_cmpstr(buffer, == , test); /* Free test data buffer */ guest_free(alloc, data); @@ -235,6 +186,12 @@ static void test_e1000e_multiple_transfers(void *obj, void *data, static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc) { QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */ + QE1000E_PCI *dev = obj; + + if (dev->pci_dev.bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}"); qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06); diff --git a/tests/qtest/eepro100-test.c b/tests/qtest/eepro100-test.c index d72ad099f1eb..8dbffff0b81b 100644 --- a/tests/qtest/eepro100-test.c +++ b/tests/qtest/eepro100-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/endianness-test.c b/tests/qtest/endianness-test.c index 9c03b72dc9c0..222d116fae2d 100644 --- a/tests/qtest/endianness-test.c +++ b/tests/qtest/endianness-test.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/bswap.h" typedef struct TestCase TestCase; @@ -28,6 +28,7 @@ struct TestCase { static const TestCase test_cases[] = { { "i386", "pc", -1 }, { "mips", "malta", 0x10000000, .bswap = true }, + { "mipsel", "malta", 0x10000000 }, { "mips64", "magnum", 0x90000000, .bswap = true }, { "mips64", "pica61", 0x90000000, .bswap = true }, { "mips64", "malta", 0x10000000, .bswap = true }, diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c index f94cd8dd8e05..c45bee7f054c 100644 --- a/tests/qtest/erst-test.c +++ b/tests/qtest/erst-test.c @@ -10,8 +10,7 @@ #include "qemu/osdep.h" #include #include "libqos/libqos-pc.h" -#include "libqos/libqtest.h" -#include "qemu-common.h" +#include "libqtest.h" #include "hw/pci/pci.h" @@ -99,7 +98,7 @@ static void setup_vm_cmd(ERSTState *s, const char *cmd) const char *arch = qtest_get_arch(); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - s->qs = qtest_pc_boot(cmd); + s->qs = qtest_pc_boot("%s", cmd); } else { g_printerr("erst-test tests are only available on x86\n"); exit(EXIT_FAILURE); @@ -155,10 +154,7 @@ static void test_acpi_erst_basic(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic); - ret = g_test_run(); - return ret; + return g_test_run(); } diff --git a/tests/qtest/es1370-test.c b/tests/qtest/es1370-test.c index 2fd7fd2d3d30..97ab65c4357e 100644 --- a/tests/qtest/es1370-test.c +++ b/tests/qtest/es1370-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" @@ -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 b0d40012e6a9..1f9b99ad6d22 100644 --- a/tests/qtest/fdc-test.c +++ b/tests/qtest/fdc-test.c @@ -27,7 +27,6 @@ #include "libqtest-single.h" #include "qapi/qmp/qdict.h" -#include "qemu-common.h" /* TODO actually test the results and get rid of this */ #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__)) @@ -69,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) @@ -551,7 +550,7 @@ static void fuzz_registers(void) static bool qtest_check_clang_sanitizer(void) { -#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +#ifdef QEMU_SANITIZE_ADDRESS return true; #else g_test_skip("QEMU not configured using --enable-sanitizers"); @@ -583,13 +582,33 @@ static void test_cve_2021_20196(void) qtest_quit(s); } +static void test_cve_2021_3507(void) +{ + QTestState *s; + + s = qtest_initf("-nographic -m 32M -nodefaults " + "-drive file=%s,format=raw,if=floppy,snapshot=on", + test_image); + qtest_outl(s, 0x9, 0x0a0206); + qtest_outw(s, 0x3f4, 0x1600); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0200); + qtest_outw(s, 0x3f4, 0x0200); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_quit(s); +} + int main(int argc, char **argv) { int fd; 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); @@ -614,12 +633,14 @@ int main(int argc, char **argv) qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); qtest_add_func("/fdc/fuzz-registers", fuzz_registers); qtest_add_func("/fdc/fuzz/cve_2021_20196", test_cve_2021_20196); + qtest_add_func("/fdc/fuzz/cve_2021_3507", test_cve_2021_3507); ret = g_test_run(); /* Cleanup */ qtest_end(); unlink(test_image); + g_free(test_image); return ret; } diff --git a/tests/qtest/fuzz-e1000e-test.c b/tests/qtest/fuzz-e1000e-test.c index 66229e60964a..5052883fb6a8 100644 --- a/tests/qtest/fuzz-e1000e-test.c +++ b/tests/qtest/fuzz-e1000e-test.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * https://bugs.launchpad.net/qemu/+bug/1879531 diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c index ba5d468970cf..392a7ae7edec 100644 --- a/tests/qtest/fuzz-lsi53c895a-test.c +++ b/tests/qtest/fuzz-lsi53c895a-test.c @@ -6,7 +6,80 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" + +/* + * This used to trigger a UAF in lsi_do_msgout() + * https://gitlab.com/qemu-project/qemu/-/issues/972 + */ +static void test_lsi_do_msgout_cancel_req(void) +{ + QTestState *s; + + if (sizeof(void *) == 4) { + g_test_skip("memory size too big for 32-bit build"); + return; + } + + s = qtest_init("-M q35 -m 2G -nodefaults " + "-device lsi53c895a,id=scsi " + "-device scsi-hd,drive=disk0 " + "-drive file=null-co://,id=disk0,if=none,format=raw"); + + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outl(s, 0xcf8, 0xc000); + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outw(s, 0xcfc, 0x7); + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outl(s, 0xcfc, 0xc000); + qtest_outl(s, 0xcf8, 0x80000804); + qtest_outw(s, 0xcfc, 0x05); + qtest_writeb(s, 0x69736c10, 0x08); + qtest_writeb(s, 0x69736c13, 0x58); + qtest_writeb(s, 0x69736c1a, 0x01); + qtest_writeb(s, 0x69736c1b, 0x06); + qtest_writeb(s, 0x69736c22, 0x01); + qtest_writeb(s, 0x69736c23, 0x07); + qtest_writeb(s, 0x69736c2b, 0x02); + qtest_writeb(s, 0x69736c48, 0x08); + qtest_writeb(s, 0x69736c4b, 0x58); + qtest_writeb(s, 0x69736c52, 0x04); + qtest_writeb(s, 0x69736c53, 0x06); + qtest_writeb(s, 0x69736c5b, 0x02); + qtest_outl(s, 0xc02d, 0x697300); + qtest_writeb(s, 0x5a554662, 0x01); + qtest_writeb(s, 0x5a554663, 0x07); + qtest_writeb(s, 0x5a55466a, 0x10); + qtest_writeb(s, 0x5a55466b, 0x22); + qtest_writeb(s, 0x5a55466c, 0x5a); + qtest_writeb(s, 0x5a55466d, 0x5a); + qtest_writeb(s, 0x5a55466e, 0x34); + qtest_writeb(s, 0x5a55466f, 0x5a); + qtest_writeb(s, 0x5a345a5a, 0x77); + qtest_writeb(s, 0x5a345a5b, 0x55); + qtest_writeb(s, 0x5a345a5c, 0x51); + qtest_writeb(s, 0x5a345a5d, 0x27); + qtest_writeb(s, 0x27515577, 0x41); + qtest_outl(s, 0xc02d, 0x5a5500); + qtest_writeb(s, 0x364001d0, 0x08); + qtest_writeb(s, 0x364001d3, 0x58); + qtest_writeb(s, 0x364001da, 0x01); + qtest_writeb(s, 0x364001db, 0x26); + qtest_writeb(s, 0x364001dc, 0x0d); + qtest_writeb(s, 0x364001dd, 0xae); + qtest_writeb(s, 0x364001de, 0x41); + qtest_writeb(s, 0x364001df, 0x5a); + qtest_writeb(s, 0x5a41ae0d, 0xf8); + qtest_writeb(s, 0x5a41ae0e, 0x36); + qtest_writeb(s, 0x5a41ae0f, 0xd7); + qtest_writeb(s, 0x5a41ae10, 0x36); + qtest_writeb(s, 0x36d736f8, 0x0c); + qtest_writeb(s, 0x36d736f9, 0x80); + qtest_writeb(s, 0x36d736fa, 0x0d); + qtest_outl(s, 0xc02d, 0x364000); + + qtest_quit(s); +} /* * This used to trigger the assert in lsi_do_dma() @@ -39,14 +112,13 @@ static void test_lsi_do_dma_empty_queue(void) int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); - g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", - test_lsi_do_dma_empty_queue); - } + qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", + test_lsi_do_dma_empty_queue); + + qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req", + test_lsi_do_msgout_cancel_req); return g_test_run(); } diff --git a/tests/qtest/fuzz-megasas-test.c b/tests/qtest/fuzz-megasas-test.c index e1141c58a4ec..8d7ed3723a3d 100644 --- a/tests/qtest/fuzz-megasas-test.c +++ b/tests/qtest/fuzz-megasas-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * This used to trigger the assert in scsi_dma_complete @@ -40,7 +40,7 @@ static void test_lp1878263_megasas_zero_iov_cnt(void) */ static void test_gitlab_issue521_megasas_sgl_ovf(void) { - QTestState *s = qtest_init("-display none -m 32M -machine q35 " + QTestState *s = qtest_init("-m 32M -machine q35 " "-nodefaults -device megasas " "-device scsi-cd,drive=null0 " "-blockdev " @@ -64,16 +64,12 @@ static void test_gitlab_issue521_megasas_sgl_ovf(void) int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); - g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("fuzz/test_lp1878263_megasas_zero_iov_cnt", - test_lp1878263_megasas_zero_iov_cnt); - qtest_add_func("fuzz/gitlab_issue521_megasas_sgl_ovf", - test_gitlab_issue521_megasas_sgl_ovf); - } + qtest_add_func("fuzz/test_lp1878263_megasas_zero_iov_cnt", + test_lp1878263_megasas_zero_iov_cnt); + qtest_add_func("fuzz/gitlab_issue521_megasas_sgl_ovf", + test_gitlab_issue521_megasas_sgl_ovf); return g_test_run(); } diff --git a/tests/qtest/fuzz-sb16-test.c b/tests/qtest/fuzz-sb16-test.c index f47a8bcdbd91..fc445b18710e 100644 --- a/tests/qtest/fuzz-sb16-test.c +++ b/tests/qtest/fuzz-sb16-test.c @@ -7,7 +7,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * This used to trigger the assert in audio_calloc @@ -15,7 +15,7 @@ */ static void test_fuzz_sb16_0x1c(void) { - QTestState *s = qtest_init("-M q35 -display none " + QTestState *s = qtest_init("-M q35 " "-device sb16,audiodev=snd0 " "-audiodev none,id=snd0"); qtest_outw(s, 0x22c, 0x41); @@ -27,7 +27,7 @@ static void test_fuzz_sb16_0x1c(void) static void test_fuzz_sb16_0x91(void) { - QTestState *s = qtest_init("-M pc -display none " + QTestState *s = qtest_init("-M pc " "-device sb16,audiodev=none " "-audiodev id=none,driver=none"); qtest_outw(s, 0x22c, 0xf141); @@ -43,7 +43,7 @@ static void test_fuzz_sb16_0x91(void) */ static void test_fuzz_sb16_0xd4(void) { - QTestState *s = qtest_init("-M pc -display none " + QTestState *s = qtest_init("-M pc " "-device sb16,audiodev=none " "-audiodev id=none,driver=none"); qtest_outb(s, 0x22c, 0x41); @@ -55,15 +55,15 @@ static void test_fuzz_sb16_0xd4(void) int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); - g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "i386") == 0) { + 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(); + return g_test_run(); } diff --git a/tests/qtest/fuzz-sdcard-test.c b/tests/qtest/fuzz-sdcard-test.c index 0f94965a66e7..cd134cdf5568 100644 --- a/tests/qtest/fuzz-sdcard-test.c +++ b/tests/qtest/fuzz-sdcard-test.c @@ -7,7 +7,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * https://gitlab.com/qemu-project/qemu/-/issues/450 @@ -18,7 +18,7 @@ static void oss_fuzz_29225(void) { QTestState *s; - s = qtest_init(" -display none -m 512m -nodefaults -nographic" + s = qtest_init(" -m 512m -nodefaults -nographic" " -device sdhci-pci,sd-spec-version=3" " -device sd-card,drive=d0" " -drive if=none,index=0,file=null-co://,format=raw,id=d0"); @@ -61,7 +61,7 @@ static void oss_fuzz_36217(void) { QTestState *s; - s = qtest_init(" -display none -m 32 -nodefaults -nographic" + s = qtest_init(" -m 32 -nodefaults -nographic" " -device sdhci-pci,sd-spec-version=3 " "-device sd-card,drive=d0 " "-drive if=none,index=0,file=null-co://,format=raw,id=d0"); @@ -95,7 +95,7 @@ static void oss_fuzz_36391(void) { QTestState *s; - s = qtest_init(" -display none -m 512M -nodefaults -nographic" + s = qtest_init(" -m 512M -nodefaults -nographic" " -device sdhci-pci,sd-spec-version=3" " -device sd-card,drive=drv" " -drive if=none,index=0,file=null-co://,format=raw,id=drv"); @@ -164,15 +164,11 @@ static void oss_fuzz_36391(void) int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); - g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "i386") == 0) { - qtest_add_func("fuzz/sdcard/oss_fuzz_29225", oss_fuzz_29225); - qtest_add_func("fuzz/sdcard/oss_fuzz_36217", oss_fuzz_36217); - qtest_add_func("fuzz/sdcard/oss_fuzz_36391", oss_fuzz_36391); - } + qtest_add_func("fuzz/sdcard/oss_fuzz_29225", oss_fuzz_29225); + qtest_add_func("fuzz/sdcard/oss_fuzz_36217", oss_fuzz_36217); + qtest_add_func("fuzz/sdcard/oss_fuzz_36391", oss_fuzz_36391); - return g_test_run(); + return g_test_run(); } diff --git a/tests/qtest/fuzz-virtio-scsi-test.c b/tests/qtest/fuzz-virtio-scsi-test.c index aaf6d10e189d..e37b48b2cc1a 100644 --- a/tests/qtest/fuzz-virtio-scsi-test.c +++ b/tests/qtest/fuzz-virtio-scsi-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * Here a MemoryRegionCache pointed to an MMIO region but had a @@ -19,7 +19,7 @@ static void test_mmio_oob_from_memory_region_cache(void) { QTestState *s; - s = qtest_init("-M pc-q35-5.2 -display none -m 512M " + s = qtest_init("-M pc-q35-5.2 -m 512M " "-device virtio-scsi,num_queues=8,addr=03.0 "); qtest_outl(s, 0xcf8, 0x80001811); @@ -62,14 +62,10 @@ static void test_mmio_oob_from_memory_region_cache(void) int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); - g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("fuzz/test_mmio_oob_from_memory_region_cache", - test_mmio_oob_from_memory_region_cache); - } + qtest_add_func("fuzz/test_mmio_oob_from_memory_region_cache", + test_mmio_oob_from_memory_region_cache); return g_test_run(); } diff --git a/tests/qtest/fuzz-xlnx-dp-test.c b/tests/qtest/fuzz-xlnx-dp-test.c index 69eb6c0eb104..e8c483965f0e 100644 --- a/tests/qtest/fuzz-xlnx-dp-test.c +++ b/tests/qtest/fuzz-xlnx-dp-test.c @@ -7,14 +7,14 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * This used to trigger the out-of-bounds read in xlnx_dp_read */ static void test_fuzz_xlnx_dp_0x3ac(void) { - QTestState *s = qtest_init("-M xlnx-zcu102 -display none "); + QTestState *s = qtest_init("-M xlnx-zcu102 "); qtest_readl(s, 0xfd4a03ac); qtest_quit(s); } diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 5f77c849837f..eb7520544b80 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -15,13 +15,14 @@ #include +#include "qemu/cutils.h" #include "qemu/datadir.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "sysemu/runstate.h" #include "qemu/main-loop.h" #include "qemu/rcu.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/qgraph.h" #include "fuzz.h" @@ -157,8 +158,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) { char *target_name; - const char *bindir; - char *datadir; GString *cmd_line; gchar *pretty_cmd_line; bool serialize = false; @@ -173,22 +172,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) target_name = strstr(**argv, "-target-"); if (target_name) { /* The binary name specifies the target */ target_name += strlen("-target-"); - /* - * With oss-fuzz, the executable is kept in the root of a directory (we - * cannot assume the path). All data (including bios binaries) must be - * in the same dir, or a subdir. Thus, we cannot place the pc-bios so - * that it would be in exec_dir/../pc-bios. - * As a workaround, oss-fuzz allows us to use argv[0] to get the - * location of the executable. Using this we add exec_dir/pc-bios to - * the datadirs. - */ - bindir = qemu_get_exec_dir(); - datadir = g_build_filename(bindir, "pc-bios", NULL); - if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { - qemu_add_data_dir(datadir); - } else { - g_free(datadir); - } } else if (*argc > 1) { /* The target is specified as an argument */ target_name = (*argv)[1]; if (!strstr(target_name, "--fuzz-target=")) { @@ -235,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/fuzz.h b/tests/qtest/fuzz/fuzz.h index 3a8570e84c79..327c1c5a55b2 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -11,13 +11,13 @@ * */ -#ifndef FUZZER_H_ -#define FUZZER_H_ +#ifndef QTEST_FUZZ_H +#define QTEST_FUZZ_H #include "qemu/units.h" #include "qapi/error.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" /** * A libfuzzer fuzzing target @@ -122,4 +122,3 @@ int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size); int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp); #endif - diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index dd7e25851cb6..7326f6840b4f 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -15,7 +15,7 @@ #include #include "hw/core/cpu.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/pci-pc.h" #include "fuzz.h" #include "fork_fuzz.h" @@ -24,6 +24,7 @@ #include "exec/ramblock.h" #include "hw/qdev-core.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/boards.h" #include "generic_fuzz_configs.h" #include "hw/mem/sparse-mem.h" @@ -144,7 +145,7 @@ static void *pattern_alloc(pattern p, size_t len) return buf; } -static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) +static int fuzz_memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) { unsigned access_size_max = mr->ops->valid.max_access_size; @@ -242,11 +243,12 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr) /* * If mr1 isn't RAM, address_space_translate doesn't update l. Use - * memory_access_size to identify the number of bytes that it is safe - * to write without accidentally writing to another MemoryRegion. + * fuzz_memory_access_size to identify the number of bytes that it + * is safe to write without accidentally writing to another + * MemoryRegion. */ if (!memory_region_is_ram(mr1)) { - l = memory_access_size(mr1, l, addr1); + l = fuzz_memory_access_size(mr1, l, addr1); } if (memory_region_is_ram(mr1) || memory_region_is_romd(mr1) || @@ -743,14 +745,12 @@ static void usage(void) static int locate_fuzz_memory_regions(Object *child, void *opaque) { - const char *name; MemoryRegion *mr; if (object_dynamic_cast(child, TYPE_MEMORY_REGION)) { mr = MEMORY_REGION(child); if ((memory_region_is_ram(mr) || memory_region_is_ram_device(mr) || memory_region_is_rom(mr)) == false) { - name = object_get_canonical_path_component(child); /* * We don't want duplicate pointers to the same MemoryRegion, so * try to remove copies of the pointer, before adding it. @@ -995,16 +995,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 004c701915e1..a825b78c14f6 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/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index 86796bff2bca..b17fc725dfd6 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/pci.h" #include "tests/qtest/libqos/pci-pc.h" #include "fuzz.h" diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index 7a244c951e5e..e403d373a000 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -19,12 +19,11 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "qemu-common.h" #include "exec/memory.h" #include "qemu/main-loop.h" -#include "tests/qtest/libqos/libqtest.h" -#include "tests/qtest/libqos/malloc.h" +#include "tests/qtest/libqtest.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" @@ -51,8 +50,7 @@ static void qos_set_machines_devices_available(void) machines_apply_to_node(mach_info); qapi_free_MachineInfoList(mach_info); - type_info = qmp_qom_list_types(true, "device", true, true, - &error_abort); + type_info = qmp_qom_list_types("device", true, true, &error_abort); types_apply_to_node(type_info); qapi_free_ObjectTypeInfoList(type_info); } diff --git a/tests/qtest/fuzz/virtio_blk_fuzz.c b/tests/qtest/fuzz/virtio_blk_fuzz.c index 623a756fd472..a9fb9ecf6c1a 100644 --- a/tests/qtest/fuzz/virtio_blk_fuzz.c +++ b/tests/qtest/fuzz/virtio_blk_fuzz.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/virtio-blk.h" #include "tests/qtest/libqos/virtio.h" #include "tests/qtest/libqos/virtio-pci.h" @@ -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/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c index 0e873ab8e25f..c2c15f07f062 100644 --- a/tests/qtest/fuzz/virtio_net_fuzz.c +++ b/tests/qtest/fuzz/virtio_net_fuzz.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "standard-headers/linux/virtio_config.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/virtio-net.h" #include "fuzz.h" #include "fork_fuzz.h" @@ -151,7 +151,7 @@ static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg) { int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds); g_assert_cmpint(ret, !=, -1); - fcntl(sockfds[0], F_SETFL, O_NONBLOCK); + g_unix_set_fd_nonblocking(sockfds[0], true, NULL); sockfds_initialized = true; g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", sockfds[1]); diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c index 6ff6fabe4ad3..b3220ef6cb20 100644 --- a/tests/qtest/fuzz/virtio_scsi_fuzz.c +++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" -#include "tests/qtest/libqos/libqtest.h" +#include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/virtio-scsi.h" #include "tests/qtest/libqos/virtio.h" #include "tests/qtest/libqos/virtio-pci.h" diff --git a/tests/qtest/fw_cfg-test.c b/tests/qtest/fw_cfg-test.c index 95b3907c18c4..5dc807ba2385 100644 --- a/tests/qtest/fw_cfg-test.c +++ b/tests/qtest/fw_cfg-test.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "standard-headers/linux/qemu_fw_cfg.h" #include "libqos/fw_cfg.h" #include "qemu/bswap.h" diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c index 64023c057408..4a7628077b23 100644 --- a/tests/qtest/hd-geo-test.c +++ b/tests/qtest/hd-geo-test.c @@ -16,10 +16,9 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/bswap.h" #include "qapi/qmp/qlist.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/fw_cfg.h" #include "libqos/libqos.h" #include "standard-headers/linux/qemu_fw_cfg.h" @@ -28,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; } @@ -423,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; @@ -469,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); @@ -479,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); @@ -507,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; } @@ -694,7 +691,8 @@ static void add_virtio_disk(TestArgs *args, args->n_virtio_disks++; } -static void test_override(TestArgs *args, CHSResult expected[]) +static void test_override(TestArgs *args, const char *arch, + CHSResult expected[]) { QTestState *qts; char *joined_args; @@ -703,7 +701,7 @@ static void test_override(TestArgs *args, CHSResult expected[]) joined_args = g_strjoinv(" ", args->argv); - qts = qtest_initf("-machine pc %s", joined_args); + qts = qtest_initf("-machine %s %s", arch, joined_args); fw_cfg = pc_fw_cfg_init(qts); read_bootdevices(fw_cfg, expected); @@ -715,7 +713,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); @@ -740,7 +738,28 @@ static void test_override_ide(void) add_ide_disk(args, 1, 0, 1, 9000, 120, 30); add_ide_disk(args, 2, 1, 0, 0, 1, 1); add_ide_disk(args, 3, 1, 1, 1, 0, 0); - test_override(args, expected); + test_override(args, "pc", expected); +} + +static void test_override_sata(void) +{ + TestArgs *args = create_args(); + CHSResult expected[] = { + {"/pci@i0cf8/pci8086,2922@1f,2/drive@0/disk@0", {10000, 120, 30} }, + {"/pci@i0cf8/pci8086,2922@1f,2/drive@1/disk@0", {9000, 120, 30} }, + {"/pci@i0cf8/pci8086,2922@1f,2/drive@2/disk@0", {0, 1, 1} }, + {"/pci@i0cf8/pci8086,2922@1f,2/drive@3/disk@0", {1, 0, 0} }, + {NULL, {0, 0, 0} } + }; + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_ide_disk(args, 0, 0, 0, 10000, 120, 30); + add_ide_disk(args, 1, 1, 0, 9000, 120, 30); + add_ide_disk(args, 2, 2, 0, 0, 1, 1); + add_ide_disk(args, 3, 3, 0, 1, 0, 0); + test_override(args, "q35", expected); } static void test_override_scsi(void) @@ -762,7 +781,43 @@ static void test_override_scsi(void) add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30); add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0); add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0); - test_override(args, expected); + test_override(args, "pc", expected); +} + +static void setup_pci_bridge(TestArgs *args, const char *id, const char *rootid) +{ + + char *root, *br; + root = g_strdup_printf("-device pcie-root-port,id=%s", rootid); + br = g_strdup_printf("-device pcie-pci-bridge,bus=%s,id=%s", rootid, id); + + args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, root); + args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, br); +} + +static void test_override_scsi_q35(void) +{ + TestArgs *args = create_args(); + CHSResult expected[] = { + { "/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@0,0", + {10000, 120, 30} + }, + {"/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@1,0", {9000, 120, 30} }, + {"/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@2,0", {1, 0, 0} }, + {"/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@3,0", {0, 1, 0} }, + {NULL, {0, 0, 0} } + }; + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + setup_pci_bridge(args, "pcie.0", "br"); + add_scsi_controller(args, "lsi53c895a", "br", 3); + add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); + add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30); + add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0); + add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0); + test_override(args, "q35", expected); } static void test_override_scsi_2_controllers(void) @@ -785,7 +840,7 @@ static void test_override_scsi_2_controllers(void) add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30); add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0); add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0); - test_override(args, expected); + test_override(args, "pc", expected); } static void test_override_virtio_blk(void) @@ -800,57 +855,66 @@ static void test_override_virtio_blk(void) add_drive_with_mbr(args, empty_mbr, 1); add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30); add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30); - test_override(args, expected); + test_override(args, "pc", expected); } -static void test_override_zero_chs(void) +static void test_override_virtio_blk_q35(void) { TestArgs *args = create_args(); CHSResult expected[] = { + {"/pci@i0cf8/pci-bridge@1/scsi@3/disk@0,0", {10000, 120, 30} }, + {"/pci@i0cf8/pci-bridge@1/scsi@4/disk@0,0", {9000, 120, 30} }, {NULL, {0, 0, 0} } }; add_drive_with_mbr(args, empty_mbr, 1); - add_ide_disk(args, 0, 1, 1, 0, 0, 0); - test_override(args, expected); + add_drive_with_mbr(args, empty_mbr, 1); + setup_pci_bridge(args, "pcie.0", "br"); + add_virtio_disk(args, 0, "br", 3, 10000, 120, 30); + add_virtio_disk(args, 1, "br", 4, 9000, 120, 30); + test_override(args, "q35", expected); } -static void test_override_scsi_hot_unplug(void) +static void test_override_zero_chs(void) { - QTestState *qts; - char *joined_args; - QFWCFG *fw_cfg; - QDict *response; - int i; TestArgs *args = create_args(); CHSResult expected[] = { - {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} }, - {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} }, {NULL, {0, 0, 0} } }; - CHSResult expected2[] = { - {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} }, + add_drive_with_mbr(args, empty_mbr, 1); + add_ide_disk(args, 0, 1, 1, 0, 0, 0); + test_override(args, "pc", expected); +} + +static void test_override_zero_chs_q35(void) +{ + TestArgs *args = create_args(); + CHSResult expected[] = { {NULL, {0, 0, 0} } }; add_drive_with_mbr(args, empty_mbr, 1); - add_drive_with_mbr(args, empty_mbr, 1); - add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2); - add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); - add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20); + add_ide_disk(args, 0, 0, 0, 0, 0, 0); + test_override(args, "q35", expected); +} + +static void test_override_hot_unplug(TestArgs *args, const char *devid, + CHSResult expected[], CHSResult expected2[]) +{ + QTestState *qts; + char *joined_args; + QFWCFG *fw_cfg; + QDict *response; + int i; joined_args = g_strjoinv(" ", args->argv); - qts = qtest_initf("-machine pc %s", joined_args); + qts = qtest_initf("%s", joined_args); fw_cfg = pc_fw_cfg_init(qts); read_bootdevices(fw_cfg, expected); /* unplug device an restart */ - response = qtest_qmp(qts, - "{ 'execute': 'device_del'," - " 'arguments': {'id': 'scsi-disk0' }}"); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - qobject_unref(response); + qtest_qmp_device_del_send(qts, devid); + response = qtest_qmp(qts, "{ 'execute': 'system_reset', 'arguments': { }}"); g_assert(response); @@ -868,20 +932,75 @@ 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); g_free(args); } +static void test_override_scsi_hot_unplug(void) +{ + TestArgs *args = create_args(); + CHSResult expected[] = { + {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} }, + {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} }, + {NULL, {0, 0, 0} } + }; + CHSResult expected2[] = { + {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} }, + {NULL, {0, 0, 0} } + }; + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2); + add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); + add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20); + + args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, + g_strdup("-machine pc")); + + test_override_hot_unplug(args, "scsi-disk0", expected, expected2); +} + +static void test_override_scsi_hot_unplug_q35(void) +{ + TestArgs *args = create_args(); + CHSResult expected[] = { + { + "/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/channel@0/disk@0,0", + {10000, 120, 30} + }, + { + "/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/channel@0/disk@1,0", + {20, 20, 20} + }, + {NULL, {0, 0, 0} } + }; + CHSResult expected2[] = { + { + "/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/channel@0/disk@1,0", + {20, 20, 20} + }, + {NULL, {0, 0, 0} } + }; + + args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, + g_strdup("-device pcie-root-port,id=p0 " + "-device pcie-pci-bridge,bus=p0,id=b1 " + "-machine q35")); + + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_scsi_controller(args, "virtio-scsi-pci", "b1", 2); + add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); + add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20); + + test_override_hot_unplug(args, "scsi-disk0", expected, expected2); +} + static void test_override_virtio_hot_unplug(void) { - QTestState *qts; - char *joined_args; - QFWCFG *fw_cfg; - QDict *response; - int i; TestArgs *args = create_args(); CHSResult expected[] = { {"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} }, @@ -897,42 +1016,45 @@ static void test_override_virtio_hot_unplug(void) add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30); add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20); - joined_args = g_strjoinv(" ", args->argv); - - qts = qtest_initf("-machine pc %s", joined_args); - fw_cfg = pc_fw_cfg_init(qts); + args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, + g_strdup("-machine pc")); - read_bootdevices(fw_cfg, expected); - - /* unplug device an restart */ - response = qtest_qmp(qts, - "{ 'execute': 'device_del'," - " 'arguments': {'id': 'virtio-disk0' }}"); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - qobject_unref(response); - response = qtest_qmp(qts, - "{ 'execute': 'system_reset', 'arguments': { }}"); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - qobject_unref(response); - - qtest_qmp_eventwait(qts, "RESET"); + test_override_hot_unplug(args, "virtio-disk0", expected, expected2); +} - read_bootdevices(fw_cfg, expected2); +static void test_override_virtio_hot_unplug_q35(void) +{ + TestArgs *args = create_args(); + CHSResult expected[] = { + { + "/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/disk@0,0", + {10000, 120, 30} + }, + { + "/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@3/disk@0,0", + {20, 20, 20} + }, + {NULL, {0, 0, 0} } + }; + CHSResult expected2[] = { + { + "/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@3/disk@0,0", + {20, 20, 20} + }, + {NULL, {0, 0, 0} } + }; - g_free(joined_args); - qtest_quit(qts); + args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, + g_strdup("-device pcie-root-port,id=p0 " + "-device pcie-pci-bridge,bus=p0,id=b1 " + "-machine q35")); - g_free(fw_cfg); + add_drive_with_mbr(args, empty_mbr, 1); + add_drive_with_mbr(args, empty_mbr, 1); + add_virtio_disk(args, 0, "b1", 2, 10000, 120, 30); + add_virtio_disk(args, 1, "b1", 3, 20, 20, 20); - for (i = 0; i < args->n_drives; i++) { - unlink(args->drives[i]); - free(args->drives[i]); - } - g_free(args->drives); - g_strfreev(args->argv); - g_free(args); + test_override_hot_unplug(args, "virtio-disk0", expected, expected2); } int main(int argc, char **argv) @@ -977,6 +1099,22 @@ int main(int argc, char **argv) test_override_scsi_hot_unplug); qtest_add_func("hd-geo/override/virtio_hot_unplug", test_override_virtio_hot_unplug); + + if (qtest_has_machine("q35")) { + qtest_add_func("hd-geo/override/sata", test_override_sata); + qtest_add_func("hd-geo/override/virtio_blk_q35", + test_override_virtio_blk_q35); + qtest_add_func("hd-geo/override/zero_chs_q35", + test_override_zero_chs_q35); + if (qtest_has_device("lsi53c895a")) { + qtest_add_func("hd-geo/override/scsi_q35", + test_override_scsi_q35); + } + qtest_add_func("hd-geo/override/scsi_hot_unplug_q35", + test_override_scsi_hot_unplug_q35); + qtest_add_func("hd-geo/override/virtio_hot_unplug_q35", + test_override_virtio_hot_unplug_q35); + } } else { g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; " "skipping hd-geo/override/* tests"); @@ -988,7 +1126,7 @@ int main(int argc, char **argv) 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/hexloader-test.c b/tests/qtest/hexloader-test.c index 561502052a67..3023548041c2 100644 --- a/tests/qtest/hexloader-test.c +++ b/tests/qtest/hexloader-test.c @@ -10,7 +10,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* Load 'test.hex' and verify that the in-memory contents are as expected. * 'test.hex' is a memory test pattern stored in Hexadecimal Object @@ -34,12 +34,8 @@ static void hex_loader_test(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("/tmp/hex_loader", hex_loader_test); - ret = g_test_run(); - - return ret; + return g_test_run(); } diff --git a/tests/qtest/i440fx-test.c b/tests/qtest/i440fx-test.c index 6d7d4d8d8f26..795fd85343db 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; - - 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); - } + g_assert_no_error(error); + close(fd); + + 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 19de3b410405..dcb050bf9b4d 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -25,12 +25,11 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/libqos.h" #include "libqos/pci-pc.h" #include "libqos/malloc-pc.h" #include "qapi/qmp/qdict.h" -#include "qemu-common.h" #include "qemu/bswap.h" #include "hw/pci/pci_ids.h" #include "hw/pci/pci_regs.h" @@ -91,6 +90,7 @@ enum { enum { CMD_DSM = 0x06, + CMD_DIAGNOSE = 0x90, CMD_READ_DMA = 0xc8, CMD_WRITE_DMA = 0xca, CMD_FLUSH_CACHE = 0xe7, @@ -122,9 +122,10 @@ 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; +G_GNUC_PRINTF(1, 2) static QTestState *ide_test_start(const char *cmdline_fmt, ...) { QTestState *qts; @@ -311,7 +312,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; @@ -575,7 +576,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); @@ -615,6 +616,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 @@ -663,7 +694,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); @@ -714,7 +745,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); @@ -758,7 +789,7 @@ static void test_flush_nodev(void) QPCIDevice *dev; QPCIBar bmdma_bar, ide_bar; - qts = ide_test_start(""); + qts = ide_test_start("%s", ""); dev = get_pci_device(qts, &bmdma_bar, &ide_bar); @@ -893,14 +924,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"); @@ -986,7 +1017,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); @@ -994,7 +1025,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); @@ -1012,26 +1043,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); @@ -1049,8 +1101,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 a58c98e4d11b..d4a8db6fd601 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/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c index 19612e9405ae..ed431e34e68d 100644 --- a/tests/qtest/ipmi-bt-test.c +++ b/tests/qtest/ipmi-bt-test.c @@ -31,7 +31,6 @@ #include "libqtest-single.h" -#include "qemu-common.h" #define IPMI_IRQ 5 diff --git a/tests/qtest/ipoctal232-test.c b/tests/qtest/ipoctal232-test.c index 65ce10b81bef..53a8c9b13ce5 100644 --- a/tests/qtest/ipoctal232-test.c +++ b/tests/qtest/ipoctal232-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" diff --git a/tests/qtest/ivshmem-test.c b/tests/qtest/ivshmem-test.c index 4e8af42a9d04..9bf8e78df672 100644 --- a/tests/qtest/ivshmem-test.c +++ b/tests/qtest/ivshmem-test.c @@ -13,8 +13,7 @@ #include "contrib/ivshmem-server/ivshmem-server.h" #include "libqos/libqos-pc.h" #include "libqos/libqos-spapr.h" -#include "libqos/libqtest.h" -#include "qemu-common.h" +#include "libqtest.h" #define TMPSHMSIZE (1 << 20) static char *tmpshm; @@ -110,9 +109,9 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix) const char *arch = qtest_get_arch(); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - s->qs = qtest_pc_boot(cmd); + s->qs = qtest_pc_boot("%s", cmd); } else if (strcmp(arch, "ppc64") == 0) { - s->qs = qtest_spapr_boot(cmd); + s->qs = qtest_spapr_boot("%s", cmd); } else { g_printerr("ivshmem-test tests are only available on x86 or ppc64\n"); exit(EXIT_FAILURE); @@ -305,6 +304,7 @@ static void setup_vm_with_server(IVState *s, int nvectors) static void test_ivshmem_server(void) { + g_autoptr(GError) err = NULL; IVState state1, state2, *s1, *s2; ServerThread thread; IvshmemServer server; @@ -321,8 +321,8 @@ static void test_ivshmem_server(void) g_assert_cmpint(ret, ==, 0); thread.server = &server; - ret = pipe(thread.pipe); - g_assert_cmpint(ret, ==, 0); + g_unix_open_pipe(thread.pipe, FD_CLOEXEC, &err); + g_assert_no_error(err); thread.thread = g_thread_new("ivshmem-server", server_thread, &thread); g_assert(thread.thread != NULL); @@ -378,6 +378,20 @@ static void test_ivshmem_server(void) close(thread.pipe[0]); } +static void test_ivshmem_hotplug_q35(void) +{ + QTestState *qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1 " + "-device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1 " + "-machine q35"); + + qtest_qmp_device_add(qts, "ivshmem-plain", "iv1", + "{'memdev': 'mb1', 'bus': 'b1'}"); + qtest_qmp_device_del_send(qts, "iv1"); + + qtest_quit(qts); +} + #define PCI_SLOT_HP 0x06 static void test_ivshmem_hotplug(void) @@ -469,6 +483,7 @@ int main(int argc, char **argv) { int ret, fd; gchar dir[] = "/tmp/ivshmem-test.XXXXXX"; + const char *arch = qtest_get_arch(); g_test_init(&argc, &argv, NULL); @@ -481,8 +496,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); @@ -494,6 +509,9 @@ int main(int argc, char **argv) qtest_add_func("/ivshmem/pair", test_ivshmem_pair); qtest_add_func("/ivshmem/server", test_ivshmem_server); } + if (!strcmp(arch, "x86_64") && qtest_has_machine("q35")) { + qtest_add_func("/ivshmem/hotplug-q35", test_ivshmem_hotplug_q35); + } out: ret = g_test_run(); diff --git a/tests/qtest/libqmp.c b/tests/qtest/libqmp.c new file mode 100644 index 000000000000..a89cab03c3b6 --- /dev/null +++ b/tests/qtest/libqmp.c @@ -0,0 +1,258 @@ +/* + * QTest + * + * Copyright IBM, Corp. 2012 + * Copyright Red Hat, Inc. 2012 + * Copyright SUSE LINUX Products GmbH 2013 + * + * Authors: + * Anthony Liguori + * Paolo Bonzini + * Andreas Färber + * + * 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 "libqmp.h" + +#ifndef _WIN32 +#include +#endif + +#include "qemu/cutils.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "qapi/qmp/json-parser.h" +#include "qapi/qmp/qjson.h" + +#define SOCKET_MAX_FDS 16 + +typedef struct { + JSONMessageParser parser; + QDict *response; +} QMPResponseParser; + +static void socket_send(int fd, const char *buf, size_t size) +{ + ssize_t res = qemu_send_full(fd, buf, size); + + assert(res == size); +} + +static void qmp_response(void *opaque, QObject *obj, Error *err) +{ + QMPResponseParser *qmp = opaque; + + assert(!obj != !err); + + if (err) { + error_prepend(&err, "QMP JSON response parsing failed: "); + error_report_err(err); + abort(); + } + + g_assert(!qmp->response); + qmp->response = qobject_to(QDict, obj); + g_assert(qmp->response); +} + +QDict *qmp_fd_receive(int fd) +{ + QMPResponseParser qmp; + bool log = getenv("QTEST_LOG") != NULL; + + qmp.response = NULL; + json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL); + while (!qmp.response) { + ssize_t len; + char c; + + len = recv(fd, &c, 1, 0); + if (len == -1 && errno == EINTR) { + continue; + } + + if (len == -1 || len == 0) { + fprintf(stderr, "Broken pipe\n"); + abort(); + } + + if (log) { + g_assert(write(2, &c, 1) == 1); + } + json_message_parser_feed(&qmp.parser, &c, 1); + } + if (log) { + g_assert(write(2, "\n", 1) == 1); + } + json_message_parser_destroy(&qmp.parser); + + return qmp.response; +} + +#ifndef _WIN32 +/* Sends a message and file descriptors to the socket. + * It's needed for qmp-commands like getfd/add-fd */ +static void socket_send_fds(int socket_fd, int *fds, size_t fds_num, + const char *buf, size_t buf_size) +{ + ssize_t ret; + struct msghdr msg = { 0 }; + char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)] = { 0 }; + size_t fdsize = sizeof(int) * fds_num; + struct cmsghdr *cmsg; + struct iovec iov = { .iov_base = (char *)buf, .iov_len = buf_size }; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (fds && fds_num > 0) { + g_assert_cmpuint(fds_num, <, SOCKET_MAX_FDS); + + msg.msg_control = control; + msg.msg_controllen = CMSG_SPACE(fdsize); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(fdsize); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + memcpy(CMSG_DATA(cmsg), fds, fdsize); + } + + do { + ret = sendmsg(socket_fd, &msg, 0); + } while (ret < 0 && errno == EINTR); + g_assert_cmpint(ret, >, 0); +} +#endif + +/** + * Allow users to send a message without waiting for the reply, + * in the case that they choose to discard all replies up until + * a particular EVENT is received. + */ +static G_GNUC_PRINTF(4, 0) void +_qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, + const char *fmt, va_list ap) +{ + QObject *qobj; + +#ifdef _WIN32 + assert(fds_num == 0); +#endif + + /* Going through qobject ensures we escape strings properly */ + qobj = qobject_from_vjsonf_nofail(fmt, ap); + + /* No need to send anything for an empty QObject. */ + if (qobj) { + int log = getenv("QTEST_LOG") != NULL; + GString *str = qobject_to_json(qobj); + + /* + * BUG: QMP doesn't react to input until it sees a newline, an + * object, or an array. Work-around: give it a newline. + */ + g_string_append_c(str, '\n'); + + if (log) { + fprintf(stderr, "%s", str->str); + } + +#ifndef _WIN32 + /* Send QMP request */ + if (fds && fds_num > 0) { + socket_send_fds(fd, fds, fds_num, str->str, str->len); + } else +#endif + { + socket_send(fd, str->str, str->len); + } + + g_string_free(str, true); + qobject_unref(qobj); + } +} + +#ifndef _WIN32 +void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, + const char *fmt, va_list ap) +{ + _qmp_fd_vsend_fds(fd, fds, fds_num, fmt, ap); +} +#endif + +void qmp_fd_vsend(int fd, const char *fmt, va_list ap) +{ + _qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); +} + + +QDict *qmp_fdv(int fd, const char *fmt, va_list ap) +{ + _qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); + + return qmp_fd_receive(fd); +} + +QDict *qmp_fd(int fd, const char *fmt, ...) +{ + va_list ap; + QDict *response; + + va_start(ap, fmt); + response = qmp_fdv(fd, fmt, ap); + va_end(ap); + return response; +} + +void qmp_fd_send(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qmp_fd_vsend(fd, fmt, ap); + va_end(ap); +} + +void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap) +{ + bool log = getenv("QTEST_LOG") != NULL; + char *str = g_strdup_vprintf(fmt, ap); + + if (log) { + fprintf(stderr, "%s", str); + } + socket_send(fd, str, strlen(str)); + g_free(str); +} + +void qmp_fd_send_raw(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qmp_fd_vsend_raw(fd, fmt, ap); + va_end(ap); +} + +bool qmp_rsp_is_err(QDict *rsp) +{ + QDict *error = qdict_get_qdict(rsp, "error"); + qobject_unref(rsp); + return !!error; +} + +void qmp_expect_error_and_unref(QDict *rsp, const char *class) +{ + QDict *error = qdict_get_qdict(rsp, "error"); + + g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, class); + g_assert_nonnull(qdict_get_try_str(error, "desc")); + g_assert(!qdict_haskey(rsp, "return")); + + qobject_unref(rsp); +} diff --git a/tests/qtest/libqmp.h b/tests/qtest/libqmp.h new file mode 100644 index 000000000000..3445b753ff44 --- /dev/null +++ b/tests/qtest/libqmp.h @@ -0,0 +1,53 @@ +/* + * libqmp test unit + * + * Copyright IBM, Corp. 2012 + * Copyright Red Hat, Inc. 2012 + * Copyright SUSE LINUX Products GmbH 2013 + * + * Authors: + * Anthony Liguori + * Paolo Bonzini + * Andreas Färber + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef LIBQMP_H +#define LIBQMP_H + +#include "qapi/qmp/qdict.h" + +QDict *qmp_fd_receive(int fd); +#ifndef _WIN32 +void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, + const char *fmt, va_list ap) G_GNUC_PRINTF(4, 0); +#endif +void qmp_fd_vsend(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); +void qmp_fd_send(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); +void qmp_fd_send_raw(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); +void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); +QDict *qmp_fdv(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); +QDict *qmp_fd(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); + +/** + * qmp_rsp_is_err: + * @rsp: QMP response to check for error + * + * Test @rsp for error and discard @rsp. + * Returns 'true' if there is error in @rsp and 'false' otherwise. + */ +bool qmp_rsp_is_err(QDict *rsp); + +/** + * qmp_expect_error_and_unref: + * @rsp: QMP response to check for error + * @class: an error class + * + * Assert the response has the given error class and discard @rsp. + */ +void qmp_expect_error_and_unref(QDict *rsp, const char *class); + +#endif /* LIBQMP_H */ diff --git a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c index 79631cc7a9ad..ab24add8eb86 100644 --- a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c +++ b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c @@ -17,9 +17,9 @@ */ #include "qemu/osdep.h" -#include "libqtest.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/ahci.c b/tests/qtest/libqos/ahci.c index eaa2096512e5..f53f12aa9965 100644 --- a/tests/qtest/libqos/ahci.c +++ b/tests/qtest/libqos/ahci.c @@ -24,11 +24,10 @@ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "ahci.h" #include "pci-pc.h" -#include "qemu-common.h" #include "qemu/host-utils.h" #include "hw/pci/pci_ids.h" diff --git a/tests/qtest/libqos/arm-imx25-pdk-machine.c b/tests/qtest/libqos/arm-imx25-pdk-machine.c index 6692adfa4fcb..8fe128fae865 100644 --- a/tests/qtest/libqos/arm-imx25-pdk-machine.c +++ b/tests/qtest/libqos/arm-imx25-pdk-machine.c @@ -19,8 +19,8 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" -#include "malloc.h" +#include "../libqtest.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 ff2049c3a7eb..4e5afe0164bf 100644 --- a/tests/qtest/libqos/arm-n800-machine.c +++ b/tests/qtest/libqos/arm-n800-machine.c @@ -19,8 +19,8 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" -#include "malloc.h" +#include "../libqtest.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 09ca863c1030..367c6c17a5f9 100644 --- a/tests/qtest/libqos/arm-raspi2-machine.c +++ b/tests/qtest/libqos/arm-raspi2-machine.c @@ -17,9 +17,9 @@ */ #include "qemu/osdep.h" -#include "libqtest.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 72425f0ad404..94f6a20fc7cc 100644 --- a/tests/qtest/libqos/arm-sabrelite-machine.c +++ b/tests/qtest/libqos/arm-sabrelite-machine.c @@ -17,9 +17,9 @@ */ #include "qemu/osdep.h" -#include "libqtest.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 321b8826d4a2..9bbce924ea18 100644 --- a/tests/qtest/libqos/arm-smdkc210-machine.c +++ b/tests/qtest/libqos/arm-smdkc210-machine.c @@ -17,9 +17,9 @@ */ #include "qemu/osdep.h" -#include "libqtest.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 e0f59322845a..4e87405b58f2 100644 --- a/tests/qtest/libqos/arm-virt-machine.c +++ b/tests/qtest/libqos/arm-virt-machine.c @@ -17,11 +17,13 @@ */ #include "qemu/osdep.h" -#include "libqtest.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" +#include "hw/pci/pci_regs.h" #define ARM_PAGE_SIZE 4096 #define VIRTIO_MMIO_BASE_ADDR 0x0A003E00 @@ -35,6 +37,7 @@ struct QVirtMachine { QOSGraphObject obj; QGuestAllocator alloc; QVirtioMMIODevice virtio_mmio; + QGenericPCIHost bridge; }; static void virt_destructor(QOSGraphObject *obj) @@ -57,11 +60,13 @@ static void *virt_get_driver(void *object, const char *interface) static QOSGraphObject *virt_get_device(void *obj, const char *device) { QVirtMachine *machine = obj; - if (!g_strcmp0(device, "virtio-mmio")) { + if (!g_strcmp0(device, "generic-pcihost")) { + return &machine->bridge.obj; + } else if (!g_strcmp0(device, "virtio-mmio")) { return &machine->virtio_mmio.obj; } - fprintf(stderr, "%s not present in arm/virtio\n", device); + fprintf(stderr, "%s not present in arm/virt\n", device); g_assert_not_reached(); } @@ -76,16 +81,22 @@ static void *qos_create_machine_arm_virt(QTestState *qts) qvirtio_mmio_init_device(&machine->virtio_mmio, qts, VIRTIO_MMIO_BASE_ADDR, VIRTIO_MMIO_SIZE); + qos_create_generic_pcihost(&machine->bridge, qts, &machine->alloc); + machine->obj.get_device = virt_get_device; machine->obj.get_driver = virt_get_driver; machine->obj.destructor = virt_destructor; return machine; } -static void virtio_mmio_register_nodes(void) +static void virt_machine_register_nodes(void) { qos_node_create_machine("arm/virt", qos_create_machine_arm_virt); qos_node_contains("arm/virt", "virtio-mmio", NULL); + + qos_node_create_machine_args("aarch64/virt", qos_create_machine_arm_virt, + " -cpu max"); + qos_node_contains("aarch64/virt", "generic-pcihost", NULL); } -libqos_init(virtio_mmio_register_nodes); +libqos_init(virt_machine_register_nodes); diff --git a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c index 56e53c745bff..daac762a062a 100644 --- a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c +++ b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c @@ -17,9 +17,9 @@ */ #include "qemu/osdep.h" -#include "libqtest.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 a451f6168f63..37c794b1301a 100644 --- a/tests/qtest/libqos/e1000e.c +++ b/tests/qtest/libqos/e1000e.c @@ -17,59 +17,24 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "hw/net/e1000_regs.h" +#include "hw/pci/pci_ids.h" +#include "../libqtest.h" #include "pci-pc.h" #include "qemu/sockets.h" #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" -#define E1000E_IMS (0x00d0) +#define E1000E_IVAR_TEST_CFG \ + (((E1000E_RX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_RXQ0_SHIFT) | \ + ((E1000E_TX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_TXQ0_SHIFT) | \ + E1000_IVAR_TX_INT_EVERY_WB) -#define E1000E_STATUS (0x0008) -#define E1000E_STATUS_LU BIT(1) -#define E1000E_STATUS_ASDV1000 BIT(9) - -#define E1000E_CTRL (0x0000) -#define E1000E_CTRL_RESET BIT(26) - -#define E1000E_RCTL (0x0100) -#define E1000E_RCTL_EN BIT(1) -#define E1000E_RCTL_UPE BIT(3) -#define E1000E_RCTL_MPE BIT(4) - -#define E1000E_RFCTL (0x5008) -#define E1000E_RFCTL_EXTEN BIT(15) - -#define E1000E_TCTL (0x0400) -#define E1000E_TCTL_EN BIT(1) - -#define E1000E_CTRL_EXT (0x0018) -#define E1000E_CTRL_EXT_DRV_LOAD BIT(28) -#define E1000E_CTRL_EXT_TXLSFLOW BIT(22) - -#define E1000E_IVAR (0x00E4) -#define E1000E_IVAR_TEST_CFG ((E1000E_RX0_MSG_ID << 0) | BIT(3) | \ - (E1000E_TX0_MSG_ID << 8) | BIT(11) | \ - (E1000E_OTHER_MSG_ID << 16) | BIT(19) | \ - BIT(31)) - -#define E1000E_RING_LEN (0x1000) - -#define E1000E_TDBAL (0x3800) - -#define E1000E_TDBAH (0x3804) -#define E1000E_TDH (0x3810) - -#define E1000E_RDBAL (0x2800) -#define E1000E_RDBAH (0x2804) -#define E1000E_RDH (0x2810) - -#define E1000E_TXD_LEN (16) -#define E1000E_RXD_LEN (16) +#define E1000E_RING_LEN (0x1000) static void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val) { @@ -87,30 +52,34 @@ void e1000e_tx_ring_push(QE1000E *d, void *descr) { QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); uint32_t tail = e1000e_macreg_read(d, E1000E_TDT); - uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000E_TXD_LEN; + uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000_RING_DESC_LEN; - qtest_memwrite(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN, - descr, E1000E_TXD_LEN); + qtest_memwrite(d_pci->pci_dev.bus->qts, + d->tx_ring + tail * E1000_RING_DESC_LEN, + descr, E1000_RING_DESC_LEN); e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len); /* Read WB data for the packet transmitted */ - qtest_memread(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN, - descr, E1000E_TXD_LEN); + qtest_memread(d_pci->pci_dev.bus->qts, + d->tx_ring + tail * E1000_RING_DESC_LEN, + descr, E1000_RING_DESC_LEN); } void e1000e_rx_ring_push(QE1000E *d, void *descr) { QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); uint32_t tail = e1000e_macreg_read(d, E1000E_RDT); - uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000E_RXD_LEN; + uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000_RING_DESC_LEN; - qtest_memwrite(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN, - descr, E1000E_RXD_LEN); + qtest_memwrite(d_pci->pci_dev.bus->qts, + d->rx_ring + tail * E1000_RING_DESC_LEN, + descr, E1000_RING_DESC_LEN); e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len); /* Read WB data for the packet received */ - qtest_memread(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN, - descr, E1000E_RXD_LEN); + qtest_memread(d_pci->pci_dev.bus->qts, + d->rx_ring + tail * E1000_RING_DESC_LEN, + descr, E1000_RING_DESC_LEN); } static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data) @@ -151,53 +120,54 @@ static void e1000e_pci_start_hw(QOSGraphObject *obj) qpci_device_enable(&d->pci_dev); /* Reset the device */ - val = e1000e_macreg_read(&d->e1000e, E1000E_CTRL); - e1000e_macreg_write(&d->e1000e, E1000E_CTRL, val | E1000E_CTRL_RESET); + val = e1000e_macreg_read(&d->e1000e, E1000_CTRL); + e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST | E1000_CTRL_SLU); /* Enable and configure MSI-X */ qpci_msix_enable(&d->pci_dev); - e1000e_macreg_write(&d->e1000e, E1000E_IVAR, E1000E_IVAR_TEST_CFG); + e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG); /* Check the device status - link and speed */ - val = e1000e_macreg_read(&d->e1000e, E1000E_STATUS); - g_assert_cmphex(val & (E1000E_STATUS_LU | E1000E_STATUS_ASDV1000), - ==, E1000E_STATUS_LU | E1000E_STATUS_ASDV1000); + val = e1000e_macreg_read(&d->e1000e, E1000_STATUS); + g_assert_cmphex(val & (E1000_STATUS_LU | E1000_STATUS_ASDV_1000), + ==, E1000_STATUS_LU | E1000_STATUS_ASDV_1000); /* Initialize TX/RX logic */ - e1000e_macreg_write(&d->e1000e, E1000E_RCTL, 0); - e1000e_macreg_write(&d->e1000e, E1000E_TCTL, 0); + e1000e_macreg_write(&d->e1000e, E1000_RCTL, 0); + e1000e_macreg_write(&d->e1000e, E1000_TCTL, 0); /* Notify the device that the driver is ready */ - val = e1000e_macreg_read(&d->e1000e, E1000E_CTRL_EXT); - e1000e_macreg_write(&d->e1000e, E1000E_CTRL_EXT, - val | E1000E_CTRL_EXT_DRV_LOAD | E1000E_CTRL_EXT_TXLSFLOW); + val = e1000e_macreg_read(&d->e1000e, E1000_CTRL_EXT); + e1000e_macreg_write(&d->e1000e, E1000_CTRL_EXT, + val | E1000_CTRL_EXT_DRV_LOAD); - e1000e_macreg_write(&d->e1000e, E1000E_TDBAL, + e1000e_macreg_write(&d->e1000e, E1000_TDBAL, (uint32_t) d->e1000e.tx_ring); - e1000e_macreg_write(&d->e1000e, E1000E_TDBAH, + e1000e_macreg_write(&d->e1000e, E1000_TDBAH, (uint32_t) (d->e1000e.tx_ring >> 32)); e1000e_macreg_write(&d->e1000e, E1000E_TDLEN, E1000E_RING_LEN); e1000e_macreg_write(&d->e1000e, E1000E_TDT, 0); - e1000e_macreg_write(&d->e1000e, E1000E_TDH, 0); + e1000e_macreg_write(&d->e1000e, E1000_TDH, 0); /* Enable transmit */ - e1000e_macreg_write(&d->e1000e, E1000E_TCTL, E1000E_TCTL_EN); - e1000e_macreg_write(&d->e1000e, E1000E_RDBAL, + e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN); + + e1000e_macreg_write(&d->e1000e, E1000_RDBAL, (uint32_t)d->e1000e.rx_ring); - e1000e_macreg_write(&d->e1000e, E1000E_RDBAH, + e1000e_macreg_write(&d->e1000e, E1000_RDBAH, (uint32_t)(d->e1000e.rx_ring >> 32)); e1000e_macreg_write(&d->e1000e, E1000E_RDLEN, E1000E_RING_LEN); e1000e_macreg_write(&d->e1000e, E1000E_RDT, 0); - e1000e_macreg_write(&d->e1000e, E1000E_RDH, 0); + e1000e_macreg_write(&d->e1000e, E1000_RDH, 0); /* Enable receive */ - e1000e_macreg_write(&d->e1000e, E1000E_RFCTL, E1000E_RFCTL_EXTEN); - e1000e_macreg_write(&d->e1000e, E1000E_RCTL, E1000E_RCTL_EN | - E1000E_RCTL_UPE | - E1000E_RCTL_MPE); + e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN); + e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN | + E1000_RCTL_UPE | + E1000_RCTL_MPE); /* Enable all interrupts */ - e1000e_macreg_write(&d->e1000e, E1000E_IMS, 0xFFFFFFFF); + e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF); } @@ -248,8 +218,8 @@ static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc, static void e1000e_register_nodes(void) { QPCIAddress addr = { - .vendor_id = 0x8086, - .device_id = 0x10D3, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = E1000_DEV_ID_82574L, }; /* FIXME: every test using this node needs to setup a -netdev socket,id=hs0 diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h index a22f5fdbad0d..3bf285af42d2 100644 --- a/tests/qtest/libqos/e1000e.h +++ b/tests/qtest/libqos/e1000e.h @@ -24,7 +24,6 @@ #define E1000E_RX0_MSG_ID (0) #define E1000E_TX0_MSG_ID (1) -#define E1000E_OTHER_MSG_ID (2) #define E1000E_TDLEN (0x3808) #define E1000E_TDT (0x3818) diff --git a/tests/qtest/libqos/fw_cfg.c b/tests/qtest/libqos/fw_cfg.c index 6b8e1babe51e..89f053ccacbd 100644 --- a/tests/qtest/libqos/fw_cfg.c +++ b/tests/qtest/libqos/fw_cfg.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "fw_cfg.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/bswap.h" #include "hw/nvram/fw_cfg.h" diff --git a/tests/qtest/libqos/fw_cfg.h b/tests/qtest/libqos/fw_cfg.h index c6a7cf8cf053..b0456a15df19 100644 --- a/tests/qtest/libqos/fw_cfg.h +++ b/tests/qtest/libqos/fw_cfg.h @@ -13,7 +13,7 @@ #ifndef LIBQOS_FW_CFG_H #define LIBQOS_FW_CFG_H -#include "libqtest.h" +#include "../libqtest.h" typedef struct QFWCFG QFWCFG; diff --git a/tests/qtest/libqos/generic-pcihost.c b/tests/qtest/libqos/generic-pcihost.c new file mode 100644 index 000000000000..3124b0e46b25 --- /dev/null +++ b/tests/qtest/libqos/generic-pcihost.c @@ -0,0 +1,231 @@ +/* + * libqos PCI bindings for generic PCI + * + * Copyright Red Hat Inc., 2022 + * + * Authors: + * Eric Auger + * + * 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 "generic-pcihost.h" +#include "qapi/qmp/qdict.h" +#include "hw/pci/pci_regs.h" +#include "qemu/host-utils.h" + +#include "qemu/module.h" + +/* QGenericPCIHost */ + +QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device) +{ + QGenericPCIHost *host = obj; + if (!g_strcmp0(device, "pci-bus-generic")) { + return &host->pci.obj; + } + fprintf(stderr, "%s not present in generic-pcihost\n", device); + g_assert_not_reached(); +} + +void qos_create_generic_pcihost(QGenericPCIHost *host, + QTestState *qts, + QGuestAllocator *alloc) +{ + host->obj.get_device = generic_pcihost_get_device; + qpci_init_generic(&host->pci, qts, alloc, false); +} + +static uint8_t qpci_generic_pio_readb(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readb(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writeb(bus->qts, s->gpex_pio_base + addr, val); +} + +static uint16_t qpci_generic_pio_readw(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readw(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writew(bus->qts, s->gpex_pio_base + addr, val); +} + +static uint32_t qpci_generic_pio_readl(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readl(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writel(bus->qts, s->gpex_pio_base + addr, val); +} + +static uint64_t qpci_generic_pio_readq(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readq(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writeq(bus->qts, s->gpex_pio_base + addr, val); +} + +static void qpci_generic_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) +{ + qtest_memread(bus->qts, addr, buf, len); +} + +static void qpci_generic_memwrite(QPCIBus *bus, uint32_t addr, + const void *buf, size_t len) +{ + qtest_memwrite(bus->qts, addr, buf, len); +} + +static uint8_t qpci_generic_config_readb(QPCIBus *bus, int devfn, uint8_t offset) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint8_t val; + + qtest_memread(bus->qts, addr, &val, 1); + return val; +} + +static uint16_t qpci_generic_config_readw(QPCIBus *bus, int devfn, uint8_t offset) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint16_t val; + + qtest_memread(bus->qts, addr, &val, 2); + return le16_to_cpu(val); +} + +static uint32_t qpci_generic_config_readl(QPCIBus *bus, int devfn, uint8_t offset) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint32_t val; + + qtest_memread(bus->qts, addr, &val, 4); + return le32_to_cpu(val); +} + +static void +qpci_generic_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + + qtest_memwrite(bus->qts, addr, &value, 1); +} + +static void +qpci_generic_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint16_t val = cpu_to_le16(value); + + qtest_memwrite(bus->qts, addr, &val, 2); +} + +static void +qpci_generic_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint32_t val = cpu_to_le32(value); + + qtest_memwrite(bus->qts, addr, &val, 4); +} + +static void *qpci_generic_get_driver(void *obj, const char *interface) +{ + QGenericPCIBus *qpci = obj; + if (!g_strcmp0(interface, "pci-bus")) { + return &qpci->bus; + } + fprintf(stderr, "%s not present in pci-bus-generic\n", interface); + g_assert_not_reached(); +} + +void qpci_init_generic(QGenericPCIBus *qpci, QTestState *qts, + QGuestAllocator *alloc, bool hotpluggable) +{ + assert(qts); + + qpci->gpex_pio_base = 0x3eff0000; + qpci->bus.not_hotpluggable = !hotpluggable; + qpci->bus.has_buggy_msi = false; + + qpci->bus.pio_readb = qpci_generic_pio_readb; + qpci->bus.pio_readw = qpci_generic_pio_readw; + qpci->bus.pio_readl = qpci_generic_pio_readl; + qpci->bus.pio_readq = qpci_generic_pio_readq; + + qpci->bus.pio_writeb = qpci_generic_pio_writeb; + qpci->bus.pio_writew = qpci_generic_pio_writew; + qpci->bus.pio_writel = qpci_generic_pio_writel; + qpci->bus.pio_writeq = qpci_generic_pio_writeq; + + qpci->bus.memread = qpci_generic_memread; + qpci->bus.memwrite = qpci_generic_memwrite; + + qpci->bus.config_readb = qpci_generic_config_readb; + qpci->bus.config_readw = qpci_generic_config_readw; + qpci->bus.config_readl = qpci_generic_config_readl; + + qpci->bus.config_writeb = qpci_generic_config_writeb; + qpci->bus.config_writew = qpci_generic_config_writew; + qpci->bus.config_writel = qpci_generic_config_writel; + + qpci->bus.qts = qts; + qpci->bus.pio_alloc_ptr = 0x0000; + qpci->bus.pio_limit = 0x10000; + qpci->bus.mmio_alloc_ptr = 0x10000000; + qpci->bus.mmio_limit = 0x2eff0000; + qpci->ecam_alloc_ptr = 0x4010000000; + + qpci->obj.get_driver = qpci_generic_get_driver; +} + +static void qpci_generic_register_nodes(void) +{ + qos_node_create_driver("pci-bus-generic", NULL); + qos_node_produces("pci-bus-generic", "pci-bus"); +} + +static void qpci_generic_pci_register_nodes(void) +{ + qos_node_create_driver("generic-pcihost", NULL); + qos_node_contains("generic-pcihost", "pci-bus-generic", NULL); +} + +libqos_init(qpci_generic_register_nodes); +libqos_init(qpci_generic_pci_register_nodes); diff --git a/tests/qtest/libqos/generic-pcihost.h b/tests/qtest/libqos/generic-pcihost.h new file mode 100644 index 000000000000..6493a8712a67 --- /dev/null +++ b/tests/qtest/libqos/generic-pcihost.h @@ -0,0 +1,54 @@ +/* + * libqos Generic PCI bindings and generic pci host bridge + * + * Copyright Red Hat Inc., 2022 + * + * Authors: + * Eric Auger + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_GENERIC_PCIHOST_H +#define LIBQOS_GENERIC_PCIHOST_H + +#include "pci.h" +#include "libqos-malloc.h" +#include "qgraph.h" + +typedef struct QGenericPCIBus { + QOSGraphObject obj; + QPCIBus bus; + uint64_t gpex_pio_base; + uint64_t ecam_alloc_ptr; +} QGenericPCIBus; + +/* + * qpci_init_generic(): + * @ret: A valid QGenericPCIBus * pointer + * @qts: The %QTestState + * @alloc: A previously initialized @alloc providing memory for @qts + * @bool: devices can be hotplugged on this bus + * + * This function initializes an already allocated + * QGenericPCIBus object. + */ +void qpci_init_generic(QGenericPCIBus *ret, QTestState *qts, + QGuestAllocator *alloc, bool hotpluggable); + +/* QGenericPCIHost */ + +typedef struct QGenericPCIHost QGenericPCIHost; + +struct QGenericPCIHost { + QOSGraphObject obj; + QGenericPCIBus pci; +}; + +QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device); +void qos_create_generic_pcihost(QGenericPCIHost *host, + QTestState *qts, + QGuestAllocator *alloc); + +#endif diff --git a/tests/qtest/libqos/i2c-imx.c b/tests/qtest/libqos/i2c-imx.c index 8f9a7e383146..710cb926d62b 100644 --- a/tests/qtest/libqos/i2c-imx.c +++ b/tests/qtest/libqos/i2c-imx.c @@ -21,7 +21,7 @@ #include "i2c.h" -#include "libqtest.h" +#include "../libqtest.h" #include "hw/i2c/imx_i2c.h" diff --git a/tests/qtest/libqos/i2c-omap.c b/tests/qtest/libqos/i2c-omap.c index eb4e453485db..6f98f54820be 100644 --- a/tests/qtest/libqos/i2c-omap.c +++ b/tests/qtest/libqos/i2c-omap.c @@ -11,7 +11,7 @@ #include "qemu/bswap.h" -#include "libqtest.h" +#include "../libqtest.h" enum OMAPI2CRegisters { OMAP_I2C_REV = 0x00, diff --git a/tests/qtest/libqos/i2c.c b/tests/qtest/libqos/i2c.c index ade1bdb40e05..1a54c004eb41 100644 --- a/tests/qtest/libqos/i2c.c +++ b/tests/qtest/libqos/i2c.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" #include "i2c.h" -#include "libqtest.h" +#include "../libqtest.h" void qi2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len) { diff --git a/tests/qtest/libqos/i2c.h b/tests/qtest/libqos/i2c.h index 1341bac1c599..d0322409227c 100644 --- a/tests/qtest/libqos/i2c.h +++ b/tests/qtest/libqos/i2c.h @@ -9,7 +9,7 @@ #ifndef LIBQOS_I2C_H #define LIBQOS_I2C_H -#include "libqtest.h" +#include "../libqtest.h" #include "qgraph.h" typedef struct I2CAdapter I2CAdapter; diff --git a/tests/qtest/libqos/libqos-malloc.c b/tests/qtest/libqos/libqos-malloc.c new file mode 100644 index 000000000000..d7566972c409 --- /dev/null +++ b/tests/qtest/libqos/libqos-malloc.c @@ -0,0 +1,346 @@ +/* + * libqos malloc support + * + * Copyright (c) 2014 + * + * Author: + * John Snow + * + * 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 "libqos-malloc.h" +#include "qemu/host-utils.h" + +typedef struct MemBlock { + QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME; + uint64_t size; + uint64_t addr; +} MemBlock; + +#define DEFAULT_PAGE_SIZE 4096 + +static void mlist_delete(MemList *list, MemBlock *node) +{ + g_assert(list && node); + QTAILQ_REMOVE(list, node, MLIST_ENTNAME); + g_free(node); +} + +static MemBlock *mlist_find_key(MemList *head, uint64_t addr) +{ + MemBlock *node; + QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { + if (node->addr == addr) { + return node; + } + } + return NULL; +} + +static MemBlock *mlist_find_space(MemList *head, uint64_t size) +{ + MemBlock *node; + + QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { + if (node->size >= size) { + return node; + } + } + return NULL; +} + +static MemBlock *mlist_sort_insert(MemList *head, MemBlock *insr) +{ + MemBlock *node; + g_assert(head && insr); + + QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { + if (insr->addr < node->addr) { + QTAILQ_INSERT_BEFORE(node, insr, MLIST_ENTNAME); + return insr; + } + } + + QTAILQ_INSERT_TAIL(head, insr, MLIST_ENTNAME); + return insr; +} + +static inline uint64_t mlist_boundary(MemBlock *node) +{ + return node->size + node->addr; +} + +static MemBlock *mlist_join(MemList *head, MemBlock *left, MemBlock *right) +{ + g_assert(head && left && right); + + left->size += right->size; + mlist_delete(head, right); + return left; +} + +static void mlist_coalesce(MemList *head, MemBlock *node) +{ + g_assert(node); + MemBlock *left; + MemBlock *right; + char merge; + + do { + merge = 0; + left = QTAILQ_PREV(node, MLIST_ENTNAME); + right = QTAILQ_NEXT(node, MLIST_ENTNAME); + + /* clowns to the left of me */ + if (left && mlist_boundary(left) == node->addr) { + node = mlist_join(head, left, node); + merge = 1; + } + + /* jokers to the right */ + if (right && mlist_boundary(node) == right->addr) { + node = mlist_join(head, node, right); + merge = 1; + } + + } while (merge); +} + +static MemBlock *mlist_new(uint64_t addr, uint64_t size) +{ + MemBlock *block; + + if (!size) { + return NULL; + } + block = g_new0(MemBlock, 1); + + block->addr = addr; + block->size = size; + + return block; +} + +static uint64_t mlist_fulfill(QGuestAllocator *s, MemBlock *freenode, + uint64_t size) +{ + uint64_t addr; + MemBlock *usednode; + + g_assert(freenode); + g_assert_cmpint(freenode->size, >=, size); + + addr = freenode->addr; + if (freenode->size == size) { + /* re-use this freenode as our used node */ + QTAILQ_REMOVE(s->free, freenode, MLIST_ENTNAME); + usednode = freenode; + } else { + /* adjust the free node and create a new used node */ + freenode->addr += size; + freenode->size -= size; + usednode = mlist_new(addr, size); + } + + mlist_sort_insert(s->used, usednode); + return addr; +} + +/* To assert the correctness of the list. + * Used only if ALLOC_PARANOID is set. */ +static void mlist_check(QGuestAllocator *s) +{ + MemBlock *node; + uint64_t addr = s->start > 0 ? s->start - 1 : 0; + uint64_t next = s->start; + + QTAILQ_FOREACH(node, s->free, MLIST_ENTNAME) { + g_assert_cmpint(node->addr, >, addr); + g_assert_cmpint(node->addr, >=, next); + addr = node->addr; + next = node->addr + node->size; + } + + addr = s->start > 0 ? s->start - 1 : 0; + next = s->start; + QTAILQ_FOREACH(node, s->used, MLIST_ENTNAME) { + g_assert_cmpint(node->addr, >, addr); + g_assert_cmpint(node->addr, >=, next); + addr = node->addr; + next = node->addr + node->size; + } +} + +static uint64_t mlist_alloc(QGuestAllocator *s, uint64_t size) +{ + MemBlock *node; + + node = mlist_find_space(s->free, size); + if (!node) { + fprintf(stderr, "Out of guest memory.\n"); + g_assert_not_reached(); + } + return mlist_fulfill(s, node, size); +} + +static void mlist_free(QGuestAllocator *s, uint64_t addr) +{ + MemBlock *node; + + if (addr == 0) { + return; + } + + node = mlist_find_key(s->used, addr); + if (!node) { + fprintf(stderr, "Error: no record found for an allocation at " + "0x%016" PRIx64 ".\n", + addr); + g_assert_not_reached(); + } + + /* Rip it out of the used list and re-insert back into the free list. */ + QTAILQ_REMOVE(s->used, node, MLIST_ENTNAME); + mlist_sort_insert(s->free, node); + mlist_coalesce(s->free, node); +} + +/* + * Mostly for valgrind happiness, but it does offer + * a chokepoint for debugging guest memory leaks, too. + */ +void alloc_destroy(QGuestAllocator *allocator) +{ + MemBlock *node; + MemBlock *tmp; + QAllocOpts mask; + + /* Check for guest leaks, and destroy the list. */ + QTAILQ_FOREACH_SAFE(node, allocator->used, MLIST_ENTNAME, tmp) { + if (allocator->opts & (ALLOC_LEAK_WARN | ALLOC_LEAK_ASSERT)) { + fprintf(stderr, "guest malloc leak @ 0x%016" PRIx64 "; " + "size 0x%016" PRIx64 ".\n", + node->addr, node->size); + } + if (allocator->opts & (ALLOC_LEAK_ASSERT)) { + g_assert_not_reached(); + } + g_free(node); + } + + /* If we have previously asserted that there are no leaks, then there + * should be only one node here with a specific address and size. */ + mask = ALLOC_LEAK_ASSERT | ALLOC_PARANOID; + QTAILQ_FOREACH_SAFE(node, allocator->free, MLIST_ENTNAME, tmp) { + if ((allocator->opts & mask) == mask) { + if ((node->addr != allocator->start) || + (node->size != allocator->end - allocator->start)) { + fprintf(stderr, "Free list is corrupted.\n"); + g_assert_not_reached(); + } + } + + g_free(node); + } + + g_free(allocator->used); + g_free(allocator->free); +} + +uint64_t guest_alloc(QGuestAllocator *allocator, size_t size) +{ + uint64_t rsize = size; + uint64_t naddr; + + if (!size) { + return 0; + } + + rsize += (allocator->page_size - 1); + rsize &= -allocator->page_size; + g_assert_cmpint((allocator->start + rsize), <=, allocator->end); + g_assert_cmpint(rsize, >=, size); + + naddr = mlist_alloc(allocator, rsize); + if (allocator->opts & ALLOC_PARANOID) { + mlist_check(allocator); + } + + return naddr; +} + +void guest_free(QGuestAllocator *allocator, uint64_t addr) +{ + if (!addr) { + return; + } + mlist_free(allocator, addr); + if (allocator->opts & ALLOC_PARANOID) { + mlist_check(allocator); + } +} + +void alloc_init(QGuestAllocator *s, QAllocOpts opts, + uint64_t start, uint64_t end, + size_t page_size) +{ + MemBlock *node; + + s->opts = opts; + s->start = start; + s->end = end; + + s->used = g_new(MemList, 1); + s->free = g_new(MemList, 1); + QTAILQ_INIT(s->used); + QTAILQ_INIT(s->free); + + node = mlist_new(s->start, s->end - s->start); + QTAILQ_INSERT_HEAD(s->free, node, MLIST_ENTNAME); + + s->page_size = page_size; +} + +void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts) +{ + allocator->opts |= opts; +} + +void migrate_allocator(QGuestAllocator *src, + QGuestAllocator *dst) +{ + MemBlock *node, *tmp; + MemList *tmpused, *tmpfree; + + /* The general memory layout should be equivalent, + * though opts can differ. */ + g_assert_cmphex(src->start, ==, dst->start); + g_assert_cmphex(src->end, ==, dst->end); + + /* Destroy (silently, regardless of options) the dest-list: */ + QTAILQ_FOREACH_SAFE(node, dst->used, MLIST_ENTNAME, tmp) { + g_free(node); + } + QTAILQ_FOREACH_SAFE(node, dst->free, MLIST_ENTNAME, tmp) { + g_free(node); + } + + tmpused = dst->used; + tmpfree = dst->free; + + /* Inherit the lists of the source allocator: */ + dst->used = src->used; + dst->free = src->free; + + /* Source is now re-initialized, the source memory is 'invalid' now: */ + src->used = tmpused; + src->free = tmpfree; + QTAILQ_INIT(src->used); + QTAILQ_INIT(src->free); + node = mlist_new(src->start, src->end - src->start); + QTAILQ_INSERT_HEAD(src->free, node, MLIST_ENTNAME); + return; +} diff --git a/tests/qtest/libqos/libqos-malloc.h b/tests/qtest/libqos/libqos-malloc.h new file mode 100644 index 000000000000..bbb8c743cc5a --- /dev/null +++ b/tests/qtest/libqos/libqos-malloc.h @@ -0,0 +1,50 @@ +/* + * libqos malloc support + * + * Copyright IBM, Corp. 2012-2013 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_MALLOC_H +#define LIBQOS_MALLOC_H + +#include "qemu/queue.h" +#include "../libqtest.h" + +typedef enum { + ALLOC_NO_FLAGS = 0x00, + ALLOC_LEAK_WARN = 0x01, + ALLOC_LEAK_ASSERT = 0x02, + ALLOC_PARANOID = 0x04 +} QAllocOpts; + +typedef QTAILQ_HEAD(MemList, MemBlock) MemList; + +typedef struct QGuestAllocator { + QAllocOpts opts; + uint64_t start; + uint64_t end; + uint32_t page_size; + + MemList *used; + MemList *free; +} QGuestAllocator; + +/* Always returns page aligned values */ +uint64_t guest_alloc(QGuestAllocator *allocator, size_t size); +void guest_free(QGuestAllocator *allocator, uint64_t addr); +void migrate_allocator(QGuestAllocator *src, QGuestAllocator *dst); + +void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts); + +void alloc_init(QGuestAllocator *alloc, QAllocOpts flags, + uint64_t start, uint64_t end, + size_t page_size); +void alloc_destroy(QGuestAllocator *allocator); + +#endif diff --git a/tests/qtest/libqos/libqos-pc.h b/tests/qtest/libqos/libqos-pc.h index 1a9923ead42f..a2e4209a4932 100644 --- a/tests/qtest/libqos/libqos-pc.h +++ b/tests/qtest/libqos/libqos-pc.h @@ -3,8 +3,10 @@ #include "libqos.h" -QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap); -QOSState *qtest_pc_boot(const char *cmdline_fmt, ...); +QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) + G_GNUC_PRINTF(1, 0); +QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) + G_GNUC_PRINTF(1, 2); void qtest_pc_shutdown(QOSState *qs); #endif diff --git a/tests/qtest/libqos/libqos-spapr.h b/tests/qtest/libqos/libqos-spapr.h index c61338917acd..e4483c14f801 100644 --- a/tests/qtest/libqos/libqos-spapr.h +++ b/tests/qtest/libqos/libqos-spapr.h @@ -3,8 +3,10 @@ #include "libqos.h" -QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap); -QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...); +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) + G_GNUC_PRINTF(1, 0); +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) + G_GNUC_PRINTF(1, 2); void qtest_spapr_shutdown(QOSState *qs); /* List of capabilities needed to silence warnings with TCG */ diff --git a/tests/qtest/libqos/libqos.c b/tests/qtest/libqos/libqos.c index 2251e864efe1..5ffda080ecdd 100644 --- a/tests/qtest/libqos/libqos.c +++ b/tests/qtest/libqos/libqos.c @@ -1,7 +1,5 @@ #include "qemu/osdep.h" -#include - -#include "libqtest.h" +#include "../libqtest.h" #include "libqos.h" #include "pci.h" #include "qapi/qmp/qdict.h" diff --git a/tests/qtest/libqos/libqos.h b/tests/qtest/libqos/libqos.h index e0b2bfe7caf9..12d05b236595 100644 --- a/tests/qtest/libqos/libqos.h +++ b/tests/qtest/libqos/libqos.h @@ -1,9 +1,9 @@ #ifndef LIBQOS_H #define LIBQOS_H -#include "libqtest.h" +#include "../libqtest.h" #include "pci.h" -#include "malloc.h" +#include "libqos-malloc.h" typedef struct QOSState QOSState; @@ -21,8 +21,10 @@ struct QOSState { QOSOps *ops; }; -QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); -QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); +QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) + G_GNUC_PRINTF(2, 0); +QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) + G_GNUC_PRINTF(2, 3); void qtest_common_shutdown(QOSState *qs); void qtest_shutdown(QOSState *qs); bool have_qemu_img(void); diff --git a/tests/qtest/libqos/malloc-pc.c b/tests/qtest/libqos/malloc-pc.c index f1e3b392a53c..bbd1b4827e54 100644 --- a/tests/qtest/libqos/malloc-pc.c +++ b/tests/qtest/libqos/malloc-pc.c @@ -16,8 +16,6 @@ #include "standard-headers/linux/qemu_fw_cfg.h" -#include "qemu-common.h" - #define ALLOC_PAGE_SIZE (4096) void pc_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags) diff --git a/tests/qtest/libqos/malloc-pc.h b/tests/qtest/libqos/malloc-pc.h index d8d79853c844..e531473601cd 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.c b/tests/qtest/libqos/malloc-spapr.c index 05b306c191d3..d90ed3c51d7d 100644 --- a/tests/qtest/libqos/malloc-spapr.c +++ b/tests/qtest/libqos/malloc-spapr.c @@ -8,8 +8,6 @@ #include "qemu/osdep.h" #include "malloc-spapr.h" -#include "qemu-common.h" - #define SPAPR_PAGE_SIZE 4096 /* Memory must be a multiple of 256 MB, diff --git a/tests/qtest/libqos/malloc-spapr.h b/tests/qtest/libqos/malloc-spapr.h index f99572fd71d9..f544c0d611ae 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/malloc.c b/tests/qtest/libqos/malloc.c deleted file mode 100644 index f708b0143262..000000000000 --- a/tests/qtest/libqos/malloc.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * libqos malloc support - * - * Copyright (c) 2014 - * - * Author: - * John Snow - * - * 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 "malloc.h" -#include "qemu-common.h" -#include "qemu/host-utils.h" - -typedef struct MemBlock { - QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME; - uint64_t size; - uint64_t addr; -} MemBlock; - -#define DEFAULT_PAGE_SIZE 4096 - -static void mlist_delete(MemList *list, MemBlock *node) -{ - g_assert(list && node); - QTAILQ_REMOVE(list, node, MLIST_ENTNAME); - g_free(node); -} - -static MemBlock *mlist_find_key(MemList *head, uint64_t addr) -{ - MemBlock *node; - QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { - if (node->addr == addr) { - return node; - } - } - return NULL; -} - -static MemBlock *mlist_find_space(MemList *head, uint64_t size) -{ - MemBlock *node; - - QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { - if (node->size >= size) { - return node; - } - } - return NULL; -} - -static MemBlock *mlist_sort_insert(MemList *head, MemBlock *insr) -{ - MemBlock *node; - g_assert(head && insr); - - QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { - if (insr->addr < node->addr) { - QTAILQ_INSERT_BEFORE(node, insr, MLIST_ENTNAME); - return insr; - } - } - - QTAILQ_INSERT_TAIL(head, insr, MLIST_ENTNAME); - return insr; -} - -static inline uint64_t mlist_boundary(MemBlock *node) -{ - return node->size + node->addr; -} - -static MemBlock *mlist_join(MemList *head, MemBlock *left, MemBlock *right) -{ - g_assert(head && left && right); - - left->size += right->size; - mlist_delete(head, right); - return left; -} - -static void mlist_coalesce(MemList *head, MemBlock *node) -{ - g_assert(node); - MemBlock *left; - MemBlock *right; - char merge; - - do { - merge = 0; - left = QTAILQ_PREV(node, MLIST_ENTNAME); - right = QTAILQ_NEXT(node, MLIST_ENTNAME); - - /* clowns to the left of me */ - if (left && mlist_boundary(left) == node->addr) { - node = mlist_join(head, left, node); - merge = 1; - } - - /* jokers to the right */ - if (right && mlist_boundary(node) == right->addr) { - node = mlist_join(head, node, right); - merge = 1; - } - - } while (merge); -} - -static MemBlock *mlist_new(uint64_t addr, uint64_t size) -{ - MemBlock *block; - - if (!size) { - return NULL; - } - block = g_new0(MemBlock, 1); - - block->addr = addr; - block->size = size; - - return block; -} - -static uint64_t mlist_fulfill(QGuestAllocator *s, MemBlock *freenode, - uint64_t size) -{ - uint64_t addr; - MemBlock *usednode; - - g_assert(freenode); - g_assert_cmpint(freenode->size, >=, size); - - addr = freenode->addr; - if (freenode->size == size) { - /* re-use this freenode as our used node */ - QTAILQ_REMOVE(s->free, freenode, MLIST_ENTNAME); - usednode = freenode; - } else { - /* adjust the free node and create a new used node */ - freenode->addr += size; - freenode->size -= size; - usednode = mlist_new(addr, size); - } - - mlist_sort_insert(s->used, usednode); - return addr; -} - -/* To assert the correctness of the list. - * Used only if ALLOC_PARANOID is set. */ -static void mlist_check(QGuestAllocator *s) -{ - MemBlock *node; - uint64_t addr = s->start > 0 ? s->start - 1 : 0; - uint64_t next = s->start; - - QTAILQ_FOREACH(node, s->free, MLIST_ENTNAME) { - g_assert_cmpint(node->addr, >, addr); - g_assert_cmpint(node->addr, >=, next); - addr = node->addr; - next = node->addr + node->size; - } - - addr = s->start > 0 ? s->start - 1 : 0; - next = s->start; - QTAILQ_FOREACH(node, s->used, MLIST_ENTNAME) { - g_assert_cmpint(node->addr, >, addr); - g_assert_cmpint(node->addr, >=, next); - addr = node->addr; - next = node->addr + node->size; - } -} - -static uint64_t mlist_alloc(QGuestAllocator *s, uint64_t size) -{ - MemBlock *node; - - node = mlist_find_space(s->free, size); - if (!node) { - fprintf(stderr, "Out of guest memory.\n"); - g_assert_not_reached(); - } - return mlist_fulfill(s, node, size); -} - -static void mlist_free(QGuestAllocator *s, uint64_t addr) -{ - MemBlock *node; - - if (addr == 0) { - return; - } - - node = mlist_find_key(s->used, addr); - if (!node) { - fprintf(stderr, "Error: no record found for an allocation at " - "0x%016" PRIx64 ".\n", - addr); - g_assert_not_reached(); - } - - /* Rip it out of the used list and re-insert back into the free list. */ - QTAILQ_REMOVE(s->used, node, MLIST_ENTNAME); - mlist_sort_insert(s->free, node); - mlist_coalesce(s->free, node); -} - -/* - * Mostly for valgrind happiness, but it does offer - * a chokepoint for debugging guest memory leaks, too. - */ -void alloc_destroy(QGuestAllocator *allocator) -{ - MemBlock *node; - MemBlock *tmp; - QAllocOpts mask; - - /* Check for guest leaks, and destroy the list. */ - QTAILQ_FOREACH_SAFE(node, allocator->used, MLIST_ENTNAME, tmp) { - if (allocator->opts & (ALLOC_LEAK_WARN | ALLOC_LEAK_ASSERT)) { - fprintf(stderr, "guest malloc leak @ 0x%016" PRIx64 "; " - "size 0x%016" PRIx64 ".\n", - node->addr, node->size); - } - if (allocator->opts & (ALLOC_LEAK_ASSERT)) { - g_assert_not_reached(); - } - g_free(node); - } - - /* If we have previously asserted that there are no leaks, then there - * should be only one node here with a specific address and size. */ - mask = ALLOC_LEAK_ASSERT | ALLOC_PARANOID; - QTAILQ_FOREACH_SAFE(node, allocator->free, MLIST_ENTNAME, tmp) { - if ((allocator->opts & mask) == mask) { - if ((node->addr != allocator->start) || - (node->size != allocator->end - allocator->start)) { - fprintf(stderr, "Free list is corrupted.\n"); - g_assert_not_reached(); - } - } - - g_free(node); - } - - g_free(allocator->used); - g_free(allocator->free); -} - -uint64_t guest_alloc(QGuestAllocator *allocator, size_t size) -{ - uint64_t rsize = size; - uint64_t naddr; - - if (!size) { - return 0; - } - - rsize += (allocator->page_size - 1); - rsize &= -allocator->page_size; - g_assert_cmpint((allocator->start + rsize), <=, allocator->end); - g_assert_cmpint(rsize, >=, size); - - naddr = mlist_alloc(allocator, rsize); - if (allocator->opts & ALLOC_PARANOID) { - mlist_check(allocator); - } - - return naddr; -} - -void guest_free(QGuestAllocator *allocator, uint64_t addr) -{ - if (!addr) { - return; - } - mlist_free(allocator, addr); - if (allocator->opts & ALLOC_PARANOID) { - mlist_check(allocator); - } -} - -void alloc_init(QGuestAllocator *s, QAllocOpts opts, - uint64_t start, uint64_t end, - size_t page_size) -{ - MemBlock *node; - - s->opts = opts; - s->start = start; - s->end = end; - - s->used = g_new(MemList, 1); - s->free = g_new(MemList, 1); - QTAILQ_INIT(s->used); - QTAILQ_INIT(s->free); - - node = mlist_new(s->start, s->end - s->start); - QTAILQ_INSERT_HEAD(s->free, node, MLIST_ENTNAME); - - s->page_size = page_size; -} - -void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts) -{ - allocator->opts |= opts; -} - -void migrate_allocator(QGuestAllocator *src, - QGuestAllocator *dst) -{ - MemBlock *node, *tmp; - MemList *tmpused, *tmpfree; - - /* The general memory layout should be equivalent, - * though opts can differ. */ - g_assert_cmphex(src->start, ==, dst->start); - g_assert_cmphex(src->end, ==, dst->end); - - /* Destroy (silently, regardless of options) the dest-list: */ - QTAILQ_FOREACH_SAFE(node, dst->used, MLIST_ENTNAME, tmp) { - g_free(node); - } - QTAILQ_FOREACH_SAFE(node, dst->free, MLIST_ENTNAME, tmp) { - g_free(node); - } - - tmpused = dst->used; - tmpfree = dst->free; - - /* Inherit the lists of the source allocator: */ - dst->used = src->used; - dst->free = src->free; - - /* Source is now re-initialized, the source memory is 'invalid' now: */ - src->used = tmpused; - src->free = tmpfree; - QTAILQ_INIT(src->used); - QTAILQ_INIT(src->free); - node = mlist_new(src->start, src->end - src->start); - QTAILQ_INSERT_HEAD(src->free, node, MLIST_ENTNAME); - return; -} diff --git a/tests/qtest/libqos/malloc.h b/tests/qtest/libqos/malloc.h deleted file mode 100644 index 4d1a2e2bef4a..000000000000 --- a/tests/qtest/libqos/malloc.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * libqos malloc support - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef LIBQOS_MALLOC_H -#define LIBQOS_MALLOC_H - -#include "qemu/queue.h" -#include "libqtest.h" - -typedef enum { - ALLOC_NO_FLAGS = 0x00, - ALLOC_LEAK_WARN = 0x01, - ALLOC_LEAK_ASSERT = 0x02, - ALLOC_PARANOID = 0x04 -} QAllocOpts; - -typedef QTAILQ_HEAD(MemList, MemBlock) MemList; - -typedef struct QGuestAllocator { - QAllocOpts opts; - uint64_t start; - uint64_t end; - uint32_t page_size; - - MemList *used; - MemList *free; -} QGuestAllocator; - -/* Always returns page aligned values */ -uint64_t guest_alloc(QGuestAllocator *allocator, size_t size); -void guest_free(QGuestAllocator *allocator, uint64_t addr); -void migrate_allocator(QGuestAllocator *src, QGuestAllocator *dst); - -void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts); - -void alloc_init(QGuestAllocator *alloc, QAllocOpts flags, - uint64_t start, uint64_t end, - size_t page_size); -void alloc_destroy(QGuestAllocator *allocator); - -#endif diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index e988d1579172..32f028872c5a 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -1,9 +1,12 @@ -libqos_srcs = files('../libqtest.c', +libqos_srcs = files( + '../libqtest.c', + '../libqmp.c', + 'qgraph.c', 'qos_external.c', 'pci.c', 'fw_cfg.c', - 'malloc.c', + 'libqos-malloc.c', 'libqos.c', 'sdhci-cmd.c', @@ -30,7 +33,6 @@ libqos_srcs = files('../libqtest.c', 'sdhci.c', 'tpci200.c', 'virtio.c', - 'virtio-9p.c', 'virtio-balloon.c', 'virtio-blk.c', 'vhost-user-blk.c', @@ -42,6 +44,8 @@ libqos_srcs = files('../libqtest.c', 'virtio-scsi.c', 'virtio-serial.c', 'virtio-iommu.c', + 'virtio-gpio.c', + 'generic-pcihost.c', # qgraph machines: 'aarch64-xlnx-zcu102-machine.c', @@ -56,6 +60,10 @@ libqos_srcs = files('../libqtest.c', 'x86_64_pc-machine.c', ) +if have_virtfs + libqos_srcs += files('virtio-9p.c', 'virtio-9p-client.c') +endif + libqos = static_library('qos', libqos_srcs + genh, name_suffix: 'fa', build_by_default: false) diff --git a/tests/qtest/libqos/pci-pc.c b/tests/qtest/libqos/pci-pc.c index f97844289f13..96046287ac68 100644 --- a/tests/qtest/libqos/pci-pc.c +++ b/tests/qtest/libqos/pci-pc.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "pci-pc.h" #include "qapi/qmp/qdict.h" #include "hw/pci/pci_regs.h" @@ -150,6 +150,7 @@ void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc) qpci->bus.qts = qts; qpci->bus.pio_alloc_ptr = 0xc000; + qpci->bus.pio_limit = 0x10000; qpci->bus.mmio_alloc_ptr = 0xE0000000; qpci->bus.mmio_limit = 0x100000000ULL; @@ -178,13 +179,7 @@ void qpci_free_pc(QPCIBus *bus) void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot) { - QDict *response; - - response = qtest_qmp(qts, "{'execute': 'device_del'," - " 'arguments': {'id': %s}}", id); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - qobject_unref(response); + qtest_qmp_device_del_send(qts, id); qtest_outl(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); diff --git a/tests/qtest/libqos/pci-pc.h b/tests/qtest/libqos/pci-pc.h index 49ec9507f22d..849bd493de0c 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.c b/tests/qtest/libqos/pci-spapr.c index 262226985f37..0f1023e4a73d 100644 --- a/tests/qtest/libqos/pci-spapr.c +++ b/tests/qtest/libqos/pci-spapr.c @@ -6,7 +6,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "pci-spapr.h" #include "rtas.h" #include "qgraph.h" @@ -197,6 +197,7 @@ void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts, qpci->bus.qts = qts; qpci->bus.pio_alloc_ptr = 0xc000; + qpci->bus.pio_limit = 0x10000; qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base; qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size; diff --git a/tests/qtest/libqos/pci-spapr.h b/tests/qtest/libqos/pci-spapr.h index 20a43718b7db..3dbf1e58ae69 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/pci.c b/tests/qtest/libqos/pci.c index 3a9076ae580a..b23d72346b6e 100644 --- a/tests/qtest/libqos/pci.c +++ b/tests/qtest/libqos/pci.c @@ -398,44 +398,56 @@ void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value) uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readb(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readb(bus, token.addr + off); } else { uint8_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return val; } } uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readw(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readw(bus, token.addr + off); } else { uint16_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(bus, token.addr + off, &val, sizeof(val)); return le16_to_cpu(val); } } uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readl(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readl(bus, token.addr + off); } else { uint32_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return le32_to_cpu(val); } } uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readq(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readq(bus, token.addr + off); } else { uint64_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(bus, token.addr + off, &val, sizeof(val)); return le64_to_cpu(val); } } @@ -443,57 +455,65 @@ uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off) void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off, uint8_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeb(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writeb(bus, token.addr + off, value); } else { - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off, uint16_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writew(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writew(bus, token.addr + off, value); } else { value = cpu_to_le16(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off, uint32_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writel(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writel(bus, token.addr + off, value); } else { value = cpu_to_le32(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off, uint64_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeq(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writeq(bus, token.addr + off, value); } else { value = cpu_to_le64(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off, void *buf, size_t len) { - g_assert(token.addr >= QPCI_PIO_LIMIT); + g_assert(!token.is_io); dev->bus->memread(dev->bus, token.addr + off, buf, len); } void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off, const void *buf, size_t len) { - g_assert(token.addr >= QPCI_PIO_LIMIT); + g_assert(!token.is_io); dev->bus->memwrite(dev->bus, token.addr + off, buf, len); } @@ -534,9 +554,10 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size); g_assert(loc >= bus->pio_alloc_ptr); - g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */ + g_assert(loc + size <= bus->pio_limit); bus->pio_alloc_ptr = loc + size; + bar.is_io = true; qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); } else { @@ -547,6 +568,7 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) g_assert(loc + size <= bus->mmio_limit); bus->mmio_alloc_ptr = loc + size; + bar.is_io = false; qpci_config_writel(dev, bar_reg, loc); } @@ -562,7 +584,7 @@ void qpci_iounmap(QPCIDevice *dev, QPCIBar bar) QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr) { - QPCIBar bar = { .addr = addr }; + QPCIBar bar = { .addr = addr, .is_io = true }; return bar; } diff --git a/tests/qtest/libqos/pci.h b/tests/qtest/libqos/pci.h index becb800f9e6a..838961452357 100644 --- a/tests/qtest/libqos/pci.h +++ b/tests/qtest/libqos/pci.h @@ -13,11 +13,9 @@ #ifndef LIBQOS_PCI_H #define LIBQOS_PCI_H -#include "libqtest.h" +#include "../libqtest.h" #include "qgraph.h" -#define QPCI_PIO_LIMIT 0x10000 - #define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) typedef struct QPCIDevice QPCIDevice; @@ -51,14 +49,16 @@ struct QPCIBus { uint8_t offset, uint32_t value); QTestState *qts; - uint16_t pio_alloc_ptr; + uint64_t pio_alloc_ptr, pio_limit; uint64_t mmio_alloc_ptr, mmio_limit; bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */ + bool not_hotpluggable; /* TRUE if devices cannot be hotplugged */ }; struct QPCIBar { uint64_t addr; + bool is_io; }; struct QPCIDevice diff --git a/tests/qtest/libqos/ppc64_pseries-machine.c b/tests/qtest/libqos/ppc64_pseries-machine.c index 24ca1799765f..364e9c689bb9 100644 --- a/tests/qtest/libqos/ppc64_pseries-machine.c +++ b/tests/qtest/libqos/ppc64_pseries-machine.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qgraph.h" #include "pci-spapr.h" #include "qemu/module.h" diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c index 109ff04e1e8f..0a2dddfafa4f 100644 --- a/tests/qtest/libqos/qgraph.c +++ b/tests/qtest/libqos/qgraph.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/queue.h" #include "qgraph_internal.h" #include "qgraph.h" diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h index 871740c0dc89..287022a67c1d 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; @@ -381,7 +381,7 @@ QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent, * mind: only tests with a path down from the actual test case node (leaf) up * to the graph's root node are actually executed by the qtest framework. And * the qtest framework uses QMP to automatically check which QEMU drivers are - * actually currently available, and accordingly qos marks certain pathes as + * actually currently available, and accordingly qos marks certain paths as * 'unavailable' in such cases (e.g. when QEMU was compiled without support for * a certain feature). */ diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index 10ee0f75b288..c6bb8bff09ee 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -18,13 +18,13 @@ #include "qemu/osdep.h" #include -#include "libqtest.h" +#include "../libqtest.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qbool.h" #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 8446e3df0b1c..ea3736488749 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.c b/tests/qtest/libqos/rtas.c index db29d5554dcb..dedbfb4cb3a6 100644 --- a/tests/qtest/libqos/rtas.c +++ b/tests/qtest/libqos/rtas.c @@ -4,7 +4,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "rtas.h" static void qrtas_copy_args(QTestState *qts, uint64_t target_args, diff --git a/tests/qtest/libqos/rtas.h b/tests/qtest/libqos/rtas.h index f38f99dfab84..be8353d505ff 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/sdhci-cmd.c b/tests/qtest/libqos/sdhci-cmd.c index 2d9e51834114..a6f073ac1ac9 100644 --- a/tests/qtest/libqos/sdhci-cmd.c +++ b/tests/qtest/libqos/sdhci-cmd.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "sdhci-cmd.h" -#include "libqtest.h" +#include "../libqtest.h" static ssize_t read_fifo(QTestState *qts, uint64_t reg, char *msg, size_t count) { diff --git a/tests/qtest/libqos/sdhci-cmd.h b/tests/qtest/libqos/sdhci-cmd.h index 64763c5a2ace..9e61dd494464 100644 --- a/tests/qtest/libqos/sdhci-cmd.h +++ b/tests/qtest/libqos/sdhci-cmd.h @@ -14,7 +14,7 @@ * for more details. */ -#include "libqtest.h" +#include "../libqtest.h" /* more details at hw/sd/sdhci-internal.h */ #define SDHC_BLKSIZE 0x04 diff --git a/tests/qtest/libqos/sdhci.c b/tests/qtest/libqos/sdhci.c index 65f0d07fc5ac..71696980f83e 100644 --- a/tests/qtest/libqos/sdhci.c +++ b/tests/qtest/libqos/sdhci.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qgraph.h" #include "pci.h" #include "qemu/module.h" diff --git a/tests/qtest/libqos/tpci200.c b/tests/qtest/libqos/tpci200.c index 1787b1f188d3..8b0060324728 100644 --- a/tests/qtest/libqos/tpci200.c +++ b/tests/qtest/libqos/tpci200.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "qgraph.h" #include "pci.h" diff --git a/tests/qtest/libqos/usb.c b/tests/qtest/libqos/usb.c index 8b45b0298446..446fdb5796c4 100644 --- a/tests/qtest/libqos/usb.c +++ b/tests/qtest/libqos/usb.c @@ -12,7 +12,7 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "hw/usb/uhci-regs.h" #include "usb.h" diff --git a/tests/qtest/libqos/vhost-user-blk.c b/tests/qtest/libqos/vhost-user-blk.c index 568c3426ed3a..2f3c9cb5336d 100644 --- a/tests/qtest/libqos/vhost-user-blk.c +++ b/tests/qtest/libqos/vhost-user-blk.c @@ -21,7 +21,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "standard-headers/linux/virtio_blk.h" #include "vhost-user-blk.h" diff --git a/tests/qtest/libqos/virtio-9p-client.c b/tests/qtest/libqos/virtio-9p-client.c new file mode 100644 index 000000000000..e4a368e03660 --- /dev/null +++ b/tests/qtest/libqos/virtio-9p-client.c @@ -0,0 +1,1049 @@ +/* + * 9P network client for VirtIO 9P test cases (based on QTest) + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * Not so fast! You might want to read the 9p developer docs first: + * https://wiki.qemu.org/Documentation/9p + */ + +#include "qemu/osdep.h" +#include "virtio-9p-client.h" + +#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) +static QGuestAllocator *alloc; + +void v9fs_set_allocator(QGuestAllocator *t_alloc) +{ + alloc = t_alloc; +} + +/* + * Used to auto generate new fids. Start with arbitrary high value to avoid + * collision with hard coded fids in basic test code. + */ +static uint32_t fid_generator = 1000; + +static uint32_t genfid(void) +{ + return fid_generator++; +} + +/** + * Splits the @a in string by @a delim into individual (non empty) strings + * and outputs them to @a out. The output array @a out is NULL terminated. + * + * Output array @a out must be freed by calling split_free(). + * + * @returns number of individual elements in output array @a out (without the + * final NULL terminating element) + */ +static int split(const char *in, const char *delim, char ***out) +{ + int n = 0, i = 0; + char *tmp, *p; + + tmp = g_strdup(in); + for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) { + if (strlen(p) > 0) { + ++n; + } + } + g_free(tmp); + + *out = g_new0(char *, n + 1); /* last element NULL delimiter */ + + tmp = g_strdup(in); + for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) { + if (strlen(p) > 0) { + (*out)[i++] = g_strdup(p); + } + } + g_free(tmp); + + return n; +} + +static void split_free(char ***out) +{ + int i; + if (!*out) { + return; + } + for (i = 0; (*out)[i]; ++i) { + g_free((*out)[i]); + } + g_free(*out); + *out = NULL; +} + +void v9fs_memwrite(P9Req *req, const void *addr, size_t len) +{ + qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len); + req->t_off += len; +} + +void v9fs_memskip(P9Req *req, size_t len) +{ + req->r_off += len; +} + +void v9fs_memread(P9Req *req, void *addr, size_t len) +{ + qtest_memread(req->qts, req->r_msg + req->r_off, addr, len); + req->r_off += len; +} + +void v9fs_uint8_read(P9Req *req, uint8_t *val) +{ + v9fs_memread(req, val, 1); +} + +void v9fs_uint16_write(P9Req *req, uint16_t val) +{ + uint16_t le_val = cpu_to_le16(val); + + v9fs_memwrite(req, &le_val, 2); +} + +void v9fs_uint16_read(P9Req *req, uint16_t *val) +{ + v9fs_memread(req, val, 2); + le16_to_cpus(val); +} + +void v9fs_uint32_write(P9Req *req, uint32_t val) +{ + uint32_t le_val = cpu_to_le32(val); + + v9fs_memwrite(req, &le_val, 4); +} + +void v9fs_uint64_write(P9Req *req, uint64_t val) +{ + uint64_t le_val = cpu_to_le64(val); + + v9fs_memwrite(req, &le_val, 8); +} + +void v9fs_uint32_read(P9Req *req, uint32_t *val) +{ + v9fs_memread(req, val, 4); + le32_to_cpus(val); +} + +void v9fs_uint64_read(P9Req *req, uint64_t *val) +{ + v9fs_memread(req, val, 8); + le64_to_cpus(val); +} + +/* len[2] string[len] */ +uint16_t v9fs_string_size(const char *string) +{ + size_t len = strlen(string); + + g_assert_cmpint(len, <=, UINT16_MAX - 2); + + return 2 + len; +} + +void v9fs_string_write(P9Req *req, const char *string) +{ + int len = strlen(string); + + g_assert_cmpint(len, <=, UINT16_MAX); + + v9fs_uint16_write(req, (uint16_t) len); + v9fs_memwrite(req, string, len); +} + +void v9fs_string_read(P9Req *req, uint16_t *len, char **string) +{ + uint16_t local_len; + + v9fs_uint16_read(req, &local_len); + if (len) { + *len = local_len; + } + if (string) { + *string = g_malloc(local_len + 1); + v9fs_memread(req, *string, local_len); + (*string)[local_len] = 0; + } else { + v9fs_memskip(req, local_len); + } +} + +typedef struct { + uint32_t size; + uint8_t id; + uint16_t tag; +} QEMU_PACKED P9Hdr; + +P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, + uint16_t tag) +{ + P9Req *req = g_new0(P9Req, 1); + uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */ + P9Hdr hdr = { + .id = id, + .tag = cpu_to_le16(tag) + }; + + g_assert_cmpint(total_size, <=, UINT32_MAX - size); + total_size += size; + hdr.size = cpu_to_le32(total_size); + + g_assert_cmpint(total_size, <=, P9_MAX_SIZE); + + req->qts = global_qtest; + req->v9p = v9p; + req->t_size = total_size; + req->t_msg = guest_alloc(alloc, req->t_size); + v9fs_memwrite(req, &hdr, 7); + req->tag = tag; + return req; +} + +void v9fs_req_send(P9Req *req) +{ + QVirtio9P *v9p = req->v9p; + + req->r_msg = guest_alloc(alloc, P9_MAX_SIZE); + req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size, + false, true); + qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); + qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head); + req->t_off = 0; +} + +static const char *rmessage_name(uint8_t id) +{ + return + id == P9_RLERROR ? "RLERROR" : + id == P9_RVERSION ? "RVERSION" : + id == P9_RATTACH ? "RATTACH" : + id == P9_RWALK ? "RWALK" : + id == P9_RLOPEN ? "RLOPEN" : + id == P9_RWRITE ? "RWRITE" : + id == P9_RMKDIR ? "RMKDIR" : + id == P9_RLCREATE ? "RLCREATE" : + id == P9_RSYMLINK ? "RSYMLINK" : + id == P9_RLINK ? "RLINK" : + id == P9_RUNLINKAT ? "RUNLINKAT" : + id == P9_RFLUSH ? "RFLUSH" : + id == P9_RREADDIR ? "READDIR" : + ""; +} + +void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len) +{ + QVirtio9P *v9p = req->v9p; + + qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len, + QVIRTIO_9P_TIMEOUT_US); +} + +void v9fs_req_recv(P9Req *req, uint8_t id) +{ + P9Hdr hdr; + + v9fs_memread(req, &hdr, 7); + hdr.size = ldl_le_p(&hdr.size); + hdr.tag = lduw_le_p(&hdr.tag); + + g_assert_cmpint(hdr.size, >=, 7); + g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE); + g_assert_cmpint(hdr.tag, ==, req->tag); + + if (hdr.id != id) { + g_printerr("Received response %d (%s) instead of %d (%s)\n", + hdr.id, rmessage_name(hdr.id), id, rmessage_name(id)); + + if (hdr.id == P9_RLERROR) { + uint32_t err; + v9fs_uint32_read(req, &err); + g_printerr("Rlerror has errno %d (%s)\n", err, strerror(err)); + } + } + g_assert_cmpint(hdr.id, ==, id); +} + +void v9fs_req_free(P9Req *req) +{ + guest_free(alloc, req->t_msg); + guest_free(alloc, req->r_msg); + g_free(req); +} + +/* size[4] Rlerror tag[2] ecode[4] */ +void v9fs_rlerror(P9Req *req, uint32_t *err) +{ + v9fs_req_recv(req, P9_RLERROR); + v9fs_uint32_read(req, err); + v9fs_req_free(req); +} + +/* size[4] Tversion tag[2] msize[4] version[s] */ +TVersionRes v9fs_tversion(TVersionOpt opt) +{ + P9Req *req; + uint32_t err; + uint32_t body_size = 4; + uint16_t string_size; + uint16_t server_len; + g_autofree char *server_version = NULL; + + g_assert(opt.client); + + if (!opt.msize) { + opt.msize = P9_MAX_SIZE; + } + + if (!opt.tag) { + opt.tag = P9_NOTAG; + } + + if (!opt.version) { + opt.version = "9P2000.L"; + } + + string_size = v9fs_string_size(opt.version); + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + req = v9fs_req_init(opt.client, body_size, P9_TVERSION, opt.tag); + + v9fs_uint32_write(req, opt.msize); + v9fs_string_write(req, opt.version); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rversion(req, &server_len, &server_version); + g_assert_cmpmem(server_version, server_len, + opt.version, strlen(opt.version)); + } + req = NULL; /* request was freed */ + } + + return (TVersionRes) { + .req = req, + }; +} + +/* size[4] Rversion tag[2] msize[4] version[s] */ +void v9fs_rversion(P9Req *req, uint16_t *len, char **version) +{ + uint32_t msize; + + v9fs_req_recv(req, P9_RVERSION); + v9fs_uint32_read(req, &msize); + + g_assert_cmpint(msize, ==, P9_MAX_SIZE); + + if (len || version) { + v9fs_string_read(req, len, version); + } + + v9fs_req_free(req); +} + +/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ +TAttachRes v9fs_tattach(TAttachOpt opt) +{ + uint32_t err; + const char *uname = ""; /* ignored by QEMU */ + const char *aname = ""; /* ignored by QEMU */ + + g_assert(opt.client); + /* expecting either Rattach or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !opt.rattach.qid); + + if (!opt.requestOnly) { + v9fs_tversion((TVersionOpt) { .client = opt.client }); + } + + if (!opt.n_uname) { + opt.n_uname = getuid(); + } + + P9Req *req = v9fs_req_init(opt.client, 4 + 4 + 2 + 2 + 4, P9_TATTACH, + opt.tag); + + v9fs_uint32_write(req, opt.fid); + v9fs_uint32_write(req, P9_NOFID); + v9fs_string_write(req, uname); + v9fs_string_write(req, aname); + v9fs_uint32_write(req, opt.n_uname); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rattach(req, opt.rattach.qid); + } + req = NULL; /* request was freed */ + } + + return (TAttachRes) { + .req = req, + }; +} + +/* size[4] Rattach tag[2] qid[13] */ +void v9fs_rattach(P9Req *req, v9fs_qid *qid) +{ + v9fs_req_recv(req, P9_RATTACH); + if (qid) { + v9fs_memread(req, qid, 13); + } + v9fs_req_free(req); +} + +/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ +TWalkRes v9fs_twalk(TWalkOpt opt) +{ + P9Req *req; + int i; + uint32_t body_size = 4 + 4 + 2; + uint32_t err; + char **wnames = NULL; + + g_assert(opt.client); + /* expecting either high- or low-level path, both not both */ + g_assert(!opt.path || !(opt.nwname || opt.wnames)); + /* expecting either Rwalk or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !(opt.rwalk.nwqid || opt.rwalk.wqid)); + + if (!opt.newfid) { + opt.newfid = genfid(); + } + + if (opt.path) { + opt.nwname = split(opt.path, "/", &wnames); + opt.wnames = wnames; + } + + for (i = 0; i < opt.nwname; i++) { + uint16_t wname_size = v9fs_string_size(opt.wnames[i]); + + g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size); + body_size += wname_size; + } + req = v9fs_req_init(opt.client, body_size, P9_TWALK, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_uint32_write(req, opt.newfid); + v9fs_uint16_write(req, opt.nwname); + for (i = 0; i < opt.nwname; i++) { + v9fs_string_write(req, opt.wnames[i]); + } + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rwalk(req, opt.rwalk.nwqid, opt.rwalk.wqid); + } + req = NULL; /* request was freed */ + } + + split_free(&wnames); + + return (TWalkRes) { + .newfid = opt.newfid, + .req = req, + }; +} + +/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */ +void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) +{ + uint16_t local_nwqid; + + v9fs_req_recv(req, P9_RWALK); + v9fs_uint16_read(req, &local_nwqid); + if (nwqid) { + *nwqid = local_nwqid; + } + if (wqid) { + *wqid = g_malloc(local_nwqid * 13); + v9fs_memread(req, *wqid, local_nwqid * 13); + } + v9fs_req_free(req); +} + +/* size[4] Tgetattr tag[2] fid[4] request_mask[8] */ +TGetAttrRes v9fs_tgetattr(TGetAttrOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either Rgetattr or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !opt.rgetattr.attr); + + if (!opt.request_mask) { + opt.request_mask = P9_GETATTR_ALL; + } + + req = v9fs_req_init(opt.client, 4 + 8, P9_TGETATTR, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_uint64_write(req, opt.request_mask); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rgetattr(req, opt.rgetattr.attr); + } + req = NULL; /* request was freed */ + } + + return (TGetAttrRes) { .req = req }; +} + +/* + * size[4] Rgetattr tag[2] valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8] + * rdev[8] size[8] blksize[8] blocks[8] + * atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8] + * ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8] + * gen[8] data_version[8] + */ +void v9fs_rgetattr(P9Req *req, v9fs_attr *attr) +{ + v9fs_req_recv(req, P9_RGETATTR); + + v9fs_uint64_read(req, &attr->valid); + v9fs_memread(req, &attr->qid, 13); + v9fs_uint32_read(req, &attr->mode); + v9fs_uint32_read(req, &attr->uid); + v9fs_uint32_read(req, &attr->gid); + v9fs_uint64_read(req, &attr->nlink); + v9fs_uint64_read(req, &attr->rdev); + v9fs_uint64_read(req, &attr->size); + v9fs_uint64_read(req, &attr->blksize); + v9fs_uint64_read(req, &attr->blocks); + v9fs_uint64_read(req, &attr->atime_sec); + v9fs_uint64_read(req, &attr->atime_nsec); + v9fs_uint64_read(req, &attr->mtime_sec); + v9fs_uint64_read(req, &attr->mtime_nsec); + v9fs_uint64_read(req, &attr->ctime_sec); + v9fs_uint64_read(req, &attr->ctime_nsec); + v9fs_uint64_read(req, &attr->btime_sec); + v9fs_uint64_read(req, &attr->btime_nsec); + v9fs_uint64_read(req, &attr->gen); + v9fs_uint64_read(req, &attr->data_version); + + v9fs_req_free(req); +} + +/* size[4] Treaddir tag[2] fid[4] offset[8] count[4] */ +TReadDirRes v9fs_treaddir(TReadDirOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either Rreaddir or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !(opt.rreaddir.count || + opt.rreaddir.nentries || opt.rreaddir.entries)); + + req = v9fs_req_init(opt.client, 4 + 8 + 4, P9_TREADDIR, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_uint64_write(req, opt.offset); + v9fs_uint32_write(req, opt.count); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rreaddir(req, opt.rreaddir.count, opt.rreaddir.nentries, + opt.rreaddir.entries); + } + req = NULL; /* request was freed */ + } + + return (TReadDirRes) { .req = req }; +} + +/* size[4] Rreaddir tag[2] count[4] data[count] */ +void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, + struct V9fsDirent **entries) +{ + uint32_t local_count; + struct V9fsDirent *e = NULL; + uint16_t slen; + uint32_t n = 0; + + v9fs_req_recv(req, P9_RREADDIR); + v9fs_uint32_read(req, &local_count); + + if (count) { + *count = local_count; + } + + for (int32_t togo = (int32_t)local_count; + togo >= 13 + 8 + 1 + 2; + togo -= 13 + 8 + 1 + 2 + slen, ++n) + { + if (!e) { + e = g_new(struct V9fsDirent, 1); + if (entries) { + *entries = e; + } + } else { + e = e->next = g_new(struct V9fsDirent, 1); + } + e->next = NULL; + /* qid[13] offset[8] type[1] name[s] */ + v9fs_memread(req, &e->qid, 13); + v9fs_uint64_read(req, &e->offset); + v9fs_uint8_read(req, &e->type); + v9fs_string_read(req, &slen, &e->name); + } + + if (nentries) { + *nentries = n; + } + + v9fs_req_free(req); +} + +void v9fs_free_dirents(struct V9fsDirent *e) +{ + struct V9fsDirent *next = NULL; + + for (; e; e = next) { + next = e->next; + g_free(e->name); + g_free(e); + } +} + +/* size[4] Tlopen tag[2] fid[4] flags[4] */ +TLOpenRes v9fs_tlopen(TLOpenOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either Rlopen or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !(opt.rlopen.qid || opt.rlopen.iounit)); + + req = v9fs_req_init(opt.client, 4 + 4, P9_TLOPEN, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_uint32_write(req, opt.flags); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rlopen(req, opt.rlopen.qid, opt.rlopen.iounit); + } + req = NULL; /* request was freed */ + } + + return (TLOpenRes) { .req = req }; +} + +/* size[4] Rlopen tag[2] qid[13] iounit[4] */ +void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit) +{ + v9fs_req_recv(req, P9_RLOPEN); + if (qid) { + v9fs_memread(req, qid, 13); + } else { + v9fs_memskip(req, 13); + } + if (iounit) { + v9fs_uint32_read(req, iounit); + } + v9fs_req_free(req); +} + +/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */ +TWriteRes v9fs_twrite(TWriteOpt opt) +{ + P9Req *req; + uint32_t err; + uint32_t body_size = 4 + 8 + 4; + uint32_t written = 0; + + g_assert(opt.client); + + g_assert_cmpint(body_size, <=, UINT32_MAX - opt.count); + body_size += opt.count; + req = v9fs_req_init(opt.client, body_size, P9_TWRITE, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_uint64_write(req, opt.offset); + v9fs_uint32_write(req, opt.count); + v9fs_memwrite(req, opt.data, opt.count); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rwrite(req, &written); + } + req = NULL; /* request was freed */ + } + + return (TWriteRes) { + .req = req, + .count = written + }; +} + +/* size[4] Rwrite tag[2] count[4] */ +void v9fs_rwrite(P9Req *req, uint32_t *count) +{ + v9fs_req_recv(req, P9_RWRITE); + if (count) { + v9fs_uint32_read(req, count); + } + v9fs_req_free(req); +} + +/* size[4] Tflush tag[2] oldtag[2] */ +TFlushRes v9fs_tflush(TFlushOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + + req = v9fs_req_init(opt.client, 2, P9_TFLUSH, opt.tag); + v9fs_uint32_write(req, opt.oldtag); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rflush(req); + } + req = NULL; /* request was freed */ + } + + return (TFlushRes) { .req = req }; +} + +/* size[4] Rflush tag[2] */ +void v9fs_rflush(P9Req *req) +{ + v9fs_req_recv(req, P9_RFLUSH); + v9fs_req_free(req); +} + +/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */ +TMkdirRes v9fs_tmkdir(TMkdirOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either hi-level atPath or low-level dfid, but not both */ + g_assert(!opt.atPath || !opt.dfid); + /* expecting either Rmkdir or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !opt.rmkdir.qid); + + if (opt.atPath) { + opt.dfid = v9fs_twalk((TWalkOpt) { .client = opt.client, + .path = opt.atPath }).newfid; + } + + if (!opt.mode) { + opt.mode = 0750; + } + + uint32_t body_size = 4 + 4 + 4; + uint16_t string_size = v9fs_string_size(opt.name); + + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + + req = v9fs_req_init(opt.client, body_size, P9_TMKDIR, opt.tag); + v9fs_uint32_write(req, opt.dfid); + v9fs_string_write(req, opt.name); + v9fs_uint32_write(req, opt.mode); + v9fs_uint32_write(req, opt.gid); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rmkdir(req, opt.rmkdir.qid); + } + req = NULL; /* request was freed */ + } + + return (TMkdirRes) { .req = req }; +} + +/* size[4] Rmkdir tag[2] qid[13] */ +void v9fs_rmkdir(P9Req *req, v9fs_qid *qid) +{ + v9fs_req_recv(req, P9_RMKDIR); + if (qid) { + v9fs_memread(req, qid, 13); + } else { + v9fs_memskip(req, 13); + } + v9fs_req_free(req); +} + +/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */ +TlcreateRes v9fs_tlcreate(TlcreateOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either hi-level atPath or low-level fid, but not both */ + g_assert(!opt.atPath || !opt.fid); + /* expecting either Rlcreate or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !(opt.rlcreate.qid || opt.rlcreate.iounit)); + + if (opt.atPath) { + opt.fid = v9fs_twalk((TWalkOpt) { .client = opt.client, + .path = opt.atPath }).newfid; + } + + if (!opt.mode) { + opt.mode = 0750; + } + + uint32_t body_size = 4 + 4 + 4 + 4; + uint16_t string_size = v9fs_string_size(opt.name); + + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + + req = v9fs_req_init(opt.client, body_size, P9_TLCREATE, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_string_write(req, opt.name); + v9fs_uint32_write(req, opt.flags); + v9fs_uint32_write(req, opt.mode); + v9fs_uint32_write(req, opt.gid); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rlcreate(req, opt.rlcreate.qid, opt.rlcreate.iounit); + } + req = NULL; /* request was freed */ + } + + return (TlcreateRes) { .req = req }; +} + +/* size[4] Rlcreate tag[2] qid[13] iounit[4] */ +void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit) +{ + v9fs_req_recv(req, P9_RLCREATE); + if (qid) { + v9fs_memread(req, qid, 13); + } else { + v9fs_memskip(req, 13); + } + if (iounit) { + v9fs_uint32_read(req, iounit); + } + v9fs_req_free(req); +} + +/* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */ +TsymlinkRes v9fs_tsymlink(TsymlinkOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either hi-level atPath or low-level fid, but not both */ + g_assert(!opt.atPath || !opt.fid); + /* expecting either Rsymlink or Rlerror, but obviously not both */ + g_assert(!opt.expectErr || !opt.rsymlink.qid); + + if (opt.atPath) { + opt.fid = v9fs_twalk((TWalkOpt) { .client = opt.client, + .path = opt.atPath }).newfid; + } + + uint32_t body_size = 4 + 4; + uint16_t string_size = v9fs_string_size(opt.name) + + v9fs_string_size(opt.symtgt); + + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + + req = v9fs_req_init(opt.client, body_size, P9_TSYMLINK, opt.tag); + v9fs_uint32_write(req, opt.fid); + v9fs_string_write(req, opt.name); + v9fs_string_write(req, opt.symtgt); + v9fs_uint32_write(req, opt.gid); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rsymlink(req, opt.rsymlink.qid); + } + req = NULL; /* request was freed */ + } + + return (TsymlinkRes) { .req = req }; +} + +/* size[4] Rsymlink tag[2] qid[13] */ +void v9fs_rsymlink(P9Req *req, v9fs_qid *qid) +{ + v9fs_req_recv(req, P9_RSYMLINK); + if (qid) { + v9fs_memread(req, qid, 13); + } else { + v9fs_memskip(req, 13); + } + v9fs_req_free(req); +} + +/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */ +TlinkRes v9fs_tlink(TlinkOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either hi-level atPath or low-level dfid, but not both */ + g_assert(!opt.atPath || !opt.dfid); + /* expecting either hi-level toPath or low-level fid, but not both */ + g_assert(!opt.toPath || !opt.fid); + + if (opt.atPath) { + opt.dfid = v9fs_twalk((TWalkOpt) { .client = opt.client, + .path = opt.atPath }).newfid; + } + if (opt.toPath) { + opt.fid = v9fs_twalk((TWalkOpt) { .client = opt.client, + .path = opt.toPath }).newfid; + } + + uint32_t body_size = 4 + 4; + uint16_t string_size = v9fs_string_size(opt.name); + + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + + req = v9fs_req_init(opt.client, body_size, P9_TLINK, opt.tag); + v9fs_uint32_write(req, opt.dfid); + v9fs_uint32_write(req, opt.fid); + v9fs_string_write(req, opt.name); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rlink(req); + } + req = NULL; /* request was freed */ + } + + return (TlinkRes) { .req = req }; +} + +/* size[4] Rlink tag[2] */ +void v9fs_rlink(P9Req *req) +{ + v9fs_req_recv(req, P9_RLINK); + v9fs_req_free(req); +} + +/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */ +TunlinkatRes v9fs_tunlinkat(TunlinkatOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + /* expecting either hi-level atPath or low-level dirfd, but not both */ + g_assert(!opt.atPath || !opt.dirfd); + + if (opt.atPath) { + opt.dirfd = v9fs_twalk((TWalkOpt) { .client = opt.client, + .path = opt.atPath }).newfid; + } + + uint32_t body_size = 4 + 4; + uint16_t string_size = v9fs_string_size(opt.name); + + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + + req = v9fs_req_init(opt.client, body_size, P9_TUNLINKAT, opt.tag); + v9fs_uint32_write(req, opt.dirfd); + v9fs_string_write(req, opt.name); + v9fs_uint32_write(req, opt.flags); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_runlinkat(req); + } + req = NULL; /* request was freed */ + } + + return (TunlinkatRes) { .req = req }; +} + +/* size[4] Runlinkat tag[2] */ +void v9fs_runlinkat(P9Req *req) +{ + v9fs_req_recv(req, P9_RUNLINKAT); + v9fs_req_free(req); +} diff --git a/tests/qtest/libqos/virtio-9p-client.h b/tests/qtest/libqos/virtio-9p-client.h new file mode 100644 index 000000000000..78228eb97d9e --- /dev/null +++ b/tests/qtest/libqos/virtio-9p-client.h @@ -0,0 +1,494 @@ +/* + * 9P network client for VirtIO 9P test cases (based on QTest) + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * Not so fast! You might want to read the 9p developer docs first: + * https://wiki.qemu.org/Documentation/9p + */ + +#ifndef TESTS_LIBQOS_VIRTIO_9P_CLIENT_H +#define TESTS_LIBQOS_VIRTIO_9P_CLIENT_H + +#include "hw/9pfs/9p.h" +#include "hw/9pfs/9p-synth.h" +#include "virtio-9p.h" +#include "qgraph.h" +#include "tests/qtest/libqtest-single.h" + +#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ + +typedef struct { + QTestState *qts; + QVirtio9P *v9p; + uint16_t tag; + uint64_t t_msg; + uint32_t t_size; + uint64_t r_msg; + /* No r_size, it is hardcoded to P9_MAX_SIZE */ + size_t t_off; + size_t r_off; + uint32_t free_head; +} P9Req; + +/* type[1] version[4] path[8] */ +typedef char v9fs_qid[13]; + +typedef struct v9fs_attr { + uint64_t valid; + v9fs_qid qid; + uint32_t mode; + uint32_t uid; + uint32_t gid; + uint64_t nlink; + uint64_t rdev; + uint64_t size; + uint64_t blksize; + uint64_t blocks; + uint64_t atime_sec; + uint64_t atime_nsec; + uint64_t mtime_sec; + uint64_t mtime_nsec; + uint64_t ctime_sec; + uint64_t ctime_nsec; + uint64_t btime_sec; + uint64_t btime_nsec; + uint64_t gen; + uint64_t data_version; +} v9fs_attr; + +#define P9_GETATTR_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ +#define P9_GETATTR_ALL 0x00003fffULL /* Mask for ALL fields */ + +struct V9fsDirent { + v9fs_qid qid; + uint64_t offset; + uint8_t type; + char *name; + struct V9fsDirent *next; +}; + +/* options for 'Twalk' 9p request */ +typedef struct TWalkOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID of directory from where walk should start (optional) */ + uint32_t fid; + /* file ID for target directory being walked to (optional) */ + uint32_t newfid; + /* low level variant of path to walk to (optional) */ + uint16_t nwname; + char **wnames; + /* high level variant of path to walk to (optional) */ + const char *path; + /* data being received from 9p server as 'Rwalk' response (optional) */ + struct { + uint16_t *nwqid; + v9fs_qid **wqid; + } rwalk; + /* only send Twalk request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TWalkOpt; + +/* result of 'Twalk' 9p request */ +typedef struct TWalkRes { + /* file ID of target directory been walked to */ + uint32_t newfid; + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TWalkRes; + +/* options for 'Tversion' 9p request */ +typedef struct TVersionOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* maximum message size that can be handled by client (optional) */ + uint32_t msize; + /* protocol version (optional) */ + const char *version; + /* only send Tversion request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TVersionOpt; + +/* result of 'Tversion' 9p request */ +typedef struct TVersionRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TVersionRes; + +/* options for 'Tattach' 9p request */ +typedef struct TAttachOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID to be associated with root of file tree (optional) */ + uint32_t fid; + /* numerical uid of user being introduced to server (optional) */ + uint32_t n_uname; + /* data being received from 9p server as 'Rattach' response (optional) */ + struct { + /* server's idea of the root of the file tree */ + v9fs_qid *qid; + } rattach; + /* only send Tattach request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TAttachOpt; + +/* result of 'Tattach' 9p request */ +typedef struct TAttachRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TAttachRes; + +/* options for 'Tgetattr' 9p request */ +typedef struct TGetAttrOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID of file/dir whose attributes shall be retrieved (required) */ + uint32_t fid; + /* bitmask indicating attribute fields to be retrieved (optional) */ + uint64_t request_mask; + /* data being received from 9p server as 'Rgetattr' response (optional) */ + struct { + v9fs_attr *attr; + } rgetattr; + /* only send Tgetattr request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TGetAttrOpt; + +/* result of 'Tgetattr' 9p request */ +typedef struct TGetAttrRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TGetAttrRes; + +/* options for 'Treaddir' 9p request */ +typedef struct TReadDirOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID of directory whose entries shall be retrieved (required) */ + uint32_t fid; + /* offset in entries stream, i.e. for multiple requests (optional) */ + uint64_t offset; + /* maximum bytes to be returned by server (required) */ + uint32_t count; + /* data being received from 9p server as 'Rreaddir' response (optional) */ + struct { + uint32_t *count; + uint32_t *nentries; + struct V9fsDirent **entries; + } rreaddir; + /* only send Treaddir request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TReadDirOpt; + +/* result of 'Treaddir' 9p request */ +typedef struct TReadDirRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TReadDirRes; + +/* options for 'Tlopen' 9p request */ +typedef struct TLOpenOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID of file / directory to be opened (required) */ + uint32_t fid; + /* Linux open(2) flags such as O_RDONLY, O_RDWR, O_WRONLY (optional) */ + uint32_t flags; + /* data being received from 9p server as 'Rlopen' response (optional) */ + struct { + v9fs_qid *qid; + uint32_t *iounit; + } rlopen; + /* only send Tlopen request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TLOpenOpt; + +/* result of 'Tlopen' 9p request */ +typedef struct TLOpenRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TLOpenRes; + +/* options for 'Twrite' 9p request */ +typedef struct TWriteOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID of file to write to (required) */ + uint32_t fid; + /* start position of write from beginning of file (optional) */ + uint64_t offset; + /* how many bytes to write */ + uint32_t count; + /* data to be written */ + const void *data; + /* only send Twrite request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TWriteOpt; + +/* result of 'Twrite' 9p request */ +typedef struct TWriteRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; + /* amount of bytes written */ + uint32_t count; +} TWriteRes; + +/* options for 'Tflush' 9p request */ +typedef struct TFlushOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* message to flush (required) */ + uint16_t oldtag; + /* only send Tflush request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TFlushOpt; + +/* result of 'Tflush' 9p request */ +typedef struct TFlushRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TFlushRes; + +/* options for 'Tmkdir' 9p request */ +typedef struct TMkdirOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* low level variant of directory where new one shall be created */ + uint32_t dfid; + /* high-level variant of directory where new one shall be created */ + const char *atPath; + /* New directory's name (required) */ + const char *name; + /* Linux mkdir(2) mode bits (optional) */ + uint32_t mode; + /* effective group ID of caller */ + uint32_t gid; + /* data being received from 9p server as 'Rmkdir' response (optional) */ + struct { + /* QID of newly created directory */ + v9fs_qid *qid; + } rmkdir; + /* only send Tmkdir request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TMkdirOpt; + +/* result of 'TMkdir' 9p request */ +typedef struct TMkdirRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TMkdirRes; + +/* options for 'Tlcreate' 9p request */ +typedef struct TlcreateOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* low-level variant of directory where new file shall be created */ + uint32_t fid; + /* high-level variant of directory where new file shall be created */ + const char *atPath; + /* name of new file (required) */ + const char *name; + /* Linux kernel intent bits */ + uint32_t flags; + /* Linux create(2) mode bits */ + uint32_t mode; + /* effective group ID of caller */ + uint32_t gid; + /* data being received from 9p server as 'Rlcreate' response (optional) */ + struct { + v9fs_qid *qid; + uint32_t *iounit; + } rlcreate; + /* only send Tlcreate request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TlcreateOpt; + +/* result of 'Tlcreate' 9p request */ +typedef struct TlcreateRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TlcreateRes; + +/* options for 'Tsymlink' 9p request */ +typedef struct TsymlinkOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* low-level variant of directory where symlink shall be created */ + uint32_t fid; + /* high-level variant of directory where symlink shall be created */ + const char *atPath; + /* name of symlink (required) */ + const char *name; + /* where symlink will point to (required) */ + const char *symtgt; + /* effective group ID of caller */ + uint32_t gid; + /* data being received from 9p server as 'Rsymlink' response (optional) */ + struct { + v9fs_qid *qid; + } rsymlink; + /* only send Tsymlink request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TsymlinkOpt; + +/* result of 'Tsymlink' 9p request */ +typedef struct TsymlinkRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TsymlinkRes; + +/* options for 'Tlink' 9p request */ +typedef struct TlinkOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* low-level variant of directory where hard link shall be created */ + uint32_t dfid; + /* high-level variant of directory where hard link shall be created */ + const char *atPath; + /* low-level variant of target referenced by new hard link */ + uint32_t fid; + /* high-level variant of target referenced by new hard link */ + const char *toPath; + /* name of hard link (required) */ + const char *name; + /* only send Tlink request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TlinkOpt; + +/* result of 'Tlink' 9p request */ +typedef struct TlinkRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TlinkRes; + +/* options for 'Tunlinkat' 9p request */ +typedef struct TunlinkatOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* low-level variant of directory where name shall be unlinked */ + uint32_t dirfd; + /* high-level variant of directory where name shall be unlinked */ + const char *atPath; + /* name of directory entry to be unlinked (required) */ + const char *name; + /* Linux unlinkat(2) flags */ + uint32_t flags; + /* only send Tunlinkat request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TunlinkatOpt; + +/* result of 'Tunlinkat' 9p request */ +typedef struct TunlinkatRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TunlinkatRes; + +void v9fs_set_allocator(QGuestAllocator *t_alloc); +void v9fs_memwrite(P9Req *req, const void *addr, size_t len); +void v9fs_memskip(P9Req *req, size_t len); +void v9fs_memread(P9Req *req, void *addr, size_t len); +void v9fs_uint8_read(P9Req *req, uint8_t *val); +void v9fs_uint16_write(P9Req *req, uint16_t val); +void v9fs_uint16_read(P9Req *req, uint16_t *val); +void v9fs_uint32_write(P9Req *req, uint32_t val); +void v9fs_uint64_write(P9Req *req, uint64_t val); +void v9fs_uint32_read(P9Req *req, uint32_t *val); +void v9fs_uint64_read(P9Req *req, uint64_t *val); +uint16_t v9fs_string_size(const char *string); +void v9fs_string_write(P9Req *req, const char *string); +void v9fs_string_read(P9Req *req, uint16_t *len, char **string); +P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, + uint16_t tag); +void v9fs_req_send(P9Req *req); +void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len); +void v9fs_req_recv(P9Req *req, uint8_t id); +void v9fs_req_free(P9Req *req); +void v9fs_rlerror(P9Req *req, uint32_t *err); +TVersionRes v9fs_tversion(TVersionOpt); +void v9fs_rversion(P9Req *req, uint16_t *len, char **version); +TAttachRes v9fs_tattach(TAttachOpt); +void v9fs_rattach(P9Req *req, v9fs_qid *qid); +TWalkRes v9fs_twalk(TWalkOpt opt); +void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid); +TGetAttrRes v9fs_tgetattr(TGetAttrOpt); +void v9fs_rgetattr(P9Req *req, v9fs_attr *attr); +TReadDirRes v9fs_treaddir(TReadDirOpt); +void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, + struct V9fsDirent **entries); +void v9fs_free_dirents(struct V9fsDirent *e); +TLOpenRes v9fs_tlopen(TLOpenOpt); +void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit); +TWriteRes v9fs_twrite(TWriteOpt); +void v9fs_rwrite(P9Req *req, uint32_t *count); +TFlushRes v9fs_tflush(TFlushOpt); +void v9fs_rflush(P9Req *req); +TMkdirRes v9fs_tmkdir(TMkdirOpt); +void v9fs_rmkdir(P9Req *req, v9fs_qid *qid); +TlcreateRes v9fs_tlcreate(TlcreateOpt); +void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit); +TsymlinkRes v9fs_tsymlink(TsymlinkOpt); +void v9fs_rsymlink(P9Req *req, v9fs_qid *qid); +TlinkRes v9fs_tlink(TlinkOpt); +void v9fs_rlink(P9Req *req); +TunlinkatRes v9fs_tunlinkat(TunlinkatOpt); +void v9fs_runlinkat(P9Req *req); + +#endif diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c index f51f0635cc0c..186fcc1141ad 100644 --- a/tests/qtest/libqos/virtio-9p.c +++ b/tests/qtest/libqos/virtio-9p.c @@ -22,7 +22,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "standard-headers/linux/virtio_ids.h" #include "virtio-9p.h" @@ -31,7 +31,7 @@ static QGuestAllocator *alloc; static char *local_test_path; -/* Concatenates the passed 2 pathes. Returned result must be freed. */ +/* Concatenates the passed 2 paths. Returned result must be freed. */ static char *concat_path(const char* a, const char* b) { return g_build_filename(a, b, NULL); @@ -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); @@ -211,6 +211,7 @@ static void *virtio_9p_pci_create(void *pci_bus, QGuestAllocator *t_alloc, * variable arguments of this function to this * replacement string */ +G_GNUC_PRINTF(3, 4) static void regex_replace(GString *haystack, const char *pattern, const char *replace_fmt, ...) { diff --git a/tests/qtest/libqos/virtio-balloon.c b/tests/qtest/libqos/virtio-balloon.c index a3da5c234d49..29b5d175845a 100644 --- a/tests/qtest/libqos/virtio-balloon.c +++ b/tests/qtest/libqos/virtio-balloon.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "qgraph.h" #include "virtio-balloon.h" diff --git a/tests/qtest/libqos/virtio-blk.c b/tests/qtest/libqos/virtio-blk.c index 5da02591bcc2..ee4943f32b99 100644 --- a/tests/qtest/libqos/virtio-blk.c +++ b/tests/qtest/libqos/virtio-blk.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "standard-headers/linux/virtio_blk.h" #include "qgraph.h" diff --git a/tests/qtest/libqos/virtio-gpio.c b/tests/qtest/libqos/virtio-gpio.c new file mode 100644 index 000000000000..f22d7b5eb572 --- /dev/null +++ b/tests/qtest/libqos/virtio-gpio.c @@ -0,0 +1,172 @@ +/* + * 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 " + "-global virtio-mmio.force-legacy=false"; + 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 000000000000..f11d41bd1946 --- /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-iommu.c b/tests/qtest/libqos/virtio-iommu.c index 18cba4ca36b6..afc7d14e9a60 100644 --- a/tests/qtest/libqos/virtio-iommu.c +++ b/tests/qtest/libqos/virtio-iommu.c @@ -12,7 +12,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "qgraph.h" #include "virtio-iommu.h" diff --git a/tests/qtest/libqos/virtio-mmio.c b/tests/qtest/libqos/virtio-mmio.c index 75efda30299a..bd0b1d890b58 100644 --- a/tests/qtest/libqos/virtio-mmio.c +++ b/tests/qtest/libqos/virtio-mmio.c @@ -8,11 +8,11 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #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-net.c b/tests/qtest/libqos/virtio-net.c index 1cae07f60d6c..2ac73ac0b416 100644 --- a/tests/qtest/libqos/virtio-net.c +++ b/tests/qtest/libqos/virtio-net.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "qgraph.h" #include "virtio-net.h" diff --git a/tests/qtest/libqos/virtio-pci.c b/tests/qtest/libqos/virtio-pci.c index cd3c0f5bf335..485b8f6b7e05 100644 --- a/tests/qtest/libqos/virtio-pci.c +++ b/tests/qtest/libqos/virtio-pci.c @@ -8,12 +8,12 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "virtio.h" #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-rng.c b/tests/qtest/libqos/virtio-rng.c index 2e09dd7c48cb..078e3abaa72a 100644 --- a/tests/qtest/libqos/virtio-rng.c +++ b/tests/qtest/libqos/virtio-rng.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "qgraph.h" #include "virtio-rng.h" diff --git a/tests/qtest/libqos/virtio-scsi.c b/tests/qtest/libqos/virtio-scsi.c index 5644e32fc319..c4d046142012 100644 --- a/tests/qtest/libqos/virtio-scsi.c +++ b/tests/qtest/libqos/virtio-scsi.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "standard-headers/linux/virtio_ids.h" #include "qgraph.h" diff --git a/tests/qtest/libqos/virtio-serial.c b/tests/qtest/libqos/virtio-serial.c index ee34afd95ad8..1d689c3e38fc 100644 --- a/tests/qtest/libqos/virtio-serial.c +++ b/tests/qtest/libqos/virtio-serial.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qemu/module.h" #include "qgraph.h" #include "virtio-serial.h" diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c index 6fe7bf9555fc..410513225f4d 100644 --- a/tests/qtest/libqos/virtio.c +++ b/tests/qtest/libqos/virtio.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "qemu/bswap.h" -#include "libqtest.h" +#include "../libqtest.h" #include "virtio.h" #include "standard-headers/linux/virtio_config.h" #include "standard-headers/linux/virtio_ring.h" @@ -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; @@ -260,6 +262,8 @@ void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq, /* vq->used->flags */ qvirtio_writew(vq->vdev, qts, vq->used, 0); + /* vq->used->idx */ + qvirtio_writew(vq->vdev, qts, vq->used + 2, 0); /* vq->used->avail_event */ qvirtio_writew(vq->vdev, qts, vq->used + 2 + sizeof(struct vring_used_elem) * vq->size, 0); diff --git a/tests/qtest/libqos/virtio.h b/tests/qtest/libqos/virtio.h index b8bd06e1b851..7adc7cbd1050 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/libqos/x86_64_pc-machine.c b/tests/qtest/libqos/x86_64_pc-machine.c index ad96742a92d6..dce0c9463a47 100644 --- a/tests/qtest/libqos/x86_64_pc-machine.c +++ b/tests/qtest/libqos/x86_64_pc-machine.c @@ -17,7 +17,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "../libqtest.h" #include "qgraph.h" #include "pci-pc.h" #include "qemu/module.h" diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h index b0838b9e0e71..851724cbcb8d 100644 --- a/tests/qtest/libqtest-single.h +++ b/tests/qtest/libqtest-single.h @@ -11,9 +11,13 @@ #ifndef LIBQTEST_SINGLE_H #define LIBQTEST_SINGLE_H -#include "libqos/libqtest.h" +#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 dc5566ccfd60..5cb38f90da19 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -16,25 +16,38 @@ #include "qemu/osdep.h" +#ifndef _WIN32 #include #include #include +#endif /* _WIN32 */ +#ifdef __linux__ +#include +#endif /* __linux__ */ -#include "libqos/libqtest.h" -#include "qemu-common.h" +#include "libqtest.h" +#include "libqmp.h" #include "qemu/ctype.h" #include "qemu/cutils.h" -#include "qapi/error.h" -#include "qapi/qmp/json-parser.h" +#include "qemu/sockets.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/qlist.h" #include "qapi/qmp/qstring.h" #define MAX_IRQ 256 -#define SOCKET_TIMEOUT 50 -#define SOCKET_MAX_FDS 16 +#ifndef _WIN32 +# define SOCKET_TIMEOUT 50 +# define CMD_EXEC "exec " +# define DEV_STDERR "/dev/fd/2" +# define DEV_NULL "/dev/null" +#else +# define SOCKET_TIMEOUT 50000 +# define CMD_EXEC "" +# define DEV_STDERR "2" +# define DEV_NULL "nul" +#endif typedef void (*QTestSendFn)(QTestState *s, const char *buf); typedef void (*ExternalSendFn)(void *s, const char *buf); @@ -58,6 +71,9 @@ struct QTestState int qmp_fd; pid_t qemu_pid; /* our child QEMU process */ int wstatus; +#ifdef _WIN32 + DWORD exit_code; +#endif int expected_status; bool big_endian; bool irq_level[MAX_IRQ]; @@ -67,7 +83,7 @@ struct QTestState }; static GHookList abrt_hooks; -static struct sigaction sigact_old; +static void (*sighandler_old)(int); static int qtest_query_target_endianness(QTestState *s); @@ -91,14 +107,22 @@ static int socket_accept(int sock) struct sockaddr_un addr; socklen_t addrlen; int ret; + /* + * timeout unit of blocking receive calls is different among platfoms. + * It's in seconds on non-Windows platforms but milliseconds on Windows. + */ +#ifndef _WIN32 struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT, .tv_usec = 0 }; +#else + DWORD timeout = SOCKET_TIMEOUT; +#endif if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout))) { fprintf(stderr, "%s failed to set SO_RCVTIMEO: %s\n", __func__, strerror(errno)); - close(sock); + closesocket(sock); return -1; } @@ -109,7 +133,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; } @@ -119,10 +143,18 @@ bool qtest_probe_child(QTestState *s) pid_t pid = s->qemu_pid; if (pid != -1) { +#ifndef _WIN32 pid = waitpid(pid, &s->wstatus, WNOHANG); if (pid == 0) { return true; } +#else + GetExitCodeProcess((HANDLE)pid, &s->exit_code); + if (s->exit_code == STILL_ACTIVE) { + return true; + } + CloseHandle((HANDLE)pid); +#endif s->qemu_pid = -1; } return false; @@ -133,24 +165,14 @@ void qtest_set_expected_status(QTestState *s, int status) s->expected_status = status; } -void qtest_kill_qemu(QTestState *s) +static void qtest_check_status(QTestState *s) { - pid_t pid = s->qemu_pid; - int wstatus; - - /* Skip wait if qtest_probe_child already reaped. */ - if (pid != -1) { - kill(pid, SIGTERM); - TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0)); - assert(pid == s->qemu_pid); - s->qemu_pid = -1; - } - /* * Check whether qemu exited with expected exit status; anything else is * fishy and should be logged with as much detail as possible. */ - wstatus = s->wstatus; +#ifndef _WIN32 + int wstatus = s->wstatus; if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != s->expected_status) { fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU " "process but encountered exit status %d (expected %d)\n", @@ -166,6 +188,50 @@ void qtest_kill_qemu(QTestState *s) __FILE__, __LINE__, sig, signame, dump); abort(); } +#else + if (s->exit_code != s->expected_status) { + fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU " + "process but encountered exit status %ld (expected %d)\n", + __FILE__, __LINE__, s->exit_code, s->expected_status); + abort(); + } +#endif +} + +void qtest_wait_qemu(QTestState *s) +{ +#ifndef _WIN32 + pid_t pid; + + pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0)); + assert(pid == s->qemu_pid); +#else + DWORD ret; + + ret = WaitForSingleObject((HANDLE)s->qemu_pid, INFINITE); + assert(ret == WAIT_OBJECT_0); + GetExitCodeProcess((HANDLE)s->qemu_pid, &s->exit_code); + CloseHandle((HANDLE)s->qemu_pid); +#endif + + qtest_check_status(s); +} + +void qtest_kill_qemu(QTestState *s) +{ + /* Skip wait if qtest_probe_child() already reaped */ + if (s->qemu_pid != -1) { +#ifndef _WIN32 + kill(s->qemu_pid, SIGTERM); +#else + TerminateProcess((HANDLE)s->qemu_pid, s->expected_status); +#endif + qtest_wait_qemu(s); + s->qemu_pid = -1; + return; + } + + qtest_check_status(s); } static void kill_qemu_hook_func(void *s) @@ -180,20 +246,12 @@ static void sigabrt_handler(int signo) static void setup_sigabrt_handler(void) { - struct sigaction sigact; - - /* Catch SIGABRT to clean up on g_assert() failure */ - sigact = (struct sigaction){ - .sa_handler = sigabrt_handler, - .sa_flags = SA_RESETHAND, - }; - sigemptyset(&sigact.sa_mask); - sigaction(SIGABRT, &sigact, &sigact_old); + sighandler_old = signal(SIGABRT, sigabrt_handler); } static void cleanup_sigabrt_handler(void) { - sigaction(SIGABRT, &sigact_old, NULL); + signal(SIGABRT, sighandler_old); } static bool hook_list_is_empty(GHookList *hook_list) @@ -201,11 +259,11 @@ static bool hook_list_is_empty(GHookList *hook_list) GHook *hook = g_hook_first_valid(hook_list, TRUE); if (!hook) { - return false; + return true; } g_hook_unref(hook_list, hook); - return true; + return false; } void qtest_add_abrt_handler(GHookFunc fn, const void *data) @@ -252,6 +310,38 @@ static const char *qtest_qemu_binary(void) return qemu_bin; } +#ifdef _WIN32 +static pid_t qtest_create_process(char *cmd) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + BOOL ret; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + ret = CreateProcess(NULL, /* module name */ + cmd, /* command line */ + NULL, /* process handle not inheritable */ + NULL, /* thread handle not inheritable */ + FALSE, /* set handle inheritance to FALSE */ + 0, /* No creation flags */ + NULL, /* use parent's environment block */ + NULL, /* use parent's starting directory */ + &si, /* pointer to STARTUPINFO structure */ + &pi /* pointer to PROCESS_INFORMATION structure */ + ); + if (ret == 0) { + fprintf(stderr, "%s:%d: unable to create a new process (%s)\n", + __FILE__, __LINE__, strerror(GetLastError())); + abort(); + } + + return (pid_t)pi.hProcess; +} +#endif /* _WIN32 */ + QTestState *qtest_init_without_qmp_handshake(const char *extra_args) { QTestState *s; @@ -260,11 +350,16 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) gchar *qmp_socket_path; gchar *command; const char *qemu_binary = qtest_qemu_binary(); + const char *trace = g_getenv("QTEST_TRACE"); + g_autofree char *tracearg = trace ? + g_strdup_printf("-trace %s ", trace) : g_strdup(""); 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 @@ -274,6 +369,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) unlink(socket_path); unlink(qmp_socket_path); + socket_init(); sock = init_socket(socket_path); qmpsock = init_socket(qmp_socket_path); @@ -282,15 +378,16 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) qtest_add_abrt_handler(kill_qemu_hook_func, s); - command = g_strdup_printf("exec %s " + command = g_strdup_printf(CMD_EXEC "%s %s" "-qtest unix:%s " "-qtest-log %s " "-chardev socket,path=%s,id=char0 " "-mon chardev=char0,mode=control " "-display none " "%s" - " -accel qtest", qemu_binary, socket_path, - getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null", + " -accel qtest", + qemu_binary, tracearg, socket_path, + getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL, qmp_socket_path, extra_args ?: ""); @@ -299,14 +396,32 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) s->pending_events = NULL; s->wstatus = 0; s->expected_status = 0; +#ifndef _WIN32 s->qemu_pid = fork(); if (s->qemu_pid == 0) { +#ifdef __linux__ + /* + * Although we register a ABRT handler to kill off QEMU + * when g_assert() triggers, we want an extra safety + * net. The QEMU process might be non-functional and + * thus not have responded to SIGTERM. The test script + * might also have crashed with SEGV, in which case the + * cleanup handlers won't ever run. + * + * This PR_SET_PDEATHSIG setup will ensure any remaining + * QEMU will get terminated with SIGKILL in these cases. + */ + prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); +#endif /* __linux__ */ if (!g_setenv("QEMU_AUDIO_DRV", "none", true)) { exit(1); } execlp("/bin/sh", "sh", "-c", command, NULL); exit(1); } +#else + s->qemu_pid = qtest_create_process(command); +#endif /* _WIN32 */ g_free(command); s->fd = socket_accept(sock); @@ -325,9 +440,19 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) s->irq_level[i] = false; } + /* + * Stopping QEMU for debugging is not supported on Windows. + * + * Using DebugActiveProcess() API can suspend the QEMU process, + * but gdb cannot attach to the process. Using the undocumented + * NtSuspendProcess() can suspend the QEMU process and gdb can + * attach to the process, but gdb cannot resume it. + */ +#ifndef _WIN32 if (getenv("QTEST_STOP")) { kill(s->qemu_pid, SIGSTOP); } +#endif /* ask endianness of the target */ @@ -373,12 +498,15 @@ 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); + socket_init(); sock_fd_init = init_socket(sock_path); qts = qtest_initf("-chardev socket,id=s0,path=%s -serial chardev:s0 %s", @@ -400,8 +528,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) { @@ -415,21 +543,9 @@ void qtest_quit(QTestState *s) static void socket_send(int fd, const char *buf, size_t size) { - size_t offset; + ssize_t res = qemu_send_full(fd, buf, size); - offset = 0; - while (offset < size) { - ssize_t len; - - len = write(fd, buf + offset, size - offset); - if (len == -1 && errno == EINTR) { - continue; - } - - g_assert_cmpint(len, >, 0); - - offset += len; - } + assert(res == size); } static void qtest_client_socket_send(QTestState *s, const char *buf) @@ -449,40 +565,6 @@ static void G_GNUC_PRINTF(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...) g_free(str); } -/* Sends a message and file descriptors to the socket. - * It's needed for qmp-commands like getfd/add-fd */ -static void socket_send_fds(int socket_fd, int *fds, size_t fds_num, - const char *buf, size_t buf_size) -{ - ssize_t ret; - struct msghdr msg = { 0 }; - char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)] = { 0 }; - size_t fdsize = sizeof(int) * fds_num; - struct cmsghdr *cmsg; - struct iovec iov = { .iov_base = (char *)buf, .iov_len = buf_size }; - - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - if (fds && fds_num > 0) { - g_assert_cmpuint(fds_num, <, SOCKET_MAX_FDS); - - msg.msg_control = control; - msg.msg_controllen = CMSG_SPACE(fdsize); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(fdsize); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - memcpy(CMSG_DATA(cmsg), fds, fdsize); - } - - do { - ret = sendmsg(socket_fd, &msg, 0); - } while (ret < 0 && errno == EINTR); - g_assert_cmpint(ret, >, 0); -} - static GString *qtest_client_socket_recv_line(QTestState *s) { GString *line; @@ -493,7 +575,7 @@ static GString *qtest_client_socket_recv_line(QTestState *s) ssize_t len; char buffer[1024]; - len = read(s->fd, buffer, sizeof(buffer)); + len = recv(s->fd, buffer, sizeof(buffer), 0); if (len == -1 && errno == EINTR) { continue; } @@ -577,59 +659,6 @@ static int qtest_query_target_endianness(QTestState *s) return big_endian; } -typedef struct { - JSONMessageParser parser; - QDict *response; -} QMPResponseParser; - -static void qmp_response(void *opaque, QObject *obj, Error *err) -{ - QMPResponseParser *qmp = opaque; - - assert(!obj != !err); - - if (err) { - error_prepend(&err, "QMP JSON response parsing failed: "); - error_report_err(err); - abort(); - } - - g_assert(!qmp->response); - qmp->response = qobject_to(QDict, obj); - g_assert(qmp->response); -} - -QDict *qmp_fd_receive(int fd) -{ - QMPResponseParser qmp; - bool log = getenv("QTEST_LOG") != NULL; - - qmp.response = NULL; - json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL); - while (!qmp.response) { - ssize_t len; - char c; - - len = read(fd, &c, 1); - if (len == -1 && errno == EINTR) { - continue; - } - - if (len == -1 || len == 0) { - fprintf(stderr, "Broken pipe\n"); - abort(); - } - - if (log) { - len = write(2, &c, 1); - } - json_message_parser_feed(&qmp.parser, &c, 1); - } - json_message_parser_destroy(&qmp.parser); - - return qmp.response; -} - QDict *qtest_qmp_receive(QTestState *s) { while (true) { @@ -660,9 +689,7 @@ int qtest_socket_server(const char *socket_path) addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); - do { - ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR(bind(sock, (struct sockaddr *)&addr, sizeof(addr))); g_assert_cmpint(ret, !=, -1); ret = listen(sock, 1); g_assert_cmpint(ret, !=, -1); @@ -670,68 +697,20 @@ int qtest_socket_server(const char *socket_path) return sock; } -/** - * Allow users to send a message without waiting for the reply, - * in the case that they choose to discard all replies up until - * a particular EVENT is received. - */ -void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, - const char *fmt, va_list ap) -{ - QObject *qobj; - - /* Going through qobject ensures we escape strings properly */ - qobj = qobject_from_vjsonf_nofail(fmt, ap); - - /* No need to send anything for an empty QObject. */ - if (qobj) { - int log = getenv("QTEST_LOG") != NULL; - GString *str = qobject_to_json(qobj); - - /* - * BUG: QMP doesn't react to input until it sees a newline, an - * object, or an array. Work-around: give it a newline. - */ - g_string_append_c(str, '\n'); - - if (log) { - fprintf(stderr, "%s", str->str); - } - /* Send QMP request */ - if (fds && fds_num > 0) { - socket_send_fds(fd, fds, fds_num, str->str, str->len); - } else { - socket_send(fd, str->str, str->len); - } - - g_string_free(str, true); - qobject_unref(qobj); - } -} - -void qmp_fd_vsend(int fd, const char *fmt, va_list ap) -{ - qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); -} - +#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); -} - -QDict *qmp_fdv(int fd, const char *fmt, va_list ap) -{ - qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); - - return qmp_fd_receive(fd); + 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) { @@ -740,6 +719,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) { @@ -749,26 +729,7 @@ QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap) return qtest_qmp_receive(s); } -QDict *qmp_fd(int fd, const char *fmt, ...) -{ - va_list ap; - QDict *response; - - va_start(ap, fmt); - response = qmp_fdv(fd, fmt, ap); - va_end(ap); - return response; -} - -void qmp_fd_send(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - qmp_fd_vsend(fd, fmt, ap); - va_end(ap); -} - +#ifndef _WIN32 QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, ...) { @@ -780,6 +741,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, ...) { @@ -801,27 +763,6 @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...) va_end(ap); } -void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap) -{ - bool log = getenv("QTEST_LOG") != NULL; - char *str = g_strdup_vprintf(fmt, ap); - - if (log) { - fprintf(stderr, "%s", str); - } - socket_send(fd, str, strlen(str)); - g_free(str); -} - -void qmp_fd_send_raw(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - qmp_fd_vsend_raw(fd, fmt, ap); - va_end(ap); -} - void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...) { va_list ap; @@ -1497,6 +1438,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; @@ -1516,6 +1458,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. @@ -1533,34 +1476,20 @@ void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd) * * {"return": {}} */ -void qtest_qmp_device_del(QTestState *qts, const char *id) +void qtest_qmp_device_del_send(QTestState *qts, const char *id) { - QDict *rsp; - - rsp = qtest_qmp(qts, "{'execute': 'device_del', 'arguments': {'id': %s}}", - id); - + QDict *rsp = qtest_qmp(qts, "{'execute': 'device_del', " + "'arguments': {'id': %s}}", id); + g_assert(rsp); g_assert(qdict_haskey(rsp, "return")); + g_assert(!qdict_haskey(rsp, "error")); qobject_unref(rsp); - qtest_qmp_eventwait(qts, "DEVICE_DELETED"); -} - -bool qmp_rsp_is_err(QDict *rsp) -{ - QDict *error = qdict_get_qdict(rsp, "error"); - qobject_unref(rsp); - return !!error; } -void qmp_expect_error_and_unref(QDict *rsp, const char *class) +void qtest_qmp_device_del(QTestState *qts, const char *id) { - QDict *error = qdict_get_qdict(rsp, "error"); - - g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, class); - g_assert_nonnull(qdict_get_try_str(error, "desc")); - g_assert(!qdict_haskey(rsp, "return")); - - qobject_unref(rsp); + qtest_qmp_device_del_send(qts, id); + qtest_qmp_eventwait(qts, "DEVICE_DELETED"); } static void qtest_client_set_tx_handler(QTestState *s, @@ -1616,7 +1545,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; @@ -1632,3 +1561,27 @@ void qtest_client_inproc_recv(void *opaque, const char *str) g_string_append(qts->rx, str); return; } + +void qtest_qom_set_bool(QTestState *s, const char *path, const char *property, + bool value) +{ + QDict *r; + + r = qtest_qmp(s, "{ 'execute': 'qom-set', 'arguments': " + "{ 'path': %s, 'property': %s, 'value': %i } }", + path, property, value); + qobject_unref(r); +} + +bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property) +{ + QDict *r; + bool b; + + r = qtest_qmp(s, "{ 'execute': 'qom-get', 'arguments': " + "{ 'path': %s, 'property': %s } }", path, property); + b = qdict_get_bool(r, "return"); + qobject_unref(r); + + return b; +} diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqtest.h similarity index 94% rename from tests/qtest/libqos/libqtest.h rename to tests/qtest/libqtest.h index 552667f17e37..fcf1c3c3b36f 100644 --- a/tests/qtest/libqos/libqtest.h +++ b/tests/qtest/libqtest.h @@ -19,6 +19,7 @@ #include "qapi/qmp/qobject.h" #include "qapi/qmp/qdict.h" +#include "libqmp.h" typedef struct QTestState QTestState; @@ -74,6 +75,15 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args); */ QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd); +/** + * qtest_wait_qemu: + * @s: #QTestState instance to operate on. + * + * Wait for the QEMU process to terminate. It is safe to call this function + * multiple times. + */ +void qtest_wait_qemu(QTestState *s); + /** * qtest_kill_qemu: * @s: #QTestState instance to operate on. @@ -93,6 +103,7 @@ void qtest_kill_qemu(QTestState *s); */ void qtest_quit(QTestState *s); +#ifndef _WIN32 /** * qtest_qmp_fds: * @s: #QTestState instance to operate on. @@ -107,6 +118,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: @@ -151,6 +163,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. @@ -166,6 +179,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: @@ -180,6 +194,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. @@ -195,6 +210,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: @@ -690,16 +706,6 @@ void qtest_remove_abrt_handler(void *data); void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...) G_GNUC_PRINTF(2, 3); -QDict *qmp_fd_receive(int fd); -void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, - const char *fmt, va_list ap) G_GNUC_PRINTF(4, 0); -void qmp_fd_vsend(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); -void qmp_fd_send(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); -void qmp_fd_send_raw(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); -void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); -QDict *qmp_fdv(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); -QDict *qmp_fd(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); - /** * qtest_cb_for_every_machine: * @cb: Pointer to the callback function @@ -730,7 +736,7 @@ bool qtest_has_device(const char *device); * qtest_qmp_device_add_qdict: * @qts: QTestState instance to operate on * @drv: Name of the device that should be added - * @arguments: QDict with properties for the device to intialize + * @arguments: QDict with properties for the device to initialize * * Generic hot-plugging test via the device_add QMP command with properties * supplied in form of QDict. Use NULL for empty properties list. @@ -752,6 +758,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 @@ -761,33 +768,26 @@ 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: + * qtest_qmp_device_del_send: * @qts: QTestState instance to operate on * @id: Identification string * * Generic hot-unplugging test via the device_del QMP command. */ -void qtest_qmp_device_del(QTestState *qts, const char *id); +void qtest_qmp_device_del_send(QTestState *qts, const char *id); /** - * qmp_rsp_is_err: - * @rsp: QMP response to check for error - * - * Test @rsp for error and discard @rsp. - * Returns 'true' if there is error in @rsp and 'false' otherwise. - */ -bool qmp_rsp_is_err(QDict *rsp); - -/** - * qmp_expect_error_and_unref: - * @rsp: QMP response to check for error - * @class: an error class + * qtest_qmp_device_del: + * @qts: QTestState instance to operate on + * @id: Identification string * - * Assert the response has the given error class and discard @rsp. + * Generic hot-unplugging test via the device_del QMP command. + * Waiting for command completion event. */ -void qmp_expect_error_and_unref(QDict *rsp, const char *class); +void qtest_qmp_device_del(QTestState *qts, const char *id); /** * qtest_probe_child: @@ -810,4 +810,26 @@ QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch, void (*send)(void*, const char*)); void qtest_client_inproc_recv(void *opaque, const char *str); + +/** + * qtest_qom_set_bool: + * @s: QTestState instance to operate on. + * @path: Path to the property being set. + * @property: Property being set. + * @value: Value to set the property. + * + * Set the property with passed in value. + */ +void qtest_qom_set_bool(QTestState *s, const char *path, const char *property, + bool value); + +/** + * qtest_qom_get_bool: + * @s: QTestState instance to operate on. + * @path: Path to the property being retrieved. + * @property: Property from where the value is being retrieved. + * + * Returns: Value retrieved from property. + */ +bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property); #endif diff --git a/tests/qtest/lpc-ich9-test.c b/tests/qtest/lpc-ich9-test.c index fe0bef998075..8ac95b89f729 100644 --- a/tests/qtest/lpc-ich9-test.c +++ b/tests/qtest/lpc-ich9-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" static void test_lp1878642_pci_bus_get_irq_level_assert(void) { diff --git a/tests/qtest/m48t59-test.c b/tests/qtest/m48t59-test.c index 6db3234100a3..843d2ced8e25 100644 --- a/tests/qtest/m48t59-test.c +++ b/tests/qtest/m48t59-test.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #define RTC_SECONDS 0x9 #define RTC_MINUTES 0xa @@ -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 138101b46ac2..31cc0bfb011b 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -12,9 +12,8 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" @@ -55,6 +54,7 @@ static struct arch2cpu cpus_map[] = { { "riscv64", "rv64" }, { "riscv32", "rv32" }, { "rx", "rx62n" }, + { "loongarch64", "la464"}, }; static const char *get_cpu_model_by_arch(const char *arch) @@ -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/megasas-test.c b/tests/qtest/megasas-test.c index eae70ff95f9c..d6796b9bd74d 100644 --- a/tests/qtest/megasas-test.c +++ b/tests/qtest/megasas-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/bswap.h" #include "qemu/module.h" #include "libqos/qgraph.h" diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index d25f82bb5ac0..f0ebb5fac603 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -1,9 +1,3 @@ -# All QTests for now are POSIX-only, but the dependencies are -# really in libqtest, not in the testcases themselves. -if not config_host.has_key('CONFIG_POSIX') - subdir_done() -endif - slow_qtests = { 'ahci-test' : 60, 'bios-tables-test' : 120, @@ -17,13 +11,7 @@ slow_qtests = { 'test-hmp' : 120, } -qtests_generic = \ - (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ - (config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \ - (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ - (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ - (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \ - [ +qtests_generic = [ 'cdrom-test', 'device-introspect-test', 'machine-none-test', @@ -32,6 +20,7 @@ qtests_generic = \ 'qom-test', 'test-hmp', 'qos-test', + 'readconfig-test', ] if config_host.has_key('CONFIG_MODULES') qtests_generic += [ 'modules-test' ] @@ -41,9 +30,17 @@ qtests_pci = \ (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) + \ (config_all_devices.has_key('CONFIG_IVSHMEM_DEVICE') ? ['ivshmem-test'] : []) +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'] : []) + \ @@ -67,14 +64,21 @@ qtests_i386 = \ (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) + \ (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \ (config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \ + (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ + (config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \ + (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ + (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 \ slirp.found() ? ['virtio-net-failover'] : []) + \ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ qtests_pci + \ + qtests_cxl + \ ['fdc-test', 'ide-test', 'hd-geo-test', @@ -90,8 +94,7 @@ qtests_i386 = \ 'vmgenid-test', 'migration-test', 'test-x86-cpuid-compat', - 'numa-test', - 'test-filter-redirector' + 'numa-test' ] if dbus_display @@ -99,14 +102,13 @@ if dbus_display endif dbus_daemon = find_program('dbus-daemon', required: false) -if dbus_daemon.found() and config_host.has_key('GDBUS_CODEGEN') +if dbus_daemon.found() and gdbus_codegen.found() # Temporarily disabled due to Patchew failures: #qtests_i386 += ['dbus-vmstate-test'] dbus_vmstate1 = custom_target('dbus-vmstate description', output: ['dbus-vmstate1.h', 'dbus-vmstate1.c'], input: meson.project_source_root() / 'backends/dbus-vmstate1.xml', - command: [config_host['GDBUS_CODEGEN'], - '@INPUT@', + command: [gdbus_codegen, '@INPUT@', '--interface-prefix', 'org.qemu', '--generate-c-code', '@BASENAME@']).to_list() else @@ -116,48 +118,34 @@ 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'] : []) -qtests_mips64 = \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + \ - (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ - (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) - -qtests_mips64el = \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + \ - (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ - (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) +qtests_mipsel = qtests_mips +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'] : []) + \ @@ -178,13 +166,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 = \ @@ -199,7 +185,8 @@ qtests_npcm7xx = \ (slirp.found() ? ['npcm7xx_emc-test'] : []) qtests_aspeed = \ ['aspeed_hace-test', - 'aspeed_smc-test'] + 'aspeed_smc-test', + 'aspeed_gpio-test'] qtests_arm = \ (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \ @@ -223,7 +210,8 @@ qtests_aarch64 = \ ['arm-cpu-features', 'numa-test', 'boot-serial-test', - 'migration-test'] + 'migration-test', + 'bcm2835-dma-test'] qtests_s390x = \ (slirp.found() ? ['pxe-test', 'test-netfilter'] : []) + \ @@ -242,7 +230,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', @@ -270,23 +257,38 @@ 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 -qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test.c')) +if have_vhost_user + qos_test_ss.add(files('vhost-user-test.c')) +endif if have_tools and have_vhost_user_blk_server qos_test_ss.add(files('vhost-user-blk-test.c')) endif tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c'] +migration_files = [files('migration-helpers.c')] +if gnutls.found() + migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls] + + if tasn1.found() + migration_files += [files('../unit/crypto-tls-x509-helpers.c', + '../unit/pkix_asn1_tab.c'), tasn1] + endif +endif + qtests = { 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], 'cdrom-test': files('boot-sector.c'), 'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1, 'erst-test': files('erst-test.c'), 'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'], - 'migration-test': files('migration-helpers.c'), + 'migration-test': migration_files, 'pxe-test': files('boot-sector.c'), 'qos-test': [chardev, io, qos_test_ss.apply(config_host, strict: false).sources()], 'tpm-crb-swtpm-test': [io, tpmemu_files], @@ -298,8 +300,14 @@ qtests = { 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), } +gvnc = dependency('gvnc-1.0', required: false) +if gvnc.found() + qtests += {'vnc-display-test': [gvnc]} + qtests_generic += [ 'vnc-display-test' ] +endif + if dbus_display -qtests += {'dbus-display-test': [dbus_display1, gio]} + qtests += {'dbus-display-test': [dbus_display1, gio]} endif qtest_executables = {} diff --git a/tests/qtest/microbit-test.c b/tests/qtest/microbit-test.c index 2b255579dfdd..4bc267020bc5 100644 --- a/tests/qtest/microbit-test.c +++ b/tests/qtest/microbit-test.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "exec/hwaddr.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "hw/arm/nrf51.h" #include "hw/char/nrf51_uart.h" @@ -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 4ee26014b783..f6f3c6680f57 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -15,6 +15,14 @@ #include "migration-helpers.h" +/* + * Number of seconds we wait when looking for migration + * status changes, to avoid test suite hanging forever + * when things go wrong. Needs to be higher enough to + * avoid false positives on loaded hosts. + */ +#define MIGRATION_STATUS_WAIT_TIMEOUT 120 + bool got_stop; static void check_stop_event(QTestState *who) @@ -26,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. */ @@ -50,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. @@ -75,6 +85,28 @@ QDict *wait_command(QTestState *who, const char *command, ...) return ret; } +/* + * Execute the qmp command only + */ +QDict *qmp_command(QTestState *who, const char *command, ...) +{ + va_list ap; + QDict *resp, *ret; + + va_start(ap, command); + resp = qtest_vqmp(who, command, ap); + va_end(ap); + + g_assert(!qdict_haskey(resp, "error")); + g_assert(qdict_haskey(resp, "return")); + + ret = qdict_get_qdict(resp, "return"); + qobject_ref(ret); + qobject_unref(resp); + + return ret; +} + /* * Send QMP command "migrate". * Arguments are built from @fmt... (formatted like @@ -107,6 +139,19 @@ QDict *migrate_query(QTestState *who) return wait_command(who, "{ 'execute': 'query-migrate' }"); } +QDict *migrate_query_not_failed(QTestState *who) +{ + const char *status; + QDict *rsp = migrate_query(who); + status = qdict_get_str(rsp, "status"); + if (g_str_equal(status, "failed")) { + g_printerr("query-migrate shows failed migration: %s\n", + qdict_get_str(rsp, "error-desc")); + } + g_assert(!g_str_equal(status, "failed")); + return rsp; +} + /* * Note: caller is responsible to free the returned object via * g_free() after use @@ -153,8 +198,11 @@ static bool check_migration_status(QTestState *who, const char *goal, void wait_for_migration_status(QTestState *who, const char *goal, const char **ungoals) { + g_test_timer_start(); while (!check_migration_status(who, goal, ungoals)) { usleep(1000); + + g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT); } } @@ -165,6 +213,7 @@ void wait_for_migration_complete(QTestState *who) void wait_for_migration_fail(QTestState *from, bool allow_active) { + g_test_timer_start(); QDict *rsp_return; char *status; bool failed; @@ -180,6 +229,8 @@ void wait_for_migration_fail(QTestState *from, bool allow_active) g_assert(result); failed = !strcmp(status, "failed"); g_free(status); + + g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT); } while (!failed); /* Is the machine currently running? */ diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 555adafce129..a188b6278796 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -9,23 +9,30 @@ * See the COPYING file in the top-level directory. * */ -#ifndef MIGRATION_HELPERS_H_ -#define MIGRATION_HELPERS_H_ -#include "libqos/libqtest.h" +#ifndef MIGRATION_HELPERS_H +#define MIGRATION_HELPERS_H + +#include "libqtest.h" 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, ...); +G_GNUC_PRINTF(2, 3) +QDict *qmp_command(QTestState *who, const char *command, ...); + G_GNUC_PRINTF(3, 4) void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...); QDict *migrate_query(QTestState *who); +QDict *migrate_query_not_failed(QTestState *who); void wait_for_migration_status(QTestState *who, const char *goal, const char **ungoals); @@ -34,4 +41,4 @@ void wait_for_migration_complete(QTestState *who); void wait_for_migration_fail(QTestState *from, bool allow_active); -#endif /* MIGRATION_HELPERS_H_ */ +#endif /* MIGRATION_HELPERS_H */ diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 0870656d826d..dbde726adf8c 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qemu/module.h" @@ -23,9 +23,17 @@ #include "qapi/qapi-visit-sockets.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" +#include "crypto/tlscredspsk.h" +#include "qapi/qmp/qlist.h" #include "migration-helpers.h" #include "tests/migration/migration-test.h" +#ifdef CONFIG_GNUTLS +# include "tests/unit/crypto-tls-psk-helpers.h" +# ifdef CONFIG_TASN1 +# include "tests/unit/crypto-tls-x509-helpers.h" +# endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ /* For dirty ring test; so far only x86_64 is supported */ #if defined(__linux__) && defined(HOST_X86_64) @@ -39,8 +47,11 @@ unsigned start_address; unsigned end_address; static bool uffd_feature_thread_id; -/* A downtime where the test really should converge */ -#define CONVERGE_DOWNTIME 1000 +/* + * Dirtylimit stop working if dirty page rate error + * value less than DIRTYLIMIT_TOLERANCE_RANGE + */ +#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ #if defined(__linux__) #include @@ -91,7 +102,7 @@ static bool ufd_version_check(void) #endif -static const char *tmpfs; +static char *tmpfs; /* The boot file modifies memory area in [start_address, end_address) * repeatedly. It outputs a 'B' at a fixed rate while it's still running. @@ -174,7 +185,7 @@ static int64_t read_ram_property_int(QTestState *who, const char *property) QDict *rsp_return, *rsp_ram; int64_t result; - rsp_return = migrate_query(who); + rsp_return = migrate_query_not_failed(who); if (!qdict_haskey(rsp_return, "ram")) { /* Still in setup */ result = 0; @@ -191,7 +202,7 @@ static int64_t read_migrate_property_int(QTestState *who, const char *property) QDict *rsp_return; int64_t result; - rsp_return = migrate_query(who); + rsp_return = migrate_query_not_failed(who); result = qdict_get_try_int(rsp_return, property, 0); qobject_unref(rsp_return); return result; @@ -206,7 +217,7 @@ static void read_blocktime(QTestState *who) { QDict *rsp_return; - rsp_return = migrate_query(who); + rsp_return = migrate_query_not_failed(who); g_assert(qdict_haskey(rsp_return, "postcopy-blocktime")); qobject_unref(rsp_return); } @@ -395,6 +406,20 @@ static void migrate_set_parameter_str(QTestState *who, const char *parameter, migrate_check_parameter_str(who, parameter, value); } +static void migrate_ensure_non_converge(QTestState *who) +{ + /* Can't converge with 1ms downtime + 30 mbs bandwidth limit */ + migrate_set_parameter_int(who, "max-bandwidth", 30 * 1000 * 1000); + migrate_set_parameter_int(who, "downtime-limit", 1); +} + +static void migrate_ensure_converge(QTestState *who) +{ + /* Should converge with 30s downtime + 1 gbs bandwidth limit */ + migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000); + migrate_set_parameter_int(who, "downtime-limit", 30 * 1000); +} + static void migrate_pause(QTestState *who) { QDict *rsp; @@ -474,28 +499,88 @@ typedef struct { bool only_target; /* Use dirty ring if true; dirty logging otherwise */ bool use_dirty_ring; - char *opts_source; - char *opts_target; + const char *opts_source; + const char *opts_target; } MigrateStart; -static MigrateStart *migrate_start_new(void) -{ - MigrateStart *args = g_new0(MigrateStart, 1); +/* + * A hook that runs after the src and dst QEMUs have been + * created, but before the migration is started. This can + * be used to set migration parameters and capabilities. + * + * Returns: NULL, or a pointer to opaque state to be + * later passed to the TestMigrateFinishHook + */ +typedef void * (*TestMigrateStartHook)(QTestState *from, + QTestState *to); - args->opts_source = g_strdup(""); - args->opts_target = g_strdup(""); - return args; -} +/* + * A hook that runs after the migration has finished, + * regardless of whether it succeeded or failed, but + * before QEMU has terminated (unless it self-terminated + * due to migration error) + * + * @opaque is a pointer to state previously returned + * by the TestMigrateStartHook if any, or NULL. + */ +typedef void (*TestMigrateFinishHook)(QTestState *from, + QTestState *to, + void *opaque); -static void migrate_start_destroy(MigrateStart *args) -{ - g_free(args->opts_source); - g_free(args->opts_target); - g_free(args); -} +typedef struct { + /* Optional: fine tune start parameters */ + MigrateStart start; + + /* Required: the URI for the dst QEMU to listen on */ + const char *listen_uri; + + /* + * Optional: the URI for the src QEMU to connect to + * If NULL, then it will query the dst QEMU for its actual + * listening address and use that as the connect address. + * This allows for dynamically picking a free TCP port. + */ + const char *connect_uri; + + /* Optional: callback to run at start to set migration parameters */ + TestMigrateStartHook start_hook; + /* Optional: callback to run at finish to cleanup */ + TestMigrateFinishHook finish_hook; + + /* + * Optional: normally we expect the migration process to complete. + * + * There can be a variety of reasons and stages in which failure + * can happen during tests. + * + * If a failure is expected to happen at time of establishing + * the connection, then MIG_TEST_FAIL will indicate that the dst + * QEMU is expected to stay running and accept future migration + * connections. + * + * If a failure is expected to happen while processing the + * migration stream, then MIG_TEST_FAIL_DEST_QUIT_ERR will indicate + * that the dst QEMU is expected to quit with non-zero exit status + */ + enum { + /* This test should succeed, the default */ + MIG_TEST_SUCCEED = 0, + /* This test should fail, dest qemu should keep alive */ + MIG_TEST_FAIL, + /* This test should fail, dest qemu should fail with abnormal status */ + MIG_TEST_FAIL_DEST_QUIT_ERR, + } result; + + /* Optional: set number of migration passes to wait for */ + unsigned int iterations; + + /* Postcopy specific fields */ + void *postcopy_data; + bool postcopy_preempt; +} MigrateCommon; static int test_migrate_start(QTestState **from, QTestState **to, - const char *uri, MigrateStart **pargs) + const char *uri, MigrateStart *args) { g_autofree gchar *arch_source = NULL; g_autofree gchar *arch_target = NULL; @@ -507,15 +592,12 @@ static int test_migrate_start(QTestState **from, QTestState **to, g_autofree char *shmem_path = NULL; const char *arch = qtest_get_arch(); const char *machine_opts = NULL; - MigrateStart *args = *pargs; const char *memory_size; - int ret = 0; if (args->use_shmem) { if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) { g_test_skip("/dev/shm is not supported"); - ret = -1; - goto out; + return -1; } } @@ -565,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 = ""; } @@ -591,7 +682,8 @@ static int test_migrate_start(QTestState **from, QTestState **to, machine_opts ? " -machine " : "", machine_opts ? machine_opts : "", memory_size, tmpfs, - arch_source, shmem_opts, args->opts_source, + arch_source, shmem_opts, + args->opts_source ? args->opts_source : "", ignore_stderr); if (!args->only_target) { *from = qtest_init(cmd_source); @@ -609,7 +701,8 @@ static int test_migrate_start(QTestState **from, QTestState **to, machine_opts ? machine_opts : "", memory_size, tmpfs, uri, arch_target, shmem_opts, - args->opts_target, ignore_stderr); + args->opts_target ? args->opts_target : "", + ignore_stderr); *to = qtest_init(cmd_target); /* @@ -620,11 +713,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, unlink(shmem_path); } -out: - migrate_start_destroy(args); - /* This tells the caller that this structure is gone */ - *pargs = NULL; - return ret; + return 0; } static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) @@ -661,27 +750,373 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) cleanup("dest_serial"); } +#ifdef CONFIG_GNUTLS +struct TestMigrateTLSPSKData { + char *workdir; + char *workdiralt; + char *pskfile; + char *pskfilealt; +}; + +static void * +test_migrate_tls_psk_start_common(QTestState *from, + QTestState *to, + bool mismatch) +{ + struct TestMigrateTLSPSKData *data = + g_new0(struct TestMigrateTLSPSKData, 1); + QDict *rsp; + + data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs); + data->pskfile = g_strdup_printf("%s/%s", data->workdir, + QCRYPTO_TLS_CREDS_PSKFILE); + 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); + g_mkdir_with_parents(data->workdiralt, 0700); + test_tls_psk_init_alt(data->pskfilealt); + } + + rsp = wait_command(from, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-psk'," + " 'id': 'tlscredspsk0'," + " 'endpoint': 'client'," + " 'dir': %s," + " 'username': 'qemu'} }", + data->workdir); + qobject_unref(rsp); + + rsp = wait_command(to, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-psk'," + " 'id': 'tlscredspsk0'," + " 'endpoint': 'server'," + " 'dir': %s } }", + mismatch ? data->workdiralt : data->workdir); + qobject_unref(rsp); + + migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0"); + migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0"); + + return data; +} + +static void * +test_migrate_tls_psk_start_match(QTestState *from, + QTestState *to) +{ + return test_migrate_tls_psk_start_common(from, to, false); +} + +static void * +test_migrate_tls_psk_start_mismatch(QTestState *from, + QTestState *to) +{ + return test_migrate_tls_psk_start_common(from, to, true); +} + +static void +test_migrate_tls_psk_finish(QTestState *from, + QTestState *to, + void *opaque) +{ + struct TestMigrateTLSPSKData *data = opaque; + + test_tls_psk_cleanup(data->pskfile); + if (data->pskfilealt) { + test_tls_psk_cleanup(data->pskfilealt); + } + rmdir(data->workdir); + if (data->workdiralt) { + rmdir(data->workdiralt); + } + + g_free(data->workdiralt); + g_free(data->pskfilealt); + g_free(data->workdir); + g_free(data->pskfile); + g_free(data); +} + +#ifdef CONFIG_TASN1 +typedef struct { + char *workdir; + char *keyfile; + char *cacert; + char *servercert; + char *serverkey; + char *clientcert; + char *clientkey; +} TestMigrateTLSX509Data; + +typedef struct { + bool verifyclient; + bool clientcert; + bool hostileclient; + bool authzclient; + const char *certhostname; + const char *certipaddr; +} TestMigrateTLSX509; + +static void * +test_migrate_tls_x509_start_common(QTestState *from, + QTestState *to, + TestMigrateTLSX509 *args) +{ + TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1); + QDict *rsp; + + data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs); + data->keyfile = g_strdup_printf("%s/key.pem", data->workdir); + + data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir); + data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir); + data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir); + if (args->clientcert) { + data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir); + data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir); + } + + 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); + if (args->clientcert) { + TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq, + args->hostileclient ? + QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME : + QCRYPTO_TLS_TEST_CLIENT_NAME, + data->clientcert); + } + + TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq, + data->servercert, + args->certhostname, + args->certipaddr); + + rsp = wait_command(from, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-x509'," + " 'id': 'tlscredsx509client0'," + " 'endpoint': 'client'," + " 'dir': %s," + " 'sanity-check': true," + " 'verify-peer': true} }", + data->workdir); + qobject_unref(rsp); + migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0"); + if (args->certhostname) { + migrate_set_parameter_str(from, "tls-hostname", args->certhostname); + } + + rsp = wait_command(to, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-x509'," + " 'id': 'tlscredsx509server0'," + " 'endpoint': 'server'," + " 'dir': %s," + " 'sanity-check': true," + " 'verify-peer': %i} }", + data->workdir, args->verifyclient); + qobject_unref(rsp); + migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0"); + + if (args->authzclient) { + rsp = wait_command(to, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'authz-simple'," + " 'id': 'tlsauthz0'," + " 'identity': %s} }", + "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME); + migrate_set_parameter_str(to, "tls-authz", "tlsauthz0"); + } + + return data; +} + +/* + * The normal case: match server's cert hostname against + * whatever host we were telling QEMU to connect to (if any) + */ +static void * +test_migrate_tls_x509_start_default_host(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .certipaddr = "127.0.0.1" + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The unusual case: the server's cert is different from + * the address we're telling QEMU to connect to (if any), + * so we must give QEMU an explicit hostname to validate + */ +static void * +test_migrate_tls_x509_start_override_host(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .certhostname = "qemu.org", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The unusual case: the server's cert is different from + * the address we're telling QEMU to connect to, and so we + * expect the client to reject the server + */ +static void * +test_migrate_tls_x509_start_mismatch_host(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .certipaddr = "10.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +static void * +test_migrate_tls_x509_start_friendly_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .authzclient = true, + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +static void * +test_migrate_tls_x509_start_hostile_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .hostileclient = true, + .authzclient = true, + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The case with no client certificate presented, + * and no server verification + */ +static void * +test_migrate_tls_x509_start_allow_anon_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The case with no client certificate presented, + * and server verification rejecting + */ +static void * +test_migrate_tls_x509_start_reject_anon_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +static void +test_migrate_tls_x509_finish(QTestState *from, + QTestState *to, + void *opaque) +{ + TestMigrateTLSX509Data *data = opaque; + + test_tls_cleanup(data->keyfile); + g_free(data->keyfile); + + unlink(data->cacert); + g_free(data->cacert); + unlink(data->servercert); + g_free(data->servercert); + unlink(data->serverkey); + g_free(data->serverkey); + + if (data->clientcert) { + unlink(data->clientcert); + g_free(data->clientcert); + } + if (data->clientkey) { + unlink(data->clientkey); + g_free(data->clientkey); + } + + rmdir(data->workdir); + g_free(data->workdir); + + g_free(data); +} +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ + static int migrate_postcopy_prepare(QTestState **from_ptr, QTestState **to_ptr, - MigrateStart *args) + MigrateCommon *args) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; - if (test_migrate_start(&from, &to, uri, &args)) { + if (test_migrate_start(&from, &to, uri, &args->start)) { return -1; } + if (args->start_hook) { + args->postcopy_data = args->start_hook(from, to); + } + migrate_set_capability(from, "postcopy-ram", true); migrate_set_capability(to, "postcopy-ram", true); migrate_set_capability(to, "postcopy-blocktime", true); - /* We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - migrate_set_parameter_int(from, "max-bandwidth", 30000000); - migrate_set_parameter_int(from, "downtime-limit", 1); + if (args->postcopy_preempt) { + migrate_set_capability(from, "postcopy-preempt", true); + migrate_set_capability(to, "postcopy-preempt", true); + } + + migrate_ensure_non_converge(from); /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); @@ -696,7 +1131,8 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, return 0; } -static void migrate_postcopy_complete(QTestState *from, QTestState *to) +static void migrate_postcopy_complete(QTestState *from, QTestState *to, + MigrateCommon *args) { wait_for_migration_complete(from); @@ -707,28 +1143,71 @@ static void migrate_postcopy_complete(QTestState *from, QTestState *to) read_blocktime(to); } + if (args->finish_hook) { + args->finish_hook(from, to, args->postcopy_data); + args->postcopy_data = NULL; + } + test_migrate_end(from, to, true); } -static void test_postcopy(void) +static void test_postcopy_common(MigrateCommon *args) { - MigrateStart *args = migrate_start_new(); QTestState *from, *to; if (migrate_postcopy_prepare(&from, &to, args)) { return; } migrate_postcopy_start(from, to); - migrate_postcopy_complete(from, to); + migrate_postcopy_complete(from, to, args); } -static void test_postcopy_recovery(void) +static void test_postcopy(void) +{ + MigrateCommon args = { }; + + test_postcopy_common(&args); +} + +static void test_postcopy_preempt(void) +{ + MigrateCommon args = { + .postcopy_preempt = true, + }; + + test_postcopy_common(&args); +} + +#ifdef CONFIG_GNUTLS +static void test_postcopy_tls_psk(void) +{ + MigrateCommon args = { + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_postcopy_common(&args); +} + +static void test_postcopy_preempt_tls_psk(void) +{ + MigrateCommon args = { + .postcopy_preempt = true, + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_postcopy_common(&args); +} +#endif + +static void test_postcopy_recovery_common(MigrateCommon *args) { - MigrateStart *args = migrate_start_new(); QTestState *from, *to; g_autofree char *uri = NULL; - args->hide_stderr = true; + /* Always hide errors for postcopy recover tests since they're expected */ + args->start.hide_stderr = true; if (migrate_postcopy_prepare(&from, &to, args)) { return; @@ -781,16 +1260,58 @@ static void test_postcopy_recovery(void) /* Restore the postcopy bandwidth to unlimited */ migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0); - migrate_postcopy_complete(from, to); + migrate_postcopy_complete(from, to, args); +} + +static void test_postcopy_recovery(void) +{ + MigrateCommon args = { }; + + test_postcopy_recovery_common(&args); +} + +#ifdef CONFIG_GNUTLS +static void test_postcopy_recovery_tls_psk(void) +{ + MigrateCommon args = { + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_postcopy_recovery_common(&args); +} +#endif + +static void test_postcopy_preempt_recovery(void) +{ + MigrateCommon args = { + .postcopy_preempt = true, + }; + + test_postcopy_recovery_common(&args); } +#ifdef CONFIG_GNUTLS +/* This contains preempt+recovery+tls test altogether */ +static void test_postcopy_preempt_all(void) +{ + MigrateCommon args = { + .postcopy_preempt = true, + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_postcopy_recovery_common(&args); +} +#endif + static void test_baddest(void) { - MigrateStart *args = migrate_start_new(); + MigrateStart args = { + .hide_stderr = true + }; QTestState *from, *to; - args->hide_stderr = true; - if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) { return; } @@ -799,59 +1320,145 @@ static void test_baddest(void) test_migrate_end(from, to, false); } -static void test_precopy_unix_common(bool dirty_ring) +static void test_precopy_common(MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - MigrateStart *args = migrate_start_new(); QTestState *from, *to; + void *data_hook = NULL; - args->use_dirty_ring = dirty_ring; - - if (test_migrate_start(&from, &to, uri, &args)) { + if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) { return; } - /* We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); + migrate_ensure_non_converge(from); + + if (args->start_hook) { + data_hook = args->start_hook(from, to); + } /* 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"); + } - migrate_qmp(from, uri, "{}"); + if (!args->connect_uri) { + g_autofree char *local_connect_uri = + migrate_get_socket_address(to, "socket-address"); + migrate_qmp(from, local_connect_uri, "{}"); + } else { + migrate_qmp(from, args->connect_uri, "{}"); + } - wait_for_migration_pass(from); - migrate_set_parameter_int(from, "downtime-limit", CONVERGE_DOWNTIME); + if (args->result != MIG_TEST_SUCCEED) { + bool allow_active = args->result == MIG_TEST_FAIL; + wait_for_migration_fail(from, allow_active); - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } + if (args->result == MIG_TEST_FAIL_DEST_QUIT_ERR) { + qtest_set_expected_status(to, EXIT_FAILURE); + } + } else { + if (args->iterations) { + while (args->iterations--) { + wait_for_migration_pass(from); + } + } else { + wait_for_migration_pass(from); + } - qtest_qmp_eventwait(to, "RESUME"); + migrate_ensure_converge(from); - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); + /* We do this first, as it has a timeout to stop us + * hanging forever if migration didn't converge */ + wait_for_migration_complete(from); - test_migrate_end(from, to, true); + if (!got_stop) { + qtest_qmp_eventwait(from, "STOP"); + } + + qtest_qmp_eventwait(to, "RESUME"); + + wait_for_serial("dest_serial"); + } + + if (args->finish_hook) { + args->finish_hook(from, to, data_hook); + } + + test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); } -static void test_precopy_unix(void) +static void test_precopy_unix_plain(void) { - /* Using default dirty logging */ - test_precopy_unix_common(false); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .listen_uri = uri, + .connect_uri = uri, + }; + + test_precopy_common(&args); } + static void test_precopy_unix_dirty_ring(void) { - /* Using dirty ring tracking */ - test_precopy_unix_common(true); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .start = { + .use_dirty_ring = true, + }, + .listen_uri = uri, + .connect_uri = uri, + }; + + test_precopy_common(&args); +} + +#ifdef CONFIG_GNUTLS +static void test_precopy_unix_tls_psk(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_precopy_common(&args); +} + +#ifdef CONFIG_TASN1 +static void test_precopy_unix_tls_x509_default_host(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_x509_start_default_host, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL_DEST_QUIT_ERR, + }; + + test_precopy_common(&args); +} + +static void test_precopy_unix_tls_x509_override_host(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_x509_start_override_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + + test_precopy_common(&args); } +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ #if 0 /* Currently upset on aarch64 TCG */ @@ -890,126 +1497,168 @@ static void test_ignore_shared(void) } #endif -static void test_xbzrle(const char *uri) +static void * +test_migrate_xbzrle_start(QTestState *from, + QTestState *to) { - MigrateStart *args = migrate_start_new(); - QTestState *from, *to; - - if (test_migrate_start(&from, &to, uri, &args)) { - return; - } - - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); - migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432); migrate_set_capability(from, "xbzrle", true); migrate_set_capability(to, "xbzrle", true); - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); - migrate_qmp(from, uri, "{}"); + return NULL; +} - wait_for_migration_pass(from); - /* Make sure we have 2 passes, so the xbzrle cache gets a workout */ - wait_for_migration_pass(from); +static void test_precopy_unix_xbzrle(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, - /* 1000ms should converge */ - migrate_set_parameter_int(from, "downtime-limit", 1000); + .start_hook = test_migrate_xbzrle_start, - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } - qtest_qmp_eventwait(to, "RESUME"); - - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); + .iterations = 2, + }; - test_migrate_end(from, to, true); + test_precopy_common(&args); } -static void test_xbzrle_unix(void) +static void test_precopy_tcp_plain(void) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + }; - test_xbzrle(uri); + test_precopy_common(&args); } -static void test_precopy_tcp(void) +#ifdef CONFIG_GNUTLS +static void test_precopy_tcp_tls_psk_match(void) { - MigrateStart *args = migrate_start_new(); - g_autofree char *uri = NULL; - QTestState *from, *to; + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; - if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) { - return; - } + test_precopy_common(&args); +} - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); +static void test_precopy_tcp_tls_psk_mismatch(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_psk_start_mismatch, + .finish_hook = test_migrate_tls_psk_finish, + .result = MIG_TEST_FAIL, + }; + + test_precopy_common(&args); +} - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); +#ifdef CONFIG_TASN1 +static void test_precopy_tcp_tls_x509_default_host(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_default_host, + .finish_hook = test_migrate_tls_x509_finish, + }; - uri = migrate_get_socket_address(to, "socket-address"); + test_precopy_common(&args); +} - migrate_qmp(from, uri, "{}"); +static void test_precopy_tcp_tls_x509_override_host(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_override_host, + .finish_hook = test_migrate_tls_x509_finish, + }; - wait_for_migration_pass(from); + test_precopy_common(&args); +} - migrate_set_parameter_int(from, "downtime-limit", CONVERGE_DOWNTIME); +static void test_precopy_tcp_tls_x509_mismatch_host(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_mismatch_host, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL_DEST_QUIT_ERR, + }; + + test_precopy_common(&args); +} - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } - qtest_qmp_eventwait(to, "RESUME"); +static void test_precopy_tcp_tls_x509_friendly_client(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_friendly_client, + .finish_hook = test_migrate_tls_x509_finish, + }; - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); + test_precopy_common(&args); +} - test_migrate_end(from, to, true); +static void test_precopy_tcp_tls_x509_hostile_client(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_hostile_client, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + + test_precopy_common(&args); } -static void test_migrate_fd_proto(void) +static void test_precopy_tcp_tls_x509_allow_anon_client(void) { - MigrateStart *args = migrate_start_new(); - QTestState *from, *to; - int ret; - int pair[2]; - QDict *rsp; - const char *error_desc; + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_allow_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + }; - if (test_migrate_start(&from, &to, "defer", &args)) { - return; - } + test_precopy_common(&args); +} - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge */ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); +static void test_precopy_tcp_tls_x509_reject_anon_client(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_reject_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + + test_precopy_common(&args); +} +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); +#ifndef _WIN32 +static void *test_migrate_fd_start_hook(QTestState *from, + QTestState *to) +{ + QDict *rsp; + int ret; + int pair[2]; /* Create two connected sockets for migration */ ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); @@ -1034,17 +1683,15 @@ static void test_migrate_fd_proto(void) qobject_unref(rsp); close(pair[1]); - /* Start migration to the 2nd socket*/ - migrate_qmp(from, "fd:fd-mig", "{}"); - - wait_for_migration_pass(from); - - migrate_set_parameter_int(from, "downtime-limit", CONVERGE_DOWNTIME); + return NULL; +} - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } - qtest_qmp_eventwait(to, "RESUME"); +static void test_migrate_fd_finish_hook(QTestState *from, + QTestState *to, + void *opaque) +{ + QDict *rsp; + const char *error_desc; /* Test closing fds */ /* We assume, that QEMU removes named fd from its list, @@ -1062,19 +1709,26 @@ static void test_migrate_fd_proto(void) error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); qobject_unref(rsp); +} - /* Complete migration */ - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); - test_migrate_end(from, to, true); +static void test_migrate_fd_proto(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .connect_uri = "fd:fd-mig", + .start_hook = test_migrate_fd_start_hook, + .finish_hook = test_migrate_fd_finish_hook + }; + test_precopy_common(&args); } +#endif /* _WIN32 */ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; - if (test_migrate_start(&from, &to, uri, &args)) { + if (test_migrate_start(&from, &to, uri, args)) { return; } @@ -1092,7 +1746,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) migrate_qmp(from, uri, "{}"); if (should_fail) { - qtest_set_expected_status(to, 1); + qtest_set_expected_status(to, EXIT_FAILURE); wait_for_migration_fail(from, true); } else { wait_for_migration_complete(from); @@ -1103,53 +1757,51 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) static void test_validate_uuid(void) { - MigrateStart *args = migrate_start_new(); + MigrateStart args = { + .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", + .opts_target = "-uuid 11111111-1111-1111-1111-111111111111", + }; - g_free(args->opts_source); - g_free(args->opts_target); - args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111"); - args->opts_target = g_strdup("-uuid 11111111-1111-1111-1111-111111111111"); - do_test_validate_uuid(args, false); + do_test_validate_uuid(&args, false); } static void test_validate_uuid_error(void) { - MigrateStart *args = migrate_start_new(); + MigrateStart args = { + .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", + .opts_target = "-uuid 22222222-2222-2222-2222-222222222222", + .hide_stderr = true, + }; - g_free(args->opts_source); - g_free(args->opts_target); - args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111"); - args->opts_target = g_strdup("-uuid 22222222-2222-2222-2222-222222222222"); - args->hide_stderr = true; - do_test_validate_uuid(args, true); + do_test_validate_uuid(&args, true); } static void test_validate_uuid_src_not_set(void) { - MigrateStart *args = migrate_start_new(); + MigrateStart args = { + .opts_target = "-uuid 22222222-2222-2222-2222-222222222222", + .hide_stderr = true, + }; - g_free(args->opts_target); - args->opts_target = g_strdup("-uuid 22222222-2222-2222-2222-222222222222"); - args->hide_stderr = true; - do_test_validate_uuid(args, false); + do_test_validate_uuid(&args, false); } static void test_validate_uuid_dst_not_set(void) { - MigrateStart *args = migrate_start_new(); + MigrateStart args = { + .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", + .hide_stderr = true, + }; - g_free(args->opts_source); - args->opts_source = g_strdup("-uuid 11111111-1111-1111-1111-111111111111"); - args->hide_stderr = true; - do_test_validate_uuid(args, false); + do_test_validate_uuid(&args, false); } static void test_migrate_auto_converge(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - MigrateStart *args = migrate_start_new(); + MigrateStart args = {}; QTestState *from, *to; - int64_t remaining, percentage; + int64_t percentage; /* * We want the test to be stable and as fast as possible. @@ -1157,14 +1809,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; @@ -1179,8 +1823,7 @@ static void test_migrate_auto_converge(void) * Set the initial parameters so that the migration could not converge * without throttling. */ - migrate_set_parameter_int(from, "downtime-limit", 1); - migrate_set_parameter_int(from, "max-bandwidth", 100000000); /* ~100Mb/s */ + migrate_ensure_non_converge(from); /* To check remaining size after precopy */ migrate_set_capability(from, "pause-before-switchover", true); @@ -1200,8 +1843,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 @@ -1212,11 +1854,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"); @@ -1224,30 +1861,15 @@ static void test_migrate_auto_converge(void) wait_for_serial("dest_serial"); wait_for_migration_complete(from); - test_migrate_end(from, to, true); } -static void test_multifd_tcp(const char *method) +static void * +test_migrate_precopy_tcp_multifd_start_common(QTestState *from, + QTestState *to, + const char *method) { - MigrateStart *args = migrate_start_new(); - QTestState *from, *to; QDict *rsp; - g_autofree char *uri = NULL; - - if (test_migrate_start(&from, &to, "defer", &args)) { - return; - } - - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(to, "multifd-channels", 16); @@ -1263,44 +1885,218 @@ static void test_multifd_tcp(const char *method) " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}"); qobject_unref(rsp); - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); - - uri = migrate_get_socket_address(to, "socket-address"); - - migrate_qmp(from, uri, "{}"); - - wait_for_migration_pass(from); + return NULL; +} - migrate_set_parameter_int(from, "downtime-limit", CONVERGE_DOWNTIME); +static void * +test_migrate_precopy_tcp_multifd_start(QTestState *from, + QTestState *to) +{ + return test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); +} - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } - qtest_qmp_eventwait(to, "RESUME"); +static void * +test_migrate_precopy_tcp_multifd_zlib_start(QTestState *from, + QTestState *to) +{ + return test_migrate_precopy_tcp_multifd_start_common(from, to, "zlib"); +} - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); - test_migrate_end(from, to, true); +#ifdef CONFIG_ZSTD +static void * +test_migrate_precopy_tcp_multifd_zstd_start(QTestState *from, + QTestState *to) +{ + return test_migrate_precopy_tcp_multifd_start_common(from, to, "zstd"); } +#endif /* CONFIG_ZSTD */ static void test_multifd_tcp_none(void) { - test_multifd_tcp("none"); + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_start, + }; + test_precopy_common(&args); } static void test_multifd_tcp_zlib(void) { - test_multifd_tcp("zlib"); + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_zlib_start, + }; + test_precopy_common(&args); } #ifdef CONFIG_ZSTD static void test_multifd_tcp_zstd(void) { - test_multifd_tcp("zstd"); + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_zstd_start, + }; + test_precopy_common(&args); } #endif +#ifdef CONFIG_GNUTLS +static void * +test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_psk_start_match(from, to); +} + +static void * +test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_psk_start_mismatch(from, to); +} + +#ifdef CONFIG_TASN1 +static void * +test_migrate_multifd_tls_x509_start_default_host(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_default_host(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_override_host(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_override_host(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_mismatch_host(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_mismatch_host(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_allow_anon_client(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_allow_anon_client(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_reject_anon_client(from, to); +} +#endif /* CONFIG_TASN1 */ + +static void test_multifd_tcp_tls_psk_match(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tcp_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_psk_mismatch(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tcp_tls_psk_start_mismatch, + .finish_hook = test_migrate_tls_psk_finish, + .result = MIG_TEST_FAIL, + }; + test_precopy_common(&args); +} + +#ifdef CONFIG_TASN1 +static void test_multifd_tcp_tls_x509_default_host(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_default_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_override_host(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_override_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_mismatch_host(void) +{ + /* + * This has different behaviour to the non-multifd case. + * + * In non-multifd case when client aborts due to mismatched + * cert host, the server has already started trying to load + * migration state, and so it exits with I/O failure. + * + * In multifd case when client aborts due to mismatched + * cert host, the server is still waiting for the other + * multifd connections to arrive so hasn't started trying + * to load migration state, and thus just aborts the migration + * without exiting. + */ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_mismatch_host, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_allow_anon_client(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_allow_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_reject_anon_client(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_reject_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + test_precopy_common(&args); +} +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ + /* * This test does: * source target @@ -1314,26 +2110,18 @@ static void test_multifd_tcp_zstd(void) */ static void test_multifd_tcp_cancel(void) { - MigrateStart *args = migrate_start_new(); + MigrateStart args = { + .hide_stderr = true, + }; QTestState *from, *to, *to2; QDict *rsp; g_autofree char *uri = NULL; - args->hide_stderr = true; - if (test_migrate_start(&from, &to, "defer", &args)) { return; } - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 300MB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 30000000); + migrate_ensure_non_converge(from); migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(to, "multifd-channels", 16); @@ -1357,8 +2145,13 @@ static void test_multifd_tcp_cancel(void) migrate_cancel(from); - args = migrate_start_new(); - args->only_target = true; + /* Make sure QEMU process "to" exited */ + qtest_set_expected_status(to, EXIT_FAILURE); + qtest_wait_qemu(to); + + args = (MigrateStart){ + .only_target = true, + }; if (test_migrate_start(&from, &to2, "defer", &args)) { return; @@ -1378,10 +2171,7 @@ static void test_multifd_tcp_cancel(void) wait_for_migration_status(from, "cancelled", NULL); - /* 300ms it should converge */ - migrate_set_parameter_int(from, "downtime-limit", 300); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); + migrate_ensure_converge(from); migrate_qmp(from, uri, "{}"); @@ -1397,6 +2187,253 @@ static void test_multifd_tcp_cancel(void) test_migrate_end(from, to2, true); } +static void calc_dirty_rate(QTestState *who, uint64_t calc_time) +{ + qobject_unref(qmp_command(who, + "{ 'execute': 'calc-dirty-rate'," + "'arguments': { " + "'calc-time': %" PRIu64 "," + "'mode': 'dirty-ring' }}", + calc_time)); +} + +static QDict *query_dirty_rate(QTestState *who) +{ + return qmp_command(who, "{ 'execute': 'query-dirty-rate' }"); +} + +static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate) +{ + qobject_unref(qmp_command(who, + "{ 'execute': 'set-vcpu-dirty-limit'," + "'arguments': { " + "'dirty-rate': %" PRIu64 " } }", + dirtyrate)); +} + +static void cancel_vcpu_dirty_limit(QTestState *who) +{ + qobject_unref(qmp_command(who, + "{ 'execute': 'cancel-vcpu-dirty-limit' }")); +} + +static QDict *query_vcpu_dirty_limit(QTestState *who) +{ + QDict *rsp; + + rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }"); + g_assert(!qdict_haskey(rsp, "error")); + g_assert(qdict_haskey(rsp, "return")); + + return rsp; +} + +static bool calc_dirtyrate_ready(QTestState *who) +{ + QDict *rsp_return; + gchar *status; + + rsp_return = query_dirty_rate(who); + g_assert(rsp_return); + + status = g_strdup(qdict_get_str(rsp_return, "status")); + g_assert(status); + + return g_strcmp0(status, "measuring"); +} + +static void wait_for_calc_dirtyrate_complete(QTestState *who, + int64_t time_s) +{ + int max_try_count = 10000; + usleep(time_s * 1000000); + + while (!calc_dirtyrate_ready(who) && max_try_count--) { + usleep(1000); + } + + /* + * Set the timeout with 10 s(max_try_count * 1000us), + * if dirtyrate measurement not complete, fail test. + */ + g_assert_cmpint(max_try_count, !=, 0); +} + +static int64_t get_dirty_rate(QTestState *who) +{ + QDict *rsp_return; + gchar *status; + QList *rates; + const QListEntry *entry; + QDict *rate; + int64_t dirtyrate; + + rsp_return = query_dirty_rate(who); + g_assert(rsp_return); + + status = g_strdup(qdict_get_str(rsp_return, "status")); + g_assert(status); + g_assert_cmpstr(status, ==, "measured"); + + rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate"); + g_assert(rates && !qlist_empty(rates)); + + entry = qlist_first(rates); + g_assert(entry); + + rate = qobject_to(QDict, qlist_entry_obj(entry)); + g_assert(rate); + + dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1); + + qobject_unref(rsp_return); + return dirtyrate; +} + +static int64_t get_limit_rate(QTestState *who) +{ + QDict *rsp_return; + QList *rates; + const QListEntry *entry; + QDict *rate; + int64_t dirtyrate; + + rsp_return = query_vcpu_dirty_limit(who); + g_assert(rsp_return); + + rates = qdict_get_qlist(rsp_return, "return"); + g_assert(rates && !qlist_empty(rates)); + + entry = qlist_first(rates); + g_assert(entry); + + rate = qobject_to(QDict, qlist_entry_obj(entry)); + g_assert(rate); + + dirtyrate = qdict_get_try_int(rate, "limit-rate", -1); + + qobject_unref(rsp_return); + return dirtyrate; +} + +static QTestState *dirtylimit_start_vm(void) +{ + QTestState *vm = NULL; + g_autofree gchar *cmd = NULL; + const char *arch = qtest_get_arch(); + g_autofree char *bootpath = NULL; + + assert((strcmp(arch, "x86_64") == 0)); + bootpath = g_strdup_printf("%s/bootsect", tmpfs); + assert(sizeof(x86_bootsect) == 512); + init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); + + cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " + "-name dirtylimit-test,debug-threads=on " + "-m 150M -smp 1 " + "-serial file:%s/vm_serial " + "-drive file=%s,format=raw ", + tmpfs, bootpath); + + vm = qtest_init(cmd); + return vm; +} + +static void dirtylimit_stop_vm(QTestState *vm) +{ + qtest_quit(vm); + cleanup("bootsect"); + cleanup("vm_serial"); +} + +static void test_vcpu_dirty_limit(void) +{ + QTestState *vm; + int64_t origin_rate; + int64_t quota_rate; + int64_t rate ; + int max_try_count = 20; + int hit = 0; + + /* Start vm for vcpu dirtylimit test */ + vm = dirtylimit_start_vm(); + + /* Wait for the first serial output from the vm*/ + wait_for_serial("vm_serial"); + + /* Do dirtyrate measurement with calc time equals 1s */ + calc_dirty_rate(vm, 1); + + /* Sleep calc time and wait for calc dirtyrate complete */ + wait_for_calc_dirtyrate_complete(vm, 1); + + /* Query original dirty page rate */ + origin_rate = get_dirty_rate(vm); + + /* VM booted from bootsect should dirty memory steadily */ + assert(origin_rate != 0); + + /* Setup quota dirty page rate at half of origin */ + quota_rate = origin_rate / 2; + + /* Set dirtylimit */ + dirtylimit_set_all(vm, quota_rate); + + /* + * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit + * works literally + */ + g_assert_cmpint(quota_rate, ==, get_limit_rate(vm)); + + /* Sleep a bit to check if it take effect */ + usleep(2000000); + + /* + * Check if dirtylimit take effect realistically, set the + * timeout with 20 s(max_try_count * 1s), if dirtylimit + * doesn't take effect, fail test. + */ + while (--max_try_count) { + calc_dirty_rate(vm, 1); + wait_for_calc_dirtyrate_complete(vm, 1); + rate = get_dirty_rate(vm); + + /* + * Assume hitting if current rate is less + * than quota rate (within accepting error) + */ + if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { + hit = 1; + break; + } + } + + g_assert_cmpint(hit, ==, 1); + + hit = 0; + max_try_count = 20; + + /* Check if dirtylimit cancellation take effect */ + cancel_vcpu_dirty_limit(vm); + while (--max_try_count) { + calc_dirty_rate(vm, 1); + wait_for_calc_dirtyrate_complete(vm, 1); + rate = get_dirty_rate(vm); + + /* + * Assume dirtylimit be canceled if current rate is + * greater than quota rate (within accepting error) + */ + if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { + hit = 1; + break; + } + } + + g_assert_cmpint(hit, ==, 1); + dirtylimit_stop_vm(vm); +} + static bool kvm_dirty_ring_supported(void) { #if defined(__linux__) && defined(HOST_X86_64) @@ -1422,22 +2459,20 @@ static bool kvm_dirty_ring_supported(void) 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(); + g_autoptr(GError) err = NULL; 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(); @@ -1447,27 +2482,86 @@ 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_dir_make_tmp("migration-test-XXXXXX", &err); if (!tmpfs) { - g_test_message("mkdtemp on path (%s): %s", template, strerror(errno)); + g_test_message("Can't create temporary directory in %s: %s", + g_get_tmp_dir(), err->message); } g_assert(tmpfs); module_call_init(MODULE_INIT_QOM); - qtest_add_func("/migration/postcopy/unix", test_postcopy); - qtest_add_func("/migration/postcopy/recovery", test_postcopy_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", test_precopy_unix); - qtest_add_func("/migration/precopy/tcp", test_precopy_tcp); + 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 + qtest_add_func("/migration/precopy/unix/tls/psk", + test_precopy_unix_tls_psk); + + 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); + qtest_add_func("/migration/precopy/unix/tls/x509/override-host", + test_precopy_unix_tls_x509_override_host); +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ + + qtest_add_func("/migration/precopy/tcp/plain", test_precopy_tcp_plain); +#ifdef CONFIG_GNUTLS + qtest_add_func("/migration/precopy/tcp/tls/psk/match", + test_precopy_tcp_tls_psk_match); + qtest_add_func("/migration/precopy/tcp/tls/psk/mismatch", + test_precopy_tcp_tls_psk_mismatch); +#ifdef CONFIG_TASN1 + qtest_add_func("/migration/precopy/tcp/tls/x509/default-host", + test_precopy_tcp_tls_x509_default_host); + qtest_add_func("/migration/precopy/tcp/tls/x509/override-host", + test_precopy_tcp_tls_x509_override_host); + qtest_add_func("/migration/precopy/tcp/tls/x509/mismatch-host", + test_precopy_tcp_tls_x509_mismatch_host); + qtest_add_func("/migration/precopy/tcp/tls/x509/friendly-client", + test_precopy_tcp_tls_x509_friendly_client); + qtest_add_func("/migration/precopy/tcp/tls/x509/hostile-client", + test_precopy_tcp_tls_x509_hostile_client); + qtest_add_func("/migration/precopy/tcp/tls/x509/allow-anon-client", + test_precopy_tcp_tls_x509_allow_anon_client); + qtest_add_func("/migration/precopy/tcp/tls/x509/reject-anon-client", + test_precopy_tcp_tls_x509_reject_anon_client); +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ + /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */ - qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix); +#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", @@ -1476,16 +2570,40 @@ int main(int argc, char **argv) test_validate_uuid_dst_not_set); qtest_add_func("/migration/auto_converge", test_migrate_auto_converge); - qtest_add_func("/migration/multifd/tcp/none", test_multifd_tcp_none); - qtest_add_func("/migration/multifd/tcp/cancel", test_multifd_tcp_cancel); - qtest_add_func("/migration/multifd/tcp/zlib", test_multifd_tcp_zlib); + qtest_add_func("/migration/multifd/tcp/plain/none", + test_multifd_tcp_none); + qtest_add_func("/migration/multifd/tcp/plain/cancel", + test_multifd_tcp_cancel); + qtest_add_func("/migration/multifd/tcp/plain/zlib", + test_multifd_tcp_zlib); #ifdef CONFIG_ZSTD - qtest_add_func("/migration/multifd/tcp/zstd", test_multifd_tcp_zstd); + qtest_add_func("/migration/multifd/tcp/plain/zstd", + test_multifd_tcp_zstd); #endif - - if (kvm_dirty_ring_supported()) { +#ifdef CONFIG_GNUTLS + qtest_add_func("/migration/multifd/tcp/tls/psk/match", + test_multifd_tcp_tls_psk_match); + qtest_add_func("/migration/multifd/tcp/tls/psk/mismatch", + test_multifd_tcp_tls_psk_mismatch); +#ifdef CONFIG_TASN1 + qtest_add_func("/migration/multifd/tcp/tls/x509/default-host", + test_multifd_tcp_tls_x509_default_host); + qtest_add_func("/migration/multifd/tcp/tls/x509/override-host", + test_multifd_tcp_tls_x509_override_host); + qtest_add_func("/migration/multifd/tcp/tls/x509/mismatch-host", + test_multifd_tcp_tls_x509_mismatch_host); + qtest_add_func("/migration/multifd/tcp/tls/x509/allow-anon-client", + test_multifd_tcp_tls_x509_allow_anon_client); + qtest_add_func("/migration/multifd/tcp/tls/x509/reject-anon-client", + test_multifd_tcp_tls_x509_reject_anon_client); +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ + + 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", + test_vcpu_dirty_limit); } ret = g_test_run(); @@ -1497,6 +2615,7 @@ int main(int argc, char **argv) g_test_message("unable to rmdir: path (%s): %s", tmpfs, strerror(errno)); } + g_free(tmpfs); return ret; } diff --git a/tests/qtest/modules-test.c b/tests/qtest/modules-test.c index c238b3f42216..be2575ae6d7d 100644 --- a/tests/qtest/modules-test.c +++ b/tests/qtest/modules-test.c @@ -1,5 +1,5 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" const char common_args[] = "-nodefaults -machine none"; @@ -16,6 +16,9 @@ static void test_modules_load(const void *data) int main(int argc, char *argv[]) { const char *modules[] = { +#ifdef CONFIG_BLKIO + "block-", "blkio", +#endif #ifdef CONFIG_CURL "block-", "curl", #endif diff --git a/tests/qtest/ne2000-test.c b/tests/qtest/ne2000-test.c index 43cfc4535aab..3fc0e555d5e2 100644 --- a/tests/qtest/ne2000-test.c +++ b/tests/qtest/ne2000-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c index 5ce8ce13b3d7..8048044d2810 100644 --- a/tests/qtest/npcm7xx_adc-test.c +++ b/tests/qtest/npcm7xx_adc-test.c @@ -17,7 +17,7 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" #include "qemu/timer.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #define REF_HZ (25000000) @@ -50,7 +50,7 @@ #define CON_INT BIT(18) #define CON_EN BIT(17) #define CON_RST BIT(16) -#define CON_CONV BIT(14) +#define CON_CONV BIT(13) #define CON_DIV(rv) extract32(rv, 1, 8) #define FST_RDST BIT(1) diff --git a/tests/qtest/npcm7xx_emc-test.c b/tests/qtest/npcm7xx_emc-test.c index 7c435ac91576..b046f1d76af0 100644 --- a/tests/qtest/npcm7xx_emc-test.c +++ b/tests/qtest/npcm7xx_emc-test.c @@ -15,7 +15,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "libqos/libqos.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qnum.h" @@ -210,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; @@ -244,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) @@ -251,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) { @@ -340,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) @@ -378,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), ==, @@ -388,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) { @@ -844,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) @@ -866,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/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c index a54fd70d273b..e320a625c4b6 100644 --- a/tests/qtest/npcm7xx_pwm-test.c +++ b/tests/qtest/npcm7xx_pwm-test.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qnum.h" @@ -268,6 +268,9 @@ static void mft_qom_set(QTestState *qts, int index, const char *name, path, name, value); /* The qom set message returns successfully. */ g_assert_true(qdict_haskey(response, "return")); + + qobject_unref(response); + g_free(path); } static uint32_t get_pll(uint32_t con) diff --git a/tests/qtest/npcm7xx_rng-test.c b/tests/qtest/npcm7xx_rng-test.c index 797f832e53a1..35b1c1f5f6d2 100644 --- a/tests/qtest/npcm7xx_rng-test.c +++ b/tests/qtest/npcm7xx_rng-test.c @@ -20,7 +20,7 @@ #include "libqtest-single.h" #include "qemu/bitops.h" -#include "qemu-common.h" +#include "qemu/cutils.h" #define RNG_BASE_ADDR 0xf000b000 diff --git a/tests/qtest/npcm7xx_sdhci-test.c b/tests/qtest/npcm7xx_sdhci-test.c index c1f496fb29bb..5d68540e5202 100644 --- a/tests/qtest/npcm7xx_sdhci-test.c +++ b/tests/qtest/npcm7xx_sdhci-test.c @@ -17,14 +17,14 @@ #include "qemu/osdep.h" #include "hw/sd/npcm7xx_sdhci.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqtest-single.h" #include "libqos/sdhci-cmd.h" #define NPCM7XX_REG_SIZE 0x100 #define NPCM7XX_MMC_BA 0xF0842000 #define NPCM7XX_BLK_SIZE 512 -#define NPCM7XX_TEST_IMAGE_SIZE (1 << 30) +#define NPCM7XX_TEST_IMAGE_SIZE (1 << 20) char *sd_path; diff --git a/tests/qtest/npcm7xx_smbus-test.c b/tests/qtest/npcm7xx_smbus-test.c index 6b3038ac596f..a878cdc00142 100644 --- a/tests/qtest/npcm7xx_smbus-test.c +++ b/tests/qtest/npcm7xx_smbus-test.c @@ -17,7 +17,7 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" #include "libqos/i2c.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "hw/sensor/tmp105_regs.h" #define NR_SMBUS_DEVICES 16 diff --git a/tests/qtest/npcm7xx_watchdog_timer-test.c b/tests/qtest/npcm7xx_watchdog_timer-test.c index 3aae5a043813..4773a673b207 100644 --- a/tests/qtest/npcm7xx_watchdog_timer-test.c +++ b/tests/qtest/npcm7xx_watchdog_timer-test.c @@ -17,7 +17,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #define WTCR_OFFSET 0x1c diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index 90bf68a5b33c..c5eb13f349f7 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -10,7 +10,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" @@ -223,17 +223,18 @@ static void aarch64_numa_cpu(const void *data) QTestState *qts; g_autofree char *cli = NULL; - cli = make_cli(data, "-machine smp.cpus=2 " + cli = make_cli(data, "-machine " + "smp.cpus=2,smp.sockets=2,smp.clusters=1,smp.cores=1,smp.threads=1 " "-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 " - "-numa cpu,node-id=1,thread-id=0 " - "-numa cpu,node-id=0,thread-id=1"); + "-numa cpu,node-id=0,socket-id=1,cluster-id=0,core-id=0,thread-id=0 " + "-numa cpu,node-id=1,socket-id=0,cluster-id=0,core-id=0,thread-id=0"); qts = qtest_init(cli); cpus = get_cpus(qts, &resp); g_assert(cpus); while ((e = qlist_pop(cpus))) { QDict *cpu, *props; - int64_t thread, node; + int64_t socket, cluster, core, thread, node; cpu = qobject_to(QDict, e); g_assert(qdict_haskey(cpu, "props")); @@ -241,12 +242,18 @@ static void aarch64_numa_cpu(const void *data) g_assert(qdict_haskey(props, "node-id")); node = qdict_get_int(props, "node-id"); + g_assert(qdict_haskey(props, "socket-id")); + socket = qdict_get_int(props, "socket-id"); + g_assert(qdict_haskey(props, "cluster-id")); + cluster = qdict_get_int(props, "cluster-id"); + g_assert(qdict_haskey(props, "core-id")); + core = qdict_get_int(props, "core-id"); g_assert(qdict_haskey(props, "thread-id")); thread = qdict_get_int(props, "thread-id"); - if (thread == 0) { + if (socket == 0 && cluster == 0 && core == 0 && thread == 0) { g_assert_cmpint(node, ==, 1); - } else if (thread == 1) { + } else if (socket == 1 && cluster == 0 && core == 0 && thread == 0) { g_assert_cmpint(node, ==, 0); } else { g_assert(false); diff --git a/tests/qtest/nvme-test.c b/tests/qtest/nvme-test.c index f8bafb5d70fb..008d189b0faf 100644 --- a/tests/qtest/nvme-test.c +++ b/tests/qtest/nvme-test.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "qemu/units.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/qgraph.h" #include "libqos/pci.h" #include "include/block/nvme.h" diff --git a/tests/qtest/pca9552-test.c b/tests/qtest/pca9552-test.c index 42a131266512..d80ed93cd3a5 100644 --- a/tests/qtest/pca9552-test.c +++ b/tests/qtest/pca9552-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/qgraph.h" #include "libqos/i2c.h" #include "hw/misc/pca9552_regs.h" diff --git a/tests/qtest/pci-test.c b/tests/qtest/pci-test.c index e15d4d94d1d0..4b2092b94973 100644 --- a/tests/qtest/pci-test.c +++ b/tests/qtest/pci-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/pcnet-test.c b/tests/qtest/pcnet-test.c index 7583aeb3c38f..900944fa7e34 100644 --- a/tests/qtest/pcnet-test.c +++ b/tests/qtest/pcnet-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/pflash-cfi02-test.c b/tests/qtest/pflash-cfi02-test.c index 6168edc821a8..0b52c2ca5c38 100644 --- a/tests/qtest/pflash-cfi02-test.c +++ b/tests/qtest/pflash-cfi02-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with @@ -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/pnv-xscom-test.c b/tests/qtest/pnv-xscom-test.c index c8d40433620a..2c46d5cf6de3 100644 --- a/tests/qtest/pnv-xscom-test.c +++ b/tests/qtest/pnv-xscom-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" typedef enum PnvChipType { PNV_CHIP_POWER8E, /* AKA Murano (default) */ diff --git a/tests/qtest/prom-env-test.c b/tests/qtest/prom-env-test.c index bdbb01d8e584..39ccb59797df 100644 --- a/tests/qtest/prom-env-test.c +++ b/tests/qtest/prom-env-test.c @@ -20,7 +20,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/libqos-spapr.h" #define MAGIC 0xcafec0de @@ -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/pvpanic-pci-test.c b/tests/qtest/pvpanic-pci-test.c index 2358852d356f..2c05b376ba72 100644 --- a/tests/qtest/pvpanic-pci-test.c +++ b/tests/qtest/pvpanic-pci-test.c @@ -12,7 +12,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" @@ -86,13 +86,9 @@ static void test_panic(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("/pvpanic-pci/panic", test_panic); qtest_add_func("/pvpanic-pci/panic-nopause", test_panic_nopause); - ret = g_test_run(); - - return ret; + return g_test_run(); } diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c index 6dcad2db4984..78f1cf8186b0 100644 --- a/tests/qtest/pvpanic-test.c +++ b/tests/qtest/pvpanic-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" static void test_panic_nopause(void) @@ -59,13 +59,9 @@ static void test_panic(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("/pvpanic/panic", test_panic); qtest_add_func("/pvpanic/panic-nopause", test_panic_nopause); - ret = g_test_run(); - - return ret; + return g_test_run(); } diff --git a/tests/qtest/pxe-test.c b/tests/qtest/pxe-test.c index 32bbae33c597..52f0b5c67c03 100644 --- a/tests/qtest/pxe-test.c +++ b/tests/qtest/pxe-test.c @@ -14,8 +14,7 @@ #include "qemu/osdep.h" #include -#include "qemu-common.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "boot-sector.h" #include "libqos/libqos-spapr.h" diff --git a/tests/qtest/q35-test.c b/tests/qtest/q35-test.c index b7cf1449906f..c922d81bc020 100644 --- a/tests/qtest/q35-test.c +++ b/tests/qtest/q35-test.c @@ -10,7 +10,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" #include "hw/pci-host/q35.h" diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index 7f103ea3fd2a..98caf6fef6d3 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/error.h" #include "qapi/qapi-visit-introspect.h" #include "qapi/qmp/qdict.h" @@ -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 */ @@ -110,6 +111,8 @@ static bool query_is_ignored(const char *cmd) "query-sev-capabilities", "query-sgx", "query-sgx-capabilities", + /* Success depends on enabling dirty page rate limit */ + "query-vcpu-dirty-limit", NULL }; int i; @@ -171,7 +174,7 @@ static bool object_type_has_mandatory_members(SchemaInfo *type) g_assert(type->meta_type == SCHEMA_META_TYPE_OBJECT); for (tail = type->u.object.members; tail; tail = tail->next) { - if (!tail->value->has_q_default) { + if (!tail->value->q_default) { return true; } } diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c index cd27fae3deb2..22957fa49c22 100644 --- a/tests/qtest/qmp-test.c +++ b/tests/qtest/qmp-test.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/error.h" #include "qapi/qapi-visit-control.h" #include "qapi/qmp/qdict.h" @@ -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/qom-test.c b/tests/qtest/qom-test.c index eb34af843b79..13510bc34961 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -9,11 +9,10 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" #include "qemu/cutils.h" -#include "libqos/libqtest.h" +#include "libqtest.h" static void test_properties(QTestState *qts, const char *path, bool recurse) { @@ -21,6 +20,7 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) QDict *response, *tuple, *tmp; QList *list; QListEntry *entry; + GSList *children = NULL, *links = NULL; g_test_message("Obtaining properties of %s", path); response = qtest_qmp(qts, "{ 'execute': 'qom-list'," @@ -42,11 +42,14 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) if (is_child || is_link) { child_path = g_strdup_printf("%s/%s", path, qdict_get_str(tuple, "name")); - test_properties(qts, child_path, is_child); - g_free(child_path); + if (is_child) { + children = g_slist_prepend(children, child_path); + } else { + links = g_slist_prepend(links, child_path); + } } else { const char *prop = qdict_get_str(tuple, "name"); - g_test_message("Testing property %s.%s", path, prop); + g_test_message("-> %s", prop); tmp = qtest_qmp(qts, "{ 'execute': 'qom-get'," " 'arguments': { 'path': %s, 'property': %s } }", @@ -56,6 +59,18 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) qobject_unref(tmp); } } + + while (links) { + test_properties(qts, links->data, false); + g_free(links->data); + links = g_slist_delete_link(links, links); + } + while (children) { + test_properties(qts, children->data, true); + g_free(children->data); + children = g_slist_delete_link(children, children); + } + qobject_unref(response); } diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c index f97d0a08fd05..5da4091ec32b 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 000000000000..9ef870643dcd --- /dev/null +++ b/tests/qtest/readconfig-test.c @@ -0,0 +1,197 @@ +/* + * 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" +#ifndef WIN32 + "unix = \"on\"\n" +#endif + "disable-ticketing = \"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/rtas-test.c b/tests/qtest/rtas-test.c index 5f1194a6eb53..1ba42b37d219 100644 --- a/tests/qtest/rtas-test.c +++ b/tests/qtest/rtas-test.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/libqos-spapr.h" #include "libqos/rtas.h" @@ -13,7 +13,7 @@ static void run_test_rtas_get_time_of_day(const char *machine) uint64_t ret; time_t t1, t2; - qs = qtest_spapr_boot(machine); + qs = qtest_spapr_boot("%s", machine); t1 = time(NULL); ret = qrtas_get_time_of_day(qs->qts, &qs->alloc, &tm, &ns); diff --git a/tests/qtest/rtc-test.c b/tests/qtest/rtc-test.c index 8126ab1bdb80..02ed4e123859 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/rtl8139-test.c b/tests/qtest/rtl8139-test.c index 450604926492..8fa3313cc333 100644 --- a/tests/qtest/rtl8139-test.c +++ b/tests/qtest/rtl8139-test.c @@ -11,7 +11,6 @@ #include "libqtest-single.h" #include "libqos/pci-pc.h" #include "qemu/timer.h" -#include "qemu-common.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/tests/qtest/sdhci-test.c b/tests/qtest/sdhci-test.c index a110cfe3219c..6275e7626c21 100644 --- a/tests/qtest/sdhci-test.c +++ b/tests/qtest/sdhci-test.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "hw/registerfields.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/pci-pc.h" #include "hw/pci/pci.h" diff --git a/tests/qtest/spapr-phb-test.c b/tests/qtest/spapr-phb-test.c index ea8d59650721..093dc22f2f41 100644 --- a/tests/qtest/spapr-phb-test.c +++ b/tests/qtest/spapr-phb-test.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" diff --git a/tests/qtest/tco-test.c b/tests/qtest/tco-test.c index 47bc7ad3019d..d865e95dfcda 100644 --- a/tests/qtest/tco-test.c +++ b/tests/qtest/tco-test.c @@ -9,14 +9,14 @@ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" #include "qapi/qmp/qdict.h" #include "hw/pci/pci_regs.h" #include "hw/i386/ich9.h" #include "hw/acpi/ich9.h" -#include "hw/acpi/tco.h" +#include "hw/acpi/ich9_tco.h" #define RCBA_BASE_ADDR 0xfed1c000 #define PM_IO_BASE_ADDR 0xb000 @@ -60,7 +60,7 @@ static void test_init(TestData *d) QTestState *qs; qs = qtest_initf("-machine q35 %s %s", - d->noreboot ? "" : "-global ICH9-LPC.noreboot=false", + d->noreboot ? "-global ICH9-LPC.noreboot=true" : "", !d->args ? "" : d->args); qtest_irq_intercept_in(qs, "ioapic"); diff --git a/tests/qtest/test-filter-mirror.c b/tests/qtest/test-filter-mirror.c index da4f94de727a..248fc8869971 100644 --- a/tests/qtest/test-filter-mirror.c +++ b/tests/qtest/test-filter-mirror.c @@ -9,8 +9,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qemu/iov.h" #include "qemu/sockets.h" @@ -77,12 +76,8 @@ static void test_mirror(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("/netfilter/mirror", test_mirror); - ret = g_test_run(); - - return ret; + return g_test_run(); } diff --git a/tests/qtest/test-filter-redirector.c b/tests/qtest/test-filter-redirector.c index fc16cf7e8d5f..24ca9280f814 100644 --- a/tests/qtest/test-filter-redirector.c +++ b/tests/qtest/test-filter-redirector.c @@ -51,8 +51,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qemu/iov.h" #include "qemu/sockets.h" diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c index 413eb95d2a0c..f8b22abe4cac 100644 --- a/tests/qtest/test-hmp.c +++ b/tests/qtest/test-hmp.c @@ -15,7 +15,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" static int verbose; diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c index 39138db7744b..b39c9055b309 100644 --- a/tests/qtest/test-x86-cpuid-compat.c +++ b/tests/qtest/test-x86-cpuid-compat.c @@ -1,5 +1,4 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" #include "qapi/qmp/qnum.h" diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c index 1d82a48c04be..40254f762f09 100644 --- a/tests/qtest/tpm-crb-swtpm-test.c +++ b/tests/qtest/tpm-crb-swtpm-test.c @@ -13,9 +13,8 @@ */ #include "qemu/osdep.h" -#include -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "tpm-tests.h" #include "hw/acpi/tpm.h" @@ -62,9 +61,9 @@ int main(int argc, char **argv) tpm_crb_swtpm_migration_test); ret = g_test_run(); - g_rmdir(ts.dst_tpm_path); + tpm_util_rmdir(ts.dst_tpm_path); g_free(ts.dst_tpm_path); - g_rmdir(ts.src_tpm_path); + tpm_util_rmdir(ts.src_tpm_path); g_free(ts.src_tpm_path); g_free(ts.uri); diff --git a/tests/qtest/tpm-emu.h b/tests/qtest/tpm-emu.h index c33d99af3743..712cee9b7a54 100644 --- a/tests/qtest/tpm-emu.h +++ b/tests/qtest/tpm-emu.h @@ -22,7 +22,7 @@ #include "qemu/sockets.h" #include "io/channel.h" #include "sysemu/tpm.h" -#include "libqos/libqtest.h" +#include "libqtest.h" struct tpm_hdr { uint16_t tag; diff --git a/tests/qtest/tpm-tis-device-swtpm-test.c b/tests/qtest/tpm-tis-device-swtpm-test.c index f7126eff9e74..8c067fddd450 100644 --- a/tests/qtest/tpm-tis-device-swtpm-test.c +++ b/tests/qtest/tpm-tis-device-swtpm-test.c @@ -14,9 +14,8 @@ */ #include "qemu/osdep.h" -#include -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "tpm-tests.h" #include "hw/acpi/tpm.h" @@ -66,9 +65,9 @@ int main(int argc, char **argv) tpm_tis_swtpm_migration_test); ret = g_test_run(); - g_rmdir(ts.dst_tpm_path); + tpm_util_rmdir(ts.dst_tpm_path); g_free(ts.dst_tpm_path); - g_rmdir(ts.src_tpm_path); + tpm_util_rmdir(ts.src_tpm_path); g_free(ts.src_tpm_path); g_free(ts.uri); diff --git a/tests/qtest/tpm-tis-swtpm-test.c b/tests/qtest/tpm-tis-swtpm-test.c index fa590e68f115..11539c0a5268 100644 --- a/tests/qtest/tpm-tis-swtpm-test.c +++ b/tests/qtest/tpm-tis-swtpm-test.c @@ -13,9 +13,8 @@ */ #include "qemu/osdep.h" -#include -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "tpm-tests.h" #include "hw/acpi/tpm.h" @@ -61,9 +60,9 @@ int main(int argc, char **argv) tpm_tis_swtpm_migration_test); ret = g_test_run(); - g_rmdir(ts.dst_tpm_path); + tpm_util_rmdir(ts.dst_tpm_path); g_free(ts.dst_tpm_path); - g_rmdir(ts.src_tpm_path); + tpm_util_rmdir(ts.src_tpm_path); g_free(ts.src_tpm_path); g_free(ts.uri); diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c index 3a40ff3f96c2..a7efe2d0d2c4 100644 --- a/tests/qtest/tpm-util.c +++ b/tests/qtest/tpm-util.c @@ -13,9 +13,10 @@ */ #include "qemu/osdep.h" +#include #include "hw/acpi/tpm.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "tpm-util.h" #include "qapi/qmp/qdict.h" @@ -292,3 +293,21 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, g_free(src_qemu_args); g_free(dst_qemu_args); } + +/* Remove directory with remainders of swtpm */ +void tpm_util_rmdir(const char *path) +{ + char *filename; + int ret; + + filename = g_strdup_printf("%s/tpm2-00.permall", path); + g_unlink(filename); + g_free(filename); + + filename = g_strdup_printf("%s/.lock", path); + g_unlink(filename); + g_free(filename); + + ret = g_rmdir(path); + g_assert(!ret); +} diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h index 3b97d690170c..80720afac0ad 100644 --- a/tests/qtest/tpm-util.h +++ b/tests/qtest/tpm-util.h @@ -53,5 +53,6 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, const char *machine_options); void tpm_util_wait_for_migration_complete(QTestState *who); +void tpm_util_rmdir(const char *path); #endif /* TESTS_TPM_UTIL_H */ diff --git a/tests/qtest/tulip-test.c b/tests/qtest/tulip-test.c index da16cbfafcc2..2fb6c4d5a781 100644 --- a/tests/qtest/tulip-test.c +++ b/tests/qtest/tulip-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/usb-hcd-uhci-test.c b/tests/qtest/usb-hcd-uhci-test.c index 7a117b64d90c..f264d2bf734d 100644 --- a/tests/qtest/usb-hcd-uhci-test.c +++ b/tests/qtest/usb-hcd-uhci-test.c @@ -72,9 +72,9 @@ int main(int argc, char **argv) qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qs = qtest_pc_boot(cmd); + qs = qtest_pc_boot("%s", cmd); } else if (strcmp(arch, "ppc64") == 0) { - qs = qtest_spapr_boot(cmd); + qs = qtest_spapr_boot("%s", cmd); } else { g_printerr("usb-hcd-uhci-test tests are only " "available on x86 or ppc64\n"); diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c index 62e670f39be0..dc37f5af4d15 100644 --- a/tests/qtest/vhost-user-blk-test.c +++ b/tests/qtest/vhost-user-blk-test.c @@ -37,7 +37,7 @@ typedef struct QVirtioBlkReq { uint8_t status; } QVirtioBlkReq; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN static const bool host_is_big_endian = true; #else static const bool host_is_big_endian; /* false */ @@ -676,6 +676,11 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QVirtioPCIDevice *dev; QTestState *qts = dev1->pdev->bus->qts; + if (dev1->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + /* plug secondary disk */ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1", "{'addr': %s, 'chardev': 'char2'}", @@ -703,6 +708,11 @@ static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc) uint64_t features; uint16_t num_queues; + if (pdev1->pdev->bus->not_hotpluggable) { + g_test_skip("bus pci.0 does not support hotplug"); + return; + } + /* * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is @@ -831,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); @@ -972,6 +983,12 @@ static void register_vhost_user_blk_test(void) .before = vhost_user_blk_test_setup, }; + if (!getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY")) { + g_test_message("QTEST_QEMU_STORAGE_DAEMON_BINARY not defined, " + "skipping vhost-user-blk-test"); + return; + } + /* * tests for vhost-user-blk and vhost-user-blk-pci * The tests are borrowed from tests/virtio-blk-test.c. But some tests diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c index ee30f5479648..bf9f7c4248ca 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) { @@ -302,6 +324,7 @@ static int chr_can_read(void *opaque) static void chr_read(void *opaque, const uint8_t *buf, int size) { + g_autoptr(GError) err = NULL; TestServer *s = opaque; CharBackend *chr = &s->chr; VhostUserMsg msg; @@ -315,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; } @@ -326,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: @@ -356,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; @@ -394,7 +462,8 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) * The receive function forces it to be blocking, * so revert it back to non-blocking. */ - qemu_set_nonblock(fd); + g_unix_set_fd_nonblocking(fd, true, &err); + g_assert_no_error(err); break; case VHOST_USER_SET_LOG_BASE: @@ -425,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; } @@ -448,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; } @@ -458,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; } @@ -480,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); @@ -489,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("Can't create temporary directory in %s: %s", + g_get_tmp_dir(), err->message); + g_error_free(err); } g_assert(tmpfs); @@ -522,14 +604,13 @@ static void chr_event(void *opaque, QEMUChrEvent event) static void test_server_create_chr(TestServer *server, const gchar *opt) { - gchar *chr_path; + g_autofree gchar *chr_path = g_strdup_printf("unix:%s%s", + server->socket_path, opt); Chardev *chr; - chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt); chr = qemu_chr_new(server->chr_name, chr_path, server->context); - g_free(chr_path); + g_assert(chr); - g_assert_nonnull(chr); qemu_chr_fe_init(&server->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, chr_event, NULL, server, server->context, true); @@ -935,11 +1016,23 @@ static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc) wait_for_rings_started(s, s->queues * 2); } + +static uint64_t vu_net_get_features(TestServer *s) +{ + 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) + VhostUserMsg *msg) { - g_assert_cmpint(msg->payload.u64 & - (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL); + 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; @@ -966,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, }; @@ -1014,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-9p-test.c b/tests/qtest/virtio-9p-test.c index e28c71bd8f79..65e69491e5ad 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -13,76 +13,27 @@ */ #include "qemu/osdep.h" -#include "libqtest-single.h" #include "qemu/module.h" -#include "hw/9pfs/9p.h" -#include "hw/9pfs/9p-synth.h" -#include "libqos/virtio-9p.h" -#include "libqos/qgraph.h" - -#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) -static QGuestAllocator *alloc; - -/* - * Used to auto generate new fids. Start with arbitrary high value to avoid - * collision with hard coded fids in basic test code. - */ -static uint32_t fid_generator = 1000; - -static uint32_t genfid(void) -{ - return fid_generator++; -} - -/** - * Splits the @a in string by @a delim into individual (non empty) strings - * and outputs them to @a out. The output array @a out is NULL terminated. - * - * Output array @a out must be freed by calling split_free(). - * - * @returns number of individual elements in output array @a out (without the - * final NULL terminating element) - */ -static int split(const char *in, const char *delim, char ***out) -{ - int n = 0, i = 0; - char *tmp, *p; - - tmp = g_strdup(in); - for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) { - if (strlen(p) > 0) { - ++n; - } - } - g_free(tmp); - - *out = g_new0(char *, n + 1); /* last element NULL delimiter */ - - tmp = g_strdup(in); - for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) { - if (strlen(p) > 0) { - (*out)[i++] = g_strdup(p); - } - } - g_free(tmp); - - return n; -} - -static void split_free(char ***out) -{ - int i; - for (i = 0; (*out)[i]; ++i) { - g_free((*out)[i]); - } - g_free(*out); - *out = NULL; -} +#include "libqos/virtio-9p-client.h" + +#define twalk(...) v9fs_twalk((TWalkOpt) __VA_ARGS__) +#define tversion(...) v9fs_tversion((TVersionOpt) __VA_ARGS__) +#define tattach(...) v9fs_tattach((TAttachOpt) __VA_ARGS__) +#define tgetattr(...) v9fs_tgetattr((TGetAttrOpt) __VA_ARGS__) +#define treaddir(...) v9fs_treaddir((TReadDirOpt) __VA_ARGS__) +#define tlopen(...) v9fs_tlopen((TLOpenOpt) __VA_ARGS__) +#define twrite(...) v9fs_twrite((TWriteOpt) __VA_ARGS__) +#define tflush(...) v9fs_tflush((TFlushOpt) __VA_ARGS__) +#define tmkdir(...) v9fs_tmkdir((TMkdirOpt) __VA_ARGS__) +#define tlcreate(...) v9fs_tlcreate((TlcreateOpt) __VA_ARGS__) +#define tsymlink(...) v9fs_tsymlink((TsymlinkOpt) __VA_ARGS__) +#define tlink(...) v9fs_tlink((TlinkOpt) __VA_ARGS__) +#define tunlinkat(...) v9fs_tunlinkat((TunlinkatOpt) __VA_ARGS__) static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); size_t tag_len = qvirtio_config_readw(v9p->vdev, 0); g_autofree char *tag = NULL; int i; @@ -96,556 +47,43 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len); } -#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ - -typedef struct { - QTestState *qts; - QVirtio9P *v9p; - uint16_t tag; - uint64_t t_msg; - uint32_t t_size; - uint64_t r_msg; - /* No r_size, it is hardcoded to P9_MAX_SIZE */ - size_t t_off; - size_t r_off; - uint32_t free_head; -} P9Req; - -static void v9fs_memwrite(P9Req *req, const void *addr, size_t len) -{ - qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len); - req->t_off += len; -} - -static void v9fs_memskip(P9Req *req, size_t len) -{ - req->r_off += len; -} - -static void v9fs_memread(P9Req *req, void *addr, size_t len) -{ - qtest_memread(req->qts, req->r_msg + req->r_off, addr, len); - req->r_off += len; -} - -static void v9fs_uint8_read(P9Req *req, uint8_t *val) -{ - v9fs_memread(req, val, 1); -} - -static void v9fs_uint16_write(P9Req *req, uint16_t val) -{ - uint16_t le_val = cpu_to_le16(val); - - v9fs_memwrite(req, &le_val, 2); -} - -static void v9fs_uint16_read(P9Req *req, uint16_t *val) -{ - v9fs_memread(req, val, 2); - le16_to_cpus(val); -} - -static void v9fs_uint32_write(P9Req *req, uint32_t val) -{ - uint32_t le_val = cpu_to_le32(val); - - v9fs_memwrite(req, &le_val, 4); -} - -static void v9fs_uint64_write(P9Req *req, uint64_t val) -{ - uint64_t le_val = cpu_to_le64(val); - - v9fs_memwrite(req, &le_val, 8); -} - -static void v9fs_uint32_read(P9Req *req, uint32_t *val) -{ - v9fs_memread(req, val, 4); - le32_to_cpus(val); -} - -static void v9fs_uint64_read(P9Req *req, uint64_t *val) -{ - v9fs_memread(req, val, 8); - le64_to_cpus(val); -} - -/* len[2] string[len] */ -static uint16_t v9fs_string_size(const char *string) -{ - size_t len = strlen(string); - - g_assert_cmpint(len, <=, UINT16_MAX - 2); - - return 2 + len; -} - -static void v9fs_string_write(P9Req *req, const char *string) -{ - int len = strlen(string); - - g_assert_cmpint(len, <=, UINT16_MAX); - - v9fs_uint16_write(req, (uint16_t) len); - v9fs_memwrite(req, string, len); -} - -static void v9fs_string_read(P9Req *req, uint16_t *len, char **string) -{ - uint16_t local_len; - - v9fs_uint16_read(req, &local_len); - if (len) { - *len = local_len; - } - if (string) { - *string = g_malloc(local_len + 1); - v9fs_memread(req, *string, local_len); - (*string)[local_len] = 0; - } else { - v9fs_memskip(req, local_len); - } -} - - typedef struct { - uint32_t size; - uint8_t id; - uint16_t tag; -} QEMU_PACKED P9Hdr; - -static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, - uint16_t tag) -{ - P9Req *req = g_new0(P9Req, 1); - uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */ - P9Hdr hdr = { - .id = id, - .tag = cpu_to_le16(tag) - }; - - g_assert_cmpint(total_size, <=, UINT32_MAX - size); - total_size += size; - hdr.size = cpu_to_le32(total_size); - - g_assert_cmpint(total_size, <=, P9_MAX_SIZE); - - req->qts = global_qtest; - req->v9p = v9p; - req->t_size = total_size; - req->t_msg = guest_alloc(alloc, req->t_size); - v9fs_memwrite(req, &hdr, 7); - req->tag = tag; - return req; -} - -static void v9fs_req_send(P9Req *req) -{ - QVirtio9P *v9p = req->v9p; - - req->r_msg = guest_alloc(alloc, P9_MAX_SIZE); - req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size, - false, true); - qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); - qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head); - req->t_off = 0; -} - -static const char *rmessage_name(uint8_t id) -{ - return - id == P9_RLERROR ? "RLERROR" : - id == P9_RVERSION ? "RVERSION" : - id == P9_RATTACH ? "RATTACH" : - id == P9_RWALK ? "RWALK" : - id == P9_RLOPEN ? "RLOPEN" : - id == P9_RWRITE ? "RWRITE" : - id == P9_RMKDIR ? "RMKDIR" : - id == P9_RLCREATE ? "RLCREATE" : - id == P9_RSYMLINK ? "RSYMLINK" : - id == P9_RLINK ? "RLINK" : - id == P9_RUNLINKAT ? "RUNLINKAT" : - id == P9_RFLUSH ? "RFLUSH" : - id == P9_RREADDIR ? "READDIR" : - ""; -} - -static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len) -{ - QVirtio9P *v9p = req->v9p; - - qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len, - QVIRTIO_9P_TIMEOUT_US); -} - -static void v9fs_req_recv(P9Req *req, uint8_t id) -{ - P9Hdr hdr; - - v9fs_memread(req, &hdr, 7); - hdr.size = ldl_le_p(&hdr.size); - hdr.tag = lduw_le_p(&hdr.tag); - - g_assert_cmpint(hdr.size, >=, 7); - g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE); - g_assert_cmpint(hdr.tag, ==, req->tag); - - if (hdr.id != id) { - g_printerr("Received response %d (%s) instead of %d (%s)\n", - hdr.id, rmessage_name(hdr.id), id, rmessage_name(id)); - - if (hdr.id == P9_RLERROR) { - uint32_t err; - v9fs_uint32_read(req, &err); - g_printerr("Rlerror has errno %d (%s)\n", err, strerror(err)); - } - } - g_assert_cmpint(hdr.id, ==, id); -} - -static void v9fs_req_free(P9Req *req) -{ - guest_free(alloc, req->t_msg); - guest_free(alloc, req->r_msg); - g_free(req); -} - -/* size[4] Rlerror tag[2] ecode[4] */ -static void v9fs_rlerror(P9Req *req, uint32_t *err) -{ - v9fs_req_recv(req, P9_RLERROR); - v9fs_uint32_read(req, err); - v9fs_req_free(req); -} - -/* size[4] Tversion tag[2] msize[4] version[s] */ -static P9Req *v9fs_tversion(QVirtio9P *v9p, uint32_t msize, const char *version, - uint16_t tag) -{ - P9Req *req; - uint32_t body_size = 4; - uint16_t string_size = v9fs_string_size(version); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - req = v9fs_req_init(v9p, body_size, P9_TVERSION, tag); - - v9fs_uint32_write(req, msize); - v9fs_string_write(req, version); - v9fs_req_send(req); - return req; -} - -/* size[4] Rversion tag[2] msize[4] version[s] */ -static void v9fs_rversion(P9Req *req, uint16_t *len, char **version) -{ - uint32_t msize; - - v9fs_req_recv(req, P9_RVERSION); - v9fs_uint32_read(req, &msize); - - g_assert_cmpint(msize, ==, P9_MAX_SIZE); - - if (len || version) { - v9fs_string_read(req, len, version); - } - - v9fs_req_free(req); -} - -/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ -static P9Req *v9fs_tattach(QVirtio9P *v9p, uint32_t fid, uint32_t n_uname, - uint16_t tag) -{ - const char *uname = ""; /* ignored by QEMU */ - const char *aname = ""; /* ignored by QEMU */ - P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag); - - v9fs_uint32_write(req, fid); - v9fs_uint32_write(req, P9_NOFID); - v9fs_string_write(req, uname); - v9fs_string_write(req, aname); - v9fs_uint32_write(req, n_uname); - v9fs_req_send(req); - return req; -} - -typedef char v9fs_qid[13]; - -/* size[4] Rattach tag[2] qid[13] */ -static void v9fs_rattach(P9Req *req, v9fs_qid *qid) -{ - v9fs_req_recv(req, P9_RATTACH); - if (qid) { - v9fs_memread(req, qid, 13); - } - v9fs_req_free(req); -} - -/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ -static P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid, - uint16_t nwname, char *const wnames[], uint16_t tag) -{ - P9Req *req; - int i; - uint32_t body_size = 4 + 4 + 2; - - for (i = 0; i < nwname; i++) { - uint16_t wname_size = v9fs_string_size(wnames[i]); - - g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size); - body_size += wname_size; - } - req = v9fs_req_init(v9p, body_size, P9_TWALK, tag); - v9fs_uint32_write(req, fid); - v9fs_uint32_write(req, newfid); - v9fs_uint16_write(req, nwname); - for (i = 0; i < nwname; i++) { - v9fs_string_write(req, wnames[i]); - } - v9fs_req_send(req); - return req; -} - -/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */ -static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) -{ - uint16_t local_nwqid; - - v9fs_req_recv(req, P9_RWALK); - v9fs_uint16_read(req, &local_nwqid); - if (nwqid) { - *nwqid = local_nwqid; - } - if (wqid) { - *wqid = g_malloc(local_nwqid * 13); - v9fs_memread(req, *wqid, local_nwqid * 13); - } - v9fs_req_free(req); -} - -/* size[4] Treaddir tag[2] fid[4] offset[8] count[4] */ -static P9Req *v9fs_treaddir(QVirtio9P *v9p, uint32_t fid, uint64_t offset, - uint32_t count, uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 4 + 8 + 4, P9_TREADDIR, tag); - v9fs_uint32_write(req, fid); - v9fs_uint64_write(req, offset); - v9fs_uint32_write(req, count); - v9fs_req_send(req); - return req; -} - -struct V9fsDirent { - v9fs_qid qid; - uint64_t offset; - uint8_t type; - char *name; - struct V9fsDirent *next; -}; - -/* size[4] Rreaddir tag[2] count[4] data[count] */ -static void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, - struct V9fsDirent **entries) -{ - uint32_t local_count; - struct V9fsDirent *e = NULL; - uint16_t slen; - uint32_t n = 0; - - v9fs_req_recv(req, P9_RREADDIR); - v9fs_uint32_read(req, &local_count); - - if (count) { - *count = local_count; - } - - for (int32_t togo = (int32_t)local_count; - togo >= 13 + 8 + 1 + 2; - togo -= 13 + 8 + 1 + 2 + slen, ++n) - { - if (!e) { - e = g_new(struct V9fsDirent, 1); - if (entries) { - *entries = e; - } - } else { - e = e->next = g_new(struct V9fsDirent, 1); - } - e->next = NULL; - /* qid[13] offset[8] type[1] name[s] */ - v9fs_memread(req, &e->qid, 13); - v9fs_uint64_read(req, &e->offset); - v9fs_uint8_read(req, &e->type); - v9fs_string_read(req, &slen, &e->name); - } - - if (nentries) { - *nentries = n; - } - - v9fs_req_free(req); -} - -static void v9fs_free_dirents(struct V9fsDirent *e) -{ - struct V9fsDirent *next = NULL; - - for (; e; e = next) { - next = e->next; - g_free(e->name); - g_free(e); - } -} - -/* size[4] Tlopen tag[2] fid[4] flags[4] */ -static P9Req *v9fs_tlopen(QVirtio9P *v9p, uint32_t fid, uint32_t flags, - uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 4 + 4, P9_TLOPEN, tag); - v9fs_uint32_write(req, fid); - v9fs_uint32_write(req, flags); - v9fs_req_send(req); - return req; -} - -/* size[4] Rlopen tag[2] qid[13] iounit[4] */ -static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit) -{ - v9fs_req_recv(req, P9_RLOPEN); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - if (iounit) { - v9fs_uint32_read(req, iounit); - } - v9fs_req_free(req); -} - -/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */ -static P9Req *v9fs_twrite(QVirtio9P *v9p, uint32_t fid, uint64_t offset, - uint32_t count, const void *data, uint16_t tag) -{ - P9Req *req; - uint32_t body_size = 4 + 8 + 4; - - g_assert_cmpint(body_size, <=, UINT32_MAX - count); - body_size += count; - req = v9fs_req_init(v9p, body_size, P9_TWRITE, tag); - v9fs_uint32_write(req, fid); - v9fs_uint64_write(req, offset); - v9fs_uint32_write(req, count); - v9fs_memwrite(req, data, count); - v9fs_req_send(req); - return req; -} - -/* size[4] Rwrite tag[2] count[4] */ -static void v9fs_rwrite(P9Req *req, uint32_t *count) -{ - v9fs_req_recv(req, P9_RWRITE); - if (count) { - v9fs_uint32_read(req, count); - } - v9fs_req_free(req); -} - -/* size[4] Tflush tag[2] oldtag[2] */ -static P9Req *v9fs_tflush(QVirtio9P *v9p, uint16_t oldtag, uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 2, P9_TFLUSH, tag); - v9fs_uint32_write(req, oldtag); - v9fs_req_send(req); - return req; -} - -/* size[4] Rflush tag[2] */ -static void v9fs_rflush(P9Req *req) -{ - v9fs_req_recv(req, P9_RFLUSH); - v9fs_req_free(req); -} - -static void do_version(QVirtio9P *v9p) -{ - const char *version = "9P2000.L"; - uint16_t server_len; - g_autofree char *server_version = NULL; - P9Req *req; - - req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rversion(req, &server_len, &server_version); - - g_assert_cmpmem(server_version, server_len, version, strlen(version)); -} - -/* utility function: walk to requested dir and return fid for that dir */ -static uint32_t do_walk(QVirtio9P *v9p, const char *path) +static inline bool is_same_qid(v9fs_qid a, v9fs_qid b) { - char **wnames; - P9Req *req; - const uint32_t fid = genfid(); - - int nwnames = split(path, "/", &wnames); - - req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); - - split_free(&wnames); - return fid; + /* don't compare QID version for checking for file ID equalness */ + return a[0] == b[0] && memcmp(&a[5], &b[5], 8) == 0; } static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; - do_version(obj); -} - -static void do_attach(QVirtio9P *v9p) -{ - P9Req *req; - - do_version(v9p); - req = v9fs_tattach(v9p, 0, getuid(), 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rattach(req, NULL); + v9fs_set_allocator(t_alloc); + tversion({ .client = obj }); } static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; - do_attach(obj); + v9fs_set_allocator(t_alloc); + tattach({ .client = obj }); } static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); char *wnames[P9_MAXWELEM]; uint16_t nwqid; g_autofree v9fs_qid *wqid = NULL; int i; - P9Req *req; for (i = 0; i < P9_MAXWELEM; i++) { wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); } - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, &nwqid, &wqid); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, + .nwname = P9_MAXWELEM, .wnames = wnames, + .rwalk = { .nwqid = &nwqid, .wqid = &wqid } + }); g_assert_cmpint(nwqid, ==, P9_MAXWELEM); @@ -664,192 +102,37 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, const char* name) return false; } -/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */ -static P9Req *v9fs_tmkdir(QVirtio9P *v9p, uint32_t dfid, const char *name, - uint32_t mode, uint32_t gid, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TMKDIR, tag); - v9fs_uint32_write(req, dfid); - v9fs_string_write(req, name); - v9fs_uint32_write(req, mode); - v9fs_uint32_write(req, gid); - v9fs_req_send(req); - return req; -} - -/* size[4] Rmkdir tag[2] qid[13] */ -static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid) -{ - v9fs_req_recv(req, P9_RMKDIR); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - v9fs_req_free(req); -} - -/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */ -static P9Req *v9fs_tlcreate(QVirtio9P *v9p, uint32_t fid, const char *name, - uint32_t flags, uint32_t mode, uint32_t gid, - uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4 + 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TLCREATE, tag); - v9fs_uint32_write(req, fid); - v9fs_string_write(req, name); - v9fs_uint32_write(req, flags); - v9fs_uint32_write(req, mode); - v9fs_uint32_write(req, gid); - v9fs_req_send(req); - return req; -} - -/* size[4] Rlcreate tag[2] qid[13] iounit[4] */ -static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit) -{ - v9fs_req_recv(req, P9_RLCREATE); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - if (iounit) { - v9fs_uint32_read(req, iounit); - } - v9fs_req_free(req); -} - -/* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */ -static P9Req *v9fs_tsymlink(QVirtio9P *v9p, uint32_t fid, const char *name, - const char *symtgt, uint32_t gid, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4; - uint16_t string_size = v9fs_string_size(name) + v9fs_string_size(symtgt); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TSYMLINK, tag); - v9fs_uint32_write(req, fid); - v9fs_string_write(req, name); - v9fs_string_write(req, symtgt); - v9fs_uint32_write(req, gid); - v9fs_req_send(req); - return req; -} - -/* size[4] Rsymlink tag[2] qid[13] */ -static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid) -{ - v9fs_req_recv(req, P9_RSYMLINK); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - v9fs_req_free(req); -} - -/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */ -static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid, - const char *name, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TLINK, tag); - v9fs_uint32_write(req, dfid); - v9fs_uint32_write(req, fid); - v9fs_string_write(req, name); - v9fs_req_send(req); - return req; -} - -/* size[4] Rlink tag[2] */ -static void v9fs_rlink(P9Req *req) -{ - v9fs_req_recv(req, P9_RLINK); - v9fs_req_free(req); -} - -/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */ -static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name, - uint32_t flags, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TUNLINKAT, tag); - v9fs_uint32_write(req, dirfd); - v9fs_string_write(req, name); - v9fs_uint32_write(req, flags); - v9fs_req_send(req); - return req; -} - -/* size[4] Runlinkat tag[2] */ -static void v9fs_runlinkat(P9Req *req) -{ - v9fs_req_recv(req, P9_RUNLINKAT); - v9fs_req_free(req); -} - /* basic readdir test where reply fits into a single response message */ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; uint16_t nqid; v9fs_qid qid; uint32_t count, nentries; struct V9fsDirent *entries = NULL; - P9Req *req; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, &nqid, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, + .nwname = 1, .wnames = wnames, .rwalk.nwqid = &nqid + }); g_assert_cmpint(nqid, ==, 1); - req = v9fs_tlopen(v9p, 1, O_DIRECTORY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, &qid, NULL); + tlopen({ + .client = v9p, .fid = 1, .flags = O_DIRECTORY, .rlopen.qid = &qid + }); /* * submit count = msize - 11, because 11 is the header size of Rreaddir */ - req = v9fs_treaddir(v9p, 1, 0, P9_MAX_SIZE - 11, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rreaddir(req, &count, &nentries, &entries); + treaddir({ + .client = v9p, .fid = 1, .offset = 0, .count = P9_MAX_SIZE - 11, + .rreaddir = { + .count = &count, .nentries = &nentries, .entries = &entries + } + }); /* * Assuming msize (P9_MAX_SIZE) is large enough so we can retrieve all @@ -879,16 +162,15 @@ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) /* readdir test where overall request is split over several messages */ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) { - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; uint16_t nqid; v9fs_qid qid; uint32_t nentries, npartialentries; struct V9fsDirent *entries, *tail, *partialentries; - P9Req *req; int fid; uint64_t offset; - do_attach(v9p); + tattach({ .client = v9p }); fid = 1; offset = 0; @@ -896,14 +178,15 @@ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) nentries = 0; tail = NULL; - req = v9fs_twalk(v9p, 0, fid, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, &nqid, NULL); + twalk({ + .client = v9p, .fid = 0, .newfid = fid, + .nwname = 1, .wnames = wnames, .rwalk.nwqid = &nqid + }); g_assert_cmpint(nqid, ==, 1); - req = v9fs_tlopen(v9p, fid, O_DIRECTORY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, &qid, NULL); + tlopen({ + .client = v9p, .fid = fid, .flags = O_DIRECTORY, .rlopen.qid = &qid + }); /* * send as many Treaddir requests as required to get all directory @@ -913,9 +196,13 @@ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) npartialentries = 0; partialentries = NULL; - req = v9fs_treaddir(v9p, fid, offset, count, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rreaddir(req, &count, &npartialentries, &partialentries); + treaddir({ + .client = v9p, .fid = fid, .offset = offset, .count = count, + .rreaddir = { + .count = &count, .nentries = &npartialentries, + .entries = &partialentries + } + }); if (npartialentries > 0 && partialentries) { if (!entries) { entries = partialentries; @@ -959,38 +246,113 @@ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(" /") }; - P9Req *req; - uint32_t err; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(" /") }; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlerror(req, &err); - - g_assert_cmpint(err, ==, ENOENT); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames, + .expectErr = ENOENT + }); g_free(wnames[0]); } +static void fs_walk_nonexistent(void *obj, void *data, QGuestAllocator *t_alloc) +{ + QVirtio9P *v9p = obj; + v9fs_set_allocator(t_alloc); + + tattach({ .client = v9p }); + /* + * The 9p2000 protocol spec says: "If the first element cannot be walked + * for any reason, Rerror is returned." + */ + twalk({ .client = v9p, .path = "non-existent", .expectErr = ENOENT }); +} + +static void fs_walk_2nd_nonexistent(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + QVirtio9P *v9p = obj; + v9fs_set_allocator(t_alloc); + v9fs_qid root_qid; + uint16_t nwqid; + uint32_t fid; + g_autofree v9fs_qid *wqid = NULL; + g_autofree char *path = g_strdup_printf( + QTEST_V9FS_SYNTH_WALK_FILE "/non-existent", 0 + ); + + tattach({ .client = v9p, .rattach.qid = &root_qid }); + fid = twalk({ + .client = v9p, .path = path, + .rwalk = { .nwqid = &nwqid, .wqid = &wqid } + }).newfid; + /* + * The 9p2000 protocol spec says: "nwqid is therefore either nwname or the + * index of the first elementwise walk that failed." + */ + assert(nwqid == 1); + + /* returned QID wqid[0] is file ID of 1st subdir */ + g_assert(wqid && wqid[0] && !is_same_qid(root_qid, wqid[0])); + + /* expect fid being unaffected by walk above */ + tgetattr({ + .client = v9p, .fid = fid, .request_mask = P9_GETATTR_BASIC, + .expectErr = ENOENT + }); +} + +static void fs_walk_none(void *obj, void *data, QGuestAllocator *t_alloc) +{ + QVirtio9P *v9p = obj; + v9fs_set_allocator(t_alloc); + v9fs_qid root_qid; + g_autofree v9fs_qid *wqid = NULL; + struct v9fs_attr attr; + + tversion({ .client = v9p }); + tattach({ + .client = v9p, .fid = 0, .n_uname = getuid(), + .rattach.qid = &root_qid + }); + + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 0, .wnames = NULL, + .rwalk.wqid = &wqid + }); + + /* special case: no QID is returned if nwname=0 was sent */ + g_assert(wqid == NULL); + + tgetattr({ + .client = v9p, .fid = 1, .request_mask = P9_GETATTR_BASIC, + .rgetattr.attr = &attr + }); + + g_assert(is_same_qid(root_qid, attr.qid)); +} + static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup("..") }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup("..") }; v9fs_qid root_qid; g_autofree v9fs_qid *wqid = NULL; - P9Req *req; - do_version(v9p); - req = v9fs_tattach(v9p, 0, getuid(), 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rattach(req, &root_qid); + tversion({ .client = v9p }); + tattach({ + .client = v9p, .fid = 0, .n_uname = getuid(), + .rattach.qid = &root_qid + }); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */ + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames, + .rwalk.wqid = &wqid /* We now we'll get one qid */ + }); g_assert_cmpmem(&root_qid, 13, wqid[0], 13); @@ -1000,18 +362,15 @@ static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; - P9Req *req; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); g_free(wnames[0]); } @@ -1019,25 +378,23 @@ static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); static const uint32_t write_count = P9_MAX_SIZE / 2; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; g_autofree char *buf = g_malloc0(write_count); uint32_t count; - P9Req *req; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); - req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwrite(req, &count); + count = twrite({ + .client = v9p, .fid = 1, .offset = 0, .count = write_count, + .data = buf + }).count; g_assert_cmpint(count, ==, write_count); g_free(wnames[0]); @@ -1046,28 +403,32 @@ static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; P9Req *req, *flush_req; uint32_t reply_len; uint8_t should_block; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); /* This will cause the 9p server to try to write data to the backend, * until the write request gets cancelled. */ should_block = 1; - req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0); + req = twrite({ + .client = v9p, .fid = 1, .offset = 0, + .count = sizeof(should_block), .data = &should_block, + .requestOnly = true + }).req; - flush_req = v9fs_tflush(v9p, req->tag, 1); + flush_req = tflush({ + .client = v9p, .oldtag = req->tag, .tag = 1, .requestOnly = true + }).req; /* The write request is supposed to be flushed: the server should just * mark the write request as used and reply to the flush request. @@ -1083,28 +444,32 @@ static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; P9Req *req, *flush_req; uint32_t count; uint8_t should_block; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); /* This will cause the write request to complete right away, before it * could be actually cancelled. */ should_block = 0; - req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0); + req = twrite({ + .client = v9p, .fid = 1, .offset = 0, + .count = sizeof(should_block), .data = &should_block, + .requestOnly = true + }).req; - flush_req = v9fs_tflush(v9p, req->tag, 1); + flush_req = tflush({ + .client = v9p, .oldtag = req->tag, .tag = 1, .requestOnly = true + }).req; /* The write request is supposed to complete. The server should * reply to the write request and the flush request. @@ -1117,99 +482,24 @@ static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) g_free(wnames[0]); } -static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname) -{ - g_autofree char *name = g_strdup(cname); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, path); - - req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rmkdir(req, NULL); -} - -/* create a regular file with Tlcreate and return file's fid */ -static uint32_t do_lcreate(QVirtio9P *v9p, const char *path, - const char *cname) -{ - g_autofree char *name = g_strdup(cname); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, path); - - req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlcreate(req, NULL, NULL); - - return fid; -} - -/* create symlink named @a clink in directory @a path pointing to @a to */ -static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink, - const char *to) -{ - g_autofree char *name = g_strdup(clink); - g_autofree char *dst = g_strdup(to); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, path); - - req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rsymlink(req, NULL); -} - -/* create a hard link named @a clink in directory @a path pointing to @a to */ -static void do_hardlink(QVirtio9P *v9p, const char *path, const char *clink, - const char *to) -{ - uint32_t dfid, fid; - P9Req *req; - - dfid = do_walk(v9p, path); - fid = do_walk(v9p, to); - - req = v9fs_tlink(v9p, dfid, fid, clink, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlink(req); -} - -static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath, - uint32_t flags) -{ - g_autofree char *name = g_strdup(rpath); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, atpath); - - req = v9fs_tunlinkat(v9p, fid, name, flags, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_runlinkat(req); -} - static void fs_readdir_split_128(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; + v9fs_set_allocator(t_alloc); do_readdir_split(obj, 128); } static void fs_readdir_split_256(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; + v9fs_set_allocator(t_alloc); do_readdir_split(obj, 256); } static void fs_readdir_split_512(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; + v9fs_set_allocator(t_alloc); do_readdir_split(obj, 512); } @@ -1219,15 +509,15 @@ static void fs_readdir_split_512(void *obj, void *data, static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *root_path = virtio_9p_test_path(""); g_autofree char *new_dir = virtio_9p_test_path("01"); g_assert(root_path != NULL); - do_attach(v9p); - do_mkdir(v9p, "/", "01"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "01" }); /* check if created directory really exists now ... */ g_assert(stat(new_dir, &st) == 0); @@ -1238,22 +528,25 @@ static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *root_path = virtio_9p_test_path(""); g_autofree char *new_dir = virtio_9p_test_path("02"); g_assert(root_path != NULL); - do_attach(v9p); - do_mkdir(v9p, "/", "02"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "02" }); /* check if created directory really exists now ... */ g_assert(stat(new_dir, &st) == 0); /* ... and is actually a directory */ g_assert((st.st_mode & S_IFMT) == S_IFDIR); - do_unlinkat(v9p, "/", "02", P9_DOTL_AT_REMOVEDIR); + tunlinkat({ + .client = v9p, .atPath = "/", .name = "02", + .flags = P9_DOTL_AT_REMOVEDIR + }); /* directory should be gone now */ g_assert(stat(new_dir, &st) != 0); } @@ -1261,13 +554,13 @@ static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *new_file = virtio_9p_test_path("03/1st_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "03"); - do_lcreate(v9p, "03", "1st_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "03" }); + tlcreate({ .client = v9p, .atPath = "03", .name = "1st_file" }); /* check if created file exists now ... */ g_assert(stat(new_file, &st) == 0); @@ -1278,20 +571,20 @@ static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *new_file = virtio_9p_test_path("04/doa_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "04"); - do_lcreate(v9p, "04", "doa_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "04" }); + tlcreate({ .client = v9p, .atPath = "04", .name = "doa_file" }); /* check if created file exists now ... */ g_assert(stat(new_file, &st) == 0); /* ... and is a regular file */ g_assert((st.st_mode & S_IFMT) == S_IFREG); - do_unlinkat(v9p, "04", "doa_file", 0); + tunlinkat({ .client = v9p, .atPath = "04", .name = "doa_file" }); /* file should be gone now */ g_assert(stat(new_file, &st) != 0); } @@ -1299,18 +592,21 @@ static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *real_file = virtio_9p_test_path("05/real_file"); g_autofree char *symlink_file = virtio_9p_test_path("05/symlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "05"); - do_lcreate(v9p, "05", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "05" }); + tlcreate({ .client = v9p, .atPath = "05", .name = "real_file" }); g_assert(stat(real_file, &st) == 0); g_assert((st.st_mode & S_IFMT) == S_IFREG); - do_symlink(v9p, "05", "symlink_file", "real_file"); + tsymlink({ + .client = v9p, .atPath = "05", .name = "symlink_file", + .symtgt = "real_file" + }); /* check if created link exists now */ g_assert(stat(symlink_file, &st) == 0); @@ -1320,21 +616,24 @@ static void fs_unlinkat_symlink(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *real_file = virtio_9p_test_path("06/real_file"); g_autofree char *symlink_file = virtio_9p_test_path("06/symlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "06"); - do_lcreate(v9p, "06", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "06" }); + tlcreate({ .client = v9p, .atPath = "06", .name = "real_file" }); g_assert(stat(real_file, &st) == 0); g_assert((st.st_mode & S_IFMT) == S_IFREG); - do_symlink(v9p, "06", "symlink_file", "real_file"); + tsymlink({ + .client = v9p, .atPath = "06", .name = "symlink_file", + .symtgt = "real_file" + }); g_assert(stat(symlink_file, &st) == 0); - do_unlinkat(v9p, "06", "symlink_file", 0); + tunlinkat({ .client = v9p, .atPath = "06", .name = "symlink_file" }); /* symlink should be gone now */ g_assert(stat(symlink_file, &st) != 0); } @@ -1342,18 +641,21 @@ static void fs_unlinkat_symlink(void *obj, void *data, static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st_real, st_link; g_autofree char *real_file = virtio_9p_test_path("07/real_file"); g_autofree char *hardlink_file = virtio_9p_test_path("07/hardlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "07"); - do_lcreate(v9p, "07", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "07" }); + tlcreate({ .client = v9p, .atPath = "07", .name = "real_file" }); g_assert(stat(real_file, &st_real) == 0); g_assert((st_real.st_mode & S_IFMT) == S_IFREG); - do_hardlink(v9p, "07", "hardlink_file", "07/real_file"); + tlink({ + .client = v9p, .atPath = "07", .name = "hardlink_file", + .toPath = "07/real_file" + }); /* check if link exists now ... */ g_assert(stat(hardlink_file, &st_link) == 0); @@ -1367,21 +669,24 @@ static void fs_unlinkat_hardlink(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st_real, st_link; g_autofree char *real_file = virtio_9p_test_path("08/real_file"); g_autofree char *hardlink_file = virtio_9p_test_path("08/hardlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "08"); - do_lcreate(v9p, "08", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "08" }); + tlcreate({ .client = v9p, .atPath = "08", .name = "real_file" }); g_assert(stat(real_file, &st_real) == 0); g_assert((st_real.st_mode & S_IFMT) == S_IFREG); - do_hardlink(v9p, "08", "hardlink_file", "08/real_file"); + tlink({ + .client = v9p, .atPath = "08", .name = "hardlink_file", + .toPath = "08/real_file" + }); g_assert(stat(hardlink_file, &st_link) == 0); - do_unlinkat(v9p, "08", "hardlink_file", 0); + tunlinkat({ .client = v9p, .atPath = "08", .name = "hardlink_file" }); /* symlink should be gone now */ g_assert(stat(hardlink_file, &st_link) != 0); /* and old file should still exist */ @@ -1407,8 +712,13 @@ static void register_virtio_9p_test(void) qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, &opts); qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash, &opts); + qos_add_test("synth/walk/none", "virtio-9p", fs_walk_none, &opts); qos_add_test("synth/walk/dotdot_from_root", "virtio-9p", fs_walk_dotdot, &opts); + qos_add_test("synth/walk/non_existent", "virtio-9p", fs_walk_nonexistent, + &opts); + qos_add_test("synth/walk/2nd_non_existent", "virtio-9p", + fs_walk_2nd_nonexistent, &opts); qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, &opts); qos_add_test("synth/write/basic", "virtio-9p", fs_write, &opts); qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success, diff --git a/tests/qtest/virtio-blk-test.c b/tests/qtest/virtio-blk-test.c index 2a236982118f..19c01f808b1d 100644 --- a/tests/qtest/virtio-blk-test.c +++ b/tests/qtest/virtio-blk-test.c @@ -33,7 +33,7 @@ typedef struct QVirtioBlkReq { } QVirtioBlkReq; -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN const bool host_is_big_endian = true; #else const bool host_is_big_endian; /* false */ @@ -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); @@ -701,6 +701,11 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QVirtioPCIDevice *dev; QTestState *qts = dev1->pdev->bus->qts; + if (dev1->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + /* plug secondary disk */ qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1", "{'addr': %s, 'drive': 'drive1'}", diff --git a/tests/qtest/virtio-ccw-test.c b/tests/qtest/virtio-ccw-test.c index d05236407b0e..2de77bb6fe19 100644 --- a/tests/qtest/virtio-ccw-test.c +++ b/tests/qtest/virtio-ccw-test.c @@ -95,8 +95,6 @@ static void virtio_scsi_hotplug(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); qtest_add_func("/virtio/balloon/nop", virtio_balloon_nop); qtest_add_func("/virtio/console/nop", virtconsole_nop); @@ -109,7 +107,5 @@ int main(int argc, char **argv) qtest_add_func("/virtio/scsi/nop", virtio_scsi_nop); qtest_add_func("/virtio/scsi/hotplug", virtio_scsi_hotplug); - ret = g_test_run(); - - return ret; + return g_test_run(); } diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c index 78811f1c9216..4a809590bf79 100644 --- a/tests/qtest/virtio-net-failover.c +++ b/tests/qtest/virtio-net-failover.c @@ -8,7 +8,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" #include "qapi/qmp/qdict.h" @@ -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 a71395849f33..dff43f0f60ec 100644 --- a/tests/qtest/virtio-net-test.c +++ b/tests/qtest/virtio-net-test.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "libqtest-single.h" #include "qemu/iov.h" #include "qemu/module.h" @@ -166,14 +165,17 @@ 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; QTestState *qts = dev->pdev->bus->qts; const char *arch = qtest_get_arch(); + if (dev->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + qtest_qmp_device_add(qts, "virtio-net-pci", "net1", "{'addr': %s}", stringify(PCI_SLOT_HP)); @@ -282,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; @@ -315,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-rng-test.c b/tests/qtest/virtio-rng-test.c index e6b8cd8e0cfa..64e131cd8c9a 100644 --- a/tests/qtest/virtio-rng-test.c +++ b/tests/qtest/virtio-rng-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/virtio-rng.h" @@ -20,6 +20,11 @@ static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc) QVirtioPCIDevice *dev = obj; QTestState *qts = dev->pdev->bus->qts; + if (dev->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + const char *arch = qtest_get_arch(); qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1", diff --git a/tests/qtest/virtio-scsi-test.c b/tests/qtest/virtio-scsi-test.c index 8ceb12aacdf6..ceaa7f2415be 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/qtest/virtio-test.c b/tests/qtest/virtio-test.c index 63134176303a..f7c6afdcf111 100644 --- a/tests/qtest/virtio-test.c +++ b/tests/qtest/virtio-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/vmgenid-test.c b/tests/qtest/vmgenid-test.c index 6781a514479b..efba76e7164e 100644 --- a/tests/qtest/vmgenid-test.c +++ b/tests/qtest/vmgenid-test.c @@ -14,7 +14,7 @@ #include "hw/acpi/acpi-defs.h" #include "boot-sector.h" #include "acpi-utils.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87" diff --git a/tests/qtest/vmxnet3-test.c b/tests/qtest/vmxnet3-test.c index 97c23fd3a8f6..a81025252c87 100644 --- a/tests/qtest/vmxnet3-test.c +++ b/tests/qtest/vmxnet3-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qemu/module.h" #include "libqos/qgraph.h" #include "libqos/pci.h" diff --git a/tests/qtest/vnc-display-test.c b/tests/qtest/vnc-display-test.c new file mode 100644 index 000000000000..e2a9d682bb69 --- /dev/null +++ b/tests/qtest/vnc-display-test.c @@ -0,0 +1,103 @@ +/* + * VNC display tests + * + * 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 "qemu/sockets.h" +#include "libqtest.h" +#include +#include + +typedef struct Test { + QTestState *qts; + VncConnection *conn; + GMainLoop *loop; +} Test; + +static void on_vnc_error(VncConnection* self, + const char* msg) +{ + g_error("vnc-error: %s", msg); +} + +static void on_vnc_auth_failure(VncConnection *self, + const char *msg) +{ + g_error("vnc-auth-failure: %s", msg); +} + +static bool +test_setup(Test *test) +{ +#ifdef WIN32 + g_test_skip("Not supported on Windows yet"); + return false; +#else + int pair[2]; + + test->qts = qtest_init("-vnc none -name vnc-test"); + + g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); + + qtest_qmp_add_client(test->qts, "vnc", pair[1]); + + test->conn = vnc_connection_new(); + g_signal_connect(test->conn, "vnc-error", + G_CALLBACK(on_vnc_error), NULL); + g_signal_connect(test->conn, "vnc-auth-failure", + G_CALLBACK(on_vnc_auth_failure), NULL); + vnc_connection_set_auth_type(test->conn, VNC_CONNECTION_AUTH_NONE); + vnc_connection_open_fd(test->conn, pair[0]); + + test->loop = g_main_loop_new(NULL, FALSE); + return true; +#endif +} + +static void +test_vnc_basic_on_vnc_initialized(VncConnection *self, + Test *test) +{ + const char *name = vnc_connection_get_name(test->conn); + + g_assert_cmpstr(name, ==, "QEMU (vnc-test)"); + g_main_loop_quit(test->loop); +} + +static void +test_vnc_basic(void) +{ + Test test; + + if (!test_setup(&test)) { + return; + } + + g_signal_connect(test.conn, "vnc-initialized", + G_CALLBACK(test_vnc_basic_on_vnc_initialized), &test); + + g_main_loop_run(test.loop); + + qtest_quit(test.qts); + g_object_unref(test.conn); + g_main_loop_unref(test.loop); +} + +int +main(int argc, char **argv) +{ + if (getenv("GTK_VNC_DEBUG")) { + vnc_util_set_debug(true); + } + + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/vnc-display/basic", test_vnc_basic); + + return g_test_run(); +} diff --git a/tests/qtest/wdt_ib700-test.c b/tests/qtest/wdt_ib700-test.c index 6c36e43fb835..797288d939fa 100644 --- a/tests/qtest/wdt_ib700-test.c +++ b/tests/qtest/wdt_ib700-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" #include "qapi/qmp/qdict.h" #include "qemu/timer.h" diff --git a/tests/qtest/xlnx-can-test.c b/tests/qtest/xlnx-can-test.c index 54de71a68643..89610fc499b6 100644 --- a/tests/qtest/xlnx-can-test.c +++ b/tests/qtest/xlnx-can-test.c @@ -25,7 +25,7 @@ */ #include "qemu/osdep.h" -#include "libqos/libqtest.h" +#include "libqtest.h" /* Base address. */ #define CAN0_BASE_ADDR 0xFF060000 diff --git a/tests/requirements.txt b/tests/requirements.txt index a21b59b44397..0ba561b6bdf0 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,6 @@ # Add Python module requirements, one per line, to be installed # in the tests/venv Python virtual environment. For more info, # refer to: https://pip.pypa.io/en/stable/user_guide/#id1 +# Note that qemu.git/python/ is always implicitly installed. avocado-framework==88.1 pycdlib==1.11.0 diff --git a/tests/tcg/Makefile.prereqs b/tests/tcg/Makefile.prereqs deleted file mode 100644 index 9a29604a839f..000000000000 --- a/tests/tcg/Makefile.prereqs +++ /dev/null @@ -1,18 +0,0 @@ -# -*- Mode: makefile -*- -# -# TCG Compiler Probe -# -# This Makefile fragment is included multiple times in the main make -# script to probe for available compilers. This is used to build up a -# selection of required docker targets before we invoke a sub-make for -# each target. - -DOCKER_IMAGE:= - --include $(BUILD_DIR)/tests/tcg/config-$(PROBE_TARGET).mak - -ifneq ($(DOCKER_IMAGE),) -build-tcg-tests-$(PROBE_TARGET): docker-image-$(DOCKER_IMAGE) -endif -$(BUILD_DIR)/tests/tcg/config_$(PROBE_TARGET).mak: config-host.mak -config-host.mak: $(SRC_PATH)/tests/tcg/configure.sh diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu deleted file mode 100644 index 84c8543878bf..000000000000 --- a/tests/tcg/Makefile.qemu +++ /dev/null @@ -1,121 +0,0 @@ -# -*- Mode: makefile -*- -# -# TCG tests (per-target rules) -# -# This Makefile fragment is included from the build-tcg target, once -# for each target we build. We have two options for compiling, either -# using a configured guest compiler or calling one of our docker images -# to do it for us. -# - -# The configure script fills in extra information about -# useful docker images or alternative compiler flags. - -# Usage: $(call quiet-command,command and args,"NAME","args to print") -# This will run "command and args", and either: -# if V=1 just print the whole command and args -# otherwise print the 'quiet' output in the format " NAME args to print" -# NAME should be a short name of the command, 7 letters or fewer. -# If called with only a single argument, will print nothing in quiet mode. -quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1 -quiet-@ = $(if $(V),,@) -quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3) - -CROSS_CC_GUEST:= -CROSS_AS_GUEST:= -CROSS_LD_GUEST:= -DOCKER_IMAGE:= - --include tests/tcg/config-$(TARGET).mak - -GUEST_BUILD= -TCG_MAKE=../Makefile.target - -# We also need the Docker make rules to depend on -SKIP_DOCKER_BUILD=1 -include $(SRC_PATH)/tests/docker/Makefile.include - -# Support installed Cross Compilers - -ifdef CROSS_CC_GUEST - -.PHONY: cross-build-guest-tests -cross-build-guest-tests: - $(call quiet-command, \ - (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \ - $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC="$(CROSS_CC_GUEST)" \ - $(if $(CROSS_AS_GUEST),AS="$(CROSS_AS_GUEST)") \ - $(if $(CROSS_LD_GUEST),LD="$(CROSS_LD_GUEST)") \ - SRC_PATH="$(SRC_PATH)" BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \ - EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ - "BUILD","$(TARGET) guest-tests with $(CROSS_CC_GUEST)") - -GUEST_BUILD=cross-build-guest-tests - -endif - -# Support building with Docker - -ifneq ($(DOCKER_IMAGE),) - -DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc \ - --cc $(DOCKER_CROSS_CC_GUEST) \ - -i qemu/$(DOCKER_IMAGE) \ - -s $(SRC_PATH) -- " - -DOCKER_AS_CMD=$(if $(DOCKER_CROSS_AS_GUEST),"$(DOCKER_SCRIPT) cc \ - --cc $(DOCKER_CROSS_AS_GUEST) \ - -i qemu/$(DOCKER_IMAGE) \ - -s $(SRC_PATH) -- ") - -DOCKER_LD_CMD=$(if $(DOCKER_CROSS_LD_GUEST),"$(DOCKER_SCRIPT) cc \ - --cc $(DOCKER_CROSS_LD_GUEST) \ - -i qemu/$(DOCKER_IMAGE) \ - -s $(SRC_PATH) -- ") - - -.PHONY: docker-build-guest-tests -docker-build-guest-tests: docker-image-$(DOCKER_IMAGE) - $(call quiet-command, \ - (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \ - $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC=$(DOCKER_COMPILE_CMD) \ - $(if $(DOCKER_AS_CMD),AS=$(DOCKER_AS_CMD)) \ - $(if $(DOCKER_LD_CMD),LD=$(DOCKER_LD_CMD)) \ - SRC_PATH="$(SRC_PATH)" BUILD_STATIC=y \ - EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ - "BUILD","$(TARGET) guest-tests with docker qemu/$(DOCKER_IMAGE)") - -GUEST_BUILD=docker-build-guest-tests - -endif - -# Final targets -all: - @echo "Do not invoke this Makefile directly"; exit 1 - -.PHONY: guest-tests - -ifneq ($(GUEST_BUILD),) -guest-tests: $(GUEST_BUILD) - -run-guest-tests: guest-tests - $(call quiet-command, \ - (cd tests/tcg/$(TARGET) && \ - $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" \ - SRC_PATH="$(SRC_PATH)" SPEED=$(SPEED) run), \ - "RUN", "tests for $(TARGET_NAME)") - -else -guest-tests: - $(call quiet-command, true, "BUILD", \ - "$(TARGET) guest-tests SKIPPED") - -run-guest-tests: - $(call quiet-command, true, "RUN", \ - "tests for $(TARGET) SKIPPED") -endif - -# It doesn't matter if these don't exits -.PHONY: clean-guest-tests -clean-guest-tests: - rm -rf tests/tcg/$(TARGET) diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target deleted file mode 100644 index acda5bcec29f..000000000000 --- a/tests/tcg/Makefile.target +++ /dev/null @@ -1,190 +0,0 @@ -# -*- Mode: makefile -*- -# -# TCG tests -# -# These are complicated by the fact we want to build them for guest -# systems. This requires knowing what guests we are building and which -# ones we have cross-compilers for or docker images with -# cross-compilers. -# -# The tests themselves should be as minimal as possible as -# cross-compilers don't always have a large amount of libraries -# available. -# -# We only include the host build system for SRC_PATH and we don't -# bother with the common rules.mk. We expect the following: -# -# CC - the C compiler command -# EXTRA_CFLAGS - any extra CFLAGS -# BUILD_STATIC - are we building static binaries -# -# By default all tests are statically compiled but some host systems -# may not package static libraries by default. If an external -# cross-compiler can only build dynamic libraries the user might need -# to make extra efforts to ensure ld.so can link at runtime when the -# tests are run. -# -# We also accept SPEED=slow to enable slower running tests -# -# We also expect to be in the tests build dir for the FOO-(linux-user|softmmu). -# - -all: --include ../../../config-host.mak --include ../config-$(TARGET).mak - -# Get semihosting definitions for user-mode emulation -ifeq ($(CONFIG_USER_ONLY),y) --include $(SRC_PATH)/configs/targets/$(TARGET).mak -endif - -# for including , in command strings -COMMA := , - -quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) - -# $1 = test name, $2 = cmd, $3 = desc -ifdef CONFIG_USER_ONLY -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2 > $1.out, \ - "TEST",$3) -else -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2,"TEST",$3) -endif - -# $1 = test name, $2 = reference -# to work around the pipe squashing the status we only pipe the result if -# 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") - -# $1 = test name, $2 = reason -skip-test = @printf " SKIPPED %s on $(TARGET_NAME) because %s\n" $1 $2 - -# $1 = test name, $2 = reference -# As above but only diff if reference file exists, otherwise the test -# passes if it managed to complete with a status of zero -conditional-diff-out = \ - $(if $(wildcard $2), \ - $(call diff-out,$1,$2), \ - $(call skip-test,"$1 check","no reference")) - - -# Tests we are building -TESTS= -# additional tests which may re-use existing binaries -EXTRA_TESTS= - -# Start with a blank slate, the build targets get to add stuff first -CFLAGS= -QEMU_CFLAGS= -LDFLAGS= - -QEMU_OPTS= - - -# If TCG debugging, or TCI is enabled things are a lot slower -# ??? Makefile no longer has any indication that TCI is enabled, -# but for the record: -# 15s original default -# 60s with --enable-debug -# 90s with --enable-tcg-interpreter -TIMEOUT=90 - -ifdef CONFIG_USER_ONLY -# The order we include is important. We include multiarch first and -# then the target. If there are common tests shared between -# sub-targets (e.g. ARM & AArch64) then it is up to -# $(TARGET_NAME)/Makefile.target to include the common parent -# architecture in its VPATH. --include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target --include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target - -# Add the common build options -CFLAGS+=-Wall -Werror -O0 -g -fno-strict-aliasing -ifeq ($(BUILD_STATIC),y) -LDFLAGS+=-static -endif - -%: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -else -# For softmmu targets we include a different Makefile fragement as the -# build options for bare programs are usually pretty different. They -# are expected to provide their own build recipes. --include $(SRC_PATH)/tests/tcg/minilib/Makefile.target --include $(SRC_PATH)/tests/tcg/multiarch/system/Makefile.softmmu-target --include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target - -endif - -all: $(TESTS) $(EXTRA_TESTS) - -# -# Test Runners -# -# By default we just run the test with the appropriate QEMU for the -# target. More advanced tests may want to override the runner in their -# specific make rules. Additional runners for the same binary should -# be added to EXTRA_RUNS. -# - -RUN_TESTS=$(patsubst %,run-%, $(TESTS)) - -# If plugins exist also include those in the tests -ifeq ($(CONFIG_PLUGIN),y) -PLUGIN_SRC=$(SRC_PATH)/tests/plugin -PLUGIN_LIB=../../plugin -VPATH+=$(PLUGIN_LIB) -PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))) - -# We need to ensure expand the run-plugin-TEST-with-PLUGIN -# pre-requistes manually here as we can't use stems to handle it. We -# also add some special helpers the run-plugin- rules can use bellow. - -$(foreach p,$(PLUGINS), \ - $(foreach t,$(TESTS),\ - $(eval run-plugin-$(t)-with-$(p): $t $p) \ - $(eval RUN_TESTS+=run-plugin-$(t)-with-$(p)))) -endif - -strip-plugin = $(wordlist 1, 1, $(subst -with-, ,$1)) -extract-plugin = $(wordlist 2, 2, $(subst -with-, ,$1)) - -RUN_TESTS+=$(EXTRA_RUNS) - -ifdef CONFIG_USER_ONLY -run-%: % - $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<, "$< on $(TARGET_NAME)") - -run-plugin-%: - $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ - -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ - -d plugin -D $*.pout \ - $(call strip-plugin,$<), \ - "$* on $(TARGET_NAME)") -else -run-%: % - $(call run-test, $<, \ - $(QEMU) -monitor none -display none \ - -chardev file$(COMMA)path=$<.out$(COMMA)id=output \ - $(QEMU_OPTS) $<, \ - "$< on $(TARGET_NAME)") - -run-plugin-%: - $(call run-test, $@, \ - $(QEMU) -monitor none -display none \ - -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)") -endif - -gdb-%: % - gdb --args $(QEMU) $(QEMU_OPTS) $< - -.PHONY: run -run: $(RUN_TESTS) - -# There is no clean target, the calling make just rm's the tests build dir diff --git a/tests/tcg/README b/tests/tcg/README deleted file mode 100644 index 706bb185b42a..000000000000 --- a/tests/tcg/README +++ /dev/null @@ -1,9 +0,0 @@ -This directory contains various interesting guest programs for -regression testing. Tests are either multi-arch, meaning they can be -built for all guest architectures that support linux-user executable, -or they are architecture specific. - -CRIS -==== -The testsuite for CRIS is in tests/tcg/cris. You can run it -with "make test-cris". diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target deleted file mode 100644 index a7286ac29523..000000000000 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ /dev/null @@ -1,76 +0,0 @@ -# -# Aarch64 system tests -# - -AARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/aarch64/system -VPATH+=$(AARCH64_SYSTEM_SRC) - -# These objects provide the basic boot code and helper functions for all tests -CRT_OBJS=boot.o - -AARCH64_TEST_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c) -AARCH64_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_SRCS)) - -CRT_PATH=$(AARCH64_SYSTEM_SRC) -LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld -LDFLAGS=-Wl,-T$(LINK_SCRIPT) -TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS) -EXTRA_RUNS+=$(MULTIARCH_RUNS) -CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) -LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc - -# building head blobs -.PRECIOUS: $(CRT_OBJS) - -%.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@ - -# Build and link the tests -%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -memory: CFLAGS+=-DCHECK_UNALIGNED=1 - -# Running -QEMU_BASE_MACHINE=-M virt -cpu max -display none -QEMU_OPTS+=$(QEMU_BASE_MACHINE) -semihosting-config enable=on,target=native,chardev=output -kernel - -# console test is manual only -QEMU_SEMIHOST=-chardev stdio,mux=on,id=stdio0 -semihosting-config enable=on,chardev=stdio0 -mon chardev=stdio0,mode=readline -run-semiconsole: QEMU_OPTS=$(QEMU_BASE_MACHINE) $(QEMU_SEMIHOST) -kernel -run-semiconsole: semiconsole - $(call skip-test, $<, "MANUAL ONLY") -run-plugin-semiconsole-with-%: semiconsole - $(call skip-test, $<, "MANUAL ONLY") - -# Simple Record/Replay Test -.PHONY: memory-record -run-memory-record: memory-record memory - $(call run-test, $<, \ - $(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)") - -.PHONY: memory-replay -run-memory-replay: memory-replay run-memory-record - $(call run-test, $<, \ - $(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)") - -EXTRA_RUNS+=run-memory-replay - -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),) -pauth-3: CFLAGS += -march=armv8.3-a -else -pauth-3: - $(call skip-test, "BUILD of $@", "missing compiler support") -run-pauth-3: - $(call skip-test, "RUN of pauth-3", "not built") -run-plugin-pauth-3-with-%: - $(call skip-test, "RUN of pauth-3 ($*)", "not built") -endif diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target deleted file mode 100644 index f7121cb4d880..000000000000 --- a/tests/tcg/aarch64/Makefile.target +++ /dev/null @@ -1,96 +0,0 @@ -# -*- Mode: makefile -*- -# -# AArch64 specific tweaks - -ARM_SRC=$(SRC_PATH)/tests/tcg/arm -VPATH += $(ARM_SRC) - -AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64 -VPATH += $(AARCH64_SRC) - -# Base architecture tests -AARCH64_TESTS=fcvt pcalign-a64 - -fcvt: LDFLAGS+=-lm - -run-fcvt: fcvt - $(call run-test,$<,$(QEMU) $<, "$< on $(TARGET_NAME)") - $(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref) - -# Pauth Tests -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),) -AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5 -pauth-%: CFLAGS += -march=armv8.3-a -run-pauth-%: QEMU_OPTS += -cpu max -run-plugin-pauth-%: QEMU_OPTS += -cpu max -endif - -# BTI Tests -# bti-1 tests the elf notes, so we require special compiler support. -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_BTI),) -AARCH64_TESTS += bti-1 -bti-1: CFLAGS += -mbranch-protection=standard -bti-1: LDFLAGS += -nostdlib -endif -# bti-2 tests PROT_BTI, so no special compiler support required. -AARCH64_TESTS += bti-2 - -# MTE Tests -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_MTE),) -AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 -mte-%: CFLAGS += -march=armv8.5-a+memtag -endif - -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_SVE),) -# System Registers Tests -AARCH64_TESTS += sysregs -sysregs: CFLAGS+=-march=armv8.1-a+sve - -# SVE ioctl test -AARCH64_TESTS += sve-ioctls -sve-ioctls: CFLAGS+=-march=armv8.1-a+sve - -# Vector SHA1 -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 diff-out, sha1-vector, sha1.out) - -TESTS += sha1-vector - -# Vector versions of sha512 (-O3 triggers vectorisation) -sha512-vector: CFLAGS=-O3 -sha512-vector: sha512.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -TESTS += sha512-vector - -ifneq ($(HAVE_GDB_BIN),) -GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py - -run-gdbstub-sysregs: sysregs - $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ - --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ - --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve.py, \ - "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") - -EXTRA_RUNS += run-gdbstub-sysregs run-gdbstub-sve-ioctls -endif -endif - -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_SVE2),) -AARCH64_TESTS += test-826 -test-826: CFLAGS+=-march=armv8.1-a+sve2 -endif - -TESTS += $(AARCH64_TESTS) diff --git a/tests/tcg/aarch64/bti-1.c b/tests/tcg/aarch64/bti-1.c deleted file mode 100644 index 61924f0d7a4c..000000000000 --- a/tests/tcg/aarch64/bti-1.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Branch target identification, basic notskip cases. - */ - -#include "bti-crt.inc.c" - -static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc) -{ - uc->uc_mcontext.pc += 8; - uc->uc_mcontext.pstate = 1; -} - -#define NOP "nop" -#define BTI_N "hint #32" -#define BTI_C "hint #34" -#define BTI_J "hint #36" -#define BTI_JC "hint #38" - -#define BTYPE_1(DEST) \ - asm("mov %0,#1; adr x16, 1f; br x16; 1: " DEST "; mov %0,#0" \ - : "=r"(skipped) : : "x16") - -#define BTYPE_2(DEST) \ - asm("mov %0,#1; adr x16, 1f; blr x16; 1: " DEST "; mov %0,#0" \ - : "=r"(skipped) : : "x16", "x30") - -#define BTYPE_3(DEST) \ - asm("mov %0,#1; adr x15, 1f; br x15; 1: " DEST "; mov %0,#0" \ - : "=r"(skipped) : : "x15") - -#define TEST(WHICH, DEST, EXPECT) \ - do { WHICH(DEST); fail += skipped ^ EXPECT; } while (0) - - -int main() -{ - int fail = 0; - int skipped; - - /* Signal-like with SA_SIGINFO. */ - signal_info(SIGILL, skip2_sigill); - - TEST(BTYPE_1, NOP, 1); - TEST(BTYPE_1, BTI_N, 1); - TEST(BTYPE_1, BTI_C, 0); - TEST(BTYPE_1, BTI_J, 0); - TEST(BTYPE_1, BTI_JC, 0); - - TEST(BTYPE_2, NOP, 1); - TEST(BTYPE_2, BTI_N, 1); - TEST(BTYPE_2, BTI_C, 0); - TEST(BTYPE_2, BTI_J, 1); - TEST(BTYPE_2, BTI_JC, 0); - - TEST(BTYPE_3, NOP, 1); - TEST(BTYPE_3, BTI_N, 1); - TEST(BTYPE_3, BTI_C, 1); - TEST(BTYPE_3, BTI_J, 0); - TEST(BTYPE_3, BTI_JC, 0); - - return fail; -} diff --git a/tests/tcg/aarch64/bti-2.c b/tests/tcg/aarch64/bti-2.c deleted file mode 100644 index 65e8e857ddac..000000000000 --- a/tests/tcg/aarch64/bti-2.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Branch target identification, basic notskip cases. - */ - -#include -#include -#include -#include -#include - -#ifndef PROT_BTI -#define PROT_BTI 0x10 -#endif - -static void skip2_sigill(int sig, siginfo_t *info, void *vuc) -{ - ucontext_t *uc = vuc; - uc->uc_mcontext.pc += 8; - uc->uc_mcontext.pstate = 1; -} - -#define NOP "nop" -#define BTI_N "hint #32" -#define BTI_C "hint #34" -#define BTI_J "hint #36" -#define BTI_JC "hint #38" - -#define BTYPE_1(DEST) \ - "mov x1, #1\n\t" \ - "adr x16, 1f\n\t" \ - "br x16\n" \ -"1: " DEST "\n\t" \ - "mov x1, #0" - -#define BTYPE_2(DEST) \ - "mov x1, #1\n\t" \ - "adr x16, 1f\n\t" \ - "blr x16\n" \ -"1: " DEST "\n\t" \ - "mov x1, #0" - -#define BTYPE_3(DEST) \ - "mov x1, #1\n\t" \ - "adr x15, 1f\n\t" \ - "br x15\n" \ -"1: " DEST "\n\t" \ - "mov x1, #0" - -#define TEST(WHICH, DEST, EXPECT) \ - WHICH(DEST) "\n" \ - ".if " #EXPECT "\n\t" \ - "eor x1, x1," #EXPECT "\n" \ - ".endif\n\t" \ - "add x0, x0, x1\n\t" - -asm("\n" -"test_begin:\n\t" - BTI_C "\n\t" - "mov x2, x30\n\t" - "mov x0, #0\n\t" - - TEST(BTYPE_1, NOP, 1) - TEST(BTYPE_1, BTI_N, 1) - TEST(BTYPE_1, BTI_C, 0) - TEST(BTYPE_1, BTI_J, 0) - TEST(BTYPE_1, BTI_JC, 0) - - TEST(BTYPE_2, NOP, 1) - TEST(BTYPE_2, BTI_N, 1) - TEST(BTYPE_2, BTI_C, 0) - TEST(BTYPE_2, BTI_J, 1) - TEST(BTYPE_2, BTI_JC, 0) - - TEST(BTYPE_3, NOP, 1) - TEST(BTYPE_3, BTI_N, 1) - TEST(BTYPE_3, BTI_C, 1) - TEST(BTYPE_3, BTI_J, 0) - TEST(BTYPE_3, BTI_JC, 0) - - "ret x2\n" -"test_end:" -); - -int main() -{ - struct sigaction sa; - void *tb, *te; - - void *p = mmap(0, getpagesize(), - PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) { - perror("mmap"); - return 1; - } - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = skip2_sigill; - sa.sa_flags = SA_SIGINFO; - if (sigaction(SIGILL, &sa, NULL) < 0) { - perror("sigaction"); - return 1; - } - - /* - * ??? With "extern char test_begin[]", some compiler versions - * will use :got references, and some linker versions will - * resolve this reference to a static symbol incorrectly. - * Bypass this error by using a pc-relative reference directly. - */ - asm("adr %0, test_begin; adr %1, test_end" : "=r"(tb), "=r"(te)); - - memcpy(p, tb, te - tb); - - return ((int (*)(void))p)(); -} diff --git a/tests/tcg/aarch64/bti-crt.inc.c b/tests/tcg/aarch64/bti-crt.inc.c deleted file mode 100644 index 47805f4e35bb..000000000000 --- a/tests/tcg/aarch64/bti-crt.inc.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Minimal user-environment for testing BTI. - * - * Normal libc is not (yet) built with BTI support enabled, - * and so could generate a BTI TRAP before ever reaching main. - */ - -#include -#include -#include -#include - -int main(void); - -void _start(void) -{ - exit(main()); -} - -void exit(int ret) -{ - register int x0 __asm__("x0") = ret; - register int x8 __asm__("x8") = __NR_exit; - - asm volatile("svc #0" : : "r"(x0), "r"(x8)); - __builtin_unreachable(); -} - -/* - * Irritatingly, the user API struct sigaction does not match the - * kernel API struct sigaction. So for simplicity, isolate the - * kernel ABI here, and make this act like signal. - */ -void signal_info(int sig, void (*fn)(int, siginfo_t *, ucontext_t *)) -{ - struct kernel_sigaction { - void (*handler)(int, siginfo_t *, ucontext_t *); - unsigned long flags; - unsigned long restorer; - unsigned long mask; - } sa = { fn, SA_SIGINFO, 0, 0 }; - - register int x0 __asm__("x0") = sig; - register void *x1 __asm__("x1") = &sa; - register void *x2 __asm__("x2") = 0; - register int x3 __asm__("x3") = sizeof(unsigned long); - register int x8 __asm__("x8") = __NR_rt_sigaction; - - asm volatile("svc #0" - : : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory"); -} diff --git a/tests/tcg/aarch64/fcvt.ref b/tests/tcg/aarch64/fcvt.ref deleted file mode 100644 index e7af24dc58a8..000000000000 --- a/tests/tcg/aarch64/fcvt.ref +++ /dev/null @@ -1,3268 +0,0 @@ -#### Enabling IEEE Half Precision -### Rounding to nearest -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0x7f00 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x400 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x4170 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4248 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bff (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7bff (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7c00 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0x7e00 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0x7e00 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0x7f00 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -nan / 0x00fffffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -nan / 0x00fffbfc0000000000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -nan / 0x00fff8040000000000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: nan / 0x007ff8040000000000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: nan / 0x007ffbfc0000000000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: nan / 0x007ffffc0000000000 (0 => OK) -### Rounding upwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x400 (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x401 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4249 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0x7f00 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x400 (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x401 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x4170 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4249 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bff (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7c00 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0x7e00 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0x7e00 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0x7f00 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766502400000000000e+09 / 0x4f730c3b (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962457600000000000e+09 / 0x4f71605e (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638080000000000000e+08 / 0x4e4c0001 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896384000000000000e+08 / 0x4e61ff01 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912768000000000000e+08 / 0x4e620001 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -nan / 0x00fffffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -nan / 0x00fffbfc0000000000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -nan / 0x00fff8040000000000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: nan / 0x007ff8040000000000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: nan / 0x007ffbfc0000000000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: nan / 0x007ffffc0000000000 (0 => OK) -### Rounding downwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730512e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0x7f00 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x400 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x416f (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4248 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bfe (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7bff (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7c00 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0x7e00 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0x7e00 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0x7f00 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -nan / 0x00fffffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -nan / 0x00fffbfc0000000000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -nan / 0x00fff8040000000000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: nan / 0x007ff8040000000000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: nan / 0x007ffbfc0000000000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: nan / 0x007ffffc0000000000 (0 => OK) -### Rounding to zero -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0x7f00 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x400 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x416f (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4248 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bfe (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7bff (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7c00 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0x7e00 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0x7e00 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0x7f00 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -nan / 0x00fffffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -nan / 0x00fffbfc0000000000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -nan / 0x00fff8040000000000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: nan / 0x007ff8040000000000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: nan / 0x007ffbfc0000000000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: nan / 0x007ffffc0000000000 (0 => OK) -Converting single-precision to integer -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 INT64: 1/0x000000000000000001 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 INT64: 2/0x000000000000000002 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 INT64: 65503/0x00000000000000ffdf (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 INT64: 65504/0x00000000000000ffe0 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 INT64: 65505/0x00000000000000ffe1 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 INT64: 131007/0x00000000000001ffbf (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 INT64: 131008/0x00000000000001ffc0 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 INT64: 131009/0x00000000000001ffc1 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 INT64: 0/00000000000000000000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting double-precision to integer -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 INT64: -2/0x00fffffffffffffffe (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 INT64: -1/0x00ffffffffffffffff (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 INT64: 0/00000000000000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 INT64: 1/0x000000000000000001 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 INT64: 1/0x000000000000000001 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 INT64: 2/0x000000000000000002 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 INT64: 65503/0x00000000000000ffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 INT64: 65504/0x00000000000000ffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 INT64: 65505/0x00000000000000ffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 INT64: 131007/0x00000000000001ffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 INT64: 131008/0x00000000000001ffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 INT64: 131009/0x00000000000001ffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 INT64: 2147483647/0x00000000007fffffff (0 => OK) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 INT64: 0/00000000000000000000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 INT64: 0/00000000000000000000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting half-precision to integer -00 HALF: 0xffff (0 => OK) -00 INT64: 4294959104/0x0000000000ffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 INT64: 4292861952/0x0000000000ffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 INT64: 4290781184/0x0000000000ffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 INT64: 4286578688/0x0000000000ff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 INT64: 3347046400/0x0000000000c77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 INT64: 3221225472/0x0000000000c0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 INT64: 3212836864/0x0000000000bf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 INT64: 3011510272/0x0000000000b3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 INT64: 2147483648/0x000000000080000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 INT64: 864026624/0x000000000033800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 INT64: 1065353216/0x00000000003f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 INT64: 1199562752/0x0000000000477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 INT64: 2139095040/0x00000000007f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 INT64: 2143297536/0x00000000007fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 INT64: 2145378304/0x00000000007fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 INT64: 2147475456/0x00000000007fffe000 (0 => OK) -#### Enabling ARM Alternative Half Precision -### Rounding to nearest -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7fff (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xffff (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xffff (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x400 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x4170 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4248 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bff (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7bff (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7fff (0x10 => INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7fff (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7fff (0x10 => INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7fff (0x1 => INVALID) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7fff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7fff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7fff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7fff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -1.31008000000000000000e+05 / 0x00c0fffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -8.18560000000000000000e+04 / 0x00c0f3fc0000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -6.56000000000000000000e+04 / 0x00c0f0040000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -6.55360000000000000000e+04 / 0x00c0f0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 6.55360000000000000000e+04 / 0x0040f0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 6.56000000000000000000e+04 / 0x0040f0040000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 8.18560000000000000000e+04 / 0x0040f3fc0000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -### Rounding upwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x400 (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x401 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4249 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7c00 (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7fff (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x1 => INVALID) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xffff (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xffff (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x400 (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x401 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x4170 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4249 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bff (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7c00 (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7fff (0x10 => INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7fff (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7fff (0x1 => INVALID) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7fff (0x1 => INVALID) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7fff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7fff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7fff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7fff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766502400000000000e+09 / 0x4f730c3b (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962457600000000000e+09 / 0x4f71605e (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638080000000000000e+08 / 0x4e4c0001 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896384000000000000e+08 / 0x4e61ff01 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912768000000000000e+08 / 0x4e620001 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -1.31008000000000000000e+05 / 0x00c0fffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -8.18560000000000000000e+04 / 0x00c0f3fc0000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -6.56000000000000000000e+04 / 0x00c0f0040000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -6.55360000000000000000e+04 / 0x00c0f0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 6.55360000000000000000e+04 / 0x0040f0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 6.56000000000000000000e+04 / 0x0040f0040000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 8.18560000000000000000e+04 / 0x0040f3fc0000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -### Rounding downwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7ffe (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730512e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xffff (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xffff (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x400 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x416f (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4248 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bfe (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7bff (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7ffe (0x10 => INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7fff (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7fff (0x10 => INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7fff (0x1 => INVALID) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7fff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7fff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7fff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7fff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -1.31008000000000000000e+05 / 0x00c0fffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -8.18560000000000000000e+04 / 0x00c0f3fc0000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -6.56000000000000000000e+04 / 0x00c0f0040000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -6.55360000000000000000e+04 / 0x00c0f0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 6.55360000000000000000e+04 / 0x0040f0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 6.56000000000000000000e+04 / 0x0040f0040000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 8.18560000000000000000e+04 / 0x0040f3fc0000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -### Rounding to zero -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7ffe (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0xffff (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0xffff (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0xc000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0xbc00 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0x400 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x3c00 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x3c01 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x3c00 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x4000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x416f (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x4248 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0x7bfe (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0x7bff (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0x7bff (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0x7ffe (0x10 => INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0x7fff (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0x7fff (0x10 => INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0x7fff (0x1 => INVALID) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0x7fff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0x7fff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0x7fff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0x7fff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: -1.31008000000000000000e+05 / 0x00c0fffc0000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: -8.18560000000000000000e+04 / 0x00c0f3fc0000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: -6.56000000000000000000e+04 / 0x00c0f0040000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: -6.55360000000000000000e+04 / 0x00c0f0000000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: -6.55040000000000000000e+04 / 0x00c0effc0000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: -5.96046447753906250000e-08 / 0x00be70000000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: -0.00000000000000000000e+00 / 0x008000000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 5.96046447753906250000e-08 / 0x003e70000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 6.55360000000000000000e+04 / 0x0040f0000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 6.56000000000000000000e+04 / 0x0040f0040000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 8.18560000000000000000e+04 / 0x0040f3fc0000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -Converting single-precision to integer -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 INT64: 1/0x000000000000000001 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 INT64: 2/0x000000000000000002 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 INT64: 65503/0x00000000000000ffdf (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 INT64: 65504/0x00000000000000ffe0 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 INT64: 65505/0x00000000000000ffe1 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 INT64: 131007/0x00000000000001ffbf (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 INT64: 131008/0x00000000000001ffc0 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 INT64: 131009/0x00000000000001ffc1 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 INT64: 0/00000000000000000000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting double-precision to integer -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 INT64: -9223372036854775808/0x008000000000000000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 INT64: -2/0x00fffffffffffffffe (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 INT64: -1/0x00ffffffffffffffff (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 INT64: 0/00000000000000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 INT64: 1/0x000000000000000001 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 INT64: 1/0x000000000000000001 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 INT64: 2/0x000000000000000002 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 INT64: 65503/0x00000000000000ffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 INT64: 65504/0x00000000000000ffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 INT64: 65505/0x00000000000000ffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 INT64: 131007/0x00000000000001ffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 INT64: 131008/0x00000000000001ffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 INT64: 131009/0x00000000000001ffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 INT64: 2147483647/0x00000000007fffffff (0 => OK) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 INT64: 9223372036854775807/0x007fffffffffffffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 INT64: 0/00000000000000000000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 INT64: 0/00000000000000000000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting half-precision to integer -00 HALF: 0xffff (0 => OK) -00 INT64: 3355435008/0x0000000000c7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 INT64: 3349143552/0x0000000000c79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 INT64: 3347062784/0x0000000000c7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 INT64: 3347054592/0x0000000000c7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 INT64: 3347046400/0x0000000000c77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 INT64: 3221225472/0x0000000000c0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 INT64: 3212836864/0x0000000000bf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 INT64: 3011510272/0x0000000000b3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 INT64: 2147483648/0x000000000080000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 INT64: 864026624/0x000000000033800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 INT64: 1065353216/0x00000000003f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 INT64: 1199562752/0x0000000000477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 INT64: 1199570944/0x000000000047800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 INT64: 1199579136/0x000000000047802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 INT64: 1201659904/0x0000000000479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 INT64: 1207951360/0x000000000047ffe000 (0 => OK) diff --git a/tests/tcg/aarch64/float_convs.ref b/tests/tcg/aarch64/float_convs.ref deleted file mode 100755 index 23c062ae361e..000000000000 --- a/tests/tcg/aarch64/float_convs.ref +++ /dev/null @@ -1,748 +0,0 @@ -### Rounding to nearest -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding upwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding downwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding to zero -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) diff --git a/tests/tcg/aarch64/float_madds.ref b/tests/tcg/aarch64/float_madds.ref deleted file mode 100644 index 21c053988789..000000000000 --- a/tests/tcg/aarch64/float_madds.ref +++ /dev/null @@ -1,768 +0,0 @@ -### Rounding to nearest -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding upwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe800000000000000p-25:0x337ffff4) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe800000000000000p-50:0x26fffff4) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000200000000000000p-25:0x33000001) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00080000000000000000p-25:0x33000400) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f400000000000000p-24:0x338000fa) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000e00000000000000p-14:0x38800007) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf600000000000000p-24:0x3387fdfb) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000200000000000000p+0:0x3f800001) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d400000000000000p+2:0x409711ea) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458200000000000000p+3:0x4128a2c1) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0600000000000000p+3:0x41100603) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1600000000000000p+15:0x477fe78b) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56200000000000000p+17:0x482de2b1) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0a00000000000000p+31:0x4f7fbf05) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+31:0x4f7fc005) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+32:0x4fffc005) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8a00000000000000p+33:0x507fbfc5) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800a00000000000000p+33:0x507fc005) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab800000000000000p+99:0x71605d5c) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c082a000000000000000p+116:0x79e04150) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-148:0x00000002) flags=UNDERFLOW INEXACT (32/0) -### Rounding downwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x1.00000000000000000000p-149:0x80000001) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding to zero -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) diff --git a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py deleted file mode 100644 index b9ef169c1a03..000000000000 --- a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import print_function -# -# Test the SVE ZReg reports the right amount of data. It uses the -# sve-ioctl test and examines the register data each time the -# __sve_ld_done breakpoint is hit. -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -initial_vlen = 0 -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 - -class TestBreakpoint(gdb.Breakpoint): - def __init__(self, sym_name="__sve_ld_done"): - super(TestBreakpoint, self).__init__(sym_name) - # self.sym, ok = gdb.lookup_symbol(sym_name) - - def stop(self): - val_i = gdb.parse_and_eval('i') - global initial_vlen - try: - for i in range(0, int(val_i)): - val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i) - report(int(val_z) == i, "z0.b.u[%d] == %d" % (i, i)) - for i in range(i + 1, initial_vlen): - val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i) - report(int(val_z) == 0, "z0.b.u[%d] == 0" % (i)) - except gdb.error: - report(False, "checking zregs (out of range)") - - # Check the aliased V registers are set and GDB has correctly - # created them for us having recognised and handled SVE. - try: - for i in range(0, 16): - val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i) - val_v = gdb.parse_and_eval("$v0.b.u[%d]" % i) - report(int(val_z) == int(val_v), - "v0.b.u[%d] == z0.b.u[%d]" % (i, i)) - except gdb.error: - report(False, "checking vregs (out of range)") - - -def run_test(): - "Run through the tests one by one" - - print ("Setup breakpoint") - bp = TestBreakpoint() - - global initial_vlen - vg = gdb.parse_and_eval("$vg") - initial_vlen = int(vg) * 8 - - gdb.execute("c") - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - report(arch.name() == "aarch64", "connected to aarch64") -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - - # Run the actual tests - run_test() -except: - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - import code - code.InteractiveConsole(locals=globals()).interact() - raise - -print("All tests complete: %d failures" % failcount) -exit(failcount) diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py deleted file mode 100644 index b96bdbb99af5..000000000000 --- a/tests/tcg/aarch64/gdbstub/test-sve.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import print_function -# -# Test the SVE registers are visable and changeable via gdbstub -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -MAGIC = 0xDEADBEEF - -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 - -def run_test(): - "Run through the tests one by one" - - gdb.execute("info registers") - report(True, "info registers") - - gdb.execute("info registers vector") - report(True, "info registers vector") - - # Now all the zregs - frame = gdb.selected_frame() - for i in range(0, 32): - rname = "z%d" % (i) - zreg = frame.read_register(rname) - report(True, "Reading %s" % rname) - for j in range(0, 4): - cmd = "set $%s.q.u[%d] = 0x%x" % (rname, j, MAGIC) - gdb.execute(cmd) - report(True, "%s" % cmd) - for j in range(0, 4): - reg = "$%s.q.u[%d]" % (rname, j) - v = gdb.parse_and_eval(reg) - report(str(v.type) == "uint128_t", "size of %s" % (reg)) - for j in range(0, 8): - cmd = "set $%s.d.u[%d] = 0x%x" % (rname, j, MAGIC) - gdb.execute(cmd) - report(True, "%s" % cmd) - for j in range(0, 8): - reg = "$%s.d.u[%d]" % (rname, j) - v = gdb.parse_and_eval(reg) - report(str(v.type) == "uint64_t", "size of %s" % (reg)) - report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC)) - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - report(arch.name() == "aarch64", "connected to aarch64") -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - - # Run the actual tests - run_test() -except: - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - -print("All tests complete: %d failures" % failcount) - -exit(failcount) diff --git a/tests/tcg/aarch64/mte-1.c b/tests/tcg/aarch64/mte-1.c deleted file mode 100644 index 88dcd617addc..000000000000 --- a/tests/tcg/aarch64/mte-1.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Memory tagging, basic pass cases. - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "mte.h" - -int main(int ac, char **av) -{ - int *p0, *p1, *p2; - long c; - - enable_mte(PR_MTE_TCF_NONE); - p0 = alloc_mte_mem(sizeof(*p0)); - - asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(1)); - assert(p1 != p0); - asm("subp %0,%1,%2" : "=r"(c) : "r"(p0), "r"(p1)); - assert(c == 0); - - asm("stg %0, [%0]" : : "r"(p1)); - asm("ldg %0, [%1]" : "=r"(p2) : "r"(p0), "0"(p0)); - assert(p1 == p2); - - return 0; -} diff --git a/tests/tcg/aarch64/mte-2.c b/tests/tcg/aarch64/mte-2.c deleted file mode 100644 index a62278276a41..000000000000 --- a/tests/tcg/aarch64/mte-2.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Memory tagging, basic fail cases, synchronous signals. - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "mte.h" - -void pass(int sig, siginfo_t *info, void *uc) -{ - assert(info->si_code == SEGV_MTESERR); - exit(0); -} - -int main(int ac, char **av) -{ - struct sigaction sa; - int *p0, *p1, *p2; - long excl = 1; - - enable_mte(PR_MTE_TCF_SYNC); - p0 = alloc_mte_mem(sizeof(*p0)); - - /* Create two differently tagged pointers. */ - asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); - asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); - assert(excl != 1); - asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); - assert(p1 != p2); - - /* Store the tag from the first pointer. */ - asm("stg %0, [%0]" : : "r"(p1)); - - *p1 = 0; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = pass; - sa.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &sa, NULL); - - *p2 = 0; - - abort(); -} diff --git a/tests/tcg/aarch64/mte-3.c b/tests/tcg/aarch64/mte-3.c deleted file mode 100644 index 424ea685c2b7..000000000000 --- a/tests/tcg/aarch64/mte-3.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Memory tagging, basic fail cases, asynchronous signals. - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "mte.h" - -void pass(int sig, siginfo_t *info, void *uc) -{ - assert(info->si_code == SEGV_MTEAERR); - exit(0); -} - -int main(int ac, char **av) -{ - struct sigaction sa; - long *p0, *p1, *p2; - long excl = 1; - - enable_mte(PR_MTE_TCF_ASYNC); - p0 = alloc_mte_mem(sizeof(*p0)); - - /* Create two differently tagged pointers. */ - asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); - asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); - assert(excl != 1); - asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); - assert(p1 != p2); - - /* Store the tag from the first pointer. */ - asm("stg %0, [%0]" : : "r"(p1)); - - *p1 = 0; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = pass; - sa.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &sa, NULL); - - /* - * Signal for async error will happen eventually. - * For a real kernel this should be after the next IRQ (e.g. timer). - * For qemu linux-user, we kick the cpu and exit at the next TB. - * In either case, loop until this happens (or killed by timeout). - * For extra sauce, yield, producing EXCP_YIELD to cpu_loop(). - */ - asm("str %0, [%0]; yield" : : "r"(p2)); - while (1); -} diff --git a/tests/tcg/aarch64/mte-4.c b/tests/tcg/aarch64/mte-4.c deleted file mode 100644 index a8cc9f598413..000000000000 --- a/tests/tcg/aarch64/mte-4.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Memory tagging, re-reading tag checks. - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "mte.h" - -void __attribute__((noinline)) tagset(void *p, size_t size) -{ - size_t i; - for (i = 0; i < size; i += 16) { - asm("stg %0, [%0]" : : "r"(p + i)); - } -} - -void __attribute__((noinline)) tagcheck(void *p, size_t size) -{ - size_t i; - void *c; - - for (i = 0; i < size; i += 16) { - asm("ldg %0, [%1]" : "=r"(c) : "r"(p + i), "0"(p)); - assert(c == p); - } -} - -int main(int ac, char **av) -{ - size_t size = getpagesize() * 4; - long excl = 1; - int *p0, *p1; - - enable_mte(PR_MTE_TCF_ASYNC); - p0 = alloc_mte_mem(size); - - /* Tag the pointer. */ - asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); - - tagset(p1, size); - tagcheck(p1, size); - - return 0; -} diff --git a/tests/tcg/aarch64/mte-5.c b/tests/tcg/aarch64/mte-5.c deleted file mode 100644 index 6dbd6ab3ea70..000000000000 --- a/tests/tcg/aarch64/mte-5.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Memory tagging, faulting unaligned access. - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "mte.h" - -void pass(int sig, siginfo_t *info, void *uc) -{ - assert(info->si_code == SEGV_MTESERR); - exit(0); -} - -int main(int ac, char **av) -{ - struct sigaction sa; - void *p0, *p1, *p2; - long excl = 1; - - enable_mte(PR_MTE_TCF_SYNC); - p0 = alloc_mte_mem(sizeof(*p0)); - - /* Create two differently tagged pointers. */ - asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); - asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); - assert(excl != 1); - asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); - assert(p1 != p2); - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = pass; - sa.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &sa, NULL); - - /* Store store two different tags in sequential granules. */ - asm("stg %0, [%0]" : : "r"(p1)); - asm("stg %0, [%0]" : : "r"(p2 + 16)); - - /* Perform an unaligned load crossing the granules. */ - asm volatile("ldr %0, [%1]" : "=r"(p0) : "r"(p1 + 12)); - abort(); -} diff --git a/tests/tcg/aarch64/mte-6.c b/tests/tcg/aarch64/mte-6.c deleted file mode 100644 index 60d51d18be5f..000000000000 --- a/tests/tcg/aarch64/mte-6.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "mte.h" - -void pass(int sig, siginfo_t *info, void *uc) -{ - assert(info->si_code == SEGV_MTESERR); - exit(0); -} - -int main(void) -{ - enable_mte(PR_MTE_TCF_SYNC); - - void *brk = sbrk(16); - if (brk == (void *)-1) { - perror("sbrk"); - return 2; - } - - if (mprotect(brk, 16, PROT_READ | PROT_WRITE | PROT_MTE)) { - perror("mprotect"); - return 2; - } - - int *p1, *p2; - long excl = 1; - - asm("irg %0,%1,%2" : "=r"(p1) : "r"(brk), "r"(excl)); - asm("gmi %0,%1,%0" : "+r"(excl) : "r"(p1)); - asm("irg %0,%1,%2" : "=r"(p2) : "r"(brk), "r"(excl)); - asm("stg %0,[%0]" : : "r"(p1)); - - *p1 = 0; - - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = pass; - sa.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &sa, NULL); - - *p2 = 0; - - abort(); -} diff --git a/tests/tcg/aarch64/mte-7.c b/tests/tcg/aarch64/mte-7.c deleted file mode 100644 index a981de62d4a2..000000000000 --- a/tests/tcg/aarch64/mte-7.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Memory tagging, unaligned access crossing pages. - * https://gitlab.com/qemu-project/qemu/-/issues/403 - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "mte.h" - -int main(int ac, char **av) -{ - void *p; - - enable_mte(PR_MTE_TCF_SYNC); - p = alloc_mte_mem(2 * 0x1000); - - /* Tag the pointer. */ - p = (void *)((unsigned long)p | (1ul << 56)); - - /* Store tag in sequential granules. */ - asm("stg %0, [%0]" : : "r"(p + 0x0ff0)); - asm("stg %0, [%0]" : : "r"(p + 0x1000)); - - /* - * Perform an unaligned store with tag 1 crossing the pages. - * Failure dies with SIGSEGV. - */ - asm("str %0, [%0]" : : "r"(p + 0x0ffc)); - return 0; -} diff --git a/tests/tcg/aarch64/mte.h b/tests/tcg/aarch64/mte.h deleted file mode 100644 index 0805676b116e..000000000000 --- a/tests/tcg/aarch64/mte.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Linux kernel fallback API definitions for MTE and test helpers. - * - * Copyright (c) 2021 Linaro Ltd - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef PR_SET_TAGGED_ADDR_CTRL -# define PR_SET_TAGGED_ADDR_CTRL 55 -#endif -#ifndef PR_TAGGED_ADDR_ENABLE -# define PR_TAGGED_ADDR_ENABLE (1UL << 0) -#endif -#ifndef PR_MTE_TCF_SHIFT -# define PR_MTE_TCF_SHIFT 1 -# define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT) -# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT) -# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT) -# define PR_MTE_TAG_SHIFT 3 -#endif - -#ifndef PROT_MTE -# define PROT_MTE 0x20 -#endif - -#ifndef SEGV_MTEAERR -# define SEGV_MTEAERR 8 -# define SEGV_MTESERR 9 -#endif - -static void enable_mte(int tcf) -{ - int r = prctl(PR_SET_TAGGED_ADDR_CTRL, - PR_TAGGED_ADDR_ENABLE | tcf | (0xfffe << PR_MTE_TAG_SHIFT), - 0, 0, 0); - if (r < 0) { - perror("PR_SET_TAGGED_ADDR_CTRL"); - exit(2); - } -} - -static void * alloc_mte_mem(size_t size) __attribute__((unused)); -static void * alloc_mte_mem(size_t size) -{ - void *p = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_MTE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) { - perror("mmap PROT_MTE"); - exit(2); - } - return p; -} diff --git a/tests/tcg/aarch64/pauth-1.c b/tests/tcg/aarch64/pauth-1.c deleted file mode 100644 index d3878cbeb6e5..000000000000 --- a/tests/tcg/aarch64/pauth-1.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include - -#ifndef PR_PAC_RESET_KEYS -#define PR_PAC_RESET_KEYS 54 -#define PR_PAC_APDAKEY (1 << 2) -#endif - -#define TESTS 1000 - -int main() -{ - int x, i, count = 0; - void *p0 = &x, *p1, *p2; - float perc; - - for (i = 0; i < TESTS; i++) { - asm volatile("pacdza %0" : "=r"(p1) : "0"(p0)); - prctl(PR_PAC_RESET_KEYS, PR_PAC_APDAKEY, 0, 0, 0); - asm volatile("pacdza %0" : "=r"(p2) : "0"(p0)); - - if (p1 != p0) { - count++; - } - if (p1 != p2) { - count++; - } - } - - perc = (float) count / (float) (TESTS * 2); - printf("Ptr Check: %0.2f%%\n", perc * 100.0); - assert(perc > 0.95); - return 0; -} diff --git a/tests/tcg/aarch64/pauth-2.c b/tests/tcg/aarch64/pauth-2.c deleted file mode 100644 index 978652ede3a6..000000000000 --- a/tests/tcg/aarch64/pauth-2.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include - -void do_test(uint64_t value) -{ - uint64_t salt1, salt2; - uint64_t encode, decode; - - /* - * With TBI enabled and a 48-bit VA, there are 7 bits of auth, - * and so a 1/128 chance of encode = pac(value,key,salt) producing - * an auth for which leaves value unchanged. - * Iterate until we find a salt for which encode != value. - */ - for (salt1 = 1; ; salt1++) { - asm volatile("pacda %0, %2" : "=r"(encode) : "0"(value), "r"(salt1)); - if (encode != value) { - break; - } - } - - /* A valid salt must produce a valid authorization. */ - asm volatile("autda %0, %2" : "=r"(decode) : "0"(encode), "r"(salt1)); - assert(decode == value); - - /* - * An invalid salt usually fails authorization, but again there - * is a chance of choosing another salt that works. - * Iterate until we find another salt which does fail. - */ - for (salt2 = salt1 + 1; ; salt2++) { - asm volatile("autda %0, %2" : "=r"(decode) : "0"(encode), "r"(salt2)); - if (decode != value) { - break; - } - } - - /* The VA bits, bit 55, and the TBI bits, should be unchanged. */ - assert(((decode ^ value) & 0xff80ffffffffffffull) == 0); - - /* - * Bits [54:53] are an error indicator based on the key used; - * the DA key above is keynumber 0, so error == 0b01. Otherwise - * bit 55 of the original is sign-extended into the rest of the auth. - */ - if ((value >> 55) & 1) { - assert(((decode >> 48) & 0xff) == 0b10111111); - } else { - assert(((decode >> 48) & 0xff) == 0b00100000); - } -} - -int main() -{ - do_test(0); - do_test(0xda004acedeadbeefull); - return 0; -} diff --git a/tests/tcg/aarch64/pauth-4.c b/tests/tcg/aarch64/pauth-4.c deleted file mode 100644 index 24a639e36ca0..000000000000 --- a/tests/tcg/aarch64/pauth-4.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -#include - -#define TESTS 1000 - -int main() -{ - int i, count = 0; - float perc; - void *base = malloc(TESTS); - - for (i = 0; i < TESTS; i++) { - uintptr_t in, x, y; - - in = i + (uintptr_t) base; - - asm("mov %0, %[in]\n\t" - "pacia %0, sp\n\t" /* sigill if pauth not supported */ - "eor %0, %0, #4\n\t" /* corrupt single bit */ - "mov %1, %0\n\t" - "autia %1, sp\n\t" /* validate corrupted pointer */ - "xpaci %0\n\t" /* strip pac from corrupted pointer */ - : /* out */ "=r"(x), "=r"(y) - : /* in */ [in] "r" (in) - : /* clobbers */); - - /* - * Once stripped, the corrupted pointer is of the form 0x0000...wxyz. - * We expect the autia to indicate failure, producing a pointer of the - * form 0x000e....wxyz. Use xpaci and != for the test, rather than - * extracting explicit bits from the top, because the location of the - * error code "e" depends on the configuration of virtual memory. - */ - if (x != y) { - count++; - } - - } - perc = (float) count / (float) TESTS; - printf("Checks Passed: %0.2f%%", perc * 100.0); - assert(perc > 0.95); - return 0; -} diff --git a/tests/tcg/aarch64/pauth-5.c b/tests/tcg/aarch64/pauth-5.c deleted file mode 100644 index 67c257918b92..000000000000 --- a/tests/tcg/aarch64/pauth-5.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - -static int x; - -int main() -{ - int *p0 = &x, *p1, *p2, *p3; - unsigned long salt = 0; - - /* - * With TBI enabled and a 48-bit VA, there are 7 bits of auth, and so - * a 1/128 chance of auth = pac(ptr,key,salt) producing zero. - * Find a salt that creates auth != 0. - */ - do { - salt++; - asm("pacda %0, %1" : "=r"(p1) : "r"(salt), "0"(p0)); - } while (p0 == p1); - - /* - * This pac must fail, because the input pointer bears an encryption, - * and so is not properly extended within bits [55:47]. This will - * toggle bit 54 in the output... - */ - asm("pacda %0, %1" : "=r"(p2) : "r"(salt), "0"(p1)); - - /* ... so that the aut must fail, setting bit 53 in the output ... */ - asm("autda %0, %1" : "=r"(p3) : "r"(salt), "0"(p2)); - - /* ... which means this equality must not hold. */ - assert(p3 != p0); - return 0; -} diff --git a/tests/tcg/aarch64/pcalign-a64.c b/tests/tcg/aarch64/pcalign-a64.c deleted file mode 100644 index 6b9277f919f4..000000000000 --- a/tests/tcg/aarch64/pcalign-a64.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Test PC misalignment exception */ - -#include -#include -#include -#include - -static void *expected; - -static void sigbus(int sig, siginfo_t *info, void *vuc) -{ - assert(info->si_code == BUS_ADRALN); - assert(info->si_addr == expected); - exit(EXIT_SUCCESS); -} - -int main() -{ - void *tmp; - - struct sigaction sa = { - .sa_sigaction = sigbus, - .sa_flags = SA_SIGINFO - }; - - if (sigaction(SIGBUS, &sa, NULL) < 0) { - perror("sigaction"); - return EXIT_FAILURE; - } - - asm volatile("adr %0, 1f + 1\n\t" - "str %0, %1\n\t" - "br %0\n" - "1:" - : "=&r"(tmp), "=m"(expected)); - abort(); -} diff --git a/tests/tcg/aarch64/semicall.h b/tests/tcg/aarch64/semicall.h deleted file mode 100644 index 8a3fce35c5f9..000000000000 --- a/tests/tcg/aarch64/semicall.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Semihosting Tests - AArch64 helper - * - * Copyright (c) 2019 - * Written by Alex Bennée - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -uintptr_t __semi_call(uintptr_t type, uintptr_t arg0) -{ - register uintptr_t t asm("x0") = type; - register uintptr_t a0 asm("x1") = arg0; - asm("hlt 0xf000" - : "=r" (t) - : "r" (t), "r" (a0)); - return t; -} diff --git a/tests/tcg/aarch64/sve-ioctls.c b/tests/tcg/aarch64/sve-ioctls.c deleted file mode 100644 index 9544dffa0ee3..000000000000 --- a/tests/tcg/aarch64/sve-ioctls.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SVE ioctls tests - * - * Test the SVE width setting ioctls work and provide a base for - * testing the gdbstub. - * - * Copyright (c) 2019 Linaro Ltd - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ -#include -#include -#include -#include -#include -#include - -#ifndef HWCAP_CPUID -#define HWCAP_CPUID (1 << 11) -#endif - -#define SVE_MAX_QUADS (2048 / 128) -#define BYTES_PER_QUAD (128 / 8) - -#define get_cpu_reg(id) ({ \ - unsigned long __val; \ - asm("mrs %0, "#id : "=r" (__val)); \ - __val; \ - }) - -static int do_sve_ioctl_test(void) -{ - int i, res, init_vq; - - res = prctl(PR_SVE_GET_VL, 0, 0, 0, 0); - if (res < 0) { - printf("FAILED to PR_SVE_GET_VL (%d)", res); - return -1; - } - init_vq = res & PR_SVE_VL_LEN_MASK; - - for (i = init_vq; i > 15; i /= 2) { - printf("Checking PR_SVE_SET_VL=%d\n", i); - res = prctl(PR_SVE_SET_VL, i, 0, 0, 0, 0); - if (res < 0) { - printf("FAILED to PR_SVE_SET_VL (%d)", res); - return -1; - } - asm("index z0.b, #0, #1\n" - ".global __sve_ld_done\n" - "__sve_ld_done:\n" - "mov z0.b, #0\n" - : /* no outputs kept */ - : /* no inputs */ - : "memory", "z0"); - } - printf("PASS\n"); - return 0; -} - -int main(int argc, char **argv) -{ - /* we also need to probe for the ioctl support */ - if (getauxval(AT_HWCAP) & HWCAP_SVE) { - return do_sve_ioctl_test(); - } else { - printf("SKIP: no HWCAP_SVE on this system\n"); - return 0; - } -} diff --git a/tests/tcg/aarch64/sysregs.c b/tests/tcg/aarch64/sysregs.c deleted file mode 100644 index 40cf8d2877ef..000000000000 --- a/tests/tcg/aarch64/sysregs.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Check emulated system register access for linux-user mode. - * - * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt - * - * Copyright (c) 2019 Linaro - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include -#include -#include -#include -#include - -#ifndef HWCAP_CPUID -#define HWCAP_CPUID (1 << 11) -#endif - -int failed_bit_count; - -/* Read and print system register `id' value */ -#define get_cpu_reg(id) ({ \ - unsigned long __val = 0xdeadbeef; \ - asm("mrs %0, "#id : "=r" (__val)); \ - printf("%-20s: 0x%016lx\n", #id, __val); \ - __val; \ - }) - -/* As above but also check no bits outside of `mask' are set*/ -#define get_cpu_reg_check_mask(id, mask) ({ \ - unsigned long __cval = get_cpu_reg(id); \ - unsigned long __extra = __cval & ~mask; \ - if (__extra) { \ - printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \ - failed_bit_count++; \ - } \ -}) - -/* As above but check RAZ */ -#define get_cpu_reg_check_zero(id) ({ \ - unsigned long __val = 0xdeadbeef; \ - asm("mrs %0, "#id : "=r" (__val)); \ - if (__val) { \ - printf("%-20s: 0x%016lx (not RAZ!)\n", #id, __val); \ - failed_bit_count++; \ - } \ -}) - -/* Chunk up mask into 63:48, 47:32, 31:16, 15:0 to ease counting */ -#define _m(a, b, c, d) (0x ## a ## b ## c ## d ##ULL) - -bool should_fail; -int should_fail_count; -int should_not_fail_count; -uintptr_t failed_pc[10]; - -void sigill_handler(int signo, siginfo_t *si, void *data) -{ - ucontext_t *uc = (ucontext_t *)data; - - if (should_fail) { - should_fail_count++; - } else { - uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc; - failed_pc[should_not_fail_count++] = pc; - } - uc->uc_mcontext.pc += 4; -} - -int main(void) -{ - struct sigaction sa; - - /* Hook in a SIGILL handler */ - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &sigill_handler; - sigemptyset(&sa.sa_mask); - - if (sigaction(SIGILL, &sa, 0) != 0) { - perror("sigaction"); - return 1; - } - - /* Counter values have been exposed since Linux 4.12 */ - printf("Checking Counter registers\n"); - - get_cpu_reg(ctr_el0); - get_cpu_reg(cntvct_el0); - get_cpu_reg(cntfrq_el0); - - /* HWCAP_CPUID indicates we can read feature registers, since Linux 4.11 */ - if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { - printf("CPUID registers unavailable\n"); - return 1; - } else { - printf("Checking CPUID registers\n"); - } - - /* - * Some registers only expose some bits to user-space. Anything - * that is IMPDEF is exported as 0 to user-space. The _mask checks - * assert no extra bits are set. - * - * This check is *not* comprehensive as some fields are set to - * minimum valid fields - for the purposes of this check allowed - * to have non-zero values. - */ - get_cpu_reg_check_mask(id_aa64isar0_el1, _m(00ff,ffff,f0ff,fff0)); - get_cpu_reg_check_mask(id_aa64isar1_el1, _m(0000,00f0,ffff,ffff)); - /* TGran4 & TGran64 as pegged to -1 */ - get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(0000,0000,ff00,0000)); - get_cpu_reg_check_zero(id_aa64mmfr1_el1); - /* EL1/EL0 reported as AA64 only */ - get_cpu_reg_check_mask(id_aa64pfr0_el1, _m(000f,000f,00ff,0011)); - get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0000,00f0)); - /* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */ - get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006)); - get_cpu_reg_check_zero(id_aa64dfr1_el1); - get_cpu_reg_check_zero(id_aa64zfr0_el1); - - get_cpu_reg_check_zero(id_aa64afr0_el1); - get_cpu_reg_check_zero(id_aa64afr1_el1); - - get_cpu_reg_check_mask(midr_el1, _m(0000,0000,ffff,ffff)); - /* mpidr sets bit 31, everything else hidden */ - get_cpu_reg_check_mask(mpidr_el1, _m(0000,0000,8000,0000)); - /* REVIDR is all IMPDEF so should be all zeros to user-space */ - get_cpu_reg_check_zero(revidr_el1); - - /* - * There are a block of more registers that are RAZ in the rest of - * the Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7 space. However for - * brevity we don't check stuff that is currently un-allocated - * here. Feel free to add them ;-) - */ - - printf("Remaining registers should fail\n"); - should_fail = true; - - /* Unexposed register access causes SIGILL */ - get_cpu_reg(id_mmfr0_el1); - get_cpu_reg(id_mmfr1_el1); - get_cpu_reg(id_mmfr2_el1); - get_cpu_reg(id_mmfr3_el1); - - get_cpu_reg(mvfr0_el1); - get_cpu_reg(mvfr1_el1); - - if (should_not_fail_count > 0) { - int i; - for (i = 0; i < should_not_fail_count; i++) { - uintptr_t pc = failed_pc[i]; - uint32_t insn = *(uint32_t *) pc; - printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc); - } - return 1; - } - - if (failed_bit_count > 0) { - printf("Extra information leaked to user-space!\n"); - return 1; - } - - return should_fail_count == 6 ? 0 : 1; -} diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S deleted file mode 100644 index e190b1efa613..000000000000 --- a/tests/tcg/aarch64/system/boot.S +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Minimal AArch64 system boot code. - * - * Copyright Linaro Ltd 2019 - * - * Loosely based on the newlib/libgloss setup stubs. Using semihosting - * for serial output and exit functions. - */ - -/* - * Semihosting interface on ARM AArch64 - * See "Semihosting for AArch32 and AArch64 Relase 2.0" by ARM - * w0 - semihosting call number - * x1 - semihosting parameter - */ -#define semihosting_call hlt 0xf000 -#define SYS_WRITEC 0x03 /* character to debug channel */ -#define SYS_WRITE0 0x04 /* string to debug channel */ -#define SYS_EXIT 0x18 - - .align 12 - - .macro ventry label - .align 7 - b \label - .endm - -vector_table: - /* Current EL with SP0. */ - ventry curr_sp0_sync /* Synchronous */ - ventry curr_sp0_irq /* Irq/vIRQ */ - ventry curr_sp0_fiq /* Fiq/vFIQ */ - ventry curr_sp0_serror /* SError/VSError */ - - /* Current EL with SPx. */ - ventry curr_spx_sync /* Synchronous */ - ventry curr_spx_irq /* IRQ/vIRQ */ - ventry curr_spx_fiq /* FIQ/vFIQ */ - ventry curr_spx_serror /* SError/VSError */ - - /* Lower EL using AArch64. */ - ventry lower_a64_sync /* Synchronous */ - ventry lower_a64_irq /* IRQ/vIRQ */ - ventry lower_a64_fiq /* FIQ/vFIQ */ - ventry lower_a64_serror /* SError/VSError */ - - /* Lower EL using AArch32. */ - ventry lower_a32_sync /* Synchronous */ - ventry lower_a32_irq /* IRQ/vIRQ */ - ventry lower_a32_fiq /* FIQ/vFIQ */ - ventry lower_a32_serror /* SError/VSError */ - - .text - .align 4 - - /* Common vector handling for now */ -curr_sp0_sync: -curr_sp0_irq: -curr_sp0_fiq: -curr_sp0_serror: -curr_spx_sync: -curr_spx_irq: -curr_spx_fiq: -curr_spx_serror: -lower_a64_sync: -lower_a64_irq: -lower_a64_fiq: -lower_a64_serror: -lower_a32_sync: -lower_a32_irq: -lower_a32_fiq: -lower_a32_serror: - mov x0, SYS_WRITE0 - adr x1, .error - semihosting_call - mov x0, SYS_EXIT - mov x1, 1 - semihosting_call - /* never returns */ - - .section .rodata -.error: - .string "Terminated by exception.\n" - - .text - .align 4 - .global __start -__start: - /* Installs a table of exception vectors to catch and handle all - exceptions by terminating the process with a diagnostic. */ - adr x0, vector_table - msr vbar_el1, x0 - - /* Page table setup (identity mapping). */ - adrp x0, ttb - add x0, x0, :lo12:ttb - msr ttbr0_el1, x0 - - /* - * Setup a flat address mapping page-tables. Stage one simply - * maps RAM to the first Gb. The stage2 tables have two 2mb - * translation block entries covering a series of adjacent - * 4k pages. - */ - - /* Stage 1 entry: indexed by IA[38:30] */ - adr x1, . /* phys address */ - bic x1, x1, #(1 << 30) - 1 /* 1GB alignment*/ - add x2, x0, x1, lsr #(30 - 3) /* offset in l1 page table */ - - /* point to stage 2 table [47:12] */ - adrp x0, ttb_stage2 - orr x1, x0, #3 /* ptr to stage 2 */ - str x1, [x2] - - /* Stage 2 entries: indexed by IA[29:21] */ - ldr x5, =(((1 << 9) - 1) << 21) - - /* First block: .text/RO/execute enabled */ - adr x1, . /* phys address */ - bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */ - and x4, x1, x5 /* IA[29:21] */ - add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */ - ldr x3, =0x401 /* attr(AF, block) */ - orr x1, x1, x3 - str x1, [x2] /* 1st 2mb (.text & rodata) */ - - /* Second block: .data/RW/no execute */ - adrp x1, .data - add x1, x1, :lo12:.data - bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */ - and x4, x1, x5 /* IA[29:21] */ - add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */ - ldr x3, =(3 << 53) | 0x401 /* attr(AF, NX, block) */ - orr x1, x1, x3 - str x1, [x2] /* 2nd 2mb (.data & .bss)*/ - - /* Setup/enable the MMU. */ - - /* - * TCR_EL1 - Translation Control Registers - * - * IPS[34:32] = 40-bit PA, 1TB - * TG0[14:15] = b00 => 4kb granuale - * ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable - * IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable - * T0SZ[5:0] = 2^(64 - 25) - * - * The size of T0SZ controls what the initial lookup level. It - * would be nice to start at level 2 but unfortunatly for a - * flat-mapping on the virt machine we need to handle IA's - * with at least 1gb range to see RAM. So we start with a - * level 1 lookup. - */ - ldr x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8) - msr tcr_el1, x0 - - mov x0, #0xee /* Inner/outer cacheable WB */ - msr mair_el1, x0 - isb - - /* - * SCTLR_EL1 - System Control Register - * - * WXN[19] = 0 = no effect, Write does not imply XN (execute never) - * I[12] = Instruction cachability control - * SA[3] = SP alignment check - * C[2] = Data cachability control - * M[0] = 1, enable stage 1 address translation for EL0/1 - */ - mrs x0, sctlr_el1 - ldr x1, =0x100d /* bits I(12) SA(3) C(2) M(0) */ - bic x0, x0, #(1 << 1) /* clear bit A(1) */ - bic x0, x0, #(1 << 19) /* clear WXN */ - orr x0, x0, x1 /* set bits */ - - dsb sy - msr sctlr_el1, x0 - isb - - /* - * Enable FP registers. The standard C pre-amble will be - * saving these and A-profile compilers will use AdvSIMD - * registers unless we tell it not to. - */ - mrs x0, cpacr_el1 - orr x0, x0, #(3 << 20) - msr cpacr_el1, x0 - - /* Setup some stack space and enter the test code. - * Assume everthing except the return value is garbage when we - * return, we won't need it. - */ - adrp x0, stack_end - add x0, x0, :lo12:stack_end - mov sp, x0 - bl main - - /* pass return value to sys exit */ -_exit: - mov x1, x0 - ldr x0, =0x20026 /* ADP_Stopped_ApplicationExit */ - stp x0, x1, [sp, #-16]! - mov x1, sp - mov x0, SYS_EXIT - semihosting_call - /* never returns */ - - /* - * Helper Functions - */ - - /* Output a single character to serial port */ - .global __sys_outc -__sys_outc: - stp x0, x1, [sp, #-16]! - /* pass address of c on stack */ - mov x1, sp - mov x0, SYS_WRITEC - semihosting_call - ldp x0, x1, [sp], #16 - ret - - .data - .align 12 - - /* Translation table - * @4k granuale: 9 bit lookup, 512 entries - */ -ttb: - .space 4096, 0 - - .align 12 -ttb_stage2: - .space 4096, 0 - - .align 12 -stack: - .space 65536, 0 -stack_end: diff --git a/tests/tcg/aarch64/system/kernel.ld b/tests/tcg/aarch64/system/kernel.ld deleted file mode 100644 index 7b3a76dcbf35..000000000000 --- a/tests/tcg/aarch64/system/kernel.ld +++ /dev/null @@ -1,24 +0,0 @@ -ENTRY(__start) - -SECTIONS -{ - /* virt machine, RAM starts at 1gb */ - . = (1 << 30); - .text : { - *(.text) - } - .rodata : { - *(.rodata) - } - /* align r/w section to next 2mb */ - . = ALIGN(1 << 21); - .data : { - *(.data) - } - .bss : { - *(.bss) - } - /DISCARD/ : { - *(.ARM.attributes) - } -} diff --git a/tests/tcg/aarch64/system/pauth-3.c b/tests/tcg/aarch64/system/pauth-3.c deleted file mode 100644 index 42eff4d5eae9..000000000000 --- a/tests/tcg/aarch64/system/pauth-3.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - /* - * Test vector from QARMA paper (https://eprint.iacr.org/2016/444.pdf) - * to verify one computation of the pauth_computepac() function, - * which uses sbox2. - * - * Use PACGA, because it returns the most bits from ComputePAC. - * We still only get the most significant 32-bits of the result. - */ - - static const uint64_t d[5] = { - 0xfb623599da6e8127ull, - 0x477d469dec0b8762ull, - 0x84be85ce9804e94bull, - 0xec2802d4e0a488e9ull, - 0xc003b93999b33765ull & 0xffffffff00000000ull - }; - uint64_t r; - - asm("msr apgakeyhi_el1, %[w0]\n\t" - "msr apgakeylo_el1, %[k0]\n\t" - "pacga %[r], %[P], %[T]" - : [r] "=r"(r) - : [P] "r" (d[0]), - [T] "r" (d[1]), - [w0] "r" (d[2]), - [k0] "r" (d[3])); - - if (r == d[4]) { - ml_printf("OK\n"); - return 0; - } else { - ml_printf("FAIL: %lx != %lx\n", r, d[4]); - return 1; - } -} diff --git a/tests/tcg/aarch64/system/semiconsole.c b/tests/tcg/aarch64/system/semiconsole.c deleted file mode 100644 index bfe7c9e26b43..000000000000 --- a/tests/tcg/aarch64/system/semiconsole.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Semihosting Console Test - * - * Copyright (c) 2019 Linaro Ltd - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include - -#define SYS_READC 0x7 - -uintptr_t __semi_call(uintptr_t type, uintptr_t arg0) -{ - register uintptr_t t asm("x0") = type; - register uintptr_t a0 asm("x1") = arg0; - asm("hlt 0xf000" - : "=r" (t) - : "r" (t), "r" (a0)); - - return t; -} - -int main(void) -{ - char c; - - ml_printf("Semihosting Console Test\n"); - ml_printf("hit X to exit:"); - - do { - c = __semi_call(SYS_READC, 0); - __sys_outc(c); - } while (c != 'X'); - - return 0; -} diff --git a/tests/tcg/aarch64/system/semiheap.c b/tests/tcg/aarch64/system/semiheap.c deleted file mode 100644 index 4ed258476d5c..000000000000 --- a/tests/tcg/aarch64/system/semiheap.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Semihosting System HEAPINFO Test - * - * Copyright (c) 2021 Linaro Ltd - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include -#include - -#define SYS_HEAPINFO 0x16 - -uintptr_t __semi_call(uintptr_t type, uintptr_t arg0) -{ - register uintptr_t t asm("x0") = type; - register uintptr_t a0 asm("x1") = arg0; - asm("hlt 0xf000" - : "=r" (t) - : "r" (t), "r" (a0) - : "memory" ); - - return t; -} - -int main(int argc, char *argv[argc]) -{ - struct { - void *heap_base; - void *heap_limit; - void *stack_base; - void *stack_limit; - } info = { }; - void *ptr_to_info = (void *) &info; - uint32_t *ptr_to_heap; - int i; - - ml_printf("Semihosting Heap Info Test\n"); - - __semi_call(SYS_HEAPINFO, (uintptr_t) &ptr_to_info); - - if (info.heap_base == NULL || info.heap_limit == NULL) { - ml_printf("null heap: %p -> %p\n", info.heap_base, info.heap_limit); - return -1; - } - - /* Error if heap base is above limit */ - if ((uintptr_t) info.heap_base >= (uintptr_t) info.heap_limit) { - ml_printf("heap base %p >= heap_limit %p\n", - info.heap_base, info.heap_limit); - return -2; - } - - if (info.stack_base == NULL) { - ml_printf("null stack: %p -> %p\n", info.stack_base, info.stack_limit); - return -3; - } - - /* - * boot.S put our stack somewhere inside the data segment of the - * ELF file, and we know that SYS_HEAPINFO won't pick a range - * that overlaps with part of a loaded ELF file. So the info - * struct (on the stack) should not be inside the reported heap. - */ - if (ptr_to_info > info.heap_base && ptr_to_info < info.heap_limit) { - ml_printf("info appears to be inside the heap: %p in %p:%p\n", - ptr_to_info, info.heap_base, info.heap_limit); - return -4; - } - - ml_printf("heap: %p -> %p\n", info.heap_base, info.heap_limit); - ml_printf("stack: %p <- %p\n", info.stack_limit, info.stack_base); - - /* finally can we read/write the heap */ - ptr_to_heap = (uint32_t *) info.heap_base; - for (i = 0; i < 512; i++) { - *ptr_to_heap++ = i; - } - ptr_to_heap = (uint32_t *) info.heap_base; - for (i = 0; i < 512; i++) { - uint32_t tmp = *ptr_to_heap; - if (tmp != i) { - ml_printf("unexpected value in heap: %d @ %p", tmp, ptr_to_heap); - return -5; - } - ptr_to_heap++; - } - ml_printf("r/w to heap upto %p\n", ptr_to_heap); - - ml_printf("Passed HeapInfo checks\n"); - return 0; -} diff --git a/tests/tcg/aarch64/test-826.c b/tests/tcg/aarch64/test-826.c deleted file mode 100644 index f59740a8c508..000000000000 --- a/tests/tcg/aarch64/test-826.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static void *expected; - -void sigsegv(int sig, siginfo_t *info, void *vuc) -{ - ucontext_t *uc = vuc; - - assert(info->si_addr == expected); - uc->uc_mcontext.pc += 4; -} - -int main() -{ - struct sigaction sa = { - .sa_sigaction = sigsegv, - .sa_flags = SA_SIGINFO - }; - - void *page; - long ofs; - - if (sigaction(SIGSEGV, &sa, NULL) < 0) { - perror("sigaction"); - return EXIT_FAILURE; - } - - page = mmap(0, getpagesize(), PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); - if (page == MAP_FAILED) { - perror("mmap"); - return EXIT_FAILURE; - } - - ofs = 0x124; - expected = page + ofs; - - asm("ptrue p0.d, vl1\n\t" - "dup z0.d, %0\n\t" - "ldnt1h {z1.d}, p0/z, [z0.d, %1]\n\t" - "dup z1.d, %1\n\t" - "ldnt1h {z0.d}, p0/z, [z1.d, %0]" - : : "r"(page), "r"(ofs) : "v0", "v1"); - - return EXIT_SUCCESS; -} diff --git a/tests/tcg/alpha/Makefile.softmmu-target b/tests/tcg/alpha/Makefile.softmmu-target deleted file mode 100644 index 09193a62d682..000000000000 --- a/tests/tcg/alpha/Makefile.softmmu-target +++ /dev/null @@ -1,34 +0,0 @@ -# -# Alpha system tests -# - -ALPHA_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/alpha/system -VPATH+=$(ALPHA_SYSTEM_SRC) - -# These objects provide the basic boot code and helper functions for all tests -CRT_OBJS=boot.o - -ALPHA_TEST_SRCS=$(wildcard $(ALPHA_SYSTEM_SRC)/*.c) -ALPHA_TESTS = $(patsubst $(ALPHA_SYSTEM_SRC)/%.c, %, $(ALPHA_TEST_SRCS)) - -CRT_PATH=$(ALPHA_SYSTEM_SRC) -LINK_SCRIPT=$(ALPHA_SYSTEM_SRC)/kernel.ld -LDFLAGS=-Wl,-T$(LINK_SCRIPT) -TESTS+=$(ALPHA_TESTS) $(MULTIARCH_TESTS) -CFLAGS+=-nostdlib -g -O1 -mcpu=ev6 $(MINILIB_INC) -LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc - -# building head blobs -.PRECIOUS: $(CRT_OBJS) - -%.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@ - -# Build and link the tests -%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -memory: CFLAGS+=-DCHECK_UNALIGNED=0 - -# Running -QEMU_OPTS+=-serial chardev:output -kernel diff --git a/tests/tcg/alpha/Makefile.target b/tests/tcg/alpha/Makefile.target deleted file mode 100644 index a58508032822..000000000000 --- a/tests/tcg/alpha/Makefile.target +++ /dev/null @@ -1,18 +0,0 @@ -# -*- Mode: makefile -*- -# -# Alpha specific tweaks - -ALPHA_SRC=$(SRC_PATH)/tests/tcg/alpha -VPATH+=$(ALPHA_SRC) - -ALPHA_TESTS=hello-alpha test-cond test-cmov test-ovf -TESTS+=$(ALPHA_TESTS) - -test-cmov: EXTRA_CFLAGS=-DTEST_CMOV -test-cmov: test-cond.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -run-test-cmov: test-cmov - -# On Alpha Linux only supports 8k pages -EXTRA_RUNS+=run-test-mmap-8192 diff --git a/tests/tcg/alpha/hello-alpha.c b/tests/tcg/alpha/hello-alpha.c deleted file mode 100644 index 84e43b2fc4a2..000000000000 --- a/tests/tcg/alpha/hello-alpha.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int main (void) -{ - write (1, "hello\n", 6); - return 0; -} diff --git a/tests/tcg/alpha/system/boot.S b/tests/tcg/alpha/system/boot.S deleted file mode 100644 index 9791b1ef7c8f..000000000000 --- a/tests/tcg/alpha/system/boot.S +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Minimal Alpha system boot code. - * - * Copyright Linaro Ltd 2019 - */ - - .set noat - .set nomacro - .arch ev6 - .text - -.macro load_pci_io reg - /* For typhoon, this is - * 0xfffffc0000000000 -- kseg identity map - * + 0x10000000000 -- typhoon pio base - * + 0x1fc000000 -- typhoon pchip0 pci base - * = 0xfffffd01fc000000 - */ - ldah \reg, -3 /* ff..fd0000 */ - lda \reg, 0x1fc(\reg) /* ff..fd01fc */ - sll \reg, 24, \reg -.endm - -#define com1Rbr 0x3f8 -#define com1Thr 0x3f8 -#define com1Ier 0x3f9 -#define com1Iir 0x3fa -#define com1Lcr 0x3fb -#define com1Mcr 0x3fc -#define com1Lsr 0x3fd -#define com1Msr 0x3fe -#define com1Scr 0x3ff -#define com1Dll 0x3f8 -#define com1Dlm 0x3f9 - -#define PAL_halt 0 -#define PAL_wrent 52 -#define PAL_wrkgp 55 - - .text - .p2align 4 - .globl _start - .ent _start -_start: - br $gp, .+4 - ldah $gp, 0($gp) !gpdisp!1 - lda $gp, 0($gp) !gpdisp!1 - - ldah $sp, $stack_end($gp) !gprelhigh - lda $sp, $stack_end($sp) !gprellow - - /* Install kernel gp for exception handlers. */ - mov $gp, $16 - call_pal PAL_wrkgp - - /* Install exception handlers. */ - ldah $16, entInt($gp) !gprelhigh - lda $16, entInt($16) !gprellow - lda $17, 0 - call_pal PAL_wrent - - ldah $16, entArith($gp) !gprelhigh - lda $16, entArith($16) !gprellow - lda $17, 1 - call_pal PAL_wrent - - ldah $16, entMM($gp) !gprelhigh - lda $16, entMM($16) !gprellow - lda $17, 2 - call_pal PAL_wrent - - ldah $16, entIF($gp) !gprelhigh - lda $16, entIF($16) !gprellow - lda $17, 3 - call_pal PAL_wrent - - ldah $16, entUna($gp) !gprelhigh - lda $16, entUna($16) !gprellow - lda $17, 4 - call_pal PAL_wrent - - ldah $16, entSys($gp) !gprelhigh - lda $16, entSys($16) !gprellow - lda $17, 5 - call_pal PAL_wrent - - /* - * Initialize COM1. - */ - load_pci_io $1 - lda $2, 0x87 /* outb(0x87, com1Lcr); */ - stb $2, com1Lcr($1) - stb $31, com1Dlm($1) /* outb(0, com1Dlm); */ - lda $2, 3 /* baudconst 3 => 56000 */ - stb $2, com1Dll($1) /* outb(baudconst, com1Dll); */ - lda $2, 0x07 - stb $2, com1Lcr($1) /* outb(0x07, com1Lcr) */ - lda $2, 0x0f - stb $2, com1Mcr($1) /* outb(0x0f, com1Mcr) */ - - bsr $26, main !samegp - - /* fall through to _exit */ - .end _start - - .globl _exit - .ent _exit -_exit: - .frame $sp, 0, $26, 0 - .prologue 0 - - /* We cannot return an error code. */ - call_pal PAL_halt - .end _exit - -/* - * We have received an exception that we don't handle. Log and exit. - */ - .ent log_exit -log_exit: -entInt: -entArith: -entMM: -entIF: -entUna: -entSys: - ldah $16, $errormsg($gp) !gprelhigh - lda $16, $errormsg($16) !gprellow - bsr $26, __sys_outs !samegp - bsr $26, _exit !samegp - .end log_exit - - .section .rodata -$errormsg: - .string "Terminated by exception.\n" - .previous - - /* - * Helper Functions - */ - - /* Output a single character to serial port */ - .global __sys_outc - .ent __sys_outc -__sys_outc: - .frame $sp, 0, $26, 0 - .prologue 0 - - load_pci_io $1 - - /* - * while ((inb(com1Lsr) & 0x20) == 0) - * continue; - */ -1: ldbu $0, com1Lsr($1) - and $0, 0x20, $0 - beq $0, 1b - - /* outb(c, com1Thr); */ - stb $16, com1Thr($1) - ret - .end __sys_outc - - /* Output a nul-terminated string to serial port */ - .global __sys_outs - .ent __sys_outs -__sys_outs: - .frame $sp, 0, $26, 0 - .prologue 0 - - load_pci_io $1 - - ldbu $2, 0($16) - beq $2, 9f - - /* - * while ((inb(com1Lsr) & 0x20) == 0) - * continue; - */ -1: ldbu $0, com1Lsr($1) - and $0, 0x20, $0 - beq $0, 1b - - /* outb(c, com1Thr); */ - stb $2, com1Thr($1) - - addq $16, 1, $16 - ldbu $2, 0($16) - bne $2, 1b - -9: ret - .end __sys_outs - -/* - * Division routines that are normally in libc. - * - * These do not follow the C calling convention. Arguments are in $24+$25, - * the result is in $27. Register $28 may be clobbered; everything else - * must be saved. - * - * We store the remainder in $28, so that we can share code. - * - * We do not signal divide by zero. - */ - -/* - * Unsigned 64-bit division. - */ - - .globl __divqu - .ent __divqu -__divqu: - .frame $sp, 48, $23 - subq $sp, 48, $sp - stq $0, 0($sp) - stq $1, 8($sp) - stq $2, 16($sp) - stq $3, 24($sp) - stq $4, 32($sp) - .prologue 0 - -#define mask $0 -#define divisor $1 -#define compare $2 -#define tmp1 $3 -#define tmp2 $4 -#define quotient $27 -#define modulus $28 - - mov $24, modulus - mov $25, divisor - mov $31, quotient - mov 1, mask - beq $25, 9f - - /* Shift left until divisor >= modulus. */ -1: cmpult divisor, modulus, compare - blt divisor, 2f - addq divisor, divisor, divisor - addq mask, mask, mask - bne compare, 1b - -2: addq quotient, mask, tmp2 - srl mask, 1, mask - cmpule divisor, modulus, compare - subq modulus, divisor, tmp1 - cmovne compare, tmp2, quotient - srl divisor, 1, divisor - cmovne compare, tmp1, modulus - bne mask, 2b - -9: ldq $0, 0($sp) - ldq $1, 8($sp) - ldq $2, 16($sp) - ldq $3, 24($sp) - ldq $4, 32($sp) - addq $sp, 48, $sp - ret $31, ($23), 1 - -#undef mask -#undef divisor -#undef compare -#undef tmp1 -#undef tmp2 -#undef quotient -#undef modulus - - .end __divqu - -/* - * Unsigned 64-bit remainder. - * Note that __divqu above leaves the result in $28. - */ - - .globl __remqu - .ent __remqu -__remqu: - .frame $sp, 16, $23 - subq $sp, 16, $sp - stq $23, 0($sp) - .prologue 0 - - bsr $23, __divqu - - ldq $23, 0($sp) - mov $28, $27 - addq $sp, 16, $sp - ret $31, ($23), 1 - .end __remqu - -/* - * Signed 64-bit division. - */ - - .globl __divqs - .ent __divqs -__divqs: - .prologue 0 - - /* Common case: both arguments are positive. */ - bis $24, $25, $28 - bge $28, __divqu - - /* At least one argument is negative. */ - subq $sp, 32, $sp - stq $23, 0($sp) - stq $24, 8($sp) - stq $25, 16($sp) - - /* Compute absolute values. */ - subq $31, $24, $28 - cmovlt $24, $28, $24 - subq $31, $25, $28 - cmovlt $25, $28, $25 - - bsr $23, __divqu - - ldq $24, 8($sp) - ldq $25, 16($sp) - - /* -a / b = a / -b = -(a / b) */ - subq $31, $27, $23 - xor $24, $25, $28 - cmovlt $28, $23, $27 - - ldq $23, 0($sp) - addq $sp, 32, $sp - ret $31, ($23), 1 - .end __divqs - -/* - * Signed 64-bit remainder. - */ - - .globl __remqs - .ent __remqs -__remqs: - .prologue 0 - - /* Common case: both arguments are positive. */ - bis $24, $25, $28 - bge $28, __remqu - - /* At least one argument is negative. */ - subq $sp, 32, $sp - stq $23, 0($sp) - stq $24, 8($sp) - stq $25, 16($sp) - - /* Compute absolute values. */ - subq $31, $24, $28 - cmovlt $24, $28, $24 - subq $31, $25, $28 - cmovlt $25, $28, $25 - - bsr $23, __divqu - - ldq $23, 0($sp) - ldq $24, 8($sp) - ldq $25, 16($sp) - - /* -a % b = -(a % b); a % -b = a % b. */ - subq $31, $28, $27 - cmovge $24, $28, $27 - - addq $sp, 32, $sp - ret $31, ($23), 1 - .end __remqs - -/* - * Unsigned 32-bit division. - */ - - .globl __divlu - .ent __divlu -__divlu: - .frame $sp, 32, $23 - subq $sp, 32, $sp - stq $23, 0($sp) - stq $24, 8($sp) - stq $25, 16($sp) - .prologue 0 - - /* Zero extend and use the 64-bit routine. */ - zap $24, 0xf0, $24 - zap $25, 0xf0, $25 - bsr $23, __divqu - - addl $27, 0, $27 - ldq $23, 0($sp) - ldq $24, 8($sp) - ldq $25, 16($sp) - addq $sp, 32, $sp - ret $31, ($23), 1 - .end __divlu - -/* - * Unsigned 32-bit remainder. - */ - - .globl __remlu - .ent __remlu -__remlu: - .frame $sp, 32, $23 - subq $sp, 32, $sp - stq $23, 0($sp) - stq $24, 8($sp) - stq $25, 16($sp) - .prologue 0 - - /* Zero extend and use the 64-bit routine. */ - zap $24, 0xf0, $24 - zap $25, 0xf0, $25 - bsr $23, __divqu - - /* Recall that the remainder is returned in $28. */ - addl $28, 0, $27 - ldq $23, 0($sp) - ldq $24, 8($sp) - ldq $25, 16($sp) - addq $sp, 32, $sp - ret $31, ($23), 1 - .end __remlu - -/* - * Signed 32-bit division. - */ - - .globl __divls - .ent __divls -__divls: - .frame $sp, 32, $23 - subq $sp, 32, $sp - stq $23, 0($sp) - stq $24, 8($sp) - stq $25, 16($sp) - .prologue 0 - - /* Sign extend. */ - addl $24, 0, $24 - addl $25, 0, $25 - - /* Compute absolute values. */ - subq $31, $24, $28 - cmovlt $24, $28, $24 - subq $31, $25, $28 - cmovlt $25, $28, $25 - - bsr $23, __divqu - - ldq $24, 8($sp) - ldq $25, 16($sp) - - /* Negate the unsigned result, if necessary. */ - xor $24, $25, $28 - subl $31, $27, $23 - addl $27, 0, $27 - addl $28, 0, $28 - cmovlt $28, $23, $27 - - ldq $23, 0($sp) - addq $sp, 32, $sp - ret $31, ($23), 1 - .end __divls - -/* - * Signed 32-bit remainder. - */ - - .globl __remls - .ent __remls -__remls: - .frame $sp, 32, $23 - subq $sp, 32, $sp - stq $23, 0($sp) - stq $24, 8($sp) - stq $25, 16($sp) - .prologue 0 - - /* Sign extend. */ - addl $24, 0, $24 - addl $25, 0, $25 - - /* Compute absolute values. */ - subq $31, $24, $28 - cmovlt $24, $28, $24 - subq $31, $25, $28 - cmovlt $25, $28, $25 - - bsr $23, __divqu - - ldq $23, 0($sp) - ldq $24, 8($sp) - ldq $25, 16($sp) - - /* Negate the unsigned result, if necessary. */ - subl $31, $28, $27 - addl $28, 0, $28 - cmovge $24, $28, $27 - - addq $sp, 32, $sp - ret $31, ($23), 1 - .end __remls - - .data - .p2align 4 -stack: - .skip 65536 -$stack_end: - .type stack,@object - .size stack, . - stack diff --git a/tests/tcg/alpha/system/kernel.ld b/tests/tcg/alpha/system/kernel.ld deleted file mode 100644 index d2ac6ecfeb8a..000000000000 --- a/tests/tcg/alpha/system/kernel.ld +++ /dev/null @@ -1,30 +0,0 @@ -ENTRY(_start) - -SECTIONS -{ - /* Linux kernel legacy start address. */ - . = 0xfffffc0000310000; - _text = .; - .text : { - *(.text) - } - .rodata : { - *(.rodata) - } - _etext = .; - - . = ALIGN(8192); - _data = .; - .got : { - *(.got) - } - .data : { - *(.sdata) - *(.data) - } - _edata = .; - .bss : { - *(.bss) - } - _end = .; -} diff --git a/tests/tcg/alpha/test-cond.c b/tests/tcg/alpha/test-cond.c deleted file mode 100644 index 3e11c4c10516..000000000000 --- a/tests/tcg/alpha/test-cond.c +++ /dev/null @@ -1,88 +0,0 @@ -#include - -#ifdef TEST_CMOV - -#define TEST_COND(N) \ -int test_##N (long a) \ -{ \ - int res = 1; \ - \ - asm ("cmov"#N" %1,$31,%0" \ - : "+r" (res) : "r" (a)); \ - return !res; \ -} - -#else - -#define TEST_COND(N) \ -int test_##N (long a) \ -{ \ - int res = 1; \ - \ - asm ("b"#N" %1,1f\n\t" \ - "addq $31,$31,%0\n\t" \ - "1: unop\n" \ - : "+r" (res) : "r" (a)); \ - return res; \ -} - -#endif - -TEST_COND(eq) -TEST_COND(ne) -TEST_COND(ge) -TEST_COND(gt) -TEST_COND(lbc) -TEST_COND(lbs) -TEST_COND(le) -TEST_COND(lt) - -static struct { - int (*func)(long); - long v; - int r; -} vectors[] = - { - {test_eq, 0, 1}, - {test_eq, 1, 0}, - - {test_ne, 0, 0}, - {test_ne, 1, 1}, - - {test_ge, 0, 1}, - {test_ge, 1, 1}, - {test_ge, -1, 0}, - - {test_gt, 0, 0}, - {test_gt, 1, 1}, - {test_gt, -1, 0}, - - {test_lbc, 0, 1}, - {test_lbc, 1, 0}, - {test_lbc, -1, 0}, - - {test_lbs, 0, 0}, - {test_lbs, 1, 1}, - {test_lbs, -1, 1}, - - {test_le, 0, 1}, - {test_le, 1, 0}, - {test_le, -1, 1}, - - {test_lt, 0, 0}, - {test_lt, 1, 0}, - {test_lt, -1, 1}, - }; - -int main (void) -{ - int i; - - for (i = 0; i < sizeof (vectors)/sizeof(vectors[0]); i++) - if ((*vectors[i].func)(vectors[i].v) != vectors[i].r) { - write(1, "Failed\n", 7); - return 1; - } - write(1, "OK\n", 3); - return 0; -} diff --git a/tests/tcg/alpha/test-ovf.c b/tests/tcg/alpha/test-ovf.c deleted file mode 100644 index 17892f1e89ec..000000000000 --- a/tests/tcg/alpha/test-ovf.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - -static long test_subqv (long a, long b) -{ - long res; - - asm ("subq/v %1,%2,%0" - : "=r" (res) : "r" (a), "r" (b)); - return res; -} -static struct { - long (*func)(long, long); - long a; - long b; - long r; -} vectors[] = - { - {test_subqv, 0, 0x7d54000, 0xfffffffff82ac000L} - }; - -int main (void) -{ - int i; - - for (i = 0; i < sizeof (vectors)/sizeof(vectors[0]); i++) - if ((*vectors[i].func)(vectors[i].a, vectors[i].b) != vectors[i].r) { - write(1, "Failed\n", 7); - } - write(1, "OK\n", 3); - return 0; -} diff --git a/tests/tcg/arm/Makefile.softmmu-target b/tests/tcg/arm/Makefile.softmmu-target deleted file mode 100644 index 3fe237ba391b..000000000000 --- a/tests/tcg/arm/Makefile.softmmu-target +++ /dev/null @@ -1,26 +0,0 @@ -# -*- Mode: makefile -*- -# -# ARM SoftMMU tests - included from tests/tcg/Makefile -# - -ARM_SRC=$(SRC_PATH)/tests/tcg/arm - -# Set search path for all sources -VPATH += $(ARM_SRC) - -ARM_TESTS=test-armv6m-undef - -TESTS += $(ARM_TESTS) - -CFLAGS+=-Wl,--build-id=none -x assembler-with-cpp -LDFLAGS+=-nostdlib -N -static - -%: %.S %.ld - $(CC) $(CFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -T $(ARM_SRC)/$@.ld - -# Specific Test Rules - -test-armv6m-undef: EXTRA_CFLAGS+=-mcpu=cortex-m0 - -run-test-armv6m-undef: QEMU_OPTS+=-semihosting -M microbit -kernel -run-plugin-test-armv6m-undef-%: QEMU_OPTS+=-semihosting -M microbit -kernel diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target deleted file mode 100644 index 2f815120a597..000000000000 --- a/tests/tcg/arm/Makefile.target +++ /dev/null @@ -1,93 +0,0 @@ -# -*- Mode: makefile -*- -# -# ARM - included from tests/tcg/Makefile -# - -ARM_SRC=$(SRC_PATH)/tests/tcg/arm - -# Set search path for all sources -VPATH += $(ARM_SRC) - -float_madds: CFLAGS+=-mfpu=neon-vfpv4 - -# Basic Hello World -ARM_TESTS = hello-arm -hello-arm: CFLAGS+=-marm -ffreestanding -hello-arm: LDFLAGS+=-nostdlib - -# IWMXT floating point extensions -ARM_TESTS += test-arm-iwmmxt -test-arm-iwmmxt: CFLAGS+=-marm -march=iwmmxt -mabi=aapcs -mfpu=fpv4-sp-d16 -test-arm-iwmmxt: test-arm-iwmmxt.S - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) - -# Float-convert Tests -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 diff-out,fcvt,$(ARM_SRC)/fcvt.ref) - -# PC alignment test -ARM_TESTS += pcalign-a32 -pcalign-a32: CFLAGS+=-marm - -ifeq ($(CONFIG_ARM_COMPATIBLE_SEMIHOSTING),y) - -# Semihosting smoke test for linux-user -semihosting: CFLAGS += -mthumb - -ARM_TESTS += semihosting-arm -semihosting-arm: CFLAGS += -marm -I$(SRC_PATH)/tests/tcg/$(TARGET_NAME) -semihosting-arm: semihosting.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -run-semihosting-arm: semihosting-arm - $(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)") - -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 $*") - -ARM_TESTS += semiconsole-arm - -semiconsole: CFLAGS += -mthumb - -semiconsole-arm: CFLAGS += -marm -I$(SRC_PATH)/tests/tcg/$(TARGET_NAME) -semiconsole-arm: semihosting.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -run-semiconsole-arm: semiconsole-arm - $(call skip-test, $<, "MANUAL ONLY") - -run-plugin-semiconsole-arm-with-%: - $(call skip-test, $<, "MANUAL ONLY") - -endif - -ARM_TESTS += commpage - -# Vector SHA1 -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 diff-out, sha1-vector, sha1.out) - -ARM_TESTS += sha1-vector - -# Vector versions of sha512 (-O3 triggers vectorisation) -sha512-vector: CFLAGS=-O3 -sha512-vector: sha512.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -ARM_TESTS += sha512-vector - -TESTS += $(ARM_TESTS) - -# On ARM Linux only supports 4k pages -EXTRA_RUNS+=run-test-mmap-4096 diff --git a/tests/tcg/arm/README b/tests/tcg/arm/README deleted file mode 100644 index e6307116e237..000000000000 --- a/tests/tcg/arm/README +++ /dev/null @@ -1,11 +0,0 @@ -These are ARM specific guest programs - -hello-arm ---------- - -A very simple inline assembly, write syscall based hello world - -test-arm-iwmmxt ---------------- - -A simple test case for older iwmmxt extended ARMs diff --git a/tests/tcg/arm/commpage.c b/tests/tcg/arm/commpage.c deleted file mode 100644 index c76e70cb8bd9..000000000000 --- a/tests/tcg/arm/commpage.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Verify the COMMPAGE emulation - * - * The ARM commpage is a set of user space helper functions provided - * by the kernel in an effort to ease portability of user space code - * between different CPUs with potentially different capabilities. It - * is a 32 bit invention and similar to the vdso segment in many ways. - * - * The ABI is documented in the Linux kernel: - * Documentation/arm/kernel_userspace_helpers.rst - * - * Copyright (c) 2020 Linaro Ltd - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include -#include - -#define ARM_COMMPAGE (0xffff0f00u) -#define ARM_KUSER_VERSION (*(int32_t *)(ARM_COMMPAGE + 0xfc)) -typedef void * (get_tls_fn)(void); -#define ARM_KUSER_GET_TLS (*(get_tls_fn *)(ARM_COMMPAGE + 0xe0)) -typedef int (cmpxchg_fn)(int oldval, int newval, volatile int *ptr); -#define ARM_KUSER_CMPXCHG (*(cmpxchg_fn *)(ARM_COMMPAGE + 0xc0)) -typedef void (dmb_fn)(void); -#define ARM_KUSER_DMB (*(dmb_fn *)(ARM_COMMPAGE + 0xa0)) -typedef int (cmpxchg64_fn)(const int64_t *oldval, - const int64_t *newval, - volatile int64_t *ptr); -#define ARM_KUSER_CMPXCHG64 (*(cmpxchg64_fn *)(ARM_COMMPAGE + 0x60)) - -#define fail_unless(x) \ - do { \ - if (!(x)) { \ - fprintf(stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - - -int main(int argc, char *argv[argc]) -{ - void *kuser_tls; - int val = 1; - const int64_t oldval = 1, newval = 2; - int64_t val64 = 1; - - fail_unless(ARM_KUSER_VERSION == 0x5); - kuser_tls = ARM_KUSER_GET_TLS(); - printf("TLS = %p\n", kuser_tls); - fail_unless(kuser_tls != 0); - fail_unless(ARM_KUSER_CMPXCHG(1, 2, &val) == 0); - printf("val = %d\n", val); - /* this is a crash test, not checking an actual barrier occurs */ - ARM_KUSER_DMB(); - fail_unless(ARM_KUSER_CMPXCHG64(&oldval, &newval, &val64) == 0); - printf("val64 = %lld\n", val64); - return 0; -} diff --git a/tests/tcg/arm/fcvt.c b/tests/tcg/arm/fcvt.c deleted file mode 100644 index 7ac47b564e24..000000000000 --- a/tests/tcg/arm/fcvt.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Test Floating Point Conversion - */ - -/* we want additional float type definitions */ -#define __STDC_WANT_IEC_60559_BFP_EXT__ -#define __STDC_WANT_IEC_60559_TYPES_EXT__ - -#include -#include -#include -#include -#include - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -static char flag_str[256]; - -static char *get_flag_state(int flags) -{ - if (flags) { - snprintf(flag_str, sizeof(flag_str), "%s %s %s %s %s", - flags & FE_OVERFLOW ? "OVERFLOW" : "", - flags & FE_UNDERFLOW ? "UNDERFLOW" : "", - flags & FE_DIVBYZERO ? "DIV0" : "", - flags & FE_INEXACT ? "INEXACT" : "", - flags & FE_INVALID ? "INVALID" : ""); - } else { - snprintf(flag_str, sizeof(flag_str), "OK"); - } - - return flag_str; -} - -static void print_double_number(int i, double num) -{ - uint64_t double_as_hex = *(uint64_t *) # - int flags = fetestexcept(FE_ALL_EXCEPT); - char *fstr = get_flag_state(flags); - - printf("%02d DOUBLE: %02.20e / %#020" PRIx64 " (%#x => %s)\n", - i, num, double_as_hex, flags, fstr); -} - -static void print_single_number(int i, float num) -{ - uint32_t single_as_hex = *(uint32_t *) # - int flags = fetestexcept(FE_ALL_EXCEPT); - char *fstr = get_flag_state(flags); - - printf("%02d SINGLE: %02.20e / %#010x (%#x => %s)\n", - i, num, single_as_hex, flags, fstr); -} - -static void print_half_number(int i, uint16_t num) -{ - int flags = fetestexcept(FE_ALL_EXCEPT); - char *fstr = get_flag_state(flags); - - printf("%02d HALF: %#04x (%#x => %s)\n", - i, num, flags, fstr); -} - -static void print_int64(int i, int64_t num) -{ - uint64_t int64_as_hex = *(uint64_t *) # - int flags = fetestexcept(FE_ALL_EXCEPT); - char *fstr = get_flag_state(flags); - - printf("%02d INT64: %20" PRId64 "/%#020" PRIx64 " (%#x => %s)\n", - i, num, int64_as_hex, flags, fstr); -} - -#ifndef SNANF -/* Signaling NaN macros, if supported. */ -# define SNANF (__builtin_nansf ("")) -# define SNAN (__builtin_nans ("")) -# define SNANL (__builtin_nansl ("")) -#endif - -float single_numbers[] = { -SNANF, - -NAN, - -INFINITY, - -FLT_MAX, - -1.111E+31, - -1.111E+30, - -1.08700982e-12, - -1.78051176e-20, - -FLT_MIN, - 0.0, - FLT_MIN, - 2.98023224e-08, - 5.96046E-8, /* min positive FP16 subnormal */ - 6.09756E-5, /* max subnormal FP16 */ - 6.10352E-5, /* min positive normal FP16 */ - 1.0, - 1.0009765625, /* smallest float after 1.0 FP16 */ - 2.0, - M_E, M_PI, - 65503.0, - 65504.0, /* max FP16 */ - 65505.0, - 131007.0, - 131008.0, /* max AFP */ - 131009.0, - 1.111E+30, - FLT_MAX, - INFINITY, - NAN, - SNANF }; - -static void convert_single_to_half(void) -{ - int i; - - printf("Converting single-precision to half-precision\n"); - - for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) { - float input = single_numbers[i]; - - feclearexcept(FE_ALL_EXCEPT); - - print_single_number(i, input); -#if defined(__arm__) - uint32_t output; - asm("vcvtb.f16.f32 %0, %1" : "=t" (output) : "x" (input)); -#else - uint16_t output; - asm("fcvt %h0, %s1" : "=w" (output) : "x" (input)); -#endif - print_half_number(i, output); - } -} - -static void convert_single_to_double(void) -{ - int i; - - printf("Converting single-precision to double-precision\n"); - - for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) { - float input = single_numbers[i]; - /* uint64_t output; */ - double output; - - feclearexcept(FE_ALL_EXCEPT); - - print_single_number(i, input); -#if defined(__arm__) - asm("vcvt.f64.f32 %P0, %1" : "=w" (output) : "t" (input)); -#else - asm("fcvt %d0, %s1" : "=w" (output) : "x" (input)); -#endif - print_double_number(i, output); - } -} - -static void convert_single_to_integer(void) -{ - int i; - - printf("Converting single-precision to integer\n"); - - for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) { - float input = single_numbers[i]; - int64_t output; - - feclearexcept(FE_ALL_EXCEPT); - - print_single_number(i, input); -#if defined(__arm__) - /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */ - output = input; -#else - asm("fcvtzs %0, %s1" : "=r" (output) : "w" (input)); -#endif - print_int64(i, output); - } -} - -/* This allows us to initialise some doubles as pure hex */ -typedef union { - double d; - uint64_t h; -} test_doubles; - -test_doubles double_numbers[] = { - {SNAN}, - {-NAN}, - {-INFINITY}, - {-DBL_MAX}, - {-FLT_MAX-1.0}, - {-FLT_MAX}, - {-1.111E+31}, - {-1.111E+30}, /* half prec */ - {-2.0}, {-1.0}, - {-DBL_MIN}, - {-FLT_MIN}, - {0.0}, - {FLT_MIN}, - {2.98023224e-08}, - {5.96046E-8}, /* min positive FP16 subnormal */ - {6.09756E-5}, /* max subnormal FP16 */ - {6.10352E-5}, /* min positive normal FP16 */ - {1.0}, - {1.0009765625}, /* smallest float after 1.0 FP16 */ - {DBL_MIN}, - {1.3789972848607228e-308}, - {1.4914738736681624e-308}, - {1.0}, {2.0}, - {M_E}, {M_PI}, - {65503.0}, - {65504.0}, /* max FP16 */ - {65505.0}, - {131007.0}, - {131008.0}, /* max AFP */ - {131009.0}, - {.h = 0x41dfffffffc00000 }, /* to int = 0x7fffffff */ - {FLT_MAX}, - {FLT_MAX + 1.0}, - {DBL_MAX}, - {INFINITY}, - {NAN}, - {.h = 0x7ff0000000000001}, /* SNAN */ - {SNAN}, -}; - -static void convert_double_to_half(void) -{ - int i; - - printf("Converting double-precision to half-precision\n"); - - for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) { - double input = double_numbers[i].d; - uint16_t output; - - feclearexcept(FE_ALL_EXCEPT); - - print_double_number(i, input); - - /* as we don't have _Float16 support */ -#if defined(__arm__) - /* asm("vcvtb.f16.f64 %0, %P1" : "=t" (output) : "x" (input)); */ - output = input; -#else - asm("fcvt %h0, %d1" : "=w" (output) : "x" (input)); -#endif - print_half_number(i, output); - } -} - -static void convert_double_to_single(void) -{ - int i; - - printf("Converting double-precision to single-precision\n"); - - for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) { - double input = double_numbers[i].d; - uint32_t output; - - feclearexcept(FE_ALL_EXCEPT); - - print_double_number(i, input); - -#if defined(__arm__) - asm("vcvt.f32.f64 %0, %P1" : "=w" (output) : "x" (input)); -#else - asm("fcvt %s0, %d1" : "=w" (output) : "x" (input)); -#endif - - print_single_number(i, output); - } -} - -static void convert_double_to_integer(void) -{ - int i; - - printf("Converting double-precision to integer\n"); - - for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) { - double input = double_numbers[i].d; - int64_t output; - - feclearexcept(FE_ALL_EXCEPT); - - print_double_number(i, input); -#if defined(__arm__) - /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */ - output = input; -#else - asm("fcvtzs %0, %d1" : "=r" (output) : "w" (input)); -#endif - print_int64(i, output); - } -} - -/* no handy defines for these numbers */ -uint16_t half_numbers[] = { - 0xffff, /* -NaN / AHP -Max */ - 0xfcff, /* -NaN / AHP */ - 0xfc01, /* -NaN / AHP */ - 0xfc00, /* -Inf */ - 0xfbff, /* -Max */ - 0xc000, /* -2 */ - 0xbc00, /* -1 */ - 0x8001, /* -MIN subnormal */ - 0x8000, /* -0 */ - 0x0000, /* +0 */ - 0x0001, /* MIN subnormal */ - 0x3c00, /* 1 */ - 0x7bff, /* Max */ - 0x7c00, /* Inf */ - 0x7c01, /* NaN / AHP */ - 0x7cff, /* NaN / AHP */ - 0x7fff, /* NaN / AHP +Max*/ -}; - -static void convert_half_to_double(void) -{ - int i; - - printf("Converting half-precision to double-precision\n"); - - for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) { - uint16_t input = half_numbers[i]; - double output; - - feclearexcept(FE_ALL_EXCEPT); - - print_half_number(i, input); -#if defined(__arm__) - /* asm("vcvtb.f64.f16 %P0, %1" : "=w" (output) : "t" (input)); */ - output = input; -#else - asm("fcvt %d0, %h1" : "=w" (output) : "x" (input)); -#endif - print_double_number(i, output); - } -} - -static void convert_half_to_single(void) -{ - int i; - - printf("Converting half-precision to single-precision\n"); - - for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) { - uint16_t input = half_numbers[i]; - float output; - - feclearexcept(FE_ALL_EXCEPT); - - print_half_number(i, input); -#if defined(__arm__) - asm("vcvtb.f32.f16 %0, %1" : "=w" (output) : "x" ((uint32_t)input)); -#else - asm("fcvt %s0, %h1" : "=w" (output) : "x" (input)); -#endif - print_single_number(i, output); - } -} - -static void convert_half_to_integer(void) -{ - int i; - - printf("Converting half-precision to integer\n"); - - for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) { - uint16_t input = half_numbers[i]; - int64_t output; - - feclearexcept(FE_ALL_EXCEPT); - - print_half_number(i, input); -#if defined(__arm__) - /* asm("vcvt.s32.f16 %0, %1" : "=t" (output) : "t" (input)); v8.2*/ - output = input; -#else - asm("fcvt %s0, %h1" : "=w" (output) : "x" (input)); -#endif - print_int64(i, output); - } -} - -typedef struct { - int flag; - char *desc; -} float_mapping; - -float_mapping round_flags[] = { - { FE_TONEAREST, "to nearest" }, - { FE_UPWARD, "upwards" }, - { FE_DOWNWARD, "downwards" }, - { FE_TOWARDZERO, "to zero" } -}; - -int main(int argc, char *argv[argc]) -{ - int i; - - printf("#### Enabling IEEE Half Precision\n"); - - for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { - fesetround(round_flags[i].flag); - printf("### Rounding %s\n", round_flags[i].desc); - convert_single_to_half(); - convert_single_to_double(); - convert_double_to_half(); - convert_double_to_single(); - convert_half_to_single(); - convert_half_to_double(); - } - - /* convert to integer */ - convert_single_to_integer(); - convert_double_to_integer(); - convert_half_to_integer(); - - /* And now with ARM alternative FP16 */ -#if defined(__arm__) - /* See glibc sysdeps/arm/fpu_control.h */ - asm("mrc p10, 7, r1, cr1, cr0, 0\n\t" - "orr r1, r1, %[flags]\n\t" - "mcr p10, 7, r1, cr1, cr0, 0\n\t" - : /* no output */ : [flags] "n" (1 << 26) : "r1" ); -#else - asm("mrs x1, fpcr\n\t" - "orr x1, x1, %[flags]\n\t" - "msr fpcr, x1\n\t" - : /* no output */ : [flags] "n" (1 << 26) : "x1" ); -#endif - - printf("#### Enabling ARM Alternative Half Precision\n"); - - for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { - fesetround(round_flags[i].flag); - printf("### Rounding %s\n", round_flags[i].desc); - convert_single_to_half(); - convert_single_to_double(); - convert_double_to_half(); - convert_double_to_single(); - convert_half_to_single(); - convert_half_to_double(); - } - - /* convert to integer */ - convert_single_to_integer(); - convert_double_to_integer(); - convert_half_to_integer(); - - return 0; -} diff --git a/tests/tcg/arm/fcvt.ref b/tests/tcg/arm/fcvt.ref deleted file mode 100644 index f052b6d7e580..000000000000 --- a/tests/tcg/arm/fcvt.ref +++ /dev/null @@ -1,3268 +0,0 @@ -#### Enabling IEEE Half Precision -### Rounding to nearest -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -### Rounding upwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x400 (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x401 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4249 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7c00 (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766502400000000000e+09 / 0x4f730c3b (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962457600000000000e+09 / 0x4f71605e (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638080000000000000e+08 / 0x4e4c0001 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896384000000000000e+08 / 0x4e61ff01 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912768000000000000e+08 / 0x4e620001 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -### Rounding downwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfc00 (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730512e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -### Rounding to zero -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0xff00 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0xfe00 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xfc00 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xfbff (0x14 => OVERFLOW INEXACT ) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7bff (0x14 => OVERFLOW INEXACT ) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7c00 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0x7e00 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0x7f00 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -nan / 0xffffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -nan / 0xffdfe000 (0x1 => INVALID) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -nan / 0xffc02000 (0x1 => INVALID) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -inf / 0xff800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: inf / 0x7f800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: nan / 0x7fc02000 (0x1 => INVALID) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: nan / 0x7fdfe000 (0x1 => INVALID) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: nan / 0x7fffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -Converting single-precision to integer -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 INT64: 1/0x000000000000000001 (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 INT64: 65503/0x00000000000000ffdf (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 INT64: 65504/0x00000000000000ffe0 (0x10 => INEXACT ) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 INT64: 65505/0x00000000000000ffe1 (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 INT64: 131007/0x00000000000001ffbf (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 INT64: 131008/0x00000000000001ffc0 (0x10 => INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 INT64: 131009/0x00000000000001ffc1 (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 INT64: -1/0x00ffffffffffffffff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 INT64: 0/00000000000000000000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting double-precision to integer -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 INT64: 1/0x000000000000000001 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 INT64: -2/0x00fffffffffffffffe (0x10 => INEXACT ) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 INT64: -1/0x00ffffffffffffffff (0x10 => INEXACT ) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 INT64: 0/00000000000000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 INT64: 0/00000000000000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 INT64: 0/00000000000000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 INT64: 65503/0x00000000000000ffdf (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 INT64: 65504/0x00000000000000ffe0 (0x10 => INEXACT ) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 INT64: 65505/0x00000000000000ffe1 (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 INT64: 131007/0x00000000000001ffbf (0x10 => INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 INT64: 131008/0x00000000000001ffc0 (0x10 => INEXACT ) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 INT64: 131009/0x00000000000001ffc1 (0x10 => INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 INT64: 2147483647/0x00000000007fffffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 INT64: -1/0x00ffffffffffffffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 INT64: 0/00000000000000000000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 INT64: 0/00000000000000000000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting half-precision to integer -00 HALF: 0xffff (0 => OK) -00 INT64: 65535/0x00000000000000ffff (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 INT64: 64767/0x00000000000000fcff (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 INT64: 64513/0x00000000000000fc01 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 INT64: 64512/0x00000000000000fc00 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 INT64: 64511/0x00000000000000fbff (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 INT64: 49152/0x00000000000000c000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 INT64: 48128/0x00000000000000bc00 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 INT64: 32769/0x000000000000008001 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 INT64: 32768/0x000000000000008000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 INT64: 1/0x000000000000000001 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 INT64: 15360/0x000000000000003c00 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 INT64: 31743/0x000000000000007bff (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 INT64: 31744/0x000000000000007c00 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 INT64: 31745/0x000000000000007c01 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 INT64: 31999/0x000000000000007cff (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 INT64: 32767/0x000000000000007fff (0 => OK) -#### Enabling ARM Alternative Half Precision -### Rounding to nearest -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7fff (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -### Rounding upwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0x01 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x400 (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 HALF: 0x401 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x4170 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4249 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bff (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7c00 (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7fff (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x1 => INVALID) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750797e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005935e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005935e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015673e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015673e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851006e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851006e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324219e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324219e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635273e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635273e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859812e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766502400000000000e+09 / 0x4f730c3b (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962457600000000000e+09 / 0x4f71605e (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750797e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013061e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638080000000000000e+08 / 0x4e4c0001 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015662e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026624000000000000e+08 / 0x4e4e0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994299e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896384000000000000e+08 / 0x4e61ff01 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013665e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912768000000000000e+08 / 0x4e620001 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138310e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282844e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238764e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509080e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675456000000000000e+09 / 0x4e805bf1 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311600e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07853004800000000000e+09 / 0x4e809220 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32540006400000000000e+09 / 0x4e9e0000 (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859812e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570815e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -### Rounding downwards -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8001 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7ffe (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859812e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909791e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909791e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635273e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635273e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289629e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289629e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730512e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730512e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750797e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570815e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859812e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007530e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999085e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138310e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750797e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -### Rounding to zero -Converting single-precision to half-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 HALF: 0x8000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 HALF: 0x8000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 HALF: 0xffff (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 HALF: 0xffff (0x1 => INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 HALF: 0xffff (0x1 => INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 HALF: 0xffff (0x1 => INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 HALF: 0x8000 (0x18 => UNDERFLOW INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 HALF: 0000 (0x18 => UNDERFLOW INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 HALF: 0x3ff (0x18 => UNDERFLOW INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 HALF: 0x400 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 HALF: 0x3c00 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 HALF: 0x3c01 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 HALF: 0x4000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 HALF: 0x416f (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 HALF: 0x4248 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 HALF: 0x7bfe (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 HALF: 0x7bff (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 HALF: 0x7bff (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 HALF: 0x7ffe (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 HALF: 0x7fff (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 HALF: 0x7fff (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 HALF: 0x7fff (0x1 => INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 HALF: 0x7fff (0x1 => INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 HALF: 0x7fff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 HALF: 0000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 HALF: 0000 (0x1 => INVALID) -Converting single-precision to double-precision -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 DOUBLE: -nan / 0x00fffc000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 DOUBLE: -1.11100004769645909790e+31 / 0x00c661874b20000000 (0 => OK) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 DOUBLE: -1.11100003258488635272e+30 / 0x00c62c0bab60000000 (0 => OK) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 DOUBLE: -1.08700982243137289628e-12 / 0x00bd731f7500000000 (0 => OK) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 DOUBLE: -1.78051176151664730511e-20 / 0x00bbd5054440000000 (0 => OK) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 DOUBLE: 2.98023223876953125000e-08 / 0x003e60000000000000 (0 => OK) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 DOUBLE: 5.96045985901128005934e-08 / 0x003e6ffffe60000000 (0 => OK) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 DOUBLE: 6.09755988989491015672e-05 / 0x003f0ff801a0000000 (0 => OK) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 DOUBLE: 6.10351999057456851005e-05 / 0x003f100000c0000000 (0 => OK) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 DOUBLE: 2.71828174591064453125e+00 / 0x004005bf0a80000000 (0 => OK) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 DOUBLE: 3.14159274101257324218e+00 / 0x00400921fb60000000 (0 => OK) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 DOUBLE: 1.11100003258488635272e+30 / 0x00462c0bab60000000 (0 => OK) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 DOUBLE: nan / 0x007ffc000000000000 (0x1 => INVALID) -Converting double-precision to half-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 HALF: 0000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 HALF: 0000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 HALF: 0000 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 HALF: 0000 (0x1 => INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 HALF: 0000 (0x1 => INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 HALF: 0000 (0x1 => INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 HALF: 0000 (0x1 => INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 HALF: 0000 (0x1 => INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 HALF: 0000 (0x1 => INVALID) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 HALF: 0000 (0x1 => INVALID) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 HALF: 0000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 HALF: 0000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 HALF: 0000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 HALF: 0000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 HALF: 0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 HALF: 0000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 HALF: 0000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 HALF: 0000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 HALF: 0x01 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 HALF: 0x01 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 HALF: 0000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 HALF: 0000 (0x10 => INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 HALF: 0000 (0x10 => INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 HALF: 0x01 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 HALF: 0x02 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 HALF: 0x02 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 HALF: 0x03 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 HALF: 0xffdf (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 HALF: 0xffe0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 HALF: 0xffe1 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 HALF: 0xffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 HALF: 0xffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 HALF: 0xffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 HALF: 0xffff (0 => OK) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 HALF: 0xffff (0x1 => INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 HALF: 0xffff (0x1 => INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 HALF: 0xffff (0x1 => INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 HALF: 0xffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 HALF: 0000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 HALF: 0000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 HALF: 0000 (0x1 => INVALID) -Converting double-precision to single-precision -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 SINGLE: 4.29077299200000000000e+09 / 0x4f7fc000 (0 => OK) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 SINGLE: 4.28657868800000000000e+09 / 0x4f7f8000 (0 => OK) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x14 => OVERFLOW INEXACT ) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 SINGLE: 4.28657843200000000000e+09 / 0x4f7f7fff (0x10 => INEXACT ) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 SINGLE: 4.07766476800000000000e+09 / 0x4f730c3a (0x10 => INEXACT ) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 SINGLE: 4.04962432000000000000e+09 / 0x4f71605d (0x10 => INEXACT ) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 SINGLE: 3.22122547200000000000e+09 / 0x4f400000 (0 => OK) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 SINGLE: 3.21283686400000000000e+09 / 0x4f3f8000 (0 => OK) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 SINGLE: 2.14748364800000000000e+09 / 0x4f000000 (0x18 => UNDERFLOW INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 SINGLE: 2.15587225600000000000e+09 / 0x4f008000 (0 => OK) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 SINGLE: 8.38860800000000000000e+06 / 0x4b000000 (0 => OK) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 SINGLE: 8.55638016000000000000e+08 / 0x4e4c0000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 SINGLE: 8.64026560000000000000e+08 / 0x4e4dffff (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 SINGLE: 9.47896320000000000000e+08 / 0x4e61ff00 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 SINGLE: 9.47912704000000000000e+08 / 0x4e620000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 SINGLE: 1.06536140800000000000e+09 / 0x4e7e0080 (0 => OK) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 SINGLE: 1.06535321600000000000e+09 / 0x4e7e0000 (0 => OK) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 SINGLE: 1.07374182400000000000e+09 / 0x4e800000 (0 => OK) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 SINGLE: 1.07675443200000000000e+09 / 0x4e805bf0 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 SINGLE: 1.07852992000000000000e+09 / 0x4e80921f (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 SINGLE: 1.19956249600000000000e+09 / 0x4e8effbe (0 => OK) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 SINGLE: 1.19956275200000000000e+09 / 0x4e8effc0 (0 => OK) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 SINGLE: 1.19956300800000000000e+09 / 0x4e8effc2 (0 => OK) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 SINGLE: 1.20795123200000000000e+09 / 0x4e8fffbf (0 => OK) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 SINGLE: 1.20795136000000000000e+09 / 0x4e8fffc0 (0 => OK) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 SINGLE: 1.20795148800000000000e+09 / 0x4e8fffc1 (0 => OK) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 SINGLE: 1.32539993600000000000e+09 / 0x4e9dffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x10 => INEXACT ) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 SINGLE: 2.13909491200000000000e+09 / 0x4efeffff (0x14 => OVERFLOW INEXACT ) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 SINGLE: 2.13909504000000000000e+09 / 0x4eff0000 (0 => OK) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0 => OK) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 SINGLE: 2.14328934400000000000e+09 / 0x4eff8000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 SINGLE: 2.14538649600000000000e+09 / 0x4effc000 (0x1 => INVALID) -Converting half-precision to single-precision -00 HALF: 0xffff (0 => OK) -00 SINGLE: -1.31008000000000000000e+05 / 0xc7ffe000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 SINGLE: -8.18560000000000000000e+04 / 0xc79fe000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 SINGLE: -6.56000000000000000000e+04 / 0xc7802000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 SINGLE: -6.55360000000000000000e+04 / 0xc7800000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 SINGLE: -6.55040000000000000000e+04 / 0xc77fe000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 SINGLE: -2.00000000000000000000e+00 / 0xc0000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 SINGLE: -1.00000000000000000000e+00 / 0xbf800000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 SINGLE: -5.96046447753906250000e-08 / 0xb3800000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 SINGLE: -0.00000000000000000000e+00 / 0x80000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 SINGLE: 5.96046447753906250000e-08 / 0x33800000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 SINGLE: 6.55360000000000000000e+04 / 0x47800000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 SINGLE: 6.56000000000000000000e+04 / 0x47802000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 SINGLE: 8.18560000000000000000e+04 / 0x479fe000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -Converting half-precision to double-precision -00 HALF: 0xffff (0 => OK) -00 DOUBLE: 6.55350000000000000000e+04 / 0x0040efffe000000000 (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 DOUBLE: 6.47670000000000000000e+04 / 0x0040ef9fe000000000 (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 DOUBLE: 6.45130000000000000000e+04 / 0x0040ef802000000000 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 DOUBLE: 6.45120000000000000000e+04 / 0x0040ef800000000000 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 DOUBLE: 6.45110000000000000000e+04 / 0x0040ef7fe000000000 (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 DOUBLE: 4.91520000000000000000e+04 / 0x0040e8000000000000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 DOUBLE: 4.81280000000000000000e+04 / 0x0040e7800000000000 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 DOUBLE: 3.27690000000000000000e+04 / 0x0040e0002000000000 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 DOUBLE: 3.27680000000000000000e+04 / 0x0040e0000000000000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 DOUBLE: 1.53600000000000000000e+04 / 0x0040ce000000000000 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 DOUBLE: 3.17430000000000000000e+04 / 0x0040deffc000000000 (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 DOUBLE: 3.17440000000000000000e+04 / 0x0040df000000000000 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 DOUBLE: 3.17450000000000000000e+04 / 0x0040df004000000000 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 DOUBLE: 3.19990000000000000000e+04 / 0x0040df3fc000000000 (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 DOUBLE: 3.27670000000000000000e+04 / 0x0040dfffc000000000 (0 => OK) -Converting single-precision to integer -00 SINGLE: -nan / 0xffa00000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 SINGLE: -nan / 0xffc00000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 SINGLE: -inf / 0xff800000 (0 => OK) -02 INT64: 1/0x000000000000000001 (0x1 => INVALID) -03 SINGLE: -3.40282346638528859811e+38 / 0xff7fffff (0 => OK) -03 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -04 SINGLE: -1.11100004769645909790e+31 / 0xf30c3a59 (0 => OK) -04 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -05 SINGLE: -1.11100003258488635272e+30 / 0xf1605d5b (0 => OK) -05 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -06 SINGLE: -1.08700982243137289628e-12 / 0xab98fba8 (0 => OK) -06 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -07 SINGLE: -1.78051176151664730511e-20 / 0x9ea82a22 (0 => OK) -07 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -08 SINGLE: -1.17549435082228750796e-38 / 0x80800000 (0 => OK) -08 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -09 SINGLE: 0.00000000000000000000e+00 / 0000000000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 SINGLE: 1.17549435082228750796e-38 / 0x00800000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 SINGLE: 2.98023223876953125000e-08 / 0x33000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 SINGLE: 5.96045985901128005934e-08 / 0x337ffff3 (0 => OK) -12 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -13 SINGLE: 6.09755988989491015672e-05 / 0x387fc00d (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 SINGLE: 6.10351999057456851005e-05 / 0x38800006 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 SINGLE: 1.00000000000000000000e+00 / 0x3f800000 (0 => OK) -15 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -16 SINGLE: 1.00097656250000000000e+00 / 0x3f802000 (0 => OK) -16 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -17 SINGLE: 2.00000000000000000000e+00 / 0x40000000 (0 => OK) -17 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -18 SINGLE: 2.71828174591064453125e+00 / 0x402df854 (0 => OK) -18 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -19 SINGLE: 3.14159274101257324218e+00 / 0x40490fdb (0 => OK) -19 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -20 SINGLE: 6.55030000000000000000e+04 / 0x477fdf00 (0 => OK) -20 INT64: 65503/0x00000000000000ffdf (0x10 => INEXACT ) -21 SINGLE: 6.55040000000000000000e+04 / 0x477fe000 (0 => OK) -21 INT64: 65504/0x00000000000000ffe0 (0x10 => INEXACT ) -22 SINGLE: 6.55050000000000000000e+04 / 0x477fe100 (0 => OK) -22 INT64: 65505/0x00000000000000ffe1 (0x10 => INEXACT ) -23 SINGLE: 1.31007000000000000000e+05 / 0x47ffdf80 (0 => OK) -23 INT64: 131007/0x00000000000001ffbf (0x10 => INEXACT ) -24 SINGLE: 1.31008000000000000000e+05 / 0x47ffe000 (0 => OK) -24 INT64: 131008/0x00000000000001ffc0 (0x10 => INEXACT ) -25 SINGLE: 1.31009000000000000000e+05 / 0x47ffe080 (0 => OK) -25 INT64: 131009/0x00000000000001ffc1 (0x10 => INEXACT ) -26 SINGLE: 1.11100003258488635272e+30 / 0x71605d5b (0 => OK) -26 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -27 SINGLE: 3.40282346638528859811e+38 / 0x7f7fffff (0 => OK) -27 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -28 SINGLE: inf / 0x7f800000 (0 => OK) -28 INT64: -1/0x00ffffffffffffffff (0x1 => INVALID) -29 SINGLE: nan / 0x7fc00000 (0 => OK) -29 INT64: 0/00000000000000000000 (0x1 => INVALID) -30 SINGLE: nan / 0x7fa00000 (0 => OK) -30 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting double-precision to integer -00 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -00 INT64: 0/00000000000000000000 (0x1 => INVALID) -01 DOUBLE: -nan / 0x00fff8000000000000 (0 => OK) -01 INT64: 0/00000000000000000000 (0x1 => INVALID) -02 DOUBLE: -inf / 0x00fff0000000000000 (0 => OK) -02 INT64: 1/0x000000000000000001 (0x1 => INVALID) -03 DOUBLE: -1.79769313486231570814e+308 / 0x00ffefffffffffffff (0 => OK) -03 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -04 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -04 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -05 DOUBLE: -3.40282346638528859811e+38 / 0x00c7efffffe0000000 (0 => OK) -05 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -06 DOUBLE: -1.11100000000000007529e+31 / 0x00c661874b135ff654 (0 => OK) -06 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -07 DOUBLE: -1.11099999999999999084e+30 / 0x00c62c0bab523323b9 (0 => OK) -07 INT64: 1/0x000000000000000001 (0x11 => INEXACT INVALID) -08 DOUBLE: -2.00000000000000000000e+00 / 0x00c000000000000000 (0 => OK) -08 INT64: -2/0x00fffffffffffffffe (0x10 => INEXACT ) -09 DOUBLE: -1.00000000000000000000e+00 / 0x00bff0000000000000 (0 => OK) -09 INT64: -1/0x00ffffffffffffffff (0x10 => INEXACT ) -10 DOUBLE: -2.22507385850720138309e-308 / 0x008010000000000000 (0 => OK) -10 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -11 DOUBLE: -1.17549435082228750796e-38 / 0x00b810000000000000 (0 => OK) -11 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -12 DOUBLE: 0.00000000000000000000e+00 / 00000000000000000000 (0 => OK) -12 INT64: 0/00000000000000000000 (0 => OK) -13 DOUBLE: 1.17549435082228750796e-38 / 0x003810000000000000 (0 => OK) -13 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -14 DOUBLE: 2.98023224000000013060e-08 / 0x003e600000001c5f68 (0 => OK) -14 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -15 DOUBLE: 5.96046000000000015661e-08 / 0x003e6ffffe6cb2fa82 (0 => OK) -15 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -16 DOUBLE: 6.09755999999999994298e-05 / 0x003f0ff801a9af58a1 (0 => OK) -16 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -17 DOUBLE: 6.10352000000000013664e-05 / 0x003f100000c06a1ef5 (0 => OK) -17 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -18 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -18 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -19 DOUBLE: 1.00097656250000000000e+00 / 0x003ff0040000000000 (0 => OK) -19 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -20 DOUBLE: 2.22507385850720138309e-308 / 0x000010000000000000 (0 => OK) -20 INT64: 0/00000000000000000000 (0x10 => INEXACT ) -21 DOUBLE: 1.37899728486072282843e-308 / 0x000009ea82a2287680 (0 => OK) -21 INT64: 0/00000000000000000000 (0x18 => UNDERFLOW INEXACT ) -22 DOUBLE: 1.49147387366816238763e-308 / 0x00000ab98fba843210 (0 => OK) -22 INT64: 0/00000000000000000000 (0x18 => UNDERFLOW INEXACT ) -23 DOUBLE: 1.00000000000000000000e+00 / 0x003ff0000000000000 (0 => OK) -23 INT64: 1/0x000000000000000001 (0x10 => INEXACT ) -24 DOUBLE: 2.00000000000000000000e+00 / 0x004000000000000000 (0 => OK) -24 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -25 DOUBLE: 2.71828182845904509079e+00 / 0x004005bf0a8b145769 (0 => OK) -25 INT64: 2/0x000000000000000002 (0x10 => INEXACT ) -26 DOUBLE: 3.14159265358979311599e+00 / 0x00400921fb54442d18 (0 => OK) -26 INT64: 3/0x000000000000000003 (0x10 => INEXACT ) -27 DOUBLE: 6.55030000000000000000e+04 / 0x0040effbe000000000 (0 => OK) -27 INT64: 65503/0x00000000000000ffdf (0x10 => INEXACT ) -28 DOUBLE: 6.55040000000000000000e+04 / 0x0040effc0000000000 (0 => OK) -28 INT64: 65504/0x00000000000000ffe0 (0x10 => INEXACT ) -29 DOUBLE: 6.55050000000000000000e+04 / 0x0040effc2000000000 (0 => OK) -29 INT64: 65505/0x00000000000000ffe1 (0x10 => INEXACT ) -30 DOUBLE: 1.31007000000000000000e+05 / 0x0040fffbf000000000 (0 => OK) -30 INT64: 131007/0x00000000000001ffbf (0x10 => INEXACT ) -31 DOUBLE: 1.31008000000000000000e+05 / 0x0040fffc0000000000 (0 => OK) -31 INT64: 131008/0x00000000000001ffc0 (0x10 => INEXACT ) -32 DOUBLE: 1.31009000000000000000e+05 / 0x0040fffc1000000000 (0 => OK) -32 INT64: 131009/0x00000000000001ffc1 (0x10 => INEXACT ) -33 DOUBLE: 2.14748364700000000000e+09 / 0x0041dfffffffc00000 (0 => OK) -33 INT64: 2147483647/0x00000000007fffffff (0x10 => INEXACT ) -34 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -34 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -35 DOUBLE: 3.40282346638528859811e+38 / 0x0047efffffe0000000 (0 => OK) -35 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -36 DOUBLE: 1.79769313486231570814e+308 / 0x007fefffffffffffff (0 => OK) -36 INT64: -1/0x00ffffffffffffffff (0x11 => INEXACT INVALID) -37 DOUBLE: inf / 0x007ff0000000000000 (0 => OK) -37 INT64: -1/0x00ffffffffffffffff (0x1 => INVALID) -38 DOUBLE: nan / 0x007ff8000000000000 (0 => OK) -38 INT64: 0/00000000000000000000 (0x1 => INVALID) -39 DOUBLE: nan / 0x007ff0000000000001 (0 => OK) -39 INT64: 0/00000000000000000000 (0x1 => INVALID) -40 DOUBLE: nan / 0x007ff4000000000000 (0 => OK) -40 INT64: 0/00000000000000000000 (0x1 => INVALID) -Converting half-precision to integer -00 HALF: 0xffff (0 => OK) -00 INT64: 65535/0x00000000000000ffff (0 => OK) -01 HALF: 0xfcff (0 => OK) -01 INT64: 64767/0x00000000000000fcff (0 => OK) -02 HALF: 0xfc01 (0 => OK) -02 INT64: 64513/0x00000000000000fc01 (0 => OK) -03 HALF: 0xfc00 (0 => OK) -03 INT64: 64512/0x00000000000000fc00 (0 => OK) -04 HALF: 0xfbff (0 => OK) -04 INT64: 64511/0x00000000000000fbff (0 => OK) -05 HALF: 0xc000 (0 => OK) -05 INT64: 49152/0x00000000000000c000 (0 => OK) -06 HALF: 0xbc00 (0 => OK) -06 INT64: 48128/0x00000000000000bc00 (0 => OK) -07 HALF: 0x8001 (0 => OK) -07 INT64: 32769/0x000000000000008001 (0 => OK) -08 HALF: 0x8000 (0 => OK) -08 INT64: 32768/0x000000000000008000 (0 => OK) -09 HALF: 0000 (0 => OK) -09 INT64: 0/00000000000000000000 (0 => OK) -10 HALF: 0x01 (0 => OK) -10 INT64: 1/0x000000000000000001 (0 => OK) -11 HALF: 0x3c00 (0 => OK) -11 INT64: 15360/0x000000000000003c00 (0 => OK) -12 HALF: 0x7bff (0 => OK) -12 INT64: 31743/0x000000000000007bff (0 => OK) -13 HALF: 0x7c00 (0 => OK) -13 INT64: 31744/0x000000000000007c00 (0 => OK) -14 HALF: 0x7c01 (0 => OK) -14 INT64: 31745/0x000000000000007c01 (0 => OK) -15 HALF: 0x7cff (0 => OK) -15 INT64: 31999/0x000000000000007cff (0 => OK) -16 HALF: 0x7fff (0 => OK) -16 INT64: 32767/0x000000000000007fff (0 => OK) diff --git a/tests/tcg/arm/float_convs.ref b/tests/tcg/arm/float_convs.ref deleted file mode 100644 index da8456bbc16e..000000000000 --- a/tests/tcg/arm/float_convs.ref +++ /dev/null @@ -1,748 +0,0 @@ -### Rounding to nearest -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (INEXACT ) - to uint32: 1 (OK) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (INEXACT ) - to uint32: 2 (OK) - to uint64: 2 (INEXACT ) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (INEXACT ) - to uint32: 65503 (OK) - to uint64: 65503 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (INEXACT ) - to uint32: 65504 (OK) - to uint64: 65504 (INEXACT ) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (INEXACT ) - to uint32: 65505 (OK) - to uint64: 65505 (INEXACT ) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (INEXACT ) - to uint32: 131007 (OK) - to uint64: 131007 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (INEXACT ) - to uint32: 131008 (OK) - to uint64: 131008 (INEXACT ) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (INEXACT ) - to uint32: 131009 (OK) - to uint64: 131009 (INEXACT ) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding upwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (INEXACT ) - to uint32: 1 (OK) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (INEXACT ) - to uint32: 2 (OK) - to uint64: 2 (INEXACT ) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (INEXACT ) - to uint32: 65503 (OK) - to uint64: 65503 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (INEXACT ) - to uint32: 65504 (OK) - to uint64: 65504 (INEXACT ) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (INEXACT ) - to uint32: 65505 (OK) - to uint64: 65505 (INEXACT ) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (INEXACT ) - to uint32: 131007 (OK) - to uint64: 131007 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (INEXACT ) - to uint32: 131008 (OK) - to uint64: 131008 (INEXACT ) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (INEXACT ) - to uint32: 131009 (OK) - to uint64: 131009 (INEXACT ) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding downwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (INEXACT ) - to uint32: 1 (OK) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (INEXACT ) - to uint32: 2 (OK) - to uint64: 2 (INEXACT ) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (INEXACT ) - to uint32: 65503 (OK) - to uint64: 65503 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (INEXACT ) - to uint32: 65504 (OK) - to uint64: 65504 (INEXACT ) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (INEXACT ) - to uint32: 65505 (OK) - to uint64: 65505 (INEXACT ) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (INEXACT ) - to uint32: 131007 (OK) - to uint64: 131007 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (INEXACT ) - to uint32: 131008 (OK) - to uint64: 131008 (INEXACT ) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (INEXACT ) - to uint32: 131009 (OK) - to uint64: 131009 (INEXACT ) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding to zero -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: 1 (INEXACT INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (INEXACT ) - to uint32: 1 (OK) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (INEXACT ) - to uint32: 2 (OK) - to uint64: 2 (INEXACT ) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (INEXACT ) - to uint32: 65503 (OK) - to uint64: 65503 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (INEXACT ) - to uint32: 65504 (OK) - to uint64: 65504 (INEXACT ) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (INEXACT ) - to uint32: 65505 (OK) - to uint64: 65505 (INEXACT ) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (INEXACT ) - to uint32: 131007 (OK) - to uint64: 131007 (INEXACT ) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (INEXACT ) - to uint32: 131008 (OK) - to uint64: 131008 (INEXACT ) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (INEXACT ) - to uint32: 131009 (OK) - to uint64: 131009 (INEXACT ) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INEXACT INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INEXACT INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ffc000000000000) (INVALID) - to int32: 0 (INVALID) - to int64: 0 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) diff --git a/tests/tcg/arm/float_madds.ref b/tests/tcg/arm/float_madds.ref deleted file mode 100644 index 21c053988789..000000000000 --- a/tests/tcg/arm/float_madds.ref +++ /dev/null @@ -1,768 +0,0 @@ -### Rounding to nearest -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding upwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe800000000000000p-25:0x337ffff4) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe800000000000000p-50:0x26fffff4) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000200000000000000p-25:0x33000001) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00080000000000000000p-25:0x33000400) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f400000000000000p-24:0x338000fa) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000e00000000000000p-14:0x38800007) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf600000000000000p-24:0x3387fdfb) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000200000000000000p+0:0x3f800001) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d400000000000000p+2:0x409711ea) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458200000000000000p+3:0x4128a2c1) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0600000000000000p+3:0x41100603) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1600000000000000p+15:0x477fe78b) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56200000000000000p+17:0x482de2b1) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0a00000000000000p+31:0x4f7fbf05) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+31:0x4f7fc005) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+32:0x4fffc005) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8a00000000000000p+33:0x507fbfc5) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800a00000000000000p+33:0x507fc005) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab800000000000000p+99:0x71605d5c) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c082a000000000000000p+116:0x79e04150) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-148:0x00000002) flags=UNDERFLOW INEXACT (32/0) -### Rounding downwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x1.00000000000000000000p-149:0x80000001) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding to zero -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffe00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fe00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) diff --git a/tests/tcg/arm/hello-arm.c b/tests/tcg/arm/hello-arm.c deleted file mode 100644 index e33edf949fb8..000000000000 --- a/tests/tcg/arm/hello-arm.c +++ /dev/null @@ -1,113 +0,0 @@ -#define __NR_SYSCALL_BASE 0x900000 -#define __NR_exit1 (__NR_SYSCALL_BASE+ 1) -#define __NR_write (__NR_SYSCALL_BASE+ 4) - -#define __sys2(x) #x -#define __sys1(x) __sys2(x) - -#ifndef __syscall -#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t" -#endif - -#define __syscall_return(type, res) \ -do { \ - return (type) (res); \ -} while (0) - -#define _syscall0(type,name) \ -type name(void) { \ - long __res; \ - __asm__ __volatile__ ( \ - __syscall(name) \ - "mov %0,r0" \ - :"=r" (__res) : : "r0","lr"); \ - __syscall_return(type,__res); \ -} - -#define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1) { \ - long __res; \ - __asm__ __volatile__ ( \ - "mov\tr0,%1\n\t" \ - __syscall(name) \ - "mov %0,r0" \ - : "=r" (__res) \ - : "r" ((long)(arg1)) \ - : "r0","lr"); \ - __syscall_return(type,__res); \ -} - -#define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1,type2 arg2) { \ - long __res; \ - __asm__ __volatile__ ( \ - "mov\tr0,%1\n\t" \ - "mov\tr1,%2\n\t" \ - __syscall(name) \ - "mov\t%0,r0" \ - : "=r" (__res) \ - : "r" ((long)(arg1)),"r" ((long)(arg2)) \ - : "r0","r1","lr"); \ - __syscall_return(type,__res); \ -} - - -#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1,type2 arg2,type3 arg3) { \ - long __res; \ - __asm__ __volatile__ ( \ - "mov\tr0,%1\n\t" \ - "mov\tr1,%2\n\t" \ - "mov\tr2,%3\n\t" \ - __syscall(name) \ - "mov\t%0,r0" \ - : "=r" (__res) \ - : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \ - : "r0","r1","r2","lr"); \ - __syscall_return(type,__res); \ -} - - -#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ - long __res; \ - __asm__ __volatile__ ( \ - "mov\tr0,%1\n\t" \ - "mov\tr1,%2\n\t" \ - "mov\tr2,%3\n\t" \ - "mov\tr3,%4\n\t" \ - __syscall(name) \ - "mov\t%0,r0" \ - : "=r" (__res) \ - : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \ - : "r0","r1","r2","r3","lr"); \ - __syscall_return(type,__res); \ -} - - -#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ - long __res; \ - __asm__ __volatile__ ( \ - "mov\tr0,%1\n\t" \ - "mov\tr1,%2\n\t" \ - "mov\tr2,%3\n\t" \ - "mov\tr3,%4\n\t" \ - "mov\tr4,%5\n\t" \ - __syscall(name) \ - "mov\t%0,r0" \ - : "=r" (__res) \ - : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \ - "r" ((long)(arg5)) \ - : "r0","r1","r2","r3","r4","lr"); \ - __syscall_return(type,__res); \ -} - -_syscall1(int,exit1,int,status); -_syscall3(int,write,int,fd,const char *,buf, int, len); - -void _start(void) -{ - write(1, "Hello World\n", 12); - exit1(0); -} diff --git a/tests/tcg/arm/pcalign-a32.c b/tests/tcg/arm/pcalign-a32.c deleted file mode 100644 index 3c9c8cc97b13..000000000000 --- a/tests/tcg/arm/pcalign-a32.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Test PC misalignment exception */ - -#ifdef __thumb__ -#error "This test must be compiled for ARM" -#endif - -#include -#include -#include -#include - -static void *expected; - -static void sigbus(int sig, siginfo_t *info, void *vuc) -{ - assert(info->si_code == BUS_ADRALN); - assert(info->si_addr == expected); - exit(EXIT_SUCCESS); -} - -int main() -{ - void *tmp; - - struct sigaction sa = { - .sa_sigaction = sigbus, - .sa_flags = SA_SIGINFO - }; - - if (sigaction(SIGBUS, &sa, NULL) < 0) { - perror("sigaction"); - return EXIT_FAILURE; - } - - asm volatile("adr %0, 1f + 2\n\t" - "str %0, %1\n\t" - "bx %0\n" - "1:" - : "=&r"(tmp), "=m"(expected)); - - /* - * From v8, it is CONSTRAINED UNPREDICTABLE whether BXWritePC aligns - * the address or not. If so, we can legitimately fall through. - */ - return EXIT_SUCCESS; -} diff --git a/tests/tcg/arm/semicall.h b/tests/tcg/arm/semicall.h deleted file mode 100644 index ad8ac51310bb..000000000000 --- a/tests/tcg/arm/semicall.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Semihosting Tests - ARM Helper - * - * Copyright (c) 2019 - * Written by Alex Bennée - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -uintptr_t __semi_call(uintptr_t type, uintptr_t arg0) -{ - register uintptr_t t asm("r0") = type; - register uintptr_t a0 asm("r1") = arg0; -#ifdef __thumb__ -# define SVC "svc 0xab" -#else -# define SVC "svc 0x123456" -#endif - asm(SVC : "=r" (t) - : "r" (t), "r" (a0)); - return t; -} diff --git a/tests/tcg/arm/test-arm-iwmmxt.S b/tests/tcg/arm/test-arm-iwmmxt.S deleted file mode 100644 index d647f9404ae9..000000000000 --- a/tests/tcg/arm/test-arm-iwmmxt.S +++ /dev/null @@ -1,49 +0,0 @@ -@ Checks whether iwMMXt is functional. -.code 32 -.globl main - -main: -ldr r0, =data0 -ldr r1, =data1 -ldr r2, =data2 -#ifndef FPA -wldrd wr0, [r0, #0] -wldrd wr1, [r0, #8] -wldrd wr2, [r1, #0] -wldrd wr3, [r1, #8] -wsubb wr2, wr2, wr0 -wsubb wr3, wr3, wr1 -wldrd wr0, [r2, #0] -wldrd wr1, [r2, #8] -waddb wr0, wr0, wr2 -waddb wr1, wr1, wr3 -wstrd wr0, [r2, #0] -wstrd wr1, [r2, #8] -#else -ldfe f0, [r0, #0] -ldfe f1, [r0, #8] -ldfe f2, [r1, #0] -ldfe f3, [r1, #8] -adfdp f2, f2, f0 -adfdp f3, f3, f1 -ldfe f0, [r2, #0] -ldfe f1, [r2, #8] -adfd f0, f0, f2 -adfd f1, f1, f3 -stfe f0, [r2, #0] -stfe f1, [r2, #8] -#endif -mov r0, #1 -mov r1, r2 -mov r2, #0x11 -swi #0x900004 -mov r0, #0 -swi #0x900001 - -.data -data0: -.string "aaaabbbbccccdddd" -data1: -.string "bbbbccccddddeeee" -data2: -.string "hvLLWs\x1fsdrs9\x1fNJ-\n" diff --git a/tests/tcg/arm/test-armv6m-undef.S b/tests/tcg/arm/test-armv6m-undef.S deleted file mode 100644 index d18ca56b4ad6..000000000000 --- a/tests/tcg/arm/test-armv6m-undef.S +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Test ARMv6-M UNDEFINED 32-bit instructions - * - * Copyright 2018 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. - */ - -/* - * Test that UNDEFINED 32-bit instructions fault as expected. This is an - * interesting test because ARMv6-M shares code with its more fully-featured - * siblings and it's necessary to verify that its limited instruction set is - * emulated correctly. - * - * The emulator must be invoked with -semihosting so that the test case can - * terminate with exit code 0 on success or 1 on failure. - * - * Failures can be debugged with -d in_asm,int,exec,cpu and the - * gdbstub (-S -s). - */ - -.syntax unified -.cpu cortex-m0 -.thumb - -/* - * Memory map - */ -#define SRAM_BASE 0x20000000 -#define SRAM_SIZE (16 * 1024) - -/* - * Semihosting interface on ARM T32 - * See "Semihosting for AArch32 and AArch64 Version 2.0 Documentation" by ARM - */ -#define semihosting_call bkpt 0xab -#define SYS_EXIT 0x18 - -vector_table: - .word SRAM_BASE + SRAM_SIZE /* 0. SP_main */ - .word exc_reset_thumb /* 1. Reset */ - .word 0 /* 2. NMI */ - .word exc_hard_fault_thumb /* 3. HardFault */ - .rept 7 - .word 0 /* 4-10. Reserved */ - .endr - .word 0 /* 11. SVCall */ - .word 0 /* 12. Reserved */ - .word 0 /* 13. Reserved */ - .word 0 /* 14. PendSV */ - .word 0 /* 15. SysTick */ - .rept 32 - .word 0 /* 16-47. External Interrupts */ - .endr - -exc_reset: -.equ exc_reset_thumb, exc_reset + 1 -.global exc_reset_thumb - /* The following 32-bit UNDEFINED instructions are tested by executing - * them. The HardFault exception handler should execute and return to - * the next test case. If no exception is raised the test fails. - */ - - /* Table A5-9 32-bit Thumb encoding */ - .short 0b1110100000000000 - .short 0b0000000000000000 - b not_reached - .short 0b1110100000000000 - .short 0b1000000000000000 - b not_reached - .short 0b1111100000000000 - .short 0b0000000000000000 - b not_reached - .short 0b1111100000000000 - .short 0b1000000000000000 - b not_reached - .short 0b1111000000000000 - .short 0b0000000000000000 - b not_reached - - /* Table A5-10 Branch and miscellaneous control instructions */ - .short 0b1111011111110000 - .short 0b1010000000000000 - b not_reached - - /* The following are valid 32-bit instructions that must not raise a - * HardFault. - */ - - /* B4.2.3 Move to Special Register (moves to IPSR are ignored) */ - msr ipsr, r0 - b 1f - b not_reached -1: - /* B4.2.2 Move from Special Register */ - mrs r0, ipsr - b 1f - b not_reached -1: - /* A6.7.13 Branch with Link (immediate) */ - bl 1f -1: - b 1f - b not_reached -1: - /* A6.7.21 Data Memory Barrier */ - dmb - b 1f - b not_reached -1: - /* A6.7.22 Data Synchronization Barrier */ - dsb - b 1f - b not_reached -1: - /* A6.7.24 Instruction Memory Barrier */ - isb - b 1f - b not_reached -1: - - /* Success! */ - movs r0, 1 - b exit - -not_reached: /* Failure :( */ - movs r0, 0 - b exit - -/* When a HardFault occurs, return to pc+6 (test cases are 3 halfwords long) */ -exc_hard_fault: -.equ exc_hard_fault_thumb, exc_hard_fault + 1 -.global exc_hard_fault_thumb - ldr r0, [sp, 0x18] - adds r0, 6 - str r0, [sp, 0x18] - bx lr - -/* - * exit: Terminate emulator - * @r0: 0 - failure, 1 - success - */ -exit: - movs r1, 0 - cmp r0, 1 - bne 1f - ldr r1, ADP_Stopped_ApplicationExit -1: - movs r0, SYS_EXIT - semihosting_call -.align 2 -ADP_Stopped_ApplicationExit: - .word 0x20026 diff --git a/tests/tcg/arm/test-armv6m-undef.ld b/tests/tcg/arm/test-armv6m-undef.ld deleted file mode 100644 index 43dbbf17d57c..000000000000 --- a/tests/tcg/arm/test-armv6m-undef.ld +++ /dev/null @@ -1,21 +0,0 @@ -ENTRY(exc_reset_thumb) - -SECTIONS -{ - . = 0x0; - .text : { - *(.text) - } - .data : { - *(.data) - } - .rodata : { - *(.rodata) - } - .bss : { - *(.bss) - } - /DISCARD/ : { - *(.ARM.attributes) - } -} diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh deleted file mode 100755 index 84f928f7f879..000000000000 --- a/tests/tcg/configure.sh +++ /dev/null @@ -1,354 +0,0 @@ -#! /bin/sh - -if test -z "$source_path"; then - echo Do not invoke this script directly. It is called - echo automatically by configure. - exit 1 -fi - -write_c_skeleton() { - cat > $TMPC </dev/null 2>&1 -} - -do_compiler() { - # Run the compiler, capturing its output to the log. First argument - # is compiler binary to execute. - local compiler="$1" - shift - if test -n "$BASH_VERSION"; then eval ' - echo >>config.log " -funcs: ${FUNCNAME[*]} -lines: ${BASH_LINENO[*]}" - '; fi - echo $compiler "$@" >> config.log - $compiler "$@" >> config.log 2>&1 || return $? -} - - -TMPDIR1="config-temp" -TMPC="${TMPDIR1}/qemu-conf.c" -TMPE="${TMPDIR1}/qemu-conf.exe" - -container="no" -if test $use_containers = "yes"; then - if has "docker" || has "podman"; then - container=$($python $source_path/tests/docker/docker.py probe) - fi -fi - -# cross compilers defaults, can be overridden with --cross-cc-ARCH -: ${cross_cc_aarch64="aarch64-linux-gnu-gcc"} -: ${cross_cc_aarch64_be="$cross_cc_aarch64"} -: ${cross_cc_cflags_aarch64_be="-mbig-endian"} -: ${cross_cc_alpha="alpha-linux-gnu-gcc"} -: ${cross_cc_arm="arm-linux-gnueabihf-gcc"} -: ${cross_cc_cflags_armeb="-mbig-endian"} -: ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"} -: ${cross_cc_cflags_hexagon="-mv67 -O2 -static"} -: ${cross_cc_hppa="hppa-linux-gnu-gcc"} -: ${cross_cc_i386="i686-linux-gnu-gcc"} -: ${cross_cc_cflags_i386="-m32"} -: ${cross_cc_m68k="m68k-linux-gnu-gcc"} -: ${cross_cc_microblaze="microblaze-linux-musl-gcc"} -: ${cross_cc_mips64el="mips64el-linux-gnuabi64-gcc"} -: ${cross_cc_mips64="mips64-linux-gnuabi64-gcc"} -: ${cross_cc_mipsel="mipsel-linux-gnu-gcc"} -: ${cross_cc_mips="mips-linux-gnu-gcc"} -: ${cross_cc_nios2="nios2-linux-gnu-gcc"} -: ${cross_cc_ppc="powerpc-linux-gnu-gcc"} -: ${cross_cc_cflags_ppc="-m32"} -: ${cross_cc_ppc64="powerpc64-linux-gnu-gcc"} -: ${cross_cc_cflags_ppc64="-m64 -mbig-endian"} -: ${cross_cc_ppc64le="$cross_cc_ppc64"} -: ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"} -: ${cross_cc_riscv64="riscv64-linux-gnu-gcc"} -: ${cross_cc_s390x="s390x-linux-gnu-gcc"} -: ${cross_cc_sh4="sh4-linux-gnu-gcc"} -: ${cross_cc_cflags_sparc="-m32 -mv8plus -mcpu=ultrasparc"} -: ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} -: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} -: ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} -: ${cross_cc_cflags_x86_64="-m64"} - -# tricore is special as it doesn't have a compiler -: ${cross_as_tricore="tricore-as"} -: ${cross_ld_tricore="tricore-ld"} - -for target in $target_list; do - arch=${target%%-*} - - # reset all container fields - container_image= - container_hosts= - container_cross_cc= - container_cross_as= - container_cross_ld= - - # suppress clang - supress_clang= - - case $target in - aarch64-*) - # We don't have any bigendian build tools so we only use this for AArch64 - container_hosts="x86_64 aarch64" - container_image=debian-arm64-cross - container_cross_cc=aarch64-linux-gnu-gcc-10 - ;; - alpha-*) - container_hosts=x86_64 - container_image=debian-alpha-cross - container_cross_cc=alpha-linux-gnu-gcc - ;; - arm-*) - # We don't have any bigendian build tools so we only use this for ARM - container_hosts="x86_64 aarch64" - container_image=debian-armhf-cross - container_cross_cc=arm-linux-gnueabihf-gcc - ;; - cris-*) - container_hosts=x86_64 - container_image=fedora-cris-cross - container_cross_cc=cris-linux-gnu-gcc - ;; - hexagon-*) - container_hosts=x86_64 - container_image=debian-hexagon-cross - container_cross_cc=hexagon-unknown-linux-musl-clang - ;; - hppa-*) - container_hosts=x86_64 - container_image=debian-hppa-cross - container_cross_cc=hppa-linux-gnu-gcc - ;; - i386-*) - container_hosts=x86_64 - container_image=fedora-i386-cross - container_cross_cc=gcc - supress_clang=yes - ;; - m68k-*) - container_hosts=x86_64 - container_image=debian-m68k-cross - container_cross_cc=m68k-linux-gnu-gcc - ;; - microblaze-*) - container_hosts=x86_64 - container_image=debian-microblaze-cross - container_cross_cc=microblaze-linux-musl-gcc - ;; - mips64el-*) - container_hosts=x86_64 - container_image=debian-mips64el-cross - container_cross_cc=mips64el-linux-gnuabi64-gcc - ;; - mips64-*) - container_hosts=x86_64 - container_image=debian-mips64-cross - container_cross_cc=mips64-linux-gnuabi64-gcc - ;; - mipsel-*) - container_hosts=x86_64 - container_image=debian-mipsel-cross - container_cross_cc=mipsel-linux-gnu-gcc - ;; - mips-*) - container_hosts=x86_64 - container_image=debian-mips-cross - container_cross_cc=mips-linux-gnu-gcc - ;; - nios2-*) - container_hosts=x86_64 - container_image=debian-nios2-cross - container_cross_cc=nios2-linux-gnu-gcc - ;; - ppc-*) - container_hosts=x86_64 - container_image=debian-powerpc-test-cross - container_cross_cc=powerpc-linux-gnu-gcc-10 - ;; - ppc64-*|ppc64le-*) - container_hosts=x86_64 - container_image=debian-powerpc-test-cross - container_cross_cc=${target%%-*}-linux-gnu-gcc-10 - container_cross_cc=powerpc${container_cross_cc#ppc} - ;; - riscv64-*) - container_hosts=x86_64 - container_image=debian-riscv64-test-cross - container_cross_cc=riscv64-linux-gnu-gcc - ;; - s390x-*) - container_hosts=x86_64 - container_image=debian-s390x-cross - container_cross_cc=s390x-linux-gnu-gcc - ;; - sh4-*) - container_hosts=x86_64 - container_image=debian-sh4-cross - container_cross_cc=sh4-linux-gnu-gcc - ;; - sparc64-*) - container_hosts=x86_64 - container_image=debian-sparc64-cross - container_cross_cc=sparc64-linux-gnu-gcc - ;; - tricore-softmmu) - container_hosts=x86_64 - container_image=debian-tricore-cross - container_cross_as=tricore-as - container_cross_ld=tricore-ld - ;; - x86_64-*) - container_hosts="aarch64 ppc64el x86_64" - container_image=debian-amd64-cross - container_cross_cc=x86_64-linux-gnu-gcc - supress_clang=yes - ;; - xtensa*-softmmu) - container_hosts=x86_64 - container_image=debian-xtensa-cross - - # default to the dc232b cpu - container_cross_cc=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc - ;; - esac - - config_target_mak=tests/tcg/config-$target.mak - - echo "# Automatically generated by configure - do not modify" > $config_target_mak - echo "TARGET_NAME=$arch" >> $config_target_mak - echo "target=$target" >> $config_target_mak - case $target in - *-linux-user) - echo "CONFIG_USER_ONLY=y" >> $config_target_mak - echo "CONFIG_LINUX_USER=y" >> $config_target_mak - echo "QEMU=$PWD/qemu-$arch" >> $config_target_mak - ;; - *-bsd-user) - echo "CONFIG_USER_ONLY=y" >> $config_target_mak - echo "CONFIG_BSD_USER=y" >> $config_target_mak - echo "QEMU=$PWD/qemu-$arch" >> $config_target_mak - ;; - *-softmmu) - echo "CONFIG_SOFTMMU=y" >> $config_target_mak - echo "QEMU=$PWD/qemu-system-$arch" >> $config_target_mak - ;; - esac - - eval "target_compiler_cflags=\${cross_cc_cflags_$arch}" - echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak - - got_cross_cc=no - - if eval test "x\"\${cross_cc_$arch}\"" != xyes; then - eval "target_compiler=\"\${cross_cc_$arch}\"" - - if has $target_compiler; then - if test "$supress_clang" = yes && - $target_compiler --version | grep -qi "clang"; then - got_cross_cc=no - else - write_c_skeleton - if ! do_compiler "$target_compiler" $target_compiler_cflags \ - -o $TMPE $TMPC -static ; then - # For host systems we might get away with building without -static - if do_compiler "$target_compiler" $target_compiler_cflags \ - -o $TMPE $TMPC ; then - got_cross_cc=yes - echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak - echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak - fi - else - got_cross_cc=yes - echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak - echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak - fi - fi - fi - - # Special handling for assembler only tests - eval "target_as=\"\${cross_as_$arch}\"" - eval "target_ld=\"\${cross_ld_$arch}\"" - if has $target_as && has $target_ld; then - case $target in - tricore-softmmu) - echo "CROSS_CC_GUEST=$target_as" >> $config_target_mak - echo "CROSS_AS_GUEST=$target_as" >> $config_target_mak - echo "CROSS_LD_GUEST=$target_ld" >> $config_target_mak - got_cross_cc=yes - ;; - esac - fi - fi - - 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. - - case $target in - aarch64-*) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.1-a+sve -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.1-a+sve2 -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.3-a -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mbranch-protection=standard -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_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_compiler" $target_compiler_cflags \ - -mpower8-vector -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mpower10 -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak - fi - ;; - i386-linux-user) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -Werror -fno-pie -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak - fi - ;; - esac - elif test $got_cross_cc = no && test "$container" != no && \ - test -n "$container_image"; then - for host in $container_hosts; do - if test "$host" = "$cpu"; then - echo "DOCKER_IMAGE=$container_image" >> $config_target_mak - echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> \ - $config_target_mak - if test -n "$container_cross_as"; then - echo "DOCKER_CROSS_AS_GUEST=$container_cross_as" >> \ - $config_target_mak - fi - if test -n "$container_cross_ld"; then - echo "DOCKER_CROSS_LD_GUEST=$container_cross_ld" >> \ - $config_target_mak - fi - fi - done - fi -done diff --git a/tests/tcg/cris/.gdbinit b/tests/tcg/cris/.gdbinit deleted file mode 100644 index 5e8c1d32f32c..000000000000 --- a/tests/tcg/cris/.gdbinit +++ /dev/null @@ -1,11 +0,0 @@ -b main -b _fail -b exit -display /i $pc -display /x $srp -display /x $r0 -display /x $r1 -display /x $r2 -display /x $r3 -display /x $r4 -display /t $ccs diff --git a/tests/tcg/cris/Makefile.target b/tests/tcg/cris/Makefile.target deleted file mode 100644 index e72d3cbdb23e..000000000000 --- a/tests/tcg/cris/Makefile.target +++ /dev/null @@ -1,59 +0,0 @@ -# -*- Mode: makefile -*- -# -# Cris tests -# -# Currently we can only build the "bare" tests with the docker -# supplied cross-compiler. -# - -CRIS_SRC = $(SRC_PATH)/tests/tcg/cris/bare -CRIS_ALL = $(wildcard $(CRIS_SRC)/*.s) -CRIS_TESTS = $(patsubst $(CRIS_SRC)/%.s, %, $(CRIS_ALL)) -# Filter out common blobs and broken tests -CRIS_BROKEN_TESTS = crt check_jsr -# upstream GCC doesn't support v32 -CRIS_BROKEN_TESTS += check_mcp check_mulv32 check_addiv32 check_movpmv32 -CRIS_BROKEN_TESTS += check_movprv32 check_clearfv32 check_movemrv32 check_bas -CRIS_BROKEN_TESTS += check_lapc check_movei -# no sure why -CRIS_BROKEN_TESTS += check_scc check_xarith - -CRIS_USABLE_TESTS = $(filter-out $(CRIS_BROKEN_TESTS), $(CRIS_TESTS)) -CRIS_RUNS = $(patsubst %, run-%, $(CRIS_USABLE_TESTS)) - -# override the list of tests, as we can't build the multiarch tests -TESTS = $(CRIS_USABLE_TESTS) -EXTRA_RUNS = -VPATH = $(CRIS_SRC) - -AS = $(CC) -x assembler-with-cpp -LD = $(CC) - -# we rely on GCC inline:ing the stuff we tell it to in many places here. -CFLAGS = -Winline -Wall -g -O2 -static -NOSTDFLAGS = -nostartfiles -nostdlib -ASFLAGS += -mcpu=v10 -g -Wa,-I,$(SRC_PATH)/tests/tcg/cris/bare -CRT_FILES = crt.o sys.o - -# stop make deleting crt files if build fails -.PRECIOUS: $(CRT_FILES) - -%.o: %.c - $(CC) -c $< -o $@ - -%.o: %.s - $(AS) $(ASFLAGS) -c $< -o $@ - -%: %.s $(CRT_FILES) - $(CC) $(ASFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT_FILES) - -# The default CPU breaks (possibly as it's max?) so force crisv17 -QEMU_OPTS=-cpu crisv17 - -# Additional runners to run under GNU SIM -CRIS_RUNS_ON_SIM=$(patsubst %, %-on-sim, $(CRIS_RUNS)) -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") diff --git a/tests/tcg/cris/README b/tests/tcg/cris/README deleted file mode 100644 index 2e65a76f10bd..000000000000 --- a/tests/tcg/cris/README +++ /dev/null @@ -1 +0,0 @@ -Test-suite for the cris port. Heavily based on the test-suite for the CRIS port of sim by Hans-Peter Nilsson. diff --git a/tests/tcg/cris/bare/check_addcv17.s b/tests/tcg/cris/bare/check_addcv17.s deleted file mode 100644 index 52ef7a97169c..000000000000 --- a/tests/tcg/cris/bare/check_addcv17.s +++ /dev/null @@ -1,65 +0,0 @@ -# mach: crisv17 - - .include "testutils.inc" - - .macro addc Rs Rd inc=0 -# Create the instruction manually since there is no assembler support yet - .word (\Rd << 12) | \Rs | (\inc << 10) | 0x09a0 - .endm - - start - - .data -mem1: - .dword 0x0 -mem2: - .dword 0x12345678 - - .text - move.d mem1,r4 - clearf nzvc - addc 4 3 - test_cc 0 1 0 0 - checkr3 0 - - move.d mem1,r4 - clearf nzvc - ax - addc 4 3 - test_cc 0 0 0 0 - checkr3 0 - - move.d mem1,r4 - clearf nzvc - setf c - addc 4 3 - test_cc 0 0 0 0 - checkr3 1 - - move.d mem2,r4 - moveq 2, r3 - clearf nzvc - setf c - addc 4 3 - test_cc 0 0 0 0 - checkr3 1234567b - - move.d mem2,r5 - clearf nzvc - cmp.d r4,r5 - test_cc 0 1 0 0 - - move.d mem2,r4 - moveq 2, r3 - clearf nzvc - addc 4 3 inc=1 - test_cc 0 0 0 0 - checkr3 1234567a - - move.d mem2,r5 - clearf nzvc - addq 4,r5 - cmp.d r4,r5 - test_cc 0 1 0 0 - - quit diff --git a/tests/tcg/cris/bare/check_addi.s b/tests/tcg/cris/bare/check_addi.s deleted file mode 100644 index a00dec02af81..000000000000 --- a/tests/tcg/cris/bare/check_addi.s +++ /dev/null @@ -1,57 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 0\n1\n2\n4\nbe02460f\n69d035a6\nc16c14d4\n - - .include "testutils.inc" - start - moveq 0,r3 - moveq 0,r4 - clearf zcvn - addi r4.b,r3 - test_cc 0 0 0 0 - checkr3 0 - - moveq 0,r3 - moveq 1,r4 - setf zcvn - addi r4.b,r3 - test_cc 1 1 1 1 - checkr3 1 - - moveq 0,r3 - moveq 1,r4 - setf cv - clearf zn - addi r4.w,r3 - test_cc 0 0 1 1 - checkr3 2 - - moveq 0,r3 - moveq 1,r4 - clearf cv - setf zn - addi r4.d,r3 - test_cc 1 1 0 0 - checkr3 4 - - move.d 0x12345678,r3 - move.d 0xabcdef97,r4 - clearf cn - setf zv - addi r4.b,r3 - test_cc 0 1 1 0 - checkr3 be02460f - - move.d 0x12345678,r3 - move.d 0xabcdef97,r4 - setf cn - clearf zv - addi r4.w,r3 - test_cc 1 0 0 1 - checkr3 69d035a6 - - move.d 0x12345678,r3 - move.d 0xabcdef97,r4 - addi r4.d,r3 - checkr3 c16c14d4 - - quit diff --git a/tests/tcg/cris/bare/check_addiv32.s b/tests/tcg/cris/bare/check_addiv32.s deleted file mode 100644 index 20ba25d2192f..000000000000 --- a/tests/tcg/cris/bare/check_addiv32.s +++ /dev/null @@ -1,62 +0,0 @@ -# mach: crisv32 -# output: 4455aa77\n4455aa77\nee19ccff\nff22\n4455aa77\nff224455\n55aa77ff\n - - .include "testutils.inc" - .data -x: - .dword 0x55aa77ff - .dword 0xccff2244 - .dword 0x88ccee19 - - start - setf cv - moveq -1,r0 - move.d x-32768,r5 - move.d 32769,r6 - addi r6.b,r5,acr - test_cc 0 0 1 1 - move.d [acr],r3 - checkr3 4455aa77 - - addu.w 32771,r5 - setf znvc - moveq -1,r8 - addi r8.w,r5,acr - test_cc 1 1 1 1 - move.d [acr],r3 - checkr3 4455aa77 - - moveq 5,r10 - clearf znvc - addi r10.b,acr,acr - test_cc 0 0 0 0 - move.d [acr],r3 - checkr3 ee19ccff - - subq 1,r5 - move.d r5,r8 - subq 1,r8 - moveq 1,r9 - addi r9.d,r8,acr - test_cc 0 0 0 0 - movu.w [acr],r3 - checkr3 ff22 - - moveq -2,r11 - addi r11.w,acr,acr - move.d [acr],r3 - checkr3 4455aa77 - - moveq 5,r9 - addi r9.d,acr,acr - subq 18,acr - move.d [acr],r3 - checkr3 ff224455 - - move.d -76789888/4,r12 - addi r12.d,r5,acr - add.d 76789886,acr - move.d [acr],r3 - checkr3 55aa77ff - - quit diff --git a/tests/tcg/cris/bare/check_addm.s b/tests/tcg/cris/bare/check_addm.s deleted file mode 100644 index efece9f538dc..000000000000 --- a/tests/tcg/cris/bare/check_addm.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n781344d0\n - - .include "testutils.inc" - .data -x: - .dword 2,-1,0xffff,-1,0x5432f789 - .word 2,-1,0xffff,0xf789 - .byte 2,0xff,0x89 - .byte 0x7e - - start - moveq -1,r3 - move.d x,r5 - add.d [r5+],r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - add.d [r5],r3 - test_cc 0 0 0 1 - addq 4,r5 - checkr3 1 - - move.d 0xffff,r3 - add.d [r5+],r3 - test_cc 0 0 0 0 - checkr3 1fffe - - moveq -1,r3 - add.d [r5+],r3 - test_cc 1 0 0 1 - checkr3 fffffffe - - move.d 0x78134452,r3 - add.d [r5+],r3 - test_cc 1 0 1 0 - checkr3 cc463bdb - - moveq -1,r3 - add.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 ffff0001 - - moveq 2,r3 - add.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xffff,r3 - add.w [r5],r3 - test_cc 1 0 0 1 - checkr3 fffe - - move.d 0xfedaffff,r3 - add.w [r5+],r3 - test_cc 1 0 0 1 - checkr3 fedafffe - - move.d 0x78134452,r3 - add.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 78133bdb - - moveq -1,r3 - add.b [r5],r3 - test_cc 0 0 0 1 - addq 1,r5 - checkr3 ffffff01 - - moveq 2,r3 - add.b [r5],r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xff,r3 - add.b [r5],r3 - test_cc 1 0 0 1 - checkr3 fe - - move.d 0xfeda49ff,r3 - add.b [r5+],r3 - test_cc 1 0 0 1 - checkr3 feda49fe - - move.d 0x78134452,r3 - add.b [r5+],r3 - test_cc 1 0 0 0 - checkr3 781344db - - move.d 0x78134452,r3 - add.b [r5],r3 - test_cc 1 0 1 0 - checkr3 781344d0 - - quit diff --git a/tests/tcg/cris/bare/check_addq.s b/tests/tcg/cris/bare/check_addq.s deleted file mode 100644 index e6f874f9b2b3..000000000000 --- a/tests/tcg/cris/bare/check_addq.s +++ /dev/null @@ -1,47 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n0\n1\n100\n10000\n47\n67\na6\n80000001\n - - .include "testutils.inc" - start - moveq -2,r3 - addq 1,r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - addq 1,r3 - test_cc 0 1 0 1 - checkr3 0 - - addq 1,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xff,r3 - addq 1,r3 - test_cc 0 0 0 0 - checkr3 100 - - move.d 0xffff,r3 - addq 1,r3 - test_cc 0 0 0 0 - checkr3 10000 - - move.d 0x42,r3 - addq 5,r3 - test_cc 0 0 0 0 - checkr3 47 - - addq 32,r3 - test_cc 0 0 0 0 - checkr3 67 - - addq 63,r3 - test_cc 0 0 0 0 - checkr3 a6 - - move.d 0x7ffffffe,r3 - addq 3,r3 - test_cc 1 0 1 0 - checkr3 80000001 - - quit diff --git a/tests/tcg/cris/bare/check_addr.s b/tests/tcg/cris/bare/check_addr.s deleted file mode 100644 index 7f55cdc1b5ec..000000000000 --- a/tests/tcg/cris/bare/check_addr.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - add.d r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - moveq -1,r4 - add.d r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xffff,r4 - move.d r4,r3 - add.d r4,r3 - test_cc 0 0 0 0 - checkr3 1fffe - - moveq -1,r4 - move.d r4,r3 - add.d r4,r3 - test_cc 1 0 0 1 - checkr3 fffffffe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - add.d r4,r3 - test_cc 1 0 1 0 - checkr3 cc463bdb - - moveq -1,r3 - moveq 2,r4 - add.w r4,r3 - test_cc 0 0 0 1 - checkr3 ffff0001 - - moveq 2,r3 - moveq -1,r4 - add.w r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xffff,r4 - move.d r4,r3 - add.w r4,r3 - test_cc 1 0 0 1 - checkr3 fffe - - move.d 0xfedaffff,r4 - move.d r4,r3 - add.w r4,r3 - test_cc 1 0 0 1 - checkr3 fedafffe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - add.w r4,r3 - test_cc 0 0 0 1 - checkr3 78133bdb - - moveq -1,r3 - moveq 2,r4 - add.b r4,r3 - test_cc 0 0 0 1 - checkr3 ffffff01 - - moveq 2,r3 - moveq -1,r4 - add.b r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xff,r4 - move.d r4,r3 - add.b r4,r3 - test_cc 1 0 0 1 - checkr3 fe - - move.d 0xfeda49ff,r4 - move.d r4,r3 - add.b r4,r3 - test_cc 1 0 0 1 - checkr3 feda49fe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - add.b r4,r3 - test_cc 1 0 0 0 - checkr3 781344db - - quit diff --git a/tests/tcg/cris/bare/check_addxc.s b/tests/tcg/cris/bare/check_addxc.s deleted file mode 100644 index 09c8355bf8f8..000000000000 --- a/tests/tcg/cris/bare/check_addxc.s +++ /dev/null @@ -1,91 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n - - .include "testutils.inc" - start - moveq 2,r3 - adds.b 0xff,r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - adds.w 0xffff,r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - addu.b 0xff,r3 - checkr3 101 - - moveq 2,r3 - move.d 0xffffffff,r4 - addu.w -1,r3 - test_cc 0 0 0 0 - checkr3 10001 - - move.d 0xffff,r3 - addu.b -1,r3 - test_cc 0 0 0 0 - checkr3 100fe - - move.d 0xffff,r3 - addu.w -1,r3 - test_cc 0 0 0 0 - checkr3 1fffe - - move.d 0xffff,r3 - adds.b 0xff,r3 - test_cc 0 0 0 1 - checkr3 fffe - - move.d 0xffff,r3 - adds.w 0xffff,r3 - test_cc 0 0 0 1 - checkr3 fffe - - moveq -1,r3 - adds.b 0xff,r3 - test_cc 1 0 0 1 - checkr3 fffffffe - - moveq -1,r3 - adds.w 0xff,r3 - test_cc 0 0 0 1 - checkr3 fe - - moveq -1,r3 - adds.w 0xffff,r3 - test_cc 1 0 0 1 - checkr3 fffffffe - - move.d 0x78134452,r3 - addu.b 0x89,r3 - test_cc 0 0 0 0 - checkr3 781344db - - move.d 0x78134452,r3 - adds.b 0x89,r3 - test_cc 0 0 0 1 - checkr3 781343db - - move.d 0x78134452,r3 - addu.w 0xf789,r3 - test_cc 0 0 0 0 - checkr3 78143bdb - - move.d 0x78134452,r3 - adds.w 0xf789,r3 - test_cc 0 0 0 1 - checkr3 78133bdb - - move.d 0x7fffffee,r3 - addu.b 0xff,r3 - test_cc 1 0 1 0 - checkr3 800000ed - - move.d 0x1,r3 - adds.w 0xffff,r3 - test_cc 0 1 0 1 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_addxm.s b/tests/tcg/cris/bare/check_addxm.s deleted file mode 100644 index 7563494b9914..000000000000 --- a/tests/tcg/cris/bare/check_addxm.s +++ /dev/null @@ -1,106 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n - - .include "testutils.inc" - .data -x: - .byte 0xff - .word 0xffff - .word 0xff - .word 0xffff - .byte 0x89 - .word 0xf789 - .byte 0xff - .word 0xffff - - start - moveq 2,r3 - move.d x,r5 - adds.b [r5+],r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - adds.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - subq 3,r5 - addu.b [r5+],r3 - test_cc 0 0 0 0 - checkr3 101 - - moveq 2,r3 - addu.w [r5+],r3 - subq 3,r5 - test_cc 0 0 0 0 - checkr3 10001 - - move.d 0xffff,r3 - addu.b [r5],r3 - test_cc 0 0 0 0 - checkr3 100fe - - move.d 0xffff,r3 - addu.w [r5],r3 - test_cc 0 0 0 0 - checkr3 1fffe - - move.d 0xffff,r3 - adds.b [r5],r3 - test_cc 0 0 0 1 - checkr3 fffe - - move.d 0xffff,r3 - adds.w [r5],r3 - test_cc 0 0 0 1 - checkr3 fffe - - moveq -1,r3 - adds.b [r5],r3 - test_cc 1 0 0 1 - addq 3,r5 - checkr3 fffffffe - - moveq -1,r3 - adds.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 fe - - moveq -1,r3 - adds.w [r5+],r3 - test_cc 1 0 0 1 - checkr3 fffffffe - - move.d 0x78134452,r3 - addu.b [r5],r3 - test_cc 0 0 0 0 - checkr3 781344db - - move.d 0x78134452,r3 - adds.b [r5+],r3 - test_cc 0 0 0 1 - checkr3 781343db - - move.d 0x78134452,r3 - addu.w [r5],r3 - test_cc 0 0 0 0 - checkr3 78143bdb - - move.d 0x78134452,r3 - adds.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 78133bdb - - move.d 0x7fffffee,r3 - addu.b [r5+],r3 - test_cc 1 0 1 0 - checkr3 800000ed - - move.d 0x1,r3 - adds.w [r5+],r3 - test_cc 0 1 0 1 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_addxr.s b/tests/tcg/cris/bare/check_addxr.s deleted file mode 100644 index 7f55cdc1b5ec..000000000000 --- a/tests/tcg/cris/bare/check_addxr.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - add.d r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - moveq 2,r3 - moveq -1,r4 - add.d r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xffff,r4 - move.d r4,r3 - add.d r4,r3 - test_cc 0 0 0 0 - checkr3 1fffe - - moveq -1,r4 - move.d r4,r3 - add.d r4,r3 - test_cc 1 0 0 1 - checkr3 fffffffe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - add.d r4,r3 - test_cc 1 0 1 0 - checkr3 cc463bdb - - moveq -1,r3 - moveq 2,r4 - add.w r4,r3 - test_cc 0 0 0 1 - checkr3 ffff0001 - - moveq 2,r3 - moveq -1,r4 - add.w r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xffff,r4 - move.d r4,r3 - add.w r4,r3 - test_cc 1 0 0 1 - checkr3 fffe - - move.d 0xfedaffff,r4 - move.d r4,r3 - add.w r4,r3 - test_cc 1 0 0 1 - checkr3 fedafffe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - add.w r4,r3 - test_cc 0 0 0 1 - checkr3 78133bdb - - moveq -1,r3 - moveq 2,r4 - add.b r4,r3 - test_cc 0 0 0 1 - checkr3 ffffff01 - - moveq 2,r3 - moveq -1,r4 - add.b r4,r3 - test_cc 0 0 0 1 - checkr3 1 - - move.d 0xff,r4 - move.d r4,r3 - add.b r4,r3 - test_cc 1 0 0 1 - checkr3 fe - - move.d 0xfeda49ff,r4 - move.d r4,r3 - add.b r4,r3 - test_cc 1 0 0 1 - checkr3 feda49fe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - add.b r4,r3 - test_cc 1 0 0 0 - checkr3 781344db - - quit diff --git a/tests/tcg/cris/bare/check_andc.s b/tests/tcg/cris/bare/check_andc.s deleted file mode 100644 index a947b773c972..000000000000 --- a/tests/tcg/cris/bare/check_andc.s +++ /dev/null @@ -1,80 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n - - .include "testutils.inc" - start - moveq -1,r3 - and.d 2,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - and.d -1,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - and.d 0xffff,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r3 - and.d -1,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - and.d 0x5432f789,r3 - test_move_cc 0 0 0 0 - checkr3 50124400 - - moveq -1,r3 - and.w 2,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0002 - - moveq 2,r3 - and.w -1,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xfffff,r3 - and.w 0xffff,r3 - test_move_cc 1 0 0 0 - checkr3 fffff - - move.d 0xfedaffaf,r3 - and.w 0xff5f,r3 - test_move_cc 1 0 0 0 - checkr3 fedaff0f - - move.d 0x78134452,r3 - and.w 0xf789,r3 - test_move_cc 0 0 0 0 - checkr3 78134400 - - moveq -1,r3 - and.b 2,r3 - test_move_cc 0 0 0 0 - checkr3 ffffff02 - - moveq 2,r3 - and.b -1,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xfa7,r3 - and.b 0x5a,r3 - test_move_cc 0 0 0 0 - checkr3 f02 - - move.d 0x78134453,r3 - and.b 0x89,r3 - test_move_cc 0 0 0 0 - checkr3 78134401 - - and.b 0,r3 - test_move_cc 0 1 0 0 - checkr3 78134400 - - quit diff --git a/tests/tcg/cris/bare/check_andm.s b/tests/tcg/cris/bare/check_andm.s deleted file mode 100644 index 93858863fe5c..000000000000 --- a/tests/tcg/cris/bare/check_andm.s +++ /dev/null @@ -1,90 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n - - .include "testutils.inc" - .data -x: - .dword 2,-1,0xffff,-1,0x5432f789 - .word 2,-1,0xffff,0xff5f,0xf789 - .byte 2,-1,0x5a,0x89,0 - - start - moveq -1,r3 - move.d x,r5 - and.d [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - and.d [r5],r3 - test_move_cc 0 0 0 0 - addq 4,r5 - checkr3 2 - - move.d 0xffff,r3 - and.d [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r3 - and.d [r5+],r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - and.d [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 50124400 - - moveq -1,r3 - and.w [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 ffff0002 - - moveq 2,r3 - and.w [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xfffff,r3 - and.w [r5],r3 - test_move_cc 1 0 0 0 - addq 2,r5 - checkr3 fffff - - move.d 0xfedaffaf,r3 - and.w [r5+],r3 - test_move_cc 1 0 0 0 - checkr3 fedaff0f - - move.d 0x78134452,r3 - and.w [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 78134400 - - moveq -1,r3 - and.b [r5],r3 - test_move_cc 0 0 0 0 - addq 1,r5 - checkr3 ffffff02 - - moveq 2,r3 - and.b [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xfa7,r3 - and.b [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 f02 - - move.d 0x78134453,r3 - and.b [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 78134401 - - and.b [r5],r3 - test_move_cc 0 1 0 0 - checkr3 78134400 - - quit diff --git a/tests/tcg/cris/bare/check_andq.s b/tests/tcg/cris/bare/check_andq.s deleted file mode 100644 index 55aa7b060772..000000000000 --- a/tests/tcg/cris/bare/check_andq.s +++ /dev/null @@ -1,46 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\nffff\nffffffff\n1f\nffffffe0\n78134452\n0\n - - .include "testutils.inc" - start - moveq -1,r3 - andq 2,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - andq -1,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - andq -1,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r3 - andq -1,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - andq 31,r3 - test_move_cc 0 0 0 0 - checkr3 1f - - moveq -1,r3 - andq -32,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffe0 - - move.d 0x78134457,r3 - andq -14,r3 - test_move_cc 0 0 0 0 - checkr3 78134452 - - moveq 0,r3 - andq -14,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_andr.s b/tests/tcg/cris/bare/check_andr.s deleted file mode 100644 index 61aa1dc32f20..000000000000 --- a/tests/tcg/cris/bare/check_andr.s +++ /dev/null @@ -1,95 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - and.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - moveq -1,r4 - and.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r4 - move.d r4,r3 - and.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r4 - move.d r4,r3 - and.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - and.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 50124400 - - moveq -1,r3 - moveq 2,r4 - and.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0002 - - moveq 2,r3 - moveq -1,r4 - and.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xfffff,r3 - move.d 0xffff,r4 - and.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 fffff - - move.d 0xfedaffaf,r3 - move.d 0xff5f,r4 - and.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 fedaff0f - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - and.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 78134400 - - moveq -1,r3 - moveq 2,r4 - and.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffffff02 - - moveq 2,r3 - moveq -1,r4 - and.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0x5a,r4 - move.d 0xfa7,r3 - and.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 f02 - - move.d 0x5432f789,r4 - move.d 0x78134453,r3 - and.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 78134401 - - moveq 0,r7 - and.b r7,r3 - test_move_cc 0 1 0 0 - checkr3 78134400 - - quit diff --git a/tests/tcg/cris/bare/check_asr.s b/tests/tcg/cris/bare/check_asr.s deleted file mode 100644 index 0a02ae6f7eb2..000000000000 --- a/tests/tcg/cris/bare/check_asr.s +++ /dev/null @@ -1,230 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n1\nffffffff\nffffffff\n5a67f\nffffffff\nffffffff\nffffffff\nf699fc67\nffffffff\n1\nffffffff\nffffffff\n5a67f\nda67ffff\nda67ffff\nda67ffff\nda67fc67\nffffffff\nffffffff\n1\nffffffff\nffffffff\n5a670007\nda67f1ff\nda67f1ff\nda67f1ff\nda67f1e7\nffffffff\nffffffff\n1\nffffffff\nffffffff\nffffffff\n5a67f1ff\n5a67f1f9\n0\n5a670000\n - - .include "testutils.inc" - start - moveq -1,r3 - asrq 0,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - asrq 1,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - asrq 31,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - asrq 15,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x5a67f19f,r3 - asrq 12,r3 - test_move_cc 0 0 0 0 - checkr3 5a67f - - move.d 0xda67f19f,r3 - move.d 31,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0xda67f19f,r3 - move.d 32,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0xda67f19f,r3 - move.d 33,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0xda67f19f,r3 - move.d 66,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 f699fc67 - - moveq -1,r3 - moveq 0,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - asr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - moveq 31,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 15,r4 - asr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x5a67f19f,r3 - moveq 12,r4 - asr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 5a67f - - move.d 0xda67f19f,r3 - move.d 31,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67ffff - - move.d 0xda67f19f,r3 - move.d 32,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67ffff - - move.d 0xda67f19f,r3 - move.d 33,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67ffff - - move.d 0xda67f19f,r3 - move.d 66,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67fc67 - - moveq -1,r3 - moveq 0,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 1,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - asr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - moveq 31,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 15,r4 - asr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x5a67719f,r3 - moveq 12,r4 - asr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 5a670007 - - move.d 0xda67f19f,r3 - move.d 31,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67f1ff - - move.d 0xda67f19f,r3 - move.d 32,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67f1ff - - move.d 0xda67f19f,r3 - move.d 33,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67f1ff - - move.d 0xda67f19f,r3 - move.d 66,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67f1e7 - - moveq -1,r3 - moveq 0,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 1,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - asr.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - moveq 31,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 15,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 7,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - -; FIXME: was wrong. - move.d 0x5a67f19f,r3 - moveq 12,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 5a67f1ff - -; FIXME: was wrong. - move.d 0x5a67f19f,r3 - moveq 4,r4 - asr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 5a67f1f9 - - move.d 0x5a67f19f,r3 - asrq 31,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0x5a67419f,r3 - moveq 16,r4 - asr.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 5a670000 - - quit diff --git a/tests/tcg/cris/bare/check_ba.s b/tests/tcg/cris/bare/check_ba.s deleted file mode 100644 index 873a4086c5f9..000000000000 --- a/tests/tcg/cris/bare/check_ba.s +++ /dev/null @@ -1,93 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: a\n - - - .set smalloffset,0 - .set largeoffset,0 - - - .macro fail - jump _fail - .endm - - .global main -main: - moveq 0,$r3 - -; Short forward branch. - ba 0f - addq 1,$r3 - fail - -; Max short forward branch. -1: - ba 2f - addq 1,$r3 - fail - -; Short backward branch. -0: - ba 1b - addq 1,$r3 - fail - - .space 254-2+smalloffset+1b-.,0 - moveq 0,$r3 - -2: -; Transit branch (long). - ba 3f - addq 1,$r3 - fail - - moveq 0,$r3 -4: -; Long forward branch. - ba 5f - addq 1,$r3 - fail - - .space 256-2-smalloffset+4b-.,0 - - moveq 0,$r3 - -; Max short backward branch. -3: - ba 4b - addq 1,$r3 - fail - -5: -; Max long forward branch. - ba 6f - addq 1,$r3 - fail - - .space 32766+largeoffset-2+5b-.,0 - - moveq 0,$r3 -6: -; Transit branch. - ba 7f - addq 1,$r3 - fail - - moveq 0,$r3 -9: - jsr pass - nop - -; Transit branch. - moveq 0,$r3 -7: - ba 8f - addq 1,$r3 - fail - - .space 32768-largeoffset+9b-.,0 - -8: -; Max long backward branch. - ba 9b - addq 1,$r3 - fail diff --git a/tests/tcg/cris/bare/check_bas.s b/tests/tcg/cris/bare/check_bas.s deleted file mode 100644 index 11929d420200..000000000000 --- a/tests/tcg/cris/bare/check_bas.s +++ /dev/null @@ -1,102 +0,0 @@ -# mach: crisv32 -# output: 0\n0\n0\nfb349abc\n0\n12124243\n0\n0\neab5baad\n0\nefb37832\n - - .include "testutils.inc" - start -x: - setf zncv - bsr 0f - nop -0: - test_cc 1 1 1 1 - move srp,r3 - sub.d 0b,r3 - checkr3 0 - - bas 1f,mof - moveq 0,r0 -6: - nop - quit - -2: - move srp,r3 - sub.d 3f,r3 - checkr3 0 - move srp,r4 - subq 4,r4 - move.d [r4],r3 - checkr3 fb349abc - - basc 4f,mof - nop - .dword 0x12124243 -7: - nop - quit - -8: - move mof,r3 - sub.d 7f,r3 - checkr3 0 - - move mof,r4 - subq 4,r4 - move.d [r4],r3 - checkr3 eab5baad - - jasc 9f,mof - nop - .dword 0xefb37832 -0: - quit - - quit -9: - move mof,r3 - sub.d 0b,r3 - checkr3 0 - - move mof,r4 - subq 4,r4 - move.d [r4],r3 - checkr3 efb37832 - - quit - -4: - move mof,r3 - sub.d 7b,r3 - checkr3 0 - move mof,r4 - subq 4,r4 - move.d [r4],r3 - checkr3 12124243 - basc 5f,bz - moveq 0,r3 - .dword 0x7634aeba - quit - - .space 32770,0 -1: - move mof,r3 - sub.d 6b,r3 - checkr3 0 - - bsrc 2b - nop - .dword 0xfb349abc -3: - - quit - -5: - move mof,r3 - sub.d 7b,r3 - checkr3 0 - move.d 8b,r6 - jasc r6,mof - nop - .dword 0xeab5baad -7: - quit diff --git a/tests/tcg/cris/bare/check_bcc.s b/tests/tcg/cris/bare/check_bcc.s deleted file mode 100644 index c57ffa6fa35a..000000000000 --- a/tests/tcg/cris/bare/check_bcc.s +++ /dev/null @@ -1,197 +0,0 @@ - .global main - .type main, @function -main: - clearf nzvc - setf nzv - bcc 0f - addq 1, $r3 - jump dofail - -0: - clearf nzvc - setf nzv - bcs dofail - addq 1,$r3 - - clearf nzvc - setf ncv - bne 1f - addq 1, $r3 - -fail: -dofail: - jump _fail - -1: - clearf nzvc - setf ncv - beq dofail - addq 1,$r3 - - clearf nzvc - setf ncz - bvc 2f - addq 1,$r3 - jump dofail - -2: - clearf nzvc - setf ncz - bvs dofail - addq 1,$r3 - - clearf nzvc - setf vcz - bpl 3f - addq 1,$r3 - jump fail -3: - clearf nzvc - setf vcz - bmi dofail - addq 1,$r3 - - clearf nzvc - setf nv - bls dofail - addq 1,$r3 - - clearf nzvc - setf nv - bhi 4f - addq 1,$r3 - jump dofail - -4: - clearf nzvc - setf zc - bge 5f - addq 1,$r3 - jump dofail - -5: - clearf nzvc - setf zc - blt dofail - addq 1,$r3 - - clearf nzvc - setf c - bgt 6f - addq 1,$r3 - jump fail - -6: - clearf nzvc - setf c - ble dofail - addq 1,$r3 - -;;;;;;;;;; - - setf nzvc - clearf nzv - bcc dofail - addq 1,$r3 - - setf nzvc - clearf nzv - bcs 0f - addq 1,$r3 - jump fail - -0: - setf nzvc - clearf ncv - bne dofail - addq 1,$r3 - - setf nzvc - clearf ncv - beq 1f - addq 1,$r3 - jump fail - -1: - setf nzvc - clearf ncz - bvc dofail - addq 1,$r3 - - setf nzvc - clearf ncz - bvs 2f - addq 1,$r3 - jump fail - -2: - setf nzvc - clearf vcz - bpl dofail - addq 1,$r3 - - setf nzvc - clearf vcz - bmi 3f - addq 1,$r3 - jump fail - -3: - setf nzvc - clearf nv - bls 4f - addq 1,$r3 - jump fail - -4: - setf nzvc - clearf nv - bhi dofail - addq 1,$r3 - - setf zvc - clearf nzc - bge dofail - addq 1,$r3 - - setf nzc - clearf vzc - blt 5f - addq 1,$r3 - jump fail - -5: - setf nzvc - clearf c - bgt dofail - addq 1,$r3 - - setf nzvc - clearf c - ble 6f - addq 1,$r3 - jump fail - -6: - ; do a forward branch. - ba 2f - nop - .fill 100 -1: - ba 3f - nop - .fill 800 -2: - ba 1b - nop - .fill 1024 -3: - - moveq 31, $r0 -1: bne 1b - subq 1, $r0 - - jsr pass - moveq 0, $r10 - ret - nop diff --git a/tests/tcg/cris/bare/check_boundc.s b/tests/tcg/cris/bare/check_boundc.s deleted file mode 100644 index fb9e5bc905bd..000000000000 --- a/tests/tcg/cris/bare/check_boundc.s +++ /dev/null @@ -1,101 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\nffff\nffffffff\n5432f789\n2\nffff\n2\nffff\nffff\nf789\n2\n2\nff\nff\nff\n89\n0\nff\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - bound.d 2,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - bound.d 0xffffffff,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - bound.d 0xffff,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r3 - bound.d 0xffffffff,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - bound.d 0x5432f789,r3 - test_move_cc 0 0 0 0 - checkr3 5432f789 - - moveq -1,r3 - bound.w 2,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq -1,r3 - bound.w 0xffff,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq 2,r3 - bound.w 0xffff,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - bound.w 0xffff,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - move.d 0xfedaffff,r3 - bound.w 0xffff,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - move.d 0x78134452,r3 - bound.w 0xf789,r3 - test_move_cc 0 0 0 0 - checkr3 f789 - - moveq -1,r3 - bound.b 2,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - bound.b 0xff,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq -1,r3 - bound.b 0xff,r3 - test_move_cc 0 0 0 0 - checkr3 ff - - move.d 0xff,r3 - bound.b 0xff,r3 - test_move_cc 0 0 0 0 - checkr3 ff - - move.d 0xfeda49ff,r3 - bound.b 0xff,r3 - test_move_cc 0 0 0 0 - checkr3 ff - - move.d 0x78134452,r3 - bound.b 0x89,r3 - test_move_cc 0 0 0 0 - checkr3 89 - - bound.w 0,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0xffff,r3 - bound.b -1,r3 - test_move_cc 0 0 0 0 - checkr3 ff - - quit diff --git a/tests/tcg/cris/bare/check_boundr.s b/tests/tcg/cris/bare/check_boundr.s deleted file mode 100644 index 5c50cc5f6adc..000000000000 --- a/tests/tcg/cris/bare/check_boundr.s +++ /dev/null @@ -1,125 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\nffff\nffffffff\n5432f789\n2\n2\nffff\nffff\nffff\nf789\n2\n2\nff\nff\n89\nfeda4953\nfeda4962\n0\n0\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - bound.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - moveq -1,r4 - bound.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r4 - move.d r4,r3 - bound.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r4 - move.d r4,r3 - bound.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - bound.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 5432f789 - - moveq -1,r3 - moveq 2,r4 - bound.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - moveq -1,r4 - bound.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq -1,r3 - bound.w r3,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - move.d 0xffff,r4 - move.d r4,r3 - bound.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - move.d 0xfedaffff,r4 - move.d r4,r3 - bound.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - bound.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 f789 - - moveq -1,r3 - moveq 2,r4 - bound.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - moveq 2,r3 - moveq -1,r4 - bound.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 2 - - move.d 0xff,r4 - move.d r4,r3 - bound.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 ff - - move.d 0xfeda49ff,r4 - move.d r4,r3 - bound.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 ff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - bound.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 89 - - move.d 0xfeda4956,r3 - move.d 0xfeda4953,r4 - bound.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 feda4953 - - move.d 0xfeda4962,r3 - move.d 0xfeda4963,r4 - bound.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 feda4962 - - move.d 0xfeda4956,r3 - move.d 0,r4 - bound.d r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0xfeda4956,r4 - move.d 0,r3 - bound.d r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_btst.s b/tests/tcg/cris/bare/check_btst.s deleted file mode 100644 index 485deb200664..000000000000 --- a/tests/tcg/cris/bare/check_btst.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1111\n - - .include "testutils.inc" - start - clearf nzvc - moveq -1,r3 - .if 1 ;..asm.arch.cris.v32 - .else - setf vc - .endif - btstq 0,r3 - test_cc 1 0 0 0 - - moveq 2,r3 - btstq 1,r3 - test_cc 1 0 0 0 - - moveq 4,r3 - btstq 1,r3 - test_cc 0 1 0 0 - - moveq -1,r3 - btstq 31,r3 - test_cc 1 0 0 0 - - move.d 0x5a67f19f,r3 - btstq 12,r3 - test_cc 1 0 0 0 - - move.d 0xda67f19f,r3 - move.d 29,r4 - btst r4,r3 - test_cc 0 0 0 0 - - move.d 0xda67f19f,r3 - move.d 32,r4 - btst r4,r3 - test_cc 1 0 0 0 - - move.d 0xda67f191,r3 - move.d 33,r4 - btst r4,r3 - test_cc 0 0 0 0 - - moveq -1,r3 - moveq 0,r4 - btst r4,r3 - test_cc 1 0 0 0 - - moveq 2,r3 - moveq 1,r4 - btst r4,r3 - test_cc 1 0 0 0 - - moveq -1,r3 - moveq 31,r4 - btst r4,r3 - test_cc 1 0 0 0 - - moveq 4,r3 - btstq 1,r3 - test_cc 0 1 0 0 - - moveq -1,r3 - moveq 15,r4 - btst r4,r3 - test_cc 1 0 0 0 - - move.d 0x5a67f19f,r3 - moveq 12,r4 - btst r4,r3 - test_cc 1 0 0 0 - - move.d 0x5a678000,r3 - moveq 11,r4 - btst r4,r3 - test_cc 0 1 0 0 - - move.d 0x5a67f19f,r3 - btst r3,r3 - test_cc 0 0 0 0 - - move.d 0x1111,r3 - checkr3 1111 - - ; check that X gets cleared and that only the NZ flags are touched. - ;; move.d 0xff, $r0 - ;; move $r0, $ccs - ;; btst r3,r3 - ;; move $ccs, $r0 - ;; and.d 0xff, $r0 - ;; cmp.d 0xe3, $r0 - ;; test_cc 0 1 0 0 - - quit diff --git a/tests/tcg/cris/bare/check_clearfv32.s b/tests/tcg/cris/bare/check_clearfv32.s deleted file mode 100644 index 4e91360273ca..000000000000 --- a/tests/tcg/cris/bare/check_clearfv32.s +++ /dev/null @@ -1,19 +0,0 @@ -# mach: crisv32 -# output: ef\nef\n - -; Check that "clearf x" doesn't trivially fail. - - .include "testutils.inc" - start - setf puixnzvc - clearf x ; Actually, x would be cleared by almost-all other insns. - move ccs,r3 - and.d 0xff, $r3 - checkr3 ef - - setf puixnzvc - moveq 0, $r3 ; moveq should only clear the xflag. - move ccs,r3 - and.d 0xff, $r3 - checkr3 ef - quit diff --git a/tests/tcg/cris/bare/check_clrjmp1.s b/tests/tcg/cris/bare/check_clrjmp1.s deleted file mode 100644 index 45a7005e24d6..000000000000 --- a/tests/tcg/cris/bare/check_clrjmp1.s +++ /dev/null @@ -1,36 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: ffffff00\n - -; A bug resulting in a non-effectual clear.b discovered running the GCC -; testsuite; jump actually wrote to p0. - - .include "testutils.inc" - - start - jump 1f - nop - .p2align 8 -1: - move.d y,r4 - - .if 0 ;0 == ..asm.arch.cris.v32 -; There was a bug causing this insn to set special register p0 -; (byte-clear) to 8 (low 8 bits of location after insn). - jump [r4+] - .endif - -1: - move.d 0f,r4 - -; The corresponding bug would cause this insn too, to set p0. - jump r4 - nop - quit -0: - moveq -1,r3 - clear.b r3 - checkr3 ffffff00 - quit - -y: - .dword 1b diff --git a/tests/tcg/cris/bare/check_cmp-2.s b/tests/tcg/cris/bare/check_cmp-2.s deleted file mode 100644 index 414d37051790..000000000000 --- a/tests/tcg/cris/bare/check_cmp-2.s +++ /dev/null @@ -1,15 +0,0 @@ - - -.include "testutils.inc" - - start - - move.d 4294967283, $r0 - move.d $r0, $r10 - cmp.d $r0, $r10 - beq 1f - move.d $r10, $r3 - fail -1: - pass - quit diff --git a/tests/tcg/cris/bare/check_cmpc.s b/tests/tcg/cris/bare/check_cmpc.s deleted file mode 100644 index 267c9ba8c01f..000000000000 --- a/tests/tcg/cris/bare/check_cmpc.s +++ /dev/null @@ -1,86 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649282\n - - .include "testutils.inc" - start - moveq -1,r3 - cmp.d -2,r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - cmp.d 1,r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - cmp.d -0xffff,r3 - test_cc 0 0 0 1 - checkr3 ffff - - moveq -1,r3 - cmp.d 1,r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - cmp.d -0x5432f789,r3 - test_cc 1 0 1 1 - checkr3 78134452 - - moveq -1,r3 - cmp.w -2,r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - cmp.w 1,r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - cmp.w 1,r3 - test_cc 1 0 0 0 - checkr3 ffff - - move.d 0xfedaffff,r3 - cmp.w 1,r3 - test_cc 1 0 0 0 - checkr3 fedaffff - - move.d 0x78134452,r3 - cmp.w 0x877,r3 - test_cc 0 0 0 0 - checkr3 78134452 - - moveq -1,r3 - cmp.b -2,r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - cmp.b 1,r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xff,r3 - cmp.b 1,r3 - test_cc 1 0 0 0 - checkr3 ff - - move.d 0xfeda49ff,r3 - cmp.b 1,r3 - test_cc 1 0 0 0 - checkr3 feda49ff - - move.d 0x78134452,r3 - cmp.b 0x77,r3 - test_cc 1 0 0 1 - checkr3 78134452 - - move.d 0x85649282,r3 - cmp.b 0x82,r3 - test_cc 0 1 0 0 - checkr3 85649282 - - quit diff --git a/tests/tcg/cris/bare/check_cmpm.s b/tests/tcg/cris/bare/check_cmpm.s deleted file mode 100644 index e4dde15b32e9..000000000000 --- a/tests/tcg/cris/bare/check_cmpm.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n - - .include "testutils.inc" - .data -x: - .dword -2,1,-0xffff,1,-0x5432f789 - .word -2,1,1,0x877 - .byte -2,1,0x77 - .byte 0x22 - - start - moveq -1,r3 - move.d x,r5 - cmp.d [r5+],r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - cmp.d [r5],r3 - test_cc 0 0 0 0 - addq 4,r5 - checkr3 2 - - move.d 0xffff,r3 - cmp.d [r5+],r3 - test_cc 0 0 0 1 - checkr3 ffff - - moveq -1,r3 - cmp.d [r5+],r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - cmp.d [r5+],r3 - test_cc 1 0 1 1 - checkr3 78134452 - - moveq -1,r3 - cmp.w [r5+],r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - cmp.w [r5+],r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - cmp.w [r5],r3 - test_cc 1 0 0 0 - checkr3 ffff - - move.d 0xfedaffff,r3 - cmp.w [r5+],r3 - test_cc 1 0 0 0 - checkr3 fedaffff - - move.d 0x78134452,r3 - cmp.w [r5+],r3 - test_cc 0 0 0 0 - checkr3 78134452 - - moveq -1,r3 - cmp.b [r5],r3 - test_cc 0 0 0 0 - addq 1,r5 - checkr3 ffffffff - - moveq 2,r3 - cmp.b [r5],r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xff,r3 - cmp.b [r5],r3 - test_cc 1 0 0 0 - checkr3 ff - - move.d 0xfeda49ff,r3 - cmp.b [r5+],r3 - test_cc 1 0 0 0 - checkr3 feda49ff - - move.d 0x78134452,r3 - cmp.b [r5+],r3 - test_cc 1 0 0 1 - checkr3 78134452 - - move.d 0x85649222,r3 - cmp.b [r5],r3 - test_cc 0 1 0 0 - checkr3 85649222 - - quit diff --git a/tests/tcg/cris/bare/check_cmpq.s b/tests/tcg/cris/bare/check_cmpq.s deleted file mode 100644 index 5469141c9160..000000000000 --- a/tests/tcg/cris/bare/check_cmpq.s +++ /dev/null @@ -1,75 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1\n1f\n1f\nffffffe1\nffffffe1\nffffffe0\n0\n0\nffffffff\nffffffff\n10000\n100\n5678900\n - - .include "testutils.inc" - start - moveq 1,r3 - cmpq 1,r3 - test_cc 0 1 0 0 - checkr3 1 - - cmpq -1,r3 - test_cc 0 0 0 1 - checkr3 1 - - cmpq 31,r3 - test_cc 1 0 0 1 - checkr3 1 - - moveq 31,r3 - cmpq 31,r3 - test_cc 0 1 0 0 - checkr3 1f - - cmpq -31,r3 - test_cc 0 0 0 1 - checkr3 1f - - movs.b -31,r3 - cmpq -31,r3 - test_cc 0 1 0 0 - checkr3 ffffffe1 - - cmpq -32,r3 - test_cc 0 0 0 0 - checkr3 ffffffe1 - - movs.b -32,r3 - cmpq -32,r3 - test_cc 0 1 0 0 - checkr3 ffffffe0 - - moveq 0,r3 - cmpq 1,r3 - test_cc 1 0 0 1 - checkr3 0 - - cmpq -32,r3 - test_cc 0 0 0 1 - checkr3 0 - - moveq -1,r3 - cmpq 1,r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - cmpq -1,r3 - test_cc 0 1 0 0 - checkr3 ffffffff - - move.d 0x10000,r3 - cmpq 1,r3 - test_cc 0 0 0 0 - checkr3 10000 - - move.d 0x100,r3 - cmpq 1,r3 - test_cc 0 0 0 0 - checkr3 100 - - move.d 0x5678900,r3 - cmpq 7,r3 - test_cc 0 0 0 0 - checkr3 5678900 - - quit diff --git a/tests/tcg/cris/bare/check_cmpr.s b/tests/tcg/cris/bare/check_cmpr.s deleted file mode 100644 index b30af7a53853..000000000000 --- a/tests/tcg/cris/bare/check_cmpr.s +++ /dev/null @@ -1,102 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq -2,r4 - cmp.d r4,r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - cmp.d r4,r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - move.d -0xffff,r4 - cmp.d r4,r3 - test_cc 0 0 0 1 - checkr3 ffff - - moveq 1,r4 - moveq -1,r3 - cmp.d r4,r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - move.d -0x5432f789,r4 - move.d 0x78134452,r3 - cmp.d r4,r3 - test_cc 1 0 1 1 - checkr3 78134452 - - moveq -1,r3 - moveq -2,r4 - cmp.w r4,r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - cmp.w r4,r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d 0xffff,r3 - move.d -0xffff,r4 - cmp.w r4,r3 - test_cc 1 0 0 0 - checkr3 ffff - - move.d 0xfedaffff,r3 - move.d -0xfedaffff,r4 - cmp.w r4,r3 - test_cc 1 0 0 0 - checkr3 fedaffff - - move.d -0x5432f789,r4 - move.d 0x78134452,r3 - cmp.w r4,r3 - test_cc 0 0 0 0 - checkr3 78134452 - - moveq -1,r3 - moveq -2,r4 - cmp.b r4,r3 - test_cc 0 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - cmp.b r4,r3 - test_cc 0 0 0 0 - checkr3 2 - - move.d -0xff,r4 - move.d 0xff,r3 - cmp.b r4,r3 - test_cc 1 0 0 0 - checkr3 ff - - move.d -0xfeda49ff,r4 - move.d 0xfeda49ff,r3 - cmp.b r4,r3 - test_cc 1 0 0 0 - checkr3 feda49ff - - move.d -0x5432f789,r4 - move.d 0x78134452,r3 - cmp.b r4,r3 - test_cc 1 0 0 1 - checkr3 78134452 - - move.d 0x85649222,r3 - move.d 0x77445622,r4 - cmp.b r4,r3 - test_cc 0 1 0 0 - checkr3 85649222 - - quit diff --git a/tests/tcg/cris/bare/check_cmpxc.s b/tests/tcg/cris/bare/check_cmpxc.s deleted file mode 100644 index b237a931752f..000000000000 --- a/tests/tcg/cris/bare/check_cmpxc.s +++ /dev/null @@ -1,92 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n - - .include "testutils.inc" - start - moveq 2,r3 - cmps.b 0xff,r3 - test_cc 0 0 0 1 - checkr3 2 - - moveq 2,r3 - cmps.w 0xffff,r3 - test_cc 0 0 0 1 - checkr3 2 - - moveq 2,r3 - cmpu.b 0xff,r3 - test_cc 1 0 0 1 - checkr3 2 - - moveq 2,r3 - move.d 0xffffffff,r4 - cmpu.w -1,r3 - test_cc 1 0 0 1 - checkr3 2 - - move.d 0xffff,r3 - cmpu.b -1,r3 - test_cc 0 0 0 0 - checkr3 ffff - - move.d 0xffff,r3 - cmpu.w -1,r3 - test_cc 0 1 0 0 - checkr3 ffff - - move.d 0xffff,r3 - cmps.b 0xff,r3 - test_cc 0 0 0 1 - checkr3 ffff - - move.d 0xffff,r3 - cmps.w 0xffff,r3 - test_cc 0 0 0 1 - checkr3 ffff - - moveq -1,r3 - cmps.b 0xff,r3 - test_cc 0 1 0 0 - checkr3 ffffffff - - moveq -1,r3 - cmps.w 0xff,r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - cmps.w 0xffff,r3 - test_cc 0 1 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - cmpu.b 0x89,r3 - test_cc 0 0 0 0 - checkr3 78134452 - - move.d 0x78134452,r3 - cmps.b 0x89,r3 - test_cc 0 0 0 1 - checkr3 78134452 - - move.d 0x78134452,r3 - cmpu.w 0xf789,r3 - test_cc 0 0 0 0 - checkr3 78134452 - - move.d 0x78134452,r3 - cmps.w 0xf789,r3 - test_cc 0 0 0 1 - checkr3 78134452 - - move.d 0x4452,r3 - cmps.w 0x8002,r3 - test_cc 0 0 0 1 - checkr3 4452 - - move.d 0x80000032,r3 - cmpu.w 0x764,r3 - test_cc 0 0 1 0 - checkr3 80000032 - - quit diff --git a/tests/tcg/cris/bare/check_cmpxm.s b/tests/tcg/cris/bare/check_cmpxm.s deleted file mode 100644 index 87ea5bf8e316..000000000000 --- a/tests/tcg/cris/bare/check_cmpxm.s +++ /dev/null @@ -1,106 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n - - .include "testutils.inc" - .data -x: - .byte 0xff - .word 0xffff - .word 0xff - .word 0xffff - .byte 0x89 - .word 0xf789 - .word 0x8002 - .word 0x764 - - start - moveq 2,r3 - move.d x,r5 - cmps.b [r5+],r3 - test_cc 0 0 0 1 - checkr3 2 - - moveq 2,r3 - cmps.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 2 - - moveq 2,r3 - subq 3,r5 - cmpu.b [r5+],r3 - test_cc 1 0 0 1 - checkr3 2 - - moveq 2,r3 - cmpu.w [r5+],r3 - test_cc 1 0 0 1 - subq 3,r5 - checkr3 2 - - move.d 0xffff,r3 - cmpu.b [r5],r3 - test_cc 0 0 0 0 - checkr3 ffff - - move.d 0xffff,r3 - cmpu.w [r5],r3 - test_cc 0 1 0 0 - checkr3 ffff - - move.d 0xffff,r3 - cmps.b [r5],r3 - test_cc 0 0 0 1 - checkr3 ffff - - move.d 0xffff,r3 - cmps.w [r5],r3 - test_cc 0 0 0 1 - checkr3 ffff - - moveq -1,r3 - cmps.b [r5],r3 - test_cc 0 1 0 0 - addq 3,r5 - checkr3 ffffffff - - moveq -1,r3 - cmps.w [r5+],r3 - test_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - cmps.w [r5+],r3 - test_cc 0 1 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - cmpu.b [r5],r3 - test_cc 0 0 0 0 - checkr3 78134452 - - move.d 0x78134452,r3 - cmps.b [r5+],r3 - test_cc 0 0 0 1 - checkr3 78134452 - - move.d 0x78134452,r3 - cmpu.w [r5],r3 - test_cc 0 0 0 0 - checkr3 78134452 - - move.d 0x78134452,r3 - cmps.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 78134452 - - move.d 0x4452,r3 - cmps.w [r5+],r3 - test_cc 0 0 0 1 - checkr3 4452 - - move.d 0x80000032,r3 - cmpu.w [r5+],r3 - test_cc 0 0 1 0 - checkr3 80000032 - - quit diff --git a/tests/tcg/cris/bare/check_dstep.s b/tests/tcg/cris/bare/check_dstep.s deleted file mode 100644 index bd43b838ea9e..000000000000 --- a/tests/tcg/cris/bare/check_dstep.s +++ /dev/null @@ -1,42 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: fffffffc\n4\nffff\nfffffffe\n9bf3911b\n0\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - dstep r4,r3 - test_move_cc 1 0 0 0 - checkr3 fffffffc - - moveq 2,r3 - moveq -1,r4 - dstep r4,r3 - test_move_cc 0 0 0 0 - checkr3 4 - - move.d 0xffff,r4 - move.d r4,r3 - dstep r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r4 - move.d r4,r3 - dstep r4,r3 - test_move_cc 1 0 0 0 - checkr3 fffffffe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - dstep r4,r3 - test_move_cc 1 0 0 0 - checkr3 9bf3911b - - move.d 0xffff,r3 - move.d 0x1fffe,r4 - dstep r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_jsr.s b/tests/tcg/cris/bare/check_jsr.s deleted file mode 100644 index 106023787314..000000000000 --- a/tests/tcg/cris/bare/check_jsr.s +++ /dev/null @@ -1,85 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 0\n0\n0\n0\n0\n0\n - -# Test that jsr Rn and jsr [PC+] work. - - .include "testutils.inc" - start -x: - move.d 0f,r6 - setf nzvc - jsr r6 - .if 1; ..asm.arch.cris.v32 - nop - .endif -0: - test_move_cc 1 1 1 1 - move srp,r3 - sub.d 0b,r3 - checkr3 0 - - move.d 1f,r0 - setf nzvc - jsr r0 - .if 1 ; ..asm.arch.cris.v32 - moveq 0,r0 - .endif -6: - nop - quit - -2: - test_move_cc 0 0 0 0 - move srp,r3 - sub.d 3f,r3 - checkr3 0 - jsr 4f - .if 1 ; ..asm.arch.cris.v32 - nop - .endif -7: - nop - quit - -8: - move srp,r3 - sub.d 7b,r3 - checkr3 0 - quit - -4: - move srp,r3 - sub.d 7b,r3 - checkr3 0 - move.d 5f,r3 - jump r3 - .if 1; ..asm.arch.cris.v32 - moveq 0,r3 - .endif - quit - - .space 32770,0 -1: - test_move_cc 1 1 1 1 - move srp,r3 - sub.d 6b,r3 - checkr3 0 - - clearf cznv - jsr 2b - .if 1; ..asm.arch.cris.v32 - nop - .endif -3: - - quit - -5: - move srp,r3 - sub.d 7b,r3 - checkr3 0 - jump 8b - .if 1 ; ..asm.arch.cris.v32 - nop - .endif - quit diff --git a/tests/tcg/cris/bare/check_lapc.s b/tests/tcg/cris/bare/check_lapc.s deleted file mode 100644 index 9a6150b749ea..000000000000 --- a/tests/tcg/cris/bare/check_lapc.s +++ /dev/null @@ -1,78 +0,0 @@ -# mach: crisv32 -# output: 0\n0\nfffffffa\nfffffffe\nffffffda\n1e\n1e\n0\n - -.include "testutils.inc" - -; To accommodate dumpr3 with more than one instruction, keep it -; out of lapc operand ranges and difference calculations. - - start - lapc.d 0f,r3 -0: - sub.d .,r3 - checkr3 0 - - lapcq 0f,r3 -0: - sub.d .,r3 - checkr3 0 - - lapc.d .,r3 - sub.d .,r3 - checkr3 fffffffa - - lapcq .,r3 - sub.d .,r3 - checkr3 fffffffe - -0: - .rept 16 - nop - .endr - lapc.d 0b,r3 - sub.d .,r3 - checkr3 ffffffda - - setf zcvn - lapc.d 0f,r3 - test_cc 1 1 1 1 - sub.d .,r3 - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -0: - checkr3 1e -0: - lapcq 0f,r3 - sub.d 0b,r3 - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -0: - checkr3 1e - clearf cn - setf zv -1: - lapcq .,r3 - test_cc 0 1 1 0 - sub.d 1b,r3 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_lsl.s b/tests/tcg/cris/bare/check_lsl.s deleted file mode 100644 index 9e2ddd7cd00c..000000000000 --- a/tests/tcg/cris/bare/check_lsl.s +++ /dev/null @@ -1,217 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n4\n80000000\nffff8000\n7f19f000\n80000000\n0\n0\n699fc67c\nffffffff\n4\n80000000\nffff8000\n7f19f000\nda670000\nda670000\nda670000\nda67c67c\nffffffff\nfffafffe\n4\nffff0000\nffff8000\n5a67f000\nda67f100\nda67f100\nda67f100\nda67f17c\nfff3faff\nfff3fafe\n4\nffffff00\nffffff00\nffffff80\n5a67f100\n5a67f1f0\n - - .include "testutils.inc" - start - moveq -1,r3 - lslq 0,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - lslq 1,r3 - test_move_cc 0 0 0 0 - checkr3 4 - - moveq -1,r3 - lslq 31,r3 - test_move_cc 1 0 0 0 - checkr3 80000000 - - moveq -1,r3 - lslq 15,r3 - test_move_cc 1 0 0 0 - checkr3 ffff8000 - - move.d 0x5a67f19f,r3 - lslq 12,r3 - test_move_cc 0 0 0 0 - checkr3 7f19f000 - - move.d 0xda67f19f,r3 - move.d 31,r4 - lsl.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 80000000 - - move.d 0xda67f19f,r3 - move.d 32,r4 - lsl.d r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0xda67f19f,r3 - move.d 33,r4 - lsl.d r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0xda67f19f,r3 - move.d 66,r4 - lsl.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 699fc67c - - moveq -1,r3 - moveq 0,r4 - lsl.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - lsl.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 4 - - moveq -1,r3 - moveq 31,r4 - lsl.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 80000000 - - moveq -1,r3 - moveq 15,r4 - lsl.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffff8000 - - move.d 0x5a67f19f,r3 - moveq 12,r4 - lsl.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 7f19f000 - - move.d 0xda67f19f,r3 - move.d 31,r4 - lsl.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 da670000 - - move.d 0xda67f19f,r3 - move.d 32,r4 - lsl.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 da670000 - - move.d 0xda67f19f,r3 - move.d 33,r4 - lsl.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 da670000 - - move.d 0xda67f19f,r3 - move.d 66,r4 - lsl.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 da67c67c - - moveq -1,r3 - moveq 0,r4 - lsl.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0xfffaffff,r3 - moveq 1,r4 - lsl.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 fffafffe - - moveq 2,r3 - moveq 1,r4 - lsl.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 4 - - moveq -1,r3 - moveq 31,r4 - lsl.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffff0000 - - moveq -1,r3 - moveq 15,r4 - lsl.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffff8000 - - move.d 0x5a67f19f,r3 - moveq 12,r4 - lsl.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 5a67f000 - - move.d 0xda67f19f,r3 - move.d 31,r4 - lsl.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 da67f100 - - move.d 0xda67f19f,r3 - move.d 32,r4 - lsl.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 da67f100 - - move.d 0xda67f19f,r3 - move.d 33,r4 - lsl.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 da67f100 - - move.d 0xda67f19f,r3 - move.d 66,r4 - lsl.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 da67f17c - - move.d 0xfff3faff,r3 - moveq 0,r4 - lsl.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 fff3faff - - move.d 0xfff3faff,r3 - moveq 1,r4 - lsl.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 fff3fafe - - moveq 2,r3 - moveq 1,r4 - lsl.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 4 - - moveq -1,r3 - moveq 31,r4 - lsl.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffffff00 - - moveq -1,r3 - moveq 15,r4 - lsl.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffffff00 - - moveq -1,r3 - moveq 7,r4 - lsl.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffff80 - - move.d 0x5a67f19f,r3 - moveq 12,r4 - lsl.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 5a67f100 - - move.d 0x5a67f19f,r3 - moveq 4,r4 - lsl.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 5a67f1f0 - - quit diff --git a/tests/tcg/cris/bare/check_lsr.s b/tests/tcg/cris/bare/check_lsr.s deleted file mode 100644 index 18fdbef9b28f..000000000000 --- a/tests/tcg/cris/bare/check_lsr.s +++ /dev/null @@ -1,218 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\n1\n1\n1ffff\n5a67f\n1\n0\n0\n3699fc67\nffffffff\n1\n1\n1ffff\n5a67f\nda670000\nda670000\nda670000\nda673c67\nffffffff\nffff7fff\n1\nffff0000\nffff0001\n5a67000f\nda67f100\nda67f100\nda67f100\nda67f127\nffffffff\nffffff7f\n1\nffffff00\nffffff00\nffffff01\n5a67f100\n5a67f109\n - - .include "testutils.inc" - start - moveq -1,r3 - lsrq 0,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - lsrq 1,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - lsrq 31,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - lsrq 15,r3 - test_move_cc 0 0 0 0 - checkr3 1ffff - - move.d 0x5a67f19f,r3 - lsrq 12,r3 - test_move_cc 0 0 0 0 - checkr3 5a67f - - move.d 0xda67f19f,r3 - move.d 31,r4 - lsr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - move.d 0xda67f19f,r3 - move.d 32,r4 - lsr.d r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0xda67f19f,r3 - move.d 33,r4 - lsr.d r4,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0xda67f19f,r3 - move.d 66,r4 - lsr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 3699fc67 - - moveq -1,r3 - moveq 0,r4 - lsr.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 2,r3 - moveq 1,r4 - lsr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - moveq 31,r4 - lsr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - moveq 15,r4 - lsr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 1ffff - - move.d 0x5a67f19f,r3 - moveq 12,r4 - lsr.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 5a67f - - move.d 0xda67f19f,r3 - move.d 31,r4 - lsr.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 da670000 - - move.d 0xda67f19f,r3 - move.d 32,r4 - lsr.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 da670000 - - move.d 0xda67f19f,r3 - move.d 33,r4 - lsr.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 da670000 - - move.d 0xda67f19f,r3 - move.d 66,r4 - lsr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 da673c67 - - moveq -1,r3 - moveq 0,r4 - lsr.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 1,r4 - lsr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff7fff - - moveq 2,r3 - moveq 1,r4 - lsr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - -;; FIXME: this was wrong. Z should be set. - moveq -1,r3 - moveq 31,r4 - lsr.w r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffff0000 - - moveq -1,r3 - moveq 15,r4 - lsr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0001 - - move.d 0x5a67f19f,r3 - moveq 12,r4 - lsr.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 5a67000f - - move.d 0xda67f19f,r3 - move.d 31,r4 - lsr.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 da67f100 - - move.d 0xda67f19f,r3 - move.d 32,r4 - lsr.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 da67f100 - - move.d 0xda67f19f,r3 - move.d 33,r4 - lsr.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 da67f100 - - move.d 0xda67f19f,r3 - move.d 66,r4 - lsr.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 da67f127 - - moveq -1,r3 - moveq 0,r4 - lsr.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq -1,r3 - moveq 1,r4 - lsr.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffffff7f - - moveq 2,r3 - moveq 1,r4 - lsr.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - moveq -1,r3 - moveq 31,r4 - lsr.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffffff00 - - moveq -1,r3 - moveq 15,r4 - lsr.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffffff00 - - moveq -1,r3 - moveq 7,r4 - lsr.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffffff01 - - move.d 0x5a67f19f,r3 - moveq 12,r4 - lsr.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 5a67f100 - - move.d 0x5a67f19f,r3 - moveq 4,r4 - lsr.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 5a67f109 - - quit diff --git a/tests/tcg/cris/bare/check_mcp.s b/tests/tcg/cris/bare/check_mcp.s deleted file mode 100644 index e65ccddfd465..000000000000 --- a/tests/tcg/cris/bare/check_mcp.s +++ /dev/null @@ -1,49 +0,0 @@ -# mach: crisv32 -# output: fffffffe\n1\n1ffff\nfffffffe\ncc463bdc\n4c463bdc\n0\n - - .include "testutils.inc" - start - -; Set R, clear C. - move 0x100,ccs - moveq -5,r3 - move 2,mof - mcp mof,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - - moveq 2,r3 - move -1,srp - mcp srp,r3 - test_cc 0 0 0 0 - checkr3 1 - - move 0xffff,srp - move srp,r3 - mcp srp,r3 - test_cc 0 0 0 0 - checkr3 1ffff - - move -1,mof - move mof,r3 - mcp mof,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - - move 0x5432f789,mof - move.d 0x78134452,r3 - mcp mof,r3 - test_cc 1 0 1 0 - checkr3 cc463bdc - - move 0x80000000,srp - mcp srp,r3 - test_cc 0 0 1 0 - checkr3 4c463bdc - - move 0xb3b9c423,srp - mcp srp,r3 - test_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movdelsr1.s b/tests/tcg/cris/bare/check_movdelsr1.s deleted file mode 100644 index 300cc8774229..000000000000 --- a/tests/tcg/cris/bare/check_movdelsr1.s +++ /dev/null @@ -1,33 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: aa117acd\n -# output: eeaabb42\n - -; Bug with move to special register in delay slot, due to -; special flush-insn-cache simulator use. Ordinary move worked; -; special register caused branch to fail. - - .include "testutils.inc" - start - move -1,srp - - move.d 0xaa117acd,r1 - moveq 3,r9 - cmpq 1,r9 - bhi 0f - move.d r1,r3 - - fail -0: - checkr3 aa117acd - - move.d 0xeeaabb42,r1 - moveq 3,r9 - cmpq 1,r9 - bhi 0f - move r1,srp - - fail -0: - move srp,r3 - checkr3 eeaabb42 - quit diff --git a/tests/tcg/cris/bare/check_movecr.s b/tests/tcg/cris/bare/check_movecr.s deleted file mode 100644 index da8ec2628428..000000000000 --- a/tests/tcg/cris/bare/check_movecr.s +++ /dev/null @@ -1,37 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: ffffff42\n94\nffff4321\n9234\n76543210\n76540000\n - -; Move constant byte, word, dword to register. Check that no extension is -; performed, that only part of the register is set. - - .include "testutils.inc" - startnostack - moveq -1,r3 - move.b 0x42,r3 - test_move_cc 0 0 0 0 - checkr3 ffffff42 - - moveq 0,r3 - move.b 0x94,r3 - test_move_cc 1 0 0 0 - checkr3 94 - - moveq -1,r3 - move.w 0x4321,r3 - test_move_cc 0 0 0 0 - checkr3 ffff4321 - - moveq 0,r3 - move.w 0x9234,r3 - test_move_cc 1 0 0 0 - checkr3 9234 - - move.d 0x76543210,r3 - test_move_cc 0 0 0 0 - checkr3 76543210 - - move.w 0,r3 - test_move_cc 0 1 0 0 - checkr3 76540000 - - quit diff --git a/tests/tcg/cris/bare/check_movei.s b/tests/tcg/cris/bare/check_movei.s deleted file mode 100644 index bbfa633373d5..000000000000 --- a/tests/tcg/cris/bare/check_movei.s +++ /dev/null @@ -1,50 +0,0 @@ -# mach: crisv32 -# output: fffffffe\n -# output: fffffffe\n - -; Check basic integral-write semantics regarding flags. - - .include "testutils.inc" - start - - move.d 0, $r3 -; A write that works. Check that flags are set correspondingly. - move.d d,r4 - ;; store to bring it into the tlb with the right prot bits - move.d r3,[r4] - moveq -2,r5 - setf c - clearf p - move.d [r4],r3 - ax - move.d r5,[r4] - move.d [r4],r3 - - bcc 0f - nop - fail - -0: - checkr3 fffffffe - -; A write that fails; check flags too. - move.d d,r4 - moveq 23,r5 - setf p - clearf c - move.d [r4],r3 - ax - move.d r5,[r4] - move.d [r4],r3 - - bcs 0f - nop - fail - -0: - checkr3 fffffffe - quit - - .data -d: - .dword 42424242 diff --git a/tests/tcg/cris/bare/check_movemr.s b/tests/tcg/cris/bare/check_movemr.s deleted file mode 100644 index 88489dee3198..000000000000 --- a/tests/tcg/cris/bare/check_movemr.s +++ /dev/null @@ -1,78 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 12345678\n10234567\n12345678\n12344567\n12344523\n76543210\nffffffaa\naa\n9911\nffff9911\n78\n56\n3456\n6712\n - - .include "testutils.inc" - start - - .data -mem1: - .dword 0x12345678 -mem2: - .word 0x4567 -mem3: - .byte 0x23 - .dword 0x76543210 - .byte 0xaa,0x11,0x99 - - .text - move.d mem1,r2 - move.d [r2],r3 - test_move_cc 0 0 0 0 - checkr3 12345678 - - move.d mem2,r3 - move.d [r3],r3 - test_move_cc 0 0 0 0 - checkr3 10234567 - - move.d mem1,r2 - move.d [r2+],r3 - test_move_cc 0 0 0 0 - checkr3 12345678 - - move.w [r2+],r3 - test_move_cc 0 0 0 0 - checkr3 12344567 - - move.b [r2+],r3 - test_move_cc 0 0 0 0 - checkr3 12344523 - - move.d [r2+],r3 - test_move_cc 0 0 0 0 - checkr3 76543210 - - movs.b [r2],r3 - test_move_cc 1 0 0 0 - checkr3 ffffffaa - - movu.b [r2+],r3 - test_move_cc 0 0 0 0 - checkr3 aa - - movu.w [r2],r3 - test_move_cc 0 0 0 0 - checkr3 9911 - - movs.w [r2+],r3 - test_move_cc 1 0 0 0 - checkr3 ffff9911 - - move.d mem1,r13 - movs.b [r13+],r3 - test_move_cc 0 0 0 0 - checkr3 78 - - movu.b [r13],r3 - test_move_cc 0 0 0 0 - checkr3 56 - - movs.w [r13+],r3 - test_move_cc 0 0 0 0 - checkr3 3456 - - movu.w [r13+],r3 - test_move_cc 0 0 0 0 - checkr3 6712 - - quit diff --git a/tests/tcg/cris/bare/check_movemrv32.s b/tests/tcg/cris/bare/check_movemrv32.s deleted file mode 100644 index 53950abd5bd5..000000000000 --- a/tests/tcg/cris/bare/check_movemrv32.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv32 -# output: 15\n7\n2\nffff1234\nb\n16\nf\n2\nffffffef\nf\nffff1234\nf\nfffffff4\nd\nfffffff2\n10\nfffffff2\nd\n - - .include "testutils.inc" - .data -x: - .dword 8,9,10,11 -y: - .dword -12,13,-14,15,16 - - start - moveq 7,r0 - moveq 2,r1 - move.d 0xffff1234,r2 - moveq 21,r3 - move.d x,r4 - setf zcvn - movem r2,[r4+] - test_cc 1 1 1 1 - subq 12,r4 - - checkr3 15 - - move.d [r4+],r3 - checkr3 7 - - move.d [r4+],r3 - checkr3 2 - - move.d [r4+],r3 - checkr3 ffff1234 - - move.d [r4+],r3 - checkr3 b - - subq 16,r4 - moveq 22,r0 - moveq 15,r1 - clearf zcvn - movem r0,[r4] - test_cc 0 0 0 0 - move.d [r4+],r3 - checkr3 16 - - move.d r1,r3 - checkr3 f - - move.d [r4+],r3 - checkr3 2 - - subq 8,r4 - moveq 10,r2 - moveq -17,r0 - clearf zc - setf vn - movem r1,[r4] - test_cc 1 0 1 0 - move.d [r4+],r3 - checkr3 ffffffef - - move.d [r4+],r3 - checkr3 f - - move.d [r4+],r3 - checkr3 ffff1234 - - move.d y,r4 - setf zc - clearf vn - movem [r4+],r3 - test_cc 0 1 0 1 - checkr3 f - - move.d r0,r3 - checkr3 fffffff4 - - move.d r1,r3 - checkr3 d - - move.d r2,r3 - checkr3 fffffff2 - - move.d [r4],r3 - checkr3 10 - - subq 8,r4 - setf zcvn - movem [r4+],r0 - test_cc 1 1 1 1 - move.d r0,r3 - checkr3 fffffff2 - - move.d r1,r3 - checkr3 d - - quit diff --git a/tests/tcg/cris/bare/check_mover.s b/tests/tcg/cris/bare/check_mover.s deleted file mode 100644 index b4db595d64b9..000000000000 --- a/tests/tcg/cris/bare/check_mover.s +++ /dev/null @@ -1,28 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: ffffff05\nffff0005\n5\nffffff00\n - -; Move between registers. Check that just the subreg is copied. - - .include "testutils.inc" - startnostack - moveq -30,r3 - moveq 5,r4 - move.b r4,r3 - test_move_cc 0 0 0 0 ; FIXME - checkr3 ffffff05 - - move.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0005 - - move.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq -1,r3 - moveq 0,r4 - move.b r4,r3 - test_move_cc 0 1 0 0 - checkr3 ffffff00 - - quit diff --git a/tests/tcg/cris/bare/check_moverm.s b/tests/tcg/cris/bare/check_moverm.s deleted file mode 100644 index eabc9588d424..000000000000 --- a/tests/tcg/cris/bare/check_moverm.s +++ /dev/null @@ -1,45 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 7823fec2\n10231879\n102318fe\n - - .include "testutils.inc" - start - - .data -mem1: - .dword 0x12345678 -mem2: - .word 0x4567 -mem3: - .byte 0x23 - .dword 0x76543210 - .byte 0xaa,0x11,0x99 - - .text - move.d mem1,r2 - move.d 0x7823fec2,r4 - setf nzvc - move.d r4,[r2+] - test_cc 1 1 1 1 - subq 4,r2 - move.d [r2],r3 - checkr3 7823fec2 - - move.d mem2,r3 - move.d 0x45231879,r4 - clearf nzvc - move.w r4,[r3] - test_cc 0 0 0 0 - move.d [r3],r3 - checkr3 10231879 - - move.d mem2,r2 - moveq -2,r4 - clearf nc - setf zv - move.b r4,[r2+] - test_cc 0 1 1 0 - subq 1,r2 - move.d [r2],r3 - checkr3 102318fe - - quit diff --git a/tests/tcg/cris/bare/check_movmp.s b/tests/tcg/cris/bare/check_movmp.s deleted file mode 100644 index 7fc11f064ddd..000000000000 --- a/tests/tcg/cris/bare/check_movmp.s +++ /dev/null @@ -1,131 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n - -# Test generic "move Ps,[]" and "move [],Pd" insns; the ones with -# functionality common to all models. - - .include "testutils.inc" - start - - .data -filler: - .byte 0xaa - .word 0x4433 - .dword 0x55778866 - .byte 0xcc - - .text -; Test that writing to zero-registers is a nop - .if 0 - ; We used to just ignore the writes, but now an error is emitted. We - ; keep the test-code but disabled, in case we need to change this again. - move 0xaa,p0 - move 0x4433,p4 - move 0x55774433,p8 - .endif - - moveq -1,r3 - setf zcvn - clear.b r3 - test_cc 1 1 1 1 - checkr3 ffffff00 - - moveq -1,r3 - clearf zcvn - clear.w r3 - test_cc 0 0 0 0 - checkr3 ffff0000 - - moveq -1,r3 - clear.d r3 - checkr3 0 - -; "Write" using ordinary memory references too. - .if 0 ; See ".if 0" above. - move.d filler,r6 - move [r6],p0 - move [r6],p4 - move [r6],p8 - .endif - -# ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n - - moveq -1,r3 - clear.b r3 - checkr3 ffffff00 - - moveq -1,r3 - clear.w r3 - checkr3 ffff0000 - - moveq -1,r3 - clear.d r3 - checkr3 0 - -; And postincremented. - .if 0 ; See ".if 0" above. - move [r6+],p0 - move [r6+],p4 - move [r6+],p8 - .endif - -# ffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n - - moveq -1,r3 - clear.b r3 - checkr3 ffffff00 - - moveq -1,r3 - clear.w r3 - checkr3 ffff0000 - - moveq -1,r3 - clear.d r3 - checkr3 0 - -; Now see that we can write to the registers too. -# bb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n -; [PC+] - move.d filler,r9 - move 0xbb113344,srp - move srp,r3 - checkr3 bb113344 - -; [R+] - move [r9+],srp - move srp,r3 - checkr3 664433aa - -; [R] - move [r9],srp - move srp,r3 - checkr3 cc557788 - -; And check writing to memory, clear and srp. - - move.d filler,r9 - move 0xabcde012,srp - setf zcvn - move srp,[r9+] - test_cc 1 1 1 1 - subq 4,r9 - move.d [r9],r3 - checkr3 abcde012 - - clearf zcvn - clear.b [r9] - test_cc 0 0 0 0 - move.d [r9],r3 - checkr3 abcde000 - - addq 2,r9 - clear.w [r9+] - subq 2,r9 - move.d [r9],r3 - checkr3 77880000 - - clear.d [r9] - move.d [r9],r3 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movpmv32.s b/tests/tcg/cris/bare/check_movpmv32.s deleted file mode 100644 index daf0970e4a64..000000000000 --- a/tests/tcg/cris/bare/check_movpmv32.s +++ /dev/null @@ -1,35 +0,0 @@ -# mach: crisv32 -# output: 11223320\nbb113344\naa557711\n - -# Test v32-specific special registers. FIXME: more registers. - - .include "testutils.inc" - start - .data -store: - .dword 0x11223344 - .dword 0x77665544 - - .text - moveq -1,r3 - move.d store,r4 - move vr,[r4] - move [r4+],mof - move mof,r3 - checkr3 11223320 - - moveq -1,r3 - clearf zcvn - move 0xbb113344,mof - test_cc 0 0 0 0 - move mof,r3 - checkr3 bb113344 - - setf zcvn - move 0xaa557711,mof - test_cc 1 1 1 1 - move mof,[r4] - move.d [r4],r3 - checkr3 aa557711 - - quit diff --git a/tests/tcg/cris/bare/check_movpr.s b/tests/tcg/cris/bare/check_movpr.s deleted file mode 100644 index eef9bdb4fbaa..000000000000 --- a/tests/tcg/cris/bare/check_movpr.s +++ /dev/null @@ -1,28 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: ffffff00\nffff0000\n0\nbb113344\n - -# Test generic "move Ps,Rd" and "move Rs,Pd" insns; the ones with -# functionality common to all models. - - .include "testutils.inc" - start - moveq -1,r3 - clear.b r3 - checkr3 ffffff00 - - moveq -1,r3 - clear.w r3 - checkr3 ffff0000 - - moveq -1,r3 - clear.d r3 - checkr3 0 - - moveq -1,r3 - move.d 0xbb113344,r4 - setf zcvn - move r4,srp - move srp,r3 - test_cc 1 1 1 1 - checkr3 bb113344 - quit diff --git a/tests/tcg/cris/bare/check_movprv32.s b/tests/tcg/cris/bare/check_movprv32.s deleted file mode 100644 index d0d90e124658..000000000000 --- a/tests/tcg/cris/bare/check_movprv32.s +++ /dev/null @@ -1,21 +0,0 @@ -# mach: crisv32 -# output: ffffff20\nbb113344\n - -# Test v32-specific special registers. FIXME: more registers. - - .include "testutils.inc" - start - moveq -1,r3 - setf zcvn - move vr,r3 - test_cc 1 1 1 1 - checkr3 ffffff20 - - moveq -1,r3 - move.d 0xbb113344,r4 - clearf cvnz - move r4,mof - test_cc 0 0 0 0 - move mof,r3 - checkr3 bb113344 - quit diff --git a/tests/tcg/cris/bare/check_movscr.s b/tests/tcg/cris/bare/check_movscr.s deleted file mode 100644 index 53c8ce6b50d4..000000000000 --- a/tests/tcg/cris/bare/check_movscr.s +++ /dev/null @@ -1,29 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 42\nffffff85\n7685\nffff8765\n0\n - -; Move constant byte, word, dword to register. Check that sign-extension -; is performed. - - .include "testutils.inc" - start - moveq -1,r3 - movs.b 0x42,r3 - checkr3 42 - - movs.b 0x85,r3 - test_move_cc 1 0 0 0 - checkr3 ffffff85 - - movs.w 0x7685,r3 - test_move_cc 0 0 0 0 - checkr3 7685 - - movs.w 0x8765,r3 - test_move_cc 1 0 0 0 - checkr3 ffff8765 - - movs.w 0,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movsm.s b/tests/tcg/cris/bare/check_movsm.s deleted file mode 100644 index 7074336e7885..000000000000 --- a/tests/tcg/cris/bare/check_movsm.s +++ /dev/null @@ -1,44 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 5\nfffffff5\n5\nfffffff5\n0\n - -; Movs between registers. Check that sign-extension is performed and the -; full register is set. - - .include "testutils.inc" - - .data -x: - .byte 5,-11 - .word 5,-11 - .word 0 - - start - move.d x,r5 - - moveq -1,r3 - movs.b [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq 0,r3 - movs.b [r5],r3 - test_move_cc 1 0 0 0 - addq 1,r5 - checkr3 fffffff5 - - moveq -1,r3 - movs.w [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq 0,r3 - movs.w [r5],r3 - test_move_cc 1 0 0 0 - addq 2,r5 - checkr3 fffffff5 - - movs.w [r5],r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movsr.s b/tests/tcg/cris/bare/check_movsr.s deleted file mode 100644 index d1889a7a1b70..000000000000 --- a/tests/tcg/cris/bare/check_movsr.s +++ /dev/null @@ -1,46 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 5\nfffffff5\n5\nfffffff5\n0\n - -; Movs between registers. Check that sign-extension is performed and the -; full register is set. - - .include "testutils.inc" - start - moveq -1,r5 - moveq 5,r4 - move.b r4,r5 - moveq -1,r3 - movs.b r5,r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq 0,r5 - moveq -11,r4 - move.b r4,r5 - moveq 0,r3 - movs.b r5,r3 - test_move_cc 1 0 0 0 - checkr3 fffffff5 - - moveq -1,r5 - moveq 5,r4 - move.w r4,r5 - moveq -1,r3 - movs.w r5,r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq 0,r5 - moveq -11,r4 - move.w r4,r5 - moveq 0,r3 - movs.w r5,r3 - test_move_cc 1 0 0 0 - checkr3 fffffff5 - - moveq 0,r5 - movs.b r5,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movucr.s b/tests/tcg/cris/bare/check_movucr.s deleted file mode 100644 index 7c8487d1a242..000000000000 --- a/tests/tcg/cris/bare/check_movucr.s +++ /dev/null @@ -1,33 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 42\n85\n7685\n8765\n0\n - -; Move constant byte, word, dword to register. Check that zero-extension -; is performed. - - .include "testutils.inc" - start - moveq -1,r3 - movu.b 0x42,r3 - test_move_cc 0 0 0 0 - checkr3 42 - - moveq -1,r3 - movu.b 0x85,r3 - test_move_cc 0 0 0 0 - checkr3 85 - - moveq -1,r3 - movu.w 0x7685,r3 - test_move_cc 0 0 0 0 - checkr3 7685 - - moveq -1,r3 - movu.w 0x8765,r3 - test_move_cc 0 0 0 0 - checkr3 8765 - - movu.b 0,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movum.s b/tests/tcg/cris/bare/check_movum.s deleted file mode 100644 index 038e539463bf..000000000000 --- a/tests/tcg/cris/bare/check_movum.s +++ /dev/null @@ -1,40 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 5\nf5\n5\nfff5\n0\n - -; Movu between registers. Check that zero-extension is performed and the -; full register is set. - - .include "testutils.inc" - - .data -x: - .byte 5,-11 - .word 5,-11 - .word 0 - - start - move.d x,r5 - - movu.b [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 5 - - movu.b [r5],r3 - test_move_cc 0 0 0 0 - addq 1,r5 - checkr3 f5 - - movu.w [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 5 - - movu.w [r5],r3 - test_move_cc 0 0 0 0 - addq 2,r5 - checkr3 fff5 - - movu.w [r5],r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_movur.s b/tests/tcg/cris/bare/check_movur.s deleted file mode 100644 index 3ecf475f7575..000000000000 --- a/tests/tcg/cris/bare/check_movur.s +++ /dev/null @@ -1,45 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 5\nf5\n5\nfff5\n0\n - -; Movu between registers. Check that zero-extension is performed and the -; full register is set. - - .include "testutils.inc" - start - moveq -1,r5 - moveq 5,r4 - move.b r4,r5 - moveq -1,r3 - movu.b r5,r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq 0,r5 - moveq -11,r4 - move.b r4,r5 - moveq -1,r3 - movu.b r5,r3 - test_move_cc 0 0 0 0 - checkr3 f5 - - moveq -1,r5 - moveq 5,r4 - move.w r4,r5 - moveq -1,r3 - movu.w r5,r3 - test_move_cc 0 0 0 0 - checkr3 5 - - moveq 0,r5 - moveq -11,r4 - move.w r4,r5 - moveq -1,r3 - movu.w r5,r3 - test_move_cc 0 0 0 0 - checkr3 fff5 - - movu.w 0,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_mulv32.s b/tests/tcg/cris/bare/check_mulv32.s deleted file mode 100644 index f379358765ba..000000000000 --- a/tests/tcg/cris/bare/check_mulv32.s +++ /dev/null @@ -1,51 +0,0 @@ -# mach: crisv32 -# output: fffffffe\n -# output: ffffffff\n -# output: fffffffe\n -# output: 1\n -# output: fffffffe\n -# output: ffffffff\n -# output: fffffffe\n -# output: 1\n - -; Check that carry is not modified on v32. - - .include "testutils.inc" - start - moveq -1,r3 - moveq 2,r4 - setf c - muls.d r4,r3 - test_cc 1 0 0 1 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - moveq -1,r3 - moveq 2,r4 - setf c - mulu.d r4,r3 - test_cc 0 0 1 1 - checkr3 fffffffe - move mof,r3 - checkr3 1 - - moveq -1,r3 - moveq 2,r4 - clearf c - muls.d r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - moveq -1,r3 - moveq 2,r4 - clearf c - mulu.d r4,r3 - test_cc 0 0 1 0 - checkr3 fffffffe - move mof,r3 - checkr3 1 - - quit diff --git a/tests/tcg/cris/bare/check_mulx.s b/tests/tcg/cris/bare/check_mulx.s deleted file mode 100644 index a7a1f82a8298..000000000000 --- a/tests/tcg/cris/bare/check_mulx.s +++ /dev/null @@ -1,257 +0,0 @@ -# mach: crisv10 crisv32 -# output: fffffffe\nffffffff\nfffffffe\n1\nfffffffe\nffffffff\nfffffffe\n1\nfffe0001\n0\nfffe0001\n0\n1\n0\n1\nfffffffe\n193eade2\n277e3a49\n193eade2\n277e3a49\nfffffffe\nffffffff\n1fffe\n0\nfffffffe\nffffffff\n1fffe\n0\n1\n0\nfffe0001\n0\nfdbdade2\nffffffff\n420fade2\n0\nfffffffe\nffffffff\n1fe\n0\nfffffffe\nffffffff\n1fe\n0\n1\n0\nfe01\n0\n1\n0\nfe01\n0\nffffd9e2\nffffffff\n2be2\n0\n0\n0\n0\n0\n - - .include "testutils.inc" - start - - .align 4 - moveq -1,r3 - moveq 2,r4 - muls.d r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - .align 4 - moveq -1,r3 - moveq 2,r4 - mulu.d r4,r3 - test_cc 0 0 1 0 - checkr3 fffffffe - move mof,r3 - checkr3 1 - - .align 4 - moveq 2,r3 - moveq -1,r4 - muls.d r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - .align 4 - moveq 2,r3 - moveq -1,r4 - mulu.d r4,r3 - test_cc 0 0 1 0 - checkr3 fffffffe - move mof,r3 - checkr3 1 - - move.d 0xffff,r4 - move.d r4,r3 - muls.d r4,r3 - test_cc 0 0 1 0 - checkr3 fffe0001 - move mof,r3 - checkr3 0 - - move.d 0xffff,r4 - move.d r4,r3 - mulu.d r4,r3 - test_cc 0 0 0 0 - checkr3 fffe0001 - move mof,r3 - checkr3 0 - - moveq -1,r4 - move.d r4,r3 - muls.d r4,r3 - test_cc 0 0 0 0 - checkr3 1 - move mof,r3 - checkr3 0 - - moveq -1,r4 - move.d r4,r3 - mulu.d r4,r3 - test_cc 1 0 1 0 - checkr3 1 - move mof,r3 - checkr3 fffffffe - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - muls.d r4,r3 - test_cc 0 0 1 0 - checkr3 193eade2 - move mof,r3 - checkr3 277e3a49 - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - mulu.d r4,r3 - test_cc 0 0 1 0 - checkr3 193eade2 - move mof,r3 - checkr3 277e3a49 - - move.d 0xffff,r3 - moveq 2,r4 - muls.w r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - moveq -1,r3 - moveq 2,r4 - mulu.w r4,r3 - test_cc 0 0 0 0 - checkr3 1fffe - move mof,r3 - checkr3 0 - nop - - moveq 2,r3 - move.d 0xffff,r4 - muls.w r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - moveq 2,r3 - moveq -1,r4 - mulu.w r4,r3 - test_cc 0 0 0 0 - checkr3 1fffe - move mof,r3 - checkr3 0 - - move.d 0xffff,r4 - move.d r4,r3 - muls.w r4,r3 - test_cc 0 0 0 0 - checkr3 1 - move mof,r3 - checkr3 0 - - moveq -1,r4 - move.d r4,r3 - mulu.w r4,r3 - test_cc 0 0 0 0 - checkr3 fffe0001 - move mof,r3 - checkr3 0 - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - muls.w r4,r3 - test_cc 1 0 0 0 - checkr3 fdbdade2 - move mof,r3 - checkr3 ffffffff - nop - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - mulu.w r4,r3 - test_cc 0 0 0 0 - checkr3 420fade2 - move mof,r3 - checkr3 0 - nop - - move.d 0xff,r3 - moveq 2,r4 - muls.b r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - moveq -1,r3 - moveq 2,r4 - mulu.b r4,r3 - test_cc 0 0 0 0 - checkr3 1fe - move mof,r3 - checkr3 0 - - moveq 2,r3 - moveq -1,r4 - muls.b r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - move mof,r3 - checkr3 ffffffff - - moveq 2,r3 - moveq -1,r4 - mulu.b r4,r3 - test_cc 0 0 0 0 - checkr3 1fe - move mof,r3 - checkr3 0 - - move.d 0xff,r4 - move.d r4,r3 - muls.b r4,r3 - test_cc 0 0 0 0 - checkr3 1 - move mof,r3 - checkr3 0 - nop - - moveq -1,r4 - move.d r4,r3 - mulu.b r4,r3 - test_cc 0 0 0 0 - checkr3 fe01 - move mof,r3 - checkr3 0 - nop - - move.d 0xfeda49ff,r4 - move.d r4,r3 - muls.b r4,r3 - test_cc 0 0 0 0 - checkr3 1 - move mof,r3 - checkr3 0 - nop - - move.d 0xfeda49ff,r4 - move.d r4,r3 - mulu.b r4,r3 - test_cc 0 0 0 0 - checkr3 fe01 - move mof,r3 - checkr3 0 - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - muls.b r4,r3 - test_cc 1 0 0 0 - checkr3 ffffd9e2 - move mof,r3 - checkr3 ffffffff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - mulu.b r4,r3 - test_cc 0 0 0 0 - checkr3 2be2 - move mof,r3 - checkr3 0 - - moveq 0,r3 - move.d 0xf87f4aeb,r4 - muls.d r4,r3 - test_cc 0 1 0 0 - checkr3 0 - move mof,r3 - checkr3 0 - - move.d 0xf87f4aeb,r3 - moveq 0,r4 - mulu.d r4,r3 - test_cc 0 1 0 0 - checkr3 0 - move mof,r3 - checkr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_neg.s b/tests/tcg/cris/bare/check_neg.s deleted file mode 100644 index 963c4b6f5ea3..000000000000 --- a/tests/tcg/cris/bare/check_neg.s +++ /dev/null @@ -1,104 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: ffffffff\nffffffff\n0\n80000000\n1\nba987655\nffff\nffff\n0\n89ab8000\nffff0001\n45677655\nff\nff\n0\n89abae80\nffffff01\n45678955\n - - .include "testutils.inc" - start - moveq 0,r3 - moveq 1,r4 - neg.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 1,r3 - moveq 0,r4 - neg.d r3,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - -;; FIXME: this was wrong. - moveq 0,r3 - neg.d r3,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0x80000000,r3 - neg.d r3,r3 - test_move_cc 1 0 0 0 - checkr3 80000000 - - moveq -1,r3 - neg.d r3,r3 - test_move_cc 0 0 0 0 - checkr3 1 - - move.d 0x456789ab,r3 - neg.d r3,r3 - test_move_cc 1 0 0 0 - checkr3 ba987655 - - moveq 0,r3 - moveq 1,r4 - neg.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffff - - moveq 1,r3 - moveq 0,r4 - neg.w r3,r3 - test_move_cc 1 0 0 0 - checkr3 ffff - - moveq 0,r3 - neg.w r3,r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0x89ab8000,r3 - neg.w r3,r3 - test_move_cc 1 0 0 0 - checkr3 89ab8000 - - moveq -1,r3 - neg.w r3,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0001 - - move.d 0x456789ab,r3 - neg.w r3,r3 - test_move_cc 0 0 0 0 - checkr3 45677655 - - moveq 0,r3 - moveq 1,r4 - neg.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 ff - - moveq 1,r3 - moveq 0,r4 - neg.b r3,r3 - test_move_cc 1 0 0 0 - checkr3 ff - - moveq 0,r3 - neg.b r3,r3 - test_move_cc 0 1 0 0 - checkr3 0 - -;; FIXME: was wrong. - move.d 0x89abae80,r3 - neg.b r3,r3 - test_move_cc 1 0 0 1 - checkr3 89abae80 - - moveq -1,r3 - neg.b r3,r3 - test_move_cc 0 0 0 0 - checkr3 ffffff01 - - move.d 0x456789ab,r3 - neg.b r3,r3 - test_move_cc 0 0 0 0 - checkr3 45678955 - - quit diff --git a/tests/tcg/cris/bare/check_not.s b/tests/tcg/cris/bare/check_not.s deleted file mode 100644 index 33bcf155e56a..000000000000 --- a/tests/tcg/cris/bare/check_not.s +++ /dev/null @@ -1,31 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: fffffffe\nfffffffd\nffff0f00\n0\n87ecbbad\n - - .include "testutils.inc" - start - moveq 1,r3 - not r3 - test_move_cc 1 0 0 0 - checkr3 fffffffe - - moveq 2,r3 - not r3 - test_move_cc 1 0 0 0 - checkr3 fffffffd - - move.d 0xf0ff,r3 - not r3 - test_move_cc 1 0 0 0 - checkr3 ffff0f00 - - moveq -1,r3 - not r3 - test_move_cc 0 1 0 0 - checkr3 0 - - move.d 0x78134452,r3 - not r3 - test_move_cc 1 0 0 0 - checkr3 87ecbbad - - quit diff --git a/tests/tcg/cris/bare/check_orc.s b/tests/tcg/cris/bare/check_orc.s deleted file mode 100644 index c733f036a2bc..000000000000 --- a/tests/tcg/cris/bare/check_orc.s +++ /dev/null @@ -1,71 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n - - .include "testutils.inc" - start - moveq 1,r3 - or.d 2,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - moveq 2,r3 - or.d 1,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xf0ff,r3 - or.d 0xff0f,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r3 - or.d -1,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x78134452,r3 - or.d 0x5432f789,r3 - test_move_cc 0 0 0 0 - checkr3 7c33f7db - - move.d 0xffff0001,r3 - or.w 2,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0003 - - moveq 2,r3 - or.w 1,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xfedaffaf,r3 - or.w 0xff5f,r3 - test_move_cc 1 0 0 0 - checkr3 fedaffff - - move.d 0x78134452,r3 - or.w 0xf789,r3 - test_move_cc 1 0 0 0 - checkr3 7813f7db - - moveq 1,r3 - or.b 2,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - moveq 2,r3 - or.b 1,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xfa3,r3 - or.b 0x4a,r3 - test_move_cc 1 0 0 0 - checkr3 feb - - move.d 0x78134453,r3 - or.b 0x89,r3 - test_move_cc 1 0 0 0 - checkr3 781344db - - quit diff --git a/tests/tcg/cris/bare/check_orm.s b/tests/tcg/cris/bare/check_orm.s deleted file mode 100644 index ee723a6aa028..000000000000 --- a/tests/tcg/cris/bare/check_orm.s +++ /dev/null @@ -1,75 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n - - .include "testutils.inc" - .data -x: - .dword 2,1,0xff0f,-1,0x5432f789 - .word 2,1,0xff5f,0xf789 - .byte 2,1,0x4a,0x89 - - start - moveq 1,r3 - move.d x,r5 - or.d [r5+],r3 - checkr3 3 - - moveq 2,r3 - or.d [r5],r3 - addq 4,r5 - checkr3 3 - - move.d 0xf0ff,r3 - or.d [r5+],r3 - checkr3 ffff - - moveq -1,r3 - or.d [r5+],r3 - checkr3 ffffffff - - move.d 0x78134452,r3 - or.d [r5+],r3 - checkr3 7c33f7db - - move.d 0xffff0001,r3 - or.w [r5+],r3 - checkr3 ffff0003 - - moveq 2,r3 - or.w [r5],r3 - addq 2,r5 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xfedaffaf,r3 - or.w [r5+],r3 - test_move_cc 1 0 0 0 - checkr3 fedaffff - - move.d 0x78134452,r3 - or.w [r5+],r3 - test_move_cc 1 0 0 0 - checkr3 7813f7db - - moveq 1,r3 - or.b [r5+],r3 - test_move_cc 0 0 0 0 - checkr3 3 - - moveq 2,r3 - or.b [r5],r3 - addq 1,r5 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xfa3,r3 - or.b [r5+],r3 - test_move_cc 1 0 0 0 - checkr3 feb - - move.d 0x78134453,r3 - or.b [r5],r3 - test_move_cc 1 0 0 0 - checkr3 781344db - - quit diff --git a/tests/tcg/cris/bare/check_orq.s b/tests/tcg/cris/bare/check_orq.s deleted file mode 100644 index 5060edc72d95..000000000000 --- a/tests/tcg/cris/bare/check_orq.s +++ /dev/null @@ -1,41 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 3\n3\nffffffff\nffffffff\n1f\nffffffe0\n7813445e\n - - .include "testutils.inc" - start - moveq 1,r3 - orq 2,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - moveq 2,r3 - orq 1,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xf0ff,r3 - orq -1,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 0,r3 - orq -1,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - moveq 0,r3 - orq 31,r3 - test_move_cc 0 0 0 0 - checkr3 1f - - moveq 0,r3 - orq -32,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffe0 - - move.d 0x78134452,r3 - orq 12,r3 - test_move_cc 0 0 0 0 - checkr3 7813445e - - quit diff --git a/tests/tcg/cris/bare/check_orr.s b/tests/tcg/cris/bare/check_orr.s deleted file mode 100644 index a514c11bc908..000000000000 --- a/tests/tcg/cris/bare/check_orr.s +++ /dev/null @@ -1,84 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n - - .include "testutils.inc" - start - moveq 1,r3 - moveq 2,r4 - or.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - moveq 2,r3 - moveq 1,r4 - or.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xff0f,r4 - move.d 0xf0ff,r3 - or.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff - - moveq -1,r4 - move.d r4,r3 - or.d r4,r3 - test_move_cc 1 0 0 0 - checkr3 ffffffff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - or.d r4,r3 - test_move_cc 0 0 0 0 - checkr3 7c33f7db - - move.d 0xffff0001,r3 - moveq 2,r4 - or.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 ffff0003 - - moveq 2,r3 - move.d 0xffff0001,r4 - or.w r4,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0xfedaffaf,r3 - move.d 0xffffff5f,r4 - or.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 fedaffff - - move.d 0x5432f789,r4 - move.d 0x78134452,r3 - or.w r4,r3 - test_move_cc 1 0 0 0 - checkr3 7813f7db - - moveq 1,r3 - move.d 0xffffff02,r4 - or.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - moveq 2,r3 - moveq 1,r4 - or.b r4,r3 - test_move_cc 0 0 0 0 - checkr3 3 - - move.d 0x4a,r4 - move.d 0xfa3,r3 - or.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 feb - - move.d 0x5432f789,r4 - move.d 0x78134453,r3 - or.b r4,r3 - test_move_cc 1 0 0 0 - checkr3 781344db - - quit diff --git a/tests/tcg/cris/bare/check_ret.s b/tests/tcg/cris/bare/check_ret.s deleted file mode 100644 index b44fb25933ae..000000000000 --- a/tests/tcg/cris/bare/check_ret.s +++ /dev/null @@ -1,25 +0,0 @@ -# mach: crisv3 crisv8 crisv10 -# output: 3\n - -# Test that ret works. - - .include "testutils.inc" - start -x: - moveq 0,r3 - jsr z -w: - quit -y: - addq 1,r3 - checkr3 3 - quit - -z: - addq 1,r3 - move srp,r2 - add.d y-w,r2 - move r2,srp - ret - addq 1,r3 - quit diff --git a/tests/tcg/cris/bare/check_scc.s b/tests/tcg/cris/bare/check_scc.s deleted file mode 100644 index 4a8674cc1a20..000000000000 --- a/tests/tcg/cris/bare/check_scc.s +++ /dev/null @@ -1,95 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n0\n1\n1\n0\n1\n0\n0\n1\n1\n0\n1\n1\n0\n - - .include "testutils.inc" - - .macro lcheckr3 v - move $ccs, $r9 - checkr3 \v - move $r9, $ccs - .endm - - start - clearf nzvc - scc r3 - lcheckr3 1 - scs r3 - lcheckr3 0 - sne r3 - lcheckr3 1 - seq r3 - lcheckr3 0 - svc r3 - lcheckr3 1 - svs r3 - lcheckr3 0 - spl r3 - lcheckr3 1 - smi r3 - lcheckr3 0 - sls r3 - lcheckr3 0 - shi r3 - lcheckr3 1 - sge r3 - lcheckr3 1 - slt r3 - lcheckr3 0 - sgt r3 - lcheckr3 1 - sle r3 - lcheckr3 0 - sa r3 - lcheckr3 1 - setf nzvc - scc r3 - lcheckr3 0 - scs r3 - lcheckr3 1 - sne r3 - lcheckr3 0 - svc r3 - lcheckr3 0 - svs r3 - lcheckr3 1 - spl r3 - lcheckr3 0 - smi r3 - lcheckr3 1 - sls r3 - lcheckr3 1 - shi r3 - lcheckr3 0 - sge r3 - lcheckr3 1 - slt r3 - lcheckr3 0 - sgt r3 - lcheckr3 0 - sle r3 - lcheckr3 1 - sa r3 - lcheckr3 1 - clearf n - sge r3 - lcheckr3 0 - slt r3 - lcheckr3 1 - - .if 1 ;..asm.arch.cris.v32 - setf p - ssb r3 - .else - moveq 1,r3 - .endif - lcheckr3 1 - - .if 1 ;..asm.arch.cris.v32 - clearf p - ssb r3 - .else - moveq 0,r3 - .endif - lcheckr3 0 - - quit diff --git a/tests/tcg/cris/bare/check_subc.s b/tests/tcg/cris/bare/check_subc.s deleted file mode 100644 index e34b5448e25d..000000000000 --- a/tests/tcg/cris/bare/check_subc.s +++ /dev/null @@ -1,87 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n - - .include "testutils.inc" - start - - moveq -1,r3 - sub.d -2,r3 - test_cc 0 0 0 0 - checkr3 1 - - moveq 2,r3 - sub.d 1,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xffff,r3 - sub.d -0xffff,r3 - test_cc 0 0 0 1 - checkr3 1fffe - - moveq -1,r3 - sub.d 1,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - - move.d 0x78134452,r3 - sub.d -0x5432f789,r3 - test_cc 1 0 1 1 - checkr3 cc463bdb - - moveq -1,r3 - sub.w -2,r3 - test_cc 0 0 0 0 - checkr3 ffff0001 - - moveq 2,r3 - sub.w 1,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xffff,r3 - sub.w 1,r3 - test_cc 1 0 0 0 - checkr3 fffe - - move.d 0xfedaffff,r3 - sub.w 1,r3 - test_cc 1 0 0 0 - checkr3 fedafffe - - move.d 0x78134452,r3 - sub.w 0x877,r3 - test_cc 0 0 0 0 - checkr3 78133bdb - - moveq -1,r3 - sub.b -2,r3 - test_cc 0 0 0 0 - checkr3 ffffff01 - - moveq 2,r3 - sub.b 1,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xff,r3 - sub.b 1,r3 - test_cc 1 0 0 0 - checkr3 fe - - move.d 0xfeda49ff,r3 - sub.b 1,r3 - test_cc 1 0 0 0 - checkr3 feda49fe - - move.d 0x78134452,r3 - sub.b 0x77,r3 - test_cc 1 0 0 1 - checkr3 781344db - - move.d 0x85649282,r3 - sub.b 0x82,r3 - test_cc 0 1 0 0 - checkr3 85649200 - - quit diff --git a/tests/tcg/cris/bare/check_subm.s b/tests/tcg/cris/bare/check_subm.s deleted file mode 100644 index e07ea02dd4c0..000000000000 --- a/tests/tcg/cris/bare/check_subm.s +++ /dev/null @@ -1,96 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n - - .include "testutils.inc" - .data -x: - .dword -2,1,-0xffff,1,-0x5432f789 - .word -2,1,1,0x877 - .byte -2,1,0x77 - .byte 0x22 - - start - moveq -1,r3 - move.d x,r5 - sub.d [r5+],r3 - test_cc 0 0 0 0 - checkr3 1 - - moveq 2,r3 - sub.d [r5],r3 - test_cc 0 0 0 0 - addq 4,r5 - checkr3 1 - - move.d 0xffff,r3 - sub.d [r5+],r3 - test_cc 0 0 0 1 - checkr3 1fffe - - moveq -1,r3 - sub.d [r5+],r3 - test_cc 1 0 0 0 - checkr3 fffffffe - - move.d 0x78134452,r3 - sub.d [r5+],r3 - test_cc 1 0 1 1 - checkr3 cc463bdb - - moveq -1,r3 - sub.w [r5+],r3 - test_cc 0 0 0 0 - checkr3 ffff0001 - - moveq 2,r3 - sub.w [r5+],r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xffff,r3 - sub.w [r5],r3 - test_cc 1 0 0 0 - checkr3 fffe - - move.d 0xfedaffff,r3 - sub.w [r5+],r3 - test_cc 1 0 0 0 - checkr3 fedafffe - - move.d 0x78134452,r3 - sub.w [r5+],r3 - test_cc 0 0 0 0 - checkr3 78133bdb - - moveq -1,r3 - sub.b [r5],r3 - test_cc 0 0 0 0 - addq 1,r5 - checkr3 ffffff01 - - moveq 2,r3 - sub.b [r5],r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xff,r3 - sub.b [r5],r3 - test_cc 1 0 0 0 - checkr3 fe - - move.d 0xfeda49ff,r3 - sub.b [r5+],r3 - test_cc 1 0 0 0 - checkr3 feda49fe - - move.d 0x78134452,r3 - sub.b [r5+],r3 - test_cc 1 0 0 1 - checkr3 781344db - - move.d 0x85649222,r3 - sub.b [r5],r3 - test_cc 0 1 0 0 - checkr3 85649200 - - quit diff --git a/tests/tcg/cris/bare/check_subq.s b/tests/tcg/cris/bare/check_subq.s deleted file mode 100644 index 9e34fa31ab3e..000000000000 --- a/tests/tcg/cris/bare/check_subq.s +++ /dev/null @@ -1,52 +0,0 @@ -# mach: crisv3 crisv8 crisv10 crisv32 -# output: 0\nffffffff\nfffffffe\nffff\nff\n56788f9\n56788d9\n567889a\n0\n7ffffffc\n - - .include "testutils.inc" - start - moveq 1,r3 - subq 1,r3 - test_cc 0 1 0 0 - checkr3 0 - - subq 1,r3 - test_cc 1 0 0 1 - checkr3 ffffffff - - subq 1,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - - move.d 0x10000,r3 - subq 1,r3 - test_cc 0 0 0 0 - checkr3 ffff - - move.d 0x100,r3 - subq 1,r3 - test_cc 0 0 0 0 - checkr3 ff - - move.d 0x5678900,r3 - subq 7,r3 - test_cc 0 0 0 0 - checkr3 56788f9 - - subq 32,r3 - test_cc 0 0 0 0 - checkr3 56788d9 - - subq 63,r3 - test_cc 0 0 0 0 - checkr3 567889a - - move.d 34,r3 - subq 34,r3 - test_cc 0 1 0 0 - checkr3 0 - - move.d 0x80000024,r3 - subq 40,r3 - test_cc 0 0 1 0 - checkr3 7ffffffc - - quit diff --git a/tests/tcg/cris/bare/check_subr.s b/tests/tcg/cris/bare/check_subr.s deleted file mode 100644 index 742fbc8915e0..000000000000 --- a/tests/tcg/cris/bare/check_subr.s +++ /dev/null @@ -1,102 +0,0 @@ -# mach: crisv0 crisv3 crisv8 crisv10 crisv32 -# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n - - .include "testutils.inc" - start - moveq -1,r3 - moveq -2,r4 - sub.d r4,r3 - test_cc 0 0 0 0 - checkr3 1 - - moveq 2,r3 - moveq 1,r4 - sub.d r4,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xffff,r3 - move.d -0xffff,r4 - sub.d r4,r3 - test_cc 0 0 0 1 - checkr3 1fffe - - moveq 1,r4 - moveq -1,r3 - sub.d r4,r3 - test_cc 1 0 0 0 - checkr3 fffffffe - - move.d -0x5432f789,r4 - move.d 0x78134452,r3 - sub.d r4,r3 - test_cc 1 0 1 1 - checkr3 cc463bdb - - moveq -1,r3 - moveq -2,r4 - sub.w r4,r3 - test_cc 0 0 0 0 - checkr3 ffff0001 - - moveq 2,r3 - moveq 1,r4 - sub.w r4,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d 0xffff,r3 - move.d -0xffff,r4 - sub.w r4,r3 - test_cc 1 0 0 0 - checkr3 fffe - - move.d 0xfedaffff,r3 - move.d -0xfedaffff,r4 - sub.w r4,r3 - test_cc 1 0 0 0 - checkr3 fedafffe - - move.d -0x5432f789,r4 - move.d 0x78134452,r3 - sub.w r4,r3 - test_cc 0 0 0 0 - checkr3 78133bdb - - moveq -1,r3 - moveq -2,r4 - sub.b r4,r3 - test_cc 0 0 0 0 - checkr3 ffffff01 - - moveq 2,r3 - moveq 1,r4 - sub.b r4,r3 - test_cc 0 0 0 0 - checkr3 1 - - move.d -0xff,r4 - move.d 0xff,r3 - sub.b r4,r3 - test_cc 1 0 0 0 - checkr3 fe - - move.d -0xfeda49ff,r4 - move.d 0xfeda49ff,r3 - sub.b r4,r3 - test_cc 1 0 0 0 - checkr3 feda49fe - - move.d -0x5432f789,r4 - move.d 0x78134452,r3 - sub.b r4,r3 - test_cc 1 0 0 1 - checkr3 781344db - - move.d 0x85649222,r3 - move.d 0x77445622,r4 - sub.b r4,r3 - test_cc 0 1 0 0 - checkr3 85649200 - - quit diff --git a/tests/tcg/cris/bare/check_xarith.s b/tests/tcg/cris/bare/check_xarith.s deleted file mode 100644 index 80038b2ab926..000000000000 --- a/tests/tcg/cris/bare/check_xarith.s +++ /dev/null @@ -1,72 +0,0 @@ - -.include "testutils.inc" - - start - - moveq -1, $r0 - moveq 0, $r1 - addq 1, $r0 - ax - addq 0, $r1 - - move.d $r0, $r3 - checkr3 0 - move.d $r1, $r3 - checkr3 1 - - move.d 0, $r0 - moveq -1, $r1 - subq 1, $r0 - ax - subq 0, $r1 - - move.d $r0, $r3 - checkr3 ffffffff - move.d $r1, $r3 - checkr3 fffffffe - - - moveq -1, $r0 - moveq -1, $r1 - cmpq -1, $r0 - ax - cmpq -1, $r1 - beq 1f - nop - fail -1: - cmpq 0, $r0 - ax - cmpq -1, $r1 - bne 1f - nop - fail -1: - - ;; test for broken X sequence, run it several times. - moveq 8, $r0 -1: - moveq 0, $r3 - move.d $r0, $r1 - andq 1, $r1 - lslq 4, $r1 - moveq 1, $r2 - or.d $r1, $r2 - ba 2f - move $r2, $ccs -2: - addq 0, $r3 - move.d $r0, $r4 - move.d $r1, $r5 - move.d $r2, $r6 - move.d $r3, $r7 - lsrq 4, $r1 - move.d $r1, $r8 - xor $r1, $r3 - checkr3 0 - subq 1, $r0 - bne 1b - nop - - pass - quit diff --git a/tests/tcg/cris/bare/crt.s b/tests/tcg/cris/bare/crt.s deleted file mode 100644 index af027d747556..000000000000 --- a/tests/tcg/cris/bare/crt.s +++ /dev/null @@ -1,13 +0,0 @@ - .data -_stack_start: - .space 8192, 0 -_stack_end: - .text - .global _start -_start: - move.d _stack_end, $sp - jsr main - nop - moveq 0, $r10 - jump exit - nop diff --git a/tests/tcg/cris/bare/sys.c b/tests/tcg/cris/bare/sys.c deleted file mode 100644 index 1644eecc3346..000000000000 --- a/tests/tcg/cris/bare/sys.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Helper functions for CRIS system tests - * - * There is no libc and only a limited set of headers. - */ - -#include - -void exit(int status) -{ - register unsigned int callno asm ("r9") = 1; /* NR_exit */ - - asm volatile ("break 13\n" - : /* no outputs */ - : "r" (callno) - : "memory"); - while (1) { - /* do nothing */ - }; -} - -size_t write(int fd, const void *buf, size_t count) -{ - register unsigned int callno asm ("r9") = 4; /* NR_write */ - register unsigned int r10 asm ("r10") = fd; - register const void *r11 asm ("r11") = buf; - register size_t r12 asm ("r12") = count; - register unsigned int r asm ("r10"); - - asm volatile ("break 13\n" - : "=r" (r) - : "r" (callno), "0" (r10), "r" (r11), "r" (r12) - : "memory"); - - return r; -} - -static inline int mystrlen(char *s) -{ - int i = 0; - while (s[i]) { - i++; - } - return i; -} - - -void pass(void) -{ - char s[] = "passed.\n"; - write(1, s, sizeof(s) - 1); - exit(0); -} - -void _fail(char *reason) -{ - char s[] = "\nfailed: "; - int len = mystrlen(reason); - write(1, s, sizeof(s) - 1); - write(1, reason, len); - write(1, "\n", 1); - exit(1); -} diff --git a/tests/tcg/cris/bare/testutils.inc b/tests/tcg/cris/bare/testutils.inc deleted file mode 100644 index aa1641b2e6b4..000000000000 --- a/tests/tcg/cris/bare/testutils.inc +++ /dev/null @@ -1,117 +0,0 @@ - .syntax no_register_prefix - - .macro start - .text - .global main -main: - .endm - - .macro quit - jump pass - nop - .endm - - .macro pass - jump pass - nop - .endm - - .macro startnostack - start - .endm - - .macro fail - .data -99: - .asciz " checkr3 failed\n" - .text - move.d 99b, $r10 - jsr _fail - nop - .endm - - .macro checkr3 val - cmp.d 0x\val, $r3 - beq 100f - nop - .data -99: - .asciz "checkr3 failed\n" - .text - move.d 99b, $r10 - jsr _fail - nop -100: - .endm - -; Test the condition codes - .macro test_cc N Z V C - .if \N - bpl 9f - nop - .else - bmi 9f - nop - .endif - .if \Z - bne 9f - nop - .else - beq 9f - nop - .endif - .if \V - bvc 9f - nop - .else - bvs 9f - nop - .endif - .if \C - bcc 9f - nop - .else - bcs 9f - nop - .endif - ba 8f - nop -9: - .data -99: - .asciz "test_move_cc failed\n" - .text - move.d 99b, $r10 - jsr _fail - nop -8: - .endm - - - .macro test_move_cc N Z V C - .if \N - bpl 9f - nop - .else - bmi 9f - nop - .endif - .if \Z - bne 9f - nop - .else - beq 9f - nop - .endif - ba 8f - nop -9: - .data -99: - .asciz "test_move_cc failed\n" - .text - move.d 99b, $r10 - jsr _fail - nop -8: - .endm diff --git a/tests/tcg/cris/libc/check_abs.c b/tests/tcg/cris/libc/check_abs.c deleted file mode 100644 index 08b67b6ef0ce..000000000000 --- a/tests/tcg/cris/libc/check_abs.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -static always_inline int cris_abs(int n) -{ - int r; - asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n)); - return r; -} - -static always_inline void -verify_abs(int val, int res, - const int n, const int z, const int v, const int c) -{ - int r; - - cris_tst_cc_init(); - r = cris_abs(val); - cris_tst_cc(n, z, v, c); - if (r != res) - err(); -} - -int main(void) -{ - verify_abs(-1, 1, 0, 0, 0, 0); - verify_abs(0x80000000, 0x80000000, 1, 0, 0, 0); - verify_abs(0x7fffffff, 0x7fffffff, 0, 0, 0, 0); - verify_abs(42, 42, 0, 0, 0, 0); - verify_abs(1, 1, 0, 0, 0, 0); - verify_abs(0xffff, 0xffff, 0, 0, 0, 0); - verify_abs(0xffff, 0xffff, 0, 0, 0, 0); - verify_abs(-31, 0x1f, 0, 0, 0, 0); - verify_abs(0, 0, 0, 1, 0, 0); - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_addc.c b/tests/tcg/cris/libc/check_addc.c deleted file mode 100644 index fc3fb1faa80a..000000000000 --- a/tests/tcg/cris/libc/check_addc.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -static always_inline int cris_addc(int a, const int b) -{ - asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b)); - return a; -} - -#define verify_addc(a, b, res, n, z, v, c) \ -{ \ - int r; \ - r = cris_addc((a), (b)); \ - cris_tst_cc((n), (z), (v), (c)); \ - if (r != (res)) \ - err(); \ -} - -int main(void) -{ - cris_tst_cc_init(); - asm volatile ("clearf cz"); - verify_addc(0, 0, 0, 0, 0, 0, 0); - - cris_tst_cc_init(); - asm volatile ("setf z"); - verify_addc(0, 0, 0, 0, 1, 0, 0); - - cris_tst_cc_init(); - asm volatile ("setf cz"); - verify_addc(0, 0, 1, 0, 0, 0, 0); - cris_tst_cc_init(); - asm volatile ("clearf c"); - verify_addc(-1, 2, 1, 0, 0, 0, 1); - - cris_tst_cc_init(); - asm volatile ("clearf nzv"); - asm volatile ("setf c"); - verify_addc(-1, 2, 2, 0, 0, 0, 1); - - cris_tst_cc_init(); - asm volatile ("setf c"); - verify_addc(0xffff, 0xffff, 0x1ffff, 0, 0, 0, 0); - - cris_tst_cc_init(); - asm volatile ("clearf nzvc"); - verify_addc(-1, -1, 0xfffffffe, 1, 0, 0, 1); - - cris_tst_cc_init(); - asm volatile ("setf c"); - verify_addc(0x78134452, 0x5432f789, 0xcc463bdc, 1, 0, 1, 0); - - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_addcm.c b/tests/tcg/cris/libc/check_addcm.c deleted file mode 100644 index b355ba164fbd..000000000000 --- a/tests/tcg/cris/libc/check_addcm.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -/* need to avoid acr as source here. */ -static always_inline int cris_addc_m(int a, const int *b) -{ - asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b)); - return a; -} - -/* 'b' is a crisv32 constrain to avoid postinc with $acr. */ -static always_inline int cris_addc_pi_m(int a, int **b) -{ - asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b)); - return a; -} - -#define verify_addc_m(a, b, res, n, z, v, c) \ -{ \ - int r; \ - r = cris_addc_m((a), (b)); \ - cris_tst_cc((n), (z), (v), (c)); \ - if (r != (res)) \ - err(); \ -} - -#define verify_addc_pi_m(a, b, res, n, z, v, c) \ -{ \ - int r; \ - r = cris_addc_pi_m((a), (b)); \ - cris_tst_cc((n), (z), (v), (c)); \ - if (r != (res)) \ - err(); \ -} - -int x[] = { 0, 0, 2, -1, 0xffff, -1, 0x5432f789}; - -int main(void) -{ - int *p = (void *)&x[0]; -#if 1 - cris_tst_cc_init(); - asm volatile ("clearf cz"); - verify_addc_m(0, p, 0, 0, 0, 0, 0); - - cris_tst_cc_init(); - asm volatile ("setf z"); - verify_addc_m(0, p, 0, 0, 1, 0, 0); - - cris_tst_cc_init(); - asm volatile ("setf c"); - verify_addc_m(0, p, 1, 0, 0, 0, 0); - - cris_tst_cc_init(); - asm volatile ("clearf c"); - verify_addc_pi_m(0, &p, 0, 0, 1, 0, 0); - - p = &x[1]; - cris_tst_cc_init(); - asm volatile ("setf c"); - verify_addc_pi_m(0, &p, 1, 0, 0, 0, 0); - - if (p != &x[2]) - err(); - - cris_tst_cc_init(); - asm volatile ("clearf c"); - verify_addc_pi_m(-1, &p, 1, 0, 0, 0, 1); - - if (p != &x[3]) - err(); -#endif - p = &x[3]; - /* TODO: investigate why this one fails. */ - cris_tst_cc_init(); - asm volatile ("setf c"); - verify_addc_m(2, p, 2, 0, 0, 0, 1); - p += 4; - - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_addo.c b/tests/tcg/cris/libc/check_addo.c deleted file mode 100644 index 4235e5fc65c5..000000000000 --- a/tests/tcg/cris/libc/check_addo.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -/* this would be better to do in asm, it's an orgy in GCC inline asm now. */ - -#define cris_addo_b(o, v) \ - asm volatile ("addo.b\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr"); -#define cris_addo_w(o, v) \ - asm volatile ("addo.w\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr"); -#define cris_addo_d(o, v) \ - asm volatile ("addo.d\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr"); -#define cris_addo_pi_b(o, v) \ - asm volatile ("addo.b\t[%0+], %1, $acr\n" \ - : "+b" (o): "r" (v) : "acr"); -#define cris_addo_pi_w(o, v) \ - asm volatile ("addo.w\t[%0+], %1, $acr\n" \ - : "+b" (o): "r" (v) : "acr"); -#define cris_addo_pi_d(o, v) \ - asm volatile ("addo.d\t[%0+], %1, $acr\n" \ - : "+b" (o): "r" (v) : "acr"); - -struct { - uint32_t v1; - uint16_t v2; - uint32_t v3; - uint8_t v4; - uint8_t v5; - uint16_t v6; - uint32_t v7; -} y = { - 32769, - -1, - 5, - 3, -4, - 2, - -76789887 -}; - -static int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19}; - -int main(void) -{ - int *r; - unsigned char *t, *p; - - /* Note, this test-case will trig an unaligned access, partly - to x[0] and to [x1]. */ - t = (unsigned char *)x; - t -= 32768; - p = (unsigned char *) &y.v1; - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_pi_d(p, t); - cris_tst_cc(1, 1, 1, 1); - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - if (*r != 0x4455aa77) - err(); - - - t += 32770; - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_pi_w(p, t); - cris_tst_cc(1, 1, 1, 1); - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - if (*r != 0x4455aa77) - err(); - - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_d(p, r); - cris_tst_cc(1, 1, 1, 1); - p += 4; - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - if (*r != 0xee19ccff) - err(); - - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_pi_b(p, t); - cris_tst_cc(0, 0, 0, 0); - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - if (*(uint16_t*)r != 0xff22) - err(); - - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_b(p, r); - cris_tst_cc(1, 1, 1, 1); - p += 1; - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - if (*r != 0x4455aa77) - err(); - - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_w(p, r); - cris_tst_cc(1, 1, 1, 1); - p += 2; - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - if (*r != 0xff224455) - err(); - - mb(); /* don't reorder anything beyond here. */ - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addo_pi_d(p, t); - cris_tst_cc(0, 0, 0, 0); - asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); - r = (void*)(((char *)r) + 76789885); - if (*r != 0x55aa77ff) - err(); - - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_addoq.c b/tests/tcg/cris/libc/check_addoq.c deleted file mode 100644 index ed509e27e0e3..000000000000 --- a/tests/tcg/cris/libc/check_addoq.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -/* this would be better to do in asm, it's an orgy in GCC inline asm now. */ - -/* ACR will be clobbered. */ -#define cris_addoq(o, v) \ - asm volatile ("addoq\t%1, %0, $acr\n" : : "r" (v), "i" (o) : "acr"); - - -int main(void) -{ - int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19}; - int *p, *t = x + 1; - - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addoq(0, t); - cris_tst_cc(1, 1, 1, 1); - asm volatile ("move.d\t$acr, %0\n" : "=r" (p)); - if (*p != 0xccff2244) - err(); - - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_addoq(4, t); - cris_tst_cc(0, 0, 0, 0); - asm volatile ("move.d\t$acr, %0\n" : "=r" (p)); - if (*p != 0x88ccee19) - err(); - - cris_tst_cc_init(); - asm volatile ("clearf\tzvnc\n"); - cris_addoq(-8, t + 1); - cris_tst_cc(0, 0, 0, 0); - asm volatile ("move.d\t$acr, %0\n" : "=r" (p)); - if (*p != 0x55aa77ff) - err(); - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_bound.c b/tests/tcg/cris/libc/check_bound.c deleted file mode 100644 index d956ab9adec3..000000000000 --- a/tests/tcg/cris/libc/check_bound.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -static always_inline int cris_bound_b(int v, int b) -{ - int r = v; - asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b)); - return r; -} - -static always_inline int cris_bound_w(int v, int b) -{ - int r = v; - asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b)); - return r; -} - -static always_inline int cris_bound_d(int v, int b) -{ - int r = v; - asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b)); - return r; -} - -int main(void) -{ - int r; - - cris_tst_cc_init(); - r = cris_bound_d(-1, 2); - cris_tst_cc(0, 0, 0, 0); - if (r != 2) - err(); - - cris_tst_cc_init(); - r = cris_bound_d(2, 0xffffffff); - cris_tst_cc(0, 0, 0, 0); - if (r != 2) - err(); - - cris_tst_cc_init(); - r = cris_bound_d(0xffff, 0xffff); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xffff) - err(); - - cris_tst_cc_init(); - r = cris_bound_d(-1, 0xffffffff); - cris_tst_cc(1, 0, 0, 0); - if (r != 0xffffffff) - err(); - - cris_tst_cc_init(); - r = cris_bound_d(0x78134452, 0x5432f789); - cris_tst_cc(0, 0, 0, 0); - if (r != 0x5432f789) - err(); - - cris_tst_cc_init(); - r = cris_bound_w(-1, 2); - cris_tst_cc(0, 0, 0, 0); - if (r != 2) - err(); - - cris_tst_cc_init(); - r = cris_bound_w(-1, 0xffff); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xffff) - err(); - - cris_tst_cc_init(); - r = cris_bound_w(2, 0xffff); - cris_tst_cc(0, 0, 0, 0); - if (r != 2) - err(); - - cris_tst_cc_init(); - r = cris_bound_w(0xfedaffff, 0xffff); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xffff) - err(); - - cris_tst_cc_init(); - r = cris_bound_w(0x78134452, 0xf789); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xf789) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(-1, 2); - cris_tst_cc(0, 0, 0, 0); - if (r != 2) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(2, 0xff); - cris_tst_cc(0, 0, 0, 0); - if (r != 2) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(-1, 0xff); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xff) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(0xff, 0xff); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xff) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(0xfeda49ff, 0xff); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xff) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(0x78134452, 0x89); - cris_tst_cc(0, 0, 0, 0); - if (r != 0x89) - err(); - - cris_tst_cc_init(); - r = cris_bound_w(0x78134452, 0); - cris_tst_cc(0, 1, 0, 0); - if (r != 0) - err(); - - cris_tst_cc_init(); - r = cris_bound_b(0xffff, -1); - cris_tst_cc(0, 0, 0, 0); - if (r != 0xff) - err(); - - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_ftag.c b/tests/tcg/cris/libc/check_ftag.c deleted file mode 100644 index aaa5c9711592..000000000000 --- a/tests/tcg/cris/libc/check_ftag.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -static always_inline void cris_ftag_i(unsigned int x) -{ - register unsigned int v asm("$r10") = x; - asm ("ftagi\t[%0]\n" : : "r" (v) ); -} -static always_inline void cris_ftag_d(unsigned int x) -{ - register unsigned int v asm("$r10") = x; - asm ("ftagd\t[%0]\n" : : "r" (v) ); -} -static always_inline void cris_fidx_i(unsigned int x) -{ - register unsigned int v asm("$r10") = x; - asm ("fidxi\t[%0]\n" : : "r" (v) ); -} -static always_inline void cris_fidx_d(unsigned int x) -{ - register unsigned int v asm("$r10") = x; - asm ("fidxd\t[%0]\n" : : "r" (v) ); -} - - -int main(void) -{ - cris_ftag_i(0); - cris_ftag_d(0); - cris_fidx_i(0); - cris_fidx_d(0); - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c b/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c deleted file mode 100644 index 45ecd159b3ca..000000000000 --- a/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c +++ /dev/null @@ -1,15 +0,0 @@ -/* PR rtl-optimization/28634. On targets with delayed branches, - dbr_schedule could do the next iteration's addition in the - branch delay slot, then subtract the value again if the branch - wasn't taken. This can lead to rounding errors. */ -int x = -1; -int y = 1; -int -main (void) -{ - while (y > 0) - y += x; - if (y != x + 1) - abort (); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_gcctorture_pr28634.c b/tests/tcg/cris/libc/check_gcctorture_pr28634.c deleted file mode 100644 index a0c525497d72..000000000000 --- a/tests/tcg/cris/libc/check_gcctorture_pr28634.c +++ /dev/null @@ -1,15 +0,0 @@ -/* PR rtl-optimization/28634. On targets with delayed branches, - dbr_schedule could do the next iteration's addition in the - branch delay slot, then subtract the value again if the branch - wasn't taken. This can lead to rounding errors. */ -double x = -0x1.0p53; -double y = 1; -int -main (void) -{ - while (y > 0) - y += x; - if (y != x + 1) - abort (); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_glibc_kernelversion.c b/tests/tcg/cris/libc/check_glibc_kernelversion.c deleted file mode 100644 index 7aada899115a..000000000000 --- a/tests/tcg/cris/libc/check_glibc_kernelversion.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Check the lz insn. - */ - -#include -#include -#include -#include "sys.h" - -#define __LINUX_KERNEL_VERSION 131584 - -#define DL_SYSDEP_OSCHECK(FATAL) \ - do { \ - /* Test whether the kernel is new enough. This test is only \ - performed if the library is not compiled to run on all \ - kernels. */ \ - if (__LINUX_KERNEL_VERSION > 0) \ - { \ - char bufmem[64]; \ - char *buf = bufmem; \ - unsigned int version; \ - int parts; \ - char *cp; \ - struct utsname uts; \ - \ - /* Try the uname syscall */ \ - if (__uname (&uts)) \ - { \ - /* This was not successful. Now try reading the /proc \ - filesystem. */ \ - ssize_t reslen; \ - int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY); \ - if (fd == -1 \ - || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0) \ - /* This also didn't work. We give up since we cannot \ - make sure the library can actually work. */ \ - FATAL ("FATAL: cannot determine library version\n"); \ - __close (fd); \ - buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0'; \ - } \ - else \ - buf = uts.release; \ - \ - /* Now convert it into a number. The string consists of at most \ - three parts. */ \ - version = 0; \ - parts = 0; \ - cp = buf; \ - while ((*cp >= '0') && (*cp <= '9')) \ - { \ - unsigned int here = *cp++ - '0'; \ - \ - while ((*cp >= '0') && (*cp <= '9')) \ - { \ - here *= 10; \ - here += *cp++ - '0'; \ - } \ - \ - ++parts; \ - version <<= 8; \ - version |= here; \ - \ - if (*cp++ != '.') \ - /* Another part following? */ \ - break; \ - } \ - \ - if (parts < 3) \ - version <<= 8 * (3 - parts); \ - \ - /* Now we can test with the required version. */ \ - if (version < __LINUX_KERNEL_VERSION) \ - /* Not sufficient. */ \ - FATAL ("FATAL: kernel too old\n"); \ - \ - _dl_osversion = version; \ - } \ - } while (0) - -int main(void) -{ - char bufmem[64] = "2.6.22"; - char *buf = bufmem; - unsigned int version; - int parts; - char *cp; - - version = 0; - parts = 0; - cp = buf; - while ((*cp >= '0') && (*cp <= '9')) - { - unsigned int here = *cp++ - '0'; - - while ((*cp >= '0') && (*cp <= '9')) - { - here *= 10; - here += *cp++ - '0'; - } - - ++parts; - version <<= 8; - version |= here; - - if (*cp++ != '.') - /* Another part following? */ - break; - } - - if (parts < 3) - version <<= 8 * (3 - parts); - if (version < __LINUX_KERNEL_VERSION) - err(); - pass(); - exit(0); -} diff --git a/tests/tcg/cris/libc/check_hello.c b/tests/tcg/cris/libc/check_hello.c deleted file mode 100644 index fb403ba99612..000000000000 --- a/tests/tcg/cris/libc/check_hello.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include -int main () -{ - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_int64.c b/tests/tcg/cris/libc/check_int64.c deleted file mode 100644 index 69caec1bb24d..000000000000 --- a/tests/tcg/cris/libc/check_int64.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - - -static always_inline int64_t add64(const int64_t a, const int64_t b) -{ - return a + b; -} - -static always_inline int64_t sub64(const int64_t a, const int64_t b) -{ - return a - b; -} - -int main(void) -{ - int64_t a = 1; - int64_t b = 2; - - /* FIXME: add some tests. */ - a = add64(a, b); - if (a != 3) - err(); - - a = sub64(a, b); - if (a != 1) - err(); - - a = add64(a, -4); - if (a != -3) - err(); - - a = add64(a, 3); - if (a != 0) - err(); - - a = 0; - a = sub64(a, 1); - if (a != -1) - err(); - - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_lz.c b/tests/tcg/cris/libc/check_lz.c deleted file mode 100644 index bf051a6b550e..000000000000 --- a/tests/tcg/cris/libc/check_lz.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include "sys.h" - -static always_inline int cris_lz(int x) -{ - int r; - asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x)); - return r; -} - -void check_lz(void) -{ - int i; - - if (cris_lz(0) != 32) - err(); - if (cris_lz(1) != 31) - err(); - if (cris_lz(2) != 30) - err(); - if (cris_lz(4) != 29) - err(); - if (cris_lz(8) != 28) - err(); - - /* try all positions with a single bit. */ - for (i = 1; i < 32; i++) { - if (cris_lz(1 << (i-1)) != (32 - i)) - err(); - } - - /* try all positions with all bits. */ - for (i = 1; i < 32; i++) { - /* split up this computation to clarify it. */ - uint32_t val; - val = (unsigned int)-1 >> (32 - i); - if (cris_lz(val) != (32 - i)) - err(); - } -} - -int main(void) -{ - check_lz(); - pass(); - exit(0); -} diff --git a/tests/tcg/cris/libc/check_mapbrk.c b/tests/tcg/cris/libc/check_mapbrk.c deleted file mode 100644 index 1aff7622bc2a..000000000000 --- a/tests/tcg/cris/libc/check_mapbrk.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -/* Basic sanity check that syscalls to implement malloc (brk, mmap2, - munmap) are trivially functional. */ - -int main () -{ - void *p1, *p2, *p3, *p4, *p5, *p6; - - if ((p1 = malloc (8100)) == NULL - || (p2 = malloc (16300)) == NULL - || (p3 = malloc (4000)) == NULL - || (p4 = malloc (500)) == NULL - || (p5 = malloc (1023*1024)) == NULL - || (p6 = malloc (8191*1024)) == NULL) - { - printf ("fail\n"); - exit (1); - } - - free (p1); - free (p2); - free (p3); - free (p4); - free (p5); - free (p6); - - p1 = malloc (64000); - if (p1 == NULL) - { - printf ("fail\n"); - exit (1); - } - free (p1); - - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_mmap1.c b/tests/tcg/cris/libc/check_mmap1.c deleted file mode 100644 index b803f0c431e7..000000000000 --- a/tests/tcg/cris/libc/check_mmap1.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -#notarget: cris*-*-elf -*/ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - int fd = open (argv[0], O_RDONLY); - struct stat sb; - int size; - void *a; - const char *str = "a string you'll only find in the program"; - - if (fd == -1) - { - perror ("open"); - abort (); - } - - if (fstat (fd, &sb) < 0) - { - perror ("fstat"); - abort (); - } - - size = sb.st_size; - - /* We want to test mmapping a size that isn't exactly a page. */ - if ((size & 8191) == 0) - size--; - - a = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - - if (memmem (a, size, str, strlen (str) + 1) == NULL) - abort (); - - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_mmap2.c b/tests/tcg/cris/libc/check_mmap2.c deleted file mode 100644 index 35139a0ed9aa..000000000000 --- a/tests/tcg/cris/libc/check_mmap2.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -#notarget: cris*-*-elf -*/ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - int fd = open (argv[0], O_RDONLY); - struct stat sb; - int size; - void *a; - const char *str = "a string you'll only find in the program"; - - if (fd == -1) - { - perror ("open"); - abort (); - } - - if (fstat (fd, &sb) < 0) - { - perror ("fstat"); - abort (); - } - - size = sb.st_size; - - /* We want to test mmapping a size that isn't exactly a page. */ - if ((size & 8191) == 0) - size--; - - a = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); - - if (memmem (a, size, str, strlen (str) + 1) == NULL) - abort (); - - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_mmap3.c b/tests/tcg/cris/libc/check_mmap3.c deleted file mode 100644 index cb890ef12005..000000000000 --- a/tests/tcg/cris/libc/check_mmap3.c +++ /dev/null @@ -1,33 +0,0 @@ -/* -#notarget: cris*-*-elf -*/ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - volatile unsigned char *a; - - /* Check that we can map a non-multiple of a page and still get a full page. */ - a = mmap (NULL, 0x4c, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (a == NULL || a == (unsigned char *) -1) - abort (); - - a[0] = 0xbe; - a[8191] = 0xef; - memset ((char *) a + 1, 0, 8190); - - if (a[0] != 0xbe || a[8191] != 0xef) - abort (); - - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_moveq.c b/tests/tcg/cris/libc/check_moveq.c deleted file mode 100644 index 80f2dff6ab24..000000000000 --- a/tests/tcg/cris/libc/check_moveq.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -#define cris_moveq(dst, src) \ - asm volatile ("moveq %1, %0\n" : "=r" (dst) : "i" (src)); - - - -int main(void) -{ - int t; - - cris_tst_cc_init(); - asm volatile ("setf\tzvnc\n"); - cris_moveq(t, 10); - cris_tst_cc(1, 1, 1, 1); - if (t != 10) - err(); - - /* make sure moveq doesn't clobber the zflag. */ - cris_tst_cc_init(); - asm volatile ("setf vnc\n"); - asm volatile ("clearf z\n"); - cris_moveq(t, 0); - cris_tst_cc(1, 0, 1, 1); - if (t != 0) - err(); - - /* make sure moveq doesn't clobber the nflag. - Also check large immediates */ - cris_tst_cc_init(); - asm volatile ("setf zvc\n"); - asm volatile ("clearf n\n"); - cris_moveq(t, -31); - cris_tst_cc(0, 1, 1, 1); - if (t != -31) - err(); - - cris_tst_cc_init(); - asm volatile ("setf nzvc\n"); - cris_moveq(t, 31); - cris_tst_cc(1, 1, 1, 1); - if (t != 31) - err(); - - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_openpf1.c b/tests/tcg/cris/libc/check_openpf1.c deleted file mode 100644 index 251d26eec2e9..000000000000 --- a/tests/tcg/cris/libc/check_openpf1.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Check that --sysroot is applied to open(2). -#sim: --sysroot=@exedir@ - - We assume, with EXE being the name of the executable: - - The simulator executes with cwd the same directory where the executable - is located (so argv[0] contains a plain filename without directory - components). - - There's no /EXE on the host file system. */ - -#include -#include -#include -#include -int main (int argc, char *argv[]) -{ - char *fnam = argv[0]; - FILE *f; - if (argv[0][0] != '/') - { - fnam = malloc (strlen (argv[0]) + 2); - if (fnam == NULL) - abort (); - strcpy (fnam, "/"); - strcat (fnam, argv[0]); - } - - f = fopen (fnam, "rb"); - if (f == NULL) - abort (); - fclose(f); - - /* Cover another execution path. */ - if (fopen ("/nonexistent", "rb") != NULL - || errno != ENOENT) - abort (); - printf ("pass\n"); - return 0; -} diff --git a/tests/tcg/cris/libc/check_openpf2.c b/tests/tcg/cris/libc/check_openpf2.c deleted file mode 100644 index 5d56189f8eaa..000000000000 --- a/tests/tcg/cris/libc/check_openpf2.c +++ /dev/null @@ -1,16 +0,0 @@ -/* Check that the simulator has chdir:ed to the --sysroot argument -#sim: --sysroot=@srcdir@ - (or that --sysroot is applied to relative file paths). */ - -#include -#include -#include -int main (int argc, char *argv[]) -{ - FILE *f = fopen ("check_openpf2.c", "rb"); - if (f == NULL) - abort (); - fclose(f); - printf ("pass\n"); - return 0; -} diff --git a/tests/tcg/cris/libc/check_openpf3.c b/tests/tcg/cris/libc/check_openpf3.c deleted file mode 100644 index 557adee92dec..000000000000 --- a/tests/tcg/cris/libc/check_openpf3.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Basic file operations (rename, unlink); once without sysroot. We - also test that the simulator has chdir:ed to PREFIX, when defined. */ - -#include -#include -#include -#include -#include -#include - -#ifndef PREFIX -#define PREFIX -#endif - -void err (const char *s) -{ - perror (s); - abort (); -} - -int main (int argc, char *argv[]) -{ - FILE *f; - struct stat buf; - - unlink (PREFIX "testfoo2.tmp"); - - f = fopen ("testfoo1.tmp", "w"); - if (f == NULL) - err ("open"); - fclose (f); - - if (rename (PREFIX "testfoo1.tmp", PREFIX "testfoo2.tmp") != 0) - err ("rename"); - - if (stat (PREFIX "testfoo2.tmp", &buf) != 0 - || !S_ISREG (buf.st_mode)) - err ("stat 1"); - - if (stat ("testfoo2.tmp", &buf) != 0 - || !S_ISREG (buf.st_mode)) - err ("stat 2"); - - if (unlink (PREFIX "testfoo2.tmp") != 0) - err ("unlink"); - - printf ("pass\n"); - return 0; -} diff --git a/tests/tcg/cris/libc/check_openpf5.c b/tests/tcg/cris/libc/check_openpf5.c deleted file mode 100644 index 1f86ea283d4b..000000000000 --- a/tests/tcg/cris/libc/check_openpf5.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Check that TRT happens when error on too many opened files. -#notarget: cris*-*-elf -#sim: --sysroot=@exedir@ -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - int i; - int filemax; - -#ifdef OPEN_MAX - filemax = OPEN_MAX; -#else - filemax = sysconf (_SC_OPEN_MAX); -#endif - - char *fn = malloc (strlen (argv[0]) + 2); - if (fn == NULL) - abort (); - strcpy (fn, "/"); - strcat (fn, argv[0]); - - for (i = 0; i < filemax + 1; i++) - { - if (open (fn, O_RDONLY) < 0) - { - /* Shouldn't happen too early. */ - if (i < filemax - 3 - 1) - { - fprintf (stderr, "i: %d\n", i); - abort (); - } - if (errno != EMFILE) - { - perror ("open"); - abort (); - } - goto ok; - } - } - abort (); - -ok: - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_settls1.c b/tests/tcg/cris/libc/check_settls1.c deleted file mode 100644 index 3abc3a9ea830..000000000000 --- a/tests/tcg/cris/libc/check_settls1.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -#include - -#include - -#ifndef SYS_set_thread_area -#define SYS_set_thread_area 243 -#endif - -int main (void) -{ - unsigned long tp, old_tp; - int ret; - - asm volatile ("move $pid,%0" : "=r" (old_tp)); - old_tp &= ~0xff; - - ret = syscall (SYS_set_thread_area, 0xf0); - if (ret != -1 || errno != EINVAL) { - syscall (SYS_set_thread_area, old_tp); - perror ("Invalid thread area accepted:"); - abort(); - } - - ret = syscall (SYS_set_thread_area, 0xeddeed00); - if (ret != 0) { - perror ("Valid thread area not accepted: "); - abort (); - } - - asm volatile ("move $pid,%0" : "=r" (tp)); - tp &= ~0xff; - syscall (SYS_set_thread_area, old_tp); - - if (tp != 0xeddeed00) { - * (volatile int *) 0 = 0; - perror ("tls2"); - abort (); - } - - printf ("pass\n"); - return EXIT_SUCCESS; -} diff --git a/tests/tcg/cris/libc/check_sigalrm.c b/tests/tcg/cris/libc/check_sigalrm.c deleted file mode 100644 index 39fa8d9bacd4..000000000000 --- a/tests/tcg/cris/libc/check_sigalrm.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include - -#define MAGIC (0xdeadbeef) - -int s = 0; -void sighandler(int sig) -{ - s = MAGIC; -} - -int main(int argc, char **argv) -{ - int p; - - p = getpid(); - signal(SIGALRM, sighandler); - kill(p, SIGALRM); - if (s != MAGIC) - return EXIT_FAILURE; - - printf ("passed\n"); - return EXIT_SUCCESS; -} diff --git a/tests/tcg/cris/libc/check_stat1.c b/tests/tcg/cris/libc/check_stat1.c deleted file mode 100644 index 2e2cae51df03..000000000000 --- a/tests/tcg/cris/libc/check_stat1.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include -#include -#include - -int main (void) -{ - struct stat buf; - - if (stat (".", &buf) != 0 - || !S_ISDIR (buf.st_mode)) - abort (); - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_stat2.c b/tests/tcg/cris/libc/check_stat2.c deleted file mode 100644 index e36172ed2573..000000000000 --- a/tests/tcg/cris/libc/check_stat2.c +++ /dev/null @@ -1,20 +0,0 @@ -/* -#notarget: cris*-*-elf -*/ - -#include -#include -#include -#include -#include - -int main (void) -{ - struct stat buf; - - if (lstat (".", &buf) != 0 - || !S_ISDIR (buf.st_mode)) - abort (); - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_stat3.c b/tests/tcg/cris/libc/check_stat3.c deleted file mode 100644 index 36a9d5d2744b..000000000000 --- a/tests/tcg/cris/libc/check_stat3.c +++ /dev/null @@ -1,25 +0,0 @@ -/* Simulator options: -#sim: --sysroot=@exedir@ -*/ -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - char path[1024] = "/"; - struct stat buf; - - strncat(path, argv[0], sizeof(path) - 2); - if (stat (".", &buf) != 0 - || !S_ISDIR (buf.st_mode)) - abort (); - if (stat (path, &buf) != 0 - || !S_ISREG (buf.st_mode)) - abort (); - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_stat4.c b/tests/tcg/cris/libc/check_stat4.c deleted file mode 100644 index 04f21fe7c4f5..000000000000 --- a/tests/tcg/cris/libc/check_stat4.c +++ /dev/null @@ -1,27 +0,0 @@ -/* Simulator options: -#notarget: cris*-*-elf -#sim: --sysroot=@exedir@ -*/ - -#include -#include -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - char path[1024] = "/"; - struct stat buf; - - strncat(path, argv[0], sizeof(path) - 2); - if (lstat (".", &buf) != 0 - || !S_ISDIR (buf.st_mode)) - abort (); - if (lstat (path, &buf) != 0 - || !S_ISREG (buf.st_mode)) - abort (); - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/check_swap.c b/tests/tcg/cris/libc/check_swap.c deleted file mode 100644 index 9a68c1e5d765..000000000000 --- a/tests/tcg/cris/libc/check_swap.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include "sys.h" -#include "crisutils.h" - -#define N 8 -#define W 4 -#define B 2 -#define R 1 - -static always_inline int cris_swap(const int mode, int x) -{ - switch (mode) - { - case N: asm ("swapn\t%0\n" : "+r" (x) : "0" (x)); break; - case W: asm ("swapw\t%0\n" : "+r" (x) : "0" (x)); break; - case B: asm ("swapb\t%0\n" : "+r" (x) : "0" (x)); break; - case R: asm ("swapr\t%0\n" : "+r" (x) : "0" (x)); break; - case B|R: asm ("swapbr\t%0\n" : "+r" (x) : "0" (x)); break; - case W|R: asm ("swapwr\t%0\n" : "+r" (x) : "0" (x)); break; - case W|B: asm ("swapwb\t%0\n" : "+r" (x) : "0" (x)); break; - case W|B|R: asm ("swapwbr\t%0\n" : "+r" (x) : "0" (x)); break; - case N|R: asm ("swapnr\t%0\n" : "+r" (x) : "0" (x)); break; - case N|B: asm ("swapnb\t%0\n" : "+r" (x) : "0" (x)); break; - case N|B|R: asm ("swapnbr\t%0\n" : "+r" (x) : "0" (x)); break; - case N|W: asm ("swapnw\t%0\n" : "+r" (x) : "0" (x)); break; - default: - err(); - break; - } - return x; -} - -/* Made this a macro to be able to pick up the location of the errors. */ -#define verify_swap(mode, val, expected, n, z) \ -do { \ - int r; \ - cris_tst_cc_init(); \ - r = cris_swap(mode, val); \ - cris_tst_mov_cc(n, z); \ - if (r != expected) \ - err(); \ -} while(0) - -void check_swap(void) -{ - /* Some of these numbers are borrowed from GDB's cris sim - testsuite. */ - if (cris_swap(N, 0) != 0xffffffff) - err(); - if (cris_swap(W, 0x12345678) != 0x56781234) - err(); - if (cris_swap(B, 0x12345678) != 0x34127856) - err(); - - verify_swap(R, 0x78134452, 0x1ec8224a, 0, 0); - verify_swap(B, 0x78134452, 0x13785244, 0, 0); - verify_swap(B|R, 0x78134452, 0xc81e4a22, 1, 0); - verify_swap(W, 0x78134452, 0x44527813, 0, 0); - verify_swap(W|R, 0x78134452, 0x224a1ec8, 0, 0); - verify_swap(W|B|R, 0x78134452, 0x4a22c81e, 0, 0); - verify_swap(N, 0x78134452, 0x87ecbbad, 1, 0); - verify_swap(N|R, 0x78134452, 0xe137ddb5, 1, 0); - verify_swap(N|B, 0x78134452, 0xec87adbb, 1, 0); - verify_swap(N|B|R, 0x78134452, 0x37e1b5dd, 0, 0); - verify_swap(N|W, 0x78134452, 0xbbad87ec, 1, 0); - verify_swap(N|B|R, 0xffffffff, 0, 0, 1); -} - -int main(void) -{ - check_swap(); - pass(); - return 0; -} diff --git a/tests/tcg/cris/libc/check_time2.c b/tests/tcg/cris/libc/check_time2.c deleted file mode 100644 index 20b69b4f60b8..000000000000 --- a/tests/tcg/cris/libc/check_time2.c +++ /dev/null @@ -1,18 +0,0 @@ -/* CB_SYS_time doesn't implement the Linux time syscall; the return - value isn't written to the argument. */ - -#include -#include -#include - -int -main (void) -{ - time_t x = (time_t) -1; - time_t t = time (&x); - - if (t == (time_t) -1 || t != x) - abort (); - printf ("pass\n"); - exit (0); -} diff --git a/tests/tcg/cris/libc/crisutils.h b/tests/tcg/cris/libc/crisutils.h deleted file mode 100644 index bbbe6c55405d..000000000000 --- a/tests/tcg/cris/libc/crisutils.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef CRISUTILS_H -#define CRISUTILS_H 1 - -static char *tst_cc_loc = NULL; - -#define cris_tst_cc_init() \ -do { tst_cc_loc = "test_cc failed at " CURRENT_LOCATION; } while(0) - -/* We need a real symbol to signal error. */ -void _err(void) { - if (!tst_cc_loc) - tst_cc_loc = "tst_cc_failed\n"; - _fail(tst_cc_loc); -} - -static always_inline void cris_tst_cc_n1(void) -{ - asm volatile ("bpl _err\n" - "nop\n"); -} -static always_inline void cris_tst_cc_n0(void) -{ - asm volatile ("bmi _err\n" - "nop\n"); -} - -static always_inline void cris_tst_cc_z1(void) -{ - asm volatile ("bne _err\n" - "nop\n"); -} -static always_inline void cris_tst_cc_z0(void) -{ - asm volatile ("beq _err\n" - "nop\n"); -} -static always_inline void cris_tst_cc_v1(void) -{ - asm volatile ("bvc _err\n" - "nop\n"); -} -static always_inline void cris_tst_cc_v0(void) -{ - asm volatile ("bvs _err\n" - "nop\n"); -} - -static always_inline void cris_tst_cc_c1(void) -{ - asm volatile ("bcc _err\n" - "nop\n"); -} -static always_inline void cris_tst_cc_c0(void) -{ - asm volatile ("bcs _err\n" - "nop\n"); -} - -static always_inline void cris_tst_mov_cc(int n, int z) -{ - if (n) cris_tst_cc_n1(); else cris_tst_cc_n0(); - if (z) cris_tst_cc_z1(); else cris_tst_cc_z0(); - asm volatile ("" : : "g" (_err)); -} - -static always_inline void cris_tst_cc(const int n, const int z, - const int v, const int c) -{ - if (n) cris_tst_cc_n1(); else cris_tst_cc_n0(); - if (z) cris_tst_cc_z1(); else cris_tst_cc_z0(); - if (v) cris_tst_cc_v1(); else cris_tst_cc_v0(); - if (c) cris_tst_cc_c1(); else cris_tst_cc_c0(); - asm volatile ("" : : "g" (_err)); -} - -#endif diff --git a/tests/tcg/cris/libc/sys.h b/tests/tcg/cris/libc/sys.h deleted file mode 100644 index 3dd47bb67306..000000000000 --- a/tests/tcg/cris/libc/sys.h +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) - -#define always_inline inline __attribute__((always_inline)) - -#define CURRENT_LOCATION __FILE__ ":" TOSTRING(__LINE__) - -#define err() \ -{ \ - _fail("at " CURRENT_LOCATION " "); \ -} - -#define mb() asm volatile ("" : : : "memory") - -void pass(void); -void _fail(char *reason); diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target deleted file mode 100644 index 23b987053491..000000000000 --- a/tests/tcg/hexagon/Makefile.target +++ /dev/null @@ -1,51 +0,0 @@ -## -## 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 -## 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 . -## - -# Hexagon doesn't support gdb, so skip the EXTRA_RUNS -EXTRA_RUNS = - -CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal -CFLAGS += -fno-unroll-loops - -HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon -VPATH += $(HEX_SRC) - -first: $(HEX_SRC)/first.S - $(CC) -static -mv67 -nostdlib $^ -o $@ - -HEX_TESTS = first -HEX_TESTS += hex_sigsegv -HEX_TESTS += misc -HEX_TESTS += usr -HEX_TESTS += preg_alias -HEX_TESTS += dual_stores -HEX_TESTS += multi_result -HEX_TESTS += mem_noshuf -HEX_TESTS += circ -HEX_TESTS += brev -HEX_TESTS += load_unpack -HEX_TESTS += load_align -HEX_TESTS += atomics -HEX_TESTS += fpstuff -HEX_TESTS += overflow - -TESTS += $(HEX_TESTS) - -# This test has to be compiled for the -mv67t target -usr: usr.c - $(CC) $(CFLAGS) -mv67t -O2 -Wno-inline-asm -Wno-expansion-to-defined $< -o $@ $(LDFLAGS) - diff --git a/tests/tcg/hexagon/atomics.c b/tests/tcg/hexagon/atomics.c deleted file mode 100644 index ff1ceee24101..000000000000 --- a/tests/tcg/hexagon/atomics.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include -#include -#include -#include -#include -#include - -/* Using volatile because we are testing atomics */ -static inline int atomic_inc32(volatile int *x) -{ - int old, dummy; - __asm__ __volatile__( - "1: %0 = memw_locked(%2)\n\t" - " %1 = add(%0, #1)\n\t" - " memw_locked(%2, p0) = %1\n\t" - " if (!p0) jump 1b\n\t" - : "=&r"(old), "=&r"(dummy) - : "r"(x) - : "p0", "memory"); - return old; -} - -/* Using volatile because we are testing atomics */ -static inline long long atomic_inc64(volatile long long *x) -{ - long long old, dummy; - __asm__ __volatile__( - "1: %0 = memd_locked(%2)\n\t" - " %1 = #1\n\t" - " %1 = add(%0, %1)\n\t" - " memd_locked(%2, p0) = %1\n\t" - " if (!p0) jump 1b\n\t" - : "=&r"(old), "=&r"(dummy) - : "r"(x) - : "p0", "memory"); - return old; -} - -/* Using volatile because we are testing atomics */ -static inline int atomic_dec32(volatile int *x) -{ - int old, dummy; - __asm__ __volatile__( - "1: %0 = memw_locked(%2)\n\t" - " %1 = add(%0, #-1)\n\t" - " memw_locked(%2, p0) = %1\n\t" - " if (!p0) jump 1b\n\t" - : "=&r"(old), "=&r"(dummy) - : "r"(x) - : "p0", "memory"); - return old; -} - -/* Using volatile because we are testing atomics */ -static inline long long atomic_dec64(volatile long long *x) -{ - long long old, dummy; - __asm__ __volatile__( - "1: %0 = memd_locked(%2)\n\t" - " %1 = #-1\n\t" - " %1 = add(%0, %1)\n\t" - " memd_locked(%2, p0) = %1\n\t" - " if (!p0) jump 1b\n\t" - : "=&r"(old), "=&r"(dummy) - : "r"(x) - : "p0", "memory"); - return old; -} - -#define LOOP_CNT 1000 -/* Using volatile because we are testing atomics */ -volatile int tick32 = 1; -/* Using volatile because we are testing atomics */ -volatile long long tick64 = 1; -int err; - -void *thread1_func(void *arg) -{ - int i; - - for (i = 0; i < LOOP_CNT; i++) { - atomic_inc32(&tick32); - atomic_dec64(&tick64); - } - return NULL; -} - -void *thread2_func(void *arg) -{ - int i; - for (i = 0; i < LOOP_CNT; i++) { - atomic_dec32(&tick32); - atomic_inc64(&tick64); - } - return NULL; -} - -void test_pthread(void) -{ - pthread_t tid1, tid2; - - pthread_create(&tid1, NULL, thread1_func, "hello1"); - pthread_create(&tid2, NULL, thread2_func, "hello2"); - pthread_join(tid1, NULL); - pthread_join(tid2, NULL); - - if (tick32 != 1) { - printf("ERROR: tick32 %d != 1\n", tick32); - err++; - } - if (tick64 != 1) { - printf("ERROR: tick64 %lld != 1\n", tick64); - err++; - } -} - -int main(int argc, char **argv) -{ - test_pthread(); - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/brev.c b/tests/tcg/hexagon/brev.c deleted file mode 100644 index 9736a2405dea..000000000000 --- a/tests/tcg/hexagon/brev.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include -#include - -int err; - -#define NBITS 8 -#define SIZE (1 << NBITS) - -long long dbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; -int wbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; -short hbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; -unsigned char bbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; - -/* - * We use the C preporcessor to deal with the combinations of types - */ - -#define BREV_LOAD(SZ, RES, ADDR, INC) \ - __asm__( \ - "m0 = %2\n\t" \ - "%0 = mem" #SZ "(%1++m0:brev)\n\t" \ - : "=r"(RES), "+r"(ADDR) \ - : "r"(INC) \ - : "m0") - -#define BREV_LOAD_b(RES, ADDR, INC) \ - BREV_LOAD(b, RES, ADDR, INC) -#define BREV_LOAD_ub(RES, ADDR, INC) \ - BREV_LOAD(ub, RES, ADDR, INC) -#define BREV_LOAD_h(RES, ADDR, INC) \ - BREV_LOAD(h, RES, ADDR, INC) -#define BREV_LOAD_uh(RES, ADDR, INC) \ - BREV_LOAD(uh, RES, ADDR, INC) -#define BREV_LOAD_w(RES, ADDR, INC) \ - BREV_LOAD(w, RES, ADDR, INC) -#define BREV_LOAD_d(RES, ADDR, INC) \ - BREV_LOAD(d, RES, ADDR, INC) - -#define BREV_STORE(SZ, PART, ADDR, VAL, INC) \ - __asm__( \ - "m0 = %2\n\t" \ - "mem" #SZ "(%0++m0:brev) = %1" PART "\n\t" \ - : "+r"(ADDR) \ - : "r"(VAL), "r"(INC) \ - : "m0", "memory") - -#define BREV_STORE_b(ADDR, VAL, INC) \ - BREV_STORE(b, "", ADDR, VAL, INC) -#define BREV_STORE_h(ADDR, VAL, INC) \ - BREV_STORE(h, "", ADDR, VAL, INC) -#define BREV_STORE_f(ADDR, VAL, INC) \ - BREV_STORE(h, ".H", ADDR, VAL, INC) -#define BREV_STORE_w(ADDR, VAL, INC) \ - BREV_STORE(w, "", ADDR, VAL, INC) -#define BREV_STORE_d(ADDR, VAL, INC) \ - BREV_STORE(d, "", ADDR, VAL, INC) - -#define BREV_STORE_NEW(SZ, ADDR, VAL, INC) \ - __asm__( \ - "m0 = %2\n\t" \ - "{\n\t" \ - " r5 = %1\n\t" \ - " mem" #SZ "(%0++m0:brev) = r5.new\n\t" \ - "}\n\t" \ - : "+r"(ADDR) \ - : "r"(VAL), "r"(INC) \ - : "r5", "m0", "memory") - -#define BREV_STORE_bnew(ADDR, VAL, INC) \ - BREV_STORE_NEW(b, ADDR, VAL, INC) -#define BREV_STORE_hnew(ADDR, VAL, INC) \ - BREV_STORE_NEW(h, ADDR, VAL, INC) -#define BREV_STORE_wnew(ADDR, VAL, INC) \ - BREV_STORE_NEW(w, ADDR, VAL, INC) - -int bitreverse(int x) -{ - int result = 0; - int i; - for (i = 0; i < NBITS; i++) { - result <<= 1; - result |= x & 1; - x >>= 1; - } - return result; -} - -int sext8(int x) -{ - return (x << 24) >> 24; -} - -void check(int i, long long result, long long expect) -{ - if (result != expect) { - printf("ERROR(%d): 0x%04llx != 0x%04llx\n", i, result, expect); - err++; - } -} - -#define TEST_BREV_LOAD(SZ, TYPE, BUF, SHIFT, EXP) \ - do { \ - p = BUF; \ - for (i = 0; i < SIZE; i++) { \ - TYPE result; \ - BREV_LOAD_##SZ(result, p, 1 << (SHIFT - NBITS)); \ - check(i, result, EXP); \ - } \ - } while (0) - -#define TEST_BREV_STORE(SZ, TYPE, BUF, VAL, SHIFT) \ - do { \ - p = BUF; \ - memset(BUF, 0xff, sizeof(BUF)); \ - for (i = 0; i < SIZE; i++) { \ - BREV_STORE_##SZ(p, (TYPE)(VAL), 1 << (SHIFT - NBITS)); \ - } \ - for (i = 0; i < SIZE; i++) { \ - check(i, BUF[i], bitreverse(i)); \ - } \ - } while (0) - -#define TEST_BREV_STORE_NEW(SZ, BUF, SHIFT) \ - do { \ - p = BUF; \ - memset(BUF, 0xff, sizeof(BUF)); \ - for (i = 0; i < SIZE; i++) { \ - BREV_STORE_##SZ(p, i, 1 << (SHIFT - NBITS)); \ - } \ - for (i = 0; i < SIZE; i++) { \ - check(i, BUF[i], bitreverse(i)); \ - } \ - } while (0) - -/* - * We'll set high_half[i] = i << 16 for use in the .H form of store - * which stores from the high half of the word. - */ -int high_half[SIZE]; - -int main() -{ - void *p; - int i; - - for (i = 0; i < SIZE; i++) { - bbuf[i] = bitreverse(i); - hbuf[i] = bitreverse(i); - wbuf[i] = bitreverse(i); - dbuf[i] = bitreverse(i); - high_half[i] = i << 16; - } - - TEST_BREV_LOAD(b, int, bbuf, 16, sext8(i)); - TEST_BREV_LOAD(ub, int, bbuf, 16, i); - TEST_BREV_LOAD(h, int, hbuf, 15, i); - TEST_BREV_LOAD(uh, int, hbuf, 15, i); - TEST_BREV_LOAD(w, int, wbuf, 14, i); - TEST_BREV_LOAD(d, long long, dbuf, 13, i); - - TEST_BREV_STORE(b, int, bbuf, i, 16); - TEST_BREV_STORE(h, int, hbuf, i, 15); - TEST_BREV_STORE(f, int, hbuf, high_half[i], 15); - TEST_BREV_STORE(w, int, wbuf, i, 14); - TEST_BREV_STORE(d, long long, dbuf, i, 13); - - TEST_BREV_STORE_NEW(bnew, bbuf, 16); - TEST_BREV_STORE_NEW(hnew, hbuf, 15); - TEST_BREV_STORE_NEW(wnew, wbuf, 14); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/circ.c b/tests/tcg/hexagon/circ.c deleted file mode 100644 index 354416eb6d39..000000000000 --- a/tests/tcg/hexagon/circ.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * 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 - * 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 . - */ - -#include - -#define DEBUG 0 -#define DEBUG_PRINTF(...) \ - do { \ - if (DEBUG) { \ - printf(__VA_ARGS__); \ - } \ - } while (0) - - -#define NBYTES (1 << 8) -#define NHALFS (NBYTES / sizeof(short)) -#define NWORDS (NBYTES / sizeof(int)) -#define NDOBLS (NBYTES / sizeof(long long)) - -long long dbuf[NDOBLS] __attribute__((aligned(1 << 12))) = {0}; -int wbuf[NWORDS] __attribute__((aligned(1 << 12))) = {0}; -short hbuf[NHALFS] __attribute__((aligned(1 << 12))) = {0}; -unsigned char bbuf[NBYTES] __attribute__((aligned(1 << 12))) = {0}; - -/* - * We use the C preporcessor to deal with the combinations of types - */ - -#define INIT(BUF, N) \ - void init_##BUF(void) \ - { \ - int i; \ - for (i = 0; i < N; i++) { \ - BUF[i] = i; \ - } \ - } \ - -INIT(bbuf, NBYTES) -INIT(hbuf, NHALFS) -INIT(wbuf, NWORDS) -INIT(dbuf, NDOBLS) - -/* - * Macros for performing circular load - * RES result - * ADDR address - * START start address of buffer - * LEN length of buffer (in bytes) - * INC address increment (in bytes for IMM, elements for REG) - */ -#define CIRC_LOAD_IMM(SIZE, RES, ADDR, START, LEN, INC) \ - __asm__( \ - "r4 = %3\n\t" \ - "m0 = r4\n\t" \ - "cs0 = %2\n\t" \ - "%0 = mem" #SIZE "(%1++#" #INC ":circ(M0))\n\t" \ - : "=r"(RES), "+r"(ADDR) \ - : "r"(START), "r"(LEN) \ - : "r4", "m0", "cs0") -#define CIRC_LOAD_IMM_b(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_IMM(b, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_IMM_ub(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_IMM(ub, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_IMM_h(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_IMM(h, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_IMM_uh(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_IMM(uh, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_IMM_w(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_IMM(w, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_IMM_d(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_IMM(d, RES, ADDR, START, LEN, INC) - -/* - * The mreg has the following pieces - * mreg[31:28] increment[10:7] - * mreg[27:24] K value (used Hexagon v3 and earlier) - * mreg[23:17] increment[6:0] - * mreg[16:0] circular buffer length - */ -static int build_mreg(int inc, int K, int len) -{ - return ((inc & 0x780) << 21) | - ((K & 0xf) << 24) | - ((inc & 0x7f) << 17) | - (len & 0x1ffff); -} - -#define CIRC_LOAD_REG(SIZE, RES, ADDR, START, LEN, INC) \ - __asm__( \ - "r4 = %2\n\t" \ - "m1 = r4\n\t" \ - "cs1 = %3\n\t" \ - "%0 = mem" #SIZE "(%1++I:circ(M1))\n\t" \ - : "=r"(RES), "+r"(ADDR) \ - : "r"(build_mreg((INC), 0, (LEN))), \ - "r"(START) \ - : "r4", "m1", "cs1") -#define CIRC_LOAD_REG_b(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_REG(b, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_REG_ub(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_REG(ub, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_REG_h(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_REG(h, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_REG_uh(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_REG(uh, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_REG_w(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_REG(w, RES, ADDR, START, LEN, INC) -#define CIRC_LOAD_REG_d(RES, ADDR, START, LEN, INC) \ - CIRC_LOAD_REG(d, RES, ADDR, START, LEN, INC) - -/* - * Macros for performing circular store - * VAL value to store - * ADDR address - * START start address of buffer - * LEN length of buffer (in bytes) - * INC address increment (in bytes for IMM, elements for REG) - */ -#define CIRC_STORE_IMM(SIZE, PART, VAL, ADDR, START, LEN, INC) \ - __asm__( \ - "r4 = %3\n\t" \ - "m0 = r4\n\t" \ - "cs0 = %1\n\t" \ - "mem" #SIZE "(%0++#" #INC ":circ(M0)) = %2" PART "\n\t" \ - : "+r"(ADDR) \ - : "r"(START), "r"(VAL), "r"(LEN) \ - : "r4", "m0", "cs0", "memory") -#define CIRC_STORE_IMM_b(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_IMM(b, "", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_IMM_h(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_IMM(h, "", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_IMM_f(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_IMM(h, ".H", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_IMM_w(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_IMM(w, "", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_IMM_d(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_IMM(d, "", VAL, ADDR, START, LEN, INC) - -#define CIRC_STORE_NEW_IMM(SIZE, VAL, ADDR, START, LEN, INC) \ - __asm__( \ - "r4 = %3\n\t" \ - "m0 = r4\n\t" \ - "cs0 = %1\n\t" \ - "{\n\t" \ - " r5 = %2\n\t" \ - " mem" #SIZE "(%0++#" #INC ":circ(M0)) = r5.new\n\t" \ - "}\n\t" \ - : "+r"(ADDR) \ - : "r"(START), "r"(VAL), "r"(LEN) \ - : "r4", "r5", "m0", "cs0", "memory") -#define CIRC_STORE_IMM_bnew(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_NEW_IMM(b, VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_IMM_hnew(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_NEW_IMM(h, VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_IMM_wnew(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_NEW_IMM(w, VAL, ADDR, START, LEN, INC) - -#define CIRC_STORE_REG(SIZE, PART, VAL, ADDR, START, LEN, INC) \ - __asm__( \ - "r4 = %1\n\t" \ - "m1 = r4\n\t" \ - "cs1 = %2\n\t" \ - "mem" #SIZE "(%0++I:circ(M1)) = %3" PART "\n\t" \ - : "+r"(ADDR) \ - : "r"(build_mreg((INC), 0, (LEN))), \ - "r"(START), \ - "r"(VAL) \ - : "r4", "m1", "cs1", "memory") -#define CIRC_STORE_REG_b(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_REG(b, "", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_REG_h(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_REG(h, "", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_REG_f(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_REG(h, ".H", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_REG_w(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_REG(w, "", VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_REG_d(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_REG(d, "", VAL, ADDR, START, LEN, INC) - -#define CIRC_STORE_NEW_REG(SIZE, VAL, ADDR, START, LEN, INC) \ - __asm__( \ - "r4 = %1\n\t" \ - "m1 = r4\n\t" \ - "cs1 = %2\n\t" \ - "{\n\t" \ - " r5 = %3\n\t" \ - " mem" #SIZE "(%0++I:circ(M1)) = r5.new\n\t" \ - "}\n\t" \ - : "+r"(ADDR) \ - : "r"(build_mreg((INC), 0, (LEN))), \ - "r"(START), \ - "r"(VAL) \ - : "r4", "r5", "m1", "cs1", "memory") -#define CIRC_STORE_REG_bnew(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_NEW_REG(b, VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_REG_hnew(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_NEW_REG(h, VAL, ADDR, START, LEN, INC) -#define CIRC_STORE_REG_wnew(VAL, ADDR, START, LEN, INC) \ - CIRC_STORE_NEW_REG(w, VAL, ADDR, START, LEN, INC) - - -int err; - -/* We'll test increments +1 and -1 */ -void check_load(int i, long long result, int inc, int size) -{ - int expect = (i * inc); - while (expect >= size) { - expect -= size; - } - while (expect < 0) { - expect += size; - } - if (result != expect) { - printf("ERROR(%d): %lld != %d\n", i, result, expect); - err++; - } -} - -#define TEST_LOAD_IMM(SZ, TYPE, BUF, BUFSIZE, INC, FMT) \ -void circ_test_load_imm_##SZ(void) \ -{ \ - TYPE *p = (TYPE *)BUF; \ - int size = 10; \ - int i; \ - for (i = 0; i < BUFSIZE; i++) { \ - TYPE element; \ - CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), (INC)); \ - DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ - i, p, element); \ - check_load(i, element, ((INC) / (int)sizeof(TYPE)), size); \ - } \ - p = (TYPE *)BUF; \ - for (i = 0; i < BUFSIZE; i++) { \ - TYPE element; \ - CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), -(INC)); \ - DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ - i, p, element); \ - check_load(i, element, (-(INC) / (int)sizeof(TYPE)), size); \ - } \ -} - -TEST_LOAD_IMM(b, char, bbuf, NBYTES, 1, d) -TEST_LOAD_IMM(ub, unsigned char, bbuf, NBYTES, 1, d) -TEST_LOAD_IMM(h, short, hbuf, NHALFS, 2, d) -TEST_LOAD_IMM(uh, unsigned short, hbuf, NHALFS, 2, d) -TEST_LOAD_IMM(w, int, wbuf, NWORDS, 4, d) -TEST_LOAD_IMM(d, long long, dbuf, NDOBLS, 8, lld) - -#define TEST_LOAD_REG(SZ, TYPE, BUF, BUFSIZE, FMT) \ -void circ_test_load_reg_##SZ(void) \ -{ \ - TYPE *p = (TYPE *)BUF; \ - int size = 13; \ - int i; \ - for (i = 0; i < BUFSIZE; i++) { \ - TYPE element; \ - CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), 1); \ - DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ - i, p, element); \ - check_load(i, element, 1, size); \ - } \ - p = (TYPE *)BUF; \ - for (i = 0; i < BUFSIZE; i++) { \ - TYPE element; \ - CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), -1); \ - DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ - i, p, element); \ - check_load(i, element, -1, size); \ - } \ -} - -TEST_LOAD_REG(b, char, bbuf, NBYTES, d) -TEST_LOAD_REG(ub, unsigned char, bbuf, NBYTES, d) -TEST_LOAD_REG(h, short, hbuf, NHALFS, d) -TEST_LOAD_REG(uh, unsigned short, hbuf, NHALFS, d) -TEST_LOAD_REG(w, int, wbuf, NWORDS, d) -TEST_LOAD_REG(d, long long, dbuf, NDOBLS, lld) - -/* The circular stores will wrap around somewhere inside the buffer */ -#define CIRC_VAL(SZ, TYPE, BUFSIZE) \ -TYPE circ_val_##SZ(int i, int inc, int size) \ -{ \ - int mod = BUFSIZE % size; \ - int elem = i * inc; \ - if (elem < 0) { \ - if (-elem <= size - mod) { \ - return (elem + BUFSIZE - mod); \ - } else { \ - return (elem + BUFSIZE + size - mod); \ - } \ - } else if (elem < mod) {\ - return (elem + BUFSIZE - mod); \ - } else { \ - return (elem + BUFSIZE - size - mod); \ - } \ -} - -CIRC_VAL(b, unsigned char, NBYTES) -CIRC_VAL(h, short, NHALFS) -CIRC_VAL(w, int, NWORDS) -CIRC_VAL(d, long long, NDOBLS) - -/* - * Circular stores should only write to the first "size" elements of the buffer - * the remainder of the elements should have BUF[i] == i - */ -#define CHECK_STORE(SZ, BUF, BUFSIZE, FMT) \ -void check_store_##SZ(int inc, int size) \ -{ \ - int i; \ - for (i = 0; i < size; i++) { \ - DEBUG_PRINTF(#BUF "[%3d] = 0x%02" #FMT ", guess = 0x%02" #FMT "\n", \ - i, BUF[i], circ_val_##SZ(i, inc, size)); \ - if (BUF[i] != circ_val_##SZ(i, inc, size)) { \ - printf("ERROR(%3d): 0x%02" #FMT " != 0x%02" #FMT "\n", \ - i, BUF[i], circ_val_##SZ(i, inc, size)); \ - err++; \ - } \ - } \ - for (i = size; i < BUFSIZE; i++) { \ - if (BUF[i] != i) { \ - printf("ERROR(%3d): 0x%02" #FMT " != 0x%02x\n", i, BUF[i], i); \ - err++; \ - } \ - } \ -} - -CHECK_STORE(b, bbuf, NBYTES, x) -CHECK_STORE(h, hbuf, NHALFS, x) -CHECK_STORE(w, wbuf, NWORDS, x) -CHECK_STORE(d, dbuf, NDOBLS, llx) - -#define CIRC_TEST_STORE_IMM(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT, INC) \ -void circ_test_store_imm_##SZ(void) \ -{ \ - unsigned int size = 27; \ - TYPE *p = BUF; \ - TYPE val = 0; \ - int i; \ - init_##BUF(); \ - for (i = 0; i < BUFSIZE; i++) { \ - CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), INC); \ - val++; \ - } \ - check_store_##CHK(((INC) / (int)sizeof(TYPE)), size); \ - p = BUF; \ - val = 0; \ - init_##BUF(); \ - for (i = 0; i < BUFSIZE; i++) { \ - CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), \ - -(INC)); \ - val++; \ - } \ - check_store_##CHK((-(INC) / (int)sizeof(TYPE)), size); \ -} - -CIRC_TEST_STORE_IMM(b, b, unsigned char, bbuf, NBYTES, 0, 1) -CIRC_TEST_STORE_IMM(h, h, short, hbuf, NHALFS, 0, 2) -CIRC_TEST_STORE_IMM(f, h, short, hbuf, NHALFS, 16, 2) -CIRC_TEST_STORE_IMM(w, w, int, wbuf, NWORDS, 0, 4) -CIRC_TEST_STORE_IMM(d, d, long long, dbuf, NDOBLS, 0, 8) -CIRC_TEST_STORE_IMM(bnew, b, unsigned char, bbuf, NBYTES, 0, 1) -CIRC_TEST_STORE_IMM(hnew, h, short, hbuf, NHALFS, 0, 2) -CIRC_TEST_STORE_IMM(wnew, w, int, wbuf, NWORDS, 0, 4) - -#define CIRC_TEST_STORE_REG(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT) \ -void circ_test_store_reg_##SZ(void) \ -{ \ - TYPE *p = BUF; \ - unsigned int size = 19; \ - TYPE val = 0; \ - int i; \ - init_##BUF(); \ - for (i = 0; i < BUFSIZE; i++) { \ - CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), 1); \ - val++; \ - } \ - check_store_##CHK(1, size); \ - p = BUF; \ - val = 0; \ - init_##BUF(); \ - for (i = 0; i < BUFSIZE; i++) { \ - CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), -1); \ - val++; \ - } \ - check_store_##CHK(-1, size); \ -} - -CIRC_TEST_STORE_REG(b, b, unsigned char, bbuf, NBYTES, 0) -CIRC_TEST_STORE_REG(h, h, short, hbuf, NHALFS, 0) -CIRC_TEST_STORE_REG(f, h, short, hbuf, NHALFS, 16) -CIRC_TEST_STORE_REG(w, w, int, wbuf, NWORDS, 0) -CIRC_TEST_STORE_REG(d, d, long long, dbuf, NDOBLS, 0) -CIRC_TEST_STORE_REG(bnew, b, unsigned char, bbuf, NBYTES, 0) -CIRC_TEST_STORE_REG(hnew, h, short, hbuf, NHALFS, 0) -CIRC_TEST_STORE_REG(wnew, w, int, wbuf, NWORDS, 0) - -/* Test the old scheme used in Hexagon V3 */ -static void circ_test_v3(void) -{ - int *p = wbuf; - int size = 15; - /* set high bit in K to test unsigned extract in fcirc */ - int K = 8; /* 1024 bytes */ - int element; - int i; - - init_wbuf(); - - for (i = 0; i < NWORDS; i++) { - __asm__( - "r4 = %2\n\t" - "m1 = r4\n\t" - "%0 = memw(%1++I:circ(M1))\n\t" - : "=r"(element), "+r"(p) - : "r"(build_mreg(1, K, size * sizeof(int))) - : "r4", "m1"); - DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2d\n", i, p, element); - check_load(i, element, 1, size); - } -} - -int main() -{ - init_bbuf(); - init_hbuf(); - init_wbuf(); - init_dbuf(); - - DEBUG_PRINTF("NBYTES = %d\n", NBYTES); - DEBUG_PRINTF("Address of dbuf = 0x%p\n", dbuf); - DEBUG_PRINTF("Address of wbuf = 0x%p\n", wbuf); - DEBUG_PRINTF("Address of hbuf = 0x%p\n", hbuf); - DEBUG_PRINTF("Address of bbuf = 0x%p\n", bbuf); - - circ_test_load_imm_b(); - circ_test_load_imm_ub(); - circ_test_load_imm_h(); - circ_test_load_imm_uh(); - circ_test_load_imm_w(); - circ_test_load_imm_d(); - - circ_test_load_reg_b(); - circ_test_load_reg_ub(); - circ_test_load_reg_h(); - circ_test_load_reg_uh(); - circ_test_load_reg_w(); - circ_test_load_reg_d(); - - circ_test_store_imm_b(); - circ_test_store_imm_h(); - circ_test_store_imm_f(); - circ_test_store_imm_w(); - circ_test_store_imm_d(); - circ_test_store_imm_bnew(); - circ_test_store_imm_hnew(); - circ_test_store_imm_wnew(); - - circ_test_store_reg_b(); - circ_test_store_reg_h(); - circ_test_store_reg_f(); - circ_test_store_reg_w(); - circ_test_store_reg_d(); - circ_test_store_reg_bnew(); - circ_test_store_reg_hnew(); - circ_test_store_reg_wnew(); - - circ_test_v3(); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/dual_stores.c b/tests/tcg/hexagon/dual_stores.c deleted file mode 100644 index a86a381ab95f..000000000000 --- a/tests/tcg/hexagon/dual_stores.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include - -/* - * Make sure that two stores in the same packet honor proper - * semantics: slot 1 executes first, then slot 0. - * This is important when the addresses overlap. - */ -static inline void dual_stores(int *p, char *q, int x, char y) -{ - asm volatile("{\n\t" - " memw(%0) = %2\n\t" - " memb(%1) = %3\n\t" - "}\n" - :: "r"(p), "r"(q), "r"(x), "r"(y) - : "memory"); -} - -typedef union { - int word; - char byte; -} Dual; - -int err; - -static void check(Dual d, int expect) -{ - if (d.word != expect) { - printf("ERROR: 0x%08x != 0x%08x\n", d.word, expect); - err++; - } -} - -int main() -{ - Dual d; - - d.word = ~0; - dual_stores(&d.word, &d.byte, 0x12345678, 0xff); - check(d, 0x123456ff); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/first.S b/tests/tcg/hexagon/first.S deleted file mode 100644 index e9f2d963ecaa..000000000000 --- a/tests/tcg/hexagon/first.S +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#define SYS_write 64 -#define SYS_exit_group 94 -#define SYS_exit 93 - -#define FD_STDOUT 1 - - .type str,@object - .section .rodata -str: - .string "Hello!\n" - .size str, 8 - -.text -.global _start -_start: - r6 = #SYS_write - r0 = #FD_STDOUT - r1 = ##str - r2 = #7 - trap0(#1) - - r0 = #0 - r6 = #SYS_exit_group - trap0(#1) - -.section ".note.ABI-tag", "a" -.align 4 -.long 1f - 0f /* name length */ -.long 3f - 2f /* data length */ -.long 1 /* note type */ - -/* - * vendor name seems like this should be MUSL but lldb doesn't agree. - */ -0: .asciz "GNU" -1: .align 4 -2: .long 0 /* linux */ - .long 3,0,0 -3: .align 4 diff --git a/tests/tcg/hexagon/float_convs.ref b/tests/tcg/hexagon/float_convs.ref deleted file mode 100644 index a5505c337b77..000000000000 --- a/tests/tcg/hexagon/float_convs.ref +++ /dev/null @@ -1,748 +0,0 @@ -### Rounding to nearest -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -### Rounding upwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -### Rounding downwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -### Rounding to zero -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fc00000) - to double: f64(-nan:0x00ffffffffffffffff) (OK) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(-nan:0x7fa00000) - to double: f64(-nan:0x00ffffffffffffffff) (INVALID) - to int32: -1 (INVALID) - to int64: -1 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) diff --git a/tests/tcg/hexagon/float_madds.ref b/tests/tcg/hexagon/float_madds.ref deleted file mode 100644 index a08c6160574e..000000000000 --- a/tests/tcg/hexagon/float_madds.ref +++ /dev/null @@ -1,768 +0,0 @@ -### Rounding to nearest -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffffffff) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(-nan:0xffffffff) flags=OK (27/1) -op : f32(-nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/0) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=INVALID (28/1) -op : f32(-nan:0x7fa00000) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/2) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/0) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/2) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding upwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffffffff) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe800000000000000p-25:0x337ffff4) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe800000000000000p-50:0x26fffff4) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000200000000000000p-25:0x33000001) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00080000000000000000p-25:0x33000400) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f400000000000000p-24:0x338000fa) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000e00000000000000p-14:0x38800007) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf600000000000000p-24:0x3387fdfb) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000200000000000000p+0:0x3f800001) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d400000000000000p+2:0x409711ea) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458200000000000000p+3:0x4128a2c1) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0600000000000000p+3:0x41100603) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1600000000000000p+15:0x477fe78b) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56200000000000000p+17:0x482de2b1) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0a00000000000000p+31:0x4f7fbf05) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+31:0x4f7fc005) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+32:0x4fffc005) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8a00000000000000p+33:0x507fbfc5) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800a00000000000000p+33:0x507fc005) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab800000000000000p+99:0x71605d5c) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c082a000000000000000p+116:0x79e04150) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(-nan:0xffffffff) flags=OK (27/1) -op : f32(-nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/0) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=INVALID (28/1) -op : f32(-nan:0x7fa00000) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/2) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/0) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/2) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-148:0x00000002) flags=UNDERFLOW INEXACT (32/0) -### Rounding downwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffffffff) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x1.00000000000000000000p-149:0x80000001) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(-nan:0xffffffff) flags=OK (27/1) -op : f32(-nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/0) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=INVALID (28/1) -op : f32(-nan:0x7fa00000) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/2) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/0) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/2) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding to zero -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffffffff) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffffffff) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(-nan:0xffffffff) flags=OK (27/1) -op : f32(-nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/0) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(-nan:0xffffffff) flags=INVALID (28/1) -op : f32(-nan:0x7fa00000) * f32(inf:0x7f800000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (28/2) -op : f32(-nan:0x7fc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/0) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0x7fc00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(-nan:0x7fc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (29/2) -op : f32(-nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-nan:0x7fa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(-nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffffffff) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) diff --git a/tests/tcg/hexagon/fpstuff.c b/tests/tcg/hexagon/fpstuff.c deleted file mode 100644 index 56bf562a4062..000000000000 --- a/tests/tcg/hexagon/fpstuff.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Copyright(c) 2020-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 - * 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 . - */ - -/* - * This test checks various FP operations performed on Hexagon - */ - -#include - -const int FPINVF_BIT = 1; /* Invalid */ -const int FPINVF = 1 << FPINVF_BIT; -const int FPDBZF_BIT = 2; /* Divide by zero */ -const int FPDBZF = 1 << FPDBZF_BIT; -const int FPOVFF_BIT = 3; /* Overflow */ -const int FPOVFF = 1 << FPOVFF_BIT; -const int FPUNFF_BIT = 4; /* Underflow */ -const int FPUNFF = 1 << FPUNFF_BIT; -const int FPINPF_BIT = 5; /* Inexact */ -const int FPINPF = 1 << FPINPF_BIT; - -const int SF_ZERO = 0x00000000; -const int SF_NaN = 0x7fc00000; -const int SF_NaN_special = 0x7f800001; -const int SF_ANY = 0x3f800000; -const int SF_HEX_NAN = 0xffffffff; -const int SF_small_neg = 0xab98fba8; -const int SF_denorm = 0x00000001; -const int SF_random = 0x346001d6; - -const long long DF_QNaN = 0x7ff8000000000000ULL; -const long long DF_SNaN = 0x7ff7000000000000ULL; -const long long DF_ANY = 0x3f80000000000000ULL; -const long long DF_HEX_NAN = 0xffffffffffffffffULL; -const long long DF_small_neg = 0xbd731f7500000000ULL; - -int err; - -#define CLEAR_FPSTATUS \ - "r2 = usr\n\t" \ - "r2 = clrbit(r2, #1)\n\t" \ - "r2 = clrbit(r2, #2)\n\t" \ - "r2 = clrbit(r2, #3)\n\t" \ - "r2 = clrbit(r2, #4)\n\t" \ - "r2 = clrbit(r2, #5)\n\t" \ - "usr = r2\n\t" - -static void check_fpstatus_bit(int usr, int expect, int flag, const char *n) -{ - int bit = 1 << flag; - if ((usr & bit) != (expect & bit)) { - printf("ERROR %s: usr = %d, expect = %d\n", n, - (usr >> flag) & 1, (expect >> flag) & 1); - err++; - } -} - -static void check_fpstatus(int usr, int expect) -{ - check_fpstatus_bit(usr, expect, FPINVF_BIT, "Invalid"); - check_fpstatus_bit(usr, expect, FPDBZF_BIT, "Div by zero"); - check_fpstatus_bit(usr, expect, FPOVFF_BIT, "Overflow"); - check_fpstatus_bit(usr, expect, FPUNFF_BIT, "Underflow"); - check_fpstatus_bit(usr, expect, FPINPF_BIT, "Inexact"); -} - -static void check32(int val, int expect) -{ - if (val != expect) { - printf("ERROR: 0x%x != 0x%x\n", val, expect); - err++; - } -} -static void check64(unsigned long long val, unsigned long long expect) -{ - if (val != expect) { - printf("ERROR: 0x%llx != 0x%llx\n", val, expect); - err++; - } -} - -static void check_compare_exception(void) -{ - int cmp; - int usr; - - /* Check that FP compares are quiet (don't raise any execptions) */ - asm (CLEAR_FPSTATUS - "p0 = sfcmp.eq(%2, %3)\n\t" - "%0 = p0\n\t" - "%1 = usr\n\t" - : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "p0", "usr"); - check32(cmp, 0); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "p0 = sfcmp.gt(%2, %3)\n\t" - "%0 = p0\n\t" - "%1 = usr\n\t" - : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "p0", "usr"); - check32(cmp, 0); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "p0 = sfcmp.ge(%2, %3)\n\t" - "%0 = p0\n\t" - "%1 = usr\n\t" - : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "p0", "usr"); - check32(cmp, 0); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "p0 = dfcmp.eq(%2, %3)\n\t" - "%0 = p0\n\t" - "%1 = usr\n\t" - : "=r"(cmp), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "p0", "usr"); - check32(cmp, 0); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "p0 = dfcmp.gt(%2, %3)\n\t" - "%0 = p0\n\t" - "%1 = usr\n\t" - : "=r"(cmp), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "p0", "usr"); - check32(cmp, 0); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "p0 = dfcmp.ge(%2, %3)\n\t" - "%0 = p0\n\t" - "%1 = usr\n\t" - : "=r"(cmp), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "p0", "usr"); - check32(cmp, 0); - check_fpstatus(usr, 0); -} - -static void check_sfminmax(void) -{ - int minmax; - int usr; - - /* - * Execute sfmin/sfmax instructions with one operand as NaN - * Check that - * Result is the other operand - * Invalid bit in USR is not set - */ - asm (CLEAR_FPSTATUS - "%0 = sfmin(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check64(minmax, SF_ANY); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "%0 = sfmax(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check64(minmax, SF_ANY); - check_fpstatus(usr, 0); - - /* - * Execute sfmin/sfmax instructions with both operands NaN - * Check that - * Result is SF_HEX_NAN - * Invalid bit in USR is set - */ - asm (CLEAR_FPSTATUS - "%0 = sfmin(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_NaN) - : "r2", "usr"); - check64(minmax, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "%0 = sfmax(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_NaN) - : "r2", "usr"); - check64(minmax, SF_HEX_NAN); - check_fpstatus(usr, 0); -} - -static void check_dfminmax(void) -{ - unsigned long long minmax; - int usr; - - /* - * Execute dfmin/dfmax instructions with one operand as SNaN - * Check that - * Result is the other operand - * Invalid bit in USR is set - */ - asm (CLEAR_FPSTATUS - "%0 = dfmin(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_ANY) - : "r2", "usr"); - check64(minmax, DF_ANY); - check_fpstatus(usr, FPINVF); - - asm (CLEAR_FPSTATUS - "%0 = dfmax(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_ANY) - : "r2", "usr"); - check64(minmax, DF_ANY); - check_fpstatus(usr, FPINVF); - - /* - * Execute dfmin/dfmax instructions with one operand as QNaN - * Check that - * Result is the other operand - * No bit in USR is set - */ - asm (CLEAR_FPSTATUS - "%0 = dfmin(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "usr"); - check64(minmax, DF_ANY); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "%0 = dfmax(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "usr"); - check64(minmax, DF_ANY); - check_fpstatus(usr, 0); - - /* - * Execute dfmin/dfmax instructions with both operands SNaN - * Check that - * Result is DF_HEX_NAN - * Invalid bit in USR is set - */ - asm (CLEAR_FPSTATUS - "%0 = dfmin(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_SNaN) - : "r2", "usr"); - check64(minmax, DF_HEX_NAN); - check_fpstatus(usr, FPINVF); - - asm (CLEAR_FPSTATUS - "%0 = dfmax(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_SNaN) - : "r2", "usr"); - check64(minmax, DF_HEX_NAN); - check_fpstatus(usr, FPINVF); - - /* - * Execute dfmin/dfmax instructions with both operands QNaN - * Check that - * Result is DF_HEX_NAN - * No bit in USR is set - */ - asm (CLEAR_FPSTATUS - "%0 = dfmin(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_QNaN) - : "r2", "usr"); - check64(minmax, DF_HEX_NAN); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "%0 = dfmax(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_QNaN) - : "r2", "usr"); - check64(minmax, DF_HEX_NAN); - check_fpstatus(usr, 0); -} - -static void check_sfrecipa(void) -{ - int result; - int usr; - int pred; - - /* - * Check that sfrecipa doesn't set status bits when - * a NaN with bit 22 non-zero is passed - */ - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "p0", "usr"); - check32(result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN) - : "r2", "p0", "usr"); - check32(result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %2)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(SF_NaN) - : "r2", "p0", "usr"); - check32(result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - /* - * Check that sfrecipa doesn't set status bits when - * a NaN with bit 22 zero is passed - */ - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(SF_NaN_special), "r"(SF_ANY) - : "r2", "p0", "usr"); - check32(result, SF_HEX_NAN); - check_fpstatus(usr, FPINVF); - - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN_special) - : "r2", "p0", "usr"); - check32(result, SF_HEX_NAN); - check_fpstatus(usr, FPINVF); - - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %2)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(SF_NaN_special) - : "r2", "p0", "usr"); - check32(result, SF_HEX_NAN); - check_fpstatus(usr, FPINVF); - - /* - * Check that sfrecipa properly sets divid-by-zero - */ - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(0x885dc960), "r"(0x80000000) - : "r2", "p0", "usr"); - check32(result, 0x3f800000); - check_fpstatus(usr, FPDBZF); - - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) : "r"(0x7f800000), "r"(SF_ZERO) - : "r2", "p0", "usr"); - check32(result, 0x3f800000); - check_fpstatus(usr, 0); - - /* - * Check that sfrecipa properly handles denorm - */ - asm (CLEAR_FPSTATUS - "%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = p0\n\t" - : "=r"(result), "=r"(pred) : "r"(SF_denorm), "r"(SF_random) - : "p0", "usr"); - check32(result, 0x6a920001); - check32(pred, 0x80); -} - -static void check_canonical_NaN(void) -{ - int sf_result; - unsigned long long df_result; - int usr; - - /* Check that each FP instruction properly returns SF_HEX_NAN/DF_HEX_NAN */ - asm(CLEAR_FPSTATUS - "%0 = sfadd(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm(CLEAR_FPSTATUS - "%0 = sfsub(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm(CLEAR_FPSTATUS - "%0 = sfmpy(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - sf_result = SF_ZERO; - asm(CLEAR_FPSTATUS - "%0 += sfmpy(%2, %3)\n\t" - "%1 = usr\n\t" - : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - sf_result = SF_ZERO; - asm(CLEAR_FPSTATUS - "p0 = !cmp.eq(r0, r0)\n\t" - "%0 += sfmpy(%2, %3, p0):scale\n\t" - "%1 = usr\n\t" - : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr", "p0"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - sf_result = SF_ZERO; - asm(CLEAR_FPSTATUS - "%0 -= sfmpy(%2, %3)\n\t" - "%1 = usr\n\t" - : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - sf_result = SF_ZERO; - asm(CLEAR_FPSTATUS - "%0 += sfmpy(%2, %3):lib\n\t" - "%1 = usr\n\t" - : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - sf_result = SF_ZERO; - asm(CLEAR_FPSTATUS - "%0 -= sfmpy(%2, %3):lib\n\t" - "%1 = usr\n\t" - : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2sf(%2)\n\t" - "%1 = usr\n\t" - : "=r"(sf_result), "=r"(usr) : "r"(DF_QNaN) - : "r2", "usr"); - check32(sf_result, SF_HEX_NAN); - check_fpstatus(usr, 0); - - asm(CLEAR_FPSTATUS - "%0 = dfadd(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(df_result), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "usr"); - check64(df_result, DF_HEX_NAN); - check_fpstatus(usr, 0); - - asm(CLEAR_FPSTATUS - "%0 = dfsub(%2, %3)\n\t" - "%1 = usr\n\t" - : "=r"(df_result), "=r"(usr) : "r"(DF_QNaN), "r"(DF_ANY) - : "r2", "usr"); - check64(df_result, DF_HEX_NAN); - check_fpstatus(usr, 0); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2df(%2)\n\t" - "%1 = usr\n\t" - : "=r"(df_result), "=r"(usr) : "r"(SF_NaN) - : "r2", "usr"); - check64(df_result, DF_HEX_NAN); - check_fpstatus(usr, 0); -} - -static void check_invsqrta(void) -{ - int result; - int predval; - - asm volatile("%0,p0 = sfinvsqrta(%2)\n\t" - "%1 = p0\n\t" - : "+r"(result), "=r"(predval) - : "r"(0x7f800000) - : "p0"); - check32(result, 0xff800000); - check32(predval, 0x0); -} - -static void check_sffixupn(void) -{ - int result; - - /* Check that sffixupn properly deals with denorm */ - asm volatile("%0 = sffixupn(%1, %2)\n\t" - : "=r"(result) - : "r"(SF_random), "r"(SF_denorm)); - check32(result, 0x246001d6); -} - -static void check_sffixupd(void) -{ - int result; - - /* Check that sffixupd properly deals with denorm */ - asm volatile("%0 = sffixupd(%1, %2)\n\t" - : "=r"(result) - : "r"(SF_denorm), "r"(SF_random)); - check32(result, 0x146001d6); -} - -static void check_float2int_convs() -{ - int res32; - long long res64; - int usr; - - /* - * Check that the various forms of float-to-unsigned - * check sign before rounding - */ - asm(CLEAR_FPSTATUS - "%0 = convert_sf2uw(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(SF_small_neg) - : "r2", "usr"); - check32(res32, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2uw(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(SF_small_neg) - : "r2", "usr"); - check32(res32, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2ud(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(SF_small_neg) - : "r2", "usr"); - check64(res64, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2ud(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(SF_small_neg) - : "r2", "usr"); - check64(res64, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2uw(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(DF_small_neg) - : "r2", "usr"); - check32(res32, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2uw(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(DF_small_neg) - : "r2", "usr"); - check32(res32, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2ud(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(DF_small_neg) - : "r2", "usr"); - check64(res64, 0); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2ud(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(DF_small_neg) - : "r2", "usr"); - check64(res64, 0); - check_fpstatus(usr, FPINVF); - - /* - * Check that the various forms of float-to-signed return -1 for NaN - */ - asm(CLEAR_FPSTATUS - "%0 = convert_sf2w(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(SF_NaN) - : "r2", "usr"); - check32(res32, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2w(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(SF_NaN) - : "r2", "usr"); - check32(res32, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2d(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(SF_NaN) - : "r2", "usr"); - check64(res64, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_sf2d(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(SF_NaN) - : "r2", "usr"); - check64(res64, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2w(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(DF_QNaN) - : "r2", "usr"); - check32(res32, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2w(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res32), "=r"(usr) : "r"(DF_QNaN) - : "r2", "usr"); - check32(res32, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2d(%2)\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(DF_QNaN) - : "r2", "usr"); - check64(res64, -1); - check_fpstatus(usr, FPINVF); - - asm(CLEAR_FPSTATUS - "%0 = convert_df2d(%2):chop\n\t" - "%1 = usr\n\t" - : "=r"(res64), "=r"(usr) : "r"(DF_QNaN) - : "r2", "usr"); - check64(res64, -1); - check_fpstatus(usr, FPINVF); -} - -int main() -{ - check_compare_exception(); - check_sfminmax(); - check_dfminmax(); - check_sfrecipa(); - check_canonical_NaN(); - check_invsqrta(); - check_sffixupn(); - check_sffixupd(); - check_float2int_convs(); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/hex_sigsegv.c b/tests/tcg/hexagon/hex_sigsegv.c deleted file mode 100644 index dc2b349257ce..000000000000 --- a/tests/tcg/hexagon/hex_sigsegv.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright(c) 2021 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 - * 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 . - */ - -/* - * Test the VLIW semantics of two stores in a packet - * - * When a packet has 2 stores, either both commit or neither commit. - * We test this with a packet that does stores to both NULL and a global - * variable, "should_not_change". After the SIGSEGV is caught, we check - * that the "should_not_change" value is the same. - */ - -#include -#include -#include -#include -#include -#include -#include - -typedef unsigned char uint8_t; - -int err; -int segv_caught; - -#define SHOULD_NOT_CHANGE_VAL 5 -int should_not_change = SHOULD_NOT_CHANGE_VAL; - -#define BUF_SIZE 300 -unsigned char buf[BUF_SIZE]; - - -static void __check(const char *filename, int line, int x, int expect) -{ - if (x != expect) { - printf("ERROR %s:%d - %d != %d\n", - filename, line, x, expect); - err++; - } -} - -#define check(x, expect) __check(__FILE__, __LINE__, (x), (expect)) - -static void __chk_error(const char *filename, int line, int ret) -{ - if (ret < 0) { - printf("ERROR %s:%d - %d\n", filename, line, ret); - err++; - } -} - -#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) - -jmp_buf jmp_env; - -static void sig_segv(int sig, siginfo_t *info, void *puc) -{ - check(sig, SIGSEGV); - segv_caught = 1; - longjmp(jmp_env, 1); -} - -int main() -{ - struct sigaction act; - - /* SIGSEGV test */ - act.sa_sigaction = sig_segv; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - chk_error(sigaction(SIGSEGV, &act, NULL)); - if (setjmp(jmp_env) == 0) { - asm volatile("r18 = ##should_not_change\n\t" - "r19 = #0\n\t" - "{\n\t" - " memw(r18) = #7\n\t" - " memw(r19) = #0\n\t" - "}\n\t" - : : : "r18", "r19", "memory"); - } - - act.sa_handler = SIG_DFL; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - chk_error(sigaction(SIGSEGV, &act, NULL)); - - check(segv_caught, 1); - check(should_not_change, SHOULD_NOT_CHANGE_VAL); - - puts(err ? "FAIL" : "PASS"); - return err ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/tests/tcg/hexagon/hvx_histogram.c b/tests/tcg/hexagon/hvx_histogram.c deleted file mode 100644 index 43377a9abb89..000000000000 --- a/tests/tcg/hexagon/hvx_histogram.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright(c) 2021 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 - * 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 . - */ - -#include -#include -#include -#include "hvx_histogram_row.h" - -const int vector_len = 128; -const int width = 275; -const int height = 20; -const int stride = (width + vector_len - 1) & -vector_len; - -int err; - -static uint8_t input[height][stride] __attribute__((aligned(128))) = { -#include "hvx_histogram_input.h" -}; - -static int result[256] __attribute__((aligned(128))); -static int expect[256] __attribute__((aligned(128))); - -static void check(void) -{ - for (int i = 0; i < 256; i++) { - int res = result[i]; - int exp = expect[i]; - if (res != exp) { - printf("ERROR at %3d: 0x%04x != 0x%04x\n", - i, res, exp); - err++; - } - } -} - -static void ref_histogram(uint8_t *src, int stride, int width, int height, - int *hist) -{ - for (int i = 0; i < 256; i++) { - hist[i] = 0; - } - - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - hist[src[i * stride + j]]++; - } - } -} - -static void hvx_histogram(uint8_t *src, int stride, int width, int height, - int *hist) -{ - int n = 8192 / width; - - for (int i = 0; i < 256; i++) { - hist[i] = 0; - } - - for (int i = 0; i < height; i += n) { - int k = height - i > n ? n : height - i; - hvx_histogram_row(src, stride, width, k, hist); - src += n * stride; - } -} - -int main() -{ - ref_histogram(&input[0][0], stride, width, height, expect); - hvx_histogram(&input[0][0], stride, width, height, result); - check(); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/hvx_histogram_input.h b/tests/tcg/hexagon/hvx_histogram_input.h deleted file mode 100644 index 2f9109255ec8..000000000000 --- a/tests/tcg/hexagon/hvx_histogram_input.h +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright(c) 2021 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 - * 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 . - */ - - { 0x26, 0x32, 0x2e, 0x2e, 0x2d, 0x2c, 0x2d, 0x2d, - 0x2c, 0x2e, 0x31, 0x33, 0x36, 0x39, 0x3b, 0x3f, - 0x42, 0x46, 0x4a, 0x4c, 0x51, 0x53, 0x53, 0x54, - 0x56, 0x57, 0x58, 0x57, 0x56, 0x52, 0x51, 0x4f, - 0x4c, 0x49, 0x47, 0x42, 0x3e, 0x3b, 0x38, 0x35, - 0x33, 0x30, 0x2e, 0x2c, 0x2b, 0x2a, 0x2a, 0x28, - 0x28, 0x27, 0x27, 0x28, 0x29, 0x2a, 0x2c, 0x2e, - 0x2f, 0x33, 0x36, 0x38, 0x3c, 0x3d, 0x40, 0x42, - 0x43, 0x42, 0x43, 0x44, 0x43, 0x41, 0x40, 0x3b, - 0x3b, 0x3a, 0x38, 0x35, 0x32, 0x2f, 0x2c, 0x29, - 0x27, 0x26, 0x23, 0x21, 0x1e, 0x1c, 0x1a, 0x19, - 0x17, 0x15, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, - 0x0f, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, - 0x0c, 0x0d, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0d, 0x0c, 0x0f, 0x0e, 0x0f, 0x0f, - 0x0f, 0x10, 0x11, 0x12, 0x14, 0x16, 0x17, 0x19, - 0x1c, 0x1d, 0x21, 0x25, 0x27, 0x29, 0x2b, 0x2f, - 0x31, 0x33, 0x36, 0x38, 0x39, 0x3a, 0x3b, 0x3c, - 0x3c, 0x3d, 0x3e, 0x3e, 0x3c, 0x3b, 0x3a, 0x39, - 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3c, 0x3e, 0x43, - 0x47, 0x4a, 0x4d, 0x51, 0x51, 0x54, 0x56, 0x56, - 0x57, 0x56, 0x53, 0x4f, 0x4b, 0x47, 0x43, 0x41, - 0x3e, 0x3c, 0x3a, 0x37, 0x36, 0x33, 0x32, 0x34, - 0x34, 0x34, 0x34, 0x35, 0x36, 0x39, 0x3d, 0x3d, - 0x3f, 0x40, 0x40, 0x40, 0x40, 0x3e, 0x40, 0x40, - 0x42, 0x44, 0x47, 0x48, 0x4b, 0x4e, 0x56, 0x5c, - 0x62, 0x68, 0x6f, 0x73, 0x76, 0x79, 0x7a, 0x7c, - 0x7e, 0x7c, 0x78, 0x72, 0x6e, 0x69, 0x65, 0x60, - 0x5b, 0x56, 0x52, 0x4d, 0x4a, 0x48, 0x47, 0x46, - 0x44, 0x43, 0x42, 0x41, 0x41, 0x41, 0x40, 0x40, - 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3b, 0x38, 0x37, - 0x36, 0x35, 0x36, 0x35, 0x36, 0x37, 0x38, 0x3c, - 0x3d, 0x3f, 0x42, 0x44, 0x46, 0x48, 0x4b, 0x4c, - 0x4e, 0x4e, 0x4d, 0x4c, 0x4a, 0x48, 0x49, 0x49, - 0x4b, 0x4d, 0x4e, }, - { 0x23, 0x2d, 0x29, 0x29, 0x28, 0x28, 0x29, 0x29, - 0x28, 0x2b, 0x2d, 0x2f, 0x32, 0x34, 0x36, 0x3a, - 0x3d, 0x41, 0x44, 0x47, 0x4a, 0x4c, 0x4e, 0x4e, - 0x50, 0x51, 0x51, 0x51, 0x4f, 0x4c, 0x4b, 0x48, - 0x46, 0x44, 0x40, 0x3d, 0x39, 0x36, 0x34, 0x30, - 0x2f, 0x2d, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, - 0x25, 0x24, 0x24, 0x24, 0x26, 0x28, 0x28, 0x2a, - 0x2b, 0x2e, 0x32, 0x34, 0x37, 0x39, 0x3b, 0x3c, - 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3c, 0x3b, 0x38, - 0x37, 0x35, 0x33, 0x30, 0x2e, 0x2b, 0x27, 0x25, - 0x24, 0x21, 0x20, 0x1d, 0x1b, 0x1a, 0x18, 0x16, - 0x15, 0x14, 0x13, 0x12, 0x10, 0x11, 0x10, 0x0e, - 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, - 0x0b, 0x0b, 0x0c, 0x0b, 0x0b, 0x09, 0x0a, 0x0b, - 0x0b, 0x0a, 0x0a, 0x0c, 0x0c, 0x0c, 0x0d, 0x0e, - 0x0e, 0x0f, 0x0f, 0x11, 0x12, 0x15, 0x15, 0x17, - 0x1a, 0x1c, 0x1f, 0x22, 0x25, 0x26, 0x29, 0x2a, - 0x2d, 0x30, 0x33, 0x34, 0x35, 0x35, 0x37, 0x37, - 0x39, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x36, 0x37, - 0x35, 0x36, 0x35, 0x35, 0x36, 0x37, 0x3a, 0x3e, - 0x40, 0x43, 0x48, 0x49, 0x4b, 0x4c, 0x4d, 0x4e, - 0x4f, 0x4f, 0x4c, 0x48, 0x45, 0x41, 0x3e, 0x3b, - 0x3a, 0x37, 0x36, 0x33, 0x32, 0x31, 0x30, 0x31, - 0x32, 0x31, 0x31, 0x31, 0x31, 0x34, 0x37, 0x38, - 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3b, 0x3d, 0x3e, - 0x3f, 0x40, 0x43, 0x44, 0x47, 0x4b, 0x4f, 0x56, - 0x5a, 0x60, 0x66, 0x69, 0x6a, 0x6e, 0x71, 0x72, - 0x73, 0x72, 0x6d, 0x69, 0x66, 0x60, 0x5c, 0x59, - 0x54, 0x50, 0x4d, 0x48, 0x46, 0x44, 0x44, 0x43, - 0x42, 0x41, 0x41, 0x40, 0x3f, 0x3f, 0x3e, 0x3d, - 0x3d, 0x3d, 0x3c, 0x3a, 0x39, 0x38, 0x35, 0x35, - 0x34, 0x34, 0x35, 0x34, 0x35, 0x36, 0x39, 0x3c, - 0x3d, 0x3e, 0x41, 0x43, 0x44, 0x46, 0x48, 0x49, - 0x4a, 0x49, 0x48, 0x47, 0x45, 0x43, 0x43, 0x44, - 0x45, 0x47, 0x48, }, - { 0x23, 0x2d, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x2a, - 0x29, 0x2c, 0x2d, 0x2f, 0x32, 0x34, 0x36, 0x3a, - 0x3d, 0x40, 0x44, 0x48, 0x4a, 0x4c, 0x4e, 0x4e, - 0x50, 0x51, 0x51, 0x51, 0x4f, 0x4c, 0x4b, 0x48, - 0x46, 0x44, 0x40, 0x3d, 0x39, 0x36, 0x34, 0x30, - 0x2f, 0x2d, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, - 0x25, 0x24, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, - 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x39, 0x3b, 0x3c, - 0x3d, 0x3e, 0x3e, 0x3d, 0x3e, 0x3c, 0x3c, 0x3a, - 0x37, 0x35, 0x33, 0x30, 0x2f, 0x2b, 0x28, 0x26, - 0x24, 0x21, 0x20, 0x1e, 0x1c, 0x1b, 0x18, 0x17, - 0x16, 0x14, 0x13, 0x12, 0x10, 0x10, 0x0f, 0x0e, - 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, - 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0c, - 0x0c, 0x0b, 0x0b, 0x0c, 0x0d, 0x0c, 0x0e, 0x0e, - 0x0e, 0x0f, 0x11, 0x11, 0x13, 0x14, 0x16, 0x18, - 0x1a, 0x1d, 0x1f, 0x22, 0x25, 0x26, 0x29, 0x2b, - 0x2d, 0x31, 0x33, 0x34, 0x36, 0x37, 0x38, 0x38, - 0x39, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x37, 0x37, - 0x35, 0x36, 0x35, 0x36, 0x35, 0x38, 0x3a, 0x3e, - 0x40, 0x41, 0x45, 0x47, 0x49, 0x4a, 0x4c, 0x4d, - 0x4e, 0x4d, 0x4a, 0x47, 0x44, 0x40, 0x3d, 0x3b, - 0x39, 0x37, 0x34, 0x34, 0x32, 0x31, 0x31, 0x33, - 0x32, 0x31, 0x32, 0x33, 0x32, 0x36, 0x38, 0x39, - 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, - 0x41, 0x42, 0x43, 0x45, 0x48, 0x4c, 0x50, 0x56, - 0x5b, 0x5f, 0x62, 0x67, 0x69, 0x6c, 0x6e, 0x6e, - 0x70, 0x6f, 0x6b, 0x67, 0x63, 0x5e, 0x5b, 0x58, - 0x54, 0x51, 0x4e, 0x4a, 0x48, 0x46, 0x46, 0x46, - 0x45, 0x46, 0x44, 0x43, 0x44, 0x43, 0x42, 0x42, - 0x41, 0x40, 0x3f, 0x3e, 0x3c, 0x3b, 0x3a, 0x39, - 0x39, 0x39, 0x38, 0x37, 0x37, 0x3a, 0x3e, 0x40, - 0x42, 0x43, 0x47, 0x47, 0x48, 0x4a, 0x4b, 0x4c, - 0x4c, 0x4b, 0x4a, 0x48, 0x46, 0x44, 0x43, 0x45, - 0x45, 0x46, 0x47, }, - { 0x21, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, - 0x28, 0x2a, 0x2d, 0x30, 0x32, 0x34, 0x37, 0x3a, - 0x3c, 0x40, 0x44, 0x48, 0x4a, 0x4c, 0x4e, 0x4e, - 0x50, 0x51, 0x52, 0x51, 0x4f, 0x4b, 0x4b, 0x48, - 0x45, 0x43, 0x3f, 0x3c, 0x39, 0x36, 0x33, 0x30, - 0x2f, 0x2d, 0x2b, 0x2a, 0x28, 0x27, 0x26, 0x25, - 0x24, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2d, 0x31, 0x34, 0x37, 0x39, 0x3b, 0x3c, - 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3d, 0x3c, 0x3a, - 0x37, 0x35, 0x33, 0x30, 0x2f, 0x2b, 0x28, 0x26, - 0x25, 0x21, 0x20, 0x1e, 0x1c, 0x19, 0x19, 0x18, - 0x17, 0x15, 0x15, 0x12, 0x11, 0x11, 0x11, 0x0f, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, - 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0f, 0x10, 0x11, 0x13, 0x13, 0x15, 0x16, 0x18, - 0x1a, 0x1c, 0x1f, 0x22, 0x25, 0x28, 0x29, 0x2d, - 0x2f, 0x32, 0x34, 0x35, 0x36, 0x37, 0x38, 0x38, - 0x39, 0x3a, 0x39, 0x39, 0x37, 0x36, 0x37, 0x36, - 0x35, 0x35, 0x37, 0x35, 0x36, 0x37, 0x3a, 0x3d, - 0x3e, 0x41, 0x43, 0x46, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x49, 0x47, 0x45, 0x42, 0x3f, 0x3d, 0x3b, - 0x3a, 0x38, 0x36, 0x34, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x31, 0x33, 0x32, 0x34, 0x37, 0x38, 0x38, - 0x3a, 0x3b, 0x3d, 0x3d, 0x3d, 0x3e, 0x3f, 0x41, - 0x42, 0x44, 0x44, 0x46, 0x49, 0x4d, 0x50, 0x54, - 0x58, 0x5c, 0x61, 0x63, 0x65, 0x69, 0x6a, 0x6c, - 0x6d, 0x6c, 0x68, 0x64, 0x61, 0x5c, 0x59, 0x57, - 0x53, 0x51, 0x4f, 0x4c, 0x4a, 0x48, 0x48, 0x49, - 0x49, 0x48, 0x48, 0x48, 0x47, 0x47, 0x46, 0x46, - 0x45, 0x44, 0x42, 0x41, 0x3f, 0x3e, 0x3c, 0x3c, - 0x3c, 0x3d, 0x3c, 0x3c, 0x3c, 0x3e, 0x41, 0x43, - 0x46, 0x48, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4e, - 0x4e, 0x4d, 0x4b, 0x49, 0x47, 0x44, 0x44, 0x45, - 0x45, 0x45, 0x46, }, - { 0x22, 0x2b, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, - 0x28, 0x2a, 0x2c, 0x2f, 0x30, 0x34, 0x37, 0x3b, - 0x3d, 0x41, 0x45, 0x48, 0x4a, 0x4c, 0x4e, 0x4e, - 0x50, 0x51, 0x52, 0x51, 0x4f, 0x4b, 0x4b, 0x47, - 0x45, 0x43, 0x3f, 0x3c, 0x39, 0x36, 0x33, 0x30, - 0x2f, 0x2d, 0x2b, 0x2a, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2e, 0x31, 0x34, 0x37, 0x39, 0x3a, 0x3b, - 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3d, 0x3c, 0x3a, - 0x38, 0x36, 0x34, 0x31, 0x2e, 0x2c, 0x29, 0x26, - 0x25, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x19, 0x18, - 0x16, 0x15, 0x14, 0x12, 0x10, 0x11, 0x11, 0x0f, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0c, 0x0d, 0x0c, - 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, - 0x0f, 0x10, 0x11, 0x13, 0x13, 0x15, 0x15, 0x18, - 0x19, 0x1d, 0x1f, 0x21, 0x24, 0x27, 0x2a, 0x2c, - 0x30, 0x33, 0x35, 0x36, 0x37, 0x38, 0x39, 0x39, - 0x3a, 0x3a, 0x39, 0x39, 0x37, 0x36, 0x37, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x39, 0x3a, - 0x3d, 0x3e, 0x41, 0x43, 0x43, 0x45, 0x46, 0x46, - 0x47, 0x46, 0x44, 0x42, 0x40, 0x3d, 0x3a, 0x39, - 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3c, 0x3c, 0x3e, 0x3e, 0x3e, 0x41, 0x43, - 0x44, 0x45, 0x46, 0x48, 0x49, 0x4c, 0x51, 0x54, - 0x56, 0x5a, 0x5f, 0x61, 0x63, 0x65, 0x67, 0x69, - 0x6a, 0x69, 0x67, 0x61, 0x5f, 0x5b, 0x58, 0x56, - 0x54, 0x51, 0x50, 0x4e, 0x4c, 0x4a, 0x4b, 0x4c, - 0x4c, 0x4b, 0x4b, 0x4b, 0x4b, 0x49, 0x4a, 0x49, - 0x49, 0x48, 0x46, 0x44, 0x42, 0x41, 0x40, 0x3f, - 0x3f, 0x40, 0x40, 0x40, 0x40, 0x42, 0x46, 0x49, - 0x4b, 0x4c, 0x4f, 0x4f, 0x50, 0x52, 0x51, 0x51, - 0x50, 0x4f, 0x4c, 0x4a, 0x48, 0x46, 0x45, 0x44, - 0x44, 0x45, 0x46, }, - { 0x21, 0x2a, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x29, 0x2d, 0x2f, 0x31, 0x34, 0x37, 0x3b, - 0x3e, 0x41, 0x45, 0x48, 0x4a, 0x4c, 0x4e, 0x4e, - 0x50, 0x51, 0x52, 0x51, 0x4f, 0x4b, 0x4b, 0x48, - 0x45, 0x43, 0x3f, 0x3c, 0x39, 0x36, 0x33, 0x2f, - 0x2f, 0x2d, 0x2a, 0x2a, 0x27, 0x26, 0x25, 0x24, - 0x22, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2f, 0x31, 0x34, 0x37, 0x39, 0x3a, 0x3c, - 0x3d, 0x3e, 0x3f, 0x40, 0x3f, 0x3d, 0x3d, 0x3a, - 0x38, 0x36, 0x34, 0x31, 0x2e, 0x2c, 0x29, 0x26, - 0x25, 0x22, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x18, - 0x16, 0x14, 0x14, 0x13, 0x11, 0x11, 0x11, 0x0f, - 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, - 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0f, 0x10, 0x13, 0x13, 0x14, 0x15, 0x17, 0x19, - 0x1a, 0x1d, 0x1f, 0x22, 0x25, 0x27, 0x2a, 0x2e, - 0x31, 0x33, 0x35, 0x38, 0x39, 0x3a, 0x3b, 0x3b, - 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x38, 0x37, - 0x36, 0x36, 0x37, 0x36, 0x37, 0x38, 0x38, 0x3a, - 0x3b, 0x3e, 0x40, 0x40, 0x41, 0x42, 0x43, 0x42, - 0x43, 0x42, 0x40, 0x40, 0x3f, 0x3c, 0x3b, 0x39, - 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x33, - 0x32, 0x32, 0x34, 0x35, 0x35, 0x36, 0x39, 0x39, - 0x3a, 0x3c, 0x3c, 0x3f, 0x40, 0x41, 0x43, 0x45, - 0x45, 0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x50, 0x53, - 0x56, 0x59, 0x5c, 0x5f, 0x60, 0x65, 0x64, 0x66, - 0x68, 0x66, 0x64, 0x61, 0x5e, 0x5a, 0x59, 0x56, - 0x54, 0x52, 0x51, 0x50, 0x4e, 0x4c, 0x4d, 0x4f, - 0x4f, 0x4f, 0x50, 0x50, 0x4f, 0x4f, 0x4e, 0x4d, - 0x4c, 0x4b, 0x49, 0x47, 0x45, 0x44, 0x43, 0x43, - 0x42, 0x43, 0x44, 0x44, 0x46, 0x47, 0x49, 0x4d, - 0x4f, 0x51, 0x53, 0x54, 0x53, 0x54, 0x54, 0x53, - 0x53, 0x51, 0x4e, 0x4b, 0x4a, 0x47, 0x45, 0x44, - 0x44, 0x45, 0x46, }, - { 0x20, 0x28, 0x26, 0x26, 0x25, 0x24, 0x27, 0x27, - 0x27, 0x29, 0x2c, 0x2e, 0x31, 0x34, 0x37, 0x3b, - 0x3e, 0x41, 0x45, 0x48, 0x4a, 0x4c, 0x4e, 0x4e, - 0x50, 0x51, 0x52, 0x51, 0x4f, 0x4b, 0x4a, 0x49, - 0x45, 0x43, 0x3f, 0x3c, 0x3a, 0x36, 0x33, 0x30, - 0x2f, 0x2d, 0x2a, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2e, 0x31, 0x34, 0x37, 0x39, 0x3b, 0x3c, - 0x3d, 0x3e, 0x3f, 0x40, 0x3e, 0x3d, 0x3d, 0x3a, - 0x38, 0x36, 0x34, 0x31, 0x2f, 0x2c, 0x29, 0x27, - 0x25, 0x21, 0x21, 0x1f, 0x1c, 0x1d, 0x19, 0x18, - 0x16, 0x15, 0x15, 0x13, 0x12, 0x11, 0x11, 0x0f, - 0x0f, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0f, 0x10, - 0x10, 0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x1a, - 0x1c, 0x1d, 0x20, 0x22, 0x25, 0x27, 0x2a, 0x2e, - 0x30, 0x34, 0x38, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, - 0x3c, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, - 0x36, 0x36, 0x38, 0x37, 0x37, 0x37, 0x38, 0x3a, - 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x40, 0x40, - 0x42, 0x40, 0x3f, 0x3e, 0x3d, 0x3b, 0x3a, 0x39, - 0x37, 0x36, 0x36, 0x35, 0x34, 0x34, 0x33, 0x33, - 0x33, 0x34, 0x35, 0x35, 0x35, 0x36, 0x38, 0x39, - 0x3a, 0x3b, 0x3d, 0x3f, 0x42, 0x43, 0x45, 0x45, - 0x46, 0x48, 0x49, 0x4b, 0x4b, 0x4d, 0x50, 0x53, - 0x56, 0x57, 0x5a, 0x5c, 0x5e, 0x61, 0x63, 0x65, - 0x66, 0x64, 0x62, 0x5f, 0x5c, 0x59, 0x58, 0x56, - 0x55, 0x54, 0x52, 0x51, 0x50, 0x51, 0x51, 0x52, - 0x52, 0x52, 0x52, 0x52, 0x51, 0x51, 0x51, 0x50, - 0x4f, 0x4e, 0x4c, 0x4a, 0x47, 0x46, 0x45, 0x45, - 0x45, 0x46, 0x46, 0x46, 0x4a, 0x4c, 0x4d, 0x52, - 0x54, 0x56, 0x58, 0x58, 0x56, 0x57, 0x57, 0x56, - 0x55, 0x53, 0x50, 0x4d, 0x49, 0x45, 0x44, 0x44, - 0x43, 0x44, 0x45, }, - { 0x1f, 0x27, 0x24, 0x23, 0x25, 0x24, 0x25, 0x26, - 0x26, 0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, - 0x3d, 0x41, 0x45, 0x48, 0x4b, 0x4d, 0x4f, 0x4e, - 0x50, 0x51, 0x52, 0x50, 0x4f, 0x4b, 0x4a, 0x49, - 0x45, 0x43, 0x3f, 0x3c, 0x3a, 0x36, 0x33, 0x30, - 0x2f, 0x2d, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x25, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3b, 0x3c, - 0x3e, 0x3f, 0x3f, 0x40, 0x3e, 0x3d, 0x3c, 0x3a, - 0x38, 0x36, 0x34, 0x31, 0x30, 0x2c, 0x29, 0x28, - 0x25, 0x23, 0x22, 0x1f, 0x1c, 0x1c, 0x18, 0x18, - 0x16, 0x14, 0x14, 0x13, 0x11, 0x11, 0x11, 0x0f, - 0x0f, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, - 0x0c, 0x0c, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0d, 0x0e, 0x0e, 0x0f, 0x0d, 0x0f, 0x10, 0x10, - 0x10, 0x11, 0x13, 0x14, 0x15, 0x16, 0x19, 0x1a, - 0x1c, 0x1f, 0x20, 0x23, 0x26, 0x28, 0x2a, 0x2e, - 0x31, 0x35, 0x38, 0x39, 0x3a, 0x3c, 0x3d, 0x3d, - 0x3e, 0x3e, 0x3d, 0x3c, 0x3a, 0x3a, 0x39, 0x39, - 0x38, 0x37, 0x38, 0x38, 0x37, 0x38, 0x39, 0x3a, - 0x3c, 0x3c, 0x3d, 0x3e, 0x3f, 0x3f, 0x40, 0x3f, - 0x41, 0x40, 0x3e, 0x3e, 0x3d, 0x3b, 0x3b, 0x39, - 0x37, 0x37, 0x35, 0x36, 0x34, 0x34, 0x34, 0x35, - 0x35, 0x34, 0x34, 0x35, 0x35, 0x37, 0x38, 0x39, - 0x3a, 0x3c, 0x3f, 0x3f, 0x43, 0x43, 0x45, 0x47, - 0x48, 0x48, 0x4a, 0x4b, 0x4e, 0x4d, 0x51, 0x53, - 0x56, 0x58, 0x59, 0x5b, 0x5d, 0x60, 0x62, 0x63, - 0x64, 0x63, 0x61, 0x5e, 0x5c, 0x5a, 0x57, 0x56, - 0x55, 0x54, 0x53, 0x52, 0x51, 0x51, 0x52, 0x52, - 0x54, 0x54, 0x55, 0x55, 0x55, 0x54, 0x54, 0x53, - 0x52, 0x50, 0x4e, 0x4d, 0x4b, 0x4a, 0x48, 0x48, - 0x48, 0x48, 0x4a, 0x4b, 0x4d, 0x4f, 0x52, 0x55, - 0x58, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5a, 0x59, - 0x58, 0x55, 0x51, 0x4e, 0x4a, 0x46, 0x45, 0x44, - 0x44, 0x44, 0x44, }, - { 0x1e, 0x26, 0x23, 0x23, 0x25, 0x24, 0x25, 0x26, - 0x26, 0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, - 0x3e, 0x42, 0x45, 0x48, 0x4b, 0x4d, 0x4f, 0x4f, - 0x50, 0x51, 0x52, 0x50, 0x4f, 0x4b, 0x4a, 0x48, - 0x46, 0x44, 0x3f, 0x3b, 0x39, 0x36, 0x33, 0x30, - 0x2f, 0x2d, 0x2a, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3b, 0x3d, - 0x3e, 0x3f, 0x41, 0x41, 0x40, 0x3e, 0x3d, 0x3b, - 0x38, 0x37, 0x34, 0x32, 0x30, 0x2c, 0x2a, 0x27, - 0x26, 0x23, 0x22, 0x20, 0x1d, 0x1b, 0x1a, 0x19, - 0x17, 0x15, 0x15, 0x13, 0x12, 0x12, 0x11, 0x0f, - 0x11, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0e, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x11, - 0x11, 0x13, 0x16, 0x15, 0x15, 0x18, 0x1a, 0x1b, - 0x1d, 0x20, 0x22, 0x24, 0x27, 0x29, 0x2c, 0x30, - 0x33, 0x37, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3e, - 0x40, 0x40, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3d, - 0x3d, 0x3f, 0x40, 0x40, 0x3f, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x40, 0x40, 0x3f, 0x3e, 0x3c, 0x3b, - 0x3a, 0x39, 0x37, 0x36, 0x36, 0x35, 0x35, 0x36, - 0x36, 0x35, 0x35, 0x36, 0x36, 0x38, 0x39, 0x39, - 0x3b, 0x3c, 0x3e, 0x40, 0x41, 0x43, 0x45, 0x47, - 0x48, 0x48, 0x4b, 0x4c, 0x4d, 0x4f, 0x51, 0x53, - 0x56, 0x56, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x62, - 0x63, 0x63, 0x61, 0x5e, 0x5c, 0x5a, 0x59, 0x57, - 0x56, 0x54, 0x54, 0x53, 0x52, 0x53, 0x53, 0x55, - 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x56, 0x56, - 0x55, 0x53, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x4b, - 0x4b, 0x4c, 0x4d, 0x4e, 0x51, 0x53, 0x55, 0x58, - 0x5b, 0x5c, 0x60, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, - 0x5a, 0x57, 0x53, 0x4f, 0x4b, 0x46, 0x45, 0x44, - 0x44, 0x44, 0x44, }, - { 0x1d, 0x25, 0x22, 0x22, 0x23, 0x23, 0x24, 0x25, - 0x25, 0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, - 0x3e, 0x42, 0x45, 0x48, 0x4b, 0x4d, 0x4f, 0x4f, - 0x50, 0x51, 0x52, 0x50, 0x4f, 0x4b, 0x4a, 0x47, - 0x45, 0x43, 0x3f, 0x3c, 0x38, 0x35, 0x33, 0x30, - 0x2f, 0x2d, 0x2a, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2b, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3c, 0x3d, - 0x3e, 0x3f, 0x40, 0x41, 0x40, 0x3e, 0x3d, 0x3b, - 0x39, 0x36, 0x34, 0x32, 0x30, 0x2d, 0x2a, 0x26, - 0x26, 0x24, 0x22, 0x1f, 0x1d, 0x1c, 0x1a, 0x19, - 0x18, 0x16, 0x15, 0x14, 0x12, 0x12, 0x12, 0x10, - 0x10, 0x0f, 0x0e, 0x10, 0x0e, 0x0e, 0x0d, 0x0c, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0d, 0x0e, - 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x11, 0x12, - 0x13, 0x14, 0x16, 0x16, 0x18, 0x1a, 0x1b, 0x1c, - 0x1e, 0x21, 0x23, 0x25, 0x28, 0x2a, 0x2e, 0x32, - 0x34, 0x38, 0x3a, 0x3c, 0x3d, 0x3f, 0x40, 0x42, - 0x43, 0x43, 0x43, 0x42, 0x40, 0x3e, 0x3e, 0x3c, - 0x3b, 0x3b, 0x3c, 0x3a, 0x3b, 0x3b, 0x3e, 0x3e, - 0x40, 0x3f, 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, - 0x42, 0x41, 0x41, 0x41, 0x40, 0x3e, 0x3d, 0x3c, - 0x3b, 0x3a, 0x39, 0x37, 0x36, 0x35, 0x36, 0x37, - 0x35, 0x36, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x41, 0x44, 0x46, - 0x48, 0x48, 0x4a, 0x4c, 0x4d, 0x4f, 0x51, 0x53, - 0x55, 0x57, 0x59, 0x5a, 0x5b, 0x5e, 0x5f, 0x61, - 0x62, 0x61, 0x60, 0x5e, 0x5c, 0x5a, 0x59, 0x58, - 0x56, 0x55, 0x54, 0x53, 0x53, 0x54, 0x54, 0x55, - 0x57, 0x57, 0x58, 0x59, 0x5a, 0x58, 0x59, 0x58, - 0x57, 0x55, 0x53, 0x52, 0x4f, 0x4e, 0x4d, 0x4d, - 0x4d, 0x4f, 0x51, 0x50, 0x54, 0x56, 0x59, 0x5c, - 0x5f, 0x61, 0x64, 0x64, 0x63, 0x61, 0x5e, 0x5e, - 0x5c, 0x59, 0x54, 0x50, 0x4c, 0x46, 0x45, 0x44, - 0x44, 0x44, 0x44, }, - { 0x1c, 0x24, 0x21, 0x21, 0x21, 0x22, 0x23, 0x23, - 0x25, 0x27, 0x2a, 0x2e, 0x31, 0x33, 0x37, 0x3b, - 0x3e, 0x42, 0x45, 0x48, 0x4b, 0x4c, 0x50, 0x4f, - 0x50, 0x51, 0x52, 0x50, 0x4e, 0x4b, 0x4a, 0x49, - 0x45, 0x42, 0x3f, 0x3c, 0x38, 0x35, 0x33, 0x30, - 0x2f, 0x2d, 0x2a, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2b, 0x2f, 0x32, 0x34, 0x38, 0x39, 0x3c, 0x3d, - 0x3e, 0x3e, 0x40, 0x41, 0x40, 0x3e, 0x3c, 0x3a, - 0x39, 0x37, 0x35, 0x33, 0x30, 0x2d, 0x2b, 0x28, - 0x26, 0x23, 0x23, 0x20, 0x1e, 0x1b, 0x19, 0x19, - 0x17, 0x16, 0x15, 0x14, 0x12, 0x12, 0x11, 0x10, - 0x0f, 0x0e, 0x0e, 0x10, 0x0e, 0x0d, 0x0c, 0x0c, - 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0d, 0x0e, - 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x14, - 0x14, 0x14, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, - 0x20, 0x23, 0x26, 0x27, 0x29, 0x2c, 0x2f, 0x33, - 0x36, 0x38, 0x3b, 0x3e, 0x3e, 0x42, 0x43, 0x46, - 0x46, 0x46, 0x46, 0x44, 0x42, 0x41, 0x3f, 0x3e, - 0x3d, 0x3d, 0x3e, 0x3d, 0x3d, 0x3e, 0x3e, 0x40, - 0x40, 0x40, 0x43, 0x43, 0x42, 0x43, 0x45, 0x43, - 0x43, 0x43, 0x42, 0x42, 0x41, 0x40, 0x40, 0x3e, - 0x3c, 0x3a, 0x3a, 0x38, 0x36, 0x36, 0x36, 0x36, - 0x37, 0x37, 0x36, 0x38, 0x38, 0x39, 0x3b, 0x3b, - 0x3e, 0x3e, 0x3e, 0x40, 0x41, 0x43, 0x45, 0x46, - 0x46, 0x49, 0x4c, 0x4c, 0x4d, 0x4f, 0x51, 0x54, - 0x56, 0x57, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x60, - 0x61, 0x61, 0x60, 0x5f, 0x5c, 0x5a, 0x59, 0x58, - 0x57, 0x57, 0x55, 0x54, 0x53, 0x55, 0x55, 0x58, - 0x58, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, - 0x5a, 0x59, 0x56, 0x54, 0x53, 0x4e, 0x4e, 0x50, - 0x50, 0x51, 0x52, 0x52, 0x57, 0x59, 0x5d, 0x60, - 0x63, 0x63, 0x66, 0x66, 0x66, 0x64, 0x63, 0x61, - 0x60, 0x5b, 0x55, 0x51, 0x4d, 0x48, 0x45, 0x44, - 0x43, 0x43, 0x43, }, - { 0x1b, 0x23, 0x20, 0x21, 0x22, 0x22, 0x23, 0x24, - 0x26, 0x27, 0x2a, 0x2e, 0x31, 0x33, 0x37, 0x3b, - 0x3d, 0x42, 0x46, 0x49, 0x4a, 0x4c, 0x4f, 0x4f, - 0x50, 0x50, 0x52, 0x50, 0x4e, 0x4b, 0x4b, 0x49, - 0x45, 0x42, 0x3e, 0x3c, 0x38, 0x35, 0x33, 0x30, - 0x2f, 0x2d, 0x2a, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2c, 0x2f, 0x32, 0x35, 0x38, 0x3a, 0x3c, 0x3d, - 0x3e, 0x3e, 0x40, 0x41, 0x40, 0x3f, 0x3d, 0x3b, - 0x3a, 0x38, 0x36, 0x33, 0x30, 0x2d, 0x2b, 0x29, - 0x27, 0x24, 0x24, 0x21, 0x1e, 0x1c, 0x1b, 0x1a, - 0x18, 0x17, 0x16, 0x15, 0x13, 0x12, 0x10, 0x0f, - 0x10, 0x0f, 0x0e, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0f, 0x0e, 0x0f, - 0x10, 0x11, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, - 0x15, 0x16, 0x17, 0x1a, 0x1b, 0x1d, 0x1e, 0x20, - 0x21, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x31, 0x35, - 0x37, 0x39, 0x3c, 0x3f, 0x40, 0x43, 0x46, 0x47, - 0x4a, 0x49, 0x48, 0x46, 0x45, 0x43, 0x42, 0x41, - 0x3f, 0x40, 0x3f, 0x3f, 0x40, 0x3f, 0x41, 0x43, - 0x43, 0x43, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x44, 0x43, 0x43, 0x42, 0x42, 0x40, - 0x3e, 0x3d, 0x3c, 0x39, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x36, 0x38, 0x39, 0x39, 0x3a, 0x3c, 0x3d, - 0x3e, 0x3e, 0x3f, 0x41, 0x42, 0x42, 0x43, 0x45, - 0x46, 0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x53, 0x54, - 0x57, 0x58, 0x5a, 0x5c, 0x5b, 0x5e, 0x60, 0x61, - 0x60, 0x60, 0x5f, 0x5f, 0x5d, 0x5b, 0x5b, 0x59, - 0x58, 0x57, 0x56, 0x55, 0x55, 0x55, 0x57, 0x59, - 0x5b, 0x5b, 0x5d, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, - 0x5d, 0x5b, 0x59, 0x56, 0x54, 0x51, 0x51, 0x51, - 0x52, 0x55, 0x56, 0x56, 0x5a, 0x5d, 0x5f, 0x63, - 0x66, 0x68, 0x6b, 0x6b, 0x68, 0x67, 0x66, 0x64, - 0x61, 0x5d, 0x57, 0x52, 0x4f, 0x49, 0x46, 0x45, - 0x43, 0x43, 0x43, }, - { 0x1a, 0x22, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x26, 0x27, 0x2a, 0x2d, 0x31, 0x33, 0x37, 0x3b, - 0x3d, 0x41, 0x46, 0x49, 0x4a, 0x4d, 0x4f, 0x4f, - 0x50, 0x51, 0x52, 0x50, 0x4e, 0x4b, 0x4b, 0x48, - 0x44, 0x42, 0x3e, 0x3c, 0x39, 0x35, 0x33, 0x30, - 0x2f, 0x2d, 0x2a, 0x28, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x27, 0x29, 0x2a, - 0x2d, 0x2f, 0x32, 0x35, 0x39, 0x3a, 0x3c, 0x3d, - 0x3e, 0x3f, 0x40, 0x41, 0x40, 0x3f, 0x3e, 0x3c, - 0x3a, 0x38, 0x36, 0x33, 0x31, 0x2d, 0x2c, 0x29, - 0x27, 0x26, 0x24, 0x21, 0x1f, 0x1d, 0x1c, 0x1a, - 0x19, 0x18, 0x16, 0x15, 0x14, 0x13, 0x12, 0x10, - 0x11, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, - 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, - 0x11, 0x12, 0x12, 0x13, 0x15, 0x15, 0x16, 0x16, - 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1e, 0x1f, 0x21, - 0x22, 0x25, 0x27, 0x2a, 0x2c, 0x2e, 0x33, 0x36, - 0x39, 0x3a, 0x3d, 0x40, 0x41, 0x45, 0x47, 0x4a, - 0x4c, 0x4d, 0x4c, 0x4a, 0x48, 0x45, 0x44, 0x41, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x44, - 0x45, 0x47, 0x47, 0x48, 0x47, 0x48, 0x47, 0x47, - 0x48, 0x48, 0x46, 0x46, 0x46, 0x43, 0x43, 0x41, - 0x3f, 0x3e, 0x3b, 0x39, 0x38, 0x37, 0x37, 0x37, - 0x38, 0x38, 0x37, 0x39, 0x39, 0x3a, 0x3c, 0x3e, - 0x3e, 0x3f, 0x3f, 0x3f, 0x42, 0x43, 0x43, 0x45, - 0x47, 0x48, 0x4b, 0x4c, 0x4e, 0x50, 0x51, 0x54, - 0x56, 0x58, 0x5a, 0x5c, 0x5c, 0x5f, 0x5f, 0x5f, - 0x61, 0x60, 0x5f, 0x5f, 0x5e, 0x5b, 0x5c, 0x5b, - 0x59, 0x59, 0x57, 0x56, 0x55, 0x56, 0x57, 0x59, - 0x5a, 0x5b, 0x5c, 0x5c, 0x5d, 0x5e, 0x5e, 0x5d, - 0x5e, 0x5c, 0x5a, 0x57, 0x55, 0x52, 0x51, 0x52, - 0x53, 0x55, 0x57, 0x58, 0x5c, 0x5e, 0x61, 0x65, - 0x69, 0x6b, 0x6c, 0x6b, 0x6a, 0x69, 0x67, 0x64, - 0x61, 0x5d, 0x59, 0x53, 0x4d, 0x48, 0x46, 0x45, - 0x44, 0x44, 0x43, }, - { 0x1a, 0x21, 0x1e, 0x1f, 0x20, 0x21, 0x23, 0x24, - 0x25, 0x28, 0x2a, 0x2e, 0x31, 0x33, 0x37, 0x3b, - 0x3e, 0x41, 0x46, 0x49, 0x4b, 0x4d, 0x4f, 0x4e, - 0x50, 0x51, 0x51, 0x50, 0x4e, 0x4b, 0x4a, 0x48, - 0x44, 0x42, 0x3e, 0x3c, 0x39, 0x35, 0x32, 0x30, - 0x2f, 0x2d, 0x29, 0x27, 0x27, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, - 0x2c, 0x2f, 0x32, 0x35, 0x38, 0x3b, 0x3c, 0x3e, - 0x3f, 0x3f, 0x40, 0x41, 0x40, 0x3f, 0x3e, 0x3c, - 0x3a, 0x39, 0x36, 0x34, 0x31, 0x2d, 0x2c, 0x29, - 0x27, 0x26, 0x24, 0x21, 0x1f, 0x1d, 0x1c, 0x1a, - 0x19, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x10, - 0x11, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, - 0x11, 0x13, 0x14, 0x14, 0x15, 0x16, 0x17, 0x19, - 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x22, 0x24, - 0x25, 0x27, 0x29, 0x2c, 0x2e, 0x31, 0x35, 0x38, - 0x3a, 0x3d, 0x41, 0x42, 0x45, 0x48, 0x4c, 0x4e, - 0x4f, 0x4f, 0x4f, 0x4d, 0x4b, 0x49, 0x47, 0x47, - 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x46, 0x47, - 0x48, 0x49, 0x4b, 0x4b, 0x4a, 0x4b, 0x4b, 0x4a, - 0x4b, 0x4a, 0x49, 0x49, 0x48, 0x46, 0x46, 0x44, - 0x42, 0x41, 0x3d, 0x3b, 0x3a, 0x38, 0x38, 0x38, - 0x37, 0x37, 0x39, 0x38, 0x3a, 0x3a, 0x3c, 0x3c, - 0x3e, 0x40, 0x40, 0x41, 0x43, 0x43, 0x45, 0x46, - 0x48, 0x49, 0x4b, 0x4e, 0x4f, 0x50, 0x53, 0x55, - 0x57, 0x59, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, - 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5c, 0x5b, 0x5a, - 0x59, 0x58, 0x57, 0x57, 0x56, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x5b, 0x5c, 0x5c, 0x5d, 0x5e, 0x5d, - 0x5c, 0x5b, 0x58, 0x57, 0x54, 0x52, 0x52, 0x53, - 0x54, 0x57, 0x58, 0x58, 0x5b, 0x5e, 0x62, 0x65, - 0x69, 0x6b, 0x6d, 0x6c, 0x6a, 0x69, 0x67, 0x64, - 0x62, 0x5e, 0x59, 0x54, 0x4d, 0x48, 0x47, 0x46, - 0x45, 0x45, 0x44, }, - { 0x1a, 0x21, 0x1e, 0x1f, 0x20, 0x21, 0x23, 0x24, - 0x25, 0x28, 0x2a, 0x2e, 0x31, 0x34, 0x37, 0x3b, - 0x3e, 0x42, 0x47, 0x49, 0x4b, 0x4d, 0x4f, 0x4f, - 0x50, 0x51, 0x51, 0x50, 0x50, 0x4c, 0x4a, 0x47, - 0x44, 0x42, 0x3e, 0x3c, 0x39, 0x35, 0x32, 0x31, - 0x2f, 0x2d, 0x29, 0x27, 0x26, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x25, 0x25, 0x26, 0x27, 0x29, 0x2b, - 0x2c, 0x2f, 0x33, 0x35, 0x38, 0x3a, 0x3c, 0x3e, - 0x40, 0x40, 0x41, 0x42, 0x41, 0x3f, 0x3f, 0x3d, - 0x3b, 0x39, 0x36, 0x33, 0x32, 0x2e, 0x2d, 0x2a, - 0x27, 0x26, 0x25, 0x22, 0x1f, 0x1d, 0x1c, 0x1b, - 0x19, 0x17, 0x17, 0x16, 0x15, 0x14, 0x12, 0x11, - 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x10, 0x11, 0x10, 0x11, 0x11, 0x12, - 0x11, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1b, - 0x1c, 0x1c, 0x1e, 0x20, 0x21, 0x22, 0x23, 0x25, - 0x27, 0x2a, 0x2c, 0x2f, 0x31, 0x35, 0x38, 0x3b, - 0x3d, 0x40, 0x44, 0x47, 0x49, 0x4c, 0x4f, 0x51, - 0x53, 0x53, 0x53, 0x51, 0x50, 0x4e, 0x4c, 0x4b, - 0x4a, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4d, - 0x4e, 0x4e, 0x4f, 0x50, 0x4f, 0x50, 0x51, 0x50, - 0x50, 0x4e, 0x4d, 0x4c, 0x4b, 0x48, 0x48, 0x47, - 0x44, 0x42, 0x3f, 0x3d, 0x3b, 0x3a, 0x39, 0x39, - 0x39, 0x38, 0x39, 0x3b, 0x3a, 0x3c, 0x3e, 0x3d, - 0x40, 0x40, 0x40, 0x42, 0x42, 0x42, 0x45, 0x46, - 0x47, 0x49, 0x4c, 0x4e, 0x50, 0x50, 0x53, 0x56, - 0x58, 0x59, 0x5d, 0x5d, 0x5e, 0x60, 0x61, 0x61, - 0x62, 0x61, 0x60, 0x60, 0x5e, 0x5d, 0x5d, 0x5b, - 0x57, 0x58, 0x56, 0x55, 0x55, 0x56, 0x56, 0x59, - 0x59, 0x58, 0x5a, 0x5a, 0x5a, 0x5c, 0x5c, 0x5c, - 0x5b, 0x5b, 0x58, 0x57, 0x54, 0x53, 0x52, 0x53, - 0x54, 0x57, 0x58, 0x59, 0x5c, 0x5f, 0x63, 0x67, - 0x6b, 0x6d, 0x6e, 0x6e, 0x6b, 0x6a, 0x68, 0x64, - 0x62, 0x5e, 0x58, 0x53, 0x4f, 0x49, 0x47, 0x46, - 0x45, 0x45, 0x44, }, - { 0x19, 0x20, 0x1e, 0x1e, 0x1f, 0x20, 0x22, 0x23, - 0x25, 0x27, 0x2a, 0x2e, 0x31, 0x34, 0x37, 0x3a, - 0x3e, 0x41, 0x46, 0x49, 0x4a, 0x4d, 0x4f, 0x4e, - 0x50, 0x51, 0x51, 0x4f, 0x4f, 0x4d, 0x49, 0x47, - 0x44, 0x42, 0x3e, 0x3c, 0x39, 0x36, 0x32, 0x31, - 0x2f, 0x2d, 0x29, 0x27, 0x26, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x25, 0x25, 0x26, 0x28, 0x29, 0x2b, - 0x2c, 0x2f, 0x33, 0x35, 0x38, 0x3a, 0x3c, 0x3e, - 0x3f, 0x3f, 0x41, 0x42, 0x41, 0x3f, 0x3f, 0x3d, - 0x3c, 0x39, 0x36, 0x33, 0x32, 0x2e, 0x2d, 0x2a, - 0x27, 0x26, 0x25, 0x22, 0x1f, 0x1e, 0x1d, 0x1b, - 0x1a, 0x17, 0x17, 0x17, 0x14, 0x14, 0x12, 0x11, - 0x11, 0x12, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x11, 0x11, 0x11, 0x12, 0x13, 0x14, - 0x14, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1c, 0x1e, - 0x1e, 0x1f, 0x22, 0x23, 0x23, 0x24, 0x25, 0x27, - 0x2a, 0x2d, 0x2f, 0x31, 0x35, 0x38, 0x3a, 0x3e, - 0x41, 0x44, 0x48, 0x4b, 0x4d, 0x51, 0x53, 0x55, - 0x57, 0x57, 0x56, 0x55, 0x54, 0x52, 0x52, 0x50, - 0x4e, 0x50, 0x4e, 0x4d, 0x4d, 0x4d, 0x4f, 0x51, - 0x51, 0x52, 0x54, 0x55, 0x55, 0x55, 0x57, 0x55, - 0x54, 0x53, 0x52, 0x4e, 0x4d, 0x4b, 0x4a, 0x49, - 0x46, 0x44, 0x41, 0x3f, 0x3d, 0x3b, 0x3a, 0x3a, - 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3b, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x44, 0x44, 0x45, 0x47, - 0x49, 0x49, 0x4a, 0x4d, 0x50, 0x51, 0x53, 0x57, - 0x5a, 0x5b, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x62, - 0x63, 0x62, 0x60, 0x60, 0x5e, 0x5c, 0x5c, 0x59, - 0x58, 0x56, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, - 0x56, 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x59, - 0x58, 0x57, 0x56, 0x55, 0x54, 0x52, 0x53, 0x53, - 0x53, 0x56, 0x57, 0x59, 0x5b, 0x5e, 0x62, 0x66, - 0x6a, 0x6c, 0x6d, 0x6e, 0x6b, 0x69, 0x67, 0x64, - 0x61, 0x5d, 0x58, 0x54, 0x50, 0x4a, 0x47, 0x46, - 0x45, 0x45, 0x44, }, - { 0x1a, 0x21, 0x1e, 0x1f, 0x1f, 0x20, 0x22, 0x23, - 0x25, 0x27, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3b, - 0x3d, 0x42, 0x45, 0x49, 0x4a, 0x4d, 0x4e, 0x4e, - 0x51, 0x52, 0x50, 0x4f, 0x4f, 0x4c, 0x49, 0x48, - 0x45, 0x42, 0x3e, 0x3b, 0x39, 0x36, 0x32, 0x32, - 0x2f, 0x2c, 0x2a, 0x28, 0x26, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x25, 0x28, 0x29, 0x2b, - 0x2d, 0x2f, 0x33, 0x35, 0x38, 0x3a, 0x3c, 0x3e, - 0x3f, 0x3f, 0x41, 0x42, 0x41, 0x3f, 0x3e, 0x3c, - 0x3c, 0x3a, 0x37, 0x33, 0x32, 0x2f, 0x2d, 0x2b, - 0x28, 0x26, 0x25, 0x22, 0x20, 0x1e, 0x1d, 0x1b, - 0x1a, 0x17, 0x17, 0x16, 0x14, 0x14, 0x12, 0x11, - 0x12, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, - 0x10, 0x11, 0x12, 0x12, 0x12, 0x13, 0x14, 0x14, - 0x16, 0x18, 0x19, 0x1a, 0x1b, 0x1d, 0x1e, 0x1f, - 0x21, 0x22, 0x23, 0x25, 0x26, 0x26, 0x28, 0x2a, - 0x2c, 0x2e, 0x32, 0x34, 0x39, 0x39, 0x3d, 0x41, - 0x45, 0x47, 0x4c, 0x4e, 0x51, 0x54, 0x56, 0x58, - 0x5b, 0x5c, 0x5a, 0x59, 0x58, 0x56, 0x55, 0x53, - 0x53, 0x52, 0x52, 0x51, 0x52, 0x52, 0x53, 0x55, - 0x57, 0x58, 0x5a, 0x5a, 0x59, 0x5b, 0x59, 0x59, - 0x58, 0x57, 0x55, 0x53, 0x51, 0x4e, 0x4c, 0x4a, - 0x48, 0x46, 0x43, 0x40, 0x3e, 0x3c, 0x3b, 0x3b, - 0x38, 0x39, 0x38, 0x39, 0x3a, 0x3d, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x43, 0x44, 0x45, 0x46, 0x48, - 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x52, 0x54, 0x56, - 0x59, 0x5c, 0x5e, 0x5f, 0x60, 0x62, 0x62, 0x63, - 0x63, 0x63, 0x61, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, - 0x59, 0x56, 0x56, 0x55, 0x54, 0x53, 0x53, 0x54, - 0x55, 0x54, 0x55, 0x55, 0x55, 0x57, 0x58, 0x57, - 0x57, 0x56, 0x55, 0x54, 0x54, 0x52, 0x52, 0x53, - 0x54, 0x55, 0x57, 0x58, 0x5b, 0x5e, 0x62, 0x65, - 0x69, 0x6b, 0x6d, 0x6e, 0x6a, 0x69, 0x67, 0x63, - 0x61, 0x5d, 0x58, 0x54, 0x4f, 0x4b, 0x48, 0x47, - 0x46, 0x45, 0x45, }, - { 0x1a, 0x21, 0x1e, 0x1f, 0x1f, 0x20, 0x22, 0x23, - 0x25, 0x27, 0x2b, 0x2d, 0x31, 0x34, 0x37, 0x3b, - 0x3d, 0x42, 0x45, 0x48, 0x4c, 0x4e, 0x4e, 0x4f, - 0x51, 0x52, 0x50, 0x50, 0x4f, 0x4c, 0x4a, 0x48, - 0x45, 0x42, 0x3f, 0x3b, 0x39, 0x36, 0x32, 0x31, - 0x2f, 0x2c, 0x2a, 0x28, 0x26, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2b, - 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3b, 0x3d, 0x3f, - 0x3f, 0x40, 0x42, 0x43, 0x42, 0x40, 0x3e, 0x3c, - 0x3c, 0x3a, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2c, - 0x2a, 0x27, 0x26, 0x23, 0x20, 0x1e, 0x1d, 0x1c, - 0x1a, 0x18, 0x18, 0x17, 0x15, 0x16, 0x14, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x12, - 0x12, 0x12, 0x13, 0x14, 0x14, 0x14, 0x15, 0x16, - 0x17, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x20, 0x22, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x2a, 0x2c, 0x2c, - 0x2f, 0x32, 0x35, 0x37, 0x3b, 0x3c, 0x41, 0x45, - 0x48, 0x4c, 0x50, 0x52, 0x54, 0x57, 0x5a, 0x5c, - 0x5f, 0x5f, 0x5f, 0x5d, 0x5c, 0x5b, 0x5a, 0x58, - 0x57, 0x57, 0x57, 0x56, 0x56, 0x57, 0x57, 0x5a, - 0x5c, 0x5e, 0x5f, 0x61, 0x5f, 0x5f, 0x5f, 0x5e, - 0x5d, 0x5c, 0x5a, 0x57, 0x55, 0x52, 0x4f, 0x4e, - 0x4a, 0x47, 0x46, 0x42, 0x41, 0x3e, 0x3d, 0x3c, - 0x3b, 0x3a, 0x39, 0x39, 0x3b, 0x3c, 0x3d, 0x3f, - 0x40, 0x42, 0x42, 0x44, 0x45, 0x46, 0x49, 0x49, - 0x4b, 0x4c, 0x4e, 0x4f, 0x51, 0x54, 0x57, 0x58, - 0x5b, 0x5d, 0x61, 0x61, 0x61, 0x63, 0x65, 0x65, - 0x64, 0x64, 0x62, 0x61, 0x60, 0x5e, 0x5d, 0x5c, - 0x59, 0x58, 0x56, 0x54, 0x53, 0x53, 0x53, 0x54, - 0x54, 0x53, 0x53, 0x54, 0x54, 0x54, 0x55, 0x55, - 0x56, 0x55, 0x54, 0x53, 0x53, 0x52, 0x52, 0x53, - 0x55, 0x56, 0x57, 0x58, 0x5b, 0x5e, 0x62, 0x66, - 0x69, 0x6b, 0x6d, 0x6d, 0x6b, 0x69, 0x67, 0x64, - 0x61, 0x5d, 0x58, 0x55, 0x50, 0x4b, 0x48, 0x47, - 0x46, 0x46, 0x46, }, - { 0x1a, 0x20, 0x1e, 0x1f, 0x1f, 0x21, 0x22, 0x23, - 0x25, 0x27, 0x2b, 0x2d, 0x31, 0x34, 0x37, 0x3b, - 0x3d, 0x42, 0x45, 0x48, 0x4c, 0x4e, 0x4f, 0x4f, - 0x51, 0x52, 0x51, 0x50, 0x4e, 0x4b, 0x4a, 0x48, - 0x45, 0x42, 0x3f, 0x3b, 0x38, 0x36, 0x32, 0x31, - 0x2f, 0x2c, 0x2a, 0x28, 0x26, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2b, - 0x2e, 0x30, 0x33, 0x36, 0x39, 0x3b, 0x3d, 0x3f, - 0x3f, 0x40, 0x41, 0x42, 0x41, 0x40, 0x3e, 0x3c, - 0x3c, 0x3a, 0x37, 0x34, 0x33, 0x30, 0x2e, 0x2b, - 0x29, 0x26, 0x24, 0x24, 0x20, 0x1f, 0x1d, 0x1d, - 0x1a, 0x19, 0x17, 0x16, 0x16, 0x16, 0x16, 0x14, - 0x13, 0x12, 0x13, 0x13, 0x13, 0x12, 0x12, 0x13, - 0x13, 0x14, 0x15, 0x15, 0x14, 0x15, 0x16, 0x18, - 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x21, 0x22, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2c, 0x2c, 0x2d, 0x2f, - 0x32, 0x35, 0x37, 0x3a, 0x3c, 0x3e, 0x44, 0x48, - 0x4c, 0x50, 0x54, 0x56, 0x58, 0x5b, 0x5e, 0x60, - 0x61, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5e, - 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x5b, 0x5c, 0x5e, - 0x60, 0x63, 0x64, 0x65, 0x63, 0x62, 0x63, 0x63, - 0x61, 0x60, 0x5e, 0x5b, 0x58, 0x55, 0x51, 0x4f, - 0x4c, 0x4a, 0x47, 0x44, 0x42, 0x41, 0x3e, 0x3c, - 0x3b, 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3e, 0x3f, - 0x40, 0x42, 0x43, 0x45, 0x46, 0x47, 0x49, 0x4a, - 0x4c, 0x4c, 0x4f, 0x51, 0x52, 0x55, 0x58, 0x5b, - 0x5c, 0x5f, 0x61, 0x62, 0x63, 0x64, 0x64, 0x65, - 0x66, 0x65, 0x63, 0x62, 0x5f, 0x5e, 0x5e, 0x5c, - 0x5b, 0x58, 0x56, 0x55, 0x54, 0x53, 0x52, 0x53, - 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x55, 0x55, - 0x55, 0x53, 0x53, 0x53, 0x52, 0x51, 0x52, 0x52, - 0x55, 0x55, 0x58, 0x58, 0x5b, 0x5d, 0x61, 0x65, - 0x68, 0x6a, 0x6c, 0x6b, 0x69, 0x68, 0x67, 0x64, - 0x61, 0x5e, 0x58, 0x54, 0x4f, 0x4b, 0x49, 0x48, - 0x47, 0x46, 0x45, }, - { 0x19, 0x20, 0x1d, 0x1f, 0x1f, 0x20, 0x23, 0x23, - 0x25, 0x27, 0x2b, 0x2d, 0x31, 0x34, 0x37, 0x3b, - 0x3d, 0x42, 0x45, 0x48, 0x4c, 0x4e, 0x4f, 0x4f, - 0x51, 0x52, 0x51, 0x50, 0x4e, 0x4b, 0x4a, 0x48, - 0x44, 0x42, 0x3f, 0x3a, 0x38, 0x36, 0x32, 0x30, - 0x2f, 0x2c, 0x2a, 0x28, 0x26, 0x26, 0x25, 0x24, - 0x23, 0x24, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2b, - 0x2e, 0x30, 0x34, 0x36, 0x39, 0x3b, 0x3d, 0x3f, - 0x3f, 0x40, 0x41, 0x42, 0x41, 0x40, 0x3e, 0x3c, - 0x3c, 0x3a, 0x37, 0x34, 0x33, 0x30, 0x2e, 0x2b, - 0x29, 0x27, 0x25, 0x24, 0x21, 0x1f, 0x1e, 0x1c, - 0x1b, 0x19, 0x17, 0x16, 0x16, 0x16, 0x16, 0x14, - 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x14, 0x15, 0x14, 0x14, 0x14, 0x17, 0x19, - 0x1a, 0x1c, 0x1e, 0x20, 0x21, 0x23, 0x24, 0x26, - 0x29, 0x29, 0x2b, 0x2c, 0x2d, 0x2e, 0x30, 0x31, - 0x34, 0x38, 0x3b, 0x3c, 0x3f, 0x42, 0x47, 0x4c, - 0x50, 0x54, 0x57, 0x5b, 0x5c, 0x5e, 0x62, 0x63, - 0x66, 0x66, 0x66, 0x65, 0x64, 0x63, 0x61, 0x62, - 0x60, 0x60, 0x5f, 0x5e, 0x5e, 0x5f, 0x60, 0x62, - 0x65, 0x67, 0x69, 0x6a, 0x69, 0x68, 0x69, 0x67, - 0x66, 0x64, 0x62, 0x5f, 0x5c, 0x58, 0x54, 0x51, - 0x4e, 0x4b, 0x49, 0x45, 0x43, 0x41, 0x40, 0x3e, - 0x3c, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x41, 0x42, 0x44, 0x46, 0x46, 0x48, 0x49, 0x4b, - 0x4d, 0x50, 0x51, 0x53, 0x55, 0x57, 0x58, 0x5c, - 0x5f, 0x60, 0x63, 0x64, 0x64, 0x65, 0x66, 0x66, - 0x66, 0x65, 0x65, 0x63, 0x61, 0x5f, 0x5e, 0x5c, - 0x5a, 0x58, 0x56, 0x55, 0x54, 0x53, 0x52, 0x52, - 0x53, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, - 0x54, 0x53, 0x53, 0x52, 0x53, 0x51, 0x53, 0x53, - 0x55, 0x57, 0x58, 0x59, 0x5b, 0x5d, 0x62, 0x64, - 0x68, 0x6a, 0x6c, 0x6b, 0x69, 0x68, 0x67, 0x64, - 0x61, 0x5d, 0x57, 0x54, 0x50, 0x4a, 0x48, 0x47, - 0x46, 0x45, 0x45, }, diff --git a/tests/tcg/hexagon/hvx_histogram_row.S b/tests/tcg/hexagon/hvx_histogram_row.S deleted file mode 100644 index 5e42c33145f1..000000000000 --- a/tests/tcg/hexagon/hvx_histogram_row.S +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright(c) 2021 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 - * 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 . - */ - - -/* - * void hvx_histogram_row(uint8_t *src, => r0 - * int stride, => r1 - * int width, => r2 - * int height, => r3 - * int *hist => r4) - */ - .text - .p2align 2 - .global hvx_histogram_row - .type hvx_histogram_row, @function -hvx_histogram_row: - { r2 = lsr(r2, #7) /* size / VLEN */ - r5 = and(r2, #127) /* size % VLEN */ - v1 = #0 - v0 = #0 - } - /* - * Step 1: Clean the whole vector register file - */ - { v3:2 = v1:0 - v5:4 = v1:0 - p0 = cmp.gt(r2, #0) /* P0 = (width / VLEN > 0) */ - p1 = cmp.eq(r5, #0) /* P1 = (width % VLEN == 0) */ - } - { q0 = vsetq(r5) - v7:6 = v1:0 - } - { v9:8 = v1:0 - v11:10 = v1:0 - } - { v13:12 = v1:0 - v15:14 = v1:0 - } - { v17:16 = v1:0 - v19:18 = v1:0 - } - { v21:20 = v1:0 - v23:22 = v1:0 - } - { v25:24 = v1:0 - v27:26 = v1:0 - } - { v29:28 = v1:0 - v31:30 = v1:0 - r10 = add(r0, r1) /* R10 = &src[2 * stride] */ - loop1(.outerloop, r3) - } - - /* - * Step 2: vhist - */ - .falign -.outerloop: - { if (!p0) jump .loopend - loop0(.innerloop, r2) - } - - .falign -.innerloop: - { v12.tmp = vmem(R0++#1) - vhist - }:endloop0 - - .falign -.loopend: - if (p1) jump .skip /* if (width % VLEN == 0) done with current row */ - { v13.tmp = vmem(r0 + #0) - vhist(q0) - } - - .falign -.skip: - { r0 = r10 /* R0 = &src[(i + 1) * stride] */ - r10 = add(r10, r1) /* R10 = &src[(i + 2) * stride] */ - }:endloop1 - - - /* - * Step 3: Sum up the data - */ - { v0.h = vshuff(v0.h) - r10 = ##0x00010001 - } - v1.h = vshuff(v1.h) - { V2.h = vshuff(v2.h) - v0.w = vdmpy(v0.h, r10.h):sat - } - { v3.h = vshuff(v3.h) - v1.w = vdmpy(v1.h, r10.h):sat - } - { v4.h = vshuff(V4.h) - v2.w = vdmpy(v2.h, r10.h):sat - } - { v5.h = vshuff(v5.h) - v3.w = vdmpy(v3.h, r10.h):sat - } - { v6.h = vshuff(v6.h) - v4.w = vdmpy(v4.h, r10.h):sat - } - { v7.h = vshuff(v7.h) - v5.w = vdmpy(v5.h, r10.h):sat - } - { v8.h = vshuff(V8.h) - v6.w = vdmpy(v6.h, r10.h):sat - } - { v9.h = vshuff(V9.h) - v7.w = vdmpy(v7.h, r10.h):sat - } - { v10.h = vshuff(v10.h) - v8.w = vdmpy(v8.h, r10.h):sat - } - { v11.h = vshuff(v11.h) - v9.w = vdmpy(v9.h, r10.h):sat - } - { v12.h = vshuff(v12.h) - v10.w = vdmpy(v10.h, r10.h):sat - } - { v13.h = vshuff(V13.h) - v11.w = vdmpy(v11.h, r10.h):sat - } - { v14.h = vshuff(v14.h) - v12.w = vdmpy(v12.h, r10.h):sat - } - { v15.h = vshuff(v15.h) - v13.w = vdmpy(v13.h, r10.h):sat - } - { v16.h = vshuff(v16.h) - v14.w = vdmpy(v14.h, r10.h):sat - } - { v17.h = vshuff(v17.h) - v15.w = vdmpy(v15.h, r10.h):sat - } - { v18.h = vshuff(v18.h) - v16.w = vdmpy(v16.h, r10.h):sat - } - { v19.h = vshuff(v19.h) - v17.w = vdmpy(v17.h, r10.h):sat - } - { v20.h = vshuff(v20.h) - v18.W = vdmpy(v18.h, r10.h):sat - } - { v21.h = vshuff(v21.h) - v19.w = vdmpy(v19.h, r10.h):sat - } - { v22.h = vshuff(v22.h) - v20.w = vdmpy(v20.h, r10.h):sat - } - { v23.h = vshuff(v23.h) - v21.w = vdmpy(v21.h, r10.h):sat - } - { v24.h = vshuff(v24.h) - v22.w = vdmpy(v22.h, r10.h):sat - } - { v25.h = vshuff(v25.h) - v23.w = vdmpy(v23.h, r10.h):sat - } - { v26.h = vshuff(v26.h) - v24.w = vdmpy(v24.h, r10.h):sat - } - { v27.h = vshuff(V27.h) - v25.w = vdmpy(v25.h, r10.h):sat - } - { v28.h = vshuff(v28.h) - v26.w = vdmpy(v26.h, r10.h):sat - } - { v29.h = vshuff(v29.h) - v27.w = vdmpy(v27.h, r10.h):sat - } - { v30.h = vshuff(v30.h) - v28.w = vdmpy(v28.h, r10.h):sat - } - { v31.h = vshuff(v31.h) - v29.w = vdmpy(v29.h, r10.h):sat - r28 = #32 - } - { vshuff(v1, v0, r28) - v30.w = vdmpy(v30.h, r10.h):sat - } - { vshuff(v3, v2, r28) - v31.w = vdmpy(v31.h, r10.h):sat - } - { vshuff(v5, v4, r28) - v0.w = vadd(v1.w, v0.w) - v2.w = vadd(v3.w, v2.w) - } - { vshuff(v7, v6, r28) - r7 = #64 - } - { vshuff(v9, v8, r28) - v4.w = vadd(v5.w, v4.w) - v6.w = vadd(v7.w, v6.w) - } - vshuff(v11, v10, r28) - { vshuff(v13, v12, r28) - v8.w = vadd(v9.w, v8.w) - v10.w = vadd(v11.w, v10.w) - } - vshuff(v15, v14, r28) - { vshuff(v17, v16, r28) - v12.w = vadd(v13.w, v12.w) - v14.w = vadd(v15.w, v14.w) - } - vshuff(v19, v18, r28) - { vshuff(v21, v20, r28) - v16.w = vadd(v17.w, v16.w) - v18.w = vadd(v19.w, v18.w) - } - vshuff(v23, v22, r28) - { vshuff(v25, v24, r28) - v20.w = vadd(v21.w, v20.w) - v22.w = vadd(v23.w, v22.w) - } - vshuff(v27, v26, r28) - { vshuff(v29, v28, r28) - v24.w = vadd(v25.w, v24.w) - v26.w = vadd(v27.w, v26.w) - } - vshuff(v31, v30, r28) - { v28.w = vadd(v29.w, v28.w) - vshuff(v2, v0, r7) - } - { v30.w = vadd(v31.w, v30.w) - vshuff(v6, v4, r7) - v0.w = vadd(v0.w, v2.w) - } - { vshuff(v10, v8, r7) - v1.tmp = vmem(r4 + #0) /* update hist[0-31] */ - v0.w = vadd(v0.w, v1.w) - vmem(r4++#1) = v0.new - } - { vshuff(v14, v12, r7) - v4.w = vadd(v4.w, v6.w) - v8.w = vadd(v8.w, v10.w) - } - { vshuff(v18, v16, r7) - v1.tmp = vmem(r4 + #0) /* update hist[32-63] */ - v4.w = vadd(v4.w, v1.w) - vmem(r4++#1) = v4.new - } - { vshuff(v22, v20, r7) - v12.w = vadd(v12.w, v14.w) - V16.w = vadd(v16.w, v18.w) - } - { vshuff(v26, v24, r7) - v1.tmp = vmem(r4 + #0) /* update hist[64-95] */ - v8.w = vadd(v8.w, v1.w) - vmem(r4++#1) = v8.new - } - { vshuff(v30, v28, r7) - v1.tmp = vmem(r4 + #0) /* update hist[96-127] */ - v12.w = vadd(v12.w, v1.w) - vmem(r4++#1) = v12.new - } - - { v20.w = vadd(v20.w, v22.w) - v1.tmp = vmem(r4 + #0) /* update hist[128-159] */ - v16.w = vadd(v16.w, v1.w) - vmem(r4++#1) = v16.new - } - { v24.w = vadd(v24.w, v26.w) - v1.tmp = vmem(r4 + #0) /* update hist[160-191] */ - v20.w = vadd(v20.w, v1.w) - vmem(r4++#1) = v20.new - } - { v28.w = vadd(v28.w, v30.w) - v1.tmp = vmem(r4 + #0) /* update hist[192-223] */ - v24.w = vadd(v24.w, v1.w) - vmem(r4++#1) = v24.new - } - { v1.tmp = vmem(r4 + #0) /* update hist[224-255] */ - v28.w = vadd(v28.w, v1.w) - vmem(r4++#1) = v28.new - } - jumpr r31 - .size hvx_histogram_row, .-hvx_histogram_row diff --git a/tests/tcg/hexagon/hvx_histogram_row.h b/tests/tcg/hexagon/hvx_histogram_row.h deleted file mode 100644 index 6a4531a92dac..000000000000 --- a/tests/tcg/hexagon/hvx_histogram_row.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright(c) 2021 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 - * 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 . - */ - -#ifndef HVX_HISTOGRAM_ROW_H -#define HVX_HISTOGRAM_ROW_H - -void hvx_histogram_row(uint8_t *src, int stride, int width, int height, - int *hist); - -#endif diff --git a/tests/tcg/hexagon/hvx_misc.c b/tests/tcg/hexagon/hvx_misc.c deleted file mode 100644 index b896f5897ec5..000000000000 --- a/tests/tcg/hexagon/hvx_misc.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright(c) 2021-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 - * 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 . - */ - -#include -#include -#include -#include -#include - -int err; - -static void __check(int line, int i, int j, uint64_t result, uint64_t expect) -{ - if (result != expect) { - printf("ERROR at line %d: [%d][%d] 0x%016llx != 0x%016llx\n", - line, i, j, result, expect); - err++; - } -} - -#define check(RES, EXP) __check(__LINE__, RES, EXP) - -#define MAX_VEC_SIZE_BYTES 128 - -typedef union { - uint64_t ud[MAX_VEC_SIZE_BYTES / 8]; - int64_t d[MAX_VEC_SIZE_BYTES / 8]; - uint32_t uw[MAX_VEC_SIZE_BYTES / 4]; - int32_t w[MAX_VEC_SIZE_BYTES / 4]; - uint16_t uh[MAX_VEC_SIZE_BYTES / 2]; - int16_t h[MAX_VEC_SIZE_BYTES / 2]; - uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; - int8_t b[MAX_VEC_SIZE_BYTES / 1]; -} MMVector; - -#define BUFSIZE 16 -#define OUTSIZE 16 -#define MASKMOD 3 - -MMVector buffer0[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES))); -MMVector buffer1[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES))); -MMVector mask[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES))); -MMVector output[OUTSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES))); -MMVector expect[OUTSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES))); - -#define CHECK_OUTPUT_FUNC(FIELD, FIELDSZ) \ -static void check_output_##FIELD(int line, size_t num_vectors) \ -{ \ - for (int i = 0; i < num_vectors; i++) { \ - for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \ - __check(line, i, j, output[i].FIELD[j], expect[i].FIELD[j]); \ - } \ - } \ -} - -CHECK_OUTPUT_FUNC(d, 8) -CHECK_OUTPUT_FUNC(w, 4) -CHECK_OUTPUT_FUNC(h, 2) -CHECK_OUTPUT_FUNC(b, 1) - -static void init_buffers(void) -{ - int counter0 = 0; - int counter1 = 17; - for (int i = 0; i < BUFSIZE; i++) { - for (int j = 0; j < MAX_VEC_SIZE_BYTES; j++) { - buffer0[i].b[j] = counter0++; - buffer1[i].b[j] = counter1++; - } - for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { - mask[i].w[j] = (i + j % MASKMOD == 0) ? 0 : 1; - } - } -} - -static void test_load_tmp(void) -{ - void *p0 = buffer0; - void *p1 = buffer1; - void *pout = output; - - for (int i = 0; i < BUFSIZE; i++) { - /* - * Load into v12 as .tmp, then use it in the next packet - * Should get the new value within the same packet and - * the old value in the next packet - */ - asm("v3 = vmem(%0 + #0)\n\t" - "r1 = #1\n\t" - "v12 = vsplat(r1)\n\t" - "{\n\t" - " v12.tmp = vmem(%1 + #0)\n\t" - " v4.w = vadd(v12.w, v3.w)\n\t" - "}\n\t" - "v4.w = vadd(v4.w, v12.w)\n\t" - "vmem(%2 + #0) = v4\n\t" - : : "r"(p0), "r"(p1), "r"(pout) - : "r1", "v12", "v3", "v4", "v6", "memory"); - p0 += sizeof(MMVector); - p1 += sizeof(MMVector); - pout += sizeof(MMVector); - - for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { - expect[i].w[j] = buffer0[i].w[j] + buffer1[i].w[j] + 1; - } - } - - check_output_w(__LINE__, BUFSIZE); -} - -static void test_load_cur(void) -{ - void *p0 = buffer0; - void *pout = output; - - for (int i = 0; i < BUFSIZE; i++) { - asm("{\n\t" - " v2.cur = vmem(%0 + #0)\n\t" - " vmem(%1 + #0) = v2\n\t" - "}\n\t" - : : "r"(p0), "r"(pout) : "v2", "memory"); - p0 += sizeof(MMVector); - pout += sizeof(MMVector); - - for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { - expect[i].uw[j] = buffer0[i].uw[j]; - } - } - - check_output_w(__LINE__, BUFSIZE); -} - -static void test_load_aligned(void) -{ - /* Aligned loads ignore the low bits of the address */ - void *p0 = buffer0; - void *pout = output; - const size_t offset = 13; - - p0 += offset; /* Create an unaligned address */ - asm("v2 = vmem(%0 + #0)\n\t" - "vmem(%1 + #0) = v2\n\t" - : : "r"(p0), "r"(pout) : "v2", "memory"); - - expect[0] = buffer0[0]; - - check_output_w(__LINE__, 1); -} - -static void test_load_unaligned(void) -{ - void *p0 = buffer0; - void *pout = output; - const size_t offset = 12; - - p0 += offset; /* Create an unaligned address */ - asm("v2 = vmemu(%0 + #0)\n\t" - "vmem(%1 + #0) = v2\n\t" - : : "r"(p0), "r"(pout) : "v2", "memory"); - - memcpy(expect, &buffer0[0].ub[offset], sizeof(MMVector)); - - check_output_w(__LINE__, 1); -} - -static void test_store_aligned(void) -{ - /* Aligned stores ignore the low bits of the address */ - void *p0 = buffer0; - void *pout = output; - const size_t offset = 13; - - pout += offset; /* Create an unaligned address */ - asm("v2 = vmem(%0 + #0)\n\t" - "vmem(%1 + #0) = v2\n\t" - : : "r"(p0), "r"(pout) : "v2", "memory"); - - expect[0] = buffer0[0]; - - check_output_w(__LINE__, 1); -} - -static void test_store_unaligned(void) -{ - void *p0 = buffer0; - void *pout = output; - const size_t offset = 12; - - pout += offset; /* Create an unaligned address */ - asm("v2 = vmem(%0 + #0)\n\t" - "vmemu(%1 + #0) = v2\n\t" - : : "r"(p0), "r"(pout) : "v2", "memory"); - - memcpy(expect, buffer0, 2 * sizeof(MMVector)); - memcpy(&expect[0].ub[offset], buffer0, sizeof(MMVector)); - - check_output_w(__LINE__, 2); -} - -static void test_masked_store(bool invert) -{ - void *p0 = buffer0; - void *pmask = mask; - void *pout = output; - - memset(expect, 0xff, sizeof(expect)); - memset(output, 0xff, sizeof(expect)); - - for (int i = 0; i < BUFSIZE; i++) { - if (invert) { - asm("r4 = #0\n\t" - "v4 = vsplat(r4)\n\t" - "v5 = vmem(%0 + #0)\n\t" - "q0 = vcmp.eq(v4.w, v5.w)\n\t" - "v5 = vmem(%1)\n\t" - "if (!q0) vmem(%2) = v5\n\t" /* Inverted test */ - : : "r"(pmask), "r"(p0), "r"(pout) - : "r4", "v4", "v5", "q0", "memory"); - } else { - asm("r4 = #0\n\t" - "v4 = vsplat(r4)\n\t" - "v5 = vmem(%0 + #0)\n\t" - "q0 = vcmp.eq(v4.w, v5.w)\n\t" - "v5 = vmem(%1)\n\t" - "if (q0) vmem(%2) = v5\n\t" /* Non-inverted test */ - : : "r"(pmask), "r"(p0), "r"(pout) - : "r4", "v4", "v5", "q0", "memory"); - } - p0 += sizeof(MMVector); - pmask += sizeof(MMVector); - pout += sizeof(MMVector); - - for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { - if (invert) { - if (i + j % MASKMOD != 0) { - expect[i].w[j] = buffer0[i].w[j]; - } - } else { - if (i + j % MASKMOD == 0) { - expect[i].w[j] = buffer0[i].w[j]; - } - } - } - } - - check_output_w(__LINE__, BUFSIZE); -} - -static void test_new_value_store(void) -{ - void *p0 = buffer0; - void *pout = output; - - asm("{\n\t" - " v2 = vmem(%0 + #0)\n\t" - " vmem(%1 + #0) = v2.new\n\t" - "}\n\t" - : : "r"(p0), "r"(pout) : "v2", "memory"); - - expect[0] = buffer0[0]; - - check_output_w(__LINE__, 1); -} - -static void test_max_temps() -{ - void *p0 = buffer0; - void *pout = output; - - asm("v0 = vmem(%0 + #0)\n\t" - "v1 = vmem(%0 + #1)\n\t" - "v2 = vmem(%0 + #2)\n\t" - "v3 = vmem(%0 + #3)\n\t" - "v4 = vmem(%0 + #4)\n\t" - "{\n\t" - " v1:0.w = vadd(v3:2.w, v1:0.w)\n\t" - " v2.b = vshuffe(v3.b, v2.b)\n\t" - " v3.w = vadd(v1.w, v4.w)\n\t" - " v4.tmp = vmem(%0 + #5)\n\t" - "}\n\t" - "vmem(%1 + #0) = v0\n\t" - "vmem(%1 + #1) = v1\n\t" - "vmem(%1 + #2) = v2\n\t" - "vmem(%1 + #3) = v3\n\t" - "vmem(%1 + #4) = v4\n\t" - : : "r"(p0), "r"(pout) : "memory"); - - /* The first two vectors come from the vadd-pair instruction */ - for (int i = 0; i < MAX_VEC_SIZE_BYTES / 4; i++) { - expect[0].w[i] = buffer0[0].w[i] + buffer0[2].w[i]; - expect[1].w[i] = buffer0[1].w[i] + buffer0[3].w[i]; - } - /* The third vector comes from the vshuffe instruction */ - for (int i = 0; i < MAX_VEC_SIZE_BYTES / 2; i++) { - expect[2].uh[i] = (buffer0[2].uh[i] & 0xff) | - (buffer0[3].uh[i] & 0xff) << 8; - } - /* The fourth vector comes from the vadd-single instruction */ - for (int i = 0; i < MAX_VEC_SIZE_BYTES / 4; i++) { - expect[3].w[i] = buffer0[1].w[i] + buffer0[5].w[i]; - } - /* - * The fifth vector comes from the load to v4 - * make sure the .tmp is dropped - */ - expect[4] = buffer0[4]; - - check_output_b(__LINE__, 5); -} - -#define VEC_OP1(ASM, EL, IN, OUT) \ - asm("v2 = vmem(%0 + #0)\n\t" \ - "v2" #EL " = " #ASM "(v2" #EL ")\n\t" \ - "vmem(%1 + #0) = v2\n\t" \ - : : "r"(IN), "r"(OUT) : "v2", "memory") - -#define VEC_OP2(ASM, EL, IN0, IN1, OUT) \ - asm("v2 = vmem(%0 + #0)\n\t" \ - "v3 = vmem(%1 + #0)\n\t" \ - "v2" #EL " = " #ASM "(v2" #EL ", v3" #EL ")\n\t" \ - "vmem(%2 + #0) = v2\n\t" \ - : : "r"(IN0), "r"(IN1), "r"(OUT) : "v2", "v3", "memory") - -#define TEST_VEC_OP1(NAME, ASM, EL, FIELD, FIELDSZ, OP) \ -static void test_##NAME(void) \ -{ \ - void *pin = buffer0; \ - void *pout = output; \ - for (int i = 0; i < BUFSIZE; i++) { \ - VEC_OP1(ASM, EL, pin, pout); \ - pin += sizeof(MMVector); \ - pout += sizeof(MMVector); \ - } \ - for (int i = 0; i < BUFSIZE; i++) { \ - for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \ - expect[i].FIELD[j] = OP buffer0[i].FIELD[j]; \ - } \ - } \ - check_output_##FIELD(__LINE__, BUFSIZE); \ -} - -#define TEST_VEC_OP2(NAME, ASM, EL, FIELD, FIELDSZ, OP) \ -static void test_##NAME(void) \ -{ \ - void *p0 = buffer0; \ - void *p1 = buffer1; \ - void *pout = output; \ - for (int i = 0; i < BUFSIZE; i++) { \ - VEC_OP2(ASM, EL, p0, p1, pout); \ - p0 += sizeof(MMVector); \ - p1 += sizeof(MMVector); \ - pout += sizeof(MMVector); \ - } \ - for (int i = 0; i < BUFSIZE; i++) { \ - for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \ - expect[i].FIELD[j] = buffer0[i].FIELD[j] OP buffer1[i].FIELD[j]; \ - } \ - } \ - check_output_##FIELD(__LINE__, BUFSIZE); \ -} - -#define THRESHOLD 31 - -#define PRED_OP2(ASM, IN0, IN1, OUT, INV) \ - asm("r4 = #%3\n\t" \ - "v1.b = vsplat(r4)\n\t" \ - "v2 = vmem(%0 + #0)\n\t" \ - "q0 = vcmp.gt(v2.b, v1.b)\n\t" \ - "v3 = vmem(%1 + #0)\n\t" \ - "q1 = vcmp.gt(v3.b, v1.b)\n\t" \ - "q2 = " #ASM "(q0, " INV "q1)\n\t" \ - "r4 = #0xff\n\t" \ - "v1.b = vsplat(r4)\n\t" \ - "if (q2) vmem(%2 + #0) = v1\n\t" \ - : : "r"(IN0), "r"(IN1), "r"(OUT), "i"(THRESHOLD) \ - : "r4", "v1", "v2", "v3", "q0", "q1", "q2", "memory") - -#define TEST_PRED_OP2(NAME, ASM, OP, INV) \ -static void test_##NAME(bool invert) \ -{ \ - void *p0 = buffer0; \ - void *p1 = buffer1; \ - void *pout = output; \ - memset(output, 0, sizeof(expect)); \ - for (int i = 0; i < BUFSIZE; i++) { \ - PRED_OP2(ASM, p0, p1, pout, INV); \ - p0 += sizeof(MMVector); \ - p1 += sizeof(MMVector); \ - pout += sizeof(MMVector); \ - } \ - for (int i = 0; i < BUFSIZE; i++) { \ - for (int j = 0; j < MAX_VEC_SIZE_BYTES; j++) { \ - bool p0 = (buffer0[i].b[j] > THRESHOLD); \ - bool p1 = (buffer1[i].b[j] > THRESHOLD); \ - if (invert) { \ - expect[i].b[j] = (p0 OP !p1) ? 0xff : 0x00; \ - } else { \ - expect[i].b[j] = (p0 OP p1) ? 0xff : 0x00; \ - } \ - } \ - } \ - check_output_b(__LINE__, BUFSIZE); \ -} - -TEST_VEC_OP2(vadd_w, vadd, .w, w, 4, +) -TEST_VEC_OP2(vadd_h, vadd, .h, h, 2, +) -TEST_VEC_OP2(vadd_b, vadd, .b, b, 1, +) -TEST_VEC_OP2(vsub_w, vsub, .w, w, 4, -) -TEST_VEC_OP2(vsub_h, vsub, .h, h, 2, -) -TEST_VEC_OP2(vsub_b, vsub, .b, b, 1, -) -TEST_VEC_OP2(vxor, vxor, , d, 8, ^) -TEST_VEC_OP2(vand, vand, , d, 8, &) -TEST_VEC_OP2(vor, vor, , d, 8, |) -TEST_VEC_OP1(vnot, vnot, , d, 8, ~) - -TEST_PRED_OP2(pred_or, or, |, "") -TEST_PRED_OP2(pred_or_n, or, |, "!") -TEST_PRED_OP2(pred_and, and, &, "") -TEST_PRED_OP2(pred_and_n, and, &, "!") -TEST_PRED_OP2(pred_xor, xor, ^, "") - -static void test_vadduwsat(void) -{ - /* - * Test for saturation by adding two numbers that add to more than UINT_MAX - * and make sure the result saturates to UINT_MAX - */ - const uint32_t x = 0xffff0000; - const uint32_t y = 0x000fffff; - - memset(expect, 0x12, sizeof(MMVector)); - memset(output, 0x34, sizeof(MMVector)); - - asm volatile ("v10 = vsplat(%0)\n\t" - "v11 = vsplat(%1)\n\t" - "v21.uw = vadd(v11.uw, v10.uw):sat\n\t" - "vmem(%2+#0) = v21\n\t" - : /* no outputs */ - : "r"(x), "r"(y), "r"(output) - : "v10", "v11", "v21", "memory"); - - for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { - expect[0].uw[j] = UINT_MAX; - } - - check_output_w(__LINE__, 1); -} - -static void test_vsubuwsat_dv(void) -{ - /* - * Test for saturation by subtracting two numbers where the result is - * negative and make sure the result saturates to zero - * - * vsubuwsat_dv operates on an HVX register pair, so we'll have a - * pair of subtractions - * w - x < 0 - * y - z < 0 - */ - const uint32_t w = 0x000000b7; - const uint32_t x = 0xffffff4e; - const uint32_t y = 0x31fe88e7; - const uint32_t z = 0x7fffff79; - - memset(expect, 0x12, sizeof(MMVector) * 2); - memset(output, 0x34, sizeof(MMVector) * 2); - - asm volatile ("v16 = vsplat(%0)\n\t" - "v17 = vsplat(%1)\n\t" - "v26 = vsplat(%2)\n\t" - "v27 = vsplat(%3)\n\t" - "v25:24.uw = vsub(v17:16.uw, v27:26.uw):sat\n\t" - "vmem(%4+#0) = v24\n\t" - "vmem(%4+#1) = v25\n\t" - : /* no outputs */ - : "r"(w), "r"(y), "r"(x), "r"(z), "r"(output) - : "v16", "v17", "v24", "v25", "v26", "v27", "memory"); - - for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { - expect[0].uw[j] = 0x00000000; - expect[1].uw[j] = 0x00000000; - } - - check_output_w(__LINE__, 2); -} - -int main() -{ - init_buffers(); - - test_load_tmp(); - test_load_cur(); - test_load_aligned(); - test_load_unaligned(); - test_store_aligned(); - test_store_unaligned(); - test_masked_store(false); - test_masked_store(true); - test_new_value_store(); - test_max_temps(); - - test_vadd_w(); - test_vadd_h(); - test_vadd_b(); - test_vsub_w(); - test_vsub_h(); - test_vsub_b(); - test_vxor(); - test_vand(); - test_vor(); - test_vnot(); - - test_pred_or(false); - test_pred_or_n(true); - test_pred_and(false); - test_pred_and_n(true); - test_pred_xor(false); - - test_vadduwsat(); - test_vsubuwsat_dv(); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/load_align.c b/tests/tcg/hexagon/load_align.c deleted file mode 100644 index 12fc9cbd8ffc..000000000000 --- a/tests/tcg/hexagon/load_align.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -/* - * Test load align instructions - * - * Example - * r1:0 = memh_fifo(r1+#0) - * loads a half word from memory, shifts the destination register - * right by one half word and inserts the loaded value into the high - * half word of the destination. - * - * There are 8 addressing modes and byte and half word variants, for a - * total of 16 instructions to test - */ - -#include -#include - -int err; - -char buf[16] __attribute__((aligned(1 << 16))); - -void init_buf(void) -{ - int i; - for (i = 0; i < 16; i++) { - buf[i] = i + 1; - } -} - -void __check(int line, long long result, long long expect) -{ - if (result != expect) { - printf("ERROR at line %d: 0x%016llx != 0x%016llx\n", - line, result, expect); - err++; - } -} - -#define check(RES, EXP) __check(__LINE__, RES, EXP) - -void __checkp(int line, void *p, void *expect) -{ - if (p != expect) { - printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect); - err++; - } -} - -#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP) - -/* - **************************************************************************** - * _io addressing mode (addr + offset) - */ -#define LOAD_io(SZ, RES, ADDR, OFF) \ - __asm__( \ - "%0 = mem" #SZ "_fifo(%1+#" #OFF ")\n\t" \ - : "+r"(RES) \ - : "r"(ADDR)) -#define LOAD_io_b(RES, ADDR, OFF) \ - LOAD_io(b, RES, ADDR, OFF) -#define LOAD_io_h(RES, ADDR, OFF) \ - LOAD_io(h, RES, ADDR, OFF) - -#define TEST_io(NAME, SZ, SIZE, EXP1, EXP2, EXP3, EXP4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - LOAD_io_##SZ(result, buf, 0 * (SIZE)); \ - check(result, (EXP1)); \ - LOAD_io_##SZ(result, buf, 1 * (SIZE)); \ - check(result, (EXP2)); \ - LOAD_io_##SZ(result, buf, 2 * (SIZE)); \ - check(result, (EXP3)); \ - LOAD_io_##SZ(result, buf, 3 * (SIZE)); \ - check(result, (EXP4)); \ -} - -TEST_io(loadalignb_io, b, 1, - 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, - 0x030201ffffffffffLL, 0x04030201ffffffffLL) -TEST_io(loadalignh_io, h, 2, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x060504030201ffffLL, 0x0807060504030201LL) - -/* - **************************************************************************** - * _ur addressing mode (index << offset + base) - */ -#define LOAD_ur(SZ, RES, SHIFT, IDX) \ - __asm__( \ - "%0 = mem" #SZ "_fifo(%1<<#" #SHIFT " + ##buf)\n\t" \ - : "+r"(RES) \ - : "r"(IDX)) -#define LOAD_ur_b(RES, SHIFT, IDX) \ - LOAD_ur(b, RES, SHIFT, IDX) -#define LOAD_ur_h(RES, SHIFT, IDX) \ - LOAD_ur(h, RES, SHIFT, IDX) - -#define TEST_ur(NAME, SZ, SHIFT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - LOAD_ur_##SZ(result, (SHIFT), 0); \ - check(result, (RES1)); \ - LOAD_ur_##SZ(result, (SHIFT), 1); \ - check(result, (RES2)); \ - LOAD_ur_##SZ(result, (SHIFT), 2); \ - check(result, (RES3)); \ - LOAD_ur_##SZ(result, (SHIFT), 3); \ - check(result, (RES4)); \ -} - -TEST_ur(loadalignb_ur, b, 1, - 0x01ffffffffffffffLL, 0x0301ffffffffffffLL, - 0x050301ffffffffffLL, 0x07050301ffffffffLL) -TEST_ur(loadalignh_ur, h, 1, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x060504030201ffffLL, 0x0807060504030201LL) - -/* - **************************************************************************** - * _ap addressing mode (addr = base) - */ -#define LOAD_ap(SZ, RES, PTR, ADDR) \ - __asm__( \ - "%0 = mem" #SZ "_fifo(%1 = ##" #ADDR ")\n\t" \ - : "+r"(RES), "=r"(PTR)) -#define LOAD_ap_b(RES, PTR, ADDR) \ - LOAD_ap(b, RES, PTR, ADDR) -#define LOAD_ap_h(RES, PTR, ADDR) \ - LOAD_ap(h, RES, PTR, ADDR) - -#define TEST_ap(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - void *ptr; \ - LOAD_ap_##SZ(result, ptr, (buf + 0 * (SIZE))); \ - check(result, (RES1)); \ - checkp(ptr, &buf[0 * (SIZE)]); \ - LOAD_ap_##SZ(result, ptr, (buf + 1 * (SIZE))); \ - check(result, (RES2)); \ - checkp(ptr, &buf[1 * (SIZE)]); \ - LOAD_ap_##SZ(result, ptr, (buf + 2 * (SIZE))); \ - check(result, (RES3)); \ - checkp(ptr, &buf[2 * (SIZE)]); \ - LOAD_ap_##SZ(result, ptr, (buf + 3 * (SIZE))); \ - check(result, (RES4)); \ - checkp(ptr, &buf[3 * (SIZE)]); \ -} - -TEST_ap(loadalignb_ap, b, 1, - 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, - 0x030201ffffffffffLL, 0x04030201ffffffffLL) -TEST_ap(loadalignh_ap, h, 2, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x060504030201ffffLL, 0x0807060504030201LL) - -/* - **************************************************************************** - * _rp addressing mode (addr ++ modifer-reg) - */ -#define LOAD_pr(SZ, RES, PTR, INC) \ - __asm__( \ - "m0 = %2\n\t" \ - "%0 = mem" #SZ "_fifo(%1++m0)\n\t" \ - : "+r"(RES), "+r"(PTR) \ - : "r"(INC) \ - : "m0") -#define LOAD_pr_b(RES, PTR, INC) \ - LOAD_pr(b, RES, PTR, INC) -#define LOAD_pr_h(RES, PTR, INC) \ - LOAD_pr(h, RES, PTR, INC) - -#define TEST_pr(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - void *ptr = buf; \ - LOAD_pr_##SZ(result, ptr, (SIZE)); \ - check(result, (RES1)); \ - checkp(ptr, &buf[1 * (SIZE)]); \ - LOAD_pr_##SZ(result, ptr, (SIZE)); \ - check(result, (RES2)); \ - checkp(ptr, &buf[2 * (SIZE)]); \ - LOAD_pr_##SZ(result, ptr, (SIZE)); \ - check(result, (RES3)); \ - checkp(ptr, &buf[3 * (SIZE)]); \ - LOAD_pr_##SZ(result, ptr, (SIZE)); \ - check(result, (RES4)); \ - checkp(ptr, &buf[4 * (SIZE)]); \ -} - -TEST_pr(loadalignb_pr, b, 1, - 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, - 0x030201ffffffffffLL, 0x04030201ffffffffLL) -TEST_pr(loadalignh_pr, h, 2, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x060504030201ffffLL, 0x0807060504030201LL) - -/* - **************************************************************************** - * _pbr addressing mode (addr ++ modifer-reg:brev) - */ -#define LOAD_pbr(SZ, RES, PTR) \ - __asm__( \ - "r4 = #(1 << (16 - 3))\n\t" \ - "m0 = r4\n\t" \ - "%0 = mem" #SZ "_fifo(%1++m0:brev)\n\t" \ - : "+r"(RES), "+r"(PTR) \ - : \ - : "r4", "m0") -#define LOAD_pbr_b(RES, PTR) \ - LOAD_pbr(b, RES, PTR) -#define LOAD_pbr_h(RES, PTR) \ - LOAD_pbr(h, RES, PTR) - -#define TEST_pbr(NAME, SZ, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - void *ptr = buf; \ - LOAD_pbr_##SZ(result, ptr); \ - check(result, (RES1)); \ - LOAD_pbr_##SZ(result, ptr); \ - check(result, (RES2)); \ - LOAD_pbr_##SZ(result, ptr); \ - check(result, (RES3)); \ - LOAD_pbr_##SZ(result, ptr); \ - check(result, (RES4)); \ -} - -TEST_pbr(loadalignb_pbr, b, - 0x01ffffffffffffffLL, 0x0501ffffffffffffLL, - 0x030501ffffffffffLL, 0x07030501ffffffffLL) -TEST_pbr(loadalignh_pbr, h, - 0x0201ffffffffffffLL, 0x06050201ffffffffLL, - 0x040306050201ffffLL, 0x0807040306050201LL) - -/* - **************************************************************************** - * _pi addressing mode (addr ++ inc) - */ -#define LOAD_pi(SZ, RES, PTR, INC) \ - __asm__( \ - "%0 = mem" #SZ "_fifo(%1++#" #INC ")\n\t" \ - : "+r"(RES), "+r"(PTR)) -#define LOAD_pi_b(RES, PTR, INC) \ - LOAD_pi(b, RES, PTR, INC) -#define LOAD_pi_h(RES, PTR, INC) \ - LOAD_pi(h, RES, PTR, INC) - -#define TEST_pi(NAME, SZ, INC, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - void *ptr = buf; \ - LOAD_pi_##SZ(result, ptr, (INC)); \ - check(result, (RES1)); \ - checkp(ptr, &buf[1 * (INC)]); \ - LOAD_pi_##SZ(result, ptr, (INC)); \ - check(result, (RES2)); \ - checkp(ptr, &buf[2 * (INC)]); \ - LOAD_pi_##SZ(result, ptr, (INC)); \ - check(result, (RES3)); \ - checkp(ptr, &buf[3 * (INC)]); \ - LOAD_pi_##SZ(result, ptr, (INC)); \ - check(result, (RES4)); \ - checkp(ptr, &buf[4 * (INC)]); \ -} - -TEST_pi(loadalignb_pi, b, 1, - 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, - 0x030201ffffffffffLL, 0x04030201ffffffffLL) -TEST_pi(loadalignh_pi, h, 2, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x060504030201ffffLL, 0x0807060504030201LL) - -/* - **************************************************************************** - * _pci addressing mode (addr ++ inc:circ) - */ -#define LOAD_pci(SZ, RES, PTR, START, LEN, INC) \ - __asm__( \ - "r4 = %3\n\t" \ - "m0 = r4\n\t" \ - "cs0 = %2\n\t" \ - "%0 = mem" #SZ "_fifo(%1++#" #INC ":circ(m0))\n\t" \ - : "+r"(RES), "+r"(PTR) \ - : "r"(START), "r"(LEN) \ - : "r4", "m0", "cs0") -#define LOAD_pci_b(RES, PTR, START, LEN, INC) \ - LOAD_pci(b, RES, PTR, START, LEN, INC) -#define LOAD_pci_h(RES, PTR, START, LEN, INC) \ - LOAD_pci(h, RES, PTR, START, LEN, INC) - -#define TEST_pci(NAME, SZ, LEN, INC, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - void *ptr = buf; \ - LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES1)); \ - checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \ - LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES2)); \ - checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \ - LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES3)); \ - checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \ - LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES4)); \ - checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \ -} - -TEST_pci(loadalignb_pci, b, 2, 1, - 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, - 0x010201ffffffffffLL, 0x02010201ffffffffLL) -TEST_pci(loadalignh_pci, h, 4, 2, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x020104030201ffffLL, 0x0403020104030201LL) - -/* - **************************************************************************** - * _pcr addressing mode (addr ++ I:circ(modifier-reg)) - */ -#define LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \ - __asm__( \ - "r4 = %2\n\t" \ - "m1 = r4\n\t" \ - "cs1 = %3\n\t" \ - "%0 = mem" #SZ "_fifo(%1++I:circ(m1))\n\t" \ - : "+r"(RES), "+r"(PTR) \ - : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \ - "r"(START) \ - : "r4", "m1", "cs1") -#define LOAD_pcr_b(RES, PTR, START, LEN, INC) \ - LOAD_pcr(b, RES, PTR, START, LEN, INC) -#define LOAD_pcr_h(RES, PTR, START, LEN, INC) \ - LOAD_pcr(h, RES, PTR, START, LEN, INC) - -#define TEST_pcr(NAME, SZ, SIZE, LEN, INC, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - long long result = ~0LL; \ - void *ptr = buf; \ - LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES1)); \ - checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \ - LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES2)); \ - checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \ - LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES3)); \ - checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \ - LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES4)); \ - checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \ -} - -TEST_pcr(loadalignb_pcr, b, 1, 2, 1, - 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, - 0x010201ffffffffffLL, 0x02010201ffffffffLL) -TEST_pcr(loadalignh_pcr, h, 2, 4, 1, - 0x0201ffffffffffffLL, 0x04030201ffffffffLL, - 0x020104030201ffffLL, 0x0403020104030201LL) - -int main() -{ - init_buf(); - - test_loadalignb_io(); - test_loadalignh_io(); - - test_loadalignb_ur(); - test_loadalignh_ur(); - - test_loadalignb_ap(); - test_loadalignh_ap(); - - test_loadalignb_pr(); - test_loadalignh_pr(); - - test_loadalignb_pbr(); - test_loadalignh_pbr(); - - test_loadalignb_pi(); - test_loadalignh_pi(); - - test_loadalignb_pci(); - test_loadalignh_pci(); - - test_loadalignb_pcr(); - test_loadalignh_pcr(); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/load_unpack.c b/tests/tcg/hexagon/load_unpack.c deleted file mode 100644 index 3575a37a28f1..000000000000 --- a/tests/tcg/hexagon/load_unpack.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -/* - * Test load unpack instructions - * - * Example - * r0 = memubh(r1+#0) - * loads a half word from memory and zero-extends the 2 bytes to form a word - * - * For each addressing mode, there are 4 tests - * bzw2 unsigned 2 elements - * bsw2 signed 2 elements - * bzw4 unsigned 4 elements - * bsw4 signed 4 elements - * There are 8 addressing modes, for a total of 32 instructions to test - */ - -#include -#include - -int err; - -char buf[16] __attribute__((aligned(1 << 16))); - -void init_buf(void) -{ - int i; - for (i = 0; i < 16; i++) { - int sign = i % 2 == 0 ? 0x80 : 0; - buf[i] = sign | (i + 1); - } -} - -void __check(int line, long long result, long long expect) -{ - if (result != expect) { - printf("ERROR at line %d: 0x%08llx != 0x%08llx\n", - line, result, expect); - err++; - } -} - -#define check(RES, EXP) __check(__LINE__, RES, EXP) - -void __checkp(int line, void *p, void *expect) -{ - if (p != expect) { - printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect); - err++; - } -} - -#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP) - -/* - **************************************************************************** - * _io addressing mode (addr + offset) - */ -#define BxW_LOAD_io(SZ, RES, ADDR, OFF) \ - __asm__( \ - "%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \ - : "=r"(RES) \ - : "r"(ADDR)) -#define BxW_LOAD_io_Z(RES, ADDR, OFF) \ - BxW_LOAD_io(ubh, RES, ADDR, OFF) -#define BxW_LOAD_io_S(RES, ADDR, OFF) \ - BxW_LOAD_io(bh, RES, ADDR, OFF) - -#define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - init_buf(); \ - BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \ - check(result, (EXP1) | (EXT)); \ - BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \ - check(result, (EXP2) | (EXT)); \ - BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \ - check(result, (EXP3) | (EXT)); \ - BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \ - check(result, (EXP4) | (EXT)); \ -} - - -TEST_io(loadbzw2_io, int, Z, 2, 0x00000000, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_io(loadbsw2_io, int, S, 2, 0x0000ff00, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_io(loadbzw4_io, long long, Z, 4, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) -TEST_io(loadbsw4_io, long long, S, 4, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) - -/* - **************************************************************************** - * _ur addressing mode (index << offset + base) - */ -#define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \ - __asm__( \ - "%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \ - : "=r"(RES) \ - : "r"(IDX)) -#define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \ - BxW_LOAD_ur(ubh, RES, SHIFT, IDX) -#define BxW_LOAD_ur_S(RES, SHIFT, IDX) \ - BxW_LOAD_ur(bh, RES, SHIFT, IDX) - -#define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - init_buf(); \ - BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \ - check(result, (RES1) | (EXT)); \ - BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \ - check(result, (RES2) | (EXT)); \ - BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \ - check(result, (RES3) | (EXT)); \ - BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \ - check(result, (RES4) | (EXT)); \ -} \ - -TEST_ur(loadbzw2_ur, int, Z, 1, 0x00000000, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_ur(loadbsw2_ur, int, S, 1, 0x0000ff00, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_ur(loadbzw4_ur, long long, Z, 2, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) -TEST_ur(loadbsw4_ur, long long, S, 2, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) - -/* - **************************************************************************** - * _ap addressing mode (addr = base) - */ -#define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \ - __asm__( \ - "%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \ - : "=r"(RES), "=r"(PTR)) -#define BxW_LOAD_ap_Z(RES, PTR, ADDR) \ - BxW_LOAD_ap(ubh, RES, PTR, ADDR) -#define BxW_LOAD_ap_S(RES, PTR, ADDR) \ - BxW_LOAD_ap(bh, RES, PTR, ADDR) - -#define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - void *ptr; \ - init_buf(); \ - BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \ - check(result, (RES1) | (EXT)); \ - checkp(ptr, &buf[0 * (SIZE)]); \ - BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \ - check(result, (RES2) | (EXT)); \ - checkp(ptr, &buf[1 * (SIZE)]); \ - BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \ - check(result, (RES3) | (EXT)); \ - checkp(ptr, &buf[2 * (SIZE)]); \ - BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \ - check(result, (RES4) | (EXT)); \ - checkp(ptr, &buf[3 * (SIZE)]); \ -} - -TEST_ap(loadbzw2_ap, int, Z, 2, 0x00000000, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_ap(loadbsw2_ap, int, S, 2, 0x0000ff00, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_ap(loadbzw4_ap, long long, Z, 4, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) -TEST_ap(loadbsw4_ap, long long, S, 4, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) - -/* - **************************************************************************** - * _rp addressing mode (addr ++ modifer-reg) - */ -#define BxW_LOAD_pr(SZ, RES, PTR, INC) \ - __asm__( \ - "m0 = %2\n\t" \ - "%0 = mem" #SZ "(%1++m0)\n\t" \ - : "=r"(RES), "+r"(PTR) \ - : "r"(INC) \ - : "m0") -#define BxW_LOAD_pr_Z(RES, PTR, INC) \ - BxW_LOAD_pr(ubh, RES, PTR, INC) -#define BxW_LOAD_pr_S(RES, PTR, INC) \ - BxW_LOAD_pr(bh, RES, PTR, INC) - -#define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - void *ptr = buf; \ - init_buf(); \ - BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ - check(result, (RES1) | (EXT)); \ - checkp(ptr, &buf[1 * (SIZE)]); \ - BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ - check(result, (RES2) | (EXT)); \ - checkp(ptr, &buf[2 * (SIZE)]); \ - BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ - check(result, (RES3) | (EXT)); \ - checkp(ptr, &buf[3 * (SIZE)]); \ - BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ - check(result, (RES4) | (EXT)); \ - checkp(ptr, &buf[4 * (SIZE)]); \ -} - -TEST_pr(loadbzw2_pr, int, Z, 2, 0x00000000, - 0x00020081, 0x0040083, 0x00060085, 0x00080087) -TEST_pr(loadbsw2_pr, int, S, 2, 0x0000ff00, - 0x00020081, 0x0040083, 0x00060085, 0x00080087) -TEST_pr(loadbzw4_pr, long long, Z, 4, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) -TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) - -/* - **************************************************************************** - * _pbr addressing mode (addr ++ modifer-reg:brev) - */ -#define BxW_LOAD_pbr(SZ, RES, PTR) \ - __asm__( \ - "r4 = #(1 << (16 - 3))\n\t" \ - "m0 = r4\n\t" \ - "%0 = mem" #SZ "(%1++m0:brev)\n\t" \ - : "=r"(RES), "+r"(PTR) \ - : \ - : "r4", "m0") -#define BxW_LOAD_pbr_Z(RES, PTR) \ - BxW_LOAD_pbr(ubh, RES, PTR) -#define BxW_LOAD_pbr_S(RES, PTR) \ - BxW_LOAD_pbr(bh, RES, PTR) - -#define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - void *ptr = buf; \ - init_buf(); \ - BxW_LOAD_pbr_##SIGN(result, ptr); \ - check(result, (RES1) | (EXT)); \ - BxW_LOAD_pbr_##SIGN(result, ptr); \ - check(result, (RES2) | (EXT)); \ - BxW_LOAD_pbr_##SIGN(result, ptr); \ - check(result, (RES3) | (EXT)); \ - BxW_LOAD_pbr_##SIGN(result, ptr); \ - check(result, (RES4) | (EXT)); \ -} - -TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000, - 0x00020081, 0x00060085, 0x00040083, 0x00080087) -TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00, - 0x00020081, 0x00060085, 0x00040083, 0x00080087) -TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0006008500040083LL, 0x000a008900080087LL) -TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0006008500040083LL, 0x000a008900080087LL) - -/* - **************************************************************************** - * _pi addressing mode (addr ++ inc) - */ -#define BxW_LOAD_pi(SZ, RES, PTR, INC) \ - __asm__( \ - "%0 = mem" #SZ "(%1++#" #INC ")\n\t" \ - : "=r"(RES), "+r"(PTR)) -#define BxW_LOAD_pi_Z(RES, PTR, INC) \ - BxW_LOAD_pi(ubh, RES, PTR, INC) -#define BxW_LOAD_pi_S(RES, PTR, INC) \ - BxW_LOAD_pi(bh, RES, PTR, INC) - -#define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - void *ptr = buf; \ - init_buf(); \ - BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ - check(result, (RES1) | (EXT)); \ - checkp(ptr, &buf[1 * (INC)]); \ - BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ - check(result, (RES2) | (EXT)); \ - checkp(ptr, &buf[2 * (INC)]); \ - BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ - check(result, (RES3) | (EXT)); \ - checkp(ptr, &buf[3 * (INC)]); \ - BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ - check(result, (RES4) | (EXT)); \ - checkp(ptr, &buf[4 * (INC)]); \ -} - -TEST_pi(loadbzw2_pi, int, Z, 2, 0x00000000, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_pi(loadbsw2_pi, int, S, 2, 0x0000ff00, - 0x00020081, 0x00040083, 0x00060085, 0x00080087) -TEST_pi(loadbzw4_pi, long long, Z, 4, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) -TEST_pi(loadbsw4_pi, long long, S, 4, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x000c008b000a0089LL, 0x0010008f000e008dLL) - -/* - **************************************************************************** - * _pci addressing mode (addr ++ inc:circ) - */ -#define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \ - __asm__( \ - "r4 = %3\n\t" \ - "m0 = r4\n\t" \ - "cs0 = %2\n\t" \ - "%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \ - : "=r"(RES), "+r"(PTR) \ - : "r"(START), "r"(LEN) \ - : "r4", "m0", "cs0") -#define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \ - BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC) -#define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \ - BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC) - -#define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - void *ptr = buf; \ - init_buf(); \ - BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES1) | (EXT)); \ - checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \ - BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES2) | (EXT)); \ - checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \ - BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES3) | (EXT)); \ - checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \ - BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES4) | (EXT)); \ - checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \ -} - -TEST_pci(loadbzw2_pci, int, Z, 6, 2, 0x00000000, - 0x00020081, 0x00040083, 0x00060085, 0x00020081) -TEST_pci(loadbsw2_pci, int, S, 6, 2, 0x0000ff00, - 0x00020081, 0x00040083, 0x00060085, 0x00020081) -TEST_pci(loadbzw4_pci, long long, Z, 8, 4, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0004008300020081LL, 0x0008008700060085LL) -TEST_pci(loadbsw4_pci, long long, S, 8, 4, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0004008300020081LL, 0x0008008700060085LL) - -/* - **************************************************************************** - * _pcr addressing mode (addr ++ I:circ(modifier-reg)) - */ -#define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \ - __asm__( \ - "r4 = %2\n\t" \ - "m1 = r4\n\t" \ - "cs1 = %3\n\t" \ - "%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \ - : "=r"(RES), "+r"(PTR) \ - : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \ - "r"(START) \ - : "r4", "m1", "cs1") -#define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \ - BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC) -#define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \ - BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC) - -#define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \ - EXT, RES1, RES2, RES3, RES4) \ -void test_##NAME(void) \ -{ \ - TYPE result; \ - void *ptr = buf; \ - init_buf(); \ - BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES1) | (EXT)); \ - checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \ - BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES2) | (EXT)); \ - checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \ - BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES3) | (EXT)); \ - checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \ - BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ - check(result, (RES4) | (EXT)); \ - checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \ -} - -TEST_pcr(loadbzw2_pcr, int, Z, 2, 8, 2, 0x00000000, - 0x00020081, 0x00060085, 0x00020081, 0x00060085) -TEST_pcr(loadbsw2_pcr, int, S, 2, 8, 2, 0x0000ff00, - 0x00020081, 0x00060085, 0x00020081, 0x00060085) -TEST_pcr(loadbzw4_pcr, long long, Z, 4, 8, 1, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0004008300020081LL, 0x0008008700060085LL) -TEST_pcr(loadbsw4_pcr, long long, S, 4, 8, 1, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0004008300020081LL, 0x0008008700060085LL) - -int main() -{ - test_loadbzw2_io(); - test_loadbsw2_io(); - test_loadbzw4_io(); - test_loadbsw4_io(); - - test_loadbzw2_ur(); - test_loadbsw2_ur(); - test_loadbzw4_ur(); - test_loadbsw4_ur(); - - test_loadbzw2_ap(); - test_loadbsw2_ap(); - test_loadbzw4_ap(); - test_loadbsw4_ap(); - - test_loadbzw2_pr(); - test_loadbsw2_pr(); - test_loadbzw4_pr(); - test_loadbsw4_pr(); - - test_loadbzw2_pbr(); - test_loadbsw2_pbr(); - test_loadbzw4_pbr(); - test_loadbsw4_pbr(); - - test_loadbzw2_pi(); - test_loadbsw2_pi(); - test_loadbzw4_pi(); - test_loadbsw4_pi(); - - test_loadbzw2_pci(); - test_loadbsw2_pci(); - test_loadbzw4_pci(); - test_loadbsw4_pci(); - - test_loadbzw2_pcr(); - test_loadbsw2_pcr(); - test_loadbzw4_pcr(); - test_loadbsw4_pcr(); - - puts(err ? "FAIL" : "PASS"); - return err ? 1 : 0; -} diff --git a/tests/tcg/hexagon/mem_noshuf.c b/tests/tcg/hexagon/mem_noshuf.c deleted file mode 100644 index dd714d5e98ae..000000000000 --- a/tests/tcg/hexagon/mem_noshuf.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include - -/* - * Make sure that the :mem_noshuf packet attribute is honored. - * This is important when the addresses overlap. - * The store instruction in slot 1 effectively executes first, - * followed by the load instruction in slot 0. - */ - -#define MEM_NOSHUF32(NAME, ST_TYPE, LD_TYPE, ST_OP, LD_OP) \ -static inline unsigned int NAME(ST_TYPE * p, LD_TYPE * q, ST_TYPE x) \ -{ \ - unsigned int ret; \ - asm volatile("{\n\t" \ - " " #ST_OP "(%1) = %3\n\t" \ - " %0 = " #LD_OP "(%2)\n\t" \ - "}:mem_noshuf\n" \ - : "=r"(ret) \ - : "r"(p), "r"(q), "r"(x) \ - : "memory"); \ - return ret; \ -} - -#define MEM_NOSHUF64(NAME, ST_TYPE, LD_TYPE, ST_OP, LD_OP) \ -static inline unsigned long long NAME(ST_TYPE * p, LD_TYPE * q, ST_TYPE x) \ -{ \ - unsigned long long ret; \ - asm volatile("{\n\t" \ - " " #ST_OP "(%1) = %3\n\t" \ - " %0 = " #LD_OP "(%2)\n\t" \ - "}:mem_noshuf\n" \ - : "=r"(ret) \ - : "r"(p), "r"(q), "r"(x) \ - : "memory"); \ - return ret; \ -} - -/* Store byte combinations */ -MEM_NOSHUF32(mem_noshuf_sb_lb, signed char, signed char, memb, memb) -MEM_NOSHUF32(mem_noshuf_sb_lub, signed char, unsigned char, memb, memub) -MEM_NOSHUF32(mem_noshuf_sb_lh, signed char, signed short, memb, memh) -MEM_NOSHUF32(mem_noshuf_sb_luh, signed char, unsigned short, memb, memuh) -MEM_NOSHUF32(mem_noshuf_sb_lw, signed char, signed int, memb, memw) -MEM_NOSHUF64(mem_noshuf_sb_ld, signed char, signed long long, memb, memd) - -/* Store half combinations */ -MEM_NOSHUF32(mem_noshuf_sh_lb, signed short, signed char, memh, memb) -MEM_NOSHUF32(mem_noshuf_sh_lub, signed short, unsigned char, memh, memub) -MEM_NOSHUF32(mem_noshuf_sh_lh, signed short, signed short, memh, memh) -MEM_NOSHUF32(mem_noshuf_sh_luh, signed short, unsigned short, memh, memuh) -MEM_NOSHUF32(mem_noshuf_sh_lw, signed short, signed int, memh, memw) -MEM_NOSHUF64(mem_noshuf_sh_ld, signed short, signed long long, memh, memd) - -/* Store word combinations */ -MEM_NOSHUF32(mem_noshuf_sw_lb, signed int, signed char, memw, memb) -MEM_NOSHUF32(mem_noshuf_sw_lub, signed int, unsigned char, memw, memub) -MEM_NOSHUF32(mem_noshuf_sw_lh, signed int, signed short, memw, memh) -MEM_NOSHUF32(mem_noshuf_sw_luh, signed int, unsigned short, memw, memuh) -MEM_NOSHUF32(mem_noshuf_sw_lw, signed int, signed int, memw, memw) -MEM_NOSHUF64(mem_noshuf_sw_ld, signed int, signed long long, memw, memd) - -/* Store double combinations */ -MEM_NOSHUF32(mem_noshuf_sd_lb, long long, signed char, memd, memb) -MEM_NOSHUF32(mem_noshuf_sd_lub, long long, unsigned char, memd, memub) -MEM_NOSHUF32(mem_noshuf_sd_lh, long long, signed short, memd, memh) -MEM_NOSHUF32(mem_noshuf_sd_luh, long long, unsigned short, memd, memuh) -MEM_NOSHUF32(mem_noshuf_sd_lw, long long, signed int, memd, memw) -MEM_NOSHUF64(mem_noshuf_sd_ld, long long, signed long long, memd, memd) - -static inline unsigned int cancel_sw_lb(int pred, int *p, signed char *q, int x) -{ - unsigned int ret; - asm volatile("p0 = cmp.eq(%4, #0)\n\t" - "{\n\t" - " if (!p0) memw(%1) = %3\n\t" - " %0 = memb(%2)\n\t" - "}:mem_noshuf\n" - : "=r"(ret) - : "r"(p), "r"(q), "r"(x), "r"(pred) - : "p0", "memory"); - return ret; -} - -static inline -unsigned long long cancel_sw_ld(int pred, int *p, long long *q, int x) -{ - long long ret; - asm volatile("p0 = cmp.eq(%4, #0)\n\t" - "{\n\t" - " if (!p0) memw(%1) = %3\n\t" - " %0 = memd(%2)\n\t" - "}:mem_noshuf\n" - : "=r"(ret) - : "r"(p), "r"(q), "r"(x), "r"(pred) - : "p0", "memory"); - return ret; -} - -typedef union { - signed long long d[2]; - unsigned long long ud[2]; - signed int w[4]; - unsigned int uw[4]; - signed short h[8]; - unsigned short uh[8]; - signed char b[16]; - unsigned char ub[16]; -} Memory; - -int err; - -static void check32(int n, int expect) -{ - if (n != expect) { - printf("ERROR: 0x%08x != 0x%08x\n", n, expect); - err++; - } -} - -static void check64(long long n, long long expect) -{ - if (n != expect) { - printf("ERROR: 0x%08llx != 0x%08llx\n", n, expect); - err++; - } -} - -int main() -{ - Memory n; - unsigned int res32; - unsigned long long res64; - - /* - * Store byte combinations - */ - n.w[0] = ~0; - res32 = mem_noshuf_sb_lb(&n.b[0], &n.b[0], 0x87); - check32(res32, 0xffffff87); - - n.w[0] = ~0; - res32 = mem_noshuf_sb_lub(&n.b[0], &n.ub[0], 0x87); - check32(res32, 0x00000087); - - n.w[0] = ~0; - res32 = mem_noshuf_sb_lh(&n.b[0], &n.h[0], 0x87); - check32(res32, 0xffffff87); - - n.w[0] = ~0; - res32 = mem_noshuf_sb_luh(&n.b[0], &n.uh[0], 0x87); - check32(res32, 0x0000ff87); - - n.w[0] = ~0; - res32 = mem_noshuf_sb_lw(&n.b[0], &n.w[0], 0x87); - check32(res32, 0xffffff87); - - n.d[0] = ~0LL; - res64 = mem_noshuf_sb_ld(&n.b[0], &n.d[0], 0x87); - check64(res64, 0xffffffffffffff87LL); - - /* - * Store half combinations - */ - n.w[0] = ~0; - res32 = mem_noshuf_sh_lb(&n.h[0], &n.b[0], 0x8787); - check32(res32, 0xffffff87); - - n.w[0] = ~0; - res32 = mem_noshuf_sh_lub(&n.h[0], &n.ub[1], 0x8f87); - check32(res32, 0x0000008f); - - n.w[0] = ~0; - res32 = mem_noshuf_sh_lh(&n.h[0], &n.h[0], 0x8a87); - check32(res32, 0xffff8a87); - - n.w[0] = ~0; - res32 = mem_noshuf_sh_luh(&n.h[0], &n.uh[0], 0x8a87); - check32(res32, 0x8a87); - - n.w[0] = ~0; - res32 = mem_noshuf_sh_lw(&n.h[1], &n.w[0], 0x8a87); - check32(res32, 0x8a87ffff); - - n.w[0] = ~0; - res64 = mem_noshuf_sh_ld(&n.h[1], &n.d[0], 0x8a87); - check64(res64, 0xffffffff8a87ffffLL); - - /* - * Store word combinations - */ - n.w[0] = ~0; - res32 = mem_noshuf_sw_lb(&n.w[0], &n.b[0], 0x12345687); - check32(res32, 0xffffff87); - - n.w[0] = ~0; - res32 = mem_noshuf_sw_lub(&n.w[0], &n.ub[0], 0x12345687); - check32(res32, 0x00000087); - - n.w[0] = ~0; - res32 = mem_noshuf_sw_lh(&n.w[0], &n.h[0], 0x1234f678); - check32(res32, 0xfffff678); - - n.w[0] = ~0; - res32 = mem_noshuf_sw_luh(&n.w[0], &n.uh[0], 0x12345678); - check32(res32, 0x00005678); - - n.w[0] = ~0; - res32 = mem_noshuf_sw_lw(&n.w[0], &n.w[0], 0x12345678); - check32(res32, 0x12345678); - - n.d[0] = ~0LL; - res64 = mem_noshuf_sw_ld(&n.w[0], &n.d[0], 0x12345678); - check64(res64, 0xffffffff12345678LL); - - /* - * Store double combinations - */ - n.d[0] = ~0LL; - res32 = mem_noshuf_sd_lb(&n.d[0], &n.b[1], 0x123456789abcdef0); - check32(res32, 0xffffffde); - - n.d[0] = ~0LL; - res32 = mem_noshuf_sd_lub(&n.d[0], &n.ub[1], 0x123456789abcdef0); - check32(res32, 0x000000de); - - n.d[0] = ~0LL; - res32 = mem_noshuf_sd_lh(&n.d[0], &n.h[1], 0x123456789abcdef0); - check32(res32, 0xffff9abc); - - n.d[0] = ~0LL; - res32 = mem_noshuf_sd_luh(&n.d[0], &n.uh[1], 0x123456789abcdef0); - check32(res32, 0x00009abc); - - n.d[0] = ~0LL; - res32 = mem_noshuf_sd_lw(&n.d[0], &n.w[1], 0x123456789abcdef0); - check32(res32, 0x12345678); - - n.d[0] = ~0LL; - res64 = mem_noshuf_sd_ld(&n.d[0], &n.d[0], 0x123456789abcdef0); - check64(res64, 0x123456789abcdef0LL); - - /* - * Predicated word stores - */ - n.w[0] = ~0; - res32 = cancel_sw_lb(0, &n.w[0], &n.b[0], 0x12345678); - check32(res32, 0xffffffff); - - n.w[0] = ~0; - res32 = cancel_sw_lb(1, &n.w[0], &n.b[0], 0x12345687); - check32(res32, 0xffffff87); - - /* - * Predicated double stores - */ - n.d[0] = ~0LL; - res64 = cancel_sw_ld(0, &n.w[0], &n.d[0], 0x12345678); - check64(res64, 0xffffffffffffffffLL); - - n.d[0] = ~0LL; - res64 = cancel_sw_ld(1, &n.w[0], &n.d[0], 0x12345678); - check64(res64, 0xffffffff12345678LL); - - n.d[0] = ~0LL; - res64 = cancel_sw_ld(0, &n.w[1], &n.d[0], 0x12345678); - check64(res64, 0xffffffffffffffffLL); - - n.d[0] = ~0LL; - res64 = cancel_sw_ld(1, &n.w[1], &n.d[0], 0x12345678); - check64(res64, 0x12345678ffffffffLL); - - /* - * No overlap tests - */ - n.w[0] = ~0; - res32 = mem_noshuf_sb_lb(&n.b[1], &n.b[0], 0x87); - check32(res32, 0xffffffff); - - n.w[0] = ~0; - res32 = mem_noshuf_sb_lb(&n.b[0], &n.b[1], 0x87); - check32(res32, 0xffffffff); - - n.w[0] = ~0; - res32 = mem_noshuf_sh_lh(&n.h[1], &n.h[0], 0x8787); - check32(res32, 0xffffffff); - - n.w[0] = ~0; - res32 = mem_noshuf_sh_lh(&n.h[0], &n.h[1], 0x8787); - check32(res32, 0xffffffff); - - n.d[0] = ~0LL; - res32 = mem_noshuf_sw_lw(&n.w[0], &n.w[1], 0x12345678); - check32(res32, 0xffffffff); - - n.d[0] = ~0LL; - res32 = mem_noshuf_sw_lw(&n.w[1], &n.w[0], 0x12345678); - check32(res32, 0xffffffff); - - n.d[0] = ~0LL; - n.d[1] = ~0LL; - res64 = mem_noshuf_sd_ld(&n.d[1], &n.d[0], 0x123456789abcdef0LL); - check64(res64, 0xffffffffffffffffLL); - - n.d[0] = ~0LL; - n.d[1] = ~0LL; - res64 = mem_noshuf_sd_ld(&n.d[0], &n.d[1], 0x123456789abcdef0LL); - check64(res64, 0xffffffffffffffffLL); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/misc.c b/tests/tcg/hexagon/misc.c deleted file mode 100644 index f0b1947fb3a8..000000000000 --- a/tests/tcg/hexagon/misc.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include -#include - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; - - -static inline void S4_storerhnew_rr(void *p, int index, uint16_t v) -{ - asm volatile("{\n\t" - " r0 = %0\n\n" - " memh(%1+%2<<#2) = r0.new\n\t" - "}\n" - :: "r"(v), "r"(p), "r"(index) - : "r0", "memory"); -} - -static uint32_t data; -static inline void *S4_storerbnew_ap(uint8_t v) -{ - void *ret; - asm volatile("{\n\t" - " r0 = %1\n\n" - " memb(%0 = ##data) = r0.new\n\t" - "}\n" - : "=r"(ret) - : "r"(v) - : "r0", "memory"); - return ret; -} - -static inline void *S4_storerhnew_ap(uint16_t v) -{ - void *ret; - asm volatile("{\n\t" - " r0 = %1\n\n" - " memh(%0 = ##data) = r0.new\n\t" - "}\n" - : "=r"(ret) - : "r"(v) - : "r0", "memory"); - return ret; -} - -static inline void *S4_storerinew_ap(uint32_t v) -{ - void *ret; - asm volatile("{\n\t" - " r0 = %1\n\n" - " memw(%0 = ##data) = r0.new\n\t" - "}\n" - : "=r"(ret) - : "r"(v) - : "r0", "memory"); - return ret; -} - -static inline void S4_storeirbt_io(void *p, int pred) -{ - asm volatile("p0 = cmp.eq(%0, #1)\n\t" - "if (p0) memb(%1+#4)=#27\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirbf_io(void *p, int pred) -{ - asm volatile("p0 = cmp.eq(%0, #1)\n\t" - "if (!p0) memb(%1+#4)=#27\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirbtnew_io(void *p, int pred) -{ - asm volatile("{\n\t" - " p0 = cmp.eq(%0, #1)\n\t" - " if (p0.new) memb(%1+#4)=#27\n\t" - "}\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirbfnew_io(void *p, int pred) -{ - asm volatile("{\n\t" - " p0 = cmp.eq(%0, #1)\n\t" - " if (!p0.new) memb(%1+#4)=#27\n\t" - "}\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirht_io(void *p, int pred) -{ - asm volatile("p0 = cmp.eq(%0, #1)\n\t" - "if (p0) memh(%1+#4)=#27\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirhf_io(void *p, int pred) -{ - asm volatile("p0 = cmp.eq(%0, #1)\n\t" - "if (!p0) memh(%1+#4)=#27\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirhtnew_io(void *p, int pred) -{ - asm volatile("{\n\t" - " p0 = cmp.eq(%0, #1)\n\t" - " if (p0.new) memh(%1+#4)=#27\n\t" - "}\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirhfnew_io(void *p, int pred) -{ - asm volatile("{\n\t" - " p0 = cmp.eq(%0, #1)\n\t" - " if (!p0.new) memh(%1+#4)=#27\n\t" - "}\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirit_io(void *p, int pred) -{ - asm volatile("p0 = cmp.eq(%0, #1)\n\t" - "if (p0) memw(%1+#4)=#27\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirif_io(void *p, int pred) -{ - asm volatile("p0 = cmp.eq(%0, #1)\n\t" - "if (!p0) memw(%1+#4)=#27\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeiritnew_io(void *p, int pred) -{ - asm volatile("{\n\t" - " p0 = cmp.eq(%0, #1)\n\t" - " if (p0.new) memw(%1+#4)=#27\n\t" - "}\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static inline void S4_storeirifnew_io(void *p, int pred) -{ - asm volatile("{\n\t" - " p0 = cmp.eq(%0, #1)\n\t" - " if (!p0.new) memw(%1+#4)=#27\n\t" - "}\n\t" - :: "r"(pred), "r"(p) - : "p0", "memory"); -} - -static int L2_ploadrifnew_pi(void *p, int pred) -{ - int result; - asm volatile("%0 = #31\n\t" - "{\n\t" - " p0 = cmp.eq(%1, #1)\n\t" - " if (!p0.new) %0 = memw(%2++#4)\n\t" - "}\n\t" - : "=r"(result) : "r"(pred), "r"(p) - : "p0"); - return result; -} - -/* - * Test that compound-compare-jump is executed in 2 parts - * First we have to do all the compares in the packet and - * account for auto-anding. Then, we can do the predicated - * jump. - */ -static inline int cmpnd_cmp_jump(void) -{ - int retval; - asm ("r5 = #7\n\t" - "r6 = #9\n\t" - "{\n\t" - " p0 = cmp.eq(r5, #7)\n\t" - " if (p0.new) jump:nt 1f\n\t" - " p0 = cmp.eq(r6, #7)\n\t" - "}\n\t" - "%0 = #12\n\t" - "jump 2f\n\t" - "1:\n\t" - "%0 = #13\n\t" - "2:\n\t" - : "=r"(retval) :: "r5", "r6", "p0"); - return retval; -} - -static inline int test_clrtnew(int arg1, int old_val) -{ - int ret; - asm volatile("r5 = %2\n\t" - "{\n\t" - "p0 = cmp.eq(%1, #1)\n\t" - "if (p0.new) r5=#0\n\t" - "}\n\t" - "%0 = r5\n\t" - : "=r"(ret) - : "r"(arg1), "r"(old_val) - : "p0", "r5"); - return ret; -} - -int err; - -static void check(int val, int expect) -{ - if (val != expect) { - printf("ERROR: 0x%04x != 0x%04x\n", val, expect); - err++; - } -} - -static void check64(long long val, long long expect) -{ - if (val != expect) { - printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect); - err++; - } -} - -uint32_t init[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; -uint32_t array[10]; - -uint32_t early_exit; - -/* - * Write this as a function because we can't guarantee the compiler will - * allocate a frame with just the SL2_return_tnew packet. - */ -static void SL2_return_tnew(int x); -asm ("SL2_return_tnew:\n\t" - " allocframe(#0)\n\t" - " r1 = #1\n\t" - " memw(##early_exit) = r1\n\t" - " {\n\t" - " p0 = cmp.eq(r0, #1)\n\t" - " if (p0.new) dealloc_return:nt\n\t" /* SL2_return_tnew */ - " }\n\t" - " r1 = #0\n\t" - " memw(##early_exit) = r1\n\t" - " dealloc_return\n\t" - ); - -static long long creg_pair(int x, int y) -{ - long long retval; - asm ("m0 = %1\n\t" - "m1 = %2\n\t" - "%0 = c7:6\n\t" - : "=r"(retval) : "r"(x), "r"(y) : "m0", "m1"); - return retval; -} - -static long long decbin(long long x, long long y, int *pred) -{ - long long retval; - asm ("%0 = decbin(%2, %3)\n\t" - "%1 = p0\n\t" - : "=r"(retval), "=r"(*pred) - : "r"(x), "r"(y)); - return retval; -} - -/* Check that predicates are auto-and'ed in a packet */ -static int auto_and(void) -{ - int retval; - asm ("r5 = #1\n\t" - "{\n\t" - " p0 = cmp.eq(r1, #1)\n\t" - " p0 = cmp.eq(r1, #2)\n\t" - "}\n\t" - "%0 = p0\n\t" - : "=r"(retval) - : - : "r5", "p0"); - return retval; -} - -void test_lsbnew(void) -{ - int result; - - asm("r0 = #2\n\t" - "r1 = #5\n\t" - "{\n\t" - " p0 = r0\n\t" - " if (p0.new) r1 = #3\n\t" - "}\n\t" - "%0 = r1\n\t" - : "=r"(result) :: "r0", "r1", "p0"); - check(result, 5); -} - -void test_l2fetch(void) -{ - /* These don't do anything in qemu, just make sure they don't assert */ - asm volatile ("l2fetch(r0, r1)\n\t" - "l2fetch(r0, r3:2)\n\t"); -} - -int main() -{ - int res; - long long res64; - int pred; - - memcpy(array, init, sizeof(array)); - S4_storerhnew_rr(array, 4, 0xffff); - check(array[4], 0xffff); - - data = ~0; - check((uint32_t)S4_storerbnew_ap(0x12), (uint32_t)&data); - check(data, 0xffffff12); - - data = ~0; - check((uint32_t)S4_storerhnew_ap(0x1234), (uint32_t)&data); - check(data, 0xffff1234); - - data = ~0; - check((uint32_t)S4_storerinew_ap(0x12345678), (uint32_t)&data); - check(data, 0x12345678); - - /* Byte */ - memcpy(array, init, sizeof(array)); - S4_storeirbt_io(&array[1], 1); - check(array[2], 27); - S4_storeirbt_io(&array[2], 0); - check(array[3], 3); - - memcpy(array, init, sizeof(array)); - S4_storeirbf_io(&array[3], 0); - check(array[4], 27); - S4_storeirbf_io(&array[4], 1); - check(array[5], 5); - - memcpy(array, init, sizeof(array)); - S4_storeirbtnew_io(&array[5], 1); - check(array[6], 27); - S4_storeirbtnew_io(&array[6], 0); - check(array[7], 7); - - memcpy(array, init, sizeof(array)); - S4_storeirbfnew_io(&array[7], 0); - check(array[8], 27); - S4_storeirbfnew_io(&array[8], 1); - check(array[9], 9); - - /* Half word */ - memcpy(array, init, sizeof(array)); - S4_storeirht_io(&array[1], 1); - check(array[2], 27); - S4_storeirht_io(&array[2], 0); - check(array[3], 3); - - memcpy(array, init, sizeof(array)); - S4_storeirhf_io(&array[3], 0); - check(array[4], 27); - S4_storeirhf_io(&array[4], 1); - check(array[5], 5); - - memcpy(array, init, sizeof(array)); - S4_storeirhtnew_io(&array[5], 1); - check(array[6], 27); - S4_storeirhtnew_io(&array[6], 0); - check(array[7], 7); - - memcpy(array, init, sizeof(array)); - S4_storeirhfnew_io(&array[7], 0); - check(array[8], 27); - S4_storeirhfnew_io(&array[8], 1); - check(array[9], 9); - - /* Word */ - memcpy(array, init, sizeof(array)); - S4_storeirit_io(&array[1], 1); - check(array[2], 27); - S4_storeirit_io(&array[2], 0); - check(array[3], 3); - - memcpy(array, init, sizeof(array)); - S4_storeirif_io(&array[3], 0); - check(array[4], 27); - S4_storeirif_io(&array[4], 1); - check(array[5], 5); - - memcpy(array, init, sizeof(array)); - S4_storeiritnew_io(&array[5], 1); - check(array[6], 27); - S4_storeiritnew_io(&array[6], 0); - check(array[7], 7); - - memcpy(array, init, sizeof(array)); - S4_storeirifnew_io(&array[7], 0); - check(array[8], 27); - S4_storeirifnew_io(&array[8], 1); - check(array[9], 9); - - memcpy(array, init, sizeof(array)); - res = L2_ploadrifnew_pi(&array[6], 0); - check(res, 6); - res = L2_ploadrifnew_pi(&array[7], 1); - check(res, 31); - - int x = cmpnd_cmp_jump(); - check(x, 12); - - SL2_return_tnew(0); - check(early_exit, 0); - SL2_return_tnew(1); - check(early_exit, 1); - - long long pair = creg_pair(5, 7); - check((int)pair, 5); - check((int)(pair >> 32), 7); - - res = test_clrtnew(1, 7); - check(res, 0); - res = test_clrtnew(2, 7); - check(res, 7); - - res64 = decbin(0xf0f1f2f3f4f5f6f7LL, 0x7f6f5f4f3f2f1f0fLL, &pred); - check64(res64, 0x357980003700010cLL); - check(pred, 0); - - res64 = decbin(0xfLL, 0x1bLL, &pred); - check64(res64, 0x78000100LL); - check(pred, 1); - - res = auto_and(); - check(res, 0); - - test_lsbnew(); - - test_l2fetch(); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c deleted file mode 100644 index 52997b312851..000000000000 --- a/tests/tcg/hexagon/multi_result.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include - -static int sfrecipa(int Rs, int Rt, int *pred_result) -{ - int result; - int predval; - - asm volatile("%0,p0 = sfrecipa(%2, %3)\n\t" - "%1 = p0\n\t" - : "+r"(result), "=r"(predval) - : "r"(Rs), "r"(Rt) - : "p0"); - *pred_result = predval; - return result; -} - -static int sfinvsqrta(int Rs, int *pred_result) -{ - int result; - int predval; - - asm volatile("%0,p0 = sfinvsqrta(%2)\n\t" - "%1 = p0\n\t" - : "+r"(result), "=r"(predval) - : "r"(Rs) - : "p0"); - *pred_result = predval; - return result; -} - -static long long vacsh(long long Rxx, long long Rss, long long Rtt, - int *pred_result, int *ovf_result) -{ - long long result = Rxx; - int predval; - int usr; - - /* - * This instruction can set bit 0 (OVF/overflow) in usr - * Clear the bit first, then return that bit to the caller - */ - asm volatile("r2 = usr\n\t" - "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */ - "usr = r2\n\t" - "%0,p0 = vacsh(%3, %4)\n\t" - "%1 = p0\n\t" - "%2 = usr\n\t" - : "+r"(result), "=r"(predval), "=r"(usr) - : "r"(Rss), "r"(Rtt) - : "r2", "p0", "usr"); - *pred_result = predval; - *ovf_result = (usr & 1); - return result; -} - -static long long vminub(long long Rtt, long long Rss, - int *pred_result) -{ - long long result; - int predval; - - asm volatile("%0,p0 = vminub(%2, %3)\n\t" - "%1 = p0\n\t" - : "=r"(result), "=r"(predval) - : "r"(Rtt), "r"(Rss) - : "p0"); - *pred_result = predval; - return result; -} - -static long long add_carry(long long Rss, long long Rtt, - int pred_in, int *pred_result) -{ - long long result; - int predval = pred_in; - - asm volatile("p0 = %1\n\t" - "%0 = add(%2, %3, p0):carry\n\t" - "%1 = p0\n\t" - : "=r"(result), "+r"(predval) - : "r"(Rss), "r"(Rtt) - : "p0"); - *pred_result = predval; - return result; -} - -static long long sub_carry(long long Rss, long long Rtt, - int pred_in, int *pred_result) -{ - long long result; - int predval = pred_in; - - asm volatile("p0 = !cmp.eq(%1, #0)\n\t" - "%0 = sub(%2, %3, p0):carry\n\t" - "%1 = p0\n\t" - : "=r"(result), "+r"(predval) - : "r"(Rss), "r"(Rtt) - : "p0"); - *pred_result = predval; - return result; -} - -int err; - -static void check_ll(long long val, long long expect) -{ - if (val != expect) { - printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect); - err++; - } -} - -static void check(int val, int expect) -{ - if (val != expect) { - printf("ERROR: 0x%08x != 0x%08x\n", val, expect); - err++; - } -} - -static void check_p(int val, int expect) -{ - if (val != expect) { - printf("ERROR: 0x%02x != 0x%02x\n", val, expect); - err++; - } -} - -static void test_sfrecipa() -{ - int res; - int pred_result; - - res = sfrecipa(0x04030201, 0x05060708, &pred_result); - check(res, 0x59f38001); - check_p(pred_result, 0x00); -} - -static void test_sfinvsqrta() -{ - int res; - int pred_result; - - res = sfinvsqrta(0x04030201, &pred_result); - check(res, 0x4d330000); - check_p(pred_result, 0xe0); - - res = sfinvsqrta(0x0, &pred_result); - check(res, 0x3f800000); - check_p(pred_result, 0x0); -} - -static void test_vacsh() -{ - long long res64; - int pred_result; - int ovf_result; - - res64 = vacsh(0x0004000300020001LL, - 0x0001000200030004LL, - 0x0000000000000000LL, &pred_result, &ovf_result); - check_ll(res64, 0x0004000300030004LL); - check_p(pred_result, 0xf0); - check(ovf_result, 0); - - res64 = vacsh(0x0004000300020001LL, - 0x0001000200030004LL, - 0x000affff000d0000LL, &pred_result, &ovf_result); - check_ll(res64, 0x000e0003000f0004LL); - check_p(pred_result, 0xcc); - check(ovf_result, 0); - - res64 = vacsh(0x00047fff00020001LL, - 0x00017fff00030004LL, - 0x000a0fff000d0000LL, &pred_result, &ovf_result); - check_ll(res64, 0x000e7fff000f0004LL); - check_p(pred_result, 0xfc); - check(ovf_result, 1); - - res64 = vacsh(0x0004000300020001LL, - 0x0001000200030009LL, - 0x000affff000d0001LL, &pred_result, &ovf_result); - check_ll(res64, 0x000e0003000f0008LL); - check_p(pred_result, 0xcc); - check(ovf_result, 0); -} - -static void test_vminub() -{ - long long res64; - int pred_result; - - res64 = vminub(0x0807060504030201LL, - 0x0102030405060708LL, - &pred_result); - check_ll(res64, 0x0102030404030201LL); - check_p(pred_result, 0xf0); - - res64 = vminub(0x0802060405030701LL, - 0x0107030504060208LL, - &pred_result); - check_ll(res64, 0x0102030404030201LL); - check_p(pred_result, 0xaa); -} - -static void test_add_carry() -{ - long long res64; - int pred_result; - - res64 = add_carry(0x0000000000000000LL, - 0xffffffffffffffffLL, - 1, &pred_result); - check_ll(res64, 0x0000000000000000LL); - check_p(pred_result, 0xff); - - res64 = add_carry(0x0000000100000000LL, - 0xffffffffffffffffLL, - 0, &pred_result); - check_ll(res64, 0x00000000ffffffffLL); - check_p(pred_result, 0xff); - - res64 = add_carry(0x0000000100000000LL, - 0xffffffffffffffffLL, - 0, &pred_result); - check_ll(res64, 0x00000000ffffffffLL); - check_p(pred_result, 0xff); -} - -static void test_sub_carry() -{ - long long res64; - int pred_result; - - res64 = sub_carry(0x0000000000000000LL, - 0x0000000000000000LL, - 1, &pred_result); - check_ll(res64, 0x0000000000000000LL); - check_p(pred_result, 0xff); - - res64 = sub_carry(0x0000000100000000LL, - 0x0000000000000000LL, - 0, &pred_result); - check_ll(res64, 0x00000000ffffffffLL); - check_p(pred_result, 0xff); - - res64 = sub_carry(0x0000000100000000LL, - 0x0000000000000000LL, - 0, &pred_result); - check_ll(res64, 0x00000000ffffffffLL); - check_p(pred_result, 0xff); -} - -int main() -{ - test_sfrecipa(); - test_sfinvsqrta(); - test_vacsh(); - test_vminub(); - test_add_carry(); - test_sub_carry(); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/overflow.c b/tests/tcg/hexagon/overflow.c deleted file mode 100644 index 94087851b0a6..000000000000 --- a/tests/tcg/hexagon/overflow.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright(c) 2021-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 - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include - - -int err; - -static void __check(const char *filename, int line, int x, int expect) -{ - if (x != expect) { - printf("ERROR %s:%d - %d != %d\n", - filename, line, x, expect); - err++; - } -} - -#define check(x, expect) __check(__FILE__, __LINE__, (x), (expect)) - -static int satub(int src, int *p, int *ovf_result) -{ - int result; - int usr; - - /* - * This instruction can set bit 0 (OVF/overflow) in usr - * Clear the bit first, then return that bit to the caller - * - * We also store the src into *p in the same packet, so we - * can ensure the overflow doesn't get set when an exception - * is generated. - */ - asm volatile("r2 = usr\n\t" - "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */ - "usr = r2\n\t" - "{\n\t" - " %0 = satub(%2)\n\t" - " memw(%3) = %2\n\t" - "}\n\t" - "%1 = usr\n\t" - : "=r"(result), "=r"(usr) - : "r"(src), "r"(p) - : "r2", "usr", "memory"); - *ovf_result = (usr & 1); - return result; -} - -int read_usr_overflow(void) -{ - int result; - asm volatile("%0 = usr\n\t" : "=r"(result)); - return result & 1; -} - -int get_usr_overflow(int usr) -{ - return usr & 1; -} - -int get_usr_fp_invalid(int usr) -{ - return (usr >> 1) & 1; -} - -int get_usr_lpcfg(int usr) -{ - return (usr >> 8) & 0x3; -} - -jmp_buf jmp_env; -int usr_overflow; - -static void sig_segv(int sig, siginfo_t *info, void *puc) -{ - usr_overflow = read_usr_overflow(); - longjmp(jmp_env, 1); -} - -static void test_packet(void) -{ - int convres; - int satres; - int usr; - - asm("r2 = usr\n\t" - "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */ - "r2 = clrbit(r2, #1)\n\t" /* clear FP invalid bit */ - "usr = r2\n\t" - "{\n\t" - " %0 = convert_sf2uw(%3):chop\n\t" - " %1 = satb(%4)\n\t" - "}\n\t" - "%2 = usr\n\t" - : "=r"(convres), "=r"(satres), "=r"(usr) - : "r"(0x6a051b86), "r"(0x0410eec0) - : "r2", "usr"); - - check(convres, 0xffffffff); - check(satres, 0x7f); - check(get_usr_overflow(usr), 1); - check(get_usr_fp_invalid(usr), 1); - - asm("r2 = usr\n\t" - "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */ - "usr = r2\n\t" - "%2 = r2\n\t" - "p3 = sp3loop0(1f, #1)\n\t" - "1:\n\t" - "{\n\t" - " %0 = satb(%2)\n\t" - "}:endloop0\n\t" - "%1 = usr\n\t" - : "=r"(satres), "=r"(usr) - : "r"(0x0410eec0) - : "r2", "usr", "p3", "sa0", "lc0"); - - check(satres, 0x7f); - check(get_usr_overflow(usr), 1); - check(get_usr_lpcfg(usr), 2); -} - -int main() -{ - struct sigaction act; - int ovf; - - /* SIGSEGV test */ - act.sa_sigaction = sig_segv; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &act, NULL); - if (setjmp(jmp_env) == 0) { - satub(300, 0, &ovf); - } - - act.sa_handler = SIG_DFL; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - - check(usr_overflow, 0); - - test_packet(); - - puts(err ? "FAIL" : "PASS"); - return err ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/tests/tcg/hexagon/preg_alias.c b/tests/tcg/hexagon/preg_alias.c deleted file mode 100644 index b44a8112b477..000000000000 --- a/tests/tcg/hexagon/preg_alias.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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 - * 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 . - */ - -#include - -static inline int preg_alias(int v0, int v1, int v2, int v3) -{ - int ret; - asm volatile("p0 = %1\n\t" - "p1 = %2\n\t" - "p2 = %3\n\t" - "p3 = %4\n\t" - "%0 = C4\n" - : "=r"(ret) - : "r"(v0), "r"(v1), "r"(v2), "r"(v3) - : "p0", "p1", "p2", "p3"); - return ret; -} - -static inline int preg_alias_pair(int v0, int v1, int v2, int v3) -{ - long long c54; - asm volatile("p0 = %1\n\t" - "p1 = %2\n\t" - "p2 = %3\n\t" - "p3 = %4\n\t" - "%0 = C5:4\n" - : "=r"(c54) - : "r"(v0), "r"(v1), "r"(v2), "r"(v3) - : "p0", "p1", "p2", "p3"); - return (int)c54; -} - -typedef union { - int creg; - struct { - unsigned char p0; - unsigned char p1; - unsigned char p2; - unsigned char p3; - } pregs; -} PRegs; - -static inline void creg_alias(int cval, PRegs *pregs) -{ - asm("c4 = %4\n\t" - "%0 = p0\n\t" - "%1 = p1\n\t" - "%2 = p2\n\t" - "%3 = p3\n\t" - : "=r"(pregs->pregs.p0), "=r"(pregs->pregs.p1), - "=r"(pregs->pregs.p2), "=r"(pregs->pregs.p3) - : "r"(cval) - : "p0", "p1", "p2", "p3"); -} - -int err; - -static void check(int val, int expect) -{ - if (val != expect) { - printf("ERROR: 0x%08x != 0x%08x\n", val, expect); - err++; - } -} - -static inline void creg_alias_pair(unsigned int cval, PRegs *pregs) -{ - unsigned long long cval_pair = (0xdeadbeefULL << 32) | cval; - int c5; - - asm ("c5:4 = %5\n\t" - "%0 = p0\n\t" - "%1 = p1\n\t" - "%2 = p2\n\t" - "%3 = p3\n\t" - "%4 = c5\n\t" - : "=r"(pregs->pregs.p0), "=r"(pregs->pregs.p1), - "=r"(pregs->pregs.p2), "=r"(pregs->pregs.p3), "=r"(c5) - : "r"(cval_pair) - : "p0", "p1", "p2", "p3"); - - check(c5, 0xdeadbeef); -} - -static void test_packet(void) -{ - /* - * Test that setting c4 inside a packet doesn't impact the predicates - * that are read during the packet. - */ - - int result; - int old_val = 0x0000001c; - - /* Test a predicated register transfer */ - result = old_val; - asm ( - "c4 = %1\n\t" - "{\n\t" - " c4 = %2\n\t" - " if (!p2) %0 = %3\n\t" - "}\n\t" - : "+r"(result) - : "r"(0xffffffff), "r"(0xff00ffff), "r"(0x837ed653) - : "p0", "p1", "p2", "p3"); - check(result, old_val); - - /* Test a predicated store */ - result = 0xffffffff; - asm ("c4 = %0\n\t" - "{\n\t" - " c4 = %1\n\t" - " if (!p2) memw(%2) = #0\n\t" - "}\n\t" - : - : "r"(0), "r"(0xffffffff), "r"(&result) - : "p0", "p1", "p2", "p3", "memory"); - check(result, 0x0); -} - -int main() -{ - int c4; - PRegs pregs; - - c4 = preg_alias(0xff, 0x00, 0xff, 0x00); - check(c4, 0x00ff00ff); - c4 = preg_alias(0xff, 0x00, 0x00, 0x00); - check(c4, 0x000000ff); - c4 = preg_alias(0x00, 0xff, 0x00, 0x00); - check(c4, 0x0000ff00); - c4 = preg_alias(0x00, 0x00, 0xff, 0x00); - check(c4, 0x00ff0000); - c4 = preg_alias(0x00, 0x00, 0x00, 0xff); - check(c4, 0xff000000); - c4 = preg_alias(0xff, 0xff, 0xff, 0xff); - check(c4, 0xffffffff); - - c4 = preg_alias_pair(0xff, 0x00, 0xff, 0x00); - check(c4, 0x00ff00ff); - c4 = preg_alias_pair(0xff, 0x00, 0x00, 0x00); - check(c4, 0x000000ff); - c4 = preg_alias_pair(0x00, 0xff, 0x00, 0x00); - check(c4, 0x0000ff00); - c4 = preg_alias_pair(0x00, 0x00, 0xff, 0x00); - check(c4, 0x00ff0000); - c4 = preg_alias_pair(0x00, 0x00, 0x00, 0xff); - check(c4, 0xff000000); - c4 = preg_alias_pair(0xff, 0xff, 0xff, 0xff); - check(c4, 0xffffffff); - - creg_alias(0x00ff00ff, &pregs); - check(pregs.creg, 0x00ff00ff); - creg_alias(0x00ffff00, &pregs); - check(pregs.creg, 0x00ffff00); - creg_alias(0x00000000, &pregs); - check(pregs.creg, 0x00000000); - creg_alias(0xff000000, &pregs); - check(pregs.creg, 0xff000000); - creg_alias(0x00ff0000, &pregs); - check(pregs.creg, 0x00ff0000); - creg_alias(0x0000ff00, &pregs); - check(pregs.creg, 0x0000ff00); - creg_alias(0x000000ff, &pregs); - check(pregs.creg, 0x000000ff); - creg_alias(0xffffffff, &pregs); - check(pregs.creg, 0xffffffff); - - creg_alias_pair(0x00ff00ff, &pregs); - check(pregs.creg, 0x00ff00ff); - creg_alias_pair(0x00ffff00, &pregs); - check(pregs.creg, 0x00ffff00); - creg_alias_pair(0x00000000, &pregs); - check(pregs.creg, 0x00000000); - creg_alias_pair(0xff000000, &pregs); - check(pregs.creg, 0xff000000); - creg_alias_pair(0x00ff0000, &pregs); - check(pregs.creg, 0x00ff0000); - creg_alias_pair(0x0000ff00, &pregs); - check(pregs.creg, 0x0000ff00); - creg_alias_pair(0x000000ff, &pregs); - check(pregs.creg, 0x000000ff); - creg_alias_pair(0xffffffff, &pregs); - check(pregs.creg, 0xffffffff); - - test_packet(); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/scatter_gather.c b/tests/tcg/hexagon/scatter_gather.c deleted file mode 100644 index b93eb1813393..000000000000 --- a/tests/tcg/hexagon/scatter_gather.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -/* - * This example tests the HVX scatter/gather instructions - * - * See section 5.13 of the V68 HVX Programmer's Reference - * - * There are 3 main classes operations - * _16 16-bit elements and 16-bit offsets - * _32 32-bit elements and 32-bit offsets - * _16_32 16-bit elements and 32-bit offsets - * - * There are also masked and accumulate versions - */ - -#include -#include -#include -#include - -typedef long HVX_Vector __attribute__((__vector_size__(128))) - __attribute__((aligned(128))); -typedef long HVX_VectorPair __attribute__((__vector_size__(256))) - __attribute__((aligned(128))); -typedef long HVX_VectorPred __attribute__((__vector_size__(128))) - __attribute__((aligned(128))); - -#define VSCATTER_16(BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermh_128B((int)BASE, RGN, OFF, VALS) -#define VSCATTER_16_MASKED(MASK, BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermhq_128B(MASK, (int)BASE, RGN, OFF, VALS) -#define VSCATTER_32(BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermw_128B((int)BASE, RGN, OFF, VALS) -#define VSCATTER_32_MASKED(MASK, BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermwq_128B(MASK, (int)BASE, RGN, OFF, VALS) -#define VSCATTER_16_32(BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermhw_128B((int)BASE, RGN, OFF, VALS) -#define VSCATTER_16_32_MASKED(MASK, BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermhwq_128B(MASK, (int)BASE, RGN, OFF, VALS) -#define VSCATTER_16_ACC(BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermh_add_128B((int)BASE, RGN, OFF, VALS) -#define VSCATTER_32_ACC(BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermw_add_128B((int)BASE, RGN, OFF, VALS) -#define VSCATTER_16_32_ACC(BASE, RGN, OFF, VALS) \ - __builtin_HEXAGON_V6_vscattermhw_add_128B((int)BASE, RGN, OFF, VALS) - -#define VGATHER_16(DSTADDR, BASE, RGN, OFF) \ - __builtin_HEXAGON_V6_vgathermh_128B(DSTADDR, (int)BASE, RGN, OFF) -#define VGATHER_16_MASKED(DSTADDR, MASK, BASE, RGN, OFF) \ - __builtin_HEXAGON_V6_vgathermhq_128B(DSTADDR, MASK, (int)BASE, RGN, OFF) -#define VGATHER_32(DSTADDR, BASE, RGN, OFF) \ - __builtin_HEXAGON_V6_vgathermw_128B(DSTADDR, (int)BASE, RGN, OFF) -#define VGATHER_32_MASKED(DSTADDR, MASK, BASE, RGN, OFF) \ - __builtin_HEXAGON_V6_vgathermwq_128B(DSTADDR, MASK, (int)BASE, RGN, OFF) -#define VGATHER_16_32(DSTADDR, BASE, RGN, OFF) \ - __builtin_HEXAGON_V6_vgathermhw_128B(DSTADDR, (int)BASE, RGN, OFF) -#define VGATHER_16_32_MASKED(DSTADDR, MASK, BASE, RGN, OFF) \ - __builtin_HEXAGON_V6_vgathermhwq_128B(DSTADDR, MASK, (int)BASE, RGN, OFF) - -#define VSHUFF_H(V) \ - __builtin_HEXAGON_V6_vshuffh_128B(V) -#define VSPLAT_H(X) \ - __builtin_HEXAGON_V6_lvsplath_128B(X) -#define VAND_VAL(PRED, VAL) \ - __builtin_HEXAGON_V6_vandvrt_128B(PRED, VAL) -#define VDEAL_H(V) \ - __builtin_HEXAGON_V6_vdealh_128B(V) - -int err; - -/* define the number of rows/cols in a square matrix */ -#define MATRIX_SIZE 64 - -/* define the size of the scatter buffer */ -#define SCATTER_BUFFER_SIZE (MATRIX_SIZE * MATRIX_SIZE) - -/* fake vtcm - put buffers together and force alignment */ -static struct { - unsigned short vscatter16[SCATTER_BUFFER_SIZE]; - unsigned short vgather16[MATRIX_SIZE]; - unsigned int vscatter32[SCATTER_BUFFER_SIZE]; - unsigned int vgather32[MATRIX_SIZE]; - unsigned short vscatter16_32[SCATTER_BUFFER_SIZE]; - unsigned short vgather16_32[MATRIX_SIZE]; -} vtcm __attribute__((aligned(0x10000))); - -/* declare the arrays of reference values */ -unsigned short vscatter16_ref[SCATTER_BUFFER_SIZE]; -unsigned short vgather16_ref[MATRIX_SIZE]; -unsigned int vscatter32_ref[SCATTER_BUFFER_SIZE]; -unsigned int vgather32_ref[MATRIX_SIZE]; -unsigned short vscatter16_32_ref[SCATTER_BUFFER_SIZE]; -unsigned short vgather16_32_ref[MATRIX_SIZE]; - -/* declare the arrays of offsets */ -unsigned short half_offsets[MATRIX_SIZE]; -unsigned int word_offsets[MATRIX_SIZE]; - -/* declare the arrays of values */ -unsigned short half_values[MATRIX_SIZE]; -unsigned short half_values_acc[MATRIX_SIZE]; -unsigned short half_values_masked[MATRIX_SIZE]; -unsigned int word_values[MATRIX_SIZE]; -unsigned int word_values_acc[MATRIX_SIZE]; -unsigned int word_values_masked[MATRIX_SIZE]; - -/* declare the arrays of predicates */ -unsigned short half_predicates[MATRIX_SIZE]; -unsigned int word_predicates[MATRIX_SIZE]; - -/* make this big enough for all the intrinsics */ -const size_t region_len = sizeof(vtcm); - -/* optionally add sync instructions */ -#define SYNC_VECTOR 1 - -static void sync_scatter(void *addr) -{ -#if SYNC_VECTOR - /* - * Do the scatter release followed by a dummy load to complete the - * synchronization. Normally the dummy load would be deferred as - * long as possible to minimize stalls. - */ - asm volatile("vmem(%0 + #0):scatter_release\n" : : "r"(addr)); - /* use volatile to force the load */ - volatile HVX_Vector vDummy = *(HVX_Vector *)addr; vDummy = vDummy; -#endif -} - -static void sync_gather(void *addr) -{ -#if SYNC_VECTOR - /* use volatile to force the load */ - volatile HVX_Vector vDummy = *(HVX_Vector *)addr; vDummy = vDummy; -#endif -} - -/* optionally print the results */ -#define PRINT_DATA 0 - -#define FILL_CHAR '.' - -/* fill vtcm scratch with ee */ -void prefill_vtcm_scratch(void) -{ - memset(&vtcm, FILL_CHAR, sizeof(vtcm)); -} - -/* create byte offsets to be a diagonal of the matrix with 16 bit elements */ -void create_offsets_values_preds_16(void) -{ - unsigned short half_element = 0; - unsigned short half_element_masked = 0; - char letter = 'A'; - char letter_masked = '@'; - - for (int i = 0; i < MATRIX_SIZE; i++) { - half_offsets[i] = i * (2 * MATRIX_SIZE + 2); - - half_element = 0; - half_element_masked = 0; - for (int j = 0; j < 2; j++) { - half_element |= letter << j * 8; - half_element_masked |= letter_masked << j * 8; - } - - half_values[i] = half_element; - half_values_acc[i] = ((i % 10) << 8) + (i % 10); - half_values_masked[i] = half_element_masked; - - letter++; - /* reset to 'A' */ - if (letter == 'M') { - letter = 'A'; - } - - half_predicates[i] = (i % 3 == 0 || i % 5 == 0) ? ~0 : 0; - } -} - -/* create byte offsets to be a diagonal of the matrix with 32 bit elements */ -void create_offsets_values_preds_32(void) -{ - unsigned int word_element = 0; - unsigned int word_element_masked = 0; - char letter = 'A'; - char letter_masked = '&'; - - for (int i = 0; i < MATRIX_SIZE; i++) { - word_offsets[i] = i * (4 * MATRIX_SIZE + 4); - - word_element = 0; - word_element_masked = 0; - for (int j = 0; j < 4; j++) { - word_element |= letter << j * 8; - word_element_masked |= letter_masked << j * 8; - } - - word_values[i] = word_element; - word_values_acc[i] = ((i % 10) << 8) + (i % 10); - word_values_masked[i] = word_element_masked; - - letter++; - /* reset to 'A' */ - if (letter == 'M') { - letter = 'A'; - } - - word_predicates[i] = (i % 4 == 0 || i % 7 == 0) ? ~0 : 0; - } -} - -/* - * create byte offsets to be a diagonal of the matrix with 16 bit elements - * and 32 bit offsets - */ -void create_offsets_values_preds_16_32(void) -{ - unsigned short half_element = 0; - unsigned short half_element_masked = 0; - char letter = 'D'; - char letter_masked = '$'; - - for (int i = 0; i < MATRIX_SIZE; i++) { - word_offsets[i] = i * (2 * MATRIX_SIZE + 2); - - half_element = 0; - half_element_masked = 0; - for (int j = 0; j < 2; j++) { - half_element |= letter << j * 8; - half_element_masked |= letter_masked << j * 8; - } - - half_values[i] = half_element; - half_values_acc[i] = ((i % 10) << 8) + (i % 10); - half_values_masked[i] = half_element_masked; - - letter++; - /* reset to 'A' */ - if (letter == 'P') { - letter = 'D'; - } - - half_predicates[i] = (i % 2 == 0 || i % 13 == 0) ? ~0 : 0; - } -} - -/* scatter the 16 bit elements using intrinsics */ -void vector_scatter_16(void) -{ - /* copy the offsets and values to vectors */ - HVX_Vector offsets = *(HVX_Vector *)half_offsets; - HVX_Vector values = *(HVX_Vector *)half_values; - - VSCATTER_16(&vtcm.vscatter16, region_len, offsets, values); - - sync_scatter(vtcm.vscatter16); -} - -/* scatter-accumulate the 16 bit elements using intrinsics */ -void vector_scatter_16_acc(void) -{ - /* copy the offsets and values to vectors */ - HVX_Vector offsets = *(HVX_Vector *)half_offsets; - HVX_Vector values = *(HVX_Vector *)half_values_acc; - - VSCATTER_16_ACC(&vtcm.vscatter16, region_len, offsets, values); - - sync_scatter(vtcm.vscatter16); -} - -/* scatter the 16 bit elements using intrinsics */ -void vector_scatter_16_masked(void) -{ - /* copy the offsets and values to vectors */ - HVX_Vector offsets = *(HVX_Vector *)half_offsets; - HVX_Vector values = *(HVX_Vector *)half_values_masked; - HVX_Vector pred_reg = *(HVX_Vector *)half_predicates; - HVX_VectorPred preds = VAND_VAL(pred_reg, ~0); - - VSCATTER_16_MASKED(preds, &vtcm.vscatter16, region_len, offsets, values); - - sync_scatter(vtcm.vscatter16); -} - -/* scatter the 32 bit elements using intrinsics */ -void vector_scatter_32(void) -{ - /* copy the offsets and values to vectors */ - HVX_Vector offsetslo = *(HVX_Vector *)word_offsets; - HVX_Vector offsetshi = *(HVX_Vector *)&word_offsets[MATRIX_SIZE / 2]; - HVX_Vector valueslo = *(HVX_Vector *)word_values; - HVX_Vector valueshi = *(HVX_Vector *)&word_values[MATRIX_SIZE / 2]; - - VSCATTER_32(&vtcm.vscatter32, region_len, offsetslo, valueslo); - VSCATTER_32(&vtcm.vscatter32, region_len, offsetshi, valueshi); - - sync_scatter(vtcm.vscatter32); -} - -/* scatter-acc the 32 bit elements using intrinsics */ -void vector_scatter_32_acc(void) -{ - /* copy the offsets and values to vectors */ - HVX_Vector offsetslo = *(HVX_Vector *)word_offsets; - HVX_Vector offsetshi = *(HVX_Vector *)&word_offsets[MATRIX_SIZE / 2]; - HVX_Vector valueslo = *(HVX_Vector *)word_values_acc; - HVX_Vector valueshi = *(HVX_Vector *)&word_values_acc[MATRIX_SIZE / 2]; - - VSCATTER_32_ACC(&vtcm.vscatter32, region_len, offsetslo, valueslo); - VSCATTER_32_ACC(&vtcm.vscatter32, region_len, offsetshi, valueshi); - - sync_scatter(vtcm.vscatter32); -} - -/* scatter the 32 bit elements using intrinsics */ -void vector_scatter_32_masked(void) -{ - /* copy the offsets and values to vectors */ - HVX_Vector offsetslo = *(HVX_Vector *)word_offsets; - HVX_Vector offsetshi = *(HVX_Vector *)&word_offsets[MATRIX_SIZE / 2]; - HVX_Vector valueslo = *(HVX_Vector *)word_values_masked; - HVX_Vector valueshi = *(HVX_Vector *)&word_values_masked[MATRIX_SIZE / 2]; - HVX_Vector pred_reglo = *(HVX_Vector *)word_predicates; - HVX_Vector pred_reghi = *(HVX_Vector *)&word_predicates[MATRIX_SIZE / 2]; - HVX_VectorPred predslo = VAND_VAL(pred_reglo, ~0); - HVX_VectorPred predshi = VAND_VAL(pred_reghi, ~0); - - VSCATTER_32_MASKED(predslo, &vtcm.vscatter32, region_len, offsetslo, - valueslo); - VSCATTER_32_MASKED(predshi, &vtcm.vscatter32, region_len, offsetshi, - valueshi); - - sync_scatter(vtcm.vscatter16); -} - -/* scatter the 16 bit elements with 32 bit offsets using intrinsics */ -void vector_scatter_16_32(void) -{ - HVX_VectorPair offsets; - HVX_Vector values; - - /* get the word offsets in a vector pair */ - offsets = *(HVX_VectorPair *)word_offsets; - - /* these values need to be shuffled for the scatter */ - values = *(HVX_Vector *)half_values; - values = VSHUFF_H(values); - - VSCATTER_16_32(&vtcm.vscatter16_32, region_len, offsets, values); - - sync_scatter(vtcm.vscatter16_32); -} - -/* scatter-acc the 16 bit elements with 32 bit offsets using intrinsics */ -void vector_scatter_16_32_acc(void) -{ - HVX_VectorPair offsets; - HVX_Vector values; - - /* get the word offsets in a vector pair */ - offsets = *(HVX_VectorPair *)word_offsets; - - /* these values need to be shuffled for the scatter */ - values = *(HVX_Vector *)half_values_acc; - values = VSHUFF_H(values); - - VSCATTER_16_32_ACC(&vtcm.vscatter16_32, region_len, offsets, values); - - sync_scatter(vtcm.vscatter16_32); -} - -/* masked scatter the 16 bit elements with 32 bit offsets using intrinsics */ -void vector_scatter_16_32_masked(void) -{ - HVX_VectorPair offsets; - HVX_Vector values; - HVX_Vector pred_reg; - - /* get the word offsets in a vector pair */ - offsets = *(HVX_VectorPair *)word_offsets; - - /* these values need to be shuffled for the scatter */ - values = *(HVX_Vector *)half_values_masked; - values = VSHUFF_H(values); - - pred_reg = *(HVX_Vector *)half_predicates; - pred_reg = VSHUFF_H(pred_reg); - HVX_VectorPred preds = VAND_VAL(pred_reg, ~0); - - VSCATTER_16_32_MASKED(preds, &vtcm.vscatter16_32, region_len, offsets, - values); - - sync_scatter(vtcm.vscatter16_32); -} - -/* gather the elements from the scatter16 buffer */ -void vector_gather_16(void) -{ - HVX_Vector *vgather = (HVX_Vector *)&vtcm.vgather16; - HVX_Vector offsets = *(HVX_Vector *)half_offsets; - - VGATHER_16(vgather, &vtcm.vscatter16, region_len, offsets); - - sync_gather(vgather); -} - -static unsigned short gather_16_masked_init(void) -{ - char letter = '?'; - return letter | (letter << 8); -} - -void vector_gather_16_masked(void) -{ - HVX_Vector *vgather = (HVX_Vector *)&vtcm.vgather16; - HVX_Vector offsets = *(HVX_Vector *)half_offsets; - HVX_Vector pred_reg = *(HVX_Vector *)half_predicates; - HVX_VectorPred preds = VAND_VAL(pred_reg, ~0); - - *vgather = VSPLAT_H(gather_16_masked_init()); - VGATHER_16_MASKED(vgather, preds, &vtcm.vscatter16, region_len, offsets); - - sync_gather(vgather); -} - -/* gather the elements from the scatter32 buffer */ -void vector_gather_32(void) -{ - HVX_Vector *vgatherlo = (HVX_Vector *)&vtcm.vgather32; - HVX_Vector *vgatherhi = - (HVX_Vector *)((int)&vtcm.vgather32 + (MATRIX_SIZE * 2)); - HVX_Vector offsetslo = *(HVX_Vector *)word_offsets; - HVX_Vector offsetshi = *(HVX_Vector *)&word_offsets[MATRIX_SIZE / 2]; - - VGATHER_32(vgatherlo, &vtcm.vscatter32, region_len, offsetslo); - VGATHER_32(vgatherhi, &vtcm.vscatter32, region_len, offsetshi); - - sync_gather(vgatherhi); -} - -static unsigned int gather_32_masked_init(void) -{ - char letter = '?'; - return letter | (letter << 8) | (letter << 16) | (letter << 24); -} - -void vector_gather_32_masked(void) -{ - HVX_Vector *vgatherlo = (HVX_Vector *)&vtcm.vgather32; - HVX_Vector *vgatherhi = - (HVX_Vector *)((int)&vtcm.vgather32 + (MATRIX_SIZE * 2)); - HVX_Vector offsetslo = *(HVX_Vector *)word_offsets; - HVX_Vector offsetshi = *(HVX_Vector *)&word_offsets[MATRIX_SIZE / 2]; - HVX_Vector pred_reglo = *(HVX_Vector *)word_predicates; - HVX_VectorPred predslo = VAND_VAL(pred_reglo, ~0); - HVX_Vector pred_reghi = *(HVX_Vector *)&word_predicates[MATRIX_SIZE / 2]; - HVX_VectorPred predshi = VAND_VAL(pred_reghi, ~0); - - *vgatherlo = VSPLAT_H(gather_32_masked_init()); - *vgatherhi = VSPLAT_H(gather_32_masked_init()); - VGATHER_32_MASKED(vgatherlo, predslo, &vtcm.vscatter32, region_len, - offsetslo); - VGATHER_32_MASKED(vgatherhi, predshi, &vtcm.vscatter32, region_len, - offsetshi); - - sync_gather(vgatherlo); - sync_gather(vgatherhi); -} - -/* gather the elements from the scatter16_32 buffer */ -void vector_gather_16_32(void) -{ - HVX_Vector *vgather; - HVX_VectorPair offsets; - HVX_Vector values; - - /* get the vtcm address to gather from */ - vgather = (HVX_Vector *)&vtcm.vgather16_32; - - /* get the word offsets in a vector pair */ - offsets = *(HVX_VectorPair *)word_offsets; - - VGATHER_16_32(vgather, &vtcm.vscatter16_32, region_len, offsets); - - /* deal the elements to get the order back */ - values = *(HVX_Vector *)vgather; - values = VDEAL_H(values); - - /* write it back to vtcm address */ - *(HVX_Vector *)vgather = values; -} - -void vector_gather_16_32_masked(void) -{ - HVX_Vector *vgather; - HVX_VectorPair offsets; - HVX_Vector pred_reg; - HVX_VectorPred preds; - HVX_Vector values; - - /* get the vtcm address to gather from */ - vgather = (HVX_Vector *)&vtcm.vgather16_32; - - /* get the word offsets in a vector pair */ - offsets = *(HVX_VectorPair *)word_offsets; - pred_reg = *(HVX_Vector *)half_predicates; - pred_reg = VSHUFF_H(pred_reg); - preds = VAND_VAL(pred_reg, ~0); - - *vgather = VSPLAT_H(gather_16_masked_init()); - VGATHER_16_32_MASKED(vgather, preds, &vtcm.vscatter16_32, region_len, - offsets); - - /* deal the elements to get the order back */ - values = *(HVX_Vector *)vgather; - values = VDEAL_H(values); - - /* write it back to vtcm address */ - *(HVX_Vector *)vgather = values; -} - -static void check_buffer(const char *name, void *c, void *r, size_t size) -{ - char *check = (char *)c; - char *ref = (char *)r; - for (int i = 0; i < size; i++) { - if (check[i] != ref[i]) { - printf("ERROR %s [%d]: 0x%x (%c) != 0x%x (%c)\n", name, i, - check[i], check[i], ref[i], ref[i]); - err++; - } - } -} - -/* - * These scalar functions are the C equivalents of the vector functions that - * use HVX - */ - -/* scatter the 16 bit elements using C */ -void scalar_scatter_16(unsigned short *vscatter16) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vscatter16[half_offsets[i] / 2] = half_values[i]; - } -} - -void check_scatter_16() -{ - memset(vscatter16_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); - scalar_scatter_16(vscatter16_ref); - check_buffer(__func__, vtcm.vscatter16, vscatter16_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); -} - -/* scatter the 16 bit elements using C */ -void scalar_scatter_16_acc(unsigned short *vscatter16) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vscatter16[half_offsets[i] / 2] += half_values_acc[i]; - } -} - -void check_scatter_16_acc() -{ - memset(vscatter16_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); - scalar_scatter_16(vscatter16_ref); - scalar_scatter_16_acc(vscatter16_ref); - check_buffer(__func__, vtcm.vscatter16, vscatter16_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); -} - -/* scatter the 16 bit elements using C */ -void scalar_scatter_16_masked(unsigned short *vscatter16) -{ - for (int i = 0; i < MATRIX_SIZE; i++) { - if (half_predicates[i]) { - vscatter16[half_offsets[i] / 2] = half_values_masked[i]; - } - } - -} - -void check_scatter_16_masked() -{ - memset(vscatter16_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); - scalar_scatter_16(vscatter16_ref); - scalar_scatter_16_acc(vscatter16_ref); - scalar_scatter_16_masked(vscatter16_ref); - check_buffer(__func__, vtcm.vscatter16, vscatter16_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); -} - -/* scatter the 32 bit elements using C */ -void scalar_scatter_32(unsigned int *vscatter32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vscatter32[word_offsets[i] / 4] = word_values[i]; - } -} - -void check_scatter_32() -{ - memset(vscatter32_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned int)); - scalar_scatter_32(vscatter32_ref); - check_buffer(__func__, vtcm.vscatter32, vscatter32_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned int)); -} - -/* scatter the 32 bit elements using C */ -void scalar_scatter_32_acc(unsigned int *vscatter32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vscatter32[word_offsets[i] / 4] += word_values_acc[i]; - } -} - -void check_scatter_32_acc() -{ - memset(vscatter32_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned int)); - scalar_scatter_32(vscatter32_ref); - scalar_scatter_32_acc(vscatter32_ref); - check_buffer(__func__, vtcm.vscatter32, vscatter32_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned int)); -} - -/* scatter the 32 bit elements using C */ -void scalar_scatter_32_masked(unsigned int *vscatter32) -{ - for (int i = 0; i < MATRIX_SIZE; i++) { - if (word_predicates[i]) { - vscatter32[word_offsets[i] / 4] = word_values_masked[i]; - } - } -} - -void check_scatter_32_masked() -{ - memset(vscatter32_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned int)); - scalar_scatter_32(vscatter32_ref); - scalar_scatter_32_acc(vscatter32_ref); - scalar_scatter_32_masked(vscatter32_ref); - check_buffer(__func__, vtcm.vscatter32, vscatter32_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned int)); -} - -/* scatter the 32 bit elements using C */ -void scalar_scatter_16_32(unsigned short *vscatter16_32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vscatter16_32[word_offsets[i] / 2] = half_values[i]; - } -} - -void check_scatter_16_32() -{ - memset(vscatter16_32_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); - scalar_scatter_16_32(vscatter16_32_ref); - check_buffer(__func__, vtcm.vscatter16_32, vscatter16_32_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); -} - -/* scatter the 32 bit elements using C */ -void scalar_scatter_16_32_acc(unsigned short *vscatter16_32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vscatter16_32[word_offsets[i] / 2] += half_values_acc[i]; - } -} - -void check_scatter_16_32_acc() -{ - memset(vscatter16_32_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); - scalar_scatter_16_32(vscatter16_32_ref); - scalar_scatter_16_32_acc(vscatter16_32_ref); - check_buffer(__func__, vtcm.vscatter16_32, vscatter16_32_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); -} - -void scalar_scatter_16_32_masked(unsigned short *vscatter16_32) -{ - for (int i = 0; i < MATRIX_SIZE; i++) { - if (half_predicates[i]) { - vscatter16_32[word_offsets[i] / 2] = half_values_masked[i]; - } - } -} - -void check_scatter_16_32_masked() -{ - memset(vscatter16_32_ref, FILL_CHAR, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); - scalar_scatter_16_32(vscatter16_32_ref); - scalar_scatter_16_32_acc(vscatter16_32_ref); - scalar_scatter_16_32_masked(vscatter16_32_ref); - check_buffer(__func__, vtcm.vscatter16_32, vscatter16_32_ref, - SCATTER_BUFFER_SIZE * sizeof(unsigned short)); -} - -/* gather the elements from the scatter buffer using C */ -void scalar_gather_16(unsigned short *vgather16) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vgather16[i] = vtcm.vscatter16[half_offsets[i] / 2]; - } -} - -void check_gather_16() -{ - memset(vgather16_ref, 0, MATRIX_SIZE * sizeof(unsigned short)); - scalar_gather_16(vgather16_ref); - check_buffer(__func__, vtcm.vgather16, vgather16_ref, - MATRIX_SIZE * sizeof(unsigned short)); -} - -void scalar_gather_16_masked(unsigned short *vgather16) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - if (half_predicates[i]) { - vgather16[i] = vtcm.vscatter16[half_offsets[i] / 2]; - } - } -} - -void check_gather_16_masked() -{ - memset(vgather16_ref, gather_16_masked_init(), - MATRIX_SIZE * sizeof(unsigned short)); - scalar_gather_16_masked(vgather16_ref); - check_buffer(__func__, vtcm.vgather16, vgather16_ref, - MATRIX_SIZE * sizeof(unsigned short)); -} - -/* gather the elements from the scatter buffer using C */ -void scalar_gather_32(unsigned int *vgather32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vgather32[i] = vtcm.vscatter32[word_offsets[i] / 4]; - } -} - -void check_gather_32(void) -{ - memset(vgather32_ref, 0, MATRIX_SIZE * sizeof(unsigned int)); - scalar_gather_32(vgather32_ref); - check_buffer(__func__, vtcm.vgather32, vgather32_ref, - MATRIX_SIZE * sizeof(unsigned int)); -} - -void scalar_gather_32_masked(unsigned int *vgather32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - if (word_predicates[i]) { - vgather32[i] = vtcm.vscatter32[word_offsets[i] / 4]; - } - } -} - - -void check_gather_32_masked(void) -{ - memset(vgather32_ref, gather_32_masked_init(), - MATRIX_SIZE * sizeof(unsigned int)); - scalar_gather_32_masked(vgather32_ref); - check_buffer(__func__, vtcm.vgather32, - vgather32_ref, MATRIX_SIZE * sizeof(unsigned int)); -} - -/* gather the elements from the scatter buffer using C */ -void scalar_gather_16_32(unsigned short *vgather16_32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - vgather16_32[i] = vtcm.vscatter16_32[word_offsets[i] / 2]; - } -} - -void check_gather_16_32(void) -{ - memset(vgather16_32_ref, 0, MATRIX_SIZE * sizeof(unsigned short)); - scalar_gather_16_32(vgather16_32_ref); - check_buffer(__func__, vtcm.vgather16_32, vgather16_32_ref, - MATRIX_SIZE * sizeof(unsigned short)); -} - -void scalar_gather_16_32_masked(unsigned short *vgather16_32) -{ - for (int i = 0; i < MATRIX_SIZE; ++i) { - if (half_predicates[i]) { - vgather16_32[i] = vtcm.vscatter16_32[word_offsets[i] / 2]; - } - } - -} - -void check_gather_16_32_masked(void) -{ - memset(vgather16_32_ref, gather_16_masked_init(), - MATRIX_SIZE * sizeof(unsigned short)); - scalar_gather_16_32_masked(vgather16_32_ref); - check_buffer(__func__, vtcm.vgather16_32, vgather16_32_ref, - MATRIX_SIZE * sizeof(unsigned short)); -} - -/* print scatter16 buffer */ -void print_scatter16_buffer(void) -{ - if (PRINT_DATA) { - printf("\n\nPrinting the 16 bit scatter buffer"); - - for (int i = 0; i < SCATTER_BUFFER_SIZE; i++) { - if ((i % MATRIX_SIZE) == 0) { - printf("\n"); - } - for (int j = 0; j < 2; j++) { - printf("%c", (char)((vtcm.vscatter16[i] >> j * 8) & 0xff)); - } - printf(" "); - } - printf("\n"); - } -} - -/* print the gather 16 buffer */ -void print_gather_result_16(void) -{ - if (PRINT_DATA) { - printf("\n\nPrinting the 16 bit gather result\n"); - - for (int i = 0; i < MATRIX_SIZE; i++) { - for (int j = 0; j < 2; j++) { - printf("%c", (char)((vtcm.vgather16[i] >> j * 8) & 0xff)); - } - printf(" "); - } - printf("\n"); - } -} - -/* print the scatter32 buffer */ -void print_scatter32_buffer(void) -{ - if (PRINT_DATA) { - printf("\n\nPrinting the 32 bit scatter buffer"); - - for (int i = 0; i < SCATTER_BUFFER_SIZE; i++) { - if ((i % MATRIX_SIZE) == 0) { - printf("\n"); - } - for (int j = 0; j < 4; j++) { - printf("%c", (char)((vtcm.vscatter32[i] >> j * 8) & 0xff)); - } - printf(" "); - } - printf("\n"); - } -} - -/* print the gather 32 buffer */ -void print_gather_result_32(void) -{ - if (PRINT_DATA) { - printf("\n\nPrinting the 32 bit gather result\n"); - - for (int i = 0; i < MATRIX_SIZE; i++) { - for (int j = 0; j < 4; j++) { - printf("%c", (char)((vtcm.vgather32[i] >> j * 8) & 0xff)); - } - printf(" "); - } - printf("\n"); - } -} - -/* print the scatter16_32 buffer */ -void print_scatter16_32_buffer(void) -{ - if (PRINT_DATA) { - printf("\n\nPrinting the 16_32 bit scatter buffer"); - - for (int i = 0; i < SCATTER_BUFFER_SIZE; i++) { - if ((i % MATRIX_SIZE) == 0) { - printf("\n"); - } - for (int j = 0; j < 2; j++) { - printf("%c", - (unsigned char)((vtcm.vscatter16_32[i] >> j * 8) & 0xff)); - } - printf(" "); - } - printf("\n"); - } -} - -/* print the gather 16_32 buffer */ -void print_gather_result_16_32(void) -{ - if (PRINT_DATA) { - printf("\n\nPrinting the 16_32 bit gather result\n"); - - for (int i = 0; i < MATRIX_SIZE; i++) { - for (int j = 0; j < 2; j++) { - printf("%c", - (unsigned char)((vtcm.vgather16_32[i] >> j * 8) & 0xff)); - } - printf(" "); - } - printf("\n"); - } -} - -int main() -{ - prefill_vtcm_scratch(); - - /* 16 bit elements with 16 bit offsets */ - create_offsets_values_preds_16(); - - vector_scatter_16(); - print_scatter16_buffer(); - check_scatter_16(); - - vector_gather_16(); - print_gather_result_16(); - check_gather_16(); - - vector_gather_16_masked(); - print_gather_result_16(); - check_gather_16_masked(); - - vector_scatter_16_acc(); - print_scatter16_buffer(); - check_scatter_16_acc(); - - vector_scatter_16_masked(); - print_scatter16_buffer(); - check_scatter_16_masked(); - - /* 32 bit elements with 32 bit offsets */ - create_offsets_values_preds_32(); - - vector_scatter_32(); - print_scatter32_buffer(); - check_scatter_32(); - - vector_gather_32(); - print_gather_result_32(); - check_gather_32(); - - vector_gather_32_masked(); - print_gather_result_32(); - check_gather_32_masked(); - - vector_scatter_32_acc(); - print_scatter32_buffer(); - check_scatter_32_acc(); - - vector_scatter_32_masked(); - print_scatter32_buffer(); - check_scatter_32_masked(); - - /* 16 bit elements with 32 bit offsets */ - create_offsets_values_preds_16_32(); - - vector_scatter_16_32(); - print_scatter16_32_buffer(); - check_scatter_16_32(); - - vector_gather_16_32(); - print_gather_result_16_32(); - check_gather_16_32(); - - vector_gather_16_32_masked(); - print_gather_result_16_32(); - check_gather_16_32_masked(); - - vector_scatter_16_32_acc(); - print_scatter16_32_buffer(); - check_scatter_16_32_acc(); - - vector_scatter_16_32_masked(); - print_scatter16_32_buffer(); - check_scatter_16_32_masked(); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/usr.c b/tests/tcg/hexagon/usr.c deleted file mode 100644 index a531511cecb0..000000000000 --- a/tests/tcg/hexagon/usr.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * Copyright(c) 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 - * 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 . - */ - -/* - * Test instructions that might set bits in user status register (USR) - */ - -#include -#include - -int err; - -static void __check(int line, uint32_t val, uint32_t expect) -{ - if (val != expect) { - printf("ERROR at line %d: %d != %d\n", line, val, expect); - err++; - } -} - -#define check(RES, EXP) __check(__LINE__, RES, EXP) - -static void __check32(int line, uint32_t val, uint32_t expect) -{ - if (val != expect) { - printf("ERROR at line %d: 0x%08x != 0x%08x\n", line, val, expect); - err++; - } -} - -#define check32(RES, EXP) __check32(__LINE__, RES, EXP) - -static void __check64(int line, uint64_t val, uint64_t expect) -{ - if (val != expect) { - printf("ERROR at line %d: 0x%016llx != 0x%016llx\n", line, val, expect); - err++; - } -} - -#define check64(RES, EXP) __check64(__LINE__, RES, EXP) - -/* - * Some of the instructions tested are only available on certain versions - * of the Hexagon core - */ -#define CORE_HAS_AUDIO (__HEXAGON_ARCH__ >= 67 && defined(__HEXAGON_AUDIO__)) -#define CORE_IS_V67 (__HEXAGON_ARCH__ >= 67) - -/* Define the bits in Hexagon USR register */ -#define USR_OVF_BIT 0 /* Sticky saturation overflow */ -#define USR_FPINVF_BIT 1 /* IEEE FP invalid sticky flag */ -#define USR_FPDBZF_BIT 2 /* IEEE FP divide-by-zero sticky flag */ -#define USR_FPOVFF_BIT 3 /* IEEE FP overflow sticky flag */ -#define USR_FPUNFF_BIT 4 /* IEEE FP underflow sticky flag */ -#define USR_FPINPF_BIT 5 /* IEEE FP inexact sticky flag */ - -/* Corresponding values in USR */ -#define USR_CLEAR 0 -#define USR_OVF (1 << USR_OVF_BIT) -#define USR_FPINVF (1 << USR_FPINVF_BIT) -#define USR_FPDBZF (1 << USR_FPDBZF_BIT) -#define USR_FPOVFF (1 << USR_FPOVFF_BIT) -#define USR_FPUNFF (1 << USR_FPUNFF_BIT) -#define USR_FPINPF (1 << USR_FPINPF_BIT) - -/* Some useful floating point values */ -const uint32_t SF_INF = 0x7f800000; -const uint32_t SF_QNaN = 0x7fc00000; -const uint32_t SF_SNaN = 0x7fb00000; -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_one = 0x3f800000; -const uint32_t SF_one_recip = 0x3f7f0001; /* 0.9960... */ -const uint32_t SF_one_invsqrta = 0x3f7f0000; /* 0.99609375 */ -const uint32_t SF_two = 0x40000000; -const uint32_t SF_four = 0x40800000; -const uint32_t SF_small_neg = 0xab98fba8; -const uint32_t SF_large_pos = 0x5afa572e; - -const uint64_t DF_QNaN = 0x7ff8000000000000ULL; -const uint64_t DF_SNaN = 0x7ff7000000000000ULL; -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_any = 0x3f80000000000000ULL; -const uint64_t DF_one = 0x3ff0000000000000ULL; -const uint64_t DF_one_hh = 0x3ff001ff80000000ULL; /* 1.00048... */ -const uint64_t DF_small_neg = 0xbd731f7500000000ULL; -const uint64_t DF_large_pos = 0x7f80000000000001ULL; - -/* - * Templates for functions to execute an instruction - * - * The templates vary by the number of arguments and the types of the args - * and result. We use one letter in the macro name for the result and each - * argument: - * x unknown (specified in a subsequent template) or don't care - * R register (32 bits) - * P pair (64 bits) - * p predicate - * I immediate - * Xx read/write - */ - -/* Clear bits 0-5 in USR */ -#define CLEAR_USRBITS \ - "r2 = usr\n\t" \ - "r2 = and(r2, #0xffffffc0)\n\t" \ - "usr = r2\n\t" - -/* Template for instructions with one register operand */ -#define FUNC_x_OP_x(RESTYPE, SRCTYPE, NAME, INSN) \ -static RESTYPE NAME(SRCTYPE src, uint32_t *usr_result) \ -{ \ - RESTYPE result; \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = usr\n\t" \ - : "=r"(result), "=r"(usr) \ - : "r"(src) \ - : "r2", "usr"); \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_R_OP_R(NAME, INSN) \ -FUNC_x_OP_x(uint32_t, uint32_t, NAME, INSN) - -#define FUNC_R_OP_P(NAME, INSN) \ -FUNC_x_OP_x(uint32_t, uint64_t, NAME, INSN) - -#define FUNC_P_OP_P(NAME, INSN) \ -FUNC_x_OP_x(uint64_t, uint64_t, NAME, INSN) - -#define FUNC_P_OP_R(NAME, INSN) \ -FUNC_x_OP_x(uint64_t, uint32_t, NAME, INSN) - -/* - * Template for instructions with a register and predicate result - * and one register operand - */ -#define FUNC_xp_OP_x(RESTYPE, SRCTYPE, NAME, INSN) \ -static RESTYPE NAME(SRCTYPE src, uint8_t *pred_result, uint32_t *usr_result) \ -{ \ - RESTYPE result; \ - uint8_t pred; \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = p2\n\t" \ - "%2 = usr\n\t" \ - : "=r"(result), "=r"(pred), "=r"(usr) \ - : "r"(src) \ - : "r2", "p2", "usr"); \ - *pred_result = pred; \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_Rp_OP_R(NAME, INSN) \ -FUNC_xp_OP_x(uint32_t, uint32_t, NAME, INSN) - -/* Template for instructions with two register operands */ -#define FUNC_x_OP_xx(RESTYPE, SRC1TYPE, SRC2TYPE, NAME, INSN) \ -static RESTYPE NAME(SRC1TYPE src1, SRC2TYPE src2, uint32_t *usr_result) \ -{ \ - RESTYPE result; \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = usr\n\t" \ - : "=r"(result), "=r"(usr) \ - : "r"(src1), "r"(src2) \ - : "r2", "usr"); \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_P_OP_PP(NAME, INSN) \ -FUNC_x_OP_xx(uint64_t, uint64_t, uint64_t, NAME, INSN) - -#define FUNC_R_OP_PP(NAME, INSN) \ -FUNC_x_OP_xx(uint32_t, uint64_t, uint64_t, NAME, INSN) - -#define FUNC_P_OP_RR(NAME, INSN) \ -FUNC_x_OP_xx(uint64_t, uint32_t, uint32_t, NAME, INSN) - -#define FUNC_R_OP_RR(NAME, INSN) \ -FUNC_x_OP_xx(uint32_t, uint32_t, uint32_t, NAME, INSN) - -#define FUNC_R_OP_PR(NAME, INSN) \ -FUNC_x_OP_xx(uint32_t, uint64_t, uint32_t, NAME, INSN) - -#define FUNC_P_OP_PR(NAME, INSN) \ -FUNC_x_OP_xx(uint64_t, uint64_t, uint32_t, NAME, INSN) - -/* - * Template for instructions with a register and predicate result - * and two register operands - */ -#define FUNC_xp_OP_xx(RESTYPE, SRC1TYPE, SRC2TYPE, NAME, INSN) \ -static RESTYPE NAME(SRC1TYPE src1, SRC2TYPE src2, \ - uint8_t *pred_result, uint32_t *usr_result) \ -{ \ - RESTYPE result; \ - uint8_t pred; \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = p2\n\t" \ - "%2 = usr\n\t" \ - : "=r"(result), "=r"(pred), "=r"(usr) \ - : "r"(src1), "r"(src2) \ - : "r2", "p2", "usr"); \ - *pred_result = pred; \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_Rp_OP_RR(NAME, INSN) \ -FUNC_xp_OP_xx(uint32_t, uint32_t, uint32_t, NAME, INSN) - -/* Template for instructions with one register and one immediate */ -#define FUNC_x_OP_xI(RESTYPE, SRC1TYPE, NAME, INSN) \ -static RESTYPE NAME(SRC1TYPE src1, int32_t src2, uint32_t *usr_result) \ -{ \ - RESTYPE result; \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = usr\n\t" \ - : "=r"(result), "=r"(usr) \ - : "r"(src1), "i"(src2) \ - : "r2", "usr"); \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_R_OP_RI(NAME, INSN) \ -FUNC_x_OP_xI(uint32_t, uint32_t, NAME, INSN) - -#define FUNC_R_OP_PI(NAME, INSN) \ -FUNC_x_OP_xI(uint32_t, uint64_t, NAME, INSN) - -/* - * Template for instructions with a read/write result - * and two register operands - */ -#define FUNC_Xx_OP_xx(RESTYPE, SRC1TYPE, SRC2TYPE, NAME, INSN) \ -static RESTYPE NAME(RESTYPE result, SRC1TYPE src1, SRC2TYPE src2, \ - uint32_t *usr_result) \ -{ \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = usr\n\t" \ - : "+r"(result), "=r"(usr) \ - : "r"(src1), "r"(src2) \ - : "r2", "usr"); \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_XR_OP_RR(NAME, INSN) \ -FUNC_Xx_OP_xx(uint32_t, uint32_t, uint32_t, NAME, INSN) - -#define FUNC_XP_OP_PP(NAME, INSN) \ -FUNC_Xx_OP_xx(uint64_t, uint64_t, uint64_t, NAME, INSN) - -#define FUNC_XP_OP_RR(NAME, INSN) \ -FUNC_Xx_OP_xx(uint64_t, uint32_t, uint32_t, NAME, INSN) - -/* - * Template for instructions with a read/write result - * and two register operands - */ -#define FUNC_Xxp_OP_xx(RESTYPE, SRC1TYPE, SRC2TYPE, NAME, INSN) \ -static RESTYPE NAME(RESTYPE result, SRC1TYPE src1, SRC2TYPE src2, \ - uint8_t *pred_result, uint32_t *usr_result) \ -{ \ - uint32_t usr; \ - uint8_t pred; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%1 = p2\n\t" \ - "%2 = usr\n\t" \ - : "+r"(result), "=r"(pred), "=r"(usr) \ - : "r"(src1), "r"(src2) \ - : "r2", "usr"); \ - *pred_result = pred; \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_XPp_OP_PP(NAME, INSN) \ -FUNC_Xxp_OP_xx(uint64_t, uint64_t, uint64_t, NAME, INSN) - -/* - * Template for instructions with a read/write result and - * two register and one predicate operands - */ -#define FUNC_Xx_OP_xxp(RESTYPE, SRC1TYPE, SRC2TYPE, NAME, INSN) \ -static RESTYPE NAME(RESTYPE result, SRC1TYPE src1, SRC2TYPE src2, uint8_t pred,\ - uint32_t *usr_result) \ -{ \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - "p2 = %4\n\t" \ - INSN "\n\t" \ - "%1 = usr\n\t" \ - : "+r"(result), "=r"(usr) \ - : "r"(src1), "r"(src2), "r"(pred) \ - : "r2", "p2", "usr"); \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_XR_OP_RRp(NAME, INSN) \ -FUNC_Xx_OP_xxp(uint32_t, uint32_t, uint32_t, NAME, INSN) - -/* Template for compare instructions with two register operands */ -#define FUNC_CMP_xx(SRC1TYPE, SRC2TYPE, NAME, INSN) \ -static uint32_t NAME(SRC1TYPE src1, SRC2TYPE src2, uint32_t *usr_result) \ -{ \ - uint32_t result; \ - uint32_t usr; \ - asm(CLEAR_USRBITS \ - INSN "\n\t" \ - "%0 = p1\n\t" \ - "%1 = usr\n\t" \ - : "=r"(result), "=r"(usr) \ - : "r"(src1), "r"(src2) \ - : "p1", "r2", "usr"); \ - *usr_result = usr & 0x3f; \ - return result; \ -} - -#define FUNC_CMP_RR(NAME, INSN) \ -FUNC_CMP_xx(uint32_t, uint32_t, NAME, INSN) - -#define FUNC_CMP_PP(NAME, INSN) \ -FUNC_CMP_xx(uint64_t, uint64_t, NAME, INSN) - -/* - * Function declarations using the templates - */ -FUNC_R_OP_R(satub, "%0 = satub(%2)") -FUNC_P_OP_PP(vaddubs, "%0 = vaddub(%2, %3):sat") -FUNC_P_OP_PP(vadduhs, "%0 = vadduh(%2, %3):sat") -FUNC_P_OP_PP(vsububs, "%0 = vsubub(%2, %3):sat") -FUNC_P_OP_PP(vsubuhs, "%0 = vsubuh(%2, %3):sat") - -/* Add vector of half integers with saturation and pack to unsigned bytes */ -FUNC_R_OP_PP(vaddhubs, "%0 = vaddhub(%2, %3):sat") - -/* Vector saturate half to unsigned byte */ -FUNC_R_OP_P(vsathub, "%0 = vsathub(%2)") - -/* Similar to above but takes a 32-bit argument */ -FUNC_R_OP_R(svsathub, "%0 = vsathub(%2)") - -/* Vector saturate word to unsigned half */ -FUNC_P_OP_P(vsatwuh_nopack, "%0 = vsatwuh(%2)") - -/* Similar to above but returns a 32-bit result */ -FUNC_R_OP_P(vsatwuh, "%0 = vsatwuh(%2)") - -/* Vector arithmetic shift halfwords with saturate and pack */ -FUNC_R_OP_PI(asrhub_sat, "%0 = vasrhub(%2, #%3):sat") - -/* Vector arithmetic shift halfwords with round, saturate and pack */ -FUNC_R_OP_PI(asrhub_rnd_sat, "%0 = vasrhub(%2, #%3):raw") - -FUNC_R_OP_RR(addsat, "%0 = add(%2, %3):sat") -/* Similar to above but with register pairs */ -FUNC_P_OP_PP(addpsat, "%0 = add(%2, %3):sat") - -FUNC_XR_OP_RR(mpy_acc_sat_hh_s0, "%0 += mpy(%2.H, %3.H):sat") -FUNC_R_OP_RR(mpy_sat_hh_s1, "%0 = mpy(%2.H, %3.H):<<1:sat") -FUNC_R_OP_RR(mpy_sat_rnd_hh_s1, "%0 = mpy(%2.H, %3.H):<<1:rnd:sat") -FUNC_R_OP_RR(mpy_up_s1_sat, "%0 = mpy(%2, %3):<<1:sat") -FUNC_P_OP_RR(vmpy2s_s1, "%0 = vmpyh(%2, %3):<<1:sat") -FUNC_P_OP_RR(vmpy2su_s1, "%0 = vmpyhsu(%2, %3):<<1:sat") -FUNC_R_OP_RR(vmpy2s_s1pack, "%0 = vmpyh(%2, %3):<<1:rnd:sat") -FUNC_P_OP_PP(vmpy2es_s1, "%0 = vmpyeh(%2, %3):<<1:sat") -FUNC_R_OP_PP(vdmpyrs_s1, "%0 = vdmpy(%2, %3):<<1:rnd:sat") -FUNC_XP_OP_PP(vdmacs_s0, "%0 += vdmpy(%2, %3):sat") -FUNC_R_OP_RR(cmpyrs_s0, "%0 = cmpy(%2, %3):rnd:sat") -FUNC_XP_OP_RR(cmacs_s0, "%0 += cmpy(%2, %3):sat") -FUNC_XP_OP_RR(cnacs_s0, "%0 -= cmpy(%2, %3):sat") -FUNC_P_OP_PP(vrcmpys_s1_h, "%0 = vrcmpys(%2, %3):<<1:sat:raw:hi") -FUNC_XP_OP_PP(mmacls_s0, "%0 += vmpyweh(%2, %3):sat") -FUNC_R_OP_RR(hmmpyl_rs1, "%0 = mpy(%2, %3.L):<<1:rnd:sat") -FUNC_XP_OP_PP(mmaculs_s0, "%0 += vmpyweuh(%2, %3):sat") -FUNC_R_OP_PR(cmpyi_wh, "%0 = cmpyiwh(%2, %3):<<1:rnd:sat") -FUNC_P_OP_PP(vcmpy_s0_sat_i, "%0 = vcmpyi(%2, %3):sat") -FUNC_P_OP_PR(vcrotate, "%0 = vcrotate(%2, %3)") -FUNC_P_OP_PR(vcnegh, "%0 = vcnegh(%2, %3)") - -#if CORE_HAS_AUDIO -FUNC_R_OP_PP(wcmpyrw, "%0 = cmpyrw(%2, %3):<<1:sat") -#endif - -FUNC_R_OP_RR(addh_l16_sat_ll, "%0 = add(%2.L, %3.L):sat") -FUNC_P_OP_P(vconj, "%0 = vconj(%2):sat") -FUNC_P_OP_PP(vxaddsubw, "%0 = vxaddsubw(%2, %3):sat") -FUNC_P_OP_P(vabshsat, "%0 = vabsh(%2):sat") -FUNC_P_OP_PP(vnavgwr, "%0 = vnavgw(%2, %3):rnd:sat") -FUNC_R_OP_RI(round_ri_sat, "%0 = round(%2, #%3):sat") -FUNC_R_OP_RR(asr_r_r_sat, "%0 = asr(%2, %3):sat") - -FUNC_XPp_OP_PP(ACS, "%0, p2 = vacsh(%3, %4)") - -/* Floating point */ -FUNC_R_OP_RR(sfmin, "%0 = sfmin(%2, %3)") -FUNC_R_OP_RR(sfmax, "%0 = sfmax(%2, %3)") -FUNC_R_OP_RR(sfadd, "%0 = sfadd(%2, %3)") -FUNC_R_OP_RR(sfsub, "%0 = sfsub(%2, %3)") -FUNC_R_OP_RR(sfmpy, "%0 = sfmpy(%2, %3)") -FUNC_XR_OP_RR(sffma, "%0 += sfmpy(%2, %3)") -FUNC_XR_OP_RR(sffms, "%0 -= sfmpy(%2, %3)") -FUNC_CMP_RR(sfcmpuo, "p1 = sfcmp.uo(%2, %3)") -FUNC_CMP_RR(sfcmpeq, "p1 = sfcmp.eq(%2, %3)") -FUNC_CMP_RR(sfcmpgt, "p1 = sfcmp.gt(%2, %3)") -FUNC_CMP_RR(sfcmpge, "p1 = sfcmp.ge(%2, %3)") - -FUNC_P_OP_PP(dfadd, "%0 = dfadd(%2, %3)") -FUNC_P_OP_PP(dfsub, "%0 = dfsub(%2, %3)") - -#if CORE_IS_V67 -FUNC_P_OP_PP(dfmin, "%0 = dfmin(%2, %3)") -FUNC_P_OP_PP(dfmax, "%0 = dfmax(%2, %3)") -FUNC_XP_OP_PP(dfmpyhh, "%0 += dfmpyhh(%2, %3)") -#endif - -FUNC_CMP_PP(dfcmpuo, "p1 = dfcmp.uo(%2, %3)") -FUNC_CMP_PP(dfcmpeq, "p1 = dfcmp.eq(%2, %3)") -FUNC_CMP_PP(dfcmpgt, "p1 = dfcmp.gt(%2, %3)") -FUNC_CMP_PP(dfcmpge, "p1 = dfcmp.ge(%2, %3)") - -/* Conversions from sf */ -FUNC_P_OP_R(conv_sf2df, "%0 = convert_sf2df(%2)") -FUNC_R_OP_R(conv_sf2uw, "%0 = convert_sf2uw(%2)") -FUNC_R_OP_R(conv_sf2w, "%0 = convert_sf2w(%2)") -FUNC_P_OP_R(conv_sf2ud, "%0 = convert_sf2ud(%2)") -FUNC_P_OP_R(conv_sf2d, "%0 = convert_sf2d(%2)") -FUNC_R_OP_R(conv_sf2uw_chop, "%0 = convert_sf2uw(%2):chop") -FUNC_R_OP_R(conv_sf2w_chop, "%0 = convert_sf2w(%2):chop") -FUNC_P_OP_R(conv_sf2ud_chop, "%0 = convert_sf2ud(%2):chop") -FUNC_P_OP_R(conv_sf2d_chop, "%0 = convert_sf2d(%2):chop") - -/* Conversions from df */ -FUNC_R_OP_P(conv_df2sf, "%0 = convert_df2sf(%2)") -FUNC_R_OP_P(conv_df2uw, "%0 = convert_df2uw(%2)") -FUNC_R_OP_P(conv_df2w, "%0 = convert_df2w(%2)") -FUNC_P_OP_P(conv_df2ud, "%0 = convert_df2ud(%2)") -FUNC_P_OP_P(conv_df2d, "%0 = convert_df2d(%2)") -FUNC_R_OP_P(conv_df2uw_chop, "%0 = convert_df2uw(%2):chop") -FUNC_R_OP_P(conv_df2w_chop, "%0 = convert_df2w(%2):chop") -FUNC_P_OP_P(conv_df2ud_chop, "%0 = convert_df2ud(%2):chop") -FUNC_P_OP_P(conv_df2d_chop, "%0 = convert_df2d(%2):chop") - -/* Integer to float conversions */ -FUNC_R_OP_R(conv_uw2sf, "%0 = convert_uw2sf(%2)") -FUNC_R_OP_R(conv_w2sf, "%0 = convert_w2sf(%2)") -FUNC_R_OP_P(conv_ud2sf, "%0 = convert_ud2sf(%2)") -FUNC_R_OP_P(conv_d2sf, "%0 = convert_d2sf(%2)") - -/* Special purpose floating point instructions */ -FUNC_XR_OP_RRp(sffma_sc, "%0 += sfmpy(%2, %3, p2):scale") -FUNC_Rp_OP_RR(sfrecipa, "%0, p2 = sfrecipa(%3, %4)") -FUNC_R_OP_RR(sffixupn, "%0 = sffixupn(%2, %3)") -FUNC_R_OP_RR(sffixupd, "%0 = sffixupd(%2, %3)") -FUNC_R_OP_R(sffixupr, "%0 = sffixupr(%2)") -FUNC_Rp_OP_R(sfinvsqrta, "%0, p2 = sfinvsqrta(%3)") - -/* - * Templates for test cases - * - * Same naming convention as the function templates - */ -#define TEST_x_OP_x(RESTYPE, CHECKFN, SRCTYPE, FUNC, SRC, RES, USR_RES) \ - do { \ - RESTYPE result; \ - SRCTYPE src = SRC; \ - uint32_t usr_result; \ - result = FUNC(src, &usr_result); \ - CHECKFN(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_R_OP_R(FUNC, SRC, RES, USR_RES) \ -TEST_x_OP_x(uint32_t, check32, uint32_t, FUNC, SRC, RES, USR_RES) - -#define TEST_R_OP_P(FUNC, SRC, RES, USR_RES) \ -TEST_x_OP_x(uint32_t, check32, uint64_t, FUNC, SRC, RES, USR_RES) - -#define TEST_P_OP_P(FUNC, SRC, RES, USR_RES) \ -TEST_x_OP_x(uint64_t, check64, uint64_t, FUNC, SRC, RES, USR_RES) - -#define TEST_P_OP_R(FUNC, SRC, RES, USR_RES) \ -TEST_x_OP_x(uint64_t, check64, uint32_t, FUNC, SRC, RES, USR_RES) - -#define TEST_xp_OP_x(RESTYPE, CHECKFN, SRCTYPE, FUNC, SRC, \ - RES, PRED_RES, USR_RES) \ - do { \ - RESTYPE result; \ - SRCTYPE src = SRC; \ - uint8_t pred_result; \ - uint32_t usr_result; \ - result = FUNC(src, &pred_result, &usr_result); \ - CHECKFN(result, RES); \ - check(pred_result, PRED_RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_Rp_OP_R(FUNC, SRC, RES, PRED_RES, USR_RES) \ -TEST_xp_OP_x(uint32_t, check32, uint32_t, FUNC, SRC, RES, PRED_RES, USR_RES) - -#define TEST_x_OP_xx(RESTYPE, CHECKFN, SRC1TYPE, SRC2TYPE, \ - FUNC, SRC1, SRC2, RES, USR_RES) \ - do { \ - RESTYPE result; \ - SRC1TYPE src1 = SRC1; \ - SRC2TYPE src2 = SRC2; \ - uint32_t usr_result; \ - result = FUNC(src1, src2, &usr_result); \ - CHECKFN(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_P_OP_PP(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xx(uint64_t, check64, uint64_t, uint64_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_R_OP_PP(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xx(uint32_t, check32, uint64_t, uint64_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_P_OP_RR(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xx(uint64_t, check64, uint32_t, uint32_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_R_OP_RR(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xx(uint32_t, check32, uint32_t, uint32_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_R_OP_PR(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xx(uint32_t, check32, uint64_t, uint32_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_P_OP_PR(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xx(uint64_t, check64, uint64_t, uint32_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_xp_OP_xx(RESTYPE, CHECKFN, SRC1TYPE, SRC2TYPE, FUNC, SRC1, SRC2, \ - RES, PRED_RES, USR_RES) \ - do { \ - RESTYPE result; \ - SRC1TYPE src1 = SRC1; \ - SRC2TYPE src2 = SRC2; \ - uint8_t pred_result; \ - uint32_t usr_result; \ - result = FUNC(src1, src2, &pred_result, &usr_result); \ - CHECKFN(result, RES); \ - check(pred_result, PRED_RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_Rp_OP_RR(FUNC, SRC1, SRC2, RES, PRED_RES, USR_RES) \ -TEST_xp_OP_xx(uint32_t, check32, uint32_t, uint32_t, FUNC, SRC1, SRC2, \ - RES, PRED_RES, USR_RES) - -#define TEST_x_OP_xI(RESTYPE, CHECKFN, SRC1TYPE, \ - FUNC, SRC1, SRC2, RES, USR_RES) \ - do { \ - RESTYPE result; \ - SRC1TYPE src1 = SRC1; \ - uint32_t src2 = SRC2; \ - uint32_t usr_result; \ - result = FUNC(src1, src2, &usr_result); \ - CHECKFN(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_R_OP_RI(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xI(uint32_t, check32, uint32_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_R_OP_PI(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_x_OP_xI(uint32_t, check64, uint64_t, \ - FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_Xx_OP_xx(RESTYPE, CHECKFN, SRC1TYPE, SRC2TYPE, \ - FUNC, RESIN, SRC1, SRC2, RES, USR_RES) \ - do { \ - RESTYPE result = RESIN; \ - SRC1TYPE src1 = SRC1; \ - SRC2TYPE src2 = SRC2; \ - uint32_t usr_result; \ - result = FUNC(result, src1, src2, &usr_result); \ - CHECKFN(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_XR_OP_RR(FUNC, RESIN, SRC1, SRC2, RES, USR_RES) \ -TEST_Xx_OP_xx(uint32_t, check32, uint32_t, uint32_t, \ - FUNC, RESIN, SRC1, SRC2, RES, USR_RES) - -#define TEST_XP_OP_PP(FUNC, RESIN, SRC1, SRC2, RES, USR_RES) \ -TEST_Xx_OP_xx(uint64_t, check64, uint64_t, uint64_t, \ - FUNC, RESIN, SRC1, SRC2, RES, USR_RES) - -#define TEST_XP_OP_RR(FUNC, RESIN, SRC1, SRC2, RES, USR_RES) \ -TEST_Xx_OP_xx(uint64_t, check64, uint32_t, uint32_t, \ - FUNC, RESIN, SRC1, SRC2, RES, USR_RES) - -#define TEST_Xxp_OP_xx(RESTYPE, CHECKFN, SRC1TYPE, SRC2TYPE, \ - FUNC, RESIN, SRC1, SRC2, RES, PRED_RES, USR_RES) \ - do { \ - RESTYPE result = RESIN; \ - SRC1TYPE src1 = SRC1; \ - SRC2TYPE src2 = SRC2; \ - uint8_t pred_res; \ - uint32_t usr_result; \ - result = FUNC(result, src1, src2, &pred_res, &usr_result); \ - CHECKFN(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_XPp_OP_PP(FUNC, RESIN, SRC1, SRC2, RES, PRED_RES, USR_RES) \ -TEST_Xxp_OP_xx(uint64_t, check64, uint64_t, uint64_t, FUNC, RESIN, SRC1, SRC2, \ - RES, PRED_RES, USR_RES) - -#define TEST_Xx_OP_xxp(RESTYPE, CHECKFN, SRC1TYPE, SRC2TYPE, \ - FUNC, RESIN, SRC1, SRC2, PRED, RES, USR_RES) \ - do { \ - RESTYPE result = RESIN; \ - SRC1TYPE src1 = SRC1; \ - SRC2TYPE src2 = SRC2; \ - uint8_t pred = PRED; \ - uint32_t usr_result; \ - result = FUNC(result, src1, src2, pred, &usr_result); \ - CHECKFN(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_XR_OP_RRp(FUNC, RESIN, SRC1, SRC2, PRED, RES, USR_RES) \ -TEST_Xx_OP_xxp(uint32_t, check32, uint32_t, uint32_t, \ - FUNC, RESIN, SRC1, SRC2, PRED, RES, USR_RES) - -#define TEST_CMP_xx(SRC1TYPE, SRC2TYPE, \ - FUNC, SRC1, SRC2, RES, USR_RES) \ - do { \ - uint32_t result; \ - SRC1TYPE src1 = SRC1; \ - SRC2TYPE src2 = SRC2; \ - uint32_t usr_result; \ - result = FUNC(src1, src2, &usr_result); \ - check(result, RES); \ - check(usr_result, USR_RES); \ - } while (0) - -#define TEST_CMP_RR(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_CMP_xx(uint32_t, uint32_t, FUNC, SRC1, SRC2, RES, USR_RES) - -#define TEST_CMP_PP(FUNC, SRC1, SRC2, RES, USR_RES) \ -TEST_CMP_xx(uint64_t, uint64_t, FUNC, SRC1, SRC2, RES, USR_RES) - -int main() -{ - TEST_R_OP_R(satub, 0, 0, USR_CLEAR); - TEST_R_OP_R(satub, 0xff, 0xff, USR_CLEAR); - TEST_R_OP_R(satub, 0xfff, 0xff, USR_OVF); - TEST_R_OP_R(satub, -1, 0, USR_OVF); - - TEST_P_OP_PP(vaddubs, 0xfeLL, 0x01LL, 0xffLL, USR_CLEAR); - TEST_P_OP_PP(vaddubs, 0xffLL, 0xffLL, 0xffLL, USR_OVF); - - TEST_P_OP_PP(vadduhs, 0xfffeLL, 0x1LL, 0xffffLL, USR_CLEAR); - TEST_P_OP_PP(vadduhs, 0xffffLL, 0x1LL, 0xffffLL, USR_OVF); - - TEST_P_OP_PP(vsububs, 0x0807060504030201LL, 0x0101010101010101LL, - 0x0706050403020100LL, USR_CLEAR); - TEST_P_OP_PP(vsububs, 0x0807060504030201LL, 0x0202020202020202LL, - 0x0605040302010000LL, USR_OVF); - - TEST_P_OP_PP(vsubuhs, 0x0004000300020001LL, 0x0001000100010001LL, - 0x0003000200010000LL, USR_CLEAR); - TEST_P_OP_PP(vsubuhs, 0x0004000300020001LL, 0x0002000200020002LL, - 0x0002000100000000LL, USR_OVF); - - TEST_R_OP_PP(vaddhubs, 0x0004000300020001LL, 0x0001000100010001LL, - 0x05040302, USR_CLEAR); - TEST_R_OP_PP(vaddhubs, 0x7fff000300020001LL, 0x0002000200020002LL, - 0xff050403, USR_OVF); - - TEST_R_OP_P(vsathub, 0x0001000300020001LL, 0x01030201, USR_CLEAR); - TEST_R_OP_P(vsathub, 0x010000700080ffffLL, 0xff708000, USR_OVF); - - TEST_R_OP_P(vsatwuh, 0x0000ffff00000001LL, 0xffff0001, USR_CLEAR); - TEST_R_OP_P(vsatwuh, 0x800000000000ffffLL, 0x0000ffff, USR_OVF); - - TEST_P_OP_P(vsatwuh_nopack, 0x0000ffff00000001LL, 0x0000ffff00000001LL, - USR_CLEAR); - TEST_P_OP_P(vsatwuh_nopack, 0x800000000000ffffLL, 0x000000000000ffffLL, - USR_OVF); - - TEST_R_OP_R(svsathub, 0x00020001, 0x0201, USR_CLEAR); - TEST_R_OP_R(svsathub, 0x0080ffff, 0x8000, USR_OVF); - - TEST_R_OP_PI(asrhub_sat, 0x004f003f002f001fLL, 3, 0x09070503, - USR_CLEAR); - TEST_R_OP_PI(asrhub_sat, 0x004fffff8fff001fLL, 3, 0x09000003, - USR_OVF); - - TEST_R_OP_PI(asrhub_rnd_sat, 0x004f003f002f001fLL, 2, 0x0a080604, - USR_CLEAR); - TEST_R_OP_PI(asrhub_rnd_sat, 0x004fffff8fff001fLL, 2, 0x0a000004, - USR_OVF); - - TEST_R_OP_RR(addsat, 1, 2, 3, - USR_CLEAR); - TEST_R_OP_RR(addsat, 0x7fffffff, 0x00000010, 0x7fffffff, - USR_OVF); - TEST_R_OP_RR(addsat, 0x80000000, 0x80000006, 0x80000000, - USR_OVF); - - TEST_P_OP_PP(addpsat, 1LL, 2LL, 3LL, USR_CLEAR); - /* overflow to max positive */ - TEST_P_OP_PP(addpsat, 0x7ffffffffffffff0LL, 0x0000000000000010LL, - 0x7fffffffffffffffLL, USR_OVF); - /* overflow to min negative */ - TEST_P_OP_PP(addpsat, 0x8000000000000003LL, 0x8000000000000006LL, - 0x8000000000000000LL, USR_OVF); - - TEST_XR_OP_RR(mpy_acc_sat_hh_s0, 0x7fffffff, 0xffff0000, 0x11110000, - 0x7fffeeee, USR_CLEAR); - TEST_XR_OP_RR(mpy_acc_sat_hh_s0, 0x7fffffff, 0x7fff0000, 0x7fff0000, - 0x7fffffff, USR_OVF); - - TEST_R_OP_RR(mpy_sat_hh_s1, 0xffff0000, 0x11110000, 0xffffddde, - USR_CLEAR); - TEST_R_OP_RR(mpy_sat_hh_s1, 0x7fff0000, 0x7fff0000, 0x7ffe0002, - USR_CLEAR); - TEST_R_OP_RR(mpy_sat_hh_s1, 0x80000000, 0x80000000, 0x7fffffff, - USR_OVF); - - TEST_R_OP_RR(mpy_sat_rnd_hh_s1, 0xffff0000, 0x11110000, 0x00005dde, - USR_CLEAR); - TEST_R_OP_RR(mpy_sat_rnd_hh_s1, 0x7fff0000, 0x7fff0000, 0x7ffe8002, - USR_CLEAR); - TEST_R_OP_RR(mpy_sat_rnd_hh_s1, 0x80000000, 0x80000000, 0x7fffffff, - USR_OVF); - - TEST_R_OP_RR(mpy_up_s1_sat, 0xffff0000, 0x11110000, 0xffffddde, - USR_CLEAR); - TEST_R_OP_RR(mpy_up_s1_sat, 0x7fff0000, 0x7fff0000, 0x7ffe0002, - USR_CLEAR); - TEST_R_OP_RR(mpy_up_s1_sat, 0x80000000, 0x80000000, 0x7fffffff, - USR_OVF); - - TEST_P_OP_RR(vmpy2s_s1, 0x7fff0000, 0x7fff0000, 0x7ffe000200000000LL, - USR_CLEAR); - TEST_P_OP_RR(vmpy2s_s1, 0x80000000, 0x80000000, 0x7fffffff00000000LL, - USR_OVF); - - TEST_P_OP_RR(vmpy2su_s1, 0x7fff0000, 0x7fff0000, 0x7ffe000200000000LL, - USR_CLEAR); - TEST_P_OP_RR(vmpy2su_s1, 0xffffbd97, 0xffffffff, 0xfffe000280000000LL, - USR_OVF); - - TEST_R_OP_RR(vmpy2s_s1pack, 0x7fff0000, 0x7fff0000, 0x7ffe0000, - USR_CLEAR); - TEST_R_OP_RR(vmpy2s_s1pack, 0x80008000, 0x80008000, 0x7fff7fff, - USR_OVF); - - TEST_P_OP_PP(vmpy2es_s1, 0x7fff7fff7fff7fffLL, 0x1fff1fff1fff1fffLL, - 0x1ffec0021ffec002LL, USR_CLEAR); - TEST_P_OP_PP(vmpy2es_s1, 0x8000800080008000LL, 0x8000800080008000LL, - 0x7fffffff7fffffffLL, USR_OVF); - - TEST_R_OP_PP(vdmpyrs_s1, 0x7fff7fff7fff7fffLL, 0x1fff1fff1fff1fffLL, - 0x3ffe3ffe, USR_CLEAR); - TEST_R_OP_PP(vdmpyrs_s1, 0x8000800080008000LL, 0x8000800080008000LL, - 0x7fff7fffLL, USR_OVF); - - TEST_XP_OP_PP(vdmacs_s0, 0x0fffffffULL, 0x00ff00ff00ff00ffLL, - 0x00ff00ff00ff00ffLL, 0x0001fc021001fc01LL, USR_CLEAR); - TEST_XP_OP_PP(vdmacs_s0, 0x01111111ULL, 0x8000800080001000LL, - 0x8000800080008000LL, 0x7fffffff39111111LL, USR_OVF); - - TEST_R_OP_RR(cmpyrs_s0, 0x7fff0000, 0x7fff0000, 0x0000c001, - USR_CLEAR); - TEST_R_OP_RR(cmpyrs_s0, 0x80008000, 0x80008000, 0x7fff0000, - USR_OVF); - - TEST_XP_OP_RR(cmacs_s0, 0x0fffffff, 0x7fff0000, 0x7fff0000, - 0x00000000d000fffeLL, USR_CLEAR); - TEST_XP_OP_RR(cmacs_s0, 0x0fff1111, 0x80008000, 0x80008000, - 0x7fffffff0fff1111LL, USR_OVF); - - TEST_XP_OP_RR(cnacs_s0, 0x000000108fffffffULL, 0x7fff0000, 0x7fff0000, - 0x00000010cfff0000ULL, USR_CLEAR); - TEST_XP_OP_RR(cnacs_s0, 0x000000108ff1111fULL, 0x00002001, 0x00007ffd, - 0x0000001080000000ULL, USR_OVF); - - TEST_P_OP_PP(vrcmpys_s1_h, 0x00ff00ff00ff00ffLL, 0x00ff00ff00ff00ffLL, - 0x0003f8040003f804LL, USR_CLEAR); - TEST_P_OP_PP(vrcmpys_s1_h, 0x8000800080008000LL, 0x8000800080008000LL, - 0x7fffffff7fffffffLL, USR_OVF); - - TEST_XP_OP_PP(mmacls_s0, 0x6fffffff, 0x00ff00ff00ff00ffLL, - 0x00ff00ff00ff00ffLL, 0x0000fe017000fe00LL, USR_CLEAR); - TEST_XP_OP_PP(mmacls_s0, 0x6f1111ff, 0x8000800080008000LL, - 0x1000100080008000LL, 0xf80008007fffffffLL, USR_OVF); - - TEST_R_OP_RR(hmmpyl_rs1, 0x7fff0000, 0x7fff0001, 0x0000fffe, - USR_CLEAR); - TEST_R_OP_RR(hmmpyl_rs1, 0x80000000, 0x80008000, 0x7fffffff, - USR_OVF); - - TEST_XP_OP_PP(mmaculs_s0, 0x000000007fffffffULL, 0xffff800080008000LL, - 0xffff800080008000LL, 0xffffc00040003fffLL, USR_CLEAR); - TEST_XP_OP_PP(mmaculs_s0, 0x000011107fffffffULL, 0x00ff00ff00ff00ffLL, - 0x00ff00ff001100ffLL, 0x00010f117fffffffLL, USR_OVF); - - TEST_R_OP_PR(cmpyi_wh, 0x7fff000000000000LL, 0x7fff0001, 0x0000fffe, - USR_CLEAR); - TEST_R_OP_PR(cmpyi_wh, 0x8000000000000000LL, 0x80008000, 0x7fffffff, - USR_OVF); - - TEST_P_OP_PP(vcmpy_s0_sat_i, 0x00ff00ff00ff00ffLL, 0x00ff00ff00ff00ffLL, - 0x0001fc020001fc02LL, USR_CLEAR); - TEST_P_OP_PP(vcmpy_s0_sat_i, 0x8000800080008000LL, 0x8000800080008000LL, - 0x7fffffff7fffffffLL, USR_OVF); - - TEST_P_OP_PR(vcrotate, 0x8000000000000000LL, 0x00000002, - 0x8000000000000000LL, USR_CLEAR); - TEST_P_OP_PR(vcrotate, 0x7fff80007fff8000LL, 0x00000001, - 0x7fff80007fff7fffLL, USR_OVF); - - TEST_P_OP_PR(vcnegh, 0x8000000000000000LL, 0x00000002, - 0x8000000000000000LL, USR_CLEAR); - TEST_P_OP_PR(vcnegh, 0x7fff80007fff8000LL, 0x00000001, - 0x7fff80007fff7fffLL, USR_OVF); - -#if CORE_HAS_AUDIO - TEST_R_OP_PP(wcmpyrw, 0x8765432101234567LL, 0x00000002ffffffffLL, - 0x00000001, USR_CLEAR); - TEST_R_OP_PP(wcmpyrw, 0x800000007fffffffLL, 0x000000ff7fffffffLL, - 0x7fffffff, USR_OVF); - TEST_R_OP_PP(wcmpyrw, 0x7fffffff80000000LL, 0x7fffffff000000ffLL, - 0x80000000, USR_OVF); -#else - printf("Audio instructions skipped\n"); -#endif - - TEST_R_OP_RR(addh_l16_sat_ll, 0x0000ffff, 0x00000002, 0x00000001, - USR_CLEAR); - TEST_R_OP_RR(addh_l16_sat_ll, 0x00007fff, 0x00000005, 0x00007fff, - USR_OVF); - TEST_R_OP_RR(addh_l16_sat_ll, 0x00008000, 0x00008000, 0xffff8000, - USR_OVF); - - TEST_P_OP_P(vconj, 0x0000ffff00000001LL, 0x0000ffff00000001LL, USR_CLEAR); - TEST_P_OP_P(vconj, 0x800000000000ffffLL, 0x7fff00000000ffffLL, USR_OVF); - - TEST_P_OP_PP(vxaddsubw, 0x8765432101234567LL, 0x00000002ffffffffLL, - 0x8765432201234569LL, USR_CLEAR); - TEST_P_OP_PP(vxaddsubw, 0x7fffffff7fffffffLL, 0xffffffffffffffffLL, - 0x7fffffff7ffffffeLL, USR_OVF); - TEST_P_OP_PP(vxaddsubw, 0x800000000fffffffLL, 0x0000000a00000008LL, - 0x8000000010000009LL, USR_OVF); - - TEST_P_OP_P(vabshsat, 0x0001000afffff800LL, 0x0001000a00010800LL, - USR_CLEAR); - TEST_P_OP_P(vabshsat, 0x8000000b000c000aLL, 0x7fff000b000c000aLL, - USR_OVF); - - TEST_P_OP_PP(vnavgwr, 0x8765432101234567LL, 0x00000002ffffffffLL, - 0xc3b2a1900091a2b4LL, USR_CLEAR); - TEST_P_OP_PP(vnavgwr, 0x7fffffff8000000aLL, 0x80000000ffffffffLL, - 0x7fffffffc0000006LL, USR_OVF); - - TEST_R_OP_RI(round_ri_sat, 0x0000ffff, 2, 0x00004000, USR_CLEAR); - TEST_R_OP_RI(round_ri_sat, 0x7fffffff, 2, 0x1fffffff, USR_OVF); - - TEST_R_OP_RR(asr_r_r_sat, 0x0000ffff, 0x00000002, 0x00003fff, - USR_CLEAR); - TEST_R_OP_RR(asr_r_r_sat, 0x00ffffff, 0xfffffff5, 0x7fffffff, - USR_OVF); - TEST_R_OP_RR(asr_r_r_sat, 0x80000000, 0xfffffff5, 0x80000000, - USR_OVF); - - TEST_XPp_OP_PP(ACS, 0x0004000300020001ULL, 0x0001000200030004ULL, - 0x0000000000000000ULL, 0x0004000300030004ULL, 0xf0, - USR_CLEAR); - TEST_XPp_OP_PP(ACS, 0x0004000300020001ULL, 0x0001000200030004ULL, - 0x000affff000d0000ULL, 0x000e0003000f0004ULL, 0xcc, - USR_CLEAR); - TEST_XPp_OP_PP(ACS, 0x00047fff00020001ULL, 0x00017fff00030004ULL, - 0x000a0fff000d0000ULL, 0x000e7fff000f0004ULL, 0xfc, - USR_OVF); - TEST_XPp_OP_PP(ACS, 0x00047fff00020001ULL, 0x00017fff00030004ULL, - 0x000a0fff000d0000ULL, 0x000e7fff000f0004ULL, 0xf0, - USR_OVF); - - /* Floating point */ - TEST_R_OP_RR(sfmin, SF_one, SF_small_neg, SF_small_neg, USR_CLEAR); - TEST_R_OP_RR(sfmin, SF_one, SF_SNaN, SF_one, USR_FPINVF); - TEST_R_OP_RR(sfmin, SF_SNaN, SF_one, SF_one, USR_FPINVF); - TEST_R_OP_RR(sfmin, SF_one, SF_QNaN, SF_one, USR_CLEAR); - 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(sfmax, SF_one, SF_small_neg, SF_one, USR_CLEAR); - TEST_R_OP_RR(sfmax, SF_one, SF_SNaN, SF_one, USR_FPINVF); - TEST_R_OP_RR(sfmax, SF_SNaN, SF_one, SF_one, USR_FPINVF); - TEST_R_OP_RR(sfmax, SF_one, SF_QNaN, SF_one, USR_CLEAR); - 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(sfadd, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sfadd, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sfadd, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sfadd, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_R_OP_RR(sfsub, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sfsub, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sfsub, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sfsub, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_R_OP_RR(sfmpy, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sfmpy, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sfmpy, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sfmpy, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_XR_OP_RR(sffma, SF_one, SF_one, SF_one, SF_two, USR_CLEAR); - TEST_XR_OP_RR(sffma, SF_zero, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_XR_OP_RR(sffma, SF_zero, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_XR_OP_RR(sffma, SF_zero, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_XR_OP_RR(sffma, SF_zero, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_XR_OP_RR(sffms, SF_one, SF_one, SF_one, SF_zero, USR_CLEAR); - TEST_XR_OP_RR(sffms, SF_zero, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_XR_OP_RR(sffms, SF_zero, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_XR_OP_RR(sffms, SF_zero, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_XR_OP_RR(sffms, SF_zero, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_CMP_RR(sfcmpuo, SF_one, SF_large_pos, 0x00, USR_CLEAR); - TEST_CMP_RR(sfcmpuo, SF_INF, SF_large_pos, 0x00, USR_CLEAR); - TEST_CMP_RR(sfcmpuo, SF_QNaN, SF_large_pos, 0xff, USR_CLEAR); - TEST_CMP_RR(sfcmpuo, SF_QNaN_neg, SF_large_pos, 0xff, USR_CLEAR); - TEST_CMP_RR(sfcmpuo, SF_SNaN, SF_large_pos, 0xff, USR_FPINVF); - TEST_CMP_RR(sfcmpuo, SF_SNaN_neg, SF_large_pos, 0xff, USR_FPINVF); - TEST_CMP_RR(sfcmpuo, SF_QNaN, SF_QNaN, 0xff, USR_CLEAR); - TEST_CMP_RR(sfcmpuo, SF_QNaN, SF_SNaN, 0xff, USR_FPINVF); - - TEST_CMP_RR(sfcmpeq, SF_one, SF_QNaN, 0x00, USR_CLEAR); - TEST_CMP_RR(sfcmpeq, SF_one, SF_SNaN, 0x00, USR_FPINVF); - TEST_CMP_RR(sfcmpgt, SF_one, SF_QNaN, 0x00, USR_CLEAR); - TEST_CMP_RR(sfcmpgt, SF_one, SF_SNaN, 0x00, USR_FPINVF); - TEST_CMP_RR(sfcmpge, SF_one, SF_QNaN, 0x00, USR_CLEAR); - TEST_CMP_RR(sfcmpge, SF_one, SF_SNaN, 0x00, USR_FPINVF); - - TEST_P_OP_PP(dfadd, DF_any, DF_QNaN, DF_HEX_NaN, USR_CLEAR); - TEST_P_OP_PP(dfadd, DF_any, DF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_P_OP_PP(dfadd, DF_QNaN, DF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_P_OP_PP(dfadd, DF_SNaN, DF_QNaN, DF_HEX_NaN, USR_FPINVF); - - TEST_P_OP_PP(dfsub, DF_any, DF_QNaN, DF_HEX_NaN, USR_CLEAR); - TEST_P_OP_PP(dfsub, DF_any, DF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_P_OP_PP(dfsub, DF_QNaN, DF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_P_OP_PP(dfsub, DF_SNaN, DF_QNaN, DF_HEX_NaN, USR_FPINVF); - -#if CORE_IS_V67 - TEST_P_OP_PP(dfmin, DF_any, DF_small_neg, DF_small_neg, USR_CLEAR); - TEST_P_OP_PP(dfmin, DF_any, DF_SNaN, DF_any, USR_FPINVF); - TEST_P_OP_PP(dfmin, DF_SNaN, DF_any, DF_any, USR_FPINVF); - TEST_P_OP_PP(dfmin, DF_any, DF_QNaN, DF_any, USR_CLEAR); - 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(dfmax, DF_any, DF_small_neg, DF_any, USR_CLEAR); - TEST_P_OP_PP(dfmax, DF_any, DF_SNaN, DF_any, USR_FPINVF); - TEST_P_OP_PP(dfmax, DF_SNaN, DF_any, DF_any, USR_FPINVF); - TEST_P_OP_PP(dfmax, DF_any, DF_QNaN, DF_any, USR_CLEAR); - 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_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); - TEST_XP_OP_PP(dfmpyhh, DF_zero, DF_any, DF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_XP_OP_PP(dfmpyhh, DF_zero, DF_QNaN, DF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_XP_OP_PP(dfmpyhh, DF_zero, DF_SNaN, DF_QNaN, DF_HEX_NaN, USR_FPINVF); -#else - printf("v67 instructions skipped\n"); -#endif - - TEST_CMP_PP(dfcmpuo, DF_small_neg, DF_any, 0x00, USR_CLEAR); - TEST_CMP_PP(dfcmpuo, DF_large_pos, DF_any, 0x00, USR_CLEAR); - TEST_CMP_PP(dfcmpuo, DF_QNaN, DF_any, 0xff, USR_CLEAR); - TEST_CMP_PP(dfcmpuo, DF_QNaN_neg, DF_any, 0xff, USR_CLEAR); - TEST_CMP_PP(dfcmpuo, DF_SNaN, DF_any, 0xff, USR_FPINVF); - TEST_CMP_PP(dfcmpuo, DF_SNaN_neg, DF_any, 0xff, USR_FPINVF); - TEST_CMP_PP(dfcmpuo, DF_QNaN, DF_QNaN, 0xff, USR_CLEAR); - TEST_CMP_PP(dfcmpuo, DF_QNaN, DF_SNaN, 0xff, USR_FPINVF); - - TEST_CMP_PP(dfcmpeq, DF_any, DF_QNaN, 0x00, USR_CLEAR); - TEST_CMP_PP(dfcmpeq, DF_any, DF_SNaN, 0x00, USR_FPINVF); - TEST_CMP_PP(dfcmpgt, DF_any, DF_QNaN, 0x00, USR_CLEAR); - TEST_CMP_PP(dfcmpgt, DF_any, DF_SNaN, 0x00, USR_FPINVF); - TEST_CMP_PP(dfcmpge, DF_any, DF_QNaN, 0x00, USR_CLEAR); - TEST_CMP_PP(dfcmpge, DF_any, DF_SNaN, 0x00, USR_FPINVF); - - TEST_P_OP_R(conv_sf2df, SF_QNaN, DF_HEX_NaN, USR_CLEAR); - TEST_P_OP_R(conv_sf2df, SF_SNaN, DF_HEX_NaN, USR_FPINVF); - TEST_R_OP_R(conv_sf2uw, SF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_R(conv_sf2uw, SF_SNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_R(conv_sf2w, SF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_R(conv_sf2w, SF_SNaN, 0xffffffff, USR_FPINVF); - TEST_P_OP_R(conv_sf2ud, SF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_R(conv_sf2ud, SF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_R(conv_sf2d, SF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_R(conv_sf2d, SF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_R_OP_R(conv_sf2uw_chop, SF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_R(conv_sf2uw_chop, SF_SNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_R(conv_sf2w_chop, SF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_R(conv_sf2w_chop, SF_SNaN, 0xffffffff, USR_FPINVF); - TEST_P_OP_R(conv_sf2ud_chop, SF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_R(conv_sf2ud_chop, SF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_R(conv_sf2d_chop, SF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_R(conv_sf2d_chop, SF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - - TEST_R_OP_P(conv_df2sf, DF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_P(conv_df2sf, DF_SNaN, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_P(conv_df2uw, DF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_P(conv_df2uw, DF_SNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_P(conv_df2w, DF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_P(conv_df2w, DF_SNaN, 0xffffffff, USR_FPINVF); - TEST_P_OP_P(conv_df2ud, DF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_P(conv_df2ud, DF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_P(conv_df2d, DF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_P(conv_df2d, DF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_R_OP_P(conv_df2uw_chop, DF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_P(conv_df2uw_chop, DF_SNaN, 0xffffffff, USR_FPINVF); - - /* Test for typo in HELPER(conv_df2uw_chop) */ - TEST_R_OP_P(conv_df2uw_chop, 0xffffff7f00000001ULL, 0xffffffff, USR_FPINVF); - - TEST_R_OP_P(conv_df2w_chop, DF_QNaN, 0xffffffff, USR_FPINVF); - TEST_R_OP_P(conv_df2w_chop, DF_SNaN, 0xffffffff, USR_FPINVF); - TEST_P_OP_P(conv_df2ud_chop, DF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_P(conv_df2ud_chop, DF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_P(conv_df2d_chop, DF_QNaN, 0xffffffffffffffffULL, USR_FPINVF); - TEST_P_OP_P(conv_df2d_chop, DF_SNaN, 0xffffffffffffffffULL, USR_FPINVF); - - TEST_R_OP_R(conv_uw2sf, 0x00000001, SF_one, USR_CLEAR); - TEST_R_OP_R(conv_uw2sf, 0x010020a5, 0x4b801052, USR_FPINPF); - TEST_R_OP_R(conv_w2sf, 0x00000001, SF_one, USR_CLEAR); - TEST_R_OP_R(conv_w2sf, 0x010020a5, 0x4b801052, USR_FPINPF); - TEST_R_OP_P(conv_ud2sf, 0x0000000000000001ULL, SF_one, USR_CLEAR); - TEST_R_OP_P(conv_ud2sf, 0x00000000010020a5ULL, 0x4b801052, USR_FPINPF); - TEST_R_OP_P(conv_d2sf, 0x0000000000000001ULL, SF_one, USR_CLEAR); - TEST_R_OP_P(conv_d2sf, 0x00000000010020a5ULL, 0x4b801052, USR_FPINPF); - - TEST_XR_OP_RRp(sffma_sc, SF_one, SF_one, SF_one, 1, SF_four, - USR_CLEAR); - TEST_XR_OP_RRp(sffma_sc, SF_QNaN, SF_one, SF_one, 1, SF_HEX_NaN, - USR_CLEAR); - TEST_XR_OP_RRp(sffma_sc, SF_one, SF_QNaN, SF_one, 1, SF_HEX_NaN, - USR_CLEAR); - TEST_XR_OP_RRp(sffma_sc, SF_one, SF_one, SF_QNaN, 1, SF_HEX_NaN, - USR_CLEAR); - TEST_XR_OP_RRp(sffma_sc, SF_SNaN, SF_one, SF_one, 1, SF_HEX_NaN, - USR_FPINVF); - TEST_XR_OP_RRp(sffma_sc, SF_one, SF_SNaN, SF_one, 1, SF_HEX_NaN, - USR_FPINVF); - TEST_XR_OP_RRp(sffma_sc, SF_one, SF_one, SF_SNaN, 1, SF_HEX_NaN, - USR_FPINVF); - - TEST_Rp_OP_RR(sfrecipa, SF_one, SF_one, SF_one_recip, 0x00, - USR_CLEAR); - TEST_Rp_OP_RR(sfrecipa, SF_QNaN, SF_one, SF_HEX_NaN, 0x00, - USR_CLEAR); - TEST_Rp_OP_RR(sfrecipa, SF_one, SF_QNaN, SF_HEX_NaN, 0x00, - USR_CLEAR); - TEST_Rp_OP_RR(sfrecipa, SF_one, SF_SNaN, SF_HEX_NaN, 0x00, - USR_FPINVF); - TEST_Rp_OP_RR(sfrecipa, SF_SNaN, SF_one, SF_HEX_NaN, 0x00, - USR_FPINVF); - - TEST_R_OP_RR(sffixupn, SF_one, SF_one, SF_one, USR_CLEAR); - TEST_R_OP_RR(sffixupn, SF_QNaN, SF_one, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sffixupn, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sffixupn, SF_SNaN, SF_one, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sffixupn, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_R_OP_RR(sffixupd, SF_one, SF_one, SF_one, USR_CLEAR); - TEST_R_OP_RR(sffixupd, SF_QNaN, SF_one, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sffixupd, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_RR(sffixupd, SF_SNaN, SF_one, SF_HEX_NaN, USR_FPINVF); - TEST_R_OP_RR(sffixupd, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_R_OP_R(sffixupr, SF_one, SF_one, USR_CLEAR); - TEST_R_OP_R(sffixupr, SF_QNaN, SF_HEX_NaN, USR_CLEAR); - TEST_R_OP_R(sffixupr, SF_SNaN, SF_HEX_NaN, USR_FPINVF); - - TEST_Rp_OP_R(sfinvsqrta, SF_one, SF_one_invsqrta, 0x00, USR_CLEAR); - TEST_Rp_OP_R(sfinvsqrta, SF_zero, SF_one, 0x00, USR_CLEAR); - TEST_Rp_OP_R(sfinvsqrta, SF_QNaN, SF_HEX_NaN, 0x00, USR_CLEAR); - TEST_Rp_OP_R(sfinvsqrta, SF_small_neg, SF_HEX_NaN, 0x00, USR_FPINVF); - TEST_Rp_OP_R(sfinvsqrta, SF_SNaN, SF_HEX_NaN, 0x00, USR_FPINVF); - - puts(err ? "FAIL" : "PASS"); - return err; -} diff --git a/tests/tcg/hexagon/vector_add_int.c b/tests/tcg/hexagon/vector_add_int.c deleted file mode 100644 index d6010ea14b56..000000000000 --- a/tests/tcg/hexagon/vector_add_int.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright(c) 2019-2021 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 - * 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 . - */ - -#include - -int gA[401]; -int gB[401]; -int gC[401]; - -void vector_add_int() -{ - int i; - for (i = 0; i < 400; i++) { - gA[i] = gB[i] + gC[i]; - } -} - -int main() -{ - int error = 0; - int i; - for (i = 0; i < 400; i++) { - gB[i] = i * 2; - gC[i] = i * 3; - } - gA[400] = 17; - vector_add_int(); - for (i = 0; i < 400; i++) { - if (gA[i] != i * 5) { - error++; - printf("ERROR: gB[%d] = %d\t", i, gB[i]); - printf("gC[%d] = %d\t", i, gC[i]); - printf("gA[%d] = %d\n", i, gA[i]); - } - } - if (gA[400] != 17) { - error++; - printf("ERROR: Overran the buffer\n"); - } - if (!error) { - printf("PASS\n"); - return 0; - } else { - printf("FAIL\n"); - return 1; - } -} diff --git a/tests/tcg/hppa/Makefile.target b/tests/tcg/hppa/Makefile.target deleted file mode 100644 index b78e6b48499f..000000000000 --- a/tests/tcg/hppa/Makefile.target +++ /dev/null @@ -1,19 +0,0 @@ -# -*- Mode: makefile -*- -# -# HPPA specific tweaks - specifically masking out broken tests - -# On parisc Linux supports 4K/16K/64K (but currently only 4k works) -EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-16384 run-test-mmap-65536 - -# This triggers failures for hppa-linux about 1% of the time -# HPPA is the odd target that can't use the sigtramp page; -# it requires the full vdso with dwarf2 unwind info. -run-signals: signals - $(call skip-test, $<, "BROKEN awaiting vdso support") -run-plugin-signals-with-%: - $(call skip-test, $<, "BROKEN awaiting vdso support") - -VPATH += $(SRC_PATH)/tests/tcg/hppa -TESTS += stby - -stby: CFLAGS += -pthread diff --git a/tests/tcg/hppa/stby.c b/tests/tcg/hppa/stby.c deleted file mode 100644 index 36bd5f723c3d..000000000000 --- a/tests/tcg/hppa/stby.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Test STBY */ - -#include -#include -#include -#include - - -struct S { - unsigned a; - unsigned b; - unsigned c; -}; - -static void check(const struct S *s, unsigned e, - const char *which, const char *insn, int ofs) -{ - int err = 0; - - if (s->a != 0) { - fprintf(stderr, "%s %s %d: garbage before word 0x%08x\n", - which, insn, ofs, s->a); - err = 1; - } - if (s->c != 0) { - fprintf(stderr, "%s %s %d: garbage after word 0x%08x\n", - which, insn, ofs, s->c); - err = 1; - } - if (s->b != e) { - fprintf(stderr, "%s %s %d: 0x%08x != 0x%08x\n", - which, insn, ofs, s->b, e); - err = 1; - } - - if (err) { - exit(1); - } -} - -#define TEST(INSN, OFS, E) \ - do { \ - s.b = 0; \ - asm volatile(INSN " %1, " #OFS "(%0)" \ - : : "r"(&s.b), "r" (0x11223344) : "memory"); \ - check(&s, E, which, INSN, OFS); \ - } while (0) - -static void test(const char *which) -{ - struct S s = { }; - - TEST("stby,b", 0, 0x11223344); - TEST("stby,b", 1, 0x00223344); - TEST("stby,b", 2, 0x00003344); - TEST("stby,b", 3, 0x00000044); - - TEST("stby,e", 0, 0x00000000); - TEST("stby,e", 1, 0x11000000); - TEST("stby,e", 2, 0x11220000); - TEST("stby,e", 3, 0x11223300); -} - -static void *child(void *x) -{ - return NULL; -} - -int main() -{ - int err; - pthread_t thr; - - /* Run test in serial mode */ - test("serial"); - - /* Create a dummy thread to start parallel mode. */ - err = pthread_create(&thr, NULL, child, NULL); - if (err != 0) { - fprintf(stderr, "pthread_create: %s\n", strerror(err)); - return 2; - } - - /* Run test in parallel mode */ - test("parallel"); - return 0; -} diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target deleted file mode 100644 index 9b9038d0bef2..000000000000 --- a/tests/tcg/i386/Makefile.softmmu-target +++ /dev/null @@ -1,47 +0,0 @@ -# -# x86 system tests -# -# This currently builds only for i386. The common C code is built -# with standard compiler flags however so we can support both by -# adding additional boot files for x86_64. -# - -I386_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/i386/system -X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system - -# These objects provide the basic boot code and helper functions for all tests -CRT_OBJS=boot.o - -CRT_PATH=$(I386_SYSTEM_SRC) -LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld -LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386 -CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) -LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc - -TESTS+=$(MULTIARCH_TESTS) -EXTRA_RUNS+=$(MULTIARCH_RUNS) - -# building head blobs -.PRECIOUS: $(CRT_OBJS) - -%.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ - -# Build and link the tests -%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -memory: CFLAGS+=-DCHECK_UNALIGNED=1 - -# non-inline runs will trigger the duplicate instruction heuristics in libinsn.so -run-plugin-%-with-libinsn.so: - $(call run-test, $@, \ - $(QEMU) -monitor none -display none \ - -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)") - -# 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 deleted file mode 100644 index e1c0310be61e..000000000000 --- a/tests/tcg/i386/Makefile.target +++ /dev/null @@ -1,82 +0,0 @@ -# i386 cross compile notes - -I386_SRC=$(SRC_PATH)/tests/tcg/i386 - -# Set search path for all sources -VPATH += $(I386_SRC) - -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)) - -test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse -run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max -run-plugin-test-i386-sse-exceptions-%: QEMU_OPTS += -cpu max - -test-i386-pcmpistri: CFLAGS += -msse4.2 -run-test-i386-pcmpistri: QEMU_OPTS += -cpu max -run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max - -run-test-i386-bmi2: QEMU_OPTS += -cpu max -run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max - -# -# hello-i386 is a barebones app -# -hello-i386: CFLAGS+=-ffreestanding -hello-i386: LDFLAGS+=-nostdlib - -# test-386 includes a couple of additional objects that need to be -# linked together, we also need a no-pie capable compiler due to the -# non-pic calls into 16-bit mode -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_I386_NOPIE),) -test-i386: CFLAGS += -fno-pie - -test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ \ - $( $@,"GENREF","generating $@") - -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 diff-out,test-i386-fprem, test-i386-fprem.ref) -else -SKIP_I386_TESTS+=test-i386-fprem -endif - -# non-inline runs will trigger the duplicate instruction heuristics in libinsn.so -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)") - -# Update TESTS -I386_TESTS:=$(filter-out $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) -TESTS=$(MULTIARCH_TESTS) $(I386_TESTS) - -# On i386 and x86_64 Linux only supports 4k pages (large pages are a different hack) -EXTRA_RUNS+=run-test-mmap-4096 - -sha512-sse: CFLAGS=-msse4.1 -O3 -sha512-sse: sha512.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -run-sha512-sse: QEMU_OPTS+=-cpu max -run-plugin-sha512-sse-with-%: QEMU_OPTS+=-cpu max - -TESTS+=sha512-sse diff --git a/tests/tcg/i386/README b/tests/tcg/i386/README deleted file mode 100644 index 09e88f30dc67..000000000000 --- a/tests/tcg/i386/README +++ /dev/null @@ -1,35 +0,0 @@ -These are i386 specific guest programs - -test-i386 ---------- - -This program executes most of the 16 bit and 32 bit x86 instructions and -generates a text output, for comparison with the output obtained with -a real CPU or another emulator. - -The Linux system call modify_ldt() is used to create x86 selectors -to test some 16 bit addressing and 32 bit with segmentation cases. - -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. - -linux-test ----------- - -This program tests various Linux system calls. It is used to verify -that the system call parameters are correctly converted between target -and host CPUs. - -test-i386-fprem ---------------- - -test-mmap ---------- - -sha1 ----- - -hello-i386 ----------- diff --git a/tests/tcg/i386/hello-i386.c b/tests/tcg/i386/hello-i386.c deleted file mode 100644 index 59196dd0b7d4..000000000000 --- a/tests/tcg/i386/hello-i386.c +++ /dev/null @@ -1,28 +0,0 @@ -#include - -static inline void exit(int status) -{ - int __res; - __asm__ volatile ("movl %%ecx,%%ebx\n"\ - "int $0x80" \ - : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status))); -} - -static inline int write(int fd, const char * buf, int len) -{ - int status; - __asm__ volatile ("pushl %%ebx\n"\ - "movl %%esi,%%ebx\n"\ - "int $0x80\n" \ - "popl %%ebx\n"\ - : "=a" (status) \ - : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); - return status; -} - -void _start(void); -void _start(void) -{ - write(1, "Hello World\n", 12); - exit(0); -} diff --git a/tests/tcg/i386/system/boot.S b/tests/tcg/i386/system/boot.S deleted file mode 100644 index 794c2cb0ad0d..000000000000 --- a/tests/tcg/i386/system/boot.S +++ /dev/null @@ -1,172 +0,0 @@ -/* - * i386 boot code, based on qemu-bmibug. - * - * Copyright 2019 Doug Gale - * Copyright 2019 Linaro - * - * This work is licensed under the terms of the GNU GPL, version 3 or later. - * See the COPYING file in the top-level directory. - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - .section .head - - /* Multi-boot header */ -multiboot_st: - .int 0x1BADB002 - .int 0x10000 - .int -(0x10000+0x1BADB002) - // Load address - .int __load_st - .int __load_st - .int __load_en - .int __bss_en - .int _start - // mode - .int 0 - // width - .int 0 - // height - .int 0 - // depth - .int 0 - - .code32 - .section .text - - /* Kernel Entry Point */ -.global _start -_start: - // Setup stack ASAP - mov $stack_end,%esp - - // Load GDT ASAP - lgdt gdtr - ljmp $0x8,$.Lloadcs -.Lloadcs: - mov $0x10,%eax - mov %eax,%ds - mov %eax,%es - mov %eax,%fs - mov %eax,%gs - mov %eax,%ss - - // Fixup the IDT to the ridiculous i386 layout - xor %ebx,%ebx -.Lnextidt: - mov idt_00(,%ebx,8),%eax - shr $16,%eax - movw $0x8,idt_00+2(,%ebx,8) - movw $0x8E00,idt_00+4(,%ebx,8) - movw %ax,idt_00+6(,%ebx,8) - add $1,%ebx - cmp $32,%ebx - jl .Lnextidt - - // Load IDTR - push $idt_00 - push $((32 * 8 - 1) << 16) - lidt 2(%esp) - add $8,%esp - - /* - * Don't worry about stack frame, assume everthing - * is garbage when we return, we won't need it. - */ - call main - -_exit: /* output any non-zero result in eax to isa-debug-exit device */ - test %al, %al - jz 1f - out %ax, $0xf4 - -1: /* QEMU ACPI poweroff */ - mov $0x604,%edx - mov $0x2000,%eax - out %ax,%dx - hlt - jmp 1b - - /* - * Helper Functions - */ - - /* Output a single character to serial port */ - .global __sys_outc -__sys_outc: - pushl %ebp - movl %esp, %ebp - out %al,$0xE9 - movl %ebp, %esp - popl %ebp - ret - - - /* Interrupt Descriptor Table */ - - .section .data - .align 16 - -idt_00: .int 0, 0 -idt_01: .int 0, 0 -idt_02: .int 0, 0 -idt_03: .int 0, 0 -idt_04: .int 0, 0 -idt_05: .int 0, 0 -idt_06: .int 0, 0 /* intr_6_opcode, Invalid Opcode */ -idt_07: .int 0, 0 -idt_08: .int 0, 0 -idt_09: .int 0, 0 -idt_0A: .int 0, 0 -idt_0B: .int 0, 0 -idt_0C: .int 0, 0 -idt_0D: .int 0, 0 -idt_0E: .int 0, 0 -idt_0F: .int 0, 0 -idt_10: .int 0, 0 -idt_11: .int 0, 0 -idt_12: .int 0, 0 -idt_13: .int 0, 0 -idt_14: .int 0, 0 -idt_15: .int 0, 0 -idt_16: .int 0, 0 -idt_17: .int 0, 0 -idt_18: .int 0, 0 -idt_19: .int 0, 0 -idt_1A: .int 0, 0 -idt_1B: .int 0, 0 -idt_1C: .int 0, 0 -idt_1D: .int 0, 0 -idt_1E: .int 0, 0 -idt_1F: .int 0, 0 - -gdt: - .short 0 -gdtr: - .short gdt_en - gdt - 1 - .int gdt - - // Code - .short 0xFFFF - .short 0 - .byte 0 - .byte 0x9b - .byte 0xCF - .byte 0 - - // Data - .short 0xFFFF - .short 0 - .byte 0 - .byte 0x93 - .byte 0xCF - .byte 0 - -gdt_en: - - .section .bss - .align 16 - -stack: .space 65536 -stack_end: diff --git a/tests/tcg/i386/system/kernel.ld b/tests/tcg/i386/system/kernel.ld deleted file mode 100644 index 27ea5bbe049c..000000000000 --- a/tests/tcg/i386/system/kernel.ld +++ /dev/null @@ -1,23 +0,0 @@ -SECTIONS { - . = 0x100000; - - .text : { - __load_st = .; - *(.head) - *(.text) - } - - .rodata : { - *(.rodata) - } - - .data : { - *(.data*) - __load_en = .; - } - - .bss : { - *(.bss) - __bss_en = .; - } -} diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c deleted file mode 100644 index 935a4d2a736a..000000000000 --- a/tests/tcg/i386/test-i386-bmi2.c +++ /dev/null @@ -1,42 +0,0 @@ -/* See if various BMI2 instructions give expected results */ -#include -#include - -int main(int argc, char *argv[]) { - uint64_t ehlo = 0x202020204f4c4845ull; - uint64_t mask = 0xa080800302020001ull; - uint32_t result32; - -#ifdef __x86_64 - uint64_t result64; - - /* 64 bits */ - asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(ehlo), "m"(mask)); - assert(result64 == 133); - - asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(result64), "m"(mask)); - assert(result64 == (ehlo & mask)); - - asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask)); - assert(result64 == 511); /* mask has 9 bits set */ - - asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask)); - assert(result64 == mask); -#endif - - /* 32 bits */ - asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"((uint32_t) ehlo), "m"(mask)); - assert(result32 == 5); - - asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(result32), "m"(mask)); - assert(result32 == (uint32_t)(ehlo & mask)); - - asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask)); - assert(result32 == 7); /* mask has 3 bits set */ - - asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask)); - assert(result32 == (uint32_t)mask); - - return 0; -} - diff --git a/tests/tcg/i386/test-i386-code16.S b/tests/tcg/i386/test-i386-code16.S deleted file mode 100644 index 816c24b96f47..000000000000 --- a/tests/tcg/i386/test-i386-code16.S +++ /dev/null @@ -1,79 +0,0 @@ - .code16 - .globl code16_start - .globl code16_end - -CS_SEG = 0xf - -code16_start: - - .globl code16_func1 - - /* basic test */ -code16_func1 = . - code16_start - mov $1, %eax - data32 lret - -/* test push/pop in 16 bit mode */ - .globl code16_func2 -code16_func2 = . - code16_start - xor %eax, %eax - mov $0x12345678, %ebx - movl %esp, %ecx - push %bx - subl %esp, %ecx - pop %ax - data32 lret - -/* test various jmp opcodes */ - .globl code16_func3 -code16_func3 = . - code16_start - jmp 1f - nop -1: - mov $4, %eax - mov $0x12345678, %ebx - xor %bx, %bx - jz 2f - add $2, %ax -2: - - call myfunc - - lcall $CS_SEG, $(myfunc2 - code16_start) - - ljmp $CS_SEG, $(myjmp1 - code16_start) -myjmp1_next: - - cs lcall *myfunc2_addr - code16_start - - cs ljmp *myjmp2_addr - code16_start -myjmp2_next: - - data32 lret - -myfunc2_addr: - .short myfunc2 - code16_start - .short CS_SEG - -myjmp2_addr: - .short myjmp2 - code16_start - .short CS_SEG - -myjmp1: - add $8, %ax - jmp myjmp1_next - -myjmp2: - add $16, %ax - jmp myjmp2_next - -myfunc: - add $1, %ax - ret - -myfunc2: - add $4, %ax - lret - - -code16_end: diff --git a/tests/tcg/i386/test-i386-f2xm1.c b/tests/tcg/i386/test-i386-f2xm1.c deleted file mode 100644 index 4513ed8cc103..000000000000 --- a/tests/tcg/i386/test-i386-f2xm1.c +++ /dev/null @@ -1,1140 +0,0 @@ -/* Test f2xm1 instruction. */ - -#include - -struct test { - long double arg, down, up; -}; - -const struct test tests[] = { - { -1.0L, -0.5L, -0.5L }, - { -0.0L, -0.0L, -0.0L }, - { 0.0L, 0.0L, 0.0L }, - /* Randomly generated tests. */ - { 0x4.1481697ac693aa6p-4L, 0x3.17ec9f8454896518p-4L, 0x3.17ec9f845489651cp-4L }, - { -0xd.84a873b14b9c0e2p-4L, -0x7.1788c46ac260d948p-4L, -0x7.1788c46ac260d94p-4L }, - { 0xa.a3dc18b1eff7e8ap-188L, 0x7.6009241b9e21523p-188L, 0x7.6009241b9e215238p-188L }, - { -0xe.846aeb6f58174d5p-92L, -0xa.1006405817acc33p-92L, -0xa.1006405817acc32p-92L }, - { 0x5.4459f2ac77bb0978p-4L, 0x4.19d3ce7fd5b90ac8p-4L, 0x4.19d3ce7fd5b90adp-4L }, - { -0xb.79bece734a62216p-4L, -0x6.4489a7fc150c0fp-4L, -0x6.4489a7fc150c0ef8p-4L }, - { 0xa.ab48f9ef732f5c4p-4L, 0x9.66acd7d4b7cf015p-4L, 0x9.66acd7d4b7cf016p-4L }, - { -0xb.8204e63359a46e6p-4L, -0x6.48060f0a504e3488p-4L, -0x6.48060f0a504e348p-4L }, - { 0xd.c732865701ae935p-4L, 0xd.103bc1a15cd9f71p-4L, 0xd.103bc1a15cd9f72p-4L }, - { -0x1.6296e8ff499827a2p-4L, -0xe.e8dc973f0bce9d1p-8L, -0xe.e8dc973f0bce9dp-8L }, - { 0x8.3e49377820195c8p-4L, 0x6.ddff7e8caa601a08p-4L, 0x6.ddff7e8caa601a1p-4L }, - { -0x7.ece8699d62a9f76p-4L, -0x4.a6516088a15ab01p-4L, -0x4.a6516088a15ab008p-4L }, - { 0x4.b875c0342c9f86b8p-4L, 0x3.a1709cfaecf11ce8p-4L, 0x3.a1709cfaecf11cecp-4L }, - { -0xe.a37e0fa859e499cp-4L, -0x7.83956f7028853738p-4L, -0x7.83956f702885373p-4L }, - { 0x7.23210d9474f0715p-4L, 0x5.cc1ac556913b5258p-4L, 0x5.cc1ac556913b526p-4L }, - { -0xb.755e74862e61e2bp-4L, -0x6.42b11ec6fd4c00dp-4L, -0x6.42b11ec6fd4c00c8p-4L }, - { 0x3.48cc248e266ab90cp-4L, 0x2.724bd1b7f02d354cp-4L, 0x2.724bd1b7f02d355p-4L }, - { -0xa.9a331b76f8ece94p-4L, -0x5.e47b32e80b1f837p-4L, -0x5.e47b32e80b1f8368p-4L }, - { 0x5.8312ebb25c93d22p-4L, 0x4.50bcc3442a6e832p-4L, 0x4.50bcc3442a6e8328p-4L }, - { -0xa.d41581f0036d233p-4L, -0x5.fdb41cec4e2c108p-4L, -0x5.fdb41cec4e2c1078p-4L }, - { 0x4.84a87d8107c5f408p-4L, 0x3.759419ac694e8798p-4L, 0x3.759419ac694e879cp-4L }, - { -0x1.1a592590e007fap-4L, -0xb.f1b5fdf338edbc1p-8L, -0xb.f1b5fdf338edbcp-8L }, - { 0x2.72f96b27827d2054p-4L, 0x1.ca7a491c0c9ae094p-4L, 0x1.ca7a491c0c9ae096p-4L }, - { -0x8.34634eae18e60c5p-4L, -0x4.c941052638a95e6p-4L, -0x4.c941052638a95e58p-4L }, - { 0x2.f6cff94cffe53048p-180L, 0x2.0df7fb06812da41p-180L, 0x2.0df7fb06812da414p-180L }, - { -0x3.e0779bd58963da5p-120L, -0x2.afed04ed88e2c16cp-120L, -0x2.afed04ed88e2c168p-120L }, - { 0xc.1c72a98f7733051p-4L, 0xb.09ddaf3c3330ff9p-4L, 0xb.09ddaf3c3330ffap-4L }, - { -0x9.6eacf3012c77e7p-4L, -0x5.5df25bc91430e81p-4L, -0x5.5df25bc91430e808p-4L }, - { 0x4.962ce97c4afbc1f8p-4L, 0x3.845e1e9659d35364p-4L, 0x3.845e1e9659d35368p-4L }, - { -0xa.a7735b993f17f55p-4L, -0x5.ea46e99ae5f6dce8p-4L, -0x5.ea46e99ae5f6dcep-4L }, - { 0x5.155f76560f08fccp-4L, 0x3.f1149b22956dff34p-4L, 0x3.f1149b22956dff38p-4L }, - { -0xd.32a453289bd47b3p-4L, -0x6.f7a99ad68a5d961p-4L, -0x6.f7a99ad68a5d9608p-4L }, - { 0xa.9942e7418052b4bp-4L, 0x9.52df2bbafc3218bp-4L, 0x9.52df2bbafc3218cp-4L }, - { -0x5.4f4efad2aff4f76p-4L, -0x3.49afb77e7a12385p-4L, -0x3.49afb77e7a12384cp-4L }, - { 0x3.c9e289d962998608p-4L, 0x2.da96d228ab6c8fd8p-4L, 0x2.da96d228ab6c8fdcp-4L }, - { -0x7.cc295689678770bp-4L, -0x4.962bd983de0367b8p-4L, -0x4.962bd983de0367bp-4L }, - { 0xa.8fc7c1f2a46626cp-4L, 0x9.487a90c858224c9p-4L, 0x9.487a90c858224cap-4L }, - { -0x8.a1d9201d5f09ad6p-4L, -0x4.fdf0ccee86f8d98p-4L, -0x4.fdf0ccee86f8d978p-4L }, - { 0x7.5b8ee6778ad1d64p-4L, 0x6.01a5419abf1cb4f8p-4L, 0x6.01a5419abf1cb5p-4L }, - { -0x9.d20d0f7fc98548p-4L, -0x5.8b571e52bd288448p-4L, -0x5.8b571e52bd28844p-4L }, - { 0x5.f135e81ee2608d4p-4L, 0x4.b293c42ca99fd6e8p-4L, 0x4.b293c42ca99fd6fp-4L }, - { -0x5.d981a42b6b7a36fp-4L, -0x3.94e920725edbe7d4p-4L, -0x3.94e920725edbe7dp-4L }, - { 0xa.edffe301db8be0bp-4L, 0x9.b08144d0a85602p-4L, 0x9.b08144d0a856021p-4L }, - { -0x4.5a026d37f55f1d18p-4L, -0x2.bfc10df32554a28cp-4L, -0x2.bfc10df32554a288p-4L }, - { 0x7.82c193b48128193p-4L, 0x6.2723ac59ee5faf68p-4L, 0x6.2723ac59ee5faf7p-4L }, - { -0xd.2d0fe1cd05a87f4p-4L, -0x6.f57a61e00a5f24bp-4L, -0x6.f57a61e00a5f24a8p-4L }, - { 0x5.e1494f95151c64fp-196L, 0x4.13628f9a498f05d8p-196L, 0x4.13628f9a498f05ep-196L }, - { -0x4.51babb72810e518p-140L, -0x2.fe6ee847d0741a5cp-140L, -0x2.fe6ee847d0741a58p-140L }, - { 0xb.638d8454a685474p-4L, 0xa.34a429815e10dc1p-4L, 0xa.34a429815e10dc2p-4L }, - { -0xb.9ec4e9f266dce49p-4L, -0x6.54194f84395ed2b8p-4L, -0x6.54194f84395ed2bp-4L }, - { 0xe.4b7a4c83290855cp-4L, 0xd.b8a9a282646fa0cp-4L, 0xd.b8a9a282646fa0dp-4L }, - { -0xf.13ec97b6c4f17a7p-4L, -0x7.ac86ac65cc0a8878p-4L, -0x7.ac86ac65cc0a887p-4L }, - { 0x3.8ded178a72c15bcp-4L, 0x2.a9dd11713298de98p-4L, 0x2.a9dd11713298de9cp-4L }, - { -0xd.36a9965916287d1p-4L, -0x6.f93c3981d5369078p-4L, -0x6.f93c3981d536907p-4L }, - { 0x6.b3a10f94dcd70e1p-4L, 0x5.63cd831188f697c8p-4L, 0x5.63cd831188f697dp-4L }, - { -0xc.8517674f15bbcbfp-4L, -0x6.b2be7a8ee34bfc8p-4L, -0x6.b2be7a8ee34bfc78p-4L }, - { 0xb.204e5335e697f73p-4L, 0x9.e8bb034ff53dc6p-4L, 0x9.e8bb034ff53dc61p-4L }, - { -0x8.913a951884085ddp-4L, -0x4.f60101f7884f4f6p-4L, -0x4.f60101f7884f4f58p-4L }, - { 0x4.5861903e9a2c5178p-4L, 0x3.50645bac48af734cp-4L, 0x3.50645bac48af735p-4L }, - { -0x5.24585590086993p-4L, -0x3.31f08d8ca7e0c6e4p-4L, -0x3.31f08d8ca7e0c6ep-4L }, - { 0xf.2ba8f23d35f13f9p-4L, 0xe.dedc34179a9e3acp-4L, 0xe.dedc34179a9e3adp-4L }, - { -0xa.3ecdb386b33fbe5p-4L, -0x5.bc2672b634fa598p-4L, -0x5.bc2672b634fa5978p-4L }, - { 0x9.9b8e544f05c6de4p-8L, 0x6.bf33cd9ab91f6d28p-8L, 0x6.bf33cd9ab91f6d3p-8L }, - { -0x7.abd5585035c4696p-4L, -0x4.862497557f052a6p-4L, -0x4.862497557f052a58p-4L }, - { 0xa.e654e5ca1c1d1fbp-4L, 0x9.a7fa0d5fa5d62cbp-4L, 0x9.a7fa0d5fa5d62ccp-4L }, - { -0x7.8b963b5c9698ae88p-8L, -0x5.2d4a519ba339886p-8L, -0x5.2d4a519ba3398858p-8L }, - { 0xb.ea47beace8589dep-4L, 0xa.cf59bd897bb1319p-4L, 0xa.cf59bd897bb131ap-4L }, - { -0x3.8f66d5a2d60e1fc8p-4L, -0x2.496dee34a71055ap-4L, -0x2.496dee34a710559cp-4L }, - { 0x3.1a53eaa26d0157p-188L, 0x2.269608f745c0b83p-188L, 0x2.269608f745c0b834p-188L }, - { -0x8.6659e1a891ccbd3p-96L, -0x5.d282825fc03c7ca8p-96L, -0x5.d282825fc03c7cap-96L }, - { 0x9.4ae3410622cd598p-4L, 0x7.ee3a22f81622643p-4L, 0x7.ee3a22f816226438p-4L }, - { -0x9.b8fe7ab721fb04cp-4L, -0x5.7ff768a6654000e8p-4L, -0x5.7ff768a6654000ep-4L }, - { 0x4.ee554b54200eeb18p-4L, 0x3.cf77028b579146a8p-4L, 0x3.cf77028b579146acp-4L }, - { -0x1.e1d0727b5f12c23cp-8L, -0x1.4d1e625247cef1dap-8L, -0x1.4d1e625247cef1d8p-8L }, - { 0x8.f3637cea7b9b0b8p-4L, 0x7.942f15c8b77d89c8p-4L, 0x7.942f15c8b77d89dp-4L }, - { -0x2.f3202c602060bd7cp-4L, -0x1.eb59cec0fd5e5b22p-4L, -0x1.eb59cec0fd5e5b2p-4L }, - { 0xc.cdb9d9e3a3a5b61p-4L, 0xb.dcaaf5c009c0684p-4L, 0xb.dcaaf5c009c0685p-4L }, - { -0x5.7ddc79efb147e828p-4L, -0x3.63390bf8b99265d4p-4L, -0x3.63390bf8b99265dp-4L }, - { 0x6.7236b6f8976437ap-4L, 0x5.27852c069a4fd5ep-4L, 0x5.27852c069a4fd5e8p-4L }, - { -0x5.e1ad137b44bc3ad8p-4L, -0x3.994d814216774764p-4L, -0x3.994d81421677476p-4L }, - { 0xb.f5ec1a26fcc9d7ep-4L, 0xa.dce2b2a69a74106p-4L, 0xa.dce2b2a69a74107p-4L }, - { -0xd.dcb826624975b1ep-4L, -0x7.394429db03b0d5e8p-4L, -0x7.394429db03b0d5ep-4L }, - { 0x1.a983e64980e6104p-4L, 0x1.31d2cb35db04030ep-4L, 0x1.31d2cb35db04031p-4L }, - { -0xa.14ebef82079ff92p-4L, -0x5.a9758de717320278p-4L, -0x5.a9758de71732027p-4L }, - { 0x1.e4fcc97f32b404d8p-4L, 0x1.5e5913e4b0dadd5ep-4L, 0x1.5e5913e4b0dadd6p-4L }, - { -0xe.9391126d81ddf25p-4L, -0x7.7db899379b97afep-4L, -0x7.7db899379b97afd8p-4L }, - { 0xb.83be497f42b1776p-8L, 0x8.1b67845064d833ap-8L, 0x8.1b67845064d833bp-8L }, - { -0xb.6c13349b9671c7bp-4L, -0x6.3ec4737bebffb8f8p-4L, -0x6.3ec4737bebffb8fp-4L }, - { 0xd.00d476fab7a907dp-4L, 0xc.1a9e868d759da06p-4L, 0xc.1a9e868d759da07p-4L }, - { -0x3.bf394566ed3e5a44p-4L, -0x2.65b989f46e7a2458p-4L, -0x2.65b989f46e7a2454p-4L }, - { 0x7.4a72aacaec9cd52p-52L, 0x5.0db91de577a1e5c8p-52L, 0x5.0db91de577a1e5dp-52L }, - { -0x4.3354d8429f36037p-24L, -0x2.e95ce5bede67faap-24L, -0x2.e95ce5bede67fa9cp-24L }, - { 0x5.431e650334b97d18p-4L, 0x4.18c10ccaa716c258p-4L, 0x4.18c10ccaa716c26p-4L }, - { -0xf.1eb2c535e06fba3p-4L, -0x7.b068a3edafc6822p-4L, -0x7.b068a3edafc68218p-4L }, - { 0x8.54a857fb1034b62p-4L, 0x6.f433cc318f296fep-4L, 0x6.f433cc318f296fe8p-4L }, - { -0xa.d3c15d582c446d9p-4L, -0x5.fd8fa08a9be23ac8p-4L, -0x5.fd8fa08a9be23acp-4L }, - { 0xc.cb73edcbfcb307fp-4L, 0xb.d9ecb2c64e8df6bp-4L, 0xb.d9ecb2c64e8df6cp-4L }, - { -0x3.fb61f1b2cf35f60cp-4L, -0x2.88fef3c7864d396cp-4L, -0x2.88fef3c7864d3968p-4L }, - { 0x9.d7eb5c50bc8c632p-4L, 0x8.8231f68c5c65f6cp-4L, 0x8.8231f68c5c65f6dp-4L }, - { -0x4.d312891f5f4e786p-4L, -0x3.048b329391356fc8p-4L, -0x3.048b329391356fc4p-4L }, - { 0xe.ae0633b99b178edp-4L, 0xe.389ce9e10301401p-4L, 0xe.389ce9e10301402p-4L }, - { -0x1.39568b7ef55672cp-4L, -0xd.38818f18029f0edp-8L, -0xd.38818f18029f0ecp-8L }, - { 0x4.cf293b1353f539bp-4L, 0x3.b4c86315977b5c7cp-4L, 0x3.b4c86315977b5c8p-4L }, - { -0xd.2b8a9e00126538ap-4L, -0x6.f4e1e5a5bc2731ap-4L, -0x6.f4e1e5a5bc273198p-4L }, - { 0x5.b5eb2a3dcc35826p-8L, 0x3.fd3309c0a1b58598p-8L, 0x3.fd3309c0a1b5859cp-8L }, - { -0xa.db19f19a7ea88bep-4L, -0x6.00be987018657798p-4L, -0x6.00be98701865779p-4L }, - { 0x1.09017c7c80c2c48ap-4L, 0xb.bde7d981fb53b8ep-8L, 0xb.bde7d981fb53b8fp-8L }, - { -0x2.5ae089add9bdff18p-4L, -0x1.8d45d20a5f7c4556p-4L, -0x1.8d45d20a5f7c4554p-4L }, - { 0x6.d211b21df46dcc18p-4L, 0x5.801525b9519ab1cp-4L, 0x5.801525b9519ab1c8p-4L }, - { -0xd.1a64a16c7c8f6d7p-4L, -0x6.ee27813a5adc48a8p-4L, -0x6.ee27813a5adc48ap-4L }, - { 0xc.1ef9ffac1d2c793p-4L, 0xb.0cd41b95ab8f726p-4L, 0xb.0cd41b95ab8f727p-4L }, - { -0x1.67c59b4c06bd7496p-4L, -0xf.1ef71ffc4b3edp-8L, -0xf.1ef71ffc4b3ecffp-8L }, - { 0x8.ba4b4feae22142bp-168L, 0x6.0cb1d8faa6f42ce8p-168L, 0x6.0cb1d8faa6f42cfp-168L }, - { -0x4.d89f7b5a88882dbp-32L, -0x3.5bef2f703124413p-32L, -0x3.5bef2f703124412cp-32L }, - { 0xb.03fa4c349a339d2p-4L, 0x9.c902a02a0215ad1p-4L, 0x9.c902a02a0215ad2p-4L }, - { -0x1.e57ddc8153f3ba8p-8L, -0x1.4fa797d98bce1f74p-8L, -0x1.4fa797d98bce1f72p-8L }, - { 0xc.9c281b57f7d11c8p-4L, 0xb.a11623dd20659ecp-4L, 0xb.a11623dd20659edp-4L }, - { -0x6.8fac6e3f60b61e1p-4L, -0x3.f56b115363b7d2d8p-4L, -0x3.f56b115363b7d2d4p-4L }, - { 0x3.65bed5b32d99326p-4L, 0x2.897c78eee4adc054p-4L, 0x2.897c78eee4adc058p-4L }, - { -0x2.3ef31cc65b2354cp-4L, -0x1.7bc0457bdf14a022p-4L, -0x1.7bc0457bdf14a02p-4L }, - { 0x2.bceec8bc1d31b0ccp-4L, 0x2.03d68f4acad10114p-4L, 0x2.03d68f4acad10118p-4L }, - { -0xd.146217a63673958p-4L, -0x6.ebcaaea4b926a99p-4L, -0x6.ebcaaea4b926a988p-4L }, - { 0x2.17b7fc97b1f46e7cp-4L, 0x1.84af2ad78df6619cp-4L, 0x1.84af2ad78df6619ep-4L }, - { -0x4.49abbcdefc0c959p-4L, -0x2.b65ca46b981930ecp-4L, -0x2.b65ca46b981930e8p-4L }, - { 0x3.efc6f5f489c6c7bcp-4L, 0x2.f9a3671c9c3698fcp-4L, 0x2.f9a3671c9c3699p-4L }, - { -0x8.f7ff40b96f9bd91p-4L, -0x5.26b9d6a96a7c7d4p-4L, -0x5.26b9d6a96a7c7d38p-4L }, - { 0x6.003126d0e9a9acc8p-4L, 0x4.c0070418e60c3eap-4L, 0x4.c0070418e60c3ea8p-4L }, - { -0x5.7be9edcc9dc2a02p-4L, -0x3.6228999b34cd56c8p-4L, -0x3.6228999b34cd56c4p-4L }, - { 0x7.8952a49ff2c2f168p-4L, 0x6.2d71e3ee870f2fp-4L, 0x6.2d71e3ee870f2f08p-4L }, - { -0x3.8a644fc56f9d1fbp-4L, -0x2.4673b0704862205cp-4L, -0x2.4673b07048622058p-4L }, - { 0xf.c1271b0a53a3319p-4L, 0xf.a9563e019f9388ep-4L, 0xf.a9563e019f9388fp-4L }, - { -0x8.a07f742f2a61d18p-4L, -0x4.fd4bef713b1bf35p-4L, -0x4.fd4bef713b1bf348p-4L }, - { 0xf.ce2fc60abd9a47cp-4L, 0xf.bb3bf685a5fb078p-4L, 0xf.bb3bf685a5fb079p-4L }, - { -0x9.e8a3a1c0f885e07p-4L, -0x5.958d6298d2833328p-4L, -0x5.958d6298d283332p-4L }, - { 0xd.11c135742977841p-96L, 0x9.0f19b73e51b46a5p-96L, 0x9.0f19b73e51b46a6p-96L }, - { -0x1.0028929dbde83802p-60L, -0xb.18e376bf8ce7ca1p-64L, -0xb.18e376bf8ce7cap-64L }, - { 0x5.244b484bc9bb7828p-4L, 0x3.fdfcc0ee0ab5b92p-4L, 0x3.fdfcc0ee0ab5b924p-4L }, - { -0x7.02ec4c8b2cc95998p-4L, -0x4.30f4ae1282b41938p-4L, -0x4.30f4ae1282b4193p-4L }, - { 0xa.4d34be63f5bedffp-4L, 0x8.fff7fb1648dba28p-4L, 0x8.fff7fb1648dba29p-4L }, - { -0xf.be786c39b309e8p-4L, -0x7.e929ac0fe4454fbp-4L, -0x7.e929ac0fe4454fa8p-4L }, - { 0x6.16481538d3215558p-4L, 0x4.d3ebea6da53ed4bp-4L, 0x4.d3ebea6da53ed4b8p-4L }, - { -0x8.5ea05eecb9ac14dp-4L, -0x4.ddb34f8925005bf8p-4L, -0x4.ddb34f8925005bfp-4L }, - { 0xd.4be5b4aaf95a52bp-4L, 0xc.7698fe58f5fbc96p-4L, 0xc.7698fe58f5fbc97p-4L }, - { -0x5.505294ddb8af9558p-4L, -0x3.4a3eaba09a1a5584p-4L, -0x3.4a3eaba09a1a558p-4L }, - { 0xf.a2f9540a64c79ap-8L, 0xb.1239629d9548b9ap-8L, 0xb.1239629d9548b9bp-8L }, - { -0x2.b68cfa7df5a80aep-4L, -0x1.c635cc5a0e342052p-4L, -0x1.c635cc5a0e34205p-4L }, - { 0xb.8ac8e4b25441b53p-4L, 0xa.6154102e9f6deb3p-4L, 0xa.6154102e9f6deb4p-4L }, - { -0x2.047a032c2a353b58p-4L, -0x1.56cbb83364a118fcp-4L, -0x1.56cbb83364a118fap-4L }, - { 0x8.eb2ab17c06312d9p-4L, 0x7.8bca95748b755068p-4L, 0x7.8bca95748b75507p-4L }, - { -0xb.932fffb0dfd7537p-4L, -0x6.4f3dd628a0e5cf6p-4L, -0x6.4f3dd628a0e5cf58p-4L }, - { 0x4.e0e6c013f25279bp-4L, 0x3.c3f354fd7de31834p-4L, 0x3.c3f354fd7de31838p-4L }, - { -0xa.7fafcf461e92982p-4L, -0x5.d8d88aa29bb4cebp-4L, -0x5.d8d88aa29bb4cea8p-4L }, - { 0x6.41b8cd66b9392ef8p-4L, 0x4.fb4312effd41adb8p-4L, 0x4.fb4312effd41adcp-4L }, - { -0xf.d372339bf2bef0fp-4L, -0x7.f0801caf476622cp-4L, -0x7.f0801caf476622b8p-4L }, - { 0xf.843d63b0a71eb93p-4L, 0xf.56375011490bccp-4L, 0xf.56375011490bcc1p-4L }, - { -0xe.679784396815117p-4L, -0x7.6d735bc4f5da77p-4L, -0x7.6d735bc4f5da76f8p-4L }, - { 0x2.d7c4bef6577f86p-168L, 0x1.f87361c88ca3f5dcp-168L, 0x1.f87361c88ca3f5dep-168L }, - { -0x3.f871c581e5f5dc24p-128L, -0x2.c08bab62f3684a08p-128L, -0x2.c08bab62f3684a04p-128L }, - { 0x9.f6c4eb5c911111ap-4L, 0x8.a309258b14973d6p-4L, 0x8.a309258b14973d7p-4L }, - { -0xa.08c53e65e98b067p-4L, -0x5.a402f5ec7cf294fp-4L, -0x5.a402f5ec7cf294e8p-4L }, - { 0x4.1a4c613ba5fe16ap-4L, 0x3.1cb7e0a2f57d95e4p-4L, 0x3.1cb7e0a2f57d95e8p-4L }, - { -0xd.36e91d3e54f0432p-4L, -0x6.f95510d133d9ba9p-4L, -0x6.f95510d133d9ba88p-4L }, - { 0xd.1de964de30857a7p-4L, 0xc.3e1d28af4fff2d7p-4L, 0xc.3e1d28af4fff2d8p-4L }, - { -0x8.604a0e63d4f5df1p-4L, -0x4.de809bb2d3dfaec8p-4L, -0x4.de809bb2d3dfaecp-4L }, - { 0xc.6b9d18c70882d52p-4L, 0xb.67389c48f17db3ap-4L, 0xb.67389c48f17db3bp-4L }, - { -0x2.711b4139fbed3dc8p-4L, -0x1.9b290dfa49d31a48p-4L, -0x1.9b290dfa49d31a46p-4L }, - { 0x9.4021cab7a0d78bbp-4L, 0x7.e3162eb6a1bdbe8p-4L, 0x7.e3162eb6a1bdbe88p-4L }, - { -0x8.305eb92b4243ea2p-4L, -0x4.c74d292fe63f0918p-4L, -0x4.c74d292fe63f091p-4L }, - { 0x4.f0330cdb93893948p-4L, 0x3.d111183eddd7d2p-4L, 0x3.d111183eddd7d204p-4L }, - { -0xe.be93c7764505ff9p-8L, -0xa.04ccfff3805ed0dp-8L, -0xa.04ccfff3805ed0cp-8L }, - { 0xd.ea533ffe043e52bp-4L, 0xd.3c980125a65c5dfp-4L, 0xd.3c980125a65c5ep-4L }, - { -0x1.1dd2693fe11489c2p-4L, -0xc.166d57fe9c4abe2p-8L, -0xc.166d57fe9c4abe1p-8L }, - { 0x2.0397d0e9676f1b2p-4L, 0x1.756fb86ebc62a682p-4L, 0x1.756fb86ebc62a684p-4L }, - { -0xa.9002b4ad763bb7cp-4L, -0x5.e0041011e34ae53p-4L, -0x5.e0041011e34ae528p-4L }, - { 0x3.34a5a4894a28659cp-4L, 0x2.623883e4934c92d8p-4L, 0x2.623883e4934c92dcp-4L }, - { -0xd.c27cd78e0864371p-4L, -0x7.2f454c780b622d58p-4L, -0x7.2f454c780b622d5p-4L }, - { 0x9.c7f27c2034ec1cfp-4L, 0x8.714272ce09a4f87p-4L, 0x8.714272ce09a4f88p-4L }, - { -0xa.a9e0aa658eda7dcp-4L, -0x5.eb564d46b128566p-4L, -0x5.eb564d46b1285658p-4L }, - { 0xa.0183ad6b5f24f24p-148L, 0x6.ef81a75cf4925d9p-148L, 0x6.ef81a75cf4925d98p-148L }, - { -0x2.0bdfa7925a4bf4ap-28L, -0x1.6b1f1d70f143adc4p-28L, -0x1.6b1f1d70f143adc2p-28L }, - { 0xa.93e861896961066p-4L, 0x9.4d004c2eac2676fp-4L, 0x9.4d004c2eac2677p-4L }, - { -0xd.4c10bf60bb97196p-4L, -0x7.0196eb9b79274b88p-4L, -0x7.0196eb9b79274b8p-4L }, - { 0x4.ff124c9911f2538p-4L, 0x3.ddd9b3e49fd11e9p-4L, 0x3.ddd9b3e49fd11e94p-4L }, - { -0x8.776b58ba7268d9ep-4L, -0x4.e9a2512b1cd9282p-4L, -0x4.e9a2512b1cd92818p-4L }, - { 0x9.b6f6d16f1d76615p-4L, 0x8.5f4d5e77db1195p-4L, 0x8.5f4d5e77db11951p-4L }, - { -0x9.b667363949a8b6dp-4L, -0x5.7ec9a21714bc48c8p-4L, -0x5.7ec9a21714bc48cp-4L }, - { 0x9.799737c602ebc35p-12L, 0x6.92a3d4df8ac3168p-12L, 0x6.92a3d4df8ac31688p-12L }, - { -0x9.dc0d38d251990e4p-4L, -0x5.8fddc90938b5c8a8p-4L, -0x5.8fddc90938b5c8ap-4L }, - { 0x1.51d68e213ec66d4ep-4L, 0xf.0feacd9b26e94efp-8L, 0xf.0feacd9b26e94fp-8L }, - { -0xd.c78a8c73db2538p-4L, -0x7.313326148c62dbd8p-4L, -0x7.313326148c62dbdp-4L }, - { 0x7.c5f3d0d9d9db89cp-4L, 0x6.67fee55e98a6cf7p-4L, 0x6.67fee55e98a6cf78p-4L }, - { -0x1.6b364994830303c2p-4L, -0xf.42da9bf688d1dbp-8L, -0xf.42da9bf688d1dafp-8L }, - { 0x4.2513fed56a721cp-4L, 0x3.25a6d8fff7773d4cp-4L, 0x3.25a6d8fff7773d5p-4L }, - { -0x3.e183251bd312b9f8p-4L, -0x2.79df44b0dabf9e1p-4L, -0x2.79df44b0dabf9e0cp-4L }, - { 0x5.372c1f6cb3bb4cep-8L, 0x3.a4094f9b223ac4d8p-8L, 0x3.a4094f9b223ac4dcp-8L }, - { -0xc.30d4cc265a07403p-4L, -0x6.908bed536532ac7p-4L, -0x6.908bed536532ac68p-4L }, - { 0xf.7e3aa552d45b234p-4L, 0xf.4e0f6f1aac5a5e6p-4L, 0xf.4e0f6f1aac5a5e7p-4L }, - { -0x3.9a644e95053aaf1cp-4L, -0x2.4ff3cc5ef967d1bcp-4L, -0x2.4ff3cc5ef967d1b8p-4L }, - { 0xe.85839cd58ef2c75p-4L, 0xe.03c1d8a304b280dp-4L, 0xe.03c1d8a304b280ep-4L }, - { -0x7.8809e818c58ede8p-4L, -0x4.744b120d61aa22b8p-4L, -0x4.744b120d61aa22bp-4L }, - { 0xd.d9ee24413681697p-176L, 0x9.99d9ff1a3fe5cecp-176L, 0x9.99d9ff1a3fe5cedp-176L }, - { -0x3.40d11dc412df0dd4p-140L, -0x2.4143c0acd05aa3fcp-140L, -0x2.4143c0acd05aa3f8p-140L }, - { 0x5.0487ddb4070bf26p-4L, 0x3.e28d14d38a11cea8p-4L, 0x3.e28d14d38a11ceacp-4L }, - { -0x5.a0e26438dfac03cp-4L, -0x3.764d74346acb839p-4L, -0x3.764d74346acb838cp-4L }, - { 0x4.cfd480a28c2b6b48p-4L, 0x3.b55a9c63e74d1b2cp-4L, 0x3.b55a9c63e74d1b3p-4L }, - { -0x1.8657dd64795c35ap-4L, -0x1.05d2980556ab36f8p-4L, -0x1.05d2980556ab36f6p-4L }, - { 0x1.262cb60430e5eb9ep-4L, 0xd.11128880978613p-8L, 0xd.111288809786131p-8L }, - { -0x8.0e85fe0bcf8a253p-4L, -0x4.b6ccdbc2803a24p-4L, -0x4.b6ccdbc2803a23f8p-4L }, - { 0x3.cefbd3ecacf92c44p-4L, 0x2.dec16ac730be9dbp-4L, 0x2.dec16ac730be9db4p-4L }, - { -0x5.f20def7196dea63p-4L, -0x3.a216f486f08b5aecp-4L, -0x3.a216f486f08b5ae8p-4L }, - { 0x1.3a394f91198290bcp-4L, 0xd.fb2be9402707d47p-8L, 0xd.fb2be9402707d48p-8L }, - { -0x5.fa0cb4bdfd2d7318p-4L, -0x3.a65ec6a869e7e184p-4L, -0x3.a65ec6a869e7e18p-4L }, - { 0x4.08cc4ee18d971c48p-4L, 0x3.0e3ffd7c5370e6b8p-4L, 0x3.0e3ffd7c5370e6bcp-4L }, - { -0xc.08ff29dce9d081fp-4L, -0x6.8035806826b593e8p-4L, -0x6.8035806826b593ep-4L }, - { 0x8.84e7a8e11ece222p-4L, 0x7.2460415572a2c778p-4L, 0x7.2460415572a2c78p-4L }, - { -0x3.6ac116d0aa98b8bp-4L, -0x2.3397207a04b6d448p-4L, -0x2.3397207a04b6d444p-4L }, - { 0x5.b4cccaf7aee9cd6p-4L, 0x4.7caf8d9a7c39bdf8p-4L, 0x4.7caf8d9a7c39bep-4L }, - { -0xd.08cda37bcd9c8cp-4L, -0x6.e73b932483f4027p-4L, -0x6.e73b932483f40268p-4L }, - { 0xb.d7f74d7d0014f61p-4L, 0xa.ba1cc39b8135ef5p-4L, 0xa.ba1cc39b8135ef6p-4L }, - { -0xa.7263655e0a0ea62p-4L, -0x5.d2fd72c3fb172f98p-4L, -0x5.d2fd72c3fb172f9p-4L }, - { 0x2.47b34fa6f1ad5d68p-4L, 0x1.a93f34ee2980e0cap-4L, 0x1.a93f34ee2980e0ccp-4L }, - { -0x8.fcbb11c22f14e77p-4L, -0x5.28f3257a6e3ab71p-4L, -0x5.28f3257a6e3ab708p-4L }, - { 0xf.9268d3496434d05p-16L, 0xa.cb65631de896653p-16L, 0xa.cb65631de896654p-16L }, - { -0x6.90a7904ae1f6ca48p-172L, -0x4.8cf0e2bc08a21768p-172L, -0x4.8cf0e2bc08a2176p-172L }, - { 0xf.e7cc8c0c8fca8d6p-4L, 0xf.de84d77e096dc2cp-4L, 0xf.de84d77e096dc2dp-4L }, - { -0xb.5766572c78c1636p-4L, -0x6.3603cb668acec5ep-4L, -0x6.3603cb668acec5d8p-4L }, - { 0x7.08271953e92da93p-4L, 0x5.b2b05f792a83ec2p-4L, 0x5.b2b05f792a83ec28p-4L }, - { -0xe.0f6704c35bc87d8p-4L, -0x7.4c742ba7517a322p-4L, -0x7.4c742ba7517a3218p-4L }, - { 0x3.622e5c923b06d66cp-8L, 0x2.5b264a119b7052e8p-8L, 0x2.5b264a119b7052ecp-8L }, - { -0x8.911302b7a344f8ap-4L, -0x4.f5ee153ff9a408ap-4L, -0x4.f5ee153ff9a40898p-4L }, - { 0x5.5234861ad0d016d8p-4L, 0x4.25e7cdeba20def88p-4L, 0x4.25e7cdeba20def9p-4L }, - { -0x8.87063dd41e8a8bbp-4L, -0x4.f11ea0bcf9eb3e7p-4L, -0x4.f11ea0bcf9eb3e68p-4L }, - { 0x4.e1420e7e82cd22dp-4L, 0x3.c44184744892d3ecp-4L, 0x3.c44184744892d3fp-4L }, - { -0xb.db1fc14ef9e7aa3p-4L, -0x6.6d4209f7697a729p-4L, -0x6.6d4209f7697a7288p-4L }, - { 0xc.8346ca25bd9f342p-4L, 0xb.835e70838f32309p-4L, 0xb.835e70838f3230ap-4L }, - { -0x1.51646879b012b5b8p-4L, -0xe.34fbed59aa6c7acp-8L, -0xe.34fbed59aa6c7abp-8L }, - { 0x2.b32d8027c5516654p-4L, 0x1.fc3b2ff7be6c91e6p-4L, 0x1.fc3b2ff7be6c91e8p-4L }, - { -0x6.fd1366df02fe9c5p-4L, -0x4.2df6864ab991689p-4L, -0x4.2df6864ab9916888p-4L }, - { 0x6.c090b4e367d6c7ep-8L, 0x4.b92b6f86425d3ccp-8L, 0x4.b92b6f86425d3cc8p-8L }, - { -0x5.081c001c09df9f3p-4L, -0x3.223d2d4760b053ap-4L, -0x3.223d2d4760b0539cp-4L }, - { 0x7.f9714aab4e09b278p-4L, 0x6.9a31bedda6cc2ab8p-4L, 0x6.9a31bedda6cc2acp-4L }, - { -0x6.4804670d1e062cd8p-4L, -0x3.cfcfa1c45c5a88e8p-4L, -0x3.cfcfa1c45c5a88e4p-4L }, - { 0x9.ef4abcd7f8e696ap-4L, 0x8.9b0f698e7955a9p-4L, 0x8.9b0f698e7955a91p-4L }, - { -0x4.8c4513525f5a0ap-4L, -0x2.dc7be2a249c73a38p-4L, -0x2.dc7be2a249c73a34p-4L }, - { 0x1.7fe67833e1976e6p-168L, 0x1.0a1971aebce11604p-168L, 0x1.0a1971aebce11606p-168L }, - { -0xe.a86b5a2c843f668p-36L, -0xa.28fa9875dd806c6p-36L, -0xa.28fa9875dd806c5p-36L }, - { 0x6.0dd96d442bc44b28p-4L, 0x4.cc518e951f69bd48p-4L, 0x4.cc518e951f69bd5p-4L }, - { -0x3.e88917f9e6c0bb2p-4L, -0x2.7dfc064ecfe2635cp-4L, -0x2.7dfc064ecfe26358p-4L }, - { 0xf.e9c0adcf6e6ebaap-4L, 0xf.e13773c6da26f73p-4L, 0xf.e13773c6da26f74p-4L }, - { -0xe.6049cc9d4ea9c32p-8L, -0x9.c5f8986aafe8b3p-8L, -0x9.c5f8986aafe8b2fp-8L }, - { 0xd.e0ca0ae677c56c7p-4L, 0xd.30868169c79fdeap-4L, 0xd.30868169c79fdebp-4L }, - { -0x3.b604528c1bde4ca8p-4L, -0x2.604b88132e3dceb4p-4L, -0x2.604b88132e3dcebp-4L }, - { 0x9.3e94ea277274ab3p-4L, 0x7.e17b8968152545ep-4L, 0x7.e17b8968152545e8p-4L }, - { -0xf.ec080621a8d9456p-4L, -0x7.f91153ca519955fp-4L, -0x7.f91153ca519955e8p-4L }, - { 0x1.96ef7e6b80e63adep-4L, 0x1.24014f5d43fc1232p-4L, 0x1.24014f5d43fc1234p-4L }, - { -0x2.fd0a9d9f59d83bc8p-4L, -0x1.f164f450f8e2c15p-4L, -0x1.f164f450f8e2c14ep-4L }, - { 0x5.82923d4fd6f683p-4L, 0x4.504b840326d2f688p-4L, 0x4.504b840326d2f69p-4L }, - { -0x2.5fa1d9a3a5a2b664p-4L, -0x1.903f73ce566d8522p-4L, -0x1.903f73ce566d852p-4L }, - { 0xf.b8a161f6eba3189p-4L, 0xf.9da7e29775ea166p-4L, 0xf.9da7e29775ea167p-4L }, - { -0xb.79a14c17c57922dp-4L, -0x6.447d36e53f9fbf98p-4L, -0x6.447d36e53f9fbf9p-4L }, - { 0x9.9b19d045170086ap-4L, 0x8.41f3b9e1fe6130dp-4L, 0x8.41f3b9e1fe6130ep-4L }, - { -0xd.65fbae6f453f5a2p-4L, -0x7.0baa677949607eb8p-4L, -0x7.0baa677949607ebp-4L }, - { 0xc.7a9e15e82248878p-4L, 0xb.790e3f5b2936dc4p-4L, 0xb.790e3f5b2936dc5p-4L }, - { -0x3.f5ec8986cfd785dp-4L, -0x2.85cf707de281dc78p-4L, -0x2.85cf707de281dc74p-4L }, - { 0xa.530c1b060238f06p-4L, 0x9.064c5060f10810bp-4L, 0x9.064c5060f10810cp-4L }, - { -0x3.aa0cc319c013919p-4L, -0x2.59398f9b92fe953p-4L, -0x2.59398f9b92fe952cp-4L }, - { 0x3.c0a4bd100746357p-184L, 0x2.99de0a05056aaf74p-184L, 0x2.99de0a05056aaf78p-184L }, - { -0x6.fd442271482ca6dp-136L, -0x4.d8398bacdf9d28ap-136L, -0x4.d8398bacdf9d2898p-136L }, - { 0x6.67012d8b67014328p-4L, 0x5.1d41e56dafaf995p-4L, 0x5.1d41e56dafaf9958p-4L }, - { -0xa.6b6836f2ff72662p-4L, -0x5.cfe921fda171774p-4L, -0x5.cfe921fda1717738p-4L }, - { 0x9.620bcddbdd20a79p-4L, 0x8.064866d2e843838p-4L, 0x8.064866d2e843839p-4L }, - { -0x4.17376606afdde85p-4L, -0x2.99319a6951355f74p-4L, -0x2.99319a6951355f7p-4L }, - { 0xd.1dc39e358b023ap-4L, 0xc.3deef0997e22f56p-4L, 0xc.3deef0997e22f57p-4L }, - { -0xb.13430c035931444p-4L, -0x6.18f3b1ddbf4bbd98p-4L, -0x6.18f3b1ddbf4bbd9p-4L }, - { 0x3.606617a1673d0184p-4L, 0x2.8531caa9e41d88d8p-4L, 0x2.8531caa9e41d88dcp-4L }, - { -0x8.f017932d188a998p-4L, -0x5.23021a6f15e3204p-4L, -0x5.23021a6f15e32038p-4L }, - { 0x3.cf39982caefbf098p-4L, 0x2.def3e957a9d7b4e8p-4L, 0x2.def3e957a9d7b4ecp-4L }, - { -0x1.8dad3bd8dae62b26p-4L, -0x1.0a93f35dbc547e06p-4L, -0x1.0a93f35dbc547e04p-4L }, - { 0xf.d53ec036950502fp-4L, 0xf.c4f16bfb42b91ebp-4L, 0xf.c4f16bfb42b91ecp-4L }, - { -0xa.9cb0f8ebab4d7f8p-4L, -0x5.e59271c5142a2828p-4L, -0x5.e59271c5142a282p-4L }, - { 0x4.9ff6d398cf5c723p-4L, 0x3.8ca6a81f115945c8p-4L, 0x3.8ca6a81f115945ccp-4L }, - { -0x3.c7ea3c3c2b39e2c8p-4L, -0x2.6ad7b91001b1a278p-4L, -0x2.6ad7b91001b1a274p-4L }, - { 0xf.7206b4c8d50f316p-4L, 0xf.3d872c603dec047p-4L, 0xf.3d872c603dec048p-4L }, - { -0x7.5f74c3dd6c9936dp-4L, -0x4.5fecbd230b7b225p-4L, -0x4.5fecbd230b7b2248p-4L }, - { 0x1.d1a5048e1cfadea8p-4L, 0x1.4fd148e51db81464p-4L, 0x1.4fd148e51db81466p-4L }, - { -0xe.8f9244700df6721p-4L, -0x7.7c3f71d67ca51a2p-4L, -0x7.7c3f71d67ca51a18p-4L }, - { 0x3.99c86ae38d72f47cp-4L, 0x2.b375b38730124248p-4L, 0x2.b375b3873012424cp-4L }, - { -0x5.e2a8926a1f2a69f8p-4L, -0x3.99d49b6de5eb2bfp-4L, -0x3.99d49b6de5eb2becp-4L }, - { 0x2.58e048821c0475f4p-64L, 0x1.a07ede4412af4bbap-64L, 0x1.a07ede4412af4bbcp-64L }, - { -0x1.8989c2560de848e8p-124L, -0x1.10c7a38e60d87138p-124L, -0x1.10c7a38e60d87136p-124L }, - { 0x7.bc19ff559d9831b8p-4L, 0x6.5e7110fac4089518p-4L, 0x6.5e7110fac408952p-4L }, - { -0x6.c87c79c7f39458b8p-4L, -0x4.12e9a15e9bfdadb8p-4L, -0x4.12e9a15e9bfdadbp-4L }, - { 0x2.f5c34056d7c105dp-4L, 0x2.30678a0e37a17cep-4L, 0x2.30678a0e37a17ce4p-4L }, - { -0xd.4a8d8fca0cbe02bp-4L, -0x7.01000b10ed4e999p-4L, -0x7.01000b10ed4e9988p-4L }, - { 0x6.f866735c25236f98p-4L, 0x5.a3e6c10f6f1511fp-4L, 0x5.a3e6c10f6f1511f8p-4L }, - { -0xc.91587f5ff35915fp-4L, -0x6.b7ad5204ea051758p-4L, -0x6.b7ad5204ea05175p-4L }, - { 0x5.8acab0d65d615ap-4L, 0x4.5788c486bedea82p-4L, 0x4.5788c486bedea828p-4L }, - { -0xa.a22cceb5d16a7b9p-4L, -0x5.e7f89a5c228804ap-4L, -0x5.e7f89a5c22880498p-4L }, - { 0x7.9bb3d37308387268p-4L, 0x6.3f21841dccbd4848p-4L, 0x6.3f21841dccbd485p-4L }, - { -0xc.186ea423cfbc56dp-4L, -0x6.868d7eab6a729728p-4L, -0x6.868d7eab6a72972p-4L }, - { 0x2.797cf0eb89b43758p-4L, 0x1.cf80358fed6434cap-4L, 0x1.cf80358fed6434ccp-4L }, - { -0x1.5803a5d39e417564p-4L, -0xe.7a4f6be0f29e7b7p-8L, -0xe.7a4f6be0f29e7b6p-8L }, - { 0xc.a52f12f15058ap-8L, 0x8.eab3287521cf0c3p-8L, 0x8.eab3287521cf0c4p-8L }, - { -0x7.c0b1a87701c336f8p-4L, -0x4.907ee683856ce948p-4L, -0x4.907ee683856ce94p-4L }, - { 0x7.810b603203760db8p-4L, 0x6.257f312ef0f8e4cp-4L, 0x6.257f312ef0f8e4c8p-4L }, - { -0x3.74e32a2c3287777cp-4L, -0x2.39a477aba5f3e36cp-4L, -0x2.39a477aba5f3e368p-4L }, - { 0x7.ce4d4cf62f3cae4p-4L, 0x6.701b2af84891b008p-4L, 0x6.701b2af84891b01p-4L }, - { -0xc.d26229e318f0c64p-4L, -0x6.d1b0028af7ad99e8p-4L, -0x6.d1b0028af7ad99ep-4L }, - { 0x8.457740622adf15fp-4L, 0x6.e51d70eb7475fd68p-4L, 0x6.e51d70eb7475fd7p-4L }, - { -0x7.492c117c47e7f31p-4L, -0x4.54ae45d535c0da2p-4L, -0x4.54ae45d535c0da18p-4L }, - { 0x1.7627671657573188p-68L, 0x1.0357feda17430d52p-68L, 0x1.0357feda17430d54p-68L }, - { -0x1.80b4a26e54c41986p-136L, -0x1.0aa858c341e9388ep-136L, -0x1.0aa858c341e9388cp-136L }, - { 0xf.52d7c0f49c1b5a4p-4L, 0xf.136f9f9fa392aa3p-4L, 0xf.136f9f9fa392aa4p-4L }, - { -0xd.90fb86e4d60004ep-4L, -0x7.1c4914f985d3d1c8p-4L, -0x7.1c4914f985d3d1cp-4L }, - { 0x1.5c0865fc4e06a84ep-4L, 0xf.87bc506c0360beap-8L, 0xf.87bc506c0360bebp-8L }, - { -0xa.2dfc5d1f96be4bcp-4L, -0x5.b4a92468e23a59ep-4L, -0x5.b4a92468e23a59d8p-4L }, - { 0xf.d25ff3331838e0ap-4L, 0xf.c0fe5c5501df211p-4L, 0xf.c0fe5c5501df212p-4L }, - { -0xe.e893761d9d926b2p-4L, -0x7.9cd539ff83893758p-4L, -0x7.9cd539ff8389375p-4L }, - { 0x5.03f2d9b66abed898p-4L, 0x3.e20cb7d716acf19cp-4L, 0x3.e20cb7d716acf1ap-4L }, - { -0xd.e1d2b8730f8408fp-4L, -0x7.3b34b6801908a2d8p-4L, -0x7.3b34b6801908a2dp-4L }, - { 0x3.8052f809aaac9b64p-4L, 0x2.9ee0e2805679d1e8p-4L, 0x2.9ee0e2805679d1ecp-4L }, - { -0xf.ad374726f5b37c2p-4L, -0x7.e31b793e91a5aa08p-4L, -0x7.e31b793e91a5aap-4L }, - { 0x3.48836233e960d588p-4L, 0x2.7211ad27a4176778p-4L, 0x2.7211ad27a417677cp-4L }, - { -0x8.af10e3af7480717p-4L, -0x5.043cabb9514315b8p-4L, -0x5.043cabb9514315bp-4L }, - { 0x2.684f23a780f8d16cp-4L, 0x1.c243ddcaf1137a7ap-4L, 0x1.c243ddcaf1137a7cp-4L }, - { -0x2.956954f33db8ba84p-4L, -0x1.b1bac7e767d6e47p-4L, -0x1.b1bac7e767d6e46ep-4L }, - { 0xe.05c36356f1cc00bp-4L, 0xd.5f6d58c69cd39e4p-4L, 0xd.5f6d58c69cd39e5p-4L }, - { -0x9.851c7f17e3779ebp-4L, -0x5.68430d8fcaf782c8p-4L, -0x5.68430d8fcaf782cp-4L }, - { 0x8.98fecd06210c28ep-8L, 0x6.07827af96e4199d8p-8L, 0x6.07827af96e4199ep-8L }, - { -0xa.944a9ff08e89db6p-4L, -0x5.e1e49752fc61a1f8p-4L, -0x5.e1e49752fc61a1fp-4L }, - { 0xf.069ae41b6f97acbp-4L, 0xe.ad7594fe8b4b59ap-4L, 0xe.ad7594fe8b4b59bp-4L }, - { -0x2.849c2bec428d3088p-4L, -0x1.a74d58f4fabdbfecp-4L, -0x1.a74d58f4fabdbfeap-4L }, - { 0x7.77014ff302ca7f18p-132L, 0x5.2c9b99c7adcd1158p-132L, 0x5.2c9b99c7adcd116p-132L }, - { -0xe.aa11ca5025d7161p-8L, -0x9.f724056ca1ff3ffp-8L, -0x9.f724056ca1ff3fep-8L }, - { 0xe.30a7bdb7d22b3c9p-4L, 0xd.96346f655e1888ep-4L, 0xd.96346f655e1888fp-4L }, - { -0xd.1710819efb6a90bp-4L, -0x6.ecd8990f76e583d8p-4L, -0x6.ecd8990f76e583dp-4L }, - { 0xc.289ab032c02ec2bp-8L, 0x8.91661f345b3b24ap-8L, 0x8.91661f345b3b24bp-8L }, - { -0x9.3c743e33f50fbe3p-8L, -0x6.52977132d3793028p-8L, -0x6.52977132d379302p-8L }, - { 0xc.b983cae10f7203p-4L, 0xb.c45064517003de9p-4L, 0xb.c45064517003deap-4L }, - { -0xb.7422dd3d2b45dc5p-4L, -0x6.422bf2df07d21bc8p-4L, -0x6.422bf2df07d21bcp-4L }, - { 0xa.fbaa8d616ab8d1dp-4L, 0x9.bfbb7af27216907p-4L, 0x9.bfbb7af27216908p-4L }, - { -0xe.926ef7c0fa60c33p-4L, -0x7.7d4da667730b916p-4L, -0x7.7d4da667730b9158p-4L }, - { 0xf.80c7c99d2c6404cp-4L, 0xf.518567961cfcee4p-4L, 0xf.518567961cfcee5p-4L }, - { -0x3.9556369534624858p-8L, -0x2.78c655fc919c92b8p-8L, -0x2.78c655fc919c92b4p-8L }, - { 0xe.80d9a3a08faf173p-4L, 0xd.fdb1f369b283091p-4L, 0xd.fdb1f369b283092p-4L }, - { -0x8.400e8efd60a398p-4L, -0x4.ceeacdda92f4d4f8p-4L, -0x4.ceeacdda92f4d4fp-4L }, - { 0x1.e30b1be4461dcf88p-4L, 0x1.5ce2ab3afe2480fcp-4L, 0x1.5ce2ab3afe2480fep-4L }, - { -0xc.2454aa891f5dba1p-4L, -0x6.8b6e7833d8a9115p-4L, -0x6.8b6e7833d8a91148p-4L }, - { 0x2.c925c1f452e23ebp-4L, 0x2.0d617fc9f8513ef4p-4L, 0x2.0d617fc9f8513ef8p-4L }, - { -0x3.a0caae204aa84214p-4L, -0x2.53bec8ebfa7cc494p-4L, -0x2.53bec8ebfa7cc49p-4L }, - { 0x6.db2d4dd8afa84408p-4L, 0x5.88928d8e125932e8p-4L, 0x5.88928d8e125932fp-4L }, - { -0x8.7fd39596a804d49p-4L, -0x4.edab5a4106ecd58p-4L, -0x4.edab5a4106ecd578p-4L }, - { 0xf.c5af0e065f2eb13p-4L, 0xf.af8ddf3950b244p-4L, 0xf.af8ddf3950b2441p-4L }, - { -0x5.9541e8c20a3e7eep-4L, -0x3.6ffb2642f78d6758p-4L, -0x3.6ffb2642f78d6754p-4L }, - { 0x2.b8baba6727f5d1ep-24L, 0x1.e2efa10b181a1d0cp-24L, 0x1.e2efa10b181a1d0ep-24L }, - { -0x8.db8aa5ad53966d6p-64L, -0x6.23bd7497280c936p-64L, -0x6.23bd7497280c9358p-64L }, - { 0xc.2a19196663e14b4p-4L, 0xb.19dfa4b37a6fc82p-4L, 0xb.19dfa4b37a6fc83p-4L }, - { -0x5.0fb02f7662c3e03p-4L, -0x3.2675eb61e2d86868p-4L, -0x3.2675eb61e2d86864p-4L }, - { 0x6.883e7a1d34914268p-4L, 0x5.3bbf577ebbb3a6e8p-4L, 0x5.3bbf577ebbb3a6fp-4L }, - { -0xb.88a85700deb5549p-4L, -0x6.4ad12b9dbb86aa58p-4L, -0x6.4ad12b9dbb86aa5p-4L }, - { 0xf.2b2a3a311948993p-4L, 0xe.de32bdbd5328a8bp-4L, 0xe.de32bdbd5328a8cp-4L }, - { -0x3.06fe2a10fe55267cp-4L, -0x1.f7730b164f7095cap-4L, -0x1.f7730b164f7095c8p-4L }, - { 0xd.de264368cd7459ap-4L, 0xd.2d302551f4723e2p-4L, 0xd.2d302551f4723e3p-4L }, - { -0x5.567777c9aa2124c8p-4L, -0x3.4da047a5e9ef6524p-4L, -0x3.4da047a5e9ef652p-4L }, - { 0x1.935a9217a5a3024p-4L, 0x1.2158a4e7876f331ep-4L, 0x1.2158a4e7876f332p-4L }, - { -0x7.3ccc7fe1d42ad228p-4L, -0x4.4e6b4b167987ff4p-4L, -0x4.4e6b4b167987ff38p-4L }, - { 0x4.bbff6d1fef17b4c8p-4L, 0x3.a4730f28cbe2fbf4p-4L, 0x3.a4730f28cbe2fbf8p-4L }, - { -0x2.826940b5855fb4cp-4L, -0x1.a5ef6bae7291935p-4L, -0x1.a5ef6bae7291934ep-4L }, - { 0x5.265fe49d84076a68p-4L, 0x3.ffca2018e001a9f4p-4L, 0x3.ffca2018e001a9f8p-4L }, - { -0xc.103986b2d38539dp-4L, -0x6.832e7fadd55aecp-4L, -0x6.832e7fadd55aebf8p-4L }, - { 0x1.70101c108d2f0d0ep-4L, 0x1.073c0b1e50c5d204p-4L, 0x1.073c0b1e50c5d206p-4L }, - { -0x2.66bb0943c921a184p-4L, -0x1.94af43fe62d2cf1ap-4L, -0x1.94af43fe62d2cf18p-4L }, - { 0x7.5a723c24f0c64ebp-4L, 0x6.0095e4fad124e338p-4L, 0x6.0095e4fad124e34p-4L }, - { -0x3.c761bdd9cf2def2cp-4L, -0x2.6a876738e18b6208p-4L, -0x2.6a876738e18b6204p-4L }, - { 0x3.e7acf294cc0ca23cp-8L, 0x2.b89933565f7ae4f4p-8L, 0x2.b89933565f7ae4f8p-8L }, - { -0x7.3c061c9452915b98p-4L, -0x4.4e06c9112a70ca8p-4L, -0x4.4e06c9112a70ca78p-4L }, - { 0x3.0efe779ab69c208p-72L, 0x2.1ebae7521123e438p-72L, 0x2.1ebae7521123e43cp-72L }, - { -0x6.90517ba54103e7cp-172L, -0x4.8cb53818436922b8p-172L, -0x4.8cb53818436922bp-172L }, - { 0xb.dde4e379662aeeap-4L, 0xa.c0facbdff63e577p-4L, 0xa.c0facbdff63e578p-4L }, - { -0xb.0226291c9bc5964p-4L, -0x6.1199984540184bp-4L, -0x6.1199984540184af8p-4L }, - { 0xd.bf9a0da9faa3504p-4L, 0xd.06ad1755cc71cafp-4L, 0xd.06ad1755cc71cbp-4L }, - { -0x5.c1892b0fafe1dc68p-4L, -0x3.87fd1b244474f46p-4L, -0x3.87fd1b244474f45cp-4L }, - { 0x1.44812a3159648466p-4L, 0xe.7384fa316de3657p-8L, 0xe.7384fa316de3658p-8L }, - { -0x3.675c755eb8dbe27cp-4L, -0x2.318fbbc51015422p-4L, -0x2.318fbbc51015421cp-4L }, - { 0x1.e8e8f49835eaacb8p-4L, 0x1.614ce65fa1a17274p-4L, 0x1.614ce65fa1a17276p-4L }, - { -0x9.eac5efdf2c187bdp-4L, -0x5.9683d9aacedb09d8p-4L, -0x5.9683d9aacedb09dp-4L }, - { 0xf.8a9cd502481f327p-4L, 0xf.5edf4b01d85e97fp-4L, 0xf.5edf4b01d85e98p-4L }, - { -0x2.9371a4cdcbd8ac4p-4L, -0x1.b0829193db9b2a82p-4L, -0x1.b0829193db9b2a8p-4L }, - { 0xf.ec9e23f6d0a3bd2p-4L, 0xf.e52cabad2944b2dp-4L, 0xf.e52cabad2944b2ep-4L }, - { -0x4.bfabe9c4786421c8p-4L, -0x2.f99d50346680f5e4p-4L, -0x2.f99d50346680f5ep-4L }, - { 0x6.028525d3aafe4428p-4L, 0x4.c21ee15b144d29a8p-4L, 0x4.c21ee15b144d29bp-4L }, - { -0x4.c2d0568402546a5p-8L, -0x3.47653cfe61fb05p-8L, -0x3.47653cfe61fb04fcp-8L }, - { 0xc.976222dd345048p-4L, 0xb.9b60191b6b95aecp-4L, 0xb.9b60191b6b95aedp-4L }, - { -0xd.6563e961e96fd5dp-4L, -0x7.0b6f86cbdfafbe78p-4L, -0x7.0b6f86cbdfafbe7p-4L }, - { 0x9.e03ff635ae5b0afp-4L, 0x8.8b0bdb10fd8a85fp-4L, 0x8.8b0bdb10fd8a86p-4L }, - { -0xa.42b9f1752ebee14p-4L, -0x5.bde4e29a894df518p-4L, -0x5.bde4e29a894df51p-4L }, - { 0x6.4ef2060125bf954p-4L, 0x5.074b877b025a5c38p-4L, 0x5.074b877b025a5c4p-4L }, - { -0xc.a4d9e356caf3a4ap-4L, -0x6.bf8205df1ee0d508p-4L, -0x6.bf8205df1ee0d5p-4L }, - { 0x7.e842fb7dd3d50cap-196L, 0x5.7b1c7b3b95bed698p-196L, 0x5.7b1c7b3b95bed6ap-196L }, - { -0x1.31f41258f7c01eccp-60L, -0xd.4121c04c9ce13acp-64L, -0xd.4121c04c9ce13abp-64L }, - { 0x2.29f54bce824a24cp-8L, 0x1.811a02ec67bf37aep-8L, 0x1.811a02ec67bf37bp-8L }, - { -0xa.b8f81b679b49916p-4L, -0x5.f1eb5dee53695e5p-4L, -0x5.f1eb5dee53695e48p-4L }, - { 0x2.dfa40c215498cf14p-4L, 0x2.1f01613fffbe7cfcp-4L, 0x2.1f01613fffbe7dp-4L }, - { -0x2.ec02031137509e54p-4L, -0x1.e7019f7577e0055ap-4L, -0x1.e7019f7577e00558p-4L }, - { 0xc.95b28af67c0d0fdp-4L, 0xb.995bfeb5a18fb19p-4L, 0xb.995bfeb5a18fb1ap-4L }, - { -0x3.8b937ee4a5ad9044p-4L, -0x2.4727f0551eb47668p-4L, -0x2.4727f0551eb47664p-4L }, - { 0xc.b61f96c1b9a40fep-8L, 0x8.f6d9fa1cd76287dp-8L, 0x8.f6d9fa1cd76287ep-8L }, - { -0x5.32ac5f2f72c534e8p-4L, -0x3.39e0dcc0490bcf08p-4L, -0x3.39e0dcc0490bcf04p-4L }, - { 0x3.71a836d1385ea83cp-4L, 0x2.930fc44d7c9f0878p-4L, 0x2.930fc44d7c9f087cp-4L }, - { -0x2.98de885b63ec9fap-4L, -0x1.b3df390ab96ff674p-4L, -0x1.b3df390ab96ff672p-4L }, - { 0x2.ec64d50f08792a24p-4L, 0x2.290720411b492388p-4L, 0x2.290720411b49238cp-4L }, - { -0x7.4a3ef749c24694d8p-4L, -0x4.55393aafd5f18ddp-4L, -0x4.55393aafd5f18dc8p-4L }, - { 0x1.c73a886f525db7c4p-4L, 0x1.48033f1818ec4274p-4L, 0x1.48033f1818ec4276p-4L }, - { -0x7.e597e9edb98f8dd8p-4L, -0x4.a2b8122945a3a86p-4L, -0x4.a2b8122945a3a858p-4L }, - { 0x5.b2db0149e01e772p-4L, 0x4.7af5d27da276247p-4L, 0x4.7af5d27da2762478p-4L }, - { -0xa.4e00c5865119715p-4L, -0x5.c2e6944e696561dp-4L, -0x5.c2e6944e696561c8p-4L }, - { 0x3.2d5ce470bbbfc05p-4L, 0x2.5c6c520e75d5dcfp-4L, 0x2.5c6c520e75d5dcf4p-4L }, - { -0x6.fef503b2cde63e88p-4L, -0x4.2eed1c50abe4d0fp-4L, -0x4.2eed1c50abe4d0e8p-4L }, - { 0x9.d7135271cf1adc5p-8L, 0x6.e98f0ad0c8f784bp-8L, 0x6.e98f0ad0c8f784b8p-8L }, - { -0x1.37a6e3f9da2ebc3ap-4L, -0xd.26c4f046ca71bc4p-8L, -0xd.26c4f046ca71bc3p-8L }, - { 0xe.f91909cb851832p-16L, 0xa.611c7fdf8ec95cap-16L, 0xa.611c7fdf8ec95cbp-16L }, - { -0x1.8aec185a037005eap-44L, -0x1.11bd3ef298133bf6p-44L, -0x1.11bd3ef298133bf4p-44L }, - { 0x4.58042455b6631c78p-4L, 0x3.5016317376e61d88p-4L, 0x3.5016317376e61d8cp-4L }, - { -0xf.a5425993c2d22edp-4L, -0x7.e04f162edd1444c8p-4L, -0x7.e04f162edd1444cp-4L }, - { 0xc.cc707747b5d9891p-4L, 0xb.db1d6d0a67ba46dp-4L, 0xb.db1d6d0a67ba46ep-4L }, - { -0x5.6352b9b11a14c48p-4L, -0x3.54b0a77bead101c4p-4L, -0x3.54b0a77bead101cp-4L }, - { 0xb.ddfe2e36f24ba09p-4L, 0xa.c1181c4c96d3b16p-4L, 0xa.c1181c4c96d3b17p-4L }, - { -0xf.ff0d58e82429fafp-4L, -0x7.ffabe56fa53e346p-4L, -0x7.ffabe56fa53e3458p-4L }, - { 0x9.bd53e4167e85b42p-4L, 0x8.6606596f18f0c25p-4L, 0x8.6606596f18f0c26p-4L }, - { -0x5.4c28c9b0b345941p-4L, -0x3.47f39e55e7145a5p-4L, -0x3.47f39e55e7145a4cp-4L }, - { 0x8.fef78aad41a1338p-4L, 0x7.a005c2fb7b575668p-4L, 0x7.a005c2fb7b57567p-4L }, - { -0xf.25b2822b10d9f65p-4L, -0x7.b2ed5c3922a4e83p-4L, -0x7.b2ed5c3922a4e828p-4L }, - { 0x5.cd10c03bcaf10088p-8L, 0x4.0d7eda5d78333cc8p-8L, 0x4.0d7eda5d78333cdp-8L }, - { -0xa.a821812c5f53b52p-4L, -0x5.ea92fddd766193d8p-4L, -0x5.ea92fddd766193dp-4L }, - { 0x5.94e05ec04235ac68p-4L, 0x4.606dcea9678b422p-4L, 0x4.606dcea9678b4228p-4L }, - { -0x5.04ba966a5474e0e8p-4L, -0x3.205aab0b1a291c5cp-4L, -0x3.205aab0b1a291c58p-4L }, - { 0xd.167af1356c9c025p-4L, 0xc.3506efb6e7f748dp-4L, 0xc.3506efb6e7f748ep-4L }, - { -0xf.d0cd204dbb8b533p-4L, -0x7.ef93a0736368116p-4L, -0x7.ef93a07363681158p-4L }, - { 0xa.c0e5742f317f8a3p-4L, 0x9.7e80068401fa255p-4L, 0x9.7e80068401fa256p-4L }, - { -0xe.2242314d427e9c1p-4L, -0x7.538ce8c2b95acc28p-4L, -0x7.538ce8c2b95acc2p-4L }, - { 0x2.37749e13337ef694p-4L, 0x1.9cd5b81ee0f49f52p-4L, 0x1.9cd5b81ee0f49f54p-4L }, - { -0x4.8513915f54085e2p-4L, -0x2.d86313394f7dfa98p-4L, -0x2.d86313394f7dfa94p-4L }, - { 0x7.11d091eb6c5e7f8p-32L, 0x4.e677cd427aff876p-32L, 0x4.e677cd427aff8768p-32L }, - { -0x2.92d0f5e17e14f8ep-176L, -0x1.c8a818bcf03dad22p-176L, -0x1.c8a818bcf03dad2p-176L }, - { 0x9.19d2bf8e626ce94p-4L, 0x7.bb9267aaaf8d16f8p-4L, 0x7.bb9267aaaf8d17p-4L }, - { -0x5.78fee31b1243e6ep-4L, -0x3.6090300d6de230a8p-4L, -0x3.6090300d6de230a4p-4L }, - { 0xe.920450e2df4f23ep-4L, 0xe.14081596bb730e3p-4L, 0xe.14081596bb730e4p-4L }, - { -0x7.8a913f4c29492cdp-4L, -0x4.758ec9da15257a08p-4L, -0x4.758ec9da15257ap-4L }, - { 0xd.f18c68c5e57c1fep-4L, 0xd.45bf8cfdf37d1c1p-4L, 0xd.45bf8cfdf37d1c2p-4L }, - { -0xc.97ed4020a652183p-4L, -0x6.ba5270a397bd198p-4L, -0x6.ba5270a397bd1978p-4L }, - { 0x6.b2da8740f690432p-4L, 0x5.63158e0eca286c4p-4L, 0x5.63158e0eca286c48p-4L }, - { -0x8.d86e55e3f0a94b1p-4L, -0x5.17d9c3b44828322p-4L, -0x5.17d9c3b448283218p-4L }, - { 0x5.0308adabc4a020fp-4L, 0x3.e14306a78e1170ccp-4L, 0x3.e14306a78e1170dp-4L }, - { -0x2.a7d9b961e2c3089p-4L, -0x1.bd23ae2c81af213p-4L, -0x1.bd23ae2c81af212ep-4L }, - { 0xd.227d8e4d09d7251p-4L, 0xc.43b7e073dd24255p-4L, 0xc.43b7e073dd24256p-4L }, - { -0x7.d5608278690935ap-4L, -0x4.9ab96d634d10f6a8p-4L, -0x4.9ab96d634d10f6ap-4L }, - { 0xe.81b27c03c76f499p-4L, 0xd.fecbb5a87bddaadp-4L, 0xd.fecbb5a87bddaaep-4L }, - { -0x2.b154c8162bc04cb4p-4L, -0x1.c2fdf56982dfaa86p-4L, -0x1.c2fdf56982dfaa84p-4L }, - { 0x4.35ecdac82f2a93c8p-4L, 0x3.33a5663cd3ec757cp-4L, 0x3.33a5663cd3ec758p-4L }, - { -0x5.771325ed71c201dp-4L, -0x3.5f833dab5799d678p-4L, -0x3.5f833dab5799d674p-4L }, - { 0xb.d5c2b3ad8490192p-4L, 0xa.b78f2869f7f0d2fp-4L, 0xa.b78f2869f7f0d3p-4L }, - { -0x5.121392f3a25f68p-4L, -0x3.27ca31d087184188p-4L, -0x3.27ca31d087184184p-4L }, - { 0x7.b9734cb7e88bd598p-4L, 0x6.5bdf83f80e502428p-4L, 0x6.5bdf83f80e50243p-4L }, - { -0x1.778ccedfa82f4736p-4L, -0xf.c36523958ccb66dp-8L, -0xf.c36523958ccb66cp-8L }, - { 0x5.9e61f2660d92e2bp-24L, 0x3.e502ce773052c2ep-24L, 0x3.e502ce773052c2e4p-24L }, - { -0xc.ed5cdd95e040dd5p-124L, -0x8.f5e01e66418fdc9p-124L, -0x8.f5e01e66418fdc8p-124L }, - { 0xe.22ec92ad54501adp-4L, 0xd.84a01b636eef0b3p-4L, 0xd.84a01b636eef0b4p-4L }, - { -0x7.ec2bfe55bde275dp-4L, -0x4.a5f4b909907e0218p-4L, -0x4.a5f4b909907e021p-4L }, - { 0xf.d304d6628c01f2ap-4L, 0xf.c1e1328eafdd3bfp-4L, 0xf.c1e1328eafdd3cp-4L }, - { -0x9.352c83f42a1922fp-4L, -0x5.43546e87e016ee88p-4L, -0x5.43546e87e016ee8p-4L }, - { 0x7.4cdb36f2473c8acp-4L, 0x5.f3a5959c53f3ceb8p-4L, 0x5.f3a5959c53f3cecp-4L }, - { -0x1.70792a73178fa0fap-4L, -0xf.79b33e5d77df4c1p-8L, -0xf.79b33e5d77df4cp-8L }, - { 0x5.1ce62b8e10774afp-4L, 0x3.f7962ac86af2f5ecp-4L, 0x3.f7962ac86af2f5fp-4L }, - { -0x7.fa8931ceaf326ac8p-4L, -0x4.ad02e3351c74545p-4L, -0x4.ad02e3351c745448p-4L }, - { 0xb.369caaaa169ce0fp-4L, 0xa.01d090312957af1p-4L, 0xa.01d090312957af2p-4L }, - { -0xa.954d79680ea5909p-4L, -0x5.e25609c7a753185p-4L, -0x5.e25609c7a7531848p-4L }, - { 0xb.432563e5c37e78fp-4L, 0xa.0ff3939e94e53c8p-4L, 0xa.0ff3939e94e53c9p-4L }, - { -0xa.950b0bb7d84c5b3p-4L, -0x5.e238ed18b7fab0bp-4L, -0x5.e238ed18b7fab0a8p-4L }, - { 0x4.3e136fbe7e156658p-4L, 0x3.3a6e53129453d0d4p-4L, 0x3.3a6e53129453d0d8p-4L }, - { -0xb.9930789b19cf8a8p-4L, -0x6.51c2880aa5aa9ff8p-4L, -0x6.51c2880aa5aa9ffp-4L }, - { 0x8.1697784edf6fe07p-8L, 0x5.ab0e426210147018p-8L, 0x5.ab0e42621014702p-8L }, - { -0x2.e9849ddc62c0d374p-4L, -0x1.e57c4324b108422ep-4L, -0x1.e57c4324b108422cp-4L }, - { 0xc.d570e244c0e60bep-4L, 0xb.e5fc70032574c78p-4L, 0xb.e5fc70032574c79p-4L }, - { -0xf.15d04c531718d34p-4L, -0x7.ad351e2ce95c1f88p-4L, -0x7.ad351e2ce95c1f8p-4L }, - { 0x1.e1200b8406eda8fep-4L, 0x1.5b715b4dfb18883p-4L, 0x1.5b715b4dfb188832p-4L }, - { -0x7.995991a529314d5p-4L, -0x4.7cf0755dd5eca728p-4L, -0x4.7cf0755dd5eca72p-4L }, - { 0x9.2cb86254ecdfd09p-192L, 0x6.5c0241febd46c9cp-192L, 0x6.5c0241febd46c9c8p-192L }, - { -0x2.4cc15f58d07c3b1cp-140L, -0x1.981818282e5dbca4p-140L, -0x1.981818282e5dbca2p-140L }, - { 0x3.9173123187f70484p-4L, 0x2.acb691682f6030d4p-4L, 0x2.acb691682f6030d8p-4L }, - { -0x4.e07d3709dbe3fep-4L, -0x3.0c14b7174878c9ecp-4L, -0x3.0c14b7174878c9e8p-4L }, - { 0x5.653d42dac0a5219p-4L, 0x4.368bd2c07053e5ep-4L, 0x4.368bd2c07053e5e8p-4L }, - { -0x9.5f1aff673a041bcp-4L, -0x5.56c3d8c108a0611p-4L, -0x5.56c3d8c108a06108p-4L }, - { 0x8.bcd403a004e1a23p-4L, 0x7.5cb550c524697b8p-4L, 0x7.5cb550c524697b88p-4L }, - { -0x8.1c9d05645c7987cp-4L, -0x4.bdae53d810a91ac8p-4L, -0x4.bdae53d810a91acp-4L }, - { 0xd.13a5ae9285d253dp-4L, 0xc.3190e4f8d4d5582p-4L, 0xc.3190e4f8d4d5583p-4L }, - { -0x9.4cf62e7e77f656p-4L, -0x5.4e5f50857e68f51p-4L, -0x5.4e5f50857e68f508p-4L }, - { 0x2.84d9c1bc69548254p-4L, 0x1.d846c310aa00c054p-4L, 0x1.d846c310aa00c056p-4L }, - { -0x4.21ac0c75a3a7dbe8p-4L, -0x2.9f423cc607a168dcp-4L, -0x2.9f423cc607a168d8p-4L }, - { 0xd.b9bd68e165f831p-4L, 0xc.ff4f076046a69dp-4L, 0xc.ff4f076046a69d1p-4L }, - { -0x8.3fd61ad578cd929p-4L, -0x4.cecf6eabd87b7c9p-4L, -0x4.cecf6eabd87b7c88p-4L }, - { 0xf.30d46d764112444p-4L, 0xe.e5c6f47afffabf2p-4L, 0xe.e5c6f47afffabf3p-4L }, - { -0xb.cd4a73dc359d737p-4L, -0x6.6783a45e4e8dae2p-4L, -0x6.6783a45e4e8dae18p-4L }, - { 0x5.457d60a9148a985p-4L, 0x4.1ad19bfee71e48dp-4L, 0x4.1ad19bfee71e48d8p-4L }, - { -0x5.9e1738c1ccd8a9a8p-4L, -0x3.74c8e8a92c7f7b74p-4L, -0x3.74c8e8a92c7f7b7p-4L }, - { 0x1.497ab915f40b4518p-4L, 0xe.add4c95fb682b23p-8L, 0xe.add4c95fb682b24p-8L }, - { -0x4.8e012f7d7878b01p-4L, -0x2.dd78a1d7e408573cp-4L, -0x2.dd78a1d7e4085738p-4L }, - { 0x5.9d5fb6a6e532323p-4L, 0x4.67ef7a4d5b079348p-4L, 0x4.67ef7a4d5b07935p-4L }, - { -0x7.bc4dc1a54a48fdbp-4L, -0x4.8e51e755a24d00f8p-4L, -0x4.8e51e755a24d00fp-4L }, - { 0x3.fc5a846dfbec9adp-200L, 0x2.c3415566e5a54668p-200L, 0x2.c3415566e5a5466cp-200L }, - { -0x7.6980774d9eb5024p-128L, -0x5.233f7f59341a9e7p-128L, -0x5.233f7f59341a9e68p-128L }, - { 0xc.52f873b5b0d54efp-8L, 0x8.afc12e42adf7bacp-8L, 0x8.afc12e42adf7badp-8L }, - { -0x2.b8137644250c4bbcp-4L, -0x1.c7266a67c6352a0ap-4L, -0x1.c7266a67c6352a08p-4L }, - { 0x8.b13bd917a919d6p-4L, 0x7.50fc3760355aaba8p-4L, 0x7.50fc3760355aabbp-4L }, - { -0xd.a7e60f2da06694ep-4L, -0x7.2517f5997441288p-4L, -0x7.2517f59974412878p-4L }, - { 0x9.6d66afe84b35074p-4L, 0x8.121cbf603f1eb03p-4L, 0x8.121cbf603f1eb04p-4L }, - { -0x8.d45410dc1895ef4p-4L, -0x5.15e9564a5d57b1d8p-4L, -0x5.15e9564a5d57b1dp-4L }, - { 0x8.7112de739485f11p-4L, 0x7.108706705b67e1bp-4L, 0x7.108706705b67e1b8p-4L }, - { -0x5.28bf133fa6f14d3p-4L, -0x3.34615bbf1f08718cp-4L, -0x3.34615bbf1f087188p-4L }, - { 0x5.9ce42450cfaf8ee8p-4L, 0x4.67823dfabf51ea3p-4L, 0x4.67823dfabf51ea38p-4L }, - { -0x6.efb719daf136a1cp-4L, -0x4.271d11505413f6b8p-4L, -0x4.271d11505413f6bp-4L }, - { 0x9.ba0bd38df957e82p-8L, 0x6.d4e5a59f2ab3464p-8L, 0x6.d4e5a59f2ab34648p-8L }, - { -0x7.f37ea4723b67675p-4L, -0x4.a98e0f5848567a48p-4L, -0x4.a98e0f5848567a4p-4L }, - { 0x2.bf5897672b745798p-4L, 0x2.05b8d1dd696925cp-4L, 0x2.05b8d1dd696925c4p-4L }, - { -0x1.2b46b769cd53c99cp-4L, -0xc.a46ee1aa5cf6e29p-8L, -0xc.a46ee1aa5cf6e28p-8L }, - { 0x8.0d256afefef3c89p-4L, 0x6.ad850d0f71e9f0fp-4L, 0x6.ad850d0f71e9f0f8p-4L }, - { -0xa.e23fca6db43882fp-4L, -0x6.03d69b4a9fcb498p-4L, -0x6.03d69b4a9fcb4978p-4L }, - { 0x3.5d7f19c9107b35a4p-4L, 0x2.82ddd03061b78d4p-4L, 0x2.82ddd03061b78d44p-4L }, - { -0x4.0740585229be331p-4L, -0x2.8fe9890e66210b8p-4L, -0x2.8fe9890e66210b7cp-4L }, - { 0xb.2f2372351c33164p-8L, 0x7.deee40d7b054f0a8p-8L, 0x7.deee40d7b054f0bp-8L }, - { -0x1.e98b74b783fe8242p-4L, -0x1.45a6bc169044944ep-4L, -0x1.45a6bc169044944cp-4L }, - { 0x1.ef271536f1acac7cp-116L, 0x1.5736b36e46fd9e2p-116L, 0x1.5736b36e46fd9e22p-116L }, - { -0x2.f2b30898a501e344p-172L, -0x2.0b1e2354091a9a9p-172L, -0x2.0b1e2354091a9a8cp-172L }, - { 0xc.de09271a73942cap-4L, 0xb.f061a10e47f19afp-4L, 0xb.f061a10e47f19bp-4L }, - { -0xd.1fe6e25acc0107ap-4L, -0x6.f0515b52d3bc8b1p-4L, -0x6.f0515b52d3bc8b08p-4L }, - { 0x5.379d21e155802d5p-8L, 0x3.a458c1e822fc87b8p-8L, 0x3.a458c1e822fc87bcp-8L }, - { -0x7.f34a81711f9595fp-4L, -0x4.a974739e5e3c1ecp-4L, -0x4.a974739e5e3c1eb8p-4L }, - { 0x9.8f02fd2b4d10383p-4L, 0x8.3542c1ae328d562p-4L, 0x8.3542c1ae328d563p-4L }, - { -0x3.10d386b4ddaa9bccp-4L, -0x1.fd6c33e550a573ep-4L, -0x1.fd6c33e550a573dep-4L }, - { 0x8.a7f4a483fcced92p-4L, 0x7.479ee5100ad2768p-4L, 0x7.479ee5100ad27688p-4L }, - { -0x8.6ddd524df76f7bdp-4L, -0x4.e50a7bb2dd656468p-4L, -0x4.e50a7bb2dd65646p-4L }, - { 0xc.779757b60637763p-4L, 0xb.757468127d65f88p-4L, 0xb.757468127d65f89p-4L }, - { -0xe.777fe73bf0e9a48p-4L, -0x7.7359b3768a34b5c8p-4L, -0x7.7359b3768a34b5cp-4L }, - { 0x2.31b8036de80e551p-4L, 0x1.9875b4516816bbbep-4L, 0x1.9875b4516816bbcp-4L }, - { -0x9.0b16723fd236994p-4L, -0x5.2faf0a9074dea98p-4L, -0x5.2faf0a9074dea978p-4L }, - { 0x8.9a19522584fca8fp-4L, 0x7.39a98b528df1ef3p-4L, 0x7.39a98b528df1ef38p-4L }, - { -0xf.5402328fd9d6fdfp-4L, -0x7.c38432212a78edbp-4L, -0x7.c38432212a78eda8p-4L }, - { 0x3.39b72eedc5fb39acp-4L, 0x2.664255df780701c4p-4L, 0x2.664255df780701c8p-4L }, - { -0xc.d7d4b25d5ee54a4p-4L, -0x6.d3da67d23282e35p-4L, -0x6.d3da67d23282e348p-4L }, - { 0xf.002b8779c597ceep-4L, 0xe.a4e96c0af56d93ap-4L, 0xe.a4e96c0af56d93bp-4L }, - { -0x7.903eb3c7555e4358p-4L, -0x4.78651e55fe9e325p-4L, -0x4.78651e55fe9e3248p-4L }, - { 0x2.90b7822bc63776fcp-4L, 0x1.e17582d5a09ed40ap-4L, 0x1.e17582d5a09ed40cp-4L }, - { -0xb.887e64736056822p-4L, -0x6.4abf8763ec5ac7ep-4L, -0x6.4abf8763ec5ac7d8p-4L }, - { 0x1.4b3a350eb68541aep-20L, 0xe.596e40ce64dcf5ap-24L, 0xe.596e40ce64dcf5bp-24L }, - { -0x1.aef913a565a8bc1ap-128L, -0x1.2aba49d9af3d613p-128L, -0x1.2aba49d9af3d612ep-128L }, - { 0xc.8b02c285d275bd6p-4L, 0xb.8c97f1c3166348p-4L, 0xb.8c97f1c31663481p-4L }, - { -0x7.2ea947c351044f48p-4L, -0x4.473fa3759df5825p-4L, -0x4.473fa3759df58248p-4L }, - { 0xc.4830d91b64528bdp-4L, 0xb.3d4b68c0a1c1452p-4L, 0xb.3d4b68c0a1c1453p-4L }, - { -0xa.faff5d48675db64p-4L, -0x6.0e8570512dea4ae8p-4L, -0x6.0e8570512dea4aep-4L }, - { 0x1.456f46c72593c416p-4L, 0xe.7e6b02981c8b075p-8L, 0xe.7e6b02981c8b076p-8L }, - { -0x2.cdc53dd42a6cdf4cp-4L, -0x1.d47df5d7bd63c49ep-4L, -0x1.d47df5d7bd63c49cp-4L }, - { 0xd.de830895fc14d25p-4L, 0xd.2da568a29ea15dp-4L, 0xd.2da568a29ea15d1p-4L }, - { -0x1.d696938384c107e8p-4L, -0x1.39897019921dfe5ap-4L, -0x1.39897019921dfe58p-4L }, - { 0x3.5cde202fff810fdp-4L, 0x2.825cba775f96e8d4p-4L, 0x2.825cba775f96e8d8p-4L }, - { -0xb.0173bf64b3af081p-4L, -0x6.114cd4839031f808p-4L, -0x6.114cd4839031f8p-4L }, - { 0x9.ae157e1a5d07d3dp-4L, 0x8.55eee27b4bf2689p-4L, 0x8.55eee27b4bf268ap-4L }, - { -0x4.bded6e2f0ae69668p-4L, -0x2.f8a157b29a4320f8p-4L, -0x2.f8a157b29a4320f4p-4L }, - { 0xb.7b9077a770021aep-4L, 0xa.4ff4d2970ce8214p-4L, 0xa.4ff4d2970ce8215p-4L }, - { -0xe.794bdddad00436cp-4L, -0x7.740408ba771c01d8p-4L, -0x7.740408ba771c01dp-4L }, - { 0x8.bcfd1861de45b01p-4L, 0x7.5cdee4cb7bee481p-4L, 0x7.5cdee4cb7bee4818p-4L }, - { -0xa.ab4ea1951712b09p-4L, -0x5.ebf61acd701b7f68p-4L, -0x5.ebf61acd701b7f6p-4L }, - { 0x6.f81960839d640cdp-4L, 0x5.a39e8005baae39bp-4L, 0x5.a39e8005baae39b8p-4L }, - { -0x7.693a270061cf9de8p-4L, -0x4.64d777196e594488p-4L, -0x4.64d777196e59448p-4L }, - { 0xe.7b0648fc94495aap-4L, 0xd.f6213f610dcf21ep-4L, 0xd.f6213f610dcf21fp-4L }, - { -0xa.916b419fbe9fc1p-4L, -0x5.e0a2312a38c0e318p-4L, -0x5.e0a2312a38c0e31p-4L }, - { 0x1.89bd813bf1f6a1c2p-92L, 0x1.10eb819b2e242b1ep-92L, 0x1.10eb819b2e242b2p-92L }, - { -0x5.9293af393bd5fbfp-184L, -0x3.dcd3e77adc468a94p-184L, -0x3.dcd3e77adc468a9p-184L }, - { 0xd.3ea27eab88fb691p-4L, 0xc.6643216e56bbfb4p-4L, 0xc.6643216e56bbfb5p-4L }, - { -0xe.5d425700b9dfb9p-4L, -0x7.699c2694c5a2105p-4L, -0x7.699c2694c5a21048p-4L }, - { 0x7.ef30d4f5d43c309p-4L, 0x6.902a2db66b7bda78p-4L, 0x6.902a2db66b7bda8p-4L }, - { -0xc.2cc3adaa5f76bd8p-4L, -0x6.8ee23784f80cfdc8p-4L, -0x6.8ee23784f80cfdcp-4L }, - { 0x2.8b29e4e9b1677aap-4L, 0x1.dd28d0729a15749cp-4L, 0x1.dd28d0729a15749ep-4L }, - { -0xb.c9870bb9c74469p-4L, -0x6.65f306cc38bba318p-4L, -0x6.65f306cc38bba31p-4L }, - { 0x3.9b5a02bfcb72b468p-4L, 0x2.b4bb195f6468ceep-4L, 0x2.b4bb195f6468cee4p-4L }, - { -0x3.fcdc007ba74601ap-4L, -0x2.89db741e09207918p-4L, -0x2.89db741e09207914p-4L }, - { 0xf.8ea939c39a2414cp-8L, 0xb.038978e1848fbcep-8L, 0xb.038978e1848fbcfp-8L }, - { -0xd.38eafd3878fe2f4p-12L, -0x9.279f93a09aef86p-12L, -0x9.279f93a09aef85fp-12L }, - { 0x1.c55b237b57929914p-8L, 0x1.3aff3dbaa1f54462p-8L, 0x1.3aff3dbaa1f54464p-8L }, - { -0xe.5512393a7c3aa68p-4L, -0x7.668fce4e8d41ec3p-4L, -0x7.668fce4e8d41ec28p-4L }, - { 0x6.c72dbae38baf489p-4L, 0x5.75f2be10b3da51p-4L, 0x5.75f2be10b3da5108p-4L }, - { -0xa.9efab67bae298c4p-4L, -0x5.e692c461328f2a38p-4L, -0x5.e692c461328f2a3p-4L }, - { 0x6.d6fe2acf94b44bp-4L, 0x5.84abad9d09e7a7dp-4L, 0x5.84abad9d09e7a7d8p-4L }, - { -0x2.1052fcc75fe78e44p-4L, -0x1.5e50254d52c2cb86p-4L, -0x1.5e50254d52c2cb84p-4L }, - { 0xf.5f7e274f7549127p-4L, 0xf.247c06ed64581d2p-4L, 0xf.247c06ed64581d3p-4L }, - { -0xc.e3f378c5ed3afabp-4L, -0x6.d8aa145971328588p-4L, -0x6.d8aa14597132858p-4L }, - { 0x5.ed5d3988224f9748p-4L, 0x4.af2122809de98b08p-4L, 0x4.af2122809de98b1p-4L }, - { -0x3.ceeb00215e0d28fp-4L, -0x2.6ef600bcd292a928p-4L, -0x2.6ef600bcd292a924p-4L }, - { 0x1.81a67feedc219a8cp-160L, 0x1.0b4ffeb467c6a36cp-160L, 0x1.0b4ffeb467c6a36ep-160L }, - { -0x4.1c590bda30ba606p-76L, -0x2.d96e935fdb4f2c6p-76L, -0x2.d96e935fdb4f2c5cp-76L }, - { 0xc.afcea80015980b8p-4L, 0xb.b8a5752c99ff1d2p-4L, 0xb.b8a5752c99ff1d3p-4L }, - { -0xb.d8b227ae135fe8fp-4L, -0x6.6c4030ee2cb63a3p-4L, -0x6.6c4030ee2cb63a28p-4L }, - { 0x8.dc01d8b49232a17p-4L, 0x7.7c58fa948c1ea33p-4L, 0x7.7c58fa948c1ea338p-4L }, - { -0x1.933e5a044e710e98p-4L, -0x1.0e2f0aea0ed3f88ep-4L, -0x1.0e2f0aea0ed3f88cp-4L }, - { 0x1.a467d39df9435c82p-4L, 0x1.2e04d4c090c9af46p-4L, 0x1.2e04d4c090c9af48p-4L }, - { -0xd.177492196d07a44p-4L, -0x6.ecffef80c3115ef8p-4L, -0x6.ecffef80c3115efp-4L }, - { 0xa.8eb53214a5d4d15p-4L, 0x9.474ddcecd909225p-4L, 0x9.474ddcecd909226p-4L }, - { -0x1.8712ead1e57a5c3cp-4L, -0x1.064bf416745202b8p-4L, -0x1.064bf416745202b6p-4L }, - { 0x8.4de1b5d10a110dbp-4L, 0x6.ed77dcb741f173c8p-4L, 0x6.ed77dcb741f173dp-4L }, - { -0x2.5fb6ddfc66521d98p-4L, -0x1.904c98bb8b81f248p-4L, -0x1.904c98bb8b81f246p-4L }, - { 0x9.4d57927720bce2ap-4L, 0x7.f0c5a855860ee5c8p-4L, 0x7.f0c5a855860ee5dp-4L }, - { -0xd.c24a0c2da437c45p-8L, -0x9.5c8c25cb60521fp-8L, -0x9.5c8c25cb60521efp-8L }, - { 0xe.f5d12aeb5942b6bp-8L, 0xa.951ffb20b4a544dp-8L, 0xa.951ffb20b4a544ep-8L }, - { -0x1.6c160eed113f724cp-8L, -0xf.be148f1adb1e1fp-12L, -0xf.be148f1adb1e1efp-12L }, - { 0xe.5e4d4cc7965edb5p-4L, 0xd.d0f05f423ac4ecp-4L, 0xd.d0f05f423ac4ec1p-4L }, - { -0x9.fc2ec0983ea77b3p-4L, -0x5.9e5b37a59c48991p-4L, -0x5.9e5b37a59c489908p-4L }, - { 0xe.add7dabec19d155p-4L, 0xe.38603c1d1ea2234p-4L, 0xe.38603c1d1ea2235p-4L }, - { -0xe.ca8e0a5bcb1909bp-4L, -0x7.91e59560df20b59p-4L, -0x7.91e59560df20b588p-4L }, - { 0xf.3c4d21f42ce9eep-4L, 0xe.f525a7db23c77d2p-4L, 0xe.f525a7db23c77d3p-4L }, - { -0x6.a2b3b3cd69bd69p-4L, -0x3.ff5415c01005cd3p-4L, -0x3.ff5415c01005cd2cp-4L }, - { 0x1.5878b28462452782p-68L, 0xe.ec4f96d55b56cbap-72L, 0xe.ec4f96d55b56cbbp-72L }, - { -0xd.226b6159f1b8274p-176L, -0x9.1aa6ccef2946b71p-176L, -0x9.1aa6ccef2946b7p-176L }, - { 0xd.a2d0231770a0b2fp-4L, 0xc.e29042d0f0148dep-4L, 0xc.e29042d0f0148dfp-4L }, - { -0x5.88f950204ac58c2p-4L, -0x3.6949fabdeff8c62cp-4L, -0x3.6949fabdeff8c628p-4L }, - { 0xd.566e196c5299a76p-4L, 0xc.8398d1f51b7d57bp-4L, 0xc.8398d1f51b7d57cp-4L }, - { -0xd.827bfd05ebedd0fp-4L, -0x7.16b1fb3d30143fdp-4L, -0x7.16b1fb3d30143fc8p-4L }, - { 0xe.690353be92b1ef7p-4L, 0xd.dec96ccbdc54711p-4L, 0xd.dec96ccbdc54712p-4L }, - { -0xc.b40a6525370a3c1p-4L, -0x6.c59691f570ea335p-4L, -0x6.c59691f570ea3348p-4L }, - { 0x4.a16f62e1fb463d7p-4L, 0x3.8de59c3015480afp-4L, 0x3.8de59c3015480af4p-4L }, - { -0xb.6a308232b3be302p-4L, -0x6.3df86ee55414e478p-4L, -0x6.3df86ee55414e47p-4L }, - { 0xa.589c3c563d348fcp-4L, 0x9.0c54f3c1e94b5d5p-4L, 0x9.0c54f3c1e94b5d6p-4L }, - { -0xe.aaf84b1b375592p-4L, -0x7.8654b73051a16d2p-4L, -0x7.8654b73051a16d18p-4L }, - { 0x2.4225b8cb6a3450acp-4L, 0x1.a5000bbb5b20203p-4L, 0x1.a5000bbb5b202032p-4L }, - { -0x5.e1f5a13fb1e038ap-16L, -0x4.13d1b0bbfe40d278p-16L, -0x4.13d1b0bbfe40d27p-16L }, - { 0x6.501f9ed256bec01p-4L, 0x5.085e4ef770a5bbd8p-4L, 0x5.085e4ef770a5bbep-4L }, - { -0xa.0150779e90ebc75p-4L, -0x5.a0a9cac5cfa9e798p-4L, -0x5.a0a9cac5cfa9e79p-4L }, - { 0xd.5de12ee5f0afea5p-4L, 0xc.8cce152f519601bp-4L, 0xc.8cce152f519601cp-4L }, - { -0x8.16fa985eea51244p-4L, -0x4.baee6e9ee24b5858p-4L, -0x4.baee6e9ee24b585p-4L }, - { 0x2.32885a9f2271ac78p-4L, 0x1.991486e0e24975d2p-4L, 0x1.991486e0e24975d4p-4L }, - { -0x9.2c631a27ad6ae34p-4L, -0x5.3f3d59c428297e48p-4L, -0x5.3f3d59c428297e4p-4L }, - { 0xd.5153d9f62ecffddp-4L, 0xc.7d4bf03f0e6d411p-4L, 0xc.7d4bf03f0e6d412p-4L }, - { -0x2.e68bda95c5b3e06cp-4L, -0x1.e3ab538ce3f7ecdap-4L, -0x1.e3ab538ce3f7ecd8p-4L }, - { 0x7.a68b5532b0e7f568p-200L, 0x5.4d8f37527724f7d8p-200L, 0x5.4d8f37527724f7ep-200L }, - { -0x3.cd1483e1b10e99dp-84L, -0x2.a27cdd6c9a12d844p-84L, -0x2.a27cdd6c9a12d84p-84L }, - { 0xc.e8479ca0a43ef6p-8L, 0x9.1ad81877660b242p-8L, 0x9.1ad81877660b243p-8L }, - { -0x9.182ad6a367d08aep-4L, -0x5.35cdecfe5b731ce8p-4L, -0x5.35cdecfe5b731cep-4L }, - { 0x9.3029b8a7e85f35dp-4L, 0x7.d29571a8ad519618p-4L, 0x7.d29571a8ad51962p-4L }, - { -0xa.52ae9411f58887cp-4L, -0x5.c4f9aa019dcb689p-4L, -0x5.c4f9aa019dcb6888p-4L }, - { 0x7.5113a83ec9894cep-4L, 0x5.f7a9702b44563248p-4L, 0x5.f7a9702b4456325p-4L }, - { -0xd.13cf8aa40b87d27p-4L, -0x6.eb9109ecc7f4ddb8p-4L, -0x6.eb9109ecc7f4ddbp-4L }, - { 0xf.2395a1a0df7935bp-4L, 0xe.d411568c149c22fp-4L, 0xe.d411568c149c23p-4L }, - { -0x1.7af3bd8ca1f57c42p-4L, -0xf.e6caba0e492e4c1p-8L, -0xf.e6caba0e492e4cp-8L }, - { 0xd.f33b2053ffa6ae5p-4L, 0xd.47e1d5b0dd7bc76p-4L, 0xd.47e1d5b0dd7bc77p-4L }, - { -0xa.8e75c696dc40c78p-4L, -0x5.df55ef48a4e347e8p-4L, -0x5.df55ef48a4e347ep-4L }, - { 0x9.85d3f0dd48eaf72p-4L, 0x8.2ba30c3f7be89e3p-4L, 0x8.2ba30c3f7be89e4p-4L }, - { -0xd.506b8a6e4aa92acp-4L, -0x7.03491cf2bf49246p-4L, -0x7.03491cf2bf492458p-4L }, - { 0xa.d1883d4b01ef45ap-4L, 0x9.90e6441f511c6d1p-4L, 0x9.90e6441f511c6d2p-4L }, - { -0x3.08af0a00602595fp-4L, -0x1.f87a2c14dd7b7f16p-4L, -0x1.f87a2c14dd7b7f14p-4L }, - { 0xf.cac159b69035579p-4L, 0xf.b684c855d131bb2p-4L, 0xf.b684c855d131bb3p-4L }, - { -0x6.46e719cea85447d8p-4L, -0x3.cf38f95b6009617cp-4L, -0x3.cf38f95b60096178p-4L }, - { 0x5.987b05c45ed8a2ep-4L, 0x4.639c8775c1682ffp-4L, 0x4.639c8775c1682ff8p-4L }, - { -0x6.c4e52aa8d26db038p-4L, -0x4.110e8410a7512478p-4L, -0x4.110e8410a751247p-4L }, - { 0x8.23b5b38feb155f2p-4L, 0x6.c3bac23408a8825p-4L, 0x6.c3bac23408a88258p-4L }, - { -0x8.ad2a11b7f1b5ea6p-4L, -0x5.0354fe71cc130f2p-4L, -0x5.0354fe71cc130f18p-4L }, - { 0xf.af53dc003c2e966p-112L, 0xa.df368663af3dfc2p-112L, 0xa.df368663af3dfc3p-112L }, - { -0x3.f7b5578e89e3d3e8p-128L, -0x2.c0090f63161770cp-128L, -0x2.c0090f63161770bcp-128L }, - { 0x3.73e18f430b288f48p-4L, 0x2.94d9fe08f28f346cp-4L, 0x2.94d9fe08f28f347p-4L }, - { -0xc.f70837877517a74p-4L, -0x6.e03802a500a2e72p-4L, -0x6.e03802a500a2e718p-4L }, - { 0x7.3487f80314c54488p-4L, 0x5.dc8fba31d9f318ep-4L, 0x5.dc8fba31d9f318e8p-4L }, - { -0x5.4eccb9e96eb8967p-4L, -0x3.4967fb3eb0a4d81cp-4L, -0x3.4967fb3eb0a4d818p-4L }, - { 0x9.44460917d619271p-4L, 0x7.e75fbc9c380ed29p-4L, 0x7.e75fbc9c380ed298p-4L }, - { -0xd.5620dcdef8d6adep-4L, -0x7.0581c9d72c7b4df8p-4L, -0x7.0581c9d72c7b4dfp-4L }, - { 0xd.105984ee31d1a19p-4L, 0xc.2d8a202b2771e41p-4L, 0xc.2d8a202b2771e42p-4L }, - { -0xe.cb19e0196a54de2p-4L, -0x7.9218a6517e6df27p-4L, -0x7.9218a6517e6df268p-4L }, - { 0x5.b49471d499a4cf1p-4L, 0x4.7c7d8b0af0f48c28p-4L, 0x4.7c7d8b0af0f48c3p-4L }, - { -0x9.94f5bdecfacab51p-8L, -0x6.8e6561102f3ee5e8p-8L, -0x6.8e6561102f3ee5ep-8L }, - { 0xf.641993c9a620462p-4L, 0xf.2ab3dcfcad4c33ap-4L, 0xf.2ab3dcfcad4c33bp-4L }, - { -0xd.a2dd238869b2787p-4L, -0x7.23294ba101bfcb28p-4L, -0x7.23294ba101bfcb2p-4L }, - { 0xd.4c3f10c6378bac1p-4L, 0xc.77072f3026675d1p-4L, 0xc.77072f3026675d2p-4L }, - { -0xd.a0da38c144c364ap-4L, -0x7.22638fd7197afdbp-4L, -0x7.22638fd7197afda8p-4L }, - { 0x5.9e57359c4cf1067p-4L, 0x4.68ca49a0fa5b5d78p-4L, 0x4.68ca49a0fa5b5d8p-4L }, - { -0xf.5afa51a915c3c2cp-4L, -0x7.c600693d7adedab8p-4L, -0x7.c600693d7adedabp-4L }, - { 0xa.7324ede2d5b774ep-4L, 0x9.29307a00e1a50c1p-4L, 0x9.29307a00e1a50c2p-4L }, - { -0x4.deb94e5dff32647p-4L, -0x3.0b17181ece0d3c68p-4L, -0x3.0b17181ece0d3c64p-4L }, - { 0x6.67af9a1b48f5476p-4L, 0x5.1de173c8b6ffd77p-4L, 0x5.1de173c8b6ffd778p-4L }, - { -0xb.916f204d9b607e2p-4L, -0x6.4e815e5c604ec948p-4L, -0x6.4e815e5c604ec94p-4L }, - { 0x9.a94b7284791aef1p-88L, 0x6.b25b7556a0da05f8p-88L, 0x6.b25b7556a0da06p-88L }, - { -0x7.986b2cd7ddf22268p-132L, -0x5.43c4afc7229c434p-132L, -0x5.43c4afc7229c4338p-132L }, - { 0x1.15035f9ba3aac31ep-4L, 0xc.49523582a5e80c3p-8L, 0xc.49523582a5e80c4p-8L }, - { -0xc.6f90a760827aa89p-4L, -0x6.aa0dc49e51cdac1p-4L, -0x6.aa0dc49e51cdac08p-4L }, - { 0xf.fef4a753b10a076p-4L, 0xf.fe8d6976d07d14bp-4L, 0xf.fe8d6976d07d14cp-4L }, - { -0x6.4c2eb46758106918p-4L, -0x3.d202750df16f62a4p-4L, -0x3.d202750df16f62ap-4L }, - { 0x1.3ef509e0c382df66p-4L, 0xe.328e01d44f681dp-8L, 0xe.328e01d44f681d1p-8L }, - { -0xc.49b63ac9b2b9eaap-4L, -0x6.9ab1ff6082b3beap-4L, -0x6.9ab1ff6082b3be98p-4L }, - { 0x6.d057f880739cc278p-4L, 0x5.7e79c56f2d15b708p-4L, 0x5.7e79c56f2d15b71p-4L }, - { -0xb.1981c21be406601p-4L, -0x6.1ba12bbd58b2c01p-4L, -0x6.1ba12bbd58b2c008p-4L }, - { 0x8.0a6f57c957a28d4p-4L, 0x6.aadb51c6015dbep-4L, 0x6.aadb51c6015dbe08p-4L }, - { -0x5.f3f181c210c8a89p-4L, -0x3.a319fd0750dac56p-4L, -0x3.a319fd0750dac55cp-4L }, - { 0xe.2859c8a2c48c40ap-4L, 0xd.8b91686f98b11bdp-4L, 0xd.8b91686f98b11bep-4L }, - { -0xa.dd44c44ce7a5755p-4L, -0x6.01aed71b7ef78488p-4L, -0x6.01aed71b7ef7848p-4L }, - { 0xb.51ba4b350a61c32p-4L, 0xa.206f7762d17482bp-4L, 0xa.206f7762d17482cp-4L }, - { -0xc.0dfbf7e5e3212ffp-12L, -0x8.58dc6a67dabce9bp-12L, -0x8.58dc6a67dabce9ap-12L }, - { 0x7.6c639e488208ccc8p-4L, 0x6.11b6da6b26aebcd8p-4L, 0x6.11b6da6b26aebcep-4L }, - { -0x3.a1d6c7b434bf3d98p-4L, -0x2.545d932e669d3904p-4L, -0x2.545d932e669d39p-4L }, - { 0x5.c358113ef832c348p-4L, 0x4.899c27db749b1de8p-4L, 0x4.899c27db749b1dfp-4L }, - { -0xb.d7d98c530f97875p-4L, -0x6.6be6509d664dfbbp-4L, -0x6.6be6509d664dfba8p-4L }, - { 0x4.fa42d3ac3bebd7e8p-4L, 0x3.d9b642da220bca6p-4L, 0x3.d9b642da220bca64p-4L }, - { -0xa.5b3f67eed42f35ep-4L, -0x5.c8c4d54ed02eeb08p-4L, -0x5.c8c4d54ed02eebp-4L }, - { 0x8.df34d29839f6cbap-140L, 0x6.2647bfc5682b23d8p-140L, 0x6.2647bfc5682b23ep-140L }, - { -0x4.37cad4bbf2a5aa78p-108L, -0x2.ec747a81313e72acp-108L, -0x2.ec747a81313e72a8p-108L }, - { 0x1.d6566fbbd43703bcp-4L, 0x1.5356ad8698dd1454p-4L, 0x1.5356ad8698dd1456p-4L }, - { -0x5.7c58e6c483f58898p-4L, -0x3.6265408f3b9628d4p-4L, -0x3.6265408f3b9628dp-4L }, - { 0x4.6a4204ea8eeaab98p-4L, 0x3.5f5f5a4b33974f1p-4L, 0x3.5f5f5a4b33974f14p-4L }, - { -0x8.3dccba3b25f76c1p-4L, -0x4.cdd2979cf80fe2a8p-4L, -0x4.cdd2979cf80fe2ap-4L }, - { 0xd.5f0d592ded19983p-4L, 0xc.8e415fdd3807e8fp-4L, 0xc.8e415fdd3807e9p-4L }, - { -0xa.c3b832d5003b707p-8L, -0x7.5a8d2a98b9c25298p-8L, -0x7.5a8d2a98b9c2529p-8L }, - { 0xa.1061f8f22c56a2p-4L, 0x8.be6ebf67d3a8ca6p-4L, 0x8.be6ebf67d3a8ca7p-4L }, - { -0x7.a0e695df486975a8p-4L, -0x4.80b3df37bd2da46p-4L, -0x4.80b3df37bd2da458p-4L }, - { 0x2.0f49c0d924c5ef48p-4L, 0x1.7e4a674b14e39638p-4L, 0x1.7e4a674b14e3963ap-4L }, - { -0x2.98c242e38ab361a4p-4L, -0x1.b3cdb6359889897cp-4L, -0x1.b3cdb6359889897ap-4L }, - { 0xe.a88d8d085eb83b1p-4L, 0xe.3173fc65ba950ccp-4L, 0xe.3173fc65ba950cdp-4L }, - { -0x7.18f85d323644c07p-4L, -0x4.3c36aae8265e794p-4L, -0x4.3c36aae8265e7938p-4L }, - { 0xb.e3d76e1e4bf5645p-8L, 0x8.6028af6e8498d12p-8L, 0x8.6028af6e8498d13p-8L }, - { -0xa.e3f91773dee5cbdp-4L, -0x6.0495789dfe04b06p-4L, -0x6.0495789dfe04b058p-4L }, - { 0x6.64a485a65ba2bb8p-4L, 0x5.1b18ec86f4768a78p-4L, 0x5.1b18ec86f4768a8p-4L }, - { -0xb.ab5d793764e46aap-4L, -0x6.595eea36719ee3p-4L, -0x6.595eea36719ee2f8p-4L }, - { 0x4.180ed04588b6b84p-4L, 0x3.1add121478e2fe34p-4L, 0x3.1add121478e2fe38p-4L }, - { -0x3.1b46b393f7f02654p-4L, -0x2.03c27049f1c5241p-4L, -0x2.03c27049f1c5240cp-4L }, - { 0xb.12b6b696713dd3p-4L, 0x9.d97de4a57a62c6ep-4L, 0x9.d97de4a57a62c6fp-4L }, - { -0x4.65ce2cb3797b29a8p-12L, -0x3.0c0efb555fa20864p-12L, -0x3.0c0efb555fa2086p-12L }, - { 0x2.8d217b257289e3ccp-48L, 0x1.c4b73c33ff87c0a6p-48L, 0x1.c4b73c33ff87c0a8p-48L }, - { -0x6.2775ae1abb4f1b8p-132L, -0x4.44068348b3cc65f8p-132L, -0x4.44068348b3cc65fp-132L }, - { 0x7.9916813ff5ff3cc8p-4L, 0x6.3c9c97e7b3dc5dcp-4L, 0x6.3c9c97e7b3dc5dc8p-4L }, - { -0xe.8cc5489d5bd410dp-4L, -0x7.7b36e89d757a4abp-4L, -0x7.7b36e89d757a4aa8p-4L }, - { 0x4.332914d9e18063ap-4L, 0x3.3158c643f12f4994p-4L, 0x3.3158c643f12f4998p-4L }, - { -0xb.0de0f587f5c107fp-4L, -0x6.16a43bbcf353ca98p-4L, -0x6.16a43bbcf353ca9p-4L }, - { 0x7.8ea9558f03ae0e7p-4L, 0x6.32938e784969b998p-4L, 0x6.32938e784969b9ap-4L }, - { -0xf.dee9088b413455fp-4L, -0x7.f47ff39c1d7b3888p-4L, -0x7.f47ff39c1d7b388p-4L }, - { 0x8.2df8e53739c9b8bp-4L, 0x6.cddbf2a3d58ac5cp-4L, 0x6.cddbf2a3d58ac5c8p-4L }, - { -0xb.237c6168dab68dbp-4L, -0x6.1fe702218f1a48a8p-4L, -0x6.1fe702218f1a48ap-4L }, - { 0xc.ff8006e798ca57dp-4L, 0xc.190015c68329532p-4L, 0xc.190015c68329533p-4L }, - { -0x5.a01080821eed49f8p-4L, -0x3.75db7123ab84cf58p-4L, -0x3.75db7123ab84cf54p-4L }, - { 0x7.837abefd5e55df78p-4L, 0x6.27d5641a6c02fc68p-4L, 0x6.27d5641a6c02fc7p-4L }, - { -0x3.5060ef99941b0558p-4L, -0x2.23c9d923cd4adb98p-4L, -0x2.23c9d923cd4adb94p-4L }, - { 0xe.81ed35e6e8294cep-4L, 0xd.ff1805c791d6424p-4L, 0xd.ff1805c791d6425p-4L }, - { -0x4.bb21255de4a41a5p-4L, -0x2.f70cf4785702e974p-4L, -0x2.f70cf4785702e97p-4L }, - { 0x2.a7771004562ceed4p-4L, 0x1.f31d427f09d18b7cp-4L, 0x1.f31d427f09d18b7ep-4L }, - { -0x1.6959757c92243a3ap-4L, -0xf.2f6ce0c9b166b49p-8L, -0xf.2f6ce0c9b166b48p-8L }, - { 0x6.bbde2a7543c30b38p-4L, 0x5.6b71442a60dd2568p-4L, 0x5.6b71442a60dd257p-4L }, - { -0xb.8edecd5dd38da0cp-4L, -0x6.4d6db28b17aa8588p-4L, -0x6.4d6db28b17aa858p-4L }, - { 0x6.c15f52803f443968p-4L, 0x5.708d7c1ba353e398p-4L, 0x5.708d7c1ba353e3ap-4L }, - { -0x3.918ec1969b0edd88p-4L, -0x2.4ab5c149bf41c4c4p-4L, -0x2.4ab5c149bf41c4cp-4L }, - { 0x7.7b238d3b9d8115e8p-120L, 0x5.2f791dc93f08299p-120L, 0x5.2f791dc93f082998p-120L }, - { -0x1.9f3582a69a86e648p-60L, -0x1.1fcd0c091eb14d28p-60L, -0x1.1fcd0c091eb14d26p-60L }, - { 0x6.81487cec2e861c7p-8L, 0x4.8c82f180777d68f8p-8L, 0x4.8c82f180777d69p-8L }, - { -0x4.87a7a304beeda28p-4L, -0x2.d9db282588789b7cp-4L, -0x2.d9db282588789b78p-4L }, - { 0xd.c7238c1ad3cafc9p-4L, 0xd.1028e60f36ff2b1p-4L, 0xd.1028e60f36ff2b2p-4L }, - { -0xe.ac1774f7032d1ffp-4L, -0x7.86be2433cc1d9da8p-4L, -0x7.86be2433cc1d9dap-4L }, - { 0x8.fc6153c653d77c7p-4L, 0x7.9d6025bd14094ad8p-4L, 0x7.9d6025bd14094aep-4L }, - { -0x1.014e18840001d972p-4L, -0xa.e85ead1a4e78382p-8L, -0xa.e85ead1a4e78381p-8L }, - { 0x5.040eb8c257682f18p-4L, 0x3.e224b9c7d7c0f06cp-4L, 0x3.e224b9c7d7c0f07p-4L }, - { -0xf.7346ad82e18af85p-4L, -0x7.cea4b926fe7c2368p-4L, -0x7.cea4b926fe7c236p-4L }, - { 0x3.c7346df124e8ef98p-4L, 0x2.d8668c024b6308e8p-4L, 0x2.d8668c024b6308ecp-4L }, - { -0xc.f461f50edbbb96fp-4L, -0x6.df2bda27bd06182p-4L, -0x6.df2bda27bd061818p-4L }, - { 0xd.c278b0558bd0b11p-4L, 0xd.0a4916e65159357p-4L, 0xd.0a4916e65159358p-4L }, - { -0x4.b2842fc0d4e29f8p-4L, -0x2.f22eea0353ff92dp-4L, -0x2.f22eea0353ff92ccp-4L }, - { 0xf.a09a22b402060edp-4L, 0xf.7ccfec40ad06d7ep-4L, 0xf.7ccfec40ad06d7fp-4L }, - { -0x8.e32395dc002f9bfp-8L, -0x6.162efd7ddd7ad93p-8L, -0x6.162efd7ddd7ad928p-8L }, - { 0xf.8c0db00bdf53596p-4L, 0xf.60d4a396fb9dadcp-4L, 0xf.60d4a396fb9daddp-4L }, - { -0x5.36e056abcab2faa8p-4L, -0x3.3c3413c718ca2bf4p-4L, -0x3.3c3413c718ca2bfp-4L }, - { 0x7.6c92e56712d5affp-4L, 0x6.11e40e1716fd4fb8p-4L, 0x6.11e40e1716fd4fcp-4L }, - { -0xd.6cb0532deaf2679p-4L, -0x7.0e43f2e8f0654b5p-4L, -0x7.0e43f2e8f0654b48p-4L }, - { 0x1.864d5d5420279f0cp-4L, 0x1.17abd4dea55c6812p-4L, 0x1.17abd4dea55c6814p-4L }, - { -0xa.e4299f2f9dca735p-4L, -0x6.04aa7510ef638d5p-4L, -0x6.04aa7510ef638d48p-4L }, - { 0xe.d132e5394f60034p-128L, 0xa.453ebc4a42e6cb8p-128L, 0xa.453ebc4a42e6cb9p-128L }, - { -0x2.35600cb5057b0fe8p-100L, -0x1.87e3627dc194acb4p-100L, -0x1.87e3627dc194acb2p-100L }, - { 0x9.ea2a7bd17c460dep-4L, 0x8.95993518360a117p-4L, 0x8.95993518360a118p-4L }, - { -0xe.c5d9227ffaac8cfp-4L, -0x7.902d5e9f35d6cfa8p-4L, -0x7.902d5e9f35d6cfap-4L }, - { 0x7.e3d1eea20b324e7p-4L, 0x6.850f961c58bba1cp-4L, 0x6.850f961c58bba1c8p-4L }, - { -0x9.86088a50194e78ap-4L, -0x5.68af5d2483728da8p-4L, -0x5.68af5d2483728dap-4L }, - { 0xf.7fa93e24f531607p-4L, 0xf.5000aaa67e5abb3p-4L, 0xf.5000aaa67e5abb4p-4L }, - { -0x6.3df2b4ad8ed98938p-4L, -0x3.ca7d689c3a04ee1cp-4L, -0x3.ca7d689c3a04ee18p-4L }, - { 0xe.e19314560029718p-4L, 0xe.7c6642b7e0cbddap-4L, 0xe.7c6642b7e0cbddbp-4L }, - { -0xa.e3c3bdecf1dec26p-8L, -0x7.701f272b4e954b3p-8L, -0x7.701f272b4e954b28p-8L }, - { 0x7.13c978b522f9333p-4L, 0x5.bda2c8c3fcf67318p-4L, 0x5.bda2c8c3fcf6732p-4L }, - { -0xd.81aab9ad9044dbbp-4L, -0x7.16613057101cc2e8p-4L, -0x7.16613057101cc2ep-4L }, - { 0x1.1d1ed153b343c44ep-4L, 0xc.a79cde97e744a1p-8L, 0xc.a79cde97e744a11p-8L }, - { -0x7.6fdb8f997549cde8p-8L, -0x5.1a74b0bff8212ac8p-8L, -0x5.1a74b0bff8212acp-8L }, - { 0x9.e81deac115960bcp-4L, 0x8.936a9f1de1dc2c9p-4L, 0x8.936a9f1de1dc2cap-4L }, - { -0xf.6e420d340620fd3p-4L, -0x7.ccdc951843f633f8p-4L, -0x7.ccdc951843f633fp-4L }, - { 0xe.6c4b7e894887c7fp-4L, 0xd.e308edc7c69afe9p-4L, 0xd.e308edc7c69afeap-4L }, - { -0xa.a620eccc4c7480bp-4L, -0x5.e9b3097aa5fb3aep-4L, -0x5.e9b3097aa5fb3ad8p-4L }, - { 0x1.c456c45ad9be2a9p-4L, 0x1.45d98d5ceaac11ecp-4L, 0x1.45d98d5ceaac11eep-4L }, - { -0x3.af9571884b9dea6cp-4L, -0x2.5c7f00327abdcc8cp-4L, -0x2.5c7f00327abdcc88p-4L }, - { 0xb.a0a2f3e13b85a66p-4L, 0xa.7a58fb959132f5p-4L, 0xa.7a58fb959132f51p-4L }, - { -0x1.574d5a4e81cea558p-4L, -0xe.72dbed0cf3f04efp-8L, -0xe.72dbed0cf3f04eep-8L }, - { 0x2.4592a2ef43290dcp-184L, 0x1.931d946725be0bacp-184L, 0x1.931d946725be0baep-184L }, - { -0x2.1340349dc88fe5ap-148L, -0x1.703c28b59101b778p-148L, -0x1.703c28b59101b776p-148L }, - { 0xc.52069130f81cabfp-8L, 0x8.af13d4a97a211afp-8L, 0x8.af13d4a97a211bp-8L }, - { -0x4.20c946d47a37871p-4L, -0x2.9ebecd164da3800cp-4L, -0x2.9ebecd164da38008p-4L }, - { 0xc.ad96dfac7b95172p-4L, 0xb.b5fbb7908197649p-4L, 0xb.b5fbb790819764ap-4L }, - { -0x1.1fc7d37c0ec92196p-4L, -0xc.2b1ec45e46b2f21p-8L, -0xc.2b1ec45e46b2f2p-8L }, - { 0xd.0d8c22a9e6d3c5p-4L, 0xc.2a1e9cdc9f50a83p-4L, 0xc.2a1e9cdc9f50a84p-4L }, - { -0x8.c7054bd7b8a06d5p-4L, -0x5.0f9cb256bb7dc48p-4L, -0x5.0f9cb256bb7dc478p-4L }, - { 0x5.13c1489191b10628p-4L, 0x3.efaed7947e426ea4p-4L, 0x3.efaed7947e426ea8p-4L }, - { -0x9.40268306f3eaf37p-4L, -0x5.486e4611a98deb68p-4L, -0x5.486e4611a98deb6p-4L }, - { 0x4.8b3a84ec2d62ab1p-4L, 0x3.7b1edaf9b2695bacp-4L, 0x3.7b1edaf9b2695bbp-4L }, - { -0x2.971ee88e20aca63cp-4L, -0x1.b2c9edea76d921ap-4L, -0x1.b2c9edea76d9219ep-4L }, - { 0x3.f7343ff72e27615cp-4L, 0x2.ffbf501a1f86d97cp-4L, 0x2.ffbf501a1f86d98p-4L }, - { -0xc.f38290b95d0f886p-4L, -0x6.ded38151017c9f78p-4L, -0x6.ded38151017c9f7p-4L }, - { 0x6.19ec462854667938p-4L, 0x4.d73549a9496846e8p-4L, 0x4.d73549a9496846fp-4L }, - { -0xe.a753d50ad228a17p-4L, -0x7.84fe3ea5ac9675c8p-4L, -0x7.84fe3ea5ac9675cp-4L }, - { 0xb.2326e5c709d8338p-4L, 0x9.ebecfa9a7ed2102p-4L, 0x9.ebecfa9a7ed2103p-4L }, - { -0xe.4cbeeba038e2a66p-4L, -0x7.63754094094d3058p-4L, -0x7.63754094094d305p-4L }, - { 0x9.90137db5d8438f6p-4L, 0x8.36609082c07d8ebp-4L, 0x8.36609082c07d8ecp-4L }, - { -0x8.f6fc2825e1cf803p-4L, -0x5.26400e89ac84512p-4L, -0x5.26400e89ac845118p-4L }, - { 0xb.a6e18f1dc982de2p-4L, 0xa.8183a9b9420a005p-4L, 0xa.8183a9b9420a006p-4L }, - { -0x7.093038cd340d2eap-4L, -0x4.3428c5f7bc4908e8p-4L, -0x4.3428c5f7bc4908ep-4L }, - { 0x1.7d48f31379a2fd94p-16L, 0x1.0849e6ab4023994ep-16L, 0x1.0849e6ab4023995p-16L }, - { -0xe.811989909a6ff03p-172L, -0xa.0db9811ffb53051p-172L, -0xa.0db9811ffb5305p-172L }, - { 0xf.a038fe23264b69fp-4L, 0xf.7c4b6a476a8be7cp-4L, 0xf.7c4b6a476a8be7dp-4L }, - { -0x5.d983ceba22bba45p-4L, -0x3.94ea4ac9f11d384cp-4L, -0x3.94ea4ac9f11d3848p-4L }, - { 0x3.aaf0ce3e734d6f2p-4L, 0x2.c161688c554ee7fcp-4L, 0x2.c161688c554ee8p-4L }, - { -0xf.72f358999238d68p-4L, -0x7.ce872556e868c9d8p-4L, -0x7.ce872556e868c9dp-4L }, - { 0x6.4d100f244be8113p-4L, 0x5.059488ceb9e3a5p-4L, 0x5.059488ceb9e3a508p-4L }, - { -0x8.8a2584d61c785a5p-4L, -0x4.f29d6d10179eb218p-4L, -0x4.f29d6d10179eb21p-4L }, - { 0xd.c98d7189a0303bfp-4L, 0xd.133307457e07c72p-4L, 0xd.133307457e07c73p-4L }, - { -0x1.4471ec132a54d16ap-4L, -0xd.ad37019fa9d9a9p-8L, -0xd.ad37019fa9d9a8fp-8L }, - { 0xb.bac11f4e1e14036p-4L, 0xa.985f73784b37eb5p-4L, 0xa.985f73784b37eb6p-4L }, - { -0x5.f466fe6cbdda3498p-4L, -0x3.a358e8e63a5fba64p-4L, -0x3.a358e8e63a5fba6p-4L }, - { 0xb.650503cc7e3186cp-4L, 0xa.364e81e99eb81f3p-4L, 0xa.364e81e99eb81f4p-4L }, - { -0x1.5d03274c615fac7ep-4L, -0xe.ae956d0835aaf87p-8L, -0xe.ae956d0835aaf86p-8L }, - { 0xf.e3a0ddc922c2768p-4L, 0xf.d8c34a986f967d3p-4L, 0xf.d8c34a986f967d4p-4L }, - { -0xa.669f21ff1f04159p-4L, -0x5.cdcc37c6f732fe1p-4L, -0x5.cdcc37c6f732fe08p-4L }, - { 0x8.ab617e168652f41p-4L, 0x7.4b137892a0c69d88p-4L, 0x7.4b137892a0c69d9p-4L }, - { -0xa.9ceb33ff19c471bp-4L, -0x5.e5abee4fb863c6ep-4L, -0x5.e5abee4fb863c6d8p-4L }, - { 0x7.e712d33d338b3f4p-4L, 0x6.883c6044c3c2bcb8p-4L, 0x6.883c6044c3c2bccp-4L }, - { -0x6.ed724b0ecd1acf48p-4L, -0x4.25f2ea71fb90ba5p-4L, -0x4.25f2ea71fb90ba48p-4L }, - { 0xb.0f353c55a1bc86bp-4L, 0x9.d59127340917f95p-4L, 0x9.d59127340917f96p-4L }, - { -0xa.9ea90fbdcd33289p-4L, -0x5.e66f0ac4d504378p-4L, -0x5.e66f0ac4d5043778p-4L }, - { 0x1.8d57c92ab74b5dbp-36L, 0x1.136ac861af6fd0cep-36L, 0x1.136ac861af6fd0dp-36L }, - { -0x5.db625c7f505b3848p-168L, -0x4.0f4b402286520448p-168L, -0x4.0f4b40228652044p-168L }, - { 0x2.b76e057b32691f28p-4L, 0x1.ff8b9dda8f045aep-4L, 0x1.ff8b9dda8f045ae2p-4L }, - { -0x6.dee852c47ad7ae6p-4L, -0x4.1e798f7b43706028p-4L, -0x4.1e798f7b4370602p-4L }, - { 0x6.bb1bf54be9664e8p-4L, 0x5.6abd10b33410d838p-4L, 0x5.6abd10b33410d84p-4L }, - { -0x6.aee79d84df01a37p-4L, -0x4.05aac336cc0ddf4p-4L, -0x4.05aac336cc0ddf38p-4L }, - { 0xf.db239caa0c58725p-4L, 0xf.cd0f1aa065d9edcp-4L, 0xf.cd0f1aa065d9eddp-4L }, - { -0x6.a15fc994e42a5f98p-4L, -0x3.fea35173a1f28d58p-4L, -0x3.fea35173a1f28d54p-4L }, - { 0xe.d6bf659b8abbf88p-4L, 0xe.6e1d0b3dcc929a2p-4L, 0xe.6e1d0b3dcc929a3p-4L }, - { -0x6.3520edf48c502b48p-4L, -0x3.c5d25806006121bcp-4L, -0x3.c5d25806006121b8p-4L }, - { 0x2.845d2338bd21f05cp-4L, 0x1.d7e66d41d318c988p-4L, 0x1.d7e66d41d318c98ap-4L }, - { -0x1.d3130e0c084f14c8p-4L, -0x1.37497e3ebaa67dcap-4L, -0x1.37497e3ebaa67dc8p-4L }, - { 0x7.e34ef80c4f7e3eep-4L, 0x6.848fd32b674801d8p-4L, 0x6.848fd32b674801ep-4L }, - { -0x5.a8b3cf39973ba25p-4L, -0x3.7a8bd473e711806cp-4L, -0x3.7a8bd473e7118068p-4L }, - { 0xa.b5fcccca163aaedp-4L, 0x9.727686834a4ee16p-4L, 0x9.727686834a4ee17p-4L }, - { -0x9.80fe0cfc3618055p-4L, -0x5.665f01272fca1dfp-4L, -0x5.665f01272fca1de8p-4L }, - { 0x1.deff9f28444c6c38p-4L, 0x1.59d80e0bc88e7a36p-4L, 0x1.59d80e0bc88e7a38p-4L }, - { -0x9.1da1f7cda29486bp-4L, -0x5.385b9fa450441c1p-4L, -0x5.385b9fa450441c08p-4L }, - { 0x9.24964216848ef53p-4L, 0x7.c6a60a15ee989f5p-4L, 0x7.c6a60a15ee989f58p-4L }, - { -0x7.c3b5a7c39208799p-4L, -0x4.91fd41abd0551208p-4L, -0x4.91fd41abd05512p-4L }, - { 0xc.7f839e0758c0fc4p-4L, 0xb.7ee2c8991a66c5bp-4L, 0xb.7ee2c8991a66c5cp-4L }, - { -0xa.04266867c71fecep-4L, -0x5.a1efea5e48c556e8p-4L, -0x5.a1efea5e48c556ep-4L }, - { 0x3.1aa2b36a1fb87f7cp-48L, 0x2.26cca4e6218f7cc8p-48L, 0x2.26cca4e6218f7cccp-48L }, - { -0x1.ba95b94050477ba6p-152L, -0x1.32c6c531dafa9e4p-152L, -0x1.32c6c531dafa9e3ep-152L }, - { 0x6.108af52b9d9b2bp-4L, 0x4.cebef902a16e9c8p-4L, 0x4.cebef902a16e9c88p-4L }, - { -0x3.072eed70b90d2ae8p-4L, -0x1.f790b03dd687e68cp-4L, -0x1.f790b03dd687e68ap-4L }, - { 0xb.ad44f9f8ad944a6p-4L, 0xa.88da98fd452a1b5p-4L, 0xa.88da98fd452a1b6p-4L }, - { -0xb.3fef5d7e57e0805p-4L, -0x6.2c0b5071c8e72768p-4L, -0x6.2c0b5071c8e7276p-4L }, - { 0xe.b53f2b3083d023ep-4L, 0xe.42131e5b55a520bp-4L, 0xe.42131e5b55a520cp-4L }, - { -0xb.f408f69524f06c2p-4L, -0x6.779147008107f7cp-4L, -0x6.779147008107f7b8p-4L }, - { 0x8.03baca4a7357516p-4L, 0x6.a446a2fcb76d806p-4L, 0x6.a446a2fcb76d8068p-4L }, - { -0xa.c1abbb69e26abf7p-4L, -0x5.f5b5017c8517f208p-4L, -0x5.f5b5017c8517f2p-4L }, - { 0x1.d872e7eedaaa637ep-4L, 0x1.54ec695ac1dbc924p-4L, 0x1.54ec695ac1dbc926p-4L }, - { -0x4.495ee30da4659e98p-4L, -0x2.b6306706e0bbaac4p-4L, -0x2.b6306706e0bbaacp-4L }, - { 0xc.150a73ee88aac4bp-4L, 0xb.0131f0d15ff1b5p-4L, 0xb.0131f0d15ff1b51p-4L }, - { -0xa.3e82e32d6766963p-4L, -0x5.bc052d79040a9f88p-4L, -0x5.bc052d79040a9f8p-4L }, - { 0x6.08720c311ad69e78p-4L, 0x4.c773b03aa96a3fc8p-4L, 0x4.c773b03aa96a3fdp-4L }, - { -0x7.3b6b4ffd7b8decp-8L, -0x4.f6d2acdaf77fd21p-8L, -0x4.f6d2acdaf77fd208p-8L }, - { 0x5.80db9fe644d1e708p-4L, 0x4.4ec994b6102856dp-4L, 0x4.4ec994b6102856d8p-4L }, - { -0x1.f640e13ffc2a24cap-4L, -0x1.4dc050898710d058p-4L, -0x1.4dc050898710d056p-4L }, - { 0xb.656227303abf84fp-4L, 0xa.36b8463547f4c73p-4L, 0xa.36b8463547f4c74p-4L }, - { -0x7.b40be4642e982ab8p-4L, -0x4.8a392adbf99bf968p-4L, -0x4.8a392adbf99bf96p-4L }, - { 0x2.8126daf9591a4a78p-4L, 0x1.d56af8b597dab07ep-4L, 0x1.d56af8b597dab08p-4L }, - { -0xf.8481196507714a9p-4L, -0x7.d4bfd1129eebe82p-4L, -0x7.d4bfd1129eebe818p-4L }, - { 0x2.1a154d27c4610f5cp-92L, 0x1.74f88a35a7f80dcep-92L, 0x1.74f88a35a7f80ddp-92L }, - { -0x5.585153da63583088p-12L, -0x3.b40448ded8eb7678p-12L, -0x3.b40448ded8eb7674p-12L }, - { 0x8.4b1f02dac6cd4b9p-4L, 0x6.eaba168a48b0171p-4L, 0x6.eaba168a48b01718p-4L }, - { -0xc.759d3a3d2bb277bp-4L, -0x6.ac7fc087257bf838p-4L, -0x6.ac7fc087257bf83p-4L }, - { 0x9.5efce40ef5c193p-4L, 0x8.0319c4d499a7ca3p-4L, 0x8.0319c4d499a7ca4p-4L }, - { -0x1.3acdec63c75ba85ap-4L, -0xd.47ed2768ca5ede8p-8L, -0xd.47ed2768ca5ede7p-8L }, - { 0x3.a8862397aa33d5bcp-4L, 0x2.bf6ad5c108758048p-4L, 0x2.bf6ad5c10875804cp-4L }, - { -0x8.40b99f3260074bbp-4L, -0x4.cf3dbd131e8a17ap-4L, -0x4.cf3dbd131e8a1798p-4L }, - { 0x1.13ba9d07bc3a2952p-4L, 0xc.3a6591e048e18fep-8L, 0xc.3a6591e048e18ffp-8L }, - { -0x2.71006a8cb34d554cp-4L, -0x1.9b18519a46103f02p-4L, -0x1.9b18519a46103fp-4L }, - { 0x9.1553f4826cd4c82p-4L, 0x7.b6f3ad6001421a68p-4L, 0x7.b6f3ad6001421a7p-4L }, - { -0x5.67cce3baa54af0cp-4L, -0x3.57257d17a151238cp-4L, -0x3.57257d17a1512388p-4L }, - { 0x3.8114a9e190ab791p-4L, 0x2.9f7d24d05db91814p-4L, 0x2.9f7d24d05db91818p-4L }, - { -0x4.9c18fd283d9a589p-4L, -0x2.e57b1e06ca7a4c84p-4L, -0x2.e57b1e06ca7a4c8p-4L }, - { 0xc.05b3f7d8b6f7624p-4L, 0xa.ef465963b3e1fc3p-4L, 0xa.ef465963b3e1fc4p-4L }, - { -0xc.aa597d6d2ed91e3p-4L, -0x6.c1b5f0a62eb977fp-4L, -0x6.c1b5f0a62eb977e8p-4L }, - { 0x5.7aa677b8b3a14efp-4L, 0x4.49543a3a46f57d38p-4L, 0x4.49543a3a46f57d4p-4L }, - { -0x6.8d1b5b54f8172e1p-4L, -0x3.f4143adbee4eb904p-4L, -0x3.f4143adbee4eb9p-4L }, - { 0x4.a8455a7e3a68ed78p-4L, 0x3.93b0e898b77bf4c8p-4L, 0x3.93b0e898b77bf4ccp-4L }, - { -0x8.f684ab518e13e14p-4L, -0x5.2607e33540e678cp-4L, -0x5.2607e33540e678b8p-4L }, - { 0xf.331d018a51a3937p-4L, 0xe.e8d595bf6b18a9ap-4L, 0xe.e8d595bf6b18a9bp-4L }, - { -0x3.eca2bd0c8570369p-4L, -0x2.80620c0582a7ae94p-4L, -0x2.80620c0582a7ae9p-4L }, - { 0xc.a5327c102d01348p-80L, 0x8.c3daa757b84ad52p-80L, 0x8.c3daa757b84ad53p-80L }, - { -0x2.a3c7cec074186df4p-180L, -0x1.d46a5432452e2c9p-180L, -0x1.d46a5432452e2c8ep-180L }, - { 0x2.293460674db2c4p-4L, 0x1.91f96e67e72e8cc2p-4L, 0x1.91f96e67e72e8cc4p-4L }, - { -0xd.ea0bd2fdf3193cep-4L, -0x7.3e53d5de8fa95728p-4L, -0x7.3e53d5de8fa9572p-4L }, - { 0x7.7cc8ad228793eeep-4L, 0x6.2169209a50da8dfp-4L, 0x6.2169209a50da8df8p-4L }, - { -0x3.3eb74cb49c028ad4p-4L, -0x2.192ac814bd5f0c5cp-4L, -0x2.192ac814bd5f0c58p-4L }, - { 0xe.bc5331958998244p-4L, 0xe.4b5bcd8b0908ccfp-4L, 0xe.4b5bcd8b0908cdp-4L }, - { -0x1.2903edbad4d00bdep-4L, -0xc.8c97befaf20c969p-8L, -0xc.8c97befaf20c968p-8L }, - { 0x5.3ee964d9303fef2p-4L, 0x4.1517b8de179c1dap-4L, 0x4.1517b8de179c1da8p-4L }, - { -0x9.0a14cf75dc8c935p-8L, -0x6.30877227885a5f9p-8L, -0x6.30877227885a5f88p-8L }, - { 0x6.e59cd2b304be20bp-8L, 0x4.d353ed698d0eff18p-8L, 0x4.d353ed698d0eff2p-8L }, - { -0xd.25ced593ff0ac61p-4L, -0x6.f2a2932d1abac2d8p-4L, -0x6.f2a2932d1abac2dp-4L }, - { 0x3.1617c019abd659bp-4L, 0x2.49f324ab933e42d8p-4L, 0x2.49f324ab933e42dcp-4L }, - { -0x6.690f39e52d0c90c8p-4L, -0x3.e1358e26e4c35228p-4L, -0x3.e1358e26e4c35224p-4L }, - { 0x9.1050fe64665d025p-4L, 0x7.b1ce2c811fa492bp-4L, 0x7.b1ce2c811fa492b8p-4L }, - { -0x7.f6184dd3447fc3fp-4L, -0x4.aad4f07652aeae78p-4L, -0x4.aad4f07652aeae7p-4L }, - { 0xd.953628a90529c68p-4L, 0xc.d1901b07c97032cp-4L, 0xc.d1901b07c97032dp-4L }, - { -0x7.43be3e30b7e5c7a8p-4L, -0x4.51ef59e61758d838p-4L, -0x4.51ef59e61758d83p-4L }, - { 0x7.a4dabfc6c9e825b8p-4L, 0x6.47f5486a01b237ap-4L, 0x6.47f5486a01b237a8p-4L }, - { -0xb.f01119533e278e8p-4L, -0x6.75ed9a05142d0eap-4L, -0x6.75ed9a05142d0e98p-4L }, - { 0x1.6396f574b56c6172p-4L, 0xf.e0af65687e4b67ep-8L, 0xf.e0af65687e4b67fp-8L }, - { -0xf.b5e4a3223e61c14p-4L, -0x7.e627a04f577a3258p-4L, -0x7.e627a04f577a325p-4L }, - { 0xd.0f395b84573f61dp-192L, 0x9.0d58a8d3ccd5356p-192L, 0x9.0d58a8d3ccd5357p-192L }, - { -0x1.cad34f8832df94b6p-188L, -0x1.3e08970bbbe4953cp-188L, -0x1.3e08970bbbe4953ap-188L }, - { 0xd.a82c5b229e8fe54p-4L, 0xc.e94629ca486873dp-4L, 0xc.e94629ca486873ep-4L }, - { -0xc.337e6ec5ca09cbfp-4L, -0x6.91a27c9fb5331f48p-4L, -0x6.91a27c9fb5331f4p-4L }, - { 0x5.999aa2e2c49c8778p-4L, 0x4.649a9990259a6b08p-4L, 0x4.649a9990259a6b1p-4L }, - { -0x7.b2a783da083648ep-8L, -0x5.47d116a619b453bp-8L, -0x5.47d116a619b453a8p-8L }, - { 0xe.68481349ea07669p-4L, 0xd.ddd72166e76368fp-4L, 0xd.ddd72166e76369p-4L }, - { -0x7.c2d56e73e1215768p-4L, -0x4.918e390065e28458p-4L, -0x4.918e390065e2845p-4L }, - { 0x7.cfb667a4a3914a3p-4L, 0x6.717a3878ea0e60d8p-4L, 0x6.717a3878ea0e60ep-4L }, - { -0x8.d974808af557b0ep-4L, -0x5.1855a0cd14dbe46p-4L, -0x5.1855a0cd14dbe458p-4L }, - { 0xb.439e5356c702ad8p-4L, 0xa.107c2031a79089ep-4L, 0xa.107c2031a79089fp-4L }, - { -0xe.188d98ec6dc463bp-4L, -0x7.4fe68a1b12545d8p-4L, -0x7.4fe68a1b12545d78p-4L }, - { 0xe.d87c88ea04cfc54p-4L, 0xe.7067f2e9706541cp-4L, 0xe.7067f2e9706541dp-4L }, - { -0x7.5df293fec0fa7908p-4L, -0x4.5f2a3838248134f8p-4L, -0x4.5f2a3838248134fp-4L }, - { 0xb.f31341da10838b7p-4L, 0xa.d992b6a99f3586cp-4L, 0xa.d992b6a99f3586dp-4L }, - { -0x4.94201f2127bae1d8p-4L, -0x2.e0f3cbf83592b45cp-4L, -0x2.e0f3cbf83592b458p-4L }, - { 0xf.466813a0cb58997p-4L, 0xf.02b6115e1e0a079p-4L, 0xf.02b6115e1e0a07ap-4L }, - { -0x1.b40206802faf31f8p-4L, -0x1.2356684fa89060dp-4L, -0x1.2356684fa89060cep-4L }, - { 0x5.cfe8b47a3d2bb528p-4L, 0x4.94cd1c5dccf7537p-4L, 0x4.94cd1c5dccf75378p-4L }, - { -0xd.f8e6092df0a67cdp-4L, -0x7.43f462a4ef5a1918p-4L, -0x7.43f462a4ef5a191p-4L }, - { 0xe.c5c2bbb0872eb38p-4L, 0xe.57c07f71f4fb432p-4L, 0xe.57c07f71f4fb433p-4L }, - { -0xe.4ffa3f0dccc1904p-4L, -0x7.64a9d0532f3787bp-4L, -0x7.64a9d0532f3787a8p-4L }, - { 0xd.f51b450c06fa53fp-8L, 0x9.dc151be4407a68ap-8L, 0x9.dc151be4407a68bp-8L }, - { -0x1.eb1cef301d81df08p-52L, -0x1.5469e23dccbca00ep-52L, -0x1.5469e23dccbca00cp-52L }, - { 0x8.5ae9b271c862bd1p-4L, 0x6.fa6d07dce385fccp-4L, 0x6.fa6d07dce385fcc8p-4L }, - { -0xa.8fdf30d83ecd512p-4L, -0x5.dff47c13aa88bb28p-4L, -0x5.dff47c13aa88bb2p-4L }, - { 0x1.e689240cdaba32p-4L, 0x1.5f8358e071a53472p-4L, 0x1.5f8358e071a53474p-4L }, - { -0x7.62f10575934711p-4L, -0x4.61adf89887b9a24p-4L, -0x4.61adf89887b9a238p-4L }, - { 0xf.65a3e9387da5a2fp-4L, 0xf.2cc85c945028fcap-4L, 0xf.2cc85c945028fcbp-4L }, - { -0xb.d4af71c255e18d6p-4L, -0x6.6a9610ee9e87a8cp-4L, -0x6.6a9610ee9e87a8b8p-4L }, - { 0x5.9a9d1446632f3aep-4L, 0x4.657ef16969a055cp-4L, 0x4.657ef16969a055c8p-4L }, - { -0x9.b4e978d15970db2p-4L, -0x5.7e1be34eafa75f3p-4L, -0x5.7e1be34eafa75f28p-4L }, - { 0x8.7aea261756d25f3p-4L, 0x7.1a5e60645036bcb8p-4L, 0x7.1a5e60645036bccp-4L }, - { -0xf.b5a3f9c32315f89p-4L, -0x7.e610eed3517ac508p-4L, -0x7.e610eed3517ac5p-4L }, - { 0xe.7abe135a43a13e6p-4L, 0xd.f5c385f4adc9adbp-4L, 0xd.f5c385f4adc9adcp-4L }, - { -0x7.31920eb4fe1bd628p-4L, -0x4.48b9bee7bd62fefp-4L, -0x4.48b9bee7bd62fee8p-4L }, - { 0x3.2bf2a0a669999b48p-4L, 0x2.5b4c32cabb20c8acp-4L, 0x2.5b4c32cabb20c8bp-4L }, - { -0xa.6bff2a4ca65e178p-4L, -0x5.d02bc0929aebb8c8p-4L, -0x5.d02bc0929aebb8cp-4L }, - { 0x9.8e13ef308c3a17bp-4L, 0x8.3448125bdeacbe9p-4L, 0x8.3448125bdeacbeap-4L }, - { -0x8.4ef4a64c01509a8p-4L, -0x4.d621b783f39f31a8p-4L, -0x4.d621b783f39f31ap-4L }, - { 0x3.765e093b8a1ce118p-4L, 0x2.96da7371ca2fa4f8p-4L, 0x2.96da7371ca2fa4fcp-4L }, - { -0x7.aadaa9cd4105412p-4L, -0x4.85a7f3b0c1e06018p-4L, -0x4.85a7f3b0c1e0601p-4L }, - { 0x1.a2bf59174aca4d52p-4L, 0x1.2cc8f455ff2cea6ap-4L, 0x1.2cc8f455ff2cea6cp-4L }, - { -0x5.8f5a8c1e06358d9p-4L, -0x3.6cc434f58f798508p-4L, -0x3.6cc434f58f798504p-4L }, - { 0x2.8d03b0fea7261144p-156L, 0x1.c4a296285d9fa774p-156L, 0x1.c4a296285d9fa776p-156L }, - { -0xb.4261fc576312e18p-204L, -0x7.cdea5cf7def284b8p-204L, -0x7.cdea5cf7def284bp-204L }, - { 0x4.6d7ef04080b676d8p-4L, 0x3.6217371c0fa676ep-4L, 0x3.6217371c0fa676e4p-4L }, - { -0xb.c0ae25e2a801fc9p-4L, -0x6.62443424ce0cc21p-4L, -0x6.62443424ce0cc208p-4L }, - { 0x9.33aadc610c07076p-4L, 0x7.d6339920da9a3778p-4L, 0x7.d6339920da9a378p-4L }, - { -0xb.62d8d178f4ea271p-4L, -0x6.3add5679a51923bp-4L, -0x6.3add5679a51923a8p-4L }, - { 0xb.de8017b99009994p-4L, 0xa.c1aeb0c257defb4p-4L, 0xa.c1aeb0c257defb5p-4L }, - { -0xc.d14f3f856910093p-4L, -0x6.d142a83bc366c57p-4L, -0x6.d142a83bc366c568p-4L }, - { 0x1.36027b0d8b10a26cp-4L, 0xd.c9e65e03a5bcddcp-8L, 0xd.c9e65e03a5bcdddp-8L }, - { -0xc.5d2d16de94144fcp-4L, -0x6.a29ae09167802018p-4L, -0x6.a29ae0916780201p-4L }, - { 0xd.79e031e02305347p-4L, 0xc.af83870de952b8fp-4L, 0xc.af83870de952b9p-4L }, - { -0xa.c010f18d71bc8c5p-4L, -0x5.f5024e3266fc5898p-4L, -0x5.f5024e3266fc589p-4L }, - { 0x1.9cd7b4a183ae1dcp-4L, 0x1.2864c8400d7852d2p-4L, 0x1.2864c8400d7852d4p-4L }, - { -0x1.720bafd1b399ec82p-4L, -0xf.8a14ed8ba218a08p-8L, -0xf.8a14ed8ba218a07p-8L }, - { 0x4.fac18c7be7e011e8p-4L, 0x3.da233da5c7f9843cp-4L, 0x3.da233da5c7f9844p-4L }, - { -0xe.e7cda687036f7d6p-8L, -0xa.20408f833c406efp-8L, -0xa.20408f833c406eep-8L }, - { 0x9.9c2d0517aeee533p-4L, 0x8.4314f6301d33356p-4L, 0x8.4314f6301d33357p-4L }, - { -0xe.573ec2d151cf156p-4L, -0x7.675f198c15befecp-4L, -0x7.675f198c15befeb8p-4L }, - { 0xe.947a2689d86b12ap-4L, 0xe.173cf492cdc5f07p-4L, 0xe.173cf492cdc5f08p-4L }, - { -0x5.fee8120e5e04be2p-4L, -0x3.a8f7bcd02665b4bcp-4L, -0x3.a8f7bcd02665b4b8p-4L }, - { 0x3.f3364f18a79b3b3cp-4L, 0x2.fc7677f28287f59cp-4L, 0x2.fc7677f28287f5ap-4L }, - { -0xd.acb73d1f464055dp-4L, -0x7.26f0d62a8825fadp-4L, -0x7.26f0d62a8825fac8p-4L }, - { 0x3.72e8ef378d42c014p-136L, 0x2.63fc8bc98f409418p-136L, 0x2.63fc8bc98f40941cp-136L }, - { -0xf.f7a6695a9469f6bp-64L, -0xb.1157d5a78619d6ap-64L, -0xb.1157d5a78619d69p-64L }, - { 0xa.ed0ce5b49afa192p-4L, 0x9.af72dd5f9d309c8p-4L, 0x9.af72dd5f9d309c9p-4L }, - { -0x8.92179a4e3bb69e3p-4L, -0x4.f66ab2d67cb085b8p-4L, -0x4.f66ab2d67cb085bp-4L }, - { 0xb.ed688726df9befap-4L, 0xa.d2fc0f03bbaa3eap-4L, 0xa.d2fc0f03bbaa3ebp-4L }, - { -0x9.3f55bdfddb49b2bp-4L, -0x5.480d56cfe248124p-4L, -0x5.480d56cfe2481238p-4L }, - { 0x7.2ec3f10b51218bfp-4L, 0x5.d71a7e29e3375c08p-4L, 0x5.d71a7e29e3375c1p-4L }, - { -0x7.f78628cdda70a8d8p-8L, -0x5.768d49335e93bc48p-8L, -0x5.768d49335e93bc4p-8L }, - { 0x6.5dbff56825b7dbb8p-4L, 0x5.14cc73903ffab37p-4L, 0x5.14cc73903ffab378p-4L }, - { -0xa.e7a98283fc10855p-4L, -0x6.062dbfc6c13a0cp-4L, -0x6.062dbfc6c13a0bf8p-4L }, - { 0xc.2509016f44e196ap-4L, 0xb.13ee99066e4da51p-4L, 0xb.13ee99066e4da52p-4L }, - { -0x7.861514480ac9199p-4L, -0x4.7350865eeea1ec4p-4L, -0x4.7350865eeea1ec38p-4L }, - { 0xf.17da41cf884346bp-4L, 0xe.c46a3230752f01ep-4L, 0xe.c46a3230752f01fp-4L }, - { -0xc.62d7c253621dcf7p-4L, -0x6.a4e721c955ab92bp-4L, -0x6.a4e721c955ab92a8p-4L }, - { 0x9.845c3e40ed6ad83p-8L, 0x6.aeb3e091a9ca62a8p-8L, 0x6.aeb3e091a9ca62bp-8L }, - { -0xd.68fda9eec5a66c2p-4L, -0x7.0cd5054a8559068p-4L, -0x7.0cd5054a85590678p-4L }, - { 0x8.18f925371b61292p-4L, 0x6.b926981ecb341cc8p-4L, 0x6.b926981ecb341cdp-4L }, - { -0x1.57f7c0849ebb346p-4L, -0xe.79d2f43931febcep-8L, -0xe.79d2f43931febcdp-8L }, - { 0xa.e4ab5281b09d79fp-4L, 0x9.a6211af13affacbp-4L, 0x9.a6211af13affaccp-4L }, - { -0x7.1174b12c13aaf4e8p-4L, -0x4.38619acc6b16c48p-4L, -0x4.38619acc6b16c478p-4L }, - { 0xe.880fef5908d95bdp-4L, 0xe.07123c37decbd2bp-4L, 0xe.07123c37decbd2cp-4L }, - { -0x7.609718a06f5f08ap-4L, -0x4.607ef189a568c048p-4L, -0x4.607ef189a568c04p-4L }, - { 0x6.e2bdbcf507ec4778p-80L, 0x4.c5d6cd2d0554bd38p-80L, 0x4.c5d6cd2d0554bd4p-80L }, - { -0xa.20544abb2f768b5p-172L, -0x7.04dd9fe9c3d0ca4p-172L, -0x7.04dd9fe9c3d0ca38p-172L }, - { 0x6.14aea1523dfe3aa8p-4L, 0x4.d27a84995c90398p-4L, 0x4.d27a84995c903988p-4L }, - { -0xc.97a55c9c85f26f9p-4L, -0x6.ba359004a30e41c8p-4L, -0x6.ba359004a30e41cp-4L }, - { 0x8.680ab975830d106p-4L, 0x7.078281205f71db5p-4L, 0x7.078281205f71db58p-4L }, - { -0x3.7b5dd7324be888fcp-4L, -0x2.3d81bd11bf2f6c4cp-4L, -0x2.3d81bd11bf2f6c48p-4L }, - { 0xd.ff0ee4cab1a5c92p-4L, 0xd.56e662606151cc8p-4L, 0xd.56e662606151cc9p-4L }, - { -0xe.008f2e366ac05f5p-4L, -0x7.46d9fe3c6c7508bp-4L, -0x7.46d9fe3c6c7508a8p-4L }, - { 0xa.b9de710cc3240eap-4L, 0x9.76be49caa91f1f7p-4L, 0x9.76be49caa91f1f8p-4L }, - { -0xd.b8496a7f5a40118p-4L, -0x7.2b5f2502bf92f008p-4L, -0x7.2b5f2502bf92fp-4L }, - { 0xb.c810c87ed94addfp-4L, 0xa.a7ba02e0d048d4bp-4L, 0xa.a7ba02e0d048d4cp-4L }, - { -0x6.0a47a8ab4ac89cd8p-4L, -0x3.af0abdfd7366387cp-4L, -0x3.af0abdfd73663878p-4L }, - { 0xd.694a760f35e0c5cp-4L, 0xc.9aeeb6a65c8040ap-4L, 0xc.9aeeb6a65c8040bp-4L }, - { -0x1.02b5df71e26e7eeep-4L, -0xa.f74a44b0786e5d7p-8L, -0xa.f74a44b0786e5d6p-8L }, - { 0x8.2d4ad8d9b79c26ep-4L, 0x6.cd300350fa1084ep-4L, 0x6.cd300350fa1084e8p-4L }, - { -0x5.d8b77fd6db5f46fp-4L, -0x3.947c5ee25dae93cp-4L, -0x3.947c5ee25dae93bcp-4L }, - { 0x3.b2d5aa2bd4f226c8p-4L, 0x2.c7cc7c21062df578p-4L, 0x2.c7cc7c21062df57cp-4L }, - { -0x1.3d87d39ca205f226p-4L, -0xd.6495ea183c77a34p-8L, -0xd.6495ea183c77a33p-8L }, - { 0x7.58b591427632828p-4L, 0x5.feee1c31635efc6p-4L, 0x5.feee1c31635efc68p-4L }, - { -0xd.51cbb799b3f3a26p-4L, -0x7.03d23697240275b8p-4L, -0x7.03d23697240275bp-4L }, - { 0x9.0e54bb10a5b7912p-4L, 0x7.afc489158099261p-4L, 0x7.afc4891580992618p-4L }, - { -0xa.7e81ca95f58d507p-4L, -0x5.d853b00c0424b748p-4L, -0x5.d853b00c0424b74p-4L }, - { 0xa.38c6b26a97ad959p-144L, 0x7.15cf9ed628b7443p-144L, 0x7.15cf9ed628b74438p-144L }, - { -0xd.8dbb3097e168af8p-16L, -0x9.64dcae1a44ce08fp-16L, -0x9.64dcae1a44ce08ep-16L }, - { 0xf.05da5fd59fc565bp-4L, 0xe.ac75be21fa0a721p-4L, 0xe.ac75be21fa0a722p-4L }, - { -0xd.dd9a1c0c442c4c6p-4L, -0x7.399a1163598e674p-4L, -0x7.399a1163598e6738p-4L }, - { 0x4.61b51c01df55d6d8p-4L, 0x3.5833a282f0757d38p-4L, 0x3.5833a282f0757d3cp-4L }, - { -0xb.dce6fd9bad9f495p-4L, -0x6.6dfecf316daaa2b8p-4L, -0x6.6dfecf316daaa2bp-4L }, - { 0xa.b6f22a1b9f2939fp-4L, 0x9.73850a513137669p-4L, 0x9.73850a51313766ap-4L }, - { -0x3.4bb35afb05788e3p-4L, -0x2.20fa7ab319293c2cp-4L, -0x2.20fa7ab319293c28p-4L }, - { 0xd.0db3afda3c5f8cp-4L, 0xc.2a4edf1f8e608e3p-4L, 0xc.2a4edf1f8e608e4p-4L }, - { -0x2.1ce57b45214ebd74p-4L, -0x1.6646119faf2579e4p-4L, -0x1.6646119faf2579e2p-4L }, - { 0x5.067f9f48fc5b234p-8L, 0x3.81d3c5994dfa29ep-8L, 0x3.81d3c5994dfa29e4p-8L }, - { -0xb.a04244a598be88fp-4L, -0x6.54b9128406b6e57p-4L, -0x6.54b9128406b6e568p-4L }, - { 0xf.d97f1711de15f9cp-4L, 0xf.cacbd7b24bfa344p-4L, 0xf.cacbd7b24bfa345p-4L }, - { -0xf.493b2b477feaaf9p-4L, -0x7.bfaad9fbab559b1p-4L, -0x7.bfaad9fbab559b08p-4L }, - { 0xc.deaf7691740cdefp-8L, 0x9.13f529a0032aecap-8L, 0x9.13f529a0032aecbp-8L }, - { -0xa.59b5d478c821a2ep-4L, -0x5.c816a0d158b46128p-4L, -0x5.c816a0d158b4612p-4L }, - { 0xd.1b186c2e3417901p-4L, 0xc.3aab3f3a165b5b1p-4L, 0xc.3aab3f3a165b5b2p-4L }, - { -0xf.14939428966efa8p-4L, -0x7.acc2e6e3a1c40bfp-4L, -0x7.acc2e6e3a1c40be8p-4L }, - { 0xa.548931dd5b08516p-4L, 0x9.07e9820c45dc918p-4L, 0x9.07e9820c45dc919p-4L }, - { -0x1.86c3057b9088fe1cp-4L, -0x1.06181e6e8d7c4ee6p-4L, -0x1.06181e6e8d7c4ee4p-4L }, - { 0x8.de5082bfa47b272p-8L, 0x6.38b52f74fd4fac9p-8L, 0x6.38b52f74fd4fac98p-8L }, - { -0x6.381df51cf6ba1e58p-4L, -0x3.c7677b23d838f2c4p-4L, -0x3.c7677b23d838f2cp-4L }, - { 0x2.f43f9bb64395d398p-28L, 0x2.0c3105ebb2d3ec1p-28L, 0x2.0c3105ebb2d3ec14p-28L }, - { -0x1.7d1826b58589517p-188L, -0x1.08278b32d446a3dap-188L, -0x1.08278b32d446a3d8p-188L }, - { 0x3.24bd5453a5d96c38p-4L, 0x2.5591a327002dbbfp-4L, 0x2.5591a327002dbbf4p-4L }, - { -0xd.ac66274a591f9a9p-4L, -0x7.26d1c15c81b1be3p-4L, -0x7.26d1c15c81b1be28p-4L }, - { 0x7.4bbb894be77050dp-4L, 0x5.f29408389bbe66ep-4L, 0x5.f29408389bbe66e8p-4L }, - { -0xa.eacc82e14c1610fp-4L, -0x6.0788b0f7dc794f7p-4L, -0x6.0788b0f7dc794f68p-4L }, - { 0x2.a982ac56625aefc4p-4L, 0x1.f4b47ebd7795a254p-4L, 0x1.f4b47ebd7795a256p-4L }, - { -0x8.056940c538fa279p-4L, -0x4.b257711af2be1e78p-4L, -0x4.b257711af2be1e7p-4L }, - { 0x1.66b64b9c9f79a1dep-4L, 0x1.00578a1c0c673a1p-4L, 0x1.00578a1c0c673a12p-4L }, - { -0x3.26b75fa52c7ce30cp-4L, -0x2.0aaf1c1238c99944p-4L, -0x2.0aaf1c1238c9994p-4L }, - { 0x9.da5604fb75e8d87p-4L, 0x8.84c2f5daaacf75ep-4L, 0x8.84c2f5daaacf75fp-4L }, - { -0x8.f39b1339c38973dp-4L, -0x5.24a94b90f03e7ed8p-4L, -0x5.24a94b90f03e7edp-4L }, - { 0x7.677b36d2e1d48358p-4L, 0x6.0d06229c56a97f4p-4L, 0x6.0d06229c56a97f48p-4L }, - { -0xa.996804efaa5460cp-4L, -0x5.e4224415b8782278p-4L, -0x5.e4224415b878227p-4L }, - { 0x6.b6c06e4a29c88afp-4L, 0x5.66b27094b245b1ep-4L, 0x5.66b27094b245b1e8p-4L }, - { -0x5.a5149fe9b18171c8p-4L, -0x3.7894bad1006fb798p-4L, -0x3.7894bad1006fb794p-4L }, - { 0x5.375a31264862647p-4L, 0x4.0e852a933247c008p-4L, 0x4.0e852a933247c01p-4L }, - { -0xc.55651fd1cbee3d4p-4L, -0x6.9f72345b02eab28p-4L, -0x6.9f72345b02eab278p-4L }, - { 0xe.006deb92f93d672p-4L, 0xd.58a49a5d8de28c4p-4L, 0xd.58a49a5d8de28c5p-4L }, - { -0xa.6871090121d471bp-4L, -0x5.ce99fb28aafa5bb8p-4L, -0x5.ce99fb28aafa5bbp-4L }, - { 0xc.8ed445e1ea26da6p-4L, 0xb.9126f62f86bcb47p-4L, 0xb.9126f62f86bcb48p-4L }, - { -0x3.70640030d409ab74p-4L, -0x2.36f53ff3b132cba8p-4L, -0x2.36f53ff3b132cba4p-4L }, - { 0x2.219473696b04364cp-96L, 0x1.7a2acafbc3adc14ep-96L, 0x1.7a2acafbc3adc15p-96L }, - { -0xd.bdc3902e400dcddp-144L, -0x9.865401201b95f7ap-144L, -0x9.865401201b95f79p-144L }, - { 0xb.b53f28201a854efp-4L, 0xa.9207b77bb750cf7p-4L, 0xa.9207b77bb750cf8p-4L }, - { -0x4.28b1a78cc7055bd8p-4L, -0x2.a3536d42907d291p-4L, -0x2.a3536d42907d290cp-4L }, - { 0xd.e2cee7a54e7c7dfp-4L, 0xd.331435f3041bf4fp-4L, 0xd.331435f3041bf5p-4L }, - { -0x9.3f6896a8070ab3ep-4L, -0x5.4816171c316ed77p-4L, -0x5.4816171c316ed768p-4L }, - { 0x1.a1524a334652c37cp-4L, 0x1.2bb95dd5b9658e26p-4L, 0x1.2bb95dd5b9658e28p-4L }, - { -0x1.9b7f6344a4875e14p-4L, -0x1.13861edcadba3e08p-4L, -0x1.13861edcadba3e06p-4L }, - { 0xb.4660bc20f1141f9p-4L, 0xa.1399f4f27c33975p-4L, 0xa.1399f4f27c33976p-4L }, - { -0xd.9888197bcafba2ap-4L, -0x7.1f30db722ee63d78p-4L, -0x7.1f30db722ee63d7p-4L }, - { 0xf.3adad3101e81209p-4L, 0xe.f33515340a557e4p-4L, 0xe.f33515340a557e5p-4L }, - { -0xa.79ea74b25ad8a16p-4L, -0x5.d64e6bad7c9fffc8p-4L, -0x5.d64e6bad7c9fffcp-4L }, - { 0xd.4d87683a39ac568p-4L, 0xc.789c1f6e5dcac31p-4L, 0xc.789c1f6e5dcac32p-4L }, - { -0xd.0f2848388d6bd4fp-4L, -0x6.e9bc44c0f7734168p-4L, -0x6.e9bc44c0f773416p-4L }, - { 0x5.d9fb99a27648b5d8p-4L, 0x4.9dca7407214af058p-4L, 0x4.9dca7407214af06p-4L }, - { -0x1.705dc2d9924977d6p-4L, -0xf.7895af9cd8410b4p-8L, -0xf.7895af9cd8410b3p-8L }, - { 0xe.de1ad3b0df8a929p-4L, 0xe.77d17cd52544381p-4L, 0xe.77d17cd52544382p-4L }, - { -0xe.4bc9f399afa1199p-4L, -0x7.6319db0e3314bc98p-4L, -0x7.6319db0e3314bc9p-4L }, - { 0x9.4bc88b56990e957p-4L, 0x7.ef27dce522664078p-4L, 0x7.ef27dce52266408p-4L }, - { -0xe.2a8337406c02664p-4L, -0x7.56a65648e9cbee38p-4L, -0x7.56a65648e9cbee3p-4L }, -}; - -int check_equal(long double res, long double expected) -{ - if (res != expected) { - return 0; - } - return (__builtin_copysignl(1.0L, res) == - __builtin_copysignl(1.0L, expected)); -} - -int main(void) -{ - int ret = 0; - int i; - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - long double ld_res; - __asm__ volatile ("f2xm1" : "=t" (ld_res) : "0" (tests[i].arg)); - if (!check_equal(ld_res, tests[i].down) && - !check_equal(ld_res, tests[i].up)) { - printf("FAIL: f2xm1 %La, expected %La or %La, got %La\n", - tests[i].arg, tests[i].down, tests[i].up, ld_res); - ret = 1; - } - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fbstp.c b/tests/tcg/i386/test-i386-fbstp.c deleted file mode 100644 index 73bf56b9dc3f..000000000000 --- a/tests/tcg/i386/test-i386-fbstp.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Test fbstp instruction. */ - -#include -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; -volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; -volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; -volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; - -int main(void) -{ - int ret = 0; - unsigned char out[10]; - memset(out, 0xfe, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-0.0L) : "st"); - out[9] &= 0x80; - if (memcmp(out, "\0\0\0\0\0\0\0\0\0\x80", sizeof out) != 0) { - printf("FAIL: fbstp -0\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-0.1L) : "st"); - out[9] &= 0x80; - if (memcmp(out, "\0\0\0\0\0\0\0\0\0\x80", sizeof out) != 0) { - printf("FAIL: fbstp -0.1\n"); - ret = 1; - } - memset(out, 0x1f, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-987654321987654321.0L) : - "st"); - out[9] &= 0x80; - if (memcmp(out, "\x21\x43\x65\x87\x19\x32\x54\x76\x98\x80", - sizeof out) != 0) { - printf("FAIL: fbstp -987654321987654321\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (999999999999999999.5L) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp 999999999999999999.5\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (1000000000000000000.0L) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp 1000000000000000000\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (1e30L) : "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp 1e30\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-999999999999999999.5L) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp -999999999999999999.5\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-1000000000000000000.0L) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp -1000000000000000000\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-1e30L) : "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp -1e30\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (__builtin_infl()) : "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp inf\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-__builtin_infl()) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp -inf\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (__builtin_nanl("")) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp nan\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-__builtin_nanl("")) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp -nan\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_1.ld) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp invalid 1\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_2.ld) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp invalid 2\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_3.ld) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp invalid 3\n"); - ret = 1; - } - memset(out, 0x12, sizeof out); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_4.ld) : - "st"); - if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { - printf("FAIL: fbstp invalid 4\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fisttp.c b/tests/tcg/i386/test-i386-fisttp.c deleted file mode 100644 index 16af59a7749f..000000000000 --- a/tests/tcg/i386/test-i386-fisttp.c +++ /dev/null @@ -1,100 +0,0 @@ -/* Test fisttpl and fisttpll instructions. */ - -#include -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; - -int main(void) -{ - int ret = 0; - int32_t res_32; - int64_t res_64; - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (0x1p100L) : "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl 0x1p100\n"); - ret = 1; - } - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-0x1p100L) : "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl -0x1p100\n"); - ret = 1; - } - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (__builtin_infl()) : - "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl inf\n"); - ret = 1; - } - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-__builtin_infl()) : - "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl -inf\n"); - ret = 1; - } - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (__builtin_nanl("")) : - "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl nan\n"); - ret = 1; - } - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : - "t" (-__builtin_nanl("")) : "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl -nan\n"); - ret = 1; - } - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) : - "st"); - if (res_32 != INT32_MIN) { - printf("FAIL: fisttpl invalid\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (0x1p100L) : "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll 0x1p100\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-0x1p100L) : "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll -0x1p100\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (__builtin_infl()) : - "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll inf\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-__builtin_infl()) : - "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll -inf\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : - "t" (__builtin_nanl("")) : "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll nan\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : - "t" (-__builtin_nanl("")) : "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll -nan\n"); - ret = 1; - } - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) : - "st"); - if (res_64 != INT64_MIN) { - printf("FAIL: fisttpll invalid\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fldcst.c b/tests/tcg/i386/test-i386-fldcst.c deleted file mode 100644 index e635432ccfdb..000000000000 --- a/tests/tcg/i386/test-i386-fldcst.c +++ /dev/null @@ -1,199 +0,0 @@ -/* Test instructions loading floating-point constants. */ - -#include -#include - -volatile long double ld_res; - -int main(void) -{ - short cw; - int ret = 0; - - /* Round to nearest. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x000; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2t" : "=t" (ld_res)); - if (ld_res != 0x3.5269e12f346e2bf8p+0L) { - printf("FAIL: fldl2t N\n"); - ret = 1; - } - /* Round downward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x400; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2t" : "=t" (ld_res)); - if (ld_res != 0x3.5269e12f346e2bf8p+0L) { - printf("FAIL: fldl2t D\n"); - ret = 1; - } - /* Round toward zero. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0xc00; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2t" : "=t" (ld_res)); - if (ld_res != 0x3.5269e12f346e2bf8p+0L) { - printf("FAIL: fldl2t Z\n"); - ret = 1; - } - /* Round upward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x800; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2t" : "=t" (ld_res)); - if (ld_res != 0x3.5269e12f346e2bfcp+0L) { - printf("FAIL: fldl2t U\n"); - ret = 1; - } - - /* Round to nearest. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x000; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2e" : "=t" (ld_res)); - if (ld_res != 0x1.71547652b82fe178p+0L) { - printf("FAIL: fldl2e N\n"); - ret = 1; - } - /* Round downward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x400; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2e" : "=t" (ld_res)); - if (ld_res != 0x1.71547652b82fe176p+0L) { - printf("FAIL: fldl2e D\n"); - ret = 1; - } - /* Round toward zero. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0xc00; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2e" : "=t" (ld_res)); - if (ld_res != 0x1.71547652b82fe176p+0L) { - printf("FAIL: fldl2e Z\n"); - ret = 1; - } - /* Round upward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x800; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldl2e" : "=t" (ld_res)); - if (ld_res != 0x1.71547652b82fe178p+0L) { - printf("FAIL: fldl2e U\n"); - ret = 1; - } - - /* Round to nearest. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x000; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldpi" : "=t" (ld_res)); - if (ld_res != 0x3.243f6a8885a308d4p+0L) { - printf("FAIL: fldpi N\n"); - ret = 1; - } - /* Round downward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x400; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldpi" : "=t" (ld_res)); - if (ld_res != 0x3.243f6a8885a308dp+0L) { - printf("FAIL: fldpi D\n"); - ret = 1; - } - /* Round toward zero. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0xc00; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldpi" : "=t" (ld_res)); - if (ld_res != 0x3.243f6a8885a308dp+0L) { - printf("FAIL: fldpi Z\n"); - ret = 1; - } - /* Round upward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x800; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldpi" : "=t" (ld_res)); - if (ld_res != 0x3.243f6a8885a308d4p+0L) { - printf("FAIL: fldpi U\n"); - ret = 1; - } - - /* Round to nearest. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x000; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldlg2" : "=t" (ld_res)); - if (ld_res != 0x4.d104d427de7fbcc8p-4L) { - printf("FAIL: fldlg2 N\n"); - ret = 1; - } - /* Round downward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x400; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldlg2" : "=t" (ld_res)); - if (ld_res != 0x4.d104d427de7fbccp-4L) { - printf("FAIL: fldlg2 D\n"); - ret = 1; - } - /* Round toward zero. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0xc00; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldlg2" : "=t" (ld_res)); - if (ld_res != 0x4.d104d427de7fbccp-4L) { - printf("FAIL: fldlg2 Z\n"); - ret = 1; - } - /* Round upward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x800; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldlg2" : "=t" (ld_res)); - if (ld_res != 0x4.d104d427de7fbcc8p-4L) { - printf("FAIL: fldlg2 U\n"); - ret = 1; - } - - /* Round to nearest. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x000; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldln2" : "=t" (ld_res)); - if (ld_res != 0xb.17217f7d1cf79acp-4L) { - printf("FAIL: fldln2 N\n"); - ret = 1; - } - /* Round downward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x400; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldln2" : "=t" (ld_res)); - if (ld_res != 0xb.17217f7d1cf79abp-4L) { - printf("FAIL: fldln2 D\n"); - ret = 1; - } - /* Round toward zero. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0xc00; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldln2" : "=t" (ld_res)); - if (ld_res != 0xb.17217f7d1cf79abp-4L) { - printf("FAIL: fldln2 Z\n"); - ret = 1; - } - /* Round upward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x800; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fldln2" : "=t" (ld_res)); - if (ld_res != 0xb.17217f7d1cf79acp-4L) { - printf("FAIL: fldln2 U\n"); - ret = 1; - } - - return ret; -} diff --git a/tests/tcg/i386/test-i386-fp-exceptions.c b/tests/tcg/i386/test-i386-fp-exceptions.c deleted file mode 100644 index dfb7117c1789..000000000000 --- a/tests/tcg/i386/test-i386-fp-exceptions.c +++ /dev/null @@ -1,831 +0,0 @@ -/* Test floating-point exceptions. */ - -#include -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile float f_res; -volatile double d_res; -volatile long double ld_res; -volatile long double ld_res2; - -volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; -volatile float f_snan = __builtin_nansf(""); -volatile double d_snan = __builtin_nans(""); -volatile long double ld_third = 1.0L / 3.0L; -volatile long double ld_snan = __builtin_nansl(""); -volatile long double ld_nan = __builtin_nanl(""); -volatile long double ld_inf = __builtin_infl(); -volatile long double ld_ninf = -__builtin_infl(); -volatile long double ld_one = 1.0L; -volatile long double ld_zero = 0.0L; -volatile long double ld_nzero = -0.0L; -volatile long double ld_min = LDBL_MIN; -volatile long double ld_max = LDBL_MAX; -volatile long double ld_nmax = -LDBL_MAX; - -#define IE (1 << 0) -#define ZE (1 << 2) -#define OE (1 << 3) -#define UE (1 << 4) -#define PE (1 << 5) -#define EXC (IE | ZE | OE | UE | PE) - -int main(void) -{ - short sw; - unsigned char out[10]; - int ret = 0; - int16_t res_16; - int32_t res_32; - int64_t res_64; - - __asm__ volatile ("fnclex"); - ld_res = f_snan; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: widen float snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = d_snan; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: widen double snan\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - f_res = ld_min; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (UE | PE)) { - printf("FAIL: narrow float underflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - d_res = ld_min; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (UE | PE)) { - printf("FAIL: narrow double underflow\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - f_res = ld_max; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: narrow float overflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - d_res = ld_max; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: narrow double overflow\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - f_res = ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: narrow float inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - d_res = ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: narrow double inexact\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - f_res = ld_snan; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: narrow float snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - d_res = ld_snan; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: narrow double snan\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - f_res = ld_invalid_1.ld; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: narrow float invalid\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - d_res = ld_invalid_1.ld; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: narrow double invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("frndint" : "=t" (ld_res) : "0" (ld_min)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: frndint min\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("frndint" : "=t" (ld_res) : "0" (ld_snan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: frndint snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("frndint" : "=t" (ld_res) : "0" (ld_invalid_1.ld)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: frndint invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fcom" : : "t" (ld_nan), "u" (ld_zero)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fcom nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fucom" : : "t" (ld_nan), "u" (ld_zero)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: fucom nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fucom" : : "t" (ld_snan), "u" (ld_zero)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fucom snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fucom" : : "t" (1.0L), "u" (ld_invalid_1.ld)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fucom invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - ld_res = ld_max + ld_max; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: add overflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_max + ld_min; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: add inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_inf + ld_ninf; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: add inf -inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_snan + ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: add snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_third + ld_invalid_1.ld; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: add invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - ld_res = ld_max - ld_nmax; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: sub overflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_max - ld_min; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: sub inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_inf - ld_inf; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: sub inf inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_snan - ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: sub snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_third - ld_invalid_1.ld; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: sub invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - ld_res = ld_max * ld_max; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: mul overflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_third * ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: mul inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_min * ld_min; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (UE | PE)) { - printf("FAIL: mul underflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_inf * ld_zero; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: mul inf 0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_snan * ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: mul snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_third * ld_invalid_1.ld; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: mul invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - ld_res = ld_max / ld_min; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: div overflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_one / ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: div inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_min / ld_max; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (UE | PE)) { - printf("FAIL: div underflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_one / ld_zero; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != ZE) { - printf("FAIL: div 1 0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_inf / ld_zero; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: div inf 0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_nan / ld_zero; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: div nan 0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_zero / ld_zero; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: div 0 0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_inf / ld_inf; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: div inf inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_snan / ld_third; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: div snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - ld_res = ld_third / ld_invalid_1.ld; - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: div invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_max)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fsqrt inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_nmax)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fsqrt -max\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_ninf)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fsqrt -inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_snan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fsqrt snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_invalid_1.ld)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fsqrt invalid\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_nzero)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: fsqrt -0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (-__builtin_nanl(""))); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: fsqrt -nan\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (1.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fistp inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (32767.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistp 32767.5\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (-32768.51L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistp -32768.51\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistp nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (ld_invalid_1.ld) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistp invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (1.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fistpl inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (2147483647.5L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpl 2147483647.5\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (-2147483648.51L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpl -2147483648.51\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpl nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpl invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (1.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fistpll inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (0x1p63) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpll 0x1p63\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (-0x1.1p63L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpll -0x1.1p63\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpll nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fistpll invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (1.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fisttp inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (32768.0L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttp 32768\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (32768.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttp 32768.5\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (-32769.0L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttp -32769\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (-32769.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttp -32769.5\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttp nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (ld_invalid_1.ld) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttp invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (1.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fisttpl inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (2147483648.0L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpl 2147483648\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-2147483649.0L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpl -2147483649\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpl nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpl invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (1.5L) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fisttpll inexact\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (0x1p63) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpll 0x1p63\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-0x1.1p63L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpll -0x1.1p63\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpll nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fisttpll invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : - "0" (ld_zero)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != ZE) { - printf("FAIL: fxtract 0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : - "0" (ld_nzero)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != ZE) { - printf("FAIL: fxtract -0\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : - "0" (ld_inf)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: fxtract inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : - "0" (ld_nan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != 0) { - printf("FAIL: fxtract nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : - "0" (ld_snan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fxtract snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : - "0" (ld_invalid_1.ld)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fxtract invalid\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_min), "u" (ld_max)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (OE | PE)) { - printf("FAIL: fscale overflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_max), "u" (ld_nmax)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != (UE | PE)) { - printf("FAIL: fscale underflow\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_zero), "u" (ld_inf)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fscale 0 inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_inf), "u" (ld_ninf)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fscale inf -inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_one), "u" (ld_snan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fscale 1 snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_snan), "u" (ld_nan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fscale snan nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (ld_invalid_1.ld), "u" (ld_one)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fscale invalid 1\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (ld_invalid_1.ld), "u" (ld_nan)); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fscale invalid nan\n"); - ret = 1; - } - - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (1.5L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != PE) { - printf("FAIL: fbstp 1.5\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (999999999999999999.5L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fbstp 999999999999999999.5\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-1000000000000000000.0L) : - "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fbstp -1000000000000000000\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_inf) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fbstp inf\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_nan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fbstp nan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_snan) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fbstp snan\n"); - ret = 1; - } - __asm__ volatile ("fnclex"); - __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_1.ld) : "st"); - __asm__ volatile ("fnstsw" : "=a" (sw)); - if ((sw & EXC) != IE) { - printf("FAIL: fbstp invalid\n"); - ret = 1; - } - - return ret; -} diff --git a/tests/tcg/i386/test-i386-fpatan.c b/tests/tcg/i386/test-i386-fpatan.c deleted file mode 100644 index 7f1f9853defd..000000000000 --- a/tests/tcg/i386/test-i386-fpatan.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* Test fpatan instruction. */ - -#include - -struct test { - long double arg0, arg1, down, up; -}; - -const struct test tests[] = { - { -__builtin_infl(), -__builtin_infl(), -0x2.5b2f8fe6643a46ap+0L, -0x2.5b2f8fe6643a469cp+0L }, - { -__builtin_infl(), -1.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -__builtin_infl(), -0.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -__builtin_infl(), 0.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -__builtin_infl(), 1.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -__builtin_infl(), __builtin_infl(), 0x2.5b2f8fe6643a469cp+0L, 0x2.5b2f8fe6643a46ap+0L }, - { -1.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -1.0L, -0.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -1.0L, 0.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -1.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0.0L, -1.0L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0.0L, -0.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0.0L, 0.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0.0L, 1.0L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0.0L, -1.0L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0.0L, -0.0L, -0.0L, -0.0L }, - { 0.0L, 0.0L, 0.0L, 0.0L }, - { 0.0L, 1.0L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 1.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 1.0L, -0.0L, -0.0L, -0.0L }, - { 1.0L, 0.0L, 0.0L, 0.0L }, - { 1.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { __builtin_infl(), -__builtin_infl(), -0xc.90fdaa22168c235p-4L, -0xc.90fdaa22168c234p-4L }, - { __builtin_infl(), -1.0L, -0.0L, -0.0L }, - { __builtin_infl(), -0.0L, -0.0L, -0.0L }, - { __builtin_infl(), 0.0L, 0.0L, 0.0L }, - { __builtin_infl(), 1.0L, 0.0L, 0.0L }, - { __builtin_infl(), __builtin_infl(), 0xc.90fdaa22168c234p-4L, 0xc.90fdaa22168c235p-4L }, - /* Randomly generated tests. */ - { -0x4.1481697ac693aa6p-4L, 0xd.84a873b14b9c0e2p-4L, 0x1.dd2a294db671468ep+0L, 0x1.dd2a294db671469p+0L }, - { 0x5.51ee0c58f7fbf45p-4L, -0x3.a11abadbd605d354p-4L, -0x9.942ec5a1e6d706ap-4L, -0x9.942ec5a1e6d7069p-4L }, - { -0x5.4459f2ac77bb0978p-4L, -0xb.79bece734a62216p-4L, -0x2.004758bce8469e14p+0L, -0x2.004758bce8469e1p+0L }, - { 0x2.aad23e7bdccbd71p+352L, 0xb.8204e63359a46e6p-4L, 0x4.5081cdc076384b38p-356L, 0x4.5081cdc076384b4p-356L }, - { 0x1.b8e650cae035d26ap+72L, -0x1.6296e8ff499827a2p-4L, -0xc.de2b934dfff2be5p-80L, -0xc.de2b934dfff2be4p-80L }, - { -0x8.3e49377820195c8p-4L, 0x7.ece8699d62a9f76p-4L, 0x2.6037dbebdbb2fd48p+0L, 0x2.6037dbebdbb2fd4cp+0L }, - { -0x4.b875c0342c9f86b8p-4L, 0xe.a37e0fa859e499cp-4L, 0x1.e1fb3a96e1e2071p+0L, 0x1.e1fb3a96e1e20712p+0L }, - { -0x7.23210d9474f0715p-4L, 0xb.755e74862e61e2bp+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.2330923899aae43p-76L, 0xa.9a331b76f8ece94p+16L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x2.c18975d92e49e91p+72L, 0xa.d41581f0036d233p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x4.84a87d8107c5f408p-4L, -0x4.69649643801fe8p-5424L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x2.72f96b27827d2054p-4L, 0x8.34634eae18e60c5p-4L, 0x1.47dcc6c860bbdaf8p+0L, 0x1.47dcc6c860bbdafap+0L }, - { 0x5.ed9ff299ffca609p-4L, 0x1.f03bcdeac4b1ed28p-4L, 0x5.0e6d2d3ad020af98p-4L, 0x5.0e6d2d3ad020afap-4L }, - { -0x1.838e5531eee660a2p+100L, -0x9.6eacf3012c77e7p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x4.962ce97c4afbc1f8p-4L, -0xa.a7735b993f17f55p-4L, -0x1.fa318fa84cd3d3c6p+0L, -0x1.fa318fa84cd3d3c4p+0L }, - { 0x5.155f76560f08fccp-4L, 0xd.32a453289bd47b3p-4L, 0x1.340095b1ff56c6e8p+0L, 0x1.340095b1ff56c6eap+0L }, - { 0xa.9942e7418052b4bp-4L, -0x5.4f4efad2aff4f76p-4L, -0x7.6e5556d70c57ac08p-4L, -0x7.6e5556d70c57acp-4L }, - { 0x3.c9e289d962998608p-4L, 0x3.e614ab44b3c3b858p+88L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.51f8f83e548cc4d8p-32L, -0x8.a1d9201d5f09ad6p-4L, -0x1.921fb541d06114b2p+0L, -0x1.921fb541d06114bp+0L }, - { 0x7.5b8ee6778ad1d64p-4L, 0x9.d20d0f7fc98548p-4L, 0xe.d84441fe9061ea4p-4L, 0xe.d84441fe9061ea5p-4L }, - { 0x2.f89af40f713046ap+44L, -0x5.d981a42b6b7a36fp-4L, -0x1.f805944fa81791f6p-48L, -0x1.f805944fa81791f4p-48L }, - { 0x1.5dbffc603b717c16p-12056L, 0x4.5a026d37f55f1d18p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x7.82c193b48128193p-4L, -0xd.2d0fe1cd05a87f4p-4L, -0x2.16c178d148863734p+0L, -0x2.16c178d14886373p+0L }, - { 0x1.785253e54547193cp-128L, -0x4.51babb72810e518p-104L, -0x1.921fb4ed226f9e3ep+0L, -0x1.921fb4ed226f9e3cp+0L }, - { 0xb.638d8454a685474p-4L, -0x5.cf6274f9336e7248p+88L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xe.4b7a4c83290855cp+5104L, 0x3.c4fb25edb13c5e9cp-96L, 0x4.3816d5c0af96b0f8p-5204L, 0x4.3816d5c0af96b1p-5204L }, - { -0x1.c6f68bc53960adep+112L, -0xd.36a9965916287d1p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x6.b3a10f94dcd70e1p-4L, 0xc.8517674f15bbcbfp-4L, 0x1.144e7f18ba67b4fep+0L, 0x1.144e7f18ba67b5p+0L }, - { -0xb.204e5335e697f73p-4L, 0x8.913a951884085ddp-4L, 0x2.7c439b7e5e590704p+0L, 0x2.7c439b7e5e590708p+0L }, - { -0x4.5861903e9a2c5178p-4L, -0x5.24585590086993p-4L, -0x2.45bcbee2a405a1d4p+0L, -0x2.45bcbee2a405a1dp+0L }, - { -0xf.2ba8f23d35f13f9p-4L, 0xa.3ecdb386b33fbe5p-4L, 0x2.8c2ffc8ed89a67b4p+0L, 0x2.8c2ffc8ed89a67b8p+0L }, - { 0x9.9b8e544f05c6de4p-8L, -0x7.abd5585035c4696p-4L, -0x1.7e2035d4e6006922p+0L, -0x1.7e2035d4e600692p+0L }, - { 0x5.732a72e50e0e8fd8p-136L, 0x7.8b963b5c9698ae88p+112L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xb.ea47beace8589dep-4L, -0x3.8f66d5a2d60e1fc8p-4L, -0x2.d9eb1ca9b45b3eacp+0L, -0x2.d9eb1ca9b45b3ea8p+0L }, - { -0xc.694faa89b4055cp+100L, -0x8.6659e1a891ccbd3p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x4.a571a0831166accp+14352L, -0x9.b8fe7ab721fb04cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x4.ee554b54200eeb18p-4L, -0x1.e1d0727b5f12c23cp-8L, -0x6.1b1657327a7313d8p-8L, -0x6.1b1657327a7313dp-8L }, - { -0x1.1e6c6f9d4f73617p-140L, 0x2.f3202c602060bd7cp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xc.cdb9d9e3a3a5b61p-4L, 0x5.7ddc79efb147e828p-4L, 0x2.bc857c5ac09c3d04p+0L, 0x2.bc857c5ac09c3d08p+0L }, - { -0x6.7236b6f8976437ap-4L, 0x5.e1ad137b44bc3ad8p-4L, 0x2.66e6f8a4616f47f8p+0L, 0x2.66e6f8a4616f47fcp+0L }, - { -0xb.f5ec1a26fcc9d7ep-4L, -0x3.772e0998925d6c78p-152L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x1.a983e64980e6104p-4L, 0xa.14ebef82079ff92p-4L, 0x1.684b277673a26358p+0L, 0x1.684b277673a2635ap+0L }, - { 0x1.e4fcc97f32b404d8p+13860L, -0x1.d272224db03bbe4ap-88L, -0xf.6367c3b63ab282p-13952L, -0xf.6367c3b63ab281fp-13952L }, - { 0xb.83be497f42b1776p-8L, -0xb.6c13349b9671c7bp-4L, -0x1.8204013b36ec0acp+0L, -0x1.8204013b36ec0abep+0L }, - { -0xd.00d476fab7a907dp-4L, 0xe.fce5159bb4f9691p+128L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xe.94e55595d939aa4p-4L, 0x8.66a9b0853e6c06ep-4L, 0x2.9e7077a5a9177248p+0L, 0x2.9e7077a5a917724cp+0L }, - { 0x5.431e650334b97d18p-4L, 0xf.1eb2c535e06fba3p-4L, 0x1.3c627af215641846p+0L, 0x1.3c627af215641848p+0L }, - { -0x8.54a857fb1034b62p-4L, -0xa.d3c15d582c446d9p-4L, -0x2.3a035e85ad032918p+0L, -0x2.3a035e85ad032914p+0L }, - { -0xc.cb73edcbfcb307fp-4L, 0xf.ed87c6cb3cd7d83p-84L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x1.3afd6b8a17918c64p+48L, -0x4.d312891f5f4e786p-4L, -0x3.243f6a8885a2ca18p+0L, -0x3.243f6a8885a2ca14p+0L }, - { 0xe.ae0633b99b178edp-4L, -0x1.39568b7ef55672cp-4L, -0x1.54bad5d8d44c04e4p-4L, -0x1.54bad5d8d44c04e2p-4L }, - { 0x4.cf293b1353f539bp-4L, 0x6.95c54f0009329c5p+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.b5eb2a3dcc35826p-5716L, -0xa.db19f19a7ea88bep-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.09017c7c80c2c48ap-4L, -0x2.5ae089add9bdff18p-4L, -0x1.281a477bf785850cp+0L, -0x1.281a477bf785850ap+0L }, - { -0x6.d211b21df46dcc18p-56L, 0xd.1a64a16c7c8f6d7p-4L, 0x1.921fb54442d18cbcp+0L, 0x1.921fb54442d18cbep+0L }, - { -0xc.1ef9ffac1d2c793p-4L, 0x1.67c59b4c06bd7496p-4L, 0x3.06b2add391c9eb78p+0L, 0x3.06b2add391c9eb7cp+0L }, - { -0x4.5d25a7f57110a158p+268L, -0x2.6c4fbdad444416d8p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xb.03fa4c349a339d2p-9120L, 0x1.e57ddc8153f3ba8p-8L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.9385036afefa239p+6960L, -0x6.8fac6e3f60b61e1p-4L, -0x4.299d61fcfb4de92p-6964L, -0x4.299d61fcfb4de918p-6964L }, - { -0x3.65bed5b32d99326p+1832L, 0x2.3ef31cc65b2354cp-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x2.bceec8bc1d31b0ccp-4L, 0xd.146217a63673958p-4L, 0x1.c6f361fb1067b388p+0L, 0x1.c6f361fb1067b38ap+0L }, - { 0x2.17b7fc97b1f46e7cp-4L, -0x4.49abbcdefc0c959p-4L, -0x1.1de39755c8eb62aep+0L, -0x1.1de39755c8eb62acp+0L }, - { -0x3.efc6f5f489c6c7bcp-4L, 0x8.f7ff40b96f9bd91p+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x6.003126d0e9a9acc8p-4L, -0x5.7be9edcc9dc2a02p-4L, -0x2.66b21a740cac5bf4p+0L, -0x2.66b21a740cac5bfp+0L }, - { -0x7.8952a49ff2c2f168p-4L, -0x1.c53227e2b7ce8fd8p-100L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0xf.c1271b0a53a3319p-4L, -0x2.281fdd0bca98746p+36L, -0x1.921fb5443b837dc2p+0L, -0x1.921fb5443b837dcp+0L }, - { 0xf.ce2fc60abd9a47cp-4L, 0x9.e8a3a1c0f885e07p-4L, 0x8.f5ad0c8c16696eap-4L, 0x8.f5ad0c8c16696ebp-4L }, - { 0x6.88e09aba14bbc208p-28L, 0x2.0051253b7bd07004p+9792L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x5.244b484bc9bb7828p-4L, -0x7.02ec4c8b2cc95998p-4L, -0xf.02379007abbea58p-4L, -0xf.02379007abbea57p-4L }, - { -0xa.4d34be63f5bedffp-4L, 0xf.be786c39b309e8p-4L, 0x2.26738a0739adbffcp+0L, 0x2.26738a0739adcp+0L }, - { -0x6.16481538d3215558p-4L, 0x8.5ea05eecb9ac14dp-4L, 0x2.3318a84b9fd18a38p+0L, 0x2.3318a84b9fd18a3cp+0L }, - { -0xd.4be5b4aaf95a52bp-4L, 0x5.505294ddb8af9558p-4L, 0x2.c2eb12ab368a9a94p+0L, 0x2.c2eb12ab368a9a98p+0L }, - { -0x1.f45f2a814c98f34p+80L, 0x2.b68cfa7df5a80aep-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x1.71591c964a8836a6p+16L, 0x2.047a032c2a353b58p-4L, 0x3.243f5428e50fb82cp+0L, 0x3.243f5428e50fb83p+0L }, - { -0x8.eb2ab17c06312d9p-4L, 0xb.932fffb0dfd7537p-4L, 0x2.3a3007c5cc9e7d3cp+0L, 0x2.3a3007c5cc9e7d4p+0L }, - { -0x1.3839b004fc949e6cp-120L, 0xa.7fafcf461e92982p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x6.41b8cd66b9392ef8p-4L, 0xf.d372339bf2bef0fp-4L, 0x1.f28133bb63853c52p+0L, 0x1.f28133bb63853c54p+0L }, - { -0xf.843d63b0a71eb93p-4L, -0xe.679784396815117p-4L, -0x2.64b1d552e74bdb24p+0L, -0x2.64b1d552e74bdb2p+0L }, - { -0x1.6be25f7b2bbfc3p-4L, -0xf.e1c7160797d7709p-4L, -0x1.a8f98c5e679f44fep+0L, -0x1.a8f98c5e679f44fcp+0L }, - { -0x9.f6c4eb5c911111ap-4L, -0xa.08c53e65e98b067p-4L, -0x2.5a492049a9cbbe7p+0L, -0x2.5a492049a9cbbe6cp+0L }, - { -0x4.1a4c613ba5fe16ap-4L, -0xd.36e91d3e54f0432p-4L, -0x1.df30682153ea13e8p+0L, -0x1.df30682153ea13e6p+0L }, - { -0xd.1de964de30857a7p-4L, -0x8.604a0e63d4f5df1p-4L, -0x2.92c30d3b7d0de73cp+0L, -0x2.92c30d3b7d0de738p+0L }, - { 0xc.6b9d18c70882d52p-4L, -0x2.711b4139fbed3dc8p-11492L, -0x3.254433723f77f3bcp-11492L, -0x3.254433723f77f3b8p-11492L }, - { 0x9.4021cab7a0d78bbp-4L, 0x8.305eb92b4243ea2p-4L, 0xb.97f7af5268b8f8fp-4L, 0xb.97f7af5268b8f9p-4L }, - { -0x4.f0330cdb93893948p-4L, 0xe.be93c7764505ff9p-8L, 0x2.f504ddece3874ccp+0L, 0x2.f504ddece3874cc4p+0L }, - { -0xd.ea533ffe043e52bp+2296L, 0x1.1dd2693fe11489c2p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x2.0397d0e9676f1b2p-4L, 0x5.48015a56bb1ddbep-136L, 0x2.9f4ab0b2d7a99144p-132L, 0x2.9f4ab0b2d7a99148p-132L }, - { -0x1.9a52d244a51432cep-80L, -0xd.c27cd78e0864371p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x9.c7f27c2034ec1cfp-4L, -0xa.a9e0aa658eda7dcp-4L, -0x2.50244d2439996p+0L, -0x2.50244d2439995ffcp+0L }, - { 0x1.403075ad6be49e48p+104L, 0x8.2f7e9e49692fd28p-4L, 0x6.8b6793c6b839addp-108L, 0x6.8b6793c6b839add8p-108L }, - { -0xa.93e861896961066p-4L, -0xd.4c10bf60bb97196p-4L, -0x2.3e2700333180df34p+0L, -0x2.3e2700333180df3p+0L }, - { 0x4.ff124c9911f2538p-4L, -0x8.776b58ba7268d9ep-4L, -0x1.09a4306282277e7p+0L, -0x1.09a4306282277e6ep+0L }, - { -0x4.db7b68b78ebb30a8p-80L, -0x9.b667363949a8b6dp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x9.799737c602ebc35p-12L, -0x4.ee069c6928cc872p+68L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xa.8eb47109f6336a7p+7944L, 0x6.e3c54639ed929cp-16L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x7.c5f3d0d9d9db89cp-4L, 0x1.6b364994830303c2p-4L, 0x2.f607d4a28c7c5d2p+0L, 0x2.f607d4a28c7c5d24p+0L }, - { -0x4.2513fed56a721cp-4L, 0x3.e183251bd312b9f8p-4L, 0x2.6399f4ee48a52b1p+0L, 0x2.6399f4ee48a52b14p+0L }, - { 0x5.372c1f6cb3bb4cep-8L, 0xc.30d4cc265a07403p-4L, 0x1.8b47c0312064586p+0L, 0x1.8b47c03120645862p+0L }, - { 0xf.7e3aa552d45b234p-4L, -0x3.9a644e95053aaf1cp-4L, -0x3.a7ef5825b5df9e1p-4L, -0x3.a7ef5825b5df9e0cp-4L }, - { 0xe.85839cd58ef2c75p-4L, 0x1.e2027a063163b7ap+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.d9ee24413681697p+96L, -0x1.a0688ee2096f86eap-148L, -0x1.e10130aa540fdb18p-248L, -0x1.e10130aa540fdb16p-248L }, - { -0x5.0487ddb4070bf26p-4L, 0xb.41c4c871bf58078p-64L, 0x3.243f6a8885a308acp+0L, 0x3.243f6a8885a308bp+0L }, - { -0x4.cfd480a28c2b6b48p-4L, 0x1.8657dd64795c35ap-4L, 0x2.d5b053c0ec2d5304p+0L, 0x2.d5b053c0ec2d5308p+0L }, - { -0x1.262cb60430e5eb9ep-4L, 0x8.0e85fe0bcf8a253p-4L, 0x1.b66463ab64833336p+0L, 0x1.b66463ab64833338p+0L }, - { -0x3.cefbd3ecacf92c44p-4L, -0x5.f20def7196dea63p-4L, -0x2.23f8c03324b67e44p+0L, -0x2.23f8c03324b67e4p+0L }, - { 0x1.3a394f91198290bcp-4L, -0x5.fa0cb4bdfd2d7318p-4L, -0x1.5e454070508e5eap+0L, -0x1.5e454070508e5e9ep+0L }, - { 0x4.08cc4ee18d971c48p-4L, -0xc.08ff29dce9d081fp-4L, -0x1.3f5281f2c773c0bap+0L, -0x1.3f5281f2c773c0b8p+0L }, - { 0x1.109cf51c23d9c444p-3868L, 0x6.d5822da15531716p-12L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x5.b4cccaf7aee9cd6p-4L, 0xd.08cda37bcd9c8cp-4L, 0x1.287c57a28064102cp+0L, 0x1.287c57a28064102ep+0L }, - { -0xb.d7f74d7d0014f61p-4L, -0xa.7263655e0a0ea62p-4L, -0x2.6b34e32fa133c618p+0L, -0x2.6b34e32fa133c614p+0L }, - { -0x2.47b34fa6f1ad5d68p-4L, -0x4.7e5d88e1178a73b8p+136L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x3.e49a34d2590d3414p-148L, 0x6.90a7904ae1f6ca48p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xf.e7cc8c0c8fca8d6p-4L, 0xb.5766572c78c1636p-4L, 0x9.e930d3e45526457p-4L, 0x9.e930d3e45526458p-4L }, - { -0x3.84138ca9f496d498p+24L, -0x3.83d9c130d6f21f6p-92L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x3.622e5c923b06d66cp-8L, 0x8.911302b7a344f8ap-4L, 0x1.987124e672754176p+0L, 0x1.987124e672754178p+0L }, - { -0x2.a91a430d68680b6cp-132L, -0x8.87063dd41e8a8bbp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x4.e1420e7e82cd22dp-4L, 0x5.ed8fe0a77cf3d518p-14676L, 0x1.36fb35f69a850f64p-14672L, 0x1.36fb35f69a850f66p-14672L }, - { -0xc.8346ca25bd9f342p-4L, 0xa.8b2343cd8095adcp-10960L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x2.b32d8027c5516654p-3772L, 0x6.fd1366df02fe9c5p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.c090b4e367d6c7ep-8L, -0x5.081c001c09df9f3p-4L, -0x1.7cb3f4f28e98b0c6p+0L, -0x1.7cb3f4f28e98b0c4p+0L }, - { -0x3.fcb8a555a704d93cp-112L, -0x1.920119c347818b36p+4120L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x4.f7a55e6bfc734b5p-132L, 0x9.188a26a4beb414p+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xb.ff33c19f0cbb73p-4L, 0x1.d50d6b459087ecdp-4L, 0x2.6cc4d1a540b1449cp-4L, 0x2.6cc4d1a540b144ap-4L }, - { 0x6.0dd96d442bc44b28p-4L, -0x3.e88917f9e6c0bb2p-4L, -0x9.2c0cc2bcd1b42bcp-4L, -0x9.2c0cc2bcd1b42bbp-4L }, - { 0xf.e9c0adcf6e6ebaap+80L, -0xe.6049cc9d4ea9c32p-8L, -0xe.746309506e28c41p-92L, -0xe.746309506e28c4p-92L }, - { -0xd.e0ca0ae677c56c7p-4L, -0x3.b604528c1bde4ca8p-4L, -0x2.e15bb2ef66714438p+0L, -0x2.e15bb2ef66714434p+0L }, - { 0x9.3e94ea277274ab3p-4L, 0xf.ec080621a8d9456p-4L, 0x1.0b752d4e563c12fp+0L, 0x1.0b752d4e563c12f2p+0L }, - { 0x1.96ef7e6b80e63adep-4L, 0x5.fa153b3eb3b0779p+984L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x2.c1491ea7eb7b418p+220L, -0x2.5fa1d9a3a5a2b664p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x1.f7142c3edd746312p-76L, 0xb.79a14c17c57922dp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x9.9b19d045170086ap-4L, -0xd.65fbae6f453f5a2p-4L, -0x2.315b8727ceee88f4p+0L, -0x2.315b8727ceee88fp+0L }, - { 0xc.7a9e15e82248878p-4L, 0x3.f5ec8986cfd785dp-4L, 0x4.ead1f3dda3a04a3p-4L, 0x4.ead1f3dda3a04a38p-4L }, - { -0x2.94c306c1808e3c18p+44L, -0x3.aa0cc319c013919p-4L, -0x3.243f6a8885a19d68p+0L, -0x3.243f6a8885a19d64p+0L }, - { -0xf.0292f4401d18d5cp-4L, -0x1.bf51089c520b29b4p-4L, -0x3.0694831553eb506p+0L, -0x3.0694831553eb505cp+0L }, - { -0x3.338096c5b380a194p+5592L, -0x5.35b41b797fb9331p-56L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x9.620bcddbdd20a79p-4L, 0x4.17376606afdde85p-4L, 0x6.93f7056b927052fp-4L, 0x6.93f7056b927052f8p-4L }, - { 0xd.1dc39e358b023ap-4L, 0xb.13430c035931444p-4L, 0xb.383ae5cd743ce8ap-4L, 0xb.383ae5cd743ce8bp-4L }, - { 0x3.606617a1673d0184p-4L, -0x8.f017932d188a998p-4L, -0x1.35a7a5999089613cp+0L, -0x1.35a7a5999089613ap+0L }, - { -0xf.3ce660b2bbefc26p-80L, -0x1.8dad3bd8dae62b26p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xf.d53ec036950502fp-4L, -0x2.a72c3e3aead35fep+14616L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x4.9ff6d398cf5c723p-4L, 0x3.c7ea3c3c2b39e2c8p+56L, 0x1.921fb54442d18454p+0L, 0x1.921fb54442d18456p+0L }, - { 0xf.7206b4c8d50f316p-4L, 0x7.5f74c3dd6c9936dp-4L, 0x7.203659231b6ebf78p-4L, 0x7.203659231b6ebf8p-4L }, - { 0x1.d1a5048e1cfadea8p-4L, 0xe.8f9244700df6721p-4L, 0x1.724f343754e1f6c2p+0L, 0x1.724f343754e1f6c4p+0L }, - { 0x3.99c86ae38d72f47cp-4L, 0x1.78aa249a87ca9a7ep-4092L, 0x6.89bb9c00e2992908p-4092L, 0x6.89bb9c00e299291p-4092L }, - { 0x9.638122087011d7dp-4L, 0xc.4c4e12b06f42474p-4L, 0xe.b33a0191f01596ap-4L, 0xe.b33a0191f01596bp-4L }, - { 0x1.ef067fd567660c6ep+124L, 0x6.c87c79c7f39458b8p-4L, 0x3.8203f86101129a1p-128L, 0x3.8203f86101129a14p-128L }, - { 0x1.7ae1a02b6be082e8p-96L, 0x6.a546c7e5065f0158p-112L, 0x4.7d81cd7fc2b19b08p-16L, 0x4.7d81cd7fc2b19b1p-16L }, - { -0x6.f866735c25236f98p-4L, -0x6.48ac3faff9ac8af8p-148L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x1.62b2ac359758568p-124L, 0xa.a22cceb5d16a7b9p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x7.9bb3d37308387268p-4L, -0xc.186ea423cfbc56dp-4L, -0x2.21dcf2dcca126d7p+0L, -0x2.21dcf2dcca126d6cp+0L }, - { 0x9.e5f3c3ae26d0dd6p-44L, -0x1.5803a5d39e417564p-4L, -0x1.921fb5443b73dd0ep+0L, -0x1.921fb5443b73dd0cp+0L }, - { -0xc.a52f12f15058ap-8L, -0x3.e058d43b80e19b7cp+32L, -0x1.921fb5444614a0ap+0L, -0x1.921fb5444614a09ep+0L }, - { -0x7.810b603203760db8p-4L, 0xd.d38ca8b0ca1dddfp-140L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x3.e726a67b179e572p+5396L, -0xc.d26229e318f0c64p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x8.457740622adf15fp-4L, -0x7.492c117c47e7f31p-4L, -0xb.8ddcb5e4e618633p-4L, -0xb.8ddcb5e4e618632p-4L }, - { 0xb.b13b38b2bab98c4p-4L, -0xc.05a51372a620cc3p-4L, -0xc.c9f0d2797fe328dp-4L, -0xc.c9f0d2797fe328cp-4L }, - { -0xf.52d7c0f49c1b5a4p-4L, 0x6.c87dc3726b00027p-112L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x1.5c0865fc4e06a84ep-4L, 0xa.2dfc5d1f96be4bcp-4L, 0x1.b41ca3f2a679e626p+0L, 0x1.b41ca3f2a679e628p+0L }, - { -0x3.f497fcccc60e3828p+60L, 0x1.dd126ec3b3b24d64p+116L, 0x1.921fb54442d18688p+0L, 0x1.921fb54442d1868ap+0L }, - { 0x5.03f2d9b66abed898p-4L, 0xd.e1d2b8730f8408fp-4L, 0x1.395ec39fa3cbe086p+0L, 0x1.395ec39fa3cbe088p+0L }, - { -0x3.8052f809aaac9b64p-4L, 0xf.ad374726f5b37c2p+16L, 0x1.921fb8d713091e94p+0L, 0x1.921fb8d713091e96p+0L }, - { 0x3.48836233e960d588p-4L, -0x8.af10e3af7480717p-4L, -0x1.35961a95496c7024p+0L, -0x1.35961a95496c7022p+0L }, - { 0x4.d09e474f01f1a2d8p-72L, 0x2.956954f33db8ba84p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xe.05c36356f1cc00bp-4L, -0x1.30a38fe2fc6ef3d6p-120L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x8.98fecd06210c28ep-8L, -0xa.944a9ff08e89db6p-4L, -0x1.8521cc1c24d70946p+0L, -0x1.8521cc1c24d70944p+0L }, - { -0xf.069ae41b6f97acbp-4L, -0x2.849c2bec428d3088p-4L, -0x2.f9be11bfeff191ep+0L, -0x2.f9be11bfeff191dcp+0L }, - { 0x1.ddc053fcc0b29fc6p-2068L, -0xe.aa11ca5025d7161p+352L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xe.30a7bdb7d22b3c9p-4L, -0x6.8b8840cf7db54858p+5320L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xc.289ab032c02ec2bp+96L, -0x2.4f1d0f8cfd43ef8cp+68L, -0x3.243f6a857bc45af8p+0L, -0x3.243f6a857bc45af4p+0L }, - { 0xc.b983cae10f7203p-4L, 0xb.7422dd3d2b45dc5p-4L, 0xb.b9dea242a2b569ap-4L, 0xb.b9dea242a2b569bp-4L }, - { -0xa.fbaa8d616ab8d1dp-4L, -0xe.926ef7c0fa60c33p-4L, -0x2.37778ac56a06051p+0L, -0x2.37778ac56a06050cp+0L }, - { 0xf.80c7c99d2c6404cp-4L, -0x7.2aac6d2a68c490bp+8L, -0x1.91fd18c483c4059ap+0L, -0x1.91fd18c483c40598p+0L }, - { -0xe.80d9a3a08faf173p-4L, -0x8.400e8efd60a398p-4L, -0x2.9fd8298eb95656f4p+0L, -0x2.9fd8298eb95656fp+0L }, - { -0x1.e30b1be4461dcf88p+212L, -0xc.2454aa891f5dba1p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x1.6492e0fa29711f58p+104L, 0x3.a0caae204aa84214p-4L, 0x2.9ad20bbc8b5aa404p-108L, 0x2.9ad20bbc8b5aa408p-108L }, - { 0x6.db2d4dd8afa84408p-4L, 0x8.7fd39596a804d49p-80L, 0x1.3d5a80194777316p-76L, 0x1.3d5a801947773162p-76L }, - { 0x3.f16bc38197cbac4cp-104L, -0xb.2a83d184147cfdcp-96L, -0x1.91c54eb36a10602cp+0L, -0x1.91c54eb36a10602ap+0L }, - { 0xa.e2eae99c9fd7478p-4L, -0x2.36e2a96b54e59b58p-4L, -0x3.35f38d6e0b59fa84p-4L, -0x3.35f38d6e0b59fa8p-4L }, - { 0x3.0a86465998f852dp+128L, -0x1.43ec0bdd98b0f80cp-112L, -0x6.a83ada10badb8dep-244L, -0x6.a83ada10badb8dd8p-244L }, - { 0x6.883e7a1d34914268p-4L, 0xb.88a85700deb5549p-4L, 0x1.0e344a89b3d1ea2ep+0L, 0x1.0e344a89b3d1ea3p+0L }, - { -0xf.2b2a3a311948993p-4L, -0x3.06fe2a10fe55267cp-4L, -0x2.f1d184e7e8b146b8p+0L, -0x2.f1d184e7e8b146b4p+0L }, - { -0xd.de264368cd7459ap-4L, 0x5.567777c9aa2124c8p-4L, 0x2.c62fd64a3dffbda4p+0L, 0x2.c62fd64a3dffbda8p+0L }, - { -0x1.935a9217a5a3024p-4L, 0x7.3ccc7fe1d42ad228p-4L, 0x1.c8ffb02ef3152e56p+0L, 0x1.c8ffb02ef3152e58p+0L }, - { -0x4.bbff6d1fef17b4c8p-4L, -0x1.4134a05ac2afda6p+20L, -0x1.921fb90a3855426ep+0L, -0x1.921fb90a3855426cp+0L }, - { 0x5.265fe49d84076a68p-4L, -0xc.103986b2d38539dp-4L, -0x1.2ad51c99871cfe42p+0L, -0x1.2ad51c99871cfe4p+0L }, - { -0x2.e02038211a5e1a1cp+84L, 0x2.66bb0943c921a184p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x7.5a723c24f0c64ebp-4L, 0x3.c761bdd9cf2def2cp-4L, 0x2.aab94e7e66bac71cp+0L, 0x2.aab94e7e66bac72p+0L }, - { -0x7.cf59e52998194478p+128L, -0xe.780c3928a522b73p-12L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x6.1dfcef356d3841p-4L, 0x3.4828bdd2a081f3ep-4L, 0x7.e0f6aac2c77ae808p-4L, 0x7.e0f6aac2c77ae81p-4L }, - { 0xb.dde4e379662aeeap-4L, 0xb.0226291c9bc5964p-4L, 0xb.f75cd67c86afa4cp-4L, 0xb.f75cd67c86afa4dp-4L }, - { -0xd.bf9a0da9faa3504p-4L, -0x5.c1892b0fafe1dc68p-4L, -0x2.bebed8f131223be4p+0L, -0x2.bebed8f131223bep+0L }, - { 0x1.44812a3159648466p-4L, 0xd.9d71d57ae36f89fp+1968L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x1.e8e8f49835eaacb8p-4L, 0x9.eac5efdf2c187bdp-4L, 0x1.c2d3d0e12540c0eep+0L, 0x1.c2d3d0e12540c0fp+0L }, - { 0xf.8a9cd502481f327p-4L, -0x2.9371a4cdcbd8ac4p-4L, -0x2.a0c8bb47d0fe5554p-4L, -0x2.a0c8bb47d0fe555p-4L }, - { 0xf.ec9e23f6d0a3bd2p-4L, -0x2.5fd5f4e23c3210e4p+108L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x1.80a14974eabf910ap-152L, -0x4.c2d0568402546a5p-8L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xc.976222dd345048p-68L, -0xd.6563e961e96fd5dp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x9.e03ff635ae5b0afp-8912L, -0xa.42b9f1752ebee14p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x6.4ef2060125bf954p-4L, 0x1.949b3c6ad95e7494p-128L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0xf.d085f6fba7aa194p+11308L, 0x9.8fa092c7be00f66p+52L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x2.29f54bce824a24cp-8L, -0xa.b8f81b679b49916p-4L, -0x1.8ee524e86c1ee1e4p+0L, -0x1.8ee524e86c1ee1e2p+0L }, - { -0x2.dfa40c215498cf14p-4L, -0x2.ec02031137509e54p-4L, -0x2.590d4b9283e4bb88p+0L, -0x2.590d4b9283e4bb84p+0L }, - { 0xc.95b28af67c0d0fdp-4L, -0x3.8b937ee4a5ad9044p-4L, -0x4.64b9dc9fe48f2ca8p-4L, -0x4.64b9dc9fe48f2cap-4L }, - { 0x1.96c3f2d8373481fcp-128L, 0x5.32ac5f2f72c534e8p+7120L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.71a836d1385ea83cp+32L, -0x2.98de885b63ec9fap-4L, -0xc.10d9073a34cf0d8p-40L, -0xc.10d9073a34cf0d7p-40L }, - { -0x2.ec64d50f08792a24p-12L, 0x7.4a3ef749c24694d8p+144L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xe.39d4437a92edbe2p+6624L, -0x7.e597e9edb98f8dd8p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x5.b2db0149e01e772p-4L, -0xa.4e00c5865119715p-4L, -0x2.13718dc24c8ca814p+0L, -0x2.13718dc24c8ca81p+0L }, - { 0x3.2d5ce470bbbfc05p-4L, -0x6.fef503b2cde63e88p-4L, -0x1.24fdbd6081eb3d04p+0L, -0x1.24fdbd6081eb3d02p+0L }, - { -0x2.75c4d49c73c6b714p-4L, -0x2.6f4dc7f3b45d7874p+84L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x3.be464272e1460c8p-92L, -0xc.5760c2d01b802f5p+84L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x4.58042455b6631c78p-4L, -0xf.a5425993c2d22edp-4L, -0x1.d774099a530614d4p+0L, -0x1.d774099a530614d2p+0L }, - { -0x3.331c1dd1ed766244p-352L, 0x5.6352b9b11a14c48p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.eeff171b7925d048p-14368L, -0xf.ff0d58e82429fafp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x9.bd53e4167e85b42p-4L, -0x5.4c28c9b0b345941p-4L, -0x2.a4b8051a75508798p+0L, -0x2.a4b8051a75508794p+0L }, - { 0x8.fef78aad41a1338p-4L, 0xf.25b2822b10d9f65p-4L, 0x1.08ed7bc61d7d73f2p+0L, 0x1.08ed7bc61d7d73f4p+0L }, - { -0x5.cd10c03bcaf10088p-8L, -0xa.a821812c5f53b52p-4L, -0x1.9ad4845fb36d2352p+0L, -0x1.9ad4845fb36d235p+0L }, - { 0x5.94e05ec04235ac68p-4L, -0xa.09752cd4a8e9c1dp-104L, -0x1.cc59396f222b7724p-100L, -0x1.cc59396f222b7722p-100L }, - { -0xd.167af1356c9c025p-4L, -0xf.d0cd204dbb8b533p-4L, -0x2.4318bedab39b9894p+0L, -0x2.4318bedab39b989p+0L }, - { 0xa.c0e5742f317f8a3p-4L, 0xe.2242314d427e9c1p-204L, 0x1.5078fcaf7a061e0cp-200L, 0x1.5078fcaf7a061e0ep-200L }, - { -0x2.37749e13337ef694p-4L, 0x4.8513915f54085e2p-4L, 0x2.06d9395eb203ac84p+0L, 0x2.06d9395eb203ac88p+0L }, - { 0xe.23a123d6d8bcffp+5256L, 0x5.25a1ebc2fc29f1cp+84L, 0x5.d30afa61156b2b38p-5176L, 0x5.d30afa61156b2b4p-5176L }, - { -0x2.4674afe3989b3a5p-72L, -0x1.5e3fb8c6c490f9b8p-100L, -0x3.243f6a7ee695750cp+0L, -0x3.243f6a7ee6957508p+0L }, - { -0xe.920450e2df4f23ep-4L, -0x7.8a913f4c29492cdp-4L, -0x2.a9facee71eddd834p+0L, -0x2.a9facee71eddd83p+0L }, - { 0xd.f18c68c5e57c1fep-4L, 0x6.4bf6a01053290c18p+100L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.65b50e81ed20864p+92L, 0x8.d86e55e3f0a94b1p-4L, 0xa.905826200246659p-100L, 0xa.90582620024665ap-100L }, - { -0x5.0308adabc4a020fp-4L, -0x2.a7d9b961e2c3089p-4L, -0x2.a7822a212eff89d4p+0L, -0x2.a7822a212eff89dp+0L }, - { -0xd.227d8e4d09d7251p-4L, 0x7.d5608278690935ap-4L, 0x2.9a9469fdb763be6cp+0L, 0x2.9a9469fdb763be7p+0L }, - { -0xe.81b27c03c76f499p-48L, -0x2.b154c8162bc04cb4p-4L, -0x1.921fb5444327b72cp+0L, -0x1.921fb5444327b72ap+0L }, - { 0x4.35ecdac82f2a93c8p-4L, -0x5.771325ed71c201dp-4L, -0xe.a11a21eaf4329d6p-4L, -0xe.a11a21eaf4329d5p-4L }, - { -0x5.eae159d6c2480c9p+32L, 0x5.121392f3a25f68p-4L, 0x3.243f6a8877ed3cf8p+0L, 0x3.243f6a8877ed3cfcp+0L }, - { 0x3.dcb9a65bf445eaccp+10876L, 0x1.778ccedfa82f4736p-4L, 0x6.13cb511c0ab34e3p-10884L, 0x6.13cb511c0ab34e38p-10884L }, - { 0xb.3cc3e4cc1b25c56p-4L, -0x6.76ae6ecaf0206ea8p-4L, -0x8.5a0330d0113839fp-4L, -0x8.5a0330d0113839ep-4L }, - { 0xe.22ec92ad54501adp-4L, -0x3.f615ff2adef13ae8p+56L, -0x1.921fb54442d18432p+0L, -0x1.921fb54442d1843p+0L }, - { -0x7.e9826b314600f95p-120L, 0x4.9a9641fa150c9178p+60L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xe.99b66de48e79158p-4376L, -0x5.c1e4a9cc5e3e83e8p+52L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x5.1ce62b8e10774afp-4L, 0x7.fa8931ceaf326ac8p-4L, 0x2.24045af1101a7c0cp+0L, 0x2.24045af1101a7c1p+0L }, - { 0x5.9b4e55550b4e7078p+112L, -0xa.954d79680ea5909p-4L, -0x1.e33a9f922fb03e88p-116L, -0x1.e33a9f922fb03e86p-116L }, - { 0xb.432563e5c37e78fp+108L, 0xa.950b0bb7d84c5b3p-4L, 0xf.08a83c251380dd2p-116L, 0xf.08a83c251380dd3p-116L }, - { 0x4.3e136fbe7e156658p-4L, 0xb.9930789b19cf8a8p-4L, 0x1.385a8b82e95fe408p+0L, 0x1.385a8b82e95fe40ap+0L }, - { -0x8.1697784edf6fe07p-8L, 0x2.e9849ddc62c0d374p-4L, 0x1.be1fa44b4ee5c01ep+0L, 0x1.be1fa44b4ee5c02p+0L }, - { 0xc.d570e244c0e60bep-4L, 0xf.15d04c531718d34p-4L, 0xd.da96e59bf70d9cfp-4L, 0xd.da96e59bf70d9dp-4L }, - { 0x1.e1200b8406eda8fep-4L, 0x1.e65664694a4c5354p-1032L, 0x1.02c5fcd18c965c48p-1028L, 0x1.02c5fcd18c965c4ap-1028L }, - { -0x9.2cb86254ecdfd09p-8L, -0x4.9982beb1a0f87638p-4L, -0x1.b1dfdabe0ce0405cp+0L, -0x1.b1dfdabe0ce0405ap+0L }, - { -0xe.45cc48c61fdc121p+40L, 0x4.e07d3709dbe3fep-4L, 0x3.243f6a88859d913cp+0L, 0x3.243f6a88859d914p+0L }, - { 0x5.653d42dac0a5219p-4L, 0x9.5f1aff673a041bcp-4L, 0x1.0c64c95c41e196a2p+0L, 0x1.0c64c95c41e196a4p+0L }, - { -0x8.bcd403a004e1a23p-4L, -0x8.1c9d05645c7987cp-4L, -0x2.64b0a8416a0a6878p+0L, -0x2.64b0a8416a0a6874p+0L }, - { 0xd.13a5ae9285d253dp-4L, 0x9.4cf62e7e77f656p-4L, 0x9.e4410391f565abdp-4L, 0x9.e4410391f565abep-4L }, - { -0x2.84d9c1bc69548254p-4L, -0x4.21ac0c75a3a7dbe8p-4L, -0x2.1e4985c908e36c6cp+0L, -0x2.1e4985c908e36c68p+0L }, - { -0xd.b9bd68e165f831p-4L, 0x8.3fd61ad578cd929p-4L, 0x2.99b53d1ee1512a74p+0L, 0x2.99b53d1ee1512a78p+0L }, - { 0xf.30d46d764112444p-4L, 0xb.cd4a73dc359d737p-4L, 0xa.916e2e87f1b749dp-4L, 0xa.916e2e87f1b749ep-4L }, - { 0x1.515f582a4522a614p-112L, -0x5.9e1738c1ccd8a9a8p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x2.92f5722be8168a3p+84L, -0x4.8e012f7d7878b01p-4L, -0x1.c4fbac335198d82cp-88L, -0x1.c4fbac335198d82ap-88L }, - { -0x1.6757eda9b94c8c8cp-6468L, -0xf.789b834a9491fb6p-308L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xf.f16a11b7efb26b4p-4L, 0x7.6980774d9eb5024p-4L, 0x2.b4d71146599f1ebcp+0L, 0x2.b4d71146599f1ecp+0L }, - { 0xc.52f873b5b0d54efp-8L, 0x2.b8137644250c4bbcp-4L, 0x1.4b748a8aaca4742cp+0L, 0x1.4b748a8aaca4742ep+0L }, - { 0x8.b13bd917a919d6p-4L, 0xd.a7e60f2da06694ep-4L, 0x1.0102ec7f8667321ap+0L, 0x1.0102ec7f8667321cp+0L }, - { -0x9.6d66afe84b35074p-4L, 0x8.d45410dc1895ef4p-4L, 0x2.6391367299a3faccp+0L, 0x2.6391367299a3fadp+0L }, - { 0x8.7112de739485f11p-6744L, -0x1.4a2fc4cfe9bc534cp-13708L, -0x2.71d20e8084e1e9cp-6968L, -0x2.71d20e8084e1e9bcp-6968L }, - { -0x5.9ce42450cfaf8ee8p-4L, 0x6.efb719daf136a1cp-4L, 0x2.404921fc654263p+0L, 0x2.404921fc65426304p+0L }, - { 0x9.ba0bd38df957e82p-5860L, -0x7.f37ea4723b67675p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x2.bf5897672b745798p-4L, -0x1.2b46b769cd53c99cp-4L, -0x6.6fcf0d804412fb1p-4L, -0x6.6fcf0d804412fb08p-4L }, - { 0x8.0d256afefef3c89p-4L, -0xa.e23fca6db43882fp-4L, -0xe.f12f9edadf77c82p-4L, -0xe.f12f9edadf77c81p-4L }, - { -0x3.5d7f19c9107b35a4p-92L, -0x4.0740585229be331p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xb.2f2372351c33164p-8L, -0x1.e98b74b783fe8242p-4L, -0x1.ebd6a4be06afe44ep+0L, -0x1.ebd6a4be06afe44cp+0L }, - { -0xf.7938a9b78d6563ep-4L, -0x5.e56611314a03c688p-24L, -0x3.243f646fc449c69p+0L, -0x3.243f646fc449c68cp+0L }, - { -0x3.378249c69ce50b28p+128L, 0xd.1fe6e25acc0107ap-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x2.9bce90f0aac016a8p+8752L, -0x3.f9a540b88fcacaf8p+20L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x9.8f02fd2b4d10383p-4L, -0x3.10d386b4ddaa9bccp-4L, -0x2.d4cb6d7692b4340cp+0L, -0x2.d4cb6d7692b43408p+0L }, - { 0x8.a7f4a483fcced92p-4L, 0x1.0dbbaa49beedef7ap-80L, 0x1.f293f545ba902d6p-80L, 0x1.f293f545ba902d62p-80L }, - { 0xc.779757b60637763p-4L, 0xe.777fe73bf0e9a48p-4L, 0xd.c087f481f381bc4p-4L, 0xd.c087f481f381bc5p-4L }, - { -0x4.637006dbd01caa2p-48L, -0x9.0b16723fd236994p-4L, -0x1.921fb54442d94812p+0L, -0x1.921fb54442d9481p+0L }, - { -0x2.26865489613f2a3cp-16L, -0xf.5402328fd9d6fdfp-4L, -0x1.9221f3ebd1a9f3a6p+0L, -0x1.9221f3ebd1a9f3a4p+0L }, - { -0x1.9cdb9776e2fd9cd6p-88L, 0xc.d7d4b25d5ee54a4p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xf.002b8779c597ceep-4L, 0x7.903eb3c7555e4358p-4L, 0x7.78ddd72dbbbd4ep-4L, 0x7.78ddd72dbbbd4e08p-4L }, - { 0x5.216f04578c6eedf8p-28L, -0xb.887e64736056822p-4L, -0x1.921fb4d260c15a72p+0L, -0x1.921fb4d260c15a7p+0L }, - { -0x2.96746a1d6d0a835cp-12L, -0x6.bbe44e9596a2f068p-44L, -0x3.243f6a85eb741a2cp+0L, -0x3.243f6a85eb741a28p+0L }, - { 0xc.8b02c285d275bd6p-4L, -0x7.2ea947c351044f48p-4L, -0x8.5212a1fc5bb54a1p-4L, -0x8.5212a1fc5bb54ap-4L }, - { -0xc.4830d91b64528bdp-4L, -0xa.faff5d48675db64p-11172L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x1.456f46c72593c416p-4L, 0x1.66e29eea15366fa6p+144L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.de830895fc14d25p-4L, 0x1.d696938384c107e8p-4L, 0x2.1bbde70f3e78278p-4L, 0x2.1bbde70f3e782784p-4L }, - { 0xd.737880bffe043f4p+1748L, -0xb.0173bf64b3af081p-4L, -0xd.175a392434528acp-1756L, -0xd.175a392434528abp-1756L }, - { -0x4.d70abf0d2e83e9e8p-32L, -0x4.bded6e2f0ae69668p-4L, -0x1.921fb554978f2276p+0L, -0x1.921fb554978f2274p+0L }, - { -0x1.6f720ef4ee00435cp-104L, -0xe.794bdddad00436cp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x8.bcfd1861de45b01p-4L, 0x2.aad3a86545c4ac24p+68L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.f81960839d640cdp-4L, -0x7.693a270061cf9de8p-4L, -0xd.0ed284135386fbep-4L, -0xd.0ed284135386fbdp-4L }, - { 0xe.7b0648fc94495aap+6848L, -0x5.48b5a0cfdf4fe08p+92L, -0x5.d6a5f8e290a54e2p-6760L, -0x5.d6a5f8e290a54e18p-6760L }, - { -0x6.26f604efc7da8708p+72L, -0x5.9293af393bd5fbfp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0xd.3ea27eab88fb691p-4L, 0xe.5d425700b9dfb9p-4L, 0xd.37014b312bf4ee6p-4L, 0xd.37014b312bf4ee7p-4L }, - { -0xf.de61a9eba878612p+2584L, 0x3.0b30eb6a97ddaf6p+20L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x2.8b29e4e9b1677aap-8428L, -0xb.c9870bb9c74469p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.cdad015fe5b95a34p-148L, 0x3.fcdc007ba74601ap-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.f1d5273873448298p-140L, 0xd.38eafd3878fe2f4p-2288L, 0x6.cc9f855116729cd8p-2148L, 0x6.cc9f855116729cep-2148L }, - { 0x1.c55b237b57929914p-8L, 0xe.5512393a7c3aa68p+88L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x6.c72dbae38baf489p-4L, 0xa.9efab67bae298c4p-4L, 0x2.238931ee6f4619p+0L, 0x2.238931ee6f461904p+0L }, - { 0x6.d6fe2acf94b44bp-4L, -0x2.1052fcc75fe78e44p-4L, -0x4.b04c77d29e1352ap-4L, -0x4.b04c77d29e135298p-4L }, - { 0x7.afbf13a7baa48938p+28L, -0xc.e3f378c5ed3afabp-4L, -0x1.ad5137573db23a6ap-32L, -0x1.ad5137573db23a68p-32L }, - { -0x5.ed5d3988224f9748p-4L, 0x1.e7758010af069478p+112L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xc.0d33ff76e10cd46p+12L, 0x4.1c590bda30ba606p-4876L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x6.57e754000acc05cp-56L, -0xb.d8b227ae135fe8fp+116L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x4.6e00ec5a491950b8p+10764L, -0x1.933e5a044e710e98p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0xd.233e9cefca1ae41p-120L, 0x3.45dd24865b41e91p+60L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.475a990a52ea68a8p+64L, -0x1.8712ead1e57a5c3cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x1.09bc36ba214221b6p+5604L, -0x4.bf6dbbf8cca43b3p-8L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x9.4d57927720bce2ap-4L, -0xd.c24a0c2da437c45p-8L, -0x3.0ca61d2678ef9458p+0L, -0x3.0ca61d2678ef9454p+0L }, - { -0x3.bd744abad650adacp+24L, -0x5.b0583bb444fdc93p-72L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x7.2f26a663cb2f6da8p-152L, 0x9.fc2ec0983ea77b3p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x7.56ebed5f60ce8aa8p-128L, 0xe.ca8e0a5bcb1909bp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x7.9e2690fa1674f7p-4852L, -0x6.a2b3b3cd69bd69p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x5.61e2ca1189149e08p-8L, -0x3.489ad8567c6e09dp-4L, -0x1.77fd0cf88ee2c678p+0L, -0x1.77fd0cf88ee2c676p+0L }, - { -0xd.a2d0231770a0b2fp-4L, -0xb.11f2a040958b184p+108L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xd.566e196c5299a76p-4L, -0xd.827bfd05ebedd0fp-4L, -0xc.ab3ec5d1508e531p-4L, -0xc.ab3ec5d1508e53p-4L }, - { 0xe.690353be92b1ef7p-4L, 0xc.b40a6525370a3c1p-4L, 0xb.8f77d01ae6a411cp-4L, 0xb.8f77d01ae6a411dp-4L }, - { -0x4.a16f62e1fb463d7p-4L, -0xb.6a308232b3be302p-4L, -0x1.f4c81947d7e0267p+0L, -0x1.f4c81947d7e0266ep+0L }, - { -0xa.589c3c563d348fcp+108L, 0x3.aabe12c6cdd5648p+11880L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.2112dc65b51a2856p+16L, -0x2.f0fad09fd8f01c5p-108L, -0x2.9ad45124fc8c3a5p-124L, -0x2.9ad45124fc8c3a4cp-124L }, - { 0x6.501f9ed256bec01p-4L, -0xa.0150779e90ebc75p-4L, -0x1.02068c4d16492b4ap+0L, -0x1.02068c4d16492b48p+0L }, - { 0x3.57784bb97c2bfa94p-3436L, -0x8.16fa985eea51244p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x4.6510b53e44e358fp+108L, -0x9.2c631a27ad6ae34p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xd.5153d9f62ecffddp-4L, 0x1.7345ed4ae2d9f036p+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x7.a68b5532b0e7f568p-4L, 0x7.9a2907c3621d33ap-4L, 0x2.5bff699f72c04828p+0L, 0x2.5bff699f72c0482cp+0L }, - { 0xc.e8479ca0a43ef6p-8L, 0x9.182ad6a367d08aep-4L, 0x1.7b7995fca66e81cep+0L, 0x1.7b7995fca66e81dp+0L }, - { -0x1.26053714fd0be6bap-44L, 0xa.52ae9411f58887cp-4L, 0x1.921fb54442edffd6p+0L, 0x1.921fb54442edffd8p+0L }, - { 0xe.a227507d931299cp-104L, -0xd.13cf8aa40b87d27p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x1.e472b4341bef26b6p-56L, -0x1.7af3bd8ca1f57c42p-7268L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xd.f33b2053ffa6ae5p-4L, 0xa.8e75c696dc40c78p-4L, 0x2.7e69886741fe3d78p+0L, 0x2.7e69886741fe3d7cp+0L }, - { 0x9.85d3f0dd48eaf72p-4L, -0x3.541ae29b92aa4abp+72L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.5a3107a9603de8b4p-28L, -0x3.08af0a00602595fp-4L, -0x1.921fb4d2276f0c64p+0L, -0x1.921fb4d2276f0c62p+0L }, - { 0xf.cac159b69035579p-4L, -0x6.46e719cea85447d8p-4L, -0x6.0da354e1ed3337d8p-4L, -0x6.0da354e1ed3337dp-4L }, - { -0x5.987b05c45ed8a2ep-4L, 0x6.c4e52aa8d26db038p-4L, 0x2.42f6589620f3dab4p+0L, 0x2.42f6589620f3dab8p+0L }, - { -0x8.23b5b38feb155f2p+28L, 0x1.15a54236fe36bd4cp-56L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x1.f5ea7b800785d2ccp-4L, -0x7.ef6aaf1d13c7a7dp-4L, -0x1.541d373bdb2328c8p+0L, -0x1.541d373bdb2328c6p+0L }, - { 0x3.73e18f430b288f48p+5764L, 0xc.f70837877517a74p-4L, 0x3.c14c064e7addf6f4p-5768L, 0x3.c14c064e7addf6f8p-5768L }, - { -0x7.3487f80314c54488p-4L, 0x5.4eccb9e96eb8967p-4L, 0x2.81b5de701e1c753cp+0L, 0x2.81b5de701e1c754p+0L }, - { -0x1.2888c122fac324e2p-116L, -0xd.5620dcdef8d6adep-1048L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x1.a20b309dc63a3432p+100L, 0x1.d9633c032d4a9bc4p+11900L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.b49471d499a4cf1p-4L, -0x9.94f5bdecfacab51p-8L, -0x3.09798474778972c8p+0L, -0x3.09798474778972c4p+0L }, - { 0xf.641993c9a620462p-4L, 0xd.a2dd238869b2787p-4L, 0xb.99ab7575d6c73c4p-4L, 0xb.99ab7575d6c73c5p-4L }, - { 0xd.4c3f10c6378bac1p-144L, -0xd.a0da38c144c364ap-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x1.6795cd67133c419cp+104L, -0xf.5afa51a915c3c2cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xa.7324ede2d5b774ep-4L, 0x9.bd729cbbfe64c8ep+64L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.67af9a1b48f5476p-4L, -0xb.916f204d9b607e2p-4L, -0x1.10ac84512c1151bep+0L, -0x1.10ac84512c1151bcp+0L }, - { -0x9.a94b7284791aef1p-4L, -0xf.30d659afbbe444dp-4L, -0x2.2323d6dc698c7f1cp+0L, -0x2.2323d6dc698c7f18p+0L }, - { 0x1.15035f9ba3aac31ep-4L, 0xc.6f90a760827aa89p-124L, 0xb.7e126079e1ac136p-120L, 0xb.7e126079e1ac137p-120L }, - { -0xf.fef4a753b10a076p-4L, 0x6.4c2eb46758106918p-4L, 0x2.c43b45ae1e73a0e8p+0L, 0x2.c43b45ae1e73a0ecp+0L }, - { 0x1.3ef509e0c382df66p-4L, 0xc.49b63ac9b2b9eaap-4L, 0x1.78415d75aa039046p+0L, 0x1.78415d75aa039048p+0L }, - { -0x6.d057f880739cc278p-4L, -0x2.c6607086f9019804p+624L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x8.0a6f57c957a28d4p-4L, -0xb.e7e303842191512p+68L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.c50b391458918814p-168L, 0x2.b751311339e95d54p+40L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xb.51ba4b350a61c32p-4L, -0xc.0dfbf7e5e3212ffp-12L, -0x1.10a1458b2219c224p-8L, -0x1.10a1458b2219c222p-8L }, - { -0x7.6c639e488208ccc8p-4L, 0x3.a1d6c7b434bf3d98p-4L, 0x2.afc1c9bc173fb84cp+0L, 0x2.afc1c9bc173fb85p+0L }, - { -0x5.c358113ef832c348p-4L, -0xb.d7d98c530f97875p-4L, -0x2.060fd0c52c8ea69p+0L, -0x2.060fd0c52c8ea68cp+0L }, - { 0x1.3e90b4eb0efaf5fap-6916L, -0xa.5b3f67eed42f35ep-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x8.df34d29839f6cbap-76L, 0x8.6f95a977e54b54fp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x1.d6566fbbd43703bcp-4L, 0x5.7c58e6c483f58898p-4L, 0x1.e4db3a1a27a3fd2ep+0L, 0x1.e4db3a1a27a3fd3p+0L }, - { -0x2.35210275477555ccp-120L, -0x8.3dccba3b25f76c1p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xd.5f0d592ded19983p-4L, 0xa.c3b832d5003b707p-8L, 0xc.deb2302702560a9p-8L, 0xc.deb2302702560aap-8L }, - { 0xa.1061f8f22c56a2p-4L, 0x7.a0e695df486975a8p-4L, 0xa.60aca0123922aa8p-4L, 0xa.60aca0123922aa9p-4L }, - { 0x2.0f49c0d924c5ef48p-4L, -0x1.4c612171c559b0d2p-4L, -0x8.ffc2ff83f8bbf35p-4L, -0x8.ffc2ff83f8bbf34p-4L }, - { 0x7.5446c6842f5c1d88p-12L, 0x7.18f85d323644c07p-4L, 0x1.91175a864f920822p+0L, 0x1.91175a864f920824p+0L }, - { -0xb.e3d76e1e4bf5645p-8L, 0xa.e3f91773dee5cbdp-4L, 0x1.a390b3558878456ap+0L, 0x1.a390b3558878456cp+0L }, - { -0x6.64a485a65ba2bb8p-4L, 0xb.ab5d793764e46aap-4L, 0x2.126e03037b78e2a4p+0L, 0x2.126e03037b78e2a8p+0L }, - { -0x4.180ed04588b6b84p-4L, -0x3.1b46b393f7f02654p-4L, -0x2.7e12fe53471d28ep+0L, -0x2.7e12fe53471d28dcp+0L }, - { -0xb.12b6b696713dd3p-4L, 0x4.65ce2cb3797b29a8p+24L, 0x1.921fb56c8c50179p+0L, 0x1.921fb56c8c501792p+0L }, - { -0xa.3485ec95ca278f3p-4L, -0xc.4eeb5c35769e37p-4L, -0x2.43572f0e1543b008p+0L, -0x2.43572f0e1543b004p+0L }, - { 0x7.9916813ff5ff3cc8p-4L, 0xe.8cc5489d5bd410dp-4L, 0x1.16ec5e1241b086b4p+0L, 0x1.16ec5e1241b086b6p+0L }, - { -0x4.332914d9e18063ap-4L, 0x2.c3783d61fd7041fcp+324L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x7.8ea9558f03ae0e7p-4L, -0xf.dee9088b413455fp-4L, -0x1.205b027c87f0ec66p+0L, -0x1.205b027c87f0ec64p+0L }, - { -0x8.2df8e53739c9b8bp-4L, -0xb.237c6168dab68dbp-4L, -0x2.344698f98d5f286p+0L, -0x2.344698f98d5f285cp+0L }, - { -0xc.ff8006e798ca57dp-4L, -0xb.402101043dda93fp-72L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x7.837abefd5e55df78p-4L, 0x1.a83077ccca0d82acp-136L, 0x3.874cdd05c1765a8p-136L, 0x3.874cdd05c1765a84p-136L }, - { 0x3.a07b4d79ba0a5338p+28L, -0x4.bb21255de4a41a5p-4L, -0x1.4dee6dffdfcabca8p-32L, -0x1.4dee6dffdfcabca6p-32L }, - { -0x5.4eee2008ac59dda8p-24L, 0x2.d2b2eaf924487474p+8820L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.bbde2a7543c30b38p-4L, 0xb.8edecd5dd38da0cp-4L, 0x1.0b1331d46f6de5d4p+0L, 0x1.0b1331d46f6de5d6p+0L }, - { -0x6.c15f52803f443968p-4L, 0x3.918ec1969b0edd88p-4L, 0x2.a7d4fdd140e4ebecp+0L, 0x2.a7d4fdd140e4ebfp+0L }, - { -0xe.f6471a773b022bdp-8L, 0x3.3e6b054d350dcc9p-4L, 0x1.d9f9aa2df774d312p+0L, 0x1.d9f9aa2df774d314p+0L }, - { 0x6.81487cec2e861c7p-8L, 0x4.87a7a304beeda28p-4L, 0x1.7b3580ce6e5967ep+0L, 0x1.7b3580ce6e5967e2p+0L }, - { -0xd.c7238c1ad3cafc9p+88L, 0xe.ac1774f7032d1ffp-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x2.3f1854f194f5df1cp-128L, 0x1.014e18840001d972p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x5.040eb8c257682f18p-4L, 0xf.7346ad82e18af85p-4L, 0x1.41c34c3094d5a47cp+0L, 0x1.41c34c3094d5a47ep+0L }, - { 0xf.1cd1b7c493a3be6p-124L, 0x1.9e8c3ea1db7772dep+120L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.e13c582ac5e85888p-64L, 0x4.b2842fc0d4e29f8p-4L, 0x1.921fb54442d18452p+0L, 0x1.921fb54442d18454p+0L }, - { 0xf.a09a22b402060edp-4L, -0x8.e32395dc002f9bfp-8L, -0x9.1869589c28478e3p-8L, -0x9.1869589c28478e2p-8L }, - { -0xf.8c0db00bdf53596p-4L, 0x5.36e056abcab2faa8p-4L, 0x2.d167d9163e9e6a94p+0L, 0x2.d167d9163e9e6a98p+0L }, - { 0x7.6c92e56712d5affp-4L, -0x6.b6582996f57933c8p+124L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x3.0c9abaa8404f3e18p+140L, -0xa.e4299f2f9dca735p-4L, -0x3.926176c315d2215p-144L, -0x3.926176c315d2214cp-144L }, - { -0xe.d132e5394f60034p-10048L, -0x4.6ac0196a0af61fdp+72L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x9.ea2a7bd17c460dep-4L, -0x3.b176489ffeab233cp-80L, -0x5.f5c096bd8a9e69d8p-80L, -0x5.f5c096bd8a9e69dp-80L }, - { -0x7.e3d1eea20b324e7p-4L, -0x9.86088a50194e78ap-4L, -0x2.433d3f80c2defd8cp+0L, -0x2.433d3f80c2defd88p+0L }, - { 0x3.dfea4f893d4c581cp-3232L, 0xc.7be5695b1db3127p+100L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xe.e19314560029718p-4L, -0xa.e3c3bdecf1dec26p-8L, -0xb.b346fb302824719p-8L, -0xb.b346fb302824718p-8L }, - { 0x7.13c978b522f9333p-4L, -0x6.c0d55cd6c8226dd8p+16L, -0x1.921fa47fb9a46872p+0L, -0x1.921fa47fb9a4687p+0L }, - { -0x1.1d1ed153b343c44ep-4L, 0x7.6fdb8f997549cde8p-8L, 0x2.bf08ff529f82588p+0L, 0x2.bf08ff529f825884p+0L }, - { 0x2.7a077ab0456582fp+88L, 0xf.6e420d340620fd3p-4L, 0x6.3afbbdbf3e3239e8p-92L, 0x6.3afbbdbf3e3239fp-92L }, - { -0xe.6c4b7e894887c7fp-4L, -0x2.a9883b33131d202cp-4880L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xe.22b622d6cdf1548p+8L, -0x3.af9571884b9dea6cp-4L, -0x3.243b3e7ef45eb194p+0L, -0x3.243b3e7ef45eb19p+0L }, - { -0xb.a0a2f3e13b85a66p-4L, -0x5.5d35693a073a956p-80L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x1.22c95177a19486ep-100L, -0x1.09a01a4ee447f2dp-8L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x6.290348987c0e55f8p+136L, -0x4.20c946d47a37871p+4972L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xc.ad96dfac7b95172p-4L, 0x1.1fc7d37c0ec92196p+104L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.0d8c22a9e6d3c5p-4L, -0x2.31c152f5ee281b54p+11172L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x5.13c1489191b10628p-4L, 0x9.40268306f3eaf37p-4L, 0x1.119f5be56987a0b4p+0L, 0x1.119f5be56987a0b6p+0L }, - { 0x9.167509d85ac5562p+60L, 0x1.4b8f74471056531ep+12628L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.f7343ff72e27615cp-4L, -0x3.3ce0a42e5743e218p-3160L, -0xd.103c74c735aacefp-3160L, -0xd.103c74c735aaceep-3160L }, - { -0x6.19ec462854667938p-4L, 0xe.a753d50ad228a17p-4L, 0x1.f71fe9e91d7e6d3ep+0L, 0x1.f71fe9e91d7e6d4p+0L }, - { 0xb.2326e5c709d8338p-4L, 0xe.4cbeeba038e2a66p-4L, 0xe.8ba0b620906082cp-4L, 0xe.8ba0b620906082dp-4L }, - { 0x9.90137db5d8438f6p-4L, 0x8.f6fc2825e1cf803p-4L, 0xc.0cd4a9c04892b88p-4L, 0xc.0cd4a9c04892b89p-4L }, - { 0xb.a6e18f1dc982de2p+16L, 0x7.093038cd340d2eap-4L, 0x9.a9560c2566d537p-24L, 0x9.a9560c2566d5371p-24L }, - { -0x1.7d48f31379a2fd94p+13764L, 0x7.408cc4c84d37f818p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0xf.a038fe23264b69fp-4L, -0x5.d983ceba22bba45p-4L, -0x2.c88bec446ef69d7cp+0L, -0x2.c88bec446ef69d78p+0L }, - { 0x3.aaf0ce3e734d6f2p-4L, 0xf.72f358999238d68p-4L, 0x1.5673af7a281b339p+0L, 0x1.5673af7a281b3392p+0L }, - { -0x6.4d100f244be8113p-4L, -0x8.8a2584d61c785a5p+10256L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x6.e4c6b8c4d0181df8p-11840L, 0x2.88e3d82654a9a2d4p+84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xb.bac11f4e1e14036p-4L, -0x5.f466fe6cbdda3498p-4L, -0x2.abfd043f83efad38p+0L, -0x2.abfd043f83efad34p+0L }, - { 0x5.b28281e63f18c36p-40L, 0x1.5d03274c615fac7ep-4L, 0x1.921fb543fff47b6ap+0L, 0x1.921fb543fff47b6cp+0L }, - { 0xf.e3a0ddc922c2768p-4L, 0xa.669f21ff1f04159p-4L, 0x9.460446a2490498ep-4L, 0x9.460446a2490498fp-4L }, - { 0x8.ab617e168652f41p-4L, 0xa.9ceb33ff19c471bp-4L, 0xe.2c71acd10589374p-4L, 0xe.2c71acd10589375p-4L }, - { 0x7.e712d33d338b3f4p-4L, 0x1.bb5c92c3b346b3d2p-140L, 0x3.81a60c2164f42748p-140L, 0x3.81a60c2164f4274cp-140L }, - { 0xb.0f353c55a1bc86bp-4L, 0x2.a7aa43ef734cca24p-14752L, 0x3.d74b1fcceaff8cc4p-14752L, 0x3.d74b1fcceaff8cc8p-14752L }, - { 0x6.355f24aadd2d76cp-4L, 0x5.db625c7f505b3848p-4L, 0xc.19b1387d741a37p-4L, 0xc.19b1387d741a371p-4L }, - { 0x2.b76e057b32691f28p+56L, 0x6.dee852c47ad7ae6p-4L, 0x2.877c26e1b4786b5p-60L, 0x2.877c26e1b4786b54p-60L }, - { -0x6.bb1bf54be9664e8p-4L, -0x1.abb9e76137c068dcp-28L, -0x3.243f6a48f9ae83e8p+0L, -0x3.243f6a48f9ae83e4p+0L }, - { 0xf.db239caa0c58725p-4L, -0x1.a857f265390a97e6p+11340L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xe.d6bf659b8abbf88p-52L, -0x6.3520edf48c502b48p-4L, -0x1.921fb54442cf2076p+0L, -0x1.921fb54442cf2074p+0L }, - { -0x2.845d2338bd21f05cp-4L, -0x1.d3130e0c084f14c8p-4L, -0x2.83ae1a3982d00d2p+0L, -0x2.83ae1a3982d00d1cp+0L }, - { 0x7.e34ef80c4f7e3eep-4L, -0x5.a8b3cf39973ba25p-4L, -0x9.f50b2ea47c1075ap-4L, -0x9.f50b2ea47c10759p-4L }, - { -0x1.56bf999942c755dap+7896L, -0x9.80fe0cfc3618055p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x1.deff9f28444c6c38p-4L, 0x9.1da1f7cda29486bp+48L, 0x1.921fb54442d187b2p+0L, 0x1.921fb54442d187b4p+0L }, - { -0x9.24964216848ef53p-4L, 0x1.f0ed69f0e4821e64p-116L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0xc.7f839e0758c0fc4p-4L, -0xa.04266867c71fecep-4L, -0x2.774af214e503f1a4p+0L, -0x2.774af214e503f1ap+0L }, - { 0x1.8d5159b50fdc3fbep-84L, -0x6.ea56e501411dee98p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x6.108af52b9d9b2bp-4L, -0xc.1cbbb5c2e434abap-88L, -0x1.ff48471de69df2e4p-84L, -0x1.ff48471de69df2e2p-84L }, - { 0x5.d6a27cfc56ca253p-36L, -0xb.3fef5d7e57e0805p-4L, -0x1.921fb543bdf581a8p+0L, -0x1.921fb543bdf581a6p+0L }, - { 0xe.b53f2b3083d023ep-4L, 0xb.f408f69524f06c2p-4L, 0xa.eb4641b720503dbp-4L, 0xa.eb4641b720503dcp-4L }, - { 0x8.03baca4a7357516p-4L, -0xa.c1abbb69e26abf7p-4L, -0xe.e31b0d044e273ap-4L, -0xe.e31b0d044e2739fp-4L }, - { 0x1.d872e7eedaaa637ep-4L, 0x4.495ee30da4659e98p-4L, 0x1.2a0c770aea65c4c6p+0L, 0x1.2a0c770aea65c4c8p+0L }, - { -0xc.150a73ee88aac4bp-4L, 0x2.8fa0b8cb59d9a58cp-8L, 0x3.20db3e407d76332p+0L, 0x3.20db3e407d763324p+0L }, - { -0x6.08720c311ad69e78p-4L, -0x7.3b6b4ffd7b8decp-8L, -0x3.111a73de1561f32p+0L, -0x3.111a73de1561f31cp+0L }, - { -0x5.80db9fe644d1e708p-4L, -0x3.ec81c27ff8544994p-76L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0xb.656227303abf84fp-4L, 0x7.b40be4642e982ab8p-4L, 0x9.82b5d74d3bcff98p-4L, 0x9.82b5d74d3bcff99p-4L }, - { 0xa.049b6be5646929ep-28L, 0x7.c2408cb283b8a548p-124L, 0xc.644b5de744c024bp-100L, 0xc.644b5de744c024cp-100L }, - { -0x1.0d0aa693e23087aep-4L, 0xa.b0a2a7b4c6b0611p+80L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x8.4b1f02dac6cd4b9p-4L, -0xc.759d3a3d2bb277bp-4L, -0x2.28783fdcb3986748p+0L, -0x2.28783fdcb3986744p+0L }, - { -0x9.5efce40ef5c193p-4L, 0x1.3acdec63c75ba85ap-4L, 0x3.02d863b62e9ce0ep+0L, 0x3.02d863b62e9ce0e4p+0L }, - { -0x3.a8862397aa33d5bcp-4L, -0x8.40b99f3260074bbp-4L, -0x1.fcf094a049d0f47p+0L, -0x1.fcf094a049d0f46ep+0L }, - { -0x1.13ba9d07bc3a2952p+84L, -0x2.71006a8cb34d554cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x9.1553f4826cd4c82p-4L, 0xa.cf99c7754a95e18p+96L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.8114a9e190ab791p-60L, -0x4.9c18fd283d9a589p-4L, -0x1.921fb54442d183a8p+0L, -0x1.921fb54442d183a6p+0L }, - { 0xc.05b3f7d8b6f7624p-4L, -0x1.954b2fada5db23c6p+104L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x5.7aa677b8b3a14efp-4L, 0x6.8d1b5b54f8172e1p-4L, 0xd.fd0cb0efb607319p-4L, 0xd.fd0cb0efb60731ap-4L }, - { -0x4.a8455a7e3a68ed78p-4L, -0x4.7b4255a8c709f0ap-16L, -0x3.2430052b6ba121b8p+0L, -0x3.2430052b6ba121b4p+0L }, - { 0xf.331d018a51a3937p-4L, -0x3.eca2bd0c8570369p-4L, -0x4.0aeef8cb409b3868p-4L, -0x4.0aeef8cb409b386p-4L }, - { 0x6.52993e0816809a4p+1080L, 0xa.8f1f3b01d061b7dp-4L, 0x1.ab87a4c2ecb907f2p-1084L, 0x1.ab87a4c2ecb907f4p-1084L }, - { 0x2.293460674db2c4p-4L, -0xd.ea0bd2fdf3193cep-4L, -0x1.6aae49a397df62c6p+0L, -0x1.6aae49a397df62c4p+0L }, - { -0x7.7cc8ad228793eeep-4L, 0x3.3eb74cb49c028ad4p-4L, 0x2.bb8e137b5adb0bc8p+0L, 0x2.bb8e137b5adb0bccp+0L }, - { 0xe.bc5331958998244p-4L, -0x1.2903edbad4d00bdep-152L, -0x1.428000ee39f15116p-152L, -0x1.428000ee39f15114p-152L }, - { 0x5.3ee964d9303fef2p-4L, 0x9.0a14cf75dc8c935p-136L, 0x1.b92274ff2c1cfc2ap-132L, 0x1.b92274ff2c1cfc2cp-132L }, - { -0x6.e59cd2b304be20bp-8L, -0xd.25ced593ff0ac61p-4L, -0x1.9a83972861c5912p+0L, -0x1.9a83972861c5911ep+0L }, - { -0x3.1617c019abd659bp-4L, -0x6.690f39e52d0c90c8p-4L, -0x2.04fdb7e0f6ca2148p+0L, -0x2.04fdb7e0f6ca2144p+0L }, - { 0x9.1050fe64665d025p-4L, -0x1.fd861374d11ff0fcp+4216L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xd.953628a90529c68p+16L, 0x1.d0ef8f8c2df971eap-52L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x7.a4dabfc6c9e825b8p-4L, -0xb.f01119533e278e8p-4L, -0x1.00526ae79cfdf7bp+0L, -0x1.00526ae79cfdf7aep+0L }, - { -0x1.6396f574b56c6172p-4L, 0xf.b5e4a3223e61c14p-4L, 0x1.a8b2f2c93a739358p+0L, 0x1.a8b2f2c93a73935ap+0L }, - { -0x1.a1e72b708ae7ec3ap-84L, -0x1.cad34f8832df94b6p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xd.a82c5b229e8fe54p-4L, -0xc.337e6ec5ca09cbfp-4L, -0xb.aaa255a332a6dc7p-4L, -0xb.aaa255a332a6dc6p-4L }, - { -0x1.6666a8b8b12721dep+4L, 0x7.b2a783da083648ep-8L, 0x3.23e770d8aa1a524cp+0L, 0x3.23e770d8aa1a525p+0L }, - { -0x3.9a1204d27a81d9a4p+56L, -0x7.c2d56e73e1215768p-4L, -0x3.243f6a8885a308b4p+0L, -0x3.243f6a8885a308bp+0L }, - { -0x7.cfb667a4a3914a3p-4L, -0x2.365d2022bd55ec38p+8880L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xb.439e5356c702ad8p-4L, -0x1.c311b31d8db88c76p+12068L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xe.d87c88ea04cfc54p-4L, 0x7.5df293fec0fa7908p-4L, 0x7.5ec19b27ea9d83ap-4L, 0x7.5ec19b27ea9d83a8p-4L }, - { -0xb.f31341da10838b7p-4L, -0x4.94201f2127bae1d8p-4L, -0x2.c69340156b018bb8p+0L, -0x2.c69340156b018bb4p+0L }, - { -0xf.466813a0cb58997p-4L, 0x1.b40206802faf31f8p-4L, 0x3.07d2400cd8e729fp+0L, 0x3.07d2400cd8e729f4p+0L }, - { -0x1.73fa2d1e8f4aed4ap-8956L, -0xd.f8e6092df0a67cdp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x3.b170aeec21cbacep-124L, -0xe.4ffa3f0dccc1904p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x6.fa8da286037d29f8p-4L, 0xf.58e77980ec0ef84p-4L, 0x1.24debdfdda0fa8c4p+0L, 0x1.24debdfdda0fa8c6p+0L }, - { 0x8.5ae9b271c862bd1p-4L, -0xa.8fdf30d83ecd512p-4L, -0xe.6cae0678d6b6b55p-4L, -0xe.6cae0678d6b6b54p-4L }, - { -0x1.e689240cdaba32p-84L, 0xe.c5e20aeb268e22p+68L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xf.65a3e9387da5a2fp-4L, -0x2.f52bdc7095786358p-68L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x5.9a9d1446632f3aep-4L, -0x4.da74bc68acb86d9p+28L, -0x1.921fb5431b39c106p+0L, -0x1.921fb5431b39c104p+0L }, - { -0x8.7aea261756d25f3p-4L, 0xf.b5a3f9c32315f89p-4L, 0x2.10d707be6bdebe98p+0L, 0x2.10d707be6bdebe9cp+0L }, - { -0xe.7abe135a43a13e6p-4L, -0xe.63241d69fc37ac5p-88L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x3.2bf2a0a669999b48p-4L, 0x2.9affca93299785ep+5448L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.31c27de6118742f6p+7288L, 0x8.4ef4a64c01509a8p-4L, 0x6.f4cfe94bc3c887e8p-7292L, 0x6.f4cfe94bc3c887fp-7292L }, - { -0xd.d97824ee2873846p+60L, -0x3.d56d54e6a082a09p-9744L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x3.457eb22e95949aa4p-132L, -0x2.c7ad460f031ac6c8p-148L, -0xd.98a6edfdd4c7bcep-20L, -0xd.98a6edfdd4c7bcdp-20L }, - { 0xa.340ec3fa9c98451p-4L, -0x5.a130fe2bb18970cp-4L, -0x8.11219835b80db8cp-4L, -0x8.11219835b80db8bp-4L }, - { 0x2.36bf7820405b3b6cp-1364L, 0xb.c0ae25e2a801fc9p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x9.33aadc610c07076p-4L, 0xb.62d8d178f4ea271p-4L, 0xe.41f0912d1fc9e9ap-4L, 0xe.41f0912d1fc9e9bp-4L }, - { -0xb.de8017b99009994p-4L, 0xc.d14f3f856910093p-4L, 0x2.515ae28f032a6f08p+0L, 0x2.515ae28f032a6f0cp+0L }, - { 0x4.d809ec362c4289bp-104L, -0xc.5d2d16de94144fcp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xd.79e031e02305347p-4L, -0xa.c010f18d71bc8c5p-4L, -0xa.c60f92816aef05p-4L, -0xa.c60f92816aef04fp-4L }, - { -0x3.39af6943075c3b8p-13668L, 0x1.720bafd1b399ec82p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x4.fac18c7be7e011e8p-4L, 0xe.e7cda687036f7d6p-8L, 0x2.f58afa694e9eab6p-4L, 0x2.f58afa694e9eab64p-4L }, - { -0x9.9c2d0517aeee533p-8L, 0x1.cae7d85a2a39e2acp-3348L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x1.d28f44d13b0d6254p-12L, -0x5.fee8120e5e04be2p-4L, -0x1.926d85fbcd378c66p+0L, -0x1.926d85fbcd378c64p+0L }, - { 0x3.f3364f18a79b3b3cp-4L, -0x3.6b2dcf47d1901574p-144L, -0xd.d8fc6e63635a2c2p-144L, -0xd.d8fc6e63635a2c1p-144L }, - { 0x6.e5d1de6f1a858028p-8428L, -0xf.f7a6695a9469f6bp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x5.768672da4d7d0c9p-64L, 0x8.92179a4e3bb69e3p-4L, 0x1.921fb54442d1845ep+0L, 0x1.921fb54442d1846p+0L }, - { 0xb.ed688726df9befap-4L, 0x9.3f55bdfddb49b2bp-4L, 0xa.8d531b9fae50f96p-4L, 0xa.8d531b9fae50f97p-4L }, - { -0x3.9761f885a890c5f8p-148L, 0x3.fbc31466ed38546cp+112L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.5dbff56825b7dbb8p-4L, 0xa.e7a98283fc10855p-4L, 0x1.0ad966b89af0b16p+0L, 0x1.0ad966b89af0b162p+0L }, - { -0xc.2509016f44e196ap-4L, 0x7.861514480ac9199p-4L, 0x2.96425b66aa6752cp+0L, 0x2.96425b66aa6752c4p+0L }, - { -0xf.17da41cf884346bp-4L, -0xc.62d7c253621dcf7p+92L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x9.845c3e40ed6ad83p-8L, 0xd.68fda9eec5a66c2p-4L, 0x1.9d78b2079eeed2acp+0L, 0x1.9d78b2079eeed2aep+0L }, - { 0x8.18f925371b61292p-4L, -0x1.57f7c0849ebb346p-4L, -0x2.a182f2c02a69e4b4p-4L, -0x2.a182f2c02a69e4bp-4L }, - { -0x5.7255a940d84ebcf8p-104L, 0x7.1174b12c13aaf4e8p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xe.880fef5908d95bdp-4L, 0x7.609718a06f5f08ap-4L, 0x2.abfc8b95e8a16a24p+0L, 0x2.abfc8b95e8a16a28p+0L }, - { -0x6.e2bdbcf507ec4778p-4L, 0xa.20544abb2f768b5p-4L, 0x2.2aff89eb7f75b724p+0L, 0x2.2aff89eb7f75b728p+0L }, - { 0x6.14aea1523dfe3aa8p-4L, 0xc.97a55c9c85f26f9p-4L, 0x1.1ef5051994890448p+0L, 0x1.1ef505199489044ap+0L }, - { -0x8.680ab975830d106p-28L, -0x3.7b5dd7324be888fcp-4L, -0x1.921fb7ae5387a11ep+0L, -0x1.921fb7ae5387a11cp+0L }, - { 0xd.ff0ee4cab1a5c92p-36L, -0xe.008f2e366ac05f5p-4L, -0x1.921fb54342ecf648p+0L, -0x1.921fb54342ecf646p+0L }, - { -0xa.b9de710cc3240eap-4L, 0xd.b8496a7f5a40118p-4L, 0x2.3bfd545148e14c4p+0L, 0x2.3bfd545148e14c44p+0L }, - { 0xb.c810c87ed94addfp-4L, -0x3.0523d455a5644e6cp-11020L, -0x4.19f89145d6fd82p-11020L, -0x4.19f89145d6fd81f8p-11020L }, - { 0x6.b4a53b079af062ep-52L, 0x1.02b5df71e26e7eeep-4L, 0x1.921fb54442cae1cp+0L, 0x1.921fb54442cae1c2p+0L }, - { -0x1.05a95b1b36f384dcp-100L, 0x5.d8b77fd6db5f46fp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.b2d5aa2bd4f226c8p-4L, 0x1.3d87d39ca205f226p-4L, 0x5.2d5b7585602e1918p-4L, 0x5.2d5b7585602e192p-4L }, - { 0x7.58b591427632828p-4L, 0xd.51cbb799b3f3a26p-4L, 0x1.1116e6ac8ad3c638p+0L, 0x1.1116e6ac8ad3c63ap+0L }, - { 0x9.0e54bb10a5b7912p-4L, 0xa.7e81ca95f58d507p-76L, 0x1.28a7d33e5f568438p-72L, 0x1.28a7d33e5f56843ap-72L }, - { -0x5.1c6359354bd6cac8p-4L, -0x6.c6dd984bf0b457cp+11148L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x3.c17697f567f1596cp-7888L, -0xd.dd9a1c0c442c4c6p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x4.61b51c01df55d6d8p-4L, -0xb.dce6fd9bad9f495p-4L, -0x1.ecb365c6c3aa5084p+0L, -0x1.ecb365c6c3aa5082p+0L }, - { -0xa.b6f22a1b9f2939fp-4L, -0x3.4bb35afb05788e3p-4L, -0x2.d7db2978909722ap+0L, -0x2.d7db29789097229cp+0L }, - { -0x1.a1b675fb478bf18p+0L, -0x2.1ce57b45214ebd74p-4L, -0x3.0f9309e0cdbb0d7cp+0L, -0x3.0f9309e0cdbb0d78p+0L }, - { -0x5.067f9f48fc5b234p-8L, 0xb.a04244a598be88fp-4L, 0x1.9909c9c477bcd66cp+0L, 0x1.9909c9c477bcd66ep+0L }, - { 0xf.d97f1711de15f9cp-4L, -0x3.d24ecad1dffaabe4p-36L, -0x3.db97674bec9f4df8p-36L, -0x3.db97674bec9f4df4p-36L }, - { -0xc.deaf7691740cdefp-8L, 0xa.59b5d478c821a2ep-4L, 0x1.a5fa83821cba7646p+0L, 0x1.a5fa83821cba7648p+0L }, - { -0xd.1b186c2e3417901p-4L, 0xf.14939428966efa8p-4L, 0x2.49480ac2f173d45p+0L, 0x2.49480ac2f173d454p+0L }, - { 0xa.548931dd5b08516p-1308L, 0x3.0d860af72111fc38p-84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x2.379420afe91ec9c8p+40L, 0x6.381df51cf6ba1e58p-4L, 0x3.243f6a888576271cp+0L, 0x3.243f6a888576272p+0L }, - { 0xb.d0fe6ed90e574e6p-4L, 0x5.f4609ad6162545cp-4608L, 0x8.101632edfcc5ab9p-4608L, 0x8.101632edfcc5abap-4608L }, - { 0x1.925eaa29d2ecb61cp+44L, -0xd.ac66274a591f9a9p-4L, -0x8.b30fadfb09888a8p-48L, -0x8.b30fadfb09888a7p-48L }, - { 0x3.a5ddc4a5f3b82868p+64L, -0x2.bab320b85305843cp+11384L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x2.a982ac56625aefc4p-4L, 0x8.056940c538fa279p-4L, 0x1.e428e4e0f8cafb9p+0L, 0x1.e428e4e0f8cafb92p+0L }, - { 0x1.66b64b9c9f79a1dep-4L, -0x3.26b75fa52c7ce30cp-4L, -0x1.2703530602efb014p+0L, -0x1.2703530602efb012p+0L }, - { -0x9.da5604fb75e8d87p-116L, 0x8.f39b1339c38973dp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x7.677b36d2e1d48358p-4L, 0xa.996804efaa5460cp-4L, 0x2.2e38eedff366f594p+0L, 0x2.2e38eedff366f598p+0L }, - { -0x6.b6c06e4a29c88afp-4L, 0x5.a5149fe9b18171c8p-4L, 0x2.714657cddd0fa80cp+0L, 0x2.714657cddd0fa81p+0L }, - { -0x5.375a31264862647p+3840L, -0xc.55651fd1cbee3d4p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xe.006deb92f93d672p+1080L, 0xa.6871090121d471bp-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0xc.8ed445e1ea26da6p-4L, -0x3.70640030d409ab74p-4L, -0x4.46dbe31ace4e4798p-4L, -0x4.46dbe31ace4e479p-4L }, - { 0x8.8651cda5ac10d93p-4L, -0x6.dee1c8172006e6e8p-4L, -0xa.da9a82f5b8d481bp-4L, -0xa.da9a82f5b8d481ap-4L }, - { -0xb.b53f28201a854efp-4L, -0x1.0a2c69e331c156f6p+3472L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xd.e2cee7a54e7c7dfp-4L, -0x9.3f6896a8070ab3ep-4L, -0x9.667e289dbdd94abp-4L, -0x9.667e289dbdd94aap-4L }, - { 0x1.a1524a334652c37cp-4L, 0x1.9b7f6344a4875e14p-4L, 0xc.7435ca5edddaf34p-4L, 0xc.7435ca5edddaf35p-4L }, - { -0xb.4660bc20f1141f9p-4L, 0x6.cc440cbde57dd15p+3488L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xf.3adad3101e81209p-4L, 0xa.79ea74b25ad8a16p-4L, 0x2.89ff542b1f7b17e8p+0L, 0x2.89ff542b1f7b17ecp+0L }, - { -0xd.4d87683a39ac568p-4L, -0xd.0f2848388d6bd4fp-4L, -0x2.5d8d3b12422814a4p+0L, -0x2.5d8d3b12422814ap+0L }, - { 0x1.767ee6689d922d76p-20L, -0x1.705dc2d9924977d6p-4L, -0x1.921eb101c57d5742p+0L, -0x1.921eb101c57d574p+0L }, - { -0xe.de1ad3b0df8a929p-4L, -0xe.4bc9f399afa1199p-4L, -0x2.6033c43349c8a4bp+0L, -0x2.6033c43349c8a4acp+0L }, - { 0x9.4bc88b56990e957p-4L, 0x3.8aa0cdd01b00999p+7580L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x7.5dedd023859c58c8p-4L, -0xe.f93cd6eb00fb07ap-4L, -0x1.1d13330bde9cdc64p+0L, -0x1.1d13330bde9cdc62p+0L }, - { -0x6.3df3c6079972141p-4L, 0xb.fe0dd62537b23a4p-2520L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x4.d95e34fb8dacb328p-124L, -0x9.b353da0ba311c6dp-60L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xc.6abf9e7c57817a2p-4L, -0x4.3c1e721def125b9p-4L, -0x2.d01af5496f51c508p+0L, -0x2.d01af5496f51c504p+0L }, - { 0x7.2ddd2222b3f198a8p-4L, 0x7.db137d9811c79dep-112L, 0x1.18208ad22454d6c4p-108L, 0x1.18208ad22454d6c6p-108L }, - { -0x4.cf7eed0ba7ab4778p-4L, -0x3.cfde77dacc7baccp-96L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x3.c4fc5635219d094cp-116L, 0x3.f00c386330e300ecp-28L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xf.6b843b68893794cp-4L, 0xf.2a2645e05f54dbfp-8L, 0xf.b71cea10e6fa9dfp-8L, 0xf.b71cea10e6fa9ep-8L }, - { -0x4.baca2c1fc8c972dp+24L, 0x6.90fbdf3ee3bced38p-776L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x2.c5e571ee1dc3a27p-4L, -0x7.0180ac3e7e17ae1p-4L, -0x1.f29bd3e4a7c4ec62p+0L, -0x1.f29bd3e4a7c4ec6p+0L }, - { -0xb.fe012bea0b6470dp-8L, 0x4.e3d9edfbba7c4bcp+136L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.42c4c079e796e1dp-4L, 0x3.797b1939cea93534p-4L, 0x2.8ed2b02d7596067cp+0L, 0x2.8ed2b02d7596068p+0L }, - { 0x5.994c986ae0567538p-4L, -0x1.aee939e2fbdd15c2p-9024L, -0x4.cf6eca9b5e92e72p-9024L, -0x4.cf6eca9b5e92e718p-9024L }, - { -0x2.6ae2f779ed5c0b58p-10132L, 0xc.75fc43f9ad2a67ap-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.b4e98c673b461666p-4L, 0x6.fa4bd77c57afe13p+3972L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xe.14620d5210a675ap+72L, 0x8.3ab9c1257774a44p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x6.75bfbc7f917d7158p-4L, 0x3.8750adb31a46680cp-4L, 0x7.ffbf86632db338ap-4L, 0x7.ffbf86632db338a8p-4L }, - { -0x2.a07fb251cb4cf3bcp+6416L, -0x5.b501e8056d41ca2p-88L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x9.a0eb440277239eap-4L, 0xc.50af1095969ae95p-4L, 0x2.3bffb3aafd0b1948p+0L, 0x2.3bffb3aafd0b194cp+0L }, - { -0x8.c5fdbc4b0b452f4p-60L, -0x8.c888d45b054b19ep-4L, -0x1.921fb54442d1856ap+0L, -0x1.921fb54442d18568p+0L }, - { -0x4.1a164828ad307d9p-4L, 0xd.d06990220d829b5p-6340L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x3.709d5b044eff68ap-4L, 0x4.79f2d04625e53728p-4L, 0xe.a63d1a773c7886ep-4L, 0xe.a63d1a773c7886fp-4L }, - { 0x2.5d97ab2d70f6435cp-4L, 0xd.562ebf23b602612p-4L, 0x1.652ee26e7a2cbd9p+0L, 0x1.652ee26e7a2cbd92p+0L }, - { 0x1.e0fded40c3c2896ep-4L, 0x9.b2a0e063a00552bp-4L, 0x1.6121f3177cf3867ep+0L, 0x1.6121f3177cf3868p+0L }, - { -0xc.ea981936ab65ff9p-4L, -0xf.1e90b017130c6d5p-4L, -0x2.471c6550f0ab8d14p+0L, -0x2.471c6550f0ab8d1p+0L }, - { -0x8.fc9915b02547e54p-4L, 0x3.fd5dcb827e327bbcp-4L, 0x2.b9495a0e3741ecc4p+0L, 0x2.b9495a0e3741ecc8p+0L }, - { -0x1.b1ad8c2578262e12p-4L, 0x9.d1177d54049414p-4L, 0x1.bddecac7f2edd0d6p+0L, 0x1.bddecac7f2edd0d8p+0L }, - { 0x2.1253578fc85773e4p-4L, -0x9.c82e26cb2d7f53dp-4L, -0x1.5cb2d32b7dd67718p+0L, -0x1.5cb2d32b7dd67716p+0L }, - { 0xf.27497e66d5603e2p-52L, -0x1.106fbe1bb8bb675p-4L, -0x1.921fb54442c3472cp+0L, -0x1.921fb54442c3472ap+0L }, - { -0x2.834fa5093bae17c8p-4L, -0x4.be621d3bea89ab38p+64L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x8.b87762725b3d25ep-4L, -0xb.917c5b4d5562a58p-96L, -0x1.53990086a1a7d33ep-92L, -0x1.53990086a1a7d33cp-92L }, - { 0x1.232c19a7b93aed74p-4L, 0x6.c11fd7b2f21ba82p+84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.ca169f967701482p-4L, 0x3.959fe15d515a94ap-20L, 0x8.727c2adf96323fcp-20L, 0x8.727c2adf96323fdp-20L }, - { 0xb.d05c1485606d27ep-4L, 0x5.4c9a1c93895dca38p-6076L, 0x7.2d4b9799a5cc26c8p-6076L, 0x7.2d4b9799a5cc26dp-6076L }, - { -0xa.aa5f16e89aaf44cp-8L, 0x1.a020e5ecd83f5f0ap+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x9.4873bc564770dcap-4L, 0x9.a30d5a20e7f065cp-4L, 0x2.5665d2a4b1ec940cp+0L, 0x2.5665d2a4b1ec941p+0L }, - { 0x8.fb1811913b9bf9fp-4L, -0xf.92fca557186ff76p-4L, -0x1.0c3797d9ba60eabap+0L, -0x1.0c3797d9ba60eab8p+0L }, - { 0x1.5638b03330502364p+5720L, 0xc.61775f4969ec8fep-4L, 0x9.42ee4d5147e88c7p-5724L, 0x9.42ee4d5147e88c8p-5724L }, - { 0x1.72119aad9ca3b71ep-4L, 0xe.a69471f34698825p-4L, 0x1.78f2269fea0fe2bcp+0L, 0x1.78f2269fea0fe2bep+0L }, - { 0x4.012c7e08cbaa9478p-4L, 0x9.7bae07b48f3d186p-8L, 0x2.59db176e78ca1928p-4L, 0x2.59db176e78ca192cp-4L }, - { 0x6.fd5607efb3f922bp-4L, 0xa.5d0e52cf5ec81ep-4L, 0xf.a38cbd712f445c9p-4L, 0xf.a38cbd712f445cap-4L }, - { -0xb.3d5a0ceef37dac4p-4L, 0xa.7bf3bd59441655fp-4L, 0x2.6415b8938c9c69f8p+0L, 0x2.6415b8938c9c69fcp+0L }, - { 0xa.9cecb0eb313d3bp-4L, 0x1.34e865521b1a17b6p+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x6.d2e474b6031561b8p+92L, -0xa.5245ba426d8cb8dp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x3.d8775bbd6cd0492cp-4L, -0x4.e24c77188e4a7c38p-4L, -0x2.3ce04e2b601eabdcp+0L, -0x2.3ce04e2b601eabd8p+0L }, - { -0x2.208fc355984ce044p-4L, -0x5.bdde15084dbc54b8p-4L, -0x1.ecf436be968f6d2ap+0L, -0x1.ecf436be968f6d28p+0L }, - { 0xc.43cdb6d485f521ep-4L, 0x6.87c475984cf17fd8p+4L, 0x1.903eea125ad80b1ap+0L, 0x1.903eea125ad80b1cp+0L }, - { -0x4.dd382677670dd278p+0L, 0x2.a23ea828ab9892c8p-4L, 0x3.1b966a3063100448p+0L, 0x3.1b966a306310044cp+0L }, - { -0x3.8b954314786b23ap-136L, -0xa.9d6c0aac945f352p-8L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xd.2671cf0537f0221p+8056L, -0x4.d16dd659f3c0f0ap-4L, -0x5.dcbaf59e460c343p-8064L, -0x5.dcbaf59e460c3428p-8064L }, - { -0x6.feb91f876d8ea878p-4L, -0x8.81efd63e6be1cf2p-4L, -0x2.4249875056a07d8p+0L, -0x2.4249875056a07d7cp+0L }, - { 0xf.bc0fa0f885ca099p-4L, 0x5.7c08324a140957ap-4L, 0x5.5dc5ee9b879c424p-4L, 0x5.5dc5ee9b879c4248p-4L }, - { 0x4.edb009626e4967fp-4L, 0x3.37c8d44a2dd88cbp-4L, 0x9.413cc440ef46a35p-4L, 0x9.413cc440ef46a36p-4L }, - { 0x1.95eaf72aa7e08a9ep-4L, -0x8.1b7b5887913ebf5p-4L, -0x1.60ae1adef48fda1p+0L, -0x1.60ae1adef48fda0ep+0L }, - { -0xb.5359194b44145bbp-4L, -0x6.04e85f85770e42f8p+16L, -0x1.921fd35f3b27f2f2p+0L, -0x1.921fd35f3b27f2fp+0L }, - { -0xb.4501e0be159d16ap-4L, -0x1.fac44e7ef22a75e2p-8244L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x5.4c01faa961b17b48p-4L, -0x7.06bc16cdb0784c5p-4L, -0x2.377e1cc99262c594p+0L, -0x2.377e1cc99262c59p+0L }, - { -0xe.d9260d8b3735c8cp-4L, -0x8.ca13ee6d024020bp-4L, -0x2.9b6bee6c5172a15cp+0L, -0x2.9b6bee6c5172a158p+0L }, - { 0xe.1b10c6cf509583p-4L, 0xc.ce2bca2cbcab86p-4L, 0xb.cb38da4c1afe696p-4L, 0xb.cb38da4c1afe697p-4L }, - { -0x3.9a147b2294cce81cp+9392L, 0x8.35964c3a9d13241p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x7.2dae4682b4686c98p-4L, 0xa.762ab4fc1d5ab9bp-4L, 0xf.82b60dca04dac5ap-4L, 0xf.82b60dca04dac5bp-4L }, - { 0x1.c7999bbe18984522p+7836L, -0x5.73257b4e6064d01p-4L, -0x3.0fed7d28e284ea74p-7840L, -0x3.0fed7d28e284ea7p-7840L }, - { 0x3.8c2ba3fe7042d388p-116L, 0x7.d5dc9701e1e187bp+124L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xc.68e5a8454d59578p-4L, 0x7.1fd64b9a5df38ef8p-4L, 0x8.56a48c286152098p-4L, 0x8.56a48c286152099p-4L }, - { -0x4.881b83c2dca08bfp-116L, 0xa.91f8d787af80328p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.d1efe43682ae912p-4L, -0x3.528a6db95c7dfd34p-4L, -0x3.c65d2785eeb5cedp-4L, -0x3.c65d2785eeb5ceccp-4L }, - { -0x2.5775a364301f7598p+4216L, -0x5.c36184a826a997c8p-2260L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x3.7d2d5d25047b7ecp-128L, -0x7.fb0b49661b4b20b8p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x7.15fab912af52fa78p-84L, 0x1.8a9bf648a0c7536ap+136L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x1.e21c9844f30c3324p-44L, -0xa.36231bab07402b6p-8L, -0x1.921fb54445c4ebd4p+0L, -0x1.921fb54445c4ebd2p+0L }, - { -0x9.d3efb895e20c043p-4L, 0x6.44c77e7837d61e48p-4L, 0x2.92e529b4f918d0dp+0L, 0x2.92e529b4f918d0d4p+0L }, - { 0x1.b7e2cb7d51c65e38p-4L, -0x9.ab90feeee0a43a6p-4L, -0x1.651ad72533e8b13p+0L, -0x1.651ad72533e8b12ep+0L }, - { -0x1.705075c296c945a2p+8148L, -0xd.8fb34ea26dcd466p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x4.3b9909e92aa74c08p-4L, -0x5.5c31877c53bcf0bp-160L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x2.ab275d4d45f58b1p+40L, -0xd.f1e17f7d11f6ef4p-4L, -0x3.243f6a88854f6cdp+0L, -0x3.243f6a88854f6cccp+0L }, - { 0x8.5d50acd960ea87ap-4L, -0x3.cdaf1e5edd4c86p+48L, -0x1.921fb54442d1613ap+0L, -0x1.921fb54442d16138p+0L }, - { 0x7.1c63b6c0603b465p-4L, -0x5.06c95cd2eef04c08p+7836L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xd.4ef26051ededf26p-4L, -0x1.e5ffb4e52e88dbbp-60L, -0x3.243f6a8885a308bp+0L, -0x3.243f6a8885a308acp+0L }, - { -0x3.7a1dacb5eeed287p-4L, -0x2.75255c967504f764p-4L, -0x2.86bc274ba5844bep+0L, -0x2.86bc274ba5844bdcp+0L }, - { 0x9.43cd9e2120286b3p-4L, 0x1.1f40e2b07af92cdap-144L, 0x1.f012f92279311758p-144L, 0x1.f012f9227931175ap-144L }, - { 0xe.e44b7be402e1d81p-4L, 0x2.19395d52c4ffbbep-140L, 0x2.413416ce00a833e4p-140L, 0x2.413416ce00a833e8p-140L }, - { -0xf.099c3c9b804cd09p-8L, 0x6.c417103ca3c8b37p+384L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.8768dd184e3fbefcp+264L, 0x9.4f4b6e56944c6fep-4L, 0x6.16c8f28c7cc0ba38p-268L, 0x6.16c8f28c7cc0ba4p-268L }, - { -0xa.9b8d5570d3354bfp-4L, -0x3.44d2e445d54ef838p-4L, -0x2.d7b9029e74d35b4p+0L, -0x2.d7b9029e74d35b3cp+0L }, - { 0x8.d490d42bb07e2c7p-4L, 0x6.1bb3f5bd906ea9d8p-4L, 0x9.aeb69331ab83233p-4L, 0x9.aeb69331ab83234p-4L }, - { -0xb.d1da672fb0a4a6cp-4L, -0x3.cd44320f7cb17634p-4L, -0x2.d494aaaf940ef35cp+0L, -0x2.d494aaaf940ef358p+0L }, - { -0xe.e798701cb00ba65p-4L, 0x6.188c517655d962b8p-4L, 0x2.c0dc1cb781eb0c04p+0L, 0x2.c0dc1cb781eb0c08p+0L }, - { -0x5.a44cc952f2f84af8p-4L, -0x7.3f72b7eca34409f8p-2908L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x1.99cd1db7dfc4219ep-8264L, 0x8.4553ceee4227da5p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.a5fcc10d81eb5f18p+120L, -0x1.43edbd1c91c01de4p+112L, -0x5.8c967b142642a9f8p-12L, -0x5.8c967b142642a9fp-12L }, - { 0x1.5e17b3337849e126p-4L, 0xc.21be7e1f393f14fp-4L, 0x1.75634482719a6aa6p+0L, 0x1.75634482719a6aa8p+0L }, - { 0x4.4c7fdb3702f28548p-8L, 0xa.75cd63ad7a1fc3cp-4L, 0x1.8b8cbd8921671fd6p+0L, 0x1.8b8cbd8921671fd8p+0L }, - { 0xe.8b29d8cde8987f8p-4L, 0xd.887cf89ee3f6121p-4L, 0xb.fda4e7230ad4398p-4L, 0xb.fda4e7230ad4399p-4L }, - { -0x4.94c6afdd6c82228p-4L, -0x1.05fda0e408aa74dap-4L, -0x2.ebfb96a3f9a42878p+0L, -0x2.ebfb96a3f9a42874p+0L }, - { 0xa.3670397a0014cd8p-4L, 0x3.a35da38274ac5cap-4L, 0x5.79be30299d3f009p-4L, 0x5.79be30299d3f0098p-4L }, - { -0x1.6e3230adc36fa2d4p+72L, 0x2.46b281598ef2f5a8p+68L, 0x3.0adf2743dfff3e94p+0L, 0x3.0adf2743dfff3e98p+0L }, - { 0x2.60029db4ae9896f4p-4L, 0x9.b40053c694dc073p-4L, 0x1.54abbdf7c77fd402p+0L, 0x1.54abbdf7c77fd404p+0L }, - { 0x2.b4e66bc066d0d2dp-4L, -0x5.4231e76df18908fp-4L, -0x1.186f69ed098e7cbcp+0L, -0x1.186f69ed098e7cbap+0L }, - { 0x1.b1a6f7bbb2a87d3ap+4L, 0x2.811588b8fd1e13dcp-4L, 0x1.7a73376fe2e0dffcp-8L, 0x1.7a73376fe2e0dffep-8L }, - { 0x9.818682634b4f569p+48L, -0xd.948c0f98202cba9p-4L, -0x1.6db912400d2d0042p-52L, -0x1.6db912400d2d004p-52L }, - { 0x5.c78c1527fbed2cb8p-132L, 0xf.4d427c83cc48947p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x5.9703943df8daac68p-4L, 0xb.e333189d0552193p+108L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xd.9f9ad2fbb7114c8p-8L, 0x7.30036483bed4a05p-12L, 0x3.1bcf3458f84318fcp+0L, 0x3.1bcf3458f84319p+0L }, - { 0x2.a5a39f32557c8ep-4L, -0x3.170c659960195678p-4L, -0xd.cca65d3fe500765p-4L, -0xd.cca65d3fe500764p-4L }, - { 0x2.82da0a654e4b095cp-4L, 0x6.cf128f250e94a368p-4L, 0x1.37ac0c52f9b10dd8p+0L, 0x1.37ac0c52f9b10ddap+0L }, - { 0xd.76c3b09c76ff3e9p-4L, 0x9.07955929333661ap+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x5.81cb354b63bfe2p-60L, -0x1.87e903d0c3db82e4p+4L, -0x1.921fb54442d18466p+0L, -0x1.921fb54442d18464p+0L }, - { -0xa.2353060706c5cabp-4L, 0x1.fb0b63a1a1d40916p-11204L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0xd.5b6d7ec2493a866p-4L, 0xb.feeccb085d9a77fp-4L, 0x2.68eb2ca1b4fe66ccp+0L, 0x2.68eb2ca1b4fe66dp+0L }, - { 0xd.8290d23d319cf46p-4L, 0x7.8f36bd86059e0dp+60L, 0x1.921fb54442d18466p+0L, 0x1.921fb54442d18468p+0L }, - { 0x9.228ffe9d2dbc7a8p-4L, 0x3.4d0b2cb006ec1248p-76L, 0x5.c818c6860b871adp-76L, 0x5.c818c6860b871ad8p-76L }, - { 0x5.d6213cf1fe6c0418p-4L, 0x1.4fb6400683507e4p-108L, 0x3.9851a6b04169056cp-108L, 0x3.9851a6b04169057p-108L }, - { 0x1.2e57c4035227f4a4p-4L, 0x3.8b63b08dc84596bcp-44L, 0x3.004e3b1435fcb234p-40L, 0x3.004e3b1435fcb238p-40L }, - { -0x1.4360cd0166c1bb96p-96L, 0x5.6b1f6c08a8c74bd8p-48L, 0x1.921fb54442d1c016p+0L, 0x1.921fb54442d1c018p+0L }, - { 0xa.16180a40d8df5dap+5656L, -0x1.0b5029b46f526448p-4L, -0x1.a80a966ff0d212dcp-5664L, -0x1.a80a966ff0d212dap-5664L }, - { 0xf.cc3eef919eef062p-84L, 0x1.a712ef62b430fa34p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x5.f94934066073bd08p-4L, 0x6.09560f5c4171de98p-4L, 0xc.a65f6b1a7f95643p-4L, 0xc.a65f6b1a7f95644p-4L }, - { 0x7.901026e26c2bf698p-4L, -0xe.7c231718ee90eb4p-4660L, -0x1.ea50f230ad14fcbap-4656L, -0x1.ea50f230ad14fcb8p-4656L }, - { -0x3.6877a67287c33a24p-148L, -0xb.ccb04bd726e2f1cp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xe.92b733496bc40efp+104L, 0x3.7e80673dfbabc99p+104L, 0x2.e80131ce1300ed4cp+0L, 0x2.e80131ce1300ed5p+0L }, - { 0x2.f8fd52cb8aa2f7cp-24L, 0xd.8eb4579dad84402p-4L, 0x1.921fb1c22b2c5adap+0L, 0x1.921fb1c22b2c5adcp+0L }, - { -0x5.5efd70abd2079fd8p-4L, 0x5.f015b527caae88c8p-4L, 0x2.4e5dc999616481bcp+0L, 0x2.4e5dc999616481cp+0L }, - { 0xc.5b36895077a659cp-4L, -0xe.6156c69bf7850ffp+68L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xc.41d507fb40798b9p-4L, 0x6.044acf83853e4228p-4L, 0x2.af6dd05f6ba7bd54p+0L, 0x2.af6dd05f6ba7bd58p+0L }, - { 0xd.b86c5707774a4a2p-4L, 0x7.eedd2b5801d30ddp-4L, 0x8.6340d5849f75649p-4L, 0x8.6340d5849f7564ap-4L }, - { -0x6.f6e101329750c02p+0L, -0x7.d6f975423ed1769p-4L, -0x3.124429a16a9c980cp+0L, -0x3.124429a16a9c9808p+0L }, - { -0x3.be6d312c65754ef8p-80L, 0xb.cb682f76a3f814p-60L, 0x1.921fba586c06424p+0L, 0x1.921fba586c064242p+0L }, - { 0x1.8221ab8a45beb70ap-4L, -0x3.b4684654db9a5424p+140L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x9.2d8b2c3da2a1544p-4L, 0x5.24f70f7b34e69378p-4L, 0x2.a17623dc05226ce8p+0L, 0x2.a17623dc05226cecp+0L }, - { 0x8.691578498705b78p+80L, 0xb.3bee0e72b609f1bp-4L, 0x1.55f2221d830f232ap-84L, 0x1.55f2221d830f232cp-84L }, - { -0xc.da6a20364262f65p-4L, 0x2.4877b265ab1f3a8p-13304L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x4.405714e489cdecc8p-8L, -0xc.15f1a93e28bcd0ep-4L, -0x1.97c04dd68088ca78p+0L, -0x1.97c04dd68088ca76p+0L }, - { -0xb.073911421d09748p-4L, -0x1.b5c0a4dd8c1566fcp-4L, -0x2.fcde10ab4dd76134p+0L, -0x2.fcde10ab4dd7613p+0L }, - { 0xe.d559a68601d334ep-4L, 0x2.d0d0da1fed32adecp-4L, 0x3.005d3f535fcec9ecp-4L, 0x3.005d3f535fcec9fp-4L }, - { 0xc.eb3db51a4117749p-4L, -0xe.a7ff95de9e6b04bp+32L, -0x1.921fb54434b70d58p+0L, -0x1.921fb54434b70d56p+0L }, - { -0x9.b242f08632fe79dp-4L, 0xf.7392589b824fb9dp-4L, 0x2.21976ce06de5b27cp+0L, 0x2.21976ce06de5b28p+0L }, - { -0x3.866d6f28fe022bf8p-4L, -0xf.6920f8295b7bddcp-4L, -0x1.cbb12c5cf3020402p+0L, -0x1.cbb12c5cf30204p+0L }, - { -0xd.371b90dc936973ap+1584L, -0x2.03fc72188444e274p+1388L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xc.8841513e4940958p-8L, 0xf.dacd69f337492f8p-4L, 0x1.9ec2bc5751b6109ep+0L, 0x1.9ec2bc5751b610ap+0L }, - { -0x2.1b6b60da18fb188p+56L, -0x1.375db6599b3290d6p-144L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x8.4bc36bd85a13605p-4L, 0x7.511fbab815148398p-4L, 0x2.6b37dcb798ecddc8p+0L, 0x2.6b37dcb798ecddccp+0L }, - { -0x1.226db2320a4bbd76p-4L, 0xe.9620cf5661a993ap-4L, 0x1.a5fea59ad16975acp+0L, 0x1.a5fea59ad16975aep+0L }, - { -0xe.9dcdafd35f490bep-4L, 0xf.47291cfe1ffaef4p-4L, 0x2.558583302f17d3ccp+0L, 0x2.558583302f17d3dp+0L }, - { 0x3.73491a68bdddaaccp+144L, 0x8.aa229058b7ec91ap-4L, 0x2.82e01ab54a6a64ep-148L, 0x2.82e01ab54a6a64e4p-148L }, - { 0x4.ad7c3e0240e17358p-4L, 0xe.3ba47f6dc65238dp-4L, 0x1.40d60ca76f3b16bcp+0L, 0x1.40d60ca76f3b16bep+0L }, - { 0x3.392a62c6b703c4ecp-4L, -0xa.05c344dc8437ce9p-4L, -0x1.427790ebd5ffa4dap+0L, -0x1.427790ebd5ffa4d8p+0L }, - { -0x4.cfc2d12040fe801p-4L, 0x5.008114fbefa3ff4p+6792L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.430b313e463247bp-4L, 0x8.e2b7001bf08e40cp-140L, 0x1.6b43699da53b302ap-136L, 0x1.6b43699da53b302cp-136L }, - { 0x1.85dde85b05b8945p-4L, -0x2.f667e823e60719c4p-4L, -0x1.18910e0e7794c9bep+0L, -0x1.18910e0e7794c9bcp+0L }, - { 0x3.6dcf06d4e2c69044p-4L, -0x3.216851a5299104fp-4L, -0xb.d6c24b0a25b1c6dp-4L, -0xb.d6c24b0a25b1c6cp-4L }, - { 0x6.f6bb9a4c17f8e4c8p-4L, -0xf.d713d37adb465cp-4L, -0x1.2816ea59da6ddadep+0L, -0x1.2816ea59da6ddadcp+0L }, - { 0x1.0313a7bf52f62c6ap+12220L, -0x5.4b92638de9222f68p-4L, -0x5.3b792079fc7b5658p-12224L, -0x5.3b792079fc7b565p-12224L }, - { -0x5.07a5e167ee5ee938p-4L, 0xa.fe50b439a96ea55p-32L, 0x3.243f6a658d516568p+0L, 0x3.243f6a658d51656cp+0L }, - { 0x7.4d40bb5519f17438p-4L, 0x6.57ce3bc088dbf5bp-4L, 0xb.71a620269adc806p-4L, 0xb.71a620269adc807p-4L }, - { -0xb.344b56eb02935aap-4L, -0x2.aa06a7b698b0b3e4p-4L, -0x2.e87c4fa4fad0ed48p+0L, -0x2.e87c4fa4fad0ed44p+0L }, - { -0x7.d11224fd32351718p-4L, 0x3.7e5a21b23d5c1b64p-20L, 0x3.243ef81e138f1854p+0L, 0x3.243ef81e138f1858p+0L }, - { -0xf.a08ab502ee0f01p+144L, 0x6.cf1c3e55412fd6cp-128L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x6.48717c11cd853a38p+12L, -0xd.f459b71bee5f0a9p-4L, -0x3.243d31f5270113d8p+0L, -0x3.243d31f5270113d4p+0L }, - { -0x2.ae45f1d99d8191ap-4L, -0x1.6d0da510a3e13b48p+72L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.4f51a9b3e2d85878p-36L, -0x8.0b439abc08ea7e9p-4L, -0x1.921fb544192200cep+0L, -0x1.921fb544192200ccp+0L }, - { 0xe.7c272173ede747dp-8L, 0x2.2303df6a957df77cp+128L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.078697a133ad5cep-4L, 0xe.dbf635b5992761bp-4L, 0xd.9d5a5adb9750ca4p-4L, 0xd.9d5a5adb9750ca5p-4L }, - { 0xe.1ec636774861dd1p-4L, 0x6.90fde6638ef190ap-4L, 0x6.f6edca5da7e976ep-4L, 0x6.f6edca5da7e976e8p-4L }, - { 0x9.2892f7ae1a4dc1cp-4L, 0x9.59de5e82fe42ee3p-8L, 0x1.05074845332e8fbp-4L, 0x1.05074845332e8fb2p-4L }, - { 0xa.0bd8e2fed33d2fbp+48L, 0x7.1e8449954445192p-4L, 0xb.56981838fbcdfb4p-56L, 0xb.56981838fbcdfb5p-56L }, - { 0x6.9391bf7167786018p-88L, -0x5.ee980a26e834c06p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xb.c8e75dd8cc31c5fp+4172L, -0xa.56e2685bfa417eep+140L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x1.24a1e06c9ce90bacp+12L, 0x3.a60249453e7b9ccp-96L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x2.c8627289ae027344p-88L, -0x6.9b634305e9253b2p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.373f26e92bcb57d2p-144L, -0x2.e1e1c6f6c78bd3c4p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x9.70dc7ea202b3d6ep-4L, 0x1.a18f74fd6269755cp-4L, 0x2.f87376c50bbbb78p+0L, 0x2.f87376c50bbbb784p+0L }, - { -0x5.70d6e285f6741be8p-4L, 0x3.ba6b718acd54f7f8p-8L, 0x3.194a6a535ac8d614p+0L, 0x3.194a6a535ac8d618p+0L }, - { 0x2.6d98cc2767fd89d8p-4L, 0xc.808b2b8f5b868bp-4L, 0x1.610412f8c9e8121ap+0L, 0x1.610412f8c9e8121cp+0L }, - { 0xf.2e99194f7ef31f7p-4L, -0x2.e9a1c1b2321b87a4p-4L, -0x3.085f31e10671090cp-4L, -0x3.085f31e106710908p-4L }, - { -0x3.924e6e858ddf4824p-4L, 0x2.9a401dba30d7dcep+10456L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x6.5f0b8c236d8dc8f8p-2672L, -0x2.c8e3c20a2013488p+2656L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xd.d75e9619a100a7fp-8L, -0x4.91095f75c24e73a8p+12L, -0x1.921fe5c34e2b3f08p+0L, -0x1.921fe5c34e2b3f06p+0L }, - { 0xa.b860bc07bcd9d43p-4L, -0x1.5cffc658f2525a68p+32L, -0x1.921fb543c5005914p+0L, -0x1.921fb543c5005912p+0L }, - { 0x2.39efe79c36d491e8p-8L, -0xc.844c97b8d649ddcp-4L, -0x1.8f4732858a9cdac8p+0L, -0x1.8f4732858a9cdac6p+0L }, - { -0x3.bc36c1490d0a008cp-4L, 0x3.7373aa65594e9ba4p+28L, 0x1.921fb54557e72276p+0L, 0x1.921fb54557e72278p+0L }, - { 0x1.e030a1263fac45b6p-4L, 0x4.6a742a7f7f068b1p-4L, 0x1.2b4b21e62728d41cp+0L, 0x1.2b4b21e62728d41ep+0L }, - { 0x1.abcbe4707103d132p-36L, 0x2.63828893421a22a8p-4L, 0x1.921fb5438fba3b7ap+0L, 0x1.921fb5438fba3b7cp+0L }, - { 0xe.fa45bfa0e35be11p-4L, -0x2.6aa2a2cda06315ep-68L, -0x2.94dd051d34d86718p-68L, -0x2.94dd051d34d86714p-68L }, - { -0x5.033b46cdbeb340cp+16L, 0x3.8a8a6bba3cfe8078p-8L, 0x3.243f69d3aba38a3cp+0L, 0x3.243f69d3aba38a4p+0L }, - { -0x6.c85e2b71c3374258p-4L, -0x5.27a1297f363c8d48p-4L, -0x2.7de1bf0aef3c59b8p+0L, -0x2.7de1bf0aef3c59b4p+0L }, - { -0xd.3df3c95e345f91cp-4L, -0x2.d4dacdbb7574d32p-4L, -0x2.ee521baede0beaa8p+0L, -0x2.ee521baede0beaa4p+0L }, - { 0x3.e0f12593c01b4688p-4L, 0xf.2f0dd139a8e6154p-68L, 0x3.ea28b93c20ccdc1p-64L, 0x3.ea28b93c20ccdc14p-64L }, - { -0x7.0a9be4dfe4012efp-4L, -0x9.79c050222c1c028p-4L, -0x2.35ba688648eae5b8p+0L, -0x2.35ba688648eae5b4p+0L }, - { 0xe.69fc312b6c20148p-4L, -0xa.7ae82870e738fcdp-8L, -0xb.a0105da162b779dp-8L, -0xb.a0105da162b779cp-8L }, - { 0x1.9c08b5ae28dcf1ep-4L, 0x8.966bd426c329fd3p-4L, 0x1.62b1a3a4abfa30dap+0L, 0x1.62b1a3a4abfa30dcp+0L }, - { -0x9.7e7da70cdfaf86fp-4L, 0x5.9e39f65bc056fafp-4L, 0x2.9b75d071d8859284p+0L, 0x2.9b75d071d8859288p+0L }, - { -0x3.10308c990392d81p-4L, 0x7.5314fd852999079p-8236L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x5.2778b767dd6e12ap-4L, 0x6.8c1f80f76611751p-4L, 0x2.3cd97d6e9dd74d8cp+0L, 0x2.3cd97d6e9dd74d9p+0L }, - { -0x1.11d59a15316df40ep-88L, 0x1.b17a45abfaca7818p+84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x8.4fc3ad0329a03fbp-24L, -0x7.730ab999d45ba668p+36L, -0x1.921fb54442d1847cp+0L, -0x1.921fb54442d1847ap+0L }, - { 0xf.4ddfc0a6a7ff926p-4L, 0xc.a51ad22241bf9a4p-3400L, 0xd.3847934faa3ce58p-3400L, 0xd.3847934faa3ce59p-3400L }, - { -0x3.749a4e30ff80721p+132L, 0x8.653a7b58a965687p-8L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x6.0147c8355dcb5118p-4L, 0xa.bbdd8af3b148586p-4L, 0x2.14b363e8be093404p+0L, 0x2.14b363e8be093408p+0L }, - { 0x9.b485a2016e89ac8p-4L, -0x6.c0577b0cfdc16538p-4L, -0x9.b9887f0bf97893p-4L, -0x9.b9887f0bf97892fp-4L }, - { 0x1.f3982a7709f0cbp+40L, 0xf.70ce68e262f1e86p-4L, 0x7.e97ada86bdfd66a8p-44L, 0x7.e97ada86bdfd66bp-44L }, - { 0xa.00f17ea146af72cp-4L, 0xd.87fd71f7ada2ddap-4L, 0xe.f2621401a87f5aap-4L, 0xe.f2621401a87f5abp-4L }, - { 0xf.8d6956f54124902p-4L, -0x3.c7f4fe11df2d42d8p+104L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xe.dc1b8debe374cf4p+116L, -0xc.0eeac80f65e8216p-4L, -0xc.fbc762d00c60c7ap-124L, -0xc.fbc762d00c60c79p-124L }, - { -0xf.b4cea5f9045b01ap-4L, 0x1.0c2e698750b7e94cp-96L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0x8.d79e88a664c070ap-4L, -0xf.9450f9ab4f8d17p-4L, -0x2.1647280289f2978cp+0L, -0x2.1647280289f29788p+0L }, - { -0x6.eebd8fca95c9ca4p-8L, -0x2.7d3fe1c0d9eb617cp-4L, -0x1.be3dea5c2a040718p+0L, -0x1.be3dea5c2a040716p+0L }, - { -0x3.afe78e9efcbac40cp+140L, -0x1.68e1081fbf7d13e6p+1008L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x7.c520bfdab8a3eep-4L, -0x1.66b5c099afee3a44p-4L, -0x2.dacc8235e43513fp-4L, -0x2.dacc8235e43513ecp-4L }, - { 0x1.e4933a2a2ddf904p+136L, 0xd.784941952fe4cecp-4L, 0x7.1db8e5d213caf838p-140L, 0x7.1db8e5d213caf84p-140L }, - { 0x4.3c17087b908950fp+7148L, -0x3.735c047b159adcccp-4L, -0xd.099540663e33b06p-7156L, -0xd.099540663e33b05p-7156L }, - { 0xc.281ad4f7e7b2506p-4L, 0xd.32303b9dcb960d7p-4L, 0xd.38d23e57b79989p-4L, 0xd.38d23e57b799891p-4L }, - { 0x7.8695060ae1f9a64p-4L, -0x2.3be9aa14143c731cp+104L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x7.62db900b9f9d9668p-4L, -0x6.cfd1fde0bfa23d8p-4L, -0xb.eb61a702cf9e3e1p-4L, -0xb.eb61a702cf9e3ep-4L }, - { -0xf.bb4bad527dbb40ep-4L, -0x5.3e9ef2b10884ee28p-10036L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x9.5778bac96c5960dp-4L, -0x1.178465778778ce2ep+14336L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x8.7ef9939b4465e16p-4L, -0x3.51600c72922bbfc4p-4L, -0x5.f4fa36d23aa5506p-4L, -0x5.f4fa36d23aa55058p-4L }, - { 0x2.5131dd015a69e96cp-2408L, 0xa.870e0a37a4eeddcp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x2.880d15d9bf79a448p-4L, 0x2.446fd3d9665e1568p-4L, 0xb.afc7a6c62bd905fp-4L, 0xb.afc7a6c62bd906p-4L }, - { -0x2.31a4e2380b4c16cp-4L, -0x7.645911f7f5f4b208p-4L, -0x1.dbfbe65a7e307902p+0L, -0x1.dbfbe65a7e3079p+0L }, - { 0xb.2103d74317cc086p-4L, 0xf.771337e878bf499p-4L, 0xf.2704bf58b4bb6a8p-4L, 0xf.2704bf58b4bb6a9p-4L }, - { 0xe.861c26d80ccd5dfp-4L, -0x1.3d69ace2aa20b076p-36L, -0x1.5dac4c2bc3e57078p-36L, -0x1.5dac4c2bc3e57076p-36L }, - { -0x2.aff893fd182e92bp-152L, 0x4.141b510c6c3a2c78p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x8.56bda974ea2dec7p-4L, 0xa.7ba4137b5209863p-4L, 0x2.3e25e1fea85cbe24p+0L, 0x2.3e25e1fea85cbe28p+0L }, - { -0x6.80d745f6314c29dp-4L, 0x1.7c7e424cf77b8afep-76L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x6.cced41d6279d2138p-4L, 0x1.c0e570d143bef0eep-4L, 0x4.09a27a95df0f54cp-4L, 0x4.09a27a95df0f54c8p-4L }, - { 0x6.5df497b7697155a8p+1564L, -0x3.ddba85629b3426e8p-4L, -0x9.b723fdc7b00661cp-1572L, -0x9.b723fdc7b00661bp-1572L }, - { -0x4.760b9460983c0a5p-4L, 0x4.8c8e8f6197ef9bd8p-4L, 0x2.58aff93ef60ec054p+0L, 0x2.58aff93ef60ec058p+0L }, - { -0xd.529973ed01b4e92p-132L, -0x3.6712c0d838d018e8p-68L, -0x1.921fb54442d1846ep+0L, -0x1.921fb54442d1846cp+0L }, - { 0xc.1f8b7a784c26504p-4L, -0xa.67183c5cde7a566p-4L, -0xb.58bfac992b804b5p-4L, -0xb.58bfac992b804b4p-4L }, - { -0x6.19f5de19ed7257a8p-4L, -0x7.3398eb375f75dfb8p-4L, -0x2.46101795deb7d9d8p+0L, -0x2.46101795deb7d9d4p+0L }, - { -0x7.36616a1fa5db84fp-4L, 0xa.2ee450fb24733e3p-4L, 0x2.2fe288a6338d798p+0L, 0x2.2fe288a6338d7984p+0L }, - { -0x4.438c4fc90d39b8ep+96L, -0x7.4f02a205338a33ap-64L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x2.c8f196a2f3e8ed9cp-9224L, -0x3.03786e351e5ebe78p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xf.2253cc715933c65p-8L, 0x5.6a7fda73f84b1c18p-4L, 0x1.65dc717427bbf3f2p+0L, 0x1.65dc717427bbf3f4p+0L }, - { -0x2.a28f500b8a00b09p+14092L, -0x1.0843d15dc3b8cafp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xd.fca2fa696c2274ap-4L, -0x4.0718db0d5c58c15p-4L, -0x2.dc787f077ff8e63p+0L, -0x2.dc787f077ff8e62cp+0L }, - { 0x3.9a1be41771a60404p-4L, 0x1.80953538294166f8p-12L, 0x6.ac4fe9d96a3bf4f8p-12L, 0x6.ac4fe9d96a3bf5p-12L }, - { -0xb.7124296f93e8defp-4L, -0x1.98246e4efb47458ap-4L, -0x3.00ce24c21911792p+0L, -0x3.00ce24c21911791cp+0L }, - { 0xb.839f5cfd4cd5f2cp+8436L, 0xa.61c8331ffa99071p-4L, 0xe.6d3d4051b118d3p-8444L, 0xe.6d3d4051b118d31p-8444L }, - { -0x1.6b1b156ea818eb8p-4L, 0xf.d7c5e11a00df0a5p-4L, 0x1.a8fb6c440c3be30cp+0L, 0x1.a8fb6c440c3be30ep+0L }, - { 0x8.598d995551324f1p-4L, 0xd.e18c0d942a69d5bp-4L, 0x1.077d42bee50504fcp+0L, 0x1.077d42bee50504fep+0L }, - { 0x6.93e866ab2447886p-4L, -0x2.26e07207dc8de1ep-4L, -0x5.0f06179f8f3a16fp-4L, -0x5.0f06179f8f3a16e8p-4L }, - { -0xf.1ce9f7b3ca52b8bp-4L, -0x1.399c88aa8d8d6c48p-4L, -0x3.0f8ab40146b6b5f8p+0L, -0x3.0f8ab40146b6b5f4p+0L }, - { -0xe.ff04c61a0a89012p-4L, -0x6.cb47f83a640007dp-9320L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x4.593edb241f803048p-4L, -0x9.cafddfe1d9bc214p-4L, -0x1.fd1b36f82d14fef4p+0L, -0x1.fd1b36f82d14fef2p+0L }, - { -0x3.0d234ad1e46298a4p+1408L, -0xd.cb179b353f53154p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0xe.9bb1c73063ea02dp-4L, 0xd.8a2175b78a11721p-4L, 0x2.64e664936b63d554p+0L, 0x2.64e664936b63d558p+0L }, - { 0xc.25bdb8a9a8881b7p-4L, -0xc.89a9a53dd5661b4p-4L, -0xc.d1c03a780665391p-4L, -0xc.d1c03a78066539p-4L }, - { 0x2.977deccc5900dccp-84L, -0x2.a3636c60ad9b8408p-112L, -0x1.04971135aba73bc2p-28L, -0x1.04971135aba73bcp-28L }, - { -0x1.4529afc43bd67b0ap-4L, 0xa.bf1476588a5cb83p+80L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x8.ebeb881ae8c2fcap-6420L, 0xa.e0e4170c0a4427p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x8.e91c2aa2ea5ec68p-4L, 0x2.91145ecdbb7882f4p+28L, 0x1.921fb540ca177aacp+0L, 0x1.921fb540ca177aaep+0L }, - { -0xf.08bf0e198ffe894p-4L, 0xe.9bb609912a78d12p-4L, 0x2.5edd27ca99c98c7cp+0L, 0x2.5edd27ca99c98c8p+0L }, - { 0x6.df4e4b64d005f82p-4L, -0x3.51711830c018995cp-4L, -0x7.3271f7b631f74408p-4L, -0x7.3271f7b631f744p-4L }, - { 0x3.1bc6c41d7b8d2494p-4L, 0x2.f721c1af4835bb14p-8L, 0xf.3ec38f9992dee5cp-8L, 0xf.3ec38f9992dee5dp-8L }, - { 0xf.4bf5dfe195d4e46p+7524L, 0x3.bbc0f8f07321f77cp+128L, 0x3.e7b20446a0be4ef8p-7400L, 0x3.e7b20446a0be4efcp-7400L }, - { -0xb.bb95272e0c88a4p-4L, 0x1.fe9b64501151218ep-4L, 0x2.f923d79c3f550efp+0L, 0x2.f923d79c3f550ef4p+0L }, - { 0x4.77e9fc00fb36ca1p-4L, 0xf.5b06933a4845034p-16L, 0x3.6fbc6b1f82dbb2ecp-12L, 0x3.6fbc6b1f82dbb2fp-12L }, - { 0x4.4ec472736efece7p-4L, -0x8.3f36b704651a623p-4L, -0x1.16e56e8ac8595702p+0L, -0x1.16e56e8ac85957p+0L }, - { -0x3.debb4f1fb4f3d46cp-8L, 0x8.8d8721565b330cep+120L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x3.60900980dfa6490cp-4L, 0x4.9ad46fe7dab0a5f8p+28L, 0x1.921fb544fe921c84p+0L, 0x1.921fb544fe921c86p+0L }, - { -0x5.d267f39c0a2d5c6p+120L, -0x6.94c6171c5caa9048p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x9.737b170f2734c17p-4L, 0x2.6fc63483927fd61p+7936L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.aac7d5cdfa18f4aap+12364L, 0xf.407ea5dcda35ceep+7392L, 0x9.261246ae706ee0fp-4972L, 0x9.261246ae706ee1p-4972L }, - { 0x5.10a6eb0bc1141b7p-4L, 0x1.68d8f3bd3c6056ecp-108L, 0x4.73e1f9d1f9e61ff8p-108L, 0x4.73e1f9d1f9e62p-108L }, - { -0xc.81e5dc89785e982p-4L, 0xf.821c92eadfd4d2p-4L, 0x2.3fde7bb67cf34c8cp+0L, 0x2.3fde7bb67cf34c9p+0L }, - { -0x9.6cc05530d550225p-4L, -0x3.ae26297bd368fc24p-4L, -0x2.c4f1bbd66d554dd4p+0L, -0x2.c4f1bbd66d554ddp+0L }, - { -0xf.7c61983cdd60da1p-4L, -0xa.9226fd0725f5548p+11124L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xa.bb09710051dcf8dp-92L, 0x1.d1dbba4f78416e6p-8L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x1.3f0ca6d40320444p-4L, -0xa.0d32575627bcf09p-12L, -0x3.1c2f68820068be54p+0L, -0x3.1c2f68820068be5p+0L }, - { 0x1.e12b6bdf6a41d318p-4L, -0x4.925b19d467927c58p-4L, -0x1.2e446699a3dada42p+0L, -0x1.2e446699a3dada4p+0L }, - { -0x3.b5a3dd14cc35d0f4p-80L, 0xf.f1a968c614d2c7bp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xf.c50d2b0b4759078p-4L, 0xf.297abc86e6d6ca4p-4L, 0xc.4087639b48a9f52p-4L, 0xc.4087639b48a9f53p-4L }, - { -0xe.08a7a2500e47733p+14336L, -0x2.2abc93e7ce82e67p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x2.02ff48a6ae8c5d58p-4L, 0x2.44174246f08b0914p-4L, 0x2.4bfc95703b29449p+0L, 0x2.4bfc95703b294494p+0L }, - { 0xc.e44944bb412fcb9p-4L, -0xd.eb1d0c38abd1094p-4L, -0xd.2dc44265a1645cp-4L, -0xd.2dc44265a1645bfp-4L }, - { -0xf.f026fffa2c76775p+40L, -0x1.a72bc5f3fc609372p-4L, -0x3.243f6a8885a16004p+0L, -0x3.243f6a8885a16p+0L }, - { 0xb.8b25e8f233c9c46p-4L, -0x5.40149751018e5d7p-4L, -0x6.d46bc98b7c992a28p-4L, -0x6.d46bc98b7c992a2p-4L }, - { -0x5.2ce714d9965b9eb8p-4L, -0x3.d352663ddebb0c3p+2848L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x6.a8e6be614c1b8df8p-4L, 0x9.1772887aa9cf3dep-4L, 0xf.0469050950c1959p-4L, 0xf.0469050950c195ap-4L }, - { 0x2.9f08f6aee7d22224p+92L, 0xb.577c8e19d32b913p-4L, 0x4.53ae4466cb3e5e78p-96L, 0x4.53ae4466cb3e5e8p-96L }, - { -0x1.66b739c29828256ap+140L, -0xb.b90281c3323087ep-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x6.78ac8bb8ab809f28p-4L, -0x7.fbc375dd3564a3e8p+12L, -0x1.921ee5c0cd46c342p+0L, -0x1.921ee5c0cd46c34p+0L }, - { -0xf.8d21bd7dfb2bab3p-4L, -0x2.720b6221072b1ec8p+48L, -0x1.921fb54442d1ea2ap+0L, -0x1.921fb54442d1ea28p+0L }, - { -0xa.b8dbb59c7b569c8p-4L, 0x1.aeedca5050d1070cp-4L, 0x2.fc61e5dba0d3a35cp+0L, 0x2.fc61e5dba0d3a36p+0L }, - { 0x6.28b837f5eb0e965p-72L, -0x5.ebeaa439a80db7ep-76L, -0xf.5d50fec9b391b43p-8L, -0xf.5d50fec9b391b42p-8L }, - { -0xe.ddd4485dc420705p-4L, -0x1.10e4f9cc5932fd56p-10872L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x1.fb13b5cd1fc66386p-4568L, 0x5.cdd697b048eb7df8p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xc.d21e8ca674c3b8fp-8L, 0x1.7fbcd99b4b7c7f6ep-44L, 0x3.243f6a8883c423c4p+0L, 0x3.243f6a8883c423c8p+0L }, - { 0x9.4618839acbce14p-20L, 0x4.7f188b632b02a568p-4L, 0x1.921da546825dcbbap+0L, 0x1.921da546825dcbbcp+0L }, - { -0x3.bfd0635ddf97bef8p+11616L, -0xa.822efa7aeaf1e3ep-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x7.f80bf5f3503e7a08p-4L, -0x5.66fb0c9fd21294p-4L, -0x2.8bbc526a1520f534p+0L, -0x2.8bbc526a1520f53p+0L }, - { 0x5.8bca7ba191d1075p-4L, -0x3.e94049e7c0978424p+11256L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x7.926da2dc2eb3e0c8p-4L, 0xe.ebcfe2cc1e5917ap-4L, 0x2.0a57a10f93327888p+0L, 0x2.0a57a10f9332788cp+0L }, - { 0x9.9c87559b14bd69ep-4L, -0x3.1f5c367f6a8d3b5cp-4L, -0x5.069feaa26d81f0f8p-4L, -0x5.069feaa26d81f0fp-4L }, - { -0x1.f845d0e426ce9e3ep-92L, 0xc.f6cacd60d500638p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.36e65c677d6c8f6cp-8L, 0x1.d3eb9e3493db468p+72L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x9.434a0bafd4669fdp-116L, -0xc.0ab2fb511db1a65p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xa.040d4a425532027p-4L, 0xc.b3f2db4a1555938p-4L, 0x2.3d0c0848c1390774p+0L, 0x2.3d0c0848c1390778p+0L }, - { 0xf.0dd7437193656e6p-4L, -0x8.9e9261e5f0cbb96p-4L, -0x8.51ed7de5596cff5p-4L, -0x8.51ed7de5596cff4p-4L }, - { -0x5.fefa7ed009a1ad1p-4L, -0xc.d35706a15ac1dabp-4L, -0x2.02139e1fc30da4f8p+0L, -0x2.02139e1fc30da4f4p+0L }, - { -0x1.429576b6a439e36cp+8536L, -0xa.f28519810a83c71p-8L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x2.e66ff240855b11a8p-4L, 0x3.5c2fcc256af1f36cp+128L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x6.db01716e57cabb6p-4L, 0xd.c13cce87d39e616p-4L, 0x2.087db05ce82d89dp+0L, 0x2.087db05ce82d89d4p+0L }, - { -0x6.94f930f4029ebd6p-4292L, 0xc.6cd86a5a2553727p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.9db1698fccb05bb8p-4L, 0xf.1ca25184529230bp-4L, 0x1.55ff8e23c2cfab8p+0L, 0x1.55ff8e23c2cfab82p+0L }, - { -0x8.be66d03d7655fd6p-4L, -0x9.e5220481205cb59p+24L, -0x1.921fb552663f2e1p+0L, -0x1.921fb552663f2e0ep+0L }, - { 0x3.b723bd1111fd51acp-4L, -0x1.a4eb25964fa28b04p-8L, -0x7.142fe4a6d289e84p-8L, -0x7.142fe4a6d289e838p-8L }, - { -0xd.63ff921e325126cp-12464L, 0xf.1bc0b107e859569p+0L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x6.33fe53feb223e4f8p-4L, 0x1.8cebaea5077b3788p+24L, 0x1.921fb5844606fp+0L, 0x1.921fb5844606f002p+0L }, - { -0x5.9e2e3b14b66b70c8p-4L, 0x7.f59f3541b0d99908p-40L, 0x3.243f6a886ef7ccc4p+0L, 0x3.243f6a886ef7ccc8p+0L }, - { 0x6.f51f8676115f0248p+136L, -0x7.1da2696d46c614d8p-4L, -0x1.05d29a4a665da448p-140L, -0x1.05d29a4a665da446p-140L }, - { 0x8.0d6f53062b6d5dap-4L, -0x6.271f8f2a56b072ep-4L, -0xa.70782c23ee3d0bap-4L, -0xa.70782c23ee3d0b9p-4L }, - { -0xf.d56a354a71cc019p-7972L, 0x7.5aff86281b39de38p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xd.c44abbdbb28d90ap-4L, 0x8.4deb3d7fdbcc113p-4L, 0x8.af3d12fc8626167p-4L, 0x8.af3d12fc8626168p-4L }, - { -0xc.dd197fcdeb2df37p-1016L, 0xd.d1ae353afc701eep-24L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x7.d2c387b3911c47dp-4L, -0x1.bc0ab21990f1029p-144L, -0x3.8c2481f80c0e7ca8p-144L, -0x3.8c2481f80c0e7ca4p-144L }, - { -0x6.3cb6cb3574d1d9f8p-4L, -0x6.96d3daf1b089a66p-4L, -0x2.5429717f7e7c73bcp+0L, -0x2.5429717f7e7c73b8p+0L }, - { -0x4.39d33a8bd7344ee8p-32L, -0x3.60b3af53040b6134p+132L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x9.a8b4f46185e5f1ep-4L, 0xe.2d87496db29944bp-4L, 0xf.9060956959d726ap-4L, 0xf.9060956959d726bp-4L }, - { -0xd.667041c980fb86ap-8L, 0x8.86bc2686850d445p+44L, 0x1.921fb54442d19d8ep+0L, 0x1.921fb54442d19d9p+0L }, - { -0x4.50e215fa10553d48p+8L, -0xf.b3f92be44496d7dp+120L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xd.f212d18f02b8957p-4L, 0x1.bdfe0c435f3ecb6p-72L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x2.43e5d27672761aep-4L, 0x3.5eaa54a49a4ae46p-856L, 0x1.7cd46c8fb5f07dccp-852L, 0x1.7cd46c8fb5f07dcep-852L }, - { 0x3.abc16e9612cf3498p-4L, 0x7.181a2f454b0cdc38p-4L, 0x1.17e13b779b179daep+0L, 0x1.17e13b779b179dbp+0L }, - { -0x3.effb9151b19d3bc4p-4L, -0xd.6d8e757bfced33fp-4L, -0x1.db249c4f5ddbb53p+0L, -0x1.db249c4f5ddbb52ep+0L }, - { -0x4.1c7675db4a13c528p-8L, -0x5.916912756e511cc8p-44L, -0x3.243f6a886ff7966cp+0L, -0x3.243f6a886ff79668p+0L }, - { -0x9.ae36136241e082p-4L, -0xa.e229ff39b139c49p+36L, -0x1.921fb54443b538c4p+0L, -0x1.921fb54443b538c2p+0L }, - { -0x8.ea7441c1fcae2c9p-4L, -0x3.1ec5e57752e627dp-4L, -0x2.ce114af4e63febacp+0L, -0x2.ce114af4e63feba8p+0L }, - { 0xd.2ba2276ff04dde1p-4L, -0x1.036ccaf8131b87e4p-4L, -0x1.3a8a5ba2fe62b7f6p-4L, -0x1.3a8a5ba2fe62b7f4p-4L }, - { 0xe.8b06f66a6205032p-4L, -0xd.ae112e1be26b88dp-4L, -0xc.13c3c7343dcb262p-4L, -0xc.13c3c7343dcb261p-4L }, - { -0xd.95c2feeb327b501p-4L, -0xe.f8f263f130a717ap-4L, -0x2.4ec20c3ac11aba8p+0L, -0x2.4ec20c3ac11aba7cp+0L }, - { 0x3.f769c52f22e30058p-140L, 0x8.46e4f1b98e2ba04p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x1.e4581b83724c3aeep-7320L, -0x8.53fa90b742c3c73p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x4.9d47118131cc5d58p-4L, -0xa.e9fb23a5f0ee204p-4L, -0x1.2bb947cf278427fap+0L, -0x1.2bb947cf278427f8p+0L }, - { -0x7.cbd5551ff762f788p-4L, -0x8.c9f6a15fcc211ap-8L, -0x3.123d7d5448f77928p+0L, -0x3.123d7d5448f77924p+0L }, - { -0xe.83b3579c4b7fd68p-112L, -0xd.200e63e91fae96p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x6.957c45c90a7c23ap+96L, 0xd.ce8bdb00853c926p-4L, 0x2.18d83b8b49fb8b3cp-100L, 0x2.18d83b8b49fb8b4p-100L }, - { 0xf.0b8ed1b50e825c8p-8L, 0x6.ed7085987456212p-12700L, 0x7.5dfe047fcd4cf058p-12696L, 0x7.5dfe047fcd4cf06p-12696L }, - { -0x4.176212e7c4ecbaap-4L, -0x6.93d4b9e5fd90fb28p-124L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x6.5877ca61dc57f7b8p-4L, -0x4.d2f3a82b21bdc158p-80L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x7.95f214f6efdcd0fp-4L, -0x6.68bbadffe256848p-4L, -0xb.396dd5127435ff2p-4L, -0xb.396dd5127435ff1p-4L }, - { -0xf.e9e97c18e559f59p-4L, 0x9.f5b28b8c5abdfbdp-4L, 0x2.95168d1a7a401db4p+0L, 0x2.95168d1a7a401db8p+0L }, - { 0x2.055b1777b282e33cp-1508L, 0xa.ddd851824e9cc4dp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xb.5eaa19741f96466p-4L, 0x6.947f8b39e9330e3p-4L, 0x8.64e80eb23f4e797p-4L, 0x8.64e80eb23f4e798p-4L }, - { 0x8.0caee3998490c06p-4L, 0xb.fdd5aaea1f21087p-4L, 0xf.ac80644d42f8741p-4L, 0xf.ac80644d42f8742p-4L }, - { 0x7.2dab42195d9c94bp-4L, -0x1.1432f4dd5422d976p-40L, -0x2.679f7d784fd215a8p-40L, -0x2.679f7d784fd215a4p-40L }, - { 0x1.4606e76e580b8a0cp-4L, 0x3.0f05b15d1a1c90ccp-4L, 0x1.2d1f3eca25e48488p+0L, 0x1.2d1f3eca25e4848ap+0L }, - { -0x8.5ed70349b636516p-4L, -0x7.b69c3fd741b5e678p-12912L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x4.681599c48280feb8p-24L, 0x3.c6a8b9f4986a9634p-4L, 0x1.921fc7f043a898ep+0L, 0x1.921fc7f043a898e2p+0L }, - { 0x4.04dc8898d9c85308p+9536L, -0x2.5df4adcca608ba98p-12L, -0x9.6c5ece3961e7b91p-9552L, -0x9.6c5ece3961e7b9p-9552L }, - { 0xa.83e14bca0dac3fdp-4L, -0x1.5c01106a0de1ffeap-4L, -0x2.0e9b5df42dab89bcp-4L, -0x2.0e9b5df42dab89b8p-4L }, - { 0x8.2cdf755e03ecc16p-4L, 0x6.a1b1ca60f56fa998p-4L, 0xa.e781da0ed69665ap-4L, 0xa.e781da0ed69665bp-4L }, - { -0x3.039964d84c1627d4p+116L, 0xb.e6ab265f4ede4b9p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x3.3fb4865ddd19c4a4p+44L, 0xc.d231d5c4e611168p-4L, 0x3.f243987c6bb87648p-48L, 0x3.f243987c6bb8764cp-48L }, - { -0x8.72d7be8c1ce0c13p-4L, 0xc.16abe5e217ed38fp-4L, 0x2.2e4782208e9be82p+0L, 0x2.2e4782208e9be824p+0L }, - { 0x1.6310b10d9de5d426p+88L, 0x5.4a1938838acdc4fp-4L, 0x3.d04c201d8bb1fa2p-92L, 0x3.d04c201d8bb1fa24p-92L }, - { 0x8.5b4b0396d43ee47p-4L, -0x9.4834e879d5b0849p-4L, -0xd.67b2a76f016882ap-4L, -0xd.67b2a76f0168829p-4L }, - { 0x7.753bb7b8c25f952p+2888L, 0x3.e7a2599013f5192p-4L, 0x8.609439e6466766ep-2896L, 0x8.609439e6466766fp-2896L }, - { -0x1.fa942bc5b553041cp+12L, -0x6.6c53ede2a18a2428p-4L, -0x3.243c2b9225dff5d8p+0L, -0x3.243c2b9225dff5d4p+0L }, - { 0xa.47ea2dd67ff54e3p-4L, -0x7.d552135c630eca7p+140L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x5.b62f47f1376eb4d8p-4L, 0xa.1da7e265035a3c4p-4L, 0x1.0e8a0d4a9838070ep+0L, 0x1.0e8a0d4a9838071p+0L }, - { 0xd.5462bb61c9e0743p-4L, -0x3.e94008a1b69179f8p+2368L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x3.c6b50185720acab4p-4L, 0xc.e8153da96b4043fp-4L, 0x1.dafd8f82584b3aep+0L, 0x1.dafd8f82584b3ae2p+0L }, - { -0x6.6e228eb9c146093p-144L, 0xa.b6c4172198a391ap-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x2.a1bcbf92db38e4f8p-4L, 0x1.578aa97b6aa2f6a4p-120L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x4.03871323508d2208p-92L, 0x1.b7b42b180b7a5baep-4908L, 0x6.d8c6e23c0a17926p-4820L, 0x6.d8c6e23c0a179268p-4820L }, - { 0x1.e866d68d12e3d6e2p+64L, 0xc.ace2470bdb01192p-4L, 0x6.a4d586910831b16p-68L, 0x6.a4d586910831b168p-68L }, - { -0x2.a5ce182e00368394p+10688L, 0x1.c403d9c62d035c8p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0x8.cac1a823d3b98bep-4L, 0x2.4dd80bb46880fd0cp+3768L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0xa.74b0b9f237195bfp-8L, -0xd.4880b498179975bp-4L, -0x1.858a2858781939d8p+0L, -0x1.858a2858781939d6p+0L }, - { -0xd.9c03b986ebe4541p-4L, 0xb.a372ba15d4c940dp-136L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { -0xa.76ccb7d81a5c5b8p-4L, -0x7.d178643f841cbc08p-4L, -0x2.7ffa8c7878fe5444p+0L, -0x2.7ffa8c7878fe544p+0L }, - { 0x8.992f6f29de9baa1p-4L, -0x2.6df885a56ac520b8p+84L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xc.c702ea51f29dd29p-4L, 0xc.52b96380b86a72ep-4L, 0x2.5fd171ce65416f68p+0L, 0x2.5fd171ce65416f6cp+0L }, - { 0x7.7da787b409a377c8p-4L, 0x4.bf0678273f028cd8p-4L, 0x9.09413df2baa84dfp-4L, 0x9.09413df2baa84ep-4L }, - { 0x7.e356b90a1e983p-4L, 0x5.657e1e60ee4799e8p-4L, 0x9.99959836d098709p-4L, 0x9.99959836d09870ap-4L }, - { -0x6.68cb8626a1a7bd2p-4L, 0x2.9433b04900ebb9p-4L, 0x2.c250ed62efbc5ed4p+0L, 0x2.c250ed62efbc5ed8p+0L }, - { -0x7.6704a5d84d429278p-12L, -0x2.53c60f0888101e64p+48L, -0x1.921fb54442d1849ep+0L, -0x1.921fb54442d1849cp+0L }, - { 0xf.a61176890fa8bdbp-4L, -0xc.17e8c4b326c4b6ep-4L, -0xa.86e92eeee828f27p-4L, -0xa.86e92eeee828f26p-4L }, - { -0x2.c555f1be423d02fcp-464L, 0x1.7c6eeead727f952ep-8L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x1.551ff116c5c06a1ap-116L, -0x2.bbf4a7d991feb2d4p-120L, -0x3.0398704f0e5afc7cp+0L, -0x3.0398704f0e5afc78p+0L }, - { 0x4.6e41b8acdd8f85dp-4L, -0x3.f4ef9b082435ce7cp-148L, -0xe.49e3b21a45821f7p-148L, -0xe.49e3b21a45821f6p-148L }, - { -0x6.40c5ab955d01a03p+5648L, -0x2.0979098b1bd5dbp+9916L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0x6.3b075dc7d59d685p-4L, -0x2.f48fe76be3d44e1p-152L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { -0x3.f74277ed265e015cp+60L, 0xc.480fd8d360f7142p-4L, 0x3.243f6a8885a308ccp+0L, 0x3.243f6a8885a308dp+0L }, - { -0x2.b74e97b30cacec2cp-4L, 0x6.47bd6d76772ae9ep-4L, 0x1.fa9e81a87803b58ep+0L, 0x1.fa9e81a87803b59p+0L }, - { -0x3.e4752a427feefdap-4L, -0x3.648ca3460f50fc28p-4L, -0x2.6cb7357e013e0c08p+0L, -0x2.6cb7357e013e0c04p+0L }, - { -0xa.338bb51e509e044p-152L, 0xb.f2d1dac2e74ad02p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.a03ed9b66660c09p-4L, 0xa.794c188e703dab8p-4L, 0x1.3ccdefaeb1710678p+0L, 0x1.3ccdefaeb171067ap+0L }, - { 0xb.2f3e3d838ebed4bp-4L, -0x4.eafc2cc3463c771p-6788L, -0x7.09091cfdd29e7dfp-6788L, -0x7.09091cfdd29e7de8p-6788L }, - { -0x8.684872e3380a1fdp+6060L, -0x4.bd8d34ac79591d58p+52L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, - { 0x5.6fb79843c82e2c1p+5652L, -0xa.dec92754a1fe74dp-5540L, -0x1.ffe1755d00a766b8p-11192L, -0x1.ffe1755d00a766b6p-11192L }, - { 0x5.c1b1d1b6b056b648p-108L, -0x6.4e37b8f49a0b21f8p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0x1.1c741352a9784764p+12044L, 0x1.7ffaf524a6c9d0e4p+7808L, 0x1.59924535f3025922p-4236L, 0x1.59924535f3025924p-4236L }, - { 0xa.36099fe806b84fcp+56L, 0x2.dfb4d2b6b161659cp-6848L, 0x4.80cbe1da75a10368p-6908L, 0x4.80cbe1da75a1037p-6908L }, - { -0x4.5190f0b1846ea89p-4L, 0x1.c37f5ed30d4ba53p+48L, 0x1.921fb54442d1ab96p+0L, 0x1.921fb54442d1ab98p+0L }, - { -0x4.0a6d4d991fcb0778p+8L, 0x2.90b4f02d88546e28p-4L, 0x3.2435422f3623d1fp+0L, 0x3.2435422f3623d1f4p+0L }, - { -0x6.f97d9ace617c1f1p-4L, -0x9.e638c81b7bb9dp-4L, -0x2.2f40065b511baef4p+0L, -0x2.2f40065b511baefp+0L }, - { -0x9.99f82f11bf88bbcp-4L, 0xa.7ea03cd6316368dp-4L, 0x2.4fd0aaeea4bea7acp+0L, 0x2.4fd0aaeea4bea7bp+0L }, - { 0x8.02f1895758feb2dp-8L, -0x1.b831b2fcec2b3d52p-4L, -0x1.49953e75cd87d946p+0L, -0x1.49953e75cd87d944p+0L }, - { -0x5.07e7aa225447584p-10264L, 0x4.4629c3e0a37fba8p+68L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.052f08bb6e5732c8p-4L, -0x5.0d5e419c51e0f3ep+116L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { -0xc.6dfcb7adf3a11cdp-4L, 0x1.121df88ac0598a6p-4L, 0x3.0e3f9f78b370d72p+0L, 0x3.0e3f9f78b370d724p+0L }, - { 0x5.d3cac7f6bdbb7e8p-13848L, 0xa.1583e5fa5a9dd55p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x5.d272fc700a86f688p-40L, 0x5.76e058e105a436p-4L, 0x1.921fb54453dda5f6p+0L, 0x1.921fb54453dda5f8p+0L }, - { 0xb.68c49383bb035d6p-4L, 0x4.ae54afae863ae4a8p-4L, 0x6.3ab8c728eac35168p-4L, 0x6.3ab8c728eac3517p-4L }, - { -0x8.81cb17de14581dbp-4L, -0x1.c2dcac66d7f29b12p+11656L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xb.0ae3fdc98ddc34fp-4L, -0xc.0b6e288dced796bp-8L, -0x1.16ccf2c7fd07e9aap-4L, -0x1.16ccf2c7fd07e9a8p-4L }, - { 0xe.c573d472a847a96p-8L, -0xb.8ff6fcd64ef65e6p-4L, -0x1.7dba02db709d9a0ap+0L, -0x1.7dba02db709d9a08p+0L }, - { 0x1.c2eb0a9ea7a016e8p-4L, 0x2.837abafcbe11a118p+20L, 0x1.921fb490de793956p+0L, 0x1.921fb490de793958p+0L }, - { -0x6.0003437ebf49b358p-4L, -0x6.8366f772a6e5ab88p-4L, -0x2.50b11488d2e618p+0L, -0x2.50b11488d2e617fcp+0L }, - { -0x5.5180b0012d133d7p-4L, 0x1.265b051593ae50bp+36L, 0x1.921fb54447719c84p+0L, 0x1.921fb54447719c86p+0L }, - { 0x7.fb6040f1f0ff7dp-4L, -0x3.7a55504e82f7f4dcp-4L, -0x6.93193e94ff08f66p-4L, -0x6.93193e94ff08f658p-4L }, - { 0x7.0db37c7302791a18p+140L, -0x9.17638d6fe5ab606p-4L, -0x1.49f61a170196d194p-144L, -0x1.49f61a170196d192p-144L }, - { -0x9.ce06d03b8cf756cp+12212L, 0x1.dedfea0526bba7dp+4572L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, - { 0xb.7859f7b209e2fadp-4L, 0x4.7d451cc9eba3b3c8p+12080L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x3.800a4ceb87c4c0dcp-4L, -0xc.6125c4bdc9fce09p-4L, -0x1.4b95805a73babb12p+0L, -0x1.4b95805a73babb1p+0L }, - { 0xe.2f27e0dfe63260cp-4L, -0x5.15611dfbb941776p-4L, -0x5.81906be9aff7f478p-4L, -0x5.81906be9aff7f47p-4L }, - { -0xe.839068311283f8ap-4L, -0x3.ec9f15b5ee5373d4p-4L, -0x2.e0a57836248d1de8p+0L, -0x2.e0a57836248d1de4p+0L }, - { 0xf.e2ae6bf1e1a61e1p-4L, 0xf.c01b51aefe3a1aap+80L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x7.b53f66013e565ap-4L, 0x1.fca730dbcec65adcp-4L, 0x2.e3a9d5c63f015c2cp+0L, 0x2.e3a9d5c63f015c3p+0L }, - { 0xd.0cf58dc63ab7324p-4L, 0x7.449c0b585a5d2f78p-4L, 0x8.214f01a14103e4p-4L, 0x8.214f01a14103e41p-4L }, - { -0x5.6bd9880a9f4986p+44L, -0x6.2ffa8922e379925p-4L, -0x3.243f6a8885a1e4a8p+0L, -0x3.243f6a8885a1e4a4p+0L }, - { 0xf.704f945653892dbp-4L, -0xb.c78f60e05acc8c6p-92L, -0xc.353165a139735efp-92L, -0xc.353165a139735eep-92L }, - { 0x9.ebfb00a0b8c2da1p-4L, -0xb.af52c658515088ep-4L, -0xd.de7a23a873b3f3ep-4L, -0xd.de7a23a873b3f3dp-4L }, - { 0x3.875f9c7fb9864ae8p+468L, -0x9.4f89ff3200affa3p-4L, -0x2.a373dfc24c5488ap-472L, -0x2.a373dfc24c54889cp-472L }, - { -0xe.d00c66c632b4331p-4L, 0x7.ec775329456f0008p-8L, 0x3.1bb12c979946dfacp+0L, 0x3.1bb12c979946dfbp+0L }, - { -0x5.5f443fc060a5186p+4L, -0x5.20a0673897bdb3p+11012L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xa.a4bce42874e01e7p-4L, -0x4.713dabcd0bf8e268p-4L, -0x6.538a5466fb3e0bp-4L, -0x6.538a5466fb3e0af8p-4L }, - { 0xd.86b3fb9862792d8p-4L, 0xb.ae5e2dfcd038356p-4L, 0xb.65b757a77df534p-4L, 0xb.65b757a77df5341p-4L }, - { -0x9.adfe099d19d2efdp-4L, 0xa.88bf6665e9494dbp-4L, 0x2.505ec334ccbb79e4p+0L, 0x2.505ec334ccbb79e8p+0L }, - { 0x2.b3ae7a75c3b22b8p-6084L, 0x9.c5c6d7173a39debp+24L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0xe.7eb5c52358f835ep-3196L, 0x8.797ad35fc309114p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { -0x9.f8c8346e4053057p-4L, 0xf.c3edebe9bb0b3eep-8L, 0x3.0b089fc3ca8e624cp+0L, 0x3.0b089fc3ca8e625p+0L }, - { 0x8.c94c984dbf4168dp-140L, 0x8.af5e9852b765959p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, - { 0x2.c2b5d9731288dc28p+11664L, 0x5.04099a913d2b78bp+84L, 0x1.d121cb458be8286ap-11580L, 0x1.d121cb458be8286cp-11580L }, - { -0x2.ace07ddf3cfef394p-4L, -0x9.34833a09fae8757p-4L, -0x1.da87e7197755b95p+0L, -0x1.da87e7197755b94ep+0L }, - { -0x9.9730cd1292b85ap-4L, 0x4.c0eb35da7752fae8p-4L, 0x2.ae7231301fba2fc8p+0L, 0x2.ae7231301fba2fccp+0L }, - { 0xd.15f9ed0a25038d3p-4L, -0xb.026f5b20c30b683p-9908L, -0xd.761645d4aa3d8eap-9908L, -0xd.761645d4aa3d8e9p-9908L }, - { 0xd.be8ae1a17d85c18p-4L, 0x7.78d4cf72d7cf81d8p-4L, 0x7.f799f5d2cfdc8abp-4L, 0x7.f799f5d2cfdc8ab8p-4L }, - { 0x7.d23da006d9cb052p+100L, -0x7.a3b09d22470dbdbp+8L, -0xf.a0c5461aa543069p-96L, -0xf.a0c5461aa543068p-96L }, - { -0x7.5c713c672b96766p-4L, 0x2.52eaea727fb51b3cp-20L, 0x3.243f19b6d5b1f9b4p+0L, 0x3.243f19b6d5b1f9b8p+0L }, - { -0x3.2d22702027067fbp-11224L, -0x8.f3611793d8dfabdp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xc.0e2efd7cc5044b8p-4L, 0x9.4b4c59fac13b018p-4L, 0xa.822768942e46d48p-4L, 0xa.822768942e46d49p-4L }, - { -0xb.0f085497de93bf5p-4L, 0x9.8ba535bfbb53d43p-4L, 0x2.6df415a19533453p+0L, 0x2.6df415a195334534p+0L }, - { -0x9.da37fa21c584069p-4L, 0xa.c84cf6492b6f825p-4L, 0x2.4fa7dddb330669c4p+0L, 0x2.4fa7dddb330669c8p+0L }, - { -0x9.3bcbc7bc0fb3ed9p+88L, -0x2.79e9ad222e894dc4p+6552L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, - { 0xa.e73a40fb29d0efep-4L, -0x2.79cf7e59fb5c72d4p-7232L, -0x3.a21696480c751084p-7232L, -0x3.a21696480c75108p-7232L }, - { 0x4.8e020087477fcaep-4L, -0xb.588ec7584c64f6dp-8L, -0x2.789fd1176ef175bp-4L, -0x2.789fd1176ef175acp-4L }, -}; - -int check_equal(long double res, long double expected) -{ - if (res != expected) { - return 0; - } - return (__builtin_copysignl(1.0L, res) == - __builtin_copysignl(1.0L, expected)); -} - -int main(void) -{ - int ret = 0; - int i; - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - long double ld_res; - __asm__ volatile ("fpatan" : "=t" (ld_res) : - "0" (tests[i].arg0), "u" (tests[i].arg1) : "st(1)"); - if (!check_equal(ld_res, tests[i].down) && - !check_equal(ld_res, tests[i].up)) { - printf("FAIL: fpatan %La %La, expected %La or %La, got %La\n", - tests[i].arg0, tests[i].arg1, tests[i].down, tests[i].up, - ld_res); - ret = 1; - } - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fprem.c b/tests/tcg/i386/test-i386-fprem.c deleted file mode 100644 index 66f5a9657da4..000000000000 --- a/tests/tcg/i386/test-i386-fprem.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * x86 FPREM test - executes the FPREM and FPREM1 instructions with corner case - * operands and prints the operands, result and FPU status word. - * - * Run this on real hardware, then under QEMU, and diff the outputs, to compare - * QEMU's implementation to your hardware. The 'run-test-i386-fprem' make - * target does this. - * - * Copyright (c) 2003 Fabrice Bellard - * Copyright (c) 2012 Catalin Patulea - * - * 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 . - */ - -#include -#include - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -/* - * Inspired by 's union ieee854_long_double, but with single - * long long mantissa fields and assuming little-endianness for simplicity. - */ -union float80u { - long double d; - - /* This is the IEEE 854 double-extended-precision format. */ - struct { - unsigned long long mantissa:63; - unsigned int one:1; - unsigned int exponent:15; - unsigned int negative:1; - unsigned int empty:16; - } __attribute__((packed)) ieee; - - /* This is for NaNs in the IEEE 854 double-extended-precision format. */ - struct { - unsigned long long mantissa:62; - unsigned int quiet_nan:1; - unsigned int one:1; - unsigned int exponent:15; - unsigned int negative:1; - unsigned int empty:16; - } __attribute__((packed)) ieee_nan; -}; - -#define IEEE854_LONG_DOUBLE_BIAS 0x3fff - -static const union float80u q_nan = { - .ieee_nan.negative = 0, /* X */ - .ieee_nan.exponent = 0x7fff, - .ieee_nan.one = 1, - .ieee_nan.quiet_nan = 1, - .ieee_nan.mantissa = 0, -}; - -static const union float80u s_nan = { - .ieee_nan.negative = 0, /* X */ - .ieee_nan.exponent = 0x7fff, - .ieee_nan.one = 1, - .ieee_nan.quiet_nan = 0, - .ieee_nan.mantissa = 1, /* nonzero */ -}; - -static const union float80u pos_inf = { - .ieee.negative = 0, - .ieee.exponent = 0x7fff, - .ieee.one = 1, - .ieee.mantissa = 0, -}; - -static const union float80u pseudo_pos_inf = { /* "unsupported" */ - .ieee.negative = 0, - .ieee.exponent = 0x7fff, - .ieee.one = 0, - .ieee.mantissa = 0, -}; - -static const union float80u pos_denorm = { - .ieee.negative = 0, - .ieee.exponent = 0, - .ieee.one = 0, - .ieee.mantissa = 1, -}; - -static const union float80u smallest_positive_norm = { - .ieee.negative = 0, - .ieee.exponent = 1, - .ieee.one = 1, - .ieee.mantissa = 0, -}; - -static void fninit() -{ - asm volatile ("fninit\n"); -} - -static long double fprem(long double a, long double b, uint16_t *sw) -{ - long double result; - asm volatile ("fprem\n" - "fnstsw %1\n" - : "=t" (result), "=m" (*sw) - : "0" (a), "u" (b) - : "st(1)"); - return result; -} - -static long double fprem1(long double a, long double b, uint16_t *sw) -{ - long double result; - asm volatile ("fprem1\n" - "fnstsw %1\n" - : "=t" (result), "=m" (*sw) - : "0" (a), "u" (b) - : "st(1)"); - return result; -} - -#define FPUS_IE (1 << 0) -#define FPUS_DE (1 << 1) -#define FPUS_ZE (1 << 2) -#define FPUS_OE (1 << 3) -#define FPUS_UE (1 << 4) -#define FPUS_PE (1 << 5) -#define FPUS_SF (1 << 6) -#define FPUS_SE (1 << 7) -#define FPUS_C0 (1 << 8) -#define FPUS_C1 (1 << 9) -#define FPUS_C2 (1 << 10) -#define FPUS_TOP 0x3800 -#define FPUS_C3 (1 << 14) -#define FPUS_B (1 << 15) - -#define FPUS_EMASK 0x007f - -#define FPUC_EM 0x3f - -static void psw(uint16_t sw) -{ - printf("SW: C3 TopC2C1C0\n"); - printf("SW: %c %d %3d %d %d %d %c %c %c %c %c %c %c %c\n", - sw & FPUS_B ? 'B' : 'b', - !!(sw & FPUS_C3), - (sw & FPUS_TOP) >> 11, - !!(sw & FPUS_C2), - !!(sw & FPUS_C1), - !!(sw & FPUS_C0), - (sw & FPUS_SE) ? 'S' : 's', - (sw & FPUS_SF) ? 'F' : 'f', - (sw & FPUS_PE) ? 'P' : 'p', - (sw & FPUS_UE) ? 'U' : 'u', - (sw & FPUS_OE) ? 'O' : 'o', - (sw & FPUS_ZE) ? 'Z' : 'z', - (sw & FPUS_DE) ? 'D' : 'd', - (sw & FPUS_IE) ? 'I' : 'i'); -} - -static void do_fprem(long double a, long double b) -{ - const union float80u au = {.d = a}; - const union float80u bu = {.d = b}; - union float80u ru; - uint16_t sw; - - printf("A: S=%d Exp=%04x Int=%d (QNaN=%d) Sig=%016llx (%.06Le)\n", - au.ieee.negative, au.ieee.exponent, au.ieee.one, - au.ieee_nan.quiet_nan, (unsigned long long)au.ieee.mantissa, - a); - printf("B: S=%d Exp=%04x Int=%d (QNaN=%d) Sig=%016llx (%.06Le)\n", - bu.ieee.negative, bu.ieee.exponent, bu.ieee.one, - bu.ieee_nan.quiet_nan, (unsigned long long)bu.ieee.mantissa, - b); - fflush(stdout); - - fninit(); - ru.d = fprem(a, b, &sw); - psw(sw); - - printf("R : S=%d Exp=%04x Int=%d (QNaN=%d) Sig=%016llx (%.06Le)\n", - ru.ieee.negative, ru.ieee.exponent, ru.ieee.one, - ru.ieee_nan.quiet_nan, (unsigned long long)ru.ieee.mantissa, - ru.d); - - fninit(); - ru.d = fprem1(a, b, &sw); - psw(sw); - - printf("R1: S=%d Exp=%04x Int=%d (QNaN=%d) Sig=%016llx (%.06Le)\n", - ru.ieee.negative, ru.ieee.exponent, ru.ieee.one, - ru.ieee_nan.quiet_nan, (unsigned long long)ru.ieee.mantissa, - ru.d); - - printf("\n"); -} - -static void do_fprem_stack_underflow(void) -{ - const long double a = 1.0; - union float80u ru; - uint16_t sw; - - fninit(); - asm volatile ("fprem\n" - "fnstsw %1\n" - : "=t" (ru.d), "=m" (sw) - : "0" (a) - : "st(1)"); - psw(sw); - - printf("R: S=%d Exp=%04x Int=%d (QNaN=%d) Sig=%016llx (%.06Le)\n", - ru.ieee.negative, ru.ieee.exponent, ru.ieee.one, - ru.ieee_nan.quiet_nan, (unsigned long long)ru.ieee.mantissa, - ru.d); - printf("\n"); -} - -static void test_fprem_cases(void) -{ - printf("= stack underflow =\n"); - do_fprem_stack_underflow(); - - printf("= invalid operation =\n"); - do_fprem(q_nan.d, 1.0); - do_fprem(s_nan.d, 1.0); - do_fprem(1.0, 0.0); - do_fprem(pos_inf.d, 1.0); - do_fprem(pseudo_pos_inf.d, 1.0); - - printf("= denormal =\n"); - do_fprem(pos_denorm.d, 1.0); - do_fprem(1.0, pos_denorm.d); - - do_fprem(smallest_positive_norm.d, smallest_positive_norm.d); - - /* printf("= underflow =\n"); */ - /* TODO: Is there a case where FPREM raises underflow? */ -} - -static void test_fprem_pairs(void) -{ - unsigned long long count; - - unsigned int negative_index_a = 0; - unsigned int negative_index_b = 0; - static const unsigned int negative_values[] = { - 0, - 1, - }; - - unsigned int exponent_index_a = 0; - unsigned int exponent_index_b = 0; - static const unsigned int exponent_values[] = { - 0, - 1, - 2, - IEEE854_LONG_DOUBLE_BIAS - 1, - IEEE854_LONG_DOUBLE_BIAS, - IEEE854_LONG_DOUBLE_BIAS + 1, - 0x7ffd, - 0x7ffe, - 0x7fff, - }; - - unsigned int one_index_a = 0; - unsigned int one_index_b = 0; - static const unsigned int one_values[] = { - 0, - 1, - }; - - unsigned int quiet_nan_index_a = 0; - unsigned int quiet_nan_index_b = 0; - static const unsigned int quiet_nan_values[] = { - 0, - 1, - }; - - unsigned int mantissa_index_a = 0; - unsigned int mantissa_index_b = 0; - static const unsigned long long mantissa_values[] = { - 0, - 1, - 2, - 0x3ffffffffffffffdULL, - 0x3ffffffffffffffeULL, - 0x3fffffffffffffffULL, - }; - - for (count = 0; ; ++count) { -#define INIT_FIELD(var, field) \ - .ieee_nan.field = field##_values[field##_index_##var] - const union float80u a = { - INIT_FIELD(a, negative), - INIT_FIELD(a, exponent), - INIT_FIELD(a, one), - INIT_FIELD(a, quiet_nan), - INIT_FIELD(a, mantissa), - }; - const union float80u b = { - INIT_FIELD(b, negative), - INIT_FIELD(b, exponent), - INIT_FIELD(b, one), - INIT_FIELD(b, quiet_nan), - INIT_FIELD(b, mantissa), - }; -#undef INIT_FIELD - - do_fprem(a.d, b.d); - - int carry = 1; -#define CARRY_INTO(var, field) do { \ - if (carry) { \ - if (++field##_index_##var == ARRAY_SIZE(field##_values)) { \ - field##_index_##var = 0; \ - } else { \ - carry = 0; \ - } \ - } \ - } while (0) - CARRY_INTO(b, mantissa); - CARRY_INTO(b, quiet_nan); - CARRY_INTO(b, one); - CARRY_INTO(b, exponent); - CARRY_INTO(b, negative); - CARRY_INTO(a, mantissa); - CARRY_INTO(a, quiet_nan); - CARRY_INTO(a, one); - CARRY_INTO(a, exponent); - CARRY_INTO(a, negative); -#undef CARRY_INTO - - if (carry) { - break; - } - } - - fprintf(stderr, "test-i386-fprem: tested %llu cases\n", count); -} - -int main(int argc, char **argv) -{ - test_fprem_cases(); - test_fprem_pairs(); - return 0; -} diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c deleted file mode 100644 index d23b3cfeec89..000000000000 --- a/tests/tcg/i386/test-i386-fscale.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Test fscale instruction. */ - -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile long double ld_third = 1.0L / 3.0L; -volatile long double ld_four_thirds = 4.0L / 3.0L; -volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; -volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; -volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; -volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; - -volatile long double ld_res; - -int isnan_ld(long double x) -{ - union u tmp = { .ld = x }; - return ((tmp.s.sign_exp & 0x7fff) == 0x7fff && - (tmp.s.sig >> 63) != 0 && - (tmp.s.sig << 1) != 0); -} - -int issignaling_ld(long double x) -{ - union u tmp = { .ld = x }; - return isnan_ld(x) && (tmp.s.sig & UINT64_C(0x4000000000000000)) == 0; -} - -int main(void) -{ - short cw; - int ret = 0; - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (2.5L), "u" (__builtin_nansl(""))); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale snan\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (2.5L), "u" (ld_invalid_1.ld)); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale invalid 1\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (2.5L), "u" (ld_invalid_2.ld)); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale invalid 2\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (2.5L), "u" (ld_invalid_3.ld)); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale invalid 3\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (2.5L), "u" (ld_invalid_4.ld)); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale invalid 4\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (0.0L), "u" (__builtin_infl())); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale 0 up inf\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (__builtin_infl()), "u" (-__builtin_infl())); - if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { - printf("FAIL: fscale inf down inf\n"); - ret = 1; - } - /* Set round-downward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x400; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (1.0L), "u" (__builtin_infl())); - if (ld_res != __builtin_infl()) { - printf("FAIL: fscale finite up inf\n"); - ret = 1; - } - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (-1.0L), "u" (-__builtin_infl())); - if (ld_res != -0.0L || __builtin_copysignl(1.0L, ld_res) != -1.0L) { - printf("FAIL: fscale finite down inf\n"); - ret = 1; - } - /* Set round-to-nearest with single-precision rounding. */ - cw = cw & ~0xf00; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ volatile ("fscale" : "=t" (ld_res) : - "0" (ld_third), "u" (2.0L)); - cw = cw | 0x300; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - if (ld_res != ld_four_thirds) { - printf("FAIL: fscale single-precision\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fxam.c b/tests/tcg/i386/test-i386-fxam.c deleted file mode 100644 index ddd76ca42d20..000000000000 --- a/tests/tcg/i386/test-i386-fxam.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Test fxam instruction. */ - -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; -volatile union u ld_pseudo_nm16382 = { .s = { UINT64_C(1) << 63, 0x8000 } }; -volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; -volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; -volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; -volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; -volatile union u ld_invalid_n1 = { .s = { 1, 0x8123 } }; -volatile union u ld_invalid_n2 = { .s = { 0, 0x8123 } }; -volatile union u ld_invalid_n3 = { .s = { 0, 0xffff } }; -volatile union u ld_invalid_n4 = { .s = { (UINT64_C(1) << 63) - 1, 0xffff } }; - -#define C0 (1 << 8) -#define C1 (1 << 9) -#define C2 (1 << 10) -#define C3 (1 << 14) -#define FLAGS (C0 | C1 | C2 | C3) - -int main(void) -{ - short sw; - int ret = 0; - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (0.0L)); - if ((sw & FLAGS) != C3) { - printf("FAIL: +0\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-0.0L)); - if ((sw & FLAGS) != (C3 | C1)) { - printf("FAIL: -0\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (1.0L)); - if ((sw & FLAGS) != C2) { - printf("FAIL: +normal\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-1.0L)); - if ((sw & FLAGS) != (C2 | C1)) { - printf("FAIL: -normal\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (__builtin_infl())); - if ((sw & FLAGS) != (C2 | C0)) { - printf("FAIL: +inf\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-__builtin_infl())); - if ((sw & FLAGS) != (C2 | C1 | C0)) { - printf("FAIL: -inf\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (__builtin_nanl(""))); - if ((sw & FLAGS) != C0) { - printf("FAIL: +nan\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-__builtin_nanl(""))); - if ((sw & FLAGS) != (C1 | C0)) { - printf("FAIL: -nan\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (__builtin_nansl(""))); - if ((sw & FLAGS) != C0) { - printf("FAIL: +snan\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-__builtin_nansl(""))); - if ((sw & FLAGS) != (C1 | C0)) { - printf("FAIL: -snan\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (0x1p-16445L)); - if ((sw & FLAGS) != (C3 | C2)) { - printf("FAIL: +denormal\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-0x1p-16445L)); - if ((sw & FLAGS) != (C3 | C2 | C1)) { - printf("FAIL: -denormal\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_pseudo_m16382.ld)); - if ((sw & FLAGS) != (C3 | C2)) { - printf("FAIL: +pseudo-denormal\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_pseudo_nm16382.ld)); - if ((sw & FLAGS) != (C3 | C2 | C1)) { - printf("FAIL: -pseudo-denormal\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_1.ld)); - if ((sw & FLAGS) != 0) { - printf("FAIL: +invalid 1\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n1.ld)); - if ((sw & FLAGS) != C1) { - printf("FAIL: -invalid 1\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_2.ld)); - if ((sw & FLAGS) != 0) { - printf("FAIL: +invalid 2\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n2.ld)); - if ((sw & FLAGS) != C1) { - printf("FAIL: -invalid 2\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_3.ld)); - if ((sw & FLAGS) != 0) { - printf("FAIL: +invalid 3\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n3.ld)); - if ((sw & FLAGS) != C1) { - printf("FAIL: -invalid 3\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_4.ld)); - if ((sw & FLAGS) != 0) { - printf("FAIL: +invalid 4\n"); - ret = 1; - } - __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n4.ld)); - if ((sw & FLAGS) != C1) { - printf("FAIL: -invalid 4\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fxtract.c b/tests/tcg/i386/test-i386-fxtract.c deleted file mode 100644 index 64fd93d33370..000000000000 --- a/tests/tcg/i386/test-i386-fxtract.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Test fxtract instruction. */ - -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; -volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; -volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; -volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; -volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; - -volatile long double ld_sig, ld_exp; - -int isnan_ld(long double x) -{ - union u tmp = { .ld = x }; - return ((tmp.s.sign_exp & 0x7fff) == 0x7fff && - (tmp.s.sig >> 63) != 0 && - (tmp.s.sig << 1) != 0); -} - -int issignaling_ld(long double x) -{ - union u tmp = { .ld = x }; - return isnan_ld(x) && (tmp.s.sig & UINT64_C(0x4000000000000000)) == 0; -} - -int main(void) -{ - int ret = 0; - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : "0" (2.5L)); - if (ld_sig != 1.25L || ld_exp != 1.0L) { - printf("FAIL: fxtract 2.5\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : "0" (0.0L)); - if (ld_sig != 0.0L || __builtin_copysignl(1.0L, ld_sig) != 1.0L || - ld_exp != -__builtin_infl()) { - printf("FAIL: fxtract 0.0\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : "0" (-0.0L)); - if (ld_sig != -0.0L || __builtin_copysignl(1.0L, ld_sig) != -1.0L || - ld_exp != -__builtin_infl()) { - printf("FAIL: fxtract -0.0\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (__builtin_infl())); - if (ld_sig != __builtin_infl() || ld_exp != __builtin_infl()) { - printf("FAIL: fxtract inf\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (-__builtin_infl())); - if (ld_sig != -__builtin_infl() || ld_exp != __builtin_infl()) { - printf("FAIL: fxtract -inf\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (__builtin_nanl(""))); - if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || - !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { - printf("FAIL: fxtract qnan\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (__builtin_nansl(""))); - if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || - !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { - printf("FAIL: fxtract snan\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (0x1p-16445L)); - if (ld_sig != 1.0L || ld_exp != -16445.0L) { - printf("FAIL: fxtract subnormal\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (ld_pseudo_m16382.ld)); - if (ld_sig != 1.0L || ld_exp != -16382.0L) { - printf("FAIL: fxtract pseudo\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (ld_invalid_1.ld)); - if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || - !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { - printf("FAIL: fxtract invalid 1\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (ld_invalid_2.ld)); - if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || - !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { - printf("FAIL: fxtract invalid 2\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (ld_invalid_3.ld)); - if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || - !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { - printf("FAIL: fxtract invalid 3\n"); - ret = 1; - } - __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : - "0" (ld_invalid_4.ld)); - if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || - !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { - printf("FAIL: fxtract invalid 4\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fyl2x.c b/tests/tcg/i386/test-i386-fyl2x.c deleted file mode 100644 index 71d7a8fc9905..000000000000 --- a/tests/tcg/i386/test-i386-fyl2x.c +++ /dev/null @@ -1,1161 +0,0 @@ -/* Test fyl2x instruction. */ - -#include - -struct test { - long double arg0, arg1, down, up; -}; - -const struct test tests[] = { - { 1.0L, 12345.0L, 0.0L, 0.0L }, - { 1.0L, -12345.0L, -0.0L, -0.0L }, - { 1.0L, 0.0L, 0.0L, 0.0L }, - { 1.0L, -0.0L, -0.0L, -0.0L }, - { 0.1L, 0.0L, -0.0L, -0.0L }, - { 0.1L, -0.0L, 0.0L, 0.0L }, - { 1.1L, 0.0L, 0.0L, 0.0L }, - { 1.1L, -0.0L, -0.0L, -0.0L }, - { 0.0L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, - { 0.0L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, - { -0.0L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, - { -0.0L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, - { 0.0L, 12345.0L, -__builtin_infl(), -__builtin_infl() }, - { 0.0L, -12345.0L, __builtin_infl(), __builtin_infl() }, - { -0.0L, 12345.0L, -__builtin_infl(), -__builtin_infl() }, - { -0.0L, -12345.0L, __builtin_infl(), __builtin_infl() }, - { 0.1L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, - { 0.1L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, - { 1.1L, __builtin_infl(), __builtin_infl(), __builtin_infl() }, - { 1.1L, -__builtin_infl(), -__builtin_infl(), -__builtin_infl() }, - { 4.0L, 1.5L, 3.0L, 3.0L }, - { 0x1p-16400L, 1.5L, -24600.0L, -24600.0L }, - /* Randomly generated tests. */ - { 0x2.0a40b4bd6349d53p+14380L, -0x3.612a1cec52e70388p-14116L, -0xb.dd9637a24570d1ap-14104L, -0xb.dd9637a24570d19p-14104L }, - { 0xa.a3dc18b1eff7e8ap-4L, 0x7.423575b7ac0ba6a8p-7212L, -0x4.45ac6ae2f9cc1a7p-7212L, -0x4.45ac6ae2f9cc1a68p-7212L }, - { 0x1.51167cab1deec25ep-9616L, 0xb.79bece734a62216p-14512L, -0x1.af0880f05109d5c8p-14496L, -0x1.af0880f05109d5c6p-14496L }, - { 0x1.55691f3dee65eb88p+6420L, -0x2.e081398cd6691b98p-2640L, -0x4.8275aa22ebb6ebe8p-2628L, -0x4.8275aa22ebb6ebep-2628L }, - { 0x3.71cca195c06ba4d4p-6312L, -0xb.14b747fa4cc13d1p+5052L, 0x1.112301748a1cc83p+5068L, 0x1.112301748a1cc832p+5068L }, - { 0x2.0f924dde0806572p+8924L, -0x7.ece8699d62a9f76p-14464L, -0x1.144eba5c079d0fa2p-14448L, -0x1.144eba5c079d0fap-14448L }, - { 0x4.b875c0342c9f86b8p-5832L, 0xe.a37e0fa859e499cp+732L, -0x1.4d5bc95e2af0bb08p+748L, -0x1.4d5bc95e2af0bb06p+748L }, - { 0x7.23210d9474f0715p+364L, -0x5.baaf3a431730f158p-2436L, -0x8.35afbc04cd37fafp-2428L, -0x8.35afbc04cd37faep-2428L }, - { 0xd.2330923899aae43p+776L, 0x2.a68cc6ddbe3b3a5p+6528L, 0x8.12b3f5a7b346e37p+6536L, 0x8.12b3f5a7b346e38p+6536L }, - { 0x2.c18975d92e49e91p+10120L, 0x5.6a0ac0f801b69198p+9064L, 0xd.60fe44e0b41da9dp+9076L, 0xd.60fe44e0b41da9ep+9076L }, - { 0x9.0950fb020f8be81p-11076L, -0x4.69649643801fe8p+14796L, 0xb.ed1e14ac1ee3159p+14808L, 0xb.ed1e14ac1ee315ap+14808L }, - { 0x9.cbe5ac9e09f4815p+8052L, -0x1.068c69d5c31cc18ap+8068L, -0x2.04558d1bf9a219b4p+8080L, -0x2.04558d1bf9a219bp+8080L }, - { 0x2.8158a2ep-16416L, 0x1.2f720ae47b67fca8p+13452L, -0x4.c00deece9e0fbdd8p+13464L, -0x4.c00deece9e0fbddp+13464L }, - { 0x3.0acd5bcfe0779bd4p+13040L, -0xe.d3cd27fc1c72a99p+11224L, -0x2.f35c6ed58511949p+11240L, -0x2.f35c6ed58511948cp+11240L }, - { 0xb.58a8c4316eacf31p-584L, 0x1.501f01a1258b3a5ep-10084L, -0x2.fa2ce9d2db22ad5cp-10076L, -0x2.fa2ce9d2db22ad58p-10076L }, - { 0x8.97f4540aa7735bap+13532L, -0x3.b7afc1088aafbb28p-9804L, -0xc.48d1793ca776382p-9792L, -0xc.48d1793ca776381p-9792L }, - { 0x5.1f9f41429952299p-6688L, -0x1.385afe2753285ceap-632L, 0x1.fdd68ec1544cca1ap-620L, 0x1.fdd68ec1544cca1cp-620L }, - { 0x2.95674162a7a77d6cp-11476L, -0x6.9ad188a393c513bp-8912L, 0x1.280b2d9ef35a1b0ep-8896L, 0x1.280b2d9ef35a1b1p-8896L }, - { 0x1.11caeb05f30a55a2p-5048L, 0xa.6b25eb8a8fc7c1fp+6868L, -0xc.d6fd12efe012db1p+6880L, -0xc.d6fd12efe012dbp+6880L }, - { 0x3.c980e98228764804p-5832L, 0x9.5de74e6eb71dccfp+1992L, -0xd.5513ed4865b07fep+2004L, -0xd.5513ed4865b07fdp+2004L }, - { 0xd.16b2f891d20d0f8p+7300L, -0x1.ab0872107c4d7a06p+5924L, -0x2.f974d3a68daf1cacp+5936L, -0x2.f974d3a68daf1ca8p+5936L }, - { 0x6.c6090865d981a428p-8676L, -0xd.23a3619aedffe31p+5328L, 0x1.bd2789bab1d1088cp+5344L, 0x1.bd2789bab1d1088ep+5344L }, - { 0x2.0d4fa66a2d01369cp-4156L, -0x5.a0e8f41f82c193bp+6724L, 0x5.b5a6f9779b0a4488p+6736L, 0x5.b5a6f9779b0a449p+6736L }, - { 0x1.ba2a72afa5a1fc38p+0L, 0xe.027c0b9bc2929f3p+11120L, 0xb.0bbdb58c72375d9p+11120L, 0xb.0bbdb58c72375dap+11120L }, - { 0xf.cc716330a37576ep-5424L, -0xd.a67cd50b638d845p-4460L, 0x1.21011acae853070ap-4444L, 0x1.21011acae853070cp-4444L }, - { 0x2.7699390ee7b13a7cp+8364L, -0x1.d8cb9730c96f499p+432L, -0x3.c598297e793d4e98p+444L, -0x3.c598297e793d4e94p+444L }, - { 0x4.6b0173e789f64bd8p-960L, -0x2.140353c78ded1788p+8748L, 0x7.c6982a68b41c327p+8756L, 0x7.c6982a68b41c3278p+8756L }, - { 0xc.08b122dd36a9965p+11804L, -0xa.c8e6364d67421f2p+12272L, -0x1.f16e0be947126474p+12288L, -0x1.f16e0be947126472p+12288L }, - { 0x9.cafbcd348517675p+784L, 0x4.148eb9b190272998p-1420L, 0xc.8c638141b3c6b91p-1412L, 0xc.8c638141b3c6b92p-1412L }, - { 0x4.6a571cdc489d4a9p-12352L, -0x8.a8aa4198b0c3207p+7748L, 0x1.a1b789910f110f64p+7764L, 0x1.a1b789910f110f66p+7764L }, - { 0x7.e9b228c12458559p+4928L, -0xb.2c5bdfaf2ba8f24p+56L, -0xd.73740755eb037a7p+68L, -0xd.73740755eb037a6p+68L }, - { 0xd.d2e346da3ecdb39p-1636L, -0x5.8d0ce8c4cdc72a28p+12736L, 0x2.3645e062564a6de4p+12748L, 0x2.3645e062564a6de8p+12748L }, - { 0x9.b624ea7f57aab0ap-8780L, -0x2.5e13b5ceb995397p-6416L, 0x5.12ac8402317cf408p-6404L, 0x5.12ac8402317cf41p-6404L }, - { 0x7.6d8427638b963b58p+12536L, 0x4.021f2d6df523df5p-14208L, 0xc.4537f396f309b57p-14196L, 0xc.4537f396f309b58p-14196L }, - { 0x1.8273f77fc7b36adp+0L, 0x2.f4e4c4891a53eaap-4624L, 0x1.c1b52b72090b9f64p-4624L, 0x1.c1b52b72090b9f66p-4624L }, - { 0x1.c92a5ddc0ccb3c36p+11600L, 0x1.090c0001295c6822p-4904L, 0x2.eeacd7b5643f39ecp-4892L, 0x2.eeacd7b5643f39fp-4892L }, - { 0xd.32c71819b8fe7abp-1688L, -0x6.3d33ce38ee554b58p-14512L, 0x2.90c54596d3bf22ecp-14500L, 0x2.90c54596d3bf22fp-14500L }, - { 0x1.0776fe51e1d0727cp+5752L, 0x1.4264622f1e6c6f9ep+12300L, 0x1.c4bccdc673bd74bap+12312L, 0x1.c4bccdc673bd74bcp+12312L }, - { 0x1.81f41db779901632p-10716L, -0x8.66aed834cdb9d9fp+4436L, 0x1.5fa54511d99a6f4ap+4452L, 0x1.5fa54511d99a6f4cp+4452L }, - { 0xc.9b4feccafbb8f3ep-5320L, -0xe.ccfc061ce46d6dfp+13440L, 0x1.335db86628278a4cp+13456L, 0x1.335db86628278a4ep+13456L }, - { 0x6.4ffb2045e1ad1378p-6564L, 0xf.7dfd3273f5ec1a3p+9724L, -0x1.8d1141c2de30f8eap+9740L, -0x1.8d1141c2de30f8e8p+9740L }, - { 0x2.ad90d677772e099cp+13112L, -0x2.830a812d5307cc94p-6908L, -0x8.0ab53e41596b795p-6896L, -0x8.0ab53e41596b794p-6896L }, - { 0x1.7bf51909429d7df2p-520L, -0x3.3d489a77c9f992fcp+5672L, 0x6.92a309adfd41fffp+5680L, 0x6.92a309adfd41fff8p+5680L }, - { 0x1.330765dbd272224cp+13924L, 0x2.b0444ac2e0ef926p+9564L, 0x9.23bf6ee60967adp+9576L, 0x9.23bf6ee60967ad1p+9576L }, - { 0xb.067254ab6c13349p-5508L, 0xa.7a515bb500d476fp+7348L, -0xe.14b76544da68e7fp+7360L, -0xe.14b76544da68e7ep+7360L }, - { 0x1.4f1b85b1df9ca2b4p+0L, -0x2.8e9812b9a5395564p+10304L, -0xf.e4bfca8c781c9d5p+10300L, -0xf.e4bfca8c781c9d4p+10300L }, - { 0x2.d4c7f38019aa6c2p+11216L, 0xb.6a68ac4a863ccap-6380L, 0x1.f4372db1fc362048p-6364L, 0x1.f4372db1fc36204ap-6364L }, - { 0x4.d6f79ebf8f5962ap-12132L, -0x7.2fde53882a542cp-9272L, 0x1.54882a9fcea32926p-9256L, 0x1.54882a9fcea32928p-9256L }, - { 0x5.f224f48169e0aea8p+4500L, -0x2.3e6bba4532dcfb74p-4984L, -0x2.77702ff129d7eb24p-4972L, -0x2.77702ff129d7eb2p-4972L }, - { 0xf.ce42d087ed87c6dp-1636L, -0x3.b45d9ada75fad714p+4704L, 0x1.79de5728a407b37ap+4716L, 0x1.79de5728a407b37cp+4716L }, - { 0x8.c2ce2631a625123p-8668L, 0x1.bdf6302fd5c0c678p+13148L, -0x3.af6876f1ee35ebf4p+13160L, -0x3.af6876f1ee35ebfp+13160L }, - { 0x2.9fb1b2e872ad16fcp+5720L, 0xa.405432519e52763p-12388L, 0xe.51b9d7128949a09p-12376L, 0xe.51b9d7128949a0ap-12376L }, - { 0x2.0c52d8494ae2a78p-12156L, 0x2.c778146cdaf5952p+8448L, -0x8.3f4ca0808d4657fp+8460L, -0x8.3f4ca0808d4657ep+8460L }, - { 0x7.7bfdf3916d8cf8dp+8552L, -0x2.fcc721321202f8fcp+7376L, -0x6.3d508fed61bad698p+7388L, -0x6.3d508fed61bad69p+7388L }, - { 0x9.09cea2796b8226bp+12760L, -0xe.d759972da423644p-6776L, -0x2.e3ecfc770c2adf48p-6760L, -0x2.e3ecfc770c2adf44p-6760L }, - { 0x3.f7d3ba7d4699285cp-2652L, 0x1.806cf84083df3ff4p+192L, -0xf.8b6c7389e003b59p+200L, -0xf.8b6c7389e003b58p+200L }, - { 0xd.df138c6b3e2cda7p-4L, -0x3.056a73ca2e92d3f8p+2760L, 0x9.f4ace14ab975a41p+2756L, 0x9.f4ace14ab975a42p+2756L }, - { 0x3.43ad78da6c4fbdbp-88L, -0x7.e7d5025d81fd262p+11984L, 0x2.aa32f09cb4608f7p+11992L, 0x2.aa32f09cb4608f74p+11992L }, - { 0x1.9b44f75fe57ddc8p-1260L, 0x4.38ec201a4e140da8p+1488L, -0x1.4c546e4cce840414p+1500L, -0x1.4c546e4cce840412p+1500L }, - { 0x1.42d057efa3eb1b9p-6636L, -0x6.64151de2cb7dab68p+14856L, 0xa.5a83005207a7a31p+14868L, 0xa.5a83005207a7a32p+14868L }, - { 0x3.5e66ae0c3ef31cc8p-13572L, -0x1.fa8c3fd05e77645ep-2452L, 0x6.8e37bd270fc92fb8p-2440L, 0x6.8e37bd270fc92fcp-2440L }, - { 0x6.001cd5c28a310bd8p+4224L, 0x4.c1b839282f6ff928p-11728L, 0x4.e88ab9284208a73p-11716L, 0x4.e88ab9284208a738p-11716L }, - { 0x2.2523780824d5de6cp+6472L, 0x1.b994f4a4f7e37afcp-8880L, 0x2.b9da3fa65283fa3p-8868L, 0x2.b9da3fa65283fa34p-8868L }, - { 0x5.6eec466c7bffa06p-608L, -0x1.97289654800c49b6p-8972L, 0x3.c31e2f1c37735488p-8964L, 0x3.c31e2f1c3773548cp-8964L }, - { 0x1.ca72ccc65efa7b72p-6772L, 0x5.f8e4e1978952a4ap-11212L, -0x9.df7016942b5d202p-11200L, -0x9.df7016942b5d201p-11200L }, - { 0xf.c6d22b8e29913f1p+9424L, -0xe.a6d7654fc1271b1p+1136L, -0x2.1b98288c7d75e8e8p+1152L, -0x2.1b98288c7d75e8e4p+1152L }, - { 0x1.61e8e00c140fee84p-9076L, -0x8.36dc1307ce2fc6p+14524L, 0x1.23351bc9d473a88p+14540L, 0x1.23351bc9d473a882p+14540L }, - { 0xf.866338e1e8a3a1dp-8L, -0x2.0442ce4344704d5cp-560L, 0x8.277e13b5af2161dp-560L, 0x8.277e13b5af2161ep-560L }, - { 0xe.3299360868a37fcp-10400L, 0x3.e615f9a223227808p-10468L, -0x9.e54507c6991311ep-10456L, -0x9.e54507c6991311dp-10456L }, - { 0x9.b3ff5c8d9b3d3acp+1836L, 0xa.828b7a9eaf39effp-2100L, 0x4.b82b5232056d9bbp-2088L, 0x4.b82b5232056d9bb8p-2088L }, - { 0xe.ffd31418495b633p+10124L, -0xc.5c871eba0b4806fp+5684L, -0x1.e90b7ad4822936e8p+5700L, -0x1.e90b7ad4822936e6p+5700L }, - { 0x1.7b8e3d8dda2e2b02p-7084L, 0xf.bbe5d63f9e346a3p-5088L, -0x1.b35a8b7f594154ecp-5072L, -0x1.b35a8b7f594154eap-5072L }, - { 0xe.8837c0b02c82f75p+8320L, 0x3.05caa0d06bb20888p-7260L, 0x6.247e5285220e72ap-7248L, 0x6.247e5285220e72a8p-7248L }, - { 0x7.bad48611f3e40dap-12820L, -0x1.643e2a67aaa8efa2p+13488L, 0x4.5abde1190f1b7cp+13500L, 0x4.5abde1190f1b7c08p+13500L }, - { 0xd.0e541be4b24c664p-5232L, 0x3.065797f0fcc28dbp-8280L, -0x3.dc667fc93532e9c4p-8268L, -0x3.dc667fc93532e9cp-8268L }, - { 0x2.c5b8595f3f1fb5acp+10588L, 0x5.914bbd1c2a1f9d8p-7504L, 0xe.64d8944801b7e74p-7492L, 0xe.64d8944801b7e75p-7492L }, - { 0x3.e915b16b3ea952b8p-12048L, -0x3.5dde4fb68f625424p+4784L, 0x9.e6b0eef12e35a51p+4796L, 0x9.e6b0eef12e35a52p+4796L }, - { 0x8.063bbdb884d4c9fp+13076L, -0xc.690888a046c216cp+13536L, -0x2.7a0a30ea19f24dcp+13552L, -0x2.7a0a30ea19f24dbcp+13552L }, - { 0x3.33cbc218p-16416L, 0x2.577f86039916008p-5496L, -0x9.626e2d063f7c1e6p-5484L, -0x9.626e2d063f7c1e5p-5484L }, - { 0xf.97d7708bcb4c28ap+13800L, 0x1.92222235b217c128p+11344L, 0x5.4b3b99b0bd7e58cp+11356L, 0x5.4b3b99b0bd7e58c8p+11356L }, - { 0x3.7a62c19d2c7a4ef8p-1380L, 0xf.4bfc2d311b1d267p+12820L, -0x5.25a19533e5ec3898p+12832L, -0x5.25a19533e5ec389p+12832L }, - { 0x3.953c10cac334f73cp+2340L, 0x1.c610af4e1921cf5p-9256L, 0x1.039b482967f45ea8p-9244L, 0x1.039b482967f45eaap-9244L }, - { 0x2.f53d77c7f418237p+9336L, 0x3.c220b549da592788p-9580L, 0x8.9157a2d708af2c2p-9568L, 0x8.9157a2d708af2c3p-9568L }, - { 0x3.fbed3dcaaa06e4c4p-1192L, -0x3.e835e2ef87a1d7ecp-7400L, 0x1.229703d42721d65p-7388L, 0x1.229703d42721d652p-7388L }, - { 0x1.68487d450687a984p+660L, -0xf.2712729e7432756p+8724L, -0x2.71833e4eea72386cp+8736L, -0x2.71833e4eea723868p+8736L }, - { 0x3.91417fe2ad087038p+6300L, 0x7.021f29569b153f3p+4316L, 0xa.c8512daa73d6e1p+4328L, 0xa.c8512daa73d6e11p+4328L }, - { 0x3.c229138106afa45p+4436L, -0x3.676f1b1db23e0ccp+13624L, -0x3.b02d1d0112ccfa2cp+13636L, -0x3.b02d1d0112ccfa28p+13636L }, - { 0x1.aec776f7ea1c0bc6p+8464L, 0xd.28a1966f8b32e32p+11704L, 0x1.b3193facdf56a46ap+11720L, 0x1.b3193facdf56a46cp+11720L }, - { 0x1.c10c86e3b300597cp+3280L, 0x4.1a760e745f4d25cp+8252L, 0x3.4965c3cd3ca8ad3cp+8264L, 0x3.4965c3cd3ca8ad4p+8264L }, - { 0x1.b1db4fb675211df6p+0L, 0x1.6be49e4860e6d81ap+7060L, 0x1.14f3265dd400057ep+7060L, 0x1.14f3265dd400058p+7060L }, - { 0x4.b497e93cf288163p-2404L, -0x9.6961065f95443f1p-2968L, 0x5.84c8bc67a7686f48p-2956L, 0x5.84c8bc67a7686f5p-2956L }, - { 0x4.5dcb8cb337091ep+6896L, 0x5.11f25379bb653bd8p+14376L, 0x8.89e37aa0f515b74p+14388L, 0x8.89e37aa0f515b75p+14388L }, - { 0xa.7268d9e3b2e61bap+2464L, 0x7.8ebb30aae46e97dp-14932L, 0x4.8d75ec76fb62c77p-14920L, 0x4.8d75ec76fb62c778p-14920L }, - { 0x2.526a2db40e4a133p+12128L, 0x1.46f991704d64c4p-1120L, 0x3.c83fcabb8bd20458p-1108L, 0x3.c83fcabb8bd2045cp-1108L }, - { 0x8.6b4ceac3f5e0728p+13928L, 0x2.9d183c4c6fdb04a4p-9108L, 0x8.e3af724b181616bp-9096L, 0x8.e3af724b181616cp-9096L }, - { 0xb.8b98aaf25e886f9p+5156L, -0x6.d99dca78791969cp+12196L, -0x8.a0f1aedd7cc7487p+12208L, -0x8.a0f1aedd7cc7486p+12208L }, - { 0xc.075641c050086f8p+3892L, 0xe.deda4695e681519p+7992L, 0xe.2496aff9a14be97p+8004L, 0xe.2496aff9a14be98p+8004L }, - { 0x1.8c92fa660e15352ep-1228L, -0xa.5069a079cc133acp+7808L, 0x3.1733766197485eacp+7820L, 0x3.1733766197485ebp+7820L }, - { 0x2.24799a29d446fa08p-7812L, -0x4.05d8a4c62f6a18e8p-3908L, 0x7.abdfaecc0aeb94ep-3896L, 0x7.abdfaecc0aeb94e8p-3896L }, - { 0x1.a2963647b8c1e952p+1464L, -0x9.dc35dae9cfa046fp-9920L, -0x3.86a529d9cab1a628p-9908L, -0x3.86a529d9cab1a624p-9908L }, - { 0x7.42c1ce68p-16416L, -0x9.8b1dbd0b049084dp+2680L, 0x2.63dd875dd5ab9c6cp+2696L, 0x2.63dd875dd5ab9c7p+2696L }, - { 0x2.4da05a583c91938p+10540L, -0x4.25be1ba5de90e918p+932L, -0xa.ac6ed13b63a1d92p+944L, -0xa.ac6ed13b63a1d91p+944L }, - { 0x8.0e17e4b161c5a45p+2440L, -0x9.bf58078144f5743p-5248L, -0x5.d0515bfeef3843f8p-5236L, -0x5.d0515bfeef3843fp-5236L }, - { 0xd.1856d68bf52a57dp-6588L, -0x5.e570d6841b2c088p-8116L, 0x9.7a6a259ef770338p-8104L, 0x9.7a6a259ef770339p-8104L }, - { 0x9.872f5ce857da213p-1656L, 0xb.cf8a253dd36dfd2p-2832L, -0x4.c401c85ddd5c1c38p-2820L, -0x4.c401c85ddd5c1c3p-2820L }, - { 0x1.567c962075b01046p-2992L, 0x5.96dea6367a681b68p-12668L, -0x4.150f162a937d4c98p-12656L, -0x4.150f162a937d4c9p-12656L }, - { 0x2.330521783950b058p-8660L, -0x5.fd2d731707657b5p+12584L, 0xc.a91b62f8e76612cp+12596L, 0xc.a91b62f8e76612dp+12596L }, - { 0x1.6365c7132e7ab896p+14300L, 0x6.74e840f8b63c3dd8p+2708L, 0x1.68ad6bdb36c77d3ep+2724L, 0x1.68ad6bdb36c77d4p+2724L }, - { 0x1.23d9c444b8796b86p+10316L, 0x5.5531715a18534968p-13748L, 0xd.6e6068774baf9a8p-13736L, 0xd.6e6068774baf9a9p-13736L }, - { 0x7.aee9cd5902c35aa8p-404L, -0x1.79b3917e3ae0ef84p+2720L, 0x2.4fb84a5052ed5f7p+2728L, 0x2.4fb84a5052ed5f74p+2728L }, - { 0x6.800a7b095615357p+10936L, -0x3.8283a98b3d446a38p-5192L, -0x9.5f8e2dd199e2736p-5180L, -0x9.5f8e2dd199e2735p-5180L }, - { 0x1.78d6aeb5bd310056p+0L, 0x1.45e29cec4ee079d8p-3296L, 0xb.5c79c6a6c49a62bp-3300L, 0xb.5c79c6a6c49a62cp-3300L }, - { 0x4.b21a682b16590228p-13876L, -0x3.70fb6523fc99c194p+14144L, 0xb.a804c9fc9c673dfp+14156L, 0xb.a804c9fc9c673ep+14156L }, - { 0x3.23f2a35775b3a338p-8344L, 0xc.78c1635bb7ee7c4p-1084L, -0x1.966b48238708618ap-1068L, -0x1.966b482387086188p-1068L }, - { 0x3.f496d494eff66598p-12580L, 0x1.6b790fafdbb51f08p+12268L, -0x4.5c277f50b347c3f8p+12280L, -0x4.5c277f50b347c3fp+12280L }, - { 0x8.ec1b59a9caa6303p-10924L, 0x3.e8d13e253b2213ccp+628L, -0xa.6c668c91aec61d6p+640L, -0xa.6c668c91aec61d5p+640L }, - { 0xd.a1a02db93dcda76p-5712L, -0x3.07a2a2ead26ae24cp+6968L, 0x4.38ef190fdff3c19p+6980L, 0x4.38ef190fdff3c198p+6980L }, - { 0x1.a0b348b4888fa2fcp-1152L, -0xe.f9e7aa3db6ed0afp+12620L, 0x4.35a0bc4fb075f8d8p+12632L, 0x4.35a0bc4fb075f8ep+12632L }, - { 0x3.6f67cd0a4f4f4a6cp-3780L, -0xd.8095adbeaff6317p+14292L, 0xc.746980c872b61e4p+14304L, 0xc.746980c872b61e5p+14304L }, - { 0x3.c5516656a58130ccp+11040L, 0x1.c0bfa71287c3acdap-1104L, 0x4.b9ba44f7f286c4a8p-1092L, 0x4.b9ba44f7f286c4bp-1092L }, - { 0x1.d9f5b1f814163e0ep+7296L, -0x2.04efcf98cc6bd1c8p+1188L, -0x3.98e7df8daf1d5404p+1200L, -0x3.98e7df8daf1d54p+1200L }, - { 0x3.a704d93ae36e79c4p-2416L, 0xa.3c0c59ab56e5e6cp+3204L, -0x6.0839412e892258p+3216L, -0x6.0839412e892257f8p+3216L }, - { 0x1.ff1cd2d2fae4bd48p+0L, -0xc.beb414075682a59p+4332L, -0xc.b689b68cb462e06p+4332L, -0xc.b689b68cb462e05p+4332L }, - { 0x7.865db97fb832a698p-3852L, 0x3.210fd99d2fe72c7p+10992L, -0x2.f0c5e11a2cdeea2cp+11004L, -0x2.f0c5e11a2cdeea28p+11004L }, - { 0x4.2bc44b2356390acp-4624L, -0x7.cd81763c0a3f1938p-10236L, 0x8.cdfdec8404d7021p-10224L, 0x8.cdfdec8404d7022p-10224L }, - { 0xf.6e6ebaa083c4cd3p+6772L, 0x3.53aa70c4188f244p-6152L, 0x5.80e5ae2af4891598p-6140L, 0x5.80e5ae2af48915ap-6140L }, - { 0xe.77c56c623d0f0eep-3144L, 0x8.6f79329139f632dp+3132L, -0x6.7788429ecc43227p+3144L, -0x6.7788429ecc432268p+3144L }, - { 0x7.b93a559e4e12075p-9120L, -0x1.351b28adc68b89bcp-13008L, 0x2.b0057e68ca71b908p-12996L, 0x2.b0057e68ca71b90cp-12996L }, - { 0x1.80e63adf125be828p+2620L, -0x6.b3b07792c5acf1b8p+4564L, -0x4.49af36f38515eb78p+4576L, -0x4.49af36f38515eb7p+4576L }, - { 0x1.f5bda0c135772ea8p-14388L, 0x1.d2d15b323301604cp+6960L, -0x6.67ad949e9dd71688p+6972L, -0x6.67ad949e9dd7168p+6972L }, - { 0xe.eba318936113b91p-13680L, -0x7.e2bc9165ba0d4e7p-744L, 0x1.a5457d1a3b4bf81cp-728L, 0x1.a5457d1a3b4bf81ep-728L }, - { 0x1.a2e010d583127526p+3200L, 0x1.e8a7eb43e7eecf8ep-11800L, 0x1.7dd8e1e0fb4c040cp-11788L, 0x1.7dd8e1e0fb4c040ep-11788L }, - { 0x2.089221e2807b8ae8p+1780L, -0x1.67ebc2e75a0f1464p+7020L, -0x9.c803d1c26ea95eap+7028L, -0x9.c803d1c26ea95e9p+7028L }, - { 0x4.0ac05ec8p-16416L, -0xa.530c1b060238f06p-5476L, 0x2.95f89a58fc3e6abp-5460L, 0x2.95f89a58fc3e6ab4p-5460L }, - { 0x3.aa0cc319c013919p-6132L, -0xf.0292f4401d18d5cp+4904L, 0x1.676d88de1fc94da8p+4920L, 0x1.676d88de1fc94daap+4920L }, - { 0x6.fd442271482ca6dp-14508L, -0x6.67012d8b67014328p+3032L, 0x1.6ac38118c5f3b35cp+3048L, 0x1.6ac38118c5f3b35ep+3048L }, - { 0x1.4d6d06de5fee4cc4p-7248L, -0x9.620bcddbdd20a79p-8756L, 0x1.09a45a7db576a522p-8740L, 0x1.09a45a7db576a524p-8740L }, - { 0x8.2e6ecc0d5fbbd0ap-1672L, -0x1.a3b873c6b160474p-2868L, 0xa.b053f78195d37f2p-2860L, 0xa.b053f78195d37f3p-2860L }, - { 0x2.c4d0c300d64c511p+7888L, 0xd.81985e859cf4061p+14748L, 0x1.a03cff013e09efbap+14764L, 0x1.a03cff013e09efbcp+14764L }, - { 0x2.3c05e4cb4622a66p-13256L, 0x3.cf39982caefbf098p-14636L, -0xc.53df31e9a942054p-14624L, -0xc.53df31e9a942053p-14624L }, - { 0x1.8dad3bd8dae62b26p+9496L, -0x3.f54fb00da54140bcp-6956L, -0x9.2d607d3aa28d78fp-6944L, -0x9.2d607d3aa28d78ep-6944L }, - { 0x1.53961f1d7569affp-5204L, -0x9.3feda7319eb8e46p+11244L, 0xb.c03c5caa9f7303ap+11256L, 0xb.c03c5caa9f7303bp+11256L }, - { 0x1.e3f51e1e159cf164p-1700L, -0x1.ee40d6991aa1e62cp-1968L, 0xc.d0607a66892a6d7p-1960L, 0xc.d0607a66892a6d8p-1960L }, - { 0xe.bee987bad9326dap-2508L, -0x3.a34a091c39f5bd5p-4752L, 0x2.39599d7487d87de4p-4740L, 0x2.39599d7487d87de8p-4740L }, - { 0x1.d1f2488e01bece42p+0L, 0x7.3390d5c71ae5e8f8p+4120L, 0x6.38e0cf11409a5648p+4120L, 0x6.38e0cf11409a565p+4120L }, - { 0x5.e2a8926a1f2a69f8p-1008L, -0x4.b1c091043808ebe8p+10972L, 0x1.26fe52f8e473663p+10984L, 0x1.26fe52f8e4736632p+10984L }, - { 0x1.8989c2560de848e8p+14156L, -0xf.7833feab3b30637p-11276L, -0x3.577473e6616fea3p-11260L, -0x3.577473e6616fea2cp-11260L }, - { 0x6.c87c79c7f39458b8p-12544L, 0xb.d70d015b5f04174p+8408L, -0x2.4408c9a20dd4504p+8424L, -0x2.4408c9a20dd4503cp+8424L }, - { 0xd.4a8d8fca0cbe02bp+5456L, 0x6.f866735c25236f98p+1300L, 0x9.4a80b93e0752cc4p+1312L, 0x9.4a80b93e0752cc5p+1312L }, - { 0x6.48ac3faff9ac8af8p+13024L, 0x1.62b2ac359758568p+3048L, 0x4.680ee828882103ep+3060L, 0x4.680ee828882103e8p+3060L }, - { 0xa.a22cceb5d16a7b9p+12552L, 0x1.e6ecf4dcc20e1c9ap+3900L, 0x5.d490ef450521d888p+3912L, 0x5.d490ef450521d89p+3912L }, - { 0x1.830dd48479f78adap+2696L, -0x1.3cbe7875c4da1bacp+13696L, -0xd.0872cbd8e0bf46bp+13704L, -0xd.0872cbd8e0bf46ap+13704L }, - { 0xa.c01d2e9cf20bab2p-3968L, -0x3.294bc4bc541628p-3004L, 0x3.0f54180488efda18p-2992L, 0x3.0f54180488efda1cp-2992L }, - { 0x3.e058d43b80e19b7cp+11400L, -0x7.810b603203760db8p+9496L, -0x1.4e392da4e7b28d82p+9512L, -0x1.4e392da4e7b28d8p+9512L }, - { 0x1.ba7195161943bbbep+12644L, -0x1.f393533d8bcf2b9p-6464L, -0x6.063e2d250c93d678p-6452L, -0x6.063e2d250c93d67p-6452L }, - { 0x1.1f75457p-16416L, -0x3.f70754c334988a7cp+7532L, 0xf.e400c62e39970d1p+7544L, 0xf.e400c62e39970d2p+7544L }, - { 0x3.731a5226115dd018p-10664L, -0x5.a44d891b492c118p+6688L, 0xe.afa29af29c307fp+6700L, 0xe.afa29af29c307f1p+6700L }, - { 0x5.b4fdcb6dd89d9c6p+11124L, -0xb.318ae2fc05a5137p-14500L, -0x1.e680e7664b81aa66p-14484L, -0x1.e680e7664b81aa64p-14484L }, - { 0x1.79ab15d5ea5af81ep-14952L, 0x4.f22aafc2c87dc378p+5960L, -0x1.20dd46df8b6d5d0ep+5976L, -0x1.20dd46df8b6d5d0cp+5976L }, - { 0x5.7ae9f319702197fp+1424L, -0x5.2488fe3916fe2e88p+10340L, -0x1.ca7d914199218ff6p+10352L, -0x1.ca7d914199218ff4p+10352L }, - { 0x1.7e566d05fa4bfe68p-11828L, -0xf.77808166e893761p+7896L, 0x2.ca9469fa524cdc5p+7912L, 0x2.ca9469fa524cdc54p+7912L }, - { 0xa.d514038a07e5b37p+12964L, 0x1.629f9336bc3a571p+1948L, 0x4.62b1beae45dbf53p+1960L, 0x4.62b1beae45dbf538p+1960L }, - { 0x4.3bf7a1a300a5f018p+10364L, -0xf.f30d3f07ad37473p+12984L, -0x2.85d5019bf4601528p+13000L, -0x2.85d5019bf4601524p+13000L }, - { 0x2.6b5061434883623p-9208L, 0x9.a456d030af10e3ap-14264L, -0x1.5ac2c899349909fp-14248L, -0x1.5ac2c899349909eep-14248L }, - { 0xe.89c1a581a13c8eap-12176L, -0x2.da80e03a956954f4p+13388L, 0x8.7ad8ca0015fc69dp+13400L, 0x8.7ad8ca0015fc69ep+13400L }, - { 0xf.0b6de12e05c3635p+10332L, 0x1.49091d3c30a38fe2p+8540L, 0x3.3e4b2c2a174d602p+8552L, 0x3.3e4b2c2a174d6024p+8552L }, - { 0x3.1086147p-16416L, -0xa.9787fe8322a2a72p-10772L, 0x2.a723d3adbf2fd25p-10756L, 0x2.a723d3adbf2fd254p-10756L }, - { 0x2.ce0956e8786046bp-8960L, 0x7.2bd571ac8ece1a28p-14644L, -0xf.af382fad626ef52p-14632L, -0xf.af382fad626ef51p-14632L }, - { 0x5.0c6e2ff0203fe848p+13020L, -0x1.07ec467a6a9c5c22p-8240L, -0x3.4715d4de6a6a238p-8228L, -0x3.4715d4de6a6a237cp-8228L }, - { 0x1.33b9813117d5b116p-8692L, -0x3.d4488a6e55d0c3cp+8188L, 0x8.202aab93e9336b5p+8200L, 0x8.202aab93e9336b6p+8200L }, - { 0x1.45a904169e9fbd9cp-6008L, -0x1.94df821b8722bfaep+11360L, 0x2.51d50e0975a72d2cp+11372L, 0x2.51d50e0975a72d3p+11372L }, - { 0x3.f58aff984b9b3204p+9232L, -0x3.a6650315666a36fcp-14312L, -0x8.3a7d9b2f7306025p-14300L, -0x8.3a7d9b2f7306024p-14300L }, - { 0x9.39fedfcb334646bp-480L, -0x1.f25409b8f76e0daap+11056L, 0x3.a02008fe8682753p+11064L, 0x3.a02008fe86827534p+11064L }, - { 0x6.0516ed4c30287198p+8164L, -0x1.7089f60565c4e04ep-6796L, -0x2.decaa14cd6f9a774p-6784L, -0x2.decaa14cd6f9a77p-6784L }, - { 0x8.d065ef1229a853cp+11308L, -0xd.57b3e95e8e6b01cp+2380L, -0x2.4d87e3ad36e3efc8p+2396L, -0x2.4d87e3ad36e3efc4p+2396L }, - { 0x2.fa1ba053149e004cp-656L, -0x2.7fd142bf349abf18p-2276L, 0x6.639940c58c55f74p-2268L, 0x6.639940c58c55f748p-2268L }, - { 0xf.c238b2baa010058p+9912L, 0x4.59241972fc24c5a8p+11548L, 0xa.86cb9e1cc4f0be8p+11560L, 0xa.86cb9e1cc4f0be9p+11560L }, - { 0x1.d646aaa62a9383e6p+0L, 0x3.00f84a86bb91dbap-6056L, 0x2.a2aaa0b9b93a6c6p-6056L, 0x2.a2aaa0b9b93a6c64p-6056L }, - { 0x2.77f437759361e3fp-2356L, -0x3.0610c5014f9956a8p-8032L, 0x1.bcfe133b031e1e7p-8020L, 0x1.bcfe133b031e1e72p-8020L }, - { 0x1.bc5bfdb21630a828p+4076L, -0x6.3a84a13517144a38p+4628L, -0x6.330ac4906176e618p+4640L, -0x6.330ac4906176e61p+4640L }, - { 0xd.6d13288b708cd99p+5852L, -0x4.2028a34835ab7088p+13624L, -0x5.e5e9658792a973fp+13636L, -0x5.e5e9658792a973e8p+13636L }, - { 0x2.fa0781a5ce6c3e88p+6884L, 0x1.c6c301a4213c2a1p+14212L, 0x2.fc79f81093748b58p+14224L, 0x2.fc79f81093748b5cp+14224L }, - { 0x5.9f857743c692f8a8p-11492L, -0x2.8b763c9b1e5765dcp+5088L, 0x7.23630afba9bef2cp+5100L, 0x7.23630afba9bef2c8p+5100L }, - { 0x7.a2e7744675542a68p+4476L, 0x9.93f484e751c1e49p+4604L, 0xa.792fe8f5fdd5e07p+4616L, 0xa.792fe8f5fdd5e08p+4616L }, - { 0x1.11daae277d6f5364p-8812L, -0x3.d9d851412428f74p+7268L, 0x8.48e4229b98372p+7280L, 0x8.48e4229b9837201p+7280L }, - { 0x1.599e76b4add8a768p+12640L, 0xc.0312220675c48dep-8384L, 0x2.511cd2efecb3462cp-8368L, 0x2.511cd2efecb3463p-8368L }, - { 0x1.d76fce983ea18f04p+3984L, 0xd.3b162e429a284abp-7116L, 0xc.df330f0e1231f7bp-7104L, 0xc.df330f0e1231f7cp-7104L }, - { 0x1.8b74ca29e35918d2p-436L, -0x2.54fefc87c991985p+2764L, 0x3.f74bbbe1e37fc588p+2772L, 0x3.f74bbbe1e37fc58cp+2772L }, - { 0xc.fb85e61563cc723p-4L, -0x1.5cd1de7bbfdd138p-14584L, 0x6.92b84a87a4b81f6p-14588L, 0x6.92b84a87a4b81f68p-14588L }, - { 0x4.06dfa8140d8a6c8p-12744L, -0x1.44ff72f9afcc807cp+10848L, 0x3.f303f71b131fd3d4p+10860L, 0x3.f303f71b131fd3d8p+10860L }, - { 0x1.5eaf968af0056a88p+2204L, -0x7.35ddb1c4dfd4818p+8056L, -0x3.e1706bd38b2ad348p+8068L, -0x3.e1706bd38b2ad344p+8068L }, - { 0x1.f79b47daf4ce0c82p+13516L, 0x4.7522f5f4f67f2aa8p-60L, 0xe.b5ccbbe59c33412p-48L, 0xe.b5ccbbe59c33413p-48L }, - { 0x1.45e7258945383cdap+1872L, -0x3.206a35c1d871c654p+3456L, -0x1.6de1f719d8e923e2p+3468L, -0x1.6de1f719d8e923ep+3468L }, - { 0x8.c482717e9cf14a6p-7368L, -0x2.9b72ec9fe7478ae8p-716L, 0x4.b01d9179e2b0c0c8p-704L, 0x4.b01d9179e2b0c0dp-704L }, - { 0x3.5aa11443b7f48ef8p-8396L, -0x1.5837711dfe654728p+5476L, 0x2.c16e15ae8bd79e5cp+5488L, 0x2.c16e15ae8bd79e6p+5488L }, - { 0x2.53bd4242192f7ab4p+14312L, -0x2.a60390f68f368cecp+9468L, -0x9.414718fc5f5020bp+9480L, -0x9.414718fc5f5020ap+9480L }, - { 0x3.7ce54eadcdde9f24p-3904L, -0x1.501e18a96a20b756p-1544L, 0x1.4036d2b1739a047cp-1532L, 0x1.4036d2b1739a047ep-1532L }, - { 0xd.5b4db41cff6f2cap+4432L, -0x1.570fa20acb2ddc2ep+13024L, -0x1.7384184ab61b5b9p+13036L, -0x1.7384184ab61b5b8ep+13036L }, - { 0x2.88f36222719718e8p-1928L, -0x4.fbec2f96890bc5e8p+6228L, 0x2.5829a880863725e8p+6240L, 0x2.5829a880863725ecp+6240L }, - { 0x1.efcbb15e88adf09p+0L, 0xc.97d62d013af0088p+8488L, 0xc.0241b42358d14d1p+8488L, 0xc.0241b42358d14d2p+8488L }, - { 0x5.f09eeb96dc538558p-4736L, 0x5.098d7678f15a72p-4304L, -0x5.d23c6567e92e3838p-4292L, -0x5.d23c6567e92e383p-4292L }, - { 0x1.0c3d81a001f325bep-3164L, -0x8.2d7911586469751p+564L, 0x6.51177426b609ff5p+576L, 0x6.51177426b609ff58p+576L }, - { 0xb.b5dda03bd01aa1bp-2384L, 0x3.80f852e5b49c1f08p-6208L, -0x2.0949885ea1918fccp-6196L, -0x2.0949885ea1918fc8p-6196L }, - { 0x4.7683b95a2d97f8ap-5156L, -0x4.35b7f1c56a3d2cbp+1424L, 0x5.4c0d70ada064bc7p+1436L, 0x5.4c0d70ada064bc78p+1436L }, - { 0x2.bdaaef3c4b35064p+11680L, -0x2.faa1909111fad7dcp+14388L, -0x8.7ef60bf38a0dd3ep+14400L, -0x8.7ef60bf38a0dd3dp+14400L }, - { 0x5.d46d6048b5d6e628p-9212L, 0xd.71bd470441c9db9p-9948L, -0x1.e3a6a527a3ea5d7ap-9932L, -0x1.e3a6a527a3ea5d78p-9932L }, - { 0x1.5f8f1649fa66406p+6520L, -0x1.63725477bb562e8cp+1156L, -0x2.35d6a805caba07c8p+1168L, -0x2.35d6a805caba07c4p+1168L }, - { 0xe.e3fdb321f26f9c4p+6484L, -0x3.b60b3167c404578p-3056L, -0x5.e0d492e2b6ee28b8p-3044L, -0x5.e0d492e2b6ee28bp-3044L }, - { 0x7.c4487897dc41f578p-5772L, 0x6.22ee9224c3c35c1p+10016L, -0x8.a49754c89a1f8f7p+10028L, -0x8.a49754c89a1f8f6p+10028L }, - { 0x2.db79f9dd4c22fe8p-11264L, -0x9.3987a9a321c2401p+48L, 0x1.95d5583932101174p+64L, 0x1.95d5583932101176p+64L }, - { 0xb.214592ce214ecfep-4L, -0x2.e889a996b77521fcp+10320L, 0x1.85db50a2a5f1944cp+10320L, 0x1.85db50a2a5f1944ep+10320L }, - { 0x6.80b6787c7ed0c98p-7488L, 0x2.6be4487c1dcd7bfp-1488L, -0x4.6cd4aeb3074b39c8p-1476L, -0x4.6cd4aeb3074b39cp-1476L }, - { 0x6.e3da0acb9e1505fp-2772L, -0x5.f7c7fac38340451p+11136L, 0x4.08e6346af3f436b8p+11148L, 0x4.08e6346af3f436cp+11148L }, - { 0x3.313fa5881a2d6e5cp-9600L, 0x2.1ac7da26f1204bfcp-2664L, -0x4.ee8c0326a97c7bf8p-2652L, -0x4.ee8c0326a97c7bfp-2652L }, - { 0x2.62f5aab737b6705p+4216L, -0xf.65bfa7da3df8702p-5984L, -0xf.da6fef5fb57dd6p-5972L, -0xf.da6fef5fb57dd5fp-5972L }, - { 0xc.e4018849b76a23ap+14856L, 0xc.90289d1db5a105cp-192L, 0x2.d93c0adf50cdc9bp-176L, 0x2.d93c0adf50cdc9b4p-176L }, - { 0x1.c0f835ea894de5f4p-10024L, -0xa.50a22423b6723b2p-2320L, 0x1.93dcf0ad050407e8p-2304L, 0x1.93dcf0ad050407eap-2304L }, - { 0x3.6383fb20c10cc778p+14900L, -0xa.7913fd7ca999ff9p-10828L, -0x2.61a190302a99bc9p-10812L, -0x2.61a190302a99bc8cp-10812L }, - { 0x1.be2aea0c1a473f64p+14204L, 0x3.b5e9eee471131f3p+4752L, 0xc.de458efd065f26ep+4764L, 0xc.de458efd065f26fp+4764L }, - { 0x1.21bc96f47956350ep+4740L, 0x7.f8fdeae69d08eb7p+8496L, 0x9.39fa9f5f9ddd9a5p+8508L, 0x9.39fa9f5f9ddd9a6p+8508L }, - { 0x4.9f7437754e62375p-4876L, -0x4.90b85f6fbc1b8688p+8944L, 0x5.6ea6245478d9c558p+8956L, 0x5.6ea6245478d9c56p+8956L }, - { 0x7.e866902p-16416L, 0xf.317f8a3f97460cep-7188L, -0x3.ce18bf0bbbe749e4p-7172L, -0x3.ce18bf0bbbe749ep-7172L }, - { 0x6.a13f4e0f825a5edp-4440L, -0x1.99bf7b4b74e4b654p+5044L, 0x1.bbe32d09c4b547a2p+5056L, 0x1.bbe32d09c4b547a4p+5056L }, - { 0x7.54085e25bafd5bd8p+3704L, 0x1.db179fdf5aef456ap-13196L, 0x1.adf52fae66292f0ep-13184L, 0x1.adf52fae66292f1p-13184L }, - { 0x6.fc29f1b82c7f8a7p-1712L, 0x7.3136749a8e732cbp+12372L, -0x3.004f0ed0aea3e038p+12384L, -0x3.004f0ed0aea3e034p+12384L }, - { 0xe.2487cdb8e096076p-1392L, -0x2.b7d3c8f4fa93f2dcp-11416L, 0xe.bd2c23a004fef05p-11408L, 0xe.bd2c23a004fef06p-11408L }, - { 0x1.0a524b330b6d1cf8p+3992L, 0x6.f2be0ff2b50477ap-88L, 0x6.c59a9376d2d243f8p-76L, 0x6.c59a9376d2d244p-76L }, - { 0x4.53290c103cf68ddp+1876L, -0x2.7b48218ca4945d54p-184L, -0x1.234aab65fdcc0972p-172L, -0x1.234aab65fdcc097p-172L }, - { 0x5.f854a5860d3485fp+11712L, 0x3.e2501079eb01d518p-972L, 0xb.1bbd2067493cbf4p-960L, 0xb.1bbd2067493cbf5p-960L }, - { 0x7.c586111d11b319f8p-13432L, -0x1.a13ae4a3354b1b9cp-4876L, 0x5.57eb7cb8deede698p-4864L, 0x5.57eb7cb8deede6ap-4864L }, - { 0x8.d2126b4d376bf71p+6480L, -0xb.c76f499facfc4cbp+5248L, -0x1.2a4d3012ac4367c2p+5264L, -0x1.2a4d3012ac4367cp+5264L }, - { 0x8.af0132d6f3c8239p-1932L, 0x2.179549e27c305d7p-7188L, -0xf.c3748e5a2f3e907p-7180L, -0xf.c3748e5a2f3e906p-7180L }, - { 0xa.e384039aa141762p-4L, -0xd.84901915b6223efp+3372L, 0x7.816daa88ba083fbp+3372L, 0x7.816daa88ba083fb8p+3372L }, - { 0x7.a25f680376b80218p+10772L, 0x1.fa22f565869b428ep-7916L, 0x5.337133b5a9625a98p-7904L, 0x5.337133b5a9625aap-7904L }, - { 0x1.a82f4735f426182cp+708L, -0x3.06c97154863b8668p+11728L, -0x8.60f995bea7d1f3ep+11736L, -0x8.60f995bea7d1f3dp+11736L }, - { 0x6.f0206ea828b61b08p+6012L, 0x3.551406b5d024e324p-4656L, 0x4.e4b523f064ac9a2p-4644L, 0x4.e4b523f064ac9a28p-4644L }, - { 0x1.6f789d7564f928e8p-3864L, 0x5.4600f951d5eba66p-9312L, -0x4.f95deb0b036b9c7p-9300L, -0x4.f95deb0b036b9c68p-9300L }, - { 0x3.0a8648ba053122fp-1060L, 0x1.91cf22af1ab650a4p+7572L, -0x6.7d38ed8edc9459e8p+7580L, -0x6.7d38ed8edc9459ep+7580L }, - { 0x8.bc7d07ddb2c022p+5920L, 0x6.10774af59183db48p+4288L, 0x8.c4fbd3cdc063727p+4300L, 0x8.c4fbd3cdc063728p+4300L }, - { 0x3.5799356238e9851p+9016L, 0xa.169ce0f7fec2be6p+12212L, 0x1.635df4dc89456662p+12228L, 0x1.635df4dc89456664p+12228L }, - { 0x1.01d4b210da78dd4cp+11956L, -0x6.e1bf3c78ece6063p+10052L, -0x1.41672971127f38a4p+10068L, -0x1.41672971127f38a2p+10068L }, - { 0xf.d84c5b3d6730ba3p+8852L, -0x1.9f855997d2792acep-6872L, -0x3.826673c9aa64c2c4p-6860L, -0x3.826673c9aa64c2cp-6860L }, - { 0x5.8ce7c53b96255d4p+13568L, -0xe.df6fe073a22e50cp-12344L, -0x3.1466efb79f69482p-12328L, -0x3.1466efb79f69481cp-12328L }, - { 0x6.75dca56p-16416L, -0x5.d3093bb8c581a6e8p-10216L, 0x1.756d02c70d3f1626p-10200L, 0x1.756d02c70d3f1628p-10200L }, - { 0xc.d570e244c0e60bep-12400L, -0x7.8ae826298b8c69ap+11848L, 0x1.6d3c875ec58ba32ap+11864L, 0x1.6d3c875ec58ba32cp+11864L }, - { 0x7.84802e101bb6a3f8p-5756L, -0x7.995991a529314d5p+2864L, 0xa.ac5dc693017439dp+2876L, 0xa.ac5dc693017439ep+2876L }, - { 0x1.25970c4a9d9bfa12p+4480L, -0x1.2660afac683e1d8ep+14004L, -0x1.41fd632043cb071ep+14016L, -0x1.41fd632043cb071cp+14016L }, - { 0x1.c8b98918c3fb8242p-364L, 0x9.c0fa6e13b7c7fcp-2056L, -0xd.d63ea6a5acb5b84p-2048L, -0xd.d63ea6a5acb5b83p-2048L }, - { 0x2.b29ea16d605290c8p-14036L, 0x2.57c6bfd9ce8106fp-4776L, -0x8.07142545c68a338p-4764L, -0x8.07142545c68a337p-4764L }, - { 0x1.179a8074009c3446p-7324L, -0x8.1c9d05645c7987cp-4408L, 0xe.811940c7fc9af73p-4396L, 0xe.811940c7fc9af74p-4396L }, - { 0x1.a274b5d250ba4a7ap-14136L, -0x9.4cf62e7e77f656p-7444L, 0x2.018b21e6dce1dfacp-7428L, 0x2.018b21e6dce1dfbp-7428L }, - { 0x1.426ce0de34aa412ap-7048L, -0x1.086b031d68e9f6fap-7232L, 0x1.c6f6a2cc131aca9p-7220L, 0x1.c6f6a2cc131aca92p-7220L }, - { 0x6.dcdeb470b2fc188p+14208L, 0x2.0ff586b55e3364a4p-8660L, 0x7.27b75caeddd08bdp-8648L, 0x7.27b75caeddd08bd8p-8648L }, - { 0xf.30d46d764112444p+192L, -0x5.e6a539ee1aceb9b8p-2624L, -0x4.84256283872b606p-2616L, -0x4.84256283872b6058p-2616L }, - { 0xa.8afac152291530ap-4L, -0x5.9e1738c1ccd8a9a8p-20L, 0x3.617206ff8982409cp-20L, 0x3.617206ff898240ap-20L }, - { 0xa.4bd5c8afa05a28cp-10580L, -0x1.23804bdf5e1e2c04p+9232L, 0x2.f0b5da03924596b4p+9244L, 0x2.f0b5da03924596b8p+9244L }, - { 0x2.ceafdb5372991918p+2280L, 0x7.bc4dc1a54a48fdbp+5068L, 0x4.4f099a01d4cd5418p+5080L, 0x4.4f099a01d4cd542p+5080L }, - { 0x3.fc5a846dfbec9adp-9172L, 0x3.b4c03ba6cf5a812p-3940L, -0x8.4c092babb4e1d41p-3928L, -0x8.4c092babb4e1d4p-3928L }, - { 0x3.14be1ced6c3553bcp+1944L, -0xa.e04dd91094312efp-2976L, -0x5.2a8f73a173accdb8p-2964L, -0x5.2a8f73a173accdbp-2964L }, - { 0x2.2c4ef645ea46758p+8712L, 0x6.d3f30796d0334a7p+11056L, 0xe.8648bda7e0f6294p+11068L, 0xe.8648bda7e0f6295p+11068L }, - { 0x4.b6b357f4259a83ap-10956L, -0x8.d45410dc1895ef4p+11920L, 0x1.79cb3dbc67eac20cp+11936L, 0x1.79cb3dbc67eac20ep+11936L }, - { 0x4.38896f39ca42f888p-5568L, 0x5.28bf133fa6f14d3p-3772L, -0x7.02b83fde3a8b00dp-3760L, -0x7.02b83fde3a8b00c8p-3760L }, - { 0x1.6739091433ebe3bap+7952L, 0x3.77db8ced789b50ep-4560L, 0x6.bbcc5b6ebb15a848p-4548L, 0x6.bbcc5b6ebb15a85p-4548L }, - { 0x2.6e82f4e37e55fa08p+480L, 0x7.f37ea4723b67675p+10636L, 0xe.f2bedee5c61d497p+10644L, 0xe.f2bedee5c61d498p+10644L }, - { 0x1.5fac4bb395ba2bccp+4156L, -0x4.ad1adda7354f267p-4744L, -0x4.bec64886a213215p-4732L, -0x4.bec64886a2132148p-4732L }, - { 0x2.a62a7e9p-16416L, -0x1.08fba0f001a4ad6p+6040L, 0x4.25e934181bdf777p+6052L, 0x4.25e934181bdf7778p+6052L }, - { 0x1.749ae18d5c47f94ep-13280L, 0x5.d580a2b2bafe339p-6680L, -0x1.2ea0483b70c44786p-6664L, -0x1.2ea0483b70c44784p-6664L }, - { 0x1.58297b3f01d01614p+4120L, 0x1.0f95b19865e46e46p-848L, 0x1.1134515c360fd09ep-836L, 0x1.1134515c360fd0ap-836L }, - { 0x4.a3a8a81ba62dd2ep+10816L, -0x7.dc627c37bc9c54d8p-7548L, -0x1.4c30a83a929ac21ep-7532L, -0x1.4c30a83a929ac21cp-7532L }, - { 0x7.289dc72de566113p-2256L, 0x4.98b3897e6f049388p-13832L, -0x2.874a0b468128b94cp-13820L, -0x2.874a0b468128b948p-13820L }, - { 0x9.8f2b30dd1fe6e25p-4736L, -0x2.78a78fa09bce90f4p-9784L, 0x2.db00f635c2145e2cp-9772L, 0x2.db00f635c2145e3p-9772L }, - { 0x5.c89b4377f34a817p+6700L, -0x1.8aae5b4631e05fa4p-348L, -0x2.85d728f29858853cp-336L, -0x2.85d728f298588538p-336L }, - { 0x5.a8ced3fe21a70d68p-4096L, 0x5.2deec40853fa524p-1044L, -0x5.2d1f88ec24116c38p-1032L, -0x5.2d1f88ec24116c3p-1032L }, - { 0x2.7d2734d21b77549p-2196L, 0x8.aa549d7c779757cp-9208L, -0x4.a49b7a241fea8f4p-9196L, -0x4.a49b7a241fea8f38p-9196L }, - { 0x7.b8041d5b3bbff3ap+12080L, 0x6.cbce06dc637006ep-13696L, 0x1.40c5137e55d4c17ep-13680L, 0x1.40c5137e55d4c18p-13680L }, - { 0x2.fc10d82242c59c8cp-12304L, -0x7.6637c2344d0ca91p+5988L, 0x1.63952bab4a1661f6p+6004L, 0x1.63952bab4a1661f8p+6004L }, - { 0x7.eceb7efp-16416L, -0x1.0130744d8cd6c3f2p+7712L, 0x4.0694309a8adc05bp+7724L, 0x4.0694309a8adc05b8p+7724L }, - { 0x5.64bdddf529c9a6dp-9832L, -0x6.58f61fd8c5e3ec6p+3184L, 0xf.3b93e106624f0dp+3196L, 0xf.3b93e106624f0d1p+3196L }, - { 0x1.990690db94ff14d8p-2496L, -0x1.6f80a4634a39b2d2p-992L, 0xd.fe2dcfcc7595336p-984L, 0xd.fe2dcfcc7595337p-984L }, - { 0x9.fb2ddd234c8a1e1p-6780L, -0xa.5203c030e1c9aa7p-11896L, 0x1.1131d9f0246b6b0cp-11880L, 0x1.1131d9f0246b6b0ep-11880L }, - { 0xf.3050779847dc78ep-15004L, 0x3.95b4f2d22803a954p-1624L, -0xd.20c275868938d06p-1612L, -0xd.20c275868938d05p-1612L }, - { 0x6.7697c3e239db107p+10048L, 0x1.21545bdaae9fde28p-9920L, 0x2.c5f3a0898c76a22p-9908L, 0x2.c5f3a0898c76a224p-9908L }, - { 0x2.c39c3b1642e4fb18p-13664L, 0x1.1fc8462fb1f9d056p+988L, -0x3.bfebb82e0cc421ap+1000L, -0x3.bfebb82e0cc4219cp+1000L }, - { 0x2.ff120c969ae503b8p+3064L, -0x2.431fbfb49e7b4928p-9856L, -0x1.b16f8df41d25490ap-9844L, -0x1.b16f8df41d254908p-9844L }, - { 0x6.976ed0ef48c07898p-8216L, -0x4.6c8e610cee69d8dp-12772L, 0x8.deff03b117f428dp-12760L, 0x8.deff03b117f428ep-12760L }, - { 0x2.6fa1664ea3a1be14p-2884L, 0x1.63214b8ba5b95b7cp-3720L, -0xf.9efae89cadca879p-3712L, -0xf.9efae89cadca878p-3712L }, - { 0x2.e1cf29eba91248ep-152L, -0x4.589495f2b172e14p+5176L, 0x2.8df5325dc46aa2a4p+5184L, 0x2.8df5325dc46aa2a8p+5184L }, - { 0x5.bdc83bdp-16416L, -0x1.5a0086d9ae7633cep+10348L, 0x5.6a7f95f9b29fe038p+10360L, 0x5.6a7f95f9b29fe04p+10360L }, - { 0x1.3bc8b60293078f84p-11188L, -0xd.1712b08be6e7f9cp-7148L, 0x2.3c10661bfd903a2cp-7132L, 0x2.3c10661bfd903a3p-7132L }, - { 0x1.e7590332a0320ee4p+4180L, -0x8.c39f3bc3d0d8d73p+1072L, -0x8.f2247e086109516p+1084L, -0x8.f2247e086109515p+1084L }, - { 0x6.4a24ad49492e8648p-9284L, -0xf.be9fc104f449286p+7428L, 0x2.3ad3547099aaf9e8p+7444L, 0x2.3ad3547099aaf9ecp+7444L }, - { 0xf.8fb50e1402f38bp-4824L, 0x2.9deafdf9778819d4p+2484L, -0x3.1456753ac5fc7a9cp+2496L, -0x3.1456753ac5fc7a98p+2496L }, - { 0xd.3ea27eab88fb691p+14284L, -0x1.cba84ae0173bf72p+3824L, -0x6.436237e69f433458p+3836L, -0x6.436237e69f43345p+3836L }, - { 0x1.fbcc353d750f0c24p-6280L, -0xc.2cc3adaa5f76bd8p-8112L, 0x1.2a9e188779743a3ap-8096L, 0x1.2a9e188779743a3cp-8096L }, - { 0x5.1653c9d362cef54p-14708L, -0xb.c9870bb9c74469p+5028L, 0x2.a51ab90a18a8738cp+5044L, 0x2.a51ab90a18a8739p+5044L }, - { 0x7.36b4057f96e568dp+8176L, -0xf.f37001ee9d18068p-6500L, -0x1.fd9c420b6f4867fcp-6484L, -0x1.fd9c420b6f4867fap-6484L }, - { 0x1.f1d5273873448298p-7948L, -0xd.38eafd3878fe2f4p+14696L, 0x1.9a766fcad504a18cp+14712L, 0x1.9a766fcad504a18ep+14712L }, - { 0xe.2ad91bdabc94c8ap+4988L, 0x3.95448e4e9f0ea9ap-13040L, 0x4.5de17dc1f4a7fab8p-13028L, 0x4.5de17dc1f4a7facp-13028L }, - { 0x6.99d9f3e8p-16416L, -0x1.ad91e546b1cb6ebap-9228L, 0x6.b9599f96d124ec8p-9216L, 0x6.b9599f96d124ec88p-9216L }, - { 0x1.f5e39c6453df56cep+3976L, -0xd.82073d1dadfc559p-13696L, -0xd.1d89ef310c16451p-13684L, -0xd.1d89ef310c1645p-13684L }, - { 0xb.edb1abf0414bf32p+4928L, -0xd.e8fd8b2f5f7e274p-1624L, -0x1.0bf6d0071c8443aap-1608L, -0x1.0bf6d0071c8443a8p-1608L }, - { 0x2.4441537d38fcde3p-10736L, 0x6.d2a95499ed5d399p+8560L, -0x1.1e1a8f495e7a1a52p+8576L, -0x1.1e1a8f495e7a1a5p+8576L }, - { 0x8.350f634f3bac009p+8676L, -0x2.d48a8e03034cffdcp+14208L, -0x5.ff3c0112847868d8p+14220L, -0x5.ff3c0112847868dp+14220L }, - { 0x3.216932500e2c85ecp+14080L, -0x1.476cc48b95f9d5p-716L, -0x4.65a794c5d3743b58p-704L, -0x4.65a794c5d3743b5p-704L }, - { 0x2.db319188f62c89e8p+988L, 0xe.a63c4600dc01d8cp-424L, 0x3.89fbee2ba66bc188p-412L, 0x3.89fbee2ba66bc18cp-412L }, - { 0x6.6aaa7a664cf96818p-3528L, -0x7.5c73f3fe919f4e7p-888L, 0x6.55e60356eb25c59p-876L, 0x6.55e60356eb25c598p-876L }, - { 0x5.916df5368bba491p-3112L, -0x2.9cfe9de6a3ad4c88p+12520L, 0x1.fbdfdf6fbd783f8cp+12532L, 0x1.fbdfdf6fbd783f8ep+12532L }, - { 0x8.e258363c3897569p-6168L, -0x1.72e257e109bc36bap+2524L, 0x2.2e36cb7155364494p+2536L, 0x2.2e36cb7155364498p+2536L }, - { 0x4.488a31c8bf6dbcp-13868L, -0x2.d5e7d27c5355e4ap+6356L, 0x9.995b6c142be9f9fp+6368L, 0x9.995b6c142be9fap+6368L }, - { 0xc.5cffd705c24a0c2p-4L, -0x9.01d522cef5d12afp-4668L, 0x3.59cb3ebcfd0a1f08p-4668L, 0x3.59cb3ebcfd0a1f0cp-4668L }, - { 0xb.40f77e9360b0776p-8424L, -0x1.c31d691fcbc9a998p-8380L, 0x3.9f658593c3b5b0ap-8368L, 0x3.9f658593c3b5b0a4p-8368L }, - { 0x7.1c785eecfe17605p+12952L, 0x6.81abff3b56ebed6p-4116L, 0x1.4942fffbc4b683b8p-4100L, 0x1.4942fffbc4b683bap-4100L }, - { 0x7.8201396b65470528p-8188L, -0x3.463d9ddfcf13487cp-10432L, 0x6.8b114d5e19d248fp-10420L, 0x6.8b114d5e19d248f8p-10420L }, - { 0x7.70d516c2a2b3b3dp-4152L, -0x8.126b2caac3c5943p-4996L, 0x8.2d35b07156a52abp-4984L, 0x8.2d35b07156a52acp-4984L }, - { 0x3.cd97932b489ad858p+6780L, -0xf.c42863b5a2d0232p-12656L, -0x1.a1ad801137893564p-12640L, -0x1.a1ad801137893562p-12640L }, - { 0x1.9396ff2d623e5408p+14096L, 0x3.9d32507b559b865cp-1176L, 0xc.702020e071d0773p-1164L, 0xc.702020e071d0774p-1164L }, - { 0x1.ed679d88b04f7fap+6264L, -0x4.b3d263673481a9ep-12932L, -0x7.31477827f160e46p-12920L, -0x7.31477827f160e458p-12920L }, - { 0x1.eae89eef96814ca6p-1852L, 0x3.a339fc1c50b7b174p-4092L, -0x1.a4d6cc5ce493c0cep-4080L, -0x1.a4d6cc5ce493c0ccp-4080L }, - { 0x1.707c24b46d461048p-14368L, 0x2.56890e2696270f18p+3396L, -0x8.33791b84ac10fa8p+3408L, -0x8.33791b84ac10fa7p+3408L }, - { 0xa.f782f5eeaaf84b2p-8396L, 0x4.8ac0d484844b719p-12612L, -0x9.4e6fad33abacc8cp-12600L, -0x9.4e6fad33abacc8bp-12600L }, - { 0x6.75f9102p-16416L, 0x1.c215aac2787d684ep-6028L, -0x7.0b8f1e582b0f2ac8p-6016L, -0x7.0b8f1e582b0f2acp-6016L }, - { 0x1.8e028ccf9407e7b6p-10456L, 0x2.6587235c80541de4p-8072L, -0x6.1e140f05b8db7f18p-8060L, -0x6.1e140f05b8db7f1p-8060L }, - { 0x1.da364cbdabbc25dcp+3776L, -0x3.e477a90405bea618p+5096L, -0x3.96d5b3c2d4f9d27p+5108L, -0x3.96d5b3c2d4f9d26cp+5108L }, - { 0x4.8ccd46cc6510b538p-6440L, 0x3.68c9ba824b18c688p-14052L, -0x5.5bc9eef09da496f8p-14040L, -0x5.5bc9eef09da496fp-14040L }, - { 0x1.5523bc7caa2a7b4p-2360L, 0xf.e04552139a2f6a5p+7728L, -0x9.254eb8dbb10de6p+7740L, -0x9.254eb8dbb10de5fp+7740L }, - { 0x3.5e00cae7d345aa9cp-13704L, -0x5.e5c76fe79a2907cp+13180L, 0x1.3baa07aa98aaf93ep+13196L, 0x1.3baa07aa98aaf94p+13196L }, - { 0x6.d8686db27423ce58p+1772L, -0x1.dd67447223055ad4p+10804L, -0xc.edb3a82a0914dc7p+10812L, -0xc.edb3a82a0914dc6p+10812L }, - { 0x5.81ac23cc9814dc5p+8424L, -0x1.82aa76204a55d282p-6048L, -0x3.1b770e30bffad924p-6036L, -0x3.1b770e30bffad92p-6036L }, - { 0xc.6ab94dcea227508p-14696L, -0x7.9584757e89e7c55p-5412L, 0x1.b343ac0c30e5ed04p-5396L, 0x1.b343ac0c30e5ed06p-5396L }, - { 0x8.f16bb6cf2395a1bp+7192L, -0x1.1a54811d7af3bd8cp+7552L, -0x1.eff326c8340b378ap+7564L, -0x1.eff326c8340b3788p+7564L }, - { 0x3.ce0c67c37ccec814p-14228L, 0xa.955a451a8e75c69p-8560L, -0x2.4c2055cf200b6e7p-8544L, -0x2.4c2055cf200b6e6cp-8544L }, - { 0x6.a4757b88p-16416L, 0x1.e49fe1c472843028p-4008L, -0x7.95f6092fae66987p-3996L, -0x7.95f6092fae669868p-3996L }, - { 0xe.71c46c73262a925p+3408L, 0x6.65257962db253ac8p-8876L, 0x5.53b25e184835333p-8864L, 0x5.53b25e1848353338p-8864L }, - { 0x1.3780298260776f1ep+10420L, -0x1.11661cd09cc6ff86p-308L, -0x2.b787db272797c17cp-296L, -0x2.b787db272797c178p-296L }, - { 0x1.fa3248ab7314fcfep-2564L, -0x2.384d1920955542p+12332L, 0x1.639b53b49c911ccap+12344L, 0x1.639b53b49c911cccp+12344L }, - { 0x2.72eeaa978efe1234p-6844L, 0x5.9b815458ba3ed0ap-10020L, -0x9.5e216a1ccb17dd4p-10008L, -0x9.5e216a1ccb17dd3p-10008L }, - { 0x4.6b38b0944800a92p-3652L, 0x1.06c7deaa434edd72p+6760L, -0xe.a287f40f40e33c8p+6768L, -0xe.a287f40f40e33c7p+6768L }, - { 0xc.e16733773c8f71ep+7968L, 0x1.d1a8610ef9653c2cp+6540L, 0x3.8a44dbbe5691ada4p+6552L, 0x3.8a44dbbe5691ada8p+6552L }, - { 0x5.fb96128dcb851d9p+6848L, 0x2.b75c4b387bdde9e8p+6840L, 0x4.8afe7743710b6da8p+6852L, 0x4.8afe7743710b6dbp+6852L }, - { 0x3.f58649c18725aaa8p+480L, -0x1.df1ad5bab9cc8704p+5396L, -0x3.86096aedbe0ccf84p+5404L, -0x3.86096aedbe0ccf8p+5404L }, - { 0x3.8c7468635255c36cp-9848L, -0x1.2d4a9bc2537a65c2p+6172L, 0x2.d44278d5964e9308p+6184L, 0x2.d44278d5964e930cp+6184L }, - { 0x1.266933c47623dcf2p+1504L, 0x1.9f5956a11f8d8a1cp+4848L, 0x9.8880a23f0954318p+4856L, 0x9.8880a23f0954319p+4856L }, - { 0x7.ee162358p-16416L, -0x7.b20cc9e4d310231p-6740L, 0x1.ed6276e44234215ep-6724L, 0x1.ed6276e44234216p-6724L }, - { 0xd.a2dd238869b2787p-1832L, 0x1.a987e218c6f17582p-4964L, -0xb.def06e8887e84fcp-4956L, -0xb.def06e8887e84fbp-4956L }, - { 0x6.d06d1c60a261b25p+13856L, -0x5.9e57359c4cf1067p+13824L, -0x1.3029be4f0d001bb4p+13840L, -0x1.3029be4f0d001bb2p+13840L }, - { 0xf.5afa51a915c3c2cp-7724L, -0x5.399276f16adbba7p-8016L, 0x9.d90782db4be7b57p-8004L, 0x9.d90782db4be7b58p-8004L }, - { 0x1.37ae53977fcc991cp+11588L, 0xc.cf5f343691ea8ecp+3336L, 0x2.43de7490fbe55f28p+3352L, 0x2.43de7490fbe55f2cp+3352L }, - { 0xb.916f204d9b607e2p-9652L, -0x1.35296e508f235de2p+2664L, 0x2.d841a1731ad9bf24p+2676L, 0x2.d841a1731ad9bf28p+2676L }, - { 0x7.986b2cd7ddf22268p+8064L, -0x2.2a06bf374755863cp-5488L, -0x4.432291fb48046c6p-5476L, -0x4.432291fb48046c58p-5476L }, - { 0x6.37c853b0413d5448p-11920L, 0x7.ff7a53a9d88503bp-13652L, -0x1.745299d0aed002f4p-13636L, -0x1.745299d0aed002f2p-13636L }, - { 0x6.4c2eb46758106918p+14296L, 0x4.fbd427830e0b7d98p-8500L, 0x1.165c4a9036705c38p-8484L, 0x1.165c4a9036705c3ap-8484L }, - { 0x6.24db1d64d95cf55p-336L, 0x6.d057f880739cc278p+14360L, -0x8.df9aba4673d5941p+14368L, -0x8.df9aba4673d594p+14368L }, - { 0xb.1981c21be406601p-3972L, 0x2.029bd5f255e8a35p-10848L, -0x1.f297ef0c6b6837e8p-10836L, -0x1.f297ef0c6b6837e6p-10836L }, - { 0x6.74e6ebd8p-16416L, 0xb.151703cbe7e3038p+8672L, -0x2.c68a91d35a06273p+8688L, -0x2.c68a91d35a06272cp+8688L }, - { 0xa.37e2d7be2859c8bp-1596L, -0x1.c4a435d45ba8988ap+7536L, 0xb.000200ece72bb1cp+7544L, 0xb.000200ece72bb1dp+7544L }, - { 0x2.916b7b8ed46e92ccp-4368L, -0x3.037efdf978c84bfcp-8832L, 0x3.3678d0ccdadaeffp-8820L, 0x3.3678d0ccdadaeff4p-8820L }, - { 0x7.6c639e488208ccc8p-2160L, 0x3.a1d6c7b434bf3d98p-12244L, -0x1.e9b030a027bc75dp-12232L, -0x1.e9b030a027bc75cep-12232L }, - { 0x1.70d6044fbe0cb0d2p-8188L, -0x1.7afb318a61f2f0eap-536L, 0x2.f58b29b59e1cd59p-524L, 0x2.f58b29b59e1cd594p-524L }, - { 0x1.3e90b4eb0efaf5fap+7324L, -0x2.96cfd9fbb50bcd78p-1116L, -0x4.a1373950c6aeb928p-1104L, -0x4.a1373950c6aeb92p-1104L }, - { 0x4.6f9a694c1cfb65dp-8964L, -0x1.0df2b52efca96a9ep+1968L, 0x2.4ea226124824d4f4p+1980L, 0x2.4ea226124824d4f8p+1980L }, - { 0x1.d6566fbbd43703bcp-4852L, -0xa.f8b1cd8907eb113p+7616L, 0xc.fe7e9244b013f7bp+7628L, 0xc.fe7e9244b013f7cp+7628L }, - { 0x1.1a90813aa3baaae6p-3212L, 0x1.07b9974764beed82p-7712L, -0xc.ecc705b170e316ap-7704L, -0xc.ecc705b170e3169p-7704L }, - { 0x6.af86ac96f68ccc18p-5372L, -0x1.5877065aa0076e0ep+9668L, 0x1.c38b175b4ec73c6ep+9680L, 0x1.c38b175b4ec73c7p+9680L }, - { 0x5.0830fc79162b51p+732L, 0x7.a0e695df486975a8p-456L, 0x1.5e1dbcc4c6615ef2p-444L, 0x1.5e1dbcc4c6615ef4p-444L }, - { 0x4.1e9381b2498bde9p-4L, -0x5.318485c71566c348p-10692L, 0xa.2a99b81fbb45d58p-10692L, 0xa.2a99b81fbb45d59p-10692L }, - { 0x3.aa23634217ae0ec4p+8196L, -0xe.31f0ba646c8980ep-56L, -0x1.c69177d12e2f164p-40L, -0x1.c69177d12e2f163ep-40L }, - { 0x5.f1ebb70f25fab228p+148L, -0x1.5c7f22ee7bdcb97ap+12792L, -0xc.cf9b8c1bbde569fp+12796L, -0xc.cf9b8c1bbde569ep+12796L }, - { 0x6.64a485a65ba2bb8p-6848L, -0xb.ab5d793764e46aap-4044L, 0x1.3808c8a9a9457a22p-4028L, 0x1.3808c8a9a9457a24p-4028L }, - { 0x2.0c076822c45b5c2p+3820L, 0xc.6d1ace4fdfc0995p-11720L, 0xb.978e3acafba5dep-11708L, 0xb.978e3acafba5de1p-11708L }, - { 0x2.c4adada59c4f74cp+356L, 0x8.cb9c5966f2f6535p+664L, 0xc.481102c34516cep+672L, 0xc.481102c34516ce1p+672L }, - { 0x1.4690bd92b944f1e6p-1756L, 0x1.89dd6b86aed3c6ep-12820L, -0xa.8d20776fa7c107fp-12812L, -0xa.8d20776fa7c107ep-12812L }, - { 0x1.e645a04ffd7fcf32p+8988L, -0x7.4662a44eadea0868p+5320L, -0xf.f71eb1d0013d055p+5332L, -0xf.f71eb1d0013d054p+5332L }, - { 0x4.332914d9e18063ap-10904L, 0x2.c3783d61fd7041fcp+14952L, -0x7.5b010c3479470088p+14964L, -0x7.5b010c347947008p+14964L }, - { 0x7.8ea9558f03ae0e7p+3360L, -0x3.f7ba4222d04d157cp+7040L, -0x3.41f0065a9b4f0258p+7052L, -0x3.41f0065a9b4f0254p+7052L }, - { 0x4.16fc729b9ce4dc58p-12344L, 0x5.91be30b46d5b46d8p+8916L, -0x1.0c803996b4e5dd76p+8932L, -0x1.0c803996b4e5dd74p+8932L }, - { 0x1.9ff000dcf3194afap+0L, -0xb.402101043dda93fp+8464L, -0x7.e0bb855f276d611p+8464L, -0x7.e0bb855f276d6108p+8464L }, - { 0x3.c1bd5f7eaf2aefbcp-3452L, 0x3.5060ef99941b0558p-28L, -0x2.ca98723a104a705cp-16L, -0x2.ca98723a104a7058p-16L }, - { 0x7.40f69af37414a67p-4984L, 0x9.76424abbc94834ap+8128L, -0xb.81b4e09a2241edap+8140L, -0xb.81b4e09a2241ed9p+8140L }, - { 0x2.a7771004562ceed4p+14300L, 0x1.6959757c92243a3ap-3048L, 0x4.edabdfe0f6ebfd28p-3036L, 0x4.edabdfe0f6ebfd3p-3036L }, - { 0x3.5def153aa1e1859cp-12528L, 0x2.e3b7b35774e3683p-11336L, -0x8.d62de479ad0aa6p-11324L, -0x8.d62de479ad0aa5fp-11324L }, - { 0x3.60afa9401fa21cb4p+13964L, -0x3.918ec1969b0edd88p+1908L, -0xc.2adfb245bfe4ad7p+1920L, -0xc.2adfb245bfe4ad6p+1920L }, - { 0x1.dec8e34ee760457ap-3276L, -0xc.f9ac1534d437324p-4104L, 0xa.5ff4de0ac7cf5eap-4092L, 0xa.5ff4de0ac7cf5ebp-4092L }, - { 0x3.40a43e7617430e38p-6876L, -0x1.21e9e8c12fbb68ap+0L, 0x1.e68f95a0715b74ecp+12L, 0x1.e68f95a0715b74eep+12L }, - { 0x6.e391c60d69e57e48p+14204L, -0x3.ab05dd3dc0cb47fcp-5284L, -0xc.b8f4fe0c2d1d37dp-5272L, -0xc.b8f4fe0c2d1d37cp-5272L }, - { 0x4.7e30a9e329ebbe38p-3820L, -0x2.029c31080003b2e4p-2628L, 0x1.dfa972c247b7e80ep-2616L, 0x1.dfa972c247b7e81p-2616L }, - { 0x5.040eb8c257682f18p+12468L, -0x1.ee68d5b05c315f0ap-10428L, -0x5.e13c804f6f999478p-10416L, -0x5.e13c804f6f99947p-10416L }, - { 0x7.8e68dbe249d1df3p-4L, -0x1.9e8c3ea1db7772dep+1124L, 0x1.c0aca5bb6957525ep+1124L, 0x1.c0aca5bb6957526p+1124L }, - { 0x1.b84f160ab17a1622p+1796L, 0x4.b2842fc0d4e29f8p-12508L, 0x2.0f8142fc8078e574p-12496L, 0x2.0f8142fc8078e578p-12496L }, - { 0x1.f41344568040c1dap-11860L, 0x1.1c6472bb8005f37ep-6852L, -0x3.3764ada231d16af8p-6840L, -0x3.3764ada231d16af4p-6840L }, - { 0x3.e3036c02f7d4d658p-9528L, 0x5.36e056abcab2faa8p+1976L, -0xc.208372633388ae4p+1988L, -0xc.208372633388ae3p+1988L }, - { 0xe.d925cace25ab5fep+8480L, -0xd.6cb0532deaf2679p+944L, -0x1.bce4911c050e131p+960L, -0x1.bce4911c050e130ep+960L }, - { 0x6.19357550809e7c3p+5024L, 0x1.5c8533e5f3b94e6ap-10972L, 0x1.abb43335a7f7f332p-10960L, 0x1.abb43335a7f7f334p-10960L }, - { 0x3.b44cb94e53d800dp-8104L, -0x1.1ab0065a82bd87f4p-2844L, 0x2.2f2be3b82899a4e8p-2832L, 0x2.2f2be3b82899a4ecp-2832L }, - { 0x9.ea2a7bd17c460dep-8580L, -0x7.62ec913ffd564678p+2716L, 0xf.7770e8e86e4eb82p+2728L, 0xf.7770e8e86e4eb83p+2728L }, - { 0xf.c7a3dd4416649cep+6636L, 0x2.6182229406539e28p+13900L, 0x3.dc11331e9f68bf5cp+13912L, 0x3.dc11331e9f68bf6p+13912L }, - { 0xf.7fa93e24f531607p-1524L, 0x1.8f7cad2b63b6624ep-12276L, -0x9.44069d140a4f7c3p-12268L, -0x9.44069d140a4f7c2p-12268L }, - { 0x1.dc32628ac0052e3p+13788L, -0xa.e3c3bdecf1dec26p-868L, -0x2.4a8d02bd7a23b6acp-852L, -0x2.4a8d02bd7a23b6a8p-852L }, - { 0xe.2792f16a45f2666p-4L, 0x3.606aae6b641136ecp-14064L, -0x9.8d4b6f35e1bb5f7p-14068L, -0x9.8d4b6f35e1bb5f6p-14068L }, - { 0x2.3a3da2a76687889cp+7488L, 0x3.b7edc7ccbaa4e6f4p-4576L, 0x6.cc836f69a9a8fbfp-4564L, 0x6.cc836f69a9a8fbf8p-4564L }, - { 0x9.e81deac115960bcp-10784L, -0x1.edc841a680c41fa6p+904L, 0x5.13a322bc0411e47p+916L, 0x5.13a322bc0411e478p+916L }, - { 0x1.cd896fd12910f8fep+4612L, -0x5.53107666263a4058p-5612L, -0x5.ff0fb993b0e4c34p-5600L, -0x5.ff0fb993b0e4c338p-5600L }, - { 0x7.115b116b66f8aa4p+13264L, -0x7.5f2ae310973bd4d8p+14416L, -0x1.7e07aa45adacd32cp+14432L, -0x1.7e07aa45adacd32ap+14432L }, - { 0x1.74145e7c2770b4ccp+2828L, -0xa.ba6ad2740e752acp-2336L, -0x7.6891da714ff943c8p-2324L, -0x7.6891da714ff943cp-2324L }, - { 0x4.8b2545de86521b8p+13740L, -0x2.1340349dc88fe5ap+4092L, -0x6.f65c22f70b2c646p+4104L, -0x6.f65c22f70b2c6458p+4104L }, - { 0xc.52069130f81cabfp-1984L, -0x4.20c946d47a37871p+2084L, 0x1.fef232e25ad65e4p+2096L, 0x1.fef232e25ad65e42p+2096L }, - { 0x3.2b65b7eb1ee545c8p+7384L, 0x2.3f8fa6f81d92432cp-14436L, 0x4.0dd155add9d84d1p-14424L, 0x4.0dd155add9d84d18p-14424L }, - { 0x1.a1b184553cda78ap+14968L, -0x2.31c152f5ee281b54p-9292L, -0x8.04eac2f38cfa541p-9280L, -0x8.04eac2f38cfa54p-9280L }, - { 0x1.44f05224646c418ap-14972L, 0x1.2804d060de7d5e6ep+13432L, -0x4.3a013b476092fe2p+13444L, -0x4.3a013b476092fe18p+13444L }, - { 0x9.167509d85ac5562p-4L, -0x1.4b8f74471056531ep+12276L, 0x1.0e948448a0348196p+12276L, 0x1.0e948448a0348198p+12276L }, - { 0x7.ee687fee5c4ec2b8p+4644L, 0x6.79c1485cae87c43p-13504L, 0x7.58c0ee6ada14d12p-13492L, 0x7.58c0ee6ada14d128p-13492L }, - { 0x3.0cf623142a333c9cp+2336L, -0xe.a753d50ad228a17p+12460L, -0x8.5ce71421a143a5bp+12472L, -0x8.5ce71421a143a5ap+12472L }, - { 0x2.c8c9b971c2760cep-7672L, 0x3.932fbae80e38a998p-12916L, -0x6.b1db6613ef55474p-12904L, -0x6.b1db6613ef554738p-12904L }, - { 0x1.32026fb6bb0871ecp-13652L, -0x4.7b7e1412f0e7c018p+4912L, 0xe.f08781f91bd2a4dp+4924L, 0xe.f08781f91bd2a4ep+4924L }, - { 0x1.74dc31e3b9305bc4p-1120L, 0x3.84981c669a06975p+10008L, -0xf.6230ebdd8fed1ebp+10016L, -0xf.6230ebdd8fed1eap+10016L }, - { 0xb.ea47989bcd17ecap-872L, -0x3.a0466264269bfc0cp-616L, 0xc.4cf96b143aaed5p-608L, 0xc.4cf96b143aaed51p-608L }, - { 0x7.d01c7f119325b4f8p-1716L, -0xb.b3079d74457748ap-8232L, 0x4.e495c312907e048p-8220L, 0x4.e495c312907e0488p-8220L }, - { 0x1.d578671f39a6b79p+6516L, -0x3.dcbcd626648e35ap-8260L, -0x6.251d78436ccc76e8p-8248L, -0x6.251d78436ccc76ep-8248L }, - { 0x6.4d100f244be8113p+5240L, -0x8.8a2584d61c785a5p-1880L, -0xa.ee25d77822d6b9ap-1868L, -0xa.ee25d77822d6b99p-1868L }, - { 0x6.e4c6b8c4d0181df8p+11256L, -0xa.238f609952a68b5p+7056L, -0x1.bde7c574f5a56112p+7072L, -0x1.bde7c574f5a5611p+7072L }, - { 0x1.775823e9c3c2806cp+0L, 0x5.f466fe6cbdda3498p-3292L, 0x3.4993f3fbee8e12ap-3292L, 0x3.4993f3fbee8e12a4p-3292L }, - { 0x1.6ca0a0798fc630d8p-6296L, -0x1.5d03274c615fac7ep-9600L, 0x2.186d3767c5e0b77cp-9588L, 0x2.186d3767c5e0b78p-9588L }, - { 0x7.f1d06ee491613b4p+11796L, -0x2.99a7c87fc7c10564p-2268L, -0x7.7d7ed6d273782118p-2256L, -0x7.7d7ed6d27378211p-2256L }, - { 0x4.55b0bf0b43297a08p-688L, -0x5.4e7599ff8ce238d8p+5432L, 0xe.37a1a230f9d393cp+5440L, 0xe.37a1a230f9d393dp+5440L }, - { 0xf.ce25a67a67167e8p+5848L, 0xd.dae4961d9a359e9p-4336L, 0x1.3cb782addfad199ep-4320L, 0x1.3cb782addfad19ap-4320L }, - { 0x5.879a9e2ad0de4358p+1484L, 0x2.a7aa43ef734cca24p+9800L, 0xf.6a7be0d01960894p+9808L, 0xf.6a7be0d01960895p+9808L }, - { 0x1.8d57c92ab74b5dbp-9440L, 0xb.b6c4b8fea0b6709p-6916L, -0x1.afec2834b3ae434p-6900L, -0x1.afec2834b3ae433ep-6900L }, - { 0x5.6edc0af664d23e5p+10200L, 0x6.dee852c47ad7ae6p-9044L, 0x1.11d23f76b577fcfep-9028L, 0x1.11d23f76b577fdp-9028L }, - { 0x3.5d8dfaa5f4b3274p+11908L, -0xd.5dcf3b09be0346ep-12448L, -0x2.6dd7025c41524ea4p-12432L, -0x2.6dd7025c41524eap-12432L }, - { 0x7.ed91ce55062c3928p-11600L, -0x6.a15fc994e42a5f98p+13812L, 0x1.2c5c7661e2e3939cp+13828L, 0x1.2c5c7661e2e3939ep+13828L }, - { 0x1.dad7ecb371577f1p-14180L, -0x1.8d483b7d23140ad2p-3480L, 0x5.5f452e54f7efca4p-3468L, 0x5.5f452e54f7efca48p-3468L }, - { 0x7.2dc2a178p-16416L, 0xf.60597a6a11748cfp+11572L, -0x3.d9d6afdc9faabf58p+11588L, -0x3.d9d6afdc9faabf54p+11588L }, - { 0x7.ff05934f4c4c383p+6524L, 0x2.5b900e7df1a77c04p+8376L, 0x3.c1c7d76fd3351f88p+8388L, 0x3.c1c7d76fd3351f8cp+8388L }, - { 0x6.284c4489a8b3cf4p-12304L, -0x1.9ce08e5156bf999ap-956L, 0x4.d7fae0579e379fp-944L, 0x4.d7fae0579e379f08p-944L }, - { 0x3.7341a9ee603f834p-11216L, -0xe.74a4f05ef7fcf94p-10108L, 0x2.793ca67d11dad138p-10092L, 0x2.793ca67d11dad13cp-10092L }, - { 0xb.4c1201a91da1f7dp-2416L, -0x1.ff8b4a662492c844p+6384L, 0x1.2d4b53b5778f5e24p+6396L, 0x1.2d4b53b5778f5e26p+6396L }, - { 0xc.503b4e17876b4f8p+14420L, 0xd.d962de347f839ep+11944L, 0x3.0c4b1eff3371d3dcp+11960L, 0x3.0c4b1eff3371d3ep+11960L }, - { 0xf.ea4c84120426686p+8032L, 0x2.0ff0659d1aa2b36cp+13504L, 0x4.0bc5229ec619288p+13516L, 0x4.0bc5229ec6192888p+13516L }, - { 0xc.d03a3525d4adca1p-8912L, 0xf.76de125c2115ea5p+10412L, -0x2.1a212be6d70d0b54p+10428L, -0x2.1a212be6d70d0b5p+10428L }, - { 0x1.2c0b226e839776bap+10920L, -0xb.7b45dbebad44f9fp+13816L, -0x1.e9c4fd19de7db7ap+13832L, -0x1.e9c4fd19de7db79ep+13832L }, - { 0x1.7526248567fdebaep-840L, 0x8.687306d6b53f2b3p-9012L, -0x1.b922757bed236fdcp-9000L, -0x1.b922757bed236fdap-9000L }, - { 0x5.d5a66b8dfa047b5p-880L, 0x3.54d7284400eeb294p+3432L, -0xb.6b29715876e4f48p+3440L, -0xb.6b29715876e4f47p+3440L }, - { 0x1.37c211415835776cp+0L, -0x1.7bf2f1bdd872e7eep+1316L, -0x6.c0359c02dd59851p+1312L, -0x6.c0359c02dd598508p+1312L }, - { 0x5.9bf965c8495ee31p-1072L, 0xe.d2641494150a73fp+4012L, -0x3.dec2358e511f578cp+4024L, -0x3.dec2358e511f5788p+4024L }, - { 0xe.89eb0db23e82e32p-9840L, 0x8.530d8f2410e4187p+14152L, -0x1.3fd83369fbaaebfep+14168L, -0x1.3fd83369fbaaebfcp+14168L }, - { 0x1.a52fd5b0cedad4p-7932L, -0x1.44fe526e6036e7f8p-3256L, 0x2.754ce8f57959c7e8p-3244L, 0x2.754ce8f57959c7ecp-3244L }, - { 0x1.549a7733f640e13ep+12420L, 0x3.1188e7c0d95889dp-3832L, 0x9.4dff9a550c1eeb8p-3820L, 0x9.4dff9a550c1eeb9p-3820L }, - { 0x9.2e4d38476817c8dp-6436L, -0x4.abcedf3d024db5f8p-4444L, 0x7.5606bf1b0956cffp-4432L, 0x7.5606bf1b0956cff8p-4432L }, - { 0xb.f856641f8481196p+10672L, -0x8.d47787d0685534ap+1648L, -0x1.7038d6792aa77424p+1664L, -0x1.7038d6792aa77422p+1664L }, - { 0x1.69824482561454f8p+336L, 0x1.e0a9fb820963e05ap+3924L, 0x2.77ce6b1d230c7e5cp+3932L, 0x2.77ce6b1d230c7e6p+3932L }, - { 0x4.7b875bee3ace9d18p-4832L, 0x1.32f4fca22bdf9c8p-11912L, -0x1.69f37c67b419941cp-11900L, -0x1.69f37c67b419941ap-11900L }, - { 0x1.f1b6d7dd3acdec62p+1524L, 0x1.b0ec522ad44311ccp+8564L, 0xa.12de18c6f5ad5a6p+8572L, 0xa.12de18c6f5ad5a7p+8572L }, - { 0xa.077356a040b99f3p+10808L, 0x3.8f22e0e027753a1p-1952L, 0x9.64edf128ed9b026p-1940L, 0x9.64edf128ed9b027p-1940L }, - { 0xb.b5048a19c401aa4p-4L, 0x1.49cb7d1d22aa7e92p-11668L, -0x9.4a276cfbcb4689p-11672L, -0x9.4a276cfbcb4688fp-11672L }, - { 0x5.ac937fd967cce3cp+180L, 0x2.044831378114a9e4p-6504L, 0x1.700fbc6017636d7ep-6496L, 0x1.700fbc6017636d8p-6496L }, - { 0x6.5a8d06709c18fd3p-8212L, -0x3.bfed54c9016cfdf8p+564L, 0x7.83ea8701dcdca1c8p+576L, 0x7.83ea8701dcdca1dp+576L }, - { 0x1.22fb3728954b2facp+11140L, 0x2.a9bbdeb2bd533bdcp+4340L, 0x7.3e2913fd71866cap+4352L, 0x7.3e2913fd71866ca8p+4352L }, - { 0x1.a3d958faa346d6d4p-2564L, -0x7.2d5882b0a8455a8p-10740L, 0x4.7dd0b200bb918158p-10728L, 0x4.7dd0b200bb91816p-10728L }, - { 0x5.aae8c1b07b4255a8p-11416L, 0x1.a5322e33e663a032p+14936L, -0x4.95a97974b2d6be5p+14948L, -0x4.95a97974b2d6be48p+14948L }, - { 0x1.32b51a0ef6515e86p+11512L, -0x2.e5e11f37294c9f08p+6628L, -0x8.25224dfd2ae08ebp+6640L, -0x8.25224dfd2ae08eap+6640L }, - { 0x9.9f9641c28f1f3bp+3252L, -0x1.a299130160a73736p-13208L, -0x1.4cad7e3dd198472ep-13196L, -0x1.4cad7e3dd198472cp-13196L }, - { 0xa.14b3d5f6dc54435p+7340L, -0x5.9aded1ca64712fc8p+9680L, -0xa.0c71bdcb75c7ab2p+9692L, -0xa.0c71bdcb75c7ab1p+9692L }, - { 0x6.15b61d120f49268p+6220L, -0xf.7f9391555365de2p+5488L, -0x1.78b815d015e81898p+5504L, -0x1.78b815d015e81896p+5504L }, - { 0x1.4f2bc08178d6eb22p-8580L, 0xa.04e870f0bde69e8p+3968L, -0x1.4fc8994b94f2a114p+3984L, -0x1.4fc8994b94f2a112p+3984L }, - { 0x1.5a47ce0ae772d35p+0L, -0x1.2cdf2167efebf2a4p-10844L, -0x8.31e78a3e624db2bp-10848L, -0x8.31e78a3e624db2ap-10848L }, - { 0x6.f4cbf9587638df9p+5352L, 0x6.68a1cb4cc0d7c8cp-4056L, 0x8.60d658044a4bc4bp-4044L, 0x8.60d658044a4bc4cp-4044L }, - { 0x3.84a9333922f6ecb4p-9532L, 0x2.fc9ff16108dd5bd8p-1556L, -0x6.f30e7b39aef8555p-1544L, -0x6.f30e7b39aef85548p-1544L }, - { 0x4.73121c1ce9aa73dp-6892L, 0x5.84c4b307a865da78p+10880L, -0x9.4867ceb0d8c1681p+10892L, -0x9.4867ceb0d8c168p+10892L }, - { 0x1.904286dff6e1c742p+12660L, 0x1.a23ce96a1531b288p-9176L, 0x5.0cc39f45fb54f2a8p-9164L, 0x5.0cc39f45fb54f2bp-9164L }, - { 0xd.fc03b164930e19ap-4788L, -0x4.484bbdd4a58040c8p-12664L, 0x5.007dc60263b9e04p-12652L, 0x5.007dc60263b9e048p-12652L }, - { 0x3.cf945718ab43d7d8p-9660L, 0x9.75ee615c9605d82p+5592L, -0x1.64ebcc8679ceb56p+5608L, -0x1.64ebcc8679ceb55ep+5608L }, - { 0x6.133ee5675e302e6p+1264L, -0x2.ebb2e212bc306adp+4292L, -0xe.735d70c085412d7p+4300L, -0xe.735d70c085412d6p+4300L }, - { 0x1.6faa14baf33d3942p+5756L, 0x2.98fb801310e3d98p-4484L, 0x3.a69121c6a4586a9cp-4472L, 0x3.a69121c6a4586aap-4472L }, - { 0x1.8bf4374345aeebcap-352L, 0x3.433b152bfb0fcc0cp+8288L, -0x4.7a63b884113c79c8p+8296L, -0x4.7a63b884113c79cp+8296L }, - { 0xf.348c75a3c924d9dp-3128L, -0x6.d27f0cba9d98c128p-4724L, 0x5.34136c5b13a1832p-4712L, 0x5.34136c5b13a18328p-4712L }, - { 0x4.6cba404p-16416L, -0x3.b1c0ab60b7afe674p-14368L, 0xe.cde75bc3f6da7cdp-14356L, 0xe.cde75bc3f6da7cep-14356L }, - { 0x3.1b7118eb85377698p+6592L, -0x5.0267e29e12c8f49p-8896L, -0x8.106249044735cbfp-8884L, -0x8.106249044735cbep-8884L }, - { 0x3.607d3c87fbf0054cp-68L, -0x2.8420e2df1534abep+5568L, 0xa.6add61dff55ffbdp+5572L, 0xa.6add61dff55ffbep+5572L }, - { 0xa.4f75c3ab1754f75p-2464L, -0x2.32d6265dd6c5c31cp+9576L, 0x1.521e6ab64b73a75p+9588L, 0x1.521e6ab64b73a752p+9588L }, - { 0x4.bebcc7d8d84470bp-4920L, 0xc.7a576a4e9617a7ap-10204L, -0xe.fb33826c58f70a1p-10192L, -0xe.fb33826c58f70ap-10192L }, - { 0x1.be14cf99336dd968p-9392L, 0x4.439759bba9387e28p+1492L, -0x9.c6c56213fcb7fdcp+1504L, -0x9.c6c56213fcb7fdbp+1504L }, - { 0xd.ccc1903e13b59f8p-12068L, -0x6.037d29fedf54928p-12240L, 0x1.1b65b2ea6fa5deeap-12224L, 0x1.1b65b2ea6fa5deecp-12224L }, - { 0x8.ec0ef83d152f4acp-13700L, -0x1.390c57a14d17b9fp+14872L, 0x4.16d1c17c1224422p+14884L, 0x4.16d1c17c12244228p+14884L }, - { 0x2.0fb3544804b262fp+5160L, 0x3.b57463fce853545p-480L, 0x4.ac550d3435adb7d8p-468L, 0x4.ac550d3435adb7ep-468L }, - { 0x1.64d1c43e23cf40aep-10652L, 0x1.0fb4b45ff8885f8ep-12252L, -0x2.c2900d82132cfb08p-12240L, -0x2.c2900d82132cfb04p-12240L }, - { 0x1.4abc31acbc7bc518p+1336L, -0xc.c65e75c39561171p+11700L, -0x4.2aff57887c738d9p+11712L, -0x4.2aff57887c738d88p+11712L }, - { 0x1.2b2e1b630ba1b3b6p+0L, 0x1.eada4be47dcfc9f2p+3300L, 0x6.e60d5e6d365afda8p+3296L, 0x6.e60d5e6d365afdbp+3296L }, - { 0x2.c8c57e2508051b3p-3924L, 0x5.21d09f2ffed0044p-5412L, -0x4.ea2bce361f26c5ap-5400L, -0x4.ea2bce361f26c598p-5400L }, - { 0x4.fe1bd62b8bf75b7p-12596L, 0x2.69999b4a350849p+13480L, -0x7.6ae41382c2fb955p+13492L, -0x7.6ae41382c2fb9548p+13492L }, - { 0x1.94cbc2f130aac9fcp+14560L, 0x4.461d0bdbe3e5e6e8p-84L, 0xf.316874645a5d084p-72L, 0xf.316874645a5d085p-72L }, - { 0x6.00a84d432c73ad6p+14048L, -0x7.1439c231e1c871ap+5524L, -0x1.84882f27e22d69e8p+5540L, -0x1.84882f27e22d69e6p+5540L }, - { 0x1.504150487ac4b4e4p+10492L, 0x1.4aca4d52f53ae634p+14816L, 0x3.4f5bd5c26e4d5f5p+14828L, 0x3.4f5bd5c26e4d5f54p+14828L }, - { 0x1.818d6363460594dp+2580L, 0x5.4e4c228f75fecc6p-13880L, 0x3.57c39c1ba0acfc6cp-13868L, 0x3.57c39c1ba0acfc7p-13868L }, - { 0x7.b18970b8033e92d8p+5184L, 0x2.405b3b6f6bd5017cp+12636L, 0x2.d9dd8099a79debfp+12648L, 0x2.d9dd8099a79debf4p+12648L }, - { 0x1.55003f934a96adfep+7436L, 0x9.0c070751c7715e7p-13016L, 0x1.06cd1a244ad7ce72p-13000L, 0x1.06cd1a244ad7ce74p-13000L }, - { 0x8.f4ea2709aeb30cap-3688L, -0x9.90099934edea7dfp+9676L, 0x8.9a4cb3758de9216p+9688L, 0x8.9a4cb3758de9217p+9688L }, - { 0x3.5a44024ad8c0a6ap+9484L, -0x3.162144dafa472c6cp+8012L, -0x7.25d3b827636c377p+8024L, -0x7.25d3b827636c3768p+8024L }, - { 0x4.5f98d1p-16420L, 0x3.174b45b7a50513fp-10904L, -0xc.63b8389565e5a89p-10892L, -0xc.63b8389565e5a88p-10892L }, - { 0x3.5e780c7808c14d1cp+4008L, -0x1.58021e31ae37918ap-8496L, -0x1.50c3bf982d8bc07ep-8484L, -0x1.50c3bf982d8bc07cp-8484L }, - { 0x6.735ed2860eb877p-8864L, -0x5.c82ebf46ce67b208p-8940L, 0xc.823c5bf27f289adp-8928L, 0xc.823c5bf27f289aep-8928L }, - { 0x9.f58318f7cfc023dp-10580L, 0xe.e7cda687036f7d6p-3536L, -0x2.67d291ecbebf4044p-3520L, -0x2.67d291ecbebf404p-3520L }, - { 0x1.3385a0a2f5ddca66p-2148L, 0x3.95cfb0b45473c558p-8036L, -0x1.e140fd913d3cdd4ep-8024L, -0x1.e140fd913d3cdd4cp-8024L }, - { 0xe.947a2689d86b12ap-8256L, 0x2.ff7409072f025f1p+9544L, -0x6.0a2c739e5b996318p+9556L, -0x6.0a2c739e5b99631p+9556L }, - { 0x3.f3364f18a79b3b3cp-14488L, -0x3.6b2dcf47d1901574p+6084L, 0xc.172e20d1e6aa072p+6096L, 0xc.172e20d1e6aa073p+6096L }, - { 0x1.b974779bc6a1600ap+156L, -0x1.fef4cd2b528d3ed6p+4876L, -0x1.38eed99c599a6616p+4884L, -0x1.38eed99c599a6614p+4884L }, - { 0x1.5da19cb6935f4324p-12448L, 0x1.1242f349c776d3c6p-13804L, -0x3.4177c20b08c8a534p-13792L, -0x3.4177c20b08c8a53p-13792L }, - { 0x5.f6b443936fcdf7dp+8000L, 0x4.9faadefeeda4d958p-12968L, 0x9.08985174ac99b73p-12956L, 0x9.08985174ac99b74p-12956L }, - { 0x3.9761f885a890c5f8p-6896L, -0x1.fde18a33769c2a36p+13492L, 0x3.5a33efe387a603p+13504L, 0x3.5a33efe387a60304p+13504L }, - { 0x6.38ae5a4p-16416L, -0xa.2bd753c4bb7feadp+8856L, 0x2.8c207ce6520e07dcp+8872L, 0x2.8c207ce6520e07ep+8872L }, - { 0x1.ce5c78f45cf53052p-12668L, 0x2.d403d4610942405cp-15000L, -0x8.bf104029e978686p-14988L, -0x8.bf104029e978685p-14988L }, - { 0x3.83b4fdb7c30a8a24p+1780L, -0x7.47e990178bed20ep-10576L, -0x3.2ad37d867fd49f4p-10564L, -0x3.2ad37d867fd49f3cp-10564L }, - { 0x4.f47fb482316be128p+6760L, 0x1.e4ba4361308b87cap+8632L, 0x3.20435b40eefebe3cp+8644L, 0x3.20435b40eefebe4p+8644L }, - { 0x9.ecba992568fda9fp+11556L, 0x1.57a41871031f24a8p-14620L, 0x3.c9c9d2d431974ee8p-14608L, 0x3.c9c9d2d431974eecp-14608L }, - { 0x5.0527cf795fdf0218p+180L, -0x1.0ed493bb5c956a5p-14104L, -0xc.0e3e3338d3a0555p-14100L, -0xc.0e3e3338d3a0554p-14100L }, - { 0x1.9e25e3c9c45d2c4cp+10096L, 0xf.d72920ce880fef5p+7404L, 0x2.70c064489db2a254p+7420L, 0x2.70c064489db2a258p+7420L }, - { 0x3.14721fc3b04b8c5p-1656L, 0x1.9d71a05ab8af6f3ep-13688L, -0xa.6fd80e54131d7c3p-13680L, -0xa.6fd80e54131d7c2p-13680L }, - { 0x2.5ad78a50881512acp-12368L, -0x6.200f74ea14aea158p+9312L, 0x1.27e55933256dda96p+9328L, 0x1.27e55933256dda98p+9328L }, - { 0x1.bed98ef392f4ab94p-6416L, 0x3.2511f8a81a02ae5cp-6232L, -0x4.ece8b6a1658e5688p-6220L, -0x4.ece8b6a1658e568p-6220L }, - { 0x9.ca98394ded775ccp+9980L, 0x3.3e1f319d7fc3b93p+2928L, 0x7.e74746d926c576d8p+2940L, 0x7.e74746d926c576ep+2940L }, - { 0x1.b05b032ac011e5c8p+0L, -0x9.89c1d87ab9de711p+11612L, -0x7.36265c43bbe44028p+11612L, -0x7.36265c43bbe4402p+11612L }, - { 0x2.56b6d5ed6e125aap+14564L, -0xd.309c19e3c810c88p+4748L, -0x2.ee719b7b44bb0cb8p+4764L, -0x2.ee719b7b44bb0cb4p+4764L }, - { 0x3.5c49fed90523d454p+1364L, 0x3.2ccd51955a529d84p-3488L, 0x1.0f0434ad8333b286p-3476L, 0x1.0f0434ad8333b288p-3476L }, - { 0xa.8ae9762015aefb8p+7828L, -0x5.a7c6805416a56c7p-576L, -0xa.d0179929a88ed25p-564L, -0xa.d0179929a88ed24p-564L }, - { 0x4.7e2047add8b77fd8p+8844L, -0x1.9d9b7dbed96ad514p+14612L, -0x3.7d45842a9b0a778p+14624L, -0x3.7d45842a9b0a777cp+14624L }, - { 0x1.48bc20b93d87d39cp+7296L, 0x1.f1f4a3bcd62d6452p-13940L, 0x3.7706fe1a27bb84ecp-13928L, 0x3.7706fe1a27bb84fp-13928L }, - { 0x5.e20fed3aa8e5dbdp-4376L, 0x8.e74b97d10e54bb2p+5756L, -0x9.81af1001916f875p+5768L, -0x9.81af1001916f874p+5768L }, - { 0x7.fea63fbd3f40e548p-8500L, -0x8.7ccedf1a38c6b27p+8392L, 0x1.19b6906c783876a8p+8408L, 0x1.19b6906c783876aap+8408L }, - { 0x4.3aa8266ac6dd9848p-4228L, -0x1.d6194fbfe0bb4bfcp-13020L, 0x1.e50280f80b74003ep-13008L, 0x1.e50280f80b74004p-13008L }, - { 0x8.532cbb25dd9a1cp-1464L, 0xe.6973c478c36a38p-11684L, -0x5.23efdcaa87ca0d1p-11672L, -0x5.23efdcaa87ca0d08p-11672L }, - { 0x3.3872f03af739bf68p+1516L, 0x1.c137424956de4544p+12564L, 0xa.67293139ecd81bap+12572L, 0xa.67293139ecd81bbp+12572L }, - { 0x6.0af11c58p-16416L, 0x2.d7786a2a00cb9468p+12132L, -0xb.631a9a8ce1d6547p+12144L, -0xb.631a9a8ce1d6546p+12144L }, - { 0xb.0c8e827b71ff9ddp+11904L, -0x1.991e9c0fb5a8a95cp+4852L, -0x4.a55994b56a2c982p+4864L, -0x4.a55994b56a2c9818p+4864L }, - { 0x5.b2a2fc8e42885c78p-10700L, -0x1.081daf3c372a6146p-2316L, 0x2.b1ca1ae901cbbed4p-2304L, 0x2.b1ca1ae901cbbed8p-2304L }, - { 0x7.f81afe7f042b169p+3428L, 0x3.7991903d8fee1378p-8468L, 0x2.e9248ef40b9703a4p-8456L, 0x2.e9248ef40b9703a8p-8456L }, - { 0x1.053217463c55943ap-5192L, -0x1.80cc47c7e5f02abap+13832L, 0x1.e7c23e8549413a6ap+13844L, 0x1.e7c23e8549413a6cp+13844L }, - { 0xc.a34c4ecf5b0aaabp+8592L, 0x2.e10d47fb5277498p+812L, 0x6.0abd7203021fbcep+824L, 0x6.0abd7203021fbce8p+824L }, - { 0x1.9f351837670e8d28p-6308L, -0x8.befb20c310d5188p+7320L, 0xd.77bc9d6e05309cdp+7332L, 0xd.77bc9d6e05309cep+7332L }, - { 0x4.862a5be8bc9616c8p+9460L, -0x5.2e01d76fb0f858a8p-5552L, -0xb.f7363992738cdf4p-5540L, -0xb.f7363992738cdf3p-5540L }, - { 0x1.1fbaf0e92a32036cp+10360L, -0x3.532ad895dea863e4p+14340L, -0x8.68e3d68cfc8efbp+14352L, -0x8.68e3d68cfc8efafp+14352L }, - { 0x8.b1ffeda31e21d18p-820L, -0x8.d4c31482f8ed374p+856L, 0x1.c2df2c0489d2c7a6p+868L, 0x1.c2df2c0489d2c7a8p+868L }, - { 0x6.bf0de63f8aba85p-9024L, 0x2.245b98a003e208ep-9644L, -0x4.b7bb688e83688eep-9632L, -0x4.b7bb688e83688ed8p-9632L }, - { 0x5.530558a8p-16416L, 0x3.4e3e89e41c249f1cp-6384L, -0xd.3f170a5de7dc7fap-6372L, -0xd.3f170a5de7dc7f9p-6372L }, - { 0xc.fbcd0eea9797117p+8288L, 0x6.58f9c61c99d53948p-2080L, 0xc.d9810980cf5822dp-2068L, 0xc.d9810980cf5822ep-2068L }, - { 0x2.dd7a3619e921daa8p-7868L, 0x4.e1c4b9ed98971fdp-7296L, -0x9.60370599ec12297p-7284L, -0x9.60370599ec12296p-7284L }, - { 0x3.70ea41aa5607c17cp+11940L, -0x1.f54a8c18553ed762p+8868L, -0x5.b5806a96815e76d8p+8880L, -0x5.b5806a96815e76dp+8880L }, - { 0x6.29c88af64c1d2208p+9156L, -0x2.d8c0b8e7335ac6p+2464L, -0x6.5d7c4d973388c83p+2476L, -0x6.5d7c4d973388c828p+2476L }, - { 0x1.9218991c4bceca82p+3496L, -0x4.e5f71ea1e451644p-12488L, -0x4.2e7a78e719b0a1ep-12476L, -0x4.2e7a78e719b0a1d8p-12476L }, - { 0x2.be4f59cbceea3f8p-8768L, 0x9.21d471a6f899699p-11672L, -0x1.38b96068ba6bd08cp-11656L, -0x1.38b96068ba6bd08ap-11656L }, - { 0x9.ea26da61e1e9ee4p+10944L, 0x5.a81356ece0725948p+13688L, 0xf.1e3f343362aac9bp+13700L, 0xf.1e3f343362aac9cp+13700L }, - { 0x6.d6086c949b90754p+10336L, -0xe.400dcdc7097b86ap-2124L, -0x2.3f81b1fd4ef356ep-2108L, -0x2.3f81b1fd4ef356dcp-2108L }, - { 0x1.0350a9dede8123fap+7292L, -0x1.31c156f68fa864e2p+10212L, -0x2.20544d6074c3297p+10224L, -0x2.20544d6074c3296cp+10224L }, - { 0x3.539f1f79bb8d2b58p+1380L, -0x4.038559ede788f67p+10440L, -0x1.5a9f0a37b78786a2p+10452L, -0x1.5a9f0a37b78786ap+10452L }, - { 0x1.4652c37bddc46c36p+0L, -0x3.490ebc26b0621858p+3736L, -0x1.2680d02b02da8dfap+3736L, -0x1.2680d02b02da8df8p+3736L }, - { 0x1.1e2283f3e0d553d2p+11948L, 0x1.795f7455f6f5970ap+10872L, 0x4.4ccefa00fb8ddc7p+10884L, 0x4.4ccefa00fb8ddc78p+10884L }, - { 0x1.03d02412ea0fcd1ep-8536L, -0xa.5ad8a157b120ca8p+14164L, 0x1.5944eeb8cff41832p+14180L, 0x1.5944eeb8cff41834p+14180L }, - { 0x2.8e6b15a22d662794p-192L, 0x4.46b5ea7e4593773p+14680L, -0x3.2f3e1f7c0534dae8p+14688L, -0x3.2f3e1f7c0534dae4p+14688L }, - { 0xc.ec916ba1d9f3d7cp-6028L, -0x6.4925df5d8dba609p+9532L, 0x9.3eb32d1c6521b32p+9544L, 0x9.3eb32d1c6521b33p+9544L }, - { 0x8.df8a92908e3e2d5p+10460L, -0x1.35f423319cb099ecp-14232L, -0x3.17c537d732e96b68p-14220L, -0x3.17c537d732e96b64p-14220L }, - { 0xe.990e956e9d5098cp-10900L, 0x8.6c02663c1fa029ap-11932L, -0x1.667643641596bc48p-11916L, -0x1.667643641596bc46p-11916L }, - { 0xf.0b38b18a81a2e75p-9264L, 0x5.807d83c8ec8ff568p+13408L, -0xc.7043951c1e543f3p+13420L, -0xc.7043951c1e543f2p+13420L }, - { 0x1.e65c8504b82ec6a2p+14584L, -0x6.9bd91d1f5f5a1338p+12052L, -0x1.78849727fbcb985cp+12068L, -0x1.78849727fbcb985ap+12068L }, - { 0xf.1b596643482a518p+13788L, -0x5.d188e3656b87e14p-1564L, -0x1.3978336aa69399ap-1548L, -0x1.3978336aa693999ep-1548L }, - { 0xc.57817a1978c4d96p-8384L, 0x1.7bc496e53462329ep+5112L, -0x3.090057635b92403p+5124L, -0x3.090057635b92402cp+5124L }, - { 0x1.acfc662b3c39eebcp+0L, 0x4.11c79de36b71e45p+8412L, 0x3.07e74dd05087436p+8412L, 0x3.07e74dd050874364p+8412L }, - { 0x1.e9ead1df706b14a2p-6468L, -0x5.98f7597ee100d5d8p+14880L, 0x8.d678b9ee0d151bap+14892L, 0x8.d678b9ee0d151bbp+14892L }, - { 0x6.433a12950afdf158p-1436L, -0x1.98718075dc660c0ap-304L, 0x8.eee39f155669ff3p-296L, 0x8.eee39f155669ff4p-296L }, - { 0x4.449bca5d7a1edddp-8936L, -0x1.0bea9b7e8ad6b81ap+8672L, 0x2.485c45d7b9b8dd2cp+8684L, 0x2.485c45d7b9b8dd3p+8684L }, - { 0x1.f2325cb37958cfa4p-7568L, 0x3.71de7698fe1de088p+10488L, -0x6.5d2f178d80f3e77p+10500L, -0x6.5d2f178d80f3e768p+10500L }, - { 0x4.3b8744dd0317419p-2872L, 0x1.9f85eb8234b6ee9cp-9052L, -0x1.232457e89b7f36ap-9040L, -0x1.232457e89b7f369ep-9040L }, - { 0x2.82d91c368563b43p+520L, 0xf.74f8978fb20a3c3p-3316L, 0x1.f7a2121c656ba95ep-3304L, 0x1.f7a2121c656ba96p-3304L }, - { 0x5.e796e1cfc9288b08p-6856L, 0x1.e7549a99b10b7a6cp+2624L, -0x3.2f671549d02c643cp+2636L, -0x3.2f671549d02c6438p+2636L }, - { 0x6.e056753a5860b3b8p-12668L, 0x3.f7ba2b85ca9670e4p+1420L, -0xc.44b971f65cd0ba4p+1432L, -0xc.44b971f65cd0ba3p+1432L }, - { 0x7.dab816b779cd0b28p+6964L, -0x2.6b4a99eb6919b3e4p+8040L, -0x4.1d5dad8f69d2d4fp+8052L, -0x4.1d5dad8f69d2d4e8p+8052L }, - { 0x2.768c2ccae5a41844p-14664L, 0x2.2bd7f0960ffa1d4cp+11764L, -0x7.c5c9672b404b585p+11776L, -0x7.c5c9672b404b5848p+11776L }, - { 0x1.4214ceb4f8b26f84p+0L, 0x1.aeee948823e94fdp-3348L, 0x8.ec272fe563e96d8p-3352L, 0x8.ec272fe563e96d9p-3352L }, - { 0xf.22fae2a1fe73d63p+12048L, -0xc.6919a02e29e222ap+10216L, -0x2.4842ec282586fd2p+10232L, -0x2.4842ec282586fd1cp+10232L }, - { 0xf.2d33cefe0c45e86p+4200L, -0x2.b6a0e50f22f86cf8p-13716L, -0x2.c8ee53eb4bc41c2p-13704L, -0x2.c8ee53eb4bc41c1cp-13704L }, - { 0xa.77239ea21ede3cap+14536L, -0x1.b2d35d2a6452f9c2p-6280L, -0x6.077b280d797de588p-6268L, -0x6.077b280d797de58p-6268L }, - { 0xb.0b452f4738e9ba3p+1988L, 0xb.054b19e6e2203d5p+12200L, 0x5.5bb4b8962241e958p+12212L, 0x5.5bb4b8962241e96p+12212L }, - { 0x1.2b4c1f63d0b618bcp-1124L, 0xa.0d829b5cf72e0d7p-2276L, -0x2.c210d48e5f1921p-2264L, -0x2.c210d48e5f1920fcp-2264L }, - { 0x1.277fb450f434ba56p-5832L, 0x3.12f29b90db4ce928p+12224L, -0x4.60704004db7e2cb8p+12236L, -0x4.60704004db7e2cbp+12236L }, - { 0x3.70f6435c48a390ep-13484L, -0x2.ed8098445a35e71cp+14560L, 0x9.a307903a581ace3p+14572L, 0x9.a307903a581ace4p+14572L }, - { 0x1.c3c2896f8e2c3c2cp-1344L, 0x2.e80154ad5d5bfe34p+12880L, -0xf.3fa556e4f615bd4p+12888L, -0xf.3fa556e4f615bd3p+12888L }, - { 0x7.55b2ffccf81fa4b8p+7264L, -0x7.898636ae4e2f4d18p+13220L, -0xd.5f3eb3613345c3bp+13232L, -0xd.5f3eb3613345c3ap+13232L }, - { 0x4.12a3f2a71216bef8p+9288L, -0x4.fc64f774546e7168p+508L, -0xb.4ef49340f384ccfp+520L, -0xb.4ef49340f384ccep+520L }, - { 0x1.78262e13ab821e2p+0L, 0x1.80928281b3ac1d92p-2440L, 0xd.57fe1c2ddca1d6bp-2444L, 0xd.57fe1c2ddca1d6cp-2444L }, - { 0xf.215dcf89bd7792ap-13144L, -0xb.2d7f53d1195baf3p-13236L, 0x2.3dbc323174b49ab8p-13220L, 0x2.3dbc323174b49abcp-13220L }, - { 0x1.daac07c45ff52192p-13804L, -0x6.e2ed9d399f6c20a8p-7344L, 0x1.734e42351476817ap-7328L, 0x1.734e42351476817cp-7328L }, - { 0x6.775c2f8ce5a4a958p-12628L, -0x1.faa26ace0fb72f9ap-13992L, 0x6.199ff67cf30c524p-13980L, 0x6.199ff67cf30c5248p-13980L }, - { 0x1.4b67a4bdb9c98152p-5500L, -0x6.aab152bd7aff0f4p-116L, 0x8.f38be04d7e34735p-104L, 0x8.f38be04d7e34736p-104L }, - { 0x1.b93aed734b7a822ap-10328L, -0x6.f21ba81d936c2638p+9052L, 0x1.183217455957ceaep+9068L, 0x1.183217455957cebp+9068L }, - { 0x6.7701481d120c1b6p+8820L, -0x1.a8ad4a5048b28454p-13072L, -0x3.92be9e2abf346cbcp-13060L, -0x3.92be9e2abf346cb8p-13060L }, - { 0xd.606d27e348943bep+8040L, -0x3.c4aee51dff57549cp+6940L, -0x7.6672e4ca1236dbf8p+6952L, -0x7.6672e4ca1236dbfp+6952L }, - { 0x8.9aaf44bff92900ap+13008L, 0xe.c1faf84f1f451c8p-796L, 0x2.ee0e7337eb6ae698p-780L, 0x2.ee0e7337eb6ae69cp-780L }, - { 0xe.4770dc927d5eba1p+14740L, -0x4.73f832df7f78bec8p-156L, -0x1.0076638bc9f51726p-140L, -0x1.0076638bc9f51724p-140L }, - { 0x2.4ee6fe7f8bfa4f84p-1868L, -0x3.c61bfddaa521f2dp+8756L, 0x1.b85065fb85524aa2p+8768L, 0x1.b85065fb85524aa4p+8768L }, - { 0x2.d971898p-16416L, 0x1.5638b03330502364p-13028L, -0x5.5b6ee288b3cddcb8p-13016L, -0x5.5b6ee288b3cddcbp-13016L }, - { 0x3.185dd7d25a7b23f8p-13364L, 0xb.908cd56ce51db8fp-11836L, -0x2.5ba31e30c31c3dbcp-11820L, -0x2.5ba31e30c31c3db8p-11820L }, - { 0x3.a9a51c7cd1a62094p-12044L, -0x2.00963f0465d54a3cp-3104L, 0x5.e2fdc96e2c6a383p-3092L, 0x5.e2fdc96e2c6a3838p-3092L }, - { 0x9.7bae07b48f3d186p-13524L, 0x3.7eab03f7d9fc9158p+12752L, -0xb.8944ae7feb4dfc1p+12764L, -0xb.8944ae7feb4dfcp+12764L }, - { 0x2.974394b3d7b2078p+4088L, 0xb.3d5a0ceef37dac4p-6224L, 0xb.38b25dccc5a2166p-6212L, 0xb.38b25dccc5a2167p-6212L }, - { 0x5.3df9deaca20b2af8p-11080L, -0x5.4e765875989e9d8p-12400L, 0xe.59f433942d6ed78p-12388L, 0xe.59f433942d6ed79p-12388L }, - { 0x9.a7432a90d8d0bdbp+3312L, -0xd.a5c8e96c062ac37p-13004L, -0xb.0bd7b947d5a7d5bp-12992L, -0xb.0bd7b947d5a7d5ap-12992L }, - { 0xa.5245ba426d8cb8dp-8052L, 0x3.d8775bbd6cd0492cp-14992L, -0x7.8e796f0d9e08e8f8p-14980L, -0x7.8e796f0d9e08e8fp-14980L }, - { 0x2.71263b8c47253e1cp+8804L, -0x1.1047e1aacc267022p+14756L, -0x2.49546c369bf44644p+14768L, -0x2.49546c369bf4464p+14768L }, - { 0xb.7bbc2a109b78a97p-12480L, -0x3.10f36db5217d4878p-2108L, 0x9.56f8ef5d208aaa8p-2096L, 0x9.56f8ef5d208aaa9p-2096L }, - { 0x3.43e23acc2678bfecp-14844L, -0x9.ba704ceece1ba4fp-10368L, 0x2.3405ec1a1d6af318p-10352L, 0x2.3405ec1a1d6af31cp-10352L }, - { 0x5.447d50515731259p-4L, -0x3.8b954314786b23ap-2376L, 0x5.aebd2b28bf0b051p-2376L, 0x5.aebd2b28bf0b0518p-2376L }, - { 0x1.53ad8155928be6a4p-2032L, 0x1.a4ce39e0a6fe0442p+6936L, -0xd.0b7938a1f47f704p+6944L, -0xd.0b7938a1f47f703p+6944L }, - { 0x4.d16dd659f3c0f0ap-11256L, -0xd.fd723f0edb1d50fp+8416L, 0x2.66fffae75fb38a2cp+8432L, 0x2.66fffae75fb38a3p+8432L }, - { 0x1.103dfac7cd7c39e4p-5592L, -0x7.de07d07c42e504c8p+3860L, 0xa.bd947f52d4fff55p+3872L, 0xa.bd947f52d4fff56p+3872L }, - { 0x5.7c08324a140957ap+6828L, -0x1.3b6c02589b9259fcp+7784L, -0x2.0dfeb4804581daep+7796L, -0x2.0dfeb4804581dadcp+7796L }, - { 0x6.6f91a8945bb1196p+14828L, 0x6.57abdcaa9f822a78p+2452L, 0x1.6f6f1ff2fef76764p+2468L, 0x1.6f6f1ff2fef76766p+2468L }, - { 0x4.0dbdac43c89f5fa8p-8876L, 0x2.d4d64652d10516ecp+9408L, -0x6.225bdb14e1f214b8p+9420L, -0x6.225bdb14e1f214bp+9420L }, - { 0x6.04e85f85770e42f8p+11628L, -0x1.68a03c17c2b3a2d4p+9568L, -0x3.ffff406c0bdc55f4p+9580L, -0x3.ffff406c0bdc55fp+9580L }, - { 0x1.fac44e7ef22a75e2p-6660L, 0x1.53007eaa586c5ed2p-11556L, -0x2.2720ae514ec9e31p-11544L, -0x2.2720ae514ec9e30cp-11544L }, - { 0x1.c1af05b36c1e1314p-7544L, -0x1.db24c1b166e6b918p-11396L, 0x3.6b060fd951632d28p-11384L, 0x3.6b060fd951632d2cp-11384L }, - { 0x1.19427dcda0480416p-100L, 0x1.c36218d9ea12b06p-11836L, -0xb.0150a2cc8ed4846p-11832L, -0xb.0150a2cc8ed4845p-11832L }, - { 0x1.99c57945979570cp+0L, -0x3.9a147b2294cce81cp+7488L, -0x2.71cb044a663ad638p+7488L, -0x2.71cb044a663ad634p+7488L }, - { 0x8.35964c3a9d13241p-14272L, 0x1.cb6b91a0ad1a1b26p+11236L, -0x6.4073995695e99f88p+11248L, -0x6.4073995695e99f8p+11248L }, - { 0x1.4ec5569f83ab5736p-11296L, -0x3.8f33377c31308a44p-3004L, 0x9.d0d5346d7f8775ap-2992L, 0x9.d0d5346d7f8775bp-2992L }, - { 0xa.e64af69cc0c9a02p+452L, -0xe.30ae8ff9c10b4e2p-11172L, -0x1.93edb29bc02715cap-11160L, -0x1.93edb29bc02715c8p-11160L }, - { 0x1.f57725c0787861ecp+8460L, -0x1.8d1cb508a9ab2afp-4984L, -0x3.344d1e223db10d48p-4972L, -0x3.344d1e223db10d44p-4972L }, - { 0xe.3fac9734bbe71dfp+1164L, 0x1.2206e0f0b72822fcp+7496L, 0x5.2b0ee153f0bcf8a8p+7504L, 0x5.2b0ee153f0bcf8bp+7504L }, - { 0x2.a47e35e1ebe00cap-12464L, -0xd.d1efe43682ae912p+4124L, 0x2.a0c9efc557e73a04p+4140L, 0x2.a0c9efc557e73a08p+4140L }, - { 0xd.4a29b6e571f7f4dp+10012L, -0x9.5dd68d90c07dd66p+12464L, -0x1.6e74e8550fd34c12p+12480L, -0x1.6e74e8550fd34c1p+12480L }, - { 0x5.c36184a826a997c8p-14612L, 0xd.f4b5749411edfbp-3724L, -0x3.1c70415b25d650c8p-3708L, -0x3.1c70415b25d650c4p-3708L }, - { 0x1.fec2d25986d2c82ep+1752L, -0x1.c57eae44abd4be9ep-12468L, -0xc.215ee188c77742cp-12460L, -0xc.215ee188c77742bp-12460L }, - { 0xc.54dfb245063a9b5p+736L, 0xf.10e4c2279861992p-10604L, 0x2.b872c2568d3b19d4p-10592L, 0x2.b872c2568d3b19d8p-10592L }, - { 0x7.2511d87p-16416L, -0x1.8e6f895a46c46376p-3516L, 0x6.3c945f5d473002ep-3504L, 0x6.3c945f5d473002e8p-3504L }, - { 0x5.ab74bda0e9f7dc48p-11284L, -0x3.85da52552263bf3cp+188L, 0x9.b3f299cce4fce6ap+200L, 0x9.b3f299cce4fce6bp+200L }, - { 0x6.f8e5e146df8b2df8p+4628L, -0x6.801cd00cd5c87f7p-14356L, -0x7.5963f19aebc7d238p-14344L, -0x7.5963f19aebc7d23p-14344L }, - { 0x6.af69ebfdc141d71p+6980L, 0xc.78d6cd9d8fb34ebp-14544L, 0x1.5430f03a79108192p-14528L, 0x1.5430f03a79108194p-14528L }, - { 0x2.d62679fc1dcc84f8p+3140L, 0x5.fdcf1e255c31878p+1624L, 0x4.9862377e4c9b3cp+1636L, 0x4.9862377e4c9b3c08p+1636L }, - { 0x7.f8395e79564ebaap+60L, -0xf.6848263df1e17f7p+10516L, -0x3.ca941be39f8c20acp+10524L, -0x3.ca941be39f8c20a8p+10524L }, - { 0x1.8c3ff1590baa159ap-8448L, -0x2.d6a2d6b9cdaf1e5cp+5536L, 0x5.da933b48b3f2c5b8p+5548L, 0x5.da933b48b3f2c5cp+5548L }, - { 0xf.7679533e38c76d9p-13512L, -0x2.9e835f5c8364ae6cp+5928L, 0x8.a342cfd4ceeb772p+5940L, 0x8.a342cfd4ceeb773p+5940L }, - { 0xb.faf082b54ef2606p-14972L, 0x1.f3c6efc2e5ffb4e6p-7316L, -0x7.226282ff9956c7c8p-7304L, -0x7.226282ff9956c7cp-7304L }, - { 0x5.bfaf79aef43b597p-6912L, -0xf.1209a1e9d495726p+14776L, 0x1.96c0fd44f325c3fp+14792L, 0x1.96c0fd44f325c3f2p+14792L }, - { 0xf.55e7c12943cd9e3p-6360L, 0x1.30338ac91f40e2b2p-2200L, -0x1.d80d24f04b5e17bep-2188L, -0x1.d80d24f04b5e17bcp-2188L }, - { 0x2.0170ec08p-16416L, 0x3.f9d950af555b34d8p+1520L, -0xf.ef1915c00213218p+1532L, -0xf.ef1915c00213217p+1532L }, - { 0x9.438df09cbbeb10bp+11920L, -0x1.f49d11dbf4152fd8p-8844L, -0x5.b1419570741079ep-8832L, -0x5.b1419570741079d8p-8832L }, - { 0x1.39b9c285df388998p+13596L, -0xc.9214ffa074b0b5fp-10512L, -0x2.9ba203464a83d634p-10496L, -0x2.9ba203464a83d63p-10496L }, - { 0xa.5f724f2608e28b2p-4708L, 0x1.dd92386080291574p+13984L, -0x2.248896740c8620e8p+13996L, -0x2.248896740c8620e4p+13996L }, - { 0x1.2fcd33518ffb63f6p+5836L, 0xf.6172d7a361a0172p-956L, 0x1.5ea55289ffeab622p-940L, 0x1.5ea55289ffeab624p-940L }, - { 0xc.a8dc2de30b15b92p+5508L, -0x4.bbe0b101ef388428p+11952L, -0x6.5eba477cb699702p+11964L, -0x6.5eba477cb6997018p+11964L }, - { 0x2.5589af74b36b200cp+2652L, 0x1.2df972a1d9a4979p+13440L, 0xc.39b5674995e5924p+13448L, 0xc.39b5674995e5925p+13448L }, - { 0x2.6e39319255f2e85cp-12576L, -0x8.6765d8ee23089b3p+13476L, 0x1.9ccca6b0cc048174p+13492L, 0x1.9ccca6b0cc048176p+13492L }, - { 0xf.d8fad8e98f71b18p+11084L, -0xd.1751bb0b57d5a64p-8428L, -0x2.3701d5ad9aede528p-8412L, -0x2.3701d5ad9aede524p-8412L }, - { 0x1.f20b5ada21c997a6p+2796L, -0x7.4f3d7f0f8057c7fp+216L, -0x4.fdc784a368328628p+228L, -0x4.fdc784a36832862p+228L }, - { 0x2.ec355c67c4fad788p-11308L, -0x1.8877194d22dc426ep+12004L, 0x4.3b58d8f089f7b7d8p+12016L, 0x4.3b58d8f089f7b7ep+12016L }, - { 0x6.10df3f08p-16416L, 0x3.817942a0a769381cp-14720L, -0xe.0c561bbd87a62c2p-14708L, -0xe.0c561bbd87a62c1p-14708L }, - { 0x6.bd0fe1dc836eadfp-2136L, -0x6.f44c3fc5e9f0dcdp-9768L, 0x3.9f3380dc7a30e2d4p-9756L, 0x3.9f3380dc7a30e2d8p-9756L }, - { 0x1.dc7ec24162fe6b86p+6416L, 0xa.d904450a87c914dp+6880L, 0x1.0fe8b419324e5f7cp+6896L, 0x1.0fe8b419324e5f7ep+6896L }, - { 0x2.1154e9b7d8bc947cp+14296L, 0x2.8005335ce62297e4p-2280L, 0x8.b9fc12eb0b97e15p-2268L, 0x8.b9fc12eb0b97e16p-2268L }, - { 0x2.74ac5ca14051d8c8p+11348L, 0x7.0dbe8b515344edd8p-11768L, 0x1.38b667035b5453eap-11752L, 0x1.38b667035b5453ecp-11752L }, - { 0x7.1de5eb4d52288bd8p+5288L, 0x1.574c4b79e115507cp+12240L, 0x1.bb70beb675fd9e3ep+12252L, 0x1.bb70beb675fd9e4p+12252L }, - { 0xe.94dc072f915b9d6p-9840L, -0x1.33686966e730be5cp-8980L, 0x2.e2358dde81d0fe6cp-8968L, 0x2.e2358dde81d0fe7p-8968L }, - { 0x1.7c62423d8dcc70ap+12720L, 0x6.caa1f4e928c8b418p-12892L, 0x1.51783086464f7fbcp-12876L, 0x1.51783086464f7fbep-12876L }, - { 0x2.fd1e13da6acdd0bcp+11408L, -0x5.a5a7ab4fcb0ebe2p+11256L, -0xf.baeeb396d2b0e9p+11268L, -0xf.baeeb396d2b0e8fp+11268L }, - { 0x1.0405975065fa257ep-7100L, -0x3.fdf6965a0a7ce894p+14952L, 0x6.eb76bf6483135628p+14964L, 0x6.eb76bf648313563p+14964L }, - { 0x1.7989128da5ed012p-9088L, 0x2.fc6d5635215dc184p-3920L, -0x6.9ff7d0476617d7fp-3908L, -0x6.9ff7d0476617d7e8p-3908L }, - { 0xd.055219222b15826p-4L, 0x2.edc4531e12e7a84p+8956L, -0xd.edf55a814a9b1a7p+8952L, -0xd.edf55a814a9b1a6p+8952L }, - { 0x7.5b088224bb277808p-7200L, -0x5.6b6879b6303a20bp+372L, 0x9.85d403deb866612p+384L, 0x9.85d403deb866613p+384L }, - { 0x7.03716987879c6018p-10492L, 0x1.adc33e4dc78313c6p-328L, -0x4.4c8d63dc02372a48p-316L, -0x4.4c8d63dc02372a4p-316L }, - { 0x1.da61b2ff79d0db24p+264L, 0x1.2e8b11af94cc68b2p+2376L, 0x1.390ca6484829684cp+2384L, 0x1.390ca6484829684ep+2384L }, - { 0xa.f1f3b5f8ea8a2b6p+7968L, 0x1.904871e14600c2bcp-7332L, 0x3.0b034b594dda06ap-7320L, 0x3.0b034b594dda06a4p-7320L }, - { 0x3.6ae487af5a263c4p+14132L, 0x1.ae943bae4789d33ap-2168L, 0x5.cdc4a551070f1538p-2156L, 0x5.cdc4a551070f154p-2156L }, - { 0x2.91609a622daf31e4p-4876L, 0x2.dc7407749b13934cp+1904L, -0x3.67b0d6eb6b3bdf74p+1916L, -0x3.67b0d6eb6b3bdf7p+1916L }, - { 0x1.d99d97dab08ea934p+12696L, -0xd.6727a80c183e2d2p-1688L, -0x2.98bfbc1c6bf749a8p-1672L, -0x2.98bfbc1c6bf749a4p-1672L }, - { 0x1.a88e6202e69d3e36p-8164L, -0x3.3b8ff738d5bcfedcp+12568L, 0x6.7151f311b8f003b8p+12580L, 0x6.7151f311b8f003cp+12580L }, - { 0x3.9da48fd55e06d82p-2016L, 0x9.75441492e92e938p-11520L, -0x4.a69ee59d49e6ac78p-11508L, -0x4.a69ee59d49e6ac7p-11508L }, - { 0x6.e4b00b3b240142e8p+10764L, 0x6.e51718f6edc8117p+11268L, 0x1.21fbbb4d7e6a6ebep+11284L, 0x1.21fbbb4d7e6a6ecp+11284L }, - { 0x4.b95f1008p-16416L, 0x7.908b2d72dd961268p-4568L, -0x1.e503ead22ff73dbcp-4552L, -0x1.e503ead22ff73dbap-4552L }, - { 0x1.66c1bb97ab0ddaf2p-14964L, 0x2.5463a5ef35f229f8p-56L, -0x8.82bae6360805bacp-44L, -0x8.82bae6360805babp-44L }, - { 0x2.3637d76bb2135d3p-9636L, -0xb.7a932240c1b4016p-14796L, 0x1.b004a4e92f670be6p-14780L, 0x1.b004a4e92f670be8p-14780L }, - { 0x4.cf778309532b4ebp-1072L, 0xd.a187d193099d32p+14532L, -0x3.8f584e61aa9fd4f8p+14544L, -0x3.8f584e61aa9fd4f4p+14544L }, - { 0x6.6073bd067abac2c8p+11092L, -0x2.20b8ef4823854164p+13672L, -0x5.c377cd23914a472p+13684L, -0x5.c377cd23914a4718p+13684L }, - { 0x6.6c2bf697eaadaa5p+5628L, 0x2.3ba43ace18fc3068p-6200L, 0x3.11d2c48e39fe1bdcp-6188L, 0x3.11d2c48e39fe1bep-6188L }, - { 0x2.87c33a262964fd9cp+8628L, -0xf.26e2f1c7fdd8f81p-2156L, -0x1.febee3d02376b5f8p-2140L, -0x1.febee3d02376b5f6p-2140L }, - { 0x2.5af103b8c04393dcp+14240L, 0xf.eeaf2649294683ep+4684L, 0x3.76507f6f2843ac0cp+4700L, 0x3.76507f6f2843ac1p+4700L }, - { 0x1.c5517be1322d88acp-3840L, -0xd.ad84401801a45f6p-12328L, 0xc.d1f792c56fea84dp-12316L, 0xc.d1f792c56fea84ep-12316L }, - { 0x1.f481e7f5a608c8c2p-10832L, -0x7.caae88ce01de0b28p-10208L, 0x1.49a86fa297491138p-10192L, 0x1.49a86fa29749113ap-10192L }, - { 0x4.3bd32cddd2adb53p+6132L, 0x1.7ef0a1fc8c9b04ccp+9928L, 0x2.3d7b927c9e933c78p+9940L, 0x2.3d7b927c9e933c7cp+9940L }, - { 0x5.7001db08p-16416L, -0xc.41d507fb40798b9p-13684L, 0x3.11df8b0dd5773becp-13668L, 0x3.11df8b0dd5773bfp-13668L }, - { 0x6.044acf83853e4228p-9104L, -0xd.b86c5707774a4a2p-8316L, 0x1.e7cb073787416962p-8300L, 0x1.e7cb073787416964p-8300L }, - { 0x7.eedd2b5801d30ddp+7992L, -0x3.7b7080994ba8601p+11972L, -0x6.cc007b1d43a7a56p+11984L, -0x6.cc007b1d43a7a558p+11984L }, - { 0x1.f5be5d508fb45da4p+9112L, 0x1.df36989632baa77cp+8068L, 0x4.2a2d08050cc7844p+8080L, 0x4.2a2d08050cc78448p+8080L }, - { 0xb.cb682f76a3f814p-588L, 0x1.8221ab8a45beb70ap+5048L, -0x3.7186b04965becde4p+5056L, -0x3.7186b04965becdep+5056L }, - { 0x1.da34232a6dcd2a12p+6624L, 0x2.4b62cb0f68a8551p-1320L, 0x3.b60a6ac66abd2584p-1308L, 0x3.b60a6ac66abd2588p-1308L }, - { 0x1.493dc3decd39a4dep+3500L, 0x1.0d22af0930e0b6fp+4276L, 0xe.5ff7e362d36c1fcp+4284L, 0xe.5ff7e362d36c1fdp+4284L }, - { 0x1.677dc1ce56c13e36p-2052L, 0x3.369a880d9098bd94p-8212L, -0x1.9c01bbe923a7cd8ep-8200L, -0x1.9c01bbe923a7cd8cp-8200L }, - { 0x1.243bd932d58f9d4p+2232L, -0x4.405714e489cdecc8p-4048L, -0x2.511c717d4ef5a6ap-4036L, -0x2.511c717d4ef5a69cp-4036L }, - { 0x6.0af8d49f145e687p+2796L, 0x5.839c88a10e84ba4p-6556L, 0x3.c47c119946aaf368p-6544L, 0x3.c47c119946aaf36cp-6544L }, - { 0x6.d702937630559bfp-3504L, -0xe.d559a68601d334ep-376L, 0xc.adf155961d544e9p-364L, 0xc.adf155961d544eap-364L }, - { 0x5.a1a1b43fda655bd8p-4L, -0xc.eb3db51a4117749p+5524L, 0x1.37666ead2720f402p+5528L, 0x1.37666ead2720f404p+5528L }, - { 0x1.d4fff2bbd3cd6096p+14012L, -0x9.b242f08632fe79dp+4872L, -0x2.12c180026a9a0d44p+4888L, -0x2.12c180026a9a0d4p+4888L }, - { 0x3.dce49626e093ee74p-1236L, 0xe.19b5bca3f808afep-1016L, -0x4.3f8a3b4158ea32dp-1004L, -0x4.3f8a3b4158ea32c8p-1004L }, - { 0x3.da483e0a56def77p+12192L, -0x1.a6e3721b926d2e74p-10244L, -0x4.eaf46fbbec4f8428p-10232L, -0x4.eaf46fbbec4f842p-10232L }, - { 0x4.07f8e4310889c4e8p+10772L, -0xc.8841513e4940958p+11376L, -0x2.0f6e90d6698fa354p+11392L, -0x2.0f6e90d6698fa35p+11392L }, - { 0x1.fb59ad3e66e925fp-7792L, 0x4.36d6c1b431f631p+6232L, -0x8.04100041d8b6f53p+6244L, -0x8.04100041d8b6f52p+6244L }, - { 0x4.dd76d9666cca4358p-320L, 0x4.25e1b5ec2d09b028p-4464L, -0x5.25e26d6cad8dc608p-4456L, -0x5.25e26d6cad8dc6p-4456L }, - { 0x7.511fbab815148398p+9832L, -0x9.136d9190525debbp+12768L, -0x1.5cac3737912c4d42p+12784L, -0x1.5cac3737912c4d4p+12784L }, - { 0x1.d2c419eacc353274p-5220L, 0x3.a7736bf4d7d242f8p+6924L, -0x4.a7f42e68003a106p+6936L, -0x4.a7f42e68003a1058p+6936L }, - { 0x3.d1ca473f87febbdp-12640L, -0x6.e69234d17bbb5598p-11576L, 0x1.54ab1b7b62ece05ep-11560L, 0x1.54ab1b7b62ece06p-11560L }, - { 0x8.aa229058b7ec91ap+11260L, 0x2.56be1f012070b9acp+8576L, 0x6.6e69b8535265253p+8588L, 0x6.6e69b85352652538p+8588L }, - { 0x1.c7748fedb8ca471ap+0L, 0x3.392a62c6b703c4ecp+13940L, 0x2.add96e5e07d757e4p+13940L, 0x2.add96e5e07d757e8p+13940L }, - { 0x1.40b8689b9086f9d2p-14232L, 0x2.67e16890207f4008p-2292L, -0x8.5be5308a970cf1cp-2280L, -0x8.5be5308a970cf1bp-2280L }, - { 0x1.4020453efbe8ffdp-10896L, 0xc.8616627c8c648f6p+1252L, -0x2.15070ecc4a673a9cp+1268L, -0x2.15070ecc4a673a98p+1268L }, - { 0x2.38adc006fc23903p+6140L, 0x6.1777a16c16e2514p-2972L, 0x9.221dcf1a3d6e125p-2960L, 0x9.221dcf1a3d6e126p-2960L }, - { 0x5.eccfd047cc0e3388p-10440L, -0x1.b6e7836a71634822p+10592L, 0x4.5e6aacff0d156058p+10604L, 0x4.5e6aacff0d15606p+10604L }, - { 0x6.42d0a34a532209ep-7740L, -0x6.f6bb9a4c17f8e4c8p+1628L, 0xd.279623da9a5e4b7p+1640L, 0xd.279623da9a5e4b8p+1640L }, - { 0x7.eb89e9bd6da32ep+8104L, 0x2.06274f7ea5ec58d4p-3536L, 0x4.018d760dfe123718p-3524L, 0x4.018d760dfe12372p-3524L }, - { 0x1.52e498e37a488bdap-1444L, -0xa.0f4bc2cfdcbdd27p+12596L, 0x3.8ba35274a6f86ec4p+12608L, 0x3.8ba35274a6f86ec8p+12608L }, - { 0xa.fe50b439a96ea55p+10156L, -0x3.a6a05daa8cf8ba1cp+14960L, -0x9.0e3027c0c5b948dp+14972L, -0x9.0e3027c0c5b948cp+14972L }, - { 0x1.95f38ef02236fd6cp+36L, 0x5.9a25ab758149ad5p+11224L, 0xc.d673d3e22020888p+11228L, 0xc.d673d3e22020889p+11228L }, - { 0x2.aa06a7b698b0b3e4p-13208L, 0xf.a22449fa646a2e3p+14428L, -0x3.267f668663bace68p+14444L, -0x3.267f668663bace64p+14444L }, - { 0x1.bf2d10d91eae0db2p+0L, -0x1.f41156a05dc1e02p-8448L, -0x1.92676f0461939be2p-8448L, -0x1.92676f0461939bep-8448L }, - { 0x3.678e1f2aa097eb6p-9600L, -0x6.48717c11cd853a38p-4344L, 0xe.b9184d58694da4ap-4332L, 0xe.b9184d58694da4bp-4332L }, - { 0x6.fa2cdb8df72f8548p-1508L, -0x5.5c8be3b33b03234p-13204L, 0x1.f86214217fa1db1p-13192L, 0x1.f86214217fa1db12p-13192L }, - { 0x5.b43694428f84ed2p+2964L, -0x2.9ea35367c5b0b0fp-2284L, -0x1.e5b4f9fe4ab5c4fcp-2272L, -0x1.e5b4f9fe4ab5c4fap-2272L }, - { 0x1.01687357811d4fd2p+5028L, -0x7.3e1390b9f6f3a3e8p+11328L, -0x8.e3f46f26fefd7d4p+11340L, -0x8.e3f46f26fefd7d3p+11340L }, - { 0x1.1181efb54abefbbep-12372L, 0x6.83c34bd099d6ae7p+4440L, -0x1.3ad73b21743243aep+4456L, -0x1.3ad73b21743243acp+4456L }, - { 0x7.6dfb1adacc93b0d8p-1996L, -0x1.c3d8c6cee90c3ba2p-5648L, 0xd.bde2db8a05260cep-5640L, 0xd.bde2db8a05260cfp-5640L }, - { 0x1.a43f7998e3bc6428p+6660L, 0x1.25125ef5c349b838p-10488L, 0x1.dc943819311290cp-10476L, 0x1.dc943819311290c2p-10476L }, - { 0x9.59de5e82fe42ee3p-4912L, -0x2.82f638bfb4cf4becp+4548L, 0x3.028babe7dbd4e47cp+4560L, 0x3.028babe7dbd4e48p+4560L }, - { 0x1.c7a1126551114648p+7108L, 0xd.27237ee2cef0c03p+12688L, 0x1.6d3da6102aee785p+12704L, 0x1.6d3da6102aee7852p+12704L }, - { 0xb.dd30144dd06980cp-11936L, -0x1.791cebbb198638bep-2520L, 0x4.4a9a2b2b484838b8p-2508L, 0x4.4a9a2b2b484838cp-2508L }, - { 0x2.0e8711d8p-16416L, -0x1.7bb6dd104adc4d0cp+2888L, 0x5.f1ba3150ca7f0828p+2900L, 0x5.f1ba3150ca7f083p+2900L }, - { 0x1.1d43bf5824a1e06cp+4368L, -0x3.6aff33a9a6024948p-7268L, -0x3.a522b04900fbdfp-7256L, -0x3.a522b04900fbdefcp-7256L }, - { 0x2.ea4f2a6ac862728cp+2680L, -0x6.3f1754e29b634308p+10700L, -0x4.16e20a83ab3a847p+10712L, -0x4.16e20a83ab3a8468p+10712L }, - { 0x6.dc2337c4dcfc9ba8p+9292L, 0x1.db67943b70f0e37ap+732L, 0x4.36cdc5c0cbf5c598p+744L, 0x4.36cdc5c0cbf5c5ap+744L }, - { 0x2.11d8eb885c371facp-3816L, 0x9.420077450c7ba7ep+3360L, -0x8.9f61fc96a86315ep+3372L, -0x8.9f61fc96a86315dp+3372L }, - { 0x2.80989ac0b86b7144p+7248L, -0x9.6b6d7f66e9adc62p-7280L, -0x1.0abe032023d3bc7ap-7264L, -0x1.0abe032023d3bc78p-7264L }, - { 0x4.9affaf38db31985p+9560L, -0x3.9fb0ce552022caep-9264L, -0x8.75b6e9f5bba47f3p-9252L, -0x8.75b6e9f5bba47f2p-9252L }, - { 0x1.79f10252e5d32328p-11808L, 0x3.5d72f3d2e9a1c1bp+832L, -0x9.b347207cf9028e7p+844L, -0x9.b347207cf9028e6p+844L }, - { 0x1.551248fac9273744p-604L, -0x4.acf1bc3134803b78p-7060L, 0xb.061ae47f2cbbf69p-7052L, 0xb.061ae47f2cbbf6ap-7052L }, - { 0x7.7cc2f48a5f0b8c2p-13612L, -0x7.4e46d17991c7841p+2360L, 0x1.8460e567b6746cbp+2376L, 0x1.8460e567b6746cb2p+2376L }, - { 0xa.371f3fbdd75e962p+3584L, -0x5.44ff275c91095f78p+5452L, -0x4.9d79ee220fd58108p+5464L, -0x4.9d79ee220fd581p+5464L }, - { 0x3.de6cea18p-16416L, -0x2.d768065c9b0efec8p-5176L, 0xb.62f62c4094f50b5p-5164L, 0xb.62f62c4094f50b6p-5164L }, - { 0x1.dd2afe046d25b216p+13800L, 0xb.fba33f67d3e9c4ep-11144L, 0x2.85ff9be480399d14p-11128L, 0x2.85ff9be480399d18p-11128L }, - { 0x1.1829747c59eaadeep+8880L, -0x2.d7c6fd57d4a80568p+13152L, -0x6.29d2526173e85b88p+13164L, -0x6.29d2526173e85b8p+13164L }, - { 0x9.479031be3e93809p+6644L, -0x5.470f8a96fe098158p+692L, -0x8.90935ba9e5537d9p+704L, -0x8.90935ba9e5537d8p+704L }, - { 0xb.e269d2411d00a65p-12500L, 0xe.dc859359b9e1993p-7060L, -0x2.d572984be4518698p-7044L, -0x2.d572984be4518694p-7044L }, - { 0x1.fc0c45d7d5b6944ep+14064L, -0x7.c373eda7898c0138p-6140L, -0x1.aa895e0c3e0a8064p-6124L, -0x1.aa895e0c3e0a8062p-6124L }, - { 0x3.19dfe4d95f04bf3cp+8788L, 0xe.56a26033db6ec8ep+3404L, 0x1.ec4d67591c6e716cp+3420L, 0x1.ec4d67591c6e716ep+3420L }, - { 0xe.80351557405b528p+5764L, -0xb.b6c59696ddc332cp-5844L, -0x1.07ec6a44e392920ap-5828L, -0x1.07ec6a44e3929208p-5828L }, - { 0x5.edc1370a9352152p-5912L, -0x6.cb8d5970de366248p-4448L, 0x9.cdb559965ad814fp-4436L, 0x9.cdb559965ad815p-4436L }, - { 0x3.311130840d33e9b8p+1248L, 0x4.619b478aa823bf98p+14140L, 0x1.5632ae7c6fddcc8ap+14152L, 0x1.5632ae7c6fddcc8cp+14152L }, - { 0xe.fb1fa7cc5c99a7bp+2644L, 0x6.215a6f280bbf23ap+13288L, 0x3.f686a6e27cbd46ccp+13300L, 0x3.f686a6e27cbd46dp+13300L }, - { 0x6.3a39de95ec46d4bp-8L, -0xe.1e6dc0d48239149p-11560L, 0x4.bb2407581006d8c8p-11556L, 0x4.bb2407581006d8dp-11556L }, - { 0x4.24ff70bcd18c18fp+10272L, 0x1.21f37f880ee736bap-11320L, 0x2.d749d1d167a36bd4p-11308L, 0x2.d749d1d167a36bd8p-11308L }, - { 0x7.390a0da36cdc0aap+7196L, -0xc.b4b337e7f289e73p+10324L, -0x1.654b9c3d455f6008p+10340L, -0x1.654b9c3d455f6006p+10340L }, - { 0x2.10284ca11e4b7564p-1160L, -0xf.507826a098b359bp+12828L, 0x4.554a03b8742e5ebp+12840L, 0x4.554a03b8742e5eb8p+12840L }, - { 0xe.136ea4a2bb31728p+4556L, 0x1.85282eebef8dacc8p+11900L, 0x1.b1393d4db800a8a2p+11912L, 0x1.b1393d4db800a8a4p+11912L }, - { 0x1.20284f808bcc88fap+9660L, -0x6.b85cbded358fc63p+12036L, -0xf.d95f13f31f24b66p+12048L, -0xf.d95f13f31f24b65p+12048L }, - { 0x7.f78dd33fc42fe6c8p+6952L, -0x6.6f2c0f935ec5eb78p+2808L, -0xa.ece48391f9f0029p+2820L, -0xa.ece48391f9f0028p+2820L }, - { 0xc.f8724b65692d26dp-11464L, 0xc.d8d86a52dace604p-11752L, -0x2.3f1f1bf4cf514d88p-11736L, -0x2.3f1f1bf4cf514d84p-11736L }, - { 0x2.d7b18b7d7e32001p-12508L, 0x6.2e48d04a8fa4117p+10856L, -0x1.2df41cd47c378c7p+10872L, -0x1.2df41cd47c378c6ep+10872L }, - { 0x3.ffb401ff0c4f759p+13256L, -0x1.4180a10c714422fap-1496L, -0x4.10a4f72213d46648p-1484L, -0x4.10a4f72213d4664p-1484L }, - { 0x2.b76b974e31a16b8p-11156L, -0x7.5d2f72fd85a96188p-4708L, 0x1.40de39cbf5a8e2bep-4692L, 0x1.40de39cbf5a8e2cp-4692L }, - { 0xa.a6e924d5c873e25p-4L, -0x2.8d7c8afc118c282p-3080L, 0x1.7f9010b25b95f5dp-3080L, 0x1.7f9010b25b95f5d2p-3080L }, - { 0x2.d9a4ff4e3c08fb64p+12248L, -0x1.52b21398d2eb239p-10876L, -0x3.f4e77a2ce1ec901p-10864L, -0x3.f4e77a2ce1ec900cp-10864L }, - { 0x3.aee0b2eba4ea93f4p-11752L, -0x3.a608c14af6727124p+9316L, 0xa.777250fbd0a127fp+9328L, 0xa.777250fbd0a128p+9328L }, - { 0x7.f6a14a5fad86d0ap+8552L, 0xb.3506e923aabefd2p-1124L, 0x1.7684faf5fb9185c8p-1108L, 0x1.7684faf5fb9185cap-1108L }, - { 0x5.3f76be96f999fc38p+7716L, 0x6.58c19d7142062018p-108L, 0xb.f5a59acc9015199p-96L, 0xb.f5a59acc901519ap-96L }, - { 0xf.aca3cd9099be9bep+1640L, 0x6.fc8dd636b71e3f1p-1800L, 0x2.cdda9cd629895304p-1788L, 0x2.cdda9cd629895308p-1788L }, - { 0x1.91d42e0b36883b3ep+4728L, -0x3.88c36c923b28995cp+1744L, -0x4.14825bb13e4b1f18p+1756L, -0x4.14825bb13e4b1f1p+1756L }, - { 0x1.bab5220de2d5268cp-11632L, -0x2.47c45a33bea715d4p+10592L, 0x6.79b1c761cb108088p+10604L, 0x6.79b1c761cb10809p+10604L }, - { 0x2.6e042d7870e54f5p+13852L, 0x8.62d7e11cf21a5ccp+8848L, 0x1.c5cf16cabe81f1a8p+8864L, 0x1.c5cf16cabe81f1aap+8864L }, - { 0x1.c98310f63362d2a6p+1284L, -0x5.78ce0504a9a6ecbp+12692L, -0x1.b767eb9220e28388p+12704L, -0x1.b767eb9220e28386p+12704L }, - { 0x3.608d17ea6d8d0a38p-1492L, -0xa.2155d2a64e7f091p+2336L, 0x3.af87ec9ef906c52p+2348L, 0x3.af87ec9ef906c524p+2348L }, - { 0x2.e6b808fp-16416L, -0x7.f3d928344c7b47c8p+5944L, 0x1.fde88cc384e52e2ep+5960L, 0x1.fde88cc384e52e3p+5960L }, - { 0x3.72e5835930c81eap-4344L, 0x1.b87e6990fe084aaap+9196L, -0x1.d2f8e4b2d0532fccp+9208L, -0x1.d2f8e4b2d0532fcap+9208L }, - { 0x1.0a1e398ca5cf0d14p-10272L, -0x1.e7e7659b06787af2p+9104L, 0x4.c790983fed5fc48p+9116L, 0x4.c790983fed5fc488p+9116L }, - { 0x9.7f447b066f4437ep-12952L, 0x5.3edda06af98605b8p+8176L, -0x1.095393f9b90e26f4p+8192L, -0x1.095393f9b90e26f2p+8192L }, - { 0x5.0884ee2ef216ceb8p-12232L, -0x4.b62cb06b0fc0e708p+1172L, 0xe.1158b1bcde399cap+1184L, 0xe.1158b1bcde399cbp+1184L }, - { 0x1.8778ce2f2d89ba82p+6300L, -0x5.a232f0b2fd82fd1p-9100L, -0x8.aa7115611ef092dp-9088L, -0x8.aa7115611ef092cp-9088L }, - { 0x5.24577f8a1d1b998p+4436L, -0x3.5a69e9684f3f2374p+624L, -0x3.a229f193a2b1b89p+636L, -0x3.a229f193a2b1b88cp+636L }, - { 0x3.e93bb773f849539cp-7916L, 0xe.fde691265bdaf28p-520L, -0x1.cf7596412dbee2fap-504L, -0x1.cf7596412dbee2f8p-504L }, - { 0x3.665e1565d0b924cp+5944L, -0x4.16982d7fcb64e9dp-7880L, -0x5.ef3d51e83c4fcfdp-7868L, -0x5.ef3d51e83c4fcfc8p-7868L }, - { 0x3.fafa5900bf81a534p-6252L, 0xb.17cc0862a59adb9p+5632L, -0x1.0ed30f6930eee0ecp+5648L, -0x1.0ed30f6930eee0eap+5648L }, - { 0x8.78bf4985ee30992p-172L, 0x1.0199abbdde89b38cp-3592L, -0xa.9f92837c78e2a71p-3588L, -0xa.9f92837c78e2a7p-3588L }, - { 0x5.1e6faf18p-16416L, 0x4.f5a6b38aa882c1d8p+7064L, -0x1.3dfcb2a38d27ad42p+7080L, -0x1.3dfcb2a38d27ad4p+7080L }, - { 0x5.5ff127fa305d256p-2732L, 0x1.0506d4431b0e8b1ep-11852L, -0xa.df2b936c1b35f1p-11844L, -0xa.df2b936c1b35f0fp-11844L }, - { 0x1.0ad7b52e9d45bd8ep-1620L, -0xa.7ba4137b5209863p-3448L, 0x4.255c9b0e196d188p-3436L, 0x4.255c9b0e196d1888p-3436L }, - { 0x6.80d745f6314c29dp+14384L, -0xb.e3f21267bbdc57fp-676L, -0x2.9c37cf9ff975118p-660L, -0x2.9c37cf9ff975117cp-660L }, - { 0x3.6676a0eb13ce909cp-10052L, 0xe.072b868a1df7877p-3024L, -0x2.26b8c4584e8e6188p-3008L, -0x2.26b8c4584e8e6184p-3008L }, - { 0x6.5df497b7697155a8p+12256L, -0x1.eedd42b14d9a1374p-13580L, -0x5.c90ca70b1a73cdap-13568L, -0x5.c90ca70b1a73cd98p-13568L }, - { 0x1.1d82e518260f0294p+6512L, -0x9.191d1ec32fdf37bp-144L, -0xe.770435b3120105cp-132L, -0xe.770435b3120105bp-132L }, - { 0xd.529973ed01b4e92p+968L, 0x6.ce2581b071a031dp-9196L, 0x1.9d4ea26451941dap-9184L, 0x1.9d4ea26451941da2p-9184L }, - { 0x1.83f16f4f0984ca08p-6872L, -0x5.338c1e2e6f3d2b3p+5908L, 0x8.b9c9ac256e9a086p+5920L, 0x8.b9c9ac256e9a087p+5920L }, - { 0x1.867d77867b5c95eap+2628L, 0x7.3398eb375f75dfb8p-9260L, 0x4.9f210d1f21e1aa2p-9248L, 0x4.9f210d1f21e1aa28p-9248L }, - { 0x1.cd985a87e976e13cp+3076L, -0x1.45dc8a1f648e67c6p-7864L, -0xf.4c830f7af568de8p-7856L, -0xf.4c830f7af568de7p-7856L }, - { 0x1.4a4d37ap-16416L, 0x1.4e33cb5b10e313f4p+10756L, -0x5.3b63e726e0a641f8p+10768L, -0x5.3b63e726e0a641fp+10768L }, - { 0x1.3482020ad3c0a882p-816L, -0x9.872caa0b23c65a8p-5864L, 0x1.e5c4dd4b25b6778cp-5852L, 0x1.e5c4dd4b25b6778ep-5852L }, - { 0x1.0e8ff00081bc371cp-6176L, 0x1.cf4067f2e44a798ep-120L, -0x2.ba7ccd219acfff4p-108L, -0x2.ba7ccd219acfff3cp-108L }, - { 0x7.a6f445256a7fda78p+4636L, -0x6.6c725b49451ea01p+4828L, -0x7.466c2cdfef5e2efp+4840L, -0x7.466c2cdfef5e2ee8p+4840L }, - { 0x1.1a2d2bcf0843d15ep-8644L, 0x6.b3ca3aa6fe517d3p+8440L, -0xe.24dc76733d14932p+8452L, -0xe.24dc76733d14931p+8452L }, - { 0x1.7eca655a01c636c2p+52L, -0x1.dd3c2732d945f4d4p+6296L, -0x6.2053619ae4b322p+6300L, -0x6.2053619ae4b321f8p+6300L }, - { 0x1.9faf5dbf7986dc42p-412L, 0x5.54b138d415c78598p-7720L, -0x8.9092d2bfa96a01p-7712L, -0x8.9092d2bfa96a00fp-7712L }, - { 0xe.bf3d1b364fa7d78p+6240L, 0xb.c74bfc158951011p+408L, 0x1.1f4796923b917cb8p+424L, 0x1.1f4796923b917cbap+424L }, - { 0x7.2ca230e9bfee2468p+9888L, -0x3.6eb3366a69620d54p-11960L, -0x8.49d8c188f6ff293p-11948L, -0x8.49d8c188f6ff292p-11948L }, - { 0x6.c33f156ecd7b9018p-5056L, -0xa.5597ddf352c5401p+6116L, 0xc.bfdf7e5c155895dp+6128L, 0xc.bfdf7e5c155895ep+6128L }, - { 0xc.894ea5b54605326p+8424L, -0x3.29d764acd5dcadc4p+1548L, -0x6.824621f901eaa6bp+1560L, -0x6.824621f901eaa6a8p+1560L }, - { 0x4.dc0e408p-16420L, 0x2.f294ae2e03276788p-14272L, -0xb.d088f60ec237848p-14260L, -0xb.d088f60ec237847p-14260L }, - { 0x1.8d8d6c474b777c26p-6764L, 0x2.82a240469d5e47c8p+912L, -0x4.251fee784a74545p+924L, -0x4.251fee784a745448p+924L }, - { 0x3.320003e916e2c018p-11548L, 0x2.0fc01824588015bp-9448L, -0x5.cfb08c45bb157868p-9436L, -0x5.cfb08c45bb15786p-9436L }, - { 0x2.766f084c0c4d4becp-4344L, -0xf.918a628430c9869p+3260L, 0x1.08196636d42693dp+3276L, 0x1.08196636d42693d2p+3276L }, - { 0x1.a7ea62a617983f7cp+4280L, 0x4.31f5016cb7a06488p-11684L, 0x4.62645a22f39bbd8p-11672L, 0x4.62645a22f39bbd88p-11672L }, - { 0x3.e2845c867de93e5p+4116L, -0x4.d4440dbc662de6f8p+9256L, -0x4.dae4a99df679d47p+9268L, -0x4.dae4a99df679d468p+9268L }, - { 0x6.eab30da02cc2a598p+9760L, 0x1.2c806e5e622e351cp+504L, 0x2.cc3e6de19ba004fcp+516L, 0x2.cc3e6de19ba005p+516L }, - { 0xa.b66e1024516b719p+6312L, -0x2.77acf612cccf4c7p-4604L, -0x3.cdf31b042afc3218p-4592L, -0x3.cdf31b042afc3214p-4592L }, - { 0x1.114b9705d7e2df02p+14968L, -0x1.5d185f94b66e1fdep+11700L, -0x4.fbb4a016d14170f8p+11712L, -0x4.fbb4a016d14170fp+11712L }, - { 0x6.05221386e27406ep+7108L, -0xa.ea5ec6727dbced3p+5124L, -0x1.2f2fb448d3bf0a6ap+5140L, -0x1.2f2fb448d3bf0a68p+5140L }, - { 0xe.ede20bdb2751c04p-4992L, -0x2.63ffa25342447e7cp-14816L, 0x2.e94a60754ec70b58p-14804L, 0x2.e94a60754ec70b5cp-14804L }, - { 0xb.1a3a6ap-16420L, 0x7.4ddb04c8953c689p-224L, -0x1.d46456593d727256p-208L, -0x1.d46456593d727254p-208L }, - { 0x3.6fa725b26802fc1p+3976L, -0x6.a2e23061803132b8p+9584L, -0x6.71d9a5a82683f7f8p+9596L, -0x6.71d9a5a82683f7fp+9596L }, - { 0x3.1bc6c41d7b8d2494p+12084L, 0x1.7b90e0d7a41add8ap-9760L, 0x4.5ff1fc2dc73c17a8p-9748L, 0x4.5ff1fc2dc73c17bp-9748L }, - { 0xf.4bf5dfe195d4e46p-10012L, 0xe.ef03e3c1cc87ddfp-14124L, -0x2.47d0f7fb93db53b8p-14108L, -0x2.47d0f7fb93db53b4p-14108L }, - { 0x5.ddca9397064452p-10792L, 0xf.f4db22808a890c7p+4992L, -0x2.a0817b6ef96e117cp+5008L, -0x2.a0817b6ef96e1178p+5008L }, - { 0x2.3bf4fe007d9b6508p-4292L, 0xf.5b06933a4845034p+6108L, -0x1.01604b2d99b21d0cp+6124L, -0x1.01604b2d99b21d0ap+6124L }, - { 0x1.13b11c9cdbbfb39cp+324L, -0x8.3f36b704651a623p+3780L, -0xa.70e2f6da63903a9p+3788L, -0xa.70e2f6da63903a8p+3788L }, - { 0x3.debb4f1fb4f3d46cp+1624L, 0x4.46c390ab2d99867p+10104L, 0x1.b2941faa9cc9d50ep+10116L, 0x1.b2941faa9cc9d51p+10116L }, - { 0x6.c1201301bf4c9218p+6756L, -0x2.4d6a37f3ed5852fcp+2216L, -0x3.cc95f7fec27acff4p+2228L, -0x3.cc95f7fec27acffp+2228L }, - { 0x1.7499fce7028b5718p-1560L, -0x3.4a630b8e2e554824p+12228L, 0x1.40b836996da41882p+12240L, 0x1.40b836996da41884p+12240L }, - { 0x2.5cdec5c3c9cd305cp-2792L, -0x4.df8c690724ffac2p-10720L, 0x3.52007c9cd5f5bcecp-10708L, 0x3.52007c9cd5f5bcfp-10708L }, - { 0xd.563eae6fd0c7a55p-4L, 0xf.407ea5dcda35ceep+14612L, -0x4.01832b7b29c949a8p+14612L, -0x4.01832b7b29c949ap+14612L }, - { 0x2.88537585e08a0db8p+8480L, -0x2.d1b1e77a78c0add8p-11944L, -0x5.d65ec904e91d1dap-11932L, -0x5.d65ec904e91d1d98p-11932L }, - { 0x1.903cbb912f0bd304p-6664L, 0x1.f043925d5bfa9a4p-6948L, -0x3.2751f0797c3c2104p-6936L, -0x3.2751f0797c3c21p-6936L }, - { 0x1.2d980aa61aaa044ap-5788L, -0x7.5c4c52f7a6d1f848p+3612L, 0xa.6691012806f86e1p+3624L, 0xa.6691012806f86e2p+3624L }, - { 0x3.df18660f37583684p+12996L, 0xa.9226fd0725f5548p-9324L, 0x2.18b8280f88377528p-9308L, 0x2.18b8280f8837752cp-9308L }, - { 0xa.bb09710051dcf8dp-6364L, -0x3.a3b7749ef082dccp+6000L, 0x5.a6d6eb577c61432p+6012L, 0x5.a6d6eb577c614328p+6012L }, - { 0x9.f86536a0190222p-8972L, 0x2.834c95d589ef3c24p-7364L, -0x5.80949d7b13ce07bp-7352L, -0x5.80949d7b13ce07a8p-7352L }, - { 0xf.095b5efb520e98cp-14876L, -0x4.925b19d467927c58p-9252L, 0x1.0996c5412e3615b4p-9236L, 0x1.0996c5412e3615b6p-9236L }, - { 0x1.dad1ee8a661ae87ap+5708L, 0x1.fe352d18c29a58f6p+10544L, 0x2.c71d060d0cef0e34p+10556L, 0x2.c71d060d0cef0e38p+10556L }, - { 0xf.c50d2b0b4759078p+2820L, 0xf.297abc86e6d6ca4p-7248L, 0xa.74140c28fb060b3p-7236L, 0xa.74140c28fb060b4p-7236L }, - { 0x7.0453d1280723b998p-8932L, -0x8.aaf24f9f3a0b99cp-4004L, 0x1.2e54114a95896f2ep-3988L, 0x1.2e54114a95896f3p-3988L }, - { 0x4.4cfc31fp-16416L, 0xb.0d9092f80bfd229p-10520L, -0x2.c4ae93c54ad8e124p-10504L, -0x2.c4ae93c54ad8e12p-10504L }, - { 0xf.a206d4e1105d091p-8016L, -0x2.d55598a73912513p+4172L, 0x5.8accb2f3cc70fd8p+4184L, 0x5.8accb2f3cc70fd88p+4184L }, - { 0x8.2ee1b7d5eb1d0c3p-6348L, -0x7.c8f8d0eff8137ff8p+13384L, 0xc.0f3dddeec691ed5p+13396L, 0xc.0f3dddeec691ed6p+13396L }, - { 0x3.b1a407914e578be8p+8968L, -0x1.7e3c9a467164bd2p-12264L, -0x3.4510b8f20a060848p-12252L, -0x3.4510b8f20a060844p-12252L }, - { 0x3.a757d9b6a00a4ba8p-1900L, -0x7.177fa6a92ce714d8p-3624L, 0x3.495259a9dfb60448p-3612L, 0x3.495259a9dfb6044cp-3612L }, - { 0x3.be5e8801d352664p+6012L, -0x3.a12c079f54735f34p+8764L, -0x5.543ef8fe17f7f85p+8776L, -0x5.543ef8fe17f7f848p+8776L }, - { 0x2.2d8852e645dca22p+9040L, 0x2.ffff06be9f08f6acp-14752L, 0x6.9f33c0295b347e1p-14740L, 0x6.9f33c0295b347e18p-14740L }, - { 0x1.03322ae66aef91c2p-720L, -0x6.ff7e97b99adce708p+5956L, 0x1.3ae73f9a1237c138p+5968L, 0x1.3ae73f9a1237c13ap+5968L }, - { 0xd.9ec53ffbb90281cp-544L, 0x4.4c329e6a78ac8bcp+132L, -0x9.11ba60714038acbp+140L, -0x9.11ba60714038acap+140L }, - { 0x7.536fe5affbc375ep+3920L, 0x3.1222fe8be3486f6p+6204L, 0x2.f0e8a6e185c7e7bcp+6216L, 0x2.f0e8a6e185c7e7cp+6216L }, - { 0x8.15c1c9e9c82d888p+14352L, 0x1.d25ed81d571b76b2p-4888L, 0x6.627636ca6db9ff78p-4876L, 0x6.627636ca6db9ff8p-4876L }, - { 0x1.06142a4caeedca5p+0L, 0x3.0b886441145c1bf8p+8452L, 0x1.a6473f7721100534p+8448L, 0x1.a6473f7721100536p+8448L }, - { 0xa.022610dbd7d5487p-4260L, 0x1.f8669248dbba890cp-12896L, -0x2.0c2fea8c9a403c08p-12884L, -0x2.0c2fea8c9a403c04p-12884L }, - { 0x1.427e698110e4f9cep+12256L, -0xa.ceffd4a7d89dae6p-12572L, -0x2.0579b1a86fbaa90cp-12556L, -0x2.0579b1a86fbaa908p-12556L }, - { 0x6.98bfa5fdcdd697bp+4448L, -0x2.ae37715f3487a328p+6884L, -0x2.e9a4f05a20a95cc4p+6896L, -0x2.e9a4f05a20a95ccp+6896L }, - { 0x5.471706d1fef36668p+11296L, 0x2.60481b44518620e4p-2100L, 0x6.8de218514d390dbp-2088L, 0x6.8de218514d390db8p-2088L }, - { 0x1.c9dc47831fc622dap+8488L, 0x2.277891fbbfd0636p-8056L, 0x4.76e84361d1c36df8p-8044L, 0x4.76e84361d1c36ep-8044L }, - { 0x2.7aa75062a08bbeap-12220L, 0x1.855b35dcfe02fd7cp+12580L, -0x4.897afe1ff40bdd3p+12592L, -0x4.897afe1ff40bdd28p+12592L }, - { 0x4.b2b1830d66fb0c98p-13732L, 0x5.23b229f58bca7ba8p-2960L, -0x1.13a3481ea7e7e5f4p-2944L, -0x1.13a3481ea7e7e5f2p-2944L }, - { 0x8.d08fe057a50127ap-1140L, -0xb.6ba4e2f724db45bp-7688L, 0x3.2b77e4777e7a7954p-7676L, 0x3.2b77e4777e7a7958p-7676L }, - { 0x1.662b22f1dd79fc5ap-1184L, -0x9.5692b3519c8755ap-8328L, 0x2.b2be0450fbef222p-8316L, 0x2.b2be0450fbef2224p-8316L }, - { 0x1.82d56f808fae1b4p+3252L, 0xa.fe2e145fc22e872p+10868L, 0x8.bab6d6535a848adp+10880L, 0x8.bab6d6535a848aep+10880L }, - { 0x6.76cfc11e7b6566b8p-4L, 0x5.449f7a84db9971ap-8384L, -0x6.e363ec6143f817cp-8384L, -0x6.e363ec6143f817b8p-8384L }, - { 0x8.6314a48e9f5cf1bp+14264L, 0x1.02a4a8db28694176p-11124L, 0x3.84e602f86fc958e4p-11112L, 0x3.84e602f86fc958e8p-11112L }, - { 0xb.a215b32c0ab2fb5p-8296L, 0x3.b121832e8103529p+14676L, -0x7.7971416c1af6341p+14688L, -0x7.7971416c1af63408p+14688L }, - { 0x3.dda3552b2cfcb6dp-6772L, 0x7.eae66ccf86eba1b8p-12672L, -0xd.1626578ff235625p-12660L, -0xd.1626578ff235624p-12660L }, - { 0x3.d1bdac6c27a4987cp-11480L, -0xb.f0201fb3fdf4fdap+10816L, 0x2.17410c1ecf9c6a04p+10832L, 0x2.17410c1ecf9c6a08p+10832L }, - { 0x1.753b55139a6ae0d4p-9588L, -0xc.b94fdca214abb5bp-10048L, 0x1.dc8597552b0e5e98p-10032L, 0x1.dc8597552b0e5e9ap-10032L }, - { 0x7.49cfb50979428ccp+13260L, 0x6.d1ca9e09ccdfe48p-8776L, 0x1.614e15a9b7619142p-8760L, 0x1.614e15a9b7619144p-8760L }, - { 0x2.fdb3fd975c2fcc24p-8752L, -0x6.dcfc60eadb01717p+11444L, 0xe.a981b074aac6ebep+11456L, 0xe.a981b074aac6ebfp+11456L }, - { 0x5.461b7b2ee09e674p-3212L, 0x2.75ad884b4a7c987cp+1616L, -0x1.ed696c80266e3dc4p+1628L, -0x1.ed696c80266e3dc2p+1628L }, - { 0x3.fe2313c91b361a94p-11200L, -0xe.dc38443676c5a64p-10132L, 0x2.8a04ef36438bec6p-10116L, 0x2.8a04ef36438bec64p-10116L }, - { 0x7.3bc9614f8e5128c8p+4260L, 0x4.1330a0a05f33682p+14436L, 0x4.3daf7300edde6ddp+14448L, 0x4.3daf7300edde6dd8p+14448L }, - { 0x8.bd152439e522049p-4L, 0xb.92113f16dc8ef45p+13704L, -0xa.18b112a71a99ff9p+13704L, -0xa.18b112a71a99ff8p+13704L }, - { 0x2.19a9a6a149d64b2cp+7252L, 0x1.465d05fbac7ff242p-3232L, 0x2.41ea09187aa26998p-3220L, 0x2.41ea09187aa2699cp-3220L }, - { 0x1.2dfa170de378162p+1848L, 0x6.e3ccc6f233fe54p+11352L, 0x3.1be1289e5ccdfe38p+11364L, 0x3.1be1289e5ccdfe3cp+11364L }, - { 0x2.45ae50f119d75d4cp+9348L, 0x2.48cb633ccf171d88p-8776L, 0x5.36cd745dea71ace8p-8764L, 0x5.36cd745dea71acfp-8764L }, - { 0x3.ffc0ede5facf9aap+144L, -0x1.639d563ebd47e19cp-3360L, -0xc.acf9b954dff786p-3356L, -0xc.acf9b954dff785fp-3356L }, - { 0x1.320a4fa8c7689a5cp+12176L, -0x3.c102f99e035bd4c4p-5096L, -0xb.28d15096dbe0335p-5084L, -0xb.28d15096dbe0334p-5084L }, - { 0x1.06fdec9589c7e3cap-11048L, 0x1.37fe7627faad46a8p+7504L, -0x3.498717a4095b29a8p+7516L, -0x3.498717a4095b29a4p+7516L }, - { 0x3.49a93629ad7fc314p-3304L, -0x6.c1900e2ee2255dfp-10704L, 0x5.72691640c0fb8b8p-10692L, 0x5.72691640c0fb8b88p-10692L }, - { 0x7.3784858026f59eb8p-12536L, 0x1.9512838f9ba32ffap-6896L, -0x4.d775f974a9b756dp-6884L, -0x4.d775f974a9b756c8p-6884L }, - { 0x1.80ea0336ba35c6a6p+10468L, 0x3.c200d3a7e961c3dcp-11276L, 0x9.9ab1fd7e38b6ddp-11264L, 0x9.9ab1fd7e38b6dd1p-11264L }, - { 0x5.aa69355ef02ac868p-13564L, 0x1.76a1cac98f2db2cep+8268L, -0x4.d85fb08ac5441228p+8280L, -0x4.d85fb08ac544122p+8280L }, - { 0x1.b089a658p-16416L, 0x1.ea990a7a7c9093b4p+524L, -0x7.ae22285ee60e2328p+536L, -0x7.ae22285ee60e232p+536L }, - { 0x5.5307153542305dp+5812L, -0xf.a0fa3c8f422f914p-12628L, -0x1.62f865e81f9e158p-12612L, -0x1.62f865e81f9e157ep-12612L }, - { 0x3.d18c9f1fe178b66cp-5976L, 0x3.07dccc28a2dbb64cp-11924L, -0x4.6b9ae7abba0f89dp-11912L, -0x4.6b9ae7abba0f89c8p-11912L }, - { 0xb.a85358c13ac490ep+8052L, -0x1.581f0dbe008f95a6p+3224L, -0x2.a4c7405adef4cb88p+3236L, -0x2.a4c7405adef4cb84p+3236L }, - { 0x5.23afe2a0b74d62p+3396L, 0xf.eaf45db22aa5f58p+400L, 0xd.34e691543edfc8fp+412L, 0xd.34e691543edfc9p+412L }, - { 0xf.bbc8e9388c45f3ap+4960L, 0xd.adbde37244f6cd2p+4352L, 0x1.093ca1363e18977cp+4368L, 0x1.093ca1363e18977ep+4368L }, - { 0xd.0ec84ab52b6bccfp-14316L, 0x3.242368e52518021p-7596L, -0xa.f9d475f53e8f64cp-7584L, -0xa.f9d475f53e8f64bp-7584L }, - { 0xe.6fcb560f3434363p+6672L, -0x2.582d5ceb82c13698p+1228L, -0x3.d2325f4c49e3efp+1240L, -0x3.d2325f4c49e3eefcp+1240L }, - { 0x2.c32af39bbff96d5cp-14764L, 0x3.ac0794141c17ee54p+3048L, -0xd.3bfe31094bba577p+3060L, -0xd.3bfe31094bba576p+3060L }, - { 0x2.1cd826493af5d3a4p-6760L, -0x6.ae408d4f2bfec03p+4488L, 0xb.062231847cd3d58p+4500L, 0xb.062231847cd3d59p+4500L }, - { 0x8.ca91adedeaa1e77p+6300L, 0xf.acd7dd8fa7e0887p-14224L, 0x1.81f2b8e35ed12114p-14208L, 0x1.81f2b8e35ed12116p-14208L }, - { 0x3.3ff778d9323b9c5p-4L, -0xd.c2058e770c939ap+12944L, 0x1.fa34dff1e1c4bc78p+12948L, 0x1.fa34dff1e1c4bc7ap+12948L }, - { 0x1.31637c3000e438e4p+11384L, -0x4.686ea46458512aep-1676L, -0xc.405174ea19fdec5p-1664L, -0xc.405174ea19fdec4p-1664L }, - { 0xd.d9373849cbb5adbp-8496L, -0x4.f30da52b4bc6c1bp-8616L, 0xa.42f909e0e6d629dp-8604L, 0xa.42f909e0e6d629ep-8604L }, - { 0x2.aaaaea743fb846c4p-10376L, -0x8.2ff53eaf90ae7cp-13868L, 0x1.4bcc3637b01b0c72p-13852L, 0x1.4bcc3637b01b0c74p-13852L }, - { 0x8.f919db6c7b9f466p-2356L, -0x6.a312fd5cbddcec78p+12452L, 0x3.cffc82d80b2c68e4p+12464L, 0x3.cffc82d80b2c68e8p+12464L }, - { 0x1.5ef60b9d2b73390ap-1820L, 0x3.6efa517d1c5d3a28p+13140L, -0x1.8676b8655aad1cd6p+13152L, -0x1.8676b8655aad1cd4p+13152L }, - { 0x3.daffca7fb01f62b4p-14284L, -0xf.6af4c77adde2767p+11168L, 0x3.5c25cd91022ff884p+11184L, 0x3.5c25cd91022ff888p+11184L }, - { 0x3.43d37022ccb92268p+5012L, 0x7.e9ab5b70fd0bde88p+11408L, 0x9.af850ca0012c747p+11420L, 0x9.af850ca0012c748p+11420L }, - { 0x2.435d3715a985bcb8p+10736L, 0x3.aacc5c1e9457eadp-10348L, 0x9.9cf2c8d41a4e1ddp-10336L, 0x9.9cf2c8d41a4e1dep-10336L }, - { 0x6.db3d1c3421345d9p+9732L, -0x4.36066072222de638p-12688L, -0xa.0217c93e79fcf29p-12676L, -0xa.0217c93e79fcf28p-12676L }, - { 0x3.08ae8e74c266a098p-5748L, 0xe.770635edbd5eaf3p-13844L, -0x1.44b14e3d8e36c586p-13828L, -0x1.44b14e3d8e36c584p-13828L }, - { 0x1.76212ep-16420L, 0x1.3ab2fe378fa08002p+12544L, -0x4.ed85475e9e6609c8p+12556L, -0x4.ed85475e9e6609cp+12556L }, - { 0x1.fd551ae8610d128p+7480L, 0x3.769a9f2eaaf3700cp-10948L, 0x6.534e5c73be7354ap-10936L, 0x6.534e5c73be7354a8p-10936L }, - { 0xa.e0aac49fb82b00bp-7972L, 0x1.6fd07eaba5d3fd5ep+32L, -0x2.cb9062aca3ea933cp+44L, -0x2.cb9062aca3ea9338p+44L }, - { 0xa.1cb34dbd6cd395fp-1656L, 0x7.4ee3c5874237b978p+12680L, -0x2.f2dec58363c34d3cp+12692L, -0x2.f2dec58363c34d38p+12692L }, - { 0xb.9b50fe352d3c1b1p+364L, -0x8.db835f5f3c3aa14p+2212L, -0xc.b772bb6b1a9a731p+2220L, -0xc.b772bb6b1a9a73p+2220L }, - { 0x3.6d33ead8abf8a548p-13856L, -0x1.c02ccce5ca28e9c4p+2936L, 0x5.ebe5c84acb3e408p+2948L, 0x5.ebe5c84acb3e4088p+2948L }, - { 0x3.0af6574b42ede154p-11844L, 0x1.1478f312ab1800b6p-700L, -0x3.1f56ff3ec7659148p-688L, -0x3.1f56ff3ec7659144p-688L }, - { 0x1.623ac0a3f7aba0bep+8220L, -0x1.4bcc58434b1bb7aap-4960L, -0x2.99e70d80ff093388p-4948L, -0x2.99e70d80ff093384p-4948L }, - { 0x2.745f807c070fa178p-12228L, 0x1.0bdeb66d4a421602p-10224L, -0x3.1f99efcbce646dfcp-10212L, -0x3.1f99efcbce646df8p-10212L }, - { 0x1.d791a56eee5e72cp+4460L, 0xe.eeae1eb0781a412p+5380L, 0x1.04336a8490f4dae4p+5396L, 0x1.04336a8490f4dae6p+5396L }, - { 0x1.005eedfe61628706p-10904L, -0x7.0f25c96d65a172ap+7888L, 0x1.2cad2db5759ce0b4p+7904L, 0x1.2cad2db5759ce0b6p+7904L }, - { 0x8.48b67c8ab19d09dp-4L, -0x1.f888e4fc233d27dcp+6724L, 0x1.df23c41e1919f418p+6724L, 0x1.df23c41e1919f41ap+6724L }, - { 0xc.ae4e6ad45a50465p+4112L, -0x2.518b484925a2b1cp+13764L, -0x2.5464c5094de3f82p+13776L, -0x2.5464c5094de3f81cp+13776L }, - { 0x1.9c18d7876ee7376ep-14044L, 0x1.23d29c845c03c0dap+3464L, -0x3.e886d92ea80a7d1p+3476L, -0x3.e886d92ea80a7d0cp+3476L }, - { 0x2.89d5cb60a9e9af5cp-4744L, -0xd.158a1c32534c8bbp-4820L, 0xf.26591cea3a34904p-4808L, 0xf.26591cea3a34905p-4808L }, - { 0xc.4033377961e2fe8p+9052L, -0x5.b388ee53b605e2b8p-3668L, -0xc.9acd9b90883283fp-3656L, -0xc.9acd9b90883283ep-3656L }, - { 0x1.d50869ea25276784p-10972L, 0x4.d1c12faa90b5e068p-508L, -0xc.e89be19644230e7p-496L, -0xc.e89be19644230e6p-496L }, - { 0x9.febbb7fe5ed6546p-4588L, 0xb.099054e905162d5p-7288L, -0xc.5aabe646430f123p-7276L, -0xc.5aabe646430f122p-7276L }, - { 0x2.9d9c43b7825d326p+12808L, -0x2.ada1ee9ab68cb0fp-4512L, -0x8.602c4c1dc8b3b28p-4500L, -0x8.602c4c1dc8b3b27p-4500L }, - { 0x4.7c5bc0f7776b0ac8p+2520L, -0x3.0a1b28d67b2747b8p-8696L, -0x1.df2103aaf6513a14p-8684L, -0x1.df2103aaf6513a12p-8684L }, - { 0x1.2f7388d95a11e1bep-6608L, 0x5.19ffda1dd0d9c2a8p-4600L, -0x8.3addbca737209aap-4588L, -0x8.3addbca737209a9p-4588L }, - { 0x7.3e70e5fcf433aa28p-11840L, 0x1.d0de4ba9a67c312ap+3816L, -0x5.3f6f925f1b5ac89p+3828L, -0x5.3f6f925f1b5ac888p+3828L }, - { 0x7.d5521358p-16416L, 0xa.6edd69b6078e966p-7072L, -0x2.9ce63aa876c852a4p-7056L, -0x2.9ce63aa876c852ap-7056L }, - { 0x1.a06b478721ce054ep+13548L, -0x1.393c0e863c65bdb8p-6108L, -0x4.0c1d22c0912dc55p-6096L, -0x4.0c1d22c0912dc548p-6096L }, - { 0x3.b69179fa44654bbcp+1440L, -0x6.e4159565f7c389f8p+10500L, -0x2.6d004320fc3ff95cp+10512L, -0x2.6d004320fc3ff958p+10512L }, - { 0x2.5ad010f8b9d60f14p+12900L, 0xb.828c126f8807123p+10908L, 0x2.440c92f86267255p+10924L, 0x2.440c92f862672554p+10924L }, - { 0x9.98a3919087bcbddp+12296L, -0xb.6ce393db0528821p+14940L, -0x2.24eb593295e856b8p+14956L, -0x2.24eb593295e856b4p+14956L }, - { 0xb.5517b51c0f4d664p-4000L, 0x1.d4234882ba64610ep-4640L, -0x1.c8c3fb42f463b05p-4628L, -0x1.c8c3fb42f463b04ep-4628L }, - { 0x8.5bd2dd7bb1477a4p-3904L, -0x1.12e3d6e3b466d59ap-476L, 0x1.05cc87caeb220ccep-464L, 0x1.05cc87caeb220cdp-464L }, - { 0x5.ed808c966d066e28p+7324L, -0x2.00368397327e3fccp-12952L, -0x3.9433ab5ccc8a19ccp-12940L, -0x3.9433ab5ccc8a19c8p-12940L }, - { 0x4.b40d71fc6217c0ap+8936L, -0x5.e9dcc5f1571235p+1792L, -0xc.e7877da64a564eep+1804L, -0xc.e7877da64a564edp+1804L }, - { 0x1.34407e864341f828p+3440L, -0x5.1b8cadf3b9cef08p+11308L, -0x4.4a390c27f8641c38p+11320L, -0x4.4a390c27f8641c3p+11320L }, - { 0x8.179975b3956adafp-10324L, 0x1.dd7c8a838a11dd72p-4000L, -0x4.b328227e31522ce8p-3988L, -0x4.b328227e31522cep-3988L }, - { 0x1.01fdcep-16416L, 0xb.a372ba15d4c940dp-5452L, -0x2.ea50fb8dd4efd0cp-5436L, -0x2.ea50fb8dd4efd0bcp-5436L }, - { 0x5.3b665bec0d2e2dcp-2800L, -0x1.f45e190fe1072f02p-12656L, 0x1.55c1aa1fbb13f3f6p-12644L, 0x1.55c1aa1fbb13f3f8p-12644L }, - { 0x8.992f6f29de9baa1p-6444L, 0x2.6df885a56ac520b8p-14752L, -0x3.d20a120e0c03b828p-14740L, -0x3.d20a120e0c03b824p-14740L }, - { 0xc.c702ea51f29dd29p+1248L, 0x1.8a572c70170d4e5cp+12552L, 0x7.881260ccbcf27268p+12560L, 0x7.881260ccbcf2727p+12560L }, - { 0x7.7da787b409a377c8p-6564L, 0x9.7e0cf04e7e0519bp-6448L, -0xf.348702698a255aep-6436L, -0xf.348702698a255adp-6436L }, - { 0x7.e356b90a1e983p+6044L, -0x1.595f87983b91e67ap+11008L, -0x1.fde107e29925392cp+11020L, -0x1.fde107e29925392ap+11020L }, - { 0x6.68cb8626a1a7bd2p-856L, -0x5.2867609201d772p+3332L, 0x1.13146bfa618ef4acp+3344L, 0x1.13146bfa618ef4aep+3344L }, - { 0x1.d9c129761350a49ep-1456L, -0x1.29e3078444080f32p-2724L, 0x6.9d32b50a997a3358p-2716L, 0x6.9d32b50a997a336p-2716L }, - { 0x7.d308bb4487d45ed8p+8360L, 0x3.05fa312cc9b12db8p-7928L, 0x6.2c42b7a54e1f43p-7916L, 0x6.2c42b7a54e1f4308p-7916L }, - { 0xb.1557c6f908f40bfp+13336L, 0x1.7c6eeead727f952ep-3248L, 0x4.d6f5b1bc630d822p-3236L, 0x4.d6f5b1bc630d8228p-3236L }, - { 0x2.aa3fe22d8b80d434p-3748L, -0x2.bbf4a7d991feb2d4p-864L, 0x2.803ec10c3efa22f4p-852L, 0x2.803ec10c3efa22f8p-852L }, - { 0x5.4ec5032p-16416L, -0x2.6748c73e3720dc58p+11340L, 0x9.a195140488f7b6fp+11352L, 0x9.a195140488f7b7p+11352L }, - { 0x1.97e6fba1fa77cd84p+776L, 0x1.0fd2d35c90316ae6p-10104L, 0x3.38adc0961147ee3cp-10096L, 0x3.38adc0961147ee4p-10096L }, - { 0xa.ff44e18825e4262p-3300L, -0x3.a9ba576b1d83aeep+6148L, 0x2.f2b3a675e3dd0e28p+6160L, 0x2.f2b3a675e3dd0e2cp+6160L }, - { 0x7.8af9d275e91fced8p-7428L, 0x1.4317fd2efba13bf6p-9056L, -0x2.49b16335dd4b114cp-9044L, -0x2.49b16335dd4b1148p-9044L }, - { 0x7.9c3ee1462407ec68p+5156L, -0x3.e97de45eb74e97b4p+11988L, -0x4.ed61fdf674171e78p+12000L, -0x4.ed61fdf674171e7p+12000L }, - { 0x1.47be5e7291ef5b5ep+8620L, 0x1.b6bb4b3df23a952p-3860L, 0x3.9b586e9657351918p-3848L, 0x3.9b586e965735191cp-3848L }, - { 0xf.f85cf60592328d2p-9520L, 0x6.cc119db119c5da9p+9692L, -0xf.ca9a38109b4c719p+9704L, -0xf.ca9a38109b4c718p+9704L }, - { 0x2.4705d056fcb476bp-10860L, 0x3.1a2184afa03ed9b8p+9408L, -0x8.394d6f3a2c6421fp+9420L, -0x8.394d6f3a2c6421ep+9420L }, - { 0x1.efef03e24f29831p-3176L, -0x1.bfca2ff565e7c7bp+7752L, 0x1.5b1b931975e428fcp+7764L, 0x1.5b1b931975e428fep+7764L }, - { 0x7.f9560ea0eafc2cc8p+9148L, -0xe.5db4d730684872fp-4644L, -0x2.0187920d54cfb648p-4628L, -0x2.0187920d54cfb644p-4628L }, - { 0x2.1c6a49285ec69a54p+7380L, -0xb.ddf812b2df6f309p+11120L, -0x1.5627be2e7b4b330ep+11136L, -0x1.5627be2e7b4b330cp+11136L }, - { 0x2.50ff3a6p-16416L, 0x1.9d7cfb7be4e5e346p-3100L, -0x6.790f9653202121ap-3088L, -0x6.790f965320212198p-3088L }, - { 0xa.f2ce777f871a092p+8780L, -0x7.e9c5837c2b7a4378p+8600L, -0x1.0f80f46491d8b8b6p+8616L, -0x1.0f80f46491d8b8b4p+8616L }, - { 0x4.3bbff88395fe0928p+7164L, 0x3.078f7e4f50cee1fp-7468L, 0x5.4cde225bf7236df8p-7456L, 0x5.4cde225bf7236ep-7456L }, - { 0x1.40aedb75cc42f43p-3192L, -0x2.375af19fcf60d21cp-10956L, 0x1.ba17d902e7ac91cp-10944L, 0x1.ba17d902e7ac91c2p-10944L }, - { 0x2.e864c555d76d8fd8p+6104L, 0xb.a979200b6675bf5p+12664L, 0x1.1622d579502026b8p+12680L, 0x1.1622d579502026bap+12680L }, - { 0x6.752e08b00a6d4d98p-13552L, 0x1.90097d94485a7816p-11844L, -0x5.2b4c1e50cbcc733p-11832L, -0x5.2b4c1e50cbcc7328p-11832L }, - { 0x3.04f44aa97cbecd68p+9068L, 0x2.20c52243c3fe5f5cp-1352L, 0x4.b642b5821f0aeabp-1340L, 0x4.b642b5821f0aeab8p-1340L }, - { 0xb.561e8e6deeeb863p+8760L, -0x5.e1ac807eaa7b77d8p+10480L, -0xc.956e10315ea540ep+10492L, -0xc.956e10315ea540dp+10492L }, - { 0xd.22dad1146a3117p-3440L, 0x1.6479b527d613626ep+10984L, -0x1.2b0f6f8ef5196098p+10996L, -0x1.2b0f6f8ef5196096p+10996L }, - { 0x2.22be5768782c69ep-1500L, -0x7.84c022153d71427p+3364L, 0x2.c059ab76744f422p+3376L, 0x2.c059ab76744f4224p+3376L }, - { 0x1.33435c6dd3af5182p-9572L, 0x1.57376b17d4e90b76p-3676L, -0x3.220b9bf2119f92fp-3664L, -0x3.220b9bf2119f92ecp-3664L }, - { 0x6.36fe5bdp-16416L, -0x3.80b314c162ff107cp-3536L, 0xe.093a021c9f60a3ap-3524L, 0xe.093a021c9f60a3bp-3524L }, - { 0x3.5eddbf43ab12e4a8p-5700L, -0xa.5a9dd55c674fbcbp-11372L, 0xe.6777bbf7206e289p-11360L, 0xe.6777bbf7206e28ap-11360L }, - { 0x4.0a86f68d596f23e8p+7288L, -0x2.82d21b0211fc61fp+6792L, -0x4.7815c915a64ae22p+6804L, -0x4.7815c915a64ae218p+6804L }, - { 0x5.dd81aeb5f9a4f41p-12728L, -0x3.431d7252485001e4p+4252L, 0xa.2288cab8ba1862ep+4264L, 0xa.2288cab8ba1862fp+4264L }, - { 0x1.c28b03b6522311d4p+8396L, -0x3.afe5362342fa9fe4p+5704L, -0x7.8efd32fc985cb208p+5716L, -0x7.8efd32fc985cb2p+5716L }, - { 0x9.8ddc34fd380f7cdp+568L, 0xd.ced796ac550d5bp-232L, 0x1.ecfe43ab490e4fp-220L, 0x1.ecfe43ab490e4f02p-220L }, - { 0xa.a847a961d00df0ap-12848L, 0x3.93bd979611f43f78p-112L, -0xb.37a8505a07b2fcfp-100L, -0xb.37a8505a07b2fcep-100L }, - { 0x3.4f402dd17b106c64p+2848L, 0xa.f846845320f317ep+11452L, 0x7.a1d0165417058f2p+11464L, 0x7.a1d0165417058f28p+11464L }, - { 0x3.5fa4d9a9fc21151cp-1100L, -0x6.a6e5ab8e0621faap-5044L, 0x1.c89777bcbd33655ap-5032L, 0x1.c89777bcbd33655cp-5032L }, - { 0x5.2d133d77a9410b7p-2572L, -0x3.275ca162a017e318p+6740L, 0x1.fa7fbb2b9abf17f6p+6752L, 0x1.fa7fbb2b9abf17f8p+6752L }, - { 0xb.e1fef9fa3e9727bp+7852L, -0x5.05efe9b304aee998p-8292L, -0x9.a240a67e18be2fap-8280L, -0x9.a240a67e18be2f9p-8280L }, - { 0x1.c09e468785b5c354p+0L, -0xf.e5ab606d8f7b3f9p+7364L, -0xc.ddc3c7616dc446ap+7364L, -0xc.ddc3c7616dc4469p+7364L }, - { 0x1.719eead8a3620922p-180L, -0x9.35dd3e7b4a587e8p-344L, 0x6.74fe200dd9b9ac08p-336L, 0x6.74fe200dd9b9ac1p-336L }, - { 0x2.8278beb0a151763cp-8212L, 0x5.eba3b3c3cbebaa48p+8284L, -0xb.de30343dea0b754p+8296L, -0xb.de30343dea0b753p+8296L }, - { 0x3.87c4c0dbaba1349cp-12224L, 0x6.e4fe70430b5bdc7p+1680L, -0x1.4929e97c9702dfbap+1696L, -0x1.4929e97c9702dfb8p+1696L }, - { 0x7.f319306232e2f73p-6724L, -0x1.ee505dd9decefc84p-6388L, 0x3.2b1b071aed29ccap-6376L, 0x3.2b1b071aed29cca4p-6376L }, - { 0x9.1283f8a751c7f83p+12432L, 0x7.dca6e7a2f237d91p+2120L, 0x1.7de46c83437e1e1ep+2136L, 0x1.7de46c83437e1e2p+2136L }, - { 0x1.3c34c3c18ccb74p+3424L, 0x1.dfc743544c7cf47p-10028L, 0x1.9119b57694c572a8p-10016L, 0x1.9119b57694c572aap-10016L }, - { 0x5.3e565a011294bb1p-3244L, -0x7.3b196b739bfda8ep+10224L, 0x5.b8f9d0123290a33p+10236L, 0x5.b8f9d0123290a338p+10236L }, - { 0x3.8eadcc909e81db74p+8456L, -0x8.b4ba5efc626545bp-7348L, -0x1.1fa19c6bacf2da3ep-7332L, -0x1.1fa19c6bacf2da3cp-7332L }, - { 0xd.3e930c035371ebdp+1480L, 0xd.c6f32497b5fa56dp-8132L, 0x4.fd987b827f63e48p-8120L, 0x4.fd987b827f63e488p-8120L }, - { 0x1.ca7125b550edcfa2p+12328L, -0x8.5acc8c64428f007p-4880L, -0x1.925b90260d25c798p-4864L, -0x1.925b90260d25c796p-4864L }, - { 0x1.0759db8p-16416L, -0x1.3d7f601417185b42p+9944L, 0x4.f877af95374dab3p+9956L, 0x4.f877af95374dab38p+9956L }, - { 0x2.ebd4b19614542238p-14220L, -0xe.1d7e71fee6192bap-6916L, 0x3.0ff877205d61bf4p-6900L, 0x3.0ff877205d61bf44p-6900L }, - { 0x1.29f13fe64015ff46p-12340L, -0xe.d00c66c632b4331p-4136L, 0x2.ca0157bfdbd30f1cp-4120L, 0x2.ca0157bfdbd30f2p-4120L }, - { 0x3.f63ba994a2b78004p+10240L, -0x1.57d10ff018294618p+10496L, -0x3.5bb555eab8c5fb3cp+10508L, -0x3.5bb555eab8c5fb38p+10508L }, - { 0xa.4140ce712f7b66p-6044L, 0xa.a4bce42874e01e7p+7932L, -0xf.b259d473b5ba7p+7944L, -0xf.b259d473b5ba6ffp+7944L }, - { 0x2.389ed5e685fc7134p-7432L, 0x1.b0d67f730c4f25bp+2716L, -0x3.113e0ce097de504p+2728L, -0x3.113e0ce097de503cp+2728L }, - { 0x2.eb978b7f340e0d58p-12364L, -0x9.adfe099d19d2efdp+14472L, 0x1.d37051fa5ea8b54cp+14488L, 0x1.d37051fa5ea8b54ep+14488L }, - { 0x1.5117ecccbd2929b6p-984L, -0x2.b3ae7a75c3b22b8p+7932L, 0xa.61940cdf8cae1a3p+7940L, 0xa.61940cdf8cae1a4p+7940L }, - { 0x9.c5c6d7173a39debp+2136L, -0xe.7eb5c52358f835ep+764L, -0x7.920e831d2af5f778p+776L, -0x7.920e831d2af5f77p+776L }, - { 0x4.3cbd69afe18488ap-11676L, -0x4.fc641a37202982b8p+4448L, 0xe.35d02b71acd487fp+4460L, 0xe.35d02b71acd488p+4460L }, - { 0x3.f0fb7afa6ec2cfb8p-3124L, 0x8.c94c984dbf4168dp-7396L, -0x6.b27180ae20d41818p-7384L, -0x6.b27180ae20d4181p-7384L }, - { 0x1.15ebd30a56ecb2b2p+0L, -0x5.856bb2e62511b85p-6612L, -0xa.7891ddb0a39e893p-6616L, -0xa.7891ddb0a39e892p-6616L }, - { 0x1.410266a44f4ade2cp+12952L, -0x5.59c0fbbe79fde728p-3952L, -0x1.0eb6baf03c343682p-3936L, -0x1.0eb6baf03c34368p-3936L }, - { 0x4.9a419d04fd743ab8p-1156L, 0x9.9730cd1292b85ap-2352L, -0x2.b3998f683c0b5874p-2340L, -0x2.b3998f683c0b587p-2340L }, - { 0x2.60759aed3ba97d74p-6648L, -0x3.457e7b428940e34cp+6612L, 0x5.4f0968584e19d46p+6624L, 0x5.4f0968584e19d468p+6624L }, - { 0x2.c09bd6c830c2da0cp+4984L, 0x3.6fa2b8685f61706p-9464L, 0x4.2ea6cd39acdfcd5p-9452L, 0x4.2ea6cd39acdfcd58p-9452L }, - { 0x7.78d4cf72d7cf81d8p-2060L, 0x7.d23da006d9cb052p-476L, -0x3.ed916667567ea0d4p-464L, -0x3.ed916667567ea0dp-464L }, - { 0x1.e8ec274891c36f6cp-7524L, -0xe.b8e278ce572ceccp+13540L, 0x1.b0a4220a5507d7cap+13556L, 0x1.b0a4220a5507d7ccp+13556L }, - { 0x2.52eaea727fb51b3cp+1024L, 0x3.2d22702027067fbp+7032L, 0xc.b866f7b6cca84f4p+7040L, 0xc.b866f7b6cca84f5p+7040L }, - { 0x4.79b08bc9ec6fd5e8p+10104L, 0x1.81c5dfaf98a0897p+10364L, 0x3.b7d3bdf2e8856dccp+10376L, 0x3.b7d3bdf2e8856ddp+10376L }, - { 0x4.a5a62cfd609d80cp+5652L, -0x5.87842a4bef49dfa8p-7756L, -0x7.a203332a806e1458p-7744L, -0x7.a203332a806e145p-7744L }, - { 0x1.3174a6b7f76a7a86p-3852L, 0x1.3b46ff4438b080d2p+3696L, -0x1.2879ff24035ac472p+3708L, -0x1.2879ff24035ac47p+3708L }, - { 0x1.59099ec9256df04ap+0L, -0x1.277978f781f67db2p+8000L, -0x7.f3bf3708724aa25p+7996L, -0x7.f3bf3708724aa248p+7996L }, - { 0x1.3cf4d6911744a6e2p-6764L, -0x2.b9ce903eca743bf8p-8152L, 0x4.80486c57075689p-8140L, 0x4.80486c5707568908p-8140L }, - { 0x9.e73df967ed71cb5p+10888L, -0x9.1c04010e8eff95cp+200L, -0x1.838dac64b03492fp+216L, -0x1.838dac64b03492eep+216L }, - { 0x5.ac4763ac26327b68p-2172L, 0x6.d1b60df617649598p-9812L, -0x3.9ca312dc58e6275p-9800L, -0x3.9ca312dc58e6274cp-9800L }, - { 0x7.c5ae0be7d6818d3p+2488L, -0x4.dbabdbbb9c48c46p+9484L, -0x2.f454d6d39c21f13cp+9496L, -0x2.f454d6d39c21f138p+9496L }, - { 0x5.da0ebfb61ec3d02p+12980L, -0x1.581ed3ef522cbf1ap-6680L, -0x4.42b6830ac9def328p-6668L, -0x4.42b6830ac9def32p-6668L }, - { 0xc.49cd167ff1e78d8p-7248L, 0x2.5d1e3b11ab1bc11p+9356L, -0x4.2e3d9db76c4da9bp+9368L, -0x4.2e3d9db76c4da9a8p+9368L }, - { 0x2.3b097280a7388008p-11704L, -0x1.061a800d969622bap+4464L, 0x2.ecddc2fed514cc58p+4476L, 0x2.ecddc2fed514cc5cp+4476L }, - { 0x3.cb828c1d80e286fcp+9648L, 0x4.e4c85ab7c7a946f8p-4884L, 0xb.877a950bfab740bp-4872L, 0xb.877a950bfab740cp-4872L }, - { 0xc.edf760d6631b3bep+8604L, -0x1.d29ab8a4c77d5026p+12620L, -0x3.d49031197037c1fcp+12632L, -0x3.d49031197037c1f8p+12632L }, - { 0xe.225defb5c321ae6p-14048L, -0x5.74840b374f4bf2b8p+5052L, 0x1.2b44f5a5454a26a4p+5068L, 0x1.2b44f5a5454a26a6p+5068L }, - { 0x1.f568cdf552161702p+0L, -0x3.0fa175f6b0d25a68p+13292L, -0x2.f8001ffc544eaf7p+13292L, -0x2.f8001ffc544eaf6cp+13292L }, - { 0xc.720d79d29899fb8p+11764L, 0x9.7936377be97bc8ep-14464L, 0x1.b3788544a5202dp-14448L, 0x1.b3788544a5202d02p-14448L }, - { 0x1.65183aeb23c7f346p-12864L, 0x3.7e98b83d4e4ca3d4p-1628L, -0xa.f97cc9cbef6f274p-1616L, -0xa.f97cc9cbef6f273p-1616L }, - { 0x1.ef79e62dda211fbp-1948L, -0x4.d23ac0a4bc617a2p-7780L, 0x2.4ab1f4112fd17bd8p-7768L, 0x2.4ab1f4112fd17bdcp-7768L }, - { 0x2.07b821eeab20cb9p-160L, -0x3.87a37dafaa376984p-3444L, 0x2.312b08e897671c68p-3436L, 0x2.312b08e897671c6cp-3436L }, - { 0xe.72871f0890145a5p+6524L, -0x8.9b9c7083ec7bb41p+4312L, -0xd.b7ed0b19656759ep+4324L, -0xd.b7ed0b19656759dp+4324L }, - { 0x7.4749b7447d5e7338p+5256L, -0x2.62e022dcd7674688p+13968L, -0x3.104df1ed95530a84p+13980L, -0x3.104df1ed95530a8p+13980L }, - { 0x3.7b8f1a318d818b88p-652L, -0xf.181bfa7fcc16529p+14968L, 0x2.6563b23fcf087a7cp+14980L, 0x2.6563b23fcf087a8p+14980L }, - { 0x7.5c8ebd177e7ae458p+7036L, 0xe.f0ee6b7c83a4f2ap+8576L, 0x1.9ad0e0a9821d3b5ep+8592L, 0x1.9ad0e0a9821d3b6p+8592L }, - { 0xa.9952cee8bf7946cp+9776L, -0x9.ebe699f73877e14p+9532L, -0x1.7b024099ee813daep+9548L, -0x1.7b024099ee813dacp+9548L }, - { 0x5.41cd5dd4d2e6f57p-832L, 0x7.56f01406b724bdfp-1104L, -0x1.7c8f99b2a519ef76p-1092L, -0x1.7c8f99b2a519ef74p-1092L }, - { 0x7.6952ff4171fab3e8p-4L, -0x1.48ad521dcbf4fffap+2016L, 0x1.6ce9dbd767f12b1p+2016L, 0x1.6ce9dbd767f12b12p+2016L }, - { 0x1.8ea82281163d7928p-10440L, 0x7.f9f050a81e69354p+10508L, -0x1.4543b78b02164af6p+10524L, -0x1.4543b78b02164af4p+10524L }, - { 0x1.6ad2d6305e908336p-4748L, -0xb.4b631a00023d4e5p-88L, 0xd.174834bfe56bdf3p-76L, 0xd.174834bfe56bdf4p-76L }, - { 0x7.eb9bc51887342998p-10920L, -0x2.99dd95695c7be558p+14760L, 0x6.eeb8ff1797c83d48p+14772L, 0x6.eeb8ff1797c83d5p+14772L }, - { 0x4.b577a5ced64ab34p-2420L, 0x2.19c1abad13c7ff4p+6292L, -0x1.3d6c8b4378990c28p+6304L, -0x1.3d6c8b4378990c26p+6304L }, - { 0x3.5a9733b22bf6430cp+448L, -0x9.845cc05884f6906p-3452L, -0x1.0b83fc7f2a9cbfe2p-3440L, -0x1.0b83fc7f2a9cbfep-3440L }, - { 0x1.8d9e8b60d5f8a05cp-872L, -0x1.50baf7988b16437p-12748L, 0x4.7a26f37415047d8p-12740L, 0x4.7a26f37415047d88p-12740L }, - { 0x1.768be5f438d658c6p+7928L, -0xe.79a06c92bcdce18p+9292L, -0x1.c04e9286dd4bbf2ap+9308L, -0x1.c04e9286dd4bbf28p+9308L }, - { 0x5.cc20a3adbc707e28p-2948L, 0x1.418168344c0a6e5cp+10428L, -0xe.73270ee786c9bb4p+10436L, -0xe.73270ee786c9bb3p+10436L }, - { 0x2.01c7e3e1c94921a8p-116L, -0x7.49980d9c71c299dp-5404L, 0x3.4605f5bf68747d74p-5396L, 0x3.4605f5bf68747d78p-5396L }, - { 0x1.2d18c093a14af7c2p+13716L, -0x3.2206b08cd203d208p-12288L, -0xa.7dbca28d7e9a709p-12276L, -0xa.7dbca28d7e9a708p-12276L }, - { 0x1.9b11ae9e8789a284p+0L, -0xc.b66cf8836b8e5dbp-1376L, -0x8.af8b48e59260aa5p-1376L, -0x8.af8b48e59260aa4p-1376L }, - { 0x3.b06bfa9d957936c4p-4168L, -0x1.188ea5802ac70448p+8880L, 0x1.1d5c217dd118b722p+8892L, 0x1.1d5c217dd118b724p+8892L }, - { 0x7.baa53749caf9a77p+800L, -0x3.ea31eb4e2589909cp-10688L, -0xc.4768c5478ebac23p-10680L, -0xc.4768c5478ebac22p-10680L }, - { 0xc.41014580a7e7c5bp-6320L, 0x1.a46de5ad785de1bcp+8256L, -0x2.885692990a3b54ccp+8268L, -0x2.885692990a3b54c8p+8268L }, - { 0xe.6403838c15ab5c3p+5876L, -0x7.15c7d5d8dcdd2f4p-6296L, -0xa.2bb3092c3f77652p-6284L, -0xa.2bb3092c3f77651p-6284L }, - { 0x4.65c5ae737a956a58p-6604L, -0xe.3fc8bb8cbd6b77fp+7832L, 0x1.6f76fc0e8ab70b94p+7848L, 0x1.6f76fc0e8ab70b96p+7848L }, - { 0x6.8944175f279787cp+10884L, -0x3.c6fc4b6f87ef254p+7116L, -0xa.0a2397fa3e675fbp+7128L, -0xa.0a2397fa3e675fap+7128L }, - { 0x7.97bc7363ddb9f9dp-14396L, -0x1.705e3b449ab47172p-10828L, 0x5.0e6bdb7051618038p-10816L, 0x5.0e6bdb705161804p-10816L }, - { 0xf.4b3b8c6e5f4077ep-8792L, -0xe.ed14847db8e58eap+10408L, 0x2.00637d26121590cp+10424L, 0x2.00637d26121590c4p+10424L }, - { 0x2.41544dd69bee4b34p-12932L, -0x9.56c015923cb5347p+9124L, 0x1.d7b74a4ea2338eb6p+9140L, 0x1.d7b74a4ea2338eb8p+9140L }, - { 0xd.e8a92b7b9d69849p+6300L, 0x3.378443d08ca9b84p-7784L, 0x4.f36729d56447749p-7772L, 0x4.f36729d564477498p-7772L }, - { 0x2.95a69238p-16416L, -0x7.80265f26200c7ebp+3052L, 0x1.e0ef561ee038353cp+3068L, 0x1.e0ef561ee038353ep+3068L }, - { 0x3.d22d04b09cd96cp-9300L, 0xf.766def43d7f6db7p-4796L, -0x2.319c6a506e36063p-4780L, -0x2.319c6a506e36062cp-4780L }, - { 0xe.05ec56e0474d77fp-9876L, 0x6.3465a4ac0b6eea4p+3892L, -0xe.f45bdd4a240a8e9p+3904L, -0xe.f45bdd4a240a8e8p+3904L }, - { 0x1.5625d5075933e438p-12804L, -0x1.6a8b27da36acfbfcp+1128L, 0x4.6d4403e057a6ebcp+1140L, 0x4.6d4403e057a6ebc8p+1140L }, - { 0x3.ff1468eb7c6639d8p+2168L, 0x5.89011895dd2bfa1p+9524L, 0x2.eeb5173dba868ba4p+9536L, 0x2.eeb5173dba868ba8p+9536L }, - { 0x5.5e6fb8e79a725d4p-10600L, 0x3.4479f5178f043be4p+5416L, -0x8.7436da836e63732p+5428L, -0x8.7436da836e63731p+5428L }, - { 0x4.bac9e5fddf2f185p+7280L, 0x2.f6cd56a85259e42p+12372L, 0x5.45114581f9e1dacp+12384L, 0x5.45114581f9e1dac8p+12384L }, - { 0x4.483dd9562600d12p-9412L, -0xa.91077e9f213cfefp-5060L, 0x1.8465eb7223d017dep-5044L, 0x1.8465eb7223d017ep-5044L }, - { 0x6.89490ba0c6021cbp-10152L, -0x1.93dd39b70d0c7806p+3368L, 0x3.e8b771e60bf65d74p+3380L, 0x3.e8b771e60bf65d78p+3380L }, - { 0x6.a491ee61660c85b8p-8176L, -0x8.c58567eeb3bfc0fp+1020L, 0x1.180c5e553f4e3ccap+1036L, 0x1.180c5e553f4e3cccp+1036L }, - { 0xd.f08f28601b06388p+13780L, 0x1.f2be9ba2b44f15dep+7068L, 0x6.8e5e3dc0bd5a4308p+7080L, 0x6.8e5e3dc0bd5a431p+7080L }, - { 0x7.457d5fa8p-16416L, 0x5.36121d8b16e4023p+12776L, -0x1.4e1c5f378a2e9af4p+12792L, -0x1.4e1c5f378a2e9af2p+12792L }, - { 0x4.1748a66d103e0fa8p+2480L, -0xb.d4d5cce3f37beb6p-5748L, -0x7.2b5e31b51058241p-5736L, -0x7.2b5e31b510582408p-5736L }, - { 0x9.a2ade899ef170ddp-7756L, 0x1.bd8b440f03c52848p+2808L, -0x3.4b4e71fdaa1b4c3cp+2820L, -0x3.4b4e71fdaa1b4c38p+2820L }, - { 0x1.92f53c269af15d42p-2928L, -0xa.9b2b2aefde35ef1p-10024L, 0x7.947ccb13fbbf40fp-10012L, 0x7.947ccb13fbbf40f8p-10012L }, - { 0x6.5d56109347b4ece8p-5268L, -0xa.9333fe0a2e921e5p+732L, 0xd.980ed7ca91c85f8p+744L, 0xd.980ed7ca91c85f9p+744L }, - { 0x3.7331573dbbfe41p-9136L, 0xd.1d5fbf9a047f6e6p-6984L, -0x1.d3f0daca4b8e608cp-6968L, -0x1.d3f0daca4b8e608ap-6968L }, - { 0x1.22091bc1d5e9fd24p+3872L, -0x4.9486f9b8459c0e5p-1392L, -0x4.5474ca8e81c1c0c8p-1380L, -0x4.5474ca8e81c1c0cp-1380L }, - { 0x2.386cb89f395c99d8p+5940L, -0x2.96e4faa003243a54p+9812L, -0x3.c1833e77be9321d8p+9824L, -0x3.c1833e77be9321d4p+9824L }, - { 0xd.a5f4daee140e571p+14840L, -0x1.4c05492fe894fe3cp-13360L, -0x4.b33b6593c762fa18p-13348L, -0x4.b33b6593c762fa1p-13348L }, - { 0x2.fdd1ccf5dd08fa6cp+7320L, 0xc.71f7b0b27cb30f2p-8224L, 0x1.63ee6ef689e23e96p-8208L, 0x1.63ee6ef689e23e98p-8208L }, - { 0x1.18572e37370fa8eap-5800L, -0x5.6bd9b71f1fad727p-10896L, 0x7.ad2c6c0e239a106p-10884L, 0x7.ad2c6c0e239a1068p-10884L }, - { 0x4.338ea3e8p-16416L, 0x7.6d96c7989caed318p+6588L, -0x1.dc4402ce4443924cp+6604L, -0x1.dc4402ce4443924ap+6604L }, - { 0x5.b84f9fac30c5708p+7284L, 0x2.75e933325654ae8cp-9812L, 0x4.6092020d634cd7e8p-9800L, 0x4.6092020d634cd7fp-9800L }, - { 0x3.3e8858dcbe489fccp-14240L, 0x7.1714d40b275a0028p+2264L, -0x1.8a57dcc28e880ca2p+2280L, -0x1.8a57dcc28e880cap+2280L }, - { 0x9.afa19306462ec46p-4888L, -0x3.32b794a45c3dca3p-11648L, 0x3.d05e73304663623cp-11636L, 0x3.d05e73304663624p-11636L }, - { 0xd.6eaf9e68e259a17p+1236L, 0x1.cae4c43fd3dd00fcp+568L, 0x8.ae504857a6a66dap+576L, 0x8.ae504857a6a66dbp+576L }, - { 0x1.5385af8dce743fa2p+4740L, 0xc.6bc92b4c49f5ed6p-10560L, 0xe.600c818b9dbc8e6p-10548L, 0xe.600c818b9dbc8e7p-10548L }, - { 0x2.6955eff09a469d1p-5464L, 0x1.bf618641435e7edep-13260L, -0x2.54a916727d0b84p-13248L, -0x2.54a916727d0b83fcp-13248L }, - { 0xb.b90392d51073b9p+2700L, -0xb.85d9396b5e43565p-13416L, -0x7.9b09aa40c40f5878p-13404L, -0x7.9b09aa40c40f587p-13404L }, - { 0x1.4e74d9c2a57143e4p+3248L, 0x1.3eb38c672955f3f6p-14744L, 0xf.cc00ef9a86640aap-14736L, 0xf.cc00ef9a86640abp-14736L }, - { 0x2.ffdfeb1e2d7afdcp-4136L, -0x4.d00269c32889b9bp-5536L, 0x4.db90696a8a4897cp-5524L, 0x4.db90696a8a4897c8p-5524L }, - { 0x4.31404d22df9d95fp-7388L, 0x1.0fe8d9c29ebdb07ep+764L, -0x1.ea4f1ad3071fc356p+776L, -0x1.ea4f1ad3071fc354p+776L }, - { 0x5.0dda6b7p-16416L, 0x2.4106f760ba40ae1p-596L, -0x9.08499f030f1555dp-584L, -0x9.08499f030f1555cp-584L }, - { 0x7.8bae544d63ec3028p-7564L, -0xc.a0b5e26f909cb8bp+6516L, 0x1.74f7acb203909964p+6532L, 0x1.74f7acb203909966p+6532L }, - { 0x5.4c3c08113f951888p-2412L, -0x9.c30a7694e19585ep-7016L, 0x5.be22b69ad1450abp-7004L, 0x5.be22b69ad1450ab8p-7004L }, - { 0x5.afb9c4521af8ad88p-5172L, -0x5.37c3c13b646fb49p+9220L, 0x6.95d89660c2da22f8p+9232L, 0x6.95d89660c2da23p+9232L }, - { 0x1.cd7081ce9dc8e7b6p+88L, -0x1.867a488422075acp-1032L, -0x8.785f0a1c2ad14f6p-1028L, -0x8.785f0a1c2ad14f5p-1028L }, - { 0xc.eab3815fae9cc61p-4692L, 0x8.ffb864f70ff47bcp+14852L, -0xa.4cda82a0bacc544p+14864L, -0xa.4cda82a0bacc543p+14864L }, - { 0x9.034b59783532405p-14652L, 0x1.068f1b119399b4fep+8912L, -0x3.ab025bbdc4919f7p+8924L, -0x3.ab025bbdc4919f6cp+8924L }, - { 0x2.7ea6fa3a41a2ed88p+13384L, -0x1.cb41210310ca777cp-2836L, -0x5.dccc2ba4750423a8p-2824L, -0x5.dccc2ba4750423ap-2824L }, - { 0x7.07a46917c6845538p-11804L, 0xe.2919c752d6e306p+14380L, -0x2.8cc7496f5889be98p+14396L, -0x2.8cc7496f5889be94p+14396L }, - { 0x1.e93b47f4fe49cc4p+3472L, -0xc.48da1160ad2d58bp-8004L, -0xa.6a788032e89083ap-7992L, -0xa.6a788032e890839p-7992L }, -}; - -int check_equal(long double res, long double expected) -{ - if (res != expected) { - return 0; - } - return (__builtin_copysignl(1.0L, res) == - __builtin_copysignl(1.0L, expected)); -} - -int main(void) -{ - int ret = 0; - int i; - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - long double ld_res; - __asm__ volatile ("fyl2x" : "=t" (ld_res) : - "0" (tests[i].arg0), "u" (tests[i].arg1) : "st(1)"); - if (!check_equal(ld_res, tests[i].down) && - !check_equal(ld_res, tests[i].up)) { - printf("FAIL: fyl2x %La %La, expected %La or %La, got %La\n", - tests[i].arg0, tests[i].arg1, tests[i].down, tests[i].up, - ld_res); - ret = 1; - } - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-fyl2xp1.c b/tests/tcg/i386/test-i386-fyl2xp1.c deleted file mode 100644 index 99b08c188a07..000000000000 --- a/tests/tcg/i386/test-i386-fyl2xp1.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* Test fyl2xp1 instruction. */ - -#include - -struct test { - long double arg0, arg1, down, up; -}; - -const struct test tests[] = { - { 0.0L, 12345.0L, 0.0L, 0.0L }, - { 0.0L, -12345.0L, -0.0L, -0.0L }, - { -0.0L, 12345.0L, -0.0L, -0.0L }, - { -0.0L, -12345.0L, 0.0L, 0.0L }, - { 0.0L, 0.0L, 0.0L, 0.0L }, - { 0.0L, -0.0L, -0.0L, -0.0L }, - { -0.0L, 0.0L, -0.0L, -0.0L }, - { -0.0L, -0.0L, 0.0L, 0.0L }, - { 0.1L, 0.0L, 0.0L, 0.0L }, - { 0.1L, -0.0L, -0.0L, -0.0L }, - { -0.1L, 0.0L, -0.0L, -0.0L }, - { -0.1L, -0.0L, 0.0L, 0.0L }, - { 0.1L, __builtin_infl(), __builtin_infl(), __builtin_infl() }, - { 0.1L, -__builtin_infl(), -__builtin_infl(), -__builtin_infl() }, - { -0.1L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, - { -0.1L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, - { 0x4p-4L, 0x1p-16400L, 0x5.269e12f3468p-16404L, 0x5.269e12f347p-16404L }, - /* Randomly generated tests. */ - { 0x1.31edb79669dd58b4p-4L, 0x6.c25439d8a5ce071p+14380L, 0xb.3d0da52c1f58af3p+14376L, 0xb.3d0da52c1f58af4p+14376L }, - { -0x1.8ee6680c65ce5a5p-4L, -0x7.423575b7ac0ba6a8p-2228L, 0x1.12aefa96f5501268p-2228L, 0x1.12aefa96f550126ap-2228L }, - { 0x2.a22cf9563bdd84bcp-140L, -0x2.de6fb39cd2988858p-9616L, -0xa.e65ebedd6a09e4cp-9756L, -0xa.e65ebedd6a09e4bp-9756L }, - { -0x7.d1095c8p-16416L, 0x1.faa600d255691f3cp+6420L, -0x1.6516c14a553da39ap-9992L, -0x1.6516c14a553da398p-9992L }, - { 0x4.109249df7871ecb8p-4L, 0x1.48d8eebeb8e650ccp-4976L, 0x6.b65f4ea303a8bc3p-4980L, 0x6.b65f4ea303a8bc38p-4980L }, - { -0x4.69bcd5ccca0e4b7p-4L, -0x5.8808ae941f249bb8p+5056L, 0x2.93432047c7d8a37p+5056L, 0x2.93432047c7d8a374p+5056L }, - { 0x3.311f29ec8b38ef74p-4L, -0x3.9865a5505c3ae018p+8924L, -0xf.188d6a2bba06e17p+8920L, -0xf.188d6a2bba06e16p+8920L }, - { -0x2.d60110be2e4f812p-4L, 0x9.d61827e646421b3p-11580L, -0x2.c4c3e84b6c7366c8p-11580L, -0x2.c4c3e84b6c7366c4p-11580L }, - { 0xe.e4d7ebcee10774ap-8L, 0x6.5cde5b7691984918p+732L, 0x8.4e3d353f31e18a3p+728L, 0x8.4e3d353f31e18a4p+728L }, - { -0x2.a675c1a9bd30047cp-4L, 0x7.6eae536d8312ebb8p+364L, -0x1.f116f2eaf6acba9ep+364L, -0x1.f116f2eaf6acba9cp+364L }, - { 0xb.b88ac679a0d52c7p-8L, 0x1.9e45eb57212a1f62p-8572L, 0x1.ac193570d9ac8e8p-8576L, 0x1.ac193570d9ac8e82p-8576L }, - { -0x4.64109ab4700cf108p-4L, 0x6.b8d96cb8e5f2d648p+6524L, -0x3.1c6e7c0e4e7a72cp+6524L, -0x3.1c6e7c0e4e7a72bcp+6524L }, - { 0x3.e104f8db9c02bf08p-4L, -0x9.7b905723db3fe54p+10116L, -0x2.f83eb6c0529e814p+10116L, -0x2.f83eb6c0529e813cp+10116L }, - { -0x3.906c6b45a9367874p-4L, -0x3.b4f349ff071caa64p-1868L, 0x1.5901debf0c548972p-1868L, 0x1.5901debf0c548974p-1868L }, - { 0x1.a960a3b0bddab872p-4L, -0xa.80f80d092c59d2fp+14796L, -0x1.7f4db50bf3cd7588p+14796L, -0x1.7f4db50bf3cd7586p+14796L }, - { -0x1.422d05691d16c3c2p-4L, -0x3.b7afc1088aafbb28p+8056L, 0x7.07a7a145b32d0108p+8052L, 0x7.07a7a145b32d011p+8052L }, - { 0x3.005497260bfe3efcp-4L, 0x2.70b5fc4ea650b9d4p+13164L, 0x9.af1b9b78be96p+13160L, 0x9.af1b9b78be96001p+13160L }, - { -0x3.06e1d8ce558315f4p-4L, 0xd.35a31147278a276p+13452L, -0x3.ff1a81342b225bf4p+13452L, -0x3.ff1a81342b225bfp+13452L }, - { 0x5.0312793de5c8af88p-8L, -0x1.4d64bd7151f8f83ep+13040L, -0x9.53672f561e11e6dp+13032L, -0x9.53672f561e11e6cp+13032L }, - { -0x4.6fd8156d1cd1594p-4L, 0x1.2bbce9cdd6e3b99ep+2372L, -0x8.c70a26daa3a50c9p+2368L, -0x8.c70a26daa3a50c8p+2368L }, - { 0x1.eab2d269541adaap-4L, 0x6.ac21c841f135e818p-10084L, 0x1.16d60a1c1c53feb2p-10084L, 0x1.16d60a1c1c53feb4p-10084L }, - { -0x3.f7c63bee23b61aep-4L, -0x1.a4746c335dbffc62p+13532L, 0xa.ce1e8b95a3cf783p+13528L, 0xa.ce1e8b95a3cf784p+13528L }, - { 0x2.6770b5d4fbdb93ap-4L, 0x2.d0747a0fc160c9d8p-680L, 0x9.17f6580ba6d8d8fp-684L, 0x9.17f6580ba6d8d9p-684L }, - { -0x4.0c0f16fccf171958p-4L, -0x3.809f02e6f0a4a7ccp-632L, 0x1.793819991e50c69p-632L, 0x1.793819991e50c692p-632L }, - { 0x2.810e5178p-16416L, -0x2.449b1281f31c58ccp-8912L, -0x8p-16448L, -0x0p+0L }, - { -0x9.d14aa8cda67cd5p-80L, 0x2.3ff156f07699390cp+1860L, -0x1.fdd7e7674c238f56p+1784L, -0x1.fdd7e7674c238f54p+1784L }, - { 0x4.336973fa388adee8p-4L, 0x6.68a249106b0173e8p+1992L, 0x2.27d09f940daa748cp+1992L, 0x2.27d09f940daa749p+1992L }, - { -0x2.975eb02ec54042c4p-4L, -0xe.5f17872c08b122dp+7300L, 0x3.a9ce29cce0f873bp+7300L, 0x3.a9ce29cce0f873b4p+7300L }, - { 0x3.18142b116ed172acp-4L, -0x4.c54f6758e57de6ap+2080L, -0x1.377f5497b5e407dcp+2080L, -0x1.377f5497b5e407dap+2080L }, - { -0x1.1bbc90a005c56912p-4L, -0x4.a9cd0b7c6a571cd8p+5332L, 0x7.ba3b3fc9d3dba0f8p+5328L, 0x7.ba3b3fc9d3dba1p+5328L }, - { 0x1.7e8efe16b98d3692p-8L, -0x3.dde86e3bf4d91464p-4156L, -0x8.4ff4f144076f27ep-4164L, -0x8.4ff4f144076f27dp-4164L }, - { -0xa.7e96579f3a805bp-8L, -0x7.ab5c584ae971a368p+6308L, 0x7.6906aa4947cba078p+6304L, 0x7.6906aa4947cba08p+6304L }, - { 0x1.9eca084b5e88755ep-4L, 0xf.227ce981b624ea7p+11116L, 0x2.1b30979fa829e6dcp+11116L, 0x2.1b30979fa829e6ep+11116L }, - { -0x2.1874c2d880381c8p-4L, -0x1.137b3104db6109dap-5420L, 0x3.7ca97456f9d67034p-5424L, 0x3.7ca97456f9d67038p-5424L }, - { 0x3.198e690cee01623p-4L, -0x1.adc155088273f77ep+13812L, -0x6.dcc1714e4ba0c37p+13808L, -0x6.dcc1714e4ba0c368p+13808L }, - { -0x4.6551f788f1588b28p-4L, -0x7.69f3a55b24a9777p+428L, 0x3.6f8dc0f3c3d2cf44p+428L, 0x3.6f8dc0f3c3d2cf48p+428L }, - { 0x7.88f397834128293p-8L, 0x6.bf38fb4299638c08p-960L, 0x4.849080f3ab11f818p-964L, 0x4.849080f3ab11f82p-964L }, - { -0x1.b55f0bbc95324732p-4L, 0x1.b42e17120776fe52p-13916L, -0x4.70f2c0a6bc44465p-13920L, -0x4.70f2c0a6bc444648p-13920L }, - { 0x3.32c5f1314a8c6dap-4L, -0x1.bdb2f33681f41db6p+12272L, -0x7.52da7e0b1bed5968p+12268L, -0x7.52da7e0b1bed596p+12268L }, - { -0x3.36905b81e589d9e8p-4L, 0x3.d8dded4726d3fb34p+784L, -0x1.3e840521ab659a96p+784L, -0x1.3e840521ab659a94p+784L }, - { 0x2.f78a13ae770dc39cp-4L, -0x3.cf1123d327fd9024p-9600L, -0xe.f4c0070f6303241p-9604L, -0xe.f4c0070f630324p-9604L }, - { -0x3.5c99081287a8051p-4L, -0x1.70700e3356c86b3cp+7752L, 0x7.d5e5870a6e18d73p+7748L, 0x7.d5e5870a6e18d738p+7748L }, - { 0xa.dd6d280bcc33172p-8L, -0xf.1ff631d3dfa8c85p+4928L, -0xe.82fa32a3cab9bcep+4924L, -0xe.82fa32a3cab9bcdp+4924L }, - { -0x2.ecbb3c2ebebf283p-4L, -0x3.212b343a660ecbb4p+4672L, 0xe.953534ceecbfcf2p+4668L, 0xe.953534ceecbfcf3p+4668L }, - { 0x3.75380852cb5eb234p-4L, -0x2.df562212c19c9528p+12736L, -0xc.f92b33893bdc2ap+12732L, -0xc.f92b33893bdc29fp+12732L }, - { -0x1.ad74e73c3fab3c44p-4L, -0x1.a457ed324f1b85bp-8776L, 0x4.32b38b6b976e91b8p-8780L, 0x4.32b38b6b976e91cp-8780L }, - { 0x2.18c8d7808e9812b8p-144L, 0x5.0f40c3a5a98fe708p-14212L, 0xf.4e3924951dac17fp-14356L, 0xf.4e3924951dac18p-14356L }, - { -0x9.5d0b284b6a68ac4p-184L, -0x3.68104ae46b7bcf6p+12464L, 0x2.e045d02aa9b47858p+12284L, 0x2.e045d02aa9b4785cp+12284L }, - { 0x2.2261e8b5a73122bcp-4L, 0x1.39e07d457c893d2p-4904L, 0x3.8b3a68313dff915p-4908L, 0x3.8b3a68313dff9154p-4908L }, - { -0x3.e7f8b8fdf0027474p-4L, 0xb.8b615ebfce42d08p-1688L, -0x4.a95fab921aa3a9c8p-1688L, -0x4.a95fab921aa3a9cp-1688L }, - { 0x2.90731457099d1b3p-4L, 0x3.41f7f39a30b3898cp-8352L, 0xb.2d9667a84b2a4dbp-8356L, 0xb.2d9667a84b2a4dcp-8356L }, - { -0x1.090c8ddde72dd1a2p-4L, 0x1.6a8b36c84fd8d976p+12300L, -0x2.2fd80d7e66d3f60cp+12296L, -0x2.2fd80d7e66d3f608p+12296L }, - { 0x2.40b0eeedb834a1d4p-4L, 0x3.56b6f4120c52d84cp-10716L, 0xa.26da0df382c1052p-10720L, 0xa.26da0df382c1053p-10720L }, - { -0x1.a336b1480b20b424p-4L, 0x2.2ac2bc77bdfef9ccp+8860L, -0x5.66a4f7795a77dca8p+8856L, -0x5.66a4f7795a77dcap+8856L }, - { 0xe.db656802d11a281p-8L, -0x4.2e126b3484e7514p+13440L, -0x5.717346005231cffp+13436L, -0x5.717346005231cfe8p+13436L }, - { -0x1.c4b925adab67ae7ep-4L, 0x1.a15ba1a3fbe9dd4p-6564L, -0x4.68657bab4041a828p-6568L, -0x4.68657bab4041a82p-6568L }, - { 0x3.7586cb9442c45784p-4L, -0x7.713929beef89c638p-6972L, -0x2.19fb69e21ac718acp-6972L, -0x2.19fb69e21ac718a8p-6972L }, - { -0x2.fa71ba62a32a8b7p-4L, -0xa.936c0eb50eb5e37p-6908L, 0x3.24855b9f7f8ce32p-6908L, 0x3.24855b9f7f8ce324p-6908L }, - { 0x3.67490f5787dde48p-4L, 0xf.67432f04da27bbp-524L, 0x4.492e50d2f71cf588p-524L, 0x4.492e50d2f71cf59p-524L }, - { -0x2.97b9427d1d5c7c24p-4L, 0x1.57a9f87e42d057eep+5708L, -0x5.7a6c8388322303c8p+5704L, -0x5.7a6c8388322303cp+5704L }, - { 0x1.33ef1ab5c6634e46p-4L, 0x1.d8999e72af335708p+9564L, 0x3.16c5444800c64aa8p+9560L, 0x3.16c5444800c64aacp+9560L }, - { -0xa.9a5ba7d8b6734cdp-8L, 0xa.671a839c0039ab8p-5508L, -0xa.284bae12c6dde0dp-5512L, -0xa.284bae12c6dde0cp-5512L }, - { 0xe.181100f05f0394cp-8L, -0x3.f3e2c4d22523780cp-416L, -0x4.e3ca00e35b39c898p-420L, -0x4.e3ca00e35b39c89p-420L }, - { -0x1.66f888b96b8e00e8p-4L, -0x3.8ded010cb7762338p+10300L, 0x7.867a91379ede7e08p+10296L, 0x7.867a91379ede7e1p+10296L }, - { 0x4.a6c0029c00b96fep-4L, -0x4.e87d73d329cb332p+11216L, -0x1.ce989e2a560b54b2p+11216L, -0x1.ce989e2a560b54bp+11216L }, - { -0x3.5843155f8dc36dfp-4L, -0xa.15334aafc6d22b9p-13476L, 0x3.6951d7122f8daafp-13476L, 0x3.6951d7122f8daaf4p-13476L }, - { 0x4.22701b25d6c80c3p-4L, -0x5.126eff0187a3803p-9272L, -0x1.ae8f4e7823ebfeeep-9272L, -0x1.ae8f4e7823ebfeecp-9272L }, - { -0x1.a7a0556e6f951196p-4L, 0x8.0be412ff866338fp+4496L, -0x1.44704cea9eeb28f4p+4496L, -0x1.44704cea9eeb28f2p+4496L }, - { 0x1.36be53940221672p-172L, -0x7.194c9b043451bfep+4704L, -0xc.6e75e23d8e56928p+4532L, -0xc.6e75e23d8e56927p+4532L }, - { -0x1.f30afcd111913c04p-156L, 0x9.b3ff5c8d9b3d3acp+2792L, -0x1.b49eb9a0eb4c908cp+2640L, -0x1.b49eb9a0eb4c908ap+2640L }, - { 0x3.140ad6b1e9922ec4p-4L, 0x3.bff4c5061256d8ccp-12384L, 0xf.3b1c7d17ba2c0edp-12388L, 0xf.3b1c7d17ba2c0eep-12388L }, - { -0x3.9ede658d4493b08p-4L, 0x2.f71c7b1bb45c5604p-12156L, -0x1.18f7f35b0c252984p-12156L, -0x1.18f7f35b0c252982p-12156L }, - { 0x2.4ddf39d02ae29214p-4L, -0x1.d106f81605905eeap+7920L, -0x5.a433bd60909bf0bp+7916L, -0x5.a433bd60909bf0a8p+7916L }, - { -0x1.c546cdac360a9cp-4L, -0x7.bad48611f3e40dap+7376L, 0x1.4ed08a35cb87ed0ep+7376L, 0x1.4ed08a35cb87ed1p+7376L }, - { 0x1.a15d4c117c202388p-4L, 0xd.0e541be4b24c664p+12760L, 0x1.d3e2699c368b4f18p+12760L, 0x1.d3e2699c368b4f1ap+12760L }, - { -0x7.16658416ee8125e8p-8L, 0x1.62dc2caf9f8fdad6p-5160L, -0xe.5fa5d852e85667p-5168L, -0xe.5fa5d852e85666fp-5168L }, - { 0xd.0bad0960312abe4p-12L, 0x1.f48ad8b59f54a95cp+192L, 0x2.4bda7bbd2000768p+184L, 0x2.4bda7bbd20007684p+184L }, - { -0x3.f1bddc60ebe5c3ap-4L, 0x8.063bbdb884d4c9fp-7972L, -0x3.46dc3e1d744ccba8p-7972L, -0x3.46dc3e1d744ccba4p-7972L }, - { 0xe.8a2046b2bb94931p-8L, 0x7.322c00fd114c6b78p+5120L, 0x9.2d030614c8ad44fp+5116L, 0x9.2d030614c8ad45p+5116L }, - { -0x3.7454ee5b08c8cb7cp-4L, -0x3.642f824f3db6287cp+11984L, 0x1.30a3de1a3b5cc8aap+11984L, 0x1.30a3de1a3b5cc8acp+11984L }, - { 0x3.b7e07d72b90e939p-4L, 0x4.8d8e9330b67dc858p-1260L, 0x1.5f5eb6ed8b9c0ed4p-1260L, 0x1.5f5eb6ed8b9c0ed6p-1260L }, - { -0xc.f22d7bfd55c6c94p-8L, 0x4.64873d3f77ee2338p-2776L, -0x5.430a59c679c81728p-2780L, -0x5.430a59c679c8172p-2780L }, - { 0x2.50df0103c304075cp-4L, -0x7.b4b24f138f39278p+14856L, -0x1.80b99699a7f61822p+14856L, -0x1.80b99699a7f6182p+14856L }, - { -0x3.1f0b53ee6296bd78p-4L, -0x7.0f43afd6ab41b8c8p-13572L, 0x2.35d20bba726b6ae8p-13572L, 0x2.35d20bba726b6aecp-13572L }, - { 0x2.6725591bb528453cp-4L, 0x1.ce864eaac5f98256p-8564L, 0x5.d5dc4cda5a5180a8p-8568L, 0x5.d5dc4cda5a5180bp-8568L }, - { -0x3.2290e7cdb1817facp-4L, 0x3.4d8a9f94b9a431bcp-11728L, -0x1.0a06e1a9cc7457eap-11728L, -0x1.0a06e1a9cc7457e8p-11728L }, - { 0x3.8b99e9b78a041538p-4L, -0x3.b23e0cc201793b9p+6472L, -0x1.113a80c6eb278128p+6472L, -0x1.113a80c6eb278126p+6472L }, - { -0x1.1f197acd86bd6b08p-4L, -0x1.f1665c655caaaf4ap-6144L, 0x3.425e0b5214f9cd34p-6148L, 0x3.425e0b5214f9cd38p-6148L }, - { 0xf.ed161e95b0ae352p-8L, -0x8.be9a4b8e5552e1cp-8976L, -0xc.2eacd7db48ff243p-8980L, -0xc.2eacd7db48ff242p-8980L }, - { -0x3.6a4be64691ce57a4p-4L, -0x5.839b606e3a436a78p-6768L, 0x1.e8f825b15269b6cap-6768L, 0x1.e8f825b15269b6ccp-6768L }, - { 0x5.00c1d6bp-16416L, -0x4.b497e93cf288163p+9424L, -0x2.1f671dd90f010a24p-6988L, -0x2.1f671dd90f010a2p-6988L }, - { -0x2.5a584197e5510fc4p-132L, -0x1.1772e32ccdc2478p+14528L, 0x3.b498edc574c550ccp+14396L, 0x3.b498edc574c550dp+14396L }, - { 0x2.f851cb35a14097acp-4L, -0xa.7268d9e3b2e61bap-12600L, -0x2.90f65da0448e38f8p-12600L, -0x2.90f65da0448e38f4p-12600L }, - { -0x4.6d56dca19ebe3708p-4L, -0x2.526a2db40e4a133p+760L, 0x1.15c884d416e79d9cp+760L, 0x1.15c884d416e79d9ep+760L }, - { 0x2.fe2658a2c8078de8p-4L, 0x1.0d699d587ebc0e5p-10464L, 0x4.2a59bbf556de3138p-10468L, 0x4.2a59bbf556de314p-10468L }, - { -0x3.0fe4a68e65c41494p-4L, -0x1.7173155e4bd10df2p+1836L, 0x7.13952436db99bf8p+1832L, 0x7.13952436db99bf88p+1832L }, - { 0x4.033ea3caa0b5f698p-4L, -0x6.03ab20e0280437cp-188L, -0x1.f111dcaf19286f9p-188L, -0x1.f111dcaf19286f8ep-188L }, - { -0x4.5b0056b6b6068878p-4L, -0xc.6497d33070a9a97p+5684L, 0x5.ae614b07dc079ecp+5684L, 0x5.ae614b07dc079ec8p+5684L }, - { 0x1.82adf1f869ababbcp-4L, -0x1.123ccd14ea237d04p-7084L, -0x2.3b0d91c0089d65e4p-7088L, -0x2.3b0d91c0089d65ep-7088L }, - { -0x2.5b451d0b82180d44p-4L, 0x6.8a58d91ee307a548p-8008L, -0x1.80ddcbdeb9c0f3bap-8008L, -0x1.80ddcbdeb9c0f3b8p-8008L }, - { 0x2.e352f84376e4f1d8p-4L, 0x5.8248426003120498p-7260L, 0x1.519dfeeb985eb048p-7260L, 0x1.519dfeeb985eb04ap-7260L }, - { -0xa.7b393feb80e94efp-12L, 0x2.ef48748849de0554p-12820L, -0x2.c6eff255a859ad08p-12828L, -0x2.c6eff255a859ad04p-12828L }, - { 0x1.5fbb3b2cb9a73a0ap-4L, -0x4.a27aba12e1fe1ef8p+10496L, -0x8.d048b795b632ed1p+10492L, -0x8.d048b795b632edp+10492L }, - { -0x3.809836ef223bfdacp-4L, 0x2.0d96044152595614p-8280L, -0xb.b533a267a420e5fp-8284L, -0xb.b533a267a420e5ep-8284L }, - { 0x2.71939b3f2db2b26p-4L, -0xd.d36dfd2744533a6p+10580L, -0x2.d5c54067b4f1a7ep+10580L, -0x2.d5c54067b4f1a7dcp+10580L }, - { -0x3.6b9ad80ebf1deb08p-4L, 0x6.7a681b6bb071e288p+13136L, -0x2.3f6e3d82be3f2ad4p+13136L, -0x2.3f6e3d82be3f2adp+13136L }, - { 0x2.9afe8631c4e5ce7p-4L, -0x3.83b2bda6ed10fea8p+4784L, -0xc.3d274a1edea87ebp+4780L, -0xc.3d274a1edea87eap+4780L }, - { -0x2.c4c0d66a1b99c3c8p-4L, 0x2.5b1e1eead3bb2cacp+13080L, -0xa.550eea778396ce3p+13076L, -0xa.550eea778396ce2p+13076L }, - { 0x4.08187131d98288b8p-4L, 0xc.30a692d385849d1p+3460L, 0x3.f3bcf1eaed28f854p+3460L, 0x3.f3bcf1eaed28f858p+3460L }, - { -0x2.ef6cdbc058cd31ep-4L, 0x2.75c1df05fa79e34p-5496L, -0xb.822f6abf9319caap-5500L, -0xb.822f6abf9319ca9p-5500L }, - { 0xc.80ee642b1a4020bp-8L, -0xc.f511a8dcdc0ce5ep+13800L, -0xe.43506254711d49bp+13796L, -0xe.43506254711d49ap+13796L }, - { -0x2.0992fd9466d2b79p-4L, -0x5.3b81e7664b8716fp+3608L, 0x1.0738060d1d9ad53ap+3608L, 0x1.0738060d1d9ad53cp+3608L }, - { 0x4.7e5d88ep-16416L, 0x4.b21a682b16590228p-5704L, 0x0p+0L, 0x8p-16448L }, - { -0x3.70fb6523fc99c194p-176L, 0xc.8fca8d5dd6ce8cep+9336L, -0x3.e5dc145add1549cp+9164L, -0x3.e5dc145add1549bcp+9164L }, - { 0x3.a722ebee85536cdp-4L, -0x7.e92da929dfeccb3p-11692L, -0x2.58ce8b42e26f75cp-11692L, -0x2.58ce8b42e26f75bcp-11692L }, - { -0x3.53ab833486c08db8p-4L, -0x8.ec1b59a9caa6303p-7400L, 0x3.00224e3c6217e70cp-7400L, 0x3.00224e3c6217e71p-7400L }, - { 0x4.9487cc987ce18b6p-4L, 0x1.b43405b727b9b4ecp+660L, 0x9.e6c239cbd68f84cp+656L, 0x9.e6c239cbd68f84dp+656L }, - { -0xe.32da65364dfac0fp-8L, -0x1.a0b348b4888fa2fcp-124L, 0x2.24daad6dfa91c368p-128L, 0x2.24daad6dfa91c36cp-128L }, - { 0x2.31765e800ee61554p-4L, 0xd.bd9f34293d3d29bp+4316L, 0x2.8bea4d125ba3dd28p+4316L, 0x2.8bea4d125ba3dd2cp+4316L }, - { -0x7.e8d207888e10bb28p-8L, 0xf.1545995a9604c33p+4440L, -0xa.ed3b79e2b24ae3cp+4436L, -0xa.ed3b79e2b24ae3bp+4436L }, - { 0x2.0dbde28b26dc5474p-4L, -0x1.d9f5b1f814163e0ep+3520L, -0x5.292de7ec7fde3dbp+3516L, -0x5.292de7ec7fde3da8p+3516L }, - { -0x2.5da10be7bc76adbcp-4L, 0xe.9c1364eb8db9e71p+11700L, -0x3.5f577bc6db6ff75cp+11700L, -0x3.5f577bc6db6ff758p+11700L }, - { 0x1.7fb27a800f7431d8p-4L, 0x3.fe39a5a5f5c97a9p+3280L, 0x8.40e81d2da1bfc96p+3276L, 0x8.40e81d2da1bfc97p+3276L }, - { -0x3.bb9fab7278c86f2p-4L, -0xf.0cbb72ff70654d3p-12084L, 0x5.c4ab2766bb87bf6p-12084L, 0x5.c4ab2766bb87bf68p-12084L }, - { 0x3.aa809df3dbec6abp-4L, 0x2.15e22591ab1c856p+7060L, 0x9.ee6cd49285b6905p+7056L, 0x9.ee6cd49285b6906p+7056L }, - { -0x1.248726fb26304a8ep-4L, 0xf.6e6ebaa083c4cd3p-2404L, -0x1.a64bcf5800dc981p-2404L, -0x1.a64bcf5800dc980ep-2404L }, - { 0x3.e5c9dd1ff3793c6cp-4L, -0xe.77c56c623d0f0eep-11552L, -0x4.8cec2abe53411658p-11552L, -0x4.8cec2abe5341165p-11552L }, - { -0x9.e1fb01951741bb8p-12L, 0x3.dc9d2acf270903a8p+14376L, -0x3.7207777a5f25e4bcp+14368L, -0x3.7207777a5f25e4b8p+14368L }, - { 0x2.d447d6b5e5ce3cc8p-4L, 0xc.0731d6f892df414p+2464L, 0x2.d34ea5652b7493e8p+2464L, 0x2.d34ea5652b7493ecp+2464L }, - { -0x3.ed070cb292baae74p-4L, 0x1.f5bda0c135772ea8p+5972L, -0xc.bc8d2aeea6f8d93p+5968L, -0xc.bc8d2aeea6f8d92p+5968L }, - { 0x4.45d277b639fcf9c8p-4L, 0x7.75d18c49b089dc88p-1124L, 0x2.8c2501bc216e5db4p-1124L, 0x2.8c2501bc216e5db8p-1124L }, - { -0x4.9e8c6ba757e6aa9p-4L, 0xd.170086ac1893a93p+13928L, -0x6.6ef8d754645a469p+13928L, -0x6.6ef8d754645a4688p+13928L }, - { 0x2.3c7efc4a74a8b844p-4L, 0x2.089221e2807b8ae8p+13656L, 0x6.240ef782a887ef18p+13652L, 0x6.240ef782a887ef2p+13652L }, - { -0x3.4b58e3e6f3f4be84p-4L, -0x7.011c78290d122728p+12196L, 0x2.546305cf20c52e78p+12196L, 0x2.546305cf20c52e7cp+12196L }, - { 0x3.c013919270a9d0a8p-200L, -0x4.0e8c6ae1a53296c8p+7956L, -0x1.5f31af56e9407d08p+7760L, -0x1.5f31af56e9407d06p+7760L }, - { -0x1.f7dc69dp-16416L, -0x1.bf51089c520b29b4p+4664L, 0x4.f62a54dd5dd4a83p-11752L, 0x4.f62a54dd5dd4a838p-11752L }, - { 0x1.e00da7403dc86138p-4L, -0x5.35b41b797fb9331p-3908L, -0xd.53e4f12ca294a6p-3912L, -0xd.53e4f12ca294a5fp-3912L }, - { -0x2.bf8b03274d13363cp-4L, -0x1.05cdd981abf77a14p+1464L, 0x4.72e3f9ff62128ed8p+1460L, 0x4.72e3f9ff62128eep+1460L }, - { 0x3.d7776260cc65e86p-4L, 0xb.13430c035931444p-3664L, 0x3.703d2634906f9538p-3664L, 0x3.703d2634906f953cp-3664L }, - { -0xf.d2d322382421f69p-8L, -0x8.f017932d188a998p+2680L, 0xd.29ddb607a558484p+2676L, 0xd.29ddb607a558485p+2676L }, - { 0x1.1da304350ac720aap-4L, 0x6.36b4ef636b98ac98p+10536L, 0x9.ab3f04c20130e66p+10532L, 0x9.ab3f04c20130e67p+10532L }, - { -0x4.a32b02b37caedc88p-4L, 0x5.4e587c75d5a6bfcp+14104L, -0x2.9eb7d7a4081dba88p+14104L, -0x2.9eb7d7a4081dba84p+14104L }, - { 0x1.5ac66b5ac9bb06fcp-4L, -0x3.c7ea3c3c2b39e2c8p-5248L, -0x7.17bcb1e2b4044dp-5252L, -0x7.17bcb1e2b4044cf8p-5252L }, - { -0x4.861b827cdb0400cp-4L, 0x1.d7dd30f75b264db4p-6584L, -0xe.23a4a8fbc48fd9fp-6588L, -0xe.23a4a8fbc48fd9ep-6588L }, - { 0x8.86257636294381fp-8L, 0xe.8f9244700df6721p+4408L, 0xb.02557c2fc89289bp+4404L, 0xb.02557c2fc89289cp+4404L }, - { -0x1.0dfbe47a9aca7786p-4L, 0x5.e2a8926a1f2a69f8p-2832L, -0x9.436d5defb285aa4p-2836L, -0x9.436d5defb285aa3p-2836L }, - { 0x2.bff85b9860bb1c0cp-4L, -0x1.8989c2560de848e8p-2992L, -0x5.a0b9bd60c6e9415p-2996L, -0x5.a0b9bd60c6e94148p-2996L }, - { -0x2.43f55447649b8c24p-4L, -0x1.b21f1e71fce5162ep-9792L, 0x5.f9f03cfb02f136b8p-9796L, 0x5.f9f03cfb02f136cp-9796L }, - { 0xd.df18cea4044bb26p-8L, -0x6.a546c7e5065f0158p+12584L, -0x8.184130740ad26bep+12580L, -0x8.184130740ad26bdp+12580L }, - { -0x2.0aa382fea7dd8ed4p-4L, 0x1.922b0febfe6b22bep+14300L, -0x4.f33585b409b249b8p+14296L, -0x4.f33585b409b249bp+14296L }, - { 0x1.9f8df2c594f5aba2p-4L, 0xa.a22cceb5d16a7b9p+12368L, 0x1.7b7ed32a30c1340ep+12368L, 0x1.7b7ed32a30c1341p+12368L }, - { -0x2.3a7805cc42052c88p-4L, 0x6.0c375211e7de2b68p-13748L, -0x1.4efed1a1d060daf8p-13748L, -0x1.4efed1a1d060daf6p-13748L }, - { 0xb.98b5acf06c53957p-8L, 0xa.c01d2e9cf20bab2p-408L, 0xa.fe7242406c2e29dp-412L, 0xa.fe7242406c2e29ep-412L }, - { -0x3.b426327377c1e0ccp-8L, -0x7.c0b1a87701c336f8p+4900L, 0x2.9ba51806e9e0d1c4p+4896L, 0x2.9ba51806e9e0d1c8p+4896L }, - { 0x2.32a92ffd519efa3p-4L, -0x1.ba7195161943bbbep-5192L, -0x5.2295fa8174e88c5p-5196L, -0x5.2295fa8174e88c48p-5196L }, - { -0x2.494a01edd418deacp-4L, 0x6.693114f18c78632p+10664L, -0x1.6d165465955afcb4p+10664L, -0x1.6d165465955afcb2p+10664L }, - { 0x3.36cc1fd8p-16416L, -0x3.731a5226115dd018p-13876L, -0x8p-16448L, -0x0p+0L }, - { -0x5.a44d891b492c118p-64L, 0xb.69fb96dbb13b38cp-1084L, -0x5.ce7362af963c8f38p-1144L, -0x5.ce7362af963c8f3p-1144L }, - { 0x3.474c4807a8ad6228p-4L, -0x2.f3562babd4b5f03cp-12580L, -0xc.b2050e940966a45p-12584L, -0xc.b2050e940966a44p-12584L }, - { -0x1.72da05f3ba83570cp-4L, 0x2.bd74f98cb810cbf8p-3608L, -0x6.00abe3e58945abf8p-3612L, -0x6.00abe3e58945abfp-3612L }, - { 0x3.03355b3ad678a4e4p-4L, 0x2.fcacda0bf497fcdp+624L, 0xb.e4fbcf489c92111p+620L, 0xb.e4fbcf489c92112p+620L }, - { -0x4.87b616543e6d68f8p-4L, -0x1.5aa2807140fcb66ep-5712L, 0xa.6762b975babc4a7p-5716L, 0xa.6762b975babc4a8p-5716L }, - { 0x3.3eef25ea1d0cb1a4p-4L, 0x8.77ef4346014be03p+2668L, 0x2.41b30237313d1594p+2668L, 0x2.41b30237313d1598p+2668L }, - { -0x4.abe5ee4fb3e5bap-4L, -0x9.ad41850d220d88cp+12620L, 0x4.d1f38825ce2a945p+12620L, 0x4.d1f38825ce2a9458p+12620L }, - { 0x5.a5eb695ee8c9932p-8L, 0x1.d13834b0342791d4p-3780L, 0xe.a5a311a3e533135p-3788L, 0xe.a5a311a3e533136p-3788L }, - { -0x3.57d686c40d552838p-4L, -0xf.0b6de12e05c3635p-8368L, 0x5.165c21cb97c896d8p-8368L, 0x5.165c21cb97c896ep-8368L }, - { 0x3.02fa76adc4b3f734p-4L, 0x2.c8a8a9ca263fb34p-1104L, 0xb.1512e047c64d14bp-1108L, 0xb.1512e047c64d14cp-1108L }, - { -0x2.e4dfe9c3785c81f4p-4L, 0x2.47670d17c1a6b908p+7296L, -0xa.7ee8efc4c4a9f53p+7292L, -0xa.7ee8efc4c4a9f52p+7292L }, - { 0x9.aaf264c27c54e8ap-8L, 0xb.54e2e10eee029ffp-4480L, 0x9.b23353124c7f80ap-4484L, 0x9.b23353124c7f80bp-4484L }, - { -0x1.47d8c6c7e55c7a26p-4L, 0x1.2ae861e0c614f7b8p+3208L, -0x2.3f9d8ce1381508fp+3204L, -0x2.3f9d8ce1381508ecp+3204L }, - { 0x3.cb86413e9654e6cp-8L, -0x1.8722bfac85135608p+3816L, -0x8.4dc558bd3004cd6p+3808L, -0x8.4dc558bd3004cd5p+3808L }, - { -0x2.b06c6bf6c50a6bfcp-4L, 0x3.666a36ff2e60f2bcp+12728L, -0xe.7119a8d1ccc016p+12724L, -0xe.7119a8d1ccc015fp+12724L }, - { 0x3.47ce25adf55a2814p-4L, 0x7.ddb836a97dd546bp+10988L, 0x2.1dd4bf63fa5a9bccp+10988L, 0x2.1dd4bf63fa5a9bdp+10988L }, - { -0x9.d038f0be8c9445p-8L, 0x2.cb89c09be031f264p-4624L, -0x2.859a5e7613fdf99cp-4628L, -0x2.859a5e7613fdf998p-4628L }, - { 0x5.f4040498e9510358p-8L, -0xe.8e6b01ce80d9a3bp+268L, -0x7.b965fce804203578p+264L, -0x7.b965fce80420357p+264L }, - { -0x3.9bec29ae6836c004p-4L, 0x3.349abf15c61637ccp-6152L, -0x1.2ea0fb97798d6ffcp-6152L, -0x1.2ea0fb97798d6ffap-6152L }, - { 0x3.1cb0194881148be8p-4L, -0xd.f8498b43249707dp-3144L, -0x3.950056a5b35f5a1cp-3144L, -0x3.950056a5b35f5a18p-3144L }, - { -0x2.bb9b8d7aa3c0d0a4p-4L, 0x5.7723b746db2d4dep-9424L, -0x1.7a10aa106c1d1108p-9424L, -0x1.7a10aa106c1d1106p-9424L }, - { 0xe.4d878fb87fd395ap-12L, 0x3.4f9956a9f16bc38p+2616L, 0x4.4337165130e7f47p+2608L, 0x4.4337165130e7f478p+2608L }, - { -0x1.1630a82965507a32p-16L, 0xa.2e28946ae2eae99p+6956L, -0xf.f5d543fa5f7a7cbp+6940L, -0xf.f5d543fa5f7a7cap+6940L }, - { 0x3.59c0a36418e9a6dp-4L, -0x2.1ad5b8410a86465cp-13676L, -0x9.3ce405e344231efp-13680L, -0x9.3ce405e344231eep-13680L }, - { -0x2.3acdbdd2877849ep-8L, 0x4.84f0a846883e7a18p-6060L, -0xe.99ec6628631da5bp-6068L, -0xe.99ec6628631da5ap-6068L }, - { 0x2.4706917d5d92e68p-4L, 0x3.1e5765ddcaca8e8cp-11800L, 0x9.946873401fa60ap-11804L, 0x9.946873401fa60a1p-11804L }, - { -0x3.c87f60de0535481cp-4L, -0xf.51c1e48dde26436p+1780L, 0x5.f65dcfd39a0ece18p+1780L, 0x5.f65dcfd39a0ece2p+1780L }, - { 0x3.7dc1ea97cf0b5704p-4L, 0xc.90a3dd049ad490bp+7836L, 0x3.93f379f1866fdb2p+7836L, 0x3.93f379f1866fdb24p+7836L }, - { -0x1.f798a53251ee9fbp-4L, -0xe.75c48de977feda3p-5476L, 0x2.bc9e9decff0f5cb4p-5476L, 0x2.bc9e9decff0f5cb8p-5476L }, - { 0xb.aa65757ee31da3p-8L, -0x5.4d142559265fe498p-6132L, -0x5.73e6d4277632f548p-6136L, -0x5.73e6d4277632f54p-6136L }, - { -0x4.6c8e0d8c9dc60d18p-4L, 0x3.c991984ee0203824p+14956L, -0x1.c4bb15413b7086ecp+14956L, -0x1.c4bb15413b7086eap+14956L }, - { 0x1.f5fd4ee6b1f86f46p-4L, -0xd.fee89bfeb4e4785p+3032L, -0x2.55958e192187d838p+3032L, -0x2.55958e192187d834p+3032L }, - { -0x2.5fc6fbe9f0d78b54p-4L, 0x1.afcc807af3d6794ap-7248L, -0x6.40ed6a17958f5abp-7252L, -0x6.40ed6a17958f5aa8p-7252L }, - { 0x2.451ffb9b70940624p-4L, -0x1.37f52061877f3bccp-11700L, -0x3.bb5eb351baf17c7cp-11704L, -0x3.bb5eb351baf17c78p-11704L }, - { -0x4.95757561d2aaa5p-4L, -0x1.3d9fcaab7bbc9c6ep-2868L, 0x9.aae38ba996d3919p-2872L, 0x9.aae38ba996d391ap-2872L }, - { 0x1.7d04bff149a7d55cp-4L, -0xf.61c71955bf9a0dap+7880L, -0x1.f94e4939cb229d26p+7880L, -0x1.f94e4939cb229d24p+7880L }, - { -0x4.47b25b1314f91ddp-4L, 0x1.f3a3c57544812a32p-7436L, -0xe.0645285005f95b2p-7440L, -0xe.0645285005f95b1p-7440L }, - { 0x4.5b48f6c753552e7p-4L, 0x7.f9951c9fa3a3d26p-14636L, 0x2.c54b2a5dc4af4df4p-14636L, 0x2.c54b2a5dc4af4df8p-14636L }, - { -0x2.755a177a9bcd19ecp-4L, 0x2.8f368cebe2a73544p+9496L, -0x9.db16676f3eeb8b6p+9492L, -0x9.db16676f3eeb8b5p+9492L }, - { 0x4.74f58fd716847278p-8L, 0xb.5105baafec9e23fp-1216L, 0x4.8234ae72b3afbcap-1220L, 0x4.8234ae72b3afbca8p-1220L }, - { -0xf.3a54ecf20e1f38dp-8L, -0x1.cb2ddc2e80a14976p+11248L, 0x2.8a0435ff27f289fp+11244L, 0x2.8a0435ff27f289f4p+11244L }, - { 0x1.6e76573c811c0cc8p-4L, -0x6.890bc5e24bb11168p-1700L, -0xc.ed43d94a59956a1p-1704L, -0xc.ed43d94a59956ap-1704L }, - { -0x1.cc0d76d858214824p-4L, 0x4.9d780438f01ffb18p+360L, -0xc.b13775b6b72f16cp+356L, -0xc.b13775b6b72f16bp+356L }, - { 0x2.975f7098p-16416L, -0x1.7c27bae5b714e156p+9888L, -0x5.8d31808ab8fc3f1p-6528L, -0x5.8d31808ab8fc3f08p-6528L }, - { -0x2.84c6bb3c78ad39p-156L, 0x2.187b034003e64b7cp-1008L, -0x7.9d6286f490256558p-1164L, -0x7.9d6286f49025655p-1164L }, - { 0x1.3294feaed50f486cp-4L, 0x2.ed77680ef406a86cp-5816L, 0x4.e0b890b56bc98c3p-5820L, 0x4.e0b890b56bc98c38p-5820L }, - { -0x4.1adda118b2b67118p-4L, -0x1.1da0ee568b65fe28p-11272L, 0x7.a2a8b5ea7803f64p-11276L, 0x7.a2a8b5ea7803f648p-11276L }, - { 0x2.77501a3949fd1c3cp-8L, 0xa.f6abbcf12cd419p-12544L, 0x2.6d1bb5bd9453001cp-12548L, 0x2.6d1bb5bd9453002p-12548L }, - { -0x3.7d7a59482ce42cb8p-4L, 0x1.751b58122d75b98ap-11080L, -0x8.474a285e08f1966p-11084L, -0x8.474a285e08f1965p-11084L }, - { 0x1.f807f393d863f41ep-4L, 0xa.fc78b24fd33203p+1300L, 0x1.d6e2db24a50f8948p+1300L, 0x1.d6e2db24a50f894ap+1300L }, - { -0x3.40dcfa4088fed5fp-4L, -0xe.e3fdb321f26f9c4p+13020L, 0x4.e22a8f2ea6bab6a8p+13020L, 0x4.e22a8f2ea6bab6bp+13020L }, - { 0x2.2c85d17e3ac7521p-4L, -0xf.8890f12fb883eafp+1744L, -0x2.dae202adf96b494p+1744L, -0x2.dae202adf96b493cp+1744L }, - { -0xe.60ec2578a9c34f3p-8L, 0xb.6de7e775308bfap+3896L, -0xf.401f5a2820d2433p+3892L, -0xf.401f5a2820d2432p+3892L }, - { 0xa.ceb454639d49191p-8L, 0xb.214592ce214ecfep+2692L, 0xa.9f939fed0fd998cp+2688L, 0xa.9f939fed0fd998dp+2688L }, - { -0x6.d08f79b55a47424p-8L, 0x3.405b3c3e3f6864cp+6040L, -0x2.066381858f2491acp+6036L, -0x2.066381858f2491a8p+6036L }, - { 0xb.58fe4c3ae76ed36p-8L, -0x3.71ed0565cf0a82f8p-3000L, -0x3.72f5022d0c286c9cp-3004L, -0x3.72f5022d0c286c98p-3004L }, - { -0x3.7ef417dcb2ad04fp-4L, -0x1.989fd2c40d16b72ep+11400L, 0x9.15614e994d5f1eep+11396L, 0x9.15614e994d5f1efp+11396L }, - { 0x2.773887c3a113544p-4L, -0x1.317ad55b9bdb3828p+5680L, -0x3.f2a82f605122f56cp+5676L, -0x3.f2a82f605122f568p+5676L }, - { -0x2.4141773c8bf242b8p-4L, -0xc.e4018849b76a23ap-6468L, 0x2.d33684b6ec2dc264p-6468L, 0x2.d33684b6ec2dc268p-6468L }, - { 0x3.adfdb601b76362f4p-4L, -0x7.03e0d7aa253797dp+10148L, -0x2.184ee92bef09f62cp+10148L, -0x2.184ee92bef09f628p+10148L }, - { -0x1.82b638b5edf2eadp-4L, -0xd.8e0fec8304331dep-2872L, 0x1.f07932a2326e2cb6p-2872L, 0x1.f07932a2326e2cb8p-2872L }, - { 0x3.114503e53e4715p-4L, -0x3.7c55d418348e7ec8p+6688L, -0xe.1cc12794f6aa77cp+6684L, -0xe.1cc12794f6aa77bp+6684L }, - { -0x2.2c7255ce8e0f4f9p-8L, 0x9.0de4b7a3cab1a87p+11120L, -0x1.c83a5890fd2868f2p+11116L, -0x1.c83a5890fd2868fp+11116L }, - { 0x4.ab95d9c4f778dd8p-4L, -0x1.27dd0ddd53988dd4p+628L, -0x6.d512169b928744b8p+624L, -0x6.d512169b928744bp+624L }, - { -0x5.593dab1fc941b63p-8L, 0x7.cba30673cf34e1ep+5956L, -0x3.cca43ab5aa4168d8p+5952L, -0x3.cca43ab5aa4168d4p+5952L }, - { 0x5.6072ba1p-16416L, -0x6.a13f4e0f825a5edp+10340L, -0x3.36d910a4c3e979d8p-6072L, -0x3.36d910a4c3e979d4p-6072L }, - { -0x3.2fe0a04p-16416L, -0x2.37749e13337ef694p+7896L, 0xa.311a8b6de7cbd63p-8520L, 0xa.311a8b6de7cbd64p-8520L }, - { 0x1.52e65c0c28e07afcp-4L, 0x7.11d091eb6c5e7f8p+12968L, 0xc.f8f6054ce2e09fep+12964L, 0xc.f8f6054ce2e09ffp+12964L }, - { -0x1.81ecf5c638b525dcp-4L, 0x1.233a57f1cc4d9d28p+5288L, -0x2.993f1f95e2f6901cp+5284L, -0x2.993f1f95e2f69018p+5284L }, - { 0x1.9a579596fe22accep-4L, -0xe.920450e2df4f23ep+12984L, -0x2.01c6d90f6cf53254p+12984L, -0x2.01c6d90f6cf5325p+12984L }, - { -0x2.357339367c8e7d0cp-4L, 0x6.f8c63462f2be0ffp-9208L, -0x1.7e848fd237f1492ep-9208L, -0x1.7e848fd237f1492cp-9208L }, - { 0x3.b0442b4fcd5e3a68p-4L, -0x6.b2da8740f690432p-11860L, -0x2.013a89ca88d8b8b8p-11860L, -0x2.013a89ca88d8b8b4p-11860L }, - { -0x2.973c8a33f43ce22p-4L, -0x1.40c22b6af128083cp+13388L, 0x5.1be67cad86a0b2b8p+13384L, 0x5.1be67cad86a0b2cp+13384L }, - { 0xc.71fa40b14fe60a5p-8L, -0xd.227d8e4d09d7251p+10336L, -0xe.646cd1236a17ed5p+10332L, -0xe.646cd1236a17ed4p+10332L }, - { -0x2.4b5c7f957978c8dcp-4L, 0x1.d0364f8078ede932p-4432L, -0x6.7a91bf8da9e1b3a8p-4436L, -0x6.7a91bf8da9e1b3ap-4436L }, - { 0xc.9e6826befd572b6p-8L, -0x4.35ecdac82f2a93c8p-10772L, -0x4.ad35c4fc10f2895p-10776L, -0x4.ad35c4fc10f28948p-10776L }, - { -0x1.99c78eacbd3c165cp-4L, -0x2.f570aceb61240648p-8960L, 0x7.32fbbe18c44de7f8p-8964L, 0x7.32fbbe18c44de8p-8964L }, - { 0x1.7c32a28ef3632bb6p-4L, 0xf.72e6996fd117ab3p-5888L, 0x1.fa74fbd79d515e86p-5888L, 0x1.fa74fbd79d515e88p-5888L }, - { -0x6.dfefda162cd8123p-8L, -0x1.67987c998364b8acp-8240L, 0xe.1f4baaf83c19e7bp-8248L, 0xe.1f4baaf83c19e7cp-8248L }, - { 0x1.e4a51bc43235ecccp-4L, -0x1.c45d9255aa8a035ap-8692L, -0x4.8fb7ec77333b0dep-8696L, -0x4.8fb7ec77333b0dd8p-8696L }, - { -0x2.5209ac099a829dcp-4L, 0x1.fa609acc51803e54p+10424L, -0x7.277bc27d907174bp+10420L, -0x7.277bc27d907174a8p+10420L }, - { 0x2.b266769ea2ada0bcp-4L, -0x3.a66d9b79239e456p+11364L, -0xd.1fd5b30e293c2c8p+11360L, -0xd.1fd5b30e293c2c7p+11360L }, - { -0x6.bec5f7d3b060d94p-8L, 0x1.47398ae3841dd2bcp+9232L, -0xc.9b04a2f88f16892p+9224L, -0xc.9b04a2f88f16891p+9224L }, - { 0x2.563eb303d8df1594p-4L, -0x2.cda72aaa85a7383cp-3376L, -0x8.d25687622b560eap-3380L, -0x8.d25687622b560e9p-3380L }, - { -0x3.19894f7cf9935508p-4L, -0x1.6864ac7cb86fcf1ep+11056L, 0x6.ff6e7770c8294bdp+11052L, 0x6.ff6e7770c8294bd8p+11052L }, - { 0x3.1975daa32c02ffep-4L, -0x4.3e136fbe7e156658p+8164L, -0x1.1572cd89e15a791ep+8164L, -0x1.1572cd89e15a791cp+8164L }, - { -0x3.65a7c9cfb4ec9ab8p-4L, -0x2.05a5de13b7dbf81cp-4648L, 0xb.23bea1415cf66bep-4652L, 0xb.23bea1415cf66bfp-4652L }, - { 0x5.0967e18p-16416L, -0xd.64b77ebba612778p+96L, -0x6.152b53b092754e88p-16316L, -0x6.152b53b092754e8p-16316L }, - { -0xc.6c68c8a4d570e25p-200L, -0x3.c05c0d3fc5741314p+9912L, 0x4.33ccc2e9096608dp+9716L, 0x4.33ccc2e9096608d8p+9716L }, - { 0x1.d63714ff39a598ecp-4L, -0x2.ca0aeb11ccacc8dp+10576L, -0x6.ff328ab531d34ad8p+10572L, -0x6.ff328ab531d34adp+10572L }, - { -0x3.e95c9e94baaf75ap-8L, 0x2.b37daf0e4cc15f5cp-6056L, -0xf.5c57a917b87be75p-6064L, -0xf.5c57a917b87be74p-6064L }, - { 0xd.21b0e96ae054bf4p-8L, -0x4.5ad7ee78e07d371p-2356L, -0x5.074bf1af42266298p-2360L, -0x5.074bf1af4226629p-2360L }, - { -0xc.9b1515d090b1ce3p-8L, -0x4.ada9d304af8d7fbp-5952L, 0x5.73fa016de999be4p-5956L, 0x5.73fa016de999be48p-5956L }, - { 0xe.b9d75b04d351c82p-8L, -0x3.85edaba407274158p+4628L, -0x4.8c6a7d6bd001b9c8p+4624L, -0x4.8c6a7d6bd001b9cp+4624L }, - { -0xd.34f3239dcc380fcp-8L, -0xc.06ad79f94cf62e7p+5852L, 0xe.b429eec27adfe9p+5848L, 0xe.b429eec27adfe91p+5848L }, - { 0x4.0c1e5626f9899408p-4L, 0x4.405bbb3021ac0c78p-3692L, 0x1.6215cccd7becd3a4p-3692L, 0x1.6215cccd7becd3a6p-3692L }, - { -0x7.9f4ff67b7c63b818p-8L, 0xa.5aabb9f03fd61adp+14208L, -0x7.39751aa043595f8p+14204L, -0x7.39751aa043595f78p+14204L }, - { 0x1.67e82d241b189066p-4L, -0x2.e37d4d68f3529cf4p-11492L, -0x5.9d9b8b0eb10abbb8p-11496L, -0x5.9d9b8b0eb10abbbp-11496L }, - { -0x4.38ba5d3e626fd8fp-8L, -0x3.172227f2cf0b9c64p-592L, 0x1.2fa8c214228a6956p-596L, 0x1.2fa8c214228a6958p-596L }, - { 0x3.02d0858fe476bc54p-4L, 0xa.26efe8211c025fp+4600L, 0x2.86845b1a66c4dc94p+4600L, 0x2.86845b1a66c4dc98p+4600L }, - { -0x1.7ec8305cbdb5012ap-4L, 0x1.737b8c40ef13706ap-8812L, -0x3.494ee73f4ccbe1cp-8816L, -0x3.494ee73f4ccbe1bcp-8816L }, - { 0x2.685b430bceda8654p-4L, 0x2.2f04308bb4c03ba8p+1352L, 0x7.10d31a9faf05516p+1348L, 0x7.10d31a9faf055168p+1348L }, - { -0x3.e7d21df6c6451cfp-4L, 0xf.38cac992e04dd92p-8384L, -0x6.253d3816519df5p-8384L, -0x6.253d3816519df4f8p-8384L }, - { 0x1.fbff5cc9a151f10ep-4L, 0x2.9be74a9169f983ccp+3984L, 0x7.0a7fb003231082d8p+3980L, 0x7.0a7fb003231082ep+3980L }, - { -0x2.508346b6f97e4b3cp-4L, 0x2.6d5aa9ca35150438p-6664L, -0x8.c1175295f78a7e1p-6668L, -0x8.c1175295f78a7ep-6668L }, - { 0x5.549003e0bc3a306p-8L, -0x2.70cf96f2945f89ap+2768L, -0x1.29379ea6735a5004p+2764L, -0x1.29379ea6735a5002p+2764L }, - { -0x3.fa89daadb8874124p-4L, -0x2.ab88ffd377db8cfp+1852L, 0x1.19f0ebb714ef0082p+1852L, 0x1.19f0ebb714ef0084p+1852L }, - { 0x4.86128b9686d1bdcp-4L, 0x2.078508a7f9bf523cp-14396L, 0xb.a9f3e9f70793d79p-14400L, 0xb.a9f3e9f70793d7ap-14400L }, - { -0x3.e6a1389c4ee6330cp-4L, -0x1.2345feb52b46b768p+10848L, 0x7.56ee97ddf48f583p+10844L, 0x7.56ee97ddf48f5838p+10844L }, - { 0x7.7f79e448p-16416L, -0x5.89900df823ee83c8p+8056L, -0x3.be6252f3b85d24f4p-8356L, -0x3.be6252f3b85d24fp-8356L }, - { -0x1.751bf47b749ae18ep-148L, -0x3.4c815158eac0515cp-14220L, 0x6.efb696954a1d8d3p-14368L, 0x6.efb696954a1d8d38p-14368L }, - { 0x3.d69c812f0a906bd4p-8L, -0xd.06f121a87cad8ccp+3452L, -0x4.79a468a3717e3028p+3448L, -0x4.79a468a3717e302p+3448L }, - { -0x1.4bfbe1c3d5f8ce94p-4L, 0x1.9747531df7189f0cp-7364L, -0x3.1aa2ca71ed8f5fc4p-7368L, -0x3.1aa2ca71ed8f5fcp-7368L }, - { 0xa.44e50bb5c56359cp-8L, -0x2.e250f2584c59c4cp-4520L, -0x2.9e49db540232a5f8p-4524L, -0x2.9e49db540232a5f4p-4524L }, - { -0xd.01531ce3c620f03p-8L, -0x9.056ee6b1e29e3e8p+5472L, 0xa.db6218bc99e8e2bp+5468L, 0xa.db6218bc99e8e2cp+5468L }, - { 0x1.0d530c43cda37932p-4L, 0x2.8bcc9cd9155cb68cp+14312L, 0x3.be202d0192c1a7fp+14308L, 0x3.be202d0192c1a7f4p+14308L }, - { -0x3.39a32a058fcbd9bp-4L, 0xd.4669ea4a5bdd882p+724L, -0x4.4fafa80c4d44f55p+724L, -0x4.4fafa80c4d44f548p+724L }, - { 0xc.1c22b996eb6fc7dp-8L, -0x3.eaca0e062a95276p-1544L, -0x4.2dddffac0b5068ep-1548L, -0x4.2dddffac0b5068d8p-1548L }, - { -0x1.9325d2dfab3eb5d2p-4L, -0x2.710afbcd65e7036cp+4436L, 0x5.d6e783266eb95218p+4432L, 0x5.d6e783266eb9522p+4432L }, - { 0xb.c4d70eca941742ap-8L, 0x3.bac06319b31be118p-3616L, 0x3.de917500e1ea70ep-3620L, 0x3.de917500e1ea70e4p-3620L }, - { -0x9.6a871f761f0c392p-8L, -0x1.592f777d4a7269b4p+6232L, 0x1.2a99e215b4f530d2p+6228L, 0x1.2a99e215b4f530d4p+6228L }, - { 0xe.df857e03ba44519p-8L, -0xc.c83486dca7f8a6cp-1324L, -0x1.0a99133f1e6df45cp-1324L, -0x1.0a99133f1e6df45ap-1324L }, - { -0x1.ae8e54132f4d75fep-4L, -0x2.7ecb7748d3228784p+5356L, 0x6.65a46eeaf16f3928p+5352L, 0x6.65a46eeaf16f393p+5352L }, - { 0x1.82ea01a6ac3c059p-4L, 0x7.98283bcc23ee3c7p-4304L, 0xf.d2b9c546b9e8162p-4308L, 0xf.d2b9c546b9e8163p-4308L }, - { -0x4.332911eac4b16d08p-4L, -0x1.9da5f0f88e76c41cp-3164L, 0xb.5b39fa5929f2c5fp-3168L, 0xb.5b39fa5929f2c6p-3168L }, - { 0x2.a5f0f5ce82c6a948p-4L, -0x5.8738762c85c9f63p+13360L, -0x1.38b6df6f8ec4846p+13360L, -0x1.38b6df6f8ec4845ep+13360L }, - { -0x2.a250e04abfe2cep-4L, 0x1.7f89064b4d7281dcp-6208L, -0x6.387e99c0eb366d48p-6212L, -0x6.387e99c0eb366d4p-6212L }, - { 0x1.533e34fc681e0d64p-4L, -0x6.976ed0ef48c07898p-5156L, -0xc.1b684b6e1d7a6cep-5160L, -0xc.1b684b6e1d7a6cdp-5160L }, - { -0x2.976fa0885b74a0dp-4L, 0x2.6fa1664ea3a1be14p-7544L, -0x9.efb47ad4a474badp-7548L, -0x9.efb47ad4a474bacp-7548L }, - { 0x3.401f19e03339b7d8p-4L, -0x2.e1cf29eba91248ep+14388L, -0xc.4dd22e8eb32e339p+14384L, -0xc.4dd22e8eb32e338p+14384L }, - { -0x2.8bbc0949a8a731bp-4L, 0x3.5cec679bb3f69d98p-9212L, -0xd.73f5e8ad1296da5p-9216L, -0xd.73f5e8ad1296da4p-9216L }, - { 0x7.3ca5eee8p-16416L, -0x1.3bc8b60293078f84p+6520L, -0xc.e0fd8c95f925282p-9896L, -0xc.e0fd8c95f925281p-9896L }, - { -0x3.45c4ac22f9b9fe7p-96L, -0x7.9d640cca80c83b9p-3056L, 0x2.3f397b79fe0ed3dcp-3148L, 0x2.3f397b79fe0ed3ep-3148L }, - { 0x1.48922246e164c31cp-8L, 0x3.251256a4a4974324p-5772L, 0x5.cf00a20473ec53bp-5780L, 0x5.cf00a20473ec53b8p-5780L }, - { -0x2.4e456ef4b9adcafp-4L, 0xf.8fb50e1402f38bp+5532L, -0x3.7e58facfd2d1d0c8p+5532L, -0x3.7e58facfd2d1d0c4p+5532L }, - { 0x1.886dc89c16b624d6p-4L, -0x3.4fa89faae23eda44p+44L, -0x6.fe2f4a64ea4a6c78p+40L, -0x6.fe2f4a64ea4a6c7p+40L }, - { -0x4.350b55034874941p-4L, -0x1.fbcc353d750f0c24p+9096L, 0xd.f83ecea28158477p+9092L, 0xd.f83ecea28158478p+9092L }, - { 0x3.90e10fdba85c0cacp-4L, -0x5.1653c9d362cef54p-13924L, -0x1.7a077ddbf4922fa4p-13924L, -0x1.7a077ddbf4922fa2p-13924L }, - { -0x3.73d037a3672f812cp-4L, 0x3.9b5a02bfcb72b468p-1488L, -0x1.43c84f88af1422acp-1488L, -0x1.43c84f88af1422aap-1488L }, - { 0x1.2b00b6e01f6098dep-4L, -0x7.c7549ce1cd120a6p-2776L, -0xc.a6a5dc751c89f3bp-2780L, -0xc.a6a5dc751c89f3ap-2780L }, - { -0x3.df6b64cd498a6994p-12L, -0x1.c55b237b57929914p-13212L, 0x9.e62d19737b44741p-13224L, 0x9.e62d19737b44742p-13224L }, - { 0x4.32a564d20155332p-4L, 0x1.b1cb6eb8e2ebd224p-2664L, 0x9.1cf96d8b1129d15p-2668L, 0x9.1cf96d8b1129d16p-2668L }, - { -0x3.1c5ee07b5d11cdf4p-4L, 0x1.b5bf8ab3e52d12cp+4216L, -0x8.889eebe2fc21ca4p+4212L, -0x8.889eebe2fc21ca3p+4212L }, - { 0x9.abe18d86bd60c06p-8L, -0x3.d7df89d3dd52449cp+8968L, -0x3.4a2eb51714a7023p+8964L, -0x3.4a2eb51714a7022cp+8964L }, - { -0x3.c6888595ff59158cp-4L, 0x5.ed5d3988224f9748p-192L, -0x2.4d30d9000b4ddc6p-192L, -0x2.4d30d9000b4ddc5cp-192L }, - { 0x1.1d8bff2ec4862e24p-4L, 0x3.034cffddb8433518p-10028L, 0x4.afd48a2d96496ecp-10032L, 0x4.afd48a2d96496ec8p-10032L }, - { -0x2.68737aad1b771f48p-4L, -0xc.afcea80015980b8p+6532L, 0x2.fc425811997eff4cp+6532L, 0x2.fc425811997eff5p+6532L }, - { 0x3.78418dbe89bccdc8p-4L, -0x8.dc01d8b49232a17p-10828L, -0x2.8236ebb32d22f0bp-10828L, -0x2.8236ebb32d22f0acp-10828L }, - { -0x7.61b784fcc75ec3bp-8L, 0xd.233e9cefca1ae41p+14200L, -0x8.df794bc06987c0ap+14196L, -0x8.df794bc06987c09p+14196L }, - { 0x3.d59e590f10746e48p-4L, 0x1.51d6a64294ba9a2ap-10144L, 0x6.8b55a306cdce8dc8p-10148L, 0x6.8b55a306cdce8ddp-10148L }, - { -0x7.28afaf977941c1b8p-8L, 0x4.26f0dae8850886d8p+8496L, -0x2.b7ea3e87e2b0473p+8492L, -0x2.b7ea3e87e2b0472cp+8492L }, - { 0xb.1fed2d782bad9dcp-8L, 0x4.a6abc93b905e715p-4876L, 0x4.91230a64c6e7b4bp-4880L, 0x4.91230a64c6e7b4b8p-4880L }, - { -0x4.07a79631c2281c9p-8L, 0xe.f5d12aeb5942b6bp+228L, -0x5.7ab5bf59532e948p+224L, -0x5.7ab5bf59532e9478p+224L }, - { 0x1.6ee95808p-16416L, 0x5.a07bbf49b0583bbp-9900L, 0x0p+0L, 0x8p-16448L }, - { -0x3.863ad23f9793533p-48L, -0x7.1c785eecfe17605p+3708L, 0x2.428413a21a98386cp+3664L, 0x2.428413a21a98387p+3664L }, - { 0x1.e7dd2eadf3394a16p-4L, 0x3.c1009cb5b2a38294p+4932L, 0x9.c046f0b4f3b69c4p+4928L, 0x9.c046f0b4f3b69c5p+4928L }, - { -0x3.d60f5fcdb37d8eap-4L, 0x1.dc3545b0a8acecf4p+12372L, -0xb.c54051f027930e7p+12368L, -0xb.c54051f027930e6p+12368L }, - { 0x2.5d3d714a0d0272bp-4L, 0x1.e6cbc995a44d6c2cp-1388L, 0x6.0c99b457b89474e8p-1392L, 0x6.0c99b457b89474fp-1392L }, - { -0x1.278a728bb66b64dep-4L, -0xc.9cb7f96b11f2a04p-1236L, 0x1.5cd64e58107b75aep-1236L, 0x1.5cd64e58107b75bp-1236L }, - { 0x2.1df7b3b08b64e3dp-4L, 0x3.dacf3b11609eff4p-88L, 0xb.0e98a5a6b729862p-92L, 0xb.0e98a5a6b729863p-92L }, - { -0x2.c12eb8612105f50cp-4L, -0x3.d5d13ddf2d02994cp+1880L, 0x1.0ba055798a93cce6p+1880L, 0x1.0ba055798a93cce8p+1880L }, - { 0x4.42ffed1cfdb04edp-4L, 0xb.83e125a36a30824p-8028L, 0x3.ec4c0c7e99dcab2cp-8028L, 0x3.ec4c0c7e99dcab3p-8028L }, - { -0x2.bd3a518dddcd87d8p-4L, 0xa.f782f5eeaaf84b2p-976L, -0x2.f88ebb9a09ff9754p-976L, -0x2.f88ebb9a09ff975p-976L }, - { 0xa.a48014f31d21f5p-8L, 0x1.787d684fec780e28p-13432L, 0x1.61fb236d58d214e6p-13436L, 0x1.61fb236d58d214e8p-13436L }, - { -0x1.d95a03b300a7839p-4L, -0x1.402a0ef3d21d78eap+11592L, 0x3.8b94b58f3dd5ddd8p+11588L, 0x3.8b94b58f3dd5dddcp+11588L }, - { 0x3.ea3ece65229e7c1cp-4L, -0x1.02df530bdd4a2488p+5252L, -0x5.1bf7eec74ce67c5p+5248L, -0x5.1bf7eec74ce67c48p+5248L }, - { -0xa.4c31201905c5915p-8L, 0x2.4b18c689eb5ab8dp-1928L, -0x2.2c6611b3ab947174p-1932L, -0x2.2c6611b3ab94717p-1932L }, - { 0x3.e691a4a4ec98c938p-4L, -0x5.cd17b52b8b67c0d8p-10292L, -0x1.d36cada1fee74204p-10292L, -0x1.d36cada1fee74202p-10292L }, - { -0x2.3da4f3249dc52684p-4L, -0xf.34520f86c43a674p+3372L, 0x3.4f42e88d8003846p+3372L, 0x3.4f42e88d80038464p+3372L }, - { 0x3.c7cd16a9c4870a48p-8L, -0x4.8c156b51b3e8457p+10772L, -0x1.89e922297cbf68aap+10768L, -0x1.89e922297cbf68a8p+10768L }, - { -0x2.b0eebddd240923ep-4L, -0x5.29574a08fac443ep-12084L, 0x1.5f0f8e898258fbacp-12084L, 0x1.5f0f8e898258fbaep-12084L }, - { 0x2.249c8a89d03aa864p-4L, -0xd.13cf8aa40b87d27p+11728L, -0x2.5f197166ecfbca14p+11728L, -0x2.5f197166ecfbca1p+11728L }, - { -0x4.6f21e629b4f6c5e8p-4L, -0x2.f5e77b1943eaf884p+6012L, 0x1.62d8f7d63feb95f8p+6012L, 0x1.62d8f7d63feb95fap+6012L }, - { 0x4.15fd44d5e86bc01p-4L, 0x5.473ae34b6e2063cp-4768L, 0x1.bb5a721b7a439e0ap-4768L, 0x1.bb5a721b7a439e0cp-4768L }, - { -0x2.ca05f449ee9bba2p-4L, 0x6.a835c5372554956p-9312L, -0x1.d6f4ea6ae1e36da8p-9312L, -0x1.d6f4ea6ae1e36da6p-9312L }, - { 0x3.38e23638p-16416L, 0xd.b64a7582d1883d4p+7568L, 0x3.fbe211139f2c5e74p-8844L, 0x3.fbe211139f2c5e78p-8844L }, - { -0x2.c0eede3d08af0a04p-96L, -0x1.9cc6ff87f9582b36p-8292L, 0x6.67d3fa6766d44f5p-8388L, 0x6.67d3fa6766d44f58p-8388L }, - { 0x3.657fca1541630014p-4L, 0xa.5555080b30f60b8p+12212L, 0x2.deab71182cd05b2cp+12212L, 0x2.deab71182cd05b3p+12212L }, - { -0x2.15a5a3d39fca9d74p-8L, 0x4.ba3ed0a011dad9c8p+11960L, -0xe.4691fded533e7dp+11952L, -0xe.4691fded533e7cfp+11952L }, - { 0x2.820600a7b4b8b6c8p-4L, 0x1.434edd70f5ea7b82p-7912L, 0x4.3eacdda95f716048p-7916L, 0x4.3eacdda95f71605p-7916L }, - { -0x4.76729a8ab5f9d168p-4L, -0x3.f2ca785573e18f44p-6872L, 0x1.dcdaf54fb1102d4cp-6872L, 0x1.dcdaf54fb1102d4ep-6872L }, - { 0x1.b28350368d79329p-4L, -0x5.bd5227673487f808p+13568L, -0xd.5b9b9a020b995c7p+13564L, -0xd.5b9b9a020b995c6p+13564L }, - { -0x4.422aeed297423dfp-4L, 0xd.6dbe42d94446092p-5372L, -0x5.fec8d99f836824e8p-5372L, -0x5.fec8d99f836824ep-5372L }, - { 0x2.b4c82511d6b8adbp-4L, -0x2.58c6fae544166138p-10216L, -0x8.770e6e77fa12c41p-10220L, -0x8.770e6e77fa12c4p-10220L }, - { -0x3.603dab982401c2fp-4L, 0xd.c28e13e36928e3ap-12400L, -0x4.b458ff98a77bea88p-12400L, -0x4.b458ff98a77bea8p-12400L }, - { 0x2.52993b67468165dp-4L, 0xe.abf2bcc7641993cp+4800L, 0x2.de7fd921b9b3f348p+4800L, 0x2.de7fd921b9b3f34cp+4800L }, - { -0x2.ffc62e45c4920ca8p-4L, -0x9.e0554ee54c3f10cp+2864L, 0x2.f5240374ef1e8fa4p+2864L, 0x2.f5240374ef1e8fa8p+2864L }, - { 0x1.d76afc41248078d8p-4L, 0x1.96be670b6795cd66p+4484L, 0x3.fecd39da987d611p+4480L, 0x3.fecd39da987d6114p+4480L }, - { -0x1.1fe55dbba061231cp-4L, -0x2.3f0e956a9cc93b7cp-2808L, 0x3.c768e818370d0554p-2812L, 0x3.c768e818370d0558p-2812L }, - { 0x4.7ffbbb9da4656abp-4L, 0x1.883501d399ebe686p-2052L, 0x8.c3b8d2ed744ac29p-2056L, 0x8.c3b8d2ed744ac2ap-2056L }, - { -0x2.e7771c3617428004p-4L, 0x4.aa305910d4a5b948p-14036L, -0x1.5913b10b6f6bb312p-14036L, -0x1.5913b10b6f6bb31p-14036L }, - { 0x1.f51f691570542864p-4L, -0x7.ff805590540d7e68p-8240L, -0x1.54f0cc2a744adbep-8240L, -0x1.54f0cc2a744adbdep-8240L }, - { -0x2.bc9523828d7c744p-4L, -0x5.f8c2890bff7a53a8p-4408L, 0x1.9db92d87363ce3a4p-4408L, 0x1.9db92d87363ce3a6p-4408L }, - { 0xb.cface8db66432b4p-8L, -0x1.52f8d17d3ef509ep-14136L, -0x1.60ecc5e5445bc5fap-14140L, -0x1.60ecc5e5445bc5f8p-14140L }, - { -0x3.c4fcb83a4348059p-4L, -0x6.92589a2ad057f888p+14032L, 0x2.8c0de6f4f4ad5a8p+14032L, 0x2.8c0de6f4f4ad5a84p+14032L }, - { 0xd.3e73c6c392e1b2cp-16L, -0x1.9d39baf7c3757386p-7232L, -0x1.ed6b25bf930609f2p-7244L, -0x1.ed6b25bf930609fp-7244L }, - { -0x1.2be18a59c6c0cb46p-4L, -0x5.2f34ad391bf16bep+14208L, 0x9.194f55dcdc049ddp+14204L, 0x9.194f55dcdc049dep+14204L }, - { 0x1.6ea2622p-16416L, 0xd.0a61c31aa71a8b4p+192L, 0x1.af1b0b9011702c9cp-16220L, 0x1.af1b0b9011702c9ep-16220L }, - { -0xe.24746d350747p-76L, -0x6.2cd68ac90fd809cp-20L, 0x7.dfe1c92e972b245p-92L, 0x7.dfe1c92e972b2458p-92L }, - { 0x3.172ad4e89020bdc4p-4L, -0x7.5d68336e21e50738p-10576L, -0x1.e05e86f2c4aaa87p-10576L, -0x1.e05e86f2c4aaa86ep-10576L }, - { -0x1.1cc46bd3cc5d5eep-4L, 0x8.dfe337c5f8f4ed8p-2964L, -0xe.c2e4fcc9056e939p-2968L, -0xe.c2e4fcc9056e938p-2968L }, - { 0x1.6aec81e28b750398p-4L, 0x6.d60397f1aab8875p+5068L, 0xd.65769829a5eb6bbp+5064L, 0xd.65769829a5eb6bcp+5064L }, - { -0xa.dd9db54ce301e4fp-8L, 0x2.994e7862cafbb18p-9172L, -0x2.9a10f7c79bc8a514p-9176L, -0x2.9a10f7c79bc8a51p-9176L }, - { 0x3.4c1067ae36f3df8p-4L, 0x5.e39292b71e3bd29p-14656L, 0x1.97849d850815a968p-14656L, 0x1.97849d850815a96ap-14656L }, - { -0x3.2716db715997395cp-4L, -0x3.7b95a736d2a03acp-2972L, 0x1.1a47ea03f6df2b3p-2972L, 0x1.1a47ea03f6df2b32p-2972L }, - { 0x3.511564feccb7ade4p-4L, 0xa.3be5fc2351c749fp+8708L, 0x2.c808aa921e98c90cp+8708L, 0x2.c808aa921e98c91p+8708L }, - { -0x3.69c632e288b42e7cp-4L, 0x2.6cfab89ec92c9a94p+12520L, -0xd.6f501c63d843bbp+12516L, -0xd.6f501c63d843bafp+12516L }, - { 0xd.50c03549bb8a308p-8L, -0xd.bb307fe5c0a193dp+11920L, -0x1.0125a0d31814385ap+11920L, -0x1.0125a0d318143858p+11920L }, - { -0x4.62f76781cd43fa1p-4L, 0x6.add388611cf3e0dp-5568L, -0x3.166b1e48e4d0d538p-5568L, -0x3.166b1e48e4d0d534p-5568L }, - { 0x2.af134161b98b158cp-4L, -0x6.b78672290432052p+4200L, -0x1.80b269a8acd58f28p+4200L, -0x1.80b269a8acd58f26p+4200L }, - { -0x4.07400317e3bbdf6p-4L, 0x4.6f0a1bd0504232fp-4560L, -0x1.daf3ffdcfaf5a3fcp-4560L, -0x1.daf3ffdcfaf5a3fap-4560L }, - { 0x3.e2c42f99082b0694p-8L, -0x2.23235efc5d063d1cp+484L, -0xb.e43a884083a14cdp+476L, -0xb.e43a884083a14ccp+476L }, - { -0x2.510f0edafa423e34p-4L, 0x8.ea166668cb9c597p-728L, -0x2.02f35e07c5b586ep-728L, -0x2.02f35e07c5b586dcp-728L }, - { 0x2.87d8f5995c149e84p-4L, -0x1.fd41fdd489dd6b86p-4740L, -0x6.be1d42ef4ae7d568p-4744L, -0x6.be1d42ef4ae7d56p-4744L }, - { -0x4.91cd3914269e7f4p-4L, -0x7.5908781b4662a448p+4676L, 0x3.90a7abc41bfff254p+4676L, 0x3.90a7abc41bfff258p+4676L }, - { 0x1.a5cddc11ef6ac702p-4L, -0x5.101df29586f07ac8p+14844L, -0xb.7475b0a9b9616e6p+14840L, -0xb.7475b0a9b9616e5p+14840L }, - { -0x2.59a788d1463d5708p-4L, 0x5.93f40353ef748448p-6680L, -0x1.4747090652a60d3p-6680L, -0x1.4747090652a60d2ep-6680L }, - { 0x2.70458f50e301850cp-4L, -0x2.bbcb14f8c8df1858p+4120L, -0x8.f3733a06672424fp+4116L, -0x8.f3733a06672424ep+4116L }, - { -0x1.edb5a0fdb59e0032p-4L, 0x1.8d559c866804202p-7668L, -0x4.9a064be7a218d8bp-7672L, -0x4.9a064be7a218d8a8p-7672L }, - { 0x5.5e55df7p-16416L, 0x1.d91cda789c52cbdp+4364L, 0xe.504ec49dde8ab29p-12052L, 0xe.504ec49dde8ab2ap-12052L }, - { -0x2.3345c79170f14c5p-180L, -0xb.f1c6659cf21c7f9p-4736L, 0x2.5ea6960e05da9f88p-4912L, 0x2.5ea6960e05da9f8cp-4912L }, - { 0x3.0afb26c30345b6c8p-4L, 0x2.302e0468775a2cfp+3692L, 0x8.cb4da2d9809cb86p+3688L, 0x8.cb4da2d9809cb87p+3688L }, - { -0x3.1a5317d464e8bcd8p-4L, -0xf.5f00a957d87468bp-352L, 0x4.c7dab607b60b8738p-352L, 0x4.c7dab607b60b874p-352L }, - { 0x2.f8e069607dea9234p-4L, -0x3.684738cd5ffb438p-4096L, -0xd.66adc86b056b9e4p-4100L, -0xd.66adc86b056b9e3p-4100L }, - { -0x1.68f2cde5ae072e6ep-4L, 0xb.6bb5e3b9506b364p+1724L, -0x1.851c08718da5d4e4p+1724L, -0x1.851c08718da5d4e2p+1724L }, - { 0x2.23ce11d6341a8aacp-4L, 0x1.455660f0dbaacbacp-9204L, 0x3.aea780e4a73a96e4p-9208L, 0x3.aea780e4a73a96e8p-9208L }, - { -0x2.135127bb12ede30cp-4L, 0xa.d8293b85a4bffcfp+12080L, -0x2.2c758719e47f09d8p+12080L, -0x2.2c758719e47f09d4p+12080L }, - { 0x1.33cb1ea0c84f5a1ap-4L, 0xa.2e25e1b057a53d2p-9672L, 0x1.106c68c29be5ecd4p-9672L, 0x1.106c68c29be5ecd6p-9672L }, - { -0x1.fa3c2eb2e9308f1cp-4L, -0xd.079788536be471ap+5984L, 0x2.7ad9dd04bd787d68p+5984L, 0x2.7ad9dd04bd787d6cp+5984L }, - { 0x3.5875e63760a4466p-4L, -0x1.e565eb8bd950bb6cp-6104L, -0x8.4f709e7bba8e058p-6108L, -0x8.4f709e7bba8e057p-6108L }, - { -0x1.3f197fa4514cf7c2p-4L, 0x7.dc189a6904687248p-3956L, -0xe.b70fcbf84500736p-3960L, -0xe.b70fcbf84500735p-3960L }, - { 0x2.98ff74bb0396e2a8p-4L, -0x6.cc6bb049840d2788p+3184L, -0x1.79c15ad6f10263bcp+3184L, -0x1.79c15ad6f10263bap+3184L }, - { -0x1.e92034fc00fd7a98p-4L, -0x3.e5597d53f64ac974p-2504L, 0xb.6faf807e0f4e0a3p-2508L, 0xb.6faf807e0f4e0a4p-2508L }, - { 0x4.24c32dc8985a08d8p-4L, 0xd.eaf2679d518cbcap-5988L, 0x4.9fc9e3020022b7cp-5988L, 0x4.9fc9e3020022b7c8p-5988L }, - { -0x2.a33049d338912ac4p-4L, -0x1.f3b94e68042c5dc8p-11892L, 0x8.1dde7a4bbda2816p-11896L, 0x8.1dde7a4bbda2817p-11896L }, - { 0x2.ba130b3c4d1f4e8p-4L, 0x6.0af61fcd08d308f8p-15004L, 0x1.5f378240ba9a69fep-15004L, 0x1.5f378240ba9a6ap-15004L }, - { -0xb.1ce64865e029d5fp-8L, 0x1.ff55919d9667cf4cp+13108L, -0x2.0bd3af3af36c6e6cp+13104L, -0x2.0bd3af3af36c6e68p+13104L }, - { 0xe.294e92a7a26e0f2p-12L, 0x1.0329cf12c0f4735cp-9924L, 0x1.4a5b55d460c69b9ep-9932L, 0x1.4a5b55d460c69bap-9932L }, - { -0xf.2e554c655733393p-8L, -0x1.63b6624e7048c69p-13664L, 0x1.f5f341a9df85c5ep-13668L, 0x1.f5f341a9df85c5e2p-13668L }, - { 0x4.19c6d69c8374d198p-8L, 0x3.3c77b09aeb197434p-5576L, 0x1.2fe6936fb94fa2a6p-5580L, 0x1.2fe6936fb94fa2a8p-5580L }, - { -0x6.0496537484fa208p-8L, -0x6.c8226dd9ecd375ap-9856L, 0x3.b95264ba207a26p-9860L, 0x3.b95264ba207a2604p-9860L }, - { 0x3.6687889ff8995454p-36L, -0xa.ea939bccf0c7a07p+1528L, -0x3.58de478a3f4ba21p+1496L, -0x3.58de478a3f4ba20cp+1496L }, - { -0x2.7f156648p-16416L, -0x4.f40ef5608acb05ep-1128L, 0x0p+0L, 0x8p-16448L }, - { 0x4.8500f80b4fa4a34p-4L, -0x7.3625bf44a443e3f8p+5176L, -0x2.96a1ca8ead93767p+5176L, -0x2.96a1ca8ead93766cp+5176L }, - { -0x3.1e76ef016909914cp-4L, 0x7.115b116b66f8aa4p-12752L, -0x2.36042efa2987b7a8p-12752L, -0x2.36042efa2987b7a4p-12752L }, - { 0x1.145e8982b98005cp-4L, -0x5.d05179f09dc2d33p-13872L, -0x8.c32eaca7f2e537ap-13876L, -0x8.c32eaca7f2e5379p-13876L }, - { -0x6.48d061b769787a38p-8L, -0x1.22c95177a19486ep-7144L, 0xa.6d51af264791aebp-7152L, 0xa.6d51af264791aecp-7152L }, - { 0x1.3733136f320f9f84p-4L, -0x1.8a40d2261f03957ep+4176L, -0x2.9a6c6aca7935b768p+4172L, -0x2.9a6c6aca7935b764p+4172L }, - { -0x1.358688a586adbbf8p-4L, -0x6.56cb6fd63dca8b9p+9600L, 0xb.7f5f931dd5eb2eep+9596L, 0xb.7f5f931dd5eb2efp+9596L }, - { 0x5.449fa70eef370f58p-8L, -0x1.a1b184553cda78ap+7432L, -0xc.465569d2c326a9ep+7424L, -0xc.465569d2c326a9dp+7424L }, - { -0x2.92231a70c5780dap-4L, 0xa.2782912323620c5p-4824L, -0x2.90e7e4c7728e0584p-4824L, -0x2.90e7e4c7728e058p-4824L }, - { 0x2.b59d7e039fdf9904p-4L, -0x2.459d427616b15588p+4412L, -0x8.344523d1b10cf33p+4408L, -0x8.344523d1b10cf32p+4408L }, - { -0xc.2393bad0835b34cp-8L, -0x7.ee687fee5c4ec2b8p+3820L, 0x8.e4ce378035800c9p+3816L, 0x8.e4ce378035800cap+3816L }, - { 0x3.cb172495f4e11098p-4L, -0x1.867b118a15199e4ep-6280L, -0x7.7dad976d917e1cd8p-6284L, -0x7.7dad976d917e1cdp-6284L }, - { -0x4.4abd064ca0fe822p-4L, -0x5.919372e384ec19cp-4452L, 0x2.8252a05d4039be14p-4452L, 0x2.8252a05d4039be18p-4452L }, - { 0x4.3035264bc9659e2p-4L, -0x9.90137db5d8438f6p+5028L, -0x3.3533f8369942f288p+5028L, -0x3.3533f8369942f284p+5028L }, - { -0x2.a02f7f8f2a33579p-4L, -0x1.74dc31e3b9305bc4p+8180L, 0x6.06d01869bfc02898p+8176L, 0x6.06d01869bfc028ap+8176L }, - { 0x2.0f8e4cbcc27850d8p-4L, -0x2.fa91e626f345fb28p-14588L, -0x8.549922eac21ecdp-14592L, -0x8.549922eac21eccfp-14592L }, - { -0x2.1fc557b50c931d24p-4L, -0xf.a038fe23264b69fp+14704L, 0x3.360291be1344afe4p+14704L, 0x3.360291be1344afe8p+14704L }, - { 0x1.b69ca8d925216fc6p-4L, 0x1.d578671f39a6b79p+4996L, 0x4.4e6ab61dbdffe2b8p+4992L, 0x4.4e6ab61dbdffe2cp+4992L }, - { -0x4.8660d1e7a3a18068p-4L, 0xc.9a201e4897d0226p+7292L, -0x6.0b24b9cb8f96233p+7292L, -0x6.0b24b9cb8f962328p+7292L }, - { 0x2.804eb8772ea477cp-4L, -0xd.c98d7189a0303bfp-9228L, -0x2.e39b75a1ab637314p-9228L, -0x2.e39b75a1ab63731p-9228L }, - { -0x5.f071a27eaa54e38p-8L, 0x1.775823e9c3c2806cp+3976L, -0xc.b60896a0bc1c55ep+3968L, -0xc.b60896a0bc1c55dp+3968L }, - { 0x1.7d19bf9b2f768d26p-136L, -0x2.d94140f31f8c61bp-1620L, -0x6.1e39086add179f3p-1756L, -0x6.1e39086add179f28p-1756L }, - { -0x7.e376b0bp-16416L, 0x1.3247488c5d03274ep+8560L, -0xd.9dad2138f46abb9p-7856L, -0xd.9dad2138f46abb8p-7856L }, - { 0x1.6343494b7816dd6p-4L, 0x1.24f1b7414cd3e44p+8680L, 0x2.3272b4a13c6b0828p+8676L, 0x2.3272b4a13c6b082cp+8676L }, - { -0x1.c03717a7400b18dep-4L, -0x2.32aa0ac2a73accfcp+12680L, 0x5.e131f8511a6780ap+12676L, 0x5.e131f8511a6780a8p+12676L }, - { 0x3.9639abe76c1e22b4p-4L, -0x1.aad25e3bbb5c92c2p-716L, -0x7.c8d239822cb8acep-720L, -0x7.c8d239822cb8acd8p-720L }, - { -0x1.6f8de0a23eb23f08p-4L, -0x2.a959c77ea7aa43ecp+988L, 0x5.c6b591b2a7e072ep+984L, 0x5.c6b591b2a7e072e8p+984L }, - { 0x3.0493f6bd3e7a9d08p-4L, 0x2.3b45ef80edb12e4p-7692L, 0x8.e68e11e3908f565p-7696L, 0x8.e68e11e3908f566p-7696L }, - { -0x3.4ebaefe2e6c2ffd4p-4L, -0xe.87ffc2cdbdd0a59p-888L, 0x4.dada35190941404p-888L, 0x4.dada351909414048p-888L }, - { 0x3.c04aa41676d3a1dcp-4L, 0x5.c671189eaee79d8p-3112L, 0x1.c13ec20855e228fap-3112L, 0x1.c13ec20855e228fcp-3112L }, - { -0xd.84c80ecec0dfc24p-8L, -0xa.41831a7d42bf933p+524L, 0xc.d7fd375ea441b22p+520L, 0xc.d7fd375ea441b23p+520L }, - { 0x3.9b18f252e9cc6204p-4L, -0xc.541234ac6a41dbfp+2520L, -0x3.9d66104d07c6c03cp+2520L, -0x3.9d66104d07c6c038p+2520L }, - { -0x9.01dc33c60cb85cfp-8L, 0x7.ff05934f4c4c383p-13868L, -0x6.9c7c08044a14d7b8p-13872L, -0x6.9c7c08044a14d7bp-13872L }, - { 0x2.c31e22698d11a4ecp-4L, -0x1.8a1311226a2cf3dp+14616L, -0x5.a8a6f3b45150fea8p+14612L, -0x5.a8a6f3b45150feap+14612L }, - { -0x3.c76e6f9502a10174p-4L, -0xd.cd06a7b980fe0dp-4668L, 0x5.5d5541ea4ee0ea48p-4668L, 0x5.5d5541ea4ee0ea5p-4668L }, - { 0x8.77c988605043e5bp-8L, 0x1.6982403523b43efap-8420L, 0x1.0f8f240be8bbfaa6p-8424L, 0x1.0f8f240be8bbfaa8p-8424L }, - { -0x2.574faa96bdd3213p-4L, 0xc.503b4e17876b4f8p-696L, -0x2.cf6c154995d02d98p-696L, -0x2.cf6c154995d02d94p-696L }, - { 0x4.0e6b69653c7259cp-4L, 0xf.ea4c84120426686p-4116L, 0x5.30298b34abe7e7cp-4116L, 0x5.30298b34abe7e7c8p-4116L }, - { -0x2.6a84e1dc3ed5b358p-4L, 0x6.681d1a92ea56e508p-8188L, -0x1.8359cb0bb17a3c26p-8188L, -0x1.8359cb0bb17a3c24p-8188L }, - { 0x2.43c341781144525p-4L, 0x1.2c0b226e839776bap-1564L, 0x3.94dda02c158a4d1p-1568L, 0x3.94dda02c158a4d14p-1568L }, - { -0x3.5ce4a1fe88889f1cp-4L, -0x5.d49892159ff7aeb8p-5000L, 0x1.fc1549257f8001eap-5000L, 0x1.fc1549257f8001ecp-5000L }, - { 0x9.d9c0516a61c2fd1p-8L, 0x5.d5a66b8dfa047b5p+6780L, 0x5.15ca590d0fb17b28p+6776L, 0x5.15ca590d0fb17b3p+6776L }, - { -0x7.ce5459cf45b18448p-8L, -0x1.37c211415835776cp+3656L, 0xd.ed8c6d47ece27fcp+3648L, 0xd.ed8c6d47ece27fdp+3648L }, - { 0x3.6aa98df8p-16416L, 0x3.3644cdf8f7e5e378p-5876L, 0x0p+0L, 0x8p-16448L }, - { -0x4.95ee308p-16420L, 0x7.44556257ec455fb8p-8352L, -0x8p-16448L, -0x0p+0L }, - { 0x1.f6845a417bd06bd4p-4L, 0x2.8d6b4f3f8a5ae1d8p-4092L, 0x6.d171ba168e7c00c8p-4096L, 0x6.d171ba168e7c00dp-4096L }, - { -0x3.362ee1134557b0c8p-4L, -0x6.44d1e706f42b9218p-14364L, 0x2.06becf0cbf15a76cp-14364L, 0x2.06becf0cbf15a77p-14364L }, - { 0x1.29ad0ab6b39c71e8p-4L, 0x8.3abf84f84659fbfp+6884L, 0xd.53ad29e0460e74bp+6880L, 0xd.53ad29e0460e74cp+6880L }, - { -0x2.7323c21f31ee0c94p-4L, 0x1.ac8d253b449af046p-12608L, -0x6.6bf33ea54480fb38p-12612L, -0x6.6bf33ea54480fb3p-12612L }, - { 0x3.d0edb25b17c3c3c8p-4L, -0x1.e23087ac1fc0803ep-1112L, -0x9.4ce21b7a005ec4p-1116L, -0x9.4ce21b7a005ec3fp-1116L }, - { -0x1.defb373d645dd7fcp-4L, 0x2.b1b352e26c101b48p+196L, -0x7.bbe0c9d1fb10f57p+192L, -0x7.bbe0c9d1fb10f568p+192L }, - { 0x3.db8c171e647ac154p-4L, 0x3.bd7064bc96439e88p-8072L, 0x1.2a5b636788b866a6p-8072L, 0x1.2a5b636788b866a8p-8072L }, - { -0x2.157c312f0a7331dcp-4L, 0x1.d519eadd05d80046p+3776L, -0x5.e7076a49325e2b2p+3772L, -0x5.e7076a49325e2b18p+3772L }, - { 0x6.13dd8fa1bb5a0888p-8L, 0xd.e1d14a94f3f3513p-14348L, 0x7.84c2d6dc58e0033p-14352L, 0x7.84c2d6dc58e00338p-14352L }, - { -0xc.a7a4a0836807865p-8L, 0xa.6cd4c82b6c3ad8fp-14052L, -0xc.332a5ac869f5485p-14056L, -0xc.332a5ac869f5484p-14056L }, - { 0x3.e4981e366529f448p-4L, -0x1.c855bc869ec45c56p-2360L, -0x8.f5fa49da4d36b7cp-2364L, -0x8.f5fa49da4d36b7bp-2364L }, - { -0x1.3df73a344e1df3cep-4L, -0x8.b6f7624f6d4b8fap+4364L, 0x1.0415fd3b8843c92ap+4364L, 0x1.0415fd3b8843c92cp+4364L }, - { 0xf.71e1693aabd6949p-8L, -0x9.67429de92a0cc45p+13180L, -0xc.b7344f5f174184ap+13176L, -0xc.b7344f5f1741849p+13176L }, - { -0x2.e92c6340870d1904p-4L, 0x6.3a68ed7dc2ab1b18p+1772L, -0x1.cde5ffd73bb78894p+1772L, -0x1.cde5ffd73bb78892p+1772L }, - { 0x1.6638437083b5e5cep-4L, -0xa.51a3936a6af3cc4p-9740L, -0x1.3f86597d7dfbb25ap-9740L, -0x1.3f86597d7dfbb258p-9740L }, - { -0x5.e85b2872af8b8768p-8L, -0x1.05a0268fc1493582p-6052L, 0x8.cff240ac67268dbp-6060L, 0x8.cff240ac67268dcp-6060L }, - { 0x2.dfdc0c89ab932644p-4L, -0x1.a6d9620079c35e76p-14696L, -0x6.4caa08299af24148p-14700L, -0x6.4caa08299af2414p-14700L }, - { -0x4.15f357d7796b39f8p-4L, -0xd.0f27ddc214b3d5fp+2272L, 0x5.8e1f34fcf9c6555p+2272L, 0x5.8e1f34fcf9c65558p+2272L }, - { 0x3.0e9f50108a3ff43cp-4L, -0x6.c4cc122615b61d18p+7552L, -0x1.b51cb1eca74aff38p+7552L, -0x1.b51cb1eca74aff36p+7552L }, - { -0x4.4a7f16c7046c96c8p-4L, -0x2.981ff7909e578104p-14228L, 0x1.2b286a2c567ea818p-14228L, 0x1.2b286a2c567ea81ap-14228L }, - { 0x5.ef34f4p-16420L, -0x1.214299eebb91926ap+7320L, -0x9.ac829743b8c0f05p-9100L, -0x9.ac829743b8c0f04p-9100L }, - { -0x1.691f3828p-16416L, 0x1.efebf2a3b96734aep+3408L, -0x3.f141a8e9339c907cp-13008L, -0x3.f141a8e9339c9078p-13008L }, - { 0x1.4e8c937c8e553dcp-4L, -0x1.3035f2318b0be00ep-6620L, -0x2.27538394a1b35e5cp-6624L, -0x2.27538394a1b35e58p-6624L }, - { -0x7.5976854fcf9031fp-8L, -0x6.11bab7a888287f3p-312L, 0x4.14b5a5ddbd843bdp-316L, 0x4.14b5a5ddbd843bd8p-316L }, - { 0x1.705c9e77f96a731cp-4L, 0x3.d432ed3f654d8a28p-2564L, 0x7.9c73705bb807b3p-2568L, 0x7.9c73705bb807b308p-2568L }, - { -0x4.9a5360d861aaa4e8p-4L, 0x1.1531b287e936aff2p-6580L, -0x8.7a86ebb8c48bafp-6584L, -0x8.7a86ebb8c48baefp-6584L }, - { 0x3.aed6e32454d1f618p-4L, 0x1.296010316396f574p-10016L, 0x5.8e0d53264bbb5658p-10020L, 0x5.8e0d53264bbb566p-10020L }, - { -0x6.40fd50816f8157b8p-8L, 0x6.4b02ec16879cadc8p-3652L, -0x3.97bb59c7052cc938p-3656L, -0x3.97bb59c7052cc934p-3656L }, - { 0x2.2873a4ee7791f16cp-4L, -0x1.5e183567b5058b64p-6240L, -0x3.fe783fc7ec0a3e54p-6244L, -0x3.fe783fc7ec0a3e5p-6244L }, - { -0x4.91ca4444446e025p-4L, 0x1.8871ecc06666a8b8p+6540L, -0xb.e684deb0c4ea1a1p+6536L, -0xb.e684deb0c4ea1ap+6536L }, - { 0x5.f63f2f14fa25c78p-8L, 0x7.f61f9817342409ap+6848L, 0x4.3b14e17bad193658p+6844L, 0x4.3b14e17bad19366p+6844L }, - { -0x3.73b374e9d6f1b14cp-4L, 0x1.a766304af3ed99eap-11340L, -0x9.472a21f120494b4p-11344L, -0x9.472a21f120494b3p-11344L }, - { 0x3.8a6aa9bc55f2078p-8L, -0x6.2c58a861a1cf29a8p+5396L, -0x1.f514ecea291b833ep+5392L, -0x1.f514ecea291b833cp+5392L }, - { -0xd.f5a19cfa9847764p-8L, -0x1.9ead8227db0f911cp-9848L, 0x2.18ba56217d205048p-9852L, 0x2.18ba56217d20504cp-9852L }, - { 0x1.03b2429f433bd84p-4L, 0x7.6174df81f989a0fp-5988L, 0xa.7924c7723ddc533p-5992L, 0xa.7924c7723ddc534p-5992L }, - { -0x1.1908bf815764d01ep-4L, 0x6.b0ac0d83a33409dp+4848L, -0xa.fa080088ed7f3f8p+4844L, -0xa.fa080088ed7f3f7p+4844L }, - { 0x4.187fb9c09c55f5ep-4L, -0x2.670dd27ee7f45a3cp-10212L, -0xc.a3d27b26df9ae5ep-10216L, -0xc.a3d27b26df9ae5dp-10216L }, - { -0x4.aded544e99e15d3p-4L, -0x1.fb63b223d8b85776p-12512L, 0xf.d3fc75e67e5697dp-12516L, 0xf.d3fc75e67e5697ep-12516L }, - { 0x9.f5a904e0a16b75p-12L, 0x6.b6db5486fa8da28p-4968L, 0x6.05bb9a21b9c5695p-4976L, 0x6.05bb9a21b9c56958p-4976L }, - { -0x3.7ea985070d82c5dcp-4L, 0x7.8ed5f1582d74d94p+13856L, -0x2.afe9bbfb32eedff4p+13856L, -0x2.afe9bbfb32eedffp+13856L }, - { 0x8.ceca186af1571abp-8L, -0x4.aa7a2e0b9a249038p+5868L, -0x3.a4aded1bd7f30504p+5864L, -0x3.a4aded1bd7f305p+5864L }, - { -0x8.fd7657912a84383p-8L, -0x1.1c18c670ecb47d26p-8016L, 0xe.a6fa205a23754cep-8024L, 0xe.a6fa205a23754cfp-8024L }, - { 0x1.2af0c6bp-16416L, 0x2.e55845c69ebf1658p+3336L, 0x4.e0ef355e6d13fa58p-13080L, 0x4.e0ef355e6d13fa6p-13080L }, - { -0x1.9a9d144p-16416L, -0x1.2b2e1b630ba1b3b6p+2664L, 0x2.b44f5c0dc1564e68p-13752L, 0x2.b44f5c0dc1564e6cp-13752L }, - { 0x2.3f11da078aa8a478p-4L, -0xb.2315f89420146ccp+8064L, -0x2.1c631386d9d9fc94p+8064L, -0x2.1c631386d9d9fc9p+8064L }, - { -0x3.019d6e7999c6dddcp-4L, 0x1.3f86f58ae2fdd6dcp-7640L, -0x5.ff0fffae46c8157p-7644L, -0x5.ff0fffae46c81568p-7644L }, - { 0xb.4e40f5e1d904b61p-8L, 0x6.532f0bc4c2ab27fp-13652L, 0x6.4f362dc573683e08p-13656L, 0x6.4f362dc573683e1p-13656L }, - { -0x2.80eab5330cc1f32cp-4L, -0x3.005426a19639d6bp+14296L, 0xb.c9efe6146589be6p+14292L, 0xb.c9efe6146589be7p+14292L }, - { 0x2.12c9e15ad0b4a958p-4L, 0x1.504150487ac4b4e4p-13364L, 0x3.b1cb463da2f231cp-13368L, 0x3.b1cb463da2f231c4p-13368L }, - { -0xc.1c5be79cff6476p-8L, 0xc.0c6b1b1a302ca68p+14360L, -0xd.7a7df9fc3108fap+14356L, -0xd.7a7df9fc3108f9fp+14356L }, - { 0x3.1bac1512e32d6aa8p-4L, -0xf.6312e170067d25bp-3972L, -0x3.f0d8177d9054014cp-3972L, -0x3.f0d8177d90540148p-3972L }, - { -0x1.519f2ae231695ea2p-4L, 0x5.5400fe4d2a5ab7f8p-8900L, -0xa.947c24f62e74fcdp-8904L, -0xa.947c24f62e74fccp-8904L }, - { 0x2.a65946c7f23f31acp-4L, 0x4.7a751384d759865p+8672L, 0xf.d77ddbba6b11fd9p+8668L, 0xf.d77ddbba6b11fdap+8668L }, - { -0x2.cd037a11f9213844p-4L, -0xd.6910092b63029a8p-1592L, 0x3.b91ac58ce049a54p-1592L, 0x3.b91ac58ce049a544p-1592L }, - { 0x3.9db1e0144ed66a8cp-8L, 0x1.d28289f977ace56p-32L, 0x9.70a6bb89b1c4544p-40L, 0x9.70a6bb89b1c4545p-40L }, - { -0x2.621a3f5edf1bfa3cp-4L, -0x3.5c6f2312eb314f6p-8832L, 0xc.835eabfeaf37f45p-8836L, 0xc.835eabfeaf37f46p-8836L }, - { 0x3.8c641d8c7144c56cp-4L, -0xd.9ccf64003bcfe19p-2164L, -0x3.ef094c1261084a5cp-2164L, -0x3.ef094c1261084a58p-2164L }, - { -0x4.a18f061049fc9cbp-4L, 0x1.e06defabb32ffe1ep+1648L, -0xe.cd74e842dc9ff13p+1644L, -0xe.cd74e842dc9ff12p+1644L }, - { 0x4.97f2306d8c28e9dp-4L, -0x1.2a39e2ab6ffe536p-536L, -0x6.c970e37e84181a4p-540L, -0x6.c970e37e84181a38p-540L }, - { -0x2.e236a258e6dd6b5cp-4L, 0x3.2f025f0ea7bb3938p+7324L, -0xe.9aad918f2225785p+7320L, -0xe.9aad918f2225784p+7320L }, - { 0x3.1c35592c972c292cp-4L, -0x3.d19015724427ff7p+5180L, -0xf.a85299ffafa135ep+5176L, -0xf.a85299ffafa135dp+5176L }, - { -0x4.2943e5b07a55b8cp-4L, -0xa.9469f6ae3a4e6f4p+1964L, 0x4.98efa780ae2c64e8p+1964L, 0x4.98efa780ae2c64fp+1964L }, - { 0xe.c4a37f159ae949ep-8L, 0x1.c776d3c51e49998ap-4852L, 0x2.4da7c80b031f717cp-4856L, 0x2.4da7c80b031f718p-4856L }, - { -0x8.b6721f00e89d647p-8L, -0x3.76d26cae7f3a370cp-10612L, 0x2.c4d3a29814e11f84p-10616L, 0x2.c4d3a29814e11f88p-10616L }, - { 0x1.d44862fbc3ffe4e8p-112L, 0xb.b4e151abbff7d07p-5376L, 0x1.ee4d3e9b98db0a2ap-5484L, 0x1.ee4d3e9b98db0a2cp-5484L }, - { -0x2.12dbeddf1c572d24p-140L, 0x2.ff042155d43837b8p-456L, -0x8.f6a8f33c480a7f2p-596L, -0x8.f6a8f33c480a7f1p-596L }, - { 0x2.3c7141110977a1c8p-4L, 0x2.05648cc457e12568p-13128L, 0x6.1a52ec074b18dfc8p-13132L, 0x6.1a52ec074b18dfdp-13132L }, - { -0x2.464f6995d5846fc4p-4L, 0x5.b10ee7beb80f44c8p-8176L, -0x1.4257e6f5e91cfddep-8176L, -0x1.4257e6f5e91cfddcp-8176L }, - { 0x2.9d621c7f336f1a48p-4L, -0x1.d8b4cd85d3888762p-52L, -0x6.73a5b1d70e5b209p-56L, -0x6.73a5b1d70e5b2088p-56L }, - { -0x4.6cbaaf7a0ff40348p-4L, -0x1.9ebb345e0fe9f626p+152L, 0xc.1b0a270a799060ap+148L, 0xc.1b0a270a799060bp+148L }, - { 0x2.d68e2ba3eefebbfcp-4L, 0x8.2755e9d53631d79p+13464L, 0x1.ebbd2662baaccf46p+13464L, 0x1.ebbd2662baaccf48p+13464L }, - { -0x2.a56af544d1743bfp-4L, -0x8.debe114eff2fb6p-4048L, 0x2.503fe5daad061f4cp-4048L, 0x2.503fe5daad061f5p-4048L }, - { 0x2.f272a3677efcea3p-4L, -0x1.65eed16b0fbcd18p+3820L, -0x5.74cf60355c5bfdd8p+3816L, -0x5.74cf60355c5bfddp+3816L }, - { -0x3.a8152a324eb599fcp-4L, 0x6.42f937c40f3caep-11832L, -0x2.580a107ac781e86cp-11832L, -0x2.580a107ac781e868p-11832L }, - { 0x1.fa90f8ba8eb45d18p-4L, 0x4.97d111ff563d917p+672L, 0xc.5cc95af0b67a1aap+668L, 0xc.5cc95af0b67a1abp+668L }, - { -0x3.21d6a286a61d7cc4p-4L, -0xe.6ac05f4362737a7p-1760L, 0x4.8804f700b3804178p-1760L, 0x4.8804f700b380418p-1760L }, - { 0x3.bcec63e4fa22720cp-4L, 0x1.eb48022e5de68778p-2240L, 0x9.4cf74bdc0e3abdap-2244L, 0x9.4cf74bdc0e3abdbp-2244L }, - { -0x2.2cafb74c417a862cp-4L, -0x7.4ac89cd8c8343a4p+5320L, 0x1.896adaaf74423c38p+5320L, 0x1.896adaaf74423c3ap+5320L }, - { 0x4.747d8f2cd1e0b778p-4L, -0x7.89b9fbbca8b068b8p-10904L, -0x2.abdd7d16fc67e358p-10904L, -0x2.abdd7d16fc67e354p-10904L }, - { -0x1.6c4d52d87e228112p-4L, -0x6.db5f46e906978aa8p+6068L, 0xe.be49f013bde4911p+6064L, 0xe.be49f013bde4912p+6064L }, - { 0x4.7d3fe6ab59f609d8p-4L, -0x3.440be44d83299c4p+7040L, -0x1.2a4c3c114199e58ep+7040L, -0x1.2a4c3c114199e58cp+7040L }, - { -0x1.e480cff01c28fb9cp-4L, -0x4.d9f9d12975bd7c4p-12344L, 0xe.190f113ed0925d4p-12348L, 0xe.190f113ed0925d5p-12348L }, - { 0x2.8861f994981bf17cp-4L, -0xd.f58d50699b9fcecp+1284L, -0x2.f59c17dbe51eda7p+1284L, -0x2.f59c17dbe51eda6cp+1284L }, - { -0x3.1a3b6bf5fdf6fd38p-4L, -0x1.fc2d15ef2a625dacp+8468L, 0x9.e07f594916cb5fcp+8464L, 0x9.e07f594916cb5fdp+8464L }, - { 0x3.fd8b6443df9dc76p-4L, 0x6.2216263345a9de58p-3452L, 0x1.f85e4c88ba163cd4p-3452L, 0x1.f85e4c88ba163cd6p-3452L }, - { -0x3.70a228d1d553bf4cp-4L, -0x2.eb67d254460cc304p-9620L, 0x1.0504afba5f5c67a6p-9620L, 0x1.0504afba5f5c67a8p-9620L }, - { 0x5.cf949cfc0d27367p-152L, -0x3.05788e2f35ec3cd4p+14300L, -0x1.9543d4ed5bd3f968p+14152L, -0x1.9543d4ed5bd3f966p+14152L }, - { -0x4.019728c8p-16416L, 0x6.86d9d7ed1e2fc6p-12528L, -0x8p-16448L, -0x0p+0L }, - { 0x9.e6cc5abae024698p-8L, 0x2.833fcfa47e2d91ap+3004L, 0x2.33784faf5903c048p+3000L, 0x2.33784faf5903c04cp+3000L }, - { -0x3.67b9dd9843d29348p-4L, -0xf.d97f1711de15f9cp+1908L, 0x5.78d0d081f721bp+1908L, 0x5.78d0d081f721b008p+1908L }, - { 0x4.7a28ab2398fb352p-4L, 0x1.9bd5eed22e819bdep-3276L, 0x9.2974b9b5c14f70bp-3280L, 0x9.2974b9b5c14f70cp-3280L }, - { -0x3.081509267e970864p-4L, -0xd.1b186c2e3417901p+1864L, 0x3.f8d299ebb41104fp+1864L, 0x3.f8d299ebb41104f4p+1864L }, - { 0x4.6abc9681ac49cfdp-4L, -0x2.95224c7756c21458p+0L, -0xe.8847182bcf70294p-4L, -0xe.8847182bcf70293p-4L }, - { -0x7.2739454a8f4579bp-8L, 0x4.6f28415fd23d939p+14200L, -0x2.e698128be4a28434p+14196L, -0x2.e698128be4a2843p+14196L }, - { 0x1.d251fdcff8361a78p-4L, -0xb.d0fe6ed90e574e6p+212L, -0x1.d68b3c44dd6d6312p+212L, -0x1.d68b3c44dd6d631p+212L }, - { -0x1.be7ad3ad1b0e4a4p-4L, -0x6.497aa8a74bb2d87p-2628L, 0x1.0bfe1bb4299021acp-2628L, 0x1.0bfe1bb4299021aep-2628L }, - { 0x4.013e3e7e82bd3c2p-4L, 0x7.4bbb894be77050dp+12468L, 0x2.59ee0420ec379c6p+12468L, 0x2.59ee0420ec379c64p+12468L }, - { -0x3.3293e00e66ee8678p-4L, -0x5.530558acc4b5df88p-6048L, 0x1.b66bd84ef8a7f7aep-6048L, 0x1.b66bd84ef8a7f7bp-6048L }, - { 0x2.596e2190f3ee11cp-4L, -0x2.cd6c97393ef343bcp+1120L, -0x8.dcd9e903e4f5e01p+1116L, -0x8.dcd9e903e4f5ep+1116L }, - { -0xe.c481fc40bbce19fp-8L, 0x1.3b4ac09f6ebd1b0ep+1796L, -0x1.b06e1e656074da7p+1792L, -0x1.b06e1e656074da6ep+1792L }, - { 0x2.9f321f282784f3acp-4L, -0x1.d9decdb4b87520d6p+8416L, -0x6.7bdfcc4fcaf35388p+8412L, -0x6.7bdfcc4fcaf3538p+8412L }, - { -0x3.1abd020d7e543628p-4L, 0xd.6d80dc94539115ep-6852L, -0x4.2dbeb1b3e077f1ep-6852L, -0x4.2dbeb1b3e077f1d8p-6852L }, - { 0x1.a74119aefdfb086ap-4L, 0x1.4dd68c499218991cp-9528L, 0x2.f5c7d01357aeb918p-9532L, 0x2.f5c7d01357aeb91cp-9532L }, - { -0x3.9cc7932ded57df7p-4L, 0x1.c00dbd725f27ace4p+392L, -0xa.5694f0b8c0a7444p+388L, -0xa.5694f0b8c0a7443p+388L }, - { 0x3.0c65989eee333da8p-4L, -0xc.8ed445e1ea26da6p+944L, -0x3.28d9b866e998f3p+944L, -0x3.28d9b866e998f2fcp+944L }, - { -0x1.01dc461ca1f30d7cp-4L, 0x2.219473696b04364cp+5028L, -0x3.32e1826689d1e408p+5024L, -0x3.32e1826689d1e404p+5024L }, - { 0x2.032a2322395b1f7cp-4L, -0x5.da9f94100d42a778p+4556L, -0x1.00234c58a1593fa4p+4556L, -0x1.00234c58a1593fa2p+4556L }, - { -0x1.37d775d6d37abbc6p-4L, -0xd.e2cee7a54e7c7dfp-2844L, 0x1.961ce3d5d092c2bcp-2844L, 0x1.961ce3d5d092c2bep-2844L }, - { 0x5.e788f67p-16416L, -0x1.b20009ea27ed12d4p+2716L, -0xe.70f136a6f3fd9c9p-13700L, -0xe.70f136a6f3fd9c8p-13700L }, - { -0xe.54631f1d0a92519p-108L, 0x2.3b61b0ed36fec68cp-11996L, -0x2.e245772cd7482448p-12100L, -0x2.e245772cd7482444p-12100L }, - { 0x4.78666b09054db02p-4L, 0xd.9866ac659888197p-12280L, 0x4.d525ce8fca3be678p-12280L, 0x4.d525ce8fca3be68p-12280L }, - { -0x2.b6ea5b47429cf1ccp-8L, 0x2.6614f05e9e7a9d2cp+13784L, -0x9.71b7a8a09362cc3p+13776L, -0x9.71b7a8a09362cc2p+13776L }, - { 0x1.9fc564d5cd252834p-4L, -0x7.78b432f287942418p+8704L, -0x1.0ac7c8898679cf7cp+8704L, -0x1.0ac7c8898679cf7ap+8704L }, - { -0x3.627629b0fc2138f4p-4L, 0x2.4adc5340e0bb85bp-14064L, -0xc.93a314133e66097p-14068L, -0xc.93a314133e66096p-14068L }, - { 0xd.e2670359c5e7cep-8L, 0x1.776c2223c9793e74p+7492L, 0x1.c9b37d76bc51a286p+7488L, 0x1.c9b37d76bc51a288p+7488L }, - { -0x1.ea4c7df916a93fa4p-4L, 0x1.77873596c55066eap-4292L, -0x4.512b68b4a46ce678p-4296L, -0x4.512b68b4a46ce67p-4296L }, - { 0x7.782d2513f5714bdp-8L, -0xd.cf27b2fef93cd6fp+900L, -0x9.2ae14b6070abef1p+896L, -0x9.2ae14b6070abefp+896L }, - { -0x4.40fc24e1abcef118p-4L, -0x1.acf23a9f7fc1bac6p+4612L, 0xb.f42951fd6c23841p+4608L, 0xb.f42951fd6c23842p+4608L }, - { 0x1.a8824a9a4cd5dc64p-4L, -0x1.c0f84566366a7b42p-1364L, -0x3.fdfecdec46081674p-1368L, -0x3.fdfecdec4608167p-1368L }, - { -0x2.656451181fd48ae8p-4L, -0x8.112f7800783ce43p+14416L, 0x1.e35a03c5b235c0bp+14416L, 0x1.e35a03c5b235c0b2p+14416L }, - { 0x8.870c70596055849p-8L, 0x1.07c83cf4f6c4df66p+2828L, 0xc.7855e9bc9829172p+2820L, 0xc.7855e9bc9829173p+2820L }, - { -0x2.b8afdde3454b599p-4L, 0x2.8eebc607cfde77d8p-8824L, -0xb.027de4727525e58p-8828L, -0xb.027de4727525e57p-8828L }, - { 0x2.31f1d5227156b604p-4L, -0x1.2b06750af8061c3p+4092L, -0x3.77668bc7db26768p+4088L, -0x3.77668bc7db26767cp+4088L }, - { -0x2.032456443411d81p-4L, -0xb.f31c2fef2a2645fp-1980L, 0x2.5131763f6e042228p-1980L, 0x2.5131763f6e04222cp-1980L }, - { 0x1.3042297b1a544afep-4L, 0x3.f1be09c7487defap+14152L, 0x6.8612fdbf3a6c6758p+14148L, 0x6.8612fdbf3a6c676p+14148L }, - { -0x4.20c8cc889aaca378p-4L, 0x1.6010a2abc0602b0ep-14432L, -0x9.791e17dde1c914ep-14436L, -0x9.791e17dde1c914dp-14436L }, - { 0x2.776cad4e7559584cp-8L, 0xb.e51e58c1c7b3dbfp+14964L, 0x2.a1fe9ebfdf8a86ap+14960L, 0x2.a1fe9ebfdf8a86a4p+14960L }, - { -0xf.b02a1730396127ep-8L, -0xc.11b48ff5e5ec64ep+7368L, 0x1.19e46bdcea15f47cp+7368L, 0x1.19e46bdcea15f47ep+7368L }, - { 0x4.1edb9c5a8639aaap-4L, 0x1.bbf840a1aee939e4p+13432L, 0x9.2c66ade98f2991ep+13428L, 0x9.2c66ade98f2991fp+13428L }, - { -0x2.e5ef99ea8924db7p-4L, 0x3.5a17dd1b1d7f10fcp-12416L, -0xf.76499bc4522f185p-12420L, -0xf.76499bc4522f184p-12420L }, - { 0x5.2ceb4e8ad3a63198p-56L, 0x1.10226b66be92f5ep-13504L, 0x7.efec9208539fa86p-13560L, 0x7.efec9208539fa868p-13560L }, - { -0x1.609defa4c28c41aap-68L, -0x1.9abae50c07573824p-3260L, 0x3.3032106521e2a38p-3328L, 0x3.3032106521e2a384p-3328L }, - { 0x1.17954e967e739b96p-4L, 0xf.d9c4d8361d42b6cp-12924L, 0x1.828a9fe2da6d8d6ap-12924L, 0x1.828a9fe2da6d8d6cp-12924L }, - { -0x2.9a3fed5ce81a8d6cp-4L, -0xc.5a8bd8936a03dp-13656L, 0x3.29f77393bb45b71cp-13656L, 0x3.29f77393bb45b72p-13656L }, - { 0x2.c752af068bb180e4p-4L, 0x3.de670419142bc428p-14816L, 0xe.4cd016833918784p-14820L, 0xe.4cd016833918785p-14820L }, - { -0x3.2082fc347aa2e55p-4L, 0x4.e64b83b064446a3p+10008L, -0x1.89807286643a3178p+10008L, -0x1.89807286643a3176p+10008L }, - { 0x2.79eaa550e420d934p-4L, 0x1.f2ae9ee8ba0d3204p-868L, 0x6.786a2bba8c07b1dp-872L, 0x6.786a2bba8c07b1d8p-872L }, - { -0xa.fc3eb30d9c09d39p-8L, -0x2.5ab3fc8e3cf96824p-2280L, 0x2.622ee8401eb2be9p-2284L, 0x2.622ee8401eb2be94p-2284L }, - { 0x3.d81a8d8a8d16a8e8p-4L, -0x3.ce388047558bafc8p-8232L, -0x1.2ea2546e51c6e8f4p-8232L, -0x1.2ea2546e51c6e8f2p-8232L }, - { -0x3.056f019da2d3178cp-4L, -0x1.323a89ec36541c0cp+6516L, 0x5.c74b2bd614a49e08p+6512L, 0x5.c74b2bd614a49e1p+6512L }, - { 0x2.bc32f485a0d1cda4p-4L, -0x2.80bd89a1c7a42c04p+10352L, -0x9.1e18f19057194f5p+10348L, -0x9.1e18f19057194f4p+10348L }, - { -0x1.680e5f4f178505bp-4L, -0xf.1a49a93ff5772ep-1880L, 0x2.0138ef578553b23p-1880L, 0x2.0138ef578553b234p-1880L }, - { 0x2.fc8ccc84ce54f5d4p-8L, 0x3.e472948a7445df58p+11256L, 0x1.0ac7c7a20eca1108p+11252L, 0x1.0ac7c7a20eca110ap+11252L }, - { -0x4.6e1a1a157ff363bp-4L, -0x9.7fc1e541c82e26dp+12412L, 0x4.7151555968fe228p+12412L, 0x4.7151555968fe2288p+12412L }, - { 0x2.58ccc597cdeae488p-4L, 0xf.172c9598837df0ep-3292L, 0x2.fad4e99f0ed6a2ap-3292L, 0x2.fad4e99f0ed6a2a4p-3292L }, - { -0x3.2be4288461f1d2ccp-4L, 0xf.f5f8e2e97cc43a7p-6300L, -0x5.16417a8368ea715p-6300L, -0x5.16417a8368ea7148p-6300L }, - { 0x1.fdf693f75f71c5f8p-4L, 0xf.1536891b917c5b4p-12272L, 0x2.8da7609b1e39234p-12272L, 0x2.8da7609b1e392344p-12272L }, - { -0x3.2561fe08d06ed66p-4L, -0xa.bc73aa7d823faf6p-2276L, 0x3.641e7eed6d3d515cp-2276L, 0x3.641e7eed6d3d516p-2276L }, - { 0x1.1bc04a8e9588d6d2p-8L, -0x1.c52369a0cacff0aep-688L, -0x2.d30b2a4ee51c61dcp-696L, -0x2.d30b2a4ee51c61d8p-696L }, - { -0x1.d61ba0502067409ep-4L, 0x3.73d3d6eaa64d0e48p-13916L, -0x9.b7284d8b255d1e5p-13920L, -0x9.b7284d8b255d1e4p-13920L }, - { 0x1.c4a0b08d7654ecb4p-4L, 0x1.b5b6c832a020e5ecp-4332L, 0x4.2306f7cb22efbd4p-4336L, 0x4.2306f7cb22efbd48p-4336L }, - { -0x3.a5b84c3a8b5a86d8p-4L, 0x3.33e3dabe68c35688p+1484L, -0x1.3206409c6c6fc45p+1484L, -0x1.3206409c6c6fc44ep+1484L }, - { 0x9.dcdfcf8p-16420L, -0x5.4a43e598fc3723cp-9444L, -0x8p-16448L, -0x0p+0L }, - { -0x7.c97e52a8p-16416L, -0x4.c1408d8a28bcc7ep+10200L, 0x3.56b150006e157e34p-6212L, 0x3.56b150006e157e38p-6212L }, - { 0x5.83b36a0816afd008p-8L, 0x6.728edc7190e888ap-8300L, 0x3.2bfe0fbf8883065p-8304L, 0x3.2bfe0fbf88830654p-8304L }, - { -0x1.a6bb6ebf8bf709p-4L, -0x1.32eaa51c63cff0c2p-12444L, 0x3.03b810bfb07b3e04p-12448L, 0x3.03b810bfb07b3e08p-12448L }, - { 0x3.adb8baaf789553dp-4L, 0x7.b3f922ab6d1fc2d8p-11600L, 0x2.4cbe69773df6c864p-11600L, 0x2.4cbe69773df6c868p-11600L }, - { -0x1.201e22e464402deap-4L, -0x3.bcdf6b0e23c23b8p-3112L, 0x6.4b04dff5faf1ab6p-3116L, 0x6.4b04dff5faf1ab68p-3116L }, - { 0xa.db12b542cfd4967p-8L, -0x2.cc4f4ec335a9b73p-3480L, -0x2.aeb2bfd2569213f8p-3484L, -0x2.aeb2bfd2569213f4p-3484L }, - { -0x1.4bacae5b8139ebf4p-4L, 0x3.018ab0d86a85aa18p-2564L, -0x5.dbfb9574a7700e9p-2568L, -0x5.dbfb9574a7700e88p-2568L }, - { 0xc.37926f622957e79p-8L, 0x6.d9a09257a9de7178p-9644L, 0x7.5f1b82a670566b2p-9648L, 0x7.5f1b82a670566b28p-9648L }, - { -0x2.ab328a75d78456d4p-4L, 0x3.984ce041f93d20dcp+8376L, -0xf.246f0c6123fd2c2p+8372L, -0xf.246f0c6123fd2c1p+8372L }, - { 0x5.0ac37ce140a5e408p-8L, 0xc.85f521d6b73e5cp-12304L, 0x5.a35e190d7bbadde8p-12308L, 0x5.a35e190d7bbaddfp-12308L }, - { -0x2.84eaed8e54bf7608p-4L, -0x3.b386e93fc25a36ep-120L, 0xe.a327ea760c0cc07p-124L, 0xe.a327ea760c0cc08p-124L }, - { 0x3.20e1ecc2bf932e94p-4L, -0x4.f0d6473e6cf14dbp-10104L, -0x1.45e1efc080d53264p-10104L, -0x1.45e1efc080d53262p-10104L }, - { -0x3.af399facb8e06b6cp-4L, -0x1.a6fe04423bc64194p-2412L, 0x9.fb819c61aa22e65p-2416L, 0x9.fb819c61aa22e66p-2416L }, - { 0xd.f2607f2eff81943p-8L, 0x1.db63aa1cc3714696p+5352L, 0x2.461d3054010ba93cp+5348L, 0x2.461d3054010ba94p+5348L }, - { -0x2.1ca9e269366503acp-4L, 0x8.85ca099da14eecfp+11944L, -0x1.bd9606e084b91422p+11944L, -0x1.bd9606e084b9142p+11944L }, - { 0x3.8f814c8a783b37e4p-4L, 0xc.dc92cfd134c1f43p+8032L, 0x3.ba705b78dbdfdb08p+8032L, 0x3.ba705b78dbdfdb0cp+8032L }, - { -0xa.363a7e007bb490cp-8L, 0x3.4fc1153a0181986p+2104L, -0x3.1c9855bfaf3c0b24p+2100L, -0x3.1c9855bfaf3c0b2p+2100L }, - { 0x4.8f405305d971325p-4L, 0x1.68828b76a000f3cap+10416L, 0x8.2690c5f0b9e8f9ep+10412L, 0x8.2690c5f0b9e8f9fp+10412L }, - { -0x3.338c408bb3a0c4a8p-4L, -0xe.159d1696dfd0e91p+10916L, 0x4.894cf2237970296p+10916L, 0x4.894cf22379702968p+10916L }, - { 0x4.8f4674e0d5a0d808p-4L, 0xa.c362f68453e1677p+3476L, 0x3.e4bf65fe96e2af2p+3476L, 0x3.e4bf65fe96e2af24p+3476L }, - { -0xd.54b8a67fe103072p-8L, 0x2.cdcd722c20086f78p-9008L, -0x3.7618e9e91de0ea8cp-9012L, -0x3.7618e9e91de0ea88p-9012L }, - { 0x1.7902a678p-16416L, 0x1.19427dcda0480416p+3436L, 0x2.559440aae40e6a3p-12980L, 0x2.559440aae40e6a34p-12980L }, - { -0x1.c36218d9ea12b06p-120L, -0xc.ce2bca2cbcab86p+11308L, 0x2.092f42c661962da4p+11192L, 0x2.092f42c661962da8p+11192L }, - { 0x4.3848af1238619848p-4L, 0x1.06b2c98753a26482p+4016L, 0x5.8b6a91a3e86c1628p+4012L, 0x5.8b6a91a3e86c163p+4012L }, - { -0x2.1a3e861da87eb79cp-4L, 0x1.4ec5569f83ab5736p-9836L, -0x4.40aa56c3c5c637e8p-9840L, -0x4.40aa56c3c5c637ep-9840L }, - { 0x1.0ae262cde6391e24p-4L, 0x5.73257b4e6064d01p+6604L, 0x7.f0d1589033cf2398p+6600L, 0x7.f0d1589033cf23ap+6600L }, - { -0x4.27fce65cac88f6e8p-4L, -0x1.f57725c0787861ecp-3256L, 0xd.99b231a6d0c4c1dp-3260L, 0xd.99b231a6d0c4c1ep-3260L }, - { 0x3.a27dda9eab4a71cp-4L, -0x1.c7f592e6977ce3bep+12420L, -0x8.6a945925111c26ep+12416L, -0x8.6a945925111c26dp+12416L }, - { -0x2.a793421cbf6f9968p-4L, 0x5.48fc6bc3d7c0194p+1292L, -0x1.621d63e8f5d14274p+1292L, -0x1.621d63e8f5d14272p+1292L }, - { 0x4.0c3cdf0761d114bp-4L, -0x1.a94536dcae3efe9ap-4444L, -0x8.a5f06bea2cc4c7bp-4448L, -0x8.a5f06bea2cc4c7ap-4448L }, - { -0xa.f93df896ce6a1p-8L, -0x5.c36184a826a997c8p+10672L, 0x5.d40fc05d1c8d8c78p+10668L, 0x5.d40fc05d1c8d8c8p+10668L }, - { 0x4.166c1433f1fd7bbp-4L, -0x3.fd85a4b30da5905cp+1568L, -0x1.4f4bec3a523108b4p+1568L, -0x1.4f4bec3a523108b2p+1568L }, - { -0x4.269ac20097d48278p-4L, 0x3.1537ec91418ea6d4p+3920L, -0x1.55f44918ad45177p+3920L, -0x1.55f44918ad45176ep+3920L }, - { 0x4.69a871365aa2e12p-4L, -0xa.36231bab07402b6p-4836L, -0x3.9699940c44fff68p-4836L, -0x3.9699940c44fff67cp-4836L }, - { -0x2.e0e69529aa3c2148p-4L, -0xc.898efcf06fac3c9p-10916L, 0x3.96631e40f648290cp-10916L, 0x3.96631e40f648291p-10916L }, - { 0x8.0d6f02cf24f9c97p-8L, 0x2.6ae43fbbb8290e98p+8564L, 0x1.ba711272f9e989e8p+8560L, 0x1.ba711272f9e989eap+8560L }, - { -0x3.5f039ab81ea9c368p-4L, -0xd.8fb34ea26dcd466p+10808L, 0x4.a10f4862e4c525c8p+10808L, 0x4.a10f4862e4c525dp+10808L }, - { 0x1.3d60e214e24fd8e2p-4L, -0x1.570c61df14ef3c2cp+188L, -0x2.4ef6c43084fc9dep+184L, -0x2.4ef6c43084fc9ddcp+184L }, - { -0x6.40ba95b8e8b92fc8p-8L, 0x1.be3c2fefa23edde8p-11668L, -0xf.eb712b3687d7e23p-11676L, -0xf.eb712b3687d7e22p-11676L }, - { 0x2.732d3b1aa6d2beep-4L, -0x3.cdaf1e5edd4c86p+184L, -0xc.821fcc2bcca0a5dp+180L, -0xc.821fcc2bcca0a5cp+180L }, - { -0x2.152e0397420f72fcp-4L, 0x2.8364ae6977782604p-11632L, -0x8.172bae23dd68d33p-11636L, -0x8.172bae23dd68d32p-11636L }, - { 0x3.e5df21cab65c997cp-4L, -0xf.2ffda7297446dd8p+564L, -0x4.c6f49497a19568p+564L, -0x4.c6f49497a19567f8p+564L }, - { -0x1.04b57b83b68184dep-4L, -0x4.ea4ab92cea09eec8p+11136L, 0x7.762e3332d594d7fp+11132L, 0x7.762e3332d594d7f8p+11132L }, - { 0x5.5594498p-16420L, 0x1.eabcf8252879b3c6p-2564L, 0x0p+0L, 0x8p-16448L }, - { -0x4.c0ce2b247d038ac8p-196L, 0x6.aab669b77225bdf8p+14936L, -0x2.db7821b4f7e6fe48p+14744L, -0x2.db7821b4f7e6fe44p+14744L }, - { 0x3.baced53f1471e364p-4L, 0x1.f4152fd9e1338794p+11508L, 0x9.72c9bd6a87c42aap+11504L, 0x9.72c9bd6a87c42abp+11504L }, - { -0x2.317130a7a75d4aa4p-4L, 0x4.3a585af61da3746p+10124L, -0xe.63319f6181f397cp+10120L, -0xe.63319f6181f397bp+10120L }, - { 0x4.1c54e5eb63fd28fp-4L, -0xc.0148aba29b8d557p-13200L, -0x3.f5d7e7e9f34a935cp-13200L, -0x3.f5d7e7e9f34a9358p-13200L }, - { -0x3.a93752f48b02534p-8L, 0x2.d86805c835243508p+7344L, -0xf.2300d704ac6742ep+7336L, -0xf.2300d704ac6742dp+7336L }, - { 0xc.f022cc79b221c33p-8L, -0x1.7bce210b7a3b4ce4p+13136L, -0x1.b03f9fb7b732302cp+13132L, -0x1.b03f9fb7b732302ap+13132L }, - { -0x3.2a0c0f7441062828p-4L, -0x3.b3492f1fb9e61c04p+5492L, 0x1.2d25592e5dfb1a5p+5492L, 0x1.2d25592e5dfb1a52p+5492L }, - { 0x1.5e4534702331dd36p-4L, 0xe.23089b23489992ap-8584L, 0x1.ac6bc81aca47148ep-8584L, 0x1.ac6bc81aca47149p-8584L }, - { -0xb.335bf0873459e2ap-8L, -0x2.d5f5698f339a3b6cp+12224L, 0x2.edb30cd4b7211294p+12220L, 0x2.edb30cd4b7211298p+12220L }, - { 0x2.a703a7cbf8389048p-4L, -0x3.c02be3f7a5fcc11p-10844L, -0xd.479c75b64677e6ep-10848L, -0xd.479c75b64677e6dp-10848L }, - { -0x4.6a8b51e9bd44a3d8p-4L, -0x9.16e2136af0bd999p+5352L, 0x4.3c3d2021a09b0ccp+5352L, 0x4.3c3d2021a09b0cc8p+5352L }, - { 0x2.2dedef8b8456de34p-4L, -0x1.612ac453131ff6ccp+12644L, -0x4.110b3f69085532bp+12640L, -0x4.110b3f69085532a8p+12640L }, - { -0xc.1dba691316d74bdp-8L, 0x2.ec398343a2ca763p-1556L, -0x3.456805b257b0ee1p-1560L, -0x3.456805b257b0ee0cp-1560L }, - { 0xe.ec733d0bbf8686ep-8L, -0x3.cf1395284a6357fp-6892L, -0x4.fb48374fa922b608p-6896L, -0x4.fb48374fa922b6p-6896L }, - { -0x1.edcef2a6b293fd46p-4L, -0x5.f75c87391b381cb8p+12600L, 0x1.1b1516b3d9f8b04cp+12600L, 0x1.1b1516b3d9f8b04ep+12600L }, - { 0x1.1ee70cc7cae8441ap-4L, 0xd.5bd215637191857p-9180L, 0x1.4e0453af199cc7d6p-9180L, 0x1.4e0453af199cc7d8p-9180L }, - { -0x1.3b763982b3071dd4p-4L, 0x9.e9da1b99800a76dp-4788L, -0x1.256fd3aa961492bap-4788L, -0x1.256fd3aa961492b8p-4788L }, - { 0x1.dcdb59c7c235dbc2p-4L, -0x2.d021db0eb4e66bc4p+4172L, -0x7.26a25cdf864b2e2p+4168L, -0x7.26a25cdf864b2e18p+4168L }, - { -0x7.39e6166b4e7ff328p-8L, 0xd.d257bb858d37bdep+5592L, -0x9.22a66ce89f4a1d8p+5588L, -0x9.22a66ce89f4a1d7p+5588L }, - { 0x2.cbc98bdd8b82901p-4L, 0x3.6f0885306061a098p+1264L, 0xc.c3fea6c91774964p+1260L, 0xc.c3fea6c91774965p+1260L }, - { -0x2.7c3e61d780a4f324p-4L, -0x1.da01a42e71e30548p+7012L, 0x7.37128b7293c62da8p+7008L, 0x7.37128b7293c62dbp+7008L }, - { 0x1.637d8202e9a84f9p-64L, -0x3.95f019facb81ca2p-352L, -0x7.2ef9571efed13f38p-416L, -0x7.2ef9571efed13f3p-416L }, - { -0x6.82a90c9p-16416L, 0x8.4b9ea0f6dd41af6p-3128L, -0x8p-16448L, -0x0p+0L }, - { 0xb.15e9277124ef54ap-8L, 0x3.181d10559801b24p-3016L, 0x3.071c007555f37dp-3020L, 0x3.071c007555f37d04p-3020L }, - { -0x2.34958a751bd7e2b4p-4L, -0x7.1e0c4f162e18cb3p-14368L, 0x1.85dc9e96b295d1f4p-14368L, 0x1.85dc9e96b295d1f6p-14368L }, - { 0x1.baa38808f4d9ef8p-4L, -0x1.94cc68b2b3c4a3cap+6596L, -0x3.bed8f66fe0b67d94p+6592L, -0x3.bed8f66fe0b67d9p+6592L }, - { -0x2.9c8a581b1fc5d614p-4L, -0x2.8c01857641e55648p-2264L, 0xa.79d78516d7f224p-2268L, 0xa.79d78516d7f2241p-2268L }, - { 0xf.b589bcceb220068p-8L, -0x1.4789d33b87e903d2p+5568L, -0x1.c2450650774c5p+5564L, -0x1.c2450650774c4ffep+5564L }, - { -0x2.8d5e2c4a97b5ca14p-4L, 0xa.6c4e4d3fd85b1d1p-2464L, -0x2.9cf440e73f0f258p-2464L, -0x2.9cf440e73f0f257cp-2464L }, - { 0x1.fac5b9a230ace1ccp-4L, -0xc.183e2d13feeccbp+5796L, -0x2.090f003628c73a5p+5796L, -0x2.090f003628c73a4cp+5796L }, - { -0x2.3a1aa1ebf9d944d8p-4L, 0xb.56f3fb671e6d7bp-10204L, -0x2.73b180956d044ca8p-10204L, -0x2.73b180956d044ca4p-10204L }, - { 0x3.f1ed5917ebae5ee8p-4L, 0x1.5d25d26ea685965ap-9392L, 0x6.f0398d9603c092cp-9396L, 0x6.f0398d9603c092c8p-9396L }, - { -0x4.2ed20be58e7ce458p-4L, -0x1.bb72045b4fb64006p+11436L, 0xc.1df41156acd8b46p+11432L, 0xc.1df41156acd8b47p+11432L }, - { 0x1.533ed177d8f43096p-4L, -0x6.6c5aad8f16c7612p-12240L, -0xb.cc4d7e98c47615cp-12244L, -0xb.cc4d7e98c47615bp-12244L }, - { -0x2.b3759933edcfbb8cp-4L, -0x5.be3632756b1f6c08p-13700L, 0x1.882fe94f6b50223p-13700L, 0x1.882fe94f6b502232p-13700L }, - { 0x4.71542952f2eb2118p-4L, -0xf.bc3571405a814dbp-12400L, -0x5.90065e0286f0d738p-12400L, -0x5.90065e0286f0d73p-12400L }, - { -0x2.17fa44980470472p-4L, 0xb.d365be5d38977b2p-484L, -0x2.648810e10755e434p-484L, -0x2.648810e10755e43p-484L }, - { 0x3.a3076d42e4a727a4p-4L, 0x1.16e61b22825583d6p-10652L, 0x5.269729e108bbd29p-10656L, 0x5.269729e108bbd298p-10656L }, - { -0x3.54041d65782d11a8p-4L, -0x3.82c837279f08c5c8p-2472L, 0x1.2e64f5ccd94f2862p-2472L, 0x1.2e64f5ccd94f2864p-2472L }, - { 0x4.6fa9ede403127e4p-4L, -0x1.71f2e5247996097cp+11700L, -0x8.29ca8ac57dfca06p+11696L, -0x8.29ca8ac57dfca05p+11696L }, - { -0x2.e31e7f5102321e84p-4L, -0x1.06117dc5bf40339ep+6984L, 0x4.b3d0402392c36ffp+6980L, 0x4.b3d0402392c36ff8p+6980L }, - { 0x3.b9638838b09138f4p-4L, -0x3.7b942a0763ad15e4p+10616L, -0x1.0d2953cf22d7307ap+10616L, -0x1.0d2953cf22d73078p+10616L }, - { -0x4.91ac63ed12ffa698p-4L, 0xf.ca607d23e02b6a5p-5416L, -0x7.a90ecaa3a7c85628p-5416L, -0x7.a90ecaa3a7c8562p-5416L }, - { 0x3.bd32cd8p-16420L, 0xc.64d8265a9554331p+13480L, 0x4.2db54f6499fee318p-2936L, 0x4.2db54f6499fee32p-2936L }, - { -0x7.30ab6348p-16416L, 0x2.d01e62e5954e5ecp-84L, -0x8p-16448L, -0x0p+0L }, - { 0x4.67c806cb2037368p-4L, -0x1.eee94944aabe7324p+14052L, -0xa.da76434365cbe5p+14048L, -0xa.da76434365cbe4fp+14048L }, - { -0x9.63a7f9a9b4e3772p-8L, -0x6.9750c01b7eab2c18p-6576L, 0x5.af5d76a3b96d562p-6580L, 0x5.af5d76a3b96d5628p-6580L }, - { 0x3.a890e71f965c423p-4L, 0x2.65754ef7508e6b2cp+14816L, 0xb.63ec8116f9623b9p+14812L, 0xb.63ec8116f9623bap+14812L }, - { -0x4.49c1355a26341ebp-4L, -0xa.2df5b84e07b2b1dp+2576L, 0x4.94ef7cdabf583378p+2576L, 0x4.94ef7cdabf58338p+2576L }, - { 0x3.592044d31e941f3cp-4L, -0xd.a2a1544a13a75a8p+8764L, -0x3.bcdd3b58fc6b4dccp+8764L, -0x3.bcdd3b58fc6b4dc8p+8764L }, - { -0x2.1c5be0eceea3074cp-4L, 0x9.8705b776af68ab6p+12632L, -0x1.f1d1b127094cc7d8p+12632L, -0x1.f1d1b127094cc7d6p+12632L }, - { 0x1.918ff257bb0d693cp-4L, 0xe.4262f654fe7fbd6p+7432L, 0x1.ec89a740290f2b92p+7432L, 0x1.ec89a740290f2b94p+7432L }, - { -0x4.4c3ff5e8f02ea658p-4L, 0x2.44e6f663c6e96414p+2392L, -0x1.062905420850e93p+2392L, -0x1.062905420850e92ep+2392L }, - { 0x4.25a93aaf3e8e66d8p-4L, -0xa.1d09747650d55b9p+9676L, -0x3.5cdba7179be56514p+9676L, -0x3.5cdba7179be5651p+9676L }, - { -0x7.4029c8dbfe579468p-8L, 0x1.c03a669c155fa5f8p+9484L, -0x1.29459dde5831c58ap+9480L, -0x1.29459dde5831c588p+9480L }, - { 0x4.99a9a4d5bf45f348p-8L, 0xa.41177495779f599p-6252L, 0x4.37364b1fa5c8e98p-6256L, 0x4.37364b1fa5c8e988p-6256L }, - { -0x2.24107ead42d5b40cp-8L, 0x1.c65fcf3a7b070d68p-10904L, -0x5.814bc88b1eff00f8p-10912L, -0x5.814bc88b1eff00fp-10912L }, - { 0xd.7bd18c92836d9b7p-8L, -0x2.fe022bf9a8eac0f8p+4008L, -0x3.8b9dbb6814dca604p+4004L, -0x3.8b9dbb6814dca6p+4004L }, - { -0x2.bd9ef84dc1262334p-4L, -0x1.926d2e72dc294662p+8176L, 0x6.d15c01dce8da9378p+8172L, 0x6.d15c01dce8da938p+8172L }, - { 0x1.79677266716881dep-4L, -0x3.9250255d51f10438p-8936L, -0x7.442fb2c4a2d081ap-8940L, -0x7.442fb2c4a2d08198p-8940L }, - { -0xd.23ebb0103a3412p-8L, 0x1.0c7d8c40c9f7f63cp-10576L, -0x1.4692db88dd7f76dep-10580L, -0x1.4692db88dd7f76dcp-10580L }, - { 0x3.c37ee7fcc3f66618p-4L, -0x1.0b426c0abe2f515p-10024L, -0x5.1746c07ac5fd95a8p-10028L, -0x5.1746c07ac5fd95ap-10028L }, - { -0x2.64319ac6eea8ea44p-4L, 0x2.14977aea96547074p-8036L, -0x7.c633388965b5c9p-8040L, -0x7.c633388965b5c8f8p-8040L }, - { 0x4.36557dfc7b7a0858p-4L, -0xb.5f490bd4a0d58a3p-8256L, -0x3.d58fc1d6c174b18p-8256L, -0x3.d58fc1d6c174b17cp-8256L }, - { -0x2.118c4c79edf47354p-4L, 0x5.7bbb5596a817d228p-2732L, -0x1.185caaa41d1fcbf8p-2732L, -0x1.185caaa41d1fcbf6p-2732L }, - { 0x2.2dfb2465030d9704p-120L, -0x3.2070b9ab6c091d04p+156L, -0x9.d4ffa1b506ada6fp+36L, -0x9.d4ffa1b506ada6ep+36L }, - { -0x1.b8ca4718dfb949b4p-156L, 0x2.b703c4e83381ac98p-13808L, -0x6.be79c4120e72058p-13964L, -0x6.be79c4120e720578p-13964L }, - { 0x3.aa7e6497bf65cec8p-4L, 0x2.207f40048a485988p+8000L, 0xa.20f27e1acc74886p+7996L, 0xa.20f27e1acc74887p+7996L }, - { -0x4.a61b8649abf09bdp-4L, -0x6.463247ab1fb7f22p-9052L, 0x3.1b719641a4a7976cp-9052L, 0x3.1b719641a4a7977p-9052L }, - { 0x3.7f3e92fee7a6f28p-4L, -0x2.0b71289ec2fa384cp+13492L, -0x9.546f7189f8f4635p+13488L, -0x9.546f7189f8f4634p+13488L }, - { -0x2.48a19098f3bb9008p-4L, 0xb.8b1a411e3e76627p-5852L, -0x2.90922f5ecf5c1fd4p-5852L, -0x2.90922f5ecf5c1fdp-5852L }, - { 0x3.b47754510462f6c4p-4L, -0x2.0bfc7264e887cdc8p+7904L, -0x9.d734f5619b3ab5bp+7900L, -0x9.d734f5619b3ab5ap+7900L }, - { -0x1.9703efc23286a644p-4L, 0x5.4bd8b1a807b11328p-15000L, -0xc.cb8cd9e7e25290cp-15004L, -0xc.cb8cd9e7e25290bp-15004L }, - { 0x3.765f83baff0c21fcp-4L, -0xf.dcbdd271ed9656bp+1780L, -0x4.7ba2cfd8cf705ba8p+1780L, -0x4.7ba2cfd8cf705bap+1780L }, - { -0x2.d47396eb2be5851p-4L, -0xa.33e2e879179697fp+1788L, 0x2.dd6dda56ba24386p+1788L, 0x2.dd6dda56ba243864p+1788L }, - { 0x2.a803fd68ec7649e8p-4L, 0xb.02935a9215a3cacp+8628L, 0x2.7092c54d30c5f24p+8628L, 0x2.7092c54d30c5f244p+8628L }, - { -0x3.0abba9ed50933008p-4L, -0xa.646a2e2861abb61p+11556L, 0x3.295a5daefccd137cp+11556L, 0x3.295a5daefccd138p+11556L }, - { 0x1.4fddcbc604cd0d02p-4L, 0x2.bb83c03d681805d8p-13988L, 0x4.f88acdec70c270ep-13992L, 0x4.f88acdec70c270e8p-13992L }, - { -0x3.13fe026e5c2ebb5cp-4L, -0x2.e6c29d1a543973dp-14108L, 0xe.4f547fb973cd189p-14112L, 0xe.4f547fb973cd18ap-14112L }, - { 0x6.fd3591d417b2bea8p-8L, 0x7.3b0323418d7119bp+10092L, 0x4.7edc810794e8dc88p+10088L, 0x4.7edc810794e8dc9p+10088L }, - { -0x3.d7d6efab7eaa891p-4L, -0x1.e2d85877948f2bfep+3328L, 0xb.f59e66f55ab1a34p+3324L, 0xb.f59e66f55ab1a35p+3324L }, - { 0x3.866120802df86e44p-4L, 0xb.ede747cdb5bd40ap-13692L, 0x3.6d37b2c1b0fc0a44p-13692L, 0x3.6d37b2c1b0fc0a48p-13692L }, - { -0x1.837e3a3951b222fep-4L, -0x9.33ad5ce66f0989cp-12372L, 0x1.51c022680d7198fcp-12372L, 0x1.51c022680d7198fep-12372L }, - { 0x1.fdcd9cf05688d39ap-4L, 0x7.a430ee8b67706cd8p+12908L, 0x1.4b0f5cb18c3a0502p+12908L, 0x1.4b0f5cb18c3a0504p+12908L }, - { -0x4.6d76b6c10b4f68dp-4L, 0x3.86937071555cdafp-6228L, -0x1.a5d93ae065b24362p-6228L, -0x1.a5d93ae065b2436p-6228L }, - { 0xc.e11cc48bc0890a6p-8L, -0xe.d33d2fb05570f5p+9980L, -0x1.0cc2a4739972082ep+9980L, -0x1.0cc2a4739972082cp+9980L }, - { -0x3.15cc58d05242c5c4p-4L, -0x2.b3bc30083b4d4404p+11624L, 0xd.5c643b37b5143f8p+11620L, 0xd.5c643b37b5143f9p+11620L }, - { 0x1.ba0d3017b025eae6p-32L, 0x1.198638bd324fcb54p+14568L, 0x2.bd54dd9644f2be48p+14536L, 0x2.bd54dd9644f2be4cp+14536L }, - { -0x5.fd20bf720e8711ep-172L, 0x6.73a42eb2b2605db8p-3488L, -0x3.7be27d9b5a793af4p-3656L, -0x3.7be27d9b5a793afp-3656L }, - { 0x3.ccf8a019857ed894p-4L, -0x1.d70139a2e6defee6p+7832L, -0x9.0d2c0e9df766c0fp+7828L, -0x9.0d2c0e9df766c0ep+7828L }, - { -0x3.76614c7863ec1a34p-4L, 0x9.5e5abe936c610a9p-7228L, -0x3.4bc5db18912ee0b4p-7228L, -0x3.4bc5db18912ee0bp-7228L }, - { 0x3.41a0d3833286b12p-4L, -0x2.80acf5ba59112edp+14608L, -0xa.b3a9e16bc318f8cp+14604L, -0xa.b3a9e16bc318f8bp+14604L }, - { -0x3.3e705853c67d7d8cp-4L, -0x5.f6741be9484aa37p+7296L, 0x1.f2f9757c7add715cp+7296L, 0x1.f2f9757c7add715ep+7296L }, - { 0x3.48681763319dda58p-4L, -0x3.67fd89d48c38dc8cp-1216L, -0xe.ac78d74c01e27a5p-1220L, -0xe.ac78d74c01e27a4p-1220L }, - { -0x4.7f84659f13b7e02p-4L, 0x7.bf798fb07a11662p+5760L, -0x3.b0889ae3587bbd1cp+5760L, -0x3.b0889ae3587bbd18p+5760L }, - { 0xa.4a3324d14b02089p-8L, 0xe.377d20895e5873fp-8496L, 0xc.eeb025e6099e398p-8500L, 0xc.eeb025e6099e399p-8500L }, - { -0x1.4888cb0fc88855d4p-4L, 0xe.db1b91e2caa0ba9p-5588L, -0x1.cabc6b23578f7164p-5588L, -0x1.cabc6b23578f7162p-5588L }, - { 0x2.7d6c843a1e34bb04p-4L, -0x9.a100a7ee5db1c0dp-13024L, -0x2.025e40217cfd859p-13024L, -0x2.025e40217cfd858cp-13024L }, - { -0x3.5fa0f418a95b1664p-4L, 0xf.bcd9d43d60027c9p-1464L, -0x5.6058e9841e63ffc8p-1464L, -0x5.6058e9841e63ffcp-1464L }, - { 0x4.8fa3ee4eaa7f608p-4L, 0x2.36d491e5ba55fc0cp+3820L, 0xc.d1ad707323f03c3p+3816L, 0xc.d1ad707323f03c4p+3816L }, - { -0x1.4b4df2cc6ad25ea8p-4L, 0x1.868500451829747cp+12564L, -0x2.f84f7bac1d20f1ep+12560L, -0x2.f84f7bac1d20f1dcp+12560L }, - { 0x1.f632e7d78adaa7bap-4L, 0x4.feb116d8a3c818ep+4492L, 0xd.55a8e7b75c1d99p+4488L, 0xd.55a8e7b75c1d991p+4488L }, - { -0x1.1908e7c45b2a3cdp-4L, -0x1.7103d1307c4d3a48p-3456L, 0x2.5d74775e3b76a7ap-3460L, 0x2.5d74775e3b76a7a4p-3460L }, - { 0x3.d1361d5e6ee7fc4cp-4L, -0x4.71adf08ff0311758p+4848L, -0x1.5f2ed550fa6c8e9ap+4848L, -0x1.5f2ed550fa6c8e98p+4848L }, - { -0x1.0feb13e1b3fa32cep-4L, 0x5.beb340c633bfc9b8p-10700L, -0x9.1bff6c6cb9b3392p-10704L, -0x9.1bff6c6cb9b3391p-10704L }, - { 0x2.9f4ded3ecc16efe8p-4L, -0xb.866e84a68035155p-1164L, -0x2.86054df08503d23p-1164L, -0x2.86054df08503d22cp-1164L }, - { -0x1.0e6005400df64018p-4L, 0x3.8d17e470f6e09b88p-8468L, -0x5.9906aeea3ec75f8p-8472L, -0x5.9906aeea3ec75f78p-8472L }, - { 0x2.06b035aa76cdd098p-4L, 0x1.e00da34298889842p-5192L, 0x5.293db0d00f0e8c4p-5196L, 0x5.293db0d00f0e8c48p-5196L }, - { -0x2.d44b97592a7f2cacp-4L, -0xf.c8025dd6fb1fa7dp+5864L, 0x4.6e2ea290515d3d28p+5864L, 0x4.6e2ea290515d3d3p+5864L }, - { 0xb.bf2398p-16424L, -0x9.79c050222c1c028p+2980L, -0xa.094c1b19085e6eap-13440L, -0xa.094c1b19085e6e9p-13440L }, - { -0xe.69fc312b6c20148p-188L, 0x1.4f5d050e1ce71f9ap+9460L, -0x1.b3de2a1f249a3644p+9276L, -0x1.b3de2a1f249a3642p+9276L }, - { 0x7.8ae95a742e52adf8p-8L, 0x8.966bd426c329fd3p+4712L, 0x5.c18ec9b9358e0c1p+4708L, 0x5.c18ec9b9358e0c18p+4708L }, - { -0x2.c7dfd0fb6c73cb18p-4L, -0x2.cf1cfb2de02b7d78p+14340L, 0xc.611330d26020636p+14336L, 0xc.611330d26020637p+14336L }, - { 0xe.5af0f71551e3f5cp-8L, 0x3.a98a7ec294cc83c8p-816L, 0x4.9cbd3cb9c9116e38p-820L, 0x4.9cbd3cb9c9116e4p-820L }, - { -0x1.8276da55153cfdbp-4L, -0x1.a307e03dd9845d44p+5600L, 0x3.be96b5f832a200acp+5596L, 0x3.be96b5f832a200bp+5596L }, - { 0x2.81a24543987fd82p-4L, 0xd.8bd22d5fd653c0cp-9644L, 0x2.d8128d3bec32cd3cp-9644L, 0x2.d8128d3bec32cd4p-9644L }, - { -0x1.379a979d3d9108c8p-4L, 0x7.730ab999d45ba668p+8876L, -0xd.9b19d340489c12ap+8872L, -0xd.9b19d340489c129p+8872L }, - { 0x4.7b84cbeaf9218068p-4L, 0x1.94a35a444837f348p-1060L, 0x9.02e333ae71b31c6p-1064L, 0x9.02e333ae71b31c7p-1064L }, - { -0x4.0c6068743ed7f7ap-4L, 0x8.653a7b58a965687p-2084L, -0x3.88871c668e454124p-2084L, -0x3.88871c668e45412p-2084L }, - { 0x1.c2424e1940d7455p-4L, -0x5.5deec579d8a42c3p-7868L, -0xc.eba462f43ab86e2p-7872L, -0xc.eba462f43ab86e1p-7872L }, - { -0x2.d7b31c0c9af1a328p-4L, -0x1.b015dec33f70594ep-11840L, 0x7.9eeac3e3d95935ep-11844L, 0x7.9eeac3e3d95935e8p-11844L }, - { 0x2.494fadc55b33b084p-4L, -0x3.dc339a3898bc7a18p+8868L, -0xb.e6c675431839112p+8864L, -0xb.e6c675431839111p+8864L }, - { -0x2.ee153b661645587cp-4L, -0x6.c3feb8fbd6d16edp+9160L, 0x1.f96ba24721b9912ep+9160L, 0x1.f96ba24721b9913p+9160L }, - { 0x4.8e20e07126ab5fbp-4L, 0x3.c7f4fe11df2d42d8p+2808L, 0x1.5dd9737f23ac2e7ap+2808L, 0x1.5dd9737f23ac2e7cp+2808L }, - { -0x2.2d194219b0dffcacp-4L, -0x6.07756407b2f410bp-12488L, 0x1.45898bc66612542p-12488L, 0x1.45898bc666125422p-12488L }, - { 0x4.99aacb94db2a32ep-4L, 0x2.185cd30ea16fd298p-8768L, 0xc.38d8901d530a557p-8772L, 0xc.38d8901d530a558p-8772L }, - { -0x2.96ffad178b37fbfcp-4L, -0x3.e5143e6ad3e345cp-12712L, 0xf.e0050f04899e61ap-12716L, 0xf.e0050f04899e61bp-12716L }, - { 0x2.07cf3823d73ab374p-8L, 0x4.fa7fc381b3d6c2f8p+13688L, 0xe.86ca1ccd04ba732p+13680L, 0xe.86ca1ccd04ba733p+13680L }, - { -0x2.28ed2ce3d1807394p-8L, -0x5.a384207efdf44f98p+10336L, 0x1.1a5201007023cabap+10332L, 0x1.1a5201007023cabcp+10332L }, - { 0x2.469a2200238d7444p-4L, 0x5.9ad70266bfb8e91p+2488L, 0x1.134a7e067761fe5ap+2488L, 0x1.134a7e067761fe5cp+2488L }, - { -0x2.37b70d8d4113f934p-4L, -0x1.af092832a5fc99d8p+10212L, 0x5.cc7a4fd5be1823d8p+10208L, 0x5.cc7a4fd5be1823ep+10208L }, - { 0x2.1e0b843dc844a878p-48L, -0x1.b9ae023d8acd6e66p-13528L, -0x5.453405a12d6a7e78p-13576L, -0x5.453405a12d6a7e7p-13576L }, - { -0x4.4c7b47cp-16416L, -0x3.547713310a06b54p+5744L, 0x1.4a6d0327cbe06654p-10668L, 0x1.4a6d0327cbe06656p-10668L }, - { 0x4.083830ddfa7690ep-4L, 0x1.613dfb10e1a54184p+10872L, 0x7.2893986d292e673p+10868L, 0x7.2893986d292e6738p+10868L }, - { -0x3.433014eef8a70788p-4L, -0x1.a8639abcd8b6e402p-8536L, 0x8.b9e0c375b70f81ap-8540L, 0x8.b9e0c375b70f81bp-8540L }, - { 0x2.d29ec953e7aa219p-4L, 0x1.4fa6beb2f76975acp+13676L, 0x4.ead9b52fbb5f5fc8p+13672L, 0x4.ead9b52fbb5f5fdp+13672L }, - { -0x3.5e2ea6dbdbaa02p-4L, 0x5.ee655300abbc5d6p+14676L, -0x2.05bd11a5d53281cp+14676L, -0x2.05bd11a5d53281bcp+14676L }, - { 0x8.304de71d9e9114cp-8L, 0x2.7910d5b01fbe64e4p-6028L, 0x1.cc1c6eb2df659e2ep-6032L, 0x1.cc1c6eb2df659e3p-6032L }, - { -0x2.b4d0633cb32e7d3p-4L, -0x1.f35e33822898ee8p+10012L, 0x8.57ef3448b90b49dp+10008L, 0x8.57ef3448b90b49ep+10008L }, - { 0x4.349e9799eee38c3p-4L, -0x3.85166ab0880d15d8p-14236L, -0x1.2f60a91c12616b9p-14236L, -0x1.2f60a91c12616b8ep-14236L }, - { -0x1.82c3ae4bbb10637cp-4L, 0x4.d7001bc86349c478p-10896L, -0xb.14b1458f431b427p-10900L, -0xb.14b1458f431b426p-10900L }, - { 0x1.2e5ba50de7eddadap-4L, -0x7.d3c6bad19081ebap-11612L, -0xc.de2fb1024afe26ap-11616L, -0xc.de2fb1024afe269p-11616L }, - { -0x3.83f8c7b7cb57825cp-4L, 0x5.1e6faf1b430e137p+13408L, -0x1.d50d40244e687828p+13408L, -0x1.d50d40244e687826p+13408L }, - { 0xb.41592caa2c324c4p-8L, 0x4.168f2c495ff127f8p+14584L, 0x4.0f6f7aae5e342928p+14580L, 0x4.0f6f7aae5e34293p+14580L }, - { -0x2.a3c26e78708216b4p-4L, 0x8.cbb456a056bda98p+2832L, -0x2.49b56eddf19b1a38p+2832L, -0x2.49b56eddf19b1a34p+2832L }, - { 0x2.559fafbe5db9e92p-4L, -0x1.020dcff6a035d17ep-1564L, -0x3.2b440ece5ae09ac4p-1568L, -0x3.2b440ece5ae09acp-1568L }, - { -0x1.c97f2c8d93653d48p-4L, -0x2.e37117c16676a0ecp-8384L, 0x7.e595007c6cac50dp-8388L, 0x7.e595007c6cac50d8p-8388L }, - { 0x1.9549043c3fae6d76p-4L, -0x5.6ca968825df497b8p-6632L, -0xb.d06c203591750cbp-6636L, -0xb.d06c203591750cap-6636L }, - { -0x2.938e403b0b6781e4p-4L, 0x1.cc1921f91d82e518p+8416L, -0x7.48adf070f40903dp+8412L, -0x7.48adf070f40903c8p+8412L }, - { 0x1.d3d61644611f7f54p-4L, -0x2.3bbe429554a65cfcp-6468L, -0x5.935b89809acb83fp-6472L, -0x5.935b89809acb83e8p-6472L }, - { -0x1.0e5ea40906fee1a8p-4L, 0x2.b30ab79d07e2deap-5244L, -0x4.4148a4a719f6c5a8p-5248L, -0x4.4148a4a719f6c5ap-5248L }, - { 0x1.b7e8585df0a1e78ap-4L, -0x1.1c71d650867d7786p-304L, -0x2.9dd0113be448c594p-308L, -0x2.9dd0113be448c59p-308L }, - { -0x3.c216a3f300f2fa4p-4L, -0x5.1494a94b36616a18p-8936L, 0x1.f659d5fe58f69792p-8936L, 0x1.f659d5fe58f69794p-8936L }, - { 0x1.c0f2c38245dc8a1ep-36L, 0x5.38cf2d6c438c4fdp+10484L, 0xd.363555200aa28b1p+10448L, 0xd.363555200aa28b2p+10448L }, - { -0x5.338a3398p-16416L, 0xb.9bac1859a410106p-9056L, -0x8p-16448L, -0x0p+0L }, - { 0x4.10c4032a61d96d4p-4L, -0x7.0d9040683a3fcp+520L, -0x2.4dc7081478ce8b44p+520L, -0x2.4dc7081478ce8b4p+520L }, - { -0x3.1a6581525a6ef994p-4L, -0x6.d2ef9a6ba6f44528p+10288L, 0x2.1f61e588277a8a1p+10288L, 0x2.1f61e588277a8a14p+10288L }, - { 0xb.44e6f1ad62eb1d3p-12L, 0x1.2f26e54a1a2d2bcep+2628L, 0x1.339dc2b5be6f05ccp+2620L, 0x1.339dc2b5be6f05cep+2620L }, - { -0x3.dc341dbfa33afaf8p-4L, 0x2.87da9cc0fd94cab4p-12668L, -0x1.020e3b564a370bbp-12668L, -0x1.020e3b564a370baep-12668L }, - { 0x2.2f1d94a92b73ba54p-8L, 0xc.fd7aedfbcc36e21p-2864L, 0x2.8c1d8f7d4aeaeb8p-2868L, 0x2.8c1d8f7d4aeaeb84p-2868L }, - { -0x3.1f6b10cfe59f209p-4L, -0x1.d7e7a366c9f4fafp+8040L, 0x9.3d25ebcfc0e8757p+8036L, 0x9.3d25ebcfc0e8758p+8036L }, - { 0x3.7328f5190b649058p-4L, -0x1.cb288c3a6ffb891ap-14664L, -0x8.156bb127252ce95p-14668L, -0x8.156bb127252ce94p-14668L }, - { -0x4.05760d773cce4b18p-4L, -0x3.619f8ab766bdc80cp-12980L, 0x1.697cf65320577f2ep-12980L, 0x1.697cf65320577f3p-12980L }, - { 0x3.06e0564e8648504p-4L, 0x1.9129d4b6a8c0a64cp-3348L, 0x6.446edb2686c4b438p-3352L, 0x6.446edb2686c4b44p-3352L }, - { -0x3.b4c9c714bc24a95p-4L, 0x8.0c9d9e18f2f4e02p+12048L, -0x3.0f534e9f9071cd6cp+12048L, -0x3.0f534e9f9071cd68p+12048L }, - { 0x1.8456626db4b3e754p-4L, 0xa.75791f1b98fa7c2p+7952L, 0x1.5de3cd5f95a39698p+7952L, 0x1.5de3cd5f95a3969ap+7952L }, - { -0x1.cf4a46c4585b047ap-4L, -0x2.588015b168bce7acp-13720L, 0x6.7fd06d3587654c08p-13724L, 0x6.7fd06d3587654c1p-13724L }, - { 0x1.332103e3ea9e239cp-4L, -0xc.30c9869073f6cbfp+14536L, -0x1.458a3582f79dec28p+14536L, -0x1.458a3582f79dec26p+14536L }, - { -0x2.8f2194cfbb3ca8dp-4L, -0x2.5bd03241d4e64288p+9824L, 0x9.7d31337f76bc8p+9820L, 0x9.7d31337f76bc801p+9820L }, - { 0x1.75adff2c459d542ep-4L, 0x8.cc5bcdf810d087bp+12200L, 0x1.1bb28d31bd29f1a2p+12200L, 0x1.1bb28d31bd29f1a4p+12200L }, - { -0x2.7210b844df60db2cp-4L, -0x1.622e351acabb98cep-1124L, 0x5.4c208ba7477d9a4p-1128L, 0x5.4c208ba7477d9a48p-1128L }, - { 0xe.6e7603454ee5fdap-8L, 0x2.cccf4c722416cda8p+10164L, 0x3.8b6a8a886aa48544p+10160L, 0x3.8b6a8a886aa48548p+10160L }, - { -0x4.51b2bbef5b4e2008p-4L, 0x3.6cdc3fba23bef70cp+12224L, -0x1.8e074b185d5c9a1p+12224L, -0x1.8e074b185d5c9a0ep+12224L }, - { 0x4.086bd3b7798df198p-4L, -0x5.3ede769cd9e10ad8p-13484L, -0x1.b37dba8860e6a8e8p-13484L, -0x1.b37dba8860e6a8e6p-13484L }, - { -0x3.444dbd716806ed7p-4L, -0x1.a1223f3c67d88328p+14220L, 0x8.96fbc10a6b2910cp+14216L, 0x8.96fbc10a6b2910dp+14216L }, - { 0x7.845f8708p-16416L, -0x9.2a78d116f539cddp+13612L, -0x6.3672794bc955e378p-2800L, -0x6.3672794bc955e37p-2800L }, - { -0x9.a00bf03936bb962p-188L, 0xb.006265771517025p+9288L, -0x9.8c4e23ea8f3d0ccp+9104L, -0x9.8c4e23ea8f3d0cbp+9104L }, - { 0x4.1484721ea2376538p-4L, -0x1.a41add8aeb9b4806p-7968L, -0x8.9aae06ea9963ce4p-7972L, -0x8.9aae06ea9963ce3p-7972L }, - { -0x2.ceb5ec6d975953c8p-4L, 0x1.3990fbbe138579bp-2444L, -0x5.747fa8d3ebe39c2p-2448L, -0x5.747fa8d3ebe39c18p-2448L }, - { 0x2.0eb33e95ad6976d4p-4L, -0x1.1151218de56ba42cp-13140L, -0x2.fb304a838c96f87cp-13144L, -0x2.fb304a838c96f878p-13144L }, - { -0x2.eb00c9bd97ca2dp-4L, -0x5.2422819f09d6c978p-5108L, 0x1.7e51d1ba67214bdcp-5108L, 0x1.7e51d1ba67214bdep-5108L }, - { 0x1.16afed5122a1c164p-4L, -0x6.328d311aeae95f4p-7344L, -0x9.6aa5fcce16eb342p-7348L, -0x9.6aa5fcce16eb341p-7348L }, - { -0x4.57c457a4cf259718p-8L, -0x3.96ccc33bb2e63e44p-12628L, 0x1.6ae07bf02b257026p-12632L, 0x1.6ae07bf02b257028p-12632L }, - { 0x1.aeeefbd8d00e0efep-4L, -0xf.b5614be31d80bd7p+7168L, -0x2.445bf283f4c48574p+7168L, -0x2.445bf283f4c4857p+7168L }, - { -0x2.5dce95be94cb3c98p-4L, -0x2.2e554820ae22992cp-120L, 0x8.0ec90a8240db617p-124L, 0x8.0ec90a8240db618p-124L }, - { 0x2.3818b947f150da88p-4L, -0x7.24ffac24722f38fp-10332L, -0x1.56b8a9c932ce8192p-10332L, -0x1.56b8a9c932ce819p-10332L }, - { -0x4.a1dc33e9391f4958p-4L, 0xc.da35ced9d50c067p-6524L, -0x6.567e050c8546b6c8p-6524L, -0x6.567e050c8546b6cp-6524L }, - { 0x4.8ad503c066b5bb88p-4L, -0x1.3c6056edfdb7ef2ep-13072L, -0x7.20fe70074b4f73d8p-13076L, -0x7.20fe70074b4f73dp-13076L }, - { -0x2.c614d5e5bb68713cp-4L, 0xa.dfd4d1fff016deap+8040L, -0x2.fca16bfa05891708p+8040L, -0x2.fca16bfa05891704p+8040L }, - { 0x2.9652c0875ceb61c8p-4L, 0x3.d368fc20214ae89p-2724L, 0xd.3c90696ace7402fp-2728L, 0xd.3c90696ace7403p-2728L }, - { -0x3.c49bb1a332166398p-4L, 0x1.e4beaa8e0eaf876p-792L, -0xb.bcbb8fd43fa70eap-796L, -0xb.bcbb8fd43fa70e9p-796L }, - { 0x9.bf4a383f6ca4c78p-8L, 0x2.f082dcbeb993682cp+14744L, 0x2.891890b8ea5a86dcp+14740L, 0x2.891890b8ea5a86ep+14740L }, - { -0x9.7cae2a328b898f8p-8L, 0x3.89ef3c26f0876fc8p-12636L, -0x3.15b05d09ca38963cp-12640L, -0x3.15b05d09ca389638p-12640L }, - { 0x3.50d23d5945a1409p-4L, -0x2.33c93e2e43fe6d7p+8756L, -0x9.92ea36d589899d7p+8752L, -0x9.92ea36d589899d6p+8752L }, - { -0x3.4717abe0a3cf3558p-4L, 0x3.8534b1e86f26faa4p+6740L, -0x1.2a0a5aa6bbe09072p+6740L, -0x1.2a0a5aa6bbe0907p+6740L }, - { 0x3.4daf40c873d20d78p-4L, -0x7.736b651db7cbd5a8p+14396L, -0x2.04813b9537b6064p+14396L, -0x2.04813b9537b6063cp+14396L }, - { -0x2.5c070e6f3535825p-4L, 0xf.3a0b99c5b4aab25p-11840L, -0x3.813a1682912fbe2cp-11840L, -0x3.813a1682912fbe28p-11840L }, - { 0x1.57462eab133f0c7ep-104L, -0xb.c22c24524226f33p-584L, -0x1.6bf458868d45cbaap-684L, -0x1.6bf458868d45cba8p-684L }, - { -0x7.d1036a7p-16416L, 0x1.9c8928976825f972p-9340L, -0x8p-16448L, -0x0p+0L }, - { 0x4.139c9d206a49b8e8p-4L, 0x7.f8137ffd163b3ba8p-6224L, 0x2.9c02918d1a124d84p-6224L, 0x2.9c02918d1a124d88p-6224L }, - { -0x7.bf1a44aeb781fdcp-8L, 0x5.c592f47919e4e23p-11080L, -0x4.1801d2a31591ef48p-11084L, -0x4.1801d2a31591ef4p-11084L }, - { 0x1.89ac0b1dee90fcbcp-4L, -0x5.2ce714d9965b9eb8p-7004L, -0xa.f68dd40a901fabdp-7008L, -0xa.f68dd40a901fabcp-7008L }, - { -0x8.f6b1a263d7a28bbp-8L, -0x6.a8e6be614c1b8df8p-13004L, 0x5.7aab3c44fdedc898p-13008L, 0x5.7aab3c44fdedc8ap-13008L }, - { 0x2.a9b18d178ac3225p-4L, 0x5.3e11ed5dcfa44448p-8052L, 0x1.2a1266fb395796a8p-8052L, 0x1.2a1266fb395796aap-8052L }, - { -0x3.526959569dd12bf4p-4L, -0x5.9adce70a60a095a8p+5500L, 0x1.e1bc0e901384afd6p+5500L, 0x1.e1bc0e901384afd8p+5500L }, - { 0x3.6ef9b4fb7ad8d1c4p-4L, -0x3.3c5645dc55c04f94p+14756L, -0xe.853a48486c560e4p+14752L, -0xe.853a48486c560e3p+14752L }, - { -0x4.ad357dc0f71b3c18p-4L, 0x1.f1a437afbf657566p-12476L, -0xf.834b1b792328df6p-12480L, -0xf.834b1b792328df5p-12480L }, - { 0x2.dd74eb48ec7ac348p-4L, 0x1.571b76b38f6ad39p+14116L, 0x5.189ace0fd7dbc34p+14112L, 0x5.189ace0fd7dbc348p+14112L }, - { -0x7.e37552b2966c9e38p-8L, -0x3.145c1bfaf5874b28p-10368L, 0x2.3993d2134acb4a2cp-10372L, 0x2.3993d2134acb4a3p-10372L }, - { 0x3.7800dc9da42fa068p-4L, -0xe.ddd4485dc420705p+14556L, -0x4.3563bf3edbcb7518p+14556L, -0x4.3563bf3edbcb751p+14556L }, - { -0x9.fdb9cb46bb40cb6p-8L, -0x7.ec4ed7347f198e18p-4392L, 0x7.47e1bfbdff5ed83p-4396L, 0x7.47e1bfbdff5ed838p-4396L }, - { 0x1.b3312385e89ecbd4p-4L, 0x1.9a43d194ce98771ep+6932L, 0x3.bc3ea85906d8a39p+6928L, 0x3.bc3ea85906d8a394p+6928L }, - { -0x3.832741f767b3e59p-4L, -0x9.4618839acbce14p-11256L, 0x3.50e5766c6f4962ecp-11256L, 0x3.50e5766c6f4962fp-11256L }, - { 0x1.5125eee5de5358fcp-4L, -0xe.ff418d777e5efbep+11616L, -0x1.b61ebb3ae9848ea4p+11616L, -0x1.b61ebb3ae9848ea2p+11616L }, - { -0x3.13efbef15009e7c8p-4L, -0x3.fc05faf9a81f3d04p+3860L, 0x1.3a668b8af93bf2ap+3860L, 0x1.3a668b8af93bf2a2p+3860L }, - { 0x1.9510ceed893154cep-4L, 0x5.8bca7ba191d1075p+6828L, 0xc.129f0a66d0014c7p+6824L, 0xc.129f0a66d0014c8p+6824L }, - { -0x1.254279726e925594p-8L, -0x7.926da2dc2eb3e0c8p-7000L, 0xc.8ac6eb52210a585p-7008L, 0xc.8ac6eb52210a586p-7008L }, - { 0x4.5ecc0b5462ae235p-4L, 0x2.6721d566c52f5a78p+2456L, 0xd.64f286714c83778p+2452L, 0xd.64f286714c83779p+2452L }, - { -0xe.a208f1fa6e8cbdp-8L, -0x7.e11743909b3a78f8p-8876L, 0xa.b4809b9e927b678p-8880L, 0xa.b4809b9e927b679p-8880L }, - { 0x6.3dc45d2p-16416L, 0x1.9db3f0479ed959aep+11628L, 0xe.8d16a10d0f22682p-4788L, 0xe.8d16a10d0f22683p-4788L }, - { -0x1.5127dea136e65c68p-144L, 0x1.0c629491d3eb9e36p-11556L, -0x1.fdf1f80bf0ed63d8p-11700L, -0x1.fdf1f80bf0ed63d6p-11700L }, - { 0x2.5e09e9760f0d8768p-4L, 0x1.7442b66581565f6ap-7544L, 0x4.a1b2e861f70853dp-7548L, 0x4.a1b2e861f70853d8p-7548L }, - { -0x1.14d28b05df6107a4p-4L, -0xf.768d54acb3f2db4p-4996L, 0x1.8fa16bbf1e49e9e6p-4996L, 0x1.8fa16bbf1e49e9e8p-4996L }, - { 0x4.a354a165b37aa58p-4L, 0x1.e8ded63613d24c3ep-11836L, 0xb.387636549b96063p-11840L, 0xb.387636549b96064p-11840L }, - { -0x3.7f1e516e412a78dcp-4L, 0x5.d4ed544e69ab835p-13136L, -0x2.131a7bf1093fe2b8p-13136L, -0x2.131a7bf1093fe2b4p-13136L }, - { 0x3.ba0b69e7e4e2cdc8p-4L, -0x1.d273ed425e50a33p+5924L, -0x8.ce800f5bbd5a8dep+5920L, -0x8.ce800f5bbd5a8ddp+5920L }, - { -0x1.ff549a9c9f82ec1ap-4L, 0x2.fdb3fd975c2fcc24p+11236L, -0x9.34d767e53428793p+11232L, -0x9.34d767e53428792p+11232L }, - { 0x2.029bf74b014ff484p-4L, -0x2.a30dbd97704f33ap-11300L, -0x7.3428258b7189c5f8p-11304L, -0x7.3428258b7189c5fp-11304L }, - { -0x2.e1b6a811746baae4p-4L, 0xf.f88c4f246cd86a5p-5444L, -0x4.93546cd11bc8d19p-5444L, -0x4.93546cd11bc8d188p-5444L }, - { 0x4.5a3aed0d1ae13a2p-4L, -0xe.7792c29f1ca2519p-11176L, -0x5.05a0661deb318c68p-11176L, -0x5.05a0661deb318c6p-11176L }, - { -0x2.63162683080b9cbcp-4L, -0x8.bd152439e522049p+8456L, 0x2.0972b167c0230b94p+8456L, 0x2.0972b167c0230b98p+8456L }, - { 0x1.b1c8e39b79681704p-4L, 0x4.33534d4293ac9658p+4804L, 0x9.c2a816a4d7c0fe6p+4800L, 0x9.c2a816a4d7c0fe7p+4800L }, - { -0x1.7e5bc5004f62d1d6p-4L, 0x9.6fd0b86f1bc0b1p+7492L, -0x1.558cfea5c44dab0ap+7492L, -0x1.558cfea5c44dab08p+7492L }, - { 0x4.0935c6e8ba8176cp-4L, -0x2.45ae50f119d75d4cp-12464L, -0xb.cc484240eada775p-12468L, -0xb.cc484240eada774p-12468L }, - { -0x5.5a423aabc9b990ap-8L, 0x1.ffe076f2fd67cd5p+136L, -0xf.9ab02a9a0165a16p+128L, -0xf.9ab02a9a0165a15p+128L }, - { 0x1.a0a0dfe1f0a99b6p-4L, -0x2.64149f518ed134b8p+12468L, -0x5.58a2666218ac564p+12464L, -0x5.58a2666218ac5638p+12464L }, - { -0x4.65e52871cff18e08p-4L, 0x4.1bf7b256271f8f28p-14612L, -0x1.e7cc9f85102b525cp-14612L, -0x1.e7cc9f85102b525ap-14612L }, - { 0x5.b61843dfb71d1fb8p-8L, 0x3.49a93629ad7fc314p+13540L, 0x1.acac91b8860aecfap+13536L, 0x1.acac91b8860aecfcp+13536L }, - { -0x3.f52785993c70ec3p-8L, -0x3.9bc242c0137acf5cp-12472L, 0x1.4c38af5e25f74042p-12476L, 0x1.4c38af5e25f74044p-12476L }, - { 0xe.d492edc66d3e62ep-8L, -0x6.03a80cdae8d71a98p+740L, -0x7.d1728cf552ba731p+736L, -0x7.d1728cf552ba7308p+736L }, - { -0x4.670e905322dbb63p-4L, 0x1.6a9a4d57bc0ab21ap-14452L, -0xa.8581ee4fafd174fp-14456L, -0xa.8581ee4fafd174ep-14456L }, - { 0x5.74d1d9f8p-16416L, -0x5.d7c80be9da872b28p+11784L, -0x2.dfe8427ef946d498p-4628L, -0x2.dfe8427ef946d494p-4628L }, - { -0x1.ea990a7a7c9093b4p-144L, -0x1.54c1c54d508c174p+4632L, 0x3.ae1df71c96cb2fc4p+4488L, 0x3.ae1df71c96cb2fc8p+4488L }, - { 0x4.93dbf2db2ba9b988p-4L, -0xf.46327c7f85e2d9bp+10320L, -0x5.8b67deefd704f668p+10320L, -0x5.8b67deefd704f66p+10320L }, - { -0x3.8cfabd226c133e6p-4L, 0x2.ea14d6304eb12438p-14544L, -0x1.0e1644540f887aa8p-14544L, -0x1.0e1644540f887aa6p-14544L }, - { 0x1.9329c67c6c57433p-4L, -0x2.91d7f1505ba6b1p+3140L, -0x5.919562e974081818p+3136L, -0x5.919562e97408181p+3136L }, - { -0x4.a986cc606ebb7c4p-4L, 0xf.bbc8e9388c45f3ap-10816L, -0x7.d189e02359a7d8f8p-10816L, -0x7.d189e02359a7d8fp-10816L }, - { 0x1.0068bafe2db46dc8p-4L, -0xd.0ec84ab52b6bccfp+10516L, -0x1.24d293c044903b7ap+10516L, -0x1.24d293c044903b78p+10516L }, - { -0xe.b86d33c9dc908e3p-8L, 0x3.9bf2d583cd0d0d8cp-8448L, -0x4.ef0b6998a234653p-8452L, -0x4.ef0b6998a2346528p-8452L }, - { 0x2.bf26bd5a8657f64p-4L, 0x1.619579cddffcb6aep+12140L, 0x5.0d0ffca3706c2acp+12136L, 0x5.0d0ffca3706c2ac8p+12136L }, - { -0x2.26a816730ea9fa2p-4L, -0x2.1cd826493af5d3a4p+5928L, 0x7.0a714112caed041p+5924L, 0x7.0a714112caed0418p+5924L }, - { 0x1.f4ebd7a17a5e1fd4p-4L, -0x8.ca91adedeaa1e77p-14972L, -0x1.769cbd033d773138p-14972L, -0x1.769cbd033d773136p-14972L }, - { -0x4.9755a649fce3a72p-4L, 0x1.9ffbbc6c991dce28p+2304L, -0xc.af74ccc1edf3feep+2300L, -0xc.af74ccc1edf3fedp+2300L }, - { 0x2.03c9c35825e8cce8p-4L, -0x4.c58df0c00390e39p+14776L, -0xd.1055487d9d10608p+14772L, -0xd.1055487d9d10607p+14772L }, - { -0x1.4a829868b2d07d8ap-4L, 0x6.ec9b9c24e5dad6d8p-6360L, -0xd.727e7114ad2833ep-6364L, -0xd.727e7114ad2833dp-6364L }, - { 0x2.e638feebcca21c28p-4L, 0x1.5555753a1fdc2362p-5456L, 0x5.202652e78b04ba6p-5460L, 0x5.202652e78b04ba68p-5460L }, - { -0x9.979149647a1982ap-8L, 0x1.1f233b6d8f73e8ccp+1520L, -0xf.d1e2d416d88a874p+1512L, -0xf.d1e2d416d88a873p+1512L }, - { 0x7.c696d728e20f0848p-8L, -0x1.5ef60b9d2b73390ap+11924L, -0xf.267aeee72356083p+11916L, -0xf.267aeee72356082p+11916L }, - { -0x4.05c95bb140d74508p-8L, -0x1.ed7fe53fd80fb15ap-13268L, 0xb.46b5e70ab7dc4a7p-13276L, 0xb.46b5e70ab7dc4a8p-13276L }, - { 0x1.2102593d8b22e7bep-4L, -0xd.0f4dc08b32e489ap-10512L, -0x1.48dc788829e9e252p-10512L, -0x1.48dc788829e9e25p-10512L }, - { -0x9.453822cef91e918p-8L, 0x4.86ba6e2b530b797p-4708L, -0x3.da8c9cccd9d956bp-4712L, -0x3.da8c9cccd9d956acp-4712L }, - { 0x1.12f7b7ecee83bc12p-4L, 0x3.6d9e8e1a109a2ec8p-13472L, 0x5.243f0c6c55752578p-13476L, 0x5.243f0c6c5575258p-13476L }, - { -0x2.777e0c0a02694fd4p-4L, 0x3.08ae8e74c266a098p-956L, -0xb.b9e9452b01c070cp-960L, -0xb.b9e9452b01c070bp-960L }, - { 0x6.ed708598p-16416L, -0xf.89d9753e770635ep+11952L, -0x9.b4bb0cc1c6d23bep-4460L, -0x9.b4bb0cc1c6d23bdp-4460L }, - { -0x1.3ab2fe378fa08002p-52L, -0x3.faaa35d0c21a25p-132L, 0x7.0e99197749af91cp-184L, 0x7.0e99197749af91c8p-184L }, - { 0x2.075c4fded02a10dp-4L, -0x1.5c155893f7056016p+13476L, -0x3.bf317f30aab92a88p+13472L, -0x3.bf317f30aab92a84p+13472L }, - { -0x3.5dd7c365c8f83704p-4L, 0xa.1cb34dbd6cd395fp+11084L, -0x3.724bd3f3733cf154p+11084L, -0x3.724bd3f3733cf15p+11084L }, - { 0x4.47f11be2f8a972c8p-4L, -0x1.736a1fc6a5a78362p+7336L, -0x7.f0ba632851590e18p+7332L, -0x7.f0ba632851590e1p+7332L }, - { -0x2.9823a4b955403824p-4L, -0x1.b699f56c55fc52a4p+216L, 0x6.ff120dac9ded8abp+212L, 0x6.ff120dac9ded8ab8p+212L }, - { 0x4.1a23ac74ce37c868p-4L, -0x1.857b2ba5a176f0aap-11308L, -0x8.03f0f38f6e53751p-11312L, -0x8.03f0f38f6e5375p-11312L }, - { -0xa.1f42d577650c9adp-8L, 0x2.c4758147ef57417cp+13012L, -0x2.93bcd7ecd68feaa8p+13008L, -0x2.93bcd7ecd68feaa4p+13008L }, - { 0x1.84b9cdd00271f558p-4L, 0x1.3a2fc03e0387d0bcp-14720L, 0x2.918ccc5362c1ca84p-14724L, 0x2.918ccc5362c1ca88p-14724L }, - { -0x2.73a88be3087e5338p-4L, 0xe.bc8d2b7772f396p-2136L, -0x3.894c4ef8b23ccf6p-2136L, -0x3.894c4ef8b23ccf5cp-2136L }, - { 0x1.17e8c62b745eff6ap-4L, -0x4.017bb7f9858a1c18p+12L, -0x6.1cc20f6aafe3d05p+8L, -0x6.1cc20f6aafe3d048p+8L }, - { -0x1.08a6904e103c8a42p-4L, 0x4.245b3e4558ce84e8p+6880L, -0x6.62de455bb063efc8p+6876L, -0x6.62de455bb063efcp+6876L }, - { 0x9.3c659a1e94df67fp-8L, -0x3.2b939ab516941194p+14296L, -0x2.97f72ef04ae09db8p+14292L, -0x2.97f72ef04ae09db4p+14292L }, - { -0x2.b761508254c49454p-4L, 0xc.e0c6bc3b7739bb7p-4252L, -0x3.74e9fc4c3e6a1f4cp-4252L, -0x3.74e9fc4c3e6a1f48p-4252L }, - { 0x1.55e43d50aa1de912p-4L, 0x5.13ab96c153d35eb8p-11768L, 0x9.65173e148f5a0ap-11772L, 0x9.65173e148f5a0a1p-11772L }, - { -0xf.543ac800941658ep-8L, -0x6.20199bbcb0f17f4p+5288L, 0x8.bb05c1a6d35f348p+5284L, 0x8.bb05c1a6d35f349p+5284L }, - { 0x3.56f9ca36fbdfa67p-4L, 0x1.d50869ea25276784p-8844L, 0x8.04776fbae54cc54p-8848L, 0x8.04776fbae54cc55p-8848L }, - { -0x2.d2b77bbab795dc74p-4L, -0x2.7faeedff97b59518p-8980L, 0xb.326b17219f8d2c7p-8984L, 0xb.326b17219f8d2c8p-8984L }, - { 0x3.3b96a64d429b4d74p-4L, -0x2.9d9c43b7825d326p+12716L, -0xb.1c721c34cbaf487p+12712L, -0xb.1c721c34cbaf486p+12712L }, - { -0xc.8d12f03af1ad8dp-8L, 0x1.1f16f03ddddac2b2p+2568L, -0x1.4d231dfe98d4ceacp+2564L, -0x1.4d231dfe98d4ceaap+2564L }, - { 0x3.8f9ba551c055efep-4L, -0x4.bdce2365684786f8p+11256L, -0x1.5fe3aa07b1e38e1p+11256L, -0x1.5fe3aa07b1e38e0ep+11256L }, - { -0x2.fd0968609dfabf38p-4L, -0x3.9f3872fe7a19d514p-7100L, 0x1.149160a36b1937d4p-7100L, 0x1.149160a36b1937d6p-7100L }, - { 0x3.a1bc97534cf86254p-120L, 0xe.078e9669dcc8821p-3916L, 0x4.9822a91bbcaa6d3p-4032L, 0x4.9822a91bbcaa6d38p-4032L }, - { -0x9.0e702a7e143108fp-164L, -0x4.f196f6e23fedaebp+3012L, 0x4.097b774bec74e7bp+2852L, 0x4.097b774bec74e7b8p+2852L }, - { 0x2.a7f9d0e587d0031cp-4L, -0x1.7df0e27c0ccf76bcp+372L, -0x5.4a1628b2dfeb3de8p+368L, -0x5.4a1628b2dfeb3dep+368L }, - { -0x1.98c8703e63e3b9f4p-4L, -0x7.c403891453f18a28p-10492L, 0x1.2d8c742191748b96p-10492L, 0x1.2d8c742191748b98p-10492L }, - { 0x2.7f9a121a213dffe8p-4L, 0x1.60a510438baeb314p+13976L, 0x4.9d1e27c49a25cffp+13972L, 0x4.9d1e27c49a25cff8p+13972L }, - { -0x3.883ffac36198bb74p-4L, 0x1.ba64610e5fc1c95p+2376L, -0x9.f33e8f6c9f253b3p+2372L, -0x9.f33e8f6c9f253b2p+2372L }, - { 0x1.b65b0807a6b7ed1ap-4L, -0xd.a336acdf6754e5bp+7972L, -0x2.0018f97311be95d4p+7972L, -0x2.0018f97311be95dp+7972L }, - { -0x1.e1d113619cb17674p-4L, -0xc.c9f8ff221cab8ddp-2844L, 0x2.4f1a50a2821f20b4p-2844L, 0x2.4f1a50a2821f20b8p-2844L }, - { 0x2.914e861be45c55e8p-8L, 0x1.55c48d407375e2cap-2168L, 0x4.ebb18aef8402f5c8p-2176L, 0x4.ebb18aef8402f5dp-2176L }, - { -0x2.f5709c93a8a0a9dp-4L, 0x7.b9cef07eaf4eed7p-4876L, -0x2.476edf2184857d34p-4876L, -0x2.476edf2184857d3p-4876L }, - { 0x3.648cf748ec9e27f8p-4L, 0x3.1423bae5f0affdccp-12004L, 0xd.aaad3e8f8eb0b16p-12008L, 0xd.aaad3e8f8eb0b17p-12008L }, - { -0x3.61791f35cba8863p-4L, -0x8.74595f3c5c6cb4dp-1688L, 0x2.e52c5807e549f5dcp-1688L, 0x2.e52c5807e549f5ep-1688L }, - { 0x1.b82710349d66924cp-4L, 0x7.e61a34168ab5f008p-8164L, 0x1.29c2f5adf7458efp-8164L, 0x1.29c2f5adf7458ef2p-8164L }, - { -0x3.4d11e5ccd6ac7cap-4L, -0x3.9a82f3943aa5a188p-9436L, 0x1.3388089c3b0d5588p-9436L, 0x1.3388089c3b0d558ap-9436L }, - { 0x4.9428b7da62c702b8p-4L, 0xd.1467d75f56bcf5ep-11520L, 0x4.bfbff268e075cc18p-11520L, 0x4.bfbff268e075cc2p-11520L }, - { -0x2.6b566d5498306d08p-4L, -0x3.ccde3d308a22eb5cp+10760L, 0xe.6187fe1b7bad52ap+10756L, 0xe.6187fe1b7bad52bp+10756L }, - { 0xf.c0bf63c433c05f9p-8L, 0x2.492819446118a574p+1964L, 0x3.26989997ddb6f92cp+1960L, 0x3.26989997ddb6f93p+1960L }, - { -0x3.6892bbb36e176cecp-4L, 0xf.d741a00abd03d2p-4572L, -0x5.799464669eee8fp-4572L, -0x5.799464669eee8ef8p-4572L }, - { 0x2.3ccc852342a3e2ep-4L, -0x1.092e784e29e30784p-14964L, -0x3.21364368eb287a8p-14968L, -0x3.21364368eb287a7cp-14968L }, - { -0x3.dabe1d3a5400a66cp-4L, 0x3.819f5f8d05fa313p+14716L, -0x1.64ef8bbed09c8112p+14716L, -0x1.64ef8bbed09c811p+14716L }, - { 0x2.6c673a145214ba98p-4L, -0xf.03aefac3e377757p-14792L, -0x3.0e1458d47bc4cb5cp-14792L, -0x3.0e1458d47bc4cb58p-14792L }, - { -0x4.0e4a540e71cc0288p-8L, 0x2.2419fb7ebbf4a7d8p-1068L, -0xc.a0ca66c14def27p-1076L, -0xc.a0ca66c14def26fp-1076L }, - { 0x4.dd8f85c8p-16416L, -0xf.980d0cd19d231dp+11088L, -0x6.d75c47eef8bbfbap-5324L, -0x6.d75c47eef8bbfb98p-5324L }, - { -0x7.f51abd665f9bee8p-36L, 0x1.dcd6e7960fd2d35cp-6200L, -0x1.562314b0db6f2412p-6232L, -0x1.562314b0db6f241p-6232L }, - { 0x2.3cac744f1052e66p-4L, 0x2.62280853a9ba5768p+8628L, 0x7.3321a245f69bf7ap+8624L, 0x7.3321a245f69bf7a8p+8624L }, - { -0x3.3f453518bf958f1p-4L, -0x1.8abf11344317fd2ep+5524L, 0x8.12e7dcb9203daf8p+5520L, 0x8.12e7dcb9203daf9p+5520L }, - { 0x4.a37a0a2e94817af8p-4L, 0x3.31608177e97de46p+4688L, 0x1.2c3317257700dc6cp+4688L, 0x1.2c3317257700dc6ep+4688L }, - { -0x2.759bed88d3ee0a9cp-4L, -0x1.23025455b6bb4b3cp-3840L, 0x4.611cf16d993dc978p-3844L, 0x4.611cf16d993dc98p-3844L }, - { 0x2.b2f4298813acd09p-4L, -0x1.5260cf8ab304676ep+12932L, -0x4.c193d858e5159aa8p+12928L, -0x4.c193d858e5159aap+12928L }, - { -0x3.02ab01e994f9301p-4L, -0x2.05a8427f1a2184bp-10208L, 0x9.bab237364385aefp-10212L, 0x9.bab237364385afp-10212L }, - { 0x3.9dd2497df6505db8p-4L, -0x5.ef9d56c6ff28bfdp+6132L, -0x1.bec25594dc09e1c2p+6132L, -0x1.bec25594dc09e1cp+6132L }, - { -0x3.1f36e2acdac799cp-4L, 0x1.fe0c5686cbb69ae8p+2348L, -0x9.fb9770501834541p+2344L, -0x9.fb977050183454p+2344L }, - { 0x3.f9f38bcacc608ea4p-4L, -0xc.a975585bddf812bp-13688L, -0x4.0dfd1663aa583348p-13688L, -0x4.0dfd1663aa58334p-13688L }, - { -0x1.e46e7b9f1fb532bep-4L, -0x2.bcb39ddfe1c68248p-9104L, 0x7.f3d951935813894p-9108L, 0x7.f3d9519358138948p-9108L }, - { 0x9.4556c7b62d8c8cfp-8L, -0x1.0eeffe20e57f824ap-6140L, -0xd.e7b819b422e8faep-6148L, -0xd.e7b819b422e8fadp-6148L }, - { -0x3.8ca02be25fde5288p-4L, -0x2.815db6eb9885e86p+11972L, 0xe.81398e978d87862p+11968L, 0xe.81398e978d87863p+11968L }, - { 0x2.98b2b17e1c13daccp-4L, -0x5.d0c98aabaedb1fbp+9108L, -0x1.4300e03ac130142cp+9108L, -0x1.4300e03ac130142ap+9108L }, - { -0x1.b53661215c292a9ap-4L, 0xc.ea5c116014da9b3p-1576L, -0x2.1a70dbc7c639fd2cp-1576L, -0x2.1a70dbc7c639fd28p-1576L }, - { 0x3.a9585cd202a6d0c4p-4L, 0xc.13d12aa5f2fb35ap+5048L, 0x3.9733ed35d1e948b4p+5048L, 0x3.9733ed35d1e948b8p+5048L }, - { -0x2.7e3ce1ae5b5d40fp-12L, -0x1.6ac3d1cdbddd70c6p+6624L, 0x5.19314cff3a227e4p+6612L, 0x5.19314cff3a227e48p+6612L }, - { 0x3.7200d9155209c2acp-4L, -0x1.a45b5a228d4622ep-3568L, -0x7.6449cd5931a2d96p-3572L, -0x7.6449cd5931a2d958p-3572L }, - { -0x1.a1a30e0fbfd17eb4p-4L, 0x8.8af95da1e0b1a78p+4272L, -0x1.535022cb1f7efafcp+4272L, -0x1.535022cb1f7efafap+4272L }, - { 0x2.33bf12728763519cp-4L, 0x2.6686b8dba75ea304p-2056L, 0x7.252e6bd693f1342p-2060L, 0x7.252e6bd693f13428p-2060L }, - { -0xc.90d32e60a9fdbc3p-8L, 0x3.62ff10781a5bdf74p-4852L, -0x3.ef43238141c37684p-4856L, -0x3.ef43238141c3768p-4856L }, - { 0x7.5625c9523f78c92p-152L, 0x6.33a7de5685f56b88p+2796L, 0x4.1a44ed3d49f37aep+2648L, 0x4.1a44ed3d49f37ae8p+2648L }, - { -0x1.0ac1f2f8p-16416L, 0x1.02a1bda3565bc8fap-3500L, -0x8p-16448L, -0x0p+0L }, - { 0x2.f11c7fc4f146158cp-4L, -0x1.77606bad7e693d04p+2548L, -0x5.b67ed1c0247fe558p+2544L, -0x5.b67ed1c0247fe55p+2544L }, - { -0x1.e932f553a0ce9d4p-4L, -0x1.c28b03b6522311d4p+5524L, 0x5.2ac3ccf307a22a88p+5520L, 0x5.2ac3ccf307a22a9p+5520L }, - { 0x2.28ebcd228b766488p-4L, 0x9.8ddc34fd380f7cdp+14008L, 0x1.becf6f24b98f4aap+14008L, 0x1.becf6f24b98f4aa2p+14008L }, - { -0x2.05aa67d0e7893ffp-8L, 0xa.a847a961d00df0ap+12556L, -0x1.f36dd414d6b2b91ep+12552L, -0x1.f36dd414d6b2b91cp+12552L }, - { 0x8.61b6b3ddab95935p-8L, 0x3.4f402dd17b106c64p-1012L, 0x2.761010bf33f5993cp-1016L, 0x2.761010bf33f5994p-1016L }, - { -0x1.9b432de297579e68p-4L, 0x3.5fa4d9a9fc21151cp+12192L, -0x8.3d6ac109bb4c2a7p+12188L, -0x8.3d6ac109bb4c2a6p+12188L }, - { 0x1.f2c45be62dde2318p-4L, -0xa.5a267aef528216ep+2032L, -0x1.b754d0e25e0a58dap+2032L, -0x1.b754d0e25e0a58d8p+2032L }, - { -0xe.c7886d486b1423bp-8L, -0x5.f0ff7cfd1f4b93d8p+11376L, 0x8.27cda2dd6d26dp+11372L, 0x8.27cda2dd6d26d01p+11372L }, - { 0x2.f148d81ff59e6c9cp-4L, 0x1.c09e468785b5c354p-7792L, 0x6.d43859f4941b858p-7796L, 0x6.d43859f4941b8588p-7796L }, - { -0x4.a7fa8456a5738f48p-4L, 0xb.8cf756c51b10491p-12304L, -0x5.bb23984d4ca08e1p-12304L, -0x5.bb23984d4ca08e08p-12304L }, - { 0x2.b29a39d96a13c414p-4L, 0x5.04f17d6142a2ec78p-4464L, 0x1.20d66e21c7406f52p-4464L, 0x1.20d66e21c7406f54p-4464L }, - { -0x3.77d74e76e2309764p-4L, -0x1.c3e2606dd5d09a4ep+9832L, 0x9.f4693dade8d5703p+9828L, 0x9.f4693dade8d5704p+9828L }, - { 0x4.09e8d44c0a9dec4p-8L, -0x3.f98c983119717b98p+5448L, -0x1.6fa98b37837c778ep+5444L, -0x1.6fa98b37837c778cp+5444L }, - { -0x4.863fe515ba68863p-4L, 0x2.44a0fe29d471fe0cp+6924L, -0x1.1669eef8591793ep+6924L, -0x1.1669eef8591793dep+6924L }, - { 0x2.4d7dfb360ed7fc04p-4L, -0x4.f0d30f06332ddp-12644L, -0xf.55b574e4f66676dp-12648L, -0xf.55b574e4f66676cp-12648L }, - { -0x2.321867445cc97e58p-4L, 0x2.9f2b2d00894a5d88p+4876L, -0x8.eed56b3be3be27p+4872L, -0x8.eed56b3be3be26fp+4872L }, - { 0x1.0f1653c21d88f58p-4L, 0x7.1d5b99213d03b6e8p+8576L, 0xa.8651050e953498ap+8572L, 0xa.8651050e953498bp+8572L }, - { -0x2.8cc781990c3e3904p-8L, 0x1.a7d261806a6e3d7ap+11852L, -0x6.1ef42f9c5224235p+11844L, -0x6.1ef42f9c52242348p+11844L }, - { 0x2.048284a37fa5629cp-4L, -0x3.94e24b6aa1db9f44p-8368L, -0x9.d187169aa9e30fdp-8372L, -0x9.d187169aa9e30fcp-8372L }, - { -0x2.7270920cc658bdfcp-4L, 0x2.2e30b685d8bcaea4p-2292L, -0x8.5aa759a252e70d6p-2296L, -0x8.5aa759a252e70d5p-2296L }, - { 0x5.dfbf765p-16416L, 0x1.75ea58cb0a2a111cp+1256L, 0xc.60b6aa985c7126p-15160L, 0xc.60b6aa985c71261p-15160L }, - { -0xe.1d7e71fee6192bap-40L, 0x9.4f89ff3200affa3p-10532L, -0xb.d9a41b81a0ded4cp-10568L, -0xb.d9a41b81a0ded4bp-10568L }, - { 0x4.56aa4f6cc88118d8p-4L, -0x3.f63ba994a2b78004p+10588L, -0x1.5f1214fe4a6577a8p+10588L, -0x1.5f1214fe4a6577a6p+10588L }, - { -0x6.4b399c5d6f79c53p-8L, 0x5.20a0673897bdb3p-7740L, -0x2.f23beac70fa873bp-7744L, -0x2.f23beac70fa873acp-7744L }, - { 0x3.1e0ea75bc7ed36ccp-4L, 0x8.e27b579a17f1c4dp-8756L, 0x2.481f238e55239f44p-8756L, 0x2.481f238e55239f48p-8756L }, - { -0x3.f633c649d5060228p-4L, 0x5.d72f16fe681c1abp-3536L, -0x2.65b046536bfbeb0cp-3536L, -0x2.65b046536bfbeb08p-3536L }, - { 0x2.d5c982b9a0bb948p-4L, 0x2.a22fd9997a52536cp-1444L, 0x9.eabe16ba330ce96p-1448L, 0x9.eabe16ba330ce97p-1448L }, - { -0x3.2a5af82e25817eecp-4L, 0x2.7171b5c5ce8e77acp-12700L, -0xc.6ea7205da7d336ep-12704L, -0xc.6ea7205da7d336dp-12704L }, - { 0x1.0fb5e02c9615884p-4L, -0x4.3cbd69afe18488ap+14960L, -0x6.4837d3bd5446182p+14956L, -0x6.4837d3bd54461818p+14956L }, - { -0x2.ebb14b0f25d3d54cp-4L, -0x3.f0fb7afa6ec2cfb8p+32L, 0x1.256547ff3538326ap+32L, 0x1.256547ff3538326cp+32L }, - { 0xa.4b37ca400e3e139p-8L, -0x2.2bd7a614add96564p-2988L, -0x1.f9d15a8fce18accp-2992L, -0x1.f9d15a8fce18acbep-2992L }, - { -0x1.9dfb38f66e6ce44ap-4L, 0x1.410266a44f4ade2cp+14432L, -0x3.1585cfd6c0bc80c4p+14428L, -0x3.1585cfd6c0bc80cp+14428L }, - { 0xc.89886ba4ab470fap-8L, 0x2.4d20ce827eba1d5cp-6572L, 0x2.8a31828e7806188cp-6576L, 0x2.8a31828e7806189p-6576L }, - { -0x2.cf1bd2db6eece3bp-4L, -0x9.81d66bb4eea5f5dp+8664L, 0x2.a5df5372cf8ee82p+8664L, 0x2.a5df5372cf8ee824p+8664L }, - { 0x3.d52f7205e2265278p-4L, -0x5.8137ad906185b418p-4344L, -0x1.b4981d0839394732p-4344L, -0x1.b4981d083939473p-4344L }, - { -0x4.068ea746952344c8p-4L, -0x3.bc6a67b96be7c0ecp-1508L, 0x1.8fe5914831f7a6f8p-1508L, 0x1.8fe5914831f7a6fap-1508L }, - { 0x2.4a7156c47e3c5cfp-4L, 0x7.a3b09d22470dbdbp+13304L, 0x1.798992cc1888896ep+13304L, 0x1.798992cc1888897p+13304L }, - { -0x2.27f0bcaf31f43d84p-4L, -0x2.52eaea727fb51b3cp-2292L, 0x7.c39f824994a1ee3p-2296L, 0x7.c39f824994a1ee38p-2296L }, - { 0x7.714aee9717d46d38p-8L, 0x1.1e6c22f27b1bf57ap+5028L, 0xb.d78e0ad132d5ff6p+5020L, 0xb.d78e0ad132d5ff7p+5020L }, - { -0x3.87ec179e6586821p-4L, 0x9.4b4c59fac13b018p+1888L, -0x3.57e18719fdcf879cp+1888L, -0x3.57e18719fdcf8798p+1888L }, - { 0x3.3d30b32379a65114p-4L, 0x4.c5d29adfdda9ea18p+4440L, 0x1.44f5e4b2409b9124p+4440L, 0x1.44f5e4b2409b9126p+4440L }, - { -0x2.e2bda144c2f2277p-4L, 0x5.64267b2495b7c128p-1996L, -0x1.8c024b9431e50014p-1996L, -0x1.8c024b9431e50012p-1996L }, - { 0x4.9de5e3de07d9f6c8p-68L, 0x9.e7a6b488ba25371p-10492L, 0x4.1f9017df12388bb8p-10556L, 0x4.1f9017df12388bcp-10556L }, - { -0x7.eeb8e528p-16416L, -0x7.bd9dbdb1739d2078p+4548L, 0x5.895fe80806e16bf8p-11864L, 0x5.895fe80806e16cp-11864L }, - { 0x2.8c83c5564b76a9ap-4L, 0x1.952d401223808022p+7108L, 0x5.66882b0ad5c27dep+7104L, 0x5.66882b0ad5c27de8p+7104L }, - { -0x2.4d42d236c3d3fd98p-4L, -0x1.ab5e5d1fb46d837cp-4360L, 0x5.fc465dcd2d8a37ep-4364L, 0x5.fc465dcd2d8a37e8p-4364L }, - { 0x4.6ae6b426dff3a728p-4L, -0x1.18b02e8036eaf6fp-2520L, -0x6.2bab4a04d616aaf8p-2524L, -0x6.2bab4a04d616aafp-2524L }, - { -0x2.3a083ce38aa2c904p-8L, -0x3.4db11e32b03da7ep-11912L, 0xa.a89c94dda8a851ap-11920L, 0xa.a89c94dda8a851bp-11920L }, - { 0x2.9ec8fd0020cc084p-4L, 0x1.3dcad9832e8f1d88p+12852L, 0x4.58883200d1e122cp+12848L, 0x4.58883200d1e122c8p+12848L }, - { -0x8.afe56fd65488476p-12L, -0x6.be0fd3b8186a0038p-7268L, 0x5.49768b31e35bebp-7276L, 0x5.49768b31e35beb08p-7276L }, - { 0x2.c9937a12a36f69e4p-4L, 0x2.84f3d72672642d5cp+2680L, 0x9.56e8000300c7c24p+2676L, 0x9.56e8000300c7c25p+2676L }, - { -0x3.6f1d5c73cafd067cp-4L, 0x4.59cae1c34a6ae298p+3720L, -0x1.8436b71ec7d37d58p+3720L, -0x1.8436b71ec7d37d56p+3720L }, - { 0x3.4d8e31567ec04358p-4L, 0xb.15e67692e908166p+728L, 0x3.005c2fd462395254p+728L, 0x3.005c2fd462395258p+728L }, - { -0x2.6fd4b22406dd3548p-4L, -0x5.32ae39061f42ebfp-3816L, 0x1.3d34a2d69fb46afap-3816L, 0x1.3d34a2d69fb46afcp-3816L }, - { 0x3.a481c0c1bd38eeccp-4L, 0x1.31f75b812f26c6fp-4144L, 0x5.a8a308f4e33ea0bp-4148L, 0x5.a8a308f4e33ea0b8p-4148L }, - { -0x2.74946e84015b7904p-4L, -0xe.ef2009edfa62e1p-7280L, 0x3.96e65616243fb15p-7280L, 0x3.96e65616243fb154p-7280L }, - { 0x4.6bc95d66b99cb698p-4L, 0x6.ec530160d23ac0ap+9560L, 0x2.6fd4a9c6a61334b8p+9560L, 0x2.6fd4a9c6a61334bcp+9560L }, - { -0x2.af79152508966b7p-4L, -0x3.033c0f9587a37dacp+9720L, 0xc.c6dd7b7b703686cp+9716L, 0xc.c6dd7b7b703686dp+9716L }, - { 0x4.12d04be0b70108dp-4L, 0x1.026134c613738e1p+832L, 0x5.48c0269f3bdf4c58p+828L, 0x5.48c0269f3bdf4c6p+828L }, - { -0x1.c5ad26059c8173c6p-4L, -0x1.902f5e5d3170116ep-600L, 0x4.3c6233f83fc19d08p-604L, 0x4.3c6233f83fc19d1p-604L }, - { 0x2.dccc064c67226e14p-4L, 0x6.2cbe80578c0dfd4p+3320L, 0x1.77583ce754d1405ep+3320L, 0x1.77583ce754d1406p+3320L }, - { -0x3.3fa98ff5a2971bfcp-4L, -0x8.b7bd8b1ef0ee6b8p+2360L, 0x2.daba824595904f3p+2360L, 0x2.daba824595904f34p+2360L }, - { 0x1.d8602eb4d94e28ecp-4L, -0x2.bae59a7e7af9a67cp+3584L, -0x6.e0d5db7658c5c028p+3580L, -0x6.e0d5db7658c5c02p+3580L }, - { -0x3.6c3a213e7b4881bp-4L, 0x5.494bb22b56f01408p+10044L, -0x1.d5f0eafdebb7153ep+10044L, -0x1.d5f0eafdebb7153cp+10044L }, - { 0x1.93f52cf9da54bfd2p-188L, 0x6.7a10e84122b54878p+13800L, 0xe.be9ca7b0c77d0b6p+13612L, 0xe.be9ca7b0c77d0b7p+13612L }, - { -0x4.58f5e4ap-16416L, -0x1.fe7de6b1cc44106ep+8880L, 0xc.81dd9ac770a9c4dp-7536L, 0xc.81dd9ac770a9c4ep-7536L }, - { 0x5.27c48a1ec2d6863p-8L, 0x2.977a191025cba5c4p+5568L, 0x1.315a3386fa9d6726p+5564L, 0x1.315a3386fa9d6728p+5564L }, - { -0x2.eb002870df40a93p-4L, -0x5.08c29ee62ab9a4c8p+692L, 0x1.765dc5a976721a6ap+692L, 0x1.765dc5a976721a6cp+692L }, - { 0x2.35b97b8a544150a4p-4L, -0x1.876176fc24a19868p-12496L, -0x4.90cea080288cc9c8p-12500L, -0x4.90cea080288cc9cp-12500L }, - { -0x4.20fe502368675c3p-4L, 0x2.89b504f1eeca05ep+14364L, -0x1.17c6332d638442ecp+14364L, -0x1.17c6332d638442eap+14364L }, - { 0x1.3507193d9fcdf874p-8L, -0x4.44ed38babbc1a31p-6140L, -0x7.6ae54c90c135363p-6148L, -0x7.6ae54c90c1353628p-6148L }, - { -0x4.9c77377231cc5c68p-4L, 0x3.0df98b1b24a9fd5p+8788L, -0x1.7f86156db3450b48p+8788L, -0x1.7f86156db3450b46p+8788L }, - { 0x4.6bfb936cb1cc028p-4L, 0x1.a2b46ba8847fdacap+12288L, 0x9.36677b413811f5ap+12284L, 0x9.36677b413811f5bp+12284L }, - { -0x7.fe3a8eade3847d6p-8L, -0x1.2e4dc4b59c87951ep-5840L, 0xd.d59f3e0866526ffp-5848L, 0xd.d59f3e0866527p-5848L }, - { 0x3.bd32a8458d6aa984p-4L, 0xf.95ff672171f9ce3p-5912L, 0x4.b8e4b10ffb79ebfp-5912L, 0x4.b8e4b10ffb79ebf8p-5912L }, - { -0xf.68a5c2a7fb327c8p-8L, -0xd.06212bca315272ap+7596L, 0x1.2a9aa0cc67647bc4p+7596L, 0x1.2a9aa0cc67647bc6p+7596L }, - { 0x2.d63c10403cb6b6ep-4L, 0x8.9e2a941dc61ad8fp+14140L, 0x2.078585b0204e1778p+14140L, 0x2.078585b0204e177cp+14140L }, - { -0x2.6b6b837e7eb6ae64p-4L, 0x4.23ab68b527c43a3p+2648L, -0xf.aa95c9793bf78dfp+2644L, -0xf.aa95c9793bf78dep+2644L }, - { 0x3.91cf23ec265a44bcp-4L, -0x4.bc960cdc39b32268p-9416L, -0x1.604dfff2b63b8282p-9416L, -0x1.604dfff2b63b828p-9416L }, - { -0x2.bc4062eed81cc3acp-4L, -0x1.fa0727fe515c697ap-11556L, 0x8.8df9fc101ed9003p-11560L, 0x8.8df9fc101ed9004p-11560L }, - { 0x2.b0fa1e0dd7f558a4p-4L, 0x5.8280a606a48f5318p+10272L, 0x1.3c5ed74d77afe5a6p+10272L, 0x1.3c5ed74d77afe5a8p+10272L }, - { -0x3.d2579cb3ff0ee9f8p-4L, -0x8.0b945d741ecd16ap-1048L, 0x3.2af74742433897ap-1048L, 0x3.2af74742433897a4p-1048L }, - { 0x3.c535c7bd86beae28p-4L, -0xf.2f9fb8404b10c06p+10324L, -0x4.a2c30bd72da67518p+10324L, -0x4.a2c30bd72da6751p+10324L }, - { -0x2.dff8fb970f266844p-4L, -0x3.74fd4274bff9725cp-1160L, 0xf.ce11601a35fdcdbp-1164L, 0xf.ce11601a35fdcdcp-1164L }, - { 0x1.4b5ff1e4dc2e3c8ap-4L, 0xd.153b5302441b7e9p-1056L, 0x1.77e756dd04bced5ep-1056L, 0x1.77e756dd04bced6p-1056L }, - { -0x2.2377af118d3b64d8p-4L, 0x1.4bd65cdbcd0ba822p+11900L, -0x4.4b025c7b23622dc8p+11896L, -0x4.4b025c7b23622dcp+11896L }, - { 0x6.95a6923d8b1019fp-48L, -0xe.509d14cf004cbe5p+2568L, -0x8.7fc1c0221d2a71cp+2524L, -0x8.7fc1c0221d2a71bp+2524L }, - { -0x6.35b4505c73bc73f8p-148L, -0x2.beb5ae276a22e078p-11460L, 0x1.897739142f742bcap-11604L, 0x1.897739142f742bccp-11604L }, - { 0x1.c09464de3920faa2p-4L, -0xe.76812b4dfc9816p-1364L, -0x2.2b1eea208c44b79p-1364L, -0x2.2b1eea208c44b78cp-1364L }, - { -0x4.62afbcd5d3fdceap-4L, 0x4.7c65d956f633426p+10856L, -0x2.12b9ade27f17cfep+10856L, -0x2.12b9ade27f17cfdcp+10856L }, - { 0x1.1eb7165174c4df74p-4L, 0x5.dd67d7554c7a8508p+13252L, 0x9.28d0f9cf98b2726p+13248L, 0x9.28d0f9cf98b2727p+13248L }, - { -0x6.1647cb705094df4p-8L, 0x5.ec80442e2871996p+2424L, -0x3.4a663d160a45da88p+2420L, -0x3.4a663d160a45da84p+2420L }, - { 0x4.8cdb06d2fa8dce68p-4L, -0x1.0734bf21712e7332p-4704L, -0x5.f09f4db0c1add98p-4708L, -0x5.f09f4db0c1add978p-4708L }, - { -0xe.c1625ff5573e525p-8L, 0x3.486cd98536b2738cp-1708L, -0x4.7fae5c446047168p-1712L, -0x4.7fae5c4460471678p-1712L }, - { 0x1.87006f5c5d2ec9eap-4L, -0x8.9ee3d43da2c297ep+9552L, -0x1.22491738b797491ap+9552L, -0x1.22491738b7974918p+9552L }, - { -0x3.3dfd025c24acda3p-4L, -0x8.400dba5a97204e1p-10880L, 0x2.b1fa547bf7acaf78p-10880L, 0x2.b1fa547bf7acaf7cp-10880L }, - { 0x2.5d1332c90ae9c9a4p-4L, -0x1.d15f57eac86808e4p-11748L, -0x5.c81202070960b9d8p-11752L, -0x5.c81202070960b9dp-11752L }, - { -0x2.28cec5c3aa2d0f18p-4L, -0x4.b7f858c41748a67p+9068L, 0xf.caa8d0ecd255b6ep+9064L, 0xf.caa8d0ecd255b6fp+9064L }, - { 0x2.67ce16bc94144a94p-4L, 0x9.ad9bf6e1a2ade89p-1124L, 0x1.f4a2cdc76f7d181p-1124L, 0x1.f4a2cdc76f7d1812p-1124L }, - { -0xe.f6744817cecdd4ep-8L, 0x5.ce4c9a5a4bd4f098p+7716L, -0x8.124097d64be7bd8p+7712L, -0x8.124097d64be7bd7p+7712L }, - { 0x3.22f0bacfe12728f8p-4L, -0x4.d9d086aa5d561098p+9364L, -0x1.40b41e628d5e3048p+9364L, -0x1.40b41e628d5e3046p+9364L }, - { -0x3.a65ad31a6788a01cp-4L, 0x2.2153a3d97331573cp-1800L, -0xc.bb3936c148ee21ap-1804L, -0xc.bb3936c148ee219p-1804L }, - { 0x4.9bdd0004d248afc8p-4L, -0x1.6ebf29fc22091bcp+4728L, -0x8.5eeca757bc17a6ep+4724L, -0x8.5eeca757bc17a6dp+4724L }, - { -0x3.6d1bb2ded9b5e544p-4L, -0x1.363933431c365c5p+6784L, 0x6.bd984ed7081d1dcp+6780L, 0x6.bd984ed7081d1dc8p+6780L }, - { 0x4.5c381c7800220bb8p-4L, -0x1.7a9820b7b4be9b5cp+10592L, -0x8.3a163379e86ae8dp+10588L, -0x8.3a163379e86ae8cp+10588L }, - { -0x6.12772be7f5f9adp-8L, 0x2.5ff922bcfdd1ccf4p+13856L, -0x1.50e2b035b7e3a3c6p+13852L, -0x1.50e2b035b7e3a3c4p+13852L }, - { 0x4.6f048c603adeb688p-4L, -0x7.dcd7d704615cb8ep-7496L, -0x2.c648b04027667808p-7496L, -0x2.c648b04027667804p-7496L }, - { -0x1.426147d80b509dfap-4L, -0x3.b6cb63cc4e57698cp+12696L, 0x7.0727b8bc7de37648p+12692L, 0x7.0727b8bc7de3765p+12692L }, - { 0x7.43a24958p-16416L, -0x1.20c104316e13e7eap+2340L, -0xb.d225983bb5815cp-14076L, -0xb.d225983bb5815bfp-14076L }, - { -0x4.aca95d18p-16416L, -0x4.b253ac25282630fp+5944L, 0x1.fac465fc7e12004p-10468L, 0x1.fac465fc7e120042p-10468L }, - { 0xd.346171700066942p-8L, -0x3.5c5b7a0cde7c0b9p-4344L, -0x3.e6d4bdea75d4f7c8p-4348L, -0x3.e6d4bdea75d4f7c4p-4348L }, - { -0xc.f7fe649ca9f78f1p-8L, -0xe.3a382cc6e7f5879p-4128L, 0x1.112c520281402072p-4128L, 0x1.112c520281402074p-4128L }, - { 0x2.891205a511e09d4p-4L, -0xa.3b1708de40827f3p+9100L, -0x2.2bce95e0f3eadc8p+9100L, -0x2.2bce95e0f3eadc7cp+9100L }, - { -0x2.745b23499b0ba8b8p-4L, 0x1.a50af797227d1b2p-12948L, -0x6.528e377bfd748168p-12952L, -0x6.528e377bfd74816p-12952L }, - { 0x2.e200bf44c048b27p-4L, 0x1.502214b180236b8ep+1004L, 0x5.056320e0e40dcac8p+1000L, 0x5.056320e0e40dcadp+1000L }, - { -0x1.003d0ef8adbf3c9ep-4L, -0x6.b73ddbc1c250fa2p+1172L, 0xa.03b4bfa836d3073p+1168L, 0xa.03b4bfa836d3074p+1168L }, - { 0x4.a8e3b6eba0e5cc5p-4L, -0xa.6207a616c7e6709p+6296L, -0x3.d4256c2208b55f5p+6296L, -0x3.d4256c2208b55f4cp+6296L }, - { -0x2.a92e6e1474be8348p-4L, 0x3.bb46a57c610a305p+7304L, -0xf.aabbe15fe37ce8bp+7300L, -0xf.aabbe15fe37ce8ap+7300L }, - { 0x4.96fd5f79440dfd3p-4L, -0x2.86ed35b8573a3bfcp+624L, -0xe.b63b818d676319ap+620L, -0xe.b63b818d6763199p+620L }, - { -0x3.eca5c520475dad78p-4L, -0x1.112bec17e2eb9514p-7920L, 0x6.ee6ca95de9ffe858p-7924L, 0x6.ee6ca95de9ffe86p-7924L }, - { 0x4.8f4fa442deb571ep-4L, 0x4.bd8cc4d14c3c0818p+3100L, 0x1.b701f77c99e885p+3100L, 0x1.b701f77c99e88502p+3100L }, - { -0x1.cc63ab2f4422f75ep-4L, -0x4.1bd4c5adafb9c458p-7880L, 0xb.4ef13944ce6d745p-7884L, 0xb.4ef13944ce6d746p-7884L }, - { 0x4.5a1c9f3d22df0e3p-4L, -0x4.64d5303735c2074p-6252L, -0x1.866d8aad2725025p-6252L, -0x1.866d8aad2725024ep-6252L }, - { -0x1.55b34aaaa8d19ee2p-4L, 0xf.75a8872ceab3815p-5504L, -0x1.f15dd2d15d4dc058p-5504L, -0x1.f15dd2d15d4dc056p-5504L }, - { 0x2.b3311b1a7010d558p-4L, 0x1.1ecd98b620696b2ep-3596L, 0x4.085356c3e0bf9dfp-3600L, 0x4.085356c3e0bf9df8p-3600L }, - { -0x1.68820b6e4592bfc4p-4L, -0x6.67e7a1d8fd4df47p-13612L, 0xd.9f8d17ac5abfbefp-13616L, 0xd.9f8d17ac5abfbfp-13616L }, - { 0x3.b6a73d8796b983bcp-4L, 0xa.68bc997e0f48d23p-14004L, 0x3.2261d9832d9eb434p-14004L, 0x3.2261d9832d9eb438p-14004L }, - { -0x1.aaa0ed7ab388530cp-4L, 0x5.c31f424ba4ed1fd8p-11856L, -0xe.a1394c8e746bdp-11860L, -0xe.a1394c8e746bcffp-11860L }, -}; - -int check_equal(long double res, long double expected) -{ - if (res != expected) { - return 0; - } - return (__builtin_copysignl(1.0L, res) == - __builtin_copysignl(1.0L, expected)); -} - -int main(void) -{ - int ret = 0; - int i; - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - long double ld_res; - __asm__ volatile ("fyl2xp1" : "=t" (ld_res) : - "0" (tests[i].arg0), "u" (tests[i].arg1) : "st(1)"); - if (!check_equal(ld_res, tests[i].down) && - !check_equal(ld_res, tests[i].up)) { - printf("FAIL: fyl2xp1 %La %La, expected %La or %La, got %La\n", - tests[i].arg0, tests[i].arg1, tests[i].down, tests[i].up, - ld_res); - ret = 1; - } - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-muldiv.h b/tests/tcg/i386/test-i386-muldiv.h deleted file mode 100644 index 015f59e157d8..000000000000 --- a/tests/tcg/i386/test-i386-muldiv.h +++ /dev/null @@ -1,76 +0,0 @@ - -void glue(glue(test_, OP), b)(long op0, long op1) -{ - long res, s1, s0, flags; - s0 = op0; - s1 = op1; - res = s0; - flags = 0; - asm ("push %4\n\t" - "popf\n\t" - stringify(OP)"b %b2\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=a" (res), "=g" (flags) - : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", - stringify(OP) "b", s0, s1, res, flags & CC_MASK); -} - -void glue(glue(test_, OP), w)(long op0h, long op0, long op1) -{ - long res, s1, flags, resh; - s1 = op1; - resh = op0h; - res = op0; - flags = 0; - asm ("push %5\n\t" - "popf\n\t" - stringify(OP) "w %w3\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=a" (res), "=g" (flags), "=d" (resh) - : "q" (s1), "0" (res), "1" (flags), "2" (resh)); - printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n", - stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK); -} - -void glue(glue(test_, OP), l)(long op0h, long op0, long op1) -{ - long res, s1, flags, resh; - s1 = op1; - resh = op0h; - res = op0; - flags = 0; - asm ("push %5\n\t" - "popf\n\t" - stringify(OP) "l %k3\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=a" (res), "=g" (flags), "=d" (resh) - : "q" (s1), "0" (res), "1" (flags), "2" (resh)); - printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n", - stringify(OP) "l", op0h, op0, s1, resh, res, flags & CC_MASK); -} - -#if defined(__x86_64__) -void glue(glue(test_, OP), q)(long op0h, long op0, long op1) -{ - long res, s1, flags, resh; - s1 = op1; - resh = op0h; - res = op0; - flags = 0; - asm ("push %5\n\t" - "popf\n\t" - stringify(OP) "q %3\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=a" (res), "=g" (flags), "=d" (resh) - : "q" (s1), "0" (res), "1" (flags), "2" (resh)); - printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n", - stringify(OP) "q", op0h, op0, s1, resh, res, flags & CC_MASK); -} -#endif - -#undef OP diff --git a/tests/tcg/i386/test-i386-pcmpistri.c b/tests/tcg/i386/test-i386-pcmpistri.c deleted file mode 100644 index 1e81ae611acf..000000000000 --- a/tests/tcg/i386/test-i386-pcmpistri.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Test pcmpistri instruction. */ - -#include -#include - -union u { - __m128i x; - unsigned char uc[16]; -}; - -union u s0 = { .uc = { 0 } }; -union u s1 = { .uc = "abcdefghijklmnop" }; -union u s2 = { .uc = "bcdefghijklmnopa" }; -union u s3 = { .uc = "bcdefghijklmnab" }; - -int -main(void) -{ - int ret = 0; - if (_mm_cmpistri(s0.x, s0.x, 0x4c) != 15) { - printf("FAIL: pcmpistri test 1\n"); - ret = 1; - } - if (_mm_cmpistri(s1.x, s2.x, 0x4c) != 15) { - printf("FAIL: pcmpistri test 2\n"); - ret = 1; - } - if (_mm_cmpistri(s1.x, s3.x, 0x4c) != 16) { - printf("FAIL: pcmpistri test 3\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c deleted file mode 100644 index 00d510cf4a10..000000000000 --- a/tests/tcg/i386/test-i386-pseudo-denormal.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Test pseudo-denormal operations. */ - -#include -#include - -union u { - struct { uint64_t sig; uint16_t sign_exp; } s; - long double ld; -}; - -volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; - -volatile long double ld_res; - -int main(void) -{ - short cw; - int ret = 0; - ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld; - if (ld_res != 0x1p-16381L) { - printf("FAIL: pseudo-denormal add\n"); - ret = 1; - } - if (ld_pseudo_m16382.ld != 0x1p-16382L) { - printf("FAIL: pseudo-denormal compare\n"); - ret = 1; - } - /* Set round-upward. */ - __asm__ volatile ("fnstcw %0" : "=m" (cw)); - cw = (cw & ~0xc00) | 0x800; - __asm__ volatile ("fldcw %0" : : "m" (cw)); - __asm__ ("frndint" : "=t" (ld_res) : "0" (ld_pseudo_m16382.ld)); - if (ld_res != 1.0L) { - printf("FAIL: pseudo-denormal round-to-integer\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-shift.h b/tests/tcg/i386/test-i386-shift.h deleted file mode 100644 index 3d8f84bffe7a..000000000000 --- a/tests/tcg/i386/test-i386-shift.h +++ /dev/null @@ -1,185 +0,0 @@ - -#define exec_op glue(exec_, OP) -#define exec_opq glue(glue(exec_, OP), q) -#define exec_opl glue(glue(exec_, OP), l) -#define exec_opw glue(glue(exec_, OP), w) -#define exec_opb glue(glue(exec_, OP), b) - -#ifndef OP_SHIFTD - -#ifdef OP_NOBYTE -#define EXECSHIFT(size, rsize, res, s1, s2, flags) \ - asm ("push %4\n\t"\ - "popf\n\t"\ - stringify(OP) size " %" rsize "2, %" rsize "0\n\t" \ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=g" (res), "=g" (flags)\ - : "r" (s1), "0" (res), "1" (flags)); -#else -#define EXECSHIFT(size, rsize, res, s1, s2, flags) \ - asm ("push %4\n\t"\ - "popf\n\t"\ - stringify(OP) size " %%cl, %" rsize "0\n\t" \ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=q" (res), "=g" (flags)\ - : "c" (s1), "0" (res), "1" (flags)); -#endif - -#if defined(__x86_64__) -void exec_opq(long s2, long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("q", "", res, s1, s2, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "q", s0, s1, res, iflags, flags & CC_MASK); -} -#endif - -void exec_opl(long s2, long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("l", "k", res, s1, s2, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK); -} - -void exec_opw(long s2, long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("w", "w", res, s1, s2, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK); -} - -#else -#define EXECSHIFT(size, rsize, res, s1, s2, flags) \ - asm ("push %4\n\t"\ - "popf\n\t"\ - stringify(OP) size " %%cl, %" rsize "5, %" rsize "0\n\t" \ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=g" (res), "=g" (flags)\ - : "c" (s1), "0" (res), "1" (flags), "r" (s2)); - -#if defined(__x86_64__) -void exec_opq(long s2, long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("q", "", res, s1, s2, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "q", s0, s2, s1, res, iflags, flags & CC_MASK); -} -#endif - -void exec_opl(long s2, long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("l", "k", res, s1, s2, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "l", s0, s2, s1, res, iflags, flags & CC_MASK); -} - -void exec_opw(long s2, long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("w", "w", res, s1, s2, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "w", s0, s2, s1, res, iflags, flags & CC_MASK); -} - -#endif - -#ifndef OP_NOBYTE -void exec_opb(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECSHIFT("b", "b", res, s1, 0, flags); - /* overflow is undefined if count != 1 */ - if (s1 != 1) - flags &= ~CC_O; - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", - stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK); -} -#endif - -void exec_op(long s2, long s0, long s1) -{ - s2 = i2l(s2); - s0 = i2l(s0); -#if defined(__x86_64__) - exec_opq(s2, s0, s1, 0); -#endif - exec_opl(s2, s0, s1, 0); -#ifdef OP_SHIFTD - exec_opw(s2, s0, s1, 0); -#else - exec_opw(s2, s0, s1, 0); -#endif -#ifndef OP_NOBYTE - exec_opb(s0, s1, 0); -#endif -#ifdef OP_CC -#if defined(__x86_64__) - exec_opq(s2, s0, s1, CC_C); -#endif - exec_opl(s2, s0, s1, CC_C); - exec_opw(s2, s0, s1, CC_C); - exec_opb(s0, s1, CC_C); -#endif -} - -void glue(test_, OP)(void) -{ - int i, n; -#if defined(__x86_64__) - n = 64; -#else - n = 32; -#endif - for(i = 0; i < n; i++) - exec_op(0x21ad3d34, 0x12345678, i); - for(i = 0; i < n; i++) - exec_op(0x813f3421, 0x82345679, i); -} - -void *glue(_test_, OP) __init_call = glue(test_, OP); - -#undef OP -#undef OP_CC -#undef OP_SHIFTD -#undef OP_NOBYTE -#undef EXECSHIFT diff --git a/tests/tcg/i386/test-i386-snan-convert.c b/tests/tcg/i386/test-i386-snan-convert.c deleted file mode 100644 index ed6d535ce20e..000000000000 --- a/tests/tcg/i386/test-i386-snan-convert.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Test conversions of signaling NaNs to and from long double. */ - -#include -#include - -volatile float f_res; -volatile double d_res; -volatile long double ld_res; - -volatile float f_snan = __builtin_nansf(""); -volatile double d_snan = __builtin_nans(""); -volatile long double ld_snan = __builtin_nansl(""); - -int issignaling_f(float x) -{ - union { float f; uint32_t u; } u = { .f = x }; - return (u.u & 0x7fffffff) > 0x7f800000 && (u.u & 0x400000) == 0; -} - -int issignaling_d(double x) -{ - union { double d; uint64_t u; } u = { .d = x }; - return (((u.u & UINT64_C(0x7fffffffffffffff)) > - UINT64_C(0x7ff0000000000000)) && - (u.u & UINT64_C(0x8000000000000)) == 0); -} - -int issignaling_ld(long double x) -{ - union { - long double ld; - struct { uint64_t sig; uint16_t sign_exp; } s; - } u = { .ld = x }; - return ((u.s.sign_exp & 0x7fff) == 0x7fff && - (u.s.sig >> 63) != 0 && - (u.s.sig & UINT64_C(0x4000000000000000)) == 0); -} - -int main(void) -{ - int ret = 0; - ld_res = f_snan; - if (issignaling_ld(ld_res)) { - printf("FAIL: float -> long double\n"); - ret = 1; - } - ld_res = d_snan; - if (issignaling_ld(ld_res)) { - printf("FAIL: double -> long double\n"); - ret = 1; - } - f_res = ld_snan; - if (issignaling_d(f_res)) { - printf("FAIL: long double -> float\n"); - ret = 1; - } - d_res = ld_snan; - if (issignaling_d(d_res)) { - printf("FAIL: long double -> double\n"); - ret = 1; - } - return ret; -} diff --git a/tests/tcg/i386/test-i386-sse-exceptions.c b/tests/tcg/i386/test-i386-sse-exceptions.c deleted file mode 100644 index a104f46c11cb..000000000000 --- a/tests/tcg/i386/test-i386-sse-exceptions.c +++ /dev/null @@ -1,813 +0,0 @@ -/* Test SSE exceptions. */ - -#include -#include -#include - -volatile float f_res; -volatile double d_res; - -volatile float f_snan = __builtin_nansf(""); -volatile float f_half = 0.5f; -volatile float f_third = 1.0f / 3.0f; -volatile float f_nan = __builtin_nanl(""); -volatile float f_inf = __builtin_inff(); -volatile float f_ninf = -__builtin_inff(); -volatile float f_one = 1.0f; -volatile float f_two = 2.0f; -volatile float f_zero = 0.0f; -volatile float f_nzero = -0.0f; -volatile float f_min = FLT_MIN; -volatile float f_true_min = 0x1p-149f; -volatile float f_max = FLT_MAX; -volatile float f_nmax = -FLT_MAX; - -volatile double d_snan = __builtin_nans(""); -volatile double d_half = 0.5; -volatile double d_third = 1.0 / 3.0; -volatile double d_nan = __builtin_nan(""); -volatile double d_inf = __builtin_inf(); -volatile double d_ninf = -__builtin_inf(); -volatile double d_one = 1.0; -volatile double d_two = 2.0; -volatile double d_zero = 0.0; -volatile double d_nzero = -0.0; -volatile double d_min = DBL_MIN; -volatile double d_true_min = 0x1p-1074; -volatile double d_max = DBL_MAX; -volatile double d_nmax = -DBL_MAX; - -volatile int32_t i32_max = INT32_MAX; - -#define IE (1 << 0) -#define ZE (1 << 2) -#define OE (1 << 3) -#define UE (1 << 4) -#define PE (1 << 5) -#define EXC (IE | ZE | OE | UE | PE) - -uint32_t mxcsr_default = 0x1f80; -uint32_t mxcsr_ftz = 0x9f80; - -int main(void) -{ - uint32_t mxcsr; - int32_t i32_res; - int ret = 0; - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = f_snan; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: widen float snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = d_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: narrow float underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = d_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: narrow float overflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: narrow float inexact\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = d_snan; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: narrow float snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundss $4, %0, %0" : "=x" (f_res) : "0" (f_min)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: roundss min\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundss $12, %0, %0" : "=x" (f_res) : "0" (f_min)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: roundss no-inexact min\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundss $4, %0, %0" : "=x" (f_res) : "0" (f_snan)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: roundss snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundss $12, %0, %0" : "=x" (f_res) : "0" (f_snan)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: roundss no-inexact snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundsd $4, %0, %0" : "=x" (d_res) : "0" (d_min)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: roundsd min\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundsd $12, %0, %0" : "=x" (d_res) : "0" (d_min)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: roundsd no-inexact min\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundsd $4, %0, %0" : "=x" (d_res) : "0" (d_snan)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: roundsd snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("roundsd $12, %0, %0" : "=x" (d_res) : "0" (d_snan)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: roundsd no-inexact snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("comiss %1, %0" : : "x" (f_nan), "x" (f_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: comiss nan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("ucomiss %1, %0" : : "x" (f_nan), "x" (f_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: ucomiss nan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("ucomiss %1, %0" : : "x" (f_snan), "x" (f_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: ucomiss snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("comisd %1, %0" : : "x" (d_nan), "x" (d_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: comisd nan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("ucomisd %1, %0" : : "x" (d_nan), "x" (d_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: ucomisd nan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("ucomisd %1, %0" : : "x" (d_snan), "x" (d_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: ucomisd snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_max + f_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: float add overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_max + f_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: float add inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_inf + f_ninf; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float add inf -inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_snan + f_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float add snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - f_res = f_true_min + f_true_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: float add FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_max + d_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: double add overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_max + d_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: double add inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_inf + d_ninf; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double add inf -inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_snan + d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double add snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - d_res = d_true_min + d_true_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: double add FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_max - f_nmax; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: float sub overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_max - f_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: float sub inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_inf - f_inf; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float sub inf inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_snan - f_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float sub snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - f_res = f_min - f_true_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: float sub FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_max - d_nmax; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: double sub overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_max - d_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: double sub inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_inf - d_inf; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double sub inf inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_snan - d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double sub snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - d_res = d_min - d_true_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: double sub FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_max * f_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: float mul overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_third * f_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: float mul inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_min * f_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: float mul underflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_inf * f_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float mul inf 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_snan * f_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float mul snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - f_res = f_min * f_half; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: float mul FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_max * d_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: double mul overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_third * d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: double mul inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_min * d_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: double mul underflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_inf * d_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double mul inf 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_snan * d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double mul snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - d_res = d_min * d_half; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: double mul FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_max / f_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: float div overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_one / f_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: float div inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_min / f_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: float div underflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_one / f_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != ZE) { - printf("FAIL: float div 1 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_inf / f_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: float div inf 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_nan / f_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: float div nan 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_zero / f_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float div 0 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_inf / f_inf; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float div inf inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - f_res = f_snan / f_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: float div snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - f_res = f_min / f_two; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: float div FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_max / d_min; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (OE | PE)) { - printf("FAIL: double div overflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_one / d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: double div inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_min / d_max; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: double div underflow\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_one / d_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != ZE) { - printf("FAIL: double div 1 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_inf / d_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: double div inf 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_nan / d_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: double div nan 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_zero / d_zero; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double div 0 0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_inf / d_inf; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double div inf inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - d_res = d_snan / d_third; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: double div snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); - d_res = d_min / d_two; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != (UE | PE)) { - printf("FAIL: double div FTZ underflow\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_max)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: sqrtss inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_nmax)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: sqrtss -max\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_ninf)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: sqrtss -inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_snan)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: sqrtss snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_nzero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: sqrtss -0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : - "0" (-__builtin_nanf(""))); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: sqrtss -nan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_max)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: sqrtsd inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_nmax)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: sqrtsd -max\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_ninf)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: sqrtsd -inf\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_snan)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: sqrtsd snan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_nzero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: sqrtsd -0\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : - "0" (-__builtin_nan(""))); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: sqrtsd -nan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("maxss %1, %0" : : "x" (f_nan), "x" (f_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: maxss nan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("minss %1, %0" : : "x" (f_nan), "x" (f_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: minss nan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("maxsd %1, %0" : : "x" (d_nan), "x" (d_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: maxsd nan\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("minsd %1, %0" : : "x" (d_nan), "x" (d_zero)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: minsd nan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtsi2ss %1, %0" : "=x" (f_res) : "m" (i32_max)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: cvtsi2ss inexact\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtsi2sd %1, %0" : "=x" (d_res) : "m" (i32_max)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: cvtsi2sd exact\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (1.5f)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: cvtss2si inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (0x1p31f)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvtss2si 0x1p31\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (f_inf)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvtss2si inf\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (1.5)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: cvtsd2si inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (0x1p31)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvtsd2si 0x1p31\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (d_inf)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvtsd2si inf\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (1.5f)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: cvttss2si inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (0x1p31f)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvttss2si 0x1p31\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (f_inf)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvttss2si inf\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (1.5)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != PE) { - printf("FAIL: cvttsd2si inexact\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (0x1p31)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvttsd2si 0x1p31\n"); - ret = 1; - } - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (d_inf)); - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != IE) { - printf("FAIL: cvttsd2si inf\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("rcpss %0, %0" : "=x" (f_res) : "0" (f_snan)); - f_res += f_one; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: rcpss snan\n"); - ret = 1; - } - - __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); - __asm__ volatile ("rsqrtss %0, %0" : "=x" (f_res) : "0" (f_snan)); - f_res += f_one; - __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); - if ((mxcsr & EXC) != 0) { - printf("FAIL: rsqrtss snan\n"); - ret = 1; - } - - return ret; -} diff --git a/tests/tcg/i386/test-i386-ssse3.c b/tests/tcg/i386/test-i386-ssse3.c deleted file mode 100644 index 0a42bd03e29a..000000000000 --- a/tests/tcg/i386/test-i386-ssse3.c +++ /dev/null @@ -1,57 +0,0 @@ -/* See if various MMX/SSE SSSE3 instructions give expected results */ -#include -#include -#include - -int main(int argc, char *argv[]) { - char hello[16]; - const char ehlo[8] = "EHLO "; - uint64_t mask = 0x8080800302020001; - - uint64_t a = 0x0000000000090007; - uint64_t b = 0x0000000000000000; - uint32_t c; - uint16_t d; - - const char e[16] = "LLOaaaaaaaaaaaaa"; - const char f[16] = "aaaaaaaaaaaaaaHE"; - - /* pshufb mm1/xmm1, mm2/xmm2 */ - asm volatile ("movq (%0), %%mm0" : : "r" (ehlo) : "mm0", "mm1"); - asm volatile ("movq %0, %%mm1" : : "m" (mask)); - asm volatile ("pshufb %mm1, %mm0"); - asm volatile ("movq %%mm0, %0" : "=m" (hello)); - printf("%s\n", hello); - - /* pshufb mm1/xmm1, m64/m128 */ - asm volatile ("movq (%0), %%mm0" : : "r" (ehlo) : "mm0"); - asm volatile ("pshufb %0, %%mm0" : : "m" (mask)); - asm volatile ("movq %%mm0, %0" : "=m" (hello)); - printf("%s\n", hello); - - /* psubsw mm1/xmm1, m64/m128 */ - asm volatile ("movq %0, %%mm0" : : "r" (a) : "mm0"); - asm volatile ("phsubsw %0, %%mm0" : : "m" (b)); - asm volatile ("movq %%mm0, %0" : "=m" (a)); - printf("%i - %i = %i\n", 9, 7, -(int16_t) a); - - /* palignr mm1/xmm1, m64/m128, imm8 */ - asm volatile ("movdqa (%0), %%xmm0" : : "r" (e) : "xmm0"); - asm volatile ("palignr $14, (%0), %%xmm0" : : "r" (f)); - asm volatile ("movdqa %%xmm0, (%0)" : : "r" (hello)); - printf("%5.5s\n", hello); - -#if 1 /* SSE4 */ - /* popcnt r64, r/m64 */ - asm volatile ("movq $0x8421000010009c63, %%rax" : : : "rax"); - asm volatile ("popcnt %%ax, %%dx" : : : "dx"); - asm volatile ("popcnt %%eax, %%ecx" : : : "ecx"); - asm volatile ("popcnt %rax, %rax"); - asm volatile ("movq %%rax, %0" : "=m" (a)); - asm volatile ("movl %%ecx, %0" : "=m" (c)); - asm volatile ("movw %%dx, %0" : "=m" (d)); - printf("%i = %i\n%i = %i = %i\n", 13, (int) a, 9, c, d + 1); -#endif - - return 0; -} diff --git a/tests/tcg/i386/test-i386-vm86.S b/tests/tcg/i386/test-i386-vm86.S deleted file mode 100644 index 3bb96c992777..000000000000 --- a/tests/tcg/i386/test-i386-vm86.S +++ /dev/null @@ -1,103 +0,0 @@ - .code16 - .globl vm86_code_start - .globl vm86_code_end - -#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100) - -vm86_code_start: - movw $GET_OFFSET(hello_world), %dx - movb $0x09, %ah - int $0x21 - - /* prepare int 0x90 vector */ - xorw %ax, %ax - movw %ax, %es - es movw $GET_OFFSET(int90_test), 0x90 * 4 - es movw %cs, 0x90 * 4 + 2 - - /* launch int 0x90 */ - - int $0x90 - - /* test IF support */ - movw $GET_OFFSET(IF_msg), %dx - movb $0x09, %ah - int $0x21 - - pushf - popw %dx - movb $0xff, %ah - int $0x21 - - cli - pushf - popw %dx - movb $0xff, %ah - int $0x21 - - sti - pushfl - popl %edx - movb $0xff, %ah - int $0x21 - -#if 0 - movw $GET_OFFSET(IF_msg1), %dx - movb $0x09, %ah - int $0x21 - - pushf - movw %sp, %bx - andw $~0x200, (%bx) - popf -#else - cli -#endif - - pushf - popw %dx - movb $0xff, %ah - int $0x21 - - pushfl - movw %sp, %bx - orw $0x200, (%bx) - popfl - - pushfl - popl %edx - movb $0xff, %ah - int $0x21 - - movb $0x00, %ah - int $0x21 - -int90_test: - pushf - pop %dx - movb $0xff, %ah - int $0x21 - - movw %sp, %bx - movw 4(%bx), %dx - movb $0xff, %ah - int $0x21 - - movw $GET_OFFSET(int90_msg), %dx - movb $0x09, %ah - int $0x21 - iret - -int90_msg: - .string "INT90 started\n$" - -hello_world: - .string "Hello VM86 world\n$" - -IF_msg: - .string "VM86 IF test\n$" - -IF_msg1: - .string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$" - -vm86_code_end: diff --git a/tests/tcg/i386/test-i386.c b/tests/tcg/i386/test-i386.c deleted file mode 100644 index 18d5609665eb..000000000000 --- a/tests/tcg/i386/test-i386.c +++ /dev/null @@ -1,2764 +0,0 @@ -/* - * x86 CPU test - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 . - */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(__x86_64__) -//#define TEST_VM86 -#define TEST_SEGS -#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" -#define FMTLX "%016lx" -#define X86_64_ONLY(x) x -#else -#define FMT64X "%016" PRIx64 -#define FMTLX "%08lx" -#define X86_64_ONLY(x) -#endif - -#ifdef TEST_VM86 -#include -#endif - -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s - -#define CC_C 0x0001 -#define CC_P 0x0004 -#define CC_A 0x0010 -#define CC_Z 0x0040 -#define CC_S 0x0080 -#define CC_O 0x0800 - -#define __init_call __attribute__ ((unused,__section__ ("initcall"))) - -#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) - -#if defined(__x86_64__) -static inline long i2l(long v) -{ - return v | ((v ^ 0xabcd) << 32); -} -#else -static inline long i2l(long v) -{ - return v; -} -#endif - -#define OP add -#include "test-i386.h" - -#define OP sub -#include "test-i386.h" - -#define OP xor -#include "test-i386.h" - -#define OP and -#include "test-i386.h" - -#define OP or -#include "test-i386.h" - -#define OP cmp -#include "test-i386.h" - -#define OP adc -#define OP_CC -#include "test-i386.h" - -#define OP sbb -#define OP_CC -#include "test-i386.h" - -#define OP inc -#define OP_CC -#define OP1 -#include "test-i386.h" - -#define OP dec -#define OP_CC -#define OP1 -#include "test-i386.h" - -#define OP neg -#define OP_CC -#define OP1 -#include "test-i386.h" - -#define OP not -#define OP_CC -#define OP1 -#include "test-i386.h" - -#undef CC_MASK -#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) - -#define OP shl -#include "test-i386-shift.h" - -#define OP shr -#include "test-i386-shift.h" - -#define OP sar -#include "test-i386-shift.h" - -#define OP rol -#include "test-i386-shift.h" - -#define OP ror -#include "test-i386-shift.h" - -#define OP rcr -#define OP_CC -#include "test-i386-shift.h" - -#define OP rcl -#define OP_CC -#include "test-i386-shift.h" - -#define OP shld -#define OP_SHIFTD -#define OP_NOBYTE -#include "test-i386-shift.h" - -#define OP shrd -#define OP_SHIFTD -#define OP_NOBYTE -#include "test-i386-shift.h" - -/* XXX: should be more precise ? */ -#undef CC_MASK -#define CC_MASK (CC_C) - -#define OP bt -#define OP_NOBYTE -#include "test-i386-shift.h" - -#define OP bts -#define OP_NOBYTE -#include "test-i386-shift.h" - -#define OP btr -#define OP_NOBYTE -#include "test-i386-shift.h" - -#define OP btc -#define OP_NOBYTE -#include "test-i386-shift.h" - -/* lea test (modrm support) */ -#define TEST_LEAQ(STR)\ -{\ - asm("lea " STR ", %0"\ - : "=r" (res)\ - : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ - printf("lea %s = " FMTLX "\n", STR, res);\ -} - -#define TEST_LEA(STR)\ -{\ - asm("lea " STR ", %0"\ - : "=r" (res)\ - : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ - printf("lea %s = " FMTLX "\n", STR, res);\ -} - -#define TEST_LEA16(STR)\ -{\ - asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\ - : "=r" (res)\ - : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ - printf("lea %s = %08lx\n", STR, res);\ -} - - -void test_lea(void) -{ - long eax, ebx, ecx, edx, esi, edi, res; - eax = i2l(0x0001); - ebx = i2l(0x0002); - ecx = i2l(0x0004); - edx = i2l(0x0008); - esi = i2l(0x0010); - edi = i2l(0x0020); - - TEST_LEA("0x4000"); - - TEST_LEA("(%%eax)"); - TEST_LEA("(%%ebx)"); - TEST_LEA("(%%ecx)"); - TEST_LEA("(%%edx)"); - TEST_LEA("(%%esi)"); - TEST_LEA("(%%edi)"); - - TEST_LEA("0x40(%%eax)"); - TEST_LEA("0x40(%%ebx)"); - TEST_LEA("0x40(%%ecx)"); - TEST_LEA("0x40(%%edx)"); - TEST_LEA("0x40(%%esi)"); - TEST_LEA("0x40(%%edi)"); - - TEST_LEA("0x4000(%%eax)"); - TEST_LEA("0x4000(%%ebx)"); - TEST_LEA("0x4000(%%ecx)"); - TEST_LEA("0x4000(%%edx)"); - TEST_LEA("0x4000(%%esi)"); - TEST_LEA("0x4000(%%edi)"); - - TEST_LEA("(%%eax, %%ecx)"); - TEST_LEA("(%%ebx, %%edx)"); - TEST_LEA("(%%ecx, %%ecx)"); - TEST_LEA("(%%edx, %%ecx)"); - TEST_LEA("(%%esi, %%ecx)"); - TEST_LEA("(%%edi, %%ecx)"); - - TEST_LEA("0x40(%%eax, %%ecx)"); - TEST_LEA("0x4000(%%ebx, %%edx)"); - - TEST_LEA("(%%ecx, %%ecx, 2)"); - TEST_LEA("(%%edx, %%ecx, 4)"); - TEST_LEA("(%%esi, %%ecx, 8)"); - - TEST_LEA("(,%%eax, 2)"); - TEST_LEA("(,%%ebx, 4)"); - TEST_LEA("(,%%ecx, 8)"); - - TEST_LEA("0x40(,%%eax, 2)"); - TEST_LEA("0x40(,%%ebx, 4)"); - TEST_LEA("0x40(,%%ecx, 8)"); - - - TEST_LEA("-10(%%ecx, %%ecx, 2)"); - TEST_LEA("-10(%%edx, %%ecx, 4)"); - TEST_LEA("-10(%%esi, %%ecx, 8)"); - - TEST_LEA("0x4000(%%ecx, %%ecx, 2)"); - TEST_LEA("0x4000(%%edx, %%ecx, 4)"); - TEST_LEA("0x4000(%%esi, %%ecx, 8)"); - -#if defined(__x86_64__) - TEST_LEAQ("0x4000"); - TEST_LEAQ("0x4000(%%rip)"); - - TEST_LEAQ("(%%rax)"); - TEST_LEAQ("(%%rbx)"); - TEST_LEAQ("(%%rcx)"); - TEST_LEAQ("(%%rdx)"); - TEST_LEAQ("(%%rsi)"); - TEST_LEAQ("(%%rdi)"); - - TEST_LEAQ("0x40(%%rax)"); - TEST_LEAQ("0x40(%%rbx)"); - TEST_LEAQ("0x40(%%rcx)"); - TEST_LEAQ("0x40(%%rdx)"); - TEST_LEAQ("0x40(%%rsi)"); - TEST_LEAQ("0x40(%%rdi)"); - - TEST_LEAQ("0x4000(%%rax)"); - TEST_LEAQ("0x4000(%%rbx)"); - TEST_LEAQ("0x4000(%%rcx)"); - TEST_LEAQ("0x4000(%%rdx)"); - TEST_LEAQ("0x4000(%%rsi)"); - TEST_LEAQ("0x4000(%%rdi)"); - - TEST_LEAQ("(%%rax, %%rcx)"); - TEST_LEAQ("(%%rbx, %%rdx)"); - TEST_LEAQ("(%%rcx, %%rcx)"); - TEST_LEAQ("(%%rdx, %%rcx)"); - TEST_LEAQ("(%%rsi, %%rcx)"); - TEST_LEAQ("(%%rdi, %%rcx)"); - - TEST_LEAQ("0x40(%%rax, %%rcx)"); - TEST_LEAQ("0x4000(%%rbx, %%rdx)"); - - TEST_LEAQ("(%%rcx, %%rcx, 2)"); - TEST_LEAQ("(%%rdx, %%rcx, 4)"); - TEST_LEAQ("(%%rsi, %%rcx, 8)"); - - TEST_LEAQ("(,%%rax, 2)"); - TEST_LEAQ("(,%%rbx, 4)"); - TEST_LEAQ("(,%%rcx, 8)"); - - TEST_LEAQ("0x40(,%%rax, 2)"); - TEST_LEAQ("0x40(,%%rbx, 4)"); - TEST_LEAQ("0x40(,%%rcx, 8)"); - - - TEST_LEAQ("-10(%%rcx, %%rcx, 2)"); - TEST_LEAQ("-10(%%rdx, %%rcx, 4)"); - TEST_LEAQ("-10(%%rsi, %%rcx, 8)"); - - TEST_LEAQ("0x4000(%%rcx, %%rcx, 2)"); - TEST_LEAQ("0x4000(%%rdx, %%rcx, 4)"); - TEST_LEAQ("0x4000(%%rsi, %%rcx, 8)"); -#else - /* limited 16 bit addressing test */ - TEST_LEA16("0x4000"); - TEST_LEA16("(%%bx)"); - TEST_LEA16("(%%si)"); - TEST_LEA16("(%%di)"); - TEST_LEA16("0x40(%%bx)"); - TEST_LEA16("0x40(%%si)"); - TEST_LEA16("0x40(%%di)"); - TEST_LEA16("0x4000(%%bx)"); - TEST_LEA16("0x4000(%%si)"); - TEST_LEA16("(%%bx,%%si)"); - TEST_LEA16("(%%bx,%%di)"); - TEST_LEA16("0x40(%%bx,%%si)"); - TEST_LEA16("0x40(%%bx,%%di)"); - TEST_LEA16("0x4000(%%bx,%%si)"); - TEST_LEA16("0x4000(%%bx,%%di)"); -#endif -} - -#define TEST_JCC(JCC, v1, v2)\ -{\ - int res;\ - asm("movl $1, %0\n\t"\ - "cmpl %2, %1\n\t"\ - "j" JCC " 1f\n\t"\ - "movl $0, %0\n\t"\ - "1:\n\t"\ - : "=r" (res)\ - : "r" (v1), "r" (v2));\ - printf("%-10s %d\n", "j" JCC, res);\ -\ - asm("movl $0, %0\n\t"\ - "cmpl %2, %1\n\t"\ - "set" JCC " %b0\n\t"\ - : "=r" (res)\ - : "r" (v1), "r" (v2));\ - printf("%-10s %d\n", "set" JCC, res);\ - if (TEST_CMOV) {\ - long val = i2l(1);\ - long res = i2l(0x12345678);\ -X86_64_ONLY(\ - asm("cmpl %2, %1\n\t"\ - "cmov" JCC "q %3, %0\n\t"\ - : "=r" (res)\ - : "r" (v1), "r" (v2), "m" (val), "0" (res));\ - printf("%-10s R=" FMTLX "\n", "cmov" JCC "q", res);)\ - asm("cmpl %2, %1\n\t"\ - "cmov" JCC "l %k3, %k0\n\t"\ - : "=r" (res)\ - : "r" (v1), "r" (v2), "m" (val), "0" (res));\ - printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);\ - asm("cmpl %2, %1\n\t"\ - "cmov" JCC "w %w3, %w0\n\t"\ - : "=r" (res)\ - : "r" (v1), "r" (v2), "r" (1), "0" (res));\ - printf("%-10s R=" FMTLX "\n", "cmov" JCC "w", res);\ - } \ -} - -/* various jump tests */ -void test_jcc(void) -{ - TEST_JCC("ne", 1, 1); - TEST_JCC("ne", 1, 0); - - TEST_JCC("e", 1, 1); - TEST_JCC("e", 1, 0); - - TEST_JCC("l", 1, 1); - TEST_JCC("l", 1, 0); - TEST_JCC("l", 1, -1); - - TEST_JCC("le", 1, 1); - TEST_JCC("le", 1, 0); - TEST_JCC("le", 1, -1); - - TEST_JCC("ge", 1, 1); - TEST_JCC("ge", 1, 0); - TEST_JCC("ge", -1, 1); - - TEST_JCC("g", 1, 1); - TEST_JCC("g", 1, 0); - TEST_JCC("g", 1, -1); - - TEST_JCC("b", 1, 1); - TEST_JCC("b", 1, 0); - TEST_JCC("b", 1, -1); - - TEST_JCC("be", 1, 1); - TEST_JCC("be", 1, 0); - TEST_JCC("be", 1, -1); - - TEST_JCC("ae", 1, 1); - TEST_JCC("ae", 1, 0); - TEST_JCC("ae", 1, -1); - - TEST_JCC("a", 1, 1); - TEST_JCC("a", 1, 0); - TEST_JCC("a", 1, -1); - - - TEST_JCC("p", 1, 1); - TEST_JCC("p", 1, 0); - - TEST_JCC("np", 1, 1); - TEST_JCC("np", 1, 0); - - TEST_JCC("o", 0x7fffffff, 0); - TEST_JCC("o", 0x7fffffff, -1); - - TEST_JCC("no", 0x7fffffff, 0); - TEST_JCC("no", 0x7fffffff, -1); - - TEST_JCC("s", 0, 1); - TEST_JCC("s", 0, -1); - TEST_JCC("s", 0, 0); - - TEST_JCC("ns", 0, 1); - TEST_JCC("ns", 0, -1); - TEST_JCC("ns", 0, 0); -} - -#define TEST_LOOP(insn) \ -{\ - for(i = 0; i < sizeof(ecx_vals) / sizeof(long); i++) {\ - ecx = ecx_vals[i];\ - for(zf = 0; zf < 2; zf++) {\ - asm("test %2, %2\n\t"\ - "movl $1, %0\n\t"\ - insn " 1f\n\t" \ - "movl $0, %0\n\t"\ - "1:\n\t"\ - : "=a" (res)\ - : "c" (ecx), "b" (!zf)); \ - printf("%-10s ECX=" FMTLX " ZF=%ld r=%d\n", insn, ecx, zf, res); \ - }\ - }\ -} - -void test_loop(void) -{ - long ecx, zf; - const long ecx_vals[] = { - 0, - 1, - 0x10000, - 0x10001, -#if defined(__x86_64__) - 0x100000000L, - 0x100000001L, -#endif - }; - int i, res; - -#if !defined(__x86_64__) - TEST_LOOP("jcxz"); - TEST_LOOP("loopw"); - TEST_LOOP("loopzw"); - TEST_LOOP("loopnzw"); -#endif - - TEST_LOOP("jecxz"); - TEST_LOOP("loopl"); - TEST_LOOP("loopzl"); - TEST_LOOP("loopnzl"); -} - -#undef CC_MASK -#ifdef TEST_P4_FLAGS -#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) -#else -#define CC_MASK (CC_O | CC_C) -#endif - -#define OP mul -#include "test-i386-muldiv.h" - -#define OP imul -#include "test-i386-muldiv.h" - -void test_imulw2(long op0, long op1) -{ - long res, s1, s0, flags; - s0 = op0; - s1 = op1; - res = s0; - flags = 0; - asm volatile ("push %4\n\t" - "popf\n\t" - "imulw %w2, %w0\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=q" (res), "=g" (flags) - : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", - "imulw", s0, s1, res, flags & CC_MASK); -} - -void test_imull2(long op0, long op1) -{ - long res, s1, s0, flags; - s0 = op0; - s1 = op1; - res = s0; - flags = 0; - asm volatile ("push %4\n\t" - "popf\n\t" - "imull %k2, %k0\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=q" (res), "=g" (flags) - : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", - "imull", s0, s1, res, flags & CC_MASK); -} - -#if defined(__x86_64__) -void test_imulq2(long op0, long op1) -{ - long res, s1, s0, flags; - s0 = op0; - s1 = op1; - res = s0; - flags = 0; - asm volatile ("push %4\n\t" - "popf\n\t" - "imulq %2, %0\n\t" - "pushf\n\t" - "pop %1\n\t" - : "=q" (res), "=g" (flags) - : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", - "imulq", s0, s1, res, flags & CC_MASK); -} -#endif - -#define TEST_IMUL_IM(size, rsize, op0, op1)\ -{\ - long res, flags, s1;\ - flags = 0;\ - res = 0;\ - s1 = op1;\ - asm volatile ("push %3\n\t"\ - "popf\n\t"\ - "imul" size " $" #op0 ", %" rsize "2, %" rsize "0\n\t" \ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=r" (res), "=g" (flags)\ - : "r" (s1), "1" (flags), "0" (res));\ - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",\ - "imul" size " im", (long)op0, (long)op1, res, flags & CC_MASK);\ -} - - -#undef CC_MASK -#define CC_MASK (0) - -#define OP div -#include "test-i386-muldiv.h" - -#define OP idiv -#include "test-i386-muldiv.h" - -void test_mul(void) -{ - test_imulb(0x1234561d, 4); - test_imulb(3, -4); - test_imulb(0x80, 0x80); - test_imulb(0x10, 0x10); - - test_imulw(0, 0x1234001d, 45); - test_imulw(0, 23, -45); - test_imulw(0, 0x8000, 0x8000); - test_imulw(0, 0x100, 0x100); - - test_imull(0, 0x1234001d, 45); - test_imull(0, 23, -45); - test_imull(0, 0x80000000, 0x80000000); - test_imull(0, 0x10000, 0x10000); - - test_mulb(0x1234561d, 4); - test_mulb(3, -4); - test_mulb(0x80, 0x80); - test_mulb(0x10, 0x10); - - test_mulw(0, 0x1234001d, 45); - test_mulw(0, 23, -45); - test_mulw(0, 0x8000, 0x8000); - test_mulw(0, 0x100, 0x100); - - test_mull(0, 0x1234001d, 45); - test_mull(0, 23, -45); - test_mull(0, 0x80000000, 0x80000000); - test_mull(0, 0x10000, 0x10000); - - test_imulw2(0x1234001d, 45); - test_imulw2(23, -45); - test_imulw2(0x8000, 0x8000); - test_imulw2(0x100, 0x100); - - test_imull2(0x1234001d, 45); - test_imull2(23, -45); - test_imull2(0x80000000, 0x80000000); - test_imull2(0x10000, 0x10000); - - TEST_IMUL_IM("w", "w", 45, 0x1234); - TEST_IMUL_IM("w", "w", -45, 23); - TEST_IMUL_IM("w", "w", 0x8000, 0x80000000); - TEST_IMUL_IM("w", "w", 0x7fff, 0x1000); - - TEST_IMUL_IM("l", "k", 45, 0x1234); - TEST_IMUL_IM("l", "k", -45, 23); - TEST_IMUL_IM("l", "k", 0x8000, 0x80000000); - TEST_IMUL_IM("l", "k", 0x7fff, 0x1000); - - test_idivb(0x12341678, 0x127e); - test_idivb(0x43210123, -5); - test_idivb(0x12340004, -1); - - test_idivw(0, 0x12345678, 12347); - test_idivw(0, -23223, -45); - test_idivw(0, 0x12348000, -1); - test_idivw(0x12343, 0x12345678, 0x81238567); - - test_idivl(0, 0x12345678, 12347); - test_idivl(0, -233223, -45); - test_idivl(0, 0x80000000, -1); - test_idivl(0x12343, 0x12345678, 0x81234567); - - test_divb(0x12341678, 0x127e); - test_divb(0x43210123, -5); - test_divb(0x12340004, -1); - - test_divw(0, 0x12345678, 12347); - test_divw(0, -23223, -45); - test_divw(0, 0x12348000, -1); - test_divw(0x12343, 0x12345678, 0x81238567); - - test_divl(0, 0x12345678, 12347); - test_divl(0, -233223, -45); - test_divl(0, 0x80000000, -1); - test_divl(0x12343, 0x12345678, 0x81234567); - -#if defined(__x86_64__) - test_imulq(0, 0x1234001d1234001d, 45); - test_imulq(0, 23, -45); - test_imulq(0, 0x8000000000000000, 0x8000000000000000); - test_imulq(0, 0x100000000, 0x100000000); - - test_mulq(0, 0x1234001d1234001d, 45); - test_mulq(0, 23, -45); - test_mulq(0, 0x8000000000000000, 0x8000000000000000); - test_mulq(0, 0x100000000, 0x100000000); - - test_imulq2(0x1234001d1234001d, 45); - test_imulq2(23, -45); - test_imulq2(0x8000000000000000, 0x8000000000000000); - test_imulq2(0x100000000, 0x100000000); - - TEST_IMUL_IM("q", "", 45, 0x12341234); - TEST_IMUL_IM("q", "", -45, 23); - TEST_IMUL_IM("q", "", 0x8000, 0x8000000000000000); - TEST_IMUL_IM("q", "", 0x7fff, 0x10000000); - - test_idivq(0, 0x12345678abcdef, 12347); - test_idivq(0, -233223, -45); - test_idivq(0, 0x8000000000000000, -1); - test_idivq(0x12343, 0x12345678, 0x81234567); - - test_divq(0, 0x12345678abcdef, 12347); - test_divq(0, -233223, -45); - test_divq(0, 0x8000000000000000, -1); - test_divq(0x12343, 0x12345678, 0x81234567); -#endif -} - -#define TEST_BSX(op, size, op0)\ -{\ - long res, val, resz;\ - val = op0;\ - asm("xor %1, %1\n"\ - "mov $0x12345678, %0\n"\ - #op " %" size "2, %" size "0 ; setz %b1" \ - : "=&r" (res), "=&q" (resz)\ - : "r" (val));\ - printf("%-10s A=" FMTLX " R=" FMTLX " %ld\n", #op, val, res, resz);\ -} - -void test_bsx(void) -{ - TEST_BSX(bsrw, "w", 0); - TEST_BSX(bsrw, "w", 0x12340128); - TEST_BSX(bsfw, "w", 0); - TEST_BSX(bsfw, "w", 0x12340128); - TEST_BSX(bsrl, "k", 0); - TEST_BSX(bsrl, "k", 0x00340128); - TEST_BSX(bsfl, "k", 0); - TEST_BSX(bsfl, "k", 0x00340128); -#if defined(__x86_64__) - TEST_BSX(bsrq, "", 0); - TEST_BSX(bsrq, "", 0x003401281234); - TEST_BSX(bsfq, "", 0); - TEST_BSX(bsfq, "", 0x003401281234); -#endif -} - -/**********************************************/ - -union float64u { - double d; - uint64_t l; -}; - -union float64u q_nan = { .l = 0xFFF8000000000000LL }; -union float64u s_nan = { .l = 0xFFF0000000000000LL }; - -void test_fops(double a, double b) -{ - printf("a=%f b=%f a+b=%f\n", a, b, a + b); - printf("a=%f b=%f a-b=%f\n", a, b, a - b); - printf("a=%f b=%f a*b=%f\n", a, b, a * b); - printf("a=%f b=%f a/b=%f\n", a, b, a / b); - printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b)); - printf("a=%f sqrt(a)=%f\n", a, sqrt(a)); - printf("a=%f sin(a)=%f\n", a, sin(a)); - printf("a=%f cos(a)=%f\n", a, cos(a)); - printf("a=%f tan(a)=%f\n", a, tan(a)); - printf("a=%f log(a)=%f\n", a, log(a)); - printf("a=%f exp(a)=%f\n", a, exp(a)); - printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b)); - /* just to test some op combining */ - printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a))); - printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a))); - printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a))); - -} - -void fpu_clear_exceptions(void) -{ - struct QEMU_PACKED { - uint16_t fpuc; - uint16_t dummy1; - uint16_t fpus; - uint16_t dummy2; - uint16_t fptag; - uint16_t dummy3; - uint32_t ignored[4]; - long double fpregs[8]; - } float_env32; - - asm volatile ("fnstenv %0\n" : "=m" (float_env32)); - float_env32.fpus &= ~0x7f; - asm volatile ("fldenv %0\n" : : "m" (float_env32)); -} - -/* XXX: display exception bits when supported */ -#define FPUS_EMASK 0x0000 -//#define FPUS_EMASK 0x007f - -void test_fcmp(double a, double b) -{ - long eflags, fpus; - - fpu_clear_exceptions(); - asm("fcom %2\n" - "fstsw %%ax\n" - : "=a" (fpus) - : "t" (a), "u" (b)); - printf("fcom(%f %f)=%04lx\n", - a, b, fpus & (0x4500 | FPUS_EMASK)); - fpu_clear_exceptions(); - asm("fucom %2\n" - "fstsw %%ax\n" - : "=a" (fpus) - : "t" (a), "u" (b)); - printf("fucom(%f %f)=%04lx\n", - a, b, fpus & (0x4500 | FPUS_EMASK)); - if (TEST_FCOMI) { - /* test f(u)comi instruction */ - fpu_clear_exceptions(); - asm("fcomi %3, %2\n" - "fstsw %%ax\n" - "pushf\n" - "pop %0\n" - : "=r" (eflags), "=a" (fpus) - : "t" (a), "u" (b)); - printf("fcomi(%f %f)=%04lx %02lx\n", - a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); - fpu_clear_exceptions(); - asm("fucomi %3, %2\n" - "fstsw %%ax\n" - "pushf\n" - "pop %0\n" - : "=r" (eflags), "=a" (fpus) - : "t" (a), "u" (b)); - printf("fucomi(%f %f)=%04lx %02lx\n", - a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); - } - fpu_clear_exceptions(); - asm volatile("fxam\n" - "fstsw %%ax\n" - : "=a" (fpus) - : "t" (a)); - printf("fxam(%f)=%04lx\n", a, fpus & 0x4700); - fpu_clear_exceptions(); -} - -void test_fcvt(double a) -{ - float fa; - long double la; - int16_t fpuc; - int i; - int64_t lla; - int ia; - int16_t wa; - double ra; - - fa = a; - la = a; - printf("(float)%f = %f\n", a, fa); - printf("(long double)%f = %Lf\n", a, la); - printf("a=" FMT64X "\n", *(uint64_t *)&a); - printf("la=" FMT64X " %04x\n", *(uint64_t *)&la, - *(unsigned short *)((char *)(&la) + 8)); - - /* test all roundings */ - asm volatile ("fstcw %0" : "=m" (fpuc)); - for(i=0;i<4;i++) { - uint16_t val16; - val16 = (fpuc & ~0x0c00) | (i << 10); - asm volatile ("fldcw %0" : : "m" (val16)); - asm volatile ("fist %0" : "=m" (wa) : "t" (a)); - asm volatile ("fistl %0" : "=m" (ia) : "t" (a)); - asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st"); - asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a)); - asm volatile ("fldcw %0" : : "m" (fpuc)); - printf("(short)a = %d\n", wa); - printf("(int)a = %d\n", ia); - printf("(int64_t)a = " FMT64X "\n", lla); - printf("rint(a) = %f\n", ra); - } -} - -#define TEST(N) \ - asm("fld" #N : "=t" (a)); \ - printf("fld" #N "= %f\n", a); - -void test_fconst(void) -{ - double a; - TEST(1); - TEST(l2t); - TEST(l2e); - TEST(pi); - TEST(lg2); - TEST(ln2); - TEST(z); -} - -void test_fbcd(double a) -{ - unsigned short bcd[5]; - double b; - - asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); - asm("fbld %1" : "=t" (b) : "m" (bcd[0])); - printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", - a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); -} - -#define TEST_ENV(env, save, restore)\ -{\ - memset((env), 0xaa, sizeof(*(env)));\ - for(i=0;i<5;i++)\ - asm volatile ("fldl %0" : : "m" (dtab[i]));\ - asm volatile (save " %0\n" : : "m" (*(env)));\ - asm volatile (restore " %0\n": : "m" (*(env)));\ - for(i=0;i<5;i++)\ - asm volatile ("fstpl %0" : "=m" (rtab[i]));\ - for(i=0;i<5;i++)\ - printf("res[%d]=%f\n", i, rtab[i]);\ - printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ - (env)->fpuc,\ - (env)->fpus & 0xff00,\ - (env)->fptag);\ -} - -void test_fenv(void) -{ - struct __attribute__((__packed__)) { - uint16_t fpuc; - uint16_t dummy1; - uint16_t fpus; - uint16_t dummy2; - uint16_t fptag; - uint16_t dummy3; - uint32_t ignored[4]; - long double fpregs[8]; - } float_env32; - struct __attribute__((__packed__)) { - uint16_t fpuc; - uint16_t fpus; - uint16_t fptag; - uint16_t ignored[4]; - long double fpregs[8]; - } float_env16; - double dtab[8]; - double rtab[8]; - int i; - - for(i=0;i<8;i++) - dtab[i] = i + 1; - - TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv"); - TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor"); - TEST_ENV(&float_env32, "fnstenv", "fldenv"); - TEST_ENV(&float_env32, "fnsave", "frstor"); - - /* test for ffree */ - for(i=0;i<5;i++) - asm volatile ("fldl %0" : : "m" (dtab[i])); - asm volatile("ffree %st(2)"); - asm volatile ("fnstenv %0\n" : : "m" (float_env32)); - asm volatile ("fninit"); - printf("fptag=%04x\n", float_env32.fptag); -} - - -#define TEST_FCMOV(a, b, eflags, CC)\ -{\ - double res;\ - asm("push %3\n"\ - "popf\n"\ - "fcmov" CC " %2, %0\n"\ - : "=t" (res)\ - : "0" (a), "u" (b), "g" (eflags));\ - printf("fcmov%s eflags=0x%04lx-> %f\n", \ - CC, (long)eflags, res);\ -} - -void test_fcmov(void) -{ - double a, b; - long eflags, i; - - a = 1.0; - b = 2.0; - for(i = 0; i < 4; i++) { - eflags = 0; - if (i & 1) - eflags |= CC_C; - if (i & 2) - eflags |= CC_Z; - TEST_FCMOV(a, b, eflags, "b"); - TEST_FCMOV(a, b, eflags, "e"); - TEST_FCMOV(a, b, eflags, "be"); - TEST_FCMOV(a, b, eflags, "nb"); - TEST_FCMOV(a, b, eflags, "ne"); - TEST_FCMOV(a, b, eflags, "nbe"); - } - TEST_FCMOV(a, b, 0, "u"); - TEST_FCMOV(a, b, CC_P, "u"); - TEST_FCMOV(a, b, 0, "nu"); - TEST_FCMOV(a, b, CC_P, "nu"); -} - -void test_floats(void) -{ - test_fops(2, 3); - test_fops(1.4, -5); - test_fcmp(2, -1); - test_fcmp(2, 2); - test_fcmp(2, 3); - test_fcmp(2, q_nan.d); - test_fcmp(q_nan.d, -1); - test_fcmp(-1.0/0.0, -1); - test_fcmp(1.0/0.0, -1); - test_fcvt(0.5); - test_fcvt(-0.5); - test_fcvt(1.0/7.0); - test_fcvt(-1.0/9.0); - test_fcvt(32768); - test_fcvt(-1e20); - test_fcvt(-1.0/0.0); - test_fcvt(1.0/0.0); - test_fcvt(q_nan.d); - test_fconst(); - test_fbcd(1234567890123456.0); - test_fbcd(-123451234567890.0); - test_fenv(); - if (TEST_CMOV) { - test_fcmov(); - } -} - -/**********************************************/ -#if !defined(__x86_64__) - -#define TEST_BCD(op, op0, cc_in, cc_mask)\ -{\ - int res, flags;\ - res = op0;\ - flags = cc_in;\ - asm ("push %3\n\t"\ - "popf\n\t"\ - #op "\n\t"\ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=a" (res), "=g" (flags)\ - : "0" (res), "1" (flags));\ - printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\ - #op, op0, res, cc_in, flags & cc_mask);\ -} - -void test_bcd(void) -{ - TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - - TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); - - TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A)); - TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A)); - TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A)); - TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A)); - TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A)); - TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A)); - TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A)); - TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A)); - - TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A)); - TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A)); - TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A)); - TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A)); - TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A)); - TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A)); - TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A)); - TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A)); - - TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); - TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); -} -#endif - -#define TEST_XCHG(op, size, opconst)\ -{\ - long op0, op1;\ - op0 = i2l(0x12345678);\ - op1 = i2l(0xfbca7654);\ - asm(#op " %" size "0, %" size "1" \ - : "=q" (op0), opconst (op1) \ - : "0" (op0));\ - printf("%-10s A=" FMTLX " B=" FMTLX "\n",\ - #op, op0, op1);\ -} - -#define TEST_CMPXCHG(op, size, opconst, eax)\ -{\ - long op0, op1, op2;\ - op0 = i2l(0x12345678);\ - op1 = i2l(0xfbca7654);\ - op2 = i2l(eax);\ - asm(#op " %" size "0, %" size "1" \ - : "=q" (op0), opconst (op1) \ - : "0" (op0), "a" (op2));\ - printf("%-10s EAX=" FMTLX " A=" FMTLX " C=" FMTLX "\n",\ - #op, op2, op0, op1);\ -} - -void test_xchg(void) -{ -#if defined(__x86_64__) - TEST_XCHG(xchgq, "", "+q"); -#endif - TEST_XCHG(xchgl, "k", "+q"); - TEST_XCHG(xchgw, "w", "+q"); - TEST_XCHG(xchgb, "b", "+q"); - -#if defined(__x86_64__) - TEST_XCHG(xchgq, "", "+m"); -#endif - TEST_XCHG(xchgl, "k", "+m"); - TEST_XCHG(xchgw, "w", "+m"); - TEST_XCHG(xchgb, "b", "+m"); - -#if defined(__x86_64__) - TEST_XCHG(xaddq, "", "+q"); -#endif - TEST_XCHG(xaddl, "k", "+q"); - TEST_XCHG(xaddw, "w", "+q"); - TEST_XCHG(xaddb, "b", "+q"); - - { - int res; - res = 0x12345678; - asm("xaddl %1, %0" : "=r" (res) : "0" (res)); - printf("xaddl same res=%08x\n", res); - } - -#if defined(__x86_64__) - TEST_XCHG(xaddq, "", "+m"); -#endif - TEST_XCHG(xaddl, "k", "+m"); - TEST_XCHG(xaddw, "w", "+m"); - TEST_XCHG(xaddb, "b", "+m"); - -#if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfbca7654); -#endif - TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfbca7654); - -#if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfffefdfc); -#endif - TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfffefdfc); - -#if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfbca7654); -#endif - TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfbca7654); - -#if defined(__x86_64__) - TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfffefdfc); -#endif - TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfffefdfc); - - { - uint64_t op0, op1, op2; - long eax, edx; - long i, eflags; - - for(i = 0; i < 2; i++) { - op0 = 0x123456789abcdLL; - eax = i2l(op0 & 0xffffffff); - edx = i2l(op0 >> 32); - if (i == 0) - op1 = 0xfbca765423456LL; - else - op1 = op0; - op2 = 0x6532432432434LL; - asm("cmpxchg8b %2\n" - "pushf\n" - "pop %3\n" - : "=a" (eax), "=d" (edx), "=m" (op1), "=g" (eflags) - : "0" (eax), "1" (edx), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); - printf("cmpxchg8b: eax=" FMTLX " edx=" FMTLX " op1=" FMT64X " CC=%02lx\n", - eax, edx, op1, eflags & CC_Z); - } - } -} - -#ifdef TEST_SEGS -/**********************************************/ -/* segmentation tests */ - -#include -#include -#include -#include - -static inline int modify_ldt(int func, void * ptr, unsigned long bytecount) -{ - return syscall(__NR_modify_ldt, func, ptr, bytecount); -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) -#define modify_ldt_ldt_s user_desc -#endif - -#define MK_SEL(n) (((n) << 3) | 7) - -uint8_t seg_data1[4096]; -uint8_t seg_data2[4096]; - -#define TEST_LR(op, size, seg, mask)\ -{\ - int res, res2;\ - uint16_t mseg = seg;\ - res = 0x12345678;\ - asm (op " %" size "2, %" size "0\n" \ - "movl $0, %1\n"\ - "jnz 1f\n"\ - "movl $1, %1\n"\ - "1:\n"\ - : "=r" (res), "=r" (res2) : "m" (mseg), "0" (res));\ - printf(op ": Z=%d %08x\n", res2, res & ~(mask));\ -} - -#define TEST_ARPL(op, size, op1, op2)\ -{\ - long a, b, c; \ - a = (op1); \ - b = (op2); \ - asm volatile(op " %" size "3, %" size "0\n"\ - "movl $0,%1\n"\ - "jnz 1f\n"\ - "movl $1,%1\n"\ - "1:\n"\ - : "=r" (a), "=r" (c) : "0" (a), "r" (b)); \ - printf(op size " A=" FMTLX " B=" FMTLX " R=" FMTLX " z=%ld\n",\ - (long)(op1), (long)(op2), a, c);\ -} - -/* NOTE: we use Linux modify_ldt syscall */ -void test_segs(void) -{ - struct modify_ldt_ldt_s ldt; - long long ldt_table[3]; - int res, res2; - char tmp; - struct { - uint32_t offset; - uint16_t seg; - } __attribute__((__packed__)) segoff; - - ldt.entry_number = 1; - ldt.base_addr = (unsigned long)&seg_data1; - ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; - ldt.seg_32bit = 1; - ldt.contents = MODIFY_LDT_CONTENTS_DATA; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 1; - ldt.seg_not_present = 0; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - ldt.entry_number = 2; - ldt.base_addr = (unsigned long)&seg_data2; - ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12; - ldt.seg_32bit = 1; - ldt.contents = MODIFY_LDT_CONTENTS_DATA; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 1; - ldt.seg_not_present = 0; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */ -#if 0 - { - int i; - for(i=0;i<3;i++) - printf("%d: %016Lx\n", i, ldt_table[i]); - } -#endif - /* do some tests with fs or gs */ - asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); - - seg_data1[1] = 0xaa; - seg_data2[1] = 0x55; - - asm volatile ("fs movzbl 0x1, %0" : "=r" (res)); - printf("FS[1] = %02x\n", res); - - asm volatile ("pushl %%gs\n" - "movl %1, %%gs\n" - "gs movzbl 0x1, %0\n" - "popl %%gs\n" - : "=r" (res) - : "r" (MK_SEL(2))); - printf("GS[1] = %02x\n", res); - - /* tests with ds/ss (implicit segment case) */ - tmp = 0xa5; - asm volatile ("pushl %%ebp\n\t" - "pushl %%ds\n\t" - "movl %2, %%ds\n\t" - "movl %3, %%ebp\n\t" - "movzbl 0x1, %0\n\t" - "movzbl (%%ebp), %1\n\t" - "popl %%ds\n\t" - "popl %%ebp\n\t" - : "=r" (res), "=r" (res2) - : "r" (MK_SEL(1)), "r" (&tmp)); - printf("DS[1] = %02x\n", res); - printf("SS[tmp] = %02x\n", res2); - - segoff.seg = MK_SEL(2); - segoff.offset = 0xabcdef12; - asm volatile("lfs %2, %0\n\t" - "movl %%fs, %1\n\t" - : "=r" (res), "=g" (res2) - : "m" (segoff)); - printf("FS:reg = %04x:%08x\n", res2, res); - - TEST_LR("larw", "w", MK_SEL(2), 0x0100); - TEST_LR("larl", "", MK_SEL(2), 0x0100); - TEST_LR("lslw", "w", MK_SEL(2), 0); - TEST_LR("lsll", "", MK_SEL(2), 0); - - TEST_LR("larw", "w", 0xfff8, 0); - TEST_LR("larl", "", 0xfff8, 0); - TEST_LR("lslw", "w", 0xfff8, 0); - TEST_LR("lsll", "", 0xfff8, 0); - - TEST_ARPL("arpl", "w", 0x12345678 | 3, 0x762123c | 1); - TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 3); - TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 1); -} - -/* 16 bit code test */ -extern char code16_start, code16_end; -extern char code16_func1; -extern char code16_func2; -extern char code16_func3; - -void test_code16(void) -{ - struct modify_ldt_ldt_s ldt; - int res, res2; - - /* build a code segment */ - ldt.entry_number = 1; - ldt.base_addr = (unsigned long)&code16_start; - ldt.limit = &code16_end - &code16_start; - ldt.seg_32bit = 0; - ldt.contents = MODIFY_LDT_CONTENTS_CODE; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 0; - ldt.seg_not_present = 0; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - /* call the first function */ - asm volatile ("lcall %1, %2" - : "=a" (res) - : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc"); - printf("func1() = 0x%08x\n", res); - asm volatile ("lcall %2, %3" - : "=a" (res), "=c" (res2) - : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc"); - printf("func2() = 0x%08x spdec=%d\n", res, res2); - asm volatile ("lcall %1, %2" - : "=a" (res) - : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc"); - printf("func3() = 0x%08x\n", res); -} -#endif - -#if defined(__x86_64__) -asm(".globl func_lret\n" - "func_lret:\n" - "movl $0x87654641, %eax\n" - "lretq\n"); -#else -asm(".globl func_lret\n" - "func_lret:\n" - "movl $0x87654321, %eax\n" - "lret\n" - - ".globl func_iret\n" - "func_iret:\n" - "movl $0xabcd4321, %eax\n" - "iret\n"); -#endif - -extern char func_lret; -extern char func_iret; - -void test_misc(void) -{ - char table[256]; - long res, i; - - for(i=0;i<256;i++) table[i] = 256 - i; - res = 0x12345678; - asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); - printf("xlat: EAX=" FMTLX "\n", res); - -#if defined(__x86_64__) -#if 0 - { - /* XXX: see if Intel Core2 and AMD64 behavior really - differ. Here we implemented the Intel way which is not - compatible yet with QEMU. */ - static struct QEMU_PACKED { - uint64_t offset; - uint16_t seg; - } desc; - long cs_sel; - - asm volatile ("mov %%cs, %0" : "=r" (cs_sel)); - - asm volatile ("push %1\n" - "call func_lret\n" - : "=a" (res) - : "r" (cs_sel) : "memory", "cc"); - printf("func_lret=" FMTLX "\n", res); - - desc.offset = (long)&func_lret; - desc.seg = cs_sel; - - asm volatile ("xor %%rax, %%rax\n" - "rex64 lcall *(%%rcx)\n" - : "=a" (res) - : "c" (&desc) - : "memory", "cc"); - printf("func_lret2=" FMTLX "\n", res); - - asm volatile ("push %2\n" - "mov $ 1f, %%rax\n" - "push %%rax\n" - "rex64 ljmp *(%%rcx)\n" - "1:\n" - : "=a" (res) - : "c" (&desc), "b" (cs_sel) - : "memory", "cc"); - printf("func_lret3=" FMTLX "\n", res); - } -#endif -#else - asm volatile ("push %%cs ; call %1" - : "=a" (res) - : "m" (func_lret): "memory", "cc"); - printf("func_lret=" FMTLX "\n", res); - - asm volatile ("pushf ; push %%cs ; call %1" - : "=a" (res) - : "m" (func_iret): "memory", "cc"); - printf("func_iret=" FMTLX "\n", res); -#endif - -#if defined(__x86_64__) - /* specific popl test */ - asm volatile ("push $12345432 ; push $0x9abcdef ; pop (%%rsp) ; pop %0" - : "=g" (res)); - printf("popl esp=" FMTLX "\n", res); -#else - /* specific popl test */ - asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0" - : "=g" (res)); - printf("popl esp=" FMTLX "\n", res); - - /* specific popw test */ - asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0" - : "=g" (res)); - printf("popw esp=" FMTLX "\n", res); -#endif -} - -uint8_t str_buffer[4096]; - -#define TEST_STRING1(OP, size, DF, REP)\ -{\ - long esi, edi, eax, ecx, eflags;\ -\ - esi = (long)(str_buffer + sizeof(str_buffer) / 2);\ - edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\ - eax = i2l(0x12345678);\ - ecx = 17;\ -\ - asm volatile ("push $0\n\t"\ - "popf\n\t"\ - DF "\n\t"\ - REP #OP size "\n\t"\ - "cld\n\t"\ - "pushf\n\t"\ - "pop %4\n\t"\ - : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\ - : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\ - printf("%-10s ESI=" FMTLX " EDI=" FMTLX " EAX=" FMTLX " ECX=" FMTLX " EFL=%04x\n",\ - REP #OP size, esi, edi, eax, ecx,\ - (int)(eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)));\ -} - -#define TEST_STRING(OP, REP)\ - TEST_STRING1(OP, "b", "", REP);\ - TEST_STRING1(OP, "w", "", REP);\ - TEST_STRING1(OP, "l", "", REP);\ - X86_64_ONLY(TEST_STRING1(OP, "q", "", REP));\ - TEST_STRING1(OP, "b", "std", REP);\ - TEST_STRING1(OP, "w", "std", REP);\ - TEST_STRING1(OP, "l", "std", REP);\ - X86_64_ONLY(TEST_STRING1(OP, "q", "std", REP)) - -void test_string(void) -{ - int i; - for(i = 0;i < sizeof(str_buffer); i++) - str_buffer[i] = i + 0x56; - TEST_STRING(stos, ""); - TEST_STRING(stos, "rep "); - TEST_STRING(lods, ""); /* to verify stos */ - TEST_STRING(lods, "rep "); - TEST_STRING(movs, ""); - TEST_STRING(movs, "rep "); - TEST_STRING(lods, ""); /* to verify stos */ - - /* XXX: better tests */ - TEST_STRING(scas, ""); - TEST_STRING(scas, "repz "); - TEST_STRING(scas, "repnz "); - TEST_STRING(cmps, ""); - TEST_STRING(cmps, "repz "); - TEST_STRING(cmps, "repnz "); -} - -#ifdef TEST_VM86 -/* VM86 test */ - -static inline void set_bit(uint8_t *a, unsigned int bit) -{ - a[bit / 8] |= (1 << (bit % 8)); -} - -static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) -{ - return (uint8_t *)((seg << 4) + (reg & 0xffff)); -} - -static inline void pushw(struct vm86_regs *r, int val) -{ - r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff); - *(uint16_t *)seg_to_linear(r->ss, r->esp) = val; -} - -static inline int vm86(int func, struct vm86plus_struct *v86) -{ - return syscall(__NR_vm86, func, v86); -} - -extern char vm86_code_start; -extern char vm86_code_end; - -#define VM86_CODE_CS 0x100 -#define VM86_CODE_IP 0x100 - -void test_vm86(void) -{ - struct vm86plus_struct ctx; - struct vm86_regs *r; - uint8_t *vm86_mem; - int seg, ret; - - vm86_mem = mmap((void *)0x00000000, 0x110000, - PROT_WRITE | PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); - if (vm86_mem == MAP_FAILED) { - printf("ERROR: could not map vm86 memory"); - return; - } - memset(&ctx, 0, sizeof(ctx)); - - /* init basic registers */ - r = &ctx.regs; - r->eip = VM86_CODE_IP; - r->esp = 0xfffe; - seg = VM86_CODE_CS; - r->cs = seg; - r->ss = seg; - r->ds = seg; - r->es = seg; - r->fs = seg; - r->gs = seg; - r->eflags = VIF_MASK; - - /* move code to proper address. We use the same layout as a .com - dos program. */ - memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, - &vm86_code_start, &vm86_code_end - &vm86_code_start); - - /* mark int 0x21 as being emulated */ - set_bit((uint8_t *)&ctx.int_revectored, 0x21); - - for(;;) { - ret = vm86(VM86_ENTER, &ctx); - switch(VM86_TYPE(ret)) { - case VM86_INTx: - { - int int_num, ah, v; - - int_num = VM86_ARG(ret); - if (int_num != 0x21) - goto unknown_int; - ah = (r->eax >> 8) & 0xff; - switch(ah) { - case 0x00: /* exit */ - goto the_end; - case 0x02: /* write char */ - { - uint8_t c = r->edx; - putchar(c); - } - break; - case 0x09: /* write string */ - { - uint8_t c, *ptr; - ptr = seg_to_linear(r->ds, r->edx); - for(;;) { - c = *ptr++; - if (c == '$') - break; - putchar(c); - } - r->eax = (r->eax & ~0xff) | '$'; - } - break; - case 0xff: /* extension: write eflags number in edx */ - v = (int)r->edx; -#ifndef LINUX_VM86_IOPL_FIX - v &= ~0x3000; -#endif - printf("%08x\n", v); - break; - default: - unknown_int: - printf("unsupported int 0x%02x\n", int_num); - goto the_end; - } - } - break; - case VM86_SIGNAL: - /* a signal came, we just ignore that */ - break; - case VM86_STI: - break; - default: - printf("ERROR: unhandled vm86 return code (0x%x)\n", ret); - goto the_end; - } - } - the_end: - printf("VM86 end\n"); - munmap(vm86_mem, 0x110000); -} -#endif - -/* exception tests */ -#if defined(__i386__) && !defined(REG_EAX) -#define REG_EAX EAX -#define REG_EBX EBX -#define REG_ECX ECX -#define REG_EDX EDX -#define REG_ESI ESI -#define REG_EDI EDI -#define REG_EBP EBP -#define REG_ESP ESP -#define REG_EIP EIP -#define REG_EFL EFL -#define REG_TRAPNO TRAPNO -#define REG_ERR ERR -#endif - -#if defined(__x86_64__) -#define REG_EIP REG_RIP -#endif - -jmp_buf jmp_env; -int v1; -int tab[2]; - -void sig_handler(int sig, siginfo_t *info, void *puc) -{ - ucontext_t *uc = puc; - - printf("si_signo=%d si_errno=%d si_code=%d", - info->si_signo, info->si_errno, info->si_code); - printf(" si_addr=0x%08lx", - (unsigned long)info->si_addr); - printf("\n"); - - printf("trapno=" FMTLX " err=" FMTLX, - (long)uc->uc_mcontext.gregs[REG_TRAPNO], - (long)uc->uc_mcontext.gregs[REG_ERR]); - printf(" EIP=" FMTLX, (long)uc->uc_mcontext.gregs[REG_EIP]); - printf("\n"); - longjmp(jmp_env, 1); -} - -void test_exceptions(void) -{ - struct sigaction act; - volatile int val; - - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO | SA_NODEFER; - sigaction(SIGFPE, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGTRAP, &act, NULL); - - /* test division by zero reporting */ - printf("DIVZ exception:\n"); - if (setjmp(jmp_env) == 0) { - /* now divide by zero */ - v1 = 0; - v1 = 2 / v1; - } - -#if !defined(__x86_64__) - printf("BOUND exception:\n"); - if (setjmp(jmp_env) == 0) { - /* bound exception */ - tab[0] = 1; - tab[1] = 10; - asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0])); - } -#endif - -#ifdef TEST_SEGS - printf("segment exceptions:\n"); - if (setjmp(jmp_env) == 0) { - /* load an invalid segment */ - asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1)); - } - if (setjmp(jmp_env) == 0) { - /* null data segment is valid */ - asm volatile ("movl %0, %%fs" : : "r" (3)); - /* null stack segment */ - asm volatile ("movl %0, %%ss" : : "r" (3)); - } - - { - struct modify_ldt_ldt_s ldt; - ldt.entry_number = 1; - ldt.base_addr = (unsigned long)&seg_data1; - ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; - ldt.seg_32bit = 1; - ldt.contents = MODIFY_LDT_CONTENTS_DATA; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 1; - ldt.seg_not_present = 1; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - if (setjmp(jmp_env) == 0) { - /* segment not present */ - asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); - } - } -#endif - - /* test SEGV reporting */ - printf("PF exception:\n"); - if (setjmp(jmp_env) == 0) { - val = 1; - /* we add a nop to test a weird PC retrieval case */ - asm volatile ("nop"); - /* now store in an invalid address */ - *(char *)0x1234 = 1; - } - - /* test SEGV reporting */ - printf("PF exception:\n"); - if (setjmp(jmp_env) == 0) { - val = 1; - /* read from an invalid address */ - v1 = *(char *)0x1234; - } - - /* test illegal instruction reporting */ - printf("UD2 exception:\n"); - if (setjmp(jmp_env) == 0) { - /* now execute an invalid instruction */ - asm volatile("ud2"); - } - printf("lock nop exception:\n"); - if (setjmp(jmp_env) == 0) { - /* now execute an invalid instruction */ - asm volatile(".byte 0xf0, 0x90"); - } - - printf("INT exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("int $0xfd"); - } - if (setjmp(jmp_env) == 0) { - asm volatile ("int $0x01"); - } - if (setjmp(jmp_env) == 0) { - asm volatile (".byte 0xcd, 0x03"); - } - if (setjmp(jmp_env) == 0) { - asm volatile ("int $0x04"); - } - if (setjmp(jmp_env) == 0) { - asm volatile ("int $0x05"); - } - - printf("INT3 exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("int3"); - } - - printf("CLI exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("cli"); - } - - printf("STI exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("cli"); - } - -#if !defined(__x86_64__) - printf("INTO exception:\n"); - if (setjmp(jmp_env) == 0) { - /* overflow exception */ - asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); - } -#endif - - printf("OUTB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); - } - - printf("INB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); - } - - printf("REP OUTSB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); - } - - printf("REP INSB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); - } - - printf("HLT exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("hlt"); - } - - printf("single step exception:\n"); - val = 0; - if (setjmp(jmp_env) == 0) { - asm volatile ("pushf\n" - "orl $0x00100, (%%esp)\n" - "popf\n" - "movl $0xabcd, %0\n" - "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory"); - } - printf("val=0x%x\n", val); -} - -#if !defined(__x86_64__) -/* specific precise single step test */ -void sig_trap_handler(int sig, siginfo_t *info, void *puc) -{ - ucontext_t *uc = puc; - printf("EIP=" FMTLX "\n", (long)uc->uc_mcontext.gregs[REG_EIP]); -} - -const uint8_t sstep_buf1[4] = { 1, 2, 3, 4}; -uint8_t sstep_buf2[4]; - -void test_single_step(void) -{ - struct sigaction act; - volatile int val; - int i; - - val = 0; - act.sa_sigaction = sig_trap_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - sigaction(SIGTRAP, &act, NULL); - asm volatile ("pushf\n" - "orl $0x00100, (%%esp)\n" - "popf\n" - "movl $0xabcd, %0\n" - - /* jmp test */ - "movl $3, %%ecx\n" - "1:\n" - "addl $1, %0\n" - "decl %%ecx\n" - "jnz 1b\n" - - /* movsb: the single step should stop at each movsb iteration */ - "movl $sstep_buf1, %%esi\n" - "movl $sstep_buf2, %%edi\n" - "movl $0, %%ecx\n" - "rep movsb\n" - "movl $3, %%ecx\n" - "rep movsb\n" - "movl $1, %%ecx\n" - "rep movsb\n" - - /* cmpsb: the single step should stop at each cmpsb iteration */ - "movl $sstep_buf1, %%esi\n" - "movl $sstep_buf2, %%edi\n" - "movl $0, %%ecx\n" - "rep cmpsb\n" - "movl $4, %%ecx\n" - "rep cmpsb\n" - - /* getpid() syscall: single step should skip one - instruction */ - "movl $20, %%eax\n" - "int $0x80\n" - "movl $0, %%eax\n" - - /* when modifying SS, trace is not done on the next - instruction */ - "movl %%ss, %%ecx\n" - "movl %%ecx, %%ss\n" - "addl $1, %0\n" - "movl $1, %%eax\n" - "movl %%ecx, %%ss\n" - "jmp 1f\n" - "addl $1, %0\n" - "1:\n" - "movl $1, %%eax\n" - "pushl %%ecx\n" - "popl %%ss\n" - "addl $1, %0\n" - "movl $1, %%eax\n" - - "pushf\n" - "andl $~0x00100, (%%esp)\n" - "popf\n" - : "=m" (val) - : - : "cc", "memory", "eax", "ecx", "esi", "edi"); - printf("val=%d\n", val); - for(i = 0; i < 4; i++) - printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]); -} - -/* self modifying code test */ -uint8_t code[] = { - 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */ - 0xc3, /* ret */ -}; - -asm(".section \".data\"\n" - "smc_code2:\n" - "movl 4(%esp), %eax\n" - "movl %eax, smc_patch_addr2 + 1\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "nop\n" - "smc_patch_addr2:\n" - "movl $1, %eax\n" - "ret\n" - ".previous\n" - ); - -typedef int FuncType(void); -extern int smc_code2(int); -void test_self_modifying_code(void) -{ - int i; - printf("self modifying code:\n"); - printf("func1 = 0x%x\n", ((FuncType *)code)()); - for(i = 2; i <= 4; i++) { - code[1] = i; - printf("func%d = 0x%x\n", i, ((FuncType *)code)()); - } - - /* more difficult test : the modified code is just after the - modifying instruction. It is forbidden in Intel specs, but it - is used by old DOS programs */ - for(i = 2; i <= 4; i++) { - printf("smc_code2(%d) = %d\n", i, smc_code2(i)); - } -} -#endif - -long enter_stack[4096]; - -#if defined(__x86_64__) -#define RSP "%%rsp" -#define RBP "%%rbp" -#else -#define RSP "%%esp" -#define RBP "%%ebp" -#endif - -#if !defined(__x86_64__) -/* causes an infinite loop, disable it for now. */ -#define TEST_ENTER(size, stack_type, level) -#else -#define TEST_ENTER(size, stack_type, level)\ -{\ - long esp_save, esp_val, ebp_val, ebp_save, i;\ - stack_type *ptr, *stack_end, *stack_ptr;\ - memset(enter_stack, 0, sizeof(enter_stack));\ - stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\ - ebp_val = (long)stack_ptr;\ - for(i=1;i<=32;i++)\ - *--stack_ptr = i;\ - esp_val = (long)stack_ptr;\ - asm("mov " RSP ", %[esp_save]\n"\ - "mov " RBP ", %[ebp_save]\n"\ - "mov %[esp_val], " RSP "\n"\ - "mov %[ebp_val], " RBP "\n"\ - "enter" size " $8, $" #level "\n"\ - "mov " RSP ", %[esp_val]\n"\ - "mov " RBP ", %[ebp_val]\n"\ - "mov %[esp_save], " RSP "\n"\ - "mov %[ebp_save], " RBP "\n"\ - : [esp_save] "=r" (esp_save),\ - [ebp_save] "=r" (ebp_save),\ - [esp_val] "=r" (esp_val),\ - [ebp_val] "=r" (ebp_val)\ - : "[esp_val]" (esp_val),\ - "[ebp_val]" (ebp_val));\ - printf("level=%d:\n", level);\ - printf("esp_val=" FMTLX "\n", esp_val - (long)stack_end);\ - printf("ebp_val=" FMTLX "\n", ebp_val - (long)stack_end);\ - for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\ - printf(FMTLX "\n", (long)ptr[0]);\ -} -#endif - -static void test_enter(void) -{ -#if defined(__x86_64__) - TEST_ENTER("q", uint64_t, 0); - TEST_ENTER("q", uint64_t, 1); - TEST_ENTER("q", uint64_t, 2); - TEST_ENTER("q", uint64_t, 31); -#else - TEST_ENTER("l", uint32_t, 0); - TEST_ENTER("l", uint32_t, 1); - TEST_ENTER("l", uint32_t, 2); - TEST_ENTER("l", uint32_t, 31); -#endif - - TEST_ENTER("w", uint16_t, 0); - TEST_ENTER("w", uint16_t, 1); - TEST_ENTER("w", uint16_t, 2); - 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;\ - a = i2l(0x8234a6f8);\ - r = a;\ - asm volatile(#op : "=a" (r) : "0" (r));\ - printf("%-10s A=" FMTLX " R=" FMTLX "\n", #op, a, r);\ -} - -#define TEST_CONV_RAX_RDX(op)\ -{\ - unsigned long a, d, r, rh; \ - a = i2l(0x8234a6f8);\ - d = i2l(0x8345a1f2);\ - r = a;\ - rh = d;\ - asm volatile(#op : "=a" (r), "=d" (rh) : "0" (r), "1" (rh)); \ - printf("%-10s A=" FMTLX " R=" FMTLX ":" FMTLX "\n", #op, a, r, rh); \ -} - -void test_conv(void) -{ - TEST_CONV_RAX(cbw); - TEST_CONV_RAX(cwde); -#if defined(__x86_64__) - TEST_CONV_RAX(cdqe); -#endif - - TEST_CONV_RAX_RDX(cwd); - TEST_CONV_RAX_RDX(cdq); -#if defined(__x86_64__) - TEST_CONV_RAX_RDX(cqo); -#endif - - { - unsigned long a, r; - a = i2l(0x12345678); - asm volatile("bswapl %k0" : "=r" (r) : "0" (a)); - printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapl", a, r); - } -#if defined(__x86_64__) - { - unsigned long a, r; - a = i2l(0x12345678); - asm volatile("bswapq %0" : "=r" (r) : "0" (a)); - printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapq", a, r); - } -#endif -} - -extern void *__start_initcall; -extern void *__stop_initcall; - - -int main(int argc, char **argv) -{ - void **ptr; - void (*func)(void); - - ptr = &__start_initcall; - while (ptr != &__stop_initcall) { - func = *ptr++; - func(); - } - test_bsx(); - test_mul(); - test_jcc(); - test_loop(); - test_floats(); -#if !defined(__x86_64__) - test_bcd(); -#endif - test_xchg(); - test_string(); - test_misc(); - test_lea(); -#ifdef TEST_SEGS - test_segs(); - test_code16(); -#endif -#ifdef TEST_VM86 - test_vm86(); -#endif -#if !defined(__x86_64__) - test_exceptions(); - test_self_modifying_code(); - test_single_step(); -#endif - test_enter(); - test_conv(); -#ifdef TEST_SSE - test_sse(); - test_fxsave(); -#endif - return 0; -} diff --git a/tests/tcg/i386/test-i386.h b/tests/tcg/i386/test-i386.h deleted file mode 100644 index 75106b8ce2a4..000000000000 --- a/tests/tcg/i386/test-i386.h +++ /dev/null @@ -1,152 +0,0 @@ - -#define exec_op glue(exec_, OP) -#define exec_opq glue(glue(exec_, OP), q) -#define exec_opl glue(glue(exec_, OP), l) -#define exec_opw glue(glue(exec_, OP), w) -#define exec_opb glue(glue(exec_, OP), b) - -#define EXECOP2(size, rsize, res, s1, flags) \ - asm ("push %4\n\t"\ - "popf\n\t"\ - stringify(OP) size " %" rsize "2, %" rsize "0\n\t" \ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=q" (res), "=g" (flags)\ - : "q" (s1), "0" (res), "1" (flags)); \ - printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", \ - stringify(OP) size, s0, s1, res, iflags, flags & CC_MASK); - -#define EXECOP1(size, rsize, res, flags) \ - asm ("push %3\n\t"\ - "popf\n\t"\ - stringify(OP) size " %" rsize "0\n\t" \ - "pushf\n\t"\ - "pop %1\n\t"\ - : "=q" (res), "=g" (flags)\ - : "0" (res), "1" (flags)); \ - printf("%-10s A=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", \ - stringify(OP) size, s0, res, iflags, flags & CC_MASK); - -#ifdef OP1 -#if defined(__x86_64__) -void exec_opq(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP1("q", "", res, flags); -} -#endif - -void exec_opl(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP1("l", "k", res, flags); -} - -void exec_opw(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP1("w", "w", res, flags); -} - -void exec_opb(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP1("b", "b", res, flags); -} -#else -#if defined(__x86_64__) -void exec_opq(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP2("q", "", res, s1, flags); -} -#endif - -void exec_opl(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP2("l", "k", res, s1, flags); -} - -void exec_opw(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP2("w", "w", res, s1, flags); -} - -void exec_opb(long s0, long s1, long iflags) -{ - long res, flags; - res = s0; - flags = iflags; - EXECOP2("b", "b", res, s1, flags); -} -#endif - -void exec_op(long s0, long s1) -{ - s0 = i2l(s0); - s1 = i2l(s1); -#if defined(__x86_64__) - exec_opq(s0, s1, 0); -#endif - exec_opl(s0, s1, 0); - exec_opw(s0, s1, 0); - exec_opb(s0, s1, 0); -#ifdef OP_CC -#if defined(__x86_64__) - exec_opq(s0, s1, CC_C); -#endif - exec_opl(s0, s1, CC_C); - exec_opw(s0, s1, CC_C); - exec_opb(s0, s1, CC_C); -#endif -} - -void glue(test_, OP)(void) -{ - exec_op(0x12345678, 0x812FADA); - exec_op(0x12341, 0x12341); - exec_op(0x12341, -0x12341); - exec_op(0xffffffff, 0); - exec_op(0xffffffff, -1); - exec_op(0xffffffff, 1); - exec_op(0xffffffff, 2); - exec_op(0x7fffffff, 0); - exec_op(0x7fffffff, 1); - exec_op(0x7fffffff, -1); - exec_op(0x80000000, -1); - exec_op(0x80000000, 1); - exec_op(0x80000000, -2); - exec_op(0x12347fff, 0); - exec_op(0x12347fff, 1); - exec_op(0x12347fff, -1); - exec_op(0x12348000, -1); - exec_op(0x12348000, 1); - exec_op(0x12348000, -2); - exec_op(0x12347f7f, 0); - exec_op(0x12347f7f, 1); - exec_op(0x12347f7f, -1); - exec_op(0x12348080, -1); - exec_op(0x12348080, 1); - exec_op(0x12348080, -2); -} - -void *glue(_test_, OP) __init_call = glue(test_, OP); - -#undef OP -#undef OP_CC diff --git a/tests/tcg/m68k/Makefile.target b/tests/tcg/m68k/Makefile.target deleted file mode 100644 index 62f109eef46b..000000000000 --- a/tests/tcg/m68k/Makefile.target +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: makefile -*- -# -# m68k specific tweaks - specifically masking out broken tests -# - -# On m68k Linux supports 4k and 8k pages (but 8k is currently broken) -EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192 diff --git a/tests/tcg/minilib/Makefile.target b/tests/tcg/minilib/Makefile.target deleted file mode 100644 index c821d2806a9c..000000000000 --- a/tests/tcg/minilib/Makefile.target +++ /dev/null @@ -1,21 +0,0 @@ -# -# System test minilib objects -# -# The system tests are very constrained in terms of the library they -# support but we are not savages. We provide a few helpful routines -# that can be shared with the tests for basic I/O. -# -# They assume each arch has provided a putc function. -# - -SYSTEM_MINILIB_SRC=$(SRC_PATH)/tests/tcg/minilib -MINILIB_SRCS=$(wildcard $(SYSTEM_MINILIB_SRC)/*.c) -MINILIB_OBJS=$(patsubst $(SYSTEM_MINILIB_SRC)/%.c, %.o, $(MINILIB_SRCS)) - -MINILIB_CFLAGS+=-nostdlib -ggdb -O0 -MINILIB_INC=-isystem $(SYSTEM_MINILIB_SRC) - -.PRECIOUS: $(MINILIB_OBJS) - -%.o: $(SYSTEM_MINILIB_SRC)/%.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ diff --git a/tests/tcg/minilib/minilib.h b/tests/tcg/minilib/minilib.h deleted file mode 100644 index 17d0f2f31407..000000000000 --- a/tests/tcg/minilib/minilib.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 Virtual Open Systems SAS - * Author: Alexander Spyridakis - * - * 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. - * - * SPDX-License-Identifier: GPL-2.0-only - */ - -#ifndef MINILIB_H -#define MINILIB_H - -/* - * Provided by the individual arch - */ -extern void __sys_outc(char c); - -/* - * Provided by the common minilib - */ -void ml_printf(const char *fmt, ...); - -#endif /* _MINILIB_H_ */ diff --git a/tests/tcg/minilib/printf.c b/tests/tcg/minilib/printf.c deleted file mode 100644 index 10472b4f5852..000000000000 --- a/tests/tcg/minilib/printf.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 Virtual Open Systems SAS - * Author: Alexander Spyridakis - * - * printf based on implementation by Kevin Wolf - * - * 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. - * - * SPDX-License-Identifier: GPL-2.0-only - */ - -#include "minilib.h" - -typedef __builtin_va_list va_list; -#define va_start(ap, X) __builtin_va_start(ap, X) -#define va_arg(ap, type) __builtin_va_arg(ap, type) -#define va_end(ap) __builtin_va_end(ap) - -static void print_str(char *s) -{ - while (*s) { - __sys_outc(*s++); - } -} - -static void print_num(unsigned long long value, int base) -{ - char digits[] = "0123456789abcdef"; - char buf[32]; - int i = sizeof(buf) - 2, j; - - /* Set the buffer to 0. See problem of before. */ - for (j = 0; j < 32; j++) { - buf[j] = 0; - } - - do { - buf[i--] = digits[value % base]; - value /= base; - } while (value); - - print_str(&buf[i + 1]); -} - -void ml_printf(const char *fmt, ...) -{ - va_list ap; - char *str; - int base; - int has_long; - int alt_form; - unsigned long long val; - - va_start(ap, fmt); - - for (; *fmt; fmt++) { - if (*fmt != '%') { - __sys_outc(*fmt); - continue; - } - fmt++; - - if (*fmt == '#') { - fmt++; - alt_form = 1; - } else { - alt_form = 0; - } - - if (*fmt == 'l') { - fmt++; - if (*fmt == 'l') { - fmt++; - has_long = 2; - } else { - has_long = 1; - } - } else { - has_long = 0; - } - - switch (*fmt) { - case 'x': - case 'p': - base = 16; - goto convert_number; - case 'd': - case 'i': - case 'u': - base = 10; - goto convert_number; - case 'o': - base = 8; - goto convert_number; - - convert_number: - switch (has_long) { - case 0: - val = va_arg(ap, unsigned int); - break; - case 1: - val = va_arg(ap, unsigned long); - break; - case 2: - val = va_arg(ap, unsigned long long); - break; - } - - if (alt_form && base == 16) { - print_str("0x"); - } - - print_num(val, base); - break; - - case 's': - str = va_arg(ap, char*); - print_str(str); - break; - case 'c': - __sys_outc(va_arg(ap, int)); - break; - case '%': - __sys_outc(*fmt); - break; - default: - __sys_outc('%'); - __sys_outc(*fmt); - break; - } - } - - va_end(ap); -} diff --git a/tests/tcg/mips/Makefile.target b/tests/tcg/mips/Makefile.target deleted file mode 100644 index 1a994d5525ed..000000000000 --- a/tests/tcg/mips/Makefile.target +++ /dev/null @@ -1,19 +0,0 @@ -# -*- Mode: makefile -*- -# -# MIPS - included from tests/tcg/Makefile.target -# - -MIPS_SRC=$(SRC_PATH)/tests/tcg/mips - -# Set search path for all sources -VPATH += $(MIPS_SRC) - -# hello-mips is 32 bit only -ifeq ($(findstring 64,$(TARGET_NAME)),) -MIPS_TESTS=hello-mips - -TESTS += $(MIPS_TESTS) - -hello-mips: CFLAGS+=-mno-abicalls -fno-PIC -mabi=32 -hello-mips: LDFLAGS+=-nostdlib -endif diff --git a/tests/tcg/mips/README b/tests/tcg/mips/README deleted file mode 100644 index e5bbc58ec545..000000000000 --- a/tests/tcg/mips/README +++ /dev/null @@ -1,7 +0,0 @@ -MIPS -==== - -hello-mips ----------- - -A very simple inline assembly, write syscall based hello world diff --git a/tests/tcg/mips/hello-mips.c b/tests/tcg/mips/hello-mips.c deleted file mode 100644 index 4e1cf501afe1..000000000000 --- a/tests/tcg/mips/hello-mips.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -* MIPS o32 Linux syscall example -* -* http://www.linux-mips.org/wiki/RISC/os -* http://www.linux-mips.org/wiki/MIPSABIHistory -* http://www.linux.com/howtos/Assembly-HOWTO/mips.shtml -* -* mipsel-linux-gcc -nostdlib -mno-abicalls -fno-PIC -mabi=32 \ -* -O2 -static -o hello-mips hello-mips.c -* -*/ -#define __NR_SYSCALL_BASE 4000 -#define __NR_exit (__NR_SYSCALL_BASE+ 1) -#define __NR_write (__NR_SYSCALL_BASE+ 4) - -static inline void exit1(int status) -{ - register unsigned long __a0 asm("$4") = (unsigned long) status; - - __asm__ __volatile__ ( - " .set push \n" - " .set noreorder \n" - " li $2, %0 \n" - " syscall \n" - " .set pop " - : - : "i" (__NR_exit), "r" (__a0) - : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", - "memory"); -} - -static inline int write(int fd, const char *buf, int len) -{ - register unsigned long __a0 asm("$4") = (unsigned long) fd; - register unsigned long __a1 asm("$5") = (unsigned long) buf; - register unsigned long __a2 asm("$6") = (unsigned long) len; - register unsigned long __a3 asm("$7"); - unsigned long __v0; - - __asm__ __volatile__ ( - " .set push \n" - " .set noreorder \n" - " li $2, %2 \n" - " syscall \n" - " move %0, $2 \n" - " .set pop " - : "=r" (__v0), "=r" (__a3) - : "i" (__NR_write), "r" (__a0), "r" (__a1), "r" (__a2) - : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", - "memory"); - -/* if (__a3 == 0) */ - return (int) __v0; -/* - errno = __v0; - return -1; - */ -} - -void __start(void) -{ - write (1, "Hello, World!\n", 14); - exit1(0); -} diff --git a/tests/tcg/mips/include/test_inputs_128.h b/tests/tcg/mips/include/test_inputs_128.h deleted file mode 100644 index e4c22dde6e57..000000000000 --- a/tests/tcg/mips/include/test_inputs_128.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Header file for pattern and random test inputs - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef TEST_INPUTS_128_H -#define TEST_INPUTS_128_H - -#include - - -#define PATTERN_INPUTS_COUNT 64 -#define PATTERN_INPUTS_SHORT_COUNT 8 - -static const uint64_t b128_pattern[PATTERN_INPUTS_COUNT][2] = { - { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xAAAAAAAAAAAAAAAAULL, 0xAAAAAAAAAAAAAAAAULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xCCCCCCCCCCCCCCCCULL, 0xCCCCCCCCCCCCCCCCULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xE38E38E38E38E38EULL, 0x38E38E38E38E38E3ULL, }, - { 0x1C71C71C71C71C71ULL, 0xC71C71C71C71C71CULL, }, - { 0xF0F0F0F0F0F0F0F0ULL, 0xF0F0F0F0F0F0F0F0ULL, }, /* 8 */ - { 0x0F0F0F0F0F0F0F0FULL, 0x0F0F0F0F0F0F0F0FULL, }, - { 0xF83E0F83E0F83E0FULL, 0x83E0F83E0F83E0F8ULL, }, - { 0x07C1F07C1F07C1F0ULL, 0x7C1F07C1F07C1F07ULL, }, - { 0xFC0FC0FC0FC0FC0FULL, 0xC0FC0FC0FC0FC0FCULL, }, - { 0x03F03F03F03F03F0ULL, 0x3F03F03F03F03F03ULL, }, - { 0xFE03F80FE03F80FEULL, 0x03F80FE03F80FE03ULL, }, - { 0x01FC07F01FC07F01ULL, 0xFC07F01FC07F01FCULL, }, - { 0xFF00FF00FF00FF00ULL, 0xFF00FF00FF00FF00ULL, }, /* 16 */ - { 0x00FF00FF00FF00FFULL, 0x00FF00FF00FF00FFULL, }, - { 0xFF803FE00FF803FEULL, 0x00FF803FE00FF803ULL, }, - { 0x007FC01FF007FC01ULL, 0xFF007FC01FF007FCULL, }, - { 0xFFC00FFC00FFC00FULL, 0xFC00FFC00FFC00FFULL, }, - { 0x003FF003FF003FF0ULL, 0x03FF003FF003FF00ULL, }, - { 0xFFE003FF800FFE00ULL, 0x3FF800FFE003FF80ULL, }, - { 0x001FFC007FF001FFULL, 0xC007FF001FFC007FULL, }, - { 0xFFF000FFF000FFF0ULL, 0x00FFF000FFF000FFULL, }, /* 24 */ - { 0x000FFF000FFF000FULL, 0xFF000FFF000FFF00ULL, }, - { 0xFFF8003FFE000FFFULL, 0x8003FFE000FFF800ULL, }, - { 0x0007FFC001FFF000ULL, 0x7FFC001FFF0007FFULL, }, - { 0xFFFC000FFFC000FFULL, 0xFC000FFFC000FFFCULL, }, - { 0x0003FFF0003FFF00ULL, 0x03FFF0003FFF0003ULL, }, - { 0xFFFE0003FFF8000FULL, 0xFFE0003FFF8000FFULL, }, - { 0x0001FFFC0007FFF0ULL, 0x001FFFC0007FFF00ULL, }, - { 0xFFFF0000FFFF0000ULL, 0xFFFF0000FFFF0000ULL, }, /* 32 */ - { 0x0000FFFF0000FFFFULL, 0x0000FFFF0000FFFFULL, }, - { 0xFFFF80003FFFE000ULL, 0x0FFFF80003FFFE00ULL, }, - { 0x00007FFFC0001FFFULL, 0xF00007FFFC0001FFULL, }, - { 0xFFFFC0000FFFFC00ULL, 0x00FFFFC0000FFFFCULL, }, - { 0x00003FFFF00003FFULL, 0xFF00003FFFF00003ULL, }, - { 0xFFFFE00003FFFF80ULL, 0x000FFFFE00003FFFULL, }, - { 0x00001FFFFC00007FULL, 0xFFF00001FFFFC000ULL, }, - { 0xFFFFF00000FFFFF0ULL, 0x0000FFFFF00000FFULL, }, /* 40 */ - { 0x00000FFFFF00000FULL, 0xFFFF00000FFFFF00ULL, }, - { 0xFFFFF800003FFFFEULL, 0x00000FFFFF800003ULL, }, - { 0x000007FFFFC00001ULL, 0xFFFFF000007FFFFCULL, }, - { 0xFFFFFC00000FFFFFULL, 0xC00000FFFFFC0000ULL, }, - { 0x000003FFFFF00000ULL, 0x3FFFFF000003FFFFULL, }, - { 0xFFFFFE000003FFFFULL, 0xF800000FFFFFE000ULL, }, - { 0x000001FFFFFC0000ULL, 0x07FFFFF000001FFFULL, }, - { 0xFFFFFF000000FFFFULL, 0xFF000000FFFFFF00ULL, }, /* 48 */ - { 0x000000FFFFFF0000ULL, 0x00FFFFFF000000FFULL, }, - { 0xFFFFFF8000003FFFULL, 0xFFE000000FFFFFF8ULL, }, - { 0x0000007FFFFFC000ULL, 0x001FFFFFF0000007ULL, }, - { 0xFFFFFFC000000FFFULL, 0xFFFC000000FFFFFFULL, }, - { 0x0000003FFFFFF000ULL, 0x0003FFFFFF000000ULL, }, - { 0xFFFFFFE0000003FFULL, 0xFFFF8000000FFFFFULL, }, - { 0x0000001FFFFFFC00ULL, 0x00007FFFFFF00000ULL, }, - { 0xFFFFFFF0000000FFULL, 0xFFFFF0000000FFFFULL, }, /* 56 */ - { 0x0000000FFFFFFF00ULL, 0x00000FFFFFFF0000ULL, }, - { 0xFFFFFFF80000003FULL, 0xFFFFFE0000000FFFULL, }, - { 0x00000007FFFFFFC0ULL, 0x000001FFFFFFF000ULL, }, - { 0xFFFFFFFC0000000FULL, 0xFFFFFFC0000000FFULL, }, - { 0x00000003FFFFFFF0ULL, 0x0000003FFFFFFF00ULL, }, - { 0xFFFFFFFE00000003ULL, 0xFFFFFFF80000000FULL, }, - { 0x00000001FFFFFFFCULL, 0x00000007FFFFFFF0ULL, }, -}; - - -#define RANDOM_INPUTS_COUNT 16 -#define RANDOM_INPUTS_SHORT_COUNT 4 - -static const uint64_t b128_random[RANDOM_INPUTS_COUNT][2] = { - { 0x886AE6CC28625540ULL, 0x4B670B5EFE7BB00CULL, }, /* 0 */ - { 0xFBBE00634D93C708ULL, 0x12F7BB1A153F52FCULL, }, - { 0xAC5AAEAAB9CF8B80ULL, 0x27D8C6FFAB2B2514ULL, }, - { 0x704F164D5E31E24EULL, 0x8DF188D8A942E2A0ULL, }, - { 0xB9926B7C7DAF4258ULL, 0xA1227CADDCCE65B6ULL, }, - { 0xD027BE89FF0A2EF9ULL, 0x170B5050FEA53078ULL, }, - { 0xB83B580665CABC4AULL, 0x91230822BFF0BA62ULL, }, - { 0xFC8F23F09AA6B782ULL, 0x93FD6637124275AEULL, }, - { 0x201E09CD56AEE649ULL, 0xEF5DE039A6A52758ULL, }, /* 8 */ - { 0xA57CD91365D9E5D7ULL, 0x9321BC9881ECBA5CULL, }, - { 0xA2E8F6F5C9CBC61BULL, 0xB2C471545E0D7A12ULL, }, - { 0xA89CF2F131A864AEULL, 0xD2A3E87A5DB986E7ULL, }, - { 0xE61438E9A652EA0AULL, 0xA85483D97879D41CULL, }, - { 0x944A35FD192361A8ULL, 0xF3912DA36A0B2D6BULL, }, - { 0x4630426322BEF79CULL, 0xEB5686F7CB19304EULL, }, - { 0x8B5AA7A2F259DEADULL, 0xD278CBCD696417E3ULL, }, -}; - - -#endif diff --git a/tests/tcg/mips/include/test_inputs_32.h b/tests/tcg/mips/include/test_inputs_32.h deleted file mode 100644 index a3b7e5464a01..000000000000 --- a/tests/tcg/mips/include/test_inputs_32.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Header file for pattern and random test inputs - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef TEST_INPUTS_32_H -#define TEST_INPUTS_32_H - -#include - - -#define PATTERN_INPUTS_32_COUNT 64 -#define PATTERN_INPUTS_32_SHORT_COUNT 8 - -static const uint32_t b32_pattern[PATTERN_INPUTS_32_COUNT] = { - 0xFFFFFFFF, /* 0 */ - 0x00000000, - 0xAAAAAAAA, - 0x55555555, - 0xCCCCCCCC, - 0x33333333, - 0xE38E38E3, - 0x1C71C71C, - 0xF0F0F0F0, /* 8 */ - 0x0F0F0F0F, - 0xF83E0F83, - 0x07C1F07C, - 0xFC0FC0FC, - 0x03F03F03, - 0xFE03F80F, - 0x01FC07F0, - 0xFF00FF00, /* 16 */ - 0x00FF00FF, - 0xFF803FE0, - 0x007FC01F, - 0xFFC00FFC, - 0x003FF003, - 0xFFE003FF, - 0x001FFC00, - 0xFFF000FF, /* 24 */ - 0x000FFF00, - 0xFFF8003F, - 0x0007FFC0, - 0xFFFC000F, - 0x0003FFF0, - 0xFFFE0003, - 0x0001FFFC, - 0xFFFF0000, /* 32 */ - 0x0000FFFF, - 0xFFFF8000, - 0x00007FFF, - 0xFFFFC000, - 0x00003FFF, - 0xFFFFE000, - 0x00001FFF, - 0xFFFFF000, /* 40 */ - 0x00000FFF, - 0xFFFFF800, - 0x000007FF, - 0xFFFFFC00, - 0x000003FF, - 0xFFFFFE00, - 0x000001FF, - 0xFFFFFF00, /* 48 */ - 0x000000FF, - 0xFFFFFF80, - 0x0000007F, - 0xFFFFFFC0, - 0x0000003F, - 0xFFFFFFE0, - 0x0000001F, - 0xFFFFFFF0, /* 56 */ - 0x0000000F, - 0xFFFFFFF8, - 0x00000007, - 0xFFFFFFFC, - 0x00000003, - 0xFFFFFFFE, - 0x00000001, -}; - - -#define RANDOM_INPUTS_32_COUNT 16 -#define RANDOM_INPUTS_32_SHORT_COUNT 4 - -static const uint32_t b32_random[RANDOM_INPUTS_32_COUNT] = { - 0x886AE6CC, /* 0 */ - 0xFBBE0063, - 0xAC5AAEAA, - 0x704F164D, - 0xB9926B7C, - 0xD027BE89, - 0xB83B5806, - 0xFC8F23F0, - 0x201E09CD, /* 8 */ - 0xA57CD913, - 0xA2E8F6F5, - 0xA89CF2F1, - 0xE61438E9, - 0x944A35FD, - 0x46304263, - 0x8B5AA7A2, -}; - - -#endif diff --git a/tests/tcg/mips/include/test_inputs_64.h b/tests/tcg/mips/include/test_inputs_64.h deleted file mode 100644 index 6891a362a337..000000000000 --- a/tests/tcg/mips/include/test_inputs_64.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Header file for pattern and random test inputs - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef TEST_INPUTS_64_H -#define TEST_INPUTS_64_H - -#include - - -#define PATTERN_INPUTS_64_COUNT 64 -#define PATTERN_INPUTS_64_SHORT_COUNT 8 - -static const uint64_t b64_pattern[PATTERN_INPUTS_64_COUNT] = { - 0xFFFFFFFFFFFFFFFFULL, /* 0 */ - 0x0000000000000000ULL, - 0xAAAAAAAAAAAAAAAAULL, - 0x5555555555555555ULL, - 0xCCCCCCCCCCCCCCCCULL, - 0x3333333333333333ULL, - 0xE38E38E38E38E38EULL, - 0x1C71C71C71C71C71ULL, - 0xF0F0F0F0F0F0F0F0ULL, /* 8 */ - 0x0F0F0F0F0F0F0F0FULL, - 0xF83E0F83E0F83E0FULL, - 0x07C1F07C1F07C1F0ULL, - 0xFC0FC0FC0FC0FC0FULL, - 0x03F03F03F03F03F0ULL, - 0xFE03F80FE03F80FEULL, - 0x01FC07F01FC07F01ULL, - 0xFF00FF00FF00FF00ULL, /* 16 */ - 0x00FF00FF00FF00FFULL, - 0xFF803FE00FF803FEULL, - 0x007FC01FF007FC01ULL, - 0xFFC00FFC00FFC00FULL, - 0x003FF003FF003FF0ULL, - 0xFFE003FF800FFE00ULL, - 0x001FFC007FF001FFULL, - 0xFFF000FFF000FFF0ULL, /* 24 */ - 0x000FFF000FFF000FULL, - 0xFFF8003FFE000FFFULL, - 0x0007FFC001FFF000ULL, - 0xFFFC000FFFC000FFULL, - 0x0003FFF0003FFF00ULL, - 0xFFFE0003FFF8000FULL, - 0x0001FFFC0007FFF0ULL, - 0xFFFF0000FFFF0000ULL, /* 32 */ - 0x0000FFFF0000FFFFULL, - 0xFFFF80003FFFE000ULL, - 0x00007FFFC0001FFFULL, - 0xFFFFC0000FFFFC00ULL, - 0x00003FFFF00003FFULL, - 0xFFFFE00003FFFF80ULL, - 0x00001FFFFC00007FULL, - 0xFFFFF00000FFFFF0ULL, /* 40 */ - 0x00000FFFFF00000FULL, - 0xFFFFF800003FFFFEULL, - 0x000007FFFFC00001ULL, - 0xFFFFFC00000FFFFFULL, - 0x000003FFFFF00000ULL, - 0xFFFFFE000003FFFFULL, - 0x000001FFFFFC0000ULL, - 0xFFFFFF000000FFFFULL, /* 48 */ - 0x000000FFFFFF0000ULL, - 0xFFFFFF8000003FFFULL, - 0x0000007FFFFFC000ULL, - 0xFFFFFFC000000FFFULL, - 0x0000003FFFFFF000ULL, - 0xFFFFFFE0000003FFULL, - 0x0000001FFFFFFC00ULL, - 0xFFFFFFF0000000FFULL, /* 56 */ - 0x0000000FFFFFFF00ULL, - 0xFFFFFFF80000003FULL, - 0x00000007FFFFFFC0ULL, - 0xFFFFFFFC0000000FULL, - 0x00000003FFFFFFF0ULL, - 0xFFFFFFFE00000003ULL, - 0x00000001FFFFFFFCULL, -}; - -static const uint64_t b64_pattern_se[PATTERN_INPUTS_64_COUNT] = { - 0xFFFFFFFFFFFFFFFFULL, /* 0 */ - 0x0000000000000000ULL, - 0xFFFFFFFFAAAAAAAAULL, - 0x0000000055555555ULL, - 0xFFFFFFFFCCCCCCCCULL, - 0x0000000033333333ULL, - 0xFFFFFFFFE38E38E3ULL, - 0x000000001C71C71CULL, - 0xFFFFFFFFF0F0F0F0ULL, /* 8 */ - 0x000000000F0F0F0FULL, - 0xFFFFFFFFF83E0F83ULL, - 0x0000000007C1F07CULL, - 0xFFFFFFFFFC0FC0FCULL, - 0x0000000003F03F03ULL, - 0xFFFFFFFFFE03F80FULL, - 0x0000000001FC07F0ULL, - 0xFFFFFFFFFF00FF00ULL, /* 16 */ - 0x0000000000FF00FFULL, - 0xFFFFFFFFFF803FE0ULL, - 0x00000000007FC01FULL, - 0xFFFFFFFFFFC00FFCULL, - 0x00000000003FF003ULL, - 0xFFFFFFFFFFE003FFULL, - 0x00000000001FFC00ULL, - 0xFFFFFFFFFFF000FFULL, /* 24 */ - 0x00000000000FFF00ULL, - 0xFFFFFFFFFFF8003FULL, - 0x000000000007FFC0ULL, - 0xFFFFFFFFFFFC000FULL, - 0x000000000003FFF0ULL, - 0xFFFFFFFFFFFE0003ULL, - 0x000000000001FFFCULL, - 0xFFFFFFFFFFFF0000ULL, /* 32 */ - 0x000000000000FFFFULL, - 0xFFFFFFFFFFFF8000ULL, - 0x0000000000007FFFULL, - 0xFFFFFFFFFFFFC000ULL, - 0x0000000000003FFFULL, - 0xFFFFFFFFFFFFE000ULL, - 0x0000000000001FFFULL, - 0xFFFFFFFFFFFFF000ULL, /* 40 */ - 0x0000000000000FFFULL, - 0xFFFFFFFFFFFFF800ULL, - 0x00000000000007FFULL, - 0xFFFFFFFFFFFFFC00ULL, - 0x00000000000003FFULL, - 0xFFFFFFFFFFFFFE00ULL, - 0x00000000000001FFULL, - 0xFFFFFFFFFFFFFF00ULL, /* 48 */ - 0x00000000000000FFULL, - 0xFFFFFFFFFFFFFF80ULL, - 0x000000000000007FULL, - 0xFFFFFFFFFFFFFFC0ULL, - 0x000000000000003FULL, - 0xFFFFFFFFFFFFFFE0ULL, - 0x000000000000001FULL, - 0xFFFFFFFFFFFFFFF0ULL, /* 56 */ - 0x000000000000000FULL, - 0xFFFFFFFFFFFFFFF8ULL, - 0x0000000000000007ULL, - 0xFFFFFFFFFFFFFFFCULL, - 0x0000000000000003ULL, - 0xFFFFFFFFFFFFFFFEULL, - 0x0000000000000001ULL, -}; - - -#define RANDOM_INPUTS_64_COUNT 16 -#define RANDOM_INPUTS_64_SHORT_COUNT 4 - -static const uint64_t b64_random[RANDOM_INPUTS_64_COUNT] = { - 0x886AE6CC28625540ULL, /* 0 */ - 0xFBBE00634D93C708ULL, - 0xAC5AAEAAB9CF8B80ULL, - 0x704F164D5E31E24EULL, - 0xB9926B7C7DAF4258ULL, - 0xD027BE89FF0A2EF9ULL, - 0xB83B580665CABC4AULL, - 0xFC8F23F09AA6B782ULL, - 0x201E09CD56AEE649ULL, /* 8 */ - 0xA57CD91365D9E5D7ULL, - 0xA2E8F6F5C9CBC61BULL, - 0xA89CF2F131A864AEULL, - 0xE61438E9A652EA0AULL, - 0x944A35FD192361A8ULL, - 0x4630426322BEF79CULL, - 0x8B5AA7A2F259DEADULL, -}; - -static const uint64_t b64_random_se[RANDOM_INPUTS_64_COUNT] = { - 0xFFFFFFFF886AE6CCULL, /* 0 */ - 0xFFFFFFFFFBBE0063ULL, - 0xFFFFFFFFAC5AAEAAULL, - 0x00000000704F164DULL, - 0xFFFFFFFFB9926B7CULL, - 0xFFFFFFFFD027BE89ULL, - 0xFFFFFFFFB83B5806ULL, - 0xFFFFFFFFFC8F23F0ULL, - 0x00000000201E09CDULL, /* 8 */ - 0xFFFFFFFFA57CD913ULL, - 0xFFFFFFFFA2E8F6F5ULL, - 0xFFFFFFFFA89CF2F1ULL, - 0xFFFFFFFFE61438E9ULL, - 0xFFFFFFFF944A35FDULL, - 0x0000000046304263ULL, - 0xFFFFFFFF8B5AA7A2ULL, -}; - - -#endif diff --git a/tests/tcg/mips/include/test_utils_128.h b/tests/tcg/mips/include/test_utils_128.h deleted file mode 100644 index 0dd38684cf33..000000000000 --- a/tests/tcg/mips/include/test_utils_128.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Header file for test utilities - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef TEST_UTILS_128_H -#define TEST_UTILS_128_H - -#include -#include -#include -#include - -#define PRINT_RESULTS 0 -#define PRINT_FAILURES 0 - - -static inline int32_t check_results_128(const char *isa_ase_name, - const char *group_name, - const char *instruction_name, - const uint32_t test_count, - const double elapsed_time, - const uint64_t *b128_result, - const uint64_t *b128_expect) -{ -#if PRINT_RESULTS - uint32_t ii; - printf("\n"); - for (ii = 0; ii < test_count; ii++) { - uint64_t a, b; - memcpy(&a, (b128_result + 2 * ii), 8); - memcpy(&b, (b128_result + 2 * ii + 1), 8); - if (ii % 8 != 0) { - printf(" { 0x%016llxULL, 0x%016llxULL, },\n", a, b); - } else { - printf(" { 0x%016llxULL, 0x%016llxULL, }, /* %3d */\n", - a, b, ii); - } - } - printf("\n"); -#endif - uint32_t i; - uint32_t pass_count = 0; - uint32_t fail_count = 0; - - printf("| %-10s \t| %-20s\t| %-16s \t|", - isa_ase_name, group_name, instruction_name); - for (i = 0; i < test_count; i++) { - if ((b128_result[2 * i] == b128_expect[2 * i]) && - (b128_result[2 * i + 1] == b128_expect[2 * i + 1])) { - pass_count++; - } else { -#if PRINT_FAILURES - uint32_t ii; - uint64_t a, b; - - printf("\n"); - - printf("FAILURE for test case %d!\n", i); - - memcpy(&a, (b128_expect + 2 * i), 8); - memcpy(&b, (b128_expect + 2 * i + 1), 8); - printf("Expected result : { 0x%016llxULL, 0x%016llxULL, },\n", - a, b); - - memcpy(&a, (b128_result + 2 * i), 8); - memcpy(&b, (b128_result + 2 * i + 1), 8); - printf("Actual result : { 0x%016llxULL, 0x%016llxULL, },\n", - a, b); - - printf("\n"); -#endif - fail_count++; - } - } - - printf(" PASS: %3d \t| FAIL: %3d \t| elapsed time: %5.2f ms \t|\n", - pass_count, fail_count, elapsed_time); - - if (fail_count > 0) { - return -1; - } else { - return 0; - } -} - -#endif diff --git a/tests/tcg/mips/include/test_utils_32.h b/tests/tcg/mips/include/test_utils_32.h deleted file mode 100644 index c33990c0c544..000000000000 --- a/tests/tcg/mips/include/test_utils_32.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Header file for test utilities - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef TEST_UTILS_32_H -#define TEST_UTILS_32_H - -#include -#include -#include -#include - -#define PRINT_RESULTS 0 - - -static inline int32_t check_results_32(const char *instruction_name, - const uint32_t test_count, - const double elapsed_time, - const uint32_t *b32_result, - const uint32_t *b32_expect) -{ -#if PRINT_RESULTS - uint32_t ii; - printf("\n"); - for (ii = 0; ii < test_count; ii++) { - uint64_t a; - memcpy(&a, (b32_result + ii), 8); - if (ii % 8 != 0) { - printf(" 0x%08lxULL,\n", a); - } else { - printf(" 0x%08lxULL, /* %3d */\n", - a, ii); - } - } - printf("\n"); -#endif - uint32_t i; - uint32_t pass_count = 0; - uint32_t fail_count = 0; - - printf("%s: ", instruction_name); - for (i = 0; i < test_count; i++) { - if (b32_result[i] == b32_expect[i]) { - pass_count++; - } else { - fail_count++; - } - } - - printf("PASS: %3d FAIL: %3d elapsed time: %5.2f ms\n", - pass_count, fail_count, elapsed_time); - - if (fail_count > 0) { - return -1; - } else { - return 0; - } -} - - -#endif diff --git a/tests/tcg/mips/include/test_utils_64.h b/tests/tcg/mips/include/test_utils_64.h deleted file mode 100644 index c9609d8281f6..000000000000 --- a/tests/tcg/mips/include/test_utils_64.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Header file for test utilities - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef TEST_UTILS_64_H -#define TEST_UTILS_64_H - -#include -#include -#include -#include - -#define PRINT_RESULTS 0 - - -static inline int32_t check_results_64(const char *isa_ase_name, - const char *group_name, - const char *instruction_name, - const uint32_t test_count, - const double elapsed_time, - const uint64_t *b64_result, - const uint64_t *b64_expect) -{ -#if PRINT_RESULTS - uint32_t ii; - printf("\n"); - for (ii = 0; ii < test_count; ii++) { - uint64_t a; - memcpy(&a, (b64_result + ii), 8); - if (ii % 8 != 0) { - printf(" 0x%016llxULL,\n", a); - } else { - printf(" 0x%016llxULL, /* %3d */\n", - a, ii); - } - } - printf("\n"); -#endif - uint32_t i; - uint32_t pass_count = 0; - uint32_t fail_count = 0; - - printf("| %-10s \t| %-20s\t| %-16s \t|", - isa_ase_name, group_name, instruction_name); - for (i = 0; i < test_count; i++) { - if (b64_result[i] == b64_expect[i]) { - pass_count++; - } else { - fail_count++; - } - } - - printf(" PASS: %3d \t| FAIL: %3d \t| elapsed time: %5.2f ms \t|\n", - pass_count, fail_count, elapsed_time); - - if (fail_count > 0) { - return -1; - } else { - return 0; - } -} - - -#endif diff --git a/tests/tcg/mips/include/wrappers_mips64r6.h b/tests/tcg/mips/include/wrappers_mips64r6.h deleted file mode 100644 index d1e5edb632ed..000000000000 --- a/tests/tcg/mips/include/wrappers_mips64r6.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Header file for wrappers around MIPS64R6 instructions assembler - * invocations - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef WRAPPERS_MIPS64R6_H -#define WRAPPERS_MIPS64R6_H - - -#define DO_MIPS64R6__RD__RS(suffix, mnemonic) \ -static inline void do_mips64r6_##suffix(const void *input, \ - void *output) \ -{ \ - __asm__ volatile ( \ - "ld $t1, 0(%0)\n\t" \ - #mnemonic " $t0, $t1\n\t" \ - "sd $t0, 0(%1)\n\t" \ - : \ - : "r" (input), "r" (output) \ - : "t0", "t1", "memory" \ - ); \ -} - -DO_MIPS64R6__RD__RS(CLO, clo) -DO_MIPS64R6__RD__RS(CLZ, clz) -DO_MIPS64R6__RD__RS(DCLO, dclo) -DO_MIPS64R6__RD__RS(DCLZ, dclz) - -DO_MIPS64R6__RD__RS(BITSWAP, bitswap) -DO_MIPS64R6__RD__RS(DBITSWAP, dbitswap) - - -#define DO_MIPS64R6__RD__RS_RT(suffix, mnemonic) \ -static inline void do_mips64r6_##suffix(const void *input1, \ - const void *input2, \ - void *output) \ -{ \ - __asm__ volatile ( \ - "ld $t1, 0(%0)\n\t" \ - "ld $t2, 0(%1)\n\t" \ - #mnemonic " $t0, $t1, $t2\n\t" \ - "sd $t0, 0(%2)\n\t" \ - : \ - : "r" (input1), "r" (input2), "r" (output) \ - : "t0", "t1", "memory" \ - ); \ -} - -DO_MIPS64R6__RD__RS_RT(SLLV, sllv) -DO_MIPS64R6__RD__RS_RT(SRLV, srlv) -DO_MIPS64R6__RD__RS_RT(SRAV, srav) -DO_MIPS64R6__RD__RS_RT(DSLLV, dsllv) -DO_MIPS64R6__RD__RS_RT(DSRLV, dsrlv) -DO_MIPS64R6__RD__RS_RT(DSRAV, dsrav) - -DO_MIPS64R6__RD__RS_RT(MUL, mul) -DO_MIPS64R6__RD__RS_RT(MUH, muh) -DO_MIPS64R6__RD__RS_RT(MULU, mulu) -DO_MIPS64R6__RD__RS_RT(MUHU, muhu) -DO_MIPS64R6__RD__RS_RT(DMUL, dmul) -DO_MIPS64R6__RD__RS_RT(DMUH, dmuh) -DO_MIPS64R6__RD__RS_RT(DMULU, dmulu) -DO_MIPS64R6__RD__RS_RT(DMUHU, dmuhu) - - -#endif diff --git a/tests/tcg/mips/include/wrappers_msa.h b/tests/tcg/mips/include/wrappers_msa.h deleted file mode 100644 index 4be7821ece68..000000000000 --- a/tests/tcg/mips/include/wrappers_msa.h +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Header file for wrappers around MSA instructions assembler invocations - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#ifndef WRAPPERS_MSA_H -#define WRAPPERS_MSA_H - - -#define RESET_MSA_REGISTER(wi) \ - __asm__ volatile ( \ - "xor.v $" #wi ", $" #wi ", $" #wi "\n\t" \ - : \ - : \ - : \ - ) - - -static inline void reset_msa_registers() -{ - - RESET_MSA_REGISTER(w0); - RESET_MSA_REGISTER(w1); - RESET_MSA_REGISTER(w2); - RESET_MSA_REGISTER(w3); - RESET_MSA_REGISTER(w4); - RESET_MSA_REGISTER(w5); - RESET_MSA_REGISTER(w6); - RESET_MSA_REGISTER(w7); - RESET_MSA_REGISTER(w8); - RESET_MSA_REGISTER(w9); - RESET_MSA_REGISTER(w10); - RESET_MSA_REGISTER(w11); - RESET_MSA_REGISTER(w12); - RESET_MSA_REGISTER(w13); - RESET_MSA_REGISTER(w14); - RESET_MSA_REGISTER(w15); - RESET_MSA_REGISTER(w16); - RESET_MSA_REGISTER(w17); - RESET_MSA_REGISTER(w18); - RESET_MSA_REGISTER(w19); - RESET_MSA_REGISTER(w20); - RESET_MSA_REGISTER(w21); - RESET_MSA_REGISTER(w22); - RESET_MSA_REGISTER(w23); - RESET_MSA_REGISTER(w24); - RESET_MSA_REGISTER(w25); - RESET_MSA_REGISTER(w26); - RESET_MSA_REGISTER(w27); - RESET_MSA_REGISTER(w28); - RESET_MSA_REGISTER(w29); - RESET_MSA_REGISTER(w30); - RESET_MSA_REGISTER(w31); - -} - - -#define DO_MSA__WD__WS(suffix, mnemonic) \ -static inline void do_msa_##suffix(const void *input, \ - const void *output) \ -{ \ - __asm__ volatile ( \ - "move $t0, %0\n\t" \ - "ld.d $w11, 0($t0)\n\t" \ - #mnemonic " $w10, $w11\n\t" \ - "move $t0, %1\n\t" \ - "st.d $w10, 0($t0)\n\t" \ - : \ - : "r" (input), "r" (output) \ - : "t0", "memory" \ - ); \ -} - -#define DO_MSA__WD__WD(suffix, mnemonic) \ -static inline void do_msa_##suffix(const void *input, \ - const void *output) \ -{ \ - __asm__ volatile ( \ - "move $t0, %0\n\t" \ - "ld.d $w11, 0($t0)\n\t" \ - #mnemonic " $w10, $w10\n\t" \ - "move $t0, %1\n\t" \ - "st.d $w10, 0($t0)\n\t" \ - : \ - : "r" (input), "r" (output) \ - : "t0", "memory" \ - ); \ -} - - -#define DO_MSA__WD__WS_WT(suffix, mnemonic) \ -static inline void do_msa_##suffix(const void *input1, \ - const void *input2, \ - const void *output) \ -{ \ - __asm__ volatile ( \ - "move $t0, %0\n\t" \ - "ld.d $w11, 0($t0)\n\t" \ - "move $t0, %1\n\t" \ - "ld.d $w12, 0($t0)\n\t" \ - #mnemonic " $w10, $w11, $w12\n\t" \ - "move $t0, %2\n\t" \ - "st.d $w10, 0($t0)\n\t" \ - : \ - : "r" (input1), "r" (input2), "r" (output) \ - : "t0", "memory" \ - ); \ -} - -#define DO_MSA__WD__WD_WT(suffix, mnemonic) \ -static inline void do_msa_##suffix(const void *input1, \ - const void *input2, \ - const void *output) \ -{ \ - __asm__ volatile ( \ - "move $t0, %0\n\t" \ - "ld.d $w11, 0($t0)\n\t" \ - "move $t0, %1\n\t" \ - "ld.d $w12, 0($t0)\n\t" \ - #mnemonic " $w10, $w10, $w12\n\t" \ - "move $t0, %2\n\t" \ - "st.d $w10, 0($t0)\n\t" \ - : \ - : "r" (input1), "r" (input2), "r" (output) \ - : "t0", "memory" \ - ); \ -} - -#define DO_MSA__WD__WS_WD(suffix, mnemonic) \ -static inline void do_msa_##suffix(const void *input1, \ - const void *input2, \ - const void *output) \ -{ \ - __asm__ volatile ( \ - "move $t0, %0\n\t" \ - "ld.d $w11, 0($t0)\n\t" \ - "move $t0, %1\n\t" \ - "ld.d $w12, 0($t0)\n\t" \ - #mnemonic " $w10, $w11, $w10\n\t" \ - "move $t0, %2\n\t" \ - "st.d $w10, 0($t0)\n\t" \ - : \ - : "r" (input1), "r" (input2), "r" (output) \ - : "t0", "memory" \ - ); \ -} - - -/* - * Bit Count - * --------- - */ - -DO_MSA__WD__WS(NLOC_B, nloc.b) -DO_MSA__WD__WS(NLOC_H, nloc.h) -DO_MSA__WD__WS(NLOC_W, nloc.w) -DO_MSA__WD__WS(NLOC_D, nloc.d) - -DO_MSA__WD__WS(NLZC_B, nlzc.b) -DO_MSA__WD__WS(NLZC_H, nlzc.h) -DO_MSA__WD__WS(NLZC_W, nlzc.w) -DO_MSA__WD__WS(NLZC_D, nlzc.d) - -DO_MSA__WD__WS(PCNT_B, pcnt.b) -DO_MSA__WD__WS(PCNT_H, pcnt.h) -DO_MSA__WD__WS(PCNT_W, pcnt.w) -DO_MSA__WD__WS(PCNT_D, pcnt.d) - - -/* - * Bit move - * -------- - */ - -DO_MSA__WD__WS_WT(BINSL_B, binsl.b) -DO_MSA__WD__WD_WT(BINSL_B__DDT, binsl.b) -DO_MSA__WD__WS_WD(BINSL_B__DSD, binsl.b) -DO_MSA__WD__WS_WT(BINSL_H, binsl.h) -DO_MSA__WD__WD_WT(BINSL_H__DDT, binsl.h) -DO_MSA__WD__WS_WD(BINSL_H__DSD, binsl.h) -DO_MSA__WD__WS_WT(BINSL_W, binsl.w) -DO_MSA__WD__WD_WT(BINSL_W__DDT, binsl.w) -DO_MSA__WD__WS_WD(BINSL_W__DSD, binsl.w) -DO_MSA__WD__WS_WT(BINSL_D, binsl.d) -DO_MSA__WD__WD_WT(BINSL_D__DDT, binsl.d) -DO_MSA__WD__WS_WD(BINSL_D__DSD, binsl.d) - -DO_MSA__WD__WS_WT(BINSR_B, binsr.b) -DO_MSA__WD__WD_WT(BINSR_B__DDT, binsr.b) -DO_MSA__WD__WS_WD(BINSR_B__DSD, binsr.b) -DO_MSA__WD__WS_WT(BINSR_H, binsr.h) -DO_MSA__WD__WD_WT(BINSR_H__DDT, binsr.h) -DO_MSA__WD__WS_WD(BINSR_H__DSD, binsr.h) -DO_MSA__WD__WS_WT(BINSR_W, binsr.w) -DO_MSA__WD__WD_WT(BINSR_W__DDT, binsr.w) -DO_MSA__WD__WS_WD(BINSR_W__DSD, binsr.w) -DO_MSA__WD__WS_WT(BINSR_D, binsr.d) -DO_MSA__WD__WD_WT(BINSR_D__DDT, binsr.d) -DO_MSA__WD__WS_WD(BINSR_D__DSD, binsr.d) - -DO_MSA__WD__WS_WT(BMNZ_V, bmnz.v) -DO_MSA__WD__WD_WT(BMNZ_V__DDT, bmnz.v) -DO_MSA__WD__WS_WD(BMNZ_V__DSD, bmnz.v) -DO_MSA__WD__WS_WT(BMZ_V, bmz.v) -DO_MSA__WD__WD_WT(BMZ_V__DDT, bmz.v) -DO_MSA__WD__WS_WD(BMZ_V__DSD, bmz.v) -DO_MSA__WD__WS_WT(BSEL_V, bsel.v) -DO_MSA__WD__WD_WT(BSEL_V__DDT, bsel.v) -DO_MSA__WD__WS_WD(BSEL_V__DSD, bsel.v) - - -/* - * Bit Set - * ------- - */ - -DO_MSA__WD__WS_WT(BCLR_B, bclr.b) -DO_MSA__WD__WS_WT(BCLR_H, bclr.h) -DO_MSA__WD__WS_WT(BCLR_W, bclr.w) -DO_MSA__WD__WS_WT(BCLR_D, bclr.d) - -DO_MSA__WD__WS_WT(BSET_B, bset.b) -DO_MSA__WD__WS_WT(BSET_H, bset.h) -DO_MSA__WD__WS_WT(BSET_W, bset.w) -DO_MSA__WD__WS_WT(BSET_D, bset.d) - -DO_MSA__WD__WS_WT(BNEG_B, bneg.b) -DO_MSA__WD__WS_WT(BNEG_H, bneg.h) -DO_MSA__WD__WS_WT(BNEG_W, bneg.w) -DO_MSA__WD__WS_WT(BNEG_D, bneg.d) - - -/* - * Fixed Multiply - * -------------- - */ - -DO_MSA__WD__WS_WT(MADD_Q_H, madd_q.h) -DO_MSA__WD__WD_WT(MADD_Q_H__DDT, madd_q.h) -DO_MSA__WD__WS_WD(MADD_Q_H__DSD, madd_q.h) -DO_MSA__WD__WS_WT(MADD_Q_W, madd_q.w) -DO_MSA__WD__WD_WT(MADD_Q_W__DDT, madd_q.w) -DO_MSA__WD__WS_WD(MADD_Q_W__DSD, madd_q.w) - -DO_MSA__WD__WS_WT(MADDR_Q_H, maddr_q.h) -DO_MSA__WD__WD_WT(MADDR_Q_H__DDT, maddr_q.h) -DO_MSA__WD__WS_WD(MADDR_Q_H__DSD, maddr_q.h) -DO_MSA__WD__WS_WT(MADDR_Q_W, maddr_q.w) -DO_MSA__WD__WD_WT(MADDR_Q_W__DDT, maddr_q.w) -DO_MSA__WD__WS_WD(MADDR_Q_W__DSD, maddr_q.w) - -DO_MSA__WD__WS_WT(MSUB_Q_H, msub_q.h) -DO_MSA__WD__WD_WT(MSUB_Q_H__DDT, msub_q.h) -DO_MSA__WD__WS_WD(MSUB_Q_H__DSD, msub_q.h) -DO_MSA__WD__WS_WT(MSUB_Q_W, msub_q.w) -DO_MSA__WD__WD_WT(MSUB_Q_W__DDT, msub_q.w) -DO_MSA__WD__WS_WD(MSUB_Q_W__DSD, msub_q.w) - -DO_MSA__WD__WS_WT(MSUBR_Q_H, msubr_q.h) -DO_MSA__WD__WD_WT(MSUBR_Q_H__DDT, msubr_q.h) -DO_MSA__WD__WS_WD(MSUBR_Q_H__DSD, msubr_q.h) -DO_MSA__WD__WS_WT(MSUBR_Q_W, msubr_q.w) -DO_MSA__WD__WD_WT(MSUBR_Q_W__DDT, msubr_q.w) -DO_MSA__WD__WS_WD(MSUBR_Q_W__DSD, msubr_q.w) - -DO_MSA__WD__WS_WT(MUL_Q_H, mul_q.h) -DO_MSA__WD__WS_WT(MUL_Q_W, mul_q.w) - -DO_MSA__WD__WS_WT(MULR_Q_H, mulr_q.h) -DO_MSA__WD__WS_WT(MULR_Q_W, mulr_q.w) - - -/* - * Float Max Min - * ------------- - */ - -DO_MSA__WD__WS_WT(FMAX_W, fmax.w) -DO_MSA__WD__WS_WT(FMAX_D, fmax.d) - -DO_MSA__WD__WS_WT(FMAX_A_W, fmax_a.w) -DO_MSA__WD__WS_WT(FMAX_A_D, fmax_a.d) - -DO_MSA__WD__WS_WT(FMIN_W, fmin.w) -DO_MSA__WD__WS_WT(FMIN_D, fmin.d) - -DO_MSA__WD__WS_WT(FMIN_A_W, fmin_a.w) -DO_MSA__WD__WS_WT(FMIN_A_D, fmin_a.d) - - -/* - * Int Add - * ------- - */ - -DO_MSA__WD__WS_WT(ADD_A_B, add_a.b) -DO_MSA__WD__WS_WT(ADD_A_H, add_a.h) -DO_MSA__WD__WS_WT(ADD_A_W, add_a.w) -DO_MSA__WD__WS_WT(ADD_A_D, add_a.d) - -DO_MSA__WD__WS_WT(ADDS_A_B, adds_a.b) -DO_MSA__WD__WS_WT(ADDS_A_H, adds_a.h) -DO_MSA__WD__WS_WT(ADDS_A_W, adds_a.w) -DO_MSA__WD__WS_WT(ADDS_A_D, adds_a.d) - -DO_MSA__WD__WS_WT(ADDS_S_B, adds_s.b) -DO_MSA__WD__WS_WT(ADDS_S_H, adds_s.h) -DO_MSA__WD__WS_WT(ADDS_S_W, adds_s.w) -DO_MSA__WD__WS_WT(ADDS_S_D, adds_s.d) - -DO_MSA__WD__WS_WT(ADDS_U_B, adds_u.b) -DO_MSA__WD__WS_WT(ADDS_U_H, adds_u.h) -DO_MSA__WD__WS_WT(ADDS_U_W, adds_u.w) -DO_MSA__WD__WS_WT(ADDS_U_D, adds_u.d) - -DO_MSA__WD__WS_WT(ADDV_B, addv.b) -DO_MSA__WD__WS_WT(ADDV_H, addv.h) -DO_MSA__WD__WS_WT(ADDV_W, addv.w) -DO_MSA__WD__WS_WT(ADDV_D, addv.d) - -DO_MSA__WD__WS_WT(HADD_S_H, hadd_s.h) -DO_MSA__WD__WS_WT(HADD_S_W, hadd_s.w) -DO_MSA__WD__WS_WT(HADD_S_D, hadd_s.d) - -DO_MSA__WD__WS_WT(HADD_U_H, hadd_u.h) -DO_MSA__WD__WS_WT(HADD_U_W, hadd_u.w) -DO_MSA__WD__WS_WT(HADD_U_D, hadd_u.d) - - -/* - * Int Average - * ----------- - */ - -DO_MSA__WD__WS_WT(AVE_S_B, ave_s.b) -DO_MSA__WD__WS_WT(AVE_S_H, ave_s.h) -DO_MSA__WD__WS_WT(AVE_S_W, ave_s.w) -DO_MSA__WD__WS_WT(AVE_S_D, ave_s.d) - -DO_MSA__WD__WS_WT(AVE_U_B, ave_u.b) -DO_MSA__WD__WS_WT(AVE_U_H, ave_u.h) -DO_MSA__WD__WS_WT(AVE_U_W, ave_u.w) -DO_MSA__WD__WS_WT(AVE_U_D, ave_u.d) - -DO_MSA__WD__WS_WT(AVER_S_B, aver_s.b) -DO_MSA__WD__WS_WT(AVER_S_H, aver_s.h) -DO_MSA__WD__WS_WT(AVER_S_W, aver_s.w) -DO_MSA__WD__WS_WT(AVER_S_D, aver_s.d) - -DO_MSA__WD__WS_WT(AVER_U_B, aver_u.b) -DO_MSA__WD__WS_WT(AVER_U_H, aver_u.h) -DO_MSA__WD__WS_WT(AVER_U_W, aver_u.w) -DO_MSA__WD__WS_WT(AVER_U_D, aver_u.d) - - -/* - * Int Compare - * ----------- - */ - -DO_MSA__WD__WS_WT(CEQ_B, ceq.b) -DO_MSA__WD__WS_WT(CEQ_H, ceq.h) -DO_MSA__WD__WS_WT(CEQ_W, ceq.w) -DO_MSA__WD__WS_WT(CEQ_D, ceq.d) - -DO_MSA__WD__WS_WT(CLE_S_B, cle_s.b) -DO_MSA__WD__WS_WT(CLE_S_H, cle_s.h) -DO_MSA__WD__WS_WT(CLE_S_W, cle_s.w) -DO_MSA__WD__WS_WT(CLE_S_D, cle_s.d) - -DO_MSA__WD__WS_WT(CLE_U_B, cle_u.b) -DO_MSA__WD__WS_WT(CLE_U_H, cle_u.h) -DO_MSA__WD__WS_WT(CLE_U_W, cle_u.w) -DO_MSA__WD__WS_WT(CLE_U_D, cle_u.d) - -DO_MSA__WD__WS_WT(CLT_S_B, clt_s.b) -DO_MSA__WD__WS_WT(CLT_S_H, clt_s.h) -DO_MSA__WD__WS_WT(CLT_S_W, clt_s.w) -DO_MSA__WD__WS_WT(CLT_S_D, clt_s.d) - -DO_MSA__WD__WS_WT(CLT_U_B, clt_u.b) -DO_MSA__WD__WS_WT(CLT_U_H, clt_u.h) -DO_MSA__WD__WS_WT(CLT_U_W, clt_u.w) -DO_MSA__WD__WS_WT(CLT_U_D, clt_u.d) - - -/* - * Int Divide - * ---------- - */ - -DO_MSA__WD__WS_WT(DIV_S_B, div_s.b) -DO_MSA__WD__WS_WT(DIV_S_H, div_s.h) -DO_MSA__WD__WS_WT(DIV_S_W, div_s.w) -DO_MSA__WD__WS_WT(DIV_S_D, div_s.d) - -DO_MSA__WD__WS_WT(DIV_U_B, div_u.b) -DO_MSA__WD__WS_WT(DIV_U_H, div_u.h) -DO_MSA__WD__WS_WT(DIV_U_W, div_u.w) -DO_MSA__WD__WS_WT(DIV_U_D, div_u.d) - - -/* - * Int Dot Product - * --------------- - */ - -DO_MSA__WD__WS_WT(DOTP_S_H, dotp_s.h) -DO_MSA__WD__WS_WT(DOTP_S_W, dotp_s.w) -DO_MSA__WD__WS_WT(DOTP_S_D, dotp_s.d) - -DO_MSA__WD__WS_WT(DOTP_U_H, dotp_u.h) -DO_MSA__WD__WS_WT(DOTP_U_W, dotp_u.w) -DO_MSA__WD__WS_WT(DOTP_U_D, dotp_u.d) - -DO_MSA__WD__WS_WT(DPADD_S_H, dpadd_s.h) -DO_MSA__WD__WD_WT(DPADD_S_H__DDT, dpadd_s.h) -DO_MSA__WD__WS_WD(DPADD_S_H__DSD, dpadd_s.h) -DO_MSA__WD__WS_WT(DPADD_S_W, dpadd_s.w) -DO_MSA__WD__WD_WT(DPADD_S_W__DDT, dpadd_s.w) -DO_MSA__WD__WS_WD(DPADD_S_W__DSD, dpadd_s.w) -DO_MSA__WD__WS_WT(DPADD_S_D, dpadd_s.d) -DO_MSA__WD__WD_WT(DPADD_S_D__DDT, dpadd_s.d) -DO_MSA__WD__WS_WD(DPADD_S_D__DSD, dpadd_s.d) - -DO_MSA__WD__WS_WT(DPADD_U_H, dpadd_u.h) -DO_MSA__WD__WD_WT(DPADD_U_H__DDT, dpadd_u.h) -DO_MSA__WD__WS_WD(DPADD_U_H__DSD, dpadd_u.h) -DO_MSA__WD__WS_WT(DPADD_U_W, dpadd_u.w) -DO_MSA__WD__WD_WT(DPADD_U_W__DDT, dpadd_u.w) -DO_MSA__WD__WS_WD(DPADD_U_W__DSD, dpadd_u.w) -DO_MSA__WD__WS_WT(DPADD_U_D, dpadd_u.d) -DO_MSA__WD__WD_WT(DPADD_U_D__DDT, dpadd_u.d) -DO_MSA__WD__WS_WD(DPADD_U_D__DSD, dpadd_u.d) - -DO_MSA__WD__WS_WT(DPSUB_S_H, dpsub_s.h) -DO_MSA__WD__WD_WT(DPSUB_S_H__DDT, dpsub_s.h) -DO_MSA__WD__WS_WD(DPSUB_S_H__DSD, dpsub_s.h) -DO_MSA__WD__WS_WT(DPSUB_S_W, dpsub_s.w) -DO_MSA__WD__WD_WT(DPSUB_S_W__DDT, dpsub_s.w) -DO_MSA__WD__WS_WD(DPSUB_S_W__DSD, dpsub_s.w) -DO_MSA__WD__WS_WT(DPSUB_S_D, dpsub_s.d) -DO_MSA__WD__WD_WT(DPSUB_S_D__DDT, dpsub_s.d) -DO_MSA__WD__WS_WD(DPSUB_S_D__DSD, dpsub_s.d) - -DO_MSA__WD__WS_WT(DPSUB_U_H, dpsub_u.h) -DO_MSA__WD__WD_WT(DPSUB_U_H__DDT, dpsub_u.h) -DO_MSA__WD__WS_WD(DPSUB_U_H__DSD, dpsub_u.h) -DO_MSA__WD__WS_WT(DPSUB_U_W, dpsub_u.w) -DO_MSA__WD__WD_WT(DPSUB_U_W__DDT, dpsub_u.w) -DO_MSA__WD__WS_WD(DPSUB_U_W__DSD, dpsub_u.w) -DO_MSA__WD__WS_WT(DPSUB_U_D, dpsub_u.d) -DO_MSA__WD__WD_WT(DPSUB_U_D__DDT, dpsub_u.d) -DO_MSA__WD__WS_WD(DPSUB_U_D__DSD, dpsub_u.d) - - -/* - * Int Max Min - * ----------- - */ - -DO_MSA__WD__WS_WT(MAX_A_B, max_a.b) -DO_MSA__WD__WS_WT(MAX_A_H, max_a.h) -DO_MSA__WD__WS_WT(MAX_A_W, max_a.w) -DO_MSA__WD__WS_WT(MAX_A_D, max_a.d) - -DO_MSA__WD__WS_WT(MAX_S_B, max_s.b) -DO_MSA__WD__WS_WT(MAX_S_H, max_s.h) -DO_MSA__WD__WS_WT(MAX_S_W, max_s.w) -DO_MSA__WD__WS_WT(MAX_S_D, max_s.d) - -DO_MSA__WD__WS_WT(MAX_U_B, max_u.b) -DO_MSA__WD__WS_WT(MAX_U_H, max_u.h) -DO_MSA__WD__WS_WT(MAX_U_W, max_u.w) -DO_MSA__WD__WS_WT(MAX_U_D, max_u.d) - -DO_MSA__WD__WS_WT(MIN_A_B, min_a.b) -DO_MSA__WD__WS_WT(MIN_A_H, min_a.h) -DO_MSA__WD__WS_WT(MIN_A_W, min_a.w) -DO_MSA__WD__WS_WT(MIN_A_D, min_a.d) - -DO_MSA__WD__WS_WT(MIN_S_B, min_s.b) -DO_MSA__WD__WS_WT(MIN_S_H, min_s.h) -DO_MSA__WD__WS_WT(MIN_S_W, min_s.w) -DO_MSA__WD__WS_WT(MIN_S_D, min_s.d) - -DO_MSA__WD__WS_WT(MIN_U_B, min_u.b) -DO_MSA__WD__WS_WT(MIN_U_H, min_u.h) -DO_MSA__WD__WS_WT(MIN_U_W, min_u.w) -DO_MSA__WD__WS_WT(MIN_U_D, min_u.d) - - -/* - * Int Modulo - * ---------- - */ - -DO_MSA__WD__WS_WT(MOD_S_B, mod_s.b) -DO_MSA__WD__WS_WT(MOD_S_H, mod_s.h) -DO_MSA__WD__WS_WT(MOD_S_W, mod_s.w) -DO_MSA__WD__WS_WT(MOD_S_D, mod_s.d) - -DO_MSA__WD__WS_WT(MOD_U_B, mod_u.b) -DO_MSA__WD__WS_WT(MOD_U_H, mod_u.h) -DO_MSA__WD__WS_WT(MOD_U_W, mod_u.w) -DO_MSA__WD__WS_WT(MOD_U_D, mod_u.d) - - -/* - * Int Multiply - * ------------ - */ - -DO_MSA__WD__WS_WT(MADDV_B, maddv.b) -DO_MSA__WD__WD_WT(MADDV_B__DDT, maddv.b) -DO_MSA__WD__WS_WD(MADDV_B__DSD, maddv.b) -DO_MSA__WD__WS_WT(MADDV_H, maddv.h) -DO_MSA__WD__WD_WT(MADDV_H__DDT, maddv.h) -DO_MSA__WD__WS_WD(MADDV_H__DSD, maddv.h) -DO_MSA__WD__WS_WT(MADDV_W, maddv.w) -DO_MSA__WD__WD_WT(MADDV_W__DDT, maddv.w) -DO_MSA__WD__WS_WD(MADDV_W__DSD, maddv.w) -DO_MSA__WD__WS_WT(MADDV_D, maddv.d) -DO_MSA__WD__WD_WT(MADDV_D__DDT, maddv.d) -DO_MSA__WD__WS_WD(MADDV_D__DSD, maddv.d) - -DO_MSA__WD__WS_WT(MSUBV_B, msubv.b) -DO_MSA__WD__WD_WT(MSUBV_B__DDT, msubv.b) -DO_MSA__WD__WS_WD(MSUBV_B__DSD, msubv.b) -DO_MSA__WD__WS_WT(MSUBV_H, msubv.h) -DO_MSA__WD__WD_WT(MSUBV_H__DDT, msubv.h) -DO_MSA__WD__WS_WD(MSUBV_H__DSD, msubv.h) -DO_MSA__WD__WS_WT(MSUBV_W, msubv.w) -DO_MSA__WD__WD_WT(MSUBV_W__DDT, msubv.w) -DO_MSA__WD__WS_WD(MSUBV_W__DSD, msubv.w) -DO_MSA__WD__WS_WT(MSUBV_D, msubv.d) -DO_MSA__WD__WD_WT(MSUBV_D__DDT, msubv.d) -DO_MSA__WD__WS_WD(MSUBV_D__DSD, msubv.d) - -DO_MSA__WD__WS_WT(MULV_B, mulv.b) -DO_MSA__WD__WS_WT(MULV_H, mulv.h) -DO_MSA__WD__WS_WT(MULV_W, mulv.w) -DO_MSA__WD__WS_WT(MULV_D, mulv.d) - - -/* - * Int Subtract - * ------------ - */ - -DO_MSA__WD__WS_WT(ASUB_S_B, asub_s.b) -DO_MSA__WD__WS_WT(ASUB_S_H, asub_s.h) -DO_MSA__WD__WS_WT(ASUB_S_W, asub_s.w) -DO_MSA__WD__WS_WT(ASUB_S_D, asub_s.d) - -DO_MSA__WD__WS_WT(ASUB_U_B, asub_u.b) -DO_MSA__WD__WS_WT(ASUB_U_H, asub_u.h) -DO_MSA__WD__WS_WT(ASUB_U_W, asub_u.w) -DO_MSA__WD__WS_WT(ASUB_U_D, asub_u.d) - -DO_MSA__WD__WS_WT(HSUB_S_H, hsub_s.h) -DO_MSA__WD__WS_WT(HSUB_S_W, hsub_s.w) -DO_MSA__WD__WS_WT(HSUB_S_D, hsub_s.d) - -DO_MSA__WD__WS_WT(HSUB_U_H, hsub_u.h) -DO_MSA__WD__WS_WT(HSUB_U_W, hsub_u.w) -DO_MSA__WD__WS_WT(HSUB_U_D, hsub_u.d) - -DO_MSA__WD__WS_WT(SUBS_S_B, subs_s.b) -DO_MSA__WD__WS_WT(SUBS_S_H, subs_s.h) -DO_MSA__WD__WS_WT(SUBS_S_W, subs_s.w) -DO_MSA__WD__WS_WT(SUBS_S_D, subs_s.d) - -DO_MSA__WD__WS_WT(SUBS_U_B, subs_u.b) -DO_MSA__WD__WS_WT(SUBS_U_H, subs_u.h) -DO_MSA__WD__WS_WT(SUBS_U_W, subs_u.w) -DO_MSA__WD__WS_WT(SUBS_U_D, subs_u.d) - -DO_MSA__WD__WS_WT(SUBSUS_U_B, subsus_u.b) -DO_MSA__WD__WS_WT(SUBSUS_U_H, subsus_u.h) -DO_MSA__WD__WS_WT(SUBSUS_U_W, subsus_u.w) -DO_MSA__WD__WS_WT(SUBSUS_U_D, subsus_u.d) - -DO_MSA__WD__WS_WT(SUBSUU_S_B, subsuu_s.b) -DO_MSA__WD__WS_WT(SUBSUU_S_H, subsuu_s.h) -DO_MSA__WD__WS_WT(SUBSUU_S_W, subsuu_s.w) -DO_MSA__WD__WS_WT(SUBSUU_S_D, subsuu_s.d) - -DO_MSA__WD__WS_WT(SUBV_B, subv.b) -DO_MSA__WD__WS_WT(SUBV_H, subv.h) -DO_MSA__WD__WS_WT(SUBV_W, subv.w) -DO_MSA__WD__WS_WT(SUBV_D, subv.d) - - -/* - * Interleave - * ---------- - */ - -DO_MSA__WD__WS_WT(ILVEV_B, ilvev.b) -DO_MSA__WD__WS_WT(ILVEV_H, ilvev.h) -DO_MSA__WD__WS_WT(ILVEV_W, ilvev.w) -DO_MSA__WD__WS_WT(ILVEV_D, ilvev.d) - -DO_MSA__WD__WS_WT(ILVOD_B, ilvod.b) -DO_MSA__WD__WS_WT(ILVOD_H, ilvod.h) -DO_MSA__WD__WS_WT(ILVOD_W, ilvod.w) -DO_MSA__WD__WS_WT(ILVOD_D, ilvod.d) - -DO_MSA__WD__WS_WT(ILVL_B, ilvl.b) -DO_MSA__WD__WS_WT(ILVL_H, ilvl.h) -DO_MSA__WD__WS_WT(ILVL_W, ilvl.w) -DO_MSA__WD__WS_WT(ILVL_D, ilvl.d) - -DO_MSA__WD__WS_WT(ILVR_B, ilvr.b) -DO_MSA__WD__WS_WT(ILVR_H, ilvr.h) -DO_MSA__WD__WS_WT(ILVR_W, ilvr.w) -DO_MSA__WD__WS_WT(ILVR_D, ilvr.d) - - -/* - * Logic - * ----- - */ - -DO_MSA__WD__WS_WT(AND_V, and.v) -DO_MSA__WD__WS_WT(NOR_V, nor.v) -DO_MSA__WD__WS_WT(OR_V, or.v) -DO_MSA__WD__WS_WT(XOR_V, xor.v) - - -/* - * Move - * ---- - */ - -DO_MSA__WD__WS(MOVE_V, move.v) - - -/* - * Pack - * ---- - */ - -DO_MSA__WD__WS_WT(PCKEV_B, pckev.b) -DO_MSA__WD__WD_WT(PCKEV_B__DDT, pckev.b) -DO_MSA__WD__WS_WD(PCKEV_B__DSD, pckev.b) -DO_MSA__WD__WS_WT(PCKEV_H, pckev.h) -DO_MSA__WD__WD_WT(PCKEV_H__DDT, pckev.h) -DO_MSA__WD__WS_WD(PCKEV_H__DSD, pckev.h) -DO_MSA__WD__WS_WT(PCKEV_W, pckev.w) -DO_MSA__WD__WD_WT(PCKEV_W__DDT, pckev.w) -DO_MSA__WD__WS_WD(PCKEV_W__DSD, pckev.w) -DO_MSA__WD__WS_WT(PCKEV_D, pckev.d) -DO_MSA__WD__WD_WT(PCKEV_D__DDT, pckev.d) -DO_MSA__WD__WS_WD(PCKEV_D__DSD, pckev.d) - -DO_MSA__WD__WS_WT(PCKOD_B, pckod.b) -DO_MSA__WD__WD_WT(PCKOD_B__DDT, pckod.b) -DO_MSA__WD__WS_WD(PCKOD_B__DSD, pckod.b) -DO_MSA__WD__WS_WT(PCKOD_H, pckod.h) -DO_MSA__WD__WD_WT(PCKOD_H__DDT, pckod.h) -DO_MSA__WD__WS_WD(PCKOD_H__DSD, pckod.h) -DO_MSA__WD__WS_WT(PCKOD_W, pckod.w) -DO_MSA__WD__WD_WT(PCKOD_W__DDT, pckod.w) -DO_MSA__WD__WS_WD(PCKOD_W__DSD, pckod.w) -DO_MSA__WD__WS_WT(PCKOD_D, pckod.d) -DO_MSA__WD__WD_WT(PCKOD_D__DDT, pckod.d) -DO_MSA__WD__WS_WD(PCKOD_D__DSD, pckod.d) - -DO_MSA__WD__WS_WT(VSHF_B, vshf.b) -DO_MSA__WD__WD_WT(VSHF_B__DDT, vshf.b) -DO_MSA__WD__WS_WD(VSHF_B__DSD, vshf.b) -DO_MSA__WD__WS_WT(VSHF_H, vshf.h) -DO_MSA__WD__WD_WT(VSHF_H__DDT, vshf.h) -DO_MSA__WD__WS_WD(VSHF_H__DSD, vshf.h) -DO_MSA__WD__WS_WT(VSHF_W, vshf.w) -DO_MSA__WD__WD_WT(VSHF_W__DDT, vshf.w) -DO_MSA__WD__WS_WD(VSHF_W__DSD, vshf.w) -DO_MSA__WD__WS_WT(VSHF_D, vshf.d) -DO_MSA__WD__WD_WT(VSHF_D__DDT, vshf.d) -DO_MSA__WD__WS_WD(VSHF_D__DSD, vshf.d) - - -/* - * Shift - * ----- - */ - -DO_MSA__WD__WS_WT(SLL_B, sll.b) -DO_MSA__WD__WS_WT(SLL_H, sll.h) -DO_MSA__WD__WS_WT(SLL_W, sll.w) -DO_MSA__WD__WS_WT(SLL_D, sll.d) - -DO_MSA__WD__WS_WT(SRA_B, sra.b) -DO_MSA__WD__WS_WT(SRA_H, sra.h) -DO_MSA__WD__WS_WT(SRA_W, sra.w) -DO_MSA__WD__WS_WT(SRA_D, sra.d) - -DO_MSA__WD__WS_WT(SRAR_B, srar.b) -DO_MSA__WD__WS_WT(SRAR_H, srar.h) -DO_MSA__WD__WS_WT(SRAR_W, srar.w) -DO_MSA__WD__WS_WT(SRAR_D, srar.d) - -DO_MSA__WD__WS_WT(SRL_B, srl.b) -DO_MSA__WD__WS_WT(SRL_H, srl.h) -DO_MSA__WD__WS_WT(SRL_W, srl.w) -DO_MSA__WD__WS_WT(SRL_D, srl.d) - -DO_MSA__WD__WS_WT(SRLR_B, srlr.b) -DO_MSA__WD__WS_WT(SRLR_H, srlr.h) -DO_MSA__WD__WS_WT(SRLR_W, srlr.w) -DO_MSA__WD__WS_WT(SRLR_D, srlr.d) - - -#endif diff --git a/tests/tcg/mips/user/ase/dsp/Makefile b/tests/tcg/mips/user/ase/dsp/Makefile deleted file mode 100644 index 5c6da96870e1..000000000000 --- a/tests/tcg/mips/user/ase/dsp/Makefile +++ /dev/null @@ -1,184 +0,0 @@ --include ../../../../config-host.mak - -CROSS=mips64el-unknown-linux-gnu- - -SIM=qemu-mipsel -SIM_FLAGS=-cpu 74Kf - -CC = $(CROSS)gcc -CFLAGS = -EL -mabi=32 -march=mips32r2 -mgp32 -mdsp -mdspr2 -static - -TESTCASES = test_dsp_r1_absq_s_ph.tst -TESTCASES += test_dsp_r1_absq_s_w.tst -TESTCASES += test_dsp_r1_addq_ph.tst -TESTCASES += test_dsp_r1_addq_s_ph.tst -TESTCASES += test_dsp_r1_addq_s_w.tst -TESTCASES += test_dsp_r1_addsc.tst -TESTCASES += test_dsp_r1_addu_qb.tst -TESTCASES += test_dsp_r1_addu_s_qb.tst -TESTCASES += test_dsp_r1_addwc.tst -TESTCASES += test_dsp_r1_bitrev.tst -TESTCASES += test_dsp_r1_bposge32.tst -TESTCASES += test_dsp_r1_cmp_eq_ph.tst -TESTCASES += test_dsp_r1_cmpgu_eq_qb.tst -TESTCASES += test_dsp_r1_cmpgu_le_qb.tst -TESTCASES += test_dsp_r1_cmpgu_lt_qb.tst -TESTCASES += test_dsp_r1_cmp_le_ph.tst -TESTCASES += test_dsp_r1_cmp_lt_ph.tst -TESTCASES += test_dsp_r1_cmpu_eq_qb.tst -TESTCASES += test_dsp_r1_cmpu_le_qb.tst -TESTCASES += test_dsp_r1_cmpu_lt_qb.tst -TESTCASES += test_dsp_r1_dpaq_sa_l_w.tst -TESTCASES += test_dsp_r1_dpaq_s_w_ph.tst -TESTCASES += test_dsp_r1_dpau_h_qbl.tst -TESTCASES += test_dsp_r1_dpau_h_qbr.tst -TESTCASES += test_dsp_r1_dpsq_sa_l_w.tst -TESTCASES += test_dsp_r1_dpsq_s_w_ph.tst -TESTCASES += test_dsp_r1_dpsu_h_qbl.tst -TESTCASES += test_dsp_r1_dpsu_h_qbr.tst -TESTCASES += test_dsp_r1_extp.tst -TESTCASES += test_dsp_r1_extpdp.tst -TESTCASES += test_dsp_r1_extpdpv.tst -TESTCASES += test_dsp_r1_extpv.tst -TESTCASES += test_dsp_r1_extr_rs_w.tst -TESTCASES += test_dsp_r1_extr_r_w.tst -TESTCASES += test_dsp_r1_extr_s_h.tst -TESTCASES += test_dsp_r1_extrv_rs_w.tst -TESTCASES += test_dsp_r1_extrv_r_w.tst -TESTCASES += test_dsp_r1_extrv_s_h.tst -TESTCASES += test_dsp_r1_extrv_w.tst -TESTCASES += test_dsp_r1_extr_w.tst -TESTCASES += test_dsp_r1_insv.tst -TESTCASES += test_dsp_r1_lbux.tst -TESTCASES += test_dsp_r1_lhx.tst -TESTCASES += test_dsp_r1_lwx.tst -TESTCASES += test_dsp_r1_madd.tst -TESTCASES += test_dsp_r1_maddu.tst -TESTCASES += test_dsp_r1_maq_sa_w_phl.tst -TESTCASES += test_dsp_r1_maq_sa_w_phr.tst -TESTCASES += test_dsp_r1_maq_s_w_phl.tst -TESTCASES += test_dsp_r1_maq_s_w_phr.tst -TESTCASES += test_dsp_r1_mfhi.tst -TESTCASES += test_dsp_r1_mflo.tst -TESTCASES += test_dsp_r1_modsub.tst -TESTCASES += test_dsp_r1_msub.tst -TESTCASES += test_dsp_r1_msubu.tst -TESTCASES += test_dsp_r1_mthi.tst -TESTCASES += test_dsp_r1_mthlip.tst -TESTCASES += test_dsp_r1_mtlo.tst -TESTCASES += test_dsp_r1_muleq_s_w_phl.tst -TESTCASES += test_dsp_r1_muleq_s_w_phr.tst -TESTCASES += test_dsp_r1_muleu_s_ph_qbl.tst -TESTCASES += test_dsp_r1_muleu_s_ph_qbr.tst -TESTCASES += test_dsp_r1_mulq_rs_ph.tst -TESTCASES += test_dsp_r1_mult.tst -TESTCASES += test_dsp_r1_multu.tst -TESTCASES += test_dsp_r1_packrl_ph.tst -TESTCASES += test_dsp_r1_pick_ph.tst -TESTCASES += test_dsp_r1_pick_qb.tst -TESTCASES += test_dsp_r1_precequ_ph_qbla.tst -TESTCASES += test_dsp_r1_precequ_ph_qbl.tst -TESTCASES += test_dsp_r1_precequ_ph_qbra.tst -TESTCASES += test_dsp_r1_precequ_ph_qbr.tst -TESTCASES += test_dsp_r1_preceq_w_phl.tst -TESTCASES += test_dsp_r1_preceq_w_phr.tst -TESTCASES += test_dsp_r1_preceu_ph_qbla.tst -TESTCASES += test_dsp_r1_preceu_ph_qbl.tst -TESTCASES += test_dsp_r1_preceu_ph_qbra.tst -TESTCASES += test_dsp_r1_preceu_ph_qbr.tst -TESTCASES += test_dsp_r1_precrq_ph_w.tst -TESTCASES += test_dsp_r1_precrq_qb_ph.tst -TESTCASES += test_dsp_r1_precrq_rs_ph_w.tst -TESTCASES += test_dsp_r1_precrqu_s_qb_ph.tst -TESTCASES += test_dsp_r1_raddu_w_qb.tst -TESTCASES += test_dsp_r1_rddsp.tst -TESTCASES += test_dsp_r1_repl_ph.tst -TESTCASES += test_dsp_r1_repl_qb.tst -TESTCASES += test_dsp_r1_replv_ph.tst -TESTCASES += test_dsp_r1_replv_qb.tst -TESTCASES += test_dsp_r1_shilo.tst -TESTCASES += test_dsp_r1_shilov.tst -TESTCASES += test_dsp_r1_shll_ph.tst -TESTCASES += test_dsp_r1_shll_qb.tst -TESTCASES += test_dsp_r1_shll_s_ph.tst -TESTCASES += test_dsp_r1_shll_s_w.tst -TESTCASES += test_dsp_r1_shllv_ph.tst -TESTCASES += test_dsp_r1_shllv_qb.tst -TESTCASES += test_dsp_r1_shllv_s_ph.tst -TESTCASES += test_dsp_r1_shllv_s_w.tst -TESTCASES += test_dsp_r1_shra_ph.tst -TESTCASES += test_dsp_r1_shra_r_ph.tst -TESTCASES += test_dsp_r1_shra_r_w.tst -TESTCASES += test_dsp_r1_shrav_ph.tst -TESTCASES += test_dsp_r1_shrav_r_ph.tst -TESTCASES += test_dsp_r1_shrav_r_w.tst -TESTCASES += test_dsp_r1_shrl_qb.tst -TESTCASES += test_dsp_r1_shrlv_qb.tst -TESTCASES += test_dsp_r1_subq_ph.tst -TESTCASES += test_dsp_r1_subq_s_ph.tst -TESTCASES += test_dsp_r1_subq_s_w.tst -TESTCASES += test_dsp_r1_subu_qb.tst -TESTCASES += test_dsp_r1_subu_s_qb.tst -TESTCASES += test_dsp_r1_wrdsp.tst -TESTCASES += test_dsp_r2_absq_s_qb.tst -TESTCASES += test_dsp_r2_addqh_ph.tst -TESTCASES += test_dsp_r2_addqh_r_ph.tst -TESTCASES += test_dsp_r2_addqh_r_w.tst -TESTCASES += test_dsp_r2_addqh_w.tst -TESTCASES += test_dsp_r2_adduh_qb.tst -TESTCASES += test_dsp_r2_adduh_r_qb.tst -TESTCASES += test_dsp_r2_addu_ph.tst -TESTCASES += test_dsp_r2_addu_s_ph.tst -TESTCASES += test_dsp_r2_append.tst -TESTCASES += test_dsp_r2_balign.tst -TESTCASES += test_dsp_r2_cmpgdu_eq_qb.tst -TESTCASES += test_dsp_r2_cmpgdu_le_qb.tst -TESTCASES += test_dsp_r2_cmpgdu_lt_qb.tst -TESTCASES += test_dsp_r2_dpaqx_sa_w_ph.tst -TESTCASES += test_dsp_r2_dpa_w_ph.tst -TESTCASES += test_dsp_r2_dpax_w_ph.tst -TESTCASES += test_dsp_r2_dpaqx_s_w_ph.tst -TESTCASES += test_dsp_r2_dpsqx_sa_w_ph.tst -TESTCASES += test_dsp_r2_dpsqx_s_w_ph.tst -TESTCASES += test_dsp_r2_dps_w_ph.tst -TESTCASES += test_dsp_r2_dpsx_w_ph.tst -TESTCASES += test_dsp_r2_mul_ph.tst -TESTCASES += test_dsp_r2_mulq_rs_w.tst -TESTCASES += test_dsp_r2_mulq_s_ph.tst -TESTCASES += test_dsp_r2_mulq_s_w.tst -TESTCASES += test_dsp_r2_mulsaq_s_w_ph.tst -TESTCASES += test_dsp_r2_mulsa_w_ph.tst -TESTCASES += test_dsp_r2_mul_s_ph.tst -TESTCASES += test_dsp_r2_precr_qb_ph.tst -TESTCASES += test_dsp_r2_precr_sra_ph_w.tst -TESTCASES += test_dsp_r2_precr_sra_r_ph_w.tst -TESTCASES += test_dsp_r2_prepend.tst -TESTCASES += test_dsp_r2_shra_qb.tst -TESTCASES += test_dsp_r2_shra_r_qb.tst -TESTCASES += test_dsp_r2_shrav_qb.tst -TESTCASES += test_dsp_r2_shrav_r_qb.tst -TESTCASES += test_dsp_r2_shrl_ph.tst -TESTCASES += test_dsp_r2_shrlv_ph.tst -TESTCASES += test_dsp_r2_subqh_ph.tst -TESTCASES += test_dsp_r2_subqh_r_ph.tst -TESTCASES += test_dsp_r2_subqh_r_w.tst -TESTCASES += test_dsp_r2_subqh_w.tst -TESTCASES += test_dsp_r2_subuh_qb.tst -TESTCASES += test_dsp_r2_subuh_r_qb.tst -TESTCASES += test_dsp_r2_subu_ph.tst -TESTCASES += test_dsp_r2_subu_s_ph.tst - - -all: $(TESTCASES) - -%.tst: %.c - $(CC) $(CFLAGS) $< -o $@ - -check: $(TESTCASES) - @for case in $(TESTCASES); do \ - echo $(SIM) $(SIM_FLAGS) ./$$case;\ - $(SIM) $(SIM_FLAGS) ./$$case; \ - done - -clean: - $(RM) -rf $(TESTCASES) diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_absq_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_absq_s_ph.c deleted file mode 100644 index aa8411202e20..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_absq_s_ph.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - - -int main() -{ - int rd, rt; - int result; - - rt = 0x10017EFD; - result = 0x10017EFD; - - __asm - ("absq_s.ph %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x8000A536; - result = 0x7FFF5ACA; - - __asm - ("absq_s.ph %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_absq_s_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_absq_s_w.c deleted file mode 100644 index 3f52a48039cd..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_absq_s_w.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x80000000; - result = 0x7FFFFFFF; - __asm - ("absq_s.w %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x80030000; - result = 0x7FFD0000; - __asm - ("absq_s.w %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x31036080; - result = 0x31036080; - __asm - ("absq_s.w %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_ph.c deleted file mode 100644 index 96a549637b41..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_ph.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0xFFFFFFFF; - rt = 0x10101010; - result = 0x100F100F; - __asm - ("addq.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - rs = 0x3712847D; - rt = 0x0031AF2D; - result = 0x374333AA; - __asm - ("addq.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - rs = 0x7fff847D; - rt = 0x0031AF2D; - result = 0x803033AA; - __asm - ("addq.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - __asm("rddsp %0\n\t" - : "=r"(dsp) - ); - assert(((dsp >> 20) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_s_ph.c deleted file mode 100644 index 5f865f6cffd5..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_s_ph.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0xFFFFFFFF; - rt = 0x10101010; - result = 0x100F100F; - __asm - ("addq_s.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - rs = 0x3712847D; - rt = 0x0031AF2D; - result = 0x37438000; - __asm - ("addq_s.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - __asm - ("rddsp %0\n\t" - : "=r"(dsp) - ); - assert(((dsp >> 20) & 0x01) == 1); - - rs = 0x7fff847D; - rt = 0x0031AF2D; - result = 0x7fff8000; - __asm - ("addq_s.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - __asm - ("rddsp %0\n\t" - : "=r"(dsp) - ); - assert(((dsp >> 20) & 0x01) == 1); - - rs = 0x8030847D; - rt = 0x8a00AF2D; - result = 0x80008000; - __asm - ("addq_s.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - __asm - ("rddsp %0\n\t" - : "=r"(dsp) - ); - assert(((dsp >> 20) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_s_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_s_w.c deleted file mode 100644 index 1e13acf68fb9..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addq_s_w.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - - -int main() -{ - int rd, rs, rt; - int result; - - rt = 0x10017EFD; - rs = 0x11111111; - result = 0x2112900e; - - __asm - ("addq_s.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rt = 0x80017EFD; - rs = 0x81111111; - result = 0x80000000; - - __asm - ("addq_s.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rt = 0x7fffffff; - rs = 0x01111111; - result = 0x7fffffff; - - __asm - ("addq_s.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addsc.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addsc.c deleted file mode 100644 index ace749f667c4..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addsc.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x0000000F; - rt = 0x00000001; - result = 0x00000010; - __asm - ("addsc %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0xFFFF0FFF; - rt = 0x00010111; - result = 0x00001110; - __asm - ("addsc %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 13) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addu_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addu_qb.c deleted file mode 100644 index 23ba2e90d1c9..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addu_qb.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x00FF00FF; - rt = 0x00010001; - result = 0x00000000; - __asm - ("addu.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 20) & 0x01) == 1); - - rs = 0xFFFF1111; - rt = 0x00020001; - result = 0xFF011112; - __asm - ("addu.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 20) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addu_s_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addu_s_qb.c deleted file mode 100644 index fe7fd3e6aa2d..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addu_s_qb.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x10FF01FF; - rt = 0x10010001; - result = 0x20FF01FF; - __asm - ("addu_s.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 20) & 0x1) == 1); - - rs = 0xFFFF1111; - rt = 0x00020001; - result = 0xFFFF1112; - __asm - ("addu_s.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 20) & 0x1) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addwc.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addwc.c deleted file mode 100644 index 8a8d81fab4ca..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_addwc.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dspi, dspo; - int result; - - rs = 0x10FF01FF; - rt = 0x10010001; - dspi = 0x00002000; - result = 0x21000201; - __asm - ("wrdsp %3\n" - "addwc %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dspi) - ); - assert(rd == result); - - rs = 0xFFFF1111; - rt = 0x00020001; - dspi = 0x00; - result = 0x00011112; - __asm - ("wrdsp %3\n" - "addwc %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dspi) - ); - assert(rd == result); - - rs = 0x8FFF1111; - rt = 0x80020001; - dspi = 0x00; - result = 0x10011112; - __asm - ("wrdsp %4\n" - "addwc %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dspo) - : "r"(rs), "r"(rt), "r"(dspi) - ); - assert(rd == result); - assert(((dspo >> 20) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_bitrev.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_bitrev.c deleted file mode 100644 index 04d8a3844eb8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_bitrev.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x00001E6A; - - __asm - ("bitrev %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_bposge32.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_bposge32.c deleted file mode 100644 index d25417ea77b2..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_bposge32.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -int main() -{ - int dsp, sum; - int result; - - dsp = 0x20; - sum = 0x01; - result = 0x02; - - __asm - ("wrdsp %1\n\t" - "bposge32 test1\n\t" - "nop\n\t" - "addi %0, 0xA2\n\t" - "nop\n\t" - "test1:\n\t" - "addi %0, 0x01\n\t" - : "+r"(sum) - : "r"(dsp) - ); - assert(sum == result); - - dsp = 0x10; - sum = 0x01; - result = 0xA4; - - __asm - ("wrdsp %1\n\t" - "bposge32 test2\n\t" - "nop\n\t" - "addi %0, 0xA2\n\t" - "nop\n\t" - "test2:\n\t" - "addi %0, 0x01\n\t" - : "+r"(sum) - : "r"(dsp) - ); - assert(sum == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_eq_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_eq_ph.c deleted file mode 100644 index 957bd88ce01f..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_eq_ph.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x11777066; - rt = 0x55AA33FF; - result = 0x00; - __asm - ("cmp.eq.ph %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - rd = (rd >> 24) & 0x03; - assert(rd == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x03; - __asm - ("cmp.eq.ph %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - rd = (rd >> 24) & 0x03; - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_le_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_le_ph.c deleted file mode 100644 index 356f156c5d1f..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_le_ph.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x11777066; - rt = 0x55AA33FF; - result = 0x02; - __asm - ("cmp.le.ph %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - rd = (rd >> 24) & 0x03; - assert(rd == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x03; - __asm - ("cmp.le.ph %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - rd = (rd >> 24) & 0x03; - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_lt_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_lt_ph.c deleted file mode 100644 index 3fb4827ad761..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmp_lt_ph.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x11777066; - rt = 0x55AA33FF; - result = 0x02; - __asm - ("cmp.lt.ph %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - rd = (rd >> 24) & 0x03; - assert(rd == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x00; - __asm - ("cmp.lt.ph %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - rd = (rd >> 24) & 0x03; - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_eq_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_eq_qb.c deleted file mode 100644 index 2615c84c75c7..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_eq_qb.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x02; - __asm - ("cmpgu.eq.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x0F; - __asm - ("cmpgu.eq.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_le_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_le_qb.c deleted file mode 100644 index 65d0813c3b19..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_le_qb.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x0F; - __asm - ("cmpgu.le.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - rs = 0x11777066; - rt = 0x11766066; - result = 0x09; - __asm - ("cmpgu.le.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_lt_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_lt_qb.c deleted file mode 100644 index 7dddad98532c..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpgu_lt_qb.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x0D; - __asm - ("cmpgu.lt.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - rs = 0x11777066; - rt = 0x11766066; - result = 0x00; - __asm - ("cmpgu.lt.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_eq_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_eq_qb.c deleted file mode 100644 index 680f2a1999d8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_eq_qb.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int dsp; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x02; - __asm - ("cmpu.eq.qb %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(dsp == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x0F; - __asm - ("cmpu.eq.qb %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(dsp == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_le_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_le_qb.c deleted file mode 100644 index 43cfa509ca3c..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_le_qb.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int dsp; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x0F; - __asm - ("cmpu.le.qb %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(dsp == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x0F; - __asm - ("cmpu.le.qb %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(dsp == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_lt_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_lt_qb.c deleted file mode 100644 index 074ca5b402de..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_cmpu_lt_qb.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int dsp; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x0D; - __asm - ("cmpu.lt.qb %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(dsp == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x00; - __asm - ("cmpu.lt.qb %1, %2\n\t" - "rddsp %0\n\t" - : "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(dsp == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpaq_s_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpaq_s_w_ph.c deleted file mode 100644 index a6425b6edc84..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpaq_s_w_ph.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach = 0, acl = 0; - int resulth, resultl, resultdsp; - - rs = 0x800000FF; - rt = 0x80000002; - resulth = 0x00; - resultl = 0x800003FB; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaq_s.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = dsp >> 17 & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpaq_sa_l_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpaq_sa_l_w.c deleted file mode 100644 index cbf900713f33..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpaq_sa_l_w.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach = 0, acl = 0; - int resulth, resultl, resultdsp; - - rs = 0x80000000; - rt = 0x80000000; - resulth = 0x7FFFFFFF; - resultl = 0xFFFFFFFF; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x00000012; - acl = 0x00000048; - rs = 0x80000000; - rt = 0x80000000; - - resulth = 0x7FFFFFFF; - resultl = 0xFFFFFFFF; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x741532A0; - acl = 0xFCEABB08; - rs = 0x80000000; - rt = 0x80000000; - - resulth = 0x7FFFFFFF; - resultl = 0xFFFFFFFF; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0; - acl = 0; - rs = 0xC0000000; - rt = 0x7FFFFFFF; - - resulth = 0xC0000000; - resultl = 0x80000000; - resultdsp = 0; - __asm - ("wrdsp $0\n\t" - "mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x20000000; - acl = 0; - rs = 0xE0000000; - rt = 0x7FFFFFFF; - - resulth = 0; - resultl = 0x40000000; - resultdsp = 0; - __asm - ("wrdsp $0\n\t" - "mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpau_h_qbl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpau_h_qbl.c deleted file mode 100644 index 6017b5e73ab2..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpau_h_qbl.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 3; - int resulth, resultl; - - rs = 0x800000FF; - rt = 0x80000002; - resulth = 0x05; - resultl = 0x4003; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpau.h.qbl $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpau_h_qbr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpau_h_qbr.c deleted file mode 100644 index e4abb2e2af03..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpau_h_qbr.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 3; - int resulth, resultl; - - rs = 0x800000FF; - rt = 0x80000002; - resulth = 0x05; - resultl = 0x0201; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpau.h.qbr $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsq_s_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsq_s_w_ph.c deleted file mode 100644 index 74058fe7ecd0..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsq_s_w_ph.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x00000004; - resultl = 0xF15F94A3; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsq_s.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x1424EF1F; - acl = 0x1035219A; - rs = 0x800083AD; - rt = 0x80003721; - resulth = 0x1424EF1E; - resultl = 0xC5C0D901; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsq_s.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsq_sa_l_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsq_sa_l_w.c deleted file mode 100644 index eda3b14e2be2..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsq_sa_l_w.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach = 5, acl = 5; - int resulth, resultl, resultdsp; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x00BD3A22; - resultl = 0xD138776B; - resultdsp = 0x00; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x54321123; - acl = 5; - rs = 0x80000000; - rt = 0x80000000; - - resulth = 0xd4321123; - resultl = 0x06; - resultdsp = 0x01; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsq_sa.l.w $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsu_h_qbl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsu_h_qbl.c deleted file mode 100644 index 94e2bf625499..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsu_h_qbl.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x04; - resultl = 0xFFFFFEE5; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsu.h.qbl $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsu_h_qbr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsu_h_qbr.c deleted file mode 100644 index a1e66356310d..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_dpsu_h_qbr.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x04; - resultl = 0xFFFFE233; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsu.h.qbr $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extp.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extp.c deleted file mode 100644 index b18bdb34c872..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extp.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -int main() -{ - int rt, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - result = 0x000C; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extp %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 14) & 0x01; - assert(dsp == 0); - assert(result == rt); - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x01; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extp %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 14) & 0x01; - assert(dsp == 1); - - ach = 0; - acl = 0x80000001; - dsp = 0x1F; - result = 0x80000001; - - __asm - ("wrdsp %1\n\t" - "mthi %2, $ac2\n\t" - "mtlo %3, $ac2\n\t" - "extp %0, $ac2, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 14) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpdp.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpdp.c deleted file mode 100644 index 79ee16e8b87c..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpdp.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include - -int main() -{ - int rt, ach, acl, dsp, pos, efi; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - result = 0x000C; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpdp %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl) - ); - pos = dsp & 0x3F; - efi = (dsp >> 14) & 0x01; - assert(pos == 3); - assert(efi == 0); - assert(result == rt); - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x01; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpdp %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl) - ); - efi = (dsp >> 14) & 0x01; - assert(efi == 1); - - - ach = 0; - acl = 0; - dsp = 0; - result = 0; - - __asm - ("wrdsp %1\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpdp %0, $ac1, 0x00\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl) - ); - assert(dsp == 0x3F); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpdpv.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpdpv.c deleted file mode 100644 index f5774eed3cae..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpdpv.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs, ach, acl, dsp, pos, efi; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - rs = 0x03; - result = 0x000C; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpdpv %0, $ac1, %4\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl), "r"(rs) - ); - pos = dsp & 0x3F; - efi = (dsp >> 14) & 0x01; - assert(pos == 3); - assert(efi == 0); - assert(result == rt); - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x01; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpdpv %0, $ac1, %4\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl), "r"(rs) - ); - efi = (dsp >> 14) & 0x01; - assert(efi == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpv.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpv.c deleted file mode 100644 index 401b94afadfc..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extpv.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -int main() -{ - int rt, ac, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - ac = 0x03; - result = 0x000C; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpv %0, $ac1, %4\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl), "r"(ac) - ); - dsp = (dsp >> 14) & 0x01; - assert(dsp == 0); - assert(result == rt); - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x01; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extpv %0, $ac1, %4\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(ach), "r"(acl), "r"(ac) - ); - dsp = (dsp >> 14) & 0x01; - assert(dsp == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_r_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_r_w.c deleted file mode 100644 index 489c1931b475..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_r_w.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include - -int main() -{ - int rt, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - result = 0xA0001699; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_r.w %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x01; - acl = 0xB4CB; - result = 0x10000B4D; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_r.w %0, $ac1, 0x04\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x3fffffff; - acl = 0x2bcdef01; - result = 0x7ffffffe; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_r.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0xFFFFFFFF; - acl = 0xFFFFFFFF; - result = 0; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_r.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_rs_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_rs_w.c deleted file mode 100644 index f9d2ed646fa3..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_rs_w.c +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include - -int main() -{ - int rt, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - result = 0x7FFFFFFF; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_rs.w %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x01; - acl = 0xB4CB; - result = 0x10000B4D; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_rs.w %0, $ac1, 0x04\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x3fffffff; - acl = 0x2bcdef01; - result = 0x7ffffffe; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_rs.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x80000000; - acl = 0x00000000; - result = 0x80000000; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_rs.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0xFFFFFFFF; - acl = 0xFFFFFFFF; - result = 0; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_rs.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_s_h.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_s_h.c deleted file mode 100644 index 9bc2a63cc2d1..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_s_h.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include - -int main() -{ - int rt, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - result = 0x00007FFF; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_s.h %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - ach = 0xffffffff; - acl = 0x12344321; - result = 0xFFFF8000; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_s.h %0, $ac1, 0x08\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dsp */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x00; - acl = 0x4321; - result = 0x432; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_s.h %0, $ac1, 0x04\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dsp */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x123; - acl = 0x87654321; - result = 0x1238; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr_s.h %0, $ac1, 28\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_w.c deleted file mode 100644 index cf926146d54c..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extr_w.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include - -int main() -{ - int rt, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - result = 0xA0001699; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr.w %0, $ac1, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x01; - acl = 0xB4CB; - result = 0x10000B4C; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr.w %0, $ac1, 0x04\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0x3fffffff; - acl = 0x2bcdef01; - result = 0x7ffffffe; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - ach = 0xFFFFFFFF; - acl = 0xFFFFFFFF; - result = 0xFFFFFFFF; - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "extr.w %0, $ac1, 0x1F\n\t" - "rddsp %1\n\t" - : "=r"(rt), "=r"(dsp) - : "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_r_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_r_w.c deleted file mode 100644 index 2403b3afe40f..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_r_w.c +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - rs = 0x03; - result = 0xA0001699; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_r.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 4; - ach = 0x01; - acl = 0xB4CB; - result = 0x10000B4D; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_r.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 31; - ach = 0x3fffffff; - acl = 0x2bcdef01; - result = 0x7ffffffe; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_r.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_rs_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_rs_w.c deleted file mode 100644 index ccceeb9f4ce9..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_rs_w.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs, ach, acl, dsp; - int result; - - rs = 0x03; - ach = 0x05; - acl = 0xB4CB; - result = 0x7FFFFFFF; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_rs.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 0x04; - ach = 0x01; - acl = 0xB4CB; - result = 0x10000B4D; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_rs.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 0x1F; - ach = 0x3fffffff; - acl = 0x2bcdef01; - result = 0x7ffffffe; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_rs.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_s_h.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_s_h.c deleted file mode 100644 index feac3e2e334a..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_s_h.c +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - rs = 0x03; - result = 0x00007FFF; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_s.h %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - rs = 0x08; - ach = 0xffffffff; - acl = 0x12344321; - result = 0xFFFF8000; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_s.h %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dsp */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 0x04; - ach = 0x00; - acl = 0x4321; - result = 0x432; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_s.h %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - rs = 0x1C; - ach = 0x123; - acl = 0x87654321; - result = 0x1238; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv_s.h %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_w.c deleted file mode 100644 index 9e8b238a04d4..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_extrv_w.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs, ach, acl, dsp; - int result; - - ach = 0x05; - acl = 0xB4CB; - dsp = 0x07; - rs = 0x03; - result = 0xA0001699; - - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 1); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 4; - ach = 0x01; - acl = 0xB4CB; - result = 0x10000B4C; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - /* Clear dspcontrol */ - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 31; - ach = 0x3fffffff; - acl = 0x2bcdef01; - result = 0x7ffffffe; - __asm - ("wrdsp %1, 0x01\n\t" - "mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "extrv.w %0, $ac1, %2\n\t" - "rddsp %1\n\t" - : "=r"(rt), "+r"(dsp) - : "r"(rs), "r"(ach), "r"(acl) - ); - dsp = (dsp >> 23) & 0x01; - assert(dsp == 0); - assert(result == rt); - - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_insv.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_insv.c deleted file mode 100644 index 9d674697ccaa..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_insv.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs, dsp; - int result; - - /* msb = 10, lsb = 5 */ - dsp = 0x305; - rt = 0x12345678; - rs = 0x87654321; - result = 0x12345438; - __asm - ("wrdsp %2, 0x03\n\t" - "insv %0, %1\n\t" - : "+r"(rt) - : "r"(rs), "r"(dsp) - ); - assert(rt == result); - - dsp = 0x1000; - rt = 0xF0F0F0F0; - rs = 0xA5A5A5A5; - result = 0xA5A5A5A5; - - __asm - ("wrdsp %2\n\t" - "insv %0, %1\n\t" - : "+r"(rt) - : "r"(rs), "r"(dsp) - ); - assert(rt == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lbux.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lbux.c deleted file mode 100644 index 2337abea2acb..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lbux.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main(void) -{ - int value, rd; - int *p; - unsigned long addr, index; - int result; - - value = 0xBCDEF389; - p = &value; - addr = (unsigned long)p; - index = 0; - result = value & 0xFF; - __asm - ("lbux %0, %1(%2)\n\t" - : "=r"(rd) - : "r"(index), "r"(addr) - ); - - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lhx.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lhx.c deleted file mode 100644 index 10be3b385fee..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lhx.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main(void) -{ - int value, rd; - int *p; - unsigned long addr, index; - int result; - - value = 0xBCDEF389; - p = &value; - addr = (unsigned long)p; - index = 0; - result = 0xFFFFF389; - __asm - ("lhx %0, %1(%2)\n\t" - : "=r"(rd) - : "r"(index), "r"(addr) - ); - - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lwx.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lwx.c deleted file mode 100644 index e6543c9e7eae..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_lwx.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main(void) -{ - int value, rd; - int *p; - unsigned long addr, index; - int result; - - value = 0xBCDEF389; - p = &value; - addr = (unsigned long)p; - index = 0; - result = 0xBCDEF389; - __asm - ("lwx %0, %1(%2)\n\t" - : "=r"(rd) - : "r"(index), "r"(addr) - ); - - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_madd.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_madd.c deleted file mode 100644 index af4bfcfe9df3..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_madd.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs; - int achi, acli; - int acho, aclo; - int resulth, resultl; - - achi = 0x05; - acli = 0xB4CB; - rs = 0x01; - rt = 0x01; - resulth = 0x05; - resultl = 0xB4CC; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "madd $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maddu.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maddu.c deleted file mode 100644 index af4bfcfe9df3..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maddu.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs; - int achi, acli; - int acho, aclo; - int resulth, resultl; - - achi = 0x05; - acli = 0xB4CB; - rs = 0x01; - rt = 0x01; - resulth = 0x05; - resultl = 0xB4CC; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "madd $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_main.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_main.c deleted file mode 100644 index b296b20c9254..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() -{ - printf("hello world\n"); -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_s_w_phl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_s_w_phl.c deleted file mode 100644 index 0f7c070155a8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_s_w_phl.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs; - int achi, acli; - int dsp; - int acho, aclo; - int resulth, resultl; - int resdsp; - - achi = 0x00000005; - acli = 0x0000B4CB; - rs = 0xFF060000; - rt = 0xCB000000; - resulth = 0x00000005; - resultl = 0x006838CB; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "maq_s.w.phl $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - - achi = 0x00000006; - acli = 0x0000B4CB; - rs = 0x80000000; - rt = 0x80000000; - resulth = 0x00000006; - resultl = 0x8000B4CA; - resdsp = 1; - - __asm - ("mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "maq_s.w.phl $ac1, %5, %6\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "=r"(acho), "=r"(aclo), "=r"(dsp) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - assert(((dsp >> 17) & 0x01) == resdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_s_w_phr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_s_w_phr.c deleted file mode 100644 index 942722a530c2..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_s_w_phr.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs; - int achi, acli; - int dsp; - int acho, aclo; - int resulth, resultl; - int resdsp; - - achi = 0x00000005; - acli = 0x0000B4CB; - rs = 0x0000FF06; - rt = 0x0000CB00; - resulth = 0x00000005; - resultl = 0x006838CB; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "maq_s.w.phr $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - - achi = 0x00000006; - acli = 0x0000B4CB; - rs = 0x00008000; - rt = 0x00008000; - resulth = 0x00000006; - resultl = 0x8000B4CA; - resdsp = 1; - - __asm - ("mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "maq_s.w.phr $ac1, %5, %6\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "=r"(acho), "=r"(aclo), "=r"(dsp) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - assert(((dsp >> 17) & 0x01) == resdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_sa_w_phl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_sa_w_phl.c deleted file mode 100644 index d83dce6f3272..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_sa_w_phl.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs; - int achi, acli; - int dsp; - int acho, aclo; - int resulth, resultl; - int resdsp; - - achi = 0x00000000; - acli = 0x0000B4CB; - rs = 0xFF060000; - rt = 0xCB000000; - resulth = 0x00000000; - resultl = 0x006838CB; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "maq_sa.w.phl $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - - achi = 0x00000000; - acli = 0x0000B4CB; - rs = 0x80000000; - rt = 0x80000000; - resulth = 0x00; - resultl = 0x7fffffff; - resdsp = 0x01; - - __asm - ("mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "maq_sa.w.phl $ac1, %5, %6\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "=r"(acho), "=r"(aclo), "=r"(dsp) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - assert(((dsp >> 17) & 0x01) == 0x01); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_sa_w_phr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_sa_w_phr.c deleted file mode 100644 index d2331118abb8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_maq_sa_w_phr.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rt, rs; - int achi, acli; - int dsp; - int acho, aclo; - int resulth, resultl; - int resdsp; - - achi = 0x00000000; - acli = 0x0000B4CB; - rs = 0x0000FF06; - rt = 0x0000CB00; - resulth = 0x00000000; - resultl = 0x006838CB; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "maq_sa.w.phr $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - - achi = 0x00000000; - acli = 0x0000B4CB; - rs = 0x00008000; - rt = 0x00008000; - resulth = 0x00000000; - resultl = 0x7FFFFFFF; - resdsp = 0x01; - - __asm - ("mthi %3, $ac1\n\t" - "mtlo %4, $ac1\n\t" - "maq_sa.w.phr $ac1, %5, %6\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "=r"(acho), "=r"(aclo), "=r"(dsp) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(resulth == acho); - assert(resultl == aclo); - assert(((dsp >> 17) & 0x01) == 0x01); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mfhi.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mfhi.c deleted file mode 100644 index 43a80669d1ea..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mfhi.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int achi, acho; - int result; - - achi = 0x004433; - result = 0x004433; - - __asm - ("mthi %1, $ac1\n\t" - "mfhi %0, $ac1\n\t" - : "=r"(acho) - : "r"(achi) - ); - assert(result == acho); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mflo.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mflo.c deleted file mode 100644 index caeafdb05ce4..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mflo.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int acli, aclo; - int result; - - acli = 0x004433; - result = 0x004433; - - __asm - ("mthi %1, $ac1\n\t" - "mfhi %0, $ac1\n\t" - : "=r"(aclo) - : "r"(acli) - ); - assert(result == aclo); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_modsub.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_modsub.c deleted file mode 100644 index c294eebb519d..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_modsub.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0xFFFFFFFF; - rt = 0x000000FF; - result = 0xFFFFFF00; - __asm - ("modsub %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - rs = 0x00000000; - rt = 0x00CD1FFF; - result = 0x0000CD1F; - __asm - ("modsub %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_msub.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_msub.c deleted file mode 100644 index 5779e6f47ac7..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_msub.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int achi, acli, rs, rt; - int acho, aclo; - int resulth, resultl; - - rs = 0x00BBAACC; - rt = 0x0B1C3D2F; - achi = 0x00004433; - acli = 0xFFCC0011; - resulth = 0xFFF81F29; - resultl = 0xB355089D; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "msub $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(acho == resulth); - assert(aclo == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_msubu.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_msubu.c deleted file mode 100644 index e0f9b5a77ae3..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_msubu.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int achi, acli, rs, rt; - int acho, aclo; - int resulth, resultl; - - rs = 0x00BBAACC; - rt = 0x0B1C3D2F; - achi = 0x00004433; - acli = 0xFFCC0011; - resulth = 0xFFF81F29; - resultl = 0xB355089D; - - __asm - ("mthi %2, $ac1\n\t" - "mtlo %3, $ac1\n\t" - "msubu $ac1, %4, %5\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(acho), "=r"(aclo) - : "r"(achi), "r"(acli), "r"(rs), "r"(rt) - ); - assert(acho == resulth); - assert(aclo == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mthi.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mthi.c deleted file mode 100644 index 43a80669d1ea..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mthi.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int achi, acho; - int result; - - achi = 0x004433; - result = 0x004433; - - __asm - ("mthi %1, $ac1\n\t" - "mfhi %0, $ac1\n\t" - : "=r"(acho) - : "r"(achi) - ); - assert(result == acho); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mthlip.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mthlip.c deleted file mode 100644 index 85f94d8450ea..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mthlip.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include - -int main() -{ - int rs, ach, acl, dsp; - int result, resulth, resultl; - - dsp = 0x07; - ach = 0x05; - acl = 0xB4CB; - rs = 0x00FFBBAA; - resulth = 0xB4CB; - resultl = 0x00FFBBAA; - result = 0x27; - - __asm - ("wrdsp %0, 0x01\n\t" - "mthi %1, $ac1\n\t" - "mtlo %2, $ac1\n\t" - "mthlip %3, $ac1\n\t" - "mfhi %1, $ac1\n\t" - "mflo %2, $ac1\n\t" - "rddsp %0\n\t" - : "+r"(dsp), "+r"(ach), "+r"(acl) - : "r"(rs) - ); - dsp = dsp & 0x3F; - assert(dsp == result); - assert(ach == resulth); - assert(acl == resultl); - - dsp = 0x1f; - ach = 0x05; - acl = 0xB4CB; - rs = 0x00FFBBAA; - resulth = 0xB4CB; - resultl = 0x00FFBBAA; - result = 0x3f; - - __asm - ("wrdsp %0, 0x01\n\t" - "mthi %1, $ac1\n\t" - "mtlo %2, $ac1\n\t" - "mthlip %3, $ac1\n\t" - "mfhi %1, $ac1\n\t" - "mflo %2, $ac1\n\t" - "rddsp %0\n\t" - : "+r"(dsp), "+r"(ach), "+r"(acl) - : "r"(rs) - ); - dsp = dsp & 0x3F; - assert(dsp == result); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mtlo.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mtlo.c deleted file mode 100644 index caeafdb05ce4..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mtlo.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int acli, aclo; - int result; - - acli = 0x004433; - result = 0x004433; - - __asm - ("mthi %1, $ac1\n\t" - "mfhi %0, $ac1\n\t" - : "=r"(aclo) - : "r"(acli) - ); - assert(result == aclo); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleq_s_w_phl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleq_s_w_phl.c deleted file mode 100644 index b3a5370fe59e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleq_s_w_phl.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x80001234; - rt = 0x80001234; - result = 0x7FFFFFFF; - resultdsp = 1; - - __asm - ("muleq_s.w.phl %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - rs = 0x12349988; - rt = 0x43219988; - result = 0x98be968; - resultdsp = 1; - - __asm - ("muleq_s.w.phl %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} - diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleq_s_w_phr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleq_s_w_phr.c deleted file mode 100644 index 8066d7d02a1e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleq_s_w_phr.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x8000; - rt = 0x8000; - result = 0x7FFFFFFF; - resultdsp = 1; - - __asm - ("muleq_s.w.phr %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - rs = 0x1234; - rt = 0x4321; - result = 0x98be968; - resultdsp = 1; - - __asm - ("muleq_s.w.phr %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleu_s_ph_qbl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleu_s_ph_qbl.c deleted file mode 100644 index 66a382806a21..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleu_s_ph_qbl.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x80001234; - rt = 0x80004321; - result = 0xFFFF0000; - resultdsp = 1; - - __asm - ("muleu_s.ph.qbl %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleu_s_ph_qbr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleu_s_ph_qbr.c deleted file mode 100644 index 4cc6c8f7cfe1..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_muleu_s_ph_qbr.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x8000; - rt = 0x80004321; - result = 0xFFFF0000; - resultdsp = 1; - - __asm - ("muleu_s.ph.qbr %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mulq_rs_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mulq_rs_ph.c deleted file mode 100644 index 370c2a801832..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mulq_rs_ph.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x80001234; - rt = 0x80004321; - result = 0x7FFF098C; - resultdsp = 1; - - __asm - ("wrdsp $0\n\t" - "mulq_rs.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - rs = 0x80011234; - rt = 0x80024321; - result = 0x7FFD098C; - resultdsp = 0; - - __asm - ("wrdsp $0\n\t" - "mulq_rs.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mult.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mult.c deleted file mode 100644 index 15e6fde92c0e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_mult.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, ach, acl; - int result, resulth, resultl; - - rs = 0x00FFBBAA; - rt = 0x4B231000; - resulth = 0x4b0f01; - resultl = 0x71f8a000; - __asm - ("mult $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(ach), "=r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_multu.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_multu.c deleted file mode 100644 index 85d36c1b621a..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_multu.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, ach, acl; - int result, resulth, resultl; - - rs = 0x00FFBBAA; - rt = 0x4B231000; - resulth = 0x4b0f01; - resultl = 0x71f8a000; - __asm - ("multu $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "=r"(ach), "=r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_packrl_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_packrl_ph.c deleted file mode 100644 index 1f8e69992503..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_packrl_ph.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x56788765; - - __asm - ("packrl.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_pick_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_pick_ph.c deleted file mode 100644 index 929a002e7544..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_pick_ph.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result; - - rs = 0x12345678; - rt = 0x87654321; - dsp = 0x0A000000; - result = 0x12344321; - - __asm - ("wrdsp %3, 0x10\n\t" - "pick.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dsp) - ); - assert(rd == result); - - rs = 0x12345678; - rt = 0x87654321; - dsp = 0x03000000; - result = 0x12345678; - - __asm - ("wrdsp %3, 0x10\n\t" - "pick.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dsp) - ); - assert(rd == result); - - rs = 0x12345678; - rt = 0x87654321; - dsp = 0x00000000; - result = 0x87654321; - - __asm - ("wrdsp %3, 0x10\n\t" - "pick.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dsp) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_pick_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_pick_qb.c deleted file mode 100644 index a79047524662..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_pick_qb.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result; - - rs = 0x12345678; - rt = 0x87654321; - dsp = 0x0f000000; - result = 0x12345678; - - __asm - ("wrdsp %3, 0x10\n\t" - "pick.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dsp) - ); - assert(rd == result); - - rs = 0x12345678; - rt = 0x87654321; - dsp = 0x00000000; - result = 0x87654321; - - __asm - ("wrdsp %3, 0x10\n\t" - "pick.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt), "r"(dsp) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceq_w_phl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceq_w_phl.c deleted file mode 100644 index bf70bf7d3aec..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceq_w_phl.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x87650000; - - __asm - ("preceq.w.phl %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceq_w_phr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceq_w_phr.c deleted file mode 100644 index 3f885ef584e6..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceq_w_phr.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x43210000; - - __asm - ("preceq.w.phr %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbl.c deleted file mode 100644 index 63b7a9568345..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbl.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x43803280; - - __asm - ("precequ.ph.qbl %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbla.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbla.c deleted file mode 100644 index 31627f0bd606..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbla.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x43802180; - - __asm - ("precequ.ph.qbla %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbr.c deleted file mode 100644 index b6f72d3cbfde..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbr.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x21801080; - - __asm - ("precequ.ph.qbr %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbra.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbra.c deleted file mode 100644 index 4764fd031d8a..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precequ_ph_qbra.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x32801080; - - __asm - ("precequ.ph.qbra %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbl.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbl.c deleted file mode 100644 index fa95c26cc48f..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbl.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x00870065; - - __asm - ("preceu.ph.qbl %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbla.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbla.c deleted file mode 100644 index 021f21a74440..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbla.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x00870043; - - __asm - ("preceu.ph.qbla %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbr.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbr.c deleted file mode 100644 index 03df18c72ca5..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbr.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x00430021; - - __asm - ("preceu.ph.qbr %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbra.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbra.c deleted file mode 100644 index 634327618cce..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_preceu_ph_qbra.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0x00650021; - - __asm - ("preceu.ph.qbra %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_ph_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_ph_w.c deleted file mode 100644 index 25d45f1a9aa8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_ph_w.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x12348765; - - __asm - ("precrq.ph.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_qb_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_qb_ph.c deleted file mode 100644 index fe23acce8c47..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_qb_ph.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x12568743; - - __asm - ("precrq.qb.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_rs_ph_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_rs_ph_w.c deleted file mode 100644 index da6845bf2423..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrq_rs_ph_w.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x12348765; - - __asm - ("wrdsp $0\n\t" - "precrq_rs.ph.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - rs = 0x7FFFC678; - rt = 0x865432A0; - result = 0x7FFF8654; - - __asm - ("wrdsp $0\n\t" - "precrq_rs.ph.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(((dsp >> 22) & 0x01) == 1); - assert(result == rd); - - rs = 0xBEEFFEED; - rt = 0x7FFF8000; - result = 0xBEF07FFF; - - __asm - ("wrdsp $0\n\t" - "precrq_rs.ph.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(((dsp >> 22) & 0x01) == 1); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrqu_s_qb_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrqu_s_qb_ph.c deleted file mode 100644 index 7481d5af3a5b..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_precrqu_s_qb_ph.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x12345678; - rt = 0x87657FFF; - result = 0x24AC00FF; - - __asm - ("precrqu_s.qb.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - assert(((dsp >> 22) & 0x01) == 0x01); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_raddu_w_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_raddu_w_qb.c deleted file mode 100644 index 77a983c0d20f..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_raddu_w_qb.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs; - int result; - - rs = 0x12345678; - result = 0x114; - - __asm - ("raddu.w.qb %0, %1\n\t" - : "=r"(rd) - : "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_rddsp.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_rddsp.c deleted file mode 100644 index 2f3028503324..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_rddsp.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -int main() -{ - int dsp_i, dsp_o; - int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i; - int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o; - - ccond_i = 0x0000000C; /* 4 */ - outflag_i = 0x0000001B; /* 3 */ - efi_i = 0x00000001; /* 5 */ - c_i = 0x00000001; /* 2 */ - scount_i = 0x0000000F; /* 1 */ - pos_i = 0x0000000C; /* 0 */ - - dsp_i = (ccond_i << 24) | \ - (outflag_i << 16) | \ - (efi_i << 14) | \ - (c_i << 13) | \ - (scount_i << 7) | \ - pos_i; - - __asm - ("wrdsp %1, 0x3F\n\t" - "rddsp %0, 0x3F\n\t" - : "=r"(dsp_o) - : "r"(dsp_i) - ); - - ccond_o = (dsp_o >> 24) & 0xFF; - outflag_o = (dsp_o >> 16) & 0xFF; - efi_o = (dsp_o >> 14) & 0x01; - c_o = (dsp_o >> 14) & 0x01; - scount_o = (dsp_o >> 7) & 0x3F; - pos_o = dsp_o & 0x1F; - - assert(ccond_o == ccond_i); - assert(outflag_o == outflag_i); - assert(efi_o == efi_i); - assert(c_o == c_i); - assert(scount_o == scount_i); - assert(pos_o == pos_i); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_repl_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_repl_ph.c deleted file mode 100644 index 21074953bdde..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_repl_ph.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -int main() -{ - int rd, result; - - result = 0x01BF01BF; - __asm - ("repl.ph %0, 0x1BF\n\t" - : "=r"(rd) - ); - assert(rd == result); - - result = 0x01FF01FF; - __asm - ("repl.ph %0, 0x01FF\n\t" - : "=r"(rd) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_repl_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_repl_qb.c deleted file mode 100644 index 6631393ea131..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_repl_qb.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -int main() -{ - int rd, result; - - result = 0xBFBFBFBF; - __asm - ("repl.qb %0, 0xBF\n\t" - : "=r"(rd) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_replv_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_replv_ph.c deleted file mode 100644 index 07fb15f1f795..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_replv_ph.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x56785678; - __asm - ("replv.ph %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_replv_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_replv_qb.c deleted file mode 100644 index dd1271fedff0..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_replv_qb.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x78787878; - __asm - ("replv.qb %0, %1\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shilo.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shilo.c deleted file mode 100644 index ce8ebc69c2ac..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shilo.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -int main() -{ - int ach, acl; - int resulth, resultl; - - ach = 0xBBAACCFF; - acl = 0x1C3B001D; - - resulth = 0x17755; - resultl = 0x99fe3876; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "shilo $ac1, 0x0F\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - ); - assert(ach == resulth); - assert(acl == resultl); - - - ach = 0x1; - acl = 0x80000000; - - resulth = 0x3; - resultl = 0x0; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "shilo $ac1, -1\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shilov.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shilov.c deleted file mode 100644 index e1d6cea4b6de..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shilov.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -int main() -{ - int rs, ach, acl; - int resulth, resultl; - - rs = 0x0F; - ach = 0xBBAACCFF; - acl = 0x1C3B001D; - - resulth = 0x17755; - resultl = 0x99fe3876; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "shilov $ac1, %2\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs) - ); - assert(ach == resulth); - assert(acl == resultl); - - - rs = 0xffffffff; - ach = 0x1; - acl = 0x80000000; - - resulth = 0x3; - resultl = 0x0; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "shilov $ac1, %2\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_ph.c deleted file mode 100644 index 5fa58ccf6374..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_ph.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt, dsp; - int result, resultdsp; - - rt = 0x12345678; - result = 0xA000C000; - resultdsp = 1; - - __asm - ("wrdsp $0\n\t" - "shll.ph %0, %2, 0x0B\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rt = 0x7fff8000; - result = 0xfffe0000; - resultdsp = 1; - - __asm - ("wrdsp $0\n\t" - "shll.ph %0, %2, 0x01\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rt = 0x00000001; - result = 0x00008000; - resultdsp = 1; - - __asm - ("wrdsp $0\n\t" - "shll.ph %0, %2, 0x0F\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_qb.c deleted file mode 100644 index 729716d62618..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_qb.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt, dsp; - int result, resultdsp; - - rt = 0x87654321; - result = 0x87654321; - resultdsp = 0x00; - - __asm - ("wrdsp $0\n\t" - "shll.qb %0, %2, 0x00\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rt = 0x87654321; - result = 0x38281808; - resultdsp = 0x01; - - __asm - ("wrdsp $0\n\t" - "shll.qb %0, %2, 0x03\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rt = 0x00000001; - result = 0x00000080; - resultdsp = 0x00; - - __asm - ("wrdsp $0\n\t" - "shll.qb %0, %2, 0x07\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_s_ph.c deleted file mode 100644 index 910fea3b317e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_s_ph.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt, dsp; - int result, resultdsp; - - rt = 0x12345678; - result = 0x7FFF7FFF; - resultdsp = 0x01; - - __asm - ("shll_s.ph %0, %2, 0x0B\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_s_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_s_w.c deleted file mode 100644 index 628c7521027b..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shll_s_w.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt, dsp; - int result, resultdsp; - - rt = 0x82345678; - result = 0x82345678; - resultdsp = 0x00; - - __asm - ("shll_s.w %0, %2, 0x0\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rt = 0x82345678; - result = 0x80000000; - resultdsp = 0x01; - - __asm - ("shll_s.w %0, %2, 0x0B\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rt = 0x12345678; - result = 0x7FFFFFFF; - resultdsp = 0x01; - - __asm - ("shll_s.w %0, %2, 0x0B\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_ph.c deleted file mode 100644 index f98a6322dc1d..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_ph.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x0; - rt = 0x12345678; - result = 0x12345678; - resultdsp = 0; - - __asm - ("shllv.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x0B; - rt = 0x12345678; - result = 0xA000C000; - resultdsp = 1; - - __asm - ("shllv.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_qb.c deleted file mode 100644 index 6d8ff4a259ba..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_qb.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x03; - rt = 0x87654321; - result = 0x38281808; - resultdsp = 0x01; - - __asm - ("shllv.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(rd == result); - - rs = 0x00; - rt = 0x87654321; - result = 0x87654321; - resultdsp = 0x01; - - __asm - ("shllv.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_s_ph.c deleted file mode 100644 index fc9bd32765b8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_s_ph.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x0; - rt = 0x12345678; - result = 0x12345678; - resultdsp = 0x0; - - __asm - ("shllv_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x0B; - rt = 0x12345678; - result = 0x7FFF7FFF; - resultdsp = 0x01; - - __asm - ("shllv_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_s_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_s_w.c deleted file mode 100644 index 350c25617adc..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shllv_s_w.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x0B; - rt = 0x12345678; - result = 0x7FFFFFFF; - resultdsp = 0x01; - - __asm - ("shllv_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x0; - rt = 0x12345678; - result = 0x12345678; - resultdsp = 0x01; - - __asm - ("shllv_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rt), "r"(rs) - ); - dsp = (dsp >> 22) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_ph.c deleted file mode 100644 index 5b2d840a6bc5..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_ph.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0xF0EC0864; - - __asm - ("shra.ph %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x87654321; - result = 0x87654321; - - __asm - ("shra.ph %0, %1, 0x00\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_r_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_r_ph.c deleted file mode 100644 index adc4ae68bdc3..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_r_ph.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0xF0ED0864; - - __asm - ("shra_r.ph %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x87654321; - result = 0x87654321; - - __asm - ("shra_r.ph %0, %1, 0x00\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_r_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_r_w.c deleted file mode 100644 index ec0cf2c72ccb..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shra_r_w.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x87654321; - result = 0xF0ECA864; - - __asm - ("shra_r.w %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x87654321; - result = 0x87654321; - - __asm - ("shra_r.w %0, %1, 0x0\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_ph.c deleted file mode 100644 index 6e42aaf8e1a7..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_ph.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x03; - rt = 0x87654321; - result = 0xF0EC0864; - - __asm - ("shrav.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - rs = 0x00; - rt = 0x87654321; - result = 0x87654321; - - __asm - ("shrav.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_r_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_r_ph.c deleted file mode 100644 index f03b978d0544..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_r_ph.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x03; - rt = 0x87654321; - result = 0xF0ED0864; - - __asm - ("shrav_r.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - rs = 0x00; - rt = 0x87654321; - result = 0x87654321; - - __asm - ("shrav_r.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_r_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_r_w.c deleted file mode 100644 index 2ab03bb5daae..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrav_r_w.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x03; - rt = 0x87654321; - result = 0xF0ECA864; - - __asm - ("shrav_r.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - rs = 0x00; - rt = 0x40000000; - result = 0x40000000; - - __asm - ("shrav_r.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - - assert(rd == result); - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrl_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrl_qb.c deleted file mode 100644 index a7e4e6a5e4f5..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrl_qb.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x00010203; - - __asm - ("shrl.qb %0, %1, 0x05\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x12345678; - result = 0x12345678; - - __asm - ("shrl.qb %0, %1, 0x0\n\t" - : "=r"(rd) - : "r"(rt) - ); - - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrlv_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrlv_qb.c deleted file mode 100644 index db77f6d0e117..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_shrlv_qb.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x05; - rt = 0x12345678; - result = 0x00010203; - - __asm - ("shrlv.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - rs = 0x00; - rt = 0x12345678; - result = 0x12345678; - - __asm - ("shrlv.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_ph.c deleted file mode 100644 index fdd7b38b647e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_ph.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x77777777; - rt = 0x67654321; - result = 0x10123456; - resultdsp = 0x0; - - __asm - ("subq.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x12345678; - rt = 0x87654321; - result = 0x8ACF1357; - resultdsp = 0x01; - - __asm - ("subq.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_s_ph.c deleted file mode 100644 index 64c89ebd5114..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_s_ph.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x7FFF1357; - resultdsp = 0x01; - - __asm - ("wrdsp $0\n\t" - "subq_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x12348000; - rt = 0x87657000; - result = 0x7FFF8000; - resultdsp = 0x01; - - __asm - ("wrdsp $0\n\t" - "subq_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x12340000; - rt = 0x87658000; - result = 0x7FFF7FFF; - resultdsp = 0x01; - - __asm - ("wrdsp $0\n\t" - "subq_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_s_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_s_w.c deleted file mode 100644 index 9d456a90f417..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subq_s_w.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x7FFFFFFF; - resultdsp = 0x01; - - __asm - ("wrdsp $0\n\t" - "subq_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x66666; - rt = 0x55555; - result = 0x11111; - resultdsp = 0x0; - - __asm - ("wrdsp $0\n\t" - "subq_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x0; - rt = 0x80000000; - result = 0x7FFFFFFF; - resultdsp = 0x01; - - __asm - ("wrdsp $0\n\t" - "subq_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x80000000; - rt = 0x80000000; - result = 0; - resultdsp = 0x00; - - __asm - ("wrdsp $0\n\t" - "subq_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subu_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subu_qb.c deleted file mode 100644 index 420909615526..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subu_qb.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x8BCF1357; - resultdsp = 0x01; - - __asm - ("subu.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subu_s_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subu_s_qb.c deleted file mode 100644 index 3d650533d171..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_subu_s_qb.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x00001357; - resultdsp = 0x01; - - __asm - ("subu_s.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_wrdsp.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r1_wrdsp.c deleted file mode 100644 index dc54943a99e8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r1_wrdsp.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -int main() -{ - int dsp_i, dsp_o; - int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i; - int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o; - - ccond_i = 0x000000BC; /* 4 */ - outflag_i = 0x0000001B; /* 3 */ - efi_i = 0x00000001; /* 5 */ - c_i = 0x00000001; /* 2 */ - scount_i = 0x0000000F; /* 1 */ - pos_i = 0x0000000C; /* 0 */ - - dsp_i = (ccond_i << 24) | \ - (outflag_i << 16) | \ - (efi_i << 14) | \ - (c_i << 13) | \ - (scount_i << 7) | \ - pos_i; - - __asm - ("wrdsp %1, 0x3F\n\t" - "rddsp %0, 0x3F\n\t" - : "=r"(dsp_o) - : "r"(dsp_i) - ); - - ccond_o = (dsp_o >> 24) & 0xFF; - outflag_o = (dsp_o >> 16) & 0xFF; - efi_o = (dsp_o >> 14) & 0x01; - c_o = (dsp_o >> 14) & 0x01; - scount_o = (dsp_o >> 7) & 0x3F; - pos_o = dsp_o & 0x1F; - - assert(ccond_o == (ccond_i & 0x0F)); - assert(outflag_o == outflag_i); - assert(efi_o == efi_i); - assert(c_o == c_i); - assert(scount_o == scount_i); - assert(pos_o == pos_i); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_absq_s_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_absq_s_qb.c deleted file mode 100644 index af4683f30475..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_absq_s_qb.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -int main() -{ - int input, result, dsp; - int hope; - - input = 0x701BA35E; - hope = 0x701B5D5E; - - __asm - ("absq_s.qb %0, %1\n\t" - : "=r"(result) - : "r"(input) - ); - assert(result == hope); - - - input = 0x801BA35E; - hope = 0x7F1B5D5E; - - __asm - ("absq_s.qb %0, %2\n\t" - "rddsp %1\n\t" - : "=r"(result), "=r"(dsp) - : "r"(input) - ); - dsp = dsp >> 20; - dsp &= 0x01; - assert(dsp == 1); - assert(result == hope); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_ph.c deleted file mode 100644 index 921f0eaf33c7..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_ph.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x706A13FE; - rt = 0x13065174; - result = 0x41B832B9; - __asm - ("addqh.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0x81000100; - rt = 0xc2000100; - result = 0xa1800100; - __asm - ("addqh.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_r_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_r_ph.c deleted file mode 100644 index 213ba3725006..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_r_ph.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x706A13FE; - rt = 0x13065174; - result = 0x41B832B9; - __asm - ("addqh_r.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0x81010100; - rt = 0xc2000100; - result = 0xa1810100; - __asm - ("addqh_r.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_r_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_r_w.c deleted file mode 100644 index 75a75c50f32d..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_r_w.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x00000010; - rt = 0x00000001; - result = 0x00000009; - - __asm - ("addqh_r.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - rs = 0xFFFFFFFE; - rt = 0x00000001; - result = 0x00000000; - - __asm - ("addqh_r.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_w.c deleted file mode 100644 index de6926ebbb72..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addqh_w.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x00000010; - rt = 0x00000001; - result = 0x00000008; - - __asm - ("addqh.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - rs = 0xFFFFFFFE; - rt = 0x00000001; - result = 0xFFFFFFFF; - - __asm - ("addqh.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addu_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addu_ph.c deleted file mode 100644 index 1d7a25a2a773..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addu_ph.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x00FF00FF; - rt = 0x00010001; - result = 0x01000100; - __asm - ("addu.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0xFFFF1111; - rt = 0x00020001; - result = 0x00011112; - __asm - ("addu.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 20) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addu_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addu_s_ph.c deleted file mode 100644 index 979651bfc9ac..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_addu_s_ph.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x00FE00FE; - rt = 0x00020001; - result = 0x010000FF; - __asm - ("addu_s.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0xFFFF1111; - rt = 0x00020001; - result = 0xFFFF1112; - __asm - ("addu_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - assert(((dsp >> 20) & 0x01) == 1); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_adduh_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_adduh_qb.c deleted file mode 100644 index a1f5d631b52e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_adduh_qb.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0xFF0055AA; - rt = 0x0113421B; - result = 0x80094B62; - __asm - ("adduh.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0xFFFF0FFF; - rt = 0x00010111; - result = 0x7F800888; - __asm - ("adduh.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_adduh_r_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_adduh_r_qb.c deleted file mode 100644 index 81e98c190d2b..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_adduh_r_qb.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0xFF0055AA; - rt = 0x01112211; - result = 0x80093C5E; - __asm - ("adduh_r.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0xFFFF0FFF; - rt = 0x00010111; - result = 0x80800888; - __asm - ("adduh_r.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_append.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_append.c deleted file mode 100644 index 9a91e1650dbd..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_append.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int result; - - rs = 0xFF0055AA; - rt = 0x0113421B; - result = 0x02268436; - __asm - ("append %0, %1, 0x01\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(rt == result); - - rs = 0xFFFF0FFF; - rt = 0x00010111; - result = 0x0010111F; - __asm - ("append %0, %1, 0x04\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(rt == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_balign.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_balign.c deleted file mode 100644 index 537cf0451cc8..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_balign.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int result; - - rs = 0xFF0055AA; - rt = 0x0113421B; - result = 0x13421BFF; - __asm - ("balign %0, %1, 0x01\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(rt == result); - - rs = 0xFFFF0FFF; - rt = 0x00010111; - result = 0x11FFFF0F; - __asm - ("balign %0, %1, 0x03\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(rt == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_eq_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_eq_qb.c deleted file mode 100644 index 2d6340d6fb12..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_eq_qb.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x02; - __asm - ("cmpgdu.eq.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(rd == result); - assert(dsp == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x0F; - __asm - ("cmpgdu.eq.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(rd == result); - assert(dsp == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_le_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_le_qb.c deleted file mode 100644 index a0ecdca2ac2e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_le_qb.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x0F; - __asm - ("cmpgdu.le.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(rd == result); - assert(dsp == result); - - rs = 0x11777066; - rt = 0x11707066; - result = 0x0B; - __asm - ("cmpgdu.le.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(rd == result); - assert(dsp == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_lt_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_lt_qb.c deleted file mode 100644 index dba99e392c29..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_cmpgdu_lt_qb.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int dsp; - int result; - - rs = 0x11777066; - rt = 0x55AA70FF; - result = 0x0D; - __asm - ("cmpgdu.lt.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(rd == result); - assert(dsp == result); - - rs = 0x11777066; - rt = 0x11777066; - result = 0x00; - __asm - ("cmpgdu.lt.qb %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 24) & 0x0F; - assert(rd == result); - assert(dsp == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpa_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpa_w_ph.c deleted file mode 100644 index fae49f10eb95..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpa_w_ph.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0x00FF00FF; - rt = 0x00010002; - resulth = 0x05; - resultl = 0x0302; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpa.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - ach = 6, acl = 7; - rs = 0xFFFF00FF; - rt = 0xFFFF0002; - resulth = 0x06; - resultl = 0x206; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpa.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpaqx_s_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpaqx_s_w_ph.c deleted file mode 100644 index ce8783024685..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpaqx_s_w_ph.c +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach = 5, acl = 5; - int resulth, resultl, resultdsp; - - rs = 0x800000FF; - rt = 0x00018000; - resulth = 0x05; - resultl = 0x80000202; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaqx_s.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 5; - acl = 5; - rs = 0x00FF00FF; - rt = 0x00010002; - resulth = 0x05; - resultl = 0x05FF; - /*********************************************************** - * Because of we set outflag at last time, although this - * time we set nothing, but it is stay the last time value. - **********************************************************/ - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaqx_s.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 5; - acl = 5; - rs = 0x800000FF; - rt = 0x00028000; - resulth = 0x05; - resultl = 0x80000400; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaqx_s.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpaqx_sa_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpaqx_sa_w_ph.c deleted file mode 100644 index d551d64ae293..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpaqx_sa_w_ph.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach, acl; - int resulth, resultl, resultdsp; - - ach = 0x00000005; - acl = 0x00000005; - rs = 0x00FF00FF; - rt = 0x00010002; - resulth = 0x00; - resultl = 0x7FFFFFFF; - resultdsp = 0x01; - dsp = 0; - __asm - ("wrdsp %2\n\t" - "mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaqx_sa.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "+r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(dsp >> (16 + 1) == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x00000009; - acl = 0x0000000B; - rs = 0x800000FF; - rt = 0x00018000; - resulth = 0x00; - resultl = 0x7FFFFFFF; - resultdsp = 0x01; - dsp = 0; - __asm - ("wrdsp %2\n\t" - "mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpaqx_sa.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "+r"(dsp) - : "r"(rs), "r"(rt) - ); - assert(dsp >> (16 + 1) == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpax_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpax_w_ph.c deleted file mode 100644 index 514797cfd1b4..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpax_w_ph.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0x00FF00FF; - rt = 0x00010002; - resulth = 0x05; - resultl = 0x0302; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpax.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - ach = 6, acl = 7; - rs = 0xFFFF00FF; - rt = 0xFFFF0002; - resulth = 0x05; - resultl = 0xFFFFFF06; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpax.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dps_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dps_w_ph.c deleted file mode 100644 index f51f9b9d13d7..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dps_w_ph.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0x00FF00FF; - rt = 0x00010002; - resulth = 0x04; - resultl = 0xFFFFFD08; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dps.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - ach = 6, acl = 7; - rs = 0xFFFF00FF; - rt = 0xFFFF0002; - resulth = 0x05; - resultl = 0xFFFFFE08; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dps.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsqx_s_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsqx_s_w_ph.c deleted file mode 100644 index e40543fd8292..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsqx_s_w_ph.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach = 5, acl = 5; - int resulth, resultl, resultdsp; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x00000005; - resultl = 0x1CE5E09B; - resultdsp = 0x00; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsqx_s.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x99F13005; - acl = 0x51730062; - rs = 0x80008000; - rt = 0x80008000; - - resulth = 0x99F13004; - resultl = 0x51730064; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsqx_s.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsqx_sa_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsqx_sa_w_ph.c deleted file mode 100644 index 7da278eacc0e..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsqx_sa_w_ph.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, dsp; - int ach = 5, acl = 5; - int resulth, resultl, resultdsp; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x00; - resultl = 0x7FFFFFFF; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsqx_sa.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - ach = 0x8c0b354A; - acl = 0xbbc02249; - rs = 0x800023AD; - rt = 0x01648000; - resulth = 0xffffffff; - resultl = 0x80000000; - resultdsp = 0x01; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsqx_sa.w.ph $ac1, %3, %4\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - "rddsp %2\n\t" - : "+r"(ach), "+r"(acl), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 17) & 0x01; - assert(dsp == resultdsp); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsx_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsx_w_ph.c deleted file mode 100644 index bb49a4031d34..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_dpsx_w_ph.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int ach = 5, acl = 5; - int resulth, resultl; - - rs = 0xBC0123AD; - rt = 0x01643721; - resulth = 0x05; - resultl = 0xE72F050; - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "dpsx.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mul_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mul_ph.c deleted file mode 100644 index c7e9d60d12e2..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mul_ph.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x03FB1234; - rt = 0x0BCC4321; - result = 0xF504F4B4; - resultdsp = 1; - - __asm - ("mul.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 0x00210010; - rt = 0x00110005; - result = 0x2310050; - resultdsp = 0; - - __asm - ("mul.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mul_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mul_s_ph.c deleted file mode 100644 index 33da110de869..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mul_s_ph.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x03FB1234; - rt = 0x0BCC4321; - result = 0x7fff7FFF; - resultdsp = 1; - - __asm - ("mul_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - rs = 0x7fffff00; - rt = 0xff007fff; - result = 0x80008000; - resultdsp = 1; - - __asm - ("mul_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - dsp = 0; - __asm - ("wrdsp %0\n\t" - : - : "r"(dsp) - ); - - rs = 0x00320001; - rt = 0x00210002; - result = 0x06720002; - resultdsp = 0; - - __asm - ("mul_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_rs_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_rs_w.c deleted file mode 100644 index 7ba633bc17f7..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_rs_w.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x80001234; - rt = 0x80004321; - result = 0x7FFFAAAB; - - __asm - ("mulq_rs.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0x80000000; - rt = 0x80000000; - result = 0x7FFFFFFF; - resultdsp = 1; - - __asm - ("mulq_rs.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_s_ph.c deleted file mode 100644 index 00e015542e69..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_s_ph.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x80000000; - rt = 0x0ffc0000; - result = 0xF0040000; - resultdsp = 0; - - __asm - ("mulq_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - rs = 0x80001234; - rt = 0x80004321; - result = 0x7FFF098B; - resultdsp = 1; - - __asm - ("mulq_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_s_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_s_w.c deleted file mode 100644 index 9c2be06cc08a..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulq_s_w.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x80001234; - rt = 0x80004321; - result = 0x7FFFAAAB; - - __asm - ("mulq_s.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0x80000000; - rt = 0x80000000; - result = 0x7FFFFFFF; - resultdsp = 1; - - __asm - ("mulq_s.w %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 21) & 0x01; - assert(rd == result); - assert(dsp == resultdsp); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulsa_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulsa_w_ph.c deleted file mode 100644 index a6940939ca50..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulsa_w_ph.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, ach, acl; - int resulth, resultl; - - ach = 0x05; - acl = 0x00BBDDCC; - rs = 0x80001234; - rt = 0x80004321; - resulth = 0x05; - resultl = 0x3BF5E918; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "mulsa.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulsaq_s_w_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulsaq_s_w_ph.c deleted file mode 100644 index 06c91a43e7ea..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_mulsaq_s_w_ph.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt, ach, acl; - int resulth, resultl; - - ach = 0x05; - acl = 0x00BBDDCC; - rs = 0x80001234; - rt = 0x80004321; - resulth = 0x05; - resultl = 0x772ff463; - - __asm - ("mthi %0, $ac1\n\t" - "mtlo %1, $ac1\n\t" - "mulsaq_s.w.ph $ac1, %2, %3\n\t" - "mfhi %0, $ac1\n\t" - "mflo %1, $ac1\n\t" - : "+r"(ach), "+r"(acl) - : "r"(rs), "r"(rt) - ); - assert(ach == resulth); - assert(acl == resultl); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_qb_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_qb_ph.c deleted file mode 100644 index 3a2b3fde0573..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_qb_ph.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x34786521; - - __asm - ("precr.qb.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(result == rd); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_sra_ph_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_sra_ph_w.c deleted file mode 100644 index 5c9baab03d00..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_sra_ph_w.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x43215678; - - __asm - ("precr_sra.ph.w %0, %1, 0x00\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(result == rt); - - rs = 0x12345678; - rt = 0x87654321; - result = 0xFFFF0000; - - __asm - ("precr_sra.ph.w %0, %1, 0x1F\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_sra_r_ph_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_sra_r_ph_w.c deleted file mode 100644 index 6474a108c057..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_precr_sra_r_ph_w.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x43215678; - - __asm - ("precr_sra_r.ph.w %0, %1, 0x00\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(result == rt); - - rs = 0x12345678; - rt = 0x87654321; - result = 0xFFFF0000; - - __asm - ("precr_sra_r.ph.w %0, %1, 0x1F\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(result == rt); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_prepend.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_prepend.c deleted file mode 100644 index f6bcd47b2da9..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_prepend.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x87654321; - __asm - ("prepend %0, %1, 0x00\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(rt == result); - - rs = 0x12345678; - rt = 0x87654321; - result = 0xACF10ECA; - __asm - ("prepend %0, %1, 0x0F\n\t" - : "+r"(rt) - : "r"(rs) - ); - assert(rt == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shra_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shra_qb.c deleted file mode 100644 index 48193de87ad0..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shra_qb.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x02060A0F; - - __asm - ("shra.qb %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x87654321; - result = 0xF00C0804; - - __asm - ("shra.qb %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shra_r_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shra_r_qb.c deleted file mode 100644 index 29afa0e4b07b..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shra_r_qb.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x02070B0F; - - __asm - ("shra_r.qb %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - rt = 0x87654321; - result = 0xF10D0804; - - __asm - ("shra_r.qb %0, %1, 0x03\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrav_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrav_qb.c deleted file mode 100644 index b21e1b7ca64a..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrav_qb.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x03; - rt = 0x12345678; - result = 0x02060A0F; - - __asm - ("shrav.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - rs = 0x03; - rt = 0x87654321; - result = 0xF00C0804; - - __asm - ("shrav.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrav_r_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrav_r_qb.c deleted file mode 100644 index 9ea8aa0cbb90..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrav_r_qb.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x03; - rt = 0x12345678; - result = 0x02070B0F; - - __asm - ("shrav_r.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - rs = 0x03; - rt = 0x87654321; - result = 0xF10D0804; - - __asm - ("shrav_r.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrl_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrl_ph.c deleted file mode 100644 index 724b9a7a4691..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrl_ph.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main() -{ - int rd, rt; - int result; - - rt = 0x12345678; - result = 0x009102B3; - - __asm - ("shrl.ph %0, %1, 0x05\n\t" - : "=r"(rd) - : "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrlv_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrlv_ph.c deleted file mode 100644 index ac79aa69acf0..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_shrlv_ph.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x05; - rt = 0x12345678; - result = 0x009102B3; - - __asm - ("shrlv.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rt), "r"(rs) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_ph.c deleted file mode 100644 index dbc096734ceb..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_ph.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x456709AB; - - __asm - ("subqh.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_r_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_r_ph.c deleted file mode 100644 index 24ef0f1aeb91..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_r_ph.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x456809AC; - - __asm - ("subqh_r.ph %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_r_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_r_w.c deleted file mode 100644 index d460f8630fae..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_r_w.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x456789AC; - - __asm - ("subqh_r.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_w.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_w.c deleted file mode 100644 index 42be3deb80a3..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subqh_w.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0x456789AB; - - __asm - ("subqh.w %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subu_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subu_ph.c deleted file mode 100644 index 0d39a017c79d..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subu_ph.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x87654321; - rt = 0x11111111; - result = 0x76543210; - resultdsp = 0x00; - - __asm - ("subu.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - rs = 0x87654321; - rt = 0x12345678; - result = 0x7531ECA9; - resultdsp = 0x01; - - __asm - ("subu.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subu_s_ph.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subu_s_ph.c deleted file mode 100644 index 8e4da4f3e544..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subu_s_ph.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt, dsp; - int result, resultdsp; - - rs = 0x87654321; - rt = 0x12345678; - result = 0x75310000; - resultdsp = 0x01; - - __asm - ("subu_s.ph %0, %2, %3\n\t" - "rddsp %1\n\t" - : "=r"(rd), "=r"(dsp) - : "r"(rs), "r"(rt) - ); - dsp = (dsp >> 20) & 0x01; - assert(dsp == resultdsp); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subuh_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subuh_qb.c deleted file mode 100644 index 92cfc764b8c9..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subuh_qb.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0xC5E7092B; - - __asm - ("subuh.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subuh_r_qb.c b/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subuh_r_qb.c deleted file mode 100644 index dac81d47db60..000000000000 --- a/tests/tcg/mips/user/ase/dsp/test_dsp_r2_subuh_r_qb.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int main() -{ - int rd, rs, rt; - int result; - - rs = 0x12345678; - rt = 0x87654321; - result = 0xC6E80A2C; - - __asm - ("subuh_r.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - rs = 0xBEFC292A; - rt = 0x9205C1B4; - result = 0x167cb4bb; - - __asm - ("subuh_r.qb %0, %1, %2\n\t" - : "=r"(rd) - : "r"(rs), "r"(rt) - ); - assert(rd == result); - - return 0; -} diff --git a/tests/tcg/mips/user/ase/msa/README b/tests/tcg/mips/user/ase/msa/README deleted file mode 100644 index ca4f070ec1eb..000000000000 --- a/tests/tcg/mips/user/ase/msa/README +++ /dev/null @@ -1,20 +0,0 @@ -The tests in subdirectories of this directory are supposed to be compiled for -mips64el MSA-enabled CPU (I6400, I6500), using an appropriate MIPS toolchain. -For example: - -/opt/img/bin/mips-img-linux-gnu-gcc \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o - -They are to be executed using QEMU user mode, using command line: - -mips64el-linux-user/qemu-mips64el -cpu I6400 - -Helper scripts test_msa_compile.sh and test_msa_run.sh are also -provided. This is an example of compilation and execution of all -MSA tests: - -cd -cd tests/tcg/mips/user/ase/msa - -./test_msa_compile.sh -./test_msa_run.sh diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_b.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_b.c deleted file mode 100644 index 6ceb5aab20ce..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_b.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLOC.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLOC.B"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0301000301000301ULL, 0x0003010003010003ULL, }, - { 0x0000020000020000ULL, 0x0200000200000200ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0500000103050000ULL, 0x0103050000010305ULL, }, - { 0x0002040000000204ULL, 0x0000000204000000ULL, }, - { 0x0600020600020600ULL, 0x0206000206000206ULL, }, - { 0x0004000004000004ULL, 0x0000040000040000ULL, }, - { 0x0700050003000107ULL, 0x0005000300010700ULL, }, - { 0x0006000400020000ULL, 0x0600040002000006ULL, }, - { 0x0800080008000800ULL, 0x0800080008000800ULL, }, /* 16 */ - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0801000300050007ULL, 0x0008010003000500ULL, }, - { 0x0000020004000600ULL, 0x0800000200040006ULL, }, - { 0x0802000600080200ULL, 0x0600080200060008ULL, }, - { 0x0000040008000004ULL, 0x0008000004000800ULL, }, - { 0x0803000801000700ULL, 0x0005000803000801ULL, }, - { 0x0000060000040008ULL, 0x0200080000060000ULL, }, - { 0x0804000804000804ULL, 0x0008040008040008ULL, }, /* 24 */ - { 0x0000080000080000ULL, 0x0800000800000800ULL, }, - { 0x0805000007000008ULL, 0x0100080300080500ULL, }, - { 0x0000080200080400ULL, 0x0006000008000008ULL, }, - { 0x0806000008020008ULL, 0x0600000802000806ULL, }, - { 0x0000080400000800ULL, 0x0008040000080000ULL, }, - { 0x0807000008050000ULL, 0x0803000008010008ULL, }, - { 0x0000080600000804ULL, 0x0000080200000800ULL, }, - { 0x0808000008080000ULL, 0x0808000008080000ULL, }, /* 32 */ - { 0x0000080800000808ULL, 0x0000080800000808ULL, }, - { 0x0808010000080300ULL, 0x0008050000080700ULL, }, - { 0x0000000802000008ULL, 0x0400000806000008ULL, }, - { 0x0808020000080600ULL, 0x0008080200000806ULL, }, - { 0x0000000804000008ULL, 0x0800000008040000ULL, }, - { 0x0808030000080801ULL, 0x0000080700000008ULL, }, - { 0x0000000806000000ULL, 0x0804000008080200ULL, }, - { 0x0808040000080804ULL, 0x0000080804000008ULL, }, /* 40 */ - { 0x0000000808000000ULL, 0x0808000000080800ULL, }, - { 0x0808050000000807ULL, 0x0000000808010000ULL, }, - { 0x0000000808020000ULL, 0x0808040000000806ULL, }, - { 0x0808060000000808ULL, 0x0200000808060000ULL, }, - { 0x0000000808040000ULL, 0x0008080000000808ULL, }, - { 0x0808070000000808ULL, 0x0500000008080300ULL, }, - { 0x0000000808060000ULL, 0x0008080400000008ULL, }, - { 0x0808080000000808ULL, 0x0800000008080800ULL, }, /* 48 */ - { 0x0000000808080000ULL, 0x0008080800000008ULL, }, - { 0x0808080100000008ULL, 0x0803000000080805ULL, }, - { 0x0000000008080200ULL, 0x0000080804000000ULL, }, - { 0x0808080200000008ULL, 0x0806000000080808ULL, }, - { 0x0000000008080400ULL, 0x0000080808000000ULL, }, - { 0x0808080300000008ULL, 0x0808010000000808ULL, }, - { 0x0000000008080600ULL, 0x0000000808040000ULL, }, - { 0x0808080400000008ULL, 0x0808040000000808ULL, }, /* 56 */ - { 0x0000000008080800ULL, 0x0000000808080000ULL, }, - { 0x0808080500000000ULL, 0x0808070000000008ULL, }, - { 0x0000000008080802ULL, 0x0000000808080400ULL, }, - { 0x0808080600000000ULL, 0x0808080200000008ULL, }, - { 0x0000000008080804ULL, 0x0000000008080800ULL, }, - { 0x0808080700000000ULL, 0x0808080500000000ULL, }, - { 0x0000000008080806ULL, 0x0000000008080804ULL, }, - { 0x0100030200000000ULL, 0x0000000007000100ULL, }, /* 64 */ - { 0x0501000000010200ULL, 0x0004010000000006ULL, }, - { 0x0100010101020101ULL, 0x0002020801000000ULL, }, - { 0x0000000000000300ULL, 0x0104010201000301ULL, }, - { 0x0101000000010000ULL, 0x0100000102020001ULL, }, - { 0x0200010108000005ULL, 0x0000000007010000ULL, }, - { 0x0100000000020100ULL, 0x0100000001040100ULL, }, - { 0x0601000401010101ULL, 0x0106000000000001ULL, }, - { 0x0000000200010300ULL, 0x0300030001010000ULL, }, /* 72 */ - { 0x0100020000020302ULL, 0x0100010101030100ULL, }, - { 0x0103040402020200ULL, 0x0102000000000000ULL, }, - { 0x0101040400010001ULL, 0x0201030000010103ULL, }, - { 0x0300000301000300ULL, 0x0100010200000200ULL, }, - { 0x0100000600000001ULL, 0x0401000100000000ULL, }, - { 0x0000000000010401ULL, 0x0300010402000000ULL, }, - { 0x0100010104000201ULL, 0x0200020200000003ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLOC_B(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLOC_B(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_d.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_d.c deleted file mode 100644 index 897e90fbbc9c..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_d.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLOC.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLOC.D"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000040ULL, 0x0000000000000040ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000003ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000005ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000006ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000007ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000006ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000009ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x000000000000000aULL, 0x0000000000000006ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000bULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x000000000000000cULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x000000000000000dULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000eULL, 0x0000000000000006ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000fULL, 0x000000000000000bULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000010ULL, 0x0000000000000010ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000011ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000004ULL, }, - { 0x0000000000000012ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x0000000000000013ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x000000000000000cULL, }, - { 0x0000000000000014ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000010ULL, }, - { 0x0000000000000015ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000014ULL, }, - { 0x0000000000000016ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000017ULL, 0x0000000000000005ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000018ULL, 0x0000000000000008ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000019ULL, 0x000000000000000bULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001aULL, 0x000000000000000eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001bULL, 0x0000000000000011ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001cULL, 0x0000000000000014ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001dULL, 0x0000000000000017ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001eULL, 0x000000000000001aULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001fULL, 0x000000000000001dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x0000000000000005ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000006ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, /* 72 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000002ULL, }, - { 0x0000000000000003ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000004ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000001ULL, 0x0000000000000002ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLOC_D(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLOC_D(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_h.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_h.c deleted file mode 100644 index 85cf3e6f702a..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_h.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLOC.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLOC.H"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0010001000100010ULL, 0x0010001000100010ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0003000000010003ULL, 0x0000000100030000ULL, }, - { 0x0000000200000000ULL, 0x0002000000000002ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0005000000030000ULL, 0x0001000500000003ULL, }, - { 0x0000000400000002ULL, 0x0000000000040000ULL, }, - { 0x0006000200000006ULL, 0x0002000000060002ULL, }, - { 0x0000000000040000ULL, 0x0000000400000000ULL, }, - { 0x0007000500030001ULL, 0x0000000000000007ULL, }, - { 0x0000000000000000ULL, 0x0006000400020000ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0009000000000000ULL, 0x0000000100030005ULL, }, - { 0x0000000200040006ULL, 0x0008000000000000ULL, }, - { 0x000a000000000002ULL, 0x0006000a00000000ULL, }, - { 0x0000000400080000ULL, 0x0000000000040008ULL, }, - { 0x000b000000010007ULL, 0x0000000000030009ULL, }, - { 0x0000000600000000ULL, 0x0002000800000000ULL, }, - { 0x000c00000004000cULL, 0x00000004000c0000ULL, }, /* 24 */ - { 0x0000000800000000ULL, 0x0008000000000008ULL, }, - { 0x000d000000070000ULL, 0x0001000b00000005ULL, }, - { 0x0000000a00000004ULL, 0x0000000000080000ULL, }, - { 0x000e0000000a0000ULL, 0x000600000002000eULL, }, - { 0x0000000c00000008ULL, 0x0000000400000000ULL, }, - { 0x000f0000000d0000ULL, 0x000b000000090000ULL, }, - { 0x0000000e0000000cULL, 0x0000000a00000008ULL, }, - { 0x0010000000100000ULL, 0x0010000000100000ULL, }, /* 32 */ - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0010000100000003ULL, 0x0000000500000007ULL, }, - { 0x0000000000020000ULL, 0x0004000000060000ULL, }, - { 0x0010000200000006ULL, 0x0000000a0000000eULL, }, - { 0x0000000000040000ULL, 0x00080000000c0000ULL, }, - { 0x0010000300000009ULL, 0x0000000f00000000ULL, }, - { 0x0000000000060000ULL, 0x000c000000100002ULL, }, - { 0x001000040000000cULL, 0x0000001000040000ULL, }, /* 40 */ - { 0x0000000000080000ULL, 0x0010000000000008ULL, }, - { 0x001000050000000fULL, 0x0000000000090000ULL, }, - { 0x00000000000a0000ULL, 0x001000040000000eULL, }, - { 0x0010000600000010ULL, 0x00020000000e0000ULL, }, - { 0x00000000000c0000ULL, 0x0000000800000010ULL, }, - { 0x0010000700000010ULL, 0x0005000000100003ULL, }, - { 0x00000000000e0000ULL, 0x0000000c00000000ULL, }, - { 0x0010000800000010ULL, 0x0008000000100008ULL, }, /* 48 */ - { 0x0000000000100000ULL, 0x0000001000000000ULL, }, - { 0x0010000900000000ULL, 0x000b00000000000dULL, }, - { 0x0000000000100002ULL, 0x0000001000040000ULL, }, - { 0x0010000a00000000ULL, 0x000e000000000010ULL, }, - { 0x0000000000100004ULL, 0x0000001000080000ULL, }, - { 0x0010000b00000000ULL, 0x0010000100000010ULL, }, - { 0x0000000000100006ULL, 0x00000000000c0000ULL, }, - { 0x0010000c00000000ULL, 0x0010000400000010ULL, }, /* 56 */ - { 0x0000000000100008ULL, 0x0000000000100000ULL, }, - { 0x0010000d00000000ULL, 0x0010000700000000ULL, }, - { 0x000000000010000aULL, 0x0000000000100004ULL, }, - { 0x0010000e00000000ULL, 0x0010000a00000000ULL, }, - { 0x000000000010000cULL, 0x0000000000100008ULL, }, - { 0x0010000f00000000ULL, 0x0010000d00000000ULL, }, - { 0x000000000010000eULL, 0x000000000010000cULL, }, - { 0x0001000300000000ULL, 0x0000000000070001ULL, }, /* 64 */ - { 0x0005000000000002ULL, 0x0000000100000000ULL, }, - { 0x0001000100010001ULL, 0x0000000200010000ULL, }, - { 0x0000000000000003ULL, 0x0001000100010003ULL, }, - { 0x0001000000000000ULL, 0x0001000000020000ULL, }, - { 0x0002000100080000ULL, 0x0000000000070000ULL, }, - { 0x0001000000000001ULL, 0x0001000000010001ULL, }, - { 0x0006000000010001ULL, 0x0001000000000000ULL, }, - { 0x0000000000000003ULL, 0x0003000300010000ULL, }, /* 72 */ - { 0x0001000200000003ULL, 0x0001000100010001ULL, }, - { 0x0001000400020002ULL, 0x0001000000000000ULL, }, - { 0x0001000400000000ULL, 0x0002000300000001ULL, }, - { 0x0003000000010003ULL, 0x0001000100000002ULL, }, - { 0x0001000000000000ULL, 0x0004000000000000ULL, }, - { 0x0000000000000004ULL, 0x0003000100020000ULL, }, - { 0x0001000100040002ULL, 0x0002000200000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLOC_H(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLOC_H(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_w.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_w.c deleted file mode 100644 index 7ed97be2b482..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nloc_w.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLOC.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLOC.W"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000002000000020ULL, 0x0000002000000020ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000300000001ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000200000000ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000500000003ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000004ULL, }, - { 0x0000000600000000ULL, 0x0000000200000006ULL, }, - { 0x0000000000000004ULL, 0x0000000000000000ULL, }, - { 0x0000000700000003ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000600000002ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000900000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000004ULL, 0x0000000800000000ULL, }, - { 0x0000000a00000000ULL, 0x0000000600000000ULL, }, - { 0x0000000000000008ULL, 0x0000000000000004ULL, }, - { 0x0000000b00000001ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000200000000ULL, }, - { 0x0000000c00000004ULL, 0x000000000000000cULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000800000000ULL, }, - { 0x0000000d00000007ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x0000000e0000000aULL, 0x0000000600000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000f0000000dULL, 0x0000000b00000009ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000001100000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000400000006ULL, }, - { 0x0000001200000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000004ULL, 0x000000080000000cULL, }, - { 0x0000001300000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000006ULL, 0x0000000c00000012ULL, }, - { 0x0000001400000000ULL, 0x0000000000000004ULL, }, /* 40 */ - { 0x0000000000000008ULL, 0x0000001000000000ULL, }, - { 0x0000001500000000ULL, 0x0000000000000009ULL, }, - { 0x000000000000000aULL, 0x0000001400000000ULL, }, - { 0x0000001600000000ULL, 0x000000020000000eULL, }, - { 0x000000000000000cULL, 0x0000000000000000ULL, }, - { 0x0000001700000000ULL, 0x0000000500000013ULL, }, - { 0x000000000000000eULL, 0x0000000000000000ULL, }, - { 0x0000001800000000ULL, 0x0000000800000018ULL, }, /* 48 */ - { 0x0000000000000010ULL, 0x0000000000000000ULL, }, - { 0x0000001900000000ULL, 0x0000000b00000000ULL, }, - { 0x0000000000000012ULL, 0x0000000000000004ULL, }, - { 0x0000001a00000000ULL, 0x0000000e00000000ULL, }, - { 0x0000000000000014ULL, 0x0000000000000008ULL, }, - { 0x0000001b00000000ULL, 0x0000001100000000ULL, }, - { 0x0000000000000016ULL, 0x000000000000000cULL, }, - { 0x0000001c00000000ULL, 0x0000001400000000ULL, }, /* 56 */ - { 0x0000000000000018ULL, 0x0000000000000010ULL, }, - { 0x0000001d00000000ULL, 0x0000001700000000ULL, }, - { 0x000000000000001aULL, 0x0000000000000014ULL, }, - { 0x0000001e00000000ULL, 0x0000001a00000000ULL, }, - { 0x000000000000001cULL, 0x0000000000000018ULL, }, - { 0x0000001f00000000ULL, 0x0000001d00000000ULL, }, - { 0x000000000000001eULL, 0x000000000000001cULL, }, - { 0x0000000100000000ULL, 0x0000000000000007ULL, }, /* 64 */ - { 0x0000000500000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000100000001ULL, }, - { 0x0000000100000000ULL, 0x0000000100000002ULL, }, - { 0x0000000200000008ULL, 0x0000000000000007ULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0x0000000600000001ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000300000001ULL, }, /* 72 */ - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0x0000000100000002ULL, 0x0000000100000000ULL, }, - { 0x0000000100000000ULL, 0x0000000200000000ULL, }, - { 0x0000000300000001ULL, 0x0000000100000000ULL, }, - { 0x0000000100000000ULL, 0x0000000400000000ULL, }, - { 0x0000000000000000ULL, 0x0000000300000002ULL, }, - { 0x0000000100000004ULL, 0x0000000200000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLOC_W(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLOC_W(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_b.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_b.c deleted file mode 100644 index 2103d5fbfea5..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_b.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLZC.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLZC.B"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0000020000020000ULL, 0x0200000200000200ULL, }, - { 0x0301000301000301ULL, 0x0003010003010003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0002040000000204ULL, 0x0000000204000000ULL, }, - { 0x0500000103050000ULL, 0x0103050000010305ULL, }, - { 0x0004000004000004ULL, 0x0000040000040000ULL, }, - { 0x0600020600020600ULL, 0x0206000206000206ULL, }, - { 0x0006000400020000ULL, 0x0600040002000006ULL, }, - { 0x0700050003000107ULL, 0x0005000300010700ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, /* 16 */ - { 0x0800080008000800ULL, 0x0800080008000800ULL, }, - { 0x0000020004000600ULL, 0x0800000200040006ULL, }, - { 0x0801000300050007ULL, 0x0008010003000500ULL, }, - { 0x0000040008000004ULL, 0x0008000004000800ULL, }, - { 0x0802000600080200ULL, 0x0600080200060008ULL, }, - { 0x0000060000040008ULL, 0x0200080000060000ULL, }, - { 0x0803000801000700ULL, 0x0005000803000801ULL, }, - { 0x0000080000080000ULL, 0x0800000800000800ULL, }, /* 24 */ - { 0x0804000804000804ULL, 0x0008040008040008ULL, }, - { 0x0000080200080400ULL, 0x0006000008000008ULL, }, - { 0x0805000007000008ULL, 0x0100080300080500ULL, }, - { 0x0000080400000800ULL, 0x0008040000080000ULL, }, - { 0x0806000008020008ULL, 0x0600000802000806ULL, }, - { 0x0000080600000804ULL, 0x0000080200000800ULL, }, - { 0x0807000008050000ULL, 0x0803000008010008ULL, }, - { 0x0000080800000808ULL, 0x0000080800000808ULL, }, /* 32 */ - { 0x0808000008080000ULL, 0x0808000008080000ULL, }, - { 0x0000000802000008ULL, 0x0400000806000008ULL, }, - { 0x0808010000080300ULL, 0x0008050000080700ULL, }, - { 0x0000000804000008ULL, 0x0800000008040000ULL, }, - { 0x0808020000080600ULL, 0x0008080200000806ULL, }, - { 0x0000000806000000ULL, 0x0804000008080200ULL, }, - { 0x0808030000080801ULL, 0x0000080700000008ULL, }, - { 0x0000000808000000ULL, 0x0808000000080800ULL, }, /* 40 */ - { 0x0808040000080804ULL, 0x0000080804000008ULL, }, - { 0x0000000808020000ULL, 0x0808040000000806ULL, }, - { 0x0808050000000807ULL, 0x0000000808010000ULL, }, - { 0x0000000808040000ULL, 0x0008080000000808ULL, }, - { 0x0808060000000808ULL, 0x0200000808060000ULL, }, - { 0x0000000808060000ULL, 0x0008080400000008ULL, }, - { 0x0808070000000808ULL, 0x0500000008080300ULL, }, - { 0x0000000808080000ULL, 0x0008080800000008ULL, }, /* 48 */ - { 0x0808080000000808ULL, 0x0800000008080800ULL, }, - { 0x0000000008080200ULL, 0x0000080804000000ULL, }, - { 0x0808080100000008ULL, 0x0803000000080805ULL, }, - { 0x0000000008080400ULL, 0x0000080808000000ULL, }, - { 0x0808080200000008ULL, 0x0806000000080808ULL, }, - { 0x0000000008080600ULL, 0x0000000808040000ULL, }, - { 0x0808080300000008ULL, 0x0808010000000808ULL, }, - { 0x0000000008080800ULL, 0x0000000808080000ULL, }, /* 56 */ - { 0x0808080400000008ULL, 0x0808040000000808ULL, }, - { 0x0000000008080802ULL, 0x0000000808080400ULL, }, - { 0x0808080500000000ULL, 0x0808070000000008ULL, }, - { 0x0000000008080804ULL, 0x0000000008080800ULL, }, - { 0x0808080600000000ULL, 0x0808080200000008ULL, }, - { 0x0000000008080806ULL, 0x0000000008080804ULL, }, - { 0x0808080700000000ULL, 0x0808080500000000ULL, }, - { 0x0001000002010101ULL, 0x0101040100010004ULL, }, /* 64 */ - { 0x0000080101000004ULL, 0x0300000303020100ULL, }, - { 0x0001000000000000ULL, 0x0200000000020203ULL, }, - { 0x0101030101020001ULL, 0x0000000000010000ULL, }, - { 0x0000010101000101ULL, 0x0002010000000100ULL, }, - { 0x0002000000040200ULL, 0x0304010100000201ULL, }, - { 0x0002010501000001ULL, 0x0002040200000001ULL, }, - { 0x0000020000000000ULL, 0x0000010203010100ULL, }, - { 0x0203040001000001ULL, 0x0001000200000201ULL, }, /* 72 */ - { 0x0001000301000000ULL, 0x0002000000000001ULL, }, - { 0x0000000000000003ULL, 0x0000010101040103ULL, }, - { 0x0000000002000100ULL, 0x0000000101000000ULL, }, - { 0x0003020000010004ULL, 0x0001000001010003ULL, }, - { 0x0001020003020100ULL, 0x0000020001040201ULL, }, - { 0x0102010102000000ULL, 0x0001000000030201ULL, }, - { 0x0001000000010000ULL, 0x0001000001010300ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLZC_B(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLZC_B(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_d.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_d.c deleted file mode 100644 index b1ca3d44aacd..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_d.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLZC.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLZC.D"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000040ULL, 0x0000000000000040ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x0000000000000003ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000005ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000006ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000006ULL, }, - { 0x0000000000000007ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x0000000000000009ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000aULL, 0x0000000000000006ULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x000000000000000bULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, /* 24 */ - { 0x000000000000000cULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000dULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000eULL, 0x0000000000000006ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000000fULL, 0x000000000000000bULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000010ULL, 0x0000000000000010ULL, }, - { 0x0000000000000000ULL, 0x0000000000000004ULL, }, - { 0x0000000000000011ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x0000000000000012ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x000000000000000cULL, }, - { 0x0000000000000013ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000010ULL, }, /* 40 */ - { 0x0000000000000014ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000014ULL, }, - { 0x0000000000000015ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000016ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000017ULL, 0x0000000000000005ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000018ULL, 0x0000000000000008ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000019ULL, 0x000000000000000bULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001aULL, 0x000000000000000eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001bULL, 0x0000000000000011ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x000000000000001cULL, 0x0000000000000014ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001dULL, 0x0000000000000017ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001eULL, 0x000000000000001aULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000001fULL, 0x000000000000001dULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLZC_D(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLZC_D(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_h.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_h.c deleted file mode 100644 index 6531c67a8691..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_h.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLZC.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLZC.H"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0010001000100010ULL, 0x0010001000100010ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x0000000200000000ULL, 0x0002000000000002ULL, }, - { 0x0003000000010003ULL, 0x0000000100030000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0000000400000002ULL, 0x0000000000040000ULL, }, - { 0x0005000000030000ULL, 0x0001000500000003ULL, }, - { 0x0000000000040000ULL, 0x0000000400000000ULL, }, - { 0x0006000200000006ULL, 0x0002000000060002ULL, }, - { 0x0000000000000000ULL, 0x0006000400020000ULL, }, - { 0x0007000500030001ULL, 0x0000000000000007ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0000000200040006ULL, 0x0008000000000000ULL, }, - { 0x0009000000000000ULL, 0x0000000100030005ULL, }, - { 0x0000000400080000ULL, 0x0000000000040008ULL, }, - { 0x000a000000000002ULL, 0x0006000a00000000ULL, }, - { 0x0000000600000000ULL, 0x0002000800000000ULL, }, - { 0x000b000000010007ULL, 0x0000000000030009ULL, }, - { 0x0000000800000000ULL, 0x0008000000000008ULL, }, /* 24 */ - { 0x000c00000004000cULL, 0x00000004000c0000ULL, }, - { 0x0000000a00000004ULL, 0x0000000000080000ULL, }, - { 0x000d000000070000ULL, 0x0001000b00000005ULL, }, - { 0x0000000c00000008ULL, 0x0000000400000000ULL, }, - { 0x000e0000000a0000ULL, 0x000600000002000eULL, }, - { 0x0000000e0000000cULL, 0x0000000a00000008ULL, }, - { 0x000f0000000d0000ULL, 0x000b000000090000ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, /* 32 */ - { 0x0010000000100000ULL, 0x0010000000100000ULL, }, - { 0x0000000000020000ULL, 0x0004000000060000ULL, }, - { 0x0010000100000003ULL, 0x0000000500000007ULL, }, - { 0x0000000000040000ULL, 0x00080000000c0000ULL, }, - { 0x0010000200000006ULL, 0x0000000a0000000eULL, }, - { 0x0000000000060000ULL, 0x000c000000100002ULL, }, - { 0x0010000300000009ULL, 0x0000000f00000000ULL, }, - { 0x0000000000080000ULL, 0x0010000000000008ULL, }, /* 40 */ - { 0x001000040000000cULL, 0x0000001000040000ULL, }, - { 0x00000000000a0000ULL, 0x001000040000000eULL, }, - { 0x001000050000000fULL, 0x0000000000090000ULL, }, - { 0x00000000000c0000ULL, 0x0000000800000010ULL, }, - { 0x0010000600000010ULL, 0x00020000000e0000ULL, }, - { 0x00000000000e0000ULL, 0x0000000c00000000ULL, }, - { 0x0010000700000010ULL, 0x0005000000100003ULL, }, - { 0x0000000000100000ULL, 0x0000001000000000ULL, }, /* 48 */ - { 0x0010000800000010ULL, 0x0008000000100008ULL, }, - { 0x0000000000100002ULL, 0x0000001000040000ULL, }, - { 0x0010000900000000ULL, 0x000b00000000000dULL, }, - { 0x0000000000100004ULL, 0x0000001000080000ULL, }, - { 0x0010000a00000000ULL, 0x000e000000000010ULL, }, - { 0x0000000000100006ULL, 0x00000000000c0000ULL, }, - { 0x0010000b00000000ULL, 0x0010000100000010ULL, }, - { 0x0000000000100008ULL, 0x0000000000100000ULL, }, /* 56 */ - { 0x0010000c00000000ULL, 0x0010000400000010ULL, }, - { 0x000000000010000aULL, 0x0000000000100004ULL, }, - { 0x0010000d00000000ULL, 0x0010000700000000ULL, }, - { 0x000000000010000cULL, 0x0000000000100008ULL, }, - { 0x0010000e00000000ULL, 0x0010000a00000000ULL, }, - { 0x000000000010000eULL, 0x000000000010000cULL, }, - { 0x0010000f00000000ULL, 0x0010000d00000000ULL, }, - { 0x0000000000020001ULL, 0x0001000400000000ULL, }, /* 64 */ - { 0x0000000900010000ULL, 0x0003000000030001ULL, }, - { 0x0000000000000000ULL, 0x0002000000000002ULL, }, - { 0x0001000300010000ULL, 0x0000000000000000ULL, }, - { 0x0000000100010001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000002ULL, 0x0003000100000002ULL, }, - { 0x0000000100010000ULL, 0x0000000400000000ULL, }, - { 0x0000000200000000ULL, 0x0000000100030001ULL, }, - { 0x0002000400010000ULL, 0x0000000000000002ULL, }, /* 72 */ - { 0x0000000000010000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000100010001ULL, }, - { 0x0000000000020001ULL, 0x0000000000010000ULL, }, - { 0x0000000200000000ULL, 0x0000000000010000ULL, }, - { 0x0000000200030001ULL, 0x0000000200010002ULL, }, - { 0x0001000100020000ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000010003ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLZC_H(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLZC_H(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_w.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_w.c deleted file mode 100644 index 71db53c9fe48..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_nlzc_w.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction NLZC.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "NLZC.W"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000002000000020ULL, 0x0000002000000020ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x0000000000000000ULL, 0x0000000200000000ULL, }, - { 0x0000000300000001ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000000000000ULL, 0x0000000000000004ULL, }, - { 0x0000000500000003ULL, 0x0000000100000000ULL, }, - { 0x0000000000000004ULL, 0x0000000000000000ULL, }, - { 0x0000000600000000ULL, 0x0000000200000006ULL, }, - { 0x0000000000000000ULL, 0x0000000600000002ULL, }, - { 0x0000000700000003ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000000000004ULL, 0x0000000800000000ULL, }, - { 0x0000000900000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000008ULL, 0x0000000000000004ULL, }, - { 0x0000000a00000000ULL, 0x0000000600000000ULL, }, - { 0x0000000000000000ULL, 0x0000000200000000ULL, }, - { 0x0000000b00000001ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000800000000ULL, }, /* 24 */ - { 0x0000000c00000004ULL, 0x000000000000000cULL, }, - { 0x0000000000000000ULL, 0x0000000000000008ULL, }, - { 0x0000000d00000007ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000e0000000aULL, 0x0000000600000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000f0000000dULL, 0x0000000b00000009ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000000000000002ULL, 0x0000000400000006ULL, }, - { 0x0000001100000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000004ULL, 0x000000080000000cULL, }, - { 0x0000001200000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000006ULL, 0x0000000c00000012ULL, }, - { 0x0000001300000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000008ULL, 0x0000001000000000ULL, }, /* 40 */ - { 0x0000001400000000ULL, 0x0000000000000004ULL, }, - { 0x000000000000000aULL, 0x0000001400000000ULL, }, - { 0x0000001500000000ULL, 0x0000000000000009ULL, }, - { 0x000000000000000cULL, 0x0000000000000000ULL, }, - { 0x0000001600000000ULL, 0x000000020000000eULL, }, - { 0x000000000000000eULL, 0x0000000000000000ULL, }, - { 0x0000001700000000ULL, 0x0000000500000013ULL, }, - { 0x0000000000000010ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000001800000000ULL, 0x0000000800000018ULL, }, - { 0x0000000000000012ULL, 0x0000000000000004ULL, }, - { 0x0000001900000000ULL, 0x0000000b00000000ULL, }, - { 0x0000000000000014ULL, 0x0000000000000008ULL, }, - { 0x0000001a00000000ULL, 0x0000000e00000000ULL, }, - { 0x0000000000000016ULL, 0x000000000000000cULL, }, - { 0x0000001b00000000ULL, 0x0000001100000000ULL, }, - { 0x0000000000000018ULL, 0x0000000000000010ULL, }, /* 56 */ - { 0x0000001c00000000ULL, 0x0000001400000000ULL, }, - { 0x000000000000001aULL, 0x0000000000000014ULL, }, - { 0x0000001d00000000ULL, 0x0000001700000000ULL, }, - { 0x000000000000001cULL, 0x0000000000000018ULL, }, - { 0x0000001e00000000ULL, 0x0000001a00000000ULL, }, - { 0x000000000000001eULL, 0x000000000000001cULL, }, - { 0x0000001f00000000ULL, 0x0000001d00000000ULL, }, - { 0x0000000000000002ULL, 0x0000000100000000ULL, }, /* 64 */ - { 0x0000000000000001ULL, 0x0000000300000003ULL, }, - { 0x0000000000000000ULL, 0x0000000200000000ULL, }, - { 0x0000000100000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000300000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000200000001ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000002ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000003ULL, 0x0000000000000001ULL, }, - { 0x0000000100000002ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_NLZC_W(b128_pattern[i], b128_result[i]); - } else { - do_msa_NLZC_W(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_b.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_b.c deleted file mode 100644 index 184f7f4a4987..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_b.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction PCNT.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "PCNT.B"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0504030504030504ULL, 0x0305040305040305ULL, }, - { 0x0304050304050304ULL, 0x0503040503040503ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, /* 8 */ - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0505040303050504ULL, 0x0303050504030305ULL, }, - { 0x0303040505030304ULL, 0x0505030304050503ULL, }, - { 0x0604020604020604ULL, 0x0206040206040206ULL, }, - { 0x0204060204060204ULL, 0x0602040602040602ULL, }, - { 0x0702050403060107ULL, 0x0205040306010702ULL, }, - { 0x0106030405020701ULL, 0x0603040502070106ULL, }, - { 0x0800080008000800ULL, 0x0800080008000800ULL, }, /* 16 */ - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0801060304050207ULL, 0x0008010603040502ULL, }, - { 0x0007020504030601ULL, 0x0800070205040306ULL, }, - { 0x0802040600080204ULL, 0x0600080204060008ULL, }, - { 0x0006040208000604ULL, 0x0208000604020800ULL, }, - { 0x0803020801040700ULL, 0x0605000803020801ULL, }, - { 0x0005060007040108ULL, 0x0203080005060007ULL, }, - { 0x0804000804000804ULL, 0x0008040008040008ULL, }, /* 24 */ - { 0x0004080004080004ULL, 0x0800040800040800ULL, }, - { 0x0805000607000408ULL, 0x0102080300080500ULL, }, - { 0x0003080201080400ULL, 0x0706000508000308ULL, }, - { 0x0806000408020008ULL, 0x0600040802000806ULL, }, - { 0x0002080400060800ULL, 0x0208040006080002ULL, }, - { 0x0807000208050004ULL, 0x0803000608010008ULL, }, - { 0x0001080600030804ULL, 0x0005080200070800ULL, }, - { 0x0808000008080000ULL, 0x0808000008080000ULL, }, /* 32 */ - { 0x0000080800000808ULL, 0x0000080800000808ULL, }, - { 0x0808010006080300ULL, 0x0408050002080700ULL, }, - { 0x0000070802000508ULL, 0x0400030806000108ULL, }, - { 0x0808020004080600ULL, 0x0008080200040806ULL, }, - { 0x0000060804000208ULL, 0x0800000608040002ULL, }, - { 0x0808030002080801ULL, 0x0004080700000608ULL, }, - { 0x0000050806000007ULL, 0x0804000108080200ULL, }, - { 0x0808040000080804ULL, 0x0000080804000008ULL, }, /* 40 */ - { 0x0000040808000004ULL, 0x0808000004080800ULL, }, - { 0x0808050000060807ULL, 0x0000040808010002ULL, }, - { 0x0000030808020001ULL, 0x0808040000070806ULL, }, - { 0x0808060000040808ULL, 0x0200000808060000ULL, }, - { 0x0000020808040000ULL, 0x0608080000020808ULL, }, - { 0x0808070000020808ULL, 0x0500000408080300ULL, }, - { 0x0000010808060000ULL, 0x0308080400000508ULL, }, - { 0x0808080000000808ULL, 0x0800000008080800ULL, }, /* 48 */ - { 0x0000000808080000ULL, 0x0008080800000008ULL, }, - { 0x0808080100000608ULL, 0x0803000004080805ULL, }, - { 0x0000000708080200ULL, 0x0005080804000003ULL, }, - { 0x0808080200000408ULL, 0x0806000000080808ULL, }, - { 0x0000000608080400ULL, 0x0002080808000000ULL, }, - { 0x0808080300000208ULL, 0x0808010000040808ULL, }, - { 0x0000000508080600ULL, 0x0000070808040000ULL, }, - { 0x0808080400000008ULL, 0x0808040000000808ULL, }, /* 56 */ - { 0x0000000408080800ULL, 0x0000040808080000ULL, }, - { 0x0808080500000006ULL, 0x0808070000000408ULL, }, - { 0x0000000308080802ULL, 0x0000010808080400ULL, }, - { 0x0808080600000004ULL, 0x0808080200000008ULL, }, - { 0x0000000208080804ULL, 0x0000000608080800ULL, }, - { 0x0808080700000002ULL, 0x0808080500000004ULL, }, - { 0x0000000108080806ULL, 0x0000000308080804ULL, }, - { 0x0204050402030401ULL, 0x0405030507060302ULL, }, /* 64 */ - { 0x0706000404040501ULL, 0x0207060303060306ULL, }, - { 0x0404050405060401ULL, 0x0404040805040302ULL, }, - { 0x0305030405030404ULL, 0x0405020404020402ULL, }, - { 0x0503050506060203ULL, 0x0302050505050405ULL, }, - { 0x0304060308020406ULL, 0x0403020207040204ULL, }, - { 0x0405030204040503ULL, 0x0303010207040503ULL, }, - { 0x0605030404040602ULL, 0x0407040502020505ULL, }, - { 0x0104020504050503ULL, 0x0705030404040403ULL, }, /* 72 */ - { 0x0405050304050506ULL, 0x0402050302050504ULL, }, - { 0x0304060604050404ULL, 0x0403040305030502ULL, }, - { 0x0304050503030305ULL, 0x0404040505050306ULL, }, - { 0x0502030504030502ULL, 0x0303030504050403ULL, }, - { 0x0303040703030303ULL, 0x0603040404030405ULL, }, - { 0x0302020402060704ULL, 0x0604030705030204ULL, }, - { 0x0404050305040605ULL, 0x0404050504030405ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_PCNT_B(b128_pattern[i], b128_result[i]); - } else { - do_msa_PCNT_B(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_d.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_d.c deleted file mode 100644 index 3cc0d851b291..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_d.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction PCNT.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "PCNT.D"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000040ULL, 0x0000000000000040ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000021ULL, 0x0000000000000020ULL, }, - { 0x000000000000001fULL, 0x0000000000000020ULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, /* 8 */ - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000022ULL, 0x000000000000001fULL, }, - { 0x000000000000001eULL, 0x0000000000000021ULL, }, - { 0x0000000000000022ULL, 0x0000000000000020ULL, }, - { 0x000000000000001eULL, 0x0000000000000020ULL, }, - { 0x0000000000000023ULL, 0x000000000000001eULL, }, - { 0x000000000000001dULL, 0x0000000000000022ULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, /* 16 */ - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000024ULL, 0x000000000000001dULL, }, - { 0x000000000000001cULL, 0x0000000000000023ULL, }, - { 0x0000000000000022ULL, 0x0000000000000022ULL, }, - { 0x000000000000001eULL, 0x000000000000001eULL, }, - { 0x0000000000000021ULL, 0x0000000000000021ULL, }, - { 0x000000000000001fULL, 0x000000000000001fULL, }, - { 0x0000000000000024ULL, 0x0000000000000020ULL, }, /* 24 */ - { 0x000000000000001cULL, 0x0000000000000020ULL, }, - { 0x0000000000000026ULL, 0x000000000000001bULL, }, - { 0x000000000000001aULL, 0x0000000000000025ULL, }, - { 0x0000000000000024ULL, 0x0000000000000022ULL, }, - { 0x000000000000001cULL, 0x000000000000001eULL, }, - { 0x0000000000000022ULL, 0x0000000000000022ULL, }, - { 0x000000000000001eULL, 0x000000000000001eULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, /* 32 */ - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x0000000000000022ULL, 0x0000000000000022ULL, }, - { 0x000000000000001eULL, 0x000000000000001eULL, }, - { 0x0000000000000024ULL, 0x0000000000000024ULL, }, - { 0x000000000000001cULL, 0x000000000000001cULL, }, - { 0x0000000000000026ULL, 0x0000000000000021ULL, }, - { 0x000000000000001aULL, 0x000000000000001fULL, }, - { 0x0000000000000028ULL, 0x000000000000001cULL, }, /* 40 */ - { 0x0000000000000018ULL, 0x0000000000000024ULL, }, - { 0x000000000000002aULL, 0x0000000000000017ULL, }, - { 0x0000000000000016ULL, 0x0000000000000029ULL, }, - { 0x000000000000002aULL, 0x0000000000000018ULL, }, - { 0x0000000000000016ULL, 0x0000000000000028ULL, }, - { 0x0000000000000029ULL, 0x000000000000001cULL, }, - { 0x0000000000000017ULL, 0x0000000000000024ULL, }, - { 0x0000000000000028ULL, 0x0000000000000020ULL, }, /* 48 */ - { 0x0000000000000018ULL, 0x0000000000000020ULL, }, - { 0x0000000000000027ULL, 0x0000000000000024ULL, }, - { 0x0000000000000019ULL, 0x000000000000001cULL, }, - { 0x0000000000000026ULL, 0x0000000000000026ULL, }, - { 0x000000000000001aULL, 0x000000000000001aULL, }, - { 0x0000000000000025ULL, 0x0000000000000025ULL, }, - { 0x000000000000001bULL, 0x000000000000001bULL, }, - { 0x0000000000000024ULL, 0x0000000000000024ULL, }, /* 56 */ - { 0x000000000000001cULL, 0x000000000000001cULL, }, - { 0x0000000000000023ULL, 0x0000000000000023ULL, }, - { 0x000000000000001dULL, 0x000000000000001dULL, }, - { 0x0000000000000022ULL, 0x0000000000000022ULL, }, - { 0x000000000000001eULL, 0x000000000000001eULL, }, - { 0x0000000000000021ULL, 0x0000000000000021ULL, }, - { 0x000000000000001fULL, 0x000000000000001fULL, }, - { 0x0000000000000019ULL, 0x0000000000000023ULL, }, /* 64 */ - { 0x000000000000001fULL, 0x0000000000000024ULL, }, - { 0x0000000000000021ULL, 0x0000000000000022ULL, }, - { 0x000000000000001fULL, 0x000000000000001bULL, }, - { 0x0000000000000023ULL, 0x0000000000000022ULL, }, - { 0x0000000000000024ULL, 0x000000000000001cULL, }, - { 0x000000000000001eULL, 0x000000000000001cULL, }, - { 0x0000000000000022ULL, 0x0000000000000022ULL, }, - { 0x000000000000001dULL, 0x0000000000000022ULL, }, /* 72 */ - { 0x0000000000000025ULL, 0x000000000000001eULL, }, - { 0x0000000000000024ULL, 0x000000000000001dULL, }, - { 0x000000000000001fULL, 0x0000000000000024ULL, }, - { 0x000000000000001dULL, 0x000000000000001eULL, }, - { 0x000000000000001dULL, 0x0000000000000021ULL, }, - { 0x000000000000001eULL, 0x0000000000000022ULL, }, - { 0x0000000000000024ULL, 0x0000000000000022ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_PCNT_D(b128_pattern[i], b128_result[i]); - } else { - do_msa_PCNT_D(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_h.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_h.c deleted file mode 100644 index f1052b3c26a3..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_h.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction PCNT.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "PCNT.H"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0010001000100010ULL, 0x0010001000100010ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0009000800070009ULL, 0x0008000700090008ULL, }, - { 0x0007000800090007ULL, 0x0008000900070008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, /* 8 */ - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x000a000700080009ULL, 0x0006000a00070008ULL, }, - { 0x0006000900080007ULL, 0x000a000600090008ULL, }, - { 0x000a00080006000aULL, 0x00080006000a0008ULL, }, - { 0x00060008000a0006ULL, 0x0008000a00060008ULL, }, - { 0x0009000900090008ULL, 0x0007000700070009ULL, }, - { 0x0007000700070008ULL, 0x0009000900090007ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, /* 16 */ - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0009000900090009ULL, 0x0008000700070007ULL, }, - { 0x0007000700070007ULL, 0x0008000900090009ULL, }, - { 0x000a000a00080006ULL, 0x0006000a000a0008ULL, }, - { 0x000600060008000aULL, 0x000a000600060008ULL, }, - { 0x000b000a00050007ULL, 0x000b000800050009ULL, }, - { 0x00050006000b0009ULL, 0x00050008000b0007ULL, }, - { 0x000c00080004000cULL, 0x00080004000c0008ULL, }, /* 24 */ - { 0x00040008000c0004ULL, 0x0008000c00040008ULL, }, - { 0x000d00060007000cULL, 0x0003000b00080005ULL, }, - { 0x0003000a00090004ULL, 0x000d00050008000bULL, }, - { 0x000e0004000a0008ULL, 0x0006000c0002000eULL, }, - { 0x0002000c00060008ULL, 0x000a0004000e0002ULL, }, - { 0x000f0002000d0004ULL, 0x000b000600090008ULL, }, - { 0x0001000e0003000cULL, 0x0005000a00070008ULL, }, - { 0x0010000000100000ULL, 0x0010000000100000ULL, }, /* 32 */ - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x00100001000e0003ULL, 0x000c0005000a0007ULL, }, - { 0x0000000f0002000dULL, 0x0004000b00060009ULL, }, - { 0x00100002000c0006ULL, 0x0008000a0004000eULL, }, - { 0x0000000e0004000aULL, 0x00080006000c0002ULL, }, - { 0x00100003000a0009ULL, 0x0004000f0000000eULL, }, - { 0x0000000d00060007ULL, 0x000c000100100002ULL, }, - { 0x001000040008000cULL, 0x0000001000040008ULL, }, /* 40 */ - { 0x0000000c00080004ULL, 0x00100000000c0008ULL, }, - { 0x001000050006000fULL, 0x0000000c00090002ULL, }, - { 0x0000000b000a0001ULL, 0x001000040007000eULL, }, - { 0x0010000600040010ULL, 0x00020008000e0000ULL, }, - { 0x0000000a000c0000ULL, 0x000e000800020010ULL, }, - { 0x0010000700020010ULL, 0x0005000400100003ULL, }, - { 0x00000009000e0000ULL, 0x000b000c0000000dULL, }, - { 0x0010000800000010ULL, 0x0008000000100008ULL, }, /* 48 */ - { 0x0000000800100000ULL, 0x0008001000000008ULL, }, - { 0x001000090000000eULL, 0x000b0000000c000dULL, }, - { 0x0000000700100002ULL, 0x0005001000040003ULL, }, - { 0x0010000a0000000cULL, 0x000e000000080010ULL, }, - { 0x0000000600100004ULL, 0x0002001000080000ULL, }, - { 0x0010000b0000000aULL, 0x0010000100040010ULL, }, - { 0x0000000500100006ULL, 0x0000000f000c0000ULL, }, - { 0x0010000c00000008ULL, 0x0010000400000010ULL, }, /* 56 */ - { 0x0000000400100008ULL, 0x0000000c00100000ULL, }, - { 0x0010000d00000006ULL, 0x001000070000000cULL, }, - { 0x000000030010000aULL, 0x0000000900100004ULL, }, - { 0x0010000e00000004ULL, 0x0010000a00000008ULL, }, - { 0x000000020010000cULL, 0x0000000600100008ULL, }, - { 0x0010000f00000002ULL, 0x0010000d00000004ULL, }, - { 0x000000010010000eULL, 0x000000030010000cULL, }, - { 0x0006000900050005ULL, 0x00090008000d0005ULL, }, /* 64 */ - { 0x000d000400080006ULL, 0x0009000900090009ULL, }, - { 0x00080009000b0005ULL, 0x0008000c00090005ULL, }, - { 0x0008000700080008ULL, 0x0009000600060006ULL, }, - { 0x0008000a000c0005ULL, 0x0005000a000a0009ULL, }, - { 0x00070009000a000aULL, 0x00070004000b0006ULL, }, - { 0x0009000500080008ULL, 0x00060003000b0008ULL, }, - { 0x000b000700080008ULL, 0x000b00090004000aULL, }, - { 0x0005000700090008ULL, 0x000c000700080007ULL, }, /* 72 */ - { 0x000900080009000bULL, 0x0006000800070009ULL, }, - { 0x0007000c00090008ULL, 0x0007000700080007ULL, }, - { 0x0007000a00060008ULL, 0x00080009000a0009ULL, }, - { 0x0007000800070007ULL, 0x0006000800090007ULL, }, - { 0x0006000b00060006ULL, 0x0009000800070009ULL, }, - { 0x000500060008000bULL, 0x000a000a00080006ULL, }, - { 0x000800080009000bULL, 0x0008000a00070009ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_PCNT_H(b128_pattern[i], b128_result[i]); - } else { - do_msa_PCNT_H(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_w.c b/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_w.c deleted file mode 100644 index 625ef29406b7..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-count/test_msa_pcnt_w.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction PCNT.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Count"; - char *instruction_name = "PCNT.W"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000002000000020ULL, 0x0000002000000020ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001100000010ULL, 0x0000000f00000011ULL, }, - { 0x0000000f00000010ULL, 0x000000110000000fULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, /* 8 */ - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001100000011ULL, 0x000000100000000fULL, }, - { 0x0000000f0000000fULL, 0x0000001000000011ULL, }, - { 0x0000001200000010ULL, 0x0000000e00000012ULL, }, - { 0x0000000e00000010ULL, 0x000000120000000eULL, }, - { 0x0000001200000011ULL, 0x0000000e00000010ULL, }, - { 0x0000000e0000000fULL, 0x0000001200000010ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, /* 16 */ - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001200000012ULL, 0x0000000f0000000eULL, }, - { 0x0000000e0000000eULL, 0x0000001100000012ULL, }, - { 0x000000140000000eULL, 0x0000001000000012ULL, }, - { 0x0000000c00000012ULL, 0x000000100000000eULL, }, - { 0x000000150000000cULL, 0x000000130000000eULL, }, - { 0x0000000b00000014ULL, 0x0000000d00000012ULL, }, - { 0x0000001400000010ULL, 0x0000000c00000014ULL, }, /* 24 */ - { 0x0000000c00000010ULL, 0x000000140000000cULL, }, - { 0x0000001300000013ULL, 0x0000000e0000000dULL, }, - { 0x0000000d0000000dULL, 0x0000001200000013ULL, }, - { 0x0000001200000012ULL, 0x0000001200000010ULL, }, - { 0x0000000e0000000eULL, 0x0000000e00000010ULL, }, - { 0x0000001100000011ULL, 0x0000001100000011ULL, }, - { 0x0000000f0000000fULL, 0x0000000f0000000fULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, /* 32 */ - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000001100000011ULL, 0x0000001100000011ULL, }, - { 0x0000000f0000000fULL, 0x0000000f0000000fULL, }, - { 0x0000001200000012ULL, 0x0000001200000012ULL, }, - { 0x0000000e0000000eULL, 0x0000000e0000000eULL, }, - { 0x0000001300000013ULL, 0x000000130000000eULL, }, - { 0x0000000d0000000dULL, 0x0000000d00000012ULL, }, - { 0x0000001400000014ULL, 0x000000100000000cULL, }, /* 40 */ - { 0x0000000c0000000cULL, 0x0000001000000014ULL, }, - { 0x0000001500000015ULL, 0x0000000c0000000bULL, }, - { 0x0000000b0000000bULL, 0x0000001400000015ULL, }, - { 0x0000001600000014ULL, 0x0000000a0000000eULL, }, - { 0x0000000a0000000cULL, 0x0000001600000012ULL, }, - { 0x0000001700000012ULL, 0x0000000900000013ULL, }, - { 0x000000090000000eULL, 0x000000170000000dULL, }, - { 0x0000001800000010ULL, 0x0000000800000018ULL, }, /* 48 */ - { 0x0000000800000010ULL, 0x0000001800000008ULL, }, - { 0x000000190000000eULL, 0x0000000b00000019ULL, }, - { 0x0000000700000012ULL, 0x0000001500000007ULL, }, - { 0x0000001a0000000cULL, 0x0000000e00000018ULL, }, - { 0x0000000600000014ULL, 0x0000001200000008ULL, }, - { 0x0000001b0000000aULL, 0x0000001100000014ULL, }, - { 0x0000000500000016ULL, 0x0000000f0000000cULL, }, - { 0x0000001c00000008ULL, 0x0000001400000010ULL, }, /* 56 */ - { 0x0000000400000018ULL, 0x0000000c00000010ULL, }, - { 0x0000001d00000006ULL, 0x000000170000000cULL, }, - { 0x000000030000001aULL, 0x0000000900000014ULL, }, - { 0x0000001e00000004ULL, 0x0000001a00000008ULL, }, - { 0x000000020000001cULL, 0x0000000600000018ULL, }, - { 0x0000001f00000002ULL, 0x0000001d00000004ULL, }, - { 0x000000010000001eULL, 0x000000030000001cULL, }, - { 0x0000000f0000000aULL, 0x0000001100000012ULL, }, /* 64 */ - { 0x000000110000000eULL, 0x0000001200000012ULL, }, - { 0x0000001100000010ULL, 0x000000140000000eULL, }, - { 0x0000000f00000010ULL, 0x0000000f0000000cULL, }, - { 0x0000001200000011ULL, 0x0000000f00000013ULL, }, - { 0x0000001000000014ULL, 0x0000000b00000011ULL, }, - { 0x0000000e00000010ULL, 0x0000000900000013ULL, }, - { 0x0000001200000010ULL, 0x000000140000000eULL, }, - { 0x0000000c00000011ULL, 0x000000130000000fULL, }, /* 72 */ - { 0x0000001100000014ULL, 0x0000000e00000010ULL, }, - { 0x0000001300000011ULL, 0x0000000e0000000fULL, }, - { 0x000000110000000eULL, 0x0000001100000013ULL, }, - { 0x0000000f0000000eULL, 0x0000000e00000010ULL, }, - { 0x000000110000000cULL, 0x0000001100000010ULL, }, - { 0x0000000b00000013ULL, 0x000000140000000eULL, }, - { 0x0000001000000014ULL, 0x0000001200000010ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_PCNT_W(b128_pattern[i], b128_result[i]); - } else { - do_msa_PCNT_W(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_b.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_b.c deleted file mode 100644 index 4a34f69953b7..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSL.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSL.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x9c71e7cc71675471ULL, 0x4767015ffe71c70cULL, }, /* 64 */ - { 0x8c6be7cc29675571ULL, 0x4767015ffe7ba70cULL, }, - { 0x8c6be7cc29625571ULL, 0x4b670b5efe7bb30cULL, }, - { 0x8c6ae7cc29625541ULL, 0x4b670b5efe7bb30cULL, }, - { 0x8caa01642982c541ULL, 0x1bf7bb1a143b33fcULL, }, - { 0xfcbe01644d92c741ULL, 0x1bf7bb1a143f53fcULL, }, - { 0xfcbe01644d93c741ULL, 0x12f7bb1a143f53fcULL, }, - { 0xfcbe01604d93c709ULL, 0x12f7bb1a143f53fcULL, }, - { 0xfc5eafa8cdd38b89ULL, 0x22d8cbfeaa2f5314ULL, }, /* 72 */ - { 0xac5aafa8b9c38b89ULL, 0x22d8cbfeaa2b3314ULL, }, - { 0xac5aafa8b9cf8b89ULL, 0x27d8c7ffaa2b2714ULL, }, - { 0xac5aafa8b9cf8b81ULL, 0x27d8c7ffaa2b2714ULL, }, - { 0x2c5a1748392fe301ULL, 0x87f187d9a84ba7a4ULL, }, - { 0x7c4e17485d3fe201ULL, 0x87f187d9a842e7a4ULL, }, - { 0x744e17485d31e201ULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, /* 80 */ - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, /* 88 */ - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x744f174c5f31e24fULL, 0x8df189d8a842e3a4ULL, }, - { 0x8c6ae6cc28714240ULL, 0x49710958a862b30cULL, }, /* 96 */ - { 0x8c6ae6cc28714240ULL, 0x49710958a862b30cULL, }, - { 0x8c6ae6cc28714240ULL, 0x49710958a862b30cULL, }, - { 0x8c6ae6cc28714240ULL, 0x49710958a862b30cULL, }, - { 0xfcaa006428b1c240ULL, 0x09f18958282253fcULL, }, - { 0xfcaa006428b1c240ULL, 0x09f18958282253fcULL, }, - { 0xfcaa006428b1c240ULL, 0x09f18958282253fcULL, }, - { 0xfcaa006428b1c240ULL, 0x09f18958282253fcULL, }, - { 0xac4a80aca8f182c0ULL, 0x09f1c9d8a8222314ULL, }, /* 104 */ - { 0xac4a80aca8f182c0ULL, 0x09f1c9d8a8222314ULL, }, - { 0xac4a80aca8f182c0ULL, 0x09f1c9d8a8222314ULL, }, - { 0xac4a80aca8f182c0ULL, 0x09f1c9d8a8222314ULL, }, - { 0x744a004c2831e240ULL, 0x89f189d8a842e3a4ULL, }, - { 0x744a004c2831e240ULL, 0x89f189d8a842e3a4ULL, }, - { 0x744a004c2831e240ULL, 0x89f189d8a842e3a4ULL, }, - { 0x744a004c2831e240ULL, 0x89f189d8a842e3a4ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_d.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_d.c deleted file mode 100644 index 0fc44fa19583..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSL.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSL.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x9c71c71c71c71c71ULL, 0x4b6471c71c71c71cULL, }, /* 64 */ - { 0x8871c71c71c71c71ULL, 0x4b670b5efe7bb00cULL, }, - { 0x8871c71c71c71c71ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886bc71c71c71c71ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886bc71c71c71c71ULL, 0x12f70b5efe7bb00cULL, }, - { 0xfbebc71c71c71c71ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbebc71c71c71c71ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbfc71c71c71c71ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbfc71c71c71c71ULL, 0x27dfbb1a153f52fcULL, }, /* 72 */ - { 0xac3fc71c71c71c71ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac3fc71c71c71c71ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5bc71c71c71c71ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x2c5bc71c71c71c71ULL, 0x8df0c6ffab2b2514ULL, }, - { 0x705bc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x705bc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, /* 80 */ - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, /* 88 */ - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704fc71c71c71c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x886ae6cc28625c71ULL, 0x4b670b5ef942e2a4ULL, }, /* 96 */ - { 0x886ae6cc28625c71ULL, 0x4b670b5ef942e2a4ULL, }, - { 0x886ae6cc28625c71ULL, 0x4b670b5ef942e2a4ULL, }, - { 0x886ae6cc28625c71ULL, 0x4b670b5ef942e2a4ULL, }, - { 0xfbbe00634d93dc71ULL, 0x12f7bb1a1142e2a4ULL, }, - { 0xfbbe00634d93dc71ULL, 0x12f7bb1a1142e2a4ULL, }, - { 0xfbbe00634d93dc71ULL, 0x12f7bb1a1142e2a4ULL, }, - { 0xfbbe00634d93dc71ULL, 0x12f7bb1a1142e2a4ULL, }, - { 0xac5aaeaab9cf9c71ULL, 0x27d8c6ffa942e2a4ULL, }, /* 104 */ - { 0xac5aaeaab9cf9c71ULL, 0x27d8c6ffa942e2a4ULL, }, - { 0xac5aaeaab9cf9c71ULL, 0x27d8c6ffa942e2a4ULL, }, - { 0xac5aaeaab9cf9c71ULL, 0x27d8c6ffa942e2a4ULL, }, - { 0x704f164d5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704f164d5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704f164d5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704f164d5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_h.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_h.c deleted file mode 100644 index cc2db04a2d45..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSL.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSL.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x8871e6cc31c71c71ULL, 0x4b1c0b5ffe71b00cULL, }, /* 64 */ - { 0x886be6cc21c75571ULL, 0x4b1c0b5ffe7bb00cULL, }, - { 0x886be6cc28625571ULL, 0x4b1c0b5efe7bb00cULL, }, - { 0x886ae6cc28625541ULL, 0x4b1c0b5efe7bb00cULL, }, - { 0xfbaa00644862d541ULL, 0x121cbb1a153b52fcULL, }, - { 0xfbbe00644862c741ULL, 0x121cbb1a153f52fcULL, }, - { 0xfbbe00644d93c741ULL, 0x129cbb1a153f52fcULL, }, - { 0xfbbe00604d93c709ULL, 0x129cbb1a153f52fcULL, }, - { 0xac5eaea8ad93c709ULL, 0x279cc6feab2f2514ULL, }, /* 72 */ - { 0xac5aaea8bd938b89ULL, 0x279cc6feab2b2514ULL, }, - { 0xac5aaea8b9cf8b89ULL, 0x279cc6ffab2b2514ULL, }, - { 0xac5aaea8b9cf8b81ULL, 0x279cc6ffab2b2514ULL, }, - { 0x705a164859cf8b81ULL, 0x8d9c88d9a94be2a4ULL, }, - { 0x704e164859cfe201ULL, 0x8d9c88d9a942e2a4ULL, }, - { 0x704e16485e31e201ULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, /* 80 */ - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, /* 88 */ - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x704f164c5e31e24fULL, 0x8d9c88d8a942e2a4ULL, }, - { 0x886ae6cc1e315540ULL, 0x4b640b58e942b2a4ULL, }, /* 96 */ - { 0x886ae6cc1e315540ULL, 0x4b640b58e942b2a4ULL, }, - { 0x886ae6cc1e315540ULL, 0x4b640b58e942b2a4ULL, }, - { 0x886ae6cc1e315540ULL, 0x4b640b58e942b2a4ULL, }, - { 0xfbaa00645e31d540ULL, 0x1364bb58094252a4ULL, }, - { 0xfbaa00645e31d540ULL, 0x1364bb58094252a4ULL, }, - { 0xfbaa00645e31d540ULL, 0x1364bb58094252a4ULL, }, - { 0xfbaa00645e31d540ULL, 0x1364bb58094252a4ULL, }, - { 0xac4aa8649e31d540ULL, 0x2364c6d8a94222a4ULL, }, /* 104 */ - { 0xac4aa8649e31d540ULL, 0x2364c6d8a94222a4ULL, }, - { 0xac4aa8649e31d540ULL, 0x2364c6d8a94222a4ULL, }, - { 0xac4aa8649e31d540ULL, 0x2364c6d8a94222a4ULL, }, - { 0x704a10645e31d540ULL, 0x8b6488d8a942e2a4ULL, }, - { 0x704a10645e31d540ULL, 0x8b6488d8a942e2a4ULL, }, - { 0x704a10645e31d540ULL, 0x8b6488d8a942e2a4ULL, }, - { 0x704a10645e31d540ULL, 0x8b6488d8a942e2a4ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_w.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_w.c deleted file mode 100644 index 21d6eec4dbcc..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsl_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSL.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSL.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x8869c71c71c71c71ULL, 0x4b670b5ffe79c71cULL, }, /* 64 */ - { 0x8869c71c28471c71ULL, 0x4b670b5ffe7bb00cULL, }, - { 0x8869c71c28471c71ULL, 0x4b670b5efe7bb00cULL, }, - { 0x8869c71c28631c71ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbb9c71c28631c71ULL, 0x12f7bb1a153bb00cULL, }, - { 0xfbb9c71c4de31c71ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbb9c71c4de31c71ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbdc71c4d931c71ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5dc71ccd931c71ULL, 0x27d8c6feab2f52fcULL, }, /* 72 */ - { 0xac5dc71cb9931c71ULL, 0x27d8c6feab2b2514ULL, }, - { 0xac5dc71cb9931c71ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac59c71cb9cf1c71ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x7049c71c39cf1c71ULL, 0x8df188d9a9432514ULL, }, - { 0x7049c71c5e4f1c71ULL, 0x8df188d9a942e2a4ULL, }, - { 0x7049c71c5e4f1c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, /* 80 */ - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, /* 88 */ - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704dc71c5e311c71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x886ae6cc28625c71ULL, 0x4b670b58f942e2a4ULL, }, /* 96 */ - { 0x886ae6cc28625c71ULL, 0x4b670b58f942e2a4ULL, }, - { 0x886ae6cc28625c71ULL, 0x4b670b58f942e2a4ULL, }, - { 0x886ae6cc28625c71ULL, 0x4b670b58f942e2a4ULL, }, - { 0xfbbae6cc4d93dc71ULL, 0x12f7bb581142e2a4ULL, }, - { 0xfbbae6cc4d93dc71ULL, 0x12f7bb581142e2a4ULL, }, - { 0xfbbae6cc4d93dc71ULL, 0x12f7bb581142e2a4ULL, }, - { 0xfbbae6cc4d93dc71ULL, 0x12f7bb581142e2a4ULL, }, - { 0xac5ae6ccb9cf9c71ULL, 0x27d8c6d8a942e2a4ULL, }, /* 104 */ - { 0xac5ae6ccb9cf9c71ULL, 0x27d8c6d8a942e2a4ULL, }, - { 0xac5ae6ccb9cf9c71ULL, 0x27d8c6d8a942e2a4ULL, }, - { 0xac5ae6ccb9cf9c71ULL, 0x27d8c6d8a942e2a4ULL, }, - { 0x704ae6cc5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704ae6cc5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704ae6cc5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - { 0x704ae6cc5e31dc71ULL, 0x8df188d8a942e2a4ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSL_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_b.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_b.c deleted file mode 100644 index b1927c5c343f..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSR.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSR.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c72e60c70c21570ULL, 0xcb677bde7e7bc60cULL, }, /* 64 */ - { 0x186ae60c68c25570ULL, 0xcb677bde7e7bc00cULL, }, - { 0x086ae60c68625570ULL, 0x4b670b5e7e7bf00cULL, }, - { 0x086ae60c28625540ULL, 0x4b670b5e7e7bf00cULL, }, - { 0x096e800329634740ULL, 0x42f70b1a157ff01cULL, }, - { 0x0b3e80030d63c740ULL, 0x42f70b1a153ff21cULL, }, - { 0x1b3e80030d93c740ULL, 0x12f73b1a153fd21cULL, }, - { 0x1bbe80234d93c708ULL, 0x12f73b1a153fd21cULL, }, - { 0x1abaae2a4d97cb08ULL, 0x17d8367f2b3bd314ULL, }, /* 72 */ - { 0x1cdaae2a799f8b08ULL, 0x17d8367f2b2bd514ULL, }, - { 0x0cdaae2a79cf8b08ULL, 0x27d846ff2b2be514ULL, }, - { 0x0c5aae2a39cf8b00ULL, 0x27d846ff2b2be514ULL, }, - { 0x0c5f962d38c9a200ULL, 0x2df148d82922e400ULL, }, - { 0x004f962d1ec1e200ULL, 0x2df148d82942e200ULL, }, - { 0x104f962d1e31e200ULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, /* 80 */ - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, /* 88 */ - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x104f960d5e31e24eULL, 0x8df108d82942e200ULL, }, - { 0x106ae60c2832e540ULL, 0x8bf309d82a43e000ULL, }, /* 96 */ - { 0x106ae60c2832d540ULL, 0x8bf70bd82e4be000ULL, }, - { 0x106ae60c2832d540ULL, 0x8b670bd87e4be000ULL, }, - { 0x106ae60c2832d540ULL, 0x8b670bd87e4be000ULL, }, - { 0x116e80032933c740ULL, 0x82f70bd8154fe000ULL, }, - { 0x133e80032933c740ULL, 0x82f70bd8153fe000ULL, }, - { 0x1b3e80032933c740ULL, 0x82f70bd8153fe000ULL, }, - { 0x1b3e80032933c740ULL, 0x82f70bd8153fe000ULL, }, - { 0x1c5a800a293f8b40ULL, 0x87d806d92b2be100ULL, }, /* 104 */ - { 0x0c5a800a29cf8b40ULL, 0x27d846db2b2be100ULL, }, - { 0x0c5a800a29cf8b40ULL, 0x27d846df2b2be100ULL, }, - { 0x0c5a800a29cf8b40ULL, 0x27d846ff2b2be100ULL, }, - { 0x105f800d2a318240ULL, 0x8dd908d82922e200ULL, }, - { 0x104f800d2e318240ULL, 0x8dd908d82922e200ULL, }, - { 0x104f800d5e318240ULL, 0x8dd908d82922e200ULL, }, - { 0x104f800d5e318240ULL, 0x8dd908d82922e200ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_d.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_d.c deleted file mode 100644 index 6499415daa82..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSR.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSR.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71d00cULL, }, /* 64 */ - { 0x1c71c71c71c71d40ULL, 0xcb670b5efe7bb00cULL, }, - { 0x1c71c71c71c71d40ULL, 0xcb670b5efe7bb00cULL, }, - { 0x1c71c71c71c75540ULL, 0xcb670b5efe7bb00cULL, }, - { 0x1c71c71c71c75540ULL, 0xcb670b5efe7bb2fcULL, }, - { 0x1c71c71c71c75508ULL, 0xd2f7bb1a153f52fcULL, }, - { 0x1c71c71c71c75508ULL, 0xd2f7bb1a153f52fcULL, }, - { 0x1c71c71c71c74708ULL, 0xd2f7bb1a153f52fcULL, }, - { 0x1c71c71c71c74708ULL, 0xd2f7bb1a153f4514ULL, }, /* 72 */ - { 0x1c71c71c71c74780ULL, 0xc7d8c6ffab2b2514ULL, }, - { 0x1c71c71c71c74780ULL, 0xc7d8c6ffab2b2514ULL, }, - { 0x1c71c71c71c70b80ULL, 0xc7d8c6ffab2b2514ULL, }, - { 0x1c71c71c71c70b80ULL, 0xc7d8c6ffab2b22a0ULL, }, - { 0x1c71c71c71c70a4eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c70a4eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, /* 80 */ - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, /* 88 */ - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c7624eULL, 0xcdf188d8a942e2a0ULL, }, - { 0x1c71c71c71c75540ULL, 0xcdf188d8fe7bb00cULL, }, /* 96 */ - { 0x1c71c71c71c75540ULL, 0xcdf188d8fe7bb00cULL, }, - { 0x1c71c71c71c75540ULL, 0xcdf188d8fe7bb00cULL, }, - { 0x1c71c71c71c75540ULL, 0xcdf188d8fe7bb00cULL, }, - { 0x1c71c71c71c75540ULL, 0xcdf188d8fe7bb2fcULL, }, - { 0x1c71c71c71c75540ULL, 0xd2f7bb1a153f52fcULL, }, - { 0x1c71c71c71c75540ULL, 0xd2f7bb1a153f52fcULL, }, - { 0x1c71c71c71c75540ULL, 0xd2f7bb1a153f52fcULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6ffab2b2514ULL, }, /* 104 */ - { 0x1c71c71c71c75540ULL, 0xc7d8c6ffab2b2514ULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6ffab2b2514ULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6ffab2b2514ULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6ffab22e2a0ULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6fea942e2a0ULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6fea942e2a0ULL, }, - { 0x1c71c71c71c75540ULL, 0xc7d8c6fea942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_h.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_h.c deleted file mode 100644 index 2dc3dbe89b7d..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSR.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSR.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x186ac6cc71c21c70ULL, 0xc7670b5e1e7bd00cULL, }, /* 64 */ - { 0x086ac6cc71c21d40ULL, 0xc7670b5efe7bd00cULL, }, - { 0x086ac6cc28621d40ULL, 0xc7670b5efe7bd00cULL, }, - { 0x886ae6cc28625540ULL, 0xc7670b5efe7bd00cULL, }, - { 0x8bbee06328635540ULL, 0xc7f73b1af53fd2fcULL, }, - { 0xfbbee06328635508ULL, 0xc7f73b1a153fd2fcULL, }, - { 0xfbbee0634d935508ULL, 0xc6f7bb1a153fd2fcULL, }, - { 0xfbbec0634d934708ULL, 0xc6f7bb1a153fd2fcULL, }, - { 0xfc5aceaa4d974708ULL, 0xc6d8c6ff1b2bc514ULL, }, /* 72 */ - { 0xac5aceaa4d9f4780ULL, 0xc6d8c6ffab2bc514ULL, }, - { 0xac5aceaab9cf4780ULL, 0xc7d8c6ffab2bc514ULL, }, - { 0xac5aeeaab9cf0b80ULL, 0xc7d8c6ffab2bc514ULL, }, - { 0xa84ff64db9c90b80ULL, 0xc7f188d8a942c2a0ULL, }, - { 0xf04ff64db9c10a4eULL, 0xc7f188d8a942c2a0ULL, }, - { 0xf04ff64d5e310a4eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, /* 80 */ - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, /* 88 */ - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e31624eULL, 0xc7f188d8a942c2a0ULL, }, - { 0x886ae6cc5e325540ULL, 0xc7f3895ea943c2a0ULL, }, /* 96 */ - { 0x886ae6cc5e325540ULL, 0xc7f78b5ea94bc2a0ULL, }, - { 0x886ae6cc5e325540ULL, 0xc7678b5eae7bc2a0ULL, }, - { 0x886ae6cc5e325540ULL, 0xc7678b5eae7bc2a0ULL, }, - { 0x8bbee0635e335540ULL, 0xc7f7bb1aa53fc2a0ULL, }, - { 0xfbbee0635e335540ULL, 0xc7f7bb1a153fc2a0ULL, }, - { 0xfbbee0635e335540ULL, 0xc7f7bb1a153fc2a0ULL, }, - { 0xfbbee0635e335540ULL, 0xc7f7bb1a153fc2a0ULL, }, - { 0xac5ae06a5e3f5540ULL, 0xc7d8beffab2bc2a0ULL, }, /* 104 */ - { 0xac5ae6aab9cf5540ULL, 0xc7d8c6ffab2bc2a0ULL, }, - { 0xac5ae6aab9cf5540ULL, 0xc7d8c6ffab2bc2a0ULL, }, - { 0xac5ae6aab9cf5540ULL, 0xc7d8c6ffab2bc2a0ULL, }, - { 0xa84fe64d5e315540ULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e315540ULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e315540ULL, 0xc7f188d8a942c2a0ULL, }, - { 0x704fd64d5e315540ULL, 0xc7f188d8a942c2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_w.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_w.c deleted file mode 100644 index 507318734007..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_binsr_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BINSR.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BINSR.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c6cc71c71c70ULL, 0xcb670b5e1c71d00cULL, }, /* 64 */ - { 0x1c71c6cc71c71d40ULL, 0xcb670b5e1e7bb00cULL, }, - { 0x1c71c6cc71c71d40ULL, 0x4b670b5e1e7bb00cULL, }, - { 0x1c71e6cc71c75540ULL, 0x4b670b5e1e7bb00cULL, }, - { 0x1c71e06371c75540ULL, 0x12f7bb1a1e7bb2fcULL, }, - { 0x1c71e06371c75508ULL, 0x12f7bb1a153f52fcULL, }, - { 0x1c71e06371c75508ULL, 0x12f7bb1a153f52fcULL, }, - { 0x1c71c06371c74708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x1c71ceaa71c74708ULL, 0x27d8c6ff153f4514ULL, }, /* 72 */ - { 0x1c71ceaa71c74780ULL, 0x27d8c6ff0b2b2514ULL, }, - { 0x1c71ceaa71c74780ULL, 0x27d8c6ff0b2b2514ULL, }, - { 0x1c71eeaa71c70b80ULL, 0x27d8c6ff0b2b2514ULL, }, - { 0x1c71f64d71c70b80ULL, 0x0df188d80b2b22a0ULL, }, - { 0x1c71f64d71c70a4eULL, 0x0df188d80942e2a0ULL, }, - { 0x1c71f64d71c70a4eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, /* 80 */ - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, /* 88 */ - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c7624eULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71e6cc71c75540ULL, 0x8d670b5e0942e2a0ULL, }, /* 96 */ - { 0x1c71e6cc71c75540ULL, 0xcb670b5e0942e2a0ULL, }, - { 0x1c71e6cc71c75540ULL, 0xcb670b5e0942e2a0ULL, }, - { 0x1c71e6cc71c75540ULL, 0xcb670b5e0942e2a0ULL, }, - { 0x1c71e06371c75540ULL, 0x92f7bb1a0942e2a0ULL, }, - { 0x1c71e06371c75540ULL, 0x92f7bb1a0942e2a0ULL, }, - { 0x1c71e06371c75540ULL, 0x92f7bb1a0942e2a0ULL, }, - { 0x1c71e06371c75540ULL, 0x92f7bb1a0942e2a0ULL, }, - { 0x1c71e06a71c75540ULL, 0x97d8c6ff0942e2a0ULL, }, /* 104 */ - { 0x1c71e6aa71c75540ULL, 0x27d8c6ff0942e2a0ULL, }, - { 0x1c71e6aa71c75540ULL, 0x27d8c6ff0942e2a0ULL, }, - { 0x1c71e6aa71c75540ULL, 0x27d8c6ff0942e2a0ULL, }, - { 0x1c71e64d71c75540ULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c75540ULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c75540ULL, 0x8df188d80942e2a0ULL, }, - { 0x1c71d64d71c75540ULL, 0x8df188d80942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BINSR_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bmnz_v.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bmnz_v.c deleted file mode 100644 index ba1c635087aa..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bmnz_v.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BMNZ.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BMNZ.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x9c7be7dc79e75d71ULL, 0xcf7f7bdffe7bf71cULL, }, /* 64 */ - { 0x8c6be7dc38665d71ULL, 0xcf6f4bdffe7bb50cULL, }, - { 0x886be7dc28625571ULL, 0xcb670b5efe7bb00cULL, }, - { 0x886ae7dc28625571ULL, 0x4b670b5efe7bb00cULL, }, - { 0x882a015008024531ULL, 0x02670b1a143b100cULL, }, - { 0xfbbe01734d93c739ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe01734d93c739ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe01734d93c739ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbdea7bb6dd38339ULL, 0x13d0b25eab2f62f4ULL, }, /* 72 */ - { 0xa85aa7ba29c38331ULL, 0x03d0825eab2b2014ULL, }, - { 0xac5aafbab9cf8bb1ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aafbab9cf8bb1ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x245a0f7e99adcaf1ULL, 0x2df9ccf9a942a510ULL, }, - { 0x744e0f5ddc3dcaf9ULL, 0x2df9ccf9a942e7a0ULL, }, - { 0x704e075d5c31c279ULL, 0x0df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, /* 80 */ - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, /* 88 */ - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f175d5e31e27fULL, 0x8df188d8a942e2a0ULL, }, - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, /* 96 */ - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, - { 0x000a004008004000ULL, 0x0061081800020000ULL, }, - { 0x000a004008004000ULL, 0x0061081800020000ULL, }, - { 0x000a004008004000ULL, 0x0061081800020000ULL, }, - { 0x000a004008004000ULL, 0x0061081800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, /* 104 */ - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BMNZ_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BMNZ_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BMNZ_V__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BMNZ_V__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bmz_v.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bmz_v.c deleted file mode 100644 index b38ddc2c1293..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bmz_v.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BMZ.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BMZ.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0860c60c20421440ULL, 0x430401461c71800cULL, }, /* 64 */ - { 0x0860e68c20621440ULL, 0x4b040146fe71a00cULL, }, - { 0x0860e6cc20625440ULL, 0x4b270946fe71b00cULL, }, - { 0x8860e6cc20625540ULL, 0x4b270b46fe79b00cULL, }, - { 0xfbf4e6ef65f3d748ULL, 0x5bb7bb46ff7df2fcULL, }, - { 0xfbb400634593c708ULL, 0x12b7bb02153d52fcULL, }, - { 0xfbb400634593c708ULL, 0x12b7bb02153d52fcULL, }, - { 0xfbb400634593c708ULL, 0x12b7bb02153d52fcULL, }, - { 0xac300862918fcf80ULL, 0x26bfcfa31539151cULL, }, /* 72 */ - { 0xac70aeeab1cfcf80ULL, 0x27bfcfe7bf39351cULL, }, - { 0xac50aeaab1cf8b80ULL, 0x2798c6e7ab292514ULL, }, - { 0xac50aeaab1cf8b80ULL, 0x2798c6e7ab292514ULL, }, - { 0xf845b6897653a30eULL, 0x879082c6ab2962a4ULL, }, - { 0xf845160d5633a34eULL, 0x8f9082c2a969e2a4ULL, }, - { 0xf845164d5633e34eULL, 0x8fb18ac2a969e2a4ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, /* 80 */ - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, /* 88 */ - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0x7045164d5631e24eULL, 0x8db188c0a940e2a0ULL, }, - { 0xf86ff6cd7e73f74eULL, 0xcff78bdeff7bf2acULL, }, /* 96 */ - { 0xf86ff6cd7e73f74eULL, 0xcff78bdeff7bf2acULL, }, - { 0xf86ff6cd7e73f74eULL, 0xcff78bdeff7bf2acULL, }, - { 0xf86ff6cd7e73f74eULL, 0xcff78bdeff7bf2acULL, }, - { 0xfbfff6ef7ff3f74eULL, 0xdff7bbdeff7ff2fcULL, }, - { 0xfbfff6ef7ff3f74eULL, 0xdff7bbdeff7ff2fcULL, }, - { 0xfbfff6ef7ff3f74eULL, 0xdff7bbdeff7ff2fcULL, }, - { 0xfbfff6ef7ff3f74eULL, 0xdff7bbdeff7ff2fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, /* 104 */ - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BMZ_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BMZ_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BMZ_V__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BMZ_V__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bsel_v.c b/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bsel_v.c deleted file mode 100644 index 062e5a2fa031..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-move/test_msa_bsel_v.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction BSEL.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Move"; - char *instruction_name = "BSEL.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xefcefcefcefcefceULL, 0xfcefcefcefcefcefULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xaa8aa8aa8aa8aa8aULL, 0xa8aa8aa8aa8aa8aaULL, }, - { 0x0820820820820820ULL, 0x8208208208208208ULL, }, - { 0x5d75d75d75d75d75ULL, 0xd75d75d75d75d75dULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4544544544544544ULL, 0x5445445445445445ULL, }, - { 0x1451451451451451ULL, 0x4514514514514514ULL, }, - { 0xdcddcddcddcddcddULL, 0xcddcddcddcddcddcULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0c40c40c40c40c40ULL, 0xc40c40c40c40c40cULL, }, - { 0x3f73f73f73f73f73ULL, 0xf73f73f73f73f73fULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x2302302302302302ULL, 0x3023023023023023ULL, }, - { 0x1031031031031031ULL, 0x0310310310310310ULL, }, - { 0xf3bf3bf3bf3bf3bfULL, 0x3bf3bf3bf3bf3bf3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x4104104104104104ULL, 0x1041041041041041ULL, }, - { 0xe28e28e28e28e28eULL, 0x28e28e28e28e28e2ULL, }, - { 0x2302302302302302ULL, 0x3023023023023023ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1451451451451451ULL, 0x4514514514514514ULL, }, - { 0x0c60c60c60c60c60ULL, 0xc60c60c60c60c60cULL, }, - { 0x1031031031031031ULL, 0x0310310310310310ULL, }, - { 0x0c40c40c40c40c40ULL, 0xc40c40c40c40c40cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x882a004008024500ULL, 0x02670b1a143b100cULL, }, - { 0x884ae68c28621140ULL, 0x4b40025eea6ba004ULL, }, - { 0x006a064c08204440ULL, 0x09670958bc52b008ULL, }, - { 0xfbfe066f4db3c748ULL, 0x1bf7bb5abd7ff2fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xa81a002209838300ULL, 0x02d0821a012b0014ULL, }, - { 0x73ae00414c11c608ULL, 0x10f7b918151652e8ULL, }, - { 0x8c7aaeeab9ce4d80ULL, 0x276f4fffbe3b351cULL, }, /* 72 */ - { 0xa83a00620983c700ULL, 0x02f78b1a153b101cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x204a060818018200ULL, 0x05d080d8a9022000ULL, }, - { 0x504f164d4e30604eULL, 0x89610858a842e2a0ULL, }, - { 0x700e00415c11c208ULL, 0x04f18898010242a0ULL, }, - { 0x204b160c1a21a246ULL, 0x8dd080d8a942a000ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, /* 80 */ - { 0x000a004008004000ULL, 0x0061081800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, /* 88 */ - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x000a000008000000ULL, 0x0040001800020000ULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 96 */ - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbfee6ef6df3d748ULL, 0x5bf7bb5eff7ff2fcULL, }, - { 0xfbfee6ef6df3d748ULL, 0x5bf7bb5eff7ff2fcULL, }, - { 0xfbfee6ef6df3d748ULL, 0x5bf7bb5eff7ff2fcULL, }, - { 0xfbfee6ef6df3d748ULL, 0x5bf7bb5eff7ff2fcULL, }, - { 0xfffeeeeffdffdfc8ULL, 0x7fffffffff7ff7fcULL, }, /* 104 */ - { 0xfffeeeeffdffdfc8ULL, 0x7fffffffff7ff7fcULL, }, - { 0xfffeeeeffdffdfc8ULL, 0x7fffffffff7ff7fcULL, }, - { 0xfffeeeeffdffdfc8ULL, 0x7fffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - { 0xfffffeefffffffceULL, 0xffffffffff7ff7fcULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BSEL_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSEL_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSEL_V__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSEL_V__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_b.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_b.c deleted file mode 100644 index 56fdee3f31e4..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BCLR.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BCLR.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, /* 0 */ - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, - { 0xfbfbfbfbfbfbfbfbULL, 0xfbfbfbfbfbfbfbfbULL, }, - { 0xdfdfdfdfdfdfdfdfULL, 0xdfdfdfdfdfdfdfdfULL, }, - { 0xefefefefefefefefULL, 0xefefefefefefefefULL, }, - { 0xf7f7f7f7f7f7f7f7ULL, 0xf7f7f7f7f7f7f7f7ULL, }, - { 0xf7bffef7bffef7bfULL, 0xfef7bffef7bffef7ULL, }, - { 0xeffd7feffd7feffdULL, 0x7feffd7feffd7fefULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8a8a8a8a8a8a8a8aULL, 0x8a8a8a8a8a8a8a8aULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xa2a2a2a2a2a2a2a2ULL, 0xa2a2a2a2a2a2a2a2ULL, }, - { 0xa2aaaaa2aaaaa2aaULL, 0xaaa2aaaaa2aaaaa2ULL, }, - { 0xaaa82aaaa82aaaa8ULL, 0x2aaaa82aaaa82aaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, - { 0x5151515151515151ULL, 0x5151515151515151ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x4545454545454545ULL, 0x4545454545454545ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5515545515545515ULL, 0x5455155455155455ULL, }, - { 0x4555554555554555ULL, 0x5545555545555545ULL, }, - { 0x4c4c4c4c4c4c4c4cULL, 0x4c4c4c4c4c4c4c4cULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xc8c8c8c8c8c8c8c8ULL, 0xc8c8c8c8c8c8c8c8ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xc4c4c4c4c4c4c4c4ULL, 0xc4c4c4c4c4c4c4c4ULL, }, - { 0xc48cccc48cccc48cULL, 0xccc48cccc48cccc4ULL, }, - { 0xcccc4ccccc4cccccULL, 0x4ccccc4ccccc4cccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3232323232323232ULL, 0x3232323232323232ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1313131313131313ULL, 0x1313131313131313ULL, }, - { 0x2323232323232323ULL, 0x2323232323232323ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333323333323333ULL, 0x3233333233333233ULL, }, - { 0x2331332331332331ULL, 0x3323313323313323ULL, }, - { 0x630e38630e38630eULL, 0x38630e38630e3863ULL, }, /* 48 */ - { 0xe28e38e28e38e28eULL, 0x38e28e38e28e38e2ULL, }, - { 0xe38a38e38a38e38aULL, 0x38e38a38e38a38e3ULL, }, - { 0xc38e18c38e18c38eULL, 0x18c38e18c38e18c3ULL, }, - { 0xe38e28e38e28e38eULL, 0x28e38e28e38e28e3ULL, }, - { 0xe38630e38630e386ULL, 0x30e38630e38630e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38c38e38c38e38cULL, 0x38e38c38e38c38e3ULL, }, - { 0x1c71471c71471c71ULL, 0x471c71471c71471cULL, }, /* 56 */ - { 0x1c70c61c70c61c70ULL, 0xc61c70c61c70c61cULL, }, - { 0x1871c31871c31871ULL, 0xc31871c31871c318ULL, }, - { 0x1c51c71c51c71c51ULL, 0xc71c51c71c51c71cULL, }, - { 0x0c61c70c61c70c61ULL, 0xc70c61c70c61c70cULL, }, - { 0x1471c71471c71471ULL, 0xc71471c71471c714ULL, }, - { 0x1431c61431c61431ULL, 0xc61431c61431c614ULL, }, - { 0x0c71470c71470c71ULL, 0x470c71470c71470cULL, }, - { 0x886aa6cc28625540ULL, 0x4367031ebe73b00cULL, }, /* 64 */ - { 0x802ae6c408625540ULL, 0x4b67035ade7bb00cULL, }, - { 0x886aa6c828625540ULL, 0x4b660b5ef673900cULL, }, - { 0x886aa6cc28605100ULL, 0x4b650a5efc7bb00cULL, }, - { 0xfaba00634c93c708ULL, 0x1277b31a153752ecULL, }, - { 0xf3be00634d934708ULL, 0x1277b31a153f52ecULL, }, - { 0xebba00634d13c708ULL, 0x12f6bb1a153752ecULL, }, - { 0xfa3e00430d91c308ULL, 0x12f5ba1a153b52fcULL, }, - { 0xac5aaeaab8cb8b80ULL, 0x2758c6bfab232404ULL, }, /* 72 */ - { 0xa41aaea299c70b80ULL, 0x2358c6fb8b2b2104ULL, }, - { 0xac5aaeaab94f8380ULL, 0x27d8867fa3230504ULL, }, - { 0xac5aae8ab9cd8b80ULL, 0x07d8c6fea92b2114ULL, }, - { 0x704b164d5e31c24eULL, 0x85718098a942e2a0ULL, }, - { 0x700f16455e31624eULL, 0x897180d88942e2a0ULL, }, - { 0x604b16495c31e24eULL, 0x0df08858a142c2a0ULL, }, - { 0x704f164d1e31e20eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_d.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_d.c deleted file mode 100644 index 0accccf093ca..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BCLR.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BCLR.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, /* 0 */ - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, - { 0xfffffbffffffffffULL, 0xfffffbffffffffffULL, }, - { 0xffffffffffdfffffULL, 0xffffffffffdfffffULL, }, - { 0xffffffffffffefffULL, 0xffffffffffffefffULL, }, - { 0xfff7ffffffffffffULL, 0xfff7ffffffffffffULL, }, - { 0xffffffffffffbfffULL, 0xfffffff7ffffffffULL, }, - { 0xfffdffffffffffffULL, 0xffffffffefffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaa8aaaaaULL, 0xaaaaaaaaaa8aaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaa2aaaaaaaaaaaaULL, 0xaaa2aaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaa2aaaaaaaaULL, }, - { 0xaaa8aaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, - { 0x5555515555555555ULL, 0x5555515555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555554555ULL, 0x5555555555554555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555551555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555545555555ULL, }, - { 0x4cccccccccccccccULL, 0x4cccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccc8ccccccccccULL, 0xccccc8ccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccc4ccccccccccccULL, 0xccc4ccccccccccccULL, }, - { 0xcccccccccccc8cccULL, 0xccccccc4ccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333332ULL, 0x3333333333333332ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333133333ULL, 0x3333333333133333ULL, }, - { 0x3333333333332333ULL, 0x3333333333332333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3331333333333333ULL, 0x3333333323333333ULL, }, - { 0x638e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e2ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38a38e38e38e3ULL, }, - { 0xe38e38e38e18e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e28e3ULL, }, - { 0xe38638e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38a38eULL, 0x38e38e30e38e38e3ULL, }, - { 0xe38c38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c31c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c51c71cULL, }, - { 0x1c71c71c71c70c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71471c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c70c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7ba00cULL, }, /* 64 */ - { 0x886ae6cc28625440ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe6bb00cULL, }, - { 0x886ae6cc28621540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f42fcULL, }, - { 0xfbbe00634d93c608ULL, 0x02f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a152f52fcULL, }, - { 0xfbbe00634d938708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8a80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6feab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31a24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_h.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_h.c deleted file mode 100644 index 474e5297b8d3..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BCLR.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BCLR.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, /* 0 */ - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xfbfffbfffbfffbffULL, 0xfbfffbfffbfffbffULL, }, - { 0xffdfffdfffdfffdfULL, 0xffdfffdfffdfffdfULL, }, - { 0xefffefffefffefffULL, 0xefffefffefffefffULL, }, - { 0xfff7fff7fff7fff7ULL, 0xfff7fff7fff7fff7ULL, }, - { 0xbffffff7feffbfffULL, 0xfff7feffbffffff7ULL, }, - { 0xfffdefffff7ffffdULL, 0xefffff7ffffdefffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa8aaa8aaa8aaa8aULL, 0xaa8aaa8aaa8aaa8aULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaa2aaa2aaa2aaa2ULL, 0xaaa2aaa2aaa2aaa2ULL, }, - { 0xaaaaaaa2aaaaaaaaULL, 0xaaa2aaaaaaaaaaa2ULL, }, - { 0xaaa8aaaaaa2aaaa8ULL, 0xaaaaaa2aaaa8aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, - { 0x5155515551555155ULL, 0x5155515551555155ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x4555455545554555ULL, 0x4555455545554555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1555555554551555ULL, 0x5555545515555555ULL, }, - { 0x5555455555555555ULL, 0x4555555555554555ULL, }, - { 0x4ccc4ccc4ccc4cccULL, 0x4ccc4ccc4ccc4cccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xc8ccc8ccc8ccc8ccULL, 0xc8ccc8ccc8ccc8ccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccc4ccc4ccc4ccc4ULL, 0xccc4ccc4ccc4ccc4ULL, }, - { 0x8cccccc4cccc8cccULL, 0xccc4cccc8cccccc4ULL, }, - { 0xcccccccccc4cccccULL, 0xcccccc4cccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3332333233323332ULL, 0x3332333233323332ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3313331333133313ULL, 0x3313331333133313ULL, }, - { 0x2333233323332333ULL, 0x2333233323332333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333332333333ULL, 0x3333323333333333ULL, }, - { 0x3331233333333331ULL, 0x2333333333312333ULL, }, - { 0x638e38e30e38638eULL, 0x38e30e38638e38e3ULL, }, /* 48 */ - { 0xe38e38e28e38e38eULL, 0x38e28e38e38e38e2ULL, }, - { 0xe38e38e38a38e38eULL, 0x38e38a38e38e38e3ULL, }, - { 0xe38e38c38e18e38eULL, 0x38c38e18e38e38c3ULL, }, - { 0xe38e28e38e38e38eULL, 0x28e38e38e38e28e3ULL, }, - { 0xe38638e38e30e386ULL, 0x38e38e30e38638e3ULL, }, - { 0xa38e38e38e38a38eULL, 0x38e38e38a38e38e3ULL, }, - { 0xe38c28e38e38e38cULL, 0x28e38e38e38c28e3ULL, }, - { 0x1c71471c71c71c71ULL, 0x471c71c71c71471cULL, }, /* 56 */ - { 0x1c70c71c71c61c70ULL, 0xc71c71c61c70c71cULL, }, - { 0x1871c31c71c71871ULL, 0xc31c71c71871c31cULL, }, - { 0x1c51c71c71c71c51ULL, 0xc71c71c71c51c71cULL, }, - { 0x0c71c71c61c70c71ULL, 0xc71c61c70c71c71cULL, }, - { 0x1c71c71471c71c71ULL, 0xc71471c71c71c714ULL, }, - { 0x1c71c71470c71c71ULL, 0xc71470c71c71c714ULL, }, - { 0x1c71c71c71471c71ULL, 0xc71c71471c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5ef67ba00cULL, }, /* 64 */ - { 0x886ae6c428625440ULL, 0x4b670b5e7e7ba00cULL, }, - { 0x886ae2cc28625540ULL, 0x4a670b5ef67bb00cULL, }, - { 0x086ac6cc28601540ULL, 0x4b650a5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x1277bb1a153f42fcULL, }, - { 0xbbbe00634d93c608ULL, 0x1277bb1a153f42fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f73b1a153f52ecULL, }, - { 0x7bbe00634d918708ULL, 0x12f5ba1a153b52fcULL, }, - { 0xa85aaeaab9cb8b80ULL, 0x275886ffa32b2514ULL, }, /* 72 */ - { 0xac5aaea2b9c78a80ULL, 0x2758c2ff2b2b2514ULL, }, - { 0xa85aaaaa39cf8b80ULL, 0x26d846ffa32b2504ULL, }, - { 0x2c5a8eaab9cd8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f064d5e31e24eULL, 0x8d7188d8a142e2a0ULL, }, - { 0x304f16455e31e24eULL, 0x8d7188d82942e2a0ULL, }, - { 0x704f124d5e31e24eULL, 0x8cf108d8a142e2a0ULL, }, - { 0x704f164d5e31a24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_w.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_w.c deleted file mode 100644 index 818b12ff0acf..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bclr_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BCLR.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BCLR.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, /* 0 */ - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xfffffbfffffffbffULL, 0xfffffbfffffffbffULL, }, - { 0xffdfffffffdfffffULL, 0xffdfffffffdfffffULL, }, - { 0xffffefffffffefffULL, 0xffffefffffffefffULL, }, - { 0xfff7fffffff7ffffULL, 0xfff7fffffff7ffffULL, }, - { 0xfffffff7ffffbfffULL, 0xfefffffffffffff7ULL, }, - { 0xeffffffffffdffffULL, 0xffffff7fefffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa8aaaaaaa8aaaaaULL, 0xaa8aaaaaaa8aaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaa2aaaaaaa2aaaaULL, 0xaaa2aaaaaaa2aaaaULL, }, - { 0xaaaaaaa2aaaaaaaaULL, 0xaaaaaaaaaaaaaaa2ULL, }, - { 0xaaaaaaaaaaa8aaaaULL, 0xaaaaaa2aaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, - { 0x5555515555555155ULL, 0x5555515555555155ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555455555554555ULL, 0x5555455555554555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555551555ULL, 0x5455555555555555ULL, }, - { 0x4555555555555555ULL, 0x5555555545555555ULL, }, - { 0x4ccccccc4cccccccULL, 0x4ccccccc4cccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccc8ccccccc8ccULL, 0xccccc8ccccccc8ccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccc4ccccccc4ccccULL, 0xccc4ccccccc4ccccULL, }, - { 0xccccccc4cccc8cccULL, 0xccccccccccccccc4ULL, }, - { 0xccccccccccccccccULL, 0xcccccc4cccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333233333332ULL, 0x3333333233333332ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3313333333133333ULL, 0x3313333333133333ULL, }, - { 0x3333233333332333ULL, 0x3333233333332333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3233333333333333ULL, }, - { 0x2333333333313333ULL, 0x3333333323333333ULL, }, - { 0x638e38e30e38e38eULL, 0x38e38e38638e38e3ULL, }, /* 48 */ - { 0xe38e38e28e38e38eULL, 0x38e38e38e38e38e2ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38a38e38e38e3ULL, }, - { 0xe38e38e38e18e38eULL, 0x38c38e38e38e38e3ULL, }, - { 0xe38e28e38e38e38eULL, 0x38e38e38e38e28e3ULL, }, - { 0xe38638e38e30e38eULL, 0x38e38e38e38638e3ULL, }, - { 0xe38e38e38e38a38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c70ULL, 0xc71c71c61c71c71cULL, }, - { 0x1c71c31c71c71871ULL, 0xc71c71c71c71c31cULL, }, - { 0x1c51c71c71c71c71ULL, 0xc71c71c71c51c71cULL, }, - { 0x1c71c71c71c70c71ULL, 0xc71c61c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71471c71c71c71cULL, }, - { 0x1c71c71471c71c71ULL, 0xc61c71c71c71c714ULL, }, - { 0x0c71c71c71c51c71ULL, 0xc71c71470c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x0b670b5efe7ba00cULL, }, /* 64 */ - { 0x886ae6c428625440ULL, 0x4b670b5eee7bb00cULL, }, - { 0x886ae2cc28625540ULL, 0x4b670b5efe6bb00cULL, }, - { 0x886ac6cc28621540ULL, 0x4a670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f42fcULL, }, - { 0xfbbe00634d93c608ULL, 0x12f7bb1a053f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a152f52fcULL, }, - { 0xfbbe00634d938708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaea2b9cf8a80ULL, 0x23d8c6ffab2b2514ULL, }, - { 0xac5aaaaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5a8eaab9cf8b80ULL, 0x26d8c6ffab2b2514ULL, }, - { 0x704f064d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f16455e31e24eULL, 0x89f188d8a942e2a0ULL, }, - { 0x704f124d5e31e24eULL, 0x0df188d8a942e2a0ULL, }, - { 0x704f164d5e31a24eULL, 0x8cf188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BCLR_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_b.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_b.c deleted file mode 100644 index 78ba32f36096..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BNEG.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BNEG.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, /* 0 */ - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, - { 0xfbfbfbfbfbfbfbfbULL, 0xfbfbfbfbfbfbfbfbULL, }, - { 0xdfdfdfdfdfdfdfdfULL, 0xdfdfdfdfdfdfdfdfULL, }, - { 0xefefefefefefefefULL, 0xefefefefefefefefULL, }, - { 0xf7f7f7f7f7f7f7f7ULL, 0xf7f7f7f7f7f7f7f7ULL, }, - { 0xf7bffef7bffef7bfULL, 0xfef7bffef7bffef7ULL, }, - { 0xeffd7feffd7feffdULL, 0x7feffd7feffd7fefULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 8 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x2020202020202020ULL, 0x2020202020202020ULL, }, - { 0x1010101010101010ULL, 0x1010101010101010ULL, }, - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, - { 0x0840010840010840ULL, 0x0108400108400108ULL, }, - { 0x1002801002801002ULL, 0x8010028010028010ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, /* 16 */ - { 0xababababababababULL, 0xababababababababULL, }, - { 0xaeaeaeaeaeaeaeaeULL, 0xaeaeaeaeaeaeaeaeULL, }, - { 0x8a8a8a8a8a8a8a8aULL, 0x8a8a8a8a8a8a8a8aULL, }, - { 0xbabababababababaULL, 0xbabababababababaULL, }, - { 0xa2a2a2a2a2a2a2a2ULL, 0xa2a2a2a2a2a2a2a2ULL, }, - { 0xa2eaaba2eaaba2eaULL, 0xaba2eaaba2eaaba2ULL, }, - { 0xbaa82abaa82abaa8ULL, 0x2abaa82abaa82abaULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, /* 24 */ - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, - { 0x5151515151515151ULL, 0x5151515151515151ULL, }, - { 0x7575757575757575ULL, 0x7575757575757575ULL, }, - { 0x4545454545454545ULL, 0x4545454545454545ULL, }, - { 0x5d5d5d5d5d5d5d5dULL, 0x5d5d5d5d5d5d5d5dULL, }, - { 0x5d15545d15545d15ULL, 0x545d15545d15545dULL, }, - { 0x4557d54557d54557ULL, 0xd54557d54557d545ULL, }, - { 0x4c4c4c4c4c4c4c4cULL, 0x4c4c4c4c4c4c4c4cULL, }, /* 32 */ - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, - { 0xc8c8c8c8c8c8c8c8ULL, 0xc8c8c8c8c8c8c8c8ULL, }, - { 0xececececececececULL, 0xececececececececULL, }, - { 0xdcdcdcdcdcdcdcdcULL, 0xdcdcdcdcdcdcdcdcULL, }, - { 0xc4c4c4c4c4c4c4c4ULL, 0xc4c4c4c4c4c4c4c4ULL, }, - { 0xc48ccdc48ccdc48cULL, 0xcdc48ccdc48ccdc4ULL, }, - { 0xdcce4cdcce4cdcceULL, 0x4cdcce4cdcce4cdcULL, }, - { 0xb3b3b3b3b3b3b3b3ULL, 0xb3b3b3b3b3b3b3b3ULL, }, /* 40 */ - { 0x3232323232323232ULL, 0x3232323232323232ULL, }, - { 0x3737373737373737ULL, 0x3737373737373737ULL, }, - { 0x1313131313131313ULL, 0x1313131313131313ULL, }, - { 0x2323232323232323ULL, 0x2323232323232323ULL, }, - { 0x3b3b3b3b3b3b3b3bULL, 0x3b3b3b3b3b3b3b3bULL, }, - { 0x3b73323b73323b73ULL, 0x323b73323b73323bULL, }, - { 0x2331b32331b32331ULL, 0xb32331b32331b323ULL, }, - { 0x630eb8630eb8630eULL, 0xb8630eb8630eb863ULL, }, /* 48 */ - { 0xe28f39e28f39e28fULL, 0x39e28f39e28f39e2ULL, }, - { 0xe78a3ce78a3ce78aULL, 0x3ce78a3ce78a3ce7ULL, }, - { 0xc3ae18c3ae18c3aeULL, 0x18c3ae18c3ae18c3ULL, }, - { 0xf39e28f39e28f39eULL, 0x28f39e28f39e28f3ULL, }, - { 0xeb8630eb8630eb86ULL, 0x30eb8630eb8630ebULL, }, - { 0xebce39ebce39ebceULL, 0x39ebce39ebce39ebULL, }, - { 0xf38cb8f38cb8f38cULL, 0xb8f38cb8f38cb8f3ULL, }, - { 0x9cf1479cf1479cf1ULL, 0x479cf1479cf1479cULL, }, /* 56 */ - { 0x1d70c61d70c61d70ULL, 0xc61d70c61d70c61dULL, }, - { 0x1875c31875c31875ULL, 0xc31875c31875c318ULL, }, - { 0x3c51e73c51e73c51ULL, 0xe73c51e73c51e73cULL, }, - { 0x0c61d70c61d70c61ULL, 0xd70c61d70c61d70cULL, }, - { 0x1479cf1479cf1479ULL, 0xcf1479cf1479cf14ULL, }, - { 0x1431c61431c61431ULL, 0xc61431c61431c614ULL, }, - { 0x0c73470c73470c73ULL, 0x470c73470c73470cULL, }, - { 0x896ea6dc29667541ULL, 0x43e7031ebe73b11cULL, }, /* 64 */ - { 0x802ae7c4086ad541ULL, 0x4fe7035adefbb41cULL, }, - { 0x986ea6c82ae25d41ULL, 0xcb664bdef673901cULL, }, - { 0x89eaa6ec68605100ULL, 0x6b650a5ffc7fb40dULL, }, - { 0xfaba40734c97e709ULL, 0x1a77b35a553753ecULL, }, - { 0xf3fe016b6d9b4709ULL, 0x1677b31e35bf56ecULL, }, - { 0xebba40674f13cf09ULL, 0x92f6fb9a1d3772ecULL, }, - { 0xfa3e40430d91c348ULL, 0x32f5ba1b173b56fdULL, }, - { 0xad5eeebab8cbab81ULL, 0x2f58cebfeb232404ULL, }, /* 72 */ - { 0xa41aafa299c70b81ULL, 0x2358cefb8bab2104ULL, }, - { 0xbc5eeeaebb4f8381ULL, 0xa7d9867fa3230504ULL, }, - { 0xaddaee8af9cd8fc0ULL, 0x07dac7fea92f2115ULL, }, - { 0x714b565d5f35c24fULL, 0x85718098e94ae3b0ULL, }, - { 0x780f17457e39624fULL, 0x897180dc89c2e6b0ULL, }, - { 0x604b56495cb1ea4fULL, 0x0df0c858a14ac2b0ULL, }, - { 0x71cf566d1e33e60eULL, 0xadf389d9ab46e6a1ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_d.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_d.c deleted file mode 100644 index 44cd608688c8..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BNEG.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BNEG.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, /* 0 */ - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, - { 0xfffffbffffffffffULL, 0xfffffbffffffffffULL, }, - { 0xffffffffffdfffffULL, 0xffffffffffdfffffULL, }, - { 0xffffffffffffefffULL, 0xffffffffffffefffULL, }, - { 0xfff7ffffffffffffULL, 0xfff7ffffffffffffULL, }, - { 0xffffffffffffbfffULL, 0xfffffff7ffffffffULL, }, - { 0xfffdffffffffffffULL, 0xffffffffefffffffULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 8 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000040000000000ULL, 0x0000040000000000ULL, }, - { 0x0000000000200000ULL, 0x0000000000200000ULL, }, - { 0x0000000000001000ULL, 0x0000000000001000ULL, }, - { 0x0008000000000000ULL, 0x0008000000000000ULL, }, - { 0x0000000000004000ULL, 0x0000000800000000ULL, }, - { 0x0002000000000000ULL, 0x0000000010000000ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0xaaaaaeaaaaaaaaaaULL, 0xaaaaaeaaaaaaaaaaULL, }, - { 0xaaaaaaaaaa8aaaaaULL, 0xaaaaaaaaaa8aaaaaULL, }, - { 0xaaaaaaaaaaaabaaaULL, 0xaaaaaaaaaaaabaaaULL, }, - { 0xaaa2aaaaaaaaaaaaULL, 0xaaa2aaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaeaaaULL, 0xaaaaaaa2aaaaaaaaULL, }, - { 0xaaa8aaaaaaaaaaaaULL, 0xaaaaaaaabaaaaaaaULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, /* 24 */ - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, - { 0x5555515555555555ULL, 0x5555515555555555ULL, }, - { 0x5555555555755555ULL, 0x5555555555755555ULL, }, - { 0x5555555555554555ULL, 0x5555555555554555ULL, }, - { 0x555d555555555555ULL, 0x555d555555555555ULL, }, - { 0x5555555555551555ULL, 0x5555555d55555555ULL, }, - { 0x5557555555555555ULL, 0x5555555545555555ULL, }, - { 0x4cccccccccccccccULL, 0x4cccccccccccccccULL, }, /* 32 */ - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, - { 0xccccc8ccccccccccULL, 0xccccc8ccccccccccULL, }, - { 0xccccccccccecccccULL, 0xccccccccccecccccULL, }, - { 0xccccccccccccdcccULL, 0xccccccccccccdcccULL, }, - { 0xccc4ccccccccccccULL, 0xccc4ccccccccccccULL, }, - { 0xcccccccccccc8cccULL, 0xccccccc4ccccccccULL, }, - { 0xccceccccccccccccULL, 0xccccccccdcccccccULL, }, - { 0xb333333333333333ULL, 0xb333333333333333ULL, }, /* 40 */ - { 0x3333333333333332ULL, 0x3333333333333332ULL, }, - { 0x3333373333333333ULL, 0x3333373333333333ULL, }, - { 0x3333333333133333ULL, 0x3333333333133333ULL, }, - { 0x3333333333332333ULL, 0x3333333333332333ULL, }, - { 0x333b333333333333ULL, 0x333b333333333333ULL, }, - { 0x3333333333337333ULL, 0x3333333b33333333ULL, }, - { 0x3331333333333333ULL, 0x3333333323333333ULL, }, - { 0x638e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e2ULL, }, - { 0xe38e3ce38e38e38eULL, 0x38e38a38e38e38e3ULL, }, - { 0xe38e38e38e18e38eULL, 0x38e38e38e3ae38e3ULL, }, - { 0xe38e38e38e38f38eULL, 0x38e38e38e38e28e3ULL, }, - { 0xe38638e38e38e38eULL, 0x38eb8e38e38e38e3ULL, }, - { 0xe38e38e38e38a38eULL, 0x38e38e30e38e38e3ULL, }, - { 0xe38c38e38e38e38eULL, 0x38e38e38f38e38e3ULL, }, - { 0x9c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71c71dULL, }, - { 0x1c71c31c71c71c71ULL, 0xc71c75c71c71c71cULL, }, - { 0x1c71c71c71e71c71ULL, 0xc71c71c71c51c71cULL, }, - { 0x1c71c71c71c70c71ULL, 0xc71c71c71c71d71cULL, }, - { 0x1c79c71c71c71c71ULL, 0xc71471c71c71c71cULL, }, - { 0x1c71c71c71c75c71ULL, 0xc71c71cf1c71c71cULL, }, - { 0x1c73c71c71c71c71ULL, 0xc71c71c70c71c71cULL, }, - { 0x886ae6cc28625541ULL, 0x4b670b5efe7ba00cULL, }, /* 64 */ - { 0x886ae6cc28625440ULL, 0x5b670b5efe7bb00cULL, }, - { 0x886ae6cc28625541ULL, 0x4b670b5efe6bb00cULL, }, - { 0x886ae6cc28621540ULL, 0x4b670b5ffe7bb00cULL, }, - { 0xfbbe00634d93c709ULL, 0x12f7bb1a153f42fcULL, }, - { 0xfbbe00634d93c608ULL, 0x02f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c709ULL, 0x12f7bb1a152f52fcULL, }, - { 0xfbbe00634d938708ULL, 0x12f7bb1b153f52fcULL, }, - { 0xac5aaeaab9cf8b81ULL, 0x27d8c6ffab2b3514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8a80ULL, 0x37d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b81ULL, 0x27d8c6ffab3b2514ULL, }, - { 0xac5aaeaab9cfcb80ULL, 0x27d8c6feab2b2514ULL, }, - { 0x704f164d5e31e24fULL, 0x8df188d8a942f2a0ULL, }, - { 0x704f164d5e31e34eULL, 0x9df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24fULL, 0x8df188d8a952e2a0ULL, }, - { 0x704f164d5e31a24eULL, 0x8df188d9a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_h.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_h.c deleted file mode 100644 index 5d17ceeba3e0..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BNEG.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BNEG.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, /* 0 */ - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xfbfffbfffbfffbffULL, 0xfbfffbfffbfffbffULL, }, - { 0xffdfffdfffdfffdfULL, 0xffdfffdfffdfffdfULL, }, - { 0xefffefffefffefffULL, 0xefffefffefffefffULL, }, - { 0xfff7fff7fff7fff7ULL, 0xfff7fff7fff7fff7ULL, }, - { 0xbffffff7feffbfffULL, 0xfff7feffbffffff7ULL, }, - { 0xfffdefffff7ffffdULL, 0xefffff7ffffdefffULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 8 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0400040004000400ULL, 0x0400040004000400ULL, }, - { 0x0020002000200020ULL, 0x0020002000200020ULL, }, - { 0x1000100010001000ULL, 0x1000100010001000ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x4000000801004000ULL, 0x0008010040000008ULL, }, - { 0x0002100000800002ULL, 0x1000008000021000ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, /* 16 */ - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0xaeaaaeaaaeaaaeaaULL, 0xaeaaaeaaaeaaaeaaULL, }, - { 0xaa8aaa8aaa8aaa8aULL, 0xaa8aaa8aaa8aaa8aULL, }, - { 0xbaaabaaabaaabaaaULL, 0xbaaabaaabaaabaaaULL, }, - { 0xaaa2aaa2aaa2aaa2ULL, 0xaaa2aaa2aaa2aaa2ULL, }, - { 0xeaaaaaa2abaaeaaaULL, 0xaaa2abaaeaaaaaa2ULL, }, - { 0xaaa8baaaaa2aaaa8ULL, 0xbaaaaa2aaaa8baaaULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, /* 24 */ - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, - { 0x5155515551555155ULL, 0x5155515551555155ULL, }, - { 0x5575557555755575ULL, 0x5575557555755575ULL, }, - { 0x4555455545554555ULL, 0x4555455545554555ULL, }, - { 0x555d555d555d555dULL, 0x555d555d555d555dULL, }, - { 0x1555555d54551555ULL, 0x555d54551555555dULL, }, - { 0x5557455555d55557ULL, 0x455555d555574555ULL, }, - { 0x4ccc4ccc4ccc4cccULL, 0x4ccc4ccc4ccc4cccULL, }, /* 32 */ - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, - { 0xc8ccc8ccc8ccc8ccULL, 0xc8ccc8ccc8ccc8ccULL, }, - { 0xccecccecccecccecULL, 0xccecccecccecccecULL, }, - { 0xdcccdcccdcccdcccULL, 0xdcccdcccdcccdcccULL, }, - { 0xccc4ccc4ccc4ccc4ULL, 0xccc4ccc4ccc4ccc4ULL, }, - { 0x8cccccc4cdcc8cccULL, 0xccc4cdcc8cccccc4ULL, }, - { 0xcccedccccc4cccceULL, 0xdccccc4ccccedcccULL, }, - { 0xb333b333b333b333ULL, 0xb333b333b333b333ULL, }, /* 40 */ - { 0x3332333233323332ULL, 0x3332333233323332ULL, }, - { 0x3733373337333733ULL, 0x3733373337333733ULL, }, - { 0x3313331333133313ULL, 0x3313331333133313ULL, }, - { 0x2333233323332333ULL, 0x2333233323332333ULL, }, - { 0x333b333b333b333bULL, 0x333b333b333b333bULL, }, - { 0x7333333b32337333ULL, 0x333b32337333333bULL, }, - { 0x3331233333b33331ULL, 0x233333b333312333ULL, }, - { 0x638eb8e30e38638eULL, 0xb8e30e38638eb8e3ULL, }, /* 48 */ - { 0xe38f38e28e39e38fULL, 0x38e28e39e38f38e2ULL, }, - { 0xe78e3ce38a38e78eULL, 0x3ce38a38e78e3ce3ULL, }, - { 0xe3ae38c38e18e3aeULL, 0x38c38e18e3ae38c3ULL, }, - { 0xf38e28e39e38f38eULL, 0x28e39e38f38e28e3ULL, }, - { 0xe38638eb8e30e386ULL, 0x38eb8e30e38638ebULL, }, - { 0xa38e38eb8f38a38eULL, 0x38eb8f38a38e38ebULL, }, - { 0xe38c28e38eb8e38cULL, 0x28e38eb8e38c28e3ULL, }, - { 0x9c71471cf1c79c71ULL, 0x471cf1c79c71471cULL, }, /* 56 */ - { 0x1c70c71d71c61c70ULL, 0xc71d71c61c70c71dULL, }, - { 0x1871c31c75c71871ULL, 0xc31c75c71871c31cULL, }, - { 0x1c51c73c71e71c51ULL, 0xc73c71e71c51c73cULL, }, - { 0x0c71d71c61c70c71ULL, 0xd71c61c70c71d71cULL, }, - { 0x1c79c71471cf1c79ULL, 0xc71471cf1c79c714ULL, }, - { 0x5c71c71470c75c71ULL, 0xc71470c75c71c714ULL, }, - { 0x1c73d71c71471c73ULL, 0xd71c71471c73d71cULL, }, - { 0x8c6af6cc28665541ULL, 0x4be74b5ef67ba00cULL, }, /* 64 */ - { 0xc86ae6c4286a5440ULL, 0x4be70f5e7e7ba00cULL, }, - { 0x8c6ae2cca8625541ULL, 0x4a678b5ef67bb01cULL, }, - { 0x086ac6cc28601540ULL, 0x4b650a5efe7fb00dULL, }, - { 0xffbe10634d97c709ULL, 0x1277fb1a1d3f42fcULL, }, - { 0xbbbe006b4d9bc608ULL, 0x1277bf1a953f42fcULL, }, - { 0xffbe0463cd93c709ULL, 0x13f73b1a1d3f52ecULL, }, - { 0x7bbe20634d918708ULL, 0x12f5ba1a153b52fdULL, }, - { 0xa85abeaab9cb8b81ULL, 0x275886ffa32b3514ULL, }, /* 72 */ - { 0xec5aaea2b9c78a80ULL, 0x2758c2ff2b2b3514ULL, }, - { 0xa85aaaaa39cf8b81ULL, 0x26d846ffa32b2504ULL, }, - { 0x2c5a8eaab9cdcb80ULL, 0x27dac7ffab2f2515ULL, }, - { 0x744f064d5e35e24fULL, 0x8d71c8d8a142f2a0ULL, }, - { 0x304f16455e39e34eULL, 0x8d718cd82942f2a0ULL, }, - { 0x744f124dde31e24fULL, 0x8cf108d8a142e2b0ULL, }, - { 0xf04f364d5e33a24eULL, 0x8df389d8a946e2a1ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_w.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_w.c deleted file mode 100644 index 90d21f453d15..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bneg_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BNEG.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BNEG.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, /* 0 */ - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xfffffbfffffffbffULL, 0xfffffbfffffffbffULL, }, - { 0xffdfffffffdfffffULL, 0xffdfffffffdfffffULL, }, - { 0xffffefffffffefffULL, 0xffffefffffffefffULL, }, - { 0xfff7fffffff7ffffULL, 0xfff7fffffff7ffffULL, }, - { 0xfffffff7ffffbfffULL, 0xfefffffffffffff7ULL, }, - { 0xeffffffffffdffffULL, 0xffffff7fefffffffULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 8 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000040000000400ULL, 0x0000040000000400ULL, }, - { 0x0020000000200000ULL, 0x0020000000200000ULL, }, - { 0x0000100000001000ULL, 0x0000100000001000ULL, }, - { 0x0008000000080000ULL, 0x0008000000080000ULL, }, - { 0x0000000800004000ULL, 0x0100000000000008ULL, }, - { 0x1000000000020000ULL, 0x0000008010000000ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, /* 16 */ - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0xaaaaaeaaaaaaaeaaULL, 0xaaaaaeaaaaaaaeaaULL, }, - { 0xaa8aaaaaaa8aaaaaULL, 0xaa8aaaaaaa8aaaaaULL, }, - { 0xaaaabaaaaaaabaaaULL, 0xaaaabaaaaaaabaaaULL, }, - { 0xaaa2aaaaaaa2aaaaULL, 0xaaa2aaaaaaa2aaaaULL, }, - { 0xaaaaaaa2aaaaeaaaULL, 0xabaaaaaaaaaaaaa2ULL, }, - { 0xbaaaaaaaaaa8aaaaULL, 0xaaaaaa2abaaaaaaaULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, /* 24 */ - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, - { 0x5555515555555155ULL, 0x5555515555555155ULL, }, - { 0x5575555555755555ULL, 0x5575555555755555ULL, }, - { 0x5555455555554555ULL, 0x5555455555554555ULL, }, - { 0x555d5555555d5555ULL, 0x555d5555555d5555ULL, }, - { 0x5555555d55551555ULL, 0x545555555555555dULL, }, - { 0x4555555555575555ULL, 0x555555d545555555ULL, }, - { 0x4ccccccc4cccccccULL, 0x4ccccccc4cccccccULL, }, /* 32 */ - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, - { 0xccccc8ccccccc8ccULL, 0xccccc8ccccccc8ccULL, }, - { 0xccecccccccecccccULL, 0xccecccccccecccccULL, }, - { 0xccccdcccccccdcccULL, 0xccccdcccccccdcccULL, }, - { 0xccc4ccccccc4ccccULL, 0xccc4ccccccc4ccccULL, }, - { 0xccccccc4cccc8cccULL, 0xcdccccccccccccc4ULL, }, - { 0xdcccccccccceccccULL, 0xcccccc4cdcccccccULL, }, - { 0xb3333333b3333333ULL, 0xb3333333b3333333ULL, }, /* 40 */ - { 0x3333333233333332ULL, 0x3333333233333332ULL, }, - { 0x3333373333333733ULL, 0x3333373333333733ULL, }, - { 0x3313333333133333ULL, 0x3313333333133333ULL, }, - { 0x3333233333332333ULL, 0x3333233333332333ULL, }, - { 0x333b3333333b3333ULL, 0x333b3333333b3333ULL, }, - { 0x3333333b33337333ULL, 0x323333333333333bULL, }, - { 0x2333333333313333ULL, 0x333333b323333333ULL, }, - { 0x638e38e30e38e38eULL, 0xb8e38e38638e38e3ULL, }, /* 48 */ - { 0xe38e38e28e38e38fULL, 0x38e38e39e38e38e2ULL, }, - { 0xe38e3ce38e38e78eULL, 0x38e38a38e38e3ce3ULL, }, - { 0xe3ae38e38e18e38eULL, 0x38c38e38e3ae38e3ULL, }, - { 0xe38e28e38e38f38eULL, 0x38e39e38e38e28e3ULL, }, - { 0xe38638e38e30e38eULL, 0x38eb8e38e38638e3ULL, }, - { 0xe38e38eb8e38a38eULL, 0x39e38e38e38e38ebULL, }, - { 0xf38e38e38e3ae38eULL, 0x38e38eb8f38e38e3ULL, }, - { 0x9c71c71cf1c71c71ULL, 0x471c71c79c71c71cULL, }, /* 56 */ - { 0x1c71c71d71c71c70ULL, 0xc71c71c61c71c71dULL, }, - { 0x1c71c31c71c71871ULL, 0xc71c75c71c71c31cULL, }, - { 0x1c51c71c71e71c71ULL, 0xc73c71c71c51c71cULL, }, - { 0x1c71d71c71c70c71ULL, 0xc71c61c71c71d71cULL, }, - { 0x1c79c71c71cf1c71ULL, 0xc71471c71c79c71cULL, }, - { 0x1c71c71471c75c71ULL, 0xc61c71c71c71c714ULL, }, - { 0x0c71c71c71c51c71ULL, 0xc71c71470c71c71cULL, }, - { 0x886af6cc28625541ULL, 0x0b670b5efe7ba00cULL, }, /* 64 */ - { 0x886ae6c428625440ULL, 0x4f670b5eee7bb00cULL, }, - { 0x886ae2cc28625541ULL, 0xcb670b5efe6bb00cULL, }, - { 0x886ac6cc28621540ULL, 0x4a670b5efe7bb00dULL, }, - { 0xfbbe10634d93c709ULL, 0x52f7bb1a153f42fcULL, }, - { 0xfbbe006b4d93c608ULL, 0x16f7bb1a053f52fcULL, }, - { 0xfbbe04634d93c709ULL, 0x92f7bb1a152f52fcULL, }, - { 0xfbbe20634d938708ULL, 0x13f7bb1a153f52fdULL, }, - { 0xac5abeaab9cf8b81ULL, 0x67d8c6ffab2b3514ULL, }, /* 72 */ - { 0xac5aaea2b9cf8a80ULL, 0x23d8c6ffbb2b2514ULL, }, - { 0xac5aaaaab9cf8b81ULL, 0xa7d8c6ffab3b2514ULL, }, - { 0xac5a8eaab9cfcb80ULL, 0x26d8c6ffab2b2515ULL, }, - { 0x704f064d5e31e24fULL, 0xcdf188d8a942f2a0ULL, }, - { 0x704f16455e31e34eULL, 0x89f188d8b942e2a0ULL, }, - { 0x704f124d5e31e24fULL, 0x0df188d8a952e2a0ULL, }, - { 0x704f364d5e31a24eULL, 0x8cf188d8a942e2a1ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BNEG_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_b.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_b.c deleted file mode 100644 index 8aabf4bb880a..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BSET.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BSET.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 8 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x2020202020202020ULL, 0x2020202020202020ULL, }, - { 0x1010101010101010ULL, 0x1010101010101010ULL, }, - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, - { 0x0840010840010840ULL, 0x0108400108400108ULL, }, - { 0x1002801002801002ULL, 0x8010028010028010ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xababababababababULL, 0xababababababababULL, }, - { 0xaeaeaeaeaeaeaeaeULL, 0xaeaeaeaeaeaeaeaeULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xbabababababababaULL, 0xbabababababababaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaeaabaaeaabaaeaULL, 0xabaaeaabaaeaabaaULL, }, - { 0xbaaaaabaaaaabaaaULL, 0xaabaaaaabaaaaabaULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7575757575757575ULL, 0x7575757575757575ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5d5d5d5d5d5d5d5dULL, 0x5d5d5d5d5d5d5d5dULL, }, - { 0x5d55555d55555d55ULL, 0x555d55555d55555dULL, }, - { 0x5557d55557d55557ULL, 0xd55557d55557d555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xececececececececULL, 0xececececececececULL, }, - { 0xdcdcdcdcdcdcdcdcULL, 0xdcdcdcdcdcdcdcdcULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccdcccccdccccULL, 0xcdcccccdcccccdccULL, }, - { 0xdcceccdcceccdcceULL, 0xccdcceccdcceccdcULL, }, - { 0xb3b3b3b3b3b3b3b3ULL, 0xb3b3b3b3b3b3b3b3ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3737373737373737ULL, 0x3737373737373737ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3b3b3b3b3b3b3b3bULL, 0x3b3b3b3b3b3b3b3bULL, }, - { 0x3b73333b73333b73ULL, 0x333b73333b73333bULL, }, - { 0x3333b33333b33333ULL, 0xb33333b33333b333ULL, }, - { 0xe38eb8e38eb8e38eULL, 0xb8e38eb8e38eb8e3ULL, }, /* 48 */ - { 0xe38f39e38f39e38fULL, 0x39e38f39e38f39e3ULL, }, - { 0xe78e3ce78e3ce78eULL, 0x3ce78e3ce78e3ce7ULL, }, - { 0xe3ae38e3ae38e3aeULL, 0x38e3ae38e3ae38e3ULL, }, - { 0xf39e38f39e38f39eULL, 0x38f39e38f39e38f3ULL, }, - { 0xeb8e38eb8e38eb8eULL, 0x38eb8e38eb8e38ebULL, }, - { 0xebce39ebce39ebceULL, 0x39ebce39ebce39ebULL, }, - { 0xf38eb8f38eb8f38eULL, 0xb8f38eb8f38eb8f3ULL, }, - { 0x9cf1c79cf1c79cf1ULL, 0xc79cf1c79cf1c79cULL, }, /* 56 */ - { 0x1d71c71d71c71d71ULL, 0xc71d71c71d71c71dULL, }, - { 0x1c75c71c75c71c75ULL, 0xc71c75c71c75c71cULL, }, - { 0x3c71e73c71e73c71ULL, 0xe73c71e73c71e73cULL, }, - { 0x1c71d71c71d71c71ULL, 0xd71c71d71c71d71cULL, }, - { 0x1c79cf1c79cf1c79ULL, 0xcf1c79cf1c79cf1cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c73c71c73c71c73ULL, 0xc71c73c71c73c71cULL, }, - { 0x896ee6dc29667541ULL, 0x4be70b5efe7bb11cULL, }, /* 64 */ - { 0x886ae7cc286ad541ULL, 0x4fe70b5efefbb41cULL, }, - { 0x986ee6cc2ae25d41ULL, 0xcb674bdefe7bb01cULL, }, - { 0x89eae6ec68625540ULL, 0x6b670b5ffe7fb40dULL, }, - { 0xfbbe40734d97e709ULL, 0x1af7bb5a553f53fcULL, }, - { 0xfbfe016b6d9bc709ULL, 0x16f7bb1e35bf56fcULL, }, - { 0xfbbe40674f93cf09ULL, 0x92f7fb9a1d3f72fcULL, }, - { 0xfbbe40634d93c748ULL, 0x32f7bb1b173f56fdULL, }, - { 0xad5eeebab9cfab81ULL, 0x2fd8ceffeb2b2514ULL, }, /* 72 */ - { 0xac5aafaab9cf8b81ULL, 0x27d8ceffabab2514ULL, }, - { 0xbc5eeeaebbcf8b81ULL, 0xa7d9c6ffab2b2514ULL, }, - { 0xaddaeeaaf9cf8fc0ULL, 0x27dac7ffab2f2515ULL, }, - { 0x714f565d5f35e24fULL, 0x8df188d8e94ae3b0ULL, }, - { 0x784f174d7e39e24fULL, 0x8df188dca9c2e6b0ULL, }, - { 0x704f564d5eb1ea4fULL, 0x8df1c8d8a94ae2b0ULL, }, - { 0x71cf566d5e33e64eULL, 0xadf389d9ab46e6a1ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_d.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_d.c deleted file mode 100644 index e3f9a7e4ca4b..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BSET.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BSET.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 8 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000040000000000ULL, 0x0000040000000000ULL, }, - { 0x0000000000200000ULL, 0x0000000000200000ULL, }, - { 0x0000000000001000ULL, 0x0000000000001000ULL, }, - { 0x0008000000000000ULL, 0x0008000000000000ULL, }, - { 0x0000000000004000ULL, 0x0000000800000000ULL, }, - { 0x0002000000000000ULL, 0x0000000010000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0xaaaaaeaaaaaaaaaaULL, 0xaaaaaeaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaabaaaULL, 0xaaaaaaaaaaaabaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaeaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaabaaaaaaaULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555755555ULL, 0x5555555555755555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x555d555555555555ULL, 0x555d555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555d55555555ULL, }, - { 0x5557555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccecccccULL, 0xccccccccccecccccULL, }, - { 0xccccccccccccdcccULL, 0xccccccccccccdcccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccceccccccccccccULL, 0xccccccccdcccccccULL, }, - { 0xb333333333333333ULL, 0xb333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333373333333333ULL, 0x3333373333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333b333333333333ULL, 0x333b333333333333ULL, }, - { 0x3333333333337333ULL, 0x3333333b33333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e3ce38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e3ae38e3ULL, }, - { 0xe38e38e38e38f38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38eb8e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38f38e38e3ULL, }, - { 0x9c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71dULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c75c71c71c71cULL, }, - { 0x1c71c71c71e71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71d71cULL, }, - { 0x1c79c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c75c71ULL, 0xc71c71cf1c71c71cULL, }, - { 0x1c73c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625541ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x5b670b5efe7bb00cULL, }, - { 0x886ae6cc28625541ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5ffe7bb00cULL, }, - { 0xfbbe00634d93c709ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c709ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1b153f52fcULL, }, - { 0xac5aaeaab9cf8b81ULL, 0x27d8c6ffab2b3514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x37d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b81ULL, 0x27d8c6ffab3b2514ULL, }, - { 0xac5aaeaab9cfcb80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24fULL, 0x8df188d8a942f2a0ULL, }, - { 0x704f164d5e31e34eULL, 0x9df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24fULL, 0x8df188d8a952e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d9a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_h.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_h.c deleted file mode 100644 index cf9f6081800e..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BSET.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BSET.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 8 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0400040004000400ULL, 0x0400040004000400ULL, }, - { 0x0020002000200020ULL, 0x0020002000200020ULL, }, - { 0x1000100010001000ULL, 0x1000100010001000ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x4000000801004000ULL, 0x0008010040000008ULL, }, - { 0x0002100000800002ULL, 0x1000008000021000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0xaeaaaeaaaeaaaeaaULL, 0xaeaaaeaaaeaaaeaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xbaaabaaabaaabaaaULL, 0xbaaabaaabaaabaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xeaaaaaaaabaaeaaaULL, 0xaaaaabaaeaaaaaaaULL, }, - { 0xaaaabaaaaaaaaaaaULL, 0xbaaaaaaaaaaabaaaULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5575557555755575ULL, 0x5575557555755575ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x555d555d555d555dULL, 0x555d555d555d555dULL, }, - { 0x5555555d55555555ULL, 0x555d55555555555dULL, }, - { 0x5557555555d55557ULL, 0x555555d555575555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccecccecccecccecULL, 0xccecccecccecccecULL, }, - { 0xdcccdcccdcccdcccULL, 0xdcccdcccdcccdcccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccccdccccccULL, 0xcccccdccccccccccULL, }, - { 0xcccedcccccccccceULL, 0xdccccccccccedcccULL, }, - { 0xb333b333b333b333ULL, 0xb333b333b333b333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3733373337333733ULL, 0x3733373337333733ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333b333b333b333bULL, 0x333b333b333b333bULL, }, - { 0x7333333b33337333ULL, 0x333b33337333333bULL, }, - { 0x3333333333b33333ULL, 0x333333b333333333ULL, }, - { 0xe38eb8e38e38e38eULL, 0xb8e38e38e38eb8e3ULL, }, /* 48 */ - { 0xe38f38e38e39e38fULL, 0x38e38e39e38f38e3ULL, }, - { 0xe78e3ce38e38e78eULL, 0x3ce38e38e78e3ce3ULL, }, - { 0xe3ae38e38e38e3aeULL, 0x38e38e38e3ae38e3ULL, }, - { 0xf38e38e39e38f38eULL, 0x38e39e38f38e38e3ULL, }, - { 0xe38e38eb8e38e38eULL, 0x38eb8e38e38e38ebULL, }, - { 0xe38e38eb8f38e38eULL, 0x38eb8f38e38e38ebULL, }, - { 0xe38e38e38eb8e38eULL, 0x38e38eb8e38e38e3ULL, }, - { 0x9c71c71cf1c79c71ULL, 0xc71cf1c79c71c71cULL, }, /* 56 */ - { 0x1c71c71d71c71c71ULL, 0xc71d71c71c71c71dULL, }, - { 0x1c71c71c75c71c71ULL, 0xc71c75c71c71c71cULL, }, - { 0x1c71c73c71e71c71ULL, 0xc73c71e71c71c73cULL, }, - { 0x1c71d71c71c71c71ULL, 0xd71c71c71c71d71cULL, }, - { 0x1c79c71c71cf1c79ULL, 0xc71c71cf1c79c71cULL, }, - { 0x5c71c71c71c75c71ULL, 0xc71c71c75c71c71cULL, }, - { 0x1c73d71c71c71c73ULL, 0xd71c71c71c73d71cULL, }, - { 0x8c6af6cc28665541ULL, 0x4be74b5efe7bb00cULL, }, /* 64 */ - { 0xc86ae6cc286a5540ULL, 0x4be70f5efe7bb00cULL, }, - { 0x8c6ae6cca8625541ULL, 0x4b678b5efe7bb01cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7fb00dULL, }, - { 0xffbe10634d97c709ULL, 0x12f7fb1a1d3f52fcULL, }, - { 0xfbbe006b4d9bc708ULL, 0x12f7bf1a953f52fcULL, }, - { 0xffbe0463cd93c709ULL, 0x13f7bb1a1d3f52fcULL, }, - { 0xfbbe20634d93c708ULL, 0x12f7bb1a153f52fdULL, }, - { 0xac5abeaab9cf8b81ULL, 0x27d8c6ffab2b3514ULL, }, /* 72 */ - { 0xec5aaeaab9cf8b80ULL, 0x27d8c6ffab2b3514ULL, }, - { 0xac5aaeaab9cf8b81ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cfcb80ULL, 0x27dac7ffab2f2515ULL, }, - { 0x744f164d5e35e24fULL, 0x8df1c8d8a942f2a0ULL, }, - { 0x704f164d5e39e34eULL, 0x8df18cd8a942f2a0ULL, }, - { 0x744f164dde31e24fULL, 0x8df188d8a942e2b0ULL, }, - { 0xf04f364d5e33e24eULL, 0x8df389d8a946e2a1ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_w.c b/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_w.c deleted file mode 100644 index 77478116f26f..000000000000 --- a/tests/tcg/mips/user/ase/msa/bit-set/test_msa_bset_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction BSET.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Bit Set"; - char *instruction_name = "BSET.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 8 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000040000000400ULL, 0x0000040000000400ULL, }, - { 0x0020000000200000ULL, 0x0020000000200000ULL, }, - { 0x0000100000001000ULL, 0x0000100000001000ULL, }, - { 0x0008000000080000ULL, 0x0008000000080000ULL, }, - { 0x0000000800004000ULL, 0x0100000000000008ULL, }, - { 0x1000000000020000ULL, 0x0000008010000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0xaaaaaeaaaaaaaeaaULL, 0xaaaaaeaaaaaaaeaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaabaaaaaaabaaaULL, 0xaaaabaaaaaaabaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaeaaaULL, 0xabaaaaaaaaaaaaaaULL, }, - { 0xbaaaaaaaaaaaaaaaULL, 0xaaaaaaaabaaaaaaaULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5575555555755555ULL, 0x5575555555755555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x555d5555555d5555ULL, 0x555d5555555d5555ULL, }, - { 0x5555555d55555555ULL, 0x555555555555555dULL, }, - { 0x5555555555575555ULL, 0x555555d555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccecccccccecccccULL, 0xccecccccccecccccULL, }, - { 0xccccdcccccccdcccULL, 0xccccdcccccccdcccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xcdccccccccccccccULL, }, - { 0xdcccccccccceccccULL, 0xccccccccdcccccccULL, }, - { 0xb3333333b3333333ULL, 0xb3333333b3333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333373333333733ULL, 0x3333373333333733ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333b3333333b3333ULL, 0x333b3333333b3333ULL, }, - { 0x3333333b33337333ULL, 0x333333333333333bULL, }, - { 0x3333333333333333ULL, 0x333333b333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38fULL, 0x38e38e39e38e38e3ULL, }, - { 0xe38e3ce38e38e78eULL, 0x38e38e38e38e3ce3ULL, }, - { 0xe3ae38e38e38e38eULL, 0x38e38e38e3ae38e3ULL, }, - { 0xe38e38e38e38f38eULL, 0x38e39e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38eb8e38e38e38e3ULL, }, - { 0xe38e38eb8e38e38eULL, 0x39e38e38e38e38ebULL, }, - { 0xf38e38e38e3ae38eULL, 0x38e38eb8f38e38e3ULL, }, - { 0x9c71c71cf1c71c71ULL, 0xc71c71c79c71c71cULL, }, /* 56 */ - { 0x1c71c71d71c71c71ULL, 0xc71c71c71c71c71dULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c75c71c71c71cULL, }, - { 0x1c71c71c71e71c71ULL, 0xc73c71c71c71c71cULL, }, - { 0x1c71d71c71c71c71ULL, 0xc71c71c71c71d71cULL, }, - { 0x1c79c71c71cf1c71ULL, 0xc71c71c71c79c71cULL, }, - { 0x1c71c71c71c75c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886af6cc28625541ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x4f670b5efe7bb00cULL, }, - { 0x886ae6cc28625541ULL, 0xcb670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00dULL, }, - { 0xfbbe10634d93c709ULL, 0x52f7bb1a153f52fcULL, }, - { 0xfbbe006b4d93c708ULL, 0x16f7bb1a153f52fcULL, }, - { 0xfbbe04634d93c709ULL, 0x92f7bb1a153f52fcULL, }, - { 0xfbbe20634d93c708ULL, 0x13f7bb1a153f52fdULL, }, - { 0xac5abeaab9cf8b81ULL, 0x67d8c6ffab2b3514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffbb2b2514ULL, }, - { 0xac5aaeaab9cf8b81ULL, 0xa7d8c6ffab3b2514ULL, }, - { 0xac5aaeaab9cfcb80ULL, 0x27d8c6ffab2b2515ULL, }, - { 0x704f164d5e31e24fULL, 0xcdf188d8a942f2a0ULL, }, - { 0x704f164d5e31e34eULL, 0x8df188d8b942e2a0ULL, }, - { 0x704f164d5e31e24fULL, 0x8df188d8a952e2a0ULL, }, - { 0x704f364d5e31e24eULL, 0x8df188d8a942e2a1ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_BSET_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_madd_q_h.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_madd_q_h.c deleted file mode 100644 index 29a29900112f..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_madd_q_h.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MADD_Q.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MADD_Q.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xfffefffdfffefffeULL, 0xfffdfffefffefffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, /* 8 */ - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, /* 16 */ - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0x38e138e138e138e1ULL, 0x38e138e138e138e1ULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0x221f221f221f221fULL, 0x221f221f221f221fULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0x12f2da0f4bd712f2ULL, 0xda0f4bd712f2da0fULL, }, - { 0xfffbfffcfffcfffbULL, 0xfffcfffcfffbfffcULL, }, - { 0xfffafffbfffbfffaULL, 0xfffbfffbfffafffbULL, }, /* 24 */ - { 0xfffafffbfffbfffaULL, 0xfffbfffbfffafffbULL, }, - { 0xc716c717c717c716ULL, 0xc717c717c716c717ULL, }, - { 0xfff9fffafffafff9ULL, 0xfffafffafff9fffaULL, }, - { 0xddd6ddd7ddd7ddd6ULL, 0xddd7ddd7ddd6ddd7ULL, }, - { 0xfff7fff8fff8fff7ULL, 0xfff8fff8fff7fff8ULL, }, - { 0xed0025e4b41ded00ULL, 0x25e4b41ded0025e4ULL, }, - { 0xfff5fff6fff6fff5ULL, 0xfff6fff6fff5fff6ULL, }, - { 0xfff5fff6fff6fff5ULL, 0xfff6fff6fff5fff6ULL, }, /* 32 */ - { 0xfff5fff6fff6fff5ULL, 0xfff6fff6fff5fff6ULL, }, - { 0x2217221822182217ULL, 0x2218221822172218ULL, }, - { 0xfff4fff5fff5fff4ULL, 0xfff5fff5fff4fff5ULL, }, - { 0x146f14701470146fULL, 0x14701470146f1470ULL, }, - { 0xfff3fff4fff4fff3ULL, 0xfff4fff4fff3fff4ULL, }, - { 0x0b53e9322d770b53ULL, 0xe9322d770b53e932ULL, }, - { 0xfff2fff3fff3fff2ULL, 0xfff3fff3fff2fff3ULL, }, - { 0xfff1fff2fff2fff1ULL, 0xfff2fff2fff1fff2ULL, }, /* 40 */ - { 0xfff1fff2fff2fff1ULL, 0xfff2fff2fff1fff2ULL, }, - { 0xddceddcfddcfddceULL, 0xddcfddcfddceddcfULL, }, - { 0xffeffff0fff0ffefULL, 0xfff0fff0ffeffff0ULL, }, - { 0xeb73eb74eb74eb73ULL, 0xeb74eb74eb73eb74ULL, }, - { 0xffedffeeffeeffedULL, 0xffeeffeeffedffeeULL, }, - { 0xf48c16afd26af48cULL, 0x16afd26af48c16afULL, }, - { 0xffecffedffecffecULL, 0xffedffecffecffedULL, }, - { 0xffecffecffecffecULL, 0xffecffecffecffecULL, }, /* 48 */ - { 0xffecffecffecffecULL, 0xffecffecffecffecULL, }, - { 0x12e2d9ff4bc712e2ULL, 0xd9ff4bc712e2d9ffULL, }, - { 0xffebffebffecffebULL, 0xffebffecffebffebULL, }, - { 0x0b4be9292d6f0b4bULL, 0xe9292d6f0b4be929ULL, }, - { 0xffeaffeaffebffeaULL, 0xffeaffebffeaffeaULL, }, - { 0x063c1932650f063cULL, 0x1932650f063c1932ULL, }, - { 0xffe9ffe9ffebffe9ULL, 0xffe9ffebffe9ffe9ULL, }, - { 0xffe8ffe9ffeaffe8ULL, 0xffe9ffeaffe8ffe9ULL, }, /* 56 */ - { 0xffe8ffe9ffeaffe8ULL, 0xffe9ffeaffe8ffe9ULL, }, - { 0xecf125d6b40fecf1ULL, 0x25d6b40fecf125d6ULL, }, - { 0xffe6ffe8ffe8ffe6ULL, 0xffe8ffe8ffe6ffe8ULL, }, - { 0xf48516a9d264f485ULL, 0x16a9d264f48516a9ULL, }, - { 0xffe5ffe7ffe6ffe5ULL, 0xffe7ffe6ffe5ffe7ULL, }, - { 0xf992e69e9ac2f992ULL, 0xe69e9ac2f992e69eULL, }, - { 0xffe3ffe7ffe4ffe3ULL, 0xffe7ffe4ffe3ffe7ULL, }, - { 0x6f9c04dd0ca138aaULL, 0x2c5200e6ffe731d8ULL, }, /* 64 */ - { 0x739604c9251a12b8ULL, 0x377dfac7ffa6fe02ULL, }, - { 0x7fff14cc0ef4c520ULL, 0x4ef5f5b700a7e6d8ULL, }, - { 0x171110672cabb158ULL, 0x0bc4eb2201aef931ULL, }, - { 0x1b0b105345248b66ULL, 0x16efe503016dc55bULL, }, - { 0x1b2f10537427a4c0ULL, 0x19be0a1804f3fb27ULL, }, - { 0x1df71014499cd899ULL, 0x1fa528c6f6de1330ULL, }, - { 0x1a3a10257fffe5d0ULL, 0x0ebe68e9e8780024ULL, }, - { 0x6860202869d99838ULL, 0x263663d9e979e8faULL, }, /* 72 */ - { 0x6b281fe93f4ecc11ULL, 0x2c1d7fffdb640103ULL, }, - { 0x7fff539865cb3619ULL, 0x38847fff139c0bc0ULL, }, - { 0x369a456c32245120ULL, 0x15027fff4d19033dULL, }, - { 0xcdac41074fdb3d58ULL, 0xd1d1756a4e201596ULL, }, - { 0xc9ef41187fff4a8fULL, 0xc0ea7fff3fba028aULL, }, - { 0x808a32ec4c586596ULL, 0x9d687fff7937fa07ULL, }, - { 0xe31436ce7fff6c79ULL, 0x030a7fff7fff00c4ULL, }, - { 0xfe192c037fff7fffULL, 0x04d47fff7e7a0049ULL, }, /* 80 */ - { 0xfe292c257fff4707ULL, 0x058b3b197fff0078ULL, }, - { 0xff5c101739ce0661ULL, 0x074420c72b2a009aULL, }, - { 0xfecc12e4645704e6ULL, 0x00ca02430de90076ULL, }, - { 0xffeb0f2b7fff0829ULL, 0x014002760dbe002cULL, }, - { 0xffeb0f367fff0487ULL, 0x016f012210050048ULL, }, - { 0xfff8058b39ce0068ULL, 0x01e100a00567005cULL, }, - { 0xfff006826457004fULL, 0x0034000b01bd0046ULL, }, - { 0xfffe05397fff0083ULL, 0x0052000b01b7001aULL, }, /* 88 */ - { 0xfffe053d7fff0048ULL, 0x005e000501ff002aULL, }, - { 0xffff01e839ce0006ULL, 0x007b000200ac0036ULL, }, - { 0xfffe023d64570004ULL, 0x000d000000370029ULL, }, - { 0xffff01cc7fff0006ULL, 0x001400000036000fULL, }, - { 0xffff01cd7fff0003ULL, 0x00160000003e0018ULL, }, - { 0xffff00a839ce0000ULL, 0x001c00000014001eULL, }, - { 0xfffe00c564570000ULL, 0x0003000000060017ULL, }, - { 0xffff009e7fff0000ULL, 0x0004000000050008ULL, }, /* 96 */ - { 0xffff007e7fff0000ULL, 0x0006000000040003ULL, }, - { 0xffff00657fff0000ULL, 0x0009000000030001ULL, }, - { 0xffff00517fff0000ULL, 0x000e000000020000ULL, }, - { 0xffff00517fff0000ULL, 0x0010000000020000ULL, }, - { 0xffff00517fff0000ULL, 0x0012000000020000ULL, }, - { 0xffff00517fff0000ULL, 0x0014000000020000ULL, }, - { 0xffff00517fff0000ULL, 0x0016000000020000ULL, }, - { 0xffff001d39ce0000ULL, 0x001c000000000000ULL, }, /* 104 */ - { 0xffff000a1a1b0000ULL, 0x0024000000000000ULL, }, - { 0xffff00030bca0000ULL, 0x002f000000000000ULL, }, - { 0xffff000105530000ULL, 0x003d000000000000ULL, }, - { 0xfffe0001093d0000ULL, 0x0006000000000000ULL, }, - { 0xfffc000110090000ULL, 0x0000000000000000ULL, }, - { 0xfff800011bd50000ULL, 0x0000000000000000ULL, }, - { 0xfff0000130500000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_madd_q_w.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_madd_q_w.c deleted file mode 100644 index 529d60d1e921..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_madd_q_w.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MADD_Q.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MADD_Q.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xfffffffefffffffeULL, 0xfffffffdfffffffeULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, /* 8 */ - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, /* 16 */ - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0x38e38e3638e38e36ULL, 0x38e38e3638e38e36ULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0x2222221e2222221eULL, 0x2222221e2222221eULL, }, - { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, }, - { 0x12f684b94bda12f2ULL, 0xda12f68012f684b9ULL, }, - { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, }, - { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, }, /* 24 */ - { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, }, - { 0xc71c71c0c71c71c0ULL, 0xc71c71c0c71c71c0ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xddddddd5ddddddd5ULL, 0xddddddd5ddddddd5ULL, }, - { 0xfffffff6fffffff6ULL, 0xfffffff6fffffff6ULL, }, - { 0xed097b38b425ecffULL, 0x25ed0970ed097b38ULL, }, - { 0xfffffff5fffffff4ULL, 0xfffffff4fffffff5ULL, }, - { 0xfffffff5fffffff4ULL, 0xfffffff4fffffff5ULL, }, /* 32 */ - { 0xfffffff5fffffff4ULL, 0xfffffff4fffffff5ULL, }, - { 0x2222221722222216ULL, 0x2222221622222217ULL, }, - { 0xfffffff4fffffff3ULL, 0xfffffff3fffffff4ULL, }, - { 0x147ae13c147ae13bULL, 0x147ae13b147ae13cULL, }, - { 0xfffffff4fffffff3ULL, 0xfffffff3fffffff4ULL, }, - { 0x0b60b5ff2d82d821ULL, 0xe93e93dc0b60b5ffULL, }, - { 0xfffffff3fffffff3ULL, 0xfffffff3fffffff3ULL, }, - { 0xfffffff2fffffff2ULL, 0xfffffff2fffffff2ULL, }, /* 40 */ - { 0xfffffff2fffffff2ULL, 0xfffffff2fffffff2ULL, }, - { 0xddddddcfddddddcfULL, 0xddddddcfddddddcfULL, }, - { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, }, - { 0xeb851ea8eb851ea8ULL, 0xeb851ea8eb851ea8ULL, }, - { 0xffffffefffffffefULL, 0xffffffefffffffefULL, }, - { 0xf49f49e3d27d27c1ULL, 0x16c16c05f49f49e3ULL, }, - { 0xffffffeeffffffeeULL, 0xffffffeeffffffeeULL, }, - { 0xffffffeeffffffeeULL, 0xffffffedffffffeeULL, }, /* 48 */ - { 0xffffffeeffffffeeULL, 0xffffffedffffffeeULL, }, - { 0x12f684ac4bda12e5ULL, 0xda12f67212f684acULL, }, - { 0xffffffeeffffffeeULL, 0xffffffecffffffeeULL, }, - { 0x0b60b5f92d82d81cULL, 0xe93e93d50b60b5f9ULL, }, - { 0xffffffedffffffeeULL, 0xffffffebffffffedULL, }, - { 0x06522c2c6522c3e1ULL, 0x1948b0e706522c2cULL, }, - { 0xffffffecffffffeeULL, 0xffffffeaffffffecULL, }, - { 0xffffffebffffffedULL, 0xffffffeaffffffebULL, }, /* 56 */ - { 0xffffffebffffffedULL, 0xffffffeaffffffebULL, }, - { 0xed097b2db425ecf6ULL, 0x25ed0965ed097b2dULL, }, - { 0xffffffeaffffffebULL, 0xffffffe9ffffffeaULL, }, - { 0xf49f49ded27d27bdULL, 0x16c16c00f49f49deULL, }, - { 0xffffffe9ffffffeaULL, 0xffffffe9ffffffe9ULL, }, - { 0xf9add3a99add3bf7ULL, 0xe6b74eecf9add3a9ULL, }, - { 0xffffffe8ffffffe8ULL, 0xffffffe8ffffffe8ULL, }, - { 0x6fb7e8710cbdc0baULL, 0x2c6b142e000499ecULL, }, /* 64 */ - { 0x73b239bf253787bbULL, 0x379780d7ffc424b2ULL, }, - { 0x7fffffff0f12777aULL, 0x4f10996a00c57ee6ULL, }, - { 0x1713a7162cca6b1fULL, 0x0be04dd301cca255ULL, }, - { 0x1b0df86445443220ULL, 0x170cba7c018c2d1bULL, }, - { 0x1b323a657448a831ULL, 0x19dc4690051313a9ULL, }, - { 0x1dfa85ec49be7952ULL, 0x1fc3e11af6fe2ffbULL, }, - { 0x1a3e24c87fffffffULL, 0x0edd19b6e8983fd8ULL, }, - { 0x6863454e69daefbeULL, 0x26563249e9999a0cULL, }, /* 72 */ - { 0x6b2b90d53f50c0dfULL, 0x2c3dccd3db84b65eULL, }, - { 0x7fffffff65cdd2a2ULL, 0x38a5553713bd77aaULL, }, - { 0x369baa383226e26fULL, 0x1523c32e4d39d083ULL, }, - { 0xcdaf514f4fded614ULL, 0xd1f377974e40f3f2ULL, }, - { 0xc9f2f02b7fffffffULL, 0xc10cb0333fdb03cfULL, }, - { 0x808e9a644c590fccULL, 0x9d8b1e2a79575ca8ULL, }, - { 0xe31932487fffffffULL, 0x032ce40b7fffffffULL, }, - { 0xfe196fe57fffffffULL, 0x050bc0117e7bb00bULL, }, /* 80 */ - { 0xfe299f467fffffffULL, 0x05cb2b207fffffffULL, }, - { 0xff5d018239cf8b7fULL, 0x0798e21e2b2b2513ULL, }, - { 0xfecdfe1e645a7d99ULL, 0x00d3dcf00dea608dULL, }, - { 0xffebe0507fffffffULL, 0x0150aaf30dc02967ULL, }, - { 0xffec8bad7fffffffULL, 0x01828e9310087db0ULL, }, - { 0xfff9423b39cf8b7fULL, 0x01fae4ad056841b8ULL, }, - { 0xfff35804645a7d99ULL, 0x003737ba01be3861ULL, }, - { 0xffff2aee7fffffffULL, 0x0057bed401b8eeafULL, }, /* 88 */ - { 0xffff32047fffffffULL, 0x0064bf7c02021ffbULL, }, - { 0xffffb89f39cf8b7fULL, 0x00841c7300ad6409ULL, }, - { 0xffff79fe645a7d99ULL, 0x000e642e0037e4a5ULL, }, - { 0xfffff72f7fffffffULL, 0x0016de7600373b15ULL, }, - { 0xfffff77a7fffffffULL, 0x001a420100406619ULL, }, - { 0xfffffd0b39cf8b7fULL, 0x00226e950015b801ULL, }, - { 0xfffffa72645a7d99ULL, 0x0003c03400070049ULL, }, - { 0xffffffa27fffffffULL, 0x0005f5d70006eb0bULL, }, /* 96 */ - { 0xfffffff97fffffffULL, 0x000978af0006d60eULL, }, - { 0xffffffff7fffffffULL, 0x000f0d050006c150ULL, }, - { 0xffffffff7fffffffULL, 0x0017eac30006acd1ULL, }, - { 0xffffffff7fffffffULL, 0x001b76100007c878ULL, }, - { 0xffffffff7fffffffULL, 0x001f87d000091335ULL, }, - { 0xffffffff7fffffffULL, 0x002433ef000a94d9ULL, }, - { 0xffffffff7fffffffULL, 0x0029914d000c5680ULL, }, - { 0xffffffff39cf8b7fULL, 0x003681f800042937ULL, }, /* 104 */ - { 0xffffffff1a1c28c3ULL, 0x004779e10001673fULL, }, - { 0xffffffff0bcae025ULL, 0x005dba1000007928ULL, }, - { 0xffffffff055376c1ULL, 0x007ae77c000028dcULL, }, - { 0xfffffffe093ed554ULL, 0x000d636d00000d2bULL, }, - { 0xfffffffc100c9463ULL, 0x0001755c0000043eULL, }, - { 0xfffffff81bdc128cULL, 0x000028ab0000015eULL, }, - { 0xfffffff0305c8babULL, 0x0000046e00000070ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADD_Q_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_maddr_q_h.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_maddr_q_h.c deleted file mode 100644 index a4713f2321e7..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_maddr_q_h.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MADDR_Q.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MADDR_Q.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 16 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x38e538e538e538e5ULL, 0x38e538e538e538e5ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x2224222422242224ULL, 0x2224222422242224ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x12f9da154bdd12f9ULL, 0xda154bdd12f9da15ULL, }, - { 0x0003000300020003ULL, 0x0003000200030003ULL, }, - { 0x0002000200010002ULL, 0x0002000100020002ULL, }, /* 24 */ - { 0x0002000200010002ULL, 0x0002000100020002ULL, }, - { 0xc71ec71ec71dc71eULL, 0xc71ec71dc71ec71eULL, }, - { 0x0001000100000001ULL, 0x0001000000010001ULL, }, - { 0xdddedddedddddddeULL, 0xdddedddddddedddeULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xed0925edb425ed09ULL, 0x25edb425ed0925edULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 32 */ - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x2222222322222222ULL, 0x2223222222222223ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x147b147c147b147bULL, 0x147c147b147b147cULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0x0b61e93f2d840b61ULL, 0xe93f2d840b61e93fULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, /* 40 */ - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0xdddedddfdddedddeULL, 0xdddfdddedddedddfULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0xeb85eb86eb85eb85ULL, 0xeb86eb85eb85eb86ULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0xf49f16c2d27df49fULL, 0x16c2d27df49f16c2ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0xffff00000001ffffULL, 0x00000001ffff0000ULL, }, /* 48 */ - { 0xffff00000001ffffULL, 0x00000001ffff0000ULL, }, - { 0x12f6da134bdc12f6ULL, 0xda134bdc12f6da13ULL, }, - { 0xffff00000002ffffULL, 0x00000002ffff0000ULL, }, - { 0x0b60e93e2d860b60ULL, 0xe93e2d860b60e93eULL, }, - { 0xffffffff0003ffffULL, 0xffff0003ffffffffULL, }, - { 0x0651194765270651ULL, 0x1947652706511947ULL, }, - { 0xfffffffe0004ffffULL, 0xfffe0004fffffffeULL, }, - { 0xfffffffe0003ffffULL, 0xfffe0003fffffffeULL, }, /* 56 */ - { 0xfffffffe0003ffffULL, 0xfffe0003fffffffeULL, }, - { 0xed0925ecb428ed09ULL, 0x25ecb428ed0925ecULL, }, - { 0xffffffff0002ffffULL, 0xffff0002ffffffffULL, }, - { 0xf49e16c1d27ef49eULL, 0x16c1d27ef49e16c1ULL, }, - { 0xfffeffff0001fffeULL, 0xffff0001fffeffffULL, }, - { 0xf9ace6b69adef9acULL, 0xe6b69adef9ace6b6ULL, }, - { 0xfffeffff0001fffeULL, 0xffff0001fffeffffULL, }, - { 0x6fb804f50cbf38c5ULL, 0x2c6a0103000331f0ULL, }, /* 64 */ - { 0x73b204e2253812d4ULL, 0x3796fae5ffc2fe1aULL, }, - { 0x7fff14e60f13c53dULL, 0x4f0ff5d500c4e6f1ULL, }, - { 0x171210822ccab176ULL, 0x0bdeeb4001ccf94aULL, }, - { 0x1b0c106f45438b85ULL, 0x170ae522018bc574ULL, }, - { 0x1b30106f7447a4e0ULL, 0x19d90a380512fb41ULL, }, - { 0x1df8103049bdd8baULL, 0x1fc028e7f6fd134bULL, }, - { 0x1a3c10417fffe5f1ULL, 0x0eda690ae8970040ULL, }, - { 0x6862204569da985aULL, 0x265363fae999e917ULL, }, /* 72 */ - { 0x6b2a20063f50cc34ULL, 0x2c3a7fffdb840121ULL, }, - { 0x7fff53b565ce363dULL, 0x38a17fff13bd0bdfULL, }, - { 0x369a458932275144ULL, 0x15207fff4d3a035dULL, }, - { 0xcdad41254fde3d7dULL, 0xd1ef756a4e4215b6ULL, }, - { 0xc9f141367fff4ab4ULL, 0xc1097fff3fdc02abULL, }, - { 0x808c330a4c5865bbULL, 0x9d887fff7959fa29ULL, }, - { 0xe31636ed7fff6c9fULL, 0x032b7fff7fff00e7ULL, }, - { 0xfe192c1c7fff7fffULL, 0x05097fff7e7a0057ULL, }, /* 80 */ - { 0xfe292c3e7fff4707ULL, 0x05c83b1a7fff008fULL, }, - { 0xff5d102139cf0662ULL, 0x079520c82b2b00b8ULL, }, - { 0xfece12f0645904e7ULL, 0x00d302440dea008eULL, }, - { 0xffec0f357fff082bULL, 0x014f02780dc00035ULL, }, - { 0xffed0f417fff0488ULL, 0x0181012410080057ULL, }, - { 0xfff9059039cf0068ULL, 0x01f900a205680070ULL, }, - { 0xfff3068864590050ULL, 0x0037000b01be0056ULL, }, - { 0xffff053f7fff0085ULL, 0x0057000c01b90020ULL, }, /* 88 */ - { 0xffff05437fff004aULL, 0x0064000602020035ULL, }, - { 0x000001eb39cf0007ULL, 0x0083000300ad0044ULL, }, - { 0x0000024164590005ULL, 0x000e000000380034ULL, }, - { 0x000001cf7fff0008ULL, 0x0016000000370014ULL, }, - { 0x000001d07fff0004ULL, 0x0019000000400021ULL, }, - { 0x000000a939cf0000ULL, 0x002100000016002bULL, }, - { 0x000000c664590000ULL, 0x0004000000070021ULL, }, - { 0x0000009f7fff0000ULL, 0x000600000007000cULL, }, /* 96 */ - { 0x000000807fff0000ULL, 0x000a000000070005ULL, }, - { 0x000000677fff0000ULL, 0x0010000000070002ULL, }, - { 0x000000537fff0000ULL, 0x0019000000070001ULL, }, - { 0x000000537fff0000ULL, 0x001d000000080002ULL, }, - { 0x000000537fff0000ULL, 0x0021000000090003ULL, }, - { 0x000000537fff0000ULL, 0x00260000000a0005ULL, }, - { 0x000000537fff0000ULL, 0x002c0000000c0008ULL, }, - { 0x0000001e39cf0000ULL, 0x003a00000004000aULL, }, /* 104 */ - { 0x0000000b1a1c0000ULL, 0x004c00000001000dULL, }, - { 0x000000040bcb0000ULL, 0x0064000000000011ULL, }, - { 0x0000000105530000ULL, 0x0083000000000016ULL, }, - { 0x00000001093e0000ULL, 0x000e000000000011ULL, }, - { 0x00000001100b0000ULL, 0x000200000000000dULL, }, - { 0x000000011bd90000ULL, 0x000000000000000aULL, }, - { 0x0000000130570000ULL, 0x0000000000000008ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_maddr_q_w.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_maddr_q_w.c deleted file mode 100644 index 19eccbf5bab0..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_maddr_q_w.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MADDR_Q.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MADDR_Q.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x38e38e3b38e38e3bULL, 0x38e38e3b38e38e3bULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x2222222522222225ULL, 0x2222222522222225ULL, }, - { 0x0000000300000003ULL, 0x0000000300000003ULL, }, - { 0x12f684c14bda12faULL, 0xda12f68812f684c1ULL, }, - { 0x0000000400000003ULL, 0x0000000400000004ULL, }, - { 0x0000000300000002ULL, 0x0000000300000003ULL, }, /* 24 */ - { 0x0000000300000002ULL, 0x0000000300000003ULL, }, - { 0xc71c71cac71c71c9ULL, 0xc71c71cac71c71caULL, }, - { 0x0000000200000001ULL, 0x0000000200000002ULL, }, - { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xed097b43b425ed0aULL, 0x25ed097ced097b43ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x2222222322222223ULL, 0x2222222422222223ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x147ae148147ae148ULL, 0x147ae149147ae148ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x0b60b60c2d82d82eULL, 0xe93e93ea0b60b60cULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, /* 40 */ - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xeb851eb9eb851eb8ULL, 0xeb851eb9eb851eb9ULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xf49f49f5d27d27d3ULL, 0x16c16c17f49f49f5ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x12f684be4bda12f8ULL, 0xda12f68512f684beULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0x0b60b60c2d82d830ULL, 0xe93e93e90b60b60cULL, }, - { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, - { 0x06522c3f6522c3f7ULL, 0x1948b0fb06522c3fULL, }, - { 0x0000000000000004ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, /* 56 */ - { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, - { 0xed097b43b425ed0cULL, 0x25ed097bed097b43ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0xf49f49f5d27d27d4ULL, 0x16c16c17f49f49f5ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0xf9add3c19add3c0eULL, 0xe6b74f04f9add3c1ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x6fb7e8890cbdc0d3ULL, 0x2c6b144700049a05ULL, }, /* 64 */ - { 0x73b239d7253787d5ULL, 0x379780f0ffc424ccULL, }, - { 0x7fffffff0f127795ULL, 0x4f10998300c57f01ULL, }, - { 0x1713a7162cca6b3bULL, 0x0be04ded01cca270ULL, }, - { 0x1b0df8644544323dULL, 0x170cba96018c2d37ULL, }, - { 0x1b323a657448a84fULL, 0x19dc46aa051313c6ULL, }, - { 0x1dfa85ed49be7970ULL, 0x1fc3e135f6fe3018ULL, }, - { 0x1a3e24ca7fffffffULL, 0x0edd19d1e8983ff6ULL, }, - { 0x6863455169daefbfULL, 0x26563264e9999a2bULL, }, /* 72 */ - { 0x6b2b90d93f50c0e0ULL, 0x2c3dccefdb84b67dULL, }, - { 0x7fffffff65cdd2a4ULL, 0x38a5555313bd77c9ULL, }, - { 0x369baa393226e271ULL, 0x1523c34a4d39d0a3ULL, }, - { 0xcdaf51504fded617ULL, 0xd1f377b44e40f412ULL, }, - { 0xc9f2f02d7fffffffULL, 0xc10cb0503fdb03f0ULL, }, - { 0x808e9a674c590fccULL, 0x9d8b1e4779575ccaULL, }, - { 0xe319324b7fffffffULL, 0x032ce4297fffffffULL, }, - { 0xfe196fe67fffffffULL, 0x050bc0417e7bb00bULL, }, /* 80 */ - { 0xfe299f487fffffffULL, 0x05cb2b577fffffffULL, }, - { 0xff5d018339cf8b80ULL, 0x0798e2662b2b2514ULL, }, - { 0xfecdfe20645a7d9bULL, 0x00d3dcf80dea608eULL, }, - { 0xffebe0517fffffffULL, 0x0150ab000dc02968ULL, }, - { 0xffec8baf7fffffffULL, 0x01828ea210087db2ULL, }, - { 0xfff9423c39cf8b80ULL, 0x01fae4c1056841b9ULL, }, - { 0xfff35806645a7d9bULL, 0x003737bc01be3862ULL, }, - { 0xffff2aee7fffffffULL, 0x0057bed801b8eeb0ULL, }, /* 88 */ - { 0xffff32047fffffffULL, 0x0064bf8102021ffcULL, }, - { 0xffffb89f39cf8b80ULL, 0x00841c7a00ad640aULL, }, - { 0xffff79fe645a7d9bULL, 0x000e642f0037e4a6ULL, }, - { 0xfffff7307fffffffULL, 0x0016de7800373b16ULL, }, - { 0xfffff77b7fffffffULL, 0x001a42040040661aULL, }, - { 0xfffffd0c39cf8b80ULL, 0x00226e990015b802ULL, }, - { 0xfffffa75645a7d9bULL, 0x0003c0350007004aULL, }, - { 0xffffffa37fffffffULL, 0x0005f5d90006eb0dULL, }, /* 96 */ - { 0xfffffffa7fffffffULL, 0x000978b30006d610ULL, }, - { 0x000000007fffffffULL, 0x000f0d0c0006c153ULL, }, - { 0x000000007fffffffULL, 0x0017eacf0006acd5ULL, }, - { 0x000000007fffffffULL, 0x001b761e0007c87dULL, }, - { 0x000000007fffffffULL, 0x001f87e00009133bULL, }, - { 0x000000007fffffffULL, 0x00243402000a94e0ULL, }, - { 0x000000007fffffffULL, 0x00299164000c5689ULL, }, - { 0x0000000039cf8b80ULL, 0x003682160004293bULL, }, /* 104 */ - { 0x000000001a1c28c4ULL, 0x00477a0900016741ULL, }, - { 0x000000000bcae026ULL, 0x005dba4500007929ULL, }, - { 0x00000000055376c2ULL, 0x007ae7c2000028ddULL, }, - { 0x00000000093ed557ULL, 0x000d637500000d2cULL, }, - { 0x00000000100c9469ULL, 0x0001755d0000043fULL, }, - { 0x000000001bdc1297ULL, 0x000028ac0000015eULL, }, - { 0x00000000305c8bbfULL, 0x0000046e00000071ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msub_q_h.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msub_q_h.c deleted file mode 100644 index b584736ed1c8..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msub_q_h.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MSUB_Q.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MSUB_Q.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xfffcfffdfffcfffcULL, 0xfffdfffcfffcfffdULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, /* 8 */ - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffbfffbfffbfffbULL, 0xfffbfffbfffbfffbULL, }, /* 16 */ - { 0xfffbfffbfffbfffbULL, 0xfffbfffbfffbfffbULL, }, - { 0xc716c716c716c716ULL, 0xc716c716c716c716ULL, }, - { 0xfff9fff9fff9fff9ULL, 0xfff9fff9fff9fff9ULL, }, - { 0xddd6ddd6ddd6ddd6ULL, 0xddd6ddd6ddd6ddd6ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xed0125e4b41ced01ULL, 0x25e4b41ced0125e4ULL, }, - { 0xfff7fff6fff6fff7ULL, 0xfff6fff6fff7fff6ULL, }, - { 0xfff7fff6fff6fff7ULL, 0xfff6fff6fff7fff6ULL, }, /* 24 */ - { 0xfff7fff6fff6fff7ULL, 0xfff6fff6fff7fff6ULL, }, - { 0x38da38d938d938daULL, 0x38d938d938da38d9ULL, }, - { 0xfff6fff5fff5fff6ULL, 0xfff5fff5fff6fff5ULL, }, - { 0x2218221722172218ULL, 0x2217221722182217ULL, }, - { 0xfff6fff5fff5fff6ULL, 0xfff5fff5fff6fff5ULL, }, - { 0x12ecda084bcf12ecULL, 0xda084bcf12ecda08ULL, }, - { 0xfff6fff5fff5fff6ULL, 0xfff5fff5fff6fff5ULL, }, - { 0xfff5fff4fff4fff5ULL, 0xfff4fff4fff5fff4ULL, }, /* 32 */ - { 0xfff5fff4fff4fff5ULL, 0xfff4fff4fff5fff4ULL, }, - { 0xddd2ddd1ddd1ddd2ULL, 0xddd1ddd1ddd2ddd1ULL, }, - { 0xfff4fff3fff3fff4ULL, 0xfff3fff3fff4fff3ULL, }, - { 0xeb78eb77eb77eb78ULL, 0xeb77eb77eb78eb77ULL, }, - { 0xfff3fff2fff2fff3ULL, 0xfff2fff2fff3fff2ULL, }, - { 0xf49216b3d26ef492ULL, 0x16b3d26ef49216b3ULL, }, - { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, }, - { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, }, /* 40 */ - { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, }, - { 0x2214221322132214ULL, 0x2213221322142213ULL, }, - { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, }, - { 0x146d146c146c146dULL, 0x146c146c146d146cULL, }, - { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, }, - { 0x0b52e92f2d740b52ULL, 0xe92f2d740b52e92fULL, }, - { 0xfff1fff0fff1fff1ULL, 0xfff0fff1fff1fff0ULL, }, - { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, }, /* 48 */ - { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, }, - { 0xecf925dcb414ecf9ULL, 0x25dcb414ecf925dcULL, }, - { 0xffefffefffeeffefULL, 0xffefffeeffefffefULL, }, - { 0xf48e16b0d26af48eULL, 0x16b0d26af48e16b0ULL, }, - { 0xffeeffeeffedffeeULL, 0xffeeffedffeeffeeULL, }, - { 0xf99be6a59ac8f99bULL, 0xe6a59ac8f99be6a5ULL, }, - { 0xffedffedffebffedULL, 0xffedffebffedffedULL, }, - { 0xffedffecffebffedULL, 0xffecffebffedffecULL, }, /* 56 */ - { 0xffedffecffebffedULL, 0xffecffebffedffecULL, }, - { 0x12e3d9fe4bc512e3ULL, 0xd9fe4bc512e3d9feULL, }, - { 0xffedffebffebffedULL, 0xffebffebffedffebULL, }, - { 0x0b4de9292d6e0b4dULL, 0xe9292d6e0b4de929ULL, }, - { 0xffecffeaffebffecULL, 0xffeaffebffecffeaULL, }, - { 0x063e1932650e063eULL, 0x1932650e063e1932ULL, }, - { 0xffecffe8ffebffecULL, 0xffe8ffebffecffe8ULL, }, - { 0x9032faf1f32dc724ULL, 0xd37cfee8ffe7cdf6ULL, }, /* 64 */ - { 0x8c37fb04dab3ed15ULL, 0xc8500506002701cbULL, }, - { 0x8000eb00f0d83aacULL, 0xb0d70a15ff2518f4ULL, }, - { 0xe8edef64d3204e73ULL, 0xf40714a9fe1d069aULL, }, - { 0xe4f2ef77baa67464ULL, 0xe8db1ac7fe5d3a6fULL, }, - { 0xe4cdef768ba25b09ULL, 0xe60bf5b1fad604a2ULL, }, - { 0xe204efb4b62c272fULL, 0xe023d70208eaec98ULL, }, - { 0xe5c0efa2800019f7ULL, 0xf10996de174fffa3ULL, }, - { 0x9799df9e9625678eULL, 0xd9909bed164d16ccULL, }, /* 72 */ - { 0x94d0dfdcc0af33b4ULL, 0xd3a880002461fec2ULL, }, - { 0x8000ac2c9a31c9abULL, 0xc7408000ec28f404ULL, }, - { 0xc964ba57cdd7aea3ULL, 0xeac18000b2aafc86ULL, }, - { 0x3251bebbb01fc26aULL, 0x2df18a94b1a2ea2cULL, }, - { 0x360dbea98000b532ULL, 0x3ed78000c007fd37ULL, }, - { 0x7f71ccd4b3a69a2aULL, 0x62588000868905b9ULL, }, - { 0x1ce6c8f180009346ULL, 0xfcb580008000fefbULL, }, - { 0x37e5be19a862dbafULL, 0xfea58b5e8000fe57ULL, }, /* 80 */ - { 0x39c0be4bdd7bcb85ULL, 0xfed88000953fff6aULL, }, - { 0x5f7d948aca8d9bc1ULL, 0xff3480008000ff95ULL, }, - { 0x0bb4a742f1e1847fULL, 0xfe7e80008000ff7cULL, }, - { 0x16a395c8f655d6c0ULL, 0xff618b5e8000ff29ULL, }, - { 0x1763961afc30c464ULL, 0xff788000953fffb4ULL, }, - { 0x26ab8000fa188e23ULL, 0xffa280008000ffcaULL, }, - { 0x04bd964dfe708000ULL, 0xff4e80008000ffbdULL, }, - { 0x092a817dfeeed540ULL, 0xffb68b5e8000ff93ULL, }, /* 88 */ - { 0x097881deff94c239ULL, 0xffc08000953fffd9ULL, }, - { 0x0fa88000ff5889feULL, 0xffd380008000ffe4ULL, }, - { 0x01eb964dffd38000ULL, 0xffaa80008000ffddULL, }, - { 0x03b5817dffe1d540ULL, 0xffdc8b5e8000ffc7ULL, }, - { 0x03d481defff3c239ULL, 0xffe18000953fffebULL, }, - { 0x06548000ffeb89feULL, 0xffea80008000fff1ULL, }, - { 0x00c6964dfffa8000ULL, 0xffd680008000ffedULL, }, - { 0x017e817dfffbd540ULL, 0xffee8b5e8000ffe1ULL, }, /* 96 */ - { 0x02e28000fffcf1b8ULL, 0xfff895b98000ffcdULL, }, - { 0x05938000fffdfb3aULL, 0xfffc9f298000ffadULL, }, - { 0x0ac88000fffdfe67ULL, 0xfffea7c28000ff79ULL, }, - { 0x0b238063fffefdb0ULL, 0xfffe8000953fffd0ULL, }, - { 0x0b8180c5fffffca8ULL, 0xfffe8000a6f7ffefULL, }, - { 0x0be28127fffffb2bULL, 0xfffe8000b5befffaULL, }, - { 0x0c478189fffff904ULL, 0xfffe8000c211fffdULL, }, - { 0x144c8000fffef2a8ULL, 0xfffe80009905fffdULL, }, /* 104 */ - { 0x218f8000fffce682ULL, 0xfffe80008000fffdULL, }, - { 0x377d8000fff9cf4eULL, 0xfffe80008000fffdULL, }, - { 0x5bc08000fff5a2fbULL, 0xfffe80008000fffdULL, }, - { 0x0b3f964dfffd8d66ULL, 0xfffc80008000fffcULL, }, - { 0x0160a8b7ffff8000ULL, 0xfff880008000fffbULL, }, - { 0x002bb7ecffff8000ULL, 0xfff080008000fff9ULL, }, - { 0x0005c47affff8000ULL, 0xffe180008000fff7ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msub_q_w.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msub_q_w.c deleted file mode 100644 index 56191924a1d6..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msub_q_w.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MSUB_Q.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MSUB_Q.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffdfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, /* 8 */ - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, }, /* 16 */ - { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, }, - { 0xc71c71c1c71c71c1ULL, 0xc71c71c1c71c71c1ULL, }, - { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, }, - { 0xddddddd7ddddddd7ULL, 0xddddddd7ddddddd7ULL, }, - { 0xfffffff9fffffff9ULL, 0xfffffff9fffffff9ULL, }, - { 0xed097b3ab425ed01ULL, 0x25ed0973ed097b3aULL, }, - { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, }, - { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, }, /* 24 */ - { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, }, - { 0x38e38e3038e38e30ULL, 0x38e38e3038e38e30ULL, }, - { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, }, - { 0x2222221922222219ULL, 0x2222221922222219ULL, }, - { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, }, - { 0x12f684b44bda12edULL, 0xda12f67c12f684b4ULL, }, - { 0xfffffff6fffffff7ULL, 0xfffffff7fffffff6ULL, }, - { 0xfffffff5fffffff6ULL, 0xfffffff6fffffff5ULL, }, /* 32 */ - { 0xfffffff5fffffff6ULL, 0xfffffff6fffffff5ULL, }, - { 0xddddddd2ddddddd3ULL, 0xddddddd3ddddddd2ULL, }, - { 0xfffffff4fffffff5ULL, 0xfffffff5fffffff4ULL, }, - { 0xeb851eabeb851eacULL, 0xeb851eaceb851eabULL, }, - { 0xfffffff2fffffff3ULL, 0xfffffff3fffffff2ULL, }, - { 0xf49f49e6d27d27c4ULL, 0x16c16c09f49f49e6ULL, }, - { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, }, - { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, }, /* 40 */ - { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, }, - { 0x2222221322222213ULL, 0x2222221322222213ULL, }, - { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, }, - { 0x147ae138147ae138ULL, 0x147ae138147ae138ULL, }, - { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, }, - { 0x0b60b5fb2d82d81dULL, 0xe93e93d90b60b5fbULL, }, - { 0xffffffefffffffefULL, 0xffffffefffffffefULL, }, - { 0xffffffeeffffffeeULL, 0xffffffefffffffeeULL, }, /* 48 */ - { 0xffffffeeffffffeeULL, 0xffffffefffffffeeULL, }, - { 0xed097b2fb425ecf6ULL, 0x25ed0969ed097b2fULL, }, - { 0xffffffecffffffecULL, 0xffffffeeffffffecULL, }, - { 0xf49f49e0d27d27bdULL, 0x16c16c04f49f49e0ULL, }, - { 0xffffffebffffffeaULL, 0xffffffedffffffebULL, }, - { 0xf9add3ab9add3bf6ULL, 0xe6b74ef0f9add3abULL, }, - { 0xffffffeaffffffe8ULL, 0xffffffecffffffeaULL, }, - { 0xffffffeaffffffe8ULL, 0xffffffebffffffeaULL, }, /* 56 */ - { 0xffffffeaffffffe8ULL, 0xffffffebffffffeaULL, }, - { 0x12f684a74bda12deULL, 0xda12f66f12f684a7ULL, }, - { 0xffffffe9ffffffe8ULL, 0xffffffeaffffffe9ULL, }, - { 0x0b60b5f42d82d815ULL, 0xe93e93d20b60b5f4ULL, }, - { 0xffffffe8ffffffe7ULL, 0xffffffe8ffffffe8ULL, }, - { 0x06522c276522c3d9ULL, 0x1948b0e406522c27ULL, }, - { 0xffffffe7ffffffe7ULL, 0xffffffe7ffffffe7ULL, }, - { 0x9048175df3423f14ULL, 0xd394eba0fffb65e2ULL, }, /* 64 */ - { 0x8c4dc60edac87812ULL, 0xc8687ef6003bdb1bULL, }, - { 0x80000000f0ed8852ULL, 0xb0ef6662ff3a80e6ULL, }, - { 0xe8ec58e8d33594acULL, 0xf41fb1f8fe335d76ULL, }, - { 0xe4f20799babbcdaaULL, 0xe8f3454efe73d2afULL, }, - { 0xe4cdc5978bb75798ULL, 0xe623b939faecec20ULL, }, - { 0xe2057a0fb6418676ULL, 0xe03c1eae0901cfcdULL, }, - { 0xe5c1db3280000000ULL, 0xf122e6111767bfefULL, }, - { 0x979cbaab96251040ULL, 0xd9a9cd7d166665baULL, }, /* 72 */ - { 0x94d46f23c0af3f1eULL, 0xd3c232f2247b4967ULL, }, - { 0x800000009a322d5aULL, 0xc75aaa8dec42881aULL, }, - { 0xc96455c6cdd91d8cULL, 0xeadc3c95b2c62f40ULL, }, - { 0x3250aeaeb02129e6ULL, 0x2e0c882bb1bf0bd0ULL, }, - { 0x360d0fd180000000ULL, 0x3ef34f8ec024fbf2ULL, }, - { 0x7f716597b3a6f032ULL, 0x6274e19686a8a318ULL, }, - { 0x1ce6cdb280000000ULL, 0xfcd31bb480000000ULL, }, - { 0x37e70b49a8625540ULL, 0xfeb1f7e080000000ULL, }, /* 80 */ - { 0x39c31699dd7c5546ULL, 0xfee37780953f52fcULL, }, - { 0x5f82316fca8f431eULL, 0xff3c0af780000000ULL, }, - { 0x0bb5432ff1e2e177ULL, 0xfe8d6e9580000000ULL, }, - { 0x16a56af3f656d2b3ULL, 0xff67ba1b80000000ULL, }, - { 0x17664384fc31bf42ULL, 0xff7e4aa4953f52fcULL, }, - { 0x26b0cbfdfa1b830bULL, 0xffa6ab9180000000ULL, }, - { 0x04be31a4fe719ab1ULL, 0xff57124580000000ULL, }, - { 0x092c8a1ffeef4c68ULL, 0xffba958e80000000ULL, }, /* 88 */ - { 0x097aa960ff949347ULL, 0xffc4dede953f52fcULL, }, - { 0x0fac7158ff59ab27ULL, 0xffd7471a80000000ULL, }, - { 0x01ebdf01ffd41248ULL, 0xffb2fdd380000000ULL, }, - { 0x03b76546ffe1ee50ULL, 0xffe05b1780000000ULL, }, - { 0x03d70afdfff427aaULL, 0xffe50b86953f52fcULL, }, - { 0x065971c1ffeda8dfULL, 0xffed6fa980000000ULL, }, - { 0x00c741e8fffb2801ULL, 0xffdce50280000000ULL, }, - { 0x01816947fffcaf39ULL, 0xfff1931580000000ULL, }, /* 96 */ - { 0x02e97a17fffdbb03ULL, 0xfffa128380000000ULL, }, - { 0x05a1edf3fffe7250ULL, 0xfffd906f80000000ULL, }, - { 0x0ae508c5fffeefc8ULL, 0xfffeffc380000000ULL, }, - { 0x0b41cf1bffff94c3ULL, 0xffff25bb953f52fcULL, }, - { 0x0ba1ab79ffffd5c1ULL, 0xffff4613a6f7bf69ULL, }, - { 0x0c04b828ffffef5bULL, 0xffff61a0b5bf25caULL, }, - { 0x0c6b104efffff971ULL, 0xffff7918c21285a5ULL, }, - { 0x148886c7fffff5d8ULL, 0xffffa3179907b21bULL, }, /* 104 */ - { 0x21f39335fffff046ULL, 0xffffc00380000000ULL, }, - { 0x38235e38ffffe7a6ULL, 0xffffd3ee80000000ULL, }, - { 0x5cd2ce93ffffda4bULL, 0xffffe1a680000000ULL, }, - { 0x0b60ff8afffff60aULL, 0xffffc69a80000000ULL, }, - { 0x01651818fffffd5eULL, 0xffff937480000000ULL, }, - { 0x002bc65fffffff4dULL, 0xffff32bb80000000ULL, }, - { 0x00055dbfffffffd0ULL, 0xfffe7bd280000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUB_Q_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msubr_q_h.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msubr_q_h.c deleted file mode 100644 index 0be6d5141860..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msubr_q_h.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MSUBR_Q.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MSUBR_Q.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xc71bc71bc71bc71bULL, 0xc71bc71bc71bc71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xdddcdddcdddcdddcULL, 0xdddcdddcdddcdddcULL, }, - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xed0725ebb423ed07ULL, 0x25ebb423ed0725ebULL, }, - { 0xfffdfffdfffefffdULL, 0xfffdfffefffdfffdULL, }, - { 0xfffefffefffffffeULL, 0xfffefffffffefffeULL, }, /* 24 */ - { 0xfffefffefffffffeULL, 0xfffefffffffefffeULL, }, - { 0x38e238e238e338e2ULL, 0x38e238e338e238e2ULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0x2222222222232222ULL, 0x2222222322222222ULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, - { 0x12f7da134bdb12f7ULL, 0xda134bdb12f7da13ULL, }, - { 0x0001000000010001ULL, 0x0000000100010000ULL, }, - { 0x0001000000010001ULL, 0x0000000100010000ULL, }, /* 32 */ - { 0x0001000000010001ULL, 0x0000000100010000ULL, }, - { 0xdddedddddddedddeULL, 0xdddddddedddeddddULL, }, - { 0x0001000000010001ULL, 0x0000000100010000ULL, }, - { 0xeb85eb84eb85eb85ULL, 0xeb84eb85eb85eb84ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xf49f16c1d27cf49fULL, 0x16c1d27cf49f16c1ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 40 */ - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x2222222122222222ULL, 0x2221222222222221ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x147b147a147b147bULL, 0x147a147b147b147aULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0b61e93e2d830b61ULL, 0xe93e2d830b61e93eULL, }, - { 0x0001000000000001ULL, 0x0000000000010000ULL, }, - { 0x00010000ffff0001ULL, 0x0000ffff00010000ULL, }, /* 48 */ - { 0x00010000ffff0001ULL, 0x0000ffff00010000ULL, }, - { 0xed0a25edb424ed0aULL, 0x25edb424ed0a25edULL, }, - { 0x00010000fffe0001ULL, 0x0000fffe00010000ULL, }, - { 0xf4a016c2d27af4a0ULL, 0x16c2d27af4a016c2ULL, }, - { 0x00010001fffd0001ULL, 0x0001fffd00010001ULL, }, - { 0xf9afe6b99ad9f9afULL, 0xe6b99ad9f9afe6b9ULL, }, - { 0x00010002fffc0001ULL, 0x0002fffc00010002ULL, }, - { 0x00010002fffd0001ULL, 0x0002fffd00010002ULL, }, /* 56 */ - { 0x00010002fffd0001ULL, 0x0002fffd00010002ULL, }, - { 0x12f7da144bd812f7ULL, 0xda144bd812f7da14ULL, }, - { 0x00010001fffe0001ULL, 0x0001fffe00010001ULL, }, - { 0x0b62e93f2d820b62ULL, 0xe93f2d820b62e93fULL, }, - { 0x00020001ffff0002ULL, 0x0001ffff00020001ULL, }, - { 0x0654194a65220654ULL, 0x194a65220654194aULL, }, - { 0x00020001ffff0002ULL, 0x0001ffff00020001ULL, }, - { 0x9048fb0bf341c73bULL, 0xd396fefdfffdce10ULL, }, /* 64 */ - { 0x8c4efb1edac8ed2cULL, 0xc86a051b003e01e6ULL, }, - { 0x8000eb1af0ed3ac3ULL, 0xb0f10a2bff3c190fULL, }, - { 0xe8edef7ed3364e8aULL, 0xf42214c0fe3406b6ULL, }, - { 0xe4f3ef91babd747bULL, 0xe8f61adefe753a8cULL, }, - { 0xe4cfef918bb95b20ULL, 0xe627f5c8faee04bfULL, }, - { 0xe207efd0b6432746ULL, 0xe040d7190903ecb5ULL, }, - { 0xe5c3efbf80001a0fULL, 0xf12696f61769ffc0ULL, }, - { 0x979ddfbb962567a6ULL, 0xd9ad9c06166716e9ULL, }, /* 72 */ - { 0x94d5dffac0af33ccULL, 0xd3c68000247cfedfULL, }, - { 0x8000ac4b9a31c9c4ULL, 0xc75f8000ec43f421ULL, }, - { 0xc965ba77cdd8aebdULL, 0xeae08000b2c6fca3ULL, }, - { 0x3252bedbb021c284ULL, 0x2e118a95b1beea4aULL, }, - { 0x360ebeca8000b54dULL, 0x3ef78000c024fd55ULL, }, - { 0x7f73ccf6b3a79a46ULL, 0x6278800086a705d7ULL, }, - { 0x1ce9c91380009362ULL, 0xfcd580008000ff19ULL, }, - { 0x37ebbe42a862dbb9ULL, 0xfeb38b5e8000fe89ULL, }, /* 80 */ - { 0x39c7be75dd7ccb94ULL, 0xfee48000953fff7cULL, }, - { 0x5f8994cfca8f9bdeULL, 0xff3c80008000ffa2ULL, }, - { 0x0bb6a77cf1e284a3ULL, 0xfe8d80008000ff8cULL, }, - { 0x16a7960ef656d6ccULL, 0xff688b5e8000ff44ULL, }, - { 0x17689660fc31c475ULL, 0xff7f8000953fffbeULL, }, - { 0x26b48000fa1a8e43ULL, 0xffa780008000ffd1ULL, }, - { 0x04bf964dfe718000ULL, 0xff5880008000ffc6ULL, }, - { 0x092e817dfeefd540ULL, 0xffbb8b5e8000ffa2ULL, }, /* 88 */ - { 0x097c81dfff94c239ULL, 0xffc58000953fffdfULL, }, - { 0x0faf8000ff5989ffULL, 0xffd780008000ffe9ULL, }, - { 0x01ec964dffd48000ULL, 0xffb280008000ffe4ULL, }, - { 0x03b8817dffe2d540ULL, 0xffe08b5e8000ffd3ULL, }, - { 0x03d881dffff4c239ULL, 0xffe58000953ffff0ULL, }, - { 0x065b8000ffed89ffULL, 0xffed80008000fff5ULL, }, - { 0x00c7964dfffb8000ULL, 0xffdc80008000fff2ULL, }, - { 0x0181817dfffdd540ULL, 0xfff18b5e8000ffe9ULL, }, /* 96 */ - { 0x02e98000fffef1b9ULL, 0xfffa95ba8000ffdbULL, }, - { 0x05a18000fffffb3bULL, 0xfffe9f2a8000ffc4ULL, }, - { 0x0ae38000fffffe68ULL, 0xffffa7c48000ff9fULL, }, - { 0x0b4080630000fdb2ULL, 0xffff8000953fffdeULL, }, - { 0x0ba080c60000fcabULL, 0xffff8000a6f7fff4ULL, }, - { 0x0c0381280000fb2fULL, 0xffff8000b5befffcULL, }, - { 0x0c69818a0000f90aULL, 0xffff8000c211ffffULL, }, - { 0x148580000000f2b4ULL, 0xffff80009905ffffULL, }, /* 104 */ - { 0x21ee80000000e69aULL, 0xffff80008000ffffULL, }, - { 0x381a80000000cf7cULL, 0xffff80008000ffffULL, }, - { 0x5cc480000000a354ULL, 0xffff80008000ffffULL, }, - { 0x0b5f964d00008dd4ULL, 0xfffe80008000ffffULL, }, - { 0x0165a8b700008000ULL, 0xfffc80008000ffffULL, }, - { 0x002cb7ec00008000ULL, 0xfff880008000ffffULL, }, - { 0x0005c47b00008000ULL, 0xfff180008000ffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBR_Q_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBR_Q_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBR_Q_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBR_Q_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msubr_q_w.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msubr_q_w.c deleted file mode 100644 index 7d57cb500a80..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_msubr_q_w.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Test program for MSA instruction MSUBR_Q.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MSUBR_Q.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x38e38e3b38e38e3bULL, 0x38e38e3b38e38e3bULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x2222222522222225ULL, 0x2222222522222225ULL, }, - { 0x0000000300000003ULL, 0x0000000300000003ULL, }, - { 0x12f684c14bda12faULL, 0xda12f68812f684c1ULL, }, - { 0x0000000400000003ULL, 0x0000000400000004ULL, }, - { 0x0000000300000002ULL, 0x0000000300000003ULL, }, /* 24 */ - { 0x0000000300000002ULL, 0x0000000300000003ULL, }, - { 0xc71c71cac71c71c9ULL, 0xc71c71cac71c71caULL, }, - { 0x0000000200000001ULL, 0x0000000200000002ULL, }, - { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xed097b43b425ed0aULL, 0x25ed097ced097b43ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x2222222322222223ULL, 0x2222222422222223ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x147ae148147ae148ULL, 0x147ae149147ae148ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x0b60b60c2d82d82eULL, 0xe93e93ea0b60b60cULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, /* 40 */ - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xeb851eb9eb851eb8ULL, 0xeb851eb9eb851eb9ULL, }, - { 0x0000000100000000ULL, 0x0000000100000001ULL, }, - { 0xf49f49f5d27d27d3ULL, 0x16c16c17f49f49f5ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x12f684be4bda12f8ULL, 0xda12f68512f684beULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0x0b60b60c2d82d830ULL, 0xe93e93e90b60b60cULL, }, - { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, - { 0x06522c3f6522c3f7ULL, 0x1948b0fb06522c3fULL, }, - { 0x0000000000000004ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, /* 56 */ - { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, - { 0xed097b43b425ed0cULL, 0x25ed097bed097b43ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0xf49f49f5d27d27d4ULL, 0x16c16c17f49f49f5ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0xf9add3c19add3c0eULL, 0xe6b74f04f9add3c1ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x6fb7e8890cbdc0d3ULL, 0x2c6b144700049a05ULL, }, /* 64 */ - { 0x73b239d7253787d5ULL, 0x379780f0ffc424ccULL, }, - { 0x7fffffff0f127795ULL, 0x4f10998300c57f01ULL, }, - { 0x1713a7162cca6b3bULL, 0x0be04ded01cca270ULL, }, - { 0x1b0df8644544323dULL, 0x170cba96018c2d37ULL, }, - { 0x1b323a657448a84fULL, 0x19dc46aa051313c6ULL, }, - { 0x1dfa85ed49be7970ULL, 0x1fc3e135f6fe3018ULL, }, - { 0x1a3e24ca7fffffffULL, 0x0edd19d1e8983ff6ULL, }, - { 0x6863455169daefbfULL, 0x26563264e9999a2bULL, }, /* 72 */ - { 0x6b2b90d93f50c0e0ULL, 0x2c3dccefdb84b67dULL, }, - { 0x7fffffff65cdd2a4ULL, 0x38a5555313bd77c9ULL, }, - { 0x369baa393226e271ULL, 0x1523c34a4d39d0a3ULL, }, - { 0xcdaf51504fded617ULL, 0xd1f377b44e40f412ULL, }, - { 0xc9f2f02d7fffffffULL, 0xc10cb0503fdb03f0ULL, }, - { 0x808e9a674c590fccULL, 0x9d8b1e4779575ccaULL, }, - { 0xe319324b7fffffffULL, 0x032ce4297fffffffULL, }, - { 0xfe196fe67fffffffULL, 0x050bc0417e7bb00bULL, }, /* 80 */ - { 0xfe299f487fffffffULL, 0x05cb2b577fffffffULL, }, - { 0xff5d018339cf8b80ULL, 0x0798e2662b2b2514ULL, }, - { 0xfecdfe20645a7d9bULL, 0x00d3dcf80dea608eULL, }, - { 0xffebe0517fffffffULL, 0x0150ab000dc02968ULL, }, - { 0xffec8baf7fffffffULL, 0x01828ea210087db2ULL, }, - { 0xfff9423c39cf8b80ULL, 0x01fae4c1056841b9ULL, }, - { 0xfff35806645a7d9bULL, 0x003737bc01be3862ULL, }, - { 0xffff2aee7fffffffULL, 0x0057bed801b8eeb0ULL, }, /* 88 */ - { 0xffff32047fffffffULL, 0x0064bf8102021ffcULL, }, - { 0xffffb89f39cf8b80ULL, 0x00841c7a00ad640aULL, }, - { 0xffff79fe645a7d9bULL, 0x000e642f0037e4a6ULL, }, - { 0xfffff7307fffffffULL, 0x0016de7800373b16ULL, }, - { 0xfffff77b7fffffffULL, 0x001a42040040661aULL, }, - { 0xfffffd0c39cf8b80ULL, 0x00226e990015b802ULL, }, - { 0xfffffa75645a7d9bULL, 0x0003c0350007004aULL, }, - { 0xffffffa37fffffffULL, 0x0005f5d90006eb0dULL, }, /* 96 */ - { 0xfffffffa7fffffffULL, 0x000978b30006d610ULL, }, - { 0x000000007fffffffULL, 0x000f0d0c0006c153ULL, }, - { 0x000000007fffffffULL, 0x0017eacf0006acd5ULL, }, - { 0x000000007fffffffULL, 0x001b761e0007c87dULL, }, - { 0x000000007fffffffULL, 0x001f87e00009133bULL, }, - { 0x000000007fffffffULL, 0x00243402000a94e0ULL, }, - { 0x000000007fffffffULL, 0x00299164000c5689ULL, }, - { 0x0000000039cf8b80ULL, 0x003682160004293bULL, }, /* 104 */ - { 0x000000001a1c28c4ULL, 0x00477a0900016741ULL, }, - { 0x000000000bcae026ULL, 0x005dba4500007929ULL, }, - { 0x00000000055376c2ULL, 0x007ae7c2000028ddULL, }, - { 0x00000000093ed557ULL, 0x000d637500000d2cULL, }, - { 0x00000000100c9469ULL, 0x0001755d0000043fULL, }, - { 0x000000001bdc1297ULL, 0x000028ac0000015eULL, }, - { 0x00000000305c8bbfULL, 0x0000046e00000071ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDR_Q_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mul_q_h.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mul_q_h.c deleted file mode 100644 index cce7e9e8ac23..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mul_q_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MUL_Q.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MUL_Q.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e438e438e438e4ULL, 0x38e438e438e438e4ULL, }, - { 0xc71cc71cc71cc71cULL, 0xc71cc71cc71cc71cULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x12f6da134bdb12f6ULL, 0xda134bdb12f6da13ULL, }, - { 0xed0925edb425ed09ULL, 0x25edb425ed0925edULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71cc71cc71cc71cULL, 0xc71cc71cc71cc71cULL, }, - { 0x38e338e338e338e3ULL, 0x38e338e338e338e3ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0xed0925ecb425ed09ULL, 0x25ecb425ed0925ecULL, }, - { 0x12f5da124bd912f5ULL, 0xda124bd912f5da12ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x147b147b147b147bULL, 0x147b147b147b147bULL, }, - { 0xeb84eb84eb84eb84ULL, 0xeb84eb84eb84eb84ULL, }, - { 0x0b60e93e2d830b60ULL, 0xe93e2d830b60e93eULL, }, - { 0xf49f16c1d27cf49fULL, 0x16c1d27cf49f16c1ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0xeb84eb84eb84eb84ULL, 0xeb84eb84eb84eb84ULL, }, - { 0x147a147a147a147aULL, 0x147a147a147a147aULL, }, - { 0xf49f16c1d27cf49fULL, 0x16c1d27cf49f16c1ULL, }, - { 0x0b60e93e2d820b60ULL, 0xe93e2d820b60e93eULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x12f6da134bdb12f6ULL, 0xda134bdb12f6da13ULL, }, - { 0xed0925ecb425ed09ULL, 0x25ecb425ed0925ecULL, }, - { 0x0b60e93e2d830b60ULL, 0xe93e2d830b60e93eULL, }, - { 0xf49f16c1d27cf49fULL, 0x16c1d27cf49f16c1ULL, }, - { 0x0652194865240652ULL, 0x1948652406521948ULL, }, - { 0xf9ade6b79adcf9adULL, 0xe6b79adcf9ade6b7ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xed0925edb425ed09ULL, 0x25edb425ed0925edULL, }, - { 0x12f5da124bd912f5ULL, 0xda124bd912f5da12ULL, }, - { 0xf49f16c1d27cf49fULL, 0x16c1d27cf49f16c1ULL, }, - { 0x0b60e93e2d820b60ULL, 0xe93e2d820b60e93eULL, }, - { 0xf9ade6b79adcf9adULL, 0xe6b79adcf9ade6b7ULL, }, - { 0x0651194965220651ULL, 0x1949652206511949ULL, }, - { 0x6fb904f60cbd38c7ULL, 0x2c6b0102000431f1ULL, }, /* 64 */ - { 0x03faffec1879da0eULL, 0x0b2bf9e1ffbfcc2aULL, }, - { 0x4e261003e9dab268ULL, 0x1778faf00101e8d6ULL, }, - { 0x9712fb9b1db7ec38ULL, 0xbccff56b01071259ULL, }, - { 0x03faffec1879da0eULL, 0x0b2bf9e1ffbfcc2aULL, }, - { 0x002400002f03195aULL, 0x02cf2515038635ccULL, }, - { 0x02c8ffc1d57533d9ULL, 0x05e71eaef1eb1809ULL, }, - { 0xfc43001139150d37ULL, 0xef194023f19aecf4ULL, }, - { 0x4e261003e9dab268ULL, 0x1778faf00101e8d6ULL, }, /* 72 */ - { 0x02c8ffc1d57533d9ULL, 0x05e71eaef1eb1809ULL, }, - { 0x36aa33af267d6a08ULL, 0x0c67196238380abdULL, }, - { 0xb69bf1d4cc591b07ULL, 0xdc7e3510397df77dULL, }, - { 0x9712fb9b1db7ec38ULL, 0xbccff56b01071259ULL, }, - { 0xfc43001139150d37ULL, 0xef194023f19aecf4ULL, }, - { 0xb69bf1d4cc591b07ULL, 0xdc7e3510397df77dULL, }, - { 0x628a03e2455006e3ULL, 0x65a26eec3ac806bdULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MUL_Q_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MUL_Q_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mul_q_w.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mul_q_w.c deleted file mode 100644 index 81d2635d7d5b..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mul_q_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MUL_Q.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MUL_Q.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e38e3938e38e39ULL, 0x38e38e3938e38e39ULL, }, - { 0xc71c71c6c71c71c6ULL, 0xc71c71c6c71c71c6ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x12f684be4bda12f7ULL, 0xda12f68512f684beULL, }, - { 0xed097b42b425ed09ULL, 0x25ed097bed097b42ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c6c71c71c6ULL, 0xc71c71c6c71c71c6ULL, }, - { 0x38e38e3838e38e38ULL, 0x38e38e3838e38e38ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0xed097b42b425ed09ULL, 0x25ed097aed097b42ULL, }, - { 0x12f684bd4bda12f5ULL, 0xda12f68412f684bdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x147ae148147ae148ULL, 0x147ae148147ae148ULL, }, - { 0xeb851eb8eb851eb8ULL, 0xeb851eb8eb851eb8ULL, }, - { 0x0b60b60b2d82d82eULL, 0xe93e93e90b60b60bULL, }, - { 0xf49f49f4d27d27d2ULL, 0x16c16c17f49f49f4ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0xeb851eb8eb851eb8ULL, 0xeb851eb8eb851eb8ULL, }, - { 0x147ae147147ae147ULL, 0x147ae147147ae147ULL, }, - { 0xf49f49f4d27d27d2ULL, 0x16c16c16f49f49f4ULL, }, - { 0x0b60b60b2d82d82dULL, 0xe93e93e90b60b60bULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x12f684be4bda12f7ULL, 0xda12f68512f684beULL, }, - { 0xed097b42b425ed09ULL, 0x25ed097aed097b42ULL, }, - { 0x0b60b60b2d82d82eULL, 0xe93e93e90b60b60bULL, }, - { 0xf49f49f4d27d27d2ULL, 0x16c16c16f49f49f4ULL, }, - { 0x06522c3f6522c3f3ULL, 0x1948b0fc06522c3fULL, }, - { 0xf9add3c09add3c0dULL, 0xe6b74f03f9add3c0ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xed097b42b425ed09ULL, 0x25ed097bed097b42ULL, }, - { 0x12f684bd4bda12f5ULL, 0xda12f68412f684bdULL, }, - { 0xf49f49f4d27d27d2ULL, 0x16c16c17f49f49f4ULL, }, - { 0x0b60b60b2d82d82dULL, 0xe93e93e90b60b60bULL, }, - { 0xf9add3c09add3c0dULL, 0xe6b74f03f9add3c0ULL, }, - { 0x06522c3f6522c3f1ULL, 0x1948b0fc06522c3fULL, }, - { 0x6fb7e8890cbdc0d2ULL, 0x2c6b144600049a04ULL, }, /* 64 */ - { 0x03fa514e1879c701ULL, 0x0b2c6ca9ffbf8ac6ULL, }, - { 0x4e252086e9daefbfULL, 0x1779189301015a34ULL, }, - { 0x9713a7171db7f3a5ULL, 0xbccfb4690107236fULL, }, - { 0x03fa514e1879c701ULL, 0x0b2c6ca9ffbf8ac6ULL, }, - { 0x002442012f047611ULL, 0x02cf8c140386e68eULL, }, - { 0x02c84b87d575d121ULL, 0x05e79a8af1eb1c52ULL, }, - { 0xfc439edc3916c1e4ULL, 0xef19389cf19a0fddULL, }, - { 0x4e252086e9daefbfULL, 0x1779189301015a34ULL, }, /* 72 */ - { 0x02c84b87d575d121ULL, 0x05e79a8af1eb1c52ULL, }, - { 0x36a93aff267d11c3ULL, 0x0c6788643838c14cULL, }, - { 0xb69baa39cc590fcdULL, 0xdc7e6df7397c58d9ULL, }, - { 0x9713a7171db7f3a5ULL, 0xbccfb4690107236fULL, }, - { 0xfc439edc3916c1e4ULL, 0xef19389cf19a0fddULL, }, - { 0xb69baa39cc590fcdULL, 0xdc7e6df7397c58d9ULL, }, - { 0x628a97e4455157d3ULL, 0x65a1c5e13ac736e1ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MUL_Q_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MUL_Q_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mulr_q_h.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mulr_q_h.c deleted file mode 100644 index d5b00f1eb0a0..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mulr_q_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MULR_Q.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MULR_Q.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e438e438e438e4ULL, 0x38e438e438e438e4ULL, }, - { 0xc71cc71cc71cc71cULL, 0xc71cc71cc71cc71cULL, }, - { 0x2223222322232223ULL, 0x2223222322232223ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x12f7da134bdb12f7ULL, 0xda134bdb12f7da13ULL, }, - { 0xed0a25eeb425ed0aULL, 0x25eeb425ed0a25eeULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71cc71cc71cc71cULL, 0xc71cc71cc71cc71cULL, }, - { 0x38e338e338e338e3ULL, 0x38e338e338e338e3ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xed0925edb426ed09ULL, 0x25edb426ed0925edULL, }, - { 0x12f6da134bda12f6ULL, 0xda134bda12f6da13ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2223222322232223ULL, 0x2223222322232223ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x147c147c147c147cULL, 0x147c147c147c147cULL, }, - { 0xeb85eb85eb85eb85ULL, 0xeb85eb85eb85eb85ULL, }, - { 0x0b61e93e2d840b61ULL, 0xe93e2d840b61e93eULL, }, - { 0xf49f16c2d27cf49fULL, 0x16c2d27cf49f16c2ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xeb85eb85eb85eb85ULL, 0xeb85eb85eb85eb85ULL, }, - { 0x147b147b147b147bULL, 0x147b147b147b147bULL, }, - { 0xf49f16c1d27df49fULL, 0x16c1d27df49f16c1ULL, }, - { 0x0b60e93e2d830b60ULL, 0xe93e2d830b60e93eULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x12f7da134bdb12f7ULL, 0xda134bdb12f7da13ULL, }, - { 0xed0925edb426ed09ULL, 0x25edb426ed0925edULL, }, - { 0x0b61e93e2d840b61ULL, 0xe93e2d840b61e93eULL, }, - { 0xf49f16c1d27df49fULL, 0x16c1d27df49f16c1ULL, }, - { 0x0652194865240652ULL, 0x1948652406521948ULL, }, - { 0xf9aee6b79addf9aeULL, 0xe6b79addf9aee6b7ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xed0a25eeb425ed0aULL, 0x25eeb425ed0a25eeULL, }, - { 0x12f6da134bda12f6ULL, 0xda134bda12f6da13ULL, }, - { 0xf49f16c2d27cf49fULL, 0x16c2d27cf49f16c2ULL, }, - { 0x0b60e93e2d830b60ULL, 0xe93e2d830b60e93eULL, }, - { 0xf9aee6b79addf9aeULL, 0xe6b79addf9aee6b7ULL, }, - { 0x0652194965230652ULL, 0x1949652306521949ULL, }, - { 0x6fba04f60cbe38c7ULL, 0x2c6b0102000531f1ULL, }, /* 64 */ - { 0x03faffed1879da0fULL, 0x0b2cf9e2ffbfcc2aULL, }, - { 0x4e261004e9dbb269ULL, 0x1779faf00102e8d7ULL, }, - { 0x9713fb9c1db7ec39ULL, 0xbccff56b01081259ULL, }, - { 0x03faffed1879da0fULL, 0x0b2cf9e2ffbfcc2aULL, }, - { 0x002400002f04195bULL, 0x02cf2516038735cdULL, }, - { 0x02c8ffc1d57633daULL, 0x05e71eaff1eb180aULL, }, - { 0xfc44001139160d37ULL, 0xef1a4023f19aecf5ULL, }, - { 0x4e261004e9dbb269ULL, 0x1779faf00102e8d7ULL, }, /* 72 */ - { 0x02c8ffc1d57633daULL, 0x05e71eaff1eb180aULL, }, - { 0x36aa33af267e6a09ULL, 0x0c67196338390abeULL, }, - { 0xb69bf1d4cc591b07ULL, 0xdc7f3511397df77eULL, }, - { 0x9713fb9c1db7ec39ULL, 0xbccff56b01081259ULL, }, - { 0xfc44001139160d37ULL, 0xef1a4023f19aecf5ULL, }, - { 0xb69bf1d4cc591b07ULL, 0xdc7f3511397df77eULL, }, - { 0x628a03e3455006e4ULL, 0x65a36eec3ac806beULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MULR_Q_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MULR_Q_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mulr_q_w.c b/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mulr_q_w.c deleted file mode 100644 index 78c9e223944f..000000000000 --- a/tests/tcg/mips/user/ase/msa/fixed-multiply/test_msa_mulr_q_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MULR_Q.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Fixed Multiply"; - char *instruction_name = "MULR_Q.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e38e3a38e38e3aULL, 0x38e38e3a38e38e3aULL, }, - { 0xc71c71c7c71c71c7ULL, 0xc71c71c7c71c71c7ULL, }, - { 0x2222222322222223ULL, 0x2222222322222223ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x12f684be4bda12f7ULL, 0xda12f68512f684beULL, }, - { 0xed097b43b425ed09ULL, 0x25ed097ced097b43ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c7c71c71c7ULL, 0xc71c71c7c71c71c7ULL, }, - { 0x38e38e3838e38e38ULL, 0x38e38e3838e38e38ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xed097b42b425ed0aULL, 0x25ed097bed097b42ULL, }, - { 0x12f684bd4bda12f6ULL, 0xda12f68512f684bdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222322222223ULL, 0x2222222322222223ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x147ae148147ae148ULL, 0x147ae148147ae148ULL, }, - { 0xeb851eb8eb851eb8ULL, 0xeb851eb8eb851eb8ULL, }, - { 0x0b60b60c2d82d82eULL, 0xe93e93e90b60b60cULL, }, - { 0xf49f49f5d27d27d2ULL, 0x16c16c17f49f49f5ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xeb851eb8eb851eb8ULL, 0xeb851eb8eb851eb8ULL, }, - { 0x147ae148147ae148ULL, 0x147ae148147ae148ULL, }, - { 0xf49f49f4d27d27d3ULL, 0x16c16c16f49f49f4ULL, }, - { 0x0b60b60b2d82d82dULL, 0xe93e93e90b60b60bULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x12f684be4bda12f7ULL, 0xda12f68512f684beULL, }, - { 0xed097b42b425ed0aULL, 0x25ed097bed097b42ULL, }, - { 0x0b60b60c2d82d82eULL, 0xe93e93e90b60b60cULL, }, - { 0xf49f49f4d27d27d3ULL, 0x16c16c16f49f49f4ULL, }, - { 0x06522c3f6522c3f4ULL, 0x1948b0fc06522c3fULL, }, - { 0xf9add3c19add3c0dULL, 0xe6b74f04f9add3c1ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xed097b43b425ed09ULL, 0x25ed097ced097b43ULL, }, - { 0x12f684bd4bda12f6ULL, 0xda12f68512f684bdULL, }, - { 0xf49f49f5d27d27d2ULL, 0x16c16c17f49f49f5ULL, }, - { 0x0b60b60b2d82d82dULL, 0xe93e93e90b60b60bULL, }, - { 0xf9add3c19add3c0dULL, 0xe6b74f04f9add3c1ULL, }, - { 0x06522c3f6522c3f2ULL, 0x1948b0fd06522c3fULL, }, - { 0x6fb7e8890cbdc0d3ULL, 0x2c6b144600049a05ULL, }, /* 64 */ - { 0x03fa514e1879c702ULL, 0x0b2c6ca9ffbf8ac7ULL, }, - { 0x4e252087e9daefc0ULL, 0x1779189301015a35ULL, }, - { 0x9713a7171db7f3a6ULL, 0xbccfb46a0107236fULL, }, - { 0x03fa514e1879c702ULL, 0x0b2c6ca9ffbf8ac7ULL, }, - { 0x002442012f047612ULL, 0x02cf8c140386e68fULL, }, - { 0x02c84b88d575d121ULL, 0x05e79a8bf1eb1c52ULL, }, - { 0xfc439edd3916c1e4ULL, 0xef19389cf19a0fdeULL, }, - { 0x4e252087e9daefc0ULL, 0x1779189301015a35ULL, }, /* 72 */ - { 0x02c84b88d575d121ULL, 0x05e79a8bf1eb1c52ULL, }, - { 0x36a93aff267d11c4ULL, 0x0c6788643838c14cULL, }, - { 0xb69baa3acc590fcdULL, 0xdc7e6df7397c58daULL, }, - { 0x9713a7171db7f3a6ULL, 0xbccfb46a0107236fULL, }, - { 0xfc439edd3916c1e4ULL, 0xef19389cf19a0fdeULL, }, - { 0xb69baa3acc590fcdULL, 0xdc7e6df7397c58daULL, }, - { 0x628a97e4455157d3ULL, 0x65a1c5e23ac736e2ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MULR_Q_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MULR_Q_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_a_d.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_a_d.c deleted file mode 100644 index d9b49cea8cb6..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_a_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMAX_A.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMAX_A.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_A_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_A_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_a_w.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_a_w.c deleted file mode 100644 index f64276f2f139..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_a_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMAX_A.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMAX_A.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaa71c71c71ULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e355555555ULL, 0x55555555e38e38e3ULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xcccccccc71c71c71ULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e355555555ULL, 0x55555555e38e38e3ULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xe38e38e333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e371c71c71ULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaa71c71c71ULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0xcccccccc71c71c71ULL, 0xccccccccccccccccULL, }, - { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, - { 0xe38e38e371c71c71ULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xfbbe00635e31e24eULL, 0x12f7bb1aa942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00635e31e24eULL, 0x12f7bb1aa942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_A_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_A_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_d.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_d.c deleted file mode 100644 index ba548e488249..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMAX.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMAX.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_w.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_w.c deleted file mode 100644 index f9aa24d62bfa..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmax_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMAX.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMAX.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x38e38e3800000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x000000001c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0x38e38e38aaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x38e38e3833333333ULL, }, - { 0x3333333371c71c71ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e3800000000ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0x38e38e38aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x3333333333333333ULL, 0x38e38e3833333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x000000001c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333371c71c71ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc4d93c708ULL, 0x4b670b5e153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5eab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5ea942e2a0ULL, }, - { 0x886ae6cc4d93c708ULL, 0x4b670b5e153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaa4d93c708ULL, 0x27d8c6ff153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5eab2b2514ULL, }, /* 72 */ - { 0xac5aaeaa4d93c708ULL, 0x27d8c6ff153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffa942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5ea942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffa942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMAX_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_a_d.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_a_d.c deleted file mode 100644 index 555aa133ae9c..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_a_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMIN_A.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMIN_A.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_A_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_A_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_a_w.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_a_w.c deleted file mode 100644 index 9a81f1c6c5de..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_a_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMIN_A.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMIN_A.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71caaaaaaaaULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x555555558e38e38eULL, 0x38e38e3855555555ULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x1c71c71cccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333333338e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x555555558e38e38eULL, 0x38e38e3855555555ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x333333338e38e38eULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c8e38e38eULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71caaaaaaaaULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71cccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, - { 0x1c71c71c8e38e38eULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d4d93c708ULL, 0x8df188d8153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d4d93c708ULL, 0x8df188d8153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_A_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_A_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_d.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_d.c deleted file mode 100644 index 97123c8c0b2f..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMIN.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMIN.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_w.c b/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_w.c deleted file mode 100644 index 1e91136441bb..000000000000 --- a/tests/tcg/mips/user/ase/msa/float-max-min/test_msa_fmin_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction FMIN.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Float Max Min"; - char *instruction_name = "FMIN.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0x0000000000000000ULL, 0xc71c71c700000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e3aaaaaaaaULL, 0xaaaaaaaae38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x33333333e38e38e3ULL, }, - { 0x1c71c71c33333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0xaaaaaaaae38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x33333333e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c700000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c33333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe006328625540ULL, 0x12f7bb1afe7bb00cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6fffe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8fe7bb00cULL, }, - { 0xfbbe006328625540ULL, 0x12f7bb1afe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe0063b9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6fffe7bb00cULL, }, /* 72 */ - { 0xfbbe0063b9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8ab2b2514ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8fe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8ab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_FMIN_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_b.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_b.c deleted file mode 100644 index c0a07b5552d5..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADD_A.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADD_A.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, /* 0 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x5757575757575757ULL, 0x5757575757575757ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x3535353535353535ULL, 0x3535353535353535ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x1e73391e73391e73ULL, 0x391e73391e73391eULL, }, - { 0x1d723a1d723a1d72ULL, 0x3a1d723a1d723a1dULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x5757575757575757ULL, 0x5757575757575757ULL, }, /* 16 */ - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0xacacacacacacacacULL, 0xacacacacacacacacULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x8a8a8a8a8a8a8a8aULL, 0x8a8a8a8a8a8a8a8aULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x73c88e73c88e73c8ULL, 0x8e73c88e73c88e73ULL, }, - { 0x72c78f72c78f72c7ULL, 0x8f72c78f72c78f72ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x72c78d72c78d72c7ULL, 0x8d72c78d72c78d72ULL, }, - { 0x71c68e71c68e71c6ULL, 0x8e71c68e71c68e71ULL, }, - { 0x3535353535353535ULL, 0x3535353535353535ULL, }, /* 32 */ - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x8a8a8a8a8a8a8a8aULL, 0x8a8a8a8a8a8a8a8aULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x6868686868686868ULL, 0x6868686868686868ULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x51a66c51a66c51a6ULL, 0x6c51a66c51a66c51ULL, }, - { 0x50a56d50a56d50a5ULL, 0x6d50a56d50a56d50ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x50a56b50a56b50a5ULL, 0x6b50a56b50a56b50ULL, }, - { 0x4fa46c4fa46c4fa4ULL, 0x6c4fa46c4fa46c4fULL, }, - { 0x1e73391e73391e73ULL, 0x391e73391e73391eULL, }, /* 48 */ - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x73c88e73c88e73c8ULL, 0x8e73c88e73c88e73ULL, }, - { 0x72c78d72c78d72c7ULL, 0x8d72c78d72c78d72ULL, }, - { 0x51a66c51a66c51a6ULL, 0x6c51a66c51a66c51ULL, }, - { 0x50a56b50a56b50a5ULL, 0x6b50a56b50a56b50ULL, }, - { 0x3ae4703ae4703ae4ULL, 0x703ae4703ae4703aULL, }, - { 0x39e37139e37139e3ULL, 0x7139e37139e37139ULL, }, - { 0x1d723a1d723a1d72ULL, 0x3a1d723a1d723a1dULL, }, /* 56 */ - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x72c78f72c78f72c7ULL, 0x8f72c78f72c78f72ULL, }, - { 0x71c68e71c68e71c6ULL, 0x8e71c68e71c68e71ULL, }, - { 0x50a56d50a56d50a5ULL, 0x6d50a56d50a56d50ULL, }, - { 0x4fa46c4fa46c4fa4ULL, 0x6c4fa46c4fa46c4fULL, }, - { 0x39e37139e37139e3ULL, 0x7139e37139e37139ULL, }, - { 0x38e27238e27238e2ULL, 0x7238e27238e27238ULL, }, - { 0xf0d4346850c4aa80ULL, 0x96ce16bc04f6a018ULL, }, /* 64 */ - { 0x7dac1a9775cf8e48ULL, 0x5d70507817baa210ULL, }, - { 0xccc46c8a6f93cac0ULL, 0x728f455f57a67520ULL, }, - { 0xe8b930818693738eULL, 0xbe76838659bd6e6cULL, }, - { 0x7dac1a9775cf8e48ULL, 0x5d70507817baa210ULL, }, - { 0x0a8400c69ada7210ULL, 0x24128a342a7ea408ULL, }, - { 0x599c52b9949eae88ULL, 0x39317f1b6a6a7718ULL, }, - { 0x759116b0ab9e5756ULL, 0x8518bd426c817064ULL, }, - { 0xccc46c8a6f93cac0ULL, 0x728f455f57a67520ULL, }, /* 72 */ - { 0x599c52b9949eae88ULL, 0x39317f1b6a6a7718ULL, }, - { 0xa8b4a4ac8e62ea00ULL, 0x4e507402aa564a28ULL, }, - { 0xc4a968a3a56293ceULL, 0x9a37b229ac6d4374ULL, }, - { 0xe8b930818693738eULL, 0xbe76838659bd6e6cULL, }, - { 0x759116b0ab9e5756ULL, 0x8518bd426c817064ULL, }, - { 0xc4a968a3a56293ceULL, 0x9a37b229ac6d4374ULL, }, - { 0xe09e2c9abc623c9cULL, 0xe61ef050ae843cc0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_d.c deleted file mode 100644 index 0771cdbdfe95..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADD_A.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADD_A.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x5555555555555557ULL, 0x5555555555555557ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x3333333333333335ULL, 0x3333333333333335ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x1c71c71c71c71c73ULL, 0x38e38e38e38e38e4ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e5ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x5555555555555557ULL, 0x5555555555555557ULL, }, /* 16 */ - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0xaaaaaaaaaaaaaaacULL, 0xaaaaaaaaaaaaaaacULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x888888888888888aULL, 0x888888888888888aULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x71c71c71c71c71c8ULL, 0x8e38e38e38e38e39ULL, }, - { 0x71c71c71c71c71c7ULL, 0x8e38e38e38e38e3aULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x71c71c71c71c71c7ULL, 0x8e38e38e38e38e38ULL, }, - { 0x71c71c71c71c71c6ULL, 0x8e38e38e38e38e39ULL, }, - { 0x3333333333333335ULL, 0x3333333333333335ULL, }, /* 32 */ - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x888888888888888aULL, 0x888888888888888aULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x6666666666666668ULL, 0x6666666666666668ULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x4fa4fa4fa4fa4fa6ULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c18ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0x6c16c16c16c16c17ULL, }, - { 0x1c71c71c71c71c73ULL, 0x38e38e38e38e38e4ULL, }, /* 48 */ - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x71c71c71c71c71c8ULL, 0x8e38e38e38e38e39ULL, }, - { 0x71c71c71c71c71c7ULL, 0x8e38e38e38e38e38ULL, }, - { 0x4fa4fa4fa4fa4fa6ULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c16ULL, }, - { 0x38e38e38e38e38e4ULL, 0x71c71c71c71c71c6ULL, }, - { 0x38e38e38e38e38e3ULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e5ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x71c71c71c71c71c7ULL, 0x8e38e38e38e38e3aULL, }, - { 0x71c71c71c71c71c6ULL, 0x8e38e38e38e38e39ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c18ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0x6c16c16c16c16c17ULL, }, - { 0x38e38e38e38e38e3ULL, 0x71c71c71c71c71c7ULL, }, - { 0x38e38e38e38e38e2ULL, 0x71c71c71c71c71c8ULL, }, - { 0xef2a3267af3b5580ULL, 0x96ce16bdfcf76018ULL, }, /* 64 */ - { 0x7bd718d08a09e3b8ULL, 0x5e5ec67913bb0308ULL, }, - { 0xcb3a6a891dce1f40ULL, 0x733fd25ea9a6d520ULL, }, - { 0xe7e42f8135cf8d0eULL, 0xbd7582865538cd6cULL, }, - { 0x7bd718d08a09e3b8ULL, 0x5e5ec67913bb0308ULL, }, - { 0x0883ff3964d871f0ULL, 0x25ef76342a7ea5f8ULL, }, - { 0x57e750f1f89cad78ULL, 0x3ad08219c06a7810ULL, }, - { 0x749115ea109e1b46ULL, 0x850632416bfc705cULL, }, - { 0xcb3a6a891dce1f40ULL, 0x733fd25ea9a6d520ULL, }, /* 72 */ - { 0x57e750f1f89cad78ULL, 0x3ad08219c06a7810ULL, }, - { 0xa74aa2aa8c60e900ULL, 0x4fb18dff56564a28ULL, }, - { 0xc3f467a2a46256ceULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0xbd7582865538cd6cULL, }, - { 0x749115ea109e1b46ULL, 0x850632416bfc705cULL, }, - { 0xc3f467a2a46256ceULL, 0x99e73e2701e84274ULL, }, - { 0xe09e2c9abc63c49cULL, 0xe41cee4ead7a3ac0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_h.c deleted file mode 100644 index 7956960d0f89..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADD_A.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADD_A.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, /* 0 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x5557555755575557ULL, 0x5557555755575557ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x3335333533353335ULL, 0x3335333533353335ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x1c7338e471c91c73ULL, 0x38e471c91c7338e4ULL, }, - { 0x1c7238e571c81c72ULL, 0x38e571c81c7238e5ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x5557555755575557ULL, 0x5557555755575557ULL, }, /* 16 */ - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0xaaacaaacaaacaaacULL, 0xaaacaaacaaacaaacULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x888a888a888a888aULL, 0x888a888a888a888aULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x71c88e39c71e71c8ULL, 0x8e39c71e71c88e39ULL, }, - { 0x71c78e3ac71d71c7ULL, 0x8e3ac71d71c78e3aULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x71c78e38c71d71c7ULL, 0x8e38c71d71c78e38ULL, }, - { 0x71c68e39c71c71c6ULL, 0x8e39c71c71c68e39ULL, }, - { 0x3335333533353335ULL, 0x3335333533353335ULL, }, /* 32 */ - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x888a888a888a888aULL, 0x888a888a888a888aULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x6668666866686668ULL, 0x6668666866686668ULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x4fa66c17a4fc4fa6ULL, 0x6c17a4fc4fa66c17ULL, }, - { 0x4fa56c18a4fb4fa5ULL, 0x6c18a4fb4fa56c18ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x4fa56c16a4fb4fa5ULL, 0x6c16a4fb4fa56c16ULL, }, - { 0x4fa46c17a4fa4fa4ULL, 0x6c17a4fa4fa46c17ULL, }, - { 0x1c7338e471c91c73ULL, 0x38e471c91c7338e4ULL, }, /* 48 */ - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x71c88e39c71e71c8ULL, 0x8e39c71e71c88e39ULL, }, - { 0x71c78e38c71d71c7ULL, 0x8e38c71d71c78e38ULL, }, - { 0x4fa66c17a4fc4fa6ULL, 0x6c17a4fc4fa66c17ULL, }, - { 0x4fa56c16a4fb4fa5ULL, 0x6c16a4fb4fa56c16ULL, }, - { 0x38e471c6e39038e4ULL, 0x71c6e39038e471c6ULL, }, - { 0x38e371c7e38f38e3ULL, 0x71c7e38f38e371c7ULL, }, - { 0x1c7238e571c81c72ULL, 0x38e571c81c7238e5ULL, }, /* 56 */ - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x71c78e3ac71d71c7ULL, 0x8e3ac71d71c78e3aULL, }, - { 0x71c68e39c71c71c6ULL, 0x8e39c71c71c68e39ULL, }, - { 0x4fa56c18a4fb4fa5ULL, 0x6c18a4fb4fa56c18ULL, }, - { 0x4fa46c17a4fa4fa4ULL, 0x6c17a4fa4fa46c17ULL, }, - { 0x38e371c7e38f38e3ULL, 0x71c7e38f38e371c7ULL, }, - { 0x38e271c8e38e38e2ULL, 0x71c8e38e38e271c8ULL, }, - { 0xef2c326850c4aa80ULL, 0x96ce16bc030a9fe8ULL, }, /* 64 */ - { 0x7bd8199775f58e38ULL, 0x5e5e504416c4a2f0ULL, }, - { 0xcb3c6a8a6e93c9c0ULL, 0x733f445f565a7508ULL, }, - { 0xe7e52f81869372f2ULL, 0xbd76828658436d54ULL, }, - { 0x7bd8199775f58e38ULL, 0x5e5e504416c4a2f0ULL, }, - { 0x088400c69b2671f0ULL, 0x25ee89cc2a7ea5f8ULL, }, - { 0x57e851b993c4ad78ULL, 0x3acf7de76a147810ULL, }, - { 0x749116b0abc456aaULL, 0x8506bc0e6bfd705cULL, }, - { 0xcb3c6a8a6e93c9c0ULL, 0x733f445f565a7508ULL, }, /* 72 */ - { 0x57e851b993c4ad78ULL, 0x3acf7de76a147810ULL, }, - { 0xa74ca2ac8c62e900ULL, 0x4fb07202a9aa4a28ULL, }, - { 0xc3f567a3a4629232ULL, 0x99e7b029ab934274ULL, }, - { 0xe7e52f81869372f2ULL, 0xbd76828658436d54ULL, }, - { 0x749116b0abc456aaULL, 0x8506bc0e6bfd705cULL, }, - { 0xc3f567a3a4629232ULL, 0x99e7b029ab934274ULL, }, - { 0xe09e2c9abc623b64ULL, 0xe41eee50ad7c3ac0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_w.c deleted file mode 100644 index 590f440406b1..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_add_a_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADD_A.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADD_A.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, /* 0 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x5555555755555557ULL, 0x5555555755555557ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x3333333533333335ULL, 0x3333333533333335ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x1c71c71e71c71c73ULL, 0x38e38e391c71c71eULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e3a1c71c71dULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x5555555755555557ULL, 0x5555555755555557ULL, }, /* 16 */ - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0xaaaaaaacaaaaaaacULL, 0xaaaaaaacaaaaaaacULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x8888888a8888888aULL, 0x8888888a8888888aULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x71c71c73c71c71c8ULL, 0x8e38e38e71c71c73ULL, }, - { 0x71c71c72c71c71c7ULL, 0x8e38e38f71c71c72ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x71c71c72c71c71c7ULL, 0x8e38e38d71c71c72ULL, }, - { 0x71c71c71c71c71c6ULL, 0x8e38e38e71c71c71ULL, }, - { 0x3333333533333335ULL, 0x3333333533333335ULL, }, /* 32 */ - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x8888888a8888888aULL, 0x8888888a8888888aULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x6666666866666668ULL, 0x6666666866666668ULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x4fa4fa51a4fa4fa6ULL, 0x6c16c16c4fa4fa51ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x6c16c16d4fa4fa50ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x6c16c16b4fa4fa50ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0x6c16c16c4fa4fa4fULL, }, - { 0x1c71c71e71c71c73ULL, 0x38e38e391c71c71eULL, }, /* 48 */ - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x71c71c73c71c71c8ULL, 0x8e38e38e71c71c73ULL, }, - { 0x71c71c72c71c71c7ULL, 0x8e38e38d71c71c72ULL, }, - { 0x4fa4fa51a4fa4fa6ULL, 0x6c16c16c4fa4fa51ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x6c16c16b4fa4fa50ULL, }, - { 0x38e38e3ae38e38e4ULL, 0x71c71c7038e38e3aULL, }, - { 0x38e38e39e38e38e3ULL, 0x71c71c7138e38e39ULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e3a1c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x71c71c72c71c71c7ULL, 0x8e38e38f71c71c72ULL, }, - { 0x71c71c71c71c71c6ULL, 0x8e38e38e71c71c71ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x6c16c16d4fa4fa50ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0x6c16c16c4fa4fa4fULL, }, - { 0x38e38e39e38e38e3ULL, 0x71c71c7138e38e39ULL, }, - { 0x38e38e38e38e38e2ULL, 0x71c71c7238e38e38ULL, }, - { 0xef2a326850c4aa80ULL, 0x96ce16bc03089fe8ULL, }, /* 64 */ - { 0x7bd718d175f61c48ULL, 0x5e5ec67816c3a2f0ULL, }, - { 0xcb3a6a8a6e92c9c0ULL, 0x733fd25d56592ae0ULL, }, - { 0xe7e42f818694378eULL, 0xbd75828658416d54ULL, }, - { 0x7bd718d175f61c48ULL, 0x5e5ec67816c3a2f0ULL, }, - { 0x0883ff3a9b278e10ULL, 0x25ef76342a7ea5f8ULL, }, - { 0x57e750f393c43b88ULL, 0x3ad082196a142de8ULL, }, - { 0x749115eaabc5a956ULL, 0x850632426bfc705cULL, }, - { 0xcb3a6a8a6e92c9c0ULL, 0x733fd25d56592ae0ULL, }, /* 72 */ - { 0x57e750f393c43b88ULL, 0x3ad082196a142de8ULL, }, - { 0xa74aa2ac8c60e900ULL, 0x4fb18dfea9a9b5d8ULL, }, - { 0xc3f467a3a46256ceULL, 0x99e73e27ab91f84cULL, }, - { 0xe7e42f818694378eULL, 0xbd75828658416d54ULL, }, - { 0x749115eaabc5a956ULL, 0x850632426bfc705cULL, }, - { 0xc3f467a3a46256ceULL, 0x99e73e27ab91f84cULL, }, - { 0xe09e2c9abc63c49cULL, 0xe41cee50ad7a3ac0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADD_A_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_b.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_b.c deleted file mode 100644 index 42dd260726f4..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_A.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_A.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, /* 0 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x5757575757575757ULL, 0x5757575757575757ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x3535353535353535ULL, 0x3535353535353535ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x1e73391e73391e73ULL, 0x391e73391e73391eULL, }, - { 0x1d723a1d723a1d72ULL, 0x3a1d723a1d723a1dULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x5757575757575757ULL, 0x5757575757575757ULL, }, /* 16 */ - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x737f7f737f7f737fULL, 0x7f737f7f737f7f73ULL, }, - { 0x727f7f727f7f727fULL, 0x7f727f7f727f7f72ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x727f7f727f7f727fULL, 0x7f727f7f727f7f72ULL, }, - { 0x717f7f717f7f717fULL, 0x7f717f7f717f7f71ULL, }, - { 0x3535353535353535ULL, 0x3535353535353535ULL, }, /* 32 */ - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x6868686868686868ULL, 0x6868686868686868ULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x517f6c517f6c517fULL, 0x6c517f6c517f6c51ULL, }, - { 0x507f6d507f6d507fULL, 0x6d507f6d507f6d50ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x507f6b507f6b507fULL, 0x6b507f6b507f6b50ULL, }, - { 0x4f7f6c4f7f6c4f7fULL, 0x6c4f7f6c4f7f6c4fULL, }, - { 0x1e73391e73391e73ULL, 0x391e73391e73391eULL, }, /* 48 */ - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x737f7f737f7f737fULL, 0x7f737f7f737f7f73ULL, }, - { 0x727f7f727f7f727fULL, 0x7f727f7f727f7f72ULL, }, - { 0x517f6c517f6c517fULL, 0x6c517f6c517f6c51ULL, }, - { 0x507f6b507f6b507fULL, 0x6b507f6b507f6b50ULL, }, - { 0x3a7f703a7f703a7fULL, 0x703a7f703a7f703aULL, }, - { 0x397f71397f71397fULL, 0x71397f71397f7139ULL, }, - { 0x1d723a1d723a1d72ULL, 0x3a1d723a1d723a1dULL, }, /* 56 */ - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x727f7f727f7f727fULL, 0x7f727f7f727f7f72ULL, }, - { 0x717f7f717f7f717fULL, 0x7f717f7f717f7f71ULL, }, - { 0x507f6d507f6d507fULL, 0x6d507f6d507f6d50ULL, }, - { 0x4f7f6c4f7f6c4f7fULL, 0x6c4f7f6c4f7f6c4fULL, }, - { 0x397f71397f71397fULL, 0x71397f71397f7139ULL, }, - { 0x387f72387f72387fULL, 0x72387f72387f7238ULL, }, - { 0x7f7f3468507f7f7fULL, 0x7f7f167f047f7f18ULL, }, /* 64 */ - { 0x7d7f1a7f757f7f48ULL, 0x5d705078177f7f10ULL, }, - { 0x7f7f6c7f6f7f7f7fULL, 0x727f455f577f7520ULL, }, - { 0x7f7f307f7f7f737fULL, 0x7f767f7f597f6e6cULL, }, - { 0x7d7f1a7f757f7f48ULL, 0x5d705078177f7f10ULL, }, - { 0x0a7f007f7f7f7210ULL, 0x24127f342a7e7f08ULL, }, - { 0x597f527f7f7f7f7fULL, 0x39317f1b6a6a7718ULL, }, - { 0x757f167f7f7f5756ULL, 0x7f187f426c7f7064ULL, }, - { 0x7f7f6c7f6f7f7f7fULL, 0x727f455f577f7520ULL, }, /* 72 */ - { 0x597f527f7f7f7f7fULL, 0x39317f1b6a6a7718ULL, }, - { 0x7f7f7f7f7f627f7fULL, 0x4e5074027f564a28ULL, }, - { 0x7f7f687f7f627f7fULL, 0x7f377f297f6d4374ULL, }, - { 0x7f7f307f7f7f737fULL, 0x7f767f7f597f6e6cULL, }, - { 0x757f167f7f7f5756ULL, 0x7f187f426c7f7064ULL, }, - { 0x7f7f687f7f627f7fULL, 0x7f377f297f6d4374ULL, }, - { 0x7f7f2c7f7f623c7fULL, 0x7f1e7f507f7f3c7fULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_d.c deleted file mode 100644 index 3e4e6f7f9917..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_A.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_A.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x5555555555555557ULL, 0x5555555555555557ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x3333333333333335ULL, 0x3333333333333335ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x1c71c71c71c71c73ULL, 0x38e38e38e38e38e4ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e5ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x5555555555555557ULL, 0x5555555555555557ULL, }, /* 16 */ - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c8ULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c7ULL, 0x7fffffffffffffffULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c7ULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c6ULL, 0x7fffffffffffffffULL, }, - { 0x3333333333333335ULL, 0x3333333333333335ULL, }, /* 32 */ - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x6666666666666668ULL, 0x6666666666666668ULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x4fa4fa4fa4fa4fa6ULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c18ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0x6c16c16c16c16c17ULL, }, - { 0x1c71c71c71c71c73ULL, 0x38e38e38e38e38e4ULL, }, /* 48 */ - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x71c71c71c71c71c8ULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c7ULL, 0x7fffffffffffffffULL, }, - { 0x4fa4fa4fa4fa4fa6ULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c16ULL, }, - { 0x38e38e38e38e38e4ULL, 0x71c71c71c71c71c6ULL, }, - { 0x38e38e38e38e38e3ULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e5ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x71c71c71c71c71c7ULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c6ULL, 0x7fffffffffffffffULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x6c16c16c16c16c18ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0x6c16c16c16c16c17ULL, }, - { 0x38e38e38e38e38e3ULL, 0x71c71c71c71c71c7ULL, }, - { 0x38e38e38e38e38e2ULL, 0x71c71c71c71c71c8ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, /* 64 */ - { 0x7bd718d08a09e3b8ULL, 0x5e5ec67913bb0308ULL, }, - { 0x7fffffffffffffffULL, 0x733fd25ea9a6d520ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7bd718d08a09e3b8ULL, 0x5e5ec67913bb0308ULL, }, - { 0x0883ff3964d871f0ULL, 0x25ef76342a7ea5f8ULL, }, - { 0x57e750f1f89cad78ULL, 0x3ad08219c06a7810ULL, }, - { 0x749115ea109e1b46ULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x733fd25ea9a6d520ULL, }, /* 72 */ - { 0x57e750f1f89cad78ULL, 0x3ad08219c06a7810ULL, }, - { 0x7fffffffffffffffULL, 0x4fb18dff56564a28ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x749115ea109e1b46ULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_h.c deleted file mode 100644 index 2901a8174b7d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_A.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_A.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, /* 0 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x5557555755575557ULL, 0x5557555755575557ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x3335333533353335ULL, 0x3335333533353335ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x1c7338e471c91c73ULL, 0x38e471c91c7338e4ULL, }, - { 0x1c7238e571c81c72ULL, 0x38e571c81c7238e5ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x5557555755575557ULL, 0x5557555755575557ULL, }, /* 16 */ - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x71c87fff7fff71c8ULL, 0x7fff7fff71c87fffULL, }, - { 0x71c77fff7fff71c7ULL, 0x7fff7fff71c77fffULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x71c77fff7fff71c7ULL, 0x7fff7fff71c77fffULL, }, - { 0x71c67fff7fff71c6ULL, 0x7fff7fff71c67fffULL, }, - { 0x3335333533353335ULL, 0x3335333533353335ULL, }, /* 32 */ - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x6668666866686668ULL, 0x6668666866686668ULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x4fa66c177fff4fa6ULL, 0x6c177fff4fa66c17ULL, }, - { 0x4fa56c187fff4fa5ULL, 0x6c187fff4fa56c18ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x4fa56c167fff4fa5ULL, 0x6c167fff4fa56c16ULL, }, - { 0x4fa46c177fff4fa4ULL, 0x6c177fff4fa46c17ULL, }, - { 0x1c7338e471c91c73ULL, 0x38e471c91c7338e4ULL, }, /* 48 */ - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x71c87fff7fff71c8ULL, 0x7fff7fff71c87fffULL, }, - { 0x71c77fff7fff71c7ULL, 0x7fff7fff71c77fffULL, }, - { 0x4fa66c177fff4fa6ULL, 0x6c177fff4fa66c17ULL, }, - { 0x4fa56c167fff4fa5ULL, 0x6c167fff4fa56c16ULL, }, - { 0x38e471c67fff38e4ULL, 0x71c67fff38e471c6ULL, }, - { 0x38e371c77fff38e3ULL, 0x71c77fff38e371c7ULL, }, - { 0x1c7238e571c81c72ULL, 0x38e571c81c7238e5ULL, }, /* 56 */ - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x71c77fff7fff71c7ULL, 0x7fff7fff71c77fffULL, }, - { 0x71c67fff7fff71c6ULL, 0x7fff7fff71c67fffULL, }, - { 0x4fa56c187fff4fa5ULL, 0x6c187fff4fa56c18ULL, }, - { 0x4fa46c177fff4fa4ULL, 0x6c177fff4fa46c17ULL, }, - { 0x38e371c77fff38e3ULL, 0x71c77fff38e371c7ULL, }, - { 0x38e271c87fff38e2ULL, 0x71c87fff38e271c8ULL, }, - { 0x7fff326850c47fffULL, 0x7fff16bc030a7fffULL, }, /* 64 */ - { 0x7bd8199775f57fffULL, 0x5e5e504416c47fffULL, }, - { 0x7fff6a8a6e937fffULL, 0x733f445f565a7508ULL, }, - { 0x7fff2f817fff72f2ULL, 0x7fff7fff58436d54ULL, }, - { 0x7bd8199775f57fffULL, 0x5e5e504416c47fffULL, }, - { 0x088400c67fff71f0ULL, 0x25ee7fff2a7e7fffULL, }, - { 0x57e851b97fff7fffULL, 0x3acf7de76a147810ULL, }, - { 0x749116b07fff56aaULL, 0x7fff7fff6bfd705cULL, }, - { 0x7fff6a8a6e937fffULL, 0x733f445f565a7508ULL, }, /* 72 */ - { 0x57e851b97fff7fffULL, 0x3acf7de76a147810ULL, }, - { 0x7fff7fff7fff7fffULL, 0x4fb072027fff4a28ULL, }, - { 0x7fff67a37fff7fffULL, 0x7fff7fff7fff4274ULL, }, - { 0x7fff2f817fff72f2ULL, 0x7fff7fff58436d54ULL, }, - { 0x749116b07fff56aaULL, 0x7fff7fff6bfd705cULL, }, - { 0x7fff67a37fff7fffULL, 0x7fff7fff7fff4274ULL, }, - { 0x7fff2c9a7fff3b64ULL, 0x7fff7fff7fff3ac0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_w.c deleted file mode 100644 index 9e483e07546a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_a_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_A.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_A.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, /* 0 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x5555555755555557ULL, 0x5555555755555557ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x3333333533333335ULL, 0x3333333533333335ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x1c71c71e71c71c73ULL, 0x38e38e391c71c71eULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e3a1c71c71dULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x5555555755555557ULL, 0x5555555755555557ULL, }, /* 16 */ - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x71c71c737fffffffULL, 0x7fffffff71c71c73ULL, }, - { 0x71c71c727fffffffULL, 0x7fffffff71c71c72ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x71c71c727fffffffULL, 0x7fffffff71c71c72ULL, }, - { 0x71c71c717fffffffULL, 0x7fffffff71c71c71ULL, }, - { 0x3333333533333335ULL, 0x3333333533333335ULL, }, /* 32 */ - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x6666666866666668ULL, 0x6666666866666668ULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x4fa4fa517fffffffULL, 0x6c16c16c4fa4fa51ULL, }, - { 0x4fa4fa507fffffffULL, 0x6c16c16d4fa4fa50ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x4fa4fa507fffffffULL, 0x6c16c16b4fa4fa50ULL, }, - { 0x4fa4fa4f7fffffffULL, 0x6c16c16c4fa4fa4fULL, }, - { 0x1c71c71e71c71c73ULL, 0x38e38e391c71c71eULL, }, /* 48 */ - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x71c71c737fffffffULL, 0x7fffffff71c71c73ULL, }, - { 0x71c71c727fffffffULL, 0x7fffffff71c71c72ULL, }, - { 0x4fa4fa517fffffffULL, 0x6c16c16c4fa4fa51ULL, }, - { 0x4fa4fa507fffffffULL, 0x6c16c16b4fa4fa50ULL, }, - { 0x38e38e3a7fffffffULL, 0x71c71c7038e38e3aULL, }, - { 0x38e38e397fffffffULL, 0x71c71c7138e38e39ULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e3a1c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x71c71c727fffffffULL, 0x7fffffff71c71c72ULL, }, - { 0x71c71c717fffffffULL, 0x7fffffff71c71c71ULL, }, - { 0x4fa4fa507fffffffULL, 0x6c16c16d4fa4fa50ULL, }, - { 0x4fa4fa4f7fffffffULL, 0x6c16c16c4fa4fa4fULL, }, - { 0x38e38e397fffffffULL, 0x71c71c7138e38e39ULL, }, - { 0x38e38e387fffffffULL, 0x71c71c7238e38e38ULL, }, - { 0x7fffffff50c4aa80ULL, 0x7fffffff03089fe8ULL, }, /* 64 */ - { 0x7bd718d175f61c48ULL, 0x5e5ec67816c3a2f0ULL, }, - { 0x7fffffff6e92c9c0ULL, 0x733fd25d56592ae0ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff58416d54ULL, }, - { 0x7bd718d175f61c48ULL, 0x5e5ec67816c3a2f0ULL, }, - { 0x0883ff3a7fffffffULL, 0x25ef76342a7ea5f8ULL, }, - { 0x57e750f37fffffffULL, 0x3ad082196a142de8ULL, }, - { 0x749115ea7fffffffULL, 0x7fffffff6bfc705cULL, }, - { 0x7fffffff6e92c9c0ULL, 0x733fd25d56592ae0ULL, }, /* 72 */ - { 0x57e750f37fffffffULL, 0x3ad082196a142de8ULL, }, - { 0x7fffffff7fffffffULL, 0x4fb18dfe7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff58416d54ULL, }, - { 0x749115ea7fffffffULL, 0x7fffffff6bfc705cULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_A_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_b.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_b.c deleted file mode 100644 index 955815bf451b..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xa9a9a9a9a9a9a9a9ULL, 0xa9a9a9a9a9a9a9a9ULL, }, - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, - { 0xcbcbcbcbcbcbcbcbULL, 0xcbcbcbcbcbcbcbcbULL, }, - { 0x3232323232323232ULL, 0x3232323232323232ULL, }, - { 0xe28d37e28d37e28dULL, 0x37e28d37e28d37e2ULL, }, - { 0x1b70c61b70c61b70ULL, 0xc61b70c61b70c61bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xa9a9a9a9a9a9a9a9ULL, 0xa9a9a9a9a9a9a9a9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8d80e28d80e28d80ULL, 0xe28d80e28d80e28dULL, }, - { 0xc61b80c61b80c61bULL, 0x80c61b80c61b80c6ULL, }, - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x2121212121212121ULL, 0x2121212121212121ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x38e37f38e37f38e3ULL, 0x7f38e37f38e37f38ULL, }, - { 0x717f1c717f1c717fULL, 0x1c717f1c717f1c71ULL, }, - { 0xcbcbcbcbcbcbcbcbULL, 0xcbcbcbcbcbcbcbcbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x2121212121212121ULL, 0x2121212121212121ULL, }, - { 0x9898989898989898ULL, 0x9898989898989898ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaf8004af8004af80ULL, 0x04af8004af8004afULL, }, - { 0xe83d93e83d93e83dULL, 0x93e83d93e83d93e8ULL, }, - { 0x3232323232323232ULL, 0x3232323232323232ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16b16c16b16c1ULL, 0x6b16c16b16c16b16ULL, }, - { 0x4f7ffa4f7ffa4f7fULL, 0xfa4f7ffa4f7ffa4fULL, }, - { 0xe28d37e28d37e28dULL, 0x37e28d37e28d37e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8d80e28d80e28d80ULL, 0xe28d80e28d80e28dULL, }, - { 0x38e37f38e37f38e3ULL, 0x7f38e37f38e37f38ULL, }, - { 0xaf8004af8004af80ULL, 0x04af8004af8004afULL, }, - { 0x16c16b16c16b16c1ULL, 0x6b16c16b16c16b16ULL, }, - { 0xc68070c68070c680ULL, 0x70c68070c68070c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1b70c61b70c61b70ULL, 0xc61b70c61b70c61bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc61b80c61b80c61bULL, 0x80c61b80c61b80c6ULL, }, - { 0x717f1c717f1c717fULL, 0x1c717f1c717f1c71ULL, }, - { 0xe83d93e83d93e83dULL, 0x93e83d93e83d93e8ULL, }, - { 0x4f7ffa4f7ffa4f7fULL, 0xfa4f7ffa4f7ffa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x387f8e387f8e387fULL, 0x8e387f8e387f8e38ULL, }, - { 0x807fcc98507f7f7fULL, 0x7f7f167ffc7f8018ULL, }, /* 64 */ - { 0x8328e62f75f51c48ULL, 0x5d5ec678137f0208ULL, }, - { 0x807f9480e131e0c0ULL, 0x723fd15da97fd520ULL, }, - { 0xf87ffc197f7f377fULL, 0xd8589336a77f92acULL, }, - { 0x8328e62f75f51c48ULL, 0x5d5ec678137f0208ULL, }, - { 0xf680007f7f808e10ULL, 0x24ee80342a7e7ff8ULL, }, - { 0xa718ae0d06808088ULL, 0x39cf8119c06a7710ULL, }, - { 0x6b0d167f7fc4a956ULL, 0x9fe880f2be7f349cULL, }, - { 0x807f9480e131e0c0ULL, 0x723fd15da97fd520ULL, }, /* 72 */ - { 0xa718ae0d06808088ULL, 0x39cf8119c06a7710ULL, }, - { 0x807f8080809e8080ULL, 0x4eb08cfe80564a28ULL, }, - { 0x1c7fc4f7170080ceULL, 0xb4c980d7806d07b4ULL, }, - { 0xf87ffc197f7f377fULL, 0xd8589336a77f92acULL, }, - { 0x6b0d167f7fc4a956ULL, 0x9fe880f2be7f349cULL, }, - { 0x1c7fc4f7170080ceULL, 0xb4c980d7806d07b4ULL, }, - { 0x7f7f2c7f7f62c47fULL, 0x80e280b0807fc480ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_d.c deleted file mode 100644 index 0795f7e2c518..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaa9ULL, 0xaaaaaaaaaaaaaaa9ULL, }, - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, - { 0xcccccccccccccccbULL, 0xcccccccccccccccbULL, }, - { 0x3333333333333332ULL, 0x3333333333333332ULL, }, - { 0xe38e38e38e38e38dULL, 0x38e38e38e38e38e2ULL, }, - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaa9ULL, 0xaaaaaaaaaaaaaaa9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0xc71c71c71c71c71bULL, 0x8000000000000000ULL, }, - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x2222222222222221ULL, 0x2222222222222221ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x38e38e38e38e38e3ULL, 0x7fffffffffffffffULL, }, - { 0x71c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0xcccccccccccccccbULL, 0xcccccccccccccccbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x2222222222222221ULL, 0x2222222222222221ULL, }, - { 0x9999999999999998ULL, 0x9999999999999998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xb05b05b05b05b05aULL, 0x05b05b05b05b05afULL, }, - { 0xe93e93e93e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x3333333333333332ULL, 0x3333333333333332ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16c16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xe38e38e38e38e38dULL, 0x38e38e38e38e38e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0x38e38e38e38e38e3ULL, 0x7fffffffffffffffULL, }, - { 0xb05b05b05b05b05aULL, 0x05b05b05b05b05afULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16c16c16c16ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71c71bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71bULL, 0x8000000000000000ULL, }, - { 0x71c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe93e93e93e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e2ULL, 0x8e38e38e38e38e38ULL, }, - { 0x8000000000000000ULL, 0x7fffffffffffffffULL, }, /* 64 */ - { 0x8428e72f75f61c48ULL, 0x5e5ec67913bb0308ULL, }, - { 0x8000000000000000ULL, 0x733fd25ea9a6d520ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589437a7be92acULL, }, - { 0x8428e72f75f61c48ULL, 0x5e5ec67913bb0308ULL, }, - { 0xf77c00c69b278e10ULL, 0x25ef76342a7ea5f8ULL, }, - { 0xa818af0e07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x6c0d16b0abc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0x8000000000000000ULL, 0x733fd25ea9a6d520ULL, }, /* 72 */ - { 0xa818af0e07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x8000000000000000ULL, 0x4fb18dff56564a28ULL, }, - { 0x1ca9c4f818016dceULL, 0xb5ca4fd8546e07b4ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589437a7be92acULL, }, - { 0x6c0d16b0abc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0x1ca9c4f818016dceULL, 0xb5ca4fd8546e07b4ULL, }, - { 0x7fffffffffffffffULL, 0x8000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_h.c deleted file mode 100644 index 793c5afb8ca2..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaa9aaa9aaa9aaa9ULL, 0xaaa9aaa9aaa9aaa9ULL, }, - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, - { 0xcccbcccbcccbcccbULL, 0xcccbcccbcccbcccbULL, }, - { 0x3332333233323332ULL, 0x3332333233323332ULL, }, - { 0xe38d38e28e37e38dULL, 0x38e28e37e38d38e2ULL, }, - { 0x1c70c71b71c61c70ULL, 0xc71b71c61c70c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaa9aaa9aaa9aaa9ULL, 0xaaa9aaa9aaa9aaa9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8e38e38d80008e38ULL, 0xe38d80008e38e38dULL, }, - { 0xc71b80001c71c71bULL, 0x80001c71c71b8000ULL, }, - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x38e37fffe38d38e3ULL, 0x7fffe38d38e37fffULL, }, - { 0x71c61c717fff71c6ULL, 0x1c717fff71c61c71ULL, }, - { 0xcccbcccbcccbcccbULL, 0xcccbcccbcccbcccbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0x9998999899989998ULL, 0x9998999899989998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xb05a05af8000b05aULL, 0x05af8000b05a05afULL, }, - { 0xe93d93e83e93e93dULL, 0x93e83e93e93d93e8ULL, }, - { 0x3332333233323332ULL, 0x3332333233323332ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16c16c16b16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0x4fa4fa4f7fff4fa4ULL, 0xfa4f7fff4fa4fa4fULL, }, - { 0xe38d38e28e37e38dULL, 0x38e28e37e38d38e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8e38e38d80008e38ULL, 0xe38d80008e38e38dULL, }, - { 0x38e37fffe38d38e3ULL, 0x7fffe38d38e37fffULL, }, - { 0xb05a05af8000b05aULL, 0x05af8000b05a05afULL, }, - { 0x16c16c16c16b16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0xc71c71c68000c71cULL, 0x71c68000c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c70c71b71c61c70ULL, 0xc71b71c61c70c71bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71b80001c71c71bULL, 0x80001c71c71b8000ULL, }, - { 0x71c61c717fff71c6ULL, 0x1c717fff71c61c71ULL, }, - { 0xe93d93e83e93e93dULL, 0x93e83e93e93d93e8ULL, }, - { 0x4fa4fa4f7fff4fa4ULL, 0xfa4f7fff4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e28e387fff38e2ULL, 0x8e387fff38e28e38ULL, }, - { 0x8000cd9850c47fffULL, 0x7fff16bcfcf68000ULL, }, /* 64 */ - { 0x8428e72f75f51c48ULL, 0x5e5ec67813ba0308ULL, }, - { 0x80009576e231e0c0ULL, 0x733fd25da9a6d520ULL, }, - { 0xf8b9fd197fff378eULL, 0xd9589436a7bd92acULL, }, - { 0x8428e72f75f51c48ULL, 0x5e5ec67813ba0308ULL, }, - { 0xf77c00c67fff8e10ULL, 0x25ee80002a7e7fffULL, }, - { 0xa818af0d07628000ULL, 0x3acf8219c06a7810ULL, }, - { 0x6c0d16b07fffa956ULL, 0xa0e88000be81359cULL, }, - { 0x80009576e231e0c0ULL, 0x733fd25da9a6d520ULL, }, /* 72 */ - { 0xa818af0d07628000ULL, 0x3acf8219c06a7810ULL, }, - { 0x8000800080008000ULL, 0x4fb08dfe80004a28ULL, }, - { 0x1ca9c4f718008000ULL, 0xb5c98000800007b4ULL, }, - { 0xf8b9fd197fff378eULL, 0xd9589436a7bd92acULL, }, - { 0x6c0d16b07fffa956ULL, 0xa0e88000be81359cULL, }, - { 0x1ca9c4f718008000ULL, 0xb5c98000800007b4ULL, }, - { 0x7fff2c9a7fffc49cULL, 0x800080008000c540ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_w.c deleted file mode 100644 index 1c72c8466921..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaa9aaaaaaa9ULL, 0xaaaaaaa9aaaaaaa9ULL, }, - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, - { 0xcccccccbcccccccbULL, 0xcccccccbcccccccbULL, }, - { 0x3333333233333332ULL, 0x3333333233333332ULL, }, - { 0xe38e38e28e38e38dULL, 0x38e38e37e38e38e2ULL, }, - { 0x1c71c71b71c71c70ULL, 0xc71c71c61c71c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaa9aaaaaaa9ULL, 0xaaaaaaa9aaaaaaa9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8e38e38d80000000ULL, 0xe38e38e28e38e38dULL, }, - { 0xc71c71c61c71c71bULL, 0x80000000c71c71c6ULL, }, - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x38e38e38e38e38e3ULL, 0x7fffffff38e38e38ULL, }, - { 0x71c71c717fffffffULL, 0x1c71c71c71c71c71ULL, }, - { 0xcccccccbcccccccbULL, 0xcccccccbcccccccbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0x9999999899999998ULL, 0x9999999899999998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xb05b05af80000000ULL, 0x05b05b04b05b05afULL, }, - { 0xe93e93e83e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x3333333233333332ULL, 0x3333333233333332ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0x4fa4fa4f7fffffffULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xe38e38e28e38e38dULL, 0x38e38e37e38e38e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8e38e38d80000000ULL, 0xe38e38e28e38e38dULL, }, - { 0x38e38e38e38e38e3ULL, 0x7fffffff38e38e38ULL, }, - { 0xb05b05af80000000ULL, 0x05b05b04b05b05afULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0xc71c71c680000000ULL, 0x71c71c70c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71b71c71c70ULL, 0xc71c71c61c71c71bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c61c71c71bULL, 0x80000000c71c71c6ULL, }, - { 0x71c71c717fffffffULL, 0x1c71c71c71c71c71ULL, }, - { 0xe93e93e83e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x4fa4fa4f7fffffffULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e38e387fffffffULL, 0x8e38e38e38e38e38ULL, }, - { 0x8000000050c4aa80ULL, 0x7ffffffffcf76018ULL, }, /* 64 */ - { 0x8428e72f75f61c48ULL, 0x5e5ec67813bb0308ULL, }, - { 0x80000000e231e0c0ULL, 0x733fd25da9a6d520ULL, }, - { 0xf8b9fd197fffffffULL, 0xd9589436a7be92acULL, }, - { 0x8428e72f75f61c48ULL, 0x5e5ec67813bb0308ULL, }, - { 0xf77c00c67fffffffULL, 0x25ef76342a7ea5f8ULL, }, - { 0xa818af0d07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x6c0d16b07fffffffULL, 0xa0e943f2be82359cULL, }, - { 0x80000000e231e0c0ULL, 0x733fd25da9a6d520ULL, }, /* 72 */ - { 0xa818af0d07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x8000000080000000ULL, 0x4fb18dfe80000000ULL, }, - { 0x1ca9c4f718016dceULL, 0xb5ca4fd780000000ULL, }, - { 0xf8b9fd197fffffffULL, 0xd9589436a7be92acULL, }, - { 0x6c0d16b07fffffffULL, 0xa0e943f2be82359cULL, }, - { 0x1ca9c4f718016dceULL, 0xb5ca4fd780000000ULL, }, - { 0x7fffffff7fffffffULL, 0x8000000080000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_b.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_b.c deleted file mode 100644 index f20340799e0d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xffffe2ffffe2ffffULL, 0xe2ffffe2ffffe2ffULL, }, - { 0xc6ffffc6ffffc6ffULL, 0xffc6ffffc6ffffc6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffe38dffe38dffe3ULL, 0x8dffe38dffe38dffULL, }, - { 0x71c6ff71c6ff71c6ULL, 0xff71c6ff71c6ff71ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe8ffffe8ffffe8ffULL, 0xffe8ffffe8ffffe8ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xffc16bffc16bffc1ULL, 0x6bffc16bffc16bffULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffe2ffffe2ffffULL, 0xe2ffffe2ffffe2ffULL, }, - { 0xffe38dffe38dffe3ULL, 0x8dffe38dffe38dffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffc16bffc16bffc1ULL, 0x6bffc16bffc16bffULL, }, - { 0xffff70ffff70ffffULL, 0x70ffff70ffff70ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc6ffffc6ffffc6ffULL, 0xffc6ffffc6ffffc6ULL, }, - { 0x71c6ff71c6ff71c6ULL, 0xff71c6ff71c6ff71ULL, }, - { 0xe8ffffe8ffffe8ffULL, 0xffe8ffffe8ffffe8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e2ff38e2ff38e2ULL, 0xff38e2ff38e2ff38ULL, }, - { 0xffd4ffff50c4aa80ULL, 0x96ce16bcfff6ff18ULL, }, /* 64 */ - { 0xffffe6ff75f5ff48ULL, 0x5dffc678ffbaffffULL, }, - { 0xffc4ffffe1ffe0c0ULL, 0x72ffd1ffffa6d520ULL, }, - { 0xf8b9fcff8693ff8eULL, 0xd8ff93ffffbdffacULL, }, - { 0xffffe6ff75f5ff48ULL, 0x5dffc678ffbaffffULL, }, - { 0xffff00c69affff10ULL, 0x24ffff342a7ea4ffULL, }, - { 0xffffaeffffffff88ULL, 0x39ffffffc06a77ffULL, }, - { 0xffff16b0abc4ff56ULL, 0x9ffffff2be81ffffULL, }, - { 0xffc4ffffe1ffe0c0ULL, 0x72ffd1ffffa6d520ULL, }, /* 72 */ - { 0xffffaeffffffff88ULL, 0x39ffffffc06a77ffULL, }, - { 0xffb4ffffffffffffULL, 0x4effffffff564a28ULL, }, - { 0xffa9c4f7ffffffceULL, 0xb4ffffffff6dffb4ULL, }, - { 0xf8b9fcff8693ff8eULL, 0xd8ff93ffffbdffacULL, }, - { 0xffff16b0abc4ff56ULL, 0x9ffffff2be81ffffULL, }, - { 0xffa9c4f7ffffffceULL, 0xb4ffffffff6dffb4ULL, }, - { 0xe09e2c9abc62ff9cULL, 0xffffffffff84ffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_d.c deleted file mode 100644 index 30249edca005..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xffffffffffffffffULL, 0xe38e38e38e38e38dULL, }, - { 0xc71c71c71c71c71bULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0x8e38e38e38e38e38ULL, }, - { 0x71c71c71c71c71c6ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe93e93e93e93e93dULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xffffffffffffffffULL, 0x6c16c16c16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xe38e38e38e38e38dULL, }, - { 0xffffffffffffffffULL, 0x8e38e38e38e38e38ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x6c16c16c16c16c16ULL, }, - { 0xffffffffffffffffULL, 0x71c71c71c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71bULL, 0xffffffffffffffffULL, }, - { 0x71c71c71c71c71c6ULL, 0xffffffffffffffffULL, }, - { 0xe93e93e93e93e93dULL, 0xffffffffffffffffULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e2ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x96ce16bdfcf76018ULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x5e5ec67913bb0308ULL, }, - { 0xffffffffffffffffULL, 0x733fd25ea9a6d520ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589437a7be92acULL, }, - { 0xffffffffffffffffULL, 0x5e5ec67913bb0308ULL, }, - { 0xffffffffffffffffULL, 0x25ef76342a7ea5f8ULL, }, - { 0xffffffffffffffffULL, 0x3ad08219c06a7810ULL, }, - { 0xffffffffffffffffULL, 0xa0e943f2be82359cULL, }, - { 0xffffffffffffffffULL, 0x733fd25ea9a6d520ULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x3ad08219c06a7810ULL, }, - { 0xffffffffffffffffULL, 0x4fb18dff56564a28ULL, }, - { 0xffffffffffffffffULL, 0xb5ca4fd8546e07b4ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589437a7be92acULL, }, - { 0xffffffffffffffffULL, 0xa0e943f2be82359cULL, }, - { 0xffffffffffffffffULL, 0xb5ca4fd8546e07b4ULL, }, - { 0xe09e2c9abc63c49cULL, 0xffffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_h.c deleted file mode 100644 index 1bd8aa9d20bd..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xffffe38dffffffffULL, 0xe38dffffffffe38dULL, }, - { 0xc71bffffffffc71bULL, 0xffffffffc71bffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffff8e38e38dffffULL, 0x8e38e38dffff8e38ULL, }, - { 0x71c6ffffc71c71c6ULL, 0xffffc71c71c6ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe93dffffffffe93dULL, 0xffffffffe93dffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xffff6c16c16bffffULL, 0x6c16c16bffff6c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffe38dffffffffULL, 0xe38dffffffffe38dULL, }, - { 0xffff8e38e38dffffULL, 0x8e38e38dffff8e38ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffff6c16c16bffffULL, 0x6c16c16bffff6c16ULL, }, - { 0xffff71c6ffffffffULL, 0x71c6ffffffff71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71bffffffffc71bULL, 0xffffffffc71bffffULL, }, - { 0x71c6ffffc71c71c6ULL, 0xffffc71c71c6ffffULL, }, - { 0xe93dffffffffe93dULL, 0xffffffffe93dffffULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e2ffffe38e38e2ULL, 0xffffe38e38e2ffffULL, }, - { 0xffffffff50c4aa80ULL, 0x96ce16bcffffffffULL, }, /* 64 */ - { 0xffffe72f75f5ffffULL, 0x5e5ec678ffffffffULL, }, - { 0xffffffffe231e0c0ULL, 0x733fd25dffffd520ULL, }, - { 0xf8b9fd198693ffffULL, 0xd9589436ffffffffULL, }, - { 0xffffe72f75f5ffffULL, 0x5e5ec678ffffffffULL, }, - { 0xffff00c69b26ffffULL, 0x25eeffff2a7ea5f8ULL, }, - { 0xffffaf0dffffffffULL, 0x3acfffffc06a7810ULL, }, - { 0xffff16b0abc4ffffULL, 0xa0e8ffffbe81ffffULL, }, - { 0xffffffffe231e0c0ULL, 0x733fd25dffffd520ULL, }, /* 72 */ - { 0xffffaf0dffffffffULL, 0x3acfffffc06a7810ULL, }, - { 0xffffffffffffffffULL, 0x4fb0ffffffff4a28ULL, }, - { 0xffffc4f7ffffffffULL, 0xb5c9ffffffffffffULL, }, - { 0xf8b9fd198693ffffULL, 0xd9589436ffffffffULL, }, - { 0xffff16b0abc4ffffULL, 0xa0e8ffffbe81ffffULL, }, - { 0xffffc4f7ffffffffULL, 0xb5c9ffffffffffffULL, }, - { 0xe09e2c9abc62ffffULL, 0xffffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_w.c deleted file mode 100644 index a91c69f6249f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_adds_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDS_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDS_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xffffffffffffffffULL, 0xe38e38e2ffffffffULL, }, - { 0xc71c71c6ffffffffULL, 0xffffffffc71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffe38e38e3ULL, 0x8e38e38dffffffffULL, }, - { 0x71c71c71c71c71c6ULL, 0xffffffff71c71c71ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe93e93e8ffffffffULL, 0xffffffffe93e93e8ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xffffffffc16c16c1ULL, 0x6c16c16bffffffffULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xe38e38e2ffffffffULL, }, - { 0xffffffffe38e38e3ULL, 0x8e38e38dffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffc16c16c1ULL, 0x6c16c16bffffffffULL, }, - { 0xffffffffffffffffULL, 0x71c71c70ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c6ffffffffULL, 0xffffffffc71c71c6ULL, }, - { 0x71c71c71c71c71c6ULL, 0xffffffff71c71c71ULL, }, - { 0xe93e93e8ffffffffULL, 0xffffffffe93e93e8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e2ULL, 0xffffffff38e38e38ULL, }, - { 0xffffffff50c4aa80ULL, 0x96ce16bcffffffffULL, }, /* 64 */ - { 0xffffffff75f61c48ULL, 0x5e5ec678ffffffffULL, }, - { 0xffffffffe231e0c0ULL, 0x733fd25dffffffffULL, }, - { 0xf8b9fd198694378eULL, 0xd9589436ffffffffULL, }, - { 0xffffffff75f61c48ULL, 0x5e5ec678ffffffffULL, }, - { 0xffffffff9b278e10ULL, 0x25ef76342a7ea5f8ULL, }, - { 0xffffffffffffffffULL, 0x3ad08219c06a7810ULL, }, - { 0xffffffffabc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0xffffffffe231e0c0ULL, 0x733fd25dffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x3ad08219c06a7810ULL, }, - { 0xffffffffffffffffULL, 0x4fb18dfeffffffffULL, }, - { 0xffffffffffffffffULL, 0xb5ca4fd7ffffffffULL, }, - { 0xf8b9fd198694378eULL, 0xd9589436ffffffffULL, }, - { 0xffffffffabc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0xffffffffffffffffULL, 0xb5ca4fd7ffffffffULL, }, - { 0xe09e2c9abc63c49cULL, 0xffffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDS_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_b.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_b.c deleted file mode 100644 index 2f11c76aa37e..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xa9a9a9a9a9a9a9a9ULL, 0xa9a9a9a9a9a9a9a9ULL, }, - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, - { 0xcbcbcbcbcbcbcbcbULL, 0xcbcbcbcbcbcbcbcbULL, }, - { 0x3232323232323232ULL, 0x3232323232323232ULL, }, - { 0xe28d37e28d37e28dULL, 0x37e28d37e28d37e2ULL, }, - { 0x1b70c61b70c61b70ULL, 0xc61b70c61b70c61bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xa9a9a9a9a9a9a9a9ULL, 0xa9a9a9a9a9a9a9a9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7676767676767676ULL, 0x7676767676767676ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8d38e28d38e28d38ULL, 0xe28d38e28d38e28dULL, }, - { 0xc61b71c61b71c61bULL, 0x71c61b71c61b71c6ULL, }, - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2121212121212121ULL, 0x2121212121212121ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x38e38d38e38d38e3ULL, 0x8d38e38d38e38d38ULL, }, - { 0x71c61c71c61c71c6ULL, 0x1c71c61c71c61c71ULL, }, - { 0xcbcbcbcbcbcbcbcbULL, 0xcbcbcbcbcbcbcbcbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7676767676767676ULL, 0x7676767676767676ULL, }, - { 0x2121212121212121ULL, 0x2121212121212121ULL, }, - { 0x9898989898989898ULL, 0x9898989898989898ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaf5a04af5a04af5aULL, 0x04af5a04af5a04afULL, }, - { 0xe83d93e83d93e83dULL, 0x93e83d93e83d93e8ULL, }, - { 0x3232323232323232ULL, 0x3232323232323232ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16b16c16b16c1ULL, 0x6b16c16b16c16b16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xe28d37e28d37e28dULL, 0x37e28d37e28d37e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8d38e28d38e28d38ULL, 0xe28d38e28d38e28dULL, }, - { 0x38e38d38e38d38e3ULL, 0x8d38e38d38e38d38ULL, }, - { 0xaf5a04af5a04af5aULL, 0x04af5a04af5a04afULL, }, - { 0x16c16b16c16b16c1ULL, 0x6b16c16b16c16b16ULL, }, - { 0xc61c70c61c70c61cULL, 0x70c61c70c61c70c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1b70c61b70c61b70ULL, 0xc61b70c61b70c61bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc61b71c61b71c61bULL, 0x71c61b71c61b71c6ULL, }, - { 0x71c61c71c61c71c6ULL, 0x1c71c61c71c61c71ULL, }, - { 0xe83d93e83d93e83dULL, 0x93e83d93e83d93e8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e28e38e28e38e2ULL, 0x8e38e28e38e28e38ULL, }, - { 0x10d4cc9850c4aa80ULL, 0x96ce16bcfcf66018ULL, }, /* 64 */ - { 0x8328e62f75f51c48ULL, 0x5d5ec67813ba0208ULL, }, - { 0x34c49476e131e0c0ULL, 0x723fd15da9a6d520ULL, }, - { 0xf8b9fc198693378eULL, 0xd8589336a7bd92acULL, }, - { 0x8328e62f75f51c48ULL, 0x5d5ec67813ba0208ULL, }, - { 0xf67c00c69a268e10ULL, 0x24ee76342a7ea4f8ULL, }, - { 0xa718ae0d06625288ULL, 0x39cf8119c06a7710ULL, }, - { 0x6b0d16b0abc4a956ULL, 0x9fe843f2be81349cULL, }, - { 0x34c49476e131e0c0ULL, 0x723fd15da9a6d520ULL, }, /* 72 */ - { 0xa718ae0d06625288ULL, 0x39cf8119c06a7710ULL, }, - { 0x58b45c54729e1600ULL, 0x4eb08cfe56564a28ULL, }, - { 0x1ca9c4f717006dceULL, 0xb4c94ed7546d07b4ULL, }, - { 0xf8b9fc198693378eULL, 0xd8589336a7bd92acULL, }, - { 0x6b0d16b0abc4a956ULL, 0x9fe843f2be81349cULL, }, - { 0x1ca9c4f717006dceULL, 0xb4c94ed7546d07b4ULL, }, - { 0xe09e2c9abc62c49cULL, 0x1ae210b05284c440ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_d.c deleted file mode 100644 index 4ed0b97876a7..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaa9ULL, 0xaaaaaaaaaaaaaaa9ULL, }, - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, - { 0xcccccccccccccccbULL, 0xcccccccccccccccbULL, }, - { 0x3333333333333332ULL, 0x3333333333333332ULL, }, - { 0xe38e38e38e38e38dULL, 0x38e38e38e38e38e2ULL, }, - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaa9ULL, 0xaaaaaaaaaaaaaaa9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7777777777777776ULL, 0x7777777777777776ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0xc71c71c71c71c71bULL, 0x71c71c71c71c71c6ULL, }, - { 0x5555555555555554ULL, 0x5555555555555554ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2222222222222221ULL, 0x2222222222222221ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e38ULL, }, - { 0x71c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0xcccccccccccccccbULL, 0xcccccccccccccccbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7777777777777776ULL, 0x7777777777777776ULL, }, - { 0x2222222222222221ULL, 0x2222222222222221ULL, }, - { 0x9999999999999998ULL, 0x9999999999999998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xb05b05b05b05b05aULL, 0x05b05b05b05b05afULL, }, - { 0xe93e93e93e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x3333333333333332ULL, 0x3333333333333332ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16c16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xe38e38e38e38e38dULL, 0x38e38e38e38e38e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e38ULL, }, - { 0xb05b05b05b05b05aULL, 0x05b05b05b05b05afULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16c16c16c16ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c70ULL, 0xc71c71c71c71c71bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71bULL, 0x71c71c71c71c71c6ULL, }, - { 0x71c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe93e93e93e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e2ULL, 0x8e38e38e38e38e38ULL, }, - { 0x10d5cd9850c4aa80ULL, 0x96ce16bdfcf76018ULL, }, /* 64 */ - { 0x8428e72f75f61c48ULL, 0x5e5ec67913bb0308ULL, }, - { 0x34c59576e231e0c0ULL, 0x733fd25ea9a6d520ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589437a7be92acULL, }, - { 0x8428e72f75f61c48ULL, 0x5e5ec67913bb0308ULL, }, - { 0xf77c00c69b278e10ULL, 0x25ef76342a7ea5f8ULL, }, - { 0xa818af0e07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x6c0d16b0abc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0x34c59576e231e0c0ULL, 0x733fd25ea9a6d520ULL, }, /* 72 */ - { 0xa818af0e07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x58b55d55739f1700ULL, 0x4fb18dff56564a28ULL, }, - { 0x1ca9c4f818016dceULL, 0xb5ca4fd8546e07b4ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589437a7be92acULL, }, - { 0x6c0d16b0abc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0x1ca9c4f818016dceULL, 0xb5ca4fd8546e07b4ULL, }, - { 0xe09e2c9abc63c49cULL, 0x1be311b15285c540ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_h.c deleted file mode 100644 index ca6ddd4b540d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaa9aaa9aaa9aaa9ULL, 0xaaa9aaa9aaa9aaa9ULL, }, - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, - { 0xcccbcccbcccbcccbULL, 0xcccbcccbcccbcccbULL, }, - { 0x3332333233323332ULL, 0x3332333233323332ULL, }, - { 0xe38d38e28e37e38dULL, 0x38e28e37e38d38e2ULL, }, - { 0x1c70c71b71c61c70ULL, 0xc71b71c61c70c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaa9aaa9aaa9aaa9ULL, 0xaaa9aaa9aaa9aaa9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7776777677767776ULL, 0x7776777677767776ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8e38e38d38e28e38ULL, 0xe38d38e28e38e38dULL, }, - { 0xc71b71c61c71c71bULL, 0x71c61c71c71b71c6ULL, }, - { 0x5554555455545554ULL, 0x5554555455545554ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x38e38e38e38d38e3ULL, 0x8e38e38d38e38e38ULL, }, - { 0x71c61c71c71c71c6ULL, 0x1c71c71c71c61c71ULL, }, - { 0xcccbcccbcccbcccbULL, 0xcccbcccbcccbcccbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7776777677767776ULL, 0x7776777677767776ULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0x9998999899989998ULL, 0x9998999899989998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xb05a05af5b04b05aULL, 0x05af5b04b05a05afULL, }, - { 0xe93d93e83e93e93dULL, 0x93e83e93e93d93e8ULL, }, - { 0x3332333233323332ULL, 0x3332333233323332ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16c16c16b16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xe38d38e28e37e38dULL, 0x38e28e37e38d38e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8e38e38d38e28e38ULL, 0xe38d38e28e38e38dULL, }, - { 0x38e38e38e38d38e3ULL, 0x8e38e38d38e38e38ULL, }, - { 0xb05a05af5b04b05aULL, 0x05af5b04b05a05afULL, }, - { 0x16c16c16c16b16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0xc71c71c61c70c71cULL, 0x71c61c70c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c70c71b71c61c70ULL, 0xc71b71c61c70c71bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71b71c61c71c71bULL, 0x71c61c71c71b71c6ULL, }, - { 0x71c61c71c71c71c6ULL, 0x1c71c71c71c61c71ULL, }, - { 0xe93d93e83e93e93dULL, 0x93e83e93e93d93e8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e28e38e38e38e2ULL, 0x8e38e38e38e28e38ULL, }, - { 0x10d4cd9850c4aa80ULL, 0x96ce16bcfcf66018ULL, }, /* 64 */ - { 0x8428e72f75f51c48ULL, 0x5e5ec67813ba0308ULL, }, - { 0x34c49576e231e0c0ULL, 0x733fd25da9a6d520ULL, }, - { 0xf8b9fd198693378eULL, 0xd9589436a7bd92acULL, }, - { 0x8428e72f75f51c48ULL, 0x5e5ec67813ba0308ULL, }, - { 0xf77c00c69b268e10ULL, 0x25ee76342a7ea5f8ULL, }, - { 0xa818af0d07625288ULL, 0x3acf8219c06a7810ULL, }, - { 0x6c0d16b0abc4a956ULL, 0xa0e843f2be81359cULL, }, - { 0x34c49576e231e0c0ULL, 0x733fd25da9a6d520ULL, }, /* 72 */ - { 0xa818af0d07625288ULL, 0x3acf8219c06a7810ULL, }, - { 0x58b45d54739e1700ULL, 0x4fb08dfe56564a28ULL, }, - { 0x1ca9c4f718006dceULL, 0xb5c94fd7546d07b4ULL, }, - { 0xf8b9fd198693378eULL, 0xd9589436a7bd92acULL, }, - { 0x6c0d16b0abc4a956ULL, 0xa0e843f2be81359cULL, }, - { 0x1ca9c4f718006dceULL, 0xb5c94fd7546d07b4ULL, }, - { 0xe09e2c9abc62c49cULL, 0x1be211b05284c540ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_w.c deleted file mode 100644 index dff0f70a0754..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_addv_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ADDV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "ADDV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaa9aaaaaaa9ULL, 0xaaaaaaa9aaaaaaa9ULL, }, - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, - { 0xcccccccbcccccccbULL, 0xcccccccbcccccccbULL, }, - { 0x3333333233333332ULL, 0x3333333233333332ULL, }, - { 0xe38e38e28e38e38dULL, 0x38e38e37e38e38e2ULL, }, - { 0x1c71c71b71c71c70ULL, 0xc71c71c61c71c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaa9aaaaaaa9ULL, 0xaaaaaaa9aaaaaaa9ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7777777677777776ULL, 0x7777777677777776ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8e38e38d38e38e38ULL, 0xe38e38e28e38e38dULL, }, - { 0xc71c71c61c71c71bULL, 0x71c71c71c71c71c6ULL, }, - { 0x5555555455555554ULL, 0x5555555455555554ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38d38e38e38ULL, }, - { 0x71c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0xcccccccbcccccccbULL, 0xcccccccbcccccccbULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7777777677777776ULL, 0x7777777677777776ULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0x9999999899999998ULL, 0x9999999899999998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xb05b05af5b05b05aULL, 0x05b05b04b05b05afULL, }, - { 0xe93e93e83e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x3333333233333332ULL, 0x3333333233333332ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xe38e38e28e38e38dULL, 0x38e38e37e38e38e2ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8e38e38d38e38e38ULL, 0xe38e38e28e38e38dULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38d38e38e38ULL, }, - { 0xb05b05af5b05b05aULL, 0x05b05b04b05b05afULL, }, - { 0x16c16c16c16c16c1ULL, 0x6c16c16b16c16c16ULL, }, - { 0xc71c71c61c71c71cULL, 0x71c71c70c71c71c6ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71b71c71c70ULL, 0xc71c71c61c71c71bULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c61c71c71bULL, 0x71c71c71c71c71c6ULL, }, - { 0x71c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe93e93e83e93e93dULL, 0x93e93e93e93e93e8ULL, }, - { 0x4fa4fa4fa4fa4fa4ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e2ULL, 0x8e38e38e38e38e38ULL, }, - { 0x10d5cd9850c4aa80ULL, 0x96ce16bcfcf76018ULL, }, /* 64 */ - { 0x8428e72f75f61c48ULL, 0x5e5ec67813bb0308ULL, }, - { 0x34c59576e231e0c0ULL, 0x733fd25da9a6d520ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589436a7be92acULL, }, - { 0x8428e72f75f61c48ULL, 0x5e5ec67813bb0308ULL, }, - { 0xf77c00c69b278e10ULL, 0x25ef76342a7ea5f8ULL, }, - { 0xa818af0d07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x6c0d16b0abc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0x34c59576e231e0c0ULL, 0x733fd25da9a6d520ULL, }, /* 72 */ - { 0xa818af0d07635288ULL, 0x3ad08219c06a7810ULL, }, - { 0x58b55d54739f1700ULL, 0x4fb18dfe56564a28ULL, }, - { 0x1ca9c4f718016dceULL, 0xb5ca4fd7546e07b4ULL, }, - { 0xf8b9fd198694378eULL, 0xd9589436a7be92acULL, }, - { 0x6c0d16b0abc5a956ULL, 0xa0e943f2be82359cULL, }, - { 0x1ca9c4f718016dceULL, 0xb5ca4fd7546e07b4ULL, }, - { 0xe09e2c9abc63c49cULL, 0x1be311b05285c540ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ADDV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_d.c deleted file mode 100644 index c50a9dde8753..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HADD_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "HADD_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffaaaaaaa9ULL, 0xffffffffaaaaaaa9ULL, }, - { 0x0000000055555554ULL, 0x0000000055555554ULL, }, - { 0xffffffffcccccccbULL, 0xffffffffcccccccbULL, }, - { 0x0000000033333332ULL, 0x0000000033333332ULL, }, - { 0xffffffff8e38e38dULL, 0xffffffffe38e38e2ULL, }, - { 0x0000000071c71c70ULL, 0x000000001c71c71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0xffffffff8e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0xffffffffaaaaaaa9ULL, 0xffffffffaaaaaaa9ULL, }, /* 16 */ - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0xffffffff55555554ULL, 0xffffffff55555554ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff77777776ULL, 0xffffffff77777776ULL, }, - { 0xffffffffddddddddULL, 0xffffffffddddddddULL, }, - { 0xffffffff38e38e38ULL, 0xffffffff8e38e38dULL, }, - { 0x000000001c71c71bULL, 0xffffffffc71c71c6ULL, }, - { 0x0000000055555554ULL, 0x0000000055555554ULL, }, /* 24 */ - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000022222221ULL, 0x0000000022222221ULL, }, - { 0x0000000088888888ULL, 0x0000000088888888ULL, }, - { 0xffffffffe38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0x00000000c71c71c6ULL, 0x0000000071c71c71ULL, }, - { 0xffffffffcccccccbULL, 0xffffffffcccccccbULL, }, /* 32 */ - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0xffffffff77777776ULL, 0xffffffff77777776ULL, }, - { 0x0000000022222221ULL, 0x0000000022222221ULL, }, - { 0xffffffff99999998ULL, 0xffffffff99999998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff5b05b05aULL, 0xffffffffb05b05afULL, }, - { 0x000000003e93e93dULL, 0xffffffffe93e93e8ULL, }, - { 0x0000000033333332ULL, 0x0000000033333332ULL, }, /* 40 */ - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0xffffffffddddddddULL, 0xffffffffddddddddULL, }, - { 0x0000000088888888ULL, 0x0000000088888888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000066666666ULL, 0x0000000066666666ULL, }, - { 0xffffffffc16c16c1ULL, 0x0000000016c16c16ULL, }, - { 0x00000000a4fa4fa4ULL, 0x000000004fa4fa4fULL, }, - { 0xffffffffe38e38e2ULL, 0x0000000038e38e37ULL, }, /* 48 */ - { 0xffffffffe38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0xffffffff8e38e38dULL, 0xffffffffe38e38e2ULL, }, - { 0x0000000038e38e38ULL, 0x000000008e38e38dULL, }, - { 0xffffffffb05b05afULL, 0x0000000005b05b04ULL, }, - { 0x0000000016c16c16ULL, 0x000000006c16c16bULL, }, - { 0xffffffff71c71c71ULL, 0x000000001c71c71bULL, }, - { 0x0000000055555554ULL, 0x0000000055555554ULL, }, - { 0x000000001c71c71bULL, 0xffffffffc71c71c6ULL, }, /* 56 */ - { 0x000000001c71c71cULL, 0xffffffffc71c71c7ULL, }, - { 0xffffffffc71c71c6ULL, 0xffffffff71c71c71ULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0xffffffffe93e93e8ULL, 0xffffffff93e93e93ULL, }, - { 0x000000004fa4fa4fULL, 0xfffffffffa4fa4faULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0x000000008e38e38dULL, 0xffffffffe38e38e3ULL, }, - { 0xffffffffb0cd3c0cULL, 0x0000000049e2bb6aULL, }, /* 64 */ - { 0xffffffffd5feadd4ULL, 0x0000000060a65e5aULL, }, - { 0xffffffff423a724cULL, 0xfffffffff6923072ULL, }, - { 0xffffffffe69cc91aULL, 0xfffffffff4a9edfeULL, }, - { 0x00000000242055a3ULL, 0x0000000011736b26ULL, }, - { 0x000000004951c76bULL, 0x0000000028370e16ULL, }, - { 0xffffffffb58d8be3ULL, 0xffffffffbe22e02eULL, }, - { 0x0000000059efe2b1ULL, 0xffffffffbc3a9dbaULL, }, - { 0xffffffffd4bd03eaULL, 0x000000002654770bULL, }, /* 72 */ - { 0xfffffffff9ee75b2ULL, 0x000000003d1819fbULL, }, - { 0xffffffff662a3a2aULL, 0xffffffffd303ec13ULL, }, - { 0x000000000a8c90f8ULL, 0xffffffffd11ba99fULL, }, - { 0x0000000098b16b8dULL, 0xffffffff8c6d38e4ULL, }, - { 0x00000000bde2dd55ULL, 0xffffffffa330dbd4ULL, }, - { 0x000000002a1ea1cdULL, 0xffffffff391cadecULL, }, - { 0x00000000ce80f89bULL, 0xffffffff37346b78ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_h.c deleted file mode 100644 index 586ef923ccf0..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HADD_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "HADD_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffa9ffa9ffa9ffa9ULL, 0xffa9ffa9ffa9ffa9ULL, }, - { 0x0054005400540054ULL, 0x0054005400540054ULL, }, - { 0xffcbffcbffcbffcbULL, 0xffcbffcbffcbffcbULL, }, - { 0x0032003200320032ULL, 0x0032003200320032ULL, }, - { 0xff8dffe20037ff8dULL, 0xffe20037ff8dffe2ULL, }, - { 0x0070001bffc60070ULL, 0x001bffc60070001bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0xff8effe30038ff8eULL, 0xffe30038ff8effe3ULL, }, - { 0x0071001cffc70071ULL, 0x001cffc70071001cULL, }, - { 0xffa9ffa9ffa9ffa9ULL, 0xffa9ffa9ffa9ffa9ULL, }, /* 16 */ - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0xff54ff54ff54ff54ULL, 0xff54ff54ff54ff54ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff76ff76ff76ff76ULL, 0xff76ff76ff76ff76ULL, }, - { 0xffddffddffddffddULL, 0xffddffddffddffddULL, }, - { 0xff38ff8dffe2ff38ULL, 0xff8dffe2ff38ff8dULL, }, - { 0x001bffc6ff71001bULL, 0xffc6ff71001bffc6ULL, }, - { 0x0054005400540054ULL, 0x0054005400540054ULL, }, /* 24 */ - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0021002100210021ULL, 0x0021002100210021ULL, }, - { 0x0088008800880088ULL, 0x0088008800880088ULL, }, - { 0xffe30038008dffe3ULL, 0x0038008dffe30038ULL, }, - { 0x00c60071001c00c6ULL, 0x0071001c00c60071ULL, }, - { 0xffcbffcbffcbffcbULL, 0xffcbffcbffcbffcbULL, }, /* 32 */ - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0xff76ff76ff76ff76ULL, 0xff76ff76ff76ff76ULL, }, - { 0x0021002100210021ULL, 0x0021002100210021ULL, }, - { 0xff98ff98ff98ff98ULL, 0xff98ff98ff98ff98ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff5affaf0004ff5aULL, 0xffaf0004ff5affafULL, }, - { 0x003dffe8ff93003dULL, 0xffe8ff93003dffe8ULL, }, - { 0x0032003200320032ULL, 0x0032003200320032ULL, }, /* 40 */ - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0xffddffddffddffddULL, 0xffddffddffddffddULL, }, - { 0x0088008800880088ULL, 0x0088008800880088ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0066006600660066ULL, 0x0066006600660066ULL, }, - { 0xffc10016006bffc1ULL, 0x0016006bffc10016ULL, }, - { 0x00a4004ffffa00a4ULL, 0x004ffffa00a4004fULL, }, - { 0xffe20037ff8dffe2ULL, 0x0037ff8dffe20037ULL, }, /* 48 */ - { 0xffe30038ff8effe3ULL, 0x0038ff8effe30038ULL, }, - { 0xff8dffe2ff38ff8dULL, 0xffe2ff38ff8dffe2ULL, }, - { 0x0038008dffe30038ULL, 0x008dffe30038008dULL, }, - { 0xffaf0004ff5affafULL, 0x0004ff5affaf0004ULL, }, - { 0x0016006bffc10016ULL, 0x006bffc10016006bULL, }, - { 0xff71001bffc6ff71ULL, 0x001bffc6ff71001bULL, }, - { 0x00540054ff550054ULL, 0x0054ff5500540054ULL, }, - { 0x001bffc60070001bULL, 0xffc60070001bffc6ULL, }, /* 56 */ - { 0x001cffc70071001cULL, 0xffc70071001cffc7ULL, }, - { 0xffc6ff71001bffc6ULL, 0xff71001bffc6ff71ULL, }, - { 0x0071001c00c60071ULL, 0x001c00c60071001cULL, }, - { 0xffe8ff93003dffe8ULL, 0xff93003dffe8ff93ULL, }, - { 0x004ffffa00a4004fULL, 0xfffa00a4004ffffaULL, }, - { 0xffaaffaa00a9ffaaULL, 0xffaa00a9ffaaffaaULL, }, - { 0x008dffe30038008dULL, 0xffe30038008dffe3ULL, }, - { 0xfff2ffb2008a0095ULL, 0x00b200690079ffbcULL, }, /* 64 */ - { 0xff460049ffbb005dULL, 0x00420025003dffacULL, }, - { 0xffe2ff90fff7ffd5ULL, 0x0023000a0029ffc4ULL, }, - { 0xffd70033005900a3ULL, 0x003cffe30040ff50ULL, }, - { 0x0065ffcc00af0007ULL, 0x007900190090005eULL, }, - { 0xffb90063ffe0ffcfULL, 0x0009ffd50054004eULL, }, - { 0x0055ffaa001cff47ULL, 0xffeaffba00400066ULL, }, - { 0x004a004d007e0015ULL, 0x0003ff930057fff2ULL, }, - { 0x0016ff7a001bffcbULL, 0x008e002400260031ULL, }, /* 72 */ - { 0xff6a0011ff4cff93ULL, 0x001effe0ffea0021ULL, }, - { 0x0006ff58ff88ff0bULL, 0xffffffc5ffd60039ULL, }, - { 0xfffbfffbffeaffd9ULL, 0x0018ff9effedffc5ULL, }, - { 0x00daffe200c00022ULL, 0xfff4ffe60024ffeeULL, }, - { 0x002e0079fff1ffeaULL, 0xff84ffa2ffe8ffdeULL, }, - { 0x00caffc0002dff62ULL, 0xff65ff87ffd4fff6ULL, }, - { 0x00bf0063008f0030ULL, 0xff7eff60ffebff82ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_w.c deleted file mode 100644 index 3589c33940d0..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HADD_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "HADD_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffaaa9ffffaaa9ULL, 0xffffaaa9ffffaaa9ULL, }, - { 0x0000555400005554ULL, 0x0000555400005554ULL, }, - { 0xffffcccbffffcccbULL, 0xffffcccbffffcccbULL, }, - { 0x0000333200003332ULL, 0x0000333200003332ULL, }, - { 0x000038e2ffffe38dULL, 0xffff8e37000038e2ULL, }, - { 0xffffc71b00001c70ULL, 0x000071c6ffffc71bULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x000038e3ffffe38eULL, 0xffff8e38000038e3ULL, }, - { 0xffffc71c00001c71ULL, 0x000071c7ffffc71cULL, }, - { 0xffffaaa9ffffaaa9ULL, 0xffffaaa9ffffaaa9ULL, }, /* 16 */ - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0xffff5554ffff5554ULL, 0xffff5554ffff5554ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffff7776ffff7776ULL, 0xffff7776ffff7776ULL, }, - { 0xffffddddffffddddULL, 0xffffddddffffddddULL, }, - { 0xffffe38dffff8e38ULL, 0xffff38e2ffffe38dULL, }, - { 0xffff71c6ffffc71bULL, 0x00001c71ffff71c6ULL, }, - { 0x0000555400005554ULL, 0x0000555400005554ULL, }, /* 24 */ - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000222100002221ULL, 0x0000222100002221ULL, }, - { 0x0000888800008888ULL, 0x0000888800008888ULL, }, - { 0x00008e38000038e3ULL, 0xffffe38d00008e38ULL, }, - { 0x00001c71000071c6ULL, 0x0000c71c00001c71ULL, }, - { 0xffffcccbffffcccbULL, 0xffffcccbffffcccbULL, }, /* 32 */ - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0xffff7776ffff7776ULL, 0xffff7776ffff7776ULL, }, - { 0x0000222100002221ULL, 0x0000222100002221ULL, }, - { 0xffff9998ffff9998ULL, 0xffff9998ffff9998ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x000005afffffb05aULL, 0xffff5b04000005afULL, }, - { 0xffff93e8ffffe93dULL, 0x00003e93ffff93e8ULL, }, - { 0x0000333200003332ULL, 0x0000333200003332ULL, }, /* 40 */ - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0xffffddddffffddddULL, 0xffffddddffffddddULL, }, - { 0x0000888800008888ULL, 0x0000888800008888ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000666600006666ULL, 0x0000666600006666ULL, }, - { 0x00006c16000016c1ULL, 0xffffc16b00006c16ULL, }, - { 0xfffffa4f00004fa4ULL, 0x0000a4fafffffa4fULL, }, - { 0xffffe38dffff8e37ULL, 0x000038e2ffffe38dULL, }, /* 48 */ - { 0xffffe38effff8e38ULL, 0x000038e3ffffe38eULL, }, - { 0xffff8e38ffff38e2ULL, 0xffffe38dffff8e38ULL, }, - { 0x000038e3ffffe38dULL, 0x00008e38000038e3ULL, }, - { 0xffffb05affff5b04ULL, 0x000005afffffb05aULL, }, - { 0x000016c1ffffc16bULL, 0x00006c16000016c1ULL, }, - { 0x00001c71ffff71c6ULL, 0xffffc71b00001c71ULL, }, - { 0xffffaaaaffffaaa9ULL, 0x0000aaaaffffaaaaULL, }, - { 0x00001c70000071c6ULL, 0xffffc71b00001c70ULL, }, /* 56 */ - { 0x00001c71000071c7ULL, 0xffffc71c00001c71ULL, }, - { 0xffffc71b00001c71ULL, 0xffff71c6ffffc71bULL, }, - { 0x000071c60000c71cULL, 0x00001c71000071c6ULL, }, - { 0xffffe93d00003e93ULL, 0xffff93e8ffffe93dULL, }, - { 0x00004fa40000a4faULL, 0xfffffa4f00004fa4ULL, }, - { 0x0000555400005555ULL, 0xffff555400005554ULL, }, - { 0xffffe38d00008e38ULL, 0x000038e3ffffe38dULL, }, - { 0xffff6f3600007da2ULL, 0x000056c5ffffae87ULL, }, /* 64 */ - { 0xffff88cdffffef6aULL, 0x0000068100005177ULL, }, - { 0xffff3714ffffb3e2ULL, 0x000012660000238fULL, }, - { 0xffff9eb700000ab0ULL, 0xffffd43fffffe11bULL, }, - { 0xffffe28a0000a2d3ULL, 0x00001e55ffffc54bULL, }, - { 0xfffffc210000149bULL, 0xffffce110000683bULL, }, - { 0xffffaa68ffffd913ULL, 0xffffd9f600003a53ULL, }, - { 0x0000120b00002fe1ULL, 0xffff9bcffffff7dfULL, }, - { 0xffff932600000f0fULL, 0x00003336ffff5b37ULL, }, /* 72 */ - { 0xffffacbdffff80d7ULL, 0xffffe2f2fffffe27ULL, }, - { 0xffff5b04ffff454fULL, 0xffffeed7ffffd03fULL, }, - { 0xffffc2a7ffff9c1dULL, 0xffffb0b0ffff8dcbULL, }, - { 0x0000571b0000b371ULL, 0xffff994fffff594eULL, }, - { 0x000070b200002539ULL, 0xffff490bfffffc3eULL, }, - { 0x00001ef9ffffe9b1ULL, 0xffff54f0ffffce56ULL, }, - { 0x0000869c0000407fULL, 0xffff16c9ffff8be2ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_d.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_d.c deleted file mode 100644 index 35b2021347a4..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HADD_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "HADD_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x00000001fffffffeULL, 0x00000001fffffffeULL, }, /* 0 */ - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, - { 0x00000001aaaaaaa9ULL, 0x00000001aaaaaaa9ULL, }, - { 0x0000000155555554ULL, 0x0000000155555554ULL, }, - { 0x00000001cccccccbULL, 0x00000001cccccccbULL, }, - { 0x0000000133333332ULL, 0x0000000133333332ULL, }, - { 0x000000018e38e38dULL, 0x00000001e38e38e2ULL, }, - { 0x0000000171c71c70ULL, 0x000000011c71c71bULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x000000008e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0x00000001aaaaaaa9ULL, 0x00000001aaaaaaa9ULL, }, /* 16 */ - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000155555554ULL, 0x0000000155555554ULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000177777776ULL, 0x0000000177777776ULL, }, - { 0x00000000ddddddddULL, 0x00000000ddddddddULL, }, - { 0x0000000138e38e38ULL, 0x000000018e38e38dULL, }, - { 0x000000011c71c71bULL, 0x00000000c71c71c6ULL, }, - { 0x0000000155555554ULL, 0x0000000155555554ULL, }, /* 24 */ - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000122222221ULL, 0x0000000122222221ULL, }, - { 0x0000000088888888ULL, 0x0000000088888888ULL, }, - { 0x00000000e38e38e3ULL, 0x0000000138e38e38ULL, }, - { 0x00000000c71c71c6ULL, 0x0000000071c71c71ULL, }, - { 0x00000001cccccccbULL, 0x00000001cccccccbULL, }, /* 32 */ - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000177777776ULL, 0x0000000177777776ULL, }, - { 0x0000000122222221ULL, 0x0000000122222221ULL, }, - { 0x0000000199999998ULL, 0x0000000199999998ULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, - { 0x000000015b05b05aULL, 0x00000001b05b05afULL, }, - { 0x000000013e93e93dULL, 0x00000000e93e93e8ULL, }, - { 0x0000000133333332ULL, 0x0000000133333332ULL, }, /* 40 */ - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x00000000ddddddddULL, 0x00000000ddddddddULL, }, - { 0x0000000088888888ULL, 0x0000000088888888ULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000066666666ULL, 0x0000000066666666ULL, }, - { 0x00000000c16c16c1ULL, 0x0000000116c16c16ULL, }, - { 0x00000000a4fa4fa4ULL, 0x000000004fa4fa4fULL, }, - { 0x00000001e38e38e2ULL, 0x0000000138e38e37ULL, }, /* 48 */ - { 0x00000000e38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0x000000018e38e38dULL, 0x00000000e38e38e2ULL, }, - { 0x0000000138e38e38ULL, 0x000000008e38e38dULL, }, - { 0x00000001b05b05afULL, 0x0000000105b05b04ULL, }, - { 0x0000000116c16c16ULL, 0x000000006c16c16bULL, }, - { 0x0000000171c71c71ULL, 0x000000011c71c71bULL, }, - { 0x0000000155555554ULL, 0x0000000055555554ULL, }, - { 0x000000011c71c71bULL, 0x00000001c71c71c6ULL, }, /* 56 */ - { 0x000000001c71c71cULL, 0x00000000c71c71c7ULL, }, - { 0x00000000c71c71c6ULL, 0x0000000171c71c71ULL, }, - { 0x0000000071c71c71ULL, 0x000000011c71c71cULL, }, - { 0x00000000e93e93e8ULL, 0x0000000193e93e93ULL, }, - { 0x000000004fa4fa4fULL, 0x00000000fa4fa4faULL, }, - { 0x00000000aaaaaaaaULL, 0x00000001aaaaaaaaULL, }, - { 0x000000008e38e38dULL, 0x00000000e38e38e3ULL, }, - { 0x00000000b0cd3c0cULL, 0x0000000149e2bb6aULL, }, /* 64 */ - { 0x00000000d5feadd4ULL, 0x0000000060a65e5aULL, }, - { 0x00000001423a724cULL, 0x00000000f6923072ULL, }, - { 0x00000000e69cc91aULL, 0x00000000f4a9edfeULL, }, - { 0x00000001242055a3ULL, 0x0000000111736b26ULL, }, - { 0x000000014951c76bULL, 0x0000000028370e16ULL, }, - { 0x00000001b58d8be3ULL, 0x00000000be22e02eULL, }, - { 0x0000000159efe2b1ULL, 0x00000000bc3a9dbaULL, }, - { 0x00000000d4bd03eaULL, 0x000000012654770bULL, }, /* 72 */ - { 0x00000000f9ee75b2ULL, 0x000000003d1819fbULL, }, - { 0x00000001662a3a2aULL, 0x00000000d303ec13ULL, }, - { 0x000000010a8c90f8ULL, 0x00000000d11ba99fULL, }, - { 0x0000000098b16b8dULL, 0x000000018c6d38e4ULL, }, - { 0x00000000bde2dd55ULL, 0x00000000a330dbd4ULL, }, - { 0x000000012a1ea1cdULL, 0x00000001391cadecULL, }, - { 0x00000000ce80f89bULL, 0x0000000137346b78ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_h.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_h.c deleted file mode 100644 index 3b38f9bb33f8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HADD_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "HADD_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x01fe01fe01fe01feULL, 0x01fe01fe01fe01feULL, }, /* 0 */ - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0x01a901a901a901a9ULL, 0x01a901a901a901a9ULL, }, - { 0x0154015401540154ULL, 0x0154015401540154ULL, }, - { 0x01cb01cb01cb01cbULL, 0x01cb01cb01cb01cbULL, }, - { 0x0132013201320132ULL, 0x0132013201320132ULL, }, - { 0x018d01e20137018dULL, 0x01e20137018d01e2ULL, }, - { 0x0170011b01c60170ULL, 0x011b01c60170011bULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x008e00e30038008eULL, 0x00e30038008e00e3ULL, }, - { 0x0071001c00c70071ULL, 0x001c00c70071001cULL, }, - { 0x01a901a901a901a9ULL, 0x01a901a901a901a9ULL, }, /* 16 */ - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0154015401540154ULL, 0x0154015401540154ULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0x0176017601760176ULL, 0x0176017601760176ULL, }, - { 0x00dd00dd00dd00ddULL, 0x00dd00dd00dd00ddULL, }, - { 0x0138018d00e20138ULL, 0x018d00e20138018dULL, }, - { 0x011b00c60171011bULL, 0x00c60171011b00c6ULL, }, - { 0x0154015401540154ULL, 0x0154015401540154ULL, }, /* 24 */ - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0121012101210121ULL, 0x0121012101210121ULL, }, - { 0x0088008800880088ULL, 0x0088008800880088ULL, }, - { 0x00e30138008d00e3ULL, 0x0138008d00e30138ULL, }, - { 0x00c60071011c00c6ULL, 0x0071011c00c60071ULL, }, - { 0x01cb01cb01cb01cbULL, 0x01cb01cb01cb01cbULL, }, /* 32 */ - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0176017601760176ULL, 0x0176017601760176ULL, }, - { 0x0121012101210121ULL, 0x0121012101210121ULL, }, - { 0x0198019801980198ULL, 0x0198019801980198ULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0x015a01af0104015aULL, 0x01af0104015a01afULL, }, - { 0x013d00e80193013dULL, 0x00e80193013d00e8ULL, }, - { 0x0132013201320132ULL, 0x0132013201320132ULL, }, /* 40 */ - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x00dd00dd00dd00ddULL, 0x00dd00dd00dd00ddULL, }, - { 0x0088008800880088ULL, 0x0088008800880088ULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0x0066006600660066ULL, 0x0066006600660066ULL, }, - { 0x00c10116006b00c1ULL, 0x0116006b00c10116ULL, }, - { 0x00a4004f00fa00a4ULL, 0x004f00fa00a4004fULL, }, - { 0x01e20137018d01e2ULL, 0x0137018d01e20137ULL, }, /* 48 */ - { 0x00e30038008e00e3ULL, 0x0038008e00e30038ULL, }, - { 0x018d00e20138018dULL, 0x00e20138018d00e2ULL, }, - { 0x0138008d00e30138ULL, 0x008d00e30138008dULL, }, - { 0x01af0104015a01afULL, 0x0104015a01af0104ULL, }, - { 0x0116006b00c10116ULL, 0x006b00c10116006bULL, }, - { 0x0171011b00c60171ULL, 0x011b00c60171011bULL, }, - { 0x0154005401550154ULL, 0x0054015501540054ULL, }, - { 0x011b01c60170011bULL, 0x01c60170011b01c6ULL, }, /* 56 */ - { 0x001c00c70071001cULL, 0x00c70071001c00c7ULL, }, - { 0x00c60171011b00c6ULL, 0x0171011b00c60171ULL, }, - { 0x0071011c00c60071ULL, 0x011c00c60071011cULL, }, - { 0x00e80193013d00e8ULL, 0x0193013d00e80193ULL, }, - { 0x004f00fa00a4004fULL, 0x00fa00a4004f00faULL, }, - { 0x00aa01aa00a900aaULL, 0x01aa00a900aa01aaULL, }, - { 0x008d00e30138008dULL, 0x00e30138008d00e3ULL, }, - { 0x00f201b2008a0095ULL, 0x00b20069017900bcULL, }, /* 64 */ - { 0x0146014900bb005dULL, 0x01420025013d01acULL, }, - { 0x00e2019000f700d5ULL, 0x0123010a012900c4ULL, }, - { 0x00d70133005900a3ULL, 0x013c00e301400150ULL, }, - { 0x016500cc00af0107ULL, 0x007901190090005eULL, }, - { 0x01b9006300e000cfULL, 0x010900d50054014eULL, }, - { 0x015500aa011c0147ULL, 0x00ea01ba00400066ULL, }, - { 0x014a004d007e0115ULL, 0x01030193005700f2ULL, }, - { 0x0116017a011b00cbULL, 0x008e012401260031ULL, }, /* 72 */ - { 0x016a0111014c0093ULL, 0x011e00e000ea0121ULL, }, - { 0x010601580188010bULL, 0x00ff01c500d60039ULL, }, - { 0x00fb00fb00ea00d9ULL, 0x0118019e00ed00c5ULL, }, - { 0x00da00e200c00122ULL, 0x00f400e6012400eeULL, }, - { 0x012e007900f100eaULL, 0x018400a200e801deULL, }, - { 0x00ca00c0012d0162ULL, 0x0165018700d400f6ULL, }, - { 0x00bf0063008f0130ULL, 0x017e016000eb0182ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_w.c b/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_w.c deleted file mode 100644 index fd420cb8de7a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-add/test_msa_hadd_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HADD_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Add"; - char *instruction_name = "HADD_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0001fffe0001fffeULL, 0x0001fffe0001fffeULL, }, /* 0 */ - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0x0001aaa90001aaa9ULL, 0x0001aaa90001aaa9ULL, }, - { 0x0001555400015554ULL, 0x0001555400015554ULL, }, - { 0x0001cccb0001cccbULL, 0x0001cccb0001cccbULL, }, - { 0x0001333200013332ULL, 0x0001333200013332ULL, }, - { 0x000138e20001e38dULL, 0x00018e37000138e2ULL, }, - { 0x0001c71b00011c70ULL, 0x000171c60001c71bULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x000038e30000e38eULL, 0x00008e38000038e3ULL, }, - { 0x0000c71c00001c71ULL, 0x000071c70000c71cULL, }, - { 0x0001aaa90001aaa9ULL, 0x0001aaa90001aaa9ULL, }, /* 16 */ - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0001555400015554ULL, 0x0001555400015554ULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0x0001777600017776ULL, 0x0001777600017776ULL, }, - { 0x0000dddd0000ddddULL, 0x0000dddd0000ddddULL, }, - { 0x0000e38d00018e38ULL, 0x000138e20000e38dULL, }, - { 0x000171c60000c71bULL, 0x00011c71000171c6ULL, }, - { 0x0001555400015554ULL, 0x0001555400015554ULL, }, /* 24 */ - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0001222100012221ULL, 0x0001222100012221ULL, }, - { 0x0000888800008888ULL, 0x0000888800008888ULL, }, - { 0x00008e38000138e3ULL, 0x0000e38d00008e38ULL, }, - { 0x00011c71000071c6ULL, 0x0000c71c00011c71ULL, }, - { 0x0001cccb0001cccbULL, 0x0001cccb0001cccbULL, }, /* 32 */ - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0001777600017776ULL, 0x0001777600017776ULL, }, - { 0x0001222100012221ULL, 0x0001222100012221ULL, }, - { 0x0001999800019998ULL, 0x0001999800019998ULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0x000105af0001b05aULL, 0x00015b04000105afULL, }, - { 0x000193e80000e93dULL, 0x00013e93000193e8ULL, }, - { 0x0001333200013332ULL, 0x0001333200013332ULL, }, /* 40 */ - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x0000dddd0000ddddULL, 0x0000dddd0000ddddULL, }, - { 0x0000888800008888ULL, 0x0000888800008888ULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0x0000666600006666ULL, 0x0000666600006666ULL, }, - { 0x00006c16000116c1ULL, 0x0000c16b00006c16ULL, }, - { 0x0000fa4f00004fa4ULL, 0x0000a4fa0000fa4fULL, }, - { 0x0001e38d00018e37ULL, 0x000138e20001e38dULL, }, /* 48 */ - { 0x0000e38e00008e38ULL, 0x000038e30000e38eULL, }, - { 0x00018e38000138e2ULL, 0x0000e38d00018e38ULL, }, - { 0x000138e30000e38dULL, 0x00008e38000138e3ULL, }, - { 0x0001b05a00015b04ULL, 0x000105af0001b05aULL, }, - { 0x000116c10000c16bULL, 0x00006c16000116c1ULL, }, - { 0x00011c71000171c6ULL, 0x0000c71b00011c71ULL, }, - { 0x0001aaaa0000aaa9ULL, 0x0000aaaa0001aaaaULL, }, - { 0x00011c70000171c6ULL, 0x0001c71b00011c70ULL, }, /* 56 */ - { 0x00001c71000071c7ULL, 0x0000c71c00001c71ULL, }, - { 0x0000c71b00011c71ULL, 0x000171c60000c71bULL, }, - { 0x000071c60000c71cULL, 0x00011c71000071c6ULL, }, - { 0x0000e93d00013e93ULL, 0x000193e80000e93dULL, }, - { 0x00004fa40000a4faULL, 0x0000fa4f00004fa4ULL, }, - { 0x0000555400015555ULL, 0x0001555400005554ULL, }, - { 0x0000e38d00008e38ULL, 0x000138e30000e38dULL, }, - { 0x00016f3600007da2ULL, 0x000056c50001ae87ULL, }, /* 64 */ - { 0x000088cd0000ef6aULL, 0x0001068100015177ULL, }, - { 0x000137140000b3e2ULL, 0x000112660001238fULL, }, - { 0x00009eb700010ab0ULL, 0x0000d43f0001e11bULL, }, - { 0x0001e28a0000a2d3ULL, 0x00001e550000c54bULL, }, - { 0x0000fc210001149bULL, 0x0000ce110000683bULL, }, - { 0x0001aa680000d913ULL, 0x0000d9f600003a53ULL, }, - { 0x0001120b00012fe1ULL, 0x00009bcf0000f7dfULL, }, - { 0x0001932600010f0fULL, 0x0000333600015b37ULL, }, /* 72 */ - { 0x0000acbd000180d7ULL, 0x0000e2f20000fe27ULL, }, - { 0x00015b040001454fULL, 0x0000eed70000d03fULL, }, - { 0x0000c2a700019c1dULL, 0x0000b0b000018dcbULL, }, - { 0x0001571b0000b371ULL, 0x0000994f0001594eULL, }, - { 0x000070b200012539ULL, 0x0001490b0000fc3eULL, }, - { 0x00011ef90000e9b1ULL, 0x000154f00000ce56ULL, }, - { 0x0000869c0001407fULL, 0x000116c900018be2ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HADD_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_b.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_b.c deleted file mode 100644 index 14ee4ab4db91..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd4d4d4d4d4d4d4d4ULL, 0xd4d4d4d4d4d4d4d4ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0xe5e5e5e5e5e5e5e5ULL, 0xe5e5e5e5e5e5e5e5ULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0xf1c61bf1c61bf1c6ULL, 0x1bf1c61bf1c61bf1ULL, }, - { 0x0d38e30d38e30d38ULL, 0xe30d38e30d38e30dULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0xf1c71cf1c71cf1c7ULL, 0x1cf1c71cf1c71cf1ULL, }, - { 0x0e38e30e38e30e38ULL, 0xe30e38e30e38e30eULL, }, - { 0xd4d4d4d4d4d4d4d4ULL, 0xd4d4d4d4d4d4d4d4ULL, }, /* 16 */ - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0xc69cf1c69cf1c69cULL, 0xf1c69cf1c69cf1c6ULL, }, - { 0xe30db8e30db8e30dULL, 0xb8e30db8e30db8e3ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, /* 24 */ - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1010101010101010ULL, 0x1010101010101010ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1cf1461cf1461cf1ULL, 0x461cf1461cf1461cULL, }, - { 0x38630e38630e3863ULL, 0x0e38630e38630e38ULL, }, - { 0xe5e5e5e5e5e5e5e5ULL, 0xe5e5e5e5e5e5e5e5ULL, }, /* 32 */ - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1010101010101010ULL, 0x1010101010101010ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd7ad02d7ad02d7adULL, 0x02d7ad02d7ad02d7ULL, }, - { 0xf41ec9f41ec9f41eULL, 0xc9f41ec9f41ec9f4ULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, /* 40 */ - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0be0350be0350be0ULL, 0x350be0350be0350bULL, }, - { 0x2752fd2752fd2752ULL, 0xfd2752fd2752fd27ULL, }, - { 0xf1c61bf1c61bf1c6ULL, 0x1bf1c61bf1c61bf1ULL, }, /* 48 */ - { 0xf1c71cf1c71cf1c7ULL, 0x1cf1c71cf1c71cf1ULL, }, - { 0xc69cf1c69cf1c69cULL, 0xf1c69cf1c69cf1c6ULL, }, - { 0x1cf1461cf1461cf1ULL, 0x461cf1461cf1461cULL, }, - { 0xd7ad02d7ad02d7adULL, 0x02d7ad02d7ad02d7ULL, }, - { 0x0be0350be0350be0ULL, 0x350be0350be0350bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0d38e30d38e30d38ULL, 0xe30d38e30d38e30dULL, }, /* 56 */ - { 0x0e38e30e38e30e38ULL, 0xe30e38e30e38e30eULL, }, - { 0xe30db8e30db8e30dULL, 0xb8e30db8e30db8e3ULL, }, - { 0x38630e38630e3863ULL, 0x0e38630e38630e38ULL, }, - { 0xf41ec9f41ec9f41eULL, 0xc9f41ec9f41ec9f4ULL, }, - { 0x2752fd2752fd2752ULL, 0xfd2752fd2752fd27ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc114f3173afa0e24ULL, 0x2e2fe33c095d0104ULL, }, - { 0x9a62cabbf018f0e0ULL, 0x391fe82ed453ea10ULL, }, - { 0xfc5cfe0c43491b47ULL, 0xec2cc91bd35ec9d6ULL, }, - { 0xc114f3173afa0e24ULL, 0x2e2fe33c095d0104ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd30cd70603b1a9c4ULL, 0x1ce7c00ce0353b08ULL, }, - { 0x35060b5855e2d42bULL, 0xcff4a1f9df401aceULL, }, - { 0x9a62cabbf018f0e0ULL, 0x391fe82ed453ea10ULL, }, /* 72 */ - { 0xd30cd70603b1a9c4ULL, 0x1ce7c00ce0353b08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e54e2fb0b00b6e7ULL, 0xdae4a7ebaa3603daULL, }, - { 0xfc5cfe0c43491b47ULL, 0xec2cc91bd35ec9d6ULL, }, - { 0x35060b5855e2d42bULL, 0xcff4a1f9df401aceULL, }, - { 0x0e54e2fb0b00b6e7ULL, 0xdae4a7ebaa3603daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_d.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_d.c deleted file mode 100644 index ae7b3c8b8922..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd555555555555554ULL, 0xd555555555555554ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, - { 0xe666666666666665ULL, 0xe666666666666665ULL, }, - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e38e38e38eULL, }, - { 0xd555555555555554ULL, 0xd555555555555554ULL, }, /* 16 */ - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0xc71c71c71c71c71cULL, 0xf1c71c71c71c71c6ULL, }, - { 0xe38e38e38e38e38dULL, 0xb8e38e38e38e38e3ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1111111111111110ULL, 0x1111111111111110ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0x0e38e38e38e38e38ULL, }, - { 0xe666666666666665ULL, 0xe666666666666665ULL, }, /* 32 */ - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1111111111111110ULL, 0x1111111111111110ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd82d82d82d82d82dULL, 0x02d82d82d82d82d7ULL, }, - { 0xf49f49f49f49f49eULL, 0xc9f49f49f49f49f4ULL, }, - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, /* 40 */ - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0b60b60b60b60b60ULL, 0x360b60b60b60b60bULL, }, - { 0x27d27d27d27d27d2ULL, 0xfd27d27d27d27d27ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x1c71c71c71c71c71ULL, }, /* 48 */ - { 0xf1c71c71c71c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0xc71c71c71c71c71cULL, 0xf1c71c71c71c71c6ULL, }, - { 0x1c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, - { 0xd82d82d82d82d82dULL, 0x02d82d82d82d82d7ULL, }, - { 0x0b60b60b60b60b60ULL, 0x360b60b60b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, /* 56 */ - { 0x0e38e38e38e38e38ULL, 0xe38e38e38e38e38eULL, }, - { 0xe38e38e38e38e38dULL, 0xb8e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x0e38e38e38e38e38ULL, }, - { 0xf49f49f49f49f49eULL, 0xc9f49f49f49f49f4ULL, }, - { 0x27d27d27d27d27d2ULL, 0xfd27d27d27d27d27ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, - { 0xfc5cfe8cc34a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f95f411aceULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, /* 72 */ - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e54e27c0c00b6e7ULL, 0xdae527ec2a3703daULL, }, - { 0xfc5cfe8cc34a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f95f411aceULL, }, - { 0x0e54e27c0c00b6e7ULL, 0xdae527ec2a3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_h.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_h.c deleted file mode 100644 index d0d327e80f08..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd554d554d554d554ULL, 0xd554d554d554d554ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, - { 0xe665e665e665e665ULL, 0xe665e665e665e665ULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0xf1c61c71c71bf1c6ULL, 0x1c71c71bf1c61c71ULL, }, - { 0x0e38e38d38e30e38ULL, 0xe38d38e30e38e38dULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0xf1c71c71c71cf1c7ULL, 0x1c71c71cf1c71c71ULL, }, - { 0x0e38e38e38e30e38ULL, 0xe38e38e30e38e38eULL, }, - { 0xd554d554d554d554ULL, 0xd554d554d554d554ULL, }, /* 16 */ - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0xc71cf1c69c71c71cULL, 0xf1c69c71c71cf1c6ULL, }, - { 0xe38db8e30e38e38dULL, 0xb8e30e38e38db8e3ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, /* 24 */ - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1110111011101110ULL, 0x1110111011101110ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1c71471cf1c61c71ULL, 0x471cf1c61c71471cULL, }, - { 0x38e30e38638e38e3ULL, 0x0e38638e38e30e38ULL, }, - { 0xe665e665e665e665ULL, 0xe665e665e665e665ULL, }, /* 32 */ - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1110111011101110ULL, 0x1110111011101110ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd82d02d7ad82d82dULL, 0x02d7ad82d82d02d7ULL, }, - { 0xf49ec9f41f49f49eULL, 0xc9f41f49f49ec9f4ULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, /* 40 */ - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0b60360be0b50b60ULL, 0x360be0b50b60360bULL, }, - { 0x27d2fd27527d27d2ULL, 0xfd27527d27d2fd27ULL, }, - { 0xf1c61c71c71bf1c6ULL, 0x1c71c71bf1c61c71ULL, }, /* 48 */ - { 0xf1c71c71c71cf1c7ULL, 0x1c71c71cf1c71c71ULL, }, - { 0xc71cf1c69c71c71cULL, 0xf1c69c71c71cf1c6ULL, }, - { 0x1c71471cf1c61c71ULL, 0x471cf1c61c71471cULL, }, - { 0xd82d02d7ad82d82dULL, 0x02d7ad82d82d02d7ULL, }, - { 0x0b60360be0b50b60ULL, 0x360be0b50b60360bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0e38e38d38e30e38ULL, 0xe38d38e30e38e38dULL, }, /* 56 */ - { 0x0e38e38e38e30e38ULL, 0xe38e38e30e38e38eULL, }, - { 0xe38db8e30e38e38dULL, 0xb8e30e38e38db8e3ULL, }, - { 0x38e30e38638e38e3ULL, 0x0e38638e38e30e38ULL, }, - { 0xf49ec9f41f49f49eULL, 0xc9f41f49f49ec9f4ULL, }, - { 0x27d2fd27527d27d2ULL, 0xfd27527d27d2fd27ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc214f3973afa0e24ULL, 0x2f2fe33c09dd0184ULL, }, - { 0x9a62cabbf118f060ULL, 0x399fe92ed4d3ea90ULL, }, - { 0xfc5cfe8c43491bc7ULL, 0xecacca1bd3dec956ULL, }, - { 0xc214f3973afa0e24ULL, 0x2f2fe33c09dd0184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40cd78603b1a944ULL, 0x1d67c10ce0353c08ULL, }, - { 0x36060b5855e2d4abULL, 0xd074a1f9df401aceULL, }, - { 0x9a62cabbf118f060ULL, 0x399fe92ed4d3ea90ULL, }, /* 72 */ - { 0xd40cd78603b1a944ULL, 0x1d67c10ce0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e54e27b0c00b6e7ULL, 0xdae4a7ebaa3603daULL, }, - { 0xfc5cfe8c43491bc7ULL, 0xecacca1bd3dec956ULL, }, - { 0x36060b5855e2d4abULL, 0xd074a1f9df401aceULL, }, - { 0x0e54e27b0c00b6e7ULL, 0xdae4a7ebaa3603daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_w.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_w.c deleted file mode 100644 index 77010209fb8b..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd5555554d5555554ULL, 0xd5555554d5555554ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, - { 0xe6666665e6666665ULL, 0xe6666665e6666665ULL, }, - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x1c71c71bf1c71c71ULL, }, - { 0x0e38e38d38e38e38ULL, 0xe38e38e30e38e38dULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71cf1c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e30e38e38eULL, }, - { 0xd5555554d5555554ULL, 0xd5555554d5555554ULL, }, /* 16 */ - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0xc71c71c69c71c71cULL, 0xf1c71c71c71c71c6ULL, }, - { 0xe38e38e30e38e38dULL, 0xb8e38e38e38e38e3ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, /* 24 */ - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1111111011111110ULL, 0x1111111011111110ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1c71c71cf1c71c71ULL, 0x471c71c61c71c71cULL, }, - { 0x38e38e38638e38e3ULL, 0x0e38e38e38e38e38ULL, }, - { 0xe6666665e6666665ULL, 0xe6666665e6666665ULL, }, /* 32 */ - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1111111011111110ULL, 0x1111111011111110ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xd82d82d7ad82d82dULL, 0x02d82d82d82d82d7ULL, }, - { 0xf49f49f41f49f49eULL, 0xc9f49f49f49f49f4ULL, }, - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, /* 40 */ - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0b60b60be0b60b60ULL, 0x360b60b50b60b60bULL, }, - { 0x27d27d27527d27d2ULL, 0xfd27d27d27d27d27ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x1c71c71bf1c71c71ULL, }, /* 48 */ - { 0xf1c71c71c71c71c7ULL, 0x1c71c71cf1c71c71ULL, }, - { 0xc71c71c69c71c71cULL, 0xf1c71c71c71c71c6ULL, }, - { 0x1c71c71cf1c71c71ULL, 0x471c71c61c71c71cULL, }, - { 0xd82d82d7ad82d82dULL, 0x02d82d82d82d82d7ULL, }, - { 0x0b60b60be0b60b60ULL, 0x360b60b50b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0e38e38d38e38e38ULL, 0xe38e38e30e38e38dULL, }, /* 56 */ - { 0x0e38e38e38e38e38ULL, 0xe38e38e30e38e38eULL, }, - { 0xe38e38e30e38e38dULL, 0xb8e38e38e38e38e3ULL, }, - { 0x38e38e38638e38e3ULL, 0x0e38e38e38e38e38ULL, }, - { 0xf49f49f41f49f49eULL, 0xc9f49f49f49f49f4ULL, }, - { 0x27d27d27527d27d2ULL, 0xfd27d27d27d27d27ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc21473973afb0e24ULL, 0x2f2f633c09dd8184ULL, }, - { 0x9a62cabbf118f060ULL, 0x399fe92ed4d36a90ULL, }, - { 0xfc5cfe8c434a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0xc21473973afb0e24ULL, 0x2f2f633c09dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578603b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f9df411aceULL, }, - { 0x9a62cabbf118f060ULL, 0x399fe92ed4d36a90ULL, }, /* 72 */ - { 0xd40c578603b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e54e27b0c00b6e7ULL, 0xdae527ebaa3703daULL, }, - { 0xfc5cfe8c434a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f9df411aceULL, }, - { 0x0e54e27b0c00b6e7ULL, 0xdae527ebaa3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_b.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_b.c deleted file mode 100644 index c9e834e74d65..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0xd4d4d4d4d4d4d4d4ULL, 0xd4d4d4d4d4d4d4d4ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe5e5e5e5e5e5e5e5ULL, 0xe5e5e5e5e5e5e5e5ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c69bf1c69bf1c6ULL, 0x9bf1c69bf1c69bf1ULL, }, - { 0x8db8e38db8e38db8ULL, 0xe38db8e38db8e38dULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0x71471c71471c7147ULL, 0x1c71471c71471c71ULL, }, - { 0x0e38630e38630e38ULL, 0x630e38630e38630eULL, }, - { 0xd4d4d4d4d4d4d4d4ULL, 0xd4d4d4d4d4d4d4d4ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6e6e6e6e6e6e6e6eULL, 0x6e6e6e6e6e6e6e6eULL, }, - { 0xc69c71c69c71c69cULL, 0x71c69c71c69c71c6ULL, }, - { 0x638db8638db8638dULL, 0xb8638db8638db863ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9090909090909090ULL, 0x9090909090909090ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c71469c71469c71ULL, 0x469c71469c71469cULL, }, - { 0x38638e38638e3863ULL, 0x8e38638e38638e38ULL, }, - { 0xe5e5e5e5e5e5e5e5ULL, 0xe5e5e5e5e5e5e5e5ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9090909090909090ULL, 0x9090909090909090ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0xd7ad82d7ad82d7adULL, 0x82d7ad82d7ad82d7ULL, }, - { 0x749ec9749ec9749eULL, 0xc9749ec9749ec974ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0x6e6e6e6e6e6e6e6eULL, 0x6e6e6e6e6e6e6e6eULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b60358b60358b60ULL, 0x358b60358b60358bULL, }, - { 0x27527d27527d2752ULL, 0x7d27527d27527d27ULL, }, - { 0xf1c69bf1c69bf1c6ULL, 0x9bf1c69bf1c69bf1ULL, }, /* 48 */ - { 0x71471c71471c7147ULL, 0x1c71471c71471c71ULL, }, - { 0xc69c71c69c71c69cULL, 0x71c69c71c69c71c6ULL, }, - { 0x9c71469c71469c71ULL, 0x469c71469c71469cULL, }, - { 0xd7ad82d7ad82d7adULL, 0x82d7ad82d7ad82d7ULL, }, - { 0x8b60358b60358b60ULL, 0x358b60358b60358bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x8db8e38db8e38db8ULL, 0xe38db8e38db8e38dULL, }, /* 56 */ - { 0x0e38630e38630e38ULL, 0x630e38630e38630eULL, }, - { 0x638db8638db8638dULL, 0xb8638db8638db863ULL, }, - { 0x38638e38638e3863ULL, 0x8e38638e38638e38ULL, }, - { 0x749ec9749ec9749eULL, 0xc9749ec9749ec974ULL, }, - { 0x27527d27527d2752ULL, 0x7d27527d27527d27ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc19473973a7a8e24ULL, 0x2eaf633c895d8184ULL, }, - { 0x9a62cabb70987060ULL, 0x399f68aed4536a10ULL, }, - { 0x7c5c7e8c43499b47ULL, 0x6cac499bd35ec956ULL, }, - { 0xc19473973a7a8e24ULL, 0x2eaf633c895d8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd38c578683b1a944ULL, 0x1ce7c08c60353b88ULL, }, - { 0xb5860b585562d42bULL, 0x4ff4a1795f409aceULL, }, - { 0x9a62cabb70987060ULL, 0x399f68aed4536a10ULL, }, /* 72 */ - { 0xd38c578683b1a944ULL, 0x1ce7c08c60353b88ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e54627b8b80b667ULL, 0x5ae4a7ebaa36835aULL, }, - { 0x7c5c7e8c43499b47ULL, 0x6cac499bd35ec956ULL, }, - { 0xb5860b585562d42bULL, 0x4ff4a1795f409aceULL, }, - { 0x8e54627b8b80b667ULL, 0x5ae4a7ebaa36835aULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_d.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_d.c deleted file mode 100644 index 5462ffac0f3f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0xd555555555555554ULL, 0xd555555555555554ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe666666666666665ULL, 0xe666666666666665ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x9c71c71c71c71c71ULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0x638e38e38e38e38eULL, }, - { 0xd555555555555554ULL, 0xd555555555555554ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6eeeeeeeeeeeeeeeULL, 0x6eeeeeeeeeeeeeeeULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c6ULL, }, - { 0x638e38e38e38e38dULL, 0xb8e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9111111111111110ULL, 0x9111111111111110ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e38ULL, }, - { 0xe666666666666665ULL, 0xe666666666666665ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9111111111111110ULL, 0x9111111111111110ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0xd82d82d82d82d82dULL, 0x82d82d82d82d82d7ULL, }, - { 0x749f49f49f49f49eULL, 0xc9f49f49f49f49f4ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, - { 0x6eeeeeeeeeeeeeeeULL, 0x6eeeeeeeeeeeeeeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b60b60b60b60b60ULL, 0x360b60b60b60b60bULL, }, - { 0x27d27d27d27d27d2ULL, 0x7d27d27d27d27d27ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x9c71c71c71c71c71ULL, }, /* 48 */ - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c6ULL, }, - { 0x9c71c71c71c71c71ULL, 0x471c71c71c71c71cULL, }, - { 0xd82d82d82d82d82dULL, 0x82d82d82d82d82d7ULL, }, - { 0x8b60b60b60b60b60ULL, 0x360b60b60b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38dULL, }, /* 56 */ - { 0x0e38e38e38e38e38ULL, 0x638e38e38e38e38eULL, }, - { 0x638e38e38e38e38dULL, 0xb8e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e38ULL, }, - { 0x749f49f49f49f49eULL, 0xc9f49f49f49f49f4ULL, }, - { 0x27d27d27d27d27d2ULL, 0x7d27d27d27d27d27ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, - { 0x7c5cfe8cc34a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, /* 72 */ - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e54e27c0c00b6e7ULL, 0x5ae527ec2a3703daULL, }, - { 0x7c5cfe8cc34a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x8e54e27c0c00b6e7ULL, 0x5ae527ec2a3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_h.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_h.c deleted file mode 100644 index 10d57e5741a8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0xd554d554d554d554ULL, 0xd554d554d554d554ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe665e665e665e665ULL, 0xe665e665e665e665ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c69c71c71bf1c6ULL, 0x9c71c71bf1c69c71ULL, }, - { 0x8e38e38db8e38e38ULL, 0xe38db8e38e38e38dULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0x71c71c71471c71c7ULL, 0x1c71471c71c71c71ULL, }, - { 0x0e38638e38e30e38ULL, 0x638e38e30e38638eULL, }, - { 0xd554d554d554d554ULL, 0xd554d554d554d554ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6eee6eee6eee6eeeULL, 0x6eee6eee6eee6eeeULL, }, - { 0xc71c71c69c71c71cULL, 0x71c69c71c71c71c6ULL, }, - { 0x638db8e38e38638dULL, 0xb8e38e38638db8e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9110911091109110ULL, 0x9110911091109110ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c71471c71c69c71ULL, 0x471c71c69c71471cULL, }, - { 0x38e38e38638e38e3ULL, 0x8e38638e38e38e38ULL, }, - { 0xe665e665e665e665ULL, 0xe665e665e665e665ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9110911091109110ULL, 0x9110911091109110ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0xd82d82d7ad82d82dULL, 0x82d7ad82d82d82d7ULL, }, - { 0x749ec9f49f49749eULL, 0xc9f49f49749ec9f4ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0x6eee6eee6eee6eeeULL, 0x6eee6eee6eee6eeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b60360b60b58b60ULL, 0x360b60b58b60360bULL, }, - { 0x27d27d27527d27d2ULL, 0x7d27527d27d27d27ULL, }, - { 0xf1c69c71c71bf1c6ULL, 0x9c71c71bf1c69c71ULL, }, /* 48 */ - { 0x71c71c71471c71c7ULL, 0x1c71471c71c71c71ULL, }, - { 0xc71c71c69c71c71cULL, 0x71c69c71c71c71c6ULL, }, - { 0x9c71471c71c69c71ULL, 0x471c71c69c71471cULL, }, - { 0xd82d82d7ad82d82dULL, 0x82d7ad82d82d82d7ULL, }, - { 0x8b60360b60b58b60ULL, 0x360b60b58b60360bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x8e38e38db8e38e38ULL, 0xe38db8e38e38e38dULL, }, /* 56 */ - { 0x0e38638e38e30e38ULL, 0x638e38e30e38638eULL, }, - { 0x638db8e38e38638dULL, 0xb8e38e38638db8e3ULL, }, - { 0x38e38e38638e38e3ULL, 0x8e38638e38e38e38ULL, }, - { 0x749ec9f49f49749eULL, 0xc9f49f49749ec9f4ULL, }, - { 0x27d27d27527d27d2ULL, 0x7d27527d27d27d27ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc21473973afa8e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb71187060ULL, 0x399f692ed4d36a90ULL, }, - { 0x7c5c7e8c43499bc7ULL, 0x6cac4a1bd3dec956ULL, }, - { 0xc21473973afa8e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578683b1a944ULL, 0x1d67c10c60353c08ULL, }, - { 0xb6060b5855e2d4abULL, 0x5074a1f95f409aceULL, }, - { 0x9a62cabb71187060ULL, 0x399f692ed4d36a90ULL, }, /* 72 */ - { 0xd40c578683b1a944ULL, 0x1d67c10c60353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e54627b8c00b6e7ULL, 0x5ae4a7ebaa3683daULL, }, - { 0x7c5c7e8c43499bc7ULL, 0x6cac4a1bd3dec956ULL, }, - { 0xb6060b5855e2d4abULL, 0x5074a1f95f409aceULL, }, - { 0x8e54627b8c00b6e7ULL, 0x5ae4a7ebaa3683daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_w.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_w.c deleted file mode 100644 index 53106dee74f0..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_ave_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVE_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVE_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0xd5555554d5555554ULL, 0xd5555554d5555554ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe6666665e6666665ULL, 0xe6666665e6666665ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x9c71c71bf1c71c71ULL, }, - { 0x8e38e38db8e38e38ULL, 0xe38e38e38e38e38dULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, - { 0x71c71c71471c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0x638e38e30e38e38eULL, }, - { 0xd5555554d5555554ULL, 0xd5555554d5555554ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6eeeeeee6eeeeeeeULL, 0x6eeeeeee6eeeeeeeULL, }, - { 0xc71c71c69c71c71cULL, 0x71c71c71c71c71c6ULL, }, - { 0x638e38e38e38e38dULL, 0xb8e38e38638e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9111111091111110ULL, 0x9111111091111110ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c71c71c71c71c71ULL, 0x471c71c69c71c71cULL, }, - { 0x38e38e38638e38e3ULL, 0x8e38e38e38e38e38ULL, }, - { 0xe6666665e6666665ULL, 0xe6666665e6666665ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9111111091111110ULL, 0x9111111091111110ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0xd82d82d7ad82d82dULL, 0x82d82d82d82d82d7ULL, }, - { 0x749f49f49f49f49eULL, 0xc9f49f49749f49f4ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, - { 0x6eeeeeee6eeeeeeeULL, 0x6eeeeeee6eeeeeeeULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b60b60b60b60b60ULL, 0x360b60b58b60b60bULL, }, - { 0x27d27d27527d27d2ULL, 0x7d27d27d27d27d27ULL, }, - { 0xf1c71c71c71c71c6ULL, 0x9c71c71bf1c71c71ULL, }, /* 48 */ - { 0x71c71c71471c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0xc71c71c69c71c71cULL, 0x71c71c71c71c71c6ULL, }, - { 0x9c71c71c71c71c71ULL, 0x471c71c69c71c71cULL, }, - { 0xd82d82d7ad82d82dULL, 0x82d82d82d82d82d7ULL, }, - { 0x8b60b60b60b60b60ULL, 0x360b60b58b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x8e38e38db8e38e38ULL, 0xe38e38e38e38e38dULL, }, /* 56 */ - { 0x0e38e38e38e38e38ULL, 0x638e38e30e38e38eULL, }, - { 0x638e38e38e38e38dULL, 0xb8e38e38638e38e3ULL, }, - { 0x38e38e38638e38e3ULL, 0x8e38e38e38e38e38ULL, }, - { 0x749f49f49f49f49eULL, 0xc9f49f49749f49f4ULL, }, - { 0x27d27d27527d27d2ULL, 0x7d27d27d27d27d27ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc21473973afb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92ed4d36a90ULL, }, - { 0x7c5cfe8c434a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xc21473973afb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578683b1a944ULL, 0x1d68410c60353c08ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92ed4d36a90ULL, }, /* 72 */ - { 0xd40c578683b1a944ULL, 0x1d68410c60353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e54e27b8c00b6e7ULL, 0x5ae527ebaa3703daULL, }, - { 0x7c5cfe8c434a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x8e54e27b8c00b6e7ULL, 0x5ae527ebaa3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVE_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_b.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_b.c deleted file mode 100644 index 465f54fc1376..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0xf1c71cf1c71cf1c7ULL, 0x1cf1c71cf1c71cf1ULL, }, - { 0x0e38e30e38e30e38ULL, 0xe30e38e30e38e30eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, - { 0x2b2b2b2b2b2b2b2bULL, 0x2b2b2b2b2b2b2b2bULL, }, - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, - { 0x1a1a1a1a1a1a1a1aULL, 0x1a1a1a1a1a1a1a1aULL, }, - { 0xf2c71cf2c71cf2c7ULL, 0x1cf2c71cf2c71cf2ULL, }, - { 0x0e39e40e39e40e39ULL, 0xe40e39e40e39e40eULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, /* 16 */ - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xefefefefefefefefULL, 0xefefefefefefefefULL, }, - { 0xc79cf1c79cf1c79cULL, 0xf1c79cf1c79cf1c7ULL, }, - { 0xe30eb9e30eb9e30eULL, 0xb9e30eb9e30eb9e3ULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, /* 24 */ - { 0x2b2b2b2b2b2b2b2bULL, 0x2b2b2b2b2b2b2b2bULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1cf2471cf2471cf2ULL, 0x471cf2471cf2471cULL, }, - { 0x39630e39630e3963ULL, 0x0e39630e39630e39ULL, }, - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, /* 32 */ - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd8ad02d8ad02d8adULL, 0x02d8ad02d8ad02d8ULL, }, - { 0xf41fcaf41fcaf41fULL, 0xcaf41fcaf41fcaf4ULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, /* 40 */ - { 0x1a1a1a1a1a1a1a1aULL, 0x1a1a1a1a1a1a1a1aULL, }, - { 0xefefefefefefefefULL, 0xefefefefefefefefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0be1360be1360be1ULL, 0x360be1360be1360bULL, }, - { 0x2852fd2852fd2852ULL, 0xfd2852fd2852fd28ULL, }, - { 0xf1c71cf1c71cf1c7ULL, 0x1cf1c71cf1c71cf1ULL, }, /* 48 */ - { 0xf2c71cf2c71cf2c7ULL, 0x1cf2c71cf2c71cf2ULL, }, - { 0xc79cf1c79cf1c79cULL, 0xf1c79cf1c79cf1c7ULL, }, - { 0x1cf2471cf2471cf2ULL, 0x471cf2471cf2471cULL, }, - { 0xd8ad02d8ad02d8adULL, 0x02d8ad02d8ad02d8ULL, }, - { 0x0be1360be1360be1ULL, 0x360be1360be1360bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0e38e30e38e30e38ULL, 0xe30e38e30e38e30eULL, }, /* 56 */ - { 0x0e39e40e39e40e39ULL, 0xe40e39e40e39e40eULL, }, - { 0xe30eb9e30eb9e30eULL, 0xb9e30eb9e30eb9e3ULL, }, - { 0x39630e39630e3963ULL, 0x0e39630e39630e39ULL, }, - { 0xf41fcaf41fcaf41fULL, 0xcaf41fcaf41fcaf4ULL, }, - { 0x2852fd2852fd2852ULL, 0xfd2852fd2852fd28ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc214f3183bfb0e24ULL, 0x2f2fe33c0a5d0104ULL, }, - { 0x9a62cabbf119f0e0ULL, 0x3920e92fd553eb10ULL, }, - { 0xfc5dfe0d434a1c47ULL, 0xec2cca1bd45fc9d6ULL, }, - { 0xc214f3183bfb0e24ULL, 0x2f2fe33c0a5d0104ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40cd70703b1a9c4ULL, 0x1de8c10de0353c08ULL, }, - { 0x36070b5856e2d52bULL, 0xd0f4a2f9df411aceULL, }, - { 0x9a62cabbf119f0e0ULL, 0x3920e92fd553eb10ULL, }, /* 72 */ - { 0xd40cd70703b1a9c4ULL, 0x1de8c10de0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e55e2fc0c00b7e7ULL, 0xdae5a7ecaa3704daULL, }, - { 0xfc5dfe0d434a1c47ULL, 0xec2cca1bd45fc9d6ULL, }, - { 0x36070b5856e2d52bULL, 0xd0f4a2f9df411aceULL, }, - { 0x0e55e2fc0c00b7e7ULL, 0xdae5a7ecaa3704daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_d.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_d.c deleted file mode 100644 index 391cb85ff0b3..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71c71c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, - { 0x2aaaaaaaaaaaaaabULL, 0x2aaaaaaaaaaaaaabULL, }, - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, - { 0x199999999999999aULL, 0x199999999999999aULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x0e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, /* 16 */ - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeeeeeeeeeeeeeefULL, 0xeeeeeeeeeeeeeeefULL, }, - { 0xc71c71c71c71c71cULL, 0xf1c71c71c71c71c7ULL, }, - { 0xe38e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, - { 0x2aaaaaaaaaaaaaaaULL, 0x2aaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaaaaaaaaaaaaabULL, 0x2aaaaaaaaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1c71c71c71c71c72ULL, 0x471c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0x0e38e38e38e38e39ULL, }, - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, /* 32 */ - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd82d82d82d82d82dULL, 0x02d82d82d82d82d8ULL, }, - { 0xf49f49f49f49f49fULL, 0xc9f49f49f49f49f4ULL, }, - { 0x1999999999999999ULL, 0x1999999999999999ULL, }, /* 40 */ - { 0x199999999999999aULL, 0x199999999999999aULL, }, - { 0xeeeeeeeeeeeeeeefULL, 0xeeeeeeeeeeeeeeefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0b60b60b60b60b61ULL, 0x360b60b60b60b60bULL, }, - { 0x27d27d27d27d27d2ULL, 0xfd27d27d27d27d28ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71c71c71c71ULL, }, /* 48 */ - { 0xf1c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0xf1c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0x471c71c71c71c71cULL, }, - { 0xd82d82d82d82d82dULL, 0x02d82d82d82d82d8ULL, }, - { 0x0b60b60b60b60b61ULL, 0x360b60b60b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e38e38e38eULL, }, /* 56 */ - { 0x0e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0xe38e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x0e38e38e38e38e39ULL, }, - { 0xf49f49f49f49f49fULL, 0xc9f49f49f49f49f4ULL, }, - { 0x27d27d27d27d27d2ULL, 0xfd27d27d27d27d28ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, - { 0xfc5cfe8cc34a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f95f411aceULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, /* 72 */ - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e54e27c0c00b6e7ULL, 0xdae527ec2a3703daULL, }, - { 0xfc5cfe8cc34a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f95f411aceULL, }, - { 0x0e54e27c0c00b6e7ULL, 0xdae527ec2a3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_h.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_h.c deleted file mode 100644 index 352b57d786a9..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0xf1c71c71c71cf1c7ULL, 0x1c71c71cf1c71c71ULL, }, - { 0x0e38e38e38e30e38ULL, 0xe38e38e30e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, - { 0x2aab2aab2aab2aabULL, 0x2aab2aab2aab2aabULL, }, - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, - { 0x199a199a199a199aULL, 0x199a199a199a199aULL, }, - { 0xf1c71c72c71cf1c7ULL, 0x1c72c71cf1c71c72ULL, }, - { 0x0e39e38e38e40e39ULL, 0xe38e38e40e39e38eULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, /* 16 */ - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeefeeefeeefeeefULL, 0xeeefeeefeeefeeefULL, }, - { 0xc71cf1c79c71c71cULL, 0xf1c79c71c71cf1c7ULL, }, - { 0xe38eb8e30e39e38eULL, 0xb8e30e39e38eb8e3ULL, }, - { 0x2aaa2aaa2aaa2aaaULL, 0x2aaa2aaa2aaa2aaaULL, }, /* 24 */ - { 0x2aab2aab2aab2aabULL, 0x2aab2aab2aab2aabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1c72471cf1c71c72ULL, 0x471cf1c71c72471cULL, }, - { 0x38e30e39638e38e3ULL, 0x0e39638e38e30e39ULL, }, - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, /* 32 */ - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd82d02d8ad82d82dULL, 0x02d8ad82d82d02d8ULL, }, - { 0xf49fc9f41f4af49fULL, 0xc9f41f4af49fc9f4ULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, /* 40 */ - { 0x199a199a199a199aULL, 0x199a199a199a199aULL, }, - { 0xeeefeeefeeefeeefULL, 0xeeefeeefeeefeeefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0b61360be0b60b61ULL, 0x360be0b60b61360bULL, }, - { 0x27d2fd28527d27d2ULL, 0xfd28527d27d2fd28ULL, }, - { 0xf1c71c71c71cf1c7ULL, 0x1c71c71cf1c71c71ULL, }, /* 48 */ - { 0xf1c71c72c71cf1c7ULL, 0x1c72c71cf1c71c72ULL, }, - { 0xc71cf1c79c71c71cULL, 0xf1c79c71c71cf1c7ULL, }, - { 0x1c72471cf1c71c72ULL, 0x471cf1c71c72471cULL, }, - { 0xd82d02d8ad82d82dULL, 0x02d8ad82d82d02d8ULL, }, - { 0x0b61360be0b60b61ULL, 0x360be0b60b61360bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0e38e38e38e30e38ULL, 0xe38e38e30e38e38eULL, }, /* 56 */ - { 0x0e39e38e38e40e39ULL, 0xe38e38e40e39e38eULL, }, - { 0xe38eb8e30e39e38eULL, 0xb8e30e39e38eb8e3ULL, }, - { 0x38e30e39638e38e3ULL, 0x0e39638e38e30e39ULL, }, - { 0xf49fc9f41f4af49fULL, 0xc9f41f4af49fc9f4ULL, }, - { 0x27d2fd28527d27d2ULL, 0xfd28527d27d2fd28ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc214f3983afb0e24ULL, 0x2f2fe33c09dd0184ULL, }, - { 0x9a62cabbf119f060ULL, 0x39a0e92fd4d3ea90ULL, }, - { 0xfc5dfe8d434a1bc7ULL, 0xecacca1bd3dfc956ULL, }, - { 0xc214f3983afb0e24ULL, 0x2f2fe33c09dd0184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40cd78703b1a944ULL, 0x1d68c10de0353c08ULL, }, - { 0x36070b5855e2d4abULL, 0xd074a1f9df411aceULL, }, - { 0x9a62cabbf119f060ULL, 0x39a0e92fd4d3ea90ULL, }, /* 72 */ - { 0xd40cd78703b1a944ULL, 0x1d68c10de0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e55e27c0c00b6e7ULL, 0xdae5a7ecaa3703daULL, }, - { 0xfc5dfe8d434a1bc7ULL, 0xecacca1bd3dfc956ULL, }, - { 0x36070b5855e2d4abULL, 0xd074a1f9df411aceULL, }, - { 0x0e55e27c0c00b6e7ULL, 0xdae5a7ecaa3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_w.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_w.c deleted file mode 100644 index cfba37b0ae24..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71cf1c71c71ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e30e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, - { 0x2aaaaaab2aaaaaabULL, 0x2aaaaaab2aaaaaabULL, }, - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, - { 0x1999999a1999999aULL, 0x1999999a1999999aULL, }, - { 0xf1c71c72c71c71c7ULL, 0x1c71c71cf1c71c72ULL, }, - { 0x0e38e38e38e38e39ULL, 0xe38e38e40e38e38eULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, /* 16 */ - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xeeeeeeefeeeeeeefULL, 0xeeeeeeefeeeeeeefULL, }, - { 0xc71c71c79c71c71cULL, 0xf1c71c71c71c71c7ULL, }, - { 0xe38e38e30e38e38eULL, 0xb8e38e39e38e38e3ULL, }, - { 0x2aaaaaaa2aaaaaaaULL, 0x2aaaaaaa2aaaaaaaULL, }, /* 24 */ - { 0x2aaaaaab2aaaaaabULL, 0x2aaaaaab2aaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1c71c71cf1c71c72ULL, 0x471c71c71c71c71cULL, }, - { 0x38e38e39638e38e3ULL, 0x0e38e38e38e38e39ULL, }, - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, /* 32 */ - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd82d82d8ad82d82dULL, 0x02d82d82d82d82d8ULL, }, - { 0xf49f49f41f49f49fULL, 0xc9f49f4af49f49f4ULL, }, - { 0x1999999919999999ULL, 0x1999999919999999ULL, }, /* 40 */ - { 0x1999999a1999999aULL, 0x1999999a1999999aULL, }, - { 0xeeeeeeefeeeeeeefULL, 0xeeeeeeefeeeeeeefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0b60b60be0b60b61ULL, 0x360b60b60b60b60bULL, }, - { 0x27d27d28527d27d2ULL, 0xfd27d27d27d27d28ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x1c71c71cf1c71c71ULL, }, /* 48 */ - { 0xf1c71c72c71c71c7ULL, 0x1c71c71cf1c71c72ULL, }, - { 0xc71c71c79c71c71cULL, 0xf1c71c71c71c71c7ULL, }, - { 0x1c71c71cf1c71c72ULL, 0x471c71c71c71c71cULL, }, - { 0xd82d82d8ad82d82dULL, 0x02d82d82d82d82d8ULL, }, - { 0x0b60b60be0b60b61ULL, 0x360b60b60b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0e38e38e38e38e38ULL, 0xe38e38e30e38e38eULL, }, /* 56 */ - { 0x0e38e38e38e38e39ULL, 0xe38e38e40e38e38eULL, }, - { 0xe38e38e30e38e38eULL, 0xb8e38e39e38e38e3ULL, }, - { 0x38e38e39638e38e3ULL, 0x0e38e38e38e38e39ULL, }, - { 0xf49f49f41f49f49fULL, 0xc9f49f4af49f49f4ULL, }, - { 0x27d27d28527d27d2ULL, 0xfd27d27d27d27d28ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc21473983afb0e24ULL, 0x2f2f633c09dd8184ULL, }, - { 0x9a62cabbf118f060ULL, 0x399fe92fd4d36a90ULL, }, - { 0xfc5cfe8d434a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0xc21473983afb0e24ULL, 0x2f2f633c09dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578703b1a944ULL, 0x1d68410de0353c08ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f9df411aceULL, }, - { 0x9a62cabbf118f060ULL, 0x399fe92fd4d36a90ULL, }, /* 72 */ - { 0xd40c578703b1a944ULL, 0x1d68410de0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x0e54e27c0c00b6e7ULL, 0xdae527ecaa3703daULL, }, - { 0xfc5cfe8d434a1bc7ULL, 0xecac4a1bd3df4956ULL, }, - { 0x36068b5855e2d4abULL, 0xd074a1f9df411aceULL, }, - { 0x0e54e27c0c00b6e7ULL, 0xdae527ecaa3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_b.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_b.c deleted file mode 100644 index 91f227b830eb..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c79cf1c79cf1c7ULL, 0x9cf1c79cf1c79cf1ULL, }, - { 0x8eb8e38eb8e38eb8ULL, 0xe38eb8e38eb8e38eULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2b2b2b2b2b2b2b2bULL, 0x2b2b2b2b2b2b2b2bULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x1a1a1a1a1a1a1a1aULL, 0x1a1a1a1a1a1a1a1aULL, }, - { 0x72471c72471c7247ULL, 0x1c72471c72471c72ULL, }, - { 0x0e39640e39640e39ULL, 0x640e39640e39640eULL, }, - { 0xd5d5d5d5d5d5d5d5ULL, 0xd5d5d5d5d5d5d5d5ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6f6f6f6f6f6f6f6fULL, 0x6f6f6f6f6f6f6f6fULL, }, - { 0xc79c71c79c71c79cULL, 0x71c79c71c79c71c7ULL, }, - { 0x638eb9638eb9638eULL, 0xb9638eb9638eb963ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2b2b2b2b2b2b2b2bULL, 0x2b2b2b2b2b2b2b2bULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9191919191919191ULL, 0x9191919191919191ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c72479c72479c72ULL, 0x479c72479c72479cULL, }, - { 0x39638e39638e3963ULL, 0x8e39638e39638e39ULL, }, - { 0xe6e6e6e6e6e6e6e6ULL, 0xe6e6e6e6e6e6e6e6ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9191919191919191ULL, 0x9191919191919191ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xd8ad82d8ad82d8adULL, 0x82d8ad82d8ad82d8ULL, }, - { 0x749fca749fca749fULL, 0xca749fca749fca74ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x1a1a1a1a1a1a1a1aULL, 0x1a1a1a1a1a1a1a1aULL, }, - { 0x6f6f6f6f6f6f6f6fULL, 0x6f6f6f6f6f6f6f6fULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b61368b61368b61ULL, 0x368b61368b61368bULL, }, - { 0x28527d28527d2852ULL, 0x7d28527d28527d28ULL, }, - { 0xf1c79cf1c79cf1c7ULL, 0x9cf1c79cf1c79cf1ULL, }, /* 48 */ - { 0x72471c72471c7247ULL, 0x1c72471c72471c72ULL, }, - { 0xc79c71c79c71c79cULL, 0x71c79c71c79c71c7ULL, }, - { 0x9c72479c72479c72ULL, 0x479c72479c72479cULL, }, - { 0xd8ad82d8ad82d8adULL, 0x82d8ad82d8ad82d8ULL, }, - { 0x8b61368b61368b61ULL, 0x368b61368b61368bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x8eb8e38eb8e38eb8ULL, 0xe38eb8e38eb8e38eULL, }, /* 56 */ - { 0x0e39640e39640e39ULL, 0x640e39640e39640eULL, }, - { 0x638eb9638eb9638eULL, 0xb9638eb9638eb963ULL, }, - { 0x39638e39638e3963ULL, 0x8e39638e39638e39ULL, }, - { 0x749fca749fca749fULL, 0xca749fca749fca74ULL, }, - { 0x28527d28527d2852ULL, 0x7d28527d28527d28ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc29473983b7b8e24ULL, 0x2faf633c8a5d8184ULL, }, - { 0x9a62cabb71997060ULL, 0x39a069afd5536b10ULL, }, - { 0x7c5d7e8d434a9c47ULL, 0x6cac4a9bd45fc956ULL, }, - { 0xc29473983b7b8e24ULL, 0x2faf633c8a5d8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd48c578783b1a944ULL, 0x1de8c18d60353c88ULL, }, - { 0xb6870b585662d52bULL, 0x50f4a2795f419aceULL, }, - { 0x9a62cabb71997060ULL, 0x39a069afd5536b10ULL, }, /* 72 */ - { 0xd48c578783b1a944ULL, 0x1de8c18d60353c88ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e55627c8c80b767ULL, 0x5ae5a7ecaa37845aULL, }, - { 0x7c5d7e8d434a9c47ULL, 0x6cac4a9bd45fc956ULL, }, - { 0xb6870b585662d52bULL, 0x50f4a2795f419aceULL, }, - { 0x8e55627c8c80b767ULL, 0x5ae5a7ecaa37845aULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_d.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_d.c deleted file mode 100644 index fde57a2a5c2d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x9c71c71c71c71c71ULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38eULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2aaaaaaaaaaaaaabULL, 0x2aaaaaaaaaaaaaabULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x199999999999999aULL, 0x199999999999999aULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x0e38e38e38e38e39ULL, 0x638e38e38e38e38eULL, }, - { 0xd555555555555555ULL, 0xd555555555555555ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6eeeeeeeeeeeeeefULL, 0x6eeeeeeeeeeeeeefULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x638e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaaaaaaaaaaaaabULL, 0x2aaaaaaaaaaaaaabULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9111111111111111ULL, 0x9111111111111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c71c71c71c71c72ULL, 0x471c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0xe666666666666666ULL, 0xe666666666666666ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9111111111111111ULL, 0x9111111111111111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xd82d82d82d82d82dULL, 0x82d82d82d82d82d8ULL, }, - { 0x749f49f49f49f49fULL, 0xc9f49f49f49f49f4ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x199999999999999aULL, 0x199999999999999aULL, }, - { 0x6eeeeeeeeeeeeeefULL, 0x6eeeeeeeeeeeeeefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b60b60b60b60b61ULL, 0x360b60b60b60b60bULL, }, - { 0x27d27d27d27d27d2ULL, 0x7d27d27d27d27d28ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x9c71c71c71c71c71ULL, }, /* 48 */ - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x9c71c71c71c71c72ULL, 0x471c71c71c71c71cULL, }, - { 0xd82d82d82d82d82dULL, 0x82d82d82d82d82d8ULL, }, - { 0x8b60b60b60b60b61ULL, 0x360b60b60b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x8e38e38e38e38e38ULL, 0xe38e38e38e38e38eULL, }, /* 56 */ - { 0x0e38e38e38e38e39ULL, 0x638e38e38e38e38eULL, }, - { 0x638e38e38e38e38eULL, 0xb8e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0x749f49f49f49f49fULL, 0xc9f49f49f49f49f4ULL, }, - { 0x27d27d27d27d27d2ULL, 0x7d27d27d27d27d28ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, - { 0x7c5cfe8cc34a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xc2147397bafb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92f54d36a90ULL, }, /* 72 */ - { 0xd40c578703b1a944ULL, 0x1d68410ce0353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e54e27c0c00b6e7ULL, 0x5ae527ec2a3703daULL, }, - { 0x7c5cfe8cc34a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x8e54e27c0c00b6e7ULL, 0x5ae527ec2a3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_h.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_h.c deleted file mode 100644 index b9ec39a3dee1..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c79c71c71cf1c7ULL, 0x9c71c71cf1c79c71ULL, }, - { 0x8e38e38eb8e38e38ULL, 0xe38eb8e38e38e38eULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2aab2aab2aab2aabULL, 0x2aab2aab2aab2aabULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x199a199a199a199aULL, 0x199a199a199a199aULL, }, - { 0x71c71c72471c71c7ULL, 0x1c72471c71c71c72ULL, }, - { 0x0e39638e38e40e39ULL, 0x638e38e40e39638eULL, }, - { 0xd555d555d555d555ULL, 0xd555d555d555d555ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6eef6eef6eef6eefULL, 0x6eef6eef6eef6eefULL, }, - { 0xc71c71c79c71c71cULL, 0x71c79c71c71c71c7ULL, }, - { 0x638eb8e38e39638eULL, 0xb8e38e39638eb8e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aab2aab2aab2aabULL, 0x2aab2aab2aab2aabULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9111911191119111ULL, 0x9111911191119111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c72471c71c79c72ULL, 0x471c71c79c72471cULL, }, - { 0x38e38e39638e38e3ULL, 0x8e39638e38e38e39ULL, }, - { 0xe666e666e666e666ULL, 0xe666e666e666e666ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9111911191119111ULL, 0x9111911191119111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xd82d82d8ad82d82dULL, 0x82d8ad82d82d82d8ULL, }, - { 0x749fc9f49f4a749fULL, 0xc9f49f4a749fc9f4ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x199a199a199a199aULL, 0x199a199a199a199aULL, }, - { 0x6eef6eef6eef6eefULL, 0x6eef6eef6eef6eefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b61360b60b68b61ULL, 0x360b60b68b61360bULL, }, - { 0x27d27d28527d27d2ULL, 0x7d28527d27d27d28ULL, }, - { 0xf1c79c71c71cf1c7ULL, 0x9c71c71cf1c79c71ULL, }, /* 48 */ - { 0x71c71c72471c71c7ULL, 0x1c72471c71c71c72ULL, }, - { 0xc71c71c79c71c71cULL, 0x71c79c71c71c71c7ULL, }, - { 0x9c72471c71c79c72ULL, 0x471c71c79c72471cULL, }, - { 0xd82d82d8ad82d82dULL, 0x82d8ad82d82d82d8ULL, }, - { 0x8b61360b60b68b61ULL, 0x360b60b68b61360bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x8e38e38eb8e38e38ULL, 0xe38eb8e38e38e38eULL, }, /* 56 */ - { 0x0e39638e38e40e39ULL, 0x638e38e40e39638eULL, }, - { 0x638eb8e38e39638eULL, 0xb8e38e39638eb8e3ULL, }, - { 0x38e38e39638e38e3ULL, 0x8e39638e38e38e39ULL, }, - { 0x749fc9f49f4a749fULL, 0xc9f49f4a749fc9f4ULL, }, - { 0x27d27d28527d27d2ULL, 0x7d28527d27d27d28ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc21473983afb8e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb71197060ULL, 0x39a0692fd4d36a90ULL, }, - { 0x7c5d7e8d434a9bc7ULL, 0x6cac4a1bd3dfc956ULL, }, - { 0xc21473983afb8e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578783b1a944ULL, 0x1d68c10d60353c08ULL, }, - { 0xb6070b5855e2d4abULL, 0x5074a1f95f419aceULL, }, - { 0x9a62cabb71197060ULL, 0x39a0692fd4d36a90ULL, }, /* 72 */ - { 0xd40c578783b1a944ULL, 0x1d68c10d60353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e55627c8c00b6e7ULL, 0x5ae5a7ecaa3783daULL, }, - { 0x7c5d7e8d434a9bc7ULL, 0x6cac4a1bd3dfc956ULL, }, - { 0xb6070b5855e2d4abULL, 0x5074a1f95f419aceULL, }, - { 0x8e55627c8c00b6e7ULL, 0x5ae5a7ecaa3783daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_w.c b/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_w.c deleted file mode 100644 index dc3c2e432edc..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-average/test_msa_aver_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction AVER_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Average"; - char *instruction_name = "AVER_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x9c71c71cf1c71c71ULL, }, - { 0x8e38e38eb8e38e38ULL, 0xe38e38e38e38e38eULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2aaaaaab2aaaaaabULL, 0x2aaaaaab2aaaaaabULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x1999999a1999999aULL, 0x1999999a1999999aULL, }, - { 0x71c71c72471c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x0e38e38e38e38e39ULL, 0x638e38e40e38e38eULL, }, - { 0xd5555555d5555555ULL, 0xd5555555d5555555ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x6eeeeeef6eeeeeefULL, 0x6eeeeeef6eeeeeefULL, }, - { 0xc71c71c79c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x638e38e38e38e38eULL, 0xb8e38e39638e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x2aaaaaab2aaaaaabULL, 0x2aaaaaab2aaaaaabULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x9111111191111111ULL, 0x9111111191111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x9c71c71c71c71c72ULL, 0x471c71c79c71c71cULL, }, - { 0x38e38e39638e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0xe6666666e6666666ULL, 0xe6666666e6666666ULL, }, /* 32 */ - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x9111111191111111ULL, 0x9111111191111111ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xd82d82d8ad82d82dULL, 0x82d82d82d82d82d8ULL, }, - { 0x749f49f49f49f49fULL, 0xc9f49f4a749f49f4ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, /* 40 */ - { 0x1999999a1999999aULL, 0x1999999a1999999aULL, }, - { 0x6eeeeeef6eeeeeefULL, 0x6eeeeeef6eeeeeefULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8b60b60b60b60b61ULL, 0x360b60b68b60b60bULL, }, - { 0x27d27d28527d27d2ULL, 0x7d27d27d27d27d28ULL, }, - { 0xf1c71c71c71c71c7ULL, 0x9c71c71cf1c71c71ULL, }, /* 48 */ - { 0x71c71c72471c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0xc71c71c79c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x9c71c71c71c71c72ULL, 0x471c71c79c71c71cULL, }, - { 0xd82d82d8ad82d82dULL, 0x82d82d82d82d82d8ULL, }, - { 0x8b60b60b60b60b61ULL, 0x360b60b68b60b60bULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x8e38e38eb8e38e38ULL, 0xe38e38e38e38e38eULL, }, /* 56 */ - { 0x0e38e38e38e38e39ULL, 0x638e38e40e38e38eULL, }, - { 0x638e38e38e38e38eULL, 0xb8e38e39638e38e3ULL, }, - { 0x38e38e39638e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0x749f49f49f49f49fULL, 0xc9f49f4a749f49f4ULL, }, - { 0x27d27d28527d27d2ULL, 0x7d27d27d27d27d28ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xc21473983afb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92fd4d36a90ULL, }, - { 0x7c5cfe8d434a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xc21473983afb0e24ULL, 0x2f2f633c89dd8184ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xd40c578783b1a944ULL, 0x1d68410d60353c08ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x9a62cabb7118f060ULL, 0x399fe92fd4d36a90ULL, }, /* 72 */ - { 0xd40c578783b1a944ULL, 0x1d68410d60353c08ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8e54e27c8c00b6e7ULL, 0x5ae527ecaa3703daULL, }, - { 0x7c5cfe8d434a1bc7ULL, 0x6cac4a1bd3df4956ULL, }, - { 0xb6068b5855e2d4abULL, 0x5074a1f95f411aceULL, }, - { 0x8e54e27c8c00b6e7ULL, 0x5ae527ecaa3703daULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AVER_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_b.c deleted file mode 100644 index c9a9ee227da0..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CEQ.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CEQ.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_d.c deleted file mode 100644 index 542c460f2fa8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CEQ.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CEQ.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_h.c deleted file mode 100644 index 3ebe59550c3a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CEQ.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CEQ.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_w.c deleted file mode 100644 index 003acf154459..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CEQ.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CEQ.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CEQ_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_b.c deleted file mode 100644 index ff20f0ea0efd..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, /* 48 */ - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, /* 56 */ - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xff00ffffff000000ULL, 0x00000000ff00ff00ULL, }, - { 0xff00000000000000ULL, 0x000000000000ffffULL, }, - { 0xff00ffffff0000ffULL, 0x000000000000ff00ULL, }, - { 0x00ff000000ffffffULL, 0xffffffff00ff00ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00ff000000ff0000ULL, 0xff00ff00000000ffULL, }, - { 0xffffff00ffffffffULL, 0x0000000000ff0000ULL, }, - { 0x00ffffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ - { 0xff00ffffff00ffffULL, 0x00ff00ffffffff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff00ffffffffffffULL, 0x00ff000000ff0000ULL, }, - { 0x00ff000000ffff00ULL, 0xffffffffffff00ffULL, }, - { 0x000000ff00000000ULL, 0xffffffffff00ffffULL, }, - { 0x00ff000000000000ULL, 0xff00ffffff00ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_d.c deleted file mode 100644 index 3dc18bd6612c..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_h.c deleted file mode 100644 index 00c48d657bba..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 48 */ - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 56 */ - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffffffffffff0000ULL, 0x00000000ffffffffULL, }, - { 0xffff000000000000ULL, 0x000000000000ffffULL, }, - { 0xffffffffffff0000ULL, 0x000000000000ffffULL, }, - { 0x000000000000ffffULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000ffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x000000000000ffffULL, 0xffffffffffff0000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_w.c deleted file mode 100644 index 16f84a13e7d7..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_b.c deleted file mode 100644 index 24574dc30d7a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffff0000ffffff00ULL, 0x00ffff00000000ffULL, }, - { 0xff000000ffffffffULL, 0x00ffffff000000ffULL, }, - { 0x00000000ff00ffffULL, 0xffffffff0000ffffULL, }, - { 0x0000ffff000000ffULL, 0xff0000ffffffff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffffffff00ffULL, 0xff00ffffff000000ULL, }, - { 0x0000ff00ff00ffffULL, 0xff0000ffffffff00ULL, }, - { 0x00ffffff00000000ULL, 0xff000000ffffff00ULL, }, /* 72 */ - { 0xffff00000000ff00ULL, 0x00ff000000ffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x000000000000ff00ULL, 0xffff000000ffffffULL, }, - { 0xffffffff00ff0000ULL, 0x00000000ffff0000ULL, }, - { 0xffff00ff00ff0000ULL, 0x00ffff00000000ffULL, }, - { 0xffffffffffff00ffULL, 0x0000ffffff000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_d.c deleted file mode 100644 index e3f571545d97..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_h.c deleted file mode 100644 index 8938d31c5960..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff0000ffffULL, }, - { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffffffff0000ULL, 0xffffffffffff0000ULL, }, - { 0x0000ffffffffffffULL, 0xffff0000ffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, /* 72 */ - { 0xffff00000000ffffULL, 0x000000000000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x000000000000ffffULL, 0xffff00000000ffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffff0000ULL, }, - { 0xffff000000000000ULL, 0x0000ffff00000000ULL, }, - { 0xffffffffffff0000ULL, 0x0000ffffffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_w.c deleted file mode 100644 index 078a0c181569..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLE_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLE_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLE_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_b.c deleted file mode 100644 index 02c3dfa09e26..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, /* 48 */ - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, /* 56 */ - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xff00ffffff000000ULL, 0x00000000ff00ff00ULL, }, - { 0xff00000000000000ULL, 0x000000000000ffffULL, }, - { 0xff00ffffff0000ffULL, 0x000000000000ff00ULL, }, - { 0x00ff000000ffffffULL, 0xffffffff00ff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ff000000ff0000ULL, 0xff00ff00000000ffULL, }, - { 0xffffff00ffffffffULL, 0x0000000000ff0000ULL, }, - { 0x00ffffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ - { 0xff00ffffff00ffffULL, 0x00ff00ffffffff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff00ffffffffffffULL, 0x00ff000000ff0000ULL, }, - { 0x00ff000000ffff00ULL, 0xffffffffffff00ffULL, }, - { 0x000000ff00000000ULL, 0xffffffffff00ffffULL, }, - { 0x00ff000000000000ULL, 0xff00ffffff00ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_d.c deleted file mode 100644 index 40637e27613a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_h.c deleted file mode 100644 index ee3cd628fc87..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 48 */ - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 56 */ - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffffffffffff0000ULL, 0x00000000ffffffffULL, }, - { 0xffff000000000000ULL, 0x000000000000ffffULL, }, - { 0xffffffffffff0000ULL, 0x000000000000ffffULL, }, - { 0x000000000000ffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000ffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x000000000000ffffULL, 0xffffffffffff0000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_w.c deleted file mode 100644 index bde4d95350c8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_b.c deleted file mode 100644 index 147bf484b7d0..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffff0000ffffff00ULL, 0x00ffff00000000ffULL, }, - { 0xff000000ffffffffULL, 0x00ffffff000000ffULL, }, - { 0x00000000ff00ffffULL, 0xffffffff0000ffffULL, }, - { 0x0000ffff000000ffULL, 0xff0000ffffffff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ffffffff00ffULL, 0xff00ffffff000000ULL, }, - { 0x0000ff00ff00ffffULL, 0xff0000ffffffff00ULL, }, - { 0x00ffffff00000000ULL, 0xff000000ffffff00ULL, }, /* 72 */ - { 0xffff00000000ff00ULL, 0x00ff000000ffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000ff00ULL, 0xffff000000ffffffULL, }, - { 0xffffffff00ff0000ULL, 0x00000000ffff0000ULL, }, - { 0xffff00ff00ff0000ULL, 0x00ffff00000000ffULL, }, - { 0xffffffffffff00ffULL, 0x0000ffffff000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_d.c deleted file mode 100644 index 5daf71672698..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_h.c deleted file mode 100644 index 8d51c2cc3c81..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff0000ffffULL, }, - { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ffffffff0000ULL, 0xffffffffffff0000ULL, }, - { 0x0000ffffffffffffULL, 0xffff0000ffffffffULL, }, - { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, /* 72 */ - { 0xffff00000000ffffULL, 0x000000000000ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000000000ffffULL, 0xffff00000000ffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffff0000ULL, }, - { 0xffff000000000000ULL, 0x0000ffff00000000ULL, }, - { 0xffffffffffff0000ULL, 0x0000ffffffff0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_w.c deleted file mode 100644 index 5403af868897..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction CLT_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Compare"; - char *instruction_name = "CLT_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_CLT_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_b.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_b.c deleted file mode 100644 index f263201e72d6..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 0 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 16 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0200ff0200ff0200ULL, 0xff0200ff0200ff02ULL, }, - { 0xfd0001fd0001fd00ULL, 0x01fd0001fd0001fdULL, }, - { 0xababababababababULL, 0xababababababababULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xfe0001fe0001fe00ULL, 0x01fe0001fe0001feULL, }, - { 0x0300ff0300ff0300ULL, 0xff0300ff0300ff03ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 32 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0100000100000100ULL, 0x0001000001000001ULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, - { 0x0100000100000100ULL, 0x0001000001000001ULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, /* 48 */ - { 0x0101ff0101ff0101ULL, 0xff0101ff0101ff01ULL, }, - { 0x0001000001000001ULL, 0x0000010000010000ULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0x0002ff0002ff0002ULL, 0xff0002ff0002ff00ULL, }, - { 0x00fe0100fe0100feULL, 0x0100fe0100fe0100ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, /* 56 */ - { 0xffff01ffff01ffffULL, 0x01ffff01ffff01ffULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, - { 0x0001000001000001ULL, 0x0000010000010000ULL, }, - { 0x00fe0100fe0100feULL, 0x0100fe0100fe0100ULL, }, - { 0x0002ff0002ff0002ULL, 0xff0002ff0002ff00ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 64 */ - { 0x18ff01000000ff08ULL, 0x04f50003000100fdULL, }, - { 0x0101000000fe0000ULL, 0x01fe00a20002fe00ULL, }, - { 0xff01ff000002fe00ULL, 0x00fa00fe00010200ULL, }, - { 0x000000ff01ff0000ULL, 0x0000fa00f600ff00ULL, }, - { 0x0101ff0101010101ULL, 0x0101010101010101ULL, }, - { 0x000000ffff020000ULL, 0x000001e600010200ULL, }, - { 0x0000000100fe0100ULL, 0x000000000000fe00ULL, }, - { 0x00000301ff00fffeULL, 0x0000fb002a000001ULL, }, /* 72 */ - { 0x10ff0100000002f0ULL, 0x02040000fc0000fbULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0001fdff00ff03ffULL, 0x000200000000ff00ULL, }, - { 0x000000ff02000001ULL, 0xff00f6002b0000f8ULL, }, - { 0xeaffff0001000009ULL, 0xfa0101fffc010018ULL, }, - { 0xff000000ffff0000ULL, 0xfe000228010100fcULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_d.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_d.c deleted file mode 100644 index 0458f933f663..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 0 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 16 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000003ULL, 0xffffffffffffffffULL, }, - { 0xfffffffffffffffdULL, 0x0000000000000001ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xfffffffffffffffeULL, 0x0000000000000001ULL, }, - { 0x0000000000000003ULL, 0xffffffffffffffffULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 32 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, /* 48 */ - { 0x0000000000000001ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, /* 56 */ - { 0xffffffffffffffffULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 64 */ - { 0x000000000000001cULL, 0x0000000000000003ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000013ULL, 0x0000000000000002ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffe6ULL, 0xfffffffffffffffaULL, }, - { 0xffffffffffffffffULL, 0xfffffffffffffffeULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_h.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_h.c deleted file mode 100644 index fffe7be072d9..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 0 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 16 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0003ffff00000003ULL, 0xffff00000003ffffULL, }, - { 0xfffd00010000fffdULL, 0x00010000fffd0001ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xfffe00010000fffeULL, 0x00010000fffe0001ULL, }, - { 0x0003ffff00000003ULL, 0xffff00000003ffffULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 32 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000000000001ULL, 0x0000000000010000ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, - { 0x0001000000000001ULL, 0x0000000000010000ULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, /* 48 */ - { 0x0001ffff00010001ULL, 0xffff00010001ffffULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0x0000ffff00020000ULL, 0xffff00020000ffffULL, }, - { 0x00000001fffe0000ULL, 0x0001fffe00000001ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, /* 56 */ - { 0xffff0001ffffffffULL, 0x0001ffffffff0001ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, - { 0x00000001fffe0000ULL, 0x0001fffe00000001ULL, }, - { 0x0000ffff00020000ULL, 0xffff00020000ffffULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 64 */ - { 0x001cffbf0000ffffULL, 0x0003000000000000ULL, }, - { 0x0001000000000000ULL, 0x000100000000fffeULL, }, - { 0xffffffff0000fffeULL, 0x0000000000000002ULL, }, - { 0x0000000000010000ULL, 0x0000fffafff3ffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x00000000ffff0000ULL, 0x0000000100000002ULL, }, - { 0x0000000000000001ULL, 0x000000000000fffeULL, }, - { 0x00000003ffffffffULL, 0x0000fffb00370000ULL, }, /* 72 */ - { 0x0013ff2e00000002ULL, 0x00020000fffd0000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000fffd00000003ULL, 0x000000000000ffffULL, }, - { 0x0000000000020000ULL, 0xfffffff600390000ULL, }, - { 0xffe6003900010000ULL, 0xfffa0001fffc0000ULL, }, - { 0xffff0000ffff0000ULL, 0xfffe000200010000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_w.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_w.c deleted file mode 100644 index 22fa184d8045..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 0 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 16 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000200000000ULL, 0xffffffff00000002ULL, }, - { 0xfffffffd00000000ULL, 0x00000001fffffffdULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xfffffffe00000000ULL, 0x00000001fffffffeULL, }, - { 0x0000000300000000ULL, 0xffffffff00000003ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 32 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000000ULL, 0x0000000000000001ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, - { 0x0000000100000000ULL, 0x0000000000000001ULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, /* 48 */ - { 0x0000000100000001ULL, 0xffffffff00000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0xffffffff00000000ULL, }, - { 0x00000000fffffffeULL, 0x0000000100000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, /* 56 */ - { 0xffffffffffffffffULL, 0x00000001ffffffffULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x00000000fffffffeULL, 0x0000000100000000ULL, }, - { 0x0000000000000002ULL, 0xffffffff00000000ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 64 */ - { 0x0000001c00000000ULL, 0x0000000300000000ULL, }, - { 0x0000000100000000ULL, 0x0000000100000000ULL, }, - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x00000000fffffff2ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000037ULL, }, /* 72 */ - { 0x0000001300000000ULL, 0x00000002fffffffdULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0xffffffff00000039ULL, }, - { 0xffffffe600000001ULL, 0xfffffffafffffffcULL, }, - { 0xffffffffffffffffULL, 0xfffffffe00000001ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_b.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_b.c deleted file mode 100644 index 8097d6c86444..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0101040101040101ULL, 0x0401010401010401ULL, }, - { 0x0902010902010902ULL, 0x0109020109020109ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0001030001030001ULL, 0x0300010300010300ULL, }, - { 0x0601000601000601ULL, 0x0006010006010006ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000010000010000ULL, 0x0100000100000100ULL, }, - { 0x0300000300000300ULL, 0x0003000003000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0001030001030001ULL, 0x0300010300010300ULL, }, - { 0x0701010701010701ULL, 0x0107010107010107ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0100000100000100ULL, 0x0001000001000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0100000100000100ULL, 0x0001000001000001ULL, }, - { 0x0201000201000201ULL, 0x0002010002010002ULL, }, - { 0x0100000100000100ULL, 0x0001000001000001ULL, }, - { 0x0402010402010402ULL, 0x0104020104020104ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0801000801000801ULL, 0x0008010008010008ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000010000010000ULL, 0x0100000100000100ULL, }, - { 0x0001020001020001ULL, 0x0200010200010200ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0002030002030002ULL, 0x0300020300020300ULL, }, - { 0x0000030000030000ULL, 0x0300000300000300ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 64 */ - { 0x0000ff0200000008ULL, 0x040000030c010200ULL, }, - { 0x0001010100000000ULL, 0x0100000001020400ULL, }, - { 0x01010a0200020000ULL, 0x0000000001010000ULL, }, - { 0x0101000001010200ULL, 0x0002110000000015ULL, }, - { 0x0101ff0101010101ULL, 0x0101010101010101ULL, }, - { 0x0102000000000100ULL, 0x000100000001020cULL, }, - { 0x0202000100030000ULL, 0x0001010000000001ULL, }, - { 0x0100000004020102ULL, 0x0002120200000001ULL, }, /* 72 */ - { 0x0000ff0102010010ULL, 0x0200010908000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0101070201040001ULL, 0x0000010101000000ULL, }, - { 0x0000000002000201ULL, 0x01020c020000010dULL, }, - { 0x0000ff0001000109ULL, 0x0700000808010200ULL, }, - { 0x0000000000000100ULL, 0x0301000000010608ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_d.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_d.c deleted file mode 100644 index 54d6fda1f260..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000003ULL, 0x0000000000000003ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000005ULL, 0x0000000000000005ULL, }, - { 0x0000000000000001ULL, 0x0000000000000004ULL, }, - { 0x0000000000000009ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000003ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000006ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000003ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000007ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000004ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000008ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000007ULL, }, - { 0x0000000000000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_h.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_h.c deleted file mode 100644 index 5a729906ace3..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0005000500050005ULL, 0x0005000500050005ULL, }, - { 0x0001000400010001ULL, 0x0004000100010004ULL, }, - { 0x0009000100020009ULL, 0x0001000200090001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x0000000300010000ULL, 0x0003000100000003ULL, }, - { 0x0006000000010006ULL, 0x0000000100060000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0x0003000000000003ULL, 0x0000000000030000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0000000300010000ULL, 0x0003000100000003ULL, }, - { 0x0007000100010007ULL, 0x0001000100070001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000000000001ULL, 0x0000000000010000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0001000000000001ULL, 0x0000000000010000ULL, }, - { 0x0002000000010002ULL, 0x0000000100020000ULL, }, - { 0x0001000000000001ULL, 0x0000000000010000ULL, }, - { 0x0004000100020004ULL, 0x0001000200040001ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0008000000010008ULL, 0x0000000100080000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, - { 0x0000000200010000ULL, 0x0002000100000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000300020000ULL, 0x0003000200000003ULL, }, - { 0x0000000300000000ULL, 0x0003000000000003ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 64 */ - { 0x0000025400000000ULL, 0x00030000000b0002ULL, }, - { 0x0000000100000000ULL, 0x0001000000010004ULL, }, - { 0x0001000a00000000ULL, 0x0000000000010000ULL, }, - { 0x0001000000010002ULL, 0x0000001000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0001000000000001ULL, 0x0000000000000002ULL, }, - { 0x0002000000000000ULL, 0x0000000100000000ULL, }, - { 0x0001000000040001ULL, 0x0000001100000000ULL, }, /* 72 */ - { 0x000001c300020000ULL, 0x0002000100080000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x0001000700010000ULL, 0x0000000100010000ULL, }, - { 0x0000000000020002ULL, 0x0001000c00000001ULL, }, - { 0x0000003900010001ULL, 0x0007000000070002ULL, }, - { 0x0000000000000001ULL, 0x0003000000000006ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_w.c b/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_w.c deleted file mode 100644 index e9e2da471814..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-divide/test_msa_div_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DIV_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Divide"; - char *instruction_name = "DIV_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000300000003ULL, 0x0000000300000003ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000500000005ULL, 0x0000000500000005ULL, }, - { 0x0000000100000001ULL, 0x0000000400000001ULL, }, - { 0x0000000900000002ULL, 0x0000000100000009ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000300000003ULL, 0x0000000300000003ULL, }, - { 0x0000000000000001ULL, 0x0000000300000000ULL, }, - { 0x0000000600000001ULL, 0x0000000000000006ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x0000000300000000ULL, 0x0000000000000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000000000001ULL, 0x0000000300000000ULL, }, - { 0x0000000700000001ULL, 0x0000000100000007ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000000ULL, 0x0000000000000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000100000000ULL, 0x0000000000000001ULL, }, - { 0x0000000200000001ULL, 0x0000000000000002ULL, }, - { 0x0000000100000000ULL, 0x0000000000000001ULL, }, - { 0x0000000400000002ULL, 0x0000000100000004ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000800000001ULL, 0x0000000000000008ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, - { 0x0000000000000001ULL, 0x0000000200000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000002ULL, 0x0000000300000000ULL, }, - { 0x0000000000000000ULL, 0x0000000300000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x000000030000000bULL, }, - { 0x0000000000000000ULL, 0x0000000100000001ULL, }, - { 0x0000000100000000ULL, 0x0000000000000001ULL, }, - { 0x0000000100000001ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000100000000ULL, 0x0000000000000000ULL, }, - { 0x0000000200000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000004ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000002ULL, 0x0000000200000008ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x0000000100000001ULL, 0x0000000000000001ULL, }, - { 0x0000000000000002ULL, 0x0000000100000000ULL, }, - { 0x0000000000000001ULL, 0x0000000700000007ULL, }, - { 0x0000000000000000ULL, 0x0000000300000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DIV_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_d.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_d.c deleted file mode 100644 index cb13ff3e751a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DOTP_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DOTP_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaacULL, 0x00000000aaaaaaacULL, }, - { 0xffffffff55555556ULL, 0xffffffff55555556ULL, }, - { 0x0000000066666668ULL, 0x0000000066666668ULL, }, - { 0xffffffff9999999aULL, 0xffffffff9999999aULL, }, - { 0x000000008e38e38fULL, 0xffffffffe38e38e5ULL, }, - { 0xffffffff71c71c73ULL, 0x000000001c71c71dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaacULL, 0x00000000aaaaaaacULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e38e39c71c71c8ULL, 0x38e38e39c71c71c8ULL, }, - { 0xc71c71c6e38e38e4ULL, 0xc71c71c6e38e38e4ULL, }, - { 0x22222222eeeeeef0ULL, 0x22222222eeeeeef0ULL, }, - { 0xddddddddbbbbbbbcULL, 0xddddddddbbbbbbbcULL, }, - { 0x2f684bdab425ed0aULL, 0xf684bda197b425eeULL, }, - { 0xd097b425f684bda2ULL, 0x097b425f12f684beULL, }, - { 0xffffffff55555556ULL, 0xffffffff55555556ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c6e38e38e4ULL, 0xc71c71c6e38e38e4ULL, }, - { 0x38e38e3871c71c72ULL, 0x38e38e3871c71c72ULL, }, - { 0xdddddddd77777778ULL, 0xdddddddd77777778ULL, }, - { 0x22222221dddddddeULL, 0x22222221dddddddeULL, }, - { 0xd097b425da12f685ULL, 0x097b425e4bda12f7ULL, }, - { 0x2f684bd97b425ed1ULL, 0xf684bda1097b425fULL, }, - { 0x0000000066666668ULL, 0x0000000066666668ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x22222222eeeeeef0ULL, 0x22222222eeeeeef0ULL, }, - { 0xdddddddd77777778ULL, 0xdddddddd77777778ULL, }, - { 0x147ae14851eb8520ULL, 0x147ae14851eb8520ULL, }, - { 0xeb851eb8147ae148ULL, 0xeb851eb8147ae148ULL, }, - { 0x1c71c71d0b60b60cULL, 0xfa4fa4fa82d82d84ULL, }, - { 0xe38e38e35b05b05cULL, 0x05b05b05e38e38e4ULL, }, - { 0xffffffff9999999aULL, 0xffffffff9999999aULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xddddddddbbbbbbbcULL, 0xddddddddbbbbbbbcULL, }, - { 0x22222221dddddddeULL, 0x22222221dddddddeULL, }, - { 0xeb851eb8147ae148ULL, 0xeb851eb8147ae148ULL, }, - { 0x147ae147851eb852ULL, 0x147ae147851eb852ULL, }, - { 0xe38e38e382d82d83ULL, 0x05b05b0560b60b61ULL, }, - { 0x1c71c71c16c16c17ULL, 0xfa4fa4fa38e38e39ULL, }, - { 0x000000008e38e38fULL, 0xffffffffe38e38e5ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2f684bdab425ed0aULL, 0xf684bda197b425eeULL, }, - { 0xd097b425da12f685ULL, 0x097b425e4bda12f7ULL, }, - { 0x1c71c71d0b60b60cULL, 0xfa4fa4fa82d82d84ULL, }, - { 0xe38e38e382d82d83ULL, 0x05b05b0560b60b61ULL, }, - { 0x35ba78199add3c0dULL, 0x0fcd6e9dc0ca4589ULL, }, - { 0xca4587e6f35ba782ULL, 0xf032916222c3f35cULL, }, - { 0xffffffff71c71c73ULL, 0x000000001c71c71dULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd097b425f684bda2ULL, 0x097b425f12f684beULL, }, - { 0x2f684bd97b425ed1ULL, 0xf684bda1097b425fULL, }, - { 0xe38e38e35b05b05cULL, 0x05b05b05e38e38e4ULL, }, - { 0x1c71c71c16c16c17ULL, 0xfa4fa4fa38e38e39ULL, }, - { 0xca4587e6f35ba782ULL, 0xf032916222c3f35cULL, }, - { 0x35ba78187e6b74f1ULL, 0x0fcd6e9df9add3c1ULL, }, - { 0x3e3ad4ae1266c290ULL, 0x1637d725aebdb714ULL, }, /* 64 */ - { 0x0e3a0c27f7d6aae4ULL, 0x0575fbb7f08ff55cULL, }, - { 0x1c00082337c84b78ULL, 0x0c3d39640fde8392ULL, }, - { 0xda65cd5e9f696cdcULL, 0xdeeb6bec644a26d0ULL, }, - { 0x0e3a0c27f7d6aae4ULL, 0x0575fbb7f08ff55cULL, }, - { 0x17945c09b2e19689ULL, 0x032b395187d966b4ULL, }, - { 0xec1f0e54b5aa67beULL, 0xfbe95b6e67ae6296ULL, }, - { 0x1aad30609bff5437ULL, 0xf059a43d01b40370ULL, }, - { 0x1c00082337c84b78ULL, 0x0c3d39640fde8392ULL, }, /* 72 */ - { 0xec1f0e54b5aa67beULL, 0xfbe95b6e67ae6296ULL, }, - { 0x2e9326619bb7c8e4ULL, 0x225024d84d163b91ULL, }, - { 0xc17a5d0372a2a622ULL, 0x0afd6368668933a8ULL, }, - { 0xda65cd5e9f696cdcULL, 0xdeeb6bec644a26d0ULL, }, - { 0x1aad30609bff5437ULL, 0xf059a43d01b40370ULL, }, - { 0xc17a5d0372a2a622ULL, 0x0afd6368668933a8ULL, }, - { 0x53edf7dbd76122edULL, 0x50347e61c2f51a40ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_h.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_h.c deleted file mode 100644 index 19451ee57d5f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DOTP_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DOTP_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ac00ac00ac00acULL, 0x00ac00ac00ac00acULL, }, - { 0xff56ff56ff56ff56ULL, 0xff56ff56ff56ff56ULL, }, - { 0x0068006800680068ULL, 0x0068006800680068ULL, }, - { 0xff9aff9aff9aff9aULL, 0xff9aff9aff9aff9aULL, }, - { 0x008fffe5003a008fULL, 0xffe5003a008fffe5ULL, }, - { 0xff73001dffc8ff73ULL, 0x001dffc8ff73001dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00ac00ac00ac00acULL, 0x00ac00ac00ac00acULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x39c839c839c839c8ULL, 0x39c839c839c839c8ULL, }, - { 0xc6e4c6e4c6e4c6e4ULL, 0xc6e4c6e4c6e4c6e4ULL, }, - { 0x22f022f022f022f0ULL, 0x22f022f022f022f0ULL, }, - { 0xddbcddbcddbcddbcULL, 0xddbcddbcddbcddbcULL, }, - { 0x300af6ee137c300aULL, 0xf6ee137c300af6eeULL, }, - { 0xd0a209beed30d0a2ULL, 0x09beed30d0a209beULL, }, - { 0xff56ff56ff56ff56ULL, 0xff56ff56ff56ff56ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc6e4c6e4c6e4c6e4ULL, 0xc6e4c6e4c6e4c6e4ULL, }, - { 0x3872387238723872ULL, 0x3872387238723872ULL, }, - { 0xdd78dd78dd78dd78ULL, 0xdd78dd78dd78dd78ULL, }, - { 0x21de21de21de21deULL, 0x21de21de21de21deULL, }, - { 0xd08508f7ecbed085ULL, 0x08f7ecbed08508f7ULL, }, - { 0x2ed1f65f12982ed1ULL, 0xf65f12982ed1f65fULL, }, - { 0x0068006800680068ULL, 0x0068006800680068ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x22f022f022f022f0ULL, 0x22f022f022f022f0ULL, }, - { 0xdd78dd78dd78dd78ULL, 0xdd78dd78dd78dd78ULL, }, - { 0x1520152015201520ULL, 0x1520152015201520ULL, }, - { 0xeb48eb48eb48eb48ULL, 0xeb48eb48eb48eb48ULL, }, - { 0x1d0cfa840bc81d0cULL, 0xfa840bc81d0cfa84ULL, }, - { 0xe35c05e4f4a0e35cULL, 0x05e4f4a0e35c05e4ULL, }, - { 0xff9aff9aff9aff9aULL, 0xff9aff9aff9aff9aULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xddbcddbcddbcddbcULL, 0xddbcddbcddbcddbcULL, }, - { 0x21de21de21de21deULL, 0x21de21de21de21deULL, }, - { 0xeb48eb48eb48eb48ULL, 0xeb48eb48eb48eb48ULL, }, - { 0x1452145214521452ULL, 0x1452145214521452ULL, }, - { 0xe3830561f472e383ULL, 0x0561f472e3830561ULL, }, - { 0x1c17fa390b281c17ULL, 0xfa390b281c17fa39ULL, }, - { 0x008fffe5003a008fULL, 0xffe5003a008fffe5ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x300af6ee137c300aULL, 0xf6ee137c300af6eeULL, }, - { 0xd08508f7ecbed085ULL, 0x08f7ecbed08508f7ULL, }, - { 0x1d0cfa840bc81d0cULL, 0xfa840bc81d0cfa84ULL, }, - { 0xe3830561f472e383ULL, 0x0561f472e3830561ULL, }, - { 0x360d0f893f04360dULL, 0x0f893f04360d0f89ULL, }, - { 0xca82f05cc136ca82ULL, 0xf05cc136ca82f05cULL, }, - { 0xff73001dffc8ff73ULL, 0x001dffc8ff73001dULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd0a209beed30d0a2ULL, 0x09beed30d0a209beULL, }, - { 0x2ed1f65f12982ed1ULL, 0xf65f12982ed1f65fULL, }, - { 0xe35c05e4f4a0e35cULL, 0x05e4f4a0e35c05e4ULL, }, - { 0x1c17fa390b281c17ULL, 0xfa390b281c17fa39ULL, }, - { 0xca82f05cc136ca82ULL, 0xf05cc136ca82f05cULL, }, - { 0x34f10fc13e9234f1ULL, 0x0fc13e9234f10fc1ULL, }, - { 0x64240d342bc42c39ULL, 0x3f6a22fd3b1d1990ULL, }, /* 64 */ - { 0xe704ebe4e24eef13ULL, 0x01a706951e1be630ULL, }, - { 0x4ca419cce226b927ULL, 0xfb55fd241553f560ULL, }, - { 0xec36ee202172098aULL, 0xd846ec28206404e0ULL, }, - { 0xe704ebe4e24eef13ULL, 0x01a706951e1be630ULL, }, - { 0x111d264945920cf1ULL, 0x0195153d113a1a54ULL, }, - { 0xea70debeff82160dULL, 0x04260f88039c0b8aULL, }, - { 0xe9721dc70769091eULL, 0xf8711c48091bf7e4ULL, }, - { 0x4ca419cce226b927ULL, 0xfb55fd241553f560ULL, }, /* 72 */ - { 0xea70debeff82160dULL, 0x04260f88039c0b8aULL, }, - { 0x3b3437281d127579ULL, 0x0c310d25237206e9ULL, }, - { 0xf706df16dc8de6b6ULL, 0xf0d31b5827f9f42aULL, }, - { 0xec36ee202172098aULL, 0xd846ec28206404e0ULL, }, - { 0xe9721dc70769091eULL, 0xf8711c48091bf7e4ULL, }, - { 0xf706df16dc8de6b6ULL, 0xf0d31b5827f9f42aULL, }, - { 0x4961190d2be51b48ULL, 0x348a3e802e952784ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_w.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_w.c deleted file mode 100644 index e635888e6c04..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DOTP_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DOTP_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaac0000aaacULL, 0x0000aaac0000aaacULL, }, - { 0xffff5556ffff5556ULL, 0xffff5556ffff5556ULL, }, - { 0x0000666800006668ULL, 0x0000666800006668ULL, }, - { 0xffff999affff999aULL, 0xffff999affff999aULL, }, - { 0xffffe38f00008e3aULL, 0x000038e5ffffe38fULL, }, - { 0x00001c73ffff71c8ULL, 0xffffc71d00001c73ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaac0000aaacULL, 0x0000aaac0000aaacULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e471c838e471c8ULL, 0x38e471c838e471c8ULL, }, - { 0xc71c38e4c71c38e4ULL, 0xc71c38e4c71c38e4ULL, }, - { 0x2222eef02222eef0ULL, 0x2222eef02222eef0ULL, }, - { 0xddddbbbcddddbbbcULL, 0xddddbbbcddddbbbcULL, }, - { 0xf684ed0a2f69097cULL, 0x12f725eef684ed0aULL, }, - { 0x097bbda2d097a130ULL, 0xed0984be097bbda2ULL, }, - { 0xffff5556ffff5556ULL, 0xffff5556ffff5556ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c38e4c71c38e4ULL, 0xc71c38e4c71c38e4ULL, }, - { 0x38e31c7238e31c72ULL, 0x38e31c7238e31c72ULL, }, - { 0xdddd7778dddd7778ULL, 0xdddd7778dddd7778ULL, }, - { 0x2221ddde2221dddeULL, 0x2221ddde2221dddeULL, }, - { 0x097af685d09784beULL, 0xed0912f7097af685ULL, }, - { 0xf6845ed12f67d098ULL, 0x12f6425ff6845ed1ULL, }, - { 0x0000666800006668ULL, 0x0000666800006668ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222eef02222eef0ULL, 0x2222eef02222eef0ULL, }, - { 0xdddd7778dddd7778ULL, 0xdddd7778dddd7778ULL, }, - { 0x147b8520147b8520ULL, 0x147b8520147b8520ULL, }, - { 0xeb84e148eb84e148ULL, 0xeb84e148eb84e148ULL, }, - { 0xfa4fb60c1c7271c8ULL, 0x0b612d84fa4fb60cULL, }, - { 0x05b0b05ce38df4a0ULL, 0xf49f38e405b0b05cULL, }, - { 0xffff999affff999aULL, 0xffff999affff999aULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xddddbbbcddddbbbcULL, 0xddddbbbcddddbbbcULL, }, - { 0x2221ddde2221dddeULL, 0x2221ddde2221dddeULL, }, - { 0xeb84e148eb84e148ULL, 0xeb84e148eb84e148ULL, }, - { 0x147ab852147ab852ULL, 0x147ab852147ab852ULL, }, - { 0x05b02d83e38e1c72ULL, 0xf49f0b6105b02d83ULL, }, - { 0xfa4f6c171c717d28ULL, 0x0b608e39fa4f6c17ULL, }, - { 0xffffe38f00008e3aULL, 0x000038e5ffffe38fULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xf684ed0a2f69097cULL, 0x12f725eef684ed0aULL, }, - { 0x097af685d09784beULL, 0xed0912f7097af685ULL, }, - { 0xfa4fb60c1c7271c8ULL, 0x0b612d84fa4fb60cULL, }, - { 0x05b02d83e38e1c72ULL, 0xf49f0b6105b02d83ULL, }, - { 0x0fcd3c0d35bb4f04ULL, 0x3f3645890fcd3c0dULL, }, - { 0xf032a782ca453f36ULL, 0xc0c9f35cf032a782ULL, }, - { 0x00001c73ffff71c8ULL, 0xffffc71d00001c73ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x097bbda2d097a130ULL, 0xed0984be097bbda2ULL, }, - { 0xf6845ed12f67d098ULL, 0x12f6425ff6845ed1ULL, }, - { 0x05b0b05ce38df4a0ULL, 0xf49f38e405b0b05cULL, }, - { 0xfa4f6c171c717d28ULL, 0x0b608e39fa4f6c17ULL, }, - { 0xf032a782ca453f36ULL, 0xc0c9f35cf032a782ULL, }, - { 0x0fcd74f135ba3292ULL, 0x3f35d3c10fcd74f1ULL, }, - { 0x3a57fe7422c25584ULL, 0x16b6b9f518facfa9ULL, }, /* 64 */ - { 0x01f36d90f9441446ULL, 0x0286cfede5f4db15ULL, }, - { 0x2f1518bcce21d93eULL, 0x0934568af4ec6499ULL, }, - { 0xc9576c1204f83042ULL, 0xd91d3e4709b06e36ULL, }, - { 0x01f36d90f9441446ULL, 0x0286cfede5f4db15ULL, }, - { 0x0012474d242f32a9ULL, 0x13f2a8f51ca9cd91ULL, }, - { 0x0144b48a04a7d0ddULL, 0x124b1c4e04fa8e45ULL, }, - { 0xfe2a6f6923268793ULL, 0x179e9377ef4766beULL, }, - { 0x2f1518bcce21d93eULL, 0x0934568af4ec6499ULL, }, /* 72 */ - { 0x0144b48a04a7d0ddULL, 0x124b1c4e04fa8e45ULL, }, - { 0x352c988848431561ULL, 0x12e4f841217b42c9ULL, }, - { 0xd437b4e8f3b0139fULL, 0x08c7d980187d5896ULL, }, - { 0xc9576c1204f83042ULL, 0xd91d3e4709b06e36ULL, }, - { 0xfe2a6f6923268793ULL, 0x179e9377ef4766beULL, }, - { 0xd437b4e8f3b0139fULL, 0x08c7d980187d5896ULL, }, - { 0x33368b8a2619d525ULL, 0x6a47932120c31904ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_d.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_d.c deleted file mode 100644 index af4337d02c9a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DOTP_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DOTP_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffc00000002ULL, 0xfffffffc00000002ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x55555552aaaaaaacULL, 0x55555552aaaaaaacULL, }, - { 0xaaaaaaa955555556ULL, 0xaaaaaaa955555556ULL, }, - { 0x9999999666666668ULL, 0x9999999666666668ULL, }, - { 0x666666659999999aULL, 0x666666659999999aULL, }, - { 0x71c71c6f8e38e38fULL, 0x1c71c719e38e38e5ULL, }, - { 0x8e38e38c71c71c73ULL, 0xe38e38e21c71c71dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x55555552aaaaaaacULL, 0x55555552aaaaaaacULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e1c71c71c8ULL, 0xe38e38e1c71c71c8ULL, }, - { 0x71c71c70e38e38e4ULL, 0x71c71c70e38e38e4ULL, }, - { 0x1111110eeeeeeef0ULL, 0x1111110eeeeeeef0ULL, }, - { 0x44444443bbbbbbbcULL, 0x44444443bbbbbbbcULL, }, - { 0xf684bd9fb425ed0aULL, 0xbda12f6697b425eeULL, }, - { 0x5ed097b2f684bda2ULL, 0x97b425ec12f684beULL, }, - { 0xaaaaaaa955555556ULL, 0xaaaaaaa955555556ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x71c71c70e38e38e4ULL, 0x71c71c70e38e38e4ULL, }, - { 0x38e38e3871c71c72ULL, 0x38e38e3871c71c72ULL, }, - { 0x8888888777777778ULL, 0x8888888777777778ULL, }, - { 0x22222221dddddddeULL, 0x22222221dddddddeULL, }, - { 0x7b425ecfda12f685ULL, 0x5ed097b34bda12f7ULL, }, - { 0x2f684bd97b425ed1ULL, 0x4bda12f6097b425fULL, }, - { 0x9999999666666668ULL, 0x9999999666666668ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1111110eeeeeeef0ULL, 0x1111110eeeeeeef0ULL, }, - { 0x8888888777777778ULL, 0x8888888777777778ULL, }, - { 0x47ae147851eb8520ULL, 0x47ae147851eb8520ULL, }, - { 0x51eb851e147ae148ULL, 0x51eb851e147ae148ULL, }, - { 0x27d27d260b60b60cULL, 0xe38e38e182d82d84ULL, }, - { 0x71c71c705b05b05cULL, 0xb60b60b4e38e38e4ULL, }, - { 0x666666659999999aULL, 0x666666659999999aULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x44444443bbbbbbbcULL, 0x44444443bbbbbbbcULL, }, - { 0x22222221dddddddeULL, 0x22222221dddddddeULL, }, - { 0x51eb851e147ae148ULL, 0x51eb851e147ae148ULL, }, - { 0x147ae147851eb852ULL, 0x147ae147851eb852ULL, }, - { 0x49f49f4982d82d83ULL, 0x38e38e3860b60b61ULL, }, - { 0x1c71c71c16c16c17ULL, 0x2d82d82d38e38e39ULL, }, - { 0x71c71c6f8e38e38fULL, 0x1c71c719e38e38e5ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xf684bd9fb425ed0aULL, 0xbda12f6697b425eeULL, }, - { 0x7b425ecfda12f685ULL, 0x5ed097b34bda12f7ULL, }, - { 0x27d27d260b60b60cULL, 0xe38e38e182d82d84ULL, }, - { 0x49f49f4982d82d83ULL, 0x38e38e3860b60b61ULL, }, - { 0x1948b0fb9add3c0dULL, 0xd6e9e063c0ca4589ULL, }, - { 0x587e6b73f35ba782ULL, 0x4587e6b622c3f35cULL, }, - { 0x8e38e38c71c71c73ULL, 0xe38e38e21c71c71dULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5ed097b2f684bda2ULL, 0x97b425ec12f684beULL, }, - { 0x2f684bd97b425ed1ULL, 0x4bda12f6097b425fULL, }, - { 0x71c71c705b05b05cULL, 0xb60b60b4e38e38e4ULL, }, - { 0x1c71c71c16c16c17ULL, 0x2d82d82d38e38e39ULL, }, - { 0x587e6b73f35ba782ULL, 0x4587e6b622c3f35cULL, }, - { 0x35ba78187e6b74f1ULL, 0x9e06522bf9add3c1ULL, }, - { 0x4f10a2461266c290ULL, 0x132f373daebdb714ULL, }, /* 64 */ - { 0x9262f356f7d6aae4ULL, 0x1ab54eb3f08ff55cULL, }, - { 0x7927f2d937c84b78ULL, 0xb5e40e840fde8392ULL, }, - { 0x4ab4e3ab9f696cdcULL, 0xd21109f6644a26d0ULL, }, - { 0x9262f356f7d6aae4ULL, 0x1ab54eb3f08ff55cULL, }, - { 0x0f105ccfb2e19689ULL, 0x032b395187d966b4ULL, }, - { 0xe1cb8469b5aa67beULL, 0x1128ae6a67ae6296ULL, }, - { 0x8afc46ad9bff5437ULL, 0x1890b25301b40370ULL, }, - { 0x7927f2d937c84b78ULL, 0xb5e40e840fde8392ULL, }, /* 72 */ - { 0xe1cb8469b5aa67beULL, 0x1128ae6a67ae6296ULL, }, - { 0xfae79ab59bb7c8e4ULL, 0x78a66f004d163b91ULL, }, - { 0x8ffb559e72a2a622ULL, 0x8744321b668933a8ULL, }, - { 0x4ab4e3ab9f696cdcULL, 0xd21109f6644a26d0ULL, }, - { 0x8afc46ad9bff5437ULL, 0x1890b25301b40370ULL, }, - { 0x8ffb559e72a2a622ULL, 0x8744321b668933a8ULL, }, - { 0x53edf7dbd76122edULL, 0xbe9d5551c2f51a40ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_h.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_h.c deleted file mode 100644 index a87b72b121ed..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DOTP_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DOTP_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfc02fc02fc02fc02ULL, 0xfc02fc02fc02fc02ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x52ac52ac52ac52acULL, 0x52ac52ac52ac52acULL, }, - { 0xa956a956a956a956ULL, 0xa956a956a956a956ULL, }, - { 0x9668966896689668ULL, 0x9668966896689668ULL, }, - { 0x659a659a659a659aULL, 0x659a659a659a659aULL, }, - { 0x6f8f19e5c53a6f8fULL, 0x19e5c53a6f8f19e5ULL, }, - { 0x8c73e21d36c88c73ULL, 0xe21d36c88c73e21dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x52ac52ac52ac52acULL, 0x52ac52ac52ac52acULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe1c8e1c8e1c8e1c8ULL, 0xe1c8e1c8e1c8e1c8ULL, }, - { 0x70e470e470e470e4ULL, 0x70e470e470e470e4ULL, }, - { 0x0ef00ef00ef00ef0ULL, 0x0ef00ef00ef00ef0ULL, }, - { 0x43bc43bc43bc43bcULL, 0x43bc43bc43bc43bcULL, }, - { 0xf50abbee837cf50aULL, 0xbbee837cf50abbeeULL, }, - { 0x5da296becf305da2ULL, 0x96becf305da296beULL, }, - { 0xa956a956a956a956ULL, 0xa956a956a956a956ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x70e470e470e470e4ULL, 0x70e470e470e470e4ULL, }, - { 0x3872387238723872ULL, 0x3872387238723872ULL, }, - { 0x8778877887788778ULL, 0x8778877887788778ULL, }, - { 0x21de21de21de21deULL, 0x21de21de21de21deULL, }, - { 0x7a855df741be7a85ULL, 0x5df741be7a855df7ULL, }, - { 0x2ed14b5f67982ed1ULL, 0x4b5f67982ed14b5fULL, }, - { 0x9668966896689668ULL, 0x9668966896689668ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0ef00ef00ef00ef0ULL, 0x0ef00ef00ef00ef0ULL, }, - { 0x8778877887788778ULL, 0x8778877887788778ULL, }, - { 0x4520452045204520ULL, 0x4520452045204520ULL, }, - { 0x5148514851485148ULL, 0x5148514851485148ULL, }, - { 0x260ce1849dc8260cULL, 0xe1849dc8260ce184ULL, }, - { 0x705cb4e4f8a0705cULL, 0xb4e4f8a0705cb4e4ULL, }, - { 0x659a659a659a659aULL, 0x659a659a659a659aULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x43bc43bc43bc43bcULL, 0x43bc43bc43bc43bcULL, }, - { 0x21de21de21de21deULL, 0x21de21de21de21deULL, }, - { 0x5148514851485148ULL, 0x5148514851485148ULL, }, - { 0x1452145214521452ULL, 0x1452145214521452ULL, }, - { 0x4983386127724983ULL, 0x3861277249833861ULL, }, - { 0x1c172d393e281c17ULL, 0x2d393e281c172d39ULL, }, - { 0x6f8f19e5c53a6f8fULL, 0x19e5c53a6f8f19e5ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xf50abbee837cf50aULL, 0xbbee837cf50abbeeULL, }, - { 0x7a855df741be7a85ULL, 0x5df741be7a855df7ULL, }, - { 0x260ce1849dc8260cULL, 0xe1849dc8260ce184ULL, }, - { 0x4983386127724983ULL, 0x3861277249833861ULL, }, - { 0x180dd5895b04180dULL, 0xd5895b04180dd589ULL, }, - { 0x5782445c6a365782ULL, 0x445c6a365782445cULL, }, - { 0x8c73e21d36c88c73ULL, 0xe21d36c88c73e21dULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5da296becf305da2ULL, 0x96becf305da296beULL, }, - { 0x2ed14b5f67982ed1ULL, 0x4b5f67982ed14b5fULL, }, - { 0x705cb4e4f8a0705cULL, 0xb4e4f8a0705cb4e4ULL, }, - { 0x1c172d393e281c17ULL, 0x2d393e281c172d39ULL, }, - { 0x5782445c6a365782ULL, 0x445c6a365782445cULL, }, - { 0x34f19dc1cc9234f1ULL, 0x9dc1cc9234f19dc1ULL, }, - { 0x742471342bc42c39ULL, 0x3f6a22fd371d7990ULL, }, /* 64 */ - { 0xd4044ee4444e4413ULL, 0x68a71195331b4430ULL, }, - { 0x80a423cc6c264e27ULL, 0x62556624be531a60ULL, }, - { 0x5c36512021725e8aULL, 0x8a465528c764a2e0ULL, }, - { 0xd4044ee4444e4413ULL, 0x68a71195331b4430ULL, }, - { 0x831d26496b929af1ULL, 0xef958b3d113a1254ULL, }, - { 0xeb7041beae82700dULL, 0xd326aa88189c1f8aULL, }, - { 0xa8721dc73869b21eULL, 0xf27179481e1be5e4ULL, }, - { 0x80a423cc6c264e27ULL, 0x62556624be531a60ULL, }, /* 72 */ - { 0xeb7041beae82700dULL, 0xd326aa88189c1f8aULL, }, - { 0x9334e7282d128b79ULL, 0xbc319725797206e9ULL, }, - { 0x670642166b8da1b6ULL, 0xe0d340587bf92d2aULL, }, - { 0x5c36512021725e8aULL, 0x8a465528c764a2e0ULL, }, - { 0xa8721dc73869b21eULL, 0xf27179481e1be5e4ULL, }, - { 0x670642166b8da1b6ULL, 0xe0d340587bf92d2aULL, }, - { 0x4961190d2be5df48ULL, 0x308afe8080952b84ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_w.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_w.c deleted file mode 100644 index 05df4cb58311..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dotp_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction DOTP_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DOTP_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffc0002fffc0002ULL, 0xfffc0002fffc0002ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5552aaac5552aaacULL, 0x5552aaac5552aaacULL, }, - { 0xaaa95556aaa95556ULL, 0xaaa95556aaa95556ULL, }, - { 0x9996666899966668ULL, 0x9996666899966668ULL, }, - { 0x6665999a6665999aULL, 0x6665999a6665999aULL, }, - { 0x1c6fe38f71c48e3aULL, 0xc71a38e51c6fe38fULL, }, - { 0xe38c1c738e3771c8ULL, 0x38e1c71de38c1c73ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5552aaac5552aaacULL, 0x5552aaac5552aaacULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38c71c8e38c71c8ULL, 0xe38c71c8e38c71c8ULL, }, - { 0x71c638e471c638e4ULL, 0x71c638e471c638e4ULL, }, - { 0x110eeef0110eeef0ULL, 0x110eeef0110eeef0ULL, }, - { 0x4443bbbc4443bbbcULL, 0x4443bbbc4443bbbcULL, }, - { 0xbd9fed0af683097cULL, 0x84bc25eebd9fed0aULL, }, - { 0x97b2bda25ecfa130ULL, 0xd09684be97b2bda2ULL, }, - { 0xaaa95556aaa95556ULL, 0xaaa95556aaa95556ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x71c638e471c638e4ULL, 0x71c638e471c638e4ULL, }, - { 0x38e31c7238e31c72ULL, 0x38e31c7238e31c72ULL, }, - { 0x8887777888877778ULL, 0x8887777888877778ULL, }, - { 0x2221ddde2221dddeULL, 0x2221ddde2221dddeULL, }, - { 0x5ecff6857b4184beULL, 0x425e12f75ecff685ULL, }, - { 0x4bd95ed12f67d098ULL, 0x684b425f4bd95ed1ULL, }, - { 0x9996666899966668ULL, 0x9996666899966668ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x110eeef0110eeef0ULL, 0x110eeef0110eeef0ULL, }, - { 0x8887777888877778ULL, 0x8887777888877778ULL, }, - { 0x47ab852047ab8520ULL, 0x47ab852047ab8520ULL, }, - { 0x51eae14851eae148ULL, 0x51eae14851eae148ULL, }, - { 0xe38cb60c27d071c8ULL, 0x9f482d84e38cb60cULL, }, - { 0xb609b05c71c5f4a0ULL, 0xfa4e38e4b609b05cULL, }, - { 0x6665999a6665999aULL, 0x6665999a6665999aULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4443bbbc4443bbbcULL, 0x4443bbbc4443bbbcULL, }, - { 0x2221ddde2221dddeULL, 0x2221ddde2221dddeULL, }, - { 0x51eae14851eae148ULL, 0x51eae14851eae148ULL, }, - { 0x147ab852147ab852ULL, 0x147ab852147ab852ULL, }, - { 0x38e32d8349f41c72ULL, 0x27d20b6138e32d83ULL, }, - { 0x2d826c171c717d28ULL, 0x3e938e392d826c17ULL, }, - { 0x1c6fe38f71c48e3aULL, 0xc71a38e51c6fe38fULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xbd9fed0af683097cULL, 0x84bc25eebd9fed0aULL, }, - { 0x5ecff6857b4184beULL, 0x425e12f75ecff685ULL, }, - { 0xe38cb60c27d071c8ULL, 0x9f482d84e38cb60cULL, }, - { 0x38e32d8349f41c72ULL, 0x27d20b6138e32d83ULL, }, - { 0xd6e93c0d19474f04ULL, 0x5ba64589d6e93c0dULL, }, - { 0x4586a782587d3f36ULL, 0x6b73f35c4586a782ULL, }, - { 0xe38c1c738e3771c8ULL, 0x38e1c71de38c1c73ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x97b2bda25ecfa130ULL, 0xd09684be97b2bda2ULL, }, - { 0x4bd95ed12f67d098ULL, 0x684b425f4bd95ed1ULL, }, - { 0xb609b05c71c5f4a0ULL, 0xfa4e38e4b609b05cULL, }, - { 0x2d826c171c717d28ULL, 0x3e938e392d826c17ULL, }, - { 0x4586a782587d3f36ULL, 0x6b73f35c4586a782ULL, }, - { 0x9e0574f135ba3292ULL, 0xcd6dd3c19e0574f1ULL, }, - { 0x18c3fe7422c25584ULL, 0x16b6b9f57608cfa9ULL, }, /* 64 */ - { 0x867e6d904e841446ULL, 0x0de4cfed4e2fdb15ULL, }, - { 0xf94f18bc4bc3d93eULL, 0x1492568ac3a66499ULL, }, - { 0x4ff36c125a383042ULL, 0x2fe23e4744196e36ULL, }, - { 0x867e6d904e841446ULL, 0x0de4cfed4e2fdb15ULL, }, - { 0xf78e474db23f32a9ULL, 0x8a26a8f51ca9cd91ULL, }, - { 0xa9bfb48aa4c2d0ddULL, 0x94641c4e1a398e45ULL, }, - { 0x6e796f69cc7c8793ULL, 0x6e879377578266beULL, }, - { 0xf94f18bc4bc3d93eULL, 0x1492568ac3a66499ULL, }, /* 72 */ - { 0xa9bfb48aa4c2d0ddULL, 0x94641c4e1a398e45ULL, }, - { 0xeb349888d2e11561ULL, 0xa0e2f84177d142c9ULL, }, - { 0x5ad3b4e8bfaf139fULL, 0x8076d98091fe5896ULL, }, - { 0x4ff36c125a383042ULL, 0x2fe23e4744196e36ULL, }, - { 0x6e796f69cc7c8793ULL, 0x6e879377578266beULL, }, - { 0x5ad3b4e8bfaf139fULL, 0x8076d98091fe5896ULL, }, - { 0x33368b8aeab5d525ULL, 0x97d9932138871904ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DOTP_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_d.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_d.c deleted file mode 100644 index d039e1a785f5..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPADD_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPADD_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */ - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, - { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x000000006666666cULL, 0x000000006666666cULL, }, - { 0x0000000000000006ULL, 0x0000000000000006ULL, }, - { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */ - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */ - { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, - { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, }, - { 0x0000000155555560ULL, 0x0000000155555560ULL, }, - { 0x2222222444444450ULL, 0x2222222444444450ULL, }, - { 0x000000020000000cULL, 0x000000020000000cULL, }, - { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, }, - { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, }, - { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */ - { 0x000000020000000eULL, 0x000000020000000eULL, }, - { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, }, - { 0x0000000155555564ULL, 0x0000000155555564ULL, }, - { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, }, - { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, }, - { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, }, - { 0x0000000000000010ULL, 0x0000000000000010ULL, }, - { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */ - { 0x0000000066666678ULL, 0x0000000066666678ULL, }, - { 0x2222222355555568ULL, 0x2222222355555568ULL, }, - { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, }, - { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, }, - { 0x0000000133333348ULL, 0x0000000133333348ULL, }, - { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, }, - { 0x00000001999999b0ULL, 0x00000001999999b0ULL, }, - { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */ - { 0x000000013333334aULL, 0x000000013333334aULL, }, - { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, }, - { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, }, - { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, }, - { 0x000000006666667eULL, 0x000000006666667eULL, }, - { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, }, - { 0x0000000000000018ULL, 0x0000000000000018ULL, }, - { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */ - { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, - { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, }, - { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, }, - { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, }, - { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, }, - { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, }, - { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, }, - { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */ - { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, - { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, }, - { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, }, - { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, }, - { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, }, - { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, }, - { 0x0000000000000020ULL, 0x0000000000000020ULL, }, - { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */ - { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, }, - { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, }, - { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, }, - { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, }, - { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, }, - { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, }, - { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, }, - { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */ - { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, }, - { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, }, - { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, }, - { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, }, - { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, }, - { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, }, - { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, }, - { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */ - { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, }, - { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, }, - { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, }, - { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, }, - { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, }, - { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, }, - { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, }, - { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */ - { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, }, - { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, }, - { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, }, - { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, }, - { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, }, - { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, }, - { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, }, - { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */ - { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, }, - { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, }, - { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, }, - { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, }, - { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, }, - { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, }, - { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, }, - { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */ - { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, }, - { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, }, - { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, }, - { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, }, - { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, }, - { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, }, - { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_h.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_h.c deleted file mode 100644 index bcaafe3b71f1..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPADD_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPADD_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, /* 0 */ - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x00ae00ae00ae00aeULL, 0x00ae00ae00ae00aeULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x006c006c006c006cULL, 0x006c006c006c006cULL, }, - { 0x0006000600060006ULL, 0x0006000600060006ULL, }, - { 0x0095ffeb00400095ULL, 0xffeb00400095ffebULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, /* 8 */ - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x00b400b400b400b4ULL, 0x00b400b400b400b4ULL, }, /* 16 */ - { 0x00b400b400b400b4ULL, 0x00b400b400b400b4ULL, }, - { 0x3a7c3a7c3a7c3a7cULL, 0x3a7c3a7c3a7c3a7cULL, }, - { 0x0160016001600160ULL, 0x0160016001600160ULL, }, - { 0x2450245024502450ULL, 0x2450245024502450ULL, }, - { 0x020c020c020c020cULL, 0x020c020c020c020cULL, }, - { 0x3216f8fa15883216ULL, 0xf8fa15883216f8faULL, }, - { 0x02b802b802b802b8ULL, 0x02b802b802b802b8ULL, }, - { 0x020e020e020e020eULL, 0x020e020e020e020eULL, }, /* 24 */ - { 0x020e020e020e020eULL, 0x020e020e020e020eULL, }, - { 0xc8f2c8f2c8f2c8f2ULL, 0xc8f2c8f2c8f2c8f2ULL, }, - { 0x0164016401640164ULL, 0x0164016401640164ULL, }, - { 0xdedcdedcdedcdedcULL, 0xdedcdedcdedcdedcULL, }, - { 0x00ba00ba00ba00baULL, 0x00ba00ba00ba00baULL, }, - { 0xd13f09b1ed78d13fULL, 0x09b1ed78d13f09b1ULL, }, - { 0x0010001000100010ULL, 0x0010001000100010ULL, }, - { 0x0078007800780078ULL, 0x0078007800780078ULL, }, /* 32 */ - { 0x0078007800780078ULL, 0x0078007800780078ULL, }, - { 0x2368236823682368ULL, 0x2368236823682368ULL, }, - { 0x00e000e000e000e0ULL, 0x00e000e000e000e0ULL, }, - { 0x1600160016001600ULL, 0x1600160016001600ULL, }, - { 0x0148014801480148ULL, 0x0148014801480148ULL, }, - { 0x1e54fbcc0d101e54ULL, 0xfbcc0d101e54fbccULL, }, - { 0x01b001b001b001b0ULL, 0x01b001b001b001b0ULL, }, - { 0x014a014a014a014aULL, 0x014a014a014a014aULL, }, /* 40 */ - { 0x014a014a014a014aULL, 0x014a014a014a014aULL, }, - { 0xdf06df06df06df06ULL, 0xdf06df06df06df06ULL, }, - { 0x00e400e400e400e4ULL, 0x00e400e400e400e4ULL, }, - { 0xec2cec2cec2cec2cULL, 0xec2cec2cec2cec2cULL, }, - { 0x007e007e007e007eULL, 0x007e007e007e007eULL, }, - { 0xe40105dff4f0e401ULL, 0x05dff4f0e40105dfULL, }, - { 0x0018001800180018ULL, 0x0018001800180018ULL, }, - { 0x00a7fffd005200a7ULL, 0xfffd005200a7fffdULL, }, /* 48 */ - { 0x00a7fffd005200a7ULL, 0xfffd005200a7fffdULL, }, - { 0x30b1f6eb13ce30b1ULL, 0xf6eb13ce30b1f6ebULL, }, - { 0x0136ffe2008c0136ULL, 0xffe2008c0136ffe2ULL, }, - { 0x1e42fa660c541e42ULL, 0xfa660c541e42fa66ULL, }, - { 0x01c5ffc700c601c5ULL, 0xffc700c601c5ffc7ULL, }, - { 0x37d20f503fca37d2ULL, 0x0f503fca37d20f50ULL, }, - { 0x0254ffac01000254ULL, 0xffac01000254ffacULL, }, - { 0x01c7ffc900c801c7ULL, 0xffc900c801c7ffc9ULL, }, /* 56 */ - { 0x01c7ffc900c801c7ULL, 0xffc900c801c7ffc9ULL, }, - { 0xd2690987edf8d269ULL, 0x0987edf8d2690987ULL, }, - { 0x013affe60090013aULL, 0xffe60090013affe6ULL, }, - { 0xe49605caf530e496ULL, 0x05caf530e49605caULL, }, - { 0x00ad0003005800adULL, 0x0003005800ad0003ULL, }, - { 0xcb2ff05fc18ecb2fULL, 0xf05fc18ecb2ff05fULL, }, - { 0x0020002000200020ULL, 0x0020002000200020ULL, }, - { 0x64440d542be42c59ULL, 0x3f8a231d3b3d19b0ULL, }, /* 64 */ - { 0x4b48f9380e321b6cULL, 0x413129b25958ffe0ULL, }, - { 0x97ec1304f058d493ULL, 0x3c8626d66eabf540ULL, }, - { 0x8422012411cade1dULL, 0x14cc12fe8f0ffa20ULL, }, - { 0x6b26ed08f418cd30ULL, 0x16731993ad2ae050ULL, }, - { 0x7c43135139aada21ULL, 0x18082ed0be64faa4ULL, }, - { 0x66b3f20f392cf02eULL, 0x1c2e3e58c200062eULL, }, - { 0x50250fd64095f94cULL, 0x149f5aa0cb1bfe12ULL, }, - { 0x9cc929a222bbb273ULL, 0x0ff457c4e06ef372ULL, }, /* 72 */ - { 0x87390860223dc880ULL, 0x141a674ce40afefcULL, }, - { 0xc26d3f883f4f3df9ULL, 0x204b7471077c05e5ULL, }, - { 0xb9731e9e1bdc24afULL, 0x111e8fc92f75fa0fULL, }, - { 0xa5a90cbe3d4e2e39ULL, 0xe9647bf14fd9feefULL, }, - { 0x8f1b2a8544b73757ULL, 0xe1d5983958f4f6d3ULL, }, - { 0x8621099b21441e0dULL, 0xd2a8b39180edeafdULL, }, - { 0xcf8222a84d293955ULL, 0x0732f211af821281ULL, }, - { 0xb24e311468e36182ULL, 0x1d5df7b5739a06edULL, }, /* 80 */ - { 0x9fb838d0948447f9ULL, 0x1c22f28463ef0925ULL, }, - { 0xa63c3700ca342b06ULL, 0x1b16f62c40350d56ULL, }, - { 0x91603bbac05427d0ULL, 0x0dabf3fc381feb90ULL, }, - { 0xed2843f4d67c28c3ULL, 0xef47f1f54694ece0ULL, }, - { 0xe3373f50950e1df3ULL, 0xeb96f4e231bee6f8ULL, }, - { 0x00111042b00d1732ULL, 0xf8f3f7b81663e296ULL, }, - { 0x0550257c952a23bcULL, 0xfd4e0730286f0ddaULL, }, - { 0x2418088a94861e5bULL, 0x1bcf191d5d740802ULL, }, /* 88 */ - { 0x1d34dae8a7fc1a85ULL, 0x1f6e155281a10a8aULL, }, - { 0x25f8ef24c16f4c23ULL, 0x12f7103e9bd702c4ULL, }, - { 0x33b0f882bf8c4de5ULL, 0x0b68ff0eb3981908ULL, }, - { 0xfaa812ea88fc60b6ULL, 0x38790427823a1198ULL, }, - { 0x11760a6866984906ULL, 0x38280709862a18aaULL, }, - { 0x355ee4445e3624a9ULL, 0x3a70056ab5ba156aULL, }, - { 0x6990f6508b1005efULL, 0x19d2f282bd2beb34ULL, }, - { 0x09f8e7147ee80358ULL, 0x0ea3c3a4d25af434ULL, }, /* 96 */ - { 0x0270e58e89681a57ULL, 0xed529f3dfdf4fa64ULL, }, - { 0x2fe0ff749ea038b9ULL, 0x08bfb178f83600f4ULL, }, - { 0x0c98e7fe6a903991ULL, 0xf0f0da2312380064ULL, }, - { 0x272ce738ba222968ULL, 0xf060e7ef217afed4ULL, }, - { 0x1b11fce0969a2387ULL, 0xebe0ecf24235fee0ULL, }, - { 0x1628f080a22617f4ULL, 0xeb86f0ea54aafebcULL, }, - { 0x0b6abf0075b21275ULL, 0xee56f2fe4664ff28ULL, }, - { 0x2d12d3d2642dcfbbULL, 0xde28f62c3ff20223ULL, }, /* 104 */ - { 0x24a2f1b03fd408a0ULL, 0xd2baf84428ad0529ULL, }, - { 0xf7c6115e36c734f8ULL, 0xd6a8f9d00d740916ULL, }, - { 0xe656ec5832b62134ULL, 0xde02fb961c9f0c1bULL, }, - { 0xf580051836e82d2eULL, 0xed2a0e7efa190093ULL, }, - { 0xc9300cbe462435ecULL, 0xf33df43e02952973ULL, }, - { 0xbff0f9ec66bc299eULL, 0xf581f02ee651f985ULL, }, - { 0x9e90f34e7f2c06f4ULL, 0x01e3f07e04092877ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_w.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_w.c deleted file mode 100644 index 90562ab8a57a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_s_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPADD_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPADD_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, /* 0 */ - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x0000aaae0000aaaeULL, 0x0000aaae0000aaaeULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000666c0000666cULL, 0x0000666c0000666cULL, }, - { 0x0000000600000006ULL, 0x0000000600000006ULL, }, - { 0xffffe39500008e40ULL, 0x000038ebffffe395ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, /* 8 */ - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x0000aab40000aab4ULL, 0x0000aab40000aab4ULL, }, /* 16 */ - { 0x0000aab40000aab4ULL, 0x0000aab40000aab4ULL, }, - { 0x38e51c7c38e51c7cULL, 0x38e51c7c38e51c7cULL, }, - { 0x0001556000015560ULL, 0x0001556000015560ULL, }, - { 0x2224445022244450ULL, 0x2224445022244450ULL, }, - { 0x0002000c0002000cULL, 0x0002000c0002000cULL, }, - { 0xf686ed162f6b0988ULL, 0x12f925faf686ed16ULL, }, - { 0x0002aab80002aab8ULL, 0x0002aab80002aab8ULL, }, - { 0x0002000e0002000eULL, 0x0002000e0002000eULL, }, /* 24 */ - { 0x0002000e0002000eULL, 0x0002000e0002000eULL, }, - { 0xc71e38f2c71e38f2ULL, 0xc71e38f2c71e38f2ULL, }, - { 0x0001556400015564ULL, 0x0001556400015564ULL, }, - { 0xdddeccdcdddeccdcULL, 0xdddeccdcdddeccdcULL, }, - { 0x0000aaba0000aabaULL, 0x0000aaba0000aabaULL, }, - { 0x097ba13fd0982f78ULL, 0xed09bdb1097ba13fULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0x0000667800006678ULL, 0x0000667800006678ULL, }, /* 32 */ - { 0x0000667800006678ULL, 0x0000667800006678ULL, }, - { 0x2223556822235568ULL, 0x2223556822235568ULL, }, - { 0x0000cce00000cce0ULL, 0x0000cce00000cce0ULL, }, - { 0x147c5200147c5200ULL, 0x147c5200147c5200ULL, }, - { 0x0001334800013348ULL, 0x0001334800013348ULL, }, - { 0xfa50e9541c73a510ULL, 0x0b6260ccfa50e954ULL, }, - { 0x000199b0000199b0ULL, 0x000199b0000199b0ULL, }, - { 0x0001334a0001334aULL, 0x0001334a0001334aULL, }, /* 40 */ - { 0x0001334a0001334aULL, 0x0001334a0001334aULL, }, - { 0xdddeef06dddeef06ULL, 0xdddeef06dddeef06ULL, }, - { 0x0000cce40000cce4ULL, 0x0000cce40000cce4ULL, }, - { 0xeb85ae2ceb85ae2cULL, 0xeb85ae2ceb85ae2cULL, }, - { 0x0000667e0000667eULL, 0x0000667e0000667eULL, }, - { 0x05b09401e38e82f0ULL, 0xf49f71df05b09401ULL, }, - { 0x0000001800000018ULL, 0x0000001800000018ULL, }, - { 0xffffe3a700008e52ULL, 0x000038fdffffe3a7ULL, }, /* 48 */ - { 0xffffe3a700008e52ULL, 0x000038fdffffe3a7ULL, }, - { 0xf684d0b12f6997ceULL, 0x12f75eebf684d0b1ULL, }, - { 0xffffc73600011c8cULL, 0x000071e2ffffc736ULL, }, - { 0xfa4f7d421c738e54ULL, 0x0b619f66fa4f7d42ULL, }, - { 0xffffaac50001aac6ULL, 0x0000aac7ffffaac5ULL, }, - { 0x0fcce6d235bcf9caULL, 0x3f36f0500fcce6d2ULL, }, - { 0xffff8e5400023900ULL, 0x0000e3acffff8e54ULL, }, - { 0xffffaac70001aac8ULL, 0x0000aac9ffffaac7ULL, }, /* 56 */ - { 0xffffaac70001aac8ULL, 0x0000aac9ffffaac7ULL, }, - { 0x097b6869d0994bf8ULL, 0xed0a2f87097b6869ULL, }, - { 0xffffc73a00011c90ULL, 0x000071e6ffffc73aULL, }, - { 0x05b07796e38f1130ULL, 0xf49faaca05b07796ULL, }, - { 0xffffe3ad00008e58ULL, 0x00003903ffffe3adULL, }, - { 0xf0328b2fca45cd8eULL, 0xc0ca2c5ff0328b2fULL, }, - { 0x0000002000000020ULL, 0x0000002000000020ULL, }, - { 0x3a57fe9422c255a4ULL, 0x16b6ba1518facfc9ULL, }, /* 64 */ - { 0x3c4b6c241c0669eaULL, 0x193d8a02feefaadeULL, }, - { 0x6b6084e0ea284328ULL, 0x2271e08cf3dc0f77ULL, }, - { 0x34b7f0f2ef20736aULL, 0xfb8f1ed3fd8c7dadULL, }, - { 0x36ab5e82e86487b0ULL, 0xfe15eec0e38158c2ULL, }, - { 0x36bda5cf0c93ba59ULL, 0x120897b5002b2653ULL, }, - { 0x38025a59113b8b36ULL, 0x2453b4030525b498ULL, }, - { 0x362cc9c2346212c9ULL, 0x3bf2477af46d1b56ULL, }, - { 0x6541e27e0283ec07ULL, 0x45269e04e9597fefULL, }, /* 72 */ - { 0x66869708072bbce4ULL, 0x5771ba52ee540e34ULL, }, - { 0x9bb32f904f6ed245ULL, 0x6a56b2930fcf50fdULL, }, - { 0x6feae478431ee5e4ULL, 0x731e8c13284ca993ULL, }, - { 0x3942508a48171626ULL, 0x4c3bca5a31fd17c9ULL, }, - { 0x376cbff36b3d9db9ULL, 0x63da5dd121447e87ULL, }, - { 0x0ba474db5eedb158ULL, 0x6ca2375139c1d71dULL, }, - { 0x3edb00658507867dULL, 0xd6e9ca725a84f021ULL, }, - { 0x21746d8f492aab6bULL, 0xc86ec10d5ef05719ULL, }, /* 80 */ - { 0x21105bf47228d8e1ULL, 0xd541f981830d22c5ULL, }, - { 0xf90ba39c64a9aab9ULL, 0xd00d1cd8b17e0558ULL, }, - { 0xedf1ebed93975370ULL, 0xd7fd3855cb7afcd4ULL, }, - { 0xf85b68939e46773eULL, 0xceb49456ccc86662ULL, }, - { 0xf8a465f666205360ULL, 0xe8078ebee9b86012ULL, }, - { 0xdaa6e8fa242ed740ULL, 0xfd8488e8ff04a562ULL, }, - { 0xc84291663638bd8eULL, 0x360ea9ec09bfe9aaULL, }, - { 0xed300e0228a5c87eULL, 0x42280c3610aaee67ULL, }, /* 88 */ - { 0xed8592684150f62dULL, 0x43c5604a0c58a5a1ULL, }, - { 0x1661583a33e11b5dULL, 0x38e0b738fb2ab5fdULL, }, - { 0x27e2359b43cb17c4ULL, 0x4169f958054c48f1ULL, }, - { 0x0ff9c2b35666c87aULL, 0x546263e7ee7c57c1ULL, }, - { 0x0f9e0bba7cf02cdcULL, 0x3fbf94eb097a6841ULL, }, - { 0x06c9e6ca464484ecULL, 0x61838f28157007d3ULL, }, - { 0x0791b5936e65c7d8ULL, 0x6a978c3b0d46a893ULL, }, - { 0x0b5ca2c16d1c8082ULL, 0x84d8b2a628807419ULL, }, /* 96 */ - { 0x0f3c4ea553ddefbaULL, 0x5d23288204008ac5ULL, }, - { 0x006066f95bad42d4ULL, 0x7a5e585328976801ULL, }, - { 0xf610532580647c0eULL, 0xa2551d9f07de4a9aULL, }, - { 0xf65aca543e1e0beaULL, 0x936bdec820b433d4ULL, }, - { 0xf66f1d9c4e4a0274ULL, 0x945159553437f0d0ULL, }, - { 0xf6a34c5265777892ULL, 0x744c4f1e33a0fa19ULL, }, - { 0xf6e8ae026961c977ULL, 0x679ecf7e36000115ULL, }, - { 0x13ee44e6654e7066ULL, 0x828c7150244331b9ULL, }, /* 104 */ - { 0xf787434e16614d78ULL, 0x55caaa201f72a96eULL, }, - { 0xe4e9b290ecfd62e7ULL, 0x76440870087d3a2cULL, }, - { 0x065e2c1ac531b8faULL, 0x86cb35600e1a0d9bULL, }, - { 0x0d00c2eeb7cb8587ULL, 0xa3f3f27b07c3312fULL, }, - { 0x0d62db84ab6f1a84ULL, 0xd3421106ff7d27d5ULL, }, - { 0x10143b76893e48fbULL, 0xdf44d938fb177a2fULL, }, - { 0x1c4ff82055152453ULL, 0xffe7837ceebc407dULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_S_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_d.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_d.c deleted file mode 100644 index 106dc73d1f2b..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPADD_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPADD_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffc00000002ULL, 0xfffffffc00000002ULL, }, /* 0 */ - { 0xfffffffc00000002ULL, 0xfffffffc00000002ULL, }, - { 0x5555554eaaaaaaaeULL, 0x5555554eaaaaaaaeULL, }, - { 0xfffffff800000004ULL, 0xfffffff800000004ULL, }, - { 0x9999998e6666666cULL, 0x9999998e6666666cULL, }, - { 0xfffffff400000006ULL, 0xfffffff400000006ULL, }, - { 0x71c71c638e38e395ULL, 0x1c71c70de38e38ebULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, /* 8 */ - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0xfffffff000000008ULL, 0xfffffff000000008ULL, }, - { 0x55555542aaaaaab4ULL, 0x55555542aaaaaab4ULL, }, /* 16 */ - { 0x55555542aaaaaab4ULL, 0x55555542aaaaaab4ULL, }, - { 0x38e38e2471c71c7cULL, 0x38e38e2471c71c7cULL, }, - { 0xaaaaaa9555555560ULL, 0xaaaaaa9555555560ULL, }, - { 0xbbbbbba444444450ULL, 0xbbbbbba444444450ULL, }, - { 0xffffffe80000000cULL, 0xffffffe80000000cULL, }, - { 0xf684bd87b425ed16ULL, 0xbda12f4e97b425faULL, }, - { 0x5555553aaaaaaab8ULL, 0x5555553aaaaaaab8ULL, }, - { 0xffffffe40000000eULL, 0xffffffe40000000eULL, }, /* 24 */ - { 0xffffffe40000000eULL, 0xffffffe40000000eULL, }, - { 0x71c71c54e38e38f2ULL, 0x71c71c54e38e38f2ULL, }, - { 0xaaaaaa8d55555564ULL, 0xaaaaaa8d55555564ULL, }, - { 0x33333314ccccccdcULL, 0x33333314ccccccdcULL, }, - { 0x55555536aaaaaabaULL, 0x55555536aaaaaabaULL, }, - { 0xd097b40684bda13fULL, 0xb425ece9f684bdb1ULL, }, - { 0xffffffe000000010ULL, 0xffffffe000000010ULL, }, - { 0x9999997666666678ULL, 0x9999997666666678ULL, }, /* 32 */ - { 0x9999997666666678ULL, 0x9999997666666678ULL, }, - { 0xaaaaaa8555555568ULL, 0xaaaaaa8555555568ULL, }, - { 0x3333330ccccccce0ULL, 0x3333330ccccccce0ULL, }, - { 0x7ae147851eb85200ULL, 0x7ae147851eb85200ULL, }, - { 0xcccccca333333348ULL, 0xcccccca333333348ULL, }, - { 0xf49f49c93e93e954ULL, 0xb05b0584b60b60ccULL, }, - { 0x66666639999999b0ULL, 0x66666639999999b0ULL, }, - { 0xcccccc9f3333334aULL, 0xcccccc9f3333334aULL, }, /* 40 */ - { 0xcccccc9f3333334aULL, 0xcccccc9f3333334aULL, }, - { 0x111110e2eeeeef06ULL, 0x111110e2eeeeef06ULL, }, - { 0x33333304cccccce4ULL, 0x33333304cccccce4ULL, }, - { 0x851eb822e147ae2cULL, 0x851eb822e147ae2cULL, }, - { 0x9999996a6666667eULL, 0x9999996a6666667eULL, }, - { 0xe38e38b3e93e9401ULL, 0xd27d27a2c71c71dfULL, }, - { 0xffffffd000000018ULL, 0xffffffd000000018ULL, }, - { 0x71c71c3f8e38e3a7ULL, 0x1c71c6e9e38e38fdULL, }, /* 48 */ - { 0x71c71c3f8e38e3a7ULL, 0x1c71c6e9e38e38fdULL, }, - { 0x684bd9df425ed0b1ULL, 0xda12f6507b425eebULL, }, - { 0xe38e38af1c71c736ULL, 0x38e38e03c71c71e2ULL, }, - { 0x0b60b5d527d27d42ULL, 0x1c71c6e549f49f66ULL, }, - { 0x5555551eaaaaaac5ULL, 0x5555551daaaaaac7ULL, }, - { 0x6e9e061a4587e6d2ULL, 0x2c3f35816b74f050ULL, }, - { 0xc71c718e38e38e54ULL, 0x71c71c378e38e3acULL, }, - { 0x5555551aaaaaaac7ULL, 0x55555519aaaaaac9ULL, }, /* 56 */ - { 0x5555551aaaaaaac7ULL, 0x55555519aaaaaac9ULL, }, - { 0xb425eccda12f6869ULL, 0xed097b05bda12f87ULL, }, - { 0xe38e38a71c71c73aULL, 0x38e38dfbc71c71e6ULL, }, - { 0x5555551777777796ULL, 0xeeeeeeb0aaaaaacaULL, }, - { 0x71c71c338e38e3adULL, 0x1c71c6dde38e3903ULL, }, - { 0xca4587a781948b2fULL, 0x61f9ad9406522c5fULL, }, - { 0xffffffc000000020ULL, 0xffffffc000000020ULL, }, - { 0x4f10a2061266c2b0ULL, 0x132f36fdaebdb734ULL, }, /* 64 */ - { 0xe173955d0a3d6d94ULL, 0x2de485b19f4dac90ULL, }, - { 0x5a9b88364205b90cULL, 0xe3c89435af2c3022ULL, }, - { 0xa5506be1e16f25e8ULL, 0xb5d99e2c137656f2ULL, }, - { 0x37b35f38d945d0ccULL, 0xd08eece004064c4eULL, }, - { 0x46c3bc088c276755ULL, 0xd3ba26318bdfb302ULL, }, - { 0x288f407241d1cf13ULL, 0xe4e2d49bf38e1598ULL, }, - { 0xb38b871fddd1234aULL, 0xfd7386eef5421908ULL, }, - { 0x2cb379f915996ec2ULL, 0xb357957305209c9aULL, }, /* 72 */ - { 0x0e7efe62cb43d680ULL, 0xc48043dd6cceff30ULL, }, - { 0x0966991866fb9f64ULL, 0x3d26b2ddb9e53ac1ULL, }, - { 0x9961eeb6d99e4586ULL, 0xc46ae4f9206e6e69ULL, }, - { 0xe416d2627907b262ULL, 0x967beeef84b89539ULL, }, - { 0x6f13191015070699ULL, 0xaf0ca142866c98a9ULL, }, - { 0xff0e6eae87a9acbbULL, 0x3650d35decf5cc51ULL, }, - { 0x52fc668a5f0acfa8ULL, 0xf4ee28afafeae691ULL, }, - { 0x8e335693216733a0ULL, 0xebf294e7e1b7da9fULL, }, /* 80 */ - { 0x242889888a96ab79ULL, 0x1029e138e123d999ULL, }, - { 0xa117d2200713df49ULL, 0xa936d669733f9d55ULL, }, - { 0xea5eaf7c9d524d27ULL, 0x533cccdee6d6ad0dULL, }, - { 0x8014252a44e6c8b7ULL, 0x5139a5a2ff917d2dULL, }, - { 0x12e82535692eaeadULL, 0x6c74742f3b1a47edULL, }, - { 0x6bfad303a455af5fULL, 0xa4da8c7753e03c42ULL, }, - { 0xd7d1673544f2b638ULL, 0x37b76789ca48e5eaULL, }, - { 0x55b32da89b1ab874ULL, 0x1136a063291c7430ULL, }, /* 88 */ - { 0xd8fa08f2c6e9500cULL, 0x15e6a0cfa25fce7eULL, }, - { 0xfb6ec0cb14ee46c0ULL, 0x85e0ab776ca06e87ULL, }, - { 0x7170744f4e43c44fULL, 0x17ee0476d6f5954fULL, }, - { 0xba3c379c6c72bc03ULL, 0xf4a9e78f41249a57ULL, }, - { 0x923c97db1bf9726fULL, 0x0c32ba5fa7655f81ULL, }, - { 0x08ff0c9a1b07a05dULL, 0x7e05b61db39e9936ULL, }, - { 0x16e37ad7ce0b9d05ULL, 0x3aa86333e7ca176eULL, }, - { 0x4396d885c2a89499ULL, 0x3259d55cbbd56e50ULL, }, /* 96 */ - { 0x86505184e2848fd5ULL, 0xfbe6ef6acb48e5d8ULL, }, - { 0xf19ecbd2f0d9cb45ULL, 0x102d8886fc3ba2e4ULL, }, - { 0x985e99073ad19cddULL, 0x0fae6c4a600fe8c8ULL, }, - { 0x40076fc7eafc7c7aULL, 0x18d0edce69b82b2cULL, }, - { 0xc633d71b8943703fULL, 0x236de461c55a6368ULL, }, - { 0xb2b44afd6be31aa8ULL, 0x366f22bc07569aa2ULL, }, - { 0x832148e5fdab87bfULL, 0x3b138b90c7099132ULL, }, - { 0x9388b611f0bd2a51ULL, 0xc95a7ba92714878aULL, }, /* 104 */ - { 0xa598b2d7184dc31bULL, 0x02d31201c0d1f3a9ULL, }, - { 0x26b9d9c7d27ede61ULL, 0x84305afc61d71edcULL, }, - { 0xd994c5da2b819a07ULL, 0xda2ed7517c38dd10ULL, }, - { 0x490b25198d55f4bbULL, 0xa54a7d332b34db68ULL, }, - { 0x9d17b063519fea3aULL, 0x1d81a65b0c1f8770ULL, }, - { 0x000b355286100badULL, 0x35e1e113d0b4c238ULL, }, - { 0x316423fb99a16a0dULL, 0xddbffc10af9e9540ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_h.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_h.c deleted file mode 100644 index 5fae97e90786..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPADD_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPADD_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfc02fc02fc02fc02ULL, 0xfc02fc02fc02fc02ULL, }, /* 0 */ - { 0xfc02fc02fc02fc02ULL, 0xfc02fc02fc02fc02ULL, }, - { 0x4eae4eae4eae4eaeULL, 0x4eae4eae4eae4eaeULL, }, - { 0xf804f804f804f804ULL, 0xf804f804f804f804ULL, }, - { 0x8e6c8e6c8e6c8e6cULL, 0x8e6c8e6c8e6c8e6cULL, }, - { 0xf406f406f406f406ULL, 0xf406f406f406f406ULL, }, - { 0x63950debb9406395ULL, 0x0debb94063950debULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, /* 8 */ - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0xf008f008f008f008ULL, 0xf008f008f008f008ULL, }, - { 0x42b442b442b442b4ULL, 0x42b442b442b442b4ULL, }, /* 16 */ - { 0x42b442b442b442b4ULL, 0x42b442b442b442b4ULL, }, - { 0x247c247c247c247cULL, 0x247c247c247c247cULL, }, - { 0x9560956095609560ULL, 0x9560956095609560ULL, }, - { 0xa450a450a450a450ULL, 0xa450a450a450a450ULL, }, - { 0xe80ce80ce80ce80cULL, 0xe80ce80ce80ce80cULL, }, - { 0xdd16a3fa6b88dd16ULL, 0xa3fa6b88dd16a3faULL, }, - { 0x3ab83ab83ab83ab8ULL, 0x3ab83ab83ab83ab8ULL, }, - { 0xe40ee40ee40ee40eULL, 0xe40ee40ee40ee40eULL, }, /* 24 */ - { 0xe40ee40ee40ee40eULL, 0xe40ee40ee40ee40eULL, }, - { 0x54f254f254f254f2ULL, 0x54f254f254f254f2ULL, }, - { 0x8d648d648d648d64ULL, 0x8d648d648d648d64ULL, }, - { 0x14dc14dc14dc14dcULL, 0x14dc14dc14dc14dcULL, }, - { 0x36ba36ba36ba36baULL, 0x36ba36ba36ba36baULL, }, - { 0xb13f94b17878b13fULL, 0x94b17878b13f94b1ULL, }, - { 0xe010e010e010e010ULL, 0xe010e010e010e010ULL, }, - { 0x7678767876787678ULL, 0x7678767876787678ULL, }, /* 32 */ - { 0x7678767876787678ULL, 0x7678767876787678ULL, }, - { 0x8568856885688568ULL, 0x8568856885688568ULL, }, - { 0x0ce00ce00ce00ce0ULL, 0x0ce00ce00ce00ce0ULL, }, - { 0x5200520052005200ULL, 0x5200520052005200ULL, }, - { 0xa348a348a348a348ULL, 0xa348a348a348a348ULL, }, - { 0xc95484cc4110c954ULL, 0x84cc4110c95484ccULL, }, - { 0x39b039b039b039b0ULL, 0x39b039b039b039b0ULL, }, - { 0x9f4a9f4a9f4a9f4aULL, 0x9f4a9f4a9f4a9f4aULL, }, /* 40 */ - { 0x9f4a9f4a9f4a9f4aULL, 0x9f4a9f4a9f4a9f4aULL, }, - { 0xe306e306e306e306ULL, 0xe306e306e306e306ULL, }, - { 0x04e404e404e404e4ULL, 0x04e404e404e404e4ULL, }, - { 0x562c562c562c562cULL, 0x562c562c562c562cULL, }, - { 0x6a7e6a7e6a7e6a7eULL, 0x6a7e6a7e6a7e6a7eULL, }, - { 0xb401a2df91f0b401ULL, 0xa2df91f0b401a2dfULL, }, - { 0xd018d018d018d018ULL, 0xd018d018d018d018ULL, }, - { 0x3fa7e9fd95523fa7ULL, 0xe9fd95523fa7e9fdULL, }, /* 48 */ - { 0x3fa7e9fd95523fa7ULL, 0xe9fd95523fa7e9fdULL, }, - { 0x34b1a5eb18ce34b1ULL, 0xa5eb18ce34b1a5ebULL, }, - { 0xaf3603e25a8caf36ULL, 0x03e25a8caf3603e2ULL, }, - { 0xd542e566f854d542ULL, 0xe566f854d542e566ULL, }, - { 0x1ec51dc71fc61ec5ULL, 0x1dc71fc61ec51dc7ULL, }, - { 0x36d2f3507aca36d2ULL, 0xf3507aca36d2f350ULL, }, - { 0x8e5437ace5008e54ULL, 0x37ace5008e5437acULL, }, - { 0x1ac719c91bc81ac7ULL, 0x19c91bc81ac719c9ULL, }, /* 56 */ - { 0x1ac719c91bc81ac7ULL, 0x19c91bc81ac719c9ULL, }, - { 0x7869b087eaf87869ULL, 0xb087eaf87869b087ULL, }, - { 0xa73afbe65290a73aULL, 0xfbe65290a73afbe6ULL, }, - { 0x1796b0ca4b301796ULL, 0xb0ca4b301796b0caULL, }, - { 0x33adde03895833adULL, 0xde03895833adde03ULL, }, - { 0x8b2f225ff38e8b2fULL, 0x225ff38e8b2f225fULL, }, - { 0xc020c020c020c020ULL, 0xc020c020c020c020ULL, }, - { 0x34443154ebe4ec59ULL, 0xff8ae31df73d39b0ULL, }, /* 64 */ - { 0x084880383032306cULL, 0x6831f4b22a587de0ULL, }, - { 0x88eca4049c587e93ULL, 0xca865ad6e8ab9840ULL, }, - { 0xe522f524bdcadd1dULL, 0x54ccaffeb00f3b20ULL, }, - { 0xb926440802182130ULL, 0xbd73c193e32a7f50ULL, }, - { 0x3c436a516daabc21ULL, 0xad084cd0f46491a4ULL, }, - { 0x27b3ac0f1c2c2c2eULL, 0x802ef7580d00b12eULL, }, - { 0xd025c9d65495de4cULL, 0x729f70a02b1b9712ULL, }, - { 0x50c9eda2c0bb2c73ULL, 0xd4f4d6c4e96eb172ULL, }, /* 72 */ - { 0x3c392f606f3d9c80ULL, 0xa81a814c020ad0fcULL, }, - { 0xcf6d16889c4f27f9ULL, 0x644b18717b7cd7e5ULL, }, - { 0x3673589e07dcc9afULL, 0x451e58c9f775050fULL, }, - { 0x92a9a9be294e2839ULL, 0xcf64adf1bed9a7efULL, }, - { 0x3b1bc78561b7da57ULL, 0xc1d52739dcf48dd3ULL, }, - { 0xa221099bcd447c0dULL, 0xa2a8679158edbafdULL, }, - { 0xeb8222a8f9295b55ULL, 0xd3326611d982e681ULL, }, - { 0x9e2ec7142fc38eccULL, 0x252170b1ef468aadULL, }, /* 80 */ - { 0x5b3cced0addf038eULL, 0x4792d47b141b612dULL, }, - { 0xad78e4f4df354c2fULL, 0xcd93f2f8260072b6ULL, }, - { 0x1e3041f03b3c9d99ULL, 0xc8df44c83f16491aULL, }, - { 0x42003b965b6cf7faULL, 0x5d309124882a7c82ULL, }, - { 0x82b67598b4cfbfcbULL, 0x920afeb79da82432ULL, }, - { 0x1a0a2a0ede448d00ULL, 0xb0b8797422bf2d4eULL, }, - { 0x288031e03ccc097aULL, 0xbee01b9c6a6f85c8ULL, }, - { 0x72c0106694442af7ULL, 0x50aa560d08f0ea98ULL, }, /* 88 */ - { 0x710637d8e7d45355ULL, 0xfa50963144a8cb2cULL, }, - { 0xbf0eecaa3a2faae6ULL, 0x63e63b048e4cebf3ULL, }, - { 0x16f03414587a870eULL, 0x72f35dbcffa25349ULL, }, - { 0x860072bc94eeb761ULL, 0xf61ea6c34a7a8fc5ULL, }, - { 0x0962bb704a1c48aaULL, 0x245c33d36e927f7fULL, }, - { 0x31e284ea963ac4c2ULL, 0x77782d72d0929bc6ULL, }, - { 0x8d10d6a4d868ace6ULL, 0x29fba58a7f86a05cULL, }, - { 0xde98199821f81f82ULL, 0x9afbdf4d3dea12acULL, }, /* 96 */ - { 0x9378a92e86104a4dULL, 0x2d160528eade271cULL, }, - { 0x134065aca120761fULL, 0x431f140f3db4433cULL, }, - { 0x37d8497ac688a50dULL, 0x63391a6dd0b6741cULL, }, - { 0x0e1578a8502e25b8ULL, 0xa12e387d0e90b4d4ULL, }, - { 0x2b65b9a082a8483bULL, 0xd8e26e173326bf2cULL, }, - { 0xa084f7800a3a820bULL, 0xc220c0c740af27aaULL, }, - { 0x9f5c29002e8ae771ULL, 0xeea4613d7100db80ULL, }, - { 0x2a8844debf5e9d5eULL, 0x9d46e906bc7b0527ULL, }, /* 104 */ - { 0x769006829567219dULL, 0xf041a3364eb808ecULL, }, - { 0xf87860ea545d8208ULL, 0x4ba95712a1ba1c84ULL, }, - { 0xc9483d8edc44cc9eULL, 0xe5aeac4a2c832ae0ULL, }, - { 0x37706d823a10b0daULL, 0x079d461a6b55dbf4ULL, }, - { 0x72109dfa526c8ea6ULL, 0x9f45813ac7e235caULL, }, - { 0xa8e0f6aa85343e96ULL, 0x37cdf6b28585e2d4ULL, }, - { 0x37803ef0bffea306ULL, 0x17150f92ff9c2ed8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_w.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_w.c deleted file mode 100644 index 2bea9f669b1f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpadd_u_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPADD_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPADD_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffc0002fffc0002ULL, 0xfffc0002fffc0002ULL, }, /* 0 */ - { 0xfffc0002fffc0002ULL, 0xfffc0002fffc0002ULL, }, - { 0x554eaaae554eaaaeULL, 0x554eaaae554eaaaeULL, }, - { 0xfff80004fff80004ULL, 0xfff80004fff80004ULL, }, - { 0x998e666c998e666cULL, 0x998e666c998e666cULL, }, - { 0xfff40006fff40006ULL, 0xfff40006fff40006ULL, }, - { 0x1c63e39571b88e40ULL, 0xc70e38eb1c63e395ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, /* 8 */ - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0xfff00008fff00008ULL, 0xfff00008fff00008ULL, }, - { 0x5542aab45542aab4ULL, 0x5542aab45542aab4ULL, }, /* 16 */ - { 0x5542aab45542aab4ULL, 0x5542aab45542aab4ULL, }, - { 0x38cf1c7c38cf1c7cULL, 0x38cf1c7c38cf1c7cULL, }, - { 0xaa955560aa955560ULL, 0xaa955560aa955560ULL, }, - { 0xbba44450bba44450ULL, 0xbba44450bba44450ULL, }, - { 0xffe8000cffe8000cULL, 0xffe8000cffe8000cULL, }, - { 0xbd87ed16f66b0988ULL, 0x84a425fabd87ed16ULL, }, - { 0x553aaab8553aaab8ULL, 0x553aaab8553aaab8ULL, }, - { 0xffe4000effe4000eULL, 0xffe4000effe4000eULL, }, /* 24 */ - { 0xffe4000effe4000eULL, 0xffe4000effe4000eULL, }, - { 0x71aa38f271aa38f2ULL, 0x71aa38f271aa38f2ULL, }, - { 0xaa8d5564aa8d5564ULL, 0xaa8d5564aa8d5564ULL, }, - { 0x3314ccdc3314ccdcULL, 0x3314ccdc3314ccdcULL, }, - { 0x5536aaba5536aabaULL, 0x5536aaba5536aabaULL, }, - { 0xb406a13fd0782f78ULL, 0x9794bdb1b406a13fULL, }, - { 0xffe00010ffe00010ULL, 0xffe00010ffe00010ULL, }, - { 0x9976667899766678ULL, 0x9976667899766678ULL, }, /* 32 */ - { 0x9976667899766678ULL, 0x9976667899766678ULL, }, - { 0xaa855568aa855568ULL, 0xaa855568aa855568ULL, }, - { 0x330ccce0330ccce0ULL, 0x330ccce0330ccce0ULL, }, - { 0x7ab852007ab85200ULL, 0x7ab852007ab85200ULL, }, - { 0xcca33348cca33348ULL, 0xcca33348cca33348ULL, }, - { 0xb02fe954f473a510ULL, 0x6beb60ccb02fe954ULL, }, - { 0x663999b0663999b0ULL, 0x663999b0663999b0ULL, }, - { 0xcc9f334acc9f334aULL, 0xcc9f334acc9f334aULL, }, /* 40 */ - { 0xcc9f334acc9f334aULL, 0xcc9f334acc9f334aULL, }, - { 0x10e2ef0610e2ef06ULL, 0x10e2ef0610e2ef06ULL, }, - { 0x3304cce43304cce4ULL, 0x3304cce43304cce4ULL, }, - { 0x84efae2c84efae2cULL, 0x84efae2c84efae2cULL, }, - { 0x996a667e996a667eULL, 0x996a667e996a667eULL, }, - { 0xd24d9401e35e82f0ULL, 0xc13c71dfd24d9401ULL, }, - { 0xffd00018ffd00018ULL, 0xffd00018ffd00018ULL, }, - { 0x1c3fe3a771948e52ULL, 0xc6ea38fd1c3fe3a7ULL, }, /* 48 */ - { 0x1c3fe3a771948e52ULL, 0xc6ea38fd1c3fe3a7ULL, }, - { 0xd9dfd0b1681797ceULL, 0x4ba65eebd9dfd0b1ULL, }, - { 0x38afc736e3591c8cULL, 0x8e0471e238afc736ULL, }, - { 0x1c3c7d420b298e54ULL, 0x2d4c9f661c3c7d42ULL, }, - { 0x551faac5551daac6ULL, 0x551eaac7551faac5ULL, }, - { 0x2c08e6d26e64f9caULL, 0xb0c4f0502c08e6d2ULL, }, - { 0x718f8e54c6e23900ULL, 0x1c38e3ac718f8e54ULL, }, - { 0x551baac75519aac8ULL, 0x551aaac9551baac7ULL, }, /* 56 */ - { 0x551baac75519aac8ULL, 0x551aaac9551baac7ULL, }, - { 0xecce6869b3e94bf8ULL, 0x25b12f87ecce6869ULL, }, - { 0x38a7c73ae3511c90ULL, 0x8dfc71e638a7c73aULL, }, - { 0xeeb1779655171130ULL, 0x884aaacaeeb17796ULL, }, - { 0x1c33e3ad71888e58ULL, 0xc6de39031c33e3adULL, }, - { 0x61ba8b2fca05cd8eULL, 0x32522c5f61ba8b2fULL, }, - { 0xffc00020ffc00020ULL, 0xffc00020ffc00020ULL, }, - { 0x1883fe94228255a4ULL, 0x1676ba1575c8cfc9ULL, }, /* 64 */ - { 0x9f026c24710669eaULL, 0x245b8a02c3f8aadeULL, }, - { 0x985184e0bcca4328ULL, 0x38ede08c879f0f77ULL, }, - { 0xe844f0f21702736aULL, 0x68d01ed3cbb87dadULL, }, - { 0x6ec35e82658687b0ULL, 0x76b4eec019e858c2ULL, }, - { 0x6651a5cf17c5ba59ULL, 0x00db97b536922653ULL, }, - { 0x10115a59bc888b36ULL, 0x953fb40350cbb498ULL, }, - { 0x7e8ac9c2890512c9ULL, 0x03c7477aa84e1b56ULL, }, - { 0x77d9e27ed4c8ec07ULL, 0x18599e046bf47fefULL, }, /* 72 */ - { 0x21999708798bbce4ULL, 0xacbdba52862e0e34ULL, }, - { 0x0cce2f904c6cd245ULL, 0x4da0b293fdff50fdULL, }, - { 0x67a1e4780c1be5e4ULL, 0xce178c138ffda993ULL, }, - { 0xb795508a66541626ULL, 0xfdf9ca5ad41717c9ULL, }, - { 0x260ebff332d09db9ULL, 0x6c815dd12b997e87ULL, }, - { 0x80e274dbf27fb158ULL, 0xecf83751bd97d71dULL, }, - { 0xb4190065dd35867dULL, 0x84d1ca72f61ef021ULL, }, - { 0x146be93b2ce39d07ULL, 0xb4edb1658fe8e617ULL, }, /* 80 */ - { 0x28da2b76b4930398ULL, 0x43fbb752e67034d3ULL, }, - { 0x6202107639989575ULL, 0xdd1056c8882a591fULL, }, - { 0x8e704692d2e83f33ULL, 0x8605bb9831163f53ULL, }, - { 0x19f6294a0938f7c3ULL, 0xb5d3886b8d6db0c9ULL, }, - { 0x338d977ccca46e03ULL, 0x26ffd0ded278d778ULL, }, - { 0xbd9d53669d1f0d1fULL, 0xcf6d52287e678700ULL, }, - { 0x18106087e287df80ULL, 0x6e5a3285497c7c8eULL, }, - { 0x7be90cbb50b10f2eULL, 0x91193a91e83049caULL, }, /* 88 */ - { 0xf5c762fa74f1dd41ULL, 0xc6a6d96a1360b472ULL, }, - { 0xdec724f4426380a0ULL, 0x8e924c103a77a87aULL, }, - { 0x43bb09c1cc850053ULL, 0x06479b02f6444a68ULL, }, - { 0x709d98fbece3b6fdULL, 0x0f02ef4f1e3d11f4ULL, }, - { 0xdf964592c2f0673eULL, 0xbf06914326915827ULL, }, - { 0xa595174288afc04eULL, 0x4dac2c104d1f338eULL, }, - { 0xf0400b1764f99f91ULL, 0x904ab47cadc0214cULL, }, - { 0x7a4505ebaa0a3823ULL, 0xc2ce09ca715dec1cULL, }, /* 96 */ - { 0xc0c227c1d78e87b7ULL, 0xfc9e0ad8846cfb1bULL, }, - { 0x4b501be126c0ecd3ULL, 0x47813bbab4be1843ULL, }, - { 0x8c94284d7bbb0613ULL, 0x5f37b7ed7918a6b1ULL, }, - { 0x16e12feca5f2470cULL, 0xecb24110b92e33d5ULL, }, - { 0x2d734e2e0f77e762ULL, 0x2dc8706ed959cbd3ULL, }, - { 0x5a430652c80bfcc7ULL, 0x835871922d75cf6eULL, }, - { 0xb30826c2c930c150ULL, 0xe0148a4e74790481ULL, }, - { 0x46021066c48e3720ULL, 0x6e76bee0c30066e8ULL, }, /* 104 */ - { 0x80543cd67141b3f2ULL, 0x14074d905449ba08ULL, }, - { 0x003ba47a25839f81ULL, 0x536fe6e8a79655ebULL, }, - { 0x709b823c97a86aeeULL, 0x13e9a6a824155b79ULL, }, - { 0xad5a661d2dfbd29aULL, 0x780997c18cea8383ULL, }, - { 0x024c799cf912e891ULL, 0x0bb620125e8129b7ULL, }, - { 0x0de66afc224e0f31ULL, 0x23590398c1ea5059ULL, }, - { 0x1d512ac23c5b270dULL, 0x38de17a18940924dULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPADD_U_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_d.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_d.c deleted file mode 100644 index 560e29a24898..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPSUB_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPSUB_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, /* 0 */ - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, - { 0xffffffff55555552ULL, 0xffffffff55555552ULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xffffffff99999994ULL, 0xffffffff99999994ULL, }, - { 0xfffffffffffffffaULL, 0xfffffffffffffffaULL, }, - { 0xffffffff71c71c6bULL, 0x000000001c71c715ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, /* 8 */ - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xffffffff5555554cULL, 0xffffffff5555554cULL, }, /* 16 */ - { 0xffffffff5555554cULL, 0xffffffff5555554cULL, }, - { 0xc71c71c58e38e384ULL, 0xc71c71c58e38e384ULL, }, - { 0xfffffffeaaaaaaa0ULL, 0xfffffffeaaaaaaa0ULL, }, - { 0xdddddddbbbbbbbb0ULL, 0xdddddddbbbbbbbb0ULL, }, - { 0xfffffffdfffffff4ULL, 0xfffffffdfffffff4ULL, }, - { 0xd097b4234bda12eaULL, 0x097b425c684bda06ULL, }, - { 0xfffffffd55555548ULL, 0xfffffffd55555548ULL, }, - { 0xfffffffdfffffff2ULL, 0xfffffffdfffffff2ULL, }, /* 24 */ - { 0xfffffffdfffffff2ULL, 0xfffffffdfffffff2ULL, }, - { 0x38e38e371c71c70eULL, 0x38e38e371c71c70eULL, }, - { 0xfffffffeaaaaaa9cULL, 0xfffffffeaaaaaa9cULL, }, - { 0x2222222133333324ULL, 0x2222222133333324ULL, }, - { 0xffffffff55555546ULL, 0xffffffff55555546ULL, }, - { 0x2f684bd97b425ec1ULL, 0xf684bda1097b424fULL, }, - { 0xfffffffffffffff0ULL, 0xfffffffffffffff0ULL, }, - { 0xffffffff99999988ULL, 0xffffffff99999988ULL, }, /* 32 */ - { 0xffffffff99999988ULL, 0xffffffff99999988ULL, }, - { 0xdddddddcaaaaaa98ULL, 0xdddddddcaaaaaa98ULL, }, - { 0xffffffff33333320ULL, 0xffffffff33333320ULL, }, - { 0xeb851eb6e147ae00ULL, 0xeb851eb6e147ae00ULL, }, - { 0xfffffffeccccccb8ULL, 0xfffffffeccccccb8ULL, }, - { 0xe38e38e1c16c16acULL, 0x05b05b0449f49f34ULL, }, - { 0xfffffffe66666650ULL, 0xfffffffe66666650ULL, }, - { 0xfffffffeccccccb6ULL, 0xfffffffeccccccb6ULL, }, /* 40 */ - { 0xfffffffeccccccb6ULL, 0xfffffffeccccccb6ULL, }, - { 0x22222221111110faULL, 0x22222221111110faULL, }, - { 0xffffffff3333331cULL, 0xffffffff3333331cULL, }, - { 0x147ae1471eb851d4ULL, 0x147ae1471eb851d4ULL, }, - { 0xffffffff99999982ULL, 0xffffffff99999982ULL, }, - { 0x1c71c71c16c16bffULL, 0xfa4fa4fa38e38e21ULL, }, - { 0xffffffffffffffe8ULL, 0xffffffffffffffe8ULL, }, - { 0xffffffff71c71c59ULL, 0x000000001c71c703ULL, }, /* 48 */ - { 0xffffffff71c71c59ULL, 0x000000001c71c703ULL, }, - { 0xd097b424bda12f4fULL, 0x097b425e84bda115ULL, }, - { 0xfffffffee38e38caULL, 0x0000000038e38e1eULL, }, - { 0xe38e38e1d82d82beULL, 0x05b05b05b60b609aULL, }, - { 0xfffffffe5555553bULL, 0x0000000055555539ULL, }, - { 0xca4587e4ba78192eULL, 0xf0329162948b0fb0ULL, }, - { 0xfffffffdc71c71acULL, 0x0000000071c71c54ULL, }, - { 0xfffffffe55555539ULL, 0x0000000055555537ULL, }, /* 56 */ - { 0xfffffffe55555539ULL, 0x0000000055555537ULL, }, - { 0x2f684bd85ed09797ULL, 0xf684bda1425ed079ULL, }, - { 0xfffffffee38e38c6ULL, 0x0000000038e38e1aULL, }, - { 0x1c71c71b8888886aULL, 0xfa4fa4fa55555536ULL, }, - { 0xffffffff71c71c53ULL, 0x000000001c71c6fdULL, }, - { 0x35ba78187e6b74d1ULL, 0x0fcd6e9df9add3a1ULL, }, - { 0xffffffffffffffe0ULL, 0xffffffffffffffe0ULL, }, - { 0xc1c52b51ed993d50ULL, 0xe9c828da514248ccULL, }, /* 64 */ - { 0xb38b1f29f5c2926cULL, 0xe4522d2260b25370ULL, }, - { 0x978b1706bdfa46f4ULL, 0xd814f3be50d3cfdeULL, }, - { 0xbd2549a81e90da18ULL, 0xf92987d1ec89a90eULL, }, - { 0xaeeb3d8026ba2f34ULL, 0xf3b38c19fbf9b3b2ULL, }, - { 0x9756e17673d898abULL, 0xf08852c874204cfeULL, }, - { 0xab37d321be2e30edULL, 0xf49ef75a0c71ea68ULL, }, - { 0x908aa2c1222edcb6ULL, 0x0445531d0abde6f8ULL, }, - { 0x748a9a9dea66913eULL, 0xf80819b8fadf6366ULL, }, /* 72 */ - { 0x886b8c4934bc2980ULL, 0xfc1ebe4a933100d0ULL, }, - { 0x59d865e79904609cULL, 0xd9ce9972461ac53fULL, }, - { 0x985e08e42661ba7aULL, 0xced13609df919197ULL, }, - { 0xbdf83b8586f84d9eULL, 0xefe5ca1d7b476ac7ULL, }, - { 0xa34b0b24eaf8f967ULL, 0xff8c25e079936757ULL, }, - { 0xe1d0ae2178565345ULL, 0xf48ec278130a33afULL, }, - { 0x8de2b645a0f53058ULL, 0xa45a44165015196fULL, }, - { 0x6792d4f3d7eea55cULL, 0xbfd22ee1a25aa627ULL, }, /* 80 */ - { 0x75702d5b9af89c83ULL, 0xcc593d1da09f7be9ULL, }, - { 0x801c3e1c97724195ULL, 0xb4c868d4067dd2d2ULL, }, - { 0xdeafd0d6f0bea5c3ULL, 0x957877eb733b98b2ULL, }, - { 0xd1883629f50ec77bULL, 0xb587d85cf1ffef10ULL, }, - { 0xd4133b37d7cbfcc8ULL, 0xbc35d373b6f24df8ULL, }, - { 0xbab344ed957a4c42ULL, 0xae8dcb499ce6cd0bULL, }, - { 0x004c193eb947b2ddULL, 0x68b0a9907b71a293ULL, }, - { 0x0b979b74995fc935ULL, 0x4a9602f12aa080cfULL, }, /* 88 */ - { 0x2ae2653846d12eb1ULL, 0x4185939a2d850f91ULL, }, - { 0x4c5017cc0eed7401ULL, 0x466840b4575dc0d7ULL, }, - { 0x255760c7e1e38957ULL, 0x8360b1037a4f3497ULL, }, - { 0x3b88c1c3a41f6803ULL, 0xa8cf0d07b592cd69ULL, }, - { 0x585dd51272f3e482ULL, 0xb5723c3756218857ULL, }, - { 0x94c1c43b5f5b538eULL, 0xdd9794c5786cc9c2ULL, }, - { 0xa0b80278cc3c6a8bULL, 0xf710a53506ea3e4aULL, }, - { 0x7c607ecd0201d92bULL, 0xf9bcdab0e105825cULL, }, /* 96 */ - { 0xb628bad7d2470e0fULL, 0xfb660e974362496cULL, }, - { 0x9ae11df599c281fbULL, 0xfd2738784b8dbfeaULL, }, - { 0x7bc5bf3b5e23aeffULL, 0xfe707ab5676dfce2ULL, }, - { 0x614dabb2dc4e0a36ULL, 0xf5f8795b76d8fd08ULL, }, - { 0x6dbd1a209fc658b0ULL, 0xecd982bc128c8ceaULL, }, - { 0x8cb93c5d61b1a8d0ULL, 0xecbaa1839f7e477aULL, }, - { 0x6d33947e52d25a59ULL, 0xf62aab8428f0bf14ULL, }, - { 0xa7970469e4259b2dULL, 0x0543881aad9efd08ULL, }, /* 104 */ - { 0x8310e5e55f8149f3ULL, 0xe925758a04d06282ULL, }, - { 0x746e208dd13c0f61ULL, 0xee4c7bccbccd15e4ULL, }, - { 0x8da69743b598403fULL, 0xdac93db8514253e0ULL, }, - { 0xdb31a0aea0a5cde6ULL, 0xe5bd105b853454a0ULL, }, - { 0x0e6cfc3a89e7bd7cULL, 0xb06ea3bad3a90bd8ULL, }, - { 0x338cc47438edb042ULL, 0x7df572596f6dffe8ULL, }, - { 0x07fce3091840a942ULL, 0xdbd5224936527bd0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_h.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_h.c deleted file mode 100644 index 3fb88ab5c2e5..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPSUB_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPSUB_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, /* 0 */ - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xff52ff52ff52ff52ULL, 0xff52ff52ff52ff52ULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xff94ff94ff94ff94ULL, 0xff94ff94ff94ff94ULL, }, - { 0xfffafffafffafffaULL, 0xfffafffafffafffaULL, }, - { 0xff6b0015ffc0ff6bULL, 0x0015ffc0ff6b0015ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, /* 8 */ - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xff4cff4cff4cff4cULL, 0xff4cff4cff4cff4cULL, }, /* 16 */ - { 0xff4cff4cff4cff4cULL, 0xff4cff4cff4cff4cULL, }, - { 0xc584c584c584c584ULL, 0xc584c584c584c584ULL, }, - { 0xfea0fea0fea0fea0ULL, 0xfea0fea0fea0fea0ULL, }, - { 0xdbb0dbb0dbb0dbb0ULL, 0xdbb0dbb0dbb0dbb0ULL, }, - { 0xfdf4fdf4fdf4fdf4ULL, 0xfdf4fdf4fdf4fdf4ULL, }, - { 0xcdea0706ea78cdeaULL, 0x0706ea78cdea0706ULL, }, - { 0xfd48fd48fd48fd48ULL, 0xfd48fd48fd48fd48ULL, }, - { 0xfdf2fdf2fdf2fdf2ULL, 0xfdf2fdf2fdf2fdf2ULL, }, /* 24 */ - { 0xfdf2fdf2fdf2fdf2ULL, 0xfdf2fdf2fdf2fdf2ULL, }, - { 0x370e370e370e370eULL, 0x370e370e370e370eULL, }, - { 0xfe9cfe9cfe9cfe9cULL, 0xfe9cfe9cfe9cfe9cULL, }, - { 0x2124212421242124ULL, 0x2124212421242124ULL, }, - { 0xff46ff46ff46ff46ULL, 0xff46ff46ff46ff46ULL, }, - { 0x2ec1f64f12882ec1ULL, 0xf64f12882ec1f64fULL, }, - { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, }, - { 0xff88ff88ff88ff88ULL, 0xff88ff88ff88ff88ULL, }, /* 32 */ - { 0xff88ff88ff88ff88ULL, 0xff88ff88ff88ff88ULL, }, - { 0xdc98dc98dc98dc98ULL, 0xdc98dc98dc98dc98ULL, }, - { 0xff20ff20ff20ff20ULL, 0xff20ff20ff20ff20ULL, }, - { 0xea00ea00ea00ea00ULL, 0xea00ea00ea00ea00ULL, }, - { 0xfeb8feb8feb8feb8ULL, 0xfeb8feb8feb8feb8ULL, }, - { 0xe1ac0434f2f0e1acULL, 0x0434f2f0e1ac0434ULL, }, - { 0xfe50fe50fe50fe50ULL, 0xfe50fe50fe50fe50ULL, }, - { 0xfeb6feb6feb6feb6ULL, 0xfeb6feb6feb6feb6ULL, }, /* 40 */ - { 0xfeb6feb6feb6feb6ULL, 0xfeb6feb6feb6feb6ULL, }, - { 0x20fa20fa20fa20faULL, 0x20fa20fa20fa20faULL, }, - { 0xff1cff1cff1cff1cULL, 0xff1cff1cff1cff1cULL, }, - { 0x13d413d413d413d4ULL, 0x13d413d413d413d4ULL, }, - { 0xff82ff82ff82ff82ULL, 0xff82ff82ff82ff82ULL, }, - { 0x1bfffa210b101bffULL, 0xfa210b101bfffa21ULL, }, - { 0xffe8ffe8ffe8ffe8ULL, 0xffe8ffe8ffe8ffe8ULL, }, - { 0xff590003ffaeff59ULL, 0x0003ffaeff590003ULL, }, /* 48 */ - { 0xff590003ffaeff59ULL, 0x0003ffaeff590003ULL, }, - { 0xcf4f0915ec32cf4fULL, 0x0915ec32cf4f0915ULL, }, - { 0xfeca001eff74fecaULL, 0x001eff74feca001eULL, }, - { 0xe1be059af3ace1beULL, 0x059af3ace1be059aULL, }, - { 0xfe3b0039ff3afe3bULL, 0x0039ff3afe3b0039ULL, }, - { 0xc82ef0b0c036c82eULL, 0xf0b0c036c82ef0b0ULL, }, - { 0xfdac0054ff00fdacULL, 0x0054ff00fdac0054ULL, }, - { 0xfe390037ff38fe39ULL, 0x0037ff38fe390037ULL, }, /* 56 */ - { 0xfe390037ff38fe39ULL, 0x0037ff38fe390037ULL, }, - { 0x2d97f67912082d97ULL, 0xf67912082d97f679ULL, }, - { 0xfec6001aff70fec6ULL, 0x001aff70fec6001aULL, }, - { 0x1b6afa360ad01b6aULL, 0xfa360ad01b6afa36ULL, }, - { 0xff53fffdffa8ff53ULL, 0xfffdffa8ff53fffdULL, }, - { 0x34d10fa13e7234d1ULL, 0x0fa13e7234d10fa1ULL, }, - { 0xffe0ffe0ffe0ffe0ULL, 0xffe0ffe0ffe0ffe0ULL, }, - { 0x9bbcf2acd41cd3a7ULL, 0xc076dce3c4c3e650ULL, }, /* 64 */ - { 0xb4b806c8f1cee494ULL, 0xbecfd64ea6a80020ULL, }, - { 0x6814ecfc0fa82b6dULL, 0xc37ad92a91550ac0ULL, }, - { 0x7bdefedcee3621e3ULL, 0xeb34ed0270f105e0ULL, }, - { 0x94da12f80be832d0ULL, 0xe98de66d52d61fb0ULL, }, - { 0x83bdecafc65625dfULL, 0xe7f8d130419c055cULL, }, - { 0x994d0df1c6d40fd2ULL, 0xe3d2c1a83e00f9d2ULL, }, - { 0xafdbf02abf6b06b4ULL, 0xeb61a56034e501eeULL, }, - { 0x6337d65edd454d8dULL, 0xf00ca83c1f920c8eULL, }, /* 72 */ - { 0x78c7f7a0ddc33780ULL, 0xebe698b41bf60104ULL, }, - { 0x3d93c078c0b1c207ULL, 0xdfb58b8ff884fa1bULL, }, - { 0x468de162e424db51ULL, 0xeee27037d08b05f1ULL, }, - { 0x5a57f342c2b2d1c7ULL, 0x169c840fb0270111ULL, }, - { 0x70e5d57bbb49c8a9ULL, 0x1e2b67c7a70c092dULL, }, - { 0x79dff665debce1f3ULL, 0x2d584c6f7f131503ULL, }, - { 0x307edd58b2d7c6abULL, 0xf8ce0def507eed7fULL, }, - { 0x12d2ebaaceb9ef2dULL, 0x0f44139e1494e19bULL, }, /* 80 */ - { 0x07500cecbf88e9fcULL, 0x109a22b12d84e9f5ULL, }, - { 0xed7c0a0c9689dd79ULL, 0xfe3a2a165149ee24ULL, }, - { 0xcf880594d43cb481ULL, 0x00ba413659fef988ULL, }, - { 0xea40f026c424ed7dULL, 0x1ce42a975ba6fcf8ULL, }, - { 0xfa52e174e584e55aULL, 0x19f040936a55fe20ULL, }, - { 0xdb86fe7ec64b0603ULL, 0x13a14ea67f40fbeaULL, }, - { 0x115cd8c4cd3c05cdULL, 0x1699652699e9f314ULL, }, - { 0xf33cc884be3c10e4ULL, 0x399852dba428ee14ULL, }, /* 88 */ - { 0x0273f878eba21554ULL, 0x31ee6cb7a1dcf428ULL, }, - { 0xdaad1e38d3d148edULL, 0x27a784e6885df2c4ULL, }, - { 0x04ea0acced565727ULL, 0x33f546b6479bdaa0ULL, }, - { 0x0fe60140cf623084ULL, 0x29715ee078b0d340ULL, }, - { 0x097de88007d93f14ULL, 0x2a887b768288e2aaULL, }, - { 0xe07fb5d0025365dfULL, 0x116297ca6cdaedb8ULL, }, - { 0xc74ecab2f1b47bc3ULL, 0x1ec35e229b5ad07eULL, }, - { 0x8c4ab55e1124622cULL, 0x2e844d9c6f52bb96ULL, }, /* 96 */ - { 0x3746c0d800b436a2ULL, 0x52ee6f0548caaafeULL, }, - { 0x3412b2381dcc3c34ULL, 0x4226686a634c9036ULL, }, - { 0x44feb5ac2d2c1b48ULL, 0x1f863d063f8e6aaeULL, }, - { 0x45ced628325f1f0bULL, 0x190e4cdb56714772ULL, }, - { 0x3a43c6b04bc8259aULL, 0x17ca65193394327cULL, }, - { 0x4cabe5a01d613107ULL, 0x14467dc849f92468ULL, }, - { 0x383d0ac03df53bb8ULL, 0x1554a52945b51a80ULL, }, - { 0x352bf8744cc532afULL, 0x1f4190b4693720beULL, }, /* 104 */ - { 0x37711cdc568e2109ULL, 0x24b0770882d72146ULL, }, - { 0x21c319bc5896349eULL, 0x12b492065fe41709ULL, }, - { 0x42090ae65cb41b62ULL, 0x0416792084231302ULL, }, - { 0x226211dc497800b0ULL, 0x072cb6d850f915fcULL, }, - { 0xf5441b3a17b21910ULL, 0x0ce58de86df716f2ULL, }, - { 0xe51807761e2e171eULL, 0x10b4544095541446ULL, }, - { 0xe980e35e0a5c10acULL, 0x137085a05b4f30deULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_w.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_w.c deleted file mode 100644 index b95878b67b30..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_s_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPSUB_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPSUB_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, /* 0 */ - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xffff5552ffff5552ULL, 0xffff5552ffff5552ULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xffff9994ffff9994ULL, 0xffff9994ffff9994ULL, }, - { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, }, - { 0x00001c6bffff71c0ULL, 0xffffc71500001c6bULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, /* 8 */ - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xffff554cffff554cULL, 0xffff554cffff554cULL, }, /* 16 */ - { 0xffff554cffff554cULL, 0xffff554cffff554cULL, }, - { 0xc71ae384c71ae384ULL, 0xc71ae384c71ae384ULL, }, - { 0xfffeaaa0fffeaaa0ULL, 0xfffeaaa0fffeaaa0ULL, }, - { 0xdddbbbb0dddbbbb0ULL, 0xdddbbbb0dddbbbb0ULL, }, - { 0xfffdfff4fffdfff4ULL, 0xfffdfff4fffdfff4ULL, }, - { 0x097912ead094f678ULL, 0xed06da06097912eaULL, }, - { 0xfffd5548fffd5548ULL, 0xfffd5548fffd5548ULL, }, - { 0xfffdfff2fffdfff2ULL, 0xfffdfff2fffdfff2ULL, }, /* 24 */ - { 0xfffdfff2fffdfff2ULL, 0xfffdfff2fffdfff2ULL, }, - { 0x38e1c70e38e1c70eULL, 0x38e1c70e38e1c70eULL, }, - { 0xfffeaa9cfffeaa9cULL, 0xfffeaa9cfffeaa9cULL, }, - { 0x2221332422213324ULL, 0x2221332422213324ULL, }, - { 0xffff5546ffff5546ULL, 0xffff5546ffff5546ULL, }, - { 0xf6845ec12f67d088ULL, 0x12f6424ff6845ec1ULL, }, - { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, }, - { 0xffff9988ffff9988ULL, 0xffff9988ffff9988ULL, }, /* 32 */ - { 0xffff9988ffff9988ULL, 0xffff9988ffff9988ULL, }, - { 0xdddcaa98dddcaa98ULL, 0xdddcaa98dddcaa98ULL, }, - { 0xffff3320ffff3320ULL, 0xffff3320ffff3320ULL, }, - { 0xeb83ae00eb83ae00ULL, 0xeb83ae00eb83ae00ULL, }, - { 0xfffeccb8fffeccb8ULL, 0xfffeccb8fffeccb8ULL, }, - { 0x05af16ace38c5af0ULL, 0xf49d9f3405af16acULL, }, - { 0xfffe6650fffe6650ULL, 0xfffe6650fffe6650ULL, }, - { 0xfffeccb6fffeccb6ULL, 0xfffeccb6fffeccb6ULL, }, /* 40 */ - { 0xfffeccb6fffeccb6ULL, 0xfffeccb6fffeccb6ULL, }, - { 0x222110fa222110faULL, 0x222110fa222110faULL, }, - { 0xffff331cffff331cULL, 0xffff331cffff331cULL, }, - { 0x147a51d4147a51d4ULL, 0x147a51d4147a51d4ULL, }, - { 0xffff9982ffff9982ULL, 0xffff9982ffff9982ULL, }, - { 0xfa4f6bff1c717d10ULL, 0x0b608e21fa4f6bffULL, }, - { 0xffffffe8ffffffe8ULL, 0xffffffe8ffffffe8ULL, }, - { 0x00001c59ffff71aeULL, 0xffffc70300001c59ULL, }, /* 48 */ - { 0x00001c59ffff71aeULL, 0xffffc70300001c59ULL, }, - { 0x097b2f4fd0966832ULL, 0xed08a115097b2f4fULL, }, - { 0x000038cafffee374ULL, 0xffff8e1e000038caULL, }, - { 0x05b082bee38c71acULL, 0xf49e609a05b082beULL, }, - { 0x0000553bfffe553aULL, 0xffff55390000553bULL, }, - { 0xf033192eca430636ULL, 0xc0c90fb0f033192eULL, }, - { 0x000071acfffdc700ULL, 0xffff1c54000071acULL, }, - { 0x00005539fffe5538ULL, 0xffff553700005539ULL, }, /* 56 */ - { 0x00005539fffe5538ULL, 0xffff553700005539ULL, }, - { 0xf68497972f66b408ULL, 0x12f5d079f6849797ULL, }, - { 0x000038c6fffee370ULL, 0xffff8e1a000038c6ULL, }, - { 0xfa4f886a1c70eed0ULL, 0x0b605536fa4f886aULL, }, - { 0x00001c53ffff71a8ULL, 0xffffc6fd00001c53ULL, }, - { 0x0fcd74d135ba3272ULL, 0x3f35d3a10fcd74d1ULL, }, - { 0xffffffe0ffffffe0ULL, 0xffffffe0ffffffe0ULL, }, - { 0xc5a8016cdd3daa5cULL, 0xe94945ebe7053037ULL, }, /* 64 */ - { 0xc3b493dce3f99616ULL, 0xe6c275fe01105522ULL, }, - { 0x949f7b2015d7bcd8ULL, 0xdd8e1f740c23f089ULL, }, - { 0xcb480f0e10df8c96ULL, 0x0470e12d02738253ULL, }, - { 0xc954a17e179b7850ULL, 0x01ea11401c7ea73eULL, }, - { 0xc9425a31f36c45a7ULL, 0xedf7684bffd4d9adULL, }, - { 0xc7fda5a7eec474caULL, 0xdbac4bfdfada4b68ULL, }, - { 0xc9d3363ecb9ded37ULL, 0xc40db8860b92e4aaULL, }, - { 0x9abe1d82fd7c13f9ULL, 0xbad961fc16a68011ULL, }, /* 72 */ - { 0x997968f8f8d4431cULL, 0xa88e45ae11abf1ccULL, }, - { 0x644cd070b0912dbbULL, 0x95a94d6df030af03ULL, }, - { 0x90151b88bce11a1cULL, 0x8ce173edd7b3566dULL, }, - { 0xc6bdaf76b7e8e9daULL, 0xb3c435a6ce02e837ULL, }, - { 0xc893400d94c26247ULL, 0x9c25a22fdebb8179ULL, }, - { 0xf45b8b25a1124ea8ULL, 0x935dc8afc63e28e3ULL, }, - { 0xc124ff9b7af87983ULL, 0x2916358ea57b0fdfULL, }, - { 0xa3bdf52f3f1bc6d3ULL, 0x1a9b7790a9e67552ULL, }, /* 80 */ - { 0xa2394ebc1f432fbaULL, 0x38d091638b040700ULL, }, - { 0x9c98e9da3d8da28dULL, 0x17578e46633c7554ULL, }, - { 0xca2304601c11139aULL, 0xecce6f4f9252c75cULL, }, - { 0xb167fd62111ca498ULL, 0xed848a6b7ffb85a6ULL, }, - { 0xb01a590af79618c4ULL, 0xcf3de0319d05b479ULL, }, - { 0xb2490b42008cb27aULL, 0xcfbf82ea8729672eULL, }, - { 0xd36607e1f75b1a82ULL, 0x8006f7ab6a0e64dcULL, }, - { 0xbf56e259efe4672cULL, 0xa61769778a2f91d2ULL, }, /* 88 */ - { 0xbe4f061a0bbba5e0ULL, 0xc922e830b7ade689ULL, }, - { 0xaac85110e5ef76abULL, 0xcc5f9db0a366adc6ULL, }, - { 0xc91b5b88fd4a93d2ULL, 0x879c58c17a96cfbaULL, }, - { 0xb8799dfa21be5efeULL, 0xa721331f6c3d78f0ULL, }, - { 0xb76ef97e2ca86ef4ULL, 0xbb78ca223c0de8adULL, }, - { 0x9da743266b64f51cULL, 0xba24b1045354f4faULL, }, - { 0xc2f3162f429e4870ULL, 0x764125c06e4d3512ULL, }, - { 0xa89d5e1d1ffccbf4ULL, 0x51bf6a197f87f33bULL, }, /* 96 */ - { 0x890f17ff2c462c7cULL, 0x34f589127c4cc49aULL, }, - { 0x53dc26951679feb0ULL, 0x2aa458e36a7c8cdeULL, }, - { 0x7ed4f0c1135e605eULL, 0x1a22c08d472920e2ULL, }, - { 0x80f6d8c622f1e674ULL, 0x071f986d36987e53ULL, }, - { 0x7ee91ba012abf971ULL, 0xeab87172091da737ULL, }, - { 0x80fac8d20b8e2fb8ULL, 0x0ad43e562523cff0ULL, }, - { 0x7ef3481012ac516eULL, 0x1acdbd0e31a33d13ULL, }, - { 0xbf53a8023cd97b5aULL, 0x07b9c024393d8136ULL, }, /* 104 */ - { 0x8e3cb38085aaebe3ULL, 0xf84dd1305e923ebfULL, }, - { 0x50c22f685af8caedULL, 0xef14166874d2544dULL, }, - { 0x7a3548245bc2dee5ULL, 0xf6b38ff08f52b803ULL, }, - { 0x3e4f96f53628fefdULL, 0xbe65c7ed60e1faffULL, }, - { 0x2c2056e3221de63fULL, 0x871151e081227a9dULL, }, - { 0x113314bc1293f380ULL, 0x774bb8df643781b9ULL, }, - { 0x07d911730a4b3a5dULL, 0x8b56a81c77aef6ebULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_S_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_d.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_d.c deleted file mode 100644 index fc6c4e61dc31..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPSUB_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPSUB_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x00000003fffffffeULL, 0x00000003fffffffeULL, }, /* 0 */ - { 0x00000003fffffffeULL, 0x00000003fffffffeULL, }, - { 0xaaaaaab155555552ULL, 0xaaaaaab155555552ULL, }, - { 0x00000007fffffffcULL, 0x00000007fffffffcULL, }, - { 0x6666667199999994ULL, 0x6666667199999994ULL, }, - { 0x0000000bfffffffaULL, 0x0000000bfffffffaULL, }, - { 0x8e38e39c71c71c6bULL, 0xe38e38f21c71c715ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, /* 8 */ - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0x0000000ffffffff8ULL, 0x0000000ffffffff8ULL, }, - { 0xaaaaaabd5555554cULL, 0xaaaaaabd5555554cULL, }, /* 16 */ - { 0xaaaaaabd5555554cULL, 0xaaaaaabd5555554cULL, }, - { 0xc71c71db8e38e384ULL, 0xc71c71db8e38e384ULL, }, - { 0x5555556aaaaaaaa0ULL, 0x5555556aaaaaaaa0ULL, }, - { 0x4444445bbbbbbbb0ULL, 0x4444445bbbbbbbb0ULL, }, - { 0x00000017fffffff4ULL, 0x00000017fffffff4ULL, }, - { 0x097b42784bda12eaULL, 0x425ed0b1684bda06ULL, }, - { 0xaaaaaac555555548ULL, 0xaaaaaac555555548ULL, }, - { 0x0000001bfffffff2ULL, 0x0000001bfffffff2ULL, }, /* 24 */ - { 0x0000001bfffffff2ULL, 0x0000001bfffffff2ULL, }, - { 0x8e38e3ab1c71c70eULL, 0x8e38e3ab1c71c70eULL, }, - { 0x55555572aaaaaa9cULL, 0x55555572aaaaaa9cULL, }, - { 0xcccccceb33333324ULL, 0xcccccceb33333324ULL, }, - { 0xaaaaaac955555546ULL, 0xaaaaaac955555546ULL, }, - { 0x2f684bf97b425ec1ULL, 0x4bda1316097b424fULL, }, - { 0x0000001ffffffff0ULL, 0x0000001ffffffff0ULL, }, - { 0x6666668999999988ULL, 0x6666668999999988ULL, }, /* 32 */ - { 0x6666668999999988ULL, 0x6666668999999988ULL, }, - { 0x5555557aaaaaaa98ULL, 0x5555557aaaaaaa98ULL, }, - { 0xccccccf333333320ULL, 0xccccccf333333320ULL, }, - { 0x851eb87ae147ae00ULL, 0x851eb87ae147ae00ULL, }, - { 0x3333335cccccccb8ULL, 0x3333335cccccccb8ULL, }, - { 0x0b60b636c16c16acULL, 0x4fa4fa7b49f49f34ULL, }, - { 0x999999c666666650ULL, 0x999999c666666650ULL, }, - { 0x33333360ccccccb6ULL, 0x33333360ccccccb6ULL, }, /* 40 */ - { 0x33333360ccccccb6ULL, 0x33333360ccccccb6ULL, }, - { 0xeeeeef1d111110faULL, 0xeeeeef1d111110faULL, }, - { 0xccccccfb3333331cULL, 0xccccccfb3333331cULL, }, - { 0x7ae147dd1eb851d4ULL, 0x7ae147dd1eb851d4ULL, }, - { 0x6666669599999982ULL, 0x6666669599999982ULL, }, - { 0x1c71c74c16c16bffULL, 0x2d82d85d38e38e21ULL, }, - { 0x0000002fffffffe8ULL, 0x0000002fffffffe8ULL, }, - { 0x8e38e3c071c71c59ULL, 0xe38e39161c71c703ULL, }, /* 48 */ - { 0x8e38e3c071c71c59ULL, 0xe38e39161c71c703ULL, }, - { 0x97b42620bda12f4fULL, 0x25ed09af84bda115ULL, }, - { 0x1c71c750e38e38caULL, 0xc71c71fc38e38e1eULL, }, - { 0xf49f4a2ad82d82beULL, 0xe38e391ab60b609aULL, }, - { 0xaaaaaae15555553bULL, 0xaaaaaae255555539ULL, }, - { 0x9161f9e5ba78192eULL, 0xd3c0ca7e948b0fb0ULL, }, - { 0x38e38e71c71c71acULL, 0x8e38e3c871c71c54ULL, }, - { 0xaaaaaae555555539ULL, 0xaaaaaae655555537ULL, }, /* 56 */ - { 0xaaaaaae555555539ULL, 0xaaaaaae655555537ULL, }, - { 0x4bda13325ed09797ULL, 0x12f684fa425ed079ULL, }, - { 0x1c71c758e38e38c6ULL, 0xc71c720438e38e1aULL, }, - { 0xaaaaaae88888886aULL, 0x1111114f55555536ULL, }, - { 0x8e38e3cc71c71c53ULL, 0xe38e39221c71c6fdULL, }, - { 0x35ba78587e6b74d1ULL, 0x9e06526bf9add3a1ULL, }, - { 0x0000003fffffffe0ULL, 0x0000003fffffffe0ULL, }, - { 0xb0ef5df9ed993d50ULL, 0xecd0c902514248ccULL, }, /* 64 */ - { 0x1e8c6aa2f5c2926cULL, 0xd21b7a4e60b25370ULL, }, - { 0xa56477c9bdfa46f4ULL, 0x1c376bca50d3cfdeULL, }, - { 0x5aaf941e1e90da18ULL, 0x4a2661d3ec89a90eULL, }, - { 0xc84ca0c726ba2f34ULL, 0x2f71131ffbf9b3b2ULL, }, - { 0xb93c43f773d898abULL, 0x2c45d9ce74204cfeULL, }, - { 0xd770bf8dbe2e30edULL, 0x1b1d2b640c71ea68ULL, }, - { 0x4c7478e0222edcb6ULL, 0x028c79110abde6f8ULL, }, - { 0xd34c8606ea66913eULL, 0x4ca86a8cfadf6366ULL, }, /* 72 */ - { 0xf181019d34bc2980ULL, 0x3b7fbc22933100d0ULL, }, - { 0xf69966e79904609cULL, 0xc2d94d22461ac53fULL, }, - { 0x669e11492661ba7aULL, 0x3b951b06df919197ULL, }, - { 0x1be92d9d86f84d9eULL, 0x698411107b476ac7ULL, }, - { 0x90ece6efeaf8f967ULL, 0x50f35ebd79936757ULL, }, - { 0x00f1915178565345ULL, 0xc9af2ca2130a33afULL, }, - { 0xad039975a0f53058ULL, 0x0b11d7505015196fULL, }, - { 0x376d4d72ebbc7b1cULL, 0xb833881ecd4918dbULL, }, /* 80 */ - { 0xb97c39c63d30eb26ULL, 0x9983e1a16fddbe3bULL, }, - { 0x103118e687f4c4aaULL, 0x36d2d322776b1540ULL, }, - { 0xd7103f328f5683b0ULL, 0xc97816b7d22d1890ULL, }, - { 0x4dd93b94622edfd8ULL, 0xbd32853a6649bd9eULL, }, - { 0xe38ab03df0d4eedcULL, 0xa6b087fab9ab9432ULL, }, - { 0x9b8bc7cd79738e5aULL, 0x1099960abd7ff844ULL, }, - { 0x2a9e79f404df0445ULL, 0x8a1a574d141add54ULL, }, - { 0x1323c575df66a395ULL, 0x4d70aaa974eb601eULL, }, /* 88 */ - { 0xbc9ea974b0ce57aeULL, 0x3dff93a625e35e6cULL, }, - { 0xbd4cca940103a7a6ULL, 0x1b03e192077feba2ULL, }, - { 0x69e12c9b9ff2608eULL, 0x0713d9101835bf32ULL, }, - { 0x183a0715853e498aULL, 0xeced28ff102b04faULL, }, - { 0xd806808efcdcfa1bULL, 0xda07aee4d9a29bfcULL, }, - { 0x8f0ceb4c5a20614fULL, 0x2693974265c37330ULL, }, - { 0x2f219f4eacacaf61ULL, 0xcde749de29866580ULL, }, - { 0xfac6c540b5ec9bf9ULL, 0x67fa3d30bf85f9fcULL, }, /* 96 */ - { 0x58719a8af58d41b9ULL, 0x8af69bdae8797a8cULL, }, - { 0x0293ed8dc2154481ULL, 0x7aef92fa834de3f0ULL, }, - { 0xe296644d91f354e5ULL, 0xd4332e315ac37ee4ULL, }, - { 0xd78a5344aa8ce0f6ULL, 0xbcf1bf88825a127aULL, }, - { 0xcfe6e77bd50e6bfaULL, 0xa42046c9a6110292ULL, }, - { 0xc2e4e16ef7883199ULL, 0x8a2eb57c71a6b370ULL, }, - { 0xb83af7ab54b68847ULL, 0x7682eb14d9902e98ULL, }, - { 0xfeb58099fb6e2639ULL, 0xd298a4d4f4eef1ccULL, }, /* 104 */ - { 0x9cbae3e8d8c9b31fULL, 0x0e0c2c1a33a56ab0ULL, }, - { 0x95dc4a7a980a468fULL, 0xe95439aa32919b0aULL, }, - { 0xc29c82993429f90bULL, 0xa33308195e2c1fecULL, }, - { 0x5a0a569e52e5f3acULL, 0x0a72368b53acb754ULL, }, - { 0x140968eb707c3bbeULL, 0xcd5491c571071d8cULL, }, - { 0xe1db913744288b2bULL, 0x10c008b6922667d4ULL, }, - { 0x65b190239a38c686ULL, 0xa6d4ec5b01d651c4ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_h.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_h.c deleted file mode 100644 index 741c887bbda9..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPSUB_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPSUB_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x03fe03fe03fe03feULL, 0x03fe03fe03fe03feULL, }, /* 0 */ - { 0x03fe03fe03fe03feULL, 0x03fe03fe03fe03feULL, }, - { 0xb152b152b152b152ULL, 0xb152b152b152b152ULL, }, - { 0x07fc07fc07fc07fcULL, 0x07fc07fc07fc07fcULL, }, - { 0x7194719471947194ULL, 0x7194719471947194ULL, }, - { 0x0bfa0bfa0bfa0bfaULL, 0x0bfa0bfa0bfa0bfaULL, }, - { 0x9c6bf21546c09c6bULL, 0xf21546c09c6bf215ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, /* 8 */ - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0x0ff80ff80ff80ff8ULL, 0x0ff80ff80ff80ff8ULL, }, - { 0xbd4cbd4cbd4cbd4cULL, 0xbd4cbd4cbd4cbd4cULL, }, /* 16 */ - { 0xbd4cbd4cbd4cbd4cULL, 0xbd4cbd4cbd4cbd4cULL, }, - { 0xdb84db84db84db84ULL, 0xdb84db84db84db84ULL, }, - { 0x6aa06aa06aa06aa0ULL, 0x6aa06aa06aa06aa0ULL, }, - { 0x5bb05bb05bb05bb0ULL, 0x5bb05bb05bb05bb0ULL, }, - { 0x17f417f417f417f4ULL, 0x17f417f417f417f4ULL, }, - { 0x22ea5c06947822eaULL, 0x5c06947822ea5c06ULL, }, - { 0xc548c548c548c548ULL, 0xc548c548c548c548ULL, }, - { 0x1bf21bf21bf21bf2ULL, 0x1bf21bf21bf21bf2ULL, }, /* 24 */ - { 0x1bf21bf21bf21bf2ULL, 0x1bf21bf21bf21bf2ULL, }, - { 0xab0eab0eab0eab0eULL, 0xab0eab0eab0eab0eULL, }, - { 0x729c729c729c729cULL, 0x729c729c729c729cULL, }, - { 0xeb24eb24eb24eb24ULL, 0xeb24eb24eb24eb24ULL, }, - { 0xc946c946c946c946ULL, 0xc946c946c946c946ULL, }, - { 0x4ec16b4f87884ec1ULL, 0x6b4f87884ec16b4fULL, }, - { 0x1ff01ff01ff01ff0ULL, 0x1ff01ff01ff01ff0ULL, }, - { 0x8988898889888988ULL, 0x8988898889888988ULL, }, /* 32 */ - { 0x8988898889888988ULL, 0x8988898889888988ULL, }, - { 0x7a987a987a987a98ULL, 0x7a987a987a987a98ULL, }, - { 0xf320f320f320f320ULL, 0xf320f320f320f320ULL, }, - { 0xae00ae00ae00ae00ULL, 0xae00ae00ae00ae00ULL, }, - { 0x5cb85cb85cb85cb8ULL, 0x5cb85cb85cb85cb8ULL, }, - { 0x36ac7b34bef036acULL, 0x7b34bef036ac7b34ULL, }, - { 0xc650c650c650c650ULL, 0xc650c650c650c650ULL, }, - { 0x60b660b660b660b6ULL, 0x60b660b660b660b6ULL, }, /* 40 */ - { 0x60b660b660b660b6ULL, 0x60b660b660b660b6ULL, }, - { 0x1cfa1cfa1cfa1cfaULL, 0x1cfa1cfa1cfa1cfaULL, }, - { 0xfb1cfb1cfb1cfb1cULL, 0xfb1cfb1cfb1cfb1cULL, }, - { 0xa9d4a9d4a9d4a9d4ULL, 0xa9d4a9d4a9d4a9d4ULL, }, - { 0x9582958295829582ULL, 0x9582958295829582ULL, }, - { 0x4bff5d216e104bffULL, 0x5d216e104bff5d21ULL, }, - { 0x2fe82fe82fe82fe8ULL, 0x2fe82fe82fe82fe8ULL, }, - { 0xc05916036aaec059ULL, 0x16036aaec0591603ULL, }, /* 48 */ - { 0xc05916036aaec059ULL, 0x16036aaec0591603ULL, }, - { 0xcb4f5a15e732cb4fULL, 0x5a15e732cb4f5a15ULL, }, - { 0x50cafc1ea57450caULL, 0xfc1ea57450cafc1eULL, }, - { 0x2abe1a9a07ac2abeULL, 0x1a9a07ac2abe1a9aULL, }, - { 0xe13be239e03ae13bULL, 0xe239e03ae13be239ULL, }, - { 0xc92e0cb08536c92eULL, 0x0cb08536c92e0cb0ULL, }, - { 0x71acc8541b0071acULL, 0xc8541b0071acc854ULL, }, - { 0xe539e637e438e539ULL, 0xe637e438e539e637ULL, }, /* 56 */ - { 0xe539e637e438e539ULL, 0xe637e438e539e637ULL, }, - { 0x87974f7915088797ULL, 0x4f79150887974f79ULL, }, - { 0x58c6041aad7058c6ULL, 0x041aad7058c6041aULL, }, - { 0xe86a4f36b4d0e86aULL, 0x4f36b4d0e86a4f36ULL, }, - { 0xcc5321fd76a8cc53ULL, 0x21fd76a8cc5321fdULL, }, - { 0x74d1dda10c7274d1ULL, 0xdda10c7274d1dda1ULL, }, - { 0x3fe03fe03fe03fe0ULL, 0x3fe03fe03fe03fe0ULL, }, - { 0xcbbcceac141c13a7ULL, 0x00761ce308c3c650ULL, }, /* 64 */ - { 0xf7b87fc8cfcecf94ULL, 0x97cf0b4ed5a88220ULL, }, - { 0x77145bfc63a8816dULL, 0x357aa52a175567c0ULL, }, - { 0x1ade0adc423622e3ULL, 0xab3450024ff1c4e0ULL, }, - { 0x46dabbf8fde8ded0ULL, 0x428d3e6d1cd680b0ULL, }, - { 0xc3bd95af925643dfULL, 0x52f8b3300b9c6e5cULL, }, - { 0xd84d53f1e3d4d3d2ULL, 0x7fd208a8f3004ed2ULL, }, - { 0x2fdb362aab6b21b4ULL, 0x8d618f60d4e568eeULL, }, - { 0xaf37125e3f45d38dULL, 0x2b0c293c16924e8eULL, }, /* 72 */ - { 0xc3c7d0a090c36380ULL, 0x57e67eb4fdf62f04ULL, }, - { 0x3093e97863b1d807ULL, 0x9bb5e78f8484281bULL, }, - { 0xc98da762f8243651ULL, 0xbae2a737088bfaf1ULL, }, - { 0x6d575642d6b2d7c7ULL, 0x309c520f41275811ULL, }, - { 0xc4e5387b9e4925a9ULL, 0x3e2bd8c7230c722dULL, }, - { 0x5ddff66532bc83f3ULL, 0x5d58986fa7134503ULL, }, - { 0x147edd5806d7a4abULL, 0x2cce99ef267e197fULL, }, - { 0xd5b2d0aab3994377ULL, 0xcd083b9ac440025bULL, }, /* 80 */ - { 0x80bf8eec25e70baaULL, 0xb6e600dda46ca823ULL, }, - { 0xe79991b05061b0b1ULL, 0xd91c24ba24bc8d1fULL, }, - { 0x5352504a2070df63ULL, 0x473b74aadc80fd45ULL, }, - { 0x0546cd72f0907c98ULL, 0x1ab13142c4b84c19ULL, }, - { 0xcc6ba15c55b01774ULL, 0x6e1606c3875c1b25ULL, }, - { 0x1dbdf6d689f3d0f7ULL, 0x4ac43fe21dbb145aULL, }, - { 0xd6baa1542922ce15ULL, 0x697e5fbada60ca72ULL, }, - { 0x1806cdbe15b6846fULL, 0x18091759d3f43a3aULL, }, /* 88 */ - { 0xfc0a8444a6e31a5bULL, 0x0daafd828699ee8eULL, }, - { 0x4f36fd647760debdULL, 0x7c3fb8561364c110ULL, }, - { 0x1bfcc992394ee12bULL, 0xfca40e06ed110caeULL, }, - { 0xa54ca0a4128a8bb6ULL, 0x70d40b38f9c0fc46ULL, }, - { 0xcb1d6138bde219f9ULL, 0x9c68fd7fb61366a6ULL, }, - { 0x3887fa1a7e8f8fe6ULL, 0x2ce4bb5039504af0ULL, }, - { 0xf65edccc34eccb94ULL, 0x3e041478ff0f739cULL, }, - { 0x4cc27494d274632dULL, 0x2a3ee78cfad81d3cULL, }, /* 96 */ - { 0xd40e966c853c370eULL, 0x04feaa379b04067cULL, }, - { 0x5da2b998597c214bULL, 0x9da08eb7ff4efc8cULL, }, - { 0xe9269a421c1c0396ULL, 0x2f41456bdcd248bcULL, }, - { 0xe87f80bc039cfc91ULL, 0xed3c08269718789cULL, }, - { 0xa6c53808a9213425ULL, 0xa2aefe7284cdb89cULL, }, - { 0x71cd34f063590a91ULL, 0xef6839544786e41cULL, }, - { 0x6adcd8201277fe43ULL, 0x7a42072920b97f84ULL, }, - { 0xd64c3010a53c52d9ULL, 0x2ffcd8e8ec4662d9ULL, }, /* 104 */ - { 0x2bcc04d0fd7bb9d3ULL, 0x54334ac042e043bbULL, }, - { 0xc73077f8e331ebe0ULL, 0x1c5f5244f12a2b70ULL, }, - { 0x309c82661787fc47ULL, 0xc7f3cf1c49211c79ULL, }, - { 0xeb78588cf53e082dULL, 0x75954984106eb821ULL, }, - { 0x5fa026e08f6af367ULL, 0xa8dfb35ce9820111ULL, }, - { 0x04b0e03c469efd7fULL, 0x7a6806a42e2df58fULL, }, - { 0xcca0baf00eacf773ULL, 0xd54e79140435c3e5ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_w.c b/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_w.c deleted file mode 100644 index 3e1b711b6157..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-dot-product/test_msa_dpsub_u_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction DPSUB_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Dot Product"; - char *instruction_name = "DPSUB_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0003fffe0003fffeULL, 0x0003fffe0003fffeULL, }, /* 0 */ - { 0x0003fffe0003fffeULL, 0x0003fffe0003fffeULL, }, - { 0xaab15552aab15552ULL, 0xaab15552aab15552ULL, }, - { 0x0007fffc0007fffcULL, 0x0007fffc0007fffcULL, }, - { 0x6671999466719994ULL, 0x6671999466719994ULL, }, - { 0x000bfffa000bfffaULL, 0x000bfffa000bfffaULL, }, - { 0xe39c1c6b8e4771c0ULL, 0x38f1c715e39c1c6bULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, /* 8 */ - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0x000ffff8000ffff8ULL, 0x000ffff8000ffff8ULL, }, - { 0xaabd554caabd554cULL, 0xaabd554caabd554cULL, }, /* 16 */ - { 0xaabd554caabd554cULL, 0xaabd554caabd554cULL, }, - { 0xc730e384c730e384ULL, 0xc730e384c730e384ULL, }, - { 0x556aaaa0556aaaa0ULL, 0x556aaaa0556aaaa0ULL, }, - { 0x445bbbb0445bbbb0ULL, 0x445bbbb0445bbbb0ULL, }, - { 0x0017fff40017fff4ULL, 0x0017fff40017fff4ULL, }, - { 0x427812ea0994f678ULL, 0x7b5bda06427812eaULL, }, - { 0xaac55548aac55548ULL, 0xaac55548aac55548ULL, }, - { 0x001bfff2001bfff2ULL, 0x001bfff2001bfff2ULL, }, /* 24 */ - { 0x001bfff2001bfff2ULL, 0x001bfff2001bfff2ULL, }, - { 0x8e55c70e8e55c70eULL, 0x8e55c70e8e55c70eULL, }, - { 0x5572aa9c5572aa9cULL, 0x5572aa9c5572aa9cULL, }, - { 0xcceb3324cceb3324ULL, 0xcceb3324cceb3324ULL, }, - { 0xaac95546aac95546ULL, 0xaac95546aac95546ULL, }, - { 0x4bf95ec12f87d088ULL, 0x686b424f4bf95ec1ULL, }, - { 0x001ffff0001ffff0ULL, 0x001ffff0001ffff0ULL, }, - { 0x6689998866899988ULL, 0x6689998866899988ULL, }, /* 32 */ - { 0x6689998866899988ULL, 0x6689998866899988ULL, }, - { 0x557aaa98557aaa98ULL, 0x557aaa98557aaa98ULL, }, - { 0xccf33320ccf33320ULL, 0xccf33320ccf33320ULL, }, - { 0x8547ae008547ae00ULL, 0x8547ae008547ae00ULL, }, - { 0x335cccb8335cccb8ULL, 0x335cccb8335cccb8ULL, }, - { 0x4fd016ac0b8c5af0ULL, 0x94149f344fd016acULL, }, - { 0x99c6665099c66650ULL, 0x99c6665099c66650ULL, }, - { 0x3360ccb63360ccb6ULL, 0x3360ccb63360ccb6ULL, }, /* 40 */ - { 0x3360ccb63360ccb6ULL, 0x3360ccb63360ccb6ULL, }, - { 0xef1d10faef1d10faULL, 0xef1d10faef1d10faULL, }, - { 0xccfb331cccfb331cULL, 0xccfb331cccfb331cULL, }, - { 0x7b1051d47b1051d4ULL, 0x7b1051d47b1051d4ULL, }, - { 0x6695998266959982ULL, 0x6695998266959982ULL, }, - { 0x2db26bff1ca17d10ULL, 0x3ec38e212db26bffULL, }, - { 0x002fffe8002fffe8ULL, 0x002fffe8002fffe8ULL, }, - { 0xe3c01c598e6b71aeULL, 0x3915c703e3c01c59ULL, }, /* 48 */ - { 0xe3c01c598e6b71aeULL, 0x3915c703e3c01c59ULL, }, - { 0x26202f4f97e86832ULL, 0xb459a11526202f4fULL, }, - { 0xc75038ca1ca6e374ULL, 0x71fb8e1ec75038caULL, }, - { 0xe3c382bef4d671acULL, 0xd2b3609ae3c382beULL, }, - { 0xaae0553baae2553aULL, 0xaae15539aae0553bULL, }, - { 0xd3f7192e919b0636ULL, 0x4f3b0fb0d3f7192eULL, }, - { 0x8e7071ac391dc700ULL, 0xe3c71c548e7071acULL, }, - { 0xaae45539aae65538ULL, 0xaae55537aae45539ULL, }, /* 56 */ - { 0xaae45539aae65538ULL, 0xaae55537aae45539ULL, }, - { 0x133197974c16b408ULL, 0xda4ed07913319797ULL, }, - { 0xc75838c61caee370ULL, 0x72038e1ac75838c6ULL, }, - { 0x114e886aaae8eed0ULL, 0x77b55536114e886aULL, }, - { 0xe3cc1c538e7771a8ULL, 0x3921c6fde3cc1c53ULL, }, - { 0x9e4574d135fa3272ULL, 0xcdadd3a19e4574d1ULL, }, - { 0x003fffe0003fffe0ULL, 0x003fffe0003fffe0ULL, }, - { 0xe77c016cdd7daa5cULL, 0xe98945eb8a373037ULL, }, /* 64 */ - { 0x60fd93dc8ef99616ULL, 0xdba475fe3c075522ULL, }, - { 0x67ae7b204335bcd8ULL, 0xc7121f747860f089ULL, }, - { 0x17bb0f0ee8fd8c96ULL, 0x972fe12d34478253ULL, }, - { 0x913ca17e9a797850ULL, 0x894b1140e617a73eULL, }, - { 0x99ae5a31e83a45a7ULL, 0xff24684bc96dd9adULL, }, - { 0xefeea5a7437774caULL, 0x6ac04bfdaf344b68ULL, }, - { 0x8175363e76faed37ULL, 0xfc38b88657b1e4aaULL, }, - { 0x88261d822b3713f9ULL, 0xe7a661fc940b8011ULL, }, /* 72 */ - { 0xde6668f88674431cULL, 0x534245ae79d1f1ccULL, }, - { 0xf331d070b3932dbbULL, 0xb25f4d6d0200af03ULL, }, - { 0x985e1b88f3e41a1cULL, 0x31e873ed7002566dULL, }, - { 0x486aaf7699abe9daULL, 0x020635a62be8e837ULL, }, - { 0xd9f1400dcd2f6247ULL, 0x937ea22fd4668179ULL, }, - { 0x7f1d8b250d804ea8ULL, 0x1307c8af426828e3ULL, }, - { 0x4be6ff9b22ca7983ULL, 0x7b2e358e09e10fdfULL, }, - { 0x3d0470dbf4d6b86fULL, 0x548567e8f5250450ULL, }, /* 80 */ - { 0x00d897321b41b715ULL, 0x02517c05df66c875ULL, }, - { 0x991ec80ea3b5c306ULL, 0xa18dc9b22cff8e2fULL, }, - { 0x44850796bb133f8dULL, 0xdc2a4cc591614211ULL, }, - { 0x192b30fc8866f607ULL, 0x97e8c289d36e61aaULL, }, - { 0x0058689e9fcad43dULL, 0xfe7a0cc7a239bc40ULL, }, - { 0xb8bc4cc2b8296867ULL, 0xccf01b9e1a7e74adULL, }, - { 0x61014864181c5d2cULL, 0x4c8bc05ea1b0cc11ULL, }, - { 0xec0d0e4af547db74ULL, 0x2d758eed74a13bb5ULL, }, /* 88 */ - { 0x03e797060056a10fULL, 0xc1a1d5f8579892eaULL, }, - { 0x9a3ca5d4a8548905ULL, 0xfd2bfd1807c0081aULL, }, - { 0x4820b48cf1454f6bULL, 0xe982ac5dfb74445aULL, }, - { 0x7eec2fbcb0c3c941ULL, 0x9d1459e9d27d4766ULL, }, - { 0x020a22e0debbd140ULL, 0x4fbb0ef3a9e0453bULL, }, - { 0xe8df4a9ccb0c350bULL, 0x37b3761e2e442cffULL, }, - { 0x7c3604df51731065ULL, 0xd9add64be7d81e17ULL, }, - { 0x35a1aacf3f24481fULL, 0x900caa26ecaf303bULL, }, /* 96 */ - { 0x7f0fd7311d2a2997ULL, 0x5e11155ee03d0362ULL, }, - { 0x7959c1ef0ab6e6c3ULL, 0x41695f03ff01377bULL, }, - { 0x89d8f6a1bc2ded57ULL, 0x29ed46aadb5c8a3cULL, }, - { 0x01ec800ecaa24ac8ULL, 0xf32ccdbb9c58b788ULL, }, - { 0xffd7297c53176782ULL, 0x4acc984953e0cc00ULL, }, - { 0x04316ff6e9707c3dULL, 0xd5f54b0b0ac9f7e0ULL, }, - { 0xffe6fc76421c7405ULL, 0x8f42f98ab98b12e9ULL, }, - { 0xa75ea33ed2e809e1ULL, 0xb6fdbf643abee85cULL, }, /* 104 */ - { 0xc75019063471bcc9ULL, 0x05bcd250f1d0ad42ULL, }, - { 0x300d94eaa78224eaULL, 0x615cfa00370a0c2aULL, }, - { 0xaa1a04f419d03dccULL, 0x8fe0ca60107a1a34ULL, }, - { 0x5f0bb18ad9b000d4ULL, 0xd3ed3780ee630840ULL, }, - { 0x25e24aa388dc4d8cULL, 0x40c1586349788fbaULL, }, - { 0x0ec344de11f41ac8ULL, 0xed9aea2a99a95e8aULL, }, - { 0x02499bebf3ac5a24ULL, 0xecb186c0e06045b8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_DPSUB_U_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_b.c deleted file mode 100644 index 7e984a786e82..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_A.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_A.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, - { 0xaa71aaaa71aaaa71ULL, 0xaaaa71aaaa71aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x558e55558e55558eULL, 0x55558e55558e5555ULL, }, - { 0x5571555571555571ULL, 0x5555715555715555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, - { 0xcc71c7cc71c7cc71ULL, 0xc7cc71c7cc71c7ccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x338e38338e38338eULL, 0x38338e38338e3833ULL, }, - { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, - { 0x558e55558e55558eULL, 0x55558e55558e5555ULL, }, - { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, - { 0x338e38338e38338eULL, 0x38338e38338e3833ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaa71aaaa71aaaa71ULL, 0xaaaa71aaaa71aaaaULL, }, - { 0x5571555571555571ULL, 0x5555715555715555ULL, }, - { 0xcc71c7cc71c7cc71ULL, 0xc7cc71c7cc71c7ccULL, }, - { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, - { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6634d935540ULL, 0x4b67bb5e157b520cULL, }, - { 0x886aaeaab9628b80ULL, 0x4b67c65eab7bb014ULL, }, - { 0x886ae64d5e62554eULL, 0x8d67885ea97bb0a0ULL, }, - { 0x886ae6634d935540ULL, 0x4b67bb5e157b520cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aae634d938b80ULL, 0x27d8bb1aab3f5214ULL, }, - { 0x704f16635e93c74eULL, 0x8df188d8a94252a0ULL, }, - { 0x886aaeaab9628b80ULL, 0x4b67c65eab7bb014ULL, }, /* 72 */ - { 0xac5aae634d938b80ULL, 0x27d8bb1aab3f5214ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x705aaeaa5e318b80ULL, 0x8dd888d8a94225a0ULL, }, - { 0x886ae64d5e62554eULL, 0x8d67885ea97bb0a0ULL, }, - { 0x704f16635e93c74eULL, 0x8df188d8a94252a0ULL, }, - { 0x705aaeaa5ecf8b80ULL, 0x8dd888d8a94225a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_d.c deleted file mode 100644 index 3dfdb482f49d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_A.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_A.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_h.c deleted file mode 100644 index e1d65f98dc96..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_A.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_A.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, - { 0xaaaaaaaa71c7aaaaULL, 0xaaaa71c7aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x555555558e385555ULL, 0x55558e3855555555ULL, }, - { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, - { 0xccccc71c71c7ccccULL, 0xc71c71c7ccccc71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333338e38e383333ULL, 0x38e38e38333338e3ULL, }, - { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, - { 0x555555558e385555ULL, 0x55558e3855555555ULL, }, - { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, - { 0x333338e38e383333ULL, 0x38e38e38333338e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaa71c7aaaaULL, 0xaaaa71c7aaaaaaaaULL, }, - { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, - { 0xccccc71c71c7ccccULL, 0xc71c71c7ccccc71cULL, }, - { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, - { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc4d935540ULL, 0x4b67bb1a153f52fcULL, }, - { 0x886aaeaab9cf8b80ULL, 0x4b67c6ffab2bb00cULL, }, - { 0x886ae6cc5e315540ULL, 0x8df188d8a942b00cULL, }, - { 0x886ae6cc4d935540ULL, 0x4b67bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaa4d938b80ULL, 0x27d8bb1aab2b52fcULL, }, - { 0x704f164d5e31c708ULL, 0x8df188d8a94252fcULL, }, - { 0x886aaeaab9cf8b80ULL, 0x4b67c6ffab2bb00cULL, }, /* 72 */ - { 0xac5aaeaa4d938b80ULL, 0x27d8bb1aab2b52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704faeaa5e318b80ULL, 0x8df188d8a9422514ULL, }, - { 0x886ae6cc5e315540ULL, 0x8df188d8a942b00cULL, }, - { 0x704f164d5e31c708ULL, 0x8df188d8a94252fcULL, }, - { 0x704faeaa5e318b80ULL, 0x8df188d8a9422514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_w.c deleted file mode 100644 index 600f60af56c2..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_A.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_A.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x555555558e38e38eULL, 0x5555555555555555ULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0xcccccccc71c71c71ULL, 0xc71c71c7ccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333333338e38e38eULL, 0x38e38e3833333333ULL, }, - { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x555555558e38e38eULL, 0x5555555555555555ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x333333338e38e38eULL, 0x38e38e3833333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaa71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0xcccccccc71c71c71ULL, 0xc71c71c7ccccccccULL, }, - { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc4d93c708ULL, 0x4b670b5e153f52fcULL, }, - { 0x886ae6ccb9cf8b80ULL, 0x4b670b5eab2b2514ULL, }, - { 0x886ae6cc5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc4d93c708ULL, 0x4b670b5e153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaa4d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6ccb9cf8b80ULL, 0x4b670b5eab2b2514ULL, }, /* 72 */ - { 0xac5aaeaa4d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_A_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_b.c deleted file mode 100644 index ab4161f20c3c..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xffff38ffff38ffffULL, 0x38ffff38ffff38ffULL, }, - { 0x1c71ff1c71ff1c71ULL, 0xff1c71ff1c71ff1cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000380000380000ULL, 0x3800003800003800ULL, }, - { 0x1c71001c71001c71ULL, 0x001c71001c71001cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5571555571555571ULL, 0x5555715555715555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe3cc38e3cc38e3ccULL, 0x38e3cc38e3cc38e3ULL, }, - { 0x1c71cc1c71cc1c71ULL, 0xcc1c71cc1c71cc1cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333383333383333ULL, 0x3833333833333833ULL, }, - { 0x3371333371333371ULL, 0x3333713333713333ULL, }, - { 0xffff38ffff38ffffULL, 0x38ffff38ffff38ffULL, }, /* 48 */ - { 0x0000380000380000ULL, 0x3800003800003800ULL, }, - { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe3cc38e3cc38e3ccULL, 0x38e3cc38e3cc38e3ULL, }, - { 0x3333383333383333ULL, 0x3833333833333833ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, - { 0x1c71ff1c71ff1c71ULL, 0xff1c71ff1c71ff1cULL, }, /* 56 */ - { 0x1c71001c71001c71ULL, 0x001c71001c71001cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5571555571555571ULL, 0x5555715555715555ULL, }, - { 0x1c71cc1c71cc1c71ULL, 0xcc1c71cc1c71cc1cULL, }, - { 0x3371333371333371ULL, 0x3333713333713333ULL, }, - { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfb6a00634d625540ULL, 0x4b670b5e157b520cULL, }, - { 0xac6ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, - { 0x706a164d5e62554eULL, 0x4b670b5efe7be20cULL, }, - { 0xfb6a00634d625540ULL, 0x4b670b5e157b520cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfb5a00634dcfc708ULL, 0x27f7c61a153f5214ULL, }, - { 0x704f16635e31e24eULL, 0x12f7bb1a154252fcULL, }, - { 0xac6ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, /* 72 */ - { 0xfb5a00634dcfc708ULL, 0x27f7c61a153f5214ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x705a164d5e31e24eULL, 0x27f1c6ffab422514ULL, }, - { 0x706a164d5e62554eULL, 0x4b670b5efe7be20cULL, }, - { 0x704f16635e31e24eULL, 0x12f7bb1a154252fcULL, }, - { 0x705a164d5e31e24eULL, 0x27f1c6ffab422514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_d.c deleted file mode 100644 index 54a78ae56a9b..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_h.c deleted file mode 100644 index 79b1e0adfd94..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xffff38e3ffffffffULL, 0x38e3ffffffff38e3ULL, }, - { 0x1c71ffff71c71c71ULL, 0xffff71c71c71ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000038e300000000ULL, 0x38e30000000038e3ULL, }, - { 0x1c71000071c71c71ULL, 0x000071c71c710000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3cccce38eULL, 0x38e3cccce38e38e3ULL, }, - { 0x1c71cccc71c71c71ULL, 0xcccc71c71c71ccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333338e333333333ULL, 0x38e33333333338e3ULL, }, - { 0x3333333371c73333ULL, 0x333371c733333333ULL, }, - { 0xffff38e3ffffffffULL, 0x38e3ffffffff38e3ULL, }, /* 48 */ - { 0x000038e300000000ULL, 0x38e30000000038e3ULL, }, - { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e3cccce38eULL, 0x38e3cccce38e38e3ULL, }, - { 0x333338e333333333ULL, 0x38e33333333338e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, - { 0x1c71ffff71c71c71ULL, 0xffff71c71c71ffffULL, }, /* 56 */ - { 0x1c71000071c71c71ULL, 0x000071c71c710000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, - { 0x1c71cccc71c71c71ULL, 0xcccc71c71c71ccccULL, }, - { 0x3333333371c73333ULL, 0x333371c733333333ULL, }, - { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d935540ULL, 0x4b670b5e153f52fcULL, }, - { 0xac5ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, - { 0x704f164d5e315540ULL, 0x4b670b5efe7be2a0ULL, }, - { 0xfbbe00634d935540ULL, 0x4b670b5e153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e315540ULL, 0x4b670b5efe7be2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_w.c deleted file mode 100644 index 32e32456ebda..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38ffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffff1c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x38e38e3800000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x000000001c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3ccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xcccccccc1c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x38e38e3833333333ULL, }, - { 0x3333333371c71c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38ffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e3800000000ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e3ccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e3833333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffff1c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x000000001c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0xcccccccc1c71c71cULL, }, - { 0x3333333371c71c71ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x4b670b5e153f52fcULL, }, - { 0xac5aaeaa28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x4b670b5e153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaa28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_b.c deleted file mode 100644 index a63d2262793e..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe3aaaae3aaaae3aaULL, 0xaae3aaaae3aaaae3ULL, }, - { 0xaaaac7aaaac7aaaaULL, 0xc7aaaac7aaaac7aaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e55e38e55e38eULL, 0x55e38e55e38e55e3ULL, }, - { 0x5571c75571c75571ULL, 0xc75571c75571c755ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe3aaaae3aaaae3aaULL, 0xaae3aaaae3aaaae3ULL, }, - { 0xe38e55e38e55e38eULL, 0x55e38e55e38e55e3ULL, }, - { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaac7aaaac7aaaaULL, 0xc7aaaac7aaaac7aaULL, }, - { 0x5571c75571c75571ULL, 0xc75571c75571c755ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, - { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbee6cc4d93c740ULL, 0x4bf7bb5efe7bb0fcULL, }, - { 0xac6ae6ccb9cf8b80ULL, 0x4bd8c6fffe7bb014ULL, }, - { 0x886ae6cc5e62e24eULL, 0x8df188d8fe7be2a0ULL, }, - { 0xfbbee6cc4d93c740ULL, 0x4bf7bb5efe7bb0fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbeaeaab9cfc780ULL, 0x27f7c6ffab3f52fcULL, }, - { 0xfbbe16635e93e24eULL, 0x8df7bbd8a942e2fcULL, }, - { 0xac6ae6ccb9cf8b80ULL, 0x4bd8c6fffe7bb014ULL, }, /* 72 */ - { 0xfbbeaeaab9cfc780ULL, 0x27f7c6ffab3f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cfe280ULL, 0x8df1c6ffab42e2a0ULL, }, - { 0x886ae6cc5e62e24eULL, 0x8df188d8fe7be2a0ULL, }, - { 0xfbbe16635e93e24eULL, 0x8df7bbd8a942e2fcULL, }, - { 0xac5aaeaab9cfe280ULL, 0x8df1c6ffab42e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_d.c deleted file mode 100644 index 815a9ef497a8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_h.c deleted file mode 100644 index b668b3950753..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38eaaaaaaaae38eULL, 0xaaaaaaaae38eaaaaULL, }, - { 0xaaaac71caaaaaaaaULL, 0xc71caaaaaaaac71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e55558e38e38eULL, 0x55558e38e38e5555ULL, }, - { 0x5555c71c71c75555ULL, 0xc71c71c75555c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38eaaaaaaaae38eULL, 0xaaaaaaaae38eaaaaULL, }, - { 0xe38e55558e38e38eULL, 0x55558e38e38e5555ULL, }, - { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaac71caaaaaaaaULL, 0xc71caaaaaaaac71cULL, }, - { 0x5555c71c71c75555ULL, 0xc71c71c75555c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, - { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbee6cc4d93c708ULL, 0x4b67bb1afe7bb00cULL, }, - { 0xac5ae6ccb9cf8b80ULL, 0x4b67c6fffe7bb00cULL, }, - { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7be2a0ULL, }, - { 0xfbbee6cc4d93c708ULL, 0x4b67bb1afe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbeaeaab9cfc708ULL, 0x27d8c6ffab2b52fcULL, }, - { 0xfbbe164d5e31e24eULL, 0x8df1bb1aa942e2a0ULL, }, - { 0xac5ae6ccb9cf8b80ULL, 0x4b67c6fffe7bb00cULL, }, /* 72 */ - { 0xfbbeaeaab9cfc708ULL, 0x27d8c6ffab2b52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cfe24eULL, 0x8df1c6ffab2be2a0ULL, }, - { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7be2a0ULL, }, - { 0xfbbe164d5e31e24eULL, 0x8df1bb1aa942e2a0ULL, }, - { 0xac5aaeaab9cfe24eULL, 0x8df1c6ffab2be2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_w.c deleted file mode 100644 index 3329455f92c7..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MAX_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MAX_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e3aaaaaaaaULL, 0xaaaaaaaae38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x55555555e38e38e3ULL, }, - { 0x5555555571c71c71ULL, 0xc71c71c755555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0xaaaaaaaae38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x55555555e38e38e3ULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x5555555571c71c71ULL, 0xc71c71c755555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe0063b9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xfbbe00635e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ - { 0xfbbe0063b9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8ab2b2514ULL, }, - { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7bb00cULL, }, - { 0xfbbe00635e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8ab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MAX_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_b.c deleted file mode 100644 index 8fdbfc3bd349..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_A.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_A.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, - { 0x1caac71caac71caaULL, 0xc71caac71caac71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe35538e35538e355ULL, 0x38e35538e35538e3ULL, }, - { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, - { 0x1ccccc1ccccc1cccULL, 0xcc1ccccc1ccccc1cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe33333e33333e333ULL, 0x33e33333e33333e3ULL, }, - { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, - { 0xe35538e35538e355ULL, 0x38e35538e35538e3ULL, }, - { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, - { 0xe33333e33333e333ULL, 0x33e33333e33333e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1caac71caac71caaULL, 0xc71caac71caac71cULL, }, - { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, - { 0x1ccccc1ccccc1cccULL, 0xcc1ccccc1ccccc1cULL, }, - { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, - { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00cc2862c708ULL, 0x12f70b1afe3fb0fcULL, }, - { 0xac5ae6cc28cf5540ULL, 0x27d80bfffe2b250cULL, }, - { 0x704f16cc2831e240ULL, 0x4bf10bd8fe42e20cULL, }, - { 0xfbbe00cc2862c708ULL, 0x12f70b1afe3fb0fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00aab9cfc708ULL, 0x12f7c6ff152b25fcULL, }, - { 0xfbbe004d4d31e208ULL, 0x12f7bb1a153fe2fcULL, }, - { 0xac5ae6cc28cf5540ULL, 0x27d80bfffe2b250cULL, }, /* 72 */ - { 0xfbbe00aab9cfc708ULL, 0x12f7c6ff152b25fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac4f164db931e24eULL, 0x27f1c6ffab2be214ULL, }, - { 0x704f16cc2831e240ULL, 0x4bf10bd8fe42e20cULL, }, - { 0xfbbe004d4d31e208ULL, 0x12f7bb1a153fe2fcULL, }, - { 0xac4f164db9cfe24eULL, 0x27f1c6ffab2be214ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_d.c deleted file mode 100644 index 6a9f6bf10e58..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_A.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_A.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_h.c deleted file mode 100644 index 67a40b96f302..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_A.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_A.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, - { 0x1c71c71caaaa1c71ULL, 0xc71caaaa1c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e35555e38eULL, 0x38e35555e38e38e3ULL, }, - { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, - { 0x1c71cccccccc1c71ULL, 0xcccccccc1c71ccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e33333333e38eULL, 0x33333333e38e3333ULL, }, - { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, - { 0xe38e38e35555e38eULL, 0x38e35555e38e38e3ULL, }, - { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, - { 0xe38e33333333e38eULL, 0x33333333e38e3333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71caaaa1c71ULL, 0xc71caaaa1c71c71cULL, }, - { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, - { 0x1c71cccccccc1c71ULL, 0xcccccccc1c71ccccULL, }, - { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, - { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00632862c708ULL, 0x12f70b5efe7bb00cULL, }, - { 0xac5ae6cc28625540ULL, 0x27d80b5efe7b2514ULL, }, - { 0x704f164d2862e24eULL, 0x4b670b5efe7be2a0ULL, }, - { 0xfbbe00632862c708ULL, 0x12f70b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe0063b9cfc708ULL, 0x12f7c6ff153f2514ULL, }, - { 0xfbbe00634d93e24eULL, 0x12f7bb1a153fe2a0ULL, }, - { 0xac5ae6cc28625540ULL, 0x27d80b5efe7b2514ULL, }, /* 72 */ - { 0xfbbe0063b9cfc708ULL, 0x12f7c6ff153f2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5a164db9cfe24eULL, 0x27d8c6ffab2be2a0ULL, }, - { 0x704f164d2862e24eULL, 0x4b670b5efe7be2a0ULL, }, - { 0xfbbe00634d93e24eULL, 0x12f7bb1a153fe2a0ULL, }, - { 0xac5a164db9cfe24eULL, 0x27d8c6ffab2be2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_w.c deleted file mode 100644 index d08cb9cea81f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_A.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_A.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71caaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e355555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0x1c71c71cccccccccULL, 0xcccccccc1c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e333333333ULL, 0x33333333e38e38e3ULL, }, - { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e355555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, - { 0xe38e38e333333333ULL, 0x33333333e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71caaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71cccccccccULL, 0xcccccccc1c71c71cULL, }, - { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe006328625540ULL, 0x12f7bb1afe7bb00cULL, }, - { 0xac5aaeaa28625540ULL, 0x27d8c6fffe7bb00cULL, }, - { 0x704f164d28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe006328625540ULL, 0x12f7bb1afe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe0063b9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaa28625540ULL, 0x27d8c6fffe7bb00cULL, }, /* 72 */ - { 0xfbbe0063b9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d28625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_A_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_b.c deleted file mode 100644 index 048233bbab11..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe38effe38effe38eULL, 0xffe38effe38effe3ULL, }, - { 0xffffc7ffffc7ffffULL, 0xc7ffffc7ffffc7ffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e00e38e00e38eULL, 0x00e38e00e38e00e3ULL, }, - { 0x0000c70000c70000ULL, 0xc70000c70000c700ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcc8ecccc8ecccc8eULL, 0xcccc8ecccc8eccccULL, }, - { 0xccccc7ccccc7ccccULL, 0xc7ccccc7ccccc7ccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e33e38e33e38eULL, 0x33e38e33e38e33e3ULL, }, - { 0x1c33c71c33c71c33ULL, 0xc71c33c71c33c71cULL, }, - { 0xe38effe38effe38eULL, 0xffe38effe38effe3ULL, }, /* 48 */ - { 0xe38e00e38e00e38eULL, 0x00e38e00e38e00e3ULL, }, - { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xcc8ecccc8ecccc8eULL, 0xcccc8ecccc8eccccULL, }, - { 0xe38e33e38e33e38eULL, 0x33e38e33e38e33e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, - { 0xffffc7ffffc7ffffULL, 0xc7ffffc7ffffc7ffULL, }, /* 56 */ - { 0x0000c70000c70000ULL, 0xc70000c70000c700ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, - { 0xccccc7ccccc7ccccULL, 0xc7ccccc7ccccc7ccULL, }, - { 0x1c33c71c33c71c33ULL, 0xc71c33c71c33c71cULL, }, - { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x88bee6cc2893c708ULL, 0x12f7bb1afe3fb0fcULL, }, - { 0x885aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, - { 0x884fe6cc2831e240ULL, 0x8df188d8a942b0a0ULL, }, - { 0x88bee6cc2893c708ULL, 0x12f7bb1afe3fb0fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xacbeaeaab9938b80ULL, 0x12d8bbffab2b25fcULL, }, - { 0xfbbe004d4d93c708ULL, 0x8df188d8a93fe2a0ULL, }, - { 0x885aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, /* 72 */ - { 0xacbeaeaab9938b80ULL, 0x12d8bbffab2b25fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac4faeaab9cf8b80ULL, 0x8dd888d8a92be2a0ULL, }, - { 0x884fe6cc2831e240ULL, 0x8df188d8a942b0a0ULL, }, - { 0xfbbe004d4d93c708ULL, 0x8df188d8a93fe2a0ULL, }, - { 0xac4faeaab9cf8b80ULL, 0x8dd888d8a92be2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_d.c deleted file mode 100644 index 04e18ebdbfa2..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_h.c deleted file mode 100644 index 3bf32d487ac8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe38effff8e38e38eULL, 0xffff8e38e38effffULL, }, - { 0xffffc71cffffffffULL, 0xc71cffffffffc71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e00008e38e38eULL, 0x00008e38e38e0000ULL, }, - { 0x0000c71c00000000ULL, 0xc71c00000000c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc8e38ccccULL, 0xcccc8e38ccccccccULL, }, - { 0xccccc71cccccccccULL, 0xc71cccccccccc71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e33338e38e38eULL, 0x33338e38e38e3333ULL, }, - { 0x1c71c71c33331c71ULL, 0xc71c33331c71c71cULL, }, - { 0xe38effff8e38e38eULL, 0xffff8e38e38effffULL, }, /* 48 */ - { 0xe38e00008e38e38eULL, 0x00008e38e38e0000ULL, }, - { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xcccccccc8e38ccccULL, 0xcccc8e38ccccccccULL, }, - { 0xe38e33338e38e38eULL, 0x33338e38e38e3333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, - { 0xffffc71cffffffffULL, 0xc71cffffffffc71cULL, }, /* 56 */ - { 0x0000c71c00000000ULL, 0xc71c00000000c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, - { 0xccccc71cccccccccULL, 0xc71cccccccccc71cULL, }, - { 0x1c71c71c33331c71ULL, 0xc71c33331c71c71cULL, }, - { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc2862c708ULL, 0x12f7bb1afe7bb00cULL, }, - { 0x886aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, - { 0x886ae6cc2862e24eULL, 0x8df188d8a942b00cULL, }, - { 0x886ae6cc2862c708ULL, 0x12f7bb1afe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc2862e24eULL, 0x8df188d8a942b00cULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_w.c deleted file mode 100644 index eeb2ec935904..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xc71c71c7ffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0x0000000000000000ULL, 0xc71c71c700000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc8e38e38eULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xc71c71c7ccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x33333333e38e38e3ULL, }, - { 0x1c71c71c33333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffe38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xcccccccc8e38e38eULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0x33333333e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xc71c71c7ffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c700000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xc71c71c7ccccccccULL, }, - { 0x1c71c71c33333333ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x12f7bb1afe7bb00cULL, }, - { 0x886ae6ccb9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x12f7bb1afe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6ccb9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, - { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_b.c deleted file mode 100644 index bdebf68a491b..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaa8e38aa8e38aa8eULL, 0x38aa8e38aa8e38aaULL, }, - { 0x1c71aa1c71aa1c71ULL, 0xaa1c71aa1c71aa1cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555385555385555ULL, 0x3855553855553855ULL, }, - { 0x1c55551c55551c55ULL, 0x551c55551c55551cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaa8e38aa8e38aa8eULL, 0x38aa8e38aa8e38aaULL, }, - { 0x5555385555385555ULL, 0x3855553855553855ULL, }, - { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71aa1c71aa1c71ULL, 0xaa1c71aa1c71aa1cULL, }, - { 0x1c55551c55551c55ULL, 0x551c55551c55551cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, - { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886a006328625508ULL, 0x12670b1a153f520cULL, }, - { 0x885aaeaa28625540ULL, 0x27670b5eab2b250cULL, }, - { 0x704f164d28315540ULL, 0x4b670b5ea942b00cULL, }, - { 0x886a006328625508ULL, 0x12670b1a153f520cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5a00634d938b08ULL, 0x12d8bb1a152b2514ULL, }, - { 0x704f004d4d31c708ULL, 0x12f1881a153f52a0ULL, }, - { 0x885aaeaa28625540ULL, 0x27670b5eab2b250cULL, }, /* 72 */ - { 0xac5a00634d938b08ULL, 0x12d8bb1a152b2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e318b4eULL, 0x27d888d8a92b2514ULL, }, - { 0x704f164d28315540ULL, 0x4b670b5ea942b00cULL, }, - { 0x704f004d4d31c708ULL, 0x12f1881a153f52a0ULL, }, - { 0x704f164d5e318b4eULL, 0x27d888d8a92b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_d.c deleted file mode 100644 index fcd90167ed90..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, - { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_h.c deleted file mode 100644 index 16f54b79e198..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaa38e38e38aaaaULL, 0x38e38e38aaaa38e3ULL, }, - { 0x1c71aaaa71c71c71ULL, 0xaaaa71c71c71aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x555538e355555555ULL, 0x38e35555555538e3ULL, }, - { 0x1c71555555551c71ULL, 0x555555551c715555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaa38e38e38aaaaULL, 0x38e38e38aaaa38e3ULL, }, - { 0x555538e355555555ULL, 0x38e35555555538e3ULL, }, - { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71aaaa71c71c71ULL, 0xaaaa71c71c71aaaaULL, }, - { 0x1c71555555551c71ULL, 0x555555551c715555ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, - { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886a006328625540ULL, 0x12f70b5e153f52fcULL, }, - { 0x886aaeaa28625540ULL, 0x27d80b5eab2b2514ULL, }, - { 0x704f164d28625540ULL, 0x4b670b5ea942b00cULL, }, - { 0x886a006328625540ULL, 0x12f70b5e153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5a00634d938b80ULL, 0x12f7bb1a153f2514ULL, }, - { 0x704f00634d93c708ULL, 0x12f788d8153f52fcULL, }, - { 0x886aaeaa28625540ULL, 0x27d80b5eab2b2514ULL, }, /* 72 */ - { 0xac5a00634d938b80ULL, 0x12f7bb1a153f2514ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e318b80ULL, 0x27d888d8a9422514ULL, }, - { 0x704f164d28625540ULL, 0x4b670b5ea942b00cULL, }, - { 0x704f00634d93c708ULL, 0x12f788d8153f52fcULL, }, - { 0x704f164d5e318b80ULL, 0x27d888d8a9422514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_w.c deleted file mode 100644 index 574c169d0346..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MIN_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Max Min"; - char *instruction_name = "MIN_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0x38e38e38aaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x38e38e3855555555ULL, }, - { 0x1c71c71c55555555ULL, 0x555555551c71c71cULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0x38e38e38aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x38e38e3855555555ULL, }, - { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x1c71c71c55555555ULL, 0x555555551c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d28625540ULL, 0x4b670b5ea942e2a0ULL, }, - { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaa4d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d4d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaa4d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffa942e2a0ULL, }, - { 0x704f164d28625540ULL, 0x4b670b5ea942e2a0ULL, }, - { 0x704f164d4d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x704f164d5e31e24eULL, 0x27d8c6ffa942e2a0ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MIN_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_b.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_b.c deleted file mode 100644 index 1533790cae2a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xe4aae2e4aae2e4aaULL, 0xe2e4aae2e4aae2e4ULL, }, - { 0xfeaae3feaae3feaaULL, 0xe3feaae3feaae3feULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2121212121212121ULL, 0x2121212121212121ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x1b551d1b551d1b55ULL, 0x1d1b551d1b551d1bULL, }, - { 0x01551c01551c0155ULL, 0x1c01551c01551c01ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe9cccce9cccce9ccULL, 0xcce9cccce9cccce9ULL, }, - { 0xe8cccce8cccce8ccULL, 0xcce8cccce8cccce8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1633331633331633ULL, 0x3316333316333316ULL, }, - { 0x1733331733331733ULL, 0x3317333317333317ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe3e438e3e438e3e4ULL, 0x38e3e438e3e438e3ULL, }, - { 0xe3e338e3e338e3e3ULL, 0x38e3e338e3e338e3ULL, }, - { 0xe3f604e3f604e3f6ULL, 0x04e3f604e3f604e3ULL, }, - { 0xe3f405e3f405e3f4ULL, 0x05e3f405e3f405e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff38ffff38ffffULL, 0x38ffff38ffff38ffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c1bc71c1bc71c1bULL, 0xc71c1bc71c1bc71cULL, }, - { 0x1c1cc71c1cc71c1cULL, 0xc71c1cc71c1cc71cULL, }, - { 0x1c09fb1c09fb1c09ULL, 0xfb1c09fb1c09fb1cULL, }, - { 0x1c0bfa1c0bfa1c0bULL, 0xfa1c0bfa1c0bfa1cULL, }, - { 0x1c71ff1c71ff1c71ULL, 0xff1c71ff1c71ff1cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x0028e6cc28621c00ULL, 0x03040b10fe3cb000ULL, }, - { 0xdc10e6cc28005540ULL, 0x24170b00fe25fa0cULL, }, - { 0xf81bfccc28001940ULL, 0x4b0d0b0efe39ec0cULL, }, - { 0xfbbe002f25f5c708ULL, 0x12f7fd1a013f02fcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xfbbe000d06f5c708ULL, 0x12f7f500151408fcULL, }, - { 0xfbbe00164df5e508ULL, 0x12f7bb1a153f16fcULL, }, - { 0xac5afcdee1cfe000ULL, 0x27d8fdffff2b2508ULL, }, /* 72 */ - { 0xfc18aeaab9cffd00ULL, 0x03fcc6ffff2b2500ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac0bf0f7b900e5ceULL, 0x27f6c6ffab2b0714ULL, }, - { 0x704f16190e31e20eULL, 0xd8f1f6d8ff42e200ULL, }, - { 0x020d164d1131e206ULL, 0xf9facdf2fd03e200ULL, }, - { 0x1c4f164d1700e24eULL, 0xdbf1fc00fe17e2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_d.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_d.c deleted file mode 100644 index a8237f424408..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x0000000000000000ULL, 0xe38e38e38e38e38dULL, }, - { 0xfffffffffffffffdULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222221ULL, 0x2222222222222221ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c72ULL, }, - { 0x0000000000000002ULL, 0x1c71c71c71c71c71ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe93e93e93e93e93eULL, 0xccccccccccccccccULL, }, - { 0xe93e93e93e93e93dULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x16c16c16c16c16c1ULL, 0x3333333333333333ULL, }, - { 0x16c16c16c16c16c2ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e38e38e38eULL, 0x05b05b05b05b05afULL, }, - { 0xe38e38e38e38e38eULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0x1c71c71c71c71c71ULL, 0xfa4fa4fa4fa4fa4fULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffa2dbefac389060ULL, 0x127fda10bebdb718ULL, }, - { 0xdc1038216e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0xf8b9fd198694378eULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xfd40a74bf7d7c5e8ULL, 0x01e950cb80ac7f1cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0xd9589437a7be92acULL, }, - { 0x019b20633f34191eULL, 0xffbfeb7528bed488ULL, }, - { 0x1ca9c4f818016dceULL, 0xdda316d7ff992cc8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_h.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_h.c deleted file mode 100644 index 5d6e4d63f8ea..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x0000e38daaaa0000ULL, 0xe38daaaa0000e38dULL, }, - { 0xfffde38eaaaafffdULL, 0xe38eaaaafffde38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2221222122212221ULL, 0x2221222122212221ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x1c711c7255551c71ULL, 0x1c7255551c711c72ULL, }, - { 0x00021c7155550002ULL, 0x1c71555500021c71ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe93ecccccccce93eULL, 0xcccccccce93eccccULL, }, - { 0xe93dcccccccce93dULL, 0xcccccccce93dccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x16c13333333316c1ULL, 0x3333333316c13333ULL, }, - { 0x16c23333333316c2ULL, 0x3333333316c23333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3e38ee38eULL, 0x38e3e38ee38e38e3ULL, }, - { 0xe38e38e3e38de38eULL, 0x38e3e38de38e38e3ULL, }, - { 0xe38e05aff4a0e38eULL, 0x05aff4a0e38e05afULL, }, - { 0xe38e05b0f49ee38eULL, 0x05b0f49ee38e05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff38e3ffffffffULL, 0x38e3ffffffff38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c1c711c71ULL, 0xc71c1c711c71c71cULL, }, - { 0x1c71c71c1c721c71ULL, 0xc71c1c721c71c71cULL, }, - { 0x1c71fa500b5f1c71ULL, 0xfa500b5f1c71fa50ULL, }, - { 0x1c71fa4f0b611c71ULL, 0xfa4f0b611c71fa4fULL, }, - { 0x1c71ffff71c71c71ULL, 0xffff71c71c71ffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffa2ffef28621c48ULL, 0x12820b5efe7bb00cULL, }, - { 0xdc10e6cc28625540ULL, 0x238f0b5efe7bfa34ULL, }, - { 0xf8b9fd19286219dcULL, 0x4b670b5efe7beaccULL, }, - { 0xfbbe00632531c708ULL, 0x12f7ff4e017e0308ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xfbbe00630762c708ULL, 0x12f7f41b153f08d4ULL, }, - { 0xfbbe00634d93e4baULL, 0x12f7bb1a153f183cULL, }, - { 0xac5afa46e231e0c0ULL, 0x27d8ffd5febe2514ULL, }, /* 72 */ - { 0xfd40ffe0b9cffd70ULL, 0x01eac6ffeae82514ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5af191b9cfe496ULL, 0x27d8c6ffab2b07b4ULL, }, - { 0x704f164d0d6de24eULL, 0xd958fa84ffdfe2a0ULL, }, - { 0x019b0042109ee24eULL, 0xffbbcdbefe3ee2a0ULL, }, - { 0x1ca9164d1800e24eULL, 0xdda1fadafe17e2a0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_w.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_w.c deleted file mode 100644 index 1b068f28f566..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xe38e38e4aaaaaaaaULL, 0xe38e38e2e38e38e4ULL, }, - { 0xfffffffeaaaaaaaaULL, 0xe38e38e3fffffffeULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222122222221ULL, 0x2222222122222221ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x1c71c71b55555555ULL, 0x1c71c71d1c71c71bULL, }, - { 0x0000000155555555ULL, 0x1c71c71c00000001ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe93e93e9ccccccccULL, 0xcccccccce93e93e9ULL, }, - { 0xe93e93e8ccccccccULL, 0xcccccccce93e93e8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x16c16c1633333333ULL, 0x3333333316c16c16ULL, }, - { 0x16c16c1733333333ULL, 0x3333333316c16c17ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3e38e38e4ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3e38e38e3ULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e38e3f49f49f6ULL, 0x05b05b04e38e38e3ULL, }, - { 0xe38e38e3f49f49f4ULL, 0x05b05b05e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38ffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c1c71c71bULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c1c71c71cULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c0b60b609ULL, 0xfa4fa4fb1c71c71cULL, }, - { 0x1c71c71c0b60b60bULL, 0xfa4fa4fa1c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffff1c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0xffa2dbf828625540ULL, 0x127fda10fe7bb00cULL, }, - { 0xdc10382228625540ULL, 0x238e445ffe7bb00cULL, }, - { 0xf8b9fd1928625540ULL, 0x4b670b5efe7bb00cULL, }, - { 0xfbbe0063253171c8ULL, 0x12f7bb1a0002f3a4ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xfbbe006307635288ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaae231e0c0ULL, 0x27d8c6fffe985280ULL, }, /* 72 */ - { 0xfd40a751b9cf8b80ULL, 0x01e950cbeae91e08ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d0d6d37ceULL, 0xd9589436ffb8aff4ULL, }, - { 0x019b205b109e1b46ULL, 0xffbfeb74fe402e90ULL, }, - { 0x1ca9c4f718016dceULL, 0xdda316d6fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_b.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_b.c deleted file mode 100644 index 0d9ddf59077f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c711f1c711f1c71ULL, 0x1f1c711f1c711f1cULL, }, - { 0x031d38031d38031dULL, 0x38031d38031d3803ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xaa1c02aa1c02aa1cULL, 0x02aa1c02aa1c02aaULL, }, - { 0x0239aa0239aa0239ULL, 0xaa0239aa0239aa02ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x55551d55551d5555ULL, 0x1d55551d55551d55ULL, }, - { 0x0155550155550155ULL, 0x5501555501555501ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xcc3e24cc3e24cc3eULL, 0x24cc3e24cc3e24ccULL, }, - { 0x085b05085b05085bULL, 0x05085b05085b0508ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1733331733331733ULL, 0x3317333317333317ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x398e38398e38398eULL, 0x38398e38398e3839ULL, }, - { 0x3939383939383939ULL, 0x3839393839393839ULL, }, - { 0x178e38178e38178eULL, 0x38178e38178e3817ULL, }, - { 0x1728051728051728ULL, 0x0517280517280517ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x031d38031d38031dULL, 0x38031d38031d3803ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c711d1c711d1c71ULL, 0x1d1c711d1c711d1cULL, }, - { 0x1c1c1d1c1c1d1c1cULL, 0x1d1c1c1d1c1c1d1cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c0b2e1c0b2e1c0bULL, 0x2e1c0b2e1c0b2e1cULL, }, - { 0x1c711f1c711f1c71ULL, 0x1f1c711f1c711f1cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x886ae60628625500ULL, 0x03670b10023c0c0cULL, }, - { 0x8810382228625540ULL, 0x24670b5e53251c0cULL, }, - { 0x181b0a3228005540ULL, 0x4b670b5e5539b00cULL, }, - { 0x7354006325311d08ULL, 0x1229001a153f5200ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f0a00634d933c08ULL, 0x121fbb1a1514080cULL, }, - { 0x1b2000164d00c708ULL, 0x1206331a153f525cULL, }, - { 0x245aaeaa190b3600ULL, 0x270a0043ab2b2508ULL, }, /* 72 */ - { 0xac5aae471f3c8b00ULL, 0x03d80b15032b2514ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b14105b0b8b32ULL, 0x27d83e27022b2514ULL, }, - { 0x704f164d0e31380eULL, 0x4223041ca9423204ULL, }, - { 0x704f164d11311b06ULL, 0x0ff1880801033ea0ULL, }, - { 0x704f164d5e31574eULL, 0x181988d8a9170400ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_d.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_d.c deleted file mode 100644 index 1c3aa2bb36cc..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c73ULL, }, - { 0x0000000000000006ULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000001ULL, }, - { 0x0000000000000004ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x5555555555555555ULL, 0x1c71c71c71c71c72ULL, }, - { 0x0000000000000002ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x2222222222222223ULL, }, - { 0x05b05b05b05b05b5ULL, 0x05b05b05b05b05b0ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x16c16c16c16c16c2ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x38e38e38e38e38e3ULL, }, - { 0x16c16c16c16c16c2ULL, 0x38e38e38e38e38e3ULL, }, - { 0x16c16c16c16c16c2ULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000006ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c72ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c72ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x2d82d82d82d82d83ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c73ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x127fda10bebdb718ULL, }, - { 0x886ae6cc28625540ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07eca3072f2ULL, 0x4b670b5efe7bb00cULL, }, - { 0x73531997253171c8ULL, 0x12f7bb1a153f52fcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0x12f7bb1a153f52fcULL, }, - { 0x1b1fd3c89130026cULL, 0x12f7bb1a153f52fcULL, }, - { 0x23efc7de916d3640ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaab9cf8b80ULL, 0x01e950cb80ac7f1cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x428a7d79aac73294ULL, }, - { 0x704f164d5e31e24eULL, 0x092b6b2214879dbcULL, }, - { 0x704f164d5e31e24eULL, 0x166733d9a7c17364ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_h.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_h.c deleted file mode 100644 index a17a69f1f37d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c711c7371c71c71ULL, 0x1c7371c71c711c73ULL, }, - { 0x000638e31c710006ULL, 0x38e31c71000638e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xaaaa00011c72aaaaULL, 0x00011c72aaaa0001ULL, }, - { 0x0004aaaa38e30004ULL, 0xaaaa38e30004aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x55551c7255555555ULL, 0x1c72555555551c72ULL, }, - { 0x0002555555550002ULL, 0x5555555500025555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xcccc22233e94ccccULL, 0x22233e94cccc2223ULL, }, - { 0x05b505b05b0505b5ULL, 0x05b05b0505b505b0ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x16c23333333316c2ULL, 0x3333333316c23333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e438e38e3838e4ULL, 0x38e38e3838e438e3ULL, }, - { 0x38e438e338e338e4ULL, 0x38e338e338e438e3ULL, }, - { 0x16c238e38e3816c2ULL, 0x38e38e3816c238e3ULL, }, - { 0x16c205b027d216c2ULL, 0x05b027d216c205b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000638e31c710006ULL, 0x38e31c71000638e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c711c7271c71c71ULL, 0x1c7271c71c711c72ULL, }, - { 0x1c711c721c721c71ULL, 0x1c721c721c711c72ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c712d830b611c71ULL, 0x2d830b611c712d83ULL, }, - { 0x1c711c7371c71c71ULL, 0x1c7371c71c711c73ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x886a005028625540ULL, 0x12820b5e14c60a14ULL, }, - { 0x886a382228625540ULL, 0x238f0b5e53501bbcULL, }, - { 0x181b07ca28625540ULL, 0x4b670b5e5539b00cULL, }, - { 0x7354006325311c88ULL, 0x12f7053a153f52fcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6400634d933b88ULL, 0x12f7bb1a153f08d4ULL, }, - { 0x1b2000634d93c708ULL, 0x12f73242153f52fcULL, }, - { 0x23f0aeaa18473640ULL, 0x27d805c1ab2b2514ULL, }, /* 72 */ - { 0xac5a00411ea98b80ULL, 0x01ea0be501332514ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b128f5b9e8b80ULL, 0x27d83e2701e92514ULL, }, - { 0x704f164d0d6d37ceULL, 0x428a0070a9423294ULL, }, - { 0x704f0042109e1b46ULL, 0x093088d814893ca8ULL, }, - { 0x704f164d5e3156ceULL, 0x166988d8a9420428ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_w.c b/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_w.c deleted file mode 100644 index ac0f704b18ea..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-modulo/test_msa_mod_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MOD_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Modulo"; - char *instruction_name = "MOD_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71f1c71c71cULL, }, - { 0x000000031c71c71dULL, 0x38e38e3800000003ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0xaaaaaaaa1c71c71cULL, 0x00000002aaaaaaaaULL, }, - { 0x0000000238e38e39ULL, 0xaaaaaaaa00000002ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x5555555555555555ULL, 0x1c71c71d55555555ULL, }, - { 0x0000000155555555ULL, 0x5555555500000001ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xcccccccc3e93e93eULL, 0x22222224ccccccccULL, }, - { 0x05b05b085b05b05bULL, 0x05b05b0505b05b08ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x16c16c1733333333ULL, 0x3333333316c16c17ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e398e38e38eULL, 0x38e38e3838e38e39ULL, }, - { 0x38e38e3938e38e39ULL, 0x38e38e3838e38e39ULL, }, - { 0x16c16c178e38e38eULL, 0x38e38e3816c16c17ULL, }, - { 0x16c16c1727d27d28ULL, 0x05b05b0516c16c17ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000031c71c71dULL, 0x38e38e3800000003ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71d1c71c71cULL, }, - { 0x1c71c71c1c71c71cULL, 0x1c71c71d1c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c71c0b60b60bULL, 0x2d82d82e1c71c71cULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71f1c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x886ae6cc28625540ULL, 0x127fda1014c31f38ULL, }, - { 0x886ae6cc28625540ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07f28625540ULL, 0x4b670b5e5538cd6cULL, }, - { 0x73531997253171c8ULL, 0x12f7bb1a153f52fcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b94d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x1b1fd3c94d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0x23efc7de18463680ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0xac5aaeaa1ea7fd70ULL, 0x01e950cb01308d34ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x27d8c6ff01e84274ULL, }, - { 0x704f164d0d6d37ceULL, 0x428a7d7aa942e2a0ULL, }, - { 0x704f164d109e1b46ULL, 0x092b6b2214879dbcULL, }, - { 0x704f164d5e31e24eULL, 0x166733dba942e2a0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MOD_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_b.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_b.c deleted file mode 100644 index d543e1af28b7..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MADDV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MADDV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 0 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x5757575757575757ULL, 0x5757575757575757ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x3636363636363636ULL, 0x3636363636363636ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x2075cb2075cb2075ULL, 0xcb2075cb2075cb20ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, /* 8 */ - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x0404040404040404ULL, 0x0404040404040404ULL, }, - { 0x5a5a5a5a5a5a5a5aULL, 0x5a5a5a5a5a5a5a5aULL, }, /* 16 */ - { 0x5a5a5a5a5a5a5a5aULL, 0x5a5a5a5a5a5a5a5aULL, }, - { 0x3e3e3e3e3e3e3e3eULL, 0x3e3e3e3e3e3e3e3eULL, }, - { 0xb0b0b0b0b0b0b0b0ULL, 0xb0b0b0b0b0b0b0b0ULL, }, - { 0x2828282828282828ULL, 0x2828282828282828ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0xc45236c45236c452ULL, 0x36c45236c45236c4ULL, }, - { 0x5c5c5c5c5c5c5c5cULL, 0x5c5c5c5c5c5c5c5cULL, }, - { 0x0707070707070707ULL, 0x0707070707070707ULL, }, /* 24 */ - { 0x0707070707070707ULL, 0x0707070707070707ULL, }, - { 0x7979797979797979ULL, 0x7979797979797979ULL, }, - { 0xb2b2b2b2b2b2b2b2ULL, 0xb2b2b2b2b2b2b2b2ULL, }, - { 0x6e6e6e6e6e6e6e6eULL, 0x6e6e6e6e6e6e6e6eULL, }, - { 0x5d5d5d5d5d5d5d5dULL, 0x5d5d5d5d5d5d5d5dULL, }, - { 0xbc83f5bc83f5bc83ULL, 0xf5bc83f5bc83f5bcULL, }, - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, - { 0x3c3c3c3c3c3c3c3cULL, 0x3c3c3c3c3c3c3c3cULL, }, /* 32 */ - { 0x3c3c3c3c3c3c3c3cULL, 0x3c3c3c3c3c3c3c3cULL, }, - { 0xb4b4b4b4b4b4b4b4ULL, 0xb4b4b4b4b4b4b4b4ULL, }, - { 0x7070707070707070ULL, 0x7070707070707070ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xa4a4a4a4a4a4a4a4ULL, 0xa4a4a4a4a4a4a4a4ULL, }, - { 0x88cc4488cc4488ccULL, 0x4488cc4488cc4488ULL, }, - { 0xd8d8d8d8d8d8d8d8ULL, 0xd8d8d8d8d8d8d8d8ULL, }, - { 0xa5a5a5a5a5a5a5a5ULL, 0xa5a5a5a5a5a5a5a5ULL, }, /* 40 */ - { 0xa5a5a5a5a5a5a5a5ULL, 0xa5a5a5a5a5a5a5a5ULL, }, - { 0x8383838383838383ULL, 0x8383838383838383ULL, }, - { 0x7272727272727272ULL, 0x7272727272727272ULL, }, - { 0x1616161616161616ULL, 0x1616161616161616ULL, }, - { 0x3f3f3f3f3f3f3f3fULL, 0x3f3f3f3f3f3f3f3fULL, }, - { 0x7889677889677889ULL, 0x6778896778896778ULL, }, - { 0x0c0c0c0c0c0c0c0cULL, 0x0c0c0c0c0c0c0c0cULL, }, - { 0x297ed4297ed4297eULL, 0xd4297ed4297ed429ULL, }, /* 48 */ - { 0x297ed4297ed4297eULL, 0xd4297ed4297ed429ULL, }, - { 0xe7ca04e7ca04e7caULL, 0x04e7ca04e7ca04e7ULL, }, - { 0x46f09c46f09c46f0ULL, 0x9c46f09c46f09c46ULL, }, - { 0x2a183c2a183c2a18ULL, 0x3c2a183c2a183c2aULL, }, - { 0x6362646362646362ULL, 0x6463626463626463ULL, }, - { 0xac26a4ac26a4ac26ULL, 0xa4ac26a4ac26a4acULL, }, - { 0x80d42c80d42c80d4ULL, 0x2c80d42c80d42c80ULL, }, - { 0x6463656463656463ULL, 0x6564636564636564ULL, }, /* 56 */ - { 0x6463656463656463ULL, 0x6564636564636564ULL, }, - { 0xfc6d8bfc6d8bfc6dULL, 0x8bfc6d8bfc6d8bfcULL, }, - { 0x48f29e48f29e48f2ULL, 0x9e48f29e48f29e48ULL, }, - { 0x98fe3298fe3298feULL, 0x3298fe3298fe3298ULL, }, - { 0x2c81d72c81d72c81ULL, 0xd72c81d72c81d72cULL, }, - { 0x002f5f002f5f002fULL, 0x5f002f5f002f5f00ULL, }, - { 0x1010101010101010ULL, 0x1010101010101010ULL, }, - { 0x50f4b4a050944910ULL, 0x09818994142910a0ULL, }, /* 64 */ - { 0xa8a0b48458da5c10ULL, 0x4fe29220ea6e7070ULL, }, - { 0x08e408fc40188310ULL, 0xbcca14c29417e060ULL, }, - { 0x889acc58f0da8d90ULL, 0x0bc1ec1242cd40e0ULL, }, - { 0xe046cc3cf820a090ULL, 0x5122f59e1812a0b0ULL, }, - { 0xf94acc85218951d0ULL, 0x95738e42d193e4c0ULL, }, - { 0x9d16cc43c6665ed0ULL, 0x53db3028d828be70ULL, }, - { 0x6db8cc0a0c890c40ULL, 0x3d628818b56622f0ULL, }, - { 0xcdfc2082f4c73340ULL, 0xaa4a0aba5f0f92e0ULL, }, /* 72 */ - { 0x71c8204099a44040ULL, 0x68b2aca066a46c90ULL, }, - { 0x016c64244a05b940ULL, 0x59f2d0a19fddc520ULL, }, - { 0x4132584638a46f40ULL, 0xd44a00c982f36fa0ULL, }, - { 0xc1e81ca2e86679c0ULL, 0x2341d81930a9cf20ULL, }, - { 0x918a1c692e892730ULL, 0x0dc830090de733a0ULL, }, - { 0xd150108b1c28dd30ULL, 0x88206031f0fddd20ULL, }, - { 0xd1b1f4b4a08961f4ULL, 0x3101a07181016120ULL, }, - { 0xd9fb2c24a0fb96f4ULL, 0x8c6880ef7f7c11a0ULL, }, /* 80 */ - { 0x9c452c10c01c3094ULL, 0x64c00035ea008320ULL, }, - { 0x6c8714b080c04094ULL, 0xa0c00000380072a0ULL, }, - { 0xac30cca08080c0acULL, 0xc0800000300016a0ULL, }, - { 0x0c101420808080acULL, 0x00000000d0003620ULL, }, - { 0xd0f014800000000cULL, 0x00000000e00082a0ULL, }, - { 0x9050ac800000000cULL, 0x0000000080004c20ULL, }, - { 0x90007400000000b4ULL, 0x0000000000006420ULL, }, - { 0x1000ac00000000b4ULL, 0x00000000000024a0ULL, }, /* 88 */ - { 0xc000ac0000000054ULL, 0x000000000000ac20ULL, }, - { 0xc000940000000054ULL, 0x00000000000088a0ULL, }, - { 0xc0004c00000000ecULL, 0x00000000000098a0ULL, }, - { 0xc0009400000000ecULL, 0x0000000000001820ULL, }, - { 0x000094000000004cULL, 0x000000000000c8a0ULL, }, - { 0x00002c000000004cULL, 0x000000000000b020ULL, }, - { 0x0000f40000000074ULL, 0x0000000000001020ULL, }, - { 0x00002c0000000074ULL, 0x00000000000010a0ULL, }, /* 96 */ - { 0x0000b40000000074ULL, 0x0000000000001020ULL, }, - { 0x00006c0000000074ULL, 0x00000000000010a0ULL, }, - { 0x0000740000000074ULL, 0x0000000000001020ULL, }, - { 0x0000740000000014ULL, 0x00000000000030a0ULL, }, - { 0x00007400000000b4ULL, 0x0000000000009020ULL, }, - { 0x0000740000000054ULL, 0x000000000000b0a0ULL, }, - { 0x00007400000000f4ULL, 0x0000000000001020ULL, }, - { 0x00004c00000000f4ULL, 0x00000000000060a0ULL, }, /* 104 */ - { 0x0000f400000000f4ULL, 0x0000000000004020ULL, }, - { 0x0000cc00000000f4ULL, 0x00000000000080a0ULL, }, - { 0x00007400000000f4ULL, 0x0000000000000020ULL, }, - { 0x00006c000000004cULL, 0x0000000000000020ULL, }, - { 0x0000b40000000074ULL, 0x0000000000000020ULL, }, - { 0x00002c00000000ccULL, 0x0000000000000020ULL, }, - { 0x0000f400000000f4ULL, 0x0000000000000020ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_d.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_d.c deleted file mode 100644 index fda35f757bc9..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MADDV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MADDV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 0 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x5555555555555557ULL, 0x5555555555555557ULL, }, - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, - { 0x3333333333333336ULL, 0x3333333333333336ULL, }, - { 0x0000000000000003ULL, 0x0000000000000003ULL, }, - { 0x1c71c71c71c71c75ULL, 0xc71c71c71c71c720ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, /* 8 */ - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x0000000000000004ULL, 0x0000000000000004ULL, }, - { 0x555555555555555aULL, 0x555555555555555aULL, }, /* 16 */ - { 0x555555555555555aULL, 0x555555555555555aULL, }, - { 0x8e38e38e38e38e3eULL, 0x8e38e38e38e38e3eULL, }, - { 0xaaaaaaaaaaaaaab0ULL, 0xaaaaaaaaaaaaaab0ULL, }, - { 0x2222222222222228ULL, 0x2222222222222228ULL, }, - { 0x0000000000000006ULL, 0x0000000000000006ULL, }, - { 0x12f684bda12f6852ULL, 0x2f684bda12f684c4ULL, }, - { 0x555555555555555cULL, 0x555555555555555cULL, }, - { 0x0000000000000007ULL, 0x0000000000000007ULL, }, /* 24 */ - { 0x0000000000000007ULL, 0x0000000000000007ULL, }, - { 0x1c71c71c71c71c79ULL, 0x1c71c71c71c71c79ULL, }, - { 0xaaaaaaaaaaaaaab2ULL, 0xaaaaaaaaaaaaaab2ULL, }, - { 0x666666666666666eULL, 0x666666666666666eULL, }, - { 0x555555555555555dULL, 0x555555555555555dULL, }, - { 0x5ed097b425ed0983ULL, 0xed097b425ed097bcULL, }, - { 0x0000000000000008ULL, 0x0000000000000008ULL, }, - { 0x333333333333333cULL, 0x333333333333333cULL, }, /* 32 */ - { 0x333333333333333cULL, 0x333333333333333cULL, }, - { 0xaaaaaaaaaaaaaab4ULL, 0xaaaaaaaaaaaaaab4ULL, }, - { 0x6666666666666670ULL, 0x6666666666666670ULL, }, - { 0x5c28f5c28f5c2900ULL, 0x5c28f5c28f5c2900ULL, }, - { 0x99999999999999a4ULL, 0x99999999999999a4ULL, }, - { 0x16c16c16c16c16ccULL, 0xd27d27d27d27d288ULL, }, - { 0xccccccccccccccd8ULL, 0xccccccccccccccd8ULL, }, - { 0x99999999999999a5ULL, 0x99999999999999a5ULL, }, /* 40 */ - { 0x99999999999999a5ULL, 0x99999999999999a5ULL, }, - { 0x7777777777777783ULL, 0x7777777777777783ULL, }, - { 0x6666666666666672ULL, 0x6666666666666672ULL, }, - { 0xa3d70a3d70a3d716ULL, 0xa3d70a3d70a3d716ULL, }, - { 0x333333333333333fULL, 0x333333333333333fULL, }, - { 0xd27d27d27d27d289ULL, 0xc16c16c16c16c178ULL, }, - { 0x000000000000000cULL, 0x000000000000000cULL, }, - { 0x1c71c71c71c71c7eULL, 0xc71c71c71c71c729ULL, }, /* 48 */ - { 0x1c71c71c71c71c7eULL, 0xc71c71c71c71c729ULL, }, - { 0x2f684bda12f684caULL, 0xf684bda12f684be7ULL, }, - { 0x38e38e38e38e38f0ULL, 0x8e38e38e38e38e46ULL, }, - { 0xb60b60b60b60b618ULL, 0xc71c71c71c71c72aULL, }, - { 0x5555555555555562ULL, 0x5555555555555563ULL, }, - { 0x06522c3f35ba7826ULL, 0xa781948b0fcd6eacULL, }, - { 0x71c71c71c71c71d4ULL, 0x1c71c71c71c71c80ULL, }, - { 0x5555555555555563ULL, 0x5555555555555564ULL, }, /* 56 */ - { 0x5555555555555563ULL, 0x5555555555555564ULL, }, - { 0x97b425ed097b426dULL, 0x7b425ed097b425fcULL, }, - { 0x38e38e38e38e38f2ULL, 0x8e38e38e38e38e48ULL, }, - { 0xeeeeeeeeeeeeeefeULL, 0x8888888888888898ULL, }, - { 0x1c71c71c71c71c81ULL, 0xc71c71c71c71c72cULL, }, - { 0x87e6b74f0329162fULL, 0x3c0ca4587e6b7500ULL, }, - { 0x0000000000000010ULL, 0x0000000000000010ULL, }, - { 0xad45be6961639010ULL, 0x3297fdea749880a0ULL, }, /* 64 */ - { 0x9ced640a487afa10ULL, 0xeaa90809e3b1a470ULL, }, - { 0xa5b377aa0caf5a10ULL, 0x95c9a7903bd12160ULL, }, - { 0xa194ffe4fb27d390ULL, 0x17e6ccd3c9a1c0e0ULL, }, - { 0x913ca585e23f3d90ULL, 0xcff7d6f338bae4b0ULL, }, - { 0xc8ead0bee02cadd0ULL, 0x381c4d6a83a94cc0ULL, }, - { 0x33b60e279e9989d0ULL, 0xe7f71f9b97ee3470ULL, }, - { 0x217580abbfdd3e40ULL, 0x6779436687bc89f0ULL, }, - { 0x2a3b944b84119e40ULL, 0x1299e2ecdfdc06e0ULL, }, /* 72 */ - { 0x9506d1b4427e7a40ULL, 0xc274b51df420ee90ULL, }, - { 0x1b2bb7962782ba40ULL, 0x9bf62dc42637b820ULL, }, - { 0x91d16316b1663b40ULL, 0x3cf7c824fb128ca0ULL, }, - { 0x8db2eb519fdeb4c0ULL, 0xbf14ed6888e32c20ULL, }, - { 0x7b725dd5c1226930ULL, 0x3e97113378b181a0ULL, }, - { 0xf21809564b05ea30ULL, 0xdf98ab944d8c5620ULL, }, - { 0x3dcc402bfcefb9f4ULL, 0xf26a7a4530ab3a20ULL, }, - { 0x81a8956a21043af4ULL, 0xe63ec4a9de07f3a0ULL, }, /* 80 */ - { 0x14acc7eab115be94ULL, 0xa72fae300e450520ULL, }, - { 0x4c5c3900181b6494ULL, 0xc26796e561c70ba0ULL, }, - { 0x513451003792b1acULL, 0x5acad191d5b18fa0ULL, }, - { 0x0daff27cb51538acULL, 0x31375ce2aea24b20ULL, }, - { 0xbb9ebee52390b20cULL, 0xd8cfb350af547ea0ULL, }, - { 0x4df25269204a3c0cULL, 0x07b9241bbd1b8320ULL, }, - { 0x39b3c4d066371fb4ULL, 0x2a4dc00c264fb720ULL, }, - { 0xf9aee458846dd0b4ULL, 0x79d838b37c524ca0ULL, }, /* 88 */ - { 0x115f9e7f00744254ULL, 0x46ec87fe3540fa20ULL, }, - { 0xb01458f6b0850854ULL, 0xde82246a25db24a0ULL, }, - { 0xc18097bf5a7bb9ecULL, 0x4155f0da566748a0ULL, }, - { 0x70c7391b1a7d90ecULL, 0x0400deec0a0cb020ULL, }, - { 0xf7a41980bd958c4cULL, 0xedfeb14ff6d44fa0ULL, }, - { 0x7906f19718fcf64cULL, 0x29e471752ecca820ULL, }, - { 0xb6393967140b1974ULL, 0xbd0ed4c39361fc20ULL, }, - { 0x74ecb57da4acfa74ULL, 0x36ea3f3dbcafcda0ULL, }, /* 96 */ - { 0x5b14aa5e3f7c1b74ULL, 0xeb031f17fe2b7120ULL, }, - { 0x0468573ef6087c74ULL, 0xe8ef35d2e05abea0ULL, }, - { 0xd69cf5cf0de21d74ULL, 0x39f569701e89ae20ULL, }, - { 0xf233f7a10f743514ULL, 0xf574fc00c1b755a0ULL, }, - { 0x873c421a5ed469b4ULL, 0x96f393305dfcdf20ULL, }, - { 0x17e80b0449fea354ULL, 0x2f05ddb06b40c2a0ULL, }, - { 0x0741f67f982609f4ULL, 0x9c23f2dbc2b79820ULL, }, - { 0x530275e3b2de7ff4ULL, 0xc6904e7f6f6c1aa0ULL, }, /* 104 */ - { 0xf8214644bbe3f5f4ULL, 0xe44a0de01c974f20ULL, }, - { 0xb59c90c0a8b66bf4ULL, 0x9abcf7a8e1391da0ULL, }, - { 0xb67d543caed5e1f4ULL, 0x4ce8f72994d78e20ULL, }, - { 0xcee67f5e9d2e224cULL, 0xba31bdf2ab48a220ULL, }, - { 0x87acb43db40fad74ULL, 0x8a259794c40e3620ULL, }, - { 0x45c27495332aeeccULL, 0xe81c4208ecf84a20ULL, }, - { 0x50a99b794e1bc8f4ULL, 0x17cdf4c275d6de20ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_h.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_h.c deleted file mode 100644 index a9ee9b328a65..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MADDV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MADDV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 0 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x5557555755575557ULL, 0x5557555755575557ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, - { 0x3336333633363336ULL, 0x3336333633363336ULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x1c75c72071cb1c75ULL, 0xc72071cb1c75c720ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, /* 8 */ - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x0004000400040004ULL, 0x0004000400040004ULL, }, - { 0x555a555a555a555aULL, 0x555a555a555a555aULL, }, /* 16 */ - { 0x555a555a555a555aULL, 0x555a555a555a555aULL, }, - { 0x8e3e8e3e8e3e8e3eULL, 0x8e3e8e3e8e3e8e3eULL, }, - { 0xaab0aab0aab0aab0ULL, 0xaab0aab0aab0aab0ULL, }, - { 0x2228222822282228ULL, 0x2228222822282228ULL, }, - { 0x0006000600060006ULL, 0x0006000600060006ULL, }, - { 0x685284c4a1366852ULL, 0x84c4a136685284c4ULL, }, - { 0x555c555c555c555cULL, 0x555c555c555c555cULL, }, - { 0x0007000700070007ULL, 0x0007000700070007ULL, }, /* 24 */ - { 0x0007000700070007ULL, 0x0007000700070007ULL, }, - { 0x1c791c791c791c79ULL, 0x1c791c791c791c79ULL, }, - { 0xaab2aab2aab2aab2ULL, 0xaab2aab2aab2aab2ULL, }, - { 0x666e666e666e666eULL, 0x666e666e666e666eULL, }, - { 0x555d555d555d555dULL, 0x555d555d555d555dULL, }, - { 0x098397bc25f50983ULL, 0x97bc25f5098397bcULL, }, - { 0x0008000800080008ULL, 0x0008000800080008ULL, }, - { 0x333c333c333c333cULL, 0x333c333c333c333cULL, }, /* 32 */ - { 0x333c333c333c333cULL, 0x333c333c333c333cULL, }, - { 0xaab4aab4aab4aab4ULL, 0xaab4aab4aab4aab4ULL, }, - { 0x6670667066706670ULL, 0x6670667066706670ULL, }, - { 0x2900290029002900ULL, 0x2900290029002900ULL, }, - { 0x99a499a499a499a4ULL, 0x99a499a499a499a4ULL, }, - { 0x16ccd2888e4416ccULL, 0xd2888e4416ccd288ULL, }, - { 0xccd8ccd8ccd8ccd8ULL, 0xccd8ccd8ccd8ccd8ULL, }, - { 0x99a599a599a599a5ULL, 0x99a599a599a599a5ULL, }, /* 40 */ - { 0x99a599a599a599a5ULL, 0x99a599a599a599a5ULL, }, - { 0x7783778377837783ULL, 0x7783778377837783ULL, }, - { 0x6672667266726672ULL, 0x6672667266726672ULL, }, - { 0xd716d716d716d716ULL, 0xd716d716d716d716ULL, }, - { 0x333f333f333f333fULL, 0x333f333f333f333fULL, }, - { 0xd289c178b067d289ULL, 0xc178b067d289c178ULL, }, - { 0x000c000c000c000cULL, 0x000c000c000c000cULL, }, - { 0x1c7ec72971d41c7eULL, 0xc72971d41c7ec729ULL, }, /* 48 */ - { 0x1c7ec72971d41c7eULL, 0xc72971d41c7ec729ULL, }, - { 0x84ca4be7130484caULL, 0x4be7130484ca4be7ULL, }, - { 0x38f08e46e39c38f0ULL, 0x8e46e39c38f08e46ULL, }, - { 0xb618c72ad83cb618ULL, 0xc72ad83cb618c72aULL, }, - { 0x5562556355645562ULL, 0x5563556455625563ULL, }, - { 0x78266eac81a47826ULL, 0x6eac81a478266eacULL, }, - { 0x71d41c80c72c71d4ULL, 0x1c80c72c71d41c80ULL, }, - { 0x5563556455655563ULL, 0x5564556555635564ULL, }, /* 56 */ - { 0x5563556455655563ULL, 0x5564556555635564ULL, }, - { 0x426d25fc098b426dULL, 0x25fc098b426d25fcULL, }, - { 0x38f28e48e39e38f2ULL, 0x8e48e39e38f28e48ULL, }, - { 0xeefe88982232eefeULL, 0x88982232eefe8898ULL, }, - { 0x1c81c72c71d71c81ULL, 0xc72c71d71c81c72cULL, }, - { 0x162f7500b75f162fULL, 0x7500b75f162f7500ULL, }, - { 0x0010001000100010ULL, 0x0010001000100010ULL, }, - { 0xcbf432a0c5949010ULL, 0x838136944f2980a0ULL, }, /* 64 */ - { 0xf8a073846fdafa10ULL, 0x81e20820066ea470ULL, }, - { 0x25e45efce9185a10ULL, 0xd1ca0ec2ee172160ULL, }, - { 0x9e9a52589fdad390ULL, 0x88c19612bccdc0e0ULL, }, - { 0xcb46933c4a203d90ULL, 0x8722679e7412e4b0ULL, }, - { 0xec4ab9850c89add0ULL, 0x31736642d9934cc0ULL, }, - { 0x15164543016689d0ULL, 0xd2dbe12880283470ULL, }, - { 0xe4b8e50ad4893e40ULL, 0xb8628f18916689f0ULL, }, - { 0x11fcd0824dc79e40ULL, 0x084a95ba790f06e0ULL, }, /* 72 */ - { 0x3ac85c4042a47a40ULL, 0xa9b210a01fa4ee90ULL, }, - { 0x4a6ce5241805ba40ULL, 0x2ff282a198ddb820ULL, }, - { 0xda320a46aaa43b40ULL, 0xaa4ae1c91cf38ca0ULL, }, - { 0x52e8fda26166b4c0ULL, 0x61416919eba92c20ULL, }, - { 0x228a9d6934896930ULL, 0x46c81709fce781a0ULL, }, - { 0xb250c28bc728ea30ULL, 0xc120763180fd5620ULL, }, - { 0xeab115b4cc89b9f4ULL, 0x1e01ac71b6013a20ULL, }, - { 0x1ffb192480fb3af4ULL, 0x7b68d8ef267cf3a0ULL, }, /* 80 */ - { 0xf545d210101cbe94ULL, 0xdcc07635cb000520ULL, }, - { 0x8b8730b052c06494ULL, 0x5ec03300e4000ba0ULL, }, - { 0xaa30f5a0a980b1acULL, 0x51803b00ac008fa0ULL, }, - { 0xa21071208c8038acULL, 0x9c00e50050004b20ULL, }, - { 0x99f03080ba00b20cULL, 0x2000270000007ea0ULL, }, - { 0xf850658020003c0cULL, 0x2000000000008320ULL, }, - { 0x9900ed0040001fb4ULL, 0x400000000000b720ULL, }, - { 0xf300c900c000d0b4ULL, 0x0000000000004ca0ULL, }, /* 88 */ - { 0x4d00840000004254ULL, 0x000000000000fa20ULL, }, - { 0x5f002c0000000854ULL, 0x00000000000024a0ULL, }, - { 0xb00068000000b9ecULL, 0x00000000000048a0ULL, }, - { 0x90004800000090ecULL, 0x000000000000b020ULL, }, - { 0x7000200000008c4cULL, 0x0000000000004fa0ULL, }, - { 0xd00060000000f64cULL, 0x000000000000a820ULL, }, - { 0x0000400000001974ULL, 0x000000000000fc20ULL, }, - { 0x000040000000fa74ULL, 0x000000000000cda0ULL, }, /* 96 */ - { 0x0000400000001b74ULL, 0x0000000000007120ULL, }, - { 0x0000400000007c74ULL, 0x000000000000bea0ULL, }, - { 0x0000400000001d74ULL, 0x000000000000ae20ULL, }, - { 0x0000000000003514ULL, 0x00000000000055a0ULL, }, - { 0x00000000000069b4ULL, 0x000000000000df20ULL, }, - { 0x000000000000a354ULL, 0x000000000000c2a0ULL, }, - { 0x00000000000009f4ULL, 0x0000000000009820ULL, }, - { 0x0000000000007ff4ULL, 0x0000000000001aa0ULL, }, /* 104 */ - { 0x000000000000f5f4ULL, 0x0000000000004f20ULL, }, - { 0x0000000000006bf4ULL, 0x0000000000001da0ULL, }, - { 0x000000000000e1f4ULL, 0x0000000000008e20ULL, }, - { 0x000000000000224cULL, 0x000000000000a220ULL, }, - { 0x000000000000ad74ULL, 0x0000000000003620ULL, }, - { 0x000000000000eeccULL, 0x0000000000004a20ULL, }, - { 0x000000000000c8f4ULL, 0x000000000000de20ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_w.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_w.c deleted file mode 100644 index bc3f5d246e7c..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_maddv_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MADDV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MADDV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 0 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x5555555755555557ULL, 0x5555555755555557ULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, - { 0x3333333633333336ULL, 0x3333333633333336ULL, }, - { 0x0000000300000003ULL, 0x0000000300000003ULL, }, - { 0x1c71c72071c71c75ULL, 0xc71c71cb1c71c720ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, /* 8 */ - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x0000000400000004ULL, 0x0000000400000004ULL, }, - { 0x5555555a5555555aULL, 0x5555555a5555555aULL, }, /* 16 */ - { 0x5555555a5555555aULL, 0x5555555a5555555aULL, }, - { 0x38e38e3e38e38e3eULL, 0x38e38e3e38e38e3eULL, }, - { 0xaaaaaab0aaaaaab0ULL, 0xaaaaaab0aaaaaab0ULL, }, - { 0x2222222822222228ULL, 0x2222222822222228ULL, }, - { 0x0000000600000006ULL, 0x0000000600000006ULL, }, - { 0x12f684c4a12f6852ULL, 0x84bda13612f684c4ULL, }, - { 0x5555555c5555555cULL, 0x5555555c5555555cULL, }, - { 0x0000000700000007ULL, 0x0000000700000007ULL, }, /* 24 */ - { 0x0000000700000007ULL, 0x0000000700000007ULL, }, - { 0x71c71c7971c71c79ULL, 0x71c71c7971c71c79ULL, }, - { 0xaaaaaab2aaaaaab2ULL, 0xaaaaaab2aaaaaab2ULL, }, - { 0x6666666e6666666eULL, 0x6666666e6666666eULL, }, - { 0x5555555d5555555dULL, 0x5555555d5555555dULL, }, - { 0x5ed097bc25ed0983ULL, 0x97b425f55ed097bcULL, }, - { 0x0000000800000008ULL, 0x0000000800000008ULL, }, - { 0x3333333c3333333cULL, 0x3333333c3333333cULL, }, /* 32 */ - { 0x3333333c3333333cULL, 0x3333333c3333333cULL, }, - { 0xaaaaaab4aaaaaab4ULL, 0xaaaaaab4aaaaaab4ULL, }, - { 0x6666667066666670ULL, 0x6666667066666670ULL, }, - { 0x8f5c29008f5c2900ULL, 0x8f5c29008f5c2900ULL, }, - { 0x999999a4999999a4ULL, 0x999999a4999999a4ULL, }, - { 0x7d27d288c16c16ccULL, 0x38e38e447d27d288ULL, }, - { 0xccccccd8ccccccd8ULL, 0xccccccd8ccccccd8ULL, }, - { 0x999999a5999999a5ULL, 0x999999a5999999a5ULL, }, /* 40 */ - { 0x999999a5999999a5ULL, 0x999999a5999999a5ULL, }, - { 0x7777778377777783ULL, 0x7777778377777783ULL, }, - { 0x6666667266666672ULL, 0x6666667266666672ULL, }, - { 0x70a3d71670a3d716ULL, 0x70a3d71670a3d716ULL, }, - { 0x3333333f3333333fULL, 0x3333333f3333333fULL, }, - { 0x6c16c1787d27d289ULL, 0x5b05b0676c16c178ULL, }, - { 0x0000000c0000000cULL, 0x0000000c0000000cULL, }, - { 0x1c71c72971c71c7eULL, 0xc71c71d41c71c729ULL, }, /* 48 */ - { 0x1c71c72971c71c7eULL, 0xc71c71d41c71c729ULL, }, - { 0x2f684be712f684caULL, 0x4bda13042f684be7ULL, }, - { 0x38e38e46e38e38f0ULL, 0x8e38e39c38e38e46ULL, }, - { 0x1c71c72a0b60b618ULL, 0x2d82d83c1c71c72aULL, }, - { 0x5555556355555562ULL, 0x5555556455555563ULL, }, - { 0x0fcd6eac35ba7826ULL, 0x5ba781a40fcd6eacULL, }, - { 0x71c71c80c71c71d4ULL, 0x1c71c72c71c71c80ULL, }, - { 0x5555556455555563ULL, 0x5555556555555564ULL, }, /* 56 */ - { 0x5555556455555563ULL, 0x5555556555555564ULL, }, - { 0x97b425fc097b426dULL, 0x25ed098b97b425fcULL, }, - { 0x38e38e48e38e38f2ULL, 0x8e38e39e38e38e48ULL, }, - { 0x88888898eeeeeefeULL, 0x2222223288888898ULL, }, - { 0x1c71c72c71c71c81ULL, 0xc71c71d71c71c72cULL, }, - { 0x7e6b75000329162fULL, 0x87e6b75f7e6b7500ULL, }, - { 0x0000001000000010ULL, 0x0000001000000010ULL, }, - { 0xb10332a061639010ULL, 0x3a253694749880a0ULL, }, /* 64 */ - { 0xc1c27384487afa10ULL, 0xbb9c0820e3b1a470ULL, }, - { 0x35565efc0caf5a10ULL, 0x735b0ec23bd12160ULL, }, - { 0xe6475258fb27d390ULL, 0x49d49612c9a1c0e0ULL, }, - { 0xf706933ce23f3d90ULL, 0xcb4b679e38bae4b0ULL, }, - { 0xabfab985e02cadd0ULL, 0x0836664283a94cc0ULL, }, - { 0xa33845439e9989d0ULL, 0x5b9fe12897ee3470ULL, }, - { 0x1df3e50abfdd3e40ULL, 0x6d858f1887bc89f0ULL, }, - { 0x9187d08284119e40ULL, 0x254495badfdc06e0ULL, }, /* 72 */ - { 0x88c55c40427e7a40ULL, 0x78ae10a0f420ee90ULL, }, - { 0x3f78e5242782ba40ULL, 0x93ad82a12637b820ULL, }, - { 0x28380a46b1663b40ULL, 0x255be1c9fb128ca0ULL, }, - { 0xd928fda29fdeb4c0ULL, 0xfbd5691988e32c20ULL, }, - { 0x53e49d69c1226930ULL, 0x0dbb170978b181a0ULL, }, - { 0x3ca3c28b4b05ea30ULL, 0x9f6976314d8c5620ULL, }, - { 0x621b15b4fcefb9f4ULL, 0x7f3fac7130ab3a20ULL, }, - { 0x81b8192421043af4ULL, 0x7180d8efde07f3a0ULL, }, /* 80 */ - { 0xa0a1d210b115be94ULL, 0x33a676350e450520ULL, }, - { 0xe27e30b0181b6494ULL, 0x359b330061c70ba0ULL, }, - { 0xe0f1f5a03792b1acULL, 0xe6a63b00d5b18fa0ULL, }, - { 0x38af7120b51538acULL, 0x7938e500aea24b20ULL, }, - { 0x7a4830802390b20cULL, 0x4b472700af547ea0ULL, }, - { 0xcc2f6580204a3c0cULL, 0x37510000bd1b8320ULL, }, - { 0x9ba9ed0066371fb4ULL, 0xeba90000264fb720ULL, }, - { 0x7400c900846dd0b4ULL, 0xb6b700007c524ca0ULL, }, /* 88 */ - { 0x7e4e840000744254ULL, 0xf24d00003540fa20ULL, }, - { 0x242a2c00b0850854ULL, 0xdb00000025db24a0ULL, }, - { 0x38a168005a7bb9ecULL, 0xa3000000566748a0ULL, }, - { 0x6cb048001a7d90ecULL, 0x7d0000000a0cb020ULL, }, - { 0xe4dc2000bd958c4cULL, 0x2f000000f6d44fa0ULL, }, - { 0xbcc9600018fcf64cULL, 0x000000002ecca820ULL, }, - { 0x739b4000140b1974ULL, 0x000000009361fc20ULL, }, - { 0x8ed24000a4acfa74ULL, 0x00000000bcafcda0ULL, }, /* 96 */ - { 0xc3dd40003f7c1b74ULL, 0x00000000fe2b7120ULL, }, - { 0x1fac4000f6087c74ULL, 0x00000000e05abea0ULL, }, - { 0x9e6f40000de21d74ULL, 0x000000001e89ae20ULL, }, - { 0x637500000f743514ULL, 0x00000000c1b755a0ULL, }, - { 0xd9b400005ed469b4ULL, 0x000000005dfcdf20ULL, }, - { 0x0a50000049fea354ULL, 0x000000006b40c2a0ULL, }, - { 0x07400000982609f4ULL, 0x00000000c2b79820ULL, }, - { 0x57c00000b2de7ff4ULL, 0x000000006f6c1aa0ULL, }, /* 104 */ - { 0x1d400000bbe3f5f4ULL, 0x000000001c974f20ULL, }, - { 0x09c00000a8b66bf4ULL, 0x00000000e1391da0ULL, }, - { 0x03400000aed5e1f4ULL, 0x0000000094d78e20ULL, }, - { 0x7d8000009d2e224cULL, 0x00000000ab48a220ULL, }, - { 0x3d000000b40fad74ULL, 0x00000000c40e3620ULL, }, - { 0x96000000332aeeccULL, 0x00000000ecf84a20ULL, }, - { 0xb40000004e1bc8f4ULL, 0x0000000075d6de20ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MADDV_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_b.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_b.c deleted file mode 100644 index 808c49d050b7..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MSUBV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MSUBV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xa9a9a9a9a9a9a9a9ULL, 0xa9a9a9a9a9a9a9a9ULL, }, - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, - { 0xcacacacacacacacaULL, 0xcacacacacacacacaULL, }, - { 0xfdfdfdfdfdfdfdfdULL, 0xfdfdfdfdfdfdfdfdULL, }, - { 0xe08b35e08b35e08bULL, 0x35e08b35e08b35e0ULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, /* 8 */ - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xa6a6a6a6a6a6a6a6ULL, 0xa6a6a6a6a6a6a6a6ULL, }, /* 16 */ - { 0xa6a6a6a6a6a6a6a6ULL, 0xa6a6a6a6a6a6a6a6ULL, }, - { 0xc2c2c2c2c2c2c2c2ULL, 0xc2c2c2c2c2c2c2c2ULL, }, - { 0x5050505050505050ULL, 0x5050505050505050ULL, }, - { 0xd8d8d8d8d8d8d8d8ULL, 0xd8d8d8d8d8d8d8d8ULL, }, - { 0xfafafafafafafafaULL, 0xfafafafafafafafaULL, }, - { 0x3caeca3caeca3caeULL, 0xca3caeca3caeca3cULL, }, - { 0xa4a4a4a4a4a4a4a4ULL, 0xa4a4a4a4a4a4a4a4ULL, }, - { 0xf9f9f9f9f9f9f9f9ULL, 0xf9f9f9f9f9f9f9f9ULL, }, /* 24 */ - { 0xf9f9f9f9f9f9f9f9ULL, 0xf9f9f9f9f9f9f9f9ULL, }, - { 0x8787878787878787ULL, 0x8787878787878787ULL, }, - { 0x4e4e4e4e4e4e4e4eULL, 0x4e4e4e4e4e4e4e4eULL, }, - { 0x9292929292929292ULL, 0x9292929292929292ULL, }, - { 0xa3a3a3a3a3a3a3a3ULL, 0xa3a3a3a3a3a3a3a3ULL, }, - { 0x447d0b447d0b447dULL, 0x0b447d0b447d0b44ULL, }, - { 0xf8f8f8f8f8f8f8f8ULL, 0xf8f8f8f8f8f8f8f8ULL, }, - { 0xc4c4c4c4c4c4c4c4ULL, 0xc4c4c4c4c4c4c4c4ULL, }, /* 32 */ - { 0xc4c4c4c4c4c4c4c4ULL, 0xc4c4c4c4c4c4c4c4ULL, }, - { 0x4c4c4c4c4c4c4c4cULL, 0x4c4c4c4c4c4c4c4cULL, }, - { 0x9090909090909090ULL, 0x9090909090909090ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5c5c5c5c5c5c5c5cULL, 0x5c5c5c5c5c5c5c5cULL, }, - { 0x7834bc7834bc7834ULL, 0xbc7834bc7834bc78ULL, }, - { 0x2828282828282828ULL, 0x2828282828282828ULL, }, - { 0x5b5b5b5b5b5b5b5bULL, 0x5b5b5b5b5b5b5b5bULL, }, /* 40 */ - { 0x5b5b5b5b5b5b5b5bULL, 0x5b5b5b5b5b5b5b5bULL, }, - { 0x7d7d7d7d7d7d7d7dULL, 0x7d7d7d7d7d7d7d7dULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0xeaeaeaeaeaeaeaeaULL, 0xeaeaeaeaeaeaeaeaULL, }, - { 0xc1c1c1c1c1c1c1c1ULL, 0xc1c1c1c1c1c1c1c1ULL, }, - { 0x8877998877998877ULL, 0x9988779988779988ULL, }, - { 0xf4f4f4f4f4f4f4f4ULL, 0xf4f4f4f4f4f4f4f4ULL, }, - { 0xd7822cd7822cd782ULL, 0x2cd7822cd7822cd7ULL, }, /* 48 */ - { 0xd7822cd7822cd782ULL, 0x2cd7822cd7822cd7ULL, }, - { 0x1936fc1936fc1936ULL, 0xfc1936fc1936fc19ULL, }, - { 0xba1064ba1064ba10ULL, 0x64ba1064ba1064baULL, }, - { 0xd6e8c4d6e8c4d6e8ULL, 0xc4d6e8c4d6e8c4d6ULL, }, - { 0x9d9e9c9d9e9c9d9eULL, 0x9c9d9e9c9d9e9c9dULL, }, - { 0x54da5c54da5c54daULL, 0x5c54da5c54da5c54ULL, }, - { 0x802cd4802cd4802cULL, 0xd4802cd4802cd480ULL, }, - { 0x9c9d9b9c9d9b9c9dULL, 0x9b9c9d9b9c9d9b9cULL, }, /* 56 */ - { 0x9c9d9b9c9d9b9c9dULL, 0x9b9c9d9b9c9d9b9cULL, }, - { 0x0493750493750493ULL, 0x7504937504937504ULL, }, - { 0xb80e62b80e62b80eULL, 0x62b80e62b80e62b8ULL, }, - { 0x6802ce6802ce6802ULL, 0xce6802ce6802ce68ULL, }, - { 0xd47f29d47f29d47fULL, 0x29d47f29d47f29d4ULL, }, - { 0x00d1a100d1a100d1ULL, 0xa100d1a100d1a100ULL, }, - { 0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL, }, - { 0xb00c4c60b06cb7f0ULL, 0xf77f776cecd7f060ULL, }, /* 64 */ - { 0x58604c7ca826a4f0ULL, 0xb11e6ee016929090ULL, }, - { 0xf81cf804c0e87df0ULL, 0x4436ec3e6ce920a0ULL, }, - { 0x786634a810267370ULL, 0xf53f14eebe33c020ULL, }, - { 0x20ba34c408e06070ULL, 0xafde0b62e8ee6050ULL, }, - { 0x07b6347bdf77af30ULL, 0x6b8d72be2f6d1c40ULL, }, - { 0x63ea34bd3a9aa230ULL, 0xad25d0d828d84290ULL, }, - { 0x934834f6f477f4c0ULL, 0xc39e78e84b9ade10ULL, }, - { 0x3304e07e0c39cdc0ULL, 0x56b6f646a1f16e20ULL, }, /* 72 */ - { 0x8f38e0c0675cc0c0ULL, 0x984e54609a5c9470ULL, }, - { 0xff949cdcb6fb47c0ULL, 0xa70e305f61233be0ULL, }, - { 0xbfcea8bac85c91c0ULL, 0x2cb600377e0d9160ULL, }, - { 0x3f18e45e189a8740ULL, 0xddbf28e7d05731e0ULL, }, - { 0x6f76e497d277d9d0ULL, 0xf338d0f7f319cd60ULL, }, - { 0x2fb0f075e4d823d0ULL, 0x78e0a0cf100323e0ULL, }, - { 0x2f4f0c4c60779f0cULL, 0xcfff608f7fff9fe0ULL, }, - { 0x379944bc60e9d40cULL, 0x2a66400d7d7a4f60ULL, }, /* 80 */ - { 0x4a0b4408801e08acULL, 0x36fc80bb3c7401e0ULL, }, - { 0x922d0cb800dcb0acULL, 0xfc5c807628f8dc60ULL, }, - { 0xb24a046000c05044ULL, 0x30c080e6c008a460ULL, }, - { 0x22a66ce00040c044ULL, 0x208000724030e4e0ULL, }, - { 0xcc726c4000808024ULL, 0xe00000de0060dc60ULL, }, - { 0xbc5e04c000000024ULL, 0xc00000bc004010e0ULL, }, - { 0x7c5cac000000002cULL, 0x0000001c00c0f0e0ULL, }, - { 0x9c4424000000002cULL, 0x000000d40080f060ULL, }, /* 88 */ - { 0xa8cc2400000000ccULL, 0x0000004c000010e0ULL, }, - { 0xc814ac00000000ccULL, 0x000000980000c060ULL, }, - { 0x48e8e400000000a4ULL, 0x0000005800004060ULL, }, - { 0x08d80c00000000a4ULL, 0x00000008000040e0ULL, }, - { 0x30880c0000000084ULL, 0x000000380000c060ULL, }, - { 0xf0b8e40000000084ULL, 0x00000070000000e0ULL, }, - { 0xf0f04c000000004cULL, 0x000000f0000000e0ULL, }, - { 0x709004000000004cULL, 0x000000d000000060ULL, }, /* 96 */ - { 0xf0f06c000000004cULL, 0x00000070000000e0ULL, }, - { 0x709064000000004cULL, 0x0000005000000060ULL, }, - { 0xf0f08c000000004cULL, 0x000000f0000000e0ULL, }, - { 0xa0d08c00000000ecULL, 0x0000009000000060ULL, }, - { 0xc0708c000000008cULL, 0x000000f0000000e0ULL, }, - { 0x80508c000000002cULL, 0x0000009000000060ULL, }, - { 0x00f08c00000000ccULL, 0x000000f0000000e0ULL, }, - { 0x00906400000000ccULL, 0x000000e000000060ULL, }, /* 104 */ - { 0x00f06c00000000ccULL, 0x000000c0000000e0ULL, }, - { 0x00900400000000ccULL, 0x0000008000000060ULL, }, - { 0x00f04c00000000ccULL, 0x00000000000000e0ULL, }, - { 0x00e0c400000000a4ULL, 0x00000000000000e0ULL, }, - { 0x00c0ec00000000acULL, 0x00000000000000e0ULL, }, - { 0x0080a40000000044ULL, 0x00000000000000e0ULL, }, - { 0x00008c000000008cULL, 0x00000000000000e0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_d.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_d.c deleted file mode 100644 index 9722dbd99f77..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MSUBV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MSUBV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaa9ULL, 0xaaaaaaaaaaaaaaa9ULL, }, - { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, }, - { 0xcccccccccccccccaULL, 0xcccccccccccccccaULL, }, - { 0xfffffffffffffffdULL, 0xfffffffffffffffdULL, }, - { 0xe38e38e38e38e38bULL, 0x38e38e38e38e38e0ULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, /* 8 */ - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, - { 0xaaaaaaaaaaaaaaa6ULL, 0xaaaaaaaaaaaaaaa6ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaa6ULL, 0xaaaaaaaaaaaaaaa6ULL, }, - { 0x71c71c71c71c71c2ULL, 0x71c71c71c71c71c2ULL, }, - { 0x5555555555555550ULL, 0x5555555555555550ULL, }, - { 0xddddddddddddddd8ULL, 0xddddddddddddddd8ULL, }, - { 0xfffffffffffffffaULL, 0xfffffffffffffffaULL, }, - { 0xed097b425ed097aeULL, 0xd097b425ed097b3cULL, }, - { 0xaaaaaaaaaaaaaaa4ULL, 0xaaaaaaaaaaaaaaa4ULL, }, - { 0xfffffffffffffff9ULL, 0xfffffffffffffff9ULL, }, /* 24 */ - { 0xfffffffffffffff9ULL, 0xfffffffffffffff9ULL, }, - { 0xe38e38e38e38e387ULL, 0xe38e38e38e38e387ULL, }, - { 0x555555555555554eULL, 0x555555555555554eULL, }, - { 0x9999999999999992ULL, 0x9999999999999992ULL, }, - { 0xaaaaaaaaaaaaaaa3ULL, 0xaaaaaaaaaaaaaaa3ULL, }, - { 0xa12f684bda12f67dULL, 0x12f684bda12f6844ULL, }, - { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, }, - { 0xccccccccccccccc4ULL, 0xccccccccccccccc4ULL, }, /* 32 */ - { 0xccccccccccccccc4ULL, 0xccccccccccccccc4ULL, }, - { 0x555555555555554cULL, 0x555555555555554cULL, }, - { 0x9999999999999990ULL, 0x9999999999999990ULL, }, - { 0xa3d70a3d70a3d700ULL, 0xa3d70a3d70a3d700ULL, }, - { 0x666666666666665cULL, 0x666666666666665cULL, }, - { 0xe93e93e93e93e934ULL, 0x2d82d82d82d82d78ULL, }, - { 0x3333333333333328ULL, 0x3333333333333328ULL, }, - { 0x666666666666665bULL, 0x666666666666665bULL, }, /* 40 */ - { 0x666666666666665bULL, 0x666666666666665bULL, }, - { 0x888888888888887dULL, 0x888888888888887dULL, }, - { 0x999999999999998eULL, 0x999999999999998eULL, }, - { 0x5c28f5c28f5c28eaULL, 0x5c28f5c28f5c28eaULL, }, - { 0xccccccccccccccc1ULL, 0xccccccccccccccc1ULL, }, - { 0x2d82d82d82d82d77ULL, 0x3e93e93e93e93e88ULL, }, - { 0xfffffffffffffff4ULL, 0xfffffffffffffff4ULL, }, - { 0xe38e38e38e38e382ULL, 0x38e38e38e38e38d7ULL, }, /* 48 */ - { 0xe38e38e38e38e382ULL, 0x38e38e38e38e38d7ULL, }, - { 0xd097b425ed097b36ULL, 0x097b425ed097b419ULL, }, - { 0xc71c71c71c71c710ULL, 0x71c71c71c71c71baULL, }, - { 0x49f49f49f49f49e8ULL, 0x38e38e38e38e38d6ULL, }, - { 0xaaaaaaaaaaaaaa9eULL, 0xaaaaaaaaaaaaaa9dULL, }, - { 0xf9add3c0ca4587daULL, 0x587e6b74f0329154ULL, }, - { 0x8e38e38e38e38e2cULL, 0xe38e38e38e38e380ULL, }, - { 0xaaaaaaaaaaaaaa9dULL, 0xaaaaaaaaaaaaaa9cULL, }, /* 56 */ - { 0xaaaaaaaaaaaaaa9dULL, 0xaaaaaaaaaaaaaa9cULL, }, - { 0x684bda12f684bd93ULL, 0x84bda12f684bda04ULL, }, - { 0xc71c71c71c71c70eULL, 0x71c71c71c71c71b8ULL, }, - { 0x1111111111111102ULL, 0x7777777777777768ULL, }, - { 0xe38e38e38e38e37fULL, 0x38e38e38e38e38d4ULL, }, - { 0x781948b0fcd6e9d1ULL, 0xc3f35ba781948b00ULL, }, - { 0xfffffffffffffff0ULL, 0xfffffffffffffff0ULL, }, - { 0x52ba41969e9c6ff0ULL, 0xcd6802158b677f60ULL, }, /* 64 */ - { 0x63129bf5b78505f0ULL, 0x1556f7f61c4e5b90ULL, }, - { 0x5a4c8855f350a5f0ULL, 0x6a36586fc42edea0ULL, }, - { 0x5e6b001b04d82c70ULL, 0xe819332c365e3f20ULL, }, - { 0x6ec35a7a1dc0c270ULL, 0x3008290cc7451b50ULL, }, - { 0x37152f411fd35230ULL, 0xc7e3b2957c56b340ULL, }, - { 0xcc49f1d861667630ULL, 0x1808e0646811cb90ULL, }, - { 0xde8a7f544022c1c0ULL, 0x9886bc9978437610ULL, }, - { 0xd5c46bb47bee61c0ULL, 0xed661d132023f920ULL, }, /* 72 */ - { 0x6af92e4bbd8185c0ULL, 0x3d8b4ae20bdf1170ULL, }, - { 0xe4d44869d87d45c0ULL, 0x6409d23bd9c847e0ULL, }, - { 0x6e2e9ce94e99c4c0ULL, 0xc30837db04ed7360ULL, }, - { 0x724d14ae60214b40ULL, 0x40eb1297771cd3e0ULL, }, - { 0x848da22a3edd96d0ULL, 0xc168eecc874e7e60ULL, }, - { 0x0de7f6a9b4fa15d0ULL, 0x2067546bb273a9e0ULL, }, - { 0xc233bfd40310460cULL, 0x0d9585bacf54c5e0ULL, }, - { 0x061015122724c70cULL, 0x0169d01f7cb17f60ULL, }, /* 80 */ - { 0x23dacc726f603aacULL, 0xf3ea8c4eaa8b5ce0ULL, }, - { 0xd82df953c25380acULL, 0xba87b7f0f99bbb60ULL, }, - { 0x546cb94a0c5e7444ULL, 0x3818c320ce1bdf60ULL, }, - { 0xa38f9428761ecf44ULL, 0x63113b9e681b66e0ULL, }, - { 0x7dc23fbe59fe7924ULL, 0x156ddd68750e6260ULL, }, - { 0x8a17717d36df5b24ULL, 0x36b1f5939596d2e0ULL, }, - { 0x7e854cd9a677ce2cULL, 0xf2b6202eb36946e0ULL, }, - { 0x246d8d067437a72cULL, 0x04c6347e9c1ff460ULL, }, /* 88 */ - { 0xc48a013a554339ccULL, 0xcb81fd31acc4a5e0ULL, }, - { 0xb971282c0b508fccULL, 0x20d62d6344ce5060ULL, }, - { 0x835f812f0bc6a7a4ULL, 0x17bd6b5a08275460ULL, }, - { 0xc0ee1b9557ab4aa4ULL, 0x170471a9d22d5fe0ULL, }, - { 0xc6f66d89431f7984ULL, 0x5c6f5a646cad3f60ULL, }, - { 0x5ae0b289f6ac0b84ULL, 0x6f9f6bc81fdb6be0ULL, }, - { 0x2f584ee03fd2014cULL, 0xa7e34ccbd1bc3fe0ULL, }, - { 0x5947927731cb724cULL, 0xf76af1f9a05f4160ULL, }, /* 96 */ - { 0x68112ad490e3a34cULL, 0x7f944a22f5d630e0ULL, }, - { 0x1cf6705c5faa944cULL, 0x801292d47291e660ULL, }, - { 0x5519f2782cb0454cULL, 0x3d691c2dd53919e0ULL, }, - { 0xe5c979861aac06ecULL, 0x585247d6e899e160ULL, }, - { 0x2450b27896665b8cULL, 0x8276d8ad504f46e0ULL, }, - { 0x2716d456a4a5ab2cULL, 0x46e1f3460c71c260ULL, }, - { 0x5751460331251dccULL, 0xdc1dc7a4a693abe0ULL, }, - { 0x3bf387b7f37473ccULL, 0x8efb4ff7cc92de60ULL, }, /* 104 */ - { 0xc3103a3df066c9ccULL, 0x7d3b07351cd59ee0ULL, }, - { 0x0d612554557c1fccULL, 0x5dbabfc2ac8ed560ULL, }, - { 0x1cd018ef103475ccULL, 0xca277277956f49e0ULL, }, - { 0x15d520225c2e79a4ULL, 0x08f2025804e95de0ULL, }, - { 0x820f9c65be3ea1acULL, 0x37094edbda6ef1e0ULL, }, - { 0x0f18515c62838744ULL, 0xcfbd4b5627d005e0ULL, }, - { 0x11d549f26502488cULL, 0x8de999d53cdc99e0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_h.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_h.c deleted file mode 100644 index 6c059c779cf6..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MSUBV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MSUBV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaa9aaa9aaa9aaa9ULL, 0xaaa9aaa9aaa9aaa9ULL, }, - { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, }, - { 0xcccacccacccacccaULL, 0xcccacccacccacccaULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xe38b38e08e35e38bULL, 0x38e08e35e38b38e0ULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, /* 8 */ - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xaaa6aaa6aaa6aaa6ULL, 0xaaa6aaa6aaa6aaa6ULL, }, /* 16 */ - { 0xaaa6aaa6aaa6aaa6ULL, 0xaaa6aaa6aaa6aaa6ULL, }, - { 0x71c271c271c271c2ULL, 0x71c271c271c271c2ULL, }, - { 0x5550555055505550ULL, 0x5550555055505550ULL, }, - { 0xddd8ddd8ddd8ddd8ULL, 0xddd8ddd8ddd8ddd8ULL, }, - { 0xfffafffafffafffaULL, 0xfffafffafffafffaULL, }, - { 0x97ae7b3c5eca97aeULL, 0x7b3c5eca97ae7b3cULL, }, - { 0xaaa4aaa4aaa4aaa4ULL, 0xaaa4aaa4aaa4aaa4ULL, }, - { 0xfff9fff9fff9fff9ULL, 0xfff9fff9fff9fff9ULL, }, /* 24 */ - { 0xfff9fff9fff9fff9ULL, 0xfff9fff9fff9fff9ULL, }, - { 0xe387e387e387e387ULL, 0xe387e387e387e387ULL, }, - { 0x554e554e554e554eULL, 0x554e554e554e554eULL, }, - { 0x9992999299929992ULL, 0x9992999299929992ULL, }, - { 0xaaa3aaa3aaa3aaa3ULL, 0xaaa3aaa3aaa3aaa3ULL, }, - { 0xf67d6844da0bf67dULL, 0x6844da0bf67d6844ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xccc4ccc4ccc4ccc4ULL, 0xccc4ccc4ccc4ccc4ULL, }, /* 32 */ - { 0xccc4ccc4ccc4ccc4ULL, 0xccc4ccc4ccc4ccc4ULL, }, - { 0x554c554c554c554cULL, 0x554c554c554c554cULL, }, - { 0x9990999099909990ULL, 0x9990999099909990ULL, }, - { 0xd700d700d700d700ULL, 0xd700d700d700d700ULL, }, - { 0x665c665c665c665cULL, 0x665c665c665c665cULL, }, - { 0xe9342d7871bce934ULL, 0x2d7871bce9342d78ULL, }, - { 0x3328332833283328ULL, 0x3328332833283328ULL, }, - { 0x665b665b665b665bULL, 0x665b665b665b665bULL, }, /* 40 */ - { 0x665b665b665b665bULL, 0x665b665b665b665bULL, }, - { 0x887d887d887d887dULL, 0x887d887d887d887dULL, }, - { 0x998e998e998e998eULL, 0x998e998e998e998eULL, }, - { 0x28ea28ea28ea28eaULL, 0x28ea28ea28ea28eaULL, }, - { 0xccc1ccc1ccc1ccc1ULL, 0xccc1ccc1ccc1ccc1ULL, }, - { 0x2d773e884f992d77ULL, 0x3e884f992d773e88ULL, }, - { 0xfff4fff4fff4fff4ULL, 0xfff4fff4fff4fff4ULL, }, - { 0xe38238d78e2ce382ULL, 0x38d78e2ce38238d7ULL, }, /* 48 */ - { 0xe38238d78e2ce382ULL, 0x38d78e2ce38238d7ULL, }, - { 0x7b36b419ecfc7b36ULL, 0xb419ecfc7b36b419ULL, }, - { 0xc71071ba1c64c710ULL, 0x71ba1c64c71071baULL, }, - { 0x49e838d627c449e8ULL, 0x38d627c449e838d6ULL, }, - { 0xaa9eaa9daa9caa9eULL, 0xaa9daa9caa9eaa9dULL, }, - { 0x87da91547e5c87daULL, 0x91547e5c87da9154ULL, }, - { 0x8e2ce38038d48e2cULL, 0xe38038d48e2ce380ULL, }, - { 0xaa9daa9caa9baa9dULL, 0xaa9caa9baa9daa9cULL, }, /* 56 */ - { 0xaa9daa9caa9baa9dULL, 0xaa9caa9baa9daa9cULL, }, - { 0xbd93da04f675bd93ULL, 0xda04f675bd93da04ULL, }, - { 0xc70e71b81c62c70eULL, 0x71b81c62c70e71b8ULL, }, - { 0x11027768ddce1102ULL, 0x7768ddce11027768ULL, }, - { 0xe37f38d48e29e37fULL, 0x38d48e29e37f38d4ULL, }, - { 0xe9d18b0048a1e9d1ULL, 0x8b0048a1e9d18b00ULL, }, - { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, }, - { 0x340ccd603a6c6ff0ULL, 0x7c7fc96cb0d77f60ULL, }, /* 64 */ - { 0x07608c7c902605f0ULL, 0x7e1ef7e0f9925b90ULL, }, - { 0xda1ca10416e8a5f0ULL, 0x2e36f13e11e9dea0ULL, }, - { 0x6166ada860262c70ULL, 0x773f69ee43333f20ULL, }, - { 0x34ba6cc4b5e0c270ULL, 0x78de98628bee1b50ULL, }, - { 0x13b6467bf3775230ULL, 0xce8d99be266db340ULL, }, - { 0xeaeababdfe9a7630ULL, 0x2d251ed87fd8cb90ULL, }, - { 0x1b481af62b77c1c0ULL, 0x479e70e86e9a7610ULL, }, - { 0xee042f7eb23961c0ULL, 0xf7b66a4686f1f920ULL, }, /* 72 */ - { 0xc538a3c0bd5c85c0ULL, 0x564eef60e05c1170ULL, }, - { 0xb5941adce7fb45c0ULL, 0xd00e7d5f672347e0ULL, }, - { 0x25cef5ba555cc4c0ULL, 0x55b61e37e30d7360ULL, }, - { 0xad18025e9e9a4b40ULL, 0x9ebf96e71457d3e0ULL, }, - { 0xdd766297cb7796d0ULL, 0xb938e8f703197e60ULL, }, - { 0x4db03d7538d815d0ULL, 0x3ee089cf7f03a9e0ULL, }, - { 0x154fea4c3377460cULL, 0xe1ff538f49ffc5e0ULL, }, - { 0x4a99edbce7e9c70cULL, 0x3f66800dba7a7f60ULL, }, /* 80 */ - { 0xea0bfe08a81e3aacULL, 0xe7fcffbbd4745ce0ULL, }, - { 0x3e2ddcb809dc80acULL, 0xc75ca276a8f8bb60ULL, }, - { 0x5e4aa9605ec07444ULL, 0x6dc0dee66108df60ULL, }, - { 0x03a670e01940cf44ULL, 0x05802472d23066e0ULL, }, - { 0x8c72ca4059807924ULL, 0xb7002ade28606260ULL, }, - { 0x945efbc07b005b24ULL, 0x4f00c3bc4040d2e0ULL, }, - { 0xab5cc300f000ce2cULL, 0xf000bd1c6fc046e0ULL, }, - { 0xd7445f001000a72cULL, 0x600018d43e80f460ULL, }, /* 88 */ - { 0x66cca200e00039ccULL, 0xc000b74c5d00a5e0ULL, }, - { 0x33140e00c0008fccULL, 0xc0005a98be005060ULL, }, - { 0xafe8d8000000a7a4ULL, 0x00002a58c2005460ULL, }, - { 0x99d8b80000004aa4ULL, 0x0000d6088c005fe0ULL, }, - { 0xa388900000007984ULL, 0x0000413818003f60ULL, }, - { 0xc5b8f00000000b84ULL, 0x0000fa7010006be0ULL, }, - { 0x41f0c0000000014cULL, 0x00002bf0f0003fe0ULL, }, - { 0x7490c0000000724cULL, 0x0000b9d0a0004160ULL, }, /* 96 */ - { 0xb0f0c0000000a34cULL, 0x00008f70c00030e0ULL, }, - { 0xed90c0000000944cULL, 0x000014508000e660ULL, }, - { 0x0ff0c0000000454cULL, 0x00002ef0000019e0ULL, }, - { 0xebd08000000006ecULL, 0x00001a900000e160ULL, }, - { 0xf770000000005b8cULL, 0x000037f0000046e0ULL, }, - { 0x825000000000ab2cULL, 0x000039900000c260ULL, }, - { 0x5af0000000001dccULL, 0x000030f00000abe0ULL, }, - { 0x22900000000073ccULL, 0x0000d1e00000de60ULL, }, /* 104 */ - { 0x3bf000000000c9ccULL, 0x000083c000009ee0ULL, }, - { 0xe990000000001fccULL, 0x0000c7800000d560ULL, }, - { 0x0cf00000000075ccULL, 0x00000f00000049e0ULL, }, - { 0x0ee00000000079a4ULL, 0x0000670000005de0ULL, }, - { 0x77c000000000a1acULL, 0x00007f000000f1e0ULL, }, - { 0x8380000000008744ULL, 0x00005700000005e0ULL, }, - { 0xef0000000000488cULL, 0x0000ef00000099e0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_w.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_w.c deleted file mode 100644 index 0a83db4787a4..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_msubv_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction MSUBV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MSUBV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaa9aaaaaaa9ULL, 0xaaaaaaa9aaaaaaa9ULL, }, - { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, }, - { 0xcccccccacccccccaULL, 0xcccccccacccccccaULL, }, - { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, - { 0xe38e38e08e38e38bULL, 0x38e38e35e38e38e0ULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, /* 8 */ - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, - { 0xaaaaaaa6aaaaaaa6ULL, 0xaaaaaaa6aaaaaaa6ULL, }, /* 16 */ - { 0xaaaaaaa6aaaaaaa6ULL, 0xaaaaaaa6aaaaaaa6ULL, }, - { 0xc71c71c2c71c71c2ULL, 0xc71c71c2c71c71c2ULL, }, - { 0x5555555055555550ULL, 0x5555555055555550ULL, }, - { 0xddddddd8ddddddd8ULL, 0xddddddd8ddddddd8ULL, }, - { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, }, - { 0xed097b3c5ed097aeULL, 0x7b425ecaed097b3cULL, }, - { 0xaaaaaaa4aaaaaaa4ULL, 0xaaaaaaa4aaaaaaa4ULL, }, - { 0xfffffff9fffffff9ULL, 0xfffffff9fffffff9ULL, }, /* 24 */ - { 0xfffffff9fffffff9ULL, 0xfffffff9fffffff9ULL, }, - { 0x8e38e3878e38e387ULL, 0x8e38e3878e38e387ULL, }, - { 0x5555554e5555554eULL, 0x5555554e5555554eULL, }, - { 0x9999999299999992ULL, 0x9999999299999992ULL, }, - { 0xaaaaaaa3aaaaaaa3ULL, 0xaaaaaaa3aaaaaaa3ULL, }, - { 0xa12f6844da12f67dULL, 0x684bda0ba12f6844ULL, }, - { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, }, - { 0xccccccc4ccccccc4ULL, 0xccccccc4ccccccc4ULL, }, /* 32 */ - { 0xccccccc4ccccccc4ULL, 0xccccccc4ccccccc4ULL, }, - { 0x5555554c5555554cULL, 0x5555554c5555554cULL, }, - { 0x9999999099999990ULL, 0x9999999099999990ULL, }, - { 0x70a3d70070a3d700ULL, 0x70a3d70070a3d700ULL, }, - { 0x6666665c6666665cULL, 0x6666665c6666665cULL, }, - { 0x82d82d783e93e934ULL, 0xc71c71bc82d82d78ULL, }, - { 0x3333332833333328ULL, 0x3333332833333328ULL, }, - { 0x6666665b6666665bULL, 0x6666665b6666665bULL, }, /* 40 */ - { 0x6666665b6666665bULL, 0x6666665b6666665bULL, }, - { 0x8888887d8888887dULL, 0x8888887d8888887dULL, }, - { 0x9999998e9999998eULL, 0x9999998e9999998eULL, }, - { 0x8f5c28ea8f5c28eaULL, 0x8f5c28ea8f5c28eaULL, }, - { 0xccccccc1ccccccc1ULL, 0xccccccc1ccccccc1ULL, }, - { 0x93e93e8882d82d77ULL, 0xa4fa4f9993e93e88ULL, }, - { 0xfffffff4fffffff4ULL, 0xfffffff4fffffff4ULL, }, - { 0xe38e38d78e38e382ULL, 0x38e38e2ce38e38d7ULL, }, /* 48 */ - { 0xe38e38d78e38e382ULL, 0x38e38e2ce38e38d7ULL, }, - { 0xd097b419ed097b36ULL, 0xb425ecfcd097b419ULL, }, - { 0xc71c71ba1c71c710ULL, 0x71c71c64c71c71baULL, }, - { 0xe38e38d6f49f49e8ULL, 0xd27d27c4e38e38d6ULL, }, - { 0xaaaaaa9daaaaaa9eULL, 0xaaaaaa9caaaaaa9dULL, }, - { 0xf0329154ca4587daULL, 0xa4587e5cf0329154ULL, }, - { 0x8e38e38038e38e2cULL, 0xe38e38d48e38e380ULL, }, - { 0xaaaaaa9caaaaaa9dULL, 0xaaaaaa9baaaaaa9cULL, }, /* 56 */ - { 0xaaaaaa9caaaaaa9dULL, 0xaaaaaa9baaaaaa9cULL, }, - { 0x684bda04f684bd93ULL, 0xda12f675684bda04ULL, }, - { 0xc71c71b81c71c70eULL, 0x71c71c62c71c71b8ULL, }, - { 0x7777776811111102ULL, 0xddddddce77777768ULL, }, - { 0xe38e38d48e38e37fULL, 0x38e38e29e38e38d4ULL, }, - { 0x81948b00fcd6e9d1ULL, 0x781948a181948b00ULL, }, - { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, }, - { 0x4efccd609e9c6ff0ULL, 0xc5dac96c8b677f60ULL, }, /* 64 */ - { 0x3e3d8c7cb78505f0ULL, 0x4463f7e01c4e5b90ULL, }, - { 0xcaa9a104f350a5f0ULL, 0x8ca4f13ec42edea0ULL, }, - { 0x19b8ada804d82c70ULL, 0xb62b69ee365e3f20ULL, }, - { 0x08f96cc41dc0c270ULL, 0x34b49862c7451b50ULL, }, - { 0x5405467b1fd35230ULL, 0xf7c999be7c56b340ULL, }, - { 0x5cc7babd61667630ULL, 0xa4601ed86811cb90ULL, }, - { 0xe20c1af64022c1c0ULL, 0x927a70e878437610ULL, }, - { 0x6e782f7e7bee61c0ULL, 0xdabb6a462023f920ULL, }, /* 72 */ - { 0x773aa3c0bd8185c0ULL, 0x8751ef600bdf1170ULL, }, - { 0xc0871adcd87d45c0ULL, 0x6c527d5fd9c847e0ULL, }, - { 0xd7c7f5ba4e99c4c0ULL, 0xdaa41e3704ed7360ULL, }, - { 0x26d7025e60214b40ULL, 0x042a96e7771cd3e0ULL, }, - { 0xac1b62973edd96d0ULL, 0xf244e8f7874e7e60ULL, }, - { 0xc35c3d75b4fa15d0ULL, 0x609689cfb273a9e0ULL, }, - { 0x9de4ea4c0310460cULL, 0x80c0538fcf54c5e0ULL, }, - { 0xbd81edbc2724c70cULL, 0x7301800d7cb17f60ULL, }, /* 80 */ - { 0xaebafe086f603aacULL, 0x35c5ffbbaa8b5ce0ULL, }, - { 0xdf14dcb8c25380acULL, 0x3ef9a276f99bbb60ULL, }, - { 0x5e0ea9600c5e7444ULL, 0x8ef3dee6ce1bdf60ULL, }, - { 0x1c7370e0761ecf44ULL, 0x864a2472681b66e0ULL, }, - { 0xb58eca4059fe7924ULL, 0x8c252ade750e6260ULL, }, - { 0xfcc4fbc036df5b24ULL, 0x36a7c3bc9596d2e0ULL, }, - { 0x57a2c300a677ce2cULL, 0x2922bd1cb36946e0ULL, }, - { 0x88bd5f007437a72cULL, 0x45fd18d49c1ff460ULL, }, /* 88 */ - { 0x2581a200554339ccULL, 0x6c99b74cacc4a5e0ULL, }, - { 0x2d500e000b508fccULL, 0x1f975a9844ce5060ULL, }, - { 0x5907d8000bc6a7a4ULL, 0x0eaa2a5808275460ULL, }, - { 0xeab7b80057ab4aa4ULL, 0x8af4d608d22d5fe0ULL, }, - { 0x95ab9000431f7984ULL, 0x840741386cad3f60ULL, }, - { 0xf5ddf000f6ac0b84ULL, 0xd51bfa701fdb6be0ULL, }, - { 0xdf7cc0003fd2014cULL, 0xb5052bf0d1bc3fe0ULL, }, - { 0x3393c00031cb724cULL, 0x06abb9d0a05f4160ULL, }, /* 96 */ - { 0xdb56c00090e3a34cULL, 0x7ff18f70f5d630e0ULL, }, - { 0xa1b5c0005faa944cULL, 0x9e0514507291e660ULL, }, - { 0xfa60c0002cb0454cULL, 0xc4182ef0d53919e0ULL, }, - { 0xa6f680001aac06ecULL, 0x05ca1a90e899e160ULL, }, - { 0x15a3000096665b8cULL, 0x0cec37f0504f46e0ULL, }, - { 0xb79a0000a4a5ab2cULL, 0x578239900c71c260ULL, }, - { 0xb70c000031251dccULL, 0xaa4c30f0a693abe0ULL, }, - { 0x01140000f37473ccULL, 0x400dd1e0cc92de60ULL, }, /* 104 */ - { 0xb1cc0000f066c9ccULL, 0x8cf683c01cd59ee0ULL, }, - { 0xf8540000557c1fccULL, 0x0f82c780ac8ed560ULL, }, - { 0xf88c0000103475ccULL, 0xa1f10f00956f49e0ULL, }, - { 0x2e7000005c2e79a4ULL, 0xcf94670004e95de0ULL, }, - { 0x96c00000be3ea1acULL, 0xdca57f00da6ef1e0ULL, }, - { 0xbf00000062838744ULL, 0x368a570027d005e0ULL, }, - { 0x4c0000006502488cULL, 0xcc98ef003cdc99e0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MSUBV_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_b.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_b.c deleted file mode 100644 index de1046820cb8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MULV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MULV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe4e4e4e4e4e4e4e4ULL, 0xe4e4e4e4e4e4e4e4ULL, }, - { 0x7272727272727272ULL, 0x7272727272727272ULL, }, - { 0x7878787878787878ULL, 0x7878787878787878ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0xbe4c30be4c30be4cULL, 0x30be4c30be4c30beULL, }, - { 0x980a26980a26980aULL, 0x26980a26980a2698ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7272727272727272ULL, 0x7272727272727272ULL, }, - { 0x3939393939393939ULL, 0x3939393939393939ULL, }, - { 0xbcbcbcbcbcbcbcbcULL, 0xbcbcbcbcbcbcbcbcULL, }, - { 0xefefefefefefefefULL, 0xefefefefefefefefULL, }, - { 0x5f26985f26985f26ULL, 0x985f26985f26985fULL, }, - { 0x4c85134c85134c85ULL, 0x134c85134c85134cULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7878787878787878ULL, 0x7878787878787878ULL, }, - { 0xbcbcbcbcbcbcbcbcULL, 0xbcbcbcbcbcbcbcbcULL, }, - { 0x9090909090909090ULL, 0x9090909090909090ULL, }, - { 0xa4a4a4a4a4a4a4a4ULL, 0xa4a4a4a4a4a4a4a4ULL, }, - { 0xe428a0e428a0e428ULL, 0xa0e428a0e428a0e4ULL, }, - { 0x500c94500c94500cULL, 0x94500c94500c9450ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0xefefefefefefefefULL, 0xefefefefefefefefULL, }, - { 0xa4a4a4a4a4a4a4a4ULL, 0xa4a4a4a4a4a4a4a4ULL, }, - { 0x2929292929292929ULL, 0x2929292929292929ULL, }, - { 0x394a28394a28394aULL, 0x28394a28394a2839ULL, }, - { 0x9483a59483a59483ULL, 0xa59483a59483a594ULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xbe4c30be4c30be4cULL, 0x30be4c30be4c30beULL, }, - { 0x5f26985f26985f26ULL, 0x985f26985f26985fULL, }, - { 0xe428a0e428a0e428ULL, 0xa0e428a0e428a0e4ULL, }, - { 0x394a28394a28394aULL, 0x28394a28394a2839ULL, }, - { 0x49c44049c44049c4ULL, 0x4049c44049c44049ULL, }, - { 0xd4ae88d4ae88d4aeULL, 0x88d4ae88d4ae88d4ULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x980a26980a26980aULL, 0x26980a26980a2698ULL, }, - { 0x4c85134c85134c85ULL, 0x134c85134c85134cULL, }, - { 0x500c94500c94500cULL, 0x94500c94500c9450ULL, }, - { 0x9483a59483a59483ULL, 0xa59483a59483a594ULL, }, - { 0xd4ae88d4ae88d4aeULL, 0x88d4ae88d4ae88d4ULL, }, - { 0x10e1b110e1b110e1ULL, 0xb110e1b110e1b110ULL, }, - { 0x40e4a49040843900ULL, 0xf971798404190090ULL, }, /* 64 */ - { 0x58ac00e408461300ULL, 0x4661098cd64560d0ULL, }, - { 0x60445478e83e2700ULL, 0x6de882a2aaa970f0ULL, }, - { 0x80b6c45cb0c20a80ULL, 0x4ff7d850aeb66080ULL, }, - { 0x58ac00e408461300ULL, 0x4661098cd64560d0ULL, }, - { 0x190400492969b140ULL, 0x445199a4b9814410ULL, }, - { 0xa4cc00bea5dd0d00ULL, 0xbe68a2e60795dab0ULL, }, - { 0xd0a200c74623ae70ULL, 0xea8758f0dd3e6480ULL, }, - { 0x60445478e83e2700ULL, 0x6de882a2aaa970f0ULL, }, /* 72 */ - { 0xa4cc00bea5dd0d00ULL, 0xbe68a2e60795dab0ULL, }, - { 0x90a444e4b1617900ULL, 0xf140240139395990ULL, }, - { 0x40c6f422ee9fb600ULL, 0x7b583028e316aa80ULL, }, - { 0x80b6c45cb0c20a80ULL, 0x4ff7d850aeb66080ULL, }, - { 0xd0a200c74623ae70ULL, 0xea8758f0dd3e6480ULL, }, - { 0x40c6f422ee9fb600ULL, 0x7b583028e316aa80ULL, }, - { 0x0061e429846184c4ULL, 0xa9e1404091048400ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_d.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_d.c deleted file mode 100644 index ae2ebef5599d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MULV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MULV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e38e38e38e38e4ULL, 0x38e38e38e38e38e4ULL, }, - { 0x1c71c71c71c71c72ULL, 0x1c71c71c71c71c72ULL, }, - { 0x7777777777777778ULL, 0x7777777777777778ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x12f684bda12f684cULL, 0x2f684bda12f684beULL, }, - { 0x425ed097b425ed0aULL, 0x25ed097b425ed098ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c72ULL, 0x1c71c71c71c71c72ULL, }, - { 0x8e38e38e38e38e39ULL, 0x8e38e38e38e38e39ULL, }, - { 0xbbbbbbbbbbbbbbbcULL, 0xbbbbbbbbbbbbbbbcULL, }, - { 0xeeeeeeeeeeeeeeefULL, 0xeeeeeeeeeeeeeeefULL, }, - { 0x097b425ed097b426ULL, 0x97b425ed097b425fULL, }, - { 0xa12f684bda12f685ULL, 0x12f684bda12f684cULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777778ULL, 0x7777777777777778ULL, }, - { 0xbbbbbbbbbbbbbbbcULL, 0xbbbbbbbbbbbbbbbcULL, }, - { 0xf5c28f5c28f5c290ULL, 0xf5c28f5c28f5c290ULL, }, - { 0x3d70a3d70a3d70a4ULL, 0x3d70a3d70a3d70a4ULL, }, - { 0x7d27d27d27d27d28ULL, 0x38e38e38e38e38e4ULL, }, - { 0xb60b60b60b60b60cULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0xeeeeeeeeeeeeeeefULL, 0xeeeeeeeeeeeeeeefULL, }, - { 0x3d70a3d70a3d70a4ULL, 0x3d70a3d70a3d70a4ULL, }, - { 0x8f5c28f5c28f5c29ULL, 0x8f5c28f5c28f5c29ULL, }, - { 0x9f49f49f49f49f4aULL, 0x8e38e38e38e38e39ULL, }, - { 0x2d82d82d82d82d83ULL, 0x3e93e93e93e93e94ULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x12f684bda12f684cULL, 0x2f684bda12f684beULL, }, - { 0x097b425ed097b426ULL, 0x97b425ed097b425fULL, }, - { 0x7d27d27d27d27d28ULL, 0x38e38e38e38e38e4ULL, }, - { 0x9f49f49f49f49f4aULL, 0x8e38e38e38e38e39ULL, }, - { 0xb0fcd6e9e06522c4ULL, 0x522c3f35ba781949ULL, }, - { 0x6b74f0329161f9aeULL, 0x74f0329161f9add4ULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x425ed097b425ed0aULL, 0x25ed097b425ed098ULL, }, - { 0xa12f684bda12f685ULL, 0x12f684bda12f684cULL, }, - { 0xb60b60b60b60b60cULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0x2d82d82d82d82d83ULL, 0x3e93e93e93e93e94ULL, }, - { 0x6b74f0329161f9aeULL, 0x74f0329161f9add4ULL, }, - { 0x781948b0fcd6e9e1ULL, 0xc3f35ba781948b10ULL, }, - { 0xad45be6961639000ULL, 0x3297fdea74988090ULL, }, /* 64 */ - { 0xefa7a5a0e7176a00ULL, 0xb8110a1f6f1923d0ULL, }, - { 0x08c6139fc4346000ULL, 0xab209f86581f7cf0ULL, }, - { 0xfbe1883aee787980ULL, 0x821d25438dd09f80ULL, }, - { 0xefa7a5a0e7176a00ULL, 0xb8110a1f6f1923d0ULL, }, - { 0x37ae2b38fded7040ULL, 0x682476774aee6810ULL, }, - { 0x6acb3d68be6cdc00ULL, 0xafdad2311444e7b0ULL, }, - { 0xedbf72842143b470ULL, 0x7f8223caefce5580ULL, }, - { 0x08c6139fc4346000ULL, 0xab209f86581f7cf0ULL, }, /* 72 */ - { 0x6acb3d68be6cdc00ULL, 0xafdad2311444e7b0ULL, }, - { 0x8624e5e1e5044000ULL, 0xd98178a63216c990ULL, }, - { 0x76a5ab8089e38100ULL, 0xa1019a60d4dad480ULL, }, - { 0xfbe1883aee787980ULL, 0x821d25438dd09f80ULL, }, - { 0xedbf72842143b470ULL, 0x7f8223caefce5580ULL, }, - { 0x76a5ab8089e38100ULL, 0xa1019a60d4dad480ULL, }, - { 0x4bb436d5b1e9cfc4ULL, 0x12d1ceb0e31ee400ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_h.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_h.c deleted file mode 100644 index 27479a82c557..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MULV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MULV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e438e438e438e4ULL, 0x38e438e438e438e4ULL, }, - { 0x1c721c721c721c72ULL, 0x1c721c721c721c72ULL, }, - { 0x7778777877787778ULL, 0x7778777877787778ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x684c84bea130684cULL, 0x84bea130684c84beULL, }, - { 0xed0ad098b426ed0aULL, 0xd098b426ed0ad098ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c721c721c721c72ULL, 0x1c721c721c721c72ULL, }, - { 0x8e398e398e398e39ULL, 0x8e398e398e398e39ULL, }, - { 0xbbbcbbbcbbbcbbbcULL, 0xbbbcbbbcbbbcbbbcULL, }, - { 0xeeefeeefeeefeeefULL, 0xeeefeeefeeefeeefULL, }, - { 0xb426425fd098b426ULL, 0x425fd098b426425fULL, }, - { 0xf685684cda13f685ULL, 0x684cda13f685684cULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7778777877787778ULL, 0x7778777877787778ULL, }, - { 0xbbbcbbbcbbbcbbbcULL, 0xbbbcbbbcbbbcbbbcULL, }, - { 0xc290c290c290c290ULL, 0xc290c290c290c290ULL, }, - { 0x70a470a470a470a4ULL, 0x70a470a470a470a4ULL, }, - { 0x7d2838e4f4a07d28ULL, 0x38e4f4a07d2838e4ULL, }, - { 0xb60cfa503e94b60cULL, 0xfa503e94b60cfa50ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0xeeefeeefeeefeeefULL, 0xeeefeeefeeefeeefULL, }, - { 0x70a470a470a470a4ULL, 0x70a470a470a470a4ULL, }, - { 0x5c295c295c295c29ULL, 0x5c295c295c295c29ULL, }, - { 0x9f4a8e397d289f4aULL, 0x8e397d289f4a8e39ULL, }, - { 0x2d833e944fa52d83ULL, 0x3e944fa52d833e94ULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x684c84bea130684cULL, 0x84bea130684c84beULL, }, - { 0xb426425fd098b426ULL, 0x425fd098b426425fULL, }, - { 0x7d2838e4f4a07d28ULL, 0x38e4f4a07d2838e4ULL, }, - { 0x9f4a8e397d289f4aULL, 0x8e397d289f4a8e39ULL, }, - { 0x22c419492c4022c4ULL, 0x19492c4022c41949ULL, }, - { 0xf9aeadd44588f9aeULL, 0xadd44588f9aeadd4ULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xed0ad098b426ed0aULL, 0xd098b426ed0ad098ULL, }, - { 0xf685684cda13f685ULL, 0x684cda13f685684cULL, }, - { 0xb60cfa503e94b60cULL, 0xfa503e94b60cfa50ULL, }, - { 0x2d833e944fa52d83ULL, 0x3e944fa52d833e94ULL, }, - { 0xf9aeadd44588f9aeULL, 0xadd44588f9aeadd4ULL, }, - { 0xe9e18b1048b1e9e1ULL, 0x8b1048b1e9e18b10ULL, }, - { 0xcbe43290c5849000ULL, 0x837136844f198090ULL, }, /* 64 */ - { 0x2cac40e4aa466a00ULL, 0xfe61d18cb74523d0ULL, }, - { 0x2d44eb78793e6000ULL, 0x4fe806a2e7a97cf0ULL, }, - { 0x78b6f35cb6c27980ULL, 0xb6f78750ceb69f80ULL, }, - { 0x2cac40e4aa466a00ULL, 0xfe61d18cb74523d0ULL, }, - { 0x21042649c2697040ULL, 0xaa51fea465816810ULL, }, - { 0x28cc8bbef4dddc00ULL, 0xa1687ae6a695e7b0ULL, }, - { 0xcfa29fc7d323b470ULL, 0xe587adf0113e5580ULL, }, - { 0x2d44eb78793e6000ULL, 0x4fe806a2e7a97cf0ULL, }, /* 72 */ - { 0x28cc8bbef4dddc00ULL, 0xa1687ae6a695e7b0ULL, }, - { 0x0fa488e4d5614000ULL, 0x864072017939c990ULL, }, - { 0x8fc62522929f8100ULL, 0x7a585f288416d480ULL, }, - { 0x78b6f35cb6c27980ULL, 0xb6f78750ceb69f80ULL, }, - { 0xcfa29fc7d323b470ULL, 0xe587adf0113e5580ULL, }, - { 0x8fc62522929f8100ULL, 0x7a585f288416d480ULL, }, - { 0x386153290561cfc4ULL, 0x5ce136403504e400ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_w.c b/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_w.c deleted file mode 100644 index adeb1bfa9885..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-multiply/test_msa_mulv_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction MULV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Multiply"; - char *instruction_name = "MULV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e4e38e38e4ULL, 0xe38e38e4e38e38e4ULL, }, - { 0x71c71c7271c71c72ULL, 0x71c71c7271c71c72ULL, }, - { 0x7777777877777778ULL, 0x7777777877777778ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x12f684bea12f684cULL, 0x84bda13012f684beULL, }, - { 0x425ed098b425ed0aULL, 0xd097b426425ed098ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x71c71c7271c71c72ULL, 0x71c71c7271c71c72ULL, }, - { 0x38e38e3938e38e39ULL, 0x38e38e3938e38e39ULL, }, - { 0xbbbbbbbcbbbbbbbcULL, 0xbbbbbbbcbbbbbbbcULL, }, - { 0xeeeeeeefeeeeeeefULL, 0xeeeeeeefeeeeeeefULL, }, - { 0x097b425fd097b426ULL, 0x425ed098097b425fULL, }, - { 0xa12f684cda12f685ULL, 0x684bda13a12f684cULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777877777778ULL, 0x7777777877777778ULL, }, - { 0xbbbbbbbcbbbbbbbcULL, 0xbbbbbbbcbbbbbbbcULL, }, - { 0x28f5c29028f5c290ULL, 0x28f5c29028f5c290ULL, }, - { 0x0a3d70a40a3d70a4ULL, 0x0a3d70a40a3d70a4ULL, }, - { 0xe38e38e427d27d28ULL, 0x9f49f4a0e38e38e4ULL, }, - { 0x4fa4fa500b60b60cULL, 0x93e93e944fa4fa50ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0xeeeeeeefeeeeeeefULL, 0xeeeeeeefeeeeeeefULL, }, - { 0x0a3d70a40a3d70a4ULL, 0x0a3d70a40a3d70a4ULL, }, - { 0xc28f5c29c28f5c29ULL, 0xc28f5c29c28f5c29ULL, }, - { 0x38e38e3949f49f4aULL, 0x27d27d2838e38e39ULL, }, - { 0x93e93e9482d82d83ULL, 0xa4fa4fa593e93e94ULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x12f684bea12f684cULL, 0x84bda13012f684beULL, }, - { 0x097b425fd097b426ULL, 0x425ed098097b425fULL, }, - { 0xe38e38e427d27d28ULL, 0x9f49f4a0e38e38e4ULL, }, - { 0x38e38e3949f49f4aULL, 0x27d27d2838e38e39ULL, }, - { 0xba781949e06522c4ULL, 0x06522c40ba781949ULL, }, - { 0x61f9add49161f9aeULL, 0xc0ca458861f9add4ULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x425ed098b425ed0aULL, 0xd097b426425ed098ULL, }, - { 0xa12f684cda12f685ULL, 0x684bda13a12f684cULL, }, - { 0x4fa4fa500b60b60cULL, 0x93e93e944fa4fa50ULL, }, - { 0x93e93e9482d82d83ULL, 0xa4fa4fa593e93e94ULL, }, - { 0x61f9add49161f9aeULL, 0xc0ca458861f9add4ULL, }, - { 0x81948b10fcd6e9e1ULL, 0x781948b181948b10ULL, }, - { 0xb103329061639000ULL, 0x3a25368474988090ULL, }, /* 64 */ - { 0x10bf40e4e7176a00ULL, 0x8176d18c6f1923d0ULL, }, - { 0x7393eb78c4346000ULL, 0xb7bf06a2581f7cf0ULL, }, - { 0xb0f0f35cee787980ULL, 0xd67987508dd09f80ULL, }, - { 0x10bf40e4e7176a00ULL, 0x8176d18c6f1923d0ULL, }, - { 0xb4f42649fded7040ULL, 0x3ceafea44aee6810ULL, }, - { 0xf73d8bbebe6cdc00ULL, 0x53697ae61444e7b0ULL, }, - { 0x7abb9fc72143b470ULL, 0x11e5adf0efce5580ULL, }, - { 0x7393eb78c4346000ULL, 0xb7bf06a2581f7cf0ULL, }, /* 72 */ - { 0xf73d8bbebe6cdc00ULL, 0x53697ae61444e7b0ULL, }, - { 0xb6b388e4e5044000ULL, 0x1aff72013216c990ULL, }, - { 0xe8bf252289e38100ULL, 0x91ae5f28d4dad480ULL, }, - { 0xb0f0f35cee787980ULL, 0xd67987508dd09f80ULL, }, - { 0x7abb9fc72143b470ULL, 0x11e5adf0efce5580ULL, }, - { 0xe8bf252289e38100ULL, 0x91ae5f28d4dad480ULL, }, - { 0x25775329b1e9cfc4ULL, 0xdfd63640e31ee400ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_MULV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_b.c deleted file mode 100644 index a3ab83b76cee..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x391c8e391c8e391cULL, 0x8e391c8e391c8e39ULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0x391c8e391c8e391cULL, 0x8e391c8e391c8e39ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x173e6c173e6c173eULL, 0x6c173e6c173e6c17ULL, }, - { 0x50a50550a50550a5ULL, 0x0550a50550a50550ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x50a50550a50550a5ULL, 0x0550a50550a50550ULL, }, - { 0x173e6c173e6c173eULL, 0x6c173e6c173e6c17ULL, }, - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, /* 48 */ - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, - { 0x391c8e391c8e391cULL, 0x8e391c8e391c8e39ULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0x173e6c173e6c173eULL, 0x6c173e6c173e6c17ULL, }, - { 0x50a50550a50550a5ULL, 0x0550a50550a50550ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x39e37139e37139e3ULL, 0x7139e37139e37139ULL, }, - { 0x1d72381d72381d72ULL, 0x381d72381d72381dULL, }, /* 56 */ - { 0x1c71391c71391c71ULL, 0x391c71391c71391cULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0x391c8e391c8e391cULL, 0x8e391c8e391c8e39ULL, }, - { 0x50a50550a50550a5ULL, 0x0550a50550a50550ULL, }, - { 0x173e6c173e6c173eULL, 0x6c173e6c173e6c17ULL, }, - { 0x39e37139e37139e3ULL, 0x7139e37139e37139ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x73ac1a9725cf8e38ULL, 0x39705044173ca210ULL, }, - { 0x241038226f93cac0ULL, 0x248f455f53507508ULL, }, - { 0xe81b30813631730eULL, 0xbe7683865539326cULL, }, - { 0x73ac1a9725cf8e38ULL, 0x39705044173ca210ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f9c52b9943c3c88ULL, 0x151f0b1b6a142d18ULL, }, - { 0x75911616119e1b46ULL, 0x850633426c03705cULL, }, - { 0x241038226f93cac0ULL, 0x248f455f53507508ULL, }, /* 72 */ - { 0x4f9c52b9943c3c88ULL, 0x151f0b1b6a142d18ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc40b68a3a56257ceULL, 0x9a193e2702174374ULL, }, - { 0xe81b30813631730eULL, 0xbe7683865539326cULL, }, - { 0x75911616119e1b46ULL, 0x850633426c03705cULL, }, - { 0xc40b68a3a56257ceULL, 0x9a193e2702174374ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_d.c deleted file mode 100644 index ee46ffadf1a8..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x05b05b05b05b05b0ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, /* 48 */ - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e38e38e38e38e3ULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e4ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0x38e38e38e38e38e3ULL, 0x71c71c71c71c71c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x73531997253171c8ULL, 0x386f5044e93c5d10ULL, }, - { 0x23efc7de916d3640ULL, 0x238e445f53508af8ULL, }, - { 0xe7e42f8135cf8d0eULL, 0xbd7582865538cd6cULL, }, - { 0x73531997253171c8ULL, 0x386f5044e93c5d10ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0x14e10be595ebd218ULL, }, - { 0x749115ea109e1b46ULL, 0x850632416bfc705cULL, }, - { 0x23efc7de916d3640ULL, 0x238e445f53508af8ULL, }, /* 72 */ - { 0x4f6351b893c43b88ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc3f467a2a46256ceULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0xbd7582865538cd6cULL, }, - { 0x749115ea109e1b46ULL, 0x850632416bfc705cULL, }, - { 0xc3f467a2a46256ceULL, 0x99e73e2701e84274ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_h.c deleted file mode 100644 index 3262365907d2..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x38e48e391c7238e4ULL, 0x8e391c7238e48e39ULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0x38e48e391c7238e4ULL, 0x8e391c7238e48e39ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x16c26c173e9416c2ULL, 0x6c173e9416c26c17ULL, }, - { 0x4fa505b0a4fb4fa5ULL, 0x05b0a4fb4fa505b0ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa505b0a4fb4fa5ULL, 0x05b0a4fb4fa505b0ULL, }, - { 0x16c26c173e9416c2ULL, 0x6c173e9416c26c17ULL, }, - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, /* 48 */ - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, - { 0x38e48e391c7238e4ULL, 0x8e391c7238e48e39ULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0x16c26c173e9416c2ULL, 0x6c173e9416c26c17ULL, }, - { 0x4fa505b0a4fb4fa5ULL, 0x05b0a4fb4fa505b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e371c7e38f38e3ULL, 0x71c7e38f38e371c7ULL, }, - { 0x1c7238e371c81c72ULL, 0x38e371c81c7238e3ULL, }, /* 56 */ - { 0x1c7138e471c71c71ULL, 0x38e471c71c7138e4ULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0x38e48e391c7238e4ULL, 0x8e391c7238e48e39ULL, }, - { 0x4fa505b0a4fb4fa5ULL, 0x05b0a4fb4fa505b0ULL, }, - { 0x16c26c173e9416c2ULL, 0x6c173e9416c26c17ULL, }, - { 0x38e371c7e38f38e3ULL, 0x71c7e38f38e371c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x7354199725318e38ULL, 0x3870504416c4a2f0ULL, }, - { 0x23f038226e93c9c0ULL, 0x238f445f53507508ULL, }, - { 0xe7e52f8135cf72f2ULL, 0xbd76828655393294ULL, }, - { 0x7354199725318e38ULL, 0x3870504416c4a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6451b993c43b88ULL, 0x14e10be56a142de8ULL, }, - { 0x749115ea109e1b46ULL, 0x850632426bfd705cULL, }, - { 0x23f038226e93c9c0ULL, 0x238f445f53507508ULL, }, /* 72 */ - { 0x4f6451b993c43b88ULL, 0x14e10be56a142de8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc3f567a3a46256ceULL, 0x99e73e2701e94274ULL, }, - { 0xe7e52f8135cf72f2ULL, 0xbd76828655393294ULL, }, - { 0x749115ea109e1b46ULL, 0x850632426bfd705cULL, }, - { 0xc3f567a3a46256ceULL, 0x99e73e2701e94274ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_w.c deleted file mode 100644 index 51f9a6941353..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x38e38e391c71c71cULL, 0x8e38e38e38e38e39ULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0x38e38e391c71c71cULL, 0x8e38e38e38e38e39ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x16c16c173e93e93eULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x05b05b054fa4fa50ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x05b05b054fa4fa50ULL, }, - { 0x16c16c173e93e93eULL, 0x6c16c16c16c16c17ULL, }, - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, /* 48 */ - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, - { 0x38e38e391c71c71cULL, 0x8e38e38e38e38e39ULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0x16c16c173e93e93eULL, 0x6c16c16c16c16c17ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x05b05b054fa4fa50ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x38e38e39e38e38e3ULL, 0x71c71c7138e38e39ULL, }, - { 0x1c71c71d71c71c72ULL, 0x38e38e381c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x38e38e391c71c71cULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0x38e38e391c71c71cULL, 0x8e38e38e38e38e39ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x05b05b054fa4fa50ULL, }, - { 0x16c16c173e93e93eULL, 0x6c16c16c16c16c17ULL, }, - { 0x38e38e39e38e38e3ULL, 0x71c71c7138e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x73531997253171c8ULL, 0x386f504416c3a2f0ULL, }, - { 0x23efc7de6e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0xe7e42f8135cf8d0eULL, 0xbd7582865538cd6cULL, }, - { 0x73531997253171c8ULL, 0x386f504416c3a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b993c43b88ULL, 0x14e10be56a142de8ULL, }, - { 0x749115ea109e1b46ULL, 0x850632426bfc705cULL, }, - { 0x23efc7de6e92c9c0ULL, 0x238e445f53508af8ULL, }, /* 72 */ - { 0x4f6351b993c43b88ULL, 0x14e10be56a142de8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc3f467a3a46256ceULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0xbd7582865538cd6cULL, }, - { 0x749115ea109e1b46ULL, 0x850632426bfc705cULL, }, - { 0xc3f467a3a46256ceULL, 0x99e73e2701e84274ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_b.c deleted file mode 100644 index e086214ef858..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x391c72391c72391cULL, 0x72391c72391c7239ULL, }, - { 0x8e391d8e391d8e39ULL, 0x1d8e391d8e391d8eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8e391d8e391d8e39ULL, 0x1d8e391d8e391d8eULL, }, - { 0x391c72391c72391cULL, 0x72391c72391c7239ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x173e94173e94173eULL, 0x94173e94173e9417ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x173e94173e94173eULL, 0x94173e94173e9417ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x391c72391c72391cULL, 0x72391c72391c7239ULL, }, - { 0x8e391d8e391d8e39ULL, 0x1d8e391d8e391d8eULL, }, - { 0x173e94173e94173eULL, 0x94173e94173e9417ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d8fc71d8fc71dULL, 0x8fc71d8fc71d8fc7ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x8e391d8e391d8e39ULL, 0x1d8e391d8e391d8eULL, }, - { 0x391c72391c72391cULL, 0x72391c72391c7239ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x173e94173e94173eULL, 0x94173e94173e9417ULL, }, - { 0xc71d8fc71d8fc71dULL, 0x8fc71d8fc71d8fc7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x7354e66925317238ULL, 0x3990b044e93c5ef0ULL, }, - { 0x24103822916d3640ULL, 0x2471bba153508b08ULL, }, - { 0x181bd07f36318d0eULL, 0x428a7d7a55393294ULL, }, - { 0x7354e66925317238ULL, 0x3990b044e93c5ef0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f64ae476c3c3c78ULL, 0x151f0be596142de8ULL, }, - { 0x8b6f161611621b46ULL, 0x7b0633be9403905cULL, }, - { 0x24103822916d3640ULL, 0x2471bba153508b08ULL, }, /* 72 */ - { 0x4f64ae476c3c3c78ULL, 0x151f0be596142de8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9e5732ULL, 0x66193e270217bd8cULL, }, - { 0x181bd07f36318d0eULL, 0x428a7d7a55393294ULL, }, - { 0x8b6f161611621b46ULL, 0x7b0633be9403905cULL, }, - { 0x3c0b985d5b9e5732ULL, 0x66193e270217bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_d.c deleted file mode 100644 index 5640b6500704..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x38e38e38e38e38e4ULL, 0x71c71c71c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71c71c71c72ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x71c71c71c71c71c7ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x16c16c16c16c16c2ULL, 0x93e93e93e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c16c16c16c16c2ULL, 0x93e93e93e93e93e9ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x71c71c71c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71c71c71c72ULL, }, - { 0x16c16c16c16c16c2ULL, 0x93e93e93e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x8e38e38e38e38e39ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x71c71c71c71c71c7ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c16c16c16c16c2ULL, 0x93e93e93e93e93e9ULL, }, - { 0xc71c71c71c71c71dULL, 0x8e38e38e38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x73531997253171c8ULL, 0x386f5044e93c5d10ULL, }, - { 0x23efc7de916d3640ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07eca3072f2ULL, 0x428a7d79aac73294ULL, }, - { 0x73531997253171c8ULL, 0x386f5044e93c5d10ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0x14e10be595ebd218ULL, }, - { 0x8b6eea15ef61e4baULL, 0x7af9cdbe94038fa4ULL, }, - { 0x23efc7de916d3640ULL, 0x238e445f53508af8ULL, }, /* 72 */ - { 0x4f6351b893c43b88ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x6618c1d8fe17bd8cULL, }, - { 0x181bd07eca3072f2ULL, 0x428a7d79aac73294ULL, }, - { 0x8b6eea15ef61e4baULL, 0x7af9cdbe94038fa4ULL, }, - { 0x3c0b985d5b9da932ULL, 0x6618c1d8fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_h.c deleted file mode 100644 index a5bf2d20540e..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x38e471c71c7238e4ULL, 0x71c71c7238e471c7ULL, }, - { 0x8e391c7238e38e39ULL, 0x1c7238e38e391c72ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8e391c7238e38e39ULL, 0x1c7238e38e391c72ULL, }, - { 0x38e471c71c7238e4ULL, 0x71c71c7238e471c7ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x16c293e93e9416c2ULL, 0x93e93e9416c293e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c293e93e9416c2ULL, 0x93e93e9416c293e9ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e471c71c7238e4ULL, 0x71c71c7238e471c7ULL, }, - { 0x8e391c7238e38e39ULL, 0x1c7238e38e391c72ULL, }, - { 0x16c293e93e9416c2ULL, 0x93e93e9416c293e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d8e391c71c71dULL, 0x8e391c71c71d8e39ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x8e391c7238e38e39ULL, 0x1c7238e38e391c72ULL, }, - { 0x38e471c71c7238e4ULL, 0x71c71c7238e471c7ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c293e93e9416c2ULL, 0x93e93e9416c293e9ULL, }, - { 0xc71d8e391c71c71dULL, 0x8e391c71c71d8e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x7354e669253171c8ULL, 0x3870afbce93c5d10ULL, }, - { 0x23f03822916d3640ULL, 0x238fbba153508af8ULL, }, - { 0x181bd07f35cf8d0eULL, 0x428a7d7a55393294ULL, }, - { 0x7354e669253171c8ULL, 0x3870afbce93c5d10ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f64ae476c3c3b88ULL, 0x14e10be595ec2de8ULL, }, - { 0x8b6f15ea109e1b46ULL, 0x7afa324294038fa4ULL, }, - { 0x23f03822916d3640ULL, 0x238fbba153508af8ULL, }, /* 72 */ - { 0x4f64ae476c3c3b88ULL, 0x14e10be595ec2de8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9e56ceULL, 0x66193e2701e9bd8cULL, }, - { 0x181bd07f35cf8d0eULL, 0x428a7d7a55393294ULL, }, - { 0x8b6f15ea109e1b46ULL, 0x7afa324294038fa4ULL, }, - { 0x3c0b985d5b9e56ceULL, 0x66193e2701e9bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_w.c deleted file mode 100644 index 772e90eedb0a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_asub_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction ASUB_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "ASUB_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x38e38e391c71c71cULL, 0x71c71c7238e38e39ULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71d8e38e38eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71d8e38e38eULL, }, - { 0x38e38e391c71c71cULL, 0x71c71c7238e38e39ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x16c16c173e93e93eULL, 0x93e93e9416c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c16c173e93e93eULL, 0x93e93e9416c16c17ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e391c71c71cULL, 0x71c71c7238e38e39ULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71d8e38e38eULL, }, - { 0x16c16c173e93e93eULL, 0x93e93e9416c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x8e38e38fc71c71c7ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x8e38e38e38e38e39ULL, 0x1c71c71d8e38e38eULL, }, - { 0x38e38e391c71c71cULL, 0x71c71c7238e38e39ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x16c16c173e93e93eULL, 0x93e93e9416c16c17ULL, }, - { 0xc71c71c71c71c71dULL, 0x8e38e38fc71c71c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x73531997253171c8ULL, 0x386f5044e93c5d10ULL, }, - { 0x23efc7de916d3640ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07f35cf8d0eULL, 0x428a7d7a5538cd6cULL, }, - { 0x73531997253171c8ULL, 0x386f5044e93c5d10ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b96c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x8b6eea16109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0x23efc7de916d3640ULL, 0x238e445f53508af8ULL, }, /* 72 */ - { 0x4f6351b96c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x6618c1d901e84274ULL, }, - { 0x181bd07f35cf8d0eULL, 0x428a7d7a5538cd6cULL, }, - { 0x8b6eea16109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0x3c0b985d5b9da932ULL, 0x6618c1d901e84274ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ASUB_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_d.c deleted file mode 100644 index 66137f58562e..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HSUB_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "HSUB_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0xffffffff8e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000055555556ULL, 0x0000000055555556ULL, }, - { 0xffffffffaaaaaaabULL, 0xffffffffaaaaaaabULL, }, - { 0x0000000033333334ULL, 0x0000000033333334ULL, }, - { 0xffffffffcccccccdULL, 0xffffffffcccccccdULL, }, - { 0x0000000071c71c72ULL, 0x000000001c71c71dULL, }, - { 0xffffffff8e38e38fULL, 0xffffffffe38e38e4ULL, }, - { 0xffffffffaaaaaaabULL, 0xffffffffaaaaaaabULL, }, /* 16 */ - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff55555555ULL, 0xffffffff55555555ULL, }, - { 0xffffffffdddddddeULL, 0xffffffffdddddddeULL, }, - { 0xffffffff77777777ULL, 0xffffffff77777777ULL, }, - { 0x000000001c71c71cULL, 0xffffffffc71c71c7ULL, }, - { 0xffffffff38e38e39ULL, 0xffffffff8e38e38eULL, }, - { 0x0000000055555556ULL, 0x0000000055555556ULL, }, /* 24 */ - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000aaaaaaabULL, 0x00000000aaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000088888889ULL, 0x0000000088888889ULL, }, - { 0x0000000022222222ULL, 0x0000000022222222ULL, }, - { 0x00000000c71c71c7ULL, 0x0000000071c71c72ULL, }, - { 0xffffffffe38e38e4ULL, 0x0000000038e38e39ULL, }, - { 0xffffffffcccccccdULL, 0xffffffffcccccccdULL, }, /* 32 */ - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0x0000000022222222ULL, 0x0000000022222222ULL, }, - { 0xffffffff77777777ULL, 0xffffffff77777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff99999999ULL, 0xffffffff99999999ULL, }, - { 0x000000003e93e93eULL, 0xffffffffe93e93e9ULL, }, - { 0xffffffff5b05b05bULL, 0xffffffffb05b05b0ULL, }, - { 0x0000000033333334ULL, 0x0000000033333334ULL, }, /* 40 */ - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x0000000088888889ULL, 0x0000000088888889ULL, }, - { 0xffffffffdddddddeULL, 0xffffffffdddddddeULL, }, - { 0x0000000066666667ULL, 0x0000000066666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000a4fa4fa5ULL, 0x000000004fa4fa50ULL, }, - { 0xffffffffc16c16c2ULL, 0x0000000016c16c17ULL, }, - { 0xffffffffe38e38e4ULL, 0x0000000038e38e39ULL, }, /* 48 */ - { 0xffffffffe38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0x0000000038e38e39ULL, 0x000000008e38e38eULL, }, - { 0xffffffff8e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0x0000000016c16c17ULL, 0x000000006c16c16cULL, }, - { 0xffffffffb05b05b0ULL, 0x0000000005b05b05ULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0xffffffff71c71c72ULL, 0x000000001c71c71cULL, }, - { 0x000000001c71c71dULL, 0xffffffffc71c71c8ULL, }, /* 56 */ - { 0x000000001c71c71cULL, 0xffffffffc71c71c7ULL, }, - { 0x0000000071c71c72ULL, 0x000000001c71c71dULL, }, - { 0xffffffffc71c71c7ULL, 0xffffffff71c71c72ULL, }, - { 0x000000004fa4fa50ULL, 0xfffffffffa4fa4fbULL, }, - { 0xffffffffe93e93e9ULL, 0xffffffff93e93e94ULL, }, - { 0x000000008e38e38eULL, 0xffffffffe38e38e4ULL, }, - { 0xffffffffaaaaaaabULL, 0xffffffffaaaaaaabULL, }, - { 0xffffffff6008918cULL, 0x000000004ceb5b52ULL, }, /* 64 */ - { 0xffffffff3ad71fc4ULL, 0x000000003627b862ULL, }, - { 0xffffffffce9b5b4cULL, 0x00000000a03be64aULL, }, - { 0xffffffff2a39047eULL, 0x00000000a22428beULL, }, - { 0xffffffffd35bab23ULL, 0x00000000147c0b0eULL, }, - { 0xffffffffae2a395bULL, 0xfffffffffdb8681eULL, }, - { 0x0000000041ee74e3ULL, 0x0000000067cc9606ULL, }, - { 0xffffffff9d8c1e15ULL, 0x0000000069b4d87aULL, }, - { 0xffffffff83f8596aULL, 0x00000000295d16f3ULL, }, /* 72 */ - { 0xffffffff5ec6e7a2ULL, 0x0000000012997403ULL, }, - { 0xfffffffff28b232aULL, 0x000000007cada1ebULL, }, - { 0xffffffff4e28cc5cULL, 0x000000007e95e45fULL, }, - { 0x0000000047ecc10dULL, 0xffffffff8f75d8ccULL, }, - { 0x0000000022bb4f45ULL, 0xffffffff78b235dcULL, }, - { 0x00000000b67f8acdULL, 0xffffffffe2c663c4ULL, }, - { 0x00000000121d33ffULL, 0xffffffffe4aea638ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_h.c deleted file mode 100644 index e66261b821db..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HSUB_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "HSUB_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0x0071001cffc70071ULL, 0x001cffc70071001cULL, }, - { 0xff8effe30038ff8eULL, 0xffe30038ff8effe3ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0056005600560056ULL, 0x0056005600560056ULL, }, - { 0xffabffabffabffabULL, 0xffabffabffabffabULL, }, - { 0x0034003400340034ULL, 0x0034003400340034ULL, }, - { 0xffcdffcdffcdffcdULL, 0xffcdffcdffcdffcdULL, }, - { 0x0072001dffc80072ULL, 0x001dffc80072001dULL, }, - { 0xff8fffe40039ff8fULL, 0xffe40039ff8fffe4ULL, }, - { 0xffabffabffabffabULL, 0xffabffabffabffabULL, }, /* 16 */ - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff55ff55ff55ff55ULL, 0xff55ff55ff55ff55ULL, }, - { 0xffdeffdeffdeffdeULL, 0xffdeffdeffdeffdeULL, }, - { 0xff77ff77ff77ff77ULL, 0xff77ff77ff77ff77ULL, }, - { 0x001cffc7ff72001cULL, 0xffc7ff72001cffc7ULL, }, - { 0xff39ff8effe3ff39ULL, 0xff8effe3ff39ff8eULL, }, - { 0x0056005600560056ULL, 0x0056005600560056ULL, }, /* 24 */ - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00ab00ab00ab00abULL, 0x00ab00ab00ab00abULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0089008900890089ULL, 0x0089008900890089ULL, }, - { 0x0022002200220022ULL, 0x0022002200220022ULL, }, - { 0x00c70072001d00c7ULL, 0x0072001d00c70072ULL, }, - { 0xffe40039008effe4ULL, 0x0039008effe40039ULL, }, - { 0xffcdffcdffcdffcdULL, 0xffcdffcdffcdffcdULL, }, /* 32 */ - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0x0022002200220022ULL, 0x0022002200220022ULL, }, - { 0xff77ff77ff77ff77ULL, 0xff77ff77ff77ff77ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff99ff99ff99ff99ULL, 0xff99ff99ff99ff99ULL, }, - { 0x003effe9ff94003eULL, 0xffe9ff94003effe9ULL, }, - { 0xff5bffb00005ff5bULL, 0xffb00005ff5bffb0ULL, }, - { 0x0034003400340034ULL, 0x0034003400340034ULL, }, /* 40 */ - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x0089008900890089ULL, 0x0089008900890089ULL, }, - { 0xffdeffdeffdeffdeULL, 0xffdeffdeffdeffdeULL, }, - { 0x0067006700670067ULL, 0x0067006700670067ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00a50050fffb00a5ULL, 0x0050fffb00a50050ULL, }, - { 0xffc20017006cffc2ULL, 0x0017006cffc20017ULL, }, - { 0xffe40039ff8fffe4ULL, 0x0039ff8fffe40039ULL, }, /* 48 */ - { 0xffe30038ff8effe3ULL, 0x0038ff8effe30038ULL, }, - { 0x0039008effe40039ULL, 0x008effe40039008eULL, }, - { 0xff8effe3ff39ff8eULL, 0xffe3ff39ff8effe3ULL, }, - { 0x0017006cffc20017ULL, 0x006cffc20017006cULL, }, - { 0xffb00005ff5bffb0ULL, 0x0005ff5bffb00005ULL, }, - { 0x00550055ff560055ULL, 0x0055ff5600550055ULL, }, - { 0xff72001cffc7ff72ULL, 0x001cffc7ff72001cULL, }, - { 0x001dffc80072001dULL, 0xffc80072001dffc8ULL, }, /* 56 */ - { 0x001cffc70071001cULL, 0xffc70071001cffc7ULL, }, - { 0x0072001d00c70072ULL, 0x001d00c70072001dULL, }, - { 0xffc7ff72001cffc7ULL, 0xff72001cffc7ff72ULL, }, - { 0x0050fffb00a50050ULL, 0xfffb00a50050fffbULL, }, - { 0xffe9ff94003effe9ULL, 0xff94003effe9ff94ULL, }, - { 0x008effe40039008eULL, 0xffe40039008effe4ULL, }, - { 0xffabffab00aaffabULL, 0xffab00aaffabffabULL, }, - { 0xff1e001affc60015ULL, 0xffe4ffadff83ffa4ULL, }, /* 64 */ - { 0xffcaff830095004dULL, 0x0054fff1ffbfffb4ULL, }, - { 0xff2e003c005900d5ULL, 0x0073000cffd3ff9cULL, }, - { 0xff39ff99fff70007ULL, 0x005a0033ffbc0010ULL, }, - { 0xff910034ffebff87ULL, 0xffabff5dff9a0046ULL, }, - { 0x003dff9d00baffbfULL, 0x001bffa1ffd60056ULL, }, - { 0xffa10056007e0047ULL, 0x003affbcffea003eULL, }, - { 0xffacffb3001cff79ULL, 0x0021ffe3ffd300b2ULL, }, - { 0xff42ffe2ff57ff4bULL, 0xffc0ff68ff300019ULL, }, /* 72 */ - { 0xffeeff4b0026ff83ULL, 0x0030ffacff6c0029ULL, }, - { 0xff520004ffea000bULL, 0x004fffc7ff800011ULL, }, - { 0xff5dff61ff88ff3dULL, 0x0036ffeeff690085ULL, }, - { 0x0006004afffcffa2ULL, 0xff26ff2aff2effd6ULL, }, - { 0x00b2ffb300cbffdaULL, 0xff96ff6eff6affe6ULL, }, - { 0x0016006c008f0062ULL, 0xffb5ff89ff7effceULL, }, - { 0x0021ffc9002dff94ULL, 0xff9cffb0ff670042ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_w.c deleted file mode 100644 index 6d97abfe3c88..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HSUB_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "HSUB_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0xffffc71c00001c71ULL, 0x000071c7ffffc71cULL, }, - { 0x000038e3ffffe38eULL, 0xffff8e38000038e3ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000555600005556ULL, 0x0000555600005556ULL, }, - { 0xffffaaabffffaaabULL, 0xffffaaabffffaaabULL, }, - { 0x0000333400003334ULL, 0x0000333400003334ULL, }, - { 0xffffcccdffffcccdULL, 0xffffcccdffffcccdULL, }, - { 0xffffc71d00001c72ULL, 0x000071c8ffffc71dULL, }, - { 0x000038e4ffffe38fULL, 0xffff8e39000038e4ULL, }, - { 0xffffaaabffffaaabULL, 0xffffaaabffffaaabULL, }, /* 16 */ - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff5555ffff5555ULL, 0xffff5555ffff5555ULL, }, - { 0xffffdddeffffdddeULL, 0xffffdddeffffdddeULL, }, - { 0xffff7777ffff7777ULL, 0xffff7777ffff7777ULL, }, - { 0xffff71c7ffffc71cULL, 0x00001c72ffff71c7ULL, }, - { 0xffffe38effff8e39ULL, 0xffff38e3ffffe38eULL, }, - { 0x0000555600005556ULL, 0x0000555600005556ULL, }, /* 24 */ - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000aaab0000aaabULL, 0x0000aaab0000aaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000888900008889ULL, 0x0000888900008889ULL, }, - { 0x0000222200002222ULL, 0x0000222200002222ULL, }, - { 0x00001c72000071c7ULL, 0x0000c71d00001c72ULL, }, - { 0x00008e39000038e4ULL, 0xffffe38e00008e39ULL, }, - { 0xffffcccdffffcccdULL, 0xffffcccdffffcccdULL, }, /* 32 */ - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0x0000222200002222ULL, 0x0000222200002222ULL, }, - { 0xffff7777ffff7777ULL, 0xffff7777ffff7777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff9999ffff9999ULL, 0xffff9999ffff9999ULL, }, - { 0xffff93e9ffffe93eULL, 0x00003e94ffff93e9ULL, }, - { 0x000005b0ffffb05bULL, 0xffff5b05000005b0ULL, }, - { 0x0000333400003334ULL, 0x0000333400003334ULL, }, /* 40 */ - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x0000888900008889ULL, 0x0000888900008889ULL, }, - { 0xffffdddeffffdddeULL, 0xffffdddeffffdddeULL, }, - { 0x0000666700006667ULL, 0x0000666700006667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xfffffa5000004fa5ULL, 0x0000a4fbfffffa50ULL, }, - { 0x00006c17000016c2ULL, 0xffffc16c00006c17ULL, }, - { 0xffffe38fffff8e39ULL, 0x000038e4ffffe38fULL, }, /* 48 */ - { 0xffffe38effff8e38ULL, 0x000038e3ffffe38eULL, }, - { 0x000038e4ffffe38eULL, 0x00008e39000038e4ULL, }, - { 0xffff8e39ffff38e3ULL, 0xffffe38effff8e39ULL, }, - { 0x000016c2ffffc16cULL, 0x00006c17000016c2ULL, }, - { 0xffffb05bffff5b05ULL, 0x000005b0ffffb05bULL, }, - { 0xffffaaabffffaaaaULL, 0x0000aaabffffaaabULL, }, - { 0x00001c72ffff71c7ULL, 0xffffc71c00001c72ULL, }, - { 0x00001c72000071c8ULL, 0xffffc71d00001c72ULL, }, /* 56 */ - { 0x00001c71000071c7ULL, 0xffffc71c00001c71ULL, }, - { 0x000071c70000c71dULL, 0x00001c72000071c7ULL, }, - { 0xffffc71c00001c72ULL, 0xffff71c7ffffc71cULL, }, - { 0x00004fa50000a4fbULL, 0xfffffa5000004fa5ULL, }, - { 0xffffe93e00003e94ULL, 0xffff93e9ffffe93eULL, }, - { 0xffffe38e00008e39ULL, 0x000038e4ffffe38eULL, }, - { 0x0000555500005556ULL, 0xffff555500005555ULL, }, - { 0xffffa19effffd322ULL, 0x0000400900004e6fULL, }, /* 64 */ - { 0xffff88070000615aULL, 0x0000904dffffab7fULL, }, - { 0xffffd9c000009ce2ULL, 0x00008468ffffd967ULL, }, - { 0xffff721d00004614ULL, 0x0000c28f00001bdbULL, }, - { 0x000014f2fffff853ULL, 0x0000079900006533ULL, }, - { 0xfffffb5b0000868bULL, 0x000057ddffffc243ULL, }, - { 0x00004d140000c213ULL, 0x00004bf8fffff02bULL, }, - { 0xffffe57100006b45ULL, 0x00008a1f0000329fULL, }, - { 0xffffc58effff648fULL, 0x00001c7afffffb1fULL, }, /* 72 */ - { 0xffffabf7fffff2c7ULL, 0x00006cbeffff582fULL, }, - { 0xfffffdb000002e4fULL, 0x000060d9ffff8617ULL, }, - { 0xffff960dffffd781ULL, 0x00009f00ffffc88bULL, }, - { 0x00008983000008f1ULL, 0xffff8293fffff936ULL, }, - { 0x00006fec00009729ULL, 0xffffd2d7ffff5646ULL, }, - { 0x0000c1a50000d2b1ULL, 0xffffc6f2ffff842eULL, }, - { 0x00005a0200007be3ULL, 0x00000519ffffc6a2ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_d.c deleted file mode 100644 index 8f39a4525bbe..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HSUB_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "HSUB_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0x000000008e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0xffffffff00000001ULL, 0xffffffff00000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff55555556ULL, 0xffffffff55555556ULL, }, - { 0xffffffffaaaaaaabULL, 0xffffffffaaaaaaabULL, }, - { 0xffffffff33333334ULL, 0xffffffff33333334ULL, }, - { 0xffffffffcccccccdULL, 0xffffffffcccccccdULL, }, - { 0xffffffff71c71c72ULL, 0xffffffff1c71c71dULL, }, - { 0xffffffff8e38e38fULL, 0xffffffffe38e38e4ULL, }, - { 0xffffffffaaaaaaabULL, 0xffffffffaaaaaaabULL, }, /* 16 */ - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0xffffffffdddddddeULL, 0xffffffffdddddddeULL, }, - { 0x0000000077777777ULL, 0x0000000077777777ULL, }, - { 0x000000001c71c71cULL, 0xffffffffc71c71c7ULL, }, - { 0x0000000038e38e39ULL, 0x000000008e38e38eULL, }, - { 0xffffffff55555556ULL, 0xffffffff55555556ULL, }, /* 24 */ - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0xffffffffaaaaaaabULL, 0xffffffffaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff88888889ULL, 0xffffffff88888889ULL, }, - { 0x0000000022222222ULL, 0x0000000022222222ULL, }, - { 0xffffffffc71c71c7ULL, 0xffffffff71c71c72ULL, }, - { 0xffffffffe38e38e4ULL, 0x0000000038e38e39ULL, }, - { 0xffffffffcccccccdULL, 0xffffffffcccccccdULL, }, /* 32 */ - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000022222222ULL, 0x0000000022222222ULL, }, - { 0x0000000077777777ULL, 0x0000000077777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000099999999ULL, 0x0000000099999999ULL, }, - { 0x000000003e93e93eULL, 0xffffffffe93e93e9ULL, }, - { 0x000000005b05b05bULL, 0x00000000b05b05b0ULL, }, - { 0xffffffff33333334ULL, 0xffffffff33333334ULL, }, /* 40 */ - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0xffffffff88888889ULL, 0xffffffff88888889ULL, }, - { 0xffffffffdddddddeULL, 0xffffffffdddddddeULL, }, - { 0xffffffff66666667ULL, 0xffffffff66666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffa4fa4fa5ULL, 0xffffffff4fa4fa50ULL, }, - { 0xffffffffc16c16c2ULL, 0x0000000016c16c17ULL, }, - { 0xffffffffe38e38e4ULL, 0xffffffff38e38e39ULL, }, /* 48 */ - { 0x00000000e38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0x0000000038e38e39ULL, 0xffffffff8e38e38eULL, }, - { 0x000000008e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0x0000000016c16c17ULL, 0xffffffff6c16c16cULL, }, - { 0x00000000b05b05b0ULL, 0x0000000005b05b05ULL, }, - { 0x0000000055555555ULL, 0xffffffff55555555ULL, }, - { 0x0000000071c71c72ULL, 0x000000001c71c71cULL, }, - { 0xffffffff1c71c71dULL, 0xffffffffc71c71c8ULL, }, /* 56 */ - { 0x000000001c71c71cULL, 0x00000000c71c71c7ULL, }, - { 0xffffffff71c71c72ULL, 0x000000001c71c71dULL, }, - { 0xffffffffc71c71c7ULL, 0x0000000071c71c72ULL, }, - { 0xffffffff4fa4fa50ULL, 0xfffffffffa4fa4fbULL, }, - { 0xffffffffe93e93e9ULL, 0x0000000093e93e94ULL, }, - { 0xffffffff8e38e38eULL, 0xffffffffe38e38e4ULL, }, - { 0xffffffffaaaaaaabULL, 0x00000000aaaaaaabULL, }, - { 0x000000006008918cULL, 0xffffffff4ceb5b52ULL, }, /* 64 */ - { 0x000000003ad71fc4ULL, 0x000000003627b862ULL, }, - { 0xffffffffce9b5b4cULL, 0xffffffffa03be64aULL, }, - { 0x000000002a39047eULL, 0xffffffffa22428beULL, }, - { 0x00000000d35bab23ULL, 0xffffffff147c0b0eULL, }, - { 0x00000000ae2a395bULL, 0xfffffffffdb8681eULL, }, - { 0x0000000041ee74e3ULL, 0xffffffff67cc9606ULL, }, - { 0x000000009d8c1e15ULL, 0xffffffff69b4d87aULL, }, - { 0x0000000083f8596aULL, 0xffffffff295d16f3ULL, }, /* 72 */ - { 0x000000005ec6e7a2ULL, 0x0000000012997403ULL, }, - { 0xfffffffff28b232aULL, 0xffffffff7cada1ebULL, }, - { 0x000000004e28cc5cULL, 0xffffffff7e95e45fULL, }, - { 0x0000000047ecc10dULL, 0xffffffff8f75d8ccULL, }, - { 0x0000000022bb4f45ULL, 0x0000000078b235dcULL, }, - { 0xffffffffb67f8acdULL, 0xffffffffe2c663c4ULL, }, - { 0x00000000121d33ffULL, 0xffffffffe4aea638ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_h.c deleted file mode 100644 index 6cc82fce29ce..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HSUB_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "HSUB_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0071001c00c70071ULL, 0x001c00c70071001cULL, }, - { 0x008e00e30038008eULL, 0x00e30038008e00e3ULL, }, - { 0xff01ff01ff01ff01ULL, 0xff01ff01ff01ff01ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff56ff56ff56ff56ULL, 0xff56ff56ff56ff56ULL, }, - { 0xffabffabffabffabULL, 0xffabffabffabffabULL, }, - { 0xff34ff34ff34ff34ULL, 0xff34ff34ff34ff34ULL, }, - { 0xffcdffcdffcdffcdULL, 0xffcdffcdffcdffcdULL, }, - { 0xff72ff1dffc8ff72ULL, 0xff1dffc8ff72ff1dULL, }, - { 0xff8fffe4ff39ff8fULL, 0xffe4ff39ff8fffe4ULL, }, - { 0xffabffabffabffabULL, 0xffabffabffabffabULL, }, /* 16 */ - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0xffdeffdeffdeffdeULL, 0xffdeffdeffdeffdeULL, }, - { 0x0077007700770077ULL, 0x0077007700770077ULL, }, - { 0x001cffc70072001cULL, 0xffc70072001cffc7ULL, }, - { 0x0039008effe30039ULL, 0x008effe30039008eULL, }, - { 0xff56ff56ff56ff56ULL, 0xff56ff56ff56ff56ULL, }, /* 24 */ - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0xffabffabffabffabULL, 0xffabffabffabffabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xff89ff89ff89ff89ULL, 0xff89ff89ff89ff89ULL, }, - { 0x0022002200220022ULL, 0x0022002200220022ULL, }, - { 0xffc7ff72001dffc7ULL, 0xff72001dffc7ff72ULL, }, - { 0xffe40039ff8effe4ULL, 0x0039ff8effe40039ULL, }, - { 0xffcdffcdffcdffcdULL, 0xffcdffcdffcdffcdULL, }, /* 32 */ - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0022002200220022ULL, 0x0022002200220022ULL, }, - { 0x0077007700770077ULL, 0x0077007700770077ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0099009900990099ULL, 0x0099009900990099ULL, }, - { 0x003effe90094003eULL, 0xffe90094003effe9ULL, }, - { 0x005b00b00005005bULL, 0x00b00005005b00b0ULL, }, - { 0xff34ff34ff34ff34ULL, 0xff34ff34ff34ff34ULL, }, /* 40 */ - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0xff89ff89ff89ff89ULL, 0xff89ff89ff89ff89ULL, }, - { 0xffdeffdeffdeffdeULL, 0xffdeffdeffdeffdeULL, }, - { 0xff67ff67ff67ff67ULL, 0xff67ff67ff67ff67ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffa5ff50fffbffa5ULL, 0xff50fffbffa5ff50ULL, }, - { 0xffc20017ff6cffc2ULL, 0x0017ff6cffc20017ULL, }, - { 0xffe4ff39ff8fffe4ULL, 0xff39ff8fffe4ff39ULL, }, /* 48 */ - { 0x00e30038008e00e3ULL, 0x0038008e00e30038ULL, }, - { 0x0039ff8effe40039ULL, 0xff8effe40039ff8eULL, }, - { 0x008effe30039008eULL, 0xffe30039008effe3ULL, }, - { 0x0017ff6cffc20017ULL, 0xff6cffc20017ff6cULL, }, - { 0x00b00005005b00b0ULL, 0x0005005b00b00005ULL, }, - { 0x0055ff5500560055ULL, 0xff5500560055ff55ULL, }, - { 0x0072001cffc70072ULL, 0x001cffc70072001cULL, }, - { 0xff1dffc8ff72ff1dULL, 0xffc8ff72ff1dffc8ULL, }, /* 56 */ - { 0x001c00c70071001cULL, 0x00c70071001c00c7ULL, }, - { 0xff72001dffc7ff72ULL, 0x001dffc7ff72001dULL, }, - { 0xffc70072001cffc7ULL, 0x0072001cffc70072ULL, }, - { 0xff50fffbffa5ff50ULL, 0xfffbffa5ff50fffbULL, }, - { 0xffe90094003effe9ULL, 0x0094003effe90094ULL, }, - { 0xff8effe40039ff8eULL, 0xffe40039ff8effe4ULL, }, - { 0xffab00abffaaffabULL, 0x00abffaaffab00abULL, }, - { 0x001e001affc60015ULL, 0xffe4ffad008300a4ULL, }, /* 64 */ - { 0xffca0083ff95004dULL, 0xff54fff100bfffb4ULL, }, - { 0x002e003cff59ffd5ULL, 0xff73ff0c00d3009cULL, }, - { 0x00390099fff70007ULL, 0xff5aff3300bc0010ULL, }, - { 0x0091ff34ffeb0087ULL, 0xffab005dff9a0046ULL, }, - { 0x003dff9dffba00bfULL, 0xff1b00a1ffd6ff56ULL, }, - { 0x00a1ff56ff7e0047ULL, 0xff3affbcffea003eULL, }, - { 0x00acffb3001c0079ULL, 0xff21ffe3ffd3ffb2ULL, }, - { 0x0042ffe20057004bULL, 0xffc0006800300019ULL, }, /* 72 */ - { 0xffee004b00260083ULL, 0xff3000ac006cff29ULL, }, - { 0x00520004ffea000bULL, 0xff4fffc700800011ULL, }, - { 0x005d00610088003dULL, 0xff36ffee0069ff85ULL, }, - { 0x0006ff4afffc00a2ULL, 0x0026002a002e00d6ULL, }, - { 0xffb2ffb3ffcb00daULL, 0xff96006e006affe6ULL, }, - { 0x0016ff6cff8f0062ULL, 0xffb5ff89007e00ceULL, }, - { 0x0021ffc9002d0094ULL, 0xff9cffb000670042ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_w.c deleted file mode 100644 index b427e87a3ac1..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_hsub_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction HSUB_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "HSUB_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000c71c00001c71ULL, 0x000071c70000c71cULL, }, - { 0x000038e30000e38eULL, 0x00008e38000038e3ULL, }, - { 0xffff0001ffff0001ULL, 0xffff0001ffff0001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff5556ffff5556ULL, 0xffff5556ffff5556ULL, }, - { 0xffffaaabffffaaabULL, 0xffffaaabffffaaabULL, }, - { 0xffff3334ffff3334ULL, 0xffff3334ffff3334ULL, }, - { 0xffffcccdffffcccdULL, 0xffffcccdffffcccdULL, }, - { 0xffffc71dffff1c72ULL, 0xffff71c8ffffc71dULL, }, - { 0xffff38e4ffffe38fULL, 0xffff8e39ffff38e4ULL, }, - { 0xffffaaabffffaaabULL, 0xffffaaabffffaaabULL, }, /* 16 */ - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0xffffdddeffffdddeULL, 0xffffdddeffffdddeULL, }, - { 0x0000777700007777ULL, 0x0000777700007777ULL, }, - { 0x000071c7ffffc71cULL, 0x00001c72000071c7ULL, }, - { 0xffffe38e00008e39ULL, 0x000038e3ffffe38eULL, }, - { 0xffff5556ffff5556ULL, 0xffff5556ffff5556ULL, }, /* 24 */ - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0xffffaaabffffaaabULL, 0xffffaaabffffaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffff8889ffff8889ULL, 0xffff8889ffff8889ULL, }, - { 0x0000222200002222ULL, 0x0000222200002222ULL, }, - { 0x00001c72ffff71c7ULL, 0xffffc71d00001c72ULL, }, - { 0xffff8e39000038e4ULL, 0xffffe38effff8e39ULL, }, - { 0xffffcccdffffcccdULL, 0xffffcccdffffcccdULL, }, /* 32 */ - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000222200002222ULL, 0x0000222200002222ULL, }, - { 0x0000777700007777ULL, 0x0000777700007777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000999900009999ULL, 0x0000999900009999ULL, }, - { 0x000093e9ffffe93eULL, 0x00003e94000093e9ULL, }, - { 0x000005b00000b05bULL, 0x00005b05000005b0ULL, }, - { 0xffff3334ffff3334ULL, 0xffff3334ffff3334ULL, }, /* 40 */ - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0xffff8889ffff8889ULL, 0xffff8889ffff8889ULL, }, - { 0xffffdddeffffdddeULL, 0xffffdddeffffdddeULL, }, - { 0xffff6667ffff6667ULL, 0xffff6667ffff6667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xfffffa50ffff4fa5ULL, 0xffffa4fbfffffa50ULL, }, - { 0xffff6c17000016c2ULL, 0xffffc16cffff6c17ULL, }, - { 0xffffe38fffff8e39ULL, 0xffff38e4ffffe38fULL, }, /* 48 */ - { 0x0000e38e00008e38ULL, 0x000038e30000e38eULL, }, - { 0x000038e4ffffe38eULL, 0xffff8e39000038e4ULL, }, - { 0x00008e39000038e3ULL, 0xffffe38e00008e39ULL, }, - { 0x000016c2ffffc16cULL, 0xffff6c17000016c2ULL, }, - { 0x0000b05b00005b05ULL, 0x000005b00000b05bULL, }, - { 0x0000aaabffffaaaaULL, 0xffffaaab0000aaabULL, }, - { 0x00001c72000071c7ULL, 0xffffc71c00001c72ULL, }, - { 0xffff1c72ffff71c8ULL, 0xffffc71dffff1c72ULL, }, /* 56 */ - { 0x00001c71000071c7ULL, 0x0000c71c00001c71ULL, }, - { 0xffff71c7ffffc71dULL, 0x00001c72ffff71c7ULL, }, - { 0xffffc71c00001c72ULL, 0x000071c7ffffc71cULL, }, - { 0xffff4fa5ffffa4fbULL, 0xfffffa50ffff4fa5ULL, }, - { 0xffffe93e00003e94ULL, 0x000093e9ffffe93eULL, }, - { 0xffffe38effff8e39ULL, 0x000038e4ffffe38eULL, }, - { 0xffff555500005556ULL, 0x00005555ffff5555ULL, }, - { 0xffffa19effffd322ULL, 0x0000400900004e6fULL, }, /* 64 */ - { 0x00008807ffff615aULL, 0xffff904d0000ab7fULL, }, - { 0xffffd9c0ffff9ce2ULL, 0xffff84680000d967ULL, }, - { 0x0000721dffff4614ULL, 0xffffc28f00001bdbULL, }, - { 0x000014f2fffff853ULL, 0x00000799ffff6533ULL, }, - { 0x0000fb5bffff868bULL, 0xffff57ddffffc243ULL, }, - { 0x00004d14ffffc213ULL, 0xffff4bf8fffff02bULL, }, - { 0x0000e571ffff6b45ULL, 0xffff8a1fffff329fULL, }, - { 0xffffc58e0000648fULL, 0x00001c7afffffb1fULL, }, /* 72 */ - { 0x0000abf7fffff2c7ULL, 0xffff6cbe0000582fULL, }, - { 0xfffffdb000002e4fULL, 0xffff60d900008617ULL, }, - { 0x0000960dffffd781ULL, 0xffff9f00ffffc88bULL, }, - { 0xffff8983000008f1ULL, 0x00008293fffff936ULL, }, - { 0x00006fecffff9729ULL, 0xffffd2d700005646ULL, }, - { 0xffffc1a5ffffd2b1ULL, 0xffffc6f20000842eULL, }, - { 0x00005a02ffff7be3ULL, 0x00000519ffffc6a2ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_HSUB_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_b.c deleted file mode 100644 index 5c1f810d6679..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xc71c80c71c80c71cULL, 0x80c71c80c71c80c7ULL, }, - { 0x8e80e38e80e38e80ULL, 0xe38e80e38e80e38eULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x727f1d727f1d727fULL, 0x1d727f1d727f1d72ULL, }, - { 0x39e47f39e47f39e4ULL, 0x7f39e47f39e47f39ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e94e93e94e93eULL, 0x94e93e94e93e94e9ULL, }, - { 0xb08005b08005b080ULL, 0x05b08005b08005b0ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x507ffb507ffb507fULL, 0xfb507ffb507ffb50ULL, }, - { 0x17c26c17c26c17c2ULL, 0x6c17c26c17c26c17ULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x39e47f39e47f39e4ULL, 0x7f39e47f39e47f39ULL, }, - { 0x8e80e38e80e38e80ULL, 0xe38e80e38e80e38eULL, }, - { 0x17c26c17c26c17c2ULL, 0x6c17c26c17c26c17ULL, }, - { 0xb08005b08005b080ULL, 0x05b08005b08005b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc78071c78071c780ULL, 0x71c78071c78071c7ULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x727f1d727f1d727fULL, 0x1d727f1d727f1d72ULL, }, - { 0xc71c80c71c80c71cULL, 0x80c71c80c71c80c7ULL, }, - { 0x507ffb507ffb507fULL, 0xfb507ffb507ffb50ULL, }, - { 0xe93e94e93e94e93eULL, 0x94e93e94e93e94e9ULL, }, - { 0x397f8f397f8f397fULL, 0x8f397f8f397f8f39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8d7fe680db7f7f38ULL, 0x39705044e93c8010ULL, }, - { 0xdc1038226f7f7f7fULL, 0x247f455f53508bf8ULL, }, - { 0x801bd080ca3173f2ULL, 0x7f767f7f5539ce6cULL, }, - { 0x73801a7f258080c8ULL, 0xc790b0bc17c47ff0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f80527f7fc43c7fULL, 0xeb1ff51b6a142de8ULL, }, - { 0x8b80ea16ef80e5baULL, 0x7f0633426cfd705cULL, }, - { 0x24f0c8de91808080ULL, 0xdc80bba1adb07508ULL, }, /* 72 */ - { 0xb17fae80803cc480ULL, 0x15e10be596ecd318ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x800b9880809ea980ULL, 0x7fe73e2702e94374ULL, }, - { 0x7fe5307f36cf8d0eULL, 0x808a8080abc73294ULL, }, - { 0x757f16ea117f1b46ULL, 0x80facdbe940390a4ULL, }, - { 0x7ff5687f7f62577fULL, 0x8019c2d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_d.c deleted file mode 100644 index 546c24c5c292..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x8000000000000000ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x7fffffffffffffffULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e93e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x7fffffffffffffffULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0x8000000000000000ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e93e93e93e9ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace668dace8e38ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038216e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0x8000000000000000ULL, 0x7fffffffffffffffULL, }, - { 0x73531997253171c8ULL, 0xc790afbb16c3a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0xeb1ef41a6a142de8ULL, }, - { 0x8b6eea15ef61e4baULL, 0x7fffffffffffffffULL, }, - { 0x23efc7de916d3640ULL, 0xdc71bba0acaf7508ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000000000000ULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x8000000000000000ULL, }, - { 0x749115ea109e1b46ULL, 0x8000000000000000ULL, }, - { 0x7fffffffffffffffULL, 0x8000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_h.c deleted file mode 100644 index 24ddc826c348..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xc71c80001c72c71cULL, 0x80001c72c71c8000ULL, }, - { 0x8e39e38e80008e39ULL, 0xe38e80008e39e38eULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c727fff71c7ULL, 0x1c727fff71c71c72ULL, }, - { 0x38e47fffe38e38e4ULL, 0x7fffe38e38e47fffULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e94e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0xb05b05b08000b05bULL, 0x05b08000b05b05b0ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa5fa507fff4fa5ULL, 0xfa507fff4fa5fa50ULL, }, - { 0x16c26c17c16c16c2ULL, 0x6c17c16c16c26c17ULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e47fffe38e38e4ULL, 0x7fffe38e38e47fffULL, }, - { 0x8e39e38e80008e39ULL, 0xe38e80008e39e38eULL, }, - { 0x16c26c17c16c16c2ULL, 0x6c17c16c16c26c17ULL, }, - { 0xb05b05b08000b05bULL, 0x05b08000b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d71c78000c71dULL, 0x71c78000c71d71c7ULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c727fff71c7ULL, 0x1c727fff71c71c72ULL, }, - { 0xc71c80001c72c71cULL, 0x80001c72c71c8000ULL, }, - { 0x4fa5fa507fff4fa5ULL, 0xfa507fff4fa5fa50ULL, }, - { 0xe93e93e93e94e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0x38e38e397fff38e3ULL, 0x8e397fff38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace669dacf7fffULL, 0x38705044e93c8000ULL, }, - { 0xdc1038226e937fffULL, 0x238f445f53508af8ULL, }, - { 0x8000d07fca3172f2ULL, 0x7fff7fff5539cd6cULL, }, - { 0x7354199725318000ULL, 0xc790afbc16c47fffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6451b97fff3b88ULL, 0xeb1ff41b6a142de8ULL, }, - { 0x8b6fea16ef62e4baULL, 0x7fff32426bfd705cULL, }, - { 0x23f0c7de916d8000ULL, 0xdc71bba1acb07508ULL, }, /* 72 */ - { 0xb09cae478000c478ULL, 0x14e10be595ecd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000985d8000a932ULL, 0x7fff3e2701e94274ULL, }, - { 0x7fff2f8135cf8d0eULL, 0x80008000aac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x8000cdbe94038fa4ULL, }, - { 0x7fff67a37fff56ceULL, 0x8000c1d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_w.c deleted file mode 100644 index f6109a53316d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x80000000c71c71c7ULL, }, - { 0x8e38e38e80000000ULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c727fffffffULL, 0x1c71c71d71c71c72ULL, }, - { 0x38e38e39e38e38e4ULL, 0x7fffffff38e38e39ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0xb05b05b080000000ULL, 0x05b05b05b05b05b0ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa507fffffffULL, 0xfa4fa4fb4fa4fa50ULL, }, - { 0x16c16c17c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e39e38e38e4ULL, 0x7fffffff38e38e39ULL, }, - { 0x8e38e38e80000000ULL, 0xe38e38e38e38e38eULL, }, - { 0x16c16c17c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xb05b05b080000000ULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c780000000ULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c727fffffffULL, 0x1c71c71d71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0x80000000c71c71c7ULL, }, - { 0x4fa4fa507fffffffULL, 0xfa4fa4fb4fa4fa50ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0x38e38e397fffffffULL, 0x8e38e38f38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace669dace8e38ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038226e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0x80000000ca3072f2ULL, 0x7fffffff5538cd6cULL, }, - { 0x73531997253171c8ULL, 0xc790afbc16c3a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b97fffffffULL, 0xeb1ef41b6a142de8ULL, }, - { 0x8b6eea16ef61e4baULL, 0x7fffffff6bfc705cULL, }, - { 0x23efc7de916d3640ULL, 0xdc71bba1acaf7508ULL, }, /* 72 */ - { 0xb09cae4780000000ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000080000000ULL, 0x7fffffff01e84274ULL, }, - { 0x7fffffff35cf8d0eULL, 0x80000000aac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x8000000094038fa4ULL, }, - { 0x7fffffff7fffffffULL, 0x80000000fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_b.c deleted file mode 100644 index f17091234879..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x001c72001c72001cULL, 0x72001c72001c7200ULL, }, - { 0x8e39008e39008e39ULL, 0x008e39008e39008eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x00001d00001d0000ULL, 0x1d00001d00001d00ULL, }, - { 0x3900003900003900ULL, 0x0039000039000039ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x003e94003e94003eULL, 0x94003e94003e9400ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1700001700001700ULL, 0x0017000017000017ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x3900003900003900ULL, 0x0039000039000039ULL, }, - { 0x8e39008e39008e39ULL, 0x008e39008e39008eULL, }, - { 0x1700001700001700ULL, 0x0017000017000017ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d00c71d00c71dULL, 0x00c71d00c71d00c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00001d00001d0000ULL, 0x1d00001d00001d00ULL, }, - { 0x001c72001c72001cULL, 0x72001c72001c7200ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x003e94003e94003eULL, 0x94003e94003e9400ULL, }, - { 0x00008f00008f0000ULL, 0x8f00008f00008f00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x0000e66900000038ULL, 0x39000044e93c5e00ULL, }, - { 0x0010382200000000ULL, 0x2400000053508b00ULL, }, - { 0x181bd07f00310000ULL, 0x0000000055390000ULL, }, - { 0x7354000025317200ULL, 0x0090b000000000f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f64000000003c00ULL, 0x001f000000142de8ULL, }, - { 0x8b6f001600620000ULL, 0x000633000000005cULL, }, - { 0x24000000916d3640ULL, 0x0071bba100000008ULL, }, /* 72 */ - { 0x0000ae476c3c0078ULL, 0x15000be596000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9e0032ULL, 0x00003e2702000000ULL, }, - { 0x0000000036008d0eULL, 0x428a7d7a00003294ULL, }, - { 0x0000160011001b46ULL, 0x7b0000be94039000ULL, }, - { 0x0000000000005700ULL, 0x661900000017bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_d.c deleted file mode 100644 index bf647db22136..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x71c71c71c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x0000000000000000ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x0000000000000000ULL, 0x93e93e93e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x16c16c16c16c16c2ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e38e38e39ULL, 0x0000000000000000ULL, }, - { 0x16c16c16c16c16c2ULL, 0x0000000000000000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x1c71c71c71c71c72ULL, }, - { 0x0000000000000000ULL, 0x71c71c71c71c71c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x93e93e93e93e93e9ULL, }, - { 0x0000000000000000ULL, 0x8e38e38e38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x386f5044e93c5d10ULL, }, - { 0x0000000000000000ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07eca3072f2ULL, 0x0000000000000000ULL, }, - { 0x73531997253171c8ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0x0000000000000000ULL, }, - { 0x8b6eea15ef61e4baULL, 0x0000000000000000ULL, }, - { 0x23efc7de916d3640ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x428a7d79aac73294ULL, }, - { 0x0000000000000000ULL, 0x7af9cdbe94038fa4ULL, }, - { 0x0000000000000000ULL, 0x6618c1d8fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_h.c deleted file mode 100644 index c4616be3e95d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x000071c71c720000ULL, 0x71c71c72000071c7ULL, }, - { 0x8e39000038e38e39ULL, 0x000038e38e390000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x00001c7200000000ULL, 0x1c72000000001c72ULL, }, - { 0x38e40000000038e4ULL, 0x0000000038e40000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x000093e93e940000ULL, 0x93e93e94000093e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x16c20000000016c2ULL, 0x0000000016c20000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e40000000038e4ULL, 0x0000000038e40000ULL, }, - { 0x8e39000038e38e39ULL, 0x000038e38e390000ULL, }, - { 0x16c20000000016c2ULL, 0x0000000016c20000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d00001c71c71dULL, 0x00001c71c71d0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00001c7200000000ULL, 0x1c72000000001c72ULL, }, - { 0x000071c71c720000ULL, 0x71c71c72000071c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000093e93e940000ULL, 0x93e93e94000093e9ULL, }, - { 0x00008e3900000000ULL, 0x8e39000000008e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x0000e66900000000ULL, 0x38700000e93c5d10ULL, }, - { 0x0000382200000000ULL, 0x238f000053508af8ULL, }, - { 0x181bd07f00000000ULL, 0x0000000055390000ULL, }, - { 0x73540000253171c8ULL, 0x0000afbc00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f64000000003b88ULL, 0x0000000000002de8ULL, }, - { 0x8b6f000000000000ULL, 0x0000324200000000ULL, }, - { 0x23f00000916d3640ULL, 0x0000bba100000000ULL, }, /* 72 */ - { 0x0000ae476c3c0000ULL, 0x14e10be595ec0000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9e0000ULL, 0x00003e2701e90000ULL, }, - { 0x0000000035cf8d0eULL, 0x428a7d7a00003294ULL, }, - { 0x000015ea109e1b46ULL, 0x7afa000094038fa4ULL, }, - { 0x00000000000056ceULL, 0x661900000000bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_w.c deleted file mode 100644 index 61052672cae9..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subs_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBS_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBS_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x000000001c71c71cULL, 0x71c71c7200000000ULL, }, - { 0x8e38e38e38e38e39ULL, 0x000000008e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x0000000000000000ULL, 0x1c71c71d00000000ULL, }, - { 0x38e38e3900000000ULL, 0x0000000038e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x000000003e93e93eULL, 0x93e93e9400000000ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x16c16c1700000000ULL, 0x0000000016c16c17ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e3900000000ULL, 0x0000000038e38e39ULL, }, - { 0x8e38e38e38e38e39ULL, 0x000000008e38e38eULL, }, - { 0x16c16c1700000000ULL, 0x0000000016c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x00000000c71c71c7ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x1c71c71d00000000ULL, }, - { 0x000000001c71c71cULL, 0x71c71c7200000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x000000003e93e93eULL, 0x93e93e9400000000ULL, }, - { 0x0000000000000000ULL, 0x8e38e38f00000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x386f5044e93c5d10ULL, }, - { 0x0000000000000000ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07f00000000ULL, 0x000000005538cd6cULL, }, - { 0x73531997253171c8ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b900000000ULL, 0x0000000000000000ULL, }, - { 0x8b6eea1600000000ULL, 0x0000000000000000ULL, }, - { 0x23efc7de916d3640ULL, 0x0000000000000000ULL, }, /* 72 */ - { 0x000000006c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x0000000001e84274ULL, }, - { 0x0000000035cf8d0eULL, 0x428a7d7a00000000ULL, }, - { 0x00000000109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0x0000000000000000ULL, 0x6618c1d900000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBS_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_b.c deleted file mode 100644 index 71ea14fa2d70..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUS_U.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUS_U.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffc7ffffc7ffffULL, 0xc7ffffc7ffffc7ffULL, }, - { 0xe38effe38effe38eULL, 0xffe38effe38effe3ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1d72001d72001d72ULL, 0x001d72001d72001dULL, }, - { 0x0000390000390000ULL, 0x3900003900003900ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc7ff72c7ff72c7ffULL, 0x72c7ff72c7ff72c7ULL, }, - { 0x8e39e38e39e38e39ULL, 0xe38e39e38e39e38eULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0x39008e39008e3900ULL, 0x8e39008e39008e39ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe9ff94e9ff94e9ffULL, 0x94e9ff94e9ff94e9ULL, }, - { 0xb05bffb05bffb05bULL, 0xffb05bffb05bffb0ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x50a50050a50050a5ULL, 0x0050a50050a50050ULL, }, - { 0x17006c17006c1700ULL, 0x6c17006c17006c17ULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffe48effe48effe4ULL, 0x8effe48effe48effULL, }, - { 0x8e39008e39008e39ULL, 0x008e39008e39008eULL, }, - { 0xffc26cffc26cffc2ULL, 0x6cffc26cffc26cffULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, - { 0xc71d71c71d71c71dULL, 0x71c71d71c71d71c7ULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x72c7ff72c7ff72c7ULL, 0xff72c7ff72c7ff72ULL, }, - { 0x001c72001c72001cULL, 0x72001c72001c7200ULL, }, - { 0x50a5fb50a5fb50a5ULL, 0xfb50a5fb50a5fb50ULL, }, - { 0x003e94003e94003eULL, 0x94003e94003e9400ULL, }, - { 0x39e38f39e38f39e3ULL, 0x8f39e38f39e38f39ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0xff00ffff00000000ULL, 0x00000000ff00ff00ULL, }, /* 64 */ - { 0x8dace66900cf8e38ULL, 0x39705044e93c5e10ULL, }, - { 0xdc10ffff6f93cac0ULL, 0x248f455fff508b00ULL, }, - { 0x181bd07f00317300ULL, 0xbe768386ff39ce6cULL, }, - { 0xff541a9725317200ULL, 0x0090b0001700a2f0ULL, }, - { 0xffff000000ffff00ULL, 0x00ffff00000000ffULL, }, - { 0xff6452b994c4ff88ULL, 0x00fff51b6a142de8ULL, }, - { 0x8b6f00160062e500ULL, 0x85ffff426c0070ffULL, }, - { 0xff00c8de916d3640ULL, 0x0071bba1ad007508ULL, }, /* 72 */ - { 0xb19cae476cffc478ULL, 0x15e1ffe596000018ULL, }, - { 0xff00ffffffffffffULL, 0x00ffffffff000000ULL, }, - { 0x3c0b985d5b9ea932ULL, 0x9ae7ffffff004374ULL, }, - { 0xe800308136008d0eULL, 0x428a7d7aab00ff94ULL, }, - { 0x75911600119eff46ULL, 0x7bfacdbe940390a4ULL, }, - { 0xc40068a3a562ffceULL, 0x66ffc2d9fe17bd8cULL, }, - { 0x000000000000ff00ULL, 0xffffffffff00ffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_d.c deleted file mode 100644 index 070c457c447a..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUS_U.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUS_U.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c72ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x38e38e38e38e38e4ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e93e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0xffffffffffffffffULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0x0000000000000000ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0x8e38e38e38e38e39ULL, }, - { 0x8e38e38e38e38e39ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x6c16c16c16c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c71c71c71c7ULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x71c71c71c71c71c7ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0x0000000000000000ULL, 0x93e93e93e93e93e9ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace668dace8e38ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038216e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07eca3072f2ULL, 0xbd7582865538cd6cULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x8b6eea15ef61e4baULL, 0x850632416bfc705cULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0x428a7d79aac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0xc3f467a2a46256ceULL, 0x6618c1d8fe17bd8cULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_h.c deleted file mode 100644 index f98d010436cb..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUS_U.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUS_U.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffc71cffffffffULL, 0xc71cffffffffc71cULL, }, - { 0xe38effff8e38e38eULL, 0xffff8e38e38effffULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c72000071c81c72ULL, 0x000071c81c720000ULL, }, - { 0x000038e400000000ULL, 0x38e40000000038e4ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c7ffffc71cULL, 0x71c7ffffc71c71c7ULL, }, - { 0x8e39e38e38e38e39ULL, 0xe38e38e38e39e38eULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0x38e48e39000038e4ULL, 0x8e39000038e48e39ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e9ffffe93eULL, 0x93e9ffffe93e93e9ULL, }, - { 0xb05bffff5b05b05bULL, 0xffff5b05b05bffffULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa50000a4fb4fa5ULL, 0x0000a4fb4fa50000ULL, }, - { 0x16c26c17000016c2ULL, 0x6c17000016c26c17ULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffff8e39e38effffULL, 0x8e39e38effff8e39ULL, }, - { 0x8e39000038e38e39ULL, 0x000038e38e390000ULL, }, - { 0xffff6c17c16cffffULL, 0x6c17c16cffff6c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, - { 0xc71d71c71c71c71dULL, 0x71c71c71c71d71c7ULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c7ffffc71d71c7ULL, 0xffffc71d71c7ffffULL, }, - { 0x000071c71c720000ULL, 0x71c71c72000071c7ULL, }, - { 0x4fa5fa50a4fb4fa5ULL, 0xfa50a4fb4fa5fa50ULL, }, - { 0x000093e93e940000ULL, 0x93e93e94000093e9ULL, }, - { 0x38e38e39e38f38e3ULL, 0x8e39e38f38e38e39ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, /* 64 */ - { 0x8cace66900008e38ULL, 0x38705044e93c5d10ULL, }, - { 0xdc10ffff6e93c9c0ULL, 0x238f445fffff8af8ULL, }, - { 0x181bd07f000072f2ULL, 0xbd768286ffffcd6cULL, }, - { 0xffff1997253171c8ULL, 0x0000afbc16c4a2f0ULL, }, - { 0xffff00000000ffffULL, 0x0000ffff00000000ULL, }, - { 0xffff51b993c4ffffULL, 0x0000f41b6a142de8ULL, }, - { 0x8b6f00000000e4baULL, 0x8506ffff6bfd705cULL, }, - { 0xffffc7de916d3640ULL, 0x0000bba1acb07508ULL, }, /* 72 */ - { 0xb09cae476c3cc478ULL, 0x14e1ffff95ec0000ULL, }, - { 0xffffffffffffffffULL, 0x0000ffffffff0000ULL, }, - { 0x3c0b985d5b9ea932ULL, 0x99e7ffffffff4274ULL, }, - { 0xe7e52f8135cf8d0eULL, 0x428a7d7aaac7ffffULL, }, - { 0x749115ea109effffULL, 0x7afacdbe94038fa4ULL, }, - { 0xc3f567a3a462ffffULL, 0x6619c1d9fe17bd8cULL, }, - { 0x000000000000ffffULL, 0xffffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_w.c deleted file mode 100644 index d325c19217d3..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsus_u_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUS_U.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUS_U.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xc71c71c7ffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71d71c71c72ULL, 0x000000001c71c71dULL, }, - { 0x0000000000000000ULL, 0x38e38e3900000000ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c7ffffffffULL, 0x71c71c72c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0x38e38e3900000000ULL, 0x8e38e38e38e38e39ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e9ffffffffULL, 0x93e93e94e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0xffffffffb05b05b0ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0x000000004fa4fa50ULL, }, - { 0x16c16c1700000000ULL, 0x6c16c16c16c16c17ULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffe38e38e4ULL, 0x8e38e38effffffffULL, }, - { 0x8e38e38e38e38e39ULL, 0x000000008e38e38eULL, }, - { 0xffffffffc16c16c2ULL, 0x6c16c16cffffffffULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0xc71c71c71c71c71dULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c72c71c71c7ULL, 0xffffffff71c71c72ULL, }, - { 0x000000001c71c71cULL, 0x71c71c7200000000ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0xfa4fa4fb4fa4fa50ULL, }, - { 0x000000003e93e93eULL, 0x93e93e9400000000ULL, }, - { 0x38e38e39e38e38e3ULL, 0x8e38e38f38e38e39ULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, /* 64 */ - { 0x8cace66900000000ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038226e92c9c0ULL, 0x238e445fffffffffULL, }, - { 0x181bd07f00000000ULL, 0xbd758286ffffffffULL, }, - { 0xffffffff253171c8ULL, 0x0000000016c3a2f0ULL, }, - { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, - { 0xffffffff93c43b88ULL, 0x000000006a142de8ULL, }, - { 0x8b6eea1600000000ULL, 0x850632426bfc705cULL, }, - { 0xffffffff916d3640ULL, 0x00000000acaf7508ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, - { 0x3c0b985d5b9da932ULL, 0x99e73e27ffffffffULL, }, - { 0xe7e42f8135cf8d0eULL, 0x428a7d7aaac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0xc3f467a3a46256ceULL, 0x6618c1d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUS_U_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_b.c deleted file mode 100644 index 66012b58941e..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUU_S.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUU_S.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x1c717f1c717f1c71ULL, 0x7f1c717f1c717f1cULL, }, - { 0x7f7f387f7f387f7fULL, 0x387f7f387f7f387fULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, - { 0x8080c88080c88080ULL, 0xc88080c88080c880ULL, }, - { 0xe48f80e48f80e48fULL, 0x80e48f80e48f80e4ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, /* 16 */ - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c72c71c72c71cULL, 0x72c71c72c71c72c7ULL, }, - { 0x7f39e37f39e37f39ULL, 0xe37f39e37f39e37fULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x80c71d80c71d80c7ULL, 0x1d80c71d80c71d80ULL, }, - { 0x39e48e39e48e39e4ULL, 0x8e39e48e39e48e39ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, /* 32 */ - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7f7f7f7f7f7f7f7fULL, 0x7f7f7f7f7f7f7f7fULL, }, - { 0xe93e7fe93e7fe93eULL, 0x7fe93e7fe93e7fe9ULL, }, - { 0x7f5b057f5b057f5bULL, 0x057f5b057f5b057fULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x80a5fb80a5fb80a5ULL, 0xfb80a5fb80a5fb80ULL, }, - { 0x17c28017c28017c2ULL, 0x8017c28017c28017ULL, }, - { 0xe48f80e48f80e48fULL, 0x80e48f80e48f80e4ULL, }, /* 48 */ - { 0x7f7f387f7f387f7fULL, 0x387f7f387f7f387fULL, }, - { 0x39e48e39e48e39e4ULL, 0x8e39e48e39e48e39ULL, }, - { 0x7f39e37f39e37f39ULL, 0xe37f39e37f39e37fULL, }, - { 0x17c28017c28017c2ULL, 0x8017c28017c28017ULL, }, - { 0x7f5b057f5b057f5bULL, 0x057f5b057f5b057fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7f1d807f1d807f1dULL, 0x807f1d807f1d807fULL, }, - { 0x8080c88080c88080ULL, 0xc88080c88080c880ULL, }, /* 56 */ - { 0x1c717f1c717f1c71ULL, 0x7f1c717f1c717f1cULL, }, - { 0x80c71d80c71d80c7ULL, 0x1d80c71d80c71d80ULL, }, - { 0xc71c72c71c72c71cULL, 0x72c71c72c71c72c7ULL, }, - { 0x80a5fb80a5fb80a5ULL, 0xfb80a5fb80a5fb80ULL, }, - { 0xe93e7fe93e7fe93eULL, 0x7fe93e7fe93e7fe9ULL, }, - { 0x80e37f80e37f80e3ULL, 0x7f80e37f80e37f80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8dac7f69dbcf8e38ULL, 0x398080447f3c5e80ULL, }, - { 0xdc1038228093cac0ULL, 0x248f808053507ff8ULL, }, - { 0x181b7f7fca3180f2ULL, 0xbe8083865539ce80ULL, }, - { 0x73548097253172c8ULL, 0xc77f7fbc80c4a27fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6480b994c43c88ULL, 0xeb1ff58080142d7fULL, }, - { 0x7f6fea16ef62e5baULL, 0x8506338080fd805cULL, }, - { 0x24f0c8de7f6d3640ULL, 0xdc717f7fadb08008ULL, }, /* 72 */ - { 0xb19c7f476c3cc478ULL, 0x15e10b7f7fecd380ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b7f5d5b7fa932ULL, 0x9ae73e2702e98080ULL, }, - { 0xe8e5808136cf7f0eULL, 0x427f7d7aabc7327fULL, }, - { 0x809116ea119e1b46ULL, 0x7bfacd7f7f037fa4ULL, }, - { 0xc4f580a3a58057ceULL, 0x6619c2d9fe177f7fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_d.c deleted file mode 100644 index 344a3730552d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUU_S.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUU_S.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, - { 0x8000000000000000ULL, 0xc71c71c71c71c71dULL, }, - { 0xe38e38e38e38e38fULL, 0x8000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, /* 16 */ - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x7fffffffffffffffULL, 0xe38e38e38e38e38eULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8000000000000000ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, /* 32 */ - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fffffffffffffffULL, 0x7fffffffffffffffULL, }, - { 0xe93e93e93e93e93eULL, 0x7fffffffffffffffULL, }, - { 0x7fffffffffffffffULL, 0x05b05b05b05b05b0ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000000000000ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0x16c16c16c16c16c2ULL, 0x8000000000000000ULL, }, - { 0xe38e38e38e38e38fULL, 0x8000000000000000ULL, }, /* 48 */ - { 0x7fffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x7fffffffffffffffULL, 0xe38e38e38e38e38eULL, }, - { 0x16c16c16c16c16c2ULL, 0x8000000000000000ULL, }, - { 0x7fffffffffffffffULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fffffffffffffffULL, 0x8000000000000000ULL, }, - { 0x8000000000000000ULL, 0xc71c71c71c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x7fffffffffffffffULL, }, - { 0x8000000000000000ULL, 0x1c71c71c71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x8000000000000000ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0xe93e93e93e93e93eULL, 0x7fffffffffffffffULL, }, - { 0x8000000000000000ULL, 0x7fffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace668dace8e38ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038216e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07eca3072f2ULL, 0xbd7582865538cd6cULL, }, - { 0x73531997253171c8ULL, 0xc790afbb16c3a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0xeb1ef41a6a142de8ULL, }, - { 0x7fffffffffffffffULL, 0x850632416bfc705cULL, }, - { 0x23efc7de916d3640ULL, 0xdc71bba0acaf7508ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0x428a7d79aac73294ULL, }, - { 0x8000000000000000ULL, 0x7af9cdbe94038fa4ULL, }, - { 0xc3f467a2a46256ceULL, 0x6618c1d8fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_h.c deleted file mode 100644 index 1cacb2639512..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUU_S.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUU_S.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x1c717fff71c71c71ULL, 0x7fff71c71c717fffULL, }, - { 0x7fff38e37fff7fffULL, 0x38e37fff7fff38e3ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, - { 0x8000c71d80008000ULL, 0xc71d80008000c71dULL, }, - { 0xe38f80008e39e38fULL, 0x80008e39e38f8000ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, /* 16 */ - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c72c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x7fffe38e38e37fffULL, 0xe38e38e37fffe38eULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x80001c72c71d8000ULL, 0x1c72c71d80001c72ULL, }, - { 0x38e48e39e38e38e4ULL, 0x8e39e38e38e48e39ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, /* 32 */ - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fff7fff7fff7fffULL, 0x7fff7fff7fff7fffULL, }, - { 0xe93e7fff3e94e93eULL, 0x7fff3e94e93e7fffULL, }, - { 0x7fff05b05b057fffULL, 0x05b05b057fff05b0ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000fa50a4fb8000ULL, 0xfa50a4fb8000fa50ULL, }, - { 0x16c28000c16c16c2ULL, 0x8000c16c16c28000ULL, }, - { 0xe38f80008e39e38fULL, 0x80008e39e38f8000ULL, }, /* 48 */ - { 0x7fff38e37fff7fffULL, 0x38e37fff7fff38e3ULL, }, - { 0x38e48e39e38e38e4ULL, 0x8e39e38e38e48e39ULL, }, - { 0x7fffe38e38e37fffULL, 0xe38e38e37fffe38eULL, }, - { 0x16c28000c16c16c2ULL, 0x8000c16c16c28000ULL, }, - { 0x7fff05b05b057fffULL, 0x05b05b057fff05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fff80001c717fffULL, 0x80001c717fff8000ULL, }, - { 0x8000c71d80008000ULL, 0xc71d80008000c71dULL, }, /* 56 */ - { 0x1c717fff71c71c71ULL, 0x7fff71c71c717fffULL, }, - { 0x80001c72c71d8000ULL, 0x1c72c71d80001c72ULL, }, - { 0xc71c71c71c72c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x8000fa50a4fb8000ULL, 0xfa50a4fb8000fa50ULL, }, - { 0xe93e7fff3e94e93eULL, 0x7fff3e94e93e7fffULL, }, - { 0x80007fffe38f8000ULL, 0x7fffe38f80007fffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cac7fffdacf8e38ULL, 0x387080007fff5d10ULL, }, - { 0xdc1038228000c9c0ULL, 0x238f800053507fffULL, }, - { 0x181b7fffca318000ULL, 0xbd7682865539cd6cULL, }, - { 0x73548000253171c8ULL, 0xc7907fff8000a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f64800093c43b88ULL, 0xeb1ff41b80002de8ULL, }, - { 0x7fffea16ef62e4baULL, 0x8506324280008000ULL, }, - { 0x23f0c7de7fff3640ULL, 0xdc717fffacb08000ULL, }, /* 72 */ - { 0xb09c7fff6c3cc478ULL, 0x14e10be57fffd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b7fff5b9ea932ULL, 0x99e73e2701e98000ULL, }, - { 0xe7e5800035cf7fffULL, 0x428a7d7aaac73294ULL, }, - { 0x800015ea109e1b46ULL, 0x7afacdbe7fff7fffULL, }, - { 0xc3f58000a46256ceULL, 0x6619c1d9fe177fffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_w.c deleted file mode 100644 index 42f3ee56f620..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subsuu_s_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBSUU_S.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBSUU_S.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0x7fffffff1c71c71cULL, }, - { 0x7fffffff7fffffffULL, 0x38e38e387fffffffULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, - { 0x8000000080000000ULL, 0xc71c71c880000000ULL, }, - { 0xe38e38e48e38e38fULL, 0x80000000e38e38e4ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, /* 16 */ - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x7fffffff38e38e39ULL, 0xe38e38e37fffffffULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x80000000c71c71c7ULL, 0x1c71c71d80000000ULL, }, - { 0x38e38e39e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, /* 32 */ - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fffffff7fffffffULL, 0x7fffffff7fffffffULL, }, - { 0xe93e93e93e93e93eULL, 0x7fffffffe93e93e9ULL, }, - { 0x7fffffff5b05b05bULL, 0x05b05b057fffffffULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x80000000a4fa4fa5ULL, 0xfa4fa4fb80000000ULL, }, - { 0x16c16c17c16c16c2ULL, 0x8000000016c16c17ULL, }, - { 0xe38e38e48e38e38fULL, 0x80000000e38e38e4ULL, }, /* 48 */ - { 0x7fffffff7fffffffULL, 0x38e38e387fffffffULL, }, - { 0x38e38e39e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x7fffffff38e38e39ULL, 0xe38e38e37fffffffULL, }, - { 0x16c16c17c16c16c2ULL, 0x8000000016c16c17ULL, }, - { 0x7fffffff5b05b05bULL, 0x05b05b057fffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x7fffffff1c71c71dULL, 0x800000007fffffffULL, }, - { 0x8000000080000000ULL, 0xc71c71c880000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0x7fffffff1c71c71cULL, }, - { 0x80000000c71c71c7ULL, 0x1c71c71d80000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x80000000a4fa4fa5ULL, 0xfa4fa4fb80000000ULL, }, - { 0xe93e93e93e93e93eULL, 0x7fffffffe93e93e9ULL, }, - { 0x80000000e38e38e3ULL, 0x7fffffff80000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace669dace8e38ULL, 0x386f50447fffffffULL, }, - { 0xdc10382280000000ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07fca3072f2ULL, 0xbd7582865538cd6cULL, }, - { 0x73531997253171c8ULL, 0xc790afbc80000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b993c43b88ULL, 0xeb1ef41b80000000ULL, }, - { 0x7fffffffef61e4baULL, 0x8506324280000000ULL, }, - { 0x23efc7de7fffffffULL, 0xdc71bba1acaf7508ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be57fffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0x428a7d7aaac73294ULL, }, - { 0x80000000109e1b46ULL, 0x7af9cdbe7fffffffULL, }, - { 0xc3f467a3a46256ceULL, 0x6618c1d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBSUU_S_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_b.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_b.c deleted file mode 100644 index b8bd0855160d..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_b.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c72c71c72c71cULL, 0x72c71c72c71c72c7ULL, }, - { 0x8e39e38e39e38e39ULL, 0xe38e39e38e39e38eULL, }, - { 0x5656565656565656ULL, 0x5656565656565656ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xababababababababULL, 0xababababababababULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0x39e48e39e48e39e4ULL, 0x8e39e48e39e48e39ULL, }, - { 0xcdcdcdcdcdcdcdcdULL, 0xcdcdcdcdcdcdcdcdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e94e93e94e93eULL, 0x94e93e94e93e94e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x3434343434343434ULL, 0x3434343434343434ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8989898989898989ULL, 0x8989898989898989ULL, }, - { 0xdedededededededeULL, 0xdedededededededeULL, }, - { 0x6767676767676767ULL, 0x6767676767676767ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x50a5fb50a5fb50a5ULL, 0xfb50a5fb50a5fb50ULL, }, - { 0x17c26c17c26c17c2ULL, 0x6c17c26c17c26c17ULL, }, - { 0xe48f39e48f39e48fULL, 0x39e48f39e48f39e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x39e48e39e48e39e4ULL, 0x8e39e48e39e48e39ULL, }, - { 0x8e39e38e39e38e39ULL, 0xe38e39e38e39e38eULL, }, - { 0x17c26c17c26c17c2ULL, 0x6c17c26c17c26c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d71c71d71c71dULL, 0x71c71d71c71d71c7ULL, }, - { 0x1d72c81d72c81d72ULL, 0xc81d72c81d72c81dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x72c71d72c71d72c7ULL, 0x1d72c71d72c71d72ULL, }, - { 0xc71c72c71c72c71cULL, 0x72c71c72c71c72c7ULL, }, - { 0x50a5fb50a5fb50a5ULL, 0xfb50a5fb50a5fb50ULL, }, - { 0xe93e94e93e94e93eULL, 0x94e93e94e93e94e9ULL, }, - { 0x39e38f39e38f39e3ULL, 0x8f39e38f39e38f39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8dace669dbcf8e38ULL, 0x39705044e93c5e10ULL, }, - { 0xdc1038226f93cac0ULL, 0x248f455f53508bf8ULL, }, - { 0x181bd07fca3173f2ULL, 0xbe7683865539ce6cULL, }, - { 0x73541a97253172c8ULL, 0xc790b0bc17c4a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6452b994c43c88ULL, 0xeb1ff51b6a142de8ULL, }, - { 0x8b6fea16ef62e5baULL, 0x850633426cfd705cULL, }, - { 0x24f0c8de916d3640ULL, 0xdc71bba1adb07508ULL, }, /* 72 */ - { 0xb19cae476c3cc478ULL, 0x15e10be596ecd318ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9ea932ULL, 0x9ae73e2702e94374ULL, }, - { 0xe8e5308136cf8d0eULL, 0x428a7d7aabc73294ULL, }, - { 0x759116ea119e1b46ULL, 0x7bfacdbe940390a4ULL, }, - { 0xc4f568a3a56257ceULL, 0x6619c2d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_d.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_d.c deleted file mode 100644 index f532e4a69d4f..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_d.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555556ULL, 0x5555555555555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaabULL, 0xaaaaaaaaaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0xcccccccccccccccdULL, 0xcccccccccccccccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e93e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x3333333333333334ULL, 0x3333333333333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888888888889ULL, 0x8888888888888889ULL, }, - { 0xdddddddddddddddeULL, 0xdddddddddddddddeULL, }, - { 0x6666666666666667ULL, 0x6666666666666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xe38e38e38e38e38fULL, 0x38e38e38e38e38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x16c16c16c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71c71c71c72ULL, 0xc71c71c71c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c71c71c71c7ULL, 0x1c71c71c71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c71c71c71c7ULL, }, - { 0x4fa4fa4fa4fa4fa5ULL, 0xfa4fa4fa4fa4fa50ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e93e93e93e9ULL, }, - { 0x38e38e38e38e38e3ULL, 0x8e38e38e38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace668dace8e38ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038216e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07eca3072f2ULL, 0xbd7582865538cd6cULL, }, - { 0x73531997253171c8ULL, 0xc790afbb16c3a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b893c43b88ULL, 0xeb1ef41a6a142de8ULL, }, - { 0x8b6eea15ef61e4baULL, 0x850632416bfc705cULL, }, - { 0x23efc7de916d3640ULL, 0xdc71bba0acaf7508ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0x428a7d79aac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0xc3f467a2a46256ceULL, 0x6618c1d8fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_h.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_h.c deleted file mode 100644 index ac7f8ee6b5f1..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_h.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c72c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x8e39e38e38e38e39ULL, 0xe38e38e38e39e38eULL, }, - { 0x5556555655565556ULL, 0x5556555655565556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaabaaabaaabaaabULL, 0xaaabaaabaaabaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0x38e48e39e38e38e4ULL, 0x8e39e38e38e48e39ULL, }, - { 0xcccdcccdcccdcccdULL, 0xcccdcccdcccdcccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e94e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x3334333433343334ULL, 0x3334333433343334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8889888988898889ULL, 0x8889888988898889ULL, }, - { 0xdddedddedddedddeULL, 0xdddedddedddedddeULL, }, - { 0x6667666766676667ULL, 0x6667666766676667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa5fa50a4fb4fa5ULL, 0xfa50a4fb4fa5fa50ULL, }, - { 0x16c26c17c16c16c2ULL, 0x6c17c16c16c26c17ULL, }, - { 0xe38f38e48e39e38fULL, 0x38e48e39e38f38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e48e39e38e38e4ULL, 0x8e39e38e38e48e39ULL, }, - { 0x8e39e38e38e38e39ULL, 0xe38e38e38e39e38eULL, }, - { 0x16c26c17c16c16c2ULL, 0x6c17c16c16c26c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71d71c71c71c71dULL, 0x71c71c71c71d71c7ULL, }, - { 0x1c72c71d71c81c72ULL, 0xc71d71c81c72c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c72c71d71c7ULL, 0x1c72c71d71c71c72ULL, }, - { 0xc71c71c71c72c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x4fa5fa50a4fb4fa5ULL, 0xfa50a4fb4fa5fa50ULL, }, - { 0xe93e93e93e94e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0x38e38e39e38f38e3ULL, 0x8e39e38f38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace669dacf8e38ULL, 0x38705044e93c5d10ULL, }, - { 0xdc1038226e93c9c0ULL, 0x238f445f53508af8ULL, }, - { 0x181bd07fca3172f2ULL, 0xbd7682865539cd6cULL, }, - { 0x73541997253171c8ULL, 0xc790afbc16c4a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6451b993c43b88ULL, 0xeb1ff41b6a142de8ULL, }, - { 0x8b6fea16ef62e4baULL, 0x850632426bfd705cULL, }, - { 0x23f0c7de916d3640ULL, 0xdc71bba1acb07508ULL, }, /* 72 */ - { 0xb09cae476c3cc478ULL, 0x14e10be595ecd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9ea932ULL, 0x99e73e2701e94274ULL, }, - { 0xe7e52f8135cf8d0eULL, 0x428a7d7aaac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x7afacdbe94038fa4ULL, }, - { 0xc3f567a3a46256ceULL, 0x6619c1d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_w.c b/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_w.c deleted file mode 100644 index 93eeaecc7ce7..000000000000 --- a/tests/tcg/mips/user/ase/msa/int-subtract/test_msa_subv_w.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Test program for MSA instruction SUBV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * Copyright (C) 2019 RT-RK Computer Based Systems LLC - * Copyright (C) 2019 Mateja Marjanovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Int Subtract"; - char *instruction_name = "SUBV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555655555556ULL, 0x5555555655555556ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaabaaaaaaabULL, 0xaaaaaaabaaaaaaabULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0x38e38e39e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0xcccccccdcccccccdULL, 0xcccccccdcccccccdULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x3333333433333334ULL, 0x3333333433333334ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8888888988888889ULL, 0x8888888988888889ULL, }, - { 0xdddddddedddddddeULL, 0xdddddddedddddddeULL, }, - { 0x6666666766666667ULL, 0x6666666766666667ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0xfa4fa4fb4fa4fa50ULL, }, - { 0x16c16c17c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xe38e38e48e38e38fULL, 0x38e38e39e38e38e4ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e39e38e38e4ULL, 0x8e38e38e38e38e39ULL, }, - { 0x8e38e38e38e38e39ULL, 0xe38e38e38e38e38eULL, }, - { 0x16c16c17c16c16c2ULL, 0x6c16c16c16c16c17ULL, }, - { 0xb05b05b05b05b05bULL, 0x05b05b05b05b05b0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71dULL, 0x71c71c71c71c71c7ULL, }, - { 0x1c71c71d71c71c72ULL, 0xc71c71c81c71c71dULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x71c71c72c71c71c7ULL, 0x1c71c71d71c71c72ULL, }, - { 0xc71c71c71c71c71cULL, 0x71c71c72c71c71c7ULL, }, - { 0x4fa4fa50a4fa4fa5ULL, 0xfa4fa4fb4fa4fa50ULL, }, - { 0xe93e93e93e93e93eULL, 0x93e93e94e93e93e9ULL, }, - { 0x38e38e39e38e38e3ULL, 0x8e38e38f38e38e39ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x8cace669dace8e38ULL, 0x386f5044e93c5d10ULL, }, - { 0xdc1038226e92c9c0ULL, 0x238e445f53508af8ULL, }, - { 0x181bd07fca3072f2ULL, 0xbd7582865538cd6cULL, }, - { 0x73531997253171c8ULL, 0xc790afbc16c3a2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4f6351b993c43b88ULL, 0xeb1ef41b6a142de8ULL, }, - { 0x8b6eea16ef61e4baULL, 0x850632426bfc705cULL, }, - { 0x23efc7de916d3640ULL, 0xdc71bba1acaf7508ULL, }, /* 72 */ - { 0xb09cae476c3bc478ULL, 0x14e10be595ebd218ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3c0b985d5b9da932ULL, 0x99e73e2701e84274ULL, }, - { 0xe7e42f8135cf8d0eULL, 0x428a7d7aaac73294ULL, }, - { 0x749115ea109e1b46ULL, 0x7af9cdbe94038fa4ULL, }, - { 0xc3f467a3a46256ceULL, 0x6618c1d9fe17bd8cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, -}; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SUBV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_b.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_b.c deleted file mode 100644 index 3506202cd955..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVEV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVEV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xff00ff00ff00ff00ULL, 0xff00ff00ff00ff00ULL, }, - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0xff55ff55ff55ff55ULL, 0xff55ff55ff55ff55ULL, }, - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0xff33ff33ff33ff33ULL, 0xff33ff33ff33ff33ULL, }, - { 0xff8effe3ff38ff8eULL, 0xffe3ff38ff8effe3ULL, }, - { 0xff71ff1cffc7ff71ULL, 0xff1cffc7ff71ff1cULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x008e00e30038008eULL, 0x00e30038008e00e3ULL, }, - { 0x0071001c00c70071ULL, 0x001c00c70071001cULL, }, - { 0xaaffaaffaaffaaffULL, 0xaaffaaffaaffaaffULL, }, /* 16 */ - { 0xaa00aa00aa00aa00ULL, 0xaa00aa00aa00aa00ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa55aa55aa55aa55ULL, 0xaa55aa55aa55aa55ULL, }, - { 0xaaccaaccaaccaaccULL, 0xaaccaaccaaccaaccULL, }, - { 0xaa33aa33aa33aa33ULL, 0xaa33aa33aa33aa33ULL, }, - { 0xaa8eaae3aa38aa8eULL, 0xaae3aa38aa8eaae3ULL, }, - { 0xaa71aa1caac7aa71ULL, 0xaa1caac7aa71aa1cULL, }, - { 0x55ff55ff55ff55ffULL, 0x55ff55ff55ff55ffULL, }, /* 24 */ - { 0x5500550055005500ULL, 0x5500550055005500ULL, }, - { 0x55aa55aa55aa55aaULL, 0x55aa55aa55aa55aaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55cc55cc55cc55ccULL, 0x55cc55cc55cc55ccULL, }, - { 0x5533553355335533ULL, 0x5533553355335533ULL, }, - { 0x558e55e35538558eULL, 0x55e35538558e55e3ULL, }, - { 0x5571551c55c75571ULL, 0x551c55c75571551cULL, }, - { 0xccffccffccffccffULL, 0xccffccffccffccffULL, }, /* 32 */ - { 0xcc00cc00cc00cc00ULL, 0xcc00cc00cc00cc00ULL, }, - { 0xccaaccaaccaaccaaULL, 0xccaaccaaccaaccaaULL, }, - { 0xcc55cc55cc55cc55ULL, 0xcc55cc55cc55cc55ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcc33cc33cc33cc33ULL, 0xcc33cc33cc33cc33ULL, }, - { 0xcc8ecce3cc38cc8eULL, 0xcce3cc38cc8ecce3ULL, }, - { 0xcc71cc1cccc7cc71ULL, 0xcc1cccc7cc71cc1cULL, }, - { 0x33ff33ff33ff33ffULL, 0x33ff33ff33ff33ffULL, }, /* 40 */ - { 0x3300330033003300ULL, 0x3300330033003300ULL, }, - { 0x33aa33aa33aa33aaULL, 0x33aa33aa33aa33aaULL, }, - { 0x3355335533553355ULL, 0x3355335533553355ULL, }, - { 0x33cc33cc33cc33ccULL, 0x33cc33cc33cc33ccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x338e33e33338338eULL, 0x33e33338338e33e3ULL, }, - { 0x3371331c33c73371ULL, 0x331c33c73371331cULL, }, - { 0x8effe3ff38ff8effULL, 0xe3ff38ff8effe3ffULL, }, /* 48 */ - { 0x8e00e30038008e00ULL, 0xe30038008e00e300ULL, }, - { 0x8eaae3aa38aa8eaaULL, 0xe3aa38aa8eaae3aaULL, }, - { 0x8e55e35538558e55ULL, 0xe35538558e55e355ULL, }, - { 0x8ecce3cc38cc8eccULL, 0xe3cc38cc8ecce3ccULL, }, - { 0x8e33e33338338e33ULL, 0xe33338338e33e333ULL, }, - { 0x8e8ee3e338388e8eULL, 0xe3e338388e8ee3e3ULL, }, - { 0x8e71e31c38c78e71ULL, 0xe31c38c78e71e31cULL, }, - { 0x71ff1cffc7ff71ffULL, 0x1cffc7ff71ff1cffULL, }, /* 56 */ - { 0x71001c00c7007100ULL, 0x1c00c70071001c00ULL, }, - { 0x71aa1caac7aa71aaULL, 0x1caac7aa71aa1caaULL, }, - { 0x71551c55c7557155ULL, 0x1c55c75571551c55ULL, }, - { 0x71cc1cccc7cc71ccULL, 0x1cccc7cc71cc1cccULL, }, - { 0x71331c33c7337133ULL, 0x1c33c73371331c33ULL, }, - { 0x718e1ce3c738718eULL, 0x1ce3c738718e1ce3ULL, }, - { 0x71711c1cc7c77171ULL, 0x1c1cc7c771711c1cULL, }, - { 0x6a6acccc62624040ULL, 0x67675e5e7b7b0c0cULL, }, /* 64 */ - { 0x6abecc6362934008ULL, 0x67f75e1a7b3f0cfcULL, }, - { 0x6a5accaa62cf4080ULL, 0x67d85eff7b2b0c14ULL, }, - { 0x6a4fcc4d6231404eULL, 0x67f15ed87b420ca0ULL, }, - { 0xbe6a63cc93620840ULL, 0xf7671a5e3f7bfc0cULL, }, - { 0xbebe636393930808ULL, 0xf7f71a1a3f3ffcfcULL, }, - { 0xbe5a63aa93cf0880ULL, 0xf7d81aff3f2bfc14ULL, }, - { 0xbe4f634d9331084eULL, 0xf7f11ad83f42fca0ULL, }, - { 0x5a6aaacccf628040ULL, 0xd867ff5e2b7b140cULL, }, /* 72 */ - { 0x5abeaa63cf938008ULL, 0xd8f7ff1a2b3f14fcULL, }, - { 0x5a5aaaaacfcf8080ULL, 0xd8d8ffff2b2b1414ULL, }, - { 0x5a4faa4dcf31804eULL, 0xd8f1ffd82b4214a0ULL, }, - { 0x4f6a4dcc31624e40ULL, 0xf167d85e427ba00cULL, }, - { 0x4fbe4d6331934e08ULL, 0xf1f7d81a423fa0fcULL, }, - { 0x4f5a4daa31cf4e80ULL, 0xf1d8d8ff422ba014ULL, }, - { 0x4f4f4d4d31314e4eULL, 0xf1f1d8d84242a0a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_d.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_d.c deleted file mode 100644 index 896b11dce04e..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVEV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVEV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0xe38e38e38e38e38eULL, }, /* 48 */ - { 0x0000000000000000ULL, 0xe38e38e38e38e38eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555555ULL, 0xe38e38e38e38e38eULL, }, - { 0xccccccccccccccccULL, 0xe38e38e38e38e38eULL, }, - { 0x3333333333333333ULL, 0xe38e38e38e38e38eULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x1c71c71c71c71c71ULL, 0xe38e38e38e38e38eULL, }, - { 0xffffffffffffffffULL, 0x1c71c71c71c71c71ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x1c71c71c71c71c71ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x1c71c71c71c71c71ULL, }, - { 0x5555555555555555ULL, 0x1c71c71c71c71c71ULL, }, - { 0xccccccccccccccccULL, 0x1c71c71c71c71c71ULL, }, - { 0x3333333333333333ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe38e38e38e38e38eULL, 0x1c71c71c71c71c71ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c71ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x886ae6cc28625540ULL, }, - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, - { 0x886ae6cc28625540ULL, 0xfbbe00634d93c708ULL, }, - { 0xfbbe00634d93c708ULL, 0xfbbe00634d93c708ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x886ae6cc28625540ULL, 0xac5aaeaab9cf8b80ULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, - { 0xfbbe00634d93c708ULL, 0x704f164d5e31e24eULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x704f164d5e31e24eULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_h.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_h.c deleted file mode 100644 index a68fea643f08..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVEV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVEV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffff0000ffff0000ULL, 0xffff0000ffff0000ULL, }, - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0xffff5555ffff5555ULL, 0xffff5555ffff5555ULL, }, - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0xffff3333ffff3333ULL, 0xffff3333ffff3333ULL, }, - { 0xffff38e3ffffe38eULL, 0xffff8e38ffff38e3ULL, }, - { 0xffffc71cffff1c71ULL, 0xffff71c7ffffc71cULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x000038e30000e38eULL, 0x00008e38000038e3ULL, }, - { 0x0000c71c00001c71ULL, 0x000071c70000c71cULL, }, - { 0xaaaaffffaaaaffffULL, 0xaaaaffffaaaaffffULL, }, /* 16 */ - { 0xaaaa0000aaaa0000ULL, 0xaaaa0000aaaa0000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaa5555aaaa5555ULL, 0xaaaa5555aaaa5555ULL, }, - { 0xaaaaccccaaaaccccULL, 0xaaaaccccaaaaccccULL, }, - { 0xaaaa3333aaaa3333ULL, 0xaaaa3333aaaa3333ULL, }, - { 0xaaaa38e3aaaae38eULL, 0xaaaa8e38aaaa38e3ULL, }, - { 0xaaaac71caaaa1c71ULL, 0xaaaa71c7aaaac71cULL, }, - { 0x5555ffff5555ffffULL, 0x5555ffff5555ffffULL, }, /* 24 */ - { 0x5555000055550000ULL, 0x5555000055550000ULL, }, - { 0x5555aaaa5555aaaaULL, 0x5555aaaa5555aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555cccc5555ccccULL, 0x5555cccc5555ccccULL, }, - { 0x5555333355553333ULL, 0x5555333355553333ULL, }, - { 0x555538e35555e38eULL, 0x55558e38555538e3ULL, }, - { 0x5555c71c55551c71ULL, 0x555571c75555c71cULL, }, - { 0xccccffffccccffffULL, 0xccccffffccccffffULL, }, /* 32 */ - { 0xcccc0000cccc0000ULL, 0xcccc0000cccc0000ULL, }, - { 0xccccaaaaccccaaaaULL, 0xccccaaaaccccaaaaULL, }, - { 0xcccc5555cccc5555ULL, 0xcccc5555cccc5555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccc3333cccc3333ULL, 0xcccc3333cccc3333ULL, }, - { 0xcccc38e3cccce38eULL, 0xcccc8e38cccc38e3ULL, }, - { 0xccccc71ccccc1c71ULL, 0xcccc71c7ccccc71cULL, }, - { 0x3333ffff3333ffffULL, 0x3333ffff3333ffffULL, }, /* 40 */ - { 0x3333000033330000ULL, 0x3333000033330000ULL, }, - { 0x3333aaaa3333aaaaULL, 0x3333aaaa3333aaaaULL, }, - { 0x3333555533335555ULL, 0x3333555533335555ULL, }, - { 0x3333cccc3333ccccULL, 0x3333cccc3333ccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333338e33333e38eULL, 0x33338e38333338e3ULL, }, - { 0x3333c71c33331c71ULL, 0x333371c73333c71cULL, }, - { 0x38e3ffffe38effffULL, 0x8e38ffff38e3ffffULL, }, /* 48 */ - { 0x38e30000e38e0000ULL, 0x8e38000038e30000ULL, }, - { 0x38e3aaaae38eaaaaULL, 0x8e38aaaa38e3aaaaULL, }, - { 0x38e35555e38e5555ULL, 0x8e38555538e35555ULL, }, - { 0x38e3cccce38eccccULL, 0x8e38cccc38e3ccccULL, }, - { 0x38e33333e38e3333ULL, 0x8e38333338e33333ULL, }, - { 0x38e338e3e38ee38eULL, 0x8e388e3838e338e3ULL, }, - { 0x38e3c71ce38e1c71ULL, 0x8e3871c738e3c71cULL, }, - { 0xc71cffff1c71ffffULL, 0x71c7ffffc71cffffULL, }, /* 56 */ - { 0xc71c00001c710000ULL, 0x71c70000c71c0000ULL, }, - { 0xc71caaaa1c71aaaaULL, 0x71c7aaaac71caaaaULL, }, - { 0xc71c55551c715555ULL, 0x71c75555c71c5555ULL, }, - { 0xc71ccccc1c71ccccULL, 0x71c7ccccc71cccccULL, }, - { 0xc71c33331c713333ULL, 0x71c73333c71c3333ULL, }, - { 0xc71c38e31c71e38eULL, 0x71c78e38c71c38e3ULL, }, - { 0xc71cc71c1c711c71ULL, 0x71c771c7c71cc71cULL, }, - { 0xe6cce6cc55405540ULL, 0x0b5e0b5eb00cb00cULL, }, /* 64 */ - { 0xe6cc00635540c708ULL, 0x0b5ebb1ab00c52fcULL, }, - { 0xe6ccaeaa55408b80ULL, 0x0b5ec6ffb00c2514ULL, }, - { 0xe6cc164d5540e24eULL, 0x0b5e88d8b00ce2a0ULL, }, - { 0x0063e6ccc7085540ULL, 0xbb1a0b5e52fcb00cULL, }, - { 0x00630063c708c708ULL, 0xbb1abb1a52fc52fcULL, }, - { 0x0063aeaac7088b80ULL, 0xbb1ac6ff52fc2514ULL, }, - { 0x0063164dc708e24eULL, 0xbb1a88d852fce2a0ULL, }, - { 0xaeaae6cc8b805540ULL, 0xc6ff0b5e2514b00cULL, }, /* 72 */ - { 0xaeaa00638b80c708ULL, 0xc6ffbb1a251452fcULL, }, - { 0xaeaaaeaa8b808b80ULL, 0xc6ffc6ff25142514ULL, }, - { 0xaeaa164d8b80e24eULL, 0xc6ff88d82514e2a0ULL, }, - { 0x164de6cce24e5540ULL, 0x88d80b5ee2a0b00cULL, }, - { 0x164d0063e24ec708ULL, 0x88d8bb1ae2a052fcULL, }, - { 0x164daeaae24e8b80ULL, 0x88d8c6ffe2a02514ULL, }, - { 0x164d164de24ee24eULL, 0x88d888d8e2a0e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_w.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_w.c deleted file mode 100644 index 6e168c701ecf..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvev_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVEV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVEV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffff00000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0xffffffff55555555ULL, 0xffffffff55555555ULL, }, - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0xffffffff33333333ULL, 0xffffffff33333333ULL, }, - { 0xffffffff8e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0xffffffff71c71c71ULL, 0xffffffff1c71c71cULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x000000008e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0xaaaaaaaaffffffffULL, 0xaaaaaaaaffffffffULL, }, /* 16 */ - { 0xaaaaaaaa00000000ULL, 0xaaaaaaaa00000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa55555555ULL, 0xaaaaaaaa55555555ULL, }, - { 0xaaaaaaaaccccccccULL, 0xaaaaaaaaccccccccULL, }, - { 0xaaaaaaaa33333333ULL, 0xaaaaaaaa33333333ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaae38e38e3ULL, }, - { 0xaaaaaaaa71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x55555555ffffffffULL, 0x55555555ffffffffULL, }, /* 24 */ - { 0x5555555500000000ULL, 0x5555555500000000ULL, }, - { 0x55555555aaaaaaaaULL, 0x55555555aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55555555ccccccccULL, 0x55555555ccccccccULL, }, - { 0x5555555533333333ULL, 0x5555555533333333ULL, }, - { 0x555555558e38e38eULL, 0x55555555e38e38e3ULL, }, - { 0x5555555571c71c71ULL, 0x555555551c71c71cULL, }, - { 0xccccccccffffffffULL, 0xccccccccffffffffULL, }, /* 32 */ - { 0xcccccccc00000000ULL, 0xcccccccc00000000ULL, }, - { 0xccccccccaaaaaaaaULL, 0xccccccccaaaaaaaaULL, }, - { 0xcccccccc55555555ULL, 0xcccccccc55555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc33333333ULL, 0xcccccccc33333333ULL, }, - { 0xcccccccc8e38e38eULL, 0xcccccccce38e38e3ULL, }, - { 0xcccccccc71c71c71ULL, 0xcccccccc1c71c71cULL, }, - { 0x33333333ffffffffULL, 0x33333333ffffffffULL, }, /* 40 */ - { 0x3333333300000000ULL, 0x3333333300000000ULL, }, - { 0x33333333aaaaaaaaULL, 0x33333333aaaaaaaaULL, }, - { 0x3333333355555555ULL, 0x3333333355555555ULL, }, - { 0x33333333ccccccccULL, 0x33333333ccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333333338e38e38eULL, 0x33333333e38e38e3ULL, }, - { 0x3333333371c71c71ULL, 0x333333331c71c71cULL, }, - { 0x8e38e38effffffffULL, 0xe38e38e3ffffffffULL, }, /* 48 */ - { 0x8e38e38e00000000ULL, 0xe38e38e300000000ULL, }, - { 0x8e38e38eaaaaaaaaULL, 0xe38e38e3aaaaaaaaULL, }, - { 0x8e38e38e55555555ULL, 0xe38e38e355555555ULL, }, - { 0x8e38e38eccccccccULL, 0xe38e38e3ccccccccULL, }, - { 0x8e38e38e33333333ULL, 0xe38e38e333333333ULL, }, - { 0x8e38e38e8e38e38eULL, 0xe38e38e3e38e38e3ULL, }, - { 0x8e38e38e71c71c71ULL, 0xe38e38e31c71c71cULL, }, - { 0x71c71c71ffffffffULL, 0x1c71c71cffffffffULL, }, /* 56 */ - { 0x71c71c7100000000ULL, 0x1c71c71c00000000ULL, }, - { 0x71c71c71aaaaaaaaULL, 0x1c71c71caaaaaaaaULL, }, - { 0x71c71c7155555555ULL, 0x1c71c71c55555555ULL, }, - { 0x71c71c71ccccccccULL, 0x1c71c71cccccccccULL, }, - { 0x71c71c7133333333ULL, 0x1c71c71c33333333ULL, }, - { 0x71c71c718e38e38eULL, 0x1c71c71ce38e38e3ULL, }, - { 0x71c71c7171c71c71ULL, 0x1c71c71c1c71c71cULL, }, - { 0x2862554028625540ULL, 0xfe7bb00cfe7bb00cULL, }, /* 64 */ - { 0x286255404d93c708ULL, 0xfe7bb00c153f52fcULL, }, - { 0x28625540b9cf8b80ULL, 0xfe7bb00cab2b2514ULL, }, - { 0x286255405e31e24eULL, 0xfe7bb00ca942e2a0ULL, }, - { 0x4d93c70828625540ULL, 0x153f52fcfe7bb00cULL, }, - { 0x4d93c7084d93c708ULL, 0x153f52fc153f52fcULL, }, - { 0x4d93c708b9cf8b80ULL, 0x153f52fcab2b2514ULL, }, - { 0x4d93c7085e31e24eULL, 0x153f52fca942e2a0ULL, }, - { 0xb9cf8b8028625540ULL, 0xab2b2514fe7bb00cULL, }, /* 72 */ - { 0xb9cf8b804d93c708ULL, 0xab2b2514153f52fcULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xab2b2514ab2b2514ULL, }, - { 0xb9cf8b805e31e24eULL, 0xab2b2514a942e2a0ULL, }, - { 0x5e31e24e28625540ULL, 0xa942e2a0fe7bb00cULL, }, - { 0x5e31e24e4d93c708ULL, 0xa942e2a0153f52fcULL, }, - { 0x5e31e24eb9cf8b80ULL, 0xa942e2a0ab2b2514ULL, }, - { 0x5e31e24e5e31e24eULL, 0xa942e2a0a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVEV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_b.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_b.c deleted file mode 100644 index 11cfbf398a50..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVL.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVL.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xff00ff00ff00ff00ULL, 0xff00ff00ff00ff00ULL, }, - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0xff55ff55ff55ff55ULL, 0xff55ff55ff55ff55ULL, }, - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0xff33ff33ff33ff33ULL, 0xff33ff33ff33ff33ULL, }, - { 0xffe3ff8eff38ffe3ULL, 0xff38ffe3ff8eff38ULL, }, - { 0xff1cff71ffc7ff1cULL, 0xffc7ff1cff71ffc7ULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x00e3008e003800e3ULL, 0x003800e3008e0038ULL, }, - { 0x001c007100c7001cULL, 0x00c7001c007100c7ULL, }, - { 0xaaffaaffaaffaaffULL, 0xaaffaaffaaffaaffULL, }, /* 16 */ - { 0xaa00aa00aa00aa00ULL, 0xaa00aa00aa00aa00ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa55aa55aa55aa55ULL, 0xaa55aa55aa55aa55ULL, }, - { 0xaaccaaccaaccaaccULL, 0xaaccaaccaaccaaccULL, }, - { 0xaa33aa33aa33aa33ULL, 0xaa33aa33aa33aa33ULL, }, - { 0xaae3aa8eaa38aae3ULL, 0xaa38aae3aa8eaa38ULL, }, - { 0xaa1caa71aac7aa1cULL, 0xaac7aa1caa71aac7ULL, }, - { 0x55ff55ff55ff55ffULL, 0x55ff55ff55ff55ffULL, }, /* 24 */ - { 0x5500550055005500ULL, 0x5500550055005500ULL, }, - { 0x55aa55aa55aa55aaULL, 0x55aa55aa55aa55aaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55cc55cc55cc55ccULL, 0x55cc55cc55cc55ccULL, }, - { 0x5533553355335533ULL, 0x5533553355335533ULL, }, - { 0x55e3558e553855e3ULL, 0x553855e3558e5538ULL, }, - { 0x551c557155c7551cULL, 0x55c7551c557155c7ULL, }, - { 0xccffccffccffccffULL, 0xccffccffccffccffULL, }, /* 32 */ - { 0xcc00cc00cc00cc00ULL, 0xcc00cc00cc00cc00ULL, }, - { 0xccaaccaaccaaccaaULL, 0xccaaccaaccaaccaaULL, }, - { 0xcc55cc55cc55cc55ULL, 0xcc55cc55cc55cc55ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcc33cc33cc33cc33ULL, 0xcc33cc33cc33cc33ULL, }, - { 0xcce3cc8ecc38cce3ULL, 0xcc38cce3cc8ecc38ULL, }, - { 0xcc1ccc71ccc7cc1cULL, 0xccc7cc1ccc71ccc7ULL, }, - { 0x33ff33ff33ff33ffULL, 0x33ff33ff33ff33ffULL, }, /* 40 */ - { 0x3300330033003300ULL, 0x3300330033003300ULL, }, - { 0x33aa33aa33aa33aaULL, 0x33aa33aa33aa33aaULL, }, - { 0x3355335533553355ULL, 0x3355335533553355ULL, }, - { 0x33cc33cc33cc33ccULL, 0x33cc33cc33cc33ccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x33e3338e333833e3ULL, 0x333833e3338e3338ULL, }, - { 0x331c337133c7331cULL, 0x33c7331c337133c7ULL, }, - { 0xe3ff8eff38ffe3ffULL, 0x38ffe3ff8eff38ffULL, }, /* 48 */ - { 0xe3008e003800e300ULL, 0x3800e3008e003800ULL, }, - { 0xe3aa8eaa38aae3aaULL, 0x38aae3aa8eaa38aaULL, }, - { 0xe3558e553855e355ULL, 0x3855e3558e553855ULL, }, - { 0xe3cc8ecc38cce3ccULL, 0x38cce3cc8ecc38ccULL, }, - { 0xe3338e333833e333ULL, 0x3833e3338e333833ULL, }, - { 0xe3e38e8e3838e3e3ULL, 0x3838e3e38e8e3838ULL, }, - { 0xe31c8e7138c7e31cULL, 0x38c7e31c8e7138c7ULL, }, - { 0x1cff71ffc7ff1cffULL, 0xc7ff1cff71ffc7ffULL, }, /* 56 */ - { 0x1c007100c7001c00ULL, 0xc7001c007100c700ULL, }, - { 0x1caa71aac7aa1caaULL, 0xc7aa1caa71aac7aaULL, }, - { 0x1c557155c7551c55ULL, 0xc7551c557155c755ULL, }, - { 0x1ccc71ccc7cc1cccULL, 0xc7cc1ccc71ccc7ccULL, }, - { 0x1c337133c7331c33ULL, 0xc7331c337133c733ULL, }, - { 0x1ce3718ec7381ce3ULL, 0xc7381ce3718ec738ULL, }, - { 0x1c1c7171c7c71c1cULL, 0xc7c71c1c7171c7c7ULL, }, - { 0xfefe7b7bb0b00c0cULL, 0x4b4b67670b0b5e5eULL, }, /* 64 */ - { 0xfe157b3fb0520cfcULL, 0x4b1267f70bbb5e1aULL, }, - { 0xfeab7b2bb0250c14ULL, 0x4b2767d80bc65effULL, }, - { 0xfea97b42b0e20ca0ULL, 0x4b8d67f10b885ed8ULL, }, - { 0x15fe3f7b52b0fc0cULL, 0x124bf767bb0b1a5eULL, }, - { 0x15153f3f5252fcfcULL, 0x1212f7f7bbbb1a1aULL, }, - { 0x15ab3f2b5225fc14ULL, 0x1227f7d8bbc61affULL, }, - { 0x15a93f4252e2fca0ULL, 0x128df7f1bb881ad8ULL, }, - { 0xabfe2b7b25b0140cULL, 0x274bd867c60bff5eULL, }, /* 72 */ - { 0xab152b3f255214fcULL, 0x2712d8f7c6bbff1aULL, }, - { 0xabab2b2b25251414ULL, 0x2727d8d8c6c6ffffULL, }, - { 0xaba92b4225e214a0ULL, 0x278dd8f1c688ffd8ULL, }, - { 0xa9fe427be2b0a00cULL, 0x8d4bf167880bd85eULL, }, - { 0xa915423fe252a0fcULL, 0x8d12f1f788bbd81aULL, }, - { 0xa9ab422be225a014ULL, 0x8d27f1d888c6d8ffULL, }, - { 0xa9a94242e2e2a0a0ULL, 0x8d8df1f18888d8d8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_d.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_d.c deleted file mode 100644 index 35581ee7ead7..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVL.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVL.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e3ULL, 0xffffffffffffffffULL, }, - { 0xc71c71c71c71c71cULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x38e38e38e38e38e3ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x38e38e38e38e38e3ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xc71c71c71c71c71cULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x38e38e38e38e38e3ULL, 0x5555555555555555ULL, }, - { 0xc71c71c71c71c71cULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x38e38e38e38e38e3ULL, 0xccccccccccccccccULL, }, - { 0xc71c71c71c71c71cULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x38e38e38e38e38e3ULL, 0x3333333333333333ULL, }, - { 0xc71c71c71c71c71cULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x38e38e38e38e38e3ULL, }, - { 0xc71c71c71c71c71cULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71cULL, 0xc71c71c71c71c71cULL, }, - { 0x4b670b5efe7bb00cULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x12f7bb1a153f52fcULL, 0x4b670b5efe7bb00cULL, }, - { 0x27d8c6ffab2b2514ULL, 0x4b670b5efe7bb00cULL, }, - { 0x8df188d8a942e2a0ULL, 0x4b670b5efe7bb00cULL, }, - { 0x4b670b5efe7bb00cULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x12f7bb1a153f52fcULL, }, - { 0x27d8c6ffab2b2514ULL, 0x12f7bb1a153f52fcULL, }, - { 0x8df188d8a942e2a0ULL, 0x12f7bb1a153f52fcULL, }, - { 0x4b670b5efe7bb00cULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0x12f7bb1a153f52fcULL, 0x27d8c6ffab2b2514ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8df188d8a942e2a0ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_h.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_h.c deleted file mode 100644 index 0d89d95eddeb..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVL.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVL.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffff0000ffff0000ULL, 0xffff0000ffff0000ULL, }, - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0xffff5555ffff5555ULL, 0xffff5555ffff5555ULL, }, - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0xffff3333ffff3333ULL, 0xffff3333ffff3333ULL, }, - { 0xffffe38effff38e3ULL, 0xffff38e3ffff8e38ULL, }, - { 0xffff1c71ffffc71cULL, 0xffffc71cffff71c7ULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x0000e38e000038e3ULL, 0x000038e300008e38ULL, }, - { 0x00001c710000c71cULL, 0x0000c71c000071c7ULL, }, - { 0xaaaaffffaaaaffffULL, 0xaaaaffffaaaaffffULL, }, /* 16 */ - { 0xaaaa0000aaaa0000ULL, 0xaaaa0000aaaa0000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaa5555aaaa5555ULL, 0xaaaa5555aaaa5555ULL, }, - { 0xaaaaccccaaaaccccULL, 0xaaaaccccaaaaccccULL, }, - { 0xaaaa3333aaaa3333ULL, 0xaaaa3333aaaa3333ULL, }, - { 0xaaaae38eaaaa38e3ULL, 0xaaaa38e3aaaa8e38ULL, }, - { 0xaaaa1c71aaaac71cULL, 0xaaaac71caaaa71c7ULL, }, - { 0x5555ffff5555ffffULL, 0x5555ffff5555ffffULL, }, /* 24 */ - { 0x5555000055550000ULL, 0x5555000055550000ULL, }, - { 0x5555aaaa5555aaaaULL, 0x5555aaaa5555aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555cccc5555ccccULL, 0x5555cccc5555ccccULL, }, - { 0x5555333355553333ULL, 0x5555333355553333ULL, }, - { 0x5555e38e555538e3ULL, 0x555538e355558e38ULL, }, - { 0x55551c715555c71cULL, 0x5555c71c555571c7ULL, }, - { 0xccccffffccccffffULL, 0xccccffffccccffffULL, }, /* 32 */ - { 0xcccc0000cccc0000ULL, 0xcccc0000cccc0000ULL, }, - { 0xccccaaaaccccaaaaULL, 0xccccaaaaccccaaaaULL, }, - { 0xcccc5555cccc5555ULL, 0xcccc5555cccc5555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccc3333cccc3333ULL, 0xcccc3333cccc3333ULL, }, - { 0xcccce38ecccc38e3ULL, 0xcccc38e3cccc8e38ULL, }, - { 0xcccc1c71ccccc71cULL, 0xccccc71ccccc71c7ULL, }, - { 0x3333ffff3333ffffULL, 0x3333ffff3333ffffULL, }, /* 40 */ - { 0x3333000033330000ULL, 0x3333000033330000ULL, }, - { 0x3333aaaa3333aaaaULL, 0x3333aaaa3333aaaaULL, }, - { 0x3333555533335555ULL, 0x3333555533335555ULL, }, - { 0x3333cccc3333ccccULL, 0x3333cccc3333ccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333e38e333338e3ULL, 0x333338e333338e38ULL, }, - { 0x33331c713333c71cULL, 0x3333c71c333371c7ULL, }, - { 0xe38effff38e3ffffULL, 0x38e3ffff8e38ffffULL, }, /* 48 */ - { 0xe38e000038e30000ULL, 0x38e300008e380000ULL, }, - { 0xe38eaaaa38e3aaaaULL, 0x38e3aaaa8e38aaaaULL, }, - { 0xe38e555538e35555ULL, 0x38e355558e385555ULL, }, - { 0xe38ecccc38e3ccccULL, 0x38e3cccc8e38ccccULL, }, - { 0xe38e333338e33333ULL, 0x38e333338e383333ULL, }, - { 0xe38ee38e38e338e3ULL, 0x38e338e38e388e38ULL, }, - { 0xe38e1c7138e3c71cULL, 0x38e3c71c8e3871c7ULL, }, - { 0x1c71ffffc71cffffULL, 0xc71cffff71c7ffffULL, }, /* 56 */ - { 0x1c710000c71c0000ULL, 0xc71c000071c70000ULL, }, - { 0x1c71aaaac71caaaaULL, 0xc71caaaa71c7aaaaULL, }, - { 0x1c715555c71c5555ULL, 0xc71c555571c75555ULL, }, - { 0x1c71ccccc71cccccULL, 0xc71ccccc71c7ccccULL, }, - { 0x1c713333c71c3333ULL, 0xc71c333371c73333ULL, }, - { 0x1c71e38ec71c38e3ULL, 0xc71c38e371c78e38ULL, }, - { 0x1c711c71c71cc71cULL, 0xc71cc71c71c771c7ULL, }, - { 0xfe7bfe7bb00cb00cULL, 0x4b674b670b5e0b5eULL, }, /* 64 */ - { 0xfe7b153fb00c52fcULL, 0x4b6712f70b5ebb1aULL, }, - { 0xfe7bab2bb00c2514ULL, 0x4b6727d80b5ec6ffULL, }, - { 0xfe7ba942b00ce2a0ULL, 0x4b678df10b5e88d8ULL, }, - { 0x153ffe7b52fcb00cULL, 0x12f74b67bb1a0b5eULL, }, - { 0x153f153f52fc52fcULL, 0x12f712f7bb1abb1aULL, }, - { 0x153fab2b52fc2514ULL, 0x12f727d8bb1ac6ffULL, }, - { 0x153fa94252fce2a0ULL, 0x12f78df1bb1a88d8ULL, }, - { 0xab2bfe7b2514b00cULL, 0x27d84b67c6ff0b5eULL, }, /* 72 */ - { 0xab2b153f251452fcULL, 0x27d812f7c6ffbb1aULL, }, - { 0xab2bab2b25142514ULL, 0x27d827d8c6ffc6ffULL, }, - { 0xab2ba9422514e2a0ULL, 0x27d88df1c6ff88d8ULL, }, - { 0xa942fe7be2a0b00cULL, 0x8df14b6788d80b5eULL, }, - { 0xa942153fe2a052fcULL, 0x8df112f788d8bb1aULL, }, - { 0xa942ab2be2a02514ULL, 0x8df127d888d8c6ffULL, }, - { 0xa942a942e2a0e2a0ULL, 0x8df18df188d888d8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_w.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_w.c deleted file mode 100644 index ce044889c3e1..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvl_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVL.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVL.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffff00000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0xffffffff55555555ULL, 0xffffffff55555555ULL, }, - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0xffffffff33333333ULL, 0xffffffff33333333ULL, }, - { 0xffffffffe38e38e3ULL, 0xffffffff38e38e38ULL, }, - { 0xffffffff1c71c71cULL, 0xffffffffc71c71c7ULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x00000000e38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0x000000001c71c71cULL, 0x00000000c71c71c7ULL, }, - { 0xaaaaaaaaffffffffULL, 0xaaaaaaaaffffffffULL, }, /* 16 */ - { 0xaaaaaaaa00000000ULL, 0xaaaaaaaa00000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa55555555ULL, 0xaaaaaaaa55555555ULL, }, - { 0xaaaaaaaaccccccccULL, 0xaaaaaaaaccccccccULL, }, - { 0xaaaaaaaa33333333ULL, 0xaaaaaaaa33333333ULL, }, - { 0xaaaaaaaae38e38e3ULL, 0xaaaaaaaa38e38e38ULL, }, - { 0xaaaaaaaa1c71c71cULL, 0xaaaaaaaac71c71c7ULL, }, - { 0x55555555ffffffffULL, 0x55555555ffffffffULL, }, /* 24 */ - { 0x5555555500000000ULL, 0x5555555500000000ULL, }, - { 0x55555555aaaaaaaaULL, 0x55555555aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55555555ccccccccULL, 0x55555555ccccccccULL, }, - { 0x5555555533333333ULL, 0x5555555533333333ULL, }, - { 0x55555555e38e38e3ULL, 0x5555555538e38e38ULL, }, - { 0x555555551c71c71cULL, 0x55555555c71c71c7ULL, }, - { 0xccccccccffffffffULL, 0xccccccccffffffffULL, }, /* 32 */ - { 0xcccccccc00000000ULL, 0xcccccccc00000000ULL, }, - { 0xccccccccaaaaaaaaULL, 0xccccccccaaaaaaaaULL, }, - { 0xcccccccc55555555ULL, 0xcccccccc55555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc33333333ULL, 0xcccccccc33333333ULL, }, - { 0xcccccccce38e38e3ULL, 0xcccccccc38e38e38ULL, }, - { 0xcccccccc1c71c71cULL, 0xccccccccc71c71c7ULL, }, - { 0x33333333ffffffffULL, 0x33333333ffffffffULL, }, /* 40 */ - { 0x3333333300000000ULL, 0x3333333300000000ULL, }, - { 0x33333333aaaaaaaaULL, 0x33333333aaaaaaaaULL, }, - { 0x3333333355555555ULL, 0x3333333355555555ULL, }, - { 0x33333333ccccccccULL, 0x33333333ccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x33333333e38e38e3ULL, 0x3333333338e38e38ULL, }, - { 0x333333331c71c71cULL, 0x33333333c71c71c7ULL, }, - { 0xe38e38e3ffffffffULL, 0x38e38e38ffffffffULL, }, /* 48 */ - { 0xe38e38e300000000ULL, 0x38e38e3800000000ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38aaaaaaaaULL, }, - { 0xe38e38e355555555ULL, 0x38e38e3855555555ULL, }, - { 0xe38e38e3ccccccccULL, 0x38e38e38ccccccccULL, }, - { 0xe38e38e333333333ULL, 0x38e38e3833333333ULL, }, - { 0xe38e38e3e38e38e3ULL, 0x38e38e3838e38e38ULL, }, - { 0xe38e38e31c71c71cULL, 0x38e38e38c71c71c7ULL, }, - { 0x1c71c71cffffffffULL, 0xc71c71c7ffffffffULL, }, /* 56 */ - { 0x1c71c71c00000000ULL, 0xc71c71c700000000ULL, }, - { 0x1c71c71caaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c755555555ULL, }, - { 0x1c71c71cccccccccULL, 0xc71c71c7ccccccccULL, }, - { 0x1c71c71c33333333ULL, 0xc71c71c733333333ULL, }, - { 0x1c71c71ce38e38e3ULL, 0xc71c71c738e38e38ULL, }, - { 0x1c71c71c1c71c71cULL, 0xc71c71c7c71c71c7ULL, }, - { 0xfe7bb00cfe7bb00cULL, 0x4b670b5e4b670b5eULL, }, /* 64 */ - { 0xfe7bb00c153f52fcULL, 0x4b670b5e12f7bb1aULL, }, - { 0xfe7bb00cab2b2514ULL, 0x4b670b5e27d8c6ffULL, }, - { 0xfe7bb00ca942e2a0ULL, 0x4b670b5e8df188d8ULL, }, - { 0x153f52fcfe7bb00cULL, 0x12f7bb1a4b670b5eULL, }, - { 0x153f52fc153f52fcULL, 0x12f7bb1a12f7bb1aULL, }, - { 0x153f52fcab2b2514ULL, 0x12f7bb1a27d8c6ffULL, }, - { 0x153f52fca942e2a0ULL, 0x12f7bb1a8df188d8ULL, }, - { 0xab2b2514fe7bb00cULL, 0x27d8c6ff4b670b5eULL, }, /* 72 */ - { 0xab2b2514153f52fcULL, 0x27d8c6ff12f7bb1aULL, }, - { 0xab2b2514ab2b2514ULL, 0x27d8c6ff27d8c6ffULL, }, - { 0xab2b2514a942e2a0ULL, 0x27d8c6ff8df188d8ULL, }, - { 0xa942e2a0fe7bb00cULL, 0x8df188d84b670b5eULL, }, - { 0xa942e2a0153f52fcULL, 0x8df188d812f7bb1aULL, }, - { 0xa942e2a0ab2b2514ULL, 0x8df188d827d8c6ffULL, }, - { 0xa942e2a0a942e2a0ULL, 0x8df188d88df188d8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVL_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_b.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_b.c deleted file mode 100644 index f7dd1d22b06d..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVOD.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVOD.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xff00ff00ff00ff00ULL, 0xff00ff00ff00ff00ULL, }, - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0xff55ff55ff55ff55ULL, 0xff55ff55ff55ff55ULL, }, - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0xff33ff33ff33ff33ULL, 0xff33ff33ff33ff33ULL, }, - { 0xffe3ff38ff8effe3ULL, 0xff38ff8effe3ff38ULL, }, - { 0xff1cffc7ff71ff1cULL, 0xffc7ff71ff1cffc7ULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x00e30038008e00e3ULL, 0x0038008e00e30038ULL, }, - { 0x001c00c70071001cULL, 0x00c70071001c00c7ULL, }, - { 0xaaffaaffaaffaaffULL, 0xaaffaaffaaffaaffULL, }, /* 16 */ - { 0xaa00aa00aa00aa00ULL, 0xaa00aa00aa00aa00ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa55aa55aa55aa55ULL, 0xaa55aa55aa55aa55ULL, }, - { 0xaaccaaccaaccaaccULL, 0xaaccaaccaaccaaccULL, }, - { 0xaa33aa33aa33aa33ULL, 0xaa33aa33aa33aa33ULL, }, - { 0xaae3aa38aa8eaae3ULL, 0xaa38aa8eaae3aa38ULL, }, - { 0xaa1caac7aa71aa1cULL, 0xaac7aa71aa1caac7ULL, }, - { 0x55ff55ff55ff55ffULL, 0x55ff55ff55ff55ffULL, }, /* 24 */ - { 0x5500550055005500ULL, 0x5500550055005500ULL, }, - { 0x55aa55aa55aa55aaULL, 0x55aa55aa55aa55aaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55cc55cc55cc55ccULL, 0x55cc55cc55cc55ccULL, }, - { 0x5533553355335533ULL, 0x5533553355335533ULL, }, - { 0x55e35538558e55e3ULL, 0x5538558e55e35538ULL, }, - { 0x551c55c75571551cULL, 0x55c75571551c55c7ULL, }, - { 0xccffccffccffccffULL, 0xccffccffccffccffULL, }, /* 32 */ - { 0xcc00cc00cc00cc00ULL, 0xcc00cc00cc00cc00ULL, }, - { 0xccaaccaaccaaccaaULL, 0xccaaccaaccaaccaaULL, }, - { 0xcc55cc55cc55cc55ULL, 0xcc55cc55cc55cc55ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcc33cc33cc33cc33ULL, 0xcc33cc33cc33cc33ULL, }, - { 0xcce3cc38cc8ecce3ULL, 0xcc38cc8ecce3cc38ULL, }, - { 0xcc1cccc7cc71cc1cULL, 0xccc7cc71cc1cccc7ULL, }, - { 0x33ff33ff33ff33ffULL, 0x33ff33ff33ff33ffULL, }, /* 40 */ - { 0x3300330033003300ULL, 0x3300330033003300ULL, }, - { 0x33aa33aa33aa33aaULL, 0x33aa33aa33aa33aaULL, }, - { 0x3355335533553355ULL, 0x3355335533553355ULL, }, - { 0x33cc33cc33cc33ccULL, 0x33cc33cc33cc33ccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x33e33338338e33e3ULL, 0x3338338e33e33338ULL, }, - { 0x331c33c73371331cULL, 0x33c73371331c33c7ULL, }, - { 0xe3ff38ff8effe3ffULL, 0x38ff8effe3ff38ffULL, }, /* 48 */ - { 0xe30038008e00e300ULL, 0x38008e00e3003800ULL, }, - { 0xe3aa38aa8eaae3aaULL, 0x38aa8eaae3aa38aaULL, }, - { 0xe35538558e55e355ULL, 0x38558e55e3553855ULL, }, - { 0xe3cc38cc8ecce3ccULL, 0x38cc8ecce3cc38ccULL, }, - { 0xe33338338e33e333ULL, 0x38338e33e3333833ULL, }, - { 0xe3e338388e8ee3e3ULL, 0x38388e8ee3e33838ULL, }, - { 0xe31c38c78e71e31cULL, 0x38c78e71e31c38c7ULL, }, - { 0x1cffc7ff71ff1cffULL, 0xc7ff71ff1cffc7ffULL, }, /* 56 */ - { 0x1c00c70071001c00ULL, 0xc70071001c00c700ULL, }, - { 0x1caac7aa71aa1caaULL, 0xc7aa71aa1caac7aaULL, }, - { 0x1c55c75571551c55ULL, 0xc75571551c55c755ULL, }, - { 0x1cccc7cc71cc1cccULL, 0xc7cc71cc1cccc7ccULL, }, - { 0x1c33c73371331c33ULL, 0xc73371331c33c733ULL, }, - { 0x1ce3c738718e1ce3ULL, 0xc738718e1ce3c738ULL, }, - { 0x1c1cc7c771711c1cULL, 0xc7c771711c1cc7c7ULL, }, - { 0x8888e6e628285555ULL, 0x4b4b0b0bfefeb0b0ULL, }, /* 64 */ - { 0x88fbe600284d55c7ULL, 0x4b120bbbfe15b052ULL, }, - { 0x88ace6ae28b9558bULL, 0x4b270bc6feabb025ULL, }, - { 0x8870e616285e55e2ULL, 0x4b8d0b88fea9b0e2ULL, }, - { 0xfb8800e64d28c755ULL, 0x124bbb0b15fe52b0ULL, }, - { 0xfbfb00004d4dc7c7ULL, 0x1212bbbb15155252ULL, }, - { 0xfbac00ae4db9c78bULL, 0x1227bbc615ab5225ULL, }, - { 0xfb7000164d5ec7e2ULL, 0x128dbb8815a952e2ULL, }, - { 0xac88aee6b9288b55ULL, 0x274bc60babfe25b0ULL, }, /* 72 */ - { 0xacfbae00b94d8bc7ULL, 0x2712c6bbab152552ULL, }, - { 0xacacaeaeb9b98b8bULL, 0x2727c6c6abab2525ULL, }, - { 0xac70ae16b95e8be2ULL, 0x278dc688aba925e2ULL, }, - { 0x708816e65e28e255ULL, 0x8d4b880ba9fee2b0ULL, }, - { 0x70fb16005e4de2c7ULL, 0x8d1288bba915e252ULL, }, - { 0x70ac16ae5eb9e28bULL, 0x8d2788c6a9abe225ULL, }, - { 0x707016165e5ee2e2ULL, 0x8d8d8888a9a9e2e2ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_d.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_d.c deleted file mode 100644 index bef28d8deda3..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVOD.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVOD.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e3ULL, 0xffffffffffffffffULL, }, - { 0xc71c71c71c71c71cULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x38e38e38e38e38e3ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x38e38e38e38e38e3ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xc71c71c71c71c71cULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x38e38e38e38e38e3ULL, 0x5555555555555555ULL, }, - { 0xc71c71c71c71c71cULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x38e38e38e38e38e3ULL, 0xccccccccccccccccULL, }, - { 0xc71c71c71c71c71cULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x38e38e38e38e38e3ULL, 0x3333333333333333ULL, }, - { 0xc71c71c71c71c71cULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x38e38e38e38e38e3ULL, }, - { 0xc71c71c71c71c71cULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71cULL, 0xc71c71c71c71c71cULL, }, - { 0x4b670b5efe7bb00cULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x12f7bb1a153f52fcULL, 0x4b670b5efe7bb00cULL, }, - { 0x27d8c6ffab2b2514ULL, 0x4b670b5efe7bb00cULL, }, - { 0x8df188d8a942e2a0ULL, 0x4b670b5efe7bb00cULL, }, - { 0x4b670b5efe7bb00cULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x12f7bb1a153f52fcULL, }, - { 0x27d8c6ffab2b2514ULL, 0x12f7bb1a153f52fcULL, }, - { 0x8df188d8a942e2a0ULL, 0x12f7bb1a153f52fcULL, }, - { 0x4b670b5efe7bb00cULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0x12f7bb1a153f52fcULL, 0x27d8c6ffab2b2514ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8df188d8a942e2a0ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_h.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_h.c deleted file mode 100644 index d2355c6676d6..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVOD.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVOD.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffff0000ffff0000ULL, 0xffff0000ffff0000ULL, }, - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0xffff5555ffff5555ULL, 0xffff5555ffff5555ULL, }, - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0xffff3333ffff3333ULL, 0xffff3333ffff3333ULL, }, - { 0xffffe38effff8e38ULL, 0xffff38e3ffffe38eULL, }, - { 0xffff1c71ffff71c7ULL, 0xffffc71cffff1c71ULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x0000e38e00008e38ULL, 0x000038e30000e38eULL, }, - { 0x00001c71000071c7ULL, 0x0000c71c00001c71ULL, }, - { 0xaaaaffffaaaaffffULL, 0xaaaaffffaaaaffffULL, }, /* 16 */ - { 0xaaaa0000aaaa0000ULL, 0xaaaa0000aaaa0000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaa5555aaaa5555ULL, 0xaaaa5555aaaa5555ULL, }, - { 0xaaaaccccaaaaccccULL, 0xaaaaccccaaaaccccULL, }, - { 0xaaaa3333aaaa3333ULL, 0xaaaa3333aaaa3333ULL, }, - { 0xaaaae38eaaaa8e38ULL, 0xaaaa38e3aaaae38eULL, }, - { 0xaaaa1c71aaaa71c7ULL, 0xaaaac71caaaa1c71ULL, }, - { 0x5555ffff5555ffffULL, 0x5555ffff5555ffffULL, }, /* 24 */ - { 0x5555000055550000ULL, 0x5555000055550000ULL, }, - { 0x5555aaaa5555aaaaULL, 0x5555aaaa5555aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555cccc5555ccccULL, 0x5555cccc5555ccccULL, }, - { 0x5555333355553333ULL, 0x5555333355553333ULL, }, - { 0x5555e38e55558e38ULL, 0x555538e35555e38eULL, }, - { 0x55551c71555571c7ULL, 0x5555c71c55551c71ULL, }, - { 0xccccffffccccffffULL, 0xccccffffccccffffULL, }, /* 32 */ - { 0xcccc0000cccc0000ULL, 0xcccc0000cccc0000ULL, }, - { 0xccccaaaaccccaaaaULL, 0xccccaaaaccccaaaaULL, }, - { 0xcccc5555cccc5555ULL, 0xcccc5555cccc5555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccc3333cccc3333ULL, 0xcccc3333cccc3333ULL, }, - { 0xcccce38ecccc8e38ULL, 0xcccc38e3cccce38eULL, }, - { 0xcccc1c71cccc71c7ULL, 0xccccc71ccccc1c71ULL, }, - { 0x3333ffff3333ffffULL, 0x3333ffff3333ffffULL, }, /* 40 */ - { 0x3333000033330000ULL, 0x3333000033330000ULL, }, - { 0x3333aaaa3333aaaaULL, 0x3333aaaa3333aaaaULL, }, - { 0x3333555533335555ULL, 0x3333555533335555ULL, }, - { 0x3333cccc3333ccccULL, 0x3333cccc3333ccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x3333e38e33338e38ULL, 0x333338e33333e38eULL, }, - { 0x33331c71333371c7ULL, 0x3333c71c33331c71ULL, }, - { 0xe38effff8e38ffffULL, 0x38e3ffffe38effffULL, }, /* 48 */ - { 0xe38e00008e380000ULL, 0x38e30000e38e0000ULL, }, - { 0xe38eaaaa8e38aaaaULL, 0x38e3aaaae38eaaaaULL, }, - { 0xe38e55558e385555ULL, 0x38e35555e38e5555ULL, }, - { 0xe38ecccc8e38ccccULL, 0x38e3cccce38eccccULL, }, - { 0xe38e33338e383333ULL, 0x38e33333e38e3333ULL, }, - { 0xe38ee38e8e388e38ULL, 0x38e338e3e38ee38eULL, }, - { 0xe38e1c718e3871c7ULL, 0x38e3c71ce38e1c71ULL, }, - { 0x1c71ffff71c7ffffULL, 0xc71cffff1c71ffffULL, }, /* 56 */ - { 0x1c71000071c70000ULL, 0xc71c00001c710000ULL, }, - { 0x1c71aaaa71c7aaaaULL, 0xc71caaaa1c71aaaaULL, }, - { 0x1c71555571c75555ULL, 0xc71c55551c715555ULL, }, - { 0x1c71cccc71c7ccccULL, 0xc71ccccc1c71ccccULL, }, - { 0x1c71333371c73333ULL, 0xc71c33331c713333ULL, }, - { 0x1c71e38e71c78e38ULL, 0xc71c38e31c71e38eULL, }, - { 0x1c711c7171c771c7ULL, 0xc71cc71c1c711c71ULL, }, - { 0x886a886a28622862ULL, 0x4b674b67fe7bfe7bULL, }, /* 64 */ - { 0x886afbbe28624d93ULL, 0x4b6712f7fe7b153fULL, }, - { 0x886aac5a2862b9cfULL, 0x4b6727d8fe7bab2bULL, }, - { 0x886a704f28625e31ULL, 0x4b678df1fe7ba942ULL, }, - { 0xfbbe886a4d932862ULL, 0x12f74b67153ffe7bULL, }, - { 0xfbbefbbe4d934d93ULL, 0x12f712f7153f153fULL, }, - { 0xfbbeac5a4d93b9cfULL, 0x12f727d8153fab2bULL, }, - { 0xfbbe704f4d935e31ULL, 0x12f78df1153fa942ULL, }, - { 0xac5a886ab9cf2862ULL, 0x27d84b67ab2bfe7bULL, }, /* 72 */ - { 0xac5afbbeb9cf4d93ULL, 0x27d812f7ab2b153fULL, }, - { 0xac5aac5ab9cfb9cfULL, 0x27d827d8ab2bab2bULL, }, - { 0xac5a704fb9cf5e31ULL, 0x27d88df1ab2ba942ULL, }, - { 0x704f886a5e312862ULL, 0x8df14b67a942fe7bULL, }, - { 0x704ffbbe5e314d93ULL, 0x8df112f7a942153fULL, }, - { 0x704fac5a5e31b9cfULL, 0x8df127d8a942ab2bULL, }, - { 0x704f704f5e315e31ULL, 0x8df18df1a942a942ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_w.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_w.c deleted file mode 100644 index 636a62d056e1..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvod_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVOD.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVOD.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffff00000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0xffffffff55555555ULL, 0xffffffff55555555ULL, }, - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0xffffffff33333333ULL, 0xffffffff33333333ULL, }, - { 0xffffffffe38e38e3ULL, 0xffffffff38e38e38ULL, }, - { 0xffffffff1c71c71cULL, 0xffffffffc71c71c7ULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x00000000e38e38e3ULL, 0x0000000038e38e38ULL, }, - { 0x000000001c71c71cULL, 0x00000000c71c71c7ULL, }, - { 0xaaaaaaaaffffffffULL, 0xaaaaaaaaffffffffULL, }, /* 16 */ - { 0xaaaaaaaa00000000ULL, 0xaaaaaaaa00000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa55555555ULL, 0xaaaaaaaa55555555ULL, }, - { 0xaaaaaaaaccccccccULL, 0xaaaaaaaaccccccccULL, }, - { 0xaaaaaaaa33333333ULL, 0xaaaaaaaa33333333ULL, }, - { 0xaaaaaaaae38e38e3ULL, 0xaaaaaaaa38e38e38ULL, }, - { 0xaaaaaaaa1c71c71cULL, 0xaaaaaaaac71c71c7ULL, }, - { 0x55555555ffffffffULL, 0x55555555ffffffffULL, }, /* 24 */ - { 0x5555555500000000ULL, 0x5555555500000000ULL, }, - { 0x55555555aaaaaaaaULL, 0x55555555aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55555555ccccccccULL, 0x55555555ccccccccULL, }, - { 0x5555555533333333ULL, 0x5555555533333333ULL, }, - { 0x55555555e38e38e3ULL, 0x5555555538e38e38ULL, }, - { 0x555555551c71c71cULL, 0x55555555c71c71c7ULL, }, - { 0xccccccccffffffffULL, 0xccccccccffffffffULL, }, /* 32 */ - { 0xcccccccc00000000ULL, 0xcccccccc00000000ULL, }, - { 0xccccccccaaaaaaaaULL, 0xccccccccaaaaaaaaULL, }, - { 0xcccccccc55555555ULL, 0xcccccccc55555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc33333333ULL, 0xcccccccc33333333ULL, }, - { 0xcccccccce38e38e3ULL, 0xcccccccc38e38e38ULL, }, - { 0xcccccccc1c71c71cULL, 0xccccccccc71c71c7ULL, }, - { 0x33333333ffffffffULL, 0x33333333ffffffffULL, }, /* 40 */ - { 0x3333333300000000ULL, 0x3333333300000000ULL, }, - { 0x33333333aaaaaaaaULL, 0x33333333aaaaaaaaULL, }, - { 0x3333333355555555ULL, 0x3333333355555555ULL, }, - { 0x33333333ccccccccULL, 0x33333333ccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x33333333e38e38e3ULL, 0x3333333338e38e38ULL, }, - { 0x333333331c71c71cULL, 0x33333333c71c71c7ULL, }, - { 0xe38e38e3ffffffffULL, 0x38e38e38ffffffffULL, }, /* 48 */ - { 0xe38e38e300000000ULL, 0x38e38e3800000000ULL, }, - { 0xe38e38e3aaaaaaaaULL, 0x38e38e38aaaaaaaaULL, }, - { 0xe38e38e355555555ULL, 0x38e38e3855555555ULL, }, - { 0xe38e38e3ccccccccULL, 0x38e38e38ccccccccULL, }, - { 0xe38e38e333333333ULL, 0x38e38e3833333333ULL, }, - { 0xe38e38e3e38e38e3ULL, 0x38e38e3838e38e38ULL, }, - { 0xe38e38e31c71c71cULL, 0x38e38e38c71c71c7ULL, }, - { 0x1c71c71cffffffffULL, 0xc71c71c7ffffffffULL, }, /* 56 */ - { 0x1c71c71c00000000ULL, 0xc71c71c700000000ULL, }, - { 0x1c71c71caaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, - { 0x1c71c71c55555555ULL, 0xc71c71c755555555ULL, }, - { 0x1c71c71cccccccccULL, 0xc71c71c7ccccccccULL, }, - { 0x1c71c71c33333333ULL, 0xc71c71c733333333ULL, }, - { 0x1c71c71ce38e38e3ULL, 0xc71c71c738e38e38ULL, }, - { 0x1c71c71c1c71c71cULL, 0xc71c71c7c71c71c7ULL, }, - { 0x886ae6cc886ae6ccULL, 0x4b670b5e4b670b5eULL, }, /* 64 */ - { 0x886ae6ccfbbe0063ULL, 0x4b670b5e12f7bb1aULL, }, - { 0x886ae6ccac5aaeaaULL, 0x4b670b5e27d8c6ffULL, }, - { 0x886ae6cc704f164dULL, 0x4b670b5e8df188d8ULL, }, - { 0xfbbe0063886ae6ccULL, 0x12f7bb1a4b670b5eULL, }, - { 0xfbbe0063fbbe0063ULL, 0x12f7bb1a12f7bb1aULL, }, - { 0xfbbe0063ac5aaeaaULL, 0x12f7bb1a27d8c6ffULL, }, - { 0xfbbe0063704f164dULL, 0x12f7bb1a8df188d8ULL, }, - { 0xac5aaeaa886ae6ccULL, 0x27d8c6ff4b670b5eULL, }, /* 72 */ - { 0xac5aaeaafbbe0063ULL, 0x27d8c6ff12f7bb1aULL, }, - { 0xac5aaeaaac5aaeaaULL, 0x27d8c6ff27d8c6ffULL, }, - { 0xac5aaeaa704f164dULL, 0x27d8c6ff8df188d8ULL, }, - { 0x704f164d886ae6ccULL, 0x8df188d84b670b5eULL, }, - { 0x704f164dfbbe0063ULL, 0x8df188d812f7bb1aULL, }, - { 0x704f164dac5aaeaaULL, 0x8df188d827d8c6ffULL, }, - { 0x704f164d704f164dULL, 0x8df188d88df188d8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVOD_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_b.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_b.c deleted file mode 100644 index 75bc9de9f93a..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVR.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVR.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xff00ff00ff00ff00ULL, 0xff00ff00ff00ff00ULL, }, - { 0xffaaffaaffaaffaaULL, 0xffaaffaaffaaffaaULL, }, - { 0xff55ff55ff55ff55ULL, 0xff55ff55ff55ff55ULL, }, - { 0xffccffccffccffccULL, 0xffccffccffccffccULL, }, - { 0xff33ff33ff33ff33ULL, 0xff33ff33ff33ff33ULL, }, - { 0xff8eff38ffe3ff8eULL, 0xffe3ff8eff38ffe3ULL, }, - { 0xff71ffc7ff1cff71ULL, 0xff1cff71ffc7ff1cULL, }, - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00aa00aa00aa00aaULL, 0x00aa00aa00aa00aaULL, }, - { 0x0055005500550055ULL, 0x0055005500550055ULL, }, - { 0x00cc00cc00cc00ccULL, 0x00cc00cc00cc00ccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x008e003800e3008eULL, 0x00e3008e003800e3ULL, }, - { 0x007100c7001c0071ULL, 0x001c007100c7001cULL, }, - { 0xaaffaaffaaffaaffULL, 0xaaffaaffaaffaaffULL, }, /* 16 */ - { 0xaa00aa00aa00aa00ULL, 0xaa00aa00aa00aa00ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaa55aa55aa55aa55ULL, 0xaa55aa55aa55aa55ULL, }, - { 0xaaccaaccaaccaaccULL, 0xaaccaaccaaccaaccULL, }, - { 0xaa33aa33aa33aa33ULL, 0xaa33aa33aa33aa33ULL, }, - { 0xaa8eaa38aae3aa8eULL, 0xaae3aa8eaa38aae3ULL, }, - { 0xaa71aac7aa1caa71ULL, 0xaa1caa71aac7aa1cULL, }, - { 0x55ff55ff55ff55ffULL, 0x55ff55ff55ff55ffULL, }, /* 24 */ - { 0x5500550055005500ULL, 0x5500550055005500ULL, }, - { 0x55aa55aa55aa55aaULL, 0x55aa55aa55aa55aaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55cc55cc55cc55ccULL, 0x55cc55cc55cc55ccULL, }, - { 0x5533553355335533ULL, 0x5533553355335533ULL, }, - { 0x558e553855e3558eULL, 0x55e3558e553855e3ULL, }, - { 0x557155c7551c5571ULL, 0x551c557155c7551cULL, }, - { 0xccffccffccffccffULL, 0xccffccffccffccffULL, }, /* 32 */ - { 0xcc00cc00cc00cc00ULL, 0xcc00cc00cc00cc00ULL, }, - { 0xccaaccaaccaaccaaULL, 0xccaaccaaccaaccaaULL, }, - { 0xcc55cc55cc55cc55ULL, 0xcc55cc55cc55cc55ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcc33cc33cc33cc33ULL, 0xcc33cc33cc33cc33ULL, }, - { 0xcc8ecc38cce3cc8eULL, 0xcce3cc8ecc38cce3ULL, }, - { 0xcc71ccc7cc1ccc71ULL, 0xcc1ccc71ccc7cc1cULL, }, - { 0x33ff33ff33ff33ffULL, 0x33ff33ff33ff33ffULL, }, /* 40 */ - { 0x3300330033003300ULL, 0x3300330033003300ULL, }, - { 0x33aa33aa33aa33aaULL, 0x33aa33aa33aa33aaULL, }, - { 0x3355335533553355ULL, 0x3355335533553355ULL, }, - { 0x33cc33cc33cc33ccULL, 0x33cc33cc33cc33ccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x338e333833e3338eULL, 0x33e3338e333833e3ULL, }, - { 0x337133c7331c3371ULL, 0x331c337133c7331cULL, }, - { 0x8eff38ffe3ff8effULL, 0xe3ff8eff38ffe3ffULL, }, /* 48 */ - { 0x8e003800e3008e00ULL, 0xe3008e003800e300ULL, }, - { 0x8eaa38aae3aa8eaaULL, 0xe3aa8eaa38aae3aaULL, }, - { 0x8e553855e3558e55ULL, 0xe3558e553855e355ULL, }, - { 0x8ecc38cce3cc8eccULL, 0xe3cc8ecc38cce3ccULL, }, - { 0x8e333833e3338e33ULL, 0xe3338e333833e333ULL, }, - { 0x8e8e3838e3e38e8eULL, 0xe3e38e8e3838e3e3ULL, }, - { 0x8e7138c7e31c8e71ULL, 0xe31c8e7138c7e31cULL, }, - { 0x71ffc7ff1cff71ffULL, 0x1cff71ffc7ff1cffULL, }, /* 56 */ - { 0x7100c7001c007100ULL, 0x1c007100c7001c00ULL, }, - { 0x71aac7aa1caa71aaULL, 0x1caa71aac7aa1caaULL, }, - { 0x7155c7551c557155ULL, 0x1c557155c7551c55ULL, }, - { 0x71ccc7cc1ccc71ccULL, 0x1ccc71ccc7cc1cccULL, }, - { 0x7133c7331c337133ULL, 0x1c337133c7331c33ULL, }, - { 0x718ec7381ce3718eULL, 0x1ce3718ec7381ce3ULL, }, - { 0x7171c7c71c1c7171ULL, 0x1c1c7171c7c71c1cULL, }, - { 0x2828626255554040ULL, 0x88886a6ae6e6ccccULL, }, /* 64 */ - { 0x284d629355c74008ULL, 0x88fb6abee600cc63ULL, }, - { 0x28b962cf558b4080ULL, 0x88ac6a5ae6aeccaaULL, }, - { 0x285e623155e2404eULL, 0x88706a4fe616cc4dULL, }, - { 0x4d289362c7550840ULL, 0xfb88be6a00e663ccULL, }, - { 0x4d4d9393c7c70808ULL, 0xfbfbbebe00006363ULL, }, - { 0x4db993cfc78b0880ULL, 0xfbacbe5a00ae63aaULL, }, - { 0x4d5e9331c7e2084eULL, 0xfb70be4f0016634dULL, }, - { 0xb928cf628b558040ULL, 0xac885a6aaee6aaccULL, }, /* 72 */ - { 0xb94dcf938bc78008ULL, 0xacfb5abeae00aa63ULL, }, - { 0xb9b9cfcf8b8b8080ULL, 0xacac5a5aaeaeaaaaULL, }, - { 0xb95ecf318be2804eULL, 0xac705a4fae16aa4dULL, }, - { 0x5e283162e2554e40ULL, 0x70884f6a16e64dccULL, }, - { 0x5e4d3193e2c74e08ULL, 0x70fb4fbe16004d63ULL, }, - { 0x5eb931cfe28b4e80ULL, 0x70ac4f5a16ae4daaULL, }, - { 0x5e5e3131e2e24e4eULL, 0x70704f4f16164d4dULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_d.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_d.c deleted file mode 100644 index a80aa446f8a8..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVR.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVR.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0xe38e38e38e38e38eULL, }, /* 48 */ - { 0x0000000000000000ULL, 0xe38e38e38e38e38eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555555ULL, 0xe38e38e38e38e38eULL, }, - { 0xccccccccccccccccULL, 0xe38e38e38e38e38eULL, }, - { 0x3333333333333333ULL, 0xe38e38e38e38e38eULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x1c71c71c71c71c71ULL, 0xe38e38e38e38e38eULL, }, - { 0xffffffffffffffffULL, 0x1c71c71c71c71c71ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x1c71c71c71c71c71ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x1c71c71c71c71c71ULL, }, - { 0x5555555555555555ULL, 0x1c71c71c71c71c71ULL, }, - { 0xccccccccccccccccULL, 0x1c71c71c71c71c71ULL, }, - { 0x3333333333333333ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe38e38e38e38e38eULL, 0x1c71c71c71c71c71ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c71ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x886ae6cc28625540ULL, }, - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, - { 0x886ae6cc28625540ULL, 0xfbbe00634d93c708ULL, }, - { 0xfbbe00634d93c708ULL, 0xfbbe00634d93c708ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x886ae6cc28625540ULL, 0xac5aaeaab9cf8b80ULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, - { 0xfbbe00634d93c708ULL, 0x704f164d5e31e24eULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x704f164d5e31e24eULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_h.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_h.c deleted file mode 100644 index caa00224fdfa..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVR.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVR.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffff0000ffff0000ULL, 0xffff0000ffff0000ULL, }, - { 0xffffaaaaffffaaaaULL, 0xffffaaaaffffaaaaULL, }, - { 0xffff5555ffff5555ULL, 0xffff5555ffff5555ULL, }, - { 0xffffccccffffccccULL, 0xffffccccffffccccULL, }, - { 0xffff3333ffff3333ULL, 0xffff3333ffff3333ULL, }, - { 0xffff8e38ffffe38eULL, 0xffffe38effff38e3ULL, }, - { 0xffff71c7ffff1c71ULL, 0xffff1c71ffffc71cULL, }, - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000aaaa0000aaaaULL, 0x0000aaaa0000aaaaULL, }, - { 0x0000555500005555ULL, 0x0000555500005555ULL, }, - { 0x0000cccc0000ccccULL, 0x0000cccc0000ccccULL, }, - { 0x0000333300003333ULL, 0x0000333300003333ULL, }, - { 0x00008e380000e38eULL, 0x0000e38e000038e3ULL, }, - { 0x000071c700001c71ULL, 0x00001c710000c71cULL, }, - { 0xaaaaffffaaaaffffULL, 0xaaaaffffaaaaffffULL, }, /* 16 */ - { 0xaaaa0000aaaa0000ULL, 0xaaaa0000aaaa0000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaa5555aaaa5555ULL, 0xaaaa5555aaaa5555ULL, }, - { 0xaaaaccccaaaaccccULL, 0xaaaaccccaaaaccccULL, }, - { 0xaaaa3333aaaa3333ULL, 0xaaaa3333aaaa3333ULL, }, - { 0xaaaa8e38aaaae38eULL, 0xaaaae38eaaaa38e3ULL, }, - { 0xaaaa71c7aaaa1c71ULL, 0xaaaa1c71aaaac71cULL, }, - { 0x5555ffff5555ffffULL, 0x5555ffff5555ffffULL, }, /* 24 */ - { 0x5555000055550000ULL, 0x5555000055550000ULL, }, - { 0x5555aaaa5555aaaaULL, 0x5555aaaa5555aaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555cccc5555ccccULL, 0x5555cccc5555ccccULL, }, - { 0x5555333355553333ULL, 0x5555333355553333ULL, }, - { 0x55558e385555e38eULL, 0x5555e38e555538e3ULL, }, - { 0x555571c755551c71ULL, 0x55551c715555c71cULL, }, - { 0xccccffffccccffffULL, 0xccccffffccccffffULL, }, /* 32 */ - { 0xcccc0000cccc0000ULL, 0xcccc0000cccc0000ULL, }, - { 0xccccaaaaccccaaaaULL, 0xccccaaaaccccaaaaULL, }, - { 0xcccc5555cccc5555ULL, 0xcccc5555cccc5555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccc3333cccc3333ULL, 0xcccc3333cccc3333ULL, }, - { 0xcccc8e38cccce38eULL, 0xcccce38ecccc38e3ULL, }, - { 0xcccc71c7cccc1c71ULL, 0xcccc1c71ccccc71cULL, }, - { 0x3333ffff3333ffffULL, 0x3333ffff3333ffffULL, }, /* 40 */ - { 0x3333000033330000ULL, 0x3333000033330000ULL, }, - { 0x3333aaaa3333aaaaULL, 0x3333aaaa3333aaaaULL, }, - { 0x3333555533335555ULL, 0x3333555533335555ULL, }, - { 0x3333cccc3333ccccULL, 0x3333cccc3333ccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x33338e383333e38eULL, 0x3333e38e333338e3ULL, }, - { 0x333371c733331c71ULL, 0x33331c713333c71cULL, }, - { 0x8e38ffffe38effffULL, 0xe38effff38e3ffffULL, }, /* 48 */ - { 0x8e380000e38e0000ULL, 0xe38e000038e30000ULL, }, - { 0x8e38aaaae38eaaaaULL, 0xe38eaaaa38e3aaaaULL, }, - { 0x8e385555e38e5555ULL, 0xe38e555538e35555ULL, }, - { 0x8e38cccce38eccccULL, 0xe38ecccc38e3ccccULL, }, - { 0x8e383333e38e3333ULL, 0xe38e333338e33333ULL, }, - { 0x8e388e38e38ee38eULL, 0xe38ee38e38e338e3ULL, }, - { 0x8e3871c7e38e1c71ULL, 0xe38e1c7138e3c71cULL, }, - { 0x71c7ffff1c71ffffULL, 0x1c71ffffc71cffffULL, }, /* 56 */ - { 0x71c700001c710000ULL, 0x1c710000c71c0000ULL, }, - { 0x71c7aaaa1c71aaaaULL, 0x1c71aaaac71caaaaULL, }, - { 0x71c755551c715555ULL, 0x1c715555c71c5555ULL, }, - { 0x71c7cccc1c71ccccULL, 0x1c71ccccc71cccccULL, }, - { 0x71c733331c713333ULL, 0x1c713333c71c3333ULL, }, - { 0x71c78e381c71e38eULL, 0x1c71e38ec71c38e3ULL, }, - { 0x71c771c71c711c71ULL, 0x1c711c71c71cc71cULL, }, - { 0x2862286255405540ULL, 0x886a886ae6cce6ccULL, }, /* 64 */ - { 0x28624d935540c708ULL, 0x886afbbee6cc0063ULL, }, - { 0x2862b9cf55408b80ULL, 0x886aac5ae6ccaeaaULL, }, - { 0x28625e315540e24eULL, 0x886a704fe6cc164dULL, }, - { 0x4d932862c7085540ULL, 0xfbbe886a0063e6ccULL, }, - { 0x4d934d93c708c708ULL, 0xfbbefbbe00630063ULL, }, - { 0x4d93b9cfc7088b80ULL, 0xfbbeac5a0063aeaaULL, }, - { 0x4d935e31c708e24eULL, 0xfbbe704f0063164dULL, }, - { 0xb9cf28628b805540ULL, 0xac5a886aaeaae6ccULL, }, /* 72 */ - { 0xb9cf4d938b80c708ULL, 0xac5afbbeaeaa0063ULL, }, - { 0xb9cfb9cf8b808b80ULL, 0xac5aac5aaeaaaeaaULL, }, - { 0xb9cf5e318b80e24eULL, 0xac5a704faeaa164dULL, }, - { 0x5e312862e24e5540ULL, 0x704f886a164de6ccULL, }, - { 0x5e314d93e24ec708ULL, 0x704ffbbe164d0063ULL, }, - { 0x5e31b9cfe24e8b80ULL, 0x704fac5a164daeaaULL, }, - { 0x5e315e31e24ee24eULL, 0x704f704f164d164dULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_w.c b/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_w.c deleted file mode 100644 index 65c89a37121c..000000000000 --- a/tests/tcg/mips/user/ase/msa/interleave/test_msa_ilvr_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction ILVR.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Interleave"; - char *instruction_name = "ILVR.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffff00000000ULL, 0xffffffff00000000ULL, }, - { 0xffffffffaaaaaaaaULL, 0xffffffffaaaaaaaaULL, }, - { 0xffffffff55555555ULL, 0xffffffff55555555ULL, }, - { 0xffffffffccccccccULL, 0xffffffffccccccccULL, }, - { 0xffffffff33333333ULL, 0xffffffff33333333ULL, }, - { 0xffffffff8e38e38eULL, 0xffffffffe38e38e3ULL, }, - { 0xffffffff71c71c71ULL, 0xffffffff1c71c71cULL, }, - { 0x00000000ffffffffULL, 0x00000000ffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x00000000aaaaaaaaULL, 0x00000000aaaaaaaaULL, }, - { 0x0000000055555555ULL, 0x0000000055555555ULL, }, - { 0x00000000ccccccccULL, 0x00000000ccccccccULL, }, - { 0x0000000033333333ULL, 0x0000000033333333ULL, }, - { 0x000000008e38e38eULL, 0x00000000e38e38e3ULL, }, - { 0x0000000071c71c71ULL, 0x000000001c71c71cULL, }, - { 0xaaaaaaaaffffffffULL, 0xaaaaaaaaffffffffULL, }, /* 16 */ - { 0xaaaaaaaa00000000ULL, 0xaaaaaaaa00000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaa55555555ULL, 0xaaaaaaaa55555555ULL, }, - { 0xaaaaaaaaccccccccULL, 0xaaaaaaaaccccccccULL, }, - { 0xaaaaaaaa33333333ULL, 0xaaaaaaaa33333333ULL, }, - { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaae38e38e3ULL, }, - { 0xaaaaaaaa71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, - { 0x55555555ffffffffULL, 0x55555555ffffffffULL, }, /* 24 */ - { 0x5555555500000000ULL, 0x5555555500000000ULL, }, - { 0x55555555aaaaaaaaULL, 0x55555555aaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x55555555ccccccccULL, 0x55555555ccccccccULL, }, - { 0x5555555533333333ULL, 0x5555555533333333ULL, }, - { 0x555555558e38e38eULL, 0x55555555e38e38e3ULL, }, - { 0x5555555571c71c71ULL, 0x555555551c71c71cULL, }, - { 0xccccccccffffffffULL, 0xccccccccffffffffULL, }, /* 32 */ - { 0xcccccccc00000000ULL, 0xcccccccc00000000ULL, }, - { 0xccccccccaaaaaaaaULL, 0xccccccccaaaaaaaaULL, }, - { 0xcccccccc55555555ULL, 0xcccccccc55555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xcccccccc33333333ULL, 0xcccccccc33333333ULL, }, - { 0xcccccccc8e38e38eULL, 0xcccccccce38e38e3ULL, }, - { 0xcccccccc71c71c71ULL, 0xcccccccc1c71c71cULL, }, - { 0x33333333ffffffffULL, 0x33333333ffffffffULL, }, /* 40 */ - { 0x3333333300000000ULL, 0x3333333300000000ULL, }, - { 0x33333333aaaaaaaaULL, 0x33333333aaaaaaaaULL, }, - { 0x3333333355555555ULL, 0x3333333355555555ULL, }, - { 0x33333333ccccccccULL, 0x33333333ccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x333333338e38e38eULL, 0x33333333e38e38e3ULL, }, - { 0x3333333371c71c71ULL, 0x333333331c71c71cULL, }, - { 0x8e38e38effffffffULL, 0xe38e38e3ffffffffULL, }, /* 48 */ - { 0x8e38e38e00000000ULL, 0xe38e38e300000000ULL, }, - { 0x8e38e38eaaaaaaaaULL, 0xe38e38e3aaaaaaaaULL, }, - { 0x8e38e38e55555555ULL, 0xe38e38e355555555ULL, }, - { 0x8e38e38eccccccccULL, 0xe38e38e3ccccccccULL, }, - { 0x8e38e38e33333333ULL, 0xe38e38e333333333ULL, }, - { 0x8e38e38e8e38e38eULL, 0xe38e38e3e38e38e3ULL, }, - { 0x8e38e38e71c71c71ULL, 0xe38e38e31c71c71cULL, }, - { 0x71c71c71ffffffffULL, 0x1c71c71cffffffffULL, }, /* 56 */ - { 0x71c71c7100000000ULL, 0x1c71c71c00000000ULL, }, - { 0x71c71c71aaaaaaaaULL, 0x1c71c71caaaaaaaaULL, }, - { 0x71c71c7155555555ULL, 0x1c71c71c55555555ULL, }, - { 0x71c71c71ccccccccULL, 0x1c71c71cccccccccULL, }, - { 0x71c71c7133333333ULL, 0x1c71c71c33333333ULL, }, - { 0x71c71c718e38e38eULL, 0x1c71c71ce38e38e3ULL, }, - { 0x71c71c7171c71c71ULL, 0x1c71c71c1c71c71cULL, }, - { 0x2862554028625540ULL, 0x886ae6cc886ae6ccULL, }, /* 64 */ - { 0x286255404d93c708ULL, 0x886ae6ccfbbe0063ULL, }, - { 0x28625540b9cf8b80ULL, 0x886ae6ccac5aaeaaULL, }, - { 0x286255405e31e24eULL, 0x886ae6cc704f164dULL, }, - { 0x4d93c70828625540ULL, 0xfbbe0063886ae6ccULL, }, - { 0x4d93c7084d93c708ULL, 0xfbbe0063fbbe0063ULL, }, - { 0x4d93c708b9cf8b80ULL, 0xfbbe0063ac5aaeaaULL, }, - { 0x4d93c7085e31e24eULL, 0xfbbe0063704f164dULL, }, - { 0xb9cf8b8028625540ULL, 0xac5aaeaa886ae6ccULL, }, /* 72 */ - { 0xb9cf8b804d93c708ULL, 0xac5aaeaafbbe0063ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xac5aaeaaac5aaeaaULL, }, - { 0xb9cf8b805e31e24eULL, 0xac5aaeaa704f164dULL, }, - { 0x5e31e24e28625540ULL, 0x704f164d886ae6ccULL, }, - { 0x5e31e24e4d93c708ULL, 0x704f164dfbbe0063ULL, }, - { 0x5e31e24eb9cf8b80ULL, 0x704f164dac5aaeaaULL, }, - { 0x5e31e24e5e31e24eULL, 0x704f164d704f164dULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_ILVR_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/logic/test_msa_and_v.c b/tests/tcg/mips/user/ase/msa/logic/test_msa_and_v.c deleted file mode 100644 index 22d1f9cc0f50..000000000000 --- a/tests/tcg/mips/user/ase/msa/logic/test_msa_and_v.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction AND.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Logic"; - char *instruction_name = "AND.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0xa28a28a28a28a28aULL, 0x28a28a28a28a28a2ULL, }, - { 0x0820820820820820ULL, 0x8208208208208208ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4104104104104104ULL, 0x1041041041041041ULL, }, - { 0x1451451451451451ULL, 0x4514514514514514ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xc08c08c08c08c08cULL, 0x08c08c08c08c08c0ULL, }, - { 0x0c40c40c40c40c40ULL, 0xc40c40c40c40c40cULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x2302302302302302ULL, 0x3023023023023023ULL, }, - { 0x1031031031031031ULL, 0x0310310310310310ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xa28a28a28a28a28aULL, 0x28a28a28a28a28a2ULL, }, - { 0x4104104104104104ULL, 0x1041041041041041ULL, }, - { 0xc08c08c08c08c08cULL, 0x08c08c08c08c08c0ULL, }, - { 0x2302302302302302ULL, 0x3023023023023023ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0820820820820820ULL, 0x8208208208208208ULL, }, - { 0x1451451451451451ULL, 0x4514514514514514ULL, }, - { 0x0c40c40c40c40c40ULL, 0xc40c40c40c40c40cULL, }, - { 0x1031031031031031ULL, 0x0310310310310310ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x882a004008024500ULL, 0x02670b1a143b100cULL, }, - { 0x884aa68828420100ULL, 0x0340025eaa2b2004ULL, }, - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, - { 0x882a004008024500ULL, 0x02670b1a143b100cULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xa81a002209838300ULL, 0x02d0821a012b0014ULL, }, - { 0x700e00414c11c208ULL, 0x00f18818010242a0ULL, }, - { 0x884aa68828420100ULL, 0x0340025eaa2b2004ULL, }, /* 72 */ - { 0xa81a002209838300ULL, 0x02d0821a012b0014ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x204a060818018200ULL, 0x05d080d8a9022000ULL, }, - { 0x004a064c08204040ULL, 0x09610858a842a000ULL, }, - { 0x700e00414c11c208ULL, 0x00f18818010242a0ULL, }, - { 0x204a060818018200ULL, 0x05d080d8a9022000ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_AND_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_AND_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/logic/test_msa_nor_v.c b/tests/tcg/mips/user/ase/msa/logic/test_msa_nor_v.c deleted file mode 100644 index 3b9e48158298..000000000000 --- a/tests/tcg/mips/user/ase/msa/logic/test_msa_nor_v.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction NOR.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Logic"; - char *instruction_name = "NOR.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x1451451451451451ULL, 0x4514514514514514ULL, }, - { 0x4104104104104104ULL, 0x1041041041041041ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x0820820820820820ULL, 0x8208208208208208ULL, }, - { 0xa28a28a28a28a28aULL, 0x28a28a28a28a28a2ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x1111111111111111ULL, 0x1111111111111111ULL, }, - { 0x2222222222222222ULL, 0x2222222222222222ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x1031031031031031ULL, 0x0310310310310310ULL, }, - { 0x2302302302302302ULL, 0x3023023023023023ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x4444444444444444ULL, 0x4444444444444444ULL, }, - { 0x8888888888888888ULL, 0x8888888888888888ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0c40c40c40c40c40ULL, 0xc40c40c40c40c40cULL, }, - { 0xc08c08c08c08c08cULL, 0x08c08c08c08c08c0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1451451451451451ULL, 0x4514514514514514ULL, }, - { 0x0820820820820820ULL, 0x8208208208208208ULL, }, - { 0x1031031031031031ULL, 0x0310310310310310ULL, }, - { 0x0c40c40c40c40c40ULL, 0xc40c40c40c40c40cULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x4104104104104104ULL, 0x1041041041041041ULL, }, - { 0xa28a28a28a28a28aULL, 0x28a28a28a28a28a2ULL, }, - { 0x2302302302302302ULL, 0x3023023023023023ULL, }, - { 0xc08c08c08c08c08cULL, 0x08c08c08c08c08c0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x77951933d79daabfULL, 0xb498f4a101844ff3ULL, }, /* 64 */ - { 0x04011910920c28b7ULL, 0xa40844a100800d03ULL, }, - { 0x538511114610203fULL, 0x9000300000844ae3ULL, }, - { 0x07900932818c08b1ULL, 0x3008742100840d53ULL, }, - { 0x04011910920c28b7ULL, 0xa40844a100800d03ULL, }, - { 0x0441ff9cb26c38f7ULL, 0xed0844e5eac0ad03ULL, }, - { 0x0001511402203077ULL, 0xc800000040c08803ULL, }, - { 0x0400e990a04c18b1ULL, 0x6008442542800d03ULL, }, - { 0x538511114610203fULL, 0x9000300000844ae3ULL, }, /* 72 */ - { 0x0001511402203077ULL, 0xc800000040c08803ULL, }, - { 0x53a551554630747fULL, 0xd827390054d4daebULL, }, - { 0x03a0411000001431ULL, 0x500631005494184bULL, }, - { 0x07900932818c08b1ULL, 0x3008742100840d53ULL, }, - { 0x0400e990a04c18b1ULL, 0x6008442542800d03ULL, }, - { 0x03a0411000001431ULL, 0x500631005494184bULL, }, - { 0x8fb0e9b2a1ce1db1ULL, 0x720e772756bd1d5fULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_NOR_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_NOR_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/logic/test_msa_or_v.c b/tests/tcg/mips/user/ase/msa/logic/test_msa_or_v.c deleted file mode 100644 index e6e5da4efb4e..000000000000 --- a/tests/tcg/mips/user/ase/msa/logic/test_msa_or_v.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction OR.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Logic"; - char *instruction_name = "OR.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0xebaebaebaebaebaeULL, 0xbaebaebaebaebaebULL, }, - { 0xbefbefbefbefbefbULL, 0xefbefbefbefbefbeULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xf7df7df7df7df7dfULL, 0x7df7df7df7df7df7ULL, }, - { 0x5d75d75d75d75d75ULL, 0xd75d75d75d75d75dULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xeeeeeeeeeeeeeeeeULL, 0xeeeeeeeeeeeeeeeeULL, }, - { 0xddddddddddddddddULL, 0xddddddddddddddddULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xefcefcefcefcefceULL, 0xfcefcefcefcefcefULL, }, - { 0xdcfdcfdcfdcfdcfdULL, 0xcfdcfdcfdcfdcfdcULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xbbbbbbbbbbbbbbbbULL, 0xbbbbbbbbbbbbbbbbULL, }, - { 0x7777777777777777ULL, 0x7777777777777777ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xf3bf3bf3bf3bf3bfULL, 0x3bf3bf3bf3bf3bf3ULL, }, - { 0x3f73f73f73f73f73ULL, 0xf73f73f73f73f73fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xebaebaebaebaebaeULL, 0xbaebaebaebaebaebULL, }, - { 0xf7df7df7df7df7dfULL, 0x7df7df7df7df7df7ULL, }, - { 0xefcefcefcefcefceULL, 0xfcefcefcefcefcefULL, }, - { 0xf3bf3bf3bf3bf3bfULL, 0x3bf3bf3bf3bf3bf3ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xbefbefbefbefbefbULL, 0xefbefbefbefbefbeULL, }, - { 0x5d75d75d75d75d75ULL, 0xd75d75d75d75d75dULL, }, - { 0xdcfdcfdcfdcfdcfdULL, 0xcfdcfdcfdcfdcfdcULL, }, - { 0x3f73f73f73f73f73ULL, 0xf73f73f73f73f73fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbfee6ef6df3d748ULL, 0x5bf7bb5eff7ff2fcULL, }, - { 0xac7aeeeeb9efdfc0ULL, 0x6fffcfffff7bb51cULL, }, - { 0xf86ff6cd7e73f74eULL, 0xcff78bdeff7bf2acULL, }, - { 0xfbfee6ef6df3d748ULL, 0x5bf7bb5eff7ff2fcULL, }, - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xfffeaeebfddfcf88ULL, 0x37ffffffbf3f77fcULL, }, - { 0xfbff166f5fb3e74eULL, 0x9ff7bbdabd7ff2fcULL, }, - { 0xac7aeeeeb9efdfc0ULL, 0x6fffcfffff7bb51cULL, }, /* 72 */ - { 0xfffeaeebfddfcf88ULL, 0x37ffffffbf3f77fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0xfc5fbeefffffebceULL, 0xaff9ceffab6be7b4ULL, }, - { 0xf86ff6cd7e73f74eULL, 0xcff78bdeff7bf2acULL, }, - { 0xfbff166f5fb3e74eULL, 0x9ff7bbdabd7ff2fcULL, }, - { 0xfc5fbeefffffebceULL, 0xaff9ceffab6be7b4ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_OR_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_OR_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/logic/test_msa_xor_v.c b/tests/tcg/mips/user/ase/msa/logic/test_msa_xor_v.c deleted file mode 100644 index 1b699b5ca41c..000000000000 --- a/tests/tcg/mips/user/ase/msa/logic/test_msa_xor_v.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction XOR.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Logic"; - char *instruction_name = "XOR.V"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x4924924924924924ULL, 0x9249249249249249ULL, }, - { 0xb6db6db6db6db6dbULL, 0x6db6db6db6db6db6ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xb6db6db6db6db6dbULL, 0x6db6db6db6db6db6ULL, }, - { 0x4924924924924924ULL, 0x9249249249249249ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x2f42f42f42f42f42ULL, 0xf42f42f42f42f42fULL, }, - { 0xd0bd0bd0bd0bd0bdULL, 0x0bd0bd0bd0bd0bd0ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x9999999999999999ULL, 0x9999999999999999ULL, }, - { 0x6666666666666666ULL, 0x6666666666666666ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xd0bd0bd0bd0bd0bdULL, 0x0bd0bd0bd0bd0bd0ULL, }, - { 0x2f42f42f42f42f42ULL, 0xf42f42f42f42f42fULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x4924924924924924ULL, 0x9249249249249249ULL, }, - { 0xb6db6db6db6db6dbULL, 0x6db6db6db6db6db6ULL, }, - { 0x2f42f42f42f42f42ULL, 0xf42f42f42f42f42fULL, }, - { 0xd0bd0bd0bd0bd0bdULL, 0x0bd0bd0bd0bd0bd0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xb6db6db6db6db6dbULL, 0x6db6db6db6db6db6ULL, }, - { 0x4924924924924924ULL, 0x9249249249249249ULL, }, - { 0xd0bd0bd0bd0bd0bdULL, 0x0bd0bd0bd0bd0bd0ULL, }, - { 0x2f42f42f42f42f42ULL, 0xf42f42f42f42f42fULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ - { 0x73d4e6af65f19248ULL, 0x5990b044eb44e2f0ULL, }, - { 0x2430486691addec0ULL, 0x6cbfcda155509518ULL, }, - { 0xf825f0817653b70eULL, 0xc6968386573952acULL, }, - { 0x73d4e6af65f19248ULL, 0x5990b044eb44e2f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x57e4aec9f45c4c88ULL, 0x352f7de5be1477e8ULL, }, - { 0x8bf1162e13a22546ULL, 0x9f0633c2bc7db05cULL, }, - { 0x2430486691addec0ULL, 0x6cbfcda155509518ULL, }, /* 72 */ - { 0x57e4aec9f45c4c88ULL, 0x352f7de5be1477e8ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xdc15b8e7e7fe69ceULL, 0xaa294e270269c7b4ULL, }, - { 0xf825f0817653b70eULL, 0xc6968386573952acULL, }, - { 0x8bf1162e13a22546ULL, 0x9f0633c2bc7db05cULL, }, - { 0xdc15b8e7e7fe69ceULL, 0xaa294e270269c7b4ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_XOR_V(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_XOR_V(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/move/test_msa_move_v.c b/tests/tcg/mips/user/ase/msa/move/test_msa_move_v.c deleted file mode 100644 index ef2aa6dbddeb..000000000000 --- a/tests/tcg/mips/user/ase/msa/move/test_msa_move_v.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Test program for MSA instruction MOVE.V - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_COUNT + RANDOM_INPUTS_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Move"; - char *instruction_name = "MOVE.V"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL, }, /* 8 */ - { 0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL, }, - { 0xf83e0f83e0f83e0fULL, 0x83e0f83e0f83e0f8ULL, }, - { 0x07c1f07c1f07c1f0ULL, 0x7c1f07c1f07c1f07ULL, }, - { 0xfc0fc0fc0fc0fc0fULL, 0xc0fc0fc0fc0fc0fcULL, }, - { 0x03f03f03f03f03f0ULL, 0x3f03f03f03f03f03ULL, }, - { 0xfe03f80fe03f80feULL, 0x03f80fe03f80fe03ULL, }, - { 0x01fc07f01fc07f01ULL, 0xfc07f01fc07f01fcULL, }, - { 0xff00ff00ff00ff00ULL, 0xff00ff00ff00ff00ULL, }, /* 16 */ - { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, }, - { 0xff803fe00ff803feULL, 0x00ff803fe00ff803ULL, }, - { 0x007fc01ff007fc01ULL, 0xff007fc01ff007fcULL, }, - { 0xffc00ffc00ffc00fULL, 0xfc00ffc00ffc00ffULL, }, - { 0x003ff003ff003ff0ULL, 0x03ff003ff003ff00ULL, }, - { 0xffe003ff800ffe00ULL, 0x3ff800ffe003ff80ULL, }, - { 0x001ffc007ff001ffULL, 0xc007ff001ffc007fULL, }, - { 0xfff000fff000fff0ULL, 0x00fff000fff000ffULL, }, /* 24 */ - { 0x000fff000fff000fULL, 0xff000fff000fff00ULL, }, - { 0xfff8003ffe000fffULL, 0x8003ffe000fff800ULL, }, - { 0x0007ffc001fff000ULL, 0x7ffc001fff0007ffULL, }, - { 0xfffc000fffc000ffULL, 0xfc000fffc000fffcULL, }, - { 0x0003fff0003fff00ULL, 0x03fff0003fff0003ULL, }, - { 0xfffe0003fff8000fULL, 0xffe0003fff8000ffULL, }, - { 0x0001fffc0007fff0ULL, 0x001fffc0007fff00ULL, }, - { 0xffff0000ffff0000ULL, 0xffff0000ffff0000ULL, }, /* 32 */ - { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, }, - { 0xffff80003fffe000ULL, 0x0ffff80003fffe00ULL, }, - { 0x00007fffc0001fffULL, 0xf00007fffc0001ffULL, }, - { 0xffffc0000ffffc00ULL, 0x00ffffc0000ffffcULL, }, - { 0x00003ffff00003ffULL, 0xff00003ffff00003ULL, }, - { 0xffffe00003ffff80ULL, 0x000ffffe00003fffULL, }, - { 0x00001ffffc00007fULL, 0xfff00001ffffc000ULL, }, - { 0xfffff00000fffff0ULL, 0x0000fffff00000ffULL, }, /* 40 */ - { 0x00000fffff00000fULL, 0xffff00000fffff00ULL, }, - { 0xfffff800003ffffeULL, 0x00000fffff800003ULL, }, - { 0x000007ffffc00001ULL, 0xfffff000007ffffcULL, }, - { 0xfffffc00000fffffULL, 0xc00000fffffc0000ULL, }, - { 0x000003fffff00000ULL, 0x3fffff000003ffffULL, }, - { 0xfffffe000003ffffULL, 0xf800000fffffe000ULL, }, - { 0x000001fffffc0000ULL, 0x07fffff000001fffULL, }, - { 0xffffff000000ffffULL, 0xff000000ffffff00ULL, }, /* 48 */ - { 0x000000ffffff0000ULL, 0x00ffffff000000ffULL, }, - { 0xffffff8000003fffULL, 0xffe000000ffffff8ULL, }, - { 0x0000007fffffc000ULL, 0x001ffffff0000007ULL, }, - { 0xffffffc000000fffULL, 0xfffc000000ffffffULL, }, - { 0x0000003ffffff000ULL, 0x0003ffffff000000ULL, }, - { 0xffffffe0000003ffULL, 0xffff8000000fffffULL, }, - { 0x0000001ffffffc00ULL, 0x00007ffffff00000ULL, }, - { 0xfffffff0000000ffULL, 0xfffff0000000ffffULL, }, /* 56 */ - { 0x0000000fffffff00ULL, 0x00000fffffff0000ULL, }, - { 0xfffffff80000003fULL, 0xfffffe0000000fffULL, }, - { 0x00000007ffffffc0ULL, 0x000001fffffff000ULL, }, - { 0xfffffffc0000000fULL, 0xffffffc0000000ffULL, }, - { 0x00000003fffffff0ULL, 0x0000003fffffff00ULL, }, - { 0xfffffffe00000003ULL, 0xfffffff80000000fULL, }, - { 0x00000001fffffffcULL, 0x00000007fffffff0ULL, }, - { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, - { 0xb9926b7c7daf4258ULL, 0xa1227caddcce65b6ULL, }, - { 0xd027be89ff0a2ef9ULL, 0x170b5050fea53078ULL, }, - { 0xb83b580665cabc4aULL, 0x91230822bff0ba62ULL, }, - { 0xfc8f23f09aa6b782ULL, 0x93fd6637124275aeULL, }, - { 0x201e09cd56aee649ULL, 0xef5de039a6a52758ULL, }, /* 72 */ - { 0xa57cd91365d9e5d7ULL, 0x9321bc9881ecba5cULL, }, - { 0xa2e8f6f5c9cbc61bULL, 0xb2c471545e0d7a12ULL, }, - { 0xa89cf2f131a864aeULL, 0xd2a3e87a5db986e7ULL, }, - { 0xe61438e9a652ea0aULL, 0xa85483d97879d41cULL, }, - { 0x944a35fd192361a8ULL, 0xf3912da36a0b2d6bULL, }, - { 0x4630426322bef79cULL, 0xeb5686f7cb19304eULL, }, - { 0x8b5aa7a2f259deadULL, 0xd278cbcd696417e3ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_COUNT) { - do_msa_MOVE_V(b128_pattern[i], b128_result[i]); - } else { - do_msa_MOVE_V(b128_random[i - PATTERN_INPUTS_COUNT], - b128_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_b.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_b.c deleted file mode 100644 index 2f4ffd919588..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKEV.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKEV.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0xe3388ee38ee3388eULL, 0xffffffffffffffffULL, }, - { 0x1cc7711c711cc771ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0xe3388ee38ee3388eULL, 0x0000000000000000ULL, }, - { 0x1cc7711c711cc771ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe3388ee38ee3388eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1cc7711c711cc771ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0xe3388ee38ee3388eULL, 0x5555555555555555ULL, }, - { 0x1cc7711c711cc771ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0xe3388ee38ee3388eULL, 0xccccccccccccccccULL, }, - { 0x1cc7711c711cc771ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe3388ee38ee3388eULL, 0x3333333333333333ULL, }, - { 0x1cc7711c711cc771ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0xe3388ee38ee3388eULL, }, /* 48 */ - { 0x0000000000000000ULL, 0xe3388ee38ee3388eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xe3388ee38ee3388eULL, }, - { 0x5555555555555555ULL, 0xe3388ee38ee3388eULL, }, - { 0xccccccccccccccccULL, 0xe3388ee38ee3388eULL, }, - { 0x3333333333333333ULL, 0xe3388ee38ee3388eULL, }, - { 0xe3388ee38ee3388eULL, 0xe3388ee38ee3388eULL, }, - { 0x1cc7711c711cc771ULL, 0xe3388ee38ee3388eULL, }, - { 0xffffffffffffffffULL, 0x1cc7711c711cc771ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x1cc7711c711cc771ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x1cc7711c711cc771ULL, }, - { 0x5555555555555555ULL, 0x1cc7711c711cc771ULL, }, - { 0xccccccccccccccccULL, 0x1cc7711c711cc771ULL, }, - { 0x3333333333333333ULL, 0x1cc7711c711cc771ULL, }, - { 0xe3388ee38ee3388eULL, 0x1cc7711c711cc771ULL, }, - { 0x1cc7711c711cc771ULL, 0x1cc7711c711cc771ULL, }, - { 0x675e7b0c6acc6240ULL, 0x675e7b0c6acc6240ULL, }, /* 64 */ - { 0xf71a3ffcbe639308ULL, 0x675e7b0c6acc6240ULL, }, - { 0xd8ff2b145aaacf80ULL, 0x675e7b0c6acc6240ULL, }, - { 0xf1d842a04f4d314eULL, 0x675e7b0c6acc6240ULL, }, - { 0x675e7b0c6acc6240ULL, 0xf71a3ffcbe639308ULL, }, - { 0xf71a3ffcbe639308ULL, 0xf71a3ffcbe639308ULL, }, - { 0xd8ff2b145aaacf80ULL, 0xf71a3ffcbe639308ULL, }, - { 0xf1d842a04f4d314eULL, 0xf71a3ffcbe639308ULL, }, - { 0x675e7b0c6acc6240ULL, 0xd8ff2b145aaacf80ULL, }, /* 72 */ - { 0xf71a3ffcbe639308ULL, 0xd8ff2b145aaacf80ULL, }, - { 0xd8ff2b145aaacf80ULL, 0xd8ff2b145aaacf80ULL, }, - { 0xf1d842a04f4d314eULL, 0xd8ff2b145aaacf80ULL, }, - { 0x675e7b0c6acc6240ULL, 0xf1d842a04f4d314eULL, }, - { 0xf71a3ffcbe639308ULL, 0xf1d842a04f4d314eULL, }, - { 0xd8ff2b145aaacf80ULL, 0xf1d842a04f4d314eULL, }, - { 0xf1d842a04f4d314eULL, 0xf1d842a04f4d314eULL, }, - { 0x675e7b0c6acc6240ULL, 0xd8a04d4ed8a04d4eULL, }, /* 80 */ - { 0xf71a3ffcbe639308ULL, 0xa04ea04e5e0ccc40ULL, }, - { 0xd8ff2b145aaacf80ULL, 0x4e4e0c401afc6308ULL, }, - { 0xf1d842a04f4d314eULL, 0x4e40fc08ff14aa80ULL, }, - { 0x675e7b0c6acc6240ULL, 0x40081480d8a04d4eULL, }, - { 0xf71a3ffcbe639308ULL, 0x0880a04e5e0ccc40ULL, }, - { 0xd8ff2b145aaacf80ULL, 0x804e0c401afc6308ULL, }, - { 0xf1d842a04f4d314eULL, 0x4e40fc08ff14aa80ULL, }, - { 0x675e7b0c6acc6240ULL, 0x40081480d8a04d4eULL, }, /* 88 */ - { 0xf71a3ffcbe639308ULL, 0x0880a04e5e0ccc40ULL, }, - { 0xd8ff2b145aaacf80ULL, 0x804e0c401afc6308ULL, }, - { 0xf1d842a04f4d314eULL, 0x4e40fc08ff14aa80ULL, }, - { 0x675e7b0c6acc6240ULL, 0x40081480d8a04d4eULL, }, - { 0xf71a3ffcbe639308ULL, 0x0880a04e5e0ccc40ULL, }, - { 0xd8ff2b145aaacf80ULL, 0x804e0c401afc6308ULL, }, - { 0xf1d842a04f4d314eULL, 0x4e40fc08ff14aa80ULL, }, - { 0x40081480d8a04d4eULL, 0x675e7b0c6acc6240ULL, }, /* 96 */ - { 0x5e0ccc400880a04eULL, 0x675e7b0c6acc6240ULL, }, - { 0x5e0ccc400c40804eULL, 0x675e7b0c6acc6240ULL, }, - { 0x5e0ccc400c40404eULL, 0x675e7b0c6acc6240ULL, }, - { 0x5e0ccc400c40404eULL, 0xf71a3ffcbe639308ULL, }, - { 0x1afc63080c40404eULL, 0xf71a3ffcbe639308ULL, }, - { 0x1afc6308fc08404eULL, 0xf71a3ffcbe639308ULL, }, - { 0x1afc6308fc08084eULL, 0xf71a3ffcbe639308ULL, }, - { 0x1afc6308fc08084eULL, 0xd8ff2b145aaacf80ULL, }, /* 104 */ - { 0xff14aa80fc08084eULL, 0xd8ff2b145aaacf80ULL, }, - { 0xff14aa801480084eULL, 0xd8ff2b145aaacf80ULL, }, - { 0xff14aa801480804eULL, 0xd8ff2b145aaacf80ULL, }, - { 0xff14aa801480804eULL, 0xf1d842a04f4d314eULL, }, - { 0xd8a04d4e1480804eULL, 0xf1d842a04f4d314eULL, }, - { 0xd8a04d4ea04e804eULL, 0xf1d842a04f4d314eULL, }, - { 0xd8a04d4ea04e4e4eULL, 0xf1d842a04f4d314eULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_d.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_d.c deleted file mode 100644 index 3f0bd47ffdd2..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKEV.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKEV.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0xe38e38e38e38e38eULL, }, /* 48 */ - { 0x0000000000000000ULL, 0xe38e38e38e38e38eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555555ULL, 0xe38e38e38e38e38eULL, }, - { 0xccccccccccccccccULL, 0xe38e38e38e38e38eULL, }, - { 0x3333333333333333ULL, 0xe38e38e38e38e38eULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x1c71c71c71c71c71ULL, 0xe38e38e38e38e38eULL, }, - { 0xffffffffffffffffULL, 0x1c71c71c71c71c71ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x1c71c71c71c71c71ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x1c71c71c71c71c71ULL, }, - { 0x5555555555555555ULL, 0x1c71c71c71c71c71ULL, }, - { 0xccccccccccccccccULL, 0x1c71c71c71c71c71ULL, }, - { 0x3333333333333333ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe38e38e38e38e38eULL, 0x1c71c71c71c71c71ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c71ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 64 */ - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x886ae6cc28625540ULL, }, - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, - { 0x886ae6cc28625540ULL, 0xfbbe00634d93c708ULL, }, - { 0xfbbe00634d93c708ULL, 0xfbbe00634d93c708ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x886ae6cc28625540ULL, 0xac5aaeaab9cf8b80ULL, }, /* 72 */ - { 0xfbbe00634d93c708ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, - { 0xfbbe00634d93c708ULL, 0x704f164d5e31e24eULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x704f164d5e31e24eULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, /* 80 */ - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, /* 88 */ - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x886ae6cc28625540ULL, 0x704f164d5e31e24eULL, }, - { 0xfbbe00634d93c708ULL, 0x886ae6cc28625540ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, /* 96 */ - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, - { 0x704f164d5e31e24eULL, 0x886ae6cc28625540ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xfbbe00634d93c708ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, /* 104 */ - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - { 0x704f164d5e31e24eULL, 0x704f164d5e31e24eULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_h.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_h.c deleted file mode 100644 index 2eae01fa75b1..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKEV.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKEV.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x8e3838e338e3e38eULL, 0xffffffffffffffffULL, }, - { 0x71c7c71cc71c1c71ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x8e3838e338e3e38eULL, 0x0000000000000000ULL, }, - { 0x71c7c71cc71c1c71ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x8e3838e338e3e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x71c7c71cc71c1c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x8e3838e338e3e38eULL, 0x5555555555555555ULL, }, - { 0x71c7c71cc71c1c71ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x8e3838e338e3e38eULL, 0xccccccccccccccccULL, }, - { 0x71c7c71cc71c1c71ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x8e3838e338e3e38eULL, 0x3333333333333333ULL, }, - { 0x71c7c71cc71c1c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x8e3838e338e3e38eULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x8e3838e338e3e38eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x8e3838e338e3e38eULL, }, - { 0x5555555555555555ULL, 0x8e3838e338e3e38eULL, }, - { 0xccccccccccccccccULL, 0x8e3838e338e3e38eULL, }, - { 0x3333333333333333ULL, 0x8e3838e338e3e38eULL, }, - { 0x8e3838e338e3e38eULL, 0x8e3838e338e3e38eULL, }, - { 0x71c7c71cc71c1c71ULL, 0x8e3838e338e3e38eULL, }, - { 0xffffffffffffffffULL, 0x71c7c71cc71c1c71ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x71c7c71cc71c1c71ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x71c7c71cc71c1c71ULL, }, - { 0x5555555555555555ULL, 0x71c7c71cc71c1c71ULL, }, - { 0xccccccccccccccccULL, 0x71c7c71cc71c1c71ULL, }, - { 0x3333333333333333ULL, 0x71c7c71cc71c1c71ULL, }, - { 0x8e3838e338e3e38eULL, 0x71c7c71cc71c1c71ULL, }, - { 0x71c7c71cc71c1c71ULL, 0x71c7c71cc71c1c71ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0x0b5eb00ce6cc5540ULL, }, /* 64 */ - { 0xbb1a52fc0063c708ULL, 0x0b5eb00ce6cc5540ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0x0b5eb00ce6cc5540ULL, }, - { 0x88d8e2a0164de24eULL, 0x0b5eb00ce6cc5540ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0xbb1a52fc0063c708ULL, }, - { 0xbb1a52fc0063c708ULL, 0xbb1a52fc0063c708ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0xbb1a52fc0063c708ULL, }, - { 0x88d8e2a0164de24eULL, 0xbb1a52fc0063c708ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0xc6ff2514aeaa8b80ULL, }, /* 72 */ - { 0xbb1a52fc0063c708ULL, 0xc6ff2514aeaa8b80ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0xc6ff2514aeaa8b80ULL, }, - { 0x88d8e2a0164de24eULL, 0xc6ff2514aeaa8b80ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0x88d8e2a0164de24eULL, }, - { 0xbb1a52fc0063c708ULL, 0x88d8e2a0164de24eULL, }, - { 0xc6ff2514aeaa8b80ULL, 0x88d8e2a0164de24eULL, }, - { 0x88d8e2a0164de24eULL, 0x88d8e2a0164de24eULL, }, - { 0x0b5eb00ce6cc5540ULL, 0xe2a0e24ee2a0e24eULL, }, /* 80 */ - { 0xbb1a52fc0063c708ULL, 0xe24ee24eb00c5540ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0xe24e554052fcc708ULL, }, - { 0x88d8e2a0164de24eULL, 0x5540c70825148b80ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0xc7088b80e2a0e24eULL, }, - { 0xbb1a52fc0063c708ULL, 0x8b80e24eb00c5540ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0xe24e554052fcc708ULL, }, - { 0x88d8e2a0164de24eULL, 0x5540c70825148b80ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0xc7088b80e2a0e24eULL, }, /* 88 */ - { 0xbb1a52fc0063c708ULL, 0x8b80e24eb00c5540ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0xe24e554052fcc708ULL, }, - { 0x88d8e2a0164de24eULL, 0x5540c70825148b80ULL, }, - { 0x0b5eb00ce6cc5540ULL, 0xc7088b80e2a0e24eULL, }, - { 0xbb1a52fc0063c708ULL, 0x8b80e24eb00c5540ULL, }, - { 0xc6ff2514aeaa8b80ULL, 0xe24e554052fcc708ULL, }, - { 0x88d8e2a0164de24eULL, 0x5540c70825148b80ULL, }, - { 0xc7088b80e2a0e24eULL, 0x0b5eb00ce6cc5540ULL, }, /* 96 */ - { 0xb00c55408b80e24eULL, 0x0b5eb00ce6cc5540ULL, }, - { 0xb00c55405540e24eULL, 0x0b5eb00ce6cc5540ULL, }, - { 0xb00c55405540e24eULL, 0x0b5eb00ce6cc5540ULL, }, - { 0xb00c55405540e24eULL, 0xbb1a52fc0063c708ULL, }, - { 0x52fcc7085540e24eULL, 0xbb1a52fc0063c708ULL, }, - { 0x52fcc708c708e24eULL, 0xbb1a52fc0063c708ULL, }, - { 0x52fcc708c708e24eULL, 0xbb1a52fc0063c708ULL, }, - { 0x52fcc708c708e24eULL, 0xc6ff2514aeaa8b80ULL, }, /* 104 */ - { 0x25148b80c708e24eULL, 0xc6ff2514aeaa8b80ULL, }, - { 0x25148b808b80e24eULL, 0xc6ff2514aeaa8b80ULL, }, - { 0x25148b808b80e24eULL, 0xc6ff2514aeaa8b80ULL, }, - { 0x25148b808b80e24eULL, 0x88d8e2a0164de24eULL, }, - { 0xe2a0e24e8b80e24eULL, 0x88d8e2a0164de24eULL, }, - { 0xe2a0e24ee24ee24eULL, 0x88d8e2a0164de24eULL, }, - { 0xe2a0e24ee24ee24eULL, 0x88d8e2a0164de24eULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_w.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_w.c deleted file mode 100644 index f7215d0e4300..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckev_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKEV.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKEV.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, - { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, - { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, - { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, - { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, - { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0xe38e38e38e38e38eULL, }, /* 48 */ - { 0x0000000000000000ULL, 0xe38e38e38e38e38eULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xe38e38e38e38e38eULL, }, - { 0x5555555555555555ULL, 0xe38e38e38e38e38eULL, }, - { 0xccccccccccccccccULL, 0xe38e38e38e38e38eULL, }, - { 0x3333333333333333ULL, 0xe38e38e38e38e38eULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x1c71c71c71c71c71ULL, 0xe38e38e38e38e38eULL, }, - { 0xffffffffffffffffULL, 0x1c71c71c71c71c71ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x1c71c71c71c71c71ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x1c71c71c71c71c71ULL, }, - { 0x5555555555555555ULL, 0x1c71c71c71c71c71ULL, }, - { 0xccccccccccccccccULL, 0x1c71c71c71c71c71ULL, }, - { 0x3333333333333333ULL, 0x1c71c71c71c71c71ULL, }, - { 0xe38e38e38e38e38eULL, 0x1c71c71c71c71c71ULL, }, - { 0x1c71c71c71c71c71ULL, 0x1c71c71c71c71c71ULL, }, - { 0xfe7bb00c28625540ULL, 0xfe7bb00c28625540ULL, }, /* 64 */ - { 0x153f52fc4d93c708ULL, 0xfe7bb00c28625540ULL, }, - { 0xab2b2514b9cf8b80ULL, 0xfe7bb00c28625540ULL, }, - { 0xa942e2a05e31e24eULL, 0xfe7bb00c28625540ULL, }, - { 0xfe7bb00c28625540ULL, 0x153f52fc4d93c708ULL, }, - { 0x153f52fc4d93c708ULL, 0x153f52fc4d93c708ULL, }, - { 0xab2b2514b9cf8b80ULL, 0x153f52fc4d93c708ULL, }, - { 0xa942e2a05e31e24eULL, 0x153f52fc4d93c708ULL, }, - { 0xfe7bb00c28625540ULL, 0xab2b2514b9cf8b80ULL, }, /* 72 */ - { 0x153f52fc4d93c708ULL, 0xab2b2514b9cf8b80ULL, }, - { 0xab2b2514b9cf8b80ULL, 0xab2b2514b9cf8b80ULL, }, - { 0xa942e2a05e31e24eULL, 0xab2b2514b9cf8b80ULL, }, - { 0xfe7bb00c28625540ULL, 0xa942e2a05e31e24eULL, }, - { 0x153f52fc4d93c708ULL, 0xa942e2a05e31e24eULL, }, - { 0xab2b2514b9cf8b80ULL, 0xa942e2a05e31e24eULL, }, - { 0xa942e2a05e31e24eULL, 0xa942e2a05e31e24eULL, }, - { 0xfe7bb00c28625540ULL, 0x5e31e24e5e31e24eULL, }, /* 80 */ - { 0x153f52fc4d93c708ULL, 0x5e31e24e28625540ULL, }, - { 0xab2b2514b9cf8b80ULL, 0x286255404d93c708ULL, }, - { 0xa942e2a05e31e24eULL, 0x4d93c708b9cf8b80ULL, }, - { 0xfe7bb00c28625540ULL, 0xb9cf8b805e31e24eULL, }, - { 0x153f52fc4d93c708ULL, 0x5e31e24e28625540ULL, }, - { 0xab2b2514b9cf8b80ULL, 0x286255404d93c708ULL, }, - { 0xa942e2a05e31e24eULL, 0x4d93c708b9cf8b80ULL, }, - { 0xfe7bb00c28625540ULL, 0xb9cf8b805e31e24eULL, }, /* 88 */ - { 0x153f52fc4d93c708ULL, 0x5e31e24e28625540ULL, }, - { 0xab2b2514b9cf8b80ULL, 0x286255404d93c708ULL, }, - { 0xa942e2a05e31e24eULL, 0x4d93c708b9cf8b80ULL, }, - { 0xfe7bb00c28625540ULL, 0xb9cf8b805e31e24eULL, }, - { 0x153f52fc4d93c708ULL, 0x5e31e24e28625540ULL, }, - { 0xab2b2514b9cf8b80ULL, 0x286255404d93c708ULL, }, - { 0xa942e2a05e31e24eULL, 0x4d93c708b9cf8b80ULL, }, - { 0xb9cf8b805e31e24eULL, 0xfe7bb00c28625540ULL, }, /* 96 */ - { 0x286255405e31e24eULL, 0xfe7bb00c28625540ULL, }, - { 0x286255405e31e24eULL, 0xfe7bb00c28625540ULL, }, - { 0x286255405e31e24eULL, 0xfe7bb00c28625540ULL, }, - { 0x286255405e31e24eULL, 0x153f52fc4d93c708ULL, }, - { 0x4d93c7085e31e24eULL, 0x153f52fc4d93c708ULL, }, - { 0x4d93c7085e31e24eULL, 0x153f52fc4d93c708ULL, }, - { 0x4d93c7085e31e24eULL, 0x153f52fc4d93c708ULL, }, - { 0x4d93c7085e31e24eULL, 0xab2b2514b9cf8b80ULL, }, /* 104 */ - { 0xb9cf8b805e31e24eULL, 0xab2b2514b9cf8b80ULL, }, - { 0xb9cf8b805e31e24eULL, 0xab2b2514b9cf8b80ULL, }, - { 0xb9cf8b805e31e24eULL, 0xab2b2514b9cf8b80ULL, }, - { 0xb9cf8b805e31e24eULL, 0xa942e2a05e31e24eULL, }, - { 0x5e31e24e5e31e24eULL, 0xa942e2a05e31e24eULL, }, - { 0x5e31e24e5e31e24eULL, 0xa942e2a05e31e24eULL, }, - { 0x5e31e24e5e31e24eULL, 0xa942e2a05e31e24eULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKEV_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_b.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_b.c deleted file mode 100644 index 63553383326c..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKOD.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKOD.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x388ee338e3388ee3ULL, 0xffffffffffffffffULL, }, - { 0xc7711cc71cc7711cULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x388ee338e3388ee3ULL, 0x0000000000000000ULL, }, - { 0xc7711cc71cc7711cULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x388ee338e3388ee3ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xc7711cc71cc7711cULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x388ee338e3388ee3ULL, 0x5555555555555555ULL, }, - { 0xc7711cc71cc7711cULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x388ee338e3388ee3ULL, 0xccccccccccccccccULL, }, - { 0xc7711cc71cc7711cULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x388ee338e3388ee3ULL, 0x3333333333333333ULL, }, - { 0xc7711cc71cc7711cULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x388ee338e3388ee3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x388ee338e3388ee3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x388ee338e3388ee3ULL, }, - { 0x5555555555555555ULL, 0x388ee338e3388ee3ULL, }, - { 0xccccccccccccccccULL, 0x388ee338e3388ee3ULL, }, - { 0x3333333333333333ULL, 0x388ee338e3388ee3ULL, }, - { 0x388ee338e3388ee3ULL, 0x388ee338e3388ee3ULL, }, - { 0xc7711cc71cc7711cULL, 0x388ee338e3388ee3ULL, }, - { 0xffffffffffffffffULL, 0xc7711cc71cc7711cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc7711cc71cc7711cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc7711cc71cc7711cULL, }, - { 0x5555555555555555ULL, 0xc7711cc71cc7711cULL, }, - { 0xccccccccccccccccULL, 0xc7711cc71cc7711cULL, }, - { 0x3333333333333333ULL, 0xc7711cc71cc7711cULL, }, - { 0x388ee338e3388ee3ULL, 0xc7711cc71cc7711cULL, }, - { 0xc7711cc71cc7711cULL, 0xc7711cc71cc7711cULL, }, - { 0x4b0bfeb088e62855ULL, 0x4b0bfeb088e62855ULL, }, /* 64 */ - { 0x12bb1552fb004dc7ULL, 0x4b0bfeb088e62855ULL, }, - { 0x27c6ab25acaeb98bULL, 0x4b0bfeb088e62855ULL, }, - { 0x8d88a9e270165ee2ULL, 0x4b0bfeb088e62855ULL, }, - { 0x4b0bfeb088e62855ULL, 0x12bb1552fb004dc7ULL, }, - { 0x12bb1552fb004dc7ULL, 0x12bb1552fb004dc7ULL, }, - { 0x27c6ab25acaeb98bULL, 0x12bb1552fb004dc7ULL, }, - { 0x8d88a9e270165ee2ULL, 0x12bb1552fb004dc7ULL, }, - { 0x4b0bfeb088e62855ULL, 0x27c6ab25acaeb98bULL, }, /* 72 */ - { 0x12bb1552fb004dc7ULL, 0x27c6ab25acaeb98bULL, }, - { 0x27c6ab25acaeb98bULL, 0x27c6ab25acaeb98bULL, }, - { 0x8d88a9e270165ee2ULL, 0x27c6ab25acaeb98bULL, }, - { 0x4b0bfeb088e62855ULL, 0x8d88a9e270165ee2ULL, }, - { 0x12bb1552fb004dc7ULL, 0x8d88a9e270165ee2ULL, }, - { 0x27c6ab25acaeb98bULL, 0x8d88a9e270165ee2ULL, }, - { 0x8d88a9e270165ee2ULL, 0x8d88a9e270165ee2ULL, }, - { 0x4b0bfeb088e62855ULL, 0x8da9705e8da9705eULL, }, /* 80 */ - { 0x12bb1552fb004dc7ULL, 0x8d708d704bfe8828ULL, }, - { 0x27c6ab25acaeb98bULL, 0x8d8d4b881215fb4dULL, }, - { 0x8d88a9e270165ee2ULL, 0x8d4b12fb27abacb9ULL, }, - { 0x4b0bfeb088e62855ULL, 0x8d1227ac8da9705eULL, }, - { 0x12bb1552fb004dc7ULL, 0x8d278d704bfe8828ULL, }, - { 0x27c6ab25acaeb98bULL, 0x8d8d4b881215fb4dULL, }, - { 0x8d88a9e270165ee2ULL, 0x8d4b12fb27abacb9ULL, }, - { 0x4b0bfeb088e62855ULL, 0x8d1227ac8da9705eULL, }, /* 88 */ - { 0x12bb1552fb004dc7ULL, 0x8d278d704bfe8828ULL, }, - { 0x27c6ab25acaeb98bULL, 0x8d8d4b881215fb4dULL, }, - { 0x8d88a9e270165ee2ULL, 0x8d4b12fb27abacb9ULL, }, - { 0x4b0bfeb088e62855ULL, 0x8d1227ac8da9705eULL, }, - { 0x12bb1552fb004dc7ULL, 0x8d278d704bfe8828ULL, }, - { 0x27c6ab25acaeb98bULL, 0x8d8d4b881215fb4dULL, }, - { 0x8d88a9e270165ee2ULL, 0x8d4b12fb27abacb9ULL, }, - { 0x8d1227ac8da9705eULL, 0x4b0bfeb088e62855ULL, }, /* 96 */ - { 0x4bfe88288d278d70ULL, 0x4b0bfeb088e62855ULL, }, - { 0x4bfe88284b888d8dULL, 0x4b0bfeb088e62855ULL, }, - { 0x4bfe88284b884b8dULL, 0x4b0bfeb088e62855ULL, }, - { 0x4bfe88284b884b4bULL, 0x12bb1552fb004dc7ULL, }, - { 0x1215fb4d4b884b4bULL, 0x12bb1552fb004dc7ULL, }, - { 0x1215fb4d12fb4b4bULL, 0x12bb1552fb004dc7ULL, }, - { 0x1215fb4d12fb124bULL, 0x12bb1552fb004dc7ULL, }, - { 0x1215fb4d12fb1212ULL, 0x27c6ab25acaeb98bULL, }, /* 104 */ - { 0x27abacb912fb1212ULL, 0x27c6ab25acaeb98bULL, }, - { 0x27abacb927ac1212ULL, 0x27c6ab25acaeb98bULL, }, - { 0x27abacb927ac2712ULL, 0x27c6ab25acaeb98bULL, }, - { 0x27abacb927ac2727ULL, 0x8d88a9e270165ee2ULL, }, - { 0x8da9705e27ac2727ULL, 0x8d88a9e270165ee2ULL, }, - { 0x8da9705e8d702727ULL, 0x8d88a9e270165ee2ULL, }, - { 0x8da9705e8d708d27ULL, 0x8d88a9e270165ee2ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_d.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_d.c deleted file mode 100644 index ac75526fdad1..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKOD.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKOD.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e3ULL, 0xffffffffffffffffULL, }, - { 0xc71c71c71c71c71cULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x38e38e38e38e38e3ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x38e38e38e38e38e3ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xc71c71c71c71c71cULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x38e38e38e38e38e3ULL, 0x5555555555555555ULL, }, - { 0xc71c71c71c71c71cULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x38e38e38e38e38e3ULL, 0xccccccccccccccccULL, }, - { 0xc71c71c71c71c71cULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x38e38e38e38e38e3ULL, 0x3333333333333333ULL, }, - { 0xc71c71c71c71c71cULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x38e38e38e38e38e3ULL, }, - { 0xc71c71c71c71c71cULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71cULL, 0xc71c71c71c71c71cULL, }, - { 0x4b670b5efe7bb00cULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ - { 0x12f7bb1a153f52fcULL, 0x4b670b5efe7bb00cULL, }, - { 0x27d8c6ffab2b2514ULL, 0x4b670b5efe7bb00cULL, }, - { 0x8df188d8a942e2a0ULL, 0x4b670b5efe7bb00cULL, }, - { 0x4b670b5efe7bb00cULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x12f7bb1a153f52fcULL, }, - { 0x27d8c6ffab2b2514ULL, 0x12f7bb1a153f52fcULL, }, - { 0x8df188d8a942e2a0ULL, 0x12f7bb1a153f52fcULL, }, - { 0x4b670b5efe7bb00cULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ - { 0x12f7bb1a153f52fcULL, 0x27d8c6ffab2b2514ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x8df188d8a942e2a0ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, /* 80 */ - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, /* 88 */ - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x4b670b5efe7bb00cULL, 0x8df188d8a942e2a0ULL, }, - { 0x12f7bb1a153f52fcULL, 0x8df188d8a942e2a0ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x4b670b5efe7bb00cULL, }, /* 96 */ - { 0x4b670b5efe7bb00cULL, 0x4b670b5efe7bb00cULL, }, - { 0x4b670b5efe7bb00cULL, 0x4b670b5efe7bb00cULL, }, - { 0x4b670b5efe7bb00cULL, 0x4b670b5efe7bb00cULL, }, - { 0x4b670b5efe7bb00cULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x12f7bb1a153f52fcULL, }, - { 0x12f7bb1a153f52fcULL, 0x27d8c6ffab2b2514ULL, }, /* 104 */ - { 0x27d8c6ffab2b2514ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x27d8c6ffab2b2514ULL, }, - { 0x27d8c6ffab2b2514ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - { 0x8df188d8a942e2a0ULL, 0x8df188d8a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_h.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_h.c deleted file mode 100644 index 12c1fa1ea5a0..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKOD.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKOD.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x38e3e38ee38e8e38ULL, 0xffffffffffffffffULL, }, - { 0xc71c1c711c7171c7ULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x38e3e38ee38e8e38ULL, 0x0000000000000000ULL, }, - { 0xc71c1c711c7171c7ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x38e3e38ee38e8e38ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xc71c1c711c7171c7ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x38e3e38ee38e8e38ULL, 0x5555555555555555ULL, }, - { 0xc71c1c711c7171c7ULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x38e3e38ee38e8e38ULL, 0xccccccccccccccccULL, }, - { 0xc71c1c711c7171c7ULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x38e3e38ee38e8e38ULL, 0x3333333333333333ULL, }, - { 0xc71c1c711c7171c7ULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e3e38ee38e8e38ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e3e38ee38e8e38ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e3e38ee38e8e38ULL, }, - { 0x5555555555555555ULL, 0x38e3e38ee38e8e38ULL, }, - { 0xccccccccccccccccULL, 0x38e3e38ee38e8e38ULL, }, - { 0x3333333333333333ULL, 0x38e3e38ee38e8e38ULL, }, - { 0x38e3e38ee38e8e38ULL, 0x38e3e38ee38e8e38ULL, }, - { 0xc71c1c711c7171c7ULL, 0x38e3e38ee38e8e38ULL, }, - { 0xffffffffffffffffULL, 0xc71c1c711c7171c7ULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c1c711c7171c7ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c1c711c7171c7ULL, }, - { 0x5555555555555555ULL, 0xc71c1c711c7171c7ULL, }, - { 0xccccccccccccccccULL, 0xc71c1c711c7171c7ULL, }, - { 0x3333333333333333ULL, 0xc71c1c711c7171c7ULL, }, - { 0x38e3e38ee38e8e38ULL, 0xc71c1c711c7171c7ULL, }, - { 0xc71c1c711c7171c7ULL, 0xc71c1c711c7171c7ULL, }, - { 0x4b67fe7b886a2862ULL, 0x4b67fe7b886a2862ULL, }, /* 64 */ - { 0x12f7153ffbbe4d93ULL, 0x4b67fe7b886a2862ULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x4b67fe7b886a2862ULL, }, - { 0x8df1a942704f5e31ULL, 0x4b67fe7b886a2862ULL, }, - { 0x4b67fe7b886a2862ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x12f7153ffbbe4d93ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x12f7153ffbbe4d93ULL, }, - { 0x8df1a942704f5e31ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x4b67fe7b886a2862ULL, 0x27d8ab2bac5ab9cfULL, }, /* 72 */ - { 0x12f7153ffbbe4d93ULL, 0x27d8ab2bac5ab9cfULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x27d8ab2bac5ab9cfULL, }, - { 0x8df1a942704f5e31ULL, 0x27d8ab2bac5ab9cfULL, }, - { 0x4b67fe7b886a2862ULL, 0x8df1a942704f5e31ULL, }, - { 0x12f7153ffbbe4d93ULL, 0x8df1a942704f5e31ULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x8df1a942704f5e31ULL, }, - { 0x8df1a942704f5e31ULL, 0x8df1a942704f5e31ULL, }, - { 0x4b67fe7b886a2862ULL, 0x8df1704f8df1704fULL, }, /* 80 */ - { 0x12f7153ffbbe4d93ULL, 0x8df18df14b67886aULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x8df14b6712f7fbbeULL, }, - { 0x8df1a942704f5e31ULL, 0x8df112f727d8ac5aULL, }, - { 0x4b67fe7b886a2862ULL, 0x8df127d88df1704fULL, }, - { 0x12f7153ffbbe4d93ULL, 0x8df18df14b67886aULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x8df14b6712f7fbbeULL, }, - { 0x8df1a942704f5e31ULL, 0x8df112f727d8ac5aULL, }, - { 0x4b67fe7b886a2862ULL, 0x8df127d88df1704fULL, }, /* 88 */ - { 0x12f7153ffbbe4d93ULL, 0x8df18df14b67886aULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x8df14b6712f7fbbeULL, }, - { 0x8df1a942704f5e31ULL, 0x8df112f727d8ac5aULL, }, - { 0x4b67fe7b886a2862ULL, 0x8df127d88df1704fULL, }, - { 0x12f7153ffbbe4d93ULL, 0x8df18df14b67886aULL, }, - { 0x27d8ab2bac5ab9cfULL, 0x8df14b6712f7fbbeULL, }, - { 0x8df1a942704f5e31ULL, 0x8df112f727d8ac5aULL, }, - { 0x8df127d88df1704fULL, 0x4b67fe7b886a2862ULL, }, /* 96 */ - { 0x4b67886a8df18df1ULL, 0x4b67fe7b886a2862ULL, }, - { 0x4b67886a4b678df1ULL, 0x4b67fe7b886a2862ULL, }, - { 0x4b67886a4b674b67ULL, 0x4b67fe7b886a2862ULL, }, - { 0x4b67886a4b674b67ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x12f7fbbe4b674b67ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x12f7fbbe12f74b67ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x12f7fbbe12f712f7ULL, 0x12f7153ffbbe4d93ULL, }, - { 0x12f7fbbe12f712f7ULL, 0x27d8ab2bac5ab9cfULL, }, /* 104 */ - { 0x27d8ac5a12f712f7ULL, 0x27d8ab2bac5ab9cfULL, }, - { 0x27d8ac5a27d812f7ULL, 0x27d8ab2bac5ab9cfULL, }, - { 0x27d8ac5a27d827d8ULL, 0x27d8ab2bac5ab9cfULL, }, - { 0x27d8ac5a27d827d8ULL, 0x8df1a942704f5e31ULL, }, - { 0x8df1704f27d827d8ULL, 0x8df1a942704f5e31ULL, }, - { 0x8df1704f8df127d8ULL, 0x8df1a942704f5e31ULL, }, - { 0x8df1704f8df18df1ULL, 0x8df1a942704f5e31ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_w.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_w.c deleted file mode 100644 index b8979c3f43be..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_pckod_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction PCKOD.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "PCKOD.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xffffffffffffffffULL, }, - { 0x5555555555555555ULL, 0xffffffffffffffffULL, }, - { 0xccccccccccccccccULL, 0xffffffffffffffffULL, }, - { 0x3333333333333333ULL, 0xffffffffffffffffULL, }, - { 0x38e38e38e38e38e3ULL, 0xffffffffffffffffULL, }, - { 0xc71c71c71c71c71cULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x0000000000000000ULL, }, - { 0x5555555555555555ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0x0000000000000000ULL, }, - { 0x3333333333333333ULL, 0x0000000000000000ULL, }, - { 0x38e38e38e38e38e3ULL, 0x0000000000000000ULL, }, - { 0xc71c71c71c71c71cULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ - { 0x0000000000000000ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x5555555555555555ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xccccccccccccccccULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x3333333333333333ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x38e38e38e38e38e3ULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xc71c71c71c71c71cULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffffffffULL, 0x5555555555555555ULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x5555555555555555ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x5555555555555555ULL, }, - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0xccccccccccccccccULL, 0x5555555555555555ULL, }, - { 0x3333333333333333ULL, 0x5555555555555555ULL, }, - { 0x38e38e38e38e38e3ULL, 0x5555555555555555ULL, }, - { 0xc71c71c71c71c71cULL, 0x5555555555555555ULL, }, - { 0xffffffffffffffffULL, 0xccccccccccccccccULL, }, /* 32 */ - { 0x0000000000000000ULL, 0xccccccccccccccccULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xccccccccccccccccULL, }, - { 0x5555555555555555ULL, 0xccccccccccccccccULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0xccccccccccccccccULL, }, - { 0x38e38e38e38e38e3ULL, 0xccccccccccccccccULL, }, - { 0xc71c71c71c71c71cULL, 0xccccccccccccccccULL, }, - { 0xffffffffffffffffULL, 0x3333333333333333ULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x3333333333333333ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x3333333333333333ULL, }, - { 0x5555555555555555ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0x3333333333333333ULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x38e38e38e38e38e3ULL, 0x3333333333333333ULL, }, - { 0xc71c71c71c71c71cULL, 0x3333333333333333ULL, }, - { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, - { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, - { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, - { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38e38e38e38e3ULL, 0x38e38e38e38e38e3ULL, }, - { 0xc71c71c71c71c71cULL, 0x38e38e38e38e38e3ULL, }, - { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, /* 56 */ - { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, - { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, - { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, - { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, - { 0x38e38e38e38e38e3ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c71c71c71c71cULL, 0xc71c71c71c71c71cULL, }, - { 0x4b670b5e886ae6ccULL, 0x4b670b5e886ae6ccULL, }, /* 64 */ - { 0x12f7bb1afbbe0063ULL, 0x4b670b5e886ae6ccULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x4b670b5e886ae6ccULL, }, - { 0x8df188d8704f164dULL, 0x4b670b5e886ae6ccULL, }, - { 0x4b670b5e886ae6ccULL, 0x12f7bb1afbbe0063ULL, }, - { 0x12f7bb1afbbe0063ULL, 0x12f7bb1afbbe0063ULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x12f7bb1afbbe0063ULL, }, - { 0x8df188d8704f164dULL, 0x12f7bb1afbbe0063ULL, }, - { 0x4b670b5e886ae6ccULL, 0x27d8c6ffac5aaeaaULL, }, /* 72 */ - { 0x12f7bb1afbbe0063ULL, 0x27d8c6ffac5aaeaaULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x27d8c6ffac5aaeaaULL, }, - { 0x8df188d8704f164dULL, 0x27d8c6ffac5aaeaaULL, }, - { 0x4b670b5e886ae6ccULL, 0x8df188d8704f164dULL, }, - { 0x12f7bb1afbbe0063ULL, 0x8df188d8704f164dULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x8df188d8704f164dULL, }, - { 0x8df188d8704f164dULL, 0x8df188d8704f164dULL, }, - { 0x4b670b5e886ae6ccULL, 0x8df188d88df188d8ULL, }, /* 80 */ - { 0x12f7bb1afbbe0063ULL, 0x8df188d84b670b5eULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x8df188d812f7bb1aULL, }, - { 0x8df188d8704f164dULL, 0x8df188d827d8c6ffULL, }, - { 0x4b670b5e886ae6ccULL, 0x8df188d88df188d8ULL, }, - { 0x12f7bb1afbbe0063ULL, 0x8df188d84b670b5eULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x8df188d812f7bb1aULL, }, - { 0x8df188d8704f164dULL, 0x8df188d827d8c6ffULL, }, - { 0x4b670b5e886ae6ccULL, 0x8df188d88df188d8ULL, }, /* 88 */ - { 0x12f7bb1afbbe0063ULL, 0x8df188d84b670b5eULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x8df188d812f7bb1aULL, }, - { 0x8df188d8704f164dULL, 0x8df188d827d8c6ffULL, }, - { 0x4b670b5e886ae6ccULL, 0x8df188d88df188d8ULL, }, - { 0x12f7bb1afbbe0063ULL, 0x8df188d84b670b5eULL, }, - { 0x27d8c6ffac5aaeaaULL, 0x8df188d812f7bb1aULL, }, - { 0x8df188d8704f164dULL, 0x8df188d827d8c6ffULL, }, - { 0x8df188d88df188d8ULL, 0x4b670b5e886ae6ccULL, }, /* 96 */ - { 0x4b670b5e8df188d8ULL, 0x4b670b5e886ae6ccULL, }, - { 0x4b670b5e4b670b5eULL, 0x4b670b5e886ae6ccULL, }, - { 0x4b670b5e4b670b5eULL, 0x4b670b5e886ae6ccULL, }, - { 0x4b670b5e4b670b5eULL, 0x12f7bb1afbbe0063ULL, }, - { 0x12f7bb1a4b670b5eULL, 0x12f7bb1afbbe0063ULL, }, - { 0x12f7bb1a12f7bb1aULL, 0x12f7bb1afbbe0063ULL, }, - { 0x12f7bb1a12f7bb1aULL, 0x12f7bb1afbbe0063ULL, }, - { 0x12f7bb1a12f7bb1aULL, 0x27d8c6ffac5aaeaaULL, }, /* 104 */ - { 0x27d8c6ff12f7bb1aULL, 0x27d8c6ffac5aaeaaULL, }, - { 0x27d8c6ff27d8c6ffULL, 0x27d8c6ffac5aaeaaULL, }, - { 0x27d8c6ff27d8c6ffULL, 0x27d8c6ffac5aaeaaULL, }, - { 0x27d8c6ff27d8c6ffULL, 0x8df188d8704f164dULL, }, - { 0x8df188d827d8c6ffULL, 0x8df188d8704f164dULL, }, - { 0x8df188d88df188d8ULL, 0x8df188d8704f164dULL, }, - { 0x8df188d88df188d8ULL, 0x8df188d8704f164dULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_PCKOD_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_b.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_b.c deleted file mode 100644 index 1839a26ca7b7..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_b.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction VSHF.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "VSHF.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, /* 80 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, /* 88 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 96 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 104 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_B__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_B__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_d.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_d.c deleted file mode 100644 index ebc198feb85c..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_d.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction VSHF.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "VSHF.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38e38e38e38e38eULL, 0xe38e38e38e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 80 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, /* 88 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0x886ae6cc28625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0xac5aaeaab9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 96 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 104 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_D__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_D__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_h.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_h.c deleted file mode 100644 index a7240134d7f0..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_h.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction VSHF.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "VSHF.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xe38ee38ee38ee38eULL, 0xe38ee38ee38ee38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, /* 80 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, /* 88 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8b808b808b808b80ULL, 0x8b808b808b808b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 96 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 104 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_H__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_H__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_w.c b/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_w.c deleted file mode 100644 index 607ac4fb53c2..000000000000 --- a/tests/tcg/mips/user/ase/msa/pack/test_msa_vshf_w.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Test program for MSA instruction VSHF.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Pack"; - char *instruction_name = "VSHF.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x8e38e38e8e38e38eULL, 0x8e38e38e8e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, /* 64 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, /* 72 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, /* 80 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, /* 88 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x2862554028625540ULL, 0x2862554028625540ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xb9cf8b80b9cf8b80ULL, 0xb9cf8b80b9cf8b80ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 96 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 104 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_W__DDT(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - ((RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_VSHF_W__DSD(b128_random[i], b128_random[j], - b128_result[ - ((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - (2 * (RANDOM_INPUTS_SHORT_COUNT) * - (RANDOM_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_b.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_b.c deleted file mode 100644 index 649e67b6a149..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SLL.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SLL.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xe0e0e0e0e0e0e0e0ULL, 0xe0e0e0e0e0e0e0e0ULL, }, - { 0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL, }, - { 0xf8f8f8f8f8f8f8f8ULL, 0xf8f8f8f8f8f8f8f8ULL, }, - { 0xf8c0fff8c0fff8c0ULL, 0xfff8c0fff8c0fff8ULL, }, - { 0xf0fe80f0fe80f0feULL, 0x80f0fe80f0fe80f0ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xa8a8a8a8a8a8a8a8ULL, 0xa8a8a8a8a8a8a8a8ULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, - { 0xa0a0a0a0a0a0a0a0ULL, 0xa0a0a0a0a0a0a0a0ULL, }, - { 0x5050505050505050ULL, 0x5050505050505050ULL, }, - { 0x5080aa5080aa5080ULL, 0xaa5080aa5080aa50ULL, }, - { 0xa05400a05400a054ULL, 0x00a05400a05400a0ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5454545454545454ULL, 0x5454545454545454ULL, }, - { 0xa0a0a0a0a0a0a0a0ULL, 0xa0a0a0a0a0a0a0a0ULL, }, - { 0x5050505050505050ULL, 0x5050505050505050ULL, }, - { 0xa8a8a8a8a8a8a8a8ULL, 0xa8a8a8a8a8a8a8a8ULL, }, - { 0xa84055a84055a840ULL, 0x55a84055a84055a8ULL, }, - { 0x50aa8050aa8050aaULL, 0x8050aa8050aa8050ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3030303030303030ULL, 0x3030303030303030ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, - { 0xc0c0c0c0c0c0c0c0ULL, 0xc0c0c0c0c0c0c0c0ULL, }, - { 0x6060606060606060ULL, 0x6060606060606060ULL, }, - { 0x6000cc6000cc6000ULL, 0xcc6000cc6000cc60ULL, }, - { 0xc09800c09800c098ULL, 0x00c09800c09800c0ULL, }, - { 0x8080808080808080ULL, 0x8080808080808080ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x6060606060606060ULL, 0x6060606060606060ULL, }, - { 0x3030303030303030ULL, 0x3030303030303030ULL, }, - { 0x9898989898989898ULL, 0x9898989898989898ULL, }, - { 0x98c03398c03398c0ULL, 0x3398c03398c03398ULL, }, - { 0x3066803066803066ULL, 0x8030668030668030ULL, }, - { 0x8000008000008000ULL, 0x0080000080000080ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x8c38e08c38e08c38ULL, 0xe08c38e08c38e08cULL, }, - { 0x60c00060c00060c0ULL, 0x0060c00060c00060ULL, }, - { 0x30e08030e08030e0ULL, 0x8030e08030e08030ULL, }, - { 0x1870c01870c01870ULL, 0xc01870c01870c018ULL, }, - { 0x1880381880381880ULL, 0x3818803818803818ULL, }, - { 0x301c00301c00301cULL, 0x00301c00301c0030ULL, }, - { 0x0080800080800080ULL, 0x8000808000808000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x70c41c70c41c70c4ULL, 0x1c70c41c70c41c70ULL, }, - { 0x8020e08020e08020ULL, 0xe08020e08020e080ULL, }, - { 0xc01070c01070c010ULL, 0x70c01070c01070c0ULL, }, - { 0xe08838e08838e088ULL, 0x38e08838e08838e0ULL, }, - { 0xe040c7e040c7e040ULL, 0xc7e040c7e040c7e0ULL, }, - { 0xc0e280c0e280c0e2ULL, 0x80c0e280c0e280c0ULL, }, - { 0x88a880c02888a040ULL, 0x5880588080d8b0c0ULL, }, /* 64 */ - { 0x4080e66000108040ULL, 0x2c805878c080c0c0ULL, }, - { 0x80a880305000a840ULL, 0x8067c000f0d800c0ULL, }, - { 0x8800808000c45400ULL, 0x60ce0b5efcecc00cULL, }, - { 0xfbf800304d4ce008ULL, 0x9080d88040f852c0ULL, }, - { 0xd8800018a0988008ULL, 0x4880d868a08048c0ULL, }, - { 0xb0f8008c9a803808ULL, 0x00f7c000a8f840c0ULL, }, - { 0xfb00006040261c00ULL, 0x40eebb1a2afc48fcULL, }, - { 0xac6880a0b93c6080ULL, 0x380030c0c0582540ULL, }, /* 72 */ - { 0x6080ae5020788080ULL, 0x9c0030fc60809440ULL, }, - { 0xc06880a872805880ULL, 0x80d880805858a040ULL, }, - { 0xac008040409e2c00ULL, 0xe0b0c6ff56ac9414ULL, }, - { 0x703c80d05ec4404eULL, 0x688040004010e200ULL, }, - { 0x80c01668c088004eULL, 0x3480406020008800ULL, }, - { 0x003c8034bc80104eULL, 0x80f1000048104000ULL, }, - { 0x708080a080628880ULL, 0xa0e288d8520888a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_d.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_d.c deleted file mode 100644 index 1d6fe5420761..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SLL.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SLL.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfffffc0000000000ULL, 0xfffffc0000000000ULL, }, - { 0xffffffffffe00000ULL, 0xffffffffffe00000ULL, }, - { 0xfffffffffffff000ULL, 0xfffffffffffff000ULL, }, - { 0xfff8000000000000ULL, 0xfff8000000000000ULL, }, - { 0xffffffffffffc000ULL, 0xfffffff800000000ULL, }, - { 0xfffe000000000000ULL, 0xfffffffff0000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaa80000000000ULL, 0xaaaaa80000000000ULL, }, - { 0x5555555555400000ULL, 0x5555555555400000ULL, }, - { 0xaaaaaaaaaaaaa000ULL, 0xaaaaaaaaaaaaa000ULL, }, - { 0x5550000000000000ULL, 0x5550000000000000ULL, }, - { 0xaaaaaaaaaaaa8000ULL, 0x5555555000000000ULL, }, - { 0x5554000000000000ULL, 0xaaaaaaaaa0000000ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555540000000000ULL, 0x5555540000000000ULL, }, - { 0xaaaaaaaaaaa00000ULL, 0xaaaaaaaaaaa00000ULL, }, - { 0x5555555555555000ULL, 0x5555555555555000ULL, }, - { 0xaaa8000000000000ULL, 0xaaa8000000000000ULL, }, - { 0x5555555555554000ULL, 0xaaaaaaa800000000ULL, }, - { 0xaaaa000000000000ULL, 0x5555555550000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333300000000000ULL, 0x3333300000000000ULL, }, - { 0x9999999999800000ULL, 0x9999999999800000ULL, }, - { 0xccccccccccccc000ULL, 0xccccccccccccc000ULL, }, - { 0x6660000000000000ULL, 0x6660000000000000ULL, }, - { 0x3333333333330000ULL, 0x6666666000000000ULL, }, - { 0x9998000000000000ULL, 0xccccccccc0000000ULL, }, - { 0x8000000000000000ULL, 0x8000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcccccc0000000000ULL, 0xcccccc0000000000ULL, }, - { 0x6666666666600000ULL, 0x6666666666600000ULL, }, - { 0x3333333333333000ULL, 0x3333333333333000ULL, }, - { 0x9998000000000000ULL, 0x9998000000000000ULL, }, - { 0xccccccccccccc000ULL, 0x9999999800000000ULL, }, - { 0x6666000000000000ULL, 0x3333333330000000ULL, }, - { 0x0000000000000000ULL, 0x8000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xe38e380000000000ULL, 0x38e38c0000000000ULL, }, - { 0x1c71c71c71c00000ULL, 0xc71c71c71c600000ULL, }, - { 0xe38e38e38e38e000ULL, 0x38e38e38e38e3000ULL, }, - { 0x1c70000000000000ULL, 0xc718000000000000ULL, }, - { 0x8e38e38e38e38000ULL, 0x1c71c71800000000ULL, }, - { 0xc71c000000000000ULL, 0x8e38e38e30000000ULL, }, - { 0x8000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x1c71c40000000000ULL, 0xc71c700000000000ULL, }, - { 0xe38e38e38e200000ULL, 0x38e38e38e3800000ULL, }, - { 0x1c71c71c71c71000ULL, 0xc71c71c71c71c000ULL, }, - { 0xe388000000000000ULL, 0x38e0000000000000ULL, }, - { 0x71c71c71c71c4000ULL, 0xe38e38e000000000ULL, }, - { 0x38e2000000000000ULL, 0x71c71c71c0000000ULL, }, - { 0x886ae6cc28625540ULL, 0x70b5efe7bb00c000ULL, }, /* 64 */ - { 0x6ae6cc2862554000ULL, 0xc000000000000000ULL, }, - { 0x886ae6cc28625540ULL, 0xb5efe7bb00c00000ULL, }, - { 0xb9b30a1895500000ULL, 0xfe7bb00c00000000ULL, }, - { 0xfbbe00634d93c708ULL, 0x7bb1a153f52fc000ULL, }, - { 0xbe00634d93c70800ULL, 0xc000000000000000ULL, }, - { 0xfbbe00634d93c708ULL, 0xb1a153f52fc00000ULL, }, - { 0x8018d364f1c20000ULL, 0x153f52fc00000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x8c6ffab2b2514000ULL, }, /* 72 */ - { 0x5aaeaab9cf8b8000ULL, 0x4000000000000000ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x6ffab2b251400000ULL, }, - { 0xabaaae73e2e00000ULL, 0xab2b251400000000ULL, }, - { 0x704f164d5e31e24eULL, 0x188d8a942e2a0000ULL, }, - { 0x4f164d5e31e24e00ULL, 0x0000000000000000ULL, }, - { 0x704f164d5e31e24eULL, 0x8d8a942e2a000000ULL, }, - { 0xc593578c78938000ULL, 0xa942e2a000000000ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_h.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_h.c deleted file mode 100644 index 1e6c27bfe730..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SLL.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SLL.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfc00fc00fc00fc00ULL, 0xfc00fc00fc00fc00ULL, }, - { 0xffe0ffe0ffe0ffe0ULL, 0xffe0ffe0ffe0ffe0ULL, }, - { 0xf000f000f000f000ULL, 0xf000f000f000f000ULL, }, - { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, }, - { 0xc000fff8ff00c000ULL, 0xfff8ff00c000fff8ULL, }, - { 0xfffef000ff80fffeULL, 0xf000ff80fffef000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xa800a800a800a800ULL, 0xa800a800a800a800ULL, }, - { 0x5540554055405540ULL, 0x5540554055405540ULL, }, - { 0xa000a000a000a000ULL, 0xa000a000a000a000ULL, }, - { 0x5550555055505550ULL, 0x5550555055505550ULL, }, - { 0x80005550aa008000ULL, 0x5550aa0080005550ULL, }, - { 0x5554a00055005554ULL, 0xa00055005554a000ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5400540054005400ULL, 0x5400540054005400ULL, }, - { 0xaaa0aaa0aaa0aaa0ULL, 0xaaa0aaa0aaa0aaa0ULL, }, - { 0x5000500050005000ULL, 0x5000500050005000ULL, }, - { 0xaaa8aaa8aaa8aaa8ULL, 0xaaa8aaa8aaa8aaa8ULL, }, - { 0x4000aaa855004000ULL, 0xaaa855004000aaa8ULL, }, - { 0xaaaa5000aa80aaaaULL, 0x5000aa80aaaa5000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3000300030003000ULL, 0x3000300030003000ULL, }, - { 0x9980998099809980ULL, 0x9980998099809980ULL, }, - { 0xc000c000c000c000ULL, 0xc000c000c000c000ULL, }, - { 0x6660666066606660ULL, 0x6660666066606660ULL, }, - { 0x00006660cc000000ULL, 0x6660cc0000006660ULL, }, - { 0x9998c00066009998ULL, 0xc00066009998c000ULL, }, - { 0x8000800080008000ULL, 0x8000800080008000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcc00cc00cc00cc00ULL, 0xcc00cc00cc00cc00ULL, }, - { 0x6660666066606660ULL, 0x6660666066606660ULL, }, - { 0x3000300030003000ULL, 0x3000300030003000ULL, }, - { 0x9998999899989998ULL, 0x9998999899989998ULL, }, - { 0xc00099983300c000ULL, 0x99983300c0009998ULL, }, - { 0x6666300099806666ULL, 0x3000998066663000ULL, }, - { 0x0000800000000000ULL, 0x8000000000008000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38008c00e0003800ULL, 0x8c00e00038008c00ULL, }, - { 0x71c01c60c70071c0ULL, 0x1c60c70071c01c60ULL, }, - { 0xe00030008000e000ULL, 0x30008000e0003000ULL, }, - { 0x1c70c71871c01c70ULL, 0xc71871c01c70c718ULL, }, - { 0x8000c71838008000ULL, 0xc71838008000c718ULL, }, - { 0xc71c30001c00c71cULL, 0x30001c00c71c3000ULL, }, - { 0x8000000080008000ULL, 0x0000800080000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc40070001c00c400ULL, 0x70001c00c4007000ULL, }, - { 0x8e20e38038e08e20ULL, 0xe38038e08e20e380ULL, }, - { 0x1000c00070001000ULL, 0xc00070001000c000ULL, }, - { 0xe38838e08e38e388ULL, 0x38e08e38e38838e0ULL, }, - { 0x400038e0c7004000ULL, 0x38e0c700400038e0ULL, }, - { 0x38e2c000e38038e2ULL, 0xc000e38038e2c000ULL, }, - { 0xa800c000a1885540ULL, 0xb3808000d800c000ULL, }, /* 64 */ - { 0x8000366043104000ULL, 0xb38078008000c000ULL, }, - { 0xa800300000005540ULL, 0x67000000d80000c0ULL, }, - { 0x0000800050c40000ULL, 0x96ce5e00f9ecb00cULL, }, - { 0xf8003000364cc708ULL, 0x7b808000f800c000ULL, }, - { 0x800003186c980800ULL, 0x7b8068008000c000ULL, }, - { 0xf8008c008000c708ULL, 0xf7000000f8002fc0ULL, }, - { 0x000060009b260000ULL, 0x25ee1a0054fc52fcULL, }, - { 0x6800a000e73c8b80ULL, 0xec00c00058004000ULL, }, /* 72 */ - { 0x80007550ce788000ULL, 0xec00fc0080004000ULL, }, - { 0x6800a80080008b80ULL, 0xd800800058005140ULL, }, - { 0x00004000739e0000ULL, 0x4fb0ff00acac2514ULL, }, - { 0x3c00d00078c4e24eULL, 0xf880000010000000ULL, }, - { 0xc000b268f1884e00ULL, 0xf880600000000000ULL, }, - { 0x3c0034008000e24eULL, 0xf100000010002a00ULL, }, - { 0x8000a000bc628000ULL, 0x1be2d800a508e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_w.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_w.c deleted file mode 100644 index 8bfbaca6fcb5..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sll_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SLL.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SLL.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xfffffc00fffffc00ULL, 0xfffffc00fffffc00ULL, }, - { 0xffe00000ffe00000ULL, 0xffe00000ffe00000ULL, }, - { 0xfffff000fffff000ULL, 0xfffff000fffff000ULL, }, - { 0xfff80000fff80000ULL, 0xfff80000fff80000ULL, }, - { 0xfffffff8ffffc000ULL, 0xff000000fffffff8ULL, }, - { 0xf0000000fffe0000ULL, 0xffffff80f0000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xaaaaa800aaaaa800ULL, 0xaaaaa800aaaaa800ULL, }, - { 0x5540000055400000ULL, 0x5540000055400000ULL, }, - { 0xaaaaa000aaaaa000ULL, 0xaaaaa000aaaaa000ULL, }, - { 0x5550000055500000ULL, 0x5550000055500000ULL, }, - { 0x55555550aaaa8000ULL, 0xaa00000055555550ULL, }, - { 0xa000000055540000ULL, 0x55555500a0000000ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x5555540055555400ULL, 0x5555540055555400ULL, }, - { 0xaaa00000aaa00000ULL, 0xaaa00000aaa00000ULL, }, - { 0x5555500055555000ULL, 0x5555500055555000ULL, }, - { 0xaaa80000aaa80000ULL, 0xaaa80000aaa80000ULL, }, - { 0xaaaaaaa855554000ULL, 0x55000000aaaaaaa8ULL, }, - { 0x50000000aaaa0000ULL, 0xaaaaaa8050000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333300033333000ULL, 0x3333300033333000ULL, }, - { 0x9980000099800000ULL, 0x9980000099800000ULL, }, - { 0xccccc000ccccc000ULL, 0xccccc000ccccc000ULL, }, - { 0x6660000066600000ULL, 0x6660000066600000ULL, }, - { 0x6666666033330000ULL, 0xcc00000066666660ULL, }, - { 0xc000000099980000ULL, 0x66666600c0000000ULL, }, - { 0x8000000080000000ULL, 0x8000000080000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0xcccccc00cccccc00ULL, 0xcccccc00cccccc00ULL, }, - { 0x6660000066600000ULL, 0x6660000066600000ULL, }, - { 0x3333300033333000ULL, 0x3333300033333000ULL, }, - { 0x9998000099980000ULL, 0x9998000099980000ULL, }, - { 0x99999998ccccc000ULL, 0x3300000099999998ULL, }, - { 0x3000000066660000ULL, 0x9999998030000000ULL, }, - { 0x8000000000000000ULL, 0x0000000080000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38e38c00e38e3800ULL, 0x8e38e00038e38c00ULL, }, - { 0x1c60000071c00000ULL, 0xc70000001c600000ULL, }, - { 0xe38e30008e38e000ULL, 0x38e38000e38e3000ULL, }, - { 0xc71800001c700000ULL, 0x71c00000c7180000ULL, }, - { 0x1c71c71838e38000ULL, 0x380000001c71c718ULL, }, - { 0x30000000c71c0000ULL, 0x71c71c0030000000ULL, }, - { 0x0000000080000000ULL, 0x8000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0xc71c70001c71c400ULL, 0x71c71c00c71c7000ULL, }, - { 0xe38000008e200000ULL, 0x38e00000e3800000ULL, }, - { 0x1c71c00071c71000ULL, 0xc71c70001c71c000ULL, }, - { 0x38e00000e3880000ULL, 0x8e38000038e00000ULL, }, - { 0xe38e38e0c71c4000ULL, 0xc7000000e38e38e0ULL, }, - { 0xc000000038e20000ULL, 0x8e38e380c0000000ULL, }, - { 0xae6cc00028625540ULL, 0x80000000bb00c000ULL, }, /* 64 */ - { 0x4357366062554000ULL, 0x78000000c0000000ULL, }, - { 0xab9b300028625540ULL, 0x0000000000c00000ULL, }, - { 0x5cd9800095500000ULL, 0x5e000000fe7bb00cULL, }, - { 0xe00630004d93c708ULL, 0x80000000f52fc000ULL, }, - { 0xddf0031893c70800ULL, 0x68000000c0000000ULL, }, - { 0xf8018c004d93c708ULL, 0x000000002fc00000ULL, }, - { 0xc00c6000f1c20000ULL, 0x1a000000153f52fcULL, }, - { 0xaaeaa000b9cf8b80ULL, 0xc0000000b2514000ULL, }, /* 72 */ - { 0x62d57550cf8b8000ULL, 0xfc00000040000000ULL, }, - { 0x6abaa800b9cf8b80ULL, 0x8000000051400000ULL, }, - { 0x55d54000e2e00000ULL, 0xff000000ab2b2514ULL, }, - { 0xf164d0005e31e24eULL, 0x000000002e2a0000ULL, }, - { 0x8278b26831e24e00ULL, 0x6000000000000000ULL, }, - { 0x3c5934005e31e24eULL, 0x000000002a000000ULL, }, - { 0xe2c9a00078938000ULL, 0xd8000000a942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SLL_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_b.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_b.c deleted file mode 100644 index a5dcee3a721e..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRA.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRA.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xeaeaeaeaeaeaeaeaULL, 0xeaeaeaeaeaeaeaeaULL, }, - { 0xfdfdfdfdfdfdfdfdULL, 0xfdfdfdfdfdfdfdfdULL, }, - { 0xfafafafafafafafaULL, 0xfafafafafafafafaULL, }, - { 0xf5f5f5f5f5f5f5f5ULL, 0xf5f5f5f5f5f5f5f5ULL, }, - { 0xf5feaaf5feaaf5feULL, 0xaaf5feaaf5feaaf5ULL, }, - { 0xfad5fffad5fffad5ULL, 0xfffad5fffad5fffaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1515151515151515ULL, 0x1515151515151515ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0a0a0a0a0a0a0a0aULL, 0x0a0a0a0a0a0a0a0aULL, }, - { 0x0a01550a01550a01ULL, 0x550a01550a01550aULL, }, - { 0x052a00052a00052aULL, 0x00052a00052a0005ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xf3f3f3f3f3f3f3f3ULL, 0xf3f3f3f3f3f3f3f3ULL, }, - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, - { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, - { 0xf9f9f9f9f9f9f9f9ULL, 0xf9f9f9f9f9f9f9f9ULL, }, - { 0xf9ffccf9ffccf9ffULL, 0xccf9ffccf9ffccf9ULL, }, - { 0xfce6fffce6fffce6ULL, 0xfffce6fffce6fffcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0c0c0c0c0c0c0c0cULL, 0x0c0c0c0c0c0c0c0cULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0x0600330600330600ULL, 0x3306003306003306ULL, }, - { 0x0319000319000319ULL, 0x0003190003190003ULL, }, - { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xf8e30ef8e30ef8e3ULL, 0x0ef8e30ef8e30ef8ULL, }, - { 0xfffc01fffc01fffcULL, 0x01fffc01fffc01ffULL, }, - { 0xfef803fef803fef8ULL, 0x03fef803fef803feULL, }, - { 0xfcf107fcf107fcf1ULL, 0x07fcf107fcf107fcULL, }, - { 0xfcfe38fcfe38fcfeULL, 0x38fcfe38fcfe38fcULL, }, - { 0xfec700fec700fec7ULL, 0x00fec700fec700feULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x071cf1071cf1071cULL, 0xf1071cf1071cf107ULL, }, - { 0x0003fe0003fe0003ULL, 0xfe0003fe0003fe00ULL, }, - { 0x0107fc0107fc0107ULL, 0xfc0107fc0107fc01ULL, }, - { 0x030ef8030ef8030eULL, 0xf8030ef8030ef803ULL, }, - { 0x0301c70301c70301ULL, 0xc70301c70301c703ULL, }, - { 0x0138ff0138ff0138ULL, 0xff0138ff0138ff01ULL, }, - { 0x881afffc28180240ULL, 0x09000101ff0fb000ULL, }, /* 64 */ - { 0xf101e6f9010c0040ULL, 0x12000117ff00ec00ULL, }, - { 0xf81afff314000a40ULL, 0x00670000ff0ffd00ULL, }, - { 0x8800fffe00311501ULL, 0x02330b5eff1eec0cULL, }, - { 0xfbef00064de4fe08ULL, 0x02fff700000752ffULL, }, - { 0xfffe000c02f2ff08ULL, 0x04fff706000014ffULL, }, - { 0xffef001826fff808ULL, 0x00f7fe00020702ffULL, }, - { 0xfbff000301c9f100ULL, 0x00fbbb1a0a0f14fcULL, }, - { 0xac16fefab9f3fc80ULL, 0x04fff8fffe052501ULL, }, /* 72 */ - { 0xf501aef5fdf9ff80ULL, 0x09fff8fffd000901ULL, }, - { 0xfa16feeadcfff180ULL, 0x00d8fffff5050101ULL, }, - { 0xac00fefdfee7e2feULL, 0x01ecc6ffd50a0914ULL, }, - { 0x701300045e0cff4eULL, 0xf1fff1fffe08e2faULL, }, - { 0x0e0116090206ff4eULL, 0xe3fff1f6fd00f8faULL, }, - { 0x071300132f00fc4eULL, 0xfff1fefff508fffaULL, }, - { 0x700000020118f801ULL, 0xfcf888d8d410f8a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_d.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_d.c deleted file mode 100644 index 95a13620b934..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRA.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRA.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffeaaaaaULL, 0xffffffffffeaaaaaULL, }, - { 0xfffffd5555555555ULL, 0xfffffd5555555555ULL, }, - { 0xfffaaaaaaaaaaaaaULL, 0xfffaaaaaaaaaaaaaULL, }, - { 0xfffffffffffff555ULL, 0xfffffffffffff555ULL, }, - { 0xfffeaaaaaaaaaaaaULL, 0xfffffffff5555555ULL, }, - { 0xffffffffffffd555ULL, 0xfffffffaaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000155555ULL, 0x0000000000155555ULL, }, - { 0x000002aaaaaaaaaaULL, 0x000002aaaaaaaaaaULL, }, - { 0x0005555555555555ULL, 0x0005555555555555ULL, }, - { 0x0000000000000aaaULL, 0x0000000000000aaaULL, }, - { 0x0001555555555555ULL, 0x000000000aaaaaaaULL, }, - { 0x0000000000002aaaULL, 0x0000000555555555ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xfffffffffff33333ULL, 0xfffffffffff33333ULL, }, - { 0xfffffe6666666666ULL, 0xfffffe6666666666ULL, }, - { 0xfffcccccccccccccULL, 0xfffcccccccccccccULL, }, - { 0xfffffffffffff999ULL, 0xfffffffffffff999ULL, }, - { 0xffff333333333333ULL, 0xfffffffff9999999ULL, }, - { 0xffffffffffffe666ULL, 0xfffffffcccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x00000000000cccccULL, 0x00000000000cccccULL, }, - { 0x0000019999999999ULL, 0x0000019999999999ULL, }, - { 0x0003333333333333ULL, 0x0003333333333333ULL, }, - { 0x0000000000000666ULL, 0x0000000000000666ULL, }, - { 0x0000ccccccccccccULL, 0x0000000006666666ULL, }, - { 0x0000000000001999ULL, 0x0000000333333333ULL, }, - { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xfffffffffff8e38eULL, 0x00000000000e38e3ULL, }, - { 0xffffff1c71c71c71ULL, 0x000001c71c71c71cULL, }, - { 0xfffe38e38e38e38eULL, 0x00038e38e38e38e3ULL, }, - { 0xfffffffffffffc71ULL, 0x000000000000071cULL, }, - { 0xffff8e38e38e38e3ULL, 0x00000000071c71c7ULL, }, - { 0xfffffffffffff1c7ULL, 0x000000038e38e38eULL, }, - { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000071c71ULL, 0xfffffffffff1c71cULL, }, - { 0x000000e38e38e38eULL, 0xfffffe38e38e38e3ULL, }, - { 0x0001c71c71c71c71ULL, 0xfffc71c71c71c71cULL, }, - { 0x000000000000038eULL, 0xfffffffffffff8e3ULL, }, - { 0x000071c71c71c71cULL, 0xfffffffff8e38e38ULL, }, - { 0x0000000000000e38ULL, 0xfffffffc71c71c71ULL, }, - { 0x886ae6cc28625540ULL, 0x0004b670b5efe7bbULL, }, /* 64 */ - { 0xff886ae6cc286255ULL, 0x0000000000000004ULL, }, - { 0x886ae6cc28625540ULL, 0x000004b670b5efe7ULL, }, - { 0xfffe21ab9b30a189ULL, 0x000000004b670b5eULL, }, - { 0xfbbe00634d93c708ULL, 0x00012f7bb1a153f5ULL, }, - { 0xfffbbe00634d93c7ULL, 0x0000000000000001ULL, }, - { 0xfbbe00634d93c708ULL, 0x0000012f7bb1a153ULL, }, - { 0xffffeef8018d364fULL, 0x0000000012f7bb1aULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x00027d8c6ffab2b2ULL, }, /* 72 */ - { 0xffac5aaeaab9cf8bULL, 0x0000000000000002ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x0000027d8c6ffab2ULL, }, - { 0xfffeb16abaaae73eULL, 0x0000000027d8c6ffULL, }, - { 0x704f164d5e31e24eULL, 0xfff8df188d8a942eULL, }, - { 0x00704f164d5e31e2ULL, 0xfffffffffffffff8ULL, }, - { 0x704f164d5e31e24eULL, 0xfffff8df188d8a94ULL, }, - { 0x0001c13c593578c7ULL, 0xffffffff8df188d8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_h.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_h.c deleted file mode 100644 index f00003d51cbb..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRA.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRA.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffeaffeaffeaffeaULL, 0xffeaffeaffeaffeaULL, }, - { 0xfd55fd55fd55fd55ULL, 0xfd55fd55fd55fd55ULL, }, - { 0xfffafffafffafffaULL, 0xfffafffafffafffaULL, }, - { 0xf555f555f555f555ULL, 0xf555f555f555f555ULL, }, - { 0xfffef555ffaafffeULL, 0xf555ffaafffef555ULL, }, - { 0xd555fffaff55d555ULL, 0xfffaff55d555fffaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015001500150015ULL, 0x0015001500150015ULL, }, - { 0x02aa02aa02aa02aaULL, 0x02aa02aa02aa02aaULL, }, - { 0x0005000500050005ULL, 0x0005000500050005ULL, }, - { 0x0aaa0aaa0aaa0aaaULL, 0x0aaa0aaa0aaa0aaaULL, }, - { 0x00010aaa00550001ULL, 0x0aaa005500010aaaULL, }, - { 0x2aaa000500aa2aaaULL, 0x000500aa2aaa0005ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xfff3fff3fff3fff3ULL, 0xfff3fff3fff3fff3ULL, }, - { 0xfe66fe66fe66fe66ULL, 0xfe66fe66fe66fe66ULL, }, - { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, - { 0xf999f999f999f999ULL, 0xf999f999f999f999ULL, }, - { 0xfffff999ffccffffULL, 0xf999ffccfffff999ULL, }, - { 0xe666fffcff99e666ULL, 0xfffcff99e666fffcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000c000c000c000cULL, 0x000c000c000c000cULL, }, - { 0x0199019901990199ULL, 0x0199019901990199ULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x0666066606660666ULL, 0x0666066606660666ULL, }, - { 0x0000066600330000ULL, 0x0666003300000666ULL, }, - { 0x1999000300661999ULL, 0x0003006619990003ULL, }, - { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xfff8000effe3fff8ULL, 0x000effe3fff8000eULL, }, - { 0xff1c01c7fc71ff1cULL, 0x01c7fc71ff1c01c7ULL, }, - { 0xfffe0003fff8fffeULL, 0x0003fff8fffe0003ULL, }, - { 0xfc71071cf1c7fc71ULL, 0x071cf1c7fc71071cULL, }, - { 0xffff071cff8effffULL, 0x071cff8effff071cULL, }, - { 0xf1c70003ff1cf1c7ULL, 0x0003ff1cf1c70003ULL, }, - { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0007fff1001c0007ULL, 0xfff1001c0007fff1ULL, }, - { 0x00e3fe38038e00e3ULL, 0xfe38038e00e3fe38ULL, }, - { 0x0001fffc00070001ULL, 0xfffc00070001fffcULL, }, - { 0x038ef8e30e38038eULL, 0xf8e30e38038ef8e3ULL, }, - { 0x0000f8e300710000ULL, 0xf8e300710000f8e3ULL, }, - { 0x0e38fffc00e30e38ULL, 0xfffc00e30e38fffcULL, }, - { 0xffe2fffe0a185540ULL, 0x00960000fffffffbULL, }, /* 64 */ - { 0xfffefcd9050c0055ULL, 0x00960002fffffffbULL, }, - { 0xffe2fff900005540ULL, 0x004b0000fffffb00ULL, }, - { 0xffffffff14310001ULL, 0x25b3000bff9eb00cULL, }, - { 0xfffe00001364c708ULL, 0x0025fffe00020005ULL, }, - { 0xffff000c09b2ffc7ULL, 0x0025ffee00000005ULL, }, - { 0xfffe00000000c708ULL, 0x0012ffff0002052fULL, }, - { 0xffff000026c9ffffULL, 0x097bffbb054f52fcULL, }, - { 0xffebfffaee738b80ULL, 0x004ffffffff50002ULL, }, /* 72 */ - { 0xfffef5d5f739ff8bULL, 0x004ffff1ffff0002ULL, }, - { 0xffebffebffff8b80ULL, 0x0027fffffff50251ULL, }, - { 0xfffffffddce7fffeULL, 0x13ecffc6eaca2514ULL, }, - { 0x001c0001178ce24eULL, 0xff1bfffefff5fffeULL, }, - { 0x000102c90bc6ffe2ULL, 0xff1bffe2fffffffeULL, }, - { 0x001c00050000e24eULL, 0xff8dfffffff5fe2aULL, }, - { 0x000000002f18ffffULL, 0xc6f8ff88ea50e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_w.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_w.c deleted file mode 100644 index f00da6d3d908..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_sra_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRA.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRA.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffeaaaaaffeaaaaaULL, 0xffeaaaaaffeaaaaaULL, }, - { 0xfffffd55fffffd55ULL, 0xfffffd55fffffd55ULL, }, - { 0xfffaaaaafffaaaaaULL, 0xfffaaaaafffaaaaaULL, }, - { 0xfffff555fffff555ULL, 0xfffff555fffff555ULL, }, - { 0xf5555555fffeaaaaULL, 0xffffffaaf5555555ULL, }, - { 0xfffffffaffffd555ULL, 0xff555555fffffffaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015555500155555ULL, 0x0015555500155555ULL, }, - { 0x000002aa000002aaULL, 0x000002aa000002aaULL, }, - { 0x0005555500055555ULL, 0x0005555500055555ULL, }, - { 0x00000aaa00000aaaULL, 0x00000aaa00000aaaULL, }, - { 0x0aaaaaaa00015555ULL, 0x000000550aaaaaaaULL, }, - { 0x0000000500002aaaULL, 0x00aaaaaa00000005ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xfff33333fff33333ULL, 0xfff33333fff33333ULL, }, - { 0xfffffe66fffffe66ULL, 0xfffffe66fffffe66ULL, }, - { 0xfffcccccfffcccccULL, 0xfffcccccfffcccccULL, }, - { 0xfffff999fffff999ULL, 0xfffff999fffff999ULL, }, - { 0xf9999999ffff3333ULL, 0xffffffccf9999999ULL, }, - { 0xfffffffcffffe666ULL, 0xff999999fffffffcULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000ccccc000cccccULL, 0x000ccccc000cccccULL, }, - { 0x0000019900000199ULL, 0x0000019900000199ULL, }, - { 0x0003333300033333ULL, 0x0003333300033333ULL, }, - { 0x0000066600000666ULL, 0x0000066600000666ULL, }, - { 0x066666660000ccccULL, 0x0000003306666666ULL, }, - { 0x0000000300001999ULL, 0x0066666600000003ULL, }, - { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xfff8e38effe38e38ULL, 0x000e38e3fff8e38eULL, }, - { 0xffffff1cfffffc71ULL, 0x000001c7ffffff1cULL, }, - { 0xfffe38e3fff8e38eULL, 0x00038e38fffe38e3ULL, }, - { 0xfffffc71fffff1c7ULL, 0x0000071cfffffc71ULL, }, - { 0xfc71c71cfffe38e3ULL, 0x00000038fc71c71cULL, }, - { 0xfffffffeffffc71cULL, 0x0071c71cfffffffeULL, }, - { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00071c71001c71c7ULL, 0xfff1c71c00071c71ULL, }, - { 0x000000e30000038eULL, 0xfffffe38000000e3ULL, }, - { 0x0001c71c00071c71ULL, 0xfffc71c70001c71cULL, }, - { 0x0000038e00000e38ULL, 0xfffff8e30000038eULL, }, - { 0x038e38e30001c71cULL, 0xffffffc7038e38e3ULL, }, - { 0x00000001000038e3ULL, 0xff8e38e300000001ULL, }, - { 0xfff886ae28625540ULL, 0x00000001ffffe7bbULL, }, /* 64 */ - { 0xf10d5cd900286255ULL, 0x00000012ffffffffULL, }, - { 0xffe21ab928625540ULL, 0x00000000ffffffe7ULL, }, - { 0xfffc43570000a189ULL, 0x0000004bfe7bb00cULL, }, - { 0xffffbbe04d93c708ULL, 0x00000000000153f5ULL, }, - { 0xff77c00c004d93c7ULL, 0x0000000400000001ULL, }, - { 0xfffeef804d93c708ULL, 0x0000000000000153ULL, }, - { 0xffffddf00001364fULL, 0x00000012153f52fcULL, }, - { 0xfffac5aab9cf8b80ULL, 0x00000000fffab2b2ULL, }, /* 72 */ - { 0xf58b55d5ffb9cf8bULL, 0x00000009fffffffaULL, }, - { 0xffeb16abb9cf8b80ULL, 0x00000000fffffab2ULL, }, - { 0xfffd62d5fffee73eULL, 0x00000027ab2b2514ULL, }, - { 0x000704f15e31e24eULL, 0xfffffffefffa942eULL, }, - { 0x0e09e2c9005e31e2ULL, 0xffffffe3fffffffaULL, }, - { 0x001c13c55e31e24eULL, 0xfffffffffffffa94ULL, }, - { 0x00038278000178c7ULL, 0xffffff8da942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRA_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_b.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_b.c deleted file mode 100644 index dcda9c2c959d..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRAR.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRAR.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xebebebebebebebebULL, 0xebebebebebebebebULL, }, - { 0xfdfdfdfdfdfdfdfdULL, 0xfdfdfdfdfdfdfdfdULL, }, - { 0xfbfbfbfbfbfbfbfbULL, 0xfbfbfbfbfbfbfbfbULL, }, - { 0xf5f5f5f5f5f5f5f5ULL, 0xf5f5f5f5f5f5f5f5ULL, }, - { 0xf5ffaaf5ffaaf5ffULL, 0xaaf5ffaaf5ffaaf5ULL, }, - { 0xfbd5fffbd5fffbd5ULL, 0xfffbd5fffbd5fffbULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1515151515151515ULL, 0x1515151515151515ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0b0b0b0b0b0b0b0bULL, 0x0b0b0b0b0b0b0b0bULL, }, - { 0x0b01550b01550b01ULL, 0x550b01550b01550bULL, }, - { 0x052b01052b01052bULL, 0x01052b01052b0105ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xf3f3f3f3f3f3f3f3ULL, 0xf3f3f3f3f3f3f3f3ULL, }, - { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, }, - { 0xfdfdfdfdfdfdfdfdULL, 0xfdfdfdfdfdfdfdfdULL, }, - { 0xfafafafafafafafaULL, 0xfafafafafafafafaULL, }, - { 0xfaffccfaffccfaffULL, 0xccfaffccfaffccfaULL, }, - { 0xfde600fde600fde6ULL, 0x00fde600fde600fdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0d0d0d0d0d0d0d0dULL, 0x0d0d0d0d0d0d0d0dULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0x0601330601330601ULL, 0x3306013306013306ULL, }, - { 0x031a00031a00031aULL, 0x00031a00031a0003ULL, }, - { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xf9e40ef9e40ef9e4ULL, 0x0ef9e40ef9e40ef9ULL, }, - { 0xfffc02fffc02fffcULL, 0x02fffc02fffc02ffULL, }, - { 0xfef904fef904fef9ULL, 0x04fef904fef904feULL, }, - { 0xfcf207fcf207fcf2ULL, 0x07fcf207fcf207fcULL, }, - { 0xfcfe38fcfe38fcfeULL, 0x38fcfe38fcfe38fcULL, }, - { 0xfec700fec700fec7ULL, 0x00fec700fec700feULL, }, - { 0x0001000001000001ULL, 0x0000010000010000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x071cf2071cf2071cULL, 0xf2071cf2071cf207ULL, }, - { 0x0104fe0104fe0104ULL, 0xfe0104fe0104fe01ULL, }, - { 0x0207fc0207fc0207ULL, 0xfc0207fc0207fc02ULL, }, - { 0x040ef9040ef9040eULL, 0xf9040ef9040ef904ULL, }, - { 0x0402c70402c70402ULL, 0xc70402c70402c704ULL, }, - { 0x0239000239000239ULL, 0x0002390002390002ULL, }, - { 0x881b00fd28190340ULL, 0x09010101000fb001ULL, }, /* 64 */ - { 0xf102e6fa010c0140ULL, 0x130101180001ec01ULL, }, - { 0xf91b00f314010b40ULL, 0x01670001000ffe01ULL, }, - { 0x880100fe01311501ULL, 0x02340b5eff1fec0cULL, }, - { 0xfbf000064de5fe08ULL, 0x0200f70000085200ULL, }, - { 0xffff000c02f20008ULL, 0x0500f70701001500ULL, }, - { 0x00f0001927fff908ULL, 0x00f7ff0003080300ULL, }, - { 0xfbff000301caf200ULL, 0x01fcbb1a0b1015fcULL, }, - { 0xac17fffbb9f4fc80ULL, 0x0500f900ff052501ULL, }, /* 72 */ - { 0xf601aef5fefaff80ULL, 0x0a00f900fd000901ULL, }, - { 0xfb17ffebdd00f180ULL, 0x00d8ff00f5050101ULL, }, - { 0xac01fffdffe8e3feULL, 0x01ecc6ffd60b0914ULL, }, - { 0x701400055e0cff4eULL, 0xf200f1ffff08e2faULL, }, - { 0x0e01160a0306004eULL, 0xe300f1f6fd01f9faULL, }, - { 0x071400132f00fc4eULL, 0xfff1fe00f508fffaULL, }, - { 0x700100020119f901ULL, 0xfcf988d8d511f9a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_d.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_d.c deleted file mode 100644 index 478098acd9cc..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRAR.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRAR.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffffffffffeaaaabULL, 0xffffffffffeaaaabULL, }, - { 0xfffffd5555555555ULL, 0xfffffd5555555555ULL, }, - { 0xfffaaaaaaaaaaaabULL, 0xfffaaaaaaaaaaaabULL, }, - { 0xfffffffffffff555ULL, 0xfffffffffffff555ULL, }, - { 0xfffeaaaaaaaaaaabULL, 0xfffffffff5555555ULL, }, - { 0xffffffffffffd555ULL, 0xfffffffaaaaaaaabULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000155555ULL, 0x0000000000155555ULL, }, - { 0x000002aaaaaaaaabULL, 0x000002aaaaaaaaabULL, }, - { 0x0005555555555555ULL, 0x0005555555555555ULL, }, - { 0x0000000000000aabULL, 0x0000000000000aabULL, }, - { 0x0001555555555555ULL, 0x000000000aaaaaabULL, }, - { 0x0000000000002aabULL, 0x0000000555555555ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xfffffffffff33333ULL, 0xfffffffffff33333ULL, }, - { 0xfffffe6666666666ULL, 0xfffffe6666666666ULL, }, - { 0xfffccccccccccccdULL, 0xfffccccccccccccdULL, }, - { 0xfffffffffffff99aULL, 0xfffffffffffff99aULL, }, - { 0xffff333333333333ULL, 0xfffffffff999999aULL, }, - { 0xffffffffffffe666ULL, 0xfffffffccccccccdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x00000000000ccccdULL, 0x00000000000ccccdULL, }, - { 0x000001999999999aULL, 0x000001999999999aULL, }, - { 0x0003333333333333ULL, 0x0003333333333333ULL, }, - { 0x0000000000000666ULL, 0x0000000000000666ULL, }, - { 0x0000cccccccccccdULL, 0x0000000006666666ULL, }, - { 0x000000000000199aULL, 0x0000000333333333ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xfffffffffff8e38eULL, 0x00000000000e38e4ULL, }, - { 0xffffff1c71c71c72ULL, 0x000001c71c71c71cULL, }, - { 0xfffe38e38e38e38eULL, 0x00038e38e38e38e4ULL, }, - { 0xfffffffffffffc72ULL, 0x000000000000071cULL, }, - { 0xffff8e38e38e38e4ULL, 0x00000000071c71c7ULL, }, - { 0xfffffffffffff1c7ULL, 0x000000038e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000071c72ULL, 0xfffffffffff1c71cULL, }, - { 0x000000e38e38e38eULL, 0xfffffe38e38e38e4ULL, }, - { 0x0001c71c71c71c72ULL, 0xfffc71c71c71c71cULL, }, - { 0x000000000000038eULL, 0xfffffffffffff8e4ULL, }, - { 0x000071c71c71c71cULL, 0xfffffffff8e38e39ULL, }, - { 0x0000000000000e39ULL, 0xfffffffc71c71c72ULL, }, - { 0x886ae6cc28625540ULL, 0x0004b670b5efe7bbULL, }, /* 64 */ - { 0xff886ae6cc286255ULL, 0x0000000000000005ULL, }, - { 0x886ae6cc28625540ULL, 0x000004b670b5efe8ULL, }, - { 0xfffe21ab9b30a189ULL, 0x000000004b670b5fULL, }, - { 0xfbbe00634d93c708ULL, 0x00012f7bb1a153f5ULL, }, - { 0xfffbbe00634d93c7ULL, 0x0000000000000001ULL, }, - { 0xfbbe00634d93c708ULL, 0x0000012f7bb1a154ULL, }, - { 0xffffeef8018d364fULL, 0x0000000012f7bb1aULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x00027d8c6ffab2b2ULL, }, /* 72 */ - { 0xffac5aaeaab9cf8cULL, 0x0000000000000002ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x0000027d8c6ffab3ULL, }, - { 0xfffeb16abaaae73eULL, 0x0000000027d8c700ULL, }, - { 0x704f164d5e31e24eULL, 0xfff8df188d8a942eULL, }, - { 0x00704f164d5e31e2ULL, 0xfffffffffffffff9ULL, }, - { 0x704f164d5e31e24eULL, 0xfffff8df188d8a94ULL, }, - { 0x0001c13c593578c8ULL, 0xffffffff8df188d9ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_h.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_h.c deleted file mode 100644 index a30025548c92..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRAR.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRAR.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffebffebffebffebULL, 0xffebffebffebffebULL, }, - { 0xfd55fd55fd55fd55ULL, 0xfd55fd55fd55fd55ULL, }, - { 0xfffbfffbfffbfffbULL, 0xfffbfffbfffbfffbULL, }, - { 0xf555f555f555f555ULL, 0xf555f555f555f555ULL, }, - { 0xfffff555ffabffffULL, 0xf555ffabfffff555ULL, }, - { 0xd555fffbff55d555ULL, 0xfffbff55d555fffbULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015001500150015ULL, 0x0015001500150015ULL, }, - { 0x02ab02ab02ab02abULL, 0x02ab02ab02ab02abULL, }, - { 0x0005000500050005ULL, 0x0005000500050005ULL, }, - { 0x0aab0aab0aab0aabULL, 0x0aab0aab0aab0aabULL, }, - { 0x00010aab00550001ULL, 0x0aab005500010aabULL, }, - { 0x2aab000500ab2aabULL, 0x000500ab2aab0005ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xfff3fff3fff3fff3ULL, 0xfff3fff3fff3fff3ULL, }, - { 0xfe66fe66fe66fe66ULL, 0xfe66fe66fe66fe66ULL, }, - { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, - { 0xf99af99af99af99aULL, 0xf99af99af99af99aULL, }, - { 0xfffff99affcdffffULL, 0xf99affcdfffff99aULL, }, - { 0xe666fffdff9ae666ULL, 0xfffdff9ae666fffdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000d000d000d000dULL, 0x000d000d000d000dULL, }, - { 0x019a019a019a019aULL, 0x019a019a019a019aULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x0666066606660666ULL, 0x0666066606660666ULL, }, - { 0x0001066600330001ULL, 0x0666003300010666ULL, }, - { 0x199a00030066199aULL, 0x00030066199a0003ULL, }, - { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xfff9000effe4fff9ULL, 0x000effe4fff9000eULL, }, - { 0xff1c01c7fc72ff1cULL, 0x01c7fc72ff1c01c7ULL, }, - { 0xfffe0004fff9fffeULL, 0x0004fff9fffe0004ULL, }, - { 0xfc72071cf1c7fc72ULL, 0x071cf1c7fc72071cULL, }, - { 0x0000071cff8e0000ULL, 0x071cff8e0000071cULL, }, - { 0xf1c70004ff1cf1c7ULL, 0x0004ff1cf1c70004ULL, }, - { 0x0000000000010000ULL, 0x0000000100000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0007fff2001c0007ULL, 0xfff2001c0007fff2ULL, }, - { 0x00e4fe39038e00e4ULL, 0xfe39038e00e4fe39ULL, }, - { 0x0002fffc00070002ULL, 0xfffc00070002fffcULL, }, - { 0x038ef8e40e39038eULL, 0xf8e40e39038ef8e4ULL, }, - { 0x0000f8e400720000ULL, 0xf8e400720000f8e4ULL, }, - { 0x0e39fffc00e40e39ULL, 0xfffc00e40e39fffcULL, }, - { 0xffe2fffe0a195540ULL, 0x009700000000fffbULL, }, /* 64 */ - { 0xfffefcda050c0055ULL, 0x009700030000fffbULL, }, - { 0xffe2fffa00005540ULL, 0x004b00000000fb01ULL, }, - { 0xffffffff14310001ULL, 0x25b4000bff9fb00cULL, }, - { 0xffff00001365c708ULL, 0x0026ffff00030005ULL, }, - { 0x0000000c09b2ffc7ULL, 0x0026ffef00000005ULL, }, - { 0xffff00000001c708ULL, 0x0013ffff00030530ULL, }, - { 0x0000000026caffffULL, 0x097cffbb055052fcULL, }, - { 0xffebfffbee748b80ULL, 0x0050fffffff50002ULL, }, /* 72 */ - { 0xfffff5d5f73aff8cULL, 0x0050fff2ffff0002ULL, }, - { 0xffebffecffff8b80ULL, 0x00280000fff50251ULL, }, - { 0xfffffffddce8fffeULL, 0x13ecffc7eacb2514ULL, }, - { 0x001c0001178ce24eULL, 0xff1cfffefff5fffeULL, }, - { 0x000202ca0bc6ffe2ULL, 0xff1cffe2fffffffeULL, }, - { 0x001c00060001e24eULL, 0xff8efffffff5fe2aULL, }, - { 0x000100012f190000ULL, 0xc6f9ff89ea51e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_w.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_w.c deleted file mode 100644 index 027d4ce56502..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srar_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRAR.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRAR.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0xffeaaaabffeaaaabULL, 0xffeaaaabffeaaaabULL, }, - { 0xfffffd55fffffd55ULL, 0xfffffd55fffffd55ULL, }, - { 0xfffaaaabfffaaaabULL, 0xfffaaaabfffaaaabULL, }, - { 0xfffff555fffff555ULL, 0xfffff555fffff555ULL, }, - { 0xf5555555fffeaaabULL, 0xffffffabf5555555ULL, }, - { 0xfffffffbffffd555ULL, 0xff555555fffffffbULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015555500155555ULL, 0x0015555500155555ULL, }, - { 0x000002ab000002abULL, 0x000002ab000002abULL, }, - { 0x0005555500055555ULL, 0x0005555500055555ULL, }, - { 0x00000aab00000aabULL, 0x00000aab00000aabULL, }, - { 0x0aaaaaab00015555ULL, 0x000000550aaaaaabULL, }, - { 0x0000000500002aabULL, 0x00aaaaab00000005ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0xfff33333fff33333ULL, 0xfff33333fff33333ULL, }, - { 0xfffffe66fffffe66ULL, 0xfffffe66fffffe66ULL, }, - { 0xfffccccdfffccccdULL, 0xfffccccdfffccccdULL, }, - { 0xfffff99afffff99aULL, 0xfffff99afffff99aULL, }, - { 0xf999999affff3333ULL, 0xffffffcdf999999aULL, }, - { 0xfffffffdffffe666ULL, 0xff99999afffffffdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000ccccd000ccccdULL, 0x000ccccd000ccccdULL, }, - { 0x0000019a0000019aULL, 0x0000019a0000019aULL, }, - { 0x0003333300033333ULL, 0x0003333300033333ULL, }, - { 0x0000066600000666ULL, 0x0000066600000666ULL, }, - { 0x066666660000cccdULL, 0x0000003306666666ULL, }, - { 0x000000030000199aULL, 0x0066666600000003ULL, }, - { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0xfff8e38effe38e39ULL, 0x000e38e4fff8e38eULL, }, - { 0xffffff1cfffffc72ULL, 0x000001c7ffffff1cULL, }, - { 0xfffe38e4fff8e38eULL, 0x00038e39fffe38e4ULL, }, - { 0xfffffc72fffff1c7ULL, 0x0000071cfffffc72ULL, }, - { 0xfc71c71cfffe38e4ULL, 0x00000039fc71c71cULL, }, - { 0xfffffffeffffc71cULL, 0x0071c71cfffffffeULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00071c72001c71c7ULL, 0xfff1c71c00071c72ULL, }, - { 0x000000e40000038eULL, 0xfffffe39000000e4ULL, }, - { 0x0001c71c00071c72ULL, 0xfffc71c70001c71cULL, }, - { 0x0000038e00000e39ULL, 0xfffff8e40000038eULL, }, - { 0x038e38e40001c71cULL, 0xffffffc7038e38e4ULL, }, - { 0x00000002000038e4ULL, 0xff8e38e400000002ULL, }, - { 0xfff886ae28625540ULL, 0x00000001ffffe7bbULL, }, /* 64 */ - { 0xf10d5cda00286255ULL, 0x0000001300000000ULL, }, - { 0xffe21aba28625540ULL, 0x00000001ffffffe8ULL, }, - { 0xfffc43570000a189ULL, 0x0000004bfe7bb00cULL, }, - { 0xffffbbe04d93c708ULL, 0x00000000000153f5ULL, }, - { 0xff77c00c004d93c7ULL, 0x0000000500000001ULL, }, - { 0xfffeef804d93c708ULL, 0x0000000000000154ULL, }, - { 0xffffddf00001364fULL, 0x00000013153f52fcULL, }, - { 0xfffac5abb9cf8b80ULL, 0x00000001fffab2b2ULL, }, /* 72 */ - { 0xf58b55d5ffb9cf8cULL, 0x0000000afffffffbULL, }, - { 0xffeb16acb9cf8b80ULL, 0x00000000fffffab3ULL, }, - { 0xfffd62d5fffee73eULL, 0x00000028ab2b2514ULL, }, - { 0x000704f15e31e24eULL, 0xfffffffefffa942eULL, }, - { 0x0e09e2ca005e31e2ULL, 0xffffffe3fffffffbULL, }, - { 0x001c13c65e31e24eULL, 0xfffffffffffffa94ULL, }, - { 0x00038279000178c8ULL, 0xffffff8ea942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRAR_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_b.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_b.c deleted file mode 100644 index 0e7c453cec11..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRL.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRL.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x3f3f3f3f3f3f3f3fULL, 0x3f3f3f3f3f3f3f3fULL, }, - { 0x0707070707070707ULL, 0x0707070707070707ULL, }, - { 0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL, }, - { 0x1f1f1f1f1f1f1f1fULL, 0x1f1f1f1f1f1f1f1fULL, }, - { 0x1f03ff1f03ff1f03ULL, 0xff1f03ff1f03ff1fULL, }, - { 0x0f7f010f7f010f7fULL, 0x010f7f010f7f010fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2a2a2a2a2a2a2a2aULL, 0x2a2a2a2a2a2a2a2aULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0a0a0a0a0a0a0a0aULL, 0x0a0a0a0a0a0a0a0aULL, }, - { 0x1515151515151515ULL, 0x1515151515151515ULL, }, - { 0x1502aa1502aa1502ULL, 0xaa1502aa1502aa15ULL, }, - { 0x0a55010a55010a55ULL, 0x010a55010a55010aULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1515151515151515ULL, 0x1515151515151515ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0a0a0a0a0a0a0a0aULL, 0x0a0a0a0a0a0a0a0aULL, }, - { 0x0a01550a01550a01ULL, 0x550a01550a01550aULL, }, - { 0x052a00052a00052aULL, 0x00052a00052a0005ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0x0c0c0c0c0c0c0c0cULL, 0x0c0c0c0c0c0c0c0cULL, }, - { 0x1919191919191919ULL, 0x1919191919191919ULL, }, - { 0x1903cc1903cc1903ULL, 0xcc1903cc1903cc19ULL, }, - { 0x0c66010c66010c66ULL, 0x010c66010c66010cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0c0c0c0c0c0c0c0cULL, 0x0c0c0c0c0c0c0c0cULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0x0600330600330600ULL, 0x3306003306003306ULL, }, - { 0x0319000319000319ULL, 0x0003190003190003ULL, }, - { 0x0101000101000101ULL, 0x0001010001010001ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x38230e38230e3823ULL, 0x0e38230e38230e38ULL, }, - { 0x0704010704010704ULL, 0x0107040107040107ULL, }, - { 0x0e08030e08030e08ULL, 0x030e08030e08030eULL, }, - { 0x1c11071c11071c11ULL, 0x071c11071c11071cULL, }, - { 0x1c02381c02381c02ULL, 0x381c02381c02381cULL, }, - { 0x0e47000e47000e47ULL, 0x000e47000e47000eULL, }, - { 0x0000010000010000ULL, 0x0100000100000100ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x071c31071c31071cULL, 0x31071c31071c3107ULL, }, - { 0x0003060003060003ULL, 0x0600030600030600ULL, }, - { 0x01070c01070c0107ULL, 0x0c01070c01070c01ULL, }, - { 0x030e18030e18030eULL, 0x18030e18030e1803ULL, }, - { 0x0301c70301c70301ULL, 0xc70301c70301c703ULL, }, - { 0x0138010138010138ULL, 0x0101380101380101ULL, }, - { 0x881a030c28180240ULL, 0x09000101030fb000ULL, }, /* 64 */ - { 0x1101e619010c0040ULL, 0x1200011707002c00ULL, }, - { 0x081a033314000a40ULL, 0x006700001f0f0500ULL, }, - { 0x8800030600311501ULL, 0x02330b5e7f1e2c0cULL, }, - { 0xfb2f00064d240608ULL, 0x020117000007520fULL, }, - { 0x1f02000c02120108ULL, 0x040117060000140fULL, }, - { 0x0f2f001826011808ULL, 0x00f702000207020fULL, }, - { 0xfb01000301493100ULL, 0x007bbb1a0a0f14fcULL, }, - { 0xac16020ab9330480ULL, 0x0401180302052501ULL, }, /* 72 */ - { 0x1501ae1505190180ULL, 0x0901183f05000901ULL, }, - { 0x0a16022a5c011180ULL, 0x00d8030115050101ULL, }, - { 0xac00020502672202ULL, 0x016cc6ff550a0914ULL, }, - { 0x701300045e0c074eULL, 0x110111030208e20aULL, }, - { 0x0e0116090206014eULL, 0x230111360500380aULL, }, - { 0x071300132f001c4eULL, 0x01f102011508070aULL, }, - { 0x7000000201183801ULL, 0x047888d8541038a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_d.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_d.c deleted file mode 100644 index f6351f875a02..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRL.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRL.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x00000000003fffffULL, 0x00000000003fffffULL, }, - { 0x000007ffffffffffULL, 0x000007ffffffffffULL, }, - { 0x000fffffffffffffULL, 0x000fffffffffffffULL, }, - { 0x0000000000001fffULL, 0x0000000000001fffULL, }, - { 0x0003ffffffffffffULL, 0x000000001fffffffULL, }, - { 0x0000000000007fffULL, 0x0000000fffffffffULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x00000000002aaaaaULL, 0x00000000002aaaaaULL, }, - { 0x0000055555555555ULL, 0x0000055555555555ULL, }, - { 0x000aaaaaaaaaaaaaULL, 0x000aaaaaaaaaaaaaULL, }, - { 0x0000000000001555ULL, 0x0000000000001555ULL, }, - { 0x0002aaaaaaaaaaaaULL, 0x0000000015555555ULL, }, - { 0x0000000000005555ULL, 0x0000000aaaaaaaaaULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000155555ULL, 0x0000000000155555ULL, }, - { 0x000002aaaaaaaaaaULL, 0x000002aaaaaaaaaaULL, }, - { 0x0005555555555555ULL, 0x0005555555555555ULL, }, - { 0x0000000000000aaaULL, 0x0000000000000aaaULL, }, - { 0x0001555555555555ULL, 0x000000000aaaaaaaULL, }, - { 0x0000000000002aaaULL, 0x0000000555555555ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000333333ULL, 0x0000000000333333ULL, }, - { 0x0000066666666666ULL, 0x0000066666666666ULL, }, - { 0x000cccccccccccccULL, 0x000cccccccccccccULL, }, - { 0x0000000000001999ULL, 0x0000000000001999ULL, }, - { 0x0003333333333333ULL, 0x0000000019999999ULL, }, - { 0x0000000000006666ULL, 0x0000000cccccccccULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x00000000000cccccULL, 0x00000000000cccccULL, }, - { 0x0000019999999999ULL, 0x0000019999999999ULL, }, - { 0x0003333333333333ULL, 0x0003333333333333ULL, }, - { 0x0000000000000666ULL, 0x0000000000000666ULL, }, - { 0x0000ccccccccccccULL, 0x0000000006666666ULL, }, - { 0x0000000000001999ULL, 0x0000000333333333ULL, }, - { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x000000000038e38eULL, 0x00000000000e38e3ULL, }, - { 0x0000071c71c71c71ULL, 0x000001c71c71c71cULL, }, - { 0x000e38e38e38e38eULL, 0x00038e38e38e38e3ULL, }, - { 0x0000000000001c71ULL, 0x000000000000071cULL, }, - { 0x00038e38e38e38e3ULL, 0x00000000071c71c7ULL, }, - { 0x00000000000071c7ULL, 0x000000038e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000001ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000071c71ULL, 0x000000000031c71cULL, }, - { 0x000000e38e38e38eULL, 0x00000638e38e38e3ULL, }, - { 0x0001c71c71c71c71ULL, 0x000c71c71c71c71cULL, }, - { 0x000000000000038eULL, 0x00000000000018e3ULL, }, - { 0x000071c71c71c71cULL, 0x0000000018e38e38ULL, }, - { 0x0000000000000e38ULL, 0x0000000c71c71c71ULL, }, - { 0x886ae6cc28625540ULL, 0x0004b670b5efe7bbULL, }, /* 64 */ - { 0x00886ae6cc286255ULL, 0x0000000000000004ULL, }, - { 0x886ae6cc28625540ULL, 0x000004b670b5efe7ULL, }, - { 0x000221ab9b30a189ULL, 0x000000004b670b5eULL, }, - { 0xfbbe00634d93c708ULL, 0x00012f7bb1a153f5ULL, }, - { 0x00fbbe00634d93c7ULL, 0x0000000000000001ULL, }, - { 0xfbbe00634d93c708ULL, 0x0000012f7bb1a153ULL, }, - { 0x0003eef8018d364fULL, 0x0000000012f7bb1aULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x00027d8c6ffab2b2ULL, }, /* 72 */ - { 0x00ac5aaeaab9cf8bULL, 0x0000000000000002ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x0000027d8c6ffab2ULL, }, - { 0x0002b16abaaae73eULL, 0x0000000027d8c6ffULL, }, - { 0x704f164d5e31e24eULL, 0x0008df188d8a942eULL, }, - { 0x00704f164d5e31e2ULL, 0x0000000000000008ULL, }, - { 0x704f164d5e31e24eULL, 0x000008df188d8a94ULL, }, - { 0x0001c13c593578c7ULL, 0x000000008df188d8ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_h.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_h.c deleted file mode 100644 index 93394ef47a51..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRL.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRL.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x003f003f003f003fULL, 0x003f003f003f003fULL, }, - { 0x07ff07ff07ff07ffULL, 0x07ff07ff07ff07ffULL, }, - { 0x000f000f000f000fULL, 0x000f000f000f000fULL, }, - { 0x1fff1fff1fff1fffULL, 0x1fff1fff1fff1fffULL, }, - { 0x00031fff00ff0003ULL, 0x1fff00ff00031fffULL, }, - { 0x7fff000f01ff7fffULL, 0x000f01ff7fff000fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x002a002a002a002aULL, 0x002a002a002a002aULL, }, - { 0x0555055505550555ULL, 0x0555055505550555ULL, }, - { 0x000a000a000a000aULL, 0x000a000a000a000aULL, }, - { 0x1555155515551555ULL, 0x1555155515551555ULL, }, - { 0x0002155500aa0002ULL, 0x155500aa00021555ULL, }, - { 0x5555000a01555555ULL, 0x000a01555555000aULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015001500150015ULL, 0x0015001500150015ULL, }, - { 0x02aa02aa02aa02aaULL, 0x02aa02aa02aa02aaULL, }, - { 0x0005000500050005ULL, 0x0005000500050005ULL, }, - { 0x0aaa0aaa0aaa0aaaULL, 0x0aaa0aaa0aaa0aaaULL, }, - { 0x00010aaa00550001ULL, 0x0aaa005500010aaaULL, }, - { 0x2aaa000500aa2aaaULL, 0x000500aa2aaa0005ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x0666066606660666ULL, 0x0666066606660666ULL, }, - { 0x000c000c000c000cULL, 0x000c000c000c000cULL, }, - { 0x1999199919991999ULL, 0x1999199919991999ULL, }, - { 0x0003199900cc0003ULL, 0x199900cc00031999ULL, }, - { 0x6666000c01996666ULL, 0x000c01996666000cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000c000c000c000cULL, 0x000c000c000c000cULL, }, - { 0x0199019901990199ULL, 0x0199019901990199ULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x0666066606660666ULL, 0x0666066606660666ULL, }, - { 0x0000066600330000ULL, 0x0666003300000666ULL, }, - { 0x1999000300661999ULL, 0x0003006619990003ULL, }, - { 0x0001000000010001ULL, 0x0000000100010000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0038000e00230038ULL, 0x000e00230038000eULL, }, - { 0x071c01c70471071cULL, 0x01c70471071c01c7ULL, }, - { 0x000e00030008000eULL, 0x00030008000e0003ULL, }, - { 0x1c71071c11c71c71ULL, 0x071c11c71c71071cULL, }, - { 0x0003071c008e0003ULL, 0x071c008e0003071cULL, }, - { 0x71c70003011c71c7ULL, 0x0003011c71c70003ULL, }, - { 0x0000000100000000ULL, 0x0001000000000001ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00070031001c0007ULL, 0x0031001c00070031ULL, }, - { 0x00e30638038e00e3ULL, 0x0638038e00e30638ULL, }, - { 0x0001000c00070001ULL, 0x000c00070001000cULL, }, - { 0x038e18e30e38038eULL, 0x18e30e38038e18e3ULL, }, - { 0x000018e300710000ULL, 0x18e30071000018e3ULL, }, - { 0x0e38000c00e30e38ULL, 0x000c00e30e38000cULL, }, - { 0x0022000e0a185540ULL, 0x00960000001f000bULL, }, /* 64 */ - { 0x00021cd9050c0055ULL, 0x009600020001000bULL, }, - { 0x0022003900005540ULL, 0x004b0000001f0b00ULL, }, - { 0x0001000714310001ULL, 0x25b3000b3f9eb00cULL, }, - { 0x003e00001364c708ULL, 0x0025000200020005ULL, }, - { 0x0003000c09b200c7ULL, 0x0025002e00000005ULL, }, - { 0x003e00000000c708ULL, 0x001200010002052fULL, }, - { 0x0001000026c90003ULL, 0x097b00bb054f52fcULL, }, - { 0x002b000a2e738b80ULL, 0x004f000300150002ULL, }, /* 72 */ - { 0x000215d51739008bULL, 0x004f003100010002ULL, }, - { 0x002b002b00018b80ULL, 0x0027000100150251ULL, }, - { 0x000100055ce70002ULL, 0x13ec00c62aca2514ULL, }, - { 0x001c0001178ce24eULL, 0x011b00020015000eULL, }, - { 0x000102c90bc600e2ULL, 0x011b00220001000eULL, }, - { 0x001c00050000e24eULL, 0x008d000100150e2aULL, }, - { 0x000000002f180003ULL, 0x46f800882a50e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_w.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_w.c deleted file mode 100644 index c18cd9892ab1..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srl_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRL.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRL.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x003fffff003fffffULL, 0x003fffff003fffffULL, }, - { 0x000007ff000007ffULL, 0x000007ff000007ffULL, }, - { 0x000fffff000fffffULL, 0x000fffff000fffffULL, }, - { 0x00001fff00001fffULL, 0x00001fff00001fffULL, }, - { 0x1fffffff0003ffffULL, 0x000000ff1fffffffULL, }, - { 0x0000000f00007fffULL, 0x01ffffff0000000fULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x002aaaaa002aaaaaULL, 0x002aaaaa002aaaaaULL, }, - { 0x0000055500000555ULL, 0x0000055500000555ULL, }, - { 0x000aaaaa000aaaaaULL, 0x000aaaaa000aaaaaULL, }, - { 0x0000155500001555ULL, 0x0000155500001555ULL, }, - { 0x155555550002aaaaULL, 0x000000aa15555555ULL, }, - { 0x0000000a00005555ULL, 0x015555550000000aULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015555500155555ULL, 0x0015555500155555ULL, }, - { 0x000002aa000002aaULL, 0x000002aa000002aaULL, }, - { 0x0005555500055555ULL, 0x0005555500055555ULL, }, - { 0x00000aaa00000aaaULL, 0x00000aaa00000aaaULL, }, - { 0x0aaaaaaa00015555ULL, 0x000000550aaaaaaaULL, }, - { 0x0000000500002aaaULL, 0x00aaaaaa00000005ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0033333300333333ULL, 0x0033333300333333ULL, }, - { 0x0000066600000666ULL, 0x0000066600000666ULL, }, - { 0x000ccccc000cccccULL, 0x000ccccc000cccccULL, }, - { 0x0000199900001999ULL, 0x0000199900001999ULL, }, - { 0x1999999900033333ULL, 0x000000cc19999999ULL, }, - { 0x0000000c00006666ULL, 0x019999990000000cULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000ccccc000cccccULL, 0x000ccccc000cccccULL, }, - { 0x0000019900000199ULL, 0x0000019900000199ULL, }, - { 0x0003333300033333ULL, 0x0003333300033333ULL, }, - { 0x0000066600000666ULL, 0x0000066600000666ULL, }, - { 0x066666660000ccccULL, 0x0000003306666666ULL, }, - { 0x0000000300001999ULL, 0x0066666600000003ULL, }, - { 0x0000000100000001ULL, 0x0000000000000001ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0038e38e00238e38ULL, 0x000e38e30038e38eULL, }, - { 0x0000071c00000471ULL, 0x000001c70000071cULL, }, - { 0x000e38e30008e38eULL, 0x00038e38000e38e3ULL, }, - { 0x00001c71000011c7ULL, 0x0000071c00001c71ULL, }, - { 0x1c71c71c000238e3ULL, 0x000000381c71c71cULL, }, - { 0x0000000e0000471cULL, 0x0071c71c0000000eULL, }, - { 0x0000000000000000ULL, 0x0000000100000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00071c71001c71c7ULL, 0x0031c71c00071c71ULL, }, - { 0x000000e30000038eULL, 0x00000638000000e3ULL, }, - { 0x0001c71c00071c71ULL, 0x000c71c70001c71cULL, }, - { 0x0000038e00000e38ULL, 0x000018e30000038eULL, }, - { 0x038e38e30001c71cULL, 0x000000c7038e38e3ULL, }, - { 0x00000001000038e3ULL, 0x018e38e300000001ULL, }, - { 0x000886ae28625540ULL, 0x00000001000fe7bbULL, }, /* 64 */ - { 0x110d5cd900286255ULL, 0x000000120000000fULL, }, - { 0x00221ab928625540ULL, 0x0000000000000fe7ULL, }, - { 0x000443570000a189ULL, 0x0000004bfe7bb00cULL, }, - { 0x000fbbe04d93c708ULL, 0x00000000000153f5ULL, }, - { 0x1f77c00c004d93c7ULL, 0x0000000400000001ULL, }, - { 0x003eef804d93c708ULL, 0x0000000000000153ULL, }, - { 0x0007ddf00001364fULL, 0x00000012153f52fcULL, }, - { 0x000ac5aab9cf8b80ULL, 0x00000000000ab2b2ULL, }, /* 72 */ - { 0x158b55d500b9cf8bULL, 0x000000090000000aULL, }, - { 0x002b16abb9cf8b80ULL, 0x0000000000000ab2ULL, }, - { 0x000562d50002e73eULL, 0x00000027ab2b2514ULL, }, - { 0x000704f15e31e24eULL, 0x00000002000a942eULL, }, - { 0x0e09e2c9005e31e2ULL, 0x000000230000000aULL, }, - { 0x001c13c55e31e24eULL, 0x0000000100000a94ULL, }, - { 0x00038278000178c7ULL, 0x0000008da942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRL_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_b.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_b.c deleted file mode 100644 index d173d8fa9cff..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_b.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRLR.B - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRLR.B"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x4040404040404040ULL, 0x4040404040404040ULL, }, - { 0x0808080808080808ULL, 0x0808080808080808ULL, }, - { 0x1010101010101010ULL, 0x1010101010101010ULL, }, - { 0x2020202020202020ULL, 0x2020202020202020ULL, }, - { 0x2004ff2004ff2004ULL, 0xff2004ff2004ff20ULL, }, - { 0x1080021080021080ULL, 0x0210800210800210ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x2b2b2b2b2b2b2b2bULL, 0x2b2b2b2b2b2b2b2bULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0b0b0b0b0b0b0b0bULL, 0x0b0b0b0b0b0b0b0bULL, }, - { 0x1515151515151515ULL, 0x1515151515151515ULL, }, - { 0x1503aa1503aa1503ULL, 0xaa1503aa1503aa15ULL, }, - { 0x0b55010b55010b55ULL, 0x010b55010b55010bULL, }, - { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x1515151515151515ULL, 0x1515151515151515ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0505050505050505ULL, 0x0505050505050505ULL, }, - { 0x0b0b0b0b0b0b0b0bULL, 0x0b0b0b0b0b0b0b0bULL, }, - { 0x0b01550b01550b01ULL, 0x550b01550b01550bULL, }, - { 0x052b01052b01052bULL, 0x01052b01052b0105ULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0x0d0d0d0d0d0d0d0dULL, 0x0d0d0d0d0d0d0d0dULL, }, - { 0x1a1a1a1a1a1a1a1aULL, 0x1a1a1a1a1a1a1a1aULL, }, - { 0x1a03cc1a03cc1a03ULL, 0xcc1a03cc1a03cc1aULL, }, - { 0x0d66020d66020d66ULL, 0x020d66020d66020dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x0d0d0d0d0d0d0d0dULL, 0x0d0d0d0d0d0d0d0dULL, }, - { 0x0202020202020202ULL, 0x0202020202020202ULL, }, - { 0x0303030303030303ULL, 0x0303030303030303ULL, }, - { 0x0606060606060606ULL, 0x0606060606060606ULL, }, - { 0x0601330601330601ULL, 0x3306013306013306ULL, }, - { 0x031a00031a00031aULL, 0x00031a00031a0003ULL, }, - { 0x0201000201000201ULL, 0x0002010002010002ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x39240e39240e3924ULL, 0x0e39240e39240e39ULL, }, - { 0x0704020704020704ULL, 0x0207040207040207ULL, }, - { 0x0e09040e09040e09ULL, 0x040e09040e09040eULL, }, - { 0x1c12071c12071c12ULL, 0x071c12071c12071cULL, }, - { 0x1c02381c02381c02ULL, 0x381c02381c02381cULL, }, - { 0x0e47000e47000e47ULL, 0x000e47000e47000eULL, }, - { 0x0001020001020001ULL, 0x0200010200010200ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x071c32071c32071cULL, 0x32071c32071c3207ULL, }, - { 0x0104060104060104ULL, 0x0601040601040601ULL, }, - { 0x02070c02070c0207ULL, 0x0c02070c02070c02ULL, }, - { 0x040e19040e19040eULL, 0x19040e19040e1904ULL, }, - { 0x0402c70402c70402ULL, 0xc70402c70402c704ULL, }, - { 0x0239020239020239ULL, 0x0202390202390202ULL, }, - { 0x881b040d28190340ULL, 0x09010101040fb001ULL, }, /* 64 */ - { 0x1102e61a010c0140ULL, 0x1301011808012c01ULL, }, - { 0x091b043314010b40ULL, 0x01670001200f0601ULL, }, - { 0x8801040601311501ULL, 0x02340b5e7f1f2c0cULL, }, - { 0xfb3000064d250608ULL, 0x0202170000085210ULL, }, - { 0x1f03000c02120208ULL, 0x0502170701001510ULL, }, - { 0x1030001927011908ULL, 0x00f7030003080310ULL, }, - { 0xfb010003014a3200ULL, 0x017cbb1a0b1015fcULL, }, - { 0xac17030bb9340480ULL, 0x0502190403052501ULL, }, /* 72 */ - { 0x1601ae15061a0180ULL, 0x0a02194005000901ULL, }, - { 0x0b17032b5d021180ULL, 0x00d8030215050101ULL, }, - { 0xac01030503682302ULL, 0x016cc6ff560b0914ULL, }, - { 0x701400055e0c074eULL, 0x120211030308e20aULL, }, - { 0x0e01160a0306024eULL, 0x230211360501390aULL, }, - { 0x071400132f001c4eULL, 0x01f102021508070aULL, }, - { 0x7001000201193901ULL, 0x047988d8551139a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_B(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_B(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_d.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_d.c deleted file mode 100644 index ecd7bd0c229a..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_d.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRLR.D - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRLR.D"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0000000000400000ULL, 0x0000000000400000ULL, }, - { 0x0000080000000000ULL, 0x0000080000000000ULL, }, - { 0x0010000000000000ULL, 0x0010000000000000ULL, }, - { 0x0000000000002000ULL, 0x0000000000002000ULL, }, - { 0x0004000000000000ULL, 0x0000000020000000ULL, }, - { 0x0000000000008000ULL, 0x0000001000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x00000000002aaaabULL, 0x00000000002aaaabULL, }, - { 0x0000055555555555ULL, 0x0000055555555555ULL, }, - { 0x000aaaaaaaaaaaabULL, 0x000aaaaaaaaaaaabULL, }, - { 0x0000000000001555ULL, 0x0000000000001555ULL, }, - { 0x0002aaaaaaaaaaabULL, 0x0000000015555555ULL, }, - { 0x0000000000005555ULL, 0x0000000aaaaaaaabULL, }, - { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0000000000155555ULL, 0x0000000000155555ULL, }, - { 0x000002aaaaaaaaabULL, 0x000002aaaaaaaaabULL, }, - { 0x0005555555555555ULL, 0x0005555555555555ULL, }, - { 0x0000000000000aabULL, 0x0000000000000aabULL, }, - { 0x0001555555555555ULL, 0x000000000aaaaaabULL, }, - { 0x0000000000002aabULL, 0x0000000555555555ULL, }, - { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0000000000333333ULL, 0x0000000000333333ULL, }, - { 0x0000066666666666ULL, 0x0000066666666666ULL, }, - { 0x000ccccccccccccdULL, 0x000ccccccccccccdULL, }, - { 0x000000000000199aULL, 0x000000000000199aULL, }, - { 0x0003333333333333ULL, 0x000000001999999aULL, }, - { 0x0000000000006666ULL, 0x0000000ccccccccdULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x00000000000ccccdULL, 0x00000000000ccccdULL, }, - { 0x000001999999999aULL, 0x000001999999999aULL, }, - { 0x0003333333333333ULL, 0x0003333333333333ULL, }, - { 0x0000000000000666ULL, 0x0000000000000666ULL, }, - { 0x0000cccccccccccdULL, 0x0000000006666666ULL, }, - { 0x000000000000199aULL, 0x0000000333333333ULL, }, - { 0x0000000000000002ULL, 0x0000000000000000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x000000000038e38eULL, 0x00000000000e38e4ULL, }, - { 0x0000071c71c71c72ULL, 0x000001c71c71c71cULL, }, - { 0x000e38e38e38e38eULL, 0x00038e38e38e38e4ULL, }, - { 0x0000000000001c72ULL, 0x000000000000071cULL, }, - { 0x00038e38e38e38e4ULL, 0x00000000071c71c7ULL, }, - { 0x00000000000071c7ULL, 0x000000038e38e38eULL, }, - { 0x0000000000000000ULL, 0x0000000000000002ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x0000000000071c72ULL, 0x000000000031c71cULL, }, - { 0x000000e38e38e38eULL, 0x00000638e38e38e4ULL, }, - { 0x0001c71c71c71c72ULL, 0x000c71c71c71c71cULL, }, - { 0x000000000000038eULL, 0x00000000000018e4ULL, }, - { 0x000071c71c71c71cULL, 0x0000000018e38e39ULL, }, - { 0x0000000000000e39ULL, 0x0000000c71c71c72ULL, }, - { 0x886ae6cc28625540ULL, 0x0004b670b5efe7bbULL, }, /* 64 */ - { 0x00886ae6cc286255ULL, 0x0000000000000005ULL, }, - { 0x886ae6cc28625540ULL, 0x000004b670b5efe8ULL, }, - { 0x000221ab9b30a189ULL, 0x000000004b670b5fULL, }, - { 0xfbbe00634d93c708ULL, 0x00012f7bb1a153f5ULL, }, - { 0x00fbbe00634d93c7ULL, 0x0000000000000001ULL, }, - { 0xfbbe00634d93c708ULL, 0x0000012f7bb1a154ULL, }, - { 0x0003eef8018d364fULL, 0x0000000012f7bb1aULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x00027d8c6ffab2b2ULL, }, /* 72 */ - { 0x00ac5aaeaab9cf8cULL, 0x0000000000000002ULL, }, - { 0xac5aaeaab9cf8b80ULL, 0x0000027d8c6ffab3ULL, }, - { 0x0002b16abaaae73eULL, 0x0000000027d8c700ULL, }, - { 0x704f164d5e31e24eULL, 0x0008df188d8a942eULL, }, - { 0x00704f164d5e31e2ULL, 0x0000000000000009ULL, }, - { 0x704f164d5e31e24eULL, 0x000008df188d8a94ULL, }, - { 0x0001c13c593578c8ULL, 0x000000008df188d9ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_D(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_D(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_h.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_h.c deleted file mode 100644 index ca7fd7534240..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_h.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRLR.H - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRLR.H"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0040004000400040ULL, 0x0040004000400040ULL, }, - { 0x0800080008000800ULL, 0x0800080008000800ULL, }, - { 0x0010001000100010ULL, 0x0010001000100010ULL, }, - { 0x2000200020002000ULL, 0x2000200020002000ULL, }, - { 0x0004200001000004ULL, 0x2000010000042000ULL, }, - { 0x8000001002008000ULL, 0x0010020080000010ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x002b002b002b002bULL, 0x002b002b002b002bULL, }, - { 0x0555055505550555ULL, 0x0555055505550555ULL, }, - { 0x000b000b000b000bULL, 0x000b000b000b000bULL, }, - { 0x1555155515551555ULL, 0x1555155515551555ULL, }, - { 0x0003155500ab0003ULL, 0x155500ab00031555ULL, }, - { 0x5555000b01555555ULL, 0x000b01555555000bULL, }, - { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015001500150015ULL, 0x0015001500150015ULL, }, - { 0x02ab02ab02ab02abULL, 0x02ab02ab02ab02abULL, }, - { 0x0005000500050005ULL, 0x0005000500050005ULL, }, - { 0x0aab0aab0aab0aabULL, 0x0aab0aab0aab0aabULL, }, - { 0x00010aab00550001ULL, 0x0aab005500010aabULL, }, - { 0x2aab000500ab2aabULL, 0x000500ab2aab0005ULL, }, - { 0x0002000200020002ULL, 0x0002000200020002ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0033003300330033ULL, 0x0033003300330033ULL, }, - { 0x0666066606660666ULL, 0x0666066606660666ULL, }, - { 0x000d000d000d000dULL, 0x000d000d000d000dULL, }, - { 0x199a199a199a199aULL, 0x199a199a199a199aULL, }, - { 0x0003199a00cd0003ULL, 0x199a00cd0003199aULL, }, - { 0x6666000d019a6666ULL, 0x000d019a6666000dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000d000d000d000dULL, 0x000d000d000d000dULL, }, - { 0x019a019a019a019aULL, 0x019a019a019a019aULL, }, - { 0x0003000300030003ULL, 0x0003000300030003ULL, }, - { 0x0666066606660666ULL, 0x0666066606660666ULL, }, - { 0x0001066600330001ULL, 0x0666003300010666ULL, }, - { 0x199a00030066199aULL, 0x00030066199a0003ULL, }, - { 0x0002000000010002ULL, 0x0000000100020000ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0039000e00240039ULL, 0x000e00240039000eULL, }, - { 0x071c01c70472071cULL, 0x01c70472071c01c7ULL, }, - { 0x000e00040009000eULL, 0x00040009000e0004ULL, }, - { 0x1c72071c11c71c72ULL, 0x071c11c71c72071cULL, }, - { 0x0004071c008e0004ULL, 0x071c008e0004071cULL, }, - { 0x71c70004011c71c7ULL, 0x0004011c71c70004ULL, }, - { 0x0000000200010000ULL, 0x0002000100000002ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00070032001c0007ULL, 0x0032001c00070032ULL, }, - { 0x00e40639038e00e4ULL, 0x0639038e00e40639ULL, }, - { 0x0002000c00070002ULL, 0x000c00070002000cULL, }, - { 0x038e18e40e39038eULL, 0x18e40e39038e18e4ULL, }, - { 0x000018e400720000ULL, 0x18e40072000018e4ULL, }, - { 0x0e39000c00e40e39ULL, 0x000c00e40e39000cULL, }, - { 0x0022000e0a195540ULL, 0x009700000020000bULL, }, /* 64 */ - { 0x00021cda050c0055ULL, 0x009700030002000bULL, }, - { 0x0022003a00005540ULL, 0x004b000000200b01ULL, }, - { 0x0001000714310001ULL, 0x25b4000b3f9fb00cULL, }, - { 0x003f00001365c708ULL, 0x0026000300030005ULL, }, - { 0x0004000c09b200c7ULL, 0x0026002f00000005ULL, }, - { 0x003f00000001c708ULL, 0x0013000100030530ULL, }, - { 0x0002000026ca0003ULL, 0x097c00bb055052fcULL, }, - { 0x002b000b2e748b80ULL, 0x0050000300150002ULL, }, /* 72 */ - { 0x000315d5173a008cULL, 0x0050003200010002ULL, }, - { 0x002b002c00018b80ULL, 0x0028000200150251ULL, }, - { 0x000100055ce80002ULL, 0x13ec00c72acb2514ULL, }, - { 0x001c0001178ce24eULL, 0x011c00020015000eULL, }, - { 0x000202ca0bc600e2ULL, 0x011c00220001000eULL, }, - { 0x001c00060001e24eULL, 0x008e000100150e2aULL, }, - { 0x000100012f190004ULL, 0x46f900892a51e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_H(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_H(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_w.c b/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_w.c deleted file mode 100644 index ccbe6c0c842c..000000000000 --- a/tests/tcg/mips/user/ase/msa/shift/test_msa_srlr_w.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Test program for MSA instruction SRLR.W - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_msa.h" -#include "../../../../include/test_inputs_128.h" -#include "../../../../include/test_utils_128.h" - -#define TEST_COUNT_TOTAL ( \ - (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ - (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) - - -int32_t main(void) -{ - char *isa_ase_name = "MSA"; - char *group_name = "Shift"; - char *instruction_name = "SRLR.W"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b128_result[TEST_COUNT_TOTAL][2]; - uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, /* 0 */ - { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, - { 0x0040000000400000ULL, 0x0040000000400000ULL, }, - { 0x0000080000000800ULL, 0x0000080000000800ULL, }, - { 0x0010000000100000ULL, 0x0010000000100000ULL, }, - { 0x0000200000002000ULL, 0x0000200000002000ULL, }, - { 0x2000000000040000ULL, 0x0000010020000000ULL, }, - { 0x0000001000008000ULL, 0x0200000000000010ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */ - { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, - { 0x002aaaab002aaaabULL, 0x002aaaab002aaaabULL, }, - { 0x0000055500000555ULL, 0x0000055500000555ULL, }, - { 0x000aaaab000aaaabULL, 0x000aaaab000aaaabULL, }, - { 0x0000155500001555ULL, 0x0000155500001555ULL, }, - { 0x155555550002aaabULL, 0x000000ab15555555ULL, }, - { 0x0000000b00005555ULL, 0x015555550000000bULL, }, - { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 24 */ - { 0x5555555555555555ULL, 0x5555555555555555ULL, }, - { 0x0015555500155555ULL, 0x0015555500155555ULL, }, - { 0x000002ab000002abULL, 0x000002ab000002abULL, }, - { 0x0005555500055555ULL, 0x0005555500055555ULL, }, - { 0x00000aab00000aabULL, 0x00000aab00000aabULL, }, - { 0x0aaaaaab00015555ULL, 0x000000550aaaaaabULL, }, - { 0x0000000500002aabULL, 0x00aaaaab00000005ULL, }, - { 0x0000000200000002ULL, 0x0000000200000002ULL, }, /* 32 */ - { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, - { 0x0033333300333333ULL, 0x0033333300333333ULL, }, - { 0x0000066600000666ULL, 0x0000066600000666ULL, }, - { 0x000ccccd000ccccdULL, 0x000ccccd000ccccdULL, }, - { 0x0000199a0000199aULL, 0x0000199a0000199aULL, }, - { 0x1999999a00033333ULL, 0x000000cd1999999aULL, }, - { 0x0000000d00006666ULL, 0x0199999a0000000dULL, }, - { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ - { 0x3333333333333333ULL, 0x3333333333333333ULL, }, - { 0x000ccccd000ccccdULL, 0x000ccccd000ccccdULL, }, - { 0x0000019a0000019aULL, 0x0000019a0000019aULL, }, - { 0x0003333300033333ULL, 0x0003333300033333ULL, }, - { 0x0000066600000666ULL, 0x0000066600000666ULL, }, - { 0x066666660000cccdULL, 0x0000003306666666ULL, }, - { 0x000000030000199aULL, 0x0066666600000003ULL, }, - { 0x0000000200000001ULL, 0x0000000000000002ULL, }, /* 48 */ - { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, - { 0x0038e38e00238e39ULL, 0x000e38e40038e38eULL, }, - { 0x0000071c00000472ULL, 0x000001c70000071cULL, }, - { 0x000e38e40008e38eULL, 0x00038e39000e38e4ULL, }, - { 0x00001c72000011c7ULL, 0x0000071c00001c72ULL, }, - { 0x1c71c71c000238e4ULL, 0x000000391c71c71cULL, }, - { 0x0000000e0000471cULL, 0x0071c71c0000000eULL, }, - { 0x0000000000000001ULL, 0x0000000200000000ULL, }, /* 56 */ - { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, - { 0x00071c72001c71c7ULL, 0x0031c71c00071c72ULL, }, - { 0x000000e40000038eULL, 0x00000639000000e4ULL, }, - { 0x0001c71c00071c72ULL, 0x000c71c70001c71cULL, }, - { 0x0000038e00000e39ULL, 0x000018e40000038eULL, }, - { 0x038e38e40001c71cULL, 0x000000c7038e38e4ULL, }, - { 0x00000002000038e4ULL, 0x018e38e400000002ULL, }, - { 0x000886ae28625540ULL, 0x00000001000fe7bbULL, }, /* 64 */ - { 0x110d5cda00286255ULL, 0x0000001300000010ULL, }, - { 0x00221aba28625540ULL, 0x0000000100000fe8ULL, }, - { 0x000443570000a189ULL, 0x0000004bfe7bb00cULL, }, - { 0x000fbbe04d93c708ULL, 0x00000000000153f5ULL, }, - { 0x1f77c00c004d93c7ULL, 0x0000000500000001ULL, }, - { 0x003eef804d93c708ULL, 0x0000000000000154ULL, }, - { 0x0007ddf00001364fULL, 0x00000013153f52fcULL, }, - { 0x000ac5abb9cf8b80ULL, 0x00000001000ab2b2ULL, }, /* 72 */ - { 0x158b55d500b9cf8cULL, 0x0000000a0000000bULL, }, - { 0x002b16acb9cf8b80ULL, 0x0000000000000ab3ULL, }, - { 0x000562d50002e73eULL, 0x00000028ab2b2514ULL, }, - { 0x000704f15e31e24eULL, 0x00000002000a942eULL, }, - { 0x0e09e2ca005e31e2ULL, 0x000000230000000bULL, }, - { 0x001c13c65e31e24eULL, 0x0000000100000a94ULL, }, - { 0x00038279000178c8ULL, 0x0000008ea942e2a0ULL, }, - }; - - reset_msa_registers(); - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_W(b128_pattern[i], b128_pattern[j], - b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); - } - } - - for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { - do_msa_SRLR_W(b128_random[i], b128_random[j], - b128_result[((PATTERN_INPUTS_SHORT_COUNT) * - (PATTERN_INPUTS_SHORT_COUNT)) + - RANDOM_INPUTS_SHORT_COUNT * i + j]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_128(isa_ase_name, group_name, instruction_name, - TEST_COUNT_TOTAL, elapsed_time, - &b128_result[0][0], &b128_expect[0][0]); - - return ret; -} diff --git a/tests/tcg/mips/user/ase/msa/test_msa_compile_32r5eb.sh b/tests/tcg/mips/user/ase/msa/test_msa_compile_32r5eb.sh deleted file mode 100755 index 940cabe4d813..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_compile_32r5eb.sh +++ /dev/null @@ -1,917 +0,0 @@ - -# -# Bit Count -# --------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_d_32r5eb - -# -# Bit move -# -------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_bmnz_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bmnz_v_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_bmz_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bmz_v_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_bsel_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bsel_v_32r5eb - -# -# Bit Set -# ------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_d_32r5eb - -# -# Fixed Multiply -# -------------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_madd_q_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_madd_q_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddr_q_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddr_q_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msub_q_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msub_q_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubr_q_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubr_q_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mul_q_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mul_q_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulr_q_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulr_q_w_32r5eb - -# -# Float Max Min -# ------------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_a_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_a_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_a_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_a_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_a_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_a_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_a_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_a_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_d_32r5eb - -# -# Int Add -# ------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_u_d_32r5eb - -# -# Int Average -# ----------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_d_32r5eb - -# -# Int Compare -# ----------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_d_32r5eb - -# -# Int Divide -# ---------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_d_32r5eb - -# -# Int Dot Product -# --------------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_u_d_32r5eb - -# -# Int Max Min -# ----------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_d_32r5eb - -# -# Int Modulo -# ---------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_d_32r5eb - -# -# Int Multiply -# ------------ -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_d_32r5eb - -# -# Int Subtract -# ------------ -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_d_32r5eb - -# -# Interleave -# ---------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_d_32r5eb - -# -# Logic -# ----- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_and_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_and_v_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_nor_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nor_v_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_or_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_or_v_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_xor_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_xor_v_32r5eb - -# -# Move -# ---- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc move/test_msa_move_v.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_move_v_32r5eb - -# -# Pack -# ---- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_d_32r5eb - -# -# Shift -# ----- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_d_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_b.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_b_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_h.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_h_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_w.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_w_32r5eb -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_d.c \ --EB -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_d_32r5eb diff --git a/tests/tcg/mips/user/ase/msa/test_msa_compile_32r5el.sh b/tests/tcg/mips/user/ase/msa/test_msa_compile_32r5el.sh deleted file mode 100755 index 048b30b8d7bb..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_compile_32r5el.sh +++ /dev/null @@ -1,917 +0,0 @@ - -# -# Bit Count -# --------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nloc_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nloc_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_nlzc_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nlzc_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-count/test_msa_pcnt_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pcnt_d_32r5el - -# -# Bit move -# -------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsl_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsl_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_binsr_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_binsr_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_bmnz_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bmnz_v_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_bmz_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bmz_v_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-move/test_msa_bsel_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bsel_v_32r5el - -# -# Bit Set -# ------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bclr_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bclr_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bneg_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bneg_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc bit-set/test_msa_bset_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_bset_d_32r5el - -# -# Fixed Multiply -# -------------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_madd_q_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_madd_q_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddr_q_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddr_q_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msub_q_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msub_q_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubr_q_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubr_q_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mul_q_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mul_q_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulr_q_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulr_q_w_32r5el - -# -# Float Max Min -# ------------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_a_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_a_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_a_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_a_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmax_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmax_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_a_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_a_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_a_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_a_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc float-max-min/test_msa_fmin_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_fmin_d_32r5el - -# -# Int Add -# ------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_add_a_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_add_a_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_a_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_a_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_adds_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_adds_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_addv_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_addv_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-add/test_msa_hadd_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hadd_u_d_32r5el - -# -# Int Average -# ----------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_ave_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ave_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-average/test_msa_aver_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_aver_u_d_32r5el - -# -# Int Compare -# ----------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_ceq_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ceq_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_cle_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_cle_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-compare/test_msa_clt_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_clt_u_d_32r5el - -# -# Int Divide -# ---------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-divide/test_msa_div_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_div_u_d_32r5el - -# -# Int Dot Product -# --------------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dotp_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dotp_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpadd_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_dpsub_u_d_32r5el - -# -# Int Max Min -# ----------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_a_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_a_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_max_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_max_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_a_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_a_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-max-min/test_msa_min_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_min_u_d_32r5el - -# -# Int Modulo -# ---------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-modulo/test_msa_mod_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mod_u_d_32r5el - -# -# Int Multiply -# ------------ -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_maddv_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_maddv_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_msubv_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_msubv_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-multiply/test_msa_mulv_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_mulv_d_32r5el - -# -# Int Subtract -# ------------ -# -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_asub_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_asub_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_hsub_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_hsub_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subs_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsus_u_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subsuu_s_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc int-subtract/test_msa_subv_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_subv_d_32r5el - -# -# Interleave -# ---------- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvev_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvev_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvod_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvod_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvl_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvl_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc interleave/test_msa_ilvr_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_ilvr_d_32r5el - -# -# Logic -# ----- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_and_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_and_v_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_nor_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_nor_v_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_or_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_or_v_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc logic/test_msa_xor_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_xor_v_32r5el - -# -# Move -# ---- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc move/test_msa_move_v.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_move_v_32r5el - -# -# Pack -# ---- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckev_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckev_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_pckod_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_pckod_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc pack/test_msa_vshf_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_vshf_d_32r5el - -# -# Shift -# ----- -# -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sll_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sll_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_sra_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_sra_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srar_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srar_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srl_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srl_d_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_b.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_b_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_h.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_h_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_w.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_w_32r5el -/opt/mti/bin/mips-mti-linux-gnu-gcc shift/test_msa_srlr_d.c \ --EL -static -mabi=32 -march=mips32r5 -mmsa -mno-odd-spreg -mfp64 -mnan=2008 -o \ - /tmp/test_msa_srlr_d_32r5el diff --git a/tests/tcg/mips/user/ase/msa/test_msa_compile_64r6eb.sh b/tests/tcg/mips/user/ase/msa/test_msa_compile_64r6eb.sh deleted file mode 100755 index 6bc8907a53d5..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_compile_64r6eb.sh +++ /dev/null @@ -1,643 +0,0 @@ - -# -# Bit Count -# --------- -# -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_d_64r6eb - -# -# Bit move -# -------- -# -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_bmnz_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bmnz_v_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_bmz_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bmz_v_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_bsel_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bsel_v_64r6eb - -# -# Bit Set -# ------- -# -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_d_64r6eb - -# -# Fixed Multiply -# -------------- -# -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mul_q_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mul_q_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulr_q_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulr_q_w_64r6eb - -# -# Float Max Min -# ------------- -# -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_a_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_a_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_a_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_a_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_a_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_a_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_a_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_a_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_d_64r6eb - -# -# Int Add -# ------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_u_d_64r6eb - -# -# Int Average -# ----------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_d_64r6eb - -# -# Int Compare -# ----------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_d_64r6eb - -# -# Int Divide -# ---------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_d_64r6eb - -# -# Int Dot Product -# --------------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_u_d_64r6eb - -# -# Int Max Min -# ----------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_d_64r6eb - -# -# Int Modulo -# ---------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_d_64r6eb - -# -# Int Multiply -# ------------ -# -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_d_64r6eb - -# -# Int Subtract -# ------------ -# -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_d_64r6eb - -# -# Interleave -# ---------- -# -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_d_64r6eb - -# -# Logic -# ----- -# -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_and_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_and_v_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_nor_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nor_v_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_or_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_or_v_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_xor_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_xor_v_64r6eb - -# -# Move -# ---- -# -/opt/img/bin/mips-img-linux-gnu-gcc move/test_msa_move_v.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_move_v_64r6eb - -# -# Pack -# ---- -# -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_d_64r6eb - -# -# Shift -# ----- -# -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_d_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_b.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_b_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_h.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_h_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_w.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_w_64r6eb -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_d.c \ --EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_d_64r6eb diff --git a/tests/tcg/mips/user/ase/msa/test_msa_compile_64r6el.sh b/tests/tcg/mips/user/ase/msa/test_msa_compile_64r6el.sh deleted file mode 100755 index 4a92c55a4e4b..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_compile_64r6el.sh +++ /dev/null @@ -1,643 +0,0 @@ - -# -# Bit Count -# --------- -# -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nloc_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nloc_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_nlzc_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nlzc_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-count/test_msa_pcnt_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pcnt_d_64r6el - -# -# Bit move -# -------- -# -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsl_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsl_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_binsr_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_binsr_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_bmnz_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bmnz_v_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_bmz_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bmz_v_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-move/test_msa_bsel_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bsel_v_64r6el - -# -# Bit Set -# ------- -# -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bclr_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bclr_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bneg_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bneg_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc bit-set/test_msa_bset_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_bset_d_64r6el - -# -# Fixed Multiply -# -------------- -# -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mul_q_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mul_q_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulr_q_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mulr_q_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulr_q_w_64r6el - -# -# Float Max Min -# ------------- -# -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_a_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_a_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_a_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_a_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmax_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmax_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_a_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_a_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_a_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_a_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc float-max-min/test_msa_fmin_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_fmin_d_64r6el - -# -# Int Add -# ------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_add_a_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_add_a_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_a_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_a_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_adds_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_adds_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_addv_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_addv_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-add/test_msa_hadd_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hadd_u_d_64r6el - -# -# Int Average -# ----------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_ave_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ave_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-average/test_msa_aver_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_aver_u_d_64r6el - -# -# Int Compare -# ----------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_ceq_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ceq_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_cle_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_cle_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-compare/test_msa_clt_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_clt_u_d_64r6el - -# -# Int Divide -# ---------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-divide/test_msa_div_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_div_u_d_64r6el - -# -# Int Dot Product -# --------------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dotp_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dotp_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpadd_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpadd_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-dot-product/test_msa_dpsub_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_dpsub_u_d_64r6el - -# -# Int Max Min -# ----------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_a_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_a_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_max_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_max_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_a_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_a_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-max-min/test_msa_min_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_min_u_d_64r6el - -# -# Int Modulo -# ---------- -# -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-modulo/test_msa_mod_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mod_u_d_64r6el - -# -# Int Multiply -# ------------ -# -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_maddv_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddv_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_msubv_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubv_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-multiply/test_msa_mulv_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mulv_d_64r6el - -# -# Int Subtract -# ------------ -# -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_asub_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_asub_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_hsub_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_hsub_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_d_64r6el - -# -# Interleave -# ---------- -# -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvev_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvev_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvod_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvod_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvl_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvl_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc interleave/test_msa_ilvr_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_ilvr_d_64r6el - -# -# Logic -# ----- -# -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_and_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_and_v_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_nor_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_nor_v_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_or_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_or_v_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc logic/test_msa_xor_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_xor_v_64r6el - -# -# Move -# ---- -# -/opt/img/bin/mips-img-linux-gnu-gcc move/test_msa_move_v.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_move_v_64r6el - -# -# Pack -# ---- -# -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckev_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckev_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_pckod_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_pckod_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc pack/test_msa_vshf_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_vshf_d_64r6el - -# -# Shift -# ----- -# -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sll_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sll_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_sra_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_sra_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srar_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srar_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srl_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srl_d_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_b.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_b_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_h.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_h_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_w.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_w_64r6el -/opt/img/bin/mips-img-linux-gnu-gcc shift/test_msa_srlr_d.c \ --EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_srlr_d_64r6el diff --git a/tests/tcg/mips/user/ase/msa/test_msa_run_32r5eb.sh b/tests/tcg/mips/user/ase/msa/test_msa_run_32r5eb.sh deleted file mode 100755 index 32dbf3134793..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_run_32r5eb.sh +++ /dev/null @@ -1,371 +0,0 @@ -PATH_TO_QEMU="../../../../../../mips-linux-user/qemu-mips" - - -# -# Bit Count -# --------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_d_32r5eb - -# -# Bit move -# -------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bmnz_v_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bmz_v_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bsel_v_32r5eb - -# -# Bit Set -# ------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_d_32r5eb - -# -# Fixed Multiply -# -------------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_madd_q_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_madd_q_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddr_q_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddr_q_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msub_q_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msub_q_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubr_q_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubr_q_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mul_q_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mul_q_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulr_q_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulr_q_w_32r5eb - -# -# Float Max Min -# ------------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_a_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_a_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_a_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_a_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_d_32r5eb - -# -# Int Add -# ------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_u_d_32r5eb - -# -# Int Average -# ----------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_d_32r5eb - -# -# Int Compare -# ----------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_d_32r5eb - -# -# Int Divide -# ---------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_d_32r5eb - -# -# Int Dot Product -# --------------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_u_d_32r5eb - -# -# Int Max Min -# ----------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_d_32r5eb - -# -# Int Modulo -# ---------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_d_32r5eb - -# -# Int Multiply -# ------------ -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_d_32r5eb - -# -# Int Subtract -# ------------ -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_d_32r5eb - -# -# Interleave -# ---------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_d_32r5eb - -# -# Logic -# ----- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_and_v_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nor_v_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_or_v_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_xor_v_32r5eb - -# -# Move -# ---- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_move_v_32r5eb - -# -# Pack -# ---- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_d_32r5eb - -# -# Shift -# ----- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_d_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_b_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_h_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_w_32r5eb -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_d_32r5eb diff --git a/tests/tcg/mips/user/ase/msa/test_msa_run_32r5el.sh b/tests/tcg/mips/user/ase/msa/test_msa_run_32r5el.sh deleted file mode 100755 index a2e6092522a2..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_run_32r5el.sh +++ /dev/null @@ -1,371 +0,0 @@ -PATH_TO_QEMU="../../../../../../mipsel-linux-user/qemu-mipsel" - - -# -# Bit Count -# --------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nloc_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nlzc_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pcnt_d_32r5el - -# -# Bit move -# -------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsl_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_binsr_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bmnz_v_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bmz_v_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bsel_v_32r5el - -# -# Bit Set -# ------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bclr_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bneg_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_bset_d_32r5el - -# -# Fixed Multiply -# -------------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_madd_q_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_madd_q_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddr_q_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddr_q_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msub_q_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msub_q_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubr_q_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubr_q_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mul_q_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mul_q_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulr_q_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulr_q_w_32r5el - -# -# Float Max Min -# ------------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_a_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_a_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmax_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_a_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_a_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_fmin_d_32r5el - -# -# Int Add -# ------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_add_a_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_a_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_adds_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_addv_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hadd_u_d_32r5el - -# -# Int Average -# ----------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ave_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_aver_u_d_32r5el - -# -# Int Compare -# ----------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ceq_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_cle_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_clt_u_d_32r5el - -# -# Int Divide -# ---------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_div_u_d_32r5el - -# -# Int Dot Product -# --------------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dotp_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpadd_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_dpsub_u_d_32r5el - -# -# Int Max Min -# ----------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_a_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_max_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_a_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_min_u_d_32r5el - -# -# Int Modulo -# ---------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mod_u_d_32r5el - -# -# Int Multiply -# ------------ -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_maddv_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_msubv_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_mulv_d_32r5el - -# -# Int Subtract -# ------------ -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_asub_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_hsub_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subs_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsus_u_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subsuu_s_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_subv_d_32r5el - -# -# Interleave -# ---------- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvev_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvod_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvl_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_ilvr_d_32r5el - -# -# Logic -# ----- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_and_v_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_nor_v_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_or_v_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_xor_v_32r5el - -# -# Move -# ---- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_move_v_32r5el - -# -# Pack -# ---- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckev_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_pckod_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_vshf_d_32r5el - -# -# Shift -# ----- -# -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sll_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_sra_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srar_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srl_d_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_b_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_h_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_w_32r5el -$PATH_TO_QEMU -cpu P5600 /tmp/test_msa_srlr_d_32r5el diff --git a/tests/tcg/mips/user/ase/msa/test_msa_run_64r6eb.sh b/tests/tcg/mips/user/ase/msa/test_msa_run_64r6eb.sh deleted file mode 100755 index 6de6d7cacf35..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_run_64r6eb.sh +++ /dev/null @@ -1,371 +0,0 @@ -PATH_TO_QEMU="../../../../../../mips64-linux-user/qemu-mips64" - - -# -# Bit Count -# --------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_d_64r6eb - -# -# Bit move -# -------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bmnz_v_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bmz_v_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bsel_v_64r6eb - -# -# Bit Set -# ------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_d_64r6eb - -# -# Fixed Multiply -# -------------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_w_64r6eb - -# -# Float Max Min -# ------------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_a_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_a_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_a_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_a_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_d_64r6eb - -# -# Int Add -# ------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_u_d_64r6eb - -# -# Int Average -# ----------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_d_64r6eb - -# -# Int Compare -# ----------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_d_64r6eb - -# -# Int Divide -# ---------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_d_64r6eb - -# -# Int Dot Product -# --------------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_u_d_64r6eb - -# -# Int Max Min -# ----------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_d_64r6eb - -# -# Int Modulo -# ---------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_d_64r6eb - -# -# Int Multiply -# ------------ -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_d_64r6eb - -# -# Int Subtract -# ------------ -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_d_64r6eb - -# -# Interleave -# ---------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_d_64r6eb - -# -# Logic -# ----- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_and_v_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nor_v_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_or_v_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_xor_v_64r6eb - -# -# Move -# ---- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_move_v_64r6eb - -# -# Pack -# ---- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_d_64r6eb - -# -# Shift -# ----- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_d_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_b_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_h_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_w_64r6eb -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_d_64r6eb diff --git a/tests/tcg/mips/user/ase/msa/test_msa_run_64r6el.sh b/tests/tcg/mips/user/ase/msa/test_msa_run_64r6el.sh deleted file mode 100755 index 979057df746c..000000000000 --- a/tests/tcg/mips/user/ase/msa/test_msa_run_64r6el.sh +++ /dev/null @@ -1,371 +0,0 @@ -PATH_TO_QEMU="../../../../../../mips64el-linux-user/qemu-mips64el" - - -# -# Bit Count -# --------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nloc_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nlzc_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pcnt_d_64r6el - -# -# Bit move -# -------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsl_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_binsr_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bmnz_v_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bmz_v_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bsel_v_64r6el - -# -# Bit Set -# ------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bclr_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bneg_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_bset_d_64r6el - -# -# Fixed Multiply -# -------------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_w_64r6el - -# -# Float Max Min -# ------------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_a_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_a_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmax_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_a_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_a_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_fmin_d_64r6el - -# -# Int Add -# ------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_add_a_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_a_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_adds_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_addv_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hadd_u_d_64r6el - -# -# Int Average -# ----------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ave_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_aver_u_d_64r6el - -# -# Int Compare -# ----------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ceq_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_cle_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_clt_u_d_64r6el - -# -# Int Divide -# ---------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_div_u_d_64r6el - -# -# Int Dot Product -# --------------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dotp_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpadd_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_dpsub_u_d_64r6el - -# -# Int Max Min -# ----------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_a_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_max_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_a_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_min_u_d_64r6el - -# -# Int Modulo -# ---------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mod_u_d_64r6el - -# -# Int Multiply -# ------------ -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddv_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubv_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulv_d_64r6el - -# -# Int Subtract -# ------------ -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_asub_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_hsub_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_d_64r6el - -# -# Interleave -# ---------- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvev_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvod_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvl_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_ilvr_d_64r6el - -# -# Logic -# ----- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_and_v_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_nor_v_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_or_v_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_xor_v_64r6el - -# -# Move -# ---- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_move_v_64r6el - -# -# Pack -# ---- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckev_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_pckod_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_vshf_d_64r6el - -# -# Shift -# ----- -# -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sll_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_sra_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srar_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srl_d_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_b_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_h_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_w_64r6el -$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_srlr_d_64r6el diff --git a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_clo.c b/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_clo.c deleted file mode 100644 index e7ecdc591001..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_clo.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Test program for MIPS64R6 instruction CLO - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Bit Count"; - char *instruction_name = "CLO"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000020ULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000002ULL, - 0x0000000000000000ULL, - 0x0000000000000003ULL, - 0x0000000000000000ULL, - 0x0000000000000004ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000005ULL, - 0x0000000000000000ULL, - 0x0000000000000006ULL, - 0x0000000000000000ULL, - 0x0000000000000007ULL, - 0x0000000000000000ULL, - 0x0000000000000008ULL, /* 16 */ - 0x0000000000000000ULL, - 0x0000000000000009ULL, - 0x0000000000000000ULL, - 0x000000000000000aULL, - 0x0000000000000000ULL, - 0x000000000000000bULL, - 0x0000000000000000ULL, - 0x000000000000000cULL, /* 24 */ - 0x0000000000000000ULL, - 0x000000000000000dULL, - 0x0000000000000000ULL, - 0x000000000000000eULL, - 0x0000000000000000ULL, - 0x000000000000000fULL, - 0x0000000000000000ULL, - 0x0000000000000010ULL, /* 32 */ - 0x0000000000000000ULL, - 0x0000000000000011ULL, - 0x0000000000000000ULL, - 0x0000000000000012ULL, - 0x0000000000000000ULL, - 0x0000000000000013ULL, - 0x0000000000000000ULL, - 0x0000000000000014ULL, /* 40 */ - 0x0000000000000000ULL, - 0x0000000000000015ULL, - 0x0000000000000000ULL, - 0x0000000000000016ULL, - 0x0000000000000000ULL, - 0x0000000000000017ULL, - 0x0000000000000000ULL, - 0x0000000000000018ULL, /* 48 */ - 0x0000000000000000ULL, - 0x0000000000000019ULL, - 0x0000000000000000ULL, - 0x000000000000001aULL, - 0x0000000000000000ULL, - 0x000000000000001bULL, - 0x0000000000000000ULL, - 0x000000000000001cULL, /* 56 */ - 0x0000000000000000ULL, - 0x000000000000001dULL, - 0x0000000000000000ULL, - 0x000000000000001eULL, - 0x0000000000000000ULL, - 0x000000000000001fULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, /* 64 */ - 0x0000000000000005ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000002ULL, - 0x0000000000000001ULL, - 0x0000000000000006ULL, - 0x0000000000000000ULL, /* 72 */ - 0x0000000000000001ULL, - 0x0000000000000001ULL, - 0x0000000000000001ULL, - 0x0000000000000003ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_64_COUNT) { - do_mips64r6_CLO(b64_pattern_se + i, b64_result + i); - } else { - do_mips64r6_CLO(b64_random_se + (i - PATTERN_INPUTS_64_COUNT), - b64_result + i); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_clz.c b/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_clz.c deleted file mode 100644 index a77a8e4eb590..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_clz.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Test program for MIPS64R6 instruction CLZ - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Bit Count"; - char *instruction_name = "CLZ"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000000ULL, /* 0 */ - 0x0000000000000020ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000002ULL, - 0x0000000000000000ULL, - 0x0000000000000003ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000004ULL, - 0x0000000000000000ULL, - 0x0000000000000005ULL, - 0x0000000000000000ULL, - 0x0000000000000006ULL, - 0x0000000000000000ULL, - 0x0000000000000007ULL, - 0x0000000000000000ULL, /* 16 */ - 0x0000000000000008ULL, - 0x0000000000000000ULL, - 0x0000000000000009ULL, - 0x0000000000000000ULL, - 0x000000000000000aULL, - 0x0000000000000000ULL, - 0x000000000000000bULL, - 0x0000000000000000ULL, /* 24 */ - 0x000000000000000cULL, - 0x0000000000000000ULL, - 0x000000000000000dULL, - 0x0000000000000000ULL, - 0x000000000000000eULL, - 0x0000000000000000ULL, - 0x000000000000000fULL, - 0x0000000000000000ULL, /* 32 */ - 0x0000000000000010ULL, - 0x0000000000000000ULL, - 0x0000000000000011ULL, - 0x0000000000000000ULL, - 0x0000000000000012ULL, - 0x0000000000000000ULL, - 0x0000000000000013ULL, - 0x0000000000000000ULL, /* 40 */ - 0x0000000000000014ULL, - 0x0000000000000000ULL, - 0x0000000000000015ULL, - 0x0000000000000000ULL, - 0x0000000000000016ULL, - 0x0000000000000000ULL, - 0x0000000000000017ULL, - 0x0000000000000000ULL, /* 48 */ - 0x0000000000000018ULL, - 0x0000000000000000ULL, - 0x0000000000000019ULL, - 0x0000000000000000ULL, - 0x000000000000001aULL, - 0x0000000000000000ULL, - 0x000000000000001bULL, - 0x0000000000000000ULL, /* 56 */ - 0x000000000000001cULL, - 0x0000000000000000ULL, - 0x000000000000001dULL, - 0x0000000000000000ULL, - 0x000000000000001eULL, - 0x0000000000000000ULL, - 0x000000000000001fULL, - 0x0000000000000000ULL, /* 64 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000002ULL, /* 72 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_64_COUNT) { - do_mips64r6_CLZ(b64_pattern_se + i, b64_result + i); - } else { - do_mips64r6_CLZ(b64_random_se + (i - PATTERN_INPUTS_64_COUNT), - b64_result + i); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_dclo.c b/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_dclo.c deleted file mode 100644 index eb41fbdfdf77..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_dclo.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DCLO - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Bit Count"; - char *instruction_name = "DCLO"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000040ULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000002ULL, - 0x0000000000000000ULL, - 0x0000000000000003ULL, - 0x0000000000000000ULL, - 0x0000000000000004ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000005ULL, - 0x0000000000000000ULL, - 0x0000000000000006ULL, - 0x0000000000000000ULL, - 0x0000000000000007ULL, - 0x0000000000000000ULL, - 0x0000000000000008ULL, /* 16 */ - 0x0000000000000000ULL, - 0x0000000000000009ULL, - 0x0000000000000000ULL, - 0x000000000000000aULL, - 0x0000000000000000ULL, - 0x000000000000000bULL, - 0x0000000000000000ULL, - 0x000000000000000cULL, /* 24 */ - 0x0000000000000000ULL, - 0x000000000000000dULL, - 0x0000000000000000ULL, - 0x000000000000000eULL, - 0x0000000000000000ULL, - 0x000000000000000fULL, - 0x0000000000000000ULL, - 0x0000000000000010ULL, /* 32 */ - 0x0000000000000000ULL, - 0x0000000000000011ULL, - 0x0000000000000000ULL, - 0x0000000000000012ULL, - 0x0000000000000000ULL, - 0x0000000000000013ULL, - 0x0000000000000000ULL, - 0x0000000000000014ULL, /* 40 */ - 0x0000000000000000ULL, - 0x0000000000000015ULL, - 0x0000000000000000ULL, - 0x0000000000000016ULL, - 0x0000000000000000ULL, - 0x0000000000000017ULL, - 0x0000000000000000ULL, - 0x0000000000000018ULL, /* 48 */ - 0x0000000000000000ULL, - 0x0000000000000019ULL, - 0x0000000000000000ULL, - 0x000000000000001aULL, - 0x0000000000000000ULL, - 0x000000000000001bULL, - 0x0000000000000000ULL, - 0x000000000000001cULL, /* 56 */ - 0x0000000000000000ULL, - 0x000000000000001dULL, - 0x0000000000000000ULL, - 0x000000000000001eULL, - 0x0000000000000000ULL, - 0x000000000000001fULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, /* 64 */ - 0x0000000000000005ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000002ULL, - 0x0000000000000001ULL, - 0x0000000000000006ULL, - 0x0000000000000000ULL, /* 72 */ - 0x0000000000000001ULL, - 0x0000000000000001ULL, - 0x0000000000000001ULL, - 0x0000000000000003ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_64_COUNT) { - do_mips64r6_DCLO((void *)&b64_pattern[i], (void *)&b64_result[i]); - } else { - do_mips64r6_DCLO((void *)&b64_random[i - PATTERN_INPUTS_64_COUNT], - (void *)&b64_result[i]); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_dclz.c b/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_dclz.c deleted file mode 100644 index be393ac19925..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/bit-count/test_mips64r6_dclz.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DCLZ - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Bit Count"; - char *instruction_name = "DCLZ"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000000ULL, /* 0 */ - 0x0000000000000040ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000002ULL, - 0x0000000000000000ULL, - 0x0000000000000003ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000004ULL, - 0x0000000000000000ULL, - 0x0000000000000005ULL, - 0x0000000000000000ULL, - 0x0000000000000006ULL, - 0x0000000000000000ULL, - 0x0000000000000007ULL, - 0x0000000000000000ULL, /* 16 */ - 0x0000000000000008ULL, - 0x0000000000000000ULL, - 0x0000000000000009ULL, - 0x0000000000000000ULL, - 0x000000000000000aULL, - 0x0000000000000000ULL, - 0x000000000000000bULL, - 0x0000000000000000ULL, /* 24 */ - 0x000000000000000cULL, - 0x0000000000000000ULL, - 0x000000000000000dULL, - 0x0000000000000000ULL, - 0x000000000000000eULL, - 0x0000000000000000ULL, - 0x000000000000000fULL, - 0x0000000000000000ULL, /* 32 */ - 0x0000000000000010ULL, - 0x0000000000000000ULL, - 0x0000000000000011ULL, - 0x0000000000000000ULL, - 0x0000000000000012ULL, - 0x0000000000000000ULL, - 0x0000000000000013ULL, - 0x0000000000000000ULL, /* 40 */ - 0x0000000000000014ULL, - 0x0000000000000000ULL, - 0x0000000000000015ULL, - 0x0000000000000000ULL, - 0x0000000000000016ULL, - 0x0000000000000000ULL, - 0x0000000000000017ULL, - 0x0000000000000000ULL, /* 48 */ - 0x0000000000000018ULL, - 0x0000000000000000ULL, - 0x0000000000000019ULL, - 0x0000000000000000ULL, - 0x000000000000001aULL, - 0x0000000000000000ULL, - 0x000000000000001bULL, - 0x0000000000000000ULL, /* 56 */ - 0x000000000000001cULL, - 0x0000000000000000ULL, - 0x000000000000001dULL, - 0x0000000000000000ULL, - 0x000000000000001eULL, - 0x0000000000000000ULL, - 0x000000000000001fULL, - 0x0000000000000000ULL, /* 64 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000002ULL, /* 72 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, - 0x0000000000000000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_64_COUNT) { - do_mips64r6_DCLZ(b64_pattern + i, b64_result + i); - } else { - do_mips64r6_DCLZ(b64_random + (i - PATTERN_INPUTS_64_COUNT), - b64_result + i); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/bit-swap/test_mips64r6_bitswap.c b/tests/tcg/mips/user/isa/mips64r6/bit-swap/test_mips64r6_bitswap.c deleted file mode 100644 index df3d1b11f6bb..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/bit-swap/test_mips64r6_bitswap.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Test program for MIPS64R6 instruction BITSWAP - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Bit Swap"; - char *instruction_name = "BITSWAP"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xffffffffffffffffULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000055555555ULL, - 0xffffffffaaaaaaaaULL, - 0x0000000033333333ULL, - 0xffffffffccccccccULL, - 0x00000000711cc771ULL, - 0xffffffff8ee3388eULL, - 0x000000000f0f0f0fULL, /* 8 */ - 0xfffffffff0f0f0f0ULL, - 0x00000000071f7cf0ULL, - 0xfffffffff8e0830fULL, - 0xfffffffff0033ff0ULL, - 0x000000000ffcc00fULL, - 0x0000000007fc017fULL, - 0xfffffffff803fe80ULL, - 0xffffffffff00ff00ULL, /* 16 */ - 0x0000000000ff00ffULL, - 0xfffffffff01fc07fULL, - 0x000000000fe03f80ULL, - 0x0000000000ff03f0ULL, - 0xffffffffff00fc0fULL, - 0x0000000001f07f00ULL, - 0xfffffffffe0f80ffULL, - 0x000000000f00ff0fULL, /* 24 */ - 0xfffffffff0ff00f0ULL, - 0x000000007f00f0ffULL, - 0xffffffff80ff0f00ULL, - 0xffffffffff0300ffULL, - 0x0000000000fcff00ULL, - 0xffffffffff1f00f0ULL, - 0x0000000000e0ff0fULL, - 0xffffffffffff0000ULL, /* 32 */ - 0x000000000000ffffULL, - 0xfffffffffcff0700ULL, - 0x000000000300f8ffULL, - 0xfffffffff0ff3f00ULL, - 0x000000000f00c0ffULL, - 0xffffffffc0ffff01ULL, - 0x000000003f0000feULL, - 0x0000000000ffff0fULL, /* 40 */ - 0xffffffffff0000f0ULL, - 0x0000000000fcff7fULL, - 0xffffffffff030080ULL, - 0x0000000000f0ffffULL, - 0xffffffffff0f0000ULL, - 0x0000000000c0ffffULL, - 0xffffffffff3f0000ULL, - 0x000000000000ffffULL, /* 48 */ - 0xffffffffffff0000ULL, - 0x000000000000fcffULL, - 0xffffffffffff0300ULL, - 0x000000000000f0ffULL, - 0xffffffffffff0f00ULL, - 0x000000000000c0ffULL, - 0xffffffffffff3f00ULL, - 0x00000000000000ffULL, /* 56 */ - 0xffffffffffffff00ULL, - 0x00000000000000fcULL, - 0xffffffffffffff03ULL, - 0x00000000000000f0ULL, - 0xffffffffffffff0fULL, - 0x00000000000000c0ULL, - 0xffffffffffffff3fULL, - 0x000000001446aa02ULL, /* 64 */ - 0xffffffffb2c9e310ULL, - 0xffffffff9df3d101ULL, - 0x000000007a8c4772ULL, - 0xffffffffbef5421aULL, - 0xffffffffff50749fULL, - 0xffffffffa6533d52ULL, - 0x000000005965ed41ULL, - 0x000000006a756792ULL, /* 72 */ - 0xffffffffa69ba7ebULL, - 0xffffffff93d363d8ULL, - 0xffffffff8c152675ULL, - 0x00000000654a5750ULL, - 0xffffffff98c48615ULL, - 0x00000000447def39ULL, - 0x000000004f9a7bb5ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_64_COUNT) { - do_mips64r6_BITSWAP(b64_pattern + i, b64_result + i); - } else { - do_mips64r6_BITSWAP(b64_random + (i - PATTERN_INPUTS_64_COUNT), - b64_result + i); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/bit-swap/test_mips64r6_dbitswap.c b/tests/tcg/mips/user/isa/mips64r6/bit-swap/test_mips64r6_dbitswap.c deleted file mode 100644 index 377835940d98..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/bit-swap/test_mips64r6_dbitswap.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DBITSWAP - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Bit Swap"; - char *instruction_name = "DBITSWAP"; - int32_t ret; - uint32_t i; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xffffffffffffffffULL, /* 0 */ - 0x0000000000000000ULL, - 0x5555555555555555ULL, - 0xaaaaaaaaaaaaaaaaULL, - 0x3333333333333333ULL, - 0xccccccccccccccccULL, - 0xc7711cc7711cc771ULL, - 0x388ee3388ee3388eULL, - 0x0f0f0f0f0f0f0f0fULL, /* 8 */ - 0xf0f0f0f0f0f0f0f0ULL, - 0x1f7cf0c1071f7cf0ULL, - 0xe0830f3ef8e0830fULL, - 0x3ff0033ff0033ff0ULL, - 0xc00ffcc00ffcc00fULL, - 0x7fc01ff007fc017fULL, - 0x803fe00ff803fe80ULL, - 0xff00ff00ff00ff00ULL, /* 16 */ - 0x00ff00ff00ff00ffULL, - 0xff01fc07f01fc07fULL, - 0x00fe03f80fe03f80ULL, - 0xff03f03f00ff03f0ULL, - 0x00fc0fc0ff00fc0fULL, - 0xff07c0ff01f07f00ULL, - 0x00f83f00fe0f80ffULL, - 0xff0f00ff0f00ff0fULL, /* 24 */ - 0x00f0ff00f0ff00f0ULL, - 0xff1f00fc7f00f0ffULL, - 0x00e0ff0380ff0f00ULL, - 0xff3f00f0ff0300ffULL, - 0x00c0ff0f00fcff00ULL, - 0xff7f00c0ff1f00f0ULL, - 0x0080ff3f00e0ff0fULL, - 0xffff0000ffff0000ULL, /* 32 */ - 0x0000ffff0000ffffULL, - 0xffff0100fcff0700ULL, - 0x0000feff0300f8ffULL, - 0xffff0300f0ff3f00ULL, - 0x0000fcff0f00c0ffULL, - 0xffff0700c0ffff01ULL, - 0x0000f8ff3f0000feULL, - 0xffff0f0000ffff0fULL, /* 40 */ - 0x0000f0ffff0000f0ULL, - 0xffff1f0000fcff7fULL, - 0x0000e0ffff030080ULL, - 0xffff3f0000f0ffffULL, - 0x0000c0ffff0f0000ULL, - 0xffff7f0000c0ffffULL, - 0x000080ffff3f0000ULL, - 0xffffff000000ffffULL, /* 48 */ - 0x000000ffffff0000ULL, - 0xffffff010000fcffULL, - 0x000000feffff0300ULL, - 0xffffff030000f0ffULL, - 0x000000fcffff0f00ULL, - 0xffffff070000c0ffULL, - 0x000000f8ffff3f00ULL, - 0xffffff0f000000ffULL, /* 56 */ - 0x000000f0ffffff00ULL, - 0xffffff1f000000fcULL, - 0x000000e0ffffff03ULL, - 0xffffff3f000000f0ULL, - 0x000000c0ffffff0fULL, - 0xffffff7f000000c0ULL, - 0x00000080ffffff3fULL, - 0x115667331446aa02ULL, /* 64 */ - 0xdf7d00c6b2c9e310ULL, - 0x355a75559df3d101ULL, - 0x0ef268b27a8c4772ULL, - 0x9d49d63ebef5421aULL, - 0x0be47d91ff50749fULL, - 0x1ddc1a60a6533d52ULL, - 0x3ff1c40f5965ed41ULL, - 0x047890b36a756792ULL, /* 72 */ - 0xa53e9bc8a69ba7ebULL, - 0x45176faf93d363d8ULL, - 0x15394f8f8c152675ULL, - 0x67281c97654a5750ULL, - 0x2952acbf98c48615ULL, - 0x620c42c6447def39ULL, - 0xd15ae5454f9a7bb5ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < TEST_COUNT_TOTAL; i++) { - if (i < PATTERN_INPUTS_64_COUNT) { - do_mips64r6_DBITSWAP(b64_pattern + i, b64_result + i); - } else { - do_mips64r6_DBITSWAP(b64_random + (i - PATTERN_INPUTS_64_COUNT), - b64_result + i); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmuh.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmuh.c deleted file mode 100644 index eb21615f9520..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmuh.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DMUH - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "DMUH"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000000ULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0x0000000000000000ULL, - 0x1c71c71c71c71c72ULL, - 0xe38e38e38e38e38eULL, - 0x1111111111111111ULL, - 0xeeeeeeeeeeeeeeeeULL, - 0x097b425ed097b426ULL, - 0xf684bda12f684bdaULL, - 0xffffffffffffffffULL, /* 24 */ - 0x0000000000000000ULL, - 0xe38e38e38e38e38eULL, - 0x1c71c71c71c71c71ULL, - 0xeeeeeeeeeeeeeeeeULL, - 0x1111111111111110ULL, - 0xf684bda12f684bdaULL, - 0x097b425ed097b425ULL, - 0x0000000000000000ULL, /* 32 */ - 0x0000000000000000ULL, - 0x1111111111111111ULL, - 0xeeeeeeeeeeeeeeeeULL, - 0x0a3d70a3d70a3d70ULL, - 0xf5c28f5c28f5c28fULL, - 0x05b05b05b05b05b0ULL, - 0xfa4fa4fa4fa4fa4fULL, - 0xffffffffffffffffULL, /* 40 */ - 0x0000000000000000ULL, - 0xeeeeeeeeeeeeeeeeULL, - 0x1111111111111110ULL, - 0xf5c28f5c28f5c28fULL, - 0x0a3d70a3d70a3d70ULL, - 0xfa4fa4fa4fa4fa4fULL, - 0x05b05b05b05b05b0ULL, - 0x0000000000000000ULL, /* 48 */ - 0x0000000000000000ULL, - 0x097b425ed097b426ULL, - 0xf684bda12f684bdaULL, - 0x05b05b05b05b05b0ULL, - 0xfa4fa4fa4fa4fa4fULL, - 0x0329161f9add3c0cULL, - 0xfcd6e9e06522c3f3ULL, - 0xffffffffffffffffULL, /* 56 */ - 0x0000000000000000ULL, - 0xf684bda12f684bdaULL, - 0x097b425ed097b425ULL, - 0xfa4fa4fa4fa4fa4fULL, - 0x05b05b05b05b05b0ULL, - 0xfcd6e9e06522c3f3ULL, - 0x0329161f9add3c0cULL, - 0x37dbf4448b48bce3ULL, /* 64 */ - 0x01fd28a6ebd66e19ULL, - 0x271290430f9643afULL, - 0xcb89d38b96a86603ULL, - 0x01fd28a6ebd66e19ULL, - 0x00122100b25f881aULL, - 0x016425c3dacd63e9ULL, - 0xfe21cf6e9b332df5ULL, - 0x271290430f9643afULL, /* 72 */ - 0x016425c3dacd63e9ULL, - 0x1b549d7f3d46f8d3ULL, - 0xdb4dd51d1b7c58f2ULL, - 0xcb89d38b96a86603ULL, - 0xfe21cf6e9b332df5ULL, - 0xdb4dd51d1b7c58f2ULL, - 0x31454bf2781d2c60ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMUH(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMUH(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmuhu.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmuhu.c deleted file mode 100644 index 7316d79e2af5..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmuhu.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DMUHU - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "DMUHU"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xfffffffffffffffeULL, /* 0 */ - 0x0000000000000000ULL, - 0xaaaaaaaaaaaaaaa9ULL, - 0x5555555555555554ULL, - 0xcccccccccccccccbULL, - 0x3333333333333332ULL, - 0xe38e38e38e38e38dULL, - 0x1c71c71c71c71c70ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0xaaaaaaaaaaaaaaa9ULL, /* 16 */ - 0x0000000000000000ULL, - 0x71c71c71c71c71c6ULL, - 0x38e38e38e38e38e3ULL, - 0x8888888888888887ULL, - 0x2222222222222221ULL, - 0x97b425ed097b425eULL, - 0x12f684bda12f684bULL, - 0x5555555555555554ULL, /* 24 */ - 0x0000000000000000ULL, - 0x38e38e38e38e38e3ULL, - 0x1c71c71c71c71c71ULL, - 0x4444444444444443ULL, - 0x1111111111111110ULL, - 0x4bda12f684bda12fULL, - 0x097b425ed097b425ULL, - 0xcccccccccccccccbULL, /* 32 */ - 0x0000000000000000ULL, - 0x8888888888888887ULL, - 0x4444444444444443ULL, - 0xa3d70a3d70a3d708ULL, - 0x28f5c28f5c28f5c2ULL, - 0xb60b60b60b60b60aULL, - 0x16c16c16c16c16c0ULL, - 0x3333333333333332ULL, /* 40 */ - 0x0000000000000000ULL, - 0x2222222222222221ULL, - 0x1111111111111110ULL, - 0x28f5c28f5c28f5c2ULL, - 0x0a3d70a3d70a3d70ULL, - 0x2d82d82d82d82d82ULL, - 0x05b05b05b05b05b0ULL, - 0xe38e38e38e38e38dULL, /* 48 */ - 0x0000000000000000ULL, - 0x97b425ed097b425eULL, - 0x4bda12f684bda12fULL, - 0xb60b60b60b60b60aULL, - 0x2d82d82d82d82d82ULL, - 0xca4587e6b74f0328ULL, - 0x1948b0fcd6e9e064ULL, - 0x1c71c71c71c71c70ULL, /* 56 */ - 0x0000000000000000ULL, - 0x12f684bda12f684bULL, - 0x097b425ed097b425ULL, - 0x16c16c16c16c16c0ULL, - 0x05b05b05b05b05b0ULL, - 0x1948b0fcd6e9e064ULL, - 0x0329161f9add3c0cULL, - 0x48b1c1dcdc0d6763ULL, /* 64 */ - 0x86260fd661cc8a61ULL, - 0x5bd825b9f1c8246fULL, - 0x3bd8e9d8f4da4851ULL, - 0x86260fd661cc8a61ULL, - 0xf78e21c74d87162aULL, - 0xa97cd4d1e230b671ULL, - 0x6e70e5bbf9651043ULL, - 0x5bd825b9f1c8246fULL, /* 72 */ - 0xa97cd4d1e230b671ULL, - 0x7409fad4b0e60fd3ULL, - 0x4b9ceb6a79ae3b40ULL, - 0x3bd8e9d8f4da4851ULL, - 0x6e70e5bbf9651043ULL, - 0x4b9ceb6a79ae3b40ULL, - 0x31454bf2781d2c60ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMUHU(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMUHU(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmul.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmul.c deleted file mode 100644 index 3ac1965cca37..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmul.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DMUL - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "DMUL"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000001ULL, /* 0 */ - 0x0000000000000000ULL, - 0x5555555555555556ULL, - 0xaaaaaaaaaaaaaaabULL, - 0x3333333333333334ULL, - 0xcccccccccccccccdULL, - 0x1c71c71c71c71c72ULL, - 0xe38e38e38e38e38fULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x5555555555555556ULL, /* 16 */ - 0x0000000000000000ULL, - 0x38e38e38e38e38e4ULL, - 0x1c71c71c71c71c72ULL, - 0x7777777777777778ULL, - 0xdddddddddddddddeULL, - 0x12f684bda12f684cULL, - 0x425ed097b425ed0aULL, - 0xaaaaaaaaaaaaaaabULL, /* 24 */ - 0x0000000000000000ULL, - 0x1c71c71c71c71c72ULL, - 0x8e38e38e38e38e39ULL, - 0xbbbbbbbbbbbbbbbcULL, - 0xeeeeeeeeeeeeeeefULL, - 0x097b425ed097b426ULL, - 0xa12f684bda12f685ULL, - 0x3333333333333334ULL, /* 32 */ - 0x0000000000000000ULL, - 0x7777777777777778ULL, - 0xbbbbbbbbbbbbbbbcULL, - 0xf5c28f5c28f5c290ULL, - 0x3d70a3d70a3d70a4ULL, - 0x7d27d27d27d27d28ULL, - 0xb60b60b60b60b60cULL, - 0xcccccccccccccccdULL, /* 40 */ - 0x0000000000000000ULL, - 0xdddddddddddddddeULL, - 0xeeeeeeeeeeeeeeefULL, - 0x3d70a3d70a3d70a4ULL, - 0x8f5c28f5c28f5c29ULL, - 0x9f49f49f49f49f4aULL, - 0x2d82d82d82d82d83ULL, - 0x1c71c71c71c71c72ULL, /* 48 */ - 0x0000000000000000ULL, - 0x12f684bda12f684cULL, - 0x097b425ed097b426ULL, - 0x7d27d27d27d27d28ULL, - 0x9f49f49f49f49f4aULL, - 0xb0fcd6e9e06522c4ULL, - 0x6b74f0329161f9aeULL, - 0xe38e38e38e38e38fULL, /* 56 */ - 0x0000000000000000ULL, - 0x425ed097b425ed0aULL, - 0xa12f684bda12f685ULL, - 0xb60b60b60b60b60cULL, - 0x2d82d82d82d82d83ULL, - 0x6b74f0329161f9aeULL, - 0x781948b0fcd6e9e1ULL, - 0xad45be6961639000ULL, /* 64 */ - 0xefa7a5a0e7176a00ULL, - 0x08c6139fc4346000ULL, - 0xfbe1883aee787980ULL, - 0xefa7a5a0e7176a00ULL, - 0x37ae2b38fded7040ULL, - 0x6acb3d68be6cdc00ULL, - 0xedbf72842143b470ULL, - 0x08c6139fc4346000ULL, /* 72 */ - 0x6acb3d68be6cdc00ULL, - 0x8624e5e1e5044000ULL, - 0x76a5ab8089e38100ULL, - 0xfbe1883aee787980ULL, - 0xedbf72842143b470ULL, - 0x76a5ab8089e38100ULL, - 0x4bb436d5b1e9cfc4ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMUL(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMUL(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmulu.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmulu.c deleted file mode 100644 index 0862780e3de7..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_dmulu.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DMULU - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "DMULU"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000001ULL, /* 0 */ - 0x0000000000000000ULL, - 0x5555555555555556ULL, - 0xaaaaaaaaaaaaaaabULL, - 0x3333333333333334ULL, - 0xcccccccccccccccdULL, - 0x1c71c71c71c71c72ULL, - 0xe38e38e38e38e38fULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x5555555555555556ULL, /* 16 */ - 0x0000000000000000ULL, - 0x38e38e38e38e38e4ULL, - 0x1c71c71c71c71c72ULL, - 0x7777777777777778ULL, - 0xdddddddddddddddeULL, - 0x12f684bda12f684cULL, - 0x425ed097b425ed0aULL, - 0xaaaaaaaaaaaaaaabULL, /* 24 */ - 0x0000000000000000ULL, - 0x1c71c71c71c71c72ULL, - 0x8e38e38e38e38e39ULL, - 0xbbbbbbbbbbbbbbbcULL, - 0xeeeeeeeeeeeeeeefULL, - 0x097b425ed097b426ULL, - 0xa12f684bda12f685ULL, - 0x3333333333333334ULL, /* 32 */ - 0x0000000000000000ULL, - 0x7777777777777778ULL, - 0xbbbbbbbbbbbbbbbcULL, - 0xf5c28f5c28f5c290ULL, - 0x3d70a3d70a3d70a4ULL, - 0x7d27d27d27d27d28ULL, - 0xb60b60b60b60b60cULL, - 0xcccccccccccccccdULL, /* 40 */ - 0x0000000000000000ULL, - 0xdddddddddddddddeULL, - 0xeeeeeeeeeeeeeeefULL, - 0x3d70a3d70a3d70a4ULL, - 0x8f5c28f5c28f5c29ULL, - 0x9f49f49f49f49f4aULL, - 0x2d82d82d82d82d83ULL, - 0x1c71c71c71c71c72ULL, /* 48 */ - 0x0000000000000000ULL, - 0x12f684bda12f684cULL, - 0x097b425ed097b426ULL, - 0x7d27d27d27d27d28ULL, - 0x9f49f49f49f49f4aULL, - 0xb0fcd6e9e06522c4ULL, - 0x6b74f0329161f9aeULL, - 0xe38e38e38e38e38fULL, /* 56 */ - 0x0000000000000000ULL, - 0x425ed097b425ed0aULL, - 0xa12f684bda12f685ULL, - 0xb60b60b60b60b60cULL, - 0x2d82d82d82d82d83ULL, - 0x6b74f0329161f9aeULL, - 0x781948b0fcd6e9e1ULL, - 0xad45be6961639000ULL, /* 64 */ - 0xefa7a5a0e7176a00ULL, - 0x08c6139fc4346000ULL, - 0xfbe1883aee787980ULL, - 0xefa7a5a0e7176a00ULL, - 0x37ae2b38fded7040ULL, - 0x6acb3d68be6cdc00ULL, - 0xedbf72842143b470ULL, - 0x08c6139fc4346000ULL, /* 72 */ - 0x6acb3d68be6cdc00ULL, - 0x8624e5e1e5044000ULL, - 0x76a5ab8089e38100ULL, - 0xfbe1883aee787980ULL, - 0xedbf72842143b470ULL, - 0x76a5ab8089e38100ULL, - 0x4bb436d5b1e9cfc4ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMULU(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DMULU(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_muh.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_muh.c deleted file mode 100644 index ff1ae6fd9ce9..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_muh.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction MUH - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "MUH"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000000ULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0x0000000000000000ULL, - 0x000000001c71c71cULL, - 0xffffffffe38e38e3ULL, - 0x0000000011111111ULL, - 0xffffffffeeeeeeeeULL, - 0x00000000097b425fULL, - 0xfffffffff684bda1ULL, - 0xffffffffffffffffULL, /* 24 */ - 0x0000000000000000ULL, - 0xffffffffe38e38e3ULL, - 0x000000001c71c71cULL, - 0xffffffffeeeeeeeeULL, - 0x0000000011111110ULL, - 0xfffffffff684bda1ULL, - 0x00000000097b425eULL, - 0x0000000000000000ULL, /* 32 */ - 0x0000000000000000ULL, - 0x0000000011111111ULL, - 0xffffffffeeeeeeeeULL, - 0x000000000a3d70a4ULL, - 0xfffffffff5c28f5cULL, - 0x0000000005b05b05ULL, - 0xfffffffffa4fa4faULL, - 0xffffffffffffffffULL, /* 40 */ - 0x0000000000000000ULL, - 0xffffffffeeeeeeeeULL, - 0x0000000011111110ULL, - 0xfffffffff5c28f5cULL, - 0x000000000a3d70a3ULL, - 0xfffffffffa4fa4faULL, - 0x0000000005b05b05ULL, - 0x0000000000000000ULL, /* 48 */ - 0x0000000000000000ULL, - 0x00000000097b425fULL, - 0xfffffffff684bda1ULL, - 0x0000000005b05b05ULL, - 0xfffffffffa4fa4faULL, - 0x000000000329161fULL, - 0xfffffffffcd6e9e0ULL, - 0xffffffffffffffffULL, /* 56 */ - 0x0000000000000000ULL, - 0xfffffffff684bda1ULL, - 0x00000000097b425eULL, - 0xfffffffffa4fa4faULL, - 0x0000000005b05b05ULL, - 0xfffffffffcd6e9e0ULL, - 0x000000000329161fULL, - 0x0000000037dbf444ULL, /* 64 */ - 0x0000000001fd28a7ULL, - 0x0000000027129043ULL, - 0xffffffffcb89d38bULL, - 0x0000000001fd28a7ULL, - 0x0000000000122100ULL, - 0x00000000016425c3ULL, - 0xfffffffffe21cf6eULL, - 0x0000000027129043ULL, /* 72 */ - 0x00000000016425c3ULL, - 0x000000001b549d7fULL, - 0xffffffffdb4dd51cULL, - 0xffffffffcb89d38bULL, - 0xfffffffffe21cf6eULL, - 0xffffffffdb4dd51cULL, - 0x0000000031454bf2ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MUH(b64_pattern_se + i, b64_pattern_se + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MUH(b64_random_se + i, b64_random_se + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_muhu.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_muhu.c deleted file mode 100644 index cb2752767a51..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_muhu.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction MUHU - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "MUHU"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xfffffffffffffffeULL, /* 0 */ - 0x0000000000000000ULL, - 0xffffffffaaaaaaa9ULL, - 0x0000000055555554ULL, - 0xffffffffcccccccbULL, - 0x0000000033333332ULL, - 0xffffffffe38e38e2ULL, - 0x000000001c71c71bULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0xffffffffaaaaaaa9ULL, /* 16 */ - 0x0000000000000000ULL, - 0x0000000071c71c70ULL, - 0x0000000038e38e38ULL, - 0xffffffff88888887ULL, - 0x0000000022222221ULL, - 0xffffffff97b425ecULL, - 0x0000000012f684bdULL, - 0x0000000055555554ULL, /* 24 */ - 0x0000000000000000ULL, - 0x0000000038e38e38ULL, - 0x000000001c71c71cULL, - 0x0000000044444443ULL, - 0x0000000011111110ULL, - 0x000000004bda12f6ULL, - 0x00000000097b425eULL, - 0xffffffffcccccccbULL, /* 32 */ - 0x0000000000000000ULL, - 0xffffffff88888887ULL, - 0x0000000044444443ULL, - 0xffffffffa3d70a3cULL, - 0x0000000028f5c28fULL, - 0xffffffffb60b60b4ULL, - 0x0000000016c16c16ULL, - 0x0000000033333332ULL, /* 40 */ - 0x0000000000000000ULL, - 0x0000000022222221ULL, - 0x0000000011111110ULL, - 0x0000000028f5c28fULL, - 0x000000000a3d70a3ULL, - 0x000000002d82d82dULL, - 0x0000000005b05b05ULL, - 0xffffffffe38e38e2ULL, /* 48 */ - 0x0000000000000000ULL, - 0xffffffff97b425ecULL, - 0x000000004bda12f6ULL, - 0xffffffffb60b60b4ULL, - 0x000000002d82d82dULL, - 0xffffffffca4587e5ULL, - 0x000000001948b0fcULL, - 0x000000001c71c71bULL, /* 56 */ - 0x0000000000000000ULL, - 0x0000000012f684bdULL, - 0x00000000097b425eULL, - 0x0000000016c16c16ULL, - 0x0000000005b05b05ULL, - 0x000000001948b0fcULL, - 0x000000000329161fULL, - 0x0000000048b1c1dcULL, /* 64 */ - 0xffffffff86260fd6ULL, - 0x000000005bd825b9ULL, - 0x000000003bd8e9d8ULL, - 0xffffffff86260fd6ULL, - 0xfffffffff78e21c6ULL, - 0xffffffffa97cd4d0ULL, - 0x000000006e70e5bbULL, - 0x000000005bd825b9ULL, /* 72 */ - 0xffffffffa97cd4d0ULL, - 0x000000007409fad3ULL, - 0x000000004b9ceb69ULL, - 0x000000003bd8e9d8ULL, - 0x000000006e70e5bbULL, - 0x000000004b9ceb69ULL, - 0x0000000031454bf2ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MUHU(b64_pattern_se + i, b64_pattern_se + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MUHU(b64_random_se + i, b64_random_se + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_mul.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_mul.c deleted file mode 100644 index 5cdc4d563240..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_mul.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction MUL - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "MUL"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000001ULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000055555556ULL, - 0xffffffffaaaaaaabULL, - 0x0000000033333334ULL, - 0xffffffffcccccccdULL, - 0x0000000071c71c72ULL, - 0xffffffff8e38e38fULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000055555556ULL, /* 16 */ - 0x0000000000000000ULL, - 0xffffffffe38e38e4ULL, - 0x0000000071c71c72ULL, - 0x0000000077777778ULL, - 0xffffffffdddddddeULL, - 0xffffffffa12f684cULL, - 0xffffffffb425ed0aULL, - 0xffffffffaaaaaaabULL, /* 24 */ - 0x0000000000000000ULL, - 0x0000000071c71c72ULL, - 0x0000000038e38e39ULL, - 0xffffffffbbbbbbbcULL, - 0xffffffffeeeeeeefULL, - 0xffffffffd097b426ULL, - 0xffffffffda12f685ULL, - 0x0000000033333334ULL, /* 32 */ - 0x0000000000000000ULL, - 0x0000000077777778ULL, - 0xffffffffbbbbbbbcULL, - 0x0000000028f5c290ULL, - 0x000000000a3d70a4ULL, - 0x0000000027d27d28ULL, - 0x000000000b60b60cULL, - 0xffffffffcccccccdULL, /* 40 */ - 0x0000000000000000ULL, - 0xffffffffdddddddeULL, - 0xffffffffeeeeeeefULL, - 0x000000000a3d70a4ULL, - 0xffffffffc28f5c29ULL, - 0x0000000049f49f4aULL, - 0xffffffff82d82d83ULL, - 0x0000000071c71c72ULL, /* 48 */ - 0x0000000000000000ULL, - 0xffffffffa12f684cULL, - 0xffffffffd097b426ULL, - 0x0000000027d27d28ULL, - 0x0000000049f49f4aULL, - 0xffffffffe06522c4ULL, - 0xffffffff9161f9aeULL, - 0xffffffff8e38e38fULL, /* 56 */ - 0x0000000000000000ULL, - 0xffffffffb425ed0aULL, - 0xffffffffda12f685ULL, - 0x000000000b60b60cULL, - 0xffffffff82d82d83ULL, - 0xffffffff9161f9aeULL, - 0xfffffffffcd6e9e1ULL, - 0x0000000061639000ULL, /* 64 */ - 0xffffffffe7176a00ULL, - 0xffffffffc4346000ULL, - 0xffffffffee787980ULL, - 0xffffffffe7176a00ULL, - 0xfffffffffded7040ULL, - 0xffffffffbe6cdc00ULL, - 0x000000002143b470ULL, - 0xffffffffc4346000ULL, /* 72 */ - 0xffffffffbe6cdc00ULL, - 0xffffffffe5044000ULL, - 0xffffffff89e38100ULL, - 0xffffffffee787980ULL, - 0x000000002143b470ULL, - 0xffffffff89e38100ULL, - 0xffffffffb1e9cfc4ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MUL(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MUL(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_mulu.c b/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_mulu.c deleted file mode 100644 index ccb3bdc1ac5e..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/int-multiply/test_mips64r6_mulu.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction MULU - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Int Multiply"; - char *instruction_name = "MULU"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000001ULL, /* 0 */ - 0x0000000000000000ULL, - 0x0000000055555556ULL, - 0xffffffffaaaaaaabULL, - 0x0000000033333334ULL, - 0xffffffffcccccccdULL, - 0x0000000071c71c72ULL, - 0xffffffff8e38e38fULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000055555556ULL, /* 16 */ - 0x0000000000000000ULL, - 0xffffffffe38e38e4ULL, - 0x0000000071c71c72ULL, - 0x0000000077777778ULL, - 0xffffffffdddddddeULL, - 0xffffffffa12f684cULL, - 0xffffffffb425ed0aULL, - 0xffffffffaaaaaaabULL, /* 24 */ - 0x0000000000000000ULL, - 0x0000000071c71c72ULL, - 0x0000000038e38e39ULL, - 0xffffffffbbbbbbbcULL, - 0xffffffffeeeeeeefULL, - 0xffffffffd097b426ULL, - 0xffffffffda12f685ULL, - 0x0000000033333334ULL, /* 32 */ - 0x0000000000000000ULL, - 0x0000000077777778ULL, - 0xffffffffbbbbbbbcULL, - 0x0000000028f5c290ULL, - 0x000000000a3d70a4ULL, - 0x0000000027d27d28ULL, - 0x000000000b60b60cULL, - 0xffffffffcccccccdULL, /* 40 */ - 0x0000000000000000ULL, - 0xffffffffdddddddeULL, - 0xffffffffeeeeeeefULL, - 0x000000000a3d70a4ULL, - 0xffffffffc28f5c29ULL, - 0x0000000049f49f4aULL, - 0xffffffff82d82d83ULL, - 0x0000000071c71c72ULL, /* 48 */ - 0x0000000000000000ULL, - 0xffffffffa12f684cULL, - 0xffffffffd097b426ULL, - 0x0000000027d27d28ULL, - 0x0000000049f49f4aULL, - 0xffffffffe06522c4ULL, - 0xffffffff9161f9aeULL, - 0xffffffff8e38e38fULL, /* 56 */ - 0x0000000000000000ULL, - 0xffffffffb425ed0aULL, - 0xffffffffda12f685ULL, - 0x000000000b60b60cULL, - 0xffffffff82d82d83ULL, - 0xffffffff9161f9aeULL, - 0xfffffffffcd6e9e1ULL, - 0x0000000061639000ULL, /* 64 */ - 0xffffffffe7176a00ULL, - 0xffffffffc4346000ULL, - 0xffffffffee787980ULL, - 0xffffffffe7176a00ULL, - 0xfffffffffded7040ULL, - 0xffffffffbe6cdc00ULL, - 0x000000002143b470ULL, - 0xffffffffc4346000ULL, /* 72 */ - 0xffffffffbe6cdc00ULL, - 0xffffffffe5044000ULL, - 0xffffffff89e38100ULL, - 0xffffffffee787980ULL, - 0x000000002143b470ULL, - 0xffffffff89e38100ULL, - 0xffffffffb1e9cfc4ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MULU(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_MULU(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_and.c b/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_and.c deleted file mode 100644 index 4d6cf2e1f1df..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_and.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction AND - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Logic"; - char *instruction_name = "AND"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x8000000000000000ULL, /* 0 */ - 0xffffffffffffffffULL, - 0xfffffc0000000000ULL, - 0xffffffffffe00000ULL, - 0xfffffffffffff000ULL, - 0xfff8000000000000ULL, - 0xffffffffffffc000ULL, - 0xfffe000000000000ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0xaaaaa80000000000ULL, - 0x5555555555400000ULL, - 0xaaaaaaaaaaaaa000ULL, - 0x5550000000000000ULL, - 0xaaaaaaaaaaaa8000ULL, - 0x5554000000000000ULL, - 0x8000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x5555540000000000ULL, - 0xaaaaaaaaaaa00000ULL, - 0x5555555555555000ULL, - 0xaaa8000000000000ULL, - 0x5555555555554000ULL, - 0xaaaa000000000000ULL, - 0x0000000000000000ULL, /* 32 */ - 0xccccccccccccccccULL, - 0x3333300000000000ULL, - 0x9999999999800000ULL, - 0xccccccccccccc000ULL, - 0x6660000000000000ULL, - 0x3333333333330000ULL, - 0x9998000000000000ULL, - 0x8000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0xcccccc0000000000ULL, - 0x6666666666600000ULL, - 0x3333333333333000ULL, - 0x9998000000000000ULL, - 0xccccccccccccc000ULL, - 0x6666000000000000ULL, - 0x0000000000000000ULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0xe38e380000000000ULL, - 0x1c71c71c71c00000ULL, - 0xe38e38e38e38e000ULL, - 0x1c70000000000000ULL, - 0x8e38e38e38e38000ULL, - 0xc71c000000000000ULL, - 0x8000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x1c71c40000000000ULL, - 0xe38e38e38e200000ULL, - 0x1c71c71c71c71000ULL, - 0xe388000000000000ULL, - 0x71c71c71c71c4000ULL, - 0x38e2000000000000ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0x6ae6cc2862554000ULL, - 0x886ae6cc28625540ULL, - 0xb9b30a1895500000ULL, - 0xfbbe00634d93c708ULL, - 0xbe00634d93c70800ULL, - 0xfbbe00634d93c708ULL, - 0x8018d364f1c20000ULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0x5aaeaab9cf8b8000ULL, - 0xac5aaeaab9cf8b80ULL, - 0xabaaae73e2e00000ULL, - 0x704f164d5e31e24eULL, - 0x4f164d5e31e24e00ULL, - 0x704f164d5e31e24eULL, - 0xc593578c78938000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_AND(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_AND(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_nor.c b/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_nor.c deleted file mode 100644 index 21005ddc53b6..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_nor.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction NOR - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Logic"; - char *instruction_name = "NOR"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x8000000000000000ULL, /* 0 */ - 0xffffffffffffffffULL, - 0xfffffc0000000000ULL, - 0xffffffffffe00000ULL, - 0xfffffffffffff000ULL, - 0xfff8000000000000ULL, - 0xffffffffffffc000ULL, - 0xfffe000000000000ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0xaaaaa80000000000ULL, - 0x5555555555400000ULL, - 0xaaaaaaaaaaaaa000ULL, - 0x5550000000000000ULL, - 0xaaaaaaaaaaaa8000ULL, - 0x5554000000000000ULL, - 0x8000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x5555540000000000ULL, - 0xaaaaaaaaaaa00000ULL, - 0x5555555555555000ULL, - 0xaaa8000000000000ULL, - 0x5555555555554000ULL, - 0xaaaa000000000000ULL, - 0x0000000000000000ULL, /* 32 */ - 0xccccccccccccccccULL, - 0x3333300000000000ULL, - 0x9999999999800000ULL, - 0xccccccccccccc000ULL, - 0x6660000000000000ULL, - 0x3333333333330000ULL, - 0x9998000000000000ULL, - 0x8000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0xcccccc0000000000ULL, - 0x6666666666600000ULL, - 0x3333333333333000ULL, - 0x9998000000000000ULL, - 0xccccccccccccc000ULL, - 0x6666000000000000ULL, - 0x0000000000000000ULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0xe38e380000000000ULL, - 0x1c71c71c71c00000ULL, - 0xe38e38e38e38e000ULL, - 0x1c70000000000000ULL, - 0x8e38e38e38e38000ULL, - 0xc71c000000000000ULL, - 0x8000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x1c71c40000000000ULL, - 0xe38e38e38e200000ULL, - 0x1c71c71c71c71000ULL, - 0xe388000000000000ULL, - 0x71c71c71c71c4000ULL, - 0x38e2000000000000ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0x6ae6cc2862554000ULL, - 0x886ae6cc28625540ULL, - 0xb9b30a1895500000ULL, - 0xfbbe00634d93c708ULL, - 0xbe00634d93c70800ULL, - 0xfbbe00634d93c708ULL, - 0x8018d364f1c20000ULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0x5aaeaab9cf8b8000ULL, - 0xac5aaeaab9cf8b80ULL, - 0xabaaae73e2e00000ULL, - 0x704f164d5e31e24eULL, - 0x4f164d5e31e24e00ULL, - 0x704f164d5e31e24eULL, - 0xc593578c78938000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_NOR(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_NOR(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_or.c b/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_or.c deleted file mode 100644 index 345b4544fe02..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_or.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction OR - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Logic"; - char *instruction_name = "OR"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x8000000000000000ULL, /* 0 */ - 0xffffffffffffffffULL, - 0xfffffc0000000000ULL, - 0xffffffffffe00000ULL, - 0xfffffffffffff000ULL, - 0xfff8000000000000ULL, - 0xffffffffffffc000ULL, - 0xfffe000000000000ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0xaaaaa80000000000ULL, - 0x5555555555400000ULL, - 0xaaaaaaaaaaaaa000ULL, - 0x5550000000000000ULL, - 0xaaaaaaaaaaaa8000ULL, - 0x5554000000000000ULL, - 0x8000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x5555540000000000ULL, - 0xaaaaaaaaaaa00000ULL, - 0x5555555555555000ULL, - 0xaaa8000000000000ULL, - 0x5555555555554000ULL, - 0xaaaa000000000000ULL, - 0x0000000000000000ULL, /* 32 */ - 0xccccccccccccccccULL, - 0x3333300000000000ULL, - 0x9999999999800000ULL, - 0xccccccccccccc000ULL, - 0x6660000000000000ULL, - 0x3333333333330000ULL, - 0x9998000000000000ULL, - 0x8000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0xcccccc0000000000ULL, - 0x6666666666600000ULL, - 0x3333333333333000ULL, - 0x9998000000000000ULL, - 0xccccccccccccc000ULL, - 0x6666000000000000ULL, - 0x0000000000000000ULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0xe38e380000000000ULL, - 0x1c71c71c71c00000ULL, - 0xe38e38e38e38e000ULL, - 0x1c70000000000000ULL, - 0x8e38e38e38e38000ULL, - 0xc71c000000000000ULL, - 0x8000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x1c71c40000000000ULL, - 0xe38e38e38e200000ULL, - 0x1c71c71c71c71000ULL, - 0xe388000000000000ULL, - 0x71c71c71c71c4000ULL, - 0x38e2000000000000ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0x6ae6cc2862554000ULL, - 0x886ae6cc28625540ULL, - 0xb9b30a1895500000ULL, - 0xfbbe00634d93c708ULL, - 0xbe00634d93c70800ULL, - 0xfbbe00634d93c708ULL, - 0x8018d364f1c20000ULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0x5aaeaab9cf8b8000ULL, - 0xac5aaeaab9cf8b80ULL, - 0xabaaae73e2e00000ULL, - 0x704f164d5e31e24eULL, - 0x4f164d5e31e24e00ULL, - 0x704f164d5e31e24eULL, - 0xc593578c78938000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_OR(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_OR(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_xor.c b/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_xor.c deleted file mode 100644 index 7e36fee517aa..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/logic/test_mips64r6_xor.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction XOR - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Logic"; - char *instruction_name = "XOR"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x8000000000000000ULL, /* 0 */ - 0xffffffffffffffffULL, - 0xfffffc0000000000ULL, - 0xffffffffffe00000ULL, - 0xfffffffffffff000ULL, - 0xfff8000000000000ULL, - 0xffffffffffffc000ULL, - 0xfffe000000000000ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0xaaaaa80000000000ULL, - 0x5555555555400000ULL, - 0xaaaaaaaaaaaaa000ULL, - 0x5550000000000000ULL, - 0xaaaaaaaaaaaa8000ULL, - 0x5554000000000000ULL, - 0x8000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x5555540000000000ULL, - 0xaaaaaaaaaaa00000ULL, - 0x5555555555555000ULL, - 0xaaa8000000000000ULL, - 0x5555555555554000ULL, - 0xaaaa000000000000ULL, - 0x0000000000000000ULL, /* 32 */ - 0xccccccccccccccccULL, - 0x3333300000000000ULL, - 0x9999999999800000ULL, - 0xccccccccccccc000ULL, - 0x6660000000000000ULL, - 0x3333333333330000ULL, - 0x9998000000000000ULL, - 0x8000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0xcccccc0000000000ULL, - 0x6666666666600000ULL, - 0x3333333333333000ULL, - 0x9998000000000000ULL, - 0xccccccccccccc000ULL, - 0x6666000000000000ULL, - 0x0000000000000000ULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0xe38e380000000000ULL, - 0x1c71c71c71c00000ULL, - 0xe38e38e38e38e000ULL, - 0x1c70000000000000ULL, - 0x8e38e38e38e38000ULL, - 0xc71c000000000000ULL, - 0x8000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x1c71c40000000000ULL, - 0xe38e38e38e200000ULL, - 0x1c71c71c71c71000ULL, - 0xe388000000000000ULL, - 0x71c71c71c71c4000ULL, - 0x38e2000000000000ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0x6ae6cc2862554000ULL, - 0x886ae6cc28625540ULL, - 0xb9b30a1895500000ULL, - 0xfbbe00634d93c708ULL, - 0xbe00634d93c70800ULL, - 0xfbbe00634d93c708ULL, - 0x8018d364f1c20000ULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0x5aaeaab9cf8b8000ULL, - 0xac5aaeaab9cf8b80ULL, - 0xabaaae73e2e00000ULL, - 0x704f164d5e31e24eULL, - 0x4f164d5e31e24e00ULL, - 0x704f164d5e31e24eULL, - 0xc593578c78938000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_XOR(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_XOR(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsllv.c b/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsllv.c deleted file mode 100644 index 4f719efda12f..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsllv.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DSLLV - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Shift"; - char *instruction_name = "DSLLV"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x8000000000000000ULL, /* 0 */ - 0xffffffffffffffffULL, - 0xfffffc0000000000ULL, - 0xffffffffffe00000ULL, - 0xfffffffffffff000ULL, - 0xfff8000000000000ULL, - 0xffffffffffffc000ULL, - 0xfffe000000000000ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0xaaaaa80000000000ULL, - 0x5555555555400000ULL, - 0xaaaaaaaaaaaaa000ULL, - 0x5550000000000000ULL, - 0xaaaaaaaaaaaa8000ULL, - 0x5554000000000000ULL, - 0x8000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x5555540000000000ULL, - 0xaaaaaaaaaaa00000ULL, - 0x5555555555555000ULL, - 0xaaa8000000000000ULL, - 0x5555555555554000ULL, - 0xaaaa000000000000ULL, - 0x0000000000000000ULL, /* 32 */ - 0xccccccccccccccccULL, - 0x3333300000000000ULL, - 0x9999999999800000ULL, - 0xccccccccccccc000ULL, - 0x6660000000000000ULL, - 0x3333333333330000ULL, - 0x9998000000000000ULL, - 0x8000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0xcccccc0000000000ULL, - 0x6666666666600000ULL, - 0x3333333333333000ULL, - 0x9998000000000000ULL, - 0xccccccccccccc000ULL, - 0x6666000000000000ULL, - 0x0000000000000000ULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0xe38e380000000000ULL, - 0x1c71c71c71c00000ULL, - 0xe38e38e38e38e000ULL, - 0x1c70000000000000ULL, - 0x8e38e38e38e38000ULL, - 0xc71c000000000000ULL, - 0x8000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x1c71c40000000000ULL, - 0xe38e38e38e200000ULL, - 0x1c71c71c71c71000ULL, - 0xe388000000000000ULL, - 0x71c71c71c71c4000ULL, - 0x38e2000000000000ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0x6ae6cc2862554000ULL, - 0x886ae6cc28625540ULL, - 0xb9b30a1895500000ULL, - 0xfbbe00634d93c708ULL, - 0xbe00634d93c70800ULL, - 0xfbbe00634d93c708ULL, - 0x8018d364f1c20000ULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0x5aaeaab9cf8b8000ULL, - 0xac5aaeaab9cf8b80ULL, - 0xabaaae73e2e00000ULL, - 0x704f164d5e31e24eULL, - 0x4f164d5e31e24e00ULL, - 0x704f164d5e31e24eULL, - 0xc593578c78938000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DSLLV(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DSLLV(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsrav.c b/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsrav.c deleted file mode 100644 index 024d508ca878..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsrav.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DSRAV - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Shift"; - char *instruction_name = "DSRAV"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xffffffffffffffffULL, /* 0 */ - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0xffffffffffeaaaaaULL, - 0xfffffd5555555555ULL, - 0xfffaaaaaaaaaaaaaULL, - 0xfffffffffffff555ULL, - 0xfffeaaaaaaaaaaaaULL, - 0xffffffffffffd555ULL, - 0x0000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x0000000000155555ULL, - 0x000002aaaaaaaaaaULL, - 0x0005555555555555ULL, - 0x0000000000000aaaULL, - 0x0001555555555555ULL, - 0x0000000000002aaaULL, - 0xffffffffffffffffULL, /* 32 */ - 0xccccccccccccccccULL, - 0xfffffffffff33333ULL, - 0xfffffe6666666666ULL, - 0xfffcccccccccccccULL, - 0xfffffffffffff999ULL, - 0xffff333333333333ULL, - 0xffffffffffffe666ULL, - 0x0000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0x00000000000cccccULL, - 0x0000019999999999ULL, - 0x0003333333333333ULL, - 0x0000000000000666ULL, - 0x0000ccccccccccccULL, - 0x0000000000001999ULL, - 0xffffffffffffffffULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0xfffffffffff8e38eULL, - 0xffffff1c71c71c71ULL, - 0xfffe38e38e38e38eULL, - 0xfffffffffffffc71ULL, - 0xffff8e38e38e38e3ULL, - 0xfffffffffffff1c7ULL, - 0x0000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x0000000000071c71ULL, - 0x000000e38e38e38eULL, - 0x0001c71c71c71c71ULL, - 0x000000000000038eULL, - 0x000071c71c71c71cULL, - 0x0000000000000e38ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0xff886ae6cc286255ULL, - 0x886ae6cc28625540ULL, - 0xfffe21ab9b30a189ULL, - 0xfbbe00634d93c708ULL, - 0xfffbbe00634d93c7ULL, - 0xfbbe00634d93c708ULL, - 0xffffeef8018d364fULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0xffac5aaeaab9cf8bULL, - 0xac5aaeaab9cf8b80ULL, - 0xfffeb16abaaae73eULL, - 0x704f164d5e31e24eULL, - 0x00704f164d5e31e2ULL, - 0x704f164d5e31e24eULL, - 0x0001c13c593578c7ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DSRAV(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DSRAV(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsrlv.c b/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsrlv.c deleted file mode 100644 index fd1c398ffde3..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_dsrlv.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction DSRLV - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Shift"; - char *instruction_name = "DSRLV"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000001ULL, /* 0 */ - 0xffffffffffffffffULL, - 0x00000000003fffffULL, - 0x000007ffffffffffULL, - 0x000fffffffffffffULL, - 0x0000000000001fffULL, - 0x0003ffffffffffffULL, - 0x0000000000007fffULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, /* 16 */ - 0xaaaaaaaaaaaaaaaaULL, - 0x00000000002aaaaaULL, - 0x0000055555555555ULL, - 0x000aaaaaaaaaaaaaULL, - 0x0000000000001555ULL, - 0x0002aaaaaaaaaaaaULL, - 0x0000000000005555ULL, - 0x0000000000000000ULL, /* 24 */ - 0x5555555555555555ULL, - 0x0000000000155555ULL, - 0x000002aaaaaaaaaaULL, - 0x0005555555555555ULL, - 0x0000000000000aaaULL, - 0x0001555555555555ULL, - 0x0000000000002aaaULL, - 0x0000000000000001ULL, /* 32 */ - 0xccccccccccccccccULL, - 0x0000000000333333ULL, - 0x0000066666666666ULL, - 0x000cccccccccccccULL, - 0x0000000000001999ULL, - 0x0003333333333333ULL, - 0x0000000000006666ULL, - 0x0000000000000000ULL, /* 40 */ - 0x3333333333333333ULL, - 0x00000000000cccccULL, - 0x0000019999999999ULL, - 0x0003333333333333ULL, - 0x0000000000000666ULL, - 0x0000ccccccccccccULL, - 0x0000000000001999ULL, - 0x0000000000000001ULL, /* 48 */ - 0xe38e38e38e38e38eULL, - 0x000000000038e38eULL, - 0x0000071c71c71c71ULL, - 0x000e38e38e38e38eULL, - 0x0000000000001c71ULL, - 0x00038e38e38e38e3ULL, - 0x00000000000071c7ULL, - 0x0000000000000000ULL, /* 56 */ - 0x1c71c71c71c71c71ULL, - 0x0000000000071c71ULL, - 0x000000e38e38e38eULL, - 0x0001c71c71c71c71ULL, - 0x000000000000038eULL, - 0x000071c71c71c71cULL, - 0x0000000000000e38ULL, - 0x886ae6cc28625540ULL, /* 64 */ - 0x00886ae6cc286255ULL, - 0x886ae6cc28625540ULL, - 0x000221ab9b30a189ULL, - 0xfbbe00634d93c708ULL, - 0x00fbbe00634d93c7ULL, - 0xfbbe00634d93c708ULL, - 0x0003eef8018d364fULL, - 0xac5aaeaab9cf8b80ULL, /* 72 */ - 0x00ac5aaeaab9cf8bULL, - 0xac5aaeaab9cf8b80ULL, - 0x0002b16abaaae73eULL, - 0x704f164d5e31e24eULL, - 0x00704f164d5e31e2ULL, - 0x704f164d5e31e24eULL, - 0x0001c13c593578c7ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DSRLV(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_DSRLV(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_sllv.c b/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_sllv.c deleted file mode 100644 index a5fa72b72780..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_sllv.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction SLLV - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Shift"; - char *instruction_name = "SLLV"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xffffffff80000000ULL, /* 0 */ - 0xffffffffffffffffULL, - 0xfffffffffffffc00ULL, - 0xffffffffffe00000ULL, - 0xfffffffffffff000ULL, - 0xfffffffffff80000ULL, - 0xffffffffffffc000ULL, - 0xfffffffffffe0000ULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, /* 16 */ - 0xffffffffaaaaaaaaULL, - 0xffffffffaaaaa800ULL, - 0x0000000055400000ULL, - 0xffffffffaaaaa000ULL, - 0x0000000055500000ULL, - 0xffffffffaaaa8000ULL, - 0x0000000055540000ULL, - 0xffffffff80000000ULL, /* 24 */ - 0x0000000055555555ULL, - 0x0000000055555400ULL, - 0xffffffffaaa00000ULL, - 0x0000000055555000ULL, - 0xffffffffaaa80000ULL, - 0x0000000055554000ULL, - 0xffffffffaaaa0000ULL, - 0x0000000000000000ULL, /* 32 */ - 0xffffffffccccccccULL, - 0x0000000033333000ULL, - 0xffffffff99800000ULL, - 0xffffffffccccc000ULL, - 0x0000000066600000ULL, - 0x0000000033330000ULL, - 0xffffffff99980000ULL, - 0xffffffff80000000ULL, /* 40 */ - 0x0000000033333333ULL, - 0xffffffffcccccc00ULL, - 0x0000000066600000ULL, - 0x0000000033333000ULL, - 0xffffffff99980000ULL, - 0xffffffffccccc000ULL, - 0x0000000066660000ULL, - 0x0000000000000000ULL, /* 48 */ - 0xffffffff8e38e38eULL, - 0xffffffffe38e3800ULL, - 0x0000000071c00000ULL, - 0xffffffff8e38e000ULL, - 0x000000001c700000ULL, - 0x0000000038e38000ULL, - 0xffffffffc71c0000ULL, - 0xffffffff80000000ULL, /* 56 */ - 0x0000000071c71c71ULL, - 0x000000001c71c400ULL, - 0xffffffff8e200000ULL, - 0x0000000071c71000ULL, - 0xffffffffe3880000ULL, - 0xffffffffc71c4000ULL, - 0x0000000038e20000ULL, - 0x0000000028625540ULL, /* 64 */ - 0x0000000062554000ULL, - 0x0000000028625540ULL, - 0xffffffff95500000ULL, - 0x000000004d93c708ULL, - 0xffffffff93c70800ULL, - 0x000000004d93c708ULL, - 0xfffffffff1c20000ULL, - 0xffffffffb9cf8b80ULL, /* 72 */ - 0xffffffffcf8b8000ULL, - 0xffffffffb9cf8b80ULL, - 0xffffffffe2e00000ULL, - 0x000000005e31e24eULL, - 0x0000000031e24e00ULL, - 0x000000005e31e24eULL, - 0x0000000078938000ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_SLLV(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_SLLV(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_srav.c b/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_srav.c deleted file mode 100644 index 79e1a047eb7d..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_srav.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction SRAV - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Shift"; - char *instruction_name = "SRAV"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0xffffffffffffffffULL, /* 0 */ - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0xffffffffffffffffULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0xffffffffffffffffULL, /* 16 */ - 0xffffffffaaaaaaaaULL, - 0xffffffffffeaaaaaULL, - 0xfffffffffffffd55ULL, - 0xfffffffffffaaaaaULL, - 0xfffffffffffff555ULL, - 0xfffffffffffeaaaaULL, - 0xffffffffffffd555ULL, - 0x0000000000000000ULL, /* 24 */ - 0x0000000055555555ULL, - 0x0000000000155555ULL, - 0x00000000000002aaULL, - 0x0000000000055555ULL, - 0x0000000000000aaaULL, - 0x0000000000015555ULL, - 0x0000000000002aaaULL, - 0xffffffffffffffffULL, /* 32 */ - 0xffffffffccccccccULL, - 0xfffffffffff33333ULL, - 0xfffffffffffffe66ULL, - 0xfffffffffffcccccULL, - 0xfffffffffffff999ULL, - 0xffffffffffff3333ULL, - 0xffffffffffffe666ULL, - 0x0000000000000000ULL, /* 40 */ - 0x0000000033333333ULL, - 0x00000000000cccccULL, - 0x0000000000000199ULL, - 0x0000000000033333ULL, - 0x0000000000000666ULL, - 0x000000000000ccccULL, - 0x0000000000001999ULL, - 0xffffffffffffffffULL, /* 48 */ - 0xffffffff8e38e38eULL, - 0xffffffffffe38e38ULL, - 0xfffffffffffffc71ULL, - 0xfffffffffff8e38eULL, - 0xfffffffffffff1c7ULL, - 0xfffffffffffe38e3ULL, - 0xffffffffffffc71cULL, - 0x0000000000000000ULL, /* 56 */ - 0x0000000071c71c71ULL, - 0x00000000001c71c7ULL, - 0x000000000000038eULL, - 0x0000000000071c71ULL, - 0x0000000000000e38ULL, - 0x000000000001c71cULL, - 0x00000000000038e3ULL, - 0x0000000028625540ULL, /* 64 */ - 0x0000000000286255ULL, - 0x0000000028625540ULL, - 0x000000000000a189ULL, - 0x000000004d93c708ULL, - 0x00000000004d93c7ULL, - 0x000000004d93c708ULL, - 0x000000000001364fULL, - 0xffffffffb9cf8b80ULL, /* 72 */ - 0xffffffffffb9cf8bULL, - 0xffffffffb9cf8b80ULL, - 0xfffffffffffee73eULL, - 0x000000005e31e24eULL, - 0x00000000005e31e2ULL, - 0x000000005e31e24eULL, - 0x00000000000178c7ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_SRAV(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_SRAV(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_srlv.c b/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_srlv.c deleted file mode 100644 index 1f8c45d8cc8a..000000000000 --- a/tests/tcg/mips/user/isa/mips64r6/shift/test_mips64r6_srlv.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test program for MIPS64R6 instruction SRLV - * - * Copyright (C) 2019 Wave Computing, Inc. - * Copyright (C) 2019 Aleksandar Markovic - * - * 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 . - * - */ - -#include -#include - -#include "../../../../include/wrappers_mips64r6.h" -#include "../../../../include/test_inputs_64.h" -#include "../../../../include/test_utils_64.h" - -#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT) - - -int32_t main(void) -{ - char *isa_ase_name = "mips64r6"; - char *group_name = "Shift"; - char *instruction_name = "SRLV"; - int32_t ret; - uint32_t i, j; - struct timeval start, end; - double elapsed_time; - - uint64_t b64_result[TEST_COUNT_TOTAL]; - uint64_t b64_expect[TEST_COUNT_TOTAL] = { - 0x0000000000000001ULL, /* 0 */ - 0xffffffffffffffffULL, - 0x00000000003fffffULL, - 0x00000000000007ffULL, - 0x00000000000fffffULL, - 0x0000000000001fffULL, - 0x000000000003ffffULL, - 0x0000000000007fffULL, - 0x0000000000000000ULL, /* 8 */ - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000000ULL, - 0x0000000000000001ULL, /* 16 */ - 0xffffffffaaaaaaaaULL, - 0x00000000002aaaaaULL, - 0x0000000000000555ULL, - 0x00000000000aaaaaULL, - 0x0000000000001555ULL, - 0x000000000002aaaaULL, - 0x0000000000005555ULL, - 0x0000000000000000ULL, /* 24 */ - 0x0000000055555555ULL, - 0x0000000000155555ULL, - 0x00000000000002aaULL, - 0x0000000000055555ULL, - 0x0000000000000aaaULL, - 0x0000000000015555ULL, - 0x0000000000002aaaULL, - 0x0000000000000001ULL, /* 32 */ - 0xffffffffccccccccULL, - 0x0000000000333333ULL, - 0x0000000000000666ULL, - 0x00000000000cccccULL, - 0x0000000000001999ULL, - 0x0000000000033333ULL, - 0x0000000000006666ULL, - 0x0000000000000000ULL, /* 40 */ - 0x0000000033333333ULL, - 0x00000000000cccccULL, - 0x0000000000000199ULL, - 0x0000000000033333ULL, - 0x0000000000000666ULL, - 0x000000000000ccccULL, - 0x0000000000001999ULL, - 0x0000000000000001ULL, /* 48 */ - 0xffffffff8e38e38eULL, - 0x0000000000238e38ULL, - 0x0000000000000471ULL, - 0x000000000008e38eULL, - 0x00000000000011c7ULL, - 0x00000000000238e3ULL, - 0x000000000000471cULL, - 0x0000000000000000ULL, /* 56 */ - 0x0000000071c71c71ULL, - 0x00000000001c71c7ULL, - 0x000000000000038eULL, - 0x0000000000071c71ULL, - 0x0000000000000e38ULL, - 0x000000000001c71cULL, - 0x00000000000038e3ULL, - 0x0000000028625540ULL, /* 64 */ - 0x0000000000286255ULL, - 0x0000000028625540ULL, - 0x000000000000a189ULL, - 0x000000004d93c708ULL, - 0x00000000004d93c7ULL, - 0x000000004d93c708ULL, - 0x000000000001364fULL, - 0xffffffffb9cf8b80ULL, /* 72 */ - 0x0000000000b9cf8bULL, - 0xffffffffb9cf8b80ULL, - 0x000000000002e73eULL, - 0x000000005e31e24eULL, - 0x00000000005e31e2ULL, - 0x000000005e31e24eULL, - 0x00000000000178c7ULL, - }; - - gettimeofday(&start, NULL); - - for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_SRLV(b64_pattern + i, b64_pattern + j, - b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) { - for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) { - do_mips64r6_SRLV(b64_random + i, b64_random + j, - b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) * - (PATTERN_INPUTS_64_SHORT_COUNT)) + - RANDOM_INPUTS_64_SHORT_COUNT * i + j)); - } - } - - gettimeofday(&end, NULL); - - elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; - elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; - - ret = check_results_64(instruction_name, TEST_COUNT_TOTAL, elapsed_time, - b64_result, b64_expect); - - return ret; -} diff --git a/tests/tcg/mips/user/isa/r5900/Makefile b/tests/tcg/mips/user/isa/r5900/Makefile deleted file mode 100644 index bff360df6c97..000000000000 --- a/tests/tcg/mips/user/isa/r5900/Makefile +++ /dev/null @@ -1,32 +0,0 @@ --include ../../../../config-host.mak - -CROSS=mipsr5900el-unknown-linux-gnu- - -SIM=qemu-mipsel -SIM_FLAGS=-cpu R5900 - -CC = $(CROSS)gcc -CFLAGS = -Wall -mabi=32 -march=r5900 -static - -TESTCASES = test_r5900_div1.tst -TESTCASES += test_r5900_divu1.tst -TESTCASES += test_r5900_madd.tst -TESTCASES += test_r5900_maddu.tst -TESTCASES += test_r5900_mflohi1.tst -TESTCASES += test_r5900_mtlohi1.tst -TESTCASES += test_r5900_mult.tst -TESTCASES += test_r5900_multu.tst - -all: $(TESTCASES) - -%.tst: %.c - $(CC) $(CFLAGS) $< -o $@ - -check: $(TESTCASES) - @for case in $(TESTCASES); do \ - echo $(SIM) $(SIM_FLAGS) ./$$case;\ - $(SIM) $(SIM_FLAGS) ./$$case; \ - done - -clean: - $(RM) -rf $(TESTCASES) diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_div1.c b/tests/tcg/mips/user/isa/r5900/test_r5900_div1.c deleted file mode 100644 index 83dafa018b55..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_div1.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Test R5900-specific DIV1. - */ - -#include -#include -#include - -struct quotient_remainder { int32_t quotient, remainder; }; - -static struct quotient_remainder div1(int32_t rs, int32_t rt) -{ - int32_t lo, hi; - - __asm__ __volatile__ ( - " div1 $0, %2, %3\n" - " mflo1 %0\n" - " mfhi1 %1\n" - : "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt)); - - assert(rs / rt == lo); - assert(rs % rt == hi); - - return (struct quotient_remainder) { .quotient = lo, .remainder = hi }; -} - -static void verify_div1(int32_t rs, int32_t rt, - int32_t expected_quotient, - int32_t expected_remainder) -{ - struct quotient_remainder qr = div1(rs, rt); - - assert(qr.quotient == expected_quotient); - assert(qr.remainder == expected_remainder); -} - -static void verify_div1_negations(int32_t rs, int32_t rt, - int32_t expected_quotient, - int32_t expected_remainder) -{ - verify_div1(rs, rt, expected_quotient, expected_remainder); - verify_div1(rs, -rt, -expected_quotient, expected_remainder); - verify_div1(-rs, rt, -expected_quotient, -expected_remainder); - verify_div1(-rs, -rt, expected_quotient, -expected_remainder); -} - -int main() -{ - verify_div1_negations(0, 1, 0, 0); - verify_div1_negations(1, 1, 1, 0); - verify_div1_negations(1, 2, 0, 1); - verify_div1_negations(17, 19, 0, 17); - verify_div1_negations(19, 17, 1, 2); - verify_div1_negations(77773, 101, 770, 3); - - verify_div1(-0x80000000, 1, -0x80000000, 0); - - /* - * Supplementary explanation from the Toshiba TX System RISC TX79 Core - * Architecture manual, A-38 and B-7, https://wiki.qemu.org/File:C790.pdf - * - * Normally, when 0x80000000 (-2147483648) the signed minimum value is - * divided by 0xFFFFFFFF (-1), the operation will result in an overflow. - * However, in this instruction an overflow exception doesn't occur and - * the result will be as follows: - * - * Quotient is 0x80000000 (-2147483648), and remainder is 0x00000000 (0). - */ - verify_div1(-0x80000000, -1, -0x80000000, 0); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_divu1.c b/tests/tcg/mips/user/isa/r5900/test_r5900_divu1.c deleted file mode 100644 index 72aeed31debf..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_divu1.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Test R5900-specific DIVU1. - */ - -#include -#include -#include - -struct quotient_remainder { uint32_t quotient, remainder; }; - -static struct quotient_remainder divu1(uint32_t rs, uint32_t rt) -{ - uint32_t lo, hi; - - __asm__ __volatile__ ( - " divu1 $0, %2, %3\n" - " mflo1 %0\n" - " mfhi1 %1\n" - : "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt)); - - assert(rs / rt == lo); - assert(rs % rt == hi); - - return (struct quotient_remainder) { .quotient = lo, .remainder = hi }; -} - -static void verify_divu1(uint32_t rs, uint32_t rt, - uint32_t expected_quotient, - uint32_t expected_remainder) -{ - struct quotient_remainder qr = divu1(rs, rt); - - assert(qr.quotient == expected_quotient); - assert(qr.remainder == expected_remainder); -} - -int main() -{ - verify_divu1(0, 1, 0, 0); - verify_divu1(1, 1, 1, 0); - verify_divu1(1, 2, 0, 1); - verify_divu1(17, 19, 0, 17); - verify_divu1(19, 17, 1, 2); - verify_divu1(77773, 101, 770, 3); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_madd.c b/tests/tcg/mips/user/isa/r5900/test_r5900_madd.c deleted file mode 100644 index f6f215e1c356..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_madd.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Test R5900-specific three-operand MADD and MADD1. - */ - -#include -#include -#include - -int64_t madd(int64_t a, int32_t rs, int32_t rt) -{ - int32_t lo = a; - int32_t hi = a >> 32; - int32_t rd; - int64_t r; - - __asm__ __volatile__ ( - " mtlo %5\n" - " mthi %6\n" - " madd %0, %3, %4\n" - " mflo %1\n" - " mfhi %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt), "r" (lo), "r" (hi)); - r = ((int64_t)hi << 32) | (uint32_t)lo; - - assert(a + (int64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -int64_t madd1(int64_t a, int32_t rs, int32_t rt) -{ - int32_t lo = a; - int32_t hi = a >> 32; - int32_t rd; - int64_t r; - - __asm__ __volatile__ ( - " mtlo1 %5\n" - " mthi1 %6\n" - " madd1 %0, %3, %4\n" - " mflo1 %1\n" - " mfhi1 %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt), "r" (lo), "r" (hi)); - r = ((int64_t)hi << 32) | (uint32_t)lo; - - assert(a + (int64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -static int64_t madd_variants(int64_t a, int32_t rs, int32_t rt) -{ - int64_t rd = madd(a, rs, rt); - int64_t rd1 = madd1(a, rs, rt); - - assert(rd == rd1); - - return rd; -} - -static void verify_madd(int64_t a, int32_t rs, int32_t rt, int64_t expected) -{ - assert(madd_variants(a, rs, rt) == expected); - assert(madd_variants(a, -rs, rt) == a + a - expected); - assert(madd_variants(a, rs, -rt) == a + a - expected); - assert(madd_variants(a, -rs, -rt) == expected); -} - -int main() -{ - verify_madd(13, 17, 19, 336); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_maddu.c b/tests/tcg/mips/user/isa/r5900/test_r5900_maddu.c deleted file mode 100644 index 30936fb2b4a2..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_maddu.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Test R5900-specific three-operand MADDU and MADDU1. - */ - -#include -#include -#include - -uint64_t maddu(uint64_t a, uint32_t rs, uint32_t rt) -{ - uint32_t lo = a; - uint32_t hi = a >> 32; - uint32_t rd; - uint64_t r; - - __asm__ __volatile__ ( - " mtlo %5\n" - " mthi %6\n" - " maddu %0, %3, %4\n" - " mflo %1\n" - " mfhi %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt), "r" (lo), "r" (hi)); - r = ((uint64_t)hi << 32) | (uint32_t)lo; - - assert(a + (uint64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -uint64_t maddu1(uint64_t a, uint32_t rs, uint32_t rt) -{ - uint32_t lo = a; - uint32_t hi = a >> 32; - uint32_t rd; - uint64_t r; - - __asm__ __volatile__ ( - " mtlo1 %5\n" - " mthi1 %6\n" - " maddu1 %0, %3, %4\n" - " mflo1 %1\n" - " mfhi1 %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt), "r" (lo), "r" (hi)); - r = ((uint64_t)hi << 32) | (uint32_t)lo; - - assert(a + (uint64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -static int64_t maddu_variants(int64_t a, int32_t rs, int32_t rt) -{ - int64_t rd = maddu(a, rs, rt); - int64_t rd1 = maddu1(a, rs, rt); - - assert(rd == rd1); - - return rd; -} - -int main() -{ - assert(maddu_variants(13, 17, 19) == 336); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_mflohi1.c b/tests/tcg/mips/user/isa/r5900/test_r5900_mflohi1.c deleted file mode 100644 index eed3683dc5d4..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_mflohi1.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Test R5900-specific MFLO1 and MFHI1. - */ - -#include -#include -#include - -int main() -{ - int32_t rs = 12207031, rt = 305175781; - int32_t rs1 = 32452867, rt1 = 49979687; - int64_t lo, hi, lo1, hi1; - int64_t r, r1; - - /* Test both LO/HI and LO1/HI1 to verify separation. */ - __asm__ __volatile__ ( - " mult $0, %4, %5\n" - " mult1 $0, %6, %7\n" - " mflo %0\n" - " mfhi %1\n" - " mflo1 %2\n" - " mfhi1 %3\n" - : "=r" (lo), "=r" (hi), - "=r" (lo1), "=r" (hi1) - : "r" (rs), "r" (rt), - "r" (rs1), "r" (rt1)); - r = ((int64_t)hi << 32) | (uint32_t)lo; - r1 = ((int64_t)hi1 << 32) | (uint32_t)lo1; - - assert(r == 3725290219116211); - assert(r1 == 1621984134912629); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_mtlohi1.c b/tests/tcg/mips/user/isa/r5900/test_r5900_mtlohi1.c deleted file mode 100644 index 7f3e72835ae4..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_mtlohi1.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Test R5900-specific MTLO1 and MTHI1. - */ - -#include -#include -#include - -int main() -{ - int32_t tlo = 12207031, thi = 305175781; - int32_t tlo1 = 32452867, thi1 = 49979687; - int32_t flo, fhi, flo1, fhi1; - - /* Test both LO/HI and LO1/HI1 to verify separation. */ - __asm__ __volatile__ ( - " mtlo %4\n" - " mthi %5\n" - " mtlo1 %6\n" - " mthi1 %7\n" - " move %0, $0\n" - " move %1, $0\n" - " move %2, $0\n" - " move %3, $0\n" - " mflo %0\n" - " mfhi %1\n" - " mflo1 %2\n" - " mfhi1 %3\n" - : "=r" (flo), "=r" (fhi), - "=r" (flo1), "=r" (fhi1) - : "r" (tlo), "r" (thi), - "r" (tlo1), "r" (thi1)); - - assert(flo == 12207031); - assert(fhi == 305175781); - assert(flo1 == 32452867); - assert(fhi1 == 49979687); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_mult.c b/tests/tcg/mips/user/isa/r5900/test_r5900_mult.c deleted file mode 100644 index 5710b395e664..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_mult.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Test R5900-specific three-operand MULT and MULT1. - */ - -#include -#include -#include - -static int64_t mult(int32_t rs, int32_t rt) -{ - int32_t rd, lo, hi; - int64_t r; - - __asm__ __volatile__ ( - " mult %0, %3, %4\n" - " mflo %1\n" - " mfhi %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt)); - r = ((int64_t)hi << 32) | (uint32_t)lo; - - assert((int64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -static int64_t mult1(int32_t rs, int32_t rt) -{ - int32_t rd, lo, hi; - int64_t r; - - __asm__ __volatile__ ( - " mult1 %0, %3, %4\n" - " mflo1 %1\n" - " mfhi1 %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt)); - r = ((int64_t)hi << 32) | (uint32_t)lo; - - assert((int64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -static int64_t mult_variants(int32_t rs, int32_t rt) -{ - int64_t rd = mult(rs, rt); - int64_t rd1 = mult1(rs, rt); - - assert(rd == rd1); - - return rd; -} - -static void verify_mult_negations(int32_t rs, int32_t rt, int64_t expected) -{ - assert(mult_variants(rs, rt) == expected); - assert(mult_variants(-rs, rt) == -expected); - assert(mult_variants(rs, -rt) == -expected); - assert(mult_variants(-rs, -rt) == expected); -} - -int main() -{ - verify_mult_negations(17, 19, 323); - verify_mult_negations(77773, 99991, 7776600043); - verify_mult_negations(12207031, 305175781, 3725290219116211); - - assert(mult_variants(-0x80000000, 0x7FFFFFFF) == -0x3FFFFFFF80000000); - assert(mult_variants(-0x80000000, -0x7FFFFFFF) == 0x3FFFFFFF80000000); - assert(mult_variants(-0x80000000, -0x80000000) == 0x4000000000000000); - - return 0; -} diff --git a/tests/tcg/mips/user/isa/r5900/test_r5900_multu.c b/tests/tcg/mips/user/isa/r5900/test_r5900_multu.c deleted file mode 100644 index f043904d699d..000000000000 --- a/tests/tcg/mips/user/isa/r5900/test_r5900_multu.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Test R5900-specific three-operand MULTU and MULTU1. - */ - -#include -#include -#include - -static uint64_t multu(uint32_t rs, uint32_t rt) -{ - uint32_t rd, lo, hi; - uint64_t r; - - __asm__ __volatile__ ( - " multu %0, %3, %4\n" - " mflo %1\n" - " mfhi %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt)); - r = ((uint64_t)hi << 32) | (uint32_t)lo; - - assert((uint64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -static uint64_t multu1(uint32_t rs, uint32_t rt) -{ - uint32_t rd, lo, hi; - uint64_t r; - - __asm__ __volatile__ ( - " multu1 %0, %3, %4\n" - " mflo1 %1\n" - " mfhi1 %2\n" - : "=r" (rd), "=r" (lo), "=r" (hi) - : "r" (rs), "r" (rt)); - r = ((uint64_t)hi << 32) | (uint32_t)lo; - - assert((uint64_t)rs * rt == r); - assert(rd == lo); - - return r; -} - -static uint64_t multu_variants(uint32_t rs, uint32_t rt) -{ - uint64_t rd = multu(rs, rt); - uint64_t rd1 = multu1(rs, rt); - - assert(rd == rd1); - - return rd; -} - -int main() -{ - assert(multu_variants(17, 19) == 323); - assert(multu_variants(77773, 99991) == 7776600043); - assert(multu_variants(12207031, 305175781) == 3725290219116211); - - assert(multu_variants(0x80000000U, 0x7FFFFFFF) == 0x3FFFFFFF80000000); - assert(multu_variants(0x80000000U, 0x80000000U) == 0x4000000000000000); - assert(multu_variants(0xFFFFFFFFU, 0xFFFFFFFFU) == 0xFFFFFFFE00000001U); - - return 0; -} diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target deleted file mode 100644 index dec401e67fdd..000000000000 --- a/tests/tcg/multiarch/Makefile.target +++ /dev/null @@ -1,117 +0,0 @@ -# -*- Mode: makefile -*- -# -# Multiarch Tests - included from tests/tcg/Makefile.target -# -# These tests are plain C and built without any architecture specific code. -# - -MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch - -# Set search path for all sources -VPATH += $(MULTIARCH_SRC) -MULTIARCH_SRCS = $(notdir $(wildcard $(MULTIARCH_SRC)/*.c)) -ifneq ($(CONFIG_LINUX_USER),) -VPATH += $(MULTIARCH_SRC)/linux -MULTIARCH_SRCS += $(notdir $(wildcard $(MULTIARCH_SRC)/linux/*.c)) -endif -MULTIARCH_TESTS = $(MULTIARCH_SRCS:.c=) - -# -# The following are any additional rules needed to build things -# - - -float_%: LDFLAGS+=-lm -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 conditional-diff-out,$<,$(SRC_PATH)/tests/tcg/$(TARGET_NAME)/$<.ref) - - -testthread: LDFLAGS+=-lpthread - -threadcount: LDFLAGS+=-lpthread - -signals: LDFLAGS+=-lrt -lpthread - -# We define the runner for test-mmap after the individual -# architectures have defined their supported pages sizes. If no -# additional page sizes are defined we only run the default test. - -# default case (host page size) -run-test-mmap: test-mmap - $(call run-test, test-mmap, $(QEMU) $<, \ - "$< (default) on $(TARGET_NAME)") - -# 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)") - -ifneq ($(HAVE_GDB_BIN),) -GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py - -run-gdbstub-sha1: sha1 - $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ - --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ - --bin $< --test $(MULTIARCH_SRC)/gdbstub/sha1.py, \ - "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") - -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") - -else -run-gdbstub-%: - $(call skip-test, "gdbstub test $*", "need working gdb") -endif -EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \ - run-gdbstub-thread-breakpoint - -# ARM Compatible Semi Hosting Tests -# -# Despite having ARM in the name we actually have several -# architectures that implement it. We gate the tests on the feature -# appearing in config. -# -ifeq ($(CONFIG_ARM_COMPATIBLE_SEMIHOSTING),y) -VPATH += $(MULTIARCH_SRC)/arm-compat-semi - -# Add -I path back to TARGET_NAME for semicall.h -semihosting: CFLAGS+=-I$(SRC_PATH)/tests/tcg/$(TARGET_NAME) - -run-semihosting: semihosting - $(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)") - -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 $*") - -semiconsole: CFLAGS+=-I$(SRC_PATH)/tests/tcg/$(TARGET_NAME) - -run-semiconsole: semiconsole - $(call skip-test, $<, "MANUAL ONLY") - -run-plugin-semiconsole-with-%: - $(call skip-test, $<, "MANUAL ONLY") - -TESTS += semihosting semiconsole -endif - -# Update TESTS -TESTS += $(MULTIARCH_TESTS) diff --git a/tests/tcg/multiarch/README b/tests/tcg/multiarch/README deleted file mode 100644 index 522c9d2ea3e2..000000000000 --- a/tests/tcg/multiarch/README +++ /dev/null @@ -1 +0,0 @@ -Multi-architecture linux-user tests diff --git a/tests/tcg/multiarch/arm-compat-semi/semiconsole.c b/tests/tcg/multiarch/arm-compat-semi/semiconsole.c deleted file mode 100644 index 1d82efc589db..000000000000 --- a/tests/tcg/multiarch/arm-compat-semi/semiconsole.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * linux-user semihosting console - * - * Copyright (c) 2019 - * Written by Alex Bennée - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#define SYS_READC 0x07 - -#include -#include -#include "semicall.h" - -int main(void) -{ - char c; - - printf("Semihosting Console Test\n"); - printf("hit X to exit:"); - - do { - c = __semi_call(SYS_READC, 0); - printf("got '%c'\n", c); - } while (c != 'X'); - - return 0; -} diff --git a/tests/tcg/multiarch/arm-compat-semi/semihosting.c b/tests/tcg/multiarch/arm-compat-semi/semihosting.c deleted file mode 100644 index 8627eee3cf78..000000000000 --- a/tests/tcg/multiarch/arm-compat-semi/semihosting.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * linux-user semihosting checks - * - * Copyright (c) 2019 - * Written by Alex Bennée - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#define SYS_WRITE0 0x04 -#define SYS_HEAPINFO 0x16 -#define SYS_REPORTEXC 0x18 - -#include -#include -#include -#include -#include "semicall.h" - -int main(int argc, char *argv[argc]) -{ -#if UINTPTR_MAX == UINT32_MAX - uintptr_t exit_code = 0x20026; -#else - uintptr_t exit_block[2] = {0x20026, 0}; - uintptr_t exit_code = (uintptr_t) &exit_block; -#endif - struct { - void *heap_base; - void *heap_limit; - void *stack_base; - void *stack_limit; - } info; - void *ptr_to_info = (void *) &info; - - __semi_call(SYS_WRITE0, (uintptr_t) "Checking HeapInfo\n"); - - memset(&info, 0, sizeof(info)); - __semi_call(SYS_HEAPINFO, (uintptr_t) &ptr_to_info); - - if (info.heap_base == NULL || info.heap_limit == NULL) { - printf("null heap: %p -> %p\n", info.heap_base, info.heap_limit); - exit(1); - } - - /* Error if heap base is above limit */ - if ((uintptr_t) info.heap_base >= (uintptr_t) info.heap_limit) { - printf("heap base %p >= heap_limit %p\n", - info.heap_base, info.heap_limit); - exit(2); - } - - if (info.stack_base == NULL || info.stack_limit) { - printf("null stack: %p -> %p\n", info.stack_base, info.stack_limit); - exit(3); - } - - /* check our local variables are indeed inside the reported stack */ - if (ptr_to_info > info.stack_base) { - printf("info appears to be above stack: %p > %p\n", ptr_to_info, - info.stack_base); - exit(4); - } else if (ptr_to_info < info.stack_limit) { - printf("info appears to be outside stack: %p < %p\n", ptr_to_info, - info.stack_limit); - exit(5); - } - - if (ptr_to_info > info.heap_base && ptr_to_info < info.heap_limit) { - printf("info appears to be inside the heap: %p in %p:%p\n", - ptr_to_info, info.heap_base, info.heap_limit); - exit(6); - } - - printf("heap: %p -> %p\n", info.heap_base, info.heap_limit); - printf("stack: %p -> %p\n", info.stack_base, info.stack_limit); - - __semi_call(SYS_WRITE0, (uintptr_t) "Passed HeapInfo checks"); - __semi_call(SYS_REPORTEXC, exit_code); - /* if we get here we failed */ - return -1; -} diff --git a/tests/tcg/multiarch/float_convs.c b/tests/tcg/multiarch/float_convs.c deleted file mode 100644 index 2e4fa55324d7..000000000000 --- a/tests/tcg/multiarch/float_convs.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Floating Point Convert Single to Various - * - * Copyright (c) 2019 Linaro - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include -#include -#include -#include -#include - - -#include "float_helpers.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -typedef struct { - int flag; - char *desc; -} float_mapping; - -float_mapping round_flags[] = { - { FE_TONEAREST, "to nearest" }, -#ifdef FE_UPWARD - { FE_UPWARD, "upwards" }, -#endif -#ifdef FE_DOWNWARD - { FE_DOWNWARD, "downwards" }, -#endif -#ifdef FE_TOWARDZERO - { FE_TOWARDZERO, "to zero" } -#endif -}; - -static void print_input(float input) -{ - char *in_fmt = fmt_f32(input); - printf("from single: %s\n", in_fmt); - free(in_fmt); -} - -static void convert_single_to_double(float input) -{ - double output; - char *out_fmt, *flag_fmt; - - feclearexcept(FE_ALL_EXCEPT); - - output = input; - - flag_fmt = fmt_flags(); - out_fmt = fmt_f64(output); - printf(" to double: %s (%s)\n", out_fmt, flag_fmt); - free(out_fmt); - free(flag_fmt); -} - -#define xstr(a) str(a) -#define str(a) #a - -#define CONVERT_SINGLE_TO_INT(TYPE, FMT) \ - static void convert_single_to_ ## TYPE(float input) \ - { \ - TYPE ## _t output; \ - char *flag_fmt; \ - const char to[] = "to " xstr(TYPE); \ - feclearexcept(FE_ALL_EXCEPT); \ - output = input; \ - flag_fmt = fmt_flags(); \ - printf("%11s: %" FMT " (%s)\n", to, output, flag_fmt); \ - free(flag_fmt); \ - } - -CONVERT_SINGLE_TO_INT( int32, PRId32) -CONVERT_SINGLE_TO_INT(uint32, PRId32) -CONVERT_SINGLE_TO_INT( int64, PRId64) -CONVERT_SINGLE_TO_INT(uint64, PRId64) - -int main(int argc, char *argv[argc]) -{ - int i, j, nums; - - nums = get_num_f32(); - - for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { - if (fesetround(round_flags[i].flag) != 0) { - printf("### Rounding %s skipped\n", round_flags[i].desc); - continue; - } - printf("### Rounding %s\n", round_flags[i].desc); - for (j = 0; j < nums; j++) { - float input = get_f32(j); - print_input(input); - /* convert_single_to_half(input); */ - convert_single_to_double(input); - convert_single_to_int32(input); - convert_single_to_int64(input); - convert_single_to_uint32(input); - convert_single_to_uint64(input); - } - } - - return 0; -} diff --git a/tests/tcg/multiarch/float_helpers.h b/tests/tcg/multiarch/float_helpers.h deleted file mode 100644 index 309f3f4bf10d..000000000000 --- a/tests/tcg/multiarch/float_helpers.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Common Float Helpers - * - * Copyright (c) 2019 Linaro - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include - -/* Some hosts do not have support for all of these; not required by ISO C. */ -#ifndef FE_OVERFLOW -#define FE_OVERFLOW 0 -#endif -#ifndef FE_UNDERFLOW -#define FE_UNDERFLOW 0 -#endif -#ifndef FE_DIVBYZERO -#define FE_DIVBYZERO 0 -#endif -#ifndef FE_INEXACT -#define FE_INEXACT 0 -#endif -#ifndef FE_INVALID -#define FE_INVALID 0 -#endif - -/* Number of constants in each table */ -int get_num_f16(void); -int get_num_f32(void); -int get_num_f64(void); - -/* Accessor helpers, overflows will automatically wrap */ -uint16_t get_f16(int i); /* use _Float16 when we can */ -float get_f32(int i); -double get_f64(int i); - -/* Return format strings, free after use */ -char * fmt_f16(uint16_t); -char * fmt_f32(float); -char * fmt_f64(double); -/* exception flags */ -char * fmt_flags(void); diff --git a/tests/tcg/multiarch/float_madds.c b/tests/tcg/multiarch/float_madds.c deleted file mode 100644 index 4888f8641f42..000000000000 --- a/tests/tcg/multiarch/float_madds.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Fused Multiply Add (Single) - * - * Copyright (c) 2019 Linaro - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include -#include -#include -#include -#include - -#include "float_helpers.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -typedef struct { - int flag; - char *desc; -} float_mapping; - -float_mapping round_flags[] = { - { FE_TONEAREST, "to nearest" }, -#ifdef FE_UPWARD - { FE_UPWARD, "upwards" }, -#endif -#ifdef FE_DOWNWARD - { FE_DOWNWARD, "downwards" }, -#endif -#ifdef FE_TOWARDZERO - { FE_TOWARDZERO, "to zero" } -#endif -}; - - -static void print_inputs(float a, float b, float c) -{ - char *a_fmt, *b_fmt, *c_fmt; - - a_fmt = fmt_f32(a); - b_fmt = fmt_f32(b); - c_fmt = fmt_f32(c); - - printf("op : %s * %s + %s\n", a_fmt, b_fmt, c_fmt); - - free(a_fmt); - free(b_fmt); - free(c_fmt); -} - -static void print_result(float r, int j, int k) -{ - char *r_fmt, *flag_fmt; - - flag_fmt = fmt_flags(); - r_fmt = fmt_f32(r); - - printf("res: %s flags=%s (%d/%d)\n", r_fmt, flag_fmt, j, k); - - free(r_fmt); - free(flag_fmt); -} - -static void do_madds(float a, float b, float c, int j, int k) -{ - float r; - - print_inputs(a, b, c); - - feclearexcept(FE_ALL_EXCEPT); - r = __builtin_fmaf(a, b, c); - - print_result(r, j, k); -} - -int main(int argc, char *argv[argc]) -{ - int i, j, k, nums = get_num_f32(); - float a, b, c; - - for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { - if (fesetround(round_flags[i].flag) != 0) { - printf("### Rounding %s skipped\n", round_flags[i].desc); - continue; - } - printf("### Rounding %s\n", round_flags[i].desc); - for (j = 0; j < nums; j++) { - for (k = 0; k < 3; k++) { - a = get_f32(j + ((k)%3)); - b = get_f32(j + ((k+1)%3)); - c = get_f32(j + ((k+2)%3)); - do_madds(a, b, c, j, k); - } - } - - /* From https://bugs.launchpad.net/qemu/+bug/1841491 */ - printf("# LP184149\n"); - do_madds(0x1.ffffffffffffcp-1022, 0x1.0000000000001p-1, 0x0.0000000000001p-1022, j, 0); - do_madds(0x8p-152, 0x8p-152, 0x8p-152, j+1, 0); - } - - return 0; -} diff --git a/tests/tcg/multiarch/gdbstub/memory.py b/tests/tcg/multiarch/gdbstub/memory.py deleted file mode 100644 index 67864ad9029b..000000000000 --- a/tests/tcg/multiarch/gdbstub/memory.py +++ /dev/null @@ -1,130 +0,0 @@ -from __future__ import print_function -# -# Test some of the softmmu debug features with the multiarch memory -# test. It is a port of the original vmlinux focused test case but -# using the "memory" test instead. -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -failcount = 0 - - -def report(cond, msg): - "Report success/fail of test" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 - - -def check_step(): - "Step an instruction, check it moved." - start_pc = gdb.parse_and_eval('$pc') - gdb.execute("si") - end_pc = gdb.parse_and_eval('$pc') - - return not (start_pc == end_pc) - - -# -# Currently it's hard to create a hbreak with the pure python API and -# manually matching PC to symbol address is a bit flaky thanks to -# function prologues. However internally QEMU's gdbstub treats them -# the same as normal breakpoints so it will do for now. -# -def check_break(sym_name): - "Setup breakpoint, continue and check we stopped." - sym, ok = gdb.lookup_symbol(sym_name) - bp = gdb.Breakpoint(sym_name, gdb.BP_BREAKPOINT) - - gdb.execute("c") - - # hopefully we came back - end_pc = gdb.parse_and_eval('$pc') - report(bp.hit_count == 1, - "break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count)) - - bp.delete() - - -def do_one_watch(sym, wtype, text): - - wp = gdb.Breakpoint(sym, gdb.BP_WATCHPOINT, wtype) - gdb.execute("c") - report_str = "%s for %s" % (text, sym) - - if wp.hit_count > 0: - report(True, report_str) - wp.delete() - else: - report(False, report_str) - - -def check_watches(sym_name): - "Watch a symbol for any access." - - # Should hit for any read - do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") - - # Again should hit for reads - do_one_watch(sym_name, gdb.WP_READ, "rwatch") - - # Finally when it is written - do_one_watch(sym_name, gdb.WP_WRITE, "watch") - - -def run_test(): - "Run through the tests one by one" - - print("Checking we can step the first few instructions") - step_ok = 0 - for i in range(3): - if check_step(): - step_ok += 1 - - report(step_ok == 3, "single step in boot code") - - # If we get here we have missed some of the other breakpoints. - print("Setup catch-all for _exit") - cbp = gdb.Breakpoint("_exit", gdb.BP_BREAKPOINT) - - check_break("main") - check_watches("test_data[128]") - - report(cbp.hit_count == 0, "didn't reach backstop") - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - - # Run the actual tests - run_test() -except (gdb.error): - print("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -# Finally kill the inferior and exit gdb with a count of failures -gdb.execute("kill") -exit(failcount) diff --git a/tests/tcg/multiarch/gdbstub/sha1.py b/tests/tcg/multiarch/gdbstub/sha1.py deleted file mode 100644 index 423b720e6da8..000000000000 --- a/tests/tcg/multiarch/gdbstub/sha1.py +++ /dev/null @@ -1,88 +0,0 @@ -from __future__ import print_function -# -# A very simple smoke test for debugging the SHA1 userspace test on -# each target. -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -initial_vlen = 0 -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 - -def check_break(sym_name): - "Setup breakpoint, continue and check we stopped." - sym, ok = gdb.lookup_symbol(sym_name) - bp = gdb.Breakpoint(sym_name) - - gdb.execute("c") - - # hopefully we came back - end_pc = gdb.parse_and_eval('$pc') - report(bp.hit_count == 1, - "break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count)) - - bp.delete() - -def run_test(): - "Run through the tests one by one" - - check_break("SHA1Init") - - # Check step and inspect values. We do a double next after the - # breakpoint as depending on the version of gdb we may step the - # preamble and not the first actual line of source. - gdb.execute("next") - gdb.execute("next") - val_ctx = gdb.parse_and_eval("context->state[0]") - exp_ctx = 0x67452301 - report(int(val_ctx) == exp_ctx, "context->state[0] == %x" % exp_ctx); - - gdb.execute("next") - val_ctx = gdb.parse_and_eval("context->state[1]") - exp_ctx = 0xEFCDAB89 - report(int(val_ctx) == exp_ctx, "context->state[1] == %x" % exp_ctx); - - # finally check we don't barf inspecting registers - gdb.execute("info registers") - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - - # Run the actual tests - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) diff --git a/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py b/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py deleted file mode 100644 index d91e8fdf19ab..000000000000 --- a/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import print_function -# -# Test auxiliary vector is loaded via gdbstub -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 - -def run_test(): - "Run through the tests one by one" - - auxv = gdb.execute("info auxv", False, True) - report(isinstance(auxv, str), "Fetched auxv from inferior") - report(auxv.find("sha1"), "Found test binary name in auxv") - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - - # Run the actual tests - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) diff --git a/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py b/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py deleted file mode 100644 index 798d508bc70a..000000000000 --- a/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import print_function -# -# Test auxiliary vector is loaded via gdbstub -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -failcount = 0 - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 - -def run_test(): - "Run through the tests one by one" - - sym, ok = gdb.lookup_symbol("thread1_func") - gdb.execute("b thread1_func") - gdb.execute("c") - - frame = gdb.selected_frame() - report(str(frame.function()) == "thread1_func", "break @ %s"%frame) - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval('$pc') == 0: - print("SKIP: PC not set") - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - - # Run the actual tests - run_test() -except (gdb.error): - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) diff --git a/tests/tcg/multiarch/libs/float_helpers.c b/tests/tcg/multiarch/libs/float_helpers.c deleted file mode 100644 index 4e68d2b65983..000000000000 --- a/tests/tcg/multiarch/libs/float_helpers.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Common Float Helpers - * - * This contains a series of useful utility routines and a set of - * floating point constants useful for exercising the edge cases in - * floating point tests. - * - * Copyright (c) 2019 Linaro - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -/* we want additional float type definitions */ -#define __STDC_WANT_IEC_60559_BFP_EXT__ -#define __STDC_WANT_IEC_60559_TYPES_EXT__ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include - -#include "../float_helpers.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -/* - * Half Precision Numbers - * - * Not yet well standardised so we return a plain uint16_t for now. - */ - -/* no handy defines for these numbers */ -static uint16_t f16_numbers[] = { - 0xffff, /* -NaN / AHP -Max */ - 0xfcff, /* -NaN / AHP */ - 0xfc01, /* -NaN / AHP */ - 0xfc00, /* -Inf */ - 0xfbff, /* -Max */ - 0xc000, /* -2 */ - 0xbc00, /* -1 */ - 0x8001, /* -MIN subnormal */ - 0x8000, /* -0 */ - 0x0000, /* +0 */ - 0x0001, /* MIN subnormal */ - 0x3c00, /* 1 */ - 0x7bff, /* Max */ - 0x7c00, /* Inf */ - 0x7c01, /* NaN / AHP */ - 0x7cff, /* NaN / AHP */ - 0x7fff, /* NaN / AHP +Max*/ -}; - -static const int num_f16 = ARRAY_SIZE(f16_numbers); - -int get_num_f16(void) -{ - return num_f16; -} - -uint16_t get_f16(int i) -{ - return f16_numbers[i % num_f16]; -} - -/* only display as hex */ -char *fmt_16(uint16_t num) -{ - char *fmt; - asprintf(&fmt, "f16(%#04x)", num); - return fmt; -} - -/* - * Single Precision Numbers - */ - -#ifndef SNANF -/* Signaling NaN macros, if supported. */ -# define SNANF (__builtin_nansf ("")) -# define SNAN (__builtin_nans ("")) -# define SNANL (__builtin_nansl ("")) -#endif - -static float f32_numbers[] = { - -SNANF, - -NAN, - -INFINITY, - -FLT_MAX, - -0x1.1874b2p+103, - -0x1.c0bab6p+99, - -0x1.31f75p-40, - -0x1.505444p-66, - -FLT_MIN, - 0.0, - FLT_MIN, - 0x1p-25, - 0x1.ffffe6p-25, /* min positive FP16 subnormal */ - 0x1.ff801ap-15, /* max subnormal FP16 */ - 0x1.00000cp-14, /* min positive normal FP16 */ - 1.0, - 0x1.004p+0, /* smallest float after 1.0 FP16 */ - 2.0, - M_E, M_PI, - 0x1.ffbep+15, - 0x1.ffcp+15, /* max FP16 */ - 0x1.ffc2p+15, - 0x1.ffbfp+16, - 0x1.ffcp+16, /* max AFP */ - 0x1.ffc1p+16, - 0x1.c0bab6p+99, - FLT_MAX, - INFINITY, - NAN, - SNANF -}; - -static const int num_f32 = ARRAY_SIZE(f32_numbers); - -int get_num_f32(void) -{ - return num_f32; -} - -float get_f32(int i) -{ - return f32_numbers[i % num_f32]; -} - -char *fmt_f32(float num) -{ - uint32_t single_as_hex = *(uint32_t *) # - char *fmt; - asprintf(&fmt, "f32(%02.20a:%#010x)", num, single_as_hex); - return fmt; -} - - -/* This allows us to initialise some doubles as pure hex */ -typedef union { - double d; - uint64_t h; -} test_doubles; - -static test_doubles f64_numbers[] = { - {SNAN}, - {-NAN}, - {-INFINITY}, - {-DBL_MAX}, - {-FLT_MAX-1.0}, - {-FLT_MAX}, - {-1.111E+31}, - {-1.111E+30}, /* half prec */ - {-2.0}, {-1.0}, - {-DBL_MIN}, - {-FLT_MIN}, - {0.0}, - {FLT_MIN}, - {2.98023224e-08}, - {5.96046E-8}, /* min positive FP16 subnormal */ - {6.09756E-5}, /* max subnormal FP16 */ - {6.10352E-5}, /* min positive normal FP16 */ - {1.0}, - {1.0009765625}, /* smallest float after 1.0 FP16 */ - {DBL_MIN}, - {1.3789972848607228e-308}, - {1.4914738736681624e-308}, - {1.0}, {2.0}, - {M_E}, {M_PI}, - {65503.0}, - {65504.0}, /* max FP16 */ - {65505.0}, - {131007.0}, - {131008.0}, /* max AFP */ - {131009.0}, - {.h = 0x41dfffffffc00000 }, /* to int = 0x7fffffff */ - {FLT_MAX}, - {FLT_MAX + 1.0}, - {DBL_MAX}, - {INFINITY}, - {NAN}, - {.h = 0x7ff0000000000001}, /* SNAN */ - {SNAN}, -}; - -static const int num_f64 = ARRAY_SIZE(f64_numbers); - -int get_num_f64(void) -{ - return num_f64; -} - -double get_f64(int i) -{ - return f64_numbers[i % num_f64].d; -} - -char *fmt_f64(double num) -{ - uint64_t double_as_hex = *(uint64_t *) # - char *fmt; - asprintf(&fmt, "f64(%02.20a:%#020" PRIx64 ")", num, double_as_hex); - return fmt; -} - -/* - * Float flags - */ -char *fmt_flags(void) -{ - int flags = fetestexcept(FE_ALL_EXCEPT); - char *fmt; - - if (flags) { - asprintf(&fmt, "%s%s%s%s%s", - flags & FE_OVERFLOW ? "OVERFLOW " : "", - flags & FE_UNDERFLOW ? "UNDERFLOW " : "", - flags & FE_DIVBYZERO ? "DIV0 " : "", - flags & FE_INEXACT ? "INEXACT " : "", - flags & FE_INVALID ? "INVALID" : ""); - } else { - asprintf(&fmt, "OK"); - } - - return fmt; -} diff --git a/tests/tcg/multiarch/linux/linux-test.c b/tests/tcg/multiarch/linux/linux-test.c deleted file mode 100644 index 019d8175ca63..000000000000 --- a/tests/tcg/multiarch/linux/linux-test.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * linux and CPU test - * - * Copyright (c) 2003 Fabrice Bellard - * - * 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 . - */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STACK_SIZE 16384 - -static void error1(const char *filename, int line, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", filename, line); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(1); -} - -static int __chk_error(const char *filename, int line, int ret) -{ - if (ret < 0) { - error1(filename, line, "%m (ret=%d, errno=%d/%s)", - ret, errno, strerror(errno)); - } - return ret; -} - -#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) - -#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) - -/*******************************************************/ - -#define FILE_BUF_SIZE 300 - -static void test_file(void) -{ - int fd, i, len, ret; - uint8_t buf[FILE_BUF_SIZE]; - uint8_t buf2[FILE_BUF_SIZE]; - uint8_t buf3[FILE_BUF_SIZE]; - char cur_dir[1024]; - struct stat st; - struct utimbuf tbuf; - struct iovec vecs[2]; - DIR *dir; - struct dirent64 *de; - /* TODO: make common tempdir creation for tcg tests */ - char template[] = "/tmp/linux-test-XXXXXX"; - char *tmpdir = mkdtemp(template); - - assert(tmpdir); - - if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) - error("getcwd"); - - chk_error(chdir(tmpdir)); - - /* open/read/write/close/readv/writev/lseek */ - - fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); - for(i=0;i < FILE_BUF_SIZE; i++) - buf[i] = i; - len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2)); - if (len != (FILE_BUF_SIZE / 2)) - error("write"); - vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2); - vecs[0].iov_len = 16; - vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16; - vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16; - len = chk_error(writev(fd, vecs, 2)); - if (len != (FILE_BUF_SIZE / 2)) - error("writev"); - chk_error(close(fd)); - - chk_error(rename("file1", "file2")); - - fd = chk_error(open("file2", O_RDONLY)); - - len = chk_error(read(fd, buf2, FILE_BUF_SIZE)); - if (len != FILE_BUF_SIZE) - error("read"); - if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) - error("memcmp"); - -#define FOFFSET 16 - ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); - if (ret != 16) - error("lseek"); - vecs[0].iov_base = buf3; - vecs[0].iov_len = 32; - vecs[1].iov_base = buf3 + 32; - vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32; - len = chk_error(readv(fd, vecs, 2)); - if (len != FILE_BUF_SIZE - FOFFSET) - error("readv"); - if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) - error("memcmp"); - - chk_error(close(fd)); - - /* access */ - chk_error(access("file2", R_OK)); - - /* stat/chmod/utime/truncate */ - - chk_error(chmod("file2", 0600)); - tbuf.actime = 1001; - tbuf.modtime = 1000; - chk_error(truncate("file2", 100)); - chk_error(utime("file2", &tbuf)); - chk_error(stat("file2", &st)); - if (st.st_size != 100) - error("stat size"); - if (!S_ISREG(st.st_mode)) - error("stat mode"); - if ((st.st_mode & 0777) != 0600) - error("stat mode2"); - if (st.st_atime != 1001 || - st.st_mtime != 1000) - error("stat time"); - - chk_error(stat(tmpdir, &st)); - if (!S_ISDIR(st.st_mode)) - error("stat mode"); - - /* fstat */ - fd = chk_error(open("file2", O_RDWR)); - chk_error(ftruncate(fd, 50)); - chk_error(fstat(fd, &st)); - chk_error(close(fd)); - - if (st.st_size != 50) - error("stat size"); - if (!S_ISREG(st.st_mode)) - error("stat mode"); - - /* symlink/lstat */ - chk_error(symlink("file2", "file3")); - chk_error(lstat("file3", &st)); - if (!S_ISLNK(st.st_mode)) - error("stat mode"); - - /* getdents */ - dir = opendir(tmpdir); - if (!dir) - error("opendir"); - len = 0; - for(;;) { - de = readdir64(dir); - if (!de) - break; - if (strcmp(de->d_name, ".") != 0 && - strcmp(de->d_name, "..") != 0 && - strcmp(de->d_name, "file2") != 0 && - strcmp(de->d_name, "file3") != 0) - error("readdir"); - len++; - } - closedir(dir); - if (len != 4) - error("readdir"); - - chk_error(unlink("file3")); - chk_error(unlink("file2")); - chk_error(chdir(cur_dir)); - chk_error(rmdir(tmpdir)); -} - -static void test_fork(void) -{ - int pid, status; - - pid = chk_error(fork()); - if (pid == 0) { - /* child */ - sleep(2); - exit(2); - } - chk_error(waitpid(pid, &status, 0)); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 2) - error("waitpid status=0x%x", status); -} - -static void test_time(void) -{ - struct timeval tv, tv2; - struct timespec ts, rem; - struct rusage rusg1, rusg2; - int ti, i; - - chk_error(gettimeofday(&tv, NULL)); - rem.tv_sec = 1; - ts.tv_sec = 0; - ts.tv_nsec = 20 * 1000000; - chk_error(nanosleep(&ts, &rem)); - if (rem.tv_sec != 1) - error("nanosleep"); - chk_error(gettimeofday(&tv2, NULL)); - ti = tv2.tv_sec - tv.tv_sec; - if (ti >= 2) - error("gettimeofday"); - - chk_error(getrusage(RUSAGE_SELF, &rusg1)); - for(i = 0;i < 10000; i++); - chk_error(getrusage(RUSAGE_SELF, &rusg2)); - if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 || - (rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0) - error("getrusage"); -} - -static int server_socket(void) -{ - int val, fd; - struct sockaddr_in sockaddr = {}; - - /* server socket */ - fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); - - val = 1; - chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))); - - sockaddr.sin_family = AF_INET; - 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)); - return fd; - -} - -static int client_socket(uint16_t port) -{ - int fd; - struct sockaddr_in sockaddr = {}; - - /* server socket */ - fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - inet_aton("127.0.0.1", &sockaddr.sin_addr); - chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); - return fd; -} - -static const char socket_msg[] = "hello socket\n"; - -static void test_socket(void) -{ - int server_fd, client_fd, fd, pid, ret, val; - struct sockaddr_in sockaddr; - struct sockaddr_in server_addr; - socklen_t len, socklen; - uint16_t server_port; - char buf[512]; - - server_fd = server_socket(); - /* find out what port we got */ - socklen = sizeof(server_addr); - ret = getsockname(server_fd, (struct sockaddr *)&server_addr, &socklen); - chk_error(ret); - server_port = ntohs(server_addr.sin_port); - - /* test a few socket options */ - len = sizeof(val); - chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len)); - if (val != SOCK_STREAM) - error("getsockopt"); - - pid = chk_error(fork()); - if (pid == 0) { - client_fd = client_socket(server_port); - send(client_fd, socket_msg, sizeof(socket_msg), 0); - close(client_fd); - exit(0); - } - len = sizeof(sockaddr); - fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len)); - - ret = chk_error(recv(fd, buf, sizeof(buf), 0)); - if (ret != sizeof(socket_msg)) - error("recv"); - if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0) - error("socket_msg"); - chk_error(close(fd)); - chk_error(close(server_fd)); -} - -#define WCOUNT_MAX 512 - -static void test_pipe(void) -{ - fd_set rfds, wfds; - int fds[2], fd_max, ret; - uint8_t ch; - int wcount, rcount; - - chk_error(pipe(fds)); - chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK)); - chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK)); - wcount = 0; - rcount = 0; - for(;;) { - FD_ZERO(&rfds); - fd_max = fds[0]; - FD_SET(fds[0], &rfds); - - FD_ZERO(&wfds); - FD_SET(fds[1], &wfds); - if (fds[1] > fd_max) - fd_max = fds[1]; - - ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL)); - if (ret > 0) { - if (FD_ISSET(fds[0], &rfds)) { - chk_error(read(fds[0], &ch, 1)); - rcount++; - if (rcount >= WCOUNT_MAX) - break; - } - if (FD_ISSET(fds[1], &wfds)) { - ch = 'a'; - chk_error(write(fds[1], &ch, 1)); - wcount++; - } - } - } - chk_error(close(fds[0])); - chk_error(close(fds[1])); -} - -static int thread1_res; -static int thread2_res; - -static int thread1_func(void *arg) -{ - int i; - for(i=0;i<5;i++) { - thread1_res++; - usleep(10 * 1000); - } - return 0; -} - -static int thread2_func(void *arg) -{ - int i; - for(i=0;i<6;i++) { - thread2_res++; - usleep(10 * 1000); - } - return 0; -} - -static void wait_for_child(pid_t pid) -{ - int status; - chk_error(waitpid(pid, &status, 0)); -} - -/* For test_clone we must match the clone flags used by glibc, see - * CLONE_THREAD_FLAGS in the QEMU source code. - */ -static void test_clone(void) -{ - uint8_t *stack1, *stack2; - pid_t pid1, pid2; - - stack1 = malloc(STACK_SIZE); - pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | - CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM, - "hello1")); - - stack2 = malloc(STACK_SIZE); - pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | - CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM, - "hello2")); - - wait_for_child(pid1); - free(stack1); - wait_for_child(pid2); - free(stack2); - - if (thread1_res != 5 || - thread2_res != 6) - error("clone"); -} - -/***********************************/ - -volatile int alarm_count; -jmp_buf jmp_env; - -static void sig_alarm(int sig) -{ - if (sig != SIGALRM) - error("signal"); - alarm_count++; -} - -static void sig_segv(int sig, siginfo_t *info, void *puc) -{ - if (sig != SIGSEGV) - error("signal"); - longjmp(jmp_env, 1); -} - -static void test_signal(void) -{ - struct sigaction act; - struct itimerval it, oit; - - /* timer test */ - - alarm_count = 0; - - act.sa_handler = sig_alarm; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - chk_error(sigaction(SIGALRM, &act, NULL)); - - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = 10 * 1000; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 10 * 1000; - chk_error(setitimer(ITIMER_REAL, &it, NULL)); - chk_error(getitimer(ITIMER_REAL, &oit)); - - while (alarm_count < 5) { - usleep(10 * 1000); - getitimer(ITIMER_REAL, &oit); - } - - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = 0; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - memset(&oit, 0xff, sizeof(oit)); - chk_error(setitimer(ITIMER_REAL, &it, &oit)); - - /* SIGSEGV test */ - act.sa_sigaction = sig_segv; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - chk_error(sigaction(SIGSEGV, &act, NULL)); - if (setjmp(jmp_env) == 0) { - /* - * clang requires volatile or it will turn this into a - * call to abort() instead of forcing a SIGSEGV. - */ - *(volatile uint8_t *)0 = 0; - } - - act.sa_handler = SIG_DFL; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - chk_error(sigaction(SIGSEGV, &act, NULL)); - - if (sigaction(SIGKILL, &act, NULL) == 0) { - error("sigaction(SIGKILL, &act, NULL) must not succeed"); - } - if (sigaction(SIGSTOP, &act, NULL) == 0) { - error("sigaction(SIGSTOP, &act, NULL) must not succeed"); - } - chk_error(sigaction(SIGKILL, NULL, &act)); - chk_error(sigaction(SIGSTOP, NULL, &act)); -} - -#define SHM_SIZE 32768 - -static void test_shm(void) -{ - void *ptr; - int shmid; - - shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777)); - ptr = shmat(shmid, NULL, 0); - if (ptr == (void *)-1) { - error("shmat"); - } - - memset(ptr, 0, SHM_SIZE); - - chk_error(shmctl(shmid, IPC_RMID, 0)); - chk_error(shmdt(ptr)); -} - -int main(int argc, char **argv) -{ - test_file(); - test_pipe(); - test_fork(); - test_time(); - test_socket(); - - if (argc > 1) { - printf("test_clone still considered buggy\n"); - test_clone(); - } - - test_signal(); - test_shm(); - return 0; -} diff --git a/tests/tcg/multiarch/sha1.c b/tests/tcg/multiarch/sha1.c deleted file mode 100644 index 0081bd765776..000000000000 --- a/tests/tcg/multiarch/sha1.c +++ /dev/null @@ -1,239 +0,0 @@ - -/* from valgrind tests */ - -/* ================ sha1.c ================ */ -/* -SHA-1 in C -By Steve Reid -100% Public Domain - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#define SHA1HANDSOFF - -#include -#include -#include - -/* ================ sha1.h ================ */ -/* -SHA-1 in C -By Steve Reid -100% Public Domain -*/ - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); -void SHA1Final(unsigned char digest[20], SHA1_CTX* context); -/* ================ end of sha1.h ================ */ - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#elif BYTE_ORDER == BIG_ENDIAN -#define blk0(i) block->l[i] -#else -#error "Endianness not defined!" -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) -{ -uint32_t a, b, c, d, e; -typedef union { - unsigned char c[64]; - uint32_t l[16]; -} CHAR64LONG16; -#ifdef SHA1HANDSOFF -CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - memcpy(block, buffer, 64); -#else - /* The following had better never be used because it causes the - * pointer-to-const buffer to be cast into a pointer to non-const. - * And the result is written through. I threw a "const" in, hoping - * this will cause a diagnostic. - */ -CHAR64LONG16* block = (const CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - memset(block, '\0', sizeof(block)); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len) -{ -uint32_t i; -uint32_t j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len>>29); - j = (j >> 3) & 63; - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ -unsigned i; -unsigned char finalcount[8]; -unsigned char c; - -#if 0 /* untested "improvement" by DHR */ - /* Convert context->count to a sequence of bytes - * in finalcount. Second element first, but - * big-endian order within element. - * But we do it all backwards. - */ - unsigned char *fcp = &finalcount[8]; - - for (i = 0; i < 2; i++) - { - uint32_t t = context->count[i]; - int j; - - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char) t; - } -#else - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } -#endif - c = 0200; - SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) { - c = 0000; - SHA1Update(context, &c, 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} -/* ================ end of sha1.c ================ */ - -#define BUFSIZE 4096 - -int -main(int argc, char **argv) -{ - SHA1_CTX ctx; - unsigned char hash[20], buf[BUFSIZE]; - int i; - - for(i=0;i -#include -#include -#include -#include -#include - -/* Required portions from endian.h */ - -/** - * BSWAP_64 - reverse bytes in a constant uint64_t value. - * @val: constantvalue whose bytes to swap. - * - * Designed to be usable in constant-requiring initializers. - * - * Example: - * struct mystruct { - * char buf[BSWAP_64(0xff00000000000000ULL)]; - * }; - */ -#define BSWAP_64(val) \ - ((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \ - | (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \ - | (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \ - | (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \ - | (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \ - | (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \ - | (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \ - | (((uint64_t)(val) & 0xff00000000000000ULL) >> 56)) - - -typedef uint64_t beint64_t; - -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - -/** - * CPU_TO_BE64 - convert a constant uint64_t value to big-endian - * @native: constant to convert - */ -#define CPU_TO_BE64(native) ((beint64_t)(native)) -/** - * BE64_TO_CPU - convert a big-endian uint64_t constant - * @le_val: big-endian constant to convert - */ -#define BE64_TO_CPU(le_val) ((uint64_t)(le_val)) - -#else /* ... HAVE_LITTLE_ENDIAN */ -#define CPU_TO_BE64(native) ((beint64_t)BSWAP_64(native)) -#define BE64_TO_CPU(le_val) BSWAP_64((uint64_t)le_val) -#endif /* HAVE_LITTE_ENDIAN */ - -/** - * cpu_to_be64 - convert a uint64_t value to big endian. - * @native: value to convert - */ -static inline beint64_t cpu_to_be64(uint64_t native) -{ - return CPU_TO_BE64(native); -} - -/** - * be64_to_cpu - convert a big-endian uint64_t value - * @be_val: big-endian value to convert - */ -static inline uint64_t be64_to_cpu(beint64_t be_val) -{ - return BE64_TO_CPU(be_val); -} - -/* From compiler.h */ - -#ifndef UNUSED -/** - * UNUSED - a parameter is unused - * - * Some compilers (eg. gcc with -W or -Wunused) warn about unused - * function parameters. This suppresses such warnings and indicates - * to the reader that it's deliberate. - * - * Example: - * // This is used as a callback, so needs to have this prototype. - * static int some_callback(void *unused UNUSED) - * { - * return 0; - * } - */ -#define UNUSED __attribute__((__unused__)) -#endif - -/* From sha512.h */ - -/** - * struct sha512 - structure representing a completed SHA512. - * @u.u8: an unsigned char array. - * @u.u64: a 64-bit integer array. - * - * Other fields may be added to the union in future. - */ -struct sha512 { - union { - uint64_t u64[8]; - unsigned char u8[64]; - } u; -}; - -/** - * sha512 - return sha512 of an object. - * @sha512: the sha512 to fill in - * @p: pointer to memory, - * @size: the number of bytes pointed to by @p - * - * The bytes pointed to by @p is SHA512 hashed into @sha512. This is - * equivalent to sha512_init(), sha512_update() then sha512_done(). - */ -void sha512(struct sha512 *sha, const void *p, size_t size); - -/** - * struct sha512_ctx - structure to store running context for sha512 - */ -struct sha512_ctx { - uint64_t s[8]; - union { - uint64_t u64[16]; - unsigned char u8[128]; - } buf; - size_t bytes; -}; - -/** - * sha512_init - initialize an SHA512 context. - * @ctx: the sha512_ctx to initialize - * - * This must be called before sha512_update or sha512_done, or - * alternately you can assign SHA512_INIT. - * - * If it was already initialized, this forgets anything which was - * hashed before. - * - * Example: - * static void hash_all(const char **arr, struct sha512 *hash) - * { - * size_t i; - * struct sha512_ctx ctx; - * - * sha512_init(&ctx); - * for (i = 0; arr[i]; i++) - * sha512_update(&ctx, arr[i], strlen(arr[i])); - * sha512_done(&ctx, hash); - * } - */ -void sha512_init(struct sha512_ctx *ctx); - -/** - * SHA512_INIT - initializer for an SHA512 context. - * - * This can be used to statically initialize an SHA512 context (instead - * of sha512_init()). - * - * Example: - * static void hash_all(const char **arr, struct sha512 *hash) - * { - * size_t i; - * struct sha512_ctx ctx = SHA512_INIT; - * - * for (i = 0; arr[i]; i++) - * sha512_update(&ctx, arr[i], strlen(arr[i])); - * sha512_done(&ctx, hash); - * } - */ -#define SHA512_INIT \ - { { 0x6a09e667f3bcc908ull, 0xbb67ae8584caa73bull, \ - 0x3c6ef372fe94f82bull, 0xa54ff53a5f1d36f1ull, \ - 0x510e527fade682d1ull, 0x9b05688c2b3e6c1full, \ - 0x1f83d9abfb41bd6bull, 0x5be0cd19137e2179ull }, \ - { { 0 } }, 0 } - -/** - * sha512_update - include some memory in the hash. - * @ctx: the sha512_ctx to use - * @p: pointer to memory, - * @size: the number of bytes pointed to by @p - * - * You can call this multiple times to hash more data, before calling - * sha512_done(). - */ -void sha512_update(struct sha512_ctx *ctx, const void *p, size_t size); - -/** - * sha512_done - finish SHA512 and return the hash - * @ctx: the sha512_ctx to complete - * @res: the hash to return. - * - * Note that @ctx is *destroyed* by this, and must be reinitialized. - * To avoid that, pass a copy instead. - */ -void sha512_done(struct sha512_ctx *sha512, struct sha512 *res); - -/* From sha512.c */ - -/* - * SHA512 core code translated from the Bitcoin project's C++: - * - * src/crypto/sha512.cpp commit f914f1a746d7f91951c1da262a4a749dd3ebfa71 - * Copyright (c) 2014 The Bitcoin Core developers - * Distributed under the MIT software license, see the accompanying - * file COPYING or http://www.opensource.org/licenses/mit-license.php. - */ -/* #include */ -/* #include */ -#include -#include -#include - -static void invalidate_sha512(struct sha512_ctx *ctx) -{ - ctx->bytes = (size_t)-1; -} - -static void check_sha512(struct sha512_ctx *ctx UNUSED) -{ - assert(ctx->bytes != (size_t)-1); -} - -static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z) -{ - return z ^ (x & (y ^ z)); -} -static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z) -{ - return (x & y) | (z & (x | y)); -} -static uint64_t Sigma0(uint64_t x) -{ - return (x >> 28 | x << 36) ^ (x >> 34 | x << 30) ^ (x >> 39 | x << 25); -} -static uint64_t Sigma1(uint64_t x) -{ - return (x >> 14 | x << 50) ^ (x >> 18 | x << 46) ^ (x >> 41 | x << 23); -} -static uint64_t sigma0(uint64_t x) -{ - return (x >> 1 | x << 63) ^ (x >> 8 | x << 56) ^ (x >> 7); -} -static uint64_t sigma1(uint64_t x) -{ - return (x >> 19 | x << 45) ^ (x >> 61 | x << 3) ^ (x >> 6); -} - -/** One round of SHA-512. */ -static void Round(uint64_t a, uint64_t b, uint64_t c, uint64_t *d, uint64_t e, uint64_t f, uint64_t g, uint64_t *h, uint64_t k, uint64_t w) -{ - uint64_t t1 = *h + Sigma1(e) + Ch(e, f, g) + k + w; - uint64_t t2 = Sigma0(a) + Maj(a, b, c); - *d += t1; - *h = t1 + t2; -} - -/** Perform one SHA-512 transformation, processing a 128-byte chunk. */ -static void Transform(uint64_t *s, const uint64_t *chunk) -{ - uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; - uint64_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - - Round(a, b, c, &d, e, f, g, &h, 0x428a2f98d728ae22ull, w0 = be64_to_cpu(chunk[0])); - Round(h, a, b, &c, d, e, f, &g, 0x7137449123ef65cdull, w1 = be64_to_cpu(chunk[1])); - Round(g, h, a, &b, c, d, e, &f, 0xb5c0fbcfec4d3b2full, w2 = be64_to_cpu(chunk[2])); - Round(f, g, h, &a, b, c, d, &e, 0xe9b5dba58189dbbcull, w3 = be64_to_cpu(chunk[3])); - Round(e, f, g, &h, a, b, c, &d, 0x3956c25bf348b538ull, w4 = be64_to_cpu(chunk[4])); - Round(d, e, f, &g, h, a, b, &c, 0x59f111f1b605d019ull, w5 = be64_to_cpu(chunk[5])); - Round(c, d, e, &f, g, h, a, &b, 0x923f82a4af194f9bull, w6 = be64_to_cpu(chunk[6])); - Round(b, c, d, &e, f, g, h, &a, 0xab1c5ed5da6d8118ull, w7 = be64_to_cpu(chunk[7])); - Round(a, b, c, &d, e, f, g, &h, 0xd807aa98a3030242ull, w8 = be64_to_cpu(chunk[8])); - Round(h, a, b, &c, d, e, f, &g, 0x12835b0145706fbeull, w9 = be64_to_cpu(chunk[9])); - Round(g, h, a, &b, c, d, e, &f, 0x243185be4ee4b28cull, w10 = be64_to_cpu(chunk[10])); - Round(f, g, h, &a, b, c, d, &e, 0x550c7dc3d5ffb4e2ull, w11 = be64_to_cpu(chunk[11])); - Round(e, f, g, &h, a, b, c, &d, 0x72be5d74f27b896full, w12 = be64_to_cpu(chunk[12])); - Round(d, e, f, &g, h, a, b, &c, 0x80deb1fe3b1696b1ull, w13 = be64_to_cpu(chunk[13])); - Round(c, d, e, &f, g, h, a, &b, 0x9bdc06a725c71235ull, w14 = be64_to_cpu(chunk[14])); - Round(b, c, d, &e, f, g, h, &a, 0xc19bf174cf692694ull, w15 = be64_to_cpu(chunk[15])); - - Round(a, b, c, &d, e, f, g, &h, 0xe49b69c19ef14ad2ull, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, &c, d, e, f, &g, 0xefbe4786384f25e3ull, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, &b, c, d, e, &f, 0x0fc19dc68b8cd5b5ull, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, &a, b, c, d, &e, 0x240ca1cc77ac9c65ull, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, &h, a, b, c, &d, 0x2de92c6f592b0275ull, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, &g, h, a, b, &c, 0x4a7484aa6ea6e483ull, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, &f, g, h, a, &b, 0x5cb0a9dcbd41fbd4ull, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, &e, f, g, h, &a, 0x76f988da831153b5ull, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, &d, e, f, g, &h, 0x983e5152ee66dfabull, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, &c, d, e, f, &g, 0xa831c66d2db43210ull, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, &b, c, d, e, &f, 0xb00327c898fb213full, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, &a, b, c, d, &e, 0xbf597fc7beef0ee4ull, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, &h, a, b, c, &d, 0xc6e00bf33da88fc2ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, &g, h, a, b, &c, 0xd5a79147930aa725ull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, &f, g, h, a, &b, 0x06ca6351e003826full, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, &e, f, g, h, &a, 0x142929670a0e6e70ull, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, &d, e, f, g, &h, 0x27b70a8546d22ffcull, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, &c, d, e, f, &g, 0x2e1b21385c26c926ull, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, &b, c, d, e, &f, 0x4d2c6dfc5ac42aedull, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, &a, b, c, d, &e, 0x53380d139d95b3dfull, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, &h, a, b, c, &d, 0x650a73548baf63deull, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, &g, h, a, b, &c, 0x766a0abb3c77b2a8ull, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, &f, g, h, a, &b, 0x81c2c92e47edaee6ull, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, &e, f, g, h, &a, 0x92722c851482353bull, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, &d, e, f, g, &h, 0xa2bfe8a14cf10364ull, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, &c, d, e, f, &g, 0xa81a664bbc423001ull, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, &b, c, d, e, &f, 0xc24b8b70d0f89791ull, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, &a, b, c, d, &e, 0xc76c51a30654be30ull, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, &h, a, b, c, &d, 0xd192e819d6ef5218ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, &g, h, a, b, &c, 0xd69906245565a910ull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, &f, g, h, a, &b, 0xf40e35855771202aull, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, &e, f, g, h, &a, 0x106aa07032bbd1b8ull, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, &d, e, f, g, &h, 0x19a4c116b8d2d0c8ull, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, &c, d, e, f, &g, 0x1e376c085141ab53ull, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, &b, c, d, e, &f, 0x2748774cdf8eeb99ull, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, &a, b, c, d, &e, 0x34b0bcb5e19b48a8ull, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, &h, a, b, c, &d, 0x391c0cb3c5c95a63ull, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, &g, h, a, b, &c, 0x4ed8aa4ae3418acbull, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, &f, g, h, a, &b, 0x5b9cca4f7763e373ull, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, &e, f, g, h, &a, 0x682e6ff3d6b2b8a3ull, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, &d, e, f, g, &h, 0x748f82ee5defb2fcull, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, &c, d, e, f, &g, 0x78a5636f43172f60ull, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, &b, c, d, e, &f, 0x84c87814a1f0ab72ull, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, &a, b, c, d, &e, 0x8cc702081a6439ecull, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, &h, a, b, c, &d, 0x90befffa23631e28ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, &g, h, a, b, &c, 0xa4506cebde82bde9ull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, &f, g, h, a, &b, 0xbef9a3f7b2c67915ull, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, &e, f, g, h, &a, 0xc67178f2e372532bull, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, &d, e, f, g, &h, 0xca273eceea26619cull, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, &c, d, e, f, &g, 0xd186b8c721c0c207ull, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, &b, c, d, e, &f, 0xeada7dd6cde0eb1eull, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, &a, b, c, d, &e, 0xf57d4f7fee6ed178ull, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, &h, a, b, c, &d, 0x06f067aa72176fbaull, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, &g, h, a, b, &c, 0x0a637dc5a2c898a6ull, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, &f, g, h, a, &b, 0x113f9804bef90daeull, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, &e, f, g, h, &a, 0x1b710b35131c471bull, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, &d, e, f, g, &h, 0x28db77f523047d84ull, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, &c, d, e, f, &g, 0x32caab7b40c72493ull, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, &b, c, d, e, &f, 0x3c9ebe0a15c9bebcull, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, &a, b, c, d, &e, 0x431d67c49c100d4cull, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, &h, a, b, c, &d, 0x4cc5d4becb3e42b6ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, &g, h, a, b, &c, 0x597f299cfc657e2aull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, &f, g, h, a, &b, 0x5fcb6fab3ad6faecull, w14 + sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, &e, f, g, h, &a, 0x6c44198c4a475817ull, w15 + sigma1(w13) + w8 + sigma0(w0)); - - s[0] += a; - s[1] += b; - s[2] += c; - s[3] += d; - s[4] += e; - s[5] += f; - s[6] += g; - s[7] += h; -} - -static bool alignment_ok(const void *p UNUSED, size_t n UNUSED) -{ -#if HAVE_UNALIGNED_ACCESS - return true; -#else - return ((size_t)p % n == 0); -#endif -} - -static void add(struct sha512_ctx *ctx, const void *p, size_t len) -{ - const unsigned char *data = p; - size_t bufsize = ctx->bytes % 128; - - if (bufsize + len >= 128) { - /* Fill the buffer, and process it. */ - memcpy(ctx->buf.u8 + bufsize, data, 128 - bufsize); - ctx->bytes += 128 - bufsize; - data += 128 - bufsize; - len -= 128 - bufsize; - Transform(ctx->s, ctx->buf.u64); - bufsize = 0; - } - - while (len >= 128) { - /* Process full chunks directly from the source. */ - if (alignment_ok(data, sizeof(uint64_t))) - Transform(ctx->s, (const uint64_t *)data); - else { - memcpy(ctx->buf.u8, data, sizeof(ctx->buf)); - Transform(ctx->s, ctx->buf.u64); - } - ctx->bytes += 128; - data += 128; - len -= 128; - } - - if (len) { - /* Fill the buffer with what remains. */ - memcpy(ctx->buf.u8 + bufsize, data, len); - ctx->bytes += len; - } -} - -void sha512_init(struct sha512_ctx *ctx) -{ - struct sha512_ctx init = SHA512_INIT; - *ctx = init; -} - -void sha512_update(struct sha512_ctx *ctx, const void *p, size_t size) -{ - check_sha512(ctx); - add(ctx, p, size); -} - -void sha512_done(struct sha512_ctx *ctx, struct sha512 *res) -{ - static const unsigned char pad[128] = { 0x80 }; - uint64_t sizedesc[2] = { 0, 0 }; - size_t i; - - sizedesc[1] = cpu_to_be64((uint64_t)ctx->bytes << 3); - - /* Add '1' bit to terminate, then all 0 bits, up to next block - 16. */ - add(ctx, pad, 1 + ((256 - 16 - (ctx->bytes % 128) - 1) % 128)); - /* Add number of bits of data (big endian) */ - add(ctx, sizedesc, sizeof(sizedesc)); - for (i = 0; i < sizeof(ctx->s) / sizeof(ctx->s[0]); i++) - res->u.u64[i] = cpu_to_be64(ctx->s[i]); - invalidate_sha512(ctx); -} - -void sha512(struct sha512 *sha, const void *p, size_t size) -{ - struct sha512_ctx ctx; - - sha512_init(&ctx); - sha512_update(&ctx, p, size); - sha512_done(&ctx, sha); -} - -/* From hex.h */ -/** - * hex_decode - Unpack a hex string. - * @str: the hexidecimal string - * @slen: the length of @str - * @buf: the buffer to write the data into - * @bufsize: the length of @buf - * - * Returns false if there are any characters which aren't 0-9, a-f or A-F, - * of the string wasn't the right length for @bufsize. - * - * Example: - * unsigned char data[20]; - * - * if (!hex_decode(argv[1], strlen(argv[1]), data, 20)) - * printf("String is malformed!\n"); - */ -bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize); - -/** - * hex_encode - Create a nul-terminated hex string - * @buf: the buffer to read the data from - * @bufsize: the length of @buf - * @dest: the string to fill - * @destsize: the max size of the string - * - * Returns true if the string, including terminator, fit in @destsize; - * - * Example: - * unsigned char buf[] = { 0x1F, 0x2F }; - * char str[5]; - * - * if (!hex_encode(buf, sizeof(buf), str, sizeof(str))) - * abort(); - */ -bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize); - -/** - * hex_str_size - Calculate how big a nul-terminated hex string is - * @bytes: bytes of data to represent - * - * Example: - * unsigned char buf[] = { 0x1F, 0x2F }; - * char str[hex_str_size(sizeof(buf))]; - * - * hex_encode(buf, sizeof(buf), str, sizeof(str)); - */ -static inline size_t hex_str_size(size_t bytes) -{ - return 2 * bytes + 1; -} - -/* From hex.c */ -static bool char_to_hex(unsigned char *val, char c) -{ - if (c >= '0' && c <= '9') { - *val = c - '0'; - return true; - } - if (c >= 'a' && c <= 'f') { - *val = c - 'a' + 10; - return true; - } - if (c >= 'A' && c <= 'F') { - *val = c - 'A' + 10; - return true; - } - return false; -} - -bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize) -{ - unsigned char v1, v2; - unsigned char *p = buf; - - while (slen > 1) { - if (!char_to_hex(&v1, str[0]) || !char_to_hex(&v2, str[1])) - return false; - if (!bufsize) - return false; - *(p++) = (v1 << 4) | v2; - str += 2; - slen -= 2; - bufsize--; - } - return slen == 0 && bufsize == 0; -} - -static char hexchar(unsigned int val) -{ - if (val < 10) - return '0' + val; - if (val < 16) - return 'a' + val - 10; - abort(); -} - -bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize) -{ - size_t i; - - if (destsize < hex_str_size(bufsize)) - return false; - - for (i = 0; i < bufsize; i++) { - unsigned int c = ((const unsigned char *)buf)[i]; - *(dest++) = hexchar(c >> 4); - *(dest++) = hexchar(c & 0xF); - } - *dest = '\0'; - - return true; -} - -/* From tap.h */ -/** - * plan_tests - announce the number of tests you plan to run - * @tests: the number of tests - * - * This should be the first call in your test program: it allows tracing - * of failures which mean that not all tests are run. - * - * If you don't know how many tests will actually be run, assume all of them - * and use skip() if you don't actually run some tests. - * - * Example: - * plan_tests(13); - */ -void plan_tests(unsigned int tests); - -/** - * ok1 - Simple conditional test - * @e: the expression which we expect to be true. - * - * This is the simplest kind of test: if the expression is true, the - * test passes. The name of the test which is printed will simply be - * file name, line number, and the expression itself. - * - * Example: - * ok1(somefunc() == 1); - */ -# define ok1(e) ((e) ? \ - _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ - _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) - -/** - * exit_status - the value that main should return. - * - * For maximum compatibility your test program should return a particular exit - * code (ie. 0 if all tests were run, and every test which was expected to - * succeed succeeded). - * - * Example: - * exit(exit_status()); - */ -int exit_status(void); - -/** - * tap_fail_callback - function to call when we fail - * - * This can be used to ease debugging, or exit on the first failure. - */ -void (*tap_fail_callback)(void); - -/* From tap.c */ - -static int no_plan = 0; -static int skip_all = 0; -static int have_plan = 0; -static unsigned int test_count = 0; /* Number of tests that have been run */ -static unsigned int e_tests = 0; /* Expected number of tests to run */ -static unsigned int failures = 0; /* Number of tests that failed */ -static char *todo_msg = NULL; -static const char *todo_msg_fixed = "libtap malloc issue"; -static int todo = 0; -static int test_died = 0; -static int test_pid; - -static void -_expected_tests(unsigned int tests) -{ - printf("1..%d\n", tests); - e_tests = tests; -} - -static void -diagv(const char *fmt, va_list ap) -{ - fputs("# ", stdout); - vfprintf(stdout, fmt, ap); - fputs("\n", stdout); -} - -static void -_diag(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - diagv(fmt, ap); - va_end(ap); -} - -/* - * Generate a test result. - * - * ok -- boolean, indicates whether or not the test passed. - * test_name -- the name of the test, may be NULL - * test_comment -- a comment to print afterwards, may be NULL - */ -unsigned int -_gen_result(int ok, const char *func, const char *file, unsigned int line, - const char *test_name, ...) -{ - va_list ap; - char *local_test_name = NULL; - char *c; - int name_is_digits; - - test_count++; - - /* Start by taking the test name and performing any printf() - expansions on it */ - if(test_name != NULL) { - va_start(ap, test_name); - if (vasprintf(&local_test_name, test_name, ap) < 0) - local_test_name = NULL; - va_end(ap); - - /* Make sure the test name contains more than digits - and spaces. Emit an error message and exit if it - does */ - if(local_test_name) { - name_is_digits = 1; - for(c = local_test_name; *c != '\0'; c++) { - if(!isdigit((unsigned char)*c) - && !isspace((unsigned char)*c)) { - name_is_digits = 0; - break; - } - } - - if(name_is_digits) { - _diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); - _diag(" Very confusing."); - } - } - } - - if(!ok) { - printf("not "); - failures++; - } - - printf("ok %d", test_count); - - if(test_name != NULL) { - printf(" - "); - - /* Print the test name, escaping any '#' characters it - might contain */ - if(local_test_name != NULL) { - flockfile(stdout); - for(c = local_test_name; *c != '\0'; c++) { - if(*c == '#') - fputc('\\', stdout); - fputc((int)*c, stdout); - } - funlockfile(stdout); - } else { /* vasprintf() failed, use a fixed message */ - printf("%s", todo_msg_fixed); - } - } - - /* If we're in a todo_start() block then flag the test as being - TODO. todo_msg should contain the message to print at this - point. If it's NULL then asprintf() failed, and we should - use the fixed message. - - This is not counted as a failure, so decrement the counter if - the test failed. */ - if(todo) { - printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); - if(!ok) - failures--; - } - - printf("\n"); - - if(!ok) - _diag(" Failed %stest (%s:%s() at line %d)", - todo ? "(TODO) " : "", file, func, line); - - free(local_test_name); - - if (!ok && tap_fail_callback) - tap_fail_callback(); - - /* We only care (when testing) that ok is positive, but here we - specifically only want to return 1 or 0 */ - return ok ? 1 : 0; -} - -/* - * Cleanup at the end of the run, produce any final output that might be - * required. - */ -static void -_cleanup(void) -{ - /* If we forked, don't do cleanup in child! */ - if (getpid() != test_pid) - return; - - /* If plan_no_plan() wasn't called, and we don't have a plan, - and we're not skipping everything, then something happened - before we could produce any output */ - if(!no_plan && !have_plan && !skip_all) { - _diag("Looks like your test died before it could output anything."); - return; - } - - if(test_died) { - _diag("Looks like your test died just after %d.", test_count); - return; - } - - - /* No plan provided, but now we know how many tests were run, and can - print the header at the end */ - if(!skip_all && (no_plan || !have_plan)) { - printf("1..%d\n", test_count); - } - - if((have_plan && !no_plan) && e_tests < test_count) { - _diag("Looks like you planned %d tests but ran %d extra.", - e_tests, test_count - e_tests); - return; - } - - if((have_plan || !no_plan) && e_tests > test_count) { - _diag("Looks like you planned %d tests but only ran %d.", - e_tests, test_count); - if(failures) { - _diag("Looks like you failed %d tests of %d run.", - failures, test_count); - } - return; - } - - if(failures) - _diag("Looks like you failed %d tests of %d.", - failures, test_count); - -} - -/* - * Initialise the TAP library. Will only do so once, however many times it's - * called. - */ -static void -_tap_init(void) -{ - static int run_once = 0; - - if(!run_once) { - test_pid = getpid(); - atexit(_cleanup); - - /* stdout needs to be unbuffered so that the output appears - in the same place relative to stderr output as it does - with Test::Harness */ -// setbuf(stdout, 0); - run_once = 1; - } -} - -/* - * Note the number of tests that will be run. - */ -void -plan_tests(unsigned int tests) -{ - - _tap_init(); - - if(have_plan != 0) { - fprintf(stderr, "You tried to plan twice!\n"); - test_died = 1; - exit(255); - } - - if(tests == 0) { - fprintf(stderr, "You said to run 0 tests! You've got to run something.\n"); - test_died = 1; - exit(255); - } - - have_plan = 1; - - _expected_tests(tests); -} - -static int -exit_status_(void) -{ - int r; - - /* If there's no plan, just return the number of failures */ - if(no_plan || !have_plan) { - return failures; - } - - /* Ran too many tests? Return the number of tests that were run - that shouldn't have been */ - if(e_tests < test_count) { - r = test_count - e_tests; - return r; - } - - /* Return the number of tests that failed + the number of tests - that weren't run */ - r = failures + e_tests - test_count; - - return r; -} - -int -exit_status(void) -{ - int r = exit_status_(); - if (r > 255) - r = 255; - return r; -} - -/* From run-test-vectors.c */ - -/* Test vectors. */ -struct test { - const char *vector; - size_t repetitions; - const char *expected; -}; - -static const char ZEROES[] = - "0000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000"; - -static struct test tests[] = { - /* http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html ShortMsg */ - { "21", 1, - "3831a6a6155e509dee59a7f451eb35324d8f8f2df6e3708894740f98fdee2388" - "9f4de5adb0c5010dfb555cda77c8ab5dc902094c52de3278f35a75ebc25f093a" }, - { "9083", 1, - "55586ebba48768aeb323655ab6f4298fc9f670964fc2e5f2731e34dfa4b0c09e" - "6e1e12e3d7286b3145c61c2047fb1a2a1297f36da64160b31fa4c8c2cddd2fb4" }, - { "0a55db", 1, - "7952585e5330cb247d72bae696fc8a6b0f7d0804577e347d99bc1b11e52f3849" - "85a428449382306a89261ae143c2f3fb613804ab20b42dc097e5bf4a96ef919b" }, - { "23be86d5", 1, - "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2" - "ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb" }, - { "eb0ca946c1", 1, - "d39ecedfe6e705a821aee4f58bfc489c3d9433eb4ac1b03a97e321a2586b40dd" - "0522f40fa5aef36afff591a78c916bfc6d1ca515c4983dd8695b1ec7951d723e" }, - { "38667f39277b", 1, - "85708b8ff05d974d6af0801c152b95f5fa5c06af9a35230c5bea2752f031f9bd" - "84bd844717b3add308a70dc777f90813c20b47b16385664eefc88449f04f2131" }, - { "b39f71aaa8a108", 1, - "258b8efa05b4a06b1e63c7a3f925c5ef11fa03e3d47d631bf4d474983783d8c0" - "b09449009e842fc9fa15de586c67cf8955a17d790b20f41dadf67ee8cdcdfce6" }, - { "dc28484ebfd293d62ac759d5754bdf502423e4d419fa79020805134b2ce3dff7" - "38c7556c91d810adbad8dd210f041296b73c2185d4646c97fc0a5b69ed49ac8c" - "7ced0bd1cfd7e3c3cca47374d189247da6811a40b0ab097067ed4ad40ade2e47" - "91e39204e398b3204971445822a1be0dd93af8", 1, - "615115d2e8b62e345adaa4bdb95395a3b4fe27d71c4a111b86c1841463c5f03d" - "6b20d164a39948ab08ae060720d05c10f6022e5c8caf2fa3bca2e04d9c539ded" }, - { "fd2203e467574e834ab07c9097ae164532f24be1eb5d88f1af7748ceff0d2c67" - "a21f4e4097f9d3bb4e9fbf97186e0db6db0100230a52b453d421f8ab9c9a6043" - "aa3295ea20d2f06a2f37470d8a99075f1b8a8336f6228cf08b5942fc1fb4299c" - "7d2480e8e82bce175540bdfad7752bc95b577f229515394f3ae5cec870a4b2f8", - 1, - "a21b1077d52b27ac545af63b32746c6e3c51cb0cb9f281eb9f3580a6d4996d5c" - "9917d2a6e484627a9d5a06fa1b25327a9d710e027387fc3e07d7c4d14c6086cc" }, - /* http://www.di-mgt.com.au/sha_testvectors.html */ - { ZEROES, 1, - "7be9fda48f4179e611c698a73cff09faf72869431efee6eaad14de0cb44bbf66" - "503f752b7a8eb17083355f3ce6eb7d2806f236b25af96a24e22b887405c20081" } -}; - -static void *xmalloc(size_t size) -{ - char * ret; - ret = malloc(size); - if (ret == NULL) { - perror("malloc"); - abort(); - } - return ret; -} - -static bool do_test(const struct test *t) -{ - struct sha512 h; - char got[128 + 1]; - bool passed; - size_t i, vector_len = strlen(t->vector) / 2; - void *vector = xmalloc(vector_len); - - hex_decode(t->vector, vector_len * 2, vector, vector_len); - - for (i = 0; i < t->repetitions; i++) { - sha512(&h, vector, vector_len); - if (t->repetitions > 1) - memcpy(vector, &h, sizeof(h)); - } - - hex_encode(&h, sizeof(h), got, sizeof(got)); - - passed = strcmp(t->expected, got) == 0; - free(vector); - return passed; -} - -int main(void) -{ - const size_t num_tests = sizeof(tests) / sizeof(tests[0]); - size_t i; - - /* This is how many tests you plan to run */ - plan_tests(num_tests); - - for (i = 0; i < num_tests; i++) - ok1(do_test(&tests[i])); - - /* This exits depending on whether all tests passed */ - return exit_status(); -} diff --git a/tests/tcg/multiarch/sigbus.c b/tests/tcg/multiarch/sigbus.c deleted file mode 100644 index 8134c5fd5680..000000000000 --- a/tests/tcg/multiarch/sigbus.c +++ /dev/null @@ -1,68 +0,0 @@ -#define _GNU_SOURCE 1 - -#include -#include -#include -#include - - -unsigned long long x = 0x8877665544332211ull; -void * volatile p = (void *)&x + 1; - -void sigbus(int sig, siginfo_t *info, void *uc) -{ - assert(sig == SIGBUS); - assert(info->si_signo == SIGBUS); -#ifdef BUS_ADRALN - assert(info->si_code == BUS_ADRALN); -#endif - assert(info->si_addr == p); - exit(EXIT_SUCCESS); -} - -int main() -{ - struct sigaction sa = { - .sa_sigaction = sigbus, - .sa_flags = SA_SIGINFO - }; - int allow_fail = 0; - int tmp; - - tmp = sigaction(SIGBUS, &sa, NULL); - assert(tmp == 0); - - /* - * Select an operation that's likely to enforce alignment. - * On many guests that support unaligned accesses by default, - * this is often an atomic operation. - */ -#if defined(__aarch64__) - asm volatile("ldxr %w0,[%1]" : "=r"(tmp) : "r"(p) : "memory"); -#elif defined(__alpha__) - asm volatile("ldl_l %0,0(%1)" : "=r"(tmp) : "r"(p) : "memory"); -#elif defined(__arm__) - asm volatile("ldrex %0,[%1]" : "=r"(tmp) : "r"(p) : "memory"); -#elif defined(__powerpc__) - asm volatile("lwarx %0,0,%1" : "=r"(tmp) : "r"(p) : "memory"); -#elif defined(__riscv_atomic) - asm volatile("lr.w %0,(%1)" : "=r"(tmp) : "r"(p) : "memory"); -#else - /* No insn known to fault unaligned -- try for a straight load. */ - allow_fail = 1; - tmp = *(volatile int *)p; -#endif - - assert(allow_fail); - - /* - * We didn't see a signal. - * We might as well validate the unaligned load worked. - */ - if (BYTE_ORDER == LITTLE_ENDIAN) { - assert(tmp == 0x55443322); - } else { - assert(tmp == 0x77665544); - } - return EXIT_SUCCESS; -} diff --git a/tests/tcg/multiarch/signals.c b/tests/tcg/multiarch/signals.c deleted file mode 100644 index 998c8fdefd6f..000000000000 --- a/tests/tcg/multiarch/signals.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * linux-user signal handling tests. - * - * Copyright (c) 2021 Linaro Ltd - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void error1(const char *filename, int line, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", filename, line); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(1); -} - -static int __chk_error(const char *filename, int line, int ret) -{ - if (ret < 0) { - error1(filename, line, "%m (ret=%d, errno=%d/%s)", - ret, errno, strerror(errno)); - } - return ret; -} - -#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) - -#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) - -/* - * Thread handling - */ -typedef struct ThreadJob ThreadJob; - -struct ThreadJob { - int number; - int sleep; - int count; -}; - -static pthread_t *threads; -static int max_threads = 10; -__thread int signal_count; -int total_signal_count; - -static void *background_thread_func(void *arg) -{ - ThreadJob *job = (ThreadJob *) arg; - - printf("thread%d: started\n", job->number); - while (total_signal_count < job->count) { - usleep(job->sleep); - } - printf("thread%d: saw %d alarms from %d\n", job->number, - signal_count, total_signal_count); - return NULL; -} - -static void spawn_threads(void) -{ - int i; - threads = calloc(sizeof(pthread_t), max_threads); - - for (i = 0; i < max_threads; i++) { - ThreadJob *job = calloc(sizeof(ThreadJob), 1); - job->number = i; - job->sleep = i * 1000; - job->count = i * 100; - pthread_create(threads + i, NULL, background_thread_func, job); - } -} - -static void close_threads(void) -{ - int i; - for (i = 0; i < max_threads; i++) { - pthread_join(threads[i], NULL); - } - free(threads); - threads = NULL; -} - -static void sig_alarm(int sig, siginfo_t *info, void *puc) -{ - if (sig != SIGRTMIN) { - error("unexpected signal"); - } - signal_count++; - __atomic_fetch_add(&total_signal_count, 1, __ATOMIC_SEQ_CST); -} - -static void test_signals(void) -{ - struct sigaction act; - struct itimerspec it; - timer_t tid; - struct sigevent sev; - - /* Set up SIG handler */ - act.sa_sigaction = sig_alarm; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - chk_error(sigaction(SIGRTMIN, &act, NULL)); - - /* Create POSIX timer */ - sev.sigev_notify = SIGEV_SIGNAL; - sev.sigev_signo = SIGRTMIN; - sev.sigev_value.sival_ptr = &tid; - chk_error(timer_create(CLOCK_REALTIME, &sev, &tid)); - - it.it_interval.tv_sec = 0; - it.it_interval.tv_nsec = 1000000; - it.it_value.tv_sec = 0; - it.it_value.tv_nsec = 1000000; - chk_error(timer_settime(tid, 0, &it, NULL)); - - spawn_threads(); - - do { - usleep(1000); - } while (total_signal_count < 2000); - - printf("shutting down after: %d signals\n", total_signal_count); - - close_threads(); - - chk_error(timer_delete(tid)); -} - -int main(int argc, char **argv) -{ - test_signals(); - return 0; -} diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target deleted file mode 100644 index 625ed792c6d6..000000000000 --- a/tests/tcg/multiarch/system/Makefile.softmmu-target +++ /dev/null @@ -1,35 +0,0 @@ -# -*- Mode: makefile -*- -# -# Multiarch system tests -# -# We just collect the tests together here and rely on the actual guest -# architecture to add to the test dependancies and deal with the -# complications of building. -# - -MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch -MULTIARCH_SYSTEM_SRC=$(MULTIARCH_SRC)/system -VPATH+=$(MULTIARCH_SYSTEM_SRC) - -MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c) -MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS)) - -ifneq ($(HAVE_GDB_BIN),) -GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py - -run-gdbstub-memory: memory - $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ - --qemu $(QEMU) \ - --output $<.gdb.out \ - --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") - -else -run-gdbstub-%: - $(call skip-test, "gdbstub test $*", "need working gdb") -endif - -MULTIARCH_RUNS += run-gdbstub-memory diff --git a/tests/tcg/multiarch/system/hello.c b/tests/tcg/multiarch/system/hello.c deleted file mode 100644 index 821dc0ef09f4..000000000000 --- a/tests/tcg/multiarch/system/hello.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Hello World, system test version - * - * We don't have the benefit of libc, just builtin C primitives and - * whatever is in minilib. - */ - -#include - -int main(void) -{ - ml_printf("Hello World\n"); - return 0; -} diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c deleted file mode 100644 index 41c7f66e2ed9..000000000000 --- a/tests/tcg/multiarch/system/memory.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Memory Test - * - * This is intended to test the softmmu code and ensure we properly - * behave across normal and unaligned accesses across several pages. - * We are not replicating memory tests for stuck bits and other - * hardware level failures but looking for issues with different size - * accesses when access is: - * - * - unaligned at various sizes (if -DCHECK_UNALIGNED set) - * - spanning a (softmmu) page - * - sign extension when loading - */ - -#include -#include -#include - -#ifndef CHECK_UNALIGNED -# error "Target does not specify CHECK_UNALIGNED" -#endif - -#define MEM_PAGE_SIZE 4096 /* nominal 4k "pages" */ -#define TEST_SIZE (MEM_PAGE_SIZE * 4) /* 4 pages */ - -#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0]))) - -__attribute__((aligned(MEM_PAGE_SIZE))) -static uint8_t test_data[TEST_SIZE]; - -typedef void (*init_ufn) (int offset); -typedef bool (*read_ufn) (int offset); -typedef bool (*read_sfn) (int offset, bool nf); - -static void pdot(int count) -{ - if (count % 128 == 0) { - ml_printf("."); - } -} - -/* - * Helper macros for shift/extract so we can keep our endian handling - * in one place. - */ -#define BYTE_SHIFT(b, pos) ((uint64_t)b << (pos * 8)) -#define BYTE_EXTRACT(b, pos) ((b >> (pos * 8)) & 0xff) - -/* - * Fill the data with ascending value bytes. - * - * Currently we only support Little Endian machines so write in - * ascending address order. When we read higher address bytes should - * either be zero or higher than the lower bytes. - */ - -static void init_test_data_u8(int unused_offset) -{ - uint8_t count = 0, *ptr = &test_data[0]; - int i; - (void)(unused_offset); - - ml_printf("Filling test area with u8:"); - for (i = 0; i < TEST_SIZE; i++) { - *ptr++ = count++; - pdot(i); - } - ml_printf("done\n"); -} - -/* - * Full the data with alternating positive and negative bytes. This - * should mean for reads larger than a byte all subsequent reads will - * stay either negative or positive. We never write 0. - */ - -static inline uint8_t get_byte(int index, bool neg) -{ - return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1)); -} - -static void init_test_data_s8(bool neg_first) -{ - uint8_t top, bottom, *ptr = &test_data[0]; - int i; - - ml_printf("Filling test area with s8 pairs (%s):", - neg_first ? "neg first" : "pos first"); - for (i = 0; i < TEST_SIZE / 2; i++) { - *ptr++ = get_byte(i, neg_first); - *ptr++ = get_byte(i, !neg_first); - pdot(i); - } - ml_printf("done\n"); -} - -/* - * Zero the first few bytes of the test data in preparation for - * new offset values. - */ -static void reset_start_data(int offset) -{ - uint32_t *ptr = (uint32_t *) &test_data[0]; - int i; - for (i = 0; i < offset; i++) { - *ptr++ = 0; - } -} - -static void init_test_data_u16(int offset) -{ - uint8_t count = 0; - uint16_t word, *ptr = (uint16_t *) &test_data[offset]; - const int max = (TEST_SIZE - offset) / sizeof(word); - int i; - - ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr); - - reset_start_data(offset); - - for (i = 0; i < max; i++) { - uint8_t low = count++, high = count++; - word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0); - *ptr++ = word; - pdot(i); - } - ml_printf("done @ %p\n", ptr); -} - -static void init_test_data_u32(int offset) -{ - uint8_t count = 0; - uint32_t word, *ptr = (uint32_t *) &test_data[offset]; - const int max = (TEST_SIZE - offset) / sizeof(word); - int i; - - ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr); - - reset_start_data(offset); - - for (i = 0; i < max; i++) { - uint8_t b4 = count++, b3 = count++; - uint8_t b2 = count++, b1 = count++; - word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) | b4; - *ptr++ = word; - pdot(i); - } - ml_printf("done @ %p\n", ptr); -} - -static void init_test_data_u64(int offset) -{ - uint8_t count = 0; - uint64_t word, *ptr = (uint64_t *) &test_data[offset]; - const int max = (TEST_SIZE - offset) / sizeof(word); - int i; - - ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr); - - reset_start_data(offset); - - for (i = 0; i < max; i++) { - uint8_t b8 = count++, b7 = count++; - uint8_t b6 = count++, b5 = count++; - uint8_t b4 = count++, b3 = count++; - uint8_t b2 = count++, b1 = count++; - word = BYTE_SHIFT(b1, 7) | BYTE_SHIFT(b2, 6) | BYTE_SHIFT(b3, 5) | - BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) | - BYTE_SHIFT(b7, 1) | b8; - *ptr++ = word; - pdot(i); - } - ml_printf("done @ %p\n", ptr); -} - -static bool read_test_data_u16(int offset) -{ - uint16_t word, *ptr = (uint16_t *)&test_data[offset]; - int i; - const int max = (TEST_SIZE - offset) / sizeof(word); - - ml_printf("Reading u16 from %#lx (offset %d):", ptr, offset); - - for (i = 0; i < max; i++) { - uint8_t high, low; - word = *ptr++; - high = (word >> 8) & 0xff; - low = word & 0xff; - if (high < low && high != 0) { - ml_printf("Error %d < %d\n", high, low); - return false; - } else { - pdot(i); - } - - } - ml_printf("done @ %p\n", ptr); - return true; -} - -static bool read_test_data_u32(int offset) -{ - uint32_t word, *ptr = (uint32_t *)&test_data[offset]; - int i; - const int max = (TEST_SIZE - offset) / sizeof(word); - - ml_printf("Reading u32 from %#lx (offset %d):", ptr, offset); - - for (i = 0; i < max; i++) { - uint8_t b1, b2, b3, b4; - int zeros = 0; - word = *ptr++; - - b1 = word >> 24 & 0xff; - b2 = word >> 16 & 0xff; - b3 = word >> 8 & 0xff; - b4 = word & 0xff; - - zeros += (b1 == 0 ? 1 : 0); - zeros += (b2 == 0 ? 1 : 0); - zeros += (b3 == 0 ? 1 : 0); - zeros += (b4 == 0 ? 1 : 0); - if (zeros > 1) { - ml_printf("Error @ %p, more zeros than expected: %d, %d, %d, %d", - ptr - 1, b1, b2, b3, b4); - return false; - } - - if ((b1 < b2 && b1 != 0) || - (b2 < b3 && b2 != 0) || - (b3 < b4 && b3 != 0)) { - ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4); - return false; - } else { - pdot(i); - } - } - ml_printf("done @ %p\n", ptr); - return true; -} - -static bool read_test_data_u64(int offset) -{ - uint64_t word, *ptr = (uint64_t *)&test_data[offset]; - int i; - const int max = (TEST_SIZE - offset) / sizeof(word); - - ml_printf("Reading u64 from %#lx (offset %d):", ptr, offset); - - for (i = 0; i < max; i++) { - uint8_t b1, b2, b3, b4, b5, b6, b7, b8; - int zeros = 0; - word = *ptr++; - - b1 = ((uint64_t) (word >> 56)) & 0xff; - b2 = ((uint64_t) (word >> 48)) & 0xff; - b3 = ((uint64_t) (word >> 40)) & 0xff; - b4 = (word >> 32) & 0xff; - b5 = (word >> 24) & 0xff; - b6 = (word >> 16) & 0xff; - b7 = (word >> 8) & 0xff; - b8 = (word >> 0) & 0xff; - - zeros += (b1 == 0 ? 1 : 0); - zeros += (b2 == 0 ? 1 : 0); - zeros += (b3 == 0 ? 1 : 0); - zeros += (b4 == 0 ? 1 : 0); - zeros += (b5 == 0 ? 1 : 0); - zeros += (b6 == 0 ? 1 : 0); - zeros += (b7 == 0 ? 1 : 0); - zeros += (b8 == 0 ? 1 : 0); - if (zeros > 1) { - ml_printf("Error @ %p, more zeros than expected: %d, %d, %d, %d, %d, %d, %d, %d", - ptr - 1, b1, b2, b3, b4, b5, b6, b7, b8); - return false; - } - - if ((b1 < b2 && b1 != 0) || - (b2 < b3 && b2 != 0) || - (b3 < b4 && b3 != 0) || - (b4 < b5 && b4 != 0) || - (b5 < b6 && b5 != 0) || - (b6 < b7 && b6 != 0) || - (b7 < b8 && b7 != 0)) { - ml_printf("Error %d, %d, %d, %d, %d, %d, %d, %d", - b1, b2, b3, b4, b5, b6, b7, b8); - return false; - } else { - pdot(i); - } - } - ml_printf("done @ %p\n", ptr); - return true; -} - -/* Read the test data and verify at various offsets */ -read_ufn read_ufns[] = { read_test_data_u16, - read_test_data_u32, - read_test_data_u64 }; - -bool do_unsigned_reads(int start_off) -{ - int i; - bool ok = true; - - for (i = 0; i < ARRAY_SIZE(read_ufns) && ok; i++) { -#if CHECK_UNALIGNED - int off; - for (off = start_off; off < 8 && ok; off++) { - ok = read_ufns[i](off); - } -#else - ok = read_ufns[i](start_off); -#endif - } - - return ok; -} - -static bool do_unsigned_test(init_ufn fn) -{ -#if CHECK_UNALIGNED - bool ok = true; - int i; - for (i = 0; i < 8 && ok; i++) { - fn(i); - ok = do_unsigned_reads(i); - } - return ok; -#else - fn(0); - return do_unsigned_reads(0); -#endif -} - -/* - * We need to ensure signed data is read into a larger data type to - * ensure that sign extension is working properly. - */ - -static bool read_test_data_s8(int offset, bool neg_first) -{ - int8_t *ptr = (int8_t *)&test_data[offset]; - int i; - const int max = (TEST_SIZE - offset) / 2; - - ml_printf("Reading s8 pairs from %#lx (offset %d):", ptr, offset); - - for (i = 0; i < max; i++) { - int16_t first, second; - bool ok; - first = *ptr++; - second = *ptr++; - - if (neg_first && first < 0 && second > 0) { - pdot(i); - } else if (!neg_first && first > 0 && second < 0) { - pdot(i); - } else { - ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second); - return false; - } - } - ml_printf("done @ %p\n", ptr); - return true; -} - -static bool read_test_data_s16(int offset, bool neg_first) -{ - int16_t *ptr = (int16_t *)&test_data[offset]; - int i; - const int max = (TEST_SIZE - offset) / (sizeof(*ptr)); - - ml_printf("Reading s16 from %#lx (offset %d, %s):", ptr, - offset, neg_first ? "neg" : "pos"); - - for (i = 0; i < max; i++) { - int32_t data = *ptr++; - - if (neg_first && data < 0) { - pdot(i); - } else if (data > 0) { - pdot(i); - } else { - ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>'); - return false; - } - } - ml_printf("done @ %p\n", ptr); - return true; -} - -static bool read_test_data_s32(int offset, bool neg_first) -{ - int32_t *ptr = (int32_t *)&test_data[offset]; - int i; - const int max = (TEST_SIZE - offset) / (sizeof(int32_t)); - - ml_printf("Reading s32 from %#lx (offset %d, %s):", - ptr, offset, neg_first ? "neg" : "pos"); - - for (i = 0; i < max; i++) { - int64_t data = *ptr++; - - if (neg_first && data < 0) { - pdot(i); - } else if (data > 0) { - pdot(i); - } else { - ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>'); - return false; - } - } - ml_printf("done @ %p\n", ptr); - return true; -} - -/* - * Read the test data and verify at various offsets - * - * For everything except bytes all our reads should be either positive - * or negative depending on what offset we are reading from. Currently - * we only handle LE systems. - */ -read_sfn read_sfns[] = { read_test_data_s8, - read_test_data_s16, - read_test_data_s32 }; - -bool do_signed_reads(bool neg_first) -{ - int i; - bool ok = true; - - for (i = 0; i < ARRAY_SIZE(read_sfns) && ok; i++) { -#if CHECK_UNALIGNED - int off; - for (off = 0; off < 8 && ok; off++) { - bool nf = i == 0 ? neg_first ^ (off & 1) : !(neg_first ^ (off & 1)); - ok = read_sfns[i](off, nf); - } -#else - ok = read_sfns[i](0, i == 0 ? neg_first : !neg_first); -#endif - } - - return ok; -} - -init_ufn init_ufns[] = { init_test_data_u8, - init_test_data_u16, - init_test_data_u32, - init_test_data_u64 }; - -int main(void) -{ - int i; - bool ok = true; - - /* Run through the unsigned tests first */ - for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) { - ok = do_unsigned_test(init_ufns[i]); - } - - if (ok) { - init_test_data_s8(false); - ok = do_signed_reads(false); - } - - if (ok) { - init_test_data_s8(true); - ok = do_signed_reads(true); - } - - ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED"); - return ok ? 0 : -1; -} diff --git a/tests/tcg/multiarch/test-mmap.c b/tests/tcg/multiarch/test-mmap.c deleted file mode 100644 index 96257f8ebec8..000000000000 --- a/tests/tcg/multiarch/test-mmap.c +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Small test program to verify simulated mmap behaviour. - * - * When running qemu-linux-user with the -p flag, you may need to tell - * this test program about the pagesize because getpagesize() will not reflect - * the -p choice. Simply pass one argument being the pagesize. - * - * Copyright (c) 2007 AXIS Communications AB - * Written by Edgar E. Iglesias. - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include - -#define D(x) - -#define fail_unless(x) \ -do \ -{ \ - if (!(x)) { \ - fprintf(stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \ - exit (EXIT_FAILURE); \ - } \ -} while (0) - -unsigned char *dummybuf; -static unsigned int pagesize; -static unsigned int pagemask; -int test_fd; -size_t test_fsize; - -void check_aligned_anonymous_unfixed_mmaps(void) -{ - void *p1; - void *p2; - void *p3; - void *p4; - void *p5; - uintptr_t p; - int i; - fprintf(stdout, "%s", __func__); - for (i = 0; i < 8; i++) { - size_t len; - len = pagesize + (pagesize * i); - p1 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p2 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p3 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p4 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - p5 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* - * Make sure we get pages aligned with the pagesize. The - * target expects this. - */ - fail_unless(p1 != MAP_FAILED); - fail_unless(p2 != MAP_FAILED); - fail_unless(p3 != MAP_FAILED); - fail_unless(p4 != MAP_FAILED); - fail_unless(p5 != MAP_FAILED); - p = (uintptr_t) p1; - D(printf("p=%x\n", p)); - fail_unless((p & pagemask) == 0); - p = (uintptr_t) p2; - fail_unless((p & pagemask) == 0); - p = (uintptr_t) p3; - fail_unless((p & pagemask) == 0); - p = (uintptr_t) p4; - fail_unless((p & pagemask) == 0); - p = (uintptr_t) p5; - fail_unless((p & pagemask) == 0); - - /* Make sure we can read from the entire area. */ - memcpy(dummybuf, p1, pagesize); - memcpy(dummybuf, p2, pagesize); - memcpy(dummybuf, p3, pagesize); - memcpy(dummybuf, p4, pagesize); - memcpy(dummybuf, p5, pagesize); - munmap(p1, len); - munmap(p2, len); - munmap(p3, len); - munmap(p4, len); - munmap(p5, len); - } - fprintf(stdout, " passed\n"); -} - -void check_large_anonymous_unfixed_mmap(void) -{ - void *p1; - uintptr_t p; - size_t len; - - fprintf(stdout, "%s", __func__); - - len = 0x02000000; - p1 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* Make sure we get pages aligned with the pagesize. The - target expects this. */ - fail_unless (p1 != MAP_FAILED); - p = (uintptr_t) p1; - fail_unless ((p & pagemask) == 0); - - /* Make sure we can read from the entire area. */ - memcpy (dummybuf, p1, pagesize); - munmap (p1, len); - fprintf(stdout, " passed\n"); -} - -void check_aligned_anonymous_unfixed_colliding_mmaps(void) -{ - char *p1; - char *p2; - char *p3; - uintptr_t p; - int i; - - fprintf(stdout, "%s", __func__); - for (i = 0; i < 2; i++) { - int nlen; - p1 = mmap(NULL, pagesize, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fail_unless(p1 != MAP_FAILED); - p = (uintptr_t) p1; - fail_unless((p & pagemask) == 0); - memcpy(dummybuf, p1, pagesize); - - p2 = mmap(NULL, pagesize, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fail_unless(p2 != MAP_FAILED); - p = (uintptr_t) p2; - fail_unless((p & pagemask) == 0); - memcpy(dummybuf, p2, pagesize); - - - munmap(p1, pagesize); - nlen = pagesize * 8; - p3 = mmap(NULL, nlen, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fail_unless(p3 != MAP_FAILED); - - /* Check if the mmaped areas collide. */ - if (p3 < p2 - && (p3 + nlen) > p2) { - fail_unless(0); - } - - memcpy(dummybuf, p3, pagesize); - - /* - * Make sure we get pages aligned with the pagesize. The - * target expects this. - */ - p = (uintptr_t) p3; - fail_unless((p & pagemask) == 0); - munmap(p2, pagesize); - munmap(p3, nlen); - } - fprintf(stdout, " passed\n"); -} - -void check_aligned_anonymous_fixed_mmaps(void) -{ - char *addr; - void *p1; - uintptr_t p; - int i; - - /* Find a suitable address to start with. */ - addr = mmap(NULL, pagesize * 40, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - fprintf(stdout, "%s addr=%p", __func__, addr); - fail_unless (addr != MAP_FAILED); - - for (i = 0; i < 40; i++) - { - /* Create submaps within our unfixed map. */ - p1 = mmap(addr, pagesize, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, - -1, 0); - /* Make sure we get pages aligned with the pagesize. - The target expects this. */ - p = (uintptr_t) p1; - fail_unless (p1 == addr); - fail_unless ((p & pagemask) == 0); - memcpy (dummybuf, p1, pagesize); - munmap (p1, pagesize); - addr += pagesize; - } - fprintf(stdout, " passed\n"); -} - -void check_aligned_anonymous_fixed_mmaps_collide_with_host(void) -{ - char *addr; - void *p1; - uintptr_t p; - int i; - - /* Find a suitable address to start with. Right were the x86 hosts - stack is. */ - addr = ((void *)0x80000000); - fprintf(stdout, "%s addr=%p", __func__, addr); - fprintf(stdout, "FIXME: QEMU fails to track pages used by the host."); - - for (i = 0; i < 20; i++) - { - /* Create submaps within our unfixed map. */ - p1 = mmap(addr, pagesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, - -1, 0); - /* Make sure we get pages aligned with the pagesize. - The target expects this. */ - p = (uintptr_t) p1; - fail_unless (p1 == addr); - fail_unless ((p & pagemask) == 0); - memcpy (p1, dummybuf, pagesize); - munmap (p1, pagesize); - addr += pagesize; - } - fprintf(stdout, " passed\n"); -} - -void check_file_unfixed_mmaps(void) -{ - unsigned int *p1, *p2, *p3; - uintptr_t p; - int i; - - fprintf(stdout, "%s", __func__); - for (i = 0; i < 0x10; i++) - { - size_t len; - - len = pagesize; - p1 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE, - test_fd, 0); - p2 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE, - test_fd, pagesize); - p3 = mmap(NULL, len, PROT_READ, - MAP_PRIVATE, - test_fd, pagesize * 2); - - fail_unless (p1 != MAP_FAILED); - fail_unless (p2 != MAP_FAILED); - fail_unless (p3 != MAP_FAILED); - - /* Make sure we get pages aligned with the pagesize. The - target expects this. */ - p = (uintptr_t) p1; - fail_unless ((p & pagemask) == 0); - p = (uintptr_t) p2; - fail_unless ((p & pagemask) == 0); - p = (uintptr_t) p3; - fail_unless ((p & pagemask) == 0); - - /* Verify that the file maps was made correctly. */ - D(printf ("p1=%d p2=%d p3=%d\n", *p1, *p2, *p3)); - fail_unless (*p1 == 0); - fail_unless (*p2 == (pagesize / sizeof *p2)); - fail_unless (*p3 == ((pagesize * 2) / sizeof *p3)); - - memcpy (dummybuf, p1, pagesize); - memcpy (dummybuf, p2, pagesize); - memcpy (dummybuf, p3, pagesize); - munmap (p1, len); - munmap (p2, len); - munmap (p3, len); - } - fprintf(stdout, " passed\n"); -} - -void check_file_unfixed_eof_mmaps(void) -{ - char *cp; - unsigned int *p1; - uintptr_t p; - int i; - - fprintf(stdout, "%s", __func__); - for (i = 0; i < 0x10; i++) - { - p1 = mmap(NULL, pagesize, PROT_READ, - MAP_PRIVATE, - test_fd, - (test_fsize - sizeof *p1) & ~pagemask); - - fail_unless (p1 != MAP_FAILED); - - /* Make sure we get pages aligned with the pagesize. The - target expects this. */ - p = (uintptr_t) p1; - fail_unless ((p & pagemask) == 0); - /* Verify that the file maps was made correctly. */ - fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1] - == ((test_fsize - sizeof *p1) / sizeof *p1)); - - /* Verify that the end of page is accessible and zeroed. */ - cp = (void *) p1; - fail_unless (cp[pagesize - 4] == 0); - munmap (p1, pagesize); - } - fprintf(stdout, " passed\n"); -} - -void check_file_fixed_eof_mmaps(void) -{ - char *addr; - char *cp; - unsigned int *p1; - uintptr_t p; - int i; - - /* Find a suitable address to start with. */ - addr = mmap(NULL, pagesize * 44, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - - fprintf(stdout, "%s addr=%p", __func__, (void *)addr); - fail_unless (addr != MAP_FAILED); - - for (i = 0; i < 0x10; i++) - { - /* Create submaps within our unfixed map. */ - p1 = mmap(addr, pagesize, PROT_READ, - MAP_PRIVATE | MAP_FIXED, - test_fd, - (test_fsize - sizeof *p1) & ~pagemask); - - fail_unless (p1 != MAP_FAILED); - - /* Make sure we get pages aligned with the pagesize. The - target expects this. */ - p = (uintptr_t) p1; - fail_unless ((p & pagemask) == 0); - - /* Verify that the file maps was made correctly. */ - fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1] - == ((test_fsize - sizeof *p1) / sizeof *p1)); - - /* Verify that the end of page is accessible and zeroed. */ - cp = (void *)p1; - fail_unless (cp[pagesize - 4] == 0); - munmap (p1, pagesize); - addr += pagesize; - } - fprintf(stdout, " passed\n"); -} - -void check_file_fixed_mmaps(void) -{ - unsigned char *addr; - unsigned int *p1, *p2, *p3, *p4; - int i; - - /* Find a suitable address to start with. */ - addr = mmap(NULL, pagesize * 40 * 4, PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - fprintf(stdout, "%s addr=%p", __func__, (void *)addr); - fail_unless (addr != MAP_FAILED); - - for (i = 0; i < 40; i++) - { - p1 = mmap(addr, pagesize, PROT_READ, - MAP_PRIVATE | MAP_FIXED, - test_fd, 0); - p2 = mmap(addr + pagesize, pagesize, PROT_READ, - MAP_PRIVATE | MAP_FIXED, - test_fd, pagesize); - p3 = mmap(addr + pagesize * 2, pagesize, PROT_READ, - MAP_PRIVATE | MAP_FIXED, - test_fd, pagesize * 2); - p4 = mmap(addr + pagesize * 3, pagesize, PROT_READ, - MAP_PRIVATE | MAP_FIXED, - test_fd, pagesize * 3); - - /* Make sure we get pages aligned with the pagesize. - The target expects this. */ - fail_unless (p1 == (void *)addr); - fail_unless (p2 == (void *)addr + pagesize); - fail_unless (p3 == (void *)addr + pagesize * 2); - fail_unless (p4 == (void *)addr + pagesize * 3); - - /* Verify that the file maps was made correctly. */ - fail_unless (*p1 == 0); - fail_unless (*p2 == (pagesize / sizeof *p2)); - fail_unless (*p3 == ((pagesize * 2) / sizeof *p3)); - fail_unless (*p4 == ((pagesize * 3) / sizeof *p4)); - - memcpy (dummybuf, p1, pagesize); - memcpy (dummybuf, p2, pagesize); - memcpy (dummybuf, p3, pagesize); - memcpy (dummybuf, p4, pagesize); - - munmap (p1, pagesize); - munmap (p2, pagesize); - munmap (p3, pagesize); - munmap (p4, pagesize); - addr += pagesize * 4; - } - fprintf(stdout, " passed\n"); -} - -void checked_write(int fd, const void *buf, size_t count) -{ - ssize_t rc = write(fd, buf, count); - fail_unless(rc == count); -} - -void check_invalid_mmaps(void) -{ - unsigned char *addr; - - /* Attempt to map a zero length page. */ - addr = mmap(NULL, 0, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fprintf(stdout, "%s addr=%p", __func__, (void *)addr); - fail_unless(addr == MAP_FAILED); - fail_unless(errno == EINVAL); - - /* Attempt to map a over length page. */ - addr = mmap(NULL, -4, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - fprintf(stdout, "%s addr=%p", __func__, (void *)addr); - fail_unless(addr == MAP_FAILED); - fail_unless(errno == ENOMEM); - - fprintf(stdout, " passed\n"); -} - -int main(int argc, char **argv) -{ - char tempname[] = "/tmp/.cmmapXXXXXX"; - unsigned int i; - - /* Trust the first argument, otherwise probe the system for our - pagesize. */ - if (argc > 1) - pagesize = strtoul(argv[1], NULL, 0); - else - pagesize = sysconf(_SC_PAGESIZE); - - /* Assume pagesize is a power of two. */ - pagemask = pagesize - 1; - dummybuf = malloc (pagesize); - printf ("pagesize=%u pagemask=%x\n", pagesize, pagemask); - - test_fd = mkstemp(tempname); - unlink(tempname); - - /* Fill the file with int's counting from zero and up. */ - for (i = 0; i < (pagesize * 4) / sizeof i; i++) { - checked_write(test_fd, &i, sizeof i); - } - - /* Append a few extra writes to make the file end at non - page boundary. */ - checked_write(test_fd, &i, sizeof i); i++; - checked_write(test_fd, &i, sizeof i); i++; - checked_write(test_fd, &i, sizeof i); i++; - - test_fsize = lseek(test_fd, 0, SEEK_CUR); - - /* Run the tests. */ - check_aligned_anonymous_unfixed_mmaps(); - check_aligned_anonymous_unfixed_colliding_mmaps(); - check_aligned_anonymous_fixed_mmaps(); - check_file_unfixed_mmaps(); - check_file_fixed_mmaps(); - check_file_fixed_eof_mmaps(); - check_file_unfixed_eof_mmaps(); - check_invalid_mmaps(); - - /* Fails at the moment. */ - /* check_aligned_anonymous_fixed_mmaps_collide_with_host(); */ - - return EXIT_SUCCESS; -} diff --git a/tests/tcg/multiarch/testthread.c b/tests/tcg/multiarch/testthread.c deleted file mode 100644 index 810ba5de67b3..000000000000 --- a/tests/tcg/multiarch/testthread.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void checked_write(int fd, const void *buf, size_t count) -{ - ssize_t rc = write(fd, buf, count); - assert(rc == count); -} - -void *thread1_func(void *arg) -{ - int i; - char buf[512]; - - for(i=0;i<10;i++) { - snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); - checked_write(1, buf, strlen(buf)); - usleep(100 * 1000); - } - return NULL; -} - -void *thread2_func(void *arg) -{ - int i; - char buf[512]; - for(i=0;i<20;i++) { - snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); - checked_write(1, buf, strlen(buf)); - usleep(150 * 1000); - } - return NULL; -} - -void test_pthread(void) -{ - pthread_t tid1, tid2; - - pthread_create(&tid1, NULL, thread1_func, "hello1"); - pthread_create(&tid2, NULL, thread2_func, "hello2"); - pthread_join(tid1, NULL); - pthread_join(tid2, NULL); - printf("End of pthread test.\n"); -} - -int main(int argc, char **argv) -{ - test_pthread(); - return 0; -} diff --git a/tests/tcg/multiarch/threadcount.c b/tests/tcg/multiarch/threadcount.c deleted file mode 100644 index 545a1c81466f..000000000000 --- a/tests/tcg/multiarch/threadcount.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Thread Exerciser - * - * Unlike testthread which is mainly concerned about testing thread - * semantics this test is used to exercise the thread creation and - * accounting. A version of this test found a problem with clashing - * cpu_indexes which caused a break in plugin handling. - * - * Based on the original test case by Nikolay Igotti. - * - * Copyright (c) 2020 Linaro Ltd - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include -#include -#include -#include - -int max_threads = 10; - -typedef struct { - int delay; -} ThreadArg; - -static void *thread_fn(void* varg) -{ - ThreadArg *arg = varg; - usleep(arg->delay); - free(arg); - return NULL; -} - -int main(int argc, char **argv) -{ - int i; - pthread_t *threads; - - if (argc > 1) { - max_threads = atoi(argv[1]); - } - threads = calloc(sizeof(pthread_t), max_threads); - - for (i = 0; i < max_threads; i++) { - ThreadArg *arg = calloc(sizeof(ThreadArg), 1); - arg->delay = i * 100; - pthread_create(threads + i, NULL, thread_fn, arg); - } - - printf("Created %d threads\n", max_threads); - - /* sleep until roughly half the threads have "finished" */ - usleep(max_threads * 50); - - for (i = 0; i < max_threads; i++) { - pthread_join(threads[i], NULL); - } - - printf("Done\n"); - - return 0; -} diff --git a/tests/tcg/nios2/Makefile.target b/tests/tcg/nios2/Makefile.target deleted file mode 100644 index b38e2352b7e3..000000000000 --- a/tests/tcg/nios2/Makefile.target +++ /dev/null @@ -1,11 +0,0 @@ -# nios2 specific test tweaks - -# Currently nios2 signal handling is broken -run-signals: signals - $(call skip-test, $<, "BROKEN") -run-plugin-signals-with-%: - $(call skip-test, $<, "BROKEN") -run-linux-test: linux-test - $(call skip-test, $<, "BROKEN") -run-plugin-linux-test-with-%: - $(call skip-test, $<, "BROKEN") diff --git a/tests/tcg/openrisc/Makefile b/tests/tcg/openrisc/Makefile deleted file mode 100644 index fb5ceda512f8..000000000000 --- a/tests/tcg/openrisc/Makefile +++ /dev/null @@ -1,71 +0,0 @@ --include ../../config-host.mak - -CROSS = or1k-linux- - -SIM = qemu-or1k - -CC = $(CROSS)gcc - -TESTCASES = test_add.tst -TESTCASES += test_sub.tst -TESTCASES += test_addc.tst -TESTCASES += test_addi.tst -TESTCASES += test_addic.tst -TESTCASES += test_and_or.tst -TESTCASES += test_bf.tst -TESTCASES += test_bnf.tst -TESTCASES += test_div.tst -TESTCASES += test_divu.tst -TESTCASES += test_extx.tst -TESTCASES += test_fx.tst -TESTCASES += test_jal.tst -TESTCASES += test_j.tst -TESTCASES += test_lf_div.tst -TESTCASES += test_lf_eqs.tst -TESTCASES += test_lf_ges.tst -TESTCASES += test_lf_gts.tst -TESTCASES += test_lf_les.tst -TESTCASES += test_lf_lts.tst -TESTCASES += test_lf_mul.tst -TESTCASES += test_lf_nes.tst -TESTCASES += test_lf_rem.tst -TESTCASES += test_lf_sub.tst -TESTCASES += test_lf_add.tst -TESTCASES += test_logic.tst -TESTCASES += test_lx.tst -TESTCASES += test_movhi.tst -TESTCASES += test_mul.tst -TESTCASES += test_mulu.tst -TESTCASES += test_muli.tst -TESTCASES += test_sfeq.tst -TESTCASES += test_sfeqi.tst -TESTCASES += test_sfges.tst -TESTCASES += test_sfgesi.tst -TESTCASES += test_sfgeu.tst -TESTCASES += test_sfgeui.tst -TESTCASES += test_sfgts.tst -TESTCASES += test_sfgtsi.tst -TESTCASES += test_sfgtu.tst -TESTCASES += test_sfgtui.tst -TESTCASES += test_sfles.tst -TESTCASES += test_sflesi.tst -TESTCASES += test_sfleu.tst -TESTCASES += test_sfleui.tst -TESTCASES += test_sflts.tst -TESTCASES += test_sfltsi.tst -TESTCASES += test_sfltu.tst -TESTCASES += test_sfltui.tst -TESTCASES += test_sfne.tst -TESTCASES += test_sfnei.tst - -all: $(TESTCASES) - -%.tst: %.c - $(CC) -static $< -o $@ - - -check: $(TESTCASES) - @for case in $(TESTCASES); do $(SIM) $$case; echo $$case pass!; sleep 0.2; done - -clean: - $(RM) -rf $(TESTCASES) diff --git a/tests/tcg/openrisc/test_add.c b/tests/tcg/openrisc/test_add.c deleted file mode 100644 index 3d23592e7606..000000000000 --- a/tests/tcg/openrisc/test_add.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int main(void) -{ - int a, b, d; - int result; - - a = 0x100; - b = 0x100; - result = 0x200; - __asm - ("l.add %0, %0, %1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("add error\n"); - return -1; - } - - a = 0xffff; - b = 0x1; - result = 0x10000; - __asm - ("l.add %0, %0, %1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("add error\n"); - return -1; - } - - a = 0x7fffffff; - b = 0x1; - __asm - ("l.add %0, %1, %2\n\t" - : "=r"(d) - : "r"(b), "r"(a) - ); - - return 0; -} diff --git a/tests/tcg/openrisc/test_addc.c b/tests/tcg/openrisc/test_addc.c deleted file mode 100644 index a8f756a69b2e..000000000000 --- a/tests/tcg/openrisc/test_addc.c +++ /dev/null @@ -1,40 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x01; - c = 0xffffffff; - result = 0; - __asm - ("l.add r1, r1, r0\n\t" /* clear carry */ - "l.addc %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("first addc error\n"); - return -1; - } - - b = 0x01; - c = 0xffffffff; - result = 0x80000001; - __asm - ("l.add r1, r1, r0\n\t" /* clear carry */ - "l.addc %0, %1, %2\n\t" - "l.movhi %2, 0x7fff\n\t" - "l.ori %2, %2, 0xffff\n\t" - "l.addc %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("addc error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_addi.c b/tests/tcg/openrisc/test_addi.c deleted file mode 100644 index bbf5a5ffab51..000000000000 --- a/tests/tcg/openrisc/test_addi.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - b = 0x01; - result = 0x00; - __asm - ("l.addi %0, %1, 0xffff\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("addi error\n\t"); - return -1; - } - - b = 0x010000; - result = 0xffff; - __asm - ("l.addi %0, %1, 0xffff\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("addi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_addic.c b/tests/tcg/openrisc/test_addic.c deleted file mode 100644 index 857aaa133025..000000000000 --- a/tests/tcg/openrisc/test_addic.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - a = 1; - result = 0x0; - __asm - ("l.add r1, r1, r0\n\t" /* clear carry */ - "l.addic %0, %0, 0xffff\n\t" - : "+r"(a) - ); - if (a != result) { - printf("first addic error\n"); - return -1; - } - - a = -1; - result = 0x201; - __asm - ("l.add r1, r1, r0\n\t" /* clear carry */ - "l.addic %0, %0, 0x1\n\t" - "l.ori %0, r0, 0x100\n\t" - "l.addic %0, %0, 0x100\n\t" - : "+r"(a) - ); - if (a != result) { - printf("second addic error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_and_or.c b/tests/tcg/openrisc/test_and_or.c deleted file mode 100644 index 810d868c7b07..000000000000 --- a/tests/tcg/openrisc/test_and_or.c +++ /dev/null @@ -1,65 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x2; - c = 0x1; - result = 0; - __asm - ("l.and %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("and error\n"); - return -1; - } - - result = 0x2; - __asm - ("l.andi %0, %1, 0x3\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("andi error %x\n", a); - return -1; - } - - result = 0x3; - __asm - ("l.or %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("or error\n"); - return -1; - } - - result = 0x3; - __asm - ("l.xor %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("xor error\n"); - return -1; - } - - __asm - ("l.xori %0, %1, 0x1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("xori error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_bf.c b/tests/tcg/openrisc/test_bf.c deleted file mode 100644 index 79f3fb99aa46..000000000000 --- a/tests/tcg/openrisc/test_bf.c +++ /dev/null @@ -1,47 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - a = 0; - b = 10; - c = 11; - result = 0x2; - __asm - ("1:\n\t" - "l.addi %1, %1, 0x01\n\t" - "l.addi %0, %0, 0x01\n\t" - "l.sfeq %1, %2\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sfeq error\n"); - return -1; - } - - a = 0x00; - b = 0x11; - c = 0x11; - result = 0x01; - __asm - ("1:\n\t" - "l.addi %1, %1, 0x01\n\t" - "l.addi %0, %0, 0x01\n\t" - "l.sfeq %1, %2\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sfeq error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_bnf.c b/tests/tcg/openrisc/test_bnf.c deleted file mode 100644 index f716215f10a1..000000000000 --- a/tests/tcg/openrisc/test_bnf.c +++ /dev/null @@ -1,51 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - b = 0; - result = 0x3; - __asm - ("l.sfeqi %1, 0x0\n\t" - "l.bnf 1f\n\t" - "l.nop\n\t" - "\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "\n\t" - "1:\n\t" - "l.addi %0, %0, 0x1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("l.bnf error\n"); - return -1; - } - - a = 0; - b = 0; - result = 1; - __asm - ("l.sfeqi %1, 0x1\n\t" - "l.bnf 1f\n\t" - "l.nop\n\t" - "\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "\n\t" - "1:\n\t" - "l.addi %0, %0, 0x1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("l.bnf error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_div.c b/tests/tcg/openrisc/test_div.c deleted file mode 100644 index 9b65f6e673ce..000000000000 --- a/tests/tcg/openrisc/test_div.c +++ /dev/null @@ -1,54 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x120; - c = 0x4; - result = 0x48; - __asm - ("l.div %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("div error\n"); - return -1; - } - - result = 0x4; - __asm - ("l.div %0, %1, %0\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("div error\n"); - return -1; - } - - b = 0xffffffff; - c = 0x80000000; - result = 0; - __asm - ("l.div %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("div error\n"); - return -1; - } - - b = 0x80000000; - c = 0xffffffff; - __asm - ("l.div %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - - return 0; -} diff --git a/tests/tcg/openrisc/test_divu.c b/tests/tcg/openrisc/test_divu.c deleted file mode 100644 index bff9e3ea590b..000000000000 --- a/tests/tcg/openrisc/test_divu.c +++ /dev/null @@ -1,34 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x120; - c = 0x4; - result = 0x48; - - __asm - ("l.divu %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("divu error\n"); - return -1; - } - - result = 0x4; - __asm - ("l.divu %0, %1, %0\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("divu error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_extx.c b/tests/tcg/openrisc/test_extx.c deleted file mode 100644 index 09221484a644..000000000000 --- a/tests/tcg/openrisc/test_extx.c +++ /dev/null @@ -1,78 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - b = 0x83; - result = 0xffffff83; - __asm - ("l.extbs %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("extbs error\n"); - return -1; - } - - result = 0x83; - __asm - ("l.extbz %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("extbz error\n"); - return -1; - } - - b = 0x8083; - result = 0xffff8083; - __asm - ("l.exths %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("exths error\n"); - return -1; - } - - result = 0x8083; - __asm - ("l.exthz %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("exthz error\n"); - return -1; - } - - b = 0x11; - result = 0x11; - __asm - ("l.extws %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - - if (a != result) { - printf("extws error\n"); - return -1; - } - - __asm - ("l.extwz %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("extwz error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_fx.c b/tests/tcg/openrisc/test_fx.c deleted file mode 100644 index df86000d9016..000000000000 --- a/tests/tcg/openrisc/test_fx.c +++ /dev/null @@ -1,57 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - b = 0x123; - result = 1; - __asm - ("l.ff1 %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("ff1 error\n"); - return -1; - } - - b = 0x0; - result = 0; - __asm - ("l.ff1 %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("ff1 error\n"); - return -1; - } - - b = 0x123; - result = 9; - __asm - ("l.fl1 %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("fl1 error\n"); - return -1; - } - - b = 0x0; - result = 0; - __asm - ("l.fl1 %0, %1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("fl1 error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_j.c b/tests/tcg/openrisc/test_j.c deleted file mode 100644 index 9ddf8bfbb5d8..000000000000 --- a/tests/tcg/openrisc/test_j.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 2; - __asm - ("l.addi %0, %0, 1\n\t" - "l.j j\n\t" - "l.nop\n\t" - "l.addi %0, %0, 1\n\t" - "l.nop\n\t" - "j:\n\t" - "l.addi %0, %0, 1\n\t" - : "+r"(a) - ); - if (a != result) { - printf("j error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_jal.c b/tests/tcg/openrisc/test_jal.c deleted file mode 100644 index 7e2da401639d..000000000000 --- a/tests/tcg/openrisc/test_jal.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 2; - __asm - ("l.addi %0, %0, 1\n\t" - "l.jal jal\n\t" - "l.nop\n\t" - "l.addi %0, %0, 1\n\t" - "l.nop\n\t" - "jal:\n\t" - "l.addi %0, %0, 1\n\t" - : "+r"(a) - ); - if (a != result) { - printf("jal error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_add.c b/tests/tcg/openrisc/test_lf_add.c deleted file mode 100644 index e00212dad659..000000000000 --- a/tests/tcg/openrisc/test_lf_add.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - float a, b; - float res2; - - a = 1.5; - b = 2.5; - res2 = 4.0; - __asm - ("lf.add.s %0, %0, %1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != res2) { - printf("lf.add.s error, %f\n", a); - return -1; - } - -/* double c, d; - double res1; - - c = 1.5; - d = 1.5; - res1 = 3.00; - __asm - ("lf.add.d %0, %1, %2\n\t" - : "+r"(c) - : "r"(d) - ); - - if ((e - res1) > 0.002) { - printf("lf.add.d error, %f\n", e - res1); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_div.c b/tests/tcg/openrisc/test_lf_div.c deleted file mode 100644 index 70b5d1c17b32..000000000000 --- a/tests/tcg/openrisc/test_lf_div.c +++ /dev/null @@ -1,37 +0,0 @@ -#include - -int main(void) -{ - float a, b, c; - float result; - - b = 1.5; - c = 0.5; - result = 3.0; - __asm - ("lf.div.s %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.div.s error\n"); - return -1; - } - -/* double a, b, c, res; - - b = 0x80000000; - c = 0x40; - result = 0x2000000; - __asm - ("lf.div.d %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.div.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_eqs.c b/tests/tcg/openrisc/test_lf_eqs.c deleted file mode 100644 index a176bd6fe0aa..000000000000 --- a/tests/tcg/openrisc/test_lf_eqs.c +++ /dev/null @@ -1,88 +0,0 @@ -#include - -int main(void) -{ - int a, result; - float b, c; - - a = 0x1; - b = 122.5; - c = 123.5; - result = 0x3; - __asm - ("lfeqd:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfeq.s %1, %2\n\t" - "l.bf lfeqd\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfeq.s error\n"); - return -1; - } - - b = 13.5; - c = 13.5; - result = 0x3; - __asm - ("lf.sfeq.s %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi r4, r4, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfeq.s error\n"); - return -1; - } - -/* double b, c; - double result; - int a; - - a = 0x1; - b = 122.5; - c = 133.5; - result = 0x3; - - __asm - ("lfeqd:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfeq.d %1, %2\n\t" - "l.bf lfeqd\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfeq.d error\n"); - return -1; - } - - double c, d, res; - int e = 0; - c = 11.5; - d = 11.5; - res = 1; - __asm - ("lf.sfeq.d %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(e) - : "r"(c), "r"(d) - ); - if (e != res) { - printf("lf.sfeq.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_ges.c b/tests/tcg/openrisc/test_lf_ges.c deleted file mode 100644 index 98e7f50b6e6d..000000000000 --- a/tests/tcg/openrisc/test_lf_ges.c +++ /dev/null @@ -1,88 +0,0 @@ -#include - -int main(void) -{ - int a, result; - float b, c; - - a = 0; - b = 122.5; - c = 123.5; - result = 0x1; - __asm - ("lfges:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfge.s %1, %2\n\t" - "l.bf lfges\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfge.s error\n"); - return -1; - } - - b = 133.5; - c = 13.5; - result = 0x3; - __asm - ("l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfge.s %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfge.s error\n"); - return -1; - } - -/* int a, result; - double b, c; - - a = 0x1; - b = 122.5; - c = 123.5; - result = 0x2; - __asm - ("lfged:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfge.d %1, %2\n\t" - "l.bf lfged\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfge.d error\n"); - return -1; - } - - b = 133.5; - c = 13.5; - result = 0x4; - __asm - ("lf.sfge.d %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfge.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_gts.c b/tests/tcg/openrisc/test_lf_gts.c deleted file mode 100644 index f3df27958ec7..000000000000 --- a/tests/tcg/openrisc/test_lf_gts.c +++ /dev/null @@ -1,86 +0,0 @@ -#include - -int main(void) -{ - int a, result; - float b, c; - - a = 0; - b = 122.5; - c = 123.5; - result = 0x1; - __asm - ("lfgts:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfgt.s %1, %2\n\t" - "l.bf lfgts\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfgt.s error\n"); - return -1; - } - - b = 133.5; - c = 13.5; - result = 0x1; - __asm - ("lf.sfgt.s %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfgt.s error\n"); - return -1; - } - -/* int a, result; - double b, c; - - a = 0; - b = 122.5; - c = 123.5; - result = 0x1; - __asm - ("lfgtd:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfgt.d %1, %2\n\t" - "l.bf lfgtd\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfgt.d error\n"); - return -1; - } - - b = 133.5; - c = 13.5; - result = 0x3; - __asm - ("l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfgt.d %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfgt.d error, %x\n", a); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_les.c b/tests/tcg/openrisc/test_lf_les.c deleted file mode 100644 index 046c511d93f8..000000000000 --- a/tests/tcg/openrisc/test_lf_les.c +++ /dev/null @@ -1,88 +0,0 @@ -#include - -int main(void) -{ - int a; - float b, c; - int result; - - a = 0; - b = 1234.2; - c = 12.4; - result = 0x1; - __asm - ("lfles:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfle.s %1, %2\n\t" - "l.bf lfles\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfle.s error\n"); - return -1; - } - - b = 1.1; - c = 19.4; - result = 0x3; - __asm - ("l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfle.s %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfle.s error\n"); - return -1; - } - -/* int a; - double b, c; - int result; - - a = 0; - b = 1212.5; - c = 123.5; - result = 0x1; - __asm - ("lfled:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfle.d %1, %2\n\t" - "l.bf lfled\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfle.d error\n"); - return -1; - } - - b = 13.5; - c = 113.5; - result = 0x2; - __asm - ("l.addi %0, %0, 0x1\n\t" - "lf.sfle.d %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfle.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_lts.c b/tests/tcg/openrisc/test_lf_lts.c deleted file mode 100644 index fa56721dfab1..000000000000 --- a/tests/tcg/openrisc/test_lf_lts.c +++ /dev/null @@ -1,92 +0,0 @@ -#include - -int main(void) -{ - int a; - float b, c, d; - int result; - - a = 0; - b = 124.5; - c = 1.4; - result = 1; - __asm - ("lfltd:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sflt.s %1, %2\n\t" - "l.bf lfltd\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sflt.s error\n"); - return -1; - } - - a = 0; - b = 11.1; - c = 13.1; - d = 1.0; - result = 2; - __asm - ("1:\n\t" - "lf.add.s %1, %1, %3\n\t" - "l.addi %0, %0, 1\n\t" - "lf.sflt.s %1, %2\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c), "r"(d) - ); - if (a != result) { - printf("lf.sflt.s error\n"); - return -1; - } - -/* int a; - double b, c; - int result; - - a = 0; - b = 1432.1; - c = 2.4; - result = 0x1; - __asm - ("lfltd:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sflt.d %1, %2\n\t" - "l.bf lfltd\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sflt.d error\n"); - return -1; - } - - a = 0; - b = 1.1; - c = 19.7; - result = 2; - __asm - ("lf.sflt.d %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 1\n\t" - "l.addi %0, %0, 1\n\t" - "l.addi %0, %0, 1\n\t" - "1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.addi %0, %0, 1\n\t" - : "+r"(a), "+r"(b) - : "r"(c) - ); - if (a != result) { - printf("lf.sflt.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_mul.c b/tests/tcg/openrisc/test_lf_mul.c deleted file mode 100644 index bc8ad800c74d..000000000000 --- a/tests/tcg/openrisc/test_lf_mul.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -int main(void) -{ - float a, b, c; - float result; - - b = 1.5; - c = 4.0; - result = 6.0; - __asm - ("lf.mul.s %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.mul.s error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_nes.c b/tests/tcg/openrisc/test_lf_nes.c deleted file mode 100644 index 613631005bf1..000000000000 --- a/tests/tcg/openrisc/test_lf_nes.c +++ /dev/null @@ -1,89 +0,0 @@ -#include - -int main(void) -{ - int a; - float b, c; - int result; - - a = 0; - b = 23.1; - c = 23.1; - result = 0x1; - __asm - ("lfnes:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfne.s %1, %2\n\t" - "l.bf lfnes\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfne.s error"); - return -1; - } - - b = 12.4; - c = 7.8; - result = 0x3; - __asm - ("l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfne.s %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfne.s error\n"); - return -1; - } -/* int a; - double b, c; - int result; - - a = 0; - b = 124.3; - c = 124.3; - result = 0x1; - __asm - ("lfned:\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfne.d %1, %2\n\t" - "l.bf lfned\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfne.d error\n"); - return -1; - } - - b = 11.5; - c = 16.7; - result = 0x3; - __asm - ("l.addi %0, %0, 0x1\n\t" - "l.addi %0, %0, 0x1\n\t" - "lf.sfne.d %1, %2\n\t" - "l.bf 1f\n\t" - "l.nop\n\t" - "l.addi r4, r4, 0x1\n\t" - "l.addi r4, r4, 0x1\n\t" - "1:\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sfne.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_rem.c b/tests/tcg/openrisc/test_lf_rem.c deleted file mode 100644 index bd6090d6948a..000000000000 --- a/tests/tcg/openrisc/test_lf_rem.c +++ /dev/null @@ -1,32 +0,0 @@ -#include - -int main(void) -{ - float a, b, c; - float result; - - b = 101.5; - c = 10; - result = 1.5; -/* __asm - ("lf.rem.d %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.rem.d error\n"); - return -1; - }*/ - - __asm - ("lf.rem.s %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.rem.s error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_lf_sub.c b/tests/tcg/openrisc/test_lf_sub.c deleted file mode 100644 index 5ee9b0391023..000000000000 --- a/tests/tcg/openrisc/test_lf_sub.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -int main(void) -{ - float a, b, c; - float result; - - b = 10.5; - c = 1.5; - result = 9.0; - __asm - ("lf.sub.s %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sub.s error\n"); - return -1; - } - -/* b = 0x999; - c = 0x654; - result = 0x345; - __asm - ("lf.sub.d %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("lf.sub.d error\n"); - return -1; - }*/ - - return 0; -} diff --git a/tests/tcg/openrisc/test_logic.c b/tests/tcg/openrisc/test_logic.c deleted file mode 100644 index 46d173f4819b..000000000000 --- a/tests/tcg/openrisc/test_logic.c +++ /dev/null @@ -1,105 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x9743; - c = 0x2; - result = 0x25d0c; - __asm - ("l.sll %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sll error\n"); - return -1; - } - - b = 0x9743; - result = 0x25d0c; - __asm - ("l.slli %0, %1, 0x2\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("slli error\n"); - return -1; - } - - b = 0x7654; - c = 0x03; - result = 0xeca; - __asm - ("l.srl %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - - b = 0x7654; - result = 0xeca; - __asm - ("l.srli %0, %1, 0x3\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("srli error\n"); - return -1; - } - - b = 0x80000001; - c = 0x4; - result = 0x18000000; - __asm - ("l.ror %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("ror error\n"); - return -1; - } - - b = 0x80000001; - result = 0x18000000; - __asm - ("l.rori %0, %1, 0x4\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("rori error\n"); - return -1; - } - - b = 0x80000001; - c = 0x03; - result = 0xf0000000; - __asm - ("l.sra %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sra error\n"); - return -1; - } - - b = 0x80000001; - result = 0xf0000000; - __asm - ("l.srai %0, %1, 0x3\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("srai error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_lx.c b/tests/tcg/openrisc/test_lx.c deleted file mode 100644 index 792e3d5c7fcb..000000000000 --- a/tests/tcg/openrisc/test_lx.c +++ /dev/null @@ -1,84 +0,0 @@ -#include - -int main(void) -{ - int a; - int p[50]; - int result; - - result = 0x23; - __asm - ("l.ori r8, r0, 0x123\n\t" - "l.sb 0x4 + %1, r8\n\t" - "\n\t" - "l.lbz %0, 0x4 + %1\n\t" - : "=r"(a), "+m"(*p) - ); - if (a != result) { - printf("lbz error, %x\n", a); - return -1; - } - - result = 0x23; - __asm - ("l.lbs %0, 0x4 + %1\n\t" - : "=r"(a) - : "m"(*p) - ); - if (a != result) { - printf("lbs error\n"); - return -1; - } - - result = 0x1111; - __asm - ("l.ori r8, r0, 0x1111\n\t" - "l.sh 0x20 + %1, r8\n\t" - "\n\t" - "l.lhs %0, 0x20 + %1\n\t" - : "=r"(a), "=m"(*p) - ); - if (a != result) { - printf("lhs error, %x\n", a); - return -1; - } - - result = 0x1111; - __asm - ("l.lhz %0, 0x20 + %1\n\t" - : "=r"(a) - : "m"(*p) - ); - if (a != result) { - printf("lhz error\n"); - return -1; - } - - result = 0x1111233; - __asm - ("l.ori r8, r0, 0x1233\n\t" - "l.movhi r1, 0x111\n\t" - "l.or r8, r8, r1\n\t" - "l.sw 0x123 + %1, r8\n\t" - "\n\t" - "l.lws %0, 0x123 + %1\n\t" - : "=r"(a), "+m"(*p) - ); - if (a != result) { - printf("lws error, %x\n", a); - return -1; - } - - result = 0x1111233; - __asm - ("l.lwz %0, 0x123 + %1\n\t" - : "=r"(a) - : "m"(*p) - ); - if (a != result) { - printf("lwz error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_movhi.c b/tests/tcg/openrisc/test_movhi.c deleted file mode 100644 index 737f75b9fdac..000000000000 --- a/tests/tcg/openrisc/test_movhi.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - result = 0x1222; - __asm - ("l.movhi r3, 0x1222\n\t" - "l.srli %0, r3, 16\n\t" - : "=r"(a) - ); - if (a != result) { - printf("movhi error\n"); - return -1; - } - - result = 0x1111; - __asm - ("l.movhi r8, 0x1111\n\t" - "l.srli %0, r8, 16\n\t" - : "=r"(a) - ); - if (a != result) { - printf("movhi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_mul.c b/tests/tcg/openrisc/test_mul.c deleted file mode 100644 index 130101fdee0d..000000000000 --- a/tests/tcg/openrisc/test_mul.c +++ /dev/null @@ -1,61 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x4; - c = 0x1; - result = 0x4; - __asm - ("l.mul %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mul error\n"); - return -1; - } - - b = 0x1; - c = 0x0; - result = 0x0; - __asm - ("l.mul %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mul error\n"); - return -1; - } - - b = 0x1; - c = 0xff; - result = 0xff; - __asm - ("l.mul %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mul error\n"); - return -1; - } - - b = 0x7fffffff; - c = 0x2; - result = 0xfffffffe; - __asm - ("l.mul %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mul error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_muli.c b/tests/tcg/openrisc/test_muli.c deleted file mode 100644 index f1042e98dec8..000000000000 --- a/tests/tcg/openrisc/test_muli.c +++ /dev/null @@ -1,48 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x4; - c = 0x1; - result = 0x4; - __asm - ("l.muli %0, %1, 0x1\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("muli error\n"); - return -1; - } - - b = 0x1; - c = 0x0; - result = 0x0; - __asm - ("l.muli %0, %1, 0x0\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("muli error\n"); - return -1; - } - - b = 0x1; - c = 0xff; - result = 0xff; - __asm - ("l.muli %0, %1, 0xff\n\t" - : "=r"(a) - : "r"(b) - ); - if (a != result) { - printf("muli error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_mulu.c b/tests/tcg/openrisc/test_mulu.c deleted file mode 100644 index 2d1e97d16e20..000000000000 --- a/tests/tcg/openrisc/test_mulu.c +++ /dev/null @@ -1,48 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - b = 0x4; - c = 0x1; - result = 0x4; - __asm - ("l.mulu %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mulu error\n"); - return -1; - } - - b = 0x1; - c = 0x0; - result = 0x0; - __asm - ("l.mulu %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mulu error\n"); - return -1; - } - - b = 0x1; - c = 0xff; - result = 0xff; - __asm - ("l.mulu %0, %1, %2\n\t" - : "=r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("mulu error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfeq.c b/tests/tcg/openrisc/test_sfeq.c deleted file mode 100644 index bd7f875b7128..000000000000 --- a/tests/tcg/openrisc/test_sfeq.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0x1; - b = 0x80; - result = 0x2; - __asm - ("1:\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.sfeq %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfeq error\n"); - return -1; - } - - a = 0x7f; - b = 0x80; - result = 0x81; - __asm - ("2:\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.sfeq %0, %1\n\t" - "l.bf 2b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfeq error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfeqi.c b/tests/tcg/openrisc/test_sfeqi.c deleted file mode 100644 index 574261321b8f..000000000000 --- a/tests/tcg/openrisc/test_sfeqi.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 1; - result = 2; - __asm - ("1:\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.sfeqi %0, 0x80\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfeqi error\n"); - return -1; - } - - a = 0x7f; - result = 0x81; - __asm - ("2:\n\t" - "l.addi %0, %0, 0x1\n\t" - "l.sfeqi %0, 0x80\n\t" - "l.bf 2b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfeqi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfges.c b/tests/tcg/openrisc/test_sfges.c deleted file mode 100644 index 23761d7f5a96..000000000000 --- a/tests/tcg/openrisc/test_sfges.c +++ /dev/null @@ -1,44 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - a = 0; - b = 3; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfges %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfges error\n"); - return -1; - } - - a = 0xff; - b = 3; - c = 0x1; - result = 2; - __asm - ("1:\n\t" - "l.sub %0, %0, %2\n\t" - "l.sfges %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sfges error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgesi.c b/tests/tcg/openrisc/test_sfgesi.c deleted file mode 100644 index 54a2d51cd5ca..000000000000 --- a/tests/tcg/openrisc/test_sfgesi.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -int main(void) -{ - int a, b; - int result; - - a = 0; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgesi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfgesi error\n"); - return -1; - } - - a = 0xff; - b = 1; - result = 2; - __asm - ("1:\n\t" - "l.sub %0, %0, %1\n\t" - "l.sfgesi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgesi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgeu.c b/tests/tcg/openrisc/test_sfgeu.c deleted file mode 100644 index 2a491d91ea00..000000000000 --- a/tests/tcg/openrisc/test_sfgeu.c +++ /dev/null @@ -1,44 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - a = 0; - b = 3; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgeu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgeu error\n"); - return -1; - } - - a = 0xff; - b = 3; - c = 1; - result = 2; - __asm - ("1:\n\t" - "l.sub %0, %0, %2\n\t" - "l.sfgeu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sfgeu error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgeui.c b/tests/tcg/openrisc/test_sfgeui.c deleted file mode 100644 index 40af35c68f7e..000000000000 --- a/tests/tcg/openrisc/test_sfgeui.c +++ /dev/null @@ -1,41 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgeui %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfgeui error\n"); - return -1; - } - - a = 0xff; - b = 1; - result = 2; - __asm - ("1:\n\t" - "l.sub %0, %0, %1\n\t" - "l.sfgeui %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgeui error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgts.c b/tests/tcg/openrisc/test_sfgts.c deleted file mode 100644 index 4481a9cc3db6..000000000000 --- a/tests/tcg/openrisc/test_sfgts.c +++ /dev/null @@ -1,45 +0,0 @@ -#include - -int main(void) -{ - int a, b, c; - int result; - - a = 0; - b = 3; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgts %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgts error\n"); - return -1; - } - - - a = 0xff; - b = 3; - c = 1; - result = 3; - __asm - ("1:\n\t" - "l.sub %0, %0, %2\n\t" - "l.sfgts %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sfgts error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgtsi.c b/tests/tcg/openrisc/test_sfgtsi.c deleted file mode 100644 index 7366e1292c51..000000000000 --- a/tests/tcg/openrisc/test_sfgtsi.c +++ /dev/null @@ -1,41 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgtsi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfgtsi error\n"); - return -1; - } - - a = 0xff; - b = 1; - result = 3; - __asm - ("1:\n\t" - "l.sub %0, %0, %1\n\t" - "l.sfgtsi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgtsi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgtu.c b/tests/tcg/openrisc/test_sfgtu.c deleted file mode 100644 index da2868916d48..000000000000 --- a/tests/tcg/openrisc/test_sfgtu.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -int main(void) -{ - int a, b, c; - int result; - - a = 0; - b = 3; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgtu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgtu error\n"); - return -1; - } - - a = 0xff; - b = 3; - c = 1; - result = 3; - __asm - ("1:\n\t" - "l.sub %0, %0, %2\n\t" - "l.sfgtu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b), "r"(c) - ); - if (a != result) { - printf("sfgtu error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfgtui.c b/tests/tcg/openrisc/test_sfgtui.c deleted file mode 100644 index 565d44f1126d..000000000000 --- a/tests/tcg/openrisc/test_sfgtui.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - result = 1; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfgtui %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfgtui error\n"); - return -1; - } - - - a = 0xff; - b = 1; - result = 3; - __asm - ("1:\n\t" - "l.sub %0, %0, %1\n\t" - "l.sfgtui %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfgtui error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfles.c b/tests/tcg/openrisc/test_sfles.c deleted file mode 100644 index f5735228fead..000000000000 --- a/tests/tcg/openrisc/test_sfles.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - b = 3; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sfles %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfles error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sflesi.c b/tests/tcg/openrisc/test_sflesi.c deleted file mode 100644 index 16fe6053e578..000000000000 --- a/tests/tcg/openrisc/test_sflesi.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sflesi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sflesi error\n"); - return -1; - } - - a = 0; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sflesi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sflesi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfleu.c b/tests/tcg/openrisc/test_sfleu.c deleted file mode 100644 index be0a3c3f48bc..000000000000 --- a/tests/tcg/openrisc/test_sfleu.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - b = 3; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sfleu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfleu error\n"); - return -1; - } - - a = 0; - b = 3; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfleu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfleu error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfleui.c b/tests/tcg/openrisc/test_sfleui.c deleted file mode 100644 index 38d3c897090e..000000000000 --- a/tests/tcg/openrisc/test_sfleui.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sfleui %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfleui error\n"); - return -1; - } - - a = 0; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfleui %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfleui error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sflts.c b/tests/tcg/openrisc/test_sflts.c deleted file mode 100644 index 7deeb48d0952..000000000000 --- a/tests/tcg/openrisc/test_sflts.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - b = 3; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sflts %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sflts error\n"); - return -1; - } - - a = 0; - b = 3; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sflts %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sflts error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfltsi.c b/tests/tcg/openrisc/test_sfltsi.c deleted file mode 100644 index 3cb1f0285727..000000000000 --- a/tests/tcg/openrisc/test_sfltsi.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sfltsi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfltsi error\n"); - return -1; - } - - a = 0; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfltsi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfltsi error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfltu.c b/tests/tcg/openrisc/test_sfltu.c deleted file mode 100644 index 7ed3b2685861..000000000000 --- a/tests/tcg/openrisc/test_sfltu.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - b = 3; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sfltu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfltu error\n"); - return -1; - } - - a = 0; - b = 3; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfltu %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfltu error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfltui.c b/tests/tcg/openrisc/test_sfltui.c deleted file mode 100644 index a5cb9f6a97d8..000000000000 --- a/tests/tcg/openrisc/test_sfltui.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 4; - __asm - ("1:\n\t" - "l.addi %0, %0, 4\n\t" - "l.sfltsi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfltui error\n"); - return -1; - } - - a = 0; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfltsi %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfltui error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfne.c b/tests/tcg/openrisc/test_sfne.c deleted file mode 100644 index b33a35cf9691..000000000000 --- a/tests/tcg/openrisc/test_sfne.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0; - b = 3; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 3\n\t" - "l.sfne %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfne error\n"); - return -1; - } - - a = 0; - b = 3; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfne %0, %1\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sfne error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sfnei.c b/tests/tcg/openrisc/test_sfnei.c deleted file mode 100644 index d311c9e66022..000000000000 --- a/tests/tcg/openrisc/test_sfnei.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -int main(void) -{ - int a; - int result; - - a = 0; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 3\n\t" - "l.sfnei %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfnei error\n"); - return -1; - } - - a = 0; - result = 3; - __asm - ("1:\n\t" - "l.addi %0, %0, 1\n\t" - "l.sfnei %0, 0x3\n\t" - "l.bf 1b\n\t" - "l.nop\n\t" - : "+r"(a) - ); - if (a != result) { - printf("sfnei error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/openrisc/test_sub.c b/tests/tcg/openrisc/test_sub.c deleted file mode 100644 index 474ec6055b2f..000000000000 --- a/tests/tcg/openrisc/test_sub.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -int main(void) -{ - int a, b; - int result; - - a = 0x100; - b = 0x100; - result = 0x0; - __asm - ("l.sub %0, %0, %1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sub error\n"); - return -1; - } - - a = 0xffff; - b = 0x1; - result = 0xfffe; - __asm - ("l.sub %0, %0, %1\n\t" - : "+r"(a) - : "r"(b) - ); - if (a != result) { - printf("sub error\n"); - return -1; - } - - return 0; -} diff --git a/tests/tcg/ppc/Makefile.target b/tests/tcg/ppc/Makefile.target deleted file mode 100644 index f5e08c7376c0..000000000000 --- a/tests/tcg/ppc/Makefile.target +++ /dev/null @@ -1,12 +0,0 @@ -# -*- Mode: makefile -*- -# -# PPC - included from tests/tcg/Makefile -# - -ifneq (,$(findstring 64,$(TARGET_NAME))) -# On PPC64 Linux can be configured with 4k (default) or 64k pages (currently broken) -EXTRA_RUNS+=run-test-mmap-4096 #run-test-mmap-65536 -else -# On PPC32 Linux supports 4K/16K/64K/256K (but currently only 4k works) -EXTRA_RUNS+=run-test-mmap-4096 #run-test-mmap-16384 run-test-mmap-65536 run-test-mmap-262144 -endif diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target deleted file mode 100644 index 8197c288a7ba..000000000000 --- a/tests/tcg/ppc64/Makefile.target +++ /dev/null @@ -1,32 +0,0 @@ -# -*- Mode: makefile -*- -# -# ppc64 specific tweaks - -VPATH += $(SRC_PATH)/tests/tcg/ppc64 -VPATH += $(SRC_PATH)/tests/tcg/ppc64le - -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),) -PPC64_TESTS=bcdsub non_signalling_xscv -endif -$(PPC64_TESTS): CFLAGS += -mpower8-vector - -PPC64_TESTS += mtfsf - -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) -PPC64_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 - -PPC64_TESTS += signal_save_restore_xer -PPC64_TESTS += xxspltw - -TESTS += $(PPC64_TESTS) diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target deleted file mode 100644 index 9624bb1e9cee..000000000000 --- a/tests/tcg/ppc64le/Makefile.target +++ /dev/null @@ -1,30 +0,0 @@ -# -*- Mode: makefile -*- -# -# ppc64le specific tweaks - -VPATH += $(SRC_PATH)/tests/tcg/ppc64le - -ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),) -PPC64LE_TESTS=bcdsub non_signalling_xscv -endif -$(PPC64LE_TESTS): CFLAGS += -mpower8-vector - -ifneq ($(DOCKER_IMAGE)$(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 += signal_save_restore_xer -PPC64LE_TESTS += xxspltw - -TESTS += $(PPC64LE_TESTS) diff --git a/tests/tcg/ppc64le/bcdsub.c b/tests/tcg/ppc64le/bcdsub.c deleted file mode 100644 index 87c8c44a4493..000000000000 --- a/tests/tcg/ppc64le/bcdsub.c +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include -#include - -#define CRF_LT (1 << 3) -#define CRF_GT (1 << 2) -#define CRF_EQ (1 << 1) -#define CRF_SO (1 << 0) -#define UNDEF 0 - -#ifdef __has_builtin -#if !__has_builtin(__builtin_bcdsub) -#define NO_BUILTIN_BCDSUB -#endif -#endif - -#ifdef NO_BUILTIN_BCDSUB -#define BCDSUB(T, A, B, PS) \ - ".long 4 << 26 | (" #T ") << 21 | (" #A ") << 16 | (" #B ") << 11" \ - " | 1 << 10 | (" #PS ") << 9 | 65\n\t" -#else -#define BCDSUB(T, A, B, PS) "bcdsub. " #T ", " #A ", " #B ", " #PS "\n\t" -#endif - -#define TEST(AH, AL, BH, BL, PS, TH, TL, CR6) \ - do { \ - int cr = 0; \ - uint64_t th, tl; \ - /* \ - * Use GPR pairs to load the VSR values and place the resulting VSR and\ - * CR6 in th, tl, and cr. Note that we avoid newer instructions (e.g., \ - * mtvsrdd/mfvsrld) so we can run this test on POWER8 machines. \ - */ \ - asm ("mtvsrd 32, %3\n\t" \ - "mtvsrd 33, %4\n\t" \ - "xxmrghd 32, 32, 33\n\t" \ - "mtvsrd 33, %5\n\t" \ - "mtvsrd 34, %6\n\t" \ - "xxmrghd 33, 33, 34\n\t" \ - BCDSUB(0, 0, 1, PS) \ - "mfocrf %0, 0b10\n\t" \ - "mfvsrd %1, 32\n\t" \ - "xxswapd 32, 32\n\t" \ - "mfvsrd %2, 32\n\t" \ - : "=r" (cr), "=r" (th), "=r" (tl) \ - : "r" (AH), "r" (AL), "r" (BH), "r" (BL) \ - : "v0", "v1", "v2"); \ - if (TH != UNDEF || TL != UNDEF) { \ - assert(tl == TL); \ - assert(th == TH); \ - } \ - assert((cr >> 4) == CR6); \ - } while (0) - -/* - * Unbounded result is equal to zero: - * sign = (PS) ? 0b1111 : 0b1100 - * CR6 = 0b0010 - */ -void test_bcdsub_eq(void) -{ - /* maximum positive BCD value */ - TEST(0x9999999999999999, 0x999999999999999c, - 0x9999999999999999, 0x999999999999999c, - 0, 0x0, 0xc, CRF_EQ); - TEST(0x9999999999999999, 0x999999999999999c, - 0x9999999999999999, 0x999999999999999c, - 1, 0x0, 0xf, CRF_EQ); -} - -/* - * Unbounded result is greater than zero: - * sign = (PS) ? 0b1111 : 0b1100 - * CR6 = (overflow) ? 0b0101 : 0b0100 - */ -void test_bcdsub_gt(void) -{ - /* maximum positive and negative one BCD values */ - TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 0, - 0x0, 0xc, (CRF_GT | CRF_SO)); - TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 1, - 0x0, 0xf, (CRF_GT | CRF_SO)); - - TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 0, - 0x9999999999999999, 0x999999999999999c, CRF_GT); - TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 1, - 0x9999999999999999, 0x999999999999999f, CRF_GT); -} - -/* - * Unbounded result is less than zero: - * sign = 0b1101 - * CR6 = (overflow) ? 0b1001 : 0b1000 - */ -void test_bcdsub_lt(void) -{ - /* positive zero and positive one BCD values */ - TEST(0x0, 0xc, 0x0, 0x1c, 0, 0x0, 0x1d, CRF_LT); - TEST(0x0, 0xc, 0x0, 0x1c, 1, 0x0, 0x1d, CRF_LT); - - /* maximum negative and positive one BCD values */ - TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 0, - 0x0, 0xd, (CRF_LT | CRF_SO)); - TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 1, - 0x0, 0xd, (CRF_LT | CRF_SO)); -} - -void test_bcdsub_invalid(void) -{ - TEST(0x0, 0x1c, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO); - TEST(0x0, 0x1c, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO); - - TEST(0x0, 0xf00, 0x0, 0x1c, 0, UNDEF, UNDEF, CRF_SO); - TEST(0x0, 0xf00, 0x0, 0x1c, 1, UNDEF, UNDEF, CRF_SO); - - TEST(0x0, 0xbad, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO); - TEST(0x0, 0xbad, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO); -} - -int main(void) -{ - struct sigaction action; - - action.sa_handler = _exit; - sigaction(SIGABRT, &action, NULL); - - test_bcdsub_eq(); - test_bcdsub_gt(); - test_bcdsub_lt(); - test_bcdsub_invalid(); - - return 0; -} diff --git a/tests/tcg/ppc64le/byte_reverse.c b/tests/tcg/ppc64le/byte_reverse.c deleted file mode 100644 index 53b76fc2e28e..000000000000 --- a/tests/tcg/ppc64le/byte_reverse.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main(void) -{ - unsigned long var; - - var = 0xFEDCBA9876543210; - asm("brh %0, %0" : "+r"(var)); - assert(var == 0xDCFE98BA54761032); - - var = 0xFEDCBA9876543210; - asm("brw %0, %0" : "+r"(var)); - assert(var == 0x98BADCFE10325476); - - var = 0xFEDCBA9876543210; - asm("brd %0, %0" : "+r"(var)); - assert(var == 0x1032547698BADCFE); - - return 0; -} - diff --git a/tests/tcg/ppc64le/float_convs.ref b/tests/tcg/ppc64le/float_convs.ref deleted file mode 100644 index 6e6f6368344b..000000000000 --- a/tests/tcg/ppc64le/float_convs.ref +++ /dev/null @@ -1,748 +0,0 @@ -### Rounding to nearest -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding upwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding downwards -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -### Rounding to zero -from single: f32(-nan:0xffa00000) - to double: f64(-nan:0x00fff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-nan:0xffc00000) - to double: f64(-nan:0x00fff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-inf:0xff800000) - to double: f64(-inf:0x00fff0000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) - to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) - to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) - to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) - to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) - to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(-0x1.00000000000000000000p-126:0x80800000) - to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x0.00000000000000000000p+0:0000000000) - to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) - to int32: 0 (OK) - to int64: 0 (OK) - to uint32: 0 (OK) - to uint64: 0 (OK) -from single: f32(0x1.00000000000000000000p-126:0x00800000) - to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p-25:0x33000000) - to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) - to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) - to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000c00000000000000p-14:0x38800006) - to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) - to int32: 0 (INEXACT ) - to int64: 0 (INEXACT ) - to uint32: 0 (INEXACT ) - to uint64: 0 (INEXACT ) -from single: f32(0x1.00000000000000000000p+0:0x3f800000) - to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) - to int32: 1 (OK) - to int64: 1 (OK) - to uint32: 1 (OK) - to uint64: 1 (OK) -from single: f32(0x1.00400000000000000000p+0:0x3f802000) - to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) - to int32: 1 (INEXACT ) - to int64: 1 (INEXACT ) - to uint32: 1 (INEXACT ) - to uint64: 1 (INEXACT ) -from single: f32(0x1.00000000000000000000p+1:0x40000000) - to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) - to int32: 2 (OK) - to int64: 2 (OK) - to uint32: 2 (OK) - to uint64: 2 (OK) -from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) - to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) - to int32: 2 (INEXACT ) - to int64: 2 (INEXACT ) - to uint32: 2 (INEXACT ) - to uint64: 2 (INEXACT ) -from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) - to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) - to int32: 3 (INEXACT ) - to int64: 3 (INEXACT ) - to uint32: 3 (INEXACT ) - to uint64: 3 (INEXACT ) -from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) - to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) - to int32: 65503 (OK) - to int64: 65503 (OK) - to uint32: 65503 (OK) - to uint64: 65503 (OK) -from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) - to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) - to int32: 65504 (OK) - to int64: 65504 (OK) - to uint32: 65504 (OK) - to uint64: 65504 (OK) -from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) - to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) - to int32: 65505 (OK) - to int64: 65505 (OK) - to uint32: 65505 (OK) - to uint64: 65505 (OK) -from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) - to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) - to int32: 131007 (OK) - to int64: 131007 (OK) - to uint32: 131007 (OK) - to uint64: 131007 (OK) -from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) - to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) - to int32: 131008 (OK) - to int64: 131008 (OK) - to uint32: 131008 (OK) - to uint64: 131008 (OK) -from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) - to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) - to int32: 131009 (OK) - to int64: 131009 (OK) - to uint32: 131009 (OK) - to uint64: 131009 (OK) -from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) - to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) - to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(inf:0x7f800000) - to double: f64(inf:0x007ff0000000000000) (OK) - to int32: 2147483647 (INVALID) - to int64: 9223372036854775807 (INVALID) - to uint32: -1 (INVALID) - to uint64: -1 (INVALID) -from single: f32(nan:0x7fc00000) - to double: f64(nan:0x007ff8000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) -from single: f32(nan:0x7fa00000) - to double: f64(nan:0x007ff4000000000000) (OK) - to int32: -2147483648 (INVALID) - to int64: -9223372036854775808 (INVALID) - to uint32: 0 (INVALID) - to uint64: 0 (INVALID) diff --git a/tests/tcg/ppc64le/float_madds.ref b/tests/tcg/ppc64le/float_madds.ref deleted file mode 100644 index e66917cb801b..000000000000 --- a/tests/tcg/ppc64le/float_madds.ref +++ /dev/null @@ -1,768 +0,0 @@ -### Rounding to nearest -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(nan:0x7fc00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding upwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe800000000000000p-25:0x337ffff4) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe800000000000000p-50:0x26fffff4) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000200000000000000p-25:0x33000001) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00080000000000000000p-25:0x33000400) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f400000000000000p-24:0x338000fa) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000e00000000000000p-14:0x38800007) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf600000000000000p-24:0x3387fdfb) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000200000000000000p+0:0x3f800001) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d400000000000000p+2:0x409711ea) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458200000000000000p+3:0x4128a2c1) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0600000000000000p+3:0x41100603) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1600000000000000p+15:0x477fe78b) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56200000000000000p+17:0x482de2b1) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0a00000000000000p+31:0x4f7fbf05) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+31:0x4f7fc005) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800a00000000000000p+32:0x4fffc005) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8a00000000000000p+33:0x507fbfc5) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800a00000000000000p+33:0x507fc005) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab800000000000000p+99:0x71605d5c) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c082a000000000000000p+116:0x79e04150) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(nan:0x7fc00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-148:0x00000002) flags=UNDERFLOW INEXACT (32/0) -### Rounding downwards -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x1.00000000000000000000p-149:0x80000001) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(nan:0x7fc00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) -### Rounding to zero -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffe00000) flags=INVALID (0/0) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/1) -op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=INVALID (0/2) -op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(-nan:0xffc00000) flags=OK (1/0) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) -res: f32(-nan:0xffc00000) flags=OK (1/1) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) -res: f32(-nan:0xffc00000) flags=OK (1/2) -op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(inf:0x7f800000) flags=OK (2/0) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) -res: f32(-inf:0xff800000) flags=OK (2/1) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(inf:0x7f800000) flags=OK (2/2) -op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) -op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) -res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) -op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) -res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) -op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) -res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) -op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) -res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) -op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) -res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) -op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) -res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) -op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) -res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) -op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) -res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) -op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) -op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) -res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) -op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) -res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) -op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) -res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) -op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) -res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) -op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) -res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) -op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) -res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) -op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) -res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) -op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) -res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) -op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) -res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) -op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) -res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) -op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) -res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) -op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) -op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(inf:0x7f800000) flags=OK (26/0) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) -res: f32(inf:0x7f800000) flags=OK (26/1) -op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(inf:0x7f800000) flags=OK (26/2) -op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fc00000) flags=OK (27/0) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) -res: f32(nan:0x7fc00000) flags=OK (27/1) -op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=OK (27/2) -op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/0) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) -res: f32(nan:0x7fc00000) flags=INVALID (28/1) -op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (28/2) -op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(nan:0x7fc00000) flags=INVALID (29/0) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) -res: f32(nan:0x7fe00000) flags=INVALID (29/1) -op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (29/2) -op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) -res: f32(nan:0x7fe00000) flags=INVALID (30/0) -op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) -res: f32(-nan:0xffe00000) flags=INVALID (30/1) -op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) -res: f32(-nan:0xffc00000) flags=INVALID (30/2) -# LP184149 -op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) -res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) -op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) -res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) diff --git a/tests/tcg/ppc64le/mtfsf.c b/tests/tcg/ppc64le/mtfsf.c deleted file mode 100644 index bed5b1afa40e..000000000000 --- a/tests/tcg/ppc64le/mtfsf.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include -#include - -#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB)) -#define MFFS(FRT) asm("mffs %0" : "=f" (FRT)) - -#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */ -#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */ -#define FPSCR_FI 17 /* Floating-point fraction inexact */ - -#define FP_VE (1ull << FPSCR_VE) -#define FP_VXSOFT (1ull << FPSCR_VXSOFT) -#define FP_FI (1ull << FPSCR_FI) - -void sigfpe_handler(int sig, siginfo_t *si, void *ucontext) -{ - if (si->si_code == FPE_FLTINV) { - exit(0); - } - exit(1); -} - -int main(void) -{ - uint64_t fpscr; - - struct sigaction sa = { - .sa_sigaction = sigfpe_handler, - .sa_flags = SA_SIGINFO - }; - - /* - * Enable the MSR bits F0 and F1 to enable exceptions. - * This shouldn't be needed in linux-user as these bits are enabled by - * default, but this allows to execute either in a VM or a real machine - * to compare the behaviors. - */ - prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE); - - /* First test if the FI bit is being set correctly */ - MTFSF(0b11111111, FP_FI); - MFFS(fpscr); - assert((fpscr & FP_FI) != 0); - - /* Then test if the deferred exception is being called correctly */ - sigaction(SIGFPE, &sa, NULL); - - /* - * Although the VXSOFT exception has been chosen, based on test in a Power9 - * any combination of exception bit + its enabling bit should work. - * But if a different exception is chosen si_code check should - * change accordingly. - */ - MTFSF(0b11111111, FP_VE | FP_VXSOFT); - - return 1; -} diff --git a/tests/tcg/ppc64le/non_signalling_xscv.c b/tests/tcg/ppc64le/non_signalling_xscv.c deleted file mode 100644 index 836df71ef092..000000000000 --- a/tests/tcg/ppc64le/non_signalling_xscv.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include - -#define TEST(INSN, B_HI, B_LO, T_HI, T_LO) \ - do { \ - uint64_t th, tl, bh = B_HI, bl = B_LO; \ - asm("mtvsrd 32, %2\n\t" \ - "mtvsrd 33, %3\n\t" \ - "xxmrghd 32, 32, 33\n\t" \ - INSN " 32, 32\n\t" \ - "mfvsrd %0, 32\n\t" \ - "xxswapd 32, 32\n\t" \ - "mfvsrd %1, 32\n\t" \ - : "=r" (th), "=r" (tl) \ - : "r" (bh), "r" (bl) \ - : "v0", "v1"); \ - printf(INSN "(0x%016" PRIx64 "%016" PRIx64 ") = 0x%016" PRIx64 \ - "%016" PRIx64 "\n", bh, bl, th, tl); \ - assert(th == T_HI && tl == T_LO); \ - } while (0) - -int main(void) -{ - /* SNaN shouldn't be silenced */ - TEST("xscvspdpn", 0x7fbfffff00000000ULL, 0x0, 0x7ff7ffffe0000000ULL, 0x0); - TEST("xscvdpspn", 0x7ff7ffffffffffffULL, 0x0, 0x7fbfffff7fbfffffULL, 0x0); - - /* - * SNaN inputs having no significant bits in the upper 23 bits of the - * signifcand will return Infinity as the result. - */ - TEST("xscvdpspn", 0x7ff000001fffffffULL, 0x0, 0x7f8000007f800000ULL, 0x0); - - return 0; -} diff --git a/tests/tcg/ppc64le/signal_save_restore_xer.c b/tests/tcg/ppc64le/signal_save_restore_xer.c deleted file mode 100644 index 9227f4f45551..000000000000 --- a/tests/tcg/ppc64le/signal_save_restore_xer.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include - -#define XER_SO (1 << 31) -#define XER_OV (1 << 30) -#define XER_CA (1 << 29) -#define XER_OV32 (1 << 19) -#define XER_CA32 (1 << 18) - -uint64_t saved; - -void sigtrap_handler(int sig, siginfo_t *si, void *ucontext) -{ - ucontext_t *uc = ucontext; - uc->uc_mcontext.regs->nip += 4; - saved = uc->uc_mcontext.regs->xer; - uc->uc_mcontext.regs->xer |= XER_OV | XER_OV32; -} - -int main(void) -{ - uint64_t initial = XER_CA | XER_CA32, restored; - struct sigaction sa = { - .sa_sigaction = sigtrap_handler, - .sa_flags = SA_SIGINFO - }; - - sigaction(SIGTRAP, &sa, NULL); - - asm("mtspr 1, %1\n\t" - "trap\n\t" - "mfspr %0, 1\n\t" - : "=r" (restored) - : "r" (initial)); - - assert(saved == initial); - assert(restored == (XER_OV | XER_OV32 | XER_CA | XER_CA32)); - - return 0; -} diff --git a/tests/tcg/ppc64le/xxspltw.c b/tests/tcg/ppc64le/xxspltw.c deleted file mode 100644 index 4cff78bfdc8d..000000000000 --- a/tests/tcg/ppc64le/xxspltw.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include - -#define WORD_A 0xAAAAAAAAUL -#define WORD_B 0xBBBBBBBBUL -#define WORD_C 0xCCCCCCCCUL -#define WORD_D 0xDDDDDDDDUL - -#define DWORD_HI (WORD_A << 32 | WORD_B) -#define DWORD_LO (WORD_C << 32 | WORD_D) - -#define TEST(HI, LO, UIM, RES) \ - do { \ - union { \ - uint64_t u; \ - double f; \ - } h = { .u = HI }, l = { .u = LO }; \ - /* \ - * Use a pair of FPRs to load the VSR avoiding insns \ - * newer than xxswapd. \ - */ \ - asm("xxmrghd 32, %0, %1\n\t" \ - "xxspltw 32, 32, %2\n\t" \ - "xxmrghd %0, 32, %0\n\t" \ - "xxswapd 32, 32\n\t" \ - "xxmrghd %1, 32, %1\n\t" \ - : "+f" (h.f), "+f" (l.f) \ - : "i" (UIM) \ - : "v0"); \ - printf("xxspltw(0x%016" PRIx64 "%016" PRIx64 ", %d) =" \ - " %016" PRIx64 "%016" PRIx64 "\n", HI, LO, UIM, \ - h.u, l.u); \ - assert(h.u == (RES)); \ - assert(l.u == (RES)); \ - } while (0) - -int main(void) -{ - TEST(DWORD_HI, DWORD_LO, 0, WORD_A << 32 | WORD_A); - TEST(DWORD_HI, DWORD_LO, 1, WORD_B << 32 | WORD_B); - TEST(DWORD_HI, DWORD_LO, 2, WORD_C << 32 | WORD_C); - TEST(DWORD_HI, DWORD_LO, 3, WORD_D << 32 | WORD_D); - return 0; -} diff --git a/tests/tcg/riscv64/Makefile.target b/tests/tcg/riscv64/Makefile.target deleted file mode 100644 index d41bf6d60d18..000000000000 --- a/tests/tcg/riscv64/Makefile.target +++ /dev/null @@ -1,5 +0,0 @@ -# -*- Mode: makefile -*- -# RISC-V specific tweaks - -VPATH += $(SRC_PATH)/tests/tcg/riscv64 -TESTS += test-div diff --git a/tests/tcg/riscv64/semicall.h b/tests/tcg/riscv64/semicall.h deleted file mode 100644 index f8c88f32dc58..000000000000 --- a/tests/tcg/riscv64/semicall.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Semihosting Tests - RiscV64 Helper - * - * Copyright (c) 2021 - * Written by Alex Bennée - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -uintptr_t __semi_call(uintptr_t type, uintptr_t arg0) -{ - register uintptr_t t asm("a0") = type; - register uintptr_t a0 asm("a1") = arg0; - asm(".option norvc\n\t" - ".balign 16\n\t" - "slli zero, zero, 0x1f\n\t" - "ebreak\n\t" - "srai zero, zero, 0x7\n\t" - : "=r" (t) - : "r" (t), "r" (a0)); - return t; -} diff --git a/tests/tcg/riscv64/test-div.c b/tests/tcg/riscv64/test-div.c deleted file mode 100644 index a90480be3f07..000000000000 --- a/tests/tcg/riscv64/test-div.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include - -struct TestS { - long x, y, q, r; -}; - -static struct TestS test_s[] = { - { 4, 2, 2, 0 }, /* normal cases */ - { 9, 7, 1, 2 }, - { 0, 0, -1, 0 }, /* div by zero cases */ - { 9, 0, -1, 9 }, - { LONG_MIN, -1, LONG_MIN, 0 }, /* overflow case */ -}; - -struct TestU { - unsigned long x, y, q, r; -}; - -static struct TestU test_u[] = { - { 4, 2, 2, 0 }, /* normal cases */ - { 9, 7, 1, 2 }, - { 0, 0, ULONG_MAX, 0 }, /* div by zero cases */ - { 9, 0, ULONG_MAX, 9 }, -}; - -#define ARRAY_SIZE(X) (sizeof(X) / sizeof(*(X))) - -int main (void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(test_s); i++) { - long q, r; - - asm("div %0, %2, %3\n\t" - "rem %1, %2, %3" - : "=&r" (q), "=r" (r) - : "r" (test_s[i].x), "r" (test_s[i].y)); - - assert(q == test_s[i].q); - assert(r == test_s[i].r); - } - - for (i = 0; i < ARRAY_SIZE(test_u); i++) { - unsigned long q, r; - - asm("divu %0, %2, %3\n\t" - "remu %1, %2, %3" - : "=&r" (q), "=r" (r) - : "r" (test_u[i].x), "r" (test_u[i].y)); - - assert(q == test_u[i].q); - assert(r == test_u[i].r); - } - - return 0; -} diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target deleted file mode 100644 index f0d474a24561..000000000000 --- a/tests/tcg/s390x/Makefile.target +++ /dev/null @@ -1,38 +0,0 @@ -S390X_SRC=$(SRC_PATH)/tests/tcg/s390x -VPATH+=$(S390X_SRC) -CFLAGS+=-march=zEC12 -m64 -TESTS+=hello-s390x -TESTS+=csst -TESTS+=ipm -TESTS+=exrl-trt -TESTS+=exrl-trtr -TESTS+=pack -TESTS+=mie3-compl -TESTS+=mie3-mvcrl -TESTS+=mie3-sel -TESTS+=mvo -TESTS+=mvc -TESTS+=shift -TESTS+=trap -TESTS+=signals-s390x -TESTS+=branch-relative-long - -ifneq ($(HAVE_GDB_BIN),) -GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py - -run-gdbstub-signals-s390x: signals-s390x - $(call run-test, $@, $(GDB_SCRIPT) \ - --gdb $(HAVE_GDB_BIN) \ - --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ - --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \ - "mixing signals and debugging on s390x") - -EXTRA_RUNS += run-gdbstub-signals-s390x -endif - -# MVX versions of sha512 -sha512-mvx: CFLAGS=-march=z13 -mvx -O3 -sha512-mvx: sha512.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -TESTS+=sha512-mvx diff --git a/tests/tcg/s390x/branch-relative-long.c b/tests/tcg/s390x/branch-relative-long.c deleted file mode 100644 index 94219afcadc3..000000000000 --- a/tests/tcg/s390x/branch-relative-long.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include - -#define DEFINE_ASM(_name, _code) \ - extern const char _name[]; \ - extern const char _name ## _end[]; \ - asm(" .globl " #_name "\n" \ - #_name ":\n" \ - " " _code "\n" \ - " .globl " #_name "_end\n" \ - #_name "_end:\n"); - -DEFINE_ASM(br_r14, "br %r14"); -DEFINE_ASM(brasl_r0, "brasl %r0,.-0x100000000"); -DEFINE_ASM(brcl_0xf, "brcl 0xf,.-0x100000000"); - -struct test { - const char *code; - const char *code_end; -}; - -static const struct test tests[] = { - { - .code = brasl_r0, - .code_end = brasl_r0_end, - }, - { - .code = brcl_0xf, - .code_end = brcl_0xf_end, - }, -}; - -int main(void) -{ - unsigned char *buf; - size_t length = 0; - size_t i; - - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - size_t test_length = 0x100000000 + (tests[i].code_end - tests[i].code); - - if (test_length > length) { - length = test_length; - } - } - - buf = mmap(NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); - if (buf == MAP_FAILED) { - perror("SKIP: mmap() failed"); - return 0; - } - - memcpy(buf, br_r14, br_r14_end - br_r14); - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - void (*code)(void) = (void *)(buf + 0x100000000); - - memcpy(code, tests[i].code, tests[i].code_end - tests[i].code); - code(); - memset(code, 0, tests[i].code_end - tests[i].code); - } - - munmap(buf, length); - - return 0; -} diff --git a/tests/tcg/s390x/csst.c b/tests/tcg/s390x/csst.c deleted file mode 100644 index 084d80af49f3..000000000000 --- a/tests/tcg/s390x/csst.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -int main(void) -{ - uint64_t parmlist[] __attribute__((aligned(16))) = { - 0xfedcba9876543210ull, - 0, - 0x7777777777777777ull, - 0, - }; - uint64_t op1 = 0x0123456789abcdefull; - uint64_t op2 = 0; - uint64_t op3 = op1; - uint64_t cc; - - asm volatile( - " lghi %%r0,%[flags]\n" - " la %%r1,%[parmlist]\n" - " csst %[op1],%[op2],%[op3]\n" - " ipm %[cc]\n" - : [op1] "+m" (op1), - [op2] "+m" (op2), - [op3] "+r" (op3), - [cc] "=r" (cc) - : [flags] "K" (0x0301), - [parmlist] "m" (parmlist) - : "r0", "r1", "cc", "memory"); - cc = (cc >> 28) & 3; - if (cc) { - write(1, "bad cc\n", 7); - return 1; - } - if (op1 != parmlist[0]) { - write(1, "bad op1\n", 8); - return 1; - } - if (op2 != parmlist[2]) { - write(1, "bad op2\n", 8); - return 1; - } - return 0; -} diff --git a/tests/tcg/s390x/exrl-trt.c b/tests/tcg/s390x/exrl-trt.c deleted file mode 100644 index 451f777b9d9c..000000000000 --- a/tests/tcg/s390x/exrl-trt.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -int main(void) -{ - char op1[] = "hello"; - char op2[256]; - register uint64_t r1 asm("r1") = 0xffffffffffffffffull; - register uint64_t r2 asm("r2") = 0xffffffffffffffffull; - uint64_t cc; - int i; - - for (i = 0; i < 256; i++) { - if (i == 0) { - op2[i] = 0xaa; - } else { - op2[i] = 0; - } - } - asm volatile( - " j 2f\n" - "1: trt 0(1,%[op1]),%[op2]\n" - "2: exrl %[op1_len],1b\n" - " ipm %[cc]\n" - : [r1] "+r" (r1), - [r2] "+r" (r2), - [cc] "=r" (cc) - : [op1] "a" (&op1), - [op1_len] "a" (5), - [op2] "Q" (op2) - : "cc"); - cc = (cc >> 28) & 3; - if (cc != 2) { - write(1, "bad cc\n", 7); - return 1; - } - if ((char *)r1 != &op1[5]) { - write(1, "bad r1\n", 7); - return 1; - } - if (r2 != 0xffffffffffffffaaull) { - write(1, "bad r2\n", 7); - return 1; - } - return 0; -} diff --git a/tests/tcg/s390x/exrl-trtr.c b/tests/tcg/s390x/exrl-trtr.c deleted file mode 100644 index 422f7f385a30..000000000000 --- a/tests/tcg/s390x/exrl-trtr.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -int main(void) -{ - char op1[] = {0, 1, 2, 3}; - char op2[256]; - register uint64_t r1 asm("r1") = 0xffffffffffffffffull; - register uint64_t r2 asm("r2") = 0xffffffffffffffffull; - uint64_t cc; - int i; - - for (i = 0; i < 256; i++) { - if (i == 1) { - op2[i] = 0xbb; - } else { - op2[i] = 0; - } - } - asm volatile( - " j 2f\n" - "1: trtr 3(1,%[op1]),%[op2]\n" - "2: exrl %[op1_len],1b\n" - " ipm %[cc]\n" - : [r1] "+r" (r1), - [r2] "+r" (r2), - [cc] "=r" (cc) - : [op1] "a" (&op1), - [op1_len] "a" (3), - [op2] "Q" (op2) - : "cc"); - cc = (cc >> 28) & 3; - if (cc != 1) { - write(1, "bad cc\n", 7); - return 1; - } - if ((char *)r1 != &op1[1]) { - write(1, "bad r1\n", 7); - return 1; - } - if (r2 != 0xffffffffffffffbbull) { - write(1, "bad r2\n", 7); - return 1; - } - return 0; -} diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py b/tests/tcg/s390x/gdbstub/test-signals-s390x.py deleted file mode 100644 index 80a284b47518..000000000000 --- a/tests/tcg/s390x/gdbstub/test-signals-s390x.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import print_function - -# -# Test that signals and debugging mix well together on s390x. -# -# This is launched via tests/guest-debug/run-test.py -# - -import gdb -import sys - -failcount = 0 - - -def report(cond, msg): - """Report success/fail of test""" - if cond: - print("PASS: %s" % (msg)) - else: - print("FAIL: %s" % (msg)) - global failcount - failcount += 1 - - -def run_test(): - """Run through the tests one by one""" - illegal_op = gdb.Breakpoint("illegal_op") - stg = gdb.Breakpoint("stg") - mvc_8 = gdb.Breakpoint("mvc_8") - - # Expect the following events: - # 1x illegal_op breakpoint - # 2x stg breakpoint, segv, breakpoint - # 2x mvc_8 breakpoint, segv, breakpoint - for _ in range(14): - gdb.execute("c") - report(illegal_op.hit_count == 1, "illegal_op.hit_count == 1") - report(stg.hit_count == 4, "stg.hit_count == 4") - report(mvc_8.hit_count == 4, "mvc_8.hit_count == 4") - - # The test must succeed. - gdb.Breakpoint("_exit") - gdb.execute("c") - status = int(gdb.parse_and_eval("$r2")) - report(status == 0, "status == 0"); - - -# -# This runs as the script it sourced (via -x, via run-test.py) -# -try: - inferior = gdb.selected_inferior() - arch = inferior.architecture() - print("ATTACHED: %s" % arch.name()) -except (gdb.error, AttributeError): - print("SKIPPING (not connected)", file=sys.stderr) - exit(0) - -if gdb.parse_and_eval("$pc") == 0: - print("SKIP: PC not set") - exit(0) - -try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - - # Run the actual tests - run_test() -except (gdb.error): - print("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - pass - -print("All tests complete: %d failures" % failcount) -exit(failcount) diff --git a/tests/tcg/s390x/hello-s390x.c b/tests/tcg/s390x/hello-s390x.c deleted file mode 100644 index 3dc0a05f2b2e..000000000000 --- a/tests/tcg/s390x/hello-s390x.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int main(void) -{ - write(1, "hello\n", 6); - return 0; -} diff --git a/tests/tcg/s390x/ipm.c b/tests/tcg/s390x/ipm.c deleted file mode 100644 index 742f3a18c5ac..000000000000 --- a/tests/tcg/s390x/ipm.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -int main(void) -{ - uint32_t op1 = 0x55555555; - uint32_t op2 = 0x44444444; - uint64_t cc = 0xffffffffffffffffull; - - asm volatile( - " clc 0(4,%[op1]),0(%[op2])\n" - " ipm %[cc]\n" - : [cc] "+r" (cc) - : [op1] "r" (&op1), - [op2] "r" (&op2) - : "cc"); - if (cc != 0xffffffff20ffffffull) { - write(1, "bad cc\n", 7); - return 1; - } - return 0; -} diff --git a/tests/tcg/s390x/mie3-compl.c b/tests/tcg/s390x/mie3-compl.c deleted file mode 100644 index 35649f3b023c..000000000000 --- a/tests/tcg/s390x/mie3-compl.c +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#define FbinOp(S, ASM) uint64_t S(uint64_t a, uint64_t b) \ -{ \ - uint64_t res = 0; \ - asm ("llihf %[res],801\n" ASM \ - : [res]"=&r"(res) : [a]"r"(a), [b]"r"(b) : "cc"); \ - return res; \ -} - -/* AND WITH COMPLEMENT */ -FbinOp(_ncrk, ".insn rrf, 0xB9F50000, %[res], %[b], %[a], 0\n") -FbinOp(_ncgrk, ".insn rrf, 0xB9E50000, %[res], %[b], %[a], 0\n") - -/* NAND */ -FbinOp(_nnrk, ".insn rrf, 0xB9740000, %[res], %[b], %[a], 0\n") -FbinOp(_nngrk, ".insn rrf, 0xB9640000, %[res], %[b], %[a], 0\n") - -/* NOT XOR */ -FbinOp(_nxrk, ".insn rrf, 0xB9770000, %[res], %[b], %[a], 0\n") -FbinOp(_nxgrk, ".insn rrf, 0xB9670000, %[res], %[b], %[a], 0\n") - -/* NOR */ -FbinOp(_nork, ".insn rrf, 0xB9760000, %[res], %[b], %[a], 0\n") -FbinOp(_nogrk, ".insn rrf, 0xB9660000, %[res], %[b], %[a], 0\n") - -/* OR WITH COMPLEMENT */ -FbinOp(_ocrk, ".insn rrf, 0xB9750000, %[res], %[b], %[a], 0\n") -FbinOp(_ocgrk, ".insn rrf, 0xB9650000, %[res], %[b], %[a], 0\n") - -int main(int argc, char *argv[]) -{ - if (_ncrk(0xFF88, 0xAA11) != 0x0000032100000011ull || - _nnrk(0xFF88, 0xAA11) != 0x00000321FFFF55FFull || - _nork(0xFF88, 0xAA11) != 0x00000321FFFF0066ull || - _nxrk(0xFF88, 0xAA11) != 0x00000321FFFFAA66ull || - _ocrk(0xFF88, 0xAA11) != 0x00000321FFFFAA77ull || - _ncgrk(0xFF88, 0xAA11) != 0x0000000000000011ull || - _nngrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFF55FFull || - _nogrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFF0066ull || - _nxgrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFFAA66ull || - _ocgrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFFAA77ull) - { - return 1; - } - - return 0; -} diff --git a/tests/tcg/s390x/mie3-mvcrl.c b/tests/tcg/s390x/mie3-mvcrl.c deleted file mode 100644 index 93c7b0a29036..000000000000 --- a/tests/tcg/s390x/mie3-mvcrl.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - - -static inline void mvcrl_8(const char *dst, const char *src) -{ - asm volatile ( - "llill %%r0, 8\n" - ".insn sse, 0xE50A00000000, 0(%[dst]), 0(%[src])" - : : [dst] "d" (dst), [src] "d" (src) - : "r0", "memory"); -} - - -int main(int argc, char *argv[]) -{ - const char *alpha = "abcdefghijklmnop"; - - /* array missing 'i' */ - char tstr[17] = "abcdefghjklmnop\0" ; - - /* mvcrl reference use: 'open a hole in an array' */ - mvcrl_8(tstr + 9, tstr + 8); - - /* place missing 'i' */ - tstr[8] = 'i'; - - return strncmp(alpha, tstr, 16ul); -} diff --git a/tests/tcg/s390x/mie3-sel.c b/tests/tcg/s390x/mie3-sel.c deleted file mode 100644 index 0dfd532ed43e..000000000000 --- a/tests/tcg/s390x/mie3-sel.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - - -#define Fi3(S, ASM) uint64_t S(uint64_t a, uint64_t b, uint64_t c) \ -{ \ -asm volatile ( \ - "ltgr %[c], %[c]\n" \ - ASM \ - : [c] "+r" (c) \ - : [a] "r" (a) \ - , [b] "r" (b) \ -); \ - return c; \ -} - -Fi3 (_selre, ".insn rrf, 0xB9F00000, %[c], %[b], %[a], 8\n") -Fi3 (_selgrz, ".insn rrf, 0xB9E30000, %[c], %[b], %[a], 8\n") -Fi3 (_selfhrnz, ".insn rrf, 0xB9C00000, %[c], %[b], %[a], 7\n") - - -int main(int argc, char *argv[]) -{ - uint64_t a = ~0, b = ~0, c = ~0; - - a = _selre(0x066600000066ull, 0x066600000006ull, a); - b = _selgrz(0xF00D00000005ull, 0xF00D00000055ull, b); - c = _selfhrnz(0x043200000044ull, 0x065400000004ull, c); - - return (int) ( - (0xFFFFFFFF00000066ull != a) || - (0x0000F00D00000005ull != b) || - (0x00000654FFFFFFFFull != c)); -} diff --git a/tests/tcg/s390x/mvc.c b/tests/tcg/s390x/mvc.c deleted file mode 100644 index 7ae4c445500c..000000000000 --- a/tests/tcg/s390x/mvc.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -jmp_buf jmp_env; - -static void handle_sigsegv(int sig) -{ - siglongjmp(jmp_env, 1); -} - -#define ALLOC_SIZE (2 * 4096) - -static inline void mvc_256(const char *dst, const char *src) -{ - asm volatile ( - " mvc 0(256,%[dst]),0(%[src])\n" - : - : [dst] "a" (dst), - [src] "a" (src) - : "memory"); -} - -int main(void) -{ - char *src, *dst; - int i; - - /* register the SIGSEGV handler */ - if (signal(SIGSEGV, handle_sigsegv) == SIG_ERR) { - fprintf(stderr, "SIGSEGV not registered\n"); - return 1; - } - - /* prepare the buffers - two consecutive pages */ - src = valloc(ALLOC_SIZE); - dst = valloc(ALLOC_SIZE); - memset(src, 0xff, ALLOC_SIZE); - memset(dst, 0x0, ALLOC_SIZE); - - /* protect the second pages */ - if (mprotect(src + 4096, 4096, PROT_NONE) || - mprotect(dst + 4096, 4096, PROT_NONE)) { - fprintf(stderr, "mprotect failed\n"); - return 1; - } - - /* fault on second destination page */ - if (sigsetjmp(jmp_env, 1) == 0) { - mvc_256(dst + 4096 - 128, src); - fprintf(stderr, "fault not triggered\n"); - return 1; - } - - /* fault on second source page */ - if (sigsetjmp(jmp_env, 1) == 0) { - mvc_256(dst, src + 4096 - 128); - fprintf(stderr, "fault not triggered\n"); - return 1; - } - - /* fault on second source and second destination page */ - if (sigsetjmp(jmp_env, 1) == 0) { - mvc_256(dst + 4096 - 128, src + 4096 - 128); - fprintf(stderr, "fault not triggered\n"); - return 1; - } - - /* restore permissions */ - if (mprotect(src + 4096, 4096, PROT_READ | PROT_WRITE) || - mprotect(dst + 4096, 4096, PROT_READ | PROT_WRITE)) { - fprintf(stderr, "mprotect failed\n"); - return 1; - } - - /* no data must be touched during the faults */ - for (i = 0; i < ALLOC_SIZE; i++) { - if (src[i] != 0xff || dst[i]) { - fprintf(stderr, "data modified during a fault\n"); - return 1; - } - } - - /* test if MVC works now correctly accross page boundaries */ - mvc_256(dst + 4096 - 128, src + 4096 - 128); - for (i = 0; i < ALLOC_SIZE; i++) { - if (src[i] != 0xff) { - fprintf(stderr, "src modified\n"); - return 1; - } - if (i < 4096 - 128 || i >= 4096 + 128) { - if (dst[i]) { - fprintf(stderr, "wrong dst modified\n"); - return 1; - } - } else { - if (dst[i] != 0xff) { - fprintf(stderr, "wrong data moved\n"); - return 1; - } - } - } - - return 0; -} diff --git a/tests/tcg/s390x/mvo.c b/tests/tcg/s390x/mvo.c deleted file mode 100644 index 0c3ecdde2eae..000000000000 --- a/tests/tcg/s390x/mvo.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include - -int main(void) -{ - uint8_t dest[6] = {0xff, 0x77, 0x88, 0x99, 0x0c, 0xff}; - uint8_t src[5] = {0xee, 0x12, 0x34, 0x56, 0xee}; - uint8_t expected[6] = {0xff, 0x01, 0x23, 0x45, 0x6c, 0xff}; - int i; - - asm volatile ( - " mvo 0(4,%[dest]),0(3,%[src])\n" - : - : [dest] "a" (dest + 1), - [src] "a" (src + 1) - : "memory"); - - for (i = 0; i < sizeof(expected); i++) { - if (dest[i] != expected[i]) { - fprintf(stderr, "bad data\n"); - return 1; - } - } - return 0; -} diff --git a/tests/tcg/s390x/pack.c b/tests/tcg/s390x/pack.c deleted file mode 100644 index 55e7e214e83e..000000000000 --- a/tests/tcg/s390x/pack.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main(void) -{ - char data[] = {0xaa, 0xaa, 0xf1, 0xf2, 0xf3, 0xc4, 0xaa, 0xaa}; - char exp[] = {0xaa, 0xaa, 0x00, 0x01, 0x23, 0x4c, 0xaa, 0xaa}; - int i; - - asm volatile( - " pack 2(4,%[data]),2(4,%[data])\n" - : - : [data] "a" (&data[0]) - : "memory"); - for (i = 0; i < 8; i++) { - if (data[i] != exp[i]) { - write(1, "bad data\n", 9); - return 1; - } - } - return 0; -} diff --git a/tests/tcg/s390x/shift.c b/tests/tcg/s390x/shift.c deleted file mode 100644 index 29594fec5c06..000000000000 --- a/tests/tcg/s390x/shift.c +++ /dev/null @@ -1,270 +0,0 @@ -#include -#include -#include - -#define DEFINE_SHIFT_SINGLE_COMMON(_name, _insn_str) \ - static uint64_t _name(uint64_t op1, uint64_t op2, uint64_t *cc) \ - { \ - asm(" sll %[cc],28\n" \ - " spm %[cc]\n" \ - " " _insn_str "\n" \ - " ipm %[cc]\n" \ - " srl %[cc],28" \ - : [op1] "+&r" (op1), \ - [cc] "+&r" (*cc) \ - : [op2] "r" (op2) \ - : "cc"); \ - return op1; \ - } -#define DEFINE_SHIFT_SINGLE_2(_insn, _offset) \ - DEFINE_SHIFT_SINGLE_COMMON(_insn ## _ ## _offset, \ - #_insn " %[op1]," #_offset "(%[op2])") -#define DEFINE_SHIFT_SINGLE_3(_insn, _offset) \ - DEFINE_SHIFT_SINGLE_COMMON(_insn ## _ ## _offset, \ - #_insn " %[op1],%[op1]," #_offset "(%[op2])") -#define DEFINE_SHIFT_DOUBLE(_insn, _offset) \ - static uint64_t _insn ## _ ## _offset(uint64_t op1, uint64_t op2, \ - uint64_t *cc) \ - { \ - uint32_t op1h = op1 >> 32; \ - uint32_t op1l = op1 & 0xffffffff; \ - register uint32_t r2 asm("2") = op1h; \ - register uint32_t r3 asm("3") = op1l; \ - \ - asm(" sll %[cc],28\n" \ - " spm %[cc]\n" \ - " " #_insn " %[r2]," #_offset "(%[op2])\n" \ - " ipm %[cc]\n" \ - " srl %[cc],28" \ - : [r2] "+&r" (r2), \ - [r3] "+&r" (r3), \ - [cc] "+&r" (*cc) \ - : [op2] "r" (op2) \ - : "cc"); \ - op1h = r2; \ - op1l = r3; \ - return (((uint64_t)op1h) << 32) | op1l; \ - } - -DEFINE_SHIFT_SINGLE_3(rll, 0x4cf3b); -DEFINE_SHIFT_SINGLE_3(rllg, 0x697c9); -DEFINE_SHIFT_SINGLE_2(sla, 0x4b0); -DEFINE_SHIFT_SINGLE_2(sla, 0xd54); -DEFINE_SHIFT_SINGLE_3(slak, 0x2832c); -DEFINE_SHIFT_SINGLE_3(slag, 0x66cc4); -DEFINE_SHIFT_SINGLE_3(slag, 0xd54); -DEFINE_SHIFT_SINGLE_2(sll, 0xd04); -DEFINE_SHIFT_SINGLE_3(sllk, 0x2699f); -DEFINE_SHIFT_SINGLE_3(sllg, 0x59df9); -DEFINE_SHIFT_SINGLE_2(sra, 0x67e); -DEFINE_SHIFT_SINGLE_3(srak, 0x60943); -DEFINE_SHIFT_SINGLE_3(srag, 0x6b048); -DEFINE_SHIFT_SINGLE_2(srl, 0x035); -DEFINE_SHIFT_SINGLE_3(srlk, 0x43dfc); -DEFINE_SHIFT_SINGLE_3(srlg, 0x27227); -DEFINE_SHIFT_DOUBLE(slda, 0x38b); -DEFINE_SHIFT_DOUBLE(sldl, 0x031); -DEFINE_SHIFT_DOUBLE(srda, 0x36f); -DEFINE_SHIFT_DOUBLE(srdl, 0x99a); - -struct shift_test { - const char *name; - uint64_t (*insn)(uint64_t, uint64_t, uint64_t *); - uint64_t op1; - uint64_t op2; - uint64_t exp_result; - uint64_t exp_cc; -}; - -static const struct shift_test tests[] = { - { - .name = "rll", - .insn = rll_0x4cf3b, - .op1 = 0xecbd589a45c248f5ull, - .op2 = 0x62e5508ccb4c99fdull, - .exp_result = 0xecbd589af545c248ull, - .exp_cc = 0, - }, - { - .name = "rllg", - .insn = rllg_0x697c9, - .op1 = 0xaa2d54c1b729f7f4ull, - .op2 = 0x5ffcf7465f5cd71full, - .exp_result = 0x29f7f4aa2d54c1b7ull, - .exp_cc = 0, - }, - { - .name = "sla-1", - .insn = sla_0x4b0, - .op1 = 0x8bf21fb67cca0e96ull, - .op2 = 0x3ddf2f53347d3030ull, - .exp_result = 0x8bf21fb600000000ull, - .exp_cc = 3, - }, - { - .name = "sla-2", - .insn = sla_0xd54, - .op1 = 0xe4faaed5def0e926ull, - .op2 = 0x18d586fab239cbeeull, - .exp_result = 0xe4faaed5fbc3a498ull, - .exp_cc = 3, - }, - { - .name = "slak", - .insn = slak_0x2832c, - .op1 = 0x7300bf78707f09f9ull, - .op2 = 0x4d193b85bb5cb39bull, - .exp_result = 0x7300bf783f84fc80ull, - .exp_cc = 3, - }, - { - .name = "slag-1", - .insn = slag_0x66cc4, - .op1 = 0xe805966de1a77762ull, - .op2 = 0x0e92953f6aa91c6bull, - .exp_result = 0xbbb1000000000000ull, - .exp_cc = 3, - }, - { - .name = "slag-2", - .insn = slag_0xd54, - .op1 = 0xdef0e92600000000ull, - .op2 = 0x18d586fab239cbeeull, - .exp_result = 0xfbc3a49800000000ull, - .exp_cc = 3, - }, - { - .name = "sll", - .insn = sll_0xd04, - .op1 = 0xb90281a3105939dfull, - .op2 = 0xb5e4df7e082e4c5eull, - .exp_result = 0xb90281a300000000ull, - .exp_cc = 0, - }, - { - .name = "sllk", - .insn = sllk_0x2699f, - .op1 = 0x777c6cf116f99557ull, - .op2 = 0xe0556cf112e5a458ull, - .exp_result = 0x777c6cf100000000ull, - .exp_cc = 0, - }, - { - .name = "sllg", - .insn = sllg_0x59df9, - .op1 = 0xcdf86cbfbc0f3557ull, - .op2 = 0x325a45acf99c6d3dull, - .exp_result = 0x55c0000000000000ull, - .exp_cc = 0, - }, - { - .name = "sra", - .insn = sra_0x67e, - .op1 = 0xb878f048d5354183ull, - .op2 = 0x9e27d13195931f79ull, - .exp_result = 0xb878f048ffffffffull, - .exp_cc = 1, - }, - { - .name = "srak", - .insn = srak_0x60943, - .op1 = 0xb6ceb5a429cedb35ull, - .op2 = 0x352354900ae34d7aull, - .exp_result = 0xb6ceb5a400000000ull, - .exp_cc = 0, - }, - { - .name = "srag", - .insn = srag_0x6b048, - .op1 = 0xd54dd4468676c63bull, - .op2 = 0x84d026db7b4dca28ull, - .exp_result = 0xffffffffffffd54dull, - .exp_cc = 1, - }, - { - .name = "srl", - .insn = srl_0x035, - .op1 = 0x09be503ef826815full, - .op2 = 0xbba8d1a0e542d5c1ull, - .exp_result = 0x9be503e00000000ull, - .exp_cc = 0, - }, - { - .name = "srlk", - .insn = srlk_0x43dfc, - .op1 = 0x540d6c8de71aee2aull, - .op2 = 0x0000000000000000ull, - .exp_result = 0x540d6c8d00000000ull, - .exp_cc = 0, - }, - { - .name = "srlg", - .insn = srlg_0x27227, - .op1 = 0x26f7123c1c447a34ull, - .op2 = 0x0000000000000000ull, - .exp_result = 0x00000000004dee24ull, - .exp_cc = 0, - }, - { - .name = "slda", - .insn = slda_0x38b, - .op1 = 0x7988f722dd5bbe7cull, - .op2 = 0x9aed3f95b4d78cc2ull, - .exp_result = 0x1ee45bab77cf8000ull, - .exp_cc = 3, - }, - { - .name = "sldl", - .insn = sldl_0x031, - .op1 = 0xaae2918dce2b049aull, - .op2 = 0x0000000000000000ull, - .exp_result = 0x0934000000000000ull, - .exp_cc = 0, - }, - { - .name = "srda", - .insn = srda_0x36f, - .op1 = 0x0cd4ed9228a50978ull, - .op2 = 0x72b046f0848b8cc9ull, - .exp_result = 0x000000000000000cull, - .exp_cc = 2, - }, - { - .name = "srdl", - .insn = srdl_0x99a, - .op1 = 0x1018611c41689a1dull, - .op2 = 0x2907e150c50ba319ull, - .exp_result = 0x0000000000000203ull, - .exp_cc = 0, - }, -}; - -int main(void) -{ - int ret = 0; - size_t i; - - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { - uint64_t result; - uint64_t cc = 0; - - result = tests[i].insn(tests[i].op1, tests[i].op2, &cc); - if (result != tests[i].exp_result) { - fprintf(stderr, - "bad %s result:\n" - "actual = 0x%" PRIx64 "\n" - "expected = 0x%" PRIx64 "\n", - tests[i].name, result, tests[i].exp_result); - ret = 1; - } - if (cc != tests[i].exp_cc) { - fprintf(stderr, - "bad %s cc:\n" - "actual = %" PRIu64 "\n" - "expected = %" PRIu64 "\n", - tests[i].name, cc, tests[i].exp_cc); - ret = 1; - } - } - return ret; -} diff --git a/tests/tcg/s390x/signals-s390x.c b/tests/tcg/s390x/signals-s390x.c deleted file mode 100644 index dc2f8ee59ac7..000000000000 --- a/tests/tcg/s390x/signals-s390x.c +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* - * Various instructions that generate SIGILL and SIGSEGV. They could have been - * defined in a separate .s file, but this would complicate the build, so the - * inline asm is used instead. - */ - -void illegal_op(void); -void after_illegal_op(void); -asm(".globl\tillegal_op\n" - "illegal_op:\t.byte\t0x00,0x00\n" - "\t.globl\tafter_illegal_op\n" - "after_illegal_op:\tbr\t%r14"); - -void stg(void *dst, unsigned long src); -asm(".globl\tstg\n" - "stg:\tstg\t%r3,0(%r2)\n" - "\tbr\t%r14"); - -void mvc_8(void *dst, void *src); -asm(".globl\tmvc_8\n" - "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n" - "\tbr\t%r14"); - -static void safe_puts(const char *s) -{ - write(0, s, strlen(s)); - write(0, "\n", 1); -} - -enum exception { - exception_operation, - exception_translation, - exception_protection, -}; - -static struct { - int sig; - void *addr; - unsigned long psw_addr; - enum exception exception; -} expected; - -static void handle_signal(int sig, siginfo_t *info, void *ucontext) -{ - void *page; - int err; - - if (sig != expected.sig) { - safe_puts("[ FAILED ] wrong signal"); - _exit(1); - } - - if (info->si_addr != expected.addr) { - safe_puts("[ FAILED ] wrong si_addr"); - _exit(1); - } - - if (((ucontext_t *)ucontext)->uc_mcontext.psw.addr != expected.psw_addr) { - safe_puts("[ FAILED ] wrong psw.addr"); - _exit(1); - } - - switch (expected.exception) { - case exception_translation: - page = mmap(expected.addr, 4096, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - if (page != expected.addr) { - safe_puts("[ FAILED ] mmap() failed"); - _exit(1); - } - break; - case exception_protection: - err = mprotect(expected.addr, 4096, PROT_READ | PROT_WRITE); - if (err != 0) { - safe_puts("[ FAILED ] mprotect() failed"); - _exit(1); - } - break; - default: - break; - } -} - -static void check_sigsegv(void *func, enum exception exception, - unsigned long val) -{ - int prot; - unsigned long *page; - unsigned long *addr; - int err; - - prot = exception == exception_translation ? PROT_NONE : PROT_READ; - page = mmap(NULL, 4096, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - assert(page != MAP_FAILED); - if (exception == exception_translation) { - /* Hopefully nothing will be mapped at this address. */ - err = munmap(page, 4096); - assert(err == 0); - } - addr = page + (val & 0x1ff); - - expected.sig = SIGSEGV; - expected.addr = page; - expected.psw_addr = (unsigned long)func; - expected.exception = exception; - if (func == stg) { - stg(addr, val); - } else { - assert(func == mvc_8); - mvc_8(addr, &val); - } - assert(*addr == val); - - err = munmap(page, 4096); - assert(err == 0); -} - -int main(void) -{ - struct sigaction act; - int err; - - memset(&act, 0, sizeof(act)); - act.sa_sigaction = handle_signal; - act.sa_flags = SA_SIGINFO; - err = sigaction(SIGILL, &act, NULL); - assert(err == 0); - err = sigaction(SIGSEGV, &act, NULL); - assert(err == 0); - - safe_puts("[ RUN ] Operation exception"); - expected.sig = SIGILL; - expected.addr = illegal_op; - expected.psw_addr = (unsigned long)after_illegal_op; - expected.exception = exception_operation; - illegal_op(); - safe_puts("[ OK ]"); - - safe_puts("[ RUN ] Translation exception from stg"); - check_sigsegv(stg, exception_translation, 42); - safe_puts("[ OK ]"); - - safe_puts("[ RUN ] Translation exception from mvc"); - check_sigsegv(mvc_8, exception_translation, 4242); - safe_puts("[ OK ]"); - - safe_puts("[ RUN ] Protection exception from stg"); - check_sigsegv(stg, exception_protection, 424242); - safe_puts("[ OK ]"); - - safe_puts("[ RUN ] Protection exception from mvc"); - check_sigsegv(mvc_8, exception_protection, 42424242); - safe_puts("[ OK ]"); - - safe_puts("[ PASSED ]"); - - _exit(0); -} diff --git a/tests/tcg/s390x/trap.c b/tests/tcg/s390x/trap.c deleted file mode 100644 index d4c61c7f520b..000000000000 --- a/tests/tcg/s390x/trap.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2021 IBM Corp. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -static void error1(const char *filename, int line, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", filename, line); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(1); -} - -static int __chk_error(const char *filename, int line, int ret) -{ - if (ret < 0) { - error1(filename, line, "%m (ret=%d, errno=%d/%s)", - ret, errno, strerror(errno)); - } - return ret; -} - -#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) - -#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) - -int sigfpe_count; -int sigill_count; - -static void sig_handler(int sig, siginfo_t *si, void *puc) -{ - if (sig == SIGFPE) { - if (si->si_code != 0) { - error("unexpected si_code: 0x%x != 0", si->si_code); - } - ++sigfpe_count; - return; - } - - if (sig == SIGILL) { - ++sigill_count; - return; - } - - error("unexpected signal 0x%x\n", sig); -} - -int main(int argc, char **argv) -{ - sigfpe_count = sigill_count = 0; - - struct sigaction act; - - /* Set up SIG handler */ - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - chk_error(sigaction(SIGFPE, &act, NULL)); - chk_error(sigaction(SIGILL, &act, NULL)); - - uint64_t z = 0x0ull; - uint64_t lz = 0xffffffffffffffffull; - asm volatile ( - "lg %%r13,%[lz]\n" - "cgitne %%r13,0\n" /* SIGFPE */ - "lg %%r13,%[z]\n" - "cgitne %%r13,0\n" /* no trap */ - "nopr\n" - "lg %%r13,%[lz]\n" - "citne %%r13,0\n" /* SIGFPE */ - "lg %%r13,%[z]\n" - "citne %%r13,0\n" /* no trap */ - "nopr\n" - : - : [z] "m" (z), [lz] "m" (lz) - : "memory", "r13"); - - if (sigfpe_count != 2) { - error("unexpected SIGFPE count: %d != 2", sigfpe_count); - } - if (sigill_count != 0) { - error("unexpected SIGILL count: %d != 0", sigill_count); - } - - printf("PASS\n"); - return 0; -} diff --git a/tests/tcg/sh4/Makefile.target b/tests/tcg/sh4/Makefile.target deleted file mode 100644 index 35ebe6b4e39b..000000000000 --- a/tests/tcg/sh4/Makefile.target +++ /dev/null @@ -1,26 +0,0 @@ -# -*- Mode: makefile -*- -# -# SuperH specific tweaks -# - -# On sh Linux supports 4k, 8k, 16k and 64k pages (but only 4k currently works) -EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192 run-test-mmap-16384 run-test-mmap-65536 - -# This triggers failures for sh4-linux about 10% of the time. -# Random SIGSEGV at unpredictable guest address, cause unknown. -run-signals: signals - $(call skip-test, $<, "BROKEN") -run-plugin-signals-with-%: - $(call skip-test, $<, "BROKEN") - -# This test is currently broken: https://gitlab.com/qemu-project/qemu/-/issues/704 -run-linux-test: linux-test - $(call skip-test, $<, "BROKEN") -run-plugin-linux-test-with-%: - $(call skip-test, $<, "BROKEN") - -# This test is currently unreliable: https://gitlab.com/qemu-project/qemu/-/issues/856 -run-threadcount: - $(call skip-test, $<, "BROKEN") -run-plugin-threadcount-with-%: - $(call skip-test, $<, "BROKEN") diff --git a/tests/tcg/sparc64/Makefile.target b/tests/tcg/sparc64/Makefile.target deleted file mode 100644 index 408dace78394..000000000000 --- a/tests/tcg/sparc64/Makefile.target +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Mode: makefile -*- -# -# sparc specific tweaks - -# On Sparc64 Linux support 8k pages -EXTRA_RUNS+=run-test-mmap-8192 diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target deleted file mode 100644 index 5007c60ce8c8..000000000000 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ /dev/null @@ -1,26 +0,0 @@ -TESTS_PATH = $(SRC_PATH)/tests/tcg/tricore - -LDFLAGS = -T$(TESTS_PATH)/link.ld -ASFLAGS = - -TESTS += test_abs.tst -TESTS += test_bmerge.tst -TESTS += test_clz.tst -TESTS += test_dvstep.tst -TESTS += test_fadd.tst -TESTS += test_fmul.tst -TESTS += test_ftoi.tst -TESTS += test_madd.tst -TESTS += test_msub.tst -TESTS += test_muls.tst - -QEMU_OPTS += -M tricore_testboard -nographic -kernel - -%.pS: $(TESTS_PATH)/%.S - $(HOST_CC) -E -o $@ $< - -%.o: %.pS - $(AS) $(ASFLAGS) -o $@ $< - -%.tst: %.o - $(LD) $(LDFLAGS) $< -o $@ diff --git a/tests/tcg/tricore/link.ld b/tests/tcg/tricore/link.ld deleted file mode 100644 index 364bcdc00a60..000000000000 --- a/tests/tcg/tricore/link.ld +++ /dev/null @@ -1,60 +0,0 @@ -/* Default linker script, for normal executables */ -OUTPUT_FORMAT("elf32-tricore") -OUTPUT_ARCH(tricore) -ENTRY(_start) - -/* the internal ram description */ -MEMORY -{ - text_ram (rx!p): org = 0x80000000, len = 15K - data_ram (w!xp): org = 0xd0000000, len = 130K -} -/* - * Define the sizes of the user and system stacks. - */ -__USTACK_SIZE = DEFINED (__USTACK_SIZE) ? __USTACK_SIZE : 1K ; -/* - * Define the start address and the size of the context save area. - */ -__CSA_BEGIN = 0xd0000000 ; -__CSA_SIZE = 8k ; -__CSA_END = __CSA_BEGIN + __CSA_SIZE ; - -SECTIONS -{ - .text : - { - *(.text) - . = ALIGN(8); - } > text_ram - - .rodata : - { - *(.rodata) - *(.rodata1) - } > data_ram - - .data : - { - . = ALIGN(8) ; - *(.data) - *(.data.*) - . = ALIGN(8) ; - __USTACK = . + __USTACK_SIZE -768; - - } > data_ram - /* - * Allocate space for BSS sections. - */ - .bss : - { - BSS_BASE = . ; - *(.bss) - *(COMMON) - . = ALIGN(8) ; - } > data_ram - /* Make sure CSA, stack and heap addresses are properly aligned. */ - _. = ASSERT ((__CSA_BEGIN & 0x3f) == 0 , "illegal CSA start address") ; - _. = ASSERT ((__CSA_SIZE & 0x3f) == 0 , "illegal CSA size") ; - -} diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h deleted file mode 100644 index 0d76fc403a75..000000000000 --- a/tests/tcg/tricore/macros.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Helpers */ -#define LI(reg, val) \ - mov.u reg, lo:val; \ - movh DREG_TEMP_LI, up:val; \ - or reg, reg, DREG_TEMP_LI; \ - -/* Address definitions */ -#define TESTDEV_ADDR 0xf0000000 -/* Register definitions */ -#define DREG_RS1 %d0 -#define DREG_RS2 %d1 -#define DREG_RS3 %d4 -#define DREG_CALC_RESULT %d1 -#define DREG_CALC_PSW %d2 -#define DREG_CORRECT_PSW %d3 -#define DREG_TEMP_LI %d10 -#define DREG_TEMP %d11 -#define DREG_TEST_NUM %d14 -#define DREG_CORRECT_RESULT %d15 - -#define DREG_DEV_ADDR %a15 - -#define EREG_RS1 %e6 -#define EREG_RS1_LO %d6 -#define EREG_RS1_HI %d7 -#define EREG_RS2 %e8 -#define EREG_RS2_LO %d8 -#define EREG_RS2_HI %d9 -#define EREG_CALC_RESULT %e8 -#define EREG_CALC_RESULT_HI %d9 -#define EREG_CALC_RESULT_LO %d8 -#define EREG_CORRECT_RESULT_LO %d0 -#define EREG_CORRECT_RESULT_HI %d1 - -/* Test case wrappers */ -#define TEST_CASE(num, testreg, correct, code...) \ -test_ ## num: \ - code; \ - LI(DREG_CORRECT_RESULT, correct) \ - mov DREG_TEST_NUM, num; \ - jne testreg, DREG_CORRECT_RESULT, fail \ - -#define TEST_CASE_E(num, correct_lo, correct_hi, code...) \ -test_ ## num: \ - code; \ - mov DREG_TEST_NUM, num; \ - LI(EREG_CORRECT_RESULT_LO, correct_lo) \ - jne EREG_CALC_RESULT_LO, EREG_CORRECT_RESULT_LO, fail; \ - LI(EREG_CORRECT_RESULT_HI, correct_hi) \ - jne EREG_CALC_RESULT_HI, EREG_CORRECT_RESULT_HI, fail; - -#define TEST_CASE_PSW(num, testreg, correct, correct_psw, code...) \ -test_ ## num: \ - code; \ - LI(DREG_CORRECT_RESULT, correct) \ - mov DREG_TEST_NUM, num; \ - jne testreg, DREG_CORRECT_RESULT, fail; \ - mfcr DREG_CALC_PSW, $psw; \ - LI(DREG_CORRECT_PSW, correct_psw) \ - mov DREG_TEST_NUM, num; \ - jne DREG_CALC_PSW, DREG_CORRECT_PSW, fail; - -/* Actual test case type - * e.g inst %dX, %dY -> TEST_D_D - * inst %dX, %dY, %dZ -> TEST_D_DD - * inst %eX, %dY, %dZ -> TEST_E_DD - */ -#define TEST_D_D(insn, num, result, rs1) \ - TEST_CASE(num, DREG_CALC_RESULT, result, \ - LI(DREG_RS1, rs1); \ - insn DREG_CALC_RESULT, DREG_RS1; \ - ) - -#define TEST_D_D_PSW(insn, num, result, psw, rs1) \ - TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ - LI(DREG_RS1, rs1); \ - rstv; \ - insn DREG_CORRECT_RESULT, DREG_RS1; \ - ) - -#define TEST_D_DD_PSW(insn, num, result, psw, rs1, rs2) \ - TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ - LI(DREG_RS1, rs1); \ - LI(DREG_RS2, rs2); \ - rstv; \ - insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2; \ - ) - -#define TEST_D_DDD_PSW(insn, num, result, psw, rs1, rs2, rs3) \ - TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ - LI(DREG_RS1, rs1); \ - LI(DREG_RS2, rs2); \ - LI(DREG_RS3, rs3); \ - rstv; \ - insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, DREG_RS3; \ - ) - -#define TEST_D_DDI_PSW(insn, num, result, psw, rs1, rs2, imm) \ - TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ - LI(DREG_RS1, rs1); \ - LI(DREG_RS2, rs2); \ - rstv; \ - insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm; \ - ) - -#define TEST_E_ED(insn, num, res_hi, res_lo, rs1_hi, rs1_lo, rs2) \ - TEST_CASE_E(num, res_lo, res_hi, \ - LI(EREG_RS1_LO, rs1_lo); \ - LI(EREG_RS1_HI, rs1_hi); \ - LI(DREG_RS2, rs2); \ - insn EREG_CALC_RESULT, EREG_RS1, DREG_RS2; \ - ) - -/* Pass/Fail handling part */ -#define TEST_PASSFAIL \ - j pass; \ -fail: \ - LI(DREG_TEMP, TESTDEV_ADDR) \ - mov.a DREG_DEV_ADDR, DREG_TEMP; \ - st.w [DREG_DEV_ADDR], DREG_TEST_NUM;\ - debug; \ - j fail; \ -pass: \ - LI(DREG_TEMP, TESTDEV_ADDR) \ - mov.a DREG_DEV_ADDR, DREG_TEMP; \ - mov DREG_TEST_NUM, 0; \ - st.w [DREG_DEV_ADDR], DREG_TEST_NUM;\ - debug; \ - j pass; diff --git a/tests/tcg/tricore/test_abs.S b/tests/tcg/tricore/test_abs.S deleted file mode 100644 index e42240159a83..000000000000 --- a/tests/tcg/tricore/test_abs.S +++ /dev/null @@ -1,7 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_D(abs, 1, 0, 0) - - TEST_PASSFAIL diff --git a/tests/tcg/tricore/test_bmerge.S b/tests/tcg/tricore/test_bmerge.S deleted file mode 100644 index 8a0fa6d3f6c9..000000000000 --- a/tests/tcg/tricore/test_bmerge.S +++ /dev/null @@ -1,8 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_DD_PSW(bmerge, 1, 0x555557f7, 0x00000b80, 0x0000001d, 0x0000ffff) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_clz.S b/tests/tcg/tricore/test_clz.S deleted file mode 100644 index e03835f1231b..000000000000 --- a/tests/tcg/tricore/test_clz.S +++ /dev/null @@ -1,9 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_D(cls.h, 1, 0x0, 0x6db17976) - TEST_D_D(cls.h, 2, 0x000f000f, 0x0) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_dvstep.S b/tests/tcg/tricore/test_dvstep.S deleted file mode 100644 index 858dbc62dd29..000000000000 --- a/tests/tcg/tricore/test_dvstep.S +++ /dev/null @@ -1,15 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - # Result RS1 RS2 - TEST_E_ED(dvstep, 1, 0x000001ff, 0xfffe5cff, 0x00000001, 0xfffffe5c, 0x0) - TEST_E_ED(dvstep, 2, 0x00000000, 0x000000ff, 0x00000000, 0x00000000, 0x0) - TEST_E_ED(dvstep, 3, 0x0000f000, 0x000000fd, 0x010000f0, 0x00000000, 0x0) - TEST_E_ED(dvstep, 4, 0xfffff000, 0x00000000, 0x7ffffff0, 0x00000000, 0x0) - TEST_E_ED(dvstep.u, 5, 0xffffff00, 0x100008ff, 0xffffffff, 0x00100008, 0x0) - TEST_E_ED(dvstep.u, 6, 0x00000100, 0x00000000, 0x08000001, 0x00000000, \ - 0xffffff2d) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_fadd.S b/tests/tcg/tricore/test_fadd.S deleted file mode 100644 index 1a650548034a..000000000000 --- a/tests/tcg/tricore/test_fadd.S +++ /dev/null @@ -1,16 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_DD_PSW(add.f, 1, 0x7fc00000, 0x00000b80, 0xffffff85, 0x00001234) - TEST_D_DD_PSW(add.f, 2, 0xf9c00000, 0x00000b80, 0xf9400000, 0xf9400000) - TEST_D_DD_PSW(add.f, 3, 0x8bb858ca, 0x00000b80, 0x8b3858ca, 0x8b3858ca) - TEST_D_DD_PSW(add.f, 4, 0x00000000, 0x00000b80, 0x000000ff, 0x00000000) - TEST_D_DD_PSW(add.f, 5, 0x7fc00000, 0x00000b80, 0xfffffe52, 0x0a4cf70c) - TEST_D_DD_PSW(add.f, 6, 0x9e6d5076, 0x84000b80, 0x9ded50ec, 0x9ded4fff) - TEST_D_DD_PSW(add.f, 7, 0x00000000, 0x04000b80, 0x0000e8bd, 0x00000000) - TEST_D_DD_PSW(add.f, 8, 0x7fc00000, 0xc4000b80, 0xffad546e, 0xffad546e) - TEST_D_DD_PSW(add.f, 9, 0x7fc00000, 0x04000b80, 0xfffe0000, 0x08130000) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_fmul.S b/tests/tcg/tricore/test_fmul.S deleted file mode 100644 index fb1f634b2de5..000000000000 --- a/tests/tcg/tricore/test_fmul.S +++ /dev/null @@ -1,8 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_DD_PSW(mul.f, 1, 0x974f4f0a, 0x84000b80, 0x1a0b1980, 0xbcbec42d) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_ftoi.S b/tests/tcg/tricore/test_ftoi.S deleted file mode 100644 index fb4af6b5aac9..000000000000 --- a/tests/tcg/tricore/test_ftoi.S +++ /dev/null @@ -1,10 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_D_PSW(ftoi, 1, 0x0, 0x84000b80, 0x05f6e605) - TEST_D_D_PSW(ftoi, 2, 0x0, 0x04000b80, 0x00012200) - TEST_D_D_PSW(ftoi, 3, 0x0, 0xc4000b80, 0xffffffff) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_madd.S b/tests/tcg/tricore/test_madd.S deleted file mode 100644 index 5d839772bb1d..000000000000 --- a/tests/tcg/tricore/test_madd.S +++ /dev/null @@ -1,11 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_DDI_PSW(madd, 1, 0x0000fffd, 0x60000b80, 0x0000ffff, 0x7fffffff,2) - TEST_D_DDI_PSW(madd, 2, 0xffff7fff, 0x60000b80, 0xffff8001, 0x7fffffff,2) - TEST_D_DDD_PSW(madds.u, 3, 0xffffffff, 0x60000b80, 0x00000000, 0x80000000, \ - 0x80000000) - - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_msub.S b/tests/tcg/tricore/test_msub.S deleted file mode 100644 index 6dee87d99c05..000000000000 --- a/tests/tcg/tricore/test_msub.S +++ /dev/null @@ -1,9 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_DDI_PSW(msub, 1, 0xd2fbe5e0, 0x00000b80,0x64003300, 0xff5420d4, -216) - TEST_D_DDI_PSW(msub, 2, 0xfffffc10, 0x00000b80,0xfffffe68, 0xfffffffd, -200) - TEST_D_DDD_PSW(msubs.u, 3, 0x0, 0x60000b80, 0x1, 0xffffffff, 0xffffffdb) - TEST_PASSFAIL - diff --git a/tests/tcg/tricore/test_muls.S b/tests/tcg/tricore/test_muls.S deleted file mode 100644 index ca517556bcf6..000000000000 --- a/tests/tcg/tricore/test_muls.S +++ /dev/null @@ -1,9 +0,0 @@ -#include "macros.h" -.text -.global _start -_start: - TEST_D_DD_PSW(muls.u, 1, 0xffffffff, 0x78000b80, 0x80000001, 0xffffffff) - TEST_D_DD_PSW(muls.u, 2, 0xffffffff, 0x60000b80, 0xfffffffe, 0xffffffff) - - TEST_PASSFAIL - diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target deleted file mode 100644 index 2afa3298bfb1..000000000000 --- a/tests/tcg/x86_64/Makefile.softmmu-target +++ /dev/null @@ -1,47 +0,0 @@ -# -# x86 system tests -# -# This currently builds only for i386. The common C code is built -# with standard compiler flags however so we can support both by -# adding additional boot files for x86_64. -# - -I386_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/i386/system -X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system - -# These objects provide the basic boot code and helper functions for all tests -CRT_OBJS=boot.o - -CRT_PATH=$(X64_SYSTEM_SRC) -LINK_SCRIPT=$(X64_SYSTEM_SRC)/kernel.ld -LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64 -CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) -LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc - -TESTS+=$(MULTIARCH_TESTS) -EXTRA_RUNS+=$(MULTIARCH_RUNS) - -# building head blobs -.PRECIOUS: $(CRT_OBJS) - -%.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ - -# Build and link the tests -%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -memory: CFLAGS+=-DCHECK_UNALIGNED=1 - -# non-inline runs will trigger the duplicate instruction heuristics in libinsn.so -run-plugin-%-with-libinsn.so: - $(call run-test, $@, \ - $(QEMU) -monitor none -display none \ - -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)") - -# 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 deleted file mode 100644 index 17cf168f0a94..000000000000 --- a/tests/tcg/x86_64/Makefile.target +++ /dev/null @@ -1,31 +0,0 @@ -# -*- Mode: makefile -*- -# -# x86_64 tests - included from tests/tcg/Makefile.target -# -# Currently we only build test-x86_64 and test-i386-ssse3 from -# $(SRC_PATH)/tests/tcg/i386/ -# - -include $(SRC_PATH)/tests/tcg/i386/Makefile.target - -ifneq ($(CONFIG_LINUX_USER),) -X86_64_TESTS += vsyscall -TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64 -else -TESTS=$(MULTIARCH_TESTS) -endif -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 - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) - -# TCG does not yet support all SSE (SIGILL on pshufb) -# sha512-sse: CFLAGS=-march=core2 -O3 -# sha512-sse: sha512.c -# $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -TESTS+=sha512-sse diff --git a/tests/tcg/x86_64/system/boot.S b/tests/tcg/x86_64/system/boot.S deleted file mode 100644 index f8a2fcc8395e..000000000000 --- a/tests/tcg/x86_64/system/boot.S +++ /dev/null @@ -1,274 +0,0 @@ -/* - * x86_64 boot and support code - * - * Copyright 2019 Linaro - * - * This work is licensed under the terms of the GNU GPL, version 3 or later. - * See the COPYING file in the top-level directory. - * - * Unlike the i386 version we instead use Xen's PVHVM booting header - * which should drop us automatically into 32 bit mode ready to go. I've - * nabbed bits of the Linux kernel setup to achieve this. - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - .section .head - -#define ELFNOTE_START(name, type, flags) \ -.pushsection .note.name, flags,@note ; \ - .balign 4 ; \ - .long 2f - 1f /* namesz */ ; \ - .long 4484f - 3f /* descsz */ ; \ - .long type ; \ -1:.asciz #name ; \ -2:.balign 4 ; \ -3: - -#define ELFNOTE_END \ -4484:.balign 4 ; \ -.popsection ; - -#define ELFNOTE(name, type, desc) \ - ELFNOTE_START(name, type, "") \ - desc ; \ - ELFNOTE_END - -#define XEN_ELFNOTE_ENTRY 1 -#define XEN_ELFNOTE_HYPERCALL_PAGE 2 -#define XEN_ELFNOTE_VIRT_BASE 3 -#define XEN_ELFNOTE_PADDR_OFFSET 4 -#define XEN_ELFNOTE_PHYS32_ENTRY 18 - -#define __ASM_FORM(x) x -#define __ASM_SEL(a,b) __ASM_FORM(b) -#define _ASM_PTR __ASM_SEL(.long, .quad) - - ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, _ASM_PTR 0x100000) - ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, _ASM_PTR _start) - ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, _ASM_PTR _start) /* entry == virtbase */ - ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, _ASM_PTR 0) - - /* - * Entry point for PVH guests. - * - * Xen ABI specifies the following register state when we come here: - * - * - `ebx`: contains the physical memory address where the loader has placed - * the boot start info structure. - * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared. - * - `cr4`: all bits are cleared. - * - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’ - * and a limit of ‘0xFFFFFFFF’. The selector value is unspecified. - * - `ds`, `es`: must be a 32-bit read/write data segment with a base of - * ‘0’ and a limit of ‘0xFFFFFFFF’. The selector values are all - * unspecified. - * - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit - * of '0x67'. - * - `eflags`: bit 17 (VM) must be cleared. Bit 9 (IF) must be cleared. - * Bit 8 (TF) must be cleared. Other bits are all unspecified. - * - * All other processor registers and flag bits are unspecified. The OS is in - * charge of setting up it's own stack, GDT and IDT. - */ - .code32 - .section .text - -.global _start -_start: - cld - lgdt gdtr - - ljmp $0x8,$.Lloadcs -.Lloadcs: - mov $0x10,%eax - mov %eax,%ds - mov %eax,%es - mov %eax,%fs - mov %eax,%gs - mov %eax,%ss - - /* Enable PAE mode (bit 5). */ - mov %cr4, %eax - btsl $5, %eax - mov %eax, %cr4 - -#define MSR_EFER 0xc0000080 /* extended feature register */ - - /* Enable Long mode. */ - mov $MSR_EFER, %ecx - rdmsr - btsl $8, %eax - wrmsr - - /* Enable paging */ - mov $.Lpml4, %ecx - mov %ecx, %cr3 - - mov %cr0, %eax - btsl $31, %eax - mov %eax, %cr0 - - /* Jump to 64-bit mode. */ - lgdt gdtr64 - ljmp $0x8,$.Lenter64 - - .code64 - .section .text -.Lenter64: - - - // Setup stack ASAP - movq $stack_end,%rsp - - /* don't worry about stack frame, assume everthing is garbage when we return */ - call main - -_exit: /* output any non-zero result in eax to isa-debug-exit device */ - test %al, %al - jz 1f - out %ax, $0xf4 - -1: /* QEMU ACPI poweroff */ - mov $0x604,%edx - mov $0x2000,%eax - out %ax,%dx - hlt - jmp 1b - - /* - * Helper Functions - * - * x86_64 calling convention is rdi, rsi, rdx, rcx, r8, r9 - */ - - /* Output a single character to serial port */ - .global __sys_outc -__sys_outc: - pushq %rax - mov %rax, %rdx - out %al,$0xE9 - popq %rax - ret - - /* Interrupt Descriptor Table */ - - .section .data - .align 16 - -idt_00: .int 0, 0 -idt_01: .int 0, 0 -idt_02: .int 0, 0 -idt_03: .int 0, 0 -idt_04: .int 0, 0 -idt_05: .int 0, 0 -idt_06: .int 0, 0 /* intr_6_opcode, Invalid Opcode */ -idt_07: .int 0, 0 -idt_08: .int 0, 0 -idt_09: .int 0, 0 -idt_0A: .int 0, 0 -idt_0B: .int 0, 0 -idt_0C: .int 0, 0 -idt_0D: .int 0, 0 -idt_0E: .int 0, 0 -idt_0F: .int 0, 0 -idt_10: .int 0, 0 -idt_11: .int 0, 0 -idt_12: .int 0, 0 -idt_13: .int 0, 0 -idt_14: .int 0, 0 -idt_15: .int 0, 0 -idt_16: .int 0, 0 -idt_17: .int 0, 0 -idt_18: .int 0, 0 -idt_19: .int 0, 0 -idt_1A: .int 0, 0 -idt_1B: .int 0, 0 -idt_1C: .int 0, 0 -idt_1D: .int 0, 0 -idt_1E: .int 0, 0 -idt_1F: .int 0, 0 - - - /* - * Global Descriptor Table (GDT) - * - * This describes various memory areas (segments) through - * segment descriptors. In 32 bit mode each segment each - * segement is associated with segment registers which are - * implicitly (or explicitly) referenced depending on the - * instruction. However in 64 bit mode selectors are flat and - * segmented addressing isn't used. - */ -gdt: - .short 0 -gdtr: - .short gdt_en - gdt - 1 - .int gdt - - // Code cs: - .short 0xFFFF - .short 0 - .byte 0 - .byte 0x9b - .byte 0xCF - .byte 0 - - // Data ds:, ss:, es:, fs:, and gs: - .short 0xFFFF - .short 0 - .byte 0 - .byte 0x93 - .byte 0xCF - .byte 0 -gdt_en: - -gdt64: - .short 0 -gdtr64: - .short gdt64_en - gdt64 - 1 - .int gdt64 - - // Code - .short 0xFFFF - .short 0 - .byte 0 - .byte 0x9b - .byte 0xAF - .byte 0 - - // Data - .short 0xFFFF - .short 0 - .byte 0 - .byte 0x93 - .byte 0xCF - .byte 0 -gdt64_en: - - .section .bss - .align 16 - -stack: .space 65536 -stack_end: - - .section .data - -.align 4096 -.Lpd: -i = 0 - .rept 512 * 4 - .quad 0x1e7 | (i << 21) - i = i + 1 - .endr - -.align 4096 -.Lpdp: - .quad .Lpd + 7 + 0 * 4096 /* 0-1 GB */ - .quad .Lpd + 7 + 1 * 4096 /* 1-2 GB */ - .quad .Lpd + 7 + 2 * 4096 /* 2-3 GB */ - .quad .Lpd + 7 + 3 * 4096 /* 3-4 GB */ - -.align 4096 -.Lpml4: - .quad .Lpdp + 7 /* 0-512 GB */ diff --git a/tests/tcg/x86_64/system/kernel.ld b/tests/tcg/x86_64/system/kernel.ld deleted file mode 100644 index ca5d6bd8509d..000000000000 --- a/tests/tcg/x86_64/system/kernel.ld +++ /dev/null @@ -1,36 +0,0 @@ -PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - note PT_NOTE FLAGS(0); /* ___ */ -} - -SECTIONS { - . = 0x100000; - - .text : { - __load_st = .; - *(.head) - *(.text) - } :text - - .rodata : { - *(.rodata) - } :text - - /DISCARD/ : { - *(.note.gnu*) - } - - .notes : { - *(.note.*) - } :note - - .data : { - *(.data) - __load_en = .; - } :text - - .bss : { - *(.bss) - __bss_en = .; - } -} diff --git a/tests/tcg/x86_64/vsyscall.c b/tests/tcg/x86_64/vsyscall.c deleted file mode 100644 index 786b047053aa..000000000000 --- a/tests/tcg/x86_64/vsyscall.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -#define VSYSCALL_PAGE 0xffffffffff600000 -#define TIME_OFFSET 0x400 -typedef time_t (*time_func)(time_t *); - -int main(void) -{ - printf("%ld\n", ((time_func)(VSYSCALL_PAGE + TIME_OFFSET))(NULL)); - return 0; -} diff --git a/tests/tcg/xtensa/Makefile.softmmu-target b/tests/tcg/xtensa/Makefile.softmmu-target deleted file mode 100644 index 9530cac2ad95..000000000000 --- a/tests/tcg/xtensa/Makefile.softmmu-target +++ /dev/null @@ -1,42 +0,0 @@ -# -# Xtensa softmmu tests -# - -ifneq ($(TARGET_WORDS_BIGENDIAN),y) - -XTENSA_SRC = $(SRC_PATH)/tests/tcg/xtensa -XTENSA_ALL = $(filter-out $(XTENSA_SRC)/linker.ld.S,$(wildcard $(XTENSA_SRC)/*.S)) -XTENSA_TESTS = $(patsubst $(XTENSA_SRC)/%.S, %, $(XTENSA_ALL)) -# Filter out common blobs and broken tests -XTENSA_BROKEN_TESTS = crt vectors -XTENSA_USABLE_TESTS = $(filter-out $(XTENSA_BROKEN_TESTS), $(XTENSA_TESTS)) - -# add to the list of tests -TESTS += $(XTENSA_USABLE_TESTS) -VPATH += $(XTENSA_SRC) - -CORE=dc232b -QEMU_OPTS+=-M sim -cpu $(CORE) -nographic -semihosting -icount 6 $(EXTFLAGS) -kernel - -INCLUDE_DIRS = $(SRC_PATH)/target/xtensa/core-$(CORE) -XTENSA_INC = $(addprefix -I,$(INCLUDE_DIRS)) - -vectors_ASFLAGS = -mtext-section-literals -ASFLAGS = -Wa,--no-absolute-literals -LDFLAGS = -Tlinker.ld -nostartfiles -nostdlib - -CRT = crt.o vectors.o - -linker.ld: linker.ld.S - $(CC) $(XTENSA_INC) -E -P $< -o $@ - -$(XTENSA_USABLE_TESTS): linker.ld macros.inc $(CRT) Makefile.softmmu-target - -# special rule for common blobs -%.o: %.S - $(CC) $(XTENSA_INC) $($*_ASFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ - -%: %.S - $(CC) $(XTENSA_INC) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT) - -endif diff --git a/tests/tcg/xtensa/crt.S b/tests/tcg/xtensa/crt.S deleted file mode 100644 index d9846acace90..000000000000 --- a/tests/tcg/xtensa/crt.S +++ /dev/null @@ -1,24 +0,0 @@ -.section .init - j 1f -.section .init.text -1: - movi a2, _start - jx a2 - -.text -.global _start -_start: - movi a2, 1 - wsr a2, windowstart - movi a2, 0 - wsr a2, windowbase - movi a1, _fstack - movi a2, 0x4000f - wsr a2, ps - isync - - call0 main - - mov a3, a2 - movi a2, 1 - simcall diff --git a/tests/tcg/xtensa/fpu.h b/tests/tcg/xtensa/fpu.h deleted file mode 100644 index 42e321747304..000000000000 --- a/tests/tcg/xtensa/fpu.h +++ /dev/null @@ -1,142 +0,0 @@ -#if XCHAL_HAVE_DFP || XCHAL_HAVE_FP_DIV -#define DFPU 1 -#else -#define DFPU 0 -#endif - -#define FCR_RM_NEAREST 0 -#define FCR_RM_TRUNC 1 -#define FCR_RM_CEIL 2 -#define FCR_RM_FLOOR 3 - -#define FSR__ 0x00000000 -#define FSR_I 0x00000080 -#define FSR_U 0x00000100 -#define FSR_O 0x00000200 -#define FSR_Z 0x00000400 -#define FSR_V 0x00000800 - -#define FSR_UI (FSR_U | FSR_I) -#define FSR_OI (FSR_O | FSR_I) - -#define F32_0 0x00000000 -#define F32_0_5 0x3f000000 -#define F32_1 0x3f800000 -#define F32_MAX 0x7f7fffff -#define F32_PINF 0x7f800000 -#define F32_NINF 0xff800000 - -#define F32_DNAN 0x7fc00000 -#define F32_SNAN(v) (0x7f800000 | (v)) -#define F32_QNAN(v) (0x7fc00000 | (v)) - -#define F32_MINUS 0x80000000 - -#define F64_0 0x0000000000000000 -#define F64_MIN_NORM 0x0010000000000000 -#define F64_1 0x3ff0000000000000 -#define F64_MAX_2 0x7fe0000000000000 -#define F64_MAX 0x7fefffffffffffff -#define F64_PINF 0x7ff0000000000000 -#define F64_NINF 0xfff0000000000000 - -#define F64_DNAN 0x7ff8000000000000 -#define F64_SNAN(v) (0x7ff0000000000000 | (v)) -#define F64_QNAN(v) (0x7ff8000000000000 | (v)) - -#define F64_MINUS 0x8000000000000000 - -.macro test_op1_rm op, fr0, fr1, v0, r, sr - movi a2, 0 - wur a2, fsr - movfp \fr0, \v0 - \op \fr1, \fr0 - check_res \fr1, \r, \sr -.endm - -.macro test_op2_rm op, fr0, fr1, fr2, v0, v1, r, sr - movi a2, 0 - wur a2, fsr - movfp \fr0, \v0 - movfp \fr1, \v1 - \op \fr2, \fr0, \fr1 - check_res \fr2, \r, \sr -.endm - -.macro test_op3_rm op, fr0, fr1, fr2, fr3, v0, v1, v2, r, sr - movi a2, 0 - wur a2, fsr - movfp \fr0, \v0 - movfp \fr1, \v1 - movfp \fr2, \v2 - \op \fr0, \fr1, \fr2 - check_res \fr3, \r, \sr -.endm - -.macro test_op1_ex op, fr0, fr1, v0, rm, r, sr - movi a2, \rm - wur a2, fcr - test_op1_rm \op, \fr0, \fr1, \v0, \r, \sr - movi a2, (\rm) | 0x7c - wur a2, fcr - test_op1_rm \op, \fr0, \fr1, \v0, \r, \sr -.endm - -.macro test_op2_ex op, fr0, fr1, fr2, v0, v1, rm, r, sr - movi a2, \rm - wur a2, fcr - test_op2_rm \op, \fr0, \fr1, \fr2, \v0, \v1, \r, \sr - movi a2, (\rm) | 0x7c - wur a2, fcr - test_op2_rm \op, \fr0, \fr1, \fr2, \v0, \v1, \r, \sr -.endm - -.macro test_op3_ex op, fr0, fr1, fr2, fr3, v0, v1, v2, rm, r, sr - movi a2, \rm - wur a2, fcr - test_op3_rm \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, \r, \sr - movi a2, (\rm) | 0x7c - wur a2, fcr - test_op3_rm \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, \r, \sr -.endm - -.macro test_op1 op, fr0, fr1, v0, r0, r1, r2, r3, sr0, sr1, sr2, sr3 - test_op1_ex \op, \fr0, \fr1, \v0, 0, \r0, \sr0 - test_op1_ex \op, \fr0, \fr1, \v0, 1, \r1, \sr1 - test_op1_ex \op, \fr0, \fr1, \v0, 2, \r2, \sr2 - test_op1_ex \op, \fr0, \fr1, \v0, 3, \r3, \sr3 -.endm - -.macro test_op2 op, fr0, fr1, fr2, v0, v1, r0, r1, r2, r3, sr0, sr1, sr2, sr3 - test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 0, \r0, \sr0 - test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 1, \r1, \sr1 - test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 2, \r2, \sr2 - test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 3, \r3, \sr3 -.endm - -.macro test_op3 op, fr0, fr1, fr2, fr3, v0, v1, v2, r0, r1, r2, r3, sr0, sr1, sr2, sr3 - test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 0, \r0, \sr0 - test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 1, \r1, \sr1 - test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 2, \r2, \sr2 - test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 3, \r3, \sr3 -.endm - -.macro test_op2_cpe op - set_vector kernel, 2f - movi a2, 0 - wsr a2, cpenable -1: - \op f2, f0, f1 - test_fail -2: - rsr a2, excvaddr - movi a3, 1b - assert eq, a2, a3 - rsr a2, exccause - movi a3, 32 - assert eq, a2, a3 - - set_vector kernel, 0 - movi a2, 1 - wsr a2, cpenable -.endm diff --git a/tests/tcg/xtensa/linker.ld.S b/tests/tcg/xtensa/linker.ld.S deleted file mode 100644 index ac89b0054ee4..000000000000 --- a/tests/tcg/xtensa/linker.ld.S +++ /dev/null @@ -1,166 +0,0 @@ -#include "core-isa.h" - -#ifndef XCHAL_VECBASE_RESET_VADDR -#define XCHAL_VECBASE_RESET_VADDR XCHAL_WINDOW_VECTORS_VADDR -#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 -#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 -#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 -#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 -#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 -#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 -#endif - -#define RAM_SIZE 0x08000000 /* 128M */ -#define ROM_SIZE 0x00001000 /* 4k */ -#define VECTORS_RESERVED_SIZE 0x1000 - -#if XCHAL_HAVE_BE -OUTPUT_FORMAT("elf32-xtensa-be") -#else -OUTPUT_FORMAT("elf32-xtensa-le") -#endif -ENTRY(_start) - -MEMORY { - ram : ORIGIN = XCHAL_VECBASE_RESET_VADDR, LENGTH = RAM_SIZE - rom : ORIGIN = XCHAL_RESET_VECTOR_VADDR, LENGTH = ROM_SIZE -} - -SECTIONS -{ - .init : - { - *(.init) - *(.init.*) - } > rom - -#if XCHAL_HAVE_WINDOWED - .vector.window XCHAL_WINDOW_VECTORS_VADDR : - { - . = XCHAL_WINDOW_OF4_VECOFS; - *(.vector.window_overflow_4) - . = XCHAL_WINDOW_UF4_VECOFS; - *(.vector.window_underflow_4) - . = XCHAL_WINDOW_OF8_VECOFS; - *(.vector.window_overflow_8) - . = XCHAL_WINDOW_UF8_VECOFS; - *(.vector.window_underflow_8) - . = XCHAL_WINDOW_OF12_VECOFS; - *(.vector.window_overflow_12) - . = XCHAL_WINDOW_UF12_VECOFS; - *(.vector.window_underflow_12) - } -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 2 - .vector.level2 XCHAL_INTLEVEL2_VECTOR_VADDR : - { - *(.vector.level2) - } -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 3 - .vector.level3 XCHAL_INTLEVEL3_VECTOR_VADDR : - { - *(.vector.level3) - } -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 4 - .vector.level4 XCHAL_INTLEVEL4_VECTOR_VADDR : - { - *(.vector.level4) - } -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 5 - .vector.level5 XCHAL_INTLEVEL5_VECTOR_VADDR : - { - *(.vector.level5) - } -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 6 - .vector.level6 XCHAL_INTLEVEL6_VECTOR_VADDR : - { - *(.vector.level6) - } -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 7 - .vector.level7 XCHAL_INTLEVEL7_VECTOR_VADDR : - { - *(.vector.level7) - } -#endif - .vector.kernel XCHAL_KERNEL_VECTOR_VADDR : - { - *(.vector.kernel) - } - .vector.user XCHAL_USER_VECTOR_VADDR : - { - *(.vector.user) - } - .vector.double XCHAL_DOUBLEEXC_VECTOR_VADDR : - { - *(.vector.double) - } - - .vector.text XCHAL_VECBASE_RESET_VADDR + VECTORS_RESERVED_SIZE : - { - *(.vector.window_overflow_4.*) - *(.vector.window_underflow_4.*) - *(.vector.window_overflow_8.*) - *(.vector.window_underflow_8.*) - *(.vector.window_overflow_12.*) - *(.vector.window_underflow_12.*) - - *(.vector.level2.*) - *(.vector.level3.*) - *(.vector.level4.*) - *(.vector.level5.*) - *(.vector.level6.*) - *(.vector.level7.*) - - *(.vector.kernel.*) - *(.vector.user.*) - *(.vector.double.*) - } > ram - - .text : - { - _ftext = .; - *(.text .stub .text.* .gnu.linkonce.t.* .literal .literal.*) - _etext = .; - } > ram - - .rodata : - { - . = ALIGN(4); - _frodata = .; - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - _erodata = .; - } > ram - - .data : - { - . = ALIGN(4); - _fdata = .; - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - _gp = ALIGN(16); - *(.sdata .sdata.* .gnu.linkonce.s.*) - _edata = .; - } > ram - - .bss : - { - . = ALIGN(4); - _fbss = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - _ebss = .; - _end = .; - } > ram -} - -PROVIDE(_fstack = (ORIGIN(ram) & 0xf0000000) + LENGTH(ram) - 16); diff --git a/tests/tcg/xtensa/macros.inc b/tests/tcg/xtensa/macros.inc deleted file mode 100644 index f88937c7bf82..000000000000 --- a/tests/tcg/xtensa/macros.inc +++ /dev/null @@ -1,122 +0,0 @@ -#include "core-isa.h" - -.macro test_suite name -.data -status: .word result -result: .space 1024 -.text -.global main -.align 4 -main: -.endm - -.macro reset_ps - movi a2, 0x4000f - wsr a2, ps - isync -.endm - -.macro test_suite_end - reset_ps - movi a0, status - l32i a2, a0, 0 - movi a0, result - sub a2, a2, a0 - movi a3, 0 - beqz a2, 2f -1: - l32i a1, a0, 0 - or a3, a3, a1 - addi a0, a0, 4 - addi a2, a2, -1 - bnez a2, 1b -2: - exit -.endm - -.macro print text -.data -97: .ascii "\text\n" -98: - .align 4 -.text - movi a2, 4 - movi a3, 2 - movi a4, 97b - movi a5, 98b - sub a5, a5, a4 - simcall -.endm - -.macro test_init -.endm - -.macro test name -#ifdef DEBUG - print test_\name -#endif - test_init -test_\name: -.global test_\name -.endm - -.macro test_end -99: - reset_ps - movi a2, status - l32i a3, a2, 0 - addi a3, a3, 4 - s32i a3, a2, 0 -.endm - -.macro exit - movi a2, 1 - simcall -.endm - -.macro test_fail - movi a2, status - l32i a2, a2, 0 - movi a3, 1 - s32i a3, a2, 0 -#ifdef DEBUG - print failed -#endif - j 99f -.endm - -.macro assert cond, arg1, arg2 - b\cond \arg1, \arg2, 90f - test_fail -90: - nop -.endm - -.macro set_vector vector, addr - movi a2, handler_\vector - movi a3, \addr - s32i a3, a2, 0 -.endm - -.macro dump r -#ifdef DEBUG -.data -.align 4 -1: .word 0 -.text - movi a4, 1b - s32i a2, a4, 0 - movi a2, 4 - movi a3, 1 - movi a5, 4 - simcall - movi a4, 1b - l32i a2, a4, 0 -#endif -.endm - -#define glue(a, b) _glue(a, b) -#define _glue(a, b) a ## b - -#define glue3(a, b, c) _glue3(a, b, c) -#define _glue3(a, b, c) a ## b ## c diff --git a/tests/tcg/xtensa/test_b.S b/tests/tcg/xtensa/test_b.S deleted file mode 100644 index 713a454c535b..000000000000 --- a/tests/tcg/xtensa/test_b.S +++ /dev/null @@ -1,245 +0,0 @@ -#include "macros.inc" - -test_suite b - -test bnone - movi a2, 0xa5a5ff00 - movi a3, 0x5a5a00ff - bnone a2, a3, 1f - test_fail -1: - movi a2, 0xa5a5ff01 - bnone a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test beq - movi a2, 0 - movi a3, 0 - beq a2, a3, 1f - test_fail -1: - movi a2, 1 - beq a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test blt - movi a2, 6 - movi a3, 7 - blt a2, a3, 1f - test_fail -1: - movi a2, 0xffffffff - blt a2, a3, 1f - test_fail -1: - movi a2, 7 - blt a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bltu - movi a2, 6 - movi a3, 7 - bltu a2, a3, 1f - test_fail -1: - movi a2, 7 - bltu a2, a3, 1f - j 2f -1: - test_fail -2: - movi a2, 0xffffffff - bltu a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test ball - movi a2, 0xa5a5ffa5 - movi a3, 0xa5a5ff00 - ball a2, a3, 1f - test_fail -1: - movi a2, 0xa5a5a5a5 - ball a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bbc - movi a2, 0xfffffffd -#undef BIT -#if XCHAL_HAVE_BE -#define BIT 0xfffffffe -#else -#define BIT 0xffffff01 -#endif - movi a3, BIT - bbc a2, a3, 1f - test_fail -1: - movi a2, 8 -#undef BIT -#if XCHAL_HAVE_BE -#define BIT 0xfffffffc -#else -#define BIT 0xffffff03 -#endif - movi a3, BIT - bbc a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bbci - movi a2, 0xfffdffff - bbci.l a2, 17, 1f - test_fail -1: - movi a2, 0x00020000 - bbci.l a2, 17, 1f - j 2f -1: - test_fail -2: -test_end - -test bany - movi a2, 0xa5a5ff01 - movi a3, 0x5a5a00ff - bany a2, a3, 1f - test_fail -1: - movi a2, 0xa5a5ff00 - bany a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bne - movi a2, 1 - movi a3, 0 - bne a2, a3, 1f - test_fail -1: - movi a2, 0 - bne a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bge - movi a2, 7 - movi a3, 7 - bge a2, a3, 1f - test_fail -1: - movi a2, 6 - bge a2, a3, 1f - j 2f -1: - test_fail -2: - movi a2, 0xffffffff - bge a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bgeu - movi a2, 7 - movi a3, 7 - bgeu a2, a3, 1f - test_fail -1: - movi a2, 0xffffffff - bgeu a2, a3, 1f - test_fail -1: - movi a2, 6 - bgeu a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bnall - movi a2, 0xa5a5a5a5 - movi a3, 0xa5a5ff00 - bnall a2, a3, 1f - test_fail -1: - movi a2, 0xa5a5ffa5 - bnall a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bbs - movi a2, 8 -#undef BIT -#if XCHAL_HAVE_BE -#define BIT 0xfffffffc -#else -#define BIT 0xffffff03 -#endif - movi a3, BIT - bbs a2, a3, 1f - test_fail -1: - movi a2, 0xfffffffd -#undef BIT -#if XCHAL_HAVE_BE -#define BIT 0xfffffffe -#else -#define BIT 0xffffff01 -#endif - movi a3, BIT - bbs a2, a3, 1f - j 2f -1: - test_fail -2: -test_end - -test bbsi - movi a2, 0x00020000 - bbsi.l a2, 17, 1f - test_fail -1: - movi a2, 0xfffdffff - bbsi.l a2, 17, 1f - j 2f -1: - test_fail -2: -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_bi.S b/tests/tcg/xtensa/test_bi.S deleted file mode 100644 index 4f94c0c7e6b3..000000000000 --- a/tests/tcg/xtensa/test_bi.S +++ /dev/null @@ -1,103 +0,0 @@ -#include "macros.inc" - -test_suite bi - -test beqi - movi a2, 7 - beqi a2, 7, 1f - test_fail -1: - movi a2, 1 - beqi a2, 7, 1f - j 2f -1: - test_fail -2: -test_end - -test bnei - movi a2, 1 - bnei a2, 7, 1f - test_fail -1: - movi a2, 7 - bnei a2, 7, 1f - j 2f -1: - test_fail -2: -test_end - -test blti - movi a2, 6 - blti a2, 7, 1f - test_fail -1: - movi a2, 0xffffffff - blti a2, 7, 1f - test_fail -1: - movi a2, 7 - blti a2, 7, 1f - j 2f -1: - test_fail -2: -test_end - -test bgei - movi a2, 7 - bgei a2, 7, 1f - test_fail -1: - movi a2, 6 - bgei a2, 7, 1f - j 2f -1: - test_fail -2: - movi a2, 0xffffffff - bgei a2, 7, 1f - j 2f -1: - test_fail -2: -test_end - -test bltui - movi a2, 6 - bltui a2, 7, 1f - test_fail -1: - movi a2, 7 - bltui a2, 7, 1f - j 2f -1: - test_fail -2: - movi a2, 0xffffffff - bltui a2, 7, 1f - j 2f -1: - test_fail -2: -test_end - -test bgeui - movi a2, 7 - bgeui a2, 7, 1f - test_fail -1: - movi a2, 0xffffffff - bgeui a2, 7, 1f - test_fail -1: - movi a2, 6 - bgeui a2, 7, 1f - j 2f -1: - test_fail -2: -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_boolean.S b/tests/tcg/xtensa/test_boolean.S deleted file mode 100644 index 5a850bfe7eac..000000000000 --- a/tests/tcg/xtensa/test_boolean.S +++ /dev/null @@ -1,27 +0,0 @@ -#include "macros.inc" - -test_suite boolean - -#if XCHAL_HAVE_BOOLEANS - -test all4 - movi a2, 0xfec0 - wsr a2, br - all4 b0, b0 - rsr a3, br - assert eq, a2, a3 - all4 b0, b4 - rsr a3, br - assert eq, a2, a3 - all4 b0, b8 - rsr a3, br - assert eq, a2, a3 - all4 b0, b12 - rsr a3, br - addi a2, a2, 1 - assert eq, a2, a3 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S deleted file mode 100644 index 3379a3f9f06e..000000000000 --- a/tests/tcg/xtensa/test_break.S +++ /dev/null @@ -1,266 +0,0 @@ -#include "macros.inc" - -test_suite break - -#if XCHAL_HAVE_DEBUG - -#define debug_level XCHAL_DEBUGLEVEL -#define debug_vector glue(level, XCHAL_DEBUGLEVEL) -#define EPC_DEBUG glue(epc, XCHAL_DEBUGLEVEL) - -test break - set_vector debug_vector, 0 - rsil a2, debug_level - _break 0, 0 - - set_vector debug_vector, 2f - rsil a2, debug_level - 1 -1: - _break 0, 0 - test_fail -2: - rsr a2, ps - movi a3, 0x1f - and a2, a2, a3 - movi a3, 0x10 | debug_level - assert eq, a2, a3 - rsr a2, EPC_DEBUG - movi a3, 1b - assert eq, a2, a3 - rsr a2, debugcause - movi a3, 0x8 - assert eq, a2, a3 -test_end - -test breakn - set_vector debug_vector, 0 - rsil a2, debug_level - _break.n 0 - - set_vector debug_vector, 2f - rsil a2, debug_level - 1 -1: - _break.n 0 - test_fail -2: - rsr a2, ps - movi a3, 0x1f - and a2, a2, a3 - movi a3, 0x10 | debug_level - assert eq, a2, a3 - rsr a2, EPC_DEBUG - movi a3, 1b - assert eq, a2, a3 - rsr a2, debugcause - movi a3, 0x10 - assert eq, a2, a3 -test_end - -#if XCHAL_NUM_IBREAK -test ibreak - set_vector debug_vector, 0 - rsil a2, debug_level - movi a2, 1f - wsr a2, ibreaka0 - movi a2, 1 - wsr a2, ibreakenable - isync -1: - rsil a2, debug_level - 1 - movi a2, 1f - wsr a2, ibreaka0 - movi a2, 0 - wsr a2, ibreakenable - isync -1: - set_vector debug_vector, 2f - movi a2, 1f - wsr a2, ibreaka0 - movi a2, 1 - wsr a2, ibreakenable - isync -1: - test_fail -2: - rsr a2, ps - movi a3, 0x1f - and a2, a2, a3 - movi a3, 0x10 | debug_level - assert eq, a2, a3 - rsr a2, EPC_DEBUG - movi a3, 1b - assert eq, a2, a3 - rsr a2, debugcause - movi a3, 0x2 - assert eq, a2, a3 -test_end - -test ibreak_remove - set_vector debug_vector, 3f - rsil a2, debug_level - 1 - movi a2, 2f - wsr a2, ibreaka0 - movi a3, 1 -1: - wsr a3, ibreakenable - isync -2: - beqz a3, 4f - test_fail -3: - assert eqi, a3, 1 - rsr a2, ps - movi a3, 0x1f - and a2, a2, a3 - movi a3, 0x10 | debug_level - assert eq, a2, a3 - rsr a2, EPC_DEBUG - movi a3, 2b - assert eq, a2, a3 - rsr a2, debugcause - movi a3, 0x2 - assert eq, a2, a3 - - movi a2, 0x40000 - wsr a2, ps - isync - movi a3, 0 - j 1b -4: -test_end - -test ibreak_priority - set_vector debug_vector, 2f - rsil a2, debug_level - 1 - movi a2, 1f - wsr a2, ibreaka0 - movi a2, 1 - wsr a2, ibreakenable - isync -1: - break 0, 0 - test_fail -2: - rsr a2, debugcause - movi a3, 0x2 - assert eq, a2, a3 -test_end -#endif - -test icount - set_vector debug_vector, 2f - rsil a2, debug_level - 1 - movi a2, -2 - wsr a2, icount - movi a2, 1 - wsr a2, icountlevel - isync - rsil a2, 0 - nop -1: - break 0, 0 - test_fail -2: - movi a2, 0 - wsr a2, icountlevel - rsr a2, EPC_DEBUG - movi a3, 1b - assert eq, a2, a3 - rsr a2, debugcause - movi a3, 0x1 - assert eq, a2, a3 -test_end - -.macro check_dbreak dr - rsr a2, EPC_DEBUG - movi a3, 1b - assert eq, a2, a3 - rsr a2, debugcause - movi a3, 0x4 | (\dr << 8) - assert eq, a2, a3 - movi a2, 0 - wsr a2, dbreakc\dr -.endm - -.macro dbreak_test dr, ctl, break, access, op - set_vector debug_vector, 2f - rsil a2, debug_level - 1 - movi a2, \ctl - wsr a2, dbreakc\dr - movi a2, \break - wsr a2, dbreaka\dr - movi a2, \access - isync -1: - \op a3, a2, 0 - test_fail -2: - check_dbreak \dr - reset_ps -.endm - -#if XCHAL_NUM_DBREAK -test dbreak_exact - dbreak_test 0, 0x4000003f, 0xd000007f, 0xd000007f, l8ui - dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007e, l16ui - dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007c, l32i - - dbreak_test 1, 0x8000003f, 0xd000007f, 0xd000007f, s8i - dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007e, s16i - dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s32i -test_end - -test dbreak_overlap - dbreak_test 0, 0x4000003f, 0xd000007d, 0xd000007c, l16ui - dbreak_test 1, 0x4000003f, 0xd000007d, 0xd000007c, l32i - - dbreak_test 0, 0x4000003e, 0xd000007e, 0xd000007f, l8ui - dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007c, l32i - - dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007d, l8ui - dbreak_test 1, 0x4000003c, 0xd000007c, 0xd000007c, l16ui - - dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007b, l8ui - dbreak_test 1, 0x40000038, 0xd0000078, 0xd000007a, l16ui - dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007c, l32i - - dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000075, l8ui - dbreak_test 0, 0x40000030, 0xd0000070, 0xd0000076, l16ui - dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000078, l32i - - dbreak_test 0, 0x40000020, 0xd0000060, 0xd000006f, l8ui - dbreak_test 1, 0x40000020, 0xd0000060, 0xd0000070, l16ui - dbreak_test 0, 0x40000020, 0xd0000060, 0xd0000074, l32i - - - dbreak_test 0, 0x8000003f, 0xd000007d, 0xd000007c, s16i - dbreak_test 1, 0x8000003f, 0xd000007d, 0xd000007c, s32i - - dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007f, s8i - dbreak_test 1, 0x8000003e, 0xd000007e, 0xd000007c, s32i - - dbreak_test 0, 0x8000003c, 0xd000007c, 0xd000007d, s8i - dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s16i - - dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007b, s8i - dbreak_test 1, 0x80000038, 0xd0000078, 0xd000007a, s16i - dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007c, s32i - - dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000075, s8i - dbreak_test 0, 0x80000030, 0xd0000070, 0xd0000076, s16i - dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000078, s32i - - dbreak_test 0, 0x80000020, 0xd0000060, 0xd000006f, s8i - dbreak_test 1, 0x80000020, 0xd0000060, 0xd0000070, s16i - dbreak_test 0, 0x80000020, 0xd0000060, 0xd0000074, s32i -test_end - -test dbreak_invalid - dbreak_test 0, 0x40000030, 0xd0000071, 0xd0000070, l16ui - dbreak_test 1, 0x40000035, 0xd0000072, 0xd0000070, l32i -test_end -#endif - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_bz.S b/tests/tcg/xtensa/test_bz.S deleted file mode 100644 index b68135011e30..000000000000 --- a/tests/tcg/xtensa/test_bz.S +++ /dev/null @@ -1,57 +0,0 @@ -#include "macros.inc" - -test_suite bz - -test beqz - movi a2, 0 - _beqz a2, 1f - test_fail -1: - movi a2, 1 - _beqz a2, 1f - j 2f -1: - test_fail -2: -test_end - -test bnez - movi a2, 1 - _bnez a2, 1f - test_fail -1: - movi a2, 0 - _bnez a2, 1f - j 2f -1: - test_fail -2: -test_end - -test bltz - movi a2, 0xffffffff - bltz a2, 1f - test_fail -1: - movi a2, 0 - bltz a2, 1f - j 2f -1: - test_fail -2: -test_end - -test bgez - movi a2, 0 - bgez a2, 1f - test_fail -1: - movi a2, 0xffffffff - bgez a2, 1f - j 2f -1: - test_fail -2: -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_cache.S b/tests/tcg/xtensa/test_cache.S deleted file mode 100644 index 7e6ba4c18a2b..000000000000 --- a/tests/tcg/xtensa/test_cache.S +++ /dev/null @@ -1,135 +0,0 @@ -#include "macros.inc" - -.purgem test_init -.macro test_init - call0 cache_unlock_invalidate -.endm - -test_suite cache - -#if XCHAL_HAVE_PTP_MMU - -.macro pf_op op - \op a2, 0 - \op a3, 0 - \op a4, 0 -.endm - -test prefetch - movi a2, 0xd0000000 /* cacheable */ - movi a3, 0xd8000000 /* non-cacheable */ - movi a4, 0x00001235 /* unmapped */ - -#if XCHAL_DCACHE_SIZE - pf_op dpfr - pf_op dpfro - pf_op dpfw - pf_op dpfwo -#endif -#ifdef XCHAL_ICACHE_SIZE - pf_op ipf -#endif -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY -#if XCHAL_DCACHE_LINE_LOCKABLE - dpfl a2, 0 -#endif -#if XCHAL_ICACHE_LINE_LOCKABLE - ipfl a2, 0 -#endif -#endif -test_end - -.macro cache_fault op, addr, exc_code - set_vector kernel, 2f - - movi a4, \addr -1: - \op a4, 0 - test_fail -2: - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - rsr a2, excvaddr - assert eq, a2, a4 - rsr a2, exccause - movi a3, \exc_code - assert eq, a2, a3 -.endm - -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY - -#if XCHAL_DCACHE_LINE_LOCKABLE -test dpfl_tlb_miss - cache_fault dpfl, 0x00002345, 24 -test_end -#endif - -#if XCHAL_DCACHE_SIZE -#if XCHAL_DCACHE_IS_WRITEBACK -test dhwb_tlb_miss - cache_fault dhwb, 0x00002345, 24 -test_end - -test dhwbi_tlb_miss - cache_fault dhwbi, 0x00002345, 24 -test_end -#endif - -test dhi_tlb_miss - cache_fault dhi, 0x00002345, 24 -test_end - -#if XCHAL_DCACHE_LINE_LOCKABLE -test dhu_tlb_miss - cache_fault dhu, 0x00002345, 24 -test_end -#endif -#endif - -#if XCHAL_ICACHE_SIZE -#if XCHAL_ICACHE_LINE_LOCKABLE -test ipfl_tlb_miss - cache_fault ipfl, 0x00002345, 16 -test_end - -test ihu_tlb_miss - cache_fault ihu, 0x00002345, 16 -test_end -#endif - -test ihi_tlb_miss - cache_fault ihi, 0x00002345, 16 -test_end -#endif - -#endif - -#endif - -test_suite_end - -cache_unlock_invalidate: -#if XCHAL_DCACHE_SIZE - movi a2, 0 - movi a3, XCHAL_DCACHE_SIZE -1: -#if XCHAL_DCACHE_LINE_LOCKABLE - diu a2, 0 -#endif - dii a2, 0 - addi a2, a2, XCHAL_DCACHE_LINESIZE - bltu a2, a3, 1b -#endif -#if XCHAL_ICACHE_SIZE - movi a2, 0 - movi a3, XCHAL_ICACHE_SIZE -1: -#if XCHAL_ICACHE_LINE_LOCKABLE - iiu a2, 0 -#endif - iii a2, 0 - addi a2, a2, XCHAL_ICACHE_LINESIZE - bltu a2, a3, 1b -#endif - ret diff --git a/tests/tcg/xtensa/test_clamps.S b/tests/tcg/xtensa/test_clamps.S deleted file mode 100644 index d9b2c38ac1d6..000000000000 --- a/tests/tcg/xtensa/test_clamps.S +++ /dev/null @@ -1,46 +0,0 @@ -#include "macros.inc" - -test_suite clamps - -#if XCHAL_HAVE_CLAMPS - -test clamps - movi a2, 0 - movi a3, 0 - clamps a4, a2, 7 - assert eq, a3, a4 - - movi a2, 0x7f - movi a3, 0x7f - clamps a4, a2, 7 - assert eq, a3, a4 - - movi a2, 0xffffff80 - movi a3, 0xffffff80 - clamps a4, a2, 7 - assert eq, a3, a4 - - movi a2, 0x80 - movi a3, 0x7f - clamps a2, a2, 7 - assert eq, a3, a2 - - movi a2, 0xffffff7f - movi a3, 0xffffff80 - clamps a2, a2, 7 - assert eq, a3, a2 - - movi a2, 0x7fffffff - movi a3, 0x7f - clamps a2, a2, 7 - assert eq, a3, a2 - - movi a2, 0x80000000 - movi a3, 0xffffff80 - clamps a2, a2, 7 - assert eq, a3, a2 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_dfp0_arith.S b/tests/tcg/xtensa/test_dfp0_arith.S deleted file mode 100644 index 53bf8122d082..000000000000 --- a/tests/tcg/xtensa/test_dfp0_arith.S +++ /dev/null @@ -1,162 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite fp0_arith - -#if XCHAL_HAVE_DFP - -.macro movfp fr, v - movi a2, ((\v) >> 32) & 0xffffffff - movi a3, ((\v) & 0xffffffff) - wfrd \fr, a2, a3 -.endm - -.macro check_res fr, r, sr - rfrd a2, \fr - dump a2 - movi a3, ((\r) >> 32) & 0xffffffff - assert eq, a2, a3 - rfr a2, \fr - dump a2 - movi a3, ((\r) & 0xffffffff) - assert eq, a2, a3 - rur a2, fsr - movi a3, \sr - assert eq, a2, a3 -.endm - -test add_d - movi a2, 1 - wsr a2, cpenable - - /* MAX_FLOAT + MAX_FLOAT = +inf/MAX_FLOAT */ - test_op2 add.d, f6, f7, f8, F64_MAX, F64_MAX, \ - F64_PINF, F64_MAX, F64_PINF, F64_MAX, \ - FSR_OI, FSR_OI, FSR_OI, FSR_OI -test_end - -test add_d_inf - /* 1 + +inf = +inf */ - test_op2 add.d, f6, f7, f8, F64_1, F64_PINF, \ - F64_PINF, F64_PINF, F64_PINF, F64_PINF, \ - FSR__, FSR__, FSR__, FSR__ - - /* +inf + -inf = default NaN */ - test_op2 add.d, f0, f1, f2, F64_PINF, F64_NINF, \ - F64_DNAN, F64_DNAN, F64_DNAN, F64_DNAN, \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -test add_d_nan_dfpu - /* 1 + QNaN = QNaN */ - test_op2 add.d, f9, f10, f11, F64_1, F64_QNAN(1), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - /* 1 + SNaN = QNaN */ - test_op2 add.d, f12, f13, f14, F64_1, F64_SNAN(1), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - - /* SNaN1 + SNaN2 = QNaN2 */ - test_op2 add.d, f15, f0, f1, F64_SNAN(1), F64_SNAN(2), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - /* QNaN1 + SNaN2 = QNaN2 */ - test_op2 add.d, f5, f6, f7, F64_QNAN(1), F64_SNAN(2), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - /* SNaN1 + QNaN2 = QNaN2 */ - test_op2 add.d, f8, f9, f10, F64_SNAN(1), F64_QNAN(2), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -test sub_d - /* norm - norm = denorm */ - test_op2 sub.d, f6, f7, f8, F64_MIN_NORM | 1, F64_MIN_NORM, \ - 0x00000001, 0x00000001, 0x00000001, 0x00000001, \ - FSR__, FSR__, FSR__, FSR__ -test_end - -test mul_d - test_op2 mul.d, f0, f1, f2, F64_1 | 1, F64_1 | 1, \ - F64_1 | 2, F64_1 | 2, F64_1 | 3, F64_1 | 2, \ - FSR_I, FSR_I, FSR_I, FSR_I - /* MAX_FLOAT/2 * MAX_FLOAT/2 = +inf/MAX_FLOAT */ - test_op2 mul.d, f6, f7, f8, F64_MAX_2, F64_MAX_2, \ - F64_PINF, F64_MAX, F64_PINF, F64_MAX, \ - FSR_OI, FSR_OI, FSR_OI, FSR_OI - /* min norm * min norm = 0/denorm */ - test_op2 mul.d, f6, f7, f8, F64_MIN_NORM, F64_MIN_NORM, \ - F64_0, F64_0, 0x00000001, F64_0, \ - FSR_UI, FSR_UI, FSR_UI, FSR_UI - /* inf * 0 = default NaN */ - test_op2 mul.d, f6, f7, f8, F64_PINF, F64_0, \ - F64_DNAN, F64_DNAN, F64_DNAN, F64_DNAN, \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -test madd_d - test_op3 madd.d, f0, f1, f2, f0, F64_0, F64_1 | 1, F64_1 | 1, \ - F64_1 | 2, F64_1 | 2, F64_1 | 3, F64_1 | 2, \ - FSR_I, FSR_I, FSR_I, FSR_I -test_end - -test madd_d_precision - test_op3 madd.d, f0, f1, f2, f0, \ - F64_MINUS | F64_1 | 2, F64_1 | 1, F64_1 | 1, \ - 0x3970000000000000, 0x3970000000000000, 0x3970000000000000, 0x3970000000000000, \ - FSR__, FSR__, FSR__, FSR__ -test_end - -test madd_d_nan_dfpu - /* DFPU madd/msub NaN1, NaN2, NaN3 priority: NaN1, NaN3, NaN2 */ - test_op3 madd.d, f0, f1, f2, f0, F64_QNAN(1), F64_1, F64_1, \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.d, f0, f1, f2, f0, F64_1, F64_QNAN(2), F64_1, \ - F64_QNAN(2), F64_QNAN(2), F64_QNAN(2), F64_QNAN(2), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.d, f0, f1, f2, f0, F64_1, F64_1, F64_QNAN(3), \ - F64_QNAN(3), F64_QNAN(3), F64_QNAN(3), F64_QNAN(3), \ - FSR__, FSR__, FSR__, FSR__ - - test_op3 madd.d, f0, f1, f2, f0, F64_QNAN(1), F64_QNAN(2), F64_1, \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.d, f0, f1, f2, f0, F64_QNAN(1), F64_1, F64_QNAN(3), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.d, f0, f1, f2, f0, F64_1, F64_QNAN(2), F64_QNAN(3), \ - F64_QNAN(3), F64_QNAN(3), F64_QNAN(3), F64_QNAN(3), \ - FSR__, FSR__, FSR__, FSR__ - - test_op3 madd.d, f0, f1, f2, f0, F64_QNAN(1), F64_QNAN(2), F64_QNAN(3), \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - - /* inf * 0 = default NaN */ - test_op3 madd.d, f0, f1, f2, f0, F64_1, F64_PINF, F64_0, \ - F64_DNAN, F64_DNAN, F64_DNAN, F64_DNAN, \ - FSR_V, FSR_V, FSR_V, FSR_V - /* inf * 0 + SNaN1 = QNaN1 */ - test_op3 madd.d, f0, f1, f2, f0, F64_SNAN(1), F64_PINF, F64_0, \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - /* inf * 0 + QNaN1 = QNaN1 */ - test_op3 madd.d, f0, f1, f2, f0, F64_QNAN(1), F64_PINF, F64_0, \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - - /* madd/msub SNaN turns to QNaN and sets Invalid flag */ - test_op3 madd.d, f0, f1, f2, f0, F64_SNAN(1), F64_1, F64_1, \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - test_op3 madd.d, f0, f1, f2, f0, F64_QNAN(1), F64_SNAN(2), F64_1, \ - F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), F64_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_exclusive.S b/tests/tcg/xtensa/test_exclusive.S deleted file mode 100644 index 7757a552ea00..000000000000 --- a/tests/tcg/xtensa/test_exclusive.S +++ /dev/null @@ -1,48 +0,0 @@ -#include "macros.inc" - -test_suite exclusive - -#if XCHAL_HAVE_EXCLUSIVE - -test exclusive_nowrite - movi a2, 0x29 - wsr a2, atomctl - clrex - movi a2, 1f - movi a3, 1 - s32ex a3, a2 - getex a3 - assert eqi, a3, 0 - l32i a3, a2, 0 - assert eqi, a3, 3 - -.data -.align 4 -1: - .word 3 -.text -test_end - -test exclusive_write - movi a2, 0x29 - wsr a2, atomctl - movi a2, 1f - l32ex a3, a2 - assert eqi, a3, 3 - movi a3, 2 - s32ex a3, a2 - getex a3 - assert eqi, a3, 1 - l32i a3, a2, 0 - assert eqi, a3, 2 - -.data -.align 4 -1: - .word 3 -.text -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_extui.S b/tests/tcg/xtensa/test_extui.S deleted file mode 100644 index c32bb824dfd3..000000000000 --- a/tests/tcg/xtensa/test_extui.S +++ /dev/null @@ -1,26 +0,0 @@ -#include "macros.inc" - -test_suite extui - -.macro test_extui v, shiftimm, maskimm - .if \shiftimm + \maskimm <= 32 - movi a2, \v - extui a3, a2, \shiftimm, \maskimm - movi a4, ((\v) >> (\shiftimm)) & ((1 << (\maskimm)) - 1) - assert eq, a3, a4 - .endif -.endm - -test extui - .set shiftimm, 0 - .rept 32 - .set maskimm, 1 - .rept 16 - test_extui 0xc8df1370, shiftimm, maskimm - .set maskimm, maskimm + 1 - .endr - .set shiftimm, shiftimm + 1 - .endr -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_flix.S b/tests/tcg/xtensa/test_flix.S deleted file mode 100644 index 7af06b2b8882..000000000000 --- a/tests/tcg/xtensa/test_flix.S +++ /dev/null @@ -1,77 +0,0 @@ -#include "macros.inc" - -test_suite flix - -#if XCHAL_HAVE_FLIX3 - -test misc - { - mov a3, a4 - mov a2, a3 - nop - } - { - nop - bne.w18 a2, a3, 1f - } - movi a2, 1f - { - mov a2, a3 - mov a3, a2 - nop - } - { - l32i a2, a3, 0 - add a4, a4, a2 - nop - } - { - mov a3, a4 - jx a3 - nop - } -1: -test_end - -test sum - - movi a2, 0 - movi a3, 2f - movi a4, 0 - movi a5, 4 - - loop a5, 1f - { - l32i a2, a3, 0 - addi a3, a3, 4 - add a4, a4, a2 - } -1: - add a4, a4, a2 - assert eqi, a4, 10 - .data -2: - .word 1, 2, 3, 4 - .previous -test_end - -test rep_dependency - - { - movi a2, 1 - movi a3, 2 - nop - } - { - or a2, a3, a3 - or a3, a2, a2 - nop - } - assert eqi, a2, 2 - assert eqi, a3, 1 - -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_fp0_arith.S b/tests/tcg/xtensa/test_fp0_arith.S deleted file mode 100644 index 7eefc1da409d..000000000000 --- a/tests/tcg/xtensa/test_fp0_arith.S +++ /dev/null @@ -1,261 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite fp0_arith - -#if XCHAL_HAVE_FP - -.macro movfp fr, v - movi a2, \v - wfr \fr, a2 -.endm - -.macro check_res fr, r, sr - rfr a2, \fr - dump a2 - movi a3, \r - assert eq, a2, a3 - rur a2, fsr -#if DFPU - movi a3, \sr - assert eq, a2, a3 -#else - assert eqi, a2, 0 -#endif -.endm - -test add_s - movi a2, 1 - wsr a2, cpenable - - test_op2 add.s, f0, f1, f2, 0x3fc00000, 0x34400000, \ - 0x3fc00002, 0x3fc00001, 0x3fc00002, 0x3fc00001, \ - FSR_I, FSR_I, FSR_I, FSR_I - test_op2 add.s, f3, f4, f5, 0x3fc00000, 0x34a00000, \ - 0x3fc00002, 0x3fc00002, 0x3fc00003, 0x3fc00002, \ - FSR_I, FSR_I, FSR_I, FSR_I - - /* MAX_FLOAT + MAX_FLOAT = +inf/MAX_FLOAT */ - test_op2 add.s, f6, f7, f8, 0x7f7fffff, 0x7f7fffff, \ - 0x7f800000, 0x7f7fffff, 0x7f800000, 0x7f7fffff, \ - FSR_OI, FSR_OI, FSR_OI, FSR_OI -test_end - -test add_s_inf - /* 1 + +inf = +inf */ - test_op2 add.s, f6, f7, f8, 0x3fc00000, 0x7f800000, \ - 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000, \ - FSR__, FSR__, FSR__, FSR__ - - /* +inf + -inf = default NaN */ - test_op2 add.s, f0, f1, f2, 0x7f800000, 0xff800000, \ - 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -#if DFPU -test add_s_nan_dfpu - /* 1 + QNaN = QNaN */ - test_op2 add.s, f9, f10, f11, 0x3fc00000, 0x7fc00001, \ - 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, \ - FSR__, FSR__, FSR__, FSR__ - /* 1 + SNaN = QNaN */ - test_op2 add.s, f12, f13, f14, 0x3fc00000, 0x7f800001, \ - 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, \ - FSR_V, FSR_V, FSR_V, FSR_V - - /* SNaN1 + SNaN2 = QNaN2 */ - test_op2 add.s, f15, f0, f1, 0x7f800001, 0x7fbfffff, \ - 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, \ - FSR_V, FSR_V, FSR_V, FSR_V - test_op2 add.s, f2, f3, f4, 0x7fbfffff, 0x7f800001, \ - 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, \ - FSR_V, FSR_V, FSR_V, FSR_V - /* QNaN1 + SNaN2 = QNaN2 */ - test_op2 add.s, f5, f6, f7, 0x7fc00001, 0x7fbfffff, \ - 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, \ - FSR_V, FSR_V, FSR_V, FSR_V - /* SNaN1 + QNaN2 = QNaN2 */ - test_op2 add.s, f8, f9, f10, 0x7fbfffff, 0x7fc00001, \ - 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end -#else -test add_s_nan_fpu2k - /* 1 + QNaN = QNaN */ - test_op2 add.s, f9, f10, f11, 0x3fc00000, 0x7fc00001, \ - 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, \ - FSR__, FSR__, FSR__, FSR__ - /* 1 + SNaN = SNaN */ - test_op2 add.s, f12, f13, f14, 0x3fc00000, 0x7f800001, \ - 0x7f800001, 0x7f800001, 0x7f800001, 0x7f800001, \ - FSR__, FSR__, FSR__, FSR__ - /* SNaN1 + SNaN2 = SNaN1 */ - test_op2 add.s, f15, f0, f1, 0x7f800001, 0x7fbfffff, \ - 0x7f800001, 0x7f800001, 0x7f800001, 0x7f800001, \ - FSR__, FSR__, FSR__, FSR__ - test_op2 add.s, f2, f3, f4, 0x7fbfffff, 0x7f800001, \ - 0x7fbfffff, 0x7fbfffff, 0x7fbfffff, 0x7fbfffff, \ - FSR__, FSR__, FSR__, FSR__ - /* QNaN1 + SNaN2 = QNaN1 */ - test_op2 add.s, f5, f6, f7, 0x7fc00001, 0x7fbfffff, \ - 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, \ - FSR__, FSR__, FSR__, FSR__ - /* SNaN1 + QNaN2 = SNaN1 */ - test_op2 add.s, f8, f9, f10, 0x7fbfffff, 0x7fc00001, \ - 0x7fbfffff, 0x7fbfffff, 0x7fbfffff, 0x7fbfffff, \ - FSR__, FSR__, FSR__, FSR__ -test_end -#endif - -test sub_s - test_op2 sub.s, f0, f1, f0, 0x3f800001, 0x33800000, \ - 0x3f800000, 0x3f800000, 0x3f800001, 0x3f800000, \ - FSR_I, FSR_I, FSR_I, FSR_I - test_op2 sub.s, f0, f1, f1, 0x3f800002, 0x33800000, \ - 0x3f800002, 0x3f800001, 0x3f800002, 0x3f800001, \ - FSR_I, FSR_I, FSR_I, FSR_I - - /* norm - norm = denorm */ - test_op2 sub.s, f6, f7, f8, 0x00800001, 0x00800000, \ - 0x00000001, 0x00000001, 0x00000001, 0x00000001, \ - FSR__, FSR__, FSR__, FSR__ -test_end - -test mul_s - test_op2 mul.s, f0, f1, f2, 0x3f800001, 0x3f800001, \ - 0x3f800002, 0x3f800002, 0x3f800003, 0x3f800002, \ - FSR_I, FSR_I, FSR_I, FSR_I - /* MAX_FLOAT/2 * MAX_FLOAT/2 = +inf/MAX_FLOAT */ - test_op2 mul.s, f6, f7, f8, 0x7f000000, 0x7f000000, \ - 0x7f800000, 0x7f7fffff, 0x7f800000, 0x7f7fffff, \ - FSR_OI, FSR_OI, FSR_OI, FSR_OI - /* min norm * min norm = 0/denorm */ - test_op2 mul.s, f6, f7, f8, 0x00800001, 0x00800000, \ - 0x00000000, 0x00000000, 0x00000001, 0x00000000, \ - FSR_UI, FSR_UI, FSR_UI, FSR_UI - /* inf * 0 = default NaN */ - test_op2 mul.s, f6, f7, f8, 0x7f800000, 0x00000000, \ - 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -test madd_s - test_op3 madd.s, f0, f1, f2, f0, 0, 0x3f800001, 0x3f800001, \ - 0x3f800002, 0x3f800002, 0x3f800003, 0x3f800002, \ - FSR_I, FSR_I, FSR_I, FSR_I -test_end - -test madd_s_precision - test_op3 madd.s, f0, f1, f2, f0, 0xbf800002, 0x3f800001, 0x3f800001, \ - 0x28800000, 0x28800000, 0x28800000, 0x28800000, \ - FSR__, FSR__, FSR__, FSR__ -test_end - -#if DFPU -test madd_s_nan_dfpu - /* DFPU madd/msub NaN1, NaN2, NaN3 priority: NaN1, NaN3, NaN2 */ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_1, F32_1, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_QNAN(2), F32_1, \ - F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_1, F32_QNAN(3), \ - F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), \ - FSR__, FSR__, FSR__, FSR__ - - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_QNAN(2), F32_1, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_1, F32_QNAN(3), \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_QNAN(2), F32_QNAN(3), \ - F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), \ - FSR__, FSR__, FSR__, FSR__ - - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_QNAN(2), F32_QNAN(3), \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - - /* inf * 0 = default NaN */ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_PINF, F32_0, \ - F32_DNAN, F32_DNAN, F32_DNAN, F32_DNAN, \ - FSR_V, FSR_V, FSR_V, FSR_V - /* inf * 0 + SNaN1 = QNaN1 */ - test_op3 madd.s, f0, f1, f2, f0, F32_SNAN(1), F32_PINF, F32_0, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - /* inf * 0 + QNaN1 = QNaN1 */ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_PINF, F32_0, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - - /* madd/msub SNaN turns to QNaN and sets Invalid flag */ - test_op3 madd.s, f0, f1, f2, f0, F32_SNAN(1), F32_1, F32_1, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_SNAN(2), F32_1, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end -#else -test madd_s_nan_fpu2k - /* FPU2000 madd/msub NaN1, NaN2, NaN3 priority: NaN2, NaN3, NaN1 */ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_1, F32_1, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_QNAN(2), F32_1, \ - F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_1, F32_QNAN(3), \ - F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), \ - FSR__, FSR__, FSR__, FSR__ - - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_QNAN(2), F32_1, \ - F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_1, F32_QNAN(3), \ - F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), F32_QNAN(3), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_QNAN(2), F32_QNAN(3), \ - F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), \ - FSR__, FSR__, FSR__, FSR__ - - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_QNAN(2), F32_QNAN(3), \ - F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), F32_QNAN(2), \ - FSR__, FSR__, FSR__, FSR__ - - /* inf * 0 = default NaN */ - test_op3 madd.s, f0, f1, f2, f0, F32_1, F32_PINF, F32_0, \ - F32_DNAN, F32_DNAN, F32_DNAN, F32_DNAN, \ - FSR__, FSR__, FSR__, FSR__ - /* inf * 0 + SNaN1 = SNaN1 */ - test_op3 madd.s, f0, f1, f2, f0, F32_SNAN(1), F32_PINF, F32_0, \ - F32_SNAN(1), F32_SNAN(1), F32_SNAN(1), F32_SNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - /* inf * 0 + QNaN1 = QNaN1 */ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_PINF, F32_0, \ - F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), F32_QNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - - /* madd/msub SNaN is preserved */ - test_op3 madd.s, f0, f1, f2, f0, F32_SNAN(1), F32_1, F32_1, \ - F32_SNAN(1), F32_SNAN(1), F32_SNAN(1), F32_SNAN(1), \ - FSR__, FSR__, FSR__, FSR__ - test_op3 madd.s, f0, f1, f2, f0, F32_QNAN(1), F32_SNAN(2), F32_1, \ - F32_SNAN(2), F32_SNAN(2), F32_SNAN(2), F32_SNAN(2), \ - FSR__, FSR__, FSR__, FSR__ -test_end -#endif - -test msub_s - test_op3 msub.s, f0, f1, f2, f0, 0x3f800000, 0x3f800001, 0x3f800001, \ - 0xb4800000, 0xb4800000, 0xb4800000, 0xb4800001, \ - FSR_I, FSR_I, FSR_I, FSR_I -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_fp0_conv.S b/tests/tcg/xtensa/test_fp0_conv.S deleted file mode 100644 index cfee6e51790c..000000000000 --- a/tests/tcg/xtensa/test_fp0_conv.S +++ /dev/null @@ -1,315 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite fp0_conv - -#if XCHAL_HAVE_FP - -.macro movfp fr, v - movi a2, \v - wfr \fr, a2 -.endm - -.macro test_ftoi_ex op, r0, fr0, v, c, r, sr - movi a2, 0 - wur a2, fsr - movfp \fr0, \v - \op \r0, \fr0, \c - dump \r0 - movi a3, \r - assert eq, \r0, a3 - rur a2, fsr -#if DFPU - movi a3, \sr - assert eq, a2, a3 -#else - assert eqi, a2, 0 -#endif -.endm - -.macro test_ftoi op, r0, fr0, v, c, r, sr - movi a2, 0 - wur a2, fcr - test_ftoi_ex \op, \r0, \fr0, \v, \c, \r, \sr - movi a2, 0x7c - wur a2, fcr - test_ftoi_ex \op, \r0, \fr0, \v, \c, \r, \sr -.endm - - -.macro test_itof_ex op, fr0, ar0, v, c, r, sr - movi a2, 0 - wur a2, fsr - movi \ar0, \v - \op \fr0, \ar0, \c - - rfr a2, \fr0 - dump a2 - movi a3, \r - assert eq, a2, a3 - rur a2, fsr -#if DFPU - movi a3, \sr - assert eq, a2, a3 -#else - assert eqi, a2, 0 -#endif -.endm - -.macro test_itof_rm op, fr0, ar0, v, c, rm, r, sr - movi a2, \rm - wur a2, fcr - test_itof_ex \op, \fr0, \ar0, \v, \c, \r, \sr - movi a2, (\rm) | 0x7c - wur a2, fcr - test_itof_ex \op, \fr0, \ar0, \v, \c, \r, \sr -.endm - -.macro test_itof op, fr0, ar0, v, c, r0, r1, r2, r3, sr - test_itof_rm \op, \fr0, \ar0, \v, \c, 0, \r0, \sr - test_itof_rm \op, \fr0, \ar0, \v, \c, 1, \r1, \sr - test_itof_rm \op, \fr0, \ar0, \v, \c, 2, \r2, \sr - test_itof_rm \op, \fr0, \ar0, \v, \c, 3, \r3, \sr -.endm - -test round_s - movi a2, 1 - wsr a2, cpenable - - /* NaN */ - test_ftoi round.s, a2, f0, 0xffc00001, 0, 0x7fffffff, FSR_V - test_ftoi round.s, a2, f0, 0xff800001, 0, 0x7fffffff, FSR_V - - /* -inf */ - test_ftoi round.s, a2, f0, 0xff800000, 0, 0x80000000, FSR_V - - /* negative overflow */ - test_ftoi round.s, a2, f0, 0xceffffff, 1, 0x80000000, FSR_V - test_ftoi round.s, a2, f0, 0xcf000000, 0, 0x80000000, FSR__ - test_ftoi round.s, a2, f0, 0xceffffff, 0, 0x80000080, FSR__ - - /* negative */ - test_ftoi round.s, a2, f0, 0xbfa00000, 1, -2, FSR_I /* -1.25 * 2 */ - test_ftoi round.s, a2, f0, 0xbfc00000, 0, -2, FSR_I /* -1.5 */ - test_ftoi round.s, a2, f0, 0xbf800000, 1, -2, FSR__ /* -1 * 2 */ - test_ftoi round.s, a2, f0, 0xbf800000, 0, -1, FSR__ /* -1 */ - test_ftoi round.s, a2, f0, 0xbf400000, 0, -1, FSR_I /* -0.75 */ - test_ftoi round.s, a2, f0, 0xbf000000, 0, 0, FSR_I /* -0.5 */ - - /* positive */ - test_ftoi round.s, a2, f0, 0x3f000000, 0, 0, FSR_I /* 0.5 */ - test_ftoi round.s, a2, f0, 0x3f400000, 0, 1, FSR_I /* 0.75 */ - test_ftoi round.s, a2, f0, 0x3f800000, 0, 1, FSR__ /* 1 */ - test_ftoi round.s, a2, f0, 0x3f800000, 1, 2, FSR__ /* 1 * 2 */ - test_ftoi round.s, a2, f0, 0x3fc00000, 0, 2, FSR_I /* 1.5 */ - test_ftoi round.s, a2, f0, 0x3fa00000, 1, 2, FSR_I /* 1.25 * 2 */ - - /* positive overflow */ - test_ftoi round.s, a2, f0, 0x4effffff, 0, 0x7fffff80, FSR__ - test_ftoi round.s, a2, f0, 0x4f000000, 0, 0x7fffffff, FSR_V - test_ftoi round.s, a2, f0, 0x4effffff, 1, 0x7fffffff, FSR_V - - /* +inf */ - test_ftoi round.s, a2, f0, 0x7f800000, 0, 0x7fffffff, FSR_V - - /* NaN */ - test_ftoi round.s, a2, f0, 0x7f800001, 0, 0x7fffffff, FSR_V - test_ftoi round.s, a2, f0, 0x7fc00000, 0, 0x7fffffff, FSR_V -test_end - -test trunc_s - /* NaN */ - test_ftoi trunc.s, a2, f0, 0xffc00001, 0, 0x7fffffff, FSR_V - test_ftoi trunc.s, a2, f0, 0xff800001, 0, 0x7fffffff, FSR_V - - /* -inf */ - test_ftoi trunc.s, a2, f0, 0xff800000, 0, 0x80000000, FSR_V - - /* negative overflow */ - test_ftoi trunc.s, a2, f0, 0xceffffff, 1, 0x80000000, FSR_V - test_ftoi trunc.s, a2, f0, 0xcf000000, 0, 0x80000000, FSR__ - test_ftoi trunc.s, a2, f0, 0xceffffff, 0, 0x80000080, FSR__ - - /* negative */ - test_ftoi trunc.s, a2, f0, 0xbfa00000, 1, -2, FSR_I /* -1.25 * 2 */ - test_ftoi trunc.s, a2, f0, 0xbfc00000, 0, -1, FSR_I /* -1.5 */ - test_ftoi trunc.s, a2, f0, 0xbf800000, 1, -2, FSR__ /* -1 * 2 */ - test_ftoi trunc.s, a2, f0, 0xbf800000, 0, -1, FSR__ /* -1 */ - test_ftoi trunc.s, a2, f0, 0xbf400000, 0, 0, FSR_I /* -0.75 */ - test_ftoi trunc.s, a2, f0, 0xbf000000, 0, 0, FSR_I /* -0.5 */ - - /* positive */ - test_ftoi trunc.s, a2, f0, 0x3f000000, 0, 0, FSR_I /* 0.5 */ - test_ftoi trunc.s, a2, f0, 0x3f400000, 0, 0, FSR_I /* 0.75 */ - test_ftoi trunc.s, a2, f0, 0x3f800000, 0, 1, FSR__ /* 1 */ - test_ftoi trunc.s, a2, f0, 0x3f800000, 1, 2, FSR__ /* 1 * 2 */ - test_ftoi trunc.s, a2, f0, 0x3fc00000, 0, 1, FSR_I /* 1.5 */ - test_ftoi trunc.s, a2, f0, 0x3fa00000, 1, 2, FSR_I /* 1.25 * 2 */ - - /* positive overflow */ - test_ftoi trunc.s, a2, f0, 0x4effffff, 0, 0x7fffff80, FSR__ - test_ftoi trunc.s, a2, f0, 0x4f000000, 0, 0x7fffffff, FSR_V - test_ftoi trunc.s, a2, f0, 0x4effffff, 1, 0x7fffffff, FSR_V - - /* +inf */ - test_ftoi trunc.s, a2, f0, 0x7f800000, 0, 0x7fffffff, FSR_V - - /* NaN */ - test_ftoi trunc.s, a2, f0, 0x7f800001, 0, 0x7fffffff, FSR_V - test_ftoi trunc.s, a2, f0, 0x7fc00000, 0, 0x7fffffff, FSR_V -test_end - -test floor_s - /* NaN */ - test_ftoi floor.s, a2, f0, 0xffc00001, 0, 0x7fffffff, FSR_V - test_ftoi floor.s, a2, f0, 0xff800001, 0, 0x7fffffff, FSR_V - - /* -inf */ - test_ftoi floor.s, a2, f0, 0xff800000, 0, 0x80000000, FSR_V - - /* negative overflow */ - test_ftoi floor.s, a2, f0, 0xceffffff, 1, 0x80000000, FSR_V - test_ftoi floor.s, a2, f0, 0xcf000000, 0, 0x80000000, FSR__ - test_ftoi floor.s, a2, f0, 0xceffffff, 0, 0x80000080, FSR__ - - /* negative */ - test_ftoi floor.s, a2, f0, 0xbfa00000, 1, -3, FSR_I /* -1.25 * 2 */ - test_ftoi floor.s, a2, f0, 0xbfc00000, 0, -2, FSR_I /* -1.5 */ - test_ftoi floor.s, a2, f0, 0xbf800000, 1, -2, FSR__ /* -1 * 2 */ - test_ftoi floor.s, a2, f0, 0xbf800000, 0, -1, FSR__ /* -1 */ - test_ftoi floor.s, a2, f0, 0xbf400000, 0, -1, FSR_I /* -0.75 */ - test_ftoi floor.s, a2, f0, 0xbf000000, 0, -1, FSR_I /* -0.5 */ - - /* positive */ - test_ftoi floor.s, a2, f0, 0x3f000000, 0, 0, FSR_I /* 0.5 */ - test_ftoi floor.s, a2, f0, 0x3f400000, 0, 0, FSR_I /* 0.75 */ - test_ftoi floor.s, a2, f0, 0x3f800000, 0, 1, FSR__ /* 1 */ - test_ftoi floor.s, a2, f0, 0x3f800000, 1, 2, FSR__ /* 1 * 2 */ - test_ftoi floor.s, a2, f0, 0x3fc00000, 0, 1, FSR_I /* 1.5 */ - test_ftoi floor.s, a2, f0, 0x3fa00000, 1, 2, FSR_I /* 1.25 * 2 */ - - /* positive overflow */ - test_ftoi floor.s, a2, f0, 0x4effffff, 0, 0x7fffff80, FSR__ - test_ftoi floor.s, a2, f0, 0x4f000000, 0, 0x7fffffff, FSR_V - test_ftoi floor.s, a2, f0, 0x4effffff, 1, 0x7fffffff, FSR_V - - /* +inf */ - test_ftoi floor.s, a2, f0, 0x7f800000, 0, 0x7fffffff, FSR_V - - /* NaN */ - test_ftoi floor.s, a2, f0, 0x7f800001, 0, 0x7fffffff, FSR_V - test_ftoi floor.s, a2, f0, 0x7fc00000, 0, 0x7fffffff, FSR_V -test_end - -test ceil_s - /* NaN */ - test_ftoi ceil.s, a2, f0, 0xffc00001, 0, 0x7fffffff, FSR_V - test_ftoi ceil.s, a2, f0, 0xff800001, 0, 0x7fffffff, FSR_V - - /* -inf */ - test_ftoi ceil.s, a2, f0, 0xff800000, 0, 0x80000000, FSR_V - - /* negative overflow */ - test_ftoi ceil.s, a2, f0, 0xceffffff, 1, 0x80000000, FSR_V - test_ftoi ceil.s, a2, f0, 0xcf000000, 0, 0x80000000, FSR__ - test_ftoi ceil.s, a2, f0, 0xceffffff, 0, 0x80000080, FSR__ - - /* negative */ - test_ftoi ceil.s, a2, f0, 0xbfa00000, 1, -2, FSR_I /* -1.25 * 2 */ - test_ftoi ceil.s, a2, f0, 0xbfc00000, 0, -1, FSR_I /* -1.5 */ - test_ftoi ceil.s, a2, f0, 0xbf800000, 1, -2, FSR__ /* -1 * 2 */ - test_ftoi ceil.s, a2, f0, 0xbf800000, 0, -1, FSR__ /* -1 */ - test_ftoi ceil.s, a2, f0, 0xbf400000, 0, 0, FSR_I /* -0.75 */ - test_ftoi ceil.s, a2, f0, 0xbf000000, 0, 0, FSR_I /* -0.5 */ - - /* positive */ - test_ftoi ceil.s, a2, f0, 0x3f000000, 0, 1, FSR_I /* 0.5 */ - test_ftoi ceil.s, a2, f0, 0x3f400000, 0, 1, FSR_I /* 0.75 */ - test_ftoi ceil.s, a2, f0, 0x3f800000, 0, 1, FSR__ /* 1 */ - test_ftoi ceil.s, a2, f0, 0x3f800000, 1, 2, FSR__ /* 1 * 2 */ - test_ftoi ceil.s, a2, f0, 0x3fc00000, 0, 2, FSR_I /* 1.5 */ - test_ftoi ceil.s, a2, f0, 0x3fa00000, 1, 3, FSR_I /* 1.25 * 2 */ - - /* positive overflow */ - test_ftoi ceil.s, a2, f0, 0x4effffff, 0, 0x7fffff80, FSR__ - test_ftoi ceil.s, a2, f0, 0x4f000000, 0, 0x7fffffff, FSR_V - test_ftoi ceil.s, a2, f0, 0x4effffff, 1, 0x7fffffff, FSR_V - - /* +inf */ - test_ftoi ceil.s, a2, f0, 0x7f800000, 0, 0x7fffffff, FSR_V - - /* NaN */ - test_ftoi ceil.s, a2, f0, 0x7f800001, 0, 0x7fffffff, FSR_V - test_ftoi ceil.s, a2, f0, 0x7fc00000, 0, 0x7fffffff, FSR_V -test_end - -test utrunc_s - /* NaN */ - test_ftoi utrunc.s, a2, f0, 0xffc00001, 0, 0xffffffff, FSR_V - test_ftoi utrunc.s, a2, f0, 0xff800001, 0, 0xffffffff, FSR_V - - /* -inf */ - test_ftoi utrunc.s, a2, f0, 0xff800000, 0, 0x80000000, FSR_V - - /* negative overflow */ - test_ftoi utrunc.s, a2, f0, 0xceffffff, 1, 0x80000000, FSR_V - test_ftoi utrunc.s, a2, f0, 0xcf000000, 0, 0x80000000, FSR_V - test_ftoi utrunc.s, a2, f0, 0xceffffff, 0, 0x80000080, FSR_V - - /* negative */ - test_ftoi utrunc.s, a2, f0, 0xbfa00000, 1, -2, FSR_V /* -1.25 * 2 */ - test_ftoi utrunc.s, a2, f0, 0xbfc00000, 0, -1, FSR_V /* -1.5 */ - test_ftoi utrunc.s, a2, f0, 0xbf800000, 1, -2, FSR_V /* -1 * 2 */ - test_ftoi utrunc.s, a2, f0, 0xbf800000, 0, -1, FSR_V /* -1 */ - test_ftoi utrunc.s, a2, f0, 0xbf400000, 0, 0, FSR_I /* -0.75 */ - test_ftoi utrunc.s, a2, f0, 0xbf000000, 0, 0, FSR_I /* -0.5 */ - - /* positive */ - test_ftoi utrunc.s, a2, f0, 0x3f000000, 0, 0, FSR_I /* 0.5 */ - test_ftoi utrunc.s, a2, f0, 0x3f400000, 0, 0, FSR_I /* 0.75 */ - test_ftoi utrunc.s, a2, f0, 0x3f800000, 0, 1, FSR__ /* 1 */ - test_ftoi utrunc.s, a2, f0, 0x3f800000, 1, 2, FSR__ /* 1 * 2 */ - test_ftoi utrunc.s, a2, f0, 0x3fc00000, 0, 1, FSR_I /* 1.5 */ - test_ftoi utrunc.s, a2, f0, 0x3fa00000, 1, 2, FSR_I /* 1.25 * 2 */ - - /* positive overflow */ - test_ftoi utrunc.s, a2, f0, 0x4effffff, 0, 0x7fffff80, FSR__ - test_ftoi utrunc.s, a2, f0, 0x4f000000, 0, 0x80000000, FSR__ - test_ftoi utrunc.s, a2, f0, 0x4effffff, 1, 0xffffff00, FSR__ - test_ftoi utrunc.s, a2, f0, 0x4f800000, 1, 0xffffffff, FSR_V - - /* +inf */ - test_ftoi utrunc.s, a2, f0, 0x7f800000, 0, 0xffffffff, FSR_V - - /* NaN */ - test_ftoi utrunc.s, a2, f0, 0x7f800001, 0, 0xffffffff, FSR_V - test_ftoi utrunc.s, a2, f0, 0x7fc00000, 0, 0xffffffff, FSR_V -test_end - -test float_s - test_itof float.s, f0, a2, -1, 0, \ - 0xbf800000, 0xbf800000, 0xbf800000, 0xbf800000, FSR__ - test_itof float.s, f0, a2, 0, 0, 0, 0, 0, 0, FSR__ - test_itof float.s, f0, a2, 1, 1, \ - 0x3f000000, 0x3f000000, 0x3f000000, 0x3f000000, FSR__ - test_itof float.s, f0, a2, 1, 0, \ - 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, FSR__ - test_itof float.s, f0, a2, 0x7fffffff, 0, \ - 0x4f000000, 0x4effffff, 0x4f000000, 0x4effffff, FSR_I -test_end - -test ufloat_s - test_itof ufloat.s, f0, a2, 0, 0, 0, 0, 0, 0, FSR__ - test_itof ufloat.s, f0, a2, 1, 1, \ - 0x3f000000, 0x3f000000, 0x3f000000, 0x3f000000, FSR__ - test_itof ufloat.s, f0, a2, 1, 0, \ - 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, FSR__ - test_itof ufloat.s, f0, a2, 0x7fffffff, 0, \ - 0x4f000000, 0x4effffff, 0x4f000000, 0x4effffff, FSR_I - test_itof ufloat.s, f0, a2, 0xffffffff, 0, \ - 0x4f800000, 0x4f7fffff, 0x4f800000, 0x4f7fffff, FSR_I -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_fp0_div.S b/tests/tcg/xtensa/test_fp0_div.S deleted file mode 100644 index c3e7ad7bb5b3..000000000000 --- a/tests/tcg/xtensa/test_fp0_div.S +++ /dev/null @@ -1,82 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite fp0_div - -#if XCHAL_HAVE_FP_DIV - -.macro divs_seq q, a, b, r, y, y0, an, bn, e, ex - div0.s \y0, \b - nexp01.s \bn, \b - const.s \e, 1 - maddn.s \e, \bn, \y0 - mov.s \y, \y0 - mov.s \ex, \b - nexp01.s \an, \a - maddn.s \y, \e, \y0 - const.s \e, 1 - const.s \q, 0 - neg.s \r, \an - maddn.s \e, \bn, \y - maddn.s \q, \r, \y0 - mkdadj.s \ex, \a - maddn.s \y, \e, \y - maddn.s \r, \bn, \q - const.s \e, 1 - maddn.s \e, \bn, \y - maddn.s \q, \r, \y - neg.s \r, \an - maddn.s \y, \e, \y - maddn.s \r, \bn, \q - addexpm.s \q, \ex - addexp.s \y, \ex - divn.s \q, \r, \y -.endm - -.macro div_s fr0, fr1, fr2 - divs_seq \fr0, \fr1, \fr2, f9, f10, f11, f12, f13, f14, f15 -.endm - -.macro movfp fr, v - movi a2, \v - wfr \fr, a2 -.endm - -.macro check_res fr, r, sr - rfr a2, \fr - dump a2 - movi a3, \r - assert eq, a2, a3 - rur a2, fsr - movi a3, \sr - assert eq, a2, a3 -.endm - -test div_s - movi a2, 1 - wsr a2, cpenable - - test_op2 div_s, f0, f1, f2, 0x40000000, 0x40400000, \ - 0x3f2aaaab, 0x3f2aaaaa, 0x3f2aaaab, 0x3f2aaaaa, \ - FSR_I, FSR_I, FSR_I, FSR_I - test_op2 div_s, f3, f4, f5, F32_1, F32_0, \ - F32_PINF, F32_PINF, F32_PINF, F32_PINF, \ - FSR_Z, FSR_Z, FSR_Z, FSR_Z - test_op2 div_s, f6, f7, f8, F32_0, F32_0, \ - F32_DNAN, F32_DNAN, F32_DNAN, F32_DNAN, \ - FSR_V, FSR_V, FSR_V, FSR_V - - /* MAX_FLOAT / 0.5 = +inf/MAX_FLOAT */ - test_op2 div_s, f0, f1, f2, F32_MAX, F32_0_5, \ - F32_PINF, F32_MAX, F32_PINF, F32_MAX, \ - FSR_OI, FSR_OI, FSR_OI, FSR_OI - - /* 0.5 / MAX_FLOAT = denorm */ - test_op2 div_s, f0, f1, f2, F32_0_5, F32_MAX, \ - 0x00100000, 0x00100000, 0x00100001, 0x00100000, \ - FSR_UI, FSR_UI, FSR_UI, FSR_UI -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_fp0_sqrt.S b/tests/tcg/xtensa/test_fp0_sqrt.S deleted file mode 100644 index 585973dce6bc..000000000000 --- a/tests/tcg/xtensa/test_fp0_sqrt.S +++ /dev/null @@ -1,76 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite fp0_sqrt - -#if XCHAL_HAVE_FP_SQRT - -.macro sqrt_seq r, a, y, t1, hn, h2, t5, h - sqrt0.s \y, \a - const.s \t1, 0 - maddn.s \t1, \y, \y - nexp01.s \hn, \a - const.s \r, 3 - addexp.s \hn, \r - maddn.s \r, \t1, \hn - nexp01.s \t1, \a - neg.s \h2, \t1 - maddn.s \y, \r, \y - const.s \r, 0 - const.s \t5, 0 - const.s \h, 0 - maddn.s \r, \h2, \y - maddn.s \t5, \y, \hn - const.s \hn, 3 - maddn.s \h, \hn, \y - maddn.s \t1, \r, \r - maddn.s \hn, \t5, \y - neg.s \y, \h - maddn.s \r, \t1, \y - maddn.s \h, \hn, \h - mksadj.s \y, \a - nexp01.s \a, \a - maddn.s \a, \r, \r - neg.s \t1, \h - addexpm.s \r, \y - addexp.s \t1, \y - divn.s \r, \a, \t1 -.endm - -.macro sqrt_s fr0, fr1 - sqrt_seq \fr0, \fr1, f10, f11, f12, f13, f14, f15 -.endm - -.macro movfp fr, v - movi a2, \v - wfr \fr, a2 -.endm - -.macro check_res fr, r, sr - rfr a2, \fr - dump a2 - movi a3, \r - assert eq, a2, a3 - rur a2, fsr - movi a3, \sr - assert eq, a2, a3 -.endm - -test sqrt_s - movi a2, 1 - wsr a2, cpenable - - test_op1 sqrt_s, f0, f1, 0x40000000, \ - 0x3fb504f3, 0x3fb504f3, 0x3fb504f4, 0x3fb504f3, \ - FSR_I, FSR_I, FSR_I, FSR_I - test_op1 sqrt_s, f3, f4, F32_1, \ - F32_1, F32_1, F32_1, F32_1, \ - FSR__, FSR__, FSR__, FSR__ - test_op1 sqrt_s, f6, f7, F32_MINUS | F32_1, \ - F32_DNAN, F32_DNAN, F32_DNAN, F32_DNAN, \ - FSR_V, FSR_V, FSR_V, FSR_V -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_fp1.S b/tests/tcg/xtensa/test_fp1.S deleted file mode 100644 index 77336a3fcf2c..000000000000 --- a/tests/tcg/xtensa/test_fp1.S +++ /dev/null @@ -1,147 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite fp1 - -#if XCHAL_HAVE_FP - -.macro movfp fr, v - movi a2, \v - wfr \fr, a2 -.endm - -.macro test_ord_ex op, br, fr0, fr1, v0, v1, r, sr - movi a2, 0 - wur a2, fsr - movfp \fr0, \v0 - movfp \fr1, \v1 - \op \br, \fr0, \fr1 - movi a2, 0 - movi a3, 1 - movt a2, a3, \br - assert eqi, a2, \r - rur a2, fsr -#if DFPU - movi a3, \sr - assert eq, a2, a3 -#else - assert eqi, a2, 0 -#endif -.endm - -.macro test_ord op, br, fr0, fr1, v0, v1, r, sr - movi a2, 0 - wur a2, fcr - test_ord_ex \op, \br, \fr0, \fr1, \v0, \v1, \r, \sr - movi a2, 0x7c - wur a2, fcr - test_ord_ex \op, \br, \fr0, \fr1, \v0, \v1, \r, \sr -.endm - -.macro test_ord_all op, aa, ab, ba, aPI, PIa, aN, Na, II, IN, NI, qnan_sr - test_ord \op b0, f0, f1, 0x3f800000, 0x3f800000, \aa, FSR__ /* ord == ord */ - test_ord \op b1, f2, f3, 0x3f800000, 0x3fc00000, \ab, FSR__ /* ord < ord */ - test_ord \op b2, f4, f5, 0x3fc00000, 0x3f800000, \ba, FSR__ /* ord > ord */ - test_ord \op b3, f6, f7, 0x3f800000, 0x7f800000, \aPI, FSR__ /* ord +INF */ - test_ord \op b4, f8, f9, 0x7f800000, 0x3f800000, \PIa, FSR__ /* +INF ord */ - test_ord \op b5, f10, f11, 0x3f800000, 0xffc00001, \aN, \qnan_sr /* ord -QNaN */ - test_ord \op b6, f12, f13, 0x3f800000, 0xff800001, \aN, FSR_V /* ord -SNaN */ - test_ord \op b7, f14, f15, 0x3f800000, 0x7f800001, \aN, FSR_V /* ord +SNaN */ - test_ord \op b8, f0, f1, 0x3f800000, 0x7fc00000, \aN, \qnan_sr /* ord +QNaN */ - test_ord \op b9, f2, f3, 0xffc00001, 0x3f800000, \Na, \qnan_sr /* -QNaN ord */ - test_ord \op b10, f4, f5, 0xff800001, 0x3f800000, \Na, FSR_V /* -SNaN ord */ - test_ord \op b11, f6, f7, 0x7f800001, 0x3f800000, \Na, FSR_V /* +SNaN ord */ - test_ord \op b12, f8, f9, 0x7fc00000, 0x3f800000, \Na, \qnan_sr /* +QNaN ord */ - test_ord \op b13, f10, f11, 0x7f800000, 0x7f800000, \II, FSR__ /* +INF +INF */ - test_ord \op b14, f12, f13, 0x7f800000, 0x7fc00000, \IN, \qnan_sr /* +INF +QNaN */ - test_ord \op b15, f14, f15, 0x7fc00000, 0x7f800000, \NI, \qnan_sr /* +QNaN +INF */ -.endm - -test un_s - movi a2, 1 - wsr a2, cpenable - test_ord_all un.s, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, FSR__ -test_end - -test oeq_s - test_ord_all oeq.s, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, FSR__ -test_end - -test ueq_s - test_ord_all ueq.s, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, FSR__ -test_end - -test olt_s - test_ord_all olt.s, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, FSR_V -test_end - -test ult_s - test_ord_all ult.s, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, FSR__ -test_end - -test ole_s - test_ord_all ole.s, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, FSR_V -test_end - -test ule_s - test_ord_all ule.s, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, FSR__ -test_end - -.macro test_cond op, fr0, fr1, cr, v0, v1, r - movfp \fr0, \v0 - movfp \fr1, \v1 - \op \fr0, \fr1, \cr - rfr a2, \fr0 - movi a3, \r - assert eq, a2, a3 -.endm - -test moveqz_s - movi a3, 0 - test_cond moveqz.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 - movi a3, 1 - test_cond moveqz.s, f0, f1, a3, 0, 0x3f800000, 0 -test_end - -test movnez_s - movi a3, 0 - test_cond movnez.s, f0, f1, a3, 0, 0x3f800000, 0 - movi a3, 1 - test_cond movnez.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 -test_end - -test movltz_s - movi a3, -1 - test_cond movltz.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 - movi a3, 0 - test_cond movltz.s, f0, f1, a3, 0, 0x3f800000, 0 - movi a3, 1 - test_cond movltz.s, f0, f1, a3, 0, 0x3f800000, 0 -test_end - -test movgez_s - movi a3, -1 - test_cond movgez.s, f0, f1, a3, 0, 0x3f800000, 0 - movi a3, 0 - test_cond movgez.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 - movi a3, 1 - test_cond movgez.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 -test_end - -test movf_s - olt.s b0, f0, f0 - test_cond movf.s, f0, f1, b0, 0, 0x3f800000, 0x3f800000 - ueq.s b0, f0, f0 - test_cond movf.s, f0, f1, b0, 0, 0x3f800000, 0 -test_end - -test movt_s - ueq.s b0, f0, f0 - test_cond movt.s, f0, f1, b0, 0, 0x3f800000, 0x3f800000 - olt.s b0, f0, f0 - test_cond movt.s, f0, f1, b0, 0, 0x3f800000, 0 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_fp_cpenable.S b/tests/tcg/xtensa/test_fp_cpenable.S deleted file mode 100644 index 882bb2f3ceb1..000000000000 --- a/tests/tcg/xtensa/test_fp_cpenable.S +++ /dev/null @@ -1,27 +0,0 @@ -#include "macros.inc" - -test_suite fp_cpenable - -#if XCHAL_HAVE_FP - -test rur - set_vector kernel, 2f - movi a2, 0 - wsr a2, cpenable - isync -1: - rur a2, fsr - //wfr f0, a2 - test_fail -2: - movi a2, 1b - rsr a3, epc1 - assert eq, a2, a3 - movi a2, 32 - rsr a3, exccause - assert eq, a2, a3 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_interrupt.S b/tests/tcg/xtensa/test_interrupt.S deleted file mode 100644 index efedc43f6062..000000000000 --- a/tests/tcg/xtensa/test_interrupt.S +++ /dev/null @@ -1,259 +0,0 @@ -#include "macros.inc" - -#define LSBIT(v) ((v) & -(v)) - -#define LEVEL_MASK(x) glue3(XCHAL_INTLEVEL, x, _MASK) -#define LEVEL_SOFT_MASK(x) (LEVEL_MASK(x) & XCHAL_INTTYPE_MASK_SOFTWARE) - -#define L1_SOFT_MASK LEVEL_SOFT_MASK(1) -#define L1_SOFT LSBIT(L1_SOFT_MASK) - -#if LEVEL_SOFT_MASK(2) -#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(2) -#elif LEVEL_SOFT_MASK(3) -#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(3) -#elif LEVEL_SOFT_MASK(4) -#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(4) -#elif LEVEL_SOFT_MASK(5) -#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(5) -#elif LEVEL_SOFT_MASK(6) -#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(6) -#else -#define HIGH_LEVEL_SOFT_MASK 0 -#endif - -#define HIGH_LEVEL_SOFT LSBIT(HIGH_LEVEL_SOFT_MASK) - -#if LEVEL_SOFT_MASK(2) -#define HIGH_LEVEL_SOFT_LEVEL 2 -#elif LEVEL_SOFT_MASK(3) -#define HIGH_LEVEL_SOFT_LEVEL 3 -#elif LEVEL_SOFT_MASK(4) -#define HIGH_LEVEL_SOFT_LEVEL 4 -#elif LEVEL_SOFT_MASK(5) -#define HIGH_LEVEL_SOFT_LEVEL 5 -#elif LEVEL_SOFT_MASK(6) -#define HIGH_LEVEL_SOFT_LEVEL 6 -#else -#define HIGH_LEVEL_SOFT_LEVEL 0 -#endif - -test_suite interrupt - -#if XCHAL_HAVE_INTERRUPTS - -.macro clear_interrupts - movi a2, 0 - wsr a2, intenable -#if XCHAL_NUM_TIMERS - wsr a2, ccompare0 -#endif -#if XCHAL_NUM_TIMERS > 1 - wsr a2, ccompare1 -#endif -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - esync - rsr a2, interrupt - wsr a2, intclear - - esync - rsr a2, interrupt - assert eqi, a2, 0 -.endm - -.macro check_l1 - rsr a2, ps - movi a3, 0x1f /* EXCM | INTMASK */ - and a2, a2, a3 - assert eqi, a2, 0x10 /* only EXCM is set for level-1 interrupt */ - rsr a2, exccause - assert eqi, a2, 4 -.endm - -test rsil - clear_interrupts - - rsr a2, ps - rsil a3, 7 - rsr a4, ps - assert eq, a2, a3 - movi a2, 0xf - and a2, a4, a2 - assert eqi, a2, 7 - xor a3, a3, a4 - movi a2, 0xfffffff0 - and a2, a3, a2 - assert eqi, a2, 0 -test_end - -#if L1_SOFT -test soft_disabled - set_vector kernel, 1f - clear_interrupts - - movi a2, L1_SOFT - wsr a2, intset - esync - rsr a3, interrupt - movi a4, ~XCHAL_INTTYPE_MASK_TIMER - and a3, a3, a4 - assert eq, a2, a3 - wsr a2, intclear - esync - rsr a3, interrupt - and a3, a3, a4 - assert eqi, a3, 0 - j 2f -1: - test_fail -2: -test_end - -test soft_intenable - set_vector kernel, 1f - clear_interrupts - - movi a2, L1_SOFT - wsr a2, intset - esync - rsr a3, interrupt - movi a4, ~XCHAL_INTTYPE_MASK_TIMER - and a3, a3, a4 - assert eq, a2, a3 - rsil a3, 0 - wsr a2, intenable - esync - test_fail -1: - check_l1 -test_end - -test soft_rsil - set_vector kernel, 1f - clear_interrupts - - movi a2, L1_SOFT - wsr a2, intset - esync - rsr a3, interrupt - movi a4, ~XCHAL_INTTYPE_MASK_TIMER - and a3, a3, a4 - assert eq, a2, a3 - wsr a2, intenable - rsil a3, 0 - esync - test_fail -1: - check_l1 -test_end - -test soft_waiti - set_vector kernel, 1f - clear_interrupts - - movi a2, L1_SOFT - wsr a2, intset - esync - rsr a3, interrupt - movi a4, ~XCHAL_INTTYPE_MASK_TIMER - and a3, a3, a4 - assert eq, a2, a3 - wsr a2, intenable - waiti 0 - test_fail -1: - check_l1 -test_end - -test soft_user - set_vector kernel, 1f - set_vector user, 2f - clear_interrupts - - movi a2, L1_SOFT - wsr a2, intset - esync - rsr a3, interrupt - movi a4, ~XCHAL_INTTYPE_MASK_TIMER - and a3, a3, a4 - assert eq, a2, a3 - wsr a2, intenable - - rsr a2, ps - movi a3, 0x20 - or a2, a2, a3 - wsr a2, ps - waiti 0 -1: - test_fail -2: - check_l1 -test_end - -#if HIGH_LEVEL_SOFT -test soft_priority - set_vector kernel, 1f - set_vector glue(level, HIGH_LEVEL_SOFT_LEVEL), 2f - clear_interrupts - - movi a2, L1_SOFT | HIGH_LEVEL_SOFT - wsr a2, intenable - rsil a3, 0 - esync - wsr a2, intset - esync -1: - test_fail -2: - rsr a2, ps - movi a3, 0x1f /* EXCM | INTMASK */ - and a2, a2, a3 - movi a3, 0x10 | HIGH_LEVEL_SOFT_LEVEL - assert eq, a2, a3 /* EXCM and INTMASK are set - for high-priority interrupt */ -test_end -#endif -#endif - -#if HIGH_LEVEL_SOFT -test eps_epc_rfi - set_vector glue(level, HIGH_LEVEL_SOFT_LEVEL), 3f - clear_interrupts - reset_ps - - movi a2, L1_SOFT_MASK | HIGH_LEVEL_SOFT_MASK - wsr a2, intenable - rsil a3, 0 - rsr a3, ps - esync - wsr a2, intset -1: - esync -2: - test_fail -3: - rsr a2, glue(eps, HIGH_LEVEL_SOFT_LEVEL) - assert eq, a2, a3 - rsr a2, glue(epc, HIGH_LEVEL_SOFT_LEVEL) - movi a3, 1b - assert ge, a2, a3 - movi a3, 2b - assert ge, a3, a2 - movi a2, 4f - wsr a2, glue(epc, HIGH_LEVEL_SOFT_LEVEL) - movi a2, 0x40000 | HIGH_LEVEL_SOFT_LEVEL - wsr a2, glue(eps, HIGH_LEVEL_SOFT_LEVEL) - rfi HIGH_LEVEL_SOFT_LEVEL - test_fail -4: - rsr a2, ps - movi a3, 0x40000 | HIGH_LEVEL_SOFT_LEVEL - assert eq, a2, a3 -test_end -#endif - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_load_store.S b/tests/tcg/xtensa/test_load_store.S deleted file mode 100644 index b339f40f1280..000000000000 --- a/tests/tcg/xtensa/test_load_store.S +++ /dev/null @@ -1,221 +0,0 @@ -#include "macros.inc" - -test_suite load_store - -.macro load_ok_test op, type, data, value - .data - .align 4 -1: - \type \data - .previous - - reset_ps - set_vector kernel, 0 - movi a3, 1b - addi a4, a4, 1 - mov a5, a4 - \op a5, a3, 0 - movi a6, \value - assert eq, a5, a6 -.endm - -#if XCHAL_UNALIGNED_LOAD_EXCEPTION -.macro load_unaligned_test will_trap, op, type, data, value - .data - .align 4 - .byte 0 -1: - \type \data - .previous - - reset_ps - .ifeq \will_trap - set_vector kernel, 0 - .else - set_vector kernel, 2f - .endif - movi a3, 1b - addi a4, a4, 1 - mov a5, a4 -1: - \op a5, a3, 0 - .ifeq \will_trap - movi a6, \value - assert eq, a5, a6 - .else - test_fail -2: - rsr a6, exccause - movi a7, 9 - assert eq, a6, a7 - rsr a6, epc1 - movi a7, 1b - assert eq, a6, a7 - rsr a6, excvaddr - assert eq, a6, a3 - assert eq, a5, a4 - .endif - reset_ps -.endm -#else -.macro load_unaligned_test will_trap, op, type, data, value - .data - .align 4 -1: - \type \data - .previous - - reset_ps - set_vector kernel, 0 - movi a3, 1b + 1 - addi a4, a4, 1 - mov a5, a4 - \op a5, a3, 0 - movi a6, \value - assert eq, a5, a6 -.endm -#endif - -.macro store_ok_test op, type, value - .data - .align 4 - .byte 0, 0, 0, 0x55 -1: - \type 0 -2: - .byte 0xaa - .previous - - reset_ps - set_vector kernel, 0 - movi a3, 1b - movi a5, \value - \op a5, a3, 0 - movi a3, 2b - l8ui a5, a3, 0 - movi a6, 0xaa - assert eq, a5, a6 - movi a3, 1b - 1 - l8ui a5, a3, 0 - movi a6, 0x55 - assert eq, a5, a6 -.endm - -#if XCHAL_UNALIGNED_STORE_EXCEPTION -.macro store_unaligned_test will_trap, op, nop, type, value - .data - .align 4 - .byte 0x55 -1: - \type 0 -2: - .byte 0xaa - .previous - - reset_ps - .ifeq \will_trap - set_vector kernel, 0 - .else - set_vector kernel, 4f - .endif - movi a3, 1b - movi a5, \value -3: - \op a5, a3, 0 - .ifne \will_trap - test_fail -4: - rsr a6, exccause - movi a7, 9 - assert eq, a6, a7 - rsr a6, epc1 - movi a7, 3b - assert eq, a6, a7 - rsr a6, excvaddr - assert eq, a6, a3 - l8ui a5, a3, 0 - assert eqi, a5, 0 - .endif - reset_ps - movi a3, 2b - l8ui a5, a3, 0 - movi a6, 0xaa - assert eq, a5, a6 - movi a3, 1b - 1 - l8ui a5, a3, 0 - movi a6, 0x55 - assert eq, a5, a6 -.endm -#else -.macro store_unaligned_test will_trap, sop, lop, type, value - .data - .align 4 - .byte 0x55 -1: - \type 0 - .previous - - reset_ps - set_vector kernel, 0 - movi a3, 1b - movi a5, \value - \sop a5, a3, 0 - movi a3, 1b - 1 - \lop a6, a3, 0 - assert eq, a5, a6 -.endm -#endif - -test load_ok - load_ok_test l16si, .short, 0x00001234, 0x00001234 - load_ok_test l16si, .short, 0x000089ab, 0xffff89ab - load_ok_test l16ui, .short, 0x00001234, 0x00001234 - load_ok_test l16ui, .short, 0x000089ab, 0x000089ab - load_ok_test l32i, .word, 0x12345678, 0x12345678 -#if XCHAL_HAVE_RELEASE_SYNC - load_ok_test l32ai, .word, 0x12345678, 0x12345678 -#endif -test_end - -#undef WILL_TRAP -#if XCHAL_UNALIGNED_LOAD_HW -#define WILL_TRAP 0 -#else -#define WILL_TRAP 1 -#endif - -test load_unaligned - load_unaligned_test WILL_TRAP, l16si, .short, 0x00001234, 0x00001234 - load_unaligned_test WILL_TRAP, l16si, .short, 0x000089ab, 0xffff89ab - load_unaligned_test WILL_TRAP, l16ui, .short, 0x00001234, 0x00001234 - load_unaligned_test WILL_TRAP, l16ui, .short, 0x000089ab, 0x000089ab - load_unaligned_test WILL_TRAP, l32i, .word, 0x12345678, 0x12345678 -#if XCHAL_HAVE_RELEASE_SYNC - load_unaligned_test 1, l32ai, .word, 0x12345678, 0x12345678 -#endif -test_end - -test store_ok - store_ok_test s16i, .short, 0x00001234 - store_ok_test s32i, .word, 0x12345678 -#if XCHAL_HAVE_RELEASE_SYNC - store_ok_test s32ri, .word, 0x12345678 -#endif -test_end - -#undef WILL_TRAP -#if XCHAL_UNALIGNED_STORE_HW -#define WILL_TRAP 0 -#else -#define WILL_TRAP 1 -#endif - -test store_unaligned - store_unaligned_test WILL_TRAP, s16i, l16ui, .short, 0x00001234 - store_unaligned_test WILL_TRAP, s32i, l32i, .word, 0x12345678 -#if XCHAL_HAVE_RELEASE_SYNC - store_unaligned_test 1, s32ri, l32i, .word, 0x12345678 -#endif -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S deleted file mode 100644 index 0cfd8661ea0e..000000000000 --- a/tests/tcg/xtensa/test_loop.S +++ /dev/null @@ -1,167 +0,0 @@ -#include "macros.inc" - -test_suite loop - -#if XCHAL_HAVE_LOOPS - -test loop - movi a2, 0 - movi a3, 5 - loop a3, 1f - addi a2, a2, 1 -1: - assert eqi, a2, 5 -test_end - -test loop0 - movi a2, 0 - loop a2, 1f - rsr a2, lcount - assert eqi, a2, -1 - j 1f -1: -test_end - -test loop_jump - movi a2, 0 - movi a3, 5 - loop a3, 1f - addi a2, a2, 1 - j 1f -1: - assert eqi, a2, 1 -test_end - -test loop_branch - movi a2, 0 - movi a3, 5 - loop a3, 1f - addi a2, a2, 1 - beqi a2, 3, 1f -1: - assert eqi, a2, 3 -test_end - -test loop_manual - movi a2, 0 - movi a3, 5 - movi a4, 1f - movi a5, 2f - wsr a3, lcount - wsr a4, lbeg - wsr a5, lend - isync - j 1f -.align 4 -1: - addi a2, a2, 1 -2: - assert eqi, a2, 6 -test_end - -test loop_excm - movi a2, 0 - movi a3, 5 - rsr a4, ps - movi a5, 0x10 - or a4, a4, a5 - wsr a4, ps - isync - loop a3, 1f - addi a2, a2, 1 -1: - xor a4, a4, a5 - isync - wsr a4, ps - assert eqi, a2, 1 -test_end - -test lbeg_invalidation - movi a2, 0 - movi a3, 1 - movi a4, 1f - movi a5, 3f - wsr a3, lcount - wsr a4, lbeg - wsr a5, lend - isync - j 1f -.align 4 -1: - addi a2, a2, 1 - j 2f -.align 4 -2: - addi a2, a2, 2 - movi a3, 2b - wsr a3, lbeg - isync - nop -3: - assert eqi, a2, 5 -test_end - -test lend_invalidation - movi a2, 0 - movi a3, 5 - movi a4, 1f - movi a5, 2f - wsr a3, lcount - wsr a4, lbeg - wsr a5, lend - isync - j 1f -.align 4 -1: - addi a2, a2, 1 -2: - beqi a3, 3, 1f - assert eqi, a2, 6 - movi a3, 3 - wsr a3, lcount - wsr a4, lend - isync - j 1b -1: - assert eqi, a2, 7 -test_end - -test loopnez - movi a2, 0 - movi a3, 5 - loopnez a3, 1f - addi a2, a2, 1 -1: - assert eqi, a2, 5 - - movi a2, 0 - movi a3, 0 - loopnez a3, 1f - test_fail -1: -test_end - -test loopgtz - movi a2, 0 - movi a3, 5 - loopgtz a3, 1f - addi a2, a2, 1 -1: - assert eqi, a2, 5 - - movi a2, 0 - movi a3, 0 - loopgtz a3, 1f - test_fail -1: - - movi a2, 0 - movi a3, 0x80000000 - loopgtz a3, 1f - test_fail -1: -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_lsc.S b/tests/tcg/xtensa/test_lsc.S deleted file mode 100644 index 348822bdd359..000000000000 --- a/tests/tcg/xtensa/test_lsc.S +++ /dev/null @@ -1,266 +0,0 @@ -#include "macros.inc" -#include "fpu.h" - -test_suite lsc - -#if XCHAL_HAVE_FP - -test lsi - movi a2, 1 - wsr a2, cpenable - - movi a2, 1f - lsi f1, a2, 4 -#if DFPU - lsi f2, a2, 8 - lsip f0, a2, 8 -#else - lsi f0, a2, 0 - lsiu f2, a2, 8 -#endif - movi a3, 1f + 8 - assert eq, a2, a3 - rfr a2, f0 - movi a3, 0x3f800000 - assert eq, a2, a3 - rfr a2, f1 - movi a3, 0x40000000 - assert eq, a2, a3 - rfr a2, f2 - movi a3, 0x40400000 - assert eq, a2, a3 -.data - .align 4 -1: -.float 1, 2, 3 -.text -test_end - -test ssi - movi a2, 1f - movi a3, 0x40800000 - wfr f3, a3 - movi a3, 0x40a00000 - wfr f4, a3 - movi a3, 0x40c00000 - wfr f5, a3 - ssi f4, a2, 4 -#if DFPU - ssi f5, a2, 8 - ssip f3, a2, 8 -#else - ssi f3, a2, 0 - ssiu f5, a2, 8 -#endif - movi a3, 1f + 8 - assert eq, a2, a3 - l32i a4, a2, -8 - movi a3, 0x40800000 - assert eq, a4, a3 - l32i a4, a2, -4 - movi a3, 0x40a00000 - assert eq, a4, a3 - l32i a4, a2, 0 - movi a3, 0x40c00000 - assert eq, a4, a3 -.data - .align 4 -1: -.float 0, 0, 0 -.text -test_end - -test lsx - movi a2, 1f - movi a3, 0 - movi a4, 4 - movi a5, 8 - lsx f7, a2, a4 -#if DFPU - lsx f8, a2, a5 - lsxp f6, a2, a5 -#else - lsx f6, a2, a3 - lsxu f8, a2, a5 -#endif - movi a3, 1f + 8 - assert eq, a2, a3 - rfr a2, f6 - movi a3, 0x40e00000 - assert eq, a2, a3 - rfr a2, f7 - movi a3, 0x41000000 - assert eq, a2, a3 - rfr a2, f8 - movi a3, 0x41100000 - assert eq, a2, a3 -.data - .align 4 -1: -.float 7, 8, 9 -.text -test_end - -test ssx - movi a2, 1f - movi a4, 0x41200000 - wfr f9, a4 - movi a4, 0x41300000 - wfr f10, a4 - movi a4, 0x41400000 - wfr f11, a4 - movi a3, 0 - movi a4, 4 - movi a5, 8 - ssx f10, a2, a4 -#if DFPU - ssx f11, a2, a5 - ssxp f9, a2, a5 -#else - ssx f9, a2, a3 - ssxu f11, a2, a5 -#endif - movi a3, 1f + 8 - assert eq, a2, a3 - l32i a4, a2, -8 - movi a3, 0x41200000 - assert eq, a4, a3 - l32i a4, a2, -4 - movi a3, 0x41300000 - assert eq, a4, a3 - l32i a4, a2, 0 - movi a3, 0x41400000 - assert eq, a4, a3 -.data - .align 4 -1: -.float 0, 0, 0 -.text -test_end - -#endif - -#if XCHAL_HAVE_DFP - -#if XCHAL_HAVE_BE -#define F64_HIGH_OFF 0 -#else -#define F64_HIGH_OFF 4 -#endif - -.macro movdf fr, hi, lo - movi a2, \hi - movi a3, \lo - wfrd \fr, a2, a3 -.endm - -test ldi - movi a2, 1 - wsr a2, cpenable - - movi a2, 1f - ldi f1, a2, 8 - ldi f2, a2, 16 - ldip f0, a2, 16 - movi a3, 1f + 16 - assert eq, a2, a3 - rfrd a2, f0 - movi a3, 0x3ff00000 - assert eq, a2, a3 - rfrd a2, f1 - movi a3, 0x40000000 - assert eq, a2, a3 - rfrd a2, f2 - movi a3, 0x40080000 - assert eq, a2, a3 -.data - .align 8 -1: -.double 1, 2, 3 -.text -test_end - -test sdi - movdf f3, 0x40800000, 0 - movdf f4, 0x40a00000, 0 - movdf f5, 0x40c00000, 0 - movi a2, 1f - sdi f4, a2, 8 - sdi f5, a2, 16 - sdip f3, a2, 16 - movi a3, 1f + 16 - assert eq, a2, a3 - l32i a4, a2, -16 + F64_HIGH_OFF - movi a3, 0x40800000 - assert eq, a4, a3 - l32i a4, a2, -8 + F64_HIGH_OFF - movi a3, 0x40a00000 - assert eq, a4, a3 - l32i a4, a2, F64_HIGH_OFF - movi a3, 0x40c00000 - assert eq, a4, a3 -.data - .align 8 -1: -.double 0, 0, 0 -.text -test_end - -test ldx - movi a2, 1f - movi a3, 0 - movi a4, 8 - movi a5, 16 - ldx f7, a2, a4 - ldx f8, a2, a5 - ldxp f6, a2, a5 - movi a3, 1f + 16 - assert eq, a2, a3 - rfrd a2, f6 - movi a3, 0x401c0000 - assert eq, a2, a3 - rfrd a2, f7 - movi a3, 0x40200000 - assert eq, a2, a3 - rfrd a2, f8 - movi a3, 0x40220000 - assert eq, a2, a3 -.data - .align 8 -1: -.double 7, 8, 9 -.text -test_end - -test sdx - movdf f9, 0x41200000, 0 - movdf f10, 0x41300000, 0 - movdf f11, 0x41400000, 0 - movi a2, 1f - movi a3, 0 - movi a4, 8 - movi a5, 16 - sdx f10, a2, a4 - sdx f11, a2, a5 - sdxp f9, a2, a5 - movi a3, 1f + 16 - assert eq, a2, a3 - l32i a4, a2, -16 + F64_HIGH_OFF - movi a3, 0x41200000 - assert eq, a4, a3 - l32i a4, a2, -8 + F64_HIGH_OFF - movi a3, 0x41300000 - assert eq, a4, a3 - l32i a4, a2, F64_HIGH_OFF - movi a3, 0x41400000 - assert eq, a4, a3 -.data - .align 8 -1: -.double 0, 0, 0 -.text -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_mac16.S b/tests/tcg/xtensa/test_mac16.S deleted file mode 100644 index ee0cedd2ae5d..000000000000 --- a/tests/tcg/xtensa/test_mac16.S +++ /dev/null @@ -1,247 +0,0 @@ -#include "macros.inc" - -test_suite mac16 - -#if XCHAL_HAVE_MAC16 - -#define ext16(v) (((v) & 0xffff) | (((v) & 0x8000) * 0x1ffffffe)) -#define mul16(a, b) ((ext16(a) * ext16(b))) - -.macro assert_acc_value v - rsr a4, ACCLO - movi a5, (\v) & 0xffffffff - assert eq, a4, a5 - rsr a4, ACCHI - movi a5, (\v) >> 32 - sext a5, a5, 7 - assert eq, a4, a5 -.endm - -.macro init_reg sr, reg, val - .if (\sr) - movi a4, \val - wsr a4, \reg - .else - movi \reg, \val - .endif -.endm - -.macro test_mulxx mulop, comb, s, t, a, b - init_reg \comb & 2, \s, \a - init_reg \comb & 1, \t, \b - - \mulop\().ll \s, \t - assert_acc_value mul16(\a, \b) - - \mulop\().lh \s, \t - assert_acc_value mul16(\a, (\b >> 16)) - - \mulop\().hl \s, \t - assert_acc_value mul16((\a >> 16), \b) - - \mulop\().hh \s, \t - assert_acc_value mul16((\a >> 16), (\b >> 16)) -.endm - -test mul_aa - test_mulxx mul.aa, 0, a2, a3, 0xf7315a5a, 0xa5a5137f -test_end - -test mul_ad - test_mulxx mul.ad, 1, a2, m2, 0xf7315a5a, 0xa5a5137f -test_end - -test mul_da - test_mulxx mul.da, 2, m1, a3, 0xf7315a5a, 0xa5a5137f -test_end - -test mul_dd - test_mulxx mul.dd, 3, m0, m3, 0xf7315a5a, 0xa5a5137f -test_end - - -.macro init_acc iv - movi a4, (\iv) & 0xffffffff - wsr a4, ACCLO - movi a4, (\iv) >> 32 - wsr a4, ACCHI -.endm - -.macro test_mulxxx mulop, comb, s, t, a, b, iv, op - init_reg \comb & 2, \s, \a - init_reg \comb & 1, \t, \b - - init_acc \iv - \mulop\().ll \s, \t - assert_acc_value (\iv \op mul16(\a, \b)) - - init_acc \iv - \mulop\().lh \s, \t - assert_acc_value (\iv \op mul16(\a, (\b >> 16))) - - init_acc \iv - \mulop\().hl \s, \t - assert_acc_value (\iv \op mul16((\a >> 16), \b)) - - init_acc \iv - \mulop\().hh \s, \t - assert_acc_value (\iv \op mul16((\a >> 16), (\b >> 16))) -.endm - - -test mula_aa - test_mulxxx mula.aa, 0, a2, a3, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, + -test_end - -test mula_ad - test_mulxxx mula.ad, 1, a2, m2, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, + -test_end - -test mula_da - test_mulxxx mula.da, 2, m1, a3, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, + -test_end - -test mula_dd - test_mulxxx mula.dd, 3, m0, m3, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, + -test_end - - -test muls_aa - test_mulxxx muls.aa, 0, a2, a3, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, - -test_end - -test muls_ad - test_mulxxx muls.ad, 1, a2, m2, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, - -test_end - -test muls_da - test_mulxxx muls.da, 2, m1, a3, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, - -test_end - -test muls_dd - test_mulxxx muls.dd, 3, m0, m3, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, - -test_end - -test ldinc - movi a2, 1f - 4 - ldinc m0, a2 - movi a3, 1f - assert eq, a2, a3 - rsr a3, m0 - movi a4, 0x55aa137f - assert eq, a3, a4 - ldinc m1, a2 - movi a3, 1f + 4 - assert eq, a2, a3 - rsr a3, m1 - movi a4, 0x12345678 - assert eq, a3, a4 - -.data -1: .word 0x55aa137f, 0x12345678, 0x137fa5a5 -.text -test_end - -test lddec - movi a2, 1f - lddec m2, a2 - movi a3, 1f - 4 - assert eq, a2, a3 - rsr a3, m2 - movi a4, 0x12345678 - assert eq, a3, a4 - lddec m3, a2 - movi a3, 1f - 8 - assert eq, a2, a3 - rsr a3, m3 - movi a4, 0x55aa137f - assert eq, a3, a4 -.data - .word 0x55aa137f, 0x12345678 -1: -.text -test_end - - -.macro test_mulxxx_ld mulop, ldop, comb, w, x, s, t, a, b, iv, op - init_reg \comb & 2, \s, \a - init_reg \comb & 1, \t, \b - - init_acc \iv - \mulop\().ll.\ldop \w, \x, \s, \t - assert_acc_value (\iv \op mul16(\a, \b)) - - init_acc \iv - \mulop\().lh.\ldop \w, \x, \s, \t - assert_acc_value (\iv \op mul16(\a, (\b >> 16))) - - init_acc \iv - \mulop\().hl.\ldop \w, \x, \s, \t - assert_acc_value (\iv \op mul16((\a >> 16), \b)) - - init_acc \iv - \mulop\().hh.\ldop \w, \x, \s, \t - assert_acc_value (\iv \op mul16((\a >> 16), (\b >> 16))) -.endm - -test mula_da_ldinc - movi a2, 1f - 4 - test_mulxxx_ld mula.da, ldinc, 2, m1, a2, m1, a3, \ - 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, + - movi a3, 1f + 12 - assert eq, a2, a3 - rsr a2, m1 - movi a3, 0x12345678 - assert eq, a2, a3 -.data -1: .word 0xf7315a5a, 0xf7315a5a, 0xf7315a5a, 0x12345678 -.text -test_end - -test mula_dd_ldinc - movi a2, 1f - 4 - test_mulxxx_ld mula.dd, ldinc, 3, m2, a2, m1, m2, \ - 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, + - movi a3, 1f + 12 - assert eq, a2, a3 - rsr a2, m2 - movi a3, 0x12345678 - assert eq, a2, a3 -.data -1: .word 0xa5a5137f, 0xa5a5137f, 0xa5a5137f, 0x12345678 -.text -test_end - -test mula_da_lddec - movi a2, 1f - test_mulxxx_ld mula.da, lddec, 2, m1, a2, m1, a3, \ - 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, + - movi a3, 1f - 16 - assert eq, a2, a3 - rsr a2, m1 - movi a3, 0x12345678 - assert eq, a2, a3 -.data - .word 0x12345678, 0xf7315a5a, 0xf7315a5a, 0xf7315a5a -1: -.text -test_end - -test mula_dd_lddec - movi a2, 1f - test_mulxxx_ld mula.dd, lddec, 3, m2, a2, m1, m2, \ - 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, + - movi a3, 1f - 16 - assert eq, a2, a3 - rsr a2, m2 - movi a3, 0x12345678 - assert eq, a2, a3 -.data - .word 0x12345678, 0xa5a5137f, 0xa5a5137f, 0xa5a5137f -1: -.text -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_max.S b/tests/tcg/xtensa/test_max.S deleted file mode 100644 index f349d578e3bb..000000000000 --- a/tests/tcg/xtensa/test_max.S +++ /dev/null @@ -1,85 +0,0 @@ -#include "macros.inc" - -test_suite max - -#if XCHAL_HAVE_MINMAX - -test max - movi a2, 0xffffffff - movi a3, 1 - movi a4, 1 - max a5, a2, a3 - assert eq, a5, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 1 - max a5, a2, a3 - assert eq, a5, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 1 - max a2, a2, a3 - assert eq, a2, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 1 - max a3, a2, a3 - assert eq, a3, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 1 - max a2, a2, a3 - assert eq, a2, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 1 - max a3, a2, a3 - assert eq, a3, a4 -test_end - -test maxu - movi a2, 0xffffffff - movi a3, 1 - movi a4, 0xffffffff - maxu a5, a2, a3 - assert eq, a5, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 0xffffffff - maxu a5, a2, a3 - assert eq, a5, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 0xffffffff - maxu a2, a2, a3 - assert eq, a2, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 0xffffffff - maxu a3, a2, a3 - assert eq, a3, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 0xffffffff - maxu a2, a2, a3 - assert eq, a2, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 0xffffffff - maxu a3, a2, a3 - assert eq, a3, a4 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_min.S b/tests/tcg/xtensa/test_min.S deleted file mode 100644 index 89ee10334f62..000000000000 --- a/tests/tcg/xtensa/test_min.S +++ /dev/null @@ -1,85 +0,0 @@ -#include "macros.inc" - -test_suite min - -#if XCHAL_HAVE_MINMAX - -test min - movi a2, 0xffffffff - movi a3, 1 - movi a4, 0xffffffff - min a5, a2, a3 - assert eq, a5, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 0xffffffff - min a5, a2, a3 - assert eq, a5, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 0xffffffff - min a2, a2, a3 - assert eq, a2, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 0xffffffff - min a3, a2, a3 - assert eq, a3, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 0xffffffff - min a2, a2, a3 - assert eq, a2, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 0xffffffff - min a3, a2, a3 - assert eq, a3, a4 -test_end - -test minu - movi a2, 0xffffffff - movi a3, 1 - movi a4, 1 - minu a5, a2, a3 - assert eq, a5, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 1 - minu a5, a2, a3 - assert eq, a5, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 1 - minu a2, a2, a3 - assert eq, a2, a4 - - movi a2, 0xffffffff - movi a3, 1 - movi a4, 1 - minu a3, a2, a3 - assert eq, a3, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 1 - minu a2, a2, a3 - assert eq, a2, a4 - - movi a2, 1 - movi a3, 0xffffffff - movi a4, 1 - minu a3, a2, a3 - assert eq, a3, a4 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S deleted file mode 100644 index 4cbd6ef4f9d8..000000000000 --- a/tests/tcg/xtensa/test_mmu.S +++ /dev/null @@ -1,747 +0,0 @@ -#include "macros.inc" - -test_suite mmu - -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY - -.purgem test_init - -.macro clean_tlb_way way, page_size, n_entries - movi a2, \way - movi a3, \page_size - movi a4, \n_entries - loop a4, 1f - idtlb a2 - iitlb a2 - add a2, a2, a3 -1: -.endm - -.macro test_init - clean_tlb_way 0, 0x00001000, 4 - clean_tlb_way 1, 0x00001000, 4 - clean_tlb_way 2, 0x00001000, 4 - clean_tlb_way 3, 0x00001000, 4 - clean_tlb_way 4, 0x00100000, 4 - movi a2, 0x00000007 - idtlb a2 - movi a2, 0x00000008 - idtlb a2 - movi a2, 0x00000009 - idtlb a2 -.endm - -test tlb_group - movi a2, 0x04000002 /* PPN */ - movi a3, 0x01200004 /* VPN */ - wdtlb a2, a3 - witlb a2, a3 - movi a3, 0x00200004 - rdtlb0 a1, a3 - ritlb0 a2, a3 - movi a3, 0x01000001 - assert eq, a1, a3 - assert eq, a2, a3 - movi a3, 0x00200004 - rdtlb1 a1, a3 - ritlb1 a2, a3 - movi a3, 0x04000002 - assert eq, a1, a3 - assert eq, a2, a3 - movi a3, 0x01234567 - pdtlb a1, a3 - pitlb a2, a3 - movi a3, 0x01234014 - assert eq, a1, a3 - movi a3, 0x0123400c - assert eq, a2, a3 - movi a3, 0x00200004 - idtlb a3 - iitlb a3 - movi a3, 0x01234567 - pdtlb a1, a3 - pitlb a2, a3 - movi a3, 0x00000010 - and a1, a1, a3 - assert eqi, a1, 0 - movi a3, 0x00000008 - and a2, a2, a3 - assert eqi, a2, 0 -test_end - -test itlb_miss - set_vector kernel, 1f - - movi a3, 0x00100000 - jx a3 - test_fail -1: - rsr a2, excvaddr - assert eq, a2, a3 - rsr a2, exccause - movi a3, 16 - assert eq, a2, a3 -test_end - -test dtlb_miss - set_vector kernel, 1f - - movi a3, 0x00100000 - l8ui a2, a3, 0 - test_fail -1: - rsr a2, excvaddr - assert eq, a2, a3 - rsr a2, exccause - movi a3, 24 - assert eq, a2, a3 -test_end - -test itlb_multi_hit - set_vector kernel, 1f - - movi a2, 0x04000002 /* PPN */ - movi a3, 0xf0000004 /* VPN */ - witlb a2, a3 - movi a3, 0xf0000000 - pitlb a2, a3 - test_fail -1: - rsr a2, exccause - movi a3, 17 - assert eq, a2, a3 -test_end - -test dtlb_multi_hit - set_vector kernel, 1f - - movi a2, 0x04000002 /* PPN */ - movi a3, 0x01200004 /* VPN */ - wdtlb a2, a3 - movi a3, 0x01200007 /* VPN */ - wdtlb a2, a3 - movi a3, 0x01200000 - pdtlb a2, a3 - test_fail -1: - rsr a2, exccause - movi a3, 25 - assert eq, a2, a3 -test_end - -test inst_fetch_privilege - set_vector kernel, 3f - - movi a2, 0x4004f - wsr a2, ps -1: - isync - nop -2: - test_fail -3: - movi a1, 1b - rsr a2, excvaddr - rsr a3, epc1 - assert ge, a2, a1 - assert ge, a3, a1 - movi a1, 2b - assert lt, a2, a1 - assert lt, a3, a1 - rsr a2, exccause - movi a3, 18 - assert eq, a2, a3 - rsr a2, ps - movi a3, 0x4005f - assert eq, a2, a3 -test_end - -test load_store_privilege - set_vector kernel, 2f - - movi a3, 10f - pitlb a3, a3 - ritlb1 a2, a3 - movi a1, 0x10 - or a2, a2, a1 - movi a1, 0x000ff000 - and a3, a3, a1 - movi a1, 4 - or a3, a3, a1 - witlb a2, a3 - movi a3, 10f - movi a1, 0x000fffff - and a1, a3, a1 - - movi a2, 0x04000003 /* PPN */ - movi a3, 0x01200004 /* VPN */ - wdtlb a2, a3 - movi a3, 0x01200001 - movi a2, 0x4004f - jx a1 -10: - wsr a2, ps - isync -1: - l8ui a2, a3, 0 - test_fail -2: - rsr a2, excvaddr - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 1b - movi a1, 0x000fffff - and a3, a3, a1 - assert eq, a2, a3 - rsr a2, exccause - movi a3, 26 - assert eq, a2, a3 - rsr a2, ps - movi a3, 0x4005f - assert eq, a2, a3 -test_end - -test cring_load_store_privilege - set_vector kernel, 0 - set_vector double, 2f - - movi a2, 0x04000003 /* PPN */ - movi a3, 0x01200004 /* VPN */ - wdtlb a2, a3 - movi a3, 0x01200004 - movi a2, 0x4005f /* ring 1 + excm => cring == 0 */ - wsr a2, ps - isync - l8ui a2, a3, 0 /* cring used */ -1: - l32e a2, a3, -4 /* ring used */ - test_fail -2: - rsr a2, excvaddr - addi a2, a2, 4 - assert eq, a2, a3 - rsr a2, depc - movi a3, 1b - assert eq, a2, a3 - rsr a2, exccause - movi a3, 26 - assert eq, a2, a3 - rsr a2, ps - movi a3, 0x4005f - assert eq, a2, a3 -test_end - -test inst_fetch_prohibited - set_vector kernel, 2f - - movi a3, 10f - pitlb a3, a3 - ritlb1 a2, a3 - movi a1, 0xfffff000 - and a2, a2, a1 - movi a1, 0x4 - or a2, a2, a1 - movi a1, 0x000ff000 - and a3, a3, a1 - movi a1, 4 - or a3, a3, a1 - witlb a2, a3 - movi a3, 10f - movi a1, 0x000fffff - and a1, a3, a1 - jx a1 - .align 4 -10: - nop - test_fail -2: - rsr a2, excvaddr - assert eq, a2, a1 - rsr a2, epc1 - assert eq, a2, a1 - rsr a2, exccause - movi a3, 20 - assert eq, a2, a3 -test_end - -test load_prohibited - set_vector kernel, 2f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x01200004 /* VPN */ - wdtlb a2, a3 - movi a3, 0x01200002 -1: - l8ui a2, a3, 0 - test_fail -2: - rsr a2, excvaddr - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - rsr a2, exccause - movi a3, 28 - assert eq, a2, a3 -test_end - -test store_prohibited - set_vector kernel, 2f - - movi a2, 0x04000001 /* PPN */ - movi a3, 0x01200004 /* VPN */ - wdtlb a2, a3 - movi a3, 0x01200003 - l8ui a2, a3, 0 -1: - s8i a2, a3, 0 - test_fail -2: - rsr a2, excvaddr - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - rsr a2, exccause - movi a3, 29 - assert eq, a2, a3 -test_end - -/* Set up page table entry vaddr->paddr, ring=pte_ring, attr=pte_attr - * and DTLB way 7 to cover this PTE, ring=pt_ring, attr=pt_attr - */ -.macro pt_setup pt_ring, pt_attr, pte_ring, vaddr, paddr, pte_attr - movi a2, 0x80000000 - wsr a2, ptevaddr - - movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ - movi a4, 0x04000003 | ((\pt_ring) << 4) /* PADDR 64M */ - wdtlb a4, a3 - isync - - movi a3, ((\paddr) & 0xfffff000) | ((\pte_ring) << 4) | (\pte_attr) - movi a1, ((\vaddr) >> 12) << 2 - add a2, a1, a2 - s32i a3, a2, 0 - - movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ - movi a4, 0x04000000 | ((\pt_ring) << 4) | (\pt_attr) /* PADDR 64M */ - wdtlb a4, a3 - isync - - movi a3, (\vaddr) -.endm - -/* out: PS.RING=ring, PS.EXCM=excm, a3=vaddr */ -.macro go_ring ring, excm, vaddr - movi a3, 10f - pitlb a3, a3 - ritlb1 a2, a3 - movi a1, 0x10 - or a2, a2, a1 - movi a1, 0x000ff000 - and a3, a3, a1 - movi a1, 4 - or a3, a3, a1 - witlb a2, a3 - movi a3, 10f - movi a1, 0x000fffff - and a1, a3, a1 - - movi a2, 0 - wsr a2, excvaddr - - movi a3, \vaddr - movi a2, 0x4000f | ((\ring) << 6) | ((\excm) << 4) - jx a1 -10: - wsr a2, ps - isync -.endm - -/* in: a3 -- virtual address to test */ -.macro assert_auto_tlb - movi a2, 0x4000f - wsr a2, ps - isync - pdtlb a2, a3 - movi a1, 0xfffff01f - and a2, a2, a1 - movi a1, 0xfffff000 - and a1, a1, a3 - xor a1, a1, a2 - assert gei, a1, 0x10 - movi a2, 0x14 - assert lt, a1, a2 -.endm - -/* in: a3 -- virtual address to test */ -.macro assert_no_auto_tlb - movi a2, 0x4000f - wsr a2, ps - isync - pdtlb a2, a3 - movi a1, 0x10 - and a1, a1, a2 - assert eqi, a1, 0 -.endm - -.macro assert_sr sr, v - rsr a2, \sr - movi a1, (\v) - assert eq, a1, a2 -.endm - -.macro assert_epc1_1m vaddr - movi a2, (\vaddr) - movi a1, 0xfffff - and a1, a1, a2 - rsr a2, epc1 - assert eq, a1, a2 -.endm - -test dtlb_autoload - set_vector kernel, 0 - - pt_setup 0, 3, 1, 0x1000, 0x1000, 3 - assert_no_auto_tlb - - l8ui a1, a3, 0 - - rsr a2, excvaddr - assert eq, a2, a3 - - assert_auto_tlb -test_end - -test autoload_load_store_privilege - set_vector kernel, 0 - set_vector double, 2f - - pt_setup 0, 3, 0, 0x2000, 0x2000, 3 - movi a3, 0x2004 - assert_no_auto_tlb - - movi a2, 0x4005f /* ring 1 + excm => cring == 0 */ - wsr a2, ps - isync -1: - l32e a2, a3, -4 /* ring used */ - test_fail -2: - rsr a2, excvaddr - addi a1, a3, -4 - assert eq, a1, a2 - - assert_auto_tlb - assert_sr depc, 1b - assert_sr exccause, 26 -test_end - -test autoload_pte_load_prohibited - set_vector kernel, 2f - - pt_setup 0, 3, 0, 0x3000, 0, 0xc - assert_no_auto_tlb -1: - l32i a2, a3, 0 - test_fail -2: - rsr a2, excvaddr - assert eq, a2, a3 - - assert_auto_tlb - assert_sr epc1, 1b - assert_sr exccause, 28 -test_end - -test autoload_pt_load_prohibited - set_vector kernel, 2f - - pt_setup 0, 0xc, 0, 0x4000, 0x4000, 3 - assert_no_auto_tlb -1: - l32i a2, a3, 0 - test_fail -2: - rsr a2, excvaddr - assert eq, a2, a3 - - assert_no_auto_tlb - assert_sr epc1, 1b - assert_sr exccause, 24 -test_end - -test autoload_pt_privilege - set_vector kernel, 2f - pt_setup 0, 3, 1, 0x5000, 0, 3 - go_ring 1, 0, 0x5001 - - l8ui a2, a3, 0 -1: - syscall -2: - rsr a2, excvaddr - assert eq, a2, a3 - - assert_auto_tlb - assert_epc1_1m 1b - assert_sr exccause, 1 -test_end - -test autoload_pte_privilege - set_vector kernel, 2f - pt_setup 0, 3, 0, 0x6000, 0, 3 - go_ring 1, 0, 0x6001 -1: - l8ui a2, a3, 0 - syscall -2: - rsr a2, excvaddr - assert eq, a2, a3 - - assert_auto_tlb - assert_epc1_1m 1b - assert_sr exccause, 26 -test_end - -test autoload_3_level_pt - set_vector kernel, 2f - pt_setup 1, 3, 1, 0x00400000, 0, 3 - pt_setup 1, 3, 1, 0x80001000, 0x2000000, 3 - go_ring 1, 0, 0x00400001 -1: - l8ui a2, a3, 0 - syscall -2: - rsr a2, excvaddr - assert eq, a2, a3 - - assert_no_auto_tlb - assert_epc1_1m 1b - assert_sr exccause, 24 -test_end - -test cross_page_insn - set_vector kernel, 2f - - movi a2, 0x04000003 /* PPN */ - movi a3, 0x00007000 /* VPN */ - witlb a2, a3 - wdtlb a2, a3 - movi a3, 0x00008000 /* VPN */ - witlb a2, a3 - wdtlb a2, a3 - - movi a2, 0x00007fff - movi a3, 20f - movi a4, 21f - sub a4, a4, a3 - loop a4, 1f - l8ui a5, a3, 0 - s8i a5, a2, 0 - addi a2, a2, 1 - addi a3, a3, 1 -1: - movi a2, 0x00007fff - movi a3, 0x00008000 - /* DTLB: OK, ITLB: OK */ - jx a2 - - .begin no-transform -20: - l32i a2, a3, 0 - syscall -21: - .end no-transform - -2: - rsr a2, exccause - movi a3, 1 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x8002 - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007fff - assert ne, a2, a3 - - reset_ps - set_vector kernel, 3f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ - wdtlb a2, a3 - movi a2, 0x00007fff - movi a3, 0x00008000 - /* DTLB: FAIL, ITLB: OK */ - jx a2 -3: - rsr a2, exccause - movi a3, 28 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7fff - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007fff - assert eq, a2, a3 - - reset_ps - set_vector kernel, 4f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ - witlb a2, a3 - movi a2, 0x04000003 /* PPN */ - wdtlb a2, a3 - movi a2, 0x00007fff - movi a3, 0x00008000 - /* DTLB: OK, ITLB: FAIL */ - jx a2 -4: - rsr a2, exccause - movi a3, 20 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7fff - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007fff - assert eq, a2, a3 - - reset_ps - set_vector kernel, 5f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ - wdtlb a2, a3 - movi a2, 0x00007fff - movi a3, 0x00008000 - /* DTLB: FAIL, ITLB: FAIL */ - jx a2 -5: - rsr a2, exccause - movi a3, 20 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7fff - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007fff - assert eq, a2, a3 -test_end - -test cross_page_tb - set_vector kernel, 2f - - movi a2, 0x04000003 /* PPN */ - movi a3, 0x00007000 /* VPN */ - witlb a2, a3 - wdtlb a2, a3 - movi a3, 0x00008000 /* VPN */ - witlb a2, a3 - wdtlb a2, a3 - - movi a2, 0x00007ffc - movi a3, 20f - movi a4, 21f - sub a4, a4, a3 - loop a4, 1f - l8ui a5, a3, 0 - s8i a5, a2, 0 - addi a2, a2, 1 - addi a3, a3, 1 -1: - movi a2, 0x00007ffc - movi a3, 0x00008000 - /* DTLB: OK, ITLB: OK */ - jx a2 - - .begin no-transform -20: - l32i a2, a3, 0 - syscall -21: - .end no-transform - -2: - rsr a2, exccause - movi a3, 1 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7fff - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007ffc - assert ne, a2, a3 - - reset_ps - set_vector kernel, 3f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ - wdtlb a2, a3 - movi a2, 0x00007ffc - movi a3, 0x00008000 - /* DTLB: FAIL, ITLB: OK */ - jx a2 -3: - rsr a2, exccause - movi a3, 28 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7ffc - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007ffc - assert eq, a2, a3 - - reset_ps - set_vector kernel, 4f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ - witlb a2, a3 - movi a2, 0x04000003 /* PPN */ - wdtlb a2, a3 - movi a2, 0x00007ffc - movi a3, 0x00008000 - /* DTLB: OK, ITLB: FAIL */ - jx a2 -4: - rsr a2, exccause - movi a3, 20 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7fff - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007ffc - assert ne, a2, a3 - - reset_ps - set_vector kernel, 5f - - movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ - wdtlb a2, a3 - movi a2, 0x00007ffc - movi a3, 0x00008000 - /* DTLB: FAIL, ITLB: FAIL */ - jx a2 -5: - rsr a2, exccause - movi a3, 28 - assert eq, a2, a3 - rsr a2, epc1 - movi a3, 0x7ffc - assert eq, a2, a3 - rsr a2, excsave1 - movi a3, 0x00007ffc - assert eq, a2, a3 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_mul16.S b/tests/tcg/xtensa/test_mul16.S deleted file mode 100644 index 32507f7f1ef1..000000000000 --- a/tests/tcg/xtensa/test_mul16.S +++ /dev/null @@ -1,87 +0,0 @@ -#include "macros.inc" - -test_suite mul16 - -#if XCHAL_HAVE_MUL16 - -test mul16u_pp - movi a2, 0x137f5a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x06e180a6 - mul16u a5, a2, a4 - assert eq, a5, a6 - mul16u a2, a2, a4 - assert eq, a2, a6 - mul16u a3, a4, a3 - assert eq, a3, a6 -test_end - -test mul16u_np - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x0c9d6bdb - mul16u a5, a2, a4 - assert eq, a5, a6 - mul16u a2, a2, a4 - assert eq, a2, a6 - mul16u a3, a4, a3 - assert eq, a3, a6 -test_end - -test mul16u_nn - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5f731 - movi a6, 0x9ff1e795 - mul16u a5, a2, a4 - assert eq, a5, a6 - mul16u a2, a2, a4 - assert eq, a2, a6 - mul16u a3, a4, a3 - assert eq, a3, a6 -test_end - -test mul16s_pp - movi a2, 0x137f5a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x06e180a6 - mul16s a5, a2, a4 - assert eq, a5, a6 - mul16s a2, a2, a4 - assert eq, a2, a6 - mul16s a3, a4, a3 - assert eq, a3, a6 -test_end - -test mul16s_np - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xf91e6bdb - mul16s a5, a2, a4 - assert eq, a5, a6 - mul16s a2, a2, a4 - assert eq, a2, a6 - mul16s a3, a4, a3 - assert eq, a3, a6 -test_end - -test mul16s_nn - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5f731 - movi a6, 0x031be795 - mul16s a5, a2, a4 - assert eq, a5, a6 - mul16s a2, a2, a4 - assert eq, a2, a6 - mul16s a3, a4, a3 - assert eq, a3, a6 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_mul32.S b/tests/tcg/xtensa/test_mul32.S deleted file mode 100644 index 862d45abcec0..000000000000 --- a/tests/tcg/xtensa/test_mul32.S +++ /dev/null @@ -1,24 +0,0 @@ -#include "macros.inc" - -test_suite mul32 - -#if XCHAL_HAVE_MUL32 - -test mull - movi a2, 0x137f5a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x5de480a6 - mull a5, a2, a4 - assert eq, a5, a6 - mull a2, a2, a4 - assert eq, a2, a6 - mull a3, a4, a3 - assert eq, a3, a6 -test_end - -#endif - -/* unfortunately dc232b doesn't have muluh/mulsh*/ - -test_suite_end diff --git a/tests/tcg/xtensa/test_nsa.S b/tests/tcg/xtensa/test_nsa.S deleted file mode 100644 index 0af7d1f50d56..000000000000 --- a/tests/tcg/xtensa/test_nsa.S +++ /dev/null @@ -1,63 +0,0 @@ -#include "macros.inc" - -test_suite nsa - -#if XCHAL_HAVE_NSA - -test nsa - movi a2, 0 - movi a3, 31 - nsa a4, a2 - assert eq, a3, a4 - - movi a2, 0xffffffff - movi a3, 31 - nsa a4, a2 - assert eq, a3, a4 - - movi a2, 1 - movi a3, 30 - nsa a2, a2 - assert eq, a3, a2 - - movi a2, 0xfffffffe - movi a3, 30 - nsa a2, a2 - assert eq, a3, a2 - - movi a2, 0x5a5a5a5a - movi a3, 0 - nsa a4, a2 - assert eq, a3, a4 - - movi a2, 0xa5a5a5a5 - movi a3, 0 - nsa a4, a2 - assert eq, a3, a4 -test_end - -test nsau - movi a2, 0 - movi a3, 32 - nsau a4, a2 - assert eq, a3, a4 - - movi a2, 0xffffffff - movi a3, 0 - nsau a4, a2 - assert eq, a3, a4 - - movi a2, 1 - movi a3, 31 - nsau a2, a2 - assert eq, a3, a2 - - movi a2, 0x5a5a5a5a - movi a3, 1 - nsau a2, a2 - assert eq, a3, a2 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_phys_mem.S b/tests/tcg/xtensa/test_phys_mem.S deleted file mode 100644 index 9bb3ee3866ed..000000000000 --- a/tests/tcg/xtensa/test_phys_mem.S +++ /dev/null @@ -1,128 +0,0 @@ -#include "macros.inc" - -test_suite phys_mem - -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY - -.purgem test_init - -.macro test_init - movi a2, 0xc0000003 /* PPN */ - movi a3, 0xc0000004 /* VPN */ - wdtlb a2, a3 - witlb a2, a3 - movi a2, 0xc0000000 - wsr a2, ptevaddr -.endm - -test inst_fetch_get_pte_no_phys - set_vector kernel, 2f - - movi a2, 0x20000000 - jx a2 -2: - movi a2, 0x20000000 - rsr a3, excvaddr - assert eq, a2, a3 - rsr a3, epc1 - assert eq, a2, a3 - rsr a3, exccause - movi a2, 16 - assert eq, a2, a3 -test_end - -test read_get_pte_no_phys - set_vector kernel, 2f - - movi a2, 0x20000000 -1: - l32i a3, a2, 0 - test_fail -2: - movi a2, 0x20000000 - rsr a3, excvaddr - assert eq, a2, a3 - movi a2, 1b - rsr a3, epc1 - assert eq, a2, a3 - rsr a3, exccause - movi a2, 24 - assert eq, a2, a3 -test_end - -test write_get_pte_no_phys - set_vector kernel, 2f - - movi a2, 0x20000000 -1: - s32i a3, a2, 0 - test_fail -2: - movi a2, 0x20000000 - rsr a3, excvaddr - assert eq, a2, a3 - movi a2, 1b - rsr a3, epc1 - assert eq, a2, a3 - rsr a3, exccause - movi a2, 24 - assert eq, a2, a3 -test_end - -#endif - -test inst_fetch_no_phys - set_vector kernel, 2f - - movi a2, 0xc0000000 - jx a2 -2: - movi a2, 0xc0000000 - rsr a3, excvaddr - assert eq, a2, a3 - rsr a3, epc1 - assert eq, a2, a3 - rsr a3, exccause - movi a2, 14 - assert eq, a2, a3 -test_end - -test read_no_phys - set_vector kernel, 2f - - movi a2, 0xc0000000 -1: - l32i a3, a2, 0 - test_fail -2: - movi a2, 0xc0000000 - rsr a3, excvaddr - assert eq, a2, a3 - movi a2, 1b - rsr a3, epc1 - assert eq, a2, a3 - rsr a3, exccause - movi a2, 15 - assert eq, a2, a3 -test_end - -test write_no_phys - set_vector kernel, 2f - - movi a2, 0xc0000000 -1: - s32i a3, a2, 0 - test_fail -2: - movi a2, 0xc0000000 - rsr a3, excvaddr - assert eq, a2, a3 - movi a2, 1b - rsr a3, epc1 - assert eq, a2, a3 - rsr a3, exccause - movi a2, 15 - assert eq, a2, a3 -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_quo.S b/tests/tcg/xtensa/test_quo.S deleted file mode 100644 index 32886b913be6..000000000000 --- a/tests/tcg/xtensa/test_quo.S +++ /dev/null @@ -1,151 +0,0 @@ -#include "macros.inc" - -test_suite quo - -#if XCHAL_HAVE_DIV32 - -test quou_pp - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0x4 - quou a5, a2, a4 - assert eq, a5, a6 - quou a2, a2, a4 - assert eq, a2, a6 - quou a4, a3, a4 - assert eq, a4, a6 -test_end - -test quou_np - movi a2, 0xa5a5137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0x8 - quou a5, a2, a4 - assert eq, a5, a6 - quou a2, a2, a4 - assert eq, a2, a6 - quou a4, a3, a4 - assert eq, a4, a6 -test_end - -test quou_pn - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0xf7315a5a - movi a6, 0 - quou a5, a2, a4 - assert eq, a5, a6 - quou a2, a2, a4 - assert eq, a2, a6 - quou a4, a3, a4 - assert eq, a4, a6 -test_end - -test quou_nn - movi a2, 0xf7315a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x1 - quou a5, a2, a4 - assert eq, a5, a6 - quou a2, a2, a4 - assert eq, a2, a6 - quou a4, a3, a4 - assert eq, a4, a6 -test_end - -test quou_exc - set_vector kernel, 2f - movi a2, 0xf7315a5a - movi a4, 0x00000000 -1: - quou a5, a2, a4 - test_fail -2: - rsr a2, exccause - assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 -test_end - -test quos_pp - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0x4 - quos a5, a2, a4 - assert eq, a5, a6 - quos a2, a2, a4 - assert eq, a2, a6 - quos a4, a3, a4 - assert eq, a4, a6 -test_end - -test quos_np - movi a2, 0xa5a5137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0xfffffffc - quos a5, a2, a4 - assert eq, a5, a6 - quos a2, a2, a4 - assert eq, a2, a6 - quos a4, a3, a4 - assert eq, a4, a6 -test_end - -test quos_pn - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0xf7315a5a - movi a6, 0xfffffff6 - quos a5, a2, a4 - assert eq, a5, a6 - quos a2, a2, a4 - assert eq, a2, a6 - quos a4, a3, a4 - assert eq, a4, a6 -test_end - -test quos_nn - movi a2, 0xf7315a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0 - quos a5, a2, a4 - assert eq, a5, a6 - quos a2, a2, a4 - assert eq, a2, a6 - quos a4, a3, a4 - assert eq, a4, a6 -test_end - -test quos_over - movi a2, 0x80000000 - movi a4, 0xffffffff - movi a6, 0x80000000 - quos a5, a2, a4 - assert eq, a5, a6 -test_end - -test quos_exc - set_vector kernel, 2f - movi a2, 0xf7315a5a - movi a4, 0x00000000 -1: - quos a5, a2, a4 - test_fail -2: - rsr a2, exccause - assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_rem.S b/tests/tcg/xtensa/test_rem.S deleted file mode 100644 index 0b96bb3390ab..000000000000 --- a/tests/tcg/xtensa/test_rem.S +++ /dev/null @@ -1,151 +0,0 @@ -#include "macros.inc" - -test_suite rem - -#if XCHAL_HAVE_DIV32 - -test remu_pp - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0x0c5caa17 - remu a5, a2, a4 - assert eq, a5, a6 - remu a2, a2, a4 - assert eq, a2, a6 - remu a4, a3, a4 - assert eq, a4, a6 -test_end - -test remu_np - movi a2, 0xa5a5137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0x9aa40af - remu a5, a2, a4 - assert eq, a5, a6 - remu a2, a2, a4 - assert eq, a2, a6 - remu a4, a3, a4 - assert eq, a4, a6 -test_end - -test remu_pn - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0xf7315a5a - movi a6, 0x5a5a137f - remu a5, a2, a4 - assert eq, a5, a6 - remu a2, a2, a4 - assert eq, a2, a6 - remu a4, a3, a4 - assert eq, a4, a6 -test_end - -test remu_nn - movi a2, 0xf7315a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x518c46db - remu a5, a2, a4 - assert eq, a5, a6 - remu a2, a2, a4 - assert eq, a2, a6 - remu a4, a3, a4 - assert eq, a4, a6 -test_end - -test remu_exc - set_vector kernel, 2f - movi a2, 0xf7315a5a - movi a4, 0x00000000 -1: - remu a5, a2, a4 - test_fail -2: - rsr a2, exccause - assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 -test_end - -test rems_pp - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0x0c5caa17 - rems a5, a2, a4 - assert eq, a5, a6 - rems a2, a2, a4 - assert eq, a2, a6 - rems a4, a3, a4 - assert eq, a4, a6 -test_end - -test rems_np - movi a2, 0xa5a5137f - mov a3, a2 - movi a4, 0x137f5a5a - movi a6, 0xf3a27ce7 - rems a5, a2, a4 - assert eq, a5, a6 - rems a2, a2, a4 - assert eq, a2, a6 - rems a4, a3, a4 - assert eq, a4, a6 -test_end - -test rems_pn - movi a2, 0x5a5a137f - mov a3, a2 - movi a4, 0xf7315a5a - movi a6, 0x02479b03 - rems a5, a2, a4 - assert eq, a5, a6 - rems a2, a2, a4 - assert eq, a2, a6 - rems a4, a3, a4 - assert eq, a4, a6 -test_end - -test rems_nn - movi a2, 0xf7315a5a - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xf7315a5a - rems a5, a2, a4 - assert eq, a5, a6 - rems a2, a2, a4 - assert eq, a2, a6 - rems a4, a3, a4 - assert eq, a4, a6 -test_end - -test rems_over - movi a2, 0x80000000 - movi a4, 0xffffffff - movi a6, 0 - rems a5, a2, a4 - assert eq, a5, a6 -test_end - -test rems_exc - set_vector kernel, 2f - movi a2, 0xf7315a5a - movi a4, 0x00000000 -1: - rems a5, a2, a4 - test_fail -2: - rsr a2, exccause - assert eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */ - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_rst0.S b/tests/tcg/xtensa/test_rst0.S deleted file mode 100644 index 143e90b401ec..000000000000 --- a/tests/tcg/xtensa/test_rst0.S +++ /dev/null @@ -1,156 +0,0 @@ -#include "macros.inc" - -test_suite rst0 - -test and - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x01250125 - and a5, a2, a4 - assert eq, a5, a6 - and a2, a2, a4 - assert eq, a2, a6 - and a3, a4, a3 - assert eq, a3, a6 -test_end - -test or - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xb7ffb7ff - or a5, a2, a4 - assert eq, a5, a6 - or a2, a2, a4 - assert eq, a2, a6 - or a3, a4, a3 - assert eq, a3, a6 -test_end - -test xor - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xb6dab6da - xor a5, a2, a4 - assert eq, a5, a6 - xor a2, a2, a4 - assert eq, a2, a6 - xor a3, a4, a3 - assert eq, a3, a6 -test_end - -test add - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xb924b924 - add a5, a2, a4 - assert eq, a5, a6 - add a2, a2, a4 - assert eq, a2, a6 - add a4, a3, a4 - assert eq, a4, a6 -test_end - -#if XCHAL_HAVE_ADDX - -test addx2 - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xcca45ec9 - addx2 a5, a2, a4 - assert eq, a5, a6 - addx2 a2, a2, a4 - assert eq, a2, a6 - addx2 a4, a3, a4 - assert eq, a4, a6 -test_end - -test addx4 - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xf3a3aa13 - addx4 a5, a2, a4 - assert eq, a5, a6 - addx4 a2, a2, a4 - assert eq, a2, a6 - addx4 a4, a3, a4 - assert eq, a4, a6 -test_end - -test addx8 - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x41a240a7 - addx8 a5, a2, a4 - assert eq, a5, a6 - addx8 a2, a2, a4 - assert eq, a2, a6 - addx8 a4, a3, a4 - assert eq, a4, a6 -test_end - -#endif - -test sub - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x6dda9226 - sub a5, a2, a4 - assert eq, a5, a6 - sub a2, a2, a4 - assert eq, a2, a6 - sub a4, a3, a4 - assert eq, a4, a6 -test_end - -#if XCHAL_HAVE_ADDX - -test subx2 - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0x815a37cb - subx2 a5, a2, a4 - assert eq, a5, a6 - subx2 a2, a2, a4 - assert eq, a2, a6 - subx2 a4, a3, a4 - assert eq, a4, a6 -test_end - -test subx4 - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xa8598315 - subx4 a5, a2, a4 - assert eq, a5, a6 - subx4 a2, a2, a4 - assert eq, a2, a6 - subx4 a4, a3, a4 - assert eq, a4, a6 -test_end - -test subx8 - movi a2, 0x137fa5a5 - mov a3, a2 - movi a4, 0xa5a5137f - movi a6, 0xf65819a9 - subx8 a5, a2, a4 - assert eq, a5, a6 - subx8 a2, a2, a4 - assert eq, a2, a6 - subx8 a4, a3, a4 - assert eq, a4, a6 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_s32c1i.S b/tests/tcg/xtensa/test_s32c1i.S deleted file mode 100644 index 2885d9d003c0..000000000000 --- a/tests/tcg/xtensa/test_s32c1i.S +++ /dev/null @@ -1,51 +0,0 @@ -#include "macros.inc" - -test_suite s32c1i - -#if XCHAL_HAVE_S32C1I - -test s32c1i_nowrite -#if XCHAL_HW_VERSION >= 230000 - movi a2, 0x29 - wsr a2, atomctl -#endif - movi a2, 1f - movi a3, 1 - wsr a3, scompare1 - movi a1, 2 - s32c1i a1, a2, 0 - assert ne, a1, a3 - l32i a1, a2, 0 - assert eqi, a1, 3 - -.data -.align 4 -1: - .word 3 -.text -test_end - -test s32c1i_write -#if XCHAL_HW_VERSION >= 230000 - movi a2, 0x29 - wsr a2, atomctl -#endif - movi a2, 1f - movi a3, 3 - wsr a3, scompare1 - movi a1, 2 - s32c1i a1, a2, 0 - assert eq, a1, a3 - l32i a1, a2, 0 - assert eqi, a1, 2 - -.data -.align 4 -1: - .word 3 -.text -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_sar.S b/tests/tcg/xtensa/test_sar.S deleted file mode 100644 index b615a5576710..000000000000 --- a/tests/tcg/xtensa/test_sar.S +++ /dev/null @@ -1,111 +0,0 @@ -#include "macros.inc" - -test_suite sar - -.macro test_sar prefix, imm - \prefix\()_set \imm - \prefix\()_ver \imm -.endm - -.macro tests_sar prefix - test_sar \prefix, 0 - test_sar \prefix, 1 - test_sar \prefix, 2 - test_sar \prefix, 3 - test_sar \prefix, 0x1f - test_sar \prefix, 0x20 - test_sar \prefix, 0x3f - test_sar \prefix, 0x40 - test_sar \prefix, 0xfffffffe -.endm - -.macro sar_set imm - movi a2, \imm - wsr a2, sar -.endm - -.macro sar_ver imm - rsr a3, sar - movi a2, \imm & 0x3f - assert eq, a2, a3 -.endm - -test sar - tests_sar sar -test_end - -.macro ssr_set imm - movi a2, \imm - ssr a2 -.endm - -.macro ssr_ver imm - rsr a3, sar - movi a2, \imm & 0x1f - assert eq, a2, a3 -.endm - -test ssr - tests_sar ssr -test_end - -.macro ssl_set imm - movi a2, \imm - ssl a2 -.endm - -.macro ssl_ver imm - rsr a3, sar - movi a2, 32 - (\imm & 0x1f) - assert eq, a2, a3 -.endm - -test ssl - tests_sar ssl -test_end - -.macro ssa8l_set imm - movi a2, \imm - ssa8l a2 -.endm - -.macro ssa8l_ver imm - rsr a3, sar - movi a2, (\imm & 0x3) << 3 - assert eq, a2, a3 -.endm - -test ssa8l - tests_sar ssa8l -test_end - -.macro ssa8b_set imm - movi a2, \imm - ssa8b a2 -.endm - -.macro ssa8b_ver imm - rsr a3, sar - movi a2, 32 - ((\imm & 0x3) << 3) - assert eq, a2, a3 -.endm - -test ssa8b - tests_sar ssa8b -test_end - -.macro ssai_set imm - ssai \imm & 0x1f -.endm - -.macro ssai_ver imm - rsr a3, sar - movi a2, \imm & 0x1f - assert eq, a2, a3 -.endm - -test ssai - tests_sar ssai -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_sext.S b/tests/tcg/xtensa/test_sext.S deleted file mode 100644 index 483d2176e421..000000000000 --- a/tests/tcg/xtensa/test_sext.S +++ /dev/null @@ -1,73 +0,0 @@ -#include "macros.inc" - -test_suite sext - -#if XCHAL_HAVE_SEXT - -test sext - movi a2, 0xffffff5a - movi a3, 0x0000005a - sext a4, a2, 7 - assert eq, a3, a4 - - movi a2, 0x000000a5 - movi a3, 0xffffffa5 - sext a4, a2, 7 - assert eq, a3, a4 - - movi a2, 0xfffffaa5 - movi a3, 0x000000a5 - sext a4, a2, 8 - assert eq, a3, a4 - - movi a2, 0x0000055a - movi a3, 0xffffff5a - sext a4, a2, 8 - assert eq, a3, a4 - - movi a2, 0xffff5a5a - movi a3, 0x00005a5a - sext a4, a2, 15 - assert eq, a3, a4 - - movi a2, 0x0000a5a5 - movi a3, 0xffffa5a5 - sext a4, a2, 15 - assert eq, a3, a4 - - movi a2, 0x00055a5a - movi a3, 0xffff5a5a - sext a4, a2, 16 - assert eq, a3, a4 - - movi a2, 0x000aa5a5 - movi a3, 0x0000a5a5 - sext a4, a2, 16 - assert eq, a3, a4 - - movi a2, 0x005a5a5a - movi a3, 0xffda5a5a - sext a4, a2, 22 - assert eq, a3, a4 - - movi a2, 0xffa5a5a5 - movi a3, 0x0025a5a5 - sext a4, a2, 22 - assert eq, a3, a4 -test_end - -test sext_same_rs - movi a2, 0xffffff5a - movi a3, 0x0000005a - sext a2, a2, 7 - assert eq, a3, a2 - - movi a2, 0x000000a5 - movi a3, 0xffffffa5 - sext a2, a2, 7 - assert eq, a3, a2 -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_shift.S b/tests/tcg/xtensa/test_shift.S deleted file mode 100644 index 5df9ed4b1e1e..000000000000 --- a/tests/tcg/xtensa/test_shift.S +++ /dev/null @@ -1,206 +0,0 @@ -#include "macros.inc" - -test_suite shift - -.macro test_shift prefix, dst, src, v, imm - \prefix\()_set \dst, \src, \v, \imm - \prefix\()_ver \dst, \v, \imm -.endm - -.macro test_shift_sd prefix, v, imm - test_shift \prefix, a3, a2, \v, \imm - test_shift \prefix, a2, a2, \v, \imm -.endm - -.macro tests_imm_shift prefix, v - test_shift_sd \prefix, \v, 1 - test_shift_sd \prefix, \v, 2 - test_shift_sd \prefix, \v, 7 - test_shift_sd \prefix, \v, 8 - test_shift_sd \prefix, \v, 15 - test_shift_sd \prefix, \v, 16 - test_shift_sd \prefix, \v, 31 -.endm - -.macro tests_shift prefix, v - test_shift_sd \prefix, \v, 0 - tests_imm_shift \prefix, \v - test_shift_sd \prefix, \v, 32 -.endm - - -.macro slli_set dst, src, v, imm - movi \src, \v - slli \dst, \src, \imm -.endm - -.macro slli_ver dst, v, imm - mov a2, \dst - movi a3, ((\v) << (\imm)) & 0xffffffff - assert eq, a2, a3 -.endm - -test slli - tests_imm_shift slli, 0xa3c51249 -test_end - - -.macro srai_set dst, src, v, imm - movi \src, \v - srai \dst, \src, \imm -.endm - -.macro srai_ver dst, v, imm - mov a2, \dst - .if (\imm) - movi a3, (((\v) >> (\imm)) & 0xffffffff) | \ - ~((((\v) & 0x80000000) >> ((\imm) - 1)) - 1) - .else - movi a3, \v - .endif - assert eq, a2, a3 -.endm - -test srai - tests_imm_shift srai, 0x49a3c512 - tests_imm_shift srai, 0xa3c51249 -test_end - - -.macro srli_set dst, src, v, imm - movi \src, \v - srli \dst, \src, \imm -.endm - -.macro srli_ver dst, v, imm - mov a2, \dst - movi a3, (((\v) >> (\imm)) & 0xffffffff) - assert eq, a2, a3 -.endm - -test srli - tests_imm_shift srli, 0x49a3c512 - tests_imm_shift srli, 0xa3c51249 -test_end - - -.macro sll_set dst, src, v, imm - movi a2, \imm - ssl a2 - movi \src, \v - sll \dst, \src -.endm - -.macro sll_sar_set dst, src, v, imm - movi a2, 32 - \imm - wsr a2, sar - movi \src, \v - sll \dst, \src -.endm - -.macro sll_ver dst, v, imm - slli_ver \dst, \v, (\imm) & 0x1f -.endm - -.macro sll_sar_ver dst, v, imm - slli_ver \dst, \v, \imm -.endm - -test sll - tests_shift sll, 0xa3c51249 - tests_shift sll_sar, 0xa3c51249 -test_end - - -.macro srl_set dst, src, v, imm - movi a2, \imm - ssr a2 - movi \src, \v - srl \dst, \src -.endm - -.macro srl_sar_set dst, src, v, imm - movi a2, \imm - wsr a2, sar - movi \src, \v - srl \dst, \src -.endm - -.macro srl_ver dst, v, imm - srli_ver \dst, \v, (\imm) & 0x1f -.endm - -.macro srl_sar_ver dst, v, imm - srli_ver \dst, \v, \imm -.endm - -test srl - tests_shift srl, 0xa3c51249 - tests_shift srl_sar, 0xa3c51249 - tests_shift srl, 0x49a3c512 - tests_shift srl_sar, 0x49a3c512 -test_end - - -.macro sra_set dst, src, v, imm - movi a2, \imm - ssr a2 - movi \src, \v - sra \dst, \src -.endm - -.macro sra_sar_set dst, src, v, imm - movi a2, \imm - wsr a2, sar - movi \src, \v - sra \dst, \src -.endm - -.macro sra_ver dst, v, imm - srai_ver \dst, \v, (\imm) & 0x1f -.endm - -.macro sra_sar_ver dst, v, imm - srai_ver \dst, \v, \imm -.endm - -test sra - tests_shift sra, 0xa3c51249 - tests_shift sra_sar, 0xa3c51249 - tests_shift sra, 0x49a3c512 - tests_shift sra_sar, 0x49a3c512 -test_end - - -.macro src_set dst, src, v, imm - movi a2, \imm - ssr a2 - movi \src, (\v) & 0xffffffff - movi a4, (\v) >> 32 - src \dst, a4, \src -.endm - -.macro src_sar_set dst, src, v, imm - movi a2, \imm - wsr a2, sar - movi \src, (\v) & 0xffffffff - movi a4, (\v) >> 32 - src \dst, a4, \src -.endm - -.macro src_ver dst, v, imm - src_sar_ver \dst, \v, (\imm) & 0x1f -.endm - -.macro src_sar_ver dst, v, imm - mov a2, \dst - movi a3, ((\v) >> (\imm)) & 0xffffffff - assert eq, a2, a3 -.endm - -test src - tests_shift src, 0xa3c51249215c3a94 - tests_shift src_sar, 0xa3c51249215c3a94 -test_end - -test_suite_end diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S deleted file mode 100644 index b1a91a0637ee..000000000000 --- a/tests/tcg/xtensa/test_sr.S +++ /dev/null @@ -1,236 +0,0 @@ -#include "macros.inc" - -test_suite sr - -#if XCHAL_HAVE_BE -#define LOW__SR 0x04 -#define HI_RSR 0x30 -#define HI_WSR 0x31 -#define HI_XSR 0x16 -#else -#define LOW__SR 0x40 -#define HI_RSR 0x03 -#define HI_WSR 0x13 -#define HI_XSR 0x61 -#endif - -.macro sr_op sym, op_sym, op_byte, sr - .if \sym - \op_sym a4, \sr - .else - .byte LOW__SR, \sr, \op_byte - .endif -.endm - -.macro test_sr_op sym, mask, op, op_byte, sr - movi a4, 0 - .if (\mask) - set_vector kernel, 0 - sr_op \sym, \op, \op_byte, \sr - .else - set_vector kernel, 2f -1: - sr_op \sym, \op, \op_byte, \sr - test_fail -2: - reset_ps - rsr a2, exccause - assert eqi, a2, 0 - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - .endif -.endm - -.macro test_sr_mask sr, sym, mask -test \sr - test_sr_op \sym, \mask & 1, rsr, HI_RSR, \sr - test_sr_op \sym, \mask & 2, wsr, HI_WSR, \sr - test_sr_op \sym, \mask & 4, xsr, HI_XSR, \sr -test_end -.endm - -.macro test_sr sr, conf - test_sr_mask \sr, \conf, 7 -.endm - -#if XCHAL_HAVE_MAC16 -test_sr acchi, 1 -test_sr acclo, 1 -#else -test_sr_mask /*acchi*/17, 0, 0 -test_sr_mask /*acclo*/16, 0, 0 -#endif - -#if XCHAL_HAVE_S32C1I && XCHAL_HW_VERSION >= 230000 -test_sr atomctl, 1 -#else -test_sr_mask /*atomctl*/99, 0, 0 -#endif - -#if XCHAL_HAVE_BOOLEANS -test_sr br, 1 -#else -test_sr_mask /*br*/4, 0, 0 -#endif - -test_sr_mask /*cacheattr*/98, 0, 0 - -#if XCHAL_HAVE_CCOUNT -test_sr ccompare0, 1 -test_sr ccount, 1 -#else -test_sr_mask /*ccompare0*/240, 0, 0 -test_sr_mask /*ccount*/234, 0, 0 -#endif - -#if XCHAL_HAVE_CP -test_sr cpenable, 1 -#else -test_sr_mask /*cpenable*/224, 0, 0 -#endif - -#if XCHAL_HAVE_DEBUG -#if XCHAL_NUM_DBREAK -test_sr dbreaka0, 1 -test_sr dbreakc0, 1 -#endif -test_sr_mask debugcause, 1, 1 -#else -test_sr_mask /*dbreaka0*/144, 0, 0 -test_sr_mask /*dbreakc0*/160, 0, 0 -test_sr_mask /*debugcause*/233, 0, 0 -#endif - -test_sr depc, 1 - -#if XCHAL_HAVE_PTP_MMU -test_sr dtlbcfg, 1 -#else -test_sr_mask /*dtlbcfg*/92, 0, 0 -#endif - -test_sr epc1, 1 - -#if XCHAL_NUM_INTLEVELS > 1 -test_sr epc2, 1 -test_sr eps2, 1 -#else -test_sr_mask /*epc2*/178, 0, 0 -test_sr_mask /*eps2*/194, 0, 0 -#endif - -test_sr exccause, 1 -test_sr excsave1, 1 - -#if XCHAL_NUM_INTLEVELS > 1 -test_sr excsave2, 1 -#else -test_sr_mask /*excsave2*/210, 0, 0 -#endif - -test_sr excvaddr, 1 - -#if XCHAL_HAVE_DEBUG -#if XCHAL_NUM_IBREAK -test_sr ibreaka0, 1 -test_sr ibreakenable, 1 -#endif -test_sr icount, 1 -test_sr icountlevel, 1 -#else -test_sr_mask /*ibreaka0*/128, 0, 0 -test_sr_mask /*ibreakenable*/96, 0, 0 -test_sr_mask /*icount*/236, 0, 0 -test_sr_mask /*icountlevel*/237, 0, 0 -#endif - -test_sr_mask /*intclear*/227, 0, 2 -test_sr_mask /*interrupt*/226, 0, 3 -test_sr intenable, 1 - -#if XCHAL_HAVE_PTP_MMU -test_sr itlbcfg, 1 -#else -test_sr_mask /*itlbcfg*/91, 0, 0 -#endif - -#if XCHAL_HAVE_LOOPS -test_sr lbeg, 1 -test_sr lcount, 1 -test_sr lend, 1 -#else -test_sr_mask /*lbeg*/0, 0, 0 -test_sr_mask /*lcount*/2, 0, 0 -test_sr_mask /*lend*/1, 0, 0 -#endif - -#if XCHAL_HAVE_ABSOLUTE_LITERALS -test_sr litbase, 1 -#else -test_sr_mask /*litbase*/5, 0, 0 -#endif - -#if XCHAL_HAVE_MAC16 -test_sr m0, 1 -#else -test_sr_mask /*m0*/32, 0, 0 -#endif - -#if XCHAL_HW_VERSION >= 250000 -test_sr_mask /*memctl*/97, 0, 7 -#else -test_sr_mask /*memctl*/97, 0, 0 -#endif - -#if XCHAL_NUM_MISC_REGS -test_sr misc0, 1 -#else -test_sr_mask /*misc0*/244, 0, 0 -#endif - -#if XCHAL_HAVE_PREFETCH -test_sr prefctl, 1 -#else -test_sr_mask /*prefctl*/40, 0, 0 -#endif - -#if XCHAL_HAVE_PRID -test_sr_mask /*prid*/235, 0, 1 -#else -test_sr_mask /*prid*/235, 0, 0 -#endif - -test_sr ps, 1 - -#if XCHAL_HAVE_PTP_MMU -test_sr ptevaddr, 1 -test_sr rasid, 1 -#else -test_sr_mask /*ptevaddr*/83, 0, 0 -test_sr_mask /*rasid*/90, 0, 0 -#endif - -test_sr sar, 1 - -#if XCHAL_HAVE_S32C1I -test_sr scompare1, 1 -#else -test_sr_mask /*scompare1*/12, 0, 0 -#endif - -#if XCHAL_HAVE_VECBASE -test_sr vecbase, 1 -#else -test_sr_mask /*vecbase*/231, 0, 0 -#endif - -#if XCHAL_HAVE_WINDOWED -test_sr windowbase, 1 -test_sr windowstart, 1 -#else -test_sr_mask /*windowbase*/72, 0, 0 -test_sr_mask /*windowstart*/73, 0, 0 -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S deleted file mode 100644 index 1ec8e20883ff..000000000000 --- a/tests/tcg/xtensa/test_timer.S +++ /dev/null @@ -1,257 +0,0 @@ -#include "macros.inc" - -#define CCOUNT_SHIFT 4 -#define WAIT_LOOPS 20 -#define level1 kernel -#define INTERRUPT_LEVEL(n) glue3(XCHAL_INT, n, _LEVEL) - -.macro make_ccount_delta target, delta - rsr \delta, ccount - rsr \target, ccount - sub \delta, \target, \delta - slli \delta, \delta, CCOUNT_SHIFT - add \target, \target, \delta -.endm - -test_suite timer - -#if XCHAL_HAVE_CCOUNT - -test ccount - rsr a3, ccount - rsr a4, ccount - assert ne, a3, a4 -test_end - -test ccount_write - rsr a3, ccount - rsr a4, ccount - sub a4, a4, a3 - movi a2, 0x12345678 - wsr a2, ccount - esync - rsr a3, ccount - sub a3, a3, a2 - slli a4, a4, 2 - assert ltu, a3, a4 -test_end - -#if XCHAL_NUM_TIMERS - -test ccount_update_deadline - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 -#if XCHAL_NUM_TIMERS > 1 - wsr a2, ccompare1 -#endif -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - movi a2, 0x12345678 - wsr a2, ccompare0 - rsr a3, interrupt - assert eqi, a3, 0 - movi a2, 0x12345677 - wsr a2, ccount - esync - nop - rsr a2, interrupt - movi a3, 1 << XCHAL_TIMER0_INTERRUPT - assert eq, a2, a3 -test_end - -test ccompare - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 -#if XCHAL_NUM_TIMERS > 1 - wsr a2, ccompare1 -#endif -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - - make_ccount_delta a2, a15 - wsr a2, ccompare0 -1: - rsr a3, interrupt - rsr a4, ccount - rsr a5, interrupt - sub a4, a4, a2 - bgez a4, 2f - assert eqi, a3, 0 - j 1b -2: - assert nei, a5, 0 -test_end - -#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 -test ccompare0_interrupt - set_vector kernel, 2f - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 -#if XCHAL_NUM_TIMERS > 1 - wsr a2, ccompare1 -#endif -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - - movi a3, WAIT_LOOPS - make_ccount_delta a2, a15 - wsr a2, ccompare0 - rsync - rsr a2, interrupt - assert eqi, a2, 0 - - movi a2, 1 << XCHAL_TIMER0_INTERRUPT - wsr a2, intenable - rsil a2, 0 - loop a3, 1f - nop -1: - test_fail -2: - rsr a2, exccause - assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ -test_end -#endif - -#if XCHAL_NUM_TIMERS > 1 - -test ccompare1_interrupt - set_vector glue(level, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT)), 2f - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 - wsr a2, ccompare0 -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - - movi a3, WAIT_LOOPS - make_ccount_delta a2, a15 - wsr a2, ccompare1 - rsync - rsr a2, interrupt - assert eqi, a2, 0 - movi a2, 1 << XCHAL_TIMER1_INTERRUPT - wsr a2, intenable - rsil a2, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT) - 1 - loop a3, 1f - nop -1: - test_fail -2: -test_end - -#endif -#if XCHAL_NUM_TIMERS > 2 - -test ccompare2_interrupt - set_vector glue(level, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT)), 2f - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 - wsr a2, ccompare0 - wsr a2, ccompare1 - - movi a3, WAIT_LOOPS - make_ccount_delta a2, a15 - wsr a2, ccompare2 - rsync - rsr a2, interrupt - assert eqi, a2, 0 - movi a2, 1 << XCHAL_TIMER2_INTERRUPT - wsr a2, intenable - rsil a2, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT) - 1 - loop a3, 1f - nop -1: - test_fail -2: -test_end - -#endif - -test ccompare_interrupt_masked - set_vector kernel, 2f - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - - movi a3, 2 * WAIT_LOOPS - make_ccount_delta a2, a15 -#if XCHAL_NUM_TIMERS > 1 - wsr a2, ccompare1 -#endif - add a2, a2, a15 - wsr a2, ccompare0 - rsync - rsr a2, interrupt - assert eqi, a2, 0 - - movi a2, 1 << XCHAL_TIMER0_INTERRUPT - wsr a2, intenable - rsil a2, 0 - loop a3, 1f - nop -1: - test_fail -2: - rsr a2, exccause - assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ -test_end - -test ccompare_interrupt_masked_waiti - set_vector kernel, 2f - movi a2, 0 - wsr a2, intenable - rsr a2, interrupt - wsr a2, intclear - movi a2, 0 -#if XCHAL_NUM_TIMERS > 2 - wsr a2, ccompare2 -#endif - - movi a3, 2 * WAIT_LOOPS - make_ccount_delta a2, a15 -#if XCHAL_NUM_TIMERS > 1 - wsr a2, ccompare1 -#endif - add a2, a2, a15 - wsr a2, ccompare0 - rsync - rsr a2, interrupt - assert eqi, a2, 0 - - movi a2, 1 << XCHAL_TIMER0_INTERRUPT - wsr a2, intenable - waiti 0 - test_fail -2: - rsr a2, exccause - assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ -test_end - -#endif -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/test_windowed.S b/tests/tcg/xtensa/test_windowed.S deleted file mode 100644 index 5ead90a790ed..000000000000 --- a/tests/tcg/xtensa/test_windowed.S +++ /dev/null @@ -1,367 +0,0 @@ -#include "macros.inc" - -test_suite windowed - -#if XCHAL_HAVE_WINDOWED - -.altmacro - -.macro reset_window start - movi a2, 0xffff - wsr a2, windowstart - rsync - movi a2, 0 - wsr a2, windowbase - rsync - movi a2, \start - wsr a2, windowstart - rsync -.endm - -.macro overflow_test shift, window, probe_ok, probe_ex - set_vector window_overflow_4, 0 - set_vector window_overflow_8, 0 - set_vector window_overflow_12, 0 - - movi a2, 1 | (((1 << ((\window) / 4)) | 1) << ((\shift) / 4)) - wsr a2, windowstart - reset_ps - - mov a2, a\probe_ok - set_vector window_overflow_\window, 10f -1: - mov a2, a\probe_ex - test_fail -10: - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - movi a2, 2f - wsr a2, epc1 - - rsr a2, windowbase - movi a3, (\shift) / 4 - assert eq, a2, a3 - rsr a2, ps - movi a3, 0x4001f - assert eq, a2, a3 - rfwo - test_fail -2: - rsr a2, windowbase - assert eqi, a2, 0 - rsr a2, windowstart - movi a3, 1 | ((1 << ((\window) / 4)) << ((\shift) / 4)) - assert eq, a2, a3 - rsr a2, ps - movi a3, 0x4000f - assert eq, a2, a3 -.endm - -.macro overflow_tests shift, window, probe - .if \probe < 15 - overflow_test \shift, \window, %((\shift) - 1), \probe - overflow_tests \shift, \window, %((\probe) + 1) - .endif -.endm - -.macro all_overflow_tests - .irp shift, 4, 8, 12 - .irp window, 4, 8, 12 - overflow_tests \shift, \window, \shift - .endr - .endr -.endm - -test overflow - all_overflow_tests -test_end - - -.macro underflow_test window - set_vector window_underflow_4, 0 - set_vector window_underflow_8, 0 - set_vector window_underflow_12, 0 - - set_vector window_underflow_\window, 10f - - reset_window 1 - reset_ps - - ssai 2 - movi a2, 2f - slli a2, a2, 2 - movi a3, (\window) / 4 - src a0, a3, a2 -1: - retw - test_fail -10: - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - movi a2, 2f - wsr a2, epc1 - - rsr a2, ps - movi a3, 0x4001f - assert eq, a2, a3 - rsr a2, windowbase - movi a3, (XCHAL_NUM_AREGS - (\window)) / 4 - assert eq, a2, a3 - rsr a2, windowstart - assert eqi, a2, 1 - rfwu -2: - rsr a2, ps - movi a3, 0x4000f - assert eq, a2, a3 - rsr a2, windowbase - assert eqi, a2, 0 - rsr a2, windowstart - assert bsi.l, a2, 0 - assert bsi.l, a2, (XCHAL_NUM_AREGS - (\window)) / 4 -.endm - -test underflow - set_vector window_overflow_4, 0 - set_vector window_overflow_8, 0 - set_vector window_overflow_12, 0 - - underflow_test 4 - underflow_test 8 - underflow_test 12 -test_end - - -.macro retw_test window - reset_window %(1 | (1 << ((XCHAL_NUM_AREGS - \window) / 4))) - reset_ps - - ssai 2 - movi a2, 1f - slli a2, a2, 2 - movi a3, (\window) / 4 - src a0, a3, a2 - retw - test_fail -1: - rsr a2, ps - movi a3, 0x4000f - assert eq, a2, a3 - rsr a2, windowbase - movi a3, (XCHAL_NUM_AREGS - (\window)) / 4 - assert eq, a2, a3 - rsr a2, windowstart - assert bci.l, a2, 0 - assert bsi.l, a2, (XCHAL_NUM_AREGS - (\window)) / 4 -.endm - -test retw - set_vector window_underflow_4, 0 - set_vector window_underflow_8, 0 - set_vector window_underflow_12, 0 - - retw_test 4 - retw_test 8 - retw_test 12 -test_end - -test movsp - set_vector kernel, 2f - - reset_window 1 - reset_ps -1: - movsp a2, a3 - test_fail -2: - rsr a2, exccause - assert eqi, a2, 5 - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - - set_vector kernel, 0 - - reset_window %(0x1 | (1 << ((XCHAL_NUM_AREGS / 4) - 1))) - reset_ps - - movsp a2, a3 -test_end - -test rotw - reset_window 0x4b - reset_ps - - movi a3, 0x10 - - rotw 1 - rsr a2, windowbase - assert eqi, a2, 1 - movi a3, 0x11 - movi a7, 0x12 - - rotw 2 - rsr a2, windowbase - assert eqi, a2, 3 - movi a3, 0x13 - movi a7, 0x14 - movi a11, 0x15 - - rotw 3 - rsr a2, windowbase - assert eqi, a2, 6 - movi a3, 0x16 - movi a7, 0x17 - -#if XCHAL_NUM_AREGS == 32 - movi a2, 0x44 - wsr a2, windowstart -#elif XCHAL_NUM_AREGS == 64 - movi a2, 0x4004 - wsr a2, windowstart - rotw -8 -#else -#error XCHAL_NUM_AREGS unsupported -#endif - rsync - - movi a2, 0x10 - assert eq, a2, a11 - movi a11, 0x18 - movi a2, 0x11 - assert eq, a2, a15 - movi a15, 0x19 - - rotw 4 - movi a2, 0x12 - assert eq, a2, a3 - movi a2, 0x13 - assert eq, a2, a7 - movi a2, 0x14 - assert eq, a2, a11 - movi a2, 0x15 - assert eq, a2, a15 - - movi a2, 0x5 - wsr a2, windowstart - rsync - - rotw -2 - movi a2, 0x18 - assert eq, a2, a3 - movi a2, 0x19 - assert eq, a2, a7 -test_end - -.macro callw_test window - call\window 2f -1: - test_fail - .align 4 -2: - rsr a2, windowbase - assert eqi, a2, 0 - rsr a2, ps - movi a3, 0x4000f | ((\window) << 14) - assert eq, a2, a3 - movi a2, 1b - slli a2, a2, 2 - ssai 2 - movi a3, (\window) / 4 - src a2, a3, a2 - assert eq, a2, a\window -.endm - -test callw - reset_window 0x1 - reset_ps - - callw_test 4 - callw_test 8 - callw_test 12 -test_end - - -.macro entry_test window - reset_window 0x1 - reset_ps - movi a2, 0x4000f | ((\window) << 14) - wsr a2, ps - isync - movi a3, 0x12345678 - j 1f - .align 4 -1: - entry a3, 0x5678 - movi a2, 0x12340000 - assert eq, a2, a3 - rsr a2, windowbase - assert eqi, a2, (\window) / 4 - rsr a2, windowstart - movi a3, 1 | (1 << ((\window) / 4)) - assert eq, a2, a3 - rotw -(\window) / 4 -.endm - -test entry - entry_test 4 - entry_test 8 - entry_test 12 -test_end - -.macro entry_overflow_test window, free, next_window - set_vector window_overflow_4, 0 - set_vector window_overflow_8, 0 - set_vector window_overflow_12, 0 - set_vector window_overflow_\next_window, 10f - - movi a2, \window - movi a2, \free - movi a2, \next_window - reset_window %(1 | ((1 | (1 << ((\next_window) / 4))) << ((\free) / 4))) - reset_ps - movi a2, 0x4000f | ((\window) << 14) - wsr a2, ps - isync - movi a3, 0x12345678 - j 1f - .align 4 -1: - entry a3, 0x5678 - test_fail - .align 4 -10: - rsr a2, epc1 - movi a3, 1b - assert eq, a2, a3 - movi a2, 2f - wsr a2, epc1 - - rsr a2, windowbase - movi a3, (\free) / 4 - assert eq, a2, a3 - rfwo -2: -.endm - -.macro all_entry_overflow_tests - .irp window, 4, 8, 12 - .irp next_window, 4, 8, 12 - .irp free, 4, 8, 12 - .if \free <= \window - entry_overflow_test \window, \free, \next_window - .endif - .endr - .endr - .endr -.endm - -test entry_overflow - all_entry_overflow_tests -test_end - -#endif - -test_suite_end diff --git a/tests/tcg/xtensa/vectors.S b/tests/tcg/xtensa/vectors.S deleted file mode 100644 index cd48cfb6562c..000000000000 --- a/tests/tcg/xtensa/vectors.S +++ /dev/null @@ -1,65 +0,0 @@ -#include "core-isa.h" - -.macro vector name - -.section .vector.\name, "ax" -.global vector_\name -vector_\name\(): - j 1f - .literal_position -1: - wsr a0, excsave1 - movi a0, 1f - ret.n - -.section .vector.\name\().text, "ax" - .literal_position -1: - rsr a0, excsave1 - wsr a2, excsave1 - movi a2, handler_\name - l32i a2, a2, 0 - beqz a2, 1f - jx a2 -1: - movi a3, 1b - movi a2, 1 - simcall - -.align 4 -.global handler_\name -handler_\name\(): .word 0 - -.endm - -#if XCHAL_HAVE_WINDOWED -vector window_overflow_4 -vector window_overflow_8 -vector window_overflow_12 -vector window_underflow_4 -vector window_underflow_8 -vector window_underflow_12 -#endif - -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 2 -vector level2 -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 3 -vector level3 -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 4 -vector level4 -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 5 -vector level5 -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 6 -vector level6 -#endif -#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 7 -vector level7 -#endif - -vector kernel -vector user -vector double diff --git a/tests/unit/check-block-qdict.c b/tests/unit/check-block-qdict.c index 5a2582509301..751c58e73733 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/check-qjson.c b/tests/unit/check-qjson.c index c845f91d4377..c4e0f851bfc6 100644 --- a/tests/unit/check-qjson.c +++ b/tests/unit/check-qjson.c @@ -21,7 +21,6 @@ #include "qapi/qmp/qnum.h" #include "qapi/qmp/qstring.h" #include "qemu/unicode.h" -#include "qemu-common.h" static QString *from_json_str(const char *jstr, bool single, Error **errp) { diff --git a/tests/unit/check-qnull.c b/tests/unit/check-qnull.c index ebf21db83ccc..5ceacc65d7f3 100644 --- a/tests/unit/check-qnull.c +++ b/tests/unit/check-qnull.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qapi/qmp/qnull.h" -#include "qemu-common.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" #include "qapi/error.h" diff --git a/tests/unit/check-qnum.c b/tests/unit/check-qnum.c index b85fca23029e..bf7fe45bacc4 100644 --- a/tests/unit/check-qnum.c +++ b/tests/unit/check-qnum.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "qapi/qmp/qnum.h" -#include "qemu-common.h" /* * Public Interface test-cases diff --git a/tests/unit/check-qobject.c b/tests/unit/check-qobject.c index c3d50e99949a..022b7c74fe57 100644 --- a/tests/unit/check-qobject.c +++ b/tests/unit/check-qobject.c @@ -15,7 +15,6 @@ #include "qapi/qmp/qnull.h" #include "qapi/qmp/qnum.h" #include "qapi/qmp/qstring.h" -#include "qemu-common.h" #include @@ -74,21 +73,6 @@ static void do_test_equality(bool expected, int _, ...) #define check_unequal(...) \ do_test_equality(false, 0, __VA_ARGS__, &test_equality_end_of_arguments) -static void do_free_all(int _, ...) -{ - va_list ap; - QObject *obj; - - va_start(ap, _); - while ((obj = va_arg(ap, QObject *)) != NULL) { - qobject_unref(obj); - } - va_end(ap); -} - -#define free_all(...) \ - do_free_all(0, __VA_ARGS__, NULL) - static void qobject_is_equal_null_test(void) { check_unequal(qnull(), NULL); @@ -96,15 +80,14 @@ static void qobject_is_equal_null_test(void) static void qobject_is_equal_num_test(void) { - QNum *u0, *i0, *d0, *dnan, *um42, *im42, *dm42; + g_autoptr(QNum) u0 = qnum_from_uint(0u); + g_autoptr(QNum) i0 = qnum_from_int(0); + g_autoptr(QNum) d0 = qnum_from_double(0.0); + g_autoptr(QNum) dnan = qnum_from_double(NAN); + g_autoptr(QNum) um42 = qnum_from_uint((uint64_t)-42); + g_autoptr(QNum) im42 = qnum_from_int(-42); + g_autoptr(QNum) dm42 = qnum_from_double(-42.0); - u0 = qnum_from_uint(0u); - i0 = qnum_from_int(0); - d0 = qnum_from_double(0.0); - dnan = qnum_from_double(NAN); - um42 = qnum_from_uint((uint64_t)-42); - im42 = qnum_from_int(-42); - dm42 = qnum_from_double(-42.0); /* Integers representing a mathematically equal number should * compare equal */ @@ -121,60 +104,45 @@ static void qobject_is_equal_num_test(void) check_unequal(um42, im42); check_unequal(um42, dm42); check_unequal(im42, dm42); - - free_all(u0, i0, d0, dnan, um42, im42, dm42); } static void qobject_is_equal_bool_test(void) { - QBool *btrue_0, *btrue_1, *bfalse_0, *bfalse_1; - - btrue_0 = qbool_from_bool(true); - btrue_1 = qbool_from_bool(true); - bfalse_0 = qbool_from_bool(false); - bfalse_1 = qbool_from_bool(false); + g_autoptr(QBool) btrue_0 = qbool_from_bool(true); + g_autoptr(QBool) btrue_1 = qbool_from_bool(true); + g_autoptr(QBool) bfalse_0 = qbool_from_bool(false); + g_autoptr(QBool) bfalse_1 = qbool_from_bool(false); check_equal(btrue_0, btrue_1); check_equal(bfalse_0, bfalse_1); check_unequal(btrue_0, bfalse_0); - - free_all(btrue_0, btrue_1, bfalse_0, bfalse_1); } static void qobject_is_equal_string_test(void) { - QString *str_base, *str_whitespace_0, *str_whitespace_1, *str_whitespace_2; - QString *str_whitespace_3, *str_case, *str_built; - - str_base = qstring_from_str("foo"); - str_whitespace_0 = qstring_from_str(" foo"); - str_whitespace_1 = qstring_from_str("foo "); - str_whitespace_2 = qstring_from_str("foo\b"); - str_whitespace_3 = qstring_from_str("fooo\b"); - str_case = qstring_from_str("Foo"); - + g_autoptr(QString) str_base = qstring_from_str("foo"); + g_autoptr(QString) str_whitespace_0 = qstring_from_str(" foo"); + g_autoptr(QString) str_whitespace_1 = qstring_from_str("foo "); + g_autoptr(QString) str_whitespace_2 = qstring_from_str("foo\b"); + g_autoptr(QString) str_whitespace_3 = qstring_from_str("fooo\b"); + g_autoptr(QString) str_case = qstring_from_str("Foo"); /* Should yield "foo" */ - str_built = qstring_from_substr("buffoon", 3, 6); + g_autoptr(QString) str_built = qstring_from_substr("buffoon", 3, 6); check_unequal(str_base, str_whitespace_0, str_whitespace_1, str_whitespace_2, str_whitespace_3, str_case); check_equal(str_base, str_built); - - free_all(str_base, str_whitespace_0, str_whitespace_1, str_whitespace_2, - str_whitespace_3, str_case, str_built); } static void qobject_is_equal_list_test(void) { - QList *list_0, *list_1, *list_cloned; - QList *list_reordered, *list_longer, *list_shorter; - - list_0 = qlist_new(); - list_1 = qlist_new(); - list_reordered = qlist_new(); - list_longer = qlist_new(); - list_shorter = qlist_new(); + g_autoptr(QList) list_0 = qlist_new(); + g_autoptr(QList) list_1 = qlist_new(); + g_autoptr(QList) list_reordered = qlist_new(); + g_autoptr(QList) list_longer = qlist_new(); + g_autoptr(QList) list_shorter = qlist_new(); + g_autoptr(QList) list_cloned = NULL; qlist_append_int(list_0, 1); qlist_append_int(list_0, 2); @@ -205,26 +173,19 @@ static void qobject_is_equal_list_test(void) * itself */ qlist_append(list_0, qnum_from_double(NAN)); g_assert(qobject_is_equal(QOBJECT(list_0), QOBJECT(list_0)) == false); - - free_all(list_0, list_1, list_cloned, list_reordered, list_longer, - list_shorter); } static void qobject_is_equal_dict_test(void) { - QDict *dict_0, *dict_1, *dict_cloned; - QDict *dict_different_key, *dict_different_value, *dict_different_null_key; - QDict *dict_longer, *dict_shorter, *dict_nested; - QDict *dict_crumpled; - - dict_0 = qdict_new(); - dict_1 = qdict_new(); - dict_different_key = qdict_new(); - dict_different_value = qdict_new(); - dict_different_null_key = qdict_new(); - dict_longer = qdict_new(); - dict_shorter = qdict_new(); - dict_nested = qdict_new(); + g_autoptr(QDict) dict_cloned = NULL; + g_autoptr(QDict) dict_0 = qdict_new(); + g_autoptr(QDict) dict_1 = qdict_new(); + g_autoptr(QDict) dict_different_key = qdict_new(); + g_autoptr(QDict) dict_different_value = qdict_new(); + g_autoptr(QDict) dict_different_null_key = qdict_new(); + g_autoptr(QDict) dict_longer = qdict_new(); + g_autoptr(QDict) dict_shorter = qdict_new(); + g_autoptr(QDict) dict_nested = qdict_new(); qdict_put_int(dict_0, "f.o", 1); qdict_put_int(dict_0, "bar", 2); @@ -274,41 +235,25 @@ static void qobject_is_equal_dict_test(void) dict_different_null_key, dict_longer, dict_shorter, dict_nested); - dict_crumpled = qobject_to(QDict, qdict_crumple(dict_1, &error_abort)); - check_equal(dict_crumpled, dict_nested); - - qdict_flatten(dict_nested); - check_equal(dict_0, dict_nested); - /* Containing an NaN value will make this dict compare unequal to * itself */ qdict_put(dict_0, "NaN", qnum_from_double(NAN)); g_assert(qobject_is_equal(QOBJECT(dict_0), QOBJECT(dict_0)) == false); - - free_all(dict_0, dict_1, dict_cloned, dict_different_key, - dict_different_value, dict_different_null_key, dict_longer, - dict_shorter, dict_nested, dict_crumpled); } static void qobject_is_equal_conversion_test(void) { - QNum *u0, *i0, *d0; - QString *s0, *s_empty; - QBool *bfalse; - - u0 = qnum_from_uint(0u); - i0 = qnum_from_int(0); - d0 = qnum_from_double(0.0); - s0 = qstring_from_str("0"); - s_empty = qstring_new(); - bfalse = qbool_from_bool(false); + g_autoptr(QNum) u0 = qnum_from_uint(0u); + g_autoptr(QNum) i0 = qnum_from_int(0); + g_autoptr(QNum) d0 = qnum_from_double(0.0); + g_autoptr(QString) s0 = qstring_from_str("0"); + g_autoptr(QString) s_empty = qstring_new(); + g_autoptr(QBool) bfalse = qbool_from_bool(false); /* No automatic type conversion */ check_unequal(u0, s0, s_empty, bfalse, qnull(), NULL); check_unequal(i0, s0, s_empty, bfalse, qnull(), NULL); check_unequal(d0, s0, s_empty, bfalse, qnull(), NULL); - - free_all(u0, i0, d0, s0, s_empty, bfalse); } int main(int argc, char **argv) diff --git a/tests/unit/check-qom-proplist.c b/tests/unit/check-qom-proplist.c index ed341088d35f..79d4a8b89d38 100644 --- a/tests/unit/check-qom-proplist.c +++ b/tests/unit/check-qom-proplist.c @@ -27,6 +27,7 @@ #include "qom/object.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/keyval.h" #include "qemu/config-file.h" #include "qom/object_interfaces.h" diff --git a/tests/unit/check-qstring.c b/tests/unit/check-qstring.c index 4bf977209342..bd861f4f8b47 100644 --- a/tests/unit/check-qstring.c +++ b/tests/unit/check-qstring.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/qmp/qstring.h" -#include "qemu-common.h" /* * Public Interface test-cases diff --git a/tests/unit/crypto-tls-psk-helpers.c b/tests/unit/crypto-tls-psk-helpers.c index 7f8a4889610c..c6cc740772ed 100644 --- a/tests/unit/crypto-tls-psk-helpers.c +++ b/tests/unit/crypto-tls-psk-helpers.c @@ -24,18 +24,29 @@ #include "crypto-tls-psk-helpers.h" #include "qemu/sockets.h" -void test_tls_psk_init(const char *pskfile) +static void +test_tls_psk_init_common(const char *pskfile, const char *user, const char *key) { - FILE *fp; + g_autoptr(GError) gerr = NULL; + g_autofree char *line = g_strdup_printf("%s:%s\n", user, key); - fp = fopen(pskfile, "w"); - if (fp == NULL) { - g_critical("Failed to create pskfile %s", pskfile); + g_file_set_contents(pskfile, line, strlen(line), &gerr); + if (gerr != NULL) { + g_critical("Failed to create pskfile %s: %s", pskfile, gerr->message); abort(); } - /* Don't do this in real applications! Use psktool. */ - fprintf(fp, "qemu:009d5638c40fde0c\n"); - fclose(fp); +} + +void test_tls_psk_init(const char *pskfile) +{ + /* Don't hard code a key like this in real applications! Use psktool. */ + test_tls_psk_init_common(pskfile, "qemu", "009d5638c40fde0c"); +} + +void test_tls_psk_init_alt(const char *pskfile) +{ + /* Don't hard code a key like this in real applications! Use psktool. */ + test_tls_psk_init_common(pskfile, "qemu", "10ffa6a2c42f0388"); } void test_tls_psk_cleanup(const char *pskfile) diff --git a/tests/unit/crypto-tls-psk-helpers.h b/tests/unit/crypto-tls-psk-helpers.h index faa645c62948..67f8bdda712c 100644 --- a/tests/unit/crypto-tls-psk-helpers.h +++ b/tests/unit/crypto-tls-psk-helpers.h @@ -24,6 +24,7 @@ #include void test_tls_psk_init(const char *keyfile); +void test_tls_psk_init_alt(const char *keyfile); void test_tls_psk_cleanup(const char *keyfile); #endif diff --git a/tests/unit/crypto-tls-x509-helpers.c b/tests/unit/crypto-tls-x509-helpers.c index fc609b3fd4e1..e9937f60d86d 100644 --- a/tests/unit/crypto-tls-x509-helpers.c +++ b/tests/unit/crypto-tls-x509-helpers.c @@ -168,9 +168,19 @@ test_tls_get_ipaddr(const char *addrstr, hints.ai_flags = AI_NUMERICHOST; g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0); - *datalen = res->ai_addrlen; - *data = g_new(char, *datalen); - memcpy(*data, res->ai_addr, *datalen); + if (res->ai_family == AF_INET) { + struct sockaddr_in *in = (struct sockaddr_in *)res->ai_addr; + *datalen = sizeof(in->sin_addr); + *data = g_new(char, *datalen); + memcpy(*data, &in->sin_addr, *datalen); + } else if (res->ai_family == AF_INET6) { + struct sockaddr_in6 *in = (struct sockaddr_in6 *)res->ai_addr; + *datalen = sizeof(in->sin6_addr); + *data = g_new(char, *datalen); + memcpy(*data, &in->sin6_addr, *datalen); + } else { + g_assert_not_reached(); + } freeaddrinfo(res); } diff --git a/tests/unit/crypto-tls-x509-helpers.h b/tests/unit/crypto-tls-x509-helpers.h index cf6329e6534f..247e7160ebdc 100644 --- a/tests/unit/crypto-tls-x509-helpers.h +++ b/tests/unit/crypto-tls-x509-helpers.h @@ -26,6 +26,9 @@ #include +#define QCRYPTO_TLS_TEST_CLIENT_NAME "ACME QEMU Client" +#define QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME "ACME Hostile Client" + /* * This contains parameter about how to generate * certificates. @@ -118,6 +121,56 @@ void test_tls_cleanup(const char *keyfile); }; \ test_tls_generate_cert(&varname, NULL) +# define TLS_ROOT_REQ_SIMPLE(varname, fname) \ + QCryptoTLSTestCertReq varname = { \ + .filename = fname, \ + .cn = "qemu-CA", \ + .basicConstraintsEnable = true, \ + .basicConstraintsCritical = true, \ + .basicConstraintsIsCA = true, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ + .keyUsageValue = GNUTLS_KEY_KEY_CERT_SIGN, \ + }; \ + test_tls_generate_cert(&varname, NULL) + +# define TLS_CERT_REQ_SIMPLE_CLIENT(varname, cavarname, cname, fname) \ + QCryptoTLSTestCertReq varname = { \ + .filename = fname, \ + .cn = cname, \ + .basicConstraintsEnable = true, \ + .basicConstraintsCritical = true, \ + .basicConstraintsIsCA = false, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ + .keyUsageValue = \ + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \ + .keyPurposeEnable = true, \ + .keyPurposeCritical = true, \ + .keyPurposeOID1 = GNUTLS_KP_TLS_WWW_CLIENT, \ + }; \ + test_tls_generate_cert(&varname, cavarname.crt) + +# define TLS_CERT_REQ_SIMPLE_SERVER(varname, cavarname, fname, \ + hostname, ipaddr) \ + QCryptoTLSTestCertReq varname = { \ + .filename = fname, \ + .cn = hostname ? hostname : ipaddr, \ + .altname1 = hostname, \ + .ipaddr1 = ipaddr, \ + .basicConstraintsEnable = true, \ + .basicConstraintsCritical = true, \ + .basicConstraintsIsCA = false, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ + .keyUsageValue = \ + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \ + .keyPurposeEnable = true, \ + .keyPurposeCritical = true, \ + .keyPurposeOID1 = GNUTLS_KP_TLS_WWW_SERVER, \ + }; \ + test_tls_generate_cert(&varname, cavarname.crt) + extern const asn1_static_node pkix_asn1_tab[]; #endif diff --git a/tests/unit/io-channel-helpers.c b/tests/unit/io-channel-helpers.c index ff156ed3c4a1..c0799c21c233 100644 --- a/tests/unit/io-channel-helpers.c +++ b/tests/unit/io-channel-helpers.c @@ -25,7 +25,6 @@ struct QIOChannelTest { QIOChannel *src; QIOChannel *dst; - bool blocking; size_t len; size_t niov; char *input; @@ -42,8 +41,6 @@ static gpointer test_io_thread_writer(gpointer opaque) { QIOChannelTest *data = opaque; - qio_channel_set_blocking(data->src, data->blocking, NULL); - qio_channel_writev_all(data->src, data->inputv, data->niov, @@ -58,8 +55,6 @@ static gpointer test_io_thread_reader(gpointer opaque) { QIOChannelTest *data = opaque; - qio_channel_set_blocking(data->dst, data->blocking, NULL); - qio_channel_readv_all(data->dst, data->outputv, data->niov, @@ -113,7 +108,9 @@ void qio_channel_test_run_threads(QIOChannelTest *test, test->src = src; test->dst = dst; - test->blocking = blocking; + + qio_channel_set_blocking(test->dst, blocking, NULL); + qio_channel_set_blocking(test->src, blocking, NULL); reader = g_thread_new("reader", test_io_thread_reader, diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 96b295263ea9..ffa444f4323c 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -47,6 +47,7 @@ tests = { 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'], 'test-qapi-util': [], 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-smp.c'], + 'test-interval-tree': [], } if have_system or have_tools @@ -77,7 +78,9 @@ if have_block 'test-crypto-hash': [crypto], 'test-crypto-hmac': [crypto], 'test-crypto-cipher': [crypto], + 'test-crypto-akcipher': [crypto], 'test-crypto-secret': [crypto, keyutils], + 'test-crypto-der': [crypto], 'test-authz-simple': [authz], 'test-authz-list': [authz], 'test-authz-listfile': [authz], @@ -86,6 +89,7 @@ if have_block 'test-io-channel-file': ['io-channel-helpers.c', io], 'test-io-channel-command': ['io-channel-helpers.c', io], 'test-io-channel-buffer': ['io-channel-helpers.c', io], + 'test-io-channel-null': [io], 'test-crypto-ivgen': [io], 'test-crypto-afsplit': [io], 'test-crypto-block': [io], @@ -148,13 +152,13 @@ if have_system endif tests += { - 'test-qdev-global-props': [qom, hwcore, testqapi] + 'test-qdev-global-props': [qom, hwcore] } endif endif -if have_ga and targetos == 'linux' and 'CONFIG_TSAN' not in config_host - tests += {'test-qga': ['../qtest/libqtest.c']} +if have_ga and targetos == 'linux' + tests += {'test-qga': ['../qtest/libqmp.c']} test_deps += {'test-qga': qga} endif diff --git a/tests/unit/ptimer-test.c b/tests/unit/ptimer-test.c index 9176b96c1ce2..04b5f4e3d031 100644 --- a/tests/unit/ptimer-test.c +++ b/tests/unit/ptimer-test.c @@ -768,8 +768,8 @@ static void add_ptimer_tests(uint8_t policy) char policy_name[256] = ""; char *tmp; - if (policy == PTIMER_POLICY_DEFAULT) { - g_sprintf(policy_name, "default"); + if (policy == PTIMER_POLICY_LEGACY) { + g_sprintf(policy_name, "legacy"); } if (policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) { @@ -798,71 +798,71 @@ static void add_ptimer_tests(uint8_t policy) g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/set_count policy=%s", policy_name), - g_memdup(&policy, 1), check_set_count, g_free); + g_memdup2(&policy, 1), check_set_count, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/set_limit policy=%s", policy_name), - g_memdup(&policy, 1), check_set_limit, g_free); + g_memdup2(&policy, 1), check_set_limit, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/oneshot policy=%s", policy_name), - g_memdup(&policy, 1), check_oneshot, g_free); + g_memdup2(&policy, 1), check_oneshot, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/periodic policy=%s", policy_name), - g_memdup(&policy, 1), check_periodic, g_free); + g_memdup2(&policy, 1), check_periodic, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/on_the_fly_mode_change policy=%s", policy_name), - g_memdup(&policy, 1), check_on_the_fly_mode_change, g_free); + g_memdup2(&policy, 1), check_on_the_fly_mode_change, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/on_the_fly_period_change policy=%s", policy_name), - g_memdup(&policy, 1), check_on_the_fly_period_change, g_free); + g_memdup2(&policy, 1), check_on_the_fly_period_change, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/on_the_fly_freq_change policy=%s", policy_name), - g_memdup(&policy, 1), check_on_the_fly_freq_change, g_free); + g_memdup2(&policy, 1), check_on_the_fly_freq_change, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/run_with_period_0 policy=%s", policy_name), - g_memdup(&policy, 1), check_run_with_period_0, g_free); + g_memdup2(&policy, 1), check_run_with_period_0, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/run_with_delta_0 policy=%s", policy_name), - g_memdup(&policy, 1), check_run_with_delta_0, g_free); + g_memdup2(&policy, 1), check_run_with_delta_0, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/periodic_with_load_0 policy=%s", policy_name), - g_memdup(&policy, 1), check_periodic_with_load_0, g_free); + g_memdup2(&policy, 1), check_periodic_with_load_0, g_free); g_free(tmp); g_test_add_data_func_full( tmp = g_strdup_printf("/ptimer/oneshot_with_load_0 policy=%s", policy_name), - g_memdup(&policy, 1), check_oneshot_with_load_0, g_free); + g_memdup2(&policy, 1), check_oneshot_with_load_0, g_free); g_free(tmp); } static void add_all_ptimer_policies_comb_tests(void) { int last_policy = PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT; - int policy = PTIMER_POLICY_DEFAULT; + int policy = PTIMER_POLICY_LEGACY; for (; policy < (last_policy << 1); policy++) { if ((policy & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT) && diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c index ef31664d0224..eecadf3a3c50 100644 --- a/tests/unit/socket-helpers.c +++ b/tests/unit/socket-helpers.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/sockets.h" #include "socket-helpers.h" @@ -89,7 +88,7 @@ static int socket_can_bind_connect(const char *hostname, int family) goto cleanup; } - qemu_set_nonblock(cfd); + qemu_socket_set_nonblock(cfd); if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) { if (errno == EINPROGRESS) { check_soerr = true; @@ -155,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 512a0048118e..ed8477ceb3f1 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 36be84ae55de..8cedea4959d5 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -38,16 +38,26 @@ typedef struct BDRVTestState { bool sleep_in_drain_begin; } BDRVTestState; -static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) +static void coroutine_fn sleep_in_drain_begin(void *opaque) +{ + BlockDriverState *bs = opaque; + + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); + bdrv_dec_in_flight(bs); +} + +static void bdrv_test_drain_begin(BlockDriverState *bs) { BDRVTestState *s = bs->opaque; s->drain_count++; if (s->sleep_in_drain_begin) { - qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); + Coroutine *co = qemu_coroutine_create(sleep_in_drain_begin, bs); + bdrv_inc_in_flight(bs); + aio_co_enter(bdrv_get_aio_context(bs), co); } } -static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs) +static void bdrv_test_drain_end(BlockDriverState *bs) { BDRVTestState *s = bs->opaque; s->drain_count--; @@ -101,8 +111,8 @@ static BlockDriver bdrv_test = { .bdrv_close = bdrv_test_close, .bdrv_co_preadv = bdrv_test_co_preadv, - .bdrv_co_drain_begin = bdrv_test_co_drain_begin, - .bdrv_co_drain_end = bdrv_test_co_drain_end, + .bdrv_drain_begin = bdrv_test_drain_begin, + .bdrv_drain_end = bdrv_test_drain_end, .bdrv_child_perm = bdrv_default_perms, @@ -146,7 +156,6 @@ static void call_in_coroutine(void (*entry)(void)) enum drain_type { BDRV_DRAIN_ALL, BDRV_DRAIN, - BDRV_SUBTREE_DRAIN, DRAIN_TYPE_MAX, }; @@ -155,7 +164,6 @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) switch (drain_type) { case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; case BDRV_DRAIN: bdrv_drained_begin(bs); break; - case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break; default: g_assert_not_reached(); } } @@ -165,7 +173,6 @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) switch (drain_type) { case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; case BDRV_DRAIN: bdrv_drained_end(bs); break; - case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break; default: g_assert_not_reached(); } } @@ -261,11 +268,6 @@ static void test_drv_cb_drain(void) test_drv_cb_common(BDRV_DRAIN, false); } -static void test_drv_cb_drain_subtree(void) -{ - test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); -} - static void test_drv_cb_co_drain_all(void) { call_in_coroutine(test_drv_cb_drain_all); @@ -276,11 +278,6 @@ static void test_drv_cb_co_drain(void) call_in_coroutine(test_drv_cb_drain); } -static void test_drv_cb_co_drain_subtree(void) -{ - call_in_coroutine(test_drv_cb_drain_subtree); -} - static void test_quiesce_common(enum drain_type drain_type, bool recursive) { BlockBackend *blk; @@ -299,7 +296,11 @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive) do_drain_begin(drain_type, bs); - g_assert_cmpint(bs->quiesce_counter, ==, 1); + if (drain_type == BDRV_DRAIN_ALL) { + g_assert_cmpint(bs->quiesce_counter, ==, 2); + } else { + g_assert_cmpint(bs->quiesce_counter, ==, 1); + } g_assert_cmpint(backing->quiesce_counter, ==, !!recursive); do_drain_end(drain_type, bs); @@ -322,11 +323,6 @@ static void test_quiesce_drain(void) test_quiesce_common(BDRV_DRAIN, false); } -static void test_quiesce_drain_subtree(void) -{ - test_quiesce_common(BDRV_SUBTREE_DRAIN, true); -} - static void test_quiesce_co_drain_all(void) { call_in_coroutine(test_quiesce_drain_all); @@ -337,11 +333,6 @@ static void test_quiesce_co_drain(void) call_in_coroutine(test_quiesce_drain); } -static void test_quiesce_co_drain_subtree(void) -{ - call_in_coroutine(test_quiesce_drain_subtree); -} - static void test_nested(void) { BlockBackend *blk; @@ -361,8 +352,8 @@ static void test_nested(void) for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) { for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) { - int backing_quiesce = (outer != BDRV_DRAIN) + - (inner != BDRV_DRAIN); + int backing_quiesce = (outer == BDRV_DRAIN_ALL) + + (inner == BDRV_DRAIN_ALL); g_assert_cmpint(bs->quiesce_counter, ==, 0); g_assert_cmpint(backing->quiesce_counter, ==, 0); @@ -372,10 +363,10 @@ static void test_nested(void) do_drain_begin(outer, bs); do_drain_begin(inner, bs); - g_assert_cmpint(bs->quiesce_counter, ==, 2); + g_assert_cmpint(bs->quiesce_counter, ==, 2 + !!backing_quiesce); g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce); - g_assert_cmpint(s->drain_count, ==, 2); - g_assert_cmpint(backing_s->drain_count, ==, backing_quiesce); + g_assert_cmpint(s->drain_count, ==, 1); + g_assert_cmpint(backing_s->drain_count, ==, !!backing_quiesce); do_drain_end(inner, bs); do_drain_end(outer, bs); @@ -392,158 +383,6 @@ static void test_nested(void) blk_unref(blk); } -static void test_multiparent(void) -{ - BlockBackend *blk_a, *blk_b; - BlockDriverState *bs_a, *bs_b, *backing; - BDRVTestState *a_s, *b_s, *backing_s; - - blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); - bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, - &error_abort); - a_s = bs_a->opaque; - blk_insert_bs(blk_a, bs_a, &error_abort); - - blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); - bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, - &error_abort); - b_s = bs_b->opaque; - blk_insert_bs(blk_b, bs_b, &error_abort); - - backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); - backing_s = backing->opaque; - bdrv_set_backing_hd(bs_a, backing, &error_abort); - bdrv_set_backing_hd(bs_b, backing, &error_abort); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 0); - g_assert_cmpint(bs_b->quiesce_counter, ==, 0); - g_assert_cmpint(backing->quiesce_counter, ==, 0); - g_assert_cmpint(a_s->drain_count, ==, 0); - g_assert_cmpint(b_s->drain_count, ==, 0); - g_assert_cmpint(backing_s->drain_count, ==, 0); - - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 1); - g_assert_cmpint(bs_b->quiesce_counter, ==, 1); - g_assert_cmpint(backing->quiesce_counter, ==, 1); - g_assert_cmpint(a_s->drain_count, ==, 1); - g_assert_cmpint(b_s->drain_count, ==, 1); - g_assert_cmpint(backing_s->drain_count, ==, 1); - - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 2); - g_assert_cmpint(bs_b->quiesce_counter, ==, 2); - g_assert_cmpint(backing->quiesce_counter, ==, 2); - g_assert_cmpint(a_s->drain_count, ==, 2); - g_assert_cmpint(b_s->drain_count, ==, 2); - g_assert_cmpint(backing_s->drain_count, ==, 2); - - do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 1); - g_assert_cmpint(bs_b->quiesce_counter, ==, 1); - g_assert_cmpint(backing->quiesce_counter, ==, 1); - g_assert_cmpint(a_s->drain_count, ==, 1); - g_assert_cmpint(b_s->drain_count, ==, 1); - g_assert_cmpint(backing_s->drain_count, ==, 1); - - do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 0); - g_assert_cmpint(bs_b->quiesce_counter, ==, 0); - g_assert_cmpint(backing->quiesce_counter, ==, 0); - g_assert_cmpint(a_s->drain_count, ==, 0); - g_assert_cmpint(b_s->drain_count, ==, 0); - g_assert_cmpint(backing_s->drain_count, ==, 0); - - bdrv_unref(backing); - bdrv_unref(bs_a); - bdrv_unref(bs_b); - blk_unref(blk_a); - blk_unref(blk_b); -} - -static void test_graph_change_drain_subtree(void) -{ - BlockBackend *blk_a, *blk_b; - BlockDriverState *bs_a, *bs_b, *backing; - BDRVTestState *a_s, *b_s, *backing_s; - - blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); - bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, - &error_abort); - a_s = bs_a->opaque; - blk_insert_bs(blk_a, bs_a, &error_abort); - - blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); - bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, - &error_abort); - b_s = bs_b->opaque; - blk_insert_bs(blk_b, bs_b, &error_abort); - - backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); - backing_s = backing->opaque; - bdrv_set_backing_hd(bs_a, backing, &error_abort); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 0); - g_assert_cmpint(bs_b->quiesce_counter, ==, 0); - g_assert_cmpint(backing->quiesce_counter, ==, 0); - g_assert_cmpint(a_s->drain_count, ==, 0); - g_assert_cmpint(b_s->drain_count, ==, 0); - g_assert_cmpint(backing_s->drain_count, ==, 0); - - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); - do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); - - bdrv_set_backing_hd(bs_b, backing, &error_abort); - g_assert_cmpint(bs_a->quiesce_counter, ==, 5); - g_assert_cmpint(bs_b->quiesce_counter, ==, 5); - g_assert_cmpint(backing->quiesce_counter, ==, 5); - g_assert_cmpint(a_s->drain_count, ==, 5); - g_assert_cmpint(b_s->drain_count, ==, 5); - g_assert_cmpint(backing_s->drain_count, ==, 5); - - bdrv_set_backing_hd(bs_b, NULL, &error_abort); - g_assert_cmpint(bs_a->quiesce_counter, ==, 3); - g_assert_cmpint(bs_b->quiesce_counter, ==, 2); - g_assert_cmpint(backing->quiesce_counter, ==, 3); - g_assert_cmpint(a_s->drain_count, ==, 3); - g_assert_cmpint(b_s->drain_count, ==, 2); - g_assert_cmpint(backing_s->drain_count, ==, 3); - - bdrv_set_backing_hd(bs_b, backing, &error_abort); - g_assert_cmpint(bs_a->quiesce_counter, ==, 5); - g_assert_cmpint(bs_b->quiesce_counter, ==, 5); - g_assert_cmpint(backing->quiesce_counter, ==, 5); - g_assert_cmpint(a_s->drain_count, ==, 5); - g_assert_cmpint(b_s->drain_count, ==, 5); - g_assert_cmpint(backing_s->drain_count, ==, 5); - - do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); - do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); - do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); - do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); - do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); - - g_assert_cmpint(bs_a->quiesce_counter, ==, 0); - g_assert_cmpint(bs_b->quiesce_counter, ==, 0); - g_assert_cmpint(backing->quiesce_counter, ==, 0); - g_assert_cmpint(a_s->drain_count, ==, 0); - g_assert_cmpint(b_s->drain_count, ==, 0); - g_assert_cmpint(backing_s->drain_count, ==, 0); - - bdrv_unref(backing); - bdrv_unref(bs_a); - bdrv_unref(bs_b); - blk_unref(blk_a); - blk_unref(blk_b); -} - static void test_graph_change_drain_all(void) { BlockBackend *blk_a, *blk_b; @@ -763,12 +602,6 @@ static void test_iothread_drain(void) test_iothread_common(BDRV_DRAIN, 1); } -static void test_iothread_drain_subtree(void) -{ - test_iothread_common(BDRV_SUBTREE_DRAIN, 0); - test_iothread_common(BDRV_SUBTREE_DRAIN, 1); -} - typedef struct TestBlockJob { BlockJob common; @@ -853,7 +686,6 @@ enum test_job_result { enum test_job_drain_node { TEST_JOB_DRAIN_SRC, TEST_JOB_DRAIN_SRC_CHILD, - TEST_JOB_DRAIN_SRC_PARENT, }; static void test_blockjob_common_drain_node(enum drain_type drain_type, @@ -891,9 +723,6 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, case TEST_JOB_DRAIN_SRC_CHILD: drain_bs = src_backing; break; - case TEST_JOB_DRAIN_SRC_PARENT: - drain_bs = src_overlay; - break; default: g_assert_not_reached(); } @@ -930,9 +759,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 +772,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()); @@ -1023,10 +874,6 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, TEST_JOB_DRAIN_SRC); test_blockjob_common_drain_node(drain_type, use_iothread, result, TEST_JOB_DRAIN_SRC_CHILD); - if (drain_type == BDRV_SUBTREE_DRAIN) { - test_blockjob_common_drain_node(drain_type, use_iothread, result, - TEST_JOB_DRAIN_SRC_PARENT); - } } static void test_blockjob_drain_all(void) @@ -1039,11 +886,6 @@ static void test_blockjob_drain(void) test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_SUCCESS); } -static void test_blockjob_drain_subtree(void) -{ - test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_SUCCESS); -} - static void test_blockjob_error_drain_all(void) { test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_FAIL_RUN); @@ -1056,12 +898,6 @@ static void test_blockjob_error_drain(void) test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_FAIL_PREPARE); } -static void test_blockjob_error_drain_subtree(void) -{ - test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_RUN); - test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_PREPARE); -} - static void test_blockjob_iothread_drain_all(void) { test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_SUCCESS); @@ -1072,11 +908,6 @@ static void test_blockjob_iothread_drain(void) test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_SUCCESS); } -static void test_blockjob_iothread_drain_subtree(void) -{ - test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_SUCCESS); -} - static void test_blockjob_iothread_error_drain_all(void) { test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_FAIL_RUN); @@ -1089,12 +920,6 @@ static void test_blockjob_iothread_error_drain(void) test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_FAIL_PREPARE); } -static void test_blockjob_iothread_error_drain_subtree(void) -{ - test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_RUN); - test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_PREPARE); -} - typedef struct BDRVTestTopState { BdrvChild *wait_child; @@ -1241,14 +1066,6 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, bdrv_drain(child_bs); bdrv_unref(child_bs); break; - case BDRV_SUBTREE_DRAIN: - /* Would have to ref/unref bs here for !detach_instead_of_delete, but - * then the whole test becomes pointless because the graph changes - * don't occur during the drain any more. */ - assert(detach_instead_of_delete); - bdrv_subtree_drained_begin(bs); - bdrv_subtree_drained_end(bs); - break; case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); bdrv_drain_all_end(); @@ -1283,11 +1100,6 @@ static void test_detach_by_drain(void) do_test_delete_by_drain(true, BDRV_DRAIN); } -static void test_detach_by_drain_subtree(void) -{ - do_test_delete_by_drain(true, BDRV_SUBTREE_DRAIN); -} - struct detach_by_parent_data { BlockDriverState *parent_b; @@ -1295,6 +1107,7 @@ struct detach_by_parent_data { BlockDriverState *c; BdrvChild *child_c; bool by_parent_cb; + bool detach_on_drain; }; static struct detach_by_parent_data detach_by_parent_data; @@ -1302,6 +1115,7 @@ static void detach_indirect_bh(void *opaque) { struct detach_by_parent_data *data = opaque; + bdrv_dec_in_flight(data->child_b->bs); bdrv_unref_child(data->parent_b, data->child_b); bdrv_ref(data->c); @@ -1316,12 +1130,21 @@ static void detach_by_parent_aio_cb(void *opaque, int ret) g_assert_cmpint(ret, ==, 0); if (data->by_parent_cb) { + bdrv_inc_in_flight(data->child_b->bs); detach_indirect_bh(data); } } static void detach_by_driver_cb_drained_begin(BdrvChild *child) { + struct detach_by_parent_data *data = &detach_by_parent_data; + + if (!data->detach_on_drain) { + return; + } + data->detach_on_drain = false; + + bdrv_inc_in_flight(data->child_b->bs); aio_bh_schedule_oneshot(qemu_get_current_aio_context(), detach_indirect_bh, &detach_by_parent_data); child_of_bds.drained_begin(child); @@ -1362,8 +1185,14 @@ static void test_detach_indirect(bool by_parent_cb) detach_by_driver_cb_class = child_of_bds; detach_by_driver_cb_class.drained_begin = detach_by_driver_cb_drained_begin; + detach_by_driver_cb_class.drained_end = NULL; + detach_by_driver_cb_class.drained_poll = NULL; } + detach_by_parent_data = (struct detach_by_parent_data) { + .detach_on_drain = false, + }; + /* Create all involved nodes */ parent_a = bdrv_new_open_driver(&bdrv_test, "parent-a", BDRV_O_RDWR, &error_abort); @@ -1415,12 +1244,16 @@ static void test_detach_indirect(bool by_parent_cb) .child_b = child_b, .c = c, .by_parent_cb = by_parent_cb, + .detach_on_drain = true, }; acb = blk_aio_preadv(blk, 0, &qiov, 0, detach_by_parent_aio_cb, NULL); g_assert(acb != NULL); /* Drain and check the expected result */ - bdrv_subtree_drained_begin(parent_b); + bdrv_drained_begin(parent_b); + bdrv_drained_begin(a); + bdrv_drained_begin(b); + bdrv_drained_begin(c); g_assert(detach_by_parent_data.child_c != NULL); @@ -1435,12 +1268,15 @@ static void test_detach_indirect(bool by_parent_cb) g_assert(QLIST_NEXT(child_a, next) == NULL); g_assert_cmpint(parent_a->quiesce_counter, ==, 1); - g_assert_cmpint(parent_b->quiesce_counter, ==, 1); + g_assert_cmpint(parent_b->quiesce_counter, ==, 3); g_assert_cmpint(a->quiesce_counter, ==, 1); - g_assert_cmpint(b->quiesce_counter, ==, 0); + g_assert_cmpint(b->quiesce_counter, ==, 1); g_assert_cmpint(c->quiesce_counter, ==, 1); - bdrv_subtree_drained_end(parent_b); + bdrv_drained_end(parent_b); + bdrv_drained_end(a); + bdrv_drained_end(b); + bdrv_drained_end(c); bdrv_unref(parent_b); blk_unref(blk); @@ -1516,16 +1352,16 @@ static void test_set_aio_context(void) &error_abort); bdrv_drained_begin(bs); - bdrv_try_set_aio_context(bs, ctx_a, &error_abort); + bdrv_try_change_aio_context(bs, ctx_a, NULL, &error_abort); aio_context_acquire(ctx_a); bdrv_drained_end(bs); bdrv_drained_begin(bs); - bdrv_try_set_aio_context(bs, ctx_b, &error_abort); + bdrv_try_change_aio_context(bs, ctx_b, NULL, &error_abort); aio_context_release(ctx_a); aio_context_acquire(ctx_b); - bdrv_try_set_aio_context(bs, qemu_get_aio_context(), &error_abort); + bdrv_try_change_aio_context(bs, qemu_get_aio_context(), NULL, &error_abort); aio_context_release(ctx_b); bdrv_drained_end(bs); @@ -1671,6 +1507,7 @@ static void test_blockjob_commit_by_drained_end(void) bdrv_drained_begin(bs_child); g_assert(!job_has_completed); bdrv_drained_end(bs_child); + aio_poll(qemu_get_aio_context(), false); g_assert(job_has_completed); bdrv_unref(bs_parents[0]); @@ -1808,9 +1645,8 @@ static void test_drop_intermediate_poll(void) for (i = 0; i < 3; i++) { if (i) { /* Takes the reference to chain[i - 1] */ - chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], - "chain", &chain_child_class, - BDRV_CHILD_COW, &error_abort); + bdrv_attach_child(chain[i], chain[i - 1], "chain", + &chain_child_class, BDRV_CHILD_COW, &error_abort); } } @@ -1827,6 +1663,7 @@ static void test_drop_intermediate_poll(void) g_assert(!job_has_completed); ret = bdrv_drop_intermediate(chain[1], chain[0], NULL); + aio_poll(qemu_get_aio_context(), false); g_assert(ret == 0); g_assert(job_has_completed); @@ -1835,6 +1672,7 @@ static void test_drop_intermediate_poll(void) typedef struct BDRVReplaceTestState { + bool setup_completed; bool was_drained; bool was_undrained; bool has_read; @@ -1895,52 +1733,78 @@ static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs, return 0; } +static void coroutine_fn bdrv_replace_test_drain_co(void *opaque) +{ + BlockDriverState *bs = opaque; + BDRVReplaceTestState *s = bs->opaque; + + /* Keep waking io_co up until it is done */ + while (s->io_co) { + aio_co_wake(s->io_co); + s->io_co = NULL; + qemu_coroutine_yield(); + } + s->drain_co = NULL; + bdrv_dec_in_flight(bs); +} + /** * If .drain_count is 0, wake up .io_co if there is one; and set * .was_drained. * Increment .drain_count. */ -static void coroutine_fn bdrv_replace_test_co_drain_begin(BlockDriverState *bs) +static void bdrv_replace_test_drain_begin(BlockDriverState *bs) { BDRVReplaceTestState *s = bs->opaque; - if (!s->drain_count) { - /* Keep waking io_co up until it is done */ - s->drain_co = qemu_coroutine_self(); - while (s->io_co) { - aio_co_wake(s->io_co); - s->io_co = NULL; - qemu_coroutine_yield(); - } - s->drain_co = NULL; + if (!s->setup_completed) { + return; + } + if (!s->drain_count) { + s->drain_co = qemu_coroutine_create(bdrv_replace_test_drain_co, bs); + bdrv_inc_in_flight(bs); + aio_co_enter(bdrv_get_aio_context(bs), s->drain_co); s->was_drained = true; } s->drain_count++; } +static void coroutine_fn bdrv_replace_test_read_entry(void *opaque) +{ + BlockDriverState *bs = opaque; + char data; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1); + int ret; + + /* Queue a read request post-drain */ + ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0); + g_assert(ret >= 0); + bdrv_dec_in_flight(bs); +} + /** * Reduce .drain_count, set .was_undrained once it reaches 0. * If .drain_count reaches 0 and the node has a backing file, issue a * read request. */ -static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs) +static void bdrv_replace_test_drain_end(BlockDriverState *bs) { BDRVReplaceTestState *s = bs->opaque; + if (!s->setup_completed) { + return; + } + g_assert(s->drain_count > 0); if (!--s->drain_count) { - int ret; - s->was_undrained = true; if (bs->backing) { - char data; - QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1); - - /* Queue a read request post-drain */ - ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0); - g_assert(ret >= 0); + Coroutine *co = qemu_coroutine_create(bdrv_replace_test_read_entry, + bs); + bdrv_inc_in_flight(bs); + aio_co_enter(bdrv_get_aio_context(bs), co); } } } @@ -1948,12 +1812,13 @@ static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs) static BlockDriver bdrv_replace_test = { .format_name = "replace_test", .instance_size = sizeof(BDRVReplaceTestState), + .supports_backing = true, .bdrv_close = bdrv_replace_test_close, .bdrv_co_preadv = bdrv_replace_test_co_preadv, - .bdrv_co_drain_begin = bdrv_replace_test_co_drain_begin, - .bdrv_co_drain_end = bdrv_replace_test_co_drain_end, + .bdrv_drain_begin = bdrv_replace_test_drain_begin, + .bdrv_drain_end = bdrv_replace_test_drain_end, .bdrv_child_perm = bdrv_default_perms, }; @@ -2027,9 +1892,9 @@ static void do_test_replace_child_mid_drain(int old_drain_count, new_child_bs->total_sectors = 1; bdrv_ref(old_child_bs); - parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child", - &child_of_bds, BDRV_CHILD_COW, - &error_abort); + bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds, + BDRV_CHILD_COW, &error_abort); + parent_s->setup_completed = true; for (i = 0; i < old_drain_count; i++) { bdrv_drained_begin(old_child_bs); @@ -2151,70 +2016,47 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); - g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", - test_drv_cb_drain_subtree); g_test_add_func("/bdrv-drain/driver-cb/co/drain_all", test_drv_cb_co_drain_all); g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain); - g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree", - test_drv_cb_co_drain_subtree); - g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); - g_test_add_func("/bdrv-drain/quiesce/drain_subtree", - test_quiesce_drain_subtree); g_test_add_func("/bdrv-drain/quiesce/co/drain_all", test_quiesce_co_drain_all); g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain); - g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree", - test_quiesce_co_drain_subtree); g_test_add_func("/bdrv-drain/nested", test_nested); - g_test_add_func("/bdrv-drain/multiparent", test_multiparent); - g_test_add_func("/bdrv-drain/graph-change/drain_subtree", - test_graph_change_drain_subtree); g_test_add_func("/bdrv-drain/graph-change/drain_all", test_graph_change_drain_all); g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all); g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain); - g_test_add_func("/bdrv-drain/iothread/drain_subtree", - test_iothread_drain_subtree); g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); - g_test_add_func("/bdrv-drain/blockjob/drain_subtree", - test_blockjob_drain_subtree); g_test_add_func("/bdrv-drain/blockjob/error/drain_all", test_blockjob_error_drain_all); g_test_add_func("/bdrv-drain/blockjob/error/drain", test_blockjob_error_drain); - g_test_add_func("/bdrv-drain/blockjob/error/drain_subtree", - test_blockjob_error_drain_subtree); g_test_add_func("/bdrv-drain/blockjob/iothread/drain_all", test_blockjob_iothread_drain_all); g_test_add_func("/bdrv-drain/blockjob/iothread/drain", test_blockjob_iothread_drain); - g_test_add_func("/bdrv-drain/blockjob/iothread/drain_subtree", - test_blockjob_iothread_drain_subtree); g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_all", test_blockjob_iothread_error_drain_all); g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain", test_blockjob_iothread_error_drain); - g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_subtree", - test_blockjob_iothread_error_drain_subtree); g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all); g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); - g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree); g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb); g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb); diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index a6e3bb79be25..c52259153169 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -26,6 +26,8 @@ static BlockDriver bdrv_pass_through = { .format_name = "pass-through", + .is_filter = true, + .filtered_child_is_backing = true, .bdrv_child_perm = bdrv_default_perms, }; @@ -57,6 +59,8 @@ static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c, static BlockDriver bdrv_exclusive_writer = { .format_name = "exclusive-writer", + .is_filter = true, + .filtered_child_is_backing = true, .bdrv_child_perm = exclusive_write_perms, }; @@ -134,7 +138,7 @@ static void test_update_perm_tree(void) blk_insert_bs(root, bs, &error_abort); bdrv_attach_child(filter, bs, "child", &child_of_bds, - BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); + BDRV_CHILD_DATA, &error_abort); ret = bdrv_append(filter, bs, NULL); g_assert_cmpint(ret, <, 0); @@ -228,11 +232,14 @@ static void test_parallel_exclusive_write(void) */ bdrv_ref(base); - bdrv_attach_child(top, fl1, "backing", &child_of_bds, BDRV_CHILD_DATA, + bdrv_attach_child(top, fl1, "backing", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); - bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + bdrv_attach_child(fl1, base, "backing", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); - bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + bdrv_attach_child(fl2, base, "backing", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); bdrv_replace_node(fl1, fl2, &error_abort); @@ -241,13 +248,26 @@ static void test_parallel_exclusive_write(void) bdrv_unref(top); } -static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c, - BdrvChildRole role, - BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) +/* + * write-to-selected node may have several DATA children, one of them may be + * "selected". Exclusive write permission is taken on selected child. + * + * We don't realize write handler itself, as we need only to test how permission + * update works. + */ +typedef struct BDRVWriteToSelectedState { + BdrvChild *selected; +} BDRVWriteToSelectedState; + +static void write_to_selected_perms(BlockDriverState *bs, BdrvChild *c, + BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) { - if (bs->file && c == bs->file) { + BDRVWriteToSelectedState *s = bs->opaque; + + if (s->selected && c == s->selected) { *nperm = BLK_PERM_WRITE; *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE; } else { @@ -256,9 +276,10 @@ static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c, } } -static BlockDriver bdrv_write_to_file = { - .format_name = "tricky-perm", - .bdrv_child_perm = write_to_file_perms, +static BlockDriver bdrv_write_to_selected = { + .format_name = "write-to-selected", + .instance_size = sizeof(BDRVWriteToSelectedState), + .bdrv_child_perm = write_to_selected_perms, }; @@ -266,15 +287,18 @@ static BlockDriver bdrv_write_to_file = { * The following test shows that topological-sort order is required for * permission update, simple DFS is not enough. * - * Consider the block driver which has two filter children: one active - * with exclusive write access and one inactive with no specific - * permissions. + * Consider the block driver (write-to-selected) which has two children: one is + * selected so we have exclusive write access to it and for the other one we + * don't need any specific permissions. * * And, these two children has a common base child, like this: + * (additional "top" on top is used in test just because the only public + * function to update permission should get a specific child to update. + * Making bdrv_refresh_perms() public just for this test isn't worth it) * - * ┌─────┐ ┌──────┐ - * │ fl2 │ ◀── │ top │ - * └─────┘ └──────┘ + * ┌─────┐ ┌───────────────────┐ ┌─────┐ + * │ fl2 │ ◀── │ write-to-selected │ ◀── │ top │ + * └─────┘ └───────────────────┘ └─────┘ * │ │ * │ │ w * │ ▼ @@ -290,14 +314,14 @@ static BlockDriver bdrv_write_to_file = { * * So, exclusive write is propagated. * - * Assume, we want to make fl2 active instead of fl1. - * So, we set some option for top driver and do permission update. + * Assume, we want to select fl2 instead of fl1. + * So, we set some option for write-to-selected driver and do permission update. * * With simple DFS, if permission update goes first through - * top->fl1->base branch it will succeed: it firstly drop exclusive write - * permissions and than apply them for another BdrvChildren. - * But if permission update goes first through top->fl2->base branch it - * will fail, as when we try to update fl2->base child, old not yet + * write-to-selected -> fl1 -> base branch it will succeed: it firstly drop + * exclusive write permissions and than apply them for another BdrvChildren. + * But if permission update goes first through write-to-selected -> fl2 -> base + * branch it will fail, as when we try to update fl2->base child, old not yet * updated fl1->base child will be in conflict. * * With topological-sort order we always update parents before children, so fl1 @@ -306,9 +330,10 @@ static BlockDriver bdrv_write_to_file = { static void test_parallel_perm_update(void) { BlockDriverState *top = no_perm_node("top"); - BlockDriverState *tricky = - bdrv_new_open_driver(&bdrv_write_to_file, "tricky", BDRV_O_RDWR, + BlockDriverState *ws = + bdrv_new_open_driver(&bdrv_write_to_selected, "ws", BDRV_O_RDWR, &error_abort); + BDRVWriteToSelectedState *s = ws->opaque; BlockDriverState *base = no_perm_node("base"); BlockDriverState *fl1 = pass_through_node("fl1"); BlockDriverState *fl2 = pass_through_node("fl2"); @@ -320,33 +345,35 @@ static void test_parallel_perm_update(void) */ bdrv_ref(base); - bdrv_attach_child(top, tricky, "file", &child_of_bds, BDRV_CHILD_DATA, + bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA, &error_abort); - c_fl1 = bdrv_attach_child(tricky, fl1, "first", &child_of_bds, - BDRV_CHILD_FILTERED, &error_abort); - c_fl2 = bdrv_attach_child(tricky, fl2, "second", &child_of_bds, - BDRV_CHILD_FILTERED, &error_abort); - bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds, + BDRV_CHILD_DATA, &error_abort); + c_fl2 = bdrv_attach_child(ws, fl2, "second", &child_of_bds, + BDRV_CHILD_DATA, &error_abort); + bdrv_attach_child(fl1, base, "backing", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); - bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + bdrv_attach_child(fl2, base, "backing", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); /* Select fl1 as first child to be active */ - tricky->file = c_fl1; + s->selected = c_fl1; bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); assert(c_fl1->perm & BLK_PERM_WRITE); assert(!(c_fl2->perm & BLK_PERM_WRITE)); /* Now, try to switch active child and update permissions */ - tricky->file = c_fl2; + s->selected = c_fl2; bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); assert(c_fl2->perm & BLK_PERM_WRITE); assert(!(c_fl1->perm & BLK_PERM_WRITE)); /* Switch once more, to not care about real child order in the list */ - tricky->file = c_fl1; + s->selected = c_fl1; bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); assert(c_fl1->perm & BLK_PERM_WRITE); @@ -379,7 +406,8 @@ static void test_append_greedy_filter(void) BlockDriverState *base = no_perm_node("base"); BlockDriverState *fl = exclusive_writer_node("fl1"); - bdrv_attach_child(top, base, "backing", &child_of_bds, BDRV_CHILD_COW, + bdrv_attach_child(top, base, "backing", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); bdrv_append(fl, base, &error_abort); diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 94718c9319b5..8ca5adec5e82 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -88,11 +88,11 @@ static void test_sync_op_pread(BdrvChild *c) int ret; /* Success */ - ret = bdrv_pread(c, 0, buf, sizeof(buf)); - g_assert_cmpint(ret, ==, 512); + ret = bdrv_pread(c, 0, sizeof(buf), buf, 0); + g_assert_cmpint(ret, ==, 0); /* Early error: Negative offset */ - ret = bdrv_pread(c, -2, buf, sizeof(buf)); + ret = bdrv_pread(c, -2, sizeof(buf), buf, 0); g_assert_cmpint(ret, ==, -EIO); } @@ -102,11 +102,11 @@ static void test_sync_op_pwrite(BdrvChild *c) int ret; /* Success */ - ret = bdrv_pwrite(c, 0, buf, sizeof(buf)); - g_assert_cmpint(ret, ==, 512); + ret = bdrv_pwrite(c, 0, sizeof(buf), buf, 0); + g_assert_cmpint(ret, ==, 0); /* Early error: Negative offset */ - ret = bdrv_pwrite(c, -2, buf, sizeof(buf)); + ret = bdrv_pwrite(c, -2, sizeof(buf), buf, 0); g_assert_cmpint(ret, ==, -EIO); } @@ -116,11 +116,11 @@ static void test_sync_op_blk_pread(BlockBackend *blk) int ret; /* Success */ - ret = blk_pread(blk, 0, buf, sizeof(buf)); - g_assert_cmpint(ret, ==, 512); + ret = blk_pread(blk, 0, sizeof(buf), buf, 0); + g_assert_cmpint(ret, ==, 0); /* Early error: Negative offset */ - ret = blk_pread(blk, -2, buf, sizeof(buf)); + ret = blk_pread(blk, -2, sizeof(buf), buf, 0); g_assert_cmpint(ret, ==, -EIO); } @@ -130,11 +130,98 @@ static void test_sync_op_blk_pwrite(BlockBackend *blk) int ret; /* Success */ - ret = blk_pwrite(blk, 0, buf, sizeof(buf), 0); - g_assert_cmpint(ret, ==, 512); + ret = blk_pwrite(blk, 0, sizeof(buf), buf, 0); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_pwrite(blk, -2, sizeof(buf), buf, 0); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_preadv(BlockBackend *blk) +{ + uint8_t buf[512]; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf)); + int ret; + + /* Success */ + ret = blk_preadv(blk, 0, sizeof(buf), &qiov, 0); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_preadv(blk, -2, sizeof(buf), &qiov, 0); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pwritev(BlockBackend *blk) +{ + uint8_t buf[512] = { 0 }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf)); + int ret; + + /* Success */ + ret = blk_pwritev(blk, 0, sizeof(buf), &qiov, 0); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_pwritev(blk, -2, sizeof(buf), &qiov, 0); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_preadv_part(BlockBackend *blk) +{ + uint8_t buf[512]; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf)); + int ret; + + /* Success */ + ret = blk_preadv_part(blk, 0, sizeof(buf), &qiov, 0, 0); + g_assert_cmpint(ret, ==, 0); /* Early error: Negative offset */ - ret = blk_pwrite(blk, -2, buf, sizeof(buf), 0); + ret = blk_preadv_part(blk, -2, sizeof(buf), &qiov, 0, 0); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pwritev_part(BlockBackend *blk) +{ + uint8_t buf[512] = { 0 }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf)); + int ret; + + /* Success */ + ret = blk_pwritev_part(blk, 0, sizeof(buf), &qiov, 0, 0); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_pwritev_part(blk, -2, sizeof(buf), &qiov, 0, 0); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pwrite_compressed(BlockBackend *blk) +{ + uint8_t buf[512] = { 0 }; + int ret; + + /* Late error: Not supported */ + ret = blk_pwrite_compressed(blk, 0, sizeof(buf), buf); + g_assert_cmpint(ret, ==, -ENOTSUP); + + /* Early error: Negative offset */ + ret = blk_pwrite_compressed(blk, -2, sizeof(buf), buf); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pwrite_zeroes(BlockBackend *blk) +{ + int ret; + + /* Success */ + ret = blk_pwrite_zeroes(blk, 0, 512, 0); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_pwrite_zeroes(blk, -2, 512, 0); g_assert_cmpint(ret, ==, -EIO); } @@ -211,6 +298,19 @@ static void test_sync_op_truncate(BdrvChild *c) c->bs->open_flags |= BDRV_O_RDWR; } +static void test_sync_op_blk_truncate(BlockBackend *blk) +{ + int ret; + + /* Normal success path */ + ret = blk_truncate(blk, 65536, false, PREALLOC_MODE_OFF, 0, NULL); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_truncate(blk, -2, false, PREALLOC_MODE_OFF, 0, NULL); + g_assert_cmpint(ret, ==, -EINVAL); +} + static void test_sync_op_block_status(BdrvChild *c) { int ret; @@ -301,6 +401,30 @@ const SyncOpTest sync_op_tests[] = { .name = "/sync-op/pwrite", .fn = test_sync_op_pwrite, .blkfn = test_sync_op_blk_pwrite, + }, { + .name = "/sync-op/preadv", + .fn = NULL, + .blkfn = test_sync_op_blk_preadv, + }, { + .name = "/sync-op/pwritev", + .fn = NULL, + .blkfn = test_sync_op_blk_pwritev, + }, { + .name = "/sync-op/preadv_part", + .fn = NULL, + .blkfn = test_sync_op_blk_preadv_part, + }, { + .name = "/sync-op/pwritev_part", + .fn = NULL, + .blkfn = test_sync_op_blk_pwritev_part, + }, { + .name = "/sync-op/pwrite_compressed", + .fn = NULL, + .blkfn = test_sync_op_blk_pwrite_compressed, + }, { + .name = "/sync-op/pwrite_zeroes", + .fn = NULL, + .blkfn = test_sync_op_blk_pwrite_zeroes, }, { .name = "/sync-op/load_vmstate", .fn = test_sync_op_load_vmstate, @@ -314,6 +438,7 @@ const SyncOpTest sync_op_tests[] = { }, { .name = "/sync-op/truncate", .fn = test_sync_op_truncate, + .blkfn = test_sync_op_blk_truncate, }, { .name = "/sync-op/block_status", .fn = test_sync_op_block_status, @@ -349,7 +474,9 @@ static void test_sync_op(const void *opaque) blk_set_aio_context(blk, ctx, &error_abort); aio_context_acquire(ctx); - t->fn(c); + if (t->fn) { + t->fn(c); + } if (t->blkfn) { t->blkfn(blk); } @@ -455,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); @@ -630,11 +759,13 @@ 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 */ - bdrv_try_set_aio_context(src, ctx, &error_abort); + bdrv_try_change_aio_context(src, ctx, NULL, &error_abort); g_assert(bdrv_get_aio_context(src) == ctx); g_assert(bdrv_get_aio_context(target) == ctx); g_assert(bdrv_get_aio_context(filter) == ctx); @@ -642,7 +773,7 @@ static void test_propagate_mirror(void) /* Change the AioContext of target */ aio_context_acquire(ctx); - bdrv_try_set_aio_context(target, main_ctx, &error_abort); + bdrv_try_change_aio_context(target, main_ctx, NULL, &error_abort); aio_context_release(ctx); g_assert(bdrv_get_aio_context(src) == main_ctx); g_assert(bdrv_get_aio_context(target) == main_ctx); @@ -652,7 +783,7 @@ static void test_propagate_mirror(void) blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); blk_insert_bs(blk, src, &error_abort); - bdrv_try_set_aio_context(target, ctx, &local_err); + bdrv_try_change_aio_context(target, ctx, NULL, &local_err); error_free_or_abort(&local_err); g_assert(blk_get_aio_context(blk) == main_ctx); @@ -663,7 +794,7 @@ static void test_propagate_mirror(void) /* ...unless we explicitly allow it */ aio_context_acquire(ctx); blk_set_allow_aio_context_change(blk, true); - bdrv_try_set_aio_context(target, ctx, &error_abort); + bdrv_try_change_aio_context(target, ctx, NULL, &error_abort); aio_context_release(ctx); g_assert(blk_get_aio_context(blk) == ctx); @@ -675,7 +806,7 @@ static void test_propagate_mirror(void) aio_context_acquire(ctx); blk_set_aio_context(blk, main_ctx, &error_abort); - bdrv_try_set_aio_context(target, main_ctx, &error_abort); + bdrv_try_change_aio_context(target, main_ctx, NULL, &error_abort); aio_context_release(ctx); blk_unref(blk); diff --git a/tests/unit/test-blockjob-txn.c b/tests/unit/test-blockjob-txn.c index c69028b45033..d3b0bb24bec6 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 4c9e1bf1e540..c0426bd10ca0 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-char.c b/tests/unit/test-char.c index 5b3b48ebacd3..649fdf64e196 100644 --- a/tests/unit/test-char.c +++ b/tests/unit/test-char.c @@ -1212,7 +1212,6 @@ static void char_file_fifo_test(void) char *fifo = g_build_filename(tmp_path, "fifo", NULL); char *out = g_build_filename(tmp_path, "out", NULL); ChardevFile file = { .in = fifo, - .has_in = true, .out = out }; ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, .u.file.data = &file }; diff --git a/tests/unit/test-clone-visitor.c b/tests/unit/test-clone-visitor.c index 5d48e125b8e4..ce67585305f6 100644 --- a/tests/unit/test-clone-visitor.c +++ b/tests/unit/test-clone-visitor.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/clone-visitor.h" #include "test-qapi-visit.h" diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c index aa77a3bcb3cb..e16b80c24595 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-akcipher.c b/tests/unit/test-crypto-akcipher.c new file mode 100644 index 000000000000..4f1f4214dd2d --- /dev/null +++ b/tests/unit/test-crypto-akcipher.c @@ -0,0 +1,990 @@ +/* + * QEMU Crypto cipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include "qemu/osdep.h" + +#include "crypto/init.h" +#include "crypto/akcipher.h" +#include "qapi/error.h" + +static const uint8_t rsa1024_private_key[] = { + 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, + 0x81, 0x81, 0x00, 0xe6, 0x4d, 0x76, 0x4f, 0xb2, + 0x97, 0x09, 0xad, 0x9d, 0x17, 0x33, 0xf2, 0x30, + 0x42, 0x83, 0xa9, 0xcb, 0x49, 0xa4, 0x2e, 0x59, + 0x5e, 0x75, 0x51, 0xd1, 0xac, 0xc8, 0x86, 0x3e, + 0xdb, 0x72, 0x2e, 0xb2, 0xf7, 0xc3, 0x5b, 0xc7, + 0xea, 0xed, 0x30, 0xd1, 0xf7, 0x37, 0xee, 0x9d, + 0x36, 0x59, 0x6f, 0xf8, 0xce, 0xc0, 0x5c, 0x82, + 0x80, 0x37, 0x83, 0xd7, 0x45, 0x6a, 0xe9, 0xea, + 0xc5, 0x3a, 0x59, 0x6b, 0x34, 0x31, 0x44, 0x00, + 0x74, 0xa7, 0x29, 0xab, 0x79, 0x4a, 0xbd, 0xe8, + 0x25, 0x35, 0x01, 0x11, 0x40, 0xbf, 0x31, 0xbd, + 0xd3, 0xe0, 0x68, 0x1e, 0xd5, 0x5b, 0x2f, 0xe9, + 0x20, 0xf2, 0x9f, 0x46, 0x35, 0x30, 0xa8, 0xf1, + 0xfe, 0xef, 0xd8, 0x76, 0x23, 0x46, 0x34, 0x70, + 0xa1, 0xce, 0xc6, 0x65, 0x6d, 0xb0, 0x94, 0x7e, + 0xe5, 0x92, 0x45, 0x7b, 0xaa, 0xbb, 0x95, 0x97, + 0x77, 0xcd, 0xd3, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x30, 0x6a, 0xc4, 0x9e, 0xc8, + 0xba, 0xfc, 0x2b, 0xe5, 0xc4, 0xc5, 0x04, 0xfb, + 0xa4, 0x60, 0x2d, 0xc8, 0x31, 0x39, 0x35, 0x0d, + 0x50, 0xd0, 0x75, 0x5d, 0x11, 0x68, 0x2e, 0xe0, + 0xf4, 0x1d, 0xb3, 0x37, 0xa8, 0xe3, 0x07, 0x5e, + 0xa6, 0x43, 0x2b, 0x6a, 0x59, 0x01, 0x07, 0x47, + 0x41, 0xef, 0xd7, 0x9c, 0x85, 0x4a, 0xe7, 0xa7, + 0xff, 0xf0, 0xab, 0xe5, 0x0c, 0x11, 0x08, 0x10, + 0x75, 0x5a, 0x68, 0xa0, 0x08, 0x03, 0xc9, 0x40, + 0x79, 0x67, 0x1d, 0x65, 0x89, 0x2d, 0x08, 0xf9, + 0xb5, 0x1b, 0x7d, 0xd2, 0x41, 0x3b, 0x33, 0xf2, + 0x47, 0x2f, 0x9c, 0x0b, 0xd5, 0xaf, 0xcb, 0xdb, + 0xbb, 0x37, 0x63, 0x03, 0xf8, 0xe7, 0x2e, 0xc7, + 0x3c, 0x86, 0x9f, 0xc2, 0x9b, 0xb4, 0x70, 0x6a, + 0x4d, 0x7c, 0xe4, 0x1b, 0x3a, 0xa9, 0xae, 0xd7, + 0xce, 0x7f, 0x56, 0xc2, 0x73, 0x5e, 0x58, 0x63, + 0xd5, 0x86, 0x41, 0x02, 0x41, 0x00, 0xf6, 0x56, + 0x69, 0xec, 0xef, 0x65, 0x95, 0xdc, 0x25, 0x47, + 0xe0, 0x6f, 0xb0, 0x4f, 0x79, 0x77, 0x0a, 0x5e, + 0x46, 0xcb, 0xbd, 0x0b, 0x71, 0x51, 0x2a, 0xa4, + 0x65, 0x29, 0x18, 0xc6, 0x30, 0xa0, 0x95, 0x4c, + 0x4b, 0xbe, 0x8c, 0x40, 0xe3, 0x9c, 0x23, 0x02, + 0x14, 0x43, 0xe9, 0x64, 0xea, 0xe3, 0xa8, 0xe2, + 0x1a, 0xd5, 0xf9, 0x5c, 0xe0, 0x36, 0x2c, 0x97, + 0xda, 0xd5, 0xc7, 0x46, 0xce, 0x11, 0x02, 0x41, + 0x00, 0xef, 0x56, 0x08, 0xb8, 0x29, 0xa5, 0xa6, + 0x7c, 0xf7, 0x5f, 0xb4, 0xf5, 0x63, 0xe7, 0xeb, + 0x45, 0xfd, 0x89, 0xaa, 0x94, 0xa6, 0x3d, 0x0b, + 0xd9, 0x04, 0x6f, 0x78, 0xe0, 0xbb, 0xa2, 0xd4, + 0x29, 0x83, 0x17, 0x95, 0x6f, 0x50, 0x3d, 0x40, + 0x5d, 0xe5, 0x24, 0xda, 0xc2, 0x23, 0x50, 0x86, + 0xa8, 0x34, 0xc8, 0x6f, 0xec, 0x7f, 0xb6, 0x45, + 0x3a, 0xdd, 0x78, 0x9b, 0xee, 0xa1, 0xe4, 0x09, + 0xa3, 0x02, 0x40, 0x5c, 0xd6, 0x66, 0x67, 0x58, + 0x35, 0xc5, 0xcb, 0xc8, 0xf5, 0x14, 0xbd, 0xa3, + 0x09, 0xe0, 0xb2, 0x1f, 0x63, 0x36, 0x75, 0x34, + 0x52, 0xea, 0xaa, 0xf7, 0x52, 0x2b, 0x99, 0xd8, + 0x6f, 0x61, 0x06, 0x34, 0x1e, 0x23, 0xf1, 0xb5, + 0x34, 0x03, 0x53, 0xe5, 0xd1, 0xb3, 0xc7, 0x80, + 0x5f, 0x7b, 0x32, 0xbf, 0x84, 0x2f, 0x2e, 0xf3, + 0x22, 0xb0, 0x91, 0x5a, 0x2f, 0x04, 0xd7, 0x4a, + 0x9a, 0x01, 0xb1, 0x02, 0x40, 0x34, 0x0b, 0x26, + 0x4c, 0x3d, 0xaa, 0x2a, 0xc0, 0xe3, 0xdd, 0xe8, + 0xf0, 0xaf, 0x6f, 0xe0, 0x06, 0x51, 0x32, 0x9d, + 0x68, 0x43, 0x99, 0xe4, 0xb8, 0xa5, 0x31, 0x44, + 0x3c, 0xc2, 0x30, 0x8f, 0x28, 0x13, 0xbc, 0x8e, + 0x1f, 0x2d, 0x78, 0x94, 0x45, 0x96, 0xad, 0x63, + 0xf0, 0x71, 0x53, 0x72, 0x64, 0xa3, 0x4d, 0xae, + 0xa0, 0xe3, 0xc8, 0x93, 0xd7, 0x50, 0x0f, 0x89, + 0x00, 0xe4, 0x2d, 0x3d, 0x37, 0x02, 0x41, 0x00, + 0xbe, 0xa6, 0x08, 0xe0, 0xc8, 0x15, 0x2a, 0x47, + 0xcb, 0xd5, 0xec, 0x93, 0xd3, 0xaa, 0x12, 0x82, + 0xaf, 0xac, 0x51, 0x5a, 0x5b, 0xa7, 0x93, 0x4b, + 0xb9, 0xab, 0x00, 0xfa, 0x5a, 0xea, 0x34, 0xe4, + 0x80, 0xf1, 0x44, 0x6a, 0x65, 0xe4, 0x33, 0x99, + 0xfb, 0x54, 0xd7, 0x89, 0x5a, 0x1b, 0xd6, 0x2b, + 0xcc, 0x6e, 0x4b, 0x19, 0xa0, 0x6d, 0x93, 0x9f, + 0xc3, 0x91, 0x7a, 0xa5, 0xd8, 0x59, 0x0e, 0x9e, +}; + +static const uint8_t rsa1024_public_key[] = { + 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe6, + 0x4d, 0x76, 0x4f, 0xb2, 0x97, 0x09, 0xad, 0x9d, + 0x17, 0x33, 0xf2, 0x30, 0x42, 0x83, 0xa9, 0xcb, + 0x49, 0xa4, 0x2e, 0x59, 0x5e, 0x75, 0x51, 0xd1, + 0xac, 0xc8, 0x86, 0x3e, 0xdb, 0x72, 0x2e, 0xb2, + 0xf7, 0xc3, 0x5b, 0xc7, 0xea, 0xed, 0x30, 0xd1, + 0xf7, 0x37, 0xee, 0x9d, 0x36, 0x59, 0x6f, 0xf8, + 0xce, 0xc0, 0x5c, 0x82, 0x80, 0x37, 0x83, 0xd7, + 0x45, 0x6a, 0xe9, 0xea, 0xc5, 0x3a, 0x59, 0x6b, + 0x34, 0x31, 0x44, 0x00, 0x74, 0xa7, 0x29, 0xab, + 0x79, 0x4a, 0xbd, 0xe8, 0x25, 0x35, 0x01, 0x11, + 0x40, 0xbf, 0x31, 0xbd, 0xd3, 0xe0, 0x68, 0x1e, + 0xd5, 0x5b, 0x2f, 0xe9, 0x20, 0xf2, 0x9f, 0x46, + 0x35, 0x30, 0xa8, 0xf1, 0xfe, 0xef, 0xd8, 0x76, + 0x23, 0x46, 0x34, 0x70, 0xa1, 0xce, 0xc6, 0x65, + 0x6d, 0xb0, 0x94, 0x7e, 0xe5, 0x92, 0x45, 0x7b, + 0xaa, 0xbb, 0x95, 0x97, 0x77, 0xcd, 0xd3, 0x02, + 0x03, 0x01, 0x00, 0x01, +}; + +static const uint8_t rsa2048_private_key[] = { + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xbd, 0x9c, 0x83, 0x6b, + 0x0e, 0x8e, 0xcf, 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, + 0xe3, 0x52, 0x0f, 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, + 0x08, 0x24, 0xba, 0x87, 0x46, 0xfb, 0x28, 0x93, + 0xe5, 0xe5, 0x81, 0x42, 0xc0, 0xf9, 0x17, 0xc7, + 0x81, 0x01, 0xf4, 0x18, 0x6a, 0x17, 0xf5, 0x57, + 0x20, 0x37, 0xcf, 0xf9, 0x74, 0x5e, 0xe1, 0x48, + 0x6a, 0x71, 0x0a, 0x0f, 0x79, 0x72, 0x2b, 0x46, + 0x10, 0x53, 0xdc, 0x14, 0x43, 0xbd, 0xbc, 0x6d, + 0x15, 0x6f, 0x15, 0x4e, 0xf0, 0x0d, 0x89, 0x39, + 0x02, 0xc3, 0x68, 0x5c, 0xa8, 0xfc, 0xed, 0x64, + 0x9d, 0x98, 0xb7, 0xcd, 0x83, 0x66, 0x93, 0xc3, + 0xd9, 0x57, 0xa0, 0x21, 0x93, 0xad, 0x5c, 0x75, + 0x69, 0x88, 0x9e, 0x81, 0xdc, 0x7f, 0x1d, 0xd5, + 0xbd, 0x1c, 0xc1, 0x30, 0x56, 0xa5, 0xda, 0x99, + 0x46, 0xa6, 0x6d, 0x0e, 0x6f, 0x5e, 0x51, 0x34, + 0x49, 0x73, 0xc3, 0x67, 0x49, 0x7e, 0x21, 0x2a, + 0x20, 0xa7, 0x2b, 0x92, 0x73, 0x1d, 0xa5, 0x25, + 0x2a, 0xd0, 0x3a, 0x89, 0x75, 0xb2, 0xbb, 0x19, + 0x37, 0x78, 0x48, 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, + 0xc6, 0x26, 0xca, 0x46, 0x8c, 0xf1, 0x42, 0x2a, + 0x31, 0xb2, 0xfc, 0xe7, 0x55, 0x51, 0xff, 0x07, + 0x13, 0x5b, 0x36, 0x59, 0x2b, 0x43, 0x30, 0x4b, + 0x05, 0x5c, 0xd2, 0x45, 0xa0, 0xa0, 0x7c, 0x17, + 0x5b, 0x07, 0xbb, 0x5d, 0x83, 0x80, 0x92, 0x6d, + 0x87, 0x1a, 0x43, 0xac, 0xc7, 0x6b, 0x8d, 0x11, + 0x60, 0x27, 0xd2, 0xdf, 0xdb, 0x71, 0x02, 0x55, + 0x6e, 0xb5, 0xca, 0x4d, 0xda, 0x59, 0x0d, 0xb8, + 0x8c, 0xcd, 0xd3, 0x0e, 0x55, 0xa0, 0xa4, 0x8d, + 0xa0, 0x14, 0x10, 0x48, 0x42, 0x35, 0x56, 0x08, + 0xf7, 0x29, 0x5f, 0xa2, 0xea, 0xa4, 0x5e, 0x8e, + 0x99, 0x56, 0xaa, 0x5a, 0x8c, 0x23, 0x8f, 0x35, + 0x22, 0x8a, 0xff, 0xed, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x01, 0x00, 0x4e, 0x4a, 0xf3, + 0x44, 0xe0, 0x64, 0xfd, 0xe1, 0xde, 0x33, 0x1e, + 0xd1, 0xf1, 0x8f, 0x6f, 0xe0, 0xa2, 0xfa, 0x08, + 0x60, 0xe1, 0xc6, 0xf0, 0xb2, 0x6d, 0x0f, 0xc6, + 0x28, 0x93, 0xb4, 0x19, 0x94, 0xab, 0xc3, 0xef, + 0x1a, 0xb4, 0xdd, 0x4e, 0xa2, 0x4a, 0x24, 0x8c, + 0x6c, 0xa6, 0x64, 0x05, 0x5f, 0x56, 0xba, 0xda, + 0xc1, 0x21, 0x1a, 0x7d, 0xf1, 0xf7, 0xce, 0xb9, + 0xa9, 0x9b, 0x92, 0x54, 0xfc, 0x95, 0x20, 0x22, + 0x4e, 0xd4, 0x9b, 0xe2, 0xab, 0x8e, 0x99, 0xb8, + 0x40, 0xaf, 0x30, 0x6a, 0xc6, 0x60, 0x0c, 0xd8, + 0x25, 0x44, 0xa1, 0xcb, 0xbb, 0x73, 0x77, 0x86, + 0xaa, 0x46, 0xf3, 0x54, 0xae, 0xa8, 0xa0, 0xdb, + 0xdd, 0xab, 0x6e, 0xfb, 0x2c, 0x5a, 0x14, 0xaf, + 0x08, 0x13, 0xa7, 0x6c, 0xe9, 0xfd, 0xcd, 0x4c, + 0x1f, 0x20, 0x3a, 0x16, 0x2b, 0xf0, 0xb6, 0x7c, + 0x47, 0x5f, 0xd1, 0x0a, 0x2c, 0xc4, 0xa5, 0x68, + 0xd0, 0x43, 0x75, 0x6b, 0x65, 0xaa, 0x32, 0xc6, + 0x99, 0x06, 0xcb, 0x8f, 0xe6, 0x8d, 0xce, 0xbf, + 0x4d, 0x0d, 0x7b, 0x22, 0x2a, 0x8a, 0xcb, 0x7d, + 0x7f, 0x16, 0x48, 0x85, 0xf1, 0x86, 0xcb, 0x54, + 0xb9, 0x39, 0xd4, 0xbc, 0xe3, 0x2d, 0x27, 0x59, + 0xf6, 0x81, 0x5e, 0x94, 0x45, 0xdf, 0xb9, 0x22, + 0xaf, 0x64, 0x0d, 0x14, 0xec, 0x8c, 0xeb, 0x71, + 0xac, 0xee, 0x09, 0x4c, 0xbf, 0x34, 0xf9, 0xf4, + 0x66, 0x77, 0x36, 0x3b, 0x41, 0x74, 0x01, 0x4f, + 0xfc, 0x56, 0x83, 0xba, 0x14, 0xb0, 0x2f, 0xdd, + 0x4d, 0xb9, 0x3f, 0xdf, 0x71, 0xbe, 0x7b, 0xba, + 0x66, 0xc8, 0xc5, 0x42, 0xc9, 0xba, 0x18, 0x63, + 0x45, 0x07, 0x2f, 0x84, 0x3e, 0xc3, 0xfb, 0x47, + 0xda, 0xd4, 0x1d, 0x0e, 0x9d, 0x96, 0xc0, 0xea, + 0xee, 0x45, 0x2f, 0xe1, 0x62, 0x23, 0xee, 0xef, + 0x3d, 0x5e, 0x55, 0xa1, 0x0d, 0x02, 0x81, 0x81, + 0x00, 0xeb, 0x76, 0x88, 0xd3, 0xae, 0x3f, 0x1d, + 0xf2, 0x49, 0xe0, 0x37, 0x49, 0x83, 0x82, 0x6c, + 0xf7, 0xf1, 0x17, 0x30, 0x75, 0x2e, 0x89, 0x06, + 0x88, 0x56, 0x32, 0xf6, 0xfa, 0x58, 0xcb, 0x3c, + 0x98, 0x67, 0xc3, 0xde, 0x10, 0x82, 0xe5, 0xfa, + 0xfa, 0x52, 0x47, 0x8d, 0xd7, 0x00, 0xc6, 0xcb, + 0xf7, 0xf6, 0x57, 0x9b, 0x6e, 0x0c, 0xac, 0xe8, + 0x3b, 0xd1, 0xde, 0xb5, 0x34, 0xaf, 0x8b, 0x2a, + 0xb0, 0x2d, 0x01, 0xeb, 0x7c, 0xa0, 0x42, 0x26, + 0xbb, 0x2b, 0x43, 0x0e, 0x1d, 0xe2, 0x4e, 0xc9, + 0xc1, 0x0a, 0x67, 0x1d, 0xfc, 0x83, 0x25, 0xce, + 0xb2, 0x18, 0xd9, 0x0d, 0x70, 0xf5, 0xa3, 0x5a, + 0x9c, 0x99, 0xdd, 0x47, 0xa1, 0x57, 0xe7, 0x20, + 0xde, 0xa1, 0x29, 0x8d, 0x96, 0x62, 0xf9, 0x26, + 0x95, 0x51, 0xa6, 0xe7, 0x09, 0x8b, 0xba, 0x16, + 0x8b, 0x19, 0x5b, 0xf9, 0x27, 0x0d, 0xc5, 0xd6, + 0x5f, 0x02, 0x81, 0x81, 0x00, 0xce, 0x26, 0x31, + 0xb5, 0x43, 0x53, 0x95, 0x39, 0xdd, 0x01, 0x98, + 0x8b, 0x3d, 0x27, 0xeb, 0x0b, 0x87, 0x1c, 0x95, + 0xfc, 0x3e, 0x36, 0x51, 0x31, 0xb5, 0xea, 0x59, + 0x56, 0xc0, 0x97, 0x62, 0xf0, 0x63, 0x2b, 0xb6, + 0x30, 0x9b, 0xdf, 0x19, 0x10, 0xe9, 0xa0, 0x3d, + 0xea, 0x54, 0x5a, 0xe6, 0xc6, 0x9e, 0x7e, 0xb5, + 0xf0, 0xb0, 0x54, 0xef, 0xc3, 0xe1, 0x47, 0xa6, + 0x95, 0xc7, 0xe4, 0xa3, 0x4a, 0x30, 0x68, 0x24, + 0x98, 0x7d, 0xc1, 0x34, 0xa9, 0xcb, 0xbc, 0x3c, + 0x08, 0x9c, 0x7d, 0x0c, 0xa2, 0xb7, 0x60, 0xaa, + 0x38, 0x08, 0x16, 0xa6, 0x7f, 0xdb, 0xd2, 0xb1, + 0x67, 0xe7, 0x93, 0x8e, 0xbb, 0x7e, 0xb9, 0xb5, + 0xd0, 0xd0, 0x9f, 0x7b, 0xcc, 0x46, 0xe6, 0x74, + 0x78, 0x1a, 0x96, 0xd6, 0xd7, 0x74, 0x34, 0x54, + 0x3b, 0x54, 0x55, 0x7f, 0x89, 0x81, 0xbc, 0x40, + 0x55, 0x87, 0x24, 0x95, 0x33, 0x02, 0x81, 0x81, + 0x00, 0xb0, 0x18, 0x5d, 0x2a, 0x1a, 0x95, 0x9f, + 0x9a, 0xd5, 0x3f, 0x37, 0x79, 0xe6, 0x3d, 0x83, + 0xab, 0x46, 0x86, 0x36, 0x3a, 0x5d, 0x0c, 0x23, + 0x73, 0x91, 0x2b, 0xda, 0x63, 0xce, 0x46, 0x68, + 0xd1, 0xfe, 0x40, 0x90, 0xf2, 0x3e, 0x43, 0x2b, + 0x19, 0x4c, 0xb1, 0xb0, 0xd5, 0x8c, 0x02, 0x21, + 0x07, 0x18, 0x17, 0xda, 0xe9, 0x49, 0xd7, 0x82, + 0x73, 0x42, 0x78, 0xd1, 0x82, 0x4e, 0x8a, 0xc0, + 0xe9, 0x33, 0x2f, 0xcd, 0x62, 0xce, 0x23, 0xca, + 0xfd, 0x8d, 0xd4, 0x3f, 0x59, 0x80, 0x27, 0xb6, + 0x61, 0x85, 0x9b, 0x2a, 0xe4, 0xef, 0x5c, 0x36, + 0x22, 0x21, 0xcd, 0x2a, 0x6d, 0x41, 0x77, 0xe2, + 0xcb, 0x5d, 0x93, 0x0d, 0x00, 0x10, 0x52, 0x8d, + 0xd5, 0x92, 0x28, 0x16, 0x78, 0xd3, 0x1a, 0x4c, + 0x8d, 0xbd, 0x9c, 0x1a, 0x0b, 0x9c, 0x91, 0x16, + 0x4c, 0xff, 0x31, 0x36, 0xbb, 0xcb, 0x64, 0x1a, + 0xf7, 0x02, 0x81, 0x80, 0x32, 0x65, 0x09, 0xdf, + 0xca, 0xee, 0xa2, 0xdb, 0x3b, 0x58, 0xc9, 0x86, + 0xb8, 0x53, 0x8a, 0xd5, 0x0d, 0x99, 0x82, 0x5c, + 0xe0, 0x84, 0x7c, 0xc2, 0xcf, 0x3a, 0xd3, 0xce, + 0x2e, 0x54, 0x93, 0xbe, 0x3a, 0x30, 0x14, 0x60, + 0xbb, 0xaa, 0x05, 0x41, 0xaa, 0x2b, 0x1f, 0x17, + 0xaa, 0xb9, 0x72, 0x12, 0xf9, 0xe9, 0xf5, 0xe6, + 0x39, 0xe4, 0xf9, 0x9c, 0x03, 0xf5, 0x75, 0x16, + 0xc6, 0x7f, 0xf1, 0x1f, 0x10, 0xc8, 0x54, 0xb1, + 0xe6, 0x84, 0x15, 0xb0, 0xb0, 0x7a, 0x7a, 0x9e, + 0x8c, 0x4a, 0xd1, 0x8c, 0xf1, 0x91, 0x32, 0xeb, + 0x71, 0xa6, 0xbf, 0xdb, 0x1f, 0xcc, 0xd8, 0xcb, + 0x92, 0xc3, 0xf2, 0xaf, 0x89, 0x22, 0x32, 0xfd, + 0x32, 0x12, 0xda, 0xbb, 0xac, 0x55, 0x68, 0x01, + 0x78, 0x56, 0x89, 0x7c, 0xb0, 0x0e, 0x9e, 0xcc, + 0xc6, 0x28, 0x04, 0x7e, 0x83, 0xf5, 0x96, 0x30, + 0x92, 0x51, 0xf2, 0x1b, 0x02, 0x81, 0x81, 0x00, + 0x83, 0x6d, 0xd1, 0x98, 0x90, 0x41, 0x8c, 0xa7, + 0x92, 0x83, 0xac, 0x89, 0x05, 0x0c, 0x79, 0x67, + 0x90, 0xb6, 0xa1, 0xf3, 0x2f, 0xca, 0xf0, 0x15, + 0xe0, 0x30, 0x58, 0xe9, 0x4f, 0xcb, 0x4c, 0x56, + 0x56, 0x56, 0x14, 0x3f, 0x1b, 0x79, 0xb6, 0xef, + 0x57, 0x4b, 0x28, 0xbd, 0xb0, 0xe6, 0x0c, 0x49, + 0x4b, 0xbe, 0xe1, 0x57, 0x28, 0x2a, 0x23, 0x5e, + 0xc4, 0xa2, 0x19, 0x4b, 0x00, 0x67, 0x78, 0xd9, + 0x26, 0x6e, 0x17, 0x25, 0xce, 0xe4, 0xfd, 0xde, + 0x86, 0xa8, 0x5a, 0x67, 0x47, 0x6b, 0x15, 0x09, + 0xe1, 0xec, 0x8e, 0x62, 0x98, 0x91, 0x6f, 0xc0, + 0x98, 0x0c, 0x70, 0x0e, 0x7d, 0xbe, 0x63, 0xbd, + 0x12, 0x5a, 0x98, 0x1c, 0xe3, 0x0c, 0xfb, 0xc7, + 0xfb, 0x1b, 0xbd, 0x02, 0x87, 0xcc, 0x0c, 0xbb, + 0xc2, 0xd4, 0xb6, 0xc1, 0xa1, 0x23, 0xd3, 0x1e, + 0x21, 0x6f, 0x48, 0xba, 0x0e, 0x2e, 0xc7, 0x42 +}; + +static const uint8_t rsa2048_public_key[] = { + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xbd, 0x9c, 0x83, 0x6b, 0x0e, 0x8e, 0xcf, + 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, 0xe3, 0x52, 0x0f, + 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, 0x08, 0x24, 0xba, + 0x87, 0x46, 0xfb, 0x28, 0x93, 0xe5, 0xe5, 0x81, + 0x42, 0xc0, 0xf9, 0x17, 0xc7, 0x81, 0x01, 0xf4, + 0x18, 0x6a, 0x17, 0xf5, 0x57, 0x20, 0x37, 0xcf, + 0xf9, 0x74, 0x5e, 0xe1, 0x48, 0x6a, 0x71, 0x0a, + 0x0f, 0x79, 0x72, 0x2b, 0x46, 0x10, 0x53, 0xdc, + 0x14, 0x43, 0xbd, 0xbc, 0x6d, 0x15, 0x6f, 0x15, + 0x4e, 0xf0, 0x0d, 0x89, 0x39, 0x02, 0xc3, 0x68, + 0x5c, 0xa8, 0xfc, 0xed, 0x64, 0x9d, 0x98, 0xb7, + 0xcd, 0x83, 0x66, 0x93, 0xc3, 0xd9, 0x57, 0xa0, + 0x21, 0x93, 0xad, 0x5c, 0x75, 0x69, 0x88, 0x9e, + 0x81, 0xdc, 0x7f, 0x1d, 0xd5, 0xbd, 0x1c, 0xc1, + 0x30, 0x56, 0xa5, 0xda, 0x99, 0x46, 0xa6, 0x6d, + 0x0e, 0x6f, 0x5e, 0x51, 0x34, 0x49, 0x73, 0xc3, + 0x67, 0x49, 0x7e, 0x21, 0x2a, 0x20, 0xa7, 0x2b, + 0x92, 0x73, 0x1d, 0xa5, 0x25, 0x2a, 0xd0, 0x3a, + 0x89, 0x75, 0xb2, 0xbb, 0x19, 0x37, 0x78, 0x48, + 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, 0xc6, 0x26, 0xca, + 0x46, 0x8c, 0xf1, 0x42, 0x2a, 0x31, 0xb2, 0xfc, + 0xe7, 0x55, 0x51, 0xff, 0x07, 0x13, 0x5b, 0x36, + 0x59, 0x2b, 0x43, 0x30, 0x4b, 0x05, 0x5c, 0xd2, + 0x45, 0xa0, 0xa0, 0x7c, 0x17, 0x5b, 0x07, 0xbb, + 0x5d, 0x83, 0x80, 0x92, 0x6d, 0x87, 0x1a, 0x43, + 0xac, 0xc7, 0x6b, 0x8d, 0x11, 0x60, 0x27, 0xd2, + 0xdf, 0xdb, 0x71, 0x02, 0x55, 0x6e, 0xb5, 0xca, + 0x4d, 0xda, 0x59, 0x0d, 0xb8, 0x8c, 0xcd, 0xd3, + 0x0e, 0x55, 0xa0, 0xa4, 0x8d, 0xa0, 0x14, 0x10, + 0x48, 0x42, 0x35, 0x56, 0x08, 0xf7, 0x29, 0x5f, + 0xa2, 0xea, 0xa4, 0x5e, 0x8e, 0x99, 0x56, 0xaa, + 0x5a, 0x8c, 0x23, 0x8f, 0x35, 0x22, 0x8a, 0xff, + 0xed, 0x02, 0x03, 0x01, 0x00, 0x01 +}; + +static const uint8_t test_sha1_dgst[] = { + 0x3c, 0x05, 0x19, 0x34, 0x29, 0x19, 0xc7, 0xe0, + 0x87, 0xb6, 0x24, 0xf9, 0x58, 0xac, 0xa4, 0xd4, + 0xb2, 0xd9, 0x03, 0x9e, +}; + +static const uint8_t exp_signature_rsa2048_pkcs1[] = { + 0x4e, 0x82, 0x56, 0x4c, 0x84, 0x66, 0xca, 0x1e, + 0xc6, 0x92, 0x46, 0x20, 0x02, 0x6b, 0x64, 0x46, + 0x15, 0x6b, 0x24, 0xf2, 0xbb, 0xfa, 0x44, 0x3c, + 0xaf, 0x42, 0xc8, 0x41, 0xfd, 0xce, 0xed, 0x95, + 0x34, 0xaf, 0x25, 0x09, 0xd1, 0x06, 0x94, 0xaa, + 0x52, 0xd4, 0x29, 0xc8, 0x52, 0x34, 0x67, 0x59, + 0x4f, 0x5a, 0xfd, 0x23, 0x30, 0x5e, 0xc7, 0x1e, + 0xa6, 0xe0, 0x1b, 0x23, 0xca, 0x82, 0x47, 0x9a, + 0x2e, 0x2c, 0x66, 0x45, 0x5a, 0x12, 0xa9, 0x15, + 0xbf, 0xd6, 0xd6, 0xfa, 0x8d, 0x60, 0x99, 0x89, + 0x91, 0x39, 0x06, 0xb7, 0xd3, 0x9a, 0xef, 0x15, + 0x7b, 0x95, 0x87, 0x77, 0x2c, 0x41, 0xd4, 0x71, + 0xd5, 0xdf, 0x22, 0x7b, 0x01, 0xe2, 0xc1, 0xfb, + 0xb9, 0x4e, 0x0c, 0x9b, 0xd5, 0x04, 0xed, 0x2b, + 0x7e, 0x73, 0x53, 0xaa, 0x33, 0x89, 0x9d, 0x95, + 0x28, 0x8f, 0x8b, 0x80, 0x34, 0x7a, 0xea, 0xe3, + 0x66, 0x8a, 0xa8, 0xad, 0xed, 0x91, 0x43, 0xdd, + 0x77, 0xe5, 0xd7, 0x16, 0xda, 0xa8, 0x00, 0x29, + 0x3f, 0x9f, 0xe0, 0x1d, 0x42, 0x9d, 0x35, 0x5d, + 0x0f, 0xf3, 0x90, 0x27, 0x3a, 0x8c, 0x46, 0x13, + 0x53, 0x3e, 0x3b, 0x38, 0x77, 0xf8, 0x57, 0x61, + 0xbc, 0xc4, 0x54, 0x68, 0x48, 0xae, 0x58, 0x03, + 0x33, 0x94, 0x3f, 0x18, 0x1e, 0xb3, 0x3f, 0x79, + 0xa7, 0x26, 0x92, 0x5d, 0x32, 0x2a, 0xdb, 0xe6, + 0x3a, 0xe8, 0xd7, 0xaa, 0x91, 0xfe, 0x9f, 0x06, + 0x26, 0x68, 0x8c, 0x27, 0x31, 0xb0, 0x04, 0x9e, + 0x94, 0x79, 0x63, 0xa1, 0xc7, 0xe8, 0x5b, 0x8c, + 0xd3, 0xf1, 0x88, 0x58, 0x31, 0x2f, 0x4e, 0x11, + 0x00, 0xfe, 0x29, 0xad, 0x2c, 0xa9, 0x8e, 0x63, + 0xd8, 0x7d, 0xc5, 0xa1, 0x71, 0xfa, 0x08, 0x29, + 0xea, 0xd6, 0x6c, 0x53, 0x00, 0x52, 0xa0, 0xed, + 0x6b, 0x7c, 0x67, 0x50, 0x71, 0x2d, 0x96, 0x7a, +}; + +static const uint8_t exp_signature_rsa1024_pkcs1[] = { + 0x6b, 0x5b, 0xbb, 0x3b, 0x1f, 0x08, 0xd8, 0xc0, + 0x4a, 0xf1, 0x5a, 0x12, 0xc2, 0x39, 0x14, 0x65, + 0x4f, 0xda, 0x79, 0x67, 0xf2, 0x89, 0x25, 0xad, + 0x9e, 0x7e, 0xba, 0xa8, 0x34, 0x15, 0x03, 0xdd, + 0x80, 0x6b, 0x01, 0xd7, 0x4a, 0xf3, 0xd6, 0xef, + 0x1e, 0x48, 0xf3, 0xbc, 0x75, 0x1a, 0xc4, 0x2c, + 0x90, 0x15, 0x9f, 0x21, 0x24, 0x98, 0x21, 0xef, + 0x6d, 0x3b, 0xf3, 0x82, 0x8f, 0x8d, 0xd8, 0x48, + 0x37, 0x16, 0x19, 0x8e, 0x3c, 0x64, 0xa0, 0x9e, + 0xf7, 0x0c, 0xd9, 0x5c, 0xc6, 0x13, 0xc4, 0x5f, + 0xf8, 0xf3, 0x59, 0x5b, 0xd0, 0x33, 0x95, 0x98, + 0xde, 0x67, 0x25, 0x58, 0x46, 0xba, 0xee, 0x0f, + 0x47, 0x7a, 0x7f, 0xd0, 0xe4, 0x77, 0x09, 0x17, + 0xe9, 0x81, 0x6e, 0x2d, 0x33, 0x9b, 0x13, 0x0b, + 0xc9, 0xb2, 0x0c, 0x2c, 0xb5, 0xdf, 0x52, 0x8f, + 0xab, 0x0d, 0xc6, 0x59, 0x1d, 0xc7, 0x33, 0x7b, +}; + +static const uint8_t test_plaintext[] = { + 0x00, 0x44, 0xbc, 0x6f, 0x77, 0xfb, 0xe2, 0xa4, + 0x98, 0x9e, 0xf5, 0x33, 0xa0, 0xbd, 0x81, 0xb9, + 0xf1, 0x44, 0x7f, 0x79, 0x89, 0x23, 0xe5, 0x46, + 0x66, 0x9f, 0x98, 0x95, 0x6f, 0x56, 0x78, 0xf6, + 0xf5, 0xac, 0x9c, 0xda, 0xc2, 0x79, 0x59, 0xf0, + 0x1b, 0x03, 0xfa, 0x46, 0x1c, 0x1f, 0x18, 0x07, + 0xce, 0xad, 0xed, 0x3d, 0x11, 0xf9, 0x1b, 0x26, + 0x4a, 0x97, 0x28, 0x71, 0x5f, 0x2c, 0x5e, 0x58, + 0xf0, 0xd6, 0xbf, 0xa4, 0x12, 0xd0, 0x1d, 0x07, + 0xcb, 0x73, 0x66, 0xb6, 0xa4, 0x09, 0xaf, 0x5d, + 0xe9, 0x14, 0x14, 0xaf, 0x69, 0xd6, 0xee, 0x0a, + 0xfc, 0xca, 0xac, 0x94, 0x47, 0xd5, 0x9d, 0x5b, + 0x2b, 0xfb, 0xce, 0x9d, 0x04, 0xc1, 0xaf, 0xa5, + 0xa1, 0x8d, 0xa9, 0x48, 0xa8, 0x65, 0xe6, 0x9f, + 0x74, 0x78, 0x16, 0x32, 0x93, 0xb5, 0x21, 0xb9, + 0x9f, 0x3f, 0xc1, 0xe5, 0xa2, 0x50, 0x8b, 0x12, + 0xfb, 0x3e, 0xb0, 0x8a, 0x00, 0xc7, 0x20, 0x56, + 0xb3, 0xb1, 0x29, 0x95, 0x89, 0xd6, 0x50, 0xf5, + 0x37, 0x38, 0x8e, 0x12, 0xf1, 0xba, 0x82, 0x37, + 0x34, 0x68, 0x4b, 0xe8, 0xe3, 0x11, 0x1c, 0x46, + 0xf9, 0x63, 0x3a, 0xd6, 0xf3, 0x3f, 0x55, 0xa6, + 0xbd, 0x89, 0xf1, 0x2d, 0x38, 0x91, 0x7c, 0xc2, + 0x4d, 0xf1, 0x69, 0x82, 0x6d, 0x71, 0x77, 0xf4, + 0xfc, 0x43, 0x20, 0x6f, 0x43, 0xb9, 0x43, 0xd1, + 0x65, 0xbd, 0xca, 0xb1, 0x43, 0x87, 0xf8, 0xc8, + 0x76, 0x21, 0xa9, 0xeb, 0x3e, 0x9a, 0xef, 0xc9, + 0x0e, 0x79, 0xbc, 0xf0, 0xf8, 0xc8, 0xe2, 0xbc, + 0x33, 0x35, 0x3e, 0xfc, 0xf9, 0x44, 0x69, 0x06, + 0x7c, 0x7f, 0x5d, 0xa2, 0x9e, 0xab, 0xc2, 0x82, + 0xa0, 0xfb, 0xc5, 0x79, 0x57, 0x8c, 0xf1, 0x1c, + 0x51, 0x64, 0x4c, 0x56, 0x08, 0x80, 0x32, 0xf4, + 0x97, 0x8f, 0x6f, 0xb2, 0x16, 0xa6, 0x9d, 0x71, +}; + +static const uint8_t exp_ciphertext_rsa1024_raw[] = { + 0x01, 0xa0, 0xc2, 0x94, 0x9f, 0xd6, 0xbe, 0x8d, + 0xe9, 0x24, 0xaa, 0x9c, 0x67, 0xd7, 0xe3, 0x04, + 0x34, 0xbf, 0xd3, 0x27, 0xa1, 0x43, 0xeb, 0x60, + 0x6b, 0x5b, 0x64, 0x15, 0x55, 0x16, 0x98, 0x35, + 0xc2, 0x59, 0xa7, 0xf7, 0x24, 0xf7, 0x05, 0xb9, + 0xe8, 0x56, 0x6f, 0xf2, 0x7d, 0x8b, 0x3c, 0xcb, + 0xa6, 0xc2, 0xac, 0x0c, 0x37, 0x8c, 0x70, 0x70, + 0x55, 0x05, 0x07, 0x0d, 0x63, 0x6b, 0x7d, 0x5f, + 0xae, 0x03, 0x1e, 0x55, 0x05, 0xbb, 0xa8, 0xe7, + 0xff, 0xa0, 0x8c, 0x5b, 0x6b, 0x01, 0x48, 0x2e, + 0x4f, 0x7f, 0xe2, 0x74, 0xc6, 0x32, 0xa7, 0x2d, + 0xdb, 0x91, 0x9b, 0x67, 0x4d, 0x71, 0xf9, 0x8c, + 0x42, 0x43, 0x75, 0x4e, 0xd0, 0x0e, 0x7c, 0xa0, + 0x97, 0x1a, 0x5f, 0x8e, 0x6f, 0xe4, 0xfa, 0x16, + 0x1d, 0x59, 0x0e, 0x0b, 0x11, 0x12, 0xa3, 0x0c, + 0xa6, 0x55, 0xe6, 0xdb, 0xa7, 0x71, 0xa6, 0xff, +}; + +static const uint8_t exp_ciphertext_rsa1024_pkcs1[] = { + 0x93, 0x78, 0x6a, 0x76, 0xb8, 0x94, 0xea, 0xe4, + 0x32, 0x79, 0x01, 0x8b, 0xc1, 0xcb, 0x2e, 0x2d, + 0xfe, 0xdc, 0x9b, 0xe3, 0xe9, 0x23, 0xe4, 0x0a, + 0xb0, 0x6b, 0x9f, 0x6b, 0x62, 0xf5, 0x3d, 0xf0, + 0x78, 0x84, 0x77, 0x21, 0xad, 0x0b, 0x30, 0x30, + 0x94, 0xe2, 0x18, 0xc4, 0x9b, 0x12, 0x06, 0xc8, + 0xaa, 0xf7, 0x30, 0xe4, 0xc8, 0x64, 0xe7, 0x51, + 0xf1, 0x6a, 0xe1, 0xa2, 0x58, 0x7a, 0x02, 0x9c, + 0x8e, 0xf0, 0x2d, 0x25, 0x6b, 0xb7, 0x25, 0x5e, + 0x05, 0xaf, 0x38, 0xb2, 0x69, 0x5e, 0x6c, 0x75, + 0x6e, 0x27, 0xba, 0x5d, 0x7d, 0x35, 0x72, 0xb7, + 0x25, 0xd4, 0xaa, 0xb2, 0x4b, 0x9e, 0x6b, 0x82, + 0xb2, 0x32, 0xe2, 0x13, 0x1d, 0x00, 0x21, 0x08, + 0xae, 0x14, 0xbb, 0xc0, 0x40, 0xb7, 0x0d, 0xd5, + 0x0e, 0x4d, 0x6d, 0x9a, 0x70, 0x86, 0xe9, 0xfc, + 0x67, 0x2b, 0xa4, 0x11, 0x45, 0xb6, 0xc4, 0x2f, +}; + +static const uint8_t exp_ciphertext_rsa2048_raw[] = { + 0x09, 0x7b, 0x9e, 0x7c, 0x10, 0x1f, 0x73, 0xb4, + 0x5f, 0xdb, 0x4f, 0x05, 0xe7, 0xfc, 0x9e, 0x35, + 0x48, 0xd8, 0xc8, 0xf5, 0xac, 0x6d, 0xb4, 0xb0, + 0xd4, 0xf7, 0x69, 0x0f, 0x30, 0x78, 0xbb, 0x55, + 0x67, 0x66, 0x66, 0x05, 0xf4, 0x77, 0xe2, 0x30, + 0xa5, 0x94, 0x10, 0xa3, 0xcb, 0xee, 0x13, 0x9f, + 0x47, 0x1b, 0x2e, 0xf9, 0xfd, 0x94, 0x09, 0xbd, + 0x26, 0x6e, 0x84, 0xc7, 0x5c, 0x42, 0x20, 0x76, + 0x72, 0x83, 0x75, 0x68, 0xa4, 0x18, 0x2d, 0x76, + 0x62, 0xc3, 0xab, 0xc0, 0xc9, 0x36, 0x59, 0xe0, + 0xa9, 0x70, 0x1f, 0xff, 0x97, 0x07, 0x0d, 0x88, + 0xc2, 0xd8, 0x51, 0x35, 0xf7, 0xb0, 0x50, 0xe4, + 0x9f, 0x3d, 0xd4, 0x71, 0x8b, 0x40, 0x89, 0x71, + 0x6c, 0xd8, 0xc2, 0x63, 0xb6, 0x3a, 0xce, 0xb1, + 0x32, 0xf1, 0xc6, 0x11, 0x31, 0x25, 0x48, 0xcf, + 0xeb, 0xbc, 0xd3, 0x9b, 0xc5, 0xbd, 0xd2, 0x57, + 0x73, 0x9b, 0x20, 0xb8, 0xdf, 0xbe, 0xb8, 0x40, + 0xb6, 0xac, 0x24, 0xdb, 0x94, 0x6a, 0x93, 0x43, + 0x4a, 0xa8, 0xa3, 0xcf, 0xd5, 0x61, 0x1b, 0x46, + 0x1d, 0x6f, 0x57, 0xec, 0xa6, 0xd0, 0x44, 0x05, + 0x48, 0xb8, 0x90, 0x80, 0x23, 0x8e, 0x5f, 0xb0, + 0x4b, 0x6f, 0xe3, 0xf9, 0xb0, 0x04, 0x60, 0xae, + 0x80, 0xcf, 0xa5, 0x5c, 0x11, 0xe4, 0xce, 0x57, + 0x5b, 0xbb, 0xde, 0x92, 0xfc, 0xe7, 0x3f, 0xe0, + 0xfc, 0x06, 0xc8, 0xf3, 0x8c, 0xac, 0x86, 0x09, + 0x31, 0xe5, 0x7e, 0xfb, 0x5d, 0xa7, 0x57, 0xf8, + 0x1d, 0x23, 0x9d, 0xa3, 0xeb, 0x53, 0x28, 0xde, + 0xbf, 0x53, 0xef, 0x35, 0x3c, 0x7e, 0x3c, 0x1b, + 0x76, 0x9d, 0x09, 0x25, 0x43, 0xd4, 0x8b, 0xca, + 0xda, 0x45, 0x5b, 0xdc, 0x9f, 0x57, 0x5a, 0x30, + 0x2e, 0xe9, 0x73, 0x68, 0x28, 0xfa, 0x40, 0xb0, + 0x7c, 0x31, 0xd7, 0x8b, 0x4e, 0x99, 0x94, 0xf1, +}; + +static const uint8_t exp_ciphertext_rsa2048_pkcs1[] = { + 0xa5, 0x19, 0x19, 0x34, 0xad, 0xf6, 0xd2, 0xbe, + 0xed, 0x8f, 0xe5, 0xfe, 0xa2, 0xa5, 0x20, 0x08, + 0x15, 0x53, 0x7c, 0x68, 0x28, 0xae, 0x07, 0xb2, + 0x4c, 0x5d, 0xee, 0xc1, 0xc6, 0xdc, 0xd6, 0x8b, + 0xc6, 0xba, 0x46, 0xe1, 0x16, 0xa9, 0x04, 0x72, + 0xdf, 0x8f, 0x1e, 0x97, 0x2a, 0x55, 0xe7, 0xac, + 0x08, 0x0d, 0x61, 0xe8, 0x64, 0x8b, 0x6f, 0x96, + 0x0e, 0xbb, 0x8a, 0x30, 0xb3, 0x73, 0x28, 0x61, + 0x16, 0x89, 0x90, 0x88, 0x8e, 0xda, 0x22, 0xe6, + 0x42, 0x16, 0xc7, 0xe8, 0x30, 0x0d, 0x7f, 0x44, + 0x1e, 0xef, 0xe6, 0xdb, 0x78, 0x54, 0x89, 0xa5, + 0x60, 0x67, 0xb3, 0x35, 0x2d, 0x79, 0x49, 0xcf, + 0xe6, 0x8f, 0xf3, 0x64, 0x52, 0x1c, 0x6c, 0x43, + 0x7e, 0xb0, 0xde, 0x55, 0xdf, 0xbe, 0xb7, 0xb1, + 0xdb, 0x02, 0xee, 0x76, 0x96, 0xcc, 0x0b, 0x97, + 0x8c, 0x23, 0xaa, 0x7d, 0x4c, 0x47, 0x28, 0x41, + 0x7a, 0x20, 0x39, 0x1f, 0x64, 0x0b, 0xf1, 0x74, + 0xf1, 0x29, 0xda, 0xe9, 0x3a, 0x36, 0xa6, 0x88, + 0xb8, 0xc0, 0x21, 0xb8, 0x9b, 0x5d, 0x90, 0x85, + 0xa3, 0x30, 0x61, 0x17, 0x8c, 0x74, 0x63, 0xd5, + 0x0f, 0x95, 0xdc, 0xc8, 0x4f, 0xa7, 0x24, 0x55, + 0x40, 0xe2, 0x84, 0x57, 0x65, 0x06, 0x11, 0x30, + 0x2b, 0x9e, 0x32, 0x95, 0x39, 0xf2, 0x1a, 0x3f, + 0xab, 0xcd, 0x7b, 0x7f, 0x9c, 0xf0, 0x00, 0x50, + 0x7c, 0xf4, 0xbe, 0xcb, 0x80, 0xea, 0x66, 0xba, + 0x0e, 0x7b, 0x46, 0x0b, 0x25, 0xe0, 0xc1, 0x03, + 0x29, 0x11, 0x2d, 0x69, 0x4f, 0x21, 0xa2, 0x58, + 0x37, 0x4b, 0x84, 0x15, 0xb3, 0x65, 0x3a, 0xac, + 0xd4, 0xd0, 0xf6, 0xdf, 0x4b, 0x82, 0xca, 0x9e, + 0xbb, 0xbe, 0x3c, 0x4d, 0xd5, 0xbf, 0x00, 0xd6, + 0x12, 0x48, 0x72, 0x0b, 0xc7, 0xf8, 0xe1, 0xcd, + 0xd0, 0x28, 0x03, 0x19, 0xa6, 0x06, 0x13, 0x45, +}; + +static const uint8_t rsa_private_key_lack_element[] = { + /* RSAPrivateKey, offset: 0, length: 176 */ + 0x30, 0x81, 0xb0, + /* version, offset: 4, length: 1 */ + 0x02, 0x01, 0x00, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e, offset: 74, length: 3 */ + 0x02, 0x03, 0x01, 0x00, 0x01, + /* d, offset: 79, length: 64 */ + 0x02, 0x40, + 0x1e, 0x80, 0xfe, 0xda, 0x65, 0xdb, 0x70, 0xb8, + 0x61, 0x91, 0x28, 0xbf, 0x6c, 0x32, 0xc1, 0x05, + 0xd1, 0x26, 0x6a, 0x1c, 0x83, 0xcc, 0xf4, 0x1f, + 0x53, 0x42, 0x72, 0x1f, 0x62, 0x57, 0x0a, 0xc4, + 0x66, 0x76, 0x30, 0x87, 0xb9, 0xb1, 0xb9, 0x6a, + 0x63, 0xfd, 0x8f, 0x3e, 0xfc, 0x35, 0x3f, 0xd6, + 0x2e, 0x6c, 0xc8, 0x70, 0x8a, 0x17, 0xc1, 0x28, + 0x6a, 0xfe, 0x51, 0x56, 0xb3, 0x92, 0x6f, 0x09, + /* p, offset: 145, length: 33 */ + 0x02, 0x21, + 0x00, 0xe3, 0x2e, 0x2d, 0x8d, 0xba, 0x1c, 0x34, + 0x4c, 0x49, 0x9f, 0xc1, 0xa6, 0xdd, 0xd7, 0x13, + 0x8d, 0x05, 0x48, 0xdd, 0xff, 0x5c, 0x30, 0xbc, + 0x6b, 0xc4, 0x18, 0x9d, 0xfc, 0xa2, 0xd0, 0x9b, + 0x4d, + /* q, offset: 180, length: 33 */ + 0x02, 0x21, + 0x00, 0xd1, 0x75, 0xaf, 0x4b, 0xc6, 0x1a, 0xb0, + 0x98, 0x14, 0x42, 0xae, 0x33, 0xf3, 0x44, 0xde, + 0x21, 0xcb, 0x04, 0xda, 0xfb, 0x1e, 0x35, 0x92, + 0xcd, 0x69, 0xc0, 0x83, 0x06, 0x83, 0x8e, 0x39, + 0x53, + /* lack element: dp, dq, u */ +}; + +static const uint8_t rsa_public_key_lack_element[] = { + /* RSAPublicKey, offset: 0, length: 67 */ + 0x30, 0x81, 0x43, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* lack element: e */ +}; + +static const uint8_t rsa_public_key_empty_element[] = { + /* RSAPublicKey, offset: 0, length: 69 */ + 0x30, 0x81, 0x45, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e: empty element */ + 0x02, 0x00, +}; + +static const uint8_t rsa_private_key_empty_element[] = { + /* RSAPrivateKey, offset: 0, length: 19 */ + 0x30, 0x81, 0x13, + /* version, offset: 4, length: 1 */ + 0x02, 0x01, 0x00, + /* n: empty element */ + 0x02, 0x00, + /* e: empty element */ + 0x02, 0x00, + /* d: empty element */ + 0x02, 0x00, + /* p: empty element */ + 0x02, 0x00, + /* q: empty element */ + 0x02, 0x00, + /* dp: empty element */ + 0x02, 0x00, + /* dq: empty element */ + 0x02, 0x00, + /* u: empty element */ + 0x02, 0x00, +}; + +static const uint8_t rsa_public_key_invalid_length_val[] = { + /* RSAPublicKey, INVALID length: 313 */ + 0x30, 0x82, 0x01, 0x39, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e, */ + 0x02, 0x03, 0x01, 0x00, 0x01, /* INTEGER, offset: 74, length: 3 */ +}; + +static const uint8_t rsa_public_key_extra_elem[] = { + /* RSAPublicKey, length: 80 */ + 0x30, 0x81, 0x50, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e, offset: 74, length: 3 */ + 0x02, 0x03, 0x01, 0x00, 0x01, + /* Additional integer field, length 3 */ + 0x02, 0x06, 0xe1, 0x22, 0xdb, 0xe1, 0x22, 0xdb, +}; + +typedef struct QCryptoRSAKeyTestData QCryptoRSAKeyTestData; +struct QCryptoRSAKeyTestData { + const char *path; + QCryptoAkCipherKeyType key_type; + QCryptoAkCipherOptions opt; + const uint8_t *key; + size_t keylen; + bool is_valid_key; + size_t exp_key_len; +}; + +typedef struct QCryptoAkCipherTestData QCryptoAkCipherTestData; +struct QCryptoAkCipherTestData { + const char *path; + QCryptoAkCipherOptions opt; + + const uint8_t *priv_key; + size_t priv_key_len; + const uint8_t *pub_key; + size_t pub_key_len; + + const uint8_t *plaintext; + size_t plen; + const uint8_t *ciphertext; + size_t clen; + const uint8_t *dgst; + size_t dlen; + const uint8_t *signature; + size_t slen; +}; + +static QCryptoRSAKeyTestData rsakey_test_data[] = { + { + .path = "/crypto/akcipher/rsakey-1024-public", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa1024_public_key, + .keylen = sizeof(rsa1024_public_key), + .is_valid_key = true, + .exp_key_len = 128, + }, + { + .path = "/crypto/akcipher/rsakey-1024-private", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa1024_private_key, + .keylen = sizeof(rsa1024_private_key), + .is_valid_key = true, + .exp_key_len = 128, + }, + { + .path = "/crypto/akcipher/rsakey-2048-public", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa2048_public_key, + .keylen = sizeof(rsa2048_public_key), + .is_valid_key = true, + .exp_key_len = 256, + }, + { + .path = "/crypto/akcipher/rsakey-2048-private", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa2048_private_key, + .keylen = sizeof(rsa2048_private_key), + .is_valid_key = true, + .exp_key_len = 256, + }, + { + .path = "/crypto/akcipher/rsakey-public-lack-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_lack_element, + .keylen = sizeof(rsa_public_key_lack_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-private-lack-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa_private_key_lack_element, + .keylen = sizeof(rsa_private_key_lack_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-empty-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_empty_element, + .keylen = sizeof(rsa_public_key_empty_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-private-empty-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa_private_key_empty_element, + .keylen = sizeof(rsa_private_key_empty_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-empty-key", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = NULL, + .keylen = 0, + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-private-empty-key", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = NULL, + .keylen = 0, + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-invalid-length-val", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_invalid_length_val, + .keylen = sizeof(rsa_public_key_invalid_length_val), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-extra-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_extra_elem, + .keylen = sizeof(rsa_public_key_extra_elem), + .is_valid_key = false, + }, +}; + +static QCryptoAkCipherTestData akcipher_test_data[] = { + /* rsa1024 with raw padding */ + { + .path = "/crypto/akcipher/rsa1024-raw", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW, + }, + }, + .pub_key = rsa1024_public_key, + .pub_key_len = sizeof(rsa1024_public_key), + .priv_key = rsa1024_private_key, + .priv_key_len = sizeof(rsa1024_private_key), + + .plaintext = test_plaintext, + .plen = 128, + .ciphertext = exp_ciphertext_rsa1024_raw, + .clen = sizeof(exp_ciphertext_rsa1024_raw), + }, + + /* rsa1024 with pkcs1 padding */ + { + .path = "/crypto/akcipher/rsa1024-pkcs1", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + }, + }, + .pub_key = rsa1024_public_key, + .pub_key_len = sizeof(rsa1024_public_key), + .priv_key = rsa1024_private_key, + .priv_key_len = sizeof(rsa1024_private_key), + + .plaintext = test_plaintext, + .plen = 64, + .ciphertext = exp_ciphertext_rsa1024_pkcs1, + .clen = sizeof(exp_ciphertext_rsa1024_pkcs1), + .dgst = test_sha1_dgst, + .dlen = sizeof(test_sha1_dgst), + .signature = exp_signature_rsa1024_pkcs1, + .slen = sizeof(exp_signature_rsa1024_pkcs1), + }, + + /* rsa2048 with raw padding */ + { + .path = "/crypto/akcipher/rsa2048-raw", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW, + }, + }, + .pub_key = rsa2048_public_key, + .pub_key_len = sizeof(rsa2048_public_key), + .priv_key = rsa2048_private_key, + .priv_key_len = sizeof(rsa2048_private_key), + + .plaintext = test_plaintext, + .plen = 256, + .ciphertext = exp_ciphertext_rsa2048_raw, + .clen = sizeof(exp_ciphertext_rsa2048_raw), + }, + + /* rsa2048 with pkcs1 padding */ + { + .path = "/crypto/akcipher/rsa2048-pkcs1", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + }, + }, + .pub_key = rsa2048_public_key, + .pub_key_len = sizeof(rsa2048_public_key), + .priv_key = rsa2048_private_key, + .priv_key_len = sizeof(rsa2048_private_key), + + .plaintext = test_plaintext, + .plen = 128, + .ciphertext = exp_ciphertext_rsa2048_pkcs1, + .clen = sizeof(exp_ciphertext_rsa2048_pkcs1), + .dgst = test_sha1_dgst, + .dlen = sizeof(test_sha1_dgst), + .signature = exp_signature_rsa2048_pkcs1, + .slen = sizeof(exp_signature_rsa2048_pkcs1), + }, + +}; + +static void test_akcipher(const void *opaque) +{ + const QCryptoAkCipherTestData *data = opaque; + g_autofree uint8_t *plaintext = NULL; + g_autofree uint8_t *ciphertext = NULL; + g_autofree uint8_t *signature = NULL; + QCryptoAkCipher *pub_key, *priv_key; + + if (!qcrypto_akcipher_supports((QCryptoAkCipherOptions *)&data->opt)) { + return; + } + pub_key = qcrypto_akcipher_new(&data->opt, + QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + data->pub_key, data->pub_key_len, + &error_abort); + g_assert(pub_key != NULL); + priv_key = qcrypto_akcipher_new(&data->opt, + QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + data->priv_key, data->priv_key_len, + &error_abort); + g_assert(priv_key != NULL); + + if (data->plaintext != NULL) { + + ciphertext = g_new0(uint8_t, data->clen); + g_assert(qcrypto_akcipher_encrypt(pub_key, data->plaintext, data->plen, + ciphertext, data->clen, + &error_abort) > 0); + + /** + * In the asymmetric encryption algorithms, the ciphertext generated + * each time may be different, here only compare the decrypted + * plaintext + */ + plaintext = g_new0(uint8_t, data->clen); + g_assert(qcrypto_akcipher_decrypt(priv_key, ciphertext, + data->clen, plaintext, + data->plen, + &error_abort) == data->plen); + g_assert(!memcmp(plaintext, data->plaintext, data->plen)); + } + + if (data->signature != NULL) { + signature = g_new(uint8_t, data->slen); + g_assert(qcrypto_akcipher_sign(priv_key, data->dgst, data->dlen, + signature, data->slen, + &error_abort) > 0); + /** + * The signature generated each time may be different, here only check + * the verification. + */ + g_assert(qcrypto_akcipher_verify(pub_key, data->signature, data->slen, + data->dgst, data->dlen, + &error_abort) == 0); + g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen, + data->dgst, data->dlen, + &error_abort) == 0); + ++signature[0]; + /* Here error should be ignored */ + g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen, + data->dgst, data->dlen, NULL) != 0); + } + + qcrypto_akcipher_free(pub_key); + qcrypto_akcipher_free(priv_key); +} + +static void test_rsakey(const void *opaque) +{ + const QCryptoRSAKeyTestData *data = (const QCryptoRSAKeyTestData *)opaque; + QCryptoAkCipherOptions opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + } + }; + g_autoptr(QCryptoAkCipher) key = qcrypto_akcipher_new( + &opt, data->key_type, data->key, data->keylen, NULL); + + if (!qcrypto_akcipher_supports(&opt)) { + return; + } + + if (!data->is_valid_key) { + g_assert(key == NULL); + return; + } + + g_assert(key != NULL); + g_assert(qcrypto_akcipher_max_ciphertext_len(key) == data->exp_key_len); + g_assert(qcrypto_akcipher_max_plaintext_len(key) == data->exp_key_len); + g_assert(qcrypto_akcipher_max_signature_len(key) == data->exp_key_len); + g_assert(qcrypto_akcipher_max_dgst_len(key) == data->exp_key_len); +} + +int main(int argc, char **argv) +{ + size_t i; + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(akcipher_test_data); i++) { + g_test_add_data_func(akcipher_test_data[i].path, + &akcipher_test_data[i], + test_akcipher); + } + for (i = 0; i < G_N_ELEMENTS(rsakey_test_data); i++) { + g_test_add_data_func(rsakey_test_data[i].path, + &rsakey_test_data[i], + test_rsakey); + } + + return g_test_run(); +} diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c index 3b1f0d509fa5..347cd5f3d79d 100644 --- a/tests/unit/test-crypto-block.c +++ b/tests/unit/test-crypto-block.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "crypto/init.h" #include "crypto/block.h" +#include "crypto/block-luks-priv.h" #include "qemu/buffer.h" #include "qemu/module.h" #include "crypto/secret.h" @@ -30,7 +31,8 @@ #endif #if (defined(_WIN32) || defined RUSAGE_THREAD) && \ - (defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)) + (defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT) || \ + defined(CONFIG_GNUTLS_CRYPTO)) #define TEST_LUKS #else #undef TEST_LUKS @@ -39,7 +41,6 @@ static QCryptoBlockCreateOptions qcow_create_opts = { .format = Q_CRYPTO_BLOCK_FORMAT_QCOW, .u.qcow = { - .has_key_secret = true, .key_secret = (char *)"sec0", }, }; @@ -47,7 +48,6 @@ static QCryptoBlockCreateOptions qcow_create_opts = { static QCryptoBlockOpenOptions qcow_open_opts = { .format = Q_CRYPTO_BLOCK_FORMAT_QCOW, .u.qcow = { - .has_key_secret = true, .key_secret = (char *)"sec0", }, }; @@ -57,7 +57,6 @@ static QCryptoBlockOpenOptions qcow_open_opts = { static QCryptoBlockOpenOptions luks_open_opts = { .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, .u.luks = { - .has_key_secret = true, .key_secret = (char *)"sec0", }, }; @@ -67,7 +66,6 @@ static QCryptoBlockOpenOptions luks_open_opts = { static QCryptoBlockCreateOptions luks_create_opts_default = { .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, .u.luks = { - .has_key_secret = true, .key_secret = (char *)"sec0", }, }; @@ -77,7 +75,6 @@ static QCryptoBlockCreateOptions luks_create_opts_default = { static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = { .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, .u.luks = { - .has_key_secret = true, .key_secret = (char *)"sec0", .has_cipher_alg = true, .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, @@ -92,7 +89,6 @@ static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = { static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_essiv = { .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, .u.luks = { - .has_key_secret = true, .key_secret = (char *)"sec0", .has_cipher_alg = true, .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, @@ -188,12 +184,12 @@ static struct QCryptoBlockTestData { }; -static ssize_t test_block_read_func(QCryptoBlock *block, - size_t offset, - uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp) +static int test_block_read_func(QCryptoBlock *block, + size_t offset, + uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) { Buffer *header = opaque; @@ -201,14 +197,14 @@ static ssize_t test_block_read_func(QCryptoBlock *block, memcpy(buf, header->buffer + offset, buflen); - return buflen; + return 0; } -static ssize_t test_block_init_func(QCryptoBlock *block, - size_t headerlen, - void *opaque, - Error **errp) +static int test_block_init_func(QCryptoBlock *block, + size_t headerlen, + void *opaque, + Error **errp) { Buffer *header = opaque; @@ -216,16 +212,16 @@ static ssize_t test_block_init_func(QCryptoBlock *block, buffer_reserve(header, headerlen); - return headerlen; + return 0; } -static ssize_t test_block_write_func(QCryptoBlock *block, - size_t offset, - const uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp) +static int test_block_write_func(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) { Buffer *header = opaque; @@ -234,7 +230,7 @@ static ssize_t test_block_write_func(QCryptoBlock *block, memcpy(header->buffer + offset, buf, buflen); header->offset = offset + buflen; - return buflen; + return 0; } @@ -344,6 +340,230 @@ static void test_block(gconstpointer opaque) } +#ifdef TEST_LUKS +typedef const char *(*LuksHeaderDoBadStuff)(QCryptoBlockLUKSHeader *hdr); + +static void +test_luks_bad_header(gconstpointer data) +{ + LuksHeaderDoBadStuff badstuff = data; + QCryptoBlock *blk; + Buffer buf; + Object *sec = test_block_secret(); + QCryptoBlockLUKSHeader hdr; + Error *err = NULL; + const char *msg; + + memset(&buf, 0, sizeof(buf)); + buffer_init(&buf, "header"); + + /* Correctly create the volume initially */ + blk = qcrypto_block_create(&luks_create_opts_default, NULL, + test_block_init_func, + test_block_write_func, + &buf, + &error_abort); + g_assert(blk); + + qcrypto_block_free(blk); + + /* Mangle it in some unpleasant way */ + g_assert(buf.offset >= sizeof(hdr)); + memcpy(&hdr, buf.buffer, sizeof(hdr)); + qcrypto_block_luks_to_disk_endian(&hdr); + + msg = badstuff(&hdr); + + qcrypto_block_luks_from_disk_endian(&hdr); + memcpy(buf.buffer, &hdr, sizeof(hdr)); + + /* Check that we fail to open it again */ + blk = qcrypto_block_open(&luks_open_opts, NULL, + test_block_read_func, + &buf, + 0, + 1, + &err); + g_assert(!blk); + g_assert(err); + + g_assert_cmpstr(error_get_pretty(err), ==, msg); + error_free(err); + + object_unparent(sec); + + buffer_free(&buf); +} + +static const char *luks_bad_null_term_cipher_name(QCryptoBlockLUKSHeader *hdr) +{ + /* Replace NUL termination with spaces */ + char *offset = hdr->cipher_name + strlen(hdr->cipher_name); + memset(offset, ' ', sizeof(hdr->cipher_name) - (offset - hdr->cipher_name)); + + return "LUKS header cipher name is not NUL terminated"; +} + +static const char *luks_bad_null_term_cipher_mode(QCryptoBlockLUKSHeader *hdr) +{ + /* Replace NUL termination with spaces */ + char *offset = hdr->cipher_mode + strlen(hdr->cipher_mode); + memset(offset, ' ', sizeof(hdr->cipher_mode) - (offset - hdr->cipher_mode)); + + return "LUKS header cipher mode is not NUL terminated"; +} + +static const char *luks_bad_null_term_hash_spec(QCryptoBlockLUKSHeader *hdr) +{ + /* Replace NUL termination with spaces */ + char *offset = hdr->hash_spec + strlen(hdr->hash_spec); + memset(offset, ' ', sizeof(hdr->hash_spec) - (offset - hdr->hash_spec)); + + return "LUKS header hash spec is not NUL terminated"; +} + +static const char *luks_bad_cipher_name_empty(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_name, "", 1); + + return "Algorithm '' with key size 32 bytes not supported"; +} + +static const char *luks_bad_cipher_name_unknown(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_name, "aess", 5); + + return "Algorithm 'aess' with key size 32 bytes not supported"; +} + +static const char *luks_bad_cipher_xts_size(QCryptoBlockLUKSHeader *hdr) +{ + hdr->master_key_len = 33; + + return "XTS cipher key length should be a multiple of 2"; +} + +static const char *luks_bad_cipher_cbc_size(QCryptoBlockLUKSHeader *hdr) +{ + hdr->master_key_len = 33; + memcpy(hdr->cipher_mode, "cbc-essiv", 10); + + return "Algorithm 'aes' with key size 33 bytes not supported"; +} + +static const char *luks_bad_cipher_mode_empty(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "", 1); + + return "Unexpected cipher mode string format ''"; +} + +static const char *luks_bad_cipher_mode_unknown(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "xfs", 4); + + return "Unexpected cipher mode string format 'xfs'"; +} + +static const char *luks_bad_ivgen_separator(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "xts:plain64", 12); + + return "Unexpected cipher mode string format 'xts:plain64'"; +} + +static const char *luks_bad_ivgen_name_empty(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "xts-", 5); + + return "IV generator '' not supported"; +} + +static const char *luks_bad_ivgen_name_unknown(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "xts-plain65", 12); + + return "IV generator 'plain65' not supported"; +} + +static const char *luks_bad_ivgen_hash_empty(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "xts-plain65:", 13); + + return "Hash algorithm '' not supported"; +} + +static const char *luks_bad_ivgen_hash_unknown(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->cipher_mode, "xts-plain65:sha257", 19); + + return "Hash algorithm 'sha257' not supported"; +} + +static const char *luks_bad_hash_spec_empty(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->hash_spec, "", 1); + + return "Hash algorithm '' not supported"; +} + +static const char *luks_bad_hash_spec_unknown(QCryptoBlockLUKSHeader *hdr) +{ + memcpy(hdr->hash_spec, "sha2566", 8); + + return "Hash algorithm 'sha2566' not supported"; +} + +static const char *luks_bad_stripes(QCryptoBlockLUKSHeader *hdr) +{ + hdr->key_slots[0].stripes = 3999; + + return "Keyslot 0 is corrupted (stripes 3999 != 4000)"; +} + +static const char *luks_bad_key_overlap_header(QCryptoBlockLUKSHeader *hdr) +{ + hdr->key_slots[0].key_offset_sector = 2; + + return "Keyslot 0 is overlapping with the LUKS header"; +} + +static const char *luks_bad_key_overlap_key(QCryptoBlockLUKSHeader *hdr) +{ + hdr->key_slots[0].key_offset_sector = hdr->key_slots[1].key_offset_sector; + + return "Keyslots 0 and 1 are overlapping in the header"; +} + +static const char *luks_bad_key_overlap_payload(QCryptoBlockLUKSHeader *hdr) +{ + hdr->key_slots[0].key_offset_sector = hdr->payload_offset_sector + 42; + + return "Keyslot 0 is overlapping with the encrypted payload"; +} + +static const char *luks_bad_payload_overlap_header(QCryptoBlockLUKSHeader *hdr) +{ + hdr->payload_offset_sector = 2; + + return "LUKS payload is overlapping with the header"; +} + +static const char *luks_bad_key_iterations(QCryptoBlockLUKSHeader *hdr) +{ + hdr->key_slots[0].iterations = 0; + + return "Keyslot 0 iteration count is zero"; +} + +static const char *luks_bad_iterations(QCryptoBlockLUKSHeader *hdr) +{ + hdr->master_key_iterations = 0; + + return "LUKS key iteration count is zero"; +} +#endif + int main(int argc, char **argv) { gsize i; @@ -364,5 +584,79 @@ int main(int argc, char **argv) } } +#ifdef TEST_LUKS + if (g_test_slow()) { + g_test_add_data_func("/crypto/block/luks/bad/cipher-name-nul-term", + luks_bad_null_term_cipher_name, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-mode-nul-term", + luks_bad_null_term_cipher_mode, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/hash-spec-nul-term", + luks_bad_null_term_hash_spec, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-name-empty", + luks_bad_cipher_name_empty, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-name-unknown", + luks_bad_cipher_name_unknown, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-xts-size", + luks_bad_cipher_xts_size, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-cbc-size", + luks_bad_cipher_cbc_size, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-mode-empty", + luks_bad_cipher_mode_empty, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/cipher-mode-unknown", + luks_bad_cipher_mode_unknown, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/ivgen-separator", + luks_bad_ivgen_separator, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/ivgen-name-empty", + luks_bad_ivgen_name_empty, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/ivgen-name-unknown", + luks_bad_ivgen_name_unknown, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/ivgen-hash-empty", + luks_bad_ivgen_hash_empty, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/ivgen-hash-unknown", + luks_bad_ivgen_hash_unknown, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/hash-spec-empty", + luks_bad_hash_spec_empty, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/hash-spec-unknown", + luks_bad_hash_spec_unknown, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/stripes", + luks_bad_stripes, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/key-overlap-header", + luks_bad_key_overlap_header, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/key-overlap-key", + luks_bad_key_overlap_key, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/key-overlap-payload", + luks_bad_key_overlap_payload, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/payload-overlap-header", + luks_bad_payload_overlap_header, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/iterations", + luks_bad_iterations, + test_luks_bad_header); + g_test_add_data_func("/crypto/block/luks/bad/key-iterations", + luks_bad_key_iterations, + test_luks_bad_header); + } +#endif + return g_test_run(); } diff --git a/tests/unit/test-crypto-der.c b/tests/unit/test-crypto-der.c new file mode 100644 index 000000000000..d218a7f17023 --- /dev/null +++ b/tests/unit/test-crypto-der.c @@ -0,0 +1,372 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "crypto/der.h" + +/* rsa(512) private key, generated by openssl */ +static const uint8_t test_rsa512_priv_key[] = + "\x30\x82\x01\x39" /* SEQUENCE, offset: 0, length: 313 */ + "\x02\x01\x00" /* INTEGER, offset: 4, length: 1 */ + "\x02\x41" /* INTEGER, offset: 7, length: 65 */ + "\x00\xb9\xe1\x22\xdb\x56\x2f\xb6\xf7\xf0\x0a\x87\x43\x07\x12\xdb" + "\x6d\xb6\x2b\x41\x8d\x2c\x3c\xa5\xdd\x78\x9a\x8f\xab\x8e\xf2\x4a" + "\xc8\x34\x0c\x12\x4f\x11\x90\xc6\xc2\xa5\xd0\xcd\xfb\xfc\x2c\x95" + "\x56\x82\xdf\x39\xf3\x3b\x1d\x62\x26\x97\xb7\x93\x25\xc7\xec\x7e" + "\xf7" + "\x02\x03\x01\x00\x01" /* INTEGER, offset: 74, length: 3 */ + "\x02\x40" /* INTEGER, offset: 79, length: 64 */ + "\x1e\x80\xfe\xda\x65\xdb\x70\xb8\x61\x91\x28\xbf\x6c\x32\xc1\x05" + "\xd1\x26\x6a\x1c\x83\xcc\xf4\x1f\x53\x42\x72\x1f\x62\x57\x0a\xc4" + "\x66\x76\x30\x87\xb9\xb1\xb9\x6a\x63\xfd\x8f\x3e\xfc\x35\x3f\xd6" + "\x2e\x6c\xc8\x70\x8a\x17\xc1\x28\x6a\xfe\x51\x56\xb3\x92\x6f\x09" + "\x02\x21" /* INTEGER, offset: 145, length: 33 */ + "\x00\xe3\x2e\x2d\x8d\xba\x1c\x34\x4c\x49\x9f\xc1\xa6\xdd\xd7\x13" + "\x8d\x05\x48\xdd\xff\x5c\x30\xbc\x6b\xc4\x18\x9d\xfc\xa2\xd0\x9b" + "\x4d" + "\x02\x21" /* INTEGER, offset: 180, length: 33 */ + "\x00\xd1\x75\xaf\x4b\xc6\x1a\xb0\x98\x14\x42\xae\x33\xf3\x44\xde" + "\x21\xcb\x04\xda\xfb\x1e\x35\x92\xcd\x69\xc0\x83\x06\x83\x8e\x39" + "\x53" + "\x02\x20" /* INTEGER, offset: 215, length: 32 */ + "\x68\x8d\x2a\xf7\xcb\xcc\x09\x21\x86\xcc\x98\x21\xc4\x7c\xa4\x09" + "\xc5\x81\xd8\x71\x1a\x2b\x6f\xbb\xa4\xde\xb3\x6e\xbe\x3b\x85\x0d" + "\x02\x20" /* INTEGER, offset: 249, length: 32 */ + "\x64\x06\x0e\xef\xe0\x6a\x5e\x6a\x41\x42\x96\x6d\xb8\x7d\xea\x95" + "\xb8\x9d\x58\xf5\x12\x38\x03\x22\x94\x9d\x99\xf4\x42\x5e\x68\x81" + "\x02\x20" /* INTEGER, offset: 283, length: 32 */ + "\x7f\x1d\x87\xe8\x55\x30\x75\xc7\x29\xec\xc9\x65\x76\x5a\x6a\xa3" + "\x4a\x6e\xe1\x26\x65\xd1\x76\xd5\xb9\xd1\x8b\xa8\x73\xe2\x6a\x9e"; + +static const uint8_t test_rsa2048_priv_key[] = + "\x30\x82\x04\xa6" /* SEQUENCE, offset: 0, length 1190 */ + "\x02\x01\x00" /* INTEGER, offset: 4, length: 1 */ + "\x02\x82\x01\x01" /* INTEGER, offset: 7, length: 257 */ + "\x00\xd1\x48\xc2\xc1\x1d\x4f\x94\xf2\xbb\x9b\xe2\x2d\xe1\xea\x4c" + "\xce\x41\x72\xe3\x41\x7e\x9d\x91\x85\xa3\x4e\xe1\x2c\xf6\x52\x6d" + "\xf9\x84\x64\xdf\x87\x28\x4a\xc9\x9d\x78\x93\x47\xc8\xd9\x66\x2e" + "\xf4\xc6\xf0\x32\x15\x1a\xe8\xaf\x5a\xca\x3a\xd3\x3e\xf6\xde\x86" + "\xdd\x9b\xa6\x4d\x74\x58\xf0\x11\x7f\x66\xd5\x1c\xd8\xde\xa3\xf8" + "\xa3\xfc\x33\x55\x89\xa9\xc3\xea\x5b\x2e\x31\x06\xf8\xcb\x9e\x6e" + "\xb2\x68\x0d\xe6\xc3\x5c\x2d\xf8\xa2\xbd\x00\x1a\xf6\xb6\xdd\x14" + "\x8d\x11\x6d\x2d\xc6\x0c\x09\xe6\xf6\xb9\x8b\x87\x4c\x9f\x4d\x63" + "\xd3\x94\xf4\x32\xca\xcf\x5e\xbf\xe2\x7f\x73\x5a\x65\xec\x82\x0d" + "\x7f\x30\x25\x03\xd4\x3a\xff\xa2\xe8\xd6\xb5\x1f\x4f\x36\x64\x61" + "\xc3\x5f\xb2\x9e\x0c\x53\x04\x19\x34\x99\xe8\xe3\xe6\xd3\x2f\x45" + "\x58\x8e\x5d\x54\x5a\xa0\xc0\x5e\x51\x9b\x22\x15\xec\x26\x6f\x72" + "\x68\xe9\xbf\x5d\x1d\xb5\xd9\xe4\x81\x1a\x92\x66\xa8\xcb\x73\x46" + "\xab\x96\x7b\xf8\x9c\xf5\xb5\x9e\x2b\x13\x71\xe0\x01\x0c\x59\x1b" + "\x63\x9f\xb7\xd1\xcd\x47\x8e\xc7\x3a\xbe\xcb\x47\xa7\x23\x43\xa7" + "\x7d\xbd\x2c\x4e\x22\x37\xcc\xf9\x1b\x1b\xbb\xed\xec\xf0\x47\x92" + "\x43" + "\x02\x03\x01\x00\x01" /* INTEGER, offset 268, length 3 */ + "\x02\x82\x01\x01" /* INTEGER, offset 273, length 257 */ + "\x00\x8d\x21\x97\x0c\x29\x9a\xf8\x23\xf4\x76\x3b\xc1\x9b\x3e\xa8" + "\x8a\xd2\xc2\x0a\x14\xa9\xb0\xd2\x68\x9f\x67\x5b\x1c\x3a\x03\xfe" + "\x5b\xac\x77\x65\xf1\xbc\x2f\x2a\xe5\x01\x61\xb8\x9f\xee\x53\x25" + "\x49\x36\x3a\xd6\x5b\x3b\x29\x3c\xcf\x69\xde\xdf\x83\xef\x70\xc2" + "\xdc\x00\xd1\xd6\x1b\xa6\xba\x45\xe2\x77\x53\x31\xbf\xe1\xec\x0b" + "\x89\x72\x52\x9f\xd5\x54\xe1\x64\x52\x16\xc5\x43\x21\x56\x16\xc2" + "\x29\x97\x58\x00\x8d\x2f\xc5\x64\x8d\x42\x0d\x27\x21\xc6\xd1\x31" + "\xc1\xab\xc5\xc7\x7f\x6d\xb0\xe3\xca\xef\xf6\xf2\xc7\xae\x09\xbf" + "\x4d\xc0\x4e\x90\x2c\x28\xb9\xcc\x22\x74\xf2\xd5\xff\x4d\x86\xf6" + "\xec\x45\x1f\xbf\x25\x4c\x30\x26\x76\x4f\x09\x13\x83\xef\x35\x73" + "\xa3\xa2\xb1\x40\xcf\x07\x7a\x83\xae\xea\x00\xea\x74\xc7\x54\x6a" + "\x88\x19\xed\x35\xd3\x7e\x5e\xac\x51\xc1\x1e\x5e\x2c\x57\x72\x20" + "\x10\x6a\x0c\x47\xe1\xf0\x36\x70\xd2\xa7\x57\x64\x47\x46\x9f\xca" + "\x23\x8a\x48\x50\x1d\x33\x6a\x86\x46\x69\xed\x54\x65\x6b\x9e\xab" + "\x1f\x84\x87\xf4\x92\x8a\x6c\x44\x20\xaa\x8d\xd8\x50\xde\x45\x74" + "\xe0\xa8\xc7\xb9\x38\x74\x24\x51\x33\xf0\x39\x54\x6c\x11\xae\xc2" + "\x29" + "\x02\x81\x81" /* INTEGER, offset 534, length 129 */ + "\x00\xe8\x26\xd1\xf9\xa0\xd3\x0e\x3f\x2f\x89\x9b\x94\x16\x12\xd1" + "\xae\x3c\x53\x9c\xcf\xc6\xf7\x03\xf5\xdf\x39\xdc\x25\x5d\xcb\xb8" + "\xb9\x74\x3e\x3b\x36\xf6\xa0\x8d\xb1\x0e\xd8\xfe\x8c\xcd\x01\x13" + "\x77\x73\x08\x0f\x32\xbd\xe6\x95\xdc\xd0\x14\x7d\x44\xdc\x3e\xd9" + "\xaa\x8a\x32\xe6\x0e\x76\xb6\x05\xc5\x6b\x87\x78\x9a\x32\xe2\xf8" + "\x78\xba\x58\x75\x58\xd5\x26\x9d\x9a\x0f\xb6\xca\xb5\x27\xd8\x58" + "\xae\x3f\x49\x54\xd2\x2b\xac\x28\x39\x88\x31\x42\x12\x08\xea\x0b" + "\x39\x58\xae\xf3\x82\xa0\xe2\x75\x7c\x96\xa9\xb8\x57\x29\x6d\xd7" + "\x37" + "\x02\x81\x81" /* INTEGER, offset 666, length 129 */ + "\x00\xe6\xc8\x91\x50\x49\x97\x56\x70\x6e\x25\xf5\x77\x25\xa5\x41" + "\xfe\xd7\x25\x1b\xc1\x4a\xff\x37\x44\x2b\x46\xa0\xdf\xe8\x02\x09" + "\xdd\xa8\x41\xa1\x12\x84\x3c\xf8\xc2\x13\x3e\xb8\x4b\x22\x01\xac" + "\xa6\x09\xb2\xe9\xcd\xc8\x51\xee\xde\xa3\x1e\x6b\xfe\xb1\xf8\xb6" + "\x9e\x48\x36\x62\x0b\x05\xfa\x38\xc1\x06\x04\x58\x95\x4d\x25\x13" + "\x6d\x0b\x12\x0b\xc9\x6d\x59\xfc\x33\x03\x36\x01\x12\x09\x72\x74" + "\x5e\x98\x65\x66\x2f\x3a\xde\xd8\xd4\xee\x6f\x82\xe6\x36\x49\x12" + "\x6a\x94\x28\xe9\x28\x9e\xef\x29\xdc\xdf\xab\x94\x65\x02\x4e\x4b" + "\x55" + "\x02\x81\x81" /* INTEGER, offset 798, length 129 */ + "\x00\xc9\xda\xb7\x48\x6e\x66\x15\x45\x2b\x78\x63\x26\x67\xeb\x05" + "\x16\x92\xad\xc0\xf3\x88\xf4\xcf\x24\xc2\x6b\xf4\xd7\x28\xaf\x32" + "\x77\x4e\x73\xad\xd9\x24\xa8\x85\x8b\x26\x75\xd7\x1f\x66\x41\x41" + "\x43\xe3\x69\x66\x8d\xa0\x41\x16\x9d\x60\xef\xef\xdc\x28\x05\x1e" + "\x0e\x03\x0c\x2e\xac\xf4\xdb\x60\x39\x40\x3e\x12\xc7\x40\xe7\xc9" + "\x54\x6f\xf2\xea\x55\xcb\x40\x40\x58\xec\xc0\xeb\x90\x88\x8c\xbc" + "\xcf\x05\x88\x25\x90\x79\x18\xc0\x01\x06\x42\x8e\x48\x50\x27\xf0" + "\x8a\x74\x69\xea\xa1\xf2\x71\xf5\xe5\xd6\xba\xcb\xe6\x3d\xc7\x9c" + "\x11" + "\x02\x81\x81" /* INTEGER, offset 930, length 129 */ + "\x00\xc9\xf5\x04\xad\x34\xe9\x39\xdc\x83\x97\xb6\x3a\x40\xf8\x60" + "\x4b\x69\xec\xf0\x5f\xf3\x88\x69\xcd\xbe\xed\x3c\xc5\x14\x5c\x0c" + "\x54\x2b\xf4\xda\xc6\xc0\x70\x36\xe4\x67\x41\x00\xb7\xc7\x17\x9e" + "\x05\x63\x01\x6d\x77\x06\x71\x24\xcf\x32\x01\xe2\x51\xed\x5e\x90" + "\x38\xed\x4a\xa1\xfb\xb1\x8c\x69\xf4\x08\x96\xef\x0a\x20\x8b\x6c" + "\x77\x85\x33\x92\x9a\xff\x95\xba\x8c\xcd\xa7\x89\xc2\x46\x00\x21" + "\xf3\xd1\xfb\x12\x34\x0c\x99\x8d\x38\xb1\x3b\x66\x5a\x9d\x70\xce" + "\xab\xf3\xe1\xe5\x40\x05\xed\x97\x3d\xd1\x82\x6e\x07\x02\xc0\x8f" + "\x4d" + "\x02\x81\x81" /* INTEGER, offset 1062, length 129 */ + "\x00\xe4\x96\x79\xa8\x6a\x70\xdd\x67\x42\xff\x15\x11\x9e\x01\x71" + "\xac\xf1\x70\x7d\x87\xe2\x6e\x0c\x4d\xbb\x21\x15\xbb\xa7\x4e\x0c" + "\x09\x7e\x82\xca\x91\xbe\xd0\xdd\x9c\x8c\xb0\x77\x64\x30\x1b\x7e" + "\xbb\x69\xcb\x4c\xde\xd6\x6a\xb9\x72\x15\x79\xdc\x05\x99\x69\x8b" + "\x24\xa1\xad\x13\x35\x31\xc0\x0b\xf1\xd2\x06\x7c\x94\x1a\x21\x2f" + "\x02\xb9\xf0\xd0\xbb\xf7\xb7\x78\xf9\x3d\x76\x60\xd6\x6b\x5f\x35" + "\x88\x14\x33\xe6\xbc\xca\x6b\x88\x90\x57\x3b\x0c\xa3\x6e\x47\xdf" + "\x4e\x2f\x4c\xf9\xab\x97\x38\xe4\x20\x32\x32\x96\xc8\x9e\x79\xd3" + "\x12"; + +static const uint8_t test_ecdsa_p192_priv_key[] = + "\x30\x53" /* SEQUENCE, offset 0, length 83 */ + "\x02\x01\x01" /* INTEGER, offset 2, length 1 */ + "\x04\x18" /* OCTET STRING, offset 5, length 24 */ + "\xcb\xc8\x86\x0e\x66\x3c\xf7\x5a\x44\x13\xb8\xef\xea\x1d\x7b\xa6" + "\x1c\xda\xf4\x1b\xc7\x67\x6b\x35" + "\xa1\x34" /* CONTEXT SPECIFIC 1, offset 31, length 52 */ + "\x03\x32" /* BIT STRING, offset 33, length 50 */ + "\x00\x04\xc4\x16\xb3\xff\xac\xd5\x87\x98\xf7\xd9\x45\xfe\xd3\x5c" + "\x17\x9d\xb2\x36\x22\xcc\x07\xb3\x6d\x3c\x4e\x04\x5f\xeb\xb6\x52" + "\x58\xfb\x36\x10\x52\xb7\x01\x62\x0e\x94\x51\x1d\xe2\xef\x10\x82" + "\x88\x78"; + +static const uint8_t test_ecdsa_p256_priv_key[] = + "\x30\x77" /* SEQUENCE, offset 0, length 119 */ + "\x02\x01\x01" /* INTEGER, offset 2, length 1 */ + "\x04\x20" /* OCTET STRING, offset 5, length 32 */ + "\xf6\x92\xdd\x29\x1c\x6e\xef\xb6\xb2\x73\x9f\x40\x1b\xb3\x2a\x28" + "\xd2\x37\xd6\x4a\x5b\xe4\x40\x4c\x6a\x95\x99\xfa\xf7\x92\x49\xbe" + "\xa0\x0a" /* CONTEXT SPECIFIC 0, offset 39, length 10 */ + "\x06\x08" /* OID, offset 41, length 8 */ + "\x2a\x86\x48\xce\x3d\x03\x01\x07" + "\xa1\x44" /* CONTEXT SPECIFIC 1, offset 51, length 68 */ + "\x03\x42" /* BIT STRING, offset 53, length 66 */ + "\x00\x04\xed\x42\x9c\x67\x79\xbe\x46\x83\x88\x3e\x8c\xc1\x33\xf3" + "\xc3\xf6\x2c\xf3\x13\x6a\x00\xc2\xc9\x3e\x87\x7f\x86\x39\xe6\xae" + "\xe3\xb9\xba\x2f\x58\x63\x32\x62\x62\x54\x07\x27\xf9\x5a\x3a\xc7" + "\x3a\x6b\x5b\xbc\x0d\x33\xba\xbb\xd4\xa3\xff\x4f\x9e\xdd\xf5\x59" + "\xc0\xf6"; + +#define MAX_CHECKER_COUNT 32 + +static int qcrypto_wrapped_decode_ctx_tag0(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *opaque, + Error **errp) +{ + return qcrypto_der_decode_ctx_tag(data, dlen, 0, cb, opaque, errp); +} + +static int qcrypto_wrapped_decode_ctx_tag1(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *opaque, + Error **errp) +{ + return qcrypto_der_decode_ctx_tag(data, dlen, 1, cb, opaque, errp); +} + +typedef struct QCryptoAns1DecoderResultChecker QCryptoAns1DecoderResultChecker; +struct QCryptoAns1DecoderResultChecker { + int (*action) (const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *opaque, Error **errp); + QCryptoDERDecodeCb cb; + bool constructed; + const uint8_t *exp_value; + size_t exp_vlen; +}; + +typedef struct QCryptoAns1DecoderTestData QCryptoAns1DecoderTestData; +struct QCryptoAns1DecoderTestData { + const char *path; + const uint8_t *test_data; + size_t test_data_len; + QCryptoAns1DecoderResultChecker checker[MAX_CHECKER_COUNT]; +}; + +typedef struct QCryptoAns1DecoderTestContext QCryptoAns1DecoderTestContext; +struct QCryptoAns1DecoderTestContext { + const uint8_t *data; + size_t dlen; +}; + +static int checker_callback(void *opaque, const uint8_t *value, + size_t vlen, Error **errp) +{ + QCryptoAns1DecoderResultChecker *checker = + (QCryptoAns1DecoderResultChecker *)opaque; + + g_assert(value == checker->exp_value); + g_assert(vlen == checker->exp_vlen); + return 0; +} + +static void test_ans1(const void *opaque) +{ + const QCryptoAns1DecoderTestData *test_data = + (QCryptoAns1DecoderTestData *)opaque; + QCryptoAns1DecoderTestContext ctx[MAX_CHECKER_COUNT]; + int seq_depth = 0, checker_idx = 0; + ctx[seq_depth].data = test_data->test_data; + ctx[seq_depth].dlen = test_data->test_data_len; + bool all_checker_completed = false; + + do { + const QCryptoAns1DecoderResultChecker *checker = + &test_data->checker[checker_idx++]; + QCryptoAns1DecoderTestContext *c = &ctx[seq_depth]; + if (!checker->action) { + all_checker_completed = true; + break; + } + g_assert(checker->action(&c->data, &c->dlen, checker_callback, + (void *)checker, &error_abort) + == checker->exp_vlen); + if (checker->constructed) { + ++seq_depth; + ctx[seq_depth].data = checker->exp_value; + ctx[seq_depth].dlen = checker->exp_vlen; + } + while (seq_depth != 0 && ctx[seq_depth].dlen == 0) { + --seq_depth; + } + + } while (true); + g_assert(seq_depth == 0); + g_assert(ctx[seq_depth].dlen == 0); + g_assert(all_checker_completed); +} + +static QCryptoAns1DecoderTestData test_data[] = { +{ + .path = "/crypto/der/parse-rsa512-priv-key", + .test_data = test_rsa512_priv_key, + .test_data_len = sizeof(test_rsa512_priv_key) - 1, + .checker = { + { qcrypto_der_decode_seq, checker_callback, true, + test_rsa512_priv_key + 4, 313 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 4 + 2, 1 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 7 + 2, 65 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 74 + 2, 3 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 79 + 2, 64 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 145 + 2, 33 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 180 + 2, 33 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 215 + 2, 32 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 249 + 2, 32 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa512_priv_key + 283 + 2, 32 }, + }, +}, +{ + .path = "/crypto/der/parse-rsa2048-priv-key", + .test_data = test_rsa2048_priv_key, + .test_data_len = sizeof(test_rsa2048_priv_key) - 1, + .checker = { + { qcrypto_der_decode_seq, checker_callback, true, + test_rsa2048_priv_key + 4, 1190 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 4 + 2, 1 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 7 + 4, 257 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 268 + 2, 3 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 273 + 4, 257 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 534 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 666 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 798 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 930 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, false, + test_rsa2048_priv_key + 1062 + 3, 129 }, + }, +}, +{ + .path = "/crypto/der/parse-ecdsa-p192-priv-key", + .test_data = test_ecdsa_p192_priv_key, + .test_data_len = sizeof(test_ecdsa_p192_priv_key) - 1, + .checker = { + { qcrypto_der_decode_seq, checker_callback, true, + test_ecdsa_p192_priv_key + 2, 83 }, + { qcrypto_der_decode_int, checker_callback, false, + test_ecdsa_p192_priv_key + 2 + 2, 1 }, + { qcrypto_der_decode_octet_str, checker_callback, false, + test_ecdsa_p192_priv_key + 5 + 2, 24 }, + { qcrypto_wrapped_decode_ctx_tag1, checker_callback, true, + test_ecdsa_p192_priv_key + 31 + 2, 52 }, + { qcrypto_der_decode_bit_str , checker_callback, false, + test_ecdsa_p192_priv_key + 33 + 2, 50 }, + }, +}, +{ + .path = "/crypto/der/parse-ecdsa-p256-priv-key", + .test_data = test_ecdsa_p256_priv_key, + .test_data_len = sizeof(test_ecdsa_p256_priv_key) - 1, + .checker = { + { qcrypto_der_decode_seq, checker_callback, true, + test_ecdsa_p256_priv_key + 2, 119 }, + { qcrypto_der_decode_int, checker_callback, false, + test_ecdsa_p256_priv_key + 2 + 2, 1 }, + { qcrypto_der_decode_octet_str, checker_callback, false, + test_ecdsa_p256_priv_key + 5 + 2, 32 }, + { qcrypto_wrapped_decode_ctx_tag0, checker_callback, true, + test_ecdsa_p256_priv_key + 39 + 2, 10 }, + { qcrypto_der_decode_oid, checker_callback, false, + test_ecdsa_p256_priv_key + 41 + 2, 8 }, + { qcrypto_wrapped_decode_ctx_tag1, checker_callback, true, + test_ecdsa_p256_priv_key + 51 + 2, 68 }, + { qcrypto_der_decode_bit_str , checker_callback, false, + test_ecdsa_p256_priv_key + 53 + 2, 66 }, + }, +}, +}; + +int main(int argc, char **argv) +{ + size_t i; + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_ans1); + } + + return g_test_run(); +} diff --git a/tests/unit/test-crypto-tlscredsx509.c b/tests/unit/test-crypto-tlscredsx509.c index aab4149b564c..3c25d75ca1f3 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 5f0da9192c53..615a1344b4aa 100644 --- a/tests/unit/test-crypto-tlssession.c +++ b/tests/unit/test-crypto-tlssession.c @@ -90,8 +90,8 @@ static void test_crypto_tls_session_psk(void) * thread, so we need these non-blocking to avoid deadlock * of ourselves */ - qemu_set_nonblock(channel[0]); - qemu_set_nonblock(channel[1]); + qemu_socket_set_nonblock(channel[0]); + qemu_socket_set_nonblock(channel[1]); clientCreds = test_tls_creds_psk_create( QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, @@ -244,13 +244,13 @@ static void test_crypto_tls_session_x509(const void *opaque) * thread, so we need these non-blocking to avoid deadlock * of ourselves */ - qemu_set_nonblock(channel[0]); - qemu_set_nonblock(channel[1]); + qemu_socket_set_nonblock(channel[0]); + qemu_socket_set_nonblock(channel[1]); #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); @@ -512,12 +512,19 @@ int main(int argc, char **argv) false, true, "wiki.qemu.org", NULL); TEST_SESS_REG(altname4, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, false, "192.168.122.1", NULL); + TEST_SESS_REG(altname5, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, false, "fec0::dead:beaf", NULL); + + TEST_SESS_REG(altname6, cacertreq.filename, servercertalt2req.filename, clientcertreq.filename, false, true, "qemu.org", NULL); - TEST_SESS_REG(altname5, cacertreq.filename, + TEST_SESS_REG(altname7, cacertreq.filename, servercertalt2req.filename, clientcertreq.filename, false, false, "www.qemu.org", NULL); - TEST_SESS_REG(altname6, cacertreq.filename, + TEST_SESS_REG(altname8, cacertreq.filename, servercertalt2req.filename, clientcertreq.filename, false, false, "wiki.qemu.org", NULL); diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 98671f1ac30e..2126b463919b 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -2315,6 +2315,14 @@ static void test_qemu_strtosz_invalid(void) g_assert_cmpint(res, ==, 0xbaadf00d); g_assert(endptr == str); + /* No suffixes */ + str = "0x18M"; + endptr = NULL; + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); + g_assert_cmpint(res, ==, 0xbaadf00d); + g_assert(endptr == str); + /* No negative values */ str = "-0"; endptr = NULL; @@ -2450,6 +2458,76 @@ static void test_qemu_strtosz_metric(void) g_assert(endptr == str + 7); } +static void test_freq_to_str(void) +{ + char *str; + + str = freq_to_str(999); + g_assert_cmpstr(str, ==, "999 Hz"); + g_free(str); + + str = freq_to_str(1000); + g_assert_cmpstr(str, ==, "1 KHz"); + g_free(str); + + str = freq_to_str(1010); + g_assert_cmpstr(str, ==, "1.01 KHz"); + g_free(str); +} + +static void test_size_to_str(void) +{ + char *str; + + str = size_to_str(0); + g_assert_cmpstr(str, ==, "0 B"); + g_free(str); + + str = size_to_str(1); + g_assert_cmpstr(str, ==, "1 B"); + g_free(str); + + str = size_to_str(1016); + g_assert_cmpstr(str, ==, "0.992 KiB"); + g_free(str); + + str = size_to_str(1024); + g_assert_cmpstr(str, ==, "1 KiB"); + g_free(str); + + str = size_to_str(512ull << 20); + g_assert_cmpstr(str, ==, "512 MiB"); + g_free(str); +} + +static void test_iec_binary_prefix(void) +{ + g_assert_cmpstr(iec_binary_prefix(0), ==, ""); + g_assert_cmpstr(iec_binary_prefix(10), ==, "Ki"); + g_assert_cmpstr(iec_binary_prefix(20), ==, "Mi"); + g_assert_cmpstr(iec_binary_prefix(30), ==, "Gi"); + g_assert_cmpstr(iec_binary_prefix(40), ==, "Ti"); + g_assert_cmpstr(iec_binary_prefix(50), ==, "Pi"); + g_assert_cmpstr(iec_binary_prefix(60), ==, "Ei"); +} + +static void test_si_prefix(void) +{ + g_assert_cmpstr(si_prefix(-18), ==, "a"); + g_assert_cmpstr(si_prefix(-15), ==, "f"); + g_assert_cmpstr(si_prefix(-12), ==, "p"); + g_assert_cmpstr(si_prefix(-9), ==, "n"); + g_assert_cmpstr(si_prefix(-6), ==, "u"); + g_assert_cmpstr(si_prefix(-3), ==, "m"); + g_assert_cmpstr(si_prefix(0), ==, ""); + g_assert_cmpstr(si_prefix(3), ==, "K"); + g_assert_cmpstr(si_prefix(6), ==, "M"); + g_assert_cmpstr(si_prefix(9), ==, "G"); + g_assert_cmpstr(si_prefix(12), ==, "T"); + g_assert_cmpstr(si_prefix(15), ==, "P"); + g_assert_cmpstr(si_prefix(18), ==, "E"); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -2729,5 +2807,13 @@ int main(int argc, char **argv) g_test_add_func("/cutils/strtosz/metric", test_qemu_strtosz_metric); + g_test_add_func("/cutils/size_to_str", + test_size_to_str); + g_test_add_func("/cutils/freq_to_str", + test_freq_to_str); + g_test_add_func("/cutils/iec_binary_prefix", + test_iec_binary_prefix); + g_test_add_func("/cutils/si_prefix", + test_si_prefix); return g_test_run(); } diff --git a/tests/unit/test-forward-visitor.c b/tests/unit/test-forward-visitor.c index 348f7e4e81c8..eea8ffc0720e 100644 --- a/tests/unit/test-forward-visitor.c +++ b/tests/unit/test-forward-visitor.c @@ -9,14 +9,13 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/forward-visitor.h" #include "qapi/qobject-input-visitor.h" #include "qapi/error.h" #include "qapi/qmp/qobject.h" #include "qapi/qmp/qdict.h" #include "test-qapi-visit.h" -#include "qemu/option.h" +#include "qemu/keyval.h" typedef bool GenericVisitor (Visitor *, const char *, void **, Error **); #define CAST_VISIT_TYPE(fn) ((GenericVisitor *)(fn)) diff --git a/tests/unit/test-image-locking.c b/tests/unit/test-image-locking.c index ba057bd66cb9..2624cec6a042 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("qemu-tst-img-lock.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("qemu-tst-img-lock.XXXXXX", &img_path, NULL); assert(fd >= 0); perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; @@ -140,6 +140,8 @@ static void test_set_perm_abort(void) check_locked_bytes(fd, perm, ~shared_perm); blk_unref(blk1); blk_unref(blk2); + close(fd); + unlink(img_path); } int main(int argc, char **argv) diff --git a/tests/unit/test-int128.c b/tests/unit/test-int128.c index b86a3c76e615..25db2455e800 100644 --- a/tests/unit/test-int128.c +++ b/tests/unit/test-int128.c @@ -206,6 +206,55 @@ static void test_rshift(void) test_rshift_one(0xFFFE8000U, 0, 0xFFFFFFFFFFFFFFFEULL, 0x8000000000000000ULL); } +static void __attribute__((__noinline__)) ATTRIBUTE_NOCLONE +test_urshift_one(uint32_t x, int n, uint64_t h, uint64_t l) +{ + Int128 a = expand(x); + Int128 r = int128_urshift(a, n); + g_assert_cmpuint(int128_getlo(r), ==, l); + g_assert_cmpuint(int128_gethi(r), ==, h); +} + +static void test_urshift(void) +{ + test_urshift_one(0x00010000U, 64, 0x0000000000000000ULL, + 0x0000000000000001ULL); + test_urshift_one(0x80010000U, 64, 0x0000000000000000ULL, + 0x8000000000000001ULL); + test_urshift_one(0x7FFE0000U, 64, 0x0000000000000000ULL, + 0x7FFFFFFFFFFFFFFEULL); + test_urshift_one(0xFFFE0000U, 64, 0x0000000000000000ULL, + 0xFFFFFFFFFFFFFFFEULL); + test_urshift_one(0x00010000U, 60, 0x0000000000000000ULL, + 0x0000000000000010ULL); + test_urshift_one(0x80010000U, 60, 0x0000000000000008ULL, + 0x0000000000000010ULL); + test_urshift_one(0x00018000U, 60, 0x0000000000000000ULL, + 0x0000000000000018ULL); + test_urshift_one(0x80018000U, 60, 0x0000000000000008ULL, + 0x0000000000000018ULL); + test_urshift_one(0x7FFE0000U, 60, 0x0000000000000007ULL, + 0xFFFFFFFFFFFFFFE0ULL); + test_urshift_one(0xFFFE0000U, 60, 0x000000000000000FULL, + 0xFFFFFFFFFFFFFFE0ULL); + test_urshift_one(0x7FFE8000U, 60, 0x0000000000000007ULL, + 0xFFFFFFFFFFFFFFE8ULL); + test_urshift_one(0xFFFE8000U, 60, 0x000000000000000FULL, + 0xFFFFFFFFFFFFFFE8ULL); + test_urshift_one(0x00018000U, 0, 0x0000000000000001ULL, + 0x8000000000000000ULL); + test_urshift_one(0x80018000U, 0, 0x8000000000000001ULL, + 0x8000000000000000ULL); + test_urshift_one(0x7FFE0000U, 0, 0x7FFFFFFFFFFFFFFEULL, + 0x0000000000000000ULL); + test_urshift_one(0xFFFE0000U, 0, 0xFFFFFFFFFFFFFFFEULL, + 0x0000000000000000ULL); + test_urshift_one(0x7FFE8000U, 0, 0x7FFFFFFFFFFFFFFEULL, + 0x8000000000000000ULL); + test_urshift_one(0xFFFE8000U, 0, 0xFFFFFFFFFFFFFFFEULL, + 0x8000000000000000ULL); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -219,5 +268,6 @@ int main(int argc, char **argv) g_test_add_func("/int128/int128_ge", test_ge); g_test_add_func("/int128/int128_gt", test_gt); g_test_add_func("/int128/int128_rshift", test_rshift); + g_test_add_func("/int128/int128_urshift", test_urshift); return g_test_run(); } diff --git a/tests/unit/test-interval-tree.c b/tests/unit/test-interval-tree.c new file mode 100644 index 000000000000..119817a0194d --- /dev/null +++ b/tests/unit/test-interval-tree.c @@ -0,0 +1,209 @@ +/* + * Test interval trees + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/interval-tree.h" + +static IntervalTreeNode nodes[20]; +static IntervalTreeRoot root; + +static void rand_interval(IntervalTreeNode *n, uint64_t start, uint64_t last) +{ + gint32 s_ofs, l_ofs, l_max; + + if (last - start > INT32_MAX) { + l_max = INT32_MAX; + } else { + l_max = last - start; + } + s_ofs = g_test_rand_int_range(0, l_max); + l_ofs = g_test_rand_int_range(s_ofs, l_max); + + n->start = start + s_ofs; + n->last = start + l_ofs; +} + +static void test_empty(void) +{ + g_assert(root.rb_root.rb_node == NULL); + g_assert(root.rb_leftmost == NULL); + g_assert(interval_tree_iter_first(&root, 0, UINT64_MAX) == NULL); +} + +static void test_find_one_point(void) +{ + /* Create a tree of a single node, which is the point [1,1]. */ + nodes[0].start = 1; + nodes[0].last = 1; + + interval_tree_insert(&nodes[0], &root); + + g_assert(interval_tree_iter_first(&root, 0, 9) == &nodes[0]); + g_assert(interval_tree_iter_next(&nodes[0], 0, 9) == NULL); + g_assert(interval_tree_iter_first(&root, 0, 0) == NULL); + g_assert(interval_tree_iter_next(&nodes[0], 0, 0) == NULL); + g_assert(interval_tree_iter_first(&root, 0, 1) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 1, 1) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 1, 2) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 2, 2) == NULL); + + interval_tree_remove(&nodes[0], &root); + g_assert(root.rb_root.rb_node == NULL); + g_assert(root.rb_leftmost == NULL); +} + +static void test_find_two_point(void) +{ + IntervalTreeNode *find0, *find1; + + /* Create a tree of a two nodes, which are both the point [1,1]. */ + nodes[0].start = 1; + nodes[0].last = 1; + nodes[1] = nodes[0]; + + interval_tree_insert(&nodes[0], &root); + interval_tree_insert(&nodes[1], &root); + + find0 = interval_tree_iter_first(&root, 0, 9); + g_assert(find0 == &nodes[0] || find0 == &nodes[1]); + + find1 = interval_tree_iter_next(find0, 0, 9); + g_assert(find1 == &nodes[0] || find1 == &nodes[1]); + g_assert(find0 != find1); + + interval_tree_remove(&nodes[1], &root); + + g_assert(interval_tree_iter_first(&root, 0, 9) == &nodes[0]); + g_assert(interval_tree_iter_next(&nodes[0], 0, 9) == NULL); + + interval_tree_remove(&nodes[0], &root); +} + +static void test_find_one_range(void) +{ + /* Create a tree of a single node, which is the range [1,8]. */ + nodes[0].start = 1; + nodes[0].last = 8; + + interval_tree_insert(&nodes[0], &root); + + g_assert(interval_tree_iter_first(&root, 0, 9) == &nodes[0]); + g_assert(interval_tree_iter_next(&nodes[0], 0, 9) == NULL); + g_assert(interval_tree_iter_first(&root, 0, 0) == NULL); + g_assert(interval_tree_iter_first(&root, 0, 1) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 1, 1) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 4, 6) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 8, 8) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 9, 9) == NULL); + + interval_tree_remove(&nodes[0], &root); +} + +static void test_find_one_range_many(void) +{ + int i; + + /* + * Create a tree of many nodes in [0,99] and [200,299], + * but only one node with exactly [110,190]. + */ + nodes[0].start = 110; + nodes[0].last = 190; + + for (i = 1; i < ARRAY_SIZE(nodes) / 2; ++i) { + rand_interval(&nodes[i], 0, 99); + } + for (; i < ARRAY_SIZE(nodes); ++i) { + rand_interval(&nodes[i], 200, 299); + } + + for (i = 0; i < ARRAY_SIZE(nodes); ++i) { + interval_tree_insert(&nodes[i], &root); + } + + /* Test that we find exactly the one node. */ + g_assert(interval_tree_iter_first(&root, 100, 199) == &nodes[0]); + g_assert(interval_tree_iter_next(&nodes[0], 100, 199) == NULL); + g_assert(interval_tree_iter_first(&root, 100, 109) == NULL); + g_assert(interval_tree_iter_first(&root, 100, 110) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 111, 120) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 111, 199) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 190, 199) == &nodes[0]); + g_assert(interval_tree_iter_first(&root, 192, 199) == NULL); + + /* + * Test that if there are multiple matches, we return the one + * with the minimal start. + */ + g_assert(interval_tree_iter_first(&root, 100, 300) == &nodes[0]); + + /* Test that we don't find it after it is removed. */ + interval_tree_remove(&nodes[0], &root); + g_assert(interval_tree_iter_first(&root, 100, 199) == NULL); + + for (i = 1; i < ARRAY_SIZE(nodes); ++i) { + interval_tree_remove(&nodes[i], &root); + } +} + +static void test_find_many_range(void) +{ + IntervalTreeNode *find; + int i, n; + + n = g_test_rand_int_range(ARRAY_SIZE(nodes) / 3, ARRAY_SIZE(nodes) / 2); + + /* + * Create a fair few nodes in [2000,2999], with the others + * distributed around. + */ + for (i = 0; i < n; ++i) { + rand_interval(&nodes[i], 2000, 2999); + } + for (; i < ARRAY_SIZE(nodes) * 2 / 3; ++i) { + rand_interval(&nodes[i], 1000, 1899); + } + for (; i < ARRAY_SIZE(nodes); ++i) { + rand_interval(&nodes[i], 3100, 3999); + } + + for (i = 0; i < ARRAY_SIZE(nodes); ++i) { + interval_tree_insert(&nodes[i], &root); + } + + /* Test that we find all of the nodes. */ + find = interval_tree_iter_first(&root, 2000, 2999); + for (i = 0; find != NULL; i++) { + find = interval_tree_iter_next(find, 2000, 2999); + } + g_assert_cmpint(i, ==, n); + + g_assert(interval_tree_iter_first(&root, 0, 999) == NULL); + g_assert(interval_tree_iter_first(&root, 1900, 1999) == NULL); + g_assert(interval_tree_iter_first(&root, 3000, 3099) == NULL); + g_assert(interval_tree_iter_first(&root, 4000, UINT64_MAX) == NULL); + + for (i = 0; i < ARRAY_SIZE(nodes); ++i) { + interval_tree_remove(&nodes[i], &root); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/interval-tree/empty", test_empty); + g_test_add_func("/interval-tree/find-one-point", test_find_one_point); + g_test_add_func("/interval-tree/find-two-point", test_find_two_point); + g_test_add_func("/interval-tree/find-one-range", test_find_one_range); + g_test_add_func("/interval-tree/find-one-range-many", + test_find_one_range_many); + g_test_add_func("/interval-tree/find-many-range", test_find_many_range); + + return g_test_run(); +} diff --git a/tests/unit/test-io-channel-command.c b/tests/unit/test-io-channel-command.c index 99056e07c023..19f72eab961d 100644 --- a/tests/unit/test-io-channel-command.c +++ b/tests/unit/test-io-channel-command.c @@ -19,37 +19,34 @@ */ #include "qemu/osdep.h" +#include #include "io/channel-command.h" #include "io-channel-helpers.h" #include "qapi/error.h" #include "qemu/module.h" -#ifndef WIN32 +#define TEST_FIFO "test-io-channel-command.fifo" + +static char *socat = NULL; + static void test_io_channel_command_fifo(bool async) { -#define TEST_FIFO "tests/test-io-channel-command.fifo" + g_autofree gchar *tmpdir = g_dir_make_tmp("qemu-test-io-channel.XXXXXX", NULL); + g_autofree gchar *fifo = g_strdup_printf("%s/%s", tmpdir, TEST_FIFO); + g_autofree gchar *srcargs = g_strdup_printf("%s - PIPE:%s,wronly", socat, fifo); + g_autofree gchar *dstargs = g_strdup_printf("%s PIPE:%s,rdonly -", socat, fifo); + g_auto(GStrv) srcargv = g_strsplit(srcargs, " ", -1); + g_auto(GStrv) dstargv = g_strsplit(dstargs, " ", -1); QIOChannel *src, *dst; QIOChannelTest *test; - const char *srcfifo = "PIPE:" TEST_FIFO ",wronly"; - const char *dstfifo = "PIPE:" TEST_FIFO ",rdonly"; - const char *srcargv[] = { - "/bin/socat", "-", srcfifo, NULL, - }; - const char *dstargv[] = { - "/bin/socat", dstfifo, "-", NULL, - }; - unlink(TEST_FIFO); - if (access("/bin/socat", X_OK) < 0) { - return; /* Pretend success if socat is not present */ - } - if (mkfifo(TEST_FIFO, 0600) < 0) { - abort(); - } - src = QIO_CHANNEL(qio_channel_command_new_spawn(srcargv, + src = QIO_CHANNEL(qio_channel_command_new_spawn((const char **) srcargv, O_WRONLY, &error_abort)); - dst = QIO_CHANNEL(qio_channel_command_new_spawn(dstargv, + /* try to avoid a race to create the socket */ + g_usleep(1000); + + dst = QIO_CHANNEL(qio_channel_command_new_spawn((const char **) dstargv, O_RDONLY, &error_abort)); @@ -60,17 +57,27 @@ static void test_io_channel_command_fifo(bool async) object_unref(OBJECT(src)); object_unref(OBJECT(dst)); - unlink(TEST_FIFO); + g_rmdir(tmpdir); } static void test_io_channel_command_fifo_async(void) { + if (!socat) { + g_test_skip("socat is not found in PATH"); + return; + } + test_io_channel_command_fifo(true); } static void test_io_channel_command_fifo_sync(void) { + if (!socat) { + g_test_skip("socat is not found in PATH"); + return; + } + test_io_channel_command_fifo(false); } @@ -80,11 +87,12 @@ static void test_io_channel_command_echo(bool async) QIOChannel *ioc; QIOChannelTest *test; const char *socatargv[] = { - "/bin/socat", "-", "-", NULL, + socat, "-", "-", NULL, }; - if (access("/bin/socat", X_OK) < 0) { - return; /* Pretend success if socat is not present */ + if (!socat) { + g_test_skip("socat is not found in PATH"); + return; } ioc = QIO_CHANNEL(qio_channel_command_new_spawn(socatargv, @@ -107,7 +115,6 @@ static void test_io_channel_command_echo_sync(void) { test_io_channel_command_echo(false); } -#endif int main(int argc, char **argv) { @@ -115,7 +122,8 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); -#ifndef WIN32 + socat = g_find_program_in_path("socat"); + g_test_add_func("/io/channel/command/fifo/sync", test_io_channel_command_fifo_sync); g_test_add_func("/io/channel/command/fifo/async", @@ -124,7 +132,6 @@ int main(int argc, char **argv) test_io_channel_command_echo_sync); g_test_add_func("/io/channel/command/echo/async", test_io_channel_command_echo_async); -#endif return g_test_run(); } diff --git a/tests/unit/test-io-channel-file.c b/tests/unit/test-io-channel-file.c index 29038e67b64d..1977006ce922 100644 --- a/tests/unit/test-io-channel-file.c +++ b/tests/unit/test-io-channel-file.c @@ -109,7 +109,7 @@ static void test_io_channel_pipe(bool async) QIOChannelTest *test; int fd[2]; - if (pipe(fd) < 0) { + if (!g_unix_open_pipe(fd, FD_CLOEXEC, NULL)) { perror("pipe"); abort(); } diff --git a/tests/unit/test-io-channel-null.c b/tests/unit/test-io-channel-null.c new file mode 100644 index 000000000000..b3aab17ccce9 --- /dev/null +++ b/tests/unit/test-io-channel-null.c @@ -0,0 +1,95 @@ +/* + * QEMU I/O channel null test + * + * Copyright (c) 2022 Red Hat, Inc. + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "io/channel-null.h" +#include "qapi/error.h" + +static gboolean test_io_channel_watch(QIOChannel *ioc, + GIOCondition condition, + gpointer opaque) +{ + GIOCondition *gotcond = opaque; + *gotcond = condition; + return G_SOURCE_REMOVE; +} + +static void test_io_channel_null_io(void) +{ + g_autoptr(QIOChannelNull) null = qio_channel_null_new(); + char buf[1024]; + GIOCondition gotcond = 0; + Error *local_err = NULL; + + g_assert(qio_channel_write(QIO_CHANNEL(null), + "Hello World", 11, + &error_abort) == 11); + + g_assert(qio_channel_read(QIO_CHANNEL(null), + buf, sizeof(buf), + &error_abort) == 0); + + qio_channel_add_watch(QIO_CHANNEL(null), + G_IO_IN, + test_io_channel_watch, + &gotcond, + NULL); + + g_main_context_iteration(NULL, false); + + g_assert(gotcond == G_IO_IN); + + qio_channel_add_watch(QIO_CHANNEL(null), + G_IO_IN | G_IO_OUT, + test_io_channel_watch, + &gotcond, + NULL); + + g_main_context_iteration(NULL, false); + + g_assert(gotcond == (G_IO_IN | G_IO_OUT)); + + qio_channel_close(QIO_CHANNEL(null), &error_abort); + + g_assert(qio_channel_write(QIO_CHANNEL(null), + "Hello World", 11, + &local_err) == -1); + g_assert_nonnull(local_err); + + g_clear_pointer(&local_err, error_free); + + g_assert(qio_channel_read(QIO_CHANNEL(null), + buf, sizeof(buf), + &local_err) == -1); + g_assert_nonnull(local_err); + + g_clear_pointer(&local_err, error_free); +} + +int main(int argc, char **argv) +{ + module_call_init(MODULE_INIT_QOM); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/io/channel/null/io", test_io_channel_null_io); + + return g_test_run(); +} diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c index c49eec1f038a..b36a5d972ad5 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); @@ -444,6 +452,7 @@ static void test_io_channel_unix_fd_pass(void) G_N_ELEMENTS(iosend), fdsend, G_N_ELEMENTS(fdsend), + 0, &error_abort); qio_channel_readv_full(dst, @@ -490,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) { @@ -521,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; @@ -554,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); @@ -587,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 f6fb988c0151..cc39247556f3 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-iov.c b/tests/unit/test-iov.c index 5371066fb6a4..6f7623d3107f 100644 --- a/tests/unit/test-iov.c +++ b/tests/unit/test-iov.c @@ -1,5 +1,4 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/iov.h" #include "qemu/sockets.h" @@ -173,7 +172,7 @@ static void test_io(void) } iov_from_buf(iov, niov, 0, buf, sz); - siov = g_memdup(iov, sizeof(*iov) * niov); + siov = g_memdup2(iov, sizeof(*iov) * niov); if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) { perror("socketpair"); @@ -187,7 +186,7 @@ static void test_io(void) close(sv[0]); FD_SET(sv[1], &fds); - fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK); + g_unix_set_fd_nonblocking(sv[1], true, NULL); r = g_test_rand_int_range(sz / 2, sz); setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r)); @@ -221,7 +220,7 @@ static void test_io(void) close(sv[1]); FD_SET(sv[0], &fds); - fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK); + g_unix_set_fd_nonblocking(sv[0], true, NULL); r = g_test_rand_int_range(sz / 2, sz); setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r)); usleep(500000); @@ -350,7 +349,7 @@ static void test_discard_front_undo(void) /* Discard zero bytes */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_tmp = iov; iov_cnt_tmp = iov_cnt; iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, 0, &undo); @@ -361,7 +360,7 @@ static void test_discard_front_undo(void) /* Discard more bytes than vector size */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_tmp = iov; iov_cnt_tmp = iov_cnt; size = iov_size(iov, iov_cnt); @@ -373,7 +372,7 @@ static void test_discard_front_undo(void) /* Discard entire vector */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_tmp = iov; iov_cnt_tmp = iov_cnt; size = iov_size(iov, iov_cnt); @@ -385,7 +384,7 @@ static void test_discard_front_undo(void) /* Discard within first element */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_tmp = iov; iov_cnt_tmp = iov_cnt; size = g_test_rand_int_range(1, iov->iov_len); @@ -397,7 +396,7 @@ static void test_discard_front_undo(void) /* Discard entire first element */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_tmp = iov; iov_cnt_tmp = iov_cnt; iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, iov->iov_len, &undo); @@ -408,7 +407,7 @@ static void test_discard_front_undo(void) /* Discard within second element */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_tmp = iov; iov_cnt_tmp = iov_cnt; size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len); @@ -499,7 +498,7 @@ static void test_discard_back_undo(void) /* Discard zero bytes */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_cnt_tmp = iov_cnt; iov_discard_back_undoable(iov, &iov_cnt_tmp, 0, &undo); iov_discard_undo(&undo); @@ -509,7 +508,7 @@ static void test_discard_back_undo(void) /* Discard more bytes than vector size */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_cnt_tmp = iov_cnt; size = iov_size(iov, iov_cnt); iov_discard_back_undoable(iov, &iov_cnt_tmp, size + 1, &undo); @@ -520,7 +519,7 @@ static void test_discard_back_undo(void) /* Discard entire vector */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_cnt_tmp = iov_cnt; size = iov_size(iov, iov_cnt); iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); @@ -531,7 +530,7 @@ static void test_discard_back_undo(void) /* Discard within last element */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_cnt_tmp = iov_cnt; size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len); iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); @@ -542,7 +541,7 @@ static void test_discard_back_undo(void) /* Discard entire last element */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_cnt_tmp = iov_cnt; size = iov[iov_cnt - 1].iov_len; iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); @@ -553,7 +552,7 @@ static void test_discard_back_undo(void) /* Discard within second-to-last element */ iov_random(&iov, &iov_cnt); - iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt); iov_cnt_tmp = iov_cnt; size = iov[iov_cnt - 1].iov_len + g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len); diff --git a/tests/unit/test-keyval.c b/tests/unit/test-keyval.c index af0581ae6c5b..4dc52c7a1a8b 100644 --- a/tests/unit/test-keyval.c +++ b/tests/unit/test-keyval.c @@ -19,7 +19,7 @@ #include "qapi/qobject-input-visitor.h" #include "test-qapi-visit.h" #include "qemu/cutils.h" -#include "qemu/option.h" +#include "qemu/keyval.h" static void test_keyval_parse(void) { diff --git a/tests/unit/test-logging.c b/tests/unit/test-logging.c index ccb819f193d9..66dbc82a56f6 100644 --- a/tests/unit/test-logging.c +++ b/tests/unit/test-logging.c @@ -27,9 +27,9 @@ #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/log.h" +#include "qemu/rcu.h" static void test_parse_range(void) { @@ -110,12 +110,10 @@ static void test_parse_path(gconstpointer data) static void test_logfile_write(gconstpointer data) { - QemuLogFile *logfile; - QemuLogFile *logfile2; + FILE *logfile0, *logfile1; gchar const *dir = data; - g_autofree gchar *file_path = NULL; + g_autofree gchar *file_path0 = NULL; g_autofree gchar *file_path1 = NULL; - FILE *orig_fd; /* * Before starting test, set log flags, to ensure the file gets @@ -123,30 +121,29 @@ static void test_logfile_write(gconstpointer data) * In cases where a logging backend other than log is used, * this is needed. */ - qemu_set_log(CPU_LOG_TB_OUT_ASM); - file_path = g_build_filename(dir, "qemu_test_log_write0.log", NULL); + qemu_set_log(CPU_LOG_TB_OUT_ASM, &error_abort); + file_path0 = g_build_filename(dir, "qemu_test_log_write0.log", NULL); file_path1 = g_build_filename(dir, "qemu_test_log_write1.log", NULL); /* * Test that even if an open file handle is changed, * our handle remains valid due to RCU. */ - qemu_set_log_filename(file_path, &error_abort); - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - orig_fd = logfile->fd; - g_assert(logfile && logfile->fd); - fprintf(logfile->fd, "%s 1st write to file\n", __func__); - fflush(logfile->fd); + qemu_set_log_filename(file_path0, &error_abort); + logfile0 = qemu_log_trylock(); + g_assert(logfile0); + fprintf(logfile0, "%s 1st write to file\n", __func__); + fflush(logfile0); /* Change the logfile and ensure that the handle is still valid. */ qemu_set_log_filename(file_path1, &error_abort); - logfile2 = qatomic_rcu_read(&qemu_logfile); - g_assert(logfile->fd == orig_fd); - g_assert(logfile2->fd != logfile->fd); - fprintf(logfile->fd, "%s 2nd write to file\n", __func__); - fflush(logfile->fd); - rcu_read_unlock(); + logfile1 = qemu_log_trylock(); + g_assert(logfile1); + g_assert(logfile0 != logfile1); + fprintf(logfile0, "%s 2nd write to file\n", __func__); + fflush(logfile0); + qemu_log_unlock(logfile0); + qemu_log_unlock(logfile1); } static void test_logfile_lock(gconstpointer data) @@ -163,7 +160,7 @@ static void test_logfile_lock(gconstpointer data) * our handle remains valid for use due to RCU. */ qemu_set_log_filename(file_path, &error_abort); - logfile = qemu_log_lock(); + logfile = qemu_log_trylock(); g_assert(logfile); fprintf(logfile, "%s 1st write to file\n", __func__); fflush(logfile); @@ -172,7 +169,7 @@ static void test_logfile_lock(gconstpointer data) * Initiate a close file and make sure our handle remains * valid since we still have the logfile lock. */ - qemu_log_close(); + qemu_set_log_filename_flags(NULL, 0, &error_abort); fprintf(logfile, "%s 2nd write to file\n", __func__); fflush(logfile); qemu_log_unlock(logfile); @@ -210,7 +207,7 @@ int main(int argc, char **argv) tmp_path, test_logfile_lock); rc = g_test_run(); - qemu_log_close(); + qemu_set_log_filename_flags(NULL, 0, &error_abort); drain_call_rcu(); rmdir_full(tmp_path); diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c index 5cb140d1b53d..b4e0a145737d 100644 --- a/tests/unit/test-qga.c +++ b/tests/unit/test-qga.c @@ -4,7 +4,7 @@ #include #include -#include "../qtest/libqos/libqtest.h" +#include "../qtest/libqtest.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" @@ -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); @@ -52,12 +53,15 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) { const gchar *extra_arg = data; GError *error = NULL; - gchar *cwd, *path, *cmd, **argv = NULL; + g_autofree char *cwd = NULL; + g_autofree char *path = NULL; + g_autofree char *cmd = NULL; + g_auto(GStrv) argv = NULL; 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(); @@ -78,17 +82,12 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) fixture->fd = connect_qga(path); g_assert_cmpint(fixture->fd, !=, -1); - - g_strfreev(argv); - g_free(cmd); - g_free(cwd); - g_free(path); } static void fixture_tear_down(TestFixture *fixture, gconstpointer data) { - gchar *tmp; + g_autofree char *tmp = NULL; kill(fixture->pid, SIGTERM); @@ -107,7 +106,6 @@ fixture_tear_down(TestFixture *fixture, gconstpointer data) tmp = g_build_filename(fixture->test_dir, "sock", NULL); g_unlink(tmp); - g_free(tmp); g_rmdir(fixture->test_dir); g_free(fixture->test_dir); @@ -122,7 +120,7 @@ static void qmp_assertion_message_error(const char *domain, QDict *dict) { const char *class, *desc; - char *s; + g_autofree char *s = NULL; QDict *error; error = qdict_get_qdict(dict, "error"); @@ -131,7 +129,6 @@ static void qmp_assertion_message_error(const char *domain, s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc); g_assertion_message(domain, file, line, func, s); - g_free(s); } #define qmp_assert_no_error(err) do { \ @@ -146,7 +143,7 @@ static void test_qga_sync_delimited(gconstpointer fix) const TestFixture *fixture = fix; guint32 v, r = g_test_rand_int(); unsigned char c; - QDict *ret; + g_autoptr(QDict) ret = NULL; qmp_fd_send_raw(fixture->fd, "\xff"); qmp_fd_send(fixture->fd, @@ -180,15 +177,13 @@ static void test_qga_sync_delimited(gconstpointer fix) v = qdict_get_int(ret, "return"); g_assert_cmpint(r, ==, v); - - qobject_unref(ret); } static void test_qga_sync(gconstpointer fix) { const TestFixture *fixture = fix; guint32 v, r = g_test_rand_int(); - QDict *ret; + g_autoptr(QDict) ret = NULL; /* * TODO guest-sync is inherently limited: we cannot distinguish @@ -210,33 +205,27 @@ static void test_qga_sync(gconstpointer fix) v = qdict_get_int(ret, "return"); g_assert_cmpint(r, ==, v); - - qobject_unref(ret); } static void test_qga_ping(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}"); g_assert_nonnull(ret); qmp_assert_no_error(ret); - - qobject_unref(ret); } static void test_qga_id(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}"); g_assert_nonnull(ret); qmp_assert_no_error(ret); g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1); - - qobject_unref(ret); } static void test_qga_invalid_oob(gconstpointer fix) @@ -253,7 +242,8 @@ static void test_qga_invalid_oob(gconstpointer fix) static void test_qga_invalid_args(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *error; + g_autoptr(QDict) ret = NULL; + QDict *error; const gchar *class, *desc; ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', " @@ -266,14 +256,13 @@ static void test_qga_invalid_args(gconstpointer fix) g_assert_cmpstr(class, ==, "GenericError"); g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected"); - - qobject_unref(ret); } static void test_qga_invalid_cmd(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *error; + g_autoptr(QDict) ret = NULL; + QDict *error; const gchar *class, *desc; ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}"); @@ -285,14 +274,13 @@ static void test_qga_invalid_cmd(gconstpointer fix) g_assert_cmpstr(class, ==, "CommandNotFound"); g_assert_cmpint(strlen(desc), >, 0); - - qobject_unref(ret); } static void test_qga_info(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; const gchar *version; ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}"); @@ -302,14 +290,12 @@ static void test_qga_info(gconstpointer fix) val = qdict_get_qdict(ret, "return"); version = qdict_get_try_str(val, "version"); g_assert_cmpstr(version, ==, QEMU_VERSION); - - qobject_unref(ret); } static void test_qga_get_vcpus(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -322,14 +308,12 @@ static void test_qga_get_vcpus(gconstpointer fix) entry = qlist_first(list); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); - - qobject_unref(ret); } static void test_qga_get_fsinfo(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -346,14 +330,13 @@ static void test_qga_get_fsinfo(gconstpointer fix) g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk")); } - - qobject_unref(ret); } static void test_qga_get_memory_block_info(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; int64_t size; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}"); @@ -366,14 +349,12 @@ static void test_qga_get_memory_block_info(gconstpointer fix) size = qdict_get_int(val, "size"); g_assert_cmpint(size, >, 0); } - - qobject_unref(ret); } static void test_qga_get_memory_blocks(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -391,14 +372,12 @@ static void test_qga_get_memory_blocks(gconstpointer fix) g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); } } - - qobject_unref(ret); } static void test_qga_network_get_interfaces(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -410,8 +389,6 @@ static void test_qga_network_get_interfaces(gconstpointer fix) list = qdict_get_qlist(ret, "return"); entry = qlist_first(list); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); - - qobject_unref(ret); } static void test_qga_file_ops(gconstpointer fix) @@ -642,7 +619,7 @@ static void test_qga_file_write_read(gconstpointer fix) static void test_qga_get_time(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; int64_t time; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); @@ -651,11 +628,9 @@ static void test_qga_get_time(gconstpointer fix) time = qdict_get_int(ret, "return"); g_assert_cmpint(time, >, 0); - - qobject_unref(ret); } -static void test_qga_blacklist(gconstpointer data) +static void test_qga_blockedrpcs(gconstpointer data) { TestFixture fix; QDict *ret, *error; @@ -663,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"); @@ -693,18 +668,22 @@ static void test_qga_blacklist(gconstpointer data) static void test_qga_config(gconstpointer data) { GError *error = NULL; - char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL; + g_autofree char *out = NULL; + g_autofree char *err = NULL; + g_autofree char *cwd = NULL; + g_autofree char *cmd = NULL; + g_auto(GStrv) argv = NULL; + g_auto(GStrv) strv = NULL; + g_autoptr(GKeyFile) kf = NULL; + char *str; char *env[2]; int status; gsize n; - GKeyFile *kf; cwd = g_get_current_dir(); cmd = g_strdup_printf("%s%cqga%cqemu-ga -D", cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR); - g_free(cwd); g_shell_parse_argv(cmd, NULL, &argv, &error); - g_free(cmd); g_assert_no_error(error); env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config", @@ -712,7 +691,6 @@ static void test_qga_config(gconstpointer data) env[1] = NULL; g_spawn_sync(NULL, argv, env, 0, NULL, NULL, &out, &err, &status, &error); - g_strfreev(argv); g_assert_no_error(error); g_assert_cmpstr(err, ==, ""); @@ -752,25 +730,21 @@ 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")); g_assert_true(g_strv_contains((const char * const *)strv, "guest-get-time")); g_assert_no_error(error); - g_strfreev(strv); - g_free(out); - g_free(err); g_free(env[0]); - g_key_file_free(kf); } static void test_qga_fsfreeze_status(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; const gchar *status; ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); @@ -779,16 +753,15 @@ static void test_qga_fsfreeze_status(gconstpointer fix) status = qdict_get_try_str(ret, "return"); g_assert_cmpstr(status, ==, "thawed"); - - qobject_unref(ret); } static void test_qga_guest_exec(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; const gchar *out; - guchar *decoded; + g_autofree guchar *decoded = NULL; int64_t pid, now, exitcode; gsize len; bool exited; @@ -827,14 +800,13 @@ static void test_qga_guest_exec(gconstpointer fix) decoded = g_base64_decode(out, &len); g_assert_cmpint(len, ==, 12); g_assert_cmpstr((char *)decoded, ==, "\" test_str \""); - g_free(decoded); - qobject_unref(ret); } static void test_qga_guest_exec_invalid(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *error; + g_autoptr(QDict) ret = NULL; + QDict *error; const gchar *class, *desc; /* invalid command */ @@ -859,13 +831,13 @@ static void test_qga_guest_exec_invalid(gconstpointer fix) desc = qdict_get_str(error, "desc"); g_assert_cmpstr(class, ==, "GenericError"); g_assert_cmpint(strlen(desc), >, 0); - qobject_unref(ret); } static void test_qga_guest_get_host_name(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}"); g_assert_nonnull(ret); @@ -873,14 +845,13 @@ static void test_qga_guest_get_host_name(gconstpointer fix) val = qdict_get_qdict(ret, "return"); g_assert(qdict_haskey(val, "host-name")); - - qobject_unref(ret); } static void test_qga_guest_get_timezone(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}"); g_assert_nonnull(ret); @@ -889,14 +860,12 @@ static void test_qga_guest_get_timezone(gconstpointer fix) /* Make sure there's at least offset */ val = qdict_get_qdict(ret, "return"); g_assert(qdict_haskey(val, "offset")); - - qobject_unref(ret); } static void test_qga_guest_get_users(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *val; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}"); @@ -906,23 +875,20 @@ static void test_qga_guest_get_users(gconstpointer fix) /* There is not much to test here */ val = qdict_get_qlist(ret, "return"); g_assert_nonnull(val); - - qobject_unref(ret); } static void test_qga_guest_get_osinfo(gconstpointer data) { TestFixture fixture; const gchar *str; - gchar *cwd, *env[2]; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + char *env[2]; + QDict *val; - cwd = g_get_current_dir(); env[0] = g_strdup_printf( - "QGA_OS_RELEASE=%s%ctests%cdata%ctest-qga-os-release", - cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR); + "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release", + g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR); env[1] = NULL; - g_free(cwd); fixture_setup(&fixture, NULL, env); ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}"); @@ -959,7 +925,6 @@ static void test_qga_guest_get_osinfo(gconstpointer data) g_assert_nonnull(str); g_assert_cmpstr(str, ==, "unit-test"); - qobject_unref(ret); g_free(env[0]); fixture_tear_down(&fixture, NULL); } @@ -969,6 +934,13 @@ int main(int argc, char **argv) TestFixture fix; int ret; +#ifdef QEMU_SANITIZE_THREAD + { + g_test_skip("tsan enabled, https://github.com/google/sanitizers/issues/1116"); + return 0; + } +#endif + setlocale (LC_ALL, ""); g_test_init(&argc, &argv, NULL); fixture_setup(&fix, NULL, NULL); @@ -997,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-qmp-cmds.c b/tests/unit/test-qmp-cmds.c index 6085c099950b..6d52b4e5d811 100644 --- a/tests/unit/test-qmp-cmds.c +++ b/tests/unit/test-qmp-cmds.c @@ -43,15 +43,15 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp) { } -FeatureStruct1 *qmp_test_features0(bool has_fs0, FeatureStruct0 *fs0, - bool has_fs1, FeatureStruct1 *fs1, - bool has_fs2, FeatureStruct2 *fs2, - bool has_fs3, FeatureStruct3 *fs3, - bool has_fs4, FeatureStruct4 *fs4, - bool has_cfs1, CondFeatureStruct1 *cfs1, - bool has_cfs2, CondFeatureStruct2 *cfs2, - bool has_cfs3, CondFeatureStruct3 *cfs3, - bool has_cfs4, CondFeatureStruct4 *cfs4, +FeatureStruct1 *qmp_test_features0(FeatureStruct0 *fs0, + FeatureStruct1 *fs1, + FeatureStruct2 *fs2, + FeatureStruct3 *fs3, + FeatureStruct4 *fs4, + CondFeatureStruct1 *cfs1, + CondFeatureStruct2 *cfs2, + CondFeatureStruct3 *cfs3, + CondFeatureStruct4 *cfs4, Error **errp) { return g_new0(FeatureStruct1, 1); @@ -77,8 +77,7 @@ void qmp_test_command_cond_features3(Error **errp) { } -UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, - bool has_udb1, UserDefOne *ud1b, +UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, UserDefOne *ud1b, Error **errp) { UserDefTwo *ret; @@ -87,8 +86,8 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, ud1c->string = strdup(ud1a->string); ud1c->integer = ud1a->integer; - ud1d->string = strdup(has_udb1 ? ud1b->string : "blah0"); - ud1d->integer = has_udb1 ? ud1b->integer : 0; + ud1d->string = strdup(ud1b ? ud1b->string : "blah0"); + ud1d->integer = ud1b ? ud1b->integer : 0; ret = g_new0(UserDefTwo, 1); ret->string0 = strdup("blah1"); @@ -98,7 +97,6 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, ret->dict1->dict2->userdef = ud1c; ret->dict1->dict2->string = strdup("blah3"); ret->dict1->dict3 = g_new0(UserDefTwoDictDict, 1); - ret->dict1->has_dict3 = true; ret->dict1->dict3->userdef = ud1d; ret->dict1->dict3->string = strdup("blah4"); @@ -140,6 +138,7 @@ void qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, } +G_GNUC_PRINTF(2, 3) static QObject *do_qmp_dispatch(bool allow_oob, const char *template, ...) { va_list ap; @@ -162,6 +161,7 @@ static QObject *do_qmp_dispatch(bool allow_oob, const char *template, ...) return ret; } +G_GNUC_PRINTF(3, 4) static void do_qmp_dispatch_error(bool allow_oob, ErrorClass cls, const char *template, ...) { @@ -271,7 +271,7 @@ static void test_dispatch_cmd_io(void) static void test_dispatch_cmd_deprecated(void) { - const char *cmd = "{ 'execute': 'test-command-features1' }"; + #define cmd "{ 'execute': 'test-command-features1' }" QDict *ret; memset(&compat_policy, 0, sizeof(compat_policy)); @@ -289,12 +289,13 @@ static void test_dispatch_cmd_deprecated(void) compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT; do_qmp_dispatch_error(false, ERROR_CLASS_COMMAND_NOT_FOUND, cmd); + #undef cmd } static void test_dispatch_cmd_arg_deprecated(void) { - const char *cmd = "{ 'execute': 'test-features0'," - " 'arguments': { 'fs1': { 'foo': 42 } } }"; + #define cmd "{ 'execute': 'test-features0'," \ + " 'arguments': { 'fs1': { 'foo': 42 } } }" QDict *ret; memset(&compat_policy, 0, sizeof(compat_policy)); @@ -312,11 +313,12 @@ static void test_dispatch_cmd_arg_deprecated(void) compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT; do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR, cmd); + #undef cmd } static void test_dispatch_cmd_ret_deprecated(void) { - const char *cmd = "{ 'execute': 'test-features0' }"; + #define cmd "{ 'execute': 'test-features0' }" QDict *ret; memset(&compat_policy, 0, sizeof(compat_policy)); @@ -336,6 +338,7 @@ static void test_dispatch_cmd_ret_deprecated(void) ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); assert(ret && qdict_size(ret) == 0); qobject_unref(ret); + #undef cmd } /* test generated dealloc functions for generated types */ diff --git a/tests/unit/test-qmp-event.c b/tests/unit/test-qmp-event.c index d58c3b78f208..3626d2372f1c 100644 --- a/tests/unit/test-qmp-event.c +++ b/tests/unit/test-qmp-event.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/compat-policy.h" #include "qapi/error.h" #include "qapi/qmp/qbool.h" @@ -110,7 +109,7 @@ static void test_event_c(TestEventData *data, data->expect = qdict_from_jsonf_nofail( "{ 'event': 'EVENT_C', 'data': {" " 'a': 1, 'b': { 'integer': 2, 'string': 'test1' }, 'c': 'test2' } }"); - qapi_event_send_event_c(true, 1, true, &b, "test2"); + qapi_event_send_event_c(true, 1, &b, "test2"); g_assert(data->emitted); qobject_unref(data->expect); } @@ -136,7 +135,7 @@ static void test_event_d(TestEventData *data, " 'struct1': { 'integer': 2, 'string': 'test1', 'enum1': 'value1' }," " 'string': 'test2', 'enum2': 'value2' }," " 'b': 'test3', 'enum3': 'value3' } }"); - qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3); + qapi_event_send_event_d(&a, "test3", NULL, true, ENUM_ONE_VALUE3); g_assert(data->emitted); qobject_unref(data->expect); } diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c index 22538f814099..77fbf985becf 100644 --- a/tests/unit/test-qobject-input-visitor.c +++ b/tests/unit/test-qobject-input-visitor.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qapi/qapi-visit-introspect.h" #include "qapi/qobject-input-visitor.h" @@ -432,7 +431,7 @@ static void test_visitor_in_struct_nested(TestInputVisitorData *data, g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42); g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string"); g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2"); - g_assert(udp->dict1->has_dict3 == false); + g_assert(!udp->dict1->dict3); } static void test_visitor_in_list(TestInputVisitorData *data, @@ -448,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); } @@ -776,6 +774,7 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data, AltEnumNum *aen; AltNumEnum *ans; AltEnumInt *asi; + AltListInt *ali; /* Parsing an int */ @@ -802,6 +801,12 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data, g_assert_cmpint(asi->u.i, ==, 42); qapi_free_AltEnumInt(asi); + v = visitor_input_test_init(data, "42"); + visit_type_AltListInt(v, NULL, &ali, &error_abort); + g_assert_cmpint(ali->type, ==, QTYPE_QNUM); + g_assert_cmpint(ali->u.i, ==, 42); + qapi_free_AltListInt(ali); + /* Parsing a double */ v = visitor_input_test_init(data, "42.5"); @@ -827,6 +832,37 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data, qapi_free_AltEnumInt(asi); } +static void test_visitor_in_alternate_list(TestInputVisitorData *data, + const void *unused) +{ + intList *item; + Visitor *v; + AltListInt *ali; + int i; + + v = visitor_input_test_init(data, "[ 42, 43, 44 ]"); + visit_type_AltListInt(v, NULL, &ali, &error_abort); + g_assert(ali != NULL); + + g_assert_cmpint(ali->type, ==, QTYPE_QLIST); + for (i = 0, item = ali->u.l; item; item = item->next, i++) { + g_assert_cmpint(item->value, ==, 42 + i); + } + + qapi_free_AltListInt(ali); + ali = NULL; + + /* An empty list is valid */ + v = visitor_input_test_init(data, "[]"); + visit_type_AltListInt(v, NULL, &ali, &error_abort); + g_assert(ali != NULL); + + g_assert_cmpint(ali->type, ==, QTYPE_QLIST); + g_assert(!ali->u.l); + qapi_free_AltListInt(ali); + ali = NULL; +} + static void input_visitor_test_add(const char *testpath, const void *user_data, void (*test_func)(TestInputVisitorData *data, @@ -1188,6 +1224,8 @@ int main(int argc, char **argv) NULL, test_visitor_in_wrong_type); input_visitor_test_add("/visitor/input/alternate-number", NULL, test_visitor_in_alternate_number); + input_visitor_test_add("/visitor/input/alternate-list", + NULL, test_visitor_in_alternate_list); input_visitor_test_add("/visitor/input/fail/struct", NULL, test_visitor_in_fail_struct); input_visitor_test_add("/visitor/input/fail/struct-nested", diff --git a/tests/unit/test-qobject-output-visitor.c b/tests/unit/test-qobject-output-visitor.c index 6af4c33eec15..7f054289fefe 100644 --- a/tests/unit/test-qobject-output-visitor.c +++ b/tests/unit/test-qobject-output-visitor.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qapi/qobject-output-visitor.h" #include "test-qapi-visit.h" @@ -183,7 +182,6 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, ud2->dict1->dict2->string = g_strdup(strings[2]); ud2->dict1->dict3 = g_malloc0(sizeof(*ud2->dict1->dict3)); - ud2->dict1->has_dict3 = true; ud2->dict1->dict3->userdef = g_new0(UserDefOne, 1); ud2->dict1->dict3->userdef->string = g_strdup(string); ud2->dict1->dict3->userdef->integer = value; @@ -285,7 +283,6 @@ static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, value->dict1->dict2->userdef->string = g_strdup(string); value->dict1->dict2->userdef->integer = 42; value->dict1->dict2->string = g_strdup(string); - value->dict1->has_dict3 = false; QAPI_LIST_PREPEND(head, value); } diff --git a/tests/unit/test-string-input-visitor.c b/tests/unit/test-string-input-visitor.c index 249faafc9d79..25094d3ffcef 100644 --- a/tests/unit/test-string-input-visitor.c +++ b/tests/unit/test-string-input-visitor.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qapi/string-input-visitor.h" #include "test-qapi-visit.h" diff --git a/tests/unit/test-string-output-visitor.c b/tests/unit/test-string-output-visitor.c index e2bedc5c7c92..7ef305361eb7 100644 --- a/tests/unit/test-string-output-visitor.c +++ b/tests/unit/test-string-output-visitor.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qapi/string-output-visitor.h" #include "test-qapi-visit.h" diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c index 70dc6314a1ef..6020e65d6986 100644 --- a/tests/unit/test-thread-pool.c +++ b/tests/unit/test-thread-pool.c @@ -1,5 +1,4 @@ #include "qemu/osdep.h" -#include "qemu-common.h" #include "block/aio.h" #include "block/thread-pool.h" #include "block/block.h" diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index 896247e3ed36..63909ccb2b54 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/sockets.h" #include "qapi/error.h" #include "socket-helpers.h" diff --git a/tests/unit/test-visitor-serialization.c b/tests/unit/test-visitor-serialization.c index 462995864775..c2056c3eaa83 100644 --- a/tests/unit/test-visitor-serialization.c +++ b/tests/unit/test-visitor-serialization.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "test-qapi-visit.h" #include "qapi/error.h" #include "qapi/qmp/qjson.h" @@ -224,7 +223,6 @@ static UserDefTwo *nested_struct_create(void) udnp->dict1->dict2->userdef->string = strdup("test_string"); udnp->dict1->dict2->string = strdup("test_string2"); udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3)); - udnp->dict1->has_dict3 = true; udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1); udnp->dict1->dict3->userdef->integer = 43; udnp->dict1->dict3->userdef->string = strdup("test_string"); @@ -244,7 +242,7 @@ static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2) udnp2->dict1->dict2->userdef->string); g_assert_cmpstr(udnp1->dict1->dict2->string, ==, udnp2->dict1->dict2->string); - g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3); + g_assert(!udnp1->dict1->dict3 == !udnp2->dict1->dict3); g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==, udnp2->dict1->dict3->userdef->integer); g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==, @@ -428,131 +426,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 @@ -565,13 +549,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; } @@ -579,9 +558,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 6a417bb1029c..541bb4f63e36 100644 --- a/tests/unit/test-vmstate.c +++ b/tests/unit/test-vmstate.c @@ -28,7 +28,6 @@ #include "migration/vmstate.h" #include "migration/qemu-file-types.h" #include "../migration/qemu-file.h" -#include "../migration/qemu-file-channel.h" #include "../migration/savevm.h" #include "qemu/coroutine.h" #include "qemu/module.h" @@ -52,9 +51,9 @@ static QEMUFile *open_test_file(bool write) } ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd)); if (write) { - f = qemu_fopen_channel_output(ioc); + f = qemu_file_new_output(ioc); } else { - f = qemu_fopen_channel_input(ioc); + f = qemu_file_new_input(ioc); } object_unref(OBJECT(ioc)); return f; @@ -88,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/unit/test-xbzrle.c b/tests/unit/test-xbzrle.c index 795d6f1cbabb..ef951b6e5405 100644 --- a/tests/unit/test-xbzrle.c +++ b/tests/unit/test-xbzrle.c @@ -11,7 +11,6 @@ * */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "../migration/xbzrle.h" diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 35088dd67f78..a5c711b1de8e 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -331,9 +331,7 @@ vubr_backend_recv_cb(int sock, void *ctx) .msg_iovlen = num, .msg_flags = MSG_DONTWAIT, }; - do { - ret = recvmsg(vubr->backend_udp_sock, &msg, 0); - } while (ret == -1 && (errno == EINTR)); + ret = RETRY_ON_EINTR(recvmsg(vubr->backend_udp_sock, &msg, 0)); if (i == 0) { iov_restore_front(elem->in_sg, sg, hdrlen); @@ -468,8 +466,8 @@ vubr_queue_set_started(VuDev *dev, int qidx, bool started) if (started && vubr->notifier.fd >= 0) { vu_set_queue_host_notifier(dev, vq, vubr->notifier.fd, - qemu_real_host_page_size, - qidx * qemu_real_host_page_size); + qemu_real_host_page_size(), + qidx * qemu_real_host_page_size()); } if (qidx % 2 == 1) { @@ -601,7 +599,7 @@ static void *notifier_thread(void *arg) { VuDev *dev = (VuDev *)arg; VubrDev *vubr = container_of(dev, VubrDev, vudev); - int pagesize = qemu_real_host_page_size; + int pagesize = qemu_real_host_page_size(); int qidx; while (true) { @@ -631,15 +629,14 @@ 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; int fd; - length = qemu_real_host_page_size * VHOST_USER_BRIDGE_MAX_QUEUES; + 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 ae91f5043e50..2cc2203d0916 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -1,14 +1,23 @@ # Makefile for VM tests -.PHONY: vm-build-all vm-clean-all +# Hack to allow running in an unconfigured build tree +ifeq ($(wildcard $(SRC_PATH)/config-host.mak),) +VM_PYTHON = PYTHONPATH=$(SRC_PATH)/python /usr/bin/env python3 +VM_VENV = +HOST_ARCH := $(shell uname -m) +else +VM_PYTHON = $(TESTS_PYTHON) +VM_VENV = check-venv +HOST_ARCH = $(ARCH) +endif -HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m)) +.PHONY: vm-build-all vm-clean-all EFI_AARCH64 = $(wildcard $(BUILD_DIR)/pc-bios/edk2-aarch64-code.fd) -X86_IMAGES := freebsd netbsd openbsd centos fedora haiku.x86_64 +X86_IMAGES := freebsd netbsd openbsd haiku.x86_64 ifneq ($(GENISOIMAGE),) -X86_IMAGES += ubuntu.i386 centos +X86_IMAGES += centos ifneq ($(EFI_AARCH64),) ARM64_IMAGES += ubuntu.aarch64 centos.aarch64 endif @@ -36,10 +45,8 @@ 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" - @echo " vm-build-ubuntu.i386 - Build QEMU in ubuntu i386 VM" ifneq ($(EFI_AARCH64),) @echo " vm-build-ubuntu.aarch64 - Build QEMU in ubuntu aarch64 VM" @echo " vm-build-centos.aarch64 - Build QEMU in CentOS aarch64 VM" @@ -84,10 +91,11 @@ vm-clean-all: $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ $(SRC_PATH)/tests/vm/basevm.py \ - $(SRC_PATH)/tests/vm/Makefile.include + $(SRC_PATH)/tests/vm/Makefile.include \ + $(VM_VENV) @mkdir -p $(IMAGES_DIR) $(call quiet-command, \ - $(PYTHON) $< \ + $(VM_PYTHON) $< \ $(if $(V)$(DEBUG), --debug) \ $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ @@ -99,11 +107,10 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ --build-image $@, \ " VM-IMAGE $*") - # Build in VM $(IMAGE) -vm-build-%: $(IMAGES_DIR)/%.img +vm-build-%: $(IMAGES_DIR)/%.img $(VM_VENV) $(call quiet-command, \ - $(PYTHON) $(SRC_PATH)/tests/vm/$* \ + $(VM_PYTHON) $(SRC_PATH)/tests/vm/$* \ $(if $(V)$(DEBUG), --debug) \ $(if $(DEBUG), --interactive) \ $(if $(J),--jobs $(J)) \ @@ -127,9 +134,9 @@ vm-boot-serial-%: $(IMAGES_DIR)/%.img -device virtio-net-pci,netdev=vnet \ || true -vm-boot-ssh-%: $(IMAGES_DIR)/%.img +vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(VM_VENV) $(call quiet-command, \ - $(PYTHON) $(SRC_PATH)/tests/vm/$* \ + $(VM_PYTHON) $(SRC_PATH)/tests/vm/$* \ $(if $(J),--jobs $(J)) \ $(if $(V)$(DEBUG), --debug) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 254e11c932bf..23229e23d161 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -18,9 +18,6 @@ import logging import time import datetime -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) -from qemu.machine import QEMUMachine -from qemu.utils import get_info_usernet_hostfwd_port, kvm_available import subprocess import hashlib import argparse @@ -31,6 +28,9 @@ import traceback import shlex +from qemu.machine import QEMUMachine +from qemu.utils import get_info_usernet_hostfwd_port, kvm_available + SSH_KEY_FILE = os.path.join(os.path.dirname(__file__), "..", "keys", "id_rsa") SSH_PUB_KEY_FILE = os.path.join(os.path.dirname(__file__), @@ -99,6 +99,11 @@ def __init__(self, args, config=None): self._source_path = args.source_path # Allow input config to override defaults. self._config = DEFAULT_CONFIG.copy() + + # 1GB per core, minimum of 4. This is only a default. + mem = max(4, args.jobs) + self._config['memory'] = f"{mem}G" + if config != None: self._config.update(config) self.validate_ssh_keys() @@ -228,7 +233,8 @@ def _ssh_do(self, user, cmd, check): "-o", "UserKnownHostsFile=" + os.devnull, "-o", "ConnectTimeout={}".format(self._config["ssh_timeout"]), - "-p", str(self.ssh_port), "-i", self._ssh_tmp_key_file] + "-p", str(self.ssh_port), "-i", self._ssh_tmp_key_file, + "-o", "IdentitiesOnly=yes"] # If not in debug mode, set ssh to quiet mode to # avoid printing the results of commands. if not self.debug: @@ -563,8 +569,7 @@ def get_default_jobs(): # more cores. but only up to a reasonable limit. User # can always override these limits with --jobs. return min(multiprocessing.cpu_count() // 2, 8) - else: - return 1 + return 1 parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, diff --git a/tests/vm/centos b/tests/vm/centos index 5c7bc1c1a9a0..097a9ca14d3c 100755 --- a/tests/vm/centos +++ b/tests/vm/centos @@ -1,8 +1,8 @@ #!/usr/bin/env python3 # -# CentOS image +# CentOS 8 Stream image # -# Copyright 2018 Red Hat Inc. +# Copyright 2018, 2022 Red Hat Inc. # # Authors: # Fam Zheng @@ -28,13 +28,12 @@ class CentosVM(basevm.BaseVM): tar -xf $SRC_ARCHIVE; make docker-test-block@centos8 {verbose} J={jobs} NETWORK=1; make docker-test-quick@centos8 {verbose} J={jobs} NETWORK=1; - make docker-test-mingw@fedora {verbose} J={jobs} NETWORK=1; """ def build_image(self, img): - cimg = self._download_with_cache("https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.3.2011-20201204.2.x86_64.qcow2") + cimg = self._download_with_cache("https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-20220125.1.x86_64.qcow2") img_tmp = img + ".tmp" - subprocess.check_call(["ln", "-f", cimg, img_tmp]) + subprocess.check_call(['cp', '-f', cimg, img_tmp]) self.exec_qemu_img("resize", img_tmp, "50G") self.boot(img_tmp, extra_args = ["-cdrom", self.gen_cloud_init_iso()]) self.wait_ssh() diff --git a/tests/vm/centos.aarch64 b/tests/vm/centos.aarch64 index 81c3004c3c53..2de7ef6992c0 100755 --- a/tests/vm/centos.aarch64 +++ b/tests/vm/centos.aarch64 @@ -20,151 +20,38 @@ import time import traceback import aarch64vm + DEFAULT_CONFIG = { 'cpu' : "max", 'machine' : "virt,gic-version=max", - 'install_cmds' : "yum install -y make ninja-build git python3 gcc gcc-c++ flex bison, "\ - "yum install -y glib2-devel pixman-devel zlib-devel, "\ - "yum install -y perl-Test-Harness, "\ - "alternatives --set python /usr/bin/python3, "\ - "sudo dnf config-manager "\ - "--add-repo=https://download.docker.com/linux/centos/docker-ce.repo,"\ - "sudo dnf install --nobest -y docker-ce.aarch64,"\ - "systemctl enable docker", + 'install_cmds' : ( + "dnf config-manager --set-enabled powertools, " + "dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo, " + "dnf install -y make ninja-build git python38 gcc gcc-c++ flex bison "\ + "glib2-devel perl pixman-devel zlib-devel docker-ce.aarch64, " + "systemctl enable docker, " + ), # We increase beyond the default time since during boot # it can take some time (many seconds) to log into the VM. 'ssh_timeout' : 60, } + class CentosAarch64VM(basevm.BaseVM): - name = "centos.aarch64" + name = "centos8.aarch64" arch = "aarch64" - login_prompt = "localhost login:" - prompt = '[root@localhost ~]#' - image_name = "CentOS-8-aarch64-1905-dvd1.iso" - image_link = "http://mirrors.usc.edu/pub/linux/distributions/centos/8.0.1905/isos/aarch64/" + image_name = "CentOS-Stream-GenericCloud-8-20220125.1.aarch64.qcow2" + image_link = "https://cloud.centos.org/centos/8-stream/aarch64/images/" image_link += image_name BUILD_SCRIPT = """ set -e; cd $(mktemp -d); - sudo chmod a+r /dev/vdb; - tar --checkpoint=.10 -xf /dev/vdb; + export SRC_ARCHIVE=/dev/vdb; + sudo chmod a+r $SRC_ARCHIVE; + tar -xf $SRC_ARCHIVE; ./configure {configure_opts}; make --output-sync {target} -j{jobs} {verbose}; """ - def set_key_perm(self): - """Set permissions properly on certain files to allow - ssh access.""" - self.console_wait_send(self.prompt, - "/usr/sbin/restorecon -R -v /root/.ssh\n") - self.console_wait_send(self.prompt, - "/usr/sbin/restorecon -R -v "\ - "/home/{}/.ssh\n".format(self._config["guest_user"])) - - def create_kickstart(self): - """Generate the kickstart file used to generate the centos image.""" - # Start with the template for the kickstart. - ks_file = self._source_path + "/tests/vm/centos-8-aarch64.ks" - subprocess.check_call("cp {} ./ks.cfg".format(ks_file), shell=True) - # Append the ssh keys to the kickstart file - # as the post processing phase of installation. - with open("ks.cfg", "a") as f: - # Add in the root pw and guest user. - rootpw = "rootpw --plaintext {}\n" - f.write(rootpw.format(self._config["root_pass"])) - add_user = "user --groups=wheel --name={} "\ - "--password={} --plaintext\n" - f.write(add_user.format(self._config["guest_user"], - self._config["guest_pass"])) - # Add the ssh keys. - f.write("%post --log=/root/ks-post.log\n") - f.write("mkdir -p /root/.ssh\n") - addkey = 'echo "{}" >> /root/.ssh/authorized_keys\n' - addkey_cmd = addkey.format(self._config["ssh_pub_key"]) - f.write(addkey_cmd) - f.write('mkdir -p /home/{}/.ssh\n'.format(self._config["guest_user"])) - addkey = 'echo "{}" >> /home/{}/.ssh/authorized_keys\n' - addkey_cmd = addkey.format(self._config["ssh_pub_key"], - self._config["guest_user"]) - f.write(addkey_cmd) - f.write("%end\n") - # Take our kickstart file and create an .iso from it. - # The .iso will be provided to qemu as we boot - # from the install dvd. - # Anaconda will recognize the label "OEMDRV" and will - # start the automated installation. - gen_iso_img = 'genisoimage -output ks.iso -volid "OEMDRV" ks.cfg' - subprocess.check_call(gen_iso_img, shell=True) - - def wait_for_shutdown(self): - """We wait for qemu to shutdown the VM and exit. - While this happens we display the console view - for easier debugging.""" - # The image creation is essentially done, - # so whether or not the wait is successful we want to - # wait for qemu to exit (the self.wait()) before we return. - try: - self.console_wait("reboot: Power down") - except Exception as e: - sys.stderr.write("Exception hit\n") - if isinstance(e, SystemExit) and e.code == 0: - return 0 - traceback.print_exc() - finally: - self.wait() - - def build_base_image(self, dest_img): - """Run through the centos installer to create - a base image with name dest_img.""" - # We create the temp image, and only rename - # to destination when we are done. - img = dest_img + ".tmp" - # Create an empty image. - # We will provide this as the install destination. - qemu_img_create = "qemu-img create {} 50G".format(img) - subprocess.check_call(qemu_img_create, shell=True) - - # Create our kickstart file to be fed to the installer. - self.create_kickstart() - # Boot the install dvd with the params as our ks.iso - os_img = self._download_with_cache(self.image_link) - dvd_iso = "centos-8-dvd.iso" - subprocess.check_call(["cp", "-f", os_img, dvd_iso]) - extra_args = "-cdrom ks.iso" - extra_args += " -drive file={},if=none,id=drive1,cache=writeback" - extra_args += " -device virtio-blk,drive=drive1,bootindex=1" - extra_args = extra_args.format(dvd_iso).split(" ") - self.boot(img, extra_args=extra_args) - self.console_wait_send("change the selection", "\n") - # We seem to need to hit esc (chr(27)) twice to abort the - # media check, which takes a long time. - # Waiting a bit seems to be more reliable before hitting esc. - self.console_wait("Checking") - time.sleep(5) - self.console_wait_send("Checking", chr(27)) - time.sleep(5) - self.console_wait_send("Checking", chr(27)) - print("Found Checking") - # Give sufficient time for the installer to create the image. - self.console_init(timeout=7200) - self.wait_for_shutdown() - os.rename(img, dest_img) - print("Done with base image build: {}".format(dest_img)) - - def check_create_base_img(self, img_base, img_dest): - """Create a base image using the installer. - We will use the base image if it exists. - This helps cut down on install time in case we - need to restart image creation, - since the base image creation can take a long time.""" - if not os.path.exists(img_base): - print("Generate new base image: {}".format(img_base)) - self.build_base_image(img_base); - else: - print("Use existing base image: {}".format(img_base)) - # Save a copy of the base image and copy it to dest. - # which we will use going forward. - subprocess.check_call(["cp", img_base, img_dest]) def boot(self, img, extra_args=None): aarch64vm.create_flash_images(self._tmpdir, self._efi_aarch64) @@ -186,42 +73,28 @@ class CentosAarch64VM(basevm.BaseVM): super(CentosAarch64VM, self).boot(img, extra_args=extra_args) def build_image(self, img): + cimg = self._download_with_cache(self.image_link) img_tmp = img + ".tmp" - self.check_create_base_img(img + ".base", img_tmp) - - # Boot the new image for the first time to finish installation. - self.boot(img_tmp) - self.console_init() - self.console_wait_send(self.login_prompt, "root\n") - self.console_wait_send("Password:", - "{}\n".format(self._config["root_pass"])) - - self.set_key_perm() - self.console_wait_send(self.prompt, "rpm -q centos-release\n") - enable_adapter = "sed -i 's/ONBOOT=no/ONBOOT=yes/g'" \ - " /etc/sysconfig/network-scripts/ifcfg-enp0s1\n" - self.console_wait_send(self.prompt, enable_adapter) - self.console_wait_send(self.prompt, "ifup enp0s1\n") - self.console_wait_send(self.prompt, - 'echo "qemu ALL=(ALL) NOPASSWD:ALL" | '\ - 'sudo tee /etc/sudoers.d/qemu\n') - self.console_wait(self.prompt) - - # Rest of the commands we issue through ssh. + subprocess.run(['cp', '-f', cimg, img_tmp]) + self.exec_qemu_img("resize", img_tmp, "50G") + self.boot(img_tmp, extra_args = ["-cdrom", self.gen_cloud_init_iso()]) self.wait_ssh(wait_root=True) + self.ssh_root_check("touch /etc/cloud/cloud-init.disabled") # If the user chooses *not* to do the second phase, # then we will jump right to the graceful shutdown if self._config['install_cmds'] != "": install_cmds = self._config['install_cmds'].split(',') for cmd in install_cmds: - self.ssh_root(cmd) + self.ssh_root_check(cmd) + self.ssh_root("poweroff") - self.wait_for_shutdown() + self.wait() os.rename(img_tmp, img) print("image creation complete: {}".format(img)) return 0 + if __name__ == "__main__": defaults = aarch64vm.get_config_defaults(CentosAarch64VM, DEFAULT_CONFIG) sys.exit(basevm.main(CentosAarch64VM, defaults)) diff --git a/tests/vm/fedora b/tests/vm/fedora deleted file mode 100755 index b977efe4a2eb..000000000000 --- a/tests/vm/fedora +++ /dev/null @@ -1,191 +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-Test-Harness', - - # 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 = [ - "-bios", "pc-bios/bios-256k.bin", - "-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 805db759d670..ba2ba23d24d0 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -28,8 +28,8 @@ class FreeBSDVM(basevm.BaseVM): name = "freebsd" arch = "x86_64" - link = "https://download.freebsd.org/ftp/releases/ISO-IMAGES/12.3/FreeBSD-12.3-RELEASE-amd64-disc1.iso.xz" - csum = "36dd0de50f1fe5f0a88e181e94657656de26fb64254412f74e80e128e8b938b4" + link = "https://download.freebsd.org/ftp/releases/ISO-IMAGES/12.4/FreeBSD-12.4-RELEASE-amd64-disc1.iso.xz" + csum = "1dcf6446e31bf3f81b582e9aba3319a258c29a937a2af6138ee4b181ed719a87" size = "20G" pkgs = [ # build tools @@ -63,6 +63,12 @@ class FreeBSDVM(basevm.BaseVM): # libs: migration "zstd", + + # libs: networking + "libslirp", + + # libs: sndio + "sndio", ] BUILD_SCRIPT = """ @@ -95,7 +101,6 @@ class FreeBSDVM(basevm.BaseVM): self.print_step("Booting installer") self.boot(img_tmp, extra_args = [ - "-bios", "pc-bios/bios-256k.bin", "-machine", "graphics=off", "-device", "VGA", "-cdrom", iso diff --git a/tests/vm/haiku.x86_64 b/tests/vm/haiku.x86_64 index 936f7d2ae2ea..29668bc27279 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 4cc58df130f3..aa54338dfa92 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 @@ -46,13 +46,17 @@ class NetBSDVM(basevm.BaseVM): "jpeg", "png", - # libs: ui + # libs: ui + "capstone", "SDL2", "gtk3+", "libxkbcommon", # libs: migration "zstd", + + # libs: networking + "libslirp", ] BUILD_SCRIPT = """ @@ -85,7 +89,6 @@ class NetBSDVM(basevm.BaseVM): self.print_step("Booting installer") self.boot(img_tmp, extra_args = [ - "-bios", "pc-bios/bios-256k.bin", "-machine", "graphics=off", "-cdrom", iso ]) diff --git a/tests/vm/openbsd b/tests/vm/openbsd index 337fe7c30334..eaeb201e9103 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM): name = "openbsd" arch = "x86_64" - link = "https://cdn.openbsd.org/pub/OpenBSD/7.0/amd64/install70.iso" - csum = "1882f9a23c9800e5dba3dbd2cf0126f552605c915433ef4c5bb672610a4ca3a4" + link = "https://cdn.openbsd.org/pub/OpenBSD/7.2/amd64/install72.iso" + csum = "0369ef40a3329efcb978c578c7fdc7bda71e502aecec930a74b44160928c91d3" size = "20G" pkgs = [ # tools @@ -48,13 +48,17 @@ class OpenBSDVM(basevm.BaseVM): "jpeg", "png", - # libs: ui + # libs: ui + "capstone", "sdl2", "gtk+3", "libxkbcommon", # libs: migration "zstd", + + # libs: networking + "libslirp", ] BUILD_SCRIPT = """ @@ -81,7 +85,6 @@ class OpenBSDVM(basevm.BaseVM): self.print_step("Booting installer") self.boot(img_tmp, extra_args = [ - "-bios", "pc-bios/bios-256k.bin", "-machine", "graphics=off", "-device", "VGA", "-cdrom", iso diff --git a/tests/vm/ubuntu.aarch64 b/tests/vm/ubuntu.aarch64 index b291945a7e9d..666947393bdf 100755 --- a/tests/vm/ubuntu.aarch64 +++ b/tests/vm/ubuntu.aarch64 @@ -32,9 +32,13 @@ DEFAULT_CONFIG = { class UbuntuAarch64VM(ubuntuvm.UbuntuVM): name = "ubuntu.aarch64" arch = "aarch64" - image_name = "ubuntu-18.04-server-cloudimg-arm64.img" - image_link = "https://cloud-images.ubuntu.com/releases/18.04/release/" + image_name - image_sha256="0fdcba761965735a8a903d8b88df8e47f156f48715c00508e4315c506d7d3cb1" + # NOTE: The Ubuntu 20.04 cloud images are periodically updated. The + # fixed image chosen below is the latest release at time of + # writing. Using a rolling latest instead would mean that the SHA + # would be incorrect at an indeterminate point in the future. + image_name = "focal-server-cloudimg-arm64.img" + image_link = "https://cloud-images.ubuntu.com/focal/20220615/" + image_name + image_sha256="95a027336e197debe88c92ff2e554598e23c409139e1e750b71b3b820b514832" BUILD_SCRIPT = """ set -e; cd $(mktemp -d); diff --git a/tests/vm/ubuntu.i386 b/tests/vm/ubuntu.i386 deleted file mode 100755 index 47681b6f87dd..000000000000 --- a/tests/vm/ubuntu.i386 +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -# -# Ubuntu i386 image -# -# Copyright 2017 Red Hat Inc. -# -# Authors: -# Fam Zheng -# -# This code is licensed under the GPL version 2 or later. See -# the COPYING file in the top-level directory. -# - -import sys -import basevm -import ubuntuvm - -DEFAULT_CONFIG = { - 'install_cmds' : "apt-get update,"\ - "apt-get build-dep -y qemu,"\ - "apt-get install -y libfdt-dev language-pack-en ninja-build", -} - -class UbuntuX86VM(ubuntuvm.UbuntuVM): - name = "ubuntu.i386" - arch = "i386" - image_link="https://cloud-images.ubuntu.com/releases/bionic/"\ - "release-20191114/ubuntu-18.04-server-cloudimg-i386.img" - image_sha256="28969840626d1ea80bb249c08eef1a4533e8904aa51a327b40f37ac4b4ff04ef" - BUILD_SCRIPT = """ - set -e; - cd $(mktemp -d); - sudo chmod a+r /dev/vdb; - tar -xf /dev/vdb; - ./configure {configure_opts}; - make --output-sync {target} -j{jobs} {verbose}; - """ - -if __name__ == "__main__": - sys.exit(basevm.main(UbuntuX86VM, DEFAULT_CONFIG)) diff --git a/tools/meson.build b/tools/meson.build index 46977af84f4d..10eb3a043f77 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -3,7 +3,7 @@ have_virtiofsd = get_option('virtiofsd') \ error_message: 'virtiofsd requires Linux') \ .require(seccomp.found() and libcap_ng.found(), error_message: 'virtiofsd requires libcap-ng-devel and seccomp-devel') \ - .require('CONFIG_VHOST_USER' in config_host, + .require(have_vhost_user, error_message: 'virtiofsd needs vhost-user-support') \ .disable_auto_if(not have_tools and not have_system) \ .allowed() diff --git a/tools/virtiofsd/fuse_log.c b/tools/virtiofsd/fuse_log.c index 745d88cd2a49..2de3f48ee7ea 100644 --- a/tools/virtiofsd/fuse_log.c +++ b/tools/virtiofsd/fuse_log.c @@ -12,6 +12,7 @@ #include "fuse_log.h" +G_GNUC_PRINTF(2, 0) static void default_log_func(__attribute__((unused)) enum fuse_log_level level, const char *fmt, va_list ap) { diff --git a/tools/virtiofsd/fuse_log.h b/tools/virtiofsd/fuse_log.h index 8d7091bd4d0b..e5c2967ab95a 100644 --- a/tools/virtiofsd/fuse_log.h +++ b/tools/virtiofsd/fuse_log.h @@ -45,7 +45,8 @@ enum fuse_log_level { * @param ap format string arguments */ typedef void (*fuse_log_func_t)(enum fuse_log_level level, const char *fmt, - va_list ap); + va_list ap) + G_GNUC_PRINTF(2, 0); /** * Install a custom log handler function. @@ -68,6 +69,7 @@ void fuse_set_log_func(fuse_log_func_t func); * @param level severity level (FUSE_LOG_ERR, FUSE_LOG_DEBUG, etc) * @param fmt sprintf-style format string including newline */ -void fuse_log(enum fuse_log_level level, const char *fmt, ...); +void fuse_log(enum fuse_log_level level, const char *fmt, ...) + G_GNUC_PRINTF(2, 3); #endif /* FUSE_LOG_H_ */ diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c index 752928741dd5..194a1b813b3b 100644 --- a/tools/virtiofsd/fuse_lowlevel.c +++ b/tools/virtiofsd/fuse_lowlevel.c @@ -216,7 +216,6 @@ static int send_reply(fuse_req_t req, int error, const void *arg, int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) { - int res; g_autofree struct iovec *padded_iov = NULL; padded_iov = g_try_new(struct iovec, count + 1); @@ -227,9 +226,7 @@ int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); count++; - res = send_reply_iov(req, 0, padded_iov, count); - - return res; + return send_reply_iov(req, 0, padded_iov, count); } @@ -589,7 +586,6 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, g_autofree struct fuse_ioctl_iovec *out_fiov = NULL; struct iovec iov[4]; size_t count = 1; - int res; memset(&arg, 0, sizeof(arg)); arg.flags |= FUSE_IOCTL_RETRY; @@ -601,15 +597,13 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, /* Can't handle non-compat 64bit ioctls on 32bit */ if (sizeof(void *) == 4 && req->ioctl_64bit) { - res = fuse_reply_err(req, EINVAL); - return res; + return fuse_reply_err(req, EINVAL); } if (in_count) { in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count); if (!in_fiov) { - res = fuse_reply_err(req, ENOMEM); - return res; + return fuse_reply_err(req, ENOMEM); } iov[count].iov_base = (void *)in_fiov; @@ -619,8 +613,7 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, if (out_count) { out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count); if (!out_fiov) { - res = fuse_reply_err(req, ENOMEM); - return res; + return fuse_reply_err(req, ENOMEM); } iov[count].iov_base = (void *)out_fiov; @@ -628,9 +621,7 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, count++; } - res = send_reply_iov(req, 0, iov, count); - - return res; + return send_reply_iov(req, 0, iov, count); } int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size) @@ -659,7 +650,6 @@ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, { g_autofree struct iovec *padded_iov = NULL; struct fuse_ioctl_out arg; - int res; padded_iov = g_try_new(struct iovec, count + 2); if (padded_iov == NULL) { @@ -673,9 +663,7 @@ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); - res = send_reply_iov(req, 0, padded_iov, count + 2); - - return res; + return send_reply_iov(req, 0, padded_iov, count + 2); } int fuse_reply_poll(fuse_req_t req, unsigned revents) @@ -2025,7 +2013,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 +2162,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 60b96470c51a..9368e292e4e8 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); @@ -901,10 +901,12 @@ static bool fv_socket_lock(struct fuse_session *se) { g_autofree gchar *sk_name = NULL; g_autofree gchar *pidfile = NULL; + g_autofree gchar *state = NULL; g_autofree gchar *dir = NULL; Error *local_err = NULL; - dir = qemu_get_local_state_pathname("run/virtiofsd"); + state = qemu_get_local_state_dir(); + dir = g_build_filename(state, "run", "virtiofsd", NULL); if (g_mkdir_with_parents(dir, S_IRWXU) < 0) { fuse_log(FUSE_LOG_ERR, "%s: Failed to create directory %s: %s\n", diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c index e226fc590fb7..f5f66f292c70 100644 --- a/tools/virtiofsd/helper.c +++ b/tools/virtiofsd/helper.c @@ -188,6 +188,9 @@ void fuse_cmdline_help(void) " -o announce_submounts Announce sub-mount points to the guest\n" " -o posix_acl/no_posix_acl Enable/Disable posix_acl. (default: disabled)\n" " -o security_label/no_security_label Enable/Disable security label. (default: disabled)\n" + " -o killpriv_v2/no_killpriv_v2\n" + " Enable/Disable FUSE_HANDLE_KILLPRIV_V2.\n" + " (default: enabled as long as client supports it)\n" ); } @@ -272,7 +275,7 @@ int fuse_daemonize(int foreground) int waiter[2]; char completed; - if (pipe(waiter)) { + if (!g_unix_open_pipe(waiter, FD_CLOEXEC, NULL)) { fuse_log(FUSE_LOG_ERR, "fuse_daemonize: pipe: %s\n", strerror(errno)); return -1; diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 028dacdd8f5a..40ea2ed27fef 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -38,7 +38,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" #include "qemu-version.h" -#include "qemu-common.h" +#include "qemu/help-texts.h" #include "fuse_virtio.h" #include "fuse_log.h" #include "fuse_lowlevel.h" @@ -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; @@ -2319,7 +2310,7 @@ static int do_lo_create(fuse_req_t req, struct lo_inode *parent_inode, * If security.selinux has not been remapped and selinux is enabled, * use fscreate to set context before file creation. If not, use * tmpfile method for regular files. Otherwise fallback to - * non-atomic method of file creation and xattr settting. + * non-atomic method of file creation and xattr setting. */ if (!mapped_name && lo->use_fscreate) { err = do_create_secctx_fscreate(req, parent_inode, name, mode, fi, @@ -4191,9 +4182,11 @@ static void setup_nofile_rlimit(unsigned long rlimit_nofile) } } +G_GNUC_PRINTF(2, 0) 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 +4199,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/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c index 888295c073de..0033dab4939e 100644 --- a/tools/virtiofsd/passthrough_seccomp.c +++ b/tools/virtiofsd/passthrough_seccomp.c @@ -110,6 +110,7 @@ static const int syscall_allowlist[] = { #endif SCMP_SYS(set_robust_list), SCMP_SYS(setxattr), + SCMP_SYS(sigreturn), SCMP_SYS(symlinkat), SCMP_SYS(syncfs), SCMP_SYS(time), /* Rarely needed, except on static builds */ diff --git a/tools/virtiofsd/passthrough_seccomp.h b/tools/virtiofsd/passthrough_seccomp.h index a3ab073f08fa..12674fc05030 100644 --- a/tools/virtiofsd/passthrough_seccomp.h +++ b/tools/virtiofsd/passthrough_seccomp.h @@ -6,10 +6,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef VIRTIOFSD_SECCOMP_H -#define VIRTIOFSD_SECCOMP_H - +#ifndef VIRTIOFSD_PASSTHROUGH_SECCOMP_H +#define VIRTIOFSD_PASSTHROUGH_SECCOMP_H void setup_seccomp(bool enable_syslog); -#endif /* VIRTIOFSD_SECCOMP_H */ +#endif /* VIRTIOFSD_PASSTHROUGH_SECCOMP_H */ diff --git a/trace-events b/trace-events index bc7100667545..b6b84b175e16 100644 --- a/trace-events +++ b/trace-events @@ -42,38 +42,6 @@ find_ram_offset(uint64_t size, uint64_t offset) "size: 0x%" PRIx64 " @ 0x%" PRIx find_ram_offset_loop(uint64_t size, uint64_t candidate, uint64_t offset, uint64_t next, uint64_t mingap) "trying size: 0x%" PRIx64 " @ 0x%" PRIx64 ", offset: 0x%" PRIx64" next: 0x%" PRIx64 " mingap: 0x%" PRIx64 ram_block_discard_range(const char *rbname, void *hva, size_t length, bool need_madvise, bool need_fallocate, int ret) "%s@%p + 0x%zx: madvise: %d fallocate: %d ret: %d" -# accel/tcg/cputlb.c -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 8418673c18cf..232c97a4a183 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 9079ef829b51..3d14bffaf80f 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 c4e5468f9e64..e915c344a8da 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -27,13 +27,15 @@ #import #include -#include "qemu-common.h" +#include "qemu/help-texts.h" +#include "qemu-main.h" #include "ui/clipboard.h" #include "ui/console.h" #include "ui/input.h" #include "ui/kbd-state.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" +#include "sysemu/runstate-action.h" #include "sysemu/cpu-throttle.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" @@ -98,13 +100,9 @@ static void cocoa_switch(DisplayChangeListener *dcl, 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; @@ -559,8 +557,20 @@ - (void) updateUIInfoLocked CGDirectDisplayID display = [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]; NSSize screenSize = [[[self window] screen] frame].size; CGSize screenPhysicalSize = CGDisplayScreenSize(display); + CVDisplayLinkRef displayLink; frameSize = isFullscreen ? screenSize : [self frame].size; + + if (!CVDisplayLinkCreateWithCGDisplay(display, &displayLink)) { + CVTime period = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink); + CVDisplayLinkRelease(displayLink); + if (!(period.flags & kCVTimeIsIndefinite)) { + update_displaychangelistener(&dcl, + 1000 * period.timeValue / period.timeScale); + info.refresh_rate = (int64_t)1000 * period.timeScale / period.timeValue; + } + } + info.width_mm = frameSize.width / screenSize.width * screenPhysicalSize.width; info.height_mm = frameSize.height / screenSize.height * screenPhysicalSize.height; } else { @@ -583,7 +593,7 @@ - (void) updateUIInfo /* * 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. @@ -776,16 +786,6 @@ - (void) handleMonitorInput:(NSEvent *)event - (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]; }); @@ -798,7 +798,6 @@ - (bool) handleEventLocked:(NSEvent *)event int buttons = 0; int keycode = 0; bool mouse_event = false; - static bool switched_to_fullscreen = false; // Location of event in virtual screen coordinates NSPoint p = [self screenLocationOfEvent:event]; NSUInteger modifiers = [event modifierFlags]; @@ -950,13 +949,6 @@ - (bool) handleEventLocked:(NSEvent *)event // forward command key combos to the host UI unless the mouse is grabbed if (!isMouseGrabbed && ([event modifierFlags] & NSEventModifierFlagCommand)) { - /* - * Prevent the command key from being stuck down in the guest - * when using Command-F to switch to full screen mode. - */ - if (keycode == Q_KEY_CODE_F) { - switched_to_fullscreen = true; - } return false; } @@ -1281,15 +1273,16 @@ - (void)applicationDidFinishLaunching: (NSNotification *) note { COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); allow_events = true; - /* Tell cocoa_display_init to proceed */ - qemu_sem_post(&app_started_sem); } - (void)applicationWillTerminate:(NSNotification *)aNotification { COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n"); - qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); + with_iothread_lock(^{ + shutdown_action = SHUTDOWN_ACTION_POWEROFF; + qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); + }); /* * Sleep here, because returning will cause OSX to kill us @@ -1488,8 +1481,8 @@ - (void)ejectDeviceMedia:(id)sender __block Error *err = NULL; with_iothread_lock(^{ - qmp_eject(true, [drive cStringUsingEncoding: NSASCIIStringEncoding], - false, NULL, false, false, &err); + qmp_eject([drive cStringUsingEncoding: NSASCIIStringEncoding], + NULL, false, false, &err); }); handleAnyDeviceErrors(err); } @@ -1523,13 +1516,13 @@ - (void)changeDeviceMedia:(id)sender __block Error *err = NULL; with_iothread_lock(^{ - qmp_blockdev_change_medium(true, - [drive cStringUsingEncoding: + qmp_blockdev_change_medium([drive cStringUsingEncoding: NSASCIIStringEncoding], - false, NULL, + NULL, [file cStringUsingEncoding: NSASCIIStringEncoding], - true, "raw", + "raw", + true, false, false, 0, &err); }); @@ -1888,16 +1881,18 @@ static void cocoa_clipboard_notify(Notifier *notifier, void *data) static void cocoa_clipboard_request(QemuClipboardInfo *info, QemuClipboardType type) { + NSAutoreleasePool *pool; NSData *text; switch (type) { case QEMU_CLIPBOARD_TYPE_TEXT: + pool = [[NSAutoreleasePool alloc] init]; text = [[NSPasteboard generalPasteboard] dataForType:NSPasteboardTypeString]; if (text) { qemu_clipboard_set_data(&cbpeer, info, type, [text length], [text bytes], true); - [text release]; } + [pool release]; break; default: break; @@ -1907,92 +1902,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(); } @@ -2071,25 +2019,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) { @@ -2109,6 +2074,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 1752f2ec8897..9ff9217f9bce 100644 --- a/ui/console.c +++ b/ui/console.c @@ -37,6 +37,9 @@ #include "exec/memory.h" #include "io/channel-file.h" #include "qom/object.h" +#ifdef CONFIG_PNG +#include +#endif #define DEFAULT_BACKSCROLL 512 #define CONSOLE_CURSOR_PERIOD 500 @@ -157,7 +160,6 @@ static void gui_update(void *opaque) uint64_t dcl_interval; DisplayState *ds = opaque; DisplayChangeListener *dcl; - QemuConsole *con; ds->refreshing = true; dpy_refresh(ds); @@ -172,11 +174,6 @@ static void gui_update(void *opaque) } if (ds->update_interval != interval) { ds->update_interval = interval; - QTAILQ_FOREACH(con, &consoles, next) { - if (con->hw_ops->update_interval) { - con->hw_ops->update_interval(con->hw, interval); - } - } trace_console_refresh(interval); } ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); @@ -218,7 +215,7 @@ static void gui_setup_refresh(DisplayState *ds) void graphic_hw_update_done(QemuConsole *con) { if (con) { - qemu_co_queue_restart_all(&con->dump_queue); + qemu_co_enter_all(&con->dump_queue, NULL); } } @@ -291,6 +288,88 @@ void graphic_hw_invalidate(QemuConsole *con) } } +#ifdef CONFIG_PNG +/** + * png_save: Take a screenshot as PNG + * + * Saves screendump as a PNG file + * + * Returns true for success or false for error. + * + * @fd: File descriptor for PNG file. + * @image: Image data in pixman format. + * @errp: Pointer to an error. + */ +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); + 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); + FILE *f = fdopen(fd, "wb"); + int y; + if (!f) { + error_setg_errno(errp, errno, + "Failed to create file from file descriptor"); + return false; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL); + if (!png_ptr) { + error_setg(errp, "PNG creation failed. Unable to write struct"); + fclose(f); + return false; + } + + info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) { + error_setg(errp, "PNG creation failed. Unable to write info"); + fclose(f); + png_destroy_write_struct(&png_ptr, &info_ptr); + return false; + } + + png_init_io(png_ptr, f); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_write_info(png_ptr, info_ptr); + + for (y = 0; y < height; ++y) { + qemu_pixman_linebuf_fill(linebuf, image, width, 0, y); + png_write_row(png_ptr, buf); + } + + png_write_end(png_ptr, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (fclose(f) != 0) { + error_setg_errno(errp, errno, + "PNG creation failed. Unable to close file"); + return false; + } + + return true; +} + +#else /* no png support */ + +static bool png_save(int fd, pixman_image_t *image, Error **errp) +{ + error_setg(errp, "Enable PNG support with libpng for screendump"); + return false; +} + +#endif /* CONFIG_PNG */ + static bool ppm_save(int fd, pixman_image_t *image, Error **errp) { int width = pixman_image_get_width(image); @@ -328,15 +407,16 @@ static void graphic_hw_update_bh(void *con) /* Safety: coroutine-only, concurrent-coroutine safe, main thread only */ void coroutine_fn -qmp_screendump(const char *filename, bool has_device, const char *device, - bool has_head, int64_t head, Error **errp) +qmp_screendump(const char *filename, const char *device, + bool has_head, int64_t head, + bool has_format, ImageFormat format, Error **errp) { g_autoptr(pixman_image_t) image = NULL; QemuConsole *con; DisplaySurface *surface; int fd; - if (has_device) { + if (device) { con = qemu_console_lookup_by_device_name(device, has_head ? head : 0, errp); if (!con) { @@ -385,8 +465,16 @@ qmp_screendump(const char *filename, bool has_device, const char *device, * yields and releases the BQL. It could produce corrupted dump, but * it should be otherwise safe. */ - if (!ppm_save(fd, image, errp)) { - qemu_unlink(filename); + if (has_format && format == IMAGE_FORMAT_PNG) { + /* PNG format specified for screendump */ + if (!png_save(fd, image, errp)) { + qemu_unlink(filename); + } + } else { + /* PPM format specified/default for screendump */ + if (!ppm_save(fd, image, errp)) { + qemu_unlink(filename); + } } } @@ -1209,7 +1297,7 @@ static void kbd_send_chars(QemuConsole *s) uint32_t size; buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size); - qemu_chr_be_write(s->chr, (uint8_t *)buf, size); + qemu_chr_be_write(s->chr, buf, size); len = qemu_chr_be_can_write(s->chr); avail -= size; } @@ -1279,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, }; @@ -2224,11 +2313,50 @@ bool qemu_console_is_gl_blocked(QemuConsole *con) return con->gl_block; } +bool qemu_console_is_multihead(DeviceState *dev) +{ + QemuConsole *con; + Object *obj; + uint32_t f = 0xffffffff; + uint32_t h; + + QTAILQ_FOREACH(con, &consoles, next) { + obj = object_property_get_link(OBJECT(con), + "device", &error_abort); + if (DEVICE(obj) != dev) { + continue; + } + + h = object_property_get_uint(OBJECT(con), + "head", &error_abort); + if (f == 0xffffffff) { + f = h; + } else if (h != f) { + return true; + } + } + return false; +} + char *qemu_console_get_label(QemuConsole *con) { if (con->console_type == GRAPHIC_CONSOLE) { if (con->device) { - return g_strdup(object_get_typename(con->device)); + DeviceState *dev; + bool multihead; + + dev = DEVICE(con->device); + multihead = qemu_console_is_multihead(dev); + if (multihead) { + return g_strdup_printf("%s.%d", dev->id ? + dev->id : + object_get_typename(con->device), + con->head); + } else { + return g_strdup_printf("%s", dev->id ? + dev->id : + object_get_typename(con->device)); + } } return g_strdup("VGA"); } else { @@ -2447,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; } @@ -2502,7 +2632,11 @@ bool qemu_display_find_default(DisplayOptions *opts) for (i = 0; i < (int)ARRAY_SIZE(prio); i++) { if (dpys[prio[i]] == NULL) { - ui_module_load_one(DisplayType_str(prio[i])); + Error *local_err = NULL; + int rv = ui_module_load(DisplayType_str(prio[i]), &local_err); + if (rv < 0) { + error_report_err(local_err); + } } if (dpys[prio[i]] == NULL) { continue; @@ -2520,7 +2654,11 @@ void qemu_display_early_init(DisplayOptions *opts) return; } if (dpys[opts->type] == NULL) { - ui_module_load_one(DisplayType_str(opts->type)); + Error *local_err = NULL; + int rv = ui_module_load(DisplayType_str(opts->type), &local_err); + if (rv < 0) { + error_report_err(local_err); + } } if (dpys[opts->type] == NULL) { error_report("Display '%s' is not available.", @@ -2550,7 +2688,11 @@ void qemu_display_help(void) printf("none\n"); for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) { if (!dpys[idx]) { - ui_module_load_one(DisplayType_str(idx)); + Error *local_err = NULL; + int rv = ui_module_load(DisplayType_str(idx), &local_err); + if (rv < 0) { + error_report_err(local_err); + } } if (dpys[idx]) { printf("%s\n", DisplayType_str(dpys[idx]->type)); diff --git a/ui/curses.c b/ui/curses.c index 861d63244c70..de962faa7cd6 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.c b/ui/dbus.c index 7a87612379e8..32d88dc94a7e 100644 --- a/ui/dbus.c +++ b/ui/dbus.c @@ -268,6 +268,7 @@ dbus_display_add_client_ready(GObject *source_object, } g_dbus_object_manager_server_set_connection(dbus_display->server, conn); + g_dbus_connection_start_message_processing(conn); } @@ -300,7 +301,8 @@ dbus_display_add_client(int csock, Error **errp) g_dbus_connection_new(G_IO_STREAM(conn), guid, - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER | + G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING, NULL, dbus_display->add_client_cancellable, dbus_display_add_client_ready, diff --git a/ui/dbus.h b/ui/dbus.h index 5f5c1f759c9b..9c149e7b416d 100644 --- a/ui/dbus.h +++ b/ui/dbus.h @@ -21,8 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef UI_DBUS_H_ -#define UI_DBUS_H_ + +#ifndef UI_DBUS_H +#define UI_DBUS_H #include "chardev/char-socket.h" #include "qemu/dbus.h" @@ -30,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; @@ -144,4 +145,4 @@ void dbus_chardev_init(DBusDisplay *dpy); void dbus_clipboard_init(DBusDisplay *dpy); -#endif /* UI_DBUS_H_ */ +#endif /* UI_DBUS_H */ diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c index d58fd761abdf..8d8a636fd1fa 100644 --- a/ui/gtk-clipboard.c +++ b/ui/gtk-clipboard.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/main-loop.h" #include "ui/gtk.h" diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index e3bd4bc27431..e84431790c9b 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -140,8 +140,8 @@ void gd_egl_refresh(DisplayChangeListener *dcl) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - vc->gfx.dcl.update_interval = gd_monitor_update_interval( - vc->window ? vc->window : vc->gfx.drawing_area); + gd_update_monitor_refresh_rate( + vc, vc->window ? vc->window : vc->gfx.drawing_area); if (!vc->gfx.esurface) { gd_egl_init(vc); @@ -195,6 +195,9 @@ void gd_egl_switch(DisplayChangeListener *dcl, if (resized) { gd_update_windowsize(vc); } + + eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); } QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc, @@ -338,7 +341,7 @@ void gd_egl_flush(DisplayChangeListener *dcl, VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); GtkWidget *area = vc->gfx.drawing_area; - if (vc->gfx.guest_fb.dmabuf) { + if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) { graphic_hw_gl_block(vc->gfx.dcl.con, true); vc->gfx.guest_fb.dmabuf->draw_submitted = true; gtk_widget_queue_draw_area(area, x, y, w, h); diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index fc5a082eb846..7696df1f6bc4 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -121,8 +121,7 @@ void gd_gl_area_refresh(DisplayChangeListener *dcl) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - vc->gfx.dcl.update_interval = gd_monitor_update_interval( - vc->window ? vc->window : vc->gfx.drawing_area); + gd_update_monitor_refresh_rate(vc, vc->window ? vc->window : vc->gfx.drawing_area); if (!vc->gfx.gls) { if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { @@ -170,6 +169,23 @@ void gd_gl_area_switch(DisplayChangeListener *dcl, } } +static int gd_cmp_gl_context_version(int major, int minor, QEMUGLParams *params) +{ + if (major > params->major_ver) { + return 1; + } + if (major < params->major_ver) { + return -1; + } + if (minor > params->minor_ver) { + return 1; + } + if (minor < params->minor_ver) { + return -1; + } + return 0; +} + QEMUGLContext gd_gl_area_create_context(DisplayGLCtx *dgc, QEMUGLParams *params) { @@ -177,8 +193,8 @@ QEMUGLContext gd_gl_area_create_context(DisplayGLCtx *dgc, GdkWindow *window; GdkGLContext *ctx; GError *err = NULL; + int major, minor; - gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); window = gtk_widget_get_window(vc->gfx.drawing_area); ctx = gdk_window_create_gl_context(window, &err); if (err) { @@ -196,12 +212,30 @@ QEMUGLContext gd_gl_area_create_context(DisplayGLCtx *dgc, g_clear_object(&ctx); return NULL; } + + gdk_gl_context_make_current(ctx); + gdk_gl_context_get_version(ctx, &major, &minor); + gdk_gl_context_clear_current(); + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + + if (gd_cmp_gl_context_version(major, minor, params) == -1) { + /* created ctx version < requested version */ + g_clear_object(&ctx); + } + + trace_gd_gl_area_create_context(ctx, params->major_ver, params->minor_ver); return ctx; } void gd_gl_area_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx) { - /* FIXME */ + GdkGLContext *current_ctx = gdk_gl_context_get_current(); + + trace_gd_gl_area_destroy_context(ctx, current_ctx); + if (ctx == current_ctx) { + gdk_gl_context_clear_current(); + } + g_clear_object(&ctx); } void gd_gl_area_scanout_texture(DisplayChangeListener *dcl, @@ -244,7 +278,7 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - if (vc->gfx.guest_fb.dmabuf) { + if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) { graphic_hw_gl_block(vc->gfx.dcl.con, true); vc->gfx.guest_fb.dmabuf->draw_submitted = true; } diff --git a/ui/gtk.c b/ui/gtk.c index c57c36749e0e..4817623c8f3f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -681,9 +681,13 @@ static void gd_mouse_mode_change(Notifier *notify, void *data) s = container_of(notify, GtkDisplayState, mouse_mode_notifier); /* release the grab at switching to absolute mode */ - if (qemu_input_is_absolute() && gd_is_grab_active(s)) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - FALSE); + if (qemu_input_is_absolute() && s->ptr_owner) { + if (!s->ptr_owner->window) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + FALSE); + } else { + gd_ungrab_pointer(s); + } } for (i = 0; i < s->nb_vcs; i++) { VirtualConsole *vc = &s->vc[i]; @@ -710,11 +714,20 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, return TRUE; } -static void gd_set_ui_info(VirtualConsole *vc, gint width, gint height) +static void gd_set_ui_refresh_rate(VirtualConsole *vc, int refresh_rate) +{ + QemuUIInfo info; + + info = *dpy_get_ui_info(vc->gfx.dcl.con); + info.refresh_rate = refresh_rate; + dpy_set_ui_info(vc->gfx.dcl.con, &info, true); +} + +static void gd_set_ui_size(VirtualConsole *vc, gint width, gint height) { QemuUIInfo info; - memset(&info, 0, sizeof(info)); + info = *dpy_get_ui_info(vc->gfx.dcl.con); info.width = width; info.height = height; dpy_set_ui_info(vc->gfx.dcl.con, &info, true); @@ -738,33 +751,32 @@ static void gd_resize_event(GtkGLArea *area, { VirtualConsole *vc = (void *)opaque; - gd_set_ui_info(vc, width, height); + gd_set_ui_size(vc, width, height); } #endif -/* - * If available, return the update interval of the monitor in ms, - * else return 0 (the default update interval). - */ -int gd_monitor_update_interval(GtkWidget *widget) +void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget) { #ifdef GDK_VERSION_3_22 GdkWindow *win = gtk_widget_get_window(widget); + int refresh_rate; if (win) { GdkDisplay *dpy = gtk_widget_get_display(widget); GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); - int refresh_rate = gdk_monitor_get_refresh_rate(monitor); /* [mHz] */ - - if (refresh_rate) { - /* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */ - return MIN(1000 * 1000 / refresh_rate, - GUI_REFRESH_INTERVAL_DEFAULT); - } + refresh_rate = gdk_monitor_get_refresh_rate(monitor); /* [mHz] */ + } else { + refresh_rate = 0; } + + gd_set_ui_refresh_rate(vc, refresh_rate); + + /* T = 1 / f = 1 [s*Hz] / f = 1000*1000 [ms*mHz] / f */ + vc->gfx.dcl.update_interval = refresh_rate ? + MIN(1000 * 1000 / refresh_rate, GUI_REFRESH_INTERVAL_DEFAULT) : + GUI_REFRESH_INTERVAL_DEFAULT; #endif - return 0; } static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) @@ -801,8 +813,7 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) return FALSE; } - vc->gfx.dcl.update_interval = - gd_monitor_update_interval(vc->window ? vc->window : s->window); + gd_update_monitor_refresh_rate(vc, vc->window ? vc->window : s->window); fbw = surface_width(vc->gfx.ds); fbh = surface_height(vc->gfx.ds); @@ -1691,7 +1702,7 @@ static gboolean gd_configure(GtkWidget *widget, { VirtualConsole *vc = opaque; - gd_set_ui_info(vc, cfg->width, cfg->height); + gd_set_ui_size(vc, cfg->width, cfg->height); return FALSE; } @@ -1752,7 +1763,7 @@ static void gd_vc_send_chars(VirtualConsole *vc) uint32_t size; buf = fifo8_pop_buf(&vc->vte.out_fifo, MIN(len, avail), &size); - qemu_chr_be_write(vc->vte.chr, (uint8_t *)buf, size); + qemu_chr_be_write(vc->vte.chr, buf, size); len = qemu_chr_be_can_write(vc->vte.chr); avail -= size; } @@ -2160,7 +2171,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, return group; } -static GtkWidget *gd_create_menu_view(GtkDisplayState *s) +static GtkWidget *gd_create_menu_view(GtkDisplayState *s, DisplayOptions *opts) { GSList *group = NULL; GtkWidget *view_menu; @@ -2258,7 +2269,8 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s) s->show_menubar_item = gtk_check_menu_item_new_with_mnemonic( _("Show Menubar")); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->show_menubar_item), - TRUE); + !opts->u.gtk.has_show_menubar || + opts->u.gtk.show_menubar); gtk_accel_group_connect(s->accel_group, GDK_KEY_m, HOTKEY_MODIFIERS, 0, g_cclosure_new_swap(G_CALLBACK(gd_accel_show_menubar), s, NULL)); gtk_accel_label_set_accel( @@ -2269,13 +2281,13 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s) return view_menu; } -static void gd_create_menus(GtkDisplayState *s) +static void gd_create_menus(GtkDisplayState *s, DisplayOptions *opts) { GtkSettings *settings; s->accel_group = gtk_accel_group_new(); s->machine_menu = gd_create_menu_machine(s); - s->view_menu = gd_create_menu_view(s); + s->view_menu = gd_create_menu_view(s, opts); s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine")); gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item), @@ -2352,7 +2364,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu"); - gd_create_menus(s); + gd_create_menus(s, opts); gd_connect_signals(s); @@ -2367,6 +2379,10 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) gtk_container_add(GTK_CONTAINER(s->window), s->vbox); gtk_widget_show_all(s->window); + if (opts->u.gtk.has_show_menubar && + !opts->u.gtk.show_menubar) { + gtk_widget_hide(s->menu_bar); + } vc = gd_vc_find_current(s); gtk_widget_set_sensitive(s->view_menu, vc != NULL); @@ -2383,7 +2399,13 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) opts->u.gtk.grab_on_hover) { gtk_menu_item_activate(GTK_MENU_ITEM(s->grab_on_hover_item)); } + if (opts->u.gtk.has_show_tabs && + opts->u.gtk.show_tabs) { + gtk_menu_item_activate(GTK_MENU_ITEM(s->show_tabs_item)); + } +#ifdef CONFIG_GTK_CLIPBOARD gd_clipboard_init(s); +#endif /* CONFIG_GTK_CLIPBOARD */ } static void early_gtk_display_init(DisplayOptions *opts) diff --git a/ui/input-linux.c b/ui/input-linux.c index 05c0c988199a..e572a2e905b9 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -316,7 +316,10 @@ static void input_linux_complete(UserCreatable *uc, Error **errp) error_setg_file_open(errp, errno, il->evdev); return; } - qemu_set_nonblock(il->fd); + if (!g_unix_set_fd_nonblocking(il->fd, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); + return; + } rc = ioctl(il->fd, EVIOCGVERSION, &ver); if (rc < 0) { diff --git a/ui/input.c b/ui/input.c index 8ac407dec485..8f4a87d1d718 100644 --- a/ui/input.c +++ b/ui/input.c @@ -124,7 +124,7 @@ qemu_input_find_handler(uint32_t mask, QemuConsole *con) return NULL; } -void qmp_input_send_event(bool has_device, const char *device, +void qmp_input_send_event(const char *device, bool has_head, int64_t head, InputEventList *events, Error **errp) { @@ -133,7 +133,7 @@ void qmp_input_send_event(bool has_device, const char *device, Error *err = NULL; con = NULL; - if (has_device) { + if (device) { if (!has_head) { head = 0; } @@ -364,7 +364,7 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt) * when 'alt+print' was pressed. This flaw is now fixed and the * 'sysrq' key serves no further purpose. We normalize it to * 'print', so that downstream receivers of the event don't - * neeed to deal with this mistake + * need to deal with this mistake */ if (evt->type == INPUT_EVENT_KIND_KEY && evt->u.key.data->key->u.qcode.data == Q_KEY_CODE_SYSRQ) { diff --git a/ui/keymaps.c b/ui/keymaps.c index d4a647464bbf..6ceaa97085ab 100644 --- a/ui/keymaps.c +++ b/ui/keymaps.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "keymaps.h" #include "trace.h" diff --git a/ui/meson.build b/ui/meson.build index 64286ba1503a..c1b137bf330c 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -1,6 +1,8 @@ softmmu_ss.add(pixman) specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: pixman) # for the include path +specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: opengl) # for the include path +softmmu_ss.add(png) softmmu_ss.add(files( 'clipboard.c', 'console.c', @@ -39,11 +41,10 @@ vnc_ss.add(files( 'vnc-jobs.c', 'vnc-clipboard.c', )) -vnc_ss.add(zlib, png, jpeg, gnutls) +vnc_ss.add(zlib, jpeg, gnutls) vnc_ss.add(when: sasl, if_true: files('vnc-auth-sasl.c')) softmmu_ss.add_all(when: vnc, if_true: vnc_ss) softmmu_ss.add(when: vnc, if_false: files('vnc-stubs.c')) -specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: opengl) ui_modules = {} @@ -53,17 +54,18 @@ if curses.found() ui_modules += {'curses' : curses_ss} endif -if config_host.has_key('CONFIG_OPENGL') +softmmu_ss.add(opengl) +if opengl.found() opengl_ss = ss.source_set() opengl_ss.add(gbm) - opengl_ss.add(when: [opengl, pixman, 'CONFIG_OPENGL'], + opengl_ss.add(when: [opengl, pixman], if_true: files('shader.c', 'console-gl.c', 'egl-helpers.c', 'egl-context.c')) ui_modules += {'opengl' : opengl_ss} endif -if config_host.has_key('CONFIG_OPENGL') and gbm.found() +if opengl.found() and gbm.found() egl_headless_ss = ss.source_set() - egl_headless_ss.add(when: [opengl, gbm, pixman, 'CONFIG_OPENGL'], + egl_headless_ss.add(when: [opengl, gbm, pixman], if_true: files('egl-headless.c')) ui_modules += {'egl-headless' : egl_headless_ss} endif @@ -73,14 +75,13 @@ if dbus_display dbus_display1 = custom_target('dbus-display gdbus-codegen', output: ['dbus-display1.h', 'dbus-display1.c'], input: files('dbus-display1.xml'), - command: [config_host['GDBUS_CODEGEN'], - '@INPUT@', + command: [gdbus_codegen, '@INPUT@', '--glib-min-required', '2.64', '--output-directory', meson.current_build_dir(), '--interface-prefix', 'org.qemu.', '--c-namespace', 'QemuDBus', '--generate-c-code', '@BASENAME@']) - dbus_ss.add(when: [gio, pixman, opengl, 'CONFIG_GIO'], + dbus_ss.add(when: [gio, pixman, opengl, gbm], if_true: [files( 'dbus-chardev.c', 'dbus-clipboard.c', @@ -96,10 +97,13 @@ if gtk.found() softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('win32-kbd-hook.c')) gtk_ss = ss.source_set() - gtk_ss.add(gtk, vte, pixman, files('gtk.c', 'gtk-clipboard.c')) + gtk_ss.add(gtk, vte, pixman, files('gtk.c')) + if have_gtk_clipboard + gtk_ss.add(files('gtk-clipboard.c')) + endif gtk_ss.add(when: x11, if_true: files('x_keymap.c')) - gtk_ss.add(when: [opengl, 'CONFIG_OPENGL'], if_true: files('gtk-gl-area.c')) - gtk_ss.add(when: [x11, opengl, 'CONFIG_OPENGL'], if_true: files('gtk-egl.c')) + gtk_ss.add(when: opengl, if_true: files('gtk-gl-area.c')) + gtk_ss.add(when: [x11, opengl], if_true: files('gtk-egl.c')) ui_modules += {'gtk' : gtk_ss} endif @@ -112,7 +116,7 @@ if sdl.found() 'sdl2-input.c', 'sdl2.c', )) - sdl_ss.add(when: [opengl, 'CONFIG_OPENGL'], if_true: files('sdl2-gl.c')) + sdl_ss.add(when: opengl, if_true: files('sdl2-gl.c')) sdl_ss.add(when: x11, if_true: files('x_keymap.c')) ui_modules += {'sdl' : sdl_ss} endif @@ -127,7 +131,7 @@ if spice.found() ui_modules += {'spice-core' : spice_core_ss} endif -if spice.found() and config_host.has_key('CONFIG_GIO') +if spice.found() and gio.found() spice_ss = ss.source_set() spice_ss.add(spice, gio, pixman, files('spice-app.c')) ui_modules += {'spice-app': spice_ss} diff --git a/ui/sdl2.c b/ui/sdl2.c index d3741f9b754d..8cb77416af2b 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -40,6 +40,8 @@ static struct sdl2_console *sdl2_console; static SDL_Surface *guest_sprite_surface; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ +static bool alt_grab; +static bool ctrl_grab; static int gui_saved_grab; static int gui_fullscreen; @@ -853,6 +855,14 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) gui_fullscreen = o->has_full_screen && o->full_screen; + if (o->u.sdl.has_grab_mod) { + if (o->u.sdl.grab_mod == HOT_KEY_MOD_LSHIFT_LCTRL_LALT) { + alt_grab = true; + } else if (o->u.sdl.grab_mod == HOT_KEY_MOD_RCTRL) { + ctrl_grab = true; + } + } + for (i = 0;; i++) { QemuConsole *con = qemu_console_lookup_by_index(i); if (!con) { diff --git a/ui/spice-core.c b/ui/spice-core.c index c3ac20ad4306..72f8f1681c6f 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -222,7 +222,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info) break; case SPICE_CHANNEL_EVENT_INITIALIZED: if (auth) { - server->has_auth = true; server->auth = g_strdup(auth); } add_channel_info(client, info); @@ -522,13 +521,9 @@ static SpiceInfo *qmp_query_spice_real(Error **errp) port = qemu_opt_get_number(opts, "port", 0); tls_port = qemu_opt_get_number(opts, "tls-port", 0); - info->has_auth = true; info->auth = g_strdup(auth); - - info->has_host = true; info->host = g_strdup(addr ? addr : "*"); - info->has_compiled_version = true; major = (SPICE_SERVER_VERSION & 0xff0000) >> 16; minor = (SPICE_SERVER_VERSION & 0xff00) >> 8; micro = SPICE_SERVER_VERSION & 0xff; diff --git a/ui/trace-events b/ui/trace-events index f78b5e66061f..977577fbba58 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -26,6 +26,8 @@ gd_key_event(const char *tab, int gdk_keycode, int qkeycode, const char *action) gd_grab(const char *tab, const char *device, const char *reason) "tab=%s, dev=%s, reason=%s" gd_ungrab(const char *tab, const char *device) "tab=%s, dev=%s" gd_keymap_windowing(const char *name) "backend=%s" +gd_gl_area_create_context(void *ctx, int major, int minor) "ctx=%p, major=%d, minor=%d" +gd_gl_area_destroy_context(void *ctx, void *current_ctx) "ctx=%p, current_ctx=%p" # vnc-auth-sasl.c # vnc-auth-vencrypt.c @@ -125,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/util.c b/ui/util.c index 7e8fc1ea537a..d54bbb74fb3d 100644 --- a/ui/util.c +++ b/ui/util.c @@ -17,7 +17,7 @@ #include "qemu/osdep.h" -#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pci_bus.h" #include "qapi/error.h" #include "ui/console.h" @@ -51,7 +51,6 @@ bool qemu_console_fill_device_address(QemuConsole *con, size_t size, Error **errp) { - ERRP_GUARD(); DeviceState *dev = DEVICE(object_property_get_link(OBJECT(con), "device", &error_abort)); diff --git a/ui/vdagent.c b/ui/vdagent.c index 7ea4bc5d9a26..4bf50f0c4d88 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -1,6 +1,5 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "include/qemu-common.h" #include "chardev/char.h" #include "qemu/buffer.h" #include "qemu/option.h" @@ -472,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) @@ -534,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; } @@ -545,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; } @@ -664,7 +665,7 @@ static void vdagent_chr_open(Chardev *chr, VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr); ChardevQemuVDAgent *cfg = backend->u.qemu_vdagent.data; -#if defined(HOST_WORDS_BIGENDIAN) +#if HOST_BIG_ENDIAN /* * TODO: vdagent protocol is defined to be LE, * so we have to byteswap everything on BE hosts. @@ -718,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; @@ -854,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; @@ -870,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/ui/vgafont.h b/ui/vgafont.h index 3606dd7338b4..7e1fc473f75e 100644 --- a/ui/vgafont.h +++ b/ui/vgafont.h @@ -1,4611 +1,4611 @@ static const uint8_t vgafont16[256 * 16] = { - /* 0 0x00 '^@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 1 0x01 '^A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x81, /* 10000001 */ - 0xa5, /* 10100101 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 2 0x02 '^B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xdb, /* 11011011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 3 0x03 '^C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 4 0x04 '^D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 5 0x05 '^E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 6 0x06 '^F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 7 0x07 '^G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 8 0x08 '^H' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xe7, /* 11100111 */ - 0xc3, /* 11000011 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 9 0x09 '^I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x42, /* 01000010 */ - 0x42, /* 01000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 10 0x0a '^J' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0x99, /* 10011001 */ - 0xbd, /* 10111101 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0xc3, /* 11000011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 11 0x0b '^K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x1a, /* 00011010 */ - 0x32, /* 00110010 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 12 0x0c '^L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 13 0x0d '^M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x33, /* 00110011 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x70, /* 01110000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 14 0x0e '^N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x67, /* 01100111 */ - 0xe7, /* 11100111 */ - 0xe6, /* 11100110 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 15 0x0f '^O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xdb, /* 11011011 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0x3c, /* 00111100 */ - 0xdb, /* 11011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 16 0x10 '^P' */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0xf0, /* 11110000 */ - 0xf8, /* 11111000 */ - 0xfe, /* 11111110 */ - 0xf8, /* 11111000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 17 0x11 '^Q' */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0e, /* 00001110 */ - 0x1e, /* 00011110 */ - 0x3e, /* 00111110 */ - 0xfe, /* 11111110 */ - 0x3e, /* 00111110 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 18 0x12 '^R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 19 0x13 '^S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 20 0x14 '^T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7b, /* 01111011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 21 0x15 '^U' */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 22 0x16 '^V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 23 0x17 '^W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 24 0x18 '^X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 25 0x19 '^Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 26 0x1a '^Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 27 0x1b '^[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xfe, /* 11111110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 28 0x1c '^\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 29 0x1d '^]' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x28, /* 00101000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x28, /* 00101000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 30 0x1e '^^' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 31 0x1f '^_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 32 0x20 ' ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 33 0x21 '!' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 34 0x22 '"' */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x24, /* 00100100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 35 0x23 '#' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 36 0x24 '$' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x86, /* 10000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 37 0x25 '%' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 38 0x26 '&' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 39 0x27 ''' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 40 0x28 '(' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 41 0x29 ')' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 42 0x2a '*' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0xff, /* 11111111 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 43 0x2b '+' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 44 0x2c ',' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 45 0x2d '-' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 46 0x2e '.' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 47 0x2f '/' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 48 0x30 '0' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 49 0x31 '1' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x38, /* 00111000 */ - 0x78, /* 01111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 50 0x32 '2' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 51 0x33 '3' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x3c, /* 00111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 52 0x34 '4' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x1c, /* 00011100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 53 0x35 '5' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 54 0x36 '6' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 55 0x37 '7' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 56 0x38 '8' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 57 0x39 '9' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 58 0x3a ':' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 59 0x3b ';' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 60 0x3c '<' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 61 0x3d '=' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 62 0x3e '>' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 63 0x3f '?' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 64 0x40 '@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xdc, /* 11011100 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 65 0x41 'A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 66 0x42 'B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 67 0x43 'C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 68 0x44 'D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 69 0x45 'E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 70 0x46 'F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 71 0x47 'G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xde, /* 11011110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x66, /* 01100110 */ - 0x3a, /* 00111010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 72 0x48 'H' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 73 0x49 'I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 74 0x4a 'J' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 75 0x4b 'K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe6, /* 11100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 76 0x4c 'L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 77 0x4d 'M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xee, /* 11101110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 78 0x4e 'N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 79 0x4f 'O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 80 0x50 'P' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 81 0x51 'Q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xde, /* 11011110 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 82 0x52 'R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 83 0x53 'S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 84 0x54 'T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x5a, /* 01011010 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 85 0x55 'U' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 86 0x56 'V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 87 0x57 'W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0xee, /* 11101110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 88 0x58 'X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 89 0x59 'Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 90 0x5a 'Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 91 0x5b '[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 92 0x5c '\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0x70, /* 01110000 */ - 0x38, /* 00111000 */ - 0x1c, /* 00011100 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 93 0x5d ']' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 94 0x5e '^' */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 95 0x5f '_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 96 0x60 '`' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 97 0x61 'a' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 98 0x62 'b' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 99 0x63 'c' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 100 0x64 'd' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 101 0x65 'e' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 102 0x66 'f' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x36, /* 00110110 */ - 0x32, /* 00110010 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 103 0x67 'g' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 104 0x68 'h' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x6c, /* 01101100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 105 0x69 'i' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 106 0x6a 'j' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - - /* 107 0x6b 'k' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 108 0x6c 'l' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 109 0x6d 'm' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 110 0x6e 'n' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 111 0x6f 'o' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 112 0x70 'p' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - - /* 113 0x71 'q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - - /* 114 0x72 'r' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 115 0x73 's' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 116 0x74 't' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0xfc, /* 11111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x36, /* 00110110 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 117 0x75 'u' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 118 0x76 'v' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 119 0x77 'w' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 120 0x78 'x' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 121 0x79 'y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - - /* 122 0x7a 'z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 123 0x7b '{' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 124 0x7c '|' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 125 0x7d '}' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 126 0x7e '~' */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 127 0x7f '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 128 0x80 '€' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 129 0x81 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 130 0x82 '‚' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 131 0x83 'ƒ' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 132 0x84 '„' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 133 0x85 '…' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 134 0x86 '†' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 135 0x87 '‡' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 136 0x88 'ˆ' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 137 0x89 '‰' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 138 0x8a 'Š' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 139 0x8b '‹' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 140 0x8c 'Œ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 141 0x8d '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 142 0x8e 'Ž' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 143 0x8f '' */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 144 0x90 '' */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 145 0x91 '‘' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x6e, /* 01101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 146 0x92 '’' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3e, /* 00111110 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xce, /* 11001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 147 0x93 '“' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 148 0x94 '”' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 149 0x95 '•' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 150 0x96 '–' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 151 0x97 '—' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 152 0x98 '˜' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 153 0x99 '™' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 154 0x9a 'š' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 155 0x9b '›' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 156 0x9c 'œ' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x64, /* 01100100 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xe6, /* 11100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 157 0x9d '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 158 0x9e 'ž' */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xf8, /* 11111000 */ - 0xc4, /* 11000100 */ - 0xcc, /* 11001100 */ - 0xde, /* 11011110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 159 0x9f 'Ÿ' */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 160 0xa0 ' ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 161 0xa1 '¡' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 162 0xa2 '¢' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 163 0xa3 '£' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 164 0xa4 '¤' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 165 0xa5 '¥' */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 166 0xa6 '¦' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 167 0xa7 '§' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 168 0xa8 '¨' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 169 0xa9 '©' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 170 0xaa 'ª' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 171 0xab '«' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xdc, /* 11011100 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 172 0xac '¬' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x66, /* 01100110 */ - 0xce, /* 11001110 */ - 0x9a, /* 10011010 */ - 0x3f, /* 00111111 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 173 0xad '­' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 174 0xae '®' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 175 0xaf '¯' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 176 0xb0 '°' */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - - /* 177 0xb1 '±' */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - - /* 178 0xb2 '²' */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - - /* 179 0xb3 '³' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 180 0xb4 '´' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 181 0xb5 'µ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 182 0xb6 '¶' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 183 0xb7 '·' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 184 0xb8 '¸' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 185 0xb9 '¹' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 186 0xba 'º' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 187 0xbb '»' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 188 0xbc '¼' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 189 0xbd '½' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 190 0xbe '¾' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 191 0xbf '¿' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 192 0xc0 'À' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 193 0xc1 'Á' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 194 0xc2 'Â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 195 0xc3 'Ã' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 196 0xc4 'Ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 197 0xc5 'Å' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 198 0xc6 'Æ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 199 0xc7 'Ç' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 200 0xc8 'È' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 201 0xc9 'É' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 202 0xca 'Ê' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 203 0xcb 'Ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 204 0xcc 'Ì' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 205 0xcd 'Í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 206 0xce 'Î' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 207 0xcf 'Ï' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 208 0xd0 'Ð' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 209 0xd1 'Ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 210 0xd2 'Ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 211 0xd3 'Ó' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 212 0xd4 'Ô' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 213 0xd5 'Õ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 214 0xd6 'Ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 215 0xd7 '×' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 216 0xd8 'Ø' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 217 0xd9 'Ù' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 218 0xda 'Ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 219 0xdb 'Û' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 220 0xdc 'Ü' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 221 0xdd 'Ý' */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - - /* 222 0xde 'Þ' */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - - /* 223 0xdf 'ß' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 224 0xe0 'à' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 225 0xe1 'á' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xd8, /* 11011000 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 226 0xe2 'â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 227 0xe3 'ã' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 228 0xe4 'ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 229 0xe5 'å' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 230 0xe6 'æ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - - /* 231 0xe7 'ç' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 232 0xe8 'è' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 233 0xe9 'é' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 234 0xea 'ê' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xee, /* 11101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 235 0xeb 'ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x3e, /* 00111110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 236 0xec 'ì' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 237 0xed 'í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x03, /* 00000011 */ - 0x06, /* 00000110 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xf3, /* 11110011 */ - 0x7e, /* 01111110 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 238 0xee 'î' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 239 0xef 'ï' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 240 0xf0 'ð' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 241 0xf1 'ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 242 0xf2 'ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 243 0xf3 'ó' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 244 0xf4 'ô' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 245 0xf5 'õ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 246 0xf6 'ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 247 0xf7 '÷' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 248 0xf8 'ø' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 249 0xf9 'ù' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 250 0xfa 'ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 251 0xfb 'û' */ - 0x00, /* 00000000 */ - 0x0f, /* 00001111 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xec, /* 11101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3c, /* 00111100 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 252 0xfc 'ü' */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 253 0xfd 'ý' */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x32, /* 00110010 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 254 0xfe 'þ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 255 0xff 'ÿ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 'ˆ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '™' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c 'œ' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e 'ž' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f 'Ÿ' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '¬' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '­' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 'é' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee 'î' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc 'ü' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ }; diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c index d48f75eb1ab4..8aeadfaa218a 100644 --- a/ui/vnc-clipboard.c +++ b/ui/vnc-clipboard.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "vnc.h" #include "vnc-jobs.h" diff --git a/ui/vnc-enc-hextile.c b/ui/vnc-enc-hextile.c index 4215bd7daf51..c763256f29c8 100644 --- a/ui/vnc-enc-hextile.c +++ b/ui/vnc-enc-hextile.c @@ -50,8 +50,8 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x, int has_fg, has_bg; uint8_t *last_fg, *last_bg; - last_fg = (uint8_t *) g_malloc(VNC_SERVER_FB_BYTES); - last_bg = (uint8_t *) g_malloc(VNC_SERVER_FB_BYTES); + last_fg = g_malloc(VNC_SERVER_FB_BYTES); + last_bg = g_malloc(VNC_SERVER_FB_BYTES); has_fg = has_bg = 0; for (j = y; j < (y + h); j += 16) { for (i = x; i < (x + w); i += 16) { diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 7b86a4713dfd..09200d71b8cf 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -32,9 +32,9 @@ INT32 definitions between jmorecfg.h (included by jpeglib.h) and Win32 basetsd.h (included by windows.h). */ -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG /* The following define is needed by pngconf.h. Otherwise it won't compile, - because setjmp.h was already included by qemu-common.h. */ + because setjmp.h was already included by osdep.h. */ #define PNG_SKIP_SETJMP_CHECK #include #endif @@ -95,7 +95,7 @@ static const struct { }; #endif -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG static const struct { int png_zlib_level, png_filters; } tight_png_conf[] = { @@ -919,7 +919,7 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h) int stream = 0; ssize_t bytes; -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG if (tight_can_send_png_rect(vs, w, h)) { return send_png_rect(vs, x, y, w, h, NULL); } @@ -966,7 +966,7 @@ static int send_mono_rect(VncState *vs, int x, int y, int stream = 1; int level = tight_conf[vs->tight->compression].mono_zlib_level; -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG if (tight_can_send_png_rect(vs, w, h)) { int ret; int bpp = vs->client_pf.bytes_per_pixel * 8; @@ -1020,7 +1020,7 @@ static int send_mono_rect(VncState *vs, int x, int y, struct palette_cb_priv { VncState *vs; uint8_t *header; -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG png_colorp png_palette; #endif }; @@ -1082,7 +1082,7 @@ static int send_palette_rect(VncState *vs, int x, int y, int colors; ssize_t bytes; -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG if (tight_can_send_png_rect(vs, w, h)) { return send_png_rect(vs, x, y, w, h, palette); } @@ -1233,7 +1233,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) /* * PNG compression stuff. */ -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG static void write_png_palette(int idx, uint32_t pix, void *opaque) { struct palette_cb_priv *priv = opaque; @@ -1379,7 +1379,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h, buffer_reset(&vs->tight->png); return 1; } -#endif /* CONFIG_VNC_PNG */ +#endif /* CONFIG_PNG */ static void vnc_tight_start(VncState *vs) { @@ -1706,7 +1706,7 @@ void vnc_tight_clear(VncState *vs) #ifdef CONFIG_VNC_JPEG buffer_free(&vs->tight->jpeg); #endif -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG buffer_free(&vs->tight->png); #endif } diff --git a/ui/vnc-enc-zywrle-template.c b/ui/vnc-enc-zywrle-template.c index e9be55966ea6..4afa583e7655 100644 --- a/ui/vnc-enc-zywrle-template.c +++ b/ui/vnc-enc-zywrle-template.c @@ -86,17 +86,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #undef L_2 #if ZYWRLE_ENDIAN == ENDIAN_BIG -# define S_0 1 -# define S_1 0 -# define L_0 3 -# define L_1 2 -# define L_2 1 +# define S_0 1 +# define S_1 0 +# define L_0 3 +# define L_1 2 +# define L_2 1 #else -# define S_0 0 -# define S_1 1 -# define L_0 0 -# define L_1 1 -# define L_2 2 +# define S_0 0 +# define S_1 1 +# define L_0 0 +# define L_1 1 +# define L_2 2 #endif #define ZYWRLE_QUANTIZE diff --git a/ui/vnc-enc-zywrle.h b/ui/vnc-enc-zywrle.h index 9b7f6989750f..e661ec117dbe 100644 --- a/ui/vnc-enc-zywrle.h +++ b/ui/vnc-enc-zywrle.h @@ -51,14 +51,14 @@ static const unsigned int zywrle_param[3][3]={ {0x0000F000, 0x00000000, 0x00000000}, {0x0000C000, 0x00F0F0F0, 0x00000000}, {0x0000C000, 0x00C0C0C0, 0x00F0F0F0}, -/* {0x0000FF00, 0x00000000, 0x00000000}, +/* {0x0000FF00, 0x00000000, 0x00000000}, {0x0000FF00, 0x00FFFFFF, 0x00000000}, {0x0000FF00, 0x00FFFFFF, 0x00FFFFFF}, */ }; #else /* Type B:Non liner quantization filter. */ static const int8_t zywrle_conv[4][256]={ -{ /* bi=5, bo=5 r=0.0:PSNR=24.849 */ +{ /* bi=5, bo=5 r=0.0:PSNR=24.849 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -92,7 +92,7 @@ static const int8_t zywrle_conv[4][256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, -{ /* bi=5, bo=5 r=2.0:PSNR=74.031 */ +{ /* bi=5, bo=5 r=2.0:PSNR=74.031 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, @@ -126,7 +126,7 @@ static const int8_t zywrle_conv[4][256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, -{ /* bi=5, bo=4 r=2.0:PSNR=64.441 */ +{ /* bi=5, bo=4 r=2.0:PSNR=64.441 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -160,7 +160,7 @@ static const int8_t zywrle_conv[4][256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, -{ /* bi=5, bo=2 r=2.0:PSNR=43.175 */ +{ /* bi=5, bo=2 r=2.0:PSNR=43.175 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -274,14 +274,14 @@ static inline void harr(int8_t *px0, int8_t *px1) x1 += x0; if (((x1 ^ orgx1) & 0x80) == 0) { /* |x1| > |x0| */ - x0 -= x1; /* H = -B */ + x0 -= x1; /* H = -B */ } } else { /* same sign */ x0 -= x1; if (((x0 ^ orgx0) & 0x80) == 0) { /* |x0| > |x1| */ - x1 += x0; /* L = A */ + x1 += x0; /* L = A */ } } *px0 = (int8_t)x1; @@ -585,7 +585,7 @@ static inline void wavelet(int *buf, int width, int height, int level) } \ } while (0) -#define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level) \ +#define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level) \ ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \ ZYWRLE_LOAD_COEFF(ph, r, g, b); \ ZYWRLE_SAVE_PIXEL(data, r, g, b);) diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index 4562bf89288e..886f9bf6113f 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -373,7 +373,7 @@ void vnc_start_worker_thread(void) VncJobQueue *q; if (vnc_worker_thread_running()) - return ; + return; q = vnc_queue_init(); qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q, diff --git a/ui/vnc.c b/ui/vnc.c index 310a873c2184..d9eacad75938 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -25,7 +25,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "vnc.h" #include "vnc-jobs.h" #include "trace.h" @@ -55,6 +54,7 @@ #include "qemu/cutils.h" #include "qemu/help_option.h" #include "io/dns-resolver.h" +#include "monitor/monitor.h" #define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT #define VNC_REFRESH_INTERVAL_INC 50 @@ -244,7 +244,6 @@ static VncServerInfo *vnc_server_info_get(VncDisplay *vd) info = g_malloc0(sizeof(*info)); vnc_init_basic_info_from_server_addr(vd->listener->sioc[0], qapi_VncServerInfo_base(info), &err); - info->has_auth = true; info->auth = g_strdup(vnc_auth_name(vd)); if (err) { qapi_free_VncServerInfo(info); @@ -263,13 +262,10 @@ static void vnc_client_cache_auth(VncState *client) if (client->tls) { client->info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls); - client->info->has_x509_dname = - client->info->x509_dname != NULL; } #ifdef CONFIG_VNC_SASL if (client->sasl.conn && client->sasl.username) { - client->info->has_sasl_username = true; client->info->sasl_username = g_strdup(client->sasl.username); } #endif @@ -341,11 +337,9 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client) if (client->tls) { info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls); - info->has_x509_dname = info->x509_dname != NULL; } #ifdef CONFIG_VNC_SASL if (client->sasl.conn && client->sasl.username) { - info->has_sasl_username = true; info->sasl_username = g_strdup(client->sasl.username); } #endif @@ -426,11 +420,8 @@ VncInfo *qmp_query_vnc(Error **errp) abort(); } - info->has_host = true; - info->has_service = true; info->has_family = true; - info->has_auth = true; info->auth = g_strdup(vnc_auth_name(vd)); } @@ -568,7 +559,6 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp) if (vd->dcl.con) { dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con), "device", &error_abort)); - info->has_display = true; info->display = g_strdup(dev->id); } for (i = 0; vd->listener != NULL && i < vd->listener->nsioc; i++) { @@ -2165,7 +2155,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) vs->features |= VNC_FEATURE_TIGHT_MASK; vs->vnc_encoding = enc; break; -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG case VNC_ENCODING_TIGHT_PNG: vs->features |= VNC_FEATURE_TIGHT_PNG_MASK; vs->vnc_encoding = enc; @@ -2340,7 +2330,7 @@ static void pixel_format_message (VncState *vs) { vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */ vnc_write_u8(vs, vs->client_pf.depth); /* depth */ -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN vnc_write_u8(vs, 1); /* big-endian-flag */ #else vnc_write_u8(vs, 0); /* big-endian-flag */ @@ -2442,8 +2432,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) if (len == 1) { return 8; } + uint32_t dlen = abs(read_s32(data, 4)); if (len == 8) { - uint32_t dlen = abs(read_s32(data, 4)); if (dlen > (1 << 20)) { error_report("vnc: client_cut_text msg payload has %u bytes" " which exceeds our limit of 1MB.", dlen); @@ -2456,8 +2446,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) } if (read_s32(data, 4) < 0) { - vnc_client_cut_text_ext(vs, abs(read_s32(data, 4)), - read_u32(data, 8), data + 12); + if (dlen < 4) { + error_report("vnc: malformed payload (header less than 4 bytes)" + " in extended clipboard pseudo-encoding."); + vnc_client_error(vs); + break; + } + vnc_client_cut_text_ext(vs, dlen, read_u32(data, 8), data + 12); break; } vnc_client_cut_text(vs, read_u32(data, 4), data + 8); @@ -3080,7 +3075,7 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv) rect = vnc_stat_rect(vd, x, y); if (rect->updated) { - return ; + return; } rect->times[rect->idx] = *tv; rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times); @@ -3256,7 +3251,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, #ifdef CONFIG_VNC_JPEG buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc); #endif -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc); #endif buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc); @@ -3820,30 +3815,19 @@ static int vnc_display_get_address(const char *addrstr, return ret; } -static void vnc_free_addresses(SocketAddress ***retsaddr, - size_t *retnsaddr) -{ - size_t i; - - for (i = 0; i < *retnsaddr; i++) { - qapi_free_SocketAddress((*retsaddr)[i]); - } - g_free(*retsaddr); - - *retsaddr = NULL; - *retnsaddr = 0; -} - static int vnc_display_get_addresses(QemuOpts *opts, bool reverse, - SocketAddress ***retsaddr, - size_t *retnsaddr, - SocketAddress ***retwsaddr, - size_t *retnwsaddr, + SocketAddressList **saddr_list_ret, + SocketAddressList **wsaddr_list_ret, Error **errp) { SocketAddress *saddr = NULL; SocketAddress *wsaddr = NULL; + g_autoptr(SocketAddressList) saddr_list = NULL; + SocketAddressList **saddr_tail = &saddr_list; + SocketAddress *single_saddr = NULL; + g_autoptr(SocketAddressList) wsaddr_list = NULL; + SocketAddressList **wsaddr_tail = &wsaddr_list; QemuOptsIter addriter; const char *addr; int to = qemu_opt_get_number(opts, "to", 0); @@ -3852,23 +3836,16 @@ static int vnc_display_get_addresses(QemuOpts *opts, bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false); bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false); int displaynum = -1; - int ret = -1; - - *retsaddr = NULL; - *retnsaddr = 0; - *retwsaddr = NULL; - *retnwsaddr = 0; addr = qemu_opt_get(opts, "vnc"); if (addr == NULL || g_str_equal(addr, "none")) { - ret = 0; - goto cleanup; + return 0; } if (qemu_opt_get(opts, "websocket") && !qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) { error_setg(errp, "SHA1 hash support is required for websockets"); - goto cleanup; + return -1; } qemu_opt_iter_init(&addriter, opts, "vnc"); @@ -3879,7 +3856,7 @@ static int vnc_display_get_addresses(QemuOpts *opts, ipv4, ipv6, &saddr, errp); if (rv < 0) { - goto cleanup; + return -1; } /* Historical compat - first listen address can be used * to set the default websocket port @@ -3887,13 +3864,16 @@ static int vnc_display_get_addresses(QemuOpts *opts, if (displaynum == -1) { displaynum = rv; } - *retsaddr = g_renew(SocketAddress *, *retsaddr, *retnsaddr + 1); - (*retsaddr)[(*retnsaddr)++] = saddr; + QAPI_LIST_APPEND(saddr_tail, saddr); } - /* If we had multiple primary displays, we don't do defaults - * for websocket, and require explicit config instead. */ - if (*retnsaddr > 1) { + if (saddr_list && !saddr_list->next) { + single_saddr = saddr_list->value; + } else { + /* + * If we had multiple primary displays, we don't do defaults + * for websocket, and require explicit config instead. + */ displaynum = -1; } @@ -3903,57 +3883,50 @@ static int vnc_display_get_addresses(QemuOpts *opts, has_ipv4, has_ipv6, ipv4, ipv6, &wsaddr, errp) < 0) { - goto cleanup; + return -1; } /* Historical compat - if only a single listen address was * provided, then this is used to set the default listen * address for websocket too */ - if (*retnsaddr == 1 && - (*retsaddr)[0]->type == SOCKET_ADDRESS_TYPE_INET && + if (single_saddr && + single_saddr->type == SOCKET_ADDRESS_TYPE_INET && wsaddr->type == SOCKET_ADDRESS_TYPE_INET && g_str_equal(wsaddr->u.inet.host, "") && - !g_str_equal((*retsaddr)[0]->u.inet.host, "")) { + !g_str_equal(single_saddr->u.inet.host, "")) { g_free(wsaddr->u.inet.host); - wsaddr->u.inet.host = g_strdup((*retsaddr)[0]->u.inet.host); + wsaddr->u.inet.host = g_strdup(single_saddr->u.inet.host); } - *retwsaddr = g_renew(SocketAddress *, *retwsaddr, *retnwsaddr + 1); - (*retwsaddr)[(*retnwsaddr)++] = wsaddr; + QAPI_LIST_APPEND(wsaddr_tail, wsaddr); } - ret = 0; - cleanup: - if (ret < 0) { - vnc_free_addresses(retsaddr, retnsaddr); - vnc_free_addresses(retwsaddr, retnwsaddr); - } - return ret; + *saddr_list_ret = g_steal_pointer(&saddr_list); + *wsaddr_list_ret = g_steal_pointer(&wsaddr_list); + return 0; } static int vnc_display_connect(VncDisplay *vd, - SocketAddress **saddr, - size_t nsaddr, - SocketAddress **wsaddr, - size_t nwsaddr, + SocketAddressList *saddr_list, + SocketAddressList *wsaddr_list, Error **errp) { /* connect to viewer */ QIOChannelSocket *sioc = NULL; - if (nwsaddr != 0) { + if (wsaddr_list) { error_setg(errp, "Cannot use websockets in reverse mode"); return -1; } - if (nsaddr != 1) { + if (!saddr_list || saddr_list->next) { error_setg(errp, "Expected a single address in reverse mode"); return -1; } /* TODO SOCKET_ADDRESS_TYPE_FD when fd has AF_UNIX */ - vd->is_unix = saddr[0]->type == SOCKET_ADDRESS_TYPE_UNIX; + vd->is_unix = saddr_list->value->type == SOCKET_ADDRESS_TYPE_UNIX; sioc = qio_channel_socket_new(); qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse"); - if (qio_channel_socket_connect_sync(sioc, saddr[0], errp) < 0) { + if (qio_channel_socket_connect_sync(sioc, saddr_list->value, errp) < 0) { object_unref(OBJECT(sioc)); return -1; } @@ -3964,20 +3937,18 @@ static int vnc_display_connect(VncDisplay *vd, static int vnc_display_listen(VncDisplay *vd, - SocketAddress **saddr, - size_t nsaddr, - SocketAddress **wsaddr, - size_t nwsaddr, + SocketAddressList *saddr_list, + SocketAddressList *wsaddr_list, Error **errp) { - size_t i; + SocketAddressList *el; - if (nsaddr) { + if (saddr_list) { vd->listener = qio_net_listener_new(); qio_net_listener_set_name(vd->listener, "vnc-listen"); - for (i = 0; i < nsaddr; i++) { + for (el = saddr_list; el; el = el->next) { if (qio_net_listener_open_sync(vd->listener, - saddr[i], 1, + el->value, 1, errp) < 0) { return -1; } @@ -3987,12 +3958,12 @@ static int vnc_display_listen(VncDisplay *vd, vnc_listen_io, vd, NULL); } - if (nwsaddr) { + if (wsaddr_list) { vd->wslistener = qio_net_listener_new(); qio_net_listener_set_name(vd->wslistener, "vnc-ws-listen"); - for (i = 0; i < nwsaddr; i++) { + for (el = wsaddr_list; el; el = el->next) { if (qio_net_listener_open_sync(vd->wslistener, - wsaddr[i], 1, + el->value, 1, errp) < 0) { return -1; } @@ -4005,13 +3976,36 @@ static int vnc_display_listen(VncDisplay *vd, return 0; } +bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp) +{ + VncDisplay *vd = vnc_display_find(NULL); + + if (!vd) { + error_setg(errp, "Can not find vnc display"); + return false; + } + + if (arg->has_addresses) { + if (vd->listener) { + qio_net_listener_disconnect(vd->listener); + object_unref(OBJECT(vd->listener)); + vd->listener = NULL; + } + + if (vnc_display_listen(vd, arg->addresses, NULL, errp) < 0) { + return false; + } + } + + return true; +} void vnc_display_open(const char *id, Error **errp) { VncDisplay *vd = vnc_display_find(id); QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); - SocketAddress **saddr = NULL, **wsaddr = NULL; - size_t nsaddr, nwsaddr; + g_autoptr(SocketAddressList) saddr_list = NULL; + g_autoptr(SocketAddressList) wsaddr_list = NULL; const char *share, *device_id; QemuConsole *con; bool password = false; @@ -4036,8 +4030,8 @@ void vnc_display_open(const char *id, Error **errp) } reverse = qemu_opt_get_bool(opts, "reverse", false); - if (vnc_display_get_addresses(opts, reverse, &saddr, &nsaddr, - &wsaddr, &nwsaddr, errp) < 0) { + if (vnc_display_get_addresses(opts, reverse, &saddr_list, &wsaddr_list, + errp) < 0) { goto fail; } @@ -4059,13 +4053,6 @@ void vnc_display_open(const char *id, Error **errp) password = qemu_opt_get_bool(opts, "password", false); } if (password) { - if (fips_get_state()) { - error_setg(errp, - "VNC password auth disabled due to FIPS mode, " - "consider using the VeNCrypt or SASL authentication " - "methods as an alternative"); - goto fail; - } if (!qcrypto_cipher_supports( QCRYPTO_CIPHER_ALG_DES, QCRYPTO_CIPHER_MODE_ECB)) { error_setg(errp, @@ -4219,16 +4206,16 @@ void vnc_display_open(const char *id, Error **errp) } qkbd_state_set_delay(vd->kbd, key_delay_ms); - if (saddr == NULL) { - goto cleanup; + if (saddr_list == NULL) { + return; } if (reverse) { - if (vnc_display_connect(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) { + if (vnc_display_connect(vd, saddr_list, wsaddr_list, errp) < 0) { goto fail; } } else { - if (vnc_display_listen(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) { + if (vnc_display_listen(vd, saddr_list, wsaddr_list, errp) < 0) { goto fail; } } @@ -4237,14 +4224,11 @@ void vnc_display_open(const char *id, Error **errp) vnc_display_print_local_addr(vd); } - cleanup: - vnc_free_addresses(&saddr, &nsaddr); - vnc_free_addresses(&wsaddr, &nwsaddr); + /* Success */ return; fail: vnc_display_close(vd); - goto cleanup; } void vnc_display_add_client(const char *id, int csock, bool skipauth) diff --git a/ui/vnc.h b/ui/vnc.h index a7149831f906..a60fb13115c9 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -201,7 +201,7 @@ typedef struct VncTight { #ifdef CONFIG_VNC_JPEG Buffer jpeg; #endif -#ifdef CONFIG_VNC_PNG +#ifdef CONFIG_PNG Buffer png; #endif int levels[4]; diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h index e8a2ec73c52f..016405e74b6e 100644 --- a/ui/vnc_keysym.h +++ b/ui/vnc_keysym.h @@ -102,7 +102,7 @@ static const name2keysym_t name2keysym[]={ /* latin 1 extensions */ { "nobreakspace", 0x0a0}, { "exclamdown", 0x0a1}, -{ "cent", 0x0a2}, +{ "cent", 0x0a2}, { "sterling", 0x0a3}, { "currency", 0x0a4}, { "yen", 0x0a5}, diff --git a/util/aio-posix.c b/util/aio-posix.c index be0182a3c64f..731f3826c062 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -15,6 +15,7 @@ #include "qemu/osdep.h" #include "block/block.h" +#include "block/thread-pool.h" #include "qemu/main-loop.h" #include "qemu/rcu.h" #include "qemu/rcu_queue.h" diff --git a/util/aio-wait.c b/util/aio-wait.c index bdb3d3af22dd..98c5accd29d0 100644 --- a/util/aio-wait.c +++ b/util/aio-wait.c @@ -35,7 +35,21 @@ static void dummy_bh_cb(void *opaque) void aio_wait_kick(void) { - /* The barrier (or an atomic op) is in the caller. */ + /* + * Paired with smp_mb in AIO_WAIT_WHILE. Here we have: + * write(condition); + * aio_wait_kick() { + * smp_mb(); + * read(num_waiters); + * } + * + * And in AIO_WAIT_WHILE: + * write(num_waiters); + * smp_mb(); + * read(condition); + */ + smp_mb(); + if (qatomic_read(&global_aio_wait.num_waiters)) { aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL); } diff --git a/util/aio-win32.c b/util/aio-win32.c index 7aac89df3a30..80cfe012ad8f 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "block/block.h" #include "qemu/main-loop.h" #include "qemu/queue.h" @@ -327,9 +326,9 @@ void aio_dispatch(AioContext *ctx) bool aio_poll(AioContext *ctx, bool blocking) { AioHandler *node; - HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; + HANDLE events[MAXIMUM_WAIT_OBJECTS]; bool progress, have_select_revents, first; - int count; + unsigned count; int timeout; /* @@ -370,6 +369,7 @@ bool aio_poll(AioContext *ctx, bool blocking) QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { if (!node->deleted && node->io_notify && aio_node_check(ctx, node->is_external)) { + assert(count < MAXIMUM_WAIT_OBJECTS); events[count++] = event_notifier_get_handle(node->e); } } diff --git a/util/async-teardown.c b/util/async-teardown.c new file mode 100644 index 000000000000..62bfce1b3ca8 --- /dev/null +++ b/util/async-teardown.c @@ -0,0 +1,150 @@ +/* + * Asynchronous teardown + * + * Copyright IBM, Corp. 2022 + * + * Authors: + * Claudio Imbrenda + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "qemu/osdep.h" +#include "qemu/async-teardown.h" + +#ifdef _SC_THREAD_STACK_MIN +#define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN) +#else +#define CLONE_STACK_SIZE 16384 +#endif + +static pid_t the_ppid; + +/* + * Close all open file descriptors. + */ +static void close_all_open_fd(void) +{ + struct dirent *de; + int fd, dfd; + DIR *dir; + +#ifdef CONFIG_CLOSE_RANGE + int r = close_range(0, ~0U, 0); + if (!r) { + /* Success, no need to try other ways. */ + return; + } +#endif + + dir = opendir("/proc/self/fd"); + if (!dir) { + /* If /proc is not mounted, there is nothing that can be done. */ + return; + } + /* Avoid closing the directory. */ + dfd = dirfd(dir); + + for (de = readdir(dir); de; de = readdir(dir)) { + fd = atoi(de->d_name); + if (fd != dfd) { + close(fd); + } + } + closedir(dir); +} + +static void hup_handler(int signal) +{ + /* Check every second if this process has been reparented. */ + while (the_ppid == getppid()) { + /* sleep() is safe to use in a signal handler. */ + sleep(1); + } + + /* At this point the parent process has terminated completely. */ + _exit(0); +} + +static int async_teardown_fn(void *arg) +{ + struct sigaction sa = { .sa_handler = hup_handler }; + sigset_t hup_signal; + char name[16]; + + /* Set a meaningful name for this process. */ + snprintf(name, 16, "cleanup/%d", the_ppid); + prctl(PR_SET_NAME, (unsigned long)name); + + /* + * Close all file descriptors that might have been inherited from the + * main qemu process when doing clone, needed to make libvirt happy. + * Not using close_range for increased compatibility with older kernels. + */ + close_all_open_fd(); + + /* Set up a handler for SIGHUP and unblock SIGHUP. */ + sigaction(SIGHUP, &sa, NULL); + sigemptyset(&hup_signal); + sigaddset(&hup_signal, SIGHUP); + sigprocmask(SIG_UNBLOCK, &hup_signal, NULL); + + /* Ask to receive SIGHUP when the parent dies. */ + prctl(PR_SET_PDEATHSIG, SIGHUP); + + /* + * Sleep forever, unless the parent process has already terminated. The + * only interruption can come from the SIGHUP signal, which in normal + * operation is received when the parent process dies. + */ + if (the_ppid == getppid()) { + pause(); + } + + /* At this point the parent process has terminated completely. */ + _exit(0); +} + +/* + * Allocate a new stack of a reasonable size, and return a pointer to its top. + */ +static void *new_stack_for_clone(void) +{ + size_t stack_size = CLONE_STACK_SIZE; + char *stack_ptr; + + /* Allocate a new stack and get a pointer to its top. */ + stack_ptr = qemu_alloc_stack(&stack_size); +#if !defined(HOST_HPPA) + /* The top is at the end of the area, except on HPPA. */ + stack_ptr += stack_size; +#endif + + return stack_ptr; +} + +/* + * Block all signals, start (clone) a new process sharing the address space + * with qemu (CLONE_VM), then restore signals. + */ +void init_async_teardown(void) +{ + sigset_t all_signals, old_signals; + + the_ppid = getpid(); + + sigfillset(&all_signals); + sigprocmask(SIG_BLOCK, &all_signals, &old_signals); + clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL); + sigprocmask(SIG_SETMASK, &old_signals, NULL); +} diff --git a/util/async.c b/util/async.c index 2ea1172f3ee7..14d63b309116 100644 --- a/util/async.c +++ b/util/async.c @@ -27,12 +27,14 @@ #include "qapi/error.h" #include "block/aio.h" #include "block/thread-pool.h" +#include "block/graph-lock.h" #include "qemu/main-loop.h" #include "qemu/atomic.h" #include "qemu/rcu_queue.h" #include "block/raw-aio.h" #include "qemu/coroutine_int.h" #include "qemu/coroutine-tls.h" +#include "sysemu/cpu-timers.h" #include "trace.h" /***********************************************************/ @@ -84,6 +86,13 @@ static void aio_bh_enqueue(QEMUBH *bh, unsigned new_flags) } aio_notify(ctx); + /* + * Workaround for record/replay. + * vCPU execution should be suspended when new BH is set. + * This is needed to avoid guest timeouts caused + * by the long cycles of the execution. + */ + icount_notify_exit(); } /* Only called from aio_bh_poll() and aio_ctx_finalize() */ @@ -368,6 +377,7 @@ aio_ctx_finalize(GSource *source) qemu_rec_mutex_destroy(&ctx->lock); qemu_lockcnt_destroy(&ctx->list_lock); timerlistgroup_deinit(&ctx->tlg); + unregister_aiocontext(ctx); aio_context_destroy(ctx); } @@ -563,6 +573,11 @@ AioContext *aio_context_new(Error **errp) ctx->aio_max_batch = 0; + ctx->thread_pool_min = 0; + ctx->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT; + + register_aiocontext(ctx); + return ctx; fail: g_source_destroy(&ctx->source); @@ -696,3 +711,20 @@ void qemu_set_current_aio_context(AioContext *ctx) assert(!get_my_aiocontext()); set_my_aiocontext(ctx); } + +void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min, + int64_t max, Error **errp) +{ + + if (min > max || !max || min > INT_MAX || max > INT_MAX) { + error_setg(errp, "bad thread-pool-min/thread-pool-max values"); + return; + } + + ctx->thread_pool_min = min; + ctx->thread_pool_max = max; + + if (ctx->thread_pool) { + thread_pool_update_params(ctx->thread_pool, ctx); + } +} diff --git a/util/bitmap.c b/util/bitmap.c index 1f201393aef1..8d12e90a5a42 100644 --- a/util/bitmap.c +++ b/util/bitmap.c @@ -240,6 +240,51 @@ void bitmap_clear(unsigned long *map, long start, long nr) } } +bool bitmap_test_and_clear(unsigned long *map, long start, long nr) +{ + unsigned long *p = map + BIT_WORD(start); + const long size = start + nr; + int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); + unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); + bool dirty = false; + + assert(start >= 0 && nr >= 0); + + /* First word */ + if (nr - bits_to_clear > 0) { + if ((*p) & mask_to_clear) { + dirty = true; + } + *p &= ~mask_to_clear; + nr -= bits_to_clear; + bits_to_clear = BITS_PER_LONG; + p++; + } + + /* Full words */ + if (bits_to_clear == BITS_PER_LONG) { + while (nr >= BITS_PER_LONG) { + if (*p) { + dirty = true; + *p = 0; + } + nr -= BITS_PER_LONG; + p++; + } + } + + /* Last word */ + if (nr) { + mask_to_clear &= BITMAP_LAST_WORD_MASK(size); + if ((*p) & mask_to_clear) { + dirty = true; + } + *p &= ~mask_to_clear; + } + + return dirty; +} + bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr) { unsigned long *p = map + BIT_WORD(start); @@ -376,7 +421,7 @@ static void bitmap_to_from_le(unsigned long *dst, { long len = BITS_TO_LONGS(nbits); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN long index; for (index = 0; index < len; index++) { diff --git a/util/cacheflush.c b/util/cacheflush.c index 4b57186d89cd..2c2c73e085c2 100644 --- a/util/cacheflush.c +++ b/util/cacheflush.c @@ -1,5 +1,5 @@ /* - * Flush the host cpu caches. + * Info about, and flushing the host cpu caches. * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -9,8 +9,218 @@ #include "qemu/cacheflush.h" #include "qemu/cacheinfo.h" #include "qemu/bitops.h" +#include "qemu/host-utils.h" +#include "qemu/atomic.h" +int qemu_icache_linesize = 0; +int qemu_icache_linesize_log; +int qemu_dcache_linesize = 0; +int qemu_dcache_linesize_log; + +/* + * Operating system specific cache detection mechanisms. + */ + +#if defined(_WIN32) + +static void sys_cache_info(int *isize, int *dsize) +{ + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf; + DWORD size = 0; + BOOL success; + size_t i, n; + + /* + * Check for the required buffer size first. Note that if the zero + * size we use for the probe results in success, then there is no + * data available; fail in that case. + */ + success = GetLogicalProcessorInformation(0, &size); + if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return; + } + + n = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + size = n * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + buf = g_new0(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, n); + if (!GetLogicalProcessorInformation(buf, &size)) { + goto fail; + } + + for (i = 0; i < n; i++) { + if (buf[i].Relationship == RelationCache + && buf[i].Cache.Level == 1) { + switch (buf[i].Cache.Type) { + case CacheUnified: + *isize = *dsize = buf[i].Cache.LineSize; + break; + case CacheInstruction: + *isize = buf[i].Cache.LineSize; + break; + case CacheData: + *dsize = buf[i].Cache.LineSize; + break; + default: + break; + } + } + } + fail: + g_free(buf); +} + +#elif defined(CONFIG_DARWIN) +# include +static void sys_cache_info(int *isize, int *dsize) +{ + /* There's only a single sysctl for both I/D cache line sizes. */ + long size; + size_t len = sizeof(size); + if (!sysctlbyname("hw.cachelinesize", &size, &len, NULL, 0)) { + *isize = *dsize = size; + } +} +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# include +static void sys_cache_info(int *isize, int *dsize) +{ + /* There's only a single sysctl for both I/D cache line sizes. */ + int size; + size_t len = sizeof(size); + if (!sysctlbyname("machdep.cacheline_size", &size, &len, NULL, 0)) { + *isize = *dsize = size; + } +} +#else +/* POSIX */ + +static void sys_cache_info(int *isize, int *dsize) +{ +# ifdef _SC_LEVEL1_ICACHE_LINESIZE + int tmp_isize = (int) sysconf(_SC_LEVEL1_ICACHE_LINESIZE); + if (tmp_isize > 0) { + *isize = tmp_isize; + } +# endif +# ifdef _SC_LEVEL1_DCACHE_LINESIZE + int tmp_dsize = (int) sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (tmp_dsize > 0) { + *dsize = tmp_dsize; + } +# endif +} +#endif /* sys_cache_info */ + + +/* + * Architecture (+ OS) specific cache detection mechanisms. + */ + +#if defined(__powerpc__) +static bool have_coherent_icache; +#endif + +#if defined(__aarch64__) && !defined(CONFIG_DARWIN) +/* Apple does not expose CTR_EL0, so we must use system interfaces. */ +static uint64_t save_ctr_el0; +static void arch_cache_info(int *isize, int *dsize) +{ + uint64_t ctr; + + /* + * The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1, + * but (at least under Linux) these are marked protected by the + * kernel. However, CTR_EL0 contains the minimum linesize in the + * entire hierarchy, and is used by userspace cache flushing. + * + * We will also use this value in flush_idcache_range. + */ + asm volatile("mrs\t%0, ctr_el0" : "=r"(ctr)); + save_ctr_el0 = ctr; + + if (*isize == 0 || *dsize == 0) { + if (*isize == 0) { + *isize = 4 << (ctr & 0xf); + } + if (*dsize == 0) { + *dsize = 4 << ((ctr >> 16) & 0xf); + } + } +} + +#elif defined(_ARCH_PPC) && defined(__linux__) +# include "elf.h" + +static void arch_cache_info(int *isize, int *dsize) +{ + if (*isize == 0) { + *isize = qemu_getauxval(AT_ICACHEBSIZE); + } + if (*dsize == 0) { + *dsize = qemu_getauxval(AT_DCACHEBSIZE); + } + have_coherent_icache = qemu_getauxval(AT_HWCAP) & PPC_FEATURE_ICACHE_SNOOP; +} + +#else +static void arch_cache_info(int *isize, int *dsize) { } +#endif /* arch_cache_info */ + +/* + * ... and if all else fails ... + */ + +static void fallback_cache_info(int *isize, int *dsize) +{ + /* If we can only find one of the two, assume they're the same. */ + if (*isize) { + if (*dsize) { + /* Success! */ + } else { + *dsize = *isize; + } + } else if (*dsize) { + *isize = *dsize; + } else { +#if defined(_ARCH_PPC) + /* + * For PPC, we're going to use the cache sizes computed for + * flush_idcache_range. Which means that we must use the + * architecture minimum. + */ + *isize = *dsize = 16; +#else + /* Otherwise, 64 bytes is not uncommon. */ + *isize = *dsize = 64; +#endif + } +} + +static void __attribute__((constructor)) init_cache_info(void) +{ + int isize = 0, dsize = 0; + + sys_cache_info(&isize, &dsize); + arch_cache_info(&isize, &dsize); + fallback_cache_info(&isize, &dsize); + + assert((isize & (isize - 1)) == 0); + assert((dsize & (dsize - 1)) == 0); + + qemu_icache_linesize = isize; + qemu_icache_linesize_log = ctz32(isize); + qemu_dcache_linesize = dsize; + qemu_dcache_linesize_log = ctz32(dsize); + + qatomic64_init(); +} + + +/* + * Architecture (+ OS) specific cache flushing mechanisms. + */ + #if defined(__i386__) || defined(__x86_64__) || defined(__s390__) /* Caches are coherent and do not require flushing; symbol inline. */ @@ -28,17 +238,6 @@ void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len) } #else -/* - * TODO: unify this with cacheinfo.c. - * We want to save the whole contents of CTR_EL0, so that we - * have more than the linesize, but also IDC and DIC. - */ -static uint64_t save_ctr_el0; -static void __attribute__((constructor)) init_ctr_el0(void) -{ - asm volatile("mrs\t%0, ctr_el0" : "=r"(save_ctr_el0)); -} - /* * This is a copy of gcc's __aarch64_sync_cache_range, modified * to fit this three-operand interface. @@ -48,8 +247,8 @@ void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len) const unsigned CTR_IDC = 1u << 28; const unsigned CTR_DIC = 1u << 29; const uint64_t ctr_el0 = save_ctr_el0; - const uintptr_t icache_lsize = 4 << extract64(ctr_el0, 0, 4); - const uintptr_t dcache_lsize = 4 << extract64(ctr_el0, 16, 4); + const uintptr_t icache_lsize = qemu_icache_linesize; + const uintptr_t dcache_lsize = qemu_dcache_linesize; uintptr_t p; /* @@ -104,8 +303,24 @@ void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len) void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len) { uintptr_t p, b, e; - size_t dsize = qemu_dcache_linesize; - size_t isize = qemu_icache_linesize; + size_t dsize, isize; + + /* + * Some processors have coherent caches and support a simplified + * flushing procedure. See + * POWER9 UM, 4.6.2.2 Instruction Cache Block Invalidate (icbi) + * https://ibm.ent.box.com/s/tmklq90ze7aj8f4n32er1mu3sy9u8k3k + */ + if (have_coherent_icache) { + asm volatile ("sync\n\t" + "icbi 0,%0\n\t" + "isync" + : : "r"(rx) : "memory"); + return; + } + + dsize = qemu_dcache_linesize; + isize = qemu_icache_linesize; b = rw & ~(dsize - 1); e = (rw + len + dsize - 1) & ~(dsize - 1); diff --git a/util/cacheinfo.c b/util/cacheinfo.c deleted file mode 100644 index ab1644d490f5..000000000000 --- a/util/cacheinfo.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * cacheinfo.c - helpers to query the host about its caches - * - * Copyright (C) 2017, Emilio G. Cota - * License: GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu/host-utils.h" -#include "qemu/atomic.h" -#include "qemu/cacheinfo.h" - -int qemu_icache_linesize = 0; -int qemu_icache_linesize_log; -int qemu_dcache_linesize = 0; -int qemu_dcache_linesize_log; - -/* - * Operating system specific detection mechanisms. - */ - -#if defined(_WIN32) - -static void sys_cache_info(int *isize, int *dsize) -{ - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf; - DWORD size = 0; - BOOL success; - size_t i, n; - - /* Check for the required buffer size first. Note that if the zero - size we use for the probe results in success, then there is no - data available; fail in that case. */ - success = GetLogicalProcessorInformation(0, &size); - if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - return; - } - - n = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - size = n * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - buf = g_new0(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, n); - if (!GetLogicalProcessorInformation(buf, &size)) { - goto fail; - } - - for (i = 0; i < n; i++) { - if (buf[i].Relationship == RelationCache - && buf[i].Cache.Level == 1) { - switch (buf[i].Cache.Type) { - case CacheUnified: - *isize = *dsize = buf[i].Cache.LineSize; - break; - case CacheInstruction: - *isize = buf[i].Cache.LineSize; - break; - case CacheData: - *dsize = buf[i].Cache.LineSize; - break; - default: - break; - } - } - } - fail: - g_free(buf); -} - -#elif defined(__APPLE__) -# include -static void sys_cache_info(int *isize, int *dsize) -{ - /* There's only a single sysctl for both I/D cache line sizes. */ - long size; - size_t len = sizeof(size); - if (!sysctlbyname("hw.cachelinesize", &size, &len, NULL, 0)) { - *isize = *dsize = size; - } -} -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -# include -static void sys_cache_info(int *isize, int *dsize) -{ - /* There's only a single sysctl for both I/D cache line sizes. */ - int size; - size_t len = sizeof(size); - if (!sysctlbyname("machdep.cacheline_size", &size, &len, NULL, 0)) { - *isize = *dsize = size; - } -} -#else -/* POSIX */ - -static void sys_cache_info(int *isize, int *dsize) -{ -# ifdef _SC_LEVEL1_ICACHE_LINESIZE - int tmp_isize = (int) sysconf(_SC_LEVEL1_ICACHE_LINESIZE); - if (tmp_isize > 0) { - *isize = tmp_isize; - } -# endif -# ifdef _SC_LEVEL1_DCACHE_LINESIZE - int tmp_dsize = (int) sysconf(_SC_LEVEL1_DCACHE_LINESIZE); - if (tmp_dsize > 0) { - *dsize = tmp_dsize; - } -# endif -} -#endif /* sys_cache_info */ - -/* - * Architecture (+ OS) specific detection mechanisms. - */ - -#if defined(__aarch64__) - -static void arch_cache_info(int *isize, int *dsize) -{ - if (*isize == 0 || *dsize == 0) { - uint64_t ctr; - - /* The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1, - but (at least under Linux) these are marked protected by the - kernel. However, CTR_EL0 contains the minimum linesize in the - entire hierarchy, and is used by userspace cache flushing. */ - asm volatile("mrs\t%0, ctr_el0" : "=r"(ctr)); - if (*isize == 0) { - *isize = 4 << (ctr & 0xf); - } - if (*dsize == 0) { - *dsize = 4 << ((ctr >> 16) & 0xf); - } - } -} - -#elif defined(_ARCH_PPC) && defined(__linux__) -# include "elf.h" - -static void arch_cache_info(int *isize, int *dsize) -{ - if (*isize == 0) { - *isize = qemu_getauxval(AT_ICACHEBSIZE); - } - if (*dsize == 0) { - *dsize = qemu_getauxval(AT_DCACHEBSIZE); - } -} - -#else -static void arch_cache_info(int *isize, int *dsize) { } -#endif /* arch_cache_info */ - -/* - * ... and if all else fails ... - */ - -static void fallback_cache_info(int *isize, int *dsize) -{ - /* If we can only find one of the two, assume they're the same. */ - if (*isize) { - if (*dsize) { - /* Success! */ - } else { - *dsize = *isize; - } - } else if (*dsize) { - *isize = *dsize; - } else { -#if defined(_ARCH_PPC) - /* - * For PPC, we're going to use the cache sizes computed for - * flush_idcache_range. Which means that we must use the - * architecture minimum. - */ - *isize = *dsize = 16; -#else - /* Otherwise, 64 bytes is not uncommon. */ - *isize = *dsize = 64; -#endif - } -} - -static void __attribute__((constructor)) init_cache_info(void) -{ - int isize = 0, dsize = 0; - - sys_cache_info(&isize, &dsize); - arch_cache_info(&isize, &dsize); - fallback_cache_info(&isize, &dsize); - - assert((isize & (isize - 1)) == 0); - assert((dsize & (dsize - 1)) == 0); - - qemu_icache_linesize = isize; - qemu_icache_linesize_log = ctz32(isize); - qemu_dcache_linesize = dsize; - qemu_dcache_linesize_log = ctz32(dsize); - - qatomic64_init(); -} diff --git a/util/compatfd.c b/util/compatfd.c index ab810c42a927..147e39e2c62b 100644 --- a/util/compatfd.c +++ b/util/compatfd.c @@ -42,25 +42,11 @@ static void *sigwait_compat(void *opaque) } } else { struct qemu_signalfd_siginfo buffer; - size_t offset = 0; - memset(&buffer, 0, sizeof(buffer)); buffer.ssi_signo = sig; - while (offset < sizeof(buffer)) { - ssize_t len; - - len = write(info->fd, (char *)&buffer + offset, - sizeof(buffer) - offset); - if (len == -1 && errno == EINTR) { - continue; - } - - if (len <= 0) { - return NULL; - } - - offset += len; + if (qemu_write_full(info->fd, &buffer, sizeof(buffer)) != sizeof(buffer)) { + return NULL; } } } @@ -74,14 +60,11 @@ static int qemu_signalfd_compat(const sigset_t *mask) info = g_malloc(sizeof(*info)); - if (pipe(fds) == -1) { + if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) { g_free(info); return -1; } - qemu_set_cloexec(fds[0]); - qemu_set_cloexec(fds[1]); - memcpy(&info->mask, mask, sizeof(*mask)); info->fd = fds[1]; diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index e99b8a4f9c8c..e2690c5f4142 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -27,7 +27,6 @@ #endif #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "qemu/coroutine_int.h" #ifdef CONFIG_SAFESTACK diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 904b375192ca..ddc98fb4f88c 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -25,12 +25,13 @@ #include "qemu/osdep.h" #include #include "qemu/coroutine_int.h" +#include "qemu/coroutine-tls.h" #ifdef CONFIG_VALGRIND_H #include #endif -#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +#ifdef QEMU_SANITIZE_ADDRESS #ifdef CONFIG_ASAN_IFACE_FIBER #define CONFIG_ASAN 1 #include @@ -66,8 +67,8 @@ typedef struct { /** * Per-thread coroutine bookkeeping */ -static __thread CoroutineUContext leader; -static __thread Coroutine *current; +QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current); +QEMU_DEFINE_STATIC_CO_TLS(CoroutineUContext, leader); /* * va_args to makecontext() must be type 'int', so passing @@ -97,14 +98,15 @@ static inline __attribute__((always_inline)) void finish_switch_fiber(void *fake_stack_save) { #ifdef CONFIG_ASAN + CoroutineUContext *leaderp = get_ptr_leader(); const void *bottom_old; size_t size_old; __sanitizer_finish_switch_fiber(fake_stack_save, &bottom_old, &size_old); - if (!leader.stack) { - leader.stack = (void *)bottom_old; - leader.stack_size = size_old; + if (!leaderp->stack) { + leaderp->stack = (void *)bottom_old; + leaderp->stack_size = size_old; } #endif #ifdef CONFIG_TSAN @@ -161,8 +163,10 @@ static void coroutine_trampoline(int i0, int i1) /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { - start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, leader.stack, - leader.stack_size); + CoroutineUContext *leaderp = get_ptr_leader(); + + start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, + leaderp->stack, leaderp->stack_size); start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */ siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } @@ -297,7 +301,7 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, int ret; void *fake_stack_save = NULL; - current = to_; + set_current(to_); ret = sigsetjmp(from->env, 0); if (ret == 0) { @@ -315,18 +319,24 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, Coroutine *qemu_coroutine_self(void) { - if (!current) { - current = &leader.base; + Coroutine *self = get_current(); + CoroutineUContext *leaderp = get_ptr_leader(); + + if (!self) { + self = &leaderp->base; + set_current(self); } #ifdef CONFIG_TSAN - if (!leader.tsan_co_fiber) { - leader.tsan_co_fiber = __tsan_get_current_fiber(); + if (!leaderp->tsan_co_fiber) { + leaderp->tsan_co_fiber = __tsan_get_current_fiber(); } #endif - return current; + return self; } bool qemu_in_coroutine(void) { - return current && current->caller; + Coroutine *self = get_current(); + + return self && self->caller; } diff --git a/util/coroutine-win32.c b/util/coroutine-win32.c index de6bd4fd3e4e..7db2e8f8c8c4 100644 --- a/util/coroutine-win32.c +++ b/util/coroutine-win32.c @@ -23,8 +23,8 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/coroutine_int.h" +#include "qemu/coroutine-tls.h" typedef struct { @@ -34,8 +34,8 @@ typedef struct CoroutineAction action; } CoroutineWin32; -static __thread CoroutineWin32 leader; -static __thread Coroutine *current; +QEMU_DEFINE_STATIC_CO_TLS(CoroutineWin32, leader); +QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current); /* This function is marked noinline to prevent GCC from inlining it * into coroutine_trampoline(). If we allow it to do that then it @@ -52,7 +52,7 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_); CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_); - current = to_; + set_current(to_); to->action = action; SwitchToFiber(to->fiber); @@ -89,14 +89,21 @@ void qemu_coroutine_delete(Coroutine *co_) Coroutine *qemu_coroutine_self(void) { + Coroutine *current = get_current(); + if (!current) { - current = &leader.base; - leader.fiber = ConvertThreadToFiber(NULL); + CoroutineWin32 *leader = get_ptr_leader(); + + current = &leader->base; + set_current(current); + leader->fiber = ConvertThreadToFiber(NULL); } return current; } bool qemu_in_coroutine(void) { + Coroutine *current = get_current(); + return current && current->caller; } diff --git a/util/cutils.c b/util/cutils.c index 0d475ec4cddd..5887e7441405 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -26,7 +26,28 @@ #include "qemu/host-utils.h" #include -#include "qemu-common.h" +#ifdef __FreeBSD__ +#include +#include +#endif + +#ifdef __NetBSD__ +#include +#endif + +#ifdef __HAIKU__ +#include +#endif + +#ifdef __APPLE__ +#include +#endif + +#ifdef G_OS_WIN32 +#include +#include +#endif + #include "qemu/ctype.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -145,77 +166,6 @@ time_t mktimegm(struct tm *tm) return t; } -/* - * Make sure data goes on disk, but if possible do not bother to - * write out the inode just for timestamp updates. - * - * Unfortunately even in 2009 many operating systems do not support - * fdatasync and have to fall back to fsync. - */ -int qemu_fdatasync(int fd) -{ -#ifdef CONFIG_FDATASYNC - return fdatasync(fd); -#else - return fsync(fd); -#endif -} - -/** - * Sync changes made to the memory mapped file back to the backing - * storage. For POSIX compliant systems this will fallback - * to regular msync call. Otherwise it will trigger whole file sync - * (including the metadata case there is no support to skip that otherwise) - * - * @addr - start of the memory area to be synced - * @length - length of the are to be synced - * @fd - file descriptor for the file to be synced - * (mandatory only for POSIX non-compliant systems) - */ -int qemu_msync(void *addr, size_t length, int fd) -{ -#ifdef CONFIG_POSIX - size_t align_mask = ~(qemu_real_host_page_size - 1); - - /** - * There are no strict reqs as per the length of mapping - * to be synced. Still the length needs to follow the address - * alignment changes. Additionally - round the size to the multiple - * of PAGE_SIZE - */ - length += ((uintptr_t)addr & (qemu_real_host_page_size - 1)); - length = (length + ~align_mask) & align_mask; - - addr = (void *)((uintptr_t)addr & align_mask); - - return msync(addr, length, MS_SYNC); -#else /* CONFIG_POSIX */ - /** - * Perform the sync based on the file descriptor - * The sync range will most probably be wider than the one - * requested - but it will still get the job done - */ - return qemu_fdatasync(fd); -#endif /* CONFIG_POSIX */ -} - -#ifndef _WIN32 -/* Sets a specific flag */ -int fcntl_setfl(int fd, int flag) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - if (flags == -1) - return -errno; - - if (fcntl(fd, F_SETFL, flags | flag) == -1) - return -errno; - - return 0; -} -#endif - static int64_t suffix_mul(char suffix, int64_t unit) { switch (qemu_toupper(suffix)) { @@ -247,10 +197,8 @@ static int64_t suffix_mul(char suffix, int64_t unit) * fractional portion is truncated to byte * - 0x7fEE - hexadecimal, unit determined by @default_suffix * - * The following cause a deprecation warning, and may be removed in the future - * - 0xabc{kKmMgGtTpP} - hex with scaling suffix - * * The following are intentionally not supported + * - hex with scaling suffix, such as 0x20M * - octal, such as 08 * - fractional hex, such as 0x1.8 * - floating point exponents, such as 1e3 @@ -272,7 +220,6 @@ static int do_strtosz(const char *nptr, const char **end, int retval; const char *endptr, *f; unsigned char c; - bool hex = false; uint64_t val, valf = 0; int64_t mul; @@ -287,17 +234,16 @@ static int do_strtosz(const char *nptr, const char **end, goto out; } if (val == 0 && (*endptr == 'x' || *endptr == 'X')) { - /* Input looks like hex, reparse, and insist on no fraction. */ + /* Input looks like hex; reparse, and insist on no fraction or suffix. */ retval = qemu_strtou64(nptr, &endptr, 16, &val); if (retval) { goto out; } - if (*endptr == '.') { + if (*endptr == '.' || suffix_mul(*endptr, unit) > 0) { endptr = nptr; retval = -EINVAL; goto out; } - hex = true; } else if (*endptr == '.') { /* * Input looks like a fraction. Make sure even 1.k works @@ -322,10 +268,6 @@ static int do_strtosz(const char *nptr, const char **end, c = *endptr; mul = suffix_mul(c, unit); if (mul > 0) { - if (hex) { - warn_report("Using a multiplier suffix on hex numbers " - "is deprecated: %s", nptr); - } endptr++; } else { mul = suffix_mul(default_suffix, unit); @@ -935,6 +877,25 @@ int parse_debug_env(const char *name, int max, int initial) return debug; } +const char *si_prefix(unsigned int exp10) +{ + static const char *prefixes[] = { + "a", "f", "p", "n", "u", "m", "", "K", "M", "G", "T", "P", "E" + }; + + exp10 += 18; + assert(exp10 % 3 == 0 && exp10 / 3 < ARRAY_SIZE(prefixes)); + return prefixes[exp10 / 3]; +} + +const char *iec_binary_prefix(unsigned int exp2) +{ + static const char *prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" }; + + assert(exp2 % 10 == 0 && exp2 / 10 < ARRAY_SIZE(prefixes)); + return prefixes[exp2 / 10]; +} + /* * Return human readable string for size @val. * @val can be anything that uint64_t allows (no more than "16 EiB"). @@ -943,7 +904,6 @@ int parse_debug_env(const char *name, int max, int initial) */ char *size_to_str(uint64_t val) { - static const char *suffixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" }; uint64_t div; int i; @@ -954,25 +914,23 @@ char *size_to_str(uint64_t val) * (see e41b509d68afb1f for more info) */ frexp(val / (1000.0 / 1024.0), &i); - i = (i - 1) / 10; - div = 1ULL << (i * 10); + i = (i - 1) / 10 * 10; + div = 1ULL << i; - return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]); + return g_strdup_printf("%0.3g %sB", (double)val / div, iec_binary_prefix(i)); } char *freq_to_str(uint64_t freq_hz) { - static const char *const suffixes[] = { "", "K", "M", "G", "T", "P", "E" }; double freq = freq_hz; - size_t idx = 0; + size_t exp10 = 0; while (freq >= 1000.0) { freq /= 1000.0; - idx++; + exp10 += 3; } - assert(idx < ARRAY_SIZE(suffixes)); - return g_strdup_printf("%0.3g %sHz", freq, suffixes[idx]); + return g_strdup_printf("%0.3g %sHz", freq, si_prefix(exp10)); } int qemu_pstrcmp0(const char **str1, const char **str2) @@ -1003,6 +961,114 @@ static inline const char *next_component(const char *dir, int *p_len) return dir; } +static const char *exec_dir; + +void qemu_init_exec_dir(const char *argv0) +{ +#ifdef G_OS_WIN32 + char *p; + char buf[MAX_PATH]; + DWORD len; + + if (exec_dir) { + return; + } + + len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); + if (len == 0) { + return; + } + + buf[len] = 0; + p = buf + len - 1; + while (p != buf && *p != '\\') { + p--; + } + *p = 0; + if (access(buf, R_OK) == 0) { + exec_dir = g_strdup(buf); + } else { + exec_dir = CONFIG_BINDIR; + } +#else + char *p = NULL; + char buf[PATH_MAX]; + + if (exec_dir) { + return; + } + +#if defined(__linux__) + { + int len; + len = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (len > 0) { + buf[len] = 0; + p = buf; + } + } +#elif defined(__FreeBSD__) \ + || (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME)) + { +#if defined(__FreeBSD__) + static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; +#else + static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +#endif + size_t len = sizeof(buf) - 1; + + *buf = '\0'; + if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) && + *buf) { + buf[sizeof(buf) - 1] = '\0'; + p = buf; + } + } +#elif defined(__APPLE__) + { + char fpath[PATH_MAX]; + uint32_t len = sizeof(fpath); + if (_NSGetExecutablePath(fpath, &len) == 0) { + p = realpath(fpath, buf); + if (!p) { + return; + } + } + } +#elif defined(__HAIKU__) + { + image_info ii; + int32_t c = 0; + + *buf = '\0'; + while (get_next_image_info(0, &c, &ii) == B_OK) { + if (ii.type == B_APP_IMAGE) { + strncpy(buf, ii.name, sizeof(buf)); + buf[sizeof(buf) - 1] = 0; + p = buf; + break; + } + } + } +#endif + /* If we don't have any way of figuring out the actual executable + location then try argv[0]. */ + if (!p && argv0) { + p = realpath(argv0, buf); + } + if (p) { + exec_dir = g_path_get_dirname(p); + } else { + exec_dir = CONFIG_BINDIR; + } +#endif +} + +const char *qemu_get_exec_dir(void) +{ + return exec_dir; +} + char *get_relocated_path(const char *dir) { size_t prefix_len = strlen(CONFIG_PREFIX); @@ -1013,31 +1079,52 @@ char *get_relocated_path(const char *dir) /* Fail if qemu_init_exec_dir was not called. */ assert(exec_dir[0]); - if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) { - return g_strdup(dir); - } result = g_string_new(exec_dir); + g_string_append(result, "/qemu-bundle"); + if (access(result->str, R_OK) == 0) { +#ifdef G_OS_WIN32 + size_t size = mbsrtowcs(NULL, &dir, 0, &(mbstate_t){0}) + 1; + PWSTR wdir = g_new(WCHAR, size); + mbsrtowcs(wdir, &dir, size, &(mbstate_t){0}); + + PCWSTR wdir_skipped_root; + PathCchSkipRoot(wdir, &wdir_skipped_root); + + size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0}); + char *cursor = result->str + result->len; + g_string_set_size(result, result->len + size); + wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0}); + g_free(wdir); +#else + g_string_append(result, dir); +#endif + } else if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) { + g_string_assign(result, dir); + } else { + g_string_assign(result, exec_dir); + + /* Advance over common components. */ + len_dir = len_bindir = prefix_len; + do { + dir += len_dir; + bindir += len_bindir; + dir = next_component(dir, &len_dir); + bindir = next_component(bindir, &len_bindir); + } while (len_dir && len_dir == len_bindir && !memcmp(dir, bindir, len_dir)); + + /* Ascend from bindir to the common prefix with dir. */ + while (len_bindir) { + bindir += len_bindir; + g_string_append(result, "/.."); + bindir = next_component(bindir, &len_bindir); + } - /* Advance over common components. */ - len_dir = len_bindir = prefix_len; - do { - dir += len_dir; - bindir += len_bindir; - dir = next_component(dir, &len_dir); - bindir = next_component(bindir, &len_bindir); - } while (len_dir && len_dir == len_bindir && !memcmp(dir, bindir, len_dir)); - - /* Ascend from bindir to the common prefix with dir. */ - while (len_bindir) { - bindir += len_bindir; - g_string_append(result, "/.."); - bindir = next_component(bindir, &len_bindir); + if (*dir) { + assert(G_IS_DIR_SEPARATOR(dir[-1])); + g_string_append(result, dir - 1); + } } - if (*dir) { - assert(G_IS_DIR_SEPARATOR(dir[-1])); - g_string_append(result, dir - 1); - } return g_string_free(result, false); } diff --git a/util/dma_notifier.c b/util/dma_notifier.c new file mode 100644 index 000000000000..104b9d1777a0 --- /dev/null +++ b/util/dma_notifier.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022, NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu/osdep.h" +#include "qemu/notify.h" +#include "qemu/dma_notifier.h" + + +static NotifierList * dma_trigger_notifier_list = NULL; + +void dma_trigger_init_notifier_list(NotifierList * notifier_list) +{ + notifier_list_init(notifier_list); + dma_trigger_notifier_list = notifier_list; +} + +void dma_trigger_notifier_connect(Notifier *notifier) +{ + if (dma_trigger_notifier_list != NULL) + { + notifier_list_add(dma_trigger_notifier_list, notifier); + } +} + +void dma_trigger_notify(void * data) +{ + if (dma_trigger_notifier_list != NULL) + { + notifier_list_notify(dma_trigger_notifier_list, data); + } +} + +void dma_trigger_disconnect(Notifier *notifier) +{ + notifier_remove(notifier); +} + + diff --git a/util/error-report.c b/util/error-report.c new file mode 100644 index 000000000000..6e44a5573217 --- /dev/null +++ b/util/error-report.c @@ -0,0 +1,404 @@ +/* + * Error reporting + * + * Copyright (C) 2010 Red Hat Inc. + * + * Authors: + * Markus Armbruster , + * + * 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 "monitor/monitor.h" +#include "qemu/error-report.h" + +/* + * @report_type is the type of message: error, warning or + * informational. + */ +typedef enum { + REPORT_TYPE_ERROR, + REPORT_TYPE_WARNING, + REPORT_TYPE_INFO, +} report_type; + +/* Prepend timestamp to messages */ +bool message_with_timestamp; +bool error_with_guestname; +const char *error_guest_name; + +int error_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = error_vprintf(fmt, ap); + va_end(ap); + return ret; +} + +static Location std_loc = { + .kind = LOC_NONE +}; +static Location *cur_loc = &std_loc; + +/* + * Push location saved in LOC onto the location stack, return it. + * The top of that stack is the current location. + * Needs a matching loc_pop(). + */ +Location *loc_push_restore(Location *loc) +{ + assert(!loc->prev); + loc->prev = cur_loc; + cur_loc = loc; + return loc; +} + +/* + * Initialize *LOC to "nowhere", push it onto the location stack. + * The top of that stack is the current location. + * Needs a matching loc_pop(). + * Return LOC. + */ +Location *loc_push_none(Location *loc) +{ + loc->kind = LOC_NONE; + loc->prev = NULL; + return loc_push_restore(loc); +} + +/* + * Pop the location stack. + * LOC must be the current location, i.e. the top of the stack. + */ +Location *loc_pop(Location *loc) +{ + assert(cur_loc == loc && loc->prev); + cur_loc = loc->prev; + loc->prev = NULL; + return loc; +} + +/* + * Save the current location in LOC, return LOC. + */ +Location *loc_save(Location *loc) +{ + *loc = *cur_loc; + loc->prev = NULL; + return loc; +} + +/* + * Change the current location to the one saved in LOC. + */ +void loc_restore(Location *loc) +{ + Location *prev = cur_loc->prev; + assert(!loc->prev); + *cur_loc = *loc; + cur_loc->prev = prev; +} + +/* + * Change the current location to "nowhere in particular". + */ +void loc_set_none(void) +{ + cur_loc->kind = LOC_NONE; +} + +/* + * Change the current location to argument ARGV[IDX..IDX+CNT-1]. + */ +void loc_set_cmdline(char **argv, int idx, int cnt) +{ + cur_loc->kind = LOC_CMDLINE; + cur_loc->num = cnt; + cur_loc->ptr = argv + idx; +} + +/* + * Change the current location to file FNAME, line LNO. + */ +void loc_set_file(const char *fname, int lno) +{ + assert (fname || cur_loc->kind == LOC_FILE); + cur_loc->kind = LOC_FILE; + cur_loc->num = lno; + if (fname) { + cur_loc->ptr = fname; + } +} + +/* + * Print current location to current monitor if we have one, else to stderr. + */ +static void print_loc(void) +{ + const char *sep = ""; + int i; + const char *const *argp; + + if (!monitor_cur() && g_get_prgname()) { + error_printf("%s:", g_get_prgname()); + sep = " "; + } + switch (cur_loc->kind) { + case LOC_CMDLINE: + argp = cur_loc->ptr; + for (i = 0; i < cur_loc->num; i++) { + error_printf("%s%s", sep, argp[i]); + sep = " "; + } + error_printf(": "); + break; + case LOC_FILE: + error_printf("%s:", (const char *)cur_loc->ptr); + if (cur_loc->num) { + error_printf("%d:", cur_loc->num); + } + error_printf(" "); + break; + default: + error_printf("%s", sep); + } +} + +static char * +real_time_iso8601(void) +{ +#if GLIB_CHECK_VERSION(2,62,0) + g_autoptr(GDateTime) dt = g_date_time_new_now_utc(); + /* ignore deprecation warning, since GLIB_VERSION_MAX_ALLOWED is 2.56 */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return g_date_time_format_iso8601(dt); +#pragma GCC diagnostic pop +#else + GTimeVal tv; + g_get_current_time(&tv); + return g_time_val_to_iso8601(&tv); +#endif +} + +/* + * Print a message to current monitor if we have one, else to stderr. + * @report_type is the type of message: error, warning or informational. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + */ +G_GNUC_PRINTF(2, 0) +static void vreport(report_type type, const char *fmt, va_list ap) +{ + gchar *timestr; + + if (message_with_timestamp && !monitor_cur()) { + timestr = real_time_iso8601(); + error_printf("%s ", timestr); + g_free(timestr); + } + + /* Only prepend guest name if -msg guest-name and -name guest=... are set */ + if (error_with_guestname && error_guest_name && !monitor_cur()) { + error_printf("%s ", error_guest_name); + } + + print_loc(); + + switch (type) { + case REPORT_TYPE_ERROR: + break; + case REPORT_TYPE_WARNING: + error_printf("warning: "); + break; + case REPORT_TYPE_INFO: + error_printf("info: "); + break; + } + + error_vprintf(fmt, ap); + error_printf("\n"); +} + +/* + * Print an error message to current monitor if we have one, else to stderr. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void error_vreport(const char *fmt, va_list ap) +{ + vreport(REPORT_TYPE_ERROR, fmt, ap); +} + +/* + * Print a warning message to current monitor if we have one, else to stderr. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + */ +void warn_vreport(const char *fmt, va_list ap) +{ + vreport(REPORT_TYPE_WARNING, fmt, ap); +} + +/* + * Print an information message to current monitor if we have one, else to + * stderr. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + */ +void info_vreport(const char *fmt, va_list ap) +{ + vreport(REPORT_TYPE_INFO, fmt, ap); +} + +/* + * Print an error message to current monitor if we have one, else to stderr. + * Format arguments like sprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use error_setg() there. + */ +void error_report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vreport(REPORT_TYPE_ERROR, fmt, ap); + va_end(ap); +} + +/* + * Print a warning message to current monitor if we have one, else to stderr. + * Format arguments like sprintf(). The resulting message should be a + * single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + */ +void warn_report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vreport(REPORT_TYPE_WARNING, fmt, ap); + va_end(ap); +} + +/* + * Print an information message to current monitor if we have one, else to + * stderr. + * Format arguments like sprintf(). The resulting message should be a + * single phrase, with no newline or trailing punctuation. + * Prepend the current location and append a newline. + */ +void info_report(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vreport(REPORT_TYPE_INFO, fmt, ap); + va_end(ap); +} + +/* + * Like error_report(), except print just once. + * If *printed is false, print the message, and flip *printed to true. + * Return whether the message was printed. + */ +bool error_report_once_cond(bool *printed, const char *fmt, ...) +{ + va_list ap; + + assert(printed); + if (*printed) { + return false; + } + *printed = true; + va_start(ap, fmt); + vreport(REPORT_TYPE_ERROR, fmt, ap); + va_end(ap); + return true; +} + +/* + * Like warn_report(), except print just once. + * If *printed is false, print the message, and flip *printed to true. + * Return whether the message was printed. + */ +bool warn_report_once_cond(bool *printed, const char *fmt, ...) +{ + va_list ap; + + assert(printed); + if (*printed) { + return false; + } + *printed = true; + va_start(ap, fmt); + vreport(REPORT_TYPE_WARNING, fmt, ap); + va_end(ap); + return true; +} + +static char *qemu_glog_domains; + +static void qemu_log_func(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + switch (log_level & G_LOG_LEVEL_MASK) { + case G_LOG_LEVEL_DEBUG: + case G_LOG_LEVEL_INFO: + /* + * Use same G_MESSAGES_DEBUG logic as glib to enable/disable debug + * messages + */ + if (qemu_glog_domains == NULL) { + break; + } + if (strcmp(qemu_glog_domains, "all") != 0 && + (log_domain == NULL || !strstr(qemu_glog_domains, log_domain))) { + break; + } + /* Fall through */ + case G_LOG_LEVEL_MESSAGE: + info_report("%s%s%s", + log_domain ?: "", log_domain ? ": " : "", message); + + break; + case G_LOG_LEVEL_WARNING: + warn_report("%s%s%s", + log_domain ?: "", log_domain ? ": " : "", message); + break; + case G_LOG_LEVEL_CRITICAL: + case G_LOG_LEVEL_ERROR: + error_report("%s%s%s", + log_domain ?: "", log_domain ? ": " : "", message); + break; + } +} + +void error_init(const char *argv0) +{ + const char *p = strrchr(argv0, '/'); + + /* Set the program name for error_print_loc(). */ + g_set_prgname(p ? p + 1 : argv0); + + /* + * This sets up glib logging so libraries using it also print their logs + * through error_report(), warn_report(), info_report(). + */ + g_log_set_default_handler(qemu_log_func, NULL); + g_warn_if_fail(qemu_glog_domains == NULL); + qemu_glog_domains = g_strdup(g_getenv("G_MESSAGES_DEBUG")); +} diff --git a/util/error.c b/util/error.c index b6c89d141208..1e7af665b838 100644 --- a/util/error.c +++ b/util/error.c @@ -45,6 +45,7 @@ static void error_handle_fatal(Error **errp, Error *err) } } +G_GNUC_PRINTF(6, 0) static void error_setv(Error **errp, const char *src, int line, const char *func, ErrorClass err_class, const char *fmt, va_list ap, diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c index 16294e98d434..76420c5b560c 100644 --- a/util/event_notifier-posix.c +++ b/util/event_notifier-posix.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/event_notifier.h" #include "qemu/main-loop.h" @@ -50,16 +49,14 @@ int event_notifier_init(EventNotifier *e, int active) if (errno != ENOSYS) { return -errno; } - if (qemu_pipe(fds) < 0) { + if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) { return -errno; } - ret = fcntl_setfl(fds[0], O_NONBLOCK); - if (ret < 0) { + if (!g_unix_set_fd_nonblocking(fds[0], true, NULL)) { ret = -errno; goto fail; } - ret = fcntl_setfl(fds[1], O_NONBLOCK); - if (ret < 0) { + if (!g_unix_set_fd_nonblocking(fds[1], true, NULL)) { ret = -errno; goto fail; } diff --git a/util/event_notifier-win32.c b/util/event_notifier-win32.c index 62c53b0a9909..9352da4699c7 100644 --- a/util/event_notifier-win32.c +++ b/util/event_notifier-win32.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/event_notifier.h" #include "qemu/main-loop.h" diff --git a/util/hbitmap.c b/util/hbitmap.c index ea989e1f0e59..297db35fb11e 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -873,11 +873,6 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) } } -bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b) -{ - return (a->orig_size == b->orig_size); -} - /** * hbitmap_sparse_merge: performs dst = dst | src * works with differing granularities. @@ -901,28 +896,24 @@ static void hbitmap_sparse_merge(HBitmap *dst, const HBitmap *src) * Given HBitmaps A and B, let R := A (BITOR) B. * Bitmaps A and B will not be modified, * except when bitmap R is an alias of A or B. - * - * @return true if the merge was successful, - * false if it was not attempted. + * Bitmaps must have same size. */ -bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) +void hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) { int i; uint64_t j; - if (!hbitmap_can_merge(a, b) || !hbitmap_can_merge(a, result)) { - return false; - } - assert(hbitmap_can_merge(b, result)); + assert(a->orig_size == result->orig_size); + assert(b->orig_size == result->orig_size); if ((!hbitmap_count(a) && result == b) || (!hbitmap_count(b) && result == a)) { - return true; + return; } if (!hbitmap_count(a) && !hbitmap_count(b)) { hbitmap_reset_all(result); - return true; + return; } if (a->granularity != b->granularity) { @@ -935,7 +926,7 @@ bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) if (b != result) { hbitmap_sparse_merge(result, b); } - return true; + return; } /* This merge is O(size), as BITS_PER_LONG and HBITMAP_LEVELS are constant. @@ -951,8 +942,6 @@ bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) /* Recompute the dirty count */ result->count = hb_count_between(result, 0, result->size - 1); - - return true; } char *hbitmap_sha256(const HBitmap *bitmap, Error **errp) diff --git a/util/hexdump.c b/util/hexdump.c index 2c105a884620..9921114b3c75 100644 --- a/util/hexdump.c +++ b/util/hexdump.c @@ -14,7 +14,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/cutils.h" void qemu_hexdump_line(char *line, unsigned int b, const void *bufptr, unsigned int len, bool ascii) diff --git a/util/host-utils.c b/util/host-utils.c index bcc772b8ec95..fb91bcba823d 100644 --- a/util/host-utils.c +++ b/util/host-utils.c @@ -34,7 +34,7 @@ static inline void mul64(uint64_t *plow, uint64_t *phigh, typedef union { uint64_t ll; struct { -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN uint32_t high, low; #else uint32_t low, high; @@ -266,3 +266,183 @@ void ulshift(uint64_t *plow, uint64_t *phigh, int32_t shift, bool *overflow) *plow = *plow << shift; } } + +/* + * Unsigned 256-by-128 division. + * Returns the remainder via r. + * Returns lower 128 bit of quotient. + * Needs a normalized divisor (most significant bit set to 1). + * + * Adapted from include/qemu/host-utils.h udiv_qrnnd, + * from the GNU Multi Precision Library - longlong.h __udiv_qrnnd + * (https://gmplib.org/repo/gmp/file/tip/longlong.h) + * + * Licensed under the GPLv2/LGPLv3 + */ +static Int128 udiv256_qrnnd(Int128 *r, Int128 n1, Int128 n0, Int128 d) +{ + Int128 d0, d1, q0, q1, r1, r0, m; + uint64_t mp0, mp1; + + d0 = int128_make64(int128_getlo(d)); + d1 = int128_make64(int128_gethi(d)); + + r1 = int128_remu(n1, d1); + q1 = int128_divu(n1, d1); + mp0 = int128_getlo(q1); + mp1 = int128_gethi(q1); + mulu128(&mp0, &mp1, int128_getlo(d0)); + m = int128_make128(mp0, mp1); + r1 = int128_make128(int128_gethi(n0), int128_getlo(r1)); + if (int128_ult(r1, m)) { + q1 = int128_sub(q1, int128_one()); + r1 = int128_add(r1, d); + if (int128_uge(r1, d)) { + if (int128_ult(r1, m)) { + q1 = int128_sub(q1, int128_one()); + r1 = int128_add(r1, d); + } + } + } + r1 = int128_sub(r1, m); + + r0 = int128_remu(r1, d1); + q0 = int128_divu(r1, d1); + mp0 = int128_getlo(q0); + mp1 = int128_gethi(q0); + mulu128(&mp0, &mp1, int128_getlo(d0)); + m = int128_make128(mp0, mp1); + r0 = int128_make128(int128_getlo(n0), int128_getlo(r0)); + if (int128_ult(r0, m)) { + q0 = int128_sub(q0, int128_one()); + r0 = int128_add(r0, d); + if (int128_uge(r0, d)) { + if (int128_ult(r0, m)) { + q0 = int128_sub(q0, int128_one()); + r0 = int128_add(r0, d); + } + } + } + r0 = int128_sub(r0, m); + + *r = r0; + return int128_or(int128_lshift(q1, 64), q0); +} + +/* + * Unsigned 256-by-128 division. + * Returns the remainder. + * Returns quotient via plow and phigh. + * Also returns the remainder via the function return value. + */ +Int128 divu256(Int128 *plow, Int128 *phigh, Int128 divisor) +{ + Int128 dhi = *phigh; + Int128 dlo = *plow; + Int128 rem, dhighest; + int sh; + + if (!int128_nz(divisor) || !int128_nz(dhi)) { + *plow = int128_divu(dlo, divisor); + *phigh = int128_zero(); + return int128_remu(dlo, divisor); + } else { + sh = clz128(divisor); + + if (int128_ult(dhi, divisor)) { + if (sh != 0) { + /* normalize the divisor, shifting the dividend accordingly */ + divisor = int128_lshift(divisor, sh); + dhi = int128_or(int128_lshift(dhi, sh), + int128_urshift(dlo, (128 - sh))); + dlo = int128_lshift(dlo, sh); + } + + *phigh = int128_zero(); + *plow = udiv256_qrnnd(&rem, dhi, dlo, divisor); + } else { + if (sh != 0) { + /* normalize the divisor, shifting the dividend accordingly */ + divisor = int128_lshift(divisor, sh); + dhighest = int128_rshift(dhi, (128 - sh)); + dhi = int128_or(int128_lshift(dhi, sh), + int128_urshift(dlo, (128 - sh))); + dlo = int128_lshift(dlo, sh); + + *phigh = udiv256_qrnnd(&dhi, dhighest, dhi, divisor); + } else { + /* + * dhi >= divisor + * Since the MSB of divisor is set (sh == 0), + * (dhi - divisor) < divisor + * + * Thus, the high part of the quotient is 1, and we can + * calculate the low part with a single call to udiv_qrnnd + * after subtracting divisor from dhi + */ + dhi = int128_sub(dhi, divisor); + *phigh = int128_one(); + } + + *plow = udiv256_qrnnd(&rem, dhi, dlo, divisor); + } + + /* + * since the dividend/divisor might have been normalized, + * the remainder might also have to be shifted back + */ + rem = int128_urshift(rem, sh); + return rem; + } +} + +/* + * Signed 256-by-128 division. + * Returns quotient via plow and phigh. + * Also returns the remainder via the function return value. + */ +Int128 divs256(Int128 *plow, Int128 *phigh, Int128 divisor) +{ + bool neg_quotient = false, neg_remainder = false; + Int128 unsig_hi = *phigh, unsig_lo = *plow; + Int128 rem; + + if (!int128_nonneg(*phigh)) { + neg_quotient = !neg_quotient; + neg_remainder = !neg_remainder; + + if (!int128_nz(unsig_lo)) { + unsig_hi = int128_neg(unsig_hi); + } else { + unsig_hi = int128_not(unsig_hi); + unsig_lo = int128_neg(unsig_lo); + } + } + + if (!int128_nonneg(divisor)) { + neg_quotient = !neg_quotient; + + divisor = int128_neg(divisor); + } + + rem = divu256(&unsig_lo, &unsig_hi, divisor); + + if (neg_quotient) { + if (!int128_nz(unsig_lo)) { + *phigh = int128_neg(unsig_hi); + *plow = int128_zero(); + } else { + *phigh = int128_not(unsig_hi); + *plow = int128_neg(unsig_lo); + } + } else { + *phigh = unsig_hi; + *plow = unsig_lo; + } + + if (neg_remainder) { + return int128_neg(rem); + } else { + return rem; + } +} diff --git a/util/interval-tree.c b/util/interval-tree.c new file mode 100644 index 000000000000..4c0baf108f0e --- /dev/null +++ b/util/interval-tree.c @@ -0,0 +1,882 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qemu/interval-tree.h" +#include "qemu/atomic.h" + +/* + * Red Black Trees. + * + * For now, don't expose Linux Red-Black Trees separately, but retain the + * separate type definitions to keep the implementation sane, and allow + * the possibility of separating them later. + * + * Derived from include/linux/rbtree_augmented.h and its dependencies. + */ + +/* + * red-black trees properties: https://en.wikipedia.org/wiki/Rbtree + * + * 1) A node is either red or black + * 2) The root is black + * 3) All leaves (NULL) are black + * 4) Both children of every red node are black + * 5) Every simple path from root to leaves contains the same number + * of black nodes. + * + * 4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two + * consecutive red nodes in a path and every red node is therefore followed by + * a black. So if B is the number of black nodes on every simple path (as per + * 5), then the longest possible path due to 4 is 2B. + * + * We shall indicate color with case, where black nodes are uppercase and red + * nodes will be lowercase. Unknown color nodes shall be drawn as red within + * parentheses and have some accompanying text comment. + * + * Notes on lockless lookups: + * + * All stores to the tree structure (rb_left and rb_right) must be done using + * WRITE_ONCE [qatomic_set for QEMU]. And we must not inadvertently cause + * (temporary) loops in the tree structure as seen in program order. + * + * These two requirements will allow lockless iteration of the tree -- not + * correct iteration mind you, tree rotations are not atomic so a lookup might + * miss entire subtrees. + * + * But they do guarantee that any such traversal will only see valid elements + * and that it will indeed complete -- does not get stuck in a loop. + * + * It also guarantees that if the lookup returns an element it is the 'correct' + * one. But not returning an element does _NOT_ mean it's not present. + * + * NOTE: + * + * Stores to __rb_parent_color are not important for simple lookups so those + * are left undone as of now. Nor did I check for loops involving parent + * pointers. + */ + +typedef enum RBColor +{ + RB_RED, + RB_BLACK, +} RBColor; + +typedef struct RBAugmentCallbacks { + void (*propagate)(RBNode *node, RBNode *stop); + void (*copy)(RBNode *old, RBNode *new); + void (*rotate)(RBNode *old, RBNode *new); +} RBAugmentCallbacks; + +static inline RBNode *rb_parent(const RBNode *n) +{ + return (RBNode *)(n->rb_parent_color & ~1); +} + +static inline RBNode *rb_red_parent(const RBNode *n) +{ + return (RBNode *)n->rb_parent_color; +} + +static inline RBColor pc_color(uintptr_t pc) +{ + return (RBColor)(pc & 1); +} + +static inline bool pc_is_red(uintptr_t pc) +{ + return pc_color(pc) == RB_RED; +} + +static inline bool pc_is_black(uintptr_t pc) +{ + return !pc_is_red(pc); +} + +static inline RBColor rb_color(const RBNode *n) +{ + return pc_color(n->rb_parent_color); +} + +static inline bool rb_is_red(const RBNode *n) +{ + return pc_is_red(n->rb_parent_color); +} + +static inline bool rb_is_black(const RBNode *n) +{ + return pc_is_black(n->rb_parent_color); +} + +static inline void rb_set_black(RBNode *n) +{ + n->rb_parent_color |= RB_BLACK; +} + +static inline void rb_set_parent_color(RBNode *n, RBNode *p, RBColor color) +{ + n->rb_parent_color = (uintptr_t)p | color; +} + +static inline void rb_set_parent(RBNode *n, RBNode *p) +{ + rb_set_parent_color(n, p, rb_color(n)); +} + +static inline void rb_link_node(RBNode *node, RBNode *parent, RBNode **rb_link) +{ + node->rb_parent_color = (uintptr_t)parent; + node->rb_left = node->rb_right = NULL; + + qatomic_set(rb_link, node); +} + +static RBNode *rb_next(RBNode *node) +{ + RBNode *parent; + + /* OMIT: if empty node, return null. */ + + /* + * If we have a right-hand child, go down and then left as far as we can. + */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) { + node = node->rb_left; + } + return node; + } + + /* + * No right-hand children. Everything down and left is smaller than us, + * so any 'next' node must be in the general direction of our parent. + * Go up the tree; any time the ancestor is a right-hand child of its + * parent, keep going up. First time it's a left-hand child of its + * parent, said parent is our 'next' node. + */ + while ((parent = rb_parent(node)) && node == parent->rb_right) { + node = parent; + } + + return parent; +} + +static inline void rb_change_child(RBNode *old, RBNode *new, + RBNode *parent, RBRoot *root) +{ + if (!parent) { + qatomic_set(&root->rb_node, new); + } else if (parent->rb_left == old) { + qatomic_set(&parent->rb_left, new); + } else { + qatomic_set(&parent->rb_right, new); + } +} + +static inline void rb_rotate_set_parents(RBNode *old, RBNode *new, + RBRoot *root, RBColor color) +{ + RBNode *parent = rb_parent(old); + + new->rb_parent_color = old->rb_parent_color; + rb_set_parent_color(old, new, color); + rb_change_child(old, new, parent, root); +} + +static void rb_insert_augmented(RBNode *node, RBRoot *root, + const RBAugmentCallbacks *augment) +{ + RBNode *parent = rb_red_parent(node), *gparent, *tmp; + + while (true) { + /* + * Loop invariant: node is red. + */ + if (unlikely(!parent)) { + /* + * The inserted node is root. Either this is the first node, or + * we recursed at Case 1 below and are no longer violating 4). + */ + rb_set_parent_color(node, NULL, RB_BLACK); + break; + } + + /* + * If there is a black parent, we are done. Otherwise, take some + * corrective action as, per 4), we don't want a red root or two + * consecutive red nodes. + */ + if (rb_is_black(parent)) { + break; + } + + gparent = rb_red_parent(parent); + + tmp = gparent->rb_right; + if (parent != tmp) { /* parent == gparent->rb_left */ + if (tmp && rb_is_red(tmp)) { + /* + * Case 1 - node's uncle is red (color flips). + * + * G g + * / \ / \ + * p u --> P U + * / / + * n n + * + * However, since g's parent might be red, and 4) does not + * allow this, we need to recurse at g. + */ + rb_set_parent_color(tmp, gparent, RB_BLACK); + rb_set_parent_color(parent, gparent, RB_BLACK); + node = gparent; + parent = rb_parent(node); + rb_set_parent_color(node, parent, RB_RED); + continue; + } + + tmp = parent->rb_right; + if (node == tmp) { + /* + * Case 2 - node's uncle is black and node is + * the parent's right child (left rotate at parent). + * + * G G + * / \ / \ + * p U --> n U + * \ / + * n p + * + * This still leaves us in violation of 4), the + * continuation into Case 3 will fix that. + */ + tmp = node->rb_left; + qatomic_set(&parent->rb_right, tmp); + qatomic_set(&node->rb_left, parent); + if (tmp) { + rb_set_parent_color(tmp, parent, RB_BLACK); + } + rb_set_parent_color(parent, node, RB_RED); + augment->rotate(parent, node); + parent = node; + tmp = node->rb_right; + } + + /* + * Case 3 - node's uncle is black and node is + * the parent's left child (right rotate at gparent). + * + * G P + * / \ / \ + * p U --> n g + * / \ + * n U + */ + qatomic_set(&gparent->rb_left, tmp); /* == parent->rb_right */ + qatomic_set(&parent->rb_right, gparent); + if (tmp) { + rb_set_parent_color(tmp, gparent, RB_BLACK); + } + rb_rotate_set_parents(gparent, parent, root, RB_RED); + augment->rotate(gparent, parent); + break; + } else { + tmp = gparent->rb_left; + if (tmp && rb_is_red(tmp)) { + /* Case 1 - color flips */ + rb_set_parent_color(tmp, gparent, RB_BLACK); + rb_set_parent_color(parent, gparent, RB_BLACK); + node = gparent; + parent = rb_parent(node); + rb_set_parent_color(node, parent, RB_RED); + continue; + } + + tmp = parent->rb_left; + if (node == tmp) { + /* Case 2 - right rotate at parent */ + tmp = node->rb_right; + qatomic_set(&parent->rb_left, tmp); + qatomic_set(&node->rb_right, parent); + if (tmp) { + rb_set_parent_color(tmp, parent, RB_BLACK); + } + rb_set_parent_color(parent, node, RB_RED); + augment->rotate(parent, node); + parent = node; + tmp = node->rb_left; + } + + /* Case 3 - left rotate at gparent */ + qatomic_set(&gparent->rb_right, tmp); /* == parent->rb_left */ + qatomic_set(&parent->rb_left, gparent); + if (tmp) { + rb_set_parent_color(tmp, gparent, RB_BLACK); + } + rb_rotate_set_parents(gparent, parent, root, RB_RED); + augment->rotate(gparent, parent); + break; + } + } +} + +static void rb_insert_augmented_cached(RBNode *node, + RBRootLeftCached *root, bool newleft, + const RBAugmentCallbacks *augment) +{ + if (newleft) { + root->rb_leftmost = node; + } + rb_insert_augmented(node, &root->rb_root, augment); +} + +static void rb_erase_color(RBNode *parent, RBRoot *root, + const RBAugmentCallbacks *augment) +{ + RBNode *node = NULL, *sibling, *tmp1, *tmp2; + + while (true) { + /* + * Loop invariants: + * - node is black (or NULL on first iteration) + * - node is not the root (parent is not NULL) + * - All leaf paths going through parent and node have a + * black node count that is 1 lower than other leaf paths. + */ + sibling = parent->rb_right; + if (node != sibling) { /* node == parent->rb_left */ + if (rb_is_red(sibling)) { + /* + * Case 1 - left rotate at parent + * + * P S + * / \ / \ + * N s --> p Sr + * / \ / \ + * Sl Sr N Sl + */ + tmp1 = sibling->rb_left; + qatomic_set(&parent->rb_right, tmp1); + qatomic_set(&sibling->rb_left, parent); + rb_set_parent_color(tmp1, parent, RB_BLACK); + rb_rotate_set_parents(parent, sibling, root, RB_RED); + augment->rotate(parent, sibling); + sibling = tmp1; + } + tmp1 = sibling->rb_right; + if (!tmp1 || rb_is_black(tmp1)) { + tmp2 = sibling->rb_left; + if (!tmp2 || rb_is_black(tmp2)) { + /* + * Case 2 - sibling color flip + * (p could be either color here) + * + * (p) (p) + * / \ / \ + * N S --> N s + * / \ / \ + * Sl Sr Sl Sr + * + * This leaves us violating 5) which + * can be fixed by flipping p to black + * if it was red, or by recursing at p. + * p is red when coming from Case 1. + */ + rb_set_parent_color(sibling, parent, RB_RED); + if (rb_is_red(parent)) { + rb_set_black(parent); + } else { + node = parent; + parent = rb_parent(node); + if (parent) { + continue; + } + } + break; + } + /* + * Case 3 - right rotate at sibling + * (p could be either color here) + * + * (p) (p) + * / \ / \ + * N S --> N sl + * / \ \ + * sl Sr S + * \ + * Sr + * + * Note: p might be red, and then bot + * p and sl are red after rotation (which + * breaks property 4). This is fixed in + * Case 4 (in rb_rotate_set_parents() + * which set sl the color of p + * and set p RB_BLACK) + * + * (p) (sl) + * / \ / \ + * N sl --> P S + * \ / \ + * S N Sr + * \ + * Sr + */ + tmp1 = tmp2->rb_right; + qatomic_set(&sibling->rb_left, tmp1); + qatomic_set(&tmp2->rb_right, sibling); + qatomic_set(&parent->rb_right, tmp2); + if (tmp1) { + rb_set_parent_color(tmp1, sibling, RB_BLACK); + } + augment->rotate(sibling, tmp2); + tmp1 = sibling; + sibling = tmp2; + } + /* + * Case 4 - left rotate at parent + color flips + * (p and sl could be either color here. + * After rotation, p becomes black, s acquires + * p's color, and sl keeps its color) + * + * (p) (s) + * / \ / \ + * N S --> P Sr + * / \ / \ + * (sl) sr N (sl) + */ + tmp2 = sibling->rb_left; + qatomic_set(&parent->rb_right, tmp2); + qatomic_set(&sibling->rb_left, parent); + rb_set_parent_color(tmp1, sibling, RB_BLACK); + if (tmp2) { + rb_set_parent(tmp2, parent); + } + rb_rotate_set_parents(parent, sibling, root, RB_BLACK); + augment->rotate(parent, sibling); + break; + } else { + sibling = parent->rb_left; + if (rb_is_red(sibling)) { + /* Case 1 - right rotate at parent */ + tmp1 = sibling->rb_right; + qatomic_set(&parent->rb_left, tmp1); + qatomic_set(&sibling->rb_right, parent); + rb_set_parent_color(tmp1, parent, RB_BLACK); + rb_rotate_set_parents(parent, sibling, root, RB_RED); + augment->rotate(parent, sibling); + sibling = tmp1; + } + tmp1 = sibling->rb_left; + if (!tmp1 || rb_is_black(tmp1)) { + tmp2 = sibling->rb_right; + if (!tmp2 || rb_is_black(tmp2)) { + /* Case 2 - sibling color flip */ + rb_set_parent_color(sibling, parent, RB_RED); + if (rb_is_red(parent)) { + rb_set_black(parent); + } else { + node = parent; + parent = rb_parent(node); + if (parent) { + continue; + } + } + break; + } + /* Case 3 - left rotate at sibling */ + tmp1 = tmp2->rb_left; + qatomic_set(&sibling->rb_right, tmp1); + qatomic_set(&tmp2->rb_left, sibling); + qatomic_set(&parent->rb_left, tmp2); + if (tmp1) { + rb_set_parent_color(tmp1, sibling, RB_BLACK); + } + augment->rotate(sibling, tmp2); + tmp1 = sibling; + sibling = tmp2; + } + /* Case 4 - right rotate at parent + color flips */ + tmp2 = sibling->rb_right; + qatomic_set(&parent->rb_left, tmp2); + qatomic_set(&sibling->rb_right, parent); + rb_set_parent_color(tmp1, sibling, RB_BLACK); + if (tmp2) { + rb_set_parent(tmp2, parent); + } + rb_rotate_set_parents(parent, sibling, root, RB_BLACK); + augment->rotate(parent, sibling); + break; + } + } +} + +static void rb_erase_augmented(RBNode *node, RBRoot *root, + const RBAugmentCallbacks *augment) +{ + RBNode *child = node->rb_right; + RBNode *tmp = node->rb_left; + RBNode *parent, *rebalance; + uintptr_t pc; + + if (!tmp) { + /* + * Case 1: node to erase has no more than 1 child (easy!) + * + * Note that if there is one child it must be red due to 5) + * and node must be black due to 4). We adjust colors locally + * so as to bypass rb_erase_color() later on. + */ + pc = node->rb_parent_color; + parent = rb_parent(node); + rb_change_child(node, child, parent, root); + if (child) { + child->rb_parent_color = pc; + rebalance = NULL; + } else { + rebalance = pc_is_black(pc) ? parent : NULL; + } + tmp = parent; + } else if (!child) { + /* Still case 1, but this time the child is node->rb_left */ + pc = node->rb_parent_color; + parent = rb_parent(node); + tmp->rb_parent_color = pc; + rb_change_child(node, tmp, parent, root); + rebalance = NULL; + tmp = parent; + } else { + RBNode *successor = child, *child2; + tmp = child->rb_left; + if (!tmp) { + /* + * Case 2: node's successor is its right child + * + * (n) (s) + * / \ / \ + * (x) (s) -> (x) (c) + * \ + * (c) + */ + parent = successor; + child2 = successor->rb_right; + + augment->copy(node, successor); + } else { + /* + * Case 3: node's successor is leftmost under + * node's right child subtree + * + * (n) (s) + * / \ / \ + * (x) (y) -> (x) (y) + * / / + * (p) (p) + * / / + * (s) (c) + * \ + * (c) + */ + do { + parent = successor; + successor = tmp; + tmp = tmp->rb_left; + } while (tmp); + child2 = successor->rb_right; + qatomic_set(&parent->rb_left, child2); + qatomic_set(&successor->rb_right, child); + rb_set_parent(child, successor); + + augment->copy(node, successor); + augment->propagate(parent, successor); + } + + tmp = node->rb_left; + qatomic_set(&successor->rb_left, tmp); + rb_set_parent(tmp, successor); + + pc = node->rb_parent_color; + tmp = rb_parent(node); + rb_change_child(node, successor, tmp, root); + + if (child2) { + rb_set_parent_color(child2, parent, RB_BLACK); + rebalance = NULL; + } else { + rebalance = rb_is_black(successor) ? parent : NULL; + } + successor->rb_parent_color = pc; + tmp = successor; + } + + augment->propagate(tmp, NULL); + + if (rebalance) { + rb_erase_color(rebalance, root, augment); + } +} + +static void rb_erase_augmented_cached(RBNode *node, RBRootLeftCached *root, + const RBAugmentCallbacks *augment) +{ + if (root->rb_leftmost == node) { + root->rb_leftmost = rb_next(node); + } + rb_erase_augmented(node, &root->rb_root, augment); +} + + +/* + * Interval trees. + * + * Derived from lib/interval_tree.c and its dependencies, + * especially include/linux/interval_tree_generic.h. + */ + +#define rb_to_itree(N) container_of(N, IntervalTreeNode, rb) + +static bool interval_tree_compute_max(IntervalTreeNode *node, bool exit) +{ + IntervalTreeNode *child; + uint64_t max = node->last; + + if (node->rb.rb_left) { + child = rb_to_itree(node->rb.rb_left); + if (child->subtree_last > max) { + max = child->subtree_last; + } + } + if (node->rb.rb_right) { + child = rb_to_itree(node->rb.rb_right); + if (child->subtree_last > max) { + max = child->subtree_last; + } + } + if (exit && node->subtree_last == max) { + return true; + } + node->subtree_last = max; + return false; +} + +static void interval_tree_propagate(RBNode *rb, RBNode *stop) +{ + while (rb != stop) { + IntervalTreeNode *node = rb_to_itree(rb); + if (interval_tree_compute_max(node, true)) { + break; + } + rb = rb_parent(&node->rb); + } +} + +static void interval_tree_copy(RBNode *rb_old, RBNode *rb_new) +{ + IntervalTreeNode *old = rb_to_itree(rb_old); + IntervalTreeNode *new = rb_to_itree(rb_new); + + new->subtree_last = old->subtree_last; +} + +static void interval_tree_rotate(RBNode *rb_old, RBNode *rb_new) +{ + IntervalTreeNode *old = rb_to_itree(rb_old); + IntervalTreeNode *new = rb_to_itree(rb_new); + + new->subtree_last = old->subtree_last; + interval_tree_compute_max(old, false); +} + +static const RBAugmentCallbacks interval_tree_augment = { + .propagate = interval_tree_propagate, + .copy = interval_tree_copy, + .rotate = interval_tree_rotate, +}; + +/* Insert / remove interval nodes from the tree */ +void interval_tree_insert(IntervalTreeNode *node, IntervalTreeRoot *root) +{ + RBNode **link = &root->rb_root.rb_node, *rb_parent = NULL; + uint64_t start = node->start, last = node->last; + IntervalTreeNode *parent; + bool leftmost = true; + + while (*link) { + rb_parent = *link; + parent = rb_to_itree(rb_parent); + + if (parent->subtree_last < last) { + parent->subtree_last = last; + } + if (start < parent->start) { + link = &parent->rb.rb_left; + } else { + link = &parent->rb.rb_right; + leftmost = false; + } + } + + node->subtree_last = last; + rb_link_node(&node->rb, rb_parent, link); + rb_insert_augmented_cached(&node->rb, root, leftmost, + &interval_tree_augment); +} + +void interval_tree_remove(IntervalTreeNode *node, IntervalTreeRoot *root) +{ + rb_erase_augmented_cached(&node->rb, root, &interval_tree_augment); +} + +/* + * Iterate over intervals intersecting [start;last] + * + * Note that a node's interval intersects [start;last] iff: + * Cond1: node->start <= last + * and + * Cond2: start <= node->last + */ + +static IntervalTreeNode *interval_tree_subtree_search(IntervalTreeNode *node, + uint64_t start, + uint64_t last) +{ + while (true) { + /* + * Loop invariant: start <= node->subtree_last + * (Cond2 is satisfied by one of the subtree nodes) + */ + if (node->rb.rb_left) { + IntervalTreeNode *left = rb_to_itree(node->rb.rb_left); + + if (start <= left->subtree_last) { + /* + * Some nodes in left subtree satisfy Cond2. + * Iterate to find the leftmost such node N. + * If it also satisfies Cond1, that's the + * match we are looking for. Otherwise, there + * is no matching interval as nodes to the + * right of N can't satisfy Cond1 either. + */ + node = left; + continue; + } + } + if (node->start <= last) { /* Cond1 */ + if (start <= node->last) { /* Cond2 */ + return node; /* node is leftmost match */ + } + if (node->rb.rb_right) { + node = rb_to_itree(node->rb.rb_right); + if (start <= node->subtree_last) { + continue; + } + } + } + return NULL; /* no match */ + } +} + +IntervalTreeNode *interval_tree_iter_first(IntervalTreeRoot *root, + uint64_t start, uint64_t last) +{ + IntervalTreeNode *node, *leftmost; + + if (!root->rb_root.rb_node) { + return NULL; + } + + /* + * Fastpath range intersection/overlap between A: [a0, a1] and + * B: [b0, b1] is given by: + * + * a0 <= b1 && b0 <= a1 + * + * ... where A holds the lock range and B holds the smallest + * 'start' and largest 'last' in the tree. For the later, we + * rely on the root node, which by augmented interval tree + * property, holds the largest value in its last-in-subtree. + * This allows mitigating some of the tree walk overhead for + * for non-intersecting ranges, maintained and consulted in O(1). + */ + node = rb_to_itree(root->rb_root.rb_node); + if (node->subtree_last < start) { + return NULL; + } + + leftmost = rb_to_itree(root->rb_leftmost); + if (leftmost->start > last) { + return NULL; + } + + return interval_tree_subtree_search(node, start, last); +} + +IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node, + uint64_t start, uint64_t last) +{ + RBNode *rb = node->rb.rb_right, *prev; + + while (true) { + /* + * Loop invariants: + * Cond1: node->start <= last + * rb == node->rb.rb_right + * + * First, search right subtree if suitable + */ + if (rb) { + IntervalTreeNode *right = rb_to_itree(rb); + + if (start <= right->subtree_last) { + return interval_tree_subtree_search(right, start, last); + } + } + + /* Move up the tree until we come from a node's left child */ + do { + rb = rb_parent(&node->rb); + if (!rb) { + return NULL; + } + prev = &node->rb; + node = rb_to_itree(rb); + rb = node->rb.rb_right; + } while (prev == rb); + + /* Check if the node intersects [start;last] */ + if (last < node->start) { /* !Cond1 */ + return NULL; + } + if (start <= node->last) { /* Cond2 */ + return node; + } + } +} + +/* Occasionally useful for calling from within the debugger. */ +#if 0 +static void debug_interval_tree_int(IntervalTreeNode *node, + const char *dir, int level) +{ + printf("%4d %*s %s [%" PRIu64 ",%" PRIu64 "] subtree_last:%" PRIu64 "\n", + level, level + 1, dir, rb_is_red(&node->rb) ? "r" : "b", + node->start, node->last, node->subtree_last); + + if (node->rb.rb_left) { + debug_interval_tree_int(rb_to_itree(node->rb.rb_left), "<", level + 1); + } + if (node->rb.rb_right) { + debug_interval_tree_int(rb_to_itree(node->rb.rb_right), ">", level + 1); + } +} + +void debug_interval_tree(IntervalTreeNode *node); +void debug_interval_tree(IntervalTreeNode *node) +{ + if (node) { + debug_interval_tree_int(node, "*", 0); + } else { + printf("null\n"); + } +} +#endif diff --git a/util/iov.c b/util/iov.c index 58c7b3eeee5f..b4be580022ad 100644 --- a/util/iov.c +++ b/util/iov.c @@ -17,7 +17,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/iov.h" #include "qemu/sockets.h" #include "qemu/cutils.h" @@ -112,12 +111,17 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send) /*XXX Note: windows has WSASend() and WSARecv() */ unsigned i = 0; ssize_t ret = 0; + ssize_t off = 0; while (i < iov_cnt) { ssize_t r = do_send - ? send(sockfd, iov[i].iov_base, iov[i].iov_len, 0) - : recv(sockfd, iov[i].iov_base, iov[i].iov_len, 0); + ? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0) + : recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0); if (r > 0) { ret += r; + off += r; + if (off < iov[i].iov_len) { + continue; + } } else if (!r) { break; } else if (errno == EINTR) { @@ -130,6 +134,7 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send) } break; } + off = 0; i++; } return ret; diff --git a/util/iova-tree.c b/util/iova-tree.c index 6dff29c1f62d..536789797e47 100644 --- a/util/iova-tree.c +++ b/util/iova-tree.c @@ -164,15 +164,13 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) g_tree_foreach(tree->tree, iova_tree_traverse, iterator); } -int 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); } - - return IOVA_OK; } /** diff --git a/util/keyval.c b/util/keyval.c index 0cf2e84dc8d8..66a5b4740f12 100644 --- a/util/keyval.c +++ b/util/keyval.c @@ -95,8 +95,8 @@ #include "qapi/qmp/qlist.h" #include "qapi/qmp/qstring.h" #include "qemu/cutils.h" +#include "qemu/keyval.h" #include "qemu/help_option.h" -#include "qemu/option.h" /* * Convert @key to a list index. diff --git a/util/log.c b/util/log.c index 2ee1500beedf..7837ff991769 100644 --- a/util/log.c +++ b/util/log.c @@ -26,153 +26,340 @@ #include "trace/control.h" #include "qemu/thread.h" #include "qemu/lockable.h" +#include "qemu/rcu.h" +#ifdef CONFIG_LINUX +#include +#endif + + +typedef struct RCUCloseFILE { + struct rcu_head rcu; + FILE *fd; +} RCUCloseFILE; + +/* Mutex covering the other global_* variables. */ +static QemuMutex global_mutex; +static char *global_filename; +static FILE *global_file; +static __thread FILE *thread_file; +static __thread Notifier qemu_log_thread_cleanup_notifier; -static char *logfilename; -static QemuMutex qemu_logfile_mutex; -QemuLogFile *qemu_logfile; int qemu_loglevel; -static int log_append = 0; +static bool log_per_thread; static GArray *debug_regions; -/* Return the number of characters emitted. */ -int qemu_log(const char *fmt, ...) +/* Returns true if qemu_log() will really write somewhere. */ +bool qemu_log_enabled(void) { - int ret = 0; - QemuLogFile *logfile; + return log_per_thread || qatomic_read(&global_file) != NULL; +} - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); +/* Returns true if qemu_log() will write somewhere other than stderr. */ +bool qemu_log_separate(void) +{ + if (log_per_thread) { + return true; + } else { + FILE *logfile = qatomic_read(&global_file); + return logfile && logfile != stderr; + } +} + +static int log_thread_id(void) +{ +#ifdef CONFIG_GETTID + return gettid(); +#elif defined(SYS_gettid) + return syscall(SYS_gettid); +#else + static int counter; + return qatomic_fetch_inc(&counter); +#endif +} + +static void qemu_log_thread_cleanup(Notifier *n, void *unused) +{ + if (thread_file != stderr) { + fclose(thread_file); + thread_file = NULL; + } +} + +/* Lock/unlock output. */ + +static FILE *qemu_log_trylock_with_err(Error **errp) +{ + FILE *logfile; + + logfile = thread_file; + if (!logfile) { + if (log_per_thread) { + g_autofree char *filename + = g_strdup_printf(global_filename, log_thread_id()); + logfile = fopen(filename, "w"); + if (!logfile) { + error_setg_errno(errp, errno, + "Error opening logfile %s for thread %d", + filename, log_thread_id()); + return NULL; + } + thread_file = logfile; + qemu_log_thread_cleanup_notifier.notify = qemu_log_thread_cleanup; + qemu_thread_atexit_add(&qemu_log_thread_cleanup_notifier); + } else { + rcu_read_lock(); + /* + * FIXME: typeof_strip_qual, as used by qatomic_rcu_read, + * does not work with pointers to undefined structures, + * such as we have with struct _IO_FILE and musl libc. + * Since all we want is a read of a pointer, cast to void**, + * which does work with typeof_strip_qual. + */ + logfile = qatomic_rcu_read((void **)&global_file); + if (!logfile) { + rcu_read_unlock(); + return NULL; + } + } + } + + qemu_flockfile(logfile); + return logfile; +} + +FILE *qemu_log_trylock(void) +{ + return qemu_log_trylock_with_err(NULL); +} + +void qemu_log_unlock(FILE *logfile) +{ if (logfile) { + fflush(logfile); + qemu_funlockfile(logfile); + if (!log_per_thread) { + rcu_read_unlock(); + } + } +} + +void qemu_log(const char *fmt, ...) +{ + FILE *f = qemu_log_trylock(); + if (f) { va_list ap; + va_start(ap, fmt); - ret = vfprintf(logfile->fd, fmt, ap); + vfprintf(f, fmt, ap); va_end(ap); - - /* Don't pass back error results. */ - if (ret < 0) { - ret = 0; - } + qemu_log_unlock(f); } - rcu_read_unlock(); - return ret; } -static void __attribute__((__constructor__)) qemu_logfile_init(void) +static void __attribute__((__constructor__)) startup(void) +{ + qemu_mutex_init(&global_mutex); +} + +static void rcu_close_file(RCUCloseFILE *r) { - qemu_mutex_init(&qemu_logfile_mutex); + fclose(r->fd); + g_free(r); } -static void qemu_logfile_free(QemuLogFile *logfile) +/** + * valid_filename_template: + * + * Validate the filename template. Require %d if per_thread, allow it + * otherwise; require no other % within the template. + */ + +typedef enum { + vft_error, + vft_stderr, + vft_strdup, + vft_pid_printf, +} ValidFilenameTemplateResult; + +static ValidFilenameTemplateResult +valid_filename_template(const char *filename, bool per_thread, Error **errp) { - g_assert(logfile); + if (filename) { + char *pidstr = strstr(filename, "%"); - if (logfile->fd != stderr) { - fclose(logfile->fd); + if (pidstr) { + /* We only accept one %d, no other format strings */ + if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) { + error_setg(errp, "Bad logfile template: %s", filename); + return 0; + } + return per_thread ? vft_strdup : vft_pid_printf; + } } - g_free(logfile); + if (per_thread) { + error_setg(errp, "Filename template with '%%d' required for 'tid'"); + return vft_error; + } + return filename ? vft_strdup : vft_stderr; } -static bool log_uses_own_buffers; - /* enable or disable low levels log */ -void qemu_set_log(int log_flags) +static bool qemu_set_log_internal(const char *filename, bool changed_name, + int log_flags, Error **errp) { - bool need_to_open_file = false; - QemuLogFile *logfile; + bool need_to_open_file; + bool daemonized; + bool per_thread; + FILE *logfile; - qemu_loglevel = log_flags; + QEMU_LOCK_GUARD(&global_mutex); + logfile = global_file; + + /* The per-thread flag is immutable. */ + if (log_per_thread) { + log_flags |= LOG_PER_THREAD; + } else { + if (global_filename) { + log_flags &= ~LOG_PER_THREAD; + } + } + + per_thread = log_flags & LOG_PER_THREAD; + + if (changed_name) { + char *newname = NULL; + + /* + * Once threads start opening their own log files, we have no + * easy mechanism to tell them all to close and re-open. + * There seems little cause to do so either -- this option + * will most often be used at user-only startup. + */ + if (log_per_thread) { + error_setg(errp, "Cannot change log filename after setting 'tid'"); + return false; + } + + switch (valid_filename_template(filename, per_thread, errp)) { + case vft_error: + return false; + case vft_stderr: + break; + case vft_strdup: + newname = g_strdup(filename); + break; + case vft_pid_printf: + newname = g_strdup_printf(filename, getpid()); + break; + } + + g_free(global_filename); + global_filename = newname; + filename = newname; + } else { + filename = global_filename; + if (per_thread && + valid_filename_template(filename, true, errp) == vft_error) { + return false; + } + } + + /* Once the per-thread flag is set, it cannot be unset. */ + if (per_thread) { + log_per_thread = true; + } + /* The flag itself is not relevant for need_to_open_file. */ + log_flags &= ~LOG_PER_THREAD; #ifdef CONFIG_TRACE_LOG - qemu_loglevel |= LOG_TRACE; + log_flags |= LOG_TRACE; #endif - /* - * In all cases we only log if qemu_loglevel is set. - * Also: - * If not daemonized we will always log either to stderr - * or to a file (if there is a logfilename). - * If we are daemonized, - * we will only log if there is a logfilename. - */ - if (qemu_loglevel && (!is_daemonized() || logfilename)) { - need_to_open_file = true; + qemu_loglevel = log_flags; + + daemonized = is_daemonized(); + need_to_open_file = false; + if (!daemonized) { + /* + * If not daemonized we only log if qemu_loglevel is set, either to + * stderr or to a file (if there is a filename). + * If per-thread, open the file for each thread in qemu_log_trylock(). + */ + need_to_open_file = qemu_loglevel && !log_per_thread; + } else { + /* + * If we are daemonized, we will only log if there is a filename. + */ + need_to_open_file = filename != NULL; + } + + if (logfile) { + fflush(logfile); + if (changed_name && logfile != stderr) { + RCUCloseFILE *r = g_new0(RCUCloseFILE, 1); + r->fd = logfile; + qatomic_rcu_set(&global_file, NULL); + call_rcu(r, rcu_close_file, rcu); + logfile = NULL; + } } - QEMU_LOCK_GUARD(&qemu_logfile_mutex); - if (qemu_logfile && !need_to_open_file) { - logfile = qemu_logfile; - qatomic_rcu_set(&qemu_logfile, NULL); - call_rcu(logfile, qemu_logfile_free, rcu); - } else if (!qemu_logfile && need_to_open_file) { - logfile = g_new0(QemuLogFile, 1); - if (logfilename) { - logfile->fd = fopen(logfilename, log_append ? "a" : "w"); - if (!logfile->fd) { - g_free(logfile); - perror(logfilename); - _exit(1); + + if (log_per_thread && daemonized) { + logfile = thread_file; + } + + if (!logfile && need_to_open_file) { + if (filename) { + if (log_per_thread) { + logfile = qemu_log_trylock_with_err(errp); + if (!logfile) { + return false; + } + qemu_log_unlock(logfile); + } else { + logfile = fopen(filename, "w"); + if (!logfile) { + error_setg_errno(errp, errno, "Error opening logfile %s", + filename); + return false; + } } /* In case we are a daemon redirect stderr to logfile */ - if (is_daemonized()) { - dup2(fileno(logfile->fd), STDERR_FILENO); - fclose(logfile->fd); - /* This will skip closing logfile in qemu_log_close() */ - logfile->fd = stderr; + if (daemonized) { + dup2(fileno(logfile), STDERR_FILENO); + fclose(logfile); + /* + * This will skip closing logfile in rcu_close_file() + * or qemu_log_thread_cleanup(). + */ + logfile = stderr; } } else { /* Default to stderr if no log file specified */ - assert(!is_daemonized()); - logfile->fd = stderr; + assert(!daemonized); + logfile = stderr; } - /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ - if (log_uses_own_buffers) { - static char logfile_buf[4096]; - setvbuf(logfile->fd, logfile_buf, _IOLBF, sizeof(logfile_buf)); + if (log_per_thread && daemonized) { + thread_file = logfile; } else { -#if defined(_WIN32) - /* Win32 doesn't support line-buffering, so use unbuffered output. */ - setvbuf(logfile->fd, NULL, _IONBF, 0); -#else - setvbuf(logfile->fd, NULL, _IOLBF, 0); -#endif - log_append = 1; + qatomic_rcu_set(&global_file, logfile); } - qatomic_rcu_set(&qemu_logfile, logfile); } + return true; } -void qemu_log_needs_buffers(void) +bool qemu_set_log(int log_flags, Error **errp) { - log_uses_own_buffers = true; + return qemu_set_log_internal(NULL, false, log_flags, errp); } -/* - * Allow the user to include %d in their logfile which will be - * substituted with the current PID. This is useful for debugging many - * nested linux-user tasks but will result in lots of logs. - * - * filename may be NULL. In that case, log output is sent to stderr - */ -void qemu_set_log_filename(const char *filename, Error **errp) +bool qemu_set_log_filename(const char *filename, Error **errp) { - g_free(logfilename); - logfilename = NULL; - - if (filename) { - char *pidstr = strstr(filename, "%"); - if (pidstr) { - /* We only accept one %d, no other format strings */ - if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) { - error_setg(errp, "Bad logfile format: %s", filename); - return; - } else { - logfilename = g_strdup_printf(filename, getpid()); - } - } else { - logfilename = g_strdup(filename); - } - } + return qemu_set_log_internal(filename, true, qemu_loglevel, errp); +} - qemu_log_close(); - qemu_set_log(qemu_loglevel); +bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp) +{ + return qemu_set_log_internal(name, true, flags, errp); } /* Returns true if addr is in our debug filter or no filter defined @@ -266,34 +453,6 @@ void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp) g_strfreev(ranges); } -/* fflush() the log file */ -void qemu_log_flush(void) -{ - QemuLogFile *logfile; - - rcu_read_lock(); - logfile = qatomic_rcu_read(&qemu_logfile); - if (logfile) { - fflush(logfile->fd); - } - rcu_read_unlock(); -} - -/* Close the log file */ -void qemu_log_close(void) -{ - QemuLogFile *logfile; - - qemu_mutex_lock(&qemu_logfile_mutex); - logfile = qemu_logfile; - - if (logfile) { - qatomic_rcu_set(&qemu_logfile, NULL); - call_rcu(logfile, qemu_logfile_free, rcu); - } - qemu_mutex_unlock(&qemu_logfile_mutex); -} - const QEMULogItem qemu_log_items[] = { { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, @@ -334,6 +493,8 @@ const QEMULogItem qemu_log_items[] = { #endif { LOG_STRACE, "strace", "log every user-mode syscall, its input, and its result" }, + { LOG_PER_THREAD, "tid", + "open a separate log file per thread; filename must contain '%d'" }, { 0, NULL, NULL }, }; diff --git a/util/main-loop.c b/util/main-loop.c index b7b0ce4ca087..58f776a8c9c8 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -30,9 +30,11 @@ #include "sysemu/replay.h" #include "qemu/main-loop.h" #include "block/aio.h" +#include "block/thread-pool.h" #include "qemu/error-report.h" #include "qemu/queue.h" #include "qemu/compiler.h" +#include "qom/object.h" #ifndef _WIN32 #include @@ -62,9 +64,7 @@ static void sigfd_handler(void *opaque) ssize_t len; while (1) { - do { - len = read(fd, &info, sizeof(info)); - } while (len == -1 && errno == EINTR); + len = RETRY_ON_EINTR(read(fd, &info, sizeof(info))); if (len == -1 && errno == EAGAIN) { break; @@ -114,7 +114,7 @@ static int qemu_signal_init(Error **errp) return -errno; } - fcntl_setfl(sigfd, O_NONBLOCK); + g_unix_set_fd_nonblocking(sigfd, true, NULL); qemu_set_fd_handler(sigfd, sigfd_handler, NULL, (void *)(intptr_t)sigfd); @@ -184,6 +184,69 @@ int qemu_init_main_loop(Error **errp) return 0; } +static void main_loop_update_params(EventLoopBase *base, Error **errp) +{ + ERRP_GUARD(); + + if (!qemu_aio_context) { + error_setg(errp, "qemu aio context not ready"); + return; + } + + aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp); + if (*errp) { + return; + } + + aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min, + base->thread_pool_max, errp); +} + +MainLoop *mloop; + +static void main_loop_init(EventLoopBase *base, Error **errp) +{ + MainLoop *m = MAIN_LOOP(base); + + if (mloop) { + error_setg(errp, "only one main-loop instance allowed"); + return; + } + + main_loop_update_params(base, errp); + + mloop = m; + return; +} + +static bool main_loop_can_be_deleted(EventLoopBase *base) +{ + return false; +} + +static void main_loop_class_init(ObjectClass *oc, void *class_data) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc); + + bc->init = main_loop_init; + bc->update_params = main_loop_update_params; + bc->can_be_deleted = main_loop_can_be_deleted; +} + +static const TypeInfo main_loop_info = { + .name = TYPE_MAIN_LOOP, + .parent = TYPE_EVENT_LOOP_BASE, + .class_init = main_loop_class_init, + .instance_size = sizeof(MainLoop), +}; + +static void main_loop_register_types(void) +{ + type_register_static(&main_loop_info); +} + +type_init(main_loop_register_types) + static int max_priority; #ifndef _WIN32 @@ -298,20 +361,30 @@ void qemu_del_polling_cb(PollingFunc *func, void *opaque) /* Wait objects support */ typedef struct WaitObjects { int num; - int revents[MAXIMUM_WAIT_OBJECTS + 1]; - HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; - WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; - void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; + int revents[MAXIMUM_WAIT_OBJECTS]; + HANDLE events[MAXIMUM_WAIT_OBJECTS]; + WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS]; + void *opaque[MAXIMUM_WAIT_OBJECTS]; } WaitObjects; static WaitObjects wait_objects = {0}; int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) { + int i; WaitObjects *w = &wait_objects; + if (w->num >= MAXIMUM_WAIT_OBJECTS) { return -1; } + + for (i = 0; i < w->num; i++) { + /* check if the same handle is added twice */ + if (w->events[i] == handle) { + return -1; + } + } + w->events[w->num] = handle; w->func[w->num] = func; w->opaque[w->num] = opaque; @@ -330,7 +403,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) if (w->events[i] == handle) { found = 1; } - if (found) { + if (found && i < (MAXIMUM_WAIT_OBJECTS - 1)) { w->events[i] = w->events[i + 1]; w->func[i] = w->func[i + 1]; w->opaque[i] = w->opaque[i + 1]; diff --git a/util/meson.build b/util/meson.build index f6ee74ad0c85..80a8fbbc8d0a 100644 --- a/util/meson.build +++ b/util/meson.build @@ -1,7 +1,9 @@ util_ss.add(files('osdep.c', 'cutils.c', 'unicode.c', 'qemu-timer-common.c')) +util_ss.add(files('thread-context.c'), numa) if not config_host_data.get('CONFIG_ATOMIC64') util_ss.add(files('atomic64.c')) endif +util_ss.add(when: 'CONFIG_LINUX', if_true: files('async-teardown.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('aio-posix.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('fdmon-poll.c')) if config_host_data.get('CONFIG_EPOLL_CREATE1') @@ -11,8 +13,11 @@ util_ss.add(when: linux_io_uring, if_true: files('fdmon-io_uring.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('compatfd.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('event_notifier-posix.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('mmap-alloc.c')) -util_ss.add(when: 'CONFIG_POSIX', if_true: files('oslib-posix.c')) -util_ss.add(when: 'CONFIG_POSIX', if_true: [files('qemu-openpty.c'), util]) +freebsd_dep = [] +if targetos == 'freebsd' + freebsd_dep = util +endif +util_ss.add(when: 'CONFIG_POSIX', if_true: [files('oslib-posix.c'), freebsd_dep]) util_ss.add(when: 'CONFIG_POSIX', if_true: files('qemu-thread-posix.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('memfd.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: files('aio-win32.c')) @@ -20,12 +25,13 @@ util_ss.add(when: 'CONFIG_WIN32', if_true: files('event_notifier-win32.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: files('oslib-win32.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: files('qemu-thread-win32.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: winmm) +util_ss.add(when: 'CONFIG_WIN32', if_true: pathcch) util_ss.add(files('envlist.c', 'path.c', 'module.c')) util_ss.add(files('host-utils.c')) util_ss.add(files('bitmap.c', 'bitops.c')) util_ss.add(files('fifo8.c')) -util_ss.add(files('cacheinfo.c', 'cacheflush.c')) -util_ss.add(files('error.c', 'qemu-error.c')) +util_ss.add(files('cacheflush.c')) +util_ss.add(files('error.c', 'error-report.c')) util_ss.add(files('qemu-print.c')) util_ss.add(files('id.c')) util_ss.add(files('qemu-config.c', 'notify.c')) @@ -39,7 +45,6 @@ if have_membarrier util_ss.add(files('sys_membarrier.c')) endif util_ss.add(files('log.c')) -util_ss.add(files('pagesize.c')) util_ss.add(files('qdist.c')) util_ss.add(files('qht.c')) util_ss.add(files('qsp.c')) @@ -52,6 +57,9 @@ util_ss.add(files('guest-random.c')) util_ss.add(files('yank.c')) util_ss.add(files('int128.c')) util_ss.add(files('memalign.c')) +util_ss.add(files('interval-tree.c')) +util_ss.add(files('lockcnt.c')) +util_ss.add(files('dma_notifier.c')) if have_user util_ss.add(files('selfmap.c')) @@ -59,31 +67,35 @@ endif if have_system util_ss.add(files('crc-ccitt.c')) - util_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus.c'), gio]) + util_ss.add(when: gio, if_true: files('dbus.c')) util_ss.add(when: 'CONFIG_LINUX', if_true: files('userfaultfd.c')) endif -if have_block - util_ss.add(files('aiocb.c', 'async.c', 'aio-wait.c')) +if have_block or have_ga + util_ss.add(files('aiocb.c', 'async.c')) util_ss.add(files('base64.c')) + util_ss.add(files('main-loop.c')) + util_ss.add(files('qemu-coroutine.c', 'qemu-coroutine-lock.c', 'qemu-coroutine-io.c')) + util_ss.add(files('coroutine-@0@.c'.format(config_host['CONFIG_COROUTINE_BACKEND']))) + util_ss.add(files('thread-pool.c', 'qemu-timer.c')) + util_ss.add(files('qemu-sockets.c')) +endif +if have_block + util_ss.add(files('aio-wait.c')) util_ss.add(files('buffer.c')) util_ss.add(files('bufferiszero.c')) - util_ss.add(files('coroutine-@0@.c'.format(config_host['CONFIG_COROUTINE_BACKEND']))) util_ss.add(files('hbitmap.c')) util_ss.add(files('hexdump.c')) util_ss.add(files('iova-tree.c')) - util_ss.add(files('iov.c', 'qemu-sockets.c', 'uri.c')) - util_ss.add(files('lockcnt.c')) - util_ss.add(files('main-loop.c')) + util_ss.add(files('iov.c', 'uri.c')) util_ss.add(files('nvdimm-utils.c')) - util_ss.add(files('qemu-coroutine.c', 'qemu-coroutine-lock.c', 'qemu-coroutine-io.c')) util_ss.add(when: 'CONFIG_LINUX', if_true: [ files('vhost-user-server.c'), vhost_user ]) util_ss.add(files('block-helpers.c')) util_ss.add(files('qemu-coroutine-sleep.c')) util_ss.add(files('qemu-co-shared-resource.c')) - util_ss.add(files('thread-pool.c', 'qemu-timer.c')) + util_ss.add(files('qemu-co-timeout.c')) util_ss.add(files('readline.c')) util_ss.add(files('throttle.c')) util_ss.add(files('timed-average.c')) diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index 893d864354a1..5ed7d29183ec 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -50,38 +50,7 @@ size_t qemu_fd_getpagesize(int fd) #endif #endif - 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; + return qemu_real_host_page_size(); } #define OVERCOMMIT_MEMORY_PATH "/proc/sys/vm/overcommit_memory" @@ -101,7 +70,7 @@ static bool map_noreserve_effective(int fd, uint32_t qemu_map_flags) * MAP_NORESERVE. * b) MAP_NORESERVE is not affected by /proc/sys/vm/overcommit_memory. */ - if (qemu_fd_getpagesize(fd) != qemu_real_host_page_size) { + if (qemu_fd_getpagesize(fd) != qemu_real_host_page_size()) { return true; } @@ -166,7 +135,7 @@ static void *mmap_reserve(size_t size, int fd) * We do this unless we are using the system page size, in which case * anonymous memory is OK. */ - if (fd == -1 || qemu_fd_getpagesize(fd) == qemu_real_host_page_size) { + if (fd == -1 || qemu_fd_getpagesize(fd) == qemu_real_host_page_size()) { fd = -1; flags |= MAP_ANONYMOUS; } else { @@ -243,7 +212,7 @@ static inline size_t mmap_guard_pagesize(int fd) /* Mappings in the same segment must share the same page size */ return qemu_fd_getpagesize(fd); #else - return qemu_real_host_page_size; + return qemu_real_host_page_size(); #endif } diff --git a/util/module.c b/util/module.c index 6bb4ad915a1c..32e263163c75 100644 --- a/util/module.c +++ b/util/module.c @@ -21,6 +21,7 @@ #include "qemu/module.h" #include "qemu/cutils.h" #include "qemu/config-file.h" +#include "qapi/error.h" #ifdef CONFIG_MODULE_UPGRADES #include "qemu-version.h" #endif @@ -144,25 +145,22 @@ static bool module_check_arch(const QemuModinfo *modinfo) return true; } -static int module_load_file(const char *fname, bool mayfail, bool export_symbols) +/* + * module_load_dso: attempt to load an existing dso file + * + * fname: full pathname of the file to load + * export_symbols: if true, add the symbols to the global name space + * errp: error to set. + * + * Return value: true on success, false on error, and errp will be set. + */ +static bool module_load_dso(const char *fname, bool export_symbols, + Error **errp) { GModule *g_module; void (*sym)(void); - const char *dsosuf = CONFIG_HOST_DSOSUF; - int len = strlen(fname); - int suf_len = strlen(dsosuf); ModuleEntry *e, *next; - int ret, flags; - - if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) { - /* wrong suffix */ - ret = -EINVAL; - goto out; - } - if (access(fname, F_OK)) { - ret = -ENOENT; - goto out; - } + int flags; assert(QTAILQ_EMPTY(&dso_init_list)); @@ -172,48 +170,38 @@ static int module_load_file(const char *fname, bool mayfail, bool export_symbols } g_module = g_module_open(fname, flags); if (!g_module) { - if (!mayfail) { - fprintf(stderr, "Failed to open module: %s\n", - g_module_error()); - } - ret = -EINVAL; - goto out; + error_setg(errp, "failed to open module: %s", g_module_error()); + return false; } if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) { - fprintf(stderr, "Failed to initialize module: %s\n", - fname); - /* Print some info if this is a QEMU module (but from different build), - * this will make debugging user problems easier. */ + error_setg(errp, "failed to initialize module: %s", fname); + /* + * Print some info if this is a QEMU module (but from different build), + * this will make debugging user problems easier. + */ if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) { - fprintf(stderr, - "Note: only modules from the same build can be loaded.\n"); + error_append_hint(errp, + "Only modules from the same build can be loaded.\n"); } g_module_close(g_module); - ret = -EINVAL; - } else { - QTAILQ_FOREACH(e, &dso_init_list, node) { - e->init(); - register_module_init(e->init, e->type); - } - ret = 0; + return false; } + QTAILQ_FOREACH(e, &dso_init_list, node) { + e->init(); + register_module_init(e->init, e->type); + } trace_module_load_module(fname); QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) { QTAILQ_REMOVE(&dso_init_list, e, node); g_free(e); } -out: - return ret; + return true; } -#endif -bool module_load_one(const char *prefix, const char *lib_name, bool mayfail) +int module_load(const char *prefix, const char *name, Error **errp) { - bool success = false; - -#ifdef CONFIG_MODULES - char *fname = NULL; + int rv = -1; #ifdef CONFIG_MODULE_UPGRADES char *version_dir; #endif @@ -221,34 +209,52 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail) char *dirs[5]; char *module_name; int i = 0, n_dirs = 0; - int ret; bool export_symbols = false; static GHashTable *loaded_modules; const QemuModinfo *modinfo; const char **sl; if (!g_module_supported()) { - fprintf(stderr, "Module is not supported by system.\n"); - return false; + error_setg(errp, "%s", "this platform does not support GLib modules"); + return -1; } if (!loaded_modules) { loaded_modules = g_hash_table_new(g_str_hash, g_str_equal); } - module_name = g_strdup_printf("%s%s", prefix, lib_name); + /* allocate all resources managed by the out: label here */ + module_name = g_strdup_printf("%s%s", prefix, name); if (g_hash_table_contains(loaded_modules, module_name)) { g_free(module_name); - return true; + return 2; /* module already loaded */ } g_hash_table_add(loaded_modules, module_name); + search_dir = getenv("QEMU_MODULE_DIR"); + if (search_dir != NULL) { + dirs[n_dirs++] = g_strdup_printf("%s", search_dir); + } + dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR); + +#ifdef CONFIG_MODULE_UPGRADES + version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION), + G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~", + '_'); + dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir); +#endif + assert(n_dirs <= ARRAY_SIZE(dirs)); + + /* end of resources managed by the out: label */ + for (modinfo = module_info; modinfo->name != NULL; modinfo++) { if (modinfo->arch) { if (strcmp(modinfo->name, module_name) == 0) { if (!module_check_arch(modinfo)) { - return false; + error_setg(errp, "module arch does not match: " + "expected '%s', got '%s'", module_arch, modinfo->arch); + goto out; } } } @@ -256,7 +262,11 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail) if (strcmp(modinfo->name, module_name) == 0) { /* we depend on other module(s) */ for (sl = modinfo->deps; *sl != NULL; sl++) { - module_load_one("", *sl, false); + int subrv = module_load("", *sl, errp); + if (subrv <= 0) { + rv = subrv; + goto out; + } } } else { for (sl = modinfo->deps; *sl != NULL; sl++) { @@ -269,59 +279,52 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail) } } - search_dir = getenv("QEMU_MODULE_DIR"); - if (search_dir != NULL) { - dirs[n_dirs++] = g_strdup_printf("%s", search_dir); - } - dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR); - dirs[n_dirs++] = g_strdup(qemu_get_exec_dir()); - -#ifdef CONFIG_MODULE_UPGRADES - version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION), - G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~", - '_'); - dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir); -#endif - - assert(n_dirs <= ARRAY_SIZE(dirs)); - for (i = 0; i < n_dirs; i++) { - fname = g_strdup_printf("%s/%s%s", - dirs[i], module_name, CONFIG_HOST_DSOSUF); - ret = module_load_file(fname, mayfail, export_symbols); - g_free(fname); - fname = NULL; - /* Try loading until loaded a module file */ - if (!ret) { - success = true; - break; + char *fname = g_strdup_printf("%s/%s%s", + dirs[i], module_name, CONFIG_HOST_DSOSUF); + int ret = access(fname, F_OK); + if (ret != 0 && (errno == ENOENT || errno == ENOTDIR)) { + /* + * if we don't find the module in this dir, try the next one. + * If we don't find it in any dir, that can be fine too: user + * did not install the module. We will return 0 in this case + * with no error set. + */ + g_free(fname); + continue; + } else if (ret != 0) { + /* most common is EACCES here */ + error_setg_errno(errp, errno, "error trying to access %s", fname); + } else if (module_load_dso(fname, export_symbols, errp)) { + rv = 1; /* module successfully loaded */ } + g_free(fname); + goto out; } + rv = 0; /* module not found */ - if (!success) { +out: + if (rv <= 0) { g_hash_table_remove(loaded_modules, module_name); g_free(module_name); } - for (i = 0; i < n_dirs; i++) { g_free(dirs[i]); } - -#endif - return success; + return rv; } -#ifdef CONFIG_MODULES - static bool module_loaded_qom_all; -void module_load_qom_one(const char *type) +int module_load_qom(const char *type, Error **errp) { const QemuModinfo *modinfo; const char **sl; + int rv = 0; if (!type) { - return; + error_setg(errp, "%s", "type is NULL"); + return -1; } trace_module_lookup_object_type(type); @@ -334,15 +337,24 @@ void module_load_qom_one(const char *type) } for (sl = modinfo->objs; *sl != NULL; sl++) { if (strcmp(type, *sl) == 0) { - module_load_one("", modinfo->name, false); + if (rv > 0) { + error_setg(errp, "multiple modules providing '%s'", type); + return -1; + } + rv = module_load("", modinfo->name, errp); + if (rv < 0) { + return rv; + } } } } + return rv; } void module_load_qom_all(void) { const QemuModinfo *modinfo; + Error *local_err = NULL; if (module_loaded_qom_all) { return; @@ -355,7 +367,9 @@ void module_load_qom_all(void) if (!module_check_arch(modinfo)) { continue; } - module_load_one("", modinfo->name, false); + if (module_load("", modinfo->name, &local_err) < 0) { + error_report_err(local_err); + } } module_loaded_qom_all = true; } @@ -371,7 +385,10 @@ void qemu_load_module_for_opts(const char *group) } for (sl = modinfo->opts; *sl != NULL; sl++) { if (strcmp(group, *sl) == 0) { - module_load_one("", modinfo->name, false); + Error *local_err = NULL; + if (module_load("", modinfo->name, &local_err) < 0) { + error_report_err(local_err); + } } } } @@ -381,7 +398,8 @@ void qemu_load_module_for_opts(const char *group) void module_allow_arch(const char *arch) {} void qemu_load_module_for_opts(const char *group) {} -void module_load_qom_one(const char *type) {} +int module_load(const char *prefix, const char *name, Error **errp) { return 2; } +int module_load_qom(const char *type, Error **errp) { return 2; } void module_load_qom_all(void) {} #endif diff --git a/util/osdep.c b/util/osdep.c index 84575ec21881..e996c4744af1 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/sockets.h" #include "qemu/error-report.h" @@ -32,8 +31,6 @@ #include "qemu/hw-version.h" #include "monitor/monitor.h" -static bool fips_enabled = false; - static const char *hw_version = QEMU_HW_VERSION; int socket_set_cork(int fd, int v) @@ -69,8 +66,8 @@ int qemu_madvise(void *addr, size_t len, int advice) static int qemu_mprotect__osdep(void *addr, size_t size, int prot) { - g_assert(!((uintptr_t)addr & ~qemu_real_host_page_mask)); - g_assert(!(size & ~qemu_real_host_page_mask)); + g_assert(!((uintptr_t)addr & ~qemu_real_host_page_mask())); + g_assert(!(size & ~qemu_real_host_page_mask())); #ifdef _WIN32 DWORD old_protect; @@ -247,9 +244,7 @@ static int qemu_lock_fcntl(int fd, int64_t start, int64_t len, int fl_type) .l_type = fl_type, }; qemu_probe_lock_ops(); - do { - ret = fcntl(fd, fcntl_op_setlk, &fl); - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR(fcntl(fd, fcntl_op_setlk, &fl)); return ret == -1 ? -errno : 0; } @@ -505,40 +500,36 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen) return ret; } -void qemu_set_hw_version(const char *version) +ssize_t qemu_send_full(int s, const void *buf, size_t count) { - hw_version = version; -} - -const char *qemu_hw_version(void) -{ - return hw_version; -} + ssize_t ret = 0; + ssize_t total = 0; -void fips_set_state(bool requested) -{ -#ifdef __linux__ - if (requested) { - FILE *fds = fopen("/proc/sys/crypto/fips_enabled", "r"); - if (fds != NULL) { - fips_enabled = (fgetc(fds) == '1'); - fclose(fds); + while (count) { + ret = send(s, buf, count, 0); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + break; } + + count -= ret; + buf += ret; + total += ret; } -#else - fips_enabled = false; -#endif /* __linux__ */ -#ifdef _FIPS_DEBUG - fprintf(stderr, "FIPS mode %s (requested %s)\n", - (fips_enabled ? "enabled" : "disabled"), - (requested ? "enabled" : "disabled")); -#endif + return total; +} + +void qemu_set_hw_version(const char *version) +{ + hw_version = version; } -bool fips_get_state(void) +const char *qemu_hw_version(void) { - return fips_enabled; + return hw_version; } #ifdef _WIN32 @@ -567,18 +558,22 @@ int socket_init(void) #ifndef CONFIG_IOVEC -/* helper function for iov_send_recv() */ static ssize_t readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write) { unsigned i = 0; ssize_t ret = 0; + ssize_t off = 0; while (i < iov_cnt) { ssize_t r = do_write - ? write(fd, iov[i].iov_base, iov[i].iov_len) - : read(fd, iov[i].iov_base, iov[i].iov_len); + ? write(fd, iov[i].iov_base + off, iov[i].iov_len - off) + : read(fd, iov[i].iov_base + off, iov[i].iov_len - off); if (r > 0) { ret += r; + off += r; + if (off < iov[i].iov_len) { + continue; + } } else if (!r) { break; } else if (errno == EINTR) { @@ -591,6 +586,7 @@ readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write) } break; } + off = 0; i++; } return ret; @@ -608,3 +604,19 @@ writev(int fd, const struct iovec *iov, int iov_cnt) return readv_writev(fd, iov, iov_cnt, true); } #endif + +/* + * Make sure data goes on disk, but if possible do not bother to + * write out the inode just for timestamp updates. + * + * Unfortunately even in 2009 many operating systems do not support + * fdatasync and have to fall back to fsync. + */ +int qemu_fdatasync(int fd) +{ +#ifdef CONFIG_FDATASYNC + return fdatasync(fd); +#else + return fsync(fd); +#endif +} diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 2ebfb7505787..59a891b6a837 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -31,7 +31,6 @@ #include -#include "qemu-common.h" #include "sysemu/sysemu.h" #include "trace.h" #include "qapi/error.h" @@ -43,31 +42,23 @@ #include "qemu/cutils.h" #include "qemu/compiler.h" #include "qemu/units.h" +#include "qemu/thread-context.h" #ifdef CONFIG_LINUX #include #endif #ifdef __FreeBSD__ -#include -#include #include +#include +#include #include #endif #ifdef __NetBSD__ -#include #include #endif -#ifdef __APPLE__ -#include -#endif - -#ifdef __HAIKU__ -#include -#endif - #include "qemu/mmap-alloc.h" #ifdef CONFIG_DEBUG_STACK_USAGE @@ -139,9 +130,8 @@ bool qemu_write_pidfile(const char *path, Error **errp) .l_len = 0, }; - fd = qemu_open_old(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + fd = qemu_create(path, O_WRONLY, S_IRUSR | S_IWUSR, errp); if (fd == -1) { - error_setg_errno(errp, errno, "Cannot open pid file"); return false; } @@ -185,7 +175,7 @@ bool qemu_write_pidfile(const char *path, Error **errp) } snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid()); - if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) { + if (qemu_write_full(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) { error_setg(errp, "Failed to write pid file"); goto fail_unlink; } @@ -226,32 +216,20 @@ void qemu_anon_ram_free(void *ptr, size_t size) qemu_ram_munmap(-1, ptr, size); } -void qemu_set_block(int fd) +void qemu_socket_set_block(int fd) { - int f; - f = fcntl(fd, F_GETFL); - assert(f != -1); - f = fcntl(fd, F_SETFL, f & ~O_NONBLOCK); - assert(f != -1); + g_unix_set_fd_nonblocking(fd, false, NULL); } -int qemu_try_set_nonblock(int fd) +int qemu_socket_try_set_nonblock(int fd) { - int f; - f = fcntl(fd, F_GETFL); - if (f == -1) { - return -errno; - } - if (fcntl(fd, F_SETFL, f | O_NONBLOCK) == -1) { - return -errno; - } - return 0; + return g_unix_set_fd_nonblocking(fd, true, NULL) ? 0 : -errno; } -void qemu_set_nonblock(int fd) +void qemu_socket_set_nonblock(int fd) { int f; - f = qemu_try_set_nonblock(fd); + f = qemu_socket_try_set_nonblock(fd); assert(f == 0); } @@ -276,35 +254,29 @@ void qemu_set_cloexec(int fd) assert(f != -1); } -/* - * Creates a pipe with FD_CLOEXEC set on both file descriptors - */ -int qemu_pipe(int pipefd[2]) +int qemu_socketpair(int domain, int type, int protocol, int sv[2]) { int ret; -#ifdef CONFIG_PIPE2 - ret = pipe2(pipefd, O_CLOEXEC); - if (ret != -1 || errno != ENOSYS) { +#ifdef SOCK_CLOEXEC + ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); + if (ret != -1 || errno != EINVAL) { return ret; } #endif - ret = pipe(pipefd); + ret = socketpair(domain, type, protocol, sv);; if (ret == 0) { - qemu_set_cloexec(pipefd[0]); - qemu_set_cloexec(pipefd[1]); + qemu_set_cloexec(sv[0]); + qemu_set_cloexec(sv[1]); } return ret; } char * -qemu_get_local_state_pathname(const char *relative_pathname) +qemu_get_local_state_dir(void) { - g_autofree char *dir = g_strdup_printf("%s/%s", - CONFIG_QEMU_LOCALSTATEDIR, - relative_pathname); - return get_relocated_path(dir); + return get_relocated_path(CONFIG_QEMU_LOCALSTATEDIR); } void qemu_set_tty_echo(int fd, bool echo) @@ -322,87 +294,6 @@ void qemu_set_tty_echo(int fd, bool echo) tcsetattr(fd, TCSANOW, &tty); } -static const char *exec_dir; - -void qemu_init_exec_dir(const char *argv0) -{ - char *p = NULL; - char buf[PATH_MAX]; - - if (exec_dir) { - return; - } - -#if defined(__linux__) - { - int len; - len = readlink("/proc/self/exe", buf, sizeof(buf) - 1); - if (len > 0) { - buf[len] = 0; - p = buf; - } - } -#elif defined(__FreeBSD__) \ - || (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME)) - { -#if defined(__FreeBSD__) - static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; -#else - static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; -#endif - size_t len = sizeof(buf) - 1; - - *buf = '\0'; - if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) && - *buf) { - buf[sizeof(buf) - 1] = '\0'; - p = buf; - } - } -#elif defined(__APPLE__) - { - char fpath[PATH_MAX]; - uint32_t len = sizeof(fpath); - if (_NSGetExecutablePath(fpath, &len) == 0) { - p = realpath(fpath, buf); - if (!p) { - return; - } - } - } -#elif defined(__HAIKU__) - { - image_info ii; - int32_t c = 0; - - *buf = '\0'; - while (get_next_image_info(0, &c, &ii) == B_OK) { - if (ii.type == B_APP_IMAGE) { - strncpy(buf, ii.name, sizeof(buf)); - buf[sizeof(buf) - 1] = 0; - p = buf; - break; - } - } - } -#endif - /* If we don't have any way of figuring out the actual executable - location then try argv[0]. */ - if (!p && argv0) { - p = realpath(argv0, buf); - } - if (p) { - exec_dir = g_path_get_dirname(p); - } else { - exec_dir = CONFIG_BINDIR; - } -} - -const char *qemu_get_exec_dir(void) -{ - return exec_dir; -} - #ifdef CONFIG_LINUX static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx) #else /* CONFIG_LINUX */ @@ -439,7 +330,7 @@ static void sigbus_handler(int signal) return; } #endif /* CONFIG_LINUX */ - warn_report("os_mem_prealloc: unrelated SIGBUS detected and ignored"); + warn_report("qemu_prealloc_mem: unrelated SIGBUS detected and ignored"); } static void *do_touch_pages(void *arg) @@ -509,13 +400,13 @@ static void *do_madv_populate_write_pages(void *arg) } static inline int get_memset_num_threads(size_t hpagesize, size_t numpages, - int smp_cpus) + int max_threads) { long host_procs = sysconf(_SC_NPROCESSORS_ONLN); int ret = 1; if (host_procs > 0) { - ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), smp_cpus); + ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), max_threads); } /* Especially with gigantic pages, don't create more threads than pages. */ @@ -528,11 +419,12 @@ static inline int get_memset_num_threads(size_t hpagesize, size_t numpages, } static int touch_all_pages(char *area, size_t hpagesize, size_t numpages, - int smp_cpus, bool use_madv_populate_write) + int max_threads, ThreadContext *tc, + bool use_madv_populate_write) { static gsize initialized = 0; MemsetContext context = { - .num_threads = get_memset_num_threads(hpagesize, numpages, smp_cpus), + .num_threads = get_memset_num_threads(hpagesize, numpages, max_threads), }; size_t numpages_per_thread, leftover; void *(*touch_fn)(void *); @@ -567,9 +459,16 @@ static int touch_all_pages(char *area, size_t hpagesize, size_t numpages, context.threads[i].numpages = numpages_per_thread + (i < leftover); context.threads[i].hpagesize = hpagesize; context.threads[i].context = &context; - qemu_thread_create(&context.threads[i].pgthread, "touch_pages", - touch_fn, &context.threads[i], - QEMU_THREAD_JOINABLE); + if (tc) { + thread_context_create_thread(tc, &context.threads[i].pgthread, + "touch_pages", + touch_fn, &context.threads[i], + QEMU_THREAD_JOINABLE); + } else { + qemu_thread_create(&context.threads[i].pgthread, "touch_pages", + touch_fn, &context.threads[i], + QEMU_THREAD_JOINABLE); + } addr += context.threads[i].numpages * hpagesize; } @@ -604,13 +503,13 @@ static bool madv_populate_write_possible(char *area, size_t pagesize) errno != EINVAL; } -void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, - Error **errp) +void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads, + ThreadContext *tc, Error **errp) { static gsize initialized; int ret; size_t hpagesize = qemu_fd_getpagesize(fd); - size_t numpages = DIV_ROUND_UP(memory, hpagesize); + size_t numpages = DIV_ROUND_UP(sz, hpagesize); bool use_madv_populate_write; struct sigaction act; @@ -640,24 +539,24 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, if (ret) { qemu_mutex_unlock(&sigbus_mutex); error_setg_errno(errp, errno, - "os_mem_prealloc: failed to install signal handler"); + "qemu_prealloc_mem: failed to install signal handler"); return; } } /* touch pages simultaneously */ - ret = touch_all_pages(area, hpagesize, numpages, smp_cpus, + ret = touch_all_pages(area, hpagesize, numpages, max_threads, tc, use_madv_populate_write); if (ret) { error_setg_errno(errp, -ret, - "os_mem_prealloc: preallocating memory failed"); + "qemu_prealloc_mem: preallocating memory failed"); } if (!use_madv_populate_write) { ret = sigaction(SIGBUS, &sigbus_oldact, NULL); if (ret) { /* Terminate QEMU since it can't recover from error */ - perror("os_mem_prealloc: failed to reinstall signal handler"); + perror("qemu_prealloc_mem: failed to reinstall signal handler"); exit(1); } qemu_mutex_unlock(&sigbus_mutex); @@ -767,7 +666,7 @@ void *qemu_alloc_stack(size_t *sz) #ifdef CONFIG_DEBUG_STACK_USAGE void *ptr2; #endif - size_t pagesz = qemu_real_host_page_size; + size_t pagesz = qemu_real_host_page_size(); #ifdef _SC_THREAD_STACK_MIN /* avoid stacks smaller than _SC_THREAD_STACK_MIN */ long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN); @@ -829,7 +728,7 @@ void qemu_free_stack(void *stack, size_t sz) unsigned int usage; void *ptr; - for (ptr = stack + qemu_real_host_page_size; ptr < stack + sz; + for (ptr = stack + qemu_real_host_page_size(); ptr < stack + sz; ptr += sizeof(uint32_t)) { if (*(uint32_t *)ptr != 0xdeadbeaf) { break; @@ -887,52 +786,35 @@ void sigaction_invoke(struct sigaction *action, action->sa_sigaction(info->ssi_signo, &si, NULL); } -#ifndef HOST_NAME_MAX -# ifdef _POSIX_HOST_NAME_MAX -# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX -# else -# define HOST_NAME_MAX 255 -# endif -#endif - -char *qemu_get_host_name(Error **errp) -{ - long len = -1; - g_autofree char *hostname = NULL; - -#ifdef _SC_HOST_NAME_MAX - len = sysconf(_SC_HOST_NAME_MAX); -#endif /* _SC_HOST_NAME_MAX */ - - if (len < 0) { - len = HOST_NAME_MAX; - } - - /* Unfortunately, gethostname() below does not guarantee a - * NULL terminated string. Therefore, allocate one byte more - * to be sure. */ - hostname = g_new0(char, len + 1); - - if (gethostname(hostname, len) < 0) { - error_setg_errno(errp, errno, - "cannot get hostname"); - return NULL; - } - - return g_steal_pointer(&hostname); -} - size_t qemu_get_host_physmem(void) { #ifdef _SC_PHYS_PAGES long pages = sysconf(_SC_PHYS_PAGES); if (pages > 0) { - if (pages > SIZE_MAX / qemu_real_host_page_size) { + if (pages > SIZE_MAX / qemu_real_host_page_size()) { return SIZE_MAX; } else { - return pages * qemu_real_host_page_size; + return pages * qemu_real_host_page_size(); } } #endif return 0; } + +int qemu_msync(void *addr, size_t length, int fd) +{ + size_t align_mask = ~(qemu_real_host_page_size() - 1); + + /** + * There are no strict reqs as per the length of mapping + * to be synced. Still the length needs to follow the address + * alignment changes. Additionally - round the size to the multiple + * of PAGE_SIZE + */ + length += ((uintptr_t)addr & (qemu_real_host_page_size() - 1)); + length = (length + ~align_mask) & align_mask; + + addr = (void *)((uintptr_t)addr & align_mask); + + return msync(addr, length, MS_SYNC); +} diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 4b1ce0be4b0e..07ade41800ac 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -24,15 +24,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. - * - * The implementation of g_poll (functions poll_rest, g_poll) at the end of - * this file are based on code from GNOME glib-2 and use a different license, - * see the license comment there. */ #include "qemu/osdep.h" #include -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/main-loop.h" #include "trace.h" @@ -41,9 +36,6 @@ #include "qemu/error-report.h" #include -/* this must come after including "trace.h" */ -#include - static int get_allocation_granularity(void) { SYSTEM_INFO system_info; @@ -185,14 +177,14 @@ static int socket_error(void) } } -void qemu_set_block(int fd) +void qemu_socket_set_block(int fd) { unsigned long opt = 0; WSAEventSelect(fd, NULL, 0); ioctlsocket(fd, FIONBIO, &opt); } -int qemu_try_set_nonblock(int fd) +int qemu_socket_try_set_nonblock(int fd) { unsigned long opt = 1; if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) { @@ -201,9 +193,9 @@ int qemu_try_set_nonblock(int fd) return 0; } -void qemu_set_nonblock(int fd) +void qemu_socket_set_nonblock(int fd) { - (void)qemu_try_set_nonblock(fd); + (void)qemu_socket_try_set_nonblock(fd); } int socket_set_fast_reuse(int fd) @@ -230,46 +222,19 @@ void qemu_set_cloexec(int fd) { } -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000ULL) - -int qemu_gettimeofday(qemu_timeval *tp) -{ - union { - unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - - if(tp) { - GetSystemTimeAsFileTime (&_now.ft); - tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL ); - tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); - } - /* Always return 0 as per Open Group Base Specifications Issue 6. - Do not set errno on error. */ - return 0; -} - int qemu_get_thread_id(void) { return GetCurrentThreadId(); } char * -qemu_get_local_state_pathname(const char *relative_pathname) +qemu_get_local_state_dir(void) { - HRESULT result; - char base_path[MAX_PATH+1] = ""; + const char * const *data_dirs = g_get_system_data_dirs(); - result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, - /* SHGFP_TYPE_CURRENT */ 0, base_path); - if (result != S_OK) { - /* misconfigured environment */ - g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result); - abort(); - } - return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", base_path, - relative_pathname); + g_assert(data_dirs && data_dirs[0]); + + return g_strdup(data_dirs[0]); } void qemu_set_tty_echo(int fd, bool echo) @@ -291,42 +256,6 @@ void qemu_set_tty_echo(int fd, bool echo) } } -static const char *exec_dir; - -void qemu_init_exec_dir(const char *argv0) -{ - - char *p; - char buf[MAX_PATH]; - DWORD len; - - if (exec_dir) { - return; - } - - len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); - if (len == 0) { - return; - } - - buf[len] = 0; - p = buf + len - 1; - while (p != buf && *p != '\\') { - p--; - } - *p = 0; - if (access(buf, R_OK) == 0) { - exec_dir = g_strdup(buf); - } else { - exec_dir = CONFIG_BINDIR; - } -} - -const char *qemu_get_exec_dir(void) -{ - return exec_dir; -} - int getpagesize(void) { SYSTEM_INFO system_info; @@ -335,14 +264,14 @@ int getpagesize(void) return system_info.dwPageSize; } -void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, - Error **errp) +void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads, + ThreadContext *tc, Error **errp) { int i; - size_t pagesize = qemu_real_host_page_size; + size_t pagesize = qemu_real_host_page_size(); - memory = (memory + pagesize - 1) & -pagesize; - for (i = 0; i < memory / pagesize; i++) { + sz = (sz + pagesize - 1) & -pagesize; + for (i = 0; i < sz / pagesize; i++) { memset(area + pagesize * i, 0, 1); } } @@ -594,19 +523,6 @@ bool qemu_write_pidfile(const char *filename, Error **errp) return true; } -char *qemu_get_host_name(Error **errp) -{ - wchar_t tmp[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD size = G_N_ELEMENTS(tmp); - - if (GetComputerNameW(tmp, &size) == 0) { - error_setg_win32(errp, GetLastError(), "failed close handle"); - return NULL; - } - - return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL); -} - size_t qemu_get_host_physmem(void) { MEMORYSTATUSEX statex; @@ -617,3 +533,13 @@ size_t qemu_get_host_physmem(void) } return 0; } + +int qemu_msync(void *addr, size_t length, int fd) +{ + /** + * Perform the sync based on the file descriptor + * The sync range will most probably be wider than the one + * requested - but it will still get the job done + */ + return qemu_fdatasync(fd); +} diff --git a/util/pagesize.c b/util/pagesize.c deleted file mode 100644 index 998632cf6ee6..000000000000 --- a/util/pagesize.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * pagesize.c - query the host about its page size - * - * Copyright (C) 2017, Emilio G. Cota - * License: GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" - -uintptr_t qemu_real_host_page_size; -intptr_t qemu_real_host_page_mask; - -static void __attribute__((constructor)) init_real_host_page_size(void) -{ - qemu_real_host_page_size = getpagesize(); - qemu_real_host_page_mask = -(intptr_t)qemu_real_host_page_size; -} diff --git a/util/qemu-co-timeout.c b/util/qemu-co-timeout.c new file mode 100644 index 000000000000..00cd335649f0 --- /dev/null +++ b/util/qemu-co-timeout.c @@ -0,0 +1,89 @@ +/* + * Helper functionality for distributing a fixed total amount of + * an abstract resource among multiple coroutines. + * + * Copyright (c) 2022 Virtuozzo International GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/coroutine.h" +#include "block/aio.h" + +typedef struct QemuCoTimeoutState { + CoroutineEntry *entry; + void *opaque; + QemuCoSleep sleep_state; + bool marker; + CleanupFunc *clean; +} QemuCoTimeoutState; + +static void coroutine_fn qemu_co_timeout_entry(void *opaque) +{ + QemuCoTimeoutState *s = opaque; + + s->entry(s->opaque); + + if (s->marker) { + assert(!s->sleep_state.to_wake); + /* .marker set by qemu_co_timeout, it have been failed */ + if (s->clean) { + s->clean(s->opaque); + } + g_free(s); + } else { + s->marker = true; + qemu_co_sleep_wake(&s->sleep_state); + } +} + +int coroutine_fn qemu_co_timeout(CoroutineEntry *entry, void *opaque, + uint64_t timeout_ns, CleanupFunc clean) +{ + QemuCoTimeoutState *s; + Coroutine *co; + + if (timeout_ns == 0) { + entry(opaque); + return 0; + } + + s = g_new(QemuCoTimeoutState, 1); + *s = (QemuCoTimeoutState) { + .entry = entry, + .opaque = opaque, + .clean = clean + }; + + co = qemu_coroutine_create(qemu_co_timeout_entry, s); + + aio_co_enter(qemu_get_current_aio_context(), co); + qemu_co_sleep_ns_wakeable(&s->sleep_state, QEMU_CLOCK_REALTIME, timeout_ns); + + if (s->marker) { + /* .marker set by qemu_co_timeout_entry, success */ + g_free(s); + return 0; + } + + /* Don't free s, as we can't cancel qemu_co_timeout_entry execution */ + s->marker = true; + return -ETIMEDOUT; +} diff --git a/util/qemu-config.c b/util/qemu-config.c index 436ab63b1694..d63f27438dc4 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -8,6 +8,7 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/config-file.h" +#include "hw/boards.h" static QemuOptsList *vm_config_groups[48]; static QemuOptsList *drive_config_groups[5]; @@ -80,14 +81,8 @@ static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc) break; } - if (desc[i].help) { - info->has_help = true; - info->help = g_strdup(desc[i].help); - } - if (desc[i].def_value_str) { - info->has_q_default = true; - info->q_default = g_strdup(desc[i].def_value_str); - } + info->help = g_strdup(desc[i].help); + info->q_default = g_strdup(desc[i].def_value_str); QAPI_LIST_PREPEND(param_list, info); } @@ -149,100 +144,82 @@ static CommandLineParameterInfoList *get_drive_infolist(void) return head; } -/* restore machine options that are now machine's properties */ -static QemuOptsList machine_opts = { - .merge_lists = true, - .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head), - .desc = { - { - .name = "type", - .type = QEMU_OPT_STRING, - .help = "emulated machine" - },{ - .name = "accel", - .type = QEMU_OPT_STRING, - .help = "accelerator list", - },{ - .name = "kernel_irqchip", - .type = QEMU_OPT_BOOL, - .help = "use KVM in-kernel irqchip", - },{ - .name = "kvm_shadow_mem", - .type = QEMU_OPT_SIZE, - .help = "KVM shadow MMU size", - },{ - .name = "kernel", - .type = QEMU_OPT_STRING, - .help = "Linux kernel image file", - },{ - .name = "initrd", - .type = QEMU_OPT_STRING, - .help = "Linux initial ramdisk file", - },{ - .name = "append", - .type = QEMU_OPT_STRING, - .help = "Linux kernel command line", - },{ - .name = "dtb", - .type = QEMU_OPT_STRING, - .help = "Linux kernel device tree file", - },{ - .name = "dumpdtb", - .type = QEMU_OPT_STRING, - .help = "Dump current dtb to a file and quit", - },{ - .name = "phandle_start", - .type = QEMU_OPT_NUMBER, - .help = "The first phandle ID we may generate dynamically", - },{ - .name = "dt_compatible", - .type = QEMU_OPT_STRING, - .help = "Overrides the \"compatible\" property of the dt root node", - },{ - .name = "dump-guest-core", - .type = QEMU_OPT_BOOL, - .help = "Include guest memory in a core dump", - },{ - .name = "mem-merge", - .type = QEMU_OPT_BOOL, - .help = "enable/disable memory merge support", - },{ - .name = "usb", - .type = QEMU_OPT_BOOL, - .help = "Set on/off to enable/disable usb", - },{ - .name = "firmware", - .type = QEMU_OPT_STRING, - .help = "firmware image", - },{ - .name = "iommu", - .type = QEMU_OPT_BOOL, - .help = "Set on/off to enable/disable Intel IOMMU (VT-d)", - },{ - .name = "suppress-vmdesc", - .type = QEMU_OPT_BOOL, - .help = "Set on to disable self-describing migration", - },{ - .name = "aes-key-wrap", - .type = QEMU_OPT_BOOL, - .help = "enable/disable AES key wrapping using the CPACF wrapping key", - },{ - .name = "dea-key-wrap", - .type = QEMU_OPT_BOOL, - .help = "enable/disable DEA key wrapping using the CPACF wrapping key", - },{ - .name = "loadparm", - .type = QEMU_OPT_STRING, - .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", - }, - { /* End of list */ } +static CommandLineParameterInfo *objprop_to_cmdline_prop(ObjectProperty *prop) +{ + CommandLineParameterInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(prop->name); + + if (g_str_equal(prop->type, "bool") || g_str_equal(prop->type, "OnOffAuto")) { + info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; + } else if (g_str_equal(prop->type, "int")) { + info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; + } else if (g_str_equal(prop->type, "size")) { + info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; + } else { + info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; } -}; -CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, - const char *option, + if (prop->description) { + info->help = g_strdup(prop->description); + } + + return info; +} + +static CommandLineParameterInfoList *query_all_machine_properties(void) +{ + CommandLineParameterInfoList *params = NULL, *clpiter; + CommandLineParameterInfo *info; + GSList *machines, *curr_mach; + ObjectPropertyIterator op_iter; + ObjectProperty *prop; + bool is_new; + + machines = object_class_get_list(TYPE_MACHINE, false); + assert(machines); + + /* Loop over all machine classes */ + for (curr_mach = machines; curr_mach; curr_mach = curr_mach->next) { + object_class_property_iter_init(&op_iter, curr_mach->data); + /* ... and over the properties of each machine: */ + while ((prop = object_property_iter_next(&op_iter))) { + if (!prop->set) { + continue; + } + /* + * Check whether the property has already been put into the list + * (via another machine class) + */ + is_new = true; + for (clpiter = params; clpiter != NULL; clpiter = clpiter->next) { + if (g_str_equal(clpiter->value->name, prop->name)) { + is_new = false; + break; + } + } + /* If it hasn't been added before, add it now to the list */ + if (is_new) { + info = objprop_to_cmdline_prop(prop); + QAPI_LIST_PREPEND(params, info); + } + } + } + + g_slist_free(machines); + + /* Add entry for the "type" parameter */ + info = g_malloc0(sizeof(*info)); + info->name = g_strdup("type"); + info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; + info->help = g_strdup("machine type"); + QAPI_LIST_PREPEND(params, info); + + return params; +} + +CommandLineOptionInfoList *qmp_query_command_line_options(const char *option, Error **errp) { CommandLineOptionInfoList *conf_list = NULL; @@ -250,7 +227,7 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, int i; for (i = 0; vm_config_groups[i] != NULL; i++) { - if (!has_option || !strcmp(option, vm_config_groups[i]->name)) { + if (!option || !strcmp(option, vm_config_groups[i]->name)) { info = g_malloc0(sizeof(*info)); info->option = g_strdup(vm_config_groups[i]->name); if (!strcmp("drive", vm_config_groups[i]->name)) { @@ -263,10 +240,10 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, } } - if (!has_option || !strcmp(option, "machine")) { + if (!option || !strcmp(option, "machine")) { info = g_malloc0(sizeof(*info)); info->option = g_strdup("machine"); - info->parameters = query_option_descs(machine_opts.desc); + info->parameters = query_all_machine_properties(); QAPI_LIST_PREPEND(conf_list, info); } @@ -314,55 +291,13 @@ void qemu_add_opts(QemuOptsList *list) abort(); } -struct ConfigWriteData { - QemuOptsList *list; - FILE *fp; -}; - -static int config_write_opt(void *opaque, const char *name, const char *value, - Error **errp) -{ - struct ConfigWriteData *data = opaque; - - fprintf(data->fp, " %s = \"%s\"\n", name, value); - return 0; -} - -static int config_write_opts(void *opaque, QemuOpts *opts, Error **errp) -{ - struct ConfigWriteData *data = opaque; - const char *id = qemu_opts_id(opts); - - if (id) { - fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id); - } else { - fprintf(data->fp, "[%s]\n", data->list->name); - } - qemu_opt_foreach(opts, config_write_opt, data, NULL); - fprintf(data->fp, "\n"); - return 0; -} - -void qemu_config_write(FILE *fp) -{ - struct ConfigWriteData data = { .fp = fp }; - QemuOptsList **lists = vm_config_groups; - int i; - - fprintf(fp, "# qemu config file\n\n"); - for (i = 0; lists[i] != NULL; i++) { - data.list = lists[i]; - qemu_opts_foreach(data.list, config_write_opts, &data, NULL); - } -} - /* Returns number of config groups on success, -errno on error */ static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, const char *fname, Error **errp) { + ERRP_GUARD(); char line[1024], prev_group[64], group[64], arg[64], value[1024]; Location loc; - Error *local_err = NULL; QDict *qdict = NULL; int res = -EINVAL, lno = 0; int count = 0; @@ -390,10 +325,9 @@ static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, } if (qdict != prev) { if (prev) { - cb(prev_group, prev, opaque, &local_err); + cb(prev_group, prev, opaque, errp); qobject_unref(prev); - if (local_err) { - error_propagate(errp, local_err); + if (*errp) { goto out; } } @@ -465,12 +399,12 @@ int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp) return ret; } -static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, +static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts, Error **errp) { QemuOpts *subopts; - QDict *subqdict; - QList *list = NULL; + g_autoptr(QDict) subqdict = NULL; + g_autoptr(QList) list = NULL; size_t orig_size, enum_size; char *prefix; @@ -479,23 +413,23 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, g_free(prefix); orig_size = qdict_size(subqdict); if (!orig_size) { - goto out; + return true; } subopts = qemu_opts_create(opts, NULL, 0, errp); if (!subopts) { - goto out; + return false; } if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) { - goto out; + return false; } enum_size = qdict_size(subqdict); if (enum_size < orig_size && enum_size) { error_setg(errp, "Unknown option '%s' for [%s]", qdict_first(subqdict)->key, opts->name); - goto out; + return false; } if (enum_size) { @@ -510,7 +444,7 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, if (qdict_size(subqdict)) { error_setg(errp, "Unused option '%s' for [%s]", qdict_first(subqdict)->key, opts->name); - goto out; + return false; } QLIST_FOREACH_ENTRY(list, list_entry) { @@ -520,46 +454,43 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, if (!section) { error_setg(errp, "[%s] section (index %u) does not consist of " "keys", opts->name, i); - goto out; + return false; } opt_name = g_strdup_printf("%s.%u", opts->name, i++); subopts = qemu_opts_create(opts, opt_name, 1, errp); g_free(opt_name); if (!subopts) { - goto out; + return false; } if (!qemu_opts_absorb_qdict(subopts, section, errp)) { qemu_opts_del(subopts); - goto out; + return false; } if (qdict_size(section)) { error_setg(errp, "[%s] section doesn't support the option '%s'", opts->name, qdict_first(section)->key); qemu_opts_del(subopts); - goto out; + return false; } } } -out: - qobject_unref(subqdict); - qobject_unref(list); + return true; } -void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, +bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, Error **errp) { int i; - Error *local_err = NULL; for (i = 0; lists[i]; i++) { - config_parse_qdict_section(options, lists[i], &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (!config_parse_qdict_section(options, lists[i], errp)) { + return false; } } + + return true; } diff --git a/util/qemu-coroutine-io.c b/util/qemu-coroutine-io.c index 7f5839cb769e..d791932d63b9 100644 --- a/util/qemu-coroutine-io.c +++ b/util/qemu-coroutine-io.c @@ -23,7 +23,6 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/sockets.h" #include "qemu/coroutine.h" #include "qemu/iov.h" diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 26694038397c..45c6b57374b4 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -39,10 +39,15 @@ void qemu_co_queue_init(CoQueue *queue) QSIMPLEQ_INIT(&queue->entries); } -void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock) +void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock, + CoQueueWaitFlags flags) { Coroutine *self = qemu_coroutine_self(); - QSIMPLEQ_INSERT_TAIL(&queue->entries, self, co_queue_next); + if (flags & CO_QUEUE_WAIT_FRONT) { + QSIMPLEQ_INSERT_HEAD(&queue->entries, self, co_queue_next); + } else { + QSIMPLEQ_INSERT_TAIL(&queue->entries, self, co_queue_next); + } if (lock) { qemu_lockable_unlock(lock); @@ -67,34 +72,6 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock) } } -static bool qemu_co_queue_do_restart(CoQueue *queue, bool single) -{ - Coroutine *next; - - if (QSIMPLEQ_EMPTY(&queue->entries)) { - return false; - } - - while ((next = QSIMPLEQ_FIRST(&queue->entries)) != NULL) { - QSIMPLEQ_REMOVE_HEAD(&queue->entries, co_queue_next); - aio_co_wake(next); - if (single) { - break; - } - } - return true; -} - -bool qemu_co_queue_next(CoQueue *queue) -{ - return qemu_co_queue_do_restart(queue, true); -} - -void qemu_co_queue_restart_all(CoQueue *queue) -{ - qemu_co_queue_do_restart(queue, false); -} - bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock) { Coroutine *next; @@ -115,6 +92,25 @@ bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock) return true; } +bool coroutine_fn qemu_co_queue_next(CoQueue *queue) +{ + /* No unlock/lock needed in coroutine context. */ + return qemu_co_enter_next_impl(queue, NULL); +} + +void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock) +{ + while (qemu_co_enter_next_impl(queue, lock)) { + /* just loop */ + } +} + +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue) +{ + /* No unlock/lock needed in coroutine context. */ + qemu_co_enter_all_impl(queue, NULL); +} + bool qemu_co_queue_empty(CoQueue *queue) { return QSIMPLEQ_FIRST(&queue->entries) == NULL; @@ -144,7 +140,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); @@ -341,7 +337,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; @@ -374,7 +370,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(); @@ -399,7 +395,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(); @@ -417,7 +413,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); @@ -427,7 +423,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(); @@ -447,7 +443,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 c03b2422ff68..356b746f0b2f 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -18,28 +18,38 @@ #include "qemu/atomic.h" #include "qemu/coroutine.h" #include "qemu/coroutine_int.h" +#include "qemu/coroutine-tls.h" #include "block/aio.h" -/** Initial batch size is 64, and is increased on demand */ +/** + * The minimal batch size is always 64, coroutines from the release_pool are + * reused as soon as there are 64 coroutines in it. The maximum pool size starts + * with 64 and is increased on demand so that coroutines are not deleted even if + * they are not immediately reused. + */ enum { - POOL_INITIAL_BATCH_SIZE = 64, + POOL_MIN_BATCH_SIZE = 64, + POOL_INITIAL_MAX_SIZE = 64, }; /** Free list to speed up creation */ static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool); -static unsigned int pool_batch_size = POOL_INITIAL_BATCH_SIZE; +static unsigned int pool_max_size = POOL_INITIAL_MAX_SIZE; static unsigned int release_pool_size; -static __thread QSLIST_HEAD(, Coroutine) alloc_pool = QSLIST_HEAD_INITIALIZER(pool); -static __thread unsigned int alloc_pool_size; -static __thread Notifier coroutine_pool_cleanup_notifier; + +typedef QSLIST_HEAD(, Coroutine) CoroutineQSList; +QEMU_DEFINE_STATIC_CO_TLS(CoroutineQSList, alloc_pool); +QEMU_DEFINE_STATIC_CO_TLS(unsigned int, alloc_pool_size); +QEMU_DEFINE_STATIC_CO_TLS(Notifier, coroutine_pool_cleanup_notifier); static void coroutine_pool_cleanup(Notifier *n, void *value) { Coroutine *co; Coroutine *tmp; + CoroutineQSList *alloc_pool = get_ptr_alloc_pool(); - QSLIST_FOREACH_SAFE(co, &alloc_pool, pool_next, tmp) { - QSLIST_REMOVE_HEAD(&alloc_pool, pool_next); + QSLIST_FOREACH_SAFE(co, alloc_pool, pool_next, tmp) { + QSLIST_REMOVE_HEAD(alloc_pool, pool_next); qemu_coroutine_delete(co); } } @@ -49,27 +59,30 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) Coroutine *co = NULL; if (CONFIG_COROUTINE_POOL) { - co = QSLIST_FIRST(&alloc_pool); + CoroutineQSList *alloc_pool = get_ptr_alloc_pool(); + + co = QSLIST_FIRST(alloc_pool); if (!co) { - if (release_pool_size > qatomic_read(&pool_batch_size)) { + if (release_pool_size > POOL_MIN_BATCH_SIZE) { /* Slow path; a good place to register the destructor, too. */ - if (!coroutine_pool_cleanup_notifier.notify) { - coroutine_pool_cleanup_notifier.notify = coroutine_pool_cleanup; - qemu_thread_atexit_add(&coroutine_pool_cleanup_notifier); + Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier(); + if (!notifier->notify) { + notifier->notify = coroutine_pool_cleanup; + qemu_thread_atexit_add(notifier); } /* This is not exact; there could be a little skew between * release_pool_size and the actual size of release_pool. But * it is just a heuristic, it does not need to be perfect. */ - alloc_pool_size = qatomic_xchg(&release_pool_size, 0); - QSLIST_MOVE_ATOMIC(&alloc_pool, &release_pool); - co = QSLIST_FIRST(&alloc_pool); + set_alloc_pool_size(qatomic_xchg(&release_pool_size, 0)); + QSLIST_MOVE_ATOMIC(alloc_pool, &release_pool); + co = QSLIST_FIRST(alloc_pool); } } if (co) { - QSLIST_REMOVE_HEAD(&alloc_pool, pool_next); - alloc_pool_size--; + QSLIST_REMOVE_HEAD(alloc_pool, pool_next); + set_alloc_pool_size(get_alloc_pool_size() - 1); } } @@ -88,14 +101,14 @@ static void coroutine_delete(Coroutine *co) co->caller = NULL; if (CONFIG_COROUTINE_POOL) { - if (release_pool_size < qatomic_read(&pool_batch_size) * 2) { + if (release_pool_size < qatomic_read(&pool_max_size) * 2) { QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next); qatomic_inc(&release_pool_size); return; } - if (alloc_pool_size < qatomic_read(&pool_batch_size)) { - QSLIST_INSERT_HEAD(&alloc_pool, co, pool_next); - alloc_pool_size++; + if (get_alloc_pool_size() < qatomic_read(&pool_max_size)) { + QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next); + set_alloc_pool_size(get_alloc_pool_size() + 1); return; } } @@ -200,17 +213,17 @@ 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; } -void qemu_coroutine_increase_pool_batch_size(unsigned int additional_pool_size) +void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size) { - qatomic_add(&pool_batch_size, additional_pool_size); + qatomic_add(&pool_max_size, additional_pool_size); } -void qemu_coroutine_decrease_pool_batch_size(unsigned int removing_pool_size) +void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size) { - qatomic_sub(&pool_batch_size, removing_pool_size); + qatomic_sub(&pool_max_size, removing_pool_size); } diff --git a/util/qemu-error.c b/util/qemu-error.c deleted file mode 100644 index 7769aee8e791..000000000000 --- a/util/qemu-error.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Error reporting - * - * Copyright (C) 2010 Red Hat Inc. - * - * Authors: - * Markus Armbruster , - * - * 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 "monitor/monitor.h" -#include "qemu/error-report.h" - -/* - * @report_type is the type of message: error, warning or - * informational. - */ -typedef enum { - REPORT_TYPE_ERROR, - REPORT_TYPE_WARNING, - REPORT_TYPE_INFO, -} report_type; - -/* Prepend timestamp to messages */ -bool message_with_timestamp; -bool error_with_guestname; -const char *error_guest_name; - -int error_printf(const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = error_vprintf(fmt, ap); - va_end(ap); - return ret; -} - -int error_printf_unless_qmp(const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = error_vprintf_unless_qmp(fmt, ap); - va_end(ap); - return ret; -} - -static Location std_loc = { - .kind = LOC_NONE -}; -static Location *cur_loc = &std_loc; - -/* - * Push location saved in LOC onto the location stack, return it. - * The top of that stack is the current location. - * Needs a matching loc_pop(). - */ -Location *loc_push_restore(Location *loc) -{ - assert(!loc->prev); - loc->prev = cur_loc; - cur_loc = loc; - return loc; -} - -/* - * Initialize *LOC to "nowhere", push it onto the location stack. - * The top of that stack is the current location. - * Needs a matching loc_pop(). - * Return LOC. - */ -Location *loc_push_none(Location *loc) -{ - loc->kind = LOC_NONE; - loc->prev = NULL; - return loc_push_restore(loc); -} - -/* - * Pop the location stack. - * LOC must be the current location, i.e. the top of the stack. - */ -Location *loc_pop(Location *loc) -{ - assert(cur_loc == loc && loc->prev); - cur_loc = loc->prev; - loc->prev = NULL; - return loc; -} - -/* - * Save the current location in LOC, return LOC. - */ -Location *loc_save(Location *loc) -{ - *loc = *cur_loc; - loc->prev = NULL; - return loc; -} - -/* - * Change the current location to the one saved in LOC. - */ -void loc_restore(Location *loc) -{ - Location *prev = cur_loc->prev; - assert(!loc->prev); - *cur_loc = *loc; - cur_loc->prev = prev; -} - -/* - * Change the current location to "nowhere in particular". - */ -void loc_set_none(void) -{ - cur_loc->kind = LOC_NONE; -} - -/* - * Change the current location to argument ARGV[IDX..IDX+CNT-1]. - */ -void loc_set_cmdline(char **argv, int idx, int cnt) -{ - cur_loc->kind = LOC_CMDLINE; - cur_loc->num = cnt; - cur_loc->ptr = argv + idx; -} - -/* - * Change the current location to file FNAME, line LNO. - */ -void loc_set_file(const char *fname, int lno) -{ - assert (fname || cur_loc->kind == LOC_FILE); - cur_loc->kind = LOC_FILE; - cur_loc->num = lno; - if (fname) { - cur_loc->ptr = fname; - } -} - -/* - * Print current location to current monitor if we have one, else to stderr. - */ -static void print_loc(void) -{ - const char *sep = ""; - int i; - const char *const *argp; - - if (!monitor_cur() && g_get_prgname()) { - fprintf(stderr, "%s:", g_get_prgname()); - sep = " "; - } - switch (cur_loc->kind) { - case LOC_CMDLINE: - argp = cur_loc->ptr; - for (i = 0; i < cur_loc->num; i++) { - error_printf("%s%s", sep, argp[i]); - sep = " "; - } - error_printf(": "); - break; - case LOC_FILE: - error_printf("%s:", (const char *)cur_loc->ptr); - if (cur_loc->num) { - error_printf("%d:", cur_loc->num); - } - error_printf(" "); - break; - default: - error_printf("%s", sep); - } -} - -/* - * Print a message to current monitor if we have one, else to stderr. - * @report_type is the type of message: error, warning or informational. - * Format arguments like vsprintf(). The resulting message should be - * a single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - */ -static void vreport(report_type type, const char *fmt, va_list ap) -{ - GTimeVal tv; - gchar *timestr; - - if (message_with_timestamp && !monitor_cur()) { - g_get_current_time(&tv); - timestr = g_time_val_to_iso8601(&tv); - error_printf("%s ", timestr); - g_free(timestr); - } - - /* Only prepend guest name if -msg guest-name and -name guest=... are set */ - if (error_with_guestname && error_guest_name && !monitor_cur()) { - error_printf("%s ", error_guest_name); - } - - print_loc(); - - switch (type) { - case REPORT_TYPE_ERROR: - break; - case REPORT_TYPE_WARNING: - error_printf("warning: "); - break; - case REPORT_TYPE_INFO: - error_printf("info: "); - break; - } - - error_vprintf(fmt, ap); - error_printf("\n"); -} - -/* - * Print an error message to current monitor if we have one, else to stderr. - * Format arguments like vsprintf(). The resulting message should be - * a single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. - */ -void error_vreport(const char *fmt, va_list ap) -{ - vreport(REPORT_TYPE_ERROR, fmt, ap); -} - -/* - * Print a warning message to current monitor if we have one, else to stderr. - * Format arguments like vsprintf(). The resulting message should be - * a single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - */ -void warn_vreport(const char *fmt, va_list ap) -{ - vreport(REPORT_TYPE_WARNING, fmt, ap); -} - -/* - * Print an information message to current monitor if we have one, else to - * stderr. - * Format arguments like vsprintf(). The resulting message should be - * a single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - */ -void info_vreport(const char *fmt, va_list ap) -{ - vreport(REPORT_TYPE_INFO, fmt, ap); -} - -/* - * Print an error message to current monitor if we have one, else to stderr. - * Format arguments like sprintf(). The resulting message should be - * a single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. - */ -void error_report(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vreport(REPORT_TYPE_ERROR, fmt, ap); - va_end(ap); -} - -/* - * Print a warning message to current monitor if we have one, else to stderr. - * Format arguments like sprintf(). The resulting message should be a - * single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - */ -void warn_report(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vreport(REPORT_TYPE_WARNING, fmt, ap); - va_end(ap); -} - -/* - * Print an information message to current monitor if we have one, else to - * stderr. - * Format arguments like sprintf(). The resulting message should be a - * single phrase, with no newline or trailing punctuation. - * Prepend the current location and append a newline. - */ -void info_report(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vreport(REPORT_TYPE_INFO, fmt, ap); - va_end(ap); -} - -/* - * Like error_report(), except print just once. - * If *printed is false, print the message, and flip *printed to true. - * Return whether the message was printed. - */ -bool error_report_once_cond(bool *printed, const char *fmt, ...) -{ - va_list ap; - - assert(printed); - if (*printed) { - return false; - } - *printed = true; - va_start(ap, fmt); - vreport(REPORT_TYPE_ERROR, fmt, ap); - va_end(ap); - return true; -} - -/* - * Like warn_report(), except print just once. - * If *printed is false, print the message, and flip *printed to true. - * Return whether the message was printed. - */ -bool warn_report_once_cond(bool *printed, const char *fmt, ...) -{ - va_list ap; - - assert(printed); - if (*printed) { - return false; - } - *printed = true; - va_start(ap, fmt); - vreport(REPORT_TYPE_WARNING, fmt, ap); - va_end(ap); - return true; -} - -static char *qemu_glog_domains; - -static void qemu_log_func(const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data) -{ - switch (log_level & G_LOG_LEVEL_MASK) { - case G_LOG_LEVEL_DEBUG: - case G_LOG_LEVEL_INFO: - /* - * Use same G_MESSAGES_DEBUG logic as glib to enable/disable debug - * messages - */ - if (qemu_glog_domains == NULL) { - break; - } - if (strcmp(qemu_glog_domains, "all") != 0 && - (log_domain == NULL || !strstr(qemu_glog_domains, log_domain))) { - break; - } - /* Fall through */ - case G_LOG_LEVEL_MESSAGE: - info_report("%s%s%s", - log_domain ?: "", log_domain ? ": " : "", message); - - break; - case G_LOG_LEVEL_WARNING: - warn_report("%s%s%s", - log_domain ?: "", log_domain ? ": " : "", message); - break; - case G_LOG_LEVEL_CRITICAL: - case G_LOG_LEVEL_ERROR: - error_report("%s%s%s", - log_domain ?: "", log_domain ? ": " : "", message); - break; - } -} - -void error_init(const char *argv0) -{ - const char *p = strrchr(argv0, '/'); - - /* Set the program name for error_print_loc(). */ - g_set_prgname(p ? p + 1 : argv0); - - /* - * This sets up glib logging so libraries using it also print their logs - * through error_report(), warn_report(), info_report(). - */ - g_log_set_default_handler(qemu_log_func, NULL); - g_warn_if_fail(qemu_glog_domains == NULL); - qemu_glog_domains = g_strdup(g_getenv("G_MESSAGES_DEBUG")); -} diff --git a/util/qemu-openpty.c b/util/qemu-openpty.c deleted file mode 100644 index 427f43a76973..000000000000 --- a/util/qemu-openpty.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * qemu-openpty.c - * - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2010 Red Hat, Inc. - * - * Wrapper function qemu_openpty() implementation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * This is not part of oslib-posix.c because this function - * uses openpty() which often in -lutil, and if we add this - * dependency to oslib-posix.o, every app will have to be - * linked with -lutil. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" - -#if defined HAVE_PTY_H -# include -#elif defined CONFIG_BSD -# include -# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -# include -# else -# include -# endif -#elif defined CONFIG_SOLARIS -# include -# include -#else -# include -#endif - -#ifdef __sun__ - -#if !defined(HAVE_OPENPTY) -/* Once illumos has openpty(), this is going to be removed. */ -static int openpty(int *amaster, int *aslave, char *name, - struct termios *termp, struct winsize *winp) -{ - const char *slave; - int mfd = -1, sfd = -1; - - *amaster = *aslave = -1; - - mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); - if (mfd < 0) - goto err; - - if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) - goto err; - - if ((slave = ptsname(mfd)) == NULL) - goto err; - - if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) - goto err; - - if (ioctl(sfd, I_PUSH, "ptem") == -1 || - (termp != NULL && tcgetattr(sfd, termp) < 0)) - goto err; - - *amaster = mfd; - *aslave = sfd; - - if (winp) - ioctl(sfd, TIOCSWINSZ, winp); - - return 0; - -err: - if (sfd != -1) - close(sfd); - close(mfd); - return -1; -} -#endif - -static void cfmakeraw (struct termios *termios_p) -{ - termios_p->c_iflag &= - ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - termios_p->c_oflag &= ~OPOST; - termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - termios_p->c_cflag &= ~(CSIZE|PARENB); - termios_p->c_cflag |= CS8; - - termios_p->c_cc[VMIN] = 0; - termios_p->c_cc[VTIME] = 0; -} -#endif - -int qemu_openpty_raw(int *aslave, char *pty_name) -{ - int amaster; - struct termios tty; -#if defined(__OpenBSD__) || defined(__DragonFly__) - char pty_buf[PATH_MAX]; -#define q_ptsname(x) pty_buf -#else - char *pty_buf = NULL; -#define q_ptsname(x) ptsname(x) -#endif - - if (openpty(&amaster, aslave, pty_buf, NULL, NULL) < 0) { - return -1; - } - - /* Set raw attributes on the pty. */ - tcgetattr(*aslave, &tty); - cfmakeraw(&tty); - tcsetattr(*aslave, TCSAFLUSH, &tty); - - if (pty_name) { - strcpy(pty_name, q_ptsname(amaster)); - } - - return amaster; -} diff --git a/util/qemu-progress.c b/util/qemu-progress.c index 20d51f8c128b..aa994668f1c4 100644 --- a/util/qemu-progress.c +++ b/util/qemu-progress.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu/qemu-progress.h" struct progress_state { float current; diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index e8f45a7d30a5..6538859b8743 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -21,7 +21,6 @@ #include #endif /* CONFIG_AF_VSOCK */ -#include "qemu-common.h" #include "monitor/monitor.h" #include "qapi/clone-visitor.h" #include "qapi/error.h" @@ -211,7 +210,8 @@ static int inet_listen_saddr(InetSocketAddress *saddr, int num, Error **errp) { - struct addrinfo ai,*res,*e; + ERRP_GUARD(); + struct addrinfo ai, *res, *e; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; @@ -219,7 +219,6 @@ static int inet_listen_saddr(InetSocketAddress *saddr, int slisten = -1; int saved_errno = 0; bool socket_created = false; - Error *err = NULL; if (saddr->keep_alive) { error_setg(errp, "keep-alive option is not supported for passive " @@ -232,11 +231,9 @@ static int inet_listen_saddr(InetSocketAddress *saddr, if (saddr->has_numeric && saddr->numeric) { ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; } - ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; - - if (err) { - error_propagate(errp, err); + ai.ai_family = inet_ai_family_from_address(saddr, errp); + if (*errp) { return -1; } @@ -393,9 +390,9 @@ static int inet_connect_addr(const InetSocketAddress *saddr, static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, Error **errp) { + ERRP_GUARD(); struct addrinfo ai, *res; int rc; - Error *err = NULL; static int useV4Mapped = 1; memset(&ai, 0, sizeof(ai)); @@ -404,11 +401,9 @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, if (qatomic_read(&useV4Mapped)) { ai.ai_flags |= AI_V4MAPPED; } - ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; - - if (err) { - error_propagate(errp, err); + ai.ai_family = inet_ai_family_from_address(saddr, errp); + if (*errp) { return NULL; } @@ -488,7 +483,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; } } @@ -500,20 +495,18 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr, InetSocketAddress *sladdr, Error **errp) { + ERRP_GUARD(); struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; int sock = -1, rc; - Error *err = NULL; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; - ai.ai_family = inet_ai_family_from_address(sraddr, &err); ai.ai_socktype = SOCK_DGRAM; - - if (err) { - error_propagate(errp, err); + ai.ai_family = inet_ai_family_from_address(sraddr, errp); + if (*errp) { goto err; } @@ -881,8 +874,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 @@ -922,9 +913,8 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, if (saddr->path[0] || abstract) { path = saddr->path; } else { - const char *tmpdir = getenv("TMPDIR"); - tmpdir = tmpdir ? tmpdir : "/tmp"; - path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir); + path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", + g_get_tmp_dir()); } pathlen = strlen(path); @@ -1051,28 +1041,9 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) return sock; err: - close(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; + closesocket(sock); return -1; } -#endif /* compatibility wrapper */ int unix_listen(const char *str, Error **errp) @@ -1099,6 +1070,26 @@ int unix_connect(const char *path, Error **errp) return sock; } +char *socket_uri(SocketAddress *addr) +{ + switch (addr->type) { + case SOCKET_ADDRESS_TYPE_INET: + return g_strdup_printf("tcp:%s:%s", + addr->u.inet.host, + addr->u.inet.port); + case SOCKET_ADDRESS_TYPE_UNIX: + return g_strdup_printf("unix:%s", + addr->u.q_unix.path); + case SOCKET_ADDRESS_TYPE_FD: + return g_strdup_printf("fd:%s", addr->u.fd.str); + case SOCKET_ADDRESS_TYPE_VSOCK: + return g_strdup_printf("vsock:%s:%s", + addr->u.vsock.cid, + addr->u.vsock.port); + default: + return g_strdup("unknown address type"); + } +} SocketAddress *socket_parse(const char *str, Error **errp) { @@ -1126,6 +1117,11 @@ SocketAddress *socket_parse(const char *str, Error **errp) if (vsock_parse(&addr->u.vsock, str + strlen("vsock:"), errp)) { goto fail; } + } else if (strstart(str, "tcp:", NULL)) { + addr->type = SOCKET_ADDRESS_TYPE_INET; + if (inet_parse(&addr->u.inet, str + strlen("tcp:"), errp)) { + goto fail; + } } else { addr->type = SOCKET_ADDRESS_TYPE_INET; if (inet_parse(&addr->u.inet, str, errp)) { @@ -1336,7 +1332,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, @@ -1363,7 +1358,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 * @@ -1395,10 +1389,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: diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index e1225b63bd27..bae938c67084 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -16,6 +16,7 @@ #include "qemu/notify.h" #include "qemu-thread-common.h" #include "qemu/tsan.h" +#include "qemu/bitmap.h" static bool name_threads; @@ -38,12 +39,20 @@ static void error_exit(int err, const char *msg) abort(); } +static inline clockid_t qemu_timedwait_clockid(void) +{ +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + return CLOCK_MONOTONIC; +#else + return CLOCK_REALTIME; +#endif +} + static void compute_abs_deadline(struct timespec *ts, int ms) { - struct timeval tv; - gettimeofday(&tv, NULL); - ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000; - ts->tv_sec = tv.tv_sec + ms / 1000; + clock_gettime(qemu_timedwait_clockid(), ts); + ts->tv_nsec += (ms % 1000) * 1000000; + ts->tv_sec += ms / 1000; if (ts->tv_nsec >= 1000000000) { ts->tv_sec++; ts->tv_nsec -= 1000000000; @@ -147,11 +156,27 @@ void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line) void qemu_cond_init(QemuCond *cond) { + pthread_condattr_t attr; int err; - err = pthread_cond_init(&cond->cond, NULL); - if (err) + err = pthread_condattr_init(&attr); + if (err) { + error_exit(err, __func__); + } +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + err = pthread_condattr_setclock(&attr, qemu_timedwait_clockid()); + if (err) { + error_exit(err, __func__); + } +#endif + err = pthread_cond_init(&cond->cond, &attr); + if (err) { + error_exit(err, __func__); + } + err = pthread_condattr_destroy(&attr); + if (err) { error_exit(err, __func__); + } cond->initialized = true; } @@ -198,16 +223,15 @@ void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, con error_exit(err, __func__); } -bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, - const char *file, const int line) +static bool +qemu_cond_timedwait_ts(QemuCond *cond, QemuMutex *mutex, struct timespec *ts, + const char *file, const int line) { int err; - struct timespec ts; assert(cond->initialized); trace_qemu_mutex_unlock(mutex, file, line); - compute_abs_deadline(&ts, ms); - err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts); + err = pthread_cond_timedwait(&cond->cond, &mutex->lock, ts); trace_qemu_mutex_locked(mutex, file, line); if (err && err != ETIMEDOUT) { error_exit(err, __func__); @@ -215,152 +239,77 @@ bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, return err != ETIMEDOUT; } +bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, + const char *file, const int line) +{ + struct timespec ts; + + compute_abs_deadline(&ts, ms); + return qemu_cond_timedwait_ts(cond, mutex, &ts, file, line); +} + void qemu_sem_init(QemuSemaphore *sem, int init) { - int rc; + qemu_mutex_init(&sem->mutex); + qemu_cond_init(&sem->cond); -#ifndef CONFIG_SEM_TIMEDWAIT - rc = pthread_mutex_init(&sem->lock, NULL); - if (rc != 0) { - error_exit(rc, __func__); - } - rc = pthread_cond_init(&sem->cond, NULL); - if (rc != 0) { - error_exit(rc, __func__); - } if (init < 0) { error_exit(EINVAL, __func__); } sem->count = init; -#else - rc = sem_init(&sem->sem, 0, init); - if (rc < 0) { - error_exit(errno, __func__); - } -#endif - sem->initialized = true; } void qemu_sem_destroy(QemuSemaphore *sem) { - int rc; - - assert(sem->initialized); - sem->initialized = false; -#ifndef CONFIG_SEM_TIMEDWAIT - rc = pthread_cond_destroy(&sem->cond); - if (rc < 0) { - error_exit(rc, __func__); - } - rc = pthread_mutex_destroy(&sem->lock); - if (rc < 0) { - error_exit(rc, __func__); - } -#else - rc = sem_destroy(&sem->sem); - if (rc < 0) { - error_exit(errno, __func__); - } -#endif + qemu_cond_destroy(&sem->cond); + qemu_mutex_destroy(&sem->mutex); } void qemu_sem_post(QemuSemaphore *sem) { - int rc; - - assert(sem->initialized); -#ifndef CONFIG_SEM_TIMEDWAIT - pthread_mutex_lock(&sem->lock); + qemu_mutex_lock(&sem->mutex); if (sem->count == UINT_MAX) { - rc = EINVAL; + error_exit(EINVAL, __func__); } else { sem->count++; - rc = pthread_cond_signal(&sem->cond); - } - pthread_mutex_unlock(&sem->lock); - if (rc != 0) { - error_exit(rc, __func__); + qemu_cond_signal(&sem->cond); } -#else - rc = sem_post(&sem->sem); - if (rc < 0) { - error_exit(errno, __func__); - } -#endif + qemu_mutex_unlock(&sem->mutex); } int qemu_sem_timedwait(QemuSemaphore *sem, int ms) { - int rc; + bool rc = true; struct timespec ts; - assert(sem->initialized); -#ifndef CONFIG_SEM_TIMEDWAIT - rc = 0; compute_abs_deadline(&ts, ms); - pthread_mutex_lock(&sem->lock); + qemu_mutex_lock(&sem->mutex); while (sem->count == 0) { - rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); - if (rc == ETIMEDOUT) { - break; + if (ms == 0) { + rc = false; + } else { + rc = qemu_cond_timedwait_ts(&sem->cond, &sem->mutex, &ts, + __FILE__, __LINE__); } - if (rc != 0) { - error_exit(rc, __func__); + if (!rc) { /* timeout */ + break; } } - if (rc != ETIMEDOUT) { + if (rc) { --sem->count; } - pthread_mutex_unlock(&sem->lock); - return (rc == ETIMEDOUT ? -1 : 0); -#else - if (ms <= 0) { - /* This is cheaper than sem_timedwait. */ - do { - rc = sem_trywait(&sem->sem); - } while (rc == -1 && errno == EINTR); - if (rc == -1 && errno == EAGAIN) { - return -1; - } - } else { - compute_abs_deadline(&ts, ms); - do { - rc = sem_timedwait(&sem->sem, &ts); - } while (rc == -1 && errno == EINTR); - if (rc == -1 && errno == ETIMEDOUT) { - return -1; - } - } - if (rc < 0) { - error_exit(errno, __func__); - } - return 0; -#endif + qemu_mutex_unlock(&sem->mutex); + return (rc ? 0 : -1); } void qemu_sem_wait(QemuSemaphore *sem) { - int rc; - - assert(sem->initialized); -#ifndef CONFIG_SEM_TIMEDWAIT - pthread_mutex_lock(&sem->lock); + qemu_mutex_lock(&sem->mutex); while (sem->count == 0) { - rc = pthread_cond_wait(&sem->cond, &sem->lock); - if (rc != 0) { - error_exit(rc, __func__); - } + qemu_cond_wait(&sem->cond, &sem->mutex); } --sem->count; - pthread_mutex_unlock(&sem->lock); -#else - do { - rc = sem_wait(&sem->sem); - } while (rc == -1 && errno == EINTR); - if (rc < 0) { - error_exit(errno, __func__); - } -#endif + qemu_mutex_unlock(&sem->mutex); } #ifdef __linux__ @@ -604,6 +553,75 @@ void qemu_thread_create(QemuThread *thread, const char *name, pthread_attr_destroy(&attr); } +int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus, + unsigned long nbits) +{ +#if defined(CONFIG_PTHREAD_AFFINITY_NP) + const size_t setsize = CPU_ALLOC_SIZE(nbits); + unsigned long value; + cpu_set_t *cpuset; + int err; + + cpuset = CPU_ALLOC(nbits); + g_assert(cpuset); + + CPU_ZERO_S(setsize, cpuset); + value = find_first_bit(host_cpus, nbits); + while (value < nbits) { + CPU_SET_S(value, setsize, cpuset); + value = find_next_bit(host_cpus, nbits, value + 1); + } + + err = pthread_setaffinity_np(thread->thread, setsize, cpuset); + CPU_FREE(cpuset); + return err; +#else + return -ENOSYS; +#endif +} + +int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus, + unsigned long *nbits) +{ +#if defined(CONFIG_PTHREAD_AFFINITY_NP) + unsigned long tmpbits; + cpu_set_t *cpuset; + size_t setsize; + int i, err; + + tmpbits = CPU_SETSIZE; + while (true) { + setsize = CPU_ALLOC_SIZE(tmpbits); + cpuset = CPU_ALLOC(tmpbits); + g_assert(cpuset); + + err = pthread_getaffinity_np(thread->thread, setsize, cpuset); + if (err) { + CPU_FREE(cpuset); + if (err != -EINVAL) { + return err; + } + tmpbits *= 2; + } else { + break; + } + } + + /* Convert the result into a proper bitmap. */ + *nbits = tmpbits; + *host_cpus = bitmap_new(tmpbits); + for (i = 0; i < tmpbits; i++) { + if (CPU_ISSET(i, cpuset)) { + set_bit(i, *host_cpus); + } + } + CPU_FREE(cpuset); + return 0; +#else + return -ENOSYS; +#endif +} + void qemu_thread_get_self(QemuThread *thread) { thread->thread = pthread_self(); diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index 52eb19f3511a..69db254ac7c1 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/thread.h" #include "qemu/notify.h" #include "qemu-thread-common.h" @@ -20,12 +19,39 @@ static bool name_threads; +typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread, + PCWSTR lpThreadDescription); +static pSetThreadDescription SetThreadDescriptionFunc; +static HMODULE kernel32_module; + +static bool load_set_thread_description(void) +{ + static gsize _init_once = 0; + + if (g_once_init_enter(&_init_once)) { + kernel32_module = LoadLibrary("kernel32.dll"); + if (kernel32_module) { + SetThreadDescriptionFunc = + (pSetThreadDescription)GetProcAddress(kernel32_module, + "SetThreadDescription"); + if (!SetThreadDescriptionFunc) { + FreeLibrary(kernel32_module); + } + } + g_once_init_leave(&_init_once, 1); + } + + return !!SetThreadDescriptionFunc; +} + void qemu_thread_naming(bool enable) { - /* But note we don't actually name them on Windows yet */ name_threads = enable; - fprintf(stderr, "qemu: thread naming not supported on this host\n"); + if (enable && !load_set_thread_description()) { + fprintf(stderr, "qemu: thread naming not supported on this host\n"); + name_threads = false; + } } static void error_exit(int err, const char *msg) @@ -401,6 +427,25 @@ void *qemu_thread_join(QemuThread *thread) return ret; } +static bool set_thread_description(HANDLE h, const char *name) +{ + HRESULT hr; + g_autofree wchar_t *namew = NULL; + + if (!load_set_thread_description()) { + return false; + } + + namew = g_utf8_to_utf16(name, -1, NULL, NULL, NULL); + if (!namew) { + return false; + } + + hr = SetThreadDescriptionFunc(h, namew); + + return SUCCEEDED(hr); +} + void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode) @@ -424,10 +469,26 @@ void qemu_thread_create(QemuThread *thread, const char *name, if (!hThread) { error_exit(GetLastError(), __func__); } + if (name_threads && name && !set_thread_description(hThread, name)) { + fprintf(stderr, "qemu: failed to set thread description: %s\n", name); + } CloseHandle(hThread); + thread->data = data; } +int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus, + unsigned long nbits) +{ + return -ENOSYS; +} + +int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus, + unsigned long *nbits) +{ + return -ENOSYS; +} + void qemu_thread_get_self(QemuThread *thread) { thread->data = qemu_thread_data; diff --git a/util/qemu-timer.c b/util/qemu-timer.c index a670a5788184..6a0de33dd2b8 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -261,6 +261,9 @@ int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) } QLIST_FOREACH(timer_list, &clock->timerlists, list) { + if (!qatomic_read(&timer_list->active_timers)) { + continue; + } qemu_mutex_lock(&timer_list->active_timers_lock); ts = timer_list->active_timers; /* Skip all external timers */ diff --git a/util/thread-context.c b/util/thread-context.c new file mode 100644 index 000000000000..2bc7883b9e01 --- /dev/null +++ b/util/thread-context.c @@ -0,0 +1,356 @@ +/* + * QEMU Thread Context + * + * Copyright Red Hat Inc., 2022 + * + * Authors: + * David Hildenbrand + * + * 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 "qemu/thread-context.h" +#include "qapi/error.h" +#include "qapi/qapi-builtin-visit.h" +#include "qapi/visitor.h" +#include "qemu/config-file.h" +#include "qapi/qapi-builtin-visit.h" +#include "qom/object_interfaces.h" +#include "qemu/module.h" +#include "qemu/bitmap.h" + +#ifdef CONFIG_NUMA +#include +#endif + +enum { + TC_CMD_NONE = 0, + TC_CMD_STOP, + TC_CMD_NEW, +}; + +typedef struct ThreadContextCmdNew { + QemuThread *thread; + const char *name; + void *(*start_routine)(void *); + void *arg; + int mode; +} ThreadContextCmdNew; + +static void *thread_context_run(void *opaque) +{ + ThreadContext *tc = opaque; + + tc->thread_id = qemu_get_thread_id(); + qemu_sem_post(&tc->sem); + + while (true) { + /* + * Threads inherit the CPU affinity of the creating thread. For this + * reason, we create new (especially short-lived) threads from our + * persistent context thread. + * + * Especially when QEMU is not allowed to set the affinity itself, + * management tools can simply set the affinity of the context thread + * after creating the context, to have new threads created via + * the context inherit the CPU affinity automatically. + */ + switch (tc->thread_cmd) { + case TC_CMD_NONE: + break; + case TC_CMD_STOP: + tc->thread_cmd = TC_CMD_NONE; + qemu_sem_post(&tc->sem); + return NULL; + case TC_CMD_NEW: { + ThreadContextCmdNew *cmd_new = tc->thread_cmd_data; + + qemu_thread_create(cmd_new->thread, cmd_new->name, + cmd_new->start_routine, cmd_new->arg, + cmd_new->mode); + tc->thread_cmd = TC_CMD_NONE; + tc->thread_cmd_data = NULL; + qemu_sem_post(&tc->sem); + break; + } + default: + g_assert_not_reached(); + } + qemu_sem_wait(&tc->sem_thread); + } +} + +static void thread_context_set_cpu_affinity(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + ThreadContext *tc = THREAD_CONTEXT(obj); + uint16List *l, *host_cpus = NULL; + unsigned long *bitmap = NULL; + int nbits = 0, ret; + + if (tc->init_cpu_bitmap) { + error_setg(errp, "Mixing CPU and node affinity not supported"); + return; + } + + if (!visit_type_uint16List(v, name, &host_cpus, errp)) { + return; + } + + if (!host_cpus) { + error_setg(errp, "CPU list is empty"); + goto out; + } + + for (l = host_cpus; l; l = l->next) { + nbits = MAX(nbits, l->value + 1); + } + bitmap = bitmap_new(nbits); + for (l = host_cpus; l; l = l->next) { + set_bit(l->value, bitmap); + } + + if (tc->thread_id != -1) { + /* + * Note: we won't be adjusting the affinity of any thread that is still + * around, but only the affinity of the context thread. + */ + ret = qemu_thread_set_affinity(&tc->thread, bitmap, nbits); + if (ret) { + error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret)); + } + } else { + tc->init_cpu_bitmap = bitmap; + bitmap = NULL; + tc->init_cpu_nbits = nbits; + } +out: + g_free(bitmap); + qapi_free_uint16List(host_cpus); +} + +static void thread_context_get_cpu_affinity(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + unsigned long *bitmap, nbits, value; + ThreadContext *tc = THREAD_CONTEXT(obj); + uint16List *host_cpus = NULL; + uint16List **tail = &host_cpus; + int ret; + + if (tc->thread_id == -1) { + error_setg(errp, "Object not initialized yet"); + return; + } + + ret = qemu_thread_get_affinity(&tc->thread, &bitmap, &nbits); + if (ret) { + error_setg(errp, "Getting CPU affinity failed: %s", strerror(ret)); + return; + } + + value = find_first_bit(bitmap, nbits); + while (value < nbits) { + QAPI_LIST_APPEND(tail, value); + + value = find_next_bit(bitmap, nbits, value + 1); + } + g_free(bitmap); + + visit_type_uint16List(v, name, &host_cpus, errp); + qapi_free_uint16List(host_cpus); +} + +static void thread_context_set_node_affinity(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ +#ifdef CONFIG_NUMA + const int nbits = numa_num_possible_cpus(); + ThreadContext *tc = THREAD_CONTEXT(obj); + uint16List *l, *host_nodes = NULL; + unsigned long *bitmap = NULL; + struct bitmask *tmp_cpus; + int ret, i; + + if (tc->init_cpu_bitmap) { + error_setg(errp, "Mixing CPU and node affinity not supported"); + return; + } + + if (!visit_type_uint16List(v, name, &host_nodes, errp)) { + return; + } + + if (!host_nodes) { + error_setg(errp, "Node list is empty"); + goto out; + } + + bitmap = bitmap_new(nbits); + tmp_cpus = numa_allocate_cpumask(); + for (l = host_nodes; l; l = l->next) { + numa_bitmask_clearall(tmp_cpus); + ret = numa_node_to_cpus(l->value, tmp_cpus); + if (ret) { + /* We ignore any errors, such as impossible nodes. */ + continue; + } + for (i = 0; i < nbits; i++) { + if (numa_bitmask_isbitset(tmp_cpus, i)) { + set_bit(i, bitmap); + } + } + } + numa_free_cpumask(tmp_cpus); + + if (bitmap_empty(bitmap, nbits)) { + error_setg(errp, "The nodes select no CPUs"); + goto out; + } + + if (tc->thread_id != -1) { + /* + * Note: we won't be adjusting the affinity of any thread that is still + * around for now, but only the affinity of the context thread. + */ + ret = qemu_thread_set_affinity(&tc->thread, bitmap, nbits); + if (ret) { + error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret)); + } + } else { + tc->init_cpu_bitmap = bitmap; + bitmap = NULL; + tc->init_cpu_nbits = nbits; + } +out: + g_free(bitmap); + qapi_free_uint16List(host_nodes); +#else + error_setg(errp, "NUMA node affinity is not supported by this QEMU"); +#endif +} + +static void thread_context_get_thread_id(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + ThreadContext *tc = THREAD_CONTEXT(obj); + uint64_t value = tc->thread_id; + + visit_type_uint64(v, name, &value, errp); +} + +static void thread_context_instance_complete(UserCreatable *uc, Error **errp) +{ + ThreadContext *tc = THREAD_CONTEXT(uc); + char *thread_name; + int ret; + + thread_name = g_strdup_printf("TC %s", + object_get_canonical_path_component(OBJECT(uc))); + qemu_thread_create(&tc->thread, thread_name, thread_context_run, tc, + QEMU_THREAD_JOINABLE); + g_free(thread_name); + + /* Wait until initialization of the thread is done. */ + while (tc->thread_id == -1) { + qemu_sem_wait(&tc->sem); + } + + if (tc->init_cpu_bitmap) { + ret = qemu_thread_set_affinity(&tc->thread, tc->init_cpu_bitmap, + tc->init_cpu_nbits); + if (ret) { + error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret)); + } + g_free(tc->init_cpu_bitmap); + tc->init_cpu_bitmap = NULL; + } +} + +static void thread_context_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + + ucc->complete = thread_context_instance_complete; + object_class_property_add(oc, "thread-id", "int", + thread_context_get_thread_id, NULL, NULL, + NULL); + object_class_property_add(oc, "cpu-affinity", "int", + thread_context_get_cpu_affinity, + thread_context_set_cpu_affinity, NULL, NULL); + object_class_property_add(oc, "node-affinity", "int", NULL, + thread_context_set_node_affinity, NULL, NULL); +} + +static void thread_context_instance_init(Object *obj) +{ + ThreadContext *tc = THREAD_CONTEXT(obj); + + tc->thread_id = -1; + qemu_sem_init(&tc->sem, 0); + qemu_sem_init(&tc->sem_thread, 0); + qemu_mutex_init(&tc->mutex); +} + +static void thread_context_instance_finalize(Object *obj) +{ + ThreadContext *tc = THREAD_CONTEXT(obj); + + if (tc->thread_id != -1) { + tc->thread_cmd = TC_CMD_STOP; + qemu_sem_post(&tc->sem_thread); + qemu_thread_join(&tc->thread); + } + qemu_sem_destroy(&tc->sem); + qemu_sem_destroy(&tc->sem_thread); + qemu_mutex_destroy(&tc->mutex); +} + +static const TypeInfo thread_context_info = { + .name = TYPE_THREAD_CONTEXT, + .parent = TYPE_OBJECT, + .class_init = thread_context_class_init, + .instance_size = sizeof(ThreadContext), + .instance_init = thread_context_instance_init, + .instance_finalize = thread_context_instance_finalize, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void thread_context_register_types(void) +{ + type_register_static(&thread_context_info); +} +type_init(thread_context_register_types) + +void thread_context_create_thread(ThreadContext *tc, QemuThread *thread, + const char *name, + void *(*start_routine)(void *), void *arg, + int mode) +{ + ThreadContextCmdNew data = { + .thread = thread, + .name = name, + .start_routine = start_routine, + .arg = arg, + .mode = mode, + }; + + qemu_mutex_lock(&tc->mutex); + tc->thread_cmd = TC_CMD_NEW; + tc->thread_cmd_data = &data; + qemu_sem_post(&tc->sem_thread); + + while (tc->thread_cmd != TC_CMD_NONE) { + qemu_sem_wait(&tc->sem); + } + qemu_mutex_unlock(&tc->mutex); +} diff --git a/util/thread-pool.c b/util/thread-pool.c index d763cea505b6..31113b586034 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -57,8 +57,7 @@ struct ThreadPool { QEMUBH *completion_bh; QemuMutex lock; QemuCond worker_stopped; - QemuSemaphore sem; - int max_threads; + QemuCond request_cond; QEMUBH *new_thread_bh; /* The following variables are only accessed from one AioContext. */ @@ -70,7 +69,8 @@ struct ThreadPool { int idle_threads; int new_threads; /* backlog of threads we need to create */ int pending_threads; /* threads created but not running yet */ - bool stopping; + int min_threads; + int max_threads; }; static void *worker_thread(void *opaque) @@ -81,19 +81,25 @@ static void *worker_thread(void *opaque) pool->pending_threads--; do_spawn_thread(pool); - while (!pool->stopping) { + while (pool->cur_threads <= pool->max_threads) { ThreadPoolElement *req; int ret; - do { + if (QTAILQ_EMPTY(&pool->request_list)) { pool->idle_threads++; - qemu_mutex_unlock(&pool->lock); - ret = qemu_sem_timedwait(&pool->sem, 10000); - qemu_mutex_lock(&pool->lock); + ret = qemu_cond_timedwait(&pool->request_cond, &pool->lock, 10000); pool->idle_threads--; - } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list)); - if (ret == -1 || pool->stopping) { - break; + if (ret == 0 && + QTAILQ_EMPTY(&pool->request_list) && + pool->cur_threads > pool->min_threads) { + /* Timed out + no work to do + no need for warm threads = exit. */ + break; + } + /* + * Even if there was some work to do, check if there aren't + * too many worker threads before picking it up. + */ + continue; } req = QTAILQ_FIRST(&pool->request_list); @@ -108,14 +114,19 @@ static void *worker_thread(void *opaque) smp_wmb(); req->state = THREAD_DONE; - qemu_mutex_lock(&pool->lock); - qemu_bh_schedule(pool->completion_bh); + qemu_mutex_lock(&pool->lock); } pool->cur_threads--; qemu_cond_signal(&pool->worker_stopped); qemu_mutex_unlock(&pool->lock); + + /* + * Wake up another thread, in case we got a wakeup but decided + * to exit due to pool->cur_threads > pool->max_threads. + */ + qemu_cond_signal(&pool->request_cond); return NULL; } @@ -211,13 +222,7 @@ static void thread_pool_cancel(BlockAIOCB *acb) trace_thread_pool_cancel(elem, elem->common.opaque); QEMU_LOCK_GUARD(&pool->lock); - if (elem->state == THREAD_QUEUED && - /* No thread has yet started working on elem. we can try to "steal" - * the item from the worker if we can get a signal from the - * semaphore. Because this is non-blocking, we can do it with - * the lock taken and ensure that elem will remain THREAD_QUEUED. - */ - qemu_sem_timedwait(&pool->sem, 0) == 0) { + if (elem->state == THREAD_QUEUED) { QTAILQ_REMOVE(&pool->request_list, elem, reqs); qemu_bh_schedule(pool->completion_bh); @@ -262,7 +267,7 @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, } QTAILQ_INSERT_TAIL(&pool->request_list, req, reqs); qemu_mutex_unlock(&pool->lock); - qemu_sem_post(&pool->sem); + qemu_cond_signal(&pool->request_cond); return &req->common; } @@ -294,6 +299,33 @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg) thread_pool_submit_aio(pool, func, arg, NULL, NULL); } +void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) +{ + qemu_mutex_lock(&pool->lock); + + pool->min_threads = ctx->thread_pool_min; + pool->max_threads = ctx->thread_pool_max; + + /* + * We either have to: + * - Increase the number available of threads until over the min_threads + * threshold. + * - Bump the worker threads so that they exit, until under the max_threads + * threshold. + * - Do nothing. The current number of threads fall in between the min and + * max thresholds. We'll let the pool manage itself. + */ + for (int i = pool->cur_threads; i < pool->min_threads; i++) { + spawn_thread(pool); + } + + for (int i = pool->cur_threads; i > pool->max_threads; i--) { + qemu_cond_signal(&pool->request_cond); + } + + qemu_mutex_unlock(&pool->lock); +} + static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) { if (!ctx) { @@ -305,12 +337,13 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool); qemu_mutex_init(&pool->lock); qemu_cond_init(&pool->worker_stopped); - qemu_sem_init(&pool->sem, 0); - pool->max_threads = 64; + qemu_cond_init(&pool->request_cond); pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); QLIST_INIT(&pool->head); QTAILQ_INIT(&pool->request_list); + + thread_pool_update_params(pool, ctx); } ThreadPool *thread_pool_new(AioContext *ctx) @@ -336,16 +369,16 @@ void thread_pool_free(ThreadPool *pool) pool->new_threads = 0; /* Wait for worker threads to terminate */ - pool->stopping = true; + pool->max_threads = 0; + qemu_cond_broadcast(&pool->request_cond); while (pool->cur_threads > 0) { - qemu_sem_post(&pool->sem); qemu_cond_wait(&pool->worker_stopped, &pool->lock); } qemu_mutex_unlock(&pool->lock); qemu_bh_delete(pool->completion_bh); - qemu_sem_destroy(&pool->sem); + qemu_cond_destroy(&pool->request_cond); qemu_cond_destroy(&pool->worker_stopped); qemu_mutex_destroy(&pool->lock); g_free(pool); diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c index b037d5faa51e..2d8af38f886a 100644 --- a/util/vfio-helpers.c +++ b/util/vfio-helpers.c @@ -163,7 +163,7 @@ void *qemu_vfio_pci_map_bar(QEMUVFIOState *s, int index, Error **errp) { void *p; - assert(QEMU_IS_ALIGNED(offset, qemu_real_host_page_size)); + assert(QEMU_IS_ALIGNED(offset, qemu_real_host_page_size())); assert_bar_index_valid(s, index); p = mmap(NULL, MIN(size, s->bar_region_info[index].size - offset), prot, MAP_SHARED, @@ -240,9 +240,9 @@ static int qemu_vfio_pci_read_config(QEMUVFIOState *s, void *buf, s->config_region_info.offset, s->config_region_info.size); assert(QEMU_IS_ALIGNED(s->config_region_info.offset + ofs, size)); - do { - ret = pread(s->device, buf, size, s->config_region_info.offset + ofs); - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR( + pread(s->device, buf, size, s->config_region_info.offset + ofs) + ); return ret == size ? 0 : -errno; } @@ -254,9 +254,9 @@ static int qemu_vfio_pci_write_config(QEMUVFIOState *s, void *buf, int size, int s->config_region_info.offset, s->config_region_info.size); assert(QEMU_IS_ALIGNED(s->config_region_info.offset + ofs, size)); - do { - ret = pwrite(s->device, buf, size, s->config_region_info.offset + ofs); - } while (ret == -1 && errno == EINTR); + ret = RETRY_ON_EINTR( + pwrite(s->device, buf, size, s->config_region_info.offset + ofs) + ); return ret == size ? 0 : -errno; } @@ -271,7 +271,7 @@ static void collect_usable_iova_ranges(QEMUVFIOState *s, void *buf) if (!cap->next) { return; } - cap = (struct vfio_info_cap_header *)(buf + cap->next); + cap = buf + cap->next; } cap_iova_range = (struct vfio_iommu_type1_info_cap_iova_range *)cap; @@ -591,9 +591,9 @@ static IOVAMapping *qemu_vfio_add_mapping(QEMUVFIOState *s, IOVAMapping m = {.host = host, .size = size, .iova = iova}; IOVAMapping *insert; - assert(QEMU_IS_ALIGNED(size, qemu_real_host_page_size)); - assert(QEMU_IS_ALIGNED(s->low_water_mark, qemu_real_host_page_size)); - assert(QEMU_IS_ALIGNED(s->high_water_mark, qemu_real_host_page_size)); + assert(QEMU_IS_ALIGNED(size, qemu_real_host_page_size())); + assert(QEMU_IS_ALIGNED(s->low_water_mark, qemu_real_host_page_size())); + assert(QEMU_IS_ALIGNED(s->high_water_mark, qemu_real_host_page_size())); trace_qemu_vfio_new_mapping(s, host, size, index, iova); assert(index >= 0); @@ -644,7 +644,7 @@ static void qemu_vfio_undo_mapping(QEMUVFIOState *s, IOVAMapping *mapping, index = mapping - s->mappings; assert(mapping->size > 0); - assert(QEMU_IS_ALIGNED(mapping->size, qemu_real_host_page_size)); + assert(QEMU_IS_ALIGNED(mapping->size, qemu_real_host_page_size())); assert(index >= 0 && index < s->nr_mappings); if (ioctl(s->container, VFIO_IOMMU_UNMAP_DMA, &unmap)) { error_setg_errno(errp, errno, "VFIO_UNMAP_DMA failed"); @@ -752,8 +752,8 @@ int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size, IOVAMapping *mapping; uint64_t iova0; - assert(QEMU_PTR_IS_ALIGNED(host, qemu_real_host_page_size)); - assert(QEMU_IS_ALIGNED(size, qemu_real_host_page_size)); + assert(QEMU_PTR_IS_ALIGNED(host, qemu_real_host_page_size())); + assert(QEMU_IS_ALIGNED(size, qemu_real_host_page_size())); trace_qemu_vfio_dma_map(s, host, size, temporary, iova); QEMU_LOCK_GUARD(&s->lock); mapping = qemu_vfio_find_mapping(s, host, &index); @@ -847,10 +847,13 @@ void qemu_vfio_close(QEMUVFIOState *s) if (!s) { return; } + + ram_block_notifier_remove(&s->ram_notifier); + for (i = 0; i < s->nr_mappings; ++i) { qemu_vfio_undo_mapping(s, &s->mappings[i], NULL); } - ram_block_notifier_remove(&s->ram_notifier); + g_free(s->usable_iova_ranges); s->nb_iova_ranges = 0; qemu_vfio_reset(s); diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c index f66fbba7108b..232984ace6d7 100644 --- a/util/vhost-user-server.c +++ b/util/vhost-user-server.c @@ -65,7 +65,7 @@ static void vmsg_unblock_fds(VhostUserMsg *vmsg) { int i; for (i = 0; i < vmsg->fd_num; i++) { - qemu_set_nonblock(vmsg->fds[i]); + qemu_socket_set_nonblock(vmsg->fds[i]); } } @@ -270,7 +270,7 @@ set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_fd_watch->fd = fd; vu_fd_watch->cb = cb; - qemu_set_nonblock(fd); + qemu_socket_set_nonblock(fd); aio_set_fd_handler(server->ioc->ctx, fd, true, kick_handler, NULL, NULL, NULL, vu_fd_watch); vu_fd_watch->vu_dev = vu_dev;